diff --git a/.bazelignore b/.bazelignore new file mode 100644 index 000000000..95a87f315 --- /dev/null +++ b/.bazelignore @@ -0,0 +1,5 @@ +.git +target +.moon +.proto +.venv diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 000000000..3b82a2047 --- /dev/null +++ b/.bazelrc @@ -0,0 +1,33 @@ +# Keep local executions independent from hosted cache or execution configuration. +startup --max_idle_secs=300 +startup --shutdown_on_low_sys_mem +startup --host_jvm_args=-Xmx2048m +common --repo_env=DO_NOT_TRACK=1 +common --lockfile_mode=error +build --incompatible_strict_action_env +build --verbose_failures +# Compiler and quality tools use the runtime acquired by pinned rules_java. +build --java_runtime_version=remotejdk_17 +build --tool_java_runtime_version=remotejdk_17 +test --test_output=errors + +# Cross-platform runtime tests need manifest or directory runfiles. +# Windows native file symlinks require Developer Mode or administrator privileges. +startup --windows_enable_symlinks +build --enable_runfiles + +# Native C++ links need the allocator ABI generated by the selected Rust compiler. +build --@rules_rust//rust/settings:experimental_use_allocator_libraries_with_mangled_symbols=true + +# Native Clippy checks use the same configuration as conventional Cargo checks. +build --@rules_rust//rust/settings:clippy.toml=//:clippy.toml +build --@rules_rust//rust/settings:clippy_flags=-Dwarnings + +# Darwin sandbox reuse otherwise traverses the complete SDK forest per action. +build:macos-sandbox --experimental_inmemory_sandbox_stashes + +# The LLVM serializer runs on Linux; serialized product targets remain separate. +build:wasix-aot --extra_execution_platforms=//build_defs/wasix:llvm_serializer_linux_x86_64 + +# Optional CI disk cache: callers supply an absolute --disk_cache path. +build:ci-cache --experimental_remote_merkle_tree_cache diff --git a/.bazelversion b/.bazelversion new file mode 100644 index 000000000..eec6dacbd --- /dev/null +++ b/.bazelversion @@ -0,0 +1 @@ +8.8.1 diff --git a/.codex/skills/qualify-oliphaunt-change/SKILL.md b/.codex/skills/qualify-oliphaunt-change/SKILL.md index dc90485b9..fc39124aa 100644 --- a/.codex/skills/qualify-oliphaunt-change/SKILL.md +++ b/.codex/skills/qualify-oliphaunt-change/SKILL.md @@ -5,202 +5,163 @@ description: Select, run, and diagnose Oliphaunt local and GitHub CI qualificati # Qualify Oliphaunt Change -Use the repository graph to select work and require exact-SHA qualification for releases. -CI's `release_products_json` input selects stable product IDs and their Moon -task/dependency closure. Keep platform selectors at `all`; a focused platform -debug run cannot qualify publication. Empty product selection remains the -exhaustive audit. Selected-product records must cover every published product; -producer evidence still comes from the same candidate run. -Generated same-repository Release PRs and their merged main release commits -derive scope automatically from Release Please manifest changes. Main push -qualifies only after Plan and Required succeed; PR results cannot be published. +Use stock Bazel targets and the owner's configured shipping export. Bazel's +actual action graph and cache determine what executes; directory ownership, +conventional dependency declarations and test dependencies do not select product +releases. Native preparation compares qualified deliveries with each product's +authenticated completed publication, then supplies necessary owners to Release +Please for version and changelog calculation. Missing history stays unknown. + +`Native Bazel qualification / Required` is the release entrypoint's source gate. +The migration still needs complete hosted platform/device qualification, the +27-product construction audit, the genuine seed adoption anchor and legacy CI +retirement. A local test, individual job or construction audit does not admit a +publication. PR and merge-queue evidence cannot assert reviewed-main assurance. ## Local feedback -1. Inspect the diff and ask Moon for affected projects/tasks. Do not infer affected products from directory names alone. -2. Run affected formatting (`format-check`, `js-format-check`, or - `rust-format-check`), `lint`, `typecheck`, and `test` tasks as applicable. - Inspect the owner's actual task definitions before selecting `build`, - `package`, `test-consumer`, `test-integration`, `test-browser`, or installed - device tests. Let Moon build declared prerequisites; task names alone do - not justify running every available lane. -3. If the diff changes a WASIX producer's source pins, patches, recipes, - toolchain or code, qualify that owner's affected portable/AOT output. Reuse - compiler outputs only when their declared source, dependency and toolchain - identities still match. A package envelope or test-only edit alone does not - justify rebuilding unrelated core, tools or extension producers. -4. Select release-policy checks by the contract that changed: - -```sh -# Product/release metadata only: -moon run release-tools:metadata - -# Release implementation changes: -moon run release-tools:test - -# Release Please candidate ownership/version selection changes: -moon run release-tools:graph-unit - -# Workflow and CI planning changes: -moon run ci-workflows:check - -# Release metadata and release implementation tests: -bash tools/release/release-check.sh - -# Extension catalog, recipe, carrier, or generated extension metadata only: -moon run extensions:lint extensions:test -``` - -Select only the checks whose inputs changed. `release-tools:metadata` validates -product versions, compatibility, carrier declarations and derived files; -`release-tools:test` exercises release behavior; `graph-unit` exercises the -pinned Release Please candidate integration. `release-tools:check` is their -local Moon aggregate. There is no separate policy test project. The Shell -aggregate runs metadata and release tests, not product compilation or installed -consumer qualification. CI's `Checks / Policy` job runs on Ubuntu and sets up -only capabilities needed by its selected tasks. Workflow planning, affectedness, -artifact-transfer and security checks belong to `ci-workflows:check`. -Publishers consume source qualification and frozen artifacts instead of -replaying source-only suites. Do not schedule both aggregates and their -constituent checks in the same lane. -`tools/ci/ci_plan.mts` writes `target/graph/ci-plan.json`; there is no -`graph-tools` Moon project. The adapter consumes Moon's selected tasks; its -behavioral tests do not replace planning against the actual candidate tree. - -Ordinary source pushes, PR preparation and CI qualification do not select the -protected `release-bootstrap` environment. Bootstrap-token lifecycle findings -from the optional release-controls audit are setup/publication findings, not -source-qualification blockers. Preserve the actual CI ref, permission and -artifact checks; do not provision, remove or relabel registry credentials to -make an unrelated source run pass. - -For source-acquisition policy or a source `mirror_url`, run -`bash src/third-party/tools/source-fetch-core.test.sh` and -`bash src/third-party/tools/fetch-sources.sh production-all --validate-only`, or the -complete owner task `moon run source-inputs:test`. The paired Shell test owns -actual Git/archive operations and invokes its TypeScript assertions once. Prove a -new endpoint with a live exact-commit fetch, but keep reachability out of the -deterministic unit gate. Qualification must show bounded canonical-to-mirror -failover, exact-pin rejection, canonical durable origin, and transactional -preservation of an existing checkout when every endpoint fails. - -5. For any workflow or local-action change, run - `bash tools/ci/check-workflows.sh` before waiting for CI. This is the - repository's exact pinned `actionlint` plus `zizmor` gate and its workflow - behavior tests; running `actionlint` alone is not sufficient. A disposable - credential-free workflow compiler probe is needed only when a release candidate - changes hosted-only job topology, permissions, protected environments, or - dispatch inputs. The local gate cannot prove hosted environment-secret - resolution or dispatch-time graph compilation. - Exercise macOS-executed Shell paths with the Bash actually selected by that - job, recording `command -v bash` and `bash --version`. `shell: bash` alone - does not establish a version. Normal release/Apple setup does not install - another Bash; the WASIX postmaster target job explicitly installs Homebrew - Bash. Keep focused Bash 3.2 behavioral checks for scripts claiming macOS - `/bin/bash` compatibility, including `set -u` empty-array behavior. Do not - impose the entire Linux release-tool suite on Bash 3.2. Syntax checks do not - replace actual Apple transport or publication-path behavior. -6. Declare runner capabilities on the narrowest Moon task that needs them. Use - `requires-rust` for Cargo, rustc, rustfmt, or another Rust-toolchain command; - `requires-maintainer-tools` for the pinned tools installed by - `tools/dev/bootstrap-tools.sh`; and `requires-android-sdk` for Android SDK work. - Use `requires-swift` for the portable Swift compiler; add `requires-apple` - only for Xcode, Apple frameworks, simulators or other Apple-only work. - Portable Swift source checks use the pinned Linux Swift setup. - Capabilities propagate through task dependencies. The planner keeps - capability-bearing checks grouped only with tasks requiring the same setup. -7. Treat a hosted runner-image pin as a toolchain dependency. Never introduce a mutable `*-latest` alias; after changing an explicit runner pin, inspect the image delta and run the platform binary contract for every affected release target. - -For a WASIX Docker, APT snapshot, or bootstrap trust change, also run the -product-owned fault test and source verifier before the expensive build: - -```sh -bash src/third-party/tools/fetch-sources.sh wasix-runtime --verify-only -moon run liboliphaunt-wasix:build-orchestration-test liboliphaunt-wasix:test -``` - -Then use `liboliphaunt-wasix:compiler-output`, `runtime-portable` and -`runtime-aot` for the actual selected producer proof. Optional PostgreSQL tools -and extensions have separate owner producers; do not restore those as core -runtime build prerequisites. For a Docker trust change, build the pinned -Dockerfile from a clean builder context. Require a -successful TLS-verified snapshot transaction and the exact declared wasixcc, -Clang, and Binaryen versions; a source/static check alone does not prove -that the pinned trust chain still reaches the snapshot service. - -For an SDK change, run each affected -SDK's relevant source checks, `test`, and `package` tasks in one Moon invocation. -Their declared dependencies remain necessary; `package` does not silently rerun -unrelated source qualification. Set -`MOON_BASE` and `MOON_HEAD`, inspect affected SDK projects, and pass the exact -targets to `moon run`; a workspace-wide selector also selects non-SDK products. -Confirm ownership with `moon query tasks --project ` when changing -task topology. Never replace the product task with a narrower native command: -for example, `cargo test -p oliphaunt --lib` omits other Cargo targets selected -by the owner task. Carrier producers copy the canonical C header; real consumers -compile against it instead of running a separate layout gate. Add -the product's explicit runtime or installed-host tests when that proof is needed, and run -`moon run extensions:lint extensions:test` when an extension catalog or generated SDK -extension surface changes. Put new guarantees in a parsed schema/generated -contract where consumers require one, a clean-consumer package check, or a -product-owned behavioral test. Do -not qualify SDK behavior by grepping prose, test names, or -implementation-source spellings. +1. Read the changed owner's `BUILD.bazel`, actual configured dependencies and + shipping export policy. Use the target and host profiles from + `.github/workflows/bazel.yml`; do not invent a path-based affectedness map. + Run only relevant targets and let Bazel reuse unchanged actions. +2. Start with source checks before expensive construction. On Linux x64 the + declared profile is `//build_defs/native:linux_x86_64_glibc_2_28`: + + ```sh + profile=//build_defs/native:linux_x86_64_glibc_2_28 + bash tools/dev/bazel.sh test \ + //:biome_format_test //:biome_lint_test //:rustfmt_test \ + //tools/ci:source_checks //tools/dev:source_checks \ + --platforms="$profile" --host_platform="$profile" --jobs=2 + ``` + + Select the relevant checks from this list. Rust owners also expose Clippy, + unit, integration and consumer targets; Clippy does not replace execution. + Shipping qualification must name actual test rules, including manual tests, + rather than relying on a `test_suite` to establish owner policy. +3. Select release-tool checks by the contract that changed: + + ```sh + # Product/version and artifact declarations: + bash tools/dev/bun.sh tools/release/check_release_please_config.mts + bash tools/dev/bun.sh tools/release/check_artifact_targets.mts + + # Release controller and pinned Release Please behavior: + bash tools/release/release-check.sh --mutation-tests-only + + # Metadata plus the release-owned controller suites: + bash tools/release/release-check.sh + + # Extension catalog and derived metadata: + bash tools/dev/bun.sh src/extensions/tools/check-extension-model.mts --check + ``` + + Run either the aggregate or its relevant constituents once. These checks do + not compile products or qualify installed consumers. Workflow and local-action + changes use `//tools/ci:source_checks`, whose pinned actionlint, zizmor and + ShellCheck checks include behavioral regressions; actionlint alone is + insufficient. Hosted permissions, environments and artifact handoffs still + need actual exact-source CI proof. +4. For a producer source, patch, recipe or toolchain change, construct and test + that owner's affected output. Package-only and test-only edits should reuse + unchanged compiler outputs. Use `tools/bazel/README.md` for Linux native, + WASIX AOT, browser and captured cross-host consumer commands. Keep module + acquisition strict; ordinary commands verify `MODULE.bazel.lock`. Intentional + repins update it with `bazel.sh mod deps --lockfile_mode=update` and review the + resulting pins, rather than ignoring lock failures. +5. Run SDK tests against the actual constructed packages and their declared + dependencies. Public carriers preserve held pins, even when a current + workspace producer has the same version. Imported completed bytes need their + genuine completion and physical identity. Current source compilation is + separate from final installed admission: Swift preparation proves workspace + source checks, while selected final Swift shipping also requires its exact + installed consumer. Never relabel preparation proof as final proof. +6. Source acquisition changes require the paired Git/archive behavior test and + deterministic policy check: + + ```sh + bash src/third-party/tools/source-fetch-core.test.sh + bash src/third-party/tools/fetch-sources.sh production-all --validate-only + ``` + + Prove a changed endpoint with one live exact-pin fetch. Require bounded + canonical-to-mirror failover, exact-pin rejection and preservation of an + existing checkout when all endpoints fail. Reachability does not belong in + the deterministic unit gate. Declare required tools and SDKs through the + owner's Bazel rule/toolchain, including execution-platform constraints. +7. Treat runner-image pins as toolchain inputs. Avoid mutable `*-latest` aliases. + Check the actual ELF, Mach-O or Android API contract after a relevant change. + Cross-compilation proves construction; native host/device execution remains + separate. Record the Bash actually used by macOS Shell paths. Keep focused + Bash 3.2 behavior checks where scripts claim that compatibility; do not impose + the entire Linux controller suite on macOS `/bin/bash`. + +Shared construction stays on Linux where reproducible. macOS and Windows own +licensed SDK work and native execution; Android/iOS behavior needs the actual +supported device or simulator. Use existing source-bound archive transports, +not another resolver, remote executor or hand-maintained product matrix. ## GitHub qualification -- Identify runs by workflow plus exact `headSha`; never accept “latest successful on branch.� -- A manual exact-main dispatch compares against `format('{0}^', github.sha)`, - the dispatched commit's immutable sole parent. Never fall back to - `origin/main` for a main dispatch: after a merge that moving ref is the - dispatched head itself and turns release-intent validation into an invalid - self-comparison. Non-main diagnostic dispatches retain their explicit - comparison to current `origin/main`. -- The `pull_request.closed` event is a runnerless cancellation tombstone. It - shares the PR concurrency group so merging cancels obsolete PR work, while - every root and `always()` aggregate job skips before runner allocation. It - cannot refund PR work that already completed. For an explicitly authorized - one-hosted-run recovery, keep CI disabled through every intermediate update - and the final merge, then enable it and manually dispatch exactly once from - the final `main` SHA. Do not also create a push run: non-PR runs for the same - SHA serialize rather than cancel one another. -- The release prerequisite is the non-cancelled `Qualified` gate for that SHA, including required checks, builds, policy, tests, and selected E2E. -- When WASIX or an extension is selected, require the same-run full lifecycle evidence artifact. It must cover every catalogued extension in direct, server, restart, materialization, and physical backup/restore modes and satisfy `--require-current-evidence` for the candidate source digest. -- Ensure artifact attestations and the publication lock reference the same SHA/tree. -- Require artifact evidence for the compatibility floors in - `src/docs/maintainers/release.md`: inspect Mach-O load commands, Android API/ELF - metadata, and Linux ELF symbol versions rather than inferring support from a - runner or package label. -- Do not rerun duplicate downstream E2E workflows when the same evidence is already part of the required gate. -- On failure, inspect the failing job log and earliest causal error. Fix the cause, push a new SHA, and restart qualification; do not reuse artifacts from the failed SHA. -- A release preparation failure is not failed CI qualification. Before - publication starts, an allowlisted release-control fix may consume a prior - successful exact-source run through `qualification_run_id`. Require the - controller's `Required` gate, preserve the original source/run identity, and - never rebuild producers or substitute a different run. +- Resolve the exact workflow, source SHA/tree, run, attempt and producing job; + never accept “latest successful on branch.� Closed PR events cancel stale PR + work and allocate no qualification runners. +- `bazel.yml` runs the source-owned configured exports. The release-inputs job + acquires one immutable public-input pool for ordinary source or the canonical + authenticated Prepare snapshot for a generated release tree. Each consumer + validates and imports those same physical inputs. +- Required first checks all predecessor jobs, then audits retained construction + across all 27 products. It does not require itself as a producer or grant + publication authority. Missing producer, source, carrier, supplier or owner + qualification coverage fails closed. +- A generated release PR or queued release tree must resolve the canonical + Prepare producer and exact version-only source bridge. A mixed queue tree + cannot substitute its branch name or synthetic title for that proof. +- Main preparation uses an exact successful Native run and Required gate. + Publication additionally authenticates final selected outputs, complete + supplier coverage and the prepared-source bridge. Selected Swift final + admission requires the source-owned final export and installed consumer. +- Require the actual extension SQL/lifecycle, browser, host and device results + declared by each owner. A passing build or ABI comparison alone does not + replace those tests. Preserve final archives and seed receipt/frozen pairs; + the full action DAG remains evidence even when cached intermediate objects + are not materialized. +- Fix the earliest causal failure and qualify a new source SHA. Do not reuse a + failed or wrong-source packet, widen scope from unknown facts, fabricate old + constructor history or create another download path to bypass authentication. +- Pre-publication recovery may use an explicit exact-source qualification after + allowlisted control fixes. Preserve original source/run/file identity and + require the current controller's Native Required gate; never rebuild producers. + +Ordinary branch work, source qualification and release-PR preparation do not use +`release-bootstrap` credentials. Setup findings do not justify provisioning or +relabeling credentials for an unrelated source run. Keep actual permission, +source and artifact checks intact. -## Report +## Declared requirements and frozen consumers -List commands and outcomes, skipped lanes with reasons, exact GitHub run/SHA, required gate state, produced artifact/lock evidence, WASIX lifecycle evidence when selected, and residual platform gaps. “Green CI� without exact-SHA and gate names is not release evidence. +Conventional manifests own consumer requirements. Only observed compiled +incorporation, Release Please ecosystem updates and necessary explicit/default +install adoption justify generated retargets. ABI compatibility or co-selection +alone does not retarget a held consumer. Native, WASIX, resources, tools, SDKs, +bindings and external extensions retain independent versions. + +External host references declare `public_support`. Removing a public host needs +breaking intent before version calculation and verification against its previous +immutable product tag. Private dependency changes do not automatically imply a +public breaking change. + +Source qualification and candidate freezing precede `Frozen consumers` and +`Publication ready`; both gates are required before protected mutation. The +consumer proof binds the lock, expected cases, configuration and producing +run/attempt. Recovery imports the same bytes and reruns required consumers. +npm staging keeps complete manifests and historical pins; Cargo source patches +are staging evidence, not registry provenance. Retain public postpublication +checks and immutable-state reconciliation. -## Declared requirements and frozen consumers +## Report -Conventional manifests own source consumer requirements. Compiled inputs, -Release Please ecosystem updates and necessary default SDK/extension install -updates justify generated retargets. Candidate preparation coordinates only the -required dependency closure when exact extension hosts change; compatible SDK -and extension updates and runtime-only releases keep independent scope. Admission -checks the resulting default install against unchanged immutable releases. -External extension host references declare `public_support = true`; private -references declare `false`. Public host removal requires breaking intent before -version selection and verification against the previous immutable product tag. - -Source `Qualified` and capsule preparation precede final installed consumer -checks. Require `Frozen consumers` and `Publication ready` before bootstrap or -normal mutation. The immutable consumer proof binds the lock, expected cases, -test configuration, producing run/attempt and resolver/log evidence. Recovery -imports prepared bytes and reruns these cases; an old missing/failed proof does -not invalidate the bytes. Record installation, compilation/link and execution -levels honestly. npm staging preserves full manifests and historical pins; -Cargo path patches are staging evidence, not registry provenance. Keep the -postpublication public checks and reconciliation. +Report commands and outcomes, exact source/run identities, Required and consumer +gate states, original artifact/lock evidence and remaining platform gaps. +Distinguish construction, install, compile/link and execution proof. “Green CI� +without exact identity and gate names is not release evidence. diff --git a/.codex/skills/release-oliphaunt/SKILL.md b/.codex/skills/release-oliphaunt/SKILL.md index dd459ac35..dc41391e8 100644 --- a/.codex/skills/release-oliphaunt/SKILL.md +++ b/.codex/skills/release-oliphaunt/SKILL.md @@ -11,19 +11,17 @@ The `publish` operation prepares the complete candidate once, conditionally runs frozen installed consumers, requires Publication ready, bootstraps missing names, and publishes it. Dependent jobs install the same immutable candidate and verify its complete contents against the lock. -Qualification may be exhaustive or selected through CI's -`release_products_json` input with every platform selector at `all`. The -existing candidate record binds product scope, required tasks and exact SHA; -publication rejects a product outside that scope. Generated release PRs and -their main merge derive scope automatically from the actual manifest transition; -only main push or eligible main dispatch can produce publishable evidence. -Publication first reuses covering completed CI or awaits an active main/requested -run. If none exists, a separate dispatch-only job requests CI for the selected -products, provided main still equals the exact candidate SHA. Failed causal -runs stop with their URL; resume by rerunning that run. An ambiguous dispatch -is never retried automatically. Pre-publication recovery may reuse an explicit -exact-source CI run after allowlisted release-control fixes; source and binary -identities remain unchanged. +Native qualification records configured shipping roots, required tests and +original final archives for the exact source SHA/tree and producing Actions +run. Preparation requires complete product/platform coverage before choosing +release scope. Generated release PR qualification imports its source-bound +Prepare inputs; an ordinary source run imports one immutable public-input pool. +Only exact-main qualification can admit publication. PR evidence remains +construction evidence. Publication reuses authenticated original files and +rejects missing, failed or wrong-source coverage. Pre-publication recovery may +reuse an explicit exact-source run after allowlisted release-control fixes; +source and binary identities remain unchanged. During migration, legacy CI is +retained for parity until the complete native run and seed adoption anchor pass. Local checks use `bash tools/release/release-check.sh` for source metadata/release-tool tests and `bash tools/release/release-check-registries.sh @@ -72,11 +70,12 @@ and do not treat target/ecosystem carriers as additional products. solo-release blocker. The bootstrap job still checks required credentials against the approved lock immediately before it publishes. 7. Generate trusted-publisher work from the approved publication lock with `bash tools/release/trusted-publisher-config.sh`. Its default mode is offline/read-only. Use authenticated `--audit` before considering `--apply`; mutation additionally requires the exact printed lock digest. Run npm audit and apply directly in a terminal because each classification pass starts with a discarded read-only TTY authentication warm-up before the bounded captured reads, and supply a fresh `--output` path for the atomically created mode-`0600` JSON evidence. Configure the direct workflow `release.yml` and `release-publish` environment. Keep release credentials only in their protected environments; do not add repository-level copies or a reusable-workflow secret bridge. -8. On a generated release PR, treat Release Please as the candidate authority - and `sync-release-pr.mts` as the deterministic selected-candidate metadata - closer. The pinned Release Please library selects shared-contrib candidates - through the declared release-ownership graph; sync chooses no new versions - or changelogs. Ordinary task dependencies are not automatic release bumps. +8. On a generated release PR, native preparation supplies delivery and necessary + compatibility-adoption selection. Pinned Release Please owns version and + changelog calculation; `sync-release-pr.mts` closes the selected candidate's + metadata and chooses no new versions or changelogs. Contrib follows its + actual native/WASIX shipping owners. Ordinary build or test dependencies are + not automatic release bumps. In an isolated clean checkout, `bash tools/release/prepare-release-pr.sh OUTPUT_DIR` generates locally. If `OUTPUT_DIR/required` is `true`, `bash tools/release/close-release-candidate.sh OUTPUT_DIR` commits locally, @@ -125,8 +124,10 @@ another repository mutation. - Prepare: synchronize release-owned files, run release checks, create the generated release PR, and stop for review. - Bootstrap: use the dedicated bootstrap environment only for identities that cannot use trusted publishing until their first package exists, including generated part identities introduced by a future lock. For npm, require a short-lived granular token with explicit `@oliphaunt` scope selection, Packages and scopes `Read and write`, and 2FA bypass, owned by a 2FA-enabled actor with scope write access; an ordinary token can authenticate yet fail the noninteractive publish with `EOTP`. The `publish` operation prepares `oliphaunt-publication-lock` and `oliphaunt-publication-candidate` first, then passes immutable artifact IDs to this conditional job. Publish only those frozen Cargo/npm bytes without rebuilding. Inventory the exact lock first and freeze only wholly absent names into the carrier-level bootstrap ledger; leave existing names awaiting the locked version for normal trusted publication. Provision only the registry token required by that scope. On rerun, a scoped name that exists without the exact version is a conflict. Model crates.io's documented token bucket; never accept an unverifiable numeric capacity assertion. Execute one sequential Cargo lane and one sequential npm lane, overlap only independent carriers, and preserve dependencies within the absent-name scope. A scoped npm package may leave an optional dependency on an existing name to the normal trusted-publication graph; other unavailable locked dependencies fail closed. If one hosted job cannot finish, drain in-flight uploads, reconcile receipts, upload the canonical hash-chained checkpoint, and fail as incomplete with the exact manual rerun command and not-before time. The maintainer reruns the failed job of that original workflow run; the rerun restores only the same release/lock/candidate identity and skips byte-matching public versions. A valid `429 Retry-After` may defer; ambiguous uploads, timeouts, integrity mismatches, malformed responses, and checkpoint failures remain hard failures. After every scoped identity has a receipt, use that exact lock with `tools/release/trusted-publisher-config.sh`: its default plan has no network access, `--audit` is read-only, and mutation requires both `--apply` and the exact `--confirm-lock-digest`. Run npm audit/apply in a real TTY and retain each fresh `--output` JSON report, never the discarded authentication warm-up display. Require workflow `release.yml`, environment `release-publish`, and npm publish-only permission; reject extra or mismatched configurations. Publication continues automatically. Configure trusted publishers and revoke bootstrap credentials before the next release. - Publish: prepare the frozen candidate, bootstrap absent Cargo/npm names if - needed, then publish in the same run. Require a successful exact-SHA `Qualified` gate, complete artifact - set, frozen publication lock, and exact Release Please PR markability proof. + needed, then publish in the same run. Require the exact-source + `Native Bazel qualification` workflow with its successful `Required` gate, + complete artifacts, frozen publication lock and exact Release Please PR + markability proof. Pin the immutable transport, stage GitHub drafts/assets/attestations, attempt the complete dependency-ordered registry plan once, verify public consumers, and promote last in one protected job. Do not predict registry capacity or @@ -168,15 +169,16 @@ bash tools/release/release-check.sh bash src/extensions/tools/check-extension-model.sh --check ``` -Release Please selects direct candidates from configured product paths. The -ownership plugin also supplies commits affecting declared shared shipped sources, -bounded by each product's published history. Review that selection against the -actual changed behavior; correct missing ownership in the graph rather than -copying source or adding repository-meta fingerprints to force a candidate. +Native preparation compares configured production observations and delivered +payloads with each product's authenticated completed publication. It selects +changed owners and necessary compatibility adoption, then passes bounded commit +intent to pinned Release Please for version calculation. Unknown history or +incomplete carrier coverage blocks preparation. Review the decision against +actual delivery changes; fix missing production inputs instead of copying source +or adding repository fingerprints to force a candidate. -For a normalized generated release PR, ordinary Moon task dependencies affect -qualification; declared release ownership controls shared-source candidate -selection. Native, WASIX, SDKs, bindings, resources, tools and external extensions are +For a normalized generated release PR, Bazel dependencies determine construction +and verification. A dependency edge alone does not select another release. Native, WASIX, SDKs, bindings, resources, tools and external extensions are independently versioned. Sync preserves authored requirements and projects the actual input versions for selected compiled payloads. Release Please ecosystem updates remain authoritative; unselected consumers retain their older published pins. A selected @@ -220,7 +222,7 @@ External extension host references declare `public_support = true`; private references declare `false`. Public host removal requires breaking intent before version selection and verification against the previous immutable product tag. -Source `Qualified` and capsule preparation precede final installed consumer +Source qualification and capsule preparation precede final installed consumer checks. Require `Frozen consumers` and `Publication ready` before bootstrap or normal mutation. The immutable consumer proof binds the lock, expected cases, test configuration, producing run/attempt and resolver/log evidence. Recovery diff --git a/.codex/skills/release-oliphaunt/references/invariants.md b/.codex/skills/release-oliphaunt/references/invariants.md index d0ff42dbd..4d805da9d 100644 --- a/.codex/skills/release-oliphaunt/references/invariants.md +++ b/.codex/skills/release-oliphaunt/references/invariants.md @@ -14,11 +14,12 @@ record that publishing identity separately. - Extension evidence runs are immutable observations. Claim regeneration never changes them, and current WASIX support is qualified only by the full lifecycle collector running against same-workflow exact-SHA artifacts and recording that commit/tree/run identity. - The publication lock is exhaustive: reject undeclared and missing packages/assets as well as hash, size, dependency, target, or version drift. -- Release Please selects direct candidates from configured product paths and - receives shared shipped-source commits from the declared release-ownership - graph, bounded by each product's published history. Ordinary task dependency - edges alone do not bump consumers. Correct missing ownership instead of copying - source or creating repository-meta fingerprints to force selection. +- Native preparation selects delivery changes against each product's authenticated + completed publication, then closes necessary compatibility adoption. Release + Please alone calculates the selected owners' versions from bounded commit + intent. A build or test dependency alone does not require a release. Source, + tool and recipe ownership comes from configured production actions; do not + copy source or add repository fingerprints to force selection. - The preparation job generates the lock after artifact assembly and freezes every locked file in one candidate. Installed consumer cases must prove that candidate and Publication ready must succeed before any bootstrap or normal diff --git a/.github/actions/bazel-cache/action.yml b/.github/actions/bazel-cache/action.yml new file mode 100644 index 000000000..293512f14 --- /dev/null +++ b/.github/actions/bazel-cache/action.yml @@ -0,0 +1,150 @@ +name: Transport bounded Bazel action cache +description: Restore or save the standard Bazel action cache for one qualification cohort. + +inputs: + phase: + description: restore before qualification or save after its final Bazel invocation. + required: true + cohort: + description: Stable qualification job identity; operating system and architecture remain separate. + required: true + output-base: + description: Exact output base used by this cohort, if explicitly selected. + default: "" + jvm-args: + description: Exact host JVM argument used by this cohort, if explicitly selected. + default: "" + server-log: + description: Exact server JVM output path used by this cohort, if explicitly selected. + default: "" + disk-cache-hit: + description: Primary action cache hit returned by the restore phase. + default: "false" + +outputs: + disk-cache-hit: + description: Whether the immutable action cache key already exists. + value: ${{ steps.disk-restore.outputs.cache-hit }} + +runs: + using: composite + steps: + - name: Select canonical cache identity + id: identity + if: ${{ inputs.phase == 'save' || !cancelled() }} + shell: bash + env: + PHASE: ${{ inputs.phase }} + COHORT: ${{ inputs.cohort }} + run: | + set -euo pipefail + case "$PHASE" in restore|save) ;; *) exit 1 ;; esac + [[ "$COHORT" =~ ^[a-z0-9][a-z0-9-]*$ ]] + version="$(tr -d '\r' < .bazelversion)" + [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] + source_commit="$(git rev-parse HEAD)" + [[ "$source_commit" =~ ^[0-9a-f]{40}$ ]] + gc_max_size=2G + cache_limit_kib=3145728 + # These three observed cache populations reached 3.4 to 3.6 GiB before collection. + case "$RUNNER_OS/$RUNNER_ARCH/$COHORT" in + macOS/ARM64/portable|Linux/X64/linux|Linux/X64/portable) gc_max_size=4G; cache_limit_kib=5242880 ;; + esac + printf 'prefix=bazel-ci-v1-%s-%s-%s-%s\nsource=%s\n' \ + "$RUNNER_OS" "$RUNNER_ARCH" "$COHORT" "$version" "$source_commit" >> "$GITHUB_OUTPUT" + printf 'gc_max_size=%s\ncache_limit_kib=%s\n' \ + "$gc_max_size" "$cache_limit_kib" >> "$GITHUB_OUTPUT" + + - name: Restore Bazel action cache + id: disk-restore + if: inputs.phase == 'restore' + continue-on-error: true + uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 + with: + path: ~/.cache/oliphaunt/bazel-ci/disk + key: ${{ steps.identity.outputs.prefix }}-disk-${{ steps.identity.outputs.source }} + restore-keys: | + ${{ steps.identity.outputs.prefix }}-disk- + + - name: Configure standard hosted Bazel caches + if: inputs.phase == 'restore' + shell: bash + run: | + set -euo pipefail + cache_root="$HOME/.cache/oliphaunt/bazel-ci" + # Downloads remain a per-job content-addressed cache, not hosted archives. + mkdir -p "$cache_root/disk" "$cache_root/repositories" + if [[ "$RUNNER_OS" == Windows ]]; then + cache_root="$(cygpath -m "$cache_root")" + fi + # Hosted user configuration stays outside source and cache transport. + printf '\nbuild --config=ci-cache\nbuild --disk_cache="%s/disk"\ncommon --repository_cache="%s/repositories"\n' \ + "$cache_root" "$cache_root" >> "$HOME/.bazelrc" + + - name: Freeze, collect and bound cache transport + id: ready + if: ${{ always() && inputs.phase == 'save' && steps.identity.outcome == 'success' && inputs.disk-cache-hit != 'true' }} + continue-on-error: true + shell: bash + env: + OUTPUT_BASE: ${{ inputs.output-base }} + JVM_ARGS: ${{ inputs.jvm-args }} + SERVER_LOG: ${{ inputs.server-log }} + GC_MAX_SIZE: ${{ steps.identity.outputs.gc_max_size }} + CACHE_LIMIT_KIB: ${{ steps.identity.outputs.cache_limit_kib }} + run: | + set -euo pipefail + startup=(bash tools/dev/bazel.sh) + [[ -z "$OUTPUT_BASE" ]] || startup+=("--output_base=$OUTPUT_BASE") + [[ -z "$JVM_ARGS" ]] || startup+=("--host_jvm_args=$JVM_ARGS") + [[ -z "$SERVER_LOG" ]] || startup+=("--server_jvm_out=$SERVER_LOG") + freeze_writer() { + if ! "${startup[@]}" shutdown; then + printf 'Bazel cache writer shutdown: failure\n' >&2 + return 1 + fi + printf 'Bazel cache writer shutdown: success\n' + } + # Later commands can need lazy outputs from this cache. Collect only + # after final qualification; snapshots within the budget need no GC. + freeze_writer || exit 0 + cache_limit_kib="$CACHE_LIMIT_KIB" + cache_root="$HOME/.cache/oliphaunt/bazel-ci/disk" + if [[ -d "$cache_root" ]]; then + printf 'Bazel cache disk: present=true\n' + cache_kib="$(du -sk "$cache_root" | cut -f1)" + if [[ "$cache_kib" =~ ^[0-9]+$ ]] && (( cache_kib > cache_limit_kib )); then + gc_target=//tools/ci:bazel_disk_cache_gc + "${startup[@]}" build --jobs=2 "$gc_target" + gc_tool="$("${startup[@]}" cquery "config($gc_target, target)" --output=starlark \ + '--starlark:expr=providers(target)["DefaultInfo"].files_to_run.executable.path')" + freeze_writer || exit 0 + gc_root="$cache_root" + if [[ "$RUNNER_OS" == Windows ]]; then + gc_root="$(cygpath -m "$gc_root")" + fi + # The stock collector returns after collection completes. Its + # logical-byte target does not replace the allocated archive bound. + JAVABIN= "$gc_tool" "--disk_cache=$gc_root" "--max_size=$GC_MAX_SIZE" + cache_kib="$(du -sk "$cache_root" | cut -f1)" + fi + printf 'Bazel cache disk: allocated_kib=%s limit_kib=%s\n' \ + "$cache_kib" "$cache_limit_kib" + # An unused directory must not replace a useful fallback snapshot. + if [[ "$cache_kib" =~ ^[0-9]+$ ]] && (( cache_kib <= cache_limit_kib )) && + [[ -n "$(find "$cache_root" -type f -print -quit)" ]]; then + printf 'disk=true\n' >> "$GITHUB_OUTPUT" + fi + else + printf 'Bazel cache disk: present=false\n' + fi + + # GitHub isolates pull_request saves under refs/pull//merge. + # This optional cache contains action results, never release authority. + - name: Save bounded Bazel action cache + if: ${{ always() && inputs.phase == 'save' && steps.ready.outputs.disk == 'true' }} + continue-on-error: true + uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 + with: + path: ~/.cache/oliphaunt/bazel-ci/disk + key: ${{ steps.identity.outputs.prefix }}-disk-${{ steps.identity.outputs.source }} diff --git a/.github/actions/native-release-inputs/action.yml b/.github/actions/native-release-inputs/action.yml new file mode 100644 index 000000000..eb42bfd8f --- /dev/null +++ b/.github/actions/native-release-inputs/action.yml @@ -0,0 +1,73 @@ +name: Acquire native release inputs +description: Retain source-bound public inputs or authenticate the exact Prepare producer. + +inputs: + run-id: + description: Successful exact-source Release preparation run. + required: false + pull-number: + description: Canonical release PR whose reviewed tree is being qualified. + required: false + public-artifact-id: + description: Immutable public-input artifact ID produced by this qualification run. + required: false + +runs: + using: composite + steps: + - name: Validate input acquisition mode + shell: bash + env: + PREPARE_RUN_ID: ${{ inputs.run-id }} + PREPARED_PULL_NUMBER: ${{ inputs.pull-number }} + PUBLIC_ARTIFACT_ID: ${{ inputs.public-artifact-id }} + run: | + if [[ -n "$PUBLIC_ARTIFACT_ID" ]]; then + [[ "$PUBLIC_ARTIFACT_ID" =~ ^[1-9][0-9]*$ && -z "$PREPARE_RUN_ID" && -z "$PREPARED_PULL_NUMBER" ]] + else + [[ "$PREPARE_RUN_ID" =~ ^[1-9][0-9]*$ && "$PREPARED_PULL_NUMBER" =~ ^[1-9][0-9]*$ ]] + fi + + - name: Install locked release tooling + shell: bash + run: bash tools/dev/bun.sh install --frozen-lockfile --filter @oliphaunt/release-tools --ignore-scripts + + - name: Download this run's public inputs + if: inputs.public-artifact-id != '' + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + artifact-ids: ${{ inputs.public-artifact-id }} + path: ${{ runner.temp }}/native-public-inputs + + - name: Import source-bound public inputs + if: inputs.public-artifact-id != '' + shell: bash + run: | # zizmor: ignore[github-env] only a source-validated runner-temp snapshot path is exported. + snapshot="$(bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh \ + tools/release/native-release-inputs.mts \ + --import-public-inputs "$RUNNER_TEMP/native-public-inputs")" + snapshot_fs="$snapshot" + if [[ "$RUNNER_OS" == Windows ]]; then + snapshot_fs="$(cygpath -u "$snapshot")" + fi + test -f "$snapshot_fs" + printf 'OLIPHAUNT_NATIVE_PUBLICATION_INPUTS=%s\n' "$snapshot" >> "$GITHUB_ENV" + + - name: Retain authenticated prepared construction inputs + if: inputs.public-artifact-id == '' + shell: bash + env: + PREPARE_RUN_ID: ${{ inputs.run-id }} + PREPARED_PULL_NUMBER: ${{ inputs.pull-number }} + GH_TOKEN: ${{ github.token }} + run: | # zizmor: ignore[github-env] only an authenticated runner-temp snapshot path is exported. + snapshot="$(bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh \ + tools/release/native-release-inputs.mts \ + --run-id "$PREPARE_RUN_ID" --pull-number "$PREPARED_PULL_NUMBER" \ + --output-directory "$RUNNER_TEMP/native-prepared-inputs")" + snapshot_fs="$snapshot" + if [[ "$RUNNER_OS" == Windows ]]; then + snapshot_fs="$(cygpath -u "$snapshot")" + fi + test -f "$snapshot_fs" + printf 'OLIPHAUNT_NATIVE_PUBLICATION_INPUTS=%s\n' "$snapshot" >> "$GITHUB_ENV" diff --git a/.github/actions/setup-apple/action.yml b/.github/actions/setup-apple/action.yml index 85dc139f8..5ed92fa44 100644 --- a/.github/actions/setup-apple/action.yml +++ b/.github/actions/setup-apple/action.yml @@ -9,7 +9,7 @@ inputs: xcode-minor: description: Supported Xcode minor version installed on the pinned macOS runner image. required: false - default: "26.5" + default: "" runs: using: composite @@ -18,16 +18,19 @@ runs: shell: bash env: REQUESTED_XCODE_MINOR: ${{ inputs.xcode-minor }} - SUPPORTED_XCODE_MINOR: "26.5" run: | # zizmor: ignore[github-env] DEVELOPER_DIR is an exact, allowlisted runner-owned Xcode bundle path. set -euo pipefail + host_policy="tools/dev/native-host-toolchains.json" + SUPPORTED_XCODE_MINOR="$(plutil -extract apple.xcode_version raw -o - "$host_policy")" + developer_dir="$(plutil -extract apple.developer_dir raw -o - "$host_policy")" + REQUESTED_XCODE_MINOR="${REQUESTED_XCODE_MINOR:-$SUPPORTED_XCODE_MINOR}" + if [[ "$REQUESTED_XCODE_MINOR" != "$SUPPORTED_XCODE_MINOR" ]]; then echo "setup-apple: unsupported Xcode minor '$REQUESTED_XCODE_MINOR'; expected $SUPPORTED_XCODE_MINOR" >&2 exit 1 fi - developer_dir="/Applications/Xcode_26.5.app/Contents/Developer" if [[ ! -d "$developer_dir" ]]; then echo "setup-apple: required Xcode developer directory was not found at $developer_dir" >&2 exit 1 diff --git a/.github/scripts/check-release-intent.sh b/.github/scripts/check-release-intent.sh index bc010efcb..dc3675c1b 100755 --- a/.github/scripts/check-release-intent.sh +++ b/.github/scripts/check-release-intent.sh @@ -7,6 +7,11 @@ head_ref="${3:-HEAD}" head_branch="${4:-}" event_name="${5:-}" full_ref="${6:-}" +policy_mode="${7:-}" +if [[ -n "$policy_mode" && "$policy_mode" != --source-policy-only ]]; then + echo "unknown release-intent policy mode: $policy_mode" >&2 + exit 1 +fi if [[ -z "${subject}" ]]; then echo "expected a non-empty PR title or commit subject" >&2 @@ -140,22 +145,31 @@ if [[ "${is_release_pr}" == true ]]; then echo "release PRs must contain one normalized release-bump commit directly on the current base" >&2 exit 1 fi - release_products_json="$( + if [[ "$policy_mode" != --source-policy-only ]]; then + release_products_json="$( + bash tools/release/release-please-state.sh "$PWD" HEAD bash tools/release/with-release-history.sh "$PWD" "${head_ref}" tools/dev/bun.sh tools/release/verify-release-commit.mts \ + --derive-products \ + --head-ref "${head_ref}" + )" bash tools/release/release-please-state.sh "$PWD" HEAD bash tools/release/with-release-history.sh "$PWD" "${head_ref}" tools/dev/bun.sh tools/release/verify-release-commit.mts \ - --derive-products \ + --products-json "${release_products_json}" \ --head-ref "${head_ref}" - )" - bash tools/release/release-please-state.sh "$PWD" HEAD bash tools/release/with-release-history.sh "$PWD" "${head_ref}" tools/dev/bun.sh tools/release/verify-release-commit.mts \ - --products-json "${release_products_json}" \ - --head-ref "${head_ref}" - consumer_products_json="${release_products_json}" + consumer_products_json="${release_products_json}" + fi elif [[ "${event_name}" == workflow_dispatch && "${full_ref}" == refs/heads/main && "${CI_RELEASE_PRODUCTS_JSON:-[]}" != '[]' ]]; then consumer_products_json="${CI_RELEASE_PRODUCTS_JSON}" fi -if [[ -n "${consumer_products_json}" ]]; then +if [[ -n "${consumer_products_json}" && "$policy_mode" != --source-policy-only ]]; then bash tools/release/with-product-history.sh "$PWD" "${head_ref}" '' @workspace bash tools/dev/bun.sh tools/release/consumer-compatibility.mts "${consumer_products_json}" fi +# Native construction decides delivery changes before Release Please runs. +# The native context separately authenticates the exact successful Prepare tree +# and its configured suppliers; these guards never recalculate that selection. +if [[ "$policy_mode" == --source-policy-only ]]; then + exit 0 +fi + release_plan="$(bash tools/release/release-plan.sh --base-ref "${base_ref}" --head-ref "${head_ref}" --format json)" release_products="$( bun "$(dirname "${BASH_SOURCE[0]}")/release-intent-data.mts" products <<<"${release_plan}" diff --git a/.github/scripts/download-build-artifacts.mts b/.github/scripts/download-build-artifacts.mts index 6f1905c5c..a9df8986c 100644 --- a/.github/scripts/download-build-artifacts.mts +++ b/.github/scripts/download-build-artifacts.mts @@ -30,17 +30,22 @@ import { } from '../../tools/packaging/atomic-directory.mts'; import { validateZipEntryTypes } from '../../tools/packaging/portable-archive.mts'; import { + githubJobArtifact, + githubReadOptionsFromEnv, isRetryableGitHubReadError, + latestGithubJob, + matchesGithubWorkflowRef, RetryableReadError, requestGithubDownload, requestGithubJsonWithRetry, requestGithubPages, + retryReadOperation, } from '../../tools/release/github-read.mts'; import { mergeChecksumManifest } from './merge-checksum-manifest.mts'; const USAGE = 'usage: download-build-artifacts.sh [--run-id ] [--job ] ' + - '[--artifact-metadata-json ] --artifact [--artifact ...]'; + '[--artifact-metadata-json ] [--job-success-only --job-attempt --workflow-path --event --ref --run-attempt --source-tree ] --artifact [--artifact ...]'; const SNAPSHOT_SCHEMA = 'oliphaunt-github-actions-run-snapshot-v1'; const FULL_SHA = /^[0-9a-f]{40}$/u; const MAX_CAPTURE_BYTES = 128 * 1024 * 1024; @@ -68,6 +73,13 @@ function parseArgs(argv) { requiredJob: '', selectedRunId: '', artifactMetadataJson: '', + workflowPath: '', + event: '', + ref: '', + runAttempt: '', + jobAttempt: '', + sourceTree: '', + jobSuccessOnly: false, }; for (let index = 0; index < rest.length; ) { const arg = rest[index]; @@ -83,6 +95,30 @@ function parseArgs(argv) { } else if (arg === '--artifact-metadata-json') { args.artifactMetadataJson = valueAfter(rest, index, '--artifact-metadata-json requires JSON'); index += 2; + } else if (arg === '--job-success-only' && !args.jobSuccessOnly) { + args.jobSuccessOnly = true; + index += 1; + } else if ( + [ + '--workflow-path', + '--event', + '--ref', + '--run-attempt', + '--job-attempt', + '--source-tree', + ].includes(arg) + ) { + const key = { + '--workflow-path': 'workflowPath', + '--event': 'event', + '--ref': 'ref', + '--run-attempt': 'runAttempt', + '--job-attempt': 'jobAttempt', + '--source-tree': 'sourceTree', + }[arg]; + if (args[key] !== '') fail(`duplicate argument: ${arg}`, 2); + args[key] = valueAfter(rest, index, `${arg} requires a value`); + index += 2; } else { fail(`unknown argument: ${arg}`, 2); } @@ -103,6 +139,22 @@ function parseArgs(argv) { 2, ); } + if (args.jobSuccessOnly && (!args.selectedRunId || !args.requiredJob)) + fail('--job-success-only requires an exact --run-id and --job', 2); + if ( + args.runAttempt && + (!/^[1-9][0-9]*$/u.test(args.runAttempt) || !Number.isSafeInteger(Number(args.runAttempt))) + ) + fail('--run-attempt requires a positive safe integer', 2); + if ( + args.jobAttempt && + (!args.jobSuccessOnly || + !/^[1-9][0-9]*$/u.test(args.jobAttempt) || + !Number.isSafeInteger(Number(args.jobAttempt))) + ) + fail('--job-attempt requires job-success-only and a positive safe integer', 2); + if (args.sourceTree && !FULL_SHA.test(args.sourceTree)) + fail('--source-tree requires an exact SHA', 2); return args; } @@ -223,6 +275,10 @@ function normalizeArtifact(entry, runId) { id: entry.id, name: entry.name, size_in_bytes: entry.size_in_bytes, + ...(entry.created_at === undefined ? {} : { created_at: entry.created_at }), + ...((entry.workflow_run?.head_sha ?? entry.head_sha) === undefined + ? {} + : { head_sha: entry.workflow_run?.head_sha ?? entry.head_sha }), }; } @@ -262,14 +318,12 @@ function exactExpectedArtifact(records, runId, name, expectedMetadata = null) { return observed; } -async function jobRecords(repo, runId) { - const records = await requestGithubPages( - `repos/${repo}/actions/runs/${runId}/jobs?filter=latest`, - { - itemsField: 'jobs', - label: `jobs for run ${runId}`, - }, - ); +async function jobRecords(repo, runId, options = {}) { + const records = await requestGithubPages(`repos/${repo}/actions/runs/${runId}/jobs?filter=all`, { + ...options, + itemsField: 'jobs', + label: `jobs for run ${runId}`, + }); const jobs = []; for (const job of records) { if ( @@ -287,18 +341,12 @@ async function jobRecords(repo, runId) { ) { throw new Error(`job inventory for run ${runId} contains malformed metadata`); } - jobs.push({ - conclusion: job.conclusion, - id: job.id, - name: job.name, - run_attempt: job.run_attempt, - status: job.status, - }); + jobs.push(job); } return jobs; } -function validateSnapshot(snapshot) { +function validateSnapshot(snapshot, { requireWorkflowSuccess = true, sourceTree = '' } = {}) { if ( snapshot === null || Array.isArray(snapshot) || @@ -311,8 +359,24 @@ function validateSnapshot(snapshot) { snapshot.workflowId <= 0 || typeof snapshot.workflowName !== 'string' || snapshot.workflowName.length === 0 || - snapshot.status !== 'completed' || - snapshot.conclusion !== 'success' || + (requireWorkflowSuccess && + (snapshot.status !== 'completed' || snapshot.conclusion !== 'success')) || + !['queued', 'in_progress', 'completed', 'waiting', 'pending', 'requested'].includes( + snapshot.status, + ) || + ![ + null, + 'success', + 'failure', + 'cancelled', + 'timed_out', + 'action_required', + 'neutral', + 'skipped', + 'stale', + 'startup_failure', + ].includes(snapshot.conclusion) || + (sourceTree !== '' && snapshot.headTree !== sourceTree) || !Number.isSafeInteger(snapshot.runAttempt) || snapshot.runAttempt <= 0 || !Array.isArray(snapshot.jobs) || @@ -337,35 +401,43 @@ function validateSnapshot(snapshot) { typeof job.name !== 'string' || typeof job.status !== 'string' || (job.conclusion !== null && typeof job.conclusion !== 'string') || - job.run_attempt !== snapshot.runAttempt + !Number.isSafeInteger(job.run_attempt) || + job.run_attempt <= 0 || + job.run_attempt > snapshot.runAttempt ) { throw new Error( - 'cached GitHub workflow run snapshot contains malformed or cross-attempt jobs', + 'cached GitHub workflow run snapshot contains malformed or future-attempt jobs', ); } } return { ...snapshot, artifacts }; } -async function createRunSnapshot(repo, runId) { - const data = await requestGithubJsonWithRetry( - `https://api.github.com/repos/${repo}/actions/runs/${runId}`, - ); +async function createRunSnapshot(repo, runId, options = {}) { + const read = (endpoint) => + requestGithubJsonWithRetry(`https://api.github.com/repos/${repo}/${endpoint}`, { + ...(options.deadlineMs === undefined ? {} : { deadlineMs: options.deadlineMs }), + }); + const pageOptions = () => { + if (options.deadlineMs === undefined) return {}; + const remaining = options.deadlineMs - Date.now(); + if (remaining <= 0) throw new Error('exact producer metadata convergence deadline exhausted'); + return { deadlineMs: remaining }; + }; + const data = await read(`actions/runs/${runId}`); if ( String(data?.id ?? '') !== String(runId) || !FULL_SHA.test(data?.head_sha ?? '') || !Number.isSafeInteger(data?.workflow_id) || data.workflow_id <= 0 || - data.status !== 'completed' || - data.conclusion !== 'success' || + (options.requireWorkflowSuccess !== false && + (data.status !== 'completed' || data.conclusion !== 'success')) || !Number.isSafeInteger(data.run_attempt) || data.run_attempt <= 0 ) { throw new Error(`workflow run ${runId} is malformed or not completed/success`); } - const workflow = await requestGithubJsonWithRetry( - `https://api.github.com/repos/${repo}/actions/workflows/${data.workflow_id}`, - ); + const workflow = await read(`actions/workflows/${data.workflow_id}`); if ( workflow?.id !== data.workflow_id || typeof workflow?.name !== 'string' || @@ -373,34 +445,53 @@ async function createRunSnapshot(repo, runId) { ) { throw new Error(`workflow ${data.workflow_id} metadata is malformed`); } - return validateSnapshot({ - artifacts: await artifactRecords(repo, runId), - conclusion: data.conclusion, - headSha: data.head_sha.toLowerCase(), - jobs: await jobRecords(repo, runId), - repo, - runAttempt: data.run_attempt, - runId: String(runId), - schema: SNAPSHOT_SCHEMA, - status: data.status, - workflowId: data.workflow_id, - workflowName: workflow.name, - }); + let headTree; + if (options.sourceTree) { + const commit = await read(`git/commits/${data.head_sha}`); + if (commit?.sha !== data.head_sha || !FULL_SHA.test(commit?.tree?.sha ?? '')) + throw new Error(`workflow run ${runId} source commit metadata is malformed`); + headTree = commit.tree.sha; + } + return validateSnapshot( + { + artifacts: await artifactRecords(repo, runId, pageOptions()), + conclusion: data.conclusion, + headSha: data.head_sha.toLowerCase(), + jobs: await jobRecords(repo, runId, pageOptions()), + repo, + runAttempt: data.run_attempt, + runId: String(runId), + schema: SNAPSHOT_SCHEMA, + status: data.status, + workflowId: data.workflow_id, + workflowName: workflow.name, + ...(workflow.path === undefined ? {} : { workflowPath: workflow.path }), + ...(data.path === undefined ? {} : { runWorkflowPath: data.path }), + ...(data.event === undefined ? {} : { event: data.event }), + ...(data.head_branch === undefined ? {} : { headBranch: data.head_branch }), + ...(data.pull_requests === undefined + ? {} + : { pullRequestNumbers: data.pull_requests.map((row) => row.number) }), + ...(headTree === undefined ? {} : { headTree }), + }, + options, + ); } -async function runSnapshot(repo, runId) { +async function runSnapshot(repo, runId, options = {}) { const file = snapshotFile(runId); - if (file !== null && existsSync(file)) { + if (file !== null && existsSync(file) && !options.refresh) { assertRegularSnapshotFile(file); const snapshot = validateSnapshot( parsedJson(readFileSync(file, 'utf8'), `cached run ${runId} snapshot`), + options, ); if (snapshot.repo !== repo || snapshot.runId !== String(runId)) { throw new Error(`cached run ${runId} snapshot belongs to a different repository or run`); } return snapshot; } - const snapshot = await createRunSnapshot(repo, runId); + const snapshot = await createRunSnapshot(repo, runId, options); if (file !== null) { mkdirSync(path.dirname(file), { recursive: true }); assertRegularSnapshotFile(file); @@ -420,14 +511,98 @@ function requiredJobSuccess(snapshot, requiredJob) { if (requiredJob === '') { return true; } - const matches = snapshot.jobs.filter((candidate) => candidate.name === requiredJob); - return matches.length === 1 && matches[0]?.conclusion === 'success'; + const job = latestGithubJob(snapshot, requiredJob); + return job?.status === 'completed' && job?.conclusion === 'success'; } function runMatchesRequest(snapshot, workflow, sha) { return snapshot.headSha === sha.toLowerCase() && snapshot.workflowName === workflow; } +function assertRunIdentity(snapshot, args) { + for (const [observed, expected, context] of [ + [snapshot.workflowPath, args.workflowPath, 'workflow path'], + [snapshot.runWorkflowPath, args.workflowPath, 'executed workflow path'], + [snapshot.event, args.event, 'event'], + [String(snapshot.runAttempt), args.runAttempt, 'run attempt'], + ]) + if (expected && observed !== expected) + throw new Error(`workflow run ${snapshot.runId} ${context} mismatch`); + if (args.ref) { + const matches = matchesGithubWorkflowRef(snapshot.event, args.ref, snapshot); + if (!matches) throw new Error(`workflow run ${snapshot.runId} ref mismatch`); + } + if (args.jobSuccessOnly) { + const job = latestGithubJob(snapshot, args.requiredJob); + if (args.jobAttempt && String(job?.run_attempt) !== args.jobAttempt) + throw new Error(`workflow run ${snapshot.runId} producing job attempt mismatch`); + } +} + +class PendingProducerJob extends Error {} + +async function exactProducerSnapshot(repo, args) { + let observedIdentity; + const environment = { + OLIPHAUNT_GITHUB_READ_DEADLINE_MS: '300000', + OLIPHAUNT_GITHUB_READ_MAX_ATTEMPTS: '10', + OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS: '5000', + OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS: '30000', + ...process.env, + }; + return retryReadOperation( + `exact producer ${args.requiredJob} in run ${args.selectedRunId}`, + async ({ attempt, deadlineMs }) => { + const snapshot = await runSnapshot(repo, args.selectedRunId, { + requireWorkflowSuccess: false, + sourceTree: args.sourceTree, + refresh: attempt > 1, + deadlineMs, + }); + if (!runMatchesRequest(snapshot, args.workflow, args.sha)) + fail(`${args.workflow} run ${args.selectedRunId} does not belong to commit ${args.sha}`); + assertRunIdentity(snapshot, args); + const job = latestGithubJob(snapshot, args.requiredJob); + if (!job) fail(`workflow run ${snapshot.runId} is missing required job ${args.requiredJob}`); + const identity = JSON.stringify([ + snapshot.repo, + snapshot.runId, + snapshot.headSha, + snapshot.headTree, + snapshot.workflowId, + snapshot.workflowName, + snapshot.workflowPath, + snapshot.runWorkflowPath, + snapshot.event, + snapshot.headBranch, + snapshot.pullRequestNumbers, + snapshot.runAttempt, + job.id, + job.run_attempt, + job.run_id, + job.head_sha, + ]); + if (observedIdentity !== undefined && identity !== observedIdentity) + fail('exact producer run or job identity changed while waiting for completion'); + observedIdentity = identity; + if (requiredJobSuccess(snapshot, args.requiredJob)) return snapshot; + if ( + !['queued', 'in_progress', 'waiting', 'pending', 'requested'].includes(job.status) || + job.conclusion !== null + ) + fail( + `${args.workflow} run ${snapshot.runId} does not satisfy required job ${args.requiredJob}`, + ); + throw new PendingProducerJob(`required job ${args.requiredJob} is ${job.status}`); + }, + { + classify: (error) => error instanceof PendingProducerJob, + deadlineMs: Math.min(300_000, githubReadOptionsFromEnv(environment).deadlineMs), + environment, + }, + ); +} + async function candidateRunIds(repo, workflow, sha) { const workflows = await requestGithubPages(`repos/${repo}/actions/workflows`, { itemsField: 'workflows', @@ -696,7 +871,9 @@ async function mergeDownloadedArtifact(artifact, sourceDir, destination) { async function selectRunId(repo, args) { if (args.selectedRunId !== '') { const runId = args.selectedRunId; - const snapshot = await runSnapshot(repo, runId); + const snapshot = args.jobSuccessOnly + ? await exactProducerSnapshot(repo, args) + : await runSnapshot(repo, runId, { sourceTree: args.sourceTree }); if (!runMatchesRequest(snapshot, args.workflow, args.sha)) { fail(`${args.workflow} run ${runId} does not belong to commit ${args.sha}`); } @@ -705,10 +882,23 @@ async function selectRunId(repo, args) { `${args.workflow} run ${runId} does not satisfy required job ${args.requiredJob || ''}`, ); } - for (const artifact of args.artifacts) { - exactExpectedArtifact(snapshot.artifacts, runId, artifact, args.expectedArtifactMetadata); - } - return snapshot; + assertRunIdentity(snapshot, args); + if (!args.jobSuccessOnly) + for (const artifact of args.artifacts) + exactExpectedArtifact(snapshot.artifacts, runId, artifact, args.expectedArtifactMetadata); + return args.jobSuccessOnly + ? { + ...snapshot, + artifacts: args.artifacts.map((name) => + githubJobArtifact( + snapshot, + latestGithubJob(snapshot, args.requiredJob), + name, + args.sha, + ), + ), + } + : snapshot; } for (const candidate of await candidateRunIds(repo, args.workflow, args.sha)) { @@ -719,6 +909,7 @@ async function selectRunId(repo, args) { if (!requiredJobSuccess(snapshot, args.requiredJob)) { continue; } + assertRunIdentity(snapshot, args); try { for (const artifact of args.artifacts) exactExpectedArtifact(snapshot.artifacts, candidate, artifact); diff --git a/.github/scripts/download-build-artifacts.sh b/.github/scripts/download-build-artifacts.sh index 875b0e998..1cb7ad6a7 100644 --- a/.github/scripts/download-build-artifacts.sh +++ b/.github/scripts/download-build-artifacts.sh @@ -6,12 +6,13 @@ trap 'rm -rf "$scratch"' EXIT trap 'exit 130' INT trap 'exit 143' TERM script=.github/scripts/download-build-artifacts.mts -bun "$script" download "$scratch" "$@" +runner=(bash tools/dev/bun.sh --no-env-file --no-install "$script") +"${runner[@]}" download "$scratch" "$@" while IFS= read -r -d '' directory; do archive="$directory/.artifact.zip" unzip -Z1 "$archive" > "$scratch/members" - bun "$script" validate-zip "$archive" "$scratch/members" + "${runner[@]}" validate-zip "$archive" "$scratch/members" unzip -q "$archive" -d "$directory" rm "$archive" done < "$scratch/archives" -bun "$script" merge "$scratch" +"${runner[@]}" merge "$scratch" diff --git a/.github/scripts/freeze-apple-carriers.test.sh b/.github/scripts/freeze-apple-carriers.test.sh deleted file mode 100644 index 0f0777437..000000000 --- a/.github/scripts/freeze-apple-carriers.test.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail -cd "$(git rev-parse --show-toplevel)" -scratch="$(mktemp -d)" -trap 'rm -rf "$scratch"' EXIT -export TEST_SOURCE_ROOT="$PWD" TEST_BUN="$(command -v bun)" -bun -e ' - const fs = require("node:fs"); - const assert = require("node:assert/strict"); - const workflow = Bun.YAML.parse(fs.readFileSync(".github/workflows/release.yml", "utf8")); - const step = Object.values(workflow.jobs).flatMap(job => job.steps ?? []) - .find(step => step.name === "Freeze canonical Apple extension carrier input"); - assert.equal(step.env.PRODUCTS_JSON, - "${{ fromJSON(needs.plan-candidate.outputs.release_plan).products_json }}"); - fs.writeFileSync(process.argv[1] + "/freeze.sh", step.run); -' "$scratch" -mkdir -p "$scratch/tools/dev" -cat > "$scratch/tools/dev/bun.sh" <<'SH' -#!/usr/bin/env bash -set -euo pipefail -if [[ "$1" == tools/release/query.mts ]]; then - exec "$TEST_BUN" "$TEST_SOURCE_ROOT/$1" "${@:2}" -fi -[[ "$1" == src/native/sdks/swift/tools/ios-carrier-manifest.mts ]] -printf '%s\n' "$@" >> calls -SH -chmod +x "$scratch/tools/dev/bun.sh" -cd "$scratch" -native=target/extension-artifacts/liboliphaunt-native/oliphaunt-extension-contrib-pg18 -wasix=target/extension-artifacts/liboliphaunt-wasix/oliphaunt-extension-contrib-pg18 -vector=target/extension-artifacts/oliphaunt-extension-vector -for root in "$native" "$wasix" "$vector"; do - mkdir -p "$root/release-assets" - printf '{}\n' > "$root/extension-artifacts.json" - printf '{}\n' > "$root/release-assets/fixture-swift-extension-carrier.json" -done -source_carrier=target/sdk-artifacts/oliphaunt-react-native/ios-carriers/oliphaunt-react-native-ios-carriers.json -mkdir -p "$(dirname "$source_carrier")" -printf 'frozen base carrier\n' > "$source_carrier" -export includes_swift=false includes_react_native=true -export PRODUCTS_JSON='["liboliphaunt-native","liboliphaunt-wasix","oliphaunt-extension-vector","oliphaunt-react-native"]' -bash -eo pipefail freeze.sh -rg -q -F "$native/extension-artifacts.json" calls -rg -q -F "$vector/extension-artifacts.json" calls -[[ "$(rg -c '^--extension-manifest$' calls)" == 2 ]] -! rg -q -F "$wasix" calls - -# No native extensions selected: preserve the qualified base, even with unrelated artifacts present. -rm calls -PRODUCTS_JSON='["oliphaunt-react-native","liboliphaunt-wasix"]' bash -eo pipefail freeze.sh -cmp "$source_carrier" target/release/ios-carriers/oliphaunt-react-native-ios-carriers.json -[[ ! -e calls ]] -for selection in '' malformed '["unknown-product"]'; do - if PRODUCTS_JSON="$selection" bash -eo pipefail freeze.sh > failure 2>&1; then - echo 'invalid Apple carrier selection was accepted' >&2; exit 1 - fi - [[ ! -e calls ]] -done -rm "$native/extension-artifacts.json" -if bash -eo pipefail freeze.sh > failure 2>&1; then - echo 'missing selected manifest was accepted' >&2; exit 1 -fi -rg -q 'Selected extension product .* is missing' failure -[[ ! -e calls ]] -echo 'Apple carrier selection: native-only inputs, empty selection and query failures passed' diff --git a/.github/scripts/release-candidate-lib.mts b/.github/scripts/release-candidate-lib.mts index e7daf5ecf..b75ec3cbc 100644 --- a/.github/scripts/release-candidate-lib.mts +++ b/.github/scripts/release-candidate-lib.mts @@ -2,6 +2,11 @@ import { createHash } from 'node:crypto'; import { existsSync, readdirSync, readFileSync } from 'node:fs'; import path from 'node:path'; import { verifyReceipts } from '../../src/extensions/tests/native/tools/verify-native-extension-lifecycle-receipts.mts'; +import { authenticateNativeBuildEvidence } from '../../tools/release/authenticate-native-build-evidence.mts'; +import { + assertNativeBuildGithub, + validateNativeBuildEvidence, +} from '../../tools/release/native-build-qualification.mts'; function compareText(left, right) { return left < right ? -1 : left > right ? 1 : 0; @@ -430,11 +435,106 @@ export function nativeEvidenceBinding( }; } +/** Controller expectations constrain a fresh API-authenticated download; JSON cannot assert origin. */ +export async function nativeBuildEvidenceBinding(evidenceRoot, { sha, tree, context }) { + const file = 'native-build-evidence.json'; + assert( + context && typeof context === 'object' && !Array.isArray(context), + 'native build controller context is missing', + ); + assert( + JSON.stringify(Object.keys(context).sort()) === + JSON.stringify(['artifactName', 'event', 'github', 'ref', 'requiredTests']), + 'native build controller context fields are invalid', + ); + assert( + Array.isArray(context.requiredTests) && context.requiredTests.length > 0, + 'native build controller context requires mandatory configured tests', + ); + const source = { commit: sha, tree }; + const authenticated = await authenticateNativeBuildEvidence(evidenceRoot, { + source, + github: context.github, + event: context.event, + ref: context.ref, + artifactName: context.artifactName, + }); + const verified = validateNativeBuildEvidence(authenticated.evidence, { + source, + github: authenticated.github, + bazelVersion: readFileSync(new URL('../../.bazelversion', import.meta.url), 'utf8').trim(), + requiredTests: context.requiredTests, + }); + return { + ...verified, + artifact: authenticated.artifact, + file, + digest: authenticated.evidenceDigest, + unverified: verified.unverified.filter( + (check) => check !== 'authenticated producing workflow, attempt, job and immutable artifact', + ), + }; +} + +function assertNativeBuildBindingShape(binding, candidate) { + assert( + binding?.scope === 'construction' && binding.releaseDecision === 'unverified', + 'native build evidence cannot grant release authority', + ); + assert(binding.file === 'native-build-evidence.json', 'native build evidence file is invalid'); + assert(/^sha256:[0-9a-f]{64}$/u.test(binding.digest), 'native build evidence digest is invalid'); + same(binding.source?.commit, candidate.sha, 'native build evidence source commit'); + same(binding.source?.tree, candidate.tree, 'native build evidence source tree'); + assertNativeBuildGithub(binding.github); + same(binding.github.repository, candidate.repository, 'native build evidence repository'); + assert( + Array.isArray(binding.cohorts) && binding.cohorts.length > 0, + 'native build configured cohorts are missing', + ); + assert( + binding.testQualification === 'passed' && + Array.isArray(binding.requiredTests) && + binding.requiredTests.length > 0, + 'native build mandatory configured tests are missing', + ); + for (const test of binding.requiredTests) { + assert( + test && + JSON.stringify(Object.keys(test).sort()) === + JSON.stringify(['configuration', 'invocationId', 'label']) && + typeof test.label === 'string' && + test.label.startsWith('//') && + typeof test.configuration === 'string' && + test.configuration.length > 0 && + typeof test.invocationId === 'string' && + test.invocationId.length > 0 && + binding.cohorts.some((cohort) => cohort.invocationId === test.invocationId), + 'native build mandatory configured test binding is invalid', + ); + } + uniqueStrings( + binding.requiredTests.map((test) => `${test.label}\0${test.configuration}`), + 'native build mandatory configured tests', + ); + positiveInteger(binding.artifact?.id, 'native build artifact ID'); + positiveInteger(binding.artifact?.size, 'native build artifact size'); + assert( + typeof binding.artifact?.name === 'string' && binding.artifact.name.length > 0, + 'native build artifact name is invalid', + ); + assert( + /^sha256:[0-9a-f]{64}$/u.test(binding.artifact?.digest), + 'native build immutable artifact digest is invalid', + ); +} + export function assertCandidateBindingShape(candidate) { assert( candidate?.schemaVersion === 2, `release candidate schemaVersion must be 2, got ${candidate?.schemaVersion}`, ); + if (Object.hasOwn(candidate.evidence ?? {}, 'nativeBuild')) + assertNativeBuildBindingShape(candidate.evidence.nativeBuild, candidate); assert( candidate.affectedPlan !== null && typeof candidate.affectedPlan === 'object', 'release candidate affectedPlan is missing', diff --git a/.github/scripts/require-workflow-success.sh b/.github/scripts/require-workflow-success.sh index 3980f4b95..912d3ec06 100644 --- a/.github/scripts/require-workflow-success.sh +++ b/.github/scripts/require-workflow-success.sh @@ -20,11 +20,17 @@ qualification_products='' qualification_plan=false qualification_dispatch=false qualification_wait=false +native_request=false +qualification_requested_run_id='' selected_artifacts_json='[]' selected_gate_artifacts_json='[]' selected_run_attempt='' while [[ $# -gt 0 ]]; do case "$1" in + --request-native-qualification) + native_request=true + shift + ;; --plan-qualification | --dispatch-qualification | --qualification-products) case "$1" in --plan-qualification) qualification_plan=true ;; --dispatch-qualification) qualification_dispatch=true ;; --qualification-products) qualification_wait=true ;; esac qualification_products="${2:?qualification scope requires product JSON}" @@ -86,6 +92,18 @@ if [[ -n "$qualification_products" ]]; then export QUALIFICATION_REQUEST_KEY required_events=(push workflow_dispatch) fi +if [[ "$native_request" == true ]]; then + [[ "$workflow" == 'Native Bazel qualification' && -z "$expected_run_id" && -z "$qualification_products" && "$release_candidate" == false ]] || { + echo '--request-native-qualification requires the Native workflow without another selection mode' >&2 + exit 2 + } + required_jobs+=(Required) + required_events=(push workflow_dispatch) + export NATIVE_QUALIFICATION_REQUEST=true + qualification_scratch="$(mktemp -d)" + trap 'rm -rf "$qualification_scratch"' EXIT + timeout=0 +fi github_read() { local label="${1:?GitHub read label is required}" @@ -302,6 +320,76 @@ candidate_satisfies_gate() { fi } +dispatch_qualification_request() { + local main_sha response requested_id row run_sha run_workflow rest + main_sha="$(github_read 'main ref before qualification request' "repos/$GH_REPO/git/ref/heads/main" main-sha)" || exit $? + if [[ "$main_sha" != "$(printf '%s' "$sha" | normalize_sha)" ]]; then + echo "cannot request missing qualification for $sha: main is $main_sha; reuse or rerun an existing exact-source CI run" >&2 + exit 1 + fi + # Dispatch is a mutation: never apply the read retry policy to an ambiguous POST. + if ! response="$(gh api --method POST -H 'X-GitHub-Api-Version: 2026-03-10' "repos/$GH_REPO/actions/workflows/$workflow_id/dispatches" --input "$qualification_scratch/request.json")"; then + echo "qualification dispatch outcome is unknown; inspect $workflow at $sha before resuming" >&2 + exit 1 + fi + requested_id="$(bun .github/scripts/workflow-run-metadata.mts dispatch-run-id <<<"$response")" || exit 1 + echo "requested qualification: https://github.com/$GH_REPO/actions/runs/$requested_id" + row="$(github_read "requested qualification run $requested_id" "repos/$GH_REPO/actions/runs/$requested_id" run-row)" || exit $? + IFS=$'\t' read -r run_sha run_workflow rest <<<"$row" + if [[ "$(printf '%s' "$run_sha" | normalize_sha)" != "$(printf '%s' "$sha" | normalize_sha)" || "$run_workflow" != "$workflow_id" ]]; then + echo "qualification dispatch source changed; refusing run $requested_id for $run_sha" >&2 + exit 1 + fi + qualification_requested_run_id="$requested_id" +} + +native_pending() { + local run_id="$1" url="https://github.com/$GH_REPO/actions/runs/$1" + local row run_sha run_workflow rest run_attempt + row="$(github_read "pending Native run $run_id" "repos/$GH_REPO/actions/runs/$run_id" run-row)" || exit $? + IFS=$'\t' read -r run_sha run_workflow rest <<<"$row" + run_attempt="${row##*$'\t'}" + [[ "$(printf '%s' "$run_sha" | normalize_sha)" == "$(printf '%s' "$sha" | normalize_sha)" && "$run_workflow" == "$workflow_id" ]] || { + echo 'pending Native run source/workflow mismatch' >&2 + exit 1 + } + if [[ -n "${GITHUB_OUTPUT:-}" ]]; then + printf 'qualification_pending_run_id=%s\nqualification_pending_run_attempt=%s\nqualification_pending_run_url=%s\n' "$run_id" "$run_attempt" "$url" >>"$GITHUB_OUTPUT" + fi + echo "Native qualification pending: $url; the retained Prepare request will resume automatically after qualification." >&2 + exit 0 +} + +request_native_qualification() { + local active failed run_id event jobs_file kind status + active="$(awk -F '\t' '$2 != "completed" { print $1; exit }' <<<"$runs")" + if [[ -n "$active" ]]; then native_pending "$active"; fi + failed="$(awk -F '\t' '$2 == "completed" && $3 != "success" { print $1; exit }' <<<"$runs")" + if [[ -n "$failed" ]]; then + echo "Native qualification failed: https://github.com/$GH_REPO/actions/runs/$failed; fix the cause or rerun that run." >&2 + exit 1 + fi + while IFS=$'\t' read -r run_id event; do + [[ -n "$run_id" ]] || continue + jobs_file="$(mktemp)" + if github_paginated_json "$workflow run $run_id jobs" jobs "repos/$GH_REPO/actions/runs/$run_id/jobs?filter=latest" >"$jobs_file"; then + kind="$(bun .github/scripts/workflow-run-metadata.mts native-run-kind "$jobs_file")" || { rm -f "$jobs_file"; exit 64; } + rm -f "$jobs_file" + else + status=$? + rm -f "$jobs_file" + exit "$status" + fi + if [[ "$kind" != source || "$event" != push ]]; then + echo "Native full qualification did not pass Required: https://github.com/$GH_REPO/actions/runs/$run_id; inspect or rerun that run." >&2 + exit 1 + fi + done < <(awk -F '\t' '$2 == "completed" && $3 == "success" { print $1 "\t" $5 }' <<<"$runs") + printf '{"ref":"main"}\n' >"$qualification_scratch/request.json" + dispatch_qualification_request + native_pending "$qualification_requested_run_id" +} + request_missing_qualification() { # Active work may become a covering proof; never dispatch beside it. if awk -F '\t' '$2 != "completed" && $6 == "causal" { found=1 } END { exit found ? 0 : 1 }' <<<"$runs"; then @@ -323,26 +411,8 @@ request_missing_qualification() { fi if [[ "$qualification_wait" == true ]]; then return; fi if [[ "$qualification_dispatch" == true ]] && awk -F '\t' '$2 == "completed" && $3 == "success" && $7 == "requested" { found=1 } END { exit found ? 0 : 1 }' <<<"$runs"; then return; fi - local main_sha response requested_id row run_sha run_workflow rest - main_sha="$(github_read 'main ref before qualification request' "repos/$GH_REPO/git/ref/heads/main" main-sha)" || exit $? - if [[ "$main_sha" != "$sha" ]]; then - echo "cannot request missing qualification for $sha: main is $main_sha; reuse or rerun an existing exact-source CI run" >&2 - exit 1 - fi EXPECTED_SHA="$sha" PRODUCTS_JSON="$qualification_products" bun .github/scripts/workflow-run-metadata.mts qualification-request >"$qualification_scratch/request.json" - # Dispatch is a mutation: never apply the read retry policy to an ambiguous POST. - if ! response="$(gh api --method POST -H 'X-GitHub-Api-Version: 2026-03-10' "repos/$GH_REPO/actions/workflows/$workflow_id/dispatches" --input "$qualification_scratch/request.json")"; then - echo "qualification dispatch outcome is unknown; inspect CI request $QUALIFICATION_REQUEST_KEY before resuming" >&2 - exit 1 - fi - requested_id="$(bun .github/scripts/workflow-run-metadata.mts dispatch-run-id <<<"$response")" || exit 1 - echo "requested qualification: https://github.com/$GH_REPO/actions/runs/$requested_id" - row="$(github_read "requested qualification run $requested_id" "repos/$GH_REPO/actions/runs/$requested_id" run-row)" || exit $? - IFS=$'\t' read -r run_sha run_workflow rest <<<"$row" - if [[ "$run_sha" != "$sha" || "$run_workflow" != "$workflow_id" ]]; then - echo "qualification dispatch source changed; refusing run $requested_id for $run_sha" >&2 - exit 1 - fi + dispatch_qualification_request } resolve_workflow_id() { @@ -453,6 +523,7 @@ while true; do request_missing_qualification [[ "$qualification_dispatch" == false ]] || exit 0 fi + if [[ "$native_request" == true && "$inventory_ready" == true ]]; then request_native_qualification; fi if [ "$SECONDS" -ge "$deadline" ]; then echo "timed out waiting for successful $workflow workflow for $sha" >&2 exit 1 diff --git a/.github/scripts/setup-msvc.ps1 b/.github/scripts/setup-msvc.ps1 index 6de664eb1..7a795257c 100644 --- a/.github/scripts/setup-msvc.ps1 +++ b/.github/scripts/setup-msvc.ps1 @@ -1,6 +1,9 @@ $ErrorActionPreference = "Stop" Set-StrictMode -Version Latest +$hostPolicyPath = Join-Path $PSScriptRoot "../../tools/dev/native-host-toolchains.json" +$hostPolicy = (Get-Content -LiteralPath $hostPolicyPath -Raw | ConvertFrom-Json).windows + function Fail([string] $Message) { throw "setup-msvc.ps1: $Message" } @@ -82,7 +85,7 @@ $vswhereOutput = & $vswhere ` -latest ` -products '*' ` -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 ` - -version '[18.0,19.0)' ` + -version "[$($hostPolicy.visual_studio_major).0,$($hostPolicy.visual_studio_major + 1).0)" ` -format json ` -utf8 if ($LASTEXITCODE -ne 0) { @@ -112,7 +115,7 @@ $installationVersion = ([string] $installationVersionProperty.Value).Trim() if (-not $installPath -or -not (Test-Path -LiteralPath $installPath -PathType Container)) { Fail "Visual Studio 18 installation path was not found at $installPath" } -$null = Require-MajorVersion "installationVersion" $installationVersion 18 +$null = Require-MajorVersion "installationVersion" $installationVersion $hostPolicy.visual_studio_major $devShellLauncher = Join-Path $installPath "Common7\Tools\Launch-VsDevShell.ps1" if (-not (Test-Path -LiteralPath $devShellLauncher -PathType Leaf)) { @@ -139,7 +142,7 @@ if (-not $env:VCToolsRedistDir) { if (-not $env:VSCMD_VER) { Fail "VSCMD_VER was not set by the Visual Studio developer shell" } -$null = Require-MajorVersion "VSCMD_VER" $env:VSCMD_VER 18 +$null = Require-MajorVersion "VSCMD_VER" $env:VSCMD_VER $hostPolicy.visual_studio_major if ($env:VSCMD_ARG_HOST_ARCH -ne "x64" -or $env:VSCMD_ARG_TGT_ARCH -ne "x64") { Fail "developer shell architecture must be HostX64/x64; observed host '$($env:VSCMD_ARG_HOST_ARCH)' target '$($env:VSCMD_ARG_TGT_ARCH)'" } @@ -147,17 +150,17 @@ if (-not $env:VCToolsVersion) { Fail "VCToolsVersion was not set by the Visual Studio developer shell" } $vcToolsVersion = $env:VCToolsVersion.Trim().TrimEnd('\') -$vcToolsVersionInfo = Require-MajorVersion "VCToolsVersion" $vcToolsVersion 14 -if ($vcToolsVersionInfo.Minor -lt 50 -or $vcToolsVersionInfo.Minor -ge 60) { +$vcToolsVersionInfo = Require-MajorVersion "VCToolsVersion" $vcToolsVersion $hostPolicy.vc_toolset_major +if ($vcToolsVersionInfo.Minor -lt $hostPolicy.vc_toolset_minor_min -or $vcToolsVersionInfo.Minor -ge $hostPolicy.vc_toolset_minor_max_exclusive) { Fail "VCToolsVersion '$vcToolsVersion' is not the Visual Studio 2026 VC145 toolset family" } if (-not $env:WindowsSDKVersion) { Fail "WindowsSDKVersion was not set by the Visual Studio developer shell" } $windowsSdkVersion = $env:WindowsSDKVersion.Trim().TrimEnd('\') -$null = Require-MajorVersion "WindowsSDKVersion" $windowsSdkVersion 10 +$null = Require-MajorVersion "WindowsSDKVersion" $windowsSdkVersion $hostPolicy.windows_sdk_major -$vcRuntimeDir = Join-Path $env:VCToolsRedistDir "x64\Microsoft.VC145.CRT" +$vcRuntimeDir = Join-Path $env:VCToolsRedistDir "x64\Microsoft.$($hostPolicy.crt_family).CRT" if (-not (Test-Path -LiteralPath $vcRuntimeDir -PathType Container)) { Fail "the exact x64 Microsoft.VC145.CRT redistributable directory was not found at $vcRuntimeDir" } diff --git a/.github/scripts/verify-release-candidate.mts b/.github/scripts/verify-release-candidate.mts index dbf9e7b93..47368241f 100644 --- a/.github/scripts/verify-release-candidate.mts +++ b/.github/scripts/verify-release-candidate.mts @@ -13,6 +13,7 @@ import { assertQualificationProductCoverage, candidateQualificationMode, FULL_PAYLOAD_QUALIFICATION_MODE, + nativeBuildEvidenceBinding, nativeEvidenceBinding, PRODUCT_QUALIFICATION_MODE, wasixEvidenceBinding, @@ -43,6 +44,8 @@ function parseArgs(argv) { '--products-json', '--native-evidence-required', '--native-evidence-root', + '--native-build-evidence-root', + '--native-build-context-json', '--wasix-evidence-required', '--wasix-evidence-root', ].includes(name) @@ -75,6 +78,8 @@ function parseArgs(argv) { fail('--native-evidence-required must be true or false'); if (nativeRequired === 'true' && !values.has('native-evidence-root')) fail('--native-evidence-root is required when native evidence is required'); + if (values.has('native-build-evidence-root') !== values.has('native-build-context-json')) + fail('--native-build-evidence-root and --native-build-context-json must be supplied together'); const qualificationMode = values.get('qualification-mode') ?? FULL_PAYLOAD_QUALIFICATION_MODE; if ( ![FULL_PAYLOAD_QUALIFICATION_MODE, PRODUCT_QUALIFICATION_MODE, 'release'].includes( @@ -94,6 +99,8 @@ function parseArgs(argv) { wasixEvidenceRequired: required === 'true', nativeEvidenceRequired: nativeRequired === 'true', nativeEvidenceRoot: values.get('native-evidence-root'), + nativeBuildEvidenceRoot: values.get('native-build-evidence-root'), + nativeBuildContextJson: values.get('native-build-context-json'), wasixEvidenceRoot: values.get('wasix-evidence-root'), qualificationMode, products, @@ -152,6 +159,27 @@ for (const [field, value] of Object.entries({ } } +if (Object.hasOwn(candidate.evidence ?? {}, 'nativeBuild') || args.nativeBuildEvidenceRoot) { + if (!candidate.evidence?.nativeBuild || !args.nativeBuildEvidenceRoot) + fail('native build evidence must be present in both candidate and verification inputs'); + try { + const context = JSON.parse(args.nativeBuildContextJson); + if (context.github?.repository !== expected.repository) + throw new Error('native build producing repository differs from qualification'); + assertBindingMatches( + candidate.evidence.nativeBuild, + await nativeBuildEvidenceBinding(args.nativeBuildEvidenceRoot, { + sha: expected.sha, + tree: expectedTree, + context, + }), + 'release candidate native build evidence', + ); + } catch (error) { + fail(error.message); + } +} + if (!['push', 'workflow_dispatch'].includes(candidate.eventName)) { fail(`release candidate event must be push or workflow_dispatch, got ${candidate.eventName}`); } diff --git a/.github/scripts/workflow-run-metadata.mts b/.github/scripts/workflow-run-metadata.mts index 0e43365fe..87b58f6b7 100644 --- a/.github/scripts/workflow-run-metadata.mts +++ b/.github/scripts/workflow-run-metadata.mts @@ -74,6 +74,13 @@ switch (command) { } case 'run-row': { const run = await Bun.stdin.json(); + if ( + process.env.NATIVE_QUALIFICATION_REQUEST === 'true' && + (run.head_branch !== 'main' || + run.path !== '.github/workflows/bazel.yml' || + !['push', 'workflow_dispatch'].includes(run.event)) + ) + throw new Error('Native qualification requires an eligible main-source run'); if ( !/^[0-9A-Fa-f]{40}$/u.test(run.head_sha ?? '') || !Number.isSafeInteger(run.workflow_id) || @@ -218,6 +225,15 @@ switch (command) { } break; } + case 'native-run-kind': { + const jobs = JSON.parse(fs.readFileSync(args[0], 'utf8')); + if (!Array.isArray(jobs)) throw new Error('Native job inventory must be a list'); + const required = jobs.filter((job) => job?.name === 'Required'); + if (required.length !== 1) + throw new Error('Native job inventory requires exactly one Required gate'); + console.log(required[0].conclusion === 'skipped' ? 'source' : 'full'); + break; + } case 'workflow-id': { const expected = process.env.WORKFLOW_NAME; let rows; @@ -278,6 +294,18 @@ switch (command) { process.exit(1); } ids.add(row.id); + if ( + process.env.NATIVE_QUALIFICATION_REQUEST === 'true' && + (typeof row.head_branch !== 'string' || typeof row.path !== 'string') + ) + throw new Error('Native run inventory is missing branch/path metadata'); + if ( + process.env.NATIVE_QUALIFICATION_REQUEST === 'true' && + (row.head_branch !== 'main' || + row.path !== '.github/workflows/bazel.yml' || + !['push', 'workflow_dispatch'].includes(row.event)) + ) + continue; rendered.push([row.id, row.status, conclusion, row.html_url, row.event].join('\t')); if (process.env.QUALIFICATION_REQUEST_KEY) { const requested = diff --git a/.github/scripts/write-release-candidate.mts b/.github/scripts/write-release-candidate.mts index 80876c767..3a404261e 100644 --- a/.github/scripts/write-release-candidate.mts +++ b/.github/scripts/write-release-candidate.mts @@ -8,6 +8,7 @@ import { assertCandidateBindingShape, candidateQualificationMode, FULL_PAYLOAD_QUALIFICATION_MODE, + nativeBuildEvidenceBinding, nativeEvidenceBinding, PRODUCT_QUALIFICATION_MODE, wasixEvidenceBinding, @@ -99,6 +100,28 @@ if (nativeRequired) { } } +let nativeBuild; +if (process.env.NATIVE_BUILD_ORIGIN_JSON?.trim()) + fail( + 'NATIVE_BUILD_ORIGIN_JSON cannot authenticate native evidence; use NATIVE_BUILD_CONTEXT_JSON', + ); +if (process.env.NATIVE_BUILD_EVIDENCE_ROOT?.trim()) { + try { + const context = JSON.parse(requiredEnv('NATIVE_BUILD_CONTEXT_JSON')); + if (context.github?.repository !== requiredEnv('GITHUB_REPOSITORY')) + throw new Error('native build producing repository differs from qualification'); + nativeBuild = await nativeBuildEvidenceBinding(requiredEnv('NATIVE_BUILD_EVIDENCE_ROOT'), { + sha: checkedOutSha, + tree, + context, + }); + } catch (error) { + fail(error.message); + } +} else if (process.env.NATIVE_BUILD_CONTEXT_JSON?.trim()) { + fail('NATIVE_BUILD_EVIDENCE_ROOT is required with native build controller context'); +} + const candidate = { schemaVersion: 2, repository: requiredEnv('GITHUB_REPOSITORY'), @@ -122,6 +145,7 @@ const candidate = { evidence: { wasixReleaseRegression: wasixEvidence, nativeExtensionLifecycle: nativeEvidence, + ...(nativeBuild === undefined ? {} : { nativeBuild }), }, }; diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml new file mode 100644 index 000000000..11823f1c0 --- /dev/null +++ b/.github/workflows/bazel.yml @@ -0,0 +1,1894 @@ +name: Native Bazel qualification + +on: + workflow_dispatch: + pull_request: + types: [opened, synchronize, reopened, closed] + merge_group: + types: [checks_requested] + push: + branches: [main] + +permissions: + contents: read + actions: read + pull-requests: read + +concurrency: + group: bazel-${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.number) || format('sha-{0}', github.sha) }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +defaults: + run: + shell: bash + +env: + CI_FULL_MATRICES: | + { + "portable": [ + {"platform":"linux-x64","runner":"ubuntu-24.04"}, + {"platform":"linux-arm64","runner":"ubuntu-24.04-arm"}, + {"platform":"macos-arm64","runner":"macos-26"}, + {"platform":"windows-x64","runner":"windows-2025-vs2026"} + ], + "linux": [ + {"platform":"x86_64","runner":"ubuntu-24.04"}, + {"platform":"aarch64","runner":"ubuntu-24.04-arm"} + ], + "postmaster-host": [ + {"platform":"linux-arm64","runner":"ubuntu-24.04-arm","compiler":"//src/wasix/postmaster:compiler_linux_arm64","prefix":"linux_arm64_gnu"}, + {"platform":"macos-arm64","runner":"macos-26","compiler":"//src/wasix/postmaster:native_macos_arm64","prefix":"macos_arm64"} + ], + "wasix-host": [ + {"platform":"linux-arm64","runner":"ubuntu-24.04-arm","profile":"//build_defs/native:linux_aarch64_glibc_2_28"}, + {"platform":"macos-arm64","runner":"macos-26","profile":"//build_defs/host:native_macos_arm64"}, + {"platform":"windows-x64","runner":"windows-2025-vs2026","profile":"//build_defs/host:native_windows_x64"} + ] + } + +jobs: + release-inputs: + name: Resolve native release inputs + if: github.event_name != 'pull_request' || github.event.action != 'closed' + runs-on: ubuntu-24.04 + timeout-minutes: 20 + permissions: + contents: read + actions: read + pull-requests: read + attestations: read + outputs: + native_inputs: ${{ steps.context.outputs.native_inputs }} + pull_number: ${{ steps.context.outputs.pull_number }} + run_id: ${{ steps.producer.outputs.run_id }} + public_artifact_id: ${{ steps.public-upload.outputs.artifact-id }} + ci_mode: ${{ steps.scope.outputs.ci_mode }} + ci_selected_requests: ${{ steps.scope.outputs.ci_selected_requests }} + ci_selected_jobs: ${{ steps.scope.outputs.ci_selected_jobs }} + ci_capture_requests: ${{ steps.scope.outputs.ci_capture_requests }} + portable_matrix: ${{ steps.scope.outputs.portable_matrix }} + linux_matrix: ${{ steps.scope.outputs.linux_matrix }} + postmaster_host_matrix: ${{ steps.scope.outputs.postmaster_host_matrix }} + wasix_host_matrix: ${{ steps.scope.outputs.wasix_host_matrix }} + steps: + - name: Checkout exact source + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + + - name: Set up verified Node.js and Bun + uses: ./.github/actions/setup-node-bun + + - name: Install locked release tooling + run: bash tools/dev/bun.sh install --frozen-lockfile --filter @oliphaunt/release-tools --ignore-scripts + + - name: Resolve canonical prepared release tree + id: context + env: + GH_TOKEN: ${{ github.token }} + EVENT_PULL_NUMBER: ${{ github.event.pull_request.number }} + run: | + context_args=(--resolve-context) + if [[ -n "$EVENT_PULL_NUMBER" ]]; then + context_args+=(--pull-number "$EVENT_PULL_NUMBER") + fi + bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh \ + tools/release/native-release-inputs.mts "${context_args[@]}" + + - name: Check release-owned source versions + env: + PR_TITLE: ${{ github.event.pull_request.title }} + BASE_REF: ${{ github.event.pull_request.base.sha || github.event.before || github.event.merge_group.base_sha || (github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main' && format('{0}^', github.sha)) || 'origin/main' }} + HEAD_REF: ${{ github.event.pull_request.head.sha || github.event.merge_group.head_sha || github.sha }} + HEAD_BRANCH: ${{ github.event.pull_request.head.ref || github.ref_name }} + CI_EVENT_NAME: ${{ github.event_name }} + CI_FULL_REF: ${{ github.ref }} + SOURCE_POLICY_SUBJECT: ${{ steps.context.outputs.source_policy_subject }} + SOURCE_POLICY_BASE: ${{ steps.context.outputs.source_policy_base }} + SOURCE_POLICY_HEAD: ${{ steps.context.outputs.source_policy_head }} + SOURCE_POLICY_BRANCH: ${{ steps.context.outputs.source_policy_branch }} + run: | + subject="${PR_TITLE:-}" + if [[ "$CI_EVENT_NAME" == merge_group && -n "$SOURCE_POLICY_HEAD" ]]; then + subject="$SOURCE_POLICY_SUBJECT" + BASE_REF="$SOURCE_POLICY_BASE" + HEAD_REF="$SOURCE_POLICY_HEAD" + HEAD_BRANCH="$SOURCE_POLICY_BRANCH" + for commit in "$BASE_REF" "$HEAD_REF"; do + if ! git cat-file -e "$commit^{commit}"; then + git fetch --no-tags origin "$commit" + fi + done + fi + if [[ -z "$subject" ]]; then + subject="$(git log -1 --pretty=%s "$HEAD_REF")" + fi + bash .github/scripts/check-release-intent.sh "$subject" "$BASE_REF" "$HEAD_REF" \ + "$HEAD_BRANCH" "$CI_EVENT_NAME" "$CI_FULL_REF" --source-policy-only + + - name: Require the exact completed Prepare producer + if: steps.context.outputs.native_inputs == 'true' + id: producer + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + PREPARE_SOURCE_SHA: ${{ steps.context.outputs.prepare_source_sha }} + run: >- + bash .github/scripts/require-workflow-success.sh Release "$PREPARE_SOURCE_SHA" 900 + --event workflow_dispatch --job 'Prepare release PR' --artifact native-release-inputs + + - name: Set up Cargo for release source metadata + uses: ./.github/actions/setup-rust + with: + cache: "false" + + - name: Qualify release controller and Git source policy + env: + MOON_BIN: /definitely-unavailable-moon + run: | + bash tools/dev/bun.sh tools/release/check_release_please_config.mts + bash tools/dev/bun.sh tools/release/check_artifact_targets.mts + bash tools/release/release-check.sh --mutation-tests-only + + - name: Plan source requests from admitted configured inputs + id: scope + env: + GH_TOKEN: ${{ github.token }} + NATIVE_PREPARED_INPUTS: ${{ steps.context.outputs.native_inputs }} + run: | + mkdir -p "$RUNNER_TEMP/native-ci-plan" + scope_args=(plan --output "$RUNNER_TEMP/native-ci-plan/plan.json") + if [[ "$NATIVE_PREPARED_INPUTS" == true ]]; then scope_args+=(--full); fi + bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh tools/ci/configured-scope.mts "${scope_args[@]}" + + - name: Check every used module extension before producer fanout + if: steps.scope.outputs.ci_mode == 'full' + run: bash tools/dev/bazel.sh mod deps --lockfile_mode=error + + - name: Upload source request plan + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-ci-plan + path: ${{ runner.temp }}/native-ci-plan/ + if-no-files-found: error + retention-days: 7 + + - name: Acquire completed public inputs once + if: (steps.context.outputs.native_inputs != 'true') && (steps.scope.outputs.ci_selected_requests != '[]') + env: + GH_TOKEN: ${{ github.token }} + run: | + snapshot="$(bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh \ + tools/release/native-release-preparation.mts --publication-inputs \ + --output-directory "$RUNNER_TEMP/native-public-acquisition")" + bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh \ + tools/release/native-release-inputs.mts --transport-public-inputs "$snapshot" \ + --output-directory "$RUNNER_TEMP/native-public-inputs" + + - name: Upload source-bound public inputs + if: (steps.context.outputs.native_inputs != 'true') && (steps.scope.outputs.ci_selected_requests != '[]') + id: public-upload + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-public-inputs + path: ${{ runner.temp }}/native-public-inputs + if-no-files-found: error + retention-days: 7 + + portable: + name: Portable packages (${{ matrix.platform }}) + if: ${{ !cancelled() && needs.release-inputs.result == 'success' && fromJSON(needs.release-inputs.outputs.portable_matrix).include[0] != null }} + needs: release-inputs + runs-on: ${{ matrix.runner }} + # macOS includes the later cold Apple slices in the shared compiler base. + timeout-minutes: ${{ matrix.platform == 'macos-arm64' && 300 || 180 }} + strategy: + fail-fast: false + matrix: ${{ fromJSON(needs.release-inputs.outputs.portable_matrix) }} + env: + CI_REQUEST_JOB: portable/${{ matrix.platform }} + CI_PLATFORM: ${{ matrix.platform }} + CI_MODE: ${{ needs.release-inputs.outputs.ci_mode }} + CI_SELECTED_REQUESTS: ${{ needs.release-inputs.outputs.ci_selected_requests }} + CI_CAPTURE_REQUESTS: ${{ needs.release-inputs.outputs.ci_capture_requests }} + steps: + - name: Checkout exact source + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + + - name: Acquire source-bound native inputs + uses: ./.github/actions/native-release-inputs + with: + run-id: ${{ needs.release-inputs.outputs.run_id }} + pull-number: ${{ needs.release-inputs.outputs.pull_number }} + public-artifact-id: ${{ needs.release-inputs.outputs.public_artifact_id }} + + - name: Restore bounded standard Bazel caches + id: bazel-cache + uses: ./.github/actions/bazel-cache + with: + phase: restore + cohort: portable + + - name: Check Bazel acquisition + if: needs.release-inputs.outputs.ci_mode == 'full' + run: bash tools/dev/bazel-bootstrap.test.sh + + - name: Select declared Apple SDK + id: apple_sdk + if: matrix.platform == 'macos-arm64' + uses: ./.github/actions/setup-apple + with: + install-build-dependencies: "false" + + - name: Qualify complete Apple runtime, resources, SDK and extension packages + id: apple_qualification + if: (matrix.platform == 'macos-arm64') && (contains(fromJSON(needs.release-inputs.outputs.ci_selected_requests), fromJSON(env.CI_REQUEST_IDS)[matrix.platform][0])) + env: + CI_REQUEST_IDS: '{"macos-arm64":["portable/macos-arm64/apple-packages"]}' + NATIVE_PREPARED_INPUTS: ${{ needs.release-inputs.outputs.native_inputs }} + QUALIFICATION_JOB_NAME: Portable packages (${{ matrix.platform }}) + run: | + CI_REQUEST_ID="$(jq -r --arg platform "$CI_PLATFORM" '.[$platform][0]' <<< "$CI_REQUEST_IDS")" + case "$NATIVE_PREPARED_INPUTS" in + true) apple_export=//:native_apple_shipping_export ;; + false) apple_export=//:native_apple_preparation_export ;; + *) echo 'Apple qualification requires an authenticated release input context' >&2; exit 1 ;; + esac + input_root="$RUNNER_TEMP/ios-extension-build-inputs" + mkdir -p "$input_root" "$RUNNER_TEMP/native-bazel-diagnostics" + jq -nc --arg repository "$GITHUB_REPOSITORY" --arg workflow "$GITHUB_WORKFLOW" \ + --arg workflowPath .github/workflows/bazel.yml --arg job "$QUALIFICATION_JOB_NAME" \ + --argjson runId "$GITHUB_RUN_ID" --argjson runAttempt "$GITHUB_RUN_ATTEMPT" \ + '{repository:$repository,workflow:$workflow,workflowPath:$workflowPath,runId:$runId,runAttempt:$runAttempt,job:$job}' \ + > "$input_root/github.json" + jq -nc --arg base "$RUNNER_TEMP/native-bazel" \ + --arg log "$RUNNER_TEMP/native-bazel-diagnostics/server-jvm.out" \ + '["--output_base="+$base,"--host_jvm_args=-Xmx3g","--server_jvm_out="+$log]' \ + > "$input_root/startup.json" + jq -nc '["-c","opt","--config=macos-sandbox", + "--platforms=//build_defs/host:apple_package_macos_arm64", + "--host_platform=//build_defs/host:native_macos_arm64","--jobs=2","--local_test_jobs=1"]' \ + > "$input_root/configuration.json" + jq -nc '["//build_defs/host:host_swift_smoke", "//build_defs/apple:swift_interface_context_test", "//build_defs/apple:expo_umbrella_test", "//src/native/sdks/swift:installed_consumer_test"]' \ + > "$input_root/targets.json" + printf '%s\n' "${CI_REQUIRES:-[]}" > "$input_root/ci-requires.json" + ci_arguments=(--ci-request-id "$CI_REQUEST_ID" --ci-job "$CI_REQUEST_JOB" --ci-mode "$CI_MODE" + --ci-requires-json "$input_root/ci-requires.json") + if jq -e --arg id "$CI_REQUEST_ID" 'index($id) != null' <<< "$CI_CAPTURE_REQUESTS" >/dev/null; then + ci_arguments+=(--ci-handoff) + fi + bash tools/dev/bun.sh tools/release/qualify-native-shipping.mts "${ci_arguments[@]}" \ + --github-json "$input_root/github.json" --startup-json "$input_root/startup.json" \ + --configuration-json "$input_root/configuration.json" \ + --shipping-export "$apple_export" \ + --targets-json "$input_root/targets.json" --output-directory "$RUNNER_TEMP/ios-extension-build-capture" + mkdir -p "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID" + cp "$RUNNER_TEMP/ios-extension-build-capture/ci-request.json" "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID/ci-request.json" + + - name: Upload iOS extension construction evidence + if: ${{ !cancelled() && steps.apple_qualification.outcome == 'success' && (needs.release-inputs.outputs.ci_mode == 'full' || contains(fromJSON(needs.release-inputs.outputs.ci_capture_requests), format('portable/{0}/apple-packages', matrix.platform))) }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-build-evidence-mobile-ios + path: ${{ runner.temp }}/ios-extension-build-capture/evidence/ + if-no-files-found: error + retention-days: 7 + + - name: Select declared MSVC SDK + if: matrix.platform == 'windows-x64' + uses: ./.github/actions/setup-msvc + + - name: Qualify packages and native host behavior + # Finish independent macOS requests after a sibling fails. Each Bazel + # request still resolves its own prerequisites, and failures stay failed. + if: ${{ !cancelled() && contains(fromJSON(needs.release-inputs.outputs.ci_selected_requests), env.CI_REQUEST_ID) && (success() || (matrix.platform == 'macos-arm64' && steps.apple_sdk.outcome == 'success')) }} + timeout-minutes: ${{ matrix.platform == 'macos-arm64' && 180 || 150 }} + env: + CI_REQUEST_ID: portable/${{ matrix.platform }}/packages + TARGET_PLATFORM: ${{ matrix.platform }} + run: | + host_tests=( + //build_defs/languages/carriers:package_test + ) + case "$TARGET_PLATFORM" in + linux-x64) profile=//build_defs/native:linux_x86_64_glibc_2_28 ;; + linux-arm64) profile=//build_defs/native:linux_aarch64_glibc_2_28 ;; + macos-arm64) profile=//build_defs/host:native_macos_arm64 ;; + windows-x64) profile=//build_defs/host:native_windows_x64 ;; + esac + case "$TARGET_PLATFORM" in + macos-arm64|windows-x64) + host_tests+=( + //build_defs/host:host_c_smoke + //build_defs/native:compiler_probe_test + //build_defs/native:probe_process_test + //src/native/runtime:abi_conformance_test + //src/native/runtime:native_tools_sql_test + ) + ;; + esac + if [[ "$TARGET_PLATFORM" == windows-x64 ]]; then + host_tests+=( + @icu//:windows_icu_smoke_test + //build_defs/extensions:postgis_server_windows_link_test + //build_defs/extensions:postgis_embedded_windows_link_test + //build_defs/extensions:pgcrypto_server_windows_link_test + //build_defs/extensions:pgcrypto_embedded_windows_link_test + //build_defs/extensions/postgis:postgis_windows_sources_test + ) + fi + if [[ "$TARGET_PLATFORM" == linux-x64 ]]; then + host_tests+=( + //build_defs/host:rust_dependency_paths_tests + //tools/ci:source_checks + //tools/dev:source_checks + //:packaging_contract_test + //build_defs/extensions:member_payload_test + //build_defs/extensions:mobile_carriers_test + //build_defs/resources:desktop_seed_profile_test + //build_defs/resources:desktop_seed_consumer_profile_test + //build_defs/resources:desktop_payload_macos_profile_test + //build_defs/resources:desktop_payload_linux_profile_test + //build_defs/resources:desktop_payload_windows_profile_test + //build_defs/resources:desktop_payload_ios_profile_test + //build_defs/resources:desktop_payload_android_profile_test + //build_defs/resources:seed_carrier_ios_datum64_standard_inputs_test + //build_defs/resources:seed_carrier_ios_datum64_icu_inputs_test + //build_defs/resources:seed_carrier_android_datum64_standard_inputs_test + //build_defs/resources:seed_carrier_android_datum64_icu_inputs_test + //build_defs/resources:seed_carrier_linux_x64_gnu_icu_inputs_test + //build_defs/resources:seed_carrier_portable_icu_inputs_test + //build_defs/extensions:windows_source_portability_test + //build_defs/extensions:windows_source_inputs_test + //:biome_format_test + //:biome_lint_test + //:rustfmt_test + //build_defs/quality:rust_clippy_test + //build_defs/quality:rust_doctest_suite + //build_defs/quality:metadata_test + //build_defs/quality:biome_runner_test + //build_defs/quality:rustfmt_runner_test + //tools/bazel:execution_log_test + //tools/bazel:shipping_coverage_test + //src/native/sdks/ts:source_checks_typecheck_test + //src/wasix/sdks/ts:source_checks_typecheck_test + //src/native/sdks/react-native:source_checks_typecheck_test + //src/wasix/postgres-tools/ts:source_checks_typecheck_test + //src/examples/wasix/browser:source_checks + //src/docs:source_checks + //src/native/sdks/kotlin:format_test + ) + fi + if [[ "$TARGET_PLATFORM" != macos-arm64 ]]; then + startup=() + if [[ "$TARGET_PLATFORM" == windows-x64 ]]; then + # MSVC still limits some object paths to MAX_PATH. Keep the whole + # job on one short base, including maintained Rust build tools. + startup=(--output_base="$RUNNER_TEMP/b") + fi + ci_targets=(//:portable_tests "${host_tests[@]}") + ci_configuration=(-c opt "--platforms=$profile" "--host_platform=$profile" --jobs=2) + ci_startup=("${startup[@]}") + ci_command='test' + ci_input_root="$RUNNER_TEMP/ci-request-inputs/$CI_REQUEST_ID" + mkdir -p "$ci_input_root" + jq -nc --args '$ARGS.positional' -- "${ci_targets[@]}" > "$ci_input_root/targets.json" + jq -nc --args '$ARGS.positional' -- "${ci_configuration[@]}" > "$ci_input_root/configuration.json" + jq -nc --args '$ARGS.positional' -- "${ci_startup[@]}" > "$ci_input_root/startup.json" + bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh tools/ci/run-configured-request.mts \ + --id "$CI_REQUEST_ID" --job "$CI_REQUEST_JOB" --mode "$CI_MODE" --command "$ci_command" \ + --targets-json "$ci_input_root/targets.json" --configuration-json "$ci_input_root/configuration.json" \ + --startup-json "$ci_input_root/startup.json" \ + --output-directory "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID" + exit + fi + + diagnostic_root="$RUNNER_TEMP/native-bazel-diagnostics" + qualifier_output_base="$RUNNER_TEMP/native-bazel" + mkdir -p "$diagnostic_root" + capture_jvm_snapshot() { + local destination="$1" java_pid java_command + local java_pid_file="$qualifier_output_base/server/server.pid.txt" + if [[ -r "$java_pid_file" ]]; then + java_pid="$(cat "$java_pid_file")" + if [[ "$java_pid" =~ ^[0-9]+$ ]]; then + java_command="$(ps -p "$java_pid" -o comm= || true)" + case "$java_command" in + java|*/java|bazel\(*\)) + if kill -QUIT "$java_pid" 2>/dev/null; then + sleep 2 + cp "$diagnostic_root/server-jvm.out" "$diagnostic_root/$destination" || true + fi + ;; + esac + fi + fi + } + ci_targets=(//:portable_tests "${host_tests[@]}") + ci_configuration=(-c opt --config=macos-sandbox "--platforms=$profile" "--host_platform=$profile" --jobs=2 + "--profile=$diagnostic_root/qualification.json.gz" "--starlark_cpu_profile=$diagnostic_root/starlark.pprof") + ci_startup=("--output_base=$qualifier_output_base" --host_jvm_args=-Xmx3g "--server_jvm_out=$diagnostic_root/server-jvm.out") + ci_command='test' + ci_input_root="$RUNNER_TEMP/ci-request-inputs/$CI_REQUEST_ID" + mkdir -p "$ci_input_root" + jq -nc --args '$ARGS.positional' -- "${ci_targets[@]}" > "$ci_input_root/targets.json" + jq -nc --args '$ARGS.positional' -- "${ci_configuration[@]}" > "$ci_input_root/configuration.json" + jq -nc --args '$ARGS.positional' -- "${ci_startup[@]}" > "$ci_input_root/startup.json" + bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh tools/ci/run-configured-request.mts \ + --id "$CI_REQUEST_ID" --job "$CI_REQUEST_JOB" --mode "$CI_MODE" --command "$ci_command" \ + --targets-json "$ci_input_root/targets.json" --configuration-json "$ci_input_root/configuration.json" \ + --startup-json "$ci_input_root/startup.json" \ + --output-directory "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID" & + qualifier_pid=$! + ( + diagnostic_delay_pid= + trap 'if [[ -n "$diagnostic_delay_pid" ]]; then kill "$diagnostic_delay_pid" 2>/dev/null || true; fi' EXIT + trap 'exit 0' TERM INT + sleep 480 & + diagnostic_delay_pid=$! + wait "$diagnostic_delay_pid" + if kill -0 "$qualifier_pid" 2>/dev/null; then + ps -axo pid,ppid,state,etime,%cpu,%mem,comm > "$diagnostic_root/processes.txt" + capture_jvm_snapshot jvm-8min.out + fi + ) & + diagnostic_pid=$! + qualifier_status=0 + trap 'kill "$diagnostic_pid" 2>/dev/null || true' EXIT + wait "$qualifier_pid" || qualifier_status=$? + kill "$diagnostic_pid" 2>/dev/null || true + wait "$diagnostic_pid" || true + trap - EXIT + capture_jvm_snapshot jvm-final.out + exit "$qualifier_status" + + - name: Construct native iOS device and simulator ABI consumers + if: ${{ !cancelled() && matrix.platform == 'macos-arm64' && steps.apple_sdk.outcome == 'success' }} + env: + CI_REQUEST_IDS: '{"macos-arm64":["portable/macos-arm64/abi-ios_device_arm64","portable/macos-arm64/abi-ios_simulator_arm64","portable/macos-arm64/abi-apple_package_macos_arm64"]}' + run: | + qualification_status=0 + while IFS= read -r CI_REQUEST_ID; do + if ! jq -e --arg id "$CI_REQUEST_ID" 'index($id) != null' <<< "$CI_SELECTED_REQUESTS" >/dev/null; then continue; fi + profile="${CI_REQUEST_ID##*/abi-}" + ci_targets=(//build_defs/extensions/mobile:all_members_consumer) + if [[ "$profile" != apple_package_macos_arm64 ]]; then + ci_targets=(//src/native/runtime:mobile_static_abi_consumer //src/native/runtime:runtime_abi_binary "${ci_targets[@]}") + fi + ci_configuration=(-c opt --config=macos-sandbox "--platforms=//build_defs/host:$profile" + --host_platform=//build_defs/host:native_macos_arm64 --jobs=2) + ci_startup=("--output_base=$RUNNER_TEMP/native-bazel" --host_jvm_args=-Xmx3g + "--server_jvm_out=$RUNNER_TEMP/native-bazel-diagnostics/server-jvm.out") + ci_command='build' + ci_input_root="$RUNNER_TEMP/ci-request-inputs/$CI_REQUEST_ID" + mkdir -p "$ci_input_root" + jq -nc --args '$ARGS.positional' -- "${ci_targets[@]}" > "$ci_input_root/targets.json" + jq -nc --args '$ARGS.positional' -- "${ci_configuration[@]}" > "$ci_input_root/configuration.json" + jq -nc --args '$ARGS.positional' -- "${ci_startup[@]}" > "$ci_input_root/startup.json" + if ! bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh tools/ci/run-configured-request.mts \ + --id "$CI_REQUEST_ID" --job "$CI_REQUEST_JOB" --mode "$CI_MODE" --command "$ci_command" \ + --targets-json "$ci_input_root/targets.json" --configuration-json "$ci_input_root/configuration.json" \ + --startup-json "$ci_input_root/startup.json" \ + --output-directory "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID"; then + qualification_status=1 + fi + done < <(jq -r --arg platform "$CI_PLATFORM" '.[$platform][]' <<< "$CI_REQUEST_IDS") + exit "$qualification_status" + + - name: Qualify final native carriers and frozen resources + id: native_qualification + if: ${{ !cancelled() && (matrix.platform == 'macos-arm64' || matrix.platform == 'windows-x64') && contains(fromJSON(needs.release-inputs.outputs.ci_selected_requests), fromJSON(env.CI_REQUEST_IDS)[matrix.platform][0]) && (success() || (matrix.platform == 'macos-arm64' && steps.apple_sdk.outcome == 'success')) }} + env: + CI_REQUEST_IDS: '{"macos-arm64":["portable/macos-arm64/native-carriers"],"windows-x64":["portable/windows-x64/native-carriers"]}' + TARGET_PLATFORM: ${{ matrix.platform }} + QUALIFICATION_JOB_NAME: Portable packages (${{ matrix.platform }}) + run: | + CI_REQUEST_ID="$(jq -r --arg platform "$CI_PLATFORM" '.[$platform][0]' <<< "$CI_REQUEST_IDS")" + input_root="$RUNNER_TEMP/native-build-inputs" + mkdir -p "$input_root" + jq -nc --arg repository "$GITHUB_REPOSITORY" --arg workflow "$GITHUB_WORKFLOW" \ + --arg workflowPath .github/workflows/bazel.yml --arg job "$QUALIFICATION_JOB_NAME" \ + --argjson runId "$GITHUB_RUN_ID" --argjson runAttempt "$GITHUB_RUN_ATTEMPT" \ + '{repository:$repository,workflow:$workflow,workflowPath:$workflowPath,runId:$runId,runAttempt:$runAttempt,job:$job}' \ + > "$input_root/github.json" + case "$TARGET_PLATFORM" in + macos-arm64) + jq -nc --arg base "$RUNNER_TEMP/native-bazel" \ + --arg log "$RUNNER_TEMP/native-bazel-diagnostics/server-jvm.out" \ + '["--output_base="+$base,"--host_jvm_args=-Xmx3g","--server_jvm_out="+$log]' \ + > "$input_root/startup.json" + jq -nc '["-c","opt","--config=macos-sandbox", + "--platforms=//build_defs/host:native_macos_arm64", + "--host_platform=//build_defs/host:native_macos_arm64","--jobs=2"]' \ + > "$input_root/configuration.json" + ;; + windows-x64) + jq -nc --arg base "$RUNNER_TEMP/b" '["--output_base="+$base]' \ + > "$input_root/startup.json" + jq -nc '["-c","opt","--platforms=//build_defs/host:native_windows_x64", + "--host_platform=//build_defs/host:native_windows_x64","--jobs=2"]' \ + > "$input_root/configuration.json" + ;; + esac + printf '%s\n' "${CI_REQUIRES:-[]}" > "$input_root/ci-requires.json" + ci_arguments=(--ci-request-id "$CI_REQUEST_ID" --ci-job "$CI_REQUEST_JOB" --ci-mode "$CI_MODE" + --ci-requires-json "$input_root/ci-requires.json") + if jq -e --arg id "$CI_REQUEST_ID" 'index($id) != null' <<< "$CI_CAPTURE_REQUESTS" >/dev/null; then + ci_arguments+=(--ci-handoff) + fi + bash tools/dev/bun.sh tools/release/qualify-native-shipping.mts "${ci_arguments[@]}" \ + --github-json "$input_root/github.json" --startup-json "$input_root/startup.json" \ + --configuration-json "$input_root/configuration.json" \ + --shipping-export //:native_shipping_export \ + --output-directory "$RUNNER_TEMP/native-build-capture" + mkdir -p "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID" + cp "$RUNNER_TEMP/native-build-capture/ci-request.json" "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID/ci-request.json" + + - name: Upload native construction evidence + if: ${{ !cancelled() && steps.native_qualification.outcome == 'success' && (needs.release-inputs.outputs.ci_mode == 'full' || contains(fromJSON(needs.release-inputs.outputs.ci_capture_requests), format('portable/{0}/native-carriers', matrix.platform))) }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-build-evidence-native-${{ matrix.platform }} + path: ${{ runner.temp }}/native-build-capture/evidence/ + if-no-files-found: error + retention-days: 7 + + - name: Qualify declared documentation export and examples + if: (matrix.platform == 'linux-x64') && (contains(fromJSON(needs.release-inputs.outputs.ci_selected_requests), fromJSON(env.CI_REQUEST_IDS)[matrix.platform][0])) + env: + CI_REQUEST_IDS: '{"linux-x64":["portable/linux-x64/docs"]}' + GITHUB_TOKEN: ${{ github.token }} + run: | + CI_REQUEST_ID="$(jq -r --arg platform "$CI_PLATFORM" '.[$platform][0]' <<< "$CI_REQUEST_IDS")" + bash tools/dev/bun.sh src/docs/tools/verify-live.mts snapshot \ + target/docs/expected-products.json target/docs/native-inputs + ci_targets=(//src/docs:site_checks) + ci_configuration=(-c opt --platforms=//build_defs/native:linux_x86_64_glibc_2_28 --host_platform=//build_defs/native:linux_x86_64_glibc_2_28 --jobs=2) + ci_startup=() + ci_command='test' + ci_input_root="$RUNNER_TEMP/ci-request-inputs/$CI_REQUEST_ID" + mkdir -p "$ci_input_root" + jq -nc --args '$ARGS.positional' -- "${ci_targets[@]}" > "$ci_input_root/targets.json" + jq -nc --args '$ARGS.positional' -- "${ci_configuration[@]}" > "$ci_input_root/configuration.json" + jq -nc --args '$ARGS.positional' -- "${ci_startup[@]}" > "$ci_input_root/startup.json" + bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh tools/ci/run-configured-request.mts \ + --id "$CI_REQUEST_ID" --job "$CI_REQUEST_JOB" --mode "$CI_MODE" --command "$ci_command" \ + --targets-json "$ci_input_root/targets.json" --configuration-json "$ci_input_root/configuration.json" \ + --startup-json "$ci_input_root/startup.json" \ + --output-directory "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID" + + - name: Check execution tool selection for foreign targets + if: (matrix.platform == 'linux-x64') && (contains(fromJSON(needs.release-inputs.outputs.ci_selected_requests), fromJSON(env.CI_REQUEST_IDS)[matrix.platform][0])) + env: + CI_REQUEST_IDS: '{"linux-x64":["portable/linux-x64/foreign-tools"]}' + run: | + CI_REQUEST_ID="$(jq -r --arg platform "$CI_PLATFORM" '.[$platform][0]' <<< "$CI_REQUEST_IDS")" + ci_targets=(//build_defs/foundation:bun_toolchain_test) + ci_configuration=(--platforms=//build_defs/foundation:windows_x86_64 --extra_execution_platforms=//build_defs/foundation:linux_x86_64 --jobs=2) + ci_startup=() + ci_command='test' + ci_input_root="$RUNNER_TEMP/ci-request-inputs/$CI_REQUEST_ID" + mkdir -p "$ci_input_root" + jq -nc --args '$ARGS.positional' -- "${ci_targets[@]}" > "$ci_input_root/targets.json" + jq -nc --args '$ARGS.positional' -- "${ci_configuration[@]}" > "$ci_input_root/configuration.json" + jq -nc --args '$ARGS.positional' -- "${ci_startup[@]}" > "$ci_input_root/startup.json" + bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh tools/ci/run-configured-request.mts \ + --id "$CI_REQUEST_ID" --job "$CI_REQUEST_JOB" --mode "$CI_MODE" --command "$ci_command" \ + --targets-json "$ci_input_root/targets.json" --configuration-json "$ci_input_root/configuration.json" \ + --startup-json "$ci_input_root/startup.json" \ + --output-directory "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID" + + - name: Exercise cold, incremental and coverage scenarios + if: (matrix.platform == 'linux-x64') && (needs.release-inputs.outputs.ci_mode == 'full') + run: | + bash tools/dev/bun.sh tools/bazel/tests/conformance.mts + bazel_version="$(cat .bazelversion)" + bazel_binary="${XDG_CACHE_HOME:-$HOME/.cache}/oliphaunt/bazel/$bazel_version/bazel-$bazel_version-linux-x86_64" + bash tools/dev/bun.sh build_defs/host/sdk-tree-conformance.mts "$bazel_binary" + + - name: Upload macOS Bazel diagnostics + if: ${{ always() && matrix.platform == 'macos-arm64' }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-bazel-macos-diagnostics + path: | + ${{ runner.temp }}/native-bazel-diagnostics + ${{ runner.temp }}/native-build-capture/diagnostics + ${{ runner.temp }}/ios-extension-build-capture/diagnostics + ${{ runner.temp }}/ci-requests/**/diagnostics + if-no-files-found: ignore + retention-days: 5 + + - name: Upload failed Windows native test diagnostics + if: failure() && matrix.platform == 'windows-x64' + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-bazel-windows-test-diagnostics + path: | + ${{ runner.temp }}/b/command.log + ${{ runner.temp }}/b/execroot/_main/bazel-out/**/testlogs/**/test.log + ${{ runner.temp }}/b/execroot/_main/bazel-out/**/testlogs/**/test.xml + if-no-files-found: ignore + retention-days: 5 + + - &ci_request_receipts + name: Upload completed source request receipts + if: always() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-ci-requests-${{ github.job }}-${{ env.CI_PLATFORM || 'single' }} + path: ${{ runner.temp }}/ci-requests/**/ci-request.json + if-no-files-found: error + retention-days: 7 + + - name: Save bounded standard Bazel caches + if: ${{ always() }} + continue-on-error: true + timeout-minutes: 10 + uses: ./.github/actions/bazel-cache + with: + phase: save + cohort: portable + disk-cache-hit: ${{ steps.bazel-cache.outputs.disk-cache-hit }} + output-base: ${{ matrix.platform == 'windows-x64' && format('{0}/b', runner.temp) || matrix.platform == 'macos-arm64' && format('{0}/native-bazel', runner.temp) || '' }} + jvm-args: ${{ matrix.platform == 'macos-arm64' && '-Xmx3g' || '' }} + server-log: ${{ matrix.platform == 'macos-arm64' && format('{0}/native-bazel-diagnostics/server-jvm.out', runner.temp) || '' }} + + linux: + name: Linux runtime (${{ matrix.platform }}) + if: ${{ !cancelled() && needs.release-inputs.result == 'success' && fromJSON(needs.release-inputs.outputs.linux_matrix).include[0] != null }} + needs: release-inputs + runs-on: ${{ matrix.runner }} + # Android construction and installed testing share the Linux x64 base. + timeout-minutes: ${{ matrix.platform == 'x86_64' && 210 || 120 }} + strategy: + fail-fast: false + matrix: ${{ fromJSON(needs.release-inputs.outputs.linux_matrix) }} + env: + CI_REQUEST_JOB: linux/${{ matrix.platform }} + CI_PLATFORM: ${{ matrix.platform }} + CI_MODE: ${{ needs.release-inputs.outputs.ci_mode }} + CI_SELECTED_REQUESTS: ${{ needs.release-inputs.outputs.ci_selected_requests }} + CI_CAPTURE_REQUESTS: ${{ needs.release-inputs.outputs.ci_capture_requests }} + steps: + - name: Checkout exact source + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + + - name: Acquire source-bound native inputs + uses: ./.github/actions/native-release-inputs + with: + run-id: ${{ needs.release-inputs.outputs.run_id }} + pull-number: ${{ needs.release-inputs.outputs.pull_number }} + public-artifact-id: ${{ needs.release-inputs.outputs.public_artifact_id }} + + - name: Restore bounded standard Bazel caches + id: bazel-cache + uses: ./.github/actions/bazel-cache + with: + phase: restore + cohort: linux + + # One invocation shares PostgreSQL/ICU/generators across real consumers. + - name: Qualify runtime, frontends, crypto and extension SQL + if: contains(fromJSON(needs.release-inputs.outputs.ci_selected_requests), env.CI_REQUEST_ID) + env: + CI_REQUEST_ID: linux/${{ matrix.platform }}/runtime + TARGET_CPU: ${{ matrix.platform }} + run: | + profile="//build_defs/native:linux_${TARGET_CPU}_glibc_2_28" + ci_targets=(//:native_linux_tests) + ci_configuration=(-c opt "--platforms=$profile" "--host_platform=$profile" --jobs=2) + ci_startup=() + ci_command='test' + ci_input_root="$RUNNER_TEMP/ci-request-inputs/$CI_REQUEST_ID" + mkdir -p "$ci_input_root" + jq -nc --args '$ARGS.positional' -- "${ci_targets[@]}" > "$ci_input_root/targets.json" + jq -nc --args '$ARGS.positional' -- "${ci_configuration[@]}" > "$ci_input_root/configuration.json" + jq -nc --args '$ARGS.positional' -- "${ci_startup[@]}" > "$ci_input_root/startup.json" + bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh tools/ci/run-configured-request.mts \ + --id "$CI_REQUEST_ID" --job "$CI_REQUEST_JOB" --mode "$CI_MODE" --command "$ci_command" \ + --targets-json "$ci_input_root/targets.json" --configuration-json "$ci_input_root/configuration.json" \ + --startup-json "$ci_input_root/startup.json" \ + --output-directory "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID" + + - name: Qualify Android cross-compiled runtime and ABI + if: (matrix.platform == 'x86_64') && (contains(fromJSON(needs.release-inputs.outputs.ci_selected_requests), fromJSON(env.CI_REQUEST_IDS)[matrix.platform][0])) + env: + CI_REQUEST_IDS: '{"x86_64":["linux/x86_64/android-abi"]}' + run: | + CI_REQUEST_ID="$(jq -r --arg platform "$CI_PLATFORM" '.[$platform][0]' <<< "$CI_REQUEST_IDS")" + ci_targets=(//build_defs/android:abi_test //build_defs/native:android_runtime_abi_test) + ci_configuration=(-c opt --platforms=//build_defs/native:linux_x86_64_glibc_2_28 --host_platform=//build_defs/native:linux_x86_64_glibc_2_28 --jobs=2) + ci_startup=() + ci_command='test' + ci_input_root="$RUNNER_TEMP/ci-request-inputs/$CI_REQUEST_ID" + mkdir -p "$ci_input_root" + jq -nc --args '$ARGS.positional' -- "${ci_targets[@]}" > "$ci_input_root/targets.json" + jq -nc --args '$ARGS.positional' -- "${ci_configuration[@]}" > "$ci_input_root/configuration.json" + jq -nc --args '$ARGS.positional' -- "${ci_startup[@]}" > "$ci_input_root/startup.json" + bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh tools/ci/run-configured-request.mts \ + --id "$CI_REQUEST_ID" --job "$CI_REQUEST_JOB" --mode "$CI_MODE" --command "$ci_command" \ + --targets-json "$ci_input_root/targets.json" --configuration-json "$ci_input_root/configuration.json" \ + --startup-json "$ci_input_root/startup.json" \ + --output-directory "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID" + + - name: Provision KVM for the exact installed Android APK test + if: (matrix.platform == 'x86_64') && (contains(fromJSON(needs.release-inputs.outputs.ci_selected_requests), format('linux/{0}/android-packages', matrix.platform))) + run: | + test -c /dev/kvm + sudo chmod 666 /dev/kvm + test -r /dev/kvm && test -w /dev/kvm + + - name: Qualify complete Android extension, Maven packages and release apps + if: (matrix.platform == 'x86_64') && (contains(fromJSON(needs.release-inputs.outputs.ci_selected_requests), fromJSON(env.CI_REQUEST_IDS)[matrix.platform][0])) + env: + CI_REQUEST_IDS: '{"x86_64":["linux/x86_64/android-packages"]}' + QUALIFICATION_JOB_NAME: Linux runtime (${{ matrix.platform }}) + run: | + CI_REQUEST_ID="$(jq -r --arg platform "$CI_PLATFORM" '.[$platform][0]' <<< "$CI_REQUEST_IDS")" + OLIPHAUNT_MOBILE_CANDIDATE_CHECKOUT="$(pwd -P)" + test "$OLIPHAUNT_MOBILE_CANDIDATE_CHECKOUT" = "$(cd "$GITHUB_WORKSPACE" && pwd -P)" + OLIPHAUNT_MOBILE_CANDIDATE_SHA="$(git rev-parse HEAD)" + OLIPHAUNT_MOBILE_CANDIDATE_TREE="$(git rev-parse 'HEAD^{tree}')" + test -z "$(git status --porcelain --untracked-files=no)" + export OLIPHAUNT_MOBILE_CANDIDATE_CHECKOUT OLIPHAUNT_MOBILE_CANDIDATE_SHA OLIPHAUNT_MOBILE_CANDIDATE_TREE + input_root="$RUNNER_TEMP/android-extension-build-inputs" + mkdir -p "$input_root" + jq -nc --arg repository "$GITHUB_REPOSITORY" --arg workflow "$GITHUB_WORKFLOW" \ + --arg workflowPath .github/workflows/bazel.yml --arg job "$QUALIFICATION_JOB_NAME" \ + --argjson runId "$GITHUB_RUN_ID" --argjson runAttempt "$GITHUB_RUN_ATTEMPT" \ + '{repository:$repository,workflow:$workflow,workflowPath:$workflowPath,runId:$runId,runAttempt:$runAttempt,job:$job}' \ + > "$input_root/github.json" + jq -nc '["-c","opt","--platforms=//build_defs/native:linux_x86_64_glibc_2_28", + "--host_platform=//build_defs/native:linux_x86_64_glibc_2_28","--jobs=2","--local_test_jobs=1"]' \ + > "$input_root/configuration.json" + jq -nc '[ + "//build_defs/android:android_binary_min_sdk_test", + "//build_defs/android:android_min_sdk_conflict_test", + "//build_defs/extensions/mobile/final:android_arm64_v8a_final_contract_test", + "//build_defs/extensions/mobile/final:android_x86_64_final_contract_test", + "//build_defs/extensions/mobile:android_arm64_all_members_consumer", + "//build_defs/extensions/mobile:android_x86_64_all_members_consumer", + "//build_defs/extensions:mobile_maven_test", + "//src/examples/native/react-native-expo:android_release", + "//src/examples/native/react-native-expo:autolinking_consumer_test", + "//src/examples/native/react-native-expo:android_installed_test" + ]' > "$input_root/targets.json" + printf '%s\n' "${CI_REQUIRES:-[]}" > "$input_root/ci-requires.json" + ci_arguments=(--ci-request-id "$CI_REQUEST_ID" --ci-job "$CI_REQUEST_JOB" --ci-mode "$CI_MODE" + --ci-requires-json "$input_root/ci-requires.json") + if jq -e --arg id "$CI_REQUEST_ID" 'index($id) != null' <<< "$CI_CAPTURE_REQUESTS" >/dev/null; then + ci_arguments+=(--ci-handoff) + fi + bash tools/dev/bun.sh tools/release/qualify-native-shipping.mts "${ci_arguments[@]}" \ + --github-json "$input_root/github.json" --configuration-json "$input_root/configuration.json" \ + --shipping-export //:native_android_shipping_export \ + --targets-json "$input_root/targets.json" --output-directory "$RUNNER_TEMP/android-extension-build-capture" + mkdir -p "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID" + cp "$RUNNER_TEMP/android-extension-build-capture/ci-request.json" "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID/ci-request.json" + + - name: Upload Android extension construction evidence + if: (matrix.platform == 'x86_64') && (needs.release-inputs.outputs.ci_mode == 'full' || contains(fromJSON(needs.release-inputs.outputs.ci_capture_requests), format('linux/{0}/android-packages', matrix.platform))) + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-build-evidence-mobile-android + path: ${{ runner.temp }}/android-extension-build-capture/evidence/ + if-no-files-found: error + retention-days: 7 + + - name: Upload installed Android failure diagnostics + if: ${{ always() && matrix.platform == 'x86_64' }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-android-installed-diagnostics + path: | + bazel-testlogs/src/examples/native/react-native-expo/android_installed_test/test.log + bazel-testlogs/src/examples/native/react-native-expo/android_installed_test/test.xml + bazel-testlogs/src/examples/native/react-native-expo/android_installed_test/test.outputs/ + if-no-files-found: ignore + retention-days: 5 + + - name: Qualify installed packages and frozen resources + if: (matrix.platform == 'x86_64') && (contains(fromJSON(needs.release-inputs.outputs.ci_selected_requests), fromJSON(env.CI_REQUEST_IDS)[matrix.platform][0])) + env: + CI_REQUEST_IDS: '{"x86_64":["linux/x86_64/source-packages"]}' + run: | + CI_REQUEST_ID="$(jq -r --arg platform "$CI_PLATFORM" '.[$platform][0]' <<< "$CI_REQUEST_IDS")" + ci_targets=( + //build_defs/languages:sdk_source_package_test + //build_defs/languages:source_contract_test + //build_defs/extensions:native_frozen_extension_sql_test + //src/native/rust-bindings:unit_test + //build_defs/native/carriers:package_test + //src/native/runtime/packaging:source_tests + //build_defs/extensions:native_carriers_test + //build_defs/extensions:wasix_sql_carriers_test + //src/extensions/external/pgtap:wasix_carriers_test + //build_defs/extensions:contrib_carriers_test + //src/extensions/contrib:native_carriers_test + //build_defs/native/apple:framework_contract_test + //build_defs/native/apple:swift_candidate_contract_test + //build_defs/native/apple:mobile_seed_contract_test + //src/native/runtime:npm + //src/native/postgres-tools:cargo_facade + //build_defs/resources:resource_contract_test + //src/database-resources:android_datum64_standard_carriers + //src/database-resources:android_datum64_icu_carriers + //src/native/sdks/react-native:lifecycle_test + //src/native/sdks/kotlin:android_maven + //src/native/sdks/kotlin:installed_public_api_consumer + //src/native/sdks/kotlin:android_test + //src/native/sdks/kotlin/oliphaunt-android-gradle-plugin:contract_test + //src/native/sdks/kotlin/oliphaunt-android-gradle-plugin:plugin_maven + //src/native/sdks/kotlin/oliphaunt-android-gradle-plugin:marker_maven + ) + ci_configuration=(-c opt --platforms=//build_defs/native:linux_x86_64_glibc_2_28 + --host_platform=//build_defs/native:linux_x86_64_glibc_2_28 --jobs=2) + ci_startup=() + ci_command='test' + ci_input_root="$RUNNER_TEMP/ci-request-inputs/$CI_REQUEST_ID" + mkdir -p "$ci_input_root" + jq -nc --args '$ARGS.positional' -- "${ci_targets[@]}" > "$ci_input_root/targets.json" + jq -nc --args '$ARGS.positional' -- "${ci_configuration[@]}" > "$ci_input_root/configuration.json" + jq -nc --args '$ARGS.positional' -- "${ci_startup[@]}" > "$ci_input_root/startup.json" + bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh tools/ci/run-configured-request.mts \ + --id "$CI_REQUEST_ID" --job "$CI_REQUEST_JOB" --mode "$CI_MODE" --command "$ci_command" \ + --targets-json "$ci_input_root/targets.json" --configuration-json "$ci_input_root/configuration.json" \ + --startup-json "$ci_input_root/startup.json" \ + --output-directory "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID" + + - name: Qualify final native carriers and frozen resources + if: contains(fromJSON(needs.release-inputs.outputs.ci_selected_requests), env.CI_REQUEST_ID) + env: + CI_REQUEST_ID: linux/${{ matrix.platform }}/native-carriers + TARGET_CPU: ${{ matrix.platform }} + QUALIFICATION_JOB_NAME: Linux runtime (${{ matrix.platform }}) + run: | + profile="//build_defs/native:linux_${TARGET_CPU}_glibc_2_28" + capture_root="$RUNNER_TEMP/native-build-capture" + input_root="$RUNNER_TEMP/native-build-inputs" + mkdir -p "$input_root" + jq -nc --arg repository "$GITHUB_REPOSITORY" --arg workflow "$GITHUB_WORKFLOW" \ + --arg workflowPath .github/workflows/bazel.yml --arg job "$QUALIFICATION_JOB_NAME" \ + --argjson runId "$GITHUB_RUN_ID" --argjson runAttempt "$GITHUB_RUN_ATTEMPT" \ + '{repository:$repository,workflow:$workflow,workflowPath:$workflowPath,runId:$runId,runAttempt:$runAttempt,job:$job}' \ + > "$input_root/github.json" + jq -nc --arg profile "$profile" \ + '["-c","opt","--platforms="+$profile,"--host_platform="+$profile, + "--jobs=2"]' \ + > "$input_root/configuration.json" + printf '%s\n' "${CI_REQUIRES:-[]}" > "$input_root/ci-requires.json" + ci_arguments=(--ci-request-id "$CI_REQUEST_ID" --ci-job "$CI_REQUEST_JOB" --ci-mode "$CI_MODE" + --ci-requires-json "$input_root/ci-requires.json") + if jq -e --arg id "$CI_REQUEST_ID" 'index($id) != null' <<< "$CI_CAPTURE_REQUESTS" >/dev/null; then + ci_arguments+=(--ci-handoff) + fi + bash tools/dev/bun.sh tools/release/qualify-native-shipping.mts "${ci_arguments[@]}" \ + --github-json "$input_root/github.json" --configuration-json "$input_root/configuration.json" \ + --shipping-export //:native_shipping_export \ + --output-directory "$capture_root" + mkdir -p "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID" + cp "$capture_root/ci-request.json" "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID/ci-request.json" + + - name: Upload native construction evidence + if: needs.release-inputs.outputs.ci_mode == 'full' || contains(fromJSON(needs.release-inputs.outputs.ci_capture_requests), format('linux/{0}/native-carriers', matrix.platform)) + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-build-evidence-${{ matrix.platform }} + path: ${{ runner.temp }}/native-build-capture/evidence/ + if-no-files-found: error + retention-days: 7 + + - *ci_request_receipts + + - name: Save bounded standard Bazel caches + if: ${{ always() }} + continue-on-error: true + timeout-minutes: 10 + uses: ./.github/actions/bazel-cache + with: + phase: save + cohort: linux + disk-cache-hit: ${{ steps.bazel-cache.outputs.disk-cache-hit }} + + wasix: + name: Linux WASIX and installed browser + if: ${{ !cancelled() && needs.release-inputs.result == 'success' && contains(fromJSON(needs.release-inputs.outputs.ci_selected_jobs), 'wasix') }} + needs: release-inputs + runs-on: ubuntu-24.04 + # The cold full request reached its final Rust actions at the old two-hour + # bound; retain time for browser/SQL qualification and evidence capture. + timeout-minutes: 150 + outputs: + source_commit: ${{ steps.wasix-cargo-capture.outputs.source_commit }} + cargo_artifact_id: ${{ steps.wasix-cargo-upload.outputs.artifact-id }} + env: + CI_REQUEST_JOB: wasix + CI_MODE: ${{ needs.release-inputs.outputs.ci_mode }} + CI_SELECTED_REQUESTS: ${{ needs.release-inputs.outputs.ci_selected_requests }} + CI_CAPTURE_REQUESTS: ${{ needs.release-inputs.outputs.ci_capture_requests }} + steps: + - name: Checkout exact source + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + + - name: Acquire source-bound native inputs + uses: ./.github/actions/native-release-inputs + with: + run-id: ${{ needs.release-inputs.outputs.run_id }} + pull-number: ${{ needs.release-inputs.outputs.pull_number }} + public-artifact-id: ${{ needs.release-inputs.outputs.public_artifact_id }} + + - name: Restore bounded standard Bazel caches + id: bazel-cache + uses: ./.github/actions/bazel-cache + with: + phase: restore + cohort: wasix + + - name: Construct platform AOT packages and qualify Linux SDK, resources and browser + if: contains(fromJSON(needs.release-inputs.outputs.ci_selected_requests), env.CI_REQUEST_ID) + env: + CI_REQUEST_ID: wasix/tools-sdk-browser + QUALIFICATION_JOB_NAME: Linux WASIX and installed browser + run: | + chrome_binary="$(bash tools/dev/bun.sh build_defs/wasix/browser/chrome-receipt.mts "$RUNNER_TEMP/chrome-host.json" "$ImageOS" "$ImageVersion")" + input_root="$RUNNER_TEMP/wasix-tools-build-inputs" + mkdir -p "$input_root" + jq -nc --arg repository "$GITHUB_REPOSITORY" --arg workflow "$GITHUB_WORKFLOW" \ + --arg workflowPath .github/workflows/bazel.yml --arg job "$QUALIFICATION_JOB_NAME" \ + --argjson runId "$GITHUB_RUN_ID" --argjson runAttempt "$GITHUB_RUN_ATTEMPT" \ + '{repository:$repository,workflow:$workflow,workflowPath:$workflowPath,runId:$runId,runAttempt:$runAttempt,job:$job}' \ + > "$input_root/github.json" + jq -nc --arg cache "$RUNNER_TEMP/wasix-source-sdk-cache" \ + --arg chrome "$chrome_binary" --arg chromeReceipt "$RUNNER_TEMP/chrome-host.json" '[ + "-c","opt","--config=wasix-aot","--platforms=//build_defs/native:linux_x86_64_glibc_2_28", + "--host_platform=//build_defs/native:linux_x86_64_glibc_2_28","--local_test_jobs=1", + "--test_env=OLIPHAUNT_WASM_AOT_VERIFY=full","--test_env=XDG_CACHE_HOME="+$cache,"--test_env=RUST_TEST_THREADS=1", + "--test_env=OLIPHAUNT_BROWSER_CHROME="+$chrome,"--test_env=OLIPHAUNT_BROWSER_CHROME_RECEIPT="+$chromeReceipt + ]' > "$input_root/configuration.json" + jq -nc '[ + "//build_defs/wasix:bridge_abi_test", + "//build_defs/wasix:initdb_shim_abi_test", + "//build_defs/wasix/postmaster:source_modes_test" + ]' > "$input_root/targets.json" + jq -nc '["postgres-tools-wasix"]' > "$input_root/complete-products.json" + printf '%s\n' "${CI_REQUIRES:-[]}" > "$input_root/ci-requires.json" + ci_arguments=(--ci-request-id "$CI_REQUEST_ID" --ci-job "$CI_REQUEST_JOB" --ci-mode "$CI_MODE" + --ci-requires-json "$input_root/ci-requires.json") + if jq -e --arg id "$CI_REQUEST_ID" 'index($id) != null' <<< "$CI_CAPTURE_REQUESTS" >/dev/null; then + ci_arguments+=(--ci-handoff) + fi + bash tools/dev/bun.sh tools/release/qualify-native-shipping.mts "${ci_arguments[@]}" \ + --github-json "$input_root/github.json" --configuration-json "$input_root/configuration.json" \ + --shipping-export //:wasix_shipping_export \ + --targets-json "$input_root/targets.json" \ + --complete-products-json "$input_root/complete-products.json" \ + --output-directory "$RUNNER_TEMP/wasix-tools-build-capture" + mkdir -p "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID" + cp "$RUNNER_TEMP/wasix-tools-build-capture/ci-request.json" "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID/ci-request.json" + + - name: Upload tools construction evidence + if: needs.release-inputs.outputs.ci_mode == 'full' || contains(fromJSON(needs.release-inputs.outputs.ci_capture_requests), 'wasix/tools-sdk-browser') + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-build-evidence-wasix-tools + path: ${{ runner.temp }}/wasix-tools-build-capture/evidence/ + if-no-files-found: error + retention-days: 7 + + - name: Upload WASIX build and query diagnostics + if: always() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-wasix-build-diagnostics + path: ${{ runner.temp }}/wasix-tools-build-capture/diagnostics/ + if-no-files-found: warn + retention-days: 7 + + - name: Capture final WASIX Cargo inputs for native hosts + if: needs.release-inputs.outputs.ci_mode == 'full' || contains(fromJSON(needs.release-inputs.outputs.ci_capture_requests), 'wasix/tools-sdk-browser') + id: wasix-cargo-capture + run: | + capture_root="$RUNNER_TEMP/wasix-cargo-capture" + mkdir -p "$capture_root" + test -z "$(git status --porcelain)" + # Reuse the producing invocation captured above. The reader requires + # the five core envelopes and the ten already-constructed contrib/tools + # envelopes needed for bounded side-module/tool execution on each host. + jq '. as $evidence | [ + .cohorts[] | { + source: $evidence.source, executionRoot: .executionRoot, aquery: .aquery, + roots: [.roots[] | select((.package.product == "liboliphaunt-wasix" + or .package.product == "postgres-tools-wasix") + and .package.ecosystem == "cargo" + and ((.package.name | startswith("liboliphaunt-wasix-")) + or (.package.name | startswith("oliphaunt-extension-contrib-pg18-")) + or (.package.name | startswith("oliphaunt-wasix-tools"))))] + } | select(.roots | length > 0) + ]' "$RUNNER_TEMP/wasix-tools-build-capture/evidence/native-build-evidence.json" \ + > "$capture_root/cohorts.json" + source_commit="$(git rev-parse HEAD)" + test -z "$(git status --porcelain)" + bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh \ + build_defs/wasix/capture-cargo.mts "$capture_root/cohorts.json" \ + target/wasix-cargo-construction HEAD + printf 'source_commit=%s\n' "$source_commit" >> "$GITHUB_OUTPUT" + + - name: Upload final WASIX Cargo inputs + if: needs.release-inputs.outputs.ci_mode == 'full' || contains(fromJSON(needs.release-inputs.outputs.ci_capture_requests), 'wasix/tools-sdk-browser') + id: wasix-cargo-upload + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-bazel-wasix-cargo-inputs + path: target/wasix-cargo-construction + if-no-files-found: error + retention-days: 7 + + - *ci_request_receipts + + - name: Save bounded standard Bazel caches + if: ${{ always() }} + continue-on-error: true + timeout-minutes: 10 + uses: ./.github/actions/bazel-cache + with: + phase: save + cohort: wasix + disk-cache-hit: ${{ steps.bazel-cache.outputs.disk-cache-hit }} + + postmaster: + name: Linux native postmaster lifecycle + if: ${{ !cancelled() && needs.release-inputs.result == 'success' && contains(fromJSON(needs.release-inputs.outputs.ci_selected_jobs), 'postmaster') }} + needs: release-inputs + runs-on: ubuntu-24.04 + timeout-minutes: 120 + outputs: + source_commit: ${{ steps.postmaster-capture.outputs.source_commit }} + source_tree: ${{ steps.postmaster-capture.outputs.source_tree }} + env: + CI_REQUEST_JOB: postmaster + CI_MODE: ${{ needs.release-inputs.outputs.ci_mode }} + CI_SELECTED_REQUESTS: ${{ needs.release-inputs.outputs.ci_selected_requests }} + CI_CAPTURE_REQUESTS: ${{ needs.release-inputs.outputs.ci_capture_requests }} + steps: + - name: Checkout exact source + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + + - name: Acquire source-bound native inputs + uses: ./.github/actions/native-release-inputs + with: + run-id: ${{ needs.release-inputs.outputs.run_id }} + pull-number: ${{ needs.release-inputs.outputs.pull_number }} + public-artifact-id: ${{ needs.release-inputs.outputs.public_artifact_id }} + + - name: Restore bounded standard Bazel caches + id: bazel-cache + uses: ./.github/actions/bazel-cache + with: + phase: restore + cohort: postmaster + + # This owner has a separate compiler/sysroot closure. Keep it parallel to + # tools/browser construction and share its one base across both profiles. + - name: Qualify native postmaster carrier and installed lifecycle + if: contains(fromJSON(needs.release-inputs.outputs.ci_selected_requests), env.CI_REQUEST_ID) + id: postmaster-capture + env: + CI_REQUEST_ID: postmaster/linux-carrier-lifecycle + run: | + input_root="$RUNNER_TEMP/postmaster-build-inputs" + mkdir -p "$input_root" + jq -nc --arg repository "$GITHUB_REPOSITORY" --arg workflow "$GITHUB_WORKFLOW" \ + --arg workflowPath .github/workflows/bazel.yml --arg job 'Linux native postmaster lifecycle' \ + --argjson runId "$GITHUB_RUN_ID" --argjson runAttempt "$GITHUB_RUN_ATTEMPT" \ + '{repository:$repository,workflow:$workflow,workflowPath:$workflowPath,runId:$runId,runAttempt:$runAttempt,job:$job}' \ + > "$input_root/github.json" + jq -nc --arg base "$RUNNER_TEMP/postmaster-native" \ + '["--output_base="+$base,"--host_jvm_args=-Xmx3g"]' > "$input_root/startup.json" + jq -nc '["-c","opt","--platforms=//build_defs/wasix:portable", + "--host_platform=//build_defs/wasix:llvm_serializer_linux_x86_64","--jobs=2"]' \ + > "$input_root/configuration.json" + jq -nc '[ + "//build_defs/wasix/postmaster:cargo_source_projection_test", + "//build_defs/wasix/postmaster:sjlj_runtime_probe_test", + "//build_defs/wasix/postmaster:vfork_runtime_probe_test", + "//build_defs/wasix/postmaster:guest_inputs_test", + "//src/wasix/postmaster:linux_sealed_profile_test", + "//src/wasix/postmaster:linux_runtime_test", + "//src/wasix/postmaster:linux_public_archive_test" + ]' > "$input_root/targets.json" + printf '%s\n' "${CI_REQUIRES:-[]}" > "$input_root/ci-requires.json" + ci_arguments=(--ci-request-id "$CI_REQUEST_ID" --ci-job "$CI_REQUEST_JOB" --ci-mode "$CI_MODE" + --ci-requires-json "$input_root/ci-requires.json") + if jq -e --arg id "$CI_REQUEST_ID" 'index($id) != null' <<< "$CI_CAPTURE_REQUESTS" >/dev/null; then + ci_arguments+=(--ci-handoff) + fi + bash tools/dev/bun.sh tools/release/qualify-native-shipping.mts "${ci_arguments[@]}" \ + --github-json "$input_root/github.json" --startup-json "$input_root/startup.json" \ + --configuration-json "$input_root/configuration.json" \ + --shipping-export //src/wasix/postmaster:linux_shipping_export \ + --targets-json "$input_root/targets.json" \ + --output-directory "$RUNNER_TEMP/postmaster-build-capture" + mkdir -p "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID" + cp "$RUNNER_TEMP/postmaster-build-capture/ci-request.json" "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID/ci-request.json" + printf 'source_commit=%s\n' "$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" + printf 'source_tree=%s\n' "$(git rev-parse 'HEAD^{tree}')" >> "$GITHUB_OUTPUT" + + - name: Upload native postmaster construction evidence + if: needs.release-inputs.outputs.ci_mode == 'full' || contains(fromJSON(needs.release-inputs.outputs.ci_capture_requests), 'postmaster/linux-carrier-lifecycle') + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-build-evidence-postmaster-linux + path: ${{ runner.temp }}/postmaster-build-capture/evidence/ + if-no-files-found: error + retention-days: 7 + + - name: Qualify linked unwinder marker detection + if: contains(fromJSON(needs.release-inputs.outputs.ci_selected_requests), env.CI_REQUEST_ID) + env: + CI_REQUEST_ID: postmaster/linked-unwinder + run: | + ci_targets=(//build_defs/wasix/postmaster:linked_unwinder_present_test //build_defs/wasix/postmaster:linked_unwinder_absent_test) + ci_configuration=(--platforms=//build_defs/native:linux_x86_64_glibc_2_28 --host_platform=//build_defs/native:linux_x86_64_glibc_2_28 --compilation_mode=opt --jobs=2) + ci_startup=("--output_base=$RUNNER_TEMP/postmaster-native" --host_jvm_args=-Xmx3g) + ci_command='test' + ci_input_root="$RUNNER_TEMP/ci-request-inputs/$CI_REQUEST_ID" + mkdir -p "$ci_input_root" + jq -nc --args '$ARGS.positional' -- "${ci_targets[@]}" > "$ci_input_root/targets.json" + jq -nc --args '$ARGS.positional' -- "${ci_configuration[@]}" > "$ci_input_root/configuration.json" + jq -nc --args '$ARGS.positional' -- "${ci_startup[@]}" > "$ci_input_root/startup.json" + bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh tools/ci/run-configured-request.mts \ + --id "$CI_REQUEST_ID" --job "$CI_REQUEST_JOB" --mode "$CI_MODE" --command "$ci_command" \ + --targets-json "$ci_input_root/targets.json" --configuration-json "$ci_input_root/configuration.json" \ + --startup-json "$ci_input_root/startup.json" \ + --output-directory "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID" + + - name: Upload native postmaster lifecycle diagnostics + if: ${{ always() }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-postmaster-lifecycle-diagnostics + path: | + ${{ runner.temp }}/postmaster-native/execroot/_main/bazel-out/**/testlogs/**/test.log + ${{ runner.temp }}/postmaster-native/execroot/_main/bazel-out/**/testlogs/**/test.xml + ${{ runner.temp }}/postmaster-native/execroot/_main/bazel-out/**/testlogs/**/*runtime_test/test.outputs/postmaster-runtime/runtime-result.json + ${{ runner.temp }}/postmaster-native/execroot/_main/bazel-out/**/testlogs/**/*runtime_test/test.outputs/postmaster-runtime/*.stdout + ${{ runner.temp }}/postmaster-native/execroot/_main/bazel-out/**/testlogs/**/*runtime_test/test.outputs/postmaster-runtime/*.stderr + ${{ runner.temp }}/postmaster-native/execroot/_main/bazel-out/**/testlogs/**/*runtime_test/test.outputs/postmaster-runtime/*.loader.jsonl + ${{ runner.temp }}/postmaster-native/execroot/_main/bazel-out/**/testlogs/**/linux_public_archive_test/test.outputs/postmaster-public-archive/archive-result.json + ${{ runner.temp }}/postmaster-native/execroot/_main/bazel-out/**/testlogs/**/linux_public_archive_test/test.outputs/postmaster-public-archive/*.stdout + ${{ runner.temp }}/postmaster-native/execroot/_main/bazel-out/**/testlogs/**/linux_public_archive_test/test.outputs/postmaster-public-archive/*.stderr + if-no-files-found: ignore + retention-days: 5 + + - *ci_request_receipts + + - name: Save bounded standard Bazel caches + if: ${{ always() }} + continue-on-error: true + timeout-minutes: 10 + uses: ./.github/actions/bazel-cache + with: + phase: save + cohort: postmaster + disk-cache-hit: ${{ steps.bazel-cache.outputs.disk-cache-hit }} + output-base: ${{ runner.temp }}/postmaster-native + jvm-args: -Xmx3g + + postmaster-host: + name: Native postmaster lifecycle (${{ matrix.platform }}) + if: ${{ !cancelled() && needs.release-inputs.result == 'success' && needs.postmaster.result == 'success' && fromJSON(needs.release-inputs.outputs.postmaster_host_matrix).include[0] != null }} + needs: [postmaster, release-inputs] + runs-on: ${{ matrix.runner }} + timeout-minutes: ${{ matrix.platform == 'macos-arm64' && 180 || 120 }} + permissions: + contents: read + actions: read + pull-requests: read + strategy: + fail-fast: false + matrix: ${{ fromJSON(needs.release-inputs.outputs.postmaster_host_matrix) }} + env: + CI_REQUEST_JOB: postmaster-host/${{ matrix.platform }} + CI_PLATFORM: ${{ matrix.platform }} + CI_MODE: ${{ needs.release-inputs.outputs.ci_mode }} + CI_SELECTED_REQUESTS: ${{ needs.release-inputs.outputs.ci_selected_requests }} + CI_CAPTURE_REQUESTS: ${{ needs.release-inputs.outputs.ci_capture_requests }} + steps: + - name: Checkout exact source + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + + - name: Acquire source-bound native inputs + uses: ./.github/actions/native-release-inputs + with: + run-id: ${{ needs.release-inputs.outputs.run_id }} + pull-number: ${{ needs.release-inputs.outputs.pull_number }} + public-artifact-id: ${{ needs.release-inputs.outputs.public_artifact_id }} + + - name: Restore bounded standard Bazel caches + id: bazel-cache + uses: ./.github/actions/bazel-cache + with: + phase: restore + cohort: postmaster-host + + - name: Select declared Apple SDK + if: matrix.platform == 'macos-arm64' + uses: ./.github/actions/setup-apple + with: + install-build-dependencies: "false" + + - name: Authenticate current Linux postmaster constructor inputs + if: contains(fromJSON(needs.release-inputs.outputs.ci_selected_requests), format('postmaster-host/{0}/carrier-lifecycle', matrix.platform)) + env: + GH_TOKEN: ${{ github.token }} + run: | + input_root="$RUNNER_TEMP/postmaster-build-inputs" + mkdir -p "$input_root" + printf '%s\n' '["liboliphaunt-wasix-postmaster"]' > "$input_root/consumer-products.json" + bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh tools/release/native-release-preparation.mts \ + --stage-release-archives --run-id "$GITHUB_RUN_ID" --ref "$GITHUB_REF" \ + --consumer-products-json "$input_root/consumer-products.json" \ + --output-directory target/postmaster-linux-import + + - name: Qualify native carrier from authenticated Linux guest + if: contains(fromJSON(needs.release-inputs.outputs.ci_selected_requests), env.CI_REQUEST_ID) + env: + CI_REQUEST_ID: postmaster-host/${{ matrix.platform }}/carrier-lifecycle + CI_REQUIRES: '["postmaster/linux-carrier-lifecycle"]' + EXPECTED_SOURCE_COMMIT: ${{ needs.postmaster.outputs.source_commit }} + EXPECTED_SOURCE_TREE: ${{ needs.postmaster.outputs.source_tree }} + TARGET_PLATFORM: ${{ matrix.platform }} + TARGET_COMPILER: ${{ matrix.compiler }} + TARGET_PREFIX: ${{ matrix.prefix }} + QUALIFICATION_JOB_NAME: Native postmaster lifecycle (${{ matrix.platform }}) + run: | + test "$(git rev-parse HEAD)" = "$EXPECTED_SOURCE_COMMIT" + test "$(git rev-parse 'HEAD^{tree}')" = "$EXPECTED_SOURCE_TREE" + input_root="$RUNNER_TEMP/postmaster-build-inputs" + mkdir -p "$input_root" + archive="$(jq -er '[.nativeCurrentArtifacts[] | select(.product == "liboliphaunt-wasix-postmaster" and (.artifact | startswith("github-release:")) and (.artifact | endswith("-linux-x64-gnu.tar.zst"))) | .file.path] | if length == 1 then .[0] else error("one original Linux postmaster archive required") end' "$OLIPHAUNT_NATIVE_PUBLICATION_INPUTS")" + jq -nc --arg repository "$GITHUB_REPOSITORY" --arg workflow "$GITHUB_WORKFLOW" \ + --arg workflowPath .github/workflows/bazel.yml --arg job "$QUALIFICATION_JOB_NAME" \ + --argjson runId "$GITHUB_RUN_ID" --argjson runAttempt "$GITHUB_RUN_ATTEMPT" \ + '{repository:$repository,workflow:$workflow,workflowPath:$workflowPath,runId:$runId,runAttempt:$runAttempt,job:$job}' \ + > "$input_root/github.json" + jq -nc --arg base "$RUNNER_TEMP/postmaster-native" \ + '["--output_base="+$base,"--host_jvm_args=-Xmx3g"]' > "$input_root/startup.json" + jq -nc --arg compiler "$TARGET_COMPILER" --arg archive "$archive" --arg platform "$TARGET_PLATFORM" \ + '["-c","opt","--platforms=//build_defs/wasix:portable","--host_platform="+$compiler, + "--extra_execution_platforms="+$compiler, + (if $platform == "macos-arm64" then "--jobs=2" else "--jobs=1" end),"--local_test_jobs=1", + "--repo_env=OLIPHAUNT_POSTMASTER_GUEST_ARCHIVE="+$archive] + + (if $platform == "macos-arm64" then ["--config=macos-sandbox"] else [] end)' \ + > "$input_root/configuration.json" + jq -nc --arg prefix "$TARGET_PREFIX" \ + '["//src/wasix/postmaster:"+$prefix+"_public_archive_test", + "//src/wasix/postmaster:"+$prefix+"_runtime_test"]' > "$input_root/targets.json" + printf '%s\n' "${CI_REQUIRES:-[]}" > "$input_root/ci-requires.json" + ci_arguments=(--ci-request-id "$CI_REQUEST_ID" --ci-job "$CI_REQUEST_JOB" --ci-mode "$CI_MODE" + --ci-requires-json "$input_root/ci-requires.json") + if jq -e --arg id "$CI_REQUEST_ID" 'index($id) != null' <<< "$CI_CAPTURE_REQUESTS" >/dev/null; then + ci_arguments+=(--ci-handoff) + fi + bash tools/dev/bun.sh tools/release/qualify-native-shipping.mts "${ci_arguments[@]}" \ + --github-json "$input_root/github.json" --startup-json "$input_root/startup.json" \ + --configuration-json "$input_root/configuration.json" \ + --shipping-export "//src/wasix/postmaster:${TARGET_PREFIX}_shipping_export" \ + --targets-json "$input_root/targets.json" \ + --output-directory "$RUNNER_TEMP/postmaster-build-capture" + mkdir -p "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID" + cp "$RUNNER_TEMP/postmaster-build-capture/ci-request.json" "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID/ci-request.json" + + - name: Upload native postmaster construction evidence + if: needs.release-inputs.outputs.ci_mode == 'full' || contains(fromJSON(needs.release-inputs.outputs.ci_capture_requests), format('postmaster-host/{0}/carrier-lifecycle', matrix.platform)) + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-build-evidence-postmaster-${{ matrix.platform }} + path: ${{ runner.temp }}/postmaster-build-capture/evidence/ + if-no-files-found: error + retention-days: 7 + + - name: Upload native postmaster build and query diagnostics + if: always() + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-postmaster-build-diagnostics-${{ matrix.platform }} + path: ${{ runner.temp }}/postmaster-build-capture/diagnostics/ + if-no-files-found: warn + retention-days: 7 + + - *ci_request_receipts + + - name: Save bounded standard Bazel caches + if: ${{ always() }} + continue-on-error: true + timeout-minutes: 10 + uses: ./.github/actions/bazel-cache + with: + phase: save + cohort: postmaster-host + disk-cache-hit: ${{ steps.bazel-cache.outputs.disk-cache-hit }} + output-base: ${{ runner.temp }}/postmaster-native + jvm-args: -Xmx3g + + react-native: + name: Native React Native consumers + if: ${{ !cancelled() && needs.release-inputs.result == 'success' && needs.portable.result == 'success' && contains(fromJSON(needs.release-inputs.outputs.ci_selected_jobs), 'react-native') }} + needs: [portable, release-inputs] + runs-on: macos-26 + timeout-minutes: 180 + env: + CI_REQUEST_JOB: react-native + CI_MODE: ${{ needs.release-inputs.outputs.ci_mode }} + CI_SELECTED_REQUESTS: ${{ needs.release-inputs.outputs.ci_selected_requests }} + CI_CAPTURE_REQUESTS: ${{ needs.release-inputs.outputs.ci_capture_requests }} + steps: + - name: Checkout exact source + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + + - name: Acquire source-bound native inputs + uses: ./.github/actions/native-release-inputs + with: + run-id: ${{ needs.release-inputs.outputs.run_id }} + pull-number: ${{ needs.release-inputs.outputs.pull_number }} + public-artifact-id: ${{ needs.release-inputs.outputs.public_artifact_id }} + + - name: Restore bounded standard Bazel caches + id: bazel-cache + uses: ./.github/actions/bazel-cache + with: + phase: restore + cohort: react-native + + - name: Select declared Apple SDK + uses: ./.github/actions/setup-apple + with: + install-build-dependencies: "false" + + - name: Authenticate final Apple and Swift consumer inputs + env: + GH_TOKEN: ${{ github.token }} + run: | + input_root="$RUNNER_TEMP/react-native-build-inputs" + mkdir -p "$input_root" + jq -nc '["oliphaunt-react-native"]' > "$input_root/consumer-products.json" + bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh tools/release/native-release-preparation.mts \ + --stage-release-archives --run-id "$GITHUB_RUN_ID" --ref "$GITHUB_REF" \ + --consumer-products-json "$input_root/consumer-products.json" \ + --output-directory target/native-react-native-archive-inputs + + - name: Qualify final React Native package and installed iOS consumer + if: contains(fromJSON(needs.release-inputs.outputs.ci_selected_requests), env.CI_REQUEST_ID) + # Leave time for authentication, diagnostics, and bounded cache saving. + timeout-minutes: 150 + env: + CI_REQUEST_ID: react-native/installed-consumer + CI_REQUIRES: '["portable/macos-arm64/apple-packages"]' + run: | + OLIPHAUNT_MOBILE_CANDIDATE_CHECKOUT="$(pwd -P)" + test "$OLIPHAUNT_MOBILE_CANDIDATE_CHECKOUT" = "$(cd "$GITHUB_WORKSPACE" && pwd -P)" + OLIPHAUNT_MOBILE_CANDIDATE_SHA="$(git rev-parse HEAD)" + OLIPHAUNT_MOBILE_CANDIDATE_TREE="$(git rev-parse 'HEAD^{tree}')" + test -z "$(git status --porcelain --untracked-files=no)" + export OLIPHAUNT_MOBILE_CANDIDATE_CHECKOUT OLIPHAUNT_MOBILE_CANDIDATE_SHA OLIPHAUNT_MOBILE_CANDIDATE_TREE + input_root="$RUNNER_TEMP/react-native-build-inputs" + jq -nc --arg repository "$GITHUB_REPOSITORY" --arg workflow "$GITHUB_WORKFLOW" \ + --arg workflowPath .github/workflows/bazel.yml --arg job 'Native React Native consumers' \ + --argjson runId "$GITHUB_RUN_ID" --argjson runAttempt "$GITHUB_RUN_ATTEMPT" \ + '{repository:$repository,workflow:$workflow,workflowPath:$workflowPath,runId:$runId,runAttempt:$runAttempt,job:$job}' \ + > "$input_root/github.json" + jq -nc --arg base "$RUNNER_TEMP/native-bazel" \ + '["--output_base="+$base,"--host_jvm_args=-Xmx3g"]' > "$input_root/startup.json" + jq -nc '["-c","opt","--config=macos-sandbox", + "--platforms=//build_defs/host:apple_package_macos_arm64", + "--host_platform=//build_defs/host:native_macos_arm64","--jobs=1","--local_test_jobs=1"]' \ + > "$input_root/configuration.json" + printf '%s\n' "${CI_REQUIRES:-[]}" > "$input_root/ci-requires.json" + ci_arguments=(--ci-request-id "$CI_REQUEST_ID" --ci-job "$CI_REQUEST_JOB" --ci-mode "$CI_MODE" + --ci-requires-json "$input_root/ci-requires.json") + if jq -e --arg id "$CI_REQUEST_ID" 'index($id) != null' <<< "$CI_CAPTURE_REQUESTS" >/dev/null; then + ci_arguments+=(--ci-handoff) + fi + bash tools/dev/bun.sh tools/release/qualify-native-shipping.mts "${ci_arguments[@]}" \ + --github-json "$input_root/github.json" --startup-json "$input_root/startup.json" \ + --configuration-json "$input_root/configuration.json" \ + --shipping-export //:native_react_native_shipping_export \ + --output-directory "$RUNNER_TEMP/react-native-build-capture" + mkdir -p "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID" + cp "$RUNNER_TEMP/react-native-build-capture/ci-request.json" "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID/ci-request.json" + + - name: Upload React Native construction evidence + if: needs.release-inputs.outputs.ci_mode == 'full' || contains(fromJSON(needs.release-inputs.outputs.ci_capture_requests), 'react-native/installed-consumer') + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-build-evidence-react-native-macos-arm64 + path: ${{ runner.temp }}/react-native-build-capture/evidence/ + if-no-files-found: error + retention-days: 7 + + - *ci_request_receipts + + - name: Upload React Native build and query diagnostics + if: always() + timeout-minutes: 5 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-react-native-diagnostics + path: | + ${{ runner.temp }}/react-native-build-capture/diagnostics/ + ${{ runner.temp }}/react-native-build-capture/build-events.jsonl + ${{ runner.temp }}/react-native-build-capture/aquery-build-events.jsonl + ${{ runner.temp }}/native-bazel/command.log + ${{ runner.temp }}/native-bazel/execroot/_main/bazel-out/**/testlogs/**/test.log + ${{ runner.temp }}/native-bazel/execroot/_main/bazel-out/**/testlogs/**/test.xml + ${{ runner.temp }}/native-bazel/execroot/_main/bazel-out/**/testlogs/src/examples/native/react-native-expo/ios_installed_test/test.outputs/** + if-no-files-found: ignore + retention-days: 5 + + - name: Save bounded standard Bazel caches + if: ${{ always() }} + continue-on-error: true + timeout-minutes: 10 + uses: ./.github/actions/bazel-cache + with: + phase: save + cohort: react-native + disk-cache-hit: ${{ steps.bazel-cache.outputs.disk-cache-hit }} + output-base: ${{ runner.temp }}/native-bazel + jvm-args: -Xmx3g + + release-families: + name: Native release families + if: ${{ !cancelled() && needs.release-inputs.result == 'success' && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') && contains(fromJSON(needs.release-inputs.outputs.ci_selected_jobs), 'release-families') }} + needs: [portable, linux, wasix, postmaster, postmaster-host, wasix-host, release-inputs] + runs-on: ubuntu-24.04 + timeout-minutes: 90 + permissions: + contents: read + actions: read + pull-requests: read + env: + CI_REQUEST_JOB: release-families + CI_MODE: ${{ needs.release-inputs.outputs.ci_mode }} + CI_SELECTED_REQUESTS: ${{ needs.release-inputs.outputs.ci_selected_requests }} + CI_CAPTURE_REQUESTS: ${{ needs.release-inputs.outputs.ci_capture_requests }} + steps: + - name: Checkout exact source + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + + - name: Acquire source-bound native inputs + uses: ./.github/actions/native-release-inputs + with: + run-id: ${{ needs.release-inputs.outputs.run_id }} + pull-number: ${{ needs.release-inputs.outputs.pull_number }} + public-artifact-id: ${{ needs.release-inputs.outputs.public_artifact_id }} + + - name: Restore bounded standard Bazel caches + id: bazel-cache + uses: ./.github/actions/bazel-cache + with: + phase: restore + cohort: release-families + + - name: Authenticate this run's completed archive producers + if: needs.release-inputs.outputs.ci_mode == 'full' && contains(fromJSON(needs.release-inputs.outputs.ci_selected_requests), 'release-families/checksums') + env: + GH_TOKEN: ${{ github.token }} + run: >- + bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh tools/release/native-release-preparation.mts + --stage-release-archives --run-id "$GITHUB_RUN_ID" --ref "$GITHUB_REF" + --output-directory target/native-release-archive-inputs + + - name: Qualify public Cargo source packages + if: contains(fromJSON(needs.release-inputs.outputs.ci_selected_requests), env.CI_REQUEST_ID) + env: + CI_REQUEST_ID: release-families/public-source + run: | + input_root="$RUNNER_TEMP/public-source-build-inputs" + mkdir -p "$input_root" + jq -nc --arg repository "$GITHUB_REPOSITORY" --arg workflow "$GITHUB_WORKFLOW" \ + --arg workflowPath .github/workflows/bazel.yml --arg job "Native release families" \ + --argjson runId "$GITHUB_RUN_ID" --argjson runAttempt "$GITHUB_RUN_ATTEMPT" \ + '{repository:$repository,workflow:$workflow,workflowPath:$workflowPath,runId:$runId,runAttempt:$runAttempt,job:$job}' \ + > "$input_root/github.json" + jq -nc '[ + "-c","opt","--platforms=//build_defs/native:linux_x86_64_glibc_2_28", + "--host_platform=//build_defs/native:linux_x86_64_glibc_2_28","--jobs=2" + ]' > "$input_root/configuration.json" + printf '%s\n' "${CI_REQUIRES:-[]}" > "$input_root/ci-requires.json" + ci_arguments=(--ci-request-id "$CI_REQUEST_ID" --ci-job "$CI_REQUEST_JOB" --ci-mode "$CI_MODE" + --ci-requires-json "$input_root/ci-requires.json") + if jq -e --arg id "$CI_REQUEST_ID" 'index($id) != null' <<< "$CI_CAPTURE_REQUESTS" >/dev/null; then + ci_arguments+=(--ci-handoff) + fi + bash tools/dev/bun.sh tools/release/qualify-native-shipping.mts "${ci_arguments[@]}" \ + --github-json "$input_root/github.json" --configuration-json "$input_root/configuration.json" \ + --shipping-export //:public_source_shipping_export \ + --output-directory "$RUNNER_TEMP/public-source-build-capture" + mkdir -p "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID" + cp "$RUNNER_TEMP/public-source-build-capture/ci-request.json" "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID/ci-request.json" + + - name: Qualify complete public checksum families + if: needs.release-inputs.outputs.ci_mode == 'full' && contains(fromJSON(needs.release-inputs.outputs.ci_selected_requests), env.CI_REQUEST_ID) + env: + CI_REQUEST_ID: release-families/checksums + CI_FULL_ONLY: 'true' + CI_REQUIRES: '["wasix-host/linux-arm64/napi","wasix-host/macos-arm64/napi","wasix-host/windows-x64/napi","portable/macos-arm64/native-carriers","portable/windows-x64/native-carriers","portable/macos-arm64/apple-packages","linux/x86_64/android-packages","linux/x86_64/native-carriers","linux/aarch64/native-carriers","wasix/tools-sdk-browser","postmaster/linux-carrier-lifecycle","postmaster-host/macos-arm64/carrier-lifecycle","postmaster-host/linux-arm64/carrier-lifecycle"]' + run: | + input_root="$RUNNER_TEMP/release-family-build-inputs" + mkdir -p "$input_root" + jq -nc --arg repository "$GITHUB_REPOSITORY" --arg workflow "$GITHUB_WORKFLOW" \ + --arg workflowPath .github/workflows/bazel.yml --arg job "Native release families" \ + --argjson runId "$GITHUB_RUN_ID" --argjson runAttempt "$GITHUB_RUN_ATTEMPT" \ + '{repository:$repository,workflow:$workflow,workflowPath:$workflowPath,runId:$runId,runAttempt:$runAttempt,job:$job}' \ + > "$input_root/github.json" + jq -nc '[ + "-c","opt","--platforms=//build_defs/native:linux_x86_64_glibc_2_28", + "--host_platform=//build_defs/native:linux_x86_64_glibc_2_28","--jobs=2" + ]' > "$input_root/configuration.json" + printf '%s\n' "${CI_REQUIRES:-[]}" > "$input_root/ci-requires.json" + ci_arguments=(--ci-request-id "$CI_REQUEST_ID" --ci-job "$CI_REQUEST_JOB" --ci-mode "$CI_MODE" + --ci-requires-json "$input_root/ci-requires.json") + if jq -e --arg id "$CI_REQUEST_ID" 'index($id) != null' <<< "$CI_CAPTURE_REQUESTS" >/dev/null; then + ci_arguments+=(--ci-handoff) + fi + bash tools/dev/bun.sh tools/release/qualify-native-shipping.mts "${ci_arguments[@]}" \ + --github-json "$input_root/github.json" --configuration-json "$input_root/configuration.json" \ + --shipping-export //:release_family_shipping_export \ + --output-directory "$RUNNER_TEMP/release-family-build-capture" + mkdir -p "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID" + cp "$RUNNER_TEMP/release-family-build-capture/ci-request.json" "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID/ci-request.json" + + - name: Upload public checksum construction evidence + if: needs.release-inputs.outputs.ci_mode == 'full' && contains(fromJSON(needs.release-inputs.outputs.ci_selected_requests), 'release-families/checksums') + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-build-evidence-release-families + path: ${{ runner.temp }}/release-family-build-capture/evidence/ + if-no-files-found: error + retention-days: 7 + + - *ci_request_receipts + + - name: Save bounded standard Bazel caches + if: ${{ always() }} + continue-on-error: true + timeout-minutes: 10 + uses: ./.github/actions/bazel-cache + with: + phase: save + cohort: release-families + disk-cache-hit: ${{ steps.bazel-cache.outputs.disk-cache-hit }} + + wasix-host: + name: WASIX imported runtime (${{ matrix.platform }}) + if: ${{ !cancelled() && needs.release-inputs.result == 'success' && needs.wasix.result == 'success' && fromJSON(needs.release-inputs.outputs.wasix_host_matrix).include[0] != null }} + needs: [wasix, release-inputs] + runs-on: ${{ matrix.runner }} + timeout-minutes: 90 + strategy: + fail-fast: false + matrix: ${{ fromJSON(needs.release-inputs.outputs.wasix_host_matrix) }} + env: + CI_REQUEST_JOB: wasix-host/${{ matrix.platform }} + CI_PLATFORM: ${{ matrix.platform }} + CI_MODE: ${{ needs.release-inputs.outputs.ci_mode }} + CI_SELECTED_REQUESTS: ${{ needs.release-inputs.outputs.ci_selected_requests }} + CI_CAPTURE_REQUESTS: ${{ needs.release-inputs.outputs.ci_capture_requests }} + steps: + - name: Checkout exact source + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + + - name: Acquire source-bound native inputs + uses: ./.github/actions/native-release-inputs + with: + run-id: ${{ needs.release-inputs.outputs.run_id }} + pull-number: ${{ needs.release-inputs.outputs.pull_number }} + public-artifact-id: ${{ needs.release-inputs.outputs.public_artifact_id }} + + - name: Restore bounded standard Bazel caches + id: bazel-cache + uses: ./.github/actions/bazel-cache + with: + phase: restore + cohort: wasix-host + + - name: Select declared Apple SDK + if: matrix.platform == 'macos-arm64' + uses: ./.github/actions/setup-apple + with: + install-build-dependencies: "false" + + - name: Select declared MSVC SDK + if: matrix.platform == 'windows-x64' + uses: ./.github/actions/setup-msvc + + # The immutable ID comes from this run's successful Linux producer. + # Receipt/source/hash validation remains mandatory in the Bazel importer. + - name: Download final Linux-built WASIX Cargo inputs + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + artifact-ids: ${{ needs.wasix.outputs.cargo_artifact_id }} + path: ${{ runner.temp }}/wasix-cargo-inputs + + - name: Authenticate current WASIX constructor inputs + if: contains(fromJSON(needs.release-inputs.outputs.ci_selected_jobs), format('wasix-host/{0}', matrix.platform)) + env: + GH_TOKEN: ${{ github.token }} + run: | + input_root="$RUNNER_TEMP/wasix-host-build-inputs" + mkdir -p "$input_root" + jq -nc '["oliphaunt-wasix-rust"]' > "$input_root/consumer-products.json" + bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh tools/release/native-release-preparation.mts \ + --stage-release-archives --run-id "$GITHUB_RUN_ID" --ref "$GITHUB_REF" \ + --consumer-products-json "$input_root/consumer-products.json" \ + --output-directory target/native-wasix-host-archive-inputs + + - name: Qualify imported AOT runtime on its native host + if: contains(fromJSON(needs.release-inputs.outputs.ci_selected_requests), env.CI_REQUEST_ID) + env: + CI_REQUIRES: '["wasix/tools-sdk-browser"]' + CI_REQUEST_ID: wasix-host/${{ matrix.platform }}/imported-runtime + EXPECTED_SOURCE_COMMIT: ${{ needs.wasix.outputs.source_commit }} + TARGET_PROFILE: ${{ matrix.profile }} + TARGET_PLATFORM: ${{ matrix.platform }} + run: | + test "$(git rev-parse HEAD)" = "$EXPECTED_SOURCE_COMMIT" + test -z "$(git status --porcelain)" + startup=() + configuration=() + if [[ "$TARGET_PLATFORM" == windows-x64 ]]; then + startup=(--output_base="$RUNNER_TEMP/b") + elif [[ "$TARGET_PLATFORM" == macos-arm64 ]]; then + startup=(--host_jvm_args=-Xmx3g) + configuration=(--config=macos-sandbox) + fi + ci_targets=(//src/wasix/sdks/rust:postgres_regression_test //build_defs/wasix:host_aot_smoke_test) + ci_configuration=("${configuration[@]}" "--platforms=$TARGET_PROFILE" "--host_platform=$TARGET_PROFILE" + "--repo_env=OLIPHAUNT_WASIX_SOURCE_COMMIT=$EXPECTED_SOURCE_COMMIT" + "--repo_env=OLIPHAUNT_WASIX_CARGO_INPUTS=$RUNNER_TEMP/wasix-cargo-inputs" + --jobs=2 --local_test_jobs=1 --test_env=OLIPHAUNT_WASM_AOT_VERIFY=full + "--test_env=XDG_CACHE_HOME=$RUNNER_TEMP/wasix-imported-sdk-cache" --test_env=RUST_TEST_THREADS=1) + ci_startup=("${startup[@]}") + ci_command='test' + ci_input_root="$RUNNER_TEMP/ci-request-inputs/$CI_REQUEST_ID" + mkdir -p "$ci_input_root" + jq -nc --args '$ARGS.positional' -- "${ci_targets[@]}" > "$ci_input_root/targets.json" + jq -nc --args '$ARGS.positional' -- "${ci_configuration[@]}" > "$ci_input_root/configuration.json" + jq -nc --args '$ARGS.positional' -- "${ci_startup[@]}" > "$ci_input_root/startup.json" + printf '%s\n' "$CI_REQUIRES" > "$ci_input_root/requires.json" + bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh tools/ci/run-configured-request.mts \ + --id "$CI_REQUEST_ID" --job "$CI_REQUEST_JOB" --mode "$CI_MODE" --command "$ci_command" \ + --targets-json "$ci_input_root/targets.json" --configuration-json "$ci_input_root/configuration.json" \ + --startup-json "$ci_input_root/startup.json" --requires-json "$ci_input_root/requires.json" \ + --output-directory "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID" + + - name: Qualify final WASIX addon on its native host + if: contains(fromJSON(needs.release-inputs.outputs.ci_selected_requests), env.CI_REQUEST_ID) + env: + CI_REQUEST_ID: wasix-host/${{ matrix.platform }}/napi + CI_REQUIRES: '["wasix/tools-sdk-browser"]' + EXPECTED_SOURCE_COMMIT: ${{ needs.wasix.outputs.source_commit }} + TARGET_PLATFORM: ${{ matrix.platform }} + QUALIFICATION_JOB_NAME: WASIX imported runtime (${{ matrix.platform }}) + run: | + test "$(git rev-parse HEAD)" = "$EXPECTED_SOURCE_COMMIT" + test -z "$(git status --porcelain)" + startup=() + configuration=() + case "$TARGET_PLATFORM" in + linux-arm64) profile=//build_defs/native:linux_aarch64_glibc_2_28 ;; + macos-arm64) + profile=//build_defs/host:native_macos_arm64 + startup=(--host_jvm_args=-Xmx3g) + configuration=(--config=macos-sandbox) + ;; + windows-x64) + profile=//build_defs/host:native_windows_x64 + startup=(--output_base="$RUNNER_TEMP/b") + ;; + esac + input_root="$RUNNER_TEMP/napi-build-inputs" + mkdir -p "$input_root" + jq -nc --arg repository "$GITHUB_REPOSITORY" --arg workflow "$GITHUB_WORKFLOW" \ + --arg workflowPath .github/workflows/bazel.yml --arg job "$QUALIFICATION_JOB_NAME" \ + --argjson runId "$GITHUB_RUN_ID" --argjson runAttempt "$GITHUB_RUN_ATTEMPT" \ + '{repository:$repository,workflow:$workflow,workflowPath:$workflowPath,runId:$runId,runAttempt:$runAttempt,job:$job}' \ + > "$input_root/github.json" + jq -nc --args '$ARGS.positional' -- "${startup[@]}" > "$input_root/startup.json" + jq -nc --args '$ARGS.positional' -- -c opt "${configuration[@]}" \ + "--platforms=$profile" "--host_platform=$profile" \ + "--repo_env=OLIPHAUNT_WASIX_SOURCE_COMMIT=$EXPECTED_SOURCE_COMMIT" \ + "--repo_env=OLIPHAUNT_WASIX_CARGO_INPUTS=$RUNNER_TEMP/wasix-cargo-inputs" \ + --jobs=1 --local_test_jobs=1 --test_env=OLIPHAUNT_WASM_AOT_VERIFY=full \ + > "$input_root/configuration.json" + printf '%s\n' "${CI_REQUIRES:-[]}" > "$input_root/ci-requires.json" + ci_arguments=(--ci-request-id "$CI_REQUEST_ID" --ci-job "$CI_REQUEST_JOB" --ci-mode "$CI_MODE" + --ci-requires-json "$input_root/ci-requires.json") + if jq -e --arg id "$CI_REQUEST_ID" 'index($id) != null' <<< "$CI_CAPTURE_REQUESTS" >/dev/null; then + ci_arguments+=(--ci-handoff) + fi + bash tools/dev/bun.sh tools/release/qualify-native-shipping.mts "${ci_arguments[@]}" \ + --github-json "$input_root/github.json" --startup-json "$input_root/startup.json" \ + --configuration-json "$input_root/configuration.json" \ + --shipping-export //:wasix_napi_shipping_export \ + --output-directory "$RUNNER_TEMP/napi-build-capture" + mkdir -p "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID" + cp "$RUNNER_TEMP/napi-build-capture/ci-request.json" "$RUNNER_TEMP/ci-requests/$CI_REQUEST_ID/ci-request.json" + + - name: Upload WASIX addon construction evidence + if: needs.release-inputs.outputs.ci_mode == 'full' || contains(fromJSON(needs.release-inputs.outputs.ci_capture_requests), format('wasix-host/{0}/napi', matrix.platform)) + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-build-evidence-napi-${{ matrix.platform }} + path: ${{ runner.temp }}/napi-build-capture/evidence/ + if-no-files-found: error + retention-days: 7 + + - name: Upload WASIX addon build diagnostics + if: ${{ always() && matrix.platform == 'macos-arm64' }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-wasix-addon-build-diagnostics-${{ matrix.platform }} + path: ${{ runner.temp }}/napi-build-capture/diagnostics/ + if-no-files-found: ignore + retention-days: 5 + + - *ci_request_receipts + + - name: Save bounded standard Bazel caches + if: ${{ always() }} + continue-on-error: true + timeout-minutes: 10 + uses: ./.github/actions/bazel-cache + with: + phase: save + cohort: wasix-host + disk-cache-hit: ${{ steps.bazel-cache.outputs.disk-cache-hit }} + output-base: ${{ matrix.platform == 'windows-x64' && format('{0}/b', runner.temp) || '' }} + jvm-args: ${{ matrix.platform == 'macos-arm64' && '-Xmx3g' || '' }} + + required: + name: Required + needs: [release-inputs, portable, linux, wasix, postmaster, postmaster-host, react-native, release-families, wasix-host] + if: always() && (github.event_name != 'pull_request' || github.event.action != 'closed') && needs.release-inputs.outputs.ci_mode == 'full' + runs-on: ubuntu-24.04 + timeout-minutes: 60 + steps: + - name: Require every native qualification job + env: + NEEDS_JSON: ${{ toJSON(needs) }} + run: jq -e 'all(.[]; .result == "success")' <<< "$NEEDS_JSON" + + - name: Checkout exact source + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + + - name: Set up verified Node.js and Bun + uses: ./.github/actions/setup-node-bun + + - name: Acquire source-bound native inputs + uses: ./.github/actions/native-release-inputs + with: + run-id: ${{ needs.release-inputs.outputs.run_id }} + pull-number: ${{ needs.release-inputs.outputs.pull_number }} + public-artifact-id: ${{ needs.release-inputs.outputs.public_artifact_id }} + + - name: Audit the completed native construction + env: + GH_TOKEN: ${{ github.token }} + run: >- + bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh + tools/release/audit-native-construction.mts + --run-id "$GITHUB_RUN_ID" --ref "$GITHUB_REF" + --output-directory "$RUNNER_TEMP/native-construction-audit" + + source-ci: + name: Source CI + needs: [release-inputs, portable, linux, wasix, postmaster, postmaster-host, react-native, release-families, wasix-host, required] + if: always() && (github.event_name != 'pull_request' || github.event.action != 'closed') + runs-on: ubuntu-24.04 + timeout-minutes: 20 + steps: + - name: Require a successful plan and every selected job + env: + NEEDS_JSON: ${{ toJSON(needs) }} + run: jq -e '."release-inputs".result == "success" and all(.[]; .result == "success" or .result == "skipped")' <<< "$NEEDS_JSON" + + - name: Checkout exact source + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + fetch-depth: 0 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + + - name: Set up verified Node.js and Bun + uses: ./.github/actions/setup-node-bun + + - name: Download source request plan + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + name: native-ci-plan + path: ${{ runner.temp }}/native-ci-plan + + - name: Download completed source request receipts + if: needs.release-inputs.outputs.ci_selected_requests != '[]' + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c + with: + pattern: native-ci-requests-* + merge-multiple: true + path: ${{ runner.temp }}/ci-requests + + - name: Verify selected requests and every omission + run: | + mkdir -p "$RUNNER_TEMP/ci-requests" + bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh tools/ci/configured-scope.mts verify \ + --plan "$RUNNER_TEMP/native-ci-plan/plan.json" --requests-dir "$RUNNER_TEMP/ci-requests" \ + --required-result '${{ needs.required.result }}' --basis-output "$RUNNER_TEMP/native-ci-basis/basis.json" + + - name: Upload admitted complete configured basis + if: needs.release-inputs.outputs.ci_mode == 'full' && needs.required.result == 'success' + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-ci-basis + path: ${{ runner.temp }}/native-ci-basis/basis.json + if-no-files-found: error + retention-days: 90 diff --git a/.github/workflows/continue-release-prepare.yml b/.github/workflows/continue-release-prepare.yml new file mode 100644 index 000000000..37e196bf5 --- /dev/null +++ b/.github/workflows/continue-release-prepare.yml @@ -0,0 +1,44 @@ +name: Continue release preparation +# Only trusted default-branch controller code runs. Canonical main run metadata +# and bounded, digest-authenticated intent are read as data; artifact contents +# and triggering-run code are never executed. The controller only reruns Prepare. +on: # zizmor: ignore[dangerous-triggers] authenticated completion controller without untrusted execution + workflow_run: + workflows: [Native Bazel qualification, Release] + types: [completed] +permissions: + contents: read +concurrency: + group: prepare-continuation-${{ github.event.workflow_run.head_sha }} + cancel-in-progress: false +defaults: + run: + shell: bash +jobs: + resume-prepare: + name: Resume authenticated original Prepare request + if: >- + ${{ github.repository == 'f0rr0/oliphaunt' && + github.event.workflow_run.head_repository.full_name == 'f0rr0/oliphaunt' && + github.event.workflow_run.head_branch == 'main' && + (github.event.workflow_run.name == 'Native Bazel qualification' || + (github.event.workflow_run.name == 'Release' && github.event.workflow_run.display_title == 'Release / prepare-release-pr / main')) && + (github.event.workflow_run.event == 'push' || github.event.workflow_run.event == 'workflow_dispatch') }} + runs-on: ubuntu-24.04 + timeout-minutes: 10 + permissions: + actions: write + contents: read + steps: + - name: Checkout trusted completion controller + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + ref: ${{ github.sha }} + fetch-depth: 1 + persist-credentials: false + - name: Set up verified Node.js and Bun + uses: ./.github/actions/setup-node-bun + - name: Authenticate retained intent and rerun original Prepare + env: + GH_TOKEN: ${{ github.token }} + run: bun tools/release/native-prepare-continuation.mts resume "$GITHUB_EVENT_PATH" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5ab9de45e..2ddbf3605 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -77,17 +77,78 @@ jobs: RELEASE_APPROVAL_RUN_ID: ${{ inputs.approval_run_id }} RELEASE_QUALIFICATION_RUN_ID: ${{ inputs.qualification_run_id }} run: bash .github/scripts/validate-release-workflow-inputs.sh - prepare-release-pr: - name: Prepare release PR + qualify-prepare-source: + name: Resolve native qualification for preparation needs: validate-inputs runs-on: ubuntu-24.04 - timeout-minutes: 20 + timeout-minutes: 10 if: ${{ inputs.operation == 'prepare-release-pr' }} environment: release-pr permissions: + actions: write + contents: read + outputs: + run_id: ${{ steps.native_qualification.outputs.run_id }} + steps: + - name: Require main + run: | + if [[ "$GITHUB_REF" != refs/heads/main ]]; then + echo "Releases must be run from main; got $GITHUB_REF" >&2 + exit 1 + fi + - name: Checkout exact preparation source + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + ref: ${{ github.sha }} + fetch-depth: 0 + persist-credentials: false + - name: Require current main + run: bash .github/scripts/require-current-main.sh "$GITHUB_SHA" + - name: Set up verified Node.js and Bun + uses: ./.github/actions/setup-node-bun + - name: Request or reuse exact Native qualification + id: native_qualification + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + run: >- + bash .github/scripts/require-workflow-success.sh 'Native Bazel qualification' "$GITHUB_SHA" 0 + --job Required --request-native-qualification + - name: Record pending exact-source Prepare intent + id: prepare_intent + if: ${{ steps.native_qualification.outputs.qualification_pending_run_id != '' }} + env: + RELEASE_OPERATION: ${{ inputs.operation }} + NATIVE_PENDING_RUN_ID: ${{ steps.native_qualification.outputs.qualification_pending_run_id }} + NATIVE_PENDING_RUN_ATTEMPT: ${{ steps.native_qualification.outputs.qualification_pending_run_attempt }} + run: bun tools/release/native-prepare-continuation.mts record "$RUNNER_TEMP/intent.json" + - name: Retain pending Prepare intent + if: ${{ steps.native_qualification.outputs.qualification_pending_run_id != '' }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: ${{ steps.prepare_intent.outputs.artifact_name }} + path: ${{ runner.temp }}/intent.json + if-no-files-found: error + retention-days: 30 + - name: Report pending automatic preparation + if: ${{ steps.native_qualification.outputs.qualification_pending_run_id != '' }} + env: + NATIVE_RUN_URL: ${{ steps.native_qualification.outputs.qualification_pending_run_url }} + run: | + printf 'Prepare is retained and will resume automatically after [Native qualification](%s) succeeds.\n' "$NATIVE_RUN_URL" >> "$GITHUB_STEP_SUMMARY" + prepare-release-pr: + name: Prepare release PR + needs: [validate-inputs, qualify-prepare-source] + runs-on: ubuntu-24.04 + timeout-minutes: 45 + if: ${{ inputs.operation == 'prepare-release-pr' && needs.qualify-prepare-source.outputs.run_id != '' }} + environment: release-pr + permissions: + actions: read contents: read issues: read pull-requests: read + attestations: read steps: - name: Require main run: | @@ -115,11 +176,10 @@ jobs: permission-contents: write permission-issues: write permission-pull-requests: write - - name: Set up Moon - uses: ./.github/actions/setup-moon - with: - task-cache: "false" - install-workspace: "true" + - name: Set up verified Node.js and Bun + uses: ./.github/actions/setup-node-bun + - name: Install locked release tooling + run: bun install --frozen-lockfile --filter @oliphaunt/release-tools --ignore-scripts - name: Set up Rust for dependency metadata and manifest synchronization uses: ./.github/actions/setup-rust with: @@ -128,10 +188,21 @@ jobs: id: prepare_candidate env: GH_TOKEN: ${{ steps.release_pr_token.outputs.token }} + NATIVE_QUALIFICATION_RUN_ID: ${{ needs.qualify-prepare-source.outputs.run_id }} run: bash tools/release/prepare-release-pr.sh "$RUNNER_TEMP/release-candidate" - name: Close and validate the local release candidate if: ${{ steps.prepare_candidate.outputs.required == 'true' }} + env: + NATIVE_QUALIFICATION_RUN_ID: ${{ needs.qualify-prepare-source.outputs.run_id }} run: bash tools/release/close-release-candidate.sh "$RUNNER_TEMP/release-candidate" + - name: Retain qualified native release inputs + if: ${{ steps.prepare_candidate.outputs.native_inputs == 'true' }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: native-release-inputs + path: ${{ runner.temp }}/release-candidate/native-release-inputs/ + if-no-files-found: error + retention-days: 30 - name: Publish the completed release PR tree if: ${{ steps.prepare_candidate.outputs.required == 'true' }} env: @@ -163,11 +234,10 @@ jobs: env: INPUT_RELEASE_COMMIT: ${{ inputs.release_commit }} run: .github/scripts/resolve-release-head.sh - - name: Set up Moon - uses: ./.github/actions/setup-moon - with: - task-cache: "false" - install-workspace: "true" + - name: Set up verified Node.js and Bun + uses: ./.github/actions/setup-node-bun + - name: Install locked release tooling + run: bash tools/dev/bun.sh install --frozen-lockfile --filter @oliphaunt/release-tools --ignore-scripts - name: Set up Cargo for dependency metadata uses: ./.github/actions/setup-rust with: @@ -187,48 +257,24 @@ jobs: status=$? [[ "$status" == 2 ]] || exit "$status" fi - bash .github/scripts/require-workflow-success.sh CI "$GITHUB_SHA" 0 --job Required - - name: Derive verified release scope - id: release_scope + bash .github/scripts/require-workflow-success.sh "Native Bazel qualification" "$GITHUB_SHA" 0 --job Required + - name: Derive verified Release Please publication scope + id: release_plan timeout-minutes: 2 + env: + GH_TOKEN: ${{ github.token }} run: | - bash tools/release/release-please-state.sh "$PWD" HEAD bash tools/release/with-release-history.sh "$PWD" "$RELEASE_HEAD_SHA" tools/dev/bun.sh tools/release/verify-publication-candidate.mts \ - --derive-products \ + bash tools/release/with-source.sh "$RELEASE_HEAD_SHA" bash tools/dev/bun.sh \ + tools/release/native-freeze-publication-candidate.mts --plan-publication \ --head-ref "$RELEASE_HEAD_SHA" \ --github-output "$GITHUB_OUTPUT" - - name: Plan product releases - id: release_plan - env: - PRODUCTS_JSON: ${{ steps.release_scope.outputs.products_json }} - run: | - release_plan_args=( - --from-product-tags - --include-current-tags - --products-json "$PRODUCTS_JSON" - --head-ref "$RELEASE_HEAD_SHA" - --format github-output - ) - bash tools/release/release-plan.sh "${release_plan_args[@]}" >> "$GITHUB_OUTPUT" - - name: No package release planned - if: ${{ steps.release_plan.outputs.has_release_changes != 'true' }} - run: echo "No release-affecting product changes were found since the last product tag." + echo "has_release_changes=true" >> "$GITHUB_OUTPUT" - name: Resolve selected registry authentication needs id: registry_needs if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} env: PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} run: bun .github/scripts/selected-registry-needs.mts - - name: Prove pending release identity - id: verify_publication_candidate - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} - timeout-minutes: 2 - env: - PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} - run: | - bash tools/release/release-please-state.sh "$PWD" HEAD bash tools/release/with-release-history.sh "$PWD" "$RELEASE_HEAD_SHA" tools/dev/bun.sh tools/release/verify-publication-candidate.mts \ - --products-json "$PRODUCTS_JSON" \ - --head-ref "$RELEASE_HEAD_SHA" \ - --github-output "$GITHUB_OUTPUT" - name: Prove Release Please PR can complete after publication id: assert_release_please_markable if: ${{ steps.release_plan.outputs.has_release_changes == 'true' }} @@ -238,84 +284,20 @@ jobs: run: | tools/dev/bun.sh tools/release/release-please-pr-lifecycle.mts \ assert-markable \ - --release-sha "${{ steps.verify_publication_candidate.outputs.release_sha }}" \ + --release-sha "${{ steps.release_plan.outputs.release_sha }}" \ --base main - - name: Plan qualification reuse or request - id: ci_qualification - if: ${{ steps.release_plan.outputs.has_release_changes == 'true' && inputs.approval_run_id == '' }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - REQUIRES_WASIX_EVIDENCE: ${{ steps.release_plan.outputs.requires_wasix_release_regression_evidence }} - REQUIRES_NATIVE_EVIDENCE: ${{ steps.release_plan.outputs.requires_native_extension_lifecycle_evidence }} - PRODUCTS_JSON: ${{ steps.release_plan.outputs.products_json }} - QUALIFICATION_RUN_ID: ${{ inputs.qualification_run_id }} - run: | - qualification_args=( - CI - "$RELEASE_HEAD_SHA" - 0 - --event push - --event workflow_dispatch - --job Builds - --job Required - --job Qualified - --artifact artifact-build-plan - --artifact oliphaunt-release-candidate - ) - if [[ -n "$QUALIFICATION_RUN_ID" ]]; then - qualification_args+=(--run-id "$QUALIFICATION_RUN_ID" --qualification-products "$PRODUCTS_JSON") - else - qualification_args+=(--plan-qualification "$PRODUCTS_JSON") - fi - if [[ "$REQUIRES_NATIVE_EVIDENCE" == true ]]; then - qualification_args+=(--artifact native-extension-lifecycle-evidence) - fi - if [[ "$REQUIRES_WASIX_EVIDENCE" == true ]]; then - qualification_args+=(--artifact wasix-release-regression-evidence) - fi - if [[ "${{ steps.release_plan.outputs.has_extension_artifacts }}" == true ]]; then - qualification_args+=(--artifact oliphaunt-extension-package-artifacts) - fi - bash .github/scripts/require-workflow-success.sh "${qualification_args[@]}" outputs: release_plan: ${{ toJSON(steps.release_plan.outputs) }} release_head: ${{ toJSON(steps.release_head.outputs) }} registry_needs: ${{ toJSON(steps.registry_needs.outputs) }} - verify_publication_candidate: ${{ toJSON(steps.verify_publication_candidate.outputs) }} - qualification_request_required: ${{ steps.ci_qualification.outputs.qualification_request_required }} - request-qualification: - name: Request missing CI qualification - needs: plan-candidate - if: ${{ needs.plan-candidate.outputs.qualification_request_required == 'true' }} - runs-on: ubuntu-24.04 - timeout-minutes: 5 - permissions: - actions: write - contents: read - steps: - - name: Checkout repository - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - with: - fetch-depth: 1 - persist-credentials: false - - name: Set up Bun - uses: ./.github/actions/setup-bun - - name: Request or reuse the candidate CI run - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - RELEASE_HEAD_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} - PRODUCTS_JSON: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).products_json }} - run: bash .github/scripts/require-workflow-success.sh CI "$RELEASE_HEAD_SHA" 120 --dispatch-qualification "$PRODUCTS_JSON" + verify_publication_candidate: ${{ toJSON(steps.release_plan.outputs) }} prepare-candidate: name: Prepare frozen publication candidate needs: - plan-candidate - - request-qualification runs-on: ubuntu-24.04 timeout-minutes: 360 - if: ${{ !cancelled() && needs.plan-candidate.result == 'success' && (needs.request-qualification.result == 'success' || needs.request-qualification.result == 'skipped') && fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' }} + if: ${{ !cancelled() && needs.plan-candidate.result == 'success' && fromJSON(needs.plan-candidate.outputs.release_plan).has_release_changes == 'true' }} environment: release-dry-run permissions: actions: read @@ -333,122 +315,28 @@ jobs: run: | .github/scripts/resolve-release-head.sh echo "OLIPHAUNT_GITHUB_RUN_SNAPSHOT_DIR=$RUNNER_TEMP/oliphaunt-github-run-snapshots" >> "$GITHUB_ENV" - - name: Set up Moon - uses: ./.github/actions/setup-moon - with: - task-cache: "false" - install-workspace: "true" - - name: Require qualified release-commit CI run + - name: Set up verified Node.js and Bun + uses: ./.github/actions/setup-node-bun + - name: Require exact-source native qualification id: ci_qualification if: ${{ inputs.approval_run_id == '' }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} - REQUIRES_WASIX_EVIDENCE: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).requires_wasix_release_regression_evidence }} - REQUIRES_NATIVE_EVIDENCE: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).requires_native_extension_lifecycle_evidence }} - PRODUCTS_JSON: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).products_json }} QUALIFICATION_RUN_ID: ${{ inputs.qualification_run_id }} run: | qualification_args=( - CI + "Native Bazel qualification" "$RELEASE_HEAD_SHA" 7200 - --qualification-products "$PRODUCTS_JSON" --event push --event workflow_dispatch - --job Builds --job Required - --job Qualified - --artifact artifact-build-plan - --artifact oliphaunt-release-candidate ) if [[ -n "$QUALIFICATION_RUN_ID" ]]; then qualification_args+=(--run-id "$QUALIFICATION_RUN_ID") fi - if [[ "$REQUIRES_NATIVE_EVIDENCE" == true ]]; then - qualification_args+=(--artifact native-extension-lifecycle-evidence) - fi - if [[ "$REQUIRES_WASIX_EVIDENCE" == true ]]; then - qualification_args+=(--artifact wasix-release-regression-evidence) - fi - if [[ "${{ fromJSON(needs.plan-candidate.outputs.release_plan).has_extension_artifacts }}" == true ]]; then - qualification_args+=(--artifact oliphaunt-extension-package-artifacts) - fi bash .github/scripts/require-workflow-success.sh "${qualification_args[@]}" - - name: Download exact-SHA qualification record - if: ${{ inputs.approval_run_id == '' }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - run: | - bash .github/scripts/download-build-artifacts.sh \ - CI \ - "$RELEASE_HEAD_SHA" \ - target/release-candidate \ - --run-id "$CI_RUN_ID" \ - --job Qualified \ - --artifact oliphaunt-release-candidate - - name: Download exact-SHA affected plan - if: ${{ inputs.approval_run_id == '' }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - run: | - bash .github/scripts/download-build-artifacts.sh \ - CI \ - "$RELEASE_HEAD_SHA" \ - target/release-candidate/affected-plan \ - --run-id "$CI_RUN_ID" \ - --job "Planning / Affected Work" \ - --artifact artifact-build-plan - - name: Download required exact-SHA WASIX evidence - if: ${{ inputs.approval_run_id == '' && fromJSON(needs.plan-candidate.outputs.release_plan).requires_wasix_release_regression_evidence == 'true' }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - run: | - bash .github/scripts/download-build-artifacts.sh \ - CI \ - "$RELEASE_HEAD_SHA" \ - target/release-candidate/wasix-evidence \ - --run-id "$CI_RUN_ID" \ - --job "E2E / WASIX Extension Lifecycle" \ - --artifact wasix-release-regression-evidence - - name: Download required exact-SHA native evidence - if: ${{ inputs.approval_run_id == '' && fromJSON(needs.plan-candidate.outputs.release_plan).requires_native_extension_lifecycle_evidence == 'true' }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - run: | - bash .github/scripts/download-build-artifacts.sh \ - CI \ - "$RELEASE_HEAD_SHA" \ - target/release-candidate/native-evidence \ - --run-id "$CI_RUN_ID" \ - --job "E2E / Native Extension Lifecycle Evidence" \ - --artifact native-extension-lifecycle-evidence - - name: Verify exact-SHA qualification record - id: verify_qualification - if: ${{ inputs.approval_run_id == '' }} - env: - PRODUCTS_JSON: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).products_json }} - CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - WASIX_EVIDENCE_REQUIRED: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).requires_wasix_release_regression_evidence }} - NATIVE_EVIDENCE_REQUIRED: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).requires_native_extension_lifecycle_evidence }} - run: | - bash .github/scripts/release-candidate.sh verify \ - target/release-candidate/oliphaunt-release-candidate.json \ - --plan target/release-candidate/affected-plan/ci-plan.json \ - --qualification-mode release \ - --products-json "$PRODUCTS_JSON" \ - --native-evidence-required "$NATIVE_EVIDENCE_REQUIRED" \ - --native-evidence-root target/release-candidate/native-evidence \ - --wasix-evidence-required "$WASIX_EVIDENCE_REQUIRED" \ - --wasix-evidence-root target/release-candidate/wasix-evidence - name: Require the explicitly selected prepared candidate id: approved_publication_lock if: ${{ inputs.approval_run_id != '' }} @@ -501,7 +389,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PRODUCTS_JSON: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).products_json }} run: | - bash tools/release/release-check-registries.sh \ + bash tools/release/release-check-registries.sh --native-preparation \ --products-json "$PRODUCTS_JSON" \ --head-ref "$RELEASE_HEAD_SHA" - name: Checkout qualified source for unchanged packaging @@ -510,379 +398,21 @@ jobs: bash tools/release/publication-controller.sh "$RELEASE_HEAD_SHA" "$GITHUB_SHA" git checkout --detach "$RELEASE_HEAD_SHA" bash tools/release/qualified-release-replay.sh "$RELEASE_HEAD_SHA" "$RELEASE_HEAD_SHA" - - name: Download WASIX runtime build artifacts - if: ${{ inputs.approval_run_id == '' && contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'liboliphaunt-wasix') }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - RELEASE_ARTIFACT_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} - run: bash .github/scripts/download-wasix-runtime-build-artifacts.sh - - name: Download WASIX release assets - if: ${{ inputs.approval_run_id == '' && contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'liboliphaunt-wasix') }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - RELEASE_ARTIFACT_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} - run: | - bash .github/scripts/download-build-artifacts.sh \ - CI \ - "$RELEASE_ARTIFACT_SHA" \ - target/oliphaunt-wasix/release-assets \ - --run-id "$CI_RUN_ID" \ - --job Builds \ - --artifact liboliphaunt-wasix-release-assets - - name: Download WASIX postmaster release assets - if: ${{ inputs.approval_run_id == '' && contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'liboliphaunt-wasix-postmaster') }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - RELEASE_ARTIFACT_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} - run: | - bash .github/scripts/download-build-artifacts.sh \ - CI \ - "$RELEASE_ARTIFACT_SHA" \ - target/oliphaunt-wasix-postmaster/release-assets \ - --run-id "$CI_RUN_ID" \ - --job Builds \ - --artifact liboliphaunt-wasix-postmaster-release-assets - - name: Download exact-extension package artifacts - if: ${{ inputs.approval_run_id == '' && fromJSON(needs.plan-candidate.outputs.release_plan).has_extension_artifacts == 'true' }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - RELEASE_ARTIFACT_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} - run: | - bash .github/scripts/download-build-artifacts.sh \ - CI \ - "$RELEASE_ARTIFACT_SHA" \ - target/extension-artifacts \ - --run-id "$CI_RUN_ID" \ - --job Builds \ - --artifact oliphaunt-extension-package-artifacts - - name: Download SDK package artifacts - if: ${{ inputs.approval_run_id == '' }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - PRODUCTS_JSON: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).products_json }} - CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - RELEASE_ARTIFACT_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} - run: | - download_sdk_artifact() { - local product="$1" - local artifact_args=() - while IFS= read -r artifact; do - artifact_args+=(--artifact "$artifact") - done < <(tools/dev/bun.sh tools/release/query.mts ci-artifact-names --product "$product" --family sdk-package --format lines) - bash .github/scripts/download-build-artifacts.sh \ - CI \ - "$RELEASE_ARTIFACT_SHA" \ - "target/sdk-artifacts/$product" \ - --run-id "$CI_RUN_ID" \ - --job Builds \ - "${artifact_args[@]}" - } - while IFS= read -r product; do - download_sdk_artifact "$product" - done < <(tools/dev/bun.sh tools/release/query.mts ci-products --family sdk-package --products-json "$PRODUCTS_JSON" --format lines) - - name: Download liboliphaunt release assets - if: ${{ inputs.approval_run_id == '' && contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'liboliphaunt-native') }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - RELEASE_ARTIFACT_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} - run: | - bash .github/scripts/download-build-artifacts.sh \ - CI \ - "$RELEASE_ARTIFACT_SHA" \ - target/liboliphaunt/release-assets \ - --run-id "$CI_RUN_ID" \ - --job Builds \ - --artifact liboliphaunt-native-release-assets - - name: Download canonical database resources - if: ${{ inputs.approval_run_id == '' && contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'database-resources') }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - RELEASE_ARTIFACT_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} - run: | - artifacts=() - for kind in icu-data native-seeds wasix-seeds; do - while IFS= read -r artifact; do - artifacts+=(--artifact "$artifact") - done < <(tools/dev/bun.sh tools/release/query.mts ci-artifact-names --product database-resources --kind "$kind" --family release-assets --format lines) - done - bash .github/scripts/download-build-artifacts.sh \ - CI \ - "$RELEASE_ARTIFACT_SHA" \ - target/database-resources/release-assets \ - --run-id "$CI_RUN_ID" \ - --job Builds \ - "${artifacts[@]}" - - name: Download native helper release assets - if: ${{ inputs.approval_run_id == '' && (contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-broker') || contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-node-direct') || contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-wasix-napi') || contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'postgres-tools-native') || contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'postgres-tools-wasix')) }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - PRODUCT_POSTGRES_TOOLS_WASIX: ${{ contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'postgres-tools-wasix') }} - PRODUCT_POSTGRES_TOOLS_NATIVE: ${{ contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'postgres-tools-native') }} - PRODUCT_OLIPHAUNT_BROKER: ${{ contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-broker') }} - PRODUCT_OLIPHAUNT_NODE_DIRECT: ${{ contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-node-direct') }} - PRODUCT_OLIPHAUNT_WASIX_NAPI: ${{ contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-wasix-napi') }} - CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - RELEASE_ARTIFACT_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} - run: | - download_helper_artifacts() { - local product="$1" - local kind="$2" - local destination="$3" - local artifact_args=() - while IFS= read -r artifact; do - artifact_args+=(--artifact "$artifact") - done < <(tools/dev/bun.sh tools/release/query.mts ci-artifact-names --product "$product" --kind "$kind" --family release-assets --format lines) - bash .github/scripts/download-build-artifacts.sh \ - CI \ - "$RELEASE_ARTIFACT_SHA" \ - "$destination" \ - --run-id "$CI_RUN_ID" \ - --job Builds \ - "${artifact_args[@]}" - } - if [ "$PRODUCT_POSTGRES_TOOLS_WASIX" = "true" ]; then - download_helper_artifacts postgres-tools-wasix wasix-tools target/postgres-tools/wasix/release-assets - download_helper_artifacts postgres-tools-wasix wasix-tools-aot target/postgres-tools/wasix/release-assets - fi - if [ "$PRODUCT_POSTGRES_TOOLS_NATIVE" = "true" ]; then - download_helper_artifacts postgres-tools-native native-tools target/postgres-tools/native/release-assets - fi - if [ "$PRODUCT_OLIPHAUNT_BROKER" = "true" ]; then - download_helper_artifacts \ - oliphaunt-broker \ - broker-helper \ - target/oliphaunt-broker/release-assets - fi - if [ "$PRODUCT_OLIPHAUNT_NODE_DIRECT" = "true" ]; then - download_helper_artifacts \ - oliphaunt-node-direct \ - node-direct-addon \ - target/oliphaunt-node-direct/release-assets - fi - if [ "$PRODUCT_OLIPHAUNT_WASIX_NAPI" = "true" ]; then - download_helper_artifacts \ - oliphaunt-wasix-napi \ - wasix-napi-addon \ - target/oliphaunt-wasix-napi/release-assets - fi - - name: Download Node direct optional npm packages - if: ${{ inputs.approval_run_id == '' && contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-node-direct') }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - RELEASE_ARTIFACT_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} - run: | - artifact_args=() - while IFS= read -r artifact; do - artifact_args+=(--artifact "$artifact") - done < <(tools/dev/bun.sh tools/release/query.mts ci-artifact-names --product oliphaunt-node-direct --kind node-direct-addon --family npm-package --format lines) - bash .github/scripts/download-build-artifacts.sh \ - CI \ - "$RELEASE_ARTIFACT_SHA" \ - target/oliphaunt-node-direct/npm-packages \ - --run-id "$CI_RUN_ID" \ - --job Builds \ - "${artifact_args[@]}" - - name: Download WASIX Node-API optional npm packages - if: ${{ inputs.approval_run_id == '' && contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-wasix-napi') }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GH_REPO: ${{ github.repository }} - CI_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} - RELEASE_ARTIFACT_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} - run: | - artifact_args=() - while IFS= read -r artifact; do - artifact_args+=(--artifact "$artifact") - done < <(tools/dev/bun.sh tools/release/query.mts ci-artifact-names --product oliphaunt-wasix-napi --kind wasix-napi-addon --family npm-package --format lines) - bash .github/scripts/download-build-artifacts.sh \ - CI \ - "$RELEASE_ARTIFACT_SHA" \ - target/oliphaunt-wasix-napi/npm-packages \ - --run-id "$CI_RUN_ID" \ - --job Builds \ - "${artifact_args[@]}" - - name: Freeze canonical Apple extension carrier input - if: ${{ inputs.approval_run_id == '' && (contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-swift') || contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-react-native')) }} - env: - PRODUCTS_JSON: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).products_json }} - includes_swift: ${{ contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-swift') }} - includes_react_native: ${{ contains(fromJson(fromJSON(needs.plan-candidate.outputs.release_plan).products_json), 'oliphaunt-react-native') }} - run: | - swift_source_carrier=target/sdk-artifacts/oliphaunt-swift/release-tree/src/sdks/swift/Carriers/oliphaunt-react-native-ios-carriers.json - react_native_source_carrier=target/sdk-artifacts/oliphaunt-react-native/ios-carriers/oliphaunt-react-native-ios-carriers.json - extension_manifest_args=() - extension_carrier_args=() - product_roots="$(tools/dev/bun.sh tools/release/query.mts \ - ci-products \ - --family extension-artifacts \ - --carrier-family native \ - --products-json "$PRODUCTS_JSON" \ - --field artifact-root \ - --format lines)" - while IFS= read -r product_root; do - [[ -n "$product_root" ]] || continue - product="$(basename "$product_root")" - manifest="$product_root/extension-artifacts.json" - if [[ ! -f "$manifest" ]]; then - echo "Selected extension product $product is missing $manifest" >&2 - exit 1 - fi - extension_manifest_args+=(--extension-manifest "$manifest") - product_carriers=() - while IFS= read -r carrier; do - product_carriers+=("$carrier") - done < <(find "$product_root/release-assets" -maxdepth 1 -type f -name '*-swift-extension-carrier.json' | LC_ALL=C sort) - if (( ${#product_carriers[@]} != 1 )); then - echo "Selected extension product $product must provide exactly one independent Swift carrier; found ${#product_carriers[@]}" >&2 - exit 1 - fi - extension_carrier_args+=(--extension-carrier "${product_carriers[0]}") - done <<< "$product_roots" - rm -rf target/release/ios-carriers target/release-work/ios-carriers - if [[ "$includes_swift" == true && "$includes_react_native" == true ]] && ! cmp -s "$swift_source_carrier" "$react_native_source_carrier"; then - echo 'Swift and React Native source carriers disagree for the same release plan.' >&2 - diff --unified "$swift_source_carrier" "$react_native_source_carrier" || true - exit 1 - fi - - if [[ "$includes_react_native" == true ]]; then - mkdir -p target/release/ios-carriers - public_carrier=target/release/ios-carriers/oliphaunt-react-native-ios-carriers.json - if (( ${#extension_manifest_args[@]} == 0 )); then - cp "$react_native_source_carrier" "$public_carrier" - else - public_args=( - --base-carrier "$react_native_source_carrier" - "${extension_manifest_args[@]}" - --output "$public_carrier" - ) - tools/dev/bun.sh src/native/sdks/swift/tools/ios-carrier-manifest.mts "${public_args[@]}" - fi - fi - - if [[ "$includes_swift" == true && ${#extension_manifest_args[@]} -gt 0 ]]; then - mkdir -p target/release-work/ios-carriers - local_aggregate_carrier=target/release-work/ios-carriers/oliphaunt-react-native-ios-carriers.json - local_args=( - --base-carrier "$swift_source_carrier" - "${extension_manifest_args[@]}" - --output "$local_aggregate_carrier" - --local-urls - ) - tools/dev/bun.sh src/native/sdks/swift/tools/ios-carrier-manifest.mts "${local_args[@]}" - extensions_csv="$(bun src/native/sdks/swift/tools/ios-carrier-manifest.mts list-extensions "$local_aggregate_carrier")" - if [[ -z "$extensions_csv" || ${#extension_carrier_args[@]} == 0 ]]; then - echo 'Swift extension validation requires selected extension carrier assets.' >&2 - exit 1 - fi - swift_version="$(tools/dev/bun.sh tools/release/product-version.mts version oliphaunt-swift)" - cache=target/release-work/swiftpm-extension-cache - bun src/native/sdks/swift/tools/render-extension-products.mts \ - --carrier "$local_aggregate_carrier" \ - --extensions "$extensions_csv" \ - --cache-dir "$cache" \ - --allow-file-urls \ - --base-package-version "$swift_version" \ - --output-dir target/release-work/swiftpm-extension-cache-warm - bun src/native/sdks/swift/tools/render-extension-products.mts \ - --carrier "$swift_source_carrier" \ - "${extension_carrier_args[@]}" \ - --extensions "$extensions_csv" \ - --cache-dir "$cache" \ - --offline \ - --base-package-version "$swift_version" \ - --output-dir target/release/swiftpm-extension-consumer-fixture - fi - - name: Set up pinned npm publisher - id: setup_github_stage_npm - if: ${{ fromJSON(needs.plan-candidate.outputs.registry_needs).needs_npm == 'true' }} - timeout-minutes: 3 - uses: ./.github/actions/setup-npm-publisher - with: - npm-version: ${{ env.NPM_VERSION }} - - name: Verify unchanged candidate source before assembly - id: validate_release - if: ${{ inputs.approval_run_id == '' }} - env: - CANDIDATE_SHA: ${{ fromJSON(needs.plan-candidate.outputs.release_head).sha }} - run: bash tools/release/qualified-release-replay.sh "$CANDIDATE_SHA" "$CANDIDATE_SHA" - - name: Package public release carriers - if: ${{ inputs.approval_run_id == '' }} - env: - OLIPHAUNT_BROKER_RELEASE_ASSET_INPUT_DIRS: ${{ github.workspace }}/target/oliphaunt-broker/release-assets - OLIPHAUNT_NODE_ADDON_ASSET_INPUT_DIRS: ${{ github.workspace }}/target/oliphaunt-node-direct/release-assets - OLIPHAUNT_WASIX_NAPI_ASSET_INPUT_DIRS: ${{ github.workspace }}/target/oliphaunt-wasix-napi/release-assets - PRODUCTS_JSON: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).products_json }} - run: bash tools/release/package-release-carriers.sh --products-json "$PRODUCTS_JSON" - - name: Freeze exhaustive publication lock + - name: Freeze authenticated native publication outputs id: freeze_publication_lock if: ${{ inputs.approval_run_id == '' }} env: + GH_TOKEN: ${{ github.token }} PRODUCTS_JSON: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).products_json }} + NATIVE_QUALIFICATION_RUN_ID: ${{ steps.ci_qualification.outputs.run_id }} run: | - lock_args=( - create - --products-json "$PRODUCTS_JSON" - --head-ref "$RELEASE_HEAD_SHA" - --output target/release/publication-lock.json - ) - for artifact_root in \ - target/release \ - target/sdk-artifacts \ - target/liboliphaunt/release-assets \ - target/liboliphaunt/cargo-artifacts \ - target/postgres-tools/native/release-assets \ - target/postgres-tools/native/cargo-artifacts \ - target/postgres-tools/wasix/release-assets \ - target/postgres-tools/wasix/cargo-artifacts \ - target/database-resources/release-assets \ - target/database-resources/cargo-artifacts \ - target/database-resources/seed-carriers \ - target/oliphaunt-wasix/release-assets \ - target/oliphaunt-wasix-postmaster/release-assets \ - target/oliphaunt-broker/release-assets \ - target/oliphaunt-broker/cargo-artifacts \ - target/oliphaunt-wasix/cargo-artifacts \ - target/oliphaunt-node-direct/release-assets \ - target/oliphaunt-node-direct/npm-packages \ - target/oliphaunt-wasix-napi/release-assets \ - target/oliphaunt-wasix-napi/npm-packages; do - if [[ -e "$artifact_root" ]]; then - lock_args+=(--artifact-root "$artifact_root") - fi - done - while IFS= read -r artifact_root; do - if [[ ! -d "$artifact_root" ]]; then - echo "Selected extension artifacts are missing $artifact_root" >&2 - exit 1 - fi - lock_args+=(--artifact-root "$artifact_root") - done < <(tools/dev/bun.sh tools/release/query.mts \ - ci-products \ - --family extension-artifacts \ + bash tools/release/qualified-release-replay.sh "$RELEASE_HEAD_SHA" "$RELEASE_HEAD_SHA" + bash tools/release/with-source.sh "$RELEASE_HEAD_SHA" bash tools/dev/bun.sh \ + tools/release/native-freeze-publication-candidate.mts \ + --run-id "$NATIVE_QUALIFICATION_RUN_ID" \ --products-json "$PRODUCTS_JSON" \ - --field artifact-root \ - --format lines) - bash tools/release/with-source.sh "$RELEASE_HEAD_SHA" bash tools/dev/bun.sh tools/release/publication-lock.mts "${lock_args[@]}" - bash tools/release/with-source.sh "$RELEASE_HEAD_SHA" bash tools/dev/bun.sh tools/release/publication-lock.mts \ - verify \ - --lock target/release/publication-lock.json \ - --head-ref "$RELEASE_HEAD_SHA" + --head-ref "$RELEASE_HEAD_SHA" \ + --output "$PUBLICATION_LOCK_PATH" - name: Freeze complete publication candidate id: freeze_publication_candidate if: ${{ inputs.approval_run_id == '' }} @@ -1126,16 +656,13 @@ jobs: env: INPUT_RELEASE_COMMIT: ${{ inputs.release_commit }} run: .github/scripts/resolve-release-head.sh - - name: Set up Moon - uses: ./.github/actions/setup-moon - with: - task-cache: "false" - install-workspace: "false" + - name: Set up verified Node.js and Bun + uses: ./.github/actions/setup-node-bun - name: Require checked publishing code env: GH_TOKEN: ${{ github.token }} GH_REPO: ${{ github.repository }} - run: bash .github/scripts/require-workflow-success.sh CI "$GITHUB_SHA" 0 --job Required + run: bash .github/scripts/require-workflow-success.sh "Native Bazel qualification" "$GITHUB_SHA" 0 --job Required - name: Prove Release Please PR can complete after bootstrap env: GH_TOKEN: ${{ github.token }} @@ -1205,16 +732,6 @@ jobs: --head-ref "$RELEASE_HEAD_SHA" \ --approval-run-id "$APPROVAL_RUN_ID" \ --workspace-root "$GITHUB_WORKSPACE" - - name: Verify external lock equals installed candidate lock - id: verify_bootstrap_lock - run: | - if ! cmp -s "$RUNNER_TEMP/approved-bootstrap/publication-lock.json" "$PUBLICATION_LOCK_PATH"; then - echo 'installed candidate lock differs from the separately downloaded approved publication lock' >&2 - exit 1 - fi - bash tools/release/with-source.sh "$RELEASE_HEAD_SHA" bash tools/dev/bun.sh tools/release/publication-lock.mts verify \ - --lock "$PUBLICATION_LOCK_PATH" \ - --head-ref "$RELEASE_HEAD_SHA" - name: Restore prior bootstrap checkpoint chain id: restore_bootstrap_checkpoint env: @@ -1454,16 +971,13 @@ jobs: env: INPUT_RELEASE_COMMIT: ${{ inputs.release_commit }} run: .github/scripts/resolve-release-head.sh - - name: Set up Moon - uses: ./.github/actions/setup-moon - with: - task-cache: "false" - install-workspace: "true" + - name: Set up verified Node.js and Bun + uses: ./.github/actions/setup-node-bun - name: Require checked publishing code env: GH_TOKEN: ${{ github.token }} GH_REPO: ${{ github.repository }} - run: bash .github/scripts/require-workflow-success.sh CI "$GITHUB_SHA" 0 --job Required + run: bash .github/scripts/require-workflow-success.sh "Native Bazel qualification" "$GITHUB_SHA" 0 --job Required - name: Set up Rust uses: ./.github/actions/setup-rust - name: Verify direct-workflow OIDC identity @@ -1575,7 +1089,7 @@ jobs: GITHUB_TOKEN: ${{ steps.check_release_tag_app.outputs.token }} PRODUCTS_JSON: ${{ fromJSON(needs.plan-candidate.outputs.release_plan).products_json }} run: | - bash tools/release/release-check-registries.sh \ + bash tools/release/release-check-registries.sh --native-preparation \ --products-json "$PRODUCTS_JSON" \ --head-ref "$RELEASE_HEAD_SHA" - name: Set up pinned npm publisher diff --git a/.gitignore b/.gitignore index 43cebf661..71576e025 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /target/ +/bazel-* /.local/ /.moon/cache/ node_modules/ diff --git a/BUILD.bazel b/BUILD.bazel new file mode 100644 index 000000000..bbe4c0880 --- /dev/null +++ b/BUILD.bazel @@ -0,0 +1,532 @@ +load("//build_defs/foundation:bun.bzl", "bun_test") +load("//build_defs/quality:biome.bzl", "biome_test") +load("//build_defs/quality:rust.bzl", "root_cargo_quality") +load("//build_defs/quality:rustfmt.bzl", "rustfmt_test") +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("@aspect_rules_ts//ts:defs.bzl", "ts_project") +load("//build_defs/release:shipping.bzl", "shipping_export") +load("//build_defs/languages/swift:extension-fixture.bzl", "selected_swift_extension_fixture_exports") + +package(default_visibility = ["//visibility:public"]) + +root_cargo_quality() + +# The conventional browser config maps SDK source outside its package. Keeping +# this stock TypeScript action at the repository root preserves that rootDir. +ts_project( + name = "browser_example_source_checks", + srcs = ["//src/examples/wasix/browser:source_files"], + tsconfig = {"compilerOptions": { + "rootDir": ".", + "outDir": ".", + "typeRoots": [ + "src/examples/wasix/browser/node_modules/@types", + "src/examples/wasix/browser/node_modules", + ], + }}, + extends = "//src/examples/wasix/browser:source_config", + no_emit = True, + declaration = True, + supports_workers = 0, + deps = ["//src/examples/wasix/browser:source_inputs"], +) + +exports_files([ + ".bazelrc", + ".bazelversion", + ".gitignore", + "biome.json", + "rustfmt.toml", + "clippy.toml", + ".github/scripts/check-ci-gate.mts", + ".github/scripts/check-release-intent.sh", + ".github/scripts/release-intent-data.mts", + ".github/zizmor.yml", + ".github/scripts/resolve-mobile-e2e.mts", + ".github/scripts/resolve-mobile-e2e.test.mts", + "src/third-party/tools/source-fetch-core.mts", + "src/third-party/tools/source-fetch-core.test.mts", + "src/third-party/tools/source-archive.mts", + "src/third-party/tools/source-fetch-scopes.mts", + "src/third-party/tools/source-fetch-scopes.test.mts", + "src/extensions/generated/extensions.catalog.json", + "src/extensions/generated/contrib-build.tsv", + "src/extensions/generated/pgxs-build.tsv", + "src/extensions/generated/wasix/extensions.json", + "src/extensions/generated/mobile/static-extensions.tsv", + "src/extensions/generated/mobile/static-registry.json", + "src/extensions/generated/docs/extension-evidence.json", + "src/extensions/artifacts/native/tools/ios-extension-registration.mts", + "src/extensions/artifacts/packages/tools/bundle-carrier-assets.mts", + "src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts", + "src/extensions/artifacts/packages/tools/package-extension-cargo-facades.mts", + "src/extensions/artifacts/native/tools/stage-windows-binary-contract.mts", + ".prototools", + "Cargo.toml", + "Cargo.lock", + "LICENSE", + "THIRD_PARTY_NOTICES.md", + "bun.lock", + "package.json", + "rust-toolchain.toml", + "release-please-config.json", + ".release-please-manifest.json", + "tools/packaging/archive-directory.mts", + "tools/packaging/atomic-directory.mts", + "tools/packaging/build-maven-artifact-manifest.mts", + "tools/packaging/emit-javascript.mts", + "tools/packaging/maven-central-contract.mts", + "tools/packaging/maven-artifact-manifest.mts", + "tools/packaging/maven-artifact-staging.mts", + "tools/packaging/npm-package.mts", + "tools/packaging/npm-package.test.mts", + "tools/packaging/release-carrier.mts", + "tools/packaging/sdk-runtime-payload.mts", + "tools/packaging/wasix-cargo-payload.mts", + "tools/packaging/native-cargo-payload.mts", + "tools/packaging/testdata/release-fixture-utils.mts", + "tools/packaging/testdata/tar-fixture.mts", + "tools/packaging/testdata/zip-fixture.mts", + "tools/packaging/portable-archive.mts", + "tools/packaging/strict-json.mts", + "tools/packaging/source-only-sdk-package.mts", + "tools/packaging/release-notices.mts", + "tools/packaging/rust-dependency-license-contract.mts", + "tools/packaging/release-directory-safety.mts", + "tools/packaging/package-archive.mts", + "tools/packaging/cargo-source-package.mts", + "tools/packaging/cargo-dependencies.mts", + "tools/packaging/cargo-manifest.mts", + "tools/packaging/frozen-cargo.mts", + "tools/packaging/npm-trusted-publishing.mts", + "tools/packaging/rust-native-targets.mts", + "tools/packaging/rust-build-script-sha256.mts", + "tools/packaging/platform-binary-contract.mts", + "tools/packaging/windows-vc-runtime-closure.mts", + "tools/packaging/windows-vc-runtime-policy.json", + "src/extensions/artifacts/packages/tools/contrib-carriers.mts", + "src/extensions/artifacts/packages/tools/extension-artifact-inventory.mts", + "src/extensions/artifacts/packages/tools/extension-runtime-asset-contract.mts", + "src/extensions/artifacts/packages/tools/package-extension-release-carriers.mts", + "src/extensions/artifacts/packages/tools/extension-registry-packages.mts", +]) + + +source_quality_files(name = "root_quality_sources") + +filegroup( + name = "quality_sources", + srcs = [ + ":root_quality_sources", + "//build_defs/android:quality_sources", + "//build_defs/apple:quality_sources", + "//build_defs/extensions:quality_sources", + "//build_defs/extensions/compiler_rt:quality_sources", + "//build_defs/extensions/postgis:quality_sources", + "//build_defs/extensions/wasix:quality_sources", + "//build_defs/foundation:quality_sources", + "//build_defs/host:quality_sources", + "//build_defs/languages:quality_sources", + "//build_defs/languages/carriers:quality_sources", + "//build_defs/languages/installed:quality_sources", + "//build_defs/languages/jvm:quality_sources", + "//build_defs/languages/swift:quality_sources", + "//build_defs/languages/ts:quality_sources", + "//build_defs/native:quality_sources", + "//build_defs/native/android:quality_sources", + "//build_defs/native/apple:quality_sources", + "//build_defs/native/carriers:quality_sources", + "//build_defs/query:quality_sources", + "//build_defs/release:quality_sources", + "//build_defs/resources:quality_sources", + "//build_defs/wasix:quality_sources", + "//build_defs/wasix/browser:quality_sources", + "//build_defs/wasix/browser/std:quality_sources", + "//build_defs/wasix/dependencies:quality_sources", + "//build_defs/wasix/postmaster:quality_sources", + "//src/database-resources:quality_sources", + "//src/database-resources/icu:quality_sources", + "//src/docs:quality_sources", + "//src/examples/wasix/browser:quality_sources", + "//src/extensions/catalog:quality_sources", + "//src/extensions/contracts:quality_sources", + "//src/extensions/external/pg_hashids:quality_sources", + "//src/extensions/external/pg_ivm:quality_sources", + "//src/extensions/external/pg_textsearch:quality_sources", + "//src/extensions/external/pg_uuidv7:quality_sources", + "//src/extensions/external/pgtap:quality_sources", + "//src/extensions/external/postgis:quality_sources", + "//src/extensions/external/vector:quality_sources", + "//src/extensions/generated/sdk:quality_sources", + "//src/extensions/tools:quality_sources", + "//src/native/broker:quality_sources", + "//src/native/mobile-bindings:quality_sources", + "//src/native/node-addon:quality_sources", + "//src/native/postgres-tools:quality_sources", + "//src/native/runtime:quality_sources", + "//src/native/sdks/kotlin:quality_sources", + "//src/native/sdks/kotlin/oliphaunt-android-gradle-plugin:quality_sources", + "//src/native/sdks/react-native:quality_sources", + "//src/native/sdks/rust:quality_sources", + "//src/native/sdks/swift:quality_sources", + "//src/native/sdks/ts:quality_sources", + "//src/query/ts:quality_sources", + "//src/third-party/postgres:quality_sources", + "//src/wasix/browser-host:quality_sources", + "//src/wasix/node-addon:quality_sources", + "//src/wasix/postgres-tools:quality_sources", + "//src/wasix/postgres-tools/ts:quality_sources", + "//src/wasix/postgres-tools/ts/tests/installed:quality_sources", + "//src/wasix/postmaster:quality_sources", + "//src/wasix/runtime:quality_sources", + "//src/wasix/sdks/rust:quality_sources", + "//src/wasix/sdks/ts:quality_sources", + "//src/wasix/sdks/ts/src/host:quality_sources", + "//tools/bazel:quality_sources", + "//tools/ci:quality_sources", + "//tools/dev:quality_sources", + "//tools/release:quality_sources", + "//build_defs/quality:quality_sources", + ], +) + +filegroup( + name = "root_rustfmt_sources", + srcs = glob(["src/benchmarks/perf/runner/**/*.rs", "src/extensions/tests/native/**/*.rs"]), +) + +filegroup( + name = "rustfmt_sources", + srcs = [ + ":root_rustfmt_sources", + "//src/query/rust:rustfmt_sources", + "//src/native/rust-bindings:rustfmt_sources", + "//src/native/mobile-bindings:rustfmt_sources", + "//src/native/sdks/rust:rustfmt_sources", + "//src/native/sdks/rust/crates/oliphaunt-build:rustfmt_sources", + "//src/native/broker:rustfmt_sources", + "//src/native/node-addon:rustfmt_sources", + "//src/native/runtime/packaging:rustfmt_sources", + "//src/native/postgres-tools:rustfmt_sources", + "//src/wasix/sdks/rust:rustfmt_sources", + "//src/wasix/pgwire-server:rustfmt_sources", + "//src/wasix/node-addon:rustfmt_sources", + "//src/wasix/runtime:rustfmt_sources", + "//src/wasix/runtime/tools/xtask:rustfmt_sources", + "//src/wasix/runtime/crates/assets:rustfmt_sources", + "//src/wasix/runtime/crates/aot/aarch64-apple-darwin:rustfmt_sources", + "//src/wasix/runtime/crates/aot/aarch64-unknown-linux-gnu:rustfmt_sources", + "//src/wasix/runtime/crates/aot/x86_64-pc-windows-msvc:rustfmt_sources", + "//src/wasix/runtime/crates/aot/x86_64-unknown-linux-gnu:rustfmt_sources", + "//src/wasix/postgres-tools:rustfmt_sources", + "//src/database-resources/icu:rustfmt_sources", + "//src/database-resources/seeds/wasix:rustfmt_sources", + "//src/wasix/postmaster:rustfmt_sources", + "//src/wasix/postmaster/tools/sealed-export-closure:rustfmt_sources", + ], +) + +bun_test( + name = "packaging_contract_test", + entry_point = "tools/packaging/platform-binary-contract.test.mts", + args = [ + "./tools/packaging/archive-directory.test.mts", + "./tools/packaging/atomic-directory.test.mts", + "./tools/packaging/cargo-dependencies.test.mts", + "./tools/packaging/cargo-source-package.test.mts", + "./tools/packaging/maven-artifact-staging.test.mts", + "./tools/packaging/maven-central-contract.test.mts", + "./tools/packaging/portable-archive.test.mts", + "./tools/packaging/portable-archive-extraction.test.mts", + "./tools/packaging/release-directory-safety.test.mts", + "./tools/packaging/release-notices.test.mts", + "./tools/packaging/source-only-sdk-package.test.mts", + "./tools/packaging/strict-json.test.mts", + "./tools/packaging/windows-vc-runtime-closure.test.mts", + ], + data = [ + ":root_quality_sources", + "//src/database-resources:seeds/carrier-identities.mts", + "//src/extensions/contracts:extension-target-profiles.mts", + "//src/native/mobile-bindings:tools/dependency-license-contract.mts", + "//src/wasix/runtime:tools/wasix-cargo-artifact-contract.mts", + "//tools/release:compatibility-version-parser.mts", + "//tools/release:extension-release-metadata.mts", + "//tools/release:platform-compatibility-policy.mts", + "//tools/release:release-artifact-targets.mts", + "//tools/release:release-graph.mts", + "//tools/release:release-history.mts", + "LICENSE", + "THIRD_PARTY_NOTICES.md", + "//src/native/runtime:THIRD_PARTY_NOTICES.md", + "//src/wasix/sdks/rust:THIRD_PARTY_NOTICES.md", + "//src/third-party/postgres:COPYRIGHT", + "//src/third-party/postgres:source.toml", + "//src/third-party/icu:LICENSE", + "//src/third-party/icu:source.toml", + "//src/third-party/openssl:LICENSE.txt", + "//src/third-party/openssl:source.toml", + ], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + size = "small", +) + +biome_test( + name = "biome_format_test", + mode = "format", + sources = [":quality_sources"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) + +biome_test( + name = "biome_lint_test", + mode = "lint", + sources = [":quality_sources"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) + +rustfmt_test( + name = "rustfmt_test", + source_files = [":rustfmt_sources"], +) + +filegroup( + name = "workflow_policy_sources", + srcs = glob([".github/workflows/*.yml", ".github/workflows/*.yaml", ".github/actions/**/action.yml", ".github/actions/**/action.yaml"], allow_empty = True), +) + +test_suite( + name = "portable_tests", + tests = [ + "//build_defs/apple:slices_test", + "//build_defs/resources:seed_construction_test", + "//build_defs/foundation:bun_toolchain_test", + "//build_defs/foundation:native_entry_test", + "//build_defs/foundation/fixtures/bun_imports:module_boundary_test", + "//build_defs/foundation/fixtures/bun_imports:external_collision_test", + "//build_defs/foundation:toolchain_metadata_test", + "//build_defs/host:host_sdk_test", + "//build_defs/host:profile_analysis_test", + "//build_defs/native:host_runtime_test_helpers_test", + "//build_defs/native:windows_exports_test", + "//build_defs/native:host_config_policy_test", + "//build_defs/native:compiler_probe_tool_inputs_test", + "//build_defs/extensions:forced_header_server_inputs_test", + "//build_defs/extensions:forced_header_embedded_inputs_test", + "//build_defs/extensions:mobile_host_ios_xcframework_test", + "//build_defs/extensions:mobile_host_android_arm64_v8a_test", + "//build_defs/extensions:mobile_host_android_x86_64_test", + "//build_defs/native:postgres_probe_header_test", + "//build_defs/extensions/postgis:gpp_test", + "//build_defs/native:icu_data_object_test", + "//build_defs/native:ios_device_profile_test", + "//build_defs/native:ios_simulator_profile_test", + "//build_defs/native:runtime_builtin_link_test", + "//build_defs/wasix:package_test", + "//build_defs/wasix:runtime_npm_test", + "//build_defs/wasix:runtime_cargo_test", + "//build_defs/wasix:tools_carriers_test", + "//build_defs/wasix:cargo_inputs_test", + "//build_defs/wasix:host_aot_smoke_inputs_test", + "//build_defs/wasix:host_aot_smoke_arguments_test", + "//build_defs/wasix/postmaster:metadata_test", + "//build_defs/wasix/postmaster:compile_metadata_test", + "//build_defs/wasix/postmaster:native_receipts_test", + "//build_defs/wasix/postmaster:receipt_reader_test", + "//build_defs/wasix/postmaster:runtime_abi_test", + "//build_defs/wasix/postmaster:libc_metadata_test", + "//build_defs/wasix/postmaster:libc_headers_test", + "//build_defs/wasix/postmaster:qualification_profile_test", + "//build_defs/wasix/postmaster:seal_modules_test", + "//build_defs/wasix/postmaster:postgres_overlay_paths_test", + "//build_defs/wasix/postmaster:postgres_overlay_traversal_test", + "//build_defs/wasix/postmaster:postgres_overlay_absolute_test", + "//build_defs/wasix/postmaster:postgres_overlay_empty_component_test", + "//build_defs/wasix/postmaster:postgres_overlay_backslash_test", + "//build_defs/wasix/postmaster:postgres_overlay_duplicate_test", + "//build_defs/android:metadata_test", + "//build_defs/android:android_min_sdk_test", + "//build_defs/android:installed_app_contract_test", + "//build_defs/languages:cargo_metadata_test", + "//build_defs/languages:napi_artifact_projection_test", + "//build_defs/languages:napi_artifact_kind_test", + "//build_defs/languages:wasix_napi_release_kind_test", + "//build_defs/languages:source_package_test", + "//build_defs/languages/installed:context_test", + "//build_defs/languages/ts:metadata_test", + "//build_defs/languages/swift:generate_test", + "//build_defs/languages/swift:xcframework_envelope_test", + "//build_defs/languages/swift:source_package_test", + "//build_defs/query:package_test", + "//build_defs/query:cargo_link_environment_test", + "//build_defs/query:nested_envelope_test", + "//src/query/rust:unit_test", + "//src/query/rust:consumer_test", + "//src/query/ts:unit_test", + "//src/query/ts:consumer_test", + "//src/native/sdks/ts:consumer_test", + "//build_defs/extensions:declared_final_inputs_test", + ], +) + +test_suite( + name = "native_linux_tests", + tests = [ + "//build_defs/languages/installed:source_compile_selection_test", + "//src/native/runtime:unix_abi_conformance_test", + "//src/native/runtime:unix_runtime_sql_test", + "//src/native/runtime:native_tools_sql_test", + "//build_defs/native:crypto_smoke_test", + "//build_defs/native:compiler_probe_test", + "//build_defs/native:probe_process_test", + "//build_defs/extensions:native_built_extension_sql_test", + "//build_defs/extensions:native_final_carriers_tests", + "//build_defs/extensions:native_final_contract_test", + "//build_defs/extensions:native_final_composition_test", + ], +) + +shipping_export( + name = "native_shipping_export", + testonly = True, + exports = [ + "//src/native/runtime:native_shipping_export", + "//src/native/postgres-tools:native_shipping_export", + "//src/native/broker:native_shipping_export", + "//src/native/node-addon:native_shipping_export", + "//src/native/rust-bindings:compiled_shipping_export", + "//src/database-resources:native_target_shipping_export", + "//src/extensions/contrib:native_shipping_export", + "//src/extensions/external/pg_hashids:native_shipping_export", + "//src/extensions/external/pg_ivm:native_shipping_export", + "//src/extensions/external/pg_textsearch:native_shipping_export", + "//src/extensions/external/pg_uuidv7:native_shipping_export", + "//src/extensions/external/pgtap:native_shipping_export", + "//src/extensions/external/postgis:native_shipping_export", + "//src/extensions/external/vector:native_shipping_export", + ] + select({ + "//build_defs/native:linux_x86_64": [ + "//src/native/postgres-tools:facade_shipping_export", + "//src/database-resources:icu_shipping_export", + "//src/query/rust:shipping_export", + "//src/query/ts:shipping_export", + "//src/native/sdks/ts:shipping_export", + "//src/native/sdks/kotlin:shipping_export", + ], + "//conditions:default": [], + }), +) + +shipping_export( + name = "native_android_shipping_export", + testonly = True, + exports = [ + "//src/native/runtime:android_shipping_export", + "//src/database-resources:android_shipping_export", + "//build_defs/extensions/mobile/final:android_shipping_export", + ], +) + +shipping_export( + name = "native_apple_shipping_export", + testonly = True, + exports = [ + "//src/native/runtime:apple_shipping_export", + "//src/database-resources:ios_shipping_export", + "//src/native/sdks/swift:shipping_export", + "//build_defs/extensions/mobile/final:ios_xcframework_shipping_export", + ], +) + +shipping_export( + name = "native_react_native_shipping_export", + testonly = True, + exports = ["//src/native/sdks/react-native:apple_shipping_export"], +) + +shipping_export( + name = "wasix_napi_shipping_export", + testonly = True, + exports = [ + "//src/wasix/node-addon:release_shipping_export", + "//src/wasix/sdks/rust:napi_release_compiled_shipping_export", + "//src/wasix/pgwire-server:napi_release_compiled_shipping_export", + ], +) + +shipping_export( + name = "wasix_shipping_export", + testonly = True, + exports = [ + "//src/wasix/runtime:shipping_export", + "//src/wasix/node-addon:release_shipping_export", + "//src/wasix/sdks/rust:napi_release_compiled_shipping_export", + "//src/wasix/pgwire-server:napi_release_compiled_shipping_export", + "//src/wasix/postgres-tools:shipping_export", + "//src/database-resources:wasix_shipping_export", + "//src/wasix/sdks/ts:shipping_export", + "//src/wasix/sdks/rust:shipping_export", + "//src/wasix/pgwire-server:shipping_export", + "//build_defs/extensions/wasix:contrib_shipping_export", + "//build_defs/extensions/wasix:pg_hashids_shipping_export", + "//build_defs/extensions/wasix:pg_ivm_shipping_export", + "//build_defs/extensions/wasix:pg_textsearch_shipping_export", + "//build_defs/extensions/wasix:pg_uuidv7_shipping_export", + "//build_defs/extensions/wasix:postgis_shipping_export", + "//build_defs/extensions/wasix:vector_shipping_export", + "//src/extensions/external/pgtap:wasix_shipping_export", + ], +) + +shipping_export( + name = "public_source_shipping_export", + testonly = True, + exports = [ + "//src/native/rust-bindings:shipping_export", + "//src/native/sdks/rust:shipping_export", + "//src/native/sdks/rust/crates/oliphaunt-build:shipping_export", + "//src/native/broker:shipping_export", + ], +) + +shipping_export( + name = "release_family_shipping_export", + testonly = True, + exports = [ + ":public_source_shipping_export", + "//src/native/runtime:checksum_shipping_export", + "//src/native/postgres-tools:checksum_shipping_export", + "//src/native/broker:checksum_shipping_export", + "//src/native/node-addon:checksum_shipping_export", + "//src/wasix/node-addon:checksum_shipping_export", + "//src/wasix/postmaster:release_shipping_export", + "//src/database-resources:checksum_shipping_export", + "//build_defs/extensions:contrib_native_family_shipping_export", + "//build_defs/extensions:contrib_wasix_family_shipping_export", + "//build_defs/extensions:pgtap_family_shipping_export", + "//build_defs/extensions:pg_hashids_family_shipping_export", + "//build_defs/extensions:pg_uuidv7_family_shipping_export", + "//build_defs/extensions:vector_family_shipping_export", + "//build_defs/extensions:pg_ivm_family_shipping_export", + "//build_defs/extensions:pg_textsearch_family_shipping_export", + "//build_defs/extensions:postgis_family_shipping_export", + ] + selected_swift_extension_fixture_exports(), +) + +# Source-only inputs for the existing SDK package policy tests. +exports_files([ + "src/examples/tools/example-release-dependencies.mts", +], visibility = ["//visibility:public"]) + +# Actual current checkout compilation precedes public installed admission. +# The Swift package roots and conventional held bytes stay identical. +shipping_export( + name = "native_apple_preparation_export", + testonly = True, + exports = [ + "//src/native/runtime:apple_shipping_export", + "//src/database-resources:ios_shipping_export", + "//src/native/sdks/swift:preparation_shipping_export", + "//build_defs/extensions/mobile/final:ios_xcframework_shipping_export", + ], +) diff --git a/Cargo.lock b/Cargo.lock index b7e737471..ca0c4aff4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2451,8 +2451,8 @@ dependencies = [ "libc", "liboliphaunt-native-bindings", "oliphaunt-broker", - "oliphaunt-build", - "oliphaunt-query", + "oliphaunt-build 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "oliphaunt-query 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde", "serde_json", "tokio", @@ -2465,7 +2465,7 @@ dependencies = [ "getrandom 0.3.4", "libc", "liboliphaunt-native-bindings", - "oliphaunt-query", + "oliphaunt-query 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2478,6 +2478,17 @@ dependencies = [ "toml 0.9.12+spec-1.1.0", ] +[[package]] +name = "oliphaunt-build" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a2a676749df3756473b4fd0deea7ef194a5d78bbcfb6fb46f5ae1da8f058f82" +dependencies = [ + "serde", + "sha2 0.10.9", + "toml 0.9.12+spec-1.1.0", +] + [[package]] name = "oliphaunt-icu" version = "0.2.2" @@ -2561,7 +2572,7 @@ version = "0.2.1" dependencies = [ "anyhow", "futures-util", - "oliphaunt-query", + "oliphaunt-query 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "oliphaunt-wasix", "serde_json", "sqlx", @@ -2575,6 +2586,12 @@ dependencies = [ name = "oliphaunt-query" version = "0.1.1" +[[package]] +name = "oliphaunt-query" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523a7416f6a830ef02928994a2a89e9fd9d01e4fe67b22f0480d377d5f9b235c" + [[package]] name = "oliphaunt-tools" version = "0.2.2" @@ -2600,7 +2617,7 @@ dependencies = [ "liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu", "liboliphaunt-wasix-portable", "oliphaunt-icu", - "oliphaunt-query", + "oliphaunt-query 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "oliphaunt-wasix-tools", "oliphaunt-wasix-tools-aot-aarch64-apple-darwin", "oliphaunt-wasix-tools-aot-aarch64-unknown-linux-gnu", @@ -5527,6 +5544,7 @@ version = "0.0.0" dependencies = [ "anyhow", "async-trait", + "inkwell", "serde", "serde_json", "sha2 0.10.9", diff --git a/Cargo.toml b/Cargo.toml index a6d658821..63ea93758 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,11 +5,12 @@ members = [ "src/native/mobile-bindings", "src/query/rust", "src/wasix/sdks/rust", + "src/wasix/node-addon", + "src/wasix/pgwire-server", "src/native/sdks/rust/crates/oliphaunt-build", "src/native/sdks/rust", "src/native/postgres-tools/crates/tools", "src/native/broker", - "src/wasix/pgwire-server", "src/database-resources/icu/cargo", "src/database-resources/seeds/wasix", "src/wasix/runtime/crates/assets", @@ -22,7 +23,6 @@ members = [ "src/wasix/postgres-tools/crates/aot/x86_64-unknown-linux-gnu", "src/wasix/postgres-tools/crates/aot/aarch64-unknown-linux-gnu", "src/wasix/postgres-tools/crates/aot/x86_64-pc-windows-msvc", - "src/wasix/node-addon", "src/benchmarks/perf/runner", "src/extensions/tests/native", "src/native/runtime/packaging", @@ -38,5 +38,10 @@ repository = "https://github.com/f0rr0/oliphaunt" homepage = "https://oliphaunt.dev" license = "MIT" +[workspace.dependencies] +# These adapters exchange Rust types/state with the SDK they adopt. +liboliphaunt-native-bindings = { path = "src/native/rust-bindings", version = "0.2.0" } +oliphaunt-wasix = { path = "src/wasix/sdks/rust", version = "0.3.2" } + [profile.release] strip = "symbols" diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 000000000..697965cb3 --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,857 @@ +module(name = "oliphaunt") + +bazel_dep(name = "platforms", version = "1.1.0") +bazel_dep(name = "bazel_skylib", version = "1.9.0") +bazel_dep(name = "bazel_lib", version = "3.7.0") +bazel_dep(name = "apple_support", version = "2.9.1") +bazel_dep(name = "rules_cc", version = "0.2.26") +bazel_dep(name = "rules_rust", version = "0.74.0") +# The generated Rust toolchain BUILD files use this mapping from our extension. +bazel_dep(name = "rules_shell", version = "0.8.0") +bazel_dep(name = "aspect_rules_js", version = "3.5.1") +bazel_dep(name = "aspect_rules_ts", version = "3.10.1") +bazel_dep(name = "rules_nodejs", version = "6.7.6") +bazel_dep(name = "rules_pkg", version = "1.3.0") +bazel_dep(name = "tar.bzl", version = "0.10.4") +bazel_dep(name = "hermetic_cc_toolchain", version = "4.3.0") +bazel_dep(name = "rules_apple", version = "5.2.0") +# Keep maintained resource/framework/signing implementations; declare licensed +# app-tool bytes in their ordinary tool runfiles and expose selected slice Files. +single_version_override( + module_name = "rules_apple", + version = "5.2.0", + patches = ["//build_defs/apple:declared-app-tools.patch"], + patch_strip = 1, +) + +bazel_dep(name = "rules_swift", version = "4.2.1") +bazel_dep(name = "rules_bison", version = "0.4.bcr.1") +bazel_dep(name = "rules_flex", version = "0.4.1") +bazel_dep(name = "rules_m4", version = "0.3.bcr.1") +bazel_dep(name = "rules_perl", version = "1.2.0") +bazel_dep(name = "rules_android_ndk", version = "0.1.5") +bazel_dep(name = "rules_java", version = "8.14.0") +bazel_dep(name = "rules_kotlin", version = "2.2.2") +bazel_dep(name = "rules_android", version = "0.6.6") +bazel_dep(name = "rules_robolectric", version = "4.14.1.2") +bazel_dep(name = "rules_jvm_external", version = "6.10") +# The separately hosted stock Maven extension emits this upstream metadata load. +bazel_dep(name = "package_metadata", version = "0.0.7") +bazel_dep(name = "rules_license", version = "1.0.0") +bazel_dep(name = "rules_cc_autoconf", version = "0.24.0") +bazel_dep(name = "gcc_toolchain", version = "0.12.0") +bazel_dep(name = "protobuf", version = "34.0.bcr.1") + +# The existing live documentation snapshot prepares these two declared files. +# Source-only checks do not resolve this repository. +local_repository = use_repo_rule("@bazel_tools//tools/build_defs/repo:local.bzl", "local_repository") +local_repository(name = "docs_build_inputs", path = "target/docs/native-inputs") + +# Apply the configured C++ dialect to Objective-C++ compilation too. +single_version_override( + module_name = "apple_support", + version = "2.9.1", + patches = ["//build_defs/host:apple-support-objcxx-flags.patch"], + patch_strip = 1, +) +single_version_override( + module_name = "rules_rust", + version = "0.74.0", + patches = [ + "//build_defs/wasix/browser:crate-source-metadata.patch", + "//build_defs/wasix/postmaster:crate-monorepo-source.patch", + "//build_defs/host:rules-rust-declared-archiver.patch", + "//build_defs/host:rules-rust-windows-dependency-paths.patch", + ], + patch_strip = 1, +) +single_version_override( + module_name = "rules_swift", + version = "4.2.1", + patches = ["//build_defs/host:rules-swift-declared-plugin-directory.patch"], + patch_strip = 1, +) +single_version_override( + module_name = "rules_cc_autoconf", + version = "0.24.0", + patches = ["//build_defs/native:patches/rules-cc-autoconf-native-process.patch", "//build_defs/native:patches/rules-cc-autoconf-fatal-diagnostics.patch"], + patch_strip = 1, +) +single_version_override( + module_name = "rules_android", + version = "0.6.6", + patches = ["//build_defs/languages/jvm:aar-import-android-bootclasspath.patch", "//build_defs/android:rules-android-min-sdk.patch"], + patch_strip = 1, +) +single_version_override( + module_name = "rules_jvm_external", + version = "6.10", + patches = ["//build_defs/android:rules-jvm-external-android-gradle.patch"], + patch_strip = 1, +) +single_version_override( + module_name = "hermetic_cc_toolchain", + version = "4.3.0", + patches = ["//build_defs/wasix:hermetic-cc-fused-colon.patch"], + patch_strip = 1, +) + +native_hosts = use_extension("//build_defs/host:repositories.bzl", "native_host_toolchains") +use_repo(native_hosts, "native_host_toolchains", "native_apple_sdk", "native_msvc_sdk") +register_toolchains("@native_host_toolchains//:all") + +zig_toolchains = use_extension("@hermetic_cc_toolchain//toolchain:ext.bzl", "toolchains") +use_repo(zig_toolchains, "zig_sdk") +register_toolchains( + "@zig_sdk//libc_aware/toolchain:linux_amd64_gnu.2.28", + "@zig_sdk//libc_aware/toolchain:linux_arm64_gnu.2.28", + "@zig_sdk//libc_aware/toolchain:linux_amd64_gnu.2.34", +) + +bun_runtime = use_repo_rule("//build_defs/foundation:repositories.bzl", "bun_runtime_repository") +bun_runtime(name = "bun_runtime") + +bun_execution = use_extension("//build_defs/foundation:repositories.bzl", "bun_toolchains") +use_repo(bun_execution, "bun_toolchains") +register_toolchains("@bun_toolchains//:all") + +quality_metadata = use_repo_rule("//build_defs/quality:repositories.bzl", "quality_metadata_repository") +quality_metadata(name = "oliphaunt_quality_metadata") +quality_tools = use_extension("//build_defs/quality:repositories.bzl", "quality_tools") +quality_tools.configure(metadata = "@oliphaunt_quality_metadata//:quality.json") +use_repo(quality_tools, "biome_linux_x64", "actionlint_linux_x64", "zizmor_linux_x64", "shellcheck_linux_x64") + +wasix_toolchain = use_repo_rule("//build_defs/wasix:repositories.bzl", "wasix_toolchain_repository") +wasix_toolchain(name = "wasix_toolchain") +register_toolchains("//build_defs/wasix/postmaster/libc_toolchain:toolchain", "//build_defs/wasix:cc_toolchain") + +postmaster_guest = use_repo_rule("//build_defs/wasix/postmaster:guest-repository.bzl", "postmaster_guest_repository") +postmaster_guest(name = "postmaster_guest") + +wasix_tool_metadata = use_repo_rule("//build_defs/wasix:repositories.bzl", "wasix_tool_metadata") +wasix_tool_metadata(name = "wasix_tool_metadata", bun = "@bun_runtime//:bun") + +wasmer_llvm_repository = use_repo_rule("//build_defs/wasix:repositories.bzl", "wasmer_llvm_repository") +wasmer_llvm_repository(name = "wasmer_llvm_linux_x64", host = "linux-x64-gnu") +wasmer_llvm_repository(name = "wasmer_llvm_linux_arm64", host = "linux-arm64-gnu") +wasmer_llvm_repository(name = "wasmer_llvm_macos_arm64", host = "macos-arm64") +wasmer_llvm_repository(name = "wasmer_llvm_windows_x64", host = "windows-x64-msvc") + +toolchain_metadata = use_repo_rule("//build_defs/foundation:repositories.bzl", "toolchain_metadata_repository") +toolchain_metadata(name = "oliphaunt_toolchain_metadata") + +languages = use_extension("//build_defs/foundation:extensions.bzl", "languages") +languages.configure(metadata = "@oliphaunt_toolchain_metadata//:toolchains.json") +use_repo(languages, "rust_toolchains", "query_types_node", "query_undici_types") +register_toolchains("@rust_toolchains//:all") + +stable_host_tools = use_extension("//build_defs/foundation:extensions.bzl", "rust_host_tools") +stable_host_tools.configure(metadata = "@oliphaunt_toolchain_metadata//:toolchains.json") +use_repo(stable_host_tools, "rust_host_tools") + +native_cargo_metadata = use_repo_rule("//build_defs/languages:repositories.bzl", "cargo_metadata_repository") +native_cargo_metadata( + name = "native_cargo_metadata", + roots = [], +) + +cargo_crates = use_extension("@rules_rust//crate_universe:extensions.bzl", "crate") +# Short physical Cargo hub names keep MSVC's relative includes below MAX_PATH; +# use_repo aliases preserve descriptive labels for the configured contexts. +cargo_crates.from_cargo( + name = "n", + host_tools = "@rust_host_tools//:BUILD.bazel", + cargo_lockfile = "@native_cargo_metadata//:Cargo.lock", + manifests = ["@native_cargo_metadata//:Cargo.toml"], + skip_cargo_lockfile_overwrite = True, + supported_platform_triples = [ + "x86_64-unknown-linux-gnu", + "aarch64-unknown-linux-gnu", + "aarch64-apple-darwin", + "x86_64-pc-windows-msvc", + "aarch64-apple-ios", + "aarch64-apple-ios-sim", + "aarch64-linux-android", + "x86_64-linux-android", + ], +) +use_repo(cargo_crates, cargo_crates = "n") + +# Cargo's test-noop forwarding applies only to the standalone Rust unit root. +cargo_crates.annotation( + crate = "napi", + repositories = ["n"], + additive_build_file_content = """ +load("@oliphaunt//build_defs/languages:napi-noop.bzl", "napi_noop_library") +napi_noop_library() +""", + extra_aliased_targets = {"napi_noop": "napi_noop"}, + label_injections = {"//build_defs/languages:napi-noop.bzl": "@oliphaunt"}, +) + +node = use_extension("@rules_nodejs//nodejs:extensions.bzl", "node") +node.toolchain(node_version_from_nvmrc = "@oliphaunt_toolchain_metadata//:node-version") +use_repo(node, "nodejs_toolchains") +register_toolchains("@nodejs_toolchains//:all") + +typescript = use_extension("@aspect_rules_ts//ts:extensions.bzl", "typescript") +typescript.deps(version_from = "@oliphaunt_toolchain_metadata//:typescript.json") +use_repo(typescript, "npm_typescript") + +postgres = use_repo_rule("//build_defs/native:repositories.bzl", "postgres_repository") +postgres(name = "postgres") + +# Local qualification declares the current host's generator binaries and data. +# This is an explicit development lane, not a hermetic release toolchain. +native_exec_tools = use_repo_rule("//build_defs/native:repositories.bzl", "native_exec_tools_repository") +native_exec_tools(name = "native_exec_tools") + +icu = use_repo_rule("//build_defs/native:repositories.bzl", "icu_repository") +icu(name = "icu") + +icu_data = use_repo_rule("//build_defs/native:icu_data.bzl", "icu_data_repository") +icu_data(name = "icu_data") + +domain_metadata = use_repo_rule("//build_defs/release:repositories.bzl", "domain_metadata") +domain_metadata(name = "oliphaunt_metadata", bun = "@bun_runtime//:bun") + +extension_sources = use_extension("//build_defs/extensions:repositories.bzl", "extension_sources") +use_repo(extension_sources, "pgtap", "pgvector", "pg_hashids", "pg_uuidv7", "pg_ivm", "pg_textsearch") + +# Append new acquisition contexts to keep existing repository identities stable. +postgres( + name = "postgres_wasix", + patch_series = "//src/wasix/runtime:postgres/series", + build_file = "//build_defs/wasix:postgres.BUILD.bazel", +) + +javascript_metadata = use_repo_rule("//build_defs/languages/ts:repositories.bzl", "javascript_metadata_repository") +javascript_metadata( + name = "oliphaunt_javascript_metadata", + manifests = [ + "//src/native/sdks/ts:package.json", + "//src/query/ts:package.json", + "//src/wasix/sdks/ts:package.json", + "//src/native/sdks/react-native:package.json", + "//src/wasix/postgres-tools/ts:package.json", + "//src/examples/wasix/browser:package.json", + ], + dependency_manifests = ["//src/wasix/postgres-tools:npm/package.json", "//src/docs:package.json", "//tools/release:package.json"], + consumer_tools = {"@oliphaunt/wasix-ts": ["vite"], "@oliphaunt/release-tools": ["protobufjs"]}, + consumer_workspaces = ["@oliphaunt/docs", "@oliphaunt/ts"], + consumer_graph_workspaces = ["@oliphaunt/ts"], + compiler_inputs = "//build_defs/languages/ts:compiler-inputs.json", +) +javascript_metadata( + name = "tools_installed_javascript_metadata", + package = "//src/wasix/postgres-tools/ts/tests/installed:package.json", + lockfile = "//src/wasix/postgres-tools/ts/tests/installed:bun.lock", + manifests = ["//src/wasix/postgres-tools/ts/tests/installed:package.json"], + consumer_tools = {"oliphaunt-wasix-tools-installed-consumer": ["@oliphaunt/wasix-ts"]}, +) +javascript_metadata( + name = "expo_app_javascript_metadata", + manifests = ["//src/native/sdks/react-native:package.json", "//src/query/ts:package.json"], + dependency_manifests = ["//src/examples/native/react-native-expo:package.json"], + consumer_workspaces = ["react-native-oliphaunt-expo"], + consumer_graph_workspaces = ["react-native-oliphaunt-expo"], +) +javascript_packages = use_extension("//build_defs/languages/ts:repositories.bzl", "javascript_packages") +javascript_packages.configure( + metadata = "@oliphaunt_javascript_metadata//:acquisition.json", + consumer_metadata = "@oliphaunt_javascript_metadata//:consumer-tools.json", + compiler_metadata = "@oliphaunt_javascript_metadata//:compiler-inputs.json", + installed_metadata = "@tools_installed_javascript_metadata//:consumer-tools.json", + android_app_metadata = "@expo_app_javascript_metadata//:consumer-tools.json", +) +use_repo(javascript_packages, "javascript_packages", "javascript_consumer_packages", "javascript_compiler_packages", "javascript_installed_packages", "javascript_android_app_packages") + +icu(name = "icu_wasix", build_file = "//build_defs/wasix:icu.BUILD.bazel") + +mobile_cargo_metadata = use_repo_rule("//build_defs/languages:repositories.bzl", "cargo_metadata_repository") +mobile_cargo_metadata( + name = "mobile_bindgen_cargo_metadata", + activations = {"src/native/mobile-bindings": ["bindgen"]}, +) +cargo_crates.from_cargo( + name = "m", + host_tools = "@rust_host_tools//:BUILD.bazel", + cargo_lockfile = "@mobile_bindgen_cargo_metadata//:Cargo.lock", + manifests = ["@mobile_bindgen_cargo_metadata//:Cargo.toml"], + skip_cargo_lockfile_overwrite = True, + supported_platform_triples = [ + "x86_64-unknown-linux-gnu", + "aarch64-unknown-linux-gnu", + "aarch64-apple-darwin", + "x86_64-pc-windows-msvc", + ], +) +use_repo(cargo_crates, mobile_bindgen_crates = "m") + +openssl = use_repo_rule("//build_defs/native:openssl_repository.bzl", "openssl_repository") +openssl(name = "openssl") + +use_repo(extension_sources, "postgis", "postgis_geos", "postgis_proj", "postgis_sqlite", "postgis_json_c", "postgis_libxml2", "postgis_libiconv") + +native_cargo_metadata( + name = "aot_serializer_cargo_metadata", + activations = {"src/wasix/runtime/tools/xtask": ["aot-serializer"]}, +) +cargo_crates.from_cargo( + name = "a", + host_tools = "@rust_host_tools//:BUILD.bazel", + cargo_lockfile = "@aot_serializer_cargo_metadata//:Cargo.lock", + manifests = ["@aot_serializer_cargo_metadata//:Cargo.toml"], + skip_cargo_lockfile_overwrite = True, + supported_platform_triples = [ + "x86_64-unknown-linux-gnu", + "aarch64-unknown-linux-gnu", + "aarch64-apple-darwin", + "x86_64-pc-windows-msvc", + ], +) +use_repo(cargo_crates, aot_serializer_crates = "a") + +browser_sources = use_repo_rule("//build_defs/wasix/browser:repositories.bzl", "browser_sources_repository") +browser_sources(name = "browser_sources") +browser_compilers = use_extension("//build_defs/wasix/browser:repositories.bzl", "browser_compilers") +browser_compilers.configure(metadata = "@browser_sources//:metadata.json") +use_repo(browser_compilers, "browser_npm", "browser_wasm_bindgen_linux_x64", "browser_binaryen_linux_x64") + +android_ndk = use_repo_rule("//build_defs/android:repositories.bzl", "android_ndk_repository") +android_ndk(name = "android_ndk") +register_toolchains("//build_defs/android:toolchain_arm64", "//build_defs/android:toolchain_x86_64") + +gradle_api = use_repo_rule("//build_defs/languages/jvm:repositories.bzl", "gradle_api_repository") +gradle_api(name = "oliphaunt_gradle_api") + +browser_cargo = use_extension("//build_defs/wasix/browser:cargo-extension.bzl", "crate") +browser_cargo.from_cargo( + name = "browser_cargo", + cargo_lockfile = "@browser_sources//:cargo/Cargo.lock", + source_metadata = "@browser_sources//:cargo-sources.json", + host_tools = "@browser_rust_std//:_metadata_tools/host-tools", + cargo_config = "@browser_sources//:wasmer-js/.cargo/config.toml", + manifests = ["@browser_sources//:cargo/Cargo.toml"], + skip_cargo_lockfile_overwrite = True, + supported_platform_triples = ["wasm32-unknown-unknown", "x86_64-unknown-linux-gnu"], +) +use_repo(browser_cargo, "browser_cargo") + +postgis_gpp = use_extension("//build_defs/extensions/postgis:gpp_repositories.bzl", "postgis_gpp") +use_repo(postgis_gpp, "postgis_gpp") + +browser_std = use_repo_rule("//build_defs/wasix/browser/std:repositories.bzl", "browser_std_repository") +browser_std(name = "browser_rust_std") +register_toolchains("//build_defs/wasix/browser/std:host_toolchain", "//build_defs/wasix/browser/std:wasm_toolchain") + +cargo_crates.annotation( + crate = "llvm-sys", + repositories = ["a"], + build_script_data = ["@oliphaunt//build_defs/wasix:wasmer_llvm_files"], + build_script_env_files = ["@oliphaunt//build_defs/wasix:wasmer_llvm_env"], + patches = ["//build_defs/wasix:llvm-sys-declared-prefix.patch"], + patch_args = ["-p1"], + link_deps = ["@aot_serializer_crates//:zstd"], + label_injections = { + "//build_defs/wasix:wasmer_llvm_files": "@oliphaunt", + "//build_defs/wasix:wasmer_llvm_gnu_link": "@oliphaunt", + "//build_defs/wasix:wasmer_llvm_gnu_files": "@oliphaunt", + "@aot_serializer_crates//:zstd": "@aot_serializer_crates", + }, +) +cargo_crates.annotation_select( + crate = "llvm-sys", + repositories = ["a", "s"], + triples = ["aarch64-unknown-linux-gnu"], + link_deps = ["@oliphaunt//build_defs/wasix:llvm_libxml2_arm64"], +) +cargo_crates.annotation_select( + crate = "llvm-sys", + repositories = ["a", "s"], + triples = ["x86_64-unknown-linux-gnu"], + link_deps = [ + "@oliphaunt//build_defs/extensions/postgis:libxml2", + "@oliphaunt//build_defs/wasix:wasmer_llvm_gnu_link", + ], + build_script_data = ["@oliphaunt//build_defs/wasix:wasmer_llvm_gnu_files"], + build_script_env_files = ["@oliphaunt//build_defs/wasix:wasmer_llvm_gnu_env"], +) + +kotlin_sdk_metadata = use_repo_rule("//build_defs/languages/jvm:kotlin-sdk-repository.bzl", "kotlin_sdk_metadata_repository") +kotlin_sdk_metadata(name = "oliphaunt_kotlin_manifest") +register_toolchains("//build_defs/languages/jvm:sdk_toolchain") + +kotlin_maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven") +kotlin_maven.from_toml( + name = "oliphaunt_kotlin_maven", + libs_versions_toml = "//src/native/sdks/kotlin:gradle/libs.versions.toml", +) +kotlin_maven.install( + name = "oliphaunt_kotlin_maven", + lock_file = "//src/native/sdks/kotlin:maven_install.json", + repositories = ["https://repo.maven.apache.org/maven2"], +) +kotlin_maven.amend_artifact( + name = "oliphaunt_kotlin_maven", + coordinates = "com.pinterest.ktlint:ktlint-cli", + testonly = "true", +) +kotlin_maven.from_toml( + name = "oliphaunt_android_lint_maven", + libs_versions_toml = "@oliphaunt_kotlin_manifest//:lint.versions.toml", +) +kotlin_maven.install( + name = "oliphaunt_android_lint_maven", + lock_file = "//build_defs/languages/jvm:lint_maven_install.json", + repositories = ["https://repo.maven.apache.org/maven2", "https://dl.google.com/dl/android/maven2"], +) +kotlin_maven.amend_artifact( + name = "oliphaunt_android_lint_maven", + coordinates = "com.android.tools.lint:lint-gradle", + testonly = "true", +) +kotlin_maven.override( + name = "rules_android_maven", + coordinates = "com.google.protobuf:protobuf-java", + target = "@protobuf//java/core:core", +) +kotlin_maven.override( + name = "android_ide_common_30_1_3", + coordinates = "com.google.protobuf:protobuf-java", + target = "@protobuf//java/core:core", +) +use_repo(kotlin_maven, "oliphaunt_kotlin_maven", "oliphaunt_android_lint_maven", "rules_android_maven") + +robolectric_sdks = use_extension("@rules_robolectric//bazel:extensions.bzl", "robolectric_repository_extensions") +use_repo( + robolectric_sdks, + "org_robolectric_android_all_instrumented_10_robolectric_5803371_i7", + "org_robolectric_android_all_instrumented_11_robolectric_6757853_i7", + "org_robolectric_android_all_instrumented_12_1_robolectric_8229987_i7", + "org_robolectric_android_all_instrumented_12_robolectric_7732740_i7", + "org_robolectric_android_all_instrumented_13_robolectric_9030017_i7", + "org_robolectric_android_all_instrumented_14_robolectric_10818077_i7", + "org_robolectric_android_all_instrumented_5_0_2_r3_robolectric_r0_i7", + "org_robolectric_android_all_instrumented_5_1_1_r9_robolectric_r2_i7", + "org_robolectric_android_all_instrumented_6_0_1_r3_robolectric_r1_i7", + "org_robolectric_android_all_instrumented_7_0_0_r1_robolectric_r1_i7", + "org_robolectric_android_all_instrumented_7_1_0_r7_robolectric_r1_i7", + "org_robolectric_android_all_instrumented_8_0_0_r4_robolectric_r1_i7", + "org_robolectric_android_all_instrumented_8_1_0_robolectric_4611349_i7", + "org_robolectric_android_all_instrumented_9_robolectric_4913185_2_i7", + robolectric_android_35 = "org_robolectric_android_all_instrumented_15_robolectric_12650502_i7", +) + +expo_android_sources = use_repo_rule("//build_defs/android:native-repository.bzl", "expo_android_sources_repository") +expo_android_sources(name = "expo_android_sources", metadata = "@expo_app_javascript_metadata//:consumer-tools.json") +expo_maven = use_extension("//build_defs/android:maven.bzl", "maven") +expo_maven.from_toml( + name = "expo_android_maven", + libs_versions_toml = "@expo_android_sources//:maven.versions.toml", +) +expo_maven.install( + name = "expo_android_maven", + lock_file = "//build_defs/android:expo_maven_install.json", + # Resolve the conventional Android variants and POM intervals with the + # maintained acquisition resolver; product construction remains Bazel. + resolver = "gradle", + repositories = ["https://repo.maven.apache.org/maven2", "https://dl.google.com/dl/android/maven2"], +) +expo_maven.override( + name = "expo_android_maven", + coordinates = "org.jetbrains.kotlin:kotlin-stdlib", + target = "@oliphaunt_kotlin_maven//:org_jetbrains_kotlin_kotlin_stdlib", +) +expo_maven.override( + name = "expo_android_maven", + coordinates = "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm", + target = "@oliphaunt_kotlin_maven//:org_jetbrains_kotlinx_kotlinx_coroutines_core_jvm", +) +expo_maven.override( + name = "expo_android_maven", + coordinates = "org.jetbrains:annotations", + target = "@oliphaunt_kotlin_maven//:org_jetbrains_annotations", +) +expo_maven.override( + name = "expo_android_maven", + coordinates = "com.squareup.zstd:zstd-kmp", + target = "@expo_android_maven//:com_squareup_zstd_zstd_kmp_android", +) +expo_maven.from_toml( + name = "expo_android_jna_maven", + libs_versions_toml = "@expo_android_sources//:jna-android.versions.toml", +) +expo_maven.install( + name = "expo_android_jna_maven", + lock_file = "//build_defs/android:expo_jna_maven_install.json", + repositories = ["https://repo.maven.apache.org/maven2"], + resolver = "coursier", +) +use_repo(expo_maven, "expo_android_jna_maven") +use_repo(expo_maven, "expo_android_maven") + +android_sdk_archive = use_repo_rule("//build_defs/languages/jvm:android-sdk-repository.bzl", "android_sdk_archive_repository") +android_sdk_archive(name = "oliphaunt_android_sdk_archive") +android_sdk_hub = use_repo_rule("//build_defs/languages/jvm:android-sdk-repository.bzl", "android_sdk_hub_repository") +android_sdk_hub(name = "oliphaunt_android_sdk", archive = "oliphaunt_android_sdk_archive") +android_sdk = use_extension("@rules_android//rules/android_sdk_repository:rule.bzl", "android_sdk_repository_extension") +override_repo(android_sdk, androidsdk = "oliphaunt_android_sdk") + +frozen_native_runtime = use_repo_rule("//build_defs/release:frozen-native-runtime.bzl", "frozen_native_runtime_repository") +frozen_native_runtime( + name = "held_native", + releases = "//build_defs/release:native-0.3.2-releases.json", + completion = "//build_defs/release:native-0.3.2-completed-publication.json", + descriptor = "//src/native/sdks/rust:release.toml", + compatibility = "//src/native/sdks/rust:Cargo.toml", + compatibility_path = "src/native/sdks/rust/Cargo.toml", + targets = ["linux-x64-gnu"], +) + +frozen_native_runtime( + name = "kotlin_frozen_native", + releases = "//build_defs/release:native-0.3.3-releases.json", + completion = "//build_defs/release:native-0.3.3-completed-publication.json", + descriptor = "//src/native/sdks/kotlin:release.toml", + compatibility = "//src/native/sdks/kotlin/oliphaunt-android-gradle-plugin:src/main/resources/dev/oliphaunt/android/liboliphaunt.version", + compatibility_path = "src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/liboliphaunt.version", + targets = ["linux-x64-gnu"], +) + +frozen_native_runtime( + name = "extension_frozen_native", + releases = "//build_defs/release:native-0.3.3-releases.json", + completion = "//build_defs/release:native-0.3.3-completed-publication.json", + descriptor = "//src/extensions/external/postgis:release.toml", + compatibility = "//src/extensions/external/postgis:release.toml", + compatibility_path = "src/extensions/external/postgis/release.toml", + targets = ["linux-x64-gnu"], +) + +frozen_native_runtime( + name = "extension_frozen_native_macos", + releases = "//build_defs/release:native-0.3.3-releases.json", + completion = "//build_defs/release:native-0.3.3-completed-publication.json", + descriptor = "//src/extensions/external/postgis:release.toml", + compatibility = "//src/extensions/external/postgis:release.toml", + compatibility_path = "src/extensions/external/postgis/release.toml", + targets = ["macos-arm64"], +) + +frozen_native_runtime( + name = "extension_frozen_native_windows", + releases = "//build_defs/release:native-0.3.3-releases.json", + completion = "//build_defs/release:native-0.3.3-completed-publication.json", + descriptor = "//src/extensions/external/postgis:release.toml", + compatibility = "//src/extensions/external/postgis:release.toml", + compatibility_path = "src/extensions/external/postgis/release.toml", + targets = ["windows-x64-msvc"], +) + +installed_cargo_inputs = use_repo_rule("//build_defs/languages/installed:repositories.bzl", "installed_cargo_repository") +installed_cargo_inputs(name = "installed_cargo_inputs", bun = "@bun_runtime//:bun") + +compiler_rt_repository = use_repo_rule("//build_defs/extensions/compiler_rt:repositories.bzl", "compiler_rt_repository") +compiler_rt_repository(name = "pgvector_compiler_rt", source = "//build_defs/extensions/compiler_rt:source.json") + +frozen_native_npm = use_repo_rule("//build_defs/release:frozen-native-npm.bzl", "frozen_native_npm_repository") +frozen_native_npm( + name = "node_frozen_native", + metadata = "//build_defs/release:native-0.3.2-npm-linux-x64-gnu.json", + attestations = "//build_defs/release:native-0.3.2-npm-linux-x64-gnu-attestations.json", + releases = "//build_defs/release:native-0.3.2-releases.json", + completion = "//build_defs/release:native-0.3.2-completed-publication.json", + descriptor = "//src/native/sdks/ts:release.toml", + compatibility = "//src/native/sdks/ts:package.json", + compatibility_path = "src/native/sdks/ts/package.json", + target = "linux-x64-gnu", +) + +frozen_native_npm( + name = "node_frozen_native_linux_arm64_gnu", + metadata = "//build_defs/release:native-0.3.2-npm-linux-arm64-gnu.json", + attestations = "//build_defs/release:native-0.3.2-npm-linux-arm64-gnu-attestations.json", + releases = "//build_defs/release:native-0.3.2-releases.json", + completion = "//build_defs/release:native-0.3.2-completed-publication.json", + descriptor = "//src/native/sdks/ts:release.toml", + compatibility = "//src/native/sdks/ts:package.json", + compatibility_path = "src/native/sdks/ts/package.json", + target = "linux-arm64-gnu", +) + +frozen_native_npm( + name = "node_frozen_native_macos_arm64", + metadata = "//build_defs/release:native-0.3.2-npm-macos-arm64.json", + attestations = "//build_defs/release:native-0.3.2-npm-macos-arm64-attestations.json", + releases = "//build_defs/release:native-0.3.2-releases.json", + completion = "//build_defs/release:native-0.3.2-completed-publication.json", + descriptor = "//src/native/sdks/ts:release.toml", + compatibility = "//src/native/sdks/ts:package.json", + compatibility_path = "src/native/sdks/ts/package.json", + target = "macos-arm64", +) + +frozen_native_npm( + name = "node_frozen_native_windows_x64_msvc", + metadata = "//build_defs/release:native-0.3.2-npm-windows-x64-msvc.json", + attestations = "//build_defs/release:native-0.3.2-npm-windows-x64-msvc-attestations.json", + releases = "//build_defs/release:native-0.3.2-releases.json", + completion = "//build_defs/release:native-0.3.2-completed-publication.json", + descriptor = "//src/native/sdks/ts:release.toml", + compatibility = "//src/native/sdks/ts:package.json", + compatibility_path = "src/native/sdks/ts/package.json", + target = "windows-x64-msvc", +) + +# LLVM's GNU C++ ABI and helper runtime use this maintained pinned provider; +# target compilation remains on the registered Zig glibc 2.28 toolchain. +llvm_gnu_runtime = use_repo_rule("@gcc_toolchain//toolchain:defs.bzl", "gcc_toolchain") +llvm_gnu_runtime( + name = "llvm_gnu_runtime", + target_arch = "x86_64", + gcc_version = "12.5.0", + binary_prefix = "auto", + enable_fortran = False, +) + +# Independent feature acquisition preserves the headless SDK's feature set. +native_cargo_metadata( + name = "wasix_seed_cargo_metadata", + activations = {"src/database-resources/seeds/wasix": ["cluster-seed-runner"]}, +) +cargo_crates.from_cargo( + name = "s", + host_tools = "@rust_host_tools//:BUILD.bazel", + cargo_lockfile = "@wasix_seed_cargo_metadata//:Cargo.lock", + manifests = ["@wasix_seed_cargo_metadata//:Cargo.toml"], + skip_cargo_lockfile_overwrite = True, + supported_platform_triples = [ + "x86_64-unknown-linux-gnu", + "aarch64-unknown-linux-gnu", + "aarch64-apple-darwin", + "x86_64-pc-windows-msvc", + ], +) +use_repo(cargo_crates, wasix_seed_crates = "s") + +# Keep Mach-O sections valid and serialized GOT relocation ordering repeatable. +cargo_crates.annotation( + crate = "wasmer-compiler-llvm", + version = "=7.2.1", + repositories = ["a", "s"], + patches = ["//build_defs/wasix:wasmer-macho-trampoline.patch"], + patch_args = ["-p1"], +) + +cargo_crates.annotation( + crate = "llvm-sys", + repositories = ["s"], + build_script_data = ["@oliphaunt//build_defs/wasix:wasmer_llvm_files"], + build_script_env_files = ["@oliphaunt//build_defs/wasix:wasmer_llvm_env"], + patches = ["//build_defs/wasix:llvm-sys-declared-prefix.patch"], + patch_args = ["-p1"], + link_deps = ["@wasix_seed_crates//:zstd"], + label_injections = { + "//build_defs/wasix:wasmer_llvm_files": "@oliphaunt", + "//build_defs/wasix:wasmer_llvm_gnu_link": "@oliphaunt", + "//build_defs/wasix:wasmer_llvm_gnu_files": "@oliphaunt", + "@wasix_seed_crates//:zstd": "@wasix_seed_crates", + }, +) + +# The pinned postmaster workspace keeps its executor/compiler feature contexts +# independent of the current WASIX SDK workspace. +postmaster_wasmer = use_repo_rule("//build_defs/wasix/postmaster:repositories.bzl", "postmaster_wasmer_repository") +postmaster_wasmer(name = "postmaster_wasmer") + +postmaster_cargo = use_repo_rule("//build_defs/wasix/postmaster:repositories.bzl", "postmaster_cargo_repository") +postmaster_cargo( + name = "postmaster_cargo", + roles = { + "executor": "oliphaunt-wasix-postmaster-executor", + "compiler": "oliphaunt-wasix-postmaster-compiler", + }, +) + +postmaster_crates = use_extension("//build_defs/wasix/postmaster:cargo-extension.bzl", "crate") +postmaster_crates.from_cargo( + name = "postmaster_executor_crates", + cargo_lockfile = "@postmaster_cargo//:executor/Cargo.lock", + manifests = ["@postmaster_cargo//:executor/Cargo.toml"], + host_tools = "@rust_host_tools//:BUILD.bazel", + source_metadata = "@postmaster_cargo//:cargo-sources.json", + skip_cargo_lockfile_overwrite = True, + supported_platform_triples = ["x86_64-unknown-linux-gnu", "aarch64-unknown-linux-gnu", "aarch64-apple-darwin"], +) +postmaster_crates.from_cargo( + name = "postmaster_compiler_crates", + cargo_lockfile = "@postmaster_cargo//:compiler/Cargo.lock", + manifests = ["@postmaster_cargo//:compiler/Cargo.toml"], + host_tools = "@rust_host_tools//:BUILD.bazel", + source_metadata = "@postmaster_cargo//:cargo-sources.json", + skip_cargo_lockfile_overwrite = True, + supported_platform_triples = ["x86_64-unknown-linux-gnu", "aarch64-unknown-linux-gnu", "aarch64-apple-darwin"], +) +postmaster_crates.from_cargo( + name = "postmaster_sealing_crates", + cargo_lockfile = "//src/wasix/postmaster/tools/sealed-export-closure:Cargo.lock", + manifests = ["//src/wasix/postmaster/tools/sealed-export-closure:Cargo.toml"], + host_tools = "@rust_host_tools//:BUILD.bazel", + skip_cargo_lockfile_overwrite = True, + supported_platform_triples = ["x86_64-unknown-linux-gnu", "aarch64-unknown-linux-gnu", "aarch64-apple-darwin"], +) +use_repo(postmaster_crates, "postmaster_executor_crates", "postmaster_compiler_crates", "postmaster_sealing_crates") + +# Detect the actual hidden, statically linked LLVM unwinder on native ELF hosts. +postmaster_crates.annotation( + crate = "wasmer-compiler", + version = "=7.2.0-alpha.2", + repositories = ["postmaster_executor_crates", "postmaster_compiler_crates"], + rustc_flags = ["--cfg=oliphaunt_linked_libunwind"], + link_deps = ["@oliphaunt//build_defs/wasix/postmaster:linked_unwinder"], + label_injections = {"//build_defs/wasix/postmaster:linked_unwinder": "@oliphaunt"}, +) + +# Core Cargo consumers use source construction on Linux or exact final-file inputs. +wasix_runtime_carriers = use_repo_rule("//build_defs/wasix:carriers-repository.bzl", "wasix_runtime_carriers_repository") +wasix_runtime_carriers(name = "wasix_runtime_carriers", bun = "@bun_runtime//:bun") +# One-way compile facts from the conventional manifest and the two real hubs. +postmaster_compile_metadata = use_repo_rule("//build_defs/wasix/postmaster:repositories.bzl", "postmaster_compile_metadata_repository") +postmaster_compile_metadata(name = "postmaster_compile_metadata") + +# The compile metadata alias selects the actual compiler-context zstd crate. +postmaster_crates.annotation( + crate = "llvm-sys", + version = "=221.0.1", + repositories = ["postmaster_compiler_crates"], + build_script_data = ["@oliphaunt//build_defs/wasix:wasmer_llvm_files"], + build_script_env_files = ["@oliphaunt//build_defs/wasix:wasmer_llvm_env"], + patches = ["//build_defs/wasix:llvm-sys-declared-prefix.patch"], + patch_args = ["-p1"], + link_deps = ["@oliphaunt//build_defs/wasix/postmaster:llvm_zstd"], + label_injections = { + "//build_defs/wasix:wasmer_llvm_files": "@oliphaunt", + "//build_defs/wasix:wasmer_llvm_gnu_link": "@oliphaunt", + "//build_defs/wasix:wasmer_llvm_gnu_files": "@oliphaunt", + "//build_defs/wasix/postmaster:llvm_zstd": "@oliphaunt", + }, +) +postmaster_crates.annotation_select( + crate = "llvm-sys", + version = "=221.0.1", + repositories = ["postmaster_compiler_crates"], + triples = ["aarch64-unknown-linux-gnu"], + link_deps = ["@oliphaunt//build_defs/wasix:llvm_libxml2_arm64"], +) +postmaster_crates.annotation_select( + crate = "llvm-sys", + version = "=221.0.1", + repositories = ["postmaster_compiler_crates"], + triples = ["x86_64-unknown-linux-gnu"], + link_deps = [ + "@oliphaunt//build_defs/extensions/postgis:libxml2", + "@oliphaunt//build_defs/wasix:wasmer_llvm_gnu_link", + ], + build_script_data = ["@oliphaunt//build_defs/wasix:wasmer_llvm_gnu_files"], + build_script_env_files = ["@oliphaunt//build_defs/wasix:wasmer_llvm_gnu_env"], +) + +# The full postmaster uses its own patched PostgreSQL and libc source contexts. +postgres( + name = "postmaster_postgres", + patch_series = "//src/wasix/postmaster:postgres/series", + build_file = "//build_defs/wasix/postmaster:postgres.BUILD.bazel", + overlays = { + "//src/wasix/postmaster:postgres/overlays/wasix-core/" + path: path + for path in [ + "src/template/wasix-core", + "src/makefiles/Makefile.wasix-core", + "src/include/port/wasix-core.h", + "src/backend/postmaster/fork_process.c", + "src/backend/port/sysv_shmem.c", + "src/interfaces/libpq/wasix_encoding_shim.c", + ] + }, +) + +postmaster_wasix_libc = use_repo_rule("//build_defs/wasix/postmaster:repositories.bzl", "postmaster_wasix_libc_repository") +postmaster_wasix_libc(name = "postmaster_wasix_libc") + +winflexbison = use_repo_rule("//build_defs/native:windows-generators.bzl", "windows_generators_repository") +winflexbison(name = "winflexbison") +register_toolchains("@winflexbison//:flex_toolchain", "@winflexbison//:bison_toolchain") + +# Reuse existing installed_cargo_inputs = use_repo_rule(...), no new resolver. +installed_cargo_inputs( + name = "installed_wasix_sdk_cargo_inputs", + bun = "@bun_runtime//:bun", + lock = "//build_defs/languages/installed:wasix/sdk/Cargo.lock", + index = "//build_defs/languages/installed:wasix/sdk/registry-index.json", +) +installed_cargo_inputs( + name = "installed_pgwire_cargo_inputs", + bun = "@bun_runtime//:bun", + lock = "//build_defs/languages/installed:wasix/server/Cargo.lock", + index = "//build_defs/languages/installed:wasix/server/registry-index.json", +) +installed_cargo_inputs( + name = "installed_query_cargo_inputs", + bun = "@bun_runtime//:bun", + lock = "//build_defs/languages/installed:wasix/query/Cargo.lock", + index = "//build_defs/languages/installed:wasix/query/registry-index.json", +) + +react_native_apple_release = use_repo_rule("//build_defs/apple:react-native-repository.bzl", "react_native_apple_release_repository") +react_native_apple_release(name = "react_native_apple_release", native_metadata = "@expo_android_sources//:apple-metadata.json") + +apple_captured_archives = use_repo_rule("//build_defs/apple:captured-repository.bzl", "apple_captured_archives_repository") +apple_captured_archives( + name = "react_native_native_base", + catalog = "@oliphaunt_metadata//:completed-supplier-artifacts.json", + current_native = "@oliphaunt_metadata//:native-apple-base-input.json", + selected_products = "@oliphaunt_metadata//:prepared-selected-products.json", + swift_construction = "@react_native_swift_package//:construction.json", +) + +apple_captured_swift = use_repo_rule("//build_defs/apple:captured-swift-repository.bzl", "apple_captured_swift_repository") +apple_captured_swift( + name = "react_native_swift_package", + catalog = "@oliphaunt_metadata//:completed-supplier-artifacts.json", + manifest = "//src/native/sdks/react-native:package.json", + selected_products = "@oliphaunt_metadata//:prepared-selected-products.json", + current_source = "@oliphaunt_metadata//:native-swift-source-input.json", + runtime = "@react_native_native_base//:runtime", +) + +# Append repository rules to preserve canonical names recorded by module extensions. +# Lazy; ordinary SDK construction does not fetch emulator/system-image archives. +android_emulator = use_repo_rule("//build_defs/languages/jvm:android-sdk-repository.bzl", "android_emulator_repository") +android_emulator(name = "oliphaunt_android_emulator") + +bazel_disk_cache_gc = use_repo_rule("//build_defs/foundation:bazel-disk-cache-gc.bzl", "bazel_disk_cache_gc_repository") +bazel_disk_cache_gc(name = "bazel_disk_cache_gc") + +deno_linux_x64 = use_repo_rule("//build_defs/foundation:repositories.bzl", "deno_linux_x64_repository") +deno_linux_x64(name = "deno_linux_x64") + +http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +http_archive( + name = "electron_linux_x64", + urls = ["https://github.com/electron/electron/releases/download/v39.2.5/electron-v39.2.5-linux-x64.zip"], + sha256 = "610c60e6ba824d7d1873eac1791ed2cd1f2a3369b27819d9d30da5165515092f", + build_file_content = """ +package(default_visibility = ["//visibility:public"]) +exports_files(["electron"]) +filegroup( + name = "runtime_files", + srcs = glob(["**"], exclude = ["BUILD.bazel", "WORKSPACE", "WORKSPACE.bazel"]), +) +""", +) + +extension_test_source = use_repo_rule("//build_defs/extensions:repositories.bzl", "extension_test_source") +extension_test_source( + name = "pg_textsearch_upgrade_from", + source_manifest = "//src/extensions/external/pg_textsearch/tests:upgrade/source.toml", +) diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock new file mode 100644 index 000000000..07e3134e5 --- /dev/null +++ b/MODULE.bazel.lock @@ -0,0 +1,55517 @@ +{ + "lockFileVersion": 28, + "registryFileHashes": { + "https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497", + "https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2", + "https://bcr.bazel.build/modules/abseil-cpp/20211102.0/MODULE.bazel": "70390338f7a5106231d20620712f7cccb659cd0e9d073d1991c038eb9fc57589", + "https://bcr.bazel.build/modules/abseil-cpp/20230125.1/MODULE.bazel": "89047429cb0207707b2dface14ba7f8df85273d484c2572755be4bab7ce9c3a0", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.0.bcr.1/MODULE.bazel": "1c8cec495288dccd14fdae6e3f95f772c1c91857047a098fad772034264cc8cb", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.0/MODULE.bazel": "d253ae36a8bd9ee3c5955384096ccb6baf16a1b1e93e858370da0a3b94f77c16", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.1/MODULE.bazel": "fa92e2eb41a04df73cdabeec37107316f7e5272650f81d6cc096418fe647b915", + "https://bcr.bazel.build/modules/abseil-cpp/20240116.1/MODULE.bazel": "37bcdb4440fbb61df6a1c296ae01b327f19e9bb521f9b8e26ec854b6f97309ed", + "https://bcr.bazel.build/modules/abseil-cpp/20240116.2/MODULE.bazel": "73939767a4686cd9a520d16af5ab440071ed75cec1a876bf2fcfaf1f71987a16", + "https://bcr.bazel.build/modules/abseil-cpp/20250127.0/MODULE.bazel": "d1086e248cda6576862b4b3fe9ad76a214e08c189af5b42557a6e1888812c5d5", + "https://bcr.bazel.build/modules/abseil-cpp/20250127.1/MODULE.bazel": "c4a89e7ceb9bf1e25cf84a9f830ff6b817b72874088bf5141b314726e46a57c1", + "https://bcr.bazel.build/modules/abseil-cpp/20250512.1/MODULE.bazel": "d209fdb6f36ffaf61c509fcc81b19e81b411a999a934a032e10cd009a0226215", + "https://bcr.bazel.build/modules/abseil-cpp/20250814.1/MODULE.bazel": "51f2312901470cdab0dbdf3b88c40cd21c62a7ed58a3de45b365ddc5b11bcab2", + "https://bcr.bazel.build/modules/abseil-cpp/20250814.1/source.json": "cea3901d7e299da7320700abbaafe57a65d039f10d0d7ea601c4a66938ea4b0c", + "https://bcr.bazel.build/modules/abseil-py/2.1.0/MODULE.bazel": "5ebe5bf853769c65707e5c28f216798f7a4b1042015e6a36e6d03094d94bec8a", + "https://bcr.bazel.build/modules/abseil-py/2.1.0/source.json": "0e8fc4f088ce07099c1cd6594c20c7ddbb48b4b3c0849b7d94ba94be88ff042b", + "https://bcr.bazel.build/modules/apple_support/2.9.1/MODULE.bazel": "fb209b83ed172af587419acb3340389cfe3260669e5f1c05e1ac3974aca614e0", + "https://bcr.bazel.build/modules/apple_support/2.9.1/source.json": "247d9f86d94c546533fb01e6e18b018486f9a6dff5faccae8838ef12e659b2a7", + "https://bcr.bazel.build/modules/aspect_bazel_lib/2.14.0/MODULE.bazel": "2b31ffcc9bdc8295b2167e07a757dbbc9ac8906e7028e5170a3708cecaac119f", + "https://bcr.bazel.build/modules/aspect_bazel_lib/2.19.2/MODULE.bazel": "30dfabbfae0139b1f0036e01c201dd4c0167da3017f0b7ef3820d78e07622989", + "https://bcr.bazel.build/modules/aspect_bazel_lib/2.19.3/MODULE.bazel": "253d739ba126f62a5767d832765b12b59e9f8d2bc88cc1572f4a73e46eb298ca", + "https://bcr.bazel.build/modules/aspect_bazel_lib/2.22.5/MODULE.bazel": "004ba890363d05372a97248c37205ae64b6fa31047629cd2c0895a9d0c7779e8", + "https://bcr.bazel.build/modules/aspect_bazel_lib/2.22.5/source.json": "ac2c3213df8f985785f1d0aeb7f0f73d5324e6e67d593d9b9470fb74a25d4a9b", + "https://bcr.bazel.build/modules/aspect_bazel_lib/2.7.7/MODULE.bazel": "491f8681205e31bb57892d67442ce448cda4f472a8e6b3dc062865e29a64f89c", + "https://bcr.bazel.build/modules/aspect_bazel_lib/2.8.1/MODULE.bazel": "812d2dd42f65dca362152101fbec418029cc8fd34cbad1a2fde905383d705838", + "https://bcr.bazel.build/modules/aspect_rules_js/2.0.0/MODULE.bazel": "b45b507574aa60a92796e3e13c195cd5744b3b8aff516a9c0cb5ae6a048161c5", + "https://bcr.bazel.build/modules/aspect_rules_js/3.5.1/MODULE.bazel": "f01b4f1bf26713e875ec0fbe9d9c2146d2b173d6194850a7cb63b579c557aab1", + "https://bcr.bazel.build/modules/aspect_rules_js/3.5.1/source.json": "f2dc028f9110d8aaf262a23267484f1c9d310f8ecf5f832e2a740d192a97756f", + "https://bcr.bazel.build/modules/aspect_rules_ts/3.10.1/MODULE.bazel": "035205a7834b0ed9724ed3c4790e12d1c779ef2520d72496ab234e6307715e6c", + "https://bcr.bazel.build/modules/aspect_rules_ts/3.10.1/source.json": "d42b6560206adb5524caad2abc40ae0b5b34478dd38184a9f6ea4a5fed848cd6", + "https://bcr.bazel.build/modules/aspect_tools_telemetry/0.5.1/MODULE.bazel": "9d94e5c22c0019995c0a3216a6abb1717dc3f35acccf4e6267a55d6df38367aa", + "https://bcr.bazel.build/modules/aspect_tools_telemetry/0.5.2/MODULE.bazel": "c715a5fb6b13a0086c061618f00d033a4ab6d76cbd1083e38d7ca953b5e547f4", + "https://bcr.bazel.build/modules/aspect_tools_telemetry/0.5.2/source.json": "4dd300d44767ad4860098b006dda614e67ab0409ae6ec6e133faad303fe9ede8", + "https://bcr.bazel.build/modules/bazel_features/1.1.0/MODULE.bazel": "cfd42ff3b815a5f39554d97182657f8c4b9719568eb7fded2b9135f084bf760b", + "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd", + "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8", + "https://bcr.bazel.build/modules/bazel_features/1.17.0/MODULE.bazel": "039de32d21b816b47bd42c778e0454217e9c9caac4a3cf8e15c7231ee3ddee4d", + "https://bcr.bazel.build/modules/bazel_features/1.18.0/MODULE.bazel": "1be0ae2557ab3a72a57aeb31b29be347bcdc5d2b1eb1e70f39e3851a7e97041a", + "https://bcr.bazel.build/modules/bazel_features/1.19.0/MODULE.bazel": "59adcdf28230d220f0067b1f435b8537dd033bfff8db21335ef9217919c7fb58", + "https://bcr.bazel.build/modules/bazel_features/1.21.0/MODULE.bazel": "675642261665d8eea09989aa3b8afb5c37627f1be178382c320d1b46afba5e3b", + "https://bcr.bazel.build/modules/bazel_features/1.23.0/MODULE.bazel": "fd1ac84bc4e97a5a0816b7fd7d4d4f6d837b0047cf4cbd81652d616af3a6591a", + "https://bcr.bazel.build/modules/bazel_features/1.25.0/MODULE.bazel": "e2e60a10a6da64bbf533f15ca652bf61a033e41c2ed734d79a9a08ba87f68c1a", + "https://bcr.bazel.build/modules/bazel_features/1.27.0/MODULE.bazel": "621eeee06c4458a9121d1f104efb80f39d34deff4984e778359c60eaf1a8cb65", + "https://bcr.bazel.build/modules/bazel_features/1.28.0/MODULE.bazel": "4b4200e6cbf8fa335b2c3f43e1d6ef3e240319c33d43d60cc0fbd4b87ece299d", + "https://bcr.bazel.build/modules/bazel_features/1.30.0/MODULE.bazel": "a14b62d05969a293b80257e72e597c2da7f717e1e69fa8b339703ed6731bec87", + "https://bcr.bazel.build/modules/bazel_features/1.33.0/MODULE.bazel": "8b8dc9d2a4c88609409c3191165bccec0e4cb044cd7a72ccbe826583303459f6", + "https://bcr.bazel.build/modules/bazel_features/1.34.0/MODULE.bazel": "e8475ad7c8965542e0c7aac8af68eb48c4af904be3d614b6aa6274c092c2ea1e", + "https://bcr.bazel.build/modules/bazel_features/1.39.0/MODULE.bazel": "28739425c1fc283c91931619749c832b555e60bcd1010b40d8441ce0a5cf726d", + "https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7", + "https://bcr.bazel.build/modules/bazel_features/1.41.0/MODULE.bazel": "6e0f87fafed801273c371d41e22a15a6f8abf83fdd7f87d5e44ad317b94433d0", + "https://bcr.bazel.build/modules/bazel_features/1.47.1/MODULE.bazel": "e6be691539341681678a68c2076771f6a73fcdc9823c5b6bf280d2e916d1ad80", + "https://bcr.bazel.build/modules/bazel_features/1.50.0/MODULE.bazel": "2083ef9c7a469f520890483ccf8e0189d6e71e2117e7752e15e6554433d5ae3e", + "https://bcr.bazel.build/modules/bazel_features/1.51.0/MODULE.bazel": "8e1310d09db6ee2e4f19f9994e360aca941ddc32083edc8d9bdc19c83c94cee4", + "https://bcr.bazel.build/modules/bazel_features/1.51.0/source.json": "d5af1f1748d2b4ace5f04087030c0a1cfd93f5be6bdf0b5c1beb24ed0fd24955", + "https://bcr.bazel.build/modules/bazel_features/1.9.0/MODULE.bazel": "885151d58d90d8d9c811eb75e3288c11f850e1d6b481a8c9f766adee4712358b", + "https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a", + "https://bcr.bazel.build/modules/bazel_lib/3.0.0-rc.0/MODULE.bazel": "d6e00979a98ac14ada5e31c8794708b41434d461e7e7ca39b59b765e6d233b18", + "https://bcr.bazel.build/modules/bazel_lib/3.0.0/MODULE.bazel": "22b70b80ac89ad3f3772526cd9feee2fa412c2b01933fea7ed13238a448d370d", + "https://bcr.bazel.build/modules/bazel_lib/3.1.0/MODULE.bazel": "6809765c14e3c766a9b9286c7b0ec56ed87a73326e48fe01749f0c0fdcfe3287", + "https://bcr.bazel.build/modules/bazel_lib/3.3.1/MODULE.bazel": "732a0d516cf6400d9b3136e4356258aef1bf91de8d5240f87f0112f098920c1d", + "https://bcr.bazel.build/modules/bazel_lib/3.7.0/MODULE.bazel": "d7c10ed67f0f7f1fda179db8f86c22642581bd614882e1a50545fbe069525173", + "https://bcr.bazel.build/modules/bazel_lib/3.7.0/source.json": "cdacdbe1a504593475889158a96acf3ec3fb6be5cac2fb7b201ba5c6beacd9d4", + "https://bcr.bazel.build/modules/bazel_linux_packages/0.4.1/MODULE.bazel": "9bcd612b78aa98db07f01ca7edc3129148aced24d3726884bba1f321031e724d", + "https://bcr.bazel.build/modules/bazel_linux_packages/0.4.1/source.json": "f3bbbf0f046fbc692b5e00f317088c6163b1874213027f1047bf505a1b9c647b", + "https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8", + "https://bcr.bazel.build/modules/bazel_skylib/1.1.1/MODULE.bazel": "1add3e7d93ff2e6998f9e118022c84d163917d912f5afafb3058e3d2f1545b5e", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.0/MODULE.bazel": "44fe84260e454ed94ad326352a698422dbe372b21a1ac9f3eab76eb531223686", + "https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": "f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a", + "https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": "20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.1/MODULE.bazel": "a0dcb779424be33100dcae821e9e27e4f2901d9dfd5333efe5ac6a8d7ab75e1d", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.2/MODULE.bazel": "3bd40978e7a1fac911d5989e6b09d8f64921865a45822d8b09e815eaa726a651", + "https://bcr.bazel.build/modules/bazel_skylib/1.5.0/MODULE.bazel": "32880f5e2945ce6a03d1fbd588e9198c0a959bb42297b2cfaf1685b7bc32e138", + "https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.0/MODULE.bazel": "0db596f4563de7938de764cc8deeabec291f55e8ec15299718b93c4423e9796d", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b", + "https://bcr.bazel.build/modules/bazel_skylib/1.8.0/MODULE.bazel": "2fb3fb53675f6adfc1ca5bfbd5cfb655ae350fba4706d924a8ec7e3ba945671c", + "https://bcr.bazel.build/modules/bazel_skylib/1.8.1/MODULE.bazel": "88ade7293becda963e0e3ea33e7d54d3425127e0a326e0d17da085a5f1f03ff6", + "https://bcr.bazel.build/modules/bazel_skylib/1.8.2/MODULE.bazel": "69ad6927098316848b34a9142bcc975e018ba27f08c4ff403f50c1b6e646ca67", + "https://bcr.bazel.build/modules/bazel_skylib/1.9.0/MODULE.bazel": "72997b29dfd95c3fa0d0c48322d05590418edef451f8db8db5509c57875fb4b7", + "https://bcr.bazel.build/modules/bazel_skylib/1.9.0/source.json": "7ad77c1e8c1b84222d9b3f3cae016a76639435744c19330b0b37c0a3c9da7dc0", + "https://bcr.bazel.build/modules/bazel_worker_api/0.0.1/MODULE.bazel": "02a13b77321773b2042e70ee5e4c5e099c8ddee4cf2da9cd420442c36938d4bd", + "https://bcr.bazel.build/modules/bazel_worker_api/0.0.4/MODULE.bazel": "460aa12d01231a80cce03c548287b433b321d205b0028ae596728c35e5ee442e", + "https://bcr.bazel.build/modules/bazel_worker_api/0.0.8/MODULE.bazel": "396c1ef53835aafe3d42ce6619080531ee770648303731f16cfaa33fa056bf0c", + "https://bcr.bazel.build/modules/bazel_worker_api/0.0.8/source.json": "abaf8ac9d2ab2f47bda9af4c0c080ff7907378888e1f4bc62a0539dd13ba61e8", + "https://bcr.bazel.build/modules/bazel_worker_java/0.0.4/MODULE.bazel": "82494a01018bb7ef06d4a17ec4cd7a758721f10eb8b6c820a818e70d669500db", + "https://bcr.bazel.build/modules/bazel_worker_java/0.0.8/MODULE.bazel": "e76479eae70bd4e8f5f4c2dfc5d03ab971cfb18750246c7b3f3454c5c2ee6629", + "https://bcr.bazel.build/modules/bazel_worker_java/0.0.8/source.json": "9395c4679444bc47bf7e51a710366a4480aa371c6f6bed01868e2fabcf11acec", + "https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84", + "https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8", + "https://bcr.bazel.build/modules/gawk/5.3.2.bcr.1/MODULE.bazel": "cdf8cbe5ee750db04b78878c9633cc76e80dcf4416cbe982ac3a9222f80713c8", + "https://bcr.bazel.build/modules/gawk/5.3.2.bcr.3/MODULE.bazel": "f1b7bb2dd53e8f2ef984b39485ec8a44e9076dda5c4b8efd2fb4c6a6e856a31d", + "https://bcr.bazel.build/modules/gawk/5.3.2.bcr.3/source.json": "ebe931bfe362e4b41e59ee00a528db6074157ff2ced92eb9e970acab2e1089c9", + "https://bcr.bazel.build/modules/gazelle/0.32.0/MODULE.bazel": "b499f58a5d0d3537f3cf5b76d8ada18242f64ec474d8391247438bf04f58c7b8", + "https://bcr.bazel.build/modules/gazelle/0.33.0/MODULE.bazel": "a13a0f279b462b784fb8dd52a4074526c4a2afe70e114c7d09066097a46b3350", + "https://bcr.bazel.build/modules/gazelle/0.34.0/MODULE.bazel": "abdd8ce4d70978933209db92e436deb3a8b737859e9354fb5fd11fb5c2004c8a", + "https://bcr.bazel.build/modules/gazelle/0.36.0/MODULE.bazel": "e375d5d6e9a6ca59b0cb38b0540bc9a05b6aa926d322f2de268ad267a2ee74c0", + "https://bcr.bazel.build/modules/gazelle/0.40.0/MODULE.bazel": "42ba5378ebe845fca43989a53186ab436d956db498acde790685fe0e8f9c6146", + "https://bcr.bazel.build/modules/gazelle/0.40.0/source.json": "1e5ef6e4d8b9b6836d93273c781e78ff829ea2e077afef7a57298040fa4f010a", + "https://bcr.bazel.build/modules/gcc_toolchain/0.12.0/MODULE.bazel": "0f575f5136b738c6a47ed5198b365bf274fedf9283ea3377189d4ab62a118959", + "https://bcr.bazel.build/modules/gcc_toolchain/0.12.0/source.json": "40f4663ce767e406c57c6de91dd0ffb8a87c12337a8fdc684c664f88e03821a2", + "https://bcr.bazel.build/modules/google_benchmark/1.8.2/MODULE.bazel": "a70cf1bba851000ba93b58ae2f6d76490a9feb74192e57ab8e8ff13c34ec50cb", + "https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4", + "https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/MODULE.bazel": "22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6", + "https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f", + "https://bcr.bazel.build/modules/googletest/1.15.2/MODULE.bazel": "6de1edc1d26cafb0ea1a6ab3f4d4192d91a312fd2d360b63adaa213cd00b2108", + "https://bcr.bazel.build/modules/googletest/1.17.0/MODULE.bazel": "dbec758171594a705933a29fcf69293d2468c49ec1f2ebca65c36f504d72df46", + "https://bcr.bazel.build/modules/googletest/1.17.0/source.json": "38e4454b25fc30f15439c0378e57909ab1fd0a443158aa35aec685da727cd713", + "https://bcr.bazel.build/modules/hermetic_cc_toolchain/4.3.0/MODULE.bazel": "4157d273074a1876fa674deca1e551bad66f06b87da1603dd856244e97b7ced8", + "https://bcr.bazel.build/modules/hermetic_cc_toolchain/4.3.0/source.json": "ce6a4b5621b88b8707e362419d9972cc9669d5c24cec2a7610483a94be8fa4ae", + "https://bcr.bazel.build/modules/hermetic_launcher/0.0.15/MODULE.bazel": "1a04856a10bd6a3d23bad08673bceb59b061c4bf9b76d335e30386832acc1b33", + "https://bcr.bazel.build/modules/hermetic_launcher/0.0.15/source.json": "aceb903a3bda5131b0a3132ccf77f36f32b96dcb70864049ec8cfdf9c0b0f068", + "https://bcr.bazel.build/modules/jq.bzl/0.1.0/MODULE.bazel": "2ce69b1af49952cd4121a9c3055faa679e748ce774c7f1fda9657f936cae902f", + "https://bcr.bazel.build/modules/jq.bzl/0.4.0/MODULE.bazel": "a7b39b37589f2b0dad53fd6c1ccaabbdb290330caa920d7ef3e6aad068cd4ab2", + "https://bcr.bazel.build/modules/jq.bzl/0.4.0/source.json": "52ec7530c4618e03f634b30ff719814a68d7d39c235938b7aa2abbfe1eb1c52c", + "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075", + "https://bcr.bazel.build/modules/jsoncpp/1.9.6/MODULE.bazel": "2f8d20d3b7d54143213c4dfc3d98225c42de7d666011528dc8fe91591e2e17b0", + "https://bcr.bazel.build/modules/jsoncpp/1.9.6/source.json": "a04756d367a2126c3541682864ecec52f92cdee80a35735a3cb249ce015ca000", + "https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902", + "https://bcr.bazel.build/modules/nlohmann_json/3.12.0.bcr.1/MODULE.bazel": "a1c8bb07b5b91d971727c635f449d05623ac9608f6fe4f5f04254ea12f08e349", + "https://bcr.bazel.build/modules/nlohmann_json/3.12.0.bcr.1/source.json": "93f82a5ae985eb935c539bfee95e04767187818189241ac956f3ccadbdb8fb02", + "https://bcr.bazel.build/modules/package_metadata/0.0.2/MODULE.bazel": "fb8d25550742674d63d7b250063d4580ca530499f045d70748b1b142081ebb92", + "https://bcr.bazel.build/modules/package_metadata/0.0.3/MODULE.bazel": "77890552ecea9e284b5424c9de827a58099348763a4359e975c359a83d4faa83", + "https://bcr.bazel.build/modules/package_metadata/0.0.7/MODULE.bazel": "7adb03933fc8401f495800cf4eafcff0edc6da0ff55c7db223ef69d19f689486", + "https://bcr.bazel.build/modules/package_metadata/0.0.7/source.json": "50639625e937b56115012674c797cca7a05a96b4878c87d803c13dc2b31de8a0", + "https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5", + "https://bcr.bazel.build/modules/platforms/0.0.11/MODULE.bazel": "0daefc49732e227caa8bfa834d65dc52e8cc18a2faf80df25e8caea151a9413f", + "https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee", + "https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37", + "https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615", + "https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814", + "https://bcr.bazel.build/modules/platforms/0.0.8/MODULE.bazel": "9f142c03e348f6d263719f5074b21ef3adf0b139ee4c5133e2aa35664da9eb2d", + "https://bcr.bazel.build/modules/platforms/0.0.9/MODULE.bazel": "4a87a60c927b56ddd67db50c89acaa62f4ce2a1d2149ccb63ffd871d5ce29ebc", + "https://bcr.bazel.build/modules/platforms/1.0.0/MODULE.bazel": "f05feb42b48f1b3c225e4ccf351f367be0371411a803198ec34a389fb22aa580", + "https://bcr.bazel.build/modules/platforms/1.1.0/MODULE.bazel": "1c0c09f5bdcf4b3f924720d2478a3711cb39f4977019ca5988685e5b7e18b3d2", + "https://bcr.bazel.build/modules/platforms/1.1.0/source.json": "fcf351c47596c939140ab0d333dfdd08ed1ea6ce33c2fe70c12493a301cf1344", + "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7", + "https://bcr.bazel.build/modules/protobuf/23.1/MODULE.bazel": "88b393b3eb4101d18129e5db51847cd40a5517a53e81216144a8c32dfeeca52a", + "https://bcr.bazel.build/modules/protobuf/24.4/MODULE.bazel": "7bc7ce5f2abf36b3b7b7c8218d3acdebb9426aeb35c2257c96445756f970eb12", + "https://bcr.bazel.build/modules/protobuf/27.0/MODULE.bazel": "7873b60be88844a0a1d8f80b9d5d20cfbd8495a689b8763e76c6372998d3f64c", + "https://bcr.bazel.build/modules/protobuf/27.1/MODULE.bazel": "703a7b614728bb06647f965264967a8ef1c39e09e8f167b3ca0bb1fd80449c0d", + "https://bcr.bazel.build/modules/protobuf/27.2/MODULE.bazel": "32450b50673882e4c8c3d10a83f3bc82161b213ed2f80d17e38bece8f165c295", + "https://bcr.bazel.build/modules/protobuf/29.0-rc2/MODULE.bazel": "6241d35983510143049943fc0d57937937122baf1b287862f9dc8590fc4c37df", + "https://bcr.bazel.build/modules/protobuf/29.0-rc3/MODULE.bazel": "33c2dfa286578573afc55a7acaea3cada4122b9631007c594bf0729f41c8de92", + "https://bcr.bazel.build/modules/protobuf/29.0/MODULE.bazel": "319dc8bf4c679ff87e71b1ccfb5a6e90a6dbc4693501d471f48662ac46d04e4e", + "https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0", + "https://bcr.bazel.build/modules/protobuf/3.19.2/MODULE.bazel": "532ffe5f2186b69fdde039efe6df13ba726ff338c6bc82275ad433013fa10573", + "https://bcr.bazel.build/modules/protobuf/3.19.6/MODULE.bazel": "9233edc5e1f2ee276a60de3eaa47ac4132302ef9643238f23128fea53ea12858", + "https://bcr.bazel.build/modules/protobuf/31.1/MODULE.bazel": "379a389bb330b7b8c1cdf331cc90bf3e13de5614799b3b52cdb7c6f389f6b38e", + "https://bcr.bazel.build/modules/protobuf/34.0.bcr.1/MODULE.bazel": "74e541b0ba877813da786a11707d4e394433c157841d5111a36be0d44b907931", + "https://bcr.bazel.build/modules/protobuf/34.0.bcr.1/source.json": "fc174b3d6215aa14197d1bd779f98bb72d9fd666ee5ec0d6bba6ae986baa4535", + "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e", + "https://bcr.bazel.build/modules/pybind11_bazel/2.12.0/MODULE.bazel": "e6f4c20442eaa7c90d7190d8dc539d0ab422f95c65a57cc59562170c58ae3d34", + "https://bcr.bazel.build/modules/pybind11_bazel/2.12.0/source.json": "6900fdc8a9e95866b8c0d4ad4aba4d4236317b5c1cd04c502df3f0d33afed680", + "https://bcr.bazel.build/modules/re2/2023-09-01/MODULE.bazel": "cb3d511531b16cfc78a225a9e2136007a48cf8a677e4264baeab57fe78a80206", + "https://bcr.bazel.build/modules/re2/2024-07-02.bcr.1/MODULE.bazel": "b4963dda9b31080be1905ef085ecd7dd6cd47c05c79b9cdf83ade83ab2ab271a", + "https://bcr.bazel.build/modules/re2/2024-07-02.bcr.1/source.json": "2ff292be6ef3340325ce8a045ecc326e92cbfab47c7cbab4bd85d28971b97ac4", + "https://bcr.bazel.build/modules/re2/2024-07-02/MODULE.bazel": "0eadc4395959969297cbcf31a249ff457f2f1d456228c67719480205aa306daa", + "https://bcr.bazel.build/modules/rules_android/0.6.6/MODULE.bazel": "b0fb569752aab65ab1a9db0a8f6cfaf5aa1754965e17e95dcf0e4d88e192a68d", + "https://bcr.bazel.build/modules/rules_android/0.6.6/source.json": "a9d8dc2d5a102dc03269a94acc886a4cab82cdcb9ccbc77b0f665d6d17a6ae09", + "https://bcr.bazel.build/modules/rules_android_ndk/0.1.5/MODULE.bazel": "ab43d418846060de6396e3f1b515a692e945bcd92a9d4541fddcddc8589004ce", + "https://bcr.bazel.build/modules/rules_android_ndk/0.1.5/source.json": "2950fc77b8e1f1e3874c4e073776f2258ce46926b43c236620c93517fd2e5865", + "https://bcr.bazel.build/modules/rules_apple/5.2.0/MODULE.bazel": "9b46da6889ba44e1b61dda2b4456f69606064cf38a95c1aacab5ae408f2aa735", + "https://bcr.bazel.build/modules/rules_apple/5.2.0/source.json": "78c5c54eeabdae3e1dfd4f67f079c0672db5df715016fdce2b09bf9b4c88bedf", + "https://bcr.bazel.build/modules/rules_bison/0.4.bcr.1/MODULE.bazel": "533fafa678511503c661f36fd36f21d860da785c79116a013ec763668e320bbb", + "https://bcr.bazel.build/modules/rules_bison/0.4.bcr.1/source.json": "a59670370c902b0a1bc901303e3783b6247c3df73b1554a32cc00927c5c38504", + "https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647", + "https://bcr.bazel.build/modules/rules_cc/0.0.10/MODULE.bazel": "ec1705118f7eaedd6e118508d3d26deba2a4e76476ada7e0e3965211be012002", + "https://bcr.bazel.build/modules/rules_cc/0.0.13/MODULE.bazel": "0e8529ed7b323dad0775ff924d2ae5af7640b23553dfcd4d34344c7e7a867191", + "https://bcr.bazel.build/modules/rules_cc/0.0.14/MODULE.bazel": "5e343a3aac88b8d7af3b1b6d2093b55c347b8eefc2e7d1442f7a02dc8fea48ac", + "https://bcr.bazel.build/modules/rules_cc/0.0.15/MODULE.bazel": "6704c35f7b4a72502ee81f61bf88706b54f06b3cbe5558ac17e2e14666cd5dcc", + "https://bcr.bazel.build/modules/rules_cc/0.0.16/MODULE.bazel": "7661303b8fc1b4d7f532e54e9d6565771fea666fbdf839e0a86affcd02defe87", + "https://bcr.bazel.build/modules/rules_cc/0.0.17/MODULE.bazel": "2ae1d8f4238ec67d7185d8861cb0a2cdf4bc608697c331b95bf990e69b62e64a", + "https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c", + "https://bcr.bazel.build/modules/rules_cc/0.0.6/MODULE.bazel": "abf360251023dfe3efcef65ab9d56beefa8394d4176dd29529750e1c57eaa33f", + "https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e", + "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5", + "https://bcr.bazel.build/modules/rules_cc/0.1.1/MODULE.bazel": "2f0222a6f229f0bf44cd711dc13c858dad98c62d52bd51d8fc3a764a83125513", + "https://bcr.bazel.build/modules/rules_cc/0.1.5/MODULE.bazel": "88dfc9361e8b5ae1008ac38f7cdfd45ad738e4fa676a3ad67d19204f045a1fd8", + "https://bcr.bazel.build/modules/rules_cc/0.2.0/MODULE.bazel": "b5c17f90458caae90d2ccd114c81970062946f49f355610ed89bebf954f5783c", + "https://bcr.bazel.build/modules/rules_cc/0.2.14/MODULE.bazel": "353c99ed148887ee89c54a17d4100ae7e7e436593d104b668476019023b58df8", + "https://bcr.bazel.build/modules/rules_cc/0.2.16/MODULE.bazel": "9242fa89f950c6ef7702801ab53922e99c69b02310c39fb6e62b2bd30df2a1d4", + "https://bcr.bazel.build/modules/rules_cc/0.2.17/MODULE.bazel": "1849602c86cb60da8613d2de887f9566a6d354a6df6d7009f9d04a14402f9a84", + "https://bcr.bazel.build/modules/rules_cc/0.2.25/MODULE.bazel": "4a3d4f3606d3b3190be495dbc497acca552807d1d5540661ef0d1658472882e3", + "https://bcr.bazel.build/modules/rules_cc/0.2.26/MODULE.bazel": "a9f7b7f4a52747910965bddb1f58fc1fef50604ed1980ebdd16ea6f446d92249", + "https://bcr.bazel.build/modules/rules_cc/0.2.26/source.json": "bf9ff315da6055c1e374d627012cc51947a05b3560674af7d69fbedbb4fde6ef", + "https://bcr.bazel.build/modules/rules_cc/0.2.4/MODULE.bazel": "1ff1223dfd24f3ecf8f028446d4a27608aa43c3f41e346d22838a4223980b8cc", + "https://bcr.bazel.build/modules/rules_cc_autoconf/0.24.0/MODULE.bazel": "332e2a2972ef5d5a537b2dbc23bea7a0d5d97fc5fa82cebe032b1b8d509b06a1", + "https://bcr.bazel.build/modules/rules_cc_autoconf/0.24.0/source.json": "7b729d9f90f03cfd1214a69ddb1f7efd0009d68271ccdbfa7dec9f2dcabaaa55", + "https://bcr.bazel.build/modules/rules_flex/0.4.1/MODULE.bazel": "f3d0e224cdce177fdc17ae8cbae9c7bd7010149b9a9482897d289090b9e78034", + "https://bcr.bazel.build/modules/rules_flex/0.4.1/source.json": "09c7de298925d653c98fa242ca490a991703bcfe1da8c4c75432d51c4803e3be", + "https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6", + "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8", + "https://bcr.bazel.build/modules/rules_go/0.41.0/MODULE.bazel": "55861d8e8bb0e62cbd2896f60ff303f62ffcb0eddb74ecb0e5c0cbe36fc292c8", + "https://bcr.bazel.build/modules/rules_go/0.42.0/MODULE.bazel": "8cfa875b9aa8c6fce2b2e5925e73c1388173ea3c32a0db4d2b4804b453c14270", + "https://bcr.bazel.build/modules/rules_go/0.46.0/MODULE.bazel": "3477df8bdcc49e698b9d25f734c4f3a9f5931ff34ee48a2c662be168f5f2d3fd", + "https://bcr.bazel.build/modules/rules_go/0.50.1/MODULE.bazel": "b91a308dc5782bb0a8021ad4330c81fea5bda77f96b9e4c117b9b9c8f6665ee0", + "https://bcr.bazel.build/modules/rules_go/0.51.0-rc2/MODULE.bazel": "edfc3a9cea7bedb0eaaff37b0d7817c1a4bf72b3c615580b0ffcee6c52690fd4", + "https://bcr.bazel.build/modules/rules_go/0.51.0-rc2/source.json": "6b5cd0b3da2bd0e6949580851db990a04af0a285f072b9a0f059424457cd8cc9", + "https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74", + "https://bcr.bazel.build/modules/rules_java/5.3.5/MODULE.bazel": "a4ec4f2db570171e3e5eb753276ee4b389bae16b96207e9d3230895c99644b86", + "https://bcr.bazel.build/modules/rules_java/6.3.0/MODULE.bazel": "a97c7678c19f236a956ad260d59c86e10a463badb7eb2eda787490f4c969b963", + "https://bcr.bazel.build/modules/rules_java/6.5.2/MODULE.bazel": "1d440d262d0e08453fa0c4d8f699ba81609ed0e9a9a0f02cd10b3e7942e61e31", + "https://bcr.bazel.build/modules/rules_java/7.1.0/MODULE.bazel": "30d9135a2b6561c761bd67bd4990da591e6bdc128790ce3e7afd6a3558b2fb64", + "https://bcr.bazel.build/modules/rules_java/7.12.2/MODULE.bazel": "579c505165ee757a4280ef83cda0150eea193eed3bef50b1004ba88b99da6de6", + "https://bcr.bazel.build/modules/rules_java/7.2.0/MODULE.bazel": "06c0334c9be61e6cef2c8c84a7800cef502063269a5af25ceb100b192453d4ab", + "https://bcr.bazel.build/modules/rules_java/7.6.1/MODULE.bazel": "2f14b7e8a1aa2f67ae92bc69d1ec0fa8d9f827c4e17ff5e5f02e91caa3b2d0fe", + "https://bcr.bazel.build/modules/rules_java/8.11.0/MODULE.bazel": "c3d280bc5ff1038dcb3bacb95d3f6b83da8dd27bba57820ec89ea4085da767ad", + "https://bcr.bazel.build/modules/rules_java/8.13.0/MODULE.bazel": "0444ebf737d144cf2bb2ccb368e7f1cce735264285f2a3711785827c1686625e", + "https://bcr.bazel.build/modules/rules_java/8.14.0/MODULE.bazel": "717717ed40cc69994596a45aec6ea78135ea434b8402fb91b009b9151dd65615", + "https://bcr.bazel.build/modules/rules_java/8.14.0/source.json": "8a88c4ca9e8759da53cddc88123880565c520503321e2566b4e33d0287a3d4bc", + "https://bcr.bazel.build/modules/rules_java/8.3.2/MODULE.bazel": "7336d5511ad5af0b8615fdc7477535a2e4e723a357b6713af439fe8cf0195017", + "https://bcr.bazel.build/modules/rules_java/8.5.1/MODULE.bazel": "d8a9e38cc5228881f7055a6079f6f7821a073df3744d441978e7a43e20226939", + "https://bcr.bazel.build/modules/rules_java/8.6.0/MODULE.bazel": "9c064c434606d75a086f15ade5edb514308cccd1544c2b2a89bbac4310e41c71", + "https://bcr.bazel.build/modules/rules_java/8.6.1/MODULE.bazel": "f4808e2ab5b0197f094cabce9f4b006a27766beb6a9975931da07099560ca9c2", + "https://bcr.bazel.build/modules/rules_java/8.9.0/MODULE.bazel": "e17c876cb53dcd817b7b7f0d2985b710610169729e8c371b2221cacdcd3dce4a", + "https://bcr.bazel.build/modules/rules_jvm_external/6.10/MODULE.bazel": "33e636ca6bc9ee0fa090a38aa33c631ded2d8cf6fead4124181d1b35dc474f7c", + "https://bcr.bazel.build/modules/rules_jvm_external/6.10/source.json": "c191249787625db72616a3fb3cc2786ab57355a2e3b615402b8b3b66b0f995b7", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/MODULE.bazel": "d269a01a18ee74d0335450b10f62c9ed81f2321d7958a2934e44272fe82dcef3", + "https://bcr.bazel.build/modules/rules_kotlin/2.1.3/MODULE.bazel": "ce7def6d576aa8d3a9c6d10e13b4d157296229674371f67dbf788dae0afae3d5", + "https://bcr.bazel.build/modules/rules_kotlin/2.2.2/MODULE.bazel": "00d39c5e0fa78cd86193946265bb849e7878c24e44260f9525108428852b315c", + "https://bcr.bazel.build/modules/rules_kotlin/2.2.2/source.json": "7a32c2259c79ae0c9a036121f120de825e3ba5f0f3a209ffbbdccf4dc62489b9", + "https://bcr.bazel.build/modules/rules_license/0.0.3/MODULE.bazel": "627e9ab0247f7d1e05736b59dbb1b6871373de5ad31c3011880b4133cafd4bd0", + "https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d", + "https://bcr.bazel.build/modules/rules_license/1.0.0/MODULE.bazel": "a7fda60eefdf3d8c827262ba499957e4df06f659330bbe6cdbdb975b768bb65c", + "https://bcr.bazel.build/modules/rules_license/1.0.0/source.json": "a52c89e54cc311196e478f8382df91c15f7a2bfdf4c6cd0e2675cc2ff0b56efb", + "https://bcr.bazel.build/modules/rules_m4/0.3.1/MODULE.bazel": "dcfb70aa14ba4ab99bcda9605d6fd0c8de4531a74bf854fb76ecd9f93a6f1e7e", + "https://bcr.bazel.build/modules/rules_m4/0.3.bcr.1/MODULE.bazel": "41d4602bb89a1495fef1e694837f47bf18fc86e4cd7fb00cd6a4f6c0d2c395e4", + "https://bcr.bazel.build/modules/rules_m4/0.3.bcr.1/source.json": "0f3dffd7c11d8ae41eaf65ebcca59df6ed0b6cc44bd323129f1070ded71160f5", + "https://bcr.bazel.build/modules/rules_nodejs/6.2.0/MODULE.bazel": "ec27907f55eb34705adb4e8257952162a2d4c3ed0f0b3b4c3c1aad1fac7be35e", + "https://bcr.bazel.build/modules/rules_nodejs/6.7.3/MODULE.bazel": "c22a48b2a0dbf05a9dc5f83837bbc24c226c1f6e618de3c3a610044c9f336056", + "https://bcr.bazel.build/modules/rules_nodejs/6.7.6/MODULE.bazel": "45f203b9c0d721bcb1a5932815f218091fa2169cede2af3d88a8a17a4fb7676a", + "https://bcr.bazel.build/modules/rules_nodejs/6.7.6/source.json": "ad9987b7979be1ce93d10ffee9b6af4f84f8835cbc7def27937d632da2e4750e", + "https://bcr.bazel.build/modules/rules_perl/1.2.0/MODULE.bazel": "b56bdae4311b88767f2d84e917c16ddd222d29098bd5c1bbbf3968eee8b5a9b5", + "https://bcr.bazel.build/modules/rules_perl/1.2.0/source.json": "d8d55cd7baa7cca004171507e77899c2c410e3e4456a59d29e6bf00ae7afbcf6", + "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc", + "https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff", + "https://bcr.bazel.build/modules/rules_pkg/1.3.0/MODULE.bazel": "ae0bdefbacc990c91f843206c90cf0f4be620639a5bf22119043599ba86d51a3", + "https://bcr.bazel.build/modules/rules_pkg/1.3.0/source.json": "58ae84c545141762f7c434c0ce78bfb55ef0be08d84863e7f0503fff135fe4e2", + "https://bcr.bazel.build/modules/rules_proto/4.0.0/MODULE.bazel": "a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06", + "https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7", + "https://bcr.bazel.build/modules/rules_proto/6.0.0-rc1/MODULE.bazel": "1e5b502e2e1a9e825eef74476a5a1ee524a92297085015a052510b09a1a09483", + "https://bcr.bazel.build/modules/rules_proto/6.0.0/MODULE.bazel": "b531d7f09f58dce456cd61b4579ce8c86b38544da75184eadaf0a7cb7966453f", + "https://bcr.bazel.build/modules/rules_proto/6.0.2/MODULE.bazel": "ce916b775a62b90b61888052a416ccdda405212b6aaeb39522f7dc53431a5e73", + "https://bcr.bazel.build/modules/rules_proto/7.0.2/MODULE.bazel": "bf81793bd6d2ad89a37a40693e56c61b0ee30f7a7fdbaf3eabbf5f39de47dea2", + "https://bcr.bazel.build/modules/rules_proto/7.0.2/source.json": "1e5e7260ae32ef4f2b52fd1d0de8d03b606a44c91b694d2f1afb1d3b28a48ce1", + "https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f", + "https://bcr.bazel.build/modules/rules_python/0.23.1/MODULE.bazel": "49ffccf0511cb8414de28321f5fcf2a31312b47c40cc21577144b7447f2bf300", + "https://bcr.bazel.build/modules/rules_python/0.25.0/MODULE.bazel": "72f1506841c920a1afec76975b35312410eea3aa7b63267436bfb1dd91d2d382", + "https://bcr.bazel.build/modules/rules_python/0.28.0/MODULE.bazel": "cba2573d870babc976664a912539b320cbaa7114cd3e8f053c720171cde331ed", + "https://bcr.bazel.build/modules/rules_python/0.31.0/MODULE.bazel": "93a43dc47ee570e6ec9f5779b2e64c1476a6ce921c48cc9a1678a91dd5f8fd58", + "https://bcr.bazel.build/modules/rules_python/0.33.2/MODULE.bazel": "3e036c4ad8d804a4dad897d333d8dce200d943df4827cb849840055be8d2e937", + "https://bcr.bazel.build/modules/rules_python/0.37.1/MODULE.bazel": "3faeb2d9fa0a81f8980643ee33f212308f4d93eea4b9ce6f36d0b742e71e9500", + "https://bcr.bazel.build/modules/rules_python/0.37.2/MODULE.bazel": "b5ffde91410745750b6c13be1c5dc4555ef5bc50562af4a89fd77807fdde626a", + "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c", + "https://bcr.bazel.build/modules/rules_python/0.40.0/MODULE.bazel": "9d1a3cd88ed7d8e39583d9ffe56ae8a244f67783ae89b60caafc9f5cf318ada7", + "https://bcr.bazel.build/modules/rules_python/1.0.0/MODULE.bazel": "898a3d999c22caa585eb062b600f88654bf92efb204fa346fb55f6f8edffca43", + "https://bcr.bazel.build/modules/rules_python/1.6.0/MODULE.bazel": "7e04ad8f8d5bea40451cf80b1bd8262552aa73f841415d20db96b7241bd027d8", + "https://bcr.bazel.build/modules/rules_python/1.7.0/MODULE.bazel": "d01f995ecd137abf30238ad9ce97f8fc3ac57289c8b24bd0bf53324d937a14f8", + "https://bcr.bazel.build/modules/rules_python/1.7.0/source.json": "028a084b65dcf8f4dc4f82f8778dbe65df133f234b316828a82e060d81bdce32", + "https://bcr.bazel.build/modules/rules_robolectric/4.14.1.2/MODULE.bazel": "d44fec647d0aeb67b9f3b980cf68ba634976f3ae7ccd6c07d790b59b87a4f251", + "https://bcr.bazel.build/modules/rules_robolectric/4.14.1.2/source.json": "37c10335f2361c337c5c1f34ed36d2da70534c23088062b33a8bdaab68aa9dea", + "https://bcr.bazel.build/modules/rules_rust/0.74.0/MODULE.bazel": "6e6fa04d7c8202f9cd63205ec9f96da39382a4ac971ee1d7a900fe8e1f68be17", + "https://bcr.bazel.build/modules/rules_rust/0.74.0/source.json": "04eac31b4536eb23dd8e8e8ca7e079d3c1c4ac99934d38aa54bbae36917c7507", + "https://bcr.bazel.build/modules/rules_shell/0.1.2/MODULE.bazel": "66e4ca3ce084b04af0b9ff05ff14cab4e5df7503973818bb91cbc6cda08d32fc", + "https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c", + "https://bcr.bazel.build/modules/rules_shell/0.3.0/MODULE.bazel": "de4402cd12f4cc8fda2354fce179fdb068c0b9ca1ec2d2b17b3e21b24c1a937b", + "https://bcr.bazel.build/modules/rules_shell/0.4.1/MODULE.bazel": "00e501db01bbf4e3e1dd1595959092c2fadf2087b2852d3f553b5370f5633592", + "https://bcr.bazel.build/modules/rules_shell/0.6.1/MODULE.bazel": "72e76b0eea4e81611ef5452aa82b3da34caca0c8b7b5c0c9584338aa93bae26b", + "https://bcr.bazel.build/modules/rules_shell/0.8.0/MODULE.bazel": "f6a89f1d6a669a26f28fe814503857055d76306b79cfc11d12399af08d0b80ae", + "https://bcr.bazel.build/modules/rules_shell/0.8.0/source.json": "eb53cc815bc503c6683c5fe12d943f98883f81fc22f51403ec8a95610cba4195", + "https://bcr.bazel.build/modules/rules_swift/4.2.1/MODULE.bazel": "550a2b9ee70c816dd4e106a85df3cab92c5ca85de8f606001075c68c832700e6", + "https://bcr.bazel.build/modules/rules_swift/4.2.1/source.json": "b5b247915427e647852fbcd449333bfd1bedde289348e8879ba2c078eca2df38", + "https://bcr.bazel.build/modules/stardoc/0.5.4/MODULE.bazel": "6569966df04610b8520957cb8e97cf2e9faac2c0309657c537ab51c16c18a2a4", + "https://bcr.bazel.build/modules/stardoc/0.6.2/MODULE.bazel": "7060193196395f5dd668eda046ccbeacebfd98efc77fed418dbe2b82ffaa39fd", + "https://bcr.bazel.build/modules/stardoc/0.7.0/MODULE.bazel": "05e3d6d30c099b6770e97da986c53bd31844d7f13d41412480ea265ac9e8079c", + "https://bcr.bazel.build/modules/stardoc/0.7.1/MODULE.bazel": "3548faea4ee5dda5580f9af150e79d0f6aea934fc60c1cc50f4efdd9420759e7", + "https://bcr.bazel.build/modules/stardoc/0.7.2/MODULE.bazel": "fc152419aa2ea0f51c29583fab1e8c99ddefd5b3778421845606ee628629e0e5", + "https://bcr.bazel.build/modules/stardoc/0.7.2/source.json": "58b029e5e901d6802967754adf0a9056747e8176f017cfe3607c0851f4d42216", + "https://bcr.bazel.build/modules/swift_argument_parser/1.7.0/MODULE.bazel": "40d4e44950e44973dcf8590bcee637591de196b5dbe3696d07eb342b74d53672", + "https://bcr.bazel.build/modules/swift_argument_parser/1.7.0/source.json": "b9b952cba0c748083b9b891e6ac46d347c92d37e8a92ead96d2a54b966bacd87", + "https://bcr.bazel.build/modules/tar.bzl/0.10.4/MODULE.bazel": "e8f9ff79199e8d9eaad7f1b0a77ad74b30bb82d794b87d8ca942bead5de83ae9", + "https://bcr.bazel.build/modules/tar.bzl/0.10.4/source.json": "20143442376c03426f6135292ba02d825cb75308aa47e6bf42dd4cc5a435c2ff", + "https://bcr.bazel.build/modules/tar.bzl/0.2.1/MODULE.bazel": "52d1c00a80a8cc67acbd01649e83d8dd6a9dc426a6c0b754a04fe8c219c76468", + "https://bcr.bazel.build/modules/tar.bzl/0.5.1/MODULE.bazel": "7c2eb3dcfc53b0f3d6f9acdfd911ca803eaf92aadf54f8ca6e4c1f3aee288351", + "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43", + "https://bcr.bazel.build/modules/upb/0.0.0-20230516-61a97ef/MODULE.bazel": "c0df5e35ad55e264160417fd0875932ee3c9dda63d9fccace35ac62f45e1b6f9", + "https://bcr.bazel.build/modules/xctestrunner/0.2.16-20260212-4c6f493/MODULE.bazel": "df9d74c77698e7dbc52a65ebdd6de5727044e98121ac309b5d046f2d04121d56", + "https://bcr.bazel.build/modules/xctestrunner/0.2.16-20260212-4c6f493/source.json": "73a5421c8ef51cd455a572dee5bb9415351ab5acbcb65d4efa56a574790bd2f2", + "https://bcr.bazel.build/modules/yq.bzl/0.1.1/MODULE.bazel": "9039681f9bcb8958ee2c87ffc74bdafba9f4369096a2b5634b88abc0eaefa072", + "https://bcr.bazel.build/modules/yq.bzl/0.3.4/MODULE.bazel": "d3a270662f5d766cd7229732d65a5a5bc485240c3007343dd279edfb60c9ae27", + "https://bcr.bazel.build/modules/yq.bzl/0.3.4/source.json": "786dafdc2843722da3416e4343ee1a05237227f068590779a6e8496a2064c0f9", + "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0", + "https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/source.json": "22bc55c47af97246cfc093d0acf683a7869377de362b5d1c552c2c2e16b7a806", + "https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198" + }, + "selectedYankedVersions": {}, + "moduleExtensions": { + "//build_defs/extensions:repositories.bzl%extension_sources": { + "general": { + "bzlTransitiveDigest": "omCCmPafbjwxer6WIAtVBFcwqMglbNhHXpzQTjRTXfw=", + "usagesDigest": "Tut2HerGPqUSZPlpLEwzkw93ZjcmZpcPTu5KYnSIT3A=", + "recordedInputs": [ + "REPO_MAPPING:,bazel_tools bazel_tools", + "REPO_MAPPING:,bun_runtime +_repo_rules2+bun_runtime", + "REPO_MAPPING:,oliphaunt_metadata +_repo_rules14+oliphaunt_metadata" + ], + "generatedRepoSpecs": { + "pg_hashids": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://codeload.github.com/iCyberon/pg_hashids/tar.gz/8c404dd86408f3a987a3ff6825ac7e42bd618b98" + ], + "sha256": "01805af758549c7f3da80198451c42db976167ef7a1a5a8abafd10292ee128ab", + "strip_prefix": "pg_hashids-8c404dd86408f3a987a3ff6825ac7e42bd618b98", + "type": "tar.gz", + "build_file_content": "\npackage(default_visibility = [\"//visibility:public\"])\nexports_files(glob([\"**\"], exclude = [\"BUILD\", \"BUILD.bazel\", \"WORKSPACE\", \"WORKSPACE.bazel\", \"MODULE.bazel\"], allow_empty = True))\nfilegroup(\n name = \"sql_inputs\",\n srcs = glob([\"*.control\", \"sql/*.sql\", \"sql/*.sql.in\", \"compat/install-*.patch\", \"compat/gencore\", \"Makefile\"], allow_empty = True),\n)\nfilegroup(name = \"headers\", srcs = glob([\"src/**/*.h\"], allow_empty = True))\nfilegroup(name = \"sql_resources\", srcs = glob([\"*.control\", \"*--*.sql\", \"sql/*--*.sql\"], allow_empty = True))\nfilegroup(name = \"sql_upgrade_resources\", srcs = glob([\"*--*--*.sql\", \"sql/*--*--*.sql\"], allow_empty = True))\nfilegroup(name = \"test_inputs\", srcs = glob([\"Makefile\", \"test/sql/*.sql\", \"test/expected/*.out\", \"test/scripts/gen*_bm25vector.py\"], allow_empty = True))\n" + } + }, + "pg_ivm": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://codeload.github.com/sraoss/pg_ivm/tar.gz/b66487f7a6f8deee3998e858d773e19923e4bd4b" + ], + "sha256": "a7c29129e959dd4233a7e565883e15e97bf9aa8e40650597868447227788fd12", + "strip_prefix": "pg_ivm-b66487f7a6f8deee3998e858d773e19923e4bd4b", + "type": "tar.gz", + "build_file_content": "\npackage(default_visibility = [\"//visibility:public\"])\nexports_files(glob([\"**\"], exclude = [\"BUILD\", \"BUILD.bazel\", \"WORKSPACE\", \"WORKSPACE.bazel\", \"MODULE.bazel\"], allow_empty = True))\nfilegroup(\n name = \"sql_inputs\",\n srcs = glob([\"*.control\", \"sql/*.sql\", \"sql/*.sql.in\", \"compat/install-*.patch\", \"compat/gencore\", \"Makefile\"], allow_empty = True),\n)\nfilegroup(name = \"headers\", srcs = glob([\"src/**/*.h\"], allow_empty = True))\nfilegroup(name = \"sql_resources\", srcs = glob([\"*.control\", \"*--*.sql\", \"sql/*--*.sql\"], allow_empty = True))\nfilegroup(name = \"sql_upgrade_resources\", srcs = glob([\"*--*--*.sql\", \"sql/*--*--*.sql\"], allow_empty = True))\nfilegroup(name = \"test_inputs\", srcs = glob([\"Makefile\", \"test/sql/*.sql\", \"test/expected/*.out\", \"test/scripts/gen*_bm25vector.py\"], allow_empty = True))\n" + } + }, + "pg_textsearch": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://codeload.github.com/timescale/pg_textsearch/tar.gz/fa142d049d08eac45a263f5abc250c8877ae076e" + ], + "sha256": "445a546810cbc17e15d05ff8a391f1b693eab382a2ef6efbf72e1c37fa0c48d0", + "strip_prefix": "pg_textsearch-fa142d049d08eac45a263f5abc250c8877ae076e", + "type": "tar.gz", + "build_file_content": "\npackage(default_visibility = [\"//visibility:public\"])\nexports_files(glob([\"**\"], exclude = [\"BUILD\", \"BUILD.bazel\", \"WORKSPACE\", \"WORKSPACE.bazel\", \"MODULE.bazel\"], allow_empty = True))\nfilegroup(\n name = \"sql_inputs\",\n srcs = glob([\"*.control\", \"sql/*.sql\", \"sql/*.sql.in\", \"compat/install-*.patch\", \"compat/gencore\", \"Makefile\"], allow_empty = True),\n)\nfilegroup(name = \"headers\", srcs = glob([\"src/**/*.h\"], allow_empty = True))\nfilegroup(name = \"sql_resources\", srcs = glob([\"*.control\", \"*--*.sql\", \"sql/*--*.sql\"], allow_empty = True))\nfilegroup(name = \"sql_upgrade_resources\", srcs = glob([\"*--*--*.sql\", \"sql/*--*--*.sql\"], allow_empty = True))\nfilegroup(name = \"test_inputs\", srcs = glob([\"Makefile\", \"test/sql/*.sql\", \"test/expected/*.out\", \"test/scripts/gen*_bm25vector.py\"], allow_empty = True))\n" + } + }, + "pg_uuidv7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://codeload.github.com/fboulnois/pg_uuidv7/tar.gz/c707aae2411181be4802f5fa565b44d9c0bcbc29" + ], + "sha256": "422b882887ace16a1358150eb8bcfcf41a74ae60db89818929ba4f59ba360251", + "strip_prefix": "pg_uuidv7-c707aae2411181be4802f5fa565b44d9c0bcbc29", + "type": "tar.gz", + "build_file_content": "\npackage(default_visibility = [\"//visibility:public\"])\nexports_files(glob([\"**\"], exclude = [\"BUILD\", \"BUILD.bazel\", \"WORKSPACE\", \"WORKSPACE.bazel\", \"MODULE.bazel\"], allow_empty = True))\nfilegroup(\n name = \"sql_inputs\",\n srcs = glob([\"*.control\", \"sql/*.sql\", \"sql/*.sql.in\", \"compat/install-*.patch\", \"compat/gencore\", \"Makefile\"], allow_empty = True),\n)\nfilegroup(name = \"headers\", srcs = glob([\"src/**/*.h\"], allow_empty = True))\nfilegroup(name = \"sql_resources\", srcs = glob([\"*.control\", \"*--*.sql\", \"sql/*--*.sql\"], allow_empty = True))\nfilegroup(name = \"sql_upgrade_resources\", srcs = glob([\"*--*--*.sql\", \"sql/*--*--*.sql\"], allow_empty = True))\nfilegroup(name = \"test_inputs\", srcs = glob([\"Makefile\", \"test/sql/*.sql\", \"test/expected/*.out\", \"test/scripts/gen*_bm25vector.py\"], allow_empty = True))\n" + } + }, + "pgtap": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://codeload.github.com/theory/pgtap/tar.gz/b89585a64ffef012ff0f219de9197c669aa8485b" + ], + "sha256": "ffd501f27670a7d3d7f0cfd4ea7f291848112c2ef408a0b73e4cb727ac83e604", + "strip_prefix": "pgtap-b89585a64ffef012ff0f219de9197c669aa8485b", + "type": "tar.gz", + "build_file_content": "\npackage(default_visibility = [\"//visibility:public\"])\nexports_files(glob([\"**\"], exclude = [\"BUILD\", \"BUILD.bazel\", \"WORKSPACE\", \"WORKSPACE.bazel\", \"MODULE.bazel\"], allow_empty = True))\nfilegroup(\n name = \"sql_inputs\",\n srcs = glob([\"*.control\", \"sql/*.sql\", \"sql/*.sql.in\", \"compat/install-*.patch\", \"compat/gencore\", \"Makefile\"], allow_empty = True),\n)\nfilegroup(name = \"headers\", srcs = glob([\"src/**/*.h\"], allow_empty = True))\nfilegroup(name = \"sql_resources\", srcs = glob([\"*.control\", \"*--*.sql\", \"sql/*--*.sql\"], allow_empty = True))\nfilegroup(name = \"sql_upgrade_resources\", srcs = glob([\"*--*--*.sql\", \"sql/*--*--*.sql\"], allow_empty = True))\nfilegroup(name = \"test_inputs\", srcs = glob([\"Makefile\", \"test/sql/*.sql\", \"test/expected/*.out\", \"test/scripts/gen*_bm25vector.py\"], allow_empty = True))\n" + } + }, + "postgis": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://codeload.github.com/postgis/postgis/tar.gz/3d12666588a84b23a3147618eaa9b40b0fe5e796" + ], + "sha256": "0cab012a4e470b2479d4dcaa6a64f5322fe64092e5c3018da94dfcfd106ef874", + "strip_prefix": "postgis-3d12666588a84b23a3147618eaa9b40b0fe5e796", + "type": "tar.gz", + "build_file_content": "\npackage(default_visibility = [\"//visibility:public\"])\nexports_files(glob([\"**\"], exclude = [\"BUILD\", \"BUILD.bazel\", \"WORKSPACE\", \"WORKSPACE.bazel\", \"MODULE.bazel\"], allow_empty = True))\nfilegroup(\n name = \"sql_inputs\",\n srcs = glob([\"*.control\", \"sql/*.sql\", \"sql/*.sql.in\", \"compat/install-*.patch\", \"compat/gencore\", \"Makefile\"], allow_empty = True),\n)\nfilegroup(name = \"headers\", srcs = glob([\"src/**/*.h\"], allow_empty = True))\nfilegroup(name = \"sql_resources\", srcs = glob([\"*.control\", \"*--*.sql\", \"sql/*--*.sql\"], allow_empty = True))\nfilegroup(name = \"sql_upgrade_resources\", srcs = glob([\"*--*--*.sql\", \"sql/*--*--*.sql\"], allow_empty = True))\nfilegroup(name = \"test_inputs\", srcs = glob([\"Makefile\", \"test/sql/*.sql\", \"test/expected/*.out\", \"test/scripts/gen*_bm25vector.py\"], allow_empty = True))\n\nfilegroup(name = \"postgis_headers\", srcs = glob([\"**/*.h\", \"**/*.hpp\", \"**/*.inl\", \"**/*.inc\"], allow_empty = True))\nfilegroup(name = \"postgis_sql_inputs\", srcs = glob([\"Version.config\", \"postgis/*.sql.in\", \"postgis/*.sql.in.*\", \"postgis/*.sql\", \"postgis/*.h\", \"libpgcommon/*.h\", \"extensions/**/*.sql\", \"extensions/**/*.sql.in\", \"extensions/**/Makefile.in\", \"extensions/upgrade-paths-rules.mk\", \"utils/*.pl\", \"raster/rt_pg/*.sql.in\", \"raster/rt_pg/*.sql.in.*\", \"raster/rt_pg/*.sql\", \"postgis/Makefile.in\", \"raster/rt_pg/Makefile.in\"], allow_empty = True))\n" + } + }, + "pgvector": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://codeload.github.com/pgvector/pgvector/tar.gz/d238409becebb8172fe696ffa776badfad4b631c" + ], + "sha256": "64692fe3b2da7c1c3f53a37d6100400597008375960ab4ce3ddd79e0cd188226", + "strip_prefix": "pgvector-d238409becebb8172fe696ffa776badfad4b631c", + "type": "tar.gz", + "build_file_content": "\npackage(default_visibility = [\"//visibility:public\"])\nexports_files(glob([\"**\"], exclude = [\"BUILD\", \"BUILD.bazel\", \"WORKSPACE\", \"WORKSPACE.bazel\", \"MODULE.bazel\"], allow_empty = True))\nfilegroup(\n name = \"sql_inputs\",\n srcs = glob([\"*.control\", \"sql/*.sql\", \"sql/*.sql.in\", \"compat/install-*.patch\", \"compat/gencore\", \"Makefile\"], allow_empty = True),\n)\nfilegroup(name = \"headers\", srcs = glob([\"src/**/*.h\"], allow_empty = True))\nfilegroup(name = \"sql_resources\", srcs = glob([\"*.control\", \"*--*.sql\", \"sql/*--*.sql\"], allow_empty = True))\nfilegroup(name = \"sql_upgrade_resources\", srcs = glob([\"*--*--*.sql\", \"sql/*--*--*.sql\"], allow_empty = True))\nfilegroup(name = \"test_inputs\", srcs = glob([\"Makefile\", \"test/sql/*.sql\", \"test/expected/*.out\", \"test/scripts/gen*_bm25vector.py\"], allow_empty = True))\n" + } + }, + "postgis_geos": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://codeload.github.com/libgeos/geos/tar.gz/c389f532d25fe6228861d9b19339f9cb57ca4bdb" + ], + "sha256": "c6ef7660abd410d20b4f30085dfc1b0f804f487967aeddda6eca2aaa36abfa5a", + "strip_prefix": "geos-c389f532d25fe6228861d9b19339f9cb57ca4bdb", + "type": "tar.gz", + "build_file_content": "\npackage(default_visibility = [\"//visibility:public\"])\nexports_files(glob([\"**\"], exclude = [\"BUILD\", \"BUILD.bazel\", \"WORKSPACE\", \"WORKSPACE.bazel\", \"MODULE.bazel\"], allow_empty = True))\nfilegroup(name = \"all_sources\", srcs = glob([\"**\"], exclude = [\"BUILD\", \"BUILD.bazel\", \"WORKSPACE\", \"WORKSPACE.bazel\", \"MODULE.bazel\"], allow_empty = True))\nfilegroup(name = \"headers\", srcs = glob([\"**/*.h\", \"**/*.hpp\", \"**/*.inl\", \"**/*.inc\"], allow_empty = True))\n\nfilegroup(name = \"native_sources\", srcs = glob([\"src/**/*.cpp\", \"capi/*.cpp\"]))\nfilegroup(name = \"native_c_sources\", srcs = glob([\"src/deps/**/*.c\"]))\nfilegroup(name = \"native_core_sources\", srcs = glob([\"src/**/*.cpp\"]))\nfilegroup(name = \"native_capi_sources\", srcs = glob([\"capi/*.cpp\"]))\n" + } + }, + "postgis_json_c": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://codeload.github.com/json-c/json-c/tar.gz/41a55cfcedb54d9c1874f2f0eb07b504091d7e37" + ], + "sha256": "a090046b2d24901eb8dca4d370c28991299e8c7cfb698b44e09ce809b1ff20b4", + "strip_prefix": "json-c-41a55cfcedb54d9c1874f2f0eb07b504091d7e37", + "type": "tar.gz", + "build_file_content": "\npackage(default_visibility = [\"//visibility:public\"])\nexports_files(glob([\"**\"], exclude = [\"BUILD\", \"BUILD.bazel\", \"WORKSPACE\", \"WORKSPACE.bazel\", \"MODULE.bazel\"], allow_empty = True))\nfilegroup(name = \"all_sources\", srcs = glob([\"**\"], exclude = [\"BUILD\", \"BUILD.bazel\", \"WORKSPACE\", \"WORKSPACE.bazel\", \"MODULE.bazel\"], allow_empty = True))\nfilegroup(name = \"headers\", srcs = glob([\"**/*.h\", \"**/*.hpp\", \"**/*.inl\", \"**/*.inc\"], allow_empty = True))\n" + } + }, + "postgis_libiconv": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://ftpmirror.gnu.org/libiconv/libiconv-1.19.tar.gz", + "https://mirrors.ocf.berkeley.edu/gnu/libiconv/libiconv-1.19.tar.gz" + ], + "sha256": "88dd96a8c0464eca144fc791ae60cd31cd8ee78321e67397e25fc095c4a19aa6", + "strip_prefix": "libiconv-1.19", + "build_file_content": "\npackage(default_visibility = [\"//visibility:public\"])\nexports_files(glob([\"**\"], exclude = [\"BUILD\", \"BUILD.bazel\", \"WORKSPACE\", \"WORKSPACE.bazel\", \"MODULE.bazel\"], allow_empty = True))\nfilegroup(name = \"all_sources\", srcs = glob([\"**\"], exclude = [\"BUILD\", \"BUILD.bazel\", \"WORKSPACE\", \"WORKSPACE.bazel\", \"MODULE.bazel\"], allow_empty = True))\nfilegroup(name = \"headers\", srcs = glob([\"**/*.h\", \"**/*.hpp\", \"**/*.inl\", \"**/*.inc\"], allow_empty = True))\n" + } + }, + "postgis_libxml2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://codeload.github.com/GNOME/libxml2/tar.gz/d23960a130c5bb82779c9405fbbf85e65fb3c57c" + ], + "sha256": "2ac9ff16a006d9793ed23d31b40867aa41d23ae7762f8a25868f733944d5d775", + "strip_prefix": "libxml2-d23960a130c5bb82779c9405fbbf85e65fb3c57c", + "type": "tar.gz", + "build_file_content": "\npackage(default_visibility = [\"//visibility:public\"])\nexports_files(glob([\"**\"], exclude = [\"BUILD\", \"BUILD.bazel\", \"WORKSPACE\", \"WORKSPACE.bazel\", \"MODULE.bazel\"], allow_empty = True))\nfilegroup(name = \"all_sources\", srcs = glob([\"**\"], exclude = [\"BUILD\", \"BUILD.bazel\", \"WORKSPACE\", \"WORKSPACE.bazel\", \"MODULE.bazel\"], allow_empty = True))\nfilegroup(name = \"headers\", srcs = glob([\"**/*.h\", \"**/*.hpp\", \"**/*.inl\", \"**/*.inc\"], allow_empty = True))\n" + } + }, + "postgis_proj": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://codeload.github.com/OSGeo/PROJ/tar.gz/f08fa86c478c4bbbf003b1ec751dd84aa6eca486" + ], + "sha256": "db00adb24cb064895f9055095ea21fecc1349ffac1f225def2ef38f3dbc4831b", + "strip_prefix": "PROJ-f08fa86c478c4bbbf003b1ec751dd84aa6eca486", + "type": "tar.gz", + "build_file_content": "\npackage(default_visibility = [\"//visibility:public\"])\nexports_files(glob([\"**\"], exclude = [\"BUILD\", \"BUILD.bazel\", \"WORKSPACE\", \"WORKSPACE.bazel\", \"MODULE.bazel\"], allow_empty = True))\nfilegroup(name = \"all_sources\", srcs = glob([\"**\"], exclude = [\"BUILD\", \"BUILD.bazel\", \"WORKSPACE\", \"WORKSPACE.bazel\", \"MODULE.bazel\"], allow_empty = True))\nfilegroup(name = \"headers\", srcs = glob([\"**/*.h\", \"**/*.hpp\", \"**/*.inl\", \"**/*.inc\"], allow_empty = True))\n\nfilegroup(name = \"native_sources\", srcs = glob([\"src/*.cpp\", \"src/projections/*.cpp\", \"src/conversions/*.cpp\", \"src/transformations/*.cpp\", \"src/iso19111/**/*.cpp\"]))\nfilegroup(name = \"native_c_sources\", srcs = glob([\"src/*.c\"], exclude = [\"src/embedded_resources.c\", \"src/memvfs.c\"]))\n" + } + }, + "postgis_sqlite": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://codeload.github.com/sqlite/sqlite/tar.gz/ccd445d76a9362c63add000354fac84ba9022176" + ], + "sha256": "96f14610a11721fbd5bd254db3ca833de9e4d922ce3da7122e092fdb19838b30", + "strip_prefix": "sqlite-ccd445d76a9362c63add000354fac84ba9022176", + "type": "tar.gz", + "build_file_content": "\npackage(default_visibility = [\"//visibility:public\"])\nexports_files(glob([\"**\"], exclude = [\"BUILD\", \"BUILD.bazel\", \"WORKSPACE\", \"WORKSPACE.bazel\", \"MODULE.bazel\"], allow_empty = True))\nfilegroup(name = \"all_sources\", srcs = glob([\"**\"], exclude = [\"BUILD\", \"BUILD.bazel\", \"WORKSPACE\", \"WORKSPACE.bazel\", \"MODULE.bazel\"], allow_empty = True))\nfilegroup(name = \"headers\", srcs = glob([\"**/*.h\", \"**/*.hpp\", \"**/*.inl\", \"**/*.inc\"], allow_empty = True))\n" + } + } + } + } + }, + "//build_defs/extensions/postgis:gpp_repositories.bzl%postgis_gpp": { + "general": { + "bzlTransitiveDigest": "yKzOBVgsBsr4KxLH1uVLBdhD/P4jqOQ3PCaXHipSNJ4=", + "usagesDigest": "xj2oIFAnnQQSB0S35e1UzZ4YISjMiDZPc9XlnB4JujU=", + "recordedInputs": [ + "REPO_MAPPING:,bazel_tools bazel_tools" + ], + "generatedRepoSpecs": { + "postgis_gpp": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "urls": [ + "https://codeload.github.com/logological/gpp/tar.gz/fc9cc00078999dabd795b782eebc94780cf39a29" + ], + "sha256": "c172969881f7f76918c18b5406a8bf8ac3aeca6ea859628e4edabe4e8a7fbcd1", + "type": "tar.gz", + "strip_prefix": "gpp-fc9cc00078999dabd795b782eebc94780cf39a29", + "build_file_content": "\nload(\"@bazel_skylib//rules:write_file.bzl\", \"write_file\")\nload(\"@rules_cc//cc:defs.bzl\", \"cc_binary\")\npackage(default_visibility = [\"//visibility:public\"])\nexports_files([\"configure.ac\", \"src/Makefile.am\", \"COPYING\", \"COPYING.LESSER\"])\nwrite_file(\n name = \"config\",\n out = \"config.h\",\n content = ['#define PACKAGE_STRING \"GPP 2.28\"', \"\"],\n)\ncc_binary(\n name = \"gpp\",\n srcs = [\"src/gpp.c\", \":config\"],\n includes = [\".\"],\n # gpp.c's upstream WIN_NT branch owns CRT aliases and its fnmatch fallback.\n defines = [\"HAVE_CONFIG_H=1\"] + select({\n \"@platforms//os:windows\": [\"WIN_NT\"],\n \"//conditions:default\": [\"HAVE_FNMATCH_H=1\", \"HAVE_STRDUP=1\", \"HAVE_STRCASECMP=1\"],\n }),\n target_compatible_with = select({\n \"@platforms//os:linux\": [], \"@platforms//os:macos\": [], \"@platforms//os:windows\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n)\n" + } + } + } + } + }, + "//build_defs/wasix/browser:cargo-extension.bzl%crate": { + "general": { + "bzlTransitiveDigest": "CAz1wpwMLCfKX+I8B7eTnq6lrqDzoSZY0AJXGiNlidg=", + "usagesDigest": "SBGsDsmc7asIDFahfYex91GcU/scS1bdsO+eDUG2r1A=", + "recordedInputs": [ + "ENV:CARGO_BAZEL_DEBUG \\0", + "ENV:CARGO_BAZEL_GENERATOR_SHA256 \\0", + "ENV:CARGO_BAZEL_GENERATOR_URL \\0", + "ENV:CARGO_BAZEL_ISOLATED \\0", + "ENV:CARGO_BAZEL_REPIN \\0", + "ENV:CARGO_BAZEL_REPIN_ONLY \\0", + "ENV:CARGO_BAZEL_TIMEOUT \\0", + "ENV:REPIN \\0", + "REPO_MAPPING:,browser_rust_std +_repo_rules20+browser_rust_std", + "REPO_MAPPING:,browser_sources +_repo_rules17+browser_sources", + "REPO_MAPPING:,rules_rust rules_rust+", + "REPO_MAPPING:bazel_features+,bazel_features_globals bazel_features++version_extension+bazel_features_globals", + "REPO_MAPPING:bazel_features+,bazel_features_version bazel_features++version_extension+bazel_features_version", + "REPO_MAPPING:rules_cc+,bazel_tools bazel_tools", + "REPO_MAPPING:rules_cc+,cc_compatibility_proxy rules_cc++compatibility_proxy+cc_compatibility_proxy", + "REPO_MAPPING:rules_cc+,rules_cc rules_cc+", + "REPO_MAPPING:rules_cc++compatibility_proxy+cc_compatibility_proxy,rules_cc rules_cc+", + "REPO_MAPPING:rules_rust+,bazel_features bazel_features+", + "REPO_MAPPING:rules_rust+,bazel_skylib bazel_skylib+", + "REPO_MAPPING:rules_rust+,bazel_tools bazel_tools", + "REPO_MAPPING:rules_rust+,rules_cc rules_cc+", + "FILE:@@+_repo_rules17+browser_sources//cargo/Cargo.lock 7c8a1f1464808b78d34ebf28421d06657694ed248885f35f46d6edef41a631a4", + "FILE:@@+_repo_rules17+browser_sources//wasmer-js/.cargo/config.toml 0169417b3aa2d8968f69a8cb60912c3ccced67235bef589393a81acef4de4f7e", + "FILE:@@+_repo_rules17+browser_sources//cargo/Cargo.toml 59de286de96dcac94286caa8b6231ecc916ffbeeef955d6e9bdc984cf269eb3b", + "FILE:@@+_repo_rules17+browser_sources//cargo-sources.json 2f170c91dc36439e81ca6c223300c1677319ba9b51b951fcda78cbae907545c9" + ], + "generatedRepoSpecs": { + "browser_cargo": { + "repoRuleId": "@@rules_rust+//crate_universe/private:crates_vendor.bzl%crates_vendor_remote_repository", + "attributes": { + "contents": { + "BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files(\n [\n \"cargo-bazel.json\",\n \"crates.bzl\",\n \"defs.bzl\",\n ] + glob(\n allow_empty = True,\n include = [\"*.bazel\"],\n ),\n)\n\nfilegroup(\n name = \"srcs\",\n srcs = glob(\n allow_empty = True,\n include = [\n \"*.bazel\",\n \"*.bzl\",\n ],\n ),\n)\n\n# Workspace Member Dependencies\nalias(\n name = \"anyhow-1.0.97\",\n actual = \"@browser_cargo__anyhow-1.0.97//:anyhow\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"anyhow\",\n actual = \"@browser_cargo__anyhow-1.0.97//:anyhow\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"async-trait-0.1.88\",\n actual = \"@browser_cargo__async-trait-0.1.88//:async_trait\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"async-trait\",\n actual = \"@browser_cargo__async-trait-0.1.88//:async_trait\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"bincode-1.3.3\",\n actual = \"@browser_cargo__bincode-1.3.3//:bincode\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"bincode\",\n actual = \"@browser_cargo__bincode-1.3.3//:bincode\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"bytes-1.10.1\",\n actual = \"@browser_cargo__bytes-1.10.1//:bytes\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"bytes\",\n actual = \"@browser_cargo__bytes-1.10.1//:bytes\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"console_error_panic_hook-0.1.7\",\n actual = \"@browser_cargo__console_error_panic_hook-0.1.7//:console_error_panic_hook\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"console_error_panic_hook\",\n actual = \"@browser_cargo__console_error_panic_hook-0.1.7//:console_error_panic_hook\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"derivative-2.2.0\",\n actual = \"@browser_cargo__derivative-2.2.0//:derivative\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"derivative\",\n actual = \"@browser_cargo__derivative-2.2.0//:derivative\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"futures-0.3.30\",\n actual = \"@browser_cargo__futures-0.3.30//:futures\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"futures\",\n actual = \"@browser_cargo__futures-0.3.30//:futures\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"instant-0.1.12\",\n actual = \"@browser_cargo__instant-0.1.12//:instant\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"instant\",\n actual = \"@browser_cargo__instant-0.1.12//:instant\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"js-sys-0.3.78\",\n actual = \"@browser_cargo__js-sys-0.3.78//:js_sys\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"js-sys\",\n actual = \"@browser_cargo__js-sys-0.3.78//:js_sys\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"lazy_static-1.5.0\",\n actual = \"@browser_cargo__lazy_static-1.5.0//:lazy_static\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"lazy_static\",\n actual = \"@browser_cargo__lazy_static-1.5.0//:lazy_static\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"once_cell-1.19.0\",\n actual = \"@browser_cargo__once_cell-1.19.0//:once_cell\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"once_cell\",\n actual = \"@browser_cargo__once_cell-1.19.0//:once_cell\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"reqwest-0.12.7\",\n actual = \"@browser_cargo__reqwest-0.12.7//:reqwest\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"reqwest\",\n actual = \"@browser_cargo__reqwest-0.12.7//:reqwest\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde-1.0.219\",\n actual = \"@browser_cargo__serde-1.0.219//:serde\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde\",\n actual = \"@browser_cargo__serde-1.0.219//:serde\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde-wasm-bindgen-0.6.5\",\n actual = \"@browser_cargo__serde-wasm-bindgen-0.6.5//:serde_wasm_bindgen\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde-wasm-bindgen\",\n actual = \"@browser_cargo__serde-wasm-bindgen-0.6.5//:serde_wasm_bindgen\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"sha2-0.10.8\",\n actual = \"@browser_cargo__sha2-0.10.8//:sha2\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"sha2\",\n actual = \"@browser_cargo__sha2-0.10.8//:sha2\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tempfile-3.12.0\",\n actual = \"@browser_cargo__tempfile-3.12.0//:tempfile\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tempfile\",\n actual = \"@browser_cargo__tempfile-3.12.0//:tempfile\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tokio-1.44.2\",\n actual = \"@browser_cargo__tokio-1.44.2//:tokio\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tokio\",\n actual = \"@browser_cargo__tokio-1.44.2//:tokio\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"toml-0.8.14\",\n actual = \"@browser_cargo__toml-0.8.14//:toml\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"toml\",\n actual = \"@browser_cargo__toml-0.8.14//:toml\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tracing-0.1.41\",\n actual = \"@browser_cargo__tracing-0.1.41//:tracing\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tracing\",\n actual = \"@browser_cargo__tracing-0.1.41//:tracing\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tracing-subscriber-0.3.18\",\n actual = \"@browser_cargo__tracing-subscriber-0.3.18//:tracing_subscriber\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tracing-subscriber\",\n actual = \"@browser_cargo__tracing-subscriber-0.3.18//:tracing_subscriber\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"url-2.5.4\",\n actual = \"@browser_cargo__url-2.5.4//:url\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"url\",\n actual = \"@browser_cargo__url-2.5.4//:url\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"virtual-fs-0.601.0\",\n actual = \"@browser_cargo__virtual-fs-0.601.0//:virtual_fs\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"virtual-fs\",\n actual = \"@browser_cargo__virtual-fs-0.601.0//:virtual_fs\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"virtual-net-0.601.0\",\n actual = \"@browser_cargo__virtual-net-0.601.0//:virtual_net\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"virtual-net\",\n actual = \"@browser_cargo__virtual-net-0.601.0//:virtual_net\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasm-bindgen-0.2.101\",\n actual = \"@browser_cargo__wasm-bindgen-0.2.101//:wasm_bindgen\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasm-bindgen\",\n actual = \"@browser_cargo__wasm-bindgen-0.2.101//:wasm_bindgen\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasm-bindgen-derive-0.2.1\",\n actual = \"@browser_cargo__wasm-bindgen-derive-0.2.1//:wasm_bindgen_derive\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasm-bindgen-derive\",\n actual = \"@browser_cargo__wasm-bindgen-derive-0.2.1//:wasm_bindgen_derive\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasm-bindgen-futures-0.4.51\",\n actual = \"@browser_cargo__wasm-bindgen-futures-0.4.51//:wasm_bindgen_futures\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasm-bindgen-futures\",\n actual = \"@browser_cargo__wasm-bindgen-futures-0.4.51//:wasm_bindgen_futures\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasm-bindgen-test-0.3.51\",\n actual = \"@browser_cargo__wasm-bindgen-test-0.3.51//:wasm_bindgen_test\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasm-bindgen-test\",\n actual = \"@browser_cargo__wasm-bindgen-test-0.3.51//:wasm_bindgen_test\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-6.1.0\",\n actual = \"@browser_cargo__wasmer-6.1.0//:wasmer\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer\",\n actual = \"@browser_cargo__wasmer-6.1.0//:wasmer\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-backend-api-0.601.0\",\n actual = \"@browser_cargo__wasmer-backend-api-0.601.0//:wasmer_backend_api\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-backend-api\",\n actual = \"@browser_cargo__wasmer-backend-api-0.601.0//:wasmer_backend_api\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-config-0.601.0\",\n actual = \"@browser_cargo__wasmer-config-0.601.0//:wasmer_config\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-config\",\n actual = \"@browser_cargo__wasmer-config-0.601.0//:wasmer_config\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-package-0.601.0\",\n actual = \"@browser_cargo__wasmer-package-0.601.0//:wasmer_package\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-package\",\n actual = \"@browser_cargo__wasmer-package-0.601.0//:wasmer_package\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-types-6.1.0\",\n actual = \"@browser_cargo__wasmer-types-6.1.0//:wasmer_types\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-types\",\n actual = \"@browser_cargo__wasmer-types-6.1.0//:wasmer_types\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-wasix-0.601.0\",\n actual = \"@browser_cargo__wasmer-wasix-0.601.0//:wasmer_wasix\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-wasix\",\n actual = \"@browser_cargo__wasmer-wasix-0.601.0//:wasmer_wasix\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"web-sys-0.3.78\",\n actual = \"@browser_cargo__web-sys-0.3.78//:web_sys\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"web-sys\",\n actual = \"@browser_cargo__web-sys-0.3.78//:web_sys\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"webc-10.0.1\",\n actual = \"@browser_cargo__webc-10.0.1//:webc\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"webc\",\n actual = \"@browser_cargo__webc-10.0.1//:webc\",\n tags = [\"manual\"],\n)\n", + "alias_rules.bzl": "\"\"\"Alias that transitions its target to `compilation_mode=opt`. Use `transition_alias=\"opt\"` to enable.\"\"\"\n\nload(\"@rules_cc//cc:defs.bzl\", \"CcInfo\")\nload(\"@rules_rust//rust:rust_common.bzl\", \"COMMON_PROVIDERS\")\n\ndef _transition_alias_impl(ctx):\n # `ctx.attr.actual` is a list of 1 item due to the transition\n providers = [ctx.attr.actual[0][provider] for provider in COMMON_PROVIDERS]\n if CcInfo in ctx.attr.actual[0]:\n providers.append(ctx.attr.actual[0][CcInfo])\n return providers\n\ndef _change_compilation_mode(compilation_mode):\n def _change_compilation_mode_impl(_settings, _attr):\n return {\n \"//command_line_option:compilation_mode\": compilation_mode,\n }\n\n return transition(\n implementation = _change_compilation_mode_impl,\n inputs = [],\n outputs = [\n \"//command_line_option:compilation_mode\",\n ],\n )\n\ndef _transition_alias_rule(compilation_mode):\n return rule(\n implementation = _transition_alias_impl,\n provides = COMMON_PROVIDERS,\n attrs = {\n \"actual\": attr.label(\n mandatory = True,\n doc = \"`rust_library()` target to transition to `compilation_mode=opt`.\",\n providers = COMMON_PROVIDERS,\n cfg = _change_compilation_mode(compilation_mode),\n ),\n \"_allowlist_function_transition\": attr.label(\n default = \"@bazel_tools//tools/allowlists/function_transition_allowlist\",\n ),\n },\n doc = \"Transitions a Rust library crate to the `compilation_mode=opt`.\",\n )\n\ntransition_alias_dbg = _transition_alias_rule(\"dbg\")\ntransition_alias_fastbuild = _transition_alias_rule(\"fastbuild\")\ntransition_alias_opt = _transition_alias_rule(\"opt\")\n", + "crates.bzl": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\"\"\"\n# `crates_repository` API\n\n- [aliases](#aliases)\n- [crate_edition](#crate_edition)\n- [crate_deps](#crate_deps)\n- [all_crate_deps](#all_crate_deps)\n- [crate_repositories](#crate_repositories)\n\n\"\"\"\n\nload(\"@bazel_tools//tools/build_defs/repo:git.bzl\", \"git_repository\")\nload(\"@bazel_tools//tools/build_defs/repo:http.bzl\", \"http_archive\")\nload(\"@bazel_tools//tools/build_defs/repo:utils.bzl\", \"maybe\")\nload(\"@bazel_skylib//lib:selects.bzl\", \"selects\")\nload(\"@rules_rust//crate_universe:defs.bzl\", \"crates_vendor_remote_repository\", \"local_crate_mirror\")\n\n###############################################################################\n# MACROS API\n###############################################################################\n\n# An identifier that represent common dependencies (unconditional).\n_COMMON_CONDITION = \"\"\n\ndef _flatten_dependency_maps(all_dependency_maps):\n \"\"\"Flatten a list of dependency maps into one dictionary.\n\n Dependency maps have the following structure:\n\n ```python\n DEPENDENCIES_MAP = {\n # The first key in the map is a Bazel package\n # name of the workspace this file is defined in.\n \"workspace_member_package\": {\n\n # Not all dependencies are supported for all platforms.\n # the condition key is the condition required to be true\n # on the host platform.\n \"condition\": {\n\n # An alias to a crate target. # The label of the crate target the\n # Aliases are only crate names. # package name refers to.\n \"package_name\": \"@full//:label\",\n }\n }\n }\n ```\n\n Args:\n all_dependency_maps (list): A list of dicts as described above\n\n Returns:\n dict: A dictionary as described above\n \"\"\"\n dependencies = {}\n\n for workspace_deps_map in all_dependency_maps:\n for pkg_name, conditional_deps_map in workspace_deps_map.items():\n if pkg_name not in dependencies:\n non_frozen_map = dict()\n for key, values in conditional_deps_map.items():\n non_frozen_map.update({key: dict(values.items())})\n dependencies.setdefault(pkg_name, non_frozen_map)\n continue\n\n for condition, deps_map in conditional_deps_map.items():\n # If the condition has not been recorded, do so and continue\n if condition not in dependencies[pkg_name]:\n dependencies[pkg_name].setdefault(condition, dict(deps_map.items()))\n continue\n\n # Alert on any miss-matched dependencies\n inconsistent_entries = []\n for crate_name, crate_label in deps_map.items():\n existing = dependencies[pkg_name][condition].get(crate_name)\n if existing and existing != crate_label:\n inconsistent_entries.append((crate_name, existing, crate_label))\n dependencies[pkg_name][condition].update({crate_name: crate_label})\n\n return dependencies\n\ndef crate_deps(deps, package_name = None):\n \"\"\"Finds the fully qualified label of the requested crates for the package where this macro is called.\n\n Args:\n deps (list): The desired list of crate targets.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()`.\n\n Returns:\n list: A list of labels to generated rust targets (str)\n \"\"\"\n\n if not deps:\n return []\n\n if package_name == None:\n package_name = native.package_name()\n\n # Join both sets of dependencies\n dependencies = _flatten_dependency_maps([\n _NORMAL_DEPENDENCIES,\n _NORMAL_DEV_DEPENDENCIES,\n _PROC_MACRO_DEPENDENCIES,\n _PROC_MACRO_DEV_DEPENDENCIES,\n _BUILD_DEPENDENCIES,\n _BUILD_PROC_MACRO_DEPENDENCIES,\n ]).pop(package_name, {})\n\n # Combine all conditional packages so we can easily index over a flat list\n # TODO: Perhaps this should actually return select statements and maintain\n # the conditionals of the dependencies\n flat_deps = {}\n for deps_set in dependencies.values():\n for crate_name, crate_label in deps_set.items():\n flat_deps.update({crate_name: crate_label})\n\n missing_crates = []\n crate_targets = []\n for crate_target in deps:\n if crate_target not in flat_deps:\n missing_crates.append(crate_target)\n else:\n crate_targets.append(flat_deps[crate_target])\n\n if missing_crates:\n fail(\"Could not find crates `{}` among dependencies of `{}`. Available dependencies were `{}`\".format(\n missing_crates,\n package_name,\n dependencies,\n ))\n\n return crate_targets\n\ndef crate_edition(package_name = None):\n \"\"\"Finds the Rust edition for the package where this macro is called.\n\n Args:\n package_name (str, optional): The package name whose edition should be\n looked up. Defaults to `native.package_name()` when unset.\n\n Returns:\n str: The Rust edition declared by the package's Cargo.toml file.\n \"\"\"\n if package_name == None:\n package_name = native.package_name()\n\n if package_name not in _CRATE_EDITIONS:\n fail(\"Tried to get crate_edition for package \" + package_name + \" but that package had no Cargo.toml file\")\n\n return _CRATE_EDITIONS[package_name]\n\ndef all_crate_deps(\n normal = False, \n normal_dev = False, \n proc_macro = False, \n proc_macro_dev = False,\n build = False,\n build_proc_macro = False,\n package_name = None):\n \"\"\"Finds the fully qualified label of all requested direct crate dependencies \\\n for the package where this macro is called.\n\n If no parameters are set, all normal dependencies are returned. Setting any one flag will\n otherwise impact the contents of the returned list.\n\n Args:\n normal (bool, optional): If True, normal dependencies are included in the\n output list.\n normal_dev (bool, optional): If True, normal dev dependencies will be\n included in the output list.\n proc_macro (bool, optional): If True, proc_macro dependencies are included\n in the output list.\n proc_macro_dev (bool, optional): If True, dev proc_macro dependencies are\n included in the output list.\n build (bool, optional): If True, build dependencies are included\n in the output list.\n build_proc_macro (bool, optional): If True, build proc_macro dependencies are\n included in the output list.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()` when unset.\n\n Returns:\n list: A list of labels to generated rust targets (str)\n \"\"\"\n\n if package_name == None:\n package_name = native.package_name()\n\n # Determine the relevant maps to use\n all_dependency_maps = []\n if normal:\n all_dependency_maps.append(_NORMAL_DEPENDENCIES)\n if normal_dev:\n all_dependency_maps.append(_NORMAL_DEV_DEPENDENCIES)\n if proc_macro:\n all_dependency_maps.append(_PROC_MACRO_DEPENDENCIES)\n if proc_macro_dev:\n all_dependency_maps.append(_PROC_MACRO_DEV_DEPENDENCIES)\n if build:\n all_dependency_maps.append(_BUILD_DEPENDENCIES)\n if build_proc_macro:\n all_dependency_maps.append(_BUILD_PROC_MACRO_DEPENDENCIES)\n\n # Default to always using normal dependencies\n if not all_dependency_maps:\n all_dependency_maps.append(_NORMAL_DEPENDENCIES)\n\n dependencies = _flatten_dependency_maps(all_dependency_maps).pop(package_name, None)\n\n if not dependencies:\n if dependencies == None:\n fail(\"Tried to get all_crate_deps for package \" + package_name + \" but that package had no Cargo.toml file\")\n else:\n return []\n\n crate_deps = list(dependencies.pop(_COMMON_CONDITION, {}).values())\n for condition, deps in dependencies.items():\n crate_deps += selects.with_or({\n tuple(_CONDITIONS[condition]): deps.values(),\n \"//conditions:default\": [],\n })\n\n return crate_deps\n\ndef aliases(\n normal = False,\n normal_dev = False,\n proc_macro = False,\n proc_macro_dev = False,\n build = False,\n build_proc_macro = False,\n package_name = None):\n \"\"\"Produces a map of Crate alias names to their original label\n\n If no dependency kinds are specified, `normal` and `proc_macro` are used by default.\n Setting any one flag will otherwise determine the contents of the returned dict.\n\n Args:\n normal (bool, optional): If True, normal dependencies are included in the\n output list.\n normal_dev (bool, optional): If True, normal dev dependencies will be\n included in the output list..\n proc_macro (bool, optional): If True, proc_macro dependencies are included\n in the output list.\n proc_macro_dev (bool, optional): If True, dev proc_macro dependencies are\n included in the output list.\n build (bool, optional): If True, build dependencies are included\n in the output list.\n build_proc_macro (bool, optional): If True, build proc_macro dependencies are\n included in the output list.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()` when unset.\n\n Returns:\n dict: The aliases of all associated packages\n \"\"\"\n if package_name == None:\n package_name = native.package_name()\n\n # Determine the relevant maps to use\n all_aliases_maps = []\n if normal:\n all_aliases_maps.append(_NORMAL_ALIASES)\n if normal_dev:\n all_aliases_maps.append(_NORMAL_DEV_ALIASES)\n if proc_macro:\n all_aliases_maps.append(_PROC_MACRO_ALIASES)\n if proc_macro_dev:\n all_aliases_maps.append(_PROC_MACRO_DEV_ALIASES)\n if build:\n all_aliases_maps.append(_BUILD_ALIASES)\n if build_proc_macro:\n all_aliases_maps.append(_BUILD_PROC_MACRO_ALIASES)\n\n # Default to always using normal aliases\n if not all_aliases_maps:\n all_aliases_maps.append(_NORMAL_ALIASES)\n all_aliases_maps.append(_PROC_MACRO_ALIASES)\n\n aliases = _flatten_dependency_maps(all_aliases_maps).pop(package_name, None)\n\n if not aliases:\n return dict()\n\n common_items = aliases.pop(_COMMON_CONDITION, {}).items()\n\n # If there are only common items in the dictionary, immediately return them\n if not len(aliases.keys()) == 1:\n return dict(common_items)\n\n # Build a single select statement where each conditional has accounted for the\n # common set of aliases.\n crate_aliases = {\"//conditions:default\": dict(common_items)}\n for condition, deps in aliases.items():\n condition_triples = _CONDITIONS[condition]\n for triple in condition_triples:\n if triple in crate_aliases:\n crate_aliases[triple].update(deps)\n else:\n crate_aliases.update({triple: dict(deps.items() + common_items)})\n\n return select(crate_aliases)\n\n###############################################################################\n# WORKSPACE MEMBER DEPS, ALIASES, AND EDITIONS\n###############################################################################\n\n_CRATE_EDITIONS = {\n \"wasmer-js\": \"2021\",\n}\n\n_NORMAL_DEPENDENCIES = {\n \"wasmer-js\": {\n _COMMON_CONDITION: {\n \"anyhow\": Label(\"@browser_cargo//anyhow-1.0.97\"),\n \"bincode\": Label(\"@browser_cargo//bincode-1.3.3\"),\n \"bytes\": Label(\"@browser_cargo//bytes-1.10.1\"),\n \"console_error_panic_hook\": Label(\"@browser_cargo//console_error_panic_hook-0.1.7\"),\n \"futures\": Label(\"@browser_cargo//futures-0.3.30\"),\n \"instant\": Label(\"@browser_cargo//instant-0.1.12\"),\n \"js-sys\": Label(\"@browser_cargo//js-sys-0.3.78\"),\n \"lazy_static\": Label(\"@browser_cargo//lazy_static-1.5.0\"),\n \"once_cell\": Label(\"@browser_cargo//once_cell-1.19.0\"),\n \"reqwest\": Label(\"@browser_cargo//reqwest-0.12.7\"),\n \"serde\": Label(\"@browser_cargo//serde-1.0.219\"),\n \"serde-wasm-bindgen\": Label(\"@browser_cargo//serde-wasm-bindgen-0.6.5\"),\n \"sha2\": Label(\"@browser_cargo//sha2-0.10.8\"),\n \"tempfile\": Label(\"@browser_cargo//tempfile-3.12.0\"),\n \"tokio\": Label(\"@browser_cargo//tokio-1.44.2\"),\n \"toml\": Label(\"@browser_cargo//toml-0.8.14\"),\n \"tracing\": Label(\"@browser_cargo//tracing-0.1.41\"),\n \"tracing-subscriber\": Label(\"@browser_cargo//tracing-subscriber-0.3.18\"),\n \"url\": Label(\"@browser_cargo//url-2.5.4\"),\n \"virtual-fs\": Label(\"@browser_cargo//virtual-fs-0.601.0\"),\n \"virtual-net\": Label(\"@browser_cargo//virtual-net-0.601.0\"),\n \"wasm-bindgen\": Label(\"@browser_cargo//wasm-bindgen-0.2.101\"),\n \"wasm-bindgen-derive\": Label(\"@browser_cargo//wasm-bindgen-derive-0.2.1\"),\n \"wasm-bindgen-futures\": Label(\"@browser_cargo//wasm-bindgen-futures-0.4.51\"),\n \"wasm-bindgen-test\": Label(\"@browser_cargo//wasm-bindgen-test-0.3.51\"),\n \"wasmer\": Label(\"@browser_cargo//wasmer-6.1.0\"),\n \"wasmer-backend-api\": Label(\"@browser_cargo//wasmer-backend-api-0.601.0\"),\n \"wasmer-config\": Label(\"@browser_cargo//wasmer-config-0.601.0\"),\n \"wasmer-package\": Label(\"@browser_cargo//wasmer-package-0.601.0\"),\n \"wasmer-types\": Label(\"@browser_cargo//wasmer-types-6.1.0\"),\n \"wasmer-wasix\": Label(\"@browser_cargo//wasmer-wasix-0.601.0\"),\n \"web-sys\": Label(\"@browser_cargo//web-sys-0.3.78\"),\n \"webc\": Label(\"@browser_cargo//webc-10.0.1\"),\n },\n },\n}\n\n\n_NORMAL_ALIASES = {\n \"wasmer-js\": {\n _COMMON_CONDITION: {\n },\n },\n}\n\n\n_NORMAL_DEV_DEPENDENCIES = {\n \"wasmer-js\": {\n },\n}\n\n\n_NORMAL_DEV_ALIASES = {\n \"wasmer-js\": {\n },\n}\n\n\n_PROC_MACRO_DEPENDENCIES = {\n \"wasmer-js\": {\n _COMMON_CONDITION: {\n \"async-trait\": Label(\"@browser_cargo//async-trait-0.1.88\"),\n \"derivative\": Label(\"@browser_cargo//derivative-2.2.0\"),\n },\n },\n}\n\n\n_PROC_MACRO_ALIASES = {\n \"wasmer-js\": {\n },\n}\n\n\n_PROC_MACRO_DEV_DEPENDENCIES = {\n \"wasmer-js\": {\n },\n}\n\n\n_PROC_MACRO_DEV_ALIASES = {\n \"wasmer-js\": {\n },\n}\n\n\n_BUILD_DEPENDENCIES = {\n \"wasmer-js\": {\n },\n}\n\n\n_BUILD_ALIASES = {\n \"wasmer-js\": {\n },\n}\n\n\n_BUILD_PROC_MACRO_DEPENDENCIES = {\n \"wasmer-js\": {\n },\n}\n\n\n_BUILD_PROC_MACRO_ALIASES = {\n \"wasmer-js\": {\n },\n}\n\n\n_CONDITIONS = {\n \"aarch64-linux-android\": [],\n \"aarch64-pc-windows-gnullvm\": [],\n \"cfg(all(any(target_arch = \\\"x86_64\\\", target_arch = \\\"arm64ec\\\"), target_env = \\\"msvc\\\", not(windows_raw_dylib)))\": [],\n \"cfg(all(any(target_os = \\\"android\\\", target_os = \\\"linux\\\"), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", target_endian = \\\"little\\\", any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\": [],\n \"cfg(all(any(target_os = \\\"android\\\", target_os = \\\"linux\\\"), any(target_arch = \\\"aarch64\\\", target_arch = \\\"arm\\\")))\": [],\n \"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", target_endian = \\\"little\\\", any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(all(not(target_arch = \\\"wasm32\\\"), target_os = \\\"windows\\\"))\": [],\n \"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", target_endian = \\\"little\\\", any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\": [\"@rules_rust//rust/platform:wasm32-unknown-unknown\"],\n \"cfg(all(target_arch = \\\"aarch64\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\": [],\n \"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"linux\\\"))\": [],\n \"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"windows\\\"))\": [],\n \"cfg(all(target_arch = \\\"aarch64\\\", target_vendor = \\\"apple\\\"))\": [],\n \"cfg(all(target_arch = \\\"loongarch64\\\", target_os = \\\"linux\\\"))\": [],\n \"cfg(all(target_arch = \\\"wasm32\\\", wasm_bindgen_unstable_test_coverage))\": [],\n \"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"gnu\\\", not(target_abi = \\\"llvm\\\"), not(windows_raw_dylib)))\": [],\n \"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"gnu\\\", not(windows_raw_dylib)))\": [],\n \"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\": [],\n \"cfg(all(target_arch = \\\"x86_64\\\", target_env = \\\"gnu\\\", not(target_abi = \\\"llvm\\\"), not(windows_raw_dylib)))\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(all(target_arch = \\\"x86_64\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\": [],\n \"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\"))\": [\"@rules_rust//rust/platform:wasm32-unknown-unknown\"],\n \"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"wasi\\\"))\": [],\n \"cfg(all(target_os = \\\"macos\\\", target_arch = \\\"aarch64\\\"))\": [],\n \"cfg(all(unix, not(target_os = \\\"ios\\\")))\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any())\": [],\n \"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"arm\\\", target_arch = \\\"x86\\\", target_arch = \\\"x86_64\\\"))\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(target_family = \\\"unix\\\", all(target_family = \\\"windows\\\", target_env = \\\"gnu\\\")))\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(target_os = \\\"macos\\\", target_os = \\\"freebsd\\\", target_os = \\\"netbsd\\\"))\": [],\n \"cfg(any(target_os = \\\"macos\\\", target_os = \\\"ios\\\"))\": [],\n \"cfg(any(unix, target_os = \\\"wasi\\\"))\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(not(all(target_arch = \\\"arm\\\", target_os = \\\"none\\\")))\": [\"@rules_rust//rust/platform:wasm32-unknown-unknown\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(not(all(windows, target_env = \\\"msvc\\\", not(target_vendor = \\\"uwp\\\"))))\": [\"@rules_rust//rust/platform:wasm32-unknown-unknown\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(not(any(target_os = \\\"windows\\\", target_vendor = \\\"apple\\\")))\": [\"@rules_rust//rust/platform:wasm32-unknown-unknown\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(not(target_arch = \\\"wasm32\\\"))\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(not(target_env = \\\"musl\\\"))\": [\"@rules_rust//rust/platform:wasm32-unknown-unknown\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(not(windows))\": [\"@rules_rust//rust/platform:wasm32-unknown-unknown\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(target_arch = \\\"spirv\\\")\": [],\n \"cfg(target_arch = \\\"wasm32\\\")\": [\"@rules_rust//rust/platform:wasm32-unknown-unknown\"],\n \"cfg(target_env = \\\"musl\\\")\": [],\n \"cfg(target_family = \\\"wasm\\\")\": [\"@rules_rust//rust/platform:wasm32-unknown-unknown\"],\n \"cfg(target_os = \\\"android\\\")\": [],\n \"cfg(target_os = \\\"haiku\\\")\": [],\n \"cfg(target_os = \\\"hermit\\\")\": [],\n \"cfg(target_os = \\\"linux\\\")\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(target_os = \\\"macos\\\")\": [],\n \"cfg(target_os = \\\"redox\\\")\": [],\n \"cfg(target_os = \\\"wasi\\\")\": [],\n \"cfg(target_os = \\\"windows\\\")\": [],\n \"cfg(target_vendor = \\\"apple\\\")\": [],\n \"cfg(tokio_taskdump)\": [],\n \"cfg(unix)\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(windows)\": [],\n \"i686-pc-windows-gnu\": [],\n \"i686-pc-windows-gnullvm\": [],\n \"wasm32-unknown-unknown\": [\"@rules_rust//rust/platform:wasm32-unknown-unknown\"],\n \"x86_64-pc-windows-gnu\": [],\n \"x86_64-pc-windows-gnullvm\": [],\n \"x86_64-unknown-linux-gnu\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n}\n\n###############################################################################\n\ndef crate_repositories():\n \"\"\"A macro for defining repositories for all generated crates.\n\n Returns:\n A list of repos visible to the module through the module extension.\n \"\"\"\n maybe(\n crates_vendor_remote_repository,\n name = \"browser_cargo\",\n # Lean interface: just point at `crates.bzl`; the repo rule\n # derives the sibling `BUILD.bazel` and `defs.bzl`.\n crates_module = Label(\"@browser_cargo//browser_cargo:crates.bzl\"),\n )\n maybe(\n http_archive,\n name = \"browser_cargo__addr2line-0.21.0\",\n sha256 = \"8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/addr2line/0.21.0/download\"],\n strip_prefix = \"addr2line-0.21.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.addr2line-0.21.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__adler-1.0.2\",\n sha256 = \"f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/adler/1.0.2/download\"],\n strip_prefix = \"adler-1.0.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.adler-1.0.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__adler2-2.0.0\",\n sha256 = \"512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/adler2/2.0.0/download\"],\n strip_prefix = \"adler2-2.0.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.adler2-2.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__ahash-0.8.11\",\n sha256 = \"e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ahash/0.8.11/download\"],\n strip_prefix = \"ahash-0.8.11\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.ahash-0.8.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__aho-corasick-1.1.2\",\n sha256 = \"b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/aho-corasick/1.1.2/download\"],\n strip_prefix = \"aho-corasick-1.1.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.aho-corasick-1.1.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__aliasable-0.1.3\",\n sha256 = \"250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/aliasable/0.1.3/download\"],\n strip_prefix = \"aliasable-0.1.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.aliasable-0.1.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__android-tzdata-0.1.1\",\n sha256 = \"e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/android-tzdata/0.1.1/download\"],\n strip_prefix = \"android-tzdata-0.1.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.android-tzdata-0.1.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__android_system_properties-0.1.5\",\n sha256 = \"819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/android_system_properties/0.1.5/download\"],\n strip_prefix = \"android_system_properties-0.1.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.android_system_properties-0.1.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__any_ascii-0.1.7\",\n sha256 = \"70033777eb8b5124a81a1889416543dddef2de240019b674c81285a2635a7e1e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/any_ascii/0.1.7/download\"],\n strip_prefix = \"any_ascii-0.1.7\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.any_ascii-0.1.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__anyhow-1.0.97\",\n sha256 = \"dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/anyhow/1.0.97/download\"],\n strip_prefix = \"anyhow-1.0.97\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.anyhow-1.0.97.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__arrayref-0.3.7\",\n sha256 = \"6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/arrayref/0.3.7/download\"],\n strip_prefix = \"arrayref-0.3.7\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.arrayref-0.3.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__arrayvec-0.7.4\",\n sha256 = \"96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/arrayvec/0.7.4/download\"],\n strip_prefix = \"arrayvec-0.7.4\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.arrayvec-0.7.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__async-trait-0.1.88\",\n sha256 = \"e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/async-trait/0.1.88/download\"],\n strip_prefix = \"async-trait-0.1.88\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.async-trait-0.1.88.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__atomic-waker-1.1.2\",\n sha256 = \"1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/atomic-waker/1.1.2/download\"],\n strip_prefix = \"atomic-waker-1.1.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.atomic-waker-1.1.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__autocfg-1.1.0\",\n sha256 = \"d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/autocfg/1.1.0/download\"],\n strip_prefix = \"autocfg-1.1.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.autocfg-1.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__backtrace-0.3.69\",\n sha256 = \"2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/backtrace/0.3.69/download\"],\n strip_prefix = \"backtrace-0.3.69\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.backtrace-0.3.69.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__base64-0.22.1\",\n sha256 = \"72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/base64/0.22.1/download\"],\n strip_prefix = \"base64-0.22.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.base64-0.22.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__beef-0.5.2\",\n sha256 = \"3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/beef/0.5.2/download\"],\n strip_prefix = \"beef-0.5.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.beef-0.5.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__bincode-1.3.3\",\n sha256 = \"b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bincode/1.3.3/download\"],\n strip_prefix = \"bincode-1.3.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.bincode-1.3.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__bindgen-0.70.1\",\n sha256 = \"f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bindgen/0.70.1/download\"],\n strip_prefix = \"bindgen-0.70.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.bindgen-0.70.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__bitflags-1.3.2\",\n sha256 = \"bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bitflags/1.3.2/download\"],\n strip_prefix = \"bitflags-1.3.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.bitflags-1.3.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__bitflags-2.9.0\",\n sha256 = \"5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bitflags/2.9.0/download\"],\n strip_prefix = \"bitflags-2.9.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.bitflags-2.9.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__blake3-1.5.1\",\n sha256 = \"30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/blake3/1.5.1/download\"],\n strip_prefix = \"blake3-1.5.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.blake3-1.5.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__block-buffer-0.10.4\",\n sha256 = \"3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/block-buffer/0.10.4/download\"],\n strip_prefix = \"block-buffer-0.10.4\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.block-buffer-0.10.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__bstr-1.9.1\",\n sha256 = \"05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bstr/1.9.1/download\"],\n strip_prefix = \"bstr-1.9.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.bstr-1.9.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__bumpalo-3.14.0\",\n sha256 = \"7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bumpalo/3.14.0/download\"],\n strip_prefix = \"bumpalo-3.14.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.bumpalo-3.14.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__bus-2.4.1\",\n sha256 = \"4b7118d0221d84fada881b657c2ddb7cd55108db79c8764c9ee212c0c259b783\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bus/2.4.1/download\"],\n strip_prefix = \"bus-2.4.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.bus-2.4.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__bytecheck-0.6.11\",\n sha256 = \"8b6372023ac861f6e6dc89c8344a8f398fb42aaba2b5dbc649ca0c0e9dbcb627\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bytecheck/0.6.11/download\"],\n strip_prefix = \"bytecheck-0.6.11\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.bytecheck-0.6.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__bytecheck-0.8.1\",\n sha256 = \"50690fb3370fb9fe3550372746084c46f2ac8c9685c583d2be10eefd89d3d1a3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bytecheck/0.8.1/download\"],\n strip_prefix = \"bytecheck-0.8.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.bytecheck-0.8.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__bytecheck_derive-0.6.11\",\n sha256 = \"a7ec4c6f261935ad534c0c22dbef2201b45918860eb1c574b972bd213a76af61\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bytecheck_derive/0.6.11/download\"],\n strip_prefix = \"bytecheck_derive-0.6.11\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.bytecheck_derive-0.6.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__bytecheck_derive-0.8.1\",\n sha256 = \"efb7846e0cb180355c2dec69e721edafa36919850f1a9f52ffba4ebc0393cb71\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bytecheck_derive/0.8.1/download\"],\n strip_prefix = \"bytecheck_derive-0.8.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.bytecheck_derive-0.8.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__byteorder-1.5.0\",\n sha256 = \"1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/byteorder/1.5.0/download\"],\n strip_prefix = \"byteorder-1.5.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.byteorder-1.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__bytes-1.10.1\",\n sha256 = \"d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bytes/1.10.1/download\"],\n strip_prefix = \"bytes-1.10.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.bytes-1.10.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__bytesize-1.3.0\",\n sha256 = \"a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bytesize/1.3.0/download\"],\n strip_prefix = \"bytesize-1.3.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.bytesize-1.3.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__cc-1.2.18\",\n sha256 = \"525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cc/1.2.18/download\"],\n strip_prefix = \"cc-1.2.18\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.cc-1.2.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__cexpr-0.6.0\",\n sha256 = \"6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cexpr/0.6.0/download\"],\n strip_prefix = \"cexpr-0.6.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.cexpr-0.6.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__cfg-if-1.0.0\",\n sha256 = \"baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cfg-if/1.0.0/download\"],\n strip_prefix = \"cfg-if-1.0.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.cfg-if-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__chrono-0.4.40\",\n sha256 = \"1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/chrono/0.4.40/download\"],\n strip_prefix = \"chrono-0.4.40\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.chrono-0.4.40.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__ciborium-0.2.2\",\n sha256 = \"42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ciborium/0.2.2/download\"],\n strip_prefix = \"ciborium-0.2.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.ciborium-0.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__ciborium-io-0.2.2\",\n sha256 = \"05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ciborium-io/0.2.2/download\"],\n strip_prefix = \"ciborium-io-0.2.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.ciborium-io-0.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__ciborium-ll-0.2.2\",\n sha256 = \"57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ciborium-ll/0.2.2/download\"],\n strip_prefix = \"ciborium-ll-0.2.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.ciborium-ll-0.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__clang-sys-1.8.1\",\n sha256 = \"0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/clang-sys/1.8.1/download\"],\n strip_prefix = \"clang-sys-1.8.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.clang-sys-1.8.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__cmake-0.1.54\",\n sha256 = \"e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cmake/0.1.54/download\"],\n strip_prefix = \"cmake-0.1.54\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.cmake-0.1.54.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__console-0.15.11\",\n sha256 = \"054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/console/0.15.11/download\"],\n strip_prefix = \"console-0.15.11\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.console-0.15.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__console_error_panic_hook-0.1.7\",\n sha256 = \"a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/console_error_panic_hook/0.1.7/download\"],\n strip_prefix = \"console_error_panic_hook-0.1.7\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.console_error_panic_hook-0.1.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__constant_time_eq-0.3.0\",\n sha256 = \"f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/constant_time_eq/0.3.0/download\"],\n strip_prefix = \"constant_time_eq-0.3.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.constant_time_eq-0.3.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__cooked-waker-5.0.0\",\n sha256 = \"147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cooked-waker/5.0.0/download\"],\n strip_prefix = \"cooked-waker-5.0.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.cooked-waker-5.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__core-foundation-0.9.4\",\n sha256 = \"91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/core-foundation/0.9.4/download\"],\n strip_prefix = \"core-foundation-0.9.4\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.core-foundation-0.9.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__core-foundation-sys-0.8.7\",\n sha256 = \"773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/core-foundation-sys/0.8.7/download\"],\n strip_prefix = \"core-foundation-sys-0.8.7\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.core-foundation-sys-0.8.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__corosensei-0.3.0\",\n sha256 = \"878ba85678ef5d34ffe1b5da981b0828232b4c7f2726b20984f59c7e79f6d514\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/corosensei/0.3.0/download\"],\n strip_prefix = \"corosensei-0.3.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.corosensei-0.3.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__cpufeatures-0.2.12\",\n sha256 = \"53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cpufeatures/0.2.12/download\"],\n strip_prefix = \"cpufeatures-0.2.12\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.cpufeatures-0.2.12.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__crc32fast-1.3.2\",\n sha256 = \"b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crc32fast/1.3.2/download\"],\n strip_prefix = \"crc32fast-1.3.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.crc32fast-1.3.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__crossbeam-channel-0.5.15\",\n sha256 = \"82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crossbeam-channel/0.5.15/download\"],\n strip_prefix = \"crossbeam-channel-0.5.15\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.crossbeam-channel-0.5.15.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__crossbeam-deque-0.8.5\",\n sha256 = \"613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crossbeam-deque/0.8.5/download\"],\n strip_prefix = \"crossbeam-deque-0.8.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.crossbeam-deque-0.8.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__crossbeam-epoch-0.9.18\",\n sha256 = \"5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crossbeam-epoch/0.9.18/download\"],\n strip_prefix = \"crossbeam-epoch-0.9.18\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.crossbeam-epoch-0.9.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__crossbeam-queue-0.3.11\",\n sha256 = \"df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crossbeam-queue/0.3.11/download\"],\n strip_prefix = \"crossbeam-queue-0.3.11\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.crossbeam-queue-0.3.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__crossbeam-utils-0.8.19\",\n sha256 = \"248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crossbeam-utils/0.8.19/download\"],\n strip_prefix = \"crossbeam-utils-0.8.19\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.crossbeam-utils-0.8.19.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__crunchy-0.2.2\",\n sha256 = \"7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crunchy/0.2.2/download\"],\n strip_prefix = \"crunchy-0.2.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.crunchy-0.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__crypto-common-0.1.6\",\n sha256 = \"1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crypto-common/0.1.6/download\"],\n strip_prefix = \"crypto-common-0.1.6\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.crypto-common-0.1.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__cynic-3.10.0\",\n sha256 = \"c99c59968c8aa7f90d84240ab6ded4d3864125ce36b5b044554542cebc974946\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cynic/3.10.0/download\"],\n strip_prefix = \"cynic-3.10.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.cynic-3.10.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__cynic-codegen-3.10.0\",\n sha256 = \"332695dddff7f260dfda1e97502b6440d443816f576994548b7751494991d2e3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cynic-codegen/3.10.0/download\"],\n strip_prefix = \"cynic-codegen-3.10.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.cynic-codegen-3.10.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__cynic-parser-0.9.1\",\n sha256 = \"cbb0f21f2f8d3134c2e887a16564c165694231f48b6ae2769193299081ecf662\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cynic-parser/0.9.1/download\"],\n strip_prefix = \"cynic-parser-0.9.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.cynic-parser-0.9.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__cynic-proc-macros-3.10.0\",\n sha256 = \"a7880789c425a73aff3ba286b2a9c794f330d4770769a42a1493d6175e4606c1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cynic-proc-macros/3.10.0/download\"],\n strip_prefix = \"cynic-proc-macros-3.10.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.cynic-proc-macros-3.10.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__darling-0.14.4\",\n sha256 = \"7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/darling/0.14.4/download\"],\n strip_prefix = \"darling-0.14.4\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.darling-0.14.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__darling-0.20.3\",\n sha256 = \"0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/darling/0.20.3/download\"],\n strip_prefix = \"darling-0.20.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.darling-0.20.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__darling_core-0.14.4\",\n sha256 = \"109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/darling_core/0.14.4/download\"],\n strip_prefix = \"darling_core-0.14.4\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.darling_core-0.14.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__darling_core-0.20.3\",\n sha256 = \"177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/darling_core/0.20.3/download\"],\n strip_prefix = \"darling_core-0.20.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.darling_core-0.20.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__darling_macro-0.14.4\",\n sha256 = \"a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/darling_macro/0.14.4/download\"],\n strip_prefix = \"darling_macro-0.14.4\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.darling_macro-0.14.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__darling_macro-0.20.3\",\n sha256 = \"836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/darling_macro/0.20.3/download\"],\n strip_prefix = \"darling_macro-0.20.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.darling_macro-0.20.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__dashmap-6.1.0\",\n sha256 = \"5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/dashmap/6.1.0/download\"],\n strip_prefix = \"dashmap-6.1.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.dashmap-6.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__deranged-0.3.11\",\n sha256 = \"b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/deranged/0.3.11/download\"],\n strip_prefix = \"deranged-0.3.11\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.deranged-0.3.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__derivative-2.2.0\",\n sha256 = \"fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/derivative/2.2.0/download\"],\n strip_prefix = \"derivative-2.2.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.derivative-2.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__derive_builder-0.12.0\",\n sha256 = \"8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/derive_builder/0.12.0/download\"],\n strip_prefix = \"derive_builder-0.12.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.derive_builder-0.12.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__derive_builder_core-0.12.0\",\n sha256 = \"c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/derive_builder_core/0.12.0/download\"],\n strip_prefix = \"derive_builder_core-0.12.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.derive_builder_core-0.12.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__derive_builder_macro-0.12.0\",\n sha256 = \"ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/derive_builder_macro/0.12.0/download\"],\n strip_prefix = \"derive_builder_macro-0.12.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.derive_builder_macro-0.12.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__derive_more-0.99.19\",\n sha256 = \"3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/derive_more/0.99.19/download\"],\n strip_prefix = \"derive_more-0.99.19\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.derive_more-0.99.19.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__derive_more-2.0.1\",\n sha256 = \"093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/derive_more/2.0.1/download\"],\n strip_prefix = \"derive_more-2.0.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.derive_more-2.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__derive_more-impl-2.0.1\",\n sha256 = \"bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/derive_more-impl/2.0.1/download\"],\n strip_prefix = \"derive_more-impl-2.0.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.derive_more-impl-2.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__digest-0.10.7\",\n sha256 = \"9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/digest/0.10.7/download\"],\n strip_prefix = \"digest-0.10.7\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.digest-0.10.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__displaydoc-0.2.5\",\n sha256 = \"97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/displaydoc/0.2.5/download\"],\n strip_prefix = \"displaydoc-0.2.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.displaydoc-0.2.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__document-features-0.2.8\",\n sha256 = \"ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/document-features/0.2.8/download\"],\n strip_prefix = \"document-features-0.2.8\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.document-features-0.2.8.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__dunce-1.0.5\",\n sha256 = \"92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/dunce/1.0.5/download\"],\n strip_prefix = \"dunce-1.0.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.dunce-1.0.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__dyn-clone-1.0.17\",\n sha256 = \"0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/dyn-clone/1.0.17/download\"],\n strip_prefix = \"dyn-clone-1.0.17\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.dyn-clone-1.0.17.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__educe-0.5.11\",\n sha256 = \"e4bd92664bf78c4d3dba9b7cdafce6fa15b13ed3ed16175218196942e99168a8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/educe/0.5.11/download\"],\n strip_prefix = \"educe-0.5.11\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.educe-0.5.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__either-1.13.0\",\n sha256 = \"60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/either/1.13.0/download\"],\n strip_prefix = \"either-1.13.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.either-1.13.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__encode_unicode-1.0.0\",\n sha256 = \"34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/encode_unicode/1.0.0/download\"],\n strip_prefix = \"encode_unicode-1.0.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.encode_unicode-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__encoding_rs-0.8.34\",\n sha256 = \"b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/encoding_rs/0.8.34/download\"],\n strip_prefix = \"encoding_rs-0.8.34\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.encoding_rs-0.8.34.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__enum-iterator-0.7.0\",\n sha256 = \"4eeac5c5edb79e4e39fe8439ef35207780a11f69c52cbe424ce3dfad4cb78de6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/enum-iterator/0.7.0/download\"],\n strip_prefix = \"enum-iterator-0.7.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.enum-iterator-0.7.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__enum-iterator-derive-0.7.0\",\n sha256 = \"c134c37760b27a871ba422106eedbb8247da973a09e82558bf26d619c882b159\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/enum-iterator-derive/0.7.0/download\"],\n strip_prefix = \"enum-iterator-derive-0.7.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.enum-iterator-derive-0.7.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__enum-ordinalize-4.3.2\",\n sha256 = \"4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/enum-ordinalize/4.3.2/download\"],\n strip_prefix = \"enum-ordinalize-4.3.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.enum-ordinalize-4.3.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__enum-ordinalize-derive-4.3.2\",\n sha256 = \"8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/enum-ordinalize-derive/4.3.2/download\"],\n strip_prefix = \"enum-ordinalize-derive-4.3.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.enum-ordinalize-derive-4.3.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__enumset-1.1.3\",\n sha256 = \"226c0da7462c13fb57e5cc9e0dc8f0635e7d27f276a3a7fd30054647f669007d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/enumset/1.1.3/download\"],\n strip_prefix = \"enumset-1.1.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.enumset-1.1.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__enumset_derive-0.8.1\",\n sha256 = \"e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/enumset_derive/0.8.1/download\"],\n strip_prefix = \"enumset_derive-0.8.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.enumset_derive-0.8.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__equivalent-1.0.1\",\n sha256 = \"5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/equivalent/1.0.1/download\"],\n strip_prefix = \"equivalent-1.0.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.equivalent-1.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__errno-0.3.8\",\n sha256 = \"a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/errno/0.3.8/download\"],\n strip_prefix = \"errno-0.3.8\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.errno-0.3.8.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__fastrand-2.0.1\",\n sha256 = \"25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/fastrand/2.0.1/download\"],\n strip_prefix = \"fastrand-2.0.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.fastrand-2.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__filetime-0.2.23\",\n sha256 = \"1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/filetime/0.2.23/download\"],\n strip_prefix = \"filetime-0.2.23\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.filetime-0.2.23.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__fixedbitset-0.5.7\",\n sha256 = \"1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/fixedbitset/0.5.7/download\"],\n strip_prefix = \"fixedbitset-0.5.7\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.fixedbitset-0.5.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__flate2-1.1.1\",\n sha256 = \"7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/flate2/1.1.1/download\"],\n strip_prefix = \"flate2-1.1.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.flate2-1.1.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__fnv-1.0.7\",\n sha256 = \"3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/fnv/1.0.7/download\"],\n strip_prefix = \"fnv-1.0.7\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.fnv-1.0.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__foreign-types-0.3.2\",\n sha256 = \"f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/foreign-types/0.3.2/download\"],\n strip_prefix = \"foreign-types-0.3.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.foreign-types-0.3.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__foreign-types-shared-0.1.1\",\n sha256 = \"00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/foreign-types-shared/0.1.1/download\"],\n strip_prefix = \"foreign-types-shared-0.1.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.foreign-types-shared-0.1.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__form_urlencoded-1.2.1\",\n sha256 = \"e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/form_urlencoded/1.2.1/download\"],\n strip_prefix = \"form_urlencoded-1.2.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.form_urlencoded-1.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__futures-0.3.30\",\n sha256 = \"645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures/0.3.30/download\"],\n strip_prefix = \"futures-0.3.30\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.futures-0.3.30.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__futures-channel-0.3.31\",\n sha256 = \"2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-channel/0.3.31/download\"],\n strip_prefix = \"futures-channel-0.3.31\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.futures-channel-0.3.31.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__futures-core-0.3.31\",\n sha256 = \"05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-core/0.3.31/download\"],\n strip_prefix = \"futures-core-0.3.31\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.futures-core-0.3.31.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__futures-executor-0.3.30\",\n sha256 = \"a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-executor/0.3.30/download\"],\n strip_prefix = \"futures-executor-0.3.30\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.futures-executor-0.3.30.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__futures-io-0.3.31\",\n sha256 = \"9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-io/0.3.31/download\"],\n strip_prefix = \"futures-io-0.3.31\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.futures-io-0.3.31.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__futures-macro-0.3.31\",\n sha256 = \"162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-macro/0.3.31/download\"],\n strip_prefix = \"futures-macro-0.3.31\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.futures-macro-0.3.31.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__futures-sink-0.3.31\",\n sha256 = \"e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-sink/0.3.31/download\"],\n strip_prefix = \"futures-sink-0.3.31\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.futures-sink-0.3.31.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__futures-task-0.3.31\",\n sha256 = \"f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-task/0.3.31/download\"],\n strip_prefix = \"futures-task-0.3.31\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.futures-task-0.3.31.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__futures-util-0.3.31\",\n sha256 = \"9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-util/0.3.31/download\"],\n strip_prefix = \"futures-util-0.3.31\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.futures-util-0.3.31.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__generic-array-0.14.7\",\n sha256 = \"85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/generic-array/0.14.7/download\"],\n strip_prefix = \"generic-array-0.14.7\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.generic-array-0.14.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__getrandom-0.2.15\",\n sha256 = \"c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/getrandom/0.2.15/download\"],\n strip_prefix = \"getrandom-0.2.15\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.getrandom-0.2.15.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__gimli-0.28.1\",\n sha256 = \"4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/gimli/0.28.1/download\"],\n strip_prefix = \"gimli-0.28.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.gimli-0.28.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__glob-0.3.2\",\n sha256 = \"a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/glob/0.3.2/download\"],\n strip_prefix = \"glob-0.3.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.glob-0.3.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__globset-0.4.14\",\n sha256 = \"57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/globset/0.4.14/download\"],\n strip_prefix = \"globset-0.4.14\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.globset-0.4.14.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__h2-0.4.5\",\n sha256 = \"fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/h2/0.4.5/download\"],\n strip_prefix = \"h2-0.4.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.h2-0.4.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__half-2.4.1\",\n sha256 = \"6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/half/2.4.1/download\"],\n strip_prefix = \"half-2.4.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.half-2.4.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__harsh-0.2.2\",\n sha256 = \"a6fce2283849822530a18d7d8eeb1719ac65a27cfb6649c0dc8dfd2d2cc5edfb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/harsh/0.2.2/download\"],\n strip_prefix = \"harsh-0.2.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.harsh-0.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__hash32-0.3.1\",\n sha256 = \"47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hash32/0.3.1/download\"],\n strip_prefix = \"hash32-0.3.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.hash32-0.3.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__hashbrown-0.14.3\",\n sha256 = \"290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hashbrown/0.14.3/download\"],\n strip_prefix = \"hashbrown-0.14.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.hashbrown-0.14.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__hashbrown-0.15.2\",\n sha256 = \"bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hashbrown/0.15.2/download\"],\n strip_prefix = \"hashbrown-0.15.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.hashbrown-0.15.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__heapless-0.8.0\",\n sha256 = \"0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/heapless/0.8.0/download\"],\n strip_prefix = \"heapless-0.8.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.heapless-0.8.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__heck-0.3.3\",\n sha256 = \"6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/heck/0.3.3/download\"],\n strip_prefix = \"heck-0.3.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.heck-0.3.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__heck-0.4.1\",\n sha256 = \"95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/heck/0.4.1/download\"],\n strip_prefix = \"heck-0.4.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.heck-0.4.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__hermit-abi-0.5.2\",\n sha256 = \"fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hermit-abi/0.5.2/download\"],\n strip_prefix = \"hermit-abi-0.5.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.hermit-abi-0.5.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__hex-0.4.3\",\n sha256 = \"7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hex/0.4.3/download\"],\n strip_prefix = \"hex-0.4.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.hex-0.4.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__http-1.3.1\",\n sha256 = \"f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/http/1.3.1/download\"],\n strip_prefix = \"http-1.3.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.http-1.3.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__http-body-1.0.0\",\n sha256 = \"1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/http-body/1.0.0/download\"],\n strip_prefix = \"http-body-1.0.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.http-body-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__http-body-util-0.1.2\",\n sha256 = \"793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/http-body-util/0.1.2/download\"],\n strip_prefix = \"http-body-util-0.1.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.http-body-util-0.1.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__httparse-1.10.1\",\n sha256 = \"6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/httparse/1.10.1/download\"],\n strip_prefix = \"httparse-1.10.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.httparse-1.10.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__hyper-1.4.0\",\n sha256 = \"c4fe55fb7a772d59a5ff1dfbff4fe0258d19b89fec4b233e75d35d5d2316badc\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hyper/1.4.0/download\"],\n strip_prefix = \"hyper-1.4.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.hyper-1.4.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__hyper-rustls-0.27.2\",\n sha256 = \"5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hyper-rustls/0.27.2/download\"],\n strip_prefix = \"hyper-rustls-0.27.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.hyper-rustls-0.27.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__hyper-tls-0.6.0\",\n sha256 = \"70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hyper-tls/0.6.0/download\"],\n strip_prefix = \"hyper-tls-0.6.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.hyper-tls-0.6.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__hyper-util-0.1.6\",\n sha256 = \"3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hyper-util/0.1.6/download\"],\n strip_prefix = \"hyper-util-0.1.6\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.hyper-util-0.1.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__iana-time-zone-0.1.59\",\n sha256 = \"b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/iana-time-zone/0.1.59/download\"],\n strip_prefix = \"iana-time-zone-0.1.59\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.iana-time-zone-0.1.59.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__iana-time-zone-haiku-0.1.2\",\n sha256 = \"f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/iana-time-zone-haiku/0.1.2/download\"],\n strip_prefix = \"iana-time-zone-haiku-0.1.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.iana-time-zone-haiku-0.1.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__icu_collections-1.5.0\",\n sha256 = \"db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_collections/1.5.0/download\"],\n strip_prefix = \"icu_collections-1.5.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.icu_collections-1.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__icu_locid-1.5.0\",\n sha256 = \"13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_locid/1.5.0/download\"],\n strip_prefix = \"icu_locid-1.5.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.icu_locid-1.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__icu_locid_transform-1.5.0\",\n sha256 = \"01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_locid_transform/1.5.0/download\"],\n strip_prefix = \"icu_locid_transform-1.5.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.icu_locid_transform-1.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__icu_locid_transform_data-1.5.1\",\n sha256 = \"7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_locid_transform_data/1.5.1/download\"],\n strip_prefix = \"icu_locid_transform_data-1.5.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.icu_locid_transform_data-1.5.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__icu_normalizer-1.5.0\",\n sha256 = \"19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_normalizer/1.5.0/download\"],\n strip_prefix = \"icu_normalizer-1.5.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.icu_normalizer-1.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__icu_normalizer_data-1.5.1\",\n sha256 = \"c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_normalizer_data/1.5.1/download\"],\n strip_prefix = \"icu_normalizer_data-1.5.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.icu_normalizer_data-1.5.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__icu_properties-1.5.1\",\n sha256 = \"93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_properties/1.5.1/download\"],\n strip_prefix = \"icu_properties-1.5.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.icu_properties-1.5.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__icu_properties_data-1.5.1\",\n sha256 = \"85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_properties_data/1.5.1/download\"],\n strip_prefix = \"icu_properties_data-1.5.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.icu_properties_data-1.5.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__icu_provider-1.5.0\",\n sha256 = \"6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_provider/1.5.0/download\"],\n strip_prefix = \"icu_provider-1.5.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.icu_provider-1.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__icu_provider_macros-1.5.0\",\n sha256 = \"1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_provider_macros/1.5.0/download\"],\n strip_prefix = \"icu_provider_macros-1.5.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.icu_provider_macros-1.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__id-arena-2.2.1\",\n sha256 = \"25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/id-arena/2.2.1/download\"],\n strip_prefix = \"id-arena-2.2.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.id-arena-2.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__ident_case-1.0.1\",\n sha256 = \"b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ident_case/1.0.1/download\"],\n strip_prefix = \"ident_case-1.0.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.ident_case-1.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__idna-1.0.3\",\n sha256 = \"686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/idna/1.0.3/download\"],\n strip_prefix = \"idna-1.0.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.idna-1.0.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__idna_adapter-1.2.0\",\n sha256 = \"daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/idna_adapter/1.2.0/download\"],\n strip_prefix = \"idna_adapter-1.2.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.idna_adapter-1.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__ignore-0.4.22\",\n sha256 = \"b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ignore/0.4.22/download\"],\n strip_prefix = \"ignore-0.4.22\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.ignore-0.4.22.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__indexmap-2.9.0\",\n sha256 = \"cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/indexmap/2.9.0/download\"],\n strip_prefix = \"indexmap-2.9.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.indexmap-2.9.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__insta-1.41.1\",\n sha256 = \"7e9ffc4d4892617c50a928c52b2961cb5174b6fc6ebf252b2fac9d21955c48b8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/insta/1.41.1/download\"],\n strip_prefix = \"insta-1.41.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.insta-1.41.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__instant-0.1.12\",\n sha256 = \"7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/instant/0.1.12/download\"],\n strip_prefix = \"instant-0.1.12\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.instant-0.1.12.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__ipnet-2.11.0\",\n sha256 = \"469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ipnet/2.11.0/download\"],\n strip_prefix = \"ipnet-2.11.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.ipnet-2.11.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__iprange-0.6.7\",\n sha256 = \"37209be0ad225457e63814401415e748e2453a5297f9b637338f5fb8afa4ec00\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/iprange/0.6.7/download\"],\n strip_prefix = \"iprange-0.6.7\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.iprange-0.6.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__itertools-0.12.1\",\n sha256 = \"ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/itertools/0.12.1/download\"],\n strip_prefix = \"itertools-0.12.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.itertools-0.12.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__itoa-1.0.10\",\n sha256 = \"b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/itoa/1.0.10/download\"],\n strip_prefix = \"itoa-1.0.10\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.itoa-1.0.10.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__js-sys-0.3.78\",\n sha256 = \"0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/js-sys/0.3.78/download\"],\n strip_prefix = \"js-sys-0.3.78\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.js-sys-0.3.78.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__lalrpop-util-0.22.1\",\n sha256 = \"e8d05b3fe34b8bd562c338db725dfa9beb9451a48f65f129ccb9538b48d2c93b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/lalrpop-util/0.22.1/download\"],\n strip_prefix = \"lalrpop-util-0.22.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.lalrpop-util-0.22.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__lazy_static-1.5.0\",\n sha256 = \"bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/lazy_static/1.5.0/download\"],\n strip_prefix = \"lazy_static-1.5.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.lazy_static-1.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__leb128-0.2.5\",\n sha256 = \"884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/leb128/0.2.5/download\"],\n strip_prefix = \"leb128-0.2.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.leb128-0.2.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__leb128fmt-0.1.0\",\n sha256 = \"09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/leb128fmt/0.1.0/download\"],\n strip_prefix = \"leb128fmt-0.1.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.leb128fmt-0.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__lexical-sort-0.3.1\",\n sha256 = \"c09e4591611e231daf4d4c685a66cb0410cc1e502027a20ae55f2bb9e997207a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/lexical-sort/0.3.1/download\"],\n strip_prefix = \"lexical-sort-0.3.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.lexical-sort-0.3.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__libc-0.2.171\",\n sha256 = \"c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/libc/0.2.171/download\"],\n strip_prefix = \"libc-0.2.171\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.libc-0.2.171.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__libloading-0.8.6\",\n sha256 = \"fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/libloading/0.8.6/download\"],\n strip_prefix = \"libloading-0.8.6\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.libloading-0.8.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__libunwind-1.3.3\",\n sha256 = \"0c6639b70a7ce854b79c70d7e83f16b5dc0137cc914f3d7d03803b513ecc67ac\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/libunwind/1.3.3/download\"],\n strip_prefix = \"libunwind-1.3.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.libunwind-1.3.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__linked-hash-map-0.5.6\",\n sha256 = \"0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/linked-hash-map/0.5.6/download\"],\n strip_prefix = \"linked-hash-map-0.5.6\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.linked-hash-map-0.5.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__linked_hash_set-0.1.4\",\n sha256 = \"47186c6da4d81ca383c7c47c1bfc80f4b95f4720514d860a5407aaf4233f9588\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/linked_hash_set/0.1.4/download\"],\n strip_prefix = \"linked_hash_set-0.1.4\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.linked_hash_set-0.1.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__linux-raw-sys-0.4.12\",\n sha256 = \"c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/linux-raw-sys/0.4.12/download\"],\n strip_prefix = \"linux-raw-sys-0.4.12\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.linux-raw-sys-0.4.12.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__litemap-0.7.5\",\n sha256 = \"23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/litemap/0.7.5/download\"],\n strip_prefix = \"litemap-0.7.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.litemap-0.7.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__litrs-0.4.1\",\n sha256 = \"b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/litrs/0.4.1/download\"],\n strip_prefix = \"litrs-0.4.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.litrs-0.4.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__lock_api-0.4.11\",\n sha256 = \"3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/lock_api/0.4.11/download\"],\n strip_prefix = \"lock_api-0.4.11\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.lock_api-0.4.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__log-0.4.20\",\n sha256 = \"b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/log/0.4.20/download\"],\n strip_prefix = \"log-0.4.20\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.log-0.4.20.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__logos-0.14.4\",\n sha256 = \"7251356ef8cb7aec833ddf598c6cb24d17b689d20b993f9d11a3d764e34e6458\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/logos/0.14.4/download\"],\n strip_prefix = \"logos-0.14.4\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.logos-0.14.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__logos-codegen-0.14.4\",\n sha256 = \"59f80069600c0d66734f5ff52cc42f2dabd6b29d205f333d61fd7832e9e9963f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/logos-codegen/0.14.4/download\"],\n strip_prefix = \"logos-codegen-0.14.4\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.logos-codegen-0.14.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__logos-derive-0.14.4\",\n sha256 = \"24fb722b06a9dc12adb0963ed585f19fc61dc5413e6a9be9422ef92c091e731d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/logos-derive/0.14.4/download\"],\n strip_prefix = \"logos-derive-0.14.4\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.logos-derive-0.14.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__lz4_flex-0.11.1\",\n sha256 = \"3ea9b256699eda7b0387ffbc776dd625e28bde3918446381781245b7a50349d8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/lz4_flex/0.11.1/download\"],\n strip_prefix = \"lz4_flex-0.11.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.lz4_flex-0.11.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__mach2-0.4.2\",\n sha256 = \"19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/mach2/0.4.2/download\"],\n strip_prefix = \"mach2-0.4.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.mach2-0.4.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__macho-unwind-info-0.5.0\",\n sha256 = \"bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/macho-unwind-info/0.5.0/download\"],\n strip_prefix = \"macho-unwind-info-0.5.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.macho-unwind-info-0.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__managed-0.8.0\",\n sha256 = \"0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/managed/0.8.0/download\"],\n strip_prefix = \"managed-0.8.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.managed-0.8.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__matchers-0.1.0\",\n sha256 = \"8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/matchers/0.1.0/download\"],\n strip_prefix = \"matchers-0.1.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.matchers-0.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__memchr-2.7.1\",\n sha256 = \"523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/memchr/2.7.1/download\"],\n strip_prefix = \"memchr-2.7.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.memchr-2.7.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__memmap2-0.6.2\",\n sha256 = \"6d28bba84adfe6646737845bc5ebbfa2c08424eb1c37e94a1fd2a82adb56a872\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/memmap2/0.6.2/download\"],\n strip_prefix = \"memmap2-0.6.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.memmap2-0.6.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__memoffset-0.9.0\",\n sha256 = \"5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/memoffset/0.9.0/download\"],\n strip_prefix = \"memoffset-0.9.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.memoffset-0.9.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__merge-streams-0.1.2\",\n sha256 = \"4f84f6452969abd246e7ac1fe4fe75906c76e8ec88d898df9aef37e0f3b6a7c2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/merge-streams/0.1.2/download\"],\n strip_prefix = \"merge-streams-0.1.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.merge-streams-0.1.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__mime-0.3.17\",\n sha256 = \"6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/mime/0.3.17/download\"],\n strip_prefix = \"mime-0.3.17\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.mime-0.3.17.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__minicov-0.3.7\",\n sha256 = \"f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/minicov/0.3.7/download\"],\n strip_prefix = \"minicov-0.3.7\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.minicov-0.3.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__minimal-lexical-0.2.1\",\n sha256 = \"68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/minimal-lexical/0.2.1/download\"],\n strip_prefix = \"minimal-lexical-0.2.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.minimal-lexical-0.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__miniz_oxide-0.7.1\",\n sha256 = \"e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/miniz_oxide/0.7.1/download\"],\n strip_prefix = \"miniz_oxide-0.7.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.miniz_oxide-0.7.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__miniz_oxide-0.8.7\",\n sha256 = \"ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/miniz_oxide/0.8.7/download\"],\n strip_prefix = \"miniz_oxide-0.8.7\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.miniz_oxide-0.8.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__mio-1.0.3\",\n sha256 = \"2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/mio/1.0.3/download\"],\n strip_prefix = \"mio-1.0.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.mio-1.0.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__more-asserts-0.2.2\",\n sha256 = \"7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/more-asserts/0.2.2/download\"],\n strip_prefix = \"more-asserts-0.2.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.more-asserts-0.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__munge-0.4.3\",\n sha256 = \"a0091202c98cf06da46c279fdf50cccb6b1c43b4521abdf6a27b4c7e71d5d9d7\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/munge/0.4.3/download\"],\n strip_prefix = \"munge-0.4.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.munge-0.4.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__munge_macro-0.4.3\",\n sha256 = \"734799cf91479720b2f970c61a22850940dd91e27d4f02b1c6fc792778df2459\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/munge_macro/0.4.3/download\"],\n strip_prefix = \"munge_macro-0.4.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.munge_macro-0.4.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__native-tls-0.2.12\",\n sha256 = \"a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/native-tls/0.2.12/download\"],\n strip_prefix = \"native-tls-0.2.12\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.native-tls-0.2.12.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__nom-5.1.3\",\n sha256 = \"08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/nom/5.1.3/download\"],\n strip_prefix = \"nom-5.1.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.nom-5.1.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__nom-7.1.3\",\n sha256 = \"d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/nom/7.1.3/download\"],\n strip_prefix = \"nom-7.1.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.nom-7.1.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__nu-ansi-term-0.46.0\",\n sha256 = \"77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/nu-ansi-term/0.46.0/download\"],\n strip_prefix = \"nu-ansi-term-0.46.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.nu-ansi-term-0.46.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__num-conv-0.1.0\",\n sha256 = \"51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/num-conv/0.1.0/download\"],\n strip_prefix = \"num-conv-0.1.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.num-conv-0.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__num-traits-0.2.17\",\n sha256 = \"39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/num-traits/0.2.17/download\"],\n strip_prefix = \"num-traits-0.2.17\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.num-traits-0.2.17.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__num_cpus-1.17.0\",\n sha256 = \"91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/num_cpus/1.17.0/download\"],\n strip_prefix = \"num_cpus-1.17.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.num_cpus-1.17.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__num_enum-0.7.3\",\n sha256 = \"4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/num_enum/0.7.3/download\"],\n strip_prefix = \"num_enum-0.7.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.num_enum-0.7.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__num_enum_derive-0.7.3\",\n sha256 = \"af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/num_enum_derive/0.7.3/download\"],\n strip_prefix = \"num_enum_derive-0.7.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.num_enum_derive-0.7.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__object-0.32.2\",\n sha256 = \"a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/object/0.32.2/download\"],\n strip_prefix = \"object-0.32.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.object-0.32.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__once_cell-1.19.0\",\n sha256 = \"3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/once_cell/1.19.0/download\"],\n strip_prefix = \"once_cell-1.19.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.once_cell-1.19.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__openssl-0.10.64\",\n sha256 = \"95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/openssl/0.10.64/download\"],\n strip_prefix = \"openssl-0.10.64\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.openssl-0.10.64.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__openssl-macros-0.1.1\",\n sha256 = \"a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/openssl-macros/0.1.1/download\"],\n strip_prefix = \"openssl-macros-0.1.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.openssl-macros-0.1.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__openssl-probe-0.1.5\",\n sha256 = \"ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/openssl-probe/0.1.5/download\"],\n strip_prefix = \"openssl-probe-0.1.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.openssl-probe-0.1.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__openssl-sys-0.9.102\",\n sha256 = \"c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/openssl-sys/0.9.102/download\"],\n strip_prefix = \"openssl-sys-0.9.102\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.openssl-sys-0.9.102.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__ouroboros-0.18.5\",\n sha256 = \"1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ouroboros/0.18.5/download\"],\n strip_prefix = \"ouroboros-0.18.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.ouroboros-0.18.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__ouroboros_macro-0.18.5\",\n sha256 = \"3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ouroboros_macro/0.18.5/download\"],\n strip_prefix = \"ouroboros_macro-0.18.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.ouroboros_macro-0.18.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__overload-0.1.1\",\n sha256 = \"b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/overload/0.1.1/download\"],\n strip_prefix = \"overload-0.1.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.overload-0.1.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__parking_lot_core-0.9.9\",\n sha256 = \"4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/parking_lot_core/0.9.9/download\"],\n strip_prefix = \"parking_lot_core-0.9.9\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.parking_lot_core-0.9.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__paste-1.0.15\",\n sha256 = \"57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/paste/1.0.15/download\"],\n strip_prefix = \"paste-1.0.15\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.paste-1.0.15.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__path-clean-1.0.1\",\n sha256 = \"17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/path-clean/1.0.1/download\"],\n strip_prefix = \"path-clean-1.0.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.path-clean-1.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__percent-encoding-2.3.1\",\n sha256 = \"e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/percent-encoding/2.3.1/download\"],\n strip_prefix = \"percent-encoding-2.3.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.percent-encoding-2.3.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__petgraph-0.7.1\",\n sha256 = \"3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/petgraph/0.7.1/download\"],\n strip_prefix = \"petgraph-0.7.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.petgraph-0.7.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__pin-project-1.1.3\",\n sha256 = \"fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pin-project/1.1.3/download\"],\n strip_prefix = \"pin-project-1.1.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.pin-project-1.1.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__pin-project-internal-1.1.3\",\n sha256 = \"4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pin-project-internal/1.1.3/download\"],\n strip_prefix = \"pin-project-internal-1.1.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.pin-project-internal-1.1.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__pin-project-lite-0.2.13\",\n sha256 = \"8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pin-project-lite/0.2.13/download\"],\n strip_prefix = \"pin-project-lite-0.2.13\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.pin-project-lite-0.2.13.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__pin-utils-0.1.0\",\n sha256 = \"8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pin-utils/0.1.0/download\"],\n strip_prefix = \"pin-utils-0.1.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.pin-utils-0.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__pkg-config-0.3.30\",\n sha256 = \"d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pkg-config/0.3.30/download\"],\n strip_prefix = \"pkg-config-0.3.30\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.pkg-config-0.3.30.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__powerfmt-0.2.0\",\n sha256 = \"439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/powerfmt/0.2.0/download\"],\n strip_prefix = \"powerfmt-0.2.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.powerfmt-0.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__ppv-lite86-0.2.17\",\n sha256 = \"5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ppv-lite86/0.2.17/download\"],\n strip_prefix = \"ppv-lite86-0.2.17\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.ppv-lite86-0.2.17.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__prettyplease-0.2.32\",\n sha256 = \"664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/prettyplease/0.2.32/download\"],\n strip_prefix = \"prettyplease-0.2.32\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.prettyplease-0.2.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__proc-macro-crate-1.3.1\",\n sha256 = \"7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/proc-macro-crate/1.3.1/download\"],\n strip_prefix = \"proc-macro-crate-1.3.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.proc-macro-crate-1.3.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__proc-macro-error-attr2-2.0.0\",\n sha256 = \"96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/proc-macro-error-attr2/2.0.0/download\"],\n strip_prefix = \"proc-macro-error-attr2-2.0.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.proc-macro-error-attr2-2.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__proc-macro-error2-2.0.1\",\n sha256 = \"11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/proc-macro-error2/2.0.1/download\"],\n strip_prefix = \"proc-macro-error2-2.0.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.proc-macro-error2-2.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__proc-macro2-1.0.94\",\n sha256 = \"a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/proc-macro2/1.0.94/download\"],\n strip_prefix = \"proc-macro2-1.0.94\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.proc-macro2-1.0.94.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__proc-macro2-diagnostics-0.10.1\",\n sha256 = \"af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/proc-macro2-diagnostics/0.10.1/download\"],\n strip_prefix = \"proc-macro2-diagnostics-0.10.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.proc-macro2-diagnostics-0.10.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__ptr_meta-0.1.4\",\n sha256 = \"0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ptr_meta/0.1.4/download\"],\n strip_prefix = \"ptr_meta-0.1.4\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.ptr_meta-0.1.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__ptr_meta-0.3.0\",\n sha256 = \"fe9e76f66d3f9606f44e45598d155cb13ecf09f4a28199e48daf8c8fc937ea90\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ptr_meta/0.3.0/download\"],\n strip_prefix = \"ptr_meta-0.3.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.ptr_meta-0.3.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__ptr_meta_derive-0.1.4\",\n sha256 = \"16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ptr_meta_derive/0.1.4/download\"],\n strip_prefix = \"ptr_meta_derive-0.1.4\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.ptr_meta_derive-0.1.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__ptr_meta_derive-0.3.0\",\n sha256 = \"ca414edb151b4c8d125c12566ab0d74dc9cdba36fb80eb7b848c15f495fd32d1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ptr_meta_derive/0.3.0/download\"],\n strip_prefix = \"ptr_meta_derive-0.3.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.ptr_meta_derive-0.3.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__pulldown-cmark-0.8.0\",\n sha256 = \"ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pulldown-cmark/0.8.0/download\"],\n strip_prefix = \"pulldown-cmark-0.8.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.pulldown-cmark-0.8.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__quote-1.0.35\",\n sha256 = \"291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/quote/1.0.35/download\"],\n strip_prefix = \"quote-1.0.35\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.quote-1.0.35.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__rancor-0.1.0\",\n sha256 = \"caf5f7161924b9d1cea0e4cabc97c372cea92b5f927fc13c6bca67157a0ad947\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rancor/0.1.0/download\"],\n strip_prefix = \"rancor-0.1.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.rancor-0.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__rand-0.8.5\",\n sha256 = \"34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rand/0.8.5/download\"],\n strip_prefix = \"rand-0.8.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.rand-0.8.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__rand_chacha-0.3.1\",\n sha256 = \"e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rand_chacha/0.3.1/download\"],\n strip_prefix = \"rand_chacha-0.3.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.rand_chacha-0.3.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__rand_core-0.6.4\",\n sha256 = \"ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rand_core/0.6.4/download\"],\n strip_prefix = \"rand_core-0.6.4\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.rand_core-0.6.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__redox_syscall-0.4.1\",\n sha256 = \"4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/redox_syscall/0.4.1/download\"],\n strip_prefix = \"redox_syscall-0.4.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.redox_syscall-0.4.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__ref-cast-1.0.24\",\n sha256 = \"4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ref-cast/1.0.24/download\"],\n strip_prefix = \"ref-cast-1.0.24\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.ref-cast-1.0.24.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__ref-cast-impl-1.0.24\",\n sha256 = \"1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ref-cast-impl/1.0.24/download\"],\n strip_prefix = \"ref-cast-impl-1.0.24\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.ref-cast-impl-1.0.24.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__regex-1.10.2\",\n sha256 = \"380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/regex/1.10.2/download\"],\n strip_prefix = \"regex-1.10.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.regex-1.10.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__regex-automata-0.1.10\",\n sha256 = \"6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/regex-automata/0.1.10/download\"],\n strip_prefix = \"regex-automata-0.1.10\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.regex-automata-0.1.10.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__regex-automata-0.4.3\",\n sha256 = \"5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/regex-automata/0.4.3/download\"],\n strip_prefix = \"regex-automata-0.4.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.regex-automata-0.4.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__regex-syntax-0.6.29\",\n sha256 = \"f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/regex-syntax/0.6.29/download\"],\n strip_prefix = \"regex-syntax-0.6.29\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.regex-syntax-0.6.29.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__regex-syntax-0.8.2\",\n sha256 = \"c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/regex-syntax/0.8.2/download\"],\n strip_prefix = \"regex-syntax-0.8.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.regex-syntax-0.8.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__region-3.0.2\",\n sha256 = \"e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/region/3.0.2/download\"],\n strip_prefix = \"region-3.0.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.region-3.0.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__rend-0.5.2\",\n sha256 = \"a35e8a6bf28cd121053a66aa2e6a2e3eaffad4a60012179f0e864aa5ffeff215\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rend/0.5.2/download\"],\n strip_prefix = \"rend-0.5.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.rend-0.5.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__replace_with-0.1.7\",\n sha256 = \"e3a8614ee435691de62bcffcf4a66d91b3594bf1428a5722e79103249a095690\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/replace_with/0.1.7/download\"],\n strip_prefix = \"replace_with-0.1.7\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.replace_with-0.1.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__reqwest-0.12.7\",\n sha256 = \"f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/reqwest/0.12.7/download\"],\n strip_prefix = \"reqwest-0.12.7\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.reqwest-0.12.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__ring-0.17.8\",\n sha256 = \"c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ring/0.17.8/download\"],\n strip_prefix = \"ring-0.17.8\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.ring-0.17.8.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__rkyv-0.8.10\",\n sha256 = \"1e147371c75553e1e2fcdb483944a8540b8438c31426279553b9a8182a9b7b65\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rkyv/0.8.10/download\"],\n strip_prefix = \"rkyv-0.8.10\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.rkyv-0.8.10.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__rkyv_derive-0.8.10\",\n sha256 = \"246b40ac189af6c675d124b802e8ef6d5246c53e17367ce9501f8f66a81abb7a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rkyv_derive/0.8.10/download\"],\n strip_prefix = \"rkyv_derive-0.8.10\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.rkyv_derive-0.8.10.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__rustc-demangle-0.1.23\",\n sha256 = \"d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustc-demangle/0.1.23/download\"],\n strip_prefix = \"rustc-demangle-0.1.23\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.rustc-demangle-0.1.23.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__rustc-hash-1.1.0\",\n sha256 = \"08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustc-hash/1.1.0/download\"],\n strip_prefix = \"rustc-hash-1.1.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.rustc-hash-1.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__rustix-0.38.34\",\n sha256 = \"70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustix/0.38.34/download\"],\n strip_prefix = \"rustix-0.38.34\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.rustix-0.38.34.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__rustls-0.23.25\",\n sha256 = \"822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustls/0.23.25/download\"],\n strip_prefix = \"rustls-0.23.25\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.rustls-0.23.25.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__rustls-pemfile-2.1.2\",\n sha256 = \"29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustls-pemfile/2.1.2/download\"],\n strip_prefix = \"rustls-pemfile-2.1.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.rustls-pemfile-2.1.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__rustls-pki-types-1.11.0\",\n sha256 = \"917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustls-pki-types/1.11.0/download\"],\n strip_prefix = \"rustls-pki-types-1.11.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.rustls-pki-types-1.11.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__rustls-webpki-0.103.1\",\n sha256 = \"fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustls-webpki/0.103.1/download\"],\n strip_prefix = \"rustls-webpki-0.103.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.rustls-webpki-0.103.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__rustversion-1.0.20\",\n sha256 = \"eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustversion/1.0.20/download\"],\n strip_prefix = \"rustversion-1.0.20\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.rustversion-1.0.20.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__ruzstd-0.5.0\",\n sha256 = \"58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ruzstd/0.5.0/download\"],\n strip_prefix = \"ruzstd-0.5.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.ruzstd-0.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__ryu-1.0.16\",\n sha256 = \"f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ryu/1.0.16/download\"],\n strip_prefix = \"ryu-1.0.16\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.ryu-1.0.16.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__saffron-0.1.0\",\n sha256 = \"03fb9a628596fc7590eb7edbf7b0613287be78df107f5f97b118aad59fb2eea9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/saffron/0.1.0/download\"],\n strip_prefix = \"saffron-0.1.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.saffron-0.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__same-file-1.0.6\",\n sha256 = \"93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/same-file/1.0.6/download\"],\n strip_prefix = \"same-file-1.0.6\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.same-file-1.0.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__schannel-0.1.23\",\n sha256 = \"fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/schannel/0.1.23/download\"],\n strip_prefix = \"schannel-0.1.23\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.schannel-0.1.23.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__schemars-0.8.21\",\n sha256 = \"09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/schemars/0.8.21/download\"],\n strip_prefix = \"schemars-0.8.21\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.schemars-0.8.21.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__schemars_derive-0.8.21\",\n sha256 = \"b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/schemars_derive/0.8.21/download\"],\n strip_prefix = \"schemars_derive-0.8.21\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.schemars_derive-0.8.21.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__scopeguard-1.2.0\",\n sha256 = \"94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/scopeguard/1.2.0/download\"],\n strip_prefix = \"scopeguard-1.2.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.scopeguard-1.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__security-framework-2.10.0\",\n sha256 = \"770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/security-framework/2.10.0/download\"],\n strip_prefix = \"security-framework-2.10.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.security-framework-2.10.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__security-framework-sys-2.14.0\",\n sha256 = \"49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/security-framework-sys/2.14.0/download\"],\n strip_prefix = \"security-framework-sys-2.14.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.security-framework-sys-2.14.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__self_cell-1.0.3\",\n sha256 = \"58bf37232d3bb9a2c4e641ca2a11d83b5062066f88df7fed36c28772046d65ba\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/self_cell/1.0.3/download\"],\n strip_prefix = \"self_cell-1.0.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.self_cell-1.0.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__semver-1.0.26\",\n sha256 = \"56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/semver/1.0.26/download\"],\n strip_prefix = \"semver-1.0.26\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.semver-1.0.26.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__serde-1.0.219\",\n sha256 = \"5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde/1.0.219/download\"],\n strip_prefix = \"serde-1.0.219\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.serde-1.0.219.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__serde-wasm-bindgen-0.6.5\",\n sha256 = \"8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde-wasm-bindgen/0.6.5/download\"],\n strip_prefix = \"serde-wasm-bindgen-0.6.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.serde-wasm-bindgen-0.6.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__serde_bytes-0.11.14\",\n sha256 = \"8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_bytes/0.11.14/download\"],\n strip_prefix = \"serde_bytes-0.11.14\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.serde_bytes-0.11.14.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__serde_derive-1.0.219\",\n sha256 = \"5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_derive/1.0.219/download\"],\n strip_prefix = \"serde_derive-1.0.219\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.serde_derive-1.0.219.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__serde_derive_internals-0.29.1\",\n sha256 = \"18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_derive_internals/0.29.1/download\"],\n strip_prefix = \"serde_derive_internals-0.29.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.serde_derive_internals-0.29.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__serde_json-1.0.140\",\n sha256 = \"20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_json/1.0.140/download\"],\n strip_prefix = \"serde_json-1.0.140\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.serde_json-1.0.140.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__serde_path_to_error-0.1.17\",\n sha256 = \"59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_path_to_error/0.1.17/download\"],\n strip_prefix = \"serde_path_to_error-0.1.17\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.serde_path_to_error-0.1.17.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__serde_spanned-0.6.6\",\n sha256 = \"79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_spanned/0.6.6/download\"],\n strip_prefix = \"serde_spanned-0.6.6\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.serde_spanned-0.6.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__serde_urlencoded-0.7.1\",\n sha256 = \"d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_urlencoded/0.7.1/download\"],\n strip_prefix = \"serde_urlencoded-0.7.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.serde_urlencoded-0.7.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__serde_yaml-0.9.34-deprecated\",\n sha256 = \"6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_yaml/0.9.34+deprecated/download\"],\n strip_prefix = \"serde_yaml-0.9.34+deprecated\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.serde_yaml-0.9.34+deprecated.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__sha2-0.10.8\",\n sha256 = \"793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/sha2/0.10.8/download\"],\n strip_prefix = \"sha2-0.10.8\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.sha2-0.10.8.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__sharded-slab-0.1.7\",\n sha256 = \"f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/sharded-slab/0.1.7/download\"],\n strip_prefix = \"sharded-slab-0.1.7\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.sharded-slab-0.1.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__shared-buffer-0.1.4\",\n sha256 = \"f6c99835bad52957e7aa241d3975ed17c1e5f8c92026377d117a606f36b84b16\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/shared-buffer/0.1.4/download\"],\n strip_prefix = \"shared-buffer-0.1.4\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.shared-buffer-0.1.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__shlex-1.3.0\",\n sha256 = \"0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/shlex/1.3.0/download\"],\n strip_prefix = \"shlex-1.3.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.shlex-1.3.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__simdutf8-0.1.4\",\n sha256 = \"f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/simdutf8/0.1.4/download\"],\n strip_prefix = \"simdutf8-0.1.4\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.simdutf8-0.1.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__similar-2.7.0\",\n sha256 = \"bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/similar/2.7.0/download\"],\n strip_prefix = \"similar-2.7.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.similar-2.7.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__slab-0.4.9\",\n sha256 = \"8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/slab/0.4.9/download\"],\n strip_prefix = \"slab-0.4.9\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.slab-0.4.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__smallvec-1.13.2\",\n sha256 = \"3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/smallvec/1.13.2/download\"],\n strip_prefix = \"smallvec-1.13.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.smallvec-1.13.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__smoltcp-0.8.2\",\n sha256 = \"ee34c1e1bfc7e9206cc0fb8030a90129b4e319ab53856249bb27642cab914fb3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/smoltcp/0.8.2/download\"],\n strip_prefix = \"smoltcp-0.8.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.smoltcp-0.8.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__socket2-0.5.7\",\n sha256 = \"ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/socket2/0.5.7/download\"],\n strip_prefix = \"socket2-0.5.7\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.socket2-0.5.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__spin-0.9.8\",\n sha256 = \"6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/spin/0.9.8/download\"],\n strip_prefix = \"spin-0.9.8\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.spin-0.9.8.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__stable_deref_trait-1.2.0\",\n sha256 = \"a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/stable_deref_trait/1.2.0/download\"],\n strip_prefix = \"stable_deref_trait-1.2.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.stable_deref_trait-1.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__static_assertions-1.1.0\",\n sha256 = \"a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/static_assertions/1.1.0/download\"],\n strip_prefix = \"static_assertions-1.1.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.static_assertions-1.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__strsim-0.10.0\",\n sha256 = \"73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/strsim/0.10.0/download\"],\n strip_prefix = \"strsim-0.10.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.strsim-0.10.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__subtle-2.6.1\",\n sha256 = \"13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/subtle/2.6.1/download\"],\n strip_prefix = \"subtle-2.6.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.subtle-2.6.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__syn-1.0.109\",\n sha256 = \"72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/syn/1.0.109/download\"],\n strip_prefix = \"syn-1.0.109\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.syn-1.0.109.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__syn-2.0.100\",\n sha256 = \"b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/syn/2.0.100/download\"],\n strip_prefix = \"syn-2.0.100\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.syn-2.0.100.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__sync_wrapper-1.0.1\",\n sha256 = \"a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/sync_wrapper/1.0.1/download\"],\n strip_prefix = \"sync_wrapper-1.0.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.sync_wrapper-1.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__synstructure-0.13.1\",\n sha256 = \"c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/synstructure/0.13.1/download\"],\n strip_prefix = \"synstructure-0.13.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.synstructure-0.13.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__system-configuration-0.6.1\",\n sha256 = \"3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/system-configuration/0.6.1/download\"],\n strip_prefix = \"system-configuration-0.6.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.system-configuration-0.6.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__system-configuration-sys-0.6.0\",\n sha256 = \"8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/system-configuration-sys/0.6.0/download\"],\n strip_prefix = \"system-configuration-sys-0.6.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.system-configuration-sys-0.6.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__tar-0.4.44\",\n sha256 = \"1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tar/0.4.44/download\"],\n strip_prefix = \"tar-0.4.44\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.tar-0.4.44.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__target-lexicon-0.12.16\",\n sha256 = \"61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/target-lexicon/0.12.16/download\"],\n strip_prefix = \"target-lexicon-0.12.16\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.target-lexicon-0.12.16.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__tempfile-3.12.0\",\n sha256 = \"04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tempfile/3.12.0/download\"],\n strip_prefix = \"tempfile-3.12.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.tempfile-3.12.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__terminal_size-0.3.0\",\n sha256 = \"21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/terminal_size/0.3.0/download\"],\n strip_prefix = \"terminal_size-0.3.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.terminal_size-0.3.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__termios-0.3.3\",\n sha256 = \"411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/termios/0.3.3/download\"],\n strip_prefix = \"termios-0.3.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.termios-0.3.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__thiserror-1.0.69\",\n sha256 = \"b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/thiserror/1.0.69/download\"],\n strip_prefix = \"thiserror-1.0.69\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.thiserror-1.0.69.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__thiserror-2.0.12\",\n sha256 = \"567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/thiserror/2.0.12/download\"],\n strip_prefix = \"thiserror-2.0.12\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.thiserror-2.0.12.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__thiserror-impl-1.0.69\",\n sha256 = \"4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/thiserror-impl/1.0.69/download\"],\n strip_prefix = \"thiserror-impl-1.0.69\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.thiserror-impl-1.0.69.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__thiserror-impl-2.0.12\",\n sha256 = \"7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/thiserror-impl/2.0.12/download\"],\n strip_prefix = \"thiserror-impl-2.0.12\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.thiserror-impl-2.0.12.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__thread_local-1.1.7\",\n sha256 = \"3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/thread_local/1.1.7/download\"],\n strip_prefix = \"thread_local-1.1.7\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.thread_local-1.1.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__time-0.3.36\",\n sha256 = \"5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/time/0.3.36/download\"],\n strip_prefix = \"time-0.3.36\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.time-0.3.36.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__time-core-0.1.2\",\n sha256 = \"ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/time-core/0.1.2/download\"],\n strip_prefix = \"time-core-0.1.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.time-core-0.1.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__time-macros-0.2.18\",\n sha256 = \"3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/time-macros/0.2.18/download\"],\n strip_prefix = \"time-macros-0.2.18\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.time-macros-0.2.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__tinystr-0.7.6\",\n sha256 = \"9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tinystr/0.7.6/download\"],\n strip_prefix = \"tinystr-0.7.6\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.tinystr-0.7.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__tinyvec-1.6.0\",\n sha256 = \"87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tinyvec/1.6.0/download\"],\n strip_prefix = \"tinyvec-1.6.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.tinyvec-1.6.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__tinyvec_macros-0.1.1\",\n sha256 = \"1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tinyvec_macros/0.1.1/download\"],\n strip_prefix = \"tinyvec_macros-0.1.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.tinyvec_macros-0.1.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__tokio-1.44.2\",\n sha256 = \"e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tokio/1.44.2/download\"],\n strip_prefix = \"tokio-1.44.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.tokio-1.44.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__tokio-macros-2.5.0\",\n sha256 = \"6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tokio-macros/2.5.0/download\"],\n strip_prefix = \"tokio-macros-2.5.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.tokio-macros-2.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__tokio-native-tls-0.3.1\",\n sha256 = \"bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tokio-native-tls/0.3.1/download\"],\n strip_prefix = \"tokio-native-tls-0.3.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.tokio-native-tls-0.3.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__tokio-rustls-0.26.0\",\n sha256 = \"0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tokio-rustls/0.26.0/download\"],\n strip_prefix = \"tokio-rustls-0.26.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.tokio-rustls-0.26.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__tokio-serde-0.9.0\",\n sha256 = \"caf600e7036b17782571dd44fa0a5cea3c82f60db5137f774a325a76a0d6852b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tokio-serde/0.9.0/download\"],\n strip_prefix = \"tokio-serde-0.9.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.tokio-serde-0.9.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__tokio-stream-0.1.15\",\n sha256 = \"267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tokio-stream/0.1.15/download\"],\n strip_prefix = \"tokio-stream-0.1.15\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.tokio-stream-0.1.15.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__tokio-util-0.7.11\",\n sha256 = \"9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tokio-util/0.7.11/download\"],\n strip_prefix = \"tokio-util-0.7.11\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.tokio-util-0.7.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__toml-0.8.14\",\n sha256 = \"6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/toml/0.8.14/download\"],\n strip_prefix = \"toml-0.8.14\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.toml-0.8.14.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__toml_datetime-0.6.6\",\n sha256 = \"4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/toml_datetime/0.6.6/download\"],\n strip_prefix = \"toml_datetime-0.6.6\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.toml_datetime-0.6.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__toml_edit-0.19.15\",\n sha256 = \"1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/toml_edit/0.19.15/download\"],\n strip_prefix = \"toml_edit-0.19.15\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.toml_edit-0.19.15.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__toml_edit-0.22.14\",\n sha256 = \"f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/toml_edit/0.22.14/download\"],\n strip_prefix = \"toml_edit-0.22.14\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.toml_edit-0.22.14.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__tower-0.4.13\",\n sha256 = \"b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tower/0.4.13/download\"],\n strip_prefix = \"tower-0.4.13\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.tower-0.4.13.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__tower-layer-0.3.2\",\n sha256 = \"c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tower-layer/0.3.2/download\"],\n strip_prefix = \"tower-layer-0.3.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.tower-layer-0.3.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__tower-service-0.3.2\",\n sha256 = \"b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tower-service/0.3.2/download\"],\n strip_prefix = \"tower-service-0.3.2\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.tower-service-0.3.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__tracing-0.1.41\",\n sha256 = \"784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tracing/0.1.41/download\"],\n strip_prefix = \"tracing-0.1.41\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.tracing-0.1.41.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__tracing-attributes-0.1.28\",\n sha256 = \"395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tracing-attributes/0.1.28/download\"],\n strip_prefix = \"tracing-attributes-0.1.28\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.tracing-attributes-0.1.28.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__tracing-core-0.1.33\",\n sha256 = \"e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tracing-core/0.1.33/download\"],\n strip_prefix = \"tracing-core-0.1.33\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.tracing-core-0.1.33.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__tracing-log-0.2.0\",\n sha256 = \"ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tracing-log/0.2.0/download\"],\n strip_prefix = \"tracing-log-0.2.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.tracing-log-0.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__tracing-subscriber-0.3.18\",\n sha256 = \"ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tracing-subscriber/0.3.18/download\"],\n strip_prefix = \"tracing-subscriber-0.3.18\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.tracing-subscriber-0.3.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__try-lock-0.2.5\",\n sha256 = \"e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/try-lock/0.2.5/download\"],\n strip_prefix = \"try-lock-0.2.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.try-lock-0.2.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__twox-hash-1.6.3\",\n sha256 = \"97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/twox-hash/1.6.3/download\"],\n strip_prefix = \"twox-hash-1.6.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.twox-hash-1.6.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__typenum-1.17.0\",\n sha256 = \"42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/typenum/1.17.0/download\"],\n strip_prefix = \"typenum-1.17.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.typenum-1.17.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__unicase-2.7.0\",\n sha256 = \"f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unicase/2.7.0/download\"],\n strip_prefix = \"unicase-2.7.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.unicase-2.7.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__unicode-ident-1.0.12\",\n sha256 = \"3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unicode-ident/1.0.12/download\"],\n strip_prefix = \"unicode-ident-1.0.12\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.unicode-ident-1.0.12.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__unicode-normalization-0.1.22\",\n sha256 = \"5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unicode-normalization/0.1.22/download\"],\n strip_prefix = \"unicode-normalization-0.1.22\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.unicode-normalization-0.1.22.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__unicode-segmentation-1.10.1\",\n sha256 = \"1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unicode-segmentation/1.10.1/download\"],\n strip_prefix = \"unicode-segmentation-1.10.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.unicode-segmentation-1.10.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__unicode-width-0.2.0\",\n sha256 = \"1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unicode-width/0.2.0/download\"],\n strip_prefix = \"unicode-width-0.2.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.unicode-width-0.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__unicode-xid-0.2.4\",\n sha256 = \"f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unicode-xid/0.2.4/download\"],\n strip_prefix = \"unicode-xid-0.2.4\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.unicode-xid-0.2.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__unsafe-libyaml-0.2.11\",\n sha256 = \"673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unsafe-libyaml/0.2.11/download\"],\n strip_prefix = \"unsafe-libyaml-0.2.11\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.unsafe-libyaml-0.2.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__untrusted-0.9.0\",\n sha256 = \"8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/untrusted/0.9.0/download\"],\n strip_prefix = \"untrusted-0.9.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.untrusted-0.9.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__url-2.5.4\",\n sha256 = \"32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/url/2.5.4/download\"],\n strip_prefix = \"url-2.5.4\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.url-2.5.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__urlencoding-2.1.3\",\n sha256 = \"daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/urlencoding/2.1.3/download\"],\n strip_prefix = \"urlencoding-2.1.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.urlencoding-2.1.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__utf16_iter-1.0.5\",\n sha256 = \"c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/utf16_iter/1.0.5/download\"],\n strip_prefix = \"utf16_iter-1.0.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.utf16_iter-1.0.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__utf8_iter-1.0.4\",\n sha256 = \"b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/utf8_iter/1.0.4/download\"],\n strip_prefix = \"utf8_iter-1.0.4\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.utf8_iter-1.0.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__uuid-1.9.1\",\n sha256 = \"5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/uuid/1.9.1/download\"],\n strip_prefix = \"uuid-1.9.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.uuid-1.9.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__valuable-0.1.0\",\n sha256 = \"830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/valuable/0.1.0/download\"],\n strip_prefix = \"valuable-0.1.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.valuable-0.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__vcpkg-0.2.15\",\n sha256 = \"accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/vcpkg/0.2.15/download\"],\n strip_prefix = \"vcpkg-0.2.15\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.vcpkg-0.2.15.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__version_check-0.9.5\",\n sha256 = \"0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/version_check/0.9.5/download\"],\n strip_prefix = \"version_check-0.9.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.version_check-0.9.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__virtual-fs-0.601.0\",\n patch_args = [\n \"-p1\",\n ],\n patches = [\n \"@@//src/wasix/browser-host:patches/0036-virtual-fs-poll-contended-pipe-reads.patch\",\n ],\n sha256 = \"8defc513ce70576bdbb4305ee67c0cba647af18c0995de8f1fa1271b724c9859\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/virtual-fs/virtual-fs-0.601.0.crate\"],\n strip_prefix = \"virtual-fs-0.601.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.virtual-fs-0.601.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__virtual-mio-0.601.0\",\n patch_args = [\n \"-p1\",\n ],\n patches = [\n \"@@//src/wasix/browser-host:patches/0037-virtual-mio-retain-inline-wakes.patch\",\n ],\n sha256 = \"a14806a3f25b70315764760c376d9f68937f5467013891bc7497a33d24105097\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/virtual-mio/virtual-mio-0.601.0.crate\"],\n strip_prefix = \"virtual-mio-0.601.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.virtual-mio-0.601.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__virtual-net-0.601.0\",\n sha256 = \"0a7dccbe5d8d3a49e2b43a2c5a4287139e33ba04c03279bfc8a0aef82def2043\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/virtual-net/0.601.0/download\"],\n strip_prefix = \"virtual-net-0.601.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.virtual-net-0.601.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wai-bindgen-gen-core-0.2.3\",\n sha256 = \"1aa3dc41b510811122b3088197234c27e08fcad63ef936306dd8e11e2803876c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wai-bindgen-gen-core/0.2.3/download\"],\n strip_prefix = \"wai-bindgen-gen-core-0.2.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wai-bindgen-gen-core-0.2.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wai-bindgen-gen-rust-0.2.3\",\n sha256 = \"19bc05e8380515c4337c40ef03b2ff233e391315b178a320de8640703d522efe\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wai-bindgen-gen-rust/0.2.3/download\"],\n strip_prefix = \"wai-bindgen-gen-rust-0.2.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wai-bindgen-gen-rust-0.2.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wai-bindgen-gen-rust-wasm-0.2.3\",\n sha256 = \"d6f35ce5e74086fac87f3a7bd50f643f00fe3559adb75c88521ecaa01c8a6199\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wai-bindgen-gen-rust-wasm/0.2.3/download\"],\n strip_prefix = \"wai-bindgen-gen-rust-wasm-0.2.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wai-bindgen-gen-rust-wasm-0.2.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wai-bindgen-rust-0.2.3\",\n sha256 = \"4e5601c6f448c063e83a5e931b8fefcdf7e01ada424ad42372c948d2e3d67741\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wai-bindgen-rust/0.2.3/download\"],\n strip_prefix = \"wai-bindgen-rust-0.2.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wai-bindgen-rust-0.2.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wai-bindgen-rust-impl-0.2.3\",\n sha256 = \"bdeeb5c1170246de8425a3e123e7ef260dc05ba2b522a1d369fe2315376efea4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wai-bindgen-rust-impl/0.2.3/download\"],\n strip_prefix = \"wai-bindgen-rust-impl-0.2.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wai-bindgen-rust-impl-0.2.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wai-parser-0.2.3\",\n sha256 = \"9bd0acb6d70885ea0c343749019ba74f015f64a9d30542e66db69b49b7e28186\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wai-parser/0.2.3/download\"],\n strip_prefix = \"wai-parser-0.2.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wai-parser-0.2.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__waker-fn-1.1.1\",\n sha256 = \"f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/waker-fn/1.1.1/download\"],\n strip_prefix = \"waker-fn-1.1.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.waker-fn-1.1.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__walkdir-2.4.0\",\n sha256 = \"d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/walkdir/2.4.0/download\"],\n strip_prefix = \"walkdir-2.4.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.walkdir-2.4.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__want-0.3.1\",\n sha256 = \"bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/want/0.3.1/download\"],\n strip_prefix = \"want-0.3.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.want-0.3.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasi-0.11.0-wasi-snapshot-preview1\",\n sha256 = \"9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasi/0.11.0+wasi-snapshot-preview1/download\"],\n strip_prefix = \"wasi-0.11.0+wasi-snapshot-preview1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasi-0.11.0+wasi-snapshot-preview1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasm-bindgen-0.2.101\",\n sha256 = \"7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-bindgen/0.2.101/download\"],\n strip_prefix = \"wasm-bindgen-0.2.101\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasm-bindgen-0.2.101.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasm-bindgen-backend-0.2.101\",\n sha256 = \"e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-bindgen-backend/0.2.101/download\"],\n strip_prefix = \"wasm-bindgen-backend-0.2.101\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasm-bindgen-backend-0.2.101.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasm-bindgen-derive-0.2.1\",\n sha256 = \"c1ab6c8bffb3f89584781211283fb57337d6902faab6eaee38f336977bdf177d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-bindgen-derive/0.2.1/download\"],\n strip_prefix = \"wasm-bindgen-derive-0.2.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasm-bindgen-derive-0.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasm-bindgen-derive-macro-0.2.1\",\n sha256 = \"b87c28b31d27616bc69a891700ef0445d2cbaa0340fdacb145145256d5f5fcbb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-bindgen-derive-macro/0.2.1/download\"],\n strip_prefix = \"wasm-bindgen-derive-macro-0.2.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasm-bindgen-derive-macro-0.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasm-bindgen-futures-0.4.51\",\n sha256 = \"0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-bindgen-futures/0.4.51/download\"],\n strip_prefix = \"wasm-bindgen-futures-0.4.51\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasm-bindgen-futures-0.4.51.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasm-bindgen-macro-0.2.101\",\n sha256 = \"7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-bindgen-macro/0.2.101/download\"],\n strip_prefix = \"wasm-bindgen-macro-0.2.101\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasm-bindgen-macro-0.2.101.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasm-bindgen-macro-support-0.2.101\",\n sha256 = \"7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-bindgen-macro-support/0.2.101/download\"],\n strip_prefix = \"wasm-bindgen-macro-support-0.2.101\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasm-bindgen-macro-support-0.2.101.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasm-bindgen-shared-0.2.101\",\n sha256 = \"f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-bindgen-shared/0.2.101/download\"],\n strip_prefix = \"wasm-bindgen-shared-0.2.101\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasm-bindgen-shared-0.2.101.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasm-bindgen-test-0.3.51\",\n sha256 = \"80cc7f8a4114fdaa0c58383caf973fc126cf004eba25c9dc639bccd3880d55ad\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-bindgen-test/0.3.51/download\"],\n strip_prefix = \"wasm-bindgen-test-0.3.51\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasm-bindgen-test-0.3.51.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasm-bindgen-test-macro-0.3.51\",\n sha256 = \"c5ada2ab788d46d4bda04c9d567702a79c8ced14f51f221646a16ed39d0e6a5d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-bindgen-test-macro/0.3.51/download\"],\n strip_prefix = \"wasm-bindgen-test-macro-0.3.51\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasm-bindgen-test-macro-0.3.51.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasm-encoder-0.221.3\",\n sha256 = \"dc8444fe4920de80a4fe5ab564fff2ae58b6b73166b89751f8c6c93509da32e5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-encoder/0.221.3/download\"],\n strip_prefix = \"wasm-encoder-0.221.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasm-encoder-0.221.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasm-encoder-0.235.0\",\n sha256 = \"b3bc393c395cb621367ff02d854179882b9a351b4e0c93d1397e6090b53a5c2a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-encoder/0.235.0/download\"],\n strip_prefix = \"wasm-encoder-0.235.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasm-encoder-0.235.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasm-streams-0.4.0\",\n sha256 = \"b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-streams/0.4.0/download\"],\n strip_prefix = \"wasm-streams-0.4.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasm-streams-0.4.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasmer-6.1.0\",\n patch_args = [\n \"-p1\",\n ],\n patches = [\n \"@@//src/wasix/browser-host:patches/0008-wasmer-instantiate-js-modules-async.patch\",\n \"@@//src/wasix/browser-host:patches/0019-wasmer-parse-exception-reference-types.patch\",\n ],\n sha256 = \"2d85671948f8886a1cc946141c0b688a5617603c103699a5fceeebeb4e75b0b6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasmer/wasmer-6.1.0.crate\"],\n strip_prefix = \"wasmer-6.1.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasmer-6.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasmer-backend-api-0.601.0\",\n sha256 = \"ef123baf425c415c1538fcf6da66d030c69d47ee8a9acc063e9f7b890c7ec893\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasmer-backend-api/0.601.0/download\"],\n strip_prefix = \"wasmer-backend-api-0.601.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasmer-backend-api-0.601.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasmer-compiler-6.1.0\",\n sha256 = \"4946475adc0af265af8f10aadf4d4a3c64845bcd3801c655bdd81ce5e3ee869b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasmer-compiler/6.1.0/download\"],\n strip_prefix = \"wasmer-compiler-6.1.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasmer-compiler-6.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasmer-config-0.601.0\",\n sha256 = \"f6c7a72bfcba1000b7609e034e0d470575fae8215b597c2c6554661729d64c22\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasmer-config/0.601.0/download\"],\n strip_prefix = \"wasmer-config-0.601.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasmer-config-0.601.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasmer-derive-6.1.0\",\n sha256 = \"c546f3380840cd63fdcc390f04cd19002f2dfa19b4691b77ecbd27642bd93452\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasmer-derive/6.1.0/download\"],\n strip_prefix = \"wasmer-derive-6.1.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasmer-derive-6.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasmer-journal-0.601.0\",\n sha256 = \"6459cd00a0000e38dd4386bec1d99687813677bb01bfe69120f0f3eaedae0a06\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasmer-journal/0.601.0/download\"],\n strip_prefix = \"wasmer-journal-0.601.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasmer-journal-0.601.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasmer-package-0.601.0\",\n sha256 = \"aedc3a5cd721e8b12778d1858b9583aca8b91927a73f5fdf0c876cd5bbb6ac56\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasmer-package/0.601.0/download\"],\n strip_prefix = \"wasmer-package-0.601.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasmer-package-0.601.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasmer-types-6.1.0\",\n sha256 = \"94a4027ce165e8dc776dc5e2a3231a96983e6dc7330efd97b793cfc4e973ad0c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasmer-types/6.1.0/download\"],\n strip_prefix = \"wasmer-types-6.1.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasmer-types-6.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasmer-vm-6.1.0\",\n sha256 = \"9c37d5be291eea00a00d077ce3a427bb3074709ee386ec358f18f0b7da33be01\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasmer-vm/6.1.0/download\"],\n strip_prefix = \"wasmer-vm-6.1.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasmer-vm-6.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasmer-wasix-0.601.0\",\n patch_args = [\n \"-p1\",\n ],\n patches = [\n \"@@//src/wasix/browser-host:patches/0002-wasmer-wasix-add-0702-compatibility-imports.patch\",\n \"@@//src/wasix/browser-host:patches/0009-wasmer-wasix-instantiate-main-module-async.patch\",\n \"@@//src/wasix/browser-host:patches/0011-wasmer-wasix-deny-single-backend-guest-spawn.patch\",\n \"@@//src/wasix/browser-host:patches/0013-wasmer-wasix-fast-single-backend-clock.patch\",\n \"@@//src/wasix/browser-host:patches/0016-wasmer-wasix-direct-single-backend-clock.patch\",\n \"@@//src/wasix/browser-host:patches/0020-wasmer-wasix-preserve-posix-close-durability.patch\",\n \"@@//src/wasix/browser-host:patches/0035-wasmer-wasix-preserve-shared-seek-offset.patch\",\n \"@@//src/wasix/browser-host:patches/0033-wasmer-wasix-poll-ready-asyncify-work.patch\",\n ],\n sha256 = \"a9a804fcfbdbbfe5b2d6fb30e741e22a21e88e964dedfea9e609f13a52823bfe\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasmer-wasix/wasmer-wasix-0.601.0.crate\"],\n strip_prefix = \"wasmer-wasix-0.601.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasmer-wasix-0.601.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasmer-wasix-types-0.601.0\",\n sha256 = \"7d2b7dad6c826f48a972709e5950a80157cb3b6bb12c6f51778282e85dc17096\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasmer-wasix-types/0.601.0/download\"],\n strip_prefix = \"wasmer-wasix-types-0.601.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasmer-wasix-types-0.601.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasmparser-0.221.3\",\n sha256 = \"d06bfa36ab3ac2be0dee563380147a5b81ba10dd8885d7fbbc9eb574be67d185\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasmparser/0.221.3/download\"],\n strip_prefix = \"wasmparser-0.221.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasmparser-0.221.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasmparser-0.224.1\",\n sha256 = \"04f17a5917c2ddd3819e84c661fae0d6ba29d7b9c1f0e96c708c65a9c4188e11\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasmparser/0.224.1/download\"],\n strip_prefix = \"wasmparser-0.224.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasmparser-0.224.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wasmparser-0.235.0\",\n sha256 = \"161296c618fa2d63f6ed5fffd1112937e803cb9ec71b32b01a76321555660917\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasmparser/0.235.0/download\"],\n strip_prefix = \"wasmparser-0.235.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wasmparser-0.235.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wast-221.0.3\",\n sha256 = \"7e0d10d282261b825ffb3d49f46e8309e60a8b608328b6a0b0578e80f3f98e57\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wast/221.0.3/download\"],\n strip_prefix = \"wast-221.0.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wast-221.0.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__wat-1.221.3\",\n sha256 = \"d744e4500534bada448bf611109a6b972160f94c8e8bcbe421e7be06ea346520\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wat/1.221.3/download\"],\n strip_prefix = \"wat-1.221.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.wat-1.221.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__web-sys-0.3.78\",\n sha256 = \"77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/web-sys/0.3.78/download\"],\n strip_prefix = \"web-sys-0.3.78\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.web-sys-0.3.78.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__web-time-1.1.0\",\n sha256 = \"5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/web-time/1.1.0/download\"],\n strip_prefix = \"web-time-1.1.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.web-time-1.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__webc-10.0.1\",\n sha256 = \"637506ca3c48eae3301e97f0167aa1b46cdfdd479d008b868a19715182e48ae3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/webc/10.0.1/download\"],\n strip_prefix = \"webc-10.0.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.webc-10.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__weezl-0.1.7\",\n sha256 = \"9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/weezl/0.1.7/download\"],\n strip_prefix = \"weezl-0.1.7\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.weezl-0.1.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__winapi-0.3.9\",\n sha256 = \"5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/winapi/0.3.9/download\"],\n strip_prefix = \"winapi-0.3.9\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.winapi-0.3.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__winapi-i686-pc-windows-gnu-0.4.0\",\n sha256 = \"ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/winapi-i686-pc-windows-gnu/0.4.0/download\"],\n strip_prefix = \"winapi-i686-pc-windows-gnu-0.4.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.winapi-i686-pc-windows-gnu-0.4.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__winapi-util-0.1.6\",\n sha256 = \"f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/winapi-util/0.1.6/download\"],\n strip_prefix = \"winapi-util-0.1.6\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.winapi-util-0.1.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__winapi-x86_64-pc-windows-gnu-0.4.0\",\n sha256 = \"712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/winapi-x86_64-pc-windows-gnu/0.4.0/download\"],\n strip_prefix = \"winapi-x86_64-pc-windows-gnu-0.4.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.winapi-x86_64-pc-windows-gnu-0.4.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows-core-0.52.0\",\n sha256 = \"33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-core/0.52.0/download\"],\n strip_prefix = \"windows-core-0.52.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows-core-0.52.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows-link-0.1.1\",\n sha256 = \"76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-link/0.1.1/download\"],\n strip_prefix = \"windows-link-0.1.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows-link-0.1.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows-registry-0.2.0\",\n sha256 = \"e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-registry/0.2.0/download\"],\n strip_prefix = \"windows-registry-0.2.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows-registry-0.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows-result-0.2.0\",\n sha256 = \"1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-result/0.2.0/download\"],\n strip_prefix = \"windows-result-0.2.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows-result-0.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows-strings-0.1.0\",\n sha256 = \"4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-strings/0.1.0/download\"],\n strip_prefix = \"windows-strings-0.1.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows-strings-0.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows-sys-0.48.0\",\n sha256 = \"677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-sys/0.48.0/download\"],\n strip_prefix = \"windows-sys-0.48.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows-sys-0.48.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows-sys-0.52.0\",\n sha256 = \"282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-sys/0.52.0/download\"],\n strip_prefix = \"windows-sys-0.52.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows-sys-0.52.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows-sys-0.59.0\",\n sha256 = \"1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-sys/0.59.0/download\"],\n strip_prefix = \"windows-sys-0.59.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows-sys-0.59.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows-targets-0.48.5\",\n sha256 = \"9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-targets/0.48.5/download\"],\n strip_prefix = \"windows-targets-0.48.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows-targets-0.48.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows-targets-0.52.6\",\n sha256 = \"9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-targets/0.52.6/download\"],\n strip_prefix = \"windows-targets-0.52.6\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows-targets-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows_aarch64_gnullvm-0.48.5\",\n sha256 = \"2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_aarch64_gnullvm/0.48.5/download\"],\n strip_prefix = \"windows_aarch64_gnullvm-0.48.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows_aarch64_gnullvm-0.48.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows_aarch64_gnullvm-0.52.6\",\n sha256 = \"32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_aarch64_gnullvm/0.52.6/download\"],\n strip_prefix = \"windows_aarch64_gnullvm-0.52.6\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows_aarch64_gnullvm-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows_aarch64_msvc-0.48.5\",\n sha256 = \"dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_aarch64_msvc/0.48.5/download\"],\n strip_prefix = \"windows_aarch64_msvc-0.48.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows_aarch64_msvc-0.48.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows_aarch64_msvc-0.52.6\",\n sha256 = \"09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_aarch64_msvc/0.52.6/download\"],\n strip_prefix = \"windows_aarch64_msvc-0.52.6\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows_aarch64_msvc-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows_i686_gnu-0.48.5\",\n sha256 = \"a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_i686_gnu/0.48.5/download\"],\n strip_prefix = \"windows_i686_gnu-0.48.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows_i686_gnu-0.48.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows_i686_gnu-0.52.6\",\n sha256 = \"8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_i686_gnu/0.52.6/download\"],\n strip_prefix = \"windows_i686_gnu-0.52.6\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows_i686_gnu-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows_i686_gnullvm-0.52.6\",\n sha256 = \"0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_i686_gnullvm/0.52.6/download\"],\n strip_prefix = \"windows_i686_gnullvm-0.52.6\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows_i686_gnullvm-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows_i686_msvc-0.48.5\",\n sha256 = \"8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_i686_msvc/0.48.5/download\"],\n strip_prefix = \"windows_i686_msvc-0.48.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows_i686_msvc-0.48.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows_i686_msvc-0.52.6\",\n sha256 = \"240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_i686_msvc/0.52.6/download\"],\n strip_prefix = \"windows_i686_msvc-0.52.6\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows_i686_msvc-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows_x86_64_gnu-0.48.5\",\n sha256 = \"53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_x86_64_gnu/0.48.5/download\"],\n strip_prefix = \"windows_x86_64_gnu-0.48.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows_x86_64_gnu-0.48.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows_x86_64_gnu-0.52.6\",\n sha256 = \"147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_x86_64_gnu/0.52.6/download\"],\n strip_prefix = \"windows_x86_64_gnu-0.52.6\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows_x86_64_gnu-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows_x86_64_gnullvm-0.48.5\",\n sha256 = \"0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_x86_64_gnullvm/0.48.5/download\"],\n strip_prefix = \"windows_x86_64_gnullvm-0.48.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows_x86_64_gnullvm-0.48.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows_x86_64_gnullvm-0.52.6\",\n sha256 = \"24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_x86_64_gnullvm/0.52.6/download\"],\n strip_prefix = \"windows_x86_64_gnullvm-0.52.6\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows_x86_64_gnullvm-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows_x86_64_msvc-0.48.5\",\n sha256 = \"ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_x86_64_msvc/0.48.5/download\"],\n strip_prefix = \"windows_x86_64_msvc-0.48.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows_x86_64_msvc-0.48.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__windows_x86_64_msvc-0.52.6\",\n sha256 = \"589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_x86_64_msvc/0.52.6/download\"],\n strip_prefix = \"windows_x86_64_msvc-0.52.6\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.windows_x86_64_msvc-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__winnow-0.5.33\",\n sha256 = \"b7520bbdec7211caa7c4e682eb1fbe07abe20cee6756b6e00f537c82c11816aa\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/winnow/0.5.33/download\"],\n strip_prefix = \"winnow-0.5.33\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.winnow-0.5.33.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__winnow-0.6.13\",\n sha256 = \"59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/winnow/0.6.13/download\"],\n strip_prefix = \"winnow-0.6.13\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.winnow-0.6.13.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__write16-1.0.0\",\n sha256 = \"d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/write16/1.0.0/download\"],\n strip_prefix = \"write16-1.0.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.write16-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__writeable-0.5.5\",\n sha256 = \"1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/writeable/0.5.5/download\"],\n strip_prefix = \"writeable-0.5.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.writeable-0.5.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__xattr-1.2.0\",\n sha256 = \"914566e6413e7fa959cc394fb30e563ba80f3541fbd40816d4c05a0fc3f2a0f1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/xattr/1.2.0/download\"],\n strip_prefix = \"xattr-1.2.0\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.xattr-1.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__xxhash-rust-0.8.11\",\n sha256 = \"63658493314859b4dfdf3fb8c1defd61587839def09582db50b8a4e93afca6bb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/xxhash-rust/0.8.11/download\"],\n strip_prefix = \"xxhash-rust-0.8.11\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.xxhash-rust-0.8.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__yansi-1.0.1\",\n sha256 = \"cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/yansi/1.0.1/download\"],\n strip_prefix = \"yansi-1.0.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.yansi-1.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__yoke-0.7.5\",\n sha256 = \"120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/yoke/0.7.5/download\"],\n strip_prefix = \"yoke-0.7.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.yoke-0.7.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__yoke-derive-0.7.5\",\n sha256 = \"2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/yoke-derive/0.7.5/download\"],\n strip_prefix = \"yoke-derive-0.7.5\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.yoke-derive-0.7.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__zerocopy-0.7.35\",\n sha256 = \"1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerocopy/0.7.35/download\"],\n strip_prefix = \"zerocopy-0.7.35\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.zerocopy-0.7.35.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__zerocopy-0.8.24\",\n sha256 = \"2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerocopy/0.8.24/download\"],\n strip_prefix = \"zerocopy-0.8.24\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.zerocopy-0.8.24.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__zerocopy-derive-0.7.35\",\n sha256 = \"fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerocopy-derive/0.7.35/download\"],\n strip_prefix = \"zerocopy-derive-0.7.35\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.zerocopy-derive-0.7.35.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__zerocopy-derive-0.8.24\",\n sha256 = \"a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerocopy-derive/0.8.24/download\"],\n strip_prefix = \"zerocopy-derive-0.8.24\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.zerocopy-derive-0.8.24.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__zerofrom-0.1.6\",\n sha256 = \"50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerofrom/0.1.6/download\"],\n strip_prefix = \"zerofrom-0.1.6\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.zerofrom-0.1.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__zerofrom-derive-0.1.6\",\n sha256 = \"d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerofrom-derive/0.1.6/download\"],\n strip_prefix = \"zerofrom-derive-0.1.6\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.zerofrom-derive-0.1.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__zeroize-1.8.1\",\n sha256 = \"ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zeroize/1.8.1/download\"],\n strip_prefix = \"zeroize-1.8.1\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.zeroize-1.8.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__zerovec-0.10.4\",\n sha256 = \"aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerovec/0.10.4/download\"],\n strip_prefix = \"zerovec-0.10.4\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.zerovec-0.10.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"browser_cargo__zerovec-derive-0.10.3\",\n sha256 = \"6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerovec-derive/0.10.3/download\"],\n strip_prefix = \"zerovec-derive-0.10.3\",\n build_file = Label(\"@browser_cargo//browser_cargo:BUILD.zerovec-derive-0.10.3.bazel\"),\n )\n\n return [\n struct(repo = \"browser_cargo\", is_dev_dep = False),\n struct(repo=\"browser_cargo__anyhow-1.0.97\", is_dev_dep = False),\n struct(repo=\"browser_cargo__async-trait-0.1.88\", is_dev_dep = False),\n struct(repo=\"browser_cargo__bincode-1.3.3\", is_dev_dep = False),\n struct(repo=\"browser_cargo__bytes-1.10.1\", is_dev_dep = False),\n struct(repo=\"browser_cargo__console_error_panic_hook-0.1.7\", is_dev_dep = False),\n struct(repo=\"browser_cargo__derivative-2.2.0\", is_dev_dep = False),\n struct(repo=\"browser_cargo__futures-0.3.30\", is_dev_dep = False),\n struct(repo=\"browser_cargo__instant-0.1.12\", is_dev_dep = False),\n struct(repo=\"browser_cargo__js-sys-0.3.78\", is_dev_dep = False),\n struct(repo=\"browser_cargo__lazy_static-1.5.0\", is_dev_dep = False),\n struct(repo=\"browser_cargo__once_cell-1.19.0\", is_dev_dep = False),\n struct(repo=\"browser_cargo__reqwest-0.12.7\", is_dev_dep = False),\n struct(repo=\"browser_cargo__serde-1.0.219\", is_dev_dep = False),\n struct(repo=\"browser_cargo__serde-wasm-bindgen-0.6.5\", is_dev_dep = False),\n struct(repo=\"browser_cargo__sha2-0.10.8\", is_dev_dep = False),\n struct(repo=\"browser_cargo__tempfile-3.12.0\", is_dev_dep = False),\n struct(repo=\"browser_cargo__tokio-1.44.2\", is_dev_dep = False),\n struct(repo=\"browser_cargo__toml-0.8.14\", is_dev_dep = False),\n struct(repo=\"browser_cargo__tracing-0.1.41\", is_dev_dep = False),\n struct(repo=\"browser_cargo__tracing-subscriber-0.3.18\", is_dev_dep = False),\n struct(repo=\"browser_cargo__url-2.5.4\", is_dev_dep = False),\n struct(repo=\"browser_cargo__virtual-fs-0.601.0\", is_dev_dep = False),\n struct(repo=\"browser_cargo__virtual-net-0.601.0\", is_dev_dep = False),\n struct(repo=\"browser_cargo__wasm-bindgen-0.2.101\", is_dev_dep = False),\n struct(repo=\"browser_cargo__wasm-bindgen-derive-0.2.1\", is_dev_dep = False),\n struct(repo=\"browser_cargo__wasm-bindgen-futures-0.4.51\", is_dev_dep = False),\n struct(repo=\"browser_cargo__wasm-bindgen-test-0.3.51\", is_dev_dep = False),\n struct(repo=\"browser_cargo__wasmer-6.1.0\", is_dev_dep = False),\n struct(repo=\"browser_cargo__wasmer-backend-api-0.601.0\", is_dev_dep = False),\n struct(repo=\"browser_cargo__wasmer-config-0.601.0\", is_dev_dep = False),\n struct(repo=\"browser_cargo__wasmer-package-0.601.0\", is_dev_dep = False),\n struct(repo=\"browser_cargo__wasmer-types-6.1.0\", is_dev_dep = False),\n struct(repo=\"browser_cargo__wasmer-wasix-0.601.0\", is_dev_dep = False),\n struct(repo=\"browser_cargo__web-sys-0.3.78\", is_dev_dep = False),\n struct(repo=\"browser_cargo__webc-10.0.1\", is_dev_dep = False),\n ]\n", + "defs.bzl": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\"\"\"Deprecated: re-exports the crate_universe macros from `:crates.bzl`.\"\"\"\n\nload(\n \":crates.bzl\",\n _aliases = \"aliases\",\n _all_crate_deps = \"all_crate_deps\",\n _crate_deps = \"crate_deps\",\n _crate_edition = \"crate_edition\",\n _crate_repositories = \"crate_repositories\",\n)\n\naliases = _aliases\nall_crate_deps = _all_crate_deps\ncrate_deps = _crate_deps\ncrate_edition = _crate_edition\ncrate_repositories = _crate_repositories\n", + "cargo-bazel.json": "{\"checksum\":\"e38b1a76b8f2b7bceab2c9674761d2ab80c505a05ed7fa867f2b1441b1ba5263\",\"conditions\":{\"aarch64-linux-android\":[],\"aarch64-pc-windows-gnullvm\":[],\"cfg(all(any(target_arch = \\\"x86_64\\\", target_arch = \\\"arm64ec\\\"), target_env = \\\"msvc\\\", not(windows_raw_dylib)))\":[],\"cfg(all(any(target_os = \\\"android\\\", target_os = \\\"linux\\\"), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", target_endian = \\\"little\\\", any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\":[],\"cfg(all(any(target_os = \\\"android\\\", target_os = \\\"linux\\\"), any(target_arch = \\\"aarch64\\\", target_arch = \\\"arm\\\")))\":[],\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", target_endian = \\\"little\\\", any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\":[\"x86_64-unknown-linux-gnu\"],\"cfg(all(not(target_arch = \\\"wasm32\\\"), target_os = \\\"windows\\\"))\":[],\"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", target_endian = \\\"little\\\", any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\":[\"wasm32-unknown-unknown\"],\"cfg(all(target_arch = \\\"aarch64\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\":[],\"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"linux\\\"))\":[],\"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"windows\\\"))\":[],\"cfg(all(target_arch = \\\"aarch64\\\", target_vendor = \\\"apple\\\"))\":[],\"cfg(all(target_arch = \\\"loongarch64\\\", target_os = \\\"linux\\\"))\":[],\"cfg(all(target_arch = \\\"wasm32\\\", wasm_bindgen_unstable_test_coverage))\":[],\"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"gnu\\\", not(target_abi = \\\"llvm\\\"), not(windows_raw_dylib)))\":[],\"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"gnu\\\", not(windows_raw_dylib)))\":[],\"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\":[],\"cfg(all(target_arch = \\\"x86_64\\\", target_env = \\\"gnu\\\", not(target_abi = \\\"llvm\\\"), not(windows_raw_dylib)))\":[\"x86_64-unknown-linux-gnu\"],\"cfg(all(target_arch = \\\"x86_64\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\":[],\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\"))\":[\"wasm32-unknown-unknown\"],\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"wasi\\\"))\":[],\"cfg(all(target_os = \\\"macos\\\", target_arch = \\\"aarch64\\\"))\":[],\"cfg(all(unix, not(target_os = \\\"ios\\\")))\":[\"x86_64-unknown-linux-gnu\"],\"cfg(any())\":[],\"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"arm\\\", target_arch = \\\"x86\\\", target_arch = \\\"x86_64\\\"))\":[\"x86_64-unknown-linux-gnu\"],\"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\":[\"x86_64-unknown-linux-gnu\"],\"cfg(any(target_family = \\\"unix\\\", all(target_family = \\\"windows\\\", target_env = \\\"gnu\\\")))\":[\"x86_64-unknown-linux-gnu\"],\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"freebsd\\\", target_os = \\\"netbsd\\\"))\":[],\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"ios\\\"))\":[],\"cfg(any(unix, target_os = \\\"wasi\\\"))\":[\"x86_64-unknown-linux-gnu\"],\"cfg(not(all(target_arch = \\\"arm\\\", target_os = \\\"none\\\")))\":[\"wasm32-unknown-unknown\",\"x86_64-unknown-linux-gnu\"],\"cfg(not(all(windows, target_env = \\\"msvc\\\", not(target_vendor = \\\"uwp\\\"))))\":[\"wasm32-unknown-unknown\",\"x86_64-unknown-linux-gnu\"],\"cfg(not(any(target_os = \\\"windows\\\", target_vendor = \\\"apple\\\")))\":[\"wasm32-unknown-unknown\",\"x86_64-unknown-linux-gnu\"],\"cfg(not(target_arch = \\\"wasm32\\\"))\":[\"x86_64-unknown-linux-gnu\"],\"cfg(not(target_env = \\\"musl\\\"))\":[\"wasm32-unknown-unknown\",\"x86_64-unknown-linux-gnu\"],\"cfg(not(windows))\":[\"wasm32-unknown-unknown\",\"x86_64-unknown-linux-gnu\"],\"cfg(target_arch = \\\"spirv\\\")\":[],\"cfg(target_arch = \\\"wasm32\\\")\":[\"wasm32-unknown-unknown\"],\"cfg(target_env = \\\"musl\\\")\":[],\"cfg(target_family = \\\"wasm\\\")\":[\"wasm32-unknown-unknown\"],\"cfg(target_os = \\\"android\\\")\":[],\"cfg(target_os = \\\"haiku\\\")\":[],\"cfg(target_os = \\\"hermit\\\")\":[],\"cfg(target_os = \\\"linux\\\")\":[\"x86_64-unknown-linux-gnu\"],\"cfg(target_os = \\\"macos\\\")\":[],\"cfg(target_os = \\\"redox\\\")\":[],\"cfg(target_os = \\\"wasi\\\")\":[],\"cfg(target_os = \\\"windows\\\")\":[],\"cfg(target_vendor = \\\"apple\\\")\":[],\"cfg(tokio_taskdump)\":[],\"cfg(unix)\":[\"x86_64-unknown-linux-gnu\"],\"cfg(windows)\":[],\"i686-pc-windows-gnu\":[],\"i686-pc-windows-gnullvm\":[],\"wasm32-unknown-unknown\":[\"wasm32-unknown-unknown\"],\"x86_64-pc-windows-gnu\":[],\"x86_64-pc-windows-gnullvm\":[],\"x86_64-unknown-linux-gnu\":[\"x86_64-unknown-linux-gnu\"]},\"crates\":{\"addr2line 0.21.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"gimli 0.28.1\",\"target\":\"gimli\"}],\"edition\":\"2018\"},\"library_target_name\":\"addr2line\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"addr2line\",\"package_url\":\"https://github.com/gimli-rs/addr2line\",\"repository\":{\"Http\":{\"sha256\":\"8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb\",\"url\":\"https://static.crates.io/crates/addr2line/0.21.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"addr2line\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.21.0\"},\"adler 1.0.2\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"adler\",\"license\":\"0BSD OR MIT OR Apache-2.0\",\"license_file\":\"LICENSE-0BSD\",\"license_ids\":[\"0BSD\",\"Apache-2.0\",\"MIT\"],\"name\":\"adler\",\"package_url\":\"https://github.com/jonas-schievink/adler.git\",\"repository\":{\"Http\":{\"sha256\":\"f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe\",\"url\":\"https://static.crates.io/crates/adler/1.0.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"adler\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.2\"},\"adler2 2.0.0\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"adler2\",\"license\":\"0BSD OR MIT OR Apache-2.0\",\"license_file\":\"LICENSE-0BSD\",\"license_ids\":[\"0BSD\",\"Apache-2.0\",\"MIT\"],\"name\":\"adler2\",\"package_url\":\"https://github.com/oyvindln/adler2\",\"repository\":{\"Http\":{\"sha256\":\"512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627\",\"url\":\"https://static.crates.io/crates/adler2/2.0.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"adler2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.0.0\"},\"ahash 0.8.11\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"version_check 0.9.5\",\"target\":\"version_check\"}]},\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"},{\"id\":\"zerocopy 0.7.35\",\"target\":\"zerocopy\"}],\"selects\":{\"cfg(not(all(target_arch = \\\"arm\\\", target_os = \\\"none\\\")))\":[{\"id\":\"once_cell 1.19.0\",\"target\":\"once_cell\"}]}},\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"ahash\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"ahash\",\"package_url\":\"https://github.com/tkaitchuck/ahash\",\"repository\":{\"Http\":{\"sha256\":\"e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011\",\"url\":\"https://static.crates.io/crates/ahash/0.8.11/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ahash\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.8.11\"},\"aho-corasick 1.1.2\":{\"common_attrs\":{\"crate_features\":[\"default\",\"perf-literal\",\"std\"],\"deps\":[{\"id\":\"memchr 2.7.1\",\"target\":\"memchr\"}],\"edition\":\"2021\"},\"library_target_name\":\"aho_corasick\",\"license\":\"Unlicense OR MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"aho-corasick\",\"package_url\":\"https://github.com/BurntSushi/aho-corasick\",\"repository\":{\"Http\":{\"sha256\":\"b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0\",\"url\":\"https://static.crates.io/crates/aho-corasick/1.1.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"aho_corasick\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.2\"},\"aliasable 0.1.3\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\"],\"edition\":\"2018\"},\"library_target_name\":\"aliasable\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"aliasable\",\"package_url\":\"https://github.com/avitex/rust-aliasable\",\"repository\":{\"Http\":{\"sha256\":\"250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd\",\"url\":\"https://static.crates.io/crates/aliasable/0.1.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"aliasable\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.3\"},\"android-tzdata 0.1.1\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"android_tzdata\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"android-tzdata\",\"package_url\":\"https://github.com/RumovZ/android-tzdata\",\"repository\":{\"Http\":{\"sha256\":\"e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0\",\"url\":\"https://static.crates.io/crates/android-tzdata/0.1.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"android_tzdata\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.1\"},\"android_system_properties 0.1.5\":{\"common_attrs\":{\"deps\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"edition\":\"2018\"},\"library_target_name\":\"android_system_properties\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"android_system_properties\",\"package_url\":\"https://github.com/nical/android_system_properties\",\"repository\":{\"Http\":{\"sha256\":\"819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311\",\"url\":\"https://static.crates.io/crates/android_system_properties/0.1.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"android_system_properties\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.5\"},\"any_ascii 0.1.7\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"any_ascii\",\"license\":\"ISC\",\"license_file\":\"LICENSE\",\"license_ids\":[\"ISC\"],\"name\":\"any_ascii\",\"package_url\":\"https://github.com/anyascii/anyascii\",\"repository\":{\"Http\":{\"sha256\":\"70033777eb8b5124a81a1889416543dddef2de240019b674c81285a2635a7e1e\",\"url\":\"https://static.crates.io/crates/any_ascii/0.1.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"any_ascii\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.7\"},\"anyhow 1.0.97\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"anyhow\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"anyhow\",\"package_url\":\"https://github.com/dtolnay/anyhow\",\"repository\":{\"Http\":{\"sha256\":\"dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f\",\"url\":\"https://static.crates.io/crates/anyhow/1.0.97/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"anyhow\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.97\"},\"arrayref 0.3.7\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"arrayref\",\"license\":\"BSD-2-Clause\",\"license_file\":\"LICENSE\",\"license_ids\":[\"BSD-2-Clause\"],\"name\":\"arrayref\",\"package_url\":\"https://github.com/droundy/arrayref\",\"repository\":{\"Http\":{\"sha256\":\"6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545\",\"url\":\"https://static.crates.io/crates/arrayref/0.3.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"arrayref\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.7\"},\"arrayvec 0.7.4\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"arrayvec\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"arrayvec\",\"package_url\":\"https://github.com/bluss/arrayvec\",\"repository\":{\"Http\":{\"sha256\":\"96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711\",\"url\":\"https://static.crates.io/crates/arrayvec/0.7.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"arrayvec\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.4\"},\"async-trait 0.1.88\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"async_trait\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"async-trait\",\"package_url\":\"https://github.com/dtolnay/async-trait\",\"repository\":{\"Http\":{\"sha256\":\"e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5\",\"url\":\"https://static.crates.io/crates/async-trait/0.1.88/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"async_trait\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.88\"},\"atomic-waker 1.1.2\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"atomic_waker\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"atomic-waker\",\"package_url\":\"https://github.com/smol-rs/atomic-waker\",\"repository\":{\"Http\":{\"sha256\":\"1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0\",\"url\":\"https://static.crates.io/crates/atomic-waker/1.1.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"atomic_waker\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.2\"},\"autocfg 1.1.0\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"autocfg\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"autocfg\",\"package_url\":\"https://github.com/cuviper/autocfg\",\"repository\":{\"Http\":{\"sha256\":\"d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa\",\"url\":\"https://static.crates.io/crates/autocfg/1.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"autocfg\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.0\"},\"backtrace 0.3.69\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"cc 1.2.18\",\"target\":\"cc\"}]},\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"},{\"id\":\"rustc-demangle 0.1.23\",\"target\":\"rustc_demangle\"}],\"selects\":{\"cfg(not(all(windows, target_env = \\\"msvc\\\", not(target_vendor = \\\"uwp\\\"))))\":[{\"id\":\"addr2line 0.21.0\",\"target\":\"addr2line\"},{\"id\":\"libc 0.2.171\",\"target\":\"libc\"},{\"id\":\"miniz_oxide 0.7.1\",\"target\":\"miniz_oxide\"},{\"id\":\"object 0.32.2\",\"target\":\"object\"}]}},\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"backtrace\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"backtrace\",\"package_url\":\"https://github.com/rust-lang/backtrace-rs\",\"repository\":{\"Http\":{\"sha256\":\"2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837\",\"url\":\"https://static.crates.io/crates/backtrace/0.3.69/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"backtrace\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.3.69\"},\"base64 0.22.1\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"base64\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"base64\",\"package_url\":\"https://github.com/marshallpierce/rust-base64\",\"repository\":{\"Http\":{\"sha256\":\"72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6\",\"url\":\"https://static.crates.io/crates/base64/0.22.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"base64\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.22.1\"},\"beef 0.5.2\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"edition\":\"2018\"},\"library_target_name\":\"beef\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"beef\",\"package_url\":\"https://github.com/maciejhirsz/beef\",\"repository\":{\"Http\":{\"sha256\":\"3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1\",\"url\":\"https://static.crates.io/crates/beef/0.5.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"beef\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.2\"},\"bincode 1.3.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"serde 1.0.219\",\"target\":\"serde\"}],\"edition\":\"2015\"},\"library_target_name\":\"bincode\",\"license\":\"MIT\",\"license_file\":\"LICENSE.md\",\"license_ids\":[\"MIT\"],\"name\":\"bincode\",\"package_url\":\"https://github.com/servo/bincode\",\"repository\":{\"Http\":{\"sha256\":\"b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad\",\"url\":\"https://static.crates.io/crates/bincode/1.3.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bincode\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.3.3\"},\"bindgen 0.70.1\":{\"build_script_attrs\":{\"link_deps\":[{\"id\":\"clang-sys 1.8.1\",\"target\":\"clang_sys\"},{\"id\":\"prettyplease 0.2.32\",\"target\":\"prettyplease\"}]},\"common_attrs\":{\"crate_features\":[\"default\",\"logging\",\"prettyplease\",\"runtime\"],\"deps\":[{\"id\":\"bitflags 2.9.0\",\"target\":\"bitflags\"},{\"id\":\"cexpr 0.6.0\",\"target\":\"cexpr\"},{\"id\":\"clang-sys 1.8.1\",\"target\":\"clang_sys\"},{\"id\":\"itertools 0.12.1\",\"target\":\"itertools\"},{\"id\":\"log 0.4.20\",\"target\":\"log\"},{\"id\":\"prettyplease 0.2.32\",\"target\":\"prettyplease\"},{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"regex 1.10.2\",\"target\":\"regex\"},{\"id\":\"rustc-hash 1.1.0\",\"target\":\"rustc_hash\"},{\"id\":\"shlex 1.3.0\",\"target\":\"shlex\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"bindgen\",\"license\":\"BSD-3-Clause\",\"license_file\":\"LICENSE\",\"license_ids\":[\"BSD-3-Clause\"],\"name\":\"bindgen\",\"package_url\":\"https://github.com/rust-lang/rust-bindgen\",\"repository\":{\"Http\":{\"sha256\":\"f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f\",\"url\":\"https://static.crates.io/crates/bindgen/0.70.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bindgen\",\"crate_root\":\"lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.70.1\"},\"bitflags 1.3.2\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"edition\":\"2018\"},\"library_target_name\":\"bitflags\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"bitflags\",\"package_url\":\"https://github.com/bitflags/bitflags\",\"repository\":{\"Http\":{\"sha256\":\"bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a\",\"url\":\"https://static.crates.io/crates/bitflags/1.3.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bitflags\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.3.2\"},\"bitflags 2.9.0\":{\"common_attrs\":{\"crate_features\":{\"common\":[],\"selects\":{\"x86_64-unknown-linux-gnu\":[\"std\"]}},\"edition\":\"2021\"},\"library_target_name\":\"bitflags\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"bitflags\",\"package_url\":\"https://github.com/bitflags/bitflags\",\"repository\":{\"Http\":{\"sha256\":\"5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd\",\"url\":\"https://static.crates.io/crates/bitflags/2.9.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bitflags\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.9.0\"},\"blake3 1.5.1\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"cc 1.2.18\",\"target\":\"cc\"}]},\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"arrayref 0.3.7\",\"target\":\"arrayref\"},{\"id\":\"arrayvec 0.7.4\",\"target\":\"arrayvec\"},{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"},{\"id\":\"constant_time_eq 0.3.0\",\"target\":\"constant_time_eq\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"blake3\",\"license\":\"CC0-1.0 OR Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\",\"CC0-1.0\"],\"name\":\"blake3\",\"package_url\":\"https://github.com/BLAKE3-team/BLAKE3\",\"repository\":{\"Http\":{\"sha256\":\"30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52\",\"url\":\"https://static.crates.io/crates/blake3/1.5.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"blake3\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.5.1\"},\"block-buffer 0.10.4\":{\"common_attrs\":{\"deps\":[{\"id\":\"generic-array 0.14.7\",\"target\":\"generic_array\"}],\"edition\":\"2018\"},\"library_target_name\":\"block_buffer\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"block-buffer\",\"package_url\":\"https://github.com/RustCrypto/utils\",\"repository\":{\"Http\":{\"sha256\":\"3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71\",\"url\":\"https://static.crates.io/crates/block-buffer/0.10.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"block_buffer\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.10.4\"},\"bstr 1.9.1\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"std\"],\"deps\":[{\"id\":\"memchr 2.7.1\",\"target\":\"memchr\"}],\"edition\":\"2021\"},\"library_target_name\":\"bstr\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"bstr\",\"package_url\":\"https://github.com/BurntSushi/bstr\",\"repository\":{\"Http\":{\"sha256\":\"05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706\",\"url\":\"https://static.crates.io/crates/bstr/1.9.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bstr\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.9.1\"},\"bumpalo 3.14.0\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"edition\":\"2021\"},\"library_target_name\":\"bumpalo\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"bumpalo\",\"package_url\":\"https://github.com/fitzgen/bumpalo\",\"repository\":{\"Http\":{\"sha256\":\"7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec\",\"url\":\"https://static.crates.io/crates/bumpalo/3.14.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bumpalo\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"3.14.0\"},\"bus 2.4.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"crossbeam-channel 0.5.15\",\"target\":\"crossbeam_channel\"},{\"id\":\"num_cpus 1.17.0\",\"target\":\"num_cpus\"},{\"id\":\"parking_lot_core 0.9.9\",\"target\":\"parking_lot_core\"}],\"edition\":\"2018\"},\"library_target_name\":\"bus\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"bus\",\"package_url\":\"https://github.com/jonhoo/bus.git\",\"repository\":{\"Http\":{\"sha256\":\"4b7118d0221d84fada881b657c2ddb7cd55108db79c8764c9ee212c0c259b783\",\"url\":\"https://static.crates.io/crates/bus/2.4.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bus\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.4.1\"},\"bytecheck 0.6.11\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"simdutf8\",\"std\"],\"deps\":[{\"id\":\"ptr_meta 0.1.4\",\"target\":\"ptr_meta\"},{\"id\":\"simdutf8 0.1.4\",\"target\":\"simdutf8\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":[{\"id\":\"bytecheck_derive 0.6.11\",\"target\":\"bytecheck_derive\"}]},\"library_target_name\":\"bytecheck\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"bytecheck\",\"package_url\":\"https://github.com/djkoloski/bytecheck\",\"repository\":{\"Http\":{\"sha256\":\"8b6372023ac861f6e6dc89c8344a8f398fb42aaba2b5dbc649ca0c0e9dbcb627\",\"url\":\"https://static.crates.io/crates/bytecheck/0.6.11/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bytecheck\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.6.11\"},\"bytecheck 0.8.1\":{\"common_attrs\":{\"crate_features\":[\"simdutf8\"],\"deps\":[{\"id\":\"ptr_meta 0.3.0\",\"target\":\"ptr_meta\"},{\"id\":\"rancor 0.1.0\",\"target\":\"rancor\"},{\"id\":\"simdutf8 0.1.4\",\"target\":\"simdutf8\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"bytecheck_derive 0.8.1\",\"target\":\"bytecheck_derive\"}]},\"library_target_name\":\"bytecheck\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"bytecheck\",\"package_url\":\"https://github.com/rkyv/bytecheck\",\"repository\":{\"Http\":{\"sha256\":\"50690fb3370fb9fe3550372746084c46f2ac8c9685c583d2be10eefd89d3d1a3\",\"url\":\"https://static.crates.io/crates/bytecheck/0.8.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bytecheck\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.1\"},\"bytecheck_derive 0.6.11\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 1.0.109\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"bytecheck_derive\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"bytecheck_derive\",\"package_url\":\"https://github.com/djkoloski/bytecheck\",\"repository\":{\"Http\":{\"sha256\":\"a7ec4c6f261935ad534c0c22dbef2201b45918860eb1c574b972bd213a76af61\",\"url\":\"https://static.crates.io/crates/bytecheck_derive/0.6.11/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"bytecheck_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.11\"},\"bytecheck_derive 0.8.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"bytecheck_derive\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"bytecheck_derive\",\"package_url\":\"https://github.com/rkyv/bytecheck\",\"repository\":{\"Http\":{\"sha256\":\"efb7846e0cb180355c2dec69e721edafa36919850f1a9f52ffba4ebc0393cb71\",\"url\":\"https://static.crates.io/crates/bytecheck_derive/0.8.1/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"bytecheck_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.1\"},\"byteorder 1.5.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"byteorder\",\"license\":\"Unlicense OR MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"byteorder\",\"package_url\":\"https://github.com/BurntSushi/byteorder\",\"repository\":{\"Http\":{\"sha256\":\"1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b\",\"url\":\"https://static.crates.io/crates/byteorder/1.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"byteorder\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.5.0\"},\"bytes 1.10.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"serde\",\"std\"],\"deps\":[{\"id\":\"serde 1.0.219\",\"target\":\"serde\"}],\"edition\":\"2018\"},\"library_target_name\":\"bytes\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"bytes\",\"package_url\":\"https://github.com/tokio-rs/bytes\",\"repository\":{\"Http\":{\"sha256\":\"d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a\",\"url\":\"https://static.crates.io/crates/bytes/1.10.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bytes\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.10.1\"},\"bytesize 1.3.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"serde\"],\"deps\":[{\"id\":\"serde 1.0.219\",\"target\":\"serde\"}],\"edition\":\"2015\"},\"library_target_name\":\"bytesize\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"bytesize\",\"package_url\":\"https://github.com/hyunsik/bytesize/\",\"repository\":{\"Http\":{\"sha256\":\"a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc\",\"url\":\"https://static.crates.io/crates/bytesize/1.3.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bytesize\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.3.0\"},\"cc 1.2.18\":{\"common_attrs\":{\"deps\":[{\"id\":\"shlex 1.3.0\",\"target\":\"shlex\"}],\"edition\":\"2018\"},\"library_target_name\":\"cc\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"cc\",\"package_url\":\"https://github.com/rust-lang/cc-rs\",\"repository\":{\"Http\":{\"sha256\":\"525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c\",\"url\":\"https://static.crates.io/crates/cc/1.2.18/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cc\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.18\"},\"cexpr 0.6.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"nom 7.1.3\",\"target\":\"nom\"}],\"edition\":\"2018\"},\"library_target_name\":\"cexpr\",\"license\":\"Apache-2.0/MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"cexpr\",\"package_url\":\"https://github.com/jethrogb/rust-cexpr\",\"repository\":{\"Http\":{\"sha256\":\"6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766\",\"url\":\"https://static.crates.io/crates/cexpr/0.6.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cexpr\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.0\"},\"cfg-if 1.0.0\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"cfg_if\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"cfg-if\",\"package_url\":\"https://github.com/alexcrichton/cfg-if\",\"repository\":{\"Http\":{\"sha256\":\"baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd\",\"url\":\"https://static.crates.io/crates/cfg-if/1.0.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cfg_if\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.0\"},\"chrono 0.4.40\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"android-tzdata\",\"clock\",\"iana-time-zone\",\"js-sys\",\"now\",\"std\",\"wasm-bindgen\",\"wasmbind\",\"winapi\",\"windows-link\"],\"deps\":{\"common\":[{\"id\":\"num-traits 0.2.17\",\"target\":\"num_traits\"}],\"selects\":{\"wasm32-unknown-unknown\":[{\"id\":\"js-sys 0.3.78\",\"target\":\"js_sys\"},{\"id\":\"wasm-bindgen 0.2.101\",\"target\":\"wasm_bindgen\"}],\"x86_64-unknown-linux-gnu\":[{\"id\":\"iana-time-zone 0.1.59\",\"target\":\"iana_time_zone\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"chrono\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE.txt\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"chrono\",\"package_url\":\"https://github.com/chronotope/chrono\",\"repository\":{\"Http\":{\"sha256\":\"1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c\",\"url\":\"https://static.crates.io/crates/chrono/0.4.40/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"chrono\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.40\"},\"ciborium 0.2.2\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"ciborium-io 0.2.2\",\"target\":\"ciborium_io\"},{\"id\":\"ciborium-ll 0.2.2\",\"target\":\"ciborium_ll\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"}],\"edition\":\"2021\"},\"library_target_name\":\"ciborium\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"ciborium\",\"package_url\":\"https://github.com/enarx/ciborium\",\"repository\":{\"Http\":{\"sha256\":\"42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e\",\"url\":\"https://static.crates.io/crates/ciborium/0.2.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ciborium\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.2\"},\"ciborium-io 0.2.2\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"ciborium_io\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"ciborium-io\",\"package_url\":\"https://github.com/enarx/ciborium\",\"repository\":{\"Http\":{\"sha256\":\"05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757\",\"url\":\"https://static.crates.io/crates/ciborium-io/0.2.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ciborium_io\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.2\"},\"ciborium-ll 0.2.2\":{\"common_attrs\":{\"deps\":[{\"id\":\"ciborium-io 0.2.2\",\"target\":\"ciborium_io\"},{\"id\":\"half 2.4.1\",\"target\":\"half\"}],\"edition\":\"2021\"},\"library_target_name\":\"ciborium_ll\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"ciborium-ll\",\"package_url\":\"https://github.com/enarx/ciborium\",\"repository\":{\"Http\":{\"sha256\":\"57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9\",\"url\":\"https://static.crates.io/crates/ciborium-ll/0.2.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ciborium_ll\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.2\"},\"clang-sys 1.8.1\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"glob 0.3.2\",\"target\":\"glob\"}],\"links\":\"clang\"},\"common_attrs\":{\"crate_features\":[\"clang_3_5\",\"clang_3_6\",\"clang_3_7\",\"clang_3_8\",\"clang_3_9\",\"clang_4_0\",\"clang_5_0\",\"clang_6_0\",\"libloading\",\"runtime\"],\"deps\":[{\"id\":\"glob 0.3.2\",\"target\":\"glob\"},{\"id\":\"libc 0.2.171\",\"target\":\"libc\"},{\"id\":\"libloading 0.8.6\",\"target\":\"libloading\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"clang_sys\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE.txt\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"clang-sys\",\"package_url\":\"https://github.com/KyleMayes/clang-sys\",\"repository\":{\"Http\":{\"sha256\":\"0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4\",\"url\":\"https://static.crates.io/crates/clang-sys/1.8.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"clang_sys\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.8.1\"},\"cmake 0.1.54\":{\"common_attrs\":{\"deps\":[{\"id\":\"cc 1.2.18\",\"target\":\"cc\"}],\"edition\":\"2021\"},\"library_target_name\":\"cmake\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"cmake\",\"package_url\":\"https://github.com/rust-lang/cmake-rs\",\"repository\":{\"Http\":{\"sha256\":\"e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0\",\"url\":\"https://static.crates.io/crates/cmake/0.1.54/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cmake\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.54\"},\"console 0.15.11\":{\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"},{\"id\":\"once_cell 1.19.0\",\"target\":\"once_cell\"}],\"selects\":{\"cfg(windows)\":[{\"id\":\"encode_unicode 1.0.0\",\"target\":\"encode_unicode\"},{\"id\":\"windows-sys 0.59.0\",\"target\":\"windows_sys\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"console\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"console\",\"package_url\":\"https://github.com/console-rs/console\",\"repository\":{\"Http\":{\"sha256\":\"054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8\",\"url\":\"https://static.crates.io/crates/console/0.15.11/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"console\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.15.11\"},\"console_error_panic_hook 0.1.7\":{\"common_attrs\":{\"deps\":[{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"},{\"id\":\"wasm-bindgen 0.2.101\",\"target\":\"wasm_bindgen\"}],\"edition\":\"2015\"},\"library_target_name\":\"console_error_panic_hook\",\"license\":\"Apache-2.0/MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"console_error_panic_hook\",\"package_url\":\"https://github.com/rustwasm/console_error_panic_hook\",\"repository\":{\"Http\":{\"sha256\":\"a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc\",\"url\":\"https://static.crates.io/crates/console_error_panic_hook/0.1.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"console_error_panic_hook\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.7\"},\"constant_time_eq 0.3.0\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"constant_time_eq\",\"license\":\"CC0-1.0 OR MIT-0 OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"CC0-1.0\",\"MIT-0\"],\"name\":\"constant_time_eq\",\"package_url\":\"https://github.com/cesarb/constant_time_eq\",\"repository\":{\"Http\":{\"sha256\":\"f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2\",\"url\":\"https://static.crates.io/crates/constant_time_eq/0.3.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"constant_time_eq\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.0\"},\"cooked-waker 5.0.0\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"cooked_waker\",\"license\":\"MPL-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MPL-2.0\"],\"name\":\"cooked-waker\",\"package_url\":\"https://github.com/Lucretiel/cooked-waker\",\"repository\":{\"Http\":{\"sha256\":\"147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f\",\"url\":\"https://static.crates.io/crates/cooked-waker/5.0.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cooked_waker\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"5.0.0\"},\"core-foundation 0.9.4\":{\"common_attrs\":{\"deps\":[{\"id\":\"core-foundation-sys 0.8.7\",\"target\":\"core_foundation_sys\"},{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"edition\":\"2018\"},\"library_target_name\":\"core_foundation\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"core-foundation\",\"package_url\":\"https://github.com/servo/core-foundation-rs\",\"repository\":{\"Http\":{\"sha256\":\"91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f\",\"url\":\"https://static.crates.io/crates/core-foundation/0.9.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"core_foundation\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.9.4\"},\"core-foundation-sys 0.8.7\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"core_foundation_sys\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"core-foundation-sys\",\"package_url\":\"https://github.com/servo/core-foundation-rs\",\"repository\":{\"Http\":{\"sha256\":\"773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b\",\"url\":\"https://static.crates.io/crates/core-foundation-sys/0.8.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"core_foundation_sys\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.7\"},\"corosensei 0.3.0\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"autocfg 1.1.0\",\"target\":\"autocfg\"}]},\"common_attrs\":{\"crate_features\":[\"default\",\"default-stack\",\"libc\",\"unwind\",\"windows-sys\"],\"deps\":[{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"},{\"id\":\"libc 0.2.171\",\"target\":\"libc\"},{\"id\":\"scopeguard 1.2.0\",\"target\":\"scopeguard\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"corosensei\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"corosensei\",\"package_url\":\"https://github.com/Amanieu/corosensei\",\"repository\":{\"Http\":{\"sha256\":\"878ba85678ef5d34ffe1b5da981b0828232b4c7f2726b20984f59c7e79f6d514\",\"url\":\"https://static.crates.io/crates/corosensei/0.3.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"corosensei\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.3.0\"},\"cpufeatures 0.2.12\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"aarch64-linux-android\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"linux\\\"))\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"cfg(all(target_arch = \\\"aarch64\\\", target_vendor = \\\"apple\\\"))\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"cfg(all(target_arch = \\\"loongarch64\\\", target_os = \\\"linux\\\"))\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"cpufeatures\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"cpufeatures\",\"package_url\":\"https://github.com/RustCrypto/utils\",\"repository\":{\"Http\":{\"sha256\":\"53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504\",\"url\":\"https://static.crates.io/crates/cpufeatures/0.2.12/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cpufeatures\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.12\"},\"crc32fast 1.3.2\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"}],\"edition\":\"2015\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"crc32fast\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"crc32fast\",\"package_url\":\"https://github.com/srijs/rust-crc32fast\",\"repository\":{\"Http\":{\"sha256\":\"b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d\",\"url\":\"https://static.crates.io/crates/crc32fast/1.3.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crc32fast\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.3.2\"},\"crossbeam-channel 0.5.15\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"crossbeam-utils 0.8.19\",\"target\":\"crossbeam_utils\"}],\"edition\":\"2021\"},\"library_target_name\":\"crossbeam_channel\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"crossbeam-channel\",\"package_url\":\"https://github.com/crossbeam-rs/crossbeam\",\"repository\":{\"Http\":{\"sha256\":\"82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2\",\"url\":\"https://static.crates.io/crates/crossbeam-channel/0.5.15/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crossbeam_channel\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.15\"},\"crossbeam-deque 0.8.5\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"crossbeam-epoch 0.9.18\",\"target\":\"crossbeam_epoch\"},{\"id\":\"crossbeam-utils 0.8.19\",\"target\":\"crossbeam_utils\"}],\"edition\":\"2021\"},\"library_target_name\":\"crossbeam_deque\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"crossbeam-deque\",\"package_url\":\"https://github.com/crossbeam-rs/crossbeam\",\"repository\":{\"Http\":{\"sha256\":\"613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d\",\"url\":\"https://static.crates.io/crates/crossbeam-deque/0.8.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crossbeam_deque\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.5\"},\"crossbeam-epoch 0.9.18\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"std\"],\"deps\":[{\"id\":\"crossbeam-utils 0.8.19\",\"target\":\"crossbeam_utils\"}],\"edition\":\"2021\"},\"library_target_name\":\"crossbeam_epoch\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"crossbeam-epoch\",\"package_url\":\"https://github.com/crossbeam-rs/crossbeam\",\"repository\":{\"Http\":{\"sha256\":\"5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e\",\"url\":\"https://static.crates.io/crates/crossbeam-epoch/0.9.18/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crossbeam_epoch\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.9.18\"},\"crossbeam-queue 0.3.11\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"deps\":[{\"id\":\"crossbeam-utils 0.8.19\",\"target\":\"crossbeam_utils\"}],\"edition\":\"2021\"},\"library_target_name\":\"crossbeam_queue\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"crossbeam-queue\",\"package_url\":\"https://github.com/crossbeam-rs/crossbeam\",\"repository\":{\"Http\":{\"sha256\":\"df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35\",\"url\":\"https://static.crates.io/crates/crossbeam-queue/0.3.11/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crossbeam_queue\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.11\"},\"crossbeam-utils 0.8.19\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"crossbeam_utils\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"crossbeam-utils\",\"package_url\":\"https://github.com/crossbeam-rs/crossbeam\",\"repository\":{\"Http\":{\"sha256\":\"248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345\",\"url\":\"https://static.crates.io/crates/crossbeam-utils/0.8.19/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crossbeam_utils\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.8.19\"},\"crunchy 0.2.2\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2015\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"crunchy\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"crunchy\",\"repository\":{\"Http\":{\"sha256\":\"7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7\",\"url\":\"https://static.crates.io/crates/crunchy/0.2.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crunchy\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.2.2\"},\"crypto-common 0.1.6\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"deps\":[{\"id\":\"generic-array 0.14.7\",\"target\":\"generic_array\"},{\"id\":\"typenum 1.17.0\",\"target\":\"typenum\"}],\"edition\":\"2018\"},\"library_target_name\":\"crypto_common\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"crypto-common\",\"package_url\":\"https://github.com/RustCrypto/traits\",\"repository\":{\"Http\":{\"sha256\":\"1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3\",\"url\":\"https://static.crates.io/crates/crypto-common/0.1.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crypto_common\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.6\"},\"cynic 3.10.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"http-reqwest\",\"reqwest\",\"serde_json\"],\"deps\":[{\"id\":\"ref-cast 1.0.24\",\"target\":\"ref_cast\"},{\"id\":\"reqwest 0.12.7\",\"target\":\"reqwest\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.140\",\"target\":\"serde_json\"},{\"id\":\"static_assertions 1.1.0\",\"target\":\"static_assertions\"},{\"id\":\"thiserror 1.0.69\",\"target\":\"thiserror\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"cynic-proc-macros 3.10.0\",\"target\":\"cynic_proc_macros\"}]},\"library_target_name\":\"cynic\",\"license\":\"MPL-2.0\",\"license_ids\":[\"MPL-2.0\"],\"name\":\"cynic\",\"package_url\":\"https://github.com/obmarg/cynic\",\"repository\":{\"Http\":{\"sha256\":\"c99c59968c8aa7f90d84240ab6ded4d3864125ce36b5b044554542cebc974946\",\"url\":\"https://static.crates.io/crates/cynic/3.10.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cynic\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"3.10.0\"},\"cynic-codegen 3.10.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"rustfmt\"],\"deps\":[{\"id\":\"cynic-parser 0.9.1\",\"target\":\"cynic_parser\"},{\"id\":\"darling 0.20.3\",\"target\":\"darling\"},{\"id\":\"once_cell 1.19.0\",\"target\":\"once_cell\"},{\"id\":\"ouroboros 0.18.5\",\"target\":\"ouroboros\"},{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"strsim 0.10.0\",\"target\":\"strsim\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"},{\"id\":\"thiserror 1.0.69\",\"target\":\"thiserror\"}],\"edition\":\"2021\"},\"library_target_name\":\"cynic_codegen\",\"license\":\"MPL-2.0\",\"license_ids\":[\"MPL-2.0\"],\"name\":\"cynic-codegen\",\"package_url\":\"https://github.com/obmarg/cynic\",\"repository\":{\"Http\":{\"sha256\":\"332695dddff7f260dfda1e97502b6440d443816f576994548b7751494991d2e3\",\"url\":\"https://static.crates.io/crates/cynic-codegen/3.10.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cynic_codegen\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"3.10.0\"},\"cynic-parser 0.9.1\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"deps\":[{\"id\":\"indexmap 2.9.0\",\"target\":\"indexmap\"},{\"id\":\"lalrpop-util 0.22.1\",\"target\":\"lalrpop_util\"},{\"id\":\"logos 0.14.4\",\"target\":\"logos\"}],\"edition\":\"2021\"},\"library_target_name\":\"cynic_parser\",\"license\":\"MPL-2.0\",\"license_ids\":[\"MPL-2.0\"],\"name\":\"cynic-parser\",\"package_url\":\"https://github.com/obmarg/cynic\",\"repository\":{\"Http\":{\"sha256\":\"cbb0f21f2f8d3134c2e887a16564c165694231f48b6ae2769193299081ecf662\",\"url\":\"https://static.crates.io/crates/cynic-parser/0.9.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cynic_parser\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.9.1\"},\"cynic-proc-macros 3.10.0\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"deps\":[{\"id\":\"cynic-codegen 3.10.0\",\"target\":\"cynic_codegen\"},{\"id\":\"darling 0.20.3\",\"target\":\"darling\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"cynic_proc_macros\",\"license\":\"MPL-2.0\",\"license_ids\":[\"MPL-2.0\"],\"name\":\"cynic-proc-macros\",\"package_url\":\"https://github.com/obmarg/cynic\",\"repository\":{\"Http\":{\"sha256\":\"a7880789c425a73aff3ba286b2a9c794f330d4770769a42a1493d6175e4606c1\",\"url\":\"https://static.crates.io/crates/cynic-proc-macros/3.10.0/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"cynic_proc_macros\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"3.10.0\"},\"darling 0.14.4\":{\"common_attrs\":{\"crate_features\":[\"default\",\"suggestions\"],\"deps\":[{\"id\":\"darling_core 0.14.4\",\"target\":\"darling_core\"}],\"edition\":\"2018\",\"proc_macro_deps\":[{\"id\":\"darling_macro 0.14.4\",\"target\":\"darling_macro\"}]},\"library_target_name\":\"darling\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"darling\",\"package_url\":\"https://github.com/TedDriggs/darling\",\"repository\":{\"Http\":{\"sha256\":\"7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850\",\"url\":\"https://static.crates.io/crates/darling/0.14.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"darling\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.14.4\"},\"darling 0.20.3\":{\"common_attrs\":{\"crate_features\":[\"default\",\"suggestions\"],\"deps\":[{\"id\":\"darling_core 0.20.3\",\"target\":\"darling_core\"}],\"edition\":\"2018\",\"proc_macro_deps\":[{\"id\":\"darling_macro 0.20.3\",\"target\":\"darling_macro\"}]},\"library_target_name\":\"darling\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"darling\",\"package_url\":\"https://github.com/TedDriggs/darling\",\"repository\":{\"Http\":{\"sha256\":\"0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e\",\"url\":\"https://static.crates.io/crates/darling/0.20.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"darling\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.20.3\"},\"darling_core 0.14.4\":{\"common_attrs\":{\"crate_features\":[\"strsim\",\"suggestions\"],\"deps\":[{\"id\":\"fnv 1.0.7\",\"target\":\"fnv\"},{\"id\":\"ident_case 1.0.1\",\"target\":\"ident_case\"},{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"strsim 0.10.0\",\"target\":\"strsim\"},{\"id\":\"syn 1.0.109\",\"target\":\"syn\"}],\"edition\":\"2018\"},\"library_target_name\":\"darling_core\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"darling_core\",\"package_url\":\"https://github.com/TedDriggs/darling\",\"repository\":{\"Http\":{\"sha256\":\"109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0\",\"url\":\"https://static.crates.io/crates/darling_core/0.14.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"darling_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.14.4\"},\"darling_core 0.20.3\":{\"common_attrs\":{\"crate_features\":[\"strsim\",\"suggestions\"],\"deps\":[{\"id\":\"fnv 1.0.7\",\"target\":\"fnv\"},{\"id\":\"ident_case 1.0.1\",\"target\":\"ident_case\"},{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"strsim 0.10.0\",\"target\":\"strsim\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2018\"},\"library_target_name\":\"darling_core\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"darling_core\",\"package_url\":\"https://github.com/TedDriggs/darling\",\"repository\":{\"Http\":{\"sha256\":\"177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621\",\"url\":\"https://static.crates.io/crates/darling_core/0.20.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"darling_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.20.3\"},\"darling_macro 0.14.4\":{\"common_attrs\":{\"deps\":[{\"id\":\"darling_core 0.14.4\",\"target\":\"darling_core\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 1.0.109\",\"target\":\"syn\"}],\"edition\":\"2018\"},\"library_target_name\":\"darling_macro\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"darling_macro\",\"package_url\":\"https://github.com/TedDriggs/darling\",\"repository\":{\"Http\":{\"sha256\":\"a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e\",\"url\":\"https://static.crates.io/crates/darling_macro/0.14.4/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"darling_macro\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.14.4\"},\"darling_macro 0.20.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"darling_core 0.20.3\",\"target\":\"darling_core\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2018\"},\"library_target_name\":\"darling_macro\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"darling_macro\",\"package_url\":\"https://github.com/TedDriggs/darling\",\"repository\":{\"Http\":{\"sha256\":\"836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5\",\"url\":\"https://static.crates.io/crates/darling_macro/0.20.3/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"darling_macro\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.20.3\"},\"dashmap 6.1.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"},{\"id\":\"crossbeam-utils 0.8.19\",\"target\":\"crossbeam_utils\"},{\"id\":\"hashbrown 0.14.3\",\"target\":\"hashbrown\"},{\"id\":\"lock_api 0.4.11\",\"target\":\"lock_api\"},{\"id\":\"once_cell 1.19.0\",\"target\":\"once_cell\"},{\"id\":\"parking_lot_core 0.9.9\",\"target\":\"parking_lot_core\"}],\"edition\":\"2018\"},\"library_target_name\":\"dashmap\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"dashmap\",\"package_url\":\"https://github.com/xacrimon/dashmap\",\"repository\":{\"Http\":{\"sha256\":\"5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf\",\"url\":\"https://static.crates.io/crates/dashmap/6.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"dashmap\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"6.1.0\"},\"deranged 0.3.11\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"powerfmt\",\"std\"],\"deps\":[{\"id\":\"powerfmt 0.2.0\",\"target\":\"powerfmt\"}],\"edition\":\"2021\"},\"library_target_name\":\"deranged\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-Apache\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"deranged\",\"package_url\":\"https://github.com/jhpratt/deranged\",\"repository\":{\"Http\":{\"sha256\":\"b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4\",\"url\":\"https://static.crates.io/crates/deranged/0.3.11/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"deranged\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.11\"},\"derivative 2.2.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 1.0.109\",\"target\":\"syn\"}],\"edition\":\"2015\"},\"library_target_name\":\"derivative\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"derivative\",\"package_url\":\"https://github.com/mcarton/rust-derivative\",\"repository\":{\"Http\":{\"sha256\":\"fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b\",\"url\":\"https://static.crates.io/crates/derivative/2.2.0/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"derivative\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.2.0\"},\"derive_builder 0.12.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2015\",\"proc_macro_deps\":[{\"id\":\"derive_builder_macro 0.12.0\",\"target\":\"derive_builder_macro\"}]},\"library_target_name\":\"derive_builder\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"derive_builder\",\"package_url\":\"https://github.com/colin-kiegel/rust-derive-builder\",\"repository\":{\"Http\":{\"sha256\":\"8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8\",\"url\":\"https://static.crates.io/crates/derive_builder/0.12.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"derive_builder\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.12.0\"},\"derive_builder_core 0.12.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"darling 0.14.4\",\"target\":\"darling\"},{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 1.0.109\",\"target\":\"syn\"}],\"edition\":\"2015\"},\"library_target_name\":\"derive_builder_core\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"derive_builder_core\",\"package_url\":\"https://github.com/colin-kiegel/rust-derive-builder\",\"repository\":{\"Http\":{\"sha256\":\"c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f\",\"url\":\"https://static.crates.io/crates/derive_builder_core/0.12.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"derive_builder_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.12.0\"},\"derive_builder_macro 0.12.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"derive_builder_core 0.12.0\",\"target\":\"derive_builder_core\"},{\"id\":\"syn 1.0.109\",\"target\":\"syn\"}],\"edition\":\"2015\"},\"library_target_name\":\"derive_builder_macro\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"derive_builder_macro\",\"package_url\":\"https://github.com/colin-kiegel/rust-derive-builder\",\"repository\":{\"Http\":{\"sha256\":\"ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e\",\"url\":\"https://static.crates.io/crates/derive_builder_macro/0.12.0/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"derive_builder_macro\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.12.0\"},\"derive_more 0.99.19\":{\"common_attrs\":{\"crate_features\":[\"display\",\"error\",\"from\"],\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2018\"},\"library_target_name\":\"derive_more\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"derive_more\",\"package_url\":\"https://github.com/JelteF/derive_more\",\"repository\":{\"Http\":{\"sha256\":\"3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f\",\"url\":\"https://static.crates.io/crates/derive_more/0.99.19/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"derive_more\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.99.19\"},\"derive_more 2.0.1\":{\"common_attrs\":{\"crate_features\":[\"debug\",\"default\",\"display\",\"from\",\"std\"],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"derive_more-impl 2.0.1\",\"target\":\"derive_more_impl\"}]},\"library_target_name\":\"derive_more\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"derive_more\",\"package_url\":\"https://github.com/JelteF/derive_more\",\"repository\":{\"Http\":{\"sha256\":\"093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678\",\"url\":\"https://static.crates.io/crates/derive_more/2.0.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"derive_more\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.0.1\"},\"derive_more-impl 2.0.1\":{\"common_attrs\":{\"crate_features\":[\"debug\",\"default\",\"display\",\"from\"],\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"},{\"id\":\"unicode-xid 0.2.4\",\"target\":\"unicode_xid\"}],\"edition\":\"2021\"},\"library_target_name\":\"derive_more_impl\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"derive_more-impl\",\"package_url\":\"https://github.com/JelteF/derive_more\",\"repository\":{\"Http\":{\"sha256\":\"bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3\",\"url\":\"https://static.crates.io/crates/derive_more-impl/2.0.1/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"derive_more_impl\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.0.1\"},\"digest 0.10.7\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"block-buffer\",\"core-api\",\"default\",\"std\"],\"deps\":[{\"id\":\"block-buffer 0.10.4\",\"target\":\"block_buffer\"},{\"id\":\"crypto-common 0.1.6\",\"target\":\"crypto_common\"}],\"edition\":\"2018\"},\"library_target_name\":\"digest\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"digest\",\"package_url\":\"https://github.com/RustCrypto/traits\",\"repository\":{\"Http\":{\"sha256\":\"9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292\",\"url\":\"https://static.crates.io/crates/digest/0.10.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"digest\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.10.7\"},\"displaydoc 0.2.5\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"displaydoc\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"displaydoc\",\"package_url\":\"https://github.com/yaahc/displaydoc\",\"repository\":{\"Http\":{\"sha256\":\"97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0\",\"url\":\"https://static.crates.io/crates/displaydoc/0.2.5/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"displaydoc\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.5\"},\"document-features 0.2.8\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"deps\":[{\"id\":\"litrs 0.4.1\",\"target\":\"litrs\"}],\"edition\":\"2018\"},\"library_target_name\":\"document_features\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"document-features\",\"package_url\":\"https://github.com/slint-ui/document-features\",\"repository\":{\"Http\":{\"sha256\":\"ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95\",\"url\":\"https://static.crates.io/crates/document-features/0.2.8/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"document_features\",\"crate_root\":\"lib.rs\"}}],\"version\":\"0.2.8\"},\"dunce 1.0.5\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"dunce\",\"license\":\"CC0-1.0 OR MIT-0 OR Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\",\"CC0-1.0\",\"MIT-0\"],\"name\":\"dunce\",\"package_url\":\"https://gitlab.com/kornelski/dunce\",\"repository\":{\"Http\":{\"sha256\":\"92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813\",\"url\":\"https://static.crates.io/crates/dunce/1.0.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"dunce\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.5\"},\"dyn-clone 1.0.17\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"dyn_clone\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"dyn-clone\",\"package_url\":\"https://github.com/dtolnay/dyn-clone\",\"repository\":{\"Http\":{\"sha256\":\"0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125\",\"url\":\"https://static.crates.io/crates/dyn-clone/1.0.17/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"dyn_clone\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.17\"},\"educe 0.5.11\":{\"common_attrs\":{\"crate_features\":[\"Debug\"],\"deps\":[{\"id\":\"enum-ordinalize 4.3.2\",\"target\":\"enum_ordinalize\"},{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"educe\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"educe\",\"package_url\":\"https://github.com/magiclen/educe\",\"repository\":{\"Http\":{\"sha256\":\"e4bd92664bf78c4d3dba9b7cdafce6fa15b13ed3ed16175218196942e99168a8\",\"url\":\"https://static.crates.io/crates/educe/0.5.11/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"educe\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.11\"},\"either 1.13.0\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"either\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"either\",\"package_url\":\"https://github.com/rayon-rs/either\",\"repository\":{\"Http\":{\"sha256\":\"60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0\",\"url\":\"https://static.crates.io/crates/either/1.13.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"either\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.13.0\"},\"encode_unicode 1.0.0\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"encode_unicode\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"encode_unicode\",\"package_url\":\"https://github.com/tormol/encode_unicode\",\"repository\":{\"Http\":{\"sha256\":\"34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0\",\"url\":\"https://static.crates.io/crates/encode_unicode/1.0.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"encode_unicode\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.0\"},\"encoding_rs 0.8.34\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\"],\"deps\":[{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"}],\"edition\":\"2018\"},\"library_target_name\":\"encoding_rs\",\"license\":\"(Apache-2.0 OR MIT) AND BSD-3-Clause\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"BSD-3-Clause\",\"MIT\"],\"name\":\"encoding_rs\",\"package_url\":\"https://github.com/hsivonen/encoding_rs\",\"repository\":{\"Http\":{\"sha256\":\"b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59\",\"url\":\"https://static.crates.io/crates/encoding_rs/0.8.34/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"encoding_rs\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.34\"},\"enum-iterator 0.7.0\":{\"common_attrs\":{\"edition\":\"2018\",\"proc_macro_deps\":[{\"id\":\"enum-iterator-derive 0.7.0\",\"target\":\"enum_iterator_derive\"}]},\"library_target_name\":\"enum_iterator\",\"license\":\"0BSD\",\"license_ids\":[\"0BSD\"],\"name\":\"enum-iterator\",\"package_url\":\"https://github.com/stephaneyfx/enum-iterator.git\",\"repository\":{\"Http\":{\"sha256\":\"4eeac5c5edb79e4e39fe8439ef35207780a11f69c52cbe424ce3dfad4cb78de6\",\"url\":\"https://static.crates.io/crates/enum-iterator/0.7.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"enum_iterator\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.0\"},\"enum-iterator-derive 0.7.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 1.0.109\",\"target\":\"syn\"}],\"edition\":\"2018\"},\"library_target_name\":\"enum_iterator_derive\",\"license\":\"0BSD\",\"license_ids\":[\"0BSD\"],\"name\":\"enum-iterator-derive\",\"package_url\":\"https://github.com/stephaneyfx/enum-iterator.git\",\"repository\":{\"Http\":{\"sha256\":\"c134c37760b27a871ba422106eedbb8247da973a09e82558bf26d619c882b159\",\"url\":\"https://static.crates.io/crates/enum-iterator-derive/0.7.0/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"enum_iterator_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.0\"},\"enum-ordinalize 4.3.2\":{\"common_attrs\":{\"crate_features\":[\"derive\"],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"enum-ordinalize-derive 4.3.2\",\"target\":\"enum_ordinalize_derive\"}]},\"library_target_name\":\"enum_ordinalize\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"enum-ordinalize\",\"package_url\":\"https://github.com/magiclen/enum-ordinalize\",\"repository\":{\"Http\":{\"sha256\":\"4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0\",\"url\":\"https://static.crates.io/crates/enum-ordinalize/4.3.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"enum_ordinalize\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"4.3.2\"},\"enum-ordinalize-derive 4.3.2\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"enum_ordinalize_derive\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"enum-ordinalize-derive\",\"package_url\":\"https://github.com/magiclen/enum-ordinalize\",\"repository\":{\"Http\":{\"sha256\":\"8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631\",\"url\":\"https://static.crates.io/crates/enum-ordinalize-derive/4.3.2/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"enum_ordinalize_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"4.3.2\"},\"enumset 1.1.3\":{\"common_attrs\":{\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"enumset_derive 0.8.1\",\"target\":\"enumset_derive\"}]},\"library_target_name\":\"enumset\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"enumset\",\"package_url\":\"https://github.com/Lymia/enumset\",\"repository\":{\"Http\":{\"sha256\":\"226c0da7462c13fb57e5cc9e0dc8f0635e7d27f276a3a7fd30054647f669007d\",\"url\":\"https://static.crates.io/crates/enumset/1.1.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"enumset\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.3\"},\"enumset_derive 0.8.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"darling 0.20.3\",\"target\":\"darling\"},{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"enumset_derive\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"enumset_derive\",\"package_url\":\"https://github.com/Lymia/enumset\",\"repository\":{\"Http\":{\"sha256\":\"e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af\",\"url\":\"https://static.crates.io/crates/enumset_derive/0.8.1/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"enumset_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.1\"},\"equivalent 1.0.1\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"equivalent\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"equivalent\",\"package_url\":\"https://github.com/cuviper/equivalent\",\"repository\":{\"Http\":{\"sha256\":\"5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5\",\"url\":\"https://static.crates.io/crates/equivalent/1.0.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"equivalent\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.1\"},\"errno 0.3.8\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(target_os = \\\"hermit\\\")\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"cfg(target_os = \\\"wasi\\\")\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"cfg(unix)\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"cfg(windows)\":[{\"id\":\"windows-sys 0.52.0\",\"target\":\"windows_sys\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"errno\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"errno\",\"package_url\":\"https://github.com/lambda-fairy/rust-errno\",\"repository\":{\"Http\":{\"sha256\":\"a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245\",\"url\":\"https://static.crates.io/crates/errno/0.3.8/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"errno\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.8\"},\"fastrand 2.0.1\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"fastrand\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"fastrand\",\"package_url\":\"https://github.com/smol-rs/fastrand\",\"repository\":{\"Http\":{\"sha256\":\"25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5\",\"url\":\"https://static.crates.io/crates/fastrand/2.0.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"fastrand\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.0.1\"},\"filetime 0.2.23\":{\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"}],\"selects\":{\"cfg(target_os = \\\"redox\\\")\":[{\"id\":\"redox_syscall 0.4.1\",\"target\":\"syscall\"}],\"cfg(unix)\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"cfg(windows)\":[{\"id\":\"windows-sys 0.52.0\",\"target\":\"windows_sys\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"filetime\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"filetime\",\"package_url\":\"https://github.com/alexcrichton/filetime\",\"repository\":{\"Http\":{\"sha256\":\"1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd\",\"url\":\"https://static.crates.io/crates/filetime/0.2.23/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"filetime\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.23\"},\"fixedbitset 0.5.7\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"fixedbitset\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"fixedbitset\",\"package_url\":\"https://github.com/petgraph/fixedbitset\",\"repository\":{\"Http\":{\"sha256\":\"1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99\",\"url\":\"https://static.crates.io/crates/fixedbitset/0.5.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"fixedbitset\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.7\"},\"flate2 1.1.1\":{\"common_attrs\":{\"crate_features\":[\"any_impl\",\"default\",\"miniz_oxide\",\"rust_backend\"],\"deps\":[{\"id\":\"crc32fast 1.3.2\",\"target\":\"crc32fast\"},{\"id\":\"miniz_oxide 0.8.7\",\"target\":\"miniz_oxide\"}],\"edition\":\"2018\"},\"library_target_name\":\"flate2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"flate2\",\"package_url\":\"https://github.com/rust-lang/flate2-rs\",\"repository\":{\"Http\":{\"sha256\":\"7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece\",\"url\":\"https://static.crates.io/crates/flate2/1.1.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"flate2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.1\"},\"fnv 1.0.7\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2015\"},\"library_target_name\":\"fnv\",\"license\":\"Apache-2.0 / MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"fnv\",\"package_url\":\"https://github.com/servo/rust-fnv\",\"repository\":{\"Http\":{\"sha256\":\"3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1\",\"url\":\"https://static.crates.io/crates/fnv/1.0.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"fnv\",\"crate_root\":\"lib.rs\"}}],\"version\":\"1.0.7\"},\"foreign-types 0.3.2\":{\"common_attrs\":{\"deps\":[{\"id\":\"foreign-types-shared 0.1.1\",\"target\":\"foreign_types_shared\"}],\"edition\":\"2015\"},\"library_target_name\":\"foreign_types\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"foreign-types\",\"package_url\":\"https://github.com/sfackler/foreign-types\",\"repository\":{\"Http\":{\"sha256\":\"f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1\",\"url\":\"https://static.crates.io/crates/foreign-types/0.3.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"foreign_types\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.2\"},\"foreign-types-shared 0.1.1\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"foreign_types_shared\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"foreign-types-shared\",\"package_url\":\"https://github.com/sfackler/foreign-types\",\"repository\":{\"Http\":{\"sha256\":\"00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b\",\"url\":\"https://static.crates.io/crates/foreign-types-shared/0.1.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"foreign_types_shared\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.1\"},\"form_urlencoded 1.2.1\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"deps\":[{\"id\":\"percent-encoding 2.3.1\",\"target\":\"percent_encoding\"}],\"edition\":\"2018\"},\"library_target_name\":\"form_urlencoded\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"form_urlencoded\",\"package_url\":\"https://github.com/servo/rust-url\",\"repository\":{\"Http\":{\"sha256\":\"e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456\",\"url\":\"https://static.crates.io/crates/form_urlencoded/1.2.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"form_urlencoded\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.1\"},\"futures 0.3.30\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"async-await\",\"default\",\"executor\",\"futures-executor\",\"std\"],\"deps\":[{\"id\":\"futures-channel 0.3.31\",\"target\":\"futures_channel\"},{\"id\":\"futures-core 0.3.31\",\"target\":\"futures_core\"},{\"id\":\"futures-executor 0.3.30\",\"target\":\"futures_executor\"},{\"id\":\"futures-io 0.3.31\",\"target\":\"futures_io\"},{\"id\":\"futures-sink 0.3.31\",\"target\":\"futures_sink\"},{\"id\":\"futures-task 0.3.31\",\"target\":\"futures_task\"},{\"id\":\"futures-util 0.3.31\",\"target\":\"futures_util\"}],\"edition\":\"2018\"},\"library_target_name\":\"futures\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0\",\"url\":\"https://static.crates.io/crates/futures/0.3.30/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.30\"},\"futures-channel 0.3.31\":{\"common_attrs\":{\"crate_features\":{\"common\":[\"alloc\",\"futures-sink\",\"sink\",\"std\"],\"selects\":{\"x86_64-unknown-linux-gnu\":[\"default\"]}},\"deps\":[{\"id\":\"futures-core 0.3.31\",\"target\":\"futures_core\"},{\"id\":\"futures-sink 0.3.31\",\"target\":\"futures_sink\"}],\"edition\":\"2018\"},\"library_target_name\":\"futures_channel\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-channel\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10\",\"url\":\"https://static.crates.io/crates/futures-channel/0.3.31/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures_channel\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.31\"},\"futures-core 0.3.31\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"futures_core\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-core\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e\",\"url\":\"https://static.crates.io/crates/futures-core/0.3.31/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.31\"},\"futures-executor 0.3.30\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"deps\":[{\"id\":\"futures-core 0.3.31\",\"target\":\"futures_core\"},{\"id\":\"futures-task 0.3.31\",\"target\":\"futures_task\"},{\"id\":\"futures-util 0.3.31\",\"target\":\"futures_util\"}],\"edition\":\"2018\"},\"library_target_name\":\"futures_executor\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-executor\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d\",\"url\":\"https://static.crates.io/crates/futures-executor/0.3.30/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures_executor\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.30\"},\"futures-io 0.3.31\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"futures_io\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-io\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6\",\"url\":\"https://static.crates.io/crates/futures-io/0.3.31/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures_io\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.31\"},\"futures-macro 0.3.31\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2018\"},\"library_target_name\":\"futures_macro\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-macro\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650\",\"url\":\"https://static.crates.io/crates/futures-macro/0.3.31/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"futures_macro\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.31\"},\"futures-sink 0.3.31\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"futures_sink\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-sink\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7\",\"url\":\"https://static.crates.io/crates/futures-sink/0.3.31/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures_sink\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.31\"},\"futures-task 0.3.31\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"futures_task\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-task\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988\",\"url\":\"https://static.crates.io/crates/futures-task/0.3.31/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures_task\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.31\"},\"futures-util 0.3.31\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"async-await\",\"async-await-macro\",\"channel\",\"default\",\"futures-channel\",\"futures-io\",\"futures-macro\",\"futures-sink\",\"io\",\"memchr\",\"sink\",\"slab\",\"std\"],\"deps\":[{\"id\":\"futures-channel 0.3.31\",\"target\":\"futures_channel\"},{\"id\":\"futures-core 0.3.31\",\"target\":\"futures_core\"},{\"id\":\"futures-io 0.3.31\",\"target\":\"futures_io\"},{\"id\":\"futures-sink 0.3.31\",\"target\":\"futures_sink\"},{\"id\":\"futures-task 0.3.31\",\"target\":\"futures_task\"},{\"id\":\"memchr 2.7.1\",\"target\":\"memchr\"},{\"id\":\"pin-project-lite 0.2.13\",\"target\":\"pin_project_lite\"},{\"id\":\"pin-utils 0.1.0\",\"target\":\"pin_utils\"},{\"id\":\"slab 0.4.9\",\"target\":\"slab\"}],\"edition\":\"2018\",\"proc_macro_deps\":[{\"id\":\"futures-macro 0.3.31\",\"target\":\"futures_macro\"}]},\"library_target_name\":\"futures_util\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-util\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81\",\"url\":\"https://static.crates.io/crates/futures-util/0.3.31/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures_util\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.31\"},\"generic-array 0.14.7\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"version_check 0.9.5\",\"target\":\"version_check\"}]},\"common_attrs\":{\"crate_features\":[\"more_lengths\"],\"deps\":[{\"id\":\"typenum 1.17.0\",\"target\":\"typenum\"}],\"edition\":\"2015\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"generic_array\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"generic-array\",\"package_url\":\"https://github.com/fizyk20/generic-array.git\",\"repository\":{\"Http\":{\"sha256\":\"85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a\",\"url\":\"https://static.crates.io/crates/generic-array/0.14.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"generic_array\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.14.7\"},\"getrandom 0.2.15\":{\"common_attrs\":{\"crate_features\":[\"js\",\"js-sys\",\"std\",\"wasm-bindgen\"],\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"}],\"selects\":{\"cfg(target_os = \\\"wasi\\\")\":[{\"id\":\"wasi 0.11.0+wasi-snapshot-preview1\",\"target\":\"wasi\"}],\"cfg(unix)\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"wasm32-unknown-unknown\":[{\"id\":\"js-sys 0.3.78\",\"target\":\"js_sys\"},{\"id\":\"wasm-bindgen 0.2.101\",\"target\":\"wasm_bindgen\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"getrandom\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"getrandom\",\"package_url\":\"https://github.com/rust-random/getrandom\",\"repository\":{\"Http\":{\"sha256\":\"c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7\",\"url\":\"https://static.crates.io/crates/getrandom/0.2.15/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"getrandom\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.15\"},\"gimli 0.28.1\":{\"common_attrs\":{\"crate_features\":[\"read\",\"read-core\"],\"edition\":\"2018\"},\"library_target_name\":\"gimli\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"gimli\",\"package_url\":\"https://github.com/gimli-rs/gimli\",\"repository\":{\"Http\":{\"sha256\":\"4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253\",\"url\":\"https://static.crates.io/crates/gimli/0.28.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"gimli\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.28.1\"},\"glob 0.3.2\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"glob\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"glob\",\"package_url\":\"https://github.com/rust-lang/glob\",\"repository\":{\"Http\":{\"sha256\":\"a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2\",\"url\":\"https://static.crates.io/crates/glob/0.3.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"glob\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.2\"},\"globset 0.4.14\":{\"common_attrs\":{\"crate_features\":[\"default\",\"log\"],\"deps\":[{\"id\":\"aho-corasick 1.1.2\",\"target\":\"aho_corasick\"},{\"id\":\"bstr 1.9.1\",\"target\":\"bstr\"},{\"id\":\"log 0.4.20\",\"target\":\"log\"},{\"id\":\"regex-automata 0.4.3\",\"target\":\"regex_automata\"},{\"id\":\"regex-syntax 0.8.2\",\"target\":\"regex_syntax\"}],\"edition\":\"2021\"},\"library_target_name\":\"globset\",\"license\":\"Unlicense OR MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"globset\",\"package_url\":\"https://github.com/BurntSushi/ripgrep/tree/master/crates/globset\",\"repository\":{\"Http\":{\"sha256\":\"57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1\",\"url\":\"https://static.crates.io/crates/globset/0.4.14/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"globset\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.14\"},\"h2 0.4.5\":{\"common_attrs\":{\"deps\":[{\"id\":\"atomic-waker 1.1.2\",\"target\":\"atomic_waker\"},{\"id\":\"bytes 1.10.1\",\"target\":\"bytes\"},{\"id\":\"fnv 1.0.7\",\"target\":\"fnv\"},{\"id\":\"futures-core 0.3.31\",\"target\":\"futures_core\"},{\"id\":\"futures-sink 0.3.31\",\"target\":\"futures_sink\"},{\"id\":\"http 1.3.1\",\"target\":\"http\"},{\"id\":\"indexmap 2.9.0\",\"target\":\"indexmap\"},{\"id\":\"slab 0.4.9\",\"target\":\"slab\"},{\"id\":\"tokio 1.44.2\",\"target\":\"tokio\"},{\"id\":\"tokio-util 0.7.11\",\"target\":\"tokio_util\"},{\"id\":\"tracing 0.1.41\",\"target\":\"tracing\"}],\"edition\":\"2021\"},\"library_target_name\":\"h2\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"h2\",\"package_url\":\"https://github.com/hyperium/h2\",\"repository\":{\"Http\":{\"sha256\":\"fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab\",\"url\":\"https://static.crates.io/crates/h2/0.4.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"h2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.5\"},\"half 2.4.1\":{\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"}],\"selects\":{\"cfg(target_arch = \\\"spirv\\\")\":[{\"id\":\"crunchy 0.2.2\",\"target\":\"crunchy\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"half\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"half\",\"package_url\":\"https://github.com/starkat99/half-rs\",\"repository\":{\"Http\":{\"sha256\":\"6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888\",\"url\":\"https://static.crates.io/crates/half/2.4.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"half\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.4.1\"},\"harsh 0.2.2\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"harsh\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"harsh\",\"package_url\":\"https://github.com/archer884/harsh\",\"repository\":{\"Http\":{\"sha256\":\"a6fce2283849822530a18d7d8eeb1719ac65a27cfb6649c0dc8dfd2d2cc5edfb\",\"url\":\"https://static.crates.io/crates/harsh/0.2.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"harsh\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.2\"},\"hash32 0.3.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"byteorder 1.5.0\",\"target\":\"byteorder\"}],\"edition\":\"2015\"},\"library_target_name\":\"hash32\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"hash32\",\"package_url\":\"https://github.com/japaric/hash32\",\"repository\":{\"Http\":{\"sha256\":\"47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606\",\"url\":\"https://static.crates.io/crates/hash32/0.3.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hash32\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.1\"},\"hashbrown 0.14.3\":{\"common_attrs\":{\"crate_features\":[\"ahash\",\"raw\"],\"deps\":[{\"id\":\"ahash 0.8.11\",\"target\":\"ahash\"}],\"edition\":\"2021\"},\"library_target_name\":\"hashbrown\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"hashbrown\",\"package_url\":\"https://github.com/rust-lang/hashbrown\",\"repository\":{\"Http\":{\"sha256\":\"290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604\",\"url\":\"https://static.crates.io/crates/hashbrown/0.14.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hashbrown\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.14.3\"},\"hashbrown 0.15.2\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"hashbrown\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"hashbrown\",\"package_url\":\"https://github.com/rust-lang/hashbrown\",\"repository\":{\"Http\":{\"sha256\":\"bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289\",\"url\":\"https://static.crates.io/crates/hashbrown/0.15.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hashbrown\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.15.2\"},\"heapless 0.8.0\":{\"build_script_attrs\":{},\"common_attrs\":{\"deps\":[{\"id\":\"hash32 0.3.1\",\"target\":\"hash32\"},{\"id\":\"stable_deref_trait 1.2.0\",\"target\":\"stable_deref_trait\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"heapless\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"heapless\",\"package_url\":\"https://github.com/rust-embedded/heapless\",\"repository\":{\"Http\":{\"sha256\":\"0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad\",\"url\":\"https://static.crates.io/crates/heapless/0.8.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"heapless\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.8.0\"},\"heck 0.3.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"unicode-segmentation 1.10.1\",\"target\":\"unicode_segmentation\"}],\"edition\":\"2018\"},\"library_target_name\":\"heck\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"heck\",\"package_url\":\"https://github.com/withoutboats/heck\",\"repository\":{\"Http\":{\"sha256\":\"6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c\",\"url\":\"https://static.crates.io/crates/heck/0.3.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"heck\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.3\"},\"heck 0.4.1\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"edition\":\"2018\"},\"library_target_name\":\"heck\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"heck\",\"package_url\":\"https://github.com/withoutboats/heck\",\"repository\":{\"Http\":{\"sha256\":\"95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8\",\"url\":\"https://static.crates.io/crates/heck/0.4.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"heck\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.1\"},\"hermit-abi 0.5.2\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"hermit_abi\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"hermit-abi\",\"package_url\":\"https://github.com/hermit-os/hermit-rs\",\"repository\":{\"Http\":{\"sha256\":\"fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c\",\"url\":\"https://static.crates.io/crates/hermit-abi/0.5.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hermit_abi\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.2\"},\"hex 0.4.3\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"hex\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"hex\",\"package_url\":\"https://github.com/KokaKiwi/rust-hex\",\"repository\":{\"Http\":{\"sha256\":\"7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70\",\"url\":\"https://static.crates.io/crates/hex/0.4.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hex\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.3\"},\"http 1.3.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"bytes 1.10.1\",\"target\":\"bytes\"},{\"id\":\"fnv 1.0.7\",\"target\":\"fnv\"},{\"id\":\"itoa 1.0.10\",\"target\":\"itoa\"}],\"edition\":\"2018\"},\"library_target_name\":\"http\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"http\",\"package_url\":\"https://github.com/hyperium/http\",\"repository\":{\"Http\":{\"sha256\":\"f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565\",\"url\":\"https://static.crates.io/crates/http/1.3.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"http\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.3.1\"},\"http-body 1.0.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"bytes 1.10.1\",\"target\":\"bytes\"},{\"id\":\"http 1.3.1\",\"target\":\"http\"}],\"edition\":\"2018\"},\"library_target_name\":\"http_body\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"http-body\",\"package_url\":\"https://github.com/hyperium/http-body\",\"repository\":{\"Http\":{\"sha256\":\"1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643\",\"url\":\"https://static.crates.io/crates/http-body/1.0.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"http_body\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.0\"},\"http-body-util 0.1.2\":{\"common_attrs\":{\"deps\":[{\"id\":\"bytes 1.10.1\",\"target\":\"bytes\"},{\"id\":\"futures-util 0.3.31\",\"target\":\"futures_util\"},{\"id\":\"http 1.3.1\",\"target\":\"http\"},{\"id\":\"http-body 1.0.0\",\"target\":\"http_body\"},{\"id\":\"pin-project-lite 0.2.13\",\"target\":\"pin_project_lite\"}],\"edition\":\"2018\"},\"library_target_name\":\"http_body_util\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"http-body-util\",\"package_url\":\"https://github.com/hyperium/http-body\",\"repository\":{\"Http\":{\"sha256\":\"793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f\",\"url\":\"https://static.crates.io/crates/http-body-util/0.1.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"http_body_util\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.2\"},\"httparse 1.10.1\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"httparse\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"httparse\",\"package_url\":\"https://github.com/seanmonstar/httparse\",\"repository\":{\"Http\":{\"sha256\":\"6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87\",\"url\":\"https://static.crates.io/crates/httparse/1.10.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"httparse\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.10.1\"},\"hyper 1.4.0\":{\"common_attrs\":{\"crate_features\":[\"client\",\"default\",\"http1\",\"http2\"],\"deps\":[{\"id\":\"bytes 1.10.1\",\"target\":\"bytes\"},{\"id\":\"futures-channel 0.3.31\",\"target\":\"futures_channel\"},{\"id\":\"futures-util 0.3.31\",\"target\":\"futures_util\"},{\"id\":\"h2 0.4.5\",\"target\":\"h2\"},{\"id\":\"http 1.3.1\",\"target\":\"http\"},{\"id\":\"http-body 1.0.0\",\"target\":\"http_body\"},{\"id\":\"httparse 1.10.1\",\"target\":\"httparse\"},{\"id\":\"itoa 1.0.10\",\"target\":\"itoa\"},{\"id\":\"pin-project-lite 0.2.13\",\"target\":\"pin_project_lite\"},{\"id\":\"smallvec 1.13.2\",\"target\":\"smallvec\"},{\"id\":\"tokio 1.44.2\",\"target\":\"tokio\"},{\"id\":\"want 0.3.1\",\"target\":\"want\"}],\"edition\":\"2021\"},\"library_target_name\":\"hyper\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"hyper\",\"package_url\":\"https://github.com/hyperium/hyper\",\"repository\":{\"Http\":{\"sha256\":\"c4fe55fb7a772d59a5ff1dfbff4fe0258d19b89fec4b233e75d35d5d2316badc\",\"url\":\"https://static.crates.io/crates/hyper/1.4.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hyper\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.4.0\"},\"hyper-rustls 0.27.2\":{\"common_attrs\":{\"deps\":[{\"id\":\"futures-util 0.3.31\",\"target\":\"futures_util\"},{\"id\":\"http 1.3.1\",\"target\":\"http\"},{\"id\":\"hyper 1.4.0\",\"target\":\"hyper\"},{\"id\":\"hyper-util 0.1.6\",\"target\":\"hyper_util\"},{\"id\":\"rustls 0.23.25\",\"target\":\"rustls\"},{\"alias\":\"pki_types\",\"id\":\"rustls-pki-types 1.11.0\",\"target\":\"rustls_pki_types\"},{\"id\":\"tokio 1.44.2\",\"target\":\"tokio\"},{\"id\":\"tokio-rustls 0.26.0\",\"target\":\"tokio_rustls\"},{\"id\":\"tower-service 0.3.2\",\"target\":\"tower_service\"}],\"edition\":\"2021\"},\"library_target_name\":\"hyper_rustls\",\"license\":\"Apache-2.0 OR ISC OR MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\",\"ISC\",\"MIT\"],\"name\":\"hyper-rustls\",\"package_url\":\"https://github.com/rustls/hyper-rustls\",\"repository\":{\"Http\":{\"sha256\":\"5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155\",\"url\":\"https://static.crates.io/crates/hyper-rustls/0.27.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hyper_rustls\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.27.2\"},\"hyper-tls 0.6.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"bytes 1.10.1\",\"target\":\"bytes\"},{\"id\":\"http-body-util 0.1.2\",\"target\":\"http_body_util\"},{\"id\":\"hyper 1.4.0\",\"target\":\"hyper\"},{\"id\":\"hyper-util 0.1.6\",\"target\":\"hyper_util\"},{\"id\":\"native-tls 0.2.12\",\"target\":\"native_tls\"},{\"id\":\"tokio 1.44.2\",\"target\":\"tokio\"},{\"id\":\"tokio-native-tls 0.3.1\",\"target\":\"tokio_native_tls\"},{\"id\":\"tower-service 0.3.2\",\"target\":\"tower_service\"}],\"edition\":\"2018\"},\"library_target_name\":\"hyper_tls\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"hyper-tls\",\"package_url\":\"https://github.com/hyperium/hyper-tls\",\"repository\":{\"Http\":{\"sha256\":\"70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0\",\"url\":\"https://static.crates.io/crates/hyper-tls/0.6.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hyper_tls\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.0\"},\"hyper-util 0.1.6\":{\"common_attrs\":{\"crate_features\":[\"client\",\"client-legacy\",\"default\",\"http1\",\"http2\",\"tokio\"],\"deps\":[{\"id\":\"bytes 1.10.1\",\"target\":\"bytes\"},{\"id\":\"futures-channel 0.3.31\",\"target\":\"futures_channel\"},{\"id\":\"futures-util 0.3.31\",\"target\":\"futures_util\"},{\"id\":\"http 1.3.1\",\"target\":\"http\"},{\"id\":\"http-body 1.0.0\",\"target\":\"http_body\"},{\"id\":\"hyper 1.4.0\",\"target\":\"hyper\"},{\"id\":\"pin-project-lite 0.2.13\",\"target\":\"pin_project_lite\"},{\"id\":\"socket2 0.5.7\",\"target\":\"socket2\"},{\"id\":\"tokio 1.44.2\",\"target\":\"tokio\"},{\"id\":\"tower 0.4.13\",\"target\":\"tower\"},{\"id\":\"tower-service 0.3.2\",\"target\":\"tower_service\"},{\"id\":\"tracing 0.1.41\",\"target\":\"tracing\"}],\"edition\":\"2021\"},\"library_target_name\":\"hyper_util\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"hyper-util\",\"package_url\":\"https://github.com/hyperium/hyper-util\",\"repository\":{\"Http\":{\"sha256\":\"3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956\",\"url\":\"https://static.crates.io/crates/hyper-util/0.1.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hyper_util\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.6\"},\"iana-time-zone 0.1.59\":{\"common_attrs\":{\"crate_features\":[\"fallback\"],\"deps\":{\"common\":[],\"selects\":{\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"ios\\\"))\":[{\"id\":\"core-foundation-sys 0.8.7\",\"target\":\"core_foundation_sys\"}],\"cfg(target_arch = \\\"wasm32\\\")\":[{\"id\":\"js-sys 0.3.78\",\"target\":\"js_sys\"},{\"id\":\"wasm-bindgen 0.2.101\",\"target\":\"wasm_bindgen\"}],\"cfg(target_os = \\\"android\\\")\":[{\"id\":\"android_system_properties 0.1.5\",\"target\":\"android_system_properties\"}],\"cfg(target_os = \\\"haiku\\\")\":[{\"id\":\"iana-time-zone-haiku 0.1.2\",\"target\":\"iana_time_zone_haiku\"}],\"cfg(target_os = \\\"windows\\\")\":[{\"id\":\"windows-core 0.52.0\",\"target\":\"windows_core\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"iana_time_zone\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"iana-time-zone\",\"package_url\":\"https://github.com/strawlab/iana-time-zone\",\"repository\":{\"Http\":{\"sha256\":\"b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539\",\"url\":\"https://static.crates.io/crates/iana-time-zone/0.1.59/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"iana_time_zone\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.59\"},\"iana-time-zone-haiku 0.1.2\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"cc 1.2.18\",\"target\":\"cc\"}]},\"common_attrs\":{\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"iana_time_zone_haiku\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"iana-time-zone-haiku\",\"package_url\":\"https://github.com/strawlab/iana-time-zone\",\"repository\":{\"Http\":{\"sha256\":\"f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f\",\"url\":\"https://static.crates.io/crates/iana-time-zone-haiku/0.1.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"iana_time_zone_haiku\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.1.2\"},\"icu_collections 1.5.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"yoke 0.7.5\",\"target\":\"yoke\"},{\"id\":\"zerofrom 0.1.6\",\"target\":\"zerofrom\"},{\"id\":\"zerovec 0.10.4\",\"target\":\"zerovec\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"displaydoc 0.2.5\",\"target\":\"displaydoc\"}]},\"library_target_name\":\"icu_collections\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_collections\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526\",\"url\":\"https://static.crates.io/crates/icu_collections/1.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"icu_collections\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.5.0\"},\"icu_locid 1.5.0\":{\"common_attrs\":{\"crate_features\":[\"zerovec\"],\"deps\":[{\"id\":\"litemap 0.7.5\",\"target\":\"litemap\"},{\"id\":\"tinystr 0.7.6\",\"target\":\"tinystr\"},{\"id\":\"writeable 0.5.5\",\"target\":\"writeable\"},{\"id\":\"zerovec 0.10.4\",\"target\":\"zerovec\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"displaydoc 0.2.5\",\"target\":\"displaydoc\"}]},\"library_target_name\":\"icu_locid\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_locid\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637\",\"url\":\"https://static.crates.io/crates/icu_locid/1.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"icu_locid\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.5.0\"},\"icu_locid_transform 1.5.0\":{\"common_attrs\":{\"crate_features\":[\"compiled_data\"],\"deps\":[{\"id\":\"icu_locid 1.5.0\",\"target\":\"icu_locid\"},{\"id\":\"icu_locid_transform_data 1.5.1\",\"target\":\"icu_locid_transform_data\"},{\"id\":\"icu_provider 1.5.0\",\"target\":\"icu_provider\"},{\"id\":\"tinystr 0.7.6\",\"target\":\"tinystr\"},{\"id\":\"zerovec 0.10.4\",\"target\":\"zerovec\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"displaydoc 0.2.5\",\"target\":\"displaydoc\"}]},\"library_target_name\":\"icu_locid_transform\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_locid_transform\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e\",\"url\":\"https://static.crates.io/crates/icu_locid_transform/1.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"icu_locid_transform\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.5.0\"},\"icu_locid_transform_data 1.5.1\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"icu_locid_transform_data\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_locid_transform_data\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d\",\"url\":\"https://static.crates.io/crates/icu_locid_transform_data/1.5.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"icu_locid_transform_data\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.5.1\"},\"icu_normalizer 1.5.0\":{\"common_attrs\":{\"crate_features\":[\"compiled_data\",\"default\"],\"deps\":[{\"id\":\"icu_collections 1.5.0\",\"target\":\"icu_collections\"},{\"id\":\"icu_normalizer_data 1.5.1\",\"target\":\"icu_normalizer_data\"},{\"id\":\"icu_properties 1.5.1\",\"target\":\"icu_properties\"},{\"id\":\"icu_provider 1.5.0\",\"target\":\"icu_provider\"},{\"id\":\"smallvec 1.13.2\",\"target\":\"smallvec\"},{\"id\":\"utf16_iter 1.0.5\",\"target\":\"utf16_iter\"},{\"id\":\"utf8_iter 1.0.4\",\"target\":\"utf8_iter\"},{\"id\":\"write16 1.0.0\",\"target\":\"write16\"},{\"id\":\"zerovec 0.10.4\",\"target\":\"zerovec\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"displaydoc 0.2.5\",\"target\":\"displaydoc\"}]},\"library_target_name\":\"icu_normalizer\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_normalizer\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f\",\"url\":\"https://static.crates.io/crates/icu_normalizer/1.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"icu_normalizer\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.5.0\"},\"icu_normalizer_data 1.5.1\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"icu_normalizer_data\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_normalizer_data\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7\",\"url\":\"https://static.crates.io/crates/icu_normalizer_data/1.5.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"icu_normalizer_data\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.5.1\"},\"icu_properties 1.5.1\":{\"common_attrs\":{\"crate_features\":[\"compiled_data\",\"default\"],\"deps\":[{\"id\":\"icu_collections 1.5.0\",\"target\":\"icu_collections\"},{\"id\":\"icu_locid_transform 1.5.0\",\"target\":\"icu_locid_transform\"},{\"id\":\"icu_properties_data 1.5.1\",\"target\":\"icu_properties_data\"},{\"id\":\"icu_provider 1.5.0\",\"target\":\"icu_provider\"},{\"id\":\"tinystr 0.7.6\",\"target\":\"tinystr\"},{\"id\":\"zerovec 0.10.4\",\"target\":\"zerovec\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"displaydoc 0.2.5\",\"target\":\"displaydoc\"}]},\"library_target_name\":\"icu_properties\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_properties\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5\",\"url\":\"https://static.crates.io/crates/icu_properties/1.5.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"icu_properties\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.5.1\"},\"icu_properties_data 1.5.1\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"icu_properties_data\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_properties_data\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2\",\"url\":\"https://static.crates.io/crates/icu_properties_data/1.5.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"icu_properties_data\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.5.1\"},\"icu_provider 1.5.0\":{\"common_attrs\":{\"crate_features\":[\"macros\"],\"deps\":[{\"id\":\"icu_locid 1.5.0\",\"target\":\"icu_locid\"},{\"id\":\"stable_deref_trait 1.2.0\",\"target\":\"stable_deref_trait\"},{\"id\":\"tinystr 0.7.6\",\"target\":\"tinystr\"},{\"id\":\"writeable 0.5.5\",\"target\":\"writeable\"},{\"id\":\"yoke 0.7.5\",\"target\":\"yoke\"},{\"id\":\"zerofrom 0.1.6\",\"target\":\"zerofrom\"},{\"id\":\"zerovec 0.10.4\",\"target\":\"zerovec\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"displaydoc 0.2.5\",\"target\":\"displaydoc\"},{\"id\":\"icu_provider_macros 1.5.0\",\"target\":\"icu_provider_macros\"}]},\"library_target_name\":\"icu_provider\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_provider\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9\",\"url\":\"https://static.crates.io/crates/icu_provider/1.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"icu_provider\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.5.0\"},\"icu_provider_macros 1.5.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"icu_provider_macros\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_provider_macros\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6\",\"url\":\"https://static.crates.io/crates/icu_provider_macros/1.5.0/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"icu_provider_macros\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.5.0\"},\"id-arena 2.2.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2015\"},\"library_target_name\":\"id_arena\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"id-arena\",\"package_url\":\"https://github.com/fitzgen/id-arena\",\"repository\":{\"Http\":{\"sha256\":\"25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005\",\"url\":\"https://static.crates.io/crates/id-arena/2.2.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"id_arena\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.2.1\"},\"ident_case 1.0.1\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"ident_case\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"ident_case\",\"package_url\":\"https://github.com/TedDriggs/ident_case\",\"repository\":{\"Http\":{\"sha256\":\"b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39\",\"url\":\"https://static.crates.io/crates/ident_case/1.0.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ident_case\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.1\"},\"idna 1.0.3\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"compiled_data\",\"std\"],\"deps\":[{\"id\":\"idna_adapter 1.2.0\",\"target\":\"idna_adapter\"},{\"id\":\"smallvec 1.13.2\",\"target\":\"smallvec\"},{\"id\":\"utf8_iter 1.0.4\",\"target\":\"utf8_iter\"}],\"edition\":\"2018\"},\"library_target_name\":\"idna\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"idna\",\"package_url\":\"https://github.com/servo/rust-url/\",\"repository\":{\"Http\":{\"sha256\":\"686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e\",\"url\":\"https://static.crates.io/crates/idna/1.0.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"idna\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.3\"},\"idna_adapter 1.2.0\":{\"common_attrs\":{\"crate_features\":[\"compiled_data\"],\"deps\":[{\"id\":\"icu_normalizer 1.5.0\",\"target\":\"icu_normalizer\"},{\"id\":\"icu_properties 1.5.1\",\"target\":\"icu_properties\"}],\"edition\":\"2021\"},\"library_target_name\":\"idna_adapter\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"idna_adapter\",\"package_url\":\"https://github.com/hsivonen/idna_adapter\",\"repository\":{\"Http\":{\"sha256\":\"daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71\",\"url\":\"https://static.crates.io/crates/idna_adapter/1.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"idna_adapter\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.0\"},\"ignore 0.4.22\":{\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"crossbeam-deque 0.8.5\",\"target\":\"crossbeam_deque\"},{\"id\":\"globset 0.4.14\",\"target\":\"globset\"},{\"id\":\"log 0.4.20\",\"target\":\"log\"},{\"id\":\"memchr 2.7.1\",\"target\":\"memchr\"},{\"id\":\"regex-automata 0.4.3\",\"target\":\"regex_automata\"},{\"id\":\"same-file 1.0.6\",\"target\":\"same_file\"},{\"id\":\"walkdir 2.4.0\",\"target\":\"walkdir\"}],\"selects\":{\"cfg(windows)\":[{\"id\":\"winapi-util 0.1.6\",\"target\":\"winapi_util\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"ignore\",\"license\":\"Unlicense OR MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"ignore\",\"package_url\":\"https://github.com/BurntSushi/ripgrep/tree/master/crates/ignore\",\"repository\":{\"Http\":{\"sha256\":\"b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1\",\"url\":\"https://static.crates.io/crates/ignore/0.4.22/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ignore\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.22\"},\"indexmap 2.9.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"serde\",\"std\"],\"deps\":[{\"id\":\"equivalent 1.0.1\",\"target\":\"equivalent\"},{\"id\":\"hashbrown 0.15.2\",\"target\":\"hashbrown\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"}],\"edition\":\"2021\"},\"library_target_name\":\"indexmap\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"indexmap\",\"package_url\":\"https://github.com/indexmap-rs/indexmap\",\"repository\":{\"Http\":{\"sha256\":\"cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e\",\"url\":\"https://static.crates.io/crates/indexmap/2.9.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"indexmap\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.9.0\"},\"insta 1.41.1\":{\"common_attrs\":{\"crate_features\":[\"colors\",\"console\",\"default\",\"filters\",\"regex\",\"serde\",\"yaml\"],\"deps\":[{\"id\":\"console 0.15.11\",\"target\":\"console\"},{\"id\":\"lazy_static 1.5.0\",\"target\":\"lazy_static\"},{\"id\":\"linked-hash-map 0.5.6\",\"target\":\"linked_hash_map\"},{\"id\":\"regex 1.10.2\",\"target\":\"regex\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"},{\"id\":\"similar 2.7.0\",\"target\":\"similar\"}],\"edition\":\"2021\"},\"library_target_name\":\"insta\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"insta\",\"package_url\":\"https://github.com/mitsuhiko/insta\",\"repository\":{\"Http\":{\"sha256\":\"7e9ffc4d4892617c50a928c52b2961cb5174b6fc6ebf252b2fac9d21955c48b8\",\"url\":\"https://static.crates.io/crates/insta/1.41.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"insta\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.41.1\"},\"instant 0.1.12\":{\"common_attrs\":{\"crate_features\":[\"js-sys\",\"wasm-bindgen\",\"wasm-bindgen_rs\",\"web-sys\"],\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"}],\"selects\":{\"wasm32-unknown-unknown\":[{\"id\":\"js-sys 0.3.78\",\"target\":\"js_sys\"},{\"alias\":\"wasm_bindgen_rs\",\"id\":\"wasm-bindgen 0.2.101\",\"target\":\"wasm_bindgen\"},{\"id\":\"web-sys 0.3.78\",\"target\":\"web_sys\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"instant\",\"license\":\"BSD-3-Clause\",\"license_file\":\"LICENSE\",\"license_ids\":[\"BSD-3-Clause\"],\"name\":\"instant\",\"package_url\":\"https://github.com/sebcrozet/instant\",\"repository\":{\"Http\":{\"sha256\":\"7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c\",\"url\":\"https://static.crates.io/crates/instant/0.1.12/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"instant\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.12\"},\"ipnet 2.11.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"ipnet\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"ipnet\",\"package_url\":\"https://github.com/krisprice/ipnet\",\"repository\":{\"Http\":{\"sha256\":\"469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130\",\"url\":\"https://static.crates.io/crates/ipnet/2.11.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ipnet\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.11.0\"},\"iprange 0.6.7\":{\"common_attrs\":{\"deps\":[{\"id\":\"ipnet 2.11.0\",\"target\":\"ipnet\"}],\"edition\":\"2015\"},\"library_target_name\":\"iprange\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"iprange\",\"package_url\":\"https://github.com/sticnarf/iprange-rs\",\"repository\":{\"Http\":{\"sha256\":\"37209be0ad225457e63814401415e748e2453a5297f9b637338f5fb8afa4ec00\",\"url\":\"https://static.crates.io/crates/iprange/0.6.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"iprange\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.7\"},\"itertools 0.12.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"either 1.13.0\",\"target\":\"either\"}],\"edition\":\"2018\"},\"library_target_name\":\"itertools\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"itertools\",\"package_url\":\"https://github.com/rust-itertools/itertools\",\"repository\":{\"Http\":{\"sha256\":\"ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569\",\"url\":\"https://static.crates.io/crates/itertools/0.12.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"itertools\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.12.1\"},\"itoa 1.0.10\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"itoa\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"itoa\",\"package_url\":\"https://github.com/dtolnay/itoa\",\"repository\":{\"Http\":{\"sha256\":\"b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c\",\"url\":\"https://static.crates.io/crates/itoa/1.0.10/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"itoa\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.10\"},\"js-sys 0.3.78\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"once_cell 1.19.0\",\"target\":\"once_cell\"},{\"id\":\"wasm-bindgen 0.2.101\",\"target\":\"wasm_bindgen\"}],\"edition\":\"2021\"},\"library_target_name\":\"js_sys\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"js-sys\",\"package_url\":\"https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/js-sys\",\"repository\":{\"Http\":{\"sha256\":\"0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738\",\"url\":\"https://static.crates.io/crates/js-sys/0.3.78/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"js_sys\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.78\"},\"lalrpop-util 0.22.1\":{\"common_attrs\":{\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"rustversion 1.0.20\",\"target\":\"rustversion\"}]},\"library_target_name\":\"lalrpop_util\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"lalrpop-util\",\"package_url\":\"https://github.com/lalrpop/lalrpop\",\"repository\":{\"Http\":{\"sha256\":\"e8d05b3fe34b8bd562c338db725dfa9beb9451a48f65f129ccb9538b48d2c93b\",\"url\":\"https://static.crates.io/crates/lalrpop-util/0.22.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"lalrpop_util\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.22.1\"},\"lazy_static 1.5.0\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"lazy_static\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"lazy_static\",\"package_url\":\"https://github.com/rust-lang-nursery/lazy-static.rs\",\"repository\":{\"Http\":{\"sha256\":\"bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe\",\"url\":\"https://static.crates.io/crates/lazy_static/1.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"lazy_static\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.5.0\"},\"leb128 0.2.5\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"leb128\",\"license\":\"Apache-2.0/MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"leb128\",\"package_url\":\"https://github.com/gimli-rs/leb128\",\"repository\":{\"Http\":{\"sha256\":\"884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67\",\"url\":\"https://static.crates.io/crates/leb128/0.2.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"leb128\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.5\"},\"leb128fmt 0.1.0\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"leb128fmt\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"leb128fmt\",\"package_url\":\"https://github.com/bluk/leb128fmt\",\"repository\":{\"Http\":{\"sha256\":\"09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2\",\"url\":\"https://static.crates.io/crates/leb128fmt/0.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"leb128fmt\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.0\"},\"lexical-sort 0.3.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"any_ascii 0.1.7\",\"target\":\"any_ascii\"}],\"edition\":\"2018\"},\"library_target_name\":\"lexical_sort\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"lexical-sort\",\"package_url\":\"https://github.com/Aloso/lexical-sort\",\"repository\":{\"Http\":{\"sha256\":\"c09e4591611e231daf4d4c685a66cb0410cc1e502027a20ae55f2bb9e997207a\",\"url\":\"https://static.crates.io/crates/lexical-sort/0.3.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"lexical_sort\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.1\"},\"libc 0.2.171\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"libc\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"libc\",\"package_url\":\"https://github.com/rust-lang/libc\",\"repository\":{\"Http\":{\"sha256\":\"c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6\",\"url\":\"https://static.crates.io/crates/libc/0.2.171/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"libc\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.2.171\"},\"libloading 0.8.6\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(unix)\":[{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"}],\"cfg(windows)\":[{\"id\":\"windows-targets 0.52.6\",\"target\":\"windows_targets\"}]}},\"edition\":\"2015\"},\"library_target_name\":\"libloading\",\"license\":\"ISC\",\"license_file\":\"LICENSE\",\"license_ids\":[\"ISC\"],\"name\":\"libloading\",\"package_url\":\"https://github.com/nagisa/rust_libloading/\",\"repository\":{\"Http\":{\"sha256\":\"fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34\",\"url\":\"https://static.crates.io/crates/libloading/0.8.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"libloading\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.6\"},\"libunwind 1.3.3\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"libunwind\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"libunwind\",\"package_url\":\"https://github.com/bluefish43/libunwind-sys\",\"repository\":{\"Http\":{\"sha256\":\"0c6639b70a7ce854b79c70d7e83f16b5dc0137cc914f3d7d03803b513ecc67ac\",\"url\":\"https://static.crates.io/crates/libunwind/1.3.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"libunwind\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.3.3\"},\"linked-hash-map 0.5.6\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"linked_hash_map\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"linked-hash-map\",\"package_url\":\"https://github.com/contain-rs/linked-hash-map\",\"repository\":{\"Http\":{\"sha256\":\"0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f\",\"url\":\"https://static.crates.io/crates/linked-hash-map/0.5.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"linked_hash_map\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.6\"},\"linked_hash_set 0.1.4\":{\"common_attrs\":{\"deps\":[{\"id\":\"linked-hash-map 0.5.6\",\"target\":\"linked_hash_map\"}],\"edition\":\"2018\"},\"library_target_name\":\"linked_hash_set\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"linked_hash_set\",\"package_url\":\"https://github.com/alexheretic/linked-hash-set\",\"repository\":{\"Http\":{\"sha256\":\"47186c6da4d81ca383c7c47c1bfc80f4b95f4720514d860a5407aaf4233f9588\",\"url\":\"https://static.crates.io/crates/linked_hash_set/0.1.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"linked_hash_set\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.4\"},\"linux-raw-sys 0.4.12\":{\"common_attrs\":{\"crate_features\":[\"elf\",\"errno\",\"general\",\"ioctl\",\"no_std\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"linux_raw_sys\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"linux-raw-sys\",\"package_url\":\"https://github.com/sunfishcode/linux-raw-sys\",\"repository\":{\"Http\":{\"sha256\":\"c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456\",\"url\":\"https://static.crates.io/crates/linux-raw-sys/0.4.12/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"linux_raw_sys\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.12\"},\"litemap 0.7.5\":{\"common_attrs\":{\"crate_features\":[\"alloc\"],\"edition\":\"2021\"},\"library_target_name\":\"litemap\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"litemap\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856\",\"url\":\"https://static.crates.io/crates/litemap/0.7.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"litemap\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.5\"},\"litrs 0.4.1\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"litrs\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"litrs\",\"package_url\":\"https://github.com/LukasKalbertodt/litrs/\",\"repository\":{\"Http\":{\"sha256\":\"b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5\",\"url\":\"https://static.crates.io/crates/litrs/0.4.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"litrs\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.1\"},\"lock_api 0.4.11\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"autocfg 1.1.0\",\"target\":\"autocfg\"}]},\"common_attrs\":{\"crate_features\":[\"atomic_usize\",\"default\"],\"deps\":[{\"id\":\"scopeguard 1.2.0\",\"target\":\"scopeguard\"}],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"lock_api\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"lock_api\",\"package_url\":\"https://github.com/Amanieu/parking_lot\",\"repository\":{\"Http\":{\"sha256\":\"3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45\",\"url\":\"https://static.crates.io/crates/lock_api/0.4.11/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"lock_api\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.4.11\"},\"log 0.4.20\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"edition\":\"2015\"},\"library_target_name\":\"log\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"log\",\"package_url\":\"https://github.com/rust-lang/log\",\"repository\":{\"Http\":{\"sha256\":\"b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f\",\"url\":\"https://static.crates.io/crates/log/0.4.20/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"log\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.20\"},\"logos 0.14.4\":{\"common_attrs\":{\"crate_features\":[\"default\",\"export_derive\",\"logos-derive\",\"std\"],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"logos-derive 0.14.4\",\"target\":\"logos_derive\"}]},\"library_target_name\":\"logos\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"logos\",\"package_url\":\"https://github.com/maciejhirsz/logos\",\"repository\":{\"Http\":{\"sha256\":\"7251356ef8cb7aec833ddf598c6cb24d17b689d20b993f9d11a3d764e34e6458\",\"url\":\"https://static.crates.io/crates/logos/0.14.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"logos\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.14.4\"},\"logos-codegen 0.14.4\":{\"common_attrs\":{\"deps\":[{\"id\":\"beef 0.5.2\",\"target\":\"beef\"},{\"id\":\"fnv 1.0.7\",\"target\":\"fnv\"},{\"id\":\"lazy_static 1.5.0\",\"target\":\"lazy_static\"},{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"regex-syntax 0.8.2\",\"target\":\"regex_syntax\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"logos_codegen\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"logos-codegen\",\"package_url\":\"https://github.com/maciejhirsz/logos\",\"repository\":{\"Http\":{\"sha256\":\"59f80069600c0d66734f5ff52cc42f2dabd6b29d205f333d61fd7832e9e9963f\",\"url\":\"https://static.crates.io/crates/logos-codegen/0.14.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"logos_codegen\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.14.4\"},\"logos-derive 0.14.4\":{\"common_attrs\":{\"deps\":[{\"id\":\"logos-codegen 0.14.4\",\"target\":\"logos_codegen\"}],\"edition\":\"2021\"},\"library_target_name\":\"logos_derive\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"logos-derive\",\"package_url\":\"https://github.com/maciejhirsz/logos\",\"repository\":{\"Http\":{\"sha256\":\"24fb722b06a9dc12adb0963ed585f19fc61dc5413e6a9be9422ef92c091e731d\",\"url\":\"https://static.crates.io/crates/logos-derive/0.14.4/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"logos_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.14.4\"},\"lz4_flex 0.11.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"frame\",\"safe-decode\",\"safe-encode\",\"std\"],\"deps\":[{\"id\":\"twox-hash 1.6.3\",\"target\":\"twox_hash\"}],\"edition\":\"2021\"},\"library_target_name\":\"lz4_flex\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"lz4_flex\",\"package_url\":\"https://github.com/pseitz/lz4_flex\",\"repository\":{\"Http\":{\"sha256\":\"3ea9b256699eda7b0387ffbc776dd625e28bde3918446381781245b7a50349d8\",\"url\":\"https://static.crates.io/crates/lz4_flex/0.11.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"lz4_flex\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.11.1\"},\"mach2 0.4.2\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"ios\\\"))\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}]}},\"edition\":\"2015\"},\"library_target_name\":\"mach2\",\"license\":\"BSD-2-Clause OR MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"BSD-2-Clause\",\"MIT\"],\"name\":\"mach2\",\"package_url\":\"https://github.com/JohnTitor/mach2\",\"repository\":{\"Http\":{\"sha256\":\"19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709\",\"url\":\"https://static.crates.io/crates/mach2/0.4.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"mach2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.2\"},\"macho-unwind-info 0.5.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"thiserror 2.0.12\",\"target\":\"thiserror\"},{\"id\":\"zerocopy 0.8.24\",\"target\":\"zerocopy\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"zerocopy-derive 0.8.24\",\"target\":\"zerocopy_derive\"}]},\"library_target_name\":\"macho_unwind_info\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"macho-unwind-info\",\"package_url\":\"https://github.com/mstange/macho-unwind-info\",\"repository\":{\"Http\":{\"sha256\":\"bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149\",\"url\":\"https://static.crates.io/crates/macho-unwind-info/0.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"macho_unwind_info\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.0\"},\"managed 0.8.0\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"map\",\"std\"],\"edition\":\"2015\"},\"library_target_name\":\"managed\",\"license\":\"0BSD\",\"license_file\":\"LICENSE-0BSD.txt\",\"license_ids\":[\"0BSD\"],\"name\":\"managed\",\"package_url\":\"https://github.com/m-labs/rust-managed.git\",\"repository\":{\"Http\":{\"sha256\":\"0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d\",\"url\":\"https://static.crates.io/crates/managed/0.8.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"managed\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.0\"},\"matchers 0.1.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"regex-automata 0.1.10\",\"target\":\"regex_automata\"}],\"edition\":\"2018\"},\"library_target_name\":\"matchers\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"matchers\",\"package_url\":\"https://github.com/hawkw/matchers\",\"repository\":{\"Http\":{\"sha256\":\"8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558\",\"url\":\"https://static.crates.io/crates/matchers/0.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"matchers\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.0\"},\"memchr 2.7.1\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"memchr\",\"license\":\"Unlicense OR MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"memchr\",\"package_url\":\"https://github.com/BurntSushi/memchr\",\"repository\":{\"Http\":{\"sha256\":\"523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149\",\"url\":\"https://static.crates.io/crates/memchr/2.7.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"memchr\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.7.1\"},\"memmap2 0.6.2\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(unix)\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"memmap2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"memmap2\",\"package_url\":\"https://github.com/RazrFalcon/memmap2-rs\",\"repository\":{\"Http\":{\"sha256\":\"6d28bba84adfe6646737845bc5ebbfa2c08424eb1c37e94a1fd2a82adb56a872\",\"url\":\"https://static.crates.io/crates/memmap2/0.6.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"memmap2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.2\"},\"memoffset 0.9.0\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"autocfg 1.1.0\",\"target\":\"autocfg\"}]},\"common_attrs\":{\"crate_features\":[\"default\"],\"edition\":\"2015\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"memoffset\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"memoffset\",\"package_url\":\"https://github.com/Gilnaa/memoffset\",\"repository\":{\"Http\":{\"sha256\":\"5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c\",\"url\":\"https://static.crates.io/crates/memoffset/0.9.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"memoffset\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.9.0\"},\"merge-streams 0.1.2\":{\"common_attrs\":{\"deps\":[{\"id\":\"futures-core 0.3.31\",\"target\":\"futures_core\"},{\"id\":\"pin-project 1.1.3\",\"target\":\"pin_project\"}],\"edition\":\"2021\"},\"library_target_name\":\"merge_streams\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"merge-streams\",\"package_url\":\"https://github.com/phil-opp/merge-streams\",\"repository\":{\"Http\":{\"sha256\":\"4f84f6452969abd246e7ac1fe4fe75906c76e8ec88d898df9aef37e0f3b6a7c2\",\"url\":\"https://static.crates.io/crates/merge-streams/0.1.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"merge_streams\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.2\"},\"mime 0.3.17\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"mime\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"mime\",\"package_url\":\"https://github.com/hyperium/mime\",\"repository\":{\"Http\":{\"sha256\":\"6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a\",\"url\":\"https://static.crates.io/crates/mime/0.3.17/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"mime\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.17\"},\"minicov 0.3.7\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"cc 1.2.18\",\"target\":\"cc\"},{\"id\":\"walkdir 2.4.0\",\"target\":\"walkdir\"}]},\"common_attrs\":{\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"minicov\",\"license\":\"Apache-2.0/MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"minicov\",\"package_url\":\"https://github.com/Amanieu/minicov\",\"repository\":{\"Http\":{\"sha256\":\"f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b\",\"url\":\"https://static.crates.io/crates/minicov/0.3.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"minicov\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.3.7\"},\"minimal-lexical 0.2.1\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"minimal_lexical\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"minimal-lexical\",\"package_url\":\"https://github.com/Alexhuszagh/minimal-lexical\",\"repository\":{\"Http\":{\"sha256\":\"68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a\",\"url\":\"https://static.crates.io/crates/minimal-lexical/0.2.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"minimal_lexical\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.1\"},\"miniz_oxide 0.7.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"adler 1.0.2\",\"target\":\"adler\"}],\"edition\":\"2018\"},\"library_target_name\":\"miniz_oxide\",\"license\":\"MIT OR Zlib OR Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\",\"MIT\",\"Zlib\"],\"name\":\"miniz_oxide\",\"package_url\":\"https://github.com/Frommi/miniz_oxide/tree/master/miniz_oxide\",\"repository\":{\"Http\":{\"sha256\":\"e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7\",\"url\":\"https://static.crates.io/crates/miniz_oxide/0.7.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"miniz_oxide\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.1\"},\"miniz_oxide 0.8.7\":{\"common_attrs\":{\"crate_features\":[\"with-alloc\"],\"deps\":[{\"id\":\"adler2 2.0.0\",\"target\":\"adler2\"}],\"edition\":\"2021\"},\"library_target_name\":\"miniz_oxide\",\"license\":\"MIT OR Zlib OR Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\",\"MIT\",\"Zlib\"],\"name\":\"miniz_oxide\",\"package_url\":\"https://github.com/Frommi/miniz_oxide/tree/master/miniz_oxide\",\"repository\":{\"Http\":{\"sha256\":\"ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430\",\"url\":\"https://static.crates.io/crates/miniz_oxide/0.8.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"miniz_oxide\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.7\"},\"mio 1.0.3\":{\"common_attrs\":{\"crate_features\":[\"net\",\"os-ext\",\"os-poll\"],\"deps\":{\"common\":[],\"selects\":{\"cfg(target_os = \\\"hermit\\\")\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"cfg(target_os = \\\"wasi\\\")\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"},{\"id\":\"wasi 0.11.0+wasi-snapshot-preview1\",\"target\":\"wasi\"}],\"cfg(unix)\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"cfg(windows)\":[{\"id\":\"windows-sys 0.52.0\",\"target\":\"windows_sys\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"mio\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"mio\",\"package_url\":\"https://github.com/tokio-rs/mio\",\"repository\":{\"Http\":{\"sha256\":\"2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd\",\"url\":\"https://static.crates.io/crates/mio/1.0.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"mio\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.3\"},\"more-asserts 0.2.2\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"more_asserts\",\"license\":\"CC0-1.0\",\"license_file\":\"LICENSE-CC0\",\"license_ids\":[\"CC0-1.0\"],\"name\":\"more-asserts\",\"package_url\":\"https://github.com/thomcc/rust-more-asserts\",\"repository\":{\"Http\":{\"sha256\":\"7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389\",\"url\":\"https://static.crates.io/crates/more-asserts/0.2.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"more_asserts\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.2\"},\"munge 0.4.3\":{\"common_attrs\":{\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"munge_macro 0.4.3\",\"target\":\"munge_macro\"}]},\"library_target_name\":\"munge\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"munge\",\"package_url\":\"https://github.com/djkoloski/munge\",\"repository\":{\"Http\":{\"sha256\":\"a0091202c98cf06da46c279fdf50cccb6b1c43b4521abdf6a27b4c7e71d5d9d7\",\"url\":\"https://static.crates.io/crates/munge/0.4.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"munge\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.3\"},\"munge_macro 0.4.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"munge_macro\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"munge_macro\",\"package_url\":\"https://github.com/djkoloski/munge\",\"repository\":{\"Http\":{\"sha256\":\"734799cf91479720b2f970c61a22850940dd91e27d4f02b1c6fc792778df2459\",\"url\":\"https://static.crates.io/crates/munge_macro/0.4.3/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"munge_macro\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.3\"},\"native-tls 0.2.12\":{\"build_script_attrs\":{\"link_deps\":{\"common\":[],\"selects\":{\"cfg(not(any(target_os = \\\"windows\\\", target_vendor = \\\"apple\\\")))\":[{\"id\":\"openssl-sys 0.9.102\",\"target\":\"openssl_sys\"}]}}},\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(not(any(target_os = \\\"windows\\\", target_vendor = \\\"apple\\\")))\":[{\"id\":\"log 0.4.20\",\"target\":\"log\"},{\"id\":\"openssl 0.10.64\",\"target\":\"openssl\"},{\"id\":\"openssl-probe 0.1.5\",\"target\":\"openssl_probe\"},{\"id\":\"openssl-sys 0.9.102\",\"target\":\"openssl_sys\"}],\"cfg(target_os = \\\"macos\\\")\":[{\"id\":\"tempfile 3.12.0\",\"target\":\"tempfile\"}],\"cfg(target_os = \\\"windows\\\")\":[{\"id\":\"schannel 0.1.23\",\"target\":\"schannel\"}],\"cfg(target_vendor = \\\"apple\\\")\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"},{\"id\":\"security-framework 2.10.0\",\"target\":\"security_framework\"},{\"id\":\"security-framework-sys 2.14.0\",\"target\":\"security_framework_sys\"}]}},\"edition\":\"2015\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"native_tls\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"native-tls\",\"package_url\":\"https://github.com/sfackler/rust-native-tls\",\"repository\":{\"Http\":{\"sha256\":\"a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466\",\"url\":\"https://static.crates.io/crates/native-tls/0.2.12/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"native_tls\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.2.12\"},\"nom 5.1.3\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"version_check 0.9.5\",\"target\":\"version_check\"}]},\"common_attrs\":{\"deps\":[{\"id\":\"memchr 2.7.1\",\"target\":\"memchr\"}],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"nom\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"nom\",\"package_url\":\"https://github.com/Geal/nom\",\"repository\":{\"Http\":{\"sha256\":\"08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b\",\"url\":\"https://static.crates.io/crates/nom/5.1.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"nom\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"5.1.3\"},\"nom 7.1.3\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"std\"],\"deps\":[{\"id\":\"memchr 2.7.1\",\"target\":\"memchr\"},{\"id\":\"minimal-lexical 0.2.1\",\"target\":\"minimal_lexical\"}],\"edition\":\"2018\"},\"library_target_name\":\"nom\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"nom\",\"package_url\":\"https://github.com/Geal/nom\",\"repository\":{\"Http\":{\"sha256\":\"d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a\",\"url\":\"https://static.crates.io/crates/nom/7.1.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"nom\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"7.1.3\"},\"nu-ansi-term 0.46.0\":{\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"overload 0.1.1\",\"target\":\"overload\"}],\"selects\":{\"cfg(target_os = \\\"windows\\\")\":[{\"id\":\"winapi 0.3.9\",\"target\":\"winapi\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"nu_ansi_term\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"nu-ansi-term\",\"package_url\":\"https://github.com/nushell/nu-ansi-term\",\"repository\":{\"Http\":{\"sha256\":\"77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84\",\"url\":\"https://static.crates.io/crates/nu-ansi-term/0.46.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"nu_ansi_term\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.46.0\"},\"num-conv 0.1.0\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"num_conv\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-Apache\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"num-conv\",\"package_url\":\"https://github.com/jhpratt/num-conv\",\"repository\":{\"Http\":{\"sha256\":\"51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9\",\"url\":\"https://static.crates.io/crates/num-conv/0.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"num_conv\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.0\"},\"num-traits 0.2.17\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"autocfg 1.1.0\",\"target\":\"autocfg\"}]},\"common_attrs\":{\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"num_traits\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"num-traits\",\"package_url\":\"https://github.com/rust-num/num-traits\",\"repository\":{\"Http\":{\"sha256\":\"39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c\",\"url\":\"https://static.crates.io/crates/num-traits/0.2.17/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"num_traits\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.2.17\"},\"num_cpus 1.17.0\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(not(windows))\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"cfg(target_os = \\\"hermit\\\")\":[{\"id\":\"hermit-abi 0.5.2\",\"target\":\"hermit_abi\"}]}},\"edition\":\"2015\"},\"library_target_name\":\"num_cpus\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"num_cpus\",\"package_url\":\"https://github.com/seanmonstar/num_cpus\",\"repository\":{\"Http\":{\"sha256\":\"91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b\",\"url\":\"https://static.crates.io/crates/num_cpus/1.17.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"num_cpus\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.17.0\"},\"num_enum 0.7.3\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"num_enum_derive 0.7.3\",\"target\":\"num_enum_derive\"}]},\"library_target_name\":\"num_enum\",\"license\":\"BSD-3-Clause OR MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"BSD-3-Clause\",\"MIT\"],\"name\":\"num_enum\",\"package_url\":\"https://github.com/illicitonion/num_enum\",\"repository\":{\"Http\":{\"sha256\":\"4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179\",\"url\":\"https://static.crates.io/crates/num_enum/0.7.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"num_enum\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.3\"},\"num_enum_derive 0.7.3\":{\"common_attrs\":{\"crate_features\":[\"proc-macro-crate\",\"std\"],\"deps\":[{\"id\":\"proc-macro-crate 1.3.1\",\"target\":\"proc_macro_crate\"},{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"num_enum_derive\",\"license\":\"BSD-3-Clause OR MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"BSD-3-Clause\",\"MIT\"],\"name\":\"num_enum_derive\",\"package_url\":\"https://github.com/illicitonion/num_enum\",\"repository\":{\"Http\":{\"sha256\":\"af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56\",\"url\":\"https://static.crates.io/crates/num_enum_derive/0.7.3/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"num_enum_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.3\"},\"object 0.32.2\":{\"common_attrs\":{\"crate_features\":[\"archive\",\"coff\",\"compression\",\"default\",\"elf\",\"macho\",\"pe\",\"read\",\"read_core\",\"std\",\"unaligned\",\"write\",\"write_core\",\"write_std\",\"xcoff\"],\"deps\":[{\"id\":\"crc32fast 1.3.2\",\"target\":\"crc32fast\"},{\"id\":\"flate2 1.1.1\",\"target\":\"flate2\"},{\"id\":\"hashbrown 0.14.3\",\"target\":\"hashbrown\"},{\"id\":\"indexmap 2.9.0\",\"target\":\"indexmap\"},{\"id\":\"memchr 2.7.1\",\"target\":\"memchr\"},{\"id\":\"ruzstd 0.5.0\",\"target\":\"ruzstd\"}],\"edition\":\"2018\"},\"library_target_name\":\"object\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"object\",\"package_url\":\"https://github.com/gimli-rs/object\",\"repository\":{\"Http\":{\"sha256\":\"a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441\",\"url\":\"https://static.crates.io/crates/object/0.32.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"object\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.32.2\"},\"once_cell 1.19.0\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"race\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"once_cell\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"once_cell\",\"package_url\":\"https://github.com/matklad/once_cell\",\"repository\":{\"Http\":{\"sha256\":\"3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92\",\"url\":\"https://static.crates.io/crates/once_cell/1.19.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"once_cell\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.19.0\"},\"openssl 0.10.64\":{\"build_script_attrs\":{\"link_deps\":[{\"alias\":\"ffi\",\"id\":\"openssl-sys 0.9.102\",\"target\":\"openssl_sys\"}]},\"common_attrs\":{\"crate_features\":[\"default\"],\"deps\":[{\"id\":\"bitflags 2.9.0\",\"target\":\"bitflags\"},{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"},{\"id\":\"foreign-types 0.3.2\",\"target\":\"foreign_types\"},{\"id\":\"libc 0.2.171\",\"target\":\"libc\"},{\"id\":\"once_cell 1.19.0\",\"target\":\"once_cell\"},{\"alias\":\"ffi\",\"id\":\"openssl-sys 0.9.102\",\"target\":\"openssl_sys\"}],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":[{\"id\":\"openssl-macros 0.1.1\",\"target\":\"openssl_macros\"}]},\"library_target_name\":\"openssl\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"openssl\",\"package_url\":\"https://github.com/sfackler/rust-openssl\",\"repository\":{\"Http\":{\"sha256\":\"95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f\",\"url\":\"https://static.crates.io/crates/openssl/0.10.64/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"openssl\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.10.64\"},\"openssl-macros 0.1.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2018\"},\"library_target_name\":\"openssl_macros\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"openssl-macros\",\"repository\":{\"Http\":{\"sha256\":\"a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c\",\"url\":\"https://static.crates.io/crates/openssl-macros/0.1.1/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"openssl_macros\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.1\"},\"openssl-probe 0.1.5\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"openssl_probe\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"openssl-probe\",\"package_url\":\"https://github.com/alexcrichton/openssl-probe\",\"repository\":{\"Http\":{\"sha256\":\"ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf\",\"url\":\"https://static.crates.io/crates/openssl-probe/0.1.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"openssl_probe\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.5\"},\"openssl-sys 0.9.102\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"cc 1.2.18\",\"target\":\"cc\"},{\"id\":\"pkg-config 0.3.30\",\"target\":\"pkg_config\"},{\"id\":\"vcpkg 0.2.15\",\"target\":\"vcpkg\"}],\"links\":\"openssl\"},\"common_attrs\":{\"deps\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"edition\":\"2018\",\"extra_deps\":[\":build_script_main\"]},\"library_target_name\":\"openssl_sys\",\"license\":\"MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\"],\"name\":\"openssl-sys\",\"package_url\":\"https://github.com/sfackler/rust-openssl\",\"repository\":{\"Http\":{\"sha256\":\"c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2\",\"url\":\"https://static.crates.io/crates/openssl-sys/0.9.102/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"openssl_sys\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_main\",\"crate_root\":\"build/main.rs\"}}],\"version\":\"0.9.102\"},\"ouroboros 0.18.5\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"aliasable 0.1.3\",\"target\":\"aliasable\"},{\"id\":\"static_assertions 1.1.0\",\"target\":\"static_assertions\"}],\"edition\":\"2018\",\"proc_macro_deps\":[{\"id\":\"ouroboros_macro 0.18.5\",\"target\":\"ouroboros_macro\"}]},\"library_target_name\":\"ouroboros\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE_APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"ouroboros\",\"package_url\":\"https://github.com/someguynamedjosh/ouroboros\",\"repository\":{\"Http\":{\"sha256\":\"1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59\",\"url\":\"https://static.crates.io/crates/ouroboros/0.18.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ouroboros\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.18.5\"},\"ouroboros_macro 0.18.5\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"deps\":[{\"id\":\"heck 0.4.1\",\"target\":\"heck\"},{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"proc-macro2-diagnostics 0.10.1\",\"target\":\"proc_macro2_diagnostics\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2018\"},\"library_target_name\":\"ouroboros_macro\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE_APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"ouroboros_macro\",\"package_url\":\"https://github.com/someguynamedjosh/ouroboros\",\"repository\":{\"Http\":{\"sha256\":\"3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0\",\"url\":\"https://static.crates.io/crates/ouroboros_macro/0.18.5/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"ouroboros_macro\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.18.5\"},\"overload 0.1.1\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"overload\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"overload\",\"package_url\":\"https://github.com/danaugrs/overload\",\"repository\":{\"Http\":{\"sha256\":\"b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39\",\"url\":\"https://static.crates.io/crates/overload/0.1.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"overload\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.1\"},\"parking_lot_core 0.9.9\":{\"build_script_attrs\":{},\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"},{\"id\":\"smallvec 1.13.2\",\"target\":\"smallvec\"}],\"selects\":{\"cfg(target_os = \\\"redox\\\")\":[{\"id\":\"redox_syscall 0.4.1\",\"target\":\"syscall\"}],\"cfg(unix)\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"cfg(windows)\":[{\"id\":\"windows-targets 0.48.5\",\"target\":\"windows_targets\"}]}},\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"parking_lot_core\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"parking_lot_core\",\"package_url\":\"https://github.com/Amanieu/parking_lot\",\"repository\":{\"Http\":{\"sha256\":\"4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e\",\"url\":\"https://static.crates.io/crates/parking_lot_core/0.9.9/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"parking_lot_core\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.9.9\"},\"paste 1.0.15\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"paste\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"paste\",\"package_url\":\"https://github.com/dtolnay/paste\",\"repository\":{\"Http\":{\"sha256\":\"57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a\",\"url\":\"https://static.crates.io/crates/paste/1.0.15/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"paste\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.15\"},\"path-clean 1.0.1\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"path_clean\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"path-clean\",\"package_url\":\"https://github.com/danreeves/path-clean\",\"repository\":{\"Http\":{\"sha256\":\"17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef\",\"url\":\"https://static.crates.io/crates/path-clean/1.0.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"path_clean\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.1\"},\"percent-encoding 2.3.1\":{\"common_attrs\":{\"crate_features\":{\"common\":[\"alloc\",\"std\"],\"selects\":{\"x86_64-unknown-linux-gnu\":[\"default\"]}},\"edition\":\"2018\"},\"library_target_name\":\"percent_encoding\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"percent-encoding\",\"package_url\":\"https://github.com/servo/rust-url/\",\"repository\":{\"Http\":{\"sha256\":\"e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e\",\"url\":\"https://static.crates.io/crates/percent-encoding/2.3.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"percent_encoding\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.3.1\"},\"petgraph 0.7.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"graphmap\",\"matrix_graph\",\"stable_graph\"],\"deps\":[{\"id\":\"fixedbitset 0.5.7\",\"target\":\"fixedbitset\"},{\"id\":\"indexmap 2.9.0\",\"target\":\"indexmap\"}],\"edition\":\"2018\"},\"library_target_name\":\"petgraph\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"petgraph\",\"package_url\":\"https://github.com/petgraph/petgraph\",\"repository\":{\"Http\":{\"sha256\":\"3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772\",\"url\":\"https://static.crates.io/crates/petgraph/0.7.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"petgraph\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.1\"},\"pin-project 1.1.3\":{\"common_attrs\":{\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"pin-project-internal 1.1.3\",\"target\":\"pin_project_internal\"}]},\"library_target_name\":\"pin_project\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"pin-project\",\"package_url\":\"https://github.com/taiki-e/pin-project\",\"repository\":{\"Http\":{\"sha256\":\"fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422\",\"url\":\"https://static.crates.io/crates/pin-project/1.1.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"pin_project\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.3\"},\"pin-project-internal 1.1.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"pin_project_internal\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"pin-project-internal\",\"package_url\":\"https://github.com/taiki-e/pin-project\",\"repository\":{\"Http\":{\"sha256\":\"4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405\",\"url\":\"https://static.crates.io/crates/pin-project-internal/1.1.3/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"pin_project_internal\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.3\"},\"pin-project-lite 0.2.13\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"pin_project_lite\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"pin-project-lite\",\"package_url\":\"https://github.com/taiki-e/pin-project-lite\",\"repository\":{\"Http\":{\"sha256\":\"8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58\",\"url\":\"https://static.crates.io/crates/pin-project-lite/0.2.13/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"pin_project_lite\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.13\"},\"pin-utils 0.1.0\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"pin_utils\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"pin-utils\",\"package_url\":\"https://github.com/rust-lang-nursery/pin-utils\",\"repository\":{\"Http\":{\"sha256\":\"8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184\",\"url\":\"https://static.crates.io/crates/pin-utils/0.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"pin_utils\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.0\"},\"pkg-config 0.3.30\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"pkg_config\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"pkg-config\",\"package_url\":\"https://github.com/rust-lang/pkg-config-rs\",\"repository\":{\"Http\":{\"sha256\":\"d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec\",\"url\":\"https://static.crates.io/crates/pkg-config/0.3.30/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"pkg_config\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.30\"},\"powerfmt 0.2.0\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"powerfmt\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-Apache\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"powerfmt\",\"package_url\":\"https://github.com/jhpratt/powerfmt\",\"repository\":{\"Http\":{\"sha256\":\"439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391\",\"url\":\"https://static.crates.io/crates/powerfmt/0.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"powerfmt\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.0\"},\"ppv-lite86 0.2.17\":{\"common_attrs\":{\"crate_features\":[\"simd\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"ppv_lite86\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"ppv-lite86\",\"package_url\":\"https://github.com/cryptocorrosion/cryptocorrosion\",\"repository\":{\"Http\":{\"sha256\":\"5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de\",\"url\":\"https://static.crates.io/crates/ppv-lite86/0.2.17/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ppv_lite86\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.17\"},\"prettyplease 0.2.32\":{\"build_script_attrs\":{\"links\":\"prettyplease02\"},\"common_attrs\":{\"crate_features\":[\"verbatim\"],\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"prettyplease\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"prettyplease\",\"package_url\":\"https://github.com/dtolnay/prettyplease\",\"repository\":{\"Http\":{\"sha256\":\"664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6\",\"url\":\"https://static.crates.io/crates/prettyplease/0.2.32/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"prettyplease\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.2.32\"},\"proc-macro-crate 1.3.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"once_cell 1.19.0\",\"target\":\"once_cell\"},{\"id\":\"toml_edit 0.19.15\",\"target\":\"toml_edit\"}],\"edition\":\"2021\"},\"library_target_name\":\"proc_macro_crate\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"proc-macro-crate\",\"package_url\":\"https://github.com/bkchr/proc-macro-crate\",\"repository\":{\"Http\":{\"sha256\":\"7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919\",\"url\":\"https://static.crates.io/crates/proc-macro-crate/1.3.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"proc_macro_crate\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.3.1\"},\"proc-macro-error-attr2 2.0.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"}],\"edition\":\"2021\"},\"library_target_name\":\"proc_macro_error_attr2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"proc-macro-error-attr2\",\"package_url\":\"https://github.com/GnomedDev/proc-macro-error-2\",\"repository\":{\"Http\":{\"sha256\":\"96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5\",\"url\":\"https://static.crates.io/crates/proc-macro-error-attr2/2.0.0/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"proc_macro_error_attr2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.0.0\"},\"proc-macro-error2 2.0.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"syn-error\"],\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"proc-macro-error-attr2 2.0.0\",\"target\":\"proc_macro_error_attr2\"}]},\"library_target_name\":\"proc_macro_error2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"proc-macro-error2\",\"package_url\":\"https://github.com/GnomedDev/proc-macro-error-2\",\"repository\":{\"Http\":{\"sha256\":\"11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802\",\"url\":\"https://static.crates.io/crates/proc-macro-error2/2.0.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"proc_macro_error2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.0.1\"},\"proc-macro2 1.0.94\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"proc-macro\"],\"deps\":[{\"id\":\"unicode-ident 1.0.12\",\"target\":\"unicode_ident\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"proc_macro2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"proc-macro2\",\"package_url\":\"https://github.com/dtolnay/proc-macro2\",\"repository\":{\"Http\":{\"sha256\":\"a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84\",\"url\":\"https://static.crates.io/crates/proc-macro2/1.0.94/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"proc_macro2\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.94\"},\"proc-macro2-diagnostics 0.10.1\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"version_check 0.9.5\",\"target\":\"version_check\"}]},\"common_attrs\":{\"crate_features\":[\"colors\",\"default\",\"yansi\"],\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"},{\"id\":\"yansi 1.0.1\",\"target\":\"yansi\"}],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"proc_macro2_diagnostics\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"proc-macro2-diagnostics\",\"package_url\":\"https://github.com/SergioBenitez/proc-macro2-diagnostics\",\"repository\":{\"Http\":{\"sha256\":\"af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8\",\"url\":\"https://static.crates.io/crates/proc-macro2-diagnostics/0.10.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"proc_macro2_diagnostics\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.10.1\"},\"ptr_meta 0.1.4\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"edition\":\"2018\",\"proc_macro_deps\":[{\"id\":\"ptr_meta_derive 0.1.4\",\"target\":\"ptr_meta_derive\"}]},\"library_target_name\":\"ptr_meta\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"ptr_meta\",\"package_url\":\"https://github.com/djkoloski/ptr_meta\",\"repository\":{\"Http\":{\"sha256\":\"0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1\",\"url\":\"https://static.crates.io/crates/ptr_meta/0.1.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ptr_meta\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.4\"},\"ptr_meta 0.3.0\":{\"common_attrs\":{\"crate_features\":[\"derive\",\"ptr_meta_derive\",\"std\"],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"ptr_meta_derive 0.3.0\",\"target\":\"ptr_meta_derive\"}]},\"library_target_name\":\"ptr_meta\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"ptr_meta\",\"package_url\":\"https://github.com/rkyv/ptr_meta\",\"repository\":{\"Http\":{\"sha256\":\"fe9e76f66d3f9606f44e45598d155cb13ecf09f4a28199e48daf8c8fc937ea90\",\"url\":\"https://static.crates.io/crates/ptr_meta/0.3.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ptr_meta\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.0\"},\"ptr_meta_derive 0.1.4\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 1.0.109\",\"target\":\"syn\"}],\"edition\":\"2018\"},\"library_target_name\":\"ptr_meta_derive\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"ptr_meta_derive\",\"package_url\":\"https://github.com/djkoloski/ptr_meta\",\"repository\":{\"Http\":{\"sha256\":\"16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac\",\"url\":\"https://static.crates.io/crates/ptr_meta_derive/0.1.4/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"ptr_meta_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.4\"},\"ptr_meta_derive 0.3.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"ptr_meta_derive\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"ptr_meta_derive\",\"package_url\":\"https://github.com/rkyv/ptr_meta\",\"repository\":{\"Http\":{\"sha256\":\"ca414edb151b4c8d125c12566ab0d74dc9cdba36fb80eb7b848c15f495fd32d1\",\"url\":\"https://static.crates.io/crates/ptr_meta_derive/0.3.0/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"ptr_meta_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.0\"},\"pulldown-cmark 0.8.0\":{\"build_script_attrs\":{},\"common_attrs\":{\"deps\":[{\"id\":\"bitflags 1.3.2\",\"target\":\"bitflags\"},{\"id\":\"memchr 2.7.1\",\"target\":\"memchr\"},{\"id\":\"unicase 2.7.0\",\"target\":\"unicase\"}],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"pulldown_cmark\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"pulldown-cmark\",\"package_url\":\"https://github.com/raphlinus/pulldown-cmark\",\"repository\":{\"Http\":{\"sha256\":\"ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8\",\"url\":\"https://static.crates.io/crates/pulldown-cmark/0.8.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"pulldown_cmark\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.8.0\"},\"quote 1.0.35\":{\"common_attrs\":{\"crate_features\":[\"default\",\"proc-macro\"],\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"}],\"edition\":\"2018\"},\"library_target_name\":\"quote\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"quote\",\"package_url\":\"https://github.com/dtolnay/quote\",\"repository\":{\"Http\":{\"sha256\":\"291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef\",\"url\":\"https://static.crates.io/crates/quote/1.0.35/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"quote\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.35\"},\"rancor 0.1.0\":{\"common_attrs\":{\"crate_features\":[\"alloc\"],\"deps\":[{\"id\":\"ptr_meta 0.3.0\",\"target\":\"ptr_meta\"}],\"edition\":\"2021\"},\"library_target_name\":\"rancor\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"rancor\",\"package_url\":\"https://github.com/rkyv/rancor\",\"repository\":{\"Http\":{\"sha256\":\"caf5f7161924b9d1cea0e4cabc97c372cea92b5f927fc13c6bca67157a0ad947\",\"url\":\"https://static.crates.io/crates/rancor/0.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rancor\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.0\"},\"rand 0.8.5\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"getrandom\",\"libc\",\"rand_chacha\",\"std\",\"std_rng\"],\"deps\":{\"common\":[{\"id\":\"rand_chacha 0.3.1\",\"target\":\"rand_chacha\"},{\"id\":\"rand_core 0.6.4\",\"target\":\"rand_core\"}],\"selects\":{\"x86_64-unknown-linux-gnu\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"rand\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rand\",\"package_url\":\"https://github.com/rust-random/rand\",\"repository\":{\"Http\":{\"sha256\":\"34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404\",\"url\":\"https://static.crates.io/crates/rand/0.8.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rand\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.5\"},\"rand_chacha 0.3.1\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"deps\":[{\"id\":\"ppv-lite86 0.2.17\",\"target\":\"ppv_lite86\"},{\"id\":\"rand_core 0.6.4\",\"target\":\"rand_core\"}],\"edition\":\"2018\"},\"library_target_name\":\"rand_chacha\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rand_chacha\",\"package_url\":\"https://github.com/rust-random/rand\",\"repository\":{\"Http\":{\"sha256\":\"e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88\",\"url\":\"https://static.crates.io/crates/rand_chacha/0.3.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rand_chacha\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.1\"},\"rand_core 0.6.4\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"getrandom\",\"std\"],\"deps\":[{\"id\":\"getrandom 0.2.15\",\"target\":\"getrandom\"}],\"edition\":\"2018\"},\"library_target_name\":\"rand_core\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rand_core\",\"package_url\":\"https://github.com/rust-random/rand\",\"repository\":{\"Http\":{\"sha256\":\"ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c\",\"url\":\"https://static.crates.io/crates/rand_core/0.6.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rand_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.4\"},\"redox_syscall 0.4.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"bitflags 1.3.2\",\"target\":\"bitflags\"}],\"edition\":\"2018\"},\"library_target_name\":\"syscall\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"redox_syscall\",\"package_url\":\"https://gitlab.redox-os.org/redox-os/syscall\",\"repository\":{\"Http\":{\"sha256\":\"4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa\",\"url\":\"https://static.crates.io/crates/redox_syscall/0.4.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"syscall\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.1\"},\"ref-cast 1.0.24\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":[{\"id\":\"ref-cast-impl 1.0.24\",\"target\":\"ref_cast_impl\"}]},\"library_target_name\":\"ref_cast\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"ref-cast\",\"package_url\":\"https://github.com/dtolnay/ref-cast\",\"repository\":{\"Http\":{\"sha256\":\"4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf\",\"url\":\"https://static.crates.io/crates/ref-cast/1.0.24/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ref_cast\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.24\"},\"ref-cast-impl 1.0.24\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"ref_cast_impl\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"ref-cast-impl\",\"package_url\":\"https://github.com/dtolnay/ref-cast\",\"repository\":{\"Http\":{\"sha256\":\"1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7\",\"url\":\"https://static.crates.io/crates/ref-cast-impl/1.0.24/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"ref_cast_impl\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.24\"},\"regex 1.10.2\":{\"common_attrs\":{\"crate_features\":[\"std\",\"unicode\",\"unicode-age\",\"unicode-bool\",\"unicode-case\",\"unicode-gencat\",\"unicode-perl\",\"unicode-script\",\"unicode-segment\"],\"deps\":[{\"id\":\"regex-automata 0.4.3\",\"target\":\"regex_automata\"},{\"id\":\"regex-syntax 0.8.2\",\"target\":\"regex_syntax\"}],\"edition\":\"2021\"},\"library_target_name\":\"regex\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"regex\",\"package_url\":\"https://github.com/rust-lang/regex\",\"repository\":{\"Http\":{\"sha256\":\"380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343\",\"url\":\"https://static.crates.io/crates/regex/1.10.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"regex\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.10.2\"},\"regex-automata 0.1.10\":{\"common_attrs\":{\"crate_features\":[\"default\",\"regex-syntax\",\"std\"],\"deps\":[{\"id\":\"regex-syntax 0.6.29\",\"target\":\"regex_syntax\"}],\"edition\":\"2015\"},\"library_target_name\":\"regex_automata\",\"license\":\"Unlicense/MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"regex-automata\",\"package_url\":\"https://github.com/BurntSushi/regex-automata\",\"repository\":{\"Http\":{\"sha256\":\"6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132\",\"url\":\"https://static.crates.io/crates/regex-automata/0.1.10/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"regex_automata\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.10\"},\"regex-automata 0.4.3\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"dfa-onepass\",\"hybrid\",\"meta\",\"nfa\",\"nfa-backtrack\",\"nfa-pikevm\",\"nfa-thompson\",\"perf\",\"perf-inline\",\"perf-literal\",\"perf-literal-multisubstring\",\"perf-literal-substring\",\"std\",\"syntax\",\"unicode\",\"unicode-age\",\"unicode-bool\",\"unicode-case\",\"unicode-gencat\",\"unicode-perl\",\"unicode-script\",\"unicode-segment\",\"unicode-word-boundary\"],\"deps\":[{\"id\":\"aho-corasick 1.1.2\",\"target\":\"aho_corasick\"},{\"id\":\"memchr 2.7.1\",\"target\":\"memchr\"},{\"id\":\"regex-syntax 0.8.2\",\"target\":\"regex_syntax\"}],\"edition\":\"2021\"},\"library_target_name\":\"regex_automata\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"regex-automata\",\"package_url\":\"https://github.com/rust-lang/regex/tree/master/regex-automata\",\"repository\":{\"Http\":{\"sha256\":\"5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f\",\"url\":\"https://static.crates.io/crates/regex-automata/0.4.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"regex_automata\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.3\"},\"regex-syntax 0.6.29\":{\"common_attrs\":{\"crate_features\":[\"default\",\"unicode\",\"unicode-age\",\"unicode-bool\",\"unicode-case\",\"unicode-gencat\",\"unicode-perl\",\"unicode-script\",\"unicode-segment\"],\"edition\":\"2018\"},\"library_target_name\":\"regex_syntax\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"regex-syntax\",\"package_url\":\"https://github.com/rust-lang/regex\",\"repository\":{\"Http\":{\"sha256\":\"f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1\",\"url\":\"https://static.crates.io/crates/regex-syntax/0.6.29/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"regex_syntax\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.29\"},\"regex-syntax 0.8.2\":{\"common_attrs\":{\"crate_features\":{\"common\":[\"std\",\"unicode\",\"unicode-age\",\"unicode-bool\",\"unicode-case\",\"unicode-gencat\",\"unicode-perl\",\"unicode-script\",\"unicode-segment\"],\"selects\":{\"x86_64-unknown-linux-gnu\":[\"default\"]}},\"edition\":\"2021\"},\"library_target_name\":\"regex_syntax\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"regex-syntax\",\"package_url\":\"https://github.com/rust-lang/regex/tree/master/regex-syntax\",\"repository\":{\"Http\":{\"sha256\":\"c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f\",\"url\":\"https://static.crates.io/crates/regex-syntax/0.8.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"regex_syntax\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.2\"},\"region 3.0.2\":{\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"bitflags 1.3.2\",\"target\":\"bitflags\"},{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"selects\":{\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"ios\\\"))\":[{\"id\":\"mach2 0.4.2\",\"target\":\"mach2\"}],\"cfg(windows)\":[{\"id\":\"windows-sys 0.52.0\",\"target\":\"windows_sys\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"region\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"region\",\"package_url\":\"https://github.com/darfink/region-rs\",\"repository\":{\"Http\":{\"sha256\":\"e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7\",\"url\":\"https://static.crates.io/crates/region/3.0.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"region\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"3.0.2\"},\"rend 0.5.2\":{\"common_attrs\":{\"crate_features\":[\"bytecheck\"],\"deps\":[{\"id\":\"bytecheck 0.8.1\",\"target\":\"bytecheck\"}],\"edition\":\"2021\"},\"library_target_name\":\"rend\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"rend\",\"package_url\":\"https://github.com/djkoloski/rend\",\"repository\":{\"Http\":{\"sha256\":\"a35e8a6bf28cd121053a66aa2e6a2e3eaffad4a60012179f0e864aa5ffeff215\",\"url\":\"https://static.crates.io/crates/rend/0.5.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rend\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.2\"},\"replace_with 0.1.7\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"replace_with\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE.txt\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"replace_with\",\"package_url\":\"https://github.com/alecmocatta/replace_with\",\"repository\":{\"Http\":{\"sha256\":\"e3a8614ee435691de62bcffcf4a66d91b3594bf1428a5722e79103249a095690\",\"url\":\"https://static.crates.io/crates/replace_with/0.1.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"replace_with\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.7\"},\"reqwest 0.12.7\":{\"common_attrs\":{\"crate_features\":[\"__tls\",\"charset\",\"default\",\"default-tls\",\"h2\",\"http2\",\"json\",\"macos-system-configuration\",\"stream\"],\"deps\":{\"common\":[{\"id\":\"base64 0.22.1\",\"target\":\"base64\"},{\"id\":\"bytes 1.10.1\",\"target\":\"bytes\"},{\"id\":\"futures-core 0.3.31\",\"target\":\"futures_core\"},{\"id\":\"futures-util 0.3.31\",\"target\":\"futures_util\"},{\"id\":\"http 1.3.1\",\"target\":\"http\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.140\",\"target\":\"serde_json\"},{\"id\":\"serde_urlencoded 0.7.1\",\"target\":\"serde_urlencoded\"},{\"id\":\"sync_wrapper 1.0.1\",\"target\":\"sync_wrapper\"},{\"id\":\"tower-service 0.3.2\",\"target\":\"tower_service\"},{\"id\":\"url 2.5.4\",\"target\":\"url\"}],\"selects\":{\"cfg(not(target_arch = \\\"wasm32\\\"))\":[{\"id\":\"http-body 1.0.0\",\"target\":\"http_body\"},{\"id\":\"http-body-util 0.1.2\",\"target\":\"http_body_util\"},{\"id\":\"hyper 1.4.0\",\"target\":\"hyper\"},{\"id\":\"hyper-util 0.1.6\",\"target\":\"hyper_util\"},{\"id\":\"ipnet 2.11.0\",\"target\":\"ipnet\"},{\"id\":\"log 0.4.20\",\"target\":\"log\"},{\"id\":\"mime 0.3.17\",\"target\":\"mime\"},{\"id\":\"once_cell 1.19.0\",\"target\":\"once_cell\"},{\"id\":\"percent-encoding 2.3.1\",\"target\":\"percent_encoding\"},{\"id\":\"pin-project-lite 0.2.13\",\"target\":\"pin_project_lite\"},{\"id\":\"tokio 1.44.2\",\"target\":\"tokio\"}],\"cfg(target_arch = \\\"wasm32\\\")\":[{\"id\":\"js-sys 0.3.78\",\"target\":\"js_sys\"},{\"id\":\"wasm-bindgen 0.2.101\",\"target\":\"wasm_bindgen\"},{\"id\":\"wasm-bindgen-futures 0.4.51\",\"target\":\"wasm_bindgen_futures\"},{\"id\":\"web-sys 0.3.78\",\"target\":\"web_sys\"}],\"cfg(windows)\":[{\"id\":\"windows-registry 0.2.0\",\"target\":\"windows_registry\"}],\"wasm32-unknown-unknown\":[{\"id\":\"wasm-streams 0.4.0\",\"target\":\"wasm_streams\"}],\"x86_64-unknown-linux-gnu\":[{\"id\":\"encoding_rs 0.8.34\",\"target\":\"encoding_rs\"},{\"id\":\"h2 0.4.5\",\"target\":\"h2\"},{\"id\":\"hyper-tls 0.6.0\",\"target\":\"hyper_tls\"},{\"alias\":\"native_tls_crate\",\"id\":\"native-tls 0.2.12\",\"target\":\"native_tls\"},{\"id\":\"rustls-pemfile 2.1.2\",\"target\":\"rustls_pemfile\"},{\"id\":\"tokio-native-tls 0.3.1\",\"target\":\"tokio_native_tls\"},{\"id\":\"tokio-util 0.7.11\",\"target\":\"tokio_util\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"reqwest\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"reqwest\",\"package_url\":\"https://github.com/seanmonstar/reqwest\",\"repository\":{\"Http\":{\"sha256\":\"f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63\",\"url\":\"https://static.crates.io/crates/reqwest/0.12.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"reqwest\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.12.7\"},\"ring 0.17.8\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"cc 1.2.18\",\"target\":\"cc\"}],\"links\":\"ring_core_0_17_8\"},\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"},{\"id\":\"getrandom 0.2.15\",\"target\":\"getrandom\"},{\"id\":\"untrusted 0.9.0\",\"target\":\"untrusted\"}],\"selects\":{\"cfg(all(any(target_os = \\\"android\\\", target_os = \\\"linux\\\"), any(target_arch = \\\"aarch64\\\", target_arch = \\\"arm\\\")))\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"windows\\\"))\":[{\"id\":\"windows-sys 0.52.0\",\"target\":\"windows_sys\"}],\"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"arm\\\", target_arch = \\\"x86\\\", target_arch = \\\"x86_64\\\"))\":[{\"id\":\"spin 0.9.8\",\"target\":\"spin\"}]}},\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"ring\",\"license_file\":\"LICENSE\",\"name\":\"ring\",\"package_url\":\"https://github.com/briansmith/ring\",\"repository\":{\"Http\":{\"sha256\":\"c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d\",\"url\":\"https://static.crates.io/crates/ring/0.17.8/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ring\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.17.8\"},\"rkyv 0.8.10\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"bytecheck\",\"bytes-1\",\"default\",\"indexmap-2\",\"std\"],\"deps\":[{\"id\":\"bytecheck 0.8.1\",\"target\":\"bytecheck\"},{\"alias\":\"bytes_1\",\"id\":\"bytes 1.10.1\",\"target\":\"bytes\"},{\"id\":\"hashbrown 0.15.2\",\"target\":\"hashbrown\"},{\"alias\":\"indexmap_2\",\"id\":\"indexmap 2.9.0\",\"target\":\"indexmap\"},{\"id\":\"munge 0.4.3\",\"target\":\"munge\"},{\"id\":\"ptr_meta 0.3.0\",\"target\":\"ptr_meta\"},{\"id\":\"rancor 0.1.0\",\"target\":\"rancor\"},{\"id\":\"rend 0.5.2\",\"target\":\"rend\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"rkyv_derive 0.8.10\",\"target\":\"rkyv_derive\"}]},\"library_target_name\":\"rkyv\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"rkyv\",\"package_url\":\"https://github.com/rkyv/rkyv\",\"repository\":{\"Http\":{\"sha256\":\"1e147371c75553e1e2fcdb483944a8540b8438c31426279553b9a8182a9b7b65\",\"url\":\"https://static.crates.io/crates/rkyv/0.8.10/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rkyv\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.10\"},\"rkyv_derive 0.8.10\":{\"common_attrs\":{\"crate_features\":[\"bytecheck\"],\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"rkyv_derive\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"rkyv_derive\",\"package_url\":\"https://github.com/rkyv/rkyv\",\"repository\":{\"Http\":{\"sha256\":\"246b40ac189af6c675d124b802e8ef6d5246c53e17367ce9501f8f66a81abb7a\",\"url\":\"https://static.crates.io/crates/rkyv_derive/0.8.10/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"rkyv_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.10\"},\"rustc-demangle 0.1.23\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"rustc_demangle\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rustc-demangle\",\"package_url\":\"https://github.com/alexcrichton/rustc-demangle\",\"repository\":{\"Http\":{\"sha256\":\"d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76\",\"url\":\"https://static.crates.io/crates/rustc-demangle/0.1.23/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rustc_demangle\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.23\"},\"rustc-hash 1.1.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2015\"},\"library_target_name\":\"rustc_hash\",\"license\":\"Apache-2.0/MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rustc-hash\",\"package_url\":\"https://github.com/rust-lang-nursery/rustc-hash\",\"repository\":{\"Http\":{\"sha256\":\"08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2\",\"url\":\"https://static.crates.io/crates/rustc-hash/1.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rustc_hash\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.0\"},\"rustix 0.38.34\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"fs\",\"libc-extra-traits\",\"std\",\"termios\",\"use-libc-auxv\"],\"deps\":{\"common\":[{\"id\":\"bitflags 2.9.0\",\"target\":\"bitflags\"}],\"selects\":{\"cfg(all(any(target_os = \\\"android\\\", target_os = \\\"linux\\\"), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", target_endian = \\\"little\\\", any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\":[{\"id\":\"linux-raw-sys 0.4.12\",\"target\":\"linux_raw_sys\"}],\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", target_endian = \\\"little\\\", any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\":[{\"id\":\"linux-raw-sys 0.4.12\",\"target\":\"linux_raw_sys\"}],\"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", target_endian = \\\"little\\\", any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\":[{\"alias\":\"libc_errno\",\"id\":\"errno 0.3.8\",\"target\":\"errno\"},{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"cfg(windows)\":[{\"alias\":\"libc_errno\",\"id\":\"errno 0.3.8\",\"target\":\"errno\"},{\"id\":\"windows-sys 0.52.0\",\"target\":\"windows_sys\"}]}},\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"rustix\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rustix\",\"package_url\":\"https://github.com/bytecodealliance/rustix\",\"repository\":{\"Http\":{\"sha256\":\"70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f\",\"url\":\"https://static.crates.io/crates/rustix/0.38.34/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rustix\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.38.34\"},\"rustls 0.23.25\":{\"build_script_attrs\":{},\"common_attrs\":{\"deps\":[{\"id\":\"once_cell 1.19.0\",\"target\":\"once_cell\"},{\"alias\":\"pki_types\",\"id\":\"rustls-pki-types 1.11.0\",\"target\":\"rustls_pki_types\"},{\"id\":\"rustls-webpki 0.103.1\",\"target\":\"webpki\"},{\"id\":\"subtle 2.6.1\",\"target\":\"subtle\"},{\"id\":\"zeroize 1.8.1\",\"target\":\"zeroize\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"rustls\",\"license\":\"Apache-2.0 OR ISC OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"ISC\",\"MIT\"],\"name\":\"rustls\",\"package_url\":\"https://github.com/rustls/rustls\",\"repository\":{\"Http\":{\"sha256\":\"822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c\",\"url\":\"https://static.crates.io/crates/rustls/0.23.25/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rustls\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.23.25\"},\"rustls-pemfile 2.1.2\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"base64 0.22.1\",\"target\":\"base64\"},{\"alias\":\"pki_types\",\"id\":\"rustls-pki-types 1.11.0\",\"target\":\"rustls_pki_types\"}],\"edition\":\"2018\"},\"library_target_name\":\"rustls_pemfile\",\"license\":\"Apache-2.0 OR ISC OR MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\",\"ISC\",\"MIT\"],\"name\":\"rustls-pemfile\",\"package_url\":\"https://github.com/rustls/pemfile\",\"repository\":{\"Http\":{\"sha256\":\"29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d\",\"url\":\"https://static.crates.io/crates/rustls-pemfile/2.1.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rustls_pemfile\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.1.2\"},\"rustls-pki-types 1.11.0\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\"],\"edition\":\"2021\"},\"library_target_name\":\"rustls_pki_types\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rustls-pki-types\",\"package_url\":\"https://github.com/rustls/pki-types\",\"repository\":{\"Http\":{\"sha256\":\"917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c\",\"url\":\"https://static.crates.io/crates/rustls-pki-types/1.11.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rustls_pki_types\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.11.0\"},\"rustls-webpki 0.103.1\":{\"common_attrs\":{\"deps\":[{\"alias\":\"pki_types\",\"id\":\"rustls-pki-types 1.11.0\",\"target\":\"rustls_pki_types\"},{\"id\":\"untrusted 0.9.0\",\"target\":\"untrusted\"}],\"edition\":\"2021\"},\"library_target_name\":\"webpki\",\"license\":\"ISC\",\"license_file\":\"LICENSE\",\"license_ids\":[\"ISC\"],\"name\":\"rustls-webpki\",\"package_url\":\"https://github.com/rustls/webpki\",\"repository\":{\"Http\":{\"sha256\":\"fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03\",\"url\":\"https://static.crates.io/crates/rustls-webpki/0.103.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"webpki\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.103.1\"},\"rustversion 1.0.20\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"rustversion\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rustversion\",\"package_url\":\"https://github.com/dtolnay/rustversion\",\"repository\":{\"Http\":{\"sha256\":\"eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2\",\"url\":\"https://static.crates.io/crates/rustversion/1.0.20/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"rustversion\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build/build.rs\"}}],\"version\":\"1.0.20\"},\"ruzstd 0.5.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"byteorder 1.5.0\",\"target\":\"byteorder\"},{\"id\":\"twox-hash 1.6.3\",\"target\":\"twox_hash\"}],\"edition\":\"2018\",\"proc_macro_deps\":[{\"id\":\"derive_more 0.99.19\",\"target\":\"derive_more\"}]},\"library_target_name\":\"ruzstd\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"ruzstd\",\"package_url\":\"https://github.com/KillingSpark/zstd-rs\",\"repository\":{\"Http\":{\"sha256\":\"58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d\",\"url\":\"https://static.crates.io/crates/ruzstd/0.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ruzstd\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.0\"},\"ryu 1.0.16\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"ryu\",\"license\":\"Apache-2.0 OR BSL-1.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"BSL-1.0\"],\"name\":\"ryu\",\"package_url\":\"https://github.com/dtolnay/ryu\",\"repository\":{\"Http\":{\"sha256\":\"f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c\",\"url\":\"https://static.crates.io/crates/ryu/1.0.16/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ryu\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.16\"},\"saffron 0.1.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"chrono 0.4.40\",\"target\":\"chrono\"},{\"id\":\"nom 5.1.3\",\"target\":\"nom\"}],\"edition\":\"2018\"},\"library_target_name\":\"saffron\",\"license_file\":\"LICENSE\",\"name\":\"saffron\",\"package_url\":\"https://github.com/cloudflare/saffron\",\"repository\":{\"Http\":{\"sha256\":\"03fb9a628596fc7590eb7edbf7b0613287be78df107f5f97b118aad59fb2eea9\",\"url\":\"https://static.crates.io/crates/saffron/0.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"saffron\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.0\"},\"same-file 1.0.6\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(windows)\":[{\"id\":\"winapi-util 0.1.6\",\"target\":\"winapi_util\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"same_file\",\"license\":\"Unlicense/MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"same-file\",\"package_url\":\"https://github.com/BurntSushi/same-file\",\"repository\":{\"Http\":{\"sha256\":\"93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502\",\"url\":\"https://static.crates.io/crates/same-file/1.0.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"same_file\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.6\"},\"schannel 0.1.23\":{\"common_attrs\":{\"deps\":[{\"id\":\"windows-sys 0.52.0\",\"target\":\"windows_sys\"}],\"edition\":\"2018\"},\"library_target_name\":\"schannel\",\"license\":\"MIT\",\"license_file\":\"LICENSE.md\",\"license_ids\":[\"MIT\"],\"name\":\"schannel\",\"package_url\":\"https://github.com/steffengy/schannel-rs\",\"repository\":{\"Http\":{\"sha256\":\"fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534\",\"url\":\"https://static.crates.io/crates/schannel/0.1.23/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"schannel\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.23\"},\"schemars 0.8.21\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"derive\",\"indexmap2\",\"schemars_derive\",\"url\"],\"deps\":[{\"id\":\"dyn-clone 1.0.17\",\"target\":\"dyn_clone\"},{\"alias\":\"indexmap2\",\"id\":\"indexmap 2.9.0\",\"target\":\"indexmap\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.140\",\"target\":\"serde_json\"},{\"id\":\"url 2.5.4\",\"target\":\"url\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":[{\"id\":\"schemars_derive 0.8.21\",\"target\":\"schemars_derive\"}]},\"library_target_name\":\"schemars\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"schemars\",\"package_url\":\"https://github.com/GREsau/schemars\",\"repository\":{\"Http\":{\"sha256\":\"09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92\",\"url\":\"https://static.crates.io/crates/schemars/0.8.21/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"schemars\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.8.21\"},\"schemars_derive 0.8.21\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"serde_derive_internals 0.29.1\",\"target\":\"serde_derive_internals\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"schemars_derive\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"schemars_derive\",\"package_url\":\"https://github.com/GREsau/schemars\",\"repository\":{\"Http\":{\"sha256\":\"b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e\",\"url\":\"https://static.crates.io/crates/schemars_derive/0.8.21/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"schemars_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.21\"},\"scopeguard 1.2.0\":{\"common_attrs\":{\"crate_features\":{\"common\":[],\"selects\":{\"x86_64-unknown-linux-gnu\":[\"default\",\"use_std\"]}},\"edition\":\"2015\"},\"library_target_name\":\"scopeguard\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"scopeguard\",\"package_url\":\"https://github.com/bluss/scopeguard\",\"repository\":{\"Http\":{\"sha256\":\"94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49\",\"url\":\"https://static.crates.io/crates/scopeguard/1.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"scopeguard\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.0\"},\"security-framework 2.10.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"bitflags 1.3.2\",\"target\":\"bitflags\"},{\"id\":\"core-foundation 0.9.4\",\"target\":\"core_foundation\"},{\"id\":\"core-foundation-sys 0.8.7\",\"target\":\"core_foundation_sys\"},{\"id\":\"libc 0.2.171\",\"target\":\"libc\"},{\"id\":\"security-framework-sys 2.14.0\",\"target\":\"security_framework_sys\"}],\"edition\":\"2021\"},\"library_target_name\":\"security_framework\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"security-framework\",\"package_url\":\"https://github.com/kornelski/rust-security-framework\",\"repository\":{\"Http\":{\"sha256\":\"770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6\",\"url\":\"https://static.crates.io/crates/security-framework/2.10.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"security_framework\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.10.0\"},\"security-framework-sys 2.14.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"core-foundation-sys 0.8.7\",\"target\":\"core_foundation_sys\"},{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"edition\":\"2021\"},\"library_target_name\":\"security_framework_sys\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"security-framework-sys\",\"package_url\":\"https://github.com/kornelski/rust-security-framework\",\"repository\":{\"Http\":{\"sha256\":\"49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32\",\"url\":\"https://static.crates.io/crates/security-framework-sys/2.14.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"security_framework_sys\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.14.0\"},\"self_cell 1.0.3\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"self_cell\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"self_cell\",\"package_url\":\"https://github.com/Voultapher/self_cell\",\"repository\":{\"Http\":{\"sha256\":\"58bf37232d3bb9a2c4e641ca2a11d83b5062066f88df7fed36c28772046d65ba\",\"url\":\"https://static.crates.io/crates/self_cell/1.0.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"self_cell\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.3\"},\"semver 1.0.26\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"serde\",\"std\"],\"deps\":[{\"id\":\"serde 1.0.219\",\"target\":\"serde\"}],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"semver\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"semver\",\"package_url\":\"https://github.com/dtolnay/semver\",\"repository\":{\"Http\":{\"sha256\":\"56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0\",\"url\":\"https://static.crates.io/crates/semver/1.0.26/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"semver\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.26\"},\"serde 1.0.219\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"derive\",\"rc\",\"serde_derive\",\"std\"],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":[{\"id\":\"serde_derive 1.0.219\",\"target\":\"serde_derive\"}]},\"library_target_name\":\"serde\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"serde\",\"package_url\":\"https://github.com/serde-rs/serde\",\"repository\":{\"Http\":{\"sha256\":\"5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6\",\"url\":\"https://static.crates.io/crates/serde/1.0.219/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"serde\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.219\"},\"serde-wasm-bindgen 0.6.5\":{\"common_attrs\":{\"deps\":[{\"id\":\"js-sys 0.3.78\",\"target\":\"js_sys\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"},{\"id\":\"wasm-bindgen 0.2.101\",\"target\":\"wasm_bindgen\"}],\"edition\":\"2018\"},\"library_target_name\":\"serde_wasm_bindgen\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"serde-wasm-bindgen\",\"package_url\":\"https://github.com/RReverser/serde-wasm-bindgen\",\"repository\":{\"Http\":{\"sha256\":\"8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b\",\"url\":\"https://static.crates.io/crates/serde-wasm-bindgen/0.6.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"serde_wasm_bindgen\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.5\"},\"serde_bytes 0.11.14\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"serde 1.0.219\",\"target\":\"serde\"}],\"edition\":\"2018\"},\"library_target_name\":\"serde_bytes\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"serde_bytes\",\"package_url\":\"https://github.com/serde-rs/bytes\",\"repository\":{\"Http\":{\"sha256\":\"8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734\",\"url\":\"https://static.crates.io/crates/serde_bytes/0.11.14/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"serde_bytes\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.11.14\"},\"serde_derive 1.0.219\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2015\"},\"library_target_name\":\"serde_derive\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"serde_derive\",\"package_url\":\"https://github.com/serde-rs/serde\",\"repository\":{\"Http\":{\"sha256\":\"5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00\",\"url\":\"https://static.crates.io/crates/serde_derive/1.0.219/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"serde_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.219\"},\"serde_derive_internals 0.29.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2015\"},\"library_target_name\":\"serde_derive_internals\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"serde_derive_internals\",\"package_url\":\"https://github.com/serde-rs/serde\",\"repository\":{\"Http\":{\"sha256\":\"18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711\",\"url\":\"https://static.crates.io/crates/serde_derive_internals/0.29.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"serde_derive_internals\",\"crate_root\":\"lib.rs\"}}],\"version\":\"0.29.1\"},\"serde_json 1.0.140\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"itoa 1.0.10\",\"target\":\"itoa\"},{\"id\":\"memchr 2.7.1\",\"target\":\"memchr\"},{\"id\":\"ryu 1.0.16\",\"target\":\"ryu\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"serde_json\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"serde_json\",\"package_url\":\"https://github.com/serde-rs/json\",\"repository\":{\"Http\":{\"sha256\":\"20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373\",\"url\":\"https://static.crates.io/crates/serde_json/1.0.140/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"serde_json\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.140\"},\"serde_path_to_error 0.1.17\":{\"common_attrs\":{\"deps\":[{\"id\":\"itoa 1.0.10\",\"target\":\"itoa\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"}],\"edition\":\"2021\"},\"library_target_name\":\"serde_path_to_error\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"serde_path_to_error\",\"package_url\":\"https://github.com/dtolnay/path-to-error\",\"repository\":{\"Http\":{\"sha256\":\"59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a\",\"url\":\"https://static.crates.io/crates/serde_path_to_error/0.1.17/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"serde_path_to_error\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.17\"},\"serde_spanned 0.6.6\":{\"common_attrs\":{\"crate_features\":[\"serde\"],\"deps\":[{\"id\":\"serde 1.0.219\",\"target\":\"serde\"}],\"edition\":\"2021\"},\"library_target_name\":\"serde_spanned\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"serde_spanned\",\"package_url\":\"https://github.com/toml-rs/toml\",\"repository\":{\"Http\":{\"sha256\":\"79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0\",\"url\":\"https://static.crates.io/crates/serde_spanned/0.6.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"serde_spanned\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.6\"},\"serde_urlencoded 0.7.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"form_urlencoded 1.2.1\",\"target\":\"form_urlencoded\"},{\"id\":\"itoa 1.0.10\",\"target\":\"itoa\"},{\"id\":\"ryu 1.0.16\",\"target\":\"ryu\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"}],\"edition\":\"2018\"},\"library_target_name\":\"serde_urlencoded\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"serde_urlencoded\",\"package_url\":\"https://github.com/nox/serde_urlencoded\",\"repository\":{\"Http\":{\"sha256\":\"d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd\",\"url\":\"https://static.crates.io/crates/serde_urlencoded/0.7.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"serde_urlencoded\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.1\"},\"serde_yaml 0.9.34+deprecated\":{\"common_attrs\":{\"deps\":[{\"id\":\"indexmap 2.9.0\",\"target\":\"indexmap\"},{\"id\":\"itoa 1.0.10\",\"target\":\"itoa\"},{\"id\":\"ryu 1.0.16\",\"target\":\"ryu\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"},{\"id\":\"unsafe-libyaml 0.2.11\",\"target\":\"unsafe_libyaml\"}],\"edition\":\"2021\"},\"library_target_name\":\"serde_yaml\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"serde_yaml\",\"package_url\":\"https://github.com/dtolnay/serde-yaml\",\"repository\":{\"Http\":{\"sha256\":\"6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47\",\"url\":\"https://static.crates.io/crates/serde_yaml/0.9.34+deprecated/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"serde_yaml\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.9.34+deprecated\"},\"sha2 0.10.8\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"},{\"id\":\"digest 0.10.7\",\"target\":\"digest\"}],\"selects\":{\"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\":[{\"id\":\"cpufeatures 0.2.12\",\"target\":\"cpufeatures\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"sha2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"sha2\",\"package_url\":\"https://github.com/RustCrypto/hashes\",\"repository\":{\"Http\":{\"sha256\":\"793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8\",\"url\":\"https://static.crates.io/crates/sha2/0.10.8/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"sha2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.10.8\"},\"sharded-slab 0.1.7\":{\"common_attrs\":{\"deps\":[{\"id\":\"lazy_static 1.5.0\",\"target\":\"lazy_static\"}],\"edition\":\"2018\"},\"library_target_name\":\"sharded_slab\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"sharded-slab\",\"package_url\":\"https://github.com/hawkw/sharded-slab\",\"repository\":{\"Http\":{\"sha256\":\"f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6\",\"url\":\"https://static.crates.io/crates/sharded-slab/0.1.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"sharded_slab\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.7\"},\"shared-buffer 0.1.4\":{\"common_attrs\":{\"deps\":[{\"id\":\"bytes 1.10.1\",\"target\":\"bytes\"},{\"id\":\"memmap2 0.6.2\",\"target\":\"memmap2\"}],\"edition\":\"2021\"},\"library_target_name\":\"shared_buffer\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE_APACHE.md\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"shared-buffer\",\"package_url\":\"https://github.com/wasmerio/shared-buffer.git\",\"repository\":{\"Http\":{\"sha256\":\"f6c99835bad52957e7aa241d3975ed17c1e5f8c92026377d117a606f36b84b16\",\"url\":\"https://static.crates.io/crates/shared-buffer/0.1.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"shared_buffer\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.4\"},\"shlex 1.3.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2015\"},\"library_target_name\":\"shlex\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"shlex\",\"package_url\":\"https://github.com/comex/rust-shlex\",\"repository\":{\"Http\":{\"sha256\":\"0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64\",\"url\":\"https://static.crates.io/crates/shlex/1.3.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"shlex\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.3.0\"},\"simdutf8 0.1.4\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"simdutf8\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-Apache\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"simdutf8\",\"package_url\":\"https://github.com/rusticstuff/simdutf8\",\"repository\":{\"Http\":{\"sha256\":\"f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a\",\"url\":\"https://static.crates.io/crates/simdutf8/0.1.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"simdutf8\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.4\"},\"similar 2.7.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"inline\",\"text\"],\"edition\":\"2018\"},\"library_target_name\":\"similar\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"similar\",\"package_url\":\"https://github.com/mitsuhiko/similar\",\"repository\":{\"Http\":{\"sha256\":\"bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa\",\"url\":\"https://static.crates.io/crates/similar/2.7.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"similar\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.7.0\"},\"slab 0.4.9\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"autocfg 1.1.0\",\"target\":\"autocfg\"}]},\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"slab\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"slab\",\"package_url\":\"https://github.com/tokio-rs/slab\",\"repository\":{\"Http\":{\"sha256\":\"8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67\",\"url\":\"https://static.crates.io/crates/slab/0.4.9/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"slab\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.4.9\"},\"smallvec 1.13.2\":{\"common_attrs\":{\"crate_features\":{\"common\":[\"const_generics\"],\"selects\":{\"x86_64-unknown-linux-gnu\":[\"const_new\"]}},\"edition\":\"2018\"},\"library_target_name\":\"smallvec\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"smallvec\",\"package_url\":\"https://github.com/servo/rust-smallvec\",\"repository\":{\"Http\":{\"sha256\":\"3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67\",\"url\":\"https://static.crates.io/crates/smallvec/1.13.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"smallvec\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.13.2\"},\"smoltcp 0.8.2\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"proto-ipv4\",\"std\"],\"deps\":[{\"id\":\"bitflags 1.3.2\",\"target\":\"bitflags\"},{\"id\":\"byteorder 1.5.0\",\"target\":\"byteorder\"},{\"id\":\"managed 0.8.0\",\"target\":\"managed\"}],\"edition\":\"2018\"},\"library_target_name\":\"smoltcp\",\"license\":\"0BSD\",\"license_file\":\"LICENSE-0BSD.txt\",\"license_ids\":[\"0BSD\"],\"name\":\"smoltcp\",\"package_url\":\"https://github.com/smoltcp-rs/smoltcp.git\",\"repository\":{\"Http\":{\"sha256\":\"ee34c1e1bfc7e9206cc0fb8030a90129b4e319ab53856249bb27642cab914fb3\",\"url\":\"https://static.crates.io/crates/smoltcp/0.8.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"smoltcp\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.2\"},\"socket2 0.5.7\":{\"common_attrs\":{\"crate_features\":[\"all\"],\"deps\":{\"common\":[],\"selects\":{\"cfg(unix)\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"cfg(windows)\":[{\"id\":\"windows-sys 0.52.0\",\"target\":\"windows_sys\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"socket2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"socket2\",\"package_url\":\"https://github.com/rust-lang/socket2\",\"repository\":{\"Http\":{\"sha256\":\"ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c\",\"url\":\"https://static.crates.io/crates/socket2/0.5.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"socket2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.7\"},\"spin 0.9.8\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"spin\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"spin\",\"package_url\":\"https://github.com/mvdnes/spin-rs.git\",\"repository\":{\"Http\":{\"sha256\":\"6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67\",\"url\":\"https://static.crates.io/crates/spin/0.9.8/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"spin\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.9.8\"},\"stable_deref_trait 1.2.0\":{\"common_attrs\":{\"crate_features\":[\"alloc\"],\"edition\":\"2015\"},\"library_target_name\":\"stable_deref_trait\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"stable_deref_trait\",\"package_url\":\"https://github.com/storyyeller/stable_deref_trait\",\"repository\":{\"Http\":{\"sha256\":\"a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3\",\"url\":\"https://static.crates.io/crates/stable_deref_trait/1.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"stable_deref_trait\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.0\"},\"static_assertions 1.1.0\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"static_assertions\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"static_assertions\",\"package_url\":\"https://github.com/nvzqz/static-assertions-rs\",\"repository\":{\"Http\":{\"sha256\":\"a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f\",\"url\":\"https://static.crates.io/crates/static_assertions/1.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"static_assertions\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.0\"},\"strsim 0.10.0\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"strsim\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"strsim\",\"package_url\":\"https://github.com/dguo/strsim-rs\",\"repository\":{\"Http\":{\"sha256\":\"73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623\",\"url\":\"https://static.crates.io/crates/strsim/0.10.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"strsim\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.10.0\"},\"subtle 2.6.1\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"subtle\",\"license\":\"BSD-3-Clause\",\"license_file\":\"LICENSE\",\"license_ids\":[\"BSD-3-Clause\"],\"name\":\"subtle\",\"package_url\":\"https://github.com/dalek-cryptography/subtle\",\"repository\":{\"Http\":{\"sha256\":\"13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292\",\"url\":\"https://static.crates.io/crates/subtle/2.6.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"subtle\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.6.1\"},\"syn 1.0.109\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"clone-impls\",\"default\",\"derive\",\"extra-traits\",\"full\",\"parsing\",\"printing\",\"proc-macro\",\"quote\",\"visit\"],\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"unicode-ident 1.0.12\",\"target\":\"unicode_ident\"}],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"syn\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"syn\",\"package_url\":\"https://github.com/dtolnay/syn\",\"repository\":{\"Http\":{\"sha256\":\"72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237\",\"url\":\"https://static.crates.io/crates/syn/1.0.109/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"syn\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.109\"},\"syn 2.0.100\":{\"common_attrs\":{\"crate_features\":[\"clone-impls\",\"default\",\"derive\",\"extra-traits\",\"fold\",\"full\",\"parsing\",\"printing\",\"proc-macro\",\"visit\",\"visit-mut\"],\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"unicode-ident 1.0.12\",\"target\":\"unicode_ident\"}],\"edition\":\"2021\"},\"library_target_name\":\"syn\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"syn\",\"package_url\":\"https://github.com/dtolnay/syn\",\"repository\":{\"Http\":{\"sha256\":\"b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0\",\"url\":\"https://static.crates.io/crates/syn/2.0.100/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"syn\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.0.100\"},\"sync_wrapper 1.0.1\":{\"common_attrs\":{\"crate_features\":[\"futures\",\"futures-core\"],\"deps\":[{\"id\":\"futures-core 0.3.31\",\"target\":\"futures_core\"}],\"edition\":\"2018\"},\"library_target_name\":\"sync_wrapper\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"sync_wrapper\",\"package_url\":\"https://github.com/Actyx/sync_wrapper\",\"repository\":{\"Http\":{\"sha256\":\"a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394\",\"url\":\"https://static.crates.io/crates/sync_wrapper/1.0.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"sync_wrapper\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.1\"},\"synstructure 0.13.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"proc-macro\"],\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2018\"},\"library_target_name\":\"synstructure\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"synstructure\",\"package_url\":\"https://github.com/mystor/synstructure\",\"repository\":{\"Http\":{\"sha256\":\"c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971\",\"url\":\"https://static.crates.io/crates/synstructure/0.13.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"synstructure\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.13.1\"},\"system-configuration 0.6.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"bitflags 2.9.0\",\"target\":\"bitflags\"},{\"id\":\"core-foundation 0.9.4\",\"target\":\"core_foundation\"},{\"id\":\"system-configuration-sys 0.6.0\",\"target\":\"system_configuration_sys\"}],\"edition\":\"2021\"},\"library_target_name\":\"system_configuration\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"system-configuration\",\"package_url\":\"https://github.com/mullvad/system-configuration-rs\",\"repository\":{\"Http\":{\"sha256\":\"3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b\",\"url\":\"https://static.crates.io/crates/system-configuration/0.6.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"system_configuration\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.1\"},\"system-configuration-sys 0.6.0\":{\"build_script_attrs\":{},\"common_attrs\":{\"deps\":[{\"id\":\"core-foundation-sys 0.8.7\",\"target\":\"core_foundation_sys\"},{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"system_configuration_sys\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"system-configuration-sys\",\"package_url\":\"https://github.com/mullvad/system-configuration-rs\",\"repository\":{\"Http\":{\"sha256\":\"8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4\",\"url\":\"https://static.crates.io/crates/system-configuration-sys/0.6.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"system_configuration_sys\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.6.0\"},\"tar 0.4.44\":{\"common_attrs\":{\"crate_features\":[\"default\",\"xattr\"],\"deps\":{\"common\":[{\"id\":\"filetime 0.2.23\",\"target\":\"filetime\"}],\"selects\":{\"cfg(unix)\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"x86_64-unknown-linux-gnu\":[{\"id\":\"xattr 1.2.0\",\"target\":\"xattr\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"tar\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"tar\",\"package_url\":\"https://github.com/alexcrichton/tar-rs\",\"repository\":{\"Http\":{\"sha256\":\"1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a\",\"url\":\"https://static.crates.io/crates/tar/0.4.44/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tar\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.44\"},\"target-lexicon 0.12.16\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"target_lexicon\",\"license\":\"Apache-2.0 WITH LLVM-exception\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"target-lexicon\",\"package_url\":\"https://github.com/bytecodealliance/target-lexicon\",\"repository\":{\"Http\":{\"sha256\":\"61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1\",\"url\":\"https://static.crates.io/crates/target-lexicon/0.12.16/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"target_lexicon\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.12.16\"},\"tempfile 3.12.0\":{\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"},{\"id\":\"fastrand 2.0.1\",\"target\":\"fastrand\"},{\"id\":\"once_cell 1.19.0\",\"target\":\"once_cell\"}],\"selects\":{\"cfg(any(unix, target_os = \\\"wasi\\\"))\":[{\"id\":\"rustix 0.38.34\",\"target\":\"rustix\"}],\"cfg(windows)\":[{\"id\":\"windows-sys 0.59.0\",\"target\":\"windows_sys\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"tempfile\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"tempfile\",\"package_url\":\"https://github.com/Stebalien/tempfile\",\"repository\":{\"Http\":{\"sha256\":\"04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64\",\"url\":\"https://static.crates.io/crates/tempfile/3.12.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tempfile\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"3.12.0\"},\"terminal_size 0.3.0\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(not(windows))\":[{\"id\":\"rustix 0.38.34\",\"target\":\"rustix\"}],\"cfg(windows)\":[{\"id\":\"windows-sys 0.48.0\",\"target\":\"windows_sys\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"terminal_size\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"terminal_size\",\"package_url\":\"https://github.com/eminence/terminal-size\",\"repository\":{\"Http\":{\"sha256\":\"21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7\",\"url\":\"https://static.crates.io/crates/terminal_size/0.3.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"terminal_size\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.0\"},\"termios 0.3.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"edition\":\"2015\"},\"library_target_name\":\"termios\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"termios\",\"package_url\":\"https://github.com/dcuddeback/termios-rs\",\"repository\":{\"Http\":{\"sha256\":\"411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b\",\"url\":\"https://static.crates.io/crates/termios/0.3.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"termios\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.3\"},\"thiserror 1.0.69\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":[{\"id\":\"thiserror-impl 1.0.69\",\"target\":\"thiserror_impl\"}]},\"library_target_name\":\"thiserror\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"thiserror\",\"package_url\":\"https://github.com/dtolnay/thiserror\",\"repository\":{\"Http\":{\"sha256\":\"b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52\",\"url\":\"https://static.crates.io/crates/thiserror/1.0.69/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"thiserror\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.69\"},\"thiserror 2.0.12\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":[{\"id\":\"thiserror-impl 2.0.12\",\"target\":\"thiserror_impl\"}]},\"library_target_name\":\"thiserror\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"thiserror\",\"package_url\":\"https://github.com/dtolnay/thiserror\",\"repository\":{\"Http\":{\"sha256\":\"567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708\",\"url\":\"https://static.crates.io/crates/thiserror/2.0.12/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"thiserror\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"2.0.12\"},\"thiserror-impl 1.0.69\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"thiserror_impl\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"thiserror-impl\",\"package_url\":\"https://github.com/dtolnay/thiserror\",\"repository\":{\"Http\":{\"sha256\":\"4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1\",\"url\":\"https://static.crates.io/crates/thiserror-impl/1.0.69/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"thiserror_impl\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.69\"},\"thiserror-impl 2.0.12\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"thiserror_impl\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"thiserror-impl\",\"package_url\":\"https://github.com/dtolnay/thiserror\",\"repository\":{\"Http\":{\"sha256\":\"7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d\",\"url\":\"https://static.crates.io/crates/thiserror-impl/2.0.12/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"thiserror_impl\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.0.12\"},\"thread_local 1.1.7\":{\"common_attrs\":{\"deps\":[{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"},{\"id\":\"once_cell 1.19.0\",\"target\":\"once_cell\"}],\"edition\":\"2021\"},\"library_target_name\":\"thread_local\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"thread_local\",\"package_url\":\"https://github.com/Amanieu/thread_local-rs\",\"repository\":{\"Http\":{\"sha256\":\"3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152\",\"url\":\"https://static.crates.io/crates/thread_local/1.1.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"thread_local\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.7\"},\"time 0.3.36\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"formatting\",\"parsing\",\"std\"],\"deps\":[{\"id\":\"deranged 0.3.11\",\"target\":\"deranged\"},{\"id\":\"itoa 1.0.10\",\"target\":\"itoa\"},{\"id\":\"num-conv 0.1.0\",\"target\":\"num_conv\"},{\"id\":\"powerfmt 0.2.0\",\"target\":\"powerfmt\"},{\"id\":\"time-core 0.1.2\",\"target\":\"time_core\"}],\"edition\":\"2021\"},\"library_target_name\":\"time\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-Apache\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"time\",\"package_url\":\"https://github.com/time-rs/time\",\"repository\":{\"Http\":{\"sha256\":\"5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885\",\"url\":\"https://static.crates.io/crates/time/0.3.36/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"time\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.36\"},\"time-core 0.1.2\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"time_core\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-Apache\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"time-core\",\"package_url\":\"https://github.com/time-rs/time\",\"repository\":{\"Http\":{\"sha256\":\"ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3\",\"url\":\"https://static.crates.io/crates/time-core/0.1.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"time_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.2\"},\"time-macros 0.2.18\":{\"common_attrs\":{\"deps\":[{\"id\":\"num-conv 0.1.0\",\"target\":\"num_conv\"},{\"id\":\"time-core 0.1.2\",\"target\":\"time_core\"}],\"edition\":\"2021\"},\"library_target_name\":\"time_macros\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-Apache\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"time-macros\",\"package_url\":\"https://github.com/time-rs/time\",\"repository\":{\"Http\":{\"sha256\":\"3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf\",\"url\":\"https://static.crates.io/crates/time-macros/0.2.18/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"time_macros\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.18\"},\"tinystr 0.7.6\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"zerovec\"],\"deps\":[{\"id\":\"zerovec 0.10.4\",\"target\":\"zerovec\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"displaydoc 0.2.5\",\"target\":\"displaydoc\"}]},\"library_target_name\":\"tinystr\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"tinystr\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f\",\"url\":\"https://static.crates.io/crates/tinystr/0.7.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tinystr\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.6\"},\"tinyvec 1.6.0\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"tinyvec_macros\"],\"deps\":[{\"id\":\"tinyvec_macros 0.1.1\",\"target\":\"tinyvec_macros\"}],\"edition\":\"2018\"},\"library_target_name\":\"tinyvec\",\"license\":\"Zlib OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE.md\",\"license_ids\":[\"Apache-2.0\",\"MIT\",\"Zlib\"],\"name\":\"tinyvec\",\"package_url\":\"https://github.com/Lokathor/tinyvec\",\"repository\":{\"Http\":{\"sha256\":\"87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50\",\"url\":\"https://static.crates.io/crates/tinyvec/1.6.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tinyvec\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.6.0\"},\"tinyvec_macros 0.1.1\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"tinyvec_macros\",\"license\":\"MIT OR Apache-2.0 OR Zlib\",\"license_file\":\"LICENSE-APACHE.md\",\"license_ids\":[\"Apache-2.0\",\"MIT\",\"Zlib\"],\"name\":\"tinyvec_macros\",\"package_url\":\"https://github.com/Soveu/tinyvec_macros\",\"repository\":{\"Http\":{\"sha256\":\"1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20\",\"url\":\"https://static.crates.io/crates/tinyvec_macros/0.1.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tinyvec_macros\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.1\"},\"tokio 1.44.2\":{\"common_attrs\":{\"crate_features\":{\"common\":[\"bytes\",\"default\",\"io-util\",\"macros\",\"rt\",\"sync\",\"time\",\"tokio-macros\"],\"selects\":{\"x86_64-unknown-linux-gnu\":[\"fs\",\"io-std\",\"libc\",\"mio\",\"net\",\"socket2\"]}},\"deps\":{\"common\":[{\"id\":\"bytes 1.10.1\",\"target\":\"bytes\"},{\"id\":\"pin-project-lite 0.2.13\",\"target\":\"pin_project_lite\"}],\"selects\":{\"cfg(tokio_taskdump)\":[{\"id\":\"backtrace 0.3.69\",\"target\":\"backtrace\"}],\"x86_64-unknown-linux-gnu\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"},{\"id\":\"mio 1.0.3\",\"target\":\"mio\"},{\"id\":\"socket2 0.5.7\",\"target\":\"socket2\"}]}},\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"tokio-macros 2.5.0\",\"target\":\"tokio_macros\"}]},\"library_target_name\":\"tokio\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tokio\",\"package_url\":\"https://github.com/tokio-rs/tokio\",\"repository\":{\"Http\":{\"sha256\":\"e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48\",\"url\":\"https://static.crates.io/crates/tokio/1.44.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tokio\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.44.2\"},\"tokio-macros 2.5.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"tokio_macros\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tokio-macros\",\"package_url\":\"https://github.com/tokio-rs/tokio\",\"repository\":{\"Http\":{\"sha256\":\"6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8\",\"url\":\"https://static.crates.io/crates/tokio-macros/2.5.0/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"tokio_macros\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.5.0\"},\"tokio-native-tls 0.3.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"native-tls 0.2.12\",\"target\":\"native_tls\"},{\"id\":\"tokio 1.44.2\",\"target\":\"tokio\"}],\"edition\":\"2018\"},\"library_target_name\":\"tokio_native_tls\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tokio-native-tls\",\"package_url\":\"https://github.com/tokio-rs/tls\",\"repository\":{\"Http\":{\"sha256\":\"bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2\",\"url\":\"https://static.crates.io/crates/tokio-native-tls/0.3.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tokio_native_tls\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.1\"},\"tokio-rustls 0.26.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"rustls 0.23.25\",\"target\":\"rustls\"},{\"alias\":\"pki_types\",\"id\":\"rustls-pki-types 1.11.0\",\"target\":\"rustls_pki_types\"},{\"id\":\"tokio 1.44.2\",\"target\":\"tokio\"}],\"edition\":\"2021\"},\"library_target_name\":\"tokio_rustls\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"tokio-rustls\",\"package_url\":\"https://github.com/rustls/tokio-rustls\",\"repository\":{\"Http\":{\"sha256\":\"0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4\",\"url\":\"https://static.crates.io/crates/tokio-rustls/0.26.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tokio_rustls\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.26.0\"},\"tokio-serde 0.9.0\":{\"common_attrs\":{\"crate_features\":[\"bincode\",\"bincode-crate\",\"educe\",\"serde\"],\"deps\":[{\"alias\":\"bincode_crate\",\"id\":\"bincode 1.3.3\",\"target\":\"bincode\"},{\"id\":\"bytes 1.10.1\",\"target\":\"bytes\"},{\"id\":\"futures-core 0.3.31\",\"target\":\"futures_core\"},{\"id\":\"futures-sink 0.3.31\",\"target\":\"futures_sink\"},{\"id\":\"pin-project 1.1.3\",\"target\":\"pin_project\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"educe 0.5.11\",\"target\":\"educe\"}]},\"library_target_name\":\"tokio_serde\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"tokio-serde\",\"package_url\":\"https://github.com/carllerche/tokio-serde\",\"repository\":{\"Http\":{\"sha256\":\"caf600e7036b17782571dd44fa0a5cea3c82f60db5137f774a325a76a0d6852b\",\"url\":\"https://static.crates.io/crates/tokio-serde/0.9.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tokio_serde\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.9.0\"},\"tokio-stream 0.1.15\":{\"common_attrs\":{\"crate_features\":[\"default\",\"sync\",\"time\",\"tokio-util\"],\"deps\":[{\"id\":\"futures-core 0.3.31\",\"target\":\"futures_core\"},{\"id\":\"pin-project-lite 0.2.13\",\"target\":\"pin_project_lite\"},{\"id\":\"tokio 1.44.2\",\"target\":\"tokio\"},{\"id\":\"tokio-util 0.7.11\",\"target\":\"tokio_util\"}],\"edition\":\"2021\"},\"library_target_name\":\"tokio_stream\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tokio-stream\",\"package_url\":\"https://github.com/tokio-rs/tokio\",\"repository\":{\"Http\":{\"sha256\":\"267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af\",\"url\":\"https://static.crates.io/crates/tokio-stream/0.1.15/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tokio_stream\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.15\"},\"tokio-util 0.7.11\":{\"common_attrs\":{\"crate_features\":{\"common\":[\"codec\",\"default\"],\"selects\":{\"x86_64-unknown-linux-gnu\":[\"io\"]}},\"deps\":[{\"id\":\"bytes 1.10.1\",\"target\":\"bytes\"},{\"id\":\"futures-core 0.3.31\",\"target\":\"futures_core\"},{\"id\":\"futures-sink 0.3.31\",\"target\":\"futures_sink\"},{\"id\":\"pin-project-lite 0.2.13\",\"target\":\"pin_project_lite\"},{\"id\":\"tokio 1.44.2\",\"target\":\"tokio\"}],\"edition\":\"2021\"},\"library_target_name\":\"tokio_util\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tokio-util\",\"package_url\":\"https://github.com/tokio-rs/tokio\",\"repository\":{\"Http\":{\"sha256\":\"9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1\",\"url\":\"https://static.crates.io/crates/tokio-util/0.7.11/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tokio_util\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.11\"},\"toml 0.8.14\":{\"common_attrs\":{\"crate_features\":[\"default\",\"display\",\"indexmap\",\"parse\",\"preserve_order\"],\"deps\":[{\"id\":\"indexmap 2.9.0\",\"target\":\"indexmap\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"},{\"id\":\"serde_spanned 0.6.6\",\"target\":\"serde_spanned\"},{\"id\":\"toml_datetime 0.6.6\",\"target\":\"toml_datetime\"},{\"id\":\"toml_edit 0.22.14\",\"target\":\"toml_edit\"}],\"edition\":\"2021\"},\"library_target_name\":\"toml\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"toml\",\"package_url\":\"https://github.com/toml-rs/toml\",\"repository\":{\"Http\":{\"sha256\":\"6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335\",\"url\":\"https://static.crates.io/crates/toml/0.8.14/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"toml\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.14\"},\"toml_datetime 0.6.6\":{\"common_attrs\":{\"crate_features\":[\"serde\"],\"deps\":[{\"id\":\"serde 1.0.219\",\"target\":\"serde\"}],\"edition\":\"2021\"},\"library_target_name\":\"toml_datetime\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"toml_datetime\",\"package_url\":\"https://github.com/toml-rs/toml\",\"repository\":{\"Http\":{\"sha256\":\"4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf\",\"url\":\"https://static.crates.io/crates/toml_datetime/0.6.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"toml_datetime\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.6\"},\"toml_edit 0.19.15\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"deps\":[{\"id\":\"indexmap 2.9.0\",\"target\":\"indexmap\"},{\"id\":\"toml_datetime 0.6.6\",\"target\":\"toml_datetime\"},{\"id\":\"winnow 0.5.33\",\"target\":\"winnow\"}],\"edition\":\"2021\"},\"library_target_name\":\"toml_edit\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"toml_edit\",\"package_url\":\"https://github.com/toml-rs/toml\",\"repository\":{\"Http\":{\"sha256\":\"1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421\",\"url\":\"https://static.crates.io/crates/toml_edit/0.19.15/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"toml_edit\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.19.15\"},\"toml_edit 0.22.14\":{\"common_attrs\":{\"crate_features\":[\"display\",\"parse\",\"serde\"],\"deps\":[{\"id\":\"indexmap 2.9.0\",\"target\":\"indexmap\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"},{\"id\":\"serde_spanned 0.6.6\",\"target\":\"serde_spanned\"},{\"id\":\"toml_datetime 0.6.6\",\"target\":\"toml_datetime\"},{\"id\":\"winnow 0.6.13\",\"target\":\"winnow\"}],\"edition\":\"2021\"},\"library_target_name\":\"toml_edit\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"toml_edit\",\"package_url\":\"https://github.com/toml-rs/toml\",\"repository\":{\"Http\":{\"sha256\":\"f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38\",\"url\":\"https://static.crates.io/crates/toml_edit/0.22.14/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"toml_edit\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.22.14\"},\"tower 0.4.13\":{\"common_attrs\":{\"crate_features\":[\"__common\",\"futures-core\",\"futures-util\",\"make\",\"pin-project\",\"pin-project-lite\",\"tokio\",\"util\"],\"deps\":[{\"id\":\"futures-core 0.3.31\",\"target\":\"futures_core\"},{\"id\":\"futures-util 0.3.31\",\"target\":\"futures_util\"},{\"id\":\"pin-project 1.1.3\",\"target\":\"pin_project\"},{\"id\":\"pin-project-lite 0.2.13\",\"target\":\"pin_project_lite\"},{\"id\":\"tokio 1.44.2\",\"target\":\"tokio\"},{\"id\":\"tower-layer 0.3.2\",\"target\":\"tower_layer\"},{\"id\":\"tower-service 0.3.2\",\"target\":\"tower_service\"}],\"edition\":\"2018\"},\"library_target_name\":\"tower\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tower\",\"package_url\":\"https://github.com/tower-rs/tower\",\"repository\":{\"Http\":{\"sha256\":\"b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c\",\"url\":\"https://static.crates.io/crates/tower/0.4.13/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tower\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.13\"},\"tower-layer 0.3.2\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"tower_layer\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tower-layer\",\"package_url\":\"https://github.com/tower-rs/tower\",\"repository\":{\"Http\":{\"sha256\":\"c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0\",\"url\":\"https://static.crates.io/crates/tower-layer/0.3.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tower_layer\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.2\"},\"tower-service 0.3.2\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"tower_service\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tower-service\",\"package_url\":\"https://github.com/tower-rs/tower\",\"repository\":{\"Http\":{\"sha256\":\"b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52\",\"url\":\"https://static.crates.io/crates/tower-service/0.3.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tower_service\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.2\"},\"tracing 0.1.41\":{\"common_attrs\":{\"crate_features\":[\"attributes\",\"default\",\"log\",\"release_max_level_debug\",\"std\",\"tracing-attributes\"],\"deps\":[{\"id\":\"log 0.4.20\",\"target\":\"log\"},{\"id\":\"pin-project-lite 0.2.13\",\"target\":\"pin_project_lite\"},{\"id\":\"tracing-core 0.1.33\",\"target\":\"tracing_core\"}],\"edition\":\"2018\",\"proc_macro_deps\":[{\"id\":\"tracing-attributes 0.1.28\",\"target\":\"tracing_attributes\"}]},\"library_target_name\":\"tracing\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tracing\",\"package_url\":\"https://github.com/tokio-rs/tracing\",\"repository\":{\"Http\":{\"sha256\":\"784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0\",\"url\":\"https://static.crates.io/crates/tracing/0.1.41/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tracing\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.41\"},\"tracing-attributes 0.1.28\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2018\"},\"library_target_name\":\"tracing_attributes\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tracing-attributes\",\"package_url\":\"https://github.com/tokio-rs/tracing\",\"repository\":{\"Http\":{\"sha256\":\"395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d\",\"url\":\"https://static.crates.io/crates/tracing-attributes/0.1.28/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"tracing_attributes\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.28\"},\"tracing-core 0.1.33\":{\"common_attrs\":{\"crate_features\":[\"default\",\"once_cell\",\"std\"],\"deps\":[{\"id\":\"once_cell 1.19.0\",\"target\":\"once_cell\"}],\"edition\":\"2018\"},\"library_target_name\":\"tracing_core\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tracing-core\",\"package_url\":\"https://github.com/tokio-rs/tracing\",\"repository\":{\"Http\":{\"sha256\":\"e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c\",\"url\":\"https://static.crates.io/crates/tracing-core/0.1.33/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tracing_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.33\"},\"tracing-log 0.2.0\":{\"common_attrs\":{\"crate_features\":[\"log-tracer\",\"std\"],\"deps\":[{\"id\":\"log 0.4.20\",\"target\":\"log\"},{\"id\":\"once_cell 1.19.0\",\"target\":\"once_cell\"},{\"id\":\"tracing-core 0.1.33\",\"target\":\"tracing_core\"}],\"edition\":\"2018\"},\"library_target_name\":\"tracing_log\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tracing-log\",\"package_url\":\"https://github.com/tokio-rs/tracing\",\"repository\":{\"Http\":{\"sha256\":\"ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3\",\"url\":\"https://static.crates.io/crates/tracing-log/0.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tracing_log\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.0\"},\"tracing-subscriber 0.3.18\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"ansi\",\"default\",\"env-filter\",\"fmt\",\"matchers\",\"nu-ansi-term\",\"once_cell\",\"regex\",\"registry\",\"sharded-slab\",\"smallvec\",\"std\",\"thread_local\",\"tracing\",\"tracing-log\"],\"deps\":[{\"id\":\"matchers 0.1.0\",\"target\":\"matchers\"},{\"id\":\"nu-ansi-term 0.46.0\",\"target\":\"nu_ansi_term\"},{\"id\":\"once_cell 1.19.0\",\"target\":\"once_cell\"},{\"id\":\"regex 1.10.2\",\"target\":\"regex\"},{\"id\":\"sharded-slab 0.1.7\",\"target\":\"sharded_slab\"},{\"id\":\"smallvec 1.13.2\",\"target\":\"smallvec\"},{\"id\":\"thread_local 1.1.7\",\"target\":\"thread_local\"},{\"id\":\"tracing 0.1.41\",\"target\":\"tracing\"},{\"id\":\"tracing-core 0.1.33\",\"target\":\"tracing_core\"},{\"id\":\"tracing-log 0.2.0\",\"target\":\"tracing_log\"}],\"edition\":\"2018\"},\"library_target_name\":\"tracing_subscriber\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tracing-subscriber\",\"package_url\":\"https://github.com/tokio-rs/tracing\",\"repository\":{\"Http\":{\"sha256\":\"ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b\",\"url\":\"https://static.crates.io/crates/tracing-subscriber/0.3.18/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tracing_subscriber\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.18\"},\"try-lock 0.2.5\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"try_lock\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"try-lock\",\"package_url\":\"https://github.com/seanmonstar/try-lock\",\"repository\":{\"Http\":{\"sha256\":\"e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b\",\"url\":\"https://static.crates.io/crates/try-lock/0.2.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"try_lock\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.5\"},\"twox-hash 1.6.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"},{\"id\":\"static_assertions 1.1.0\",\"target\":\"static_assertions\"}],\"edition\":\"2018\"},\"library_target_name\":\"twox_hash\",\"license\":\"MIT\",\"license_file\":\"LICENSE.txt\",\"license_ids\":[\"MIT\"],\"name\":\"twox-hash\",\"package_url\":\"https://github.com/shepmaster/twox-hash\",\"repository\":{\"Http\":{\"sha256\":\"97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675\",\"url\":\"https://static.crates.io/crates/twox-hash/1.6.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"twox_hash\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.6.3\"},\"typenum 1.17.0\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2018\",\"extra_deps\":[\":build_script_main\"]},\"library_target_name\":\"typenum\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"typenum\",\"package_url\":\"https://github.com/paholg/typenum\",\"repository\":{\"Http\":{\"sha256\":\"42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825\",\"url\":\"https://static.crates.io/crates/typenum/1.17.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"typenum\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_main\",\"crate_root\":\"build/main.rs\"}}],\"version\":\"1.17.0\"},\"unicase 2.7.0\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"version_check 0.9.5\",\"target\":\"version_check\"}]},\"common_attrs\":{\"edition\":\"2015\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"unicase\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"unicase\",\"package_url\":\"https://github.com/seanmonstar/unicase\",\"repository\":{\"Http\":{\"sha256\":\"f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89\",\"url\":\"https://static.crates.io/crates/unicase/2.7.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"unicase\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"2.7.0\"},\"unicode-ident 1.0.12\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"unicode_ident\",\"license\":\"(MIT OR Apache-2.0) AND Unicode-DFS-2016\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\",\"Unicode-DFS-2016\"],\"name\":\"unicode-ident\",\"package_url\":\"https://github.com/dtolnay/unicode-ident\",\"repository\":{\"Http\":{\"sha256\":\"3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b\",\"url\":\"https://static.crates.io/crates/unicode-ident/1.0.12/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"unicode_ident\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.12\"},\"unicode-normalization 0.1.22\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"tinyvec 1.6.0\",\"target\":\"tinyvec\"}],\"edition\":\"2018\"},\"library_target_name\":\"unicode_normalization\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"unicode-normalization\",\"package_url\":\"https://github.com/unicode-rs/unicode-normalization\",\"repository\":{\"Http\":{\"sha256\":\"5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921\",\"url\":\"https://static.crates.io/crates/unicode-normalization/0.1.22/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"unicode_normalization\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.22\"},\"unicode-segmentation 1.10.1\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"unicode_segmentation\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"unicode-segmentation\",\"package_url\":\"https://github.com/unicode-rs/unicode-segmentation\",\"repository\":{\"Http\":{\"sha256\":\"1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36\",\"url\":\"https://static.crates.io/crates/unicode-segmentation/1.10.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"unicode_segmentation\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.10.1\"},\"unicode-width 0.2.0\":{\"common_attrs\":{\"crate_features\":[\"cjk\",\"default\"],\"edition\":\"2021\"},\"library_target_name\":\"unicode_width\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"unicode-width\",\"package_url\":\"https://github.com/unicode-rs/unicode-width\",\"repository\":{\"Http\":{\"sha256\":\"1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd\",\"url\":\"https://static.crates.io/crates/unicode-width/0.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"unicode_width\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.0\"},\"unicode-xid 0.2.4\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"edition\":\"2015\"},\"library_target_name\":\"unicode_xid\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"unicode-xid\",\"package_url\":\"https://github.com/unicode-rs/unicode-xid\",\"repository\":{\"Http\":{\"sha256\":\"f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c\",\"url\":\"https://static.crates.io/crates/unicode-xid/0.2.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"unicode_xid\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.4\"},\"unsafe-libyaml 0.2.11\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"unsafe_libyaml\",\"license\":\"MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\"],\"name\":\"unsafe-libyaml\",\"package_url\":\"https://github.com/dtolnay/unsafe-libyaml\",\"repository\":{\"Http\":{\"sha256\":\"673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861\",\"url\":\"https://static.crates.io/crates/unsafe-libyaml/0.2.11/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"unsafe_libyaml\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.11\"},\"untrusted 0.9.0\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"untrusted\",\"license\":\"ISC\",\"license_file\":\"LICENSE.txt\",\"license_ids\":[\"ISC\"],\"name\":\"untrusted\",\"package_url\":\"https://github.com/briansmith/untrusted\",\"repository\":{\"Http\":{\"sha256\":\"8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1\",\"url\":\"https://static.crates.io/crates/untrusted/0.9.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"untrusted\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.9.0\"},\"url 2.5.4\":{\"common_attrs\":{\"crate_features\":[\"default\",\"serde\",\"std\"],\"deps\":[{\"id\":\"form_urlencoded 1.2.1\",\"target\":\"form_urlencoded\"},{\"id\":\"idna 1.0.3\",\"target\":\"idna\"},{\"id\":\"percent-encoding 2.3.1\",\"target\":\"percent_encoding\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"}],\"edition\":\"2018\"},\"library_target_name\":\"url\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"url\",\"package_url\":\"https://github.com/servo/rust-url\",\"repository\":{\"Http\":{\"sha256\":\"32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60\",\"url\":\"https://static.crates.io/crates/url/2.5.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"url\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.5.4\"},\"urlencoding 2.1.3\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"urlencoding\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"urlencoding\",\"package_url\":\"https://github.com/kornelski/rust_urlencoding\",\"repository\":{\"Http\":{\"sha256\":\"daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da\",\"url\":\"https://static.crates.io/crates/urlencoding/2.1.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"urlencoding\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.1.3\"},\"utf16_iter 1.0.5\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"utf16_iter\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"utf16_iter\",\"package_url\":\"https://github.com/hsivonen/utf16_iter\",\"repository\":{\"Http\":{\"sha256\":\"c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246\",\"url\":\"https://static.crates.io/crates/utf16_iter/1.0.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"utf16_iter\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.5\"},\"utf8_iter 1.0.4\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"utf8_iter\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"utf8_iter\",\"package_url\":\"https://github.com/hsivonen/utf8_iter\",\"repository\":{\"Http\":{\"sha256\":\"b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be\",\"url\":\"https://static.crates.io/crates/utf8_iter/1.0.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"utf8_iter\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.4\"},\"uuid 1.9.1\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"uuid\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"uuid\",\"package_url\":\"https://github.com/uuid-rs/uuid\",\"repository\":{\"Http\":{\"sha256\":\"5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439\",\"url\":\"https://static.crates.io/crates/uuid/1.9.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"uuid\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.9.1\"},\"valuable 0.1.0\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"valuable\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"valuable\",\"package_url\":\"https://github.com/tokio-rs/valuable\",\"repository\":{\"Http\":{\"sha256\":\"830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d\",\"url\":\"https://static.crates.io/crates/valuable/0.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"valuable\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.1.0\"},\"vcpkg 0.2.15\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"vcpkg\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"vcpkg\",\"package_url\":\"https://github.com/mcgoo/vcpkg-rs\",\"repository\":{\"Http\":{\"sha256\":\"accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426\",\"url\":\"https://static.crates.io/crates/vcpkg/0.2.15/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"vcpkg\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.15\"},\"version_check 0.9.5\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"version_check\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"version_check\",\"package_url\":\"https://github.com/SergioBenitez/version_check\",\"repository\":{\"Http\":{\"sha256\":\"0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a\",\"url\":\"https://static.crates.io/crates/version_check/0.9.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"version_check\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.9.5\"},\"virtual-fs 0.601.0\":{\"common_attrs\":{\"crate_features\":[\"anyhow\",\"js\",\"webc\",\"webc-fs\"],\"deps\":[{\"id\":\"anyhow 1.0.97\",\"target\":\"anyhow\"},{\"id\":\"bytes 1.10.1\",\"target\":\"bytes\"},{\"id\":\"dashmap 6.1.0\",\"target\":\"dashmap\"},{\"id\":\"derive_more 2.0.1\",\"target\":\"derive_more\"},{\"id\":\"dunce 1.0.5\",\"target\":\"dunce\"},{\"id\":\"futures 0.3.30\",\"target\":\"futures\"},{\"id\":\"getrandom 0.2.15\",\"target\":\"getrandom\"},{\"id\":\"indexmap 2.9.0\",\"target\":\"indexmap\"},{\"id\":\"pin-project-lite 0.2.13\",\"target\":\"pin_project_lite\"},{\"id\":\"replace_with 0.1.7\",\"target\":\"replace_with\"},{\"id\":\"shared-buffer 0.1.4\",\"target\":\"shared_buffer\"},{\"id\":\"slab 0.4.9\",\"target\":\"slab\"},{\"id\":\"thiserror 1.0.69\",\"target\":\"thiserror\"},{\"id\":\"tokio 1.44.2\",\"target\":\"tokio\"},{\"id\":\"tracing 0.1.41\",\"target\":\"tracing\"},{\"id\":\"virtual-mio 0.601.0\",\"target\":\"virtual_mio\"},{\"id\":\"wasmer-package 0.601.0\",\"target\":\"wasmer_package\"},{\"id\":\"web-time 1.1.0\",\"target\":\"web_time\"},{\"id\":\"webc 10.0.1\",\"target\":\"webc\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"async-trait 0.1.88\",\"target\":\"async_trait\"}]},\"library_target_name\":\"virtual_fs\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"virtual-fs\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[\"@@//src/wasix/browser-host:patches/0036-virtual-fs-poll-contended-pipe-reads.patch\"],\"sha256\":\"8defc513ce70576bdbb4305ee67c0cba647af18c0995de8f1fa1271b724c9859\",\"url\":\"https://static.crates.io/crates/virtual-fs/virtual-fs-0.601.0.crate\"}},\"targets\":[{\"Library\":{\"crate_name\":\"virtual_fs\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.601.0\"},\"virtual-mio 0.601.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"bytes 1.10.1\",\"target\":\"bytes\"},{\"id\":\"futures 0.3.30\",\"target\":\"futures\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"},{\"id\":\"thiserror 1.0.69\",\"target\":\"thiserror\"},{\"id\":\"tracing 0.1.41\",\"target\":\"tracing\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"async-trait 0.1.88\",\"target\":\"async_trait\"}]},\"library_target_name\":\"virtual_mio\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"virtual-mio\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[\"@@//src/wasix/browser-host:patches/0037-virtual-mio-retain-inline-wakes.patch\"],\"sha256\":\"a14806a3f25b70315764760c376d9f68937f5467013891bc7497a33d24105097\",\"url\":\"https://static.crates.io/crates/virtual-mio/virtual-mio-0.601.0.crate\"}},\"targets\":[{\"Library\":{\"crate_name\":\"virtual_mio\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.601.0\"},\"virtual-net 0.601.0\":{\"common_attrs\":{\"crate_features\":[\"libc\",\"remote\",\"rkyv\",\"tokio-serde\",\"tokio-util\"],\"deps\":[{\"id\":\"anyhow 1.0.97\",\"target\":\"anyhow\"},{\"id\":\"base64 0.22.1\",\"target\":\"base64\"},{\"id\":\"bincode 1.3.3\",\"target\":\"bincode\"},{\"id\":\"bytecheck 0.6.11\",\"target\":\"bytecheck\"},{\"id\":\"bytes 1.10.1\",\"target\":\"bytes\"},{\"id\":\"derive_more 2.0.1\",\"target\":\"derive_more\"},{\"id\":\"futures-util 0.3.31\",\"target\":\"futures_util\"},{\"id\":\"ipnet 2.11.0\",\"target\":\"ipnet\"},{\"id\":\"iprange 0.6.7\",\"target\":\"iprange\"},{\"id\":\"libc 0.2.171\",\"target\":\"libc\"},{\"id\":\"pin-project-lite 0.2.13\",\"target\":\"pin_project_lite\"},{\"id\":\"rkyv 0.8.10\",\"target\":\"rkyv\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"},{\"id\":\"smoltcp 0.8.2\",\"target\":\"smoltcp\"},{\"id\":\"thiserror 1.0.69\",\"target\":\"thiserror\"},{\"id\":\"tokio 1.44.2\",\"target\":\"tokio\"},{\"id\":\"tokio-serde 0.9.0\",\"target\":\"tokio_serde\"},{\"id\":\"tokio-util 0.7.11\",\"target\":\"tokio_util\"},{\"id\":\"tracing 0.1.41\",\"target\":\"tracing\"},{\"id\":\"virtual-mio 0.601.0\",\"target\":\"virtual_mio\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"async-trait 0.1.88\",\"target\":\"async_trait\"}]},\"library_target_name\":\"virtual_net\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"virtual-net\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"sha256\":\"0a7dccbe5d8d3a49e2b43a2c5a4287139e33ba04c03279bfc8a0aef82def2043\",\"url\":\"https://static.crates.io/crates/virtual-net/0.601.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"virtual_net\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.601.0\"},\"wai-bindgen-gen-core 0.2.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"anyhow 1.0.97\",\"target\":\"anyhow\"},{\"id\":\"wai-parser 0.2.3\",\"target\":\"wai_parser\"}],\"edition\":\"2021\"},\"library_target_name\":\"wai_bindgen_gen_core\",\"license\":\"Apache-2.0\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"wai-bindgen-gen-core\",\"package_url\":\"https://github.com/wasmerio/wai\",\"repository\":{\"Http\":{\"sha256\":\"1aa3dc41b510811122b3088197234c27e08fcad63ef936306dd8e11e2803876c\",\"url\":\"https://static.crates.io/crates/wai-bindgen-gen-core/0.2.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wai_bindgen_gen_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.3\"},\"wai-bindgen-gen-rust 0.2.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"heck 0.3.3\",\"target\":\"heck\"},{\"id\":\"wai-bindgen-gen-core 0.2.3\",\"target\":\"wai_bindgen_gen_core\"}],\"edition\":\"2021\"},\"library_target_name\":\"wai_bindgen_gen_rust\",\"license\":\"Apache-2.0\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"wai-bindgen-gen-rust\",\"package_url\":\"https://github.com/wasmerio/wai\",\"repository\":{\"Http\":{\"sha256\":\"19bc05e8380515c4337c40ef03b2ff233e391315b178a320de8640703d522efe\",\"url\":\"https://static.crates.io/crates/wai-bindgen-gen-rust/0.2.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wai_bindgen_gen_rust\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.3\"},\"wai-bindgen-gen-rust-wasm 0.2.3\":{\"build_script_attrs\":{},\"common_attrs\":{\"deps\":[{\"id\":\"heck 0.3.3\",\"target\":\"heck\"},{\"id\":\"wai-bindgen-gen-core 0.2.3\",\"target\":\"wai_bindgen_gen_core\"},{\"id\":\"wai-bindgen-gen-rust 0.2.3\",\"target\":\"wai_bindgen_gen_rust\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"wai_bindgen_gen_rust_wasm\",\"license\":\"Apache-2.0\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"wai-bindgen-gen-rust-wasm\",\"package_url\":\"https://github.com/wasmerio/wai\",\"repository\":{\"Http\":{\"sha256\":\"d6f35ce5e74086fac87f3a7bd50f643f00fe3559adb75c88521ecaa01c8a6199\",\"url\":\"https://static.crates.io/crates/wai-bindgen-gen-rust-wasm/0.2.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wai_bindgen_gen_rust_wasm\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.2.3\"},\"wai-bindgen-rust 0.2.3\":{\"common_attrs\":{\"crate_features\":[\"macros\",\"wai-bindgen-rust-impl\"],\"deps\":[{\"id\":\"bitflags 1.3.2\",\"target\":\"bitflags\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"wai-bindgen-rust-impl 0.2.3\",\"target\":\"wai_bindgen_rust_impl\"}]},\"library_target_name\":\"wai_bindgen_rust\",\"license\":\"Apache-2.0\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"wai-bindgen-rust\",\"package_url\":\"https://github.com/wasmerio/wai\",\"repository\":{\"Http\":{\"sha256\":\"4e5601c6f448c063e83a5e931b8fefcdf7e01ada424ad42372c948d2e3d67741\",\"url\":\"https://static.crates.io/crates/wai-bindgen-rust/0.2.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wai_bindgen_rust\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.3\"},\"wai-bindgen-rust-impl 0.2.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"syn 1.0.109\",\"target\":\"syn\"},{\"id\":\"wai-bindgen-gen-core 0.2.3\",\"target\":\"wai_bindgen_gen_core\"},{\"id\":\"wai-bindgen-gen-rust-wasm 0.2.3\",\"target\":\"wai_bindgen_gen_rust_wasm\"}],\"edition\":\"2021\"},\"library_target_name\":\"wai_bindgen_rust_impl\",\"license\":\"Apache-2.0\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"wai-bindgen-rust-impl\",\"package_url\":\"https://github.com/wasmerio/wai\",\"repository\":{\"Http\":{\"sha256\":\"bdeeb5c1170246de8425a3e123e7ef260dc05ba2b522a1d369fe2315376efea4\",\"url\":\"https://static.crates.io/crates/wai-bindgen-rust-impl/0.2.3/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"wai_bindgen_rust_impl\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.3\"},\"wai-parser 0.2.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"anyhow 1.0.97\",\"target\":\"anyhow\"},{\"id\":\"id-arena 2.2.1\",\"target\":\"id_arena\"},{\"id\":\"pulldown-cmark 0.8.0\",\"target\":\"pulldown_cmark\"},{\"id\":\"unicode-normalization 0.1.22\",\"target\":\"unicode_normalization\"},{\"id\":\"unicode-xid 0.2.4\",\"target\":\"unicode_xid\"}],\"edition\":\"2021\"},\"library_target_name\":\"wai_parser\",\"license\":\"Apache-2.0\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"wai-parser\",\"package_url\":\"https://github.com/wasmerio/wai\",\"repository\":{\"Http\":{\"sha256\":\"9bd0acb6d70885ea0c343749019ba74f015f64a9d30542e66db69b49b7e28186\",\"url\":\"https://static.crates.io/crates/wai-parser/0.2.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wai_parser\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.3\"},\"waker-fn 1.1.1\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"waker_fn\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"waker-fn\",\"package_url\":\"https://github.com/smol-rs/waker-fn\",\"repository\":{\"Http\":{\"sha256\":\"f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690\",\"url\":\"https://static.crates.io/crates/waker-fn/1.1.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"waker_fn\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.1\"},\"walkdir 2.4.0\":{\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"same-file 1.0.6\",\"target\":\"same_file\"}],\"selects\":{\"cfg(windows)\":[{\"id\":\"winapi-util 0.1.6\",\"target\":\"winapi_util\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"walkdir\",\"license\":\"Unlicense/MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"walkdir\",\"package_url\":\"https://github.com/BurntSushi/walkdir\",\"repository\":{\"Http\":{\"sha256\":\"d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee\",\"url\":\"https://static.crates.io/crates/walkdir/2.4.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"walkdir\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.4.0\"},\"want 0.3.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"try-lock 0.2.5\",\"target\":\"try_lock\"}],\"edition\":\"2018\"},\"library_target_name\":\"want\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"want\",\"package_url\":\"https://github.com/seanmonstar/want\",\"repository\":{\"Http\":{\"sha256\":\"bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e\",\"url\":\"https://static.crates.io/crates/want/0.3.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"want\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.1\"},\"wasi 0.11.0+wasi-snapshot-preview1\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"wasi\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasi\",\"package_url\":\"https://github.com/bytecodealliance/wasi\",\"repository\":{\"Http\":{\"sha256\":\"9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423\",\"url\":\"https://static.crates.io/crates/wasi/0.11.0+wasi-snapshot-preview1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasi\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.11.0+wasi-snapshot-preview1\"},\"wasm-bindgen 0.2.101\":{\"build_script_attrs\":{\"link_deps\":[{\"id\":\"wasm-bindgen-shared 0.2.101\",\"target\":\"wasm_bindgen_shared\"}]},\"common_attrs\":{\"crate_features\":[\"default\",\"msrv\",\"rustversion\",\"std\"],\"deps\":[{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"},{\"id\":\"once_cell 1.19.0\",\"target\":\"once_cell\"},{\"id\":\"wasm-bindgen-shared 0.2.101\",\"target\":\"wasm_bindgen_shared\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":[{\"id\":\"rustversion 1.0.20\",\"target\":\"rustversion\"},{\"id\":\"wasm-bindgen-macro 0.2.101\",\"target\":\"wasm_bindgen_macro\"}]},\"library_target_name\":\"wasm_bindgen\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-bindgen\",\"package_url\":\"https://github.com/wasm-bindgen/wasm-bindgen\",\"repository\":{\"Http\":{\"sha256\":\"7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b\",\"url\":\"https://static.crates.io/crates/wasm-bindgen/0.2.101/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasm_bindgen\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.2.101\"},\"wasm-bindgen-backend 0.2.101\":{\"common_attrs\":{\"deps\":[{\"id\":\"bumpalo 3.14.0\",\"target\":\"bumpalo\"},{\"id\":\"log 0.4.20\",\"target\":\"log\"},{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"},{\"id\":\"wasm-bindgen-shared 0.2.101\",\"target\":\"wasm_bindgen_shared\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasm_bindgen_backend\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-bindgen-backend\",\"package_url\":\"https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/backend\",\"repository\":{\"Http\":{\"sha256\":\"e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb\",\"url\":\"https://static.crates.io/crates/wasm-bindgen-backend/0.2.101/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasm_bindgen_backend\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.101\"},\"wasm-bindgen-derive 0.2.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"js-sys 0.3.78\",\"target\":\"js_sys\"},{\"id\":\"wasm-bindgen 0.2.101\",\"target\":\"wasm_bindgen\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"wasm-bindgen-derive-macro 0.2.1\",\"target\":\"wasm_bindgen_derive_macro\"}]},\"library_target_name\":\"wasm_bindgen_derive\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasm-bindgen-derive\",\"package_url\":\"https://github.com/fjarri/wasm-bindgen-derive\",\"repository\":{\"Http\":{\"sha256\":\"c1ab6c8bffb3f89584781211283fb57337d6902faab6eaee38f336977bdf177d\",\"url\":\"https://static.crates.io/crates/wasm-bindgen-derive/0.2.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasm_bindgen_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.1\"},\"wasm-bindgen-derive-macro 0.2.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 1.0.109\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasm_bindgen_derive_macro\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasm-bindgen-derive-macro\",\"package_url\":\"https://github.com/fjarri/wasm-bindgen-derive\",\"repository\":{\"Http\":{\"sha256\":\"b87c28b31d27616bc69a891700ef0445d2cbaa0340fdacb145145256d5f5fcbb\",\"url\":\"https://static.crates.io/crates/wasm-bindgen-derive-macro/0.2.1/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"wasm_bindgen_derive_macro\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.1\"},\"wasm-bindgen-futures 0.4.51\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"},{\"id\":\"js-sys 0.3.78\",\"target\":\"js_sys\"},{\"id\":\"once_cell 1.19.0\",\"target\":\"once_cell\"},{\"id\":\"wasm-bindgen 0.2.101\",\"target\":\"wasm_bindgen\"}],\"selects\":{\"wasm32-unknown-unknown\":[{\"id\":\"web-sys 0.3.78\",\"target\":\"web_sys\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"wasm_bindgen_futures\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-bindgen-futures\",\"package_url\":\"https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/futures\",\"repository\":{\"Http\":{\"sha256\":\"0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe\",\"url\":\"https://static.crates.io/crates/wasm-bindgen-futures/0.4.51/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasm_bindgen_futures\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.51\"},\"wasm-bindgen-macro 0.2.101\":{\"common_attrs\":{\"deps\":[{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"wasm-bindgen-macro-support 0.2.101\",\"target\":\"wasm_bindgen_macro_support\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasm_bindgen_macro\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-bindgen-macro\",\"package_url\":\"https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/macro\",\"repository\":{\"Http\":{\"sha256\":\"7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d\",\"url\":\"https://static.crates.io/crates/wasm-bindgen-macro/0.2.101/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"wasm_bindgen_macro\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.101\"},\"wasm-bindgen-macro-support 0.2.101\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"},{\"id\":\"wasm-bindgen-backend 0.2.101\",\"target\":\"wasm_bindgen_backend\"},{\"id\":\"wasm-bindgen-shared 0.2.101\",\"target\":\"wasm_bindgen_shared\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasm_bindgen_macro_support\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-bindgen-macro-support\",\"package_url\":\"https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/macro-support\",\"repository\":{\"Http\":{\"sha256\":\"7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa\",\"url\":\"https://static.crates.io/crates/wasm-bindgen-macro-support/0.2.101/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasm_bindgen_macro_support\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.101\"},\"wasm-bindgen-shared 0.2.101\":{\"build_script_attrs\":{\"links\":\"wasm_bindgen\"},\"common_attrs\":{\"deps\":[{\"id\":\"unicode-ident 1.0.12\",\"target\":\"unicode_ident\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"wasm_bindgen_shared\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-bindgen-shared\",\"package_url\":\"https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/shared\",\"repository\":{\"Http\":{\"sha256\":\"f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1\",\"url\":\"https://static.crates.io/crates/wasm-bindgen-shared/0.2.101/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasm_bindgen_shared\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.2.101\"},\"wasm-bindgen-test 0.3.51\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":{\"common\":[{\"id\":\"js-sys 0.3.78\",\"target\":\"js_sys\"},{\"id\":\"wasm-bindgen 0.2.101\",\"target\":\"wasm_bindgen\"},{\"id\":\"wasm-bindgen-futures 0.4.51\",\"target\":\"wasm_bindgen_futures\"}],\"selects\":{\"cfg(all(target_arch = \\\"wasm32\\\", wasm_bindgen_unstable_test_coverage))\":[{\"id\":\"minicov 0.3.7\",\"target\":\"minicov\"}]}},\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"wasm-bindgen-test-macro 0.3.51\",\"target\":\"wasm_bindgen_test_macro\"}]},\"library_target_name\":\"wasm_bindgen_test\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-bindgen-test\",\"package_url\":\"https://github.com/wasm-bindgen/wasm-bindgen\",\"repository\":{\"Http\":{\"sha256\":\"80cc7f8a4114fdaa0c58383caf973fc126cf004eba25c9dc639bccd3880d55ad\",\"url\":\"https://static.crates.io/crates/wasm-bindgen-test/0.3.51/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasm_bindgen_test\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.51\"},\"wasm-bindgen-test-macro 0.3.51\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasm_bindgen_test_macro\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-bindgen-test-macro\",\"package_url\":\"https://github.com/wasm-bindgen/wasm-bindgen\",\"repository\":{\"Http\":{\"sha256\":\"c5ada2ab788d46d4bda04c9d567702a79c8ced14f51f221646a16ed39d0e6a5d\",\"url\":\"https://static.crates.io/crates/wasm-bindgen-test-macro/0.3.51/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"wasm_bindgen_test_macro\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.51\"},\"wasm-encoder 0.221.3\":{\"common_attrs\":{\"crate_features\":[\"component-model\"],\"deps\":[{\"id\":\"leb128 0.2.5\",\"target\":\"leb128\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasm_encoder\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-encoder\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-encoder\",\"repository\":{\"Http\":{\"sha256\":\"dc8444fe4920de80a4fe5ab564fff2ae58b6b73166b89751f8c6c93509da32e5\",\"url\":\"https://static.crates.io/crates/wasm-encoder/0.221.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasm_encoder\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.221.3\"},\"wasm-encoder 0.235.0\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"std\"],\"deps\":[{\"id\":\"leb128fmt 0.1.0\",\"target\":\"leb128fmt\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"wasm_encoder\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-encoder\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-encoder\",\"repository\":{\"Http\":{\"sha256\":\"b3bc393c395cb621367ff02d854179882b9a351b4e0c93d1397e6090b53a5c2a\",\"url\":\"https://static.crates.io/crates/wasm-encoder/0.235.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasm_encoder\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.235.0\"},\"wasm-streams 0.4.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"futures-util 0.3.31\",\"target\":\"futures_util\"},{\"id\":\"js-sys 0.3.78\",\"target\":\"js_sys\"},{\"id\":\"wasm-bindgen 0.2.101\",\"target\":\"wasm_bindgen\"},{\"id\":\"wasm-bindgen-futures 0.4.51\",\"target\":\"wasm_bindgen_futures\"},{\"id\":\"web-sys 0.3.78\",\"target\":\"web_sys\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasm_streams\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-streams\",\"package_url\":\"https://github.com/MattiasBuelens/wasm-streams/\",\"repository\":{\"Http\":{\"sha256\":\"b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129\",\"url\":\"https://static.crates.io/crates/wasm-streams/0.4.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasm_streams\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.0\"},\"wasmer 6.1.0\":{\"build_script_attrs\":{\"deps\":{\"common\":[{\"id\":\"cmake 0.1.54\",\"target\":\"cmake\"},{\"id\":\"tar 0.4.44\",\"target\":\"tar\"}],\"selects\":{\"cfg(not(target_env = \\\"musl\\\"))\":[{\"id\":\"bindgen 0.70.1\",\"target\":\"bindgen\"}],\"cfg(target_env = \\\"musl\\\")\":[{\"id\":\"bindgen 0.70.1\",\"target\":\"bindgen\"}]}}},\"common_attrs\":{\"crate_features\":[\"enable-serde\",\"js\",\"js-default\",\"js-serializable-module\",\"js-sys\",\"std\",\"wasm-bindgen\",\"wasm-types-polyfill\",\"wasmparser\",\"wat\"],\"deps\":{\"common\":[{\"id\":\"bytes 1.10.1\",\"target\":\"bytes\"},{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"},{\"id\":\"derive_more 2.0.1\",\"target\":\"derive_more\"},{\"id\":\"indexmap 2.9.0\",\"target\":\"indexmap\"},{\"id\":\"js-sys 0.3.78\",\"target\":\"js_sys\"},{\"id\":\"more-asserts 0.2.2\",\"target\":\"more_asserts\"},{\"id\":\"rustc-demangle 0.1.23\",\"target\":\"rustc_demangle\"},{\"id\":\"shared-buffer 0.1.4\",\"target\":\"shared_buffer\"},{\"id\":\"thiserror 1.0.69\",\"target\":\"thiserror\"},{\"id\":\"tracing 0.1.41\",\"target\":\"tracing\"},{\"id\":\"wasm-bindgen 0.2.101\",\"target\":\"wasm_bindgen\"},{\"id\":\"wasmer-compiler 6.1.0\",\"target\":\"wasmer_compiler\"},{\"id\":\"wasmparser 0.224.1\",\"target\":\"wasmparser\"},{\"id\":\"wat 1.221.3\",\"target\":\"wat\"}],\"selects\":{\"cfg(all(not(target_arch = \\\"wasm32\\\"), target_os = \\\"windows\\\"))\":[{\"id\":\"windows-sys 0.59.0\",\"target\":\"windows_sys\"}],\"cfg(not(target_arch = \\\"wasm32\\\"))\":[{\"id\":\"target-lexicon 0.12.16\",\"target\":\"target_lexicon\"},{\"id\":\"wasmer-types 6.1.0\",\"target\":\"wasmer_types\"}],\"cfg(target_arch = \\\"wasm32\\\")\":[{\"id\":\"serde 1.0.219\",\"target\":\"serde\"},{\"id\":\"serde-wasm-bindgen 0.6.5\",\"target\":\"serde_wasm_bindgen\"},{\"id\":\"target-lexicon 0.12.16\",\"target\":\"target_lexicon\"},{\"id\":\"wasm-bindgen-futures 0.4.51\",\"target\":\"wasm_bindgen_futures\"},{\"id\":\"wasmer-types 6.1.0\",\"target\":\"wasmer_types\"}],\"x86_64-unknown-linux-gnu\":[{\"id\":\"wasmer-vm 6.1.0\",\"target\":\"wasmer_vm\"}]}},\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":{\"common\":[{\"id\":\"paste 1.0.15\",\"target\":\"paste\"}],\"selects\":{\"cfg(not(target_arch = \\\"wasm32\\\"))\":[{\"id\":\"wasmer-derive 6.1.0\",\"target\":\"wasmer_derive\"}],\"cfg(target_arch = \\\"wasm32\\\")\":[{\"id\":\"wasmer-derive 6.1.0\",\"target\":\"wasmer_derive\"}]}}},\"library_target_name\":\"wasmer\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[\"@@//src/wasix/browser-host:patches/0008-wasmer-instantiate-js-modules-async.patch\",\"@@//src/wasix/browser-host:patches/0019-wasmer-parse-exception-reference-types.patch\"],\"sha256\":\"2d85671948f8886a1cc946141c0b688a5617603c103699a5fceeebeb4e75b0b6\",\"url\":\"https://static.crates.io/crates/wasmer/wasmer-6.1.0.crate\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"6.1.0\"},\"wasmer-backend-api 0.601.0\":{\"common_attrs\":{\"crate_features\":[\"js\"],\"deps\":{\"common\":[{\"id\":\"anyhow 1.0.97\",\"target\":\"anyhow\"},{\"id\":\"cynic 3.10.0\",\"target\":\"cynic\"},{\"id\":\"futures 0.3.30\",\"target\":\"futures\"},{\"id\":\"harsh 0.2.2\",\"target\":\"harsh\"},{\"id\":\"merge-streams 0.1.2\",\"target\":\"merge_streams\"},{\"id\":\"pin-project-lite 0.2.13\",\"target\":\"pin_project_lite\"},{\"id\":\"reqwest 0.12.7\",\"target\":\"reqwest\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.140\",\"target\":\"serde_json\"},{\"id\":\"serde_path_to_error 0.1.17\",\"target\":\"serde_path_to_error\"},{\"id\":\"time 0.3.36\",\"target\":\"time\"},{\"id\":\"tokio 1.44.2\",\"target\":\"tokio\"},{\"id\":\"tracing 0.1.41\",\"target\":\"tracing\"},{\"id\":\"url 2.5.4\",\"target\":\"url\"},{\"id\":\"wasmer-config 0.601.0\",\"target\":\"wasmer_config\"},{\"id\":\"wasmer-package 0.601.0\",\"target\":\"wasmer_package\"},{\"id\":\"webc 10.0.1\",\"target\":\"webc\"}],\"selects\":{\"cfg(target_family = \\\"wasm\\\")\":[{\"id\":\"getrandom 0.2.15\",\"target\":\"getrandom\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"wasmer_backend_api\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer-backend-api\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"sha256\":\"ef123baf425c415c1538fcf6da66d030c69d47ee8a9acc063e9f7b890c7ec893\",\"url\":\"https://static.crates.io/crates/wasmer-backend-api/0.601.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_backend_api\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.601.0\"},\"wasmer-compiler 6.1.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"enable-serde\",\"serde\",\"serde_bytes\",\"std\"],\"deps\":{\"common\":[{\"id\":\"backtrace 0.3.69\",\"target\":\"backtrace\"},{\"id\":\"bytes 1.10.1\",\"target\":\"bytes\"},{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"},{\"id\":\"enum-iterator 0.7.0\",\"target\":\"enum_iterator\"},{\"id\":\"enumset 1.1.3\",\"target\":\"enumset\"},{\"id\":\"leb128 0.2.5\",\"target\":\"leb128\"},{\"id\":\"libc 0.2.171\",\"target\":\"libc\"},{\"id\":\"memmap2 0.6.2\",\"target\":\"memmap2\"},{\"id\":\"more-asserts 0.2.2\",\"target\":\"more_asserts\"},{\"id\":\"object 0.32.2\",\"target\":\"object\"},{\"id\":\"rkyv 0.8.10\",\"target\":\"rkyv\"},{\"id\":\"self_cell 1.0.3\",\"target\":\"self_cell\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"},{\"id\":\"serde_bytes 0.11.14\",\"target\":\"serde_bytes\"},{\"id\":\"shared-buffer 0.1.4\",\"target\":\"shared_buffer\"},{\"id\":\"smallvec 1.13.2\",\"target\":\"smallvec\"},{\"id\":\"target-lexicon 0.12.16\",\"target\":\"target_lexicon\"},{\"id\":\"thiserror 1.0.69\",\"target\":\"thiserror\"},{\"id\":\"wasmer-types 6.1.0\",\"target\":\"wasmer_types\"},{\"id\":\"xxhash-rust 0.8.11\",\"target\":\"xxhash_rust\"}],\"selects\":{\"cfg(all(target_os = \\\"macos\\\", target_arch = \\\"aarch64\\\"))\":[{\"id\":\"macho-unwind-info 0.5.0\",\"target\":\"macho_unwind_info\"}],\"cfg(not(target_arch = \\\"wasm32\\\"))\":[{\"id\":\"region 3.0.2\",\"target\":\"region\"},{\"id\":\"wasmer-vm 6.1.0\",\"target\":\"wasmer_vm\"}],\"cfg(target_os = \\\"windows\\\")\":[{\"id\":\"windows-sys 0.59.0\",\"target\":\"windows_sys\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"wasmer_compiler\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer-compiler\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"sha256\":\"4946475adc0af265af8f10aadf4d4a3c64845bcd3801c655bdd81ce5e3ee869b\",\"url\":\"https://static.crates.io/crates/wasmer-compiler/6.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_compiler\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"6.1.0\"},\"wasmer-config 0.601.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"anyhow 1.0.97\",\"target\":\"anyhow\"},{\"id\":\"bytesize 1.3.0\",\"target\":\"bytesize\"},{\"id\":\"ciborium 0.2.2\",\"target\":\"ciborium\"},{\"id\":\"derive_builder 0.12.0\",\"target\":\"derive_builder\"},{\"id\":\"hex 0.4.3\",\"target\":\"hex\"},{\"id\":\"indexmap 2.9.0\",\"target\":\"indexmap\"},{\"id\":\"saffron 0.1.0\",\"target\":\"saffron\"},{\"id\":\"schemars 0.8.21\",\"target\":\"schemars\"},{\"id\":\"semver 1.0.26\",\"target\":\"semver\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.140\",\"target\":\"serde_json\"},{\"id\":\"serde_yaml 0.9.34+deprecated\",\"target\":\"serde_yaml\"},{\"id\":\"thiserror 1.0.69\",\"target\":\"thiserror\"},{\"id\":\"toml 0.8.14\",\"target\":\"toml\"},{\"id\":\"url 2.5.4\",\"target\":\"url\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasmer_config\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer-config\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"sha256\":\"f6c7a72bfcba1000b7609e034e0d470575fae8215b597c2c6554661729d64c22\",\"url\":\"https://static.crates.io/crates/wasmer-config/0.601.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_config\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.601.0\"},\"wasmer-derive 6.1.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro-error2 2.0.1\",\"target\":\"proc_macro_error2\"},{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 1.0.109\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasmer_derive\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer-derive\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"sha256\":\"c546f3380840cd63fdcc390f04cd19002f2dfa19b4691b77ecbd27642bd93452\",\"url\":\"https://static.crates.io/crates/wasmer-derive/6.1.0/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"wasmer_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"6.1.0\"},\"wasmer-journal 0.601.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"anyhow 1.0.97\",\"target\":\"anyhow\"},{\"id\":\"base64 0.22.1\",\"target\":\"base64\"},{\"id\":\"bincode 1.3.3\",\"target\":\"bincode\"},{\"id\":\"bytecheck 0.6.11\",\"target\":\"bytecheck\"},{\"id\":\"bytes 1.10.1\",\"target\":\"bytes\"},{\"id\":\"derive_more 2.0.1\",\"target\":\"derive_more\"},{\"id\":\"lz4_flex 0.11.1\",\"target\":\"lz4_flex\"},{\"id\":\"num_enum 0.7.3\",\"target\":\"num_enum\"},{\"id\":\"rkyv 0.8.10\",\"target\":\"rkyv\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.140\",\"target\":\"serde_json\"},{\"id\":\"thiserror 1.0.69\",\"target\":\"thiserror\"},{\"id\":\"tracing 0.1.41\",\"target\":\"tracing\"},{\"id\":\"virtual-fs 0.601.0\",\"target\":\"virtual_fs\"},{\"id\":\"virtual-net 0.601.0\",\"target\":\"virtual_net\"},{\"id\":\"wasmer 6.1.0\",\"target\":\"wasmer\"},{\"id\":\"wasmer-config 0.601.0\",\"target\":\"wasmer_config\"},{\"id\":\"wasmer-wasix-types 0.601.0\",\"target\":\"wasmer_wasix_types\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"async-trait 0.1.88\",\"target\":\"async_trait\"}]},\"library_target_name\":\"wasmer_journal\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer-journal\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"sha256\":\"6459cd00a0000e38dd4386bec1d99687813677bb01bfe69120f0f3eaedae0a06\",\"url\":\"https://static.crates.io/crates/wasmer-journal/0.601.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_journal\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.601.0\"},\"wasmer-js 0.0.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"anyhow 1.0.97\",\"target\":\"anyhow\"},{\"id\":\"bincode 1.3.3\",\"target\":\"bincode\"},{\"id\":\"bytes 1.10.1\",\"target\":\"bytes\"},{\"id\":\"console_error_panic_hook 0.1.7\",\"target\":\"console_error_panic_hook\"},{\"id\":\"futures 0.3.30\",\"target\":\"futures\"},{\"id\":\"instant 0.1.12\",\"target\":\"instant\"},{\"id\":\"js-sys 0.3.78\",\"target\":\"js_sys\"},{\"id\":\"lazy_static 1.5.0\",\"target\":\"lazy_static\"},{\"id\":\"once_cell 1.19.0\",\"target\":\"once_cell\"},{\"id\":\"reqwest 0.12.7\",\"target\":\"reqwest\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"},{\"id\":\"serde-wasm-bindgen 0.6.5\",\"target\":\"serde_wasm_bindgen\"},{\"id\":\"sha2 0.10.8\",\"target\":\"sha2\"},{\"id\":\"tempfile 3.12.0\",\"target\":\"tempfile\"},{\"id\":\"tokio 1.44.2\",\"target\":\"tokio\"},{\"id\":\"toml 0.8.14\",\"target\":\"toml\"},{\"id\":\"tracing 0.1.41\",\"target\":\"tracing\"},{\"id\":\"tracing-subscriber 0.3.18\",\"target\":\"tracing_subscriber\"},{\"id\":\"url 2.5.4\",\"target\":\"url\"},{\"id\":\"virtual-fs 0.601.0\",\"target\":\"virtual_fs\"},{\"id\":\"virtual-net 0.601.0\",\"target\":\"virtual_net\"},{\"id\":\"wasm-bindgen 0.2.101\",\"target\":\"wasm_bindgen\"},{\"id\":\"wasm-bindgen-derive 0.2.1\",\"target\":\"wasm_bindgen_derive\"},{\"id\":\"wasm-bindgen-futures 0.4.51\",\"target\":\"wasm_bindgen_futures\"},{\"id\":\"wasm-bindgen-test 0.3.51\",\"target\":\"wasm_bindgen_test\"},{\"id\":\"wasmer 6.1.0\",\"target\":\"wasmer\"},{\"id\":\"wasmer-backend-api 0.601.0\",\"target\":\"wasmer_backend_api\"},{\"id\":\"wasmer-config 0.601.0\",\"target\":\"wasmer_config\"},{\"id\":\"wasmer-package 0.601.0\",\"target\":\"wasmer_package\"},{\"id\":\"wasmer-types 6.1.0\",\"target\":\"wasmer_types\"},{\"id\":\"wasmer-wasix 0.601.0\",\"target\":\"wasmer_wasix\"},{\"id\":\"web-sys 0.3.78\",\"target\":\"web_sys\"},{\"id\":\"webc 10.0.1\",\"target\":\"webc\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"async-trait 0.1.88\",\"target\":\"async_trait\"},{\"id\":\"derivative 2.2.0\",\"target\":\"derivative\"}]},\"name\":\"wasmer-js\",\"repository\":null,\"targets\":[],\"version\":\"0.0.0\"},\"wasmer-package 0.601.0\":{\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"anyhow 1.0.97\",\"target\":\"anyhow\"},{\"id\":\"bytes 1.10.1\",\"target\":\"bytes\"},{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"},{\"id\":\"ciborium 0.2.2\",\"target\":\"ciborium\"},{\"id\":\"flate2 1.1.1\",\"target\":\"flate2\"},{\"id\":\"ignore 0.4.22\",\"target\":\"ignore\"},{\"id\":\"insta 1.41.1\",\"target\":\"insta\"},{\"id\":\"semver 1.0.26\",\"target\":\"semver\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.140\",\"target\":\"serde_json\"},{\"id\":\"sha2 0.10.8\",\"target\":\"sha2\"},{\"id\":\"shared-buffer 0.1.4\",\"target\":\"shared_buffer\"},{\"id\":\"tar 0.4.44\",\"target\":\"tar\"},{\"id\":\"tempfile 3.12.0\",\"target\":\"tempfile\"},{\"id\":\"thiserror 1.0.69\",\"target\":\"thiserror\"},{\"id\":\"toml 0.8.14\",\"target\":\"toml\"},{\"id\":\"url 2.5.4\",\"target\":\"url\"},{\"id\":\"wasmer-config 0.601.0\",\"target\":\"wasmer_config\"},{\"id\":\"wasmer-types 6.1.0\",\"target\":\"wasmer_types\"},{\"id\":\"webc 10.0.1\",\"target\":\"webc\"}],\"selects\":{\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"wasi\\\"))\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"wasmer_package\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer-package\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"sha256\":\"aedc3a5cd721e8b12778d1858b9583aca8b91927a73f5fdf0c876cd5bbb6ac56\",\"url\":\"https://static.crates.io/crates/wasmer-package/0.601.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_package\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.601.0\"},\"wasmer-types 6.1.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"detect-wasm-features\",\"enable-serde\",\"serde\",\"serde_bytes\",\"std\"],\"deps\":[{\"id\":\"bytecheck 0.6.11\",\"target\":\"bytecheck\"},{\"id\":\"enum-iterator 0.7.0\",\"target\":\"enum_iterator\"},{\"id\":\"enumset 1.1.3\",\"target\":\"enumset\"},{\"id\":\"getrandom 0.2.15\",\"target\":\"getrandom\"},{\"id\":\"hex 0.4.3\",\"target\":\"hex\"},{\"id\":\"indexmap 2.9.0\",\"target\":\"indexmap\"},{\"id\":\"more-asserts 0.2.2\",\"target\":\"more_asserts\"},{\"id\":\"rkyv 0.8.10\",\"target\":\"rkyv\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"},{\"id\":\"serde_bytes 0.11.14\",\"target\":\"serde_bytes\"},{\"id\":\"sha2 0.10.8\",\"target\":\"sha2\"},{\"id\":\"target-lexicon 0.12.16\",\"target\":\"target_lexicon\"},{\"id\":\"thiserror 1.0.69\",\"target\":\"thiserror\"},{\"id\":\"wasmparser 0.224.1\",\"target\":\"wasmparser\"},{\"id\":\"xxhash-rust 0.8.11\",\"target\":\"xxhash_rust\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasmer_types\",\"license\":\"MIT OR Apache-2.0 WITH LLVM-exception\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasmer-types\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"sha256\":\"94a4027ce165e8dc776dc5e2a3231a96983e6dc7330efd97b793cfc4e973ad0c\",\"url\":\"https://static.crates.io/crates/wasmer-types/6.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_types\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"6.1.0\"},\"wasmer-vm 6.1.0\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"cc 1.2.18\",\"target\":\"cc\"}],\"proc_macro_deps\":[{\"id\":\"rustversion 1.0.20\",\"target\":\"rustversion\"}]},\"common_attrs\":{\"crate_features\":[\"default\",\"enable-serde\",\"serde\"],\"deps\":{\"common\":[{\"id\":\"backtrace 0.3.69\",\"target\":\"backtrace\"},{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"},{\"id\":\"corosensei 0.3.0\",\"target\":\"corosensei\"},{\"id\":\"crossbeam-queue 0.3.11\",\"target\":\"crossbeam_queue\"},{\"id\":\"dashmap 6.1.0\",\"target\":\"dashmap\"},{\"id\":\"enum-iterator 0.7.0\",\"target\":\"enum_iterator\"},{\"id\":\"fnv 1.0.7\",\"target\":\"fnv\"},{\"id\":\"indexmap 2.9.0\",\"target\":\"indexmap\"},{\"id\":\"libc 0.2.171\",\"target\":\"libc\"},{\"id\":\"memoffset 0.9.0\",\"target\":\"memoffset\"},{\"id\":\"more-asserts 0.2.2\",\"target\":\"more_asserts\"},{\"id\":\"region 3.0.2\",\"target\":\"region\"},{\"id\":\"scopeguard 1.2.0\",\"target\":\"scopeguard\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"},{\"id\":\"thiserror 1.0.69\",\"target\":\"thiserror\"},{\"id\":\"wasmer-types 6.1.0\",\"target\":\"wasmer_types\"}],\"selects\":{\"cfg(any(target_family = \\\"unix\\\", all(target_family = \\\"windows\\\", target_env = \\\"gnu\\\")))\":[{\"id\":\"libunwind 1.3.3\",\"target\":\"libunwind\"}],\"cfg(target_os = \\\"windows\\\")\":[{\"id\":\"windows-sys 0.59.0\",\"target\":\"windows_sys\"}],\"cfg(target_vendor = \\\"apple\\\")\":[{\"id\":\"mach2 0.4.2\",\"target\":\"mach2\"}]}},\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"wasmer_vm\",\"license\":\"MIT OR Apache-2.0 WITH LLVM-exception\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasmer-vm\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"sha256\":\"9c37d5be291eea00a00d077ce3a427bb3074709ee386ec358f18f0b7da33be01\",\"url\":\"https://static.crates.io/crates/wasmer-vm/6.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_vm\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"6.1.0\"},\"wasmer-wasix 0.601.0\":{\"common_attrs\":{\"crate_features\":[\"chrono\",\"js\",\"js-default\",\"js-sys\",\"wasm-bindgen\",\"wasm-bindgen-futures\",\"web-sys\"],\"deps\":{\"common\":[{\"id\":\"anyhow 1.0.97\",\"target\":\"anyhow\"},{\"id\":\"base64 0.22.1\",\"target\":\"base64\"},{\"id\":\"bincode 1.3.3\",\"target\":\"bincode\"},{\"id\":\"blake3 1.5.1\",\"target\":\"blake3\"},{\"id\":\"bus 2.4.1\",\"target\":\"bus\"},{\"id\":\"bytecheck 0.6.11\",\"target\":\"bytecheck\"},{\"id\":\"bytes 1.10.1\",\"target\":\"bytes\"},{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"},{\"id\":\"chrono 0.4.40\",\"target\":\"chrono\"},{\"id\":\"cooked-waker 5.0.0\",\"target\":\"cooked_waker\"},{\"id\":\"crossbeam-channel 0.5.15\",\"target\":\"crossbeam_channel\"},{\"id\":\"dashmap 6.1.0\",\"target\":\"dashmap\"},{\"id\":\"derive_more 2.0.1\",\"target\":\"derive_more\"},{\"id\":\"futures 0.3.30\",\"target\":\"futures\"},{\"id\":\"getrandom 0.2.15\",\"target\":\"getrandom\"},{\"id\":\"heapless 0.8.0\",\"target\":\"heapless\"},{\"id\":\"hex 0.4.3\",\"target\":\"hex\"},{\"id\":\"http 1.3.1\",\"target\":\"http\"},{\"id\":\"js-sys 0.3.78\",\"target\":\"js_sys\"},{\"id\":\"linked_hash_set 0.1.4\",\"target\":\"linked_hash_set\"},{\"id\":\"lz4_flex 0.11.1\",\"target\":\"lz4_flex\"},{\"id\":\"num_enum 0.7.3\",\"target\":\"num_enum\"},{\"id\":\"once_cell 1.19.0\",\"target\":\"once_cell\"},{\"id\":\"petgraph 0.7.1\",\"target\":\"petgraph\"},{\"id\":\"pin-project 1.1.3\",\"target\":\"pin_project\"},{\"id\":\"pin-utils 0.1.0\",\"target\":\"pin_utils\"},{\"id\":\"rand 0.8.5\",\"target\":\"rand\"},{\"id\":\"rkyv 0.8.10\",\"target\":\"rkyv\"},{\"id\":\"semver 1.0.26\",\"target\":\"semver\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.140\",\"target\":\"serde_json\"},{\"id\":\"serde_yaml 0.9.34+deprecated\",\"target\":\"serde_yaml\"},{\"id\":\"sha2 0.10.8\",\"target\":\"sha2\"},{\"id\":\"shared-buffer 0.1.4\",\"target\":\"shared_buffer\"},{\"id\":\"tempfile 3.12.0\",\"target\":\"tempfile\"},{\"id\":\"thiserror 1.0.69\",\"target\":\"thiserror\"},{\"id\":\"tokio 1.44.2\",\"target\":\"tokio\"},{\"id\":\"tokio-stream 0.1.15\",\"target\":\"tokio_stream\"},{\"id\":\"toml 0.8.14\",\"target\":\"toml\"},{\"id\":\"tracing 0.1.41\",\"target\":\"tracing\"},{\"id\":\"url 2.5.4\",\"target\":\"url\"},{\"id\":\"urlencoding 2.1.3\",\"target\":\"urlencoding\"},{\"id\":\"virtual-fs 0.601.0\",\"target\":\"virtual_fs\"},{\"id\":\"virtual-mio 0.601.0\",\"target\":\"virtual_mio\"},{\"id\":\"virtual-net 0.601.0\",\"target\":\"virtual_net\"},{\"id\":\"waker-fn 1.1.1\",\"target\":\"waker_fn\"},{\"id\":\"wasm-bindgen 0.2.101\",\"target\":\"wasm_bindgen\"},{\"id\":\"wasm-bindgen-futures 0.4.51\",\"target\":\"wasm_bindgen_futures\"},{\"id\":\"wasm-encoder 0.235.0\",\"target\":\"wasm_encoder\"},{\"id\":\"wasmer 6.1.0\",\"target\":\"wasmer\"},{\"id\":\"wasmer-config 0.601.0\",\"target\":\"wasmer_config\"},{\"id\":\"wasmer-journal 0.601.0\",\"target\":\"wasmer_journal\"},{\"id\":\"wasmer-package 0.601.0\",\"target\":\"wasmer_package\"},{\"id\":\"wasmer-types 6.1.0\",\"target\":\"wasmer_types\"},{\"id\":\"wasmer-wasix-types 0.601.0\",\"target\":\"wasmer_wasix_types\"},{\"id\":\"wasmparser 0.224.1\",\"target\":\"wasmparser\"},{\"id\":\"web-sys 0.3.78\",\"target\":\"web_sys\"},{\"id\":\"webc 10.0.1\",\"target\":\"webc\"},{\"id\":\"weezl 0.1.7\",\"target\":\"weezl\"},{\"id\":\"xxhash-rust 0.8.11\",\"target\":\"xxhash_rust\"}],\"selects\":{\"cfg(all(unix, not(target_os = \\\"ios\\\")))\":[{\"id\":\"termios 0.3.3\",\"target\":\"termios\"}],\"cfg(not(target_arch = \\\"wasm32\\\"))\":[{\"id\":\"terminal_size 0.3.0\",\"target\":\"terminal_size\"}],\"cfg(unix)\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"cfg(windows)\":[{\"id\":\"windows-sys 0.59.0\",\"target\":\"windows_sys\"}]}},\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"async-trait 0.1.88\",\"target\":\"async_trait\"},{\"id\":\"serde_derive 1.0.219\",\"target\":\"serde_derive\"}]},\"library_target_name\":\"wasmer_wasix\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer-wasix\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[\"@@//src/wasix/browser-host:patches/0002-wasmer-wasix-add-0702-compatibility-imports.patch\",\"@@//src/wasix/browser-host:patches/0009-wasmer-wasix-instantiate-main-module-async.patch\",\"@@//src/wasix/browser-host:patches/0011-wasmer-wasix-deny-single-backend-guest-spawn.patch\",\"@@//src/wasix/browser-host:patches/0013-wasmer-wasix-fast-single-backend-clock.patch\",\"@@//src/wasix/browser-host:patches/0016-wasmer-wasix-direct-single-backend-clock.patch\",\"@@//src/wasix/browser-host:patches/0020-wasmer-wasix-preserve-posix-close-durability.patch\",\"@@//src/wasix/browser-host:patches/0035-wasmer-wasix-preserve-shared-seek-offset.patch\",\"@@//src/wasix/browser-host:patches/0033-wasmer-wasix-poll-ready-asyncify-work.patch\"],\"sha256\":\"a9a804fcfbdbbfe5b2d6fb30e741e22a21e88e964dedfea9e609f13a52823bfe\",\"url\":\"https://static.crates.io/crates/wasmer-wasix/wasmer-wasix-0.601.0.crate\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_wasix\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.601.0\"},\"wasmer-wasix-types 0.601.0\":{\"common_attrs\":{\"crate_features\":[\"enable-serde\",\"serde\"],\"deps\":[{\"id\":\"anyhow 1.0.97\",\"target\":\"anyhow\"},{\"id\":\"bitflags 1.3.2\",\"target\":\"bitflags\"},{\"id\":\"byteorder 1.5.0\",\"target\":\"byteorder\"},{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"},{\"id\":\"num_enum 0.7.3\",\"target\":\"num_enum\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"},{\"id\":\"time 0.3.36\",\"target\":\"time\"},{\"id\":\"tracing 0.1.41\",\"target\":\"tracing\"},{\"id\":\"wai-bindgen-gen-core 0.2.3\",\"target\":\"wai_bindgen_gen_core\"},{\"id\":\"wai-bindgen-gen-rust 0.2.3\",\"target\":\"wai_bindgen_gen_rust\"},{\"id\":\"wai-bindgen-gen-rust-wasm 0.2.3\",\"target\":\"wai_bindgen_gen_rust_wasm\"},{\"id\":\"wai-bindgen-rust 0.2.3\",\"target\":\"wai_bindgen_rust\"},{\"id\":\"wai-parser 0.2.3\",\"target\":\"wai_parser\"},{\"id\":\"wasmer 6.1.0\",\"target\":\"wasmer\"},{\"id\":\"wasmer-types 6.1.0\",\"target\":\"wasmer_types\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"wasmer-derive 6.1.0\",\"target\":\"wasmer_derive\"}]},\"library_target_name\":\"wasmer_wasix_types\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer-wasix-types\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"sha256\":\"7d2b7dad6c826f48a972709e5950a80157cb3b6bb12c6f51778282e85dc17096\",\"url\":\"https://static.crates.io/crates/wasmer-wasix-types/0.601.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_wasix_types\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.601.0\"},\"wasmparser 0.221.3\":{\"build_script_attrs\":{},\"common_attrs\":{\"deps\":[{\"id\":\"bitflags 2.9.0\",\"target\":\"bitflags\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"wasmparser\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasmparser\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasmparser\",\"repository\":{\"Http\":{\"sha256\":\"d06bfa36ab3ac2be0dee563380147a5b81ba10dd8885d7fbbc9eb574be67d185\",\"url\":\"https://static.crates.io/crates/wasmparser/0.221.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmparser\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.221.3\"},\"wasmparser 0.224.1\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"features\",\"simd\",\"validate\"],\"deps\":[{\"id\":\"bitflags 2.9.0\",\"target\":\"bitflags\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"wasmparser\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasmparser\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasmparser\",\"repository\":{\"Http\":{\"sha256\":\"04f17a5917c2ddd3819e84c661fae0d6ba29d7b9c1f0e96c708c65a9c4188e11\",\"url\":\"https://static.crates.io/crates/wasmparser/0.224.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmparser\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.224.1\"},\"wasmparser 0.235.0\":{\"build_script_attrs\":{},\"common_attrs\":{\"deps\":[{\"id\":\"bitflags 2.9.0\",\"target\":\"bitflags\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"wasmparser\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasmparser\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasmparser\",\"repository\":{\"Http\":{\"sha256\":\"161296c618fa2d63f6ed5fffd1112937e803cb9ec71b32b01a76321555660917\",\"url\":\"https://static.crates.io/crates/wasmparser/0.235.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmparser\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.235.0\"},\"wast 221.0.3\":{\"common_attrs\":{\"crate_features\":[\"component-model\",\"wasm-module\"],\"deps\":[{\"id\":\"bumpalo 3.14.0\",\"target\":\"bumpalo\"},{\"id\":\"leb128 0.2.5\",\"target\":\"leb128\"},{\"id\":\"memchr 2.7.1\",\"target\":\"memchr\"},{\"id\":\"unicode-width 0.2.0\",\"target\":\"unicode_width\"},{\"id\":\"wasm-encoder 0.221.3\",\"target\":\"wasm_encoder\"}],\"edition\":\"2021\"},\"library_target_name\":\"wast\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wast\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wast\",\"repository\":{\"Http\":{\"sha256\":\"7e0d10d282261b825ffb3d49f46e8309e60a8b608328b6a0b0578e80f3f98e57\",\"url\":\"https://static.crates.io/crates/wast/221.0.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wast\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"221.0.3\"},\"wat 1.221.3\":{\"common_attrs\":{\"crate_features\":[\"component-model\",\"default\"],\"deps\":[{\"id\":\"wast 221.0.3\",\"target\":\"wast\"}],\"edition\":\"2021\"},\"library_target_name\":\"wat\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wat\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wat\",\"repository\":{\"Http\":{\"sha256\":\"d744e4500534bada448bf611109a6b972160f94c8e8bcbe421e7be06ea346520\",\"url\":\"https://static.crates.io/crates/wat/1.221.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wat\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.221.3\"},\"web-sys 0.3.78\":{\"common_attrs\":{\"crate_features\":{\"common\":[\"BinaryType\",\"Blob\",\"BlobPropertyBag\",\"DedicatedWorkerGlobalScope\",\"DomException\",\"ErrorEvent\",\"Event\",\"EventTarget\",\"File\",\"FileReader\",\"FileSystemDirectoryHandle\",\"FileSystemFileHandle\",\"FileSystemGetDirectoryOptions\",\"FileSystemHandle\",\"Headers\",\"MessageEvent\",\"Navigator\",\"ProgressEvent\",\"QueuingStrategy\",\"ReadableByteStreamController\",\"ReadableStream\",\"ReadableStreamDefaultController\",\"ReadableStreamDefaultReader\",\"Request\",\"RequestInit\",\"RequestMode\",\"Response\",\"StorageManager\",\"Url\",\"WebSocket\",\"Window\",\"Worker\",\"WorkerGlobalScope\",\"WorkerNavigator\",\"WorkerOptions\",\"WorkerType\",\"WritableStream\",\"WritableStreamDefaultController\",\"WritableStreamDefaultWriter\",\"console\",\"default\",\"std\"],\"selects\":{\"wasm32-unknown-unknown\":[\"AbortController\",\"AbortSignal\",\"FormData\",\"Performance\",\"PerformanceTiming\",\"ReadableStreamByobReader\",\"ReadableStreamByobRequest\",\"ReadableStreamGetReaderOptions\",\"ReadableStreamReadResult\",\"ReadableStreamReaderMode\",\"ReadableStreamType\",\"ReadableWritablePair\",\"RequestCredentials\",\"ServiceWorkerGlobalScope\",\"StreamPipeOptions\",\"TransformStream\",\"TransformStreamDefaultController\",\"Transformer\",\"UnderlyingSink\",\"UnderlyingSource\"]}},\"deps\":[{\"id\":\"js-sys 0.3.78\",\"target\":\"js_sys\"},{\"id\":\"wasm-bindgen 0.2.101\",\"target\":\"wasm_bindgen\"}],\"edition\":\"2021\"},\"library_target_name\":\"web_sys\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"web-sys\",\"package_url\":\"https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/web-sys\",\"repository\":{\"Http\":{\"sha256\":\"77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12\",\"url\":\"https://static.crates.io/crates/web-sys/0.3.78/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"web_sys\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.78\"},\"web-time 1.1.0\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\"))\":[{\"id\":\"js-sys 0.3.78\",\"target\":\"js_sys\"},{\"id\":\"wasm-bindgen 0.2.101\",\"target\":\"wasm_bindgen\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"web_time\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"web-time\",\"package_url\":\"https://github.com/daxpedda/web-time\",\"repository\":{\"Http\":{\"sha256\":\"5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb\",\"url\":\"https://static.crates.io/crates/web-time/1.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"web_time\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.0\"},\"webc 10.0.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"v1\",\"v2\",\"v3\"],\"deps\":[{\"id\":\"anyhow 1.0.97\",\"target\":\"anyhow\"},{\"id\":\"base64 0.22.1\",\"target\":\"base64\"},{\"id\":\"bytes 1.10.1\",\"target\":\"bytes\"},{\"id\":\"cfg-if 1.0.0\",\"target\":\"cfg_if\"},{\"id\":\"ciborium 0.2.2\",\"target\":\"ciborium\"},{\"id\":\"ignore 0.4.22\",\"target\":\"ignore\"},{\"id\":\"indexmap 2.9.0\",\"target\":\"indexmap\"},{\"id\":\"leb128 0.2.5\",\"target\":\"leb128\"},{\"id\":\"lexical-sort 0.3.1\",\"target\":\"lexical_sort\"},{\"id\":\"libc 0.2.171\",\"target\":\"libc\"},{\"id\":\"once_cell 1.19.0\",\"target\":\"once_cell\"},{\"id\":\"path-clean 1.0.1\",\"target\":\"path_clean\"},{\"id\":\"rand 0.8.5\",\"target\":\"rand\"},{\"id\":\"serde 1.0.219\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.140\",\"target\":\"serde_json\"},{\"id\":\"sha2 0.10.8\",\"target\":\"sha2\"},{\"id\":\"shared-buffer 0.1.4\",\"target\":\"shared_buffer\"},{\"id\":\"thiserror 1.0.69\",\"target\":\"thiserror\"},{\"id\":\"url 2.5.4\",\"target\":\"url\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"document-features 0.2.8\",\"target\":\"document_features\"}]},\"library_target_name\":\"webc\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"webc\",\"package_url\":\"https://github.com/wasmerio/pirita\",\"repository\":{\"Http\":{\"sha256\":\"637506ca3c48eae3301e97f0167aa1b46cdfdd479d008b868a19715182e48ae3\",\"url\":\"https://static.crates.io/crates/webc/10.0.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"webc\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"10.0.1\"},\"weezl 0.1.7\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"weezl\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"weezl\",\"package_url\":\"https://github.com/image-rs/lzw.git\",\"repository\":{\"Http\":{\"sha256\":\"9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb\",\"url\":\"https://static.crates.io/crates/weezl/0.1.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"weezl\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.7\"},\"winapi 0.3.9\":{\"build_script_attrs\":{},\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"i686-pc-windows-gnu\":[{\"id\":\"winapi-i686-pc-windows-gnu 0.4.0\",\"target\":\"winapi_i686_pc_windows_gnu\"}],\"x86_64-pc-windows-gnu\":[{\"id\":\"winapi-x86_64-pc-windows-gnu 0.4.0\",\"target\":\"winapi_x86_64_pc_windows_gnu\"}]}},\"edition\":\"2015\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"winapi\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"winapi\",\"package_url\":\"https://github.com/retep998/winapi-rs\",\"repository\":{\"Http\":{\"sha256\":\"5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419\",\"url\":\"https://static.crates.io/crates/winapi/0.3.9/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"winapi\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.3.9\"},\"winapi-i686-pc-windows-gnu 0.4.0\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2015\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"winapi_i686_pc_windows_gnu\",\"license\":\"MIT/Apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"winapi-i686-pc-windows-gnu\",\"package_url\":\"https://github.com/retep998/winapi-rs\",\"repository\":{\"Http\":{\"sha256\":\"ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6\",\"url\":\"https://static.crates.io/crates/winapi-i686-pc-windows-gnu/0.4.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"winapi_i686_pc_windows_gnu\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.4.0\"},\"winapi-util 0.1.6\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(windows)\":[{\"id\":\"winapi 0.3.9\",\"target\":\"winapi\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"winapi_util\",\"license\":\"Unlicense/MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"winapi-util\",\"package_url\":\"https://github.com/BurntSushi/winapi-util\",\"repository\":{\"Http\":{\"sha256\":\"f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596\",\"url\":\"https://static.crates.io/crates/winapi-util/0.1.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"winapi_util\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.6\"},\"winapi-x86_64-pc-windows-gnu 0.4.0\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2015\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"winapi_x86_64_pc_windows_gnu\",\"license\":\"MIT/Apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"winapi-x86_64-pc-windows-gnu\",\"package_url\":\"https://github.com/retep998/winapi-rs\",\"repository\":{\"Http\":{\"sha256\":\"712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f\",\"url\":\"https://static.crates.io/crates/winapi-x86_64-pc-windows-gnu/0.4.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"winapi_x86_64_pc_windows_gnu\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.4.0\"},\"windows-core 0.52.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"windows-targets 0.52.6\",\"target\":\"windows_targets\"}],\"edition\":\"2021\"},\"library_target_name\":\"windows_core\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows-core\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9\",\"url\":\"https://static.crates.io/crates/windows-core/0.52.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.52.0\"},\"windows-link 0.1.1\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"windows_link\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows-link\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38\",\"url\":\"https://static.crates.io/crates/windows-link/0.1.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_link\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.1\"},\"windows-registry 0.2.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"windows-result 0.2.0\",\"target\":\"windows_result\"},{\"id\":\"windows-strings 0.1.0\",\"target\":\"windows_strings\"},{\"id\":\"windows-targets 0.52.6\",\"target\":\"windows_targets\"}],\"edition\":\"2021\"},\"library_target_name\":\"windows_registry\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows-registry\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0\",\"url\":\"https://static.crates.io/crates/windows-registry/0.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_registry\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.0\"},\"windows-result 0.2.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"windows-targets 0.52.6\",\"target\":\"windows_targets\"}],\"edition\":\"2021\"},\"library_target_name\":\"windows_result\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows-result\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e\",\"url\":\"https://static.crates.io/crates/windows-result/0.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_result\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.0\"},\"windows-strings 0.1.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"windows-result 0.2.0\",\"target\":\"windows_result\"},{\"id\":\"windows-targets 0.52.6\",\"target\":\"windows_targets\"}],\"edition\":\"2021\"},\"library_target_name\":\"windows_strings\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows-strings\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10\",\"url\":\"https://static.crates.io/crates/windows-strings/0.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_strings\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.0\"},\"windows-sys 0.48.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"windows-targets 0.48.5\",\"target\":\"windows_targets\"}],\"edition\":\"2018\"},\"library_target_name\":\"windows_sys\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows-sys\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9\",\"url\":\"https://static.crates.io/crates/windows-sys/0.48.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_sys\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.48.0\"},\"windows-sys 0.52.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"windows-targets 0.52.6\",\"target\":\"windows_targets\"}],\"edition\":\"2021\"},\"library_target_name\":\"windows_sys\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows-sys\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d\",\"url\":\"https://static.crates.io/crates/windows-sys/0.52.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_sys\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.52.0\"},\"windows-sys 0.59.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"windows-targets 0.52.6\",\"target\":\"windows_targets\"}],\"edition\":\"2021\"},\"library_target_name\":\"windows_sys\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows-sys\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b\",\"url\":\"https://static.crates.io/crates/windows-sys/0.59.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_sys\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.59.0\"},\"windows-targets 0.48.5\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"aarch64-pc-windows-gnullvm\":[{\"id\":\"windows_aarch64_gnullvm 0.48.5\",\"target\":\"windows_aarch64_gnullvm\"}],\"cfg(all(target_arch = \\\"aarch64\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\":[{\"id\":\"windows_aarch64_msvc 0.48.5\",\"target\":\"windows_aarch64_msvc\"}],\"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"gnu\\\", not(windows_raw_dylib)))\":[{\"id\":\"windows_i686_gnu 0.48.5\",\"target\":\"windows_i686_gnu\"}],\"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\":[{\"id\":\"windows_i686_msvc 0.48.5\",\"target\":\"windows_i686_msvc\"}],\"cfg(all(target_arch = \\\"x86_64\\\", target_env = \\\"gnu\\\", not(target_abi = \\\"llvm\\\"), not(windows_raw_dylib)))\":[{\"id\":\"windows_x86_64_gnu 0.48.5\",\"target\":\"windows_x86_64_gnu\"}],\"cfg(all(target_arch = \\\"x86_64\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\":[{\"id\":\"windows_x86_64_msvc 0.48.5\",\"target\":\"windows_x86_64_msvc\"}],\"x86_64-pc-windows-gnullvm\":[{\"id\":\"windows_x86_64_gnullvm 0.48.5\",\"target\":\"windows_x86_64_gnullvm\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"windows_targets\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows-targets\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c\",\"url\":\"https://static.crates.io/crates/windows-targets/0.48.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_targets\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.48.5\"},\"windows-targets 0.52.6\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"aarch64-pc-windows-gnullvm\":[{\"id\":\"windows_aarch64_gnullvm 0.52.6\",\"target\":\"windows_aarch64_gnullvm\"}],\"cfg(all(any(target_arch = \\\"x86_64\\\", target_arch = \\\"arm64ec\\\"), target_env = \\\"msvc\\\", not(windows_raw_dylib)))\":[{\"id\":\"windows_x86_64_msvc 0.52.6\",\"target\":\"windows_x86_64_msvc\"}],\"cfg(all(target_arch = \\\"aarch64\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\":[{\"id\":\"windows_aarch64_msvc 0.52.6\",\"target\":\"windows_aarch64_msvc\"}],\"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"gnu\\\", not(target_abi = \\\"llvm\\\"), not(windows_raw_dylib)))\":[{\"id\":\"windows_i686_gnu 0.52.6\",\"target\":\"windows_i686_gnu\"}],\"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\":[{\"id\":\"windows_i686_msvc 0.52.6\",\"target\":\"windows_i686_msvc\"}],\"cfg(all(target_arch = \\\"x86_64\\\", target_env = \\\"gnu\\\", not(target_abi = \\\"llvm\\\"), not(windows_raw_dylib)))\":[{\"id\":\"windows_x86_64_gnu 0.52.6\",\"target\":\"windows_x86_64_gnu\"}],\"i686-pc-windows-gnullvm\":[{\"id\":\"windows_i686_gnullvm 0.52.6\",\"target\":\"windows_i686_gnullvm\"}],\"x86_64-pc-windows-gnullvm\":[{\"id\":\"windows_x86_64_gnullvm 0.52.6\",\"target\":\"windows_x86_64_gnullvm\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"windows_targets\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows-targets\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973\",\"url\":\"https://static.crates.io/crates/windows-targets/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_targets\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.52.6\"},\"windows_aarch64_gnullvm 0.48.5\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_aarch64_gnullvm\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_aarch64_gnullvm\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8\",\"url\":\"https://static.crates.io/crates/windows_aarch64_gnullvm/0.48.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_aarch64_gnullvm\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.48.5\"},\"windows_aarch64_gnullvm 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_aarch64_gnullvm\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_aarch64_gnullvm\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3\",\"url\":\"https://static.crates.io/crates/windows_aarch64_gnullvm/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_aarch64_gnullvm\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"windows_aarch64_msvc 0.48.5\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_aarch64_msvc\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_aarch64_msvc\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc\",\"url\":\"https://static.crates.io/crates/windows_aarch64_msvc/0.48.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_aarch64_msvc\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.48.5\"},\"windows_aarch64_msvc 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_aarch64_msvc\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_aarch64_msvc\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469\",\"url\":\"https://static.crates.io/crates/windows_aarch64_msvc/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_aarch64_msvc\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"windows_i686_gnu 0.48.5\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_i686_gnu\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_i686_gnu\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e\",\"url\":\"https://static.crates.io/crates/windows_i686_gnu/0.48.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_i686_gnu\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.48.5\"},\"windows_i686_gnu 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_i686_gnu\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_i686_gnu\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b\",\"url\":\"https://static.crates.io/crates/windows_i686_gnu/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_i686_gnu\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"windows_i686_gnullvm 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_i686_gnullvm\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_i686_gnullvm\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66\",\"url\":\"https://static.crates.io/crates/windows_i686_gnullvm/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_i686_gnullvm\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"windows_i686_msvc 0.48.5\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_i686_msvc\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_i686_msvc\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406\",\"url\":\"https://static.crates.io/crates/windows_i686_msvc/0.48.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_i686_msvc\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.48.5\"},\"windows_i686_msvc 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_i686_msvc\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_i686_msvc\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66\",\"url\":\"https://static.crates.io/crates/windows_i686_msvc/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_i686_msvc\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"windows_x86_64_gnu 0.48.5\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_x86_64_gnu\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_x86_64_gnu\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e\",\"url\":\"https://static.crates.io/crates/windows_x86_64_gnu/0.48.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_x86_64_gnu\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.48.5\"},\"windows_x86_64_gnu 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_x86_64_gnu\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_x86_64_gnu\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78\",\"url\":\"https://static.crates.io/crates/windows_x86_64_gnu/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_x86_64_gnu\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"windows_x86_64_gnullvm 0.48.5\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_x86_64_gnullvm\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_x86_64_gnullvm\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc\",\"url\":\"https://static.crates.io/crates/windows_x86_64_gnullvm/0.48.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_x86_64_gnullvm\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.48.5\"},\"windows_x86_64_gnullvm 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_x86_64_gnullvm\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_x86_64_gnullvm\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d\",\"url\":\"https://static.crates.io/crates/windows_x86_64_gnullvm/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_x86_64_gnullvm\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"windows_x86_64_msvc 0.48.5\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_x86_64_msvc\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_x86_64_msvc\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538\",\"url\":\"https://static.crates.io/crates/windows_x86_64_msvc/0.48.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_x86_64_msvc\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.48.5\"},\"windows_x86_64_msvc 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_x86_64_msvc\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_x86_64_msvc\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec\",\"url\":\"https://static.crates.io/crates/windows_x86_64_msvc/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_x86_64_msvc\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"winnow 0.5.33\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"winnow\",\"license\":\"MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\"],\"name\":\"winnow\",\"package_url\":\"https://github.com/winnow-rs/winnow\",\"repository\":{\"Http\":{\"sha256\":\"b7520bbdec7211caa7c4e682eb1fbe07abe20cee6756b6e00f537c82c11816aa\",\"url\":\"https://static.crates.io/crates/winnow/0.5.33/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"winnow\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.33\"},\"winnow 0.6.13\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"winnow\",\"license\":\"MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\"],\"name\":\"winnow\",\"package_url\":\"https://github.com/winnow-rs/winnow\",\"repository\":{\"Http\":{\"sha256\":\"59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1\",\"url\":\"https://static.crates.io/crates/winnow/0.6.13/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"winnow\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.13\"},\"write16 1.0.0\":{\"common_attrs\":{\"crate_features\":[\"alloc\"],\"edition\":\"2021\"},\"library_target_name\":\"write16\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"write16\",\"package_url\":\"https://github.com/hsivonen/write16\",\"repository\":{\"Http\":{\"sha256\":\"d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936\",\"url\":\"https://static.crates.io/crates/write16/1.0.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"write16\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.0\"},\"writeable 0.5.5\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"writeable\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"writeable\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51\",\"url\":\"https://static.crates.io/crates/writeable/0.5.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"writeable\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.5\"},\"xattr 1.2.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"unsupported\"],\"deps\":{\"common\":[{\"id\":\"rustix 0.38.34\",\"target\":\"rustix\"}],\"selects\":{\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"freebsd\\\", target_os = \\\"netbsd\\\"))\":[{\"id\":\"libc 0.2.171\",\"target\":\"libc\"}],\"cfg(target_os = \\\"linux\\\")\":[{\"id\":\"linux-raw-sys 0.4.12\",\"target\":\"linux_raw_sys\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"xattr\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"xattr\",\"package_url\":\"https://github.com/Stebalien/xattr\",\"repository\":{\"Http\":{\"sha256\":\"914566e6413e7fa959cc394fb30e563ba80f3541fbd40816d4c05a0fc3f2a0f1\",\"url\":\"https://static.crates.io/crates/xattr/1.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"xattr\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.0\"},\"xxhash-rust 0.8.11\":{\"common_attrs\":{\"crate_features\":[\"xxh64\"],\"edition\":\"2018\"},\"library_target_name\":\"xxhash_rust\",\"license\":\"BSL-1.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"BSL-1.0\"],\"name\":\"xxhash-rust\",\"package_url\":\"https://github.com/DoumanAsh/xxhash-rust\",\"repository\":{\"Http\":{\"sha256\":\"63658493314859b4dfdf3fb8c1defd61587839def09582db50b8a4e93afca6bb\",\"url\":\"https://static.crates.io/crates/xxhash-rust/0.8.11/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"xxhash_rust\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.11\"},\"yansi 1.0.1\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"yansi\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"yansi\",\"package_url\":\"https://github.com/SergioBenitez/yansi\",\"repository\":{\"Http\":{\"sha256\":\"cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049\",\"url\":\"https://static.crates.io/crates/yansi/1.0.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"yansi\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.1\"},\"yoke 0.7.5\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"derive\",\"zerofrom\"],\"deps\":[{\"id\":\"stable_deref_trait 1.2.0\",\"target\":\"stable_deref_trait\"},{\"id\":\"zerofrom 0.1.6\",\"target\":\"zerofrom\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"yoke-derive 0.7.5\",\"target\":\"yoke_derive\"}]},\"library_target_name\":\"yoke\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"yoke\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40\",\"url\":\"https://static.crates.io/crates/yoke/0.7.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"yoke\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.5\"},\"yoke-derive 0.7.5\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"},{\"id\":\"synstructure 0.13.1\",\"target\":\"synstructure\"}],\"edition\":\"2021\"},\"library_target_name\":\"yoke_derive\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"yoke-derive\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154\",\"url\":\"https://static.crates.io/crates/yoke-derive/0.7.5/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"yoke_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.5\"},\"zerocopy 0.7.35\":{\"common_attrs\":{\"crate_features\":[\"simd\"],\"edition\":\"2018\",\"proc_macro_deps\":{\"common\":[],\"selects\":{\"cfg(any())\":[{\"id\":\"zerocopy-derive 0.7.35\",\"target\":\"zerocopy_derive\"}]}}},\"library_target_name\":\"zerocopy\",\"license\":\"BSD-2-Clause OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"BSD-2-Clause\",\"MIT\"],\"name\":\"zerocopy\",\"package_url\":\"https://github.com/google/zerocopy\",\"repository\":{\"Http\":{\"sha256\":\"1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0\",\"url\":\"https://static.crates.io/crates/zerocopy/0.7.35/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"zerocopy\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.35\"},\"zerocopy 0.8.24\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":{\"common\":[],\"selects\":{\"cfg(any())\":[{\"id\":\"zerocopy-derive 0.8.24\",\"target\":\"zerocopy_derive\"}]}}},\"library_target_name\":\"zerocopy\",\"license\":\"BSD-2-Clause OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"BSD-2-Clause\",\"MIT\"],\"name\":\"zerocopy\",\"package_url\":\"https://github.com/google/zerocopy\",\"repository\":{\"Http\":{\"sha256\":\"2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879\",\"url\":\"https://static.crates.io/crates/zerocopy/0.8.24/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"zerocopy\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.8.24\"},\"zerocopy-derive 0.7.35\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2018\"},\"library_target_name\":\"zerocopy_derive\",\"license\":\"BSD-2-Clause OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"BSD-2-Clause\",\"MIT\"],\"name\":\"zerocopy-derive\",\"package_url\":\"https://github.com/google/zerocopy\",\"repository\":{\"Http\":{\"sha256\":\"fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e\",\"url\":\"https://static.crates.io/crates/zerocopy-derive/0.7.35/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"zerocopy_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.35\"},\"zerocopy-derive 0.8.24\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"zerocopy_derive\",\"license\":\"BSD-2-Clause OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"BSD-2-Clause\",\"MIT\"],\"name\":\"zerocopy-derive\",\"package_url\":\"https://github.com/google/zerocopy\",\"repository\":{\"Http\":{\"sha256\":\"a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be\",\"url\":\"https://static.crates.io/crates/zerocopy-derive/0.8.24/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"zerocopy_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.24\"},\"zerofrom 0.1.6\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"derive\"],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"zerofrom-derive 0.1.6\",\"target\":\"zerofrom_derive\"}]},\"library_target_name\":\"zerofrom\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"zerofrom\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5\",\"url\":\"https://static.crates.io/crates/zerofrom/0.1.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"zerofrom\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.6\"},\"zerofrom-derive 0.1.6\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"},{\"id\":\"synstructure 0.13.1\",\"target\":\"synstructure\"}],\"edition\":\"2021\"},\"library_target_name\":\"zerofrom_derive\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"zerofrom-derive\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502\",\"url\":\"https://static.crates.io/crates/zerofrom-derive/0.1.6/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"zerofrom_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.6\"},\"zeroize 1.8.1\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"zeroize\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"zeroize\",\"package_url\":\"https://github.com/RustCrypto/utils/tree/master/zeroize\",\"repository\":{\"Http\":{\"sha256\":\"ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde\",\"url\":\"https://static.crates.io/crates/zeroize/1.8.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"zeroize\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.8.1\"},\"zerovec 0.10.4\":{\"common_attrs\":{\"crate_features\":[\"derive\",\"yoke\"],\"deps\":[{\"id\":\"yoke 0.7.5\",\"target\":\"yoke\"},{\"id\":\"zerofrom 0.1.6\",\"target\":\"zerofrom\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"zerovec-derive 0.10.3\",\"target\":\"zerovec_derive\"}]},\"library_target_name\":\"zerovec\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"zerovec\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079\",\"url\":\"https://static.crates.io/crates/zerovec/0.10.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"zerovec\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.10.4\"},\"zerovec-derive 0.10.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.94\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.35\",\"target\":\"quote\"},{\"id\":\"syn 2.0.100\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"zerovec_derive\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"zerovec-derive\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6\",\"url\":\"https://static.crates.io/crates/zerovec-derive/0.10.3/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"zerovec_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.10.3\"}},\"direct_deps\":[\"anyhow 1.0.97\",\"async-trait 0.1.88\",\"bincode 1.3.3\",\"bytes 1.10.1\",\"console_error_panic_hook 0.1.7\",\"derivative 2.2.0\",\"futures 0.3.30\",\"instant 0.1.12\",\"js-sys 0.3.78\",\"lazy_static 1.5.0\",\"once_cell 1.19.0\",\"reqwest 0.12.7\",\"serde 1.0.219\",\"serde-wasm-bindgen 0.6.5\",\"sha2 0.10.8\",\"tempfile 3.12.0\",\"tokio 1.44.2\",\"toml 0.8.14\",\"tracing 0.1.41\",\"tracing-subscriber 0.3.18\",\"url 2.5.4\",\"virtual-fs 0.601.0\",\"virtual-net 0.601.0\",\"wasm-bindgen 0.2.101\",\"wasm-bindgen-derive 0.2.1\",\"wasm-bindgen-futures 0.4.51\",\"wasm-bindgen-test 0.3.51\",\"wasmer 6.1.0\",\"wasmer-backend-api 0.601.0\",\"wasmer-config 0.601.0\",\"wasmer-package 0.601.0\",\"wasmer-types 6.1.0\",\"wasmer-wasix 0.601.0\",\"web-sys 0.3.78\",\"webc 10.0.1\"],\"direct_dev_deps\":[],\"workspace_members\":{\"wasmer-js 0.0.0\":\"wasmer-js\"}}", + "anyhow-1.0.97/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"anyhow-1.0.97\",\n actual = \"@browser_cargo__anyhow-1.0.97//:anyhow\",\n tags = [\"manual\"],\n)\n", + "anyhow/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"anyhow\",\n actual = \"@browser_cargo__anyhow-1.0.97//:anyhow\",\n tags = [\"manual\"],\n)\n", + "async-trait-0.1.88/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"async-trait-0.1.88\",\n actual = \"@browser_cargo__async-trait-0.1.88//:async_trait\",\n tags = [\"manual\"],\n)\n", + "async-trait/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"async-trait\",\n actual = \"@browser_cargo__async-trait-0.1.88//:async_trait\",\n tags = [\"manual\"],\n)\n", + "bincode-1.3.3/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"bincode-1.3.3\",\n actual = \"@browser_cargo__bincode-1.3.3//:bincode\",\n tags = [\"manual\"],\n)\n", + "bincode/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"bincode\",\n actual = \"@browser_cargo__bincode-1.3.3//:bincode\",\n tags = [\"manual\"],\n)\n", + "bytes-1.10.1/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"bytes-1.10.1\",\n actual = \"@browser_cargo__bytes-1.10.1//:bytes\",\n tags = [\"manual\"],\n)\n", + "bytes/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"bytes\",\n actual = \"@browser_cargo__bytes-1.10.1//:bytes\",\n tags = [\"manual\"],\n)\n", + "console_error_panic_hook-0.1.7/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"console_error_panic_hook-0.1.7\",\n actual = \"@browser_cargo__console_error_panic_hook-0.1.7//:console_error_panic_hook\",\n tags = [\"manual\"],\n)\n", + "console_error_panic_hook/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"console_error_panic_hook\",\n actual = \"@browser_cargo__console_error_panic_hook-0.1.7//:console_error_panic_hook\",\n tags = [\"manual\"],\n)\n", + "derivative-2.2.0/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"derivative-2.2.0\",\n actual = \"@browser_cargo__derivative-2.2.0//:derivative\",\n tags = [\"manual\"],\n)\n", + "derivative/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"derivative\",\n actual = \"@browser_cargo__derivative-2.2.0//:derivative\",\n tags = [\"manual\"],\n)\n", + "futures-0.3.30/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"futures-0.3.30\",\n actual = \"@browser_cargo__futures-0.3.30//:futures\",\n tags = [\"manual\"],\n)\n", + "futures/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"futures\",\n actual = \"@browser_cargo__futures-0.3.30//:futures\",\n tags = [\"manual\"],\n)\n", + "instant-0.1.12/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"instant-0.1.12\",\n actual = \"@browser_cargo__instant-0.1.12//:instant\",\n tags = [\"manual\"],\n)\n", + "instant/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"instant\",\n actual = \"@browser_cargo__instant-0.1.12//:instant\",\n tags = [\"manual\"],\n)\n", + "js-sys-0.3.78/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"js-sys-0.3.78\",\n actual = \"@browser_cargo__js-sys-0.3.78//:js_sys\",\n tags = [\"manual\"],\n)\n", + "js-sys/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"js-sys\",\n actual = \"@browser_cargo__js-sys-0.3.78//:js_sys\",\n tags = [\"manual\"],\n)\n", + "lazy_static-1.5.0/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"lazy_static-1.5.0\",\n actual = \"@browser_cargo__lazy_static-1.5.0//:lazy_static\",\n tags = [\"manual\"],\n)\n", + "lazy_static/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"lazy_static\",\n actual = \"@browser_cargo__lazy_static-1.5.0//:lazy_static\",\n tags = [\"manual\"],\n)\n", + "once_cell-1.19.0/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"once_cell-1.19.0\",\n actual = \"@browser_cargo__once_cell-1.19.0//:once_cell\",\n tags = [\"manual\"],\n)\n", + "once_cell/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"once_cell\",\n actual = \"@browser_cargo__once_cell-1.19.0//:once_cell\",\n tags = [\"manual\"],\n)\n", + "reqwest-0.12.7/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"reqwest-0.12.7\",\n actual = \"@browser_cargo__reqwest-0.12.7//:reqwest\",\n tags = [\"manual\"],\n)\n", + "reqwest/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"reqwest\",\n actual = \"@browser_cargo__reqwest-0.12.7//:reqwest\",\n tags = [\"manual\"],\n)\n", + "serde-1.0.219/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"serde-1.0.219\",\n actual = \"@browser_cargo__serde-1.0.219//:serde\",\n tags = [\"manual\"],\n)\n", + "serde/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"serde\",\n actual = \"@browser_cargo__serde-1.0.219//:serde\",\n tags = [\"manual\"],\n)\n", + "serde-wasm-bindgen-0.6.5/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"serde-wasm-bindgen-0.6.5\",\n actual = \"@browser_cargo__serde-wasm-bindgen-0.6.5//:serde_wasm_bindgen\",\n tags = [\"manual\"],\n)\n", + "serde-wasm-bindgen/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"serde-wasm-bindgen\",\n actual = \"@browser_cargo__serde-wasm-bindgen-0.6.5//:serde_wasm_bindgen\",\n tags = [\"manual\"],\n)\n", + "sha2-0.10.8/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"sha2-0.10.8\",\n actual = \"@browser_cargo__sha2-0.10.8//:sha2\",\n tags = [\"manual\"],\n)\n", + "sha2/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"sha2\",\n actual = \"@browser_cargo__sha2-0.10.8//:sha2\",\n tags = [\"manual\"],\n)\n", + "tempfile-3.12.0/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"tempfile-3.12.0\",\n actual = \"@browser_cargo__tempfile-3.12.0//:tempfile\",\n tags = [\"manual\"],\n)\n", + "tempfile/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"tempfile\",\n actual = \"@browser_cargo__tempfile-3.12.0//:tempfile\",\n tags = [\"manual\"],\n)\n", + "tokio-1.44.2/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"tokio-1.44.2\",\n actual = \"@browser_cargo__tokio-1.44.2//:tokio\",\n tags = [\"manual\"],\n)\n", + "tokio/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"tokio\",\n actual = \"@browser_cargo__tokio-1.44.2//:tokio\",\n tags = [\"manual\"],\n)\n", + "toml-0.8.14/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"toml-0.8.14\",\n actual = \"@browser_cargo__toml-0.8.14//:toml\",\n tags = [\"manual\"],\n)\n", + "toml/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"toml\",\n actual = \"@browser_cargo__toml-0.8.14//:toml\",\n tags = [\"manual\"],\n)\n", + "tracing-0.1.41/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"tracing-0.1.41\",\n actual = \"@browser_cargo__tracing-0.1.41//:tracing\",\n tags = [\"manual\"],\n)\n", + "tracing/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"tracing\",\n actual = \"@browser_cargo__tracing-0.1.41//:tracing\",\n tags = [\"manual\"],\n)\n", + "tracing-subscriber-0.3.18/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"tracing-subscriber-0.3.18\",\n actual = \"@browser_cargo__tracing-subscriber-0.3.18//:tracing_subscriber\",\n tags = [\"manual\"],\n)\n", + "tracing-subscriber/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"tracing-subscriber\",\n actual = \"@browser_cargo__tracing-subscriber-0.3.18//:tracing_subscriber\",\n tags = [\"manual\"],\n)\n", + "url-2.5.4/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"url-2.5.4\",\n actual = \"@browser_cargo__url-2.5.4//:url\",\n tags = [\"manual\"],\n)\n", + "url/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"url\",\n actual = \"@browser_cargo__url-2.5.4//:url\",\n tags = [\"manual\"],\n)\n", + "virtual-fs-0.601.0/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"virtual-fs-0.601.0\",\n actual = \"@browser_cargo__virtual-fs-0.601.0//:virtual_fs\",\n tags = [\"manual\"],\n)\n", + "virtual-fs/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"virtual-fs\",\n actual = \"@browser_cargo__virtual-fs-0.601.0//:virtual_fs\",\n tags = [\"manual\"],\n)\n", + "virtual-net-0.601.0/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"virtual-net-0.601.0\",\n actual = \"@browser_cargo__virtual-net-0.601.0//:virtual_net\",\n tags = [\"manual\"],\n)\n", + "virtual-net/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"virtual-net\",\n actual = \"@browser_cargo__virtual-net-0.601.0//:virtual_net\",\n tags = [\"manual\"],\n)\n", + "wasm-bindgen-0.2.101/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasm-bindgen-0.2.101\",\n actual = \"@browser_cargo__wasm-bindgen-0.2.101//:wasm_bindgen\",\n tags = [\"manual\"],\n)\n", + "wasm-bindgen/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasm-bindgen\",\n actual = \"@browser_cargo__wasm-bindgen-0.2.101//:wasm_bindgen\",\n tags = [\"manual\"],\n)\n", + "wasm-bindgen-derive-0.2.1/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasm-bindgen-derive-0.2.1\",\n actual = \"@browser_cargo__wasm-bindgen-derive-0.2.1//:wasm_bindgen_derive\",\n tags = [\"manual\"],\n)\n", + "wasm-bindgen-derive/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasm-bindgen-derive\",\n actual = \"@browser_cargo__wasm-bindgen-derive-0.2.1//:wasm_bindgen_derive\",\n tags = [\"manual\"],\n)\n", + "wasm-bindgen-futures-0.4.51/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasm-bindgen-futures-0.4.51\",\n actual = \"@browser_cargo__wasm-bindgen-futures-0.4.51//:wasm_bindgen_futures\",\n tags = [\"manual\"],\n)\n", + "wasm-bindgen-futures/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasm-bindgen-futures\",\n actual = \"@browser_cargo__wasm-bindgen-futures-0.4.51//:wasm_bindgen_futures\",\n tags = [\"manual\"],\n)\n", + "wasm-bindgen-test-0.3.51/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasm-bindgen-test-0.3.51\",\n actual = \"@browser_cargo__wasm-bindgen-test-0.3.51//:wasm_bindgen_test\",\n tags = [\"manual\"],\n)\n", + "wasm-bindgen-test/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasm-bindgen-test\",\n actual = \"@browser_cargo__wasm-bindgen-test-0.3.51//:wasm_bindgen_test\",\n tags = [\"manual\"],\n)\n", + "wasmer-6.1.0/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-6.1.0\",\n actual = \"@browser_cargo__wasmer-6.1.0//:wasmer\",\n tags = [\"manual\"],\n)\n", + "wasmer/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer\",\n actual = \"@browser_cargo__wasmer-6.1.0//:wasmer\",\n tags = [\"manual\"],\n)\n", + "wasmer-backend-api-0.601.0/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-backend-api-0.601.0\",\n actual = \"@browser_cargo__wasmer-backend-api-0.601.0//:wasmer_backend_api\",\n tags = [\"manual\"],\n)\n", + "wasmer-backend-api/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-backend-api\",\n actual = \"@browser_cargo__wasmer-backend-api-0.601.0//:wasmer_backend_api\",\n tags = [\"manual\"],\n)\n", + "wasmer-config-0.601.0/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-config-0.601.0\",\n actual = \"@browser_cargo__wasmer-config-0.601.0//:wasmer_config\",\n tags = [\"manual\"],\n)\n", + "wasmer-config/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-config\",\n actual = \"@browser_cargo__wasmer-config-0.601.0//:wasmer_config\",\n tags = [\"manual\"],\n)\n", + "wasmer-package-0.601.0/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-package-0.601.0\",\n actual = \"@browser_cargo__wasmer-package-0.601.0//:wasmer_package\",\n tags = [\"manual\"],\n)\n", + "wasmer-package/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-package\",\n actual = \"@browser_cargo__wasmer-package-0.601.0//:wasmer_package\",\n tags = [\"manual\"],\n)\n", + "wasmer-types-6.1.0/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-types-6.1.0\",\n actual = \"@browser_cargo__wasmer-types-6.1.0//:wasmer_types\",\n tags = [\"manual\"],\n)\n", + "wasmer-types/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-types\",\n actual = \"@browser_cargo__wasmer-types-6.1.0//:wasmer_types\",\n tags = [\"manual\"],\n)\n", + "wasmer-wasix-0.601.0/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-wasix-0.601.0\",\n actual = \"@browser_cargo__wasmer-wasix-0.601.0//:wasmer_wasix\",\n tags = [\"manual\"],\n)\n", + "wasmer-wasix/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-wasix\",\n actual = \"@browser_cargo__wasmer-wasix-0.601.0//:wasmer_wasix\",\n tags = [\"manual\"],\n)\n", + "web-sys-0.3.78/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"web-sys-0.3.78\",\n actual = \"@browser_cargo__web-sys-0.3.78//:web_sys\",\n tags = [\"manual\"],\n)\n", + "web-sys/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"web-sys\",\n actual = \"@browser_cargo__web-sys-0.3.78//:web_sys\",\n tags = [\"manual\"],\n)\n", + "webc-10.0.1/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"webc-10.0.1\",\n actual = \"@browser_cargo__webc-10.0.1//:webc\",\n tags = [\"manual\"],\n)\n", + "webc/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"webc\",\n actual = \"@browser_cargo__webc-10.0.1//:webc\",\n tags = [\"manual\"],\n)\n" + } + } + }, + "browser_cargo__addr2line-0.21.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/addr2line/0.21.0/download" + ], + "strip_prefix": "addr2line-0.21.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"addr2line\",\n deps = [\n \"@browser_cargo__gimli-0.28.1//:gimli\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=addr2line\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.21.0\",\n)\n" + } + }, + "browser_cargo__adler-1.0.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/adler/1.0.2/download" + ], + "strip_prefix": "adler-1.0.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"adler\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=adler\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.2\",\n)\n" + } + }, + "browser_cargo__adler2-2.0.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/adler2/2.0.0/download" + ], + "strip_prefix": "adler2-2.0.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"adler2\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=adler2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.0\",\n)\n" + } + }, + "browser_cargo__ahash-0.8.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ahash/0.8.11/download" + ], + "strip_prefix": "ahash-0.8.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ahash\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n \"@browser_cargo__zerocopy-0.7.35//:zerocopy\",\n ] + select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [\n \"@browser_cargo__once_cell-1.19.0//:once_cell\", # cfg(not(all(target_arch = \"arm\", target_os = \"none\")))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__once_cell-1.19.0//:once_cell\", # cfg(not(all(target_arch = \"arm\", target_os = \"none\")))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ahash\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.11\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@browser_cargo__version_check-0.9.5//:version_check\",\n ],\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"ahash\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ahash\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.8.11\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__aho-corasick-1.1.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/aho-corasick/1.1.2/download" + ], + "strip_prefix": "aho-corasick-1.1.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"aho_corasick\",\n deps = [\n \"@browser_cargo__memchr-2.7.1//:memchr\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"perf-literal\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=aho-corasick\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.2\",\n)\n" + } + }, + "browser_cargo__aliasable-0.1.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/aliasable/0.1.3/download" + ], + "strip_prefix": "aliasable-0.1.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"aliasable\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=aliasable\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.3\",\n)\n" + } + }, + "browser_cargo__android-tzdata-0.1.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/android-tzdata/0.1.1/download" + ], + "strip_prefix": "android-tzdata-0.1.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"android_tzdata\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=android-tzdata\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.1\",\n)\n" + } + }, + "browser_cargo__android_system_properties-0.1.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/android_system_properties/0.1.5/download" + ], + "strip_prefix": "android_system_properties-0.1.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"android_system_properties\",\n deps = [\n \"@browser_cargo__libc-0.2.171//:libc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=android_system_properties\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.5\",\n)\n" + } + }, + "browser_cargo__any_ascii-0.1.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "70033777eb8b5124a81a1889416543dddef2de240019b674c81285a2635a7e1e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/any_ascii/0.1.7/download" + ], + "strip_prefix": "any_ascii-0.1.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"any_ascii\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=any_ascii\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.7\",\n)\n" + } + }, + "browser_cargo__anyhow-1.0.97": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/anyhow/1.0.97/download" + ], + "strip_prefix": "anyhow-1.0.97", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"anyhow\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=anyhow\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.97\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"anyhow\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=anyhow\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.97\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__arrayref-0.3.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/arrayref/0.3.7/download" + ], + "strip_prefix": "arrayref-0.3.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"arrayref\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=arrayref\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.7\",\n)\n" + } + }, + "browser_cargo__arrayvec-0.7.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/arrayvec/0.7.4/download" + ], + "strip_prefix": "arrayvec-0.7.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"arrayvec\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=arrayvec\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.4\",\n)\n" + } + }, + "browser_cargo__async-trait-0.1.88": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/async-trait/0.1.88/download" + ], + "strip_prefix": "async-trait-0.1.88", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"async_trait\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=async-trait\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.88\",\n)\n" + } + }, + "browser_cargo__atomic-waker-1.1.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/atomic-waker/1.1.2/download" + ], + "strip_prefix": "atomic-waker-1.1.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"atomic_waker\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=atomic-waker\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.2\",\n)\n" + } + }, + "browser_cargo__autocfg-1.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/autocfg/1.1.0/download" + ], + "strip_prefix": "autocfg-1.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"autocfg\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=autocfg\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.0\",\n)\n" + } + }, + "browser_cargo__backtrace-0.3.69": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/backtrace/0.3.69/download" + ], + "strip_prefix": "backtrace-0.3.69", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"backtrace\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n \"@browser_cargo__rustc-demangle-0.1.23//:rustc_demangle\",\n ] + select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [\n \"@browser_cargo__addr2line-0.21.0//:addr2line\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@browser_cargo__libc-0.2.171//:libc\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@browser_cargo__miniz_oxide-0.7.1//:miniz_oxide\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@browser_cargo__object-0.32.2//:object\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__addr2line-0.21.0//:addr2line\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@browser_cargo__libc-0.2.171//:libc\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@browser_cargo__miniz_oxide-0.7.1//:miniz_oxide\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@browser_cargo__object-0.32.2//:object\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=backtrace\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.69\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@browser_cargo__cc-1.2.18//:cc\",\n ],\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"backtrace\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=backtrace\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.3.69\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__base64-0.22.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/base64/0.22.1/download" + ], + "strip_prefix": "base64-0.22.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"base64\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=base64\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.22.1\",\n)\n" + } + }, + "browser_cargo__beef-0.5.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/beef/0.5.2/download" + ], + "strip_prefix": "beef-0.5.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"beef\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=beef\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.2\",\n)\n" + } + }, + "browser_cargo__bincode-1.3.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bincode/1.3.3/download" + ], + "strip_prefix": "bincode-1.3.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bincode\",\n deps = [\n \"@browser_cargo__serde-1.0.219//:serde\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bincode\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.3.3\",\n)\n" + } + }, + "browser_cargo__bindgen-0.70.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bindgen/0.70.1/download" + ], + "strip_prefix": "bindgen-0.70.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bindgen\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__bitflags-2.9.0//:bitflags\",\n \"@browser_cargo__cexpr-0.6.0//:cexpr\",\n \"@browser_cargo__clang-sys-1.8.1//:clang_sys\",\n \"@browser_cargo__itertools-0.12.1//:itertools\",\n \"@browser_cargo__log-0.4.20//:log\",\n \"@browser_cargo__prettyplease-0.2.32//:prettyplease\",\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__regex-1.10.2//:regex\",\n \"@browser_cargo__rustc-hash-1.1.0//:rustc_hash\",\n \"@browser_cargo__shlex-1.3.0//:shlex\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"logging\",\n \"prettyplease\",\n \"runtime\",\n ],\n crate_root = \"lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bindgen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.70.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"logging\",\n \"prettyplease\",\n \"runtime\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n link_deps = [\n \"@browser_cargo__clang-sys-1.8.1//:clang_sys\",\n \"@browser_cargo__prettyplease-0.2.32//:prettyplease\",\n ],\n edition = \"2018\",\n pkg_name = \"bindgen\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bindgen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.70.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__bitflags-1.3.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bitflags/1.3.2/download" + ], + "strip_prefix": "bitflags-1.3.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bitflags\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bitflags\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.3.2\",\n)\n" + } + }, + "browser_cargo__bitflags-2.9.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bitflags/2.9.0/download" + ], + "strip_prefix": "bitflags-2.9.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bitflags\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"std\", # x86_64-unknown-linux-gnu\n ],\n \"//conditions:default\": [],\n }),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bitflags\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.9.0\",\n)\n" + } + }, + "browser_cargo__blake3-1.5.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/blake3/1.5.1/download" + ], + "strip_prefix": "blake3-1.5.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"blake3\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__arrayref-0.3.7//:arrayref\",\n \"@browser_cargo__arrayvec-0.7.4//:arrayvec\",\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n \"@browser_cargo__constant_time_eq-0.3.0//:constant_time_eq\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=blake3\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.5.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@browser_cargo__cc-1.2.18//:cc\",\n ],\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"blake3\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=blake3\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.5.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__block-buffer-0.10.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/block-buffer/0.10.4/download" + ], + "strip_prefix": "block-buffer-0.10.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"block_buffer\",\n deps = [\n \"@browser_cargo__generic-array-0.14.7//:generic_array\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=block-buffer\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.4\",\n)\n" + } + }, + "browser_cargo__bstr-1.9.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bstr/1.9.1/download" + ], + "strip_prefix": "bstr-1.9.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bstr\",\n deps = [\n \"@browser_cargo__memchr-2.7.1//:memchr\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bstr\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.9.1\",\n)\n" + } + }, + "browser_cargo__bumpalo-3.14.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bumpalo/3.14.0/download" + ], + "strip_prefix": "bumpalo-3.14.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bumpalo\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bumpalo\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"3.14.0\",\n)\n" + } + }, + "browser_cargo__bus-2.4.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4b7118d0221d84fada881b657c2ddb7cd55108db79c8764c9ee212c0c259b783", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bus/2.4.1/download" + ], + "strip_prefix": "bus-2.4.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bus\",\n deps = [\n \"@browser_cargo__crossbeam-channel-0.5.15//:crossbeam_channel\",\n \"@browser_cargo__num_cpus-1.17.0//:num_cpus\",\n \"@browser_cargo__parking_lot_core-0.9.9//:parking_lot_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bus\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.4.1\",\n)\n" + } + }, + "browser_cargo__bytecheck-0.6.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8b6372023ac861f6e6dc89c8344a8f398fb42aaba2b5dbc649ca0c0e9dbcb627", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bytecheck/0.6.11/download" + ], + "strip_prefix": "bytecheck-0.6.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bytecheck\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__ptr_meta-0.1.4//:ptr_meta\",\n \"@browser_cargo__simdutf8-0.1.4//:simdutf8\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__bytecheck_derive-0.6.11//:bytecheck_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"simdutf8\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bytecheck\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.11\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"simdutf8\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"bytecheck\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bytecheck\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.6.11\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__bytecheck-0.8.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "50690fb3370fb9fe3550372746084c46f2ac8c9685c583d2be10eefd89d3d1a3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bytecheck/0.8.1/download" + ], + "strip_prefix": "bytecheck-0.8.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bytecheck\",\n deps = [\n \"@browser_cargo__ptr_meta-0.3.0//:ptr_meta\",\n \"@browser_cargo__rancor-0.1.0//:rancor\",\n \"@browser_cargo__simdutf8-0.1.4//:simdutf8\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__bytecheck_derive-0.8.1//:bytecheck_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"simdutf8\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bytecheck\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.1\",\n)\n" + } + }, + "browser_cargo__bytecheck_derive-0.6.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a7ec4c6f261935ad534c0c22dbef2201b45918860eb1c574b972bd213a76af61", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bytecheck_derive/0.6.11/download" + ], + "strip_prefix": "bytecheck_derive-0.6.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"bytecheck_derive\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-1.0.109//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bytecheck_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.11\",\n)\n" + } + }, + "browser_cargo__bytecheck_derive-0.8.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "efb7846e0cb180355c2dec69e721edafa36919850f1a9f52ffba4ebc0393cb71", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bytecheck_derive/0.8.1/download" + ], + "strip_prefix": "bytecheck_derive-0.8.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"bytecheck_derive\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bytecheck_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.1\",\n)\n" + } + }, + "browser_cargo__byteorder-1.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/byteorder/1.5.0/download" + ], + "strip_prefix": "byteorder-1.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"byteorder\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=byteorder\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.5.0\",\n)\n" + } + }, + "browser_cargo__bytes-1.10.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bytes/1.10.1/download" + ], + "strip_prefix": "bytes-1.10.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bytes\",\n deps = [\n \"@browser_cargo__serde-1.0.219//:serde\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bytes\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.10.1\",\n)\n" + } + }, + "browser_cargo__bytesize-1.3.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bytesize/1.3.0/download" + ], + "strip_prefix": "bytesize-1.3.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bytesize\",\n deps = [\n \"@browser_cargo__serde-1.0.219//:serde\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"serde\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bytesize\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.3.0\",\n)\n" + } + }, + "browser_cargo__cc-1.2.18": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cc/1.2.18/download" + ], + "strip_prefix": "cc-1.2.18", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cc\",\n deps = [\n \"@browser_cargo__shlex-1.3.0//:shlex\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.18\",\n)\n" + } + }, + "browser_cargo__cexpr-0.6.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cexpr/0.6.0/download" + ], + "strip_prefix": "cexpr-0.6.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cexpr\",\n deps = [\n \"@browser_cargo__nom-7.1.3//:nom\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cexpr\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.0\",\n)\n" + } + }, + "browser_cargo__cfg-if-1.0.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cfg-if/1.0.0/download" + ], + "strip_prefix": "cfg-if-1.0.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cfg_if\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cfg-if\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.0\",\n)\n" + } + }, + "browser_cargo__chrono-0.4.40": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/chrono/0.4.40/download" + ], + "strip_prefix": "chrono-0.4.40", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"chrono\",\n deps = [\n \"@browser_cargo__num-traits-0.2.17//:num_traits\",\n ] + select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [\n \"@browser_cargo__js-sys-0.3.78//:js_sys\", # wasm32-unknown-unknown\n \"@browser_cargo__wasm-bindgen-0.2.101//:wasm_bindgen\", # wasm32-unknown-unknown\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__iana-time-zone-0.1.59//:iana_time_zone\", # x86_64-unknown-linux-gnu\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"android-tzdata\",\n \"clock\",\n \"iana-time-zone\",\n \"js-sys\",\n \"now\",\n \"std\",\n \"wasm-bindgen\",\n \"wasmbind\",\n \"winapi\",\n \"windows-link\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=chrono\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.40\",\n)\n" + } + }, + "browser_cargo__ciborium-0.2.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ciborium/0.2.2/download" + ], + "strip_prefix": "ciborium-0.2.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ciborium\",\n deps = [\n \"@browser_cargo__ciborium-io-0.2.2//:ciborium_io\",\n \"@browser_cargo__ciborium-ll-0.2.2//:ciborium_ll\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ciborium\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.2\",\n)\n" + } + }, + "browser_cargo__ciborium-io-0.2.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ciborium-io/0.2.2/download" + ], + "strip_prefix": "ciborium-io-0.2.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ciborium_io\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ciborium-io\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.2\",\n)\n" + } + }, + "browser_cargo__ciborium-ll-0.2.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ciborium-ll/0.2.2/download" + ], + "strip_prefix": "ciborium-ll-0.2.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ciborium_ll\",\n deps = [\n \"@browser_cargo__ciborium-io-0.2.2//:ciborium_io\",\n \"@browser_cargo__half-2.4.1//:half\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ciborium-ll\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.2\",\n)\n" + } + }, + "browser_cargo__clang-sys-1.8.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/clang-sys/1.8.1/download" + ], + "strip_prefix": "clang-sys-1.8.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"clang_sys\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__glob-0.3.2//:glob\",\n \"@browser_cargo__libc-0.2.171//:libc\",\n \"@browser_cargo__libloading-0.8.6//:libloading\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"clang_3_5\",\n \"clang_3_6\",\n \"clang_3_7\",\n \"clang_3_8\",\n \"clang_3_9\",\n \"clang_4_0\",\n \"clang_5_0\",\n \"clang_6_0\",\n \"libloading\",\n \"runtime\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=clang-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.8.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"clang_3_5\",\n \"clang_3_6\",\n \"clang_3_7\",\n \"clang_3_8\",\n \"clang_3_9\",\n \"clang_4_0\",\n \"clang_5_0\",\n \"clang_6_0\",\n \"libloading\",\n \"runtime\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@browser_cargo__glob-0.3.2//:glob\",\n ],\n emit_warnings = False,\n edition = \"2021\",\n links = \"clang\",\n pkg_name = \"clang-sys\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=clang-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.8.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__cmake-0.1.54": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cmake/0.1.54/download" + ], + "strip_prefix": "cmake-0.1.54", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cmake\",\n deps = [\n \"@browser_cargo__cc-1.2.18//:cc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cmake\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.54\",\n)\n" + } + }, + "browser_cargo__console-0.15.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/console/0.15.11/download" + ], + "strip_prefix": "console-0.15.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"console\",\n deps = [\n \"@browser_cargo__libc-0.2.171//:libc\",\n \"@browser_cargo__once_cell-1.19.0//:once_cell\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=console\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.15.11\",\n)\n" + } + }, + "browser_cargo__console_error_panic_hook-0.1.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/console_error_panic_hook/0.1.7/download" + ], + "strip_prefix": "console_error_panic_hook-0.1.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"console_error_panic_hook\",\n deps = [\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n \"@browser_cargo__wasm-bindgen-0.2.101//:wasm_bindgen\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=console_error_panic_hook\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.7\",\n)\n" + } + }, + "browser_cargo__constant_time_eq-0.3.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/constant_time_eq/0.3.0/download" + ], + "strip_prefix": "constant_time_eq-0.3.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"constant_time_eq\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=constant_time_eq\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.0\",\n)\n" + } + }, + "browser_cargo__cooked-waker-5.0.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cooked-waker/5.0.0/download" + ], + "strip_prefix": "cooked-waker-5.0.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cooked_waker\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cooked-waker\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"5.0.0\",\n)\n" + } + }, + "browser_cargo__core-foundation-0.9.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/core-foundation/0.9.4/download" + ], + "strip_prefix": "core-foundation-0.9.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"core_foundation\",\n deps = [\n \"@browser_cargo__core-foundation-sys-0.8.7//:core_foundation_sys\",\n \"@browser_cargo__libc-0.2.171//:libc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=core-foundation\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.4\",\n)\n" + } + }, + "browser_cargo__core-foundation-sys-0.8.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/core-foundation-sys/0.8.7/download" + ], + "strip_prefix": "core-foundation-sys-0.8.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"core_foundation_sys\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=core-foundation-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.7\",\n)\n" + } + }, + "browser_cargo__corosensei-0.3.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "878ba85678ef5d34ffe1b5da981b0828232b4c7f2726b20984f59c7e79f6d514", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/corosensei/0.3.0/download" + ], + "strip_prefix": "corosensei-0.3.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"corosensei\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n \"@browser_cargo__libc-0.2.171//:libc\",\n \"@browser_cargo__scopeguard-1.2.0//:scopeguard\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"default-stack\",\n \"libc\",\n \"unwind\",\n \"windows-sys\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=corosensei\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"default-stack\",\n \"libc\",\n \"unwind\",\n \"windows-sys\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@browser_cargo__autocfg-1.1.0//:autocfg\",\n ],\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"corosensei\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=corosensei\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.3.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__cpufeatures-0.2.12": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cpufeatures/0.2.12/download" + ], + "strip_prefix": "cpufeatures-0.2.12", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cpufeatures\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cpufeatures\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.12\",\n)\n" + } + }, + "browser_cargo__crc32fast-1.3.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crc32fast/1.3.2/download" + ], + "strip_prefix": "crc32fast-1.3.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crc32fast\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crc32fast\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.3.2\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2015\",\n pkg_name = \"crc32fast\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crc32fast\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.3.2\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__crossbeam-channel-0.5.15": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crossbeam-channel/0.5.15/download" + ], + "strip_prefix": "crossbeam-channel-0.5.15", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crossbeam_channel\",\n deps = [\n \"@browser_cargo__crossbeam-utils-0.8.19//:crossbeam_utils\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crossbeam-channel\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.15\",\n)\n" + } + }, + "browser_cargo__crossbeam-deque-0.8.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crossbeam-deque/0.8.5/download" + ], + "strip_prefix": "crossbeam-deque-0.8.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crossbeam_deque\",\n deps = [\n \"@browser_cargo__crossbeam-epoch-0.9.18//:crossbeam_epoch\",\n \"@browser_cargo__crossbeam-utils-0.8.19//:crossbeam_utils\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crossbeam-deque\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.5\",\n)\n" + } + }, + "browser_cargo__crossbeam-epoch-0.9.18": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crossbeam-epoch/0.9.18/download" + ], + "strip_prefix": "crossbeam-epoch-0.9.18", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crossbeam_epoch\",\n deps = [\n \"@browser_cargo__crossbeam-utils-0.8.19//:crossbeam_utils\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crossbeam-epoch\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.18\",\n)\n" + } + }, + "browser_cargo__crossbeam-queue-0.3.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crossbeam-queue/0.3.11/download" + ], + "strip_prefix": "crossbeam-queue-0.3.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crossbeam_queue\",\n deps = [\n \"@browser_cargo__crossbeam-utils-0.8.19//:crossbeam_utils\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crossbeam-queue\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.11\",\n)\n" + } + }, + "browser_cargo__crossbeam-utils-0.8.19": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crossbeam-utils/0.8.19/download" + ], + "strip_prefix": "crossbeam-utils-0.8.19", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crossbeam_utils\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crossbeam-utils\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.19\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"crossbeam-utils\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crossbeam-utils\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.8.19\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__crunchy-0.2.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crunchy/0.2.2/download" + ], + "strip_prefix": "crunchy-0.2.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crunchy\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crunchy\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.2\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2015\",\n pkg_name = \"crunchy\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crunchy\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.2.2\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__crypto-common-0.1.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crypto-common/0.1.6/download" + ], + "strip_prefix": "crypto-common-0.1.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crypto_common\",\n deps = [\n \"@browser_cargo__generic-array-0.14.7//:generic_array\",\n \"@browser_cargo__typenum-1.17.0//:typenum\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crypto-common\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.6\",\n)\n" + } + }, + "browser_cargo__cynic-3.10.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c99c59968c8aa7f90d84240ab6ded4d3864125ce36b5b044554542cebc974946", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cynic/3.10.0/download" + ], + "strip_prefix": "cynic-3.10.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cynic\",\n deps = [\n \"@browser_cargo__ref-cast-1.0.24//:ref_cast\",\n \"@browser_cargo__reqwest-0.12.7//:reqwest\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n \"@browser_cargo__serde_json-1.0.140//:serde_json\",\n \"@browser_cargo__static_assertions-1.1.0//:static_assertions\",\n \"@browser_cargo__thiserror-1.0.69//:thiserror\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__cynic-proc-macros-3.10.0//:cynic_proc_macros\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"http-reqwest\",\n \"reqwest\",\n \"serde_json\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cynic\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"3.10.0\",\n)\n" + } + }, + "browser_cargo__cynic-codegen-3.10.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "332695dddff7f260dfda1e97502b6440d443816f576994548b7751494991d2e3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cynic-codegen/3.10.0/download" + ], + "strip_prefix": "cynic-codegen-3.10.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cynic_codegen\",\n deps = [\n \"@browser_cargo__cynic-parser-0.9.1//:cynic_parser\",\n \"@browser_cargo__darling-0.20.3//:darling\",\n \"@browser_cargo__once_cell-1.19.0//:once_cell\",\n \"@browser_cargo__ouroboros-0.18.5//:ouroboros\",\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__strsim-0.10.0//:strsim\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n \"@browser_cargo__thiserror-1.0.69//:thiserror\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"rustfmt\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cynic-codegen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"3.10.0\",\n)\n" + } + }, + "browser_cargo__cynic-parser-0.9.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "cbb0f21f2f8d3134c2e887a16564c165694231f48b6ae2769193299081ecf662", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cynic-parser/0.9.1/download" + ], + "strip_prefix": "cynic-parser-0.9.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cynic_parser\",\n deps = [\n \"@browser_cargo__indexmap-2.9.0//:indexmap\",\n \"@browser_cargo__lalrpop-util-0.22.1//:lalrpop_util\",\n \"@browser_cargo__logos-0.14.4//:logos\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cynic-parser\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.1\",\n)\n" + } + }, + "browser_cargo__cynic-proc-macros-3.10.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a7880789c425a73aff3ba286b2a9c794f330d4770769a42a1493d6175e4606c1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cynic-proc-macros/3.10.0/download" + ], + "strip_prefix": "cynic-proc-macros-3.10.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"cynic_proc_macros\",\n deps = [\n \"@browser_cargo__cynic-codegen-3.10.0//:cynic_codegen\",\n \"@browser_cargo__darling-0.20.3//:darling\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cynic-proc-macros\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"3.10.0\",\n)\n" + } + }, + "browser_cargo__darling-0.14.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/darling/0.14.4/download" + ], + "strip_prefix": "darling-0.14.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"darling\",\n deps = [\n \"@browser_cargo__darling_core-0.14.4//:darling_core\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__darling_macro-0.14.4//:darling_macro\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"suggestions\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=darling\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.14.4\",\n)\n" + } + }, + "browser_cargo__darling-0.20.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/darling/0.20.3/download" + ], + "strip_prefix": "darling-0.20.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"darling\",\n deps = [\n \"@browser_cargo__darling_core-0.20.3//:darling_core\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__darling_macro-0.20.3//:darling_macro\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"suggestions\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=darling\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.20.3\",\n)\n" + } + }, + "browser_cargo__darling_core-0.14.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/darling_core/0.14.4/download" + ], + "strip_prefix": "darling_core-0.14.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"darling_core\",\n deps = [\n \"@browser_cargo__fnv-1.0.7//:fnv\",\n \"@browser_cargo__ident_case-1.0.1//:ident_case\",\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__strsim-0.10.0//:strsim\",\n \"@browser_cargo__syn-1.0.109//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"strsim\",\n \"suggestions\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=darling_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.14.4\",\n)\n" + } + }, + "browser_cargo__darling_core-0.20.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/darling_core/0.20.3/download" + ], + "strip_prefix": "darling_core-0.20.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"darling_core\",\n deps = [\n \"@browser_cargo__fnv-1.0.7//:fnv\",\n \"@browser_cargo__ident_case-1.0.1//:ident_case\",\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__strsim-0.10.0//:strsim\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"strsim\",\n \"suggestions\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=darling_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.20.3\",\n)\n" + } + }, + "browser_cargo__darling_macro-0.14.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/darling_macro/0.14.4/download" + ], + "strip_prefix": "darling_macro-0.14.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"darling_macro\",\n deps = [\n \"@browser_cargo__darling_core-0.14.4//:darling_core\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-1.0.109//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=darling_macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.14.4\",\n)\n" + } + }, + "browser_cargo__darling_macro-0.20.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/darling_macro/0.20.3/download" + ], + "strip_prefix": "darling_macro-0.20.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"darling_macro\",\n deps = [\n \"@browser_cargo__darling_core-0.20.3//:darling_core\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=darling_macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.20.3\",\n)\n" + } + }, + "browser_cargo__dashmap-6.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/dashmap/6.1.0/download" + ], + "strip_prefix": "dashmap-6.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"dashmap\",\n deps = [\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n \"@browser_cargo__crossbeam-utils-0.8.19//:crossbeam_utils\",\n \"@browser_cargo__hashbrown-0.14.3//:hashbrown\",\n \"@browser_cargo__lock_api-0.4.11//:lock_api\",\n \"@browser_cargo__once_cell-1.19.0//:once_cell\",\n \"@browser_cargo__parking_lot_core-0.9.9//:parking_lot_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=dashmap\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"6.1.0\",\n)\n" + } + }, + "browser_cargo__deranged-0.3.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/deranged/0.3.11/download" + ], + "strip_prefix": "deranged-0.3.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"deranged\",\n deps = [\n \"@browser_cargo__powerfmt-0.2.0//:powerfmt\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"powerfmt\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=deranged\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.11\",\n)\n" + } + }, + "browser_cargo__derivative-2.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/derivative/2.2.0/download" + ], + "strip_prefix": "derivative-2.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"derivative\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-1.0.109//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=derivative\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.2.0\",\n)\n" + } + }, + "browser_cargo__derive_builder-0.12.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/derive_builder/0.12.0/download" + ], + "strip_prefix": "derive_builder-0.12.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"derive_builder\",\n proc_macro_deps = [\n \"@browser_cargo__derive_builder_macro-0.12.0//:derive_builder_macro\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=derive_builder\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.12.0\",\n)\n" + } + }, + "browser_cargo__derive_builder_core-0.12.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/derive_builder_core/0.12.0/download" + ], + "strip_prefix": "derive_builder_core-0.12.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"derive_builder_core\",\n deps = [\n \"@browser_cargo__darling-0.14.4//:darling\",\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-1.0.109//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=derive_builder_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.12.0\",\n)\n" + } + }, + "browser_cargo__derive_builder_macro-0.12.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/derive_builder_macro/0.12.0/download" + ], + "strip_prefix": "derive_builder_macro-0.12.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"derive_builder_macro\",\n deps = [\n \"@browser_cargo__derive_builder_core-0.12.0//:derive_builder_core\",\n \"@browser_cargo__syn-1.0.109//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=derive_builder_macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.12.0\",\n)\n" + } + }, + "browser_cargo__derive_more-0.99.19": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/derive_more/0.99.19/download" + ], + "strip_prefix": "derive_more-0.99.19", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"derive_more\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"display\",\n \"error\",\n \"from\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=derive_more\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.99.19\",\n)\n" + } + }, + "browser_cargo__derive_more-2.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/derive_more/2.0.1/download" + ], + "strip_prefix": "derive_more-2.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"derive_more\",\n proc_macro_deps = [\n \"@browser_cargo__derive_more-impl-2.0.1//:derive_more_impl\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"debug\",\n \"default\",\n \"display\",\n \"from\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=derive_more\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.1\",\n)\n" + } + }, + "browser_cargo__derive_more-impl-2.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/derive_more-impl/2.0.1/download" + ], + "strip_prefix": "derive_more-impl-2.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"derive_more_impl\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n \"@browser_cargo__unicode-xid-0.2.4//:unicode_xid\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"debug\",\n \"default\",\n \"display\",\n \"from\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=derive_more-impl\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.1\",\n)\n" + } + }, + "browser_cargo__digest-0.10.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/digest/0.10.7/download" + ], + "strip_prefix": "digest-0.10.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"digest\",\n deps = [\n \"@browser_cargo__block-buffer-0.10.4//:block_buffer\",\n \"@browser_cargo__crypto-common-0.1.6//:crypto_common\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"block-buffer\",\n \"core-api\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=digest\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.7\",\n)\n" + } + }, + "browser_cargo__displaydoc-0.2.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/displaydoc/0.2.5/download" + ], + "strip_prefix": "displaydoc-0.2.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"displaydoc\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=displaydoc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.5\",\n)\n" + } + }, + "browser_cargo__document-features-0.2.8": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/document-features/0.2.8/download" + ], + "strip_prefix": "document-features-0.2.8", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"document_features\",\n deps = [\n \"@browser_cargo__litrs-0.4.1//:litrs\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=document-features\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.8\",\n)\n" + } + }, + "browser_cargo__dunce-1.0.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/dunce/1.0.5/download" + ], + "strip_prefix": "dunce-1.0.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"dunce\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=dunce\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.5\",\n)\n" + } + }, + "browser_cargo__dyn-clone-1.0.17": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/dyn-clone/1.0.17/download" + ], + "strip_prefix": "dyn-clone-1.0.17", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"dyn_clone\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=dyn-clone\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.17\",\n)\n" + } + }, + "browser_cargo__educe-0.5.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e4bd92664bf78c4d3dba9b7cdafce6fa15b13ed3ed16175218196942e99168a8", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/educe/0.5.11/download" + ], + "strip_prefix": "educe-0.5.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"educe\",\n deps = [\n \"@browser_cargo__enum-ordinalize-4.3.2//:enum_ordinalize\",\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"Debug\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=educe\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.11\",\n)\n" + } + }, + "browser_cargo__either-1.13.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/either/1.13.0/download" + ], + "strip_prefix": "either-1.13.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"either\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=either\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.13.0\",\n)\n" + } + }, + "browser_cargo__encode_unicode-1.0.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/encode_unicode/1.0.0/download" + ], + "strip_prefix": "encode_unicode-1.0.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"encode_unicode\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=encode_unicode\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.0\",\n)\n" + } + }, + "browser_cargo__encoding_rs-0.8.34": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/encoding_rs/0.8.34/download" + ], + "strip_prefix": "encoding_rs-0.8.34", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"encoding_rs\",\n deps = [\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=encoding_rs\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.34\",\n)\n" + } + }, + "browser_cargo__enum-iterator-0.7.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4eeac5c5edb79e4e39fe8439ef35207780a11f69c52cbe424ce3dfad4cb78de6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/enum-iterator/0.7.0/download" + ], + "strip_prefix": "enum-iterator-0.7.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"enum_iterator\",\n proc_macro_deps = [\n \"@browser_cargo__enum-iterator-derive-0.7.0//:enum_iterator_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=enum-iterator\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.0\",\n)\n" + } + }, + "browser_cargo__enum-iterator-derive-0.7.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c134c37760b27a871ba422106eedbb8247da973a09e82558bf26d619c882b159", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/enum-iterator-derive/0.7.0/download" + ], + "strip_prefix": "enum-iterator-derive-0.7.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"enum_iterator_derive\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-1.0.109//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=enum-iterator-derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.0\",\n)\n" + } + }, + "browser_cargo__enum-ordinalize-4.3.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/enum-ordinalize/4.3.2/download" + ], + "strip_prefix": "enum-ordinalize-4.3.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"enum_ordinalize\",\n proc_macro_deps = [\n \"@browser_cargo__enum-ordinalize-derive-4.3.2//:enum_ordinalize_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"derive\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=enum-ordinalize\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"4.3.2\",\n)\n" + } + }, + "browser_cargo__enum-ordinalize-derive-4.3.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/enum-ordinalize-derive/4.3.2/download" + ], + "strip_prefix": "enum-ordinalize-derive-4.3.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"enum_ordinalize_derive\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=enum-ordinalize-derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"4.3.2\",\n)\n" + } + }, + "browser_cargo__enumset-1.1.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "226c0da7462c13fb57e5cc9e0dc8f0635e7d27f276a3a7fd30054647f669007d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/enumset/1.1.3/download" + ], + "strip_prefix": "enumset-1.1.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"enumset\",\n proc_macro_deps = [\n \"@browser_cargo__enumset_derive-0.8.1//:enumset_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=enumset\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.3\",\n)\n" + } + }, + "browser_cargo__enumset_derive-0.8.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/enumset_derive/0.8.1/download" + ], + "strip_prefix": "enumset_derive-0.8.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"enumset_derive\",\n deps = [\n \"@browser_cargo__darling-0.20.3//:darling\",\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=enumset_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.1\",\n)\n" + } + }, + "browser_cargo__equivalent-1.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/equivalent/1.0.1/download" + ], + "strip_prefix": "equivalent-1.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"equivalent\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=equivalent\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.1\",\n)\n" + } + }, + "browser_cargo__errno-0.3.8": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/errno/0.3.8/download" + ], + "strip_prefix": "errno-0.3.8", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"errno\",\n deps = select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__libc-0.2.171//:libc\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=errno\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.8\",\n)\n" + } + }, + "browser_cargo__fastrand-2.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/fastrand/2.0.1/download" + ], + "strip_prefix": "fastrand-2.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"fastrand\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=fastrand\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.1\",\n)\n" + } + }, + "browser_cargo__filetime-0.2.23": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/filetime/0.2.23/download" + ], + "strip_prefix": "filetime-0.2.23", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"filetime\",\n deps = [\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__libc-0.2.171//:libc\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=filetime\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.23\",\n)\n" + } + }, + "browser_cargo__fixedbitset-0.5.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/fixedbitset/0.5.7/download" + ], + "strip_prefix": "fixedbitset-0.5.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"fixedbitset\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=fixedbitset\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.7\",\n)\n" + } + }, + "browser_cargo__flate2-1.1.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/flate2/1.1.1/download" + ], + "strip_prefix": "flate2-1.1.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"flate2\",\n deps = [\n \"@browser_cargo__crc32fast-1.3.2//:crc32fast\",\n \"@browser_cargo__miniz_oxide-0.8.7//:miniz_oxide\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"any_impl\",\n \"default\",\n \"miniz_oxide\",\n \"rust_backend\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=flate2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.1\",\n)\n" + } + }, + "browser_cargo__fnv-1.0.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/fnv/1.0.7/download" + ], + "strip_prefix": "fnv-1.0.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"fnv\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=fnv\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.7\",\n)\n" + } + }, + "browser_cargo__foreign-types-0.3.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/foreign-types/0.3.2/download" + ], + "strip_prefix": "foreign-types-0.3.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"foreign_types\",\n deps = [\n \"@browser_cargo__foreign-types-shared-0.1.1//:foreign_types_shared\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=foreign-types\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.2\",\n)\n" + } + }, + "browser_cargo__foreign-types-shared-0.1.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/foreign-types-shared/0.1.1/download" + ], + "strip_prefix": "foreign-types-shared-0.1.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"foreign_types_shared\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=foreign-types-shared\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.1\",\n)\n" + } + }, + "browser_cargo__form_urlencoded-1.2.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/form_urlencoded/1.2.1/download" + ], + "strip_prefix": "form_urlencoded-1.2.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"form_urlencoded\",\n deps = [\n \"@browser_cargo__percent-encoding-2.3.1//:percent_encoding\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=form_urlencoded\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.1\",\n)\n" + } + }, + "browser_cargo__futures-0.3.30": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures/0.3.30/download" + ], + "strip_prefix": "futures-0.3.30", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures\",\n deps = [\n \"@browser_cargo__futures-channel-0.3.31//:futures_channel\",\n \"@browser_cargo__futures-core-0.3.31//:futures_core\",\n \"@browser_cargo__futures-executor-0.3.30//:futures_executor\",\n \"@browser_cargo__futures-io-0.3.31//:futures_io\",\n \"@browser_cargo__futures-sink-0.3.31//:futures_sink\",\n \"@browser_cargo__futures-task-0.3.31//:futures_task\",\n \"@browser_cargo__futures-util-0.3.31//:futures_util\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"async-await\",\n \"default\",\n \"executor\",\n \"futures-executor\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.30\",\n)\n" + } + }, + "browser_cargo__futures-channel-0.3.31": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-channel/0.3.31/download" + ], + "strip_prefix": "futures-channel-0.3.31", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures_channel\",\n deps = [\n \"@browser_cargo__futures-core-0.3.31//:futures_core\",\n \"@browser_cargo__futures-sink-0.3.31//:futures_sink\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"futures-sink\",\n \"sink\",\n \"std\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"default\", # x86_64-unknown-linux-gnu\n ],\n \"//conditions:default\": [],\n }),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-channel\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.31\",\n)\n" + } + }, + "browser_cargo__futures-core-0.3.31": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-core/0.3.31/download" + ], + "strip_prefix": "futures-core-0.3.31", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures_core\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.31\",\n)\n" + } + }, + "browser_cargo__futures-executor-0.3.30": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-executor/0.3.30/download" + ], + "strip_prefix": "futures-executor-0.3.30", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures_executor\",\n deps = [\n \"@browser_cargo__futures-core-0.3.31//:futures_core\",\n \"@browser_cargo__futures-task-0.3.31//:futures_task\",\n \"@browser_cargo__futures-util-0.3.31//:futures_util\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-executor\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.30\",\n)\n" + } + }, + "browser_cargo__futures-io-0.3.31": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-io/0.3.31/download" + ], + "strip_prefix": "futures-io-0.3.31", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures_io\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-io\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.31\",\n)\n" + } + }, + "browser_cargo__futures-macro-0.3.31": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-macro/0.3.31/download" + ], + "strip_prefix": "futures-macro-0.3.31", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"futures_macro\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.31\",\n)\n" + } + }, + "browser_cargo__futures-sink-0.3.31": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-sink/0.3.31/download" + ], + "strip_prefix": "futures-sink-0.3.31", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures_sink\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-sink\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.31\",\n)\n" + } + }, + "browser_cargo__futures-task-0.3.31": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-task/0.3.31/download" + ], + "strip_prefix": "futures-task-0.3.31", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures_task\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-task\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.31\",\n)\n" + } + }, + "browser_cargo__futures-util-0.3.31": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-util/0.3.31/download" + ], + "strip_prefix": "futures-util-0.3.31", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures_util\",\n deps = [\n \"@browser_cargo__futures-channel-0.3.31//:futures_channel\",\n \"@browser_cargo__futures-core-0.3.31//:futures_core\",\n \"@browser_cargo__futures-io-0.3.31//:futures_io\",\n \"@browser_cargo__futures-sink-0.3.31//:futures_sink\",\n \"@browser_cargo__futures-task-0.3.31//:futures_task\",\n \"@browser_cargo__memchr-2.7.1//:memchr\",\n \"@browser_cargo__pin-project-lite-0.2.13//:pin_project_lite\",\n \"@browser_cargo__pin-utils-0.1.0//:pin_utils\",\n \"@browser_cargo__slab-0.4.9//:slab\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__futures-macro-0.3.31//:futures_macro\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"async-await\",\n \"async-await-macro\",\n \"channel\",\n \"default\",\n \"futures-channel\",\n \"futures-io\",\n \"futures-macro\",\n \"futures-sink\",\n \"io\",\n \"memchr\",\n \"sink\",\n \"slab\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-util\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.31\",\n)\n" + } + }, + "browser_cargo__generic-array-0.14.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/generic-array/0.14.7/download" + ], + "strip_prefix": "generic-array-0.14.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"generic_array\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__typenum-1.17.0//:typenum\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"more_lengths\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=generic-array\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.14.7\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"more_lengths\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@browser_cargo__version_check-0.9.5//:version_check\",\n ],\n emit_warnings = False,\n edition = \"2015\",\n pkg_name = \"generic-array\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=generic-array\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.14.7\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__getrandom-0.2.15": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/getrandom/0.2.15/download" + ], + "strip_prefix": "getrandom-0.2.15", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"getrandom\",\n deps = [\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n ] + select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [\n \"@browser_cargo__js-sys-0.3.78//:js_sys\", # wasm32-unknown-unknown\n \"@browser_cargo__wasm-bindgen-0.2.101//:wasm_bindgen\", # wasm32-unknown-unknown\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__libc-0.2.171//:libc\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"js\",\n \"js-sys\",\n \"std\",\n \"wasm-bindgen\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=getrandom\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.15\",\n)\n" + } + }, + "browser_cargo__gimli-0.28.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/gimli/0.28.1/download" + ], + "strip_prefix": "gimli-0.28.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"gimli\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"read\",\n \"read-core\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=gimli\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.28.1\",\n)\n" + } + }, + "browser_cargo__glob-0.3.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/glob/0.3.2/download" + ], + "strip_prefix": "glob-0.3.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"glob\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=glob\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.2\",\n)\n" + } + }, + "browser_cargo__globset-0.4.14": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/globset/0.4.14/download" + ], + "strip_prefix": "globset-0.4.14", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"globset\",\n deps = [\n \"@browser_cargo__aho-corasick-1.1.2//:aho_corasick\",\n \"@browser_cargo__bstr-1.9.1//:bstr\",\n \"@browser_cargo__log-0.4.20//:log\",\n \"@browser_cargo__regex-automata-0.4.3//:regex_automata\",\n \"@browser_cargo__regex-syntax-0.8.2//:regex_syntax\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"log\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=globset\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.14\",\n)\n" + } + }, + "browser_cargo__h2-0.4.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/h2/0.4.5/download" + ], + "strip_prefix": "h2-0.4.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"h2\",\n deps = [\n \"@browser_cargo__atomic-waker-1.1.2//:atomic_waker\",\n \"@browser_cargo__bytes-1.10.1//:bytes\",\n \"@browser_cargo__fnv-1.0.7//:fnv\",\n \"@browser_cargo__futures-core-0.3.31//:futures_core\",\n \"@browser_cargo__futures-sink-0.3.31//:futures_sink\",\n \"@browser_cargo__http-1.3.1//:http\",\n \"@browser_cargo__indexmap-2.9.0//:indexmap\",\n \"@browser_cargo__slab-0.4.9//:slab\",\n \"@browser_cargo__tokio-1.44.2//:tokio\",\n \"@browser_cargo__tokio-util-0.7.11//:tokio_util\",\n \"@browser_cargo__tracing-0.1.41//:tracing\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=h2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.5\",\n)\n" + } + }, + "browser_cargo__half-2.4.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/half/2.4.1/download" + ], + "strip_prefix": "half-2.4.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"half\",\n deps = [\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=half\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.4.1\",\n)\n" + } + }, + "browser_cargo__harsh-0.2.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a6fce2283849822530a18d7d8eeb1719ac65a27cfb6649c0dc8dfd2d2cc5edfb", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/harsh/0.2.2/download" + ], + "strip_prefix": "harsh-0.2.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"harsh\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=harsh\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.2\",\n)\n" + } + }, + "browser_cargo__hash32-0.3.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hash32/0.3.1/download" + ], + "strip_prefix": "hash32-0.3.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hash32\",\n deps = [\n \"@browser_cargo__byteorder-1.5.0//:byteorder\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hash32\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.1\",\n)\n" + } + }, + "browser_cargo__hashbrown-0.14.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hashbrown/0.14.3/download" + ], + "strip_prefix": "hashbrown-0.14.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hashbrown\",\n deps = [\n \"@browser_cargo__ahash-0.8.11//:ahash\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"ahash\",\n \"raw\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hashbrown\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.14.3\",\n)\n" + } + }, + "browser_cargo__hashbrown-0.15.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hashbrown/0.15.2/download" + ], + "strip_prefix": "hashbrown-0.15.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hashbrown\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hashbrown\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.15.2\",\n)\n" + } + }, + "browser_cargo__heapless-0.8.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/heapless/0.8.0/download" + ], + "strip_prefix": "heapless-0.8.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"heapless\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__hash32-0.3.1//:hash32\",\n \"@browser_cargo__stable_deref_trait-1.2.0//:stable_deref_trait\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=heapless\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"heapless\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=heapless\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.8.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__heck-0.3.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/heck/0.3.3/download" + ], + "strip_prefix": "heck-0.3.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"heck\",\n deps = [\n \"@browser_cargo__unicode-segmentation-1.10.1//:unicode_segmentation\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=heck\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.3\",\n)\n" + } + }, + "browser_cargo__heck-0.4.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/heck/0.4.1/download" + ], + "strip_prefix": "heck-0.4.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"heck\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=heck\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.1\",\n)\n" + } + }, + "browser_cargo__hermit-abi-0.5.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hermit-abi/0.5.2/download" + ], + "strip_prefix": "hermit-abi-0.5.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hermit_abi\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hermit-abi\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.2\",\n)\n" + } + }, + "browser_cargo__hex-0.4.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hex/0.4.3/download" + ], + "strip_prefix": "hex-0.4.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hex\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hex\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.3\",\n)\n" + } + }, + "browser_cargo__http-1.3.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/http/1.3.1/download" + ], + "strip_prefix": "http-1.3.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"http\",\n deps = [\n \"@browser_cargo__bytes-1.10.1//:bytes\",\n \"@browser_cargo__fnv-1.0.7//:fnv\",\n \"@browser_cargo__itoa-1.0.10//:itoa\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=http\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.3.1\",\n)\n" + } + }, + "browser_cargo__http-body-1.0.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/http-body/1.0.0/download" + ], + "strip_prefix": "http-body-1.0.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"http_body\",\n deps = [\n \"@browser_cargo__bytes-1.10.1//:bytes\",\n \"@browser_cargo__http-1.3.1//:http\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=http-body\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.0\",\n)\n" + } + }, + "browser_cargo__http-body-util-0.1.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/http-body-util/0.1.2/download" + ], + "strip_prefix": "http-body-util-0.1.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"http_body_util\",\n deps = [\n \"@browser_cargo__bytes-1.10.1//:bytes\",\n \"@browser_cargo__futures-util-0.3.31//:futures_util\",\n \"@browser_cargo__http-1.3.1//:http\",\n \"@browser_cargo__http-body-1.0.0//:http_body\",\n \"@browser_cargo__pin-project-lite-0.2.13//:pin_project_lite\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=http-body-util\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.2\",\n)\n" + } + }, + "browser_cargo__httparse-1.10.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/httparse/1.10.1/download" + ], + "strip_prefix": "httparse-1.10.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"httparse\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=httparse\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.10.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"httparse\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=httparse\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.10.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__hyper-1.4.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c4fe55fb7a772d59a5ff1dfbff4fe0258d19b89fec4b233e75d35d5d2316badc", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hyper/1.4.0/download" + ], + "strip_prefix": "hyper-1.4.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hyper\",\n deps = [\n \"@browser_cargo__bytes-1.10.1//:bytes\",\n \"@browser_cargo__futures-channel-0.3.31//:futures_channel\",\n \"@browser_cargo__futures-util-0.3.31//:futures_util\",\n \"@browser_cargo__h2-0.4.5//:h2\",\n \"@browser_cargo__http-1.3.1//:http\",\n \"@browser_cargo__http-body-1.0.0//:http_body\",\n \"@browser_cargo__httparse-1.10.1//:httparse\",\n \"@browser_cargo__itoa-1.0.10//:itoa\",\n \"@browser_cargo__pin-project-lite-0.2.13//:pin_project_lite\",\n \"@browser_cargo__smallvec-1.13.2//:smallvec\",\n \"@browser_cargo__tokio-1.44.2//:tokio\",\n \"@browser_cargo__want-0.3.1//:want\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"client\",\n \"default\",\n \"http1\",\n \"http2\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hyper\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.4.0\",\n)\n" + } + }, + "browser_cargo__hyper-rustls-0.27.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hyper-rustls/0.27.2/download" + ], + "strip_prefix": "hyper-rustls-0.27.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hyper_rustls\",\n deps = [\n \"@browser_cargo__futures-util-0.3.31//:futures_util\",\n \"@browser_cargo__http-1.3.1//:http\",\n \"@browser_cargo__hyper-1.4.0//:hyper\",\n \"@browser_cargo__hyper-util-0.1.6//:hyper_util\",\n \"@browser_cargo__rustls-0.23.25//:rustls\",\n \"@browser_cargo__rustls-pki-types-1.11.0//:rustls_pki_types\",\n \"@browser_cargo__tokio-1.44.2//:tokio\",\n \"@browser_cargo__tokio-rustls-0.26.0//:tokio_rustls\",\n \"@browser_cargo__tower-service-0.3.2//:tower_service\",\n ],\n aliases = {\n \"@browser_cargo__rustls-pki-types-1.11.0//:rustls_pki_types\": \"pki_types\",\n },\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hyper-rustls\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.27.2\",\n)\n" + } + }, + "browser_cargo__hyper-tls-0.6.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hyper-tls/0.6.0/download" + ], + "strip_prefix": "hyper-tls-0.6.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hyper_tls\",\n deps = [\n \"@browser_cargo__bytes-1.10.1//:bytes\",\n \"@browser_cargo__http-body-util-0.1.2//:http_body_util\",\n \"@browser_cargo__hyper-1.4.0//:hyper\",\n \"@browser_cargo__hyper-util-0.1.6//:hyper_util\",\n \"@browser_cargo__native-tls-0.2.12//:native_tls\",\n \"@browser_cargo__tokio-1.44.2//:tokio\",\n \"@browser_cargo__tokio-native-tls-0.3.1//:tokio_native_tls\",\n \"@browser_cargo__tower-service-0.3.2//:tower_service\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hyper-tls\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.0\",\n)\n" + } + }, + "browser_cargo__hyper-util-0.1.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hyper-util/0.1.6/download" + ], + "strip_prefix": "hyper-util-0.1.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hyper_util\",\n deps = [\n \"@browser_cargo__bytes-1.10.1//:bytes\",\n \"@browser_cargo__futures-channel-0.3.31//:futures_channel\",\n \"@browser_cargo__futures-util-0.3.31//:futures_util\",\n \"@browser_cargo__http-1.3.1//:http\",\n \"@browser_cargo__http-body-1.0.0//:http_body\",\n \"@browser_cargo__hyper-1.4.0//:hyper\",\n \"@browser_cargo__pin-project-lite-0.2.13//:pin_project_lite\",\n \"@browser_cargo__socket2-0.5.7//:socket2\",\n \"@browser_cargo__tokio-1.44.2//:tokio\",\n \"@browser_cargo__tower-0.4.13//:tower\",\n \"@browser_cargo__tower-service-0.3.2//:tower_service\",\n \"@browser_cargo__tracing-0.1.41//:tracing\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"client\",\n \"client-legacy\",\n \"default\",\n \"http1\",\n \"http2\",\n \"tokio\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hyper-util\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.6\",\n)\n" + } + }, + "browser_cargo__iana-time-zone-0.1.59": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/iana-time-zone/0.1.59/download" + ], + "strip_prefix": "iana-time-zone-0.1.59", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"iana_time_zone\",\n deps = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [\n \"@browser_cargo__js-sys-0.3.78//:js_sys\", # cfg(target_arch = \"wasm32\")\n \"@browser_cargo__wasm-bindgen-0.2.101//:wasm_bindgen\", # cfg(target_arch = \"wasm32\")\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"fallback\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=iana-time-zone\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.59\",\n)\n" + } + }, + "browser_cargo__iana-time-zone-haiku-0.1.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/iana-time-zone-haiku/0.1.2/download" + ], + "strip_prefix": "iana-time-zone-haiku-0.1.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"iana_time_zone_haiku\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=iana-time-zone-haiku\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.2\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@browser_cargo__cc-1.2.18//:cc\",\n ],\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"iana-time-zone-haiku\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=iana-time-zone-haiku\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.1.2\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__icu_collections-1.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_collections/1.5.0/download" + ], + "strip_prefix": "icu_collections-1.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"icu_collections\",\n deps = [\n \"@browser_cargo__yoke-0.7.5//:yoke\",\n \"@browser_cargo__zerofrom-0.1.6//:zerofrom\",\n \"@browser_cargo__zerovec-0.10.4//:zerovec\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__displaydoc-0.2.5//:displaydoc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_collections\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.5.0\",\n)\n" + } + }, + "browser_cargo__icu_locid-1.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_locid/1.5.0/download" + ], + "strip_prefix": "icu_locid-1.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"icu_locid\",\n deps = [\n \"@browser_cargo__litemap-0.7.5//:litemap\",\n \"@browser_cargo__tinystr-0.7.6//:tinystr\",\n \"@browser_cargo__writeable-0.5.5//:writeable\",\n \"@browser_cargo__zerovec-0.10.4//:zerovec\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__displaydoc-0.2.5//:displaydoc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"zerovec\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_locid\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.5.0\",\n)\n" + } + }, + "browser_cargo__icu_locid_transform-1.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_locid_transform/1.5.0/download" + ], + "strip_prefix": "icu_locid_transform-1.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"icu_locid_transform\",\n deps = [\n \"@browser_cargo__icu_locid-1.5.0//:icu_locid\",\n \"@browser_cargo__icu_locid_transform_data-1.5.1//:icu_locid_transform_data\",\n \"@browser_cargo__icu_provider-1.5.0//:icu_provider\",\n \"@browser_cargo__tinystr-0.7.6//:tinystr\",\n \"@browser_cargo__zerovec-0.10.4//:zerovec\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__displaydoc-0.2.5//:displaydoc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"compiled_data\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_locid_transform\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.5.0\",\n)\n" + } + }, + "browser_cargo__icu_locid_transform_data-1.5.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_locid_transform_data/1.5.1/download" + ], + "strip_prefix": "icu_locid_transform_data-1.5.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"icu_locid_transform_data\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_locid_transform_data\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.5.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"icu_locid_transform_data\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_locid_transform_data\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.5.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__icu_normalizer-1.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_normalizer/1.5.0/download" + ], + "strip_prefix": "icu_normalizer-1.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"icu_normalizer\",\n deps = [\n \"@browser_cargo__icu_collections-1.5.0//:icu_collections\",\n \"@browser_cargo__icu_normalizer_data-1.5.1//:icu_normalizer_data\",\n \"@browser_cargo__icu_properties-1.5.1//:icu_properties\",\n \"@browser_cargo__icu_provider-1.5.0//:icu_provider\",\n \"@browser_cargo__smallvec-1.13.2//:smallvec\",\n \"@browser_cargo__utf16_iter-1.0.5//:utf16_iter\",\n \"@browser_cargo__utf8_iter-1.0.4//:utf8_iter\",\n \"@browser_cargo__write16-1.0.0//:write16\",\n \"@browser_cargo__zerovec-0.10.4//:zerovec\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__displaydoc-0.2.5//:displaydoc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"compiled_data\",\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_normalizer\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.5.0\",\n)\n" + } + }, + "browser_cargo__icu_normalizer_data-1.5.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_normalizer_data/1.5.1/download" + ], + "strip_prefix": "icu_normalizer_data-1.5.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"icu_normalizer_data\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_normalizer_data\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.5.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"icu_normalizer_data\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_normalizer_data\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.5.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__icu_properties-1.5.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_properties/1.5.1/download" + ], + "strip_prefix": "icu_properties-1.5.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"icu_properties\",\n deps = [\n \"@browser_cargo__icu_collections-1.5.0//:icu_collections\",\n \"@browser_cargo__icu_locid_transform-1.5.0//:icu_locid_transform\",\n \"@browser_cargo__icu_properties_data-1.5.1//:icu_properties_data\",\n \"@browser_cargo__icu_provider-1.5.0//:icu_provider\",\n \"@browser_cargo__tinystr-0.7.6//:tinystr\",\n \"@browser_cargo__zerovec-0.10.4//:zerovec\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__displaydoc-0.2.5//:displaydoc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"compiled_data\",\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_properties\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.5.1\",\n)\n" + } + }, + "browser_cargo__icu_properties_data-1.5.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_properties_data/1.5.1/download" + ], + "strip_prefix": "icu_properties_data-1.5.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"icu_properties_data\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_properties_data\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.5.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"icu_properties_data\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_properties_data\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.5.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__icu_provider-1.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_provider/1.5.0/download" + ], + "strip_prefix": "icu_provider-1.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"icu_provider\",\n deps = [\n \"@browser_cargo__icu_locid-1.5.0//:icu_locid\",\n \"@browser_cargo__stable_deref_trait-1.2.0//:stable_deref_trait\",\n \"@browser_cargo__tinystr-0.7.6//:tinystr\",\n \"@browser_cargo__writeable-0.5.5//:writeable\",\n \"@browser_cargo__yoke-0.7.5//:yoke\",\n \"@browser_cargo__zerofrom-0.1.6//:zerofrom\",\n \"@browser_cargo__zerovec-0.10.4//:zerovec\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__displaydoc-0.2.5//:displaydoc\",\n \"@browser_cargo__icu_provider_macros-1.5.0//:icu_provider_macros\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"macros\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_provider\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.5.0\",\n)\n" + } + }, + "browser_cargo__icu_provider_macros-1.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_provider_macros/1.5.0/download" + ], + "strip_prefix": "icu_provider_macros-1.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"icu_provider_macros\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_provider_macros\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.5.0\",\n)\n" + } + }, + "browser_cargo__id-arena-2.2.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "25a2bc672d1148e28034f176e01fffebb08b35768468cc954630da77a1449005", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/id-arena/2.2.1/download" + ], + "strip_prefix": "id-arena-2.2.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"id_arena\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=id-arena\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.2.1\",\n)\n" + } + }, + "browser_cargo__ident_case-1.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ident_case/1.0.1/download" + ], + "strip_prefix": "ident_case-1.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ident_case\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ident_case\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.1\",\n)\n" + } + }, + "browser_cargo__idna-1.0.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/idna/1.0.3/download" + ], + "strip_prefix": "idna-1.0.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"idna\",\n deps = [\n \"@browser_cargo__idna_adapter-1.2.0//:idna_adapter\",\n \"@browser_cargo__smallvec-1.13.2//:smallvec\",\n \"@browser_cargo__utf8_iter-1.0.4//:utf8_iter\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"compiled_data\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=idna\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.3\",\n)\n" + } + }, + "browser_cargo__idna_adapter-1.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/idna_adapter/1.2.0/download" + ], + "strip_prefix": "idna_adapter-1.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"idna_adapter\",\n deps = [\n \"@browser_cargo__icu_normalizer-1.5.0//:icu_normalizer\",\n \"@browser_cargo__icu_properties-1.5.1//:icu_properties\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"compiled_data\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=idna_adapter\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.0\",\n)\n" + } + }, + "browser_cargo__ignore-0.4.22": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ignore/0.4.22/download" + ], + "strip_prefix": "ignore-0.4.22", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ignore\",\n deps = [\n \"@browser_cargo__crossbeam-deque-0.8.5//:crossbeam_deque\",\n \"@browser_cargo__globset-0.4.14//:globset\",\n \"@browser_cargo__log-0.4.20//:log\",\n \"@browser_cargo__memchr-2.7.1//:memchr\",\n \"@browser_cargo__regex-automata-0.4.3//:regex_automata\",\n \"@browser_cargo__same-file-1.0.6//:same_file\",\n \"@browser_cargo__walkdir-2.4.0//:walkdir\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ignore\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.22\",\n)\n" + } + }, + "browser_cargo__indexmap-2.9.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/indexmap/2.9.0/download" + ], + "strip_prefix": "indexmap-2.9.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"indexmap\",\n deps = [\n \"@browser_cargo__equivalent-1.0.1//:equivalent\",\n \"@browser_cargo__hashbrown-0.15.2//:hashbrown\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=indexmap\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.9.0\",\n)\n" + } + }, + "browser_cargo__insta-1.41.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7e9ffc4d4892617c50a928c52b2961cb5174b6fc6ebf252b2fac9d21955c48b8", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/insta/1.41.1/download" + ], + "strip_prefix": "insta-1.41.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"insta\",\n deps = [\n \"@browser_cargo__console-0.15.11//:console\",\n \"@browser_cargo__lazy_static-1.5.0//:lazy_static\",\n \"@browser_cargo__linked-hash-map-0.5.6//:linked_hash_map\",\n \"@browser_cargo__regex-1.10.2//:regex\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n \"@browser_cargo__similar-2.7.0//:similar\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"colors\",\n \"console\",\n \"default\",\n \"filters\",\n \"regex\",\n \"serde\",\n \"yaml\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=insta\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.41.1\",\n)\n" + } + }, + "browser_cargo__instant-0.1.12": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/instant/0.1.12/download" + ], + "strip_prefix": "instant-0.1.12", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"instant\",\n deps = [\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n ] + select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [\n \"@browser_cargo__js-sys-0.3.78//:js_sys\", # wasm32-unknown-unknown\n \"@browser_cargo__wasm-bindgen-0.2.101//:wasm_bindgen\", # wasm32-unknown-unknown\n \"@browser_cargo__web-sys-0.3.78//:web_sys\", # wasm32-unknown-unknown\n ],\n \"//conditions:default\": [],\n }),\n aliases = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": {\n \"@browser_cargo__wasm-bindgen-0.2.101//:wasm_bindgen\": \"wasm_bindgen_rs\", # wasm32-unknown-unknown\n },\n \"//conditions:default\": {},\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"js-sys\",\n \"wasm-bindgen\",\n \"wasm-bindgen_rs\",\n \"web-sys\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=instant\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.12\",\n)\n" + } + }, + "browser_cargo__ipnet-2.11.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ipnet/2.11.0/download" + ], + "strip_prefix": "ipnet-2.11.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ipnet\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ipnet\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.11.0\",\n)\n" + } + }, + "browser_cargo__iprange-0.6.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "37209be0ad225457e63814401415e748e2453a5297f9b637338f5fb8afa4ec00", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/iprange/0.6.7/download" + ], + "strip_prefix": "iprange-0.6.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"iprange\",\n deps = [\n \"@browser_cargo__ipnet-2.11.0//:ipnet\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=iprange\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.7\",\n)\n" + } + }, + "browser_cargo__itertools-0.12.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/itertools/0.12.1/download" + ], + "strip_prefix": "itertools-0.12.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"itertools\",\n deps = [\n \"@browser_cargo__either-1.13.0//:either\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=itertools\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.12.1\",\n)\n" + } + }, + "browser_cargo__itoa-1.0.10": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/itoa/1.0.10/download" + ], + "strip_prefix": "itoa-1.0.10", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"itoa\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=itoa\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.10\",\n)\n" + } + }, + "browser_cargo__js-sys-0.3.78": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/js-sys/0.3.78/download" + ], + "strip_prefix": "js-sys-0.3.78", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"js_sys\",\n deps = [\n \"@browser_cargo__once_cell-1.19.0//:once_cell\",\n \"@browser_cargo__wasm-bindgen-0.2.101//:wasm_bindgen\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=js-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.78\",\n)\n" + } + }, + "browser_cargo__lalrpop-util-0.22.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e8d05b3fe34b8bd562c338db725dfa9beb9451a48f65f129ccb9538b48d2c93b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/lalrpop-util/0.22.1/download" + ], + "strip_prefix": "lalrpop-util-0.22.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"lalrpop_util\",\n proc_macro_deps = [\n \"@browser_cargo__rustversion-1.0.20//:rustversion\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=lalrpop-util\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.22.1\",\n)\n" + } + }, + "browser_cargo__lazy_static-1.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/lazy_static/1.5.0/download" + ], + "strip_prefix": "lazy_static-1.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"lazy_static\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=lazy_static\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.5.0\",\n)\n" + } + }, + "browser_cargo__leb128-0.2.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/leb128/0.2.5/download" + ], + "strip_prefix": "leb128-0.2.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"leb128\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=leb128\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.5\",\n)\n" + } + }, + "browser_cargo__leb128fmt-0.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/leb128fmt/0.1.0/download" + ], + "strip_prefix": "leb128fmt-0.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"leb128fmt\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=leb128fmt\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.0\",\n)\n" + } + }, + "browser_cargo__lexical-sort-0.3.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c09e4591611e231daf4d4c685a66cb0410cc1e502027a20ae55f2bb9e997207a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/lexical-sort/0.3.1/download" + ], + "strip_prefix": "lexical-sort-0.3.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"lexical_sort\",\n deps = [\n \"@browser_cargo__any_ascii-0.1.7//:any_ascii\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=lexical-sort\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.1\",\n)\n" + } + }, + "browser_cargo__libc-0.2.171": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/libc/0.2.171/download" + ], + "strip_prefix": "libc-0.2.171", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"libc\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=libc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.171\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"libc\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=libc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.2.171\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__libloading-0.8.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/libloading/0.8.6/download" + ], + "strip_prefix": "libloading-0.8.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"libloading\",\n deps = select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=libloading\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.6\",\n)\n" + } + }, + "browser_cargo__libunwind-1.3.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0c6639b70a7ce854b79c70d7e83f16b5dc0137cc914f3d7d03803b513ecc67ac", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/libunwind/1.3.3/download" + ], + "strip_prefix": "libunwind-1.3.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"libunwind\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=libunwind\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.3.3\",\n)\n" + } + }, + "browser_cargo__linked-hash-map-0.5.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/linked-hash-map/0.5.6/download" + ], + "strip_prefix": "linked-hash-map-0.5.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"linked_hash_map\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=linked-hash-map\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.6\",\n)\n" + } + }, + "browser_cargo__linked_hash_set-0.1.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "47186c6da4d81ca383c7c47c1bfc80f4b95f4720514d860a5407aaf4233f9588", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/linked_hash_set/0.1.4/download" + ], + "strip_prefix": "linked_hash_set-0.1.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"linked_hash_set\",\n deps = [\n \"@browser_cargo__linked-hash-map-0.5.6//:linked_hash_map\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=linked_hash_set\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.4\",\n)\n" + } + }, + "browser_cargo__linux-raw-sys-0.4.12": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/linux-raw-sys/0.4.12/download" + ], + "strip_prefix": "linux-raw-sys-0.4.12", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"linux_raw_sys\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"elf\",\n \"errno\",\n \"general\",\n \"ioctl\",\n \"no_std\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=linux-raw-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.12\",\n)\n" + } + }, + "browser_cargo__litemap-0.7.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/litemap/0.7.5/download" + ], + "strip_prefix": "litemap-0.7.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"litemap\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=litemap\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.5\",\n)\n" + } + }, + "browser_cargo__litrs-0.4.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/litrs/0.4.1/download" + ], + "strip_prefix": "litrs-0.4.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"litrs\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=litrs\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.1\",\n)\n" + } + }, + "browser_cargo__lock_api-0.4.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/lock_api/0.4.11/download" + ], + "strip_prefix": "lock_api-0.4.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"lock_api\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__scopeguard-1.2.0//:scopeguard\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"atomic_usize\",\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=lock_api\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.11\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"atomic_usize\",\n \"default\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@browser_cargo__autocfg-1.1.0//:autocfg\",\n ],\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"lock_api\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=lock_api\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.4.11\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__log-0.4.20": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/log/0.4.20/download" + ], + "strip_prefix": "log-0.4.20", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"log\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=log\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.20\",\n)\n" + } + }, + "browser_cargo__logos-0.14.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7251356ef8cb7aec833ddf598c6cb24d17b689d20b993f9d11a3d764e34e6458", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/logos/0.14.4/download" + ], + "strip_prefix": "logos-0.14.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"logos\",\n proc_macro_deps = [\n \"@browser_cargo__logos-derive-0.14.4//:logos_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"export_derive\",\n \"logos-derive\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=logos\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.14.4\",\n)\n" + } + }, + "browser_cargo__logos-codegen-0.14.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "59f80069600c0d66734f5ff52cc42f2dabd6b29d205f333d61fd7832e9e9963f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/logos-codegen/0.14.4/download" + ], + "strip_prefix": "logos-codegen-0.14.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"logos_codegen\",\n deps = [\n \"@browser_cargo__beef-0.5.2//:beef\",\n \"@browser_cargo__fnv-1.0.7//:fnv\",\n \"@browser_cargo__lazy_static-1.5.0//:lazy_static\",\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__regex-syntax-0.8.2//:regex_syntax\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=logos-codegen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.14.4\",\n)\n" + } + }, + "browser_cargo__logos-derive-0.14.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "24fb722b06a9dc12adb0963ed585f19fc61dc5413e6a9be9422ef92c091e731d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/logos-derive/0.14.4/download" + ], + "strip_prefix": "logos-derive-0.14.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"logos_derive\",\n deps = [\n \"@browser_cargo__logos-codegen-0.14.4//:logos_codegen\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=logos-derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.14.4\",\n)\n" + } + }, + "browser_cargo__lz4_flex-0.11.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3ea9b256699eda7b0387ffbc776dd625e28bde3918446381781245b7a50349d8", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/lz4_flex/0.11.1/download" + ], + "strip_prefix": "lz4_flex-0.11.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"lz4_flex\",\n deps = [\n \"@browser_cargo__twox-hash-1.6.3//:twox_hash\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"frame\",\n \"safe-decode\",\n \"safe-encode\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=lz4_flex\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.11.1\",\n)\n" + } + }, + "browser_cargo__mach2-0.4.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/mach2/0.4.2/download" + ], + "strip_prefix": "mach2-0.4.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"mach2\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=mach2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.2\",\n)\n" + } + }, + "browser_cargo__macho-unwind-info-0.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/macho-unwind-info/0.5.0/download" + ], + "strip_prefix": "macho-unwind-info-0.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"macho_unwind_info\",\n deps = [\n \"@browser_cargo__thiserror-2.0.12//:thiserror\",\n \"@browser_cargo__zerocopy-0.8.24//:zerocopy\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__zerocopy-derive-0.8.24//:zerocopy_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=macho-unwind-info\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.0\",\n)\n" + } + }, + "browser_cargo__managed-0.8.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/managed/0.8.0/download" + ], + "strip_prefix": "managed-0.8.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"managed\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"map\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=managed\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.0\",\n)\n" + } + }, + "browser_cargo__matchers-0.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/matchers/0.1.0/download" + ], + "strip_prefix": "matchers-0.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"matchers\",\n deps = [\n \"@browser_cargo__regex-automata-0.1.10//:regex_automata\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=matchers\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.0\",\n)\n" + } + }, + "browser_cargo__memchr-2.7.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/memchr/2.7.1/download" + ], + "strip_prefix": "memchr-2.7.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"memchr\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=memchr\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.7.1\",\n)\n" + } + }, + "browser_cargo__memmap2-0.6.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6d28bba84adfe6646737845bc5ebbfa2c08424eb1c37e94a1fd2a82adb56a872", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/memmap2/0.6.2/download" + ], + "strip_prefix": "memmap2-0.6.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"memmap2\",\n deps = select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__libc-0.2.171//:libc\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=memmap2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.2\",\n)\n" + } + }, + "browser_cargo__memoffset-0.9.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/memoffset/0.9.0/download" + ], + "strip_prefix": "memoffset-0.9.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"memoffset\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=memoffset\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@browser_cargo__autocfg-1.1.0//:autocfg\",\n ],\n emit_warnings = False,\n edition = \"2015\",\n pkg_name = \"memoffset\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=memoffset\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.9.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__merge-streams-0.1.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4f84f6452969abd246e7ac1fe4fe75906c76e8ec88d898df9aef37e0f3b6a7c2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/merge-streams/0.1.2/download" + ], + "strip_prefix": "merge-streams-0.1.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"merge_streams\",\n deps = [\n \"@browser_cargo__futures-core-0.3.31//:futures_core\",\n \"@browser_cargo__pin-project-1.1.3//:pin_project\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=merge-streams\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.2\",\n)\n" + } + }, + "browser_cargo__mime-0.3.17": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/mime/0.3.17/download" + ], + "strip_prefix": "mime-0.3.17", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"mime\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=mime\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.17\",\n)\n" + } + }, + "browser_cargo__minicov-0.3.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/minicov/0.3.7/download" + ], + "strip_prefix": "minicov-0.3.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"minicov\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=minicov\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.7\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@browser_cargo__cc-1.2.18//:cc\",\n \"@browser_cargo__walkdir-2.4.0//:walkdir\",\n ],\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"minicov\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=minicov\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.3.7\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__minimal-lexical-0.2.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/minimal-lexical/0.2.1/download" + ], + "strip_prefix": "minimal-lexical-0.2.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"minimal_lexical\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=minimal-lexical\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.1\",\n)\n" + } + }, + "browser_cargo__miniz_oxide-0.7.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/miniz_oxide/0.7.1/download" + ], + "strip_prefix": "miniz_oxide-0.7.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"miniz_oxide\",\n deps = [\n \"@browser_cargo__adler-1.0.2//:adler\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=miniz_oxide\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.1\",\n)\n" + } + }, + "browser_cargo__miniz_oxide-0.8.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/miniz_oxide/0.8.7/download" + ], + "strip_prefix": "miniz_oxide-0.8.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"miniz_oxide\",\n deps = [\n \"@browser_cargo__adler2-2.0.0//:adler2\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"with-alloc\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=miniz_oxide\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.7\",\n)\n" + } + }, + "browser_cargo__mio-1.0.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/mio/1.0.3/download" + ], + "strip_prefix": "mio-1.0.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"mio\",\n deps = select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__libc-0.2.171//:libc\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"net\",\n \"os-ext\",\n \"os-poll\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=mio\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.3\",\n)\n" + } + }, + "browser_cargo__more-asserts-0.2.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/more-asserts/0.2.2/download" + ], + "strip_prefix": "more-asserts-0.2.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"more_asserts\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=more-asserts\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.2\",\n)\n" + } + }, + "browser_cargo__munge-0.4.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a0091202c98cf06da46c279fdf50cccb6b1c43b4521abdf6a27b4c7e71d5d9d7", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/munge/0.4.3/download" + ], + "strip_prefix": "munge-0.4.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"munge\",\n proc_macro_deps = [\n \"@browser_cargo__munge_macro-0.4.3//:munge_macro\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=munge\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.3\",\n)\n" + } + }, + "browser_cargo__munge_macro-0.4.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "734799cf91479720b2f970c61a22850940dd91e27d4f02b1c6fc792778df2459", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/munge_macro/0.4.3/download" + ], + "strip_prefix": "munge_macro-0.4.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"munge_macro\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=munge_macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.3\",\n)\n" + } + }, + "browser_cargo__native-tls-0.2.12": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/native-tls/0.2.12/download" + ], + "strip_prefix": "native-tls-0.2.12", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"native_tls\",\n deps = [\n \":build_script_build\",\n ] + select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [\n \"@browser_cargo__log-0.4.20//:log\", # cfg(not(any(target_os = \"windows\", target_vendor = \"apple\")))\n \"@browser_cargo__openssl-0.10.64//:openssl\", # cfg(not(any(target_os = \"windows\", target_vendor = \"apple\")))\n \"@browser_cargo__openssl-probe-0.1.5//:openssl_probe\", # cfg(not(any(target_os = \"windows\", target_vendor = \"apple\")))\n \"@browser_cargo__openssl-sys-0.9.102//:openssl_sys\", # cfg(not(any(target_os = \"windows\", target_vendor = \"apple\")))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__log-0.4.20//:log\", # cfg(not(any(target_os = \"windows\", target_vendor = \"apple\")))\n \"@browser_cargo__openssl-0.10.64//:openssl\", # cfg(not(any(target_os = \"windows\", target_vendor = \"apple\")))\n \"@browser_cargo__openssl-probe-0.1.5//:openssl_probe\", # cfg(not(any(target_os = \"windows\", target_vendor = \"apple\")))\n \"@browser_cargo__openssl-sys-0.9.102//:openssl_sys\", # cfg(not(any(target_os = \"windows\", target_vendor = \"apple\")))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=native-tls\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.12\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n link_deps = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [\n \"@browser_cargo__openssl-sys-0.9.102//:openssl_sys\", # cfg(not(any(target_os = \"windows\", target_vendor = \"apple\")))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__openssl-sys-0.9.102//:openssl_sys\", # cfg(not(any(target_os = \"windows\", target_vendor = \"apple\")))\n ],\n \"//conditions:default\": [],\n }),\n edition = \"2015\",\n pkg_name = \"native-tls\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=native-tls\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.2.12\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__nom-5.1.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/nom/5.1.3/download" + ], + "strip_prefix": "nom-5.1.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"nom\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__memchr-2.7.1//:memchr\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=nom\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"5.1.3\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@browser_cargo__version_check-0.9.5//:version_check\",\n ],\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"nom\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=nom\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"5.1.3\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__nom-7.1.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/nom/7.1.3/download" + ], + "strip_prefix": "nom-7.1.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"nom\",\n deps = [\n \"@browser_cargo__memchr-2.7.1//:memchr\",\n \"@browser_cargo__minimal-lexical-0.2.1//:minimal_lexical\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=nom\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"7.1.3\",\n)\n" + } + }, + "browser_cargo__nu-ansi-term-0.46.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/nu-ansi-term/0.46.0/download" + ], + "strip_prefix": "nu-ansi-term-0.46.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"nu_ansi_term\",\n deps = [\n \"@browser_cargo__overload-0.1.1//:overload\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=nu-ansi-term\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.46.0\",\n)\n" + } + }, + "browser_cargo__num-conv-0.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/num-conv/0.1.0/download" + ], + "strip_prefix": "num-conv-0.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"num_conv\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=num-conv\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.0\",\n)\n" + } + }, + "browser_cargo__num-traits-0.2.17": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/num-traits/0.2.17/download" + ], + "strip_prefix": "num-traits-0.2.17", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"num_traits\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=num-traits\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.17\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@browser_cargo__autocfg-1.1.0//:autocfg\",\n ],\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"num-traits\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=num-traits\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.2.17\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__num_cpus-1.17.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/num_cpus/1.17.0/download" + ], + "strip_prefix": "num_cpus-1.17.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"num_cpus\",\n deps = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [\n \"@browser_cargo__libc-0.2.171//:libc\", # cfg(not(windows))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__libc-0.2.171//:libc\", # cfg(not(windows))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=num_cpus\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.17.0\",\n)\n" + } + }, + "browser_cargo__num_enum-0.7.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/num_enum/0.7.3/download" + ], + "strip_prefix": "num_enum-0.7.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"num_enum\",\n proc_macro_deps = [\n \"@browser_cargo__num_enum_derive-0.7.3//:num_enum_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=num_enum\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.3\",\n)\n" + } + }, + "browser_cargo__num_enum_derive-0.7.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/num_enum_derive/0.7.3/download" + ], + "strip_prefix": "num_enum_derive-0.7.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"num_enum_derive\",\n deps = [\n \"@browser_cargo__proc-macro-crate-1.3.1//:proc_macro_crate\",\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"proc-macro-crate\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=num_enum_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.3\",\n)\n" + } + }, + "browser_cargo__object-0.32.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/object/0.32.2/download" + ], + "strip_prefix": "object-0.32.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"object\",\n deps = [\n \"@browser_cargo__crc32fast-1.3.2//:crc32fast\",\n \"@browser_cargo__flate2-1.1.1//:flate2\",\n \"@browser_cargo__hashbrown-0.14.3//:hashbrown\",\n \"@browser_cargo__indexmap-2.9.0//:indexmap\",\n \"@browser_cargo__memchr-2.7.1//:memchr\",\n \"@browser_cargo__ruzstd-0.5.0//:ruzstd\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"archive\",\n \"coff\",\n \"compression\",\n \"default\",\n \"elf\",\n \"macho\",\n \"pe\",\n \"read\",\n \"read_core\",\n \"std\",\n \"unaligned\",\n \"write\",\n \"write_core\",\n \"write_std\",\n \"xcoff\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=object\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.32.2\",\n)\n" + } + }, + "browser_cargo__once_cell-1.19.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/once_cell/1.19.0/download" + ], + "strip_prefix": "once_cell-1.19.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"once_cell\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"race\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=once_cell\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.19.0\",\n)\n" + } + }, + "browser_cargo__openssl-0.10.64": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/openssl/0.10.64/download" + ], + "strip_prefix": "openssl-0.10.64", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"openssl\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__bitflags-2.9.0//:bitflags\",\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n \"@browser_cargo__foreign-types-0.3.2//:foreign_types\",\n \"@browser_cargo__libc-0.2.171//:libc\",\n \"@browser_cargo__once_cell-1.19.0//:once_cell\",\n \"@browser_cargo__openssl-sys-0.9.102//:openssl_sys\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__openssl-macros-0.1.1//:openssl_macros\",\n ],\n aliases = {\n \"@browser_cargo__openssl-sys-0.9.102//:openssl_sys\": \"ffi\",\n },\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=openssl\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.64\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n link_deps = [\n \"@browser_cargo__openssl-sys-0.9.102//:openssl_sys\",\n ],\n edition = \"2018\",\n pkg_name = \"openssl\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=openssl\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.10.64\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__openssl-macros-0.1.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/openssl-macros/0.1.1/download" + ], + "strip_prefix": "openssl-macros-0.1.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"openssl_macros\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=openssl-macros\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.1\",\n)\n" + } + }, + "browser_cargo__openssl-probe-0.1.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/openssl-probe/0.1.5/download" + ], + "strip_prefix": "openssl-probe-0.1.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"openssl_probe\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=openssl-probe\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.5\",\n)\n" + } + }, + "browser_cargo__openssl-sys-0.9.102": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/openssl-sys/0.9.102/download" + ], + "strip_prefix": "openssl-sys-0.9.102", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"openssl_sys\",\n deps = [\n \":build_script_main\",\n \"@browser_cargo__libc-0.2.171//:libc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=openssl-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.102\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_main\",\n crate_root = \"build/main.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@browser_cargo__cc-1.2.18//:cc\",\n \"@browser_cargo__pkg-config-0.3.30//:pkg_config\",\n \"@browser_cargo__vcpkg-0.2.15//:vcpkg\",\n ],\n emit_warnings = False,\n edition = \"2018\",\n links = \"openssl\",\n pkg_name = \"openssl-sys\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=openssl-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.9.102\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_main\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__ouroboros-0.18.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ouroboros/0.18.5/download" + ], + "strip_prefix": "ouroboros-0.18.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ouroboros\",\n deps = [\n \"@browser_cargo__aliasable-0.1.3//:aliasable\",\n \"@browser_cargo__static_assertions-1.1.0//:static_assertions\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__ouroboros_macro-0.18.5//:ouroboros_macro\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ouroboros\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.18.5\",\n)\n" + } + }, + "browser_cargo__ouroboros_macro-0.18.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ouroboros_macro/0.18.5/download" + ], + "strip_prefix": "ouroboros_macro-0.18.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"ouroboros_macro\",\n deps = [\n \"@browser_cargo__heck-0.4.1//:heck\",\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__proc-macro2-diagnostics-0.10.1//:proc_macro2_diagnostics\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ouroboros_macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.18.5\",\n)\n" + } + }, + "browser_cargo__overload-0.1.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/overload/0.1.1/download" + ], + "strip_prefix": "overload-0.1.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"overload\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=overload\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.1\",\n)\n" + } + }, + "browser_cargo__parking_lot_core-0.9.9": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/parking_lot_core/0.9.9/download" + ], + "strip_prefix": "parking_lot_core-0.9.9", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"parking_lot_core\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n \"@browser_cargo__smallvec-1.13.2//:smallvec\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__libc-0.2.171//:libc\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=parking_lot_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.9\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"parking_lot_core\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=parking_lot_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.9.9\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__paste-1.0.15": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/paste/1.0.15/download" + ], + "strip_prefix": "paste-1.0.15", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"paste\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=paste\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.15\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"paste\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=paste\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.15\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__path-clean-1.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/path-clean/1.0.1/download" + ], + "strip_prefix": "path-clean-1.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"path_clean\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=path-clean\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.1\",\n)\n" + } + }, + "browser_cargo__percent-encoding-2.3.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/percent-encoding/2.3.1/download" + ], + "strip_prefix": "percent-encoding-2.3.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"percent_encoding\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"default\", # x86_64-unknown-linux-gnu\n ],\n \"//conditions:default\": [],\n }),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=percent-encoding\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.3.1\",\n)\n" + } + }, + "browser_cargo__petgraph-0.7.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/petgraph/0.7.1/download" + ], + "strip_prefix": "petgraph-0.7.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"petgraph\",\n deps = [\n \"@browser_cargo__fixedbitset-0.5.7//:fixedbitset\",\n \"@browser_cargo__indexmap-2.9.0//:indexmap\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"graphmap\",\n \"matrix_graph\",\n \"stable_graph\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=petgraph\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.1\",\n)\n" + } + }, + "browser_cargo__pin-project-1.1.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/pin-project/1.1.3/download" + ], + "strip_prefix": "pin-project-1.1.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"pin_project\",\n proc_macro_deps = [\n \"@browser_cargo__pin-project-internal-1.1.3//:pin_project_internal\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pin-project\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.3\",\n)\n" + } + }, + "browser_cargo__pin-project-internal-1.1.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/pin-project-internal/1.1.3/download" + ], + "strip_prefix": "pin-project-internal-1.1.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"pin_project_internal\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pin-project-internal\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.3\",\n)\n" + } + }, + "browser_cargo__pin-project-lite-0.2.13": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/pin-project-lite/0.2.13/download" + ], + "strip_prefix": "pin-project-lite-0.2.13", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"pin_project_lite\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pin-project-lite\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.13\",\n)\n" + } + }, + "browser_cargo__pin-utils-0.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/pin-utils/0.1.0/download" + ], + "strip_prefix": "pin-utils-0.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"pin_utils\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pin-utils\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.0\",\n)\n" + } + }, + "browser_cargo__pkg-config-0.3.30": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/pkg-config/0.3.30/download" + ], + "strip_prefix": "pkg-config-0.3.30", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"pkg_config\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pkg-config\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.30\",\n)\n" + } + }, + "browser_cargo__powerfmt-0.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/powerfmt/0.2.0/download" + ], + "strip_prefix": "powerfmt-0.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"powerfmt\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=powerfmt\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.0\",\n)\n" + } + }, + "browser_cargo__ppv-lite86-0.2.17": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ppv-lite86/0.2.17/download" + ], + "strip_prefix": "ppv-lite86-0.2.17", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ppv_lite86\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"simd\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ppv-lite86\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.17\",\n)\n" + } + }, + "browser_cargo__prettyplease-0.2.32": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/prettyplease/0.2.32/download" + ], + "strip_prefix": "prettyplease-0.2.32", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"prettyplease\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"verbatim\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=prettyplease\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.32\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"verbatim\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n links = \"prettyplease02\",\n pkg_name = \"prettyplease\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=prettyplease\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.2.32\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__proc-macro-crate-1.3.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/proc-macro-crate/1.3.1/download" + ], + "strip_prefix": "proc-macro-crate-1.3.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"proc_macro_crate\",\n deps = [\n \"@browser_cargo__once_cell-1.19.0//:once_cell\",\n \"@browser_cargo__toml_edit-0.19.15//:toml_edit\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=proc-macro-crate\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.3.1\",\n)\n" + } + }, + "browser_cargo__proc-macro-error-attr2-2.0.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/proc-macro-error-attr2/2.0.0/download" + ], + "strip_prefix": "proc-macro-error-attr2-2.0.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"proc_macro_error_attr2\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=proc-macro-error-attr2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.0\",\n)\n" + } + }, + "browser_cargo__proc-macro-error2-2.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/proc-macro-error2/2.0.1/download" + ], + "strip_prefix": "proc-macro-error2-2.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"proc_macro_error2\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__proc-macro-error-attr2-2.0.0//:proc_macro_error_attr2\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"syn-error\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=proc-macro-error2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.1\",\n)\n" + } + }, + "browser_cargo__proc-macro2-1.0.94": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/proc-macro2/1.0.94/download" + ], + "strip_prefix": "proc-macro2-1.0.94", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"proc_macro2\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__unicode-ident-1.0.12//:unicode_ident\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"proc-macro\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=proc-macro2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.94\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"proc-macro\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"proc-macro2\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=proc-macro2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.94\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__proc-macro2-diagnostics-0.10.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/proc-macro2-diagnostics/0.10.1/download" + ], + "strip_prefix": "proc-macro2-diagnostics-0.10.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"proc_macro2_diagnostics\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n \"@browser_cargo__yansi-1.0.1//:yansi\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"colors\",\n \"default\",\n \"yansi\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=proc-macro2-diagnostics\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"colors\",\n \"default\",\n \"yansi\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@browser_cargo__version_check-0.9.5//:version_check\",\n ],\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"proc-macro2-diagnostics\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=proc-macro2-diagnostics\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.10.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__ptr_meta-0.1.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ptr_meta/0.1.4/download" + ], + "strip_prefix": "ptr_meta-0.1.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ptr_meta\",\n proc_macro_deps = [\n \"@browser_cargo__ptr_meta_derive-0.1.4//:ptr_meta_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ptr_meta\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.4\",\n)\n" + } + }, + "browser_cargo__ptr_meta-0.3.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "fe9e76f66d3f9606f44e45598d155cb13ecf09f4a28199e48daf8c8fc937ea90", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ptr_meta/0.3.0/download" + ], + "strip_prefix": "ptr_meta-0.3.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ptr_meta\",\n proc_macro_deps = [\n \"@browser_cargo__ptr_meta_derive-0.3.0//:ptr_meta_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"derive\",\n \"ptr_meta_derive\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ptr_meta\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.0\",\n)\n" + } + }, + "browser_cargo__ptr_meta_derive-0.1.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ptr_meta_derive/0.1.4/download" + ], + "strip_prefix": "ptr_meta_derive-0.1.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"ptr_meta_derive\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-1.0.109//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ptr_meta_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.4\",\n)\n" + } + }, + "browser_cargo__ptr_meta_derive-0.3.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ca414edb151b4c8d125c12566ab0d74dc9cdba36fb80eb7b848c15f495fd32d1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ptr_meta_derive/0.3.0/download" + ], + "strip_prefix": "ptr_meta_derive-0.3.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"ptr_meta_derive\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ptr_meta_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.0\",\n)\n" + } + }, + "browser_cargo__pulldown-cmark-0.8.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/pulldown-cmark/0.8.0/download" + ], + "strip_prefix": "pulldown-cmark-0.8.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"pulldown_cmark\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__bitflags-1.3.2//:bitflags\",\n \"@browser_cargo__memchr-2.7.1//:memchr\",\n \"@browser_cargo__unicase-2.7.0//:unicase\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pulldown-cmark\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"pulldown-cmark\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pulldown-cmark\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.8.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__quote-1.0.35": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/quote/1.0.35/download" + ], + "strip_prefix": "quote-1.0.35", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"quote\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"proc-macro\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=quote\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.35\",\n)\n" + } + }, + "browser_cargo__rancor-0.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "caf5f7161924b9d1cea0e4cabc97c372cea92b5f927fc13c6bca67157a0ad947", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rancor/0.1.0/download" + ], + "strip_prefix": "rancor-0.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rancor\",\n deps = [\n \"@browser_cargo__ptr_meta-0.3.0//:ptr_meta\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rancor\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.0\",\n)\n" + } + }, + "browser_cargo__rand-0.8.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rand/0.8.5/download" + ], + "strip_prefix": "rand-0.8.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rand\",\n deps = [\n \"@browser_cargo__rand_chacha-0.3.1//:rand_chacha\",\n \"@browser_cargo__rand_core-0.6.4//:rand_core\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__libc-0.2.171//:libc\", # x86_64-unknown-linux-gnu\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"getrandom\",\n \"libc\",\n \"rand_chacha\",\n \"std\",\n \"std_rng\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rand\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.5\",\n)\n" + } + }, + "browser_cargo__rand_chacha-0.3.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rand_chacha/0.3.1/download" + ], + "strip_prefix": "rand_chacha-0.3.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rand_chacha\",\n deps = [\n \"@browser_cargo__ppv-lite86-0.2.17//:ppv_lite86\",\n \"@browser_cargo__rand_core-0.6.4//:rand_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rand_chacha\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.1\",\n)\n" + } + }, + "browser_cargo__rand_core-0.6.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rand_core/0.6.4/download" + ], + "strip_prefix": "rand_core-0.6.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rand_core\",\n deps = [\n \"@browser_cargo__getrandom-0.2.15//:getrandom\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"getrandom\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rand_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.4\",\n)\n" + } + }, + "browser_cargo__redox_syscall-0.4.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/redox_syscall/0.4.1/download" + ], + "strip_prefix": "redox_syscall-0.4.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"syscall\",\n deps = [\n \"@browser_cargo__bitflags-1.3.2//:bitflags\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=redox_syscall\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.1\",\n)\n" + } + }, + "browser_cargo__ref-cast-1.0.24": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ref-cast/1.0.24/download" + ], + "strip_prefix": "ref-cast-1.0.24", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ref_cast\",\n deps = [\n \":build_script_build\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__ref-cast-impl-1.0.24//:ref_cast_impl\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ref-cast\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.24\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"ref-cast\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ref-cast\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.24\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__ref-cast-impl-1.0.24": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ref-cast-impl/1.0.24/download" + ], + "strip_prefix": "ref-cast-impl-1.0.24", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"ref_cast_impl\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ref-cast-impl\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.24\",\n)\n" + } + }, + "browser_cargo__regex-1.10.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/regex/1.10.2/download" + ], + "strip_prefix": "regex-1.10.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"regex\",\n deps = [\n \"@browser_cargo__regex-automata-0.4.3//:regex_automata\",\n \"@browser_cargo__regex-syntax-0.8.2//:regex_syntax\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n \"unicode\",\n \"unicode-age\",\n \"unicode-bool\",\n \"unicode-case\",\n \"unicode-gencat\",\n \"unicode-perl\",\n \"unicode-script\",\n \"unicode-segment\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=regex\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.10.2\",\n)\n" + } + }, + "browser_cargo__regex-automata-0.1.10": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/regex-automata/0.1.10/download" + ], + "strip_prefix": "regex-automata-0.1.10", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"regex_automata\",\n deps = [\n \"@browser_cargo__regex-syntax-0.6.29//:regex_syntax\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"regex-syntax\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=regex-automata\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.10\",\n)\n" + } + }, + "browser_cargo__regex-automata-0.4.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/regex-automata/0.4.3/download" + ], + "strip_prefix": "regex-automata-0.4.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"regex_automata\",\n deps = [\n \"@browser_cargo__aho-corasick-1.1.2//:aho_corasick\",\n \"@browser_cargo__memchr-2.7.1//:memchr\",\n \"@browser_cargo__regex-syntax-0.8.2//:regex_syntax\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"dfa-onepass\",\n \"hybrid\",\n \"meta\",\n \"nfa\",\n \"nfa-backtrack\",\n \"nfa-pikevm\",\n \"nfa-thompson\",\n \"perf\",\n \"perf-inline\",\n \"perf-literal\",\n \"perf-literal-multisubstring\",\n \"perf-literal-substring\",\n \"std\",\n \"syntax\",\n \"unicode\",\n \"unicode-age\",\n \"unicode-bool\",\n \"unicode-case\",\n \"unicode-gencat\",\n \"unicode-perl\",\n \"unicode-script\",\n \"unicode-segment\",\n \"unicode-word-boundary\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=regex-automata\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.3\",\n)\n" + } + }, + "browser_cargo__regex-syntax-0.6.29": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/regex-syntax/0.6.29/download" + ], + "strip_prefix": "regex-syntax-0.6.29", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"regex_syntax\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"unicode\",\n \"unicode-age\",\n \"unicode-bool\",\n \"unicode-case\",\n \"unicode-gencat\",\n \"unicode-perl\",\n \"unicode-script\",\n \"unicode-segment\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=regex-syntax\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.29\",\n)\n" + } + }, + "browser_cargo__regex-syntax-0.8.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/regex-syntax/0.8.2/download" + ], + "strip_prefix": "regex-syntax-0.8.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"regex_syntax\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n \"unicode\",\n \"unicode-age\",\n \"unicode-bool\",\n \"unicode-case\",\n \"unicode-gencat\",\n \"unicode-perl\",\n \"unicode-script\",\n \"unicode-segment\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"default\", # x86_64-unknown-linux-gnu\n ],\n \"//conditions:default\": [],\n }),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=regex-syntax\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.2\",\n)\n" + } + }, + "browser_cargo__region-3.0.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/region/3.0.2/download" + ], + "strip_prefix": "region-3.0.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"region\",\n deps = [\n \"@browser_cargo__bitflags-1.3.2//:bitflags\",\n \"@browser_cargo__libc-0.2.171//:libc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=region\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"3.0.2\",\n)\n" + } + }, + "browser_cargo__rend-0.5.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a35e8a6bf28cd121053a66aa2e6a2e3eaffad4a60012179f0e864aa5ffeff215", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rend/0.5.2/download" + ], + "strip_prefix": "rend-0.5.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rend\",\n deps = [\n \"@browser_cargo__bytecheck-0.8.1//:bytecheck\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"bytecheck\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rend\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.2\",\n)\n" + } + }, + "browser_cargo__replace_with-0.1.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e3a8614ee435691de62bcffcf4a66d91b3594bf1428a5722e79103249a095690", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/replace_with/0.1.7/download" + ], + "strip_prefix": "replace_with-0.1.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"replace_with\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=replace_with\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.7\",\n)\n" + } + }, + "browser_cargo__reqwest-0.12.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/reqwest/0.12.7/download" + ], + "strip_prefix": "reqwest-0.12.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"reqwest\",\n deps = [\n \"@browser_cargo__base64-0.22.1//:base64\",\n \"@browser_cargo__bytes-1.10.1//:bytes\",\n \"@browser_cargo__futures-core-0.3.31//:futures_core\",\n \"@browser_cargo__futures-util-0.3.31//:futures_util\",\n \"@browser_cargo__http-1.3.1//:http\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n \"@browser_cargo__serde_json-1.0.140//:serde_json\",\n \"@browser_cargo__serde_urlencoded-0.7.1//:serde_urlencoded\",\n \"@browser_cargo__sync_wrapper-1.0.1//:sync_wrapper\",\n \"@browser_cargo__tower-service-0.3.2//:tower_service\",\n \"@browser_cargo__url-2.5.4//:url\",\n ] + select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [\n \"@browser_cargo__js-sys-0.3.78//:js_sys\", # cfg(target_arch = \"wasm32\")\n \"@browser_cargo__wasm-bindgen-0.2.101//:wasm_bindgen\", # cfg(target_arch = \"wasm32\")\n \"@browser_cargo__wasm-bindgen-futures-0.4.51//:wasm_bindgen_futures\", # cfg(target_arch = \"wasm32\")\n \"@browser_cargo__wasm-streams-0.4.0//:wasm_streams\", # wasm32-unknown-unknown\n \"@browser_cargo__web-sys-0.3.78//:web_sys\", # cfg(target_arch = \"wasm32\")\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__encoding_rs-0.8.34//:encoding_rs\", # x86_64-unknown-linux-gnu\n \"@browser_cargo__h2-0.4.5//:h2\", # x86_64-unknown-linux-gnu\n \"@browser_cargo__http-body-1.0.0//:http_body\", # cfg(not(target_arch = \"wasm32\"))\n \"@browser_cargo__http-body-util-0.1.2//:http_body_util\", # cfg(not(target_arch = \"wasm32\"))\n \"@browser_cargo__hyper-1.4.0//:hyper\", # cfg(not(target_arch = \"wasm32\"))\n \"@browser_cargo__hyper-tls-0.6.0//:hyper_tls\", # x86_64-unknown-linux-gnu\n \"@browser_cargo__hyper-util-0.1.6//:hyper_util\", # cfg(not(target_arch = \"wasm32\"))\n \"@browser_cargo__ipnet-2.11.0//:ipnet\", # cfg(not(target_arch = \"wasm32\"))\n \"@browser_cargo__log-0.4.20//:log\", # cfg(not(target_arch = \"wasm32\"))\n \"@browser_cargo__mime-0.3.17//:mime\", # cfg(not(target_arch = \"wasm32\"))\n \"@browser_cargo__native-tls-0.2.12//:native_tls\", # x86_64-unknown-linux-gnu\n \"@browser_cargo__once_cell-1.19.0//:once_cell\", # cfg(not(target_arch = \"wasm32\"))\n \"@browser_cargo__percent-encoding-2.3.1//:percent_encoding\", # cfg(not(target_arch = \"wasm32\"))\n \"@browser_cargo__pin-project-lite-0.2.13//:pin_project_lite\", # cfg(not(target_arch = \"wasm32\"))\n \"@browser_cargo__rustls-pemfile-2.1.2//:rustls_pemfile\", # x86_64-unknown-linux-gnu\n \"@browser_cargo__tokio-1.44.2//:tokio\", # cfg(not(target_arch = \"wasm32\"))\n \"@browser_cargo__tokio-native-tls-0.3.1//:tokio_native_tls\", # x86_64-unknown-linux-gnu\n \"@browser_cargo__tokio-util-0.7.11//:tokio_util\", # x86_64-unknown-linux-gnu\n ],\n \"//conditions:default\": [],\n }),\n aliases = select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": {\n \"@browser_cargo__native-tls-0.2.12//:native_tls\": \"native_tls_crate\", # x86_64-unknown-linux-gnu\n },\n \"//conditions:default\": {},\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"__tls\",\n \"charset\",\n \"default\",\n \"default-tls\",\n \"h2\",\n \"http2\",\n \"json\",\n \"macos-system-configuration\",\n \"stream\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=reqwest\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.12.7\",\n)\n" + } + }, + "browser_cargo__ring-0.17.8": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ring/0.17.8/download" + ], + "strip_prefix": "ring-0.17.8", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ring\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n \"@browser_cargo__getrandom-0.2.15//:getrandom\",\n \"@browser_cargo__untrusted-0.9.0//:untrusted\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__spin-0.9.8//:spin\", # cfg(any(target_arch = \"aarch64\", target_arch = \"arm\", target_arch = \"x86\", target_arch = \"x86_64\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ring\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.17.8\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@browser_cargo__cc-1.2.18//:cc\",\n ],\n emit_warnings = False,\n edition = \"2021\",\n links = \"ring_core_0_17_8\",\n pkg_name = \"ring\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ring\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.17.8\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__rkyv-0.8.10": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1e147371c75553e1e2fcdb483944a8540b8438c31426279553b9a8182a9b7b65", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rkyv/0.8.10/download" + ], + "strip_prefix": "rkyv-0.8.10", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rkyv\",\n deps = [\n \"@browser_cargo__bytecheck-0.8.1//:bytecheck\",\n \"@browser_cargo__bytes-1.10.1//:bytes\",\n \"@browser_cargo__hashbrown-0.15.2//:hashbrown\",\n \"@browser_cargo__indexmap-2.9.0//:indexmap\",\n \"@browser_cargo__munge-0.4.3//:munge\",\n \"@browser_cargo__ptr_meta-0.3.0//:ptr_meta\",\n \"@browser_cargo__rancor-0.1.0//:rancor\",\n \"@browser_cargo__rend-0.5.2//:rend\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__rkyv_derive-0.8.10//:rkyv_derive\",\n ],\n aliases = {\n \"@browser_cargo__bytes-1.10.1//:bytes\": \"bytes_1\",\n \"@browser_cargo__indexmap-2.9.0//:indexmap\": \"indexmap_2\",\n },\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"bytecheck\",\n \"bytes-1\",\n \"default\",\n \"indexmap-2\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rkyv\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.10\",\n)\n" + } + }, + "browser_cargo__rkyv_derive-0.8.10": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "246b40ac189af6c675d124b802e8ef6d5246c53e17367ce9501f8f66a81abb7a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rkyv_derive/0.8.10/download" + ], + "strip_prefix": "rkyv_derive-0.8.10", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"rkyv_derive\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"bytecheck\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rkyv_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.10\",\n)\n" + } + }, + "browser_cargo__rustc-demangle-0.1.23": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rustc-demangle/0.1.23/download" + ], + "strip_prefix": "rustc-demangle-0.1.23", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rustc_demangle\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustc-demangle\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.23\",\n)\n" + } + }, + "browser_cargo__rustc-hash-1.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rustc-hash/1.1.0/download" + ], + "strip_prefix": "rustc-hash-1.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rustc_hash\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustc-hash\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.0\",\n)\n" + } + }, + "browser_cargo__rustix-0.38.34": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rustix/0.38.34/download" + ], + "strip_prefix": "rustix-0.38.34", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rustix\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__bitflags-2.9.0//:bitflags\",\n ] + select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [\n \"@browser_cargo__errno-0.3.8//:errno\", # cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \"linux\", target_endian = \"little\", any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\")))))))\n \"@browser_cargo__libc-0.2.171//:libc\", # cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \"linux\", target_endian = \"little\", any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\")))))))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__linux-raw-sys-0.4.12//:linux_raw_sys\", # cfg(all(not(rustix_use_libc), not(miri), target_os = \"linux\", target_endian = \"little\", any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\"))))\n ],\n \"//conditions:default\": [],\n }),\n aliases = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": {\n \"@browser_cargo__errno-0.3.8//:errno\": \"libc_errno\", # cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \"linux\", target_endian = \"little\", any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\")))))))\n },\n \"//conditions:default\": {},\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"fs\",\n \"libc-extra-traits\",\n \"std\",\n \"termios\",\n \"use-libc-auxv\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustix\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.38.34\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"fs\",\n \"libc-extra-traits\",\n \"std\",\n \"termios\",\n \"use-libc-auxv\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"rustix\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustix\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.38.34\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__rustls-0.23.25": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rustls/0.23.25/download" + ], + "strip_prefix": "rustls-0.23.25", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rustls\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__once_cell-1.19.0//:once_cell\",\n \"@browser_cargo__rustls-pki-types-1.11.0//:rustls_pki_types\",\n \"@browser_cargo__rustls-webpki-0.103.1//:webpki\",\n \"@browser_cargo__subtle-2.6.1//:subtle\",\n \"@browser_cargo__zeroize-1.8.1//:zeroize\",\n ],\n aliases = {\n \"@browser_cargo__rustls-pki-types-1.11.0//:rustls_pki_types\": \"pki_types\",\n },\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustls\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.23.25\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"rustls\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustls\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.23.25\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__rustls-pemfile-2.1.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rustls-pemfile/2.1.2/download" + ], + "strip_prefix": "rustls-pemfile-2.1.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rustls_pemfile\",\n deps = [\n \"@browser_cargo__base64-0.22.1//:base64\",\n \"@browser_cargo__rustls-pki-types-1.11.0//:rustls_pki_types\",\n ],\n aliases = {\n \"@browser_cargo__rustls-pki-types-1.11.0//:rustls_pki_types\": \"pki_types\",\n },\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustls-pemfile\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.1.2\",\n)\n" + } + }, + "browser_cargo__rustls-pki-types-1.11.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rustls-pki-types/1.11.0/download" + ], + "strip_prefix": "rustls-pki-types-1.11.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rustls_pki_types\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustls-pki-types\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.11.0\",\n)\n" + } + }, + "browser_cargo__rustls-webpki-0.103.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rustls-webpki/0.103.1/download" + ], + "strip_prefix": "rustls-webpki-0.103.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"webpki\",\n deps = [\n \"@browser_cargo__rustls-pki-types-1.11.0//:rustls_pki_types\",\n \"@browser_cargo__untrusted-0.9.0//:untrusted\",\n ],\n aliases = {\n \"@browser_cargo__rustls-pki-types-1.11.0//:rustls_pki_types\": \"pki_types\",\n },\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustls-webpki\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.103.1\",\n)\n" + } + }, + "browser_cargo__rustversion-1.0.20": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rustversion/1.0.20/download" + ], + "strip_prefix": "rustversion-1.0.20", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"rustversion\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustversion\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.20\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build/build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"rustversion\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustversion\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.20\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__ruzstd-0.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ruzstd/0.5.0/download" + ], + "strip_prefix": "ruzstd-0.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ruzstd\",\n deps = [\n \"@browser_cargo__byteorder-1.5.0//:byteorder\",\n \"@browser_cargo__twox-hash-1.6.3//:twox_hash\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__derive_more-0.99.19//:derive_more\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ruzstd\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.0\",\n)\n" + } + }, + "browser_cargo__ryu-1.0.16": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ryu/1.0.16/download" + ], + "strip_prefix": "ryu-1.0.16", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ryu\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ryu\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.16\",\n)\n" + } + }, + "browser_cargo__saffron-0.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "03fb9a628596fc7590eb7edbf7b0613287be78df107f5f97b118aad59fb2eea9", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/saffron/0.1.0/download" + ], + "strip_prefix": "saffron-0.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"saffron\",\n deps = [\n \"@browser_cargo__chrono-0.4.40//:chrono\",\n \"@browser_cargo__nom-5.1.3//:nom\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=saffron\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.0\",\n)\n" + } + }, + "browser_cargo__same-file-1.0.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/same-file/1.0.6/download" + ], + "strip_prefix": "same-file-1.0.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"same_file\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=same-file\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.6\",\n)\n" + } + }, + "browser_cargo__schannel-0.1.23": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/schannel/0.1.23/download" + ], + "strip_prefix": "schannel-0.1.23", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"schannel\",\n deps = [\n \"@browser_cargo__windows-sys-0.52.0//:windows_sys\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=schannel\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.23\",\n)\n" + } + }, + "browser_cargo__schemars-0.8.21": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/schemars/0.8.21/download" + ], + "strip_prefix": "schemars-0.8.21", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"schemars\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__dyn-clone-1.0.17//:dyn_clone\",\n \"@browser_cargo__indexmap-2.9.0//:indexmap\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n \"@browser_cargo__serde_json-1.0.140//:serde_json\",\n \"@browser_cargo__url-2.5.4//:url\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__schemars_derive-0.8.21//:schemars_derive\",\n ],\n aliases = {\n \"@browser_cargo__indexmap-2.9.0//:indexmap\": \"indexmap2\",\n },\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"derive\",\n \"indexmap2\",\n \"schemars_derive\",\n \"url\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=schemars\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.21\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"derive\",\n \"indexmap2\",\n \"schemars_derive\",\n \"url\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"schemars\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=schemars\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.8.21\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__schemars_derive-0.8.21": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/schemars_derive/0.8.21/download" + ], + "strip_prefix": "schemars_derive-0.8.21", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"schemars_derive\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__serde_derive_internals-0.29.1//:serde_derive_internals\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=schemars_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.21\",\n)\n" + } + }, + "browser_cargo__scopeguard-1.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/scopeguard/1.2.0/download" + ], + "strip_prefix": "scopeguard-1.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"scopeguard\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"default\", # x86_64-unknown-linux-gnu\n \"use_std\", # x86_64-unknown-linux-gnu\n ],\n \"//conditions:default\": [],\n }),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=scopeguard\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.0\",\n)\n" + } + }, + "browser_cargo__security-framework-2.10.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/security-framework/2.10.0/download" + ], + "strip_prefix": "security-framework-2.10.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"security_framework\",\n deps = [\n \"@browser_cargo__bitflags-1.3.2//:bitflags\",\n \"@browser_cargo__core-foundation-0.9.4//:core_foundation\",\n \"@browser_cargo__core-foundation-sys-0.8.7//:core_foundation_sys\",\n \"@browser_cargo__libc-0.2.171//:libc\",\n \"@browser_cargo__security-framework-sys-2.14.0//:security_framework_sys\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=security-framework\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.10.0\",\n)\n" + } + }, + "browser_cargo__security-framework-sys-2.14.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/security-framework-sys/2.14.0/download" + ], + "strip_prefix": "security-framework-sys-2.14.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"security_framework_sys\",\n deps = [\n \"@browser_cargo__core-foundation-sys-0.8.7//:core_foundation_sys\",\n \"@browser_cargo__libc-0.2.171//:libc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=security-framework-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.14.0\",\n)\n" + } + }, + "browser_cargo__self_cell-1.0.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "58bf37232d3bb9a2c4e641ca2a11d83b5062066f88df7fed36c28772046d65ba", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/self_cell/1.0.3/download" + ], + "strip_prefix": "self_cell-1.0.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"self_cell\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=self_cell\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.3\",\n)\n" + } + }, + "browser_cargo__semver-1.0.26": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/semver/1.0.26/download" + ], + "strip_prefix": "semver-1.0.26", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"semver\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=semver\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.26\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"serde\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"semver\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=semver\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.26\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__serde-1.0.219": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde/1.0.219/download" + ], + "strip_prefix": "serde-1.0.219", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde\",\n deps = [\n \":build_script_build\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__serde_derive-1.0.219//:serde_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"derive\",\n \"rc\",\n \"serde_derive\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.219\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"derive\",\n \"rc\",\n \"serde_derive\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"serde\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.219\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__serde-wasm-bindgen-0.6.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde-wasm-bindgen/0.6.5/download" + ], + "strip_prefix": "serde-wasm-bindgen-0.6.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde_wasm_bindgen\",\n deps = [\n \"@browser_cargo__js-sys-0.3.78//:js_sys\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n \"@browser_cargo__wasm-bindgen-0.2.101//:wasm_bindgen\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde-wasm-bindgen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.5\",\n)\n" + } + }, + "browser_cargo__serde_bytes-0.11.14": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde_bytes/0.11.14/download" + ], + "strip_prefix": "serde_bytes-0.11.14", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde_bytes\",\n deps = [\n \"@browser_cargo__serde-1.0.219//:serde\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_bytes\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.11.14\",\n)\n" + } + }, + "browser_cargo__serde_derive-1.0.219": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde_derive/1.0.219/download" + ], + "strip_prefix": "serde_derive-1.0.219", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"serde_derive\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.219\",\n)\n" + } + }, + "browser_cargo__serde_derive_internals-0.29.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde_derive_internals/0.29.1/download" + ], + "strip_prefix": "serde_derive_internals-0.29.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde_derive_internals\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_derive_internals\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.29.1\",\n)\n" + } + }, + "browser_cargo__serde_json-1.0.140": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde_json/1.0.140/download" + ], + "strip_prefix": "serde_json-1.0.140", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde_json\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__itoa-1.0.10//:itoa\",\n \"@browser_cargo__memchr-2.7.1//:memchr\",\n \"@browser_cargo__ryu-1.0.16//:ryu\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_json\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.140\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"serde_json\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_json\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.140\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__serde_path_to_error-0.1.17": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde_path_to_error/0.1.17/download" + ], + "strip_prefix": "serde_path_to_error-0.1.17", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde_path_to_error\",\n deps = [\n \"@browser_cargo__itoa-1.0.10//:itoa\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_path_to_error\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.17\",\n)\n" + } + }, + "browser_cargo__serde_spanned-0.6.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde_spanned/0.6.6/download" + ], + "strip_prefix": "serde_spanned-0.6.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde_spanned\",\n deps = [\n \"@browser_cargo__serde-1.0.219//:serde\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"serde\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_spanned\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.6\",\n)\n" + } + }, + "browser_cargo__serde_urlencoded-0.7.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde_urlencoded/0.7.1/download" + ], + "strip_prefix": "serde_urlencoded-0.7.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde_urlencoded\",\n deps = [\n \"@browser_cargo__form_urlencoded-1.2.1//:form_urlencoded\",\n \"@browser_cargo__itoa-1.0.10//:itoa\",\n \"@browser_cargo__ryu-1.0.16//:ryu\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_urlencoded\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.1\",\n)\n" + } + }, + "browser_cargo__serde_yaml-0.9.34-deprecated": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde_yaml/0.9.34+deprecated/download" + ], + "strip_prefix": "serde_yaml-0.9.34+deprecated", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde_yaml\",\n deps = [\n \"@browser_cargo__indexmap-2.9.0//:indexmap\",\n \"@browser_cargo__itoa-1.0.10//:itoa\",\n \"@browser_cargo__ryu-1.0.16//:ryu\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n \"@browser_cargo__unsafe-libyaml-0.2.11//:unsafe_libyaml\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_yaml\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.34+deprecated\",\n)\n" + } + }, + "browser_cargo__sha2-0.10.8": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/sha2/0.10.8/download" + ], + "strip_prefix": "sha2-0.10.8", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"sha2\",\n deps = [\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n \"@browser_cargo__digest-0.10.7//:digest\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__cpufeatures-0.2.12//:cpufeatures\", # cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=sha2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.8\",\n)\n" + } + }, + "browser_cargo__sharded-slab-0.1.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/sharded-slab/0.1.7/download" + ], + "strip_prefix": "sharded-slab-0.1.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"sharded_slab\",\n deps = [\n \"@browser_cargo__lazy_static-1.5.0//:lazy_static\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=sharded-slab\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.7\",\n)\n" + } + }, + "browser_cargo__shared-buffer-0.1.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f6c99835bad52957e7aa241d3975ed17c1e5f8c92026377d117a606f36b84b16", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/shared-buffer/0.1.4/download" + ], + "strip_prefix": "shared-buffer-0.1.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"shared_buffer\",\n deps = [\n \"@browser_cargo__bytes-1.10.1//:bytes\",\n \"@browser_cargo__memmap2-0.6.2//:memmap2\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=shared-buffer\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.4\",\n)\n" + } + }, + "browser_cargo__shlex-1.3.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/shlex/1.3.0/download" + ], + "strip_prefix": "shlex-1.3.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"shlex\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=shlex\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.3.0\",\n)\n" + } + }, + "browser_cargo__simdutf8-0.1.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/simdutf8/0.1.4/download" + ], + "strip_prefix": "simdutf8-0.1.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"simdutf8\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=simdutf8\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.4\",\n)\n" + } + }, + "browser_cargo__similar-2.7.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/similar/2.7.0/download" + ], + "strip_prefix": "similar-2.7.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"similar\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"inline\",\n \"text\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=similar\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.7.0\",\n)\n" + } + }, + "browser_cargo__slab-0.4.9": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/slab/0.4.9/download" + ], + "strip_prefix": "slab-0.4.9", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"slab\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=slab\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.9\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@browser_cargo__autocfg-1.1.0//:autocfg\",\n ],\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"slab\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=slab\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.4.9\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__smallvec-1.13.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/smallvec/1.13.2/download" + ], + "strip_prefix": "smallvec-1.13.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"smallvec\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"const_generics\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"const_new\", # x86_64-unknown-linux-gnu\n ],\n \"//conditions:default\": [],\n }),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=smallvec\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.13.2\",\n)\n" + } + }, + "browser_cargo__smoltcp-0.8.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ee34c1e1bfc7e9206cc0fb8030a90129b4e319ab53856249bb27642cab914fb3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/smoltcp/0.8.2/download" + ], + "strip_prefix": "smoltcp-0.8.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"smoltcp\",\n deps = [\n \"@browser_cargo__bitflags-1.3.2//:bitflags\",\n \"@browser_cargo__byteorder-1.5.0//:byteorder\",\n \"@browser_cargo__managed-0.8.0//:managed\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"proto-ipv4\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=smoltcp\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.2\",\n)\n" + } + }, + "browser_cargo__socket2-0.5.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/socket2/0.5.7/download" + ], + "strip_prefix": "socket2-0.5.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"socket2\",\n deps = select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__libc-0.2.171//:libc\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"all\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=socket2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.7\",\n)\n" + } + }, + "browser_cargo__spin-0.9.8": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/spin/0.9.8/download" + ], + "strip_prefix": "spin-0.9.8", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"spin\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=spin\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.8\",\n)\n" + } + }, + "browser_cargo__stable_deref_trait-1.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/stable_deref_trait/1.2.0/download" + ], + "strip_prefix": "stable_deref_trait-1.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"stable_deref_trait\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=stable_deref_trait\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.0\",\n)\n" + } + }, + "browser_cargo__static_assertions-1.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/static_assertions/1.1.0/download" + ], + "strip_prefix": "static_assertions-1.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"static_assertions\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=static_assertions\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.0\",\n)\n" + } + }, + "browser_cargo__strsim-0.10.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/strsim/0.10.0/download" + ], + "strip_prefix": "strsim-0.10.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"strsim\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=strsim\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.0\",\n)\n" + } + }, + "browser_cargo__subtle-2.6.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/subtle/2.6.1/download" + ], + "strip_prefix": "subtle-2.6.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"subtle\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=subtle\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.6.1\",\n)\n" + } + }, + "browser_cargo__syn-1.0.109": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/syn/1.0.109/download" + ], + "strip_prefix": "syn-1.0.109", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"syn\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__unicode-ident-1.0.12//:unicode_ident\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"clone-impls\",\n \"default\",\n \"derive\",\n \"extra-traits\",\n \"full\",\n \"parsing\",\n \"printing\",\n \"proc-macro\",\n \"quote\",\n \"visit\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=syn\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.109\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"clone-impls\",\n \"default\",\n \"derive\",\n \"extra-traits\",\n \"full\",\n \"parsing\",\n \"printing\",\n \"proc-macro\",\n \"quote\",\n \"visit\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"syn\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=syn\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.109\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__syn-2.0.100": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/syn/2.0.100/download" + ], + "strip_prefix": "syn-2.0.100", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"syn\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__unicode-ident-1.0.12//:unicode_ident\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"clone-impls\",\n \"default\",\n \"derive\",\n \"extra-traits\",\n \"fold\",\n \"full\",\n \"parsing\",\n \"printing\",\n \"proc-macro\",\n \"visit\",\n \"visit-mut\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=syn\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.100\",\n)\n" + } + }, + "browser_cargo__sync_wrapper-1.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/sync_wrapper/1.0.1/download" + ], + "strip_prefix": "sync_wrapper-1.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"sync_wrapper\",\n deps = [\n \"@browser_cargo__futures-core-0.3.31//:futures_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"futures\",\n \"futures-core\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=sync_wrapper\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.1\",\n)\n" + } + }, + "browser_cargo__synstructure-0.13.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/synstructure/0.13.1/download" + ], + "strip_prefix": "synstructure-0.13.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"synstructure\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"proc-macro\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=synstructure\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.13.1\",\n)\n" + } + }, + "browser_cargo__system-configuration-0.6.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/system-configuration/0.6.1/download" + ], + "strip_prefix": "system-configuration-0.6.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"system_configuration\",\n deps = [\n \"@browser_cargo__bitflags-2.9.0//:bitflags\",\n \"@browser_cargo__core-foundation-0.9.4//:core_foundation\",\n \"@browser_cargo__system-configuration-sys-0.6.0//:system_configuration_sys\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=system-configuration\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.1\",\n)\n" + } + }, + "browser_cargo__system-configuration-sys-0.6.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/system-configuration-sys/0.6.0/download" + ], + "strip_prefix": "system-configuration-sys-0.6.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"system_configuration_sys\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__core-foundation-sys-0.8.7//:core_foundation_sys\",\n \"@browser_cargo__libc-0.2.171//:libc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=system-configuration-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"system-configuration-sys\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=system-configuration-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.6.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__tar-0.4.44": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tar/0.4.44/download" + ], + "strip_prefix": "tar-0.4.44", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tar\",\n deps = [\n \"@browser_cargo__filetime-0.2.23//:filetime\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__libc-0.2.171//:libc\", # cfg(unix)\n \"@browser_cargo__xattr-1.2.0//:xattr\", # x86_64-unknown-linux-gnu\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"xattr\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tar\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.44\",\n)\n" + } + }, + "browser_cargo__target-lexicon-0.12.16": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/target-lexicon/0.12.16/download" + ], + "strip_prefix": "target-lexicon-0.12.16", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"target_lexicon\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=target-lexicon\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.12.16\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"target-lexicon\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=target-lexicon\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.12.16\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__tempfile-3.12.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tempfile/3.12.0/download" + ], + "strip_prefix": "tempfile-3.12.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tempfile\",\n deps = [\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n \"@browser_cargo__fastrand-2.0.1//:fastrand\",\n \"@browser_cargo__once_cell-1.19.0//:once_cell\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__rustix-0.38.34//:rustix\", # cfg(any(unix, target_os = \"wasi\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tempfile\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"3.12.0\",\n)\n" + } + }, + "browser_cargo__terminal_size-0.3.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/terminal_size/0.3.0/download" + ], + "strip_prefix": "terminal_size-0.3.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"terminal_size\",\n deps = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [\n \"@browser_cargo__rustix-0.38.34//:rustix\", # cfg(not(windows))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__rustix-0.38.34//:rustix\", # cfg(not(windows))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=terminal_size\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.0\",\n)\n" + } + }, + "browser_cargo__termios-0.3.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/termios/0.3.3/download" + ], + "strip_prefix": "termios-0.3.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"termios\",\n deps = [\n \"@browser_cargo__libc-0.2.171//:libc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=termios\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.3\",\n)\n" + } + }, + "browser_cargo__thiserror-1.0.69": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/thiserror/1.0.69/download" + ], + "strip_prefix": "thiserror-1.0.69", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"thiserror\",\n deps = [\n \":build_script_build\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__thiserror-impl-1.0.69//:thiserror_impl\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=thiserror\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.69\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"thiserror\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=thiserror\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.69\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__thiserror-2.0.12": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/thiserror/2.0.12/download" + ], + "strip_prefix": "thiserror-2.0.12", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"thiserror\",\n deps = [\n \":build_script_build\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__thiserror-impl-2.0.12//:thiserror_impl\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=thiserror\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.12\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"thiserror\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=thiserror\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"2.0.12\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__thiserror-impl-1.0.69": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/thiserror-impl/1.0.69/download" + ], + "strip_prefix": "thiserror-impl-1.0.69", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"thiserror_impl\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=thiserror-impl\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.69\",\n)\n" + } + }, + "browser_cargo__thiserror-impl-2.0.12": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/thiserror-impl/2.0.12/download" + ], + "strip_prefix": "thiserror-impl-2.0.12", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"thiserror_impl\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=thiserror-impl\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.12\",\n)\n" + } + }, + "browser_cargo__thread_local-1.1.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/thread_local/1.1.7/download" + ], + "strip_prefix": "thread_local-1.1.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"thread_local\",\n deps = [\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n \"@browser_cargo__once_cell-1.19.0//:once_cell\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=thread_local\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.7\",\n)\n" + } + }, + "browser_cargo__time-0.3.36": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/time/0.3.36/download" + ], + "strip_prefix": "time-0.3.36", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"time\",\n deps = [\n \"@browser_cargo__deranged-0.3.11//:deranged\",\n \"@browser_cargo__itoa-1.0.10//:itoa\",\n \"@browser_cargo__num-conv-0.1.0//:num_conv\",\n \"@browser_cargo__powerfmt-0.2.0//:powerfmt\",\n \"@browser_cargo__time-core-0.1.2//:time_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"formatting\",\n \"parsing\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=time\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.36\",\n)\n" + } + }, + "browser_cargo__time-core-0.1.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/time-core/0.1.2/download" + ], + "strip_prefix": "time-core-0.1.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"time_core\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=time-core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.2\",\n)\n" + } + }, + "browser_cargo__time-macros-0.2.18": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/time-macros/0.2.18/download" + ], + "strip_prefix": "time-macros-0.2.18", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"time_macros\",\n deps = [\n \"@browser_cargo__num-conv-0.1.0//:num_conv\",\n \"@browser_cargo__time-core-0.1.2//:time_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=time-macros\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.18\",\n)\n" + } + }, + "browser_cargo__tinystr-0.7.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tinystr/0.7.6/download" + ], + "strip_prefix": "tinystr-0.7.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tinystr\",\n deps = [\n \"@browser_cargo__zerovec-0.10.4//:zerovec\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__displaydoc-0.2.5//:displaydoc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"zerovec\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tinystr\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.6\",\n)\n" + } + }, + "browser_cargo__tinyvec-1.6.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tinyvec/1.6.0/download" + ], + "strip_prefix": "tinyvec-1.6.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tinyvec\",\n deps = [\n \"@browser_cargo__tinyvec_macros-0.1.1//:tinyvec_macros\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"tinyvec_macros\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tinyvec\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.6.0\",\n)\n" + } + }, + "browser_cargo__tinyvec_macros-0.1.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tinyvec_macros/0.1.1/download" + ], + "strip_prefix": "tinyvec_macros-0.1.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tinyvec_macros\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tinyvec_macros\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.1\",\n)\n" + } + }, + "browser_cargo__tokio-1.44.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tokio/1.44.2/download" + ], + "strip_prefix": "tokio-1.44.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tokio\",\n deps = [\n \"@browser_cargo__bytes-1.10.1//:bytes\",\n \"@browser_cargo__pin-project-lite-0.2.13//:pin_project_lite\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__libc-0.2.171//:libc\", # x86_64-unknown-linux-gnu\n \"@browser_cargo__mio-1.0.3//:mio\", # x86_64-unknown-linux-gnu\n \"@browser_cargo__socket2-0.5.7//:socket2\", # x86_64-unknown-linux-gnu\n ],\n \"//conditions:default\": [],\n }),\n proc_macro_deps = [\n \"@browser_cargo__tokio-macros-2.5.0//:tokio_macros\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"bytes\",\n \"default\",\n \"io-util\",\n \"macros\",\n \"rt\",\n \"sync\",\n \"time\",\n \"tokio-macros\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"fs\", # x86_64-unknown-linux-gnu\n \"io-std\", # x86_64-unknown-linux-gnu\n \"libc\", # x86_64-unknown-linux-gnu\n \"mio\", # x86_64-unknown-linux-gnu\n \"net\", # x86_64-unknown-linux-gnu\n \"socket2\", # x86_64-unknown-linux-gnu\n ],\n \"//conditions:default\": [],\n }),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tokio\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.44.2\",\n)\n" + } + }, + "browser_cargo__tokio-macros-2.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tokio-macros/2.5.0/download" + ], + "strip_prefix": "tokio-macros-2.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"tokio_macros\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tokio-macros\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.5.0\",\n)\n" + } + }, + "browser_cargo__tokio-native-tls-0.3.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tokio-native-tls/0.3.1/download" + ], + "strip_prefix": "tokio-native-tls-0.3.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tokio_native_tls\",\n deps = [\n \"@browser_cargo__native-tls-0.2.12//:native_tls\",\n \"@browser_cargo__tokio-1.44.2//:tokio\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tokio-native-tls\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.1\",\n)\n" + } + }, + "browser_cargo__tokio-rustls-0.26.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tokio-rustls/0.26.0/download" + ], + "strip_prefix": "tokio-rustls-0.26.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tokio_rustls\",\n deps = [\n \"@browser_cargo__rustls-0.23.25//:rustls\",\n \"@browser_cargo__rustls-pki-types-1.11.0//:rustls_pki_types\",\n \"@browser_cargo__tokio-1.44.2//:tokio\",\n ],\n aliases = {\n \"@browser_cargo__rustls-pki-types-1.11.0//:rustls_pki_types\": \"pki_types\",\n },\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tokio-rustls\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.26.0\",\n)\n" + } + }, + "browser_cargo__tokio-serde-0.9.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "caf600e7036b17782571dd44fa0a5cea3c82f60db5137f774a325a76a0d6852b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tokio-serde/0.9.0/download" + ], + "strip_prefix": "tokio-serde-0.9.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tokio_serde\",\n deps = [\n \"@browser_cargo__bincode-1.3.3//:bincode\",\n \"@browser_cargo__bytes-1.10.1//:bytes\",\n \"@browser_cargo__futures-core-0.3.31//:futures_core\",\n \"@browser_cargo__futures-sink-0.3.31//:futures_sink\",\n \"@browser_cargo__pin-project-1.1.3//:pin_project\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__educe-0.5.11//:educe\",\n ],\n aliases = {\n \"@browser_cargo__bincode-1.3.3//:bincode\": \"bincode_crate\",\n },\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"bincode\",\n \"bincode-crate\",\n \"educe\",\n \"serde\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tokio-serde\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.0\",\n)\n" + } + }, + "browser_cargo__tokio-stream-0.1.15": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tokio-stream/0.1.15/download" + ], + "strip_prefix": "tokio-stream-0.1.15", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tokio_stream\",\n deps = [\n \"@browser_cargo__futures-core-0.3.31//:futures_core\",\n \"@browser_cargo__pin-project-lite-0.2.13//:pin_project_lite\",\n \"@browser_cargo__tokio-1.44.2//:tokio\",\n \"@browser_cargo__tokio-util-0.7.11//:tokio_util\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"sync\",\n \"time\",\n \"tokio-util\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tokio-stream\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.15\",\n)\n" + } + }, + "browser_cargo__tokio-util-0.7.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tokio-util/0.7.11/download" + ], + "strip_prefix": "tokio-util-0.7.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tokio_util\",\n deps = [\n \"@browser_cargo__bytes-1.10.1//:bytes\",\n \"@browser_cargo__futures-core-0.3.31//:futures_core\",\n \"@browser_cargo__futures-sink-0.3.31//:futures_sink\",\n \"@browser_cargo__pin-project-lite-0.2.13//:pin_project_lite\",\n \"@browser_cargo__tokio-1.44.2//:tokio\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"codec\",\n \"default\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"io\", # x86_64-unknown-linux-gnu\n ],\n \"//conditions:default\": [],\n }),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tokio-util\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.11\",\n)\n" + } + }, + "browser_cargo__toml-0.8.14": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/toml/0.8.14/download" + ], + "strip_prefix": "toml-0.8.14", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"toml\",\n deps = [\n \"@browser_cargo__indexmap-2.9.0//:indexmap\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n \"@browser_cargo__serde_spanned-0.6.6//:serde_spanned\",\n \"@browser_cargo__toml_datetime-0.6.6//:toml_datetime\",\n \"@browser_cargo__toml_edit-0.22.14//:toml_edit\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"display\",\n \"indexmap\",\n \"parse\",\n \"preserve_order\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=toml\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.14\",\n)\n" + } + }, + "browser_cargo__toml_datetime-0.6.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/toml_datetime/0.6.6/download" + ], + "strip_prefix": "toml_datetime-0.6.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"toml_datetime\",\n deps = [\n \"@browser_cargo__serde-1.0.219//:serde\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"serde\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=toml_datetime\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.6\",\n)\n" + } + }, + "browser_cargo__toml_edit-0.19.15": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/toml_edit/0.19.15/download" + ], + "strip_prefix": "toml_edit-0.19.15", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"toml_edit\",\n deps = [\n \"@browser_cargo__indexmap-2.9.0//:indexmap\",\n \"@browser_cargo__toml_datetime-0.6.6//:toml_datetime\",\n \"@browser_cargo__winnow-0.5.33//:winnow\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=toml_edit\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.19.15\",\n)\n" + } + }, + "browser_cargo__toml_edit-0.22.14": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/toml_edit/0.22.14/download" + ], + "strip_prefix": "toml_edit-0.22.14", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"toml_edit\",\n deps = [\n \"@browser_cargo__indexmap-2.9.0//:indexmap\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n \"@browser_cargo__serde_spanned-0.6.6//:serde_spanned\",\n \"@browser_cargo__toml_datetime-0.6.6//:toml_datetime\",\n \"@browser_cargo__winnow-0.6.13//:winnow\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"display\",\n \"parse\",\n \"serde\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=toml_edit\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.22.14\",\n)\n" + } + }, + "browser_cargo__tower-0.4.13": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tower/0.4.13/download" + ], + "strip_prefix": "tower-0.4.13", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tower\",\n deps = [\n \"@browser_cargo__futures-core-0.3.31//:futures_core\",\n \"@browser_cargo__futures-util-0.3.31//:futures_util\",\n \"@browser_cargo__pin-project-1.1.3//:pin_project\",\n \"@browser_cargo__pin-project-lite-0.2.13//:pin_project_lite\",\n \"@browser_cargo__tokio-1.44.2//:tokio\",\n \"@browser_cargo__tower-layer-0.3.2//:tower_layer\",\n \"@browser_cargo__tower-service-0.3.2//:tower_service\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"__common\",\n \"futures-core\",\n \"futures-util\",\n \"make\",\n \"pin-project\",\n \"pin-project-lite\",\n \"tokio\",\n \"util\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tower\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.13\",\n)\n" + } + }, + "browser_cargo__tower-layer-0.3.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tower-layer/0.3.2/download" + ], + "strip_prefix": "tower-layer-0.3.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tower_layer\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tower-layer\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.2\",\n)\n" + } + }, + "browser_cargo__tower-service-0.3.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tower-service/0.3.2/download" + ], + "strip_prefix": "tower-service-0.3.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tower_service\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tower-service\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.2\",\n)\n" + } + }, + "browser_cargo__tracing-0.1.41": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tracing/0.1.41/download" + ], + "strip_prefix": "tracing-0.1.41", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tracing\",\n deps = [\n \"@browser_cargo__log-0.4.20//:log\",\n \"@browser_cargo__pin-project-lite-0.2.13//:pin_project_lite\",\n \"@browser_cargo__tracing-core-0.1.33//:tracing_core\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__tracing-attributes-0.1.28//:tracing_attributes\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"attributes\",\n \"default\",\n \"log\",\n \"release_max_level_debug\",\n \"std\",\n \"tracing-attributes\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tracing\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.41\",\n)\n" + } + }, + "browser_cargo__tracing-attributes-0.1.28": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tracing-attributes/0.1.28/download" + ], + "strip_prefix": "tracing-attributes-0.1.28", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"tracing_attributes\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tracing-attributes\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.28\",\n)\n" + } + }, + "browser_cargo__tracing-core-0.1.33": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tracing-core/0.1.33/download" + ], + "strip_prefix": "tracing-core-0.1.33", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tracing_core\",\n deps = [\n \"@browser_cargo__once_cell-1.19.0//:once_cell\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"once_cell\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tracing-core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.33\",\n)\n" + } + }, + "browser_cargo__tracing-log-0.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tracing-log/0.2.0/download" + ], + "strip_prefix": "tracing-log-0.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tracing_log\",\n deps = [\n \"@browser_cargo__log-0.4.20//:log\",\n \"@browser_cargo__once_cell-1.19.0//:once_cell\",\n \"@browser_cargo__tracing-core-0.1.33//:tracing_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"log-tracer\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tracing-log\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.0\",\n)\n" + } + }, + "browser_cargo__tracing-subscriber-0.3.18": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tracing-subscriber/0.3.18/download" + ], + "strip_prefix": "tracing-subscriber-0.3.18", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tracing_subscriber\",\n deps = [\n \"@browser_cargo__matchers-0.1.0//:matchers\",\n \"@browser_cargo__nu-ansi-term-0.46.0//:nu_ansi_term\",\n \"@browser_cargo__once_cell-1.19.0//:once_cell\",\n \"@browser_cargo__regex-1.10.2//:regex\",\n \"@browser_cargo__sharded-slab-0.1.7//:sharded_slab\",\n \"@browser_cargo__smallvec-1.13.2//:smallvec\",\n \"@browser_cargo__thread_local-1.1.7//:thread_local\",\n \"@browser_cargo__tracing-0.1.41//:tracing\",\n \"@browser_cargo__tracing-core-0.1.33//:tracing_core\",\n \"@browser_cargo__tracing-log-0.2.0//:tracing_log\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"ansi\",\n \"default\",\n \"env-filter\",\n \"fmt\",\n \"matchers\",\n \"nu-ansi-term\",\n \"once_cell\",\n \"regex\",\n \"registry\",\n \"sharded-slab\",\n \"smallvec\",\n \"std\",\n \"thread_local\",\n \"tracing\",\n \"tracing-log\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tracing-subscriber\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.18\",\n)\n" + } + }, + "browser_cargo__try-lock-0.2.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/try-lock/0.2.5/download" + ], + "strip_prefix": "try-lock-0.2.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"try_lock\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=try-lock\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.5\",\n)\n" + } + }, + "browser_cargo__twox-hash-1.6.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/twox-hash/1.6.3/download" + ], + "strip_prefix": "twox-hash-1.6.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"twox_hash\",\n deps = [\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n \"@browser_cargo__static_assertions-1.1.0//:static_assertions\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=twox-hash\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.6.3\",\n)\n" + } + }, + "browser_cargo__typenum-1.17.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/typenum/1.17.0/download" + ], + "strip_prefix": "typenum-1.17.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"typenum\",\n deps = [\n \":build_script_main\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=typenum\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.17.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_main\",\n crate_root = \"build/main.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"typenum\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=typenum\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.17.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_main\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__unicase-2.7.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unicase/2.7.0/download" + ], + "strip_prefix": "unicase-2.7.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unicase\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unicase\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.7.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@browser_cargo__version_check-0.9.5//:version_check\",\n ],\n emit_warnings = False,\n edition = \"2015\",\n pkg_name = \"unicase\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unicase\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"2.7.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__unicode-ident-1.0.12": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unicode-ident/1.0.12/download" + ], + "strip_prefix": "unicode-ident-1.0.12", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unicode_ident\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unicode-ident\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.12\",\n)\n" + } + }, + "browser_cargo__unicode-normalization-0.1.22": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unicode-normalization/0.1.22/download" + ], + "strip_prefix": "unicode-normalization-0.1.22", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unicode_normalization\",\n deps = [\n \"@browser_cargo__tinyvec-1.6.0//:tinyvec\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unicode-normalization\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.22\",\n)\n" + } + }, + "browser_cargo__unicode-segmentation-1.10.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unicode-segmentation/1.10.1/download" + ], + "strip_prefix": "unicode-segmentation-1.10.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unicode_segmentation\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unicode-segmentation\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.10.1\",\n)\n" + } + }, + "browser_cargo__unicode-width-0.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unicode-width/0.2.0/download" + ], + "strip_prefix": "unicode-width-0.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unicode_width\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"cjk\",\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unicode-width\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.0\",\n)\n" + } + }, + "browser_cargo__unicode-xid-0.2.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unicode-xid/0.2.4/download" + ], + "strip_prefix": "unicode-xid-0.2.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unicode_xid\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unicode-xid\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.4\",\n)\n" + } + }, + "browser_cargo__unsafe-libyaml-0.2.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unsafe-libyaml/0.2.11/download" + ], + "strip_prefix": "unsafe-libyaml-0.2.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unsafe_libyaml\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unsafe-libyaml\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.11\",\n)\n" + } + }, + "browser_cargo__untrusted-0.9.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/untrusted/0.9.0/download" + ], + "strip_prefix": "untrusted-0.9.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"untrusted\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=untrusted\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.0\",\n)\n" + } + }, + "browser_cargo__url-2.5.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/url/2.5.4/download" + ], + "strip_prefix": "url-2.5.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"url\",\n deps = [\n \"@browser_cargo__form_urlencoded-1.2.1//:form_urlencoded\",\n \"@browser_cargo__idna-1.0.3//:idna\",\n \"@browser_cargo__percent-encoding-2.3.1//:percent_encoding\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=url\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.5.4\",\n)\n" + } + }, + "browser_cargo__urlencoding-2.1.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/urlencoding/2.1.3/download" + ], + "strip_prefix": "urlencoding-2.1.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"urlencoding\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=urlencoding\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.1.3\",\n)\n" + } + }, + "browser_cargo__utf16_iter-1.0.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/utf16_iter/1.0.5/download" + ], + "strip_prefix": "utf16_iter-1.0.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"utf16_iter\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=utf16_iter\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.5\",\n)\n" + } + }, + "browser_cargo__utf8_iter-1.0.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/utf8_iter/1.0.4/download" + ], + "strip_prefix": "utf8_iter-1.0.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"utf8_iter\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=utf8_iter\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.4\",\n)\n" + } + }, + "browser_cargo__uuid-1.9.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/uuid/1.9.1/download" + ], + "strip_prefix": "uuid-1.9.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"uuid\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=uuid\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.9.1\",\n)\n" + } + }, + "browser_cargo__valuable-0.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/valuable/0.1.0/download" + ], + "strip_prefix": "valuable-0.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"valuable\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=valuable\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"valuable\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=valuable\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.1.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__vcpkg-0.2.15": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/vcpkg/0.2.15/download" + ], + "strip_prefix": "vcpkg-0.2.15", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"vcpkg\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=vcpkg\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.15\",\n)\n" + } + }, + "browser_cargo__version_check-0.9.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/version_check/0.9.5/download" + ], + "strip_prefix": "version_check-0.9.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"version_check\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=version_check\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.5\",\n)\n" + } + }, + "browser_cargo__virtual-fs-0.601.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [ + "@@//src/wasix/browser-host:patches/0036-virtual-fs-poll-contended-pipe-reads.patch" + ], + "remote_patch_strip": 1, + "sha256": "8defc513ce70576bdbb4305ee67c0cba647af18c0995de8f1fa1271b724c9859", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/virtual-fs/virtual-fs-0.601.0.crate" + ], + "strip_prefix": "virtual-fs-0.601.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"virtual_fs\",\n deps = [\n \"@browser_cargo__anyhow-1.0.97//:anyhow\",\n \"@browser_cargo__bytes-1.10.1//:bytes\",\n \"@browser_cargo__dashmap-6.1.0//:dashmap\",\n \"@browser_cargo__derive_more-2.0.1//:derive_more\",\n \"@browser_cargo__dunce-1.0.5//:dunce\",\n \"@browser_cargo__futures-0.3.30//:futures\",\n \"@browser_cargo__getrandom-0.2.15//:getrandom\",\n \"@browser_cargo__indexmap-2.9.0//:indexmap\",\n \"@browser_cargo__pin-project-lite-0.2.13//:pin_project_lite\",\n \"@browser_cargo__replace_with-0.1.7//:replace_with\",\n \"@browser_cargo__shared-buffer-0.1.4//:shared_buffer\",\n \"@browser_cargo__slab-0.4.9//:slab\",\n \"@browser_cargo__thiserror-1.0.69//:thiserror\",\n \"@browser_cargo__tokio-1.44.2//:tokio\",\n \"@browser_cargo__tracing-0.1.41//:tracing\",\n \"@browser_cargo__virtual-mio-0.601.0//:virtual_mio\",\n \"@browser_cargo__wasmer-package-0.601.0//:wasmer_package\",\n \"@browser_cargo__web-time-1.1.0//:web_time\",\n \"@browser_cargo__webc-10.0.1//:webc\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__async-trait-0.1.88//:async_trait\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"anyhow\",\n \"js\",\n \"webc\",\n \"webc-fs\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=virtual-fs\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.601.0\",\n)\n" + } + }, + "browser_cargo__virtual-mio-0.601.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [ + "@@//src/wasix/browser-host:patches/0037-virtual-mio-retain-inline-wakes.patch" + ], + "remote_patch_strip": 1, + "sha256": "a14806a3f25b70315764760c376d9f68937f5467013891bc7497a33d24105097", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/virtual-mio/virtual-mio-0.601.0.crate" + ], + "strip_prefix": "virtual-mio-0.601.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"virtual_mio\",\n deps = [\n \"@browser_cargo__bytes-1.10.1//:bytes\",\n \"@browser_cargo__futures-0.3.30//:futures\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n \"@browser_cargo__thiserror-1.0.69//:thiserror\",\n \"@browser_cargo__tracing-0.1.41//:tracing\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__async-trait-0.1.88//:async_trait\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=virtual-mio\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.601.0\",\n)\n" + } + }, + "browser_cargo__virtual-net-0.601.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0a7dccbe5d8d3a49e2b43a2c5a4287139e33ba04c03279bfc8a0aef82def2043", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/virtual-net/0.601.0/download" + ], + "strip_prefix": "virtual-net-0.601.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"virtual_net\",\n deps = [\n \"@browser_cargo__anyhow-1.0.97//:anyhow\",\n \"@browser_cargo__base64-0.22.1//:base64\",\n \"@browser_cargo__bincode-1.3.3//:bincode\",\n \"@browser_cargo__bytecheck-0.6.11//:bytecheck\",\n \"@browser_cargo__bytes-1.10.1//:bytes\",\n \"@browser_cargo__derive_more-2.0.1//:derive_more\",\n \"@browser_cargo__futures-util-0.3.31//:futures_util\",\n \"@browser_cargo__ipnet-2.11.0//:ipnet\",\n \"@browser_cargo__iprange-0.6.7//:iprange\",\n \"@browser_cargo__libc-0.2.171//:libc\",\n \"@browser_cargo__pin-project-lite-0.2.13//:pin_project_lite\",\n \"@browser_cargo__rkyv-0.8.10//:rkyv\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n \"@browser_cargo__smoltcp-0.8.2//:smoltcp\",\n \"@browser_cargo__thiserror-1.0.69//:thiserror\",\n \"@browser_cargo__tokio-1.44.2//:tokio\",\n \"@browser_cargo__tokio-serde-0.9.0//:tokio_serde\",\n \"@browser_cargo__tokio-util-0.7.11//:tokio_util\",\n \"@browser_cargo__tracing-0.1.41//:tracing\",\n \"@browser_cargo__virtual-mio-0.601.0//:virtual_mio\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__async-trait-0.1.88//:async_trait\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"libc\",\n \"remote\",\n \"rkyv\",\n \"tokio-serde\",\n \"tokio-util\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=virtual-net\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.601.0\",\n)\n" + } + }, + "browser_cargo__wai-bindgen-gen-core-0.2.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1aa3dc41b510811122b3088197234c27e08fcad63ef936306dd8e11e2803876c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wai-bindgen-gen-core/0.2.3/download" + ], + "strip_prefix": "wai-bindgen-gen-core-0.2.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wai_bindgen_gen_core\",\n deps = [\n \"@browser_cargo__anyhow-1.0.97//:anyhow\",\n \"@browser_cargo__wai-parser-0.2.3//:wai_parser\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wai-bindgen-gen-core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.3\",\n)\n" + } + }, + "browser_cargo__wai-bindgen-gen-rust-0.2.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "19bc05e8380515c4337c40ef03b2ff233e391315b178a320de8640703d522efe", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wai-bindgen-gen-rust/0.2.3/download" + ], + "strip_prefix": "wai-bindgen-gen-rust-0.2.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wai_bindgen_gen_rust\",\n deps = [\n \"@browser_cargo__heck-0.3.3//:heck\",\n \"@browser_cargo__wai-bindgen-gen-core-0.2.3//:wai_bindgen_gen_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wai-bindgen-gen-rust\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.3\",\n)\n" + } + }, + "browser_cargo__wai-bindgen-gen-rust-wasm-0.2.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d6f35ce5e74086fac87f3a7bd50f643f00fe3559adb75c88521ecaa01c8a6199", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wai-bindgen-gen-rust-wasm/0.2.3/download" + ], + "strip_prefix": "wai-bindgen-gen-rust-wasm-0.2.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wai_bindgen_gen_rust_wasm\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__heck-0.3.3//:heck\",\n \"@browser_cargo__wai-bindgen-gen-core-0.2.3//:wai_bindgen_gen_core\",\n \"@browser_cargo__wai-bindgen-gen-rust-0.2.3//:wai_bindgen_gen_rust\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wai-bindgen-gen-rust-wasm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.3\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"wai-bindgen-gen-rust-wasm\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wai-bindgen-gen-rust-wasm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.2.3\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__wai-bindgen-rust-0.2.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4e5601c6f448c063e83a5e931b8fefcdf7e01ada424ad42372c948d2e3d67741", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wai-bindgen-rust/0.2.3/download" + ], + "strip_prefix": "wai-bindgen-rust-0.2.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wai_bindgen_rust\",\n deps = [\n \"@browser_cargo__bitflags-1.3.2//:bitflags\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__wai-bindgen-rust-impl-0.2.3//:wai_bindgen_rust_impl\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"macros\",\n \"wai-bindgen-rust-impl\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wai-bindgen-rust\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.3\",\n)\n" + } + }, + "browser_cargo__wai-bindgen-rust-impl-0.2.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bdeeb5c1170246de8425a3e123e7ef260dc05ba2b522a1d369fe2315376efea4", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wai-bindgen-rust-impl/0.2.3/download" + ], + "strip_prefix": "wai-bindgen-rust-impl-0.2.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"wai_bindgen_rust_impl\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__syn-1.0.109//:syn\",\n \"@browser_cargo__wai-bindgen-gen-core-0.2.3//:wai_bindgen_gen_core\",\n \"@browser_cargo__wai-bindgen-gen-rust-wasm-0.2.3//:wai_bindgen_gen_rust_wasm\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wai-bindgen-rust-impl\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.3\",\n)\n" + } + }, + "browser_cargo__wai-parser-0.2.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9bd0acb6d70885ea0c343749019ba74f015f64a9d30542e66db69b49b7e28186", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wai-parser/0.2.3/download" + ], + "strip_prefix": "wai-parser-0.2.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wai_parser\",\n deps = [\n \"@browser_cargo__anyhow-1.0.97//:anyhow\",\n \"@browser_cargo__id-arena-2.2.1//:id_arena\",\n \"@browser_cargo__pulldown-cmark-0.8.0//:pulldown_cmark\",\n \"@browser_cargo__unicode-normalization-0.1.22//:unicode_normalization\",\n \"@browser_cargo__unicode-xid-0.2.4//:unicode_xid\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wai-parser\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.3\",\n)\n" + } + }, + "browser_cargo__waker-fn-1.1.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/waker-fn/1.1.1/download" + ], + "strip_prefix": "waker-fn-1.1.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"waker_fn\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=waker-fn\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.1\",\n)\n" + } + }, + "browser_cargo__walkdir-2.4.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/walkdir/2.4.0/download" + ], + "strip_prefix": "walkdir-2.4.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"walkdir\",\n deps = [\n \"@browser_cargo__same-file-1.0.6//:same_file\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=walkdir\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.4.0\",\n)\n" + } + }, + "browser_cargo__want-0.3.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/want/0.3.1/download" + ], + "strip_prefix": "want-0.3.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"want\",\n deps = [\n \"@browser_cargo__try-lock-0.2.5//:try_lock\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=want\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.1\",\n)\n" + } + }, + "browser_cargo__wasi-0.11.0-wasi-snapshot-preview1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasi/0.11.0+wasi-snapshot-preview1/download" + ], + "strip_prefix": "wasi-0.11.0+wasi-snapshot-preview1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasi\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasi\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.11.0+wasi-snapshot-preview1\",\n)\n" + } + }, + "browser_cargo__wasm-bindgen-0.2.101": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-bindgen/0.2.101/download" + ], + "strip_prefix": "wasm-bindgen-0.2.101", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasm_bindgen\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n \"@browser_cargo__once_cell-1.19.0//:once_cell\",\n \"@browser_cargo__wasm-bindgen-shared-0.2.101//:wasm_bindgen_shared\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__rustversion-1.0.20//:rustversion\",\n \"@browser_cargo__wasm-bindgen-macro-0.2.101//:wasm_bindgen_macro\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"msrv\",\n \"rustversion\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.101\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"msrv\",\n \"rustversion\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n link_deps = [\n \"@browser_cargo__wasm-bindgen-shared-0.2.101//:wasm_bindgen_shared\",\n ],\n edition = \"2021\",\n pkg_name = \"wasm-bindgen\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.2.101\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__wasm-bindgen-backend-0.2.101": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-bindgen-backend/0.2.101/download" + ], + "strip_prefix": "wasm-bindgen-backend-0.2.101", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasm_bindgen_backend\",\n deps = [\n \"@browser_cargo__bumpalo-3.14.0//:bumpalo\",\n \"@browser_cargo__log-0.4.20//:log\",\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n \"@browser_cargo__wasm-bindgen-shared-0.2.101//:wasm_bindgen_shared\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen-backend\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.101\",\n)\n" + } + }, + "browser_cargo__wasm-bindgen-derive-0.2.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c1ab6c8bffb3f89584781211283fb57337d6902faab6eaee38f336977bdf177d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-bindgen-derive/0.2.1/download" + ], + "strip_prefix": "wasm-bindgen-derive-0.2.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasm_bindgen_derive\",\n deps = [\n \"@browser_cargo__js-sys-0.3.78//:js_sys\",\n \"@browser_cargo__wasm-bindgen-0.2.101//:wasm_bindgen\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__wasm-bindgen-derive-macro-0.2.1//:wasm_bindgen_derive_macro\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen-derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.1\",\n)\n" + } + }, + "browser_cargo__wasm-bindgen-derive-macro-0.2.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b87c28b31d27616bc69a891700ef0445d2cbaa0340fdacb145145256d5f5fcbb", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-bindgen-derive-macro/0.2.1/download" + ], + "strip_prefix": "wasm-bindgen-derive-macro-0.2.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"wasm_bindgen_derive_macro\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-1.0.109//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen-derive-macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.1\",\n)\n" + } + }, + "browser_cargo__wasm-bindgen-futures-0.4.51": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0ca85039a9b469b38336411d6d6ced91f3fc87109a2a27b0c197663f5144dffe", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-bindgen-futures/0.4.51/download" + ], + "strip_prefix": "wasm-bindgen-futures-0.4.51", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasm_bindgen_futures\",\n deps = [\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n \"@browser_cargo__js-sys-0.3.78//:js_sys\",\n \"@browser_cargo__once_cell-1.19.0//:once_cell\",\n \"@browser_cargo__wasm-bindgen-0.2.101//:wasm_bindgen\",\n ] + select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [\n \"@browser_cargo__web-sys-0.3.78//:web_sys\", # wasm32-unknown-unknown\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen-futures\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.51\",\n)\n" + } + }, + "browser_cargo__wasm-bindgen-macro-0.2.101": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-bindgen-macro/0.2.101/download" + ], + "strip_prefix": "wasm-bindgen-macro-0.2.101", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"wasm_bindgen_macro\",\n deps = [\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__wasm-bindgen-macro-support-0.2.101//:wasm_bindgen_macro_support\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen-macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.101\",\n)\n" + } + }, + "browser_cargo__wasm-bindgen-macro-support-0.2.101": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-bindgen-macro-support/0.2.101/download" + ], + "strip_prefix": "wasm-bindgen-macro-support-0.2.101", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasm_bindgen_macro_support\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n \"@browser_cargo__wasm-bindgen-backend-0.2.101//:wasm_bindgen_backend\",\n \"@browser_cargo__wasm-bindgen-shared-0.2.101//:wasm_bindgen_shared\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen-macro-support\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.101\",\n)\n" + } + }, + "browser_cargo__wasm-bindgen-shared-0.2.101": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-bindgen-shared/0.2.101/download" + ], + "strip_prefix": "wasm-bindgen-shared-0.2.101", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasm_bindgen_shared\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__unicode-ident-1.0.12//:unicode_ident\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen-shared\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.101\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n links = \"wasm_bindgen\",\n pkg_name = \"wasm-bindgen-shared\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen-shared\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.2.101\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__wasm-bindgen-test-0.3.51": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "80cc7f8a4114fdaa0c58383caf973fc126cf004eba25c9dc639bccd3880d55ad", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-bindgen-test/0.3.51/download" + ], + "strip_prefix": "wasm-bindgen-test-0.3.51", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasm_bindgen_test\",\n deps = [\n \"@browser_cargo__js-sys-0.3.78//:js_sys\",\n \"@browser_cargo__wasm-bindgen-0.2.101//:wasm_bindgen\",\n \"@browser_cargo__wasm-bindgen-futures-0.4.51//:wasm_bindgen_futures\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__wasm-bindgen-test-macro-0.3.51//:wasm_bindgen_test_macro\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen-test\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.51\",\n)\n" + } + }, + "browser_cargo__wasm-bindgen-test-macro-0.3.51": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c5ada2ab788d46d4bda04c9d567702a79c8ced14f51f221646a16ed39d0e6a5d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-bindgen-test-macro/0.3.51/download" + ], + "strip_prefix": "wasm-bindgen-test-macro-0.3.51", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"wasm_bindgen_test_macro\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen-test-macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.51\",\n)\n" + } + }, + "browser_cargo__wasm-encoder-0.221.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "dc8444fe4920de80a4fe5ab564fff2ae58b6b73166b89751f8c6c93509da32e5", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-encoder/0.221.3/download" + ], + "strip_prefix": "wasm-encoder-0.221.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasm_encoder\",\n deps = [\n \"@browser_cargo__leb128-0.2.5//:leb128\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"component-model\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-encoder\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.221.3\",\n)\n" + } + }, + "browser_cargo__wasm-encoder-0.235.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b3bc393c395cb621367ff02d854179882b9a351b4e0c93d1397e6090b53a5c2a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-encoder/0.235.0/download" + ], + "strip_prefix": "wasm-encoder-0.235.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasm_encoder\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__leb128fmt-0.1.0//:leb128fmt\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-encoder\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.235.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"wasm-encoder\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-encoder\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.235.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__wasm-streams-0.4.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-streams/0.4.0/download" + ], + "strip_prefix": "wasm-streams-0.4.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasm_streams\",\n deps = [\n \"@browser_cargo__futures-util-0.3.31//:futures_util\",\n \"@browser_cargo__js-sys-0.3.78//:js_sys\",\n \"@browser_cargo__wasm-bindgen-0.2.101//:wasm_bindgen\",\n \"@browser_cargo__wasm-bindgen-futures-0.4.51//:wasm_bindgen_futures\",\n \"@browser_cargo__web-sys-0.3.78//:web_sys\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-streams\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.0\",\n)\n" + } + }, + "browser_cargo__wasmer-6.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [ + "@@//src/wasix/browser-host:patches/0008-wasmer-instantiate-js-modules-async.patch", + "@@//src/wasix/browser-host:patches/0019-wasmer-parse-exception-reference-types.patch" + ], + "remote_patch_strip": 1, + "sha256": "2d85671948f8886a1cc946141c0b688a5617603c103699a5fceeebeb4e75b0b6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasmer/wasmer-6.1.0.crate" + ], + "strip_prefix": "wasmer-6.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__bytes-1.10.1//:bytes\",\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n \"@browser_cargo__derive_more-2.0.1//:derive_more\",\n \"@browser_cargo__indexmap-2.9.0//:indexmap\",\n \"@browser_cargo__js-sys-0.3.78//:js_sys\",\n \"@browser_cargo__more-asserts-0.2.2//:more_asserts\",\n \"@browser_cargo__rustc-demangle-0.1.23//:rustc_demangle\",\n \"@browser_cargo__shared-buffer-0.1.4//:shared_buffer\",\n \"@browser_cargo__thiserror-1.0.69//:thiserror\",\n \"@browser_cargo__tracing-0.1.41//:tracing\",\n \"@browser_cargo__wasm-bindgen-0.2.101//:wasm_bindgen\",\n \"@browser_cargo__wasmer-compiler-6.1.0//:wasmer_compiler\",\n \"@browser_cargo__wasmparser-0.224.1//:wasmparser\",\n \"@browser_cargo__wat-1.221.3//:wat\",\n ] + select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [\n \"@browser_cargo__serde-1.0.219//:serde\", # cfg(target_arch = \"wasm32\")\n \"@browser_cargo__serde-wasm-bindgen-0.6.5//:serde_wasm_bindgen\", # cfg(target_arch = \"wasm32\")\n \"@browser_cargo__target-lexicon-0.12.16//:target_lexicon\", # cfg(target_arch = \"wasm32\")\n \"@browser_cargo__wasm-bindgen-futures-0.4.51//:wasm_bindgen_futures\", # cfg(target_arch = \"wasm32\")\n \"@browser_cargo__wasmer-types-6.1.0//:wasmer_types\", # cfg(target_arch = \"wasm32\")\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__target-lexicon-0.12.16//:target_lexicon\", # cfg(not(target_arch = \"wasm32\"))\n \"@browser_cargo__wasmer-types-6.1.0//:wasmer_types\", # cfg(not(target_arch = \"wasm32\"))\n \"@browser_cargo__wasmer-vm-6.1.0//:wasmer_vm\", # x86_64-unknown-linux-gnu\n ],\n \"//conditions:default\": [],\n }),\n proc_macro_deps = [\n \"@browser_cargo__paste-1.0.15//:paste\",\n ] + select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [\n \"@browser_cargo__wasmer-derive-6.1.0//:wasmer_derive\", # cfg(target_arch = \"wasm32\")\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__wasmer-derive-6.1.0//:wasmer_derive\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"enable-serde\",\n \"js\",\n \"js-default\",\n \"js-serializable-module\",\n \"js-sys\",\n \"std\",\n \"wasm-bindgen\",\n \"wasm-types-polyfill\",\n \"wasmparser\",\n \"wat\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"6.1.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"enable-serde\",\n \"js\",\n \"js-default\",\n \"js-serializable-module\",\n \"js-sys\",\n \"std\",\n \"wasm-bindgen\",\n \"wasm-types-polyfill\",\n \"wasmparser\",\n \"wat\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@browser_cargo__cmake-0.1.54//:cmake\",\n \"@browser_cargo__tar-0.4.44//:tar\",\n ] + select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [\n \"@browser_cargo__bindgen-0.70.1//:bindgen\", # cfg(not(target_env = \"musl\"))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__bindgen-0.70.1//:bindgen\", # cfg(not(target_env = \"musl\"))\n ],\n \"//conditions:default\": [],\n }),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"wasmer\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"6.1.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__wasmer-backend-api-0.601.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ef123baf425c415c1538fcf6da66d030c69d47ee8a9acc063e9f7b890c7ec893", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasmer-backend-api/0.601.0/download" + ], + "strip_prefix": "wasmer-backend-api-0.601.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_backend_api\",\n deps = [\n \"@browser_cargo__anyhow-1.0.97//:anyhow\",\n \"@browser_cargo__cynic-3.10.0//:cynic\",\n \"@browser_cargo__futures-0.3.30//:futures\",\n \"@browser_cargo__harsh-0.2.2//:harsh\",\n \"@browser_cargo__merge-streams-0.1.2//:merge_streams\",\n \"@browser_cargo__pin-project-lite-0.2.13//:pin_project_lite\",\n \"@browser_cargo__reqwest-0.12.7//:reqwest\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n \"@browser_cargo__serde_json-1.0.140//:serde_json\",\n \"@browser_cargo__serde_path_to_error-0.1.17//:serde_path_to_error\",\n \"@browser_cargo__time-0.3.36//:time\",\n \"@browser_cargo__tokio-1.44.2//:tokio\",\n \"@browser_cargo__tracing-0.1.41//:tracing\",\n \"@browser_cargo__url-2.5.4//:url\",\n \"@browser_cargo__wasmer-config-0.601.0//:wasmer_config\",\n \"@browser_cargo__wasmer-package-0.601.0//:wasmer_package\",\n \"@browser_cargo__webc-10.0.1//:webc\",\n ] + select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [\n \"@browser_cargo__getrandom-0.2.15//:getrandom\", # cfg(target_family = \"wasm\")\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"js\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-backend-api\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.601.0\",\n)\n" + } + }, + "browser_cargo__wasmer-compiler-6.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4946475adc0af265af8f10aadf4d4a3c64845bcd3801c655bdd81ce5e3ee869b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasmer-compiler/6.1.0/download" + ], + "strip_prefix": "wasmer-compiler-6.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_compiler\",\n deps = [\n \"@browser_cargo__backtrace-0.3.69//:backtrace\",\n \"@browser_cargo__bytes-1.10.1//:bytes\",\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n \"@browser_cargo__enum-iterator-0.7.0//:enum_iterator\",\n \"@browser_cargo__enumset-1.1.3//:enumset\",\n \"@browser_cargo__leb128-0.2.5//:leb128\",\n \"@browser_cargo__libc-0.2.171//:libc\",\n \"@browser_cargo__memmap2-0.6.2//:memmap2\",\n \"@browser_cargo__more-asserts-0.2.2//:more_asserts\",\n \"@browser_cargo__object-0.32.2//:object\",\n \"@browser_cargo__rkyv-0.8.10//:rkyv\",\n \"@browser_cargo__self_cell-1.0.3//:self_cell\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n \"@browser_cargo__serde_bytes-0.11.14//:serde_bytes\",\n \"@browser_cargo__shared-buffer-0.1.4//:shared_buffer\",\n \"@browser_cargo__smallvec-1.13.2//:smallvec\",\n \"@browser_cargo__target-lexicon-0.12.16//:target_lexicon\",\n \"@browser_cargo__thiserror-1.0.69//:thiserror\",\n \"@browser_cargo__wasmer-types-6.1.0//:wasmer_types\",\n \"@browser_cargo__xxhash-rust-0.8.11//:xxhash_rust\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__region-3.0.2//:region\", # cfg(not(target_arch = \"wasm32\"))\n \"@browser_cargo__wasmer-vm-6.1.0//:wasmer_vm\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"enable-serde\",\n \"serde\",\n \"serde_bytes\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-compiler\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"6.1.0\",\n)\n" + } + }, + "browser_cargo__wasmer-config-0.601.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f6c7a72bfcba1000b7609e034e0d470575fae8215b597c2c6554661729d64c22", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasmer-config/0.601.0/download" + ], + "strip_prefix": "wasmer-config-0.601.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_config\",\n deps = [\n \"@browser_cargo__anyhow-1.0.97//:anyhow\",\n \"@browser_cargo__bytesize-1.3.0//:bytesize\",\n \"@browser_cargo__ciborium-0.2.2//:ciborium\",\n \"@browser_cargo__derive_builder-0.12.0//:derive_builder\",\n \"@browser_cargo__hex-0.4.3//:hex\",\n \"@browser_cargo__indexmap-2.9.0//:indexmap\",\n \"@browser_cargo__saffron-0.1.0//:saffron\",\n \"@browser_cargo__schemars-0.8.21//:schemars\",\n \"@browser_cargo__semver-1.0.26//:semver\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n \"@browser_cargo__serde_json-1.0.140//:serde_json\",\n \"@browser_cargo__serde_yaml-0.9.34-deprecated//:serde_yaml\",\n \"@browser_cargo__thiserror-1.0.69//:thiserror\",\n \"@browser_cargo__toml-0.8.14//:toml\",\n \"@browser_cargo__url-2.5.4//:url\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-config\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.601.0\",\n)\n" + } + }, + "browser_cargo__wasmer-derive-6.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c546f3380840cd63fdcc390f04cd19002f2dfa19b4691b77ecbd27642bd93452", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasmer-derive/6.1.0/download" + ], + "strip_prefix": "wasmer-derive-6.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"wasmer_derive\",\n deps = [\n \"@browser_cargo__proc-macro-error2-2.0.1//:proc_macro_error2\",\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-1.0.109//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"6.1.0\",\n)\n" + } + }, + "browser_cargo__wasmer-journal-0.601.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6459cd00a0000e38dd4386bec1d99687813677bb01bfe69120f0f3eaedae0a06", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasmer-journal/0.601.0/download" + ], + "strip_prefix": "wasmer-journal-0.601.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_journal\",\n deps = [\n \"@browser_cargo__anyhow-1.0.97//:anyhow\",\n \"@browser_cargo__base64-0.22.1//:base64\",\n \"@browser_cargo__bincode-1.3.3//:bincode\",\n \"@browser_cargo__bytecheck-0.6.11//:bytecheck\",\n \"@browser_cargo__bytes-1.10.1//:bytes\",\n \"@browser_cargo__derive_more-2.0.1//:derive_more\",\n \"@browser_cargo__lz4_flex-0.11.1//:lz4_flex\",\n \"@browser_cargo__num_enum-0.7.3//:num_enum\",\n \"@browser_cargo__rkyv-0.8.10//:rkyv\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n \"@browser_cargo__serde_json-1.0.140//:serde_json\",\n \"@browser_cargo__thiserror-1.0.69//:thiserror\",\n \"@browser_cargo__tracing-0.1.41//:tracing\",\n \"@browser_cargo__virtual-fs-0.601.0//:virtual_fs\",\n \"@browser_cargo__virtual-net-0.601.0//:virtual_net\",\n \"@browser_cargo__wasmer-6.1.0//:wasmer\",\n \"@browser_cargo__wasmer-config-0.601.0//:wasmer_config\",\n \"@browser_cargo__wasmer-wasix-types-0.601.0//:wasmer_wasix_types\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__async-trait-0.1.88//:async_trait\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-journal\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.601.0\",\n)\n" + } + }, + "browser_cargo__wasmer-package-0.601.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "aedc3a5cd721e8b12778d1858b9583aca8b91927a73f5fdf0c876cd5bbb6ac56", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasmer-package/0.601.0/download" + ], + "strip_prefix": "wasmer-package-0.601.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_package\",\n deps = [\n \"@browser_cargo__anyhow-1.0.97//:anyhow\",\n \"@browser_cargo__bytes-1.10.1//:bytes\",\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n \"@browser_cargo__ciborium-0.2.2//:ciborium\",\n \"@browser_cargo__flate2-1.1.1//:flate2\",\n \"@browser_cargo__ignore-0.4.22//:ignore\",\n \"@browser_cargo__insta-1.41.1//:insta\",\n \"@browser_cargo__semver-1.0.26//:semver\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n \"@browser_cargo__serde_json-1.0.140//:serde_json\",\n \"@browser_cargo__sha2-0.10.8//:sha2\",\n \"@browser_cargo__shared-buffer-0.1.4//:shared_buffer\",\n \"@browser_cargo__tar-0.4.44//:tar\",\n \"@browser_cargo__tempfile-3.12.0//:tempfile\",\n \"@browser_cargo__thiserror-1.0.69//:thiserror\",\n \"@browser_cargo__toml-0.8.14//:toml\",\n \"@browser_cargo__url-2.5.4//:url\",\n \"@browser_cargo__wasmer-config-0.601.0//:wasmer_config\",\n \"@browser_cargo__wasmer-types-6.1.0//:wasmer_types\",\n \"@browser_cargo__webc-10.0.1//:webc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-package\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.601.0\",\n)\n" + } + }, + "browser_cargo__wasmer-types-6.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "94a4027ce165e8dc776dc5e2a3231a96983e6dc7330efd97b793cfc4e973ad0c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasmer-types/6.1.0/download" + ], + "strip_prefix": "wasmer-types-6.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_types\",\n deps = [\n \"@browser_cargo__bytecheck-0.6.11//:bytecheck\",\n \"@browser_cargo__enum-iterator-0.7.0//:enum_iterator\",\n \"@browser_cargo__enumset-1.1.3//:enumset\",\n \"@browser_cargo__getrandom-0.2.15//:getrandom\",\n \"@browser_cargo__hex-0.4.3//:hex\",\n \"@browser_cargo__indexmap-2.9.0//:indexmap\",\n \"@browser_cargo__more-asserts-0.2.2//:more_asserts\",\n \"@browser_cargo__rkyv-0.8.10//:rkyv\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n \"@browser_cargo__serde_bytes-0.11.14//:serde_bytes\",\n \"@browser_cargo__sha2-0.10.8//:sha2\",\n \"@browser_cargo__target-lexicon-0.12.16//:target_lexicon\",\n \"@browser_cargo__thiserror-1.0.69//:thiserror\",\n \"@browser_cargo__wasmparser-0.224.1//:wasmparser\",\n \"@browser_cargo__xxhash-rust-0.8.11//:xxhash_rust\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"detect-wasm-features\",\n \"enable-serde\",\n \"serde\",\n \"serde_bytes\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-types\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"6.1.0\",\n)\n" + } + }, + "browser_cargo__wasmer-vm-6.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9c37d5be291eea00a00d077ce3a427bb3074709ee386ec358f18f0b7da33be01", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasmer-vm/6.1.0/download" + ], + "strip_prefix": "wasmer-vm-6.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_vm\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__backtrace-0.3.69//:backtrace\",\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n \"@browser_cargo__corosensei-0.3.0//:corosensei\",\n \"@browser_cargo__crossbeam-queue-0.3.11//:crossbeam_queue\",\n \"@browser_cargo__dashmap-6.1.0//:dashmap\",\n \"@browser_cargo__enum-iterator-0.7.0//:enum_iterator\",\n \"@browser_cargo__fnv-1.0.7//:fnv\",\n \"@browser_cargo__indexmap-2.9.0//:indexmap\",\n \"@browser_cargo__libc-0.2.171//:libc\",\n \"@browser_cargo__memoffset-0.9.0//:memoffset\",\n \"@browser_cargo__more-asserts-0.2.2//:more_asserts\",\n \"@browser_cargo__region-3.0.2//:region\",\n \"@browser_cargo__scopeguard-1.2.0//:scopeguard\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n \"@browser_cargo__thiserror-1.0.69//:thiserror\",\n \"@browser_cargo__wasmer-types-6.1.0//:wasmer_types\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__libunwind-1.3.3//:libunwind\", # cfg(any(target_family = \"unix\", all(target_family = \"windows\", target_env = \"gnu\")))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"enable-serde\",\n \"serde\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-vm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"6.1.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"enable-serde\",\n \"serde\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@browser_cargo__cc-1.2.18//:cc\",\n ],\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"wasmer-vm\",\n proc_macro_deps = [\n \"@browser_cargo__rustversion-1.0.20//:rustversion\",\n ],\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-vm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"6.1.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__wasmer-wasix-0.601.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [ + "@@//src/wasix/browser-host:patches/0002-wasmer-wasix-add-0702-compatibility-imports.patch", + "@@//src/wasix/browser-host:patches/0009-wasmer-wasix-instantiate-main-module-async.patch", + "@@//src/wasix/browser-host:patches/0011-wasmer-wasix-deny-single-backend-guest-spawn.patch", + "@@//src/wasix/browser-host:patches/0013-wasmer-wasix-fast-single-backend-clock.patch", + "@@//src/wasix/browser-host:patches/0016-wasmer-wasix-direct-single-backend-clock.patch", + "@@//src/wasix/browser-host:patches/0020-wasmer-wasix-preserve-posix-close-durability.patch", + "@@//src/wasix/browser-host:patches/0035-wasmer-wasix-preserve-shared-seek-offset.patch", + "@@//src/wasix/browser-host:patches/0033-wasmer-wasix-poll-ready-asyncify-work.patch" + ], + "remote_patch_strip": 1, + "sha256": "a9a804fcfbdbbfe5b2d6fb30e741e22a21e88e964dedfea9e609f13a52823bfe", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasmer-wasix/wasmer-wasix-0.601.0.crate" + ], + "strip_prefix": "wasmer-wasix-0.601.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_wasix\",\n deps = [\n \"@browser_cargo__anyhow-1.0.97//:anyhow\",\n \"@browser_cargo__base64-0.22.1//:base64\",\n \"@browser_cargo__bincode-1.3.3//:bincode\",\n \"@browser_cargo__blake3-1.5.1//:blake3\",\n \"@browser_cargo__bus-2.4.1//:bus\",\n \"@browser_cargo__bytecheck-0.6.11//:bytecheck\",\n \"@browser_cargo__bytes-1.10.1//:bytes\",\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n \"@browser_cargo__chrono-0.4.40//:chrono\",\n \"@browser_cargo__cooked-waker-5.0.0//:cooked_waker\",\n \"@browser_cargo__crossbeam-channel-0.5.15//:crossbeam_channel\",\n \"@browser_cargo__dashmap-6.1.0//:dashmap\",\n \"@browser_cargo__derive_more-2.0.1//:derive_more\",\n \"@browser_cargo__futures-0.3.30//:futures\",\n \"@browser_cargo__getrandom-0.2.15//:getrandom\",\n \"@browser_cargo__heapless-0.8.0//:heapless\",\n \"@browser_cargo__hex-0.4.3//:hex\",\n \"@browser_cargo__http-1.3.1//:http\",\n \"@browser_cargo__js-sys-0.3.78//:js_sys\",\n \"@browser_cargo__linked_hash_set-0.1.4//:linked_hash_set\",\n \"@browser_cargo__lz4_flex-0.11.1//:lz4_flex\",\n \"@browser_cargo__num_enum-0.7.3//:num_enum\",\n \"@browser_cargo__once_cell-1.19.0//:once_cell\",\n \"@browser_cargo__petgraph-0.7.1//:petgraph\",\n \"@browser_cargo__pin-project-1.1.3//:pin_project\",\n \"@browser_cargo__pin-utils-0.1.0//:pin_utils\",\n \"@browser_cargo__rand-0.8.5//:rand\",\n \"@browser_cargo__rkyv-0.8.10//:rkyv\",\n \"@browser_cargo__semver-1.0.26//:semver\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n \"@browser_cargo__serde_json-1.0.140//:serde_json\",\n \"@browser_cargo__serde_yaml-0.9.34-deprecated//:serde_yaml\",\n \"@browser_cargo__sha2-0.10.8//:sha2\",\n \"@browser_cargo__shared-buffer-0.1.4//:shared_buffer\",\n \"@browser_cargo__tempfile-3.12.0//:tempfile\",\n \"@browser_cargo__thiserror-1.0.69//:thiserror\",\n \"@browser_cargo__tokio-1.44.2//:tokio\",\n \"@browser_cargo__tokio-stream-0.1.15//:tokio_stream\",\n \"@browser_cargo__toml-0.8.14//:toml\",\n \"@browser_cargo__tracing-0.1.41//:tracing\",\n \"@browser_cargo__url-2.5.4//:url\",\n \"@browser_cargo__urlencoding-2.1.3//:urlencoding\",\n \"@browser_cargo__virtual-fs-0.601.0//:virtual_fs\",\n \"@browser_cargo__virtual-mio-0.601.0//:virtual_mio\",\n \"@browser_cargo__virtual-net-0.601.0//:virtual_net\",\n \"@browser_cargo__waker-fn-1.1.1//:waker_fn\",\n \"@browser_cargo__wasm-bindgen-0.2.101//:wasm_bindgen\",\n \"@browser_cargo__wasm-bindgen-futures-0.4.51//:wasm_bindgen_futures\",\n \"@browser_cargo__wasm-encoder-0.235.0//:wasm_encoder\",\n \"@browser_cargo__wasmer-6.1.0//:wasmer\",\n \"@browser_cargo__wasmer-config-0.601.0//:wasmer_config\",\n \"@browser_cargo__wasmer-journal-0.601.0//:wasmer_journal\",\n \"@browser_cargo__wasmer-package-0.601.0//:wasmer_package\",\n \"@browser_cargo__wasmer-types-6.1.0//:wasmer_types\",\n \"@browser_cargo__wasmer-wasix-types-0.601.0//:wasmer_wasix_types\",\n \"@browser_cargo__wasmparser-0.224.1//:wasmparser\",\n \"@browser_cargo__web-sys-0.3.78//:web_sys\",\n \"@browser_cargo__webc-10.0.1//:webc\",\n \"@browser_cargo__weezl-0.1.7//:weezl\",\n \"@browser_cargo__xxhash-rust-0.8.11//:xxhash_rust\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__libc-0.2.171//:libc\", # cfg(unix)\n \"@browser_cargo__terminal_size-0.3.0//:terminal_size\", # cfg(not(target_arch = \"wasm32\"))\n \"@browser_cargo__termios-0.3.3//:termios\", # cfg(all(unix, not(target_os = \"ios\")))\n ],\n \"//conditions:default\": [],\n }),\n proc_macro_deps = [\n \"@browser_cargo__async-trait-0.1.88//:async_trait\",\n \"@browser_cargo__serde_derive-1.0.219//:serde_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"chrono\",\n \"js\",\n \"js-default\",\n \"js-sys\",\n \"wasm-bindgen\",\n \"wasm-bindgen-futures\",\n \"web-sys\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-wasix\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.601.0\",\n)\n" + } + }, + "browser_cargo__wasmer-wasix-types-0.601.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7d2b7dad6c826f48a972709e5950a80157cb3b6bb12c6f51778282e85dc17096", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasmer-wasix-types/0.601.0/download" + ], + "strip_prefix": "wasmer-wasix-types-0.601.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_wasix_types\",\n deps = [\n \"@browser_cargo__anyhow-1.0.97//:anyhow\",\n \"@browser_cargo__bitflags-1.3.2//:bitflags\",\n \"@browser_cargo__byteorder-1.5.0//:byteorder\",\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n \"@browser_cargo__num_enum-0.7.3//:num_enum\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n \"@browser_cargo__time-0.3.36//:time\",\n \"@browser_cargo__tracing-0.1.41//:tracing\",\n \"@browser_cargo__wai-bindgen-gen-core-0.2.3//:wai_bindgen_gen_core\",\n \"@browser_cargo__wai-bindgen-gen-rust-0.2.3//:wai_bindgen_gen_rust\",\n \"@browser_cargo__wai-bindgen-gen-rust-wasm-0.2.3//:wai_bindgen_gen_rust_wasm\",\n \"@browser_cargo__wai-bindgen-rust-0.2.3//:wai_bindgen_rust\",\n \"@browser_cargo__wai-parser-0.2.3//:wai_parser\",\n \"@browser_cargo__wasmer-6.1.0//:wasmer\",\n \"@browser_cargo__wasmer-types-6.1.0//:wasmer_types\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__wasmer-derive-6.1.0//:wasmer_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"enable-serde\",\n \"serde\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-wasix-types\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.601.0\",\n)\n" + } + }, + "browser_cargo__wasmparser-0.221.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d06bfa36ab3ac2be0dee563380147a5b81ba10dd8885d7fbbc9eb574be67d185", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasmparser/0.221.3/download" + ], + "strip_prefix": "wasmparser-0.221.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmparser\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__bitflags-2.9.0//:bitflags\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmparser\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.221.3\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"wasmparser\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmparser\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.221.3\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__wasmparser-0.224.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "04f17a5917c2ddd3819e84c661fae0d6ba29d7b9c1f0e96c708c65a9c4188e11", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasmparser/0.224.1/download" + ], + "strip_prefix": "wasmparser-0.224.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmparser\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__bitflags-2.9.0//:bitflags\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"features\",\n \"simd\",\n \"validate\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmparser\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.224.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"features\",\n \"simd\",\n \"validate\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"wasmparser\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmparser\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.224.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__wasmparser-0.235.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "161296c618fa2d63f6ed5fffd1112937e803cb9ec71b32b01a76321555660917", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasmparser/0.235.0/download" + ], + "strip_prefix": "wasmparser-0.235.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmparser\",\n deps = [\n \":build_script_build\",\n \"@browser_cargo__bitflags-2.9.0//:bitflags\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmparser\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.235.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"wasmparser\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmparser\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.235.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__wast-221.0.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7e0d10d282261b825ffb3d49f46e8309e60a8b608328b6a0b0578e80f3f98e57", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wast/221.0.3/download" + ], + "strip_prefix": "wast-221.0.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wast\",\n deps = [\n \"@browser_cargo__bumpalo-3.14.0//:bumpalo\",\n \"@browser_cargo__leb128-0.2.5//:leb128\",\n \"@browser_cargo__memchr-2.7.1//:memchr\",\n \"@browser_cargo__unicode-width-0.2.0//:unicode_width\",\n \"@browser_cargo__wasm-encoder-0.221.3//:wasm_encoder\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"component-model\",\n \"wasm-module\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wast\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"221.0.3\",\n)\n" + } + }, + "browser_cargo__wat-1.221.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d744e4500534bada448bf611109a6b972160f94c8e8bcbe421e7be06ea346520", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wat/1.221.3/download" + ], + "strip_prefix": "wat-1.221.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wat\",\n deps = [\n \"@browser_cargo__wast-221.0.3//:wast\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"component-model\",\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wat\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.221.3\",\n)\n" + } + }, + "browser_cargo__web-sys-0.3.78": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "77e4b637749ff0d92b8fad63aa1f7cff3cbe125fd49c175cd6345e7272638b12", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/web-sys/0.3.78/download" + ], + "strip_prefix": "web-sys-0.3.78", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"web_sys\",\n deps = [\n \"@browser_cargo__js-sys-0.3.78//:js_sys\",\n \"@browser_cargo__wasm-bindgen-0.2.101//:wasm_bindgen\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"BinaryType\",\n \"Blob\",\n \"BlobPropertyBag\",\n \"DedicatedWorkerGlobalScope\",\n \"DomException\",\n \"ErrorEvent\",\n \"Event\",\n \"EventTarget\",\n \"File\",\n \"FileReader\",\n \"FileSystemDirectoryHandle\",\n \"FileSystemFileHandle\",\n \"FileSystemGetDirectoryOptions\",\n \"FileSystemHandle\",\n \"Headers\",\n \"MessageEvent\",\n \"Navigator\",\n \"ProgressEvent\",\n \"QueuingStrategy\",\n \"ReadableByteStreamController\",\n \"ReadableStream\",\n \"ReadableStreamDefaultController\",\n \"ReadableStreamDefaultReader\",\n \"Request\",\n \"RequestInit\",\n \"RequestMode\",\n \"Response\",\n \"StorageManager\",\n \"Url\",\n \"WebSocket\",\n \"Window\",\n \"Worker\",\n \"WorkerGlobalScope\",\n \"WorkerNavigator\",\n \"WorkerOptions\",\n \"WorkerType\",\n \"WritableStream\",\n \"WritableStreamDefaultController\",\n \"WritableStreamDefaultWriter\",\n \"console\",\n \"default\",\n \"std\",\n ] + select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [\n \"AbortController\", # wasm32-unknown-unknown\n \"AbortSignal\", # wasm32-unknown-unknown\n \"FormData\", # wasm32-unknown-unknown\n \"Performance\", # wasm32-unknown-unknown\n \"PerformanceTiming\", # wasm32-unknown-unknown\n \"ReadableStreamByobReader\", # wasm32-unknown-unknown\n \"ReadableStreamByobRequest\", # wasm32-unknown-unknown\n \"ReadableStreamGetReaderOptions\", # wasm32-unknown-unknown\n \"ReadableStreamReadResult\", # wasm32-unknown-unknown\n \"ReadableStreamReaderMode\", # wasm32-unknown-unknown\n \"ReadableStreamType\", # wasm32-unknown-unknown\n \"ReadableWritablePair\", # wasm32-unknown-unknown\n \"RequestCredentials\", # wasm32-unknown-unknown\n \"ServiceWorkerGlobalScope\", # wasm32-unknown-unknown\n \"StreamPipeOptions\", # wasm32-unknown-unknown\n \"TransformStream\", # wasm32-unknown-unknown\n \"TransformStreamDefaultController\", # wasm32-unknown-unknown\n \"Transformer\", # wasm32-unknown-unknown\n \"UnderlyingSink\", # wasm32-unknown-unknown\n \"UnderlyingSource\", # wasm32-unknown-unknown\n ],\n \"//conditions:default\": [],\n }),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=web-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.78\",\n)\n" + } + }, + "browser_cargo__web-time-1.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/web-time/1.1.0/download" + ], + "strip_prefix": "web-time-1.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"web_time\",\n deps = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [\n \"@browser_cargo__js-sys-0.3.78//:js_sys\", # cfg(all(target_family = \"wasm\", target_os = \"unknown\"))\n \"@browser_cargo__wasm-bindgen-0.2.101//:wasm_bindgen\", # cfg(all(target_family = \"wasm\", target_os = \"unknown\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=web-time\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.0\",\n)\n" + } + }, + "browser_cargo__webc-10.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "637506ca3c48eae3301e97f0167aa1b46cdfdd479d008b868a19715182e48ae3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/webc/10.0.1/download" + ], + "strip_prefix": "webc-10.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"webc\",\n deps = [\n \"@browser_cargo__anyhow-1.0.97//:anyhow\",\n \"@browser_cargo__base64-0.22.1//:base64\",\n \"@browser_cargo__bytes-1.10.1//:bytes\",\n \"@browser_cargo__cfg-if-1.0.0//:cfg_if\",\n \"@browser_cargo__ciborium-0.2.2//:ciborium\",\n \"@browser_cargo__ignore-0.4.22//:ignore\",\n \"@browser_cargo__indexmap-2.9.0//:indexmap\",\n \"@browser_cargo__leb128-0.2.5//:leb128\",\n \"@browser_cargo__lexical-sort-0.3.1//:lexical_sort\",\n \"@browser_cargo__libc-0.2.171//:libc\",\n \"@browser_cargo__once_cell-1.19.0//:once_cell\",\n \"@browser_cargo__path-clean-1.0.1//:path_clean\",\n \"@browser_cargo__rand-0.8.5//:rand\",\n \"@browser_cargo__serde-1.0.219//:serde\",\n \"@browser_cargo__serde_json-1.0.140//:serde_json\",\n \"@browser_cargo__sha2-0.10.8//:sha2\",\n \"@browser_cargo__shared-buffer-0.1.4//:shared_buffer\",\n \"@browser_cargo__thiserror-1.0.69//:thiserror\",\n \"@browser_cargo__url-2.5.4//:url\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__document-features-0.2.8//:document_features\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"v1\",\n \"v2\",\n \"v3\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=webc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"10.0.1\",\n)\n" + } + }, + "browser_cargo__weezl-0.1.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/weezl/0.1.7/download" + ], + "strip_prefix": "weezl-0.1.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"weezl\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=weezl\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.7\",\n)\n" + } + }, + "browser_cargo__winapi-0.3.9": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/winapi/0.3.9/download" + ], + "strip_prefix": "winapi-0.3.9", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"winapi\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=winapi\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.9\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2015\",\n pkg_name = \"winapi\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=winapi\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.3.9\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__winapi-i686-pc-windows-gnu-0.4.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/winapi-i686-pc-windows-gnu/0.4.0/download" + ], + "strip_prefix": "winapi-i686-pc-windows-gnu-0.4.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"winapi_i686_pc_windows_gnu\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=winapi-i686-pc-windows-gnu\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2015\",\n pkg_name = \"winapi-i686-pc-windows-gnu\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=winapi-i686-pc-windows-gnu\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.4.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__winapi-util-0.1.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/winapi-util/0.1.6/download" + ], + "strip_prefix": "winapi-util-0.1.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"winapi_util\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=winapi-util\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.6\",\n)\n" + } + }, + "browser_cargo__winapi-x86_64-pc-windows-gnu-0.4.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/winapi-x86_64-pc-windows-gnu/0.4.0/download" + ], + "strip_prefix": "winapi-x86_64-pc-windows-gnu-0.4.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"winapi_x86_64_pc_windows_gnu\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=winapi-x86_64-pc-windows-gnu\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2015\",\n pkg_name = \"winapi-x86_64-pc-windows-gnu\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=winapi-x86_64-pc-windows-gnu\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.4.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__windows-core-0.52.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows-core/0.52.0/download" + ], + "strip_prefix": "windows-core-0.52.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_core\",\n deps = [\n \"@browser_cargo__windows-targets-0.52.6//:windows_targets\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows-core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.0\",\n)\n" + } + }, + "browser_cargo__windows-link-0.1.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows-link/0.1.1/download" + ], + "strip_prefix": "windows-link-0.1.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_link\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows-link\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.1\",\n)\n" + } + }, + "browser_cargo__windows-registry-0.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows-registry/0.2.0/download" + ], + "strip_prefix": "windows-registry-0.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_registry\",\n deps = [\n \"@browser_cargo__windows-result-0.2.0//:windows_result\",\n \"@browser_cargo__windows-strings-0.1.0//:windows_strings\",\n \"@browser_cargo__windows-targets-0.52.6//:windows_targets\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows-registry\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.0\",\n)\n" + } + }, + "browser_cargo__windows-result-0.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows-result/0.2.0/download" + ], + "strip_prefix": "windows-result-0.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_result\",\n deps = [\n \"@browser_cargo__windows-targets-0.52.6//:windows_targets\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows-result\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.0\",\n)\n" + } + }, + "browser_cargo__windows-strings-0.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows-strings/0.1.0/download" + ], + "strip_prefix": "windows-strings-0.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_strings\",\n deps = [\n \"@browser_cargo__windows-result-0.2.0//:windows_result\",\n \"@browser_cargo__windows-targets-0.52.6//:windows_targets\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows-strings\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.0\",\n)\n" + } + }, + "browser_cargo__windows-sys-0.48.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows-sys/0.48.0/download" + ], + "strip_prefix": "windows-sys-0.48.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_sys\",\n deps = [\n \"@browser_cargo__windows-targets-0.48.5//:windows_targets\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.48.0\",\n)\n" + } + }, + "browser_cargo__windows-sys-0.52.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows-sys/0.52.0/download" + ], + "strip_prefix": "windows-sys-0.52.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_sys\",\n deps = [\n \"@browser_cargo__windows-targets-0.52.6//:windows_targets\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.0\",\n)\n" + } + }, + "browser_cargo__windows-sys-0.59.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows-sys/0.59.0/download" + ], + "strip_prefix": "windows-sys-0.59.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_sys\",\n deps = [\n \"@browser_cargo__windows-targets-0.52.6//:windows_targets\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.59.0\",\n)\n" + } + }, + "browser_cargo__windows-targets-0.48.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows-targets/0.48.5/download" + ], + "strip_prefix": "windows-targets-0.48.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_targets\",\n deps = select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__windows_x86_64_gnu-0.48.5//:windows_x86_64_gnu\", # cfg(all(target_arch = \"x86_64\", target_env = \"gnu\", not(target_abi = \"llvm\"), not(windows_raw_dylib)))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows-targets\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.48.5\",\n)\n" + } + }, + "browser_cargo__windows-targets-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows-targets/0.52.6/download" + ], + "strip_prefix": "windows-targets-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_targets\",\n deps = select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__windows_x86_64_gnu-0.52.6//:windows_x86_64_gnu\", # cfg(all(target_arch = \"x86_64\", target_env = \"gnu\", not(target_abi = \"llvm\"), not(windows_raw_dylib)))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows-targets\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n" + } + }, + "browser_cargo__windows_aarch64_gnullvm-0.48.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_aarch64_gnullvm/0.48.5/download" + ], + "strip_prefix": "windows_aarch64_gnullvm-0.48.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_aarch64_gnullvm\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_aarch64_gnullvm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.48.5\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"windows_aarch64_gnullvm\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_aarch64_gnullvm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.48.5\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__windows_aarch64_gnullvm-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_aarch64_gnullvm/0.52.6/download" + ], + "strip_prefix": "windows_aarch64_gnullvm-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_aarch64_gnullvm\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_aarch64_gnullvm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_aarch64_gnullvm\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_aarch64_gnullvm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__windows_aarch64_msvc-0.48.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_aarch64_msvc/0.48.5/download" + ], + "strip_prefix": "windows_aarch64_msvc-0.48.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_aarch64_msvc\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_aarch64_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.48.5\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"windows_aarch64_msvc\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_aarch64_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.48.5\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__windows_aarch64_msvc-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_aarch64_msvc/0.52.6/download" + ], + "strip_prefix": "windows_aarch64_msvc-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_aarch64_msvc\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_aarch64_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_aarch64_msvc\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_aarch64_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__windows_i686_gnu-0.48.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_i686_gnu/0.48.5/download" + ], + "strip_prefix": "windows_i686_gnu-0.48.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_i686_gnu\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_i686_gnu\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.48.5\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"windows_i686_gnu\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_i686_gnu\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.48.5\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__windows_i686_gnu-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_i686_gnu/0.52.6/download" + ], + "strip_prefix": "windows_i686_gnu-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_i686_gnu\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_i686_gnu\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_i686_gnu\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_i686_gnu\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__windows_i686_gnullvm-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_i686_gnullvm/0.52.6/download" + ], + "strip_prefix": "windows_i686_gnullvm-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_i686_gnullvm\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_i686_gnullvm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_i686_gnullvm\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_i686_gnullvm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__windows_i686_msvc-0.48.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_i686_msvc/0.48.5/download" + ], + "strip_prefix": "windows_i686_msvc-0.48.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_i686_msvc\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_i686_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.48.5\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"windows_i686_msvc\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_i686_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.48.5\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__windows_i686_msvc-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_i686_msvc/0.52.6/download" + ], + "strip_prefix": "windows_i686_msvc-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_i686_msvc\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_i686_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_i686_msvc\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_i686_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__windows_x86_64_gnu-0.48.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_x86_64_gnu/0.48.5/download" + ], + "strip_prefix": "windows_x86_64_gnu-0.48.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_x86_64_gnu\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_gnu\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.48.5\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"windows_x86_64_gnu\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_gnu\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.48.5\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__windows_x86_64_gnu-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_x86_64_gnu/0.52.6/download" + ], + "strip_prefix": "windows_x86_64_gnu-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_x86_64_gnu\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_gnu\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_x86_64_gnu\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_gnu\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__windows_x86_64_gnullvm-0.48.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_x86_64_gnullvm/0.48.5/download" + ], + "strip_prefix": "windows_x86_64_gnullvm-0.48.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_x86_64_gnullvm\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_gnullvm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.48.5\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"windows_x86_64_gnullvm\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_gnullvm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.48.5\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__windows_x86_64_gnullvm-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_x86_64_gnullvm/0.52.6/download" + ], + "strip_prefix": "windows_x86_64_gnullvm-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_x86_64_gnullvm\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_gnullvm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_x86_64_gnullvm\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_gnullvm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__windows_x86_64_msvc-0.48.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_x86_64_msvc/0.48.5/download" + ], + "strip_prefix": "windows_x86_64_msvc-0.48.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_x86_64_msvc\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.48.5\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"windows_x86_64_msvc\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.48.5\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__windows_x86_64_msvc-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_x86_64_msvc/0.52.6/download" + ], + "strip_prefix": "windows_x86_64_msvc-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_x86_64_msvc\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_x86_64_msvc\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__winnow-0.5.33": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b7520bbdec7211caa7c4e682eb1fbe07abe20cee6756b6e00f537c82c11816aa", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/winnow/0.5.33/download" + ], + "strip_prefix": "winnow-0.5.33", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"winnow\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=winnow\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.33\",\n)\n" + } + }, + "browser_cargo__winnow-0.6.13": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/winnow/0.6.13/download" + ], + "strip_prefix": "winnow-0.6.13", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"winnow\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=winnow\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.13\",\n)\n" + } + }, + "browser_cargo__write16-1.0.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/write16/1.0.0/download" + ], + "strip_prefix": "write16-1.0.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"write16\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=write16\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.0\",\n)\n" + } + }, + "browser_cargo__writeable-0.5.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/writeable/0.5.5/download" + ], + "strip_prefix": "writeable-0.5.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"writeable\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=writeable\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.5\",\n)\n" + } + }, + "browser_cargo__xattr-1.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "914566e6413e7fa959cc394fb30e563ba80f3541fbd40816d4c05a0fc3f2a0f1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/xattr/1.2.0/download" + ], + "strip_prefix": "xattr-1.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"xattr\",\n deps = [\n \"@browser_cargo__rustix-0.38.34//:rustix\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@browser_cargo__linux-raw-sys-0.4.12//:linux_raw_sys\", # cfg(target_os = \"linux\")\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"unsupported\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=xattr\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.0\",\n)\n" + } + }, + "browser_cargo__xxhash-rust-0.8.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "63658493314859b4dfdf3fb8c1defd61587839def09582db50b8a4e93afca6bb", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/xxhash-rust/0.8.11/download" + ], + "strip_prefix": "xxhash-rust-0.8.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"xxhash_rust\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"xxh64\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=xxhash-rust\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.11\",\n)\n" + } + }, + "browser_cargo__yansi-1.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/yansi/1.0.1/download" + ], + "strip_prefix": "yansi-1.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"yansi\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=yansi\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.1\",\n)\n" + } + }, + "browser_cargo__yoke-0.7.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/yoke/0.7.5/download" + ], + "strip_prefix": "yoke-0.7.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"yoke\",\n deps = [\n \"@browser_cargo__stable_deref_trait-1.2.0//:stable_deref_trait\",\n \"@browser_cargo__zerofrom-0.1.6//:zerofrom\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__yoke-derive-0.7.5//:yoke_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"derive\",\n \"zerofrom\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=yoke\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.5\",\n)\n" + } + }, + "browser_cargo__yoke-derive-0.7.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/yoke-derive/0.7.5/download" + ], + "strip_prefix": "yoke-derive-0.7.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"yoke_derive\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n \"@browser_cargo__synstructure-0.13.1//:synstructure\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=yoke-derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.5\",\n)\n" + } + }, + "browser_cargo__zerocopy-0.7.35": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zerocopy/0.7.35/download" + ], + "strip_prefix": "zerocopy-0.7.35", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"zerocopy\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"simd\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerocopy\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.35\",\n)\n" + } + }, + "browser_cargo__zerocopy-0.8.24": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zerocopy/0.8.24/download" + ], + "strip_prefix": "zerocopy-0.8.24", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"zerocopy\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerocopy\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.24\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"zerocopy\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerocopy\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.8.24\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "browser_cargo__zerocopy-derive-0.7.35": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zerocopy-derive/0.7.35/download" + ], + "strip_prefix": "zerocopy-derive-0.7.35", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"zerocopy_derive\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerocopy-derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.35\",\n)\n" + } + }, + "browser_cargo__zerocopy-derive-0.8.24": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zerocopy-derive/0.8.24/download" + ], + "strip_prefix": "zerocopy-derive-0.8.24", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"zerocopy_derive\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerocopy-derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.24\",\n)\n" + } + }, + "browser_cargo__zerofrom-0.1.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zerofrom/0.1.6/download" + ], + "strip_prefix": "zerofrom-0.1.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"zerofrom\",\n proc_macro_deps = [\n \"@browser_cargo__zerofrom-derive-0.1.6//:zerofrom_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"derive\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerofrom\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.6\",\n)\n" + } + }, + "browser_cargo__zerofrom-derive-0.1.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zerofrom-derive/0.1.6/download" + ], + "strip_prefix": "zerofrom-derive-0.1.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"zerofrom_derive\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n \"@browser_cargo__synstructure-0.13.1//:synstructure\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerofrom-derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.6\",\n)\n" + } + }, + "browser_cargo__zeroize-1.8.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zeroize/1.8.1/download" + ], + "strip_prefix": "zeroize-1.8.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"zeroize\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zeroize\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.8.1\",\n)\n" + } + }, + "browser_cargo__zerovec-0.10.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zerovec/0.10.4/download" + ], + "strip_prefix": "zerovec-0.10.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"zerovec\",\n deps = [\n \"@browser_cargo__yoke-0.7.5//:yoke\",\n \"@browser_cargo__zerofrom-0.1.6//:zerofrom\",\n ],\n proc_macro_deps = [\n \"@browser_cargo__zerovec-derive-0.10.3//:zerovec_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"derive\",\n \"yoke\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerovec\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.4\",\n)\n" + } + }, + "browser_cargo__zerovec-derive-0.10.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zerovec-derive/0.10.3/download" + ], + "strip_prefix": "zerovec-derive-0.10.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"zerovec_derive\",\n deps = [\n \"@browser_cargo__proc-macro2-1.0.94//:proc_macro2\",\n \"@browser_cargo__quote-1.0.35//:quote\",\n \"@browser_cargo__syn-2.0.100//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerovec-derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.3\",\n)\n" + } + } + } + } + }, + "//build_defs/wasix/postmaster:cargo-extension.bzl%crate": { + "general": { + "bzlTransitiveDigest": "vwQTfCRjUu8rnqLjaFsjMhXX+Pzho5aBqPbbfRPpD4M=", + "usagesDigest": "We5SzYP6tENIT4mvgm69pJwuxJygBQTLY4ijBNg0pCk=", + "recordedInputs": [ + "ENV:CARGO_BAZEL_DEBUG \\0", + "ENV:CARGO_BAZEL_GENERATOR_SHA256 \\0", + "ENV:CARGO_BAZEL_GENERATOR_URL \\0", + "ENV:CARGO_BAZEL_ISOLATED \\0", + "ENV:CARGO_BAZEL_REPIN \\0", + "ENV:CARGO_BAZEL_REPIN_ONLY \\0", + "ENV:CARGO_BAZEL_TIMEOUT \\0", + "ENV:REPIN \\0", + "REPO_MAPPING:,postmaster_cargo +_repo_rules31+postmaster_cargo", + "REPO_MAPPING:,rules_rust rules_rust+", + "REPO_MAPPING:,rust_host_tools +rust_host_tools+rust_host_tools", + "REPO_MAPPING:bazel_features+,bazel_features_globals bazel_features++version_extension+bazel_features_globals", + "REPO_MAPPING:bazel_features+,bazel_features_version bazel_features++version_extension+bazel_features_version", + "REPO_MAPPING:rules_cc+,bazel_tools bazel_tools", + "REPO_MAPPING:rules_cc+,cc_compatibility_proxy rules_cc++compatibility_proxy+cc_compatibility_proxy", + "REPO_MAPPING:rules_cc+,rules_cc rules_cc+", + "REPO_MAPPING:rules_cc++compatibility_proxy+cc_compatibility_proxy,rules_cc rules_cc+", + "REPO_MAPPING:rules_rust+,bazel_features bazel_features+", + "REPO_MAPPING:rules_rust+,bazel_skylib bazel_skylib+", + "REPO_MAPPING:rules_rust+,bazel_tools bazel_tools", + "REPO_MAPPING:rules_rust+,rules_cc rules_cc+", + "FILE:@@+_repo_rules31+postmaster_cargo//executor/Cargo.lock 32b14e2109669a102a4d9082426a4943af07c806c3b5d4527a58d1d4f3028556", + "FILE:@@+_repo_rules31+postmaster_cargo//executor/Cargo.toml eead42e47d4743b519a452f514ed7cf9685c4cb20b665ca7a38ede67eb927e2a", + "FILE:@@+_repo_rules31+postmaster_cargo//cargo-sources.json 156fcbab9beb374f4772a1c9dbdc6c4b64040791852e4cf010c4bb0ca9a9e0ea", + "FILE:@@+_repo_rules31+postmaster_cargo//compiler/Cargo.lock 32b14e2109669a102a4d9082426a4943af07c806c3b5d4527a58d1d4f3028556", + "FILE:@@+_repo_rules31+postmaster_cargo//compiler/Cargo.toml a23978a49d400724f691051a05d488c0a12ff8957c8ee54c9fb0251e0daacf7d", + "FILE:@@//src/wasix/postmaster/tools/sealed-export-closure/Cargo.lock eb7b5c200acfcc79b318b8273deae9d666a4f172c74e43e80fd4ec2eca86792e", + "FILE:@@//src/wasix/postmaster/tools/sealed-export-closure/Cargo.toml 14a9c9cf5bf4957a43911dc680fe6b12d470d7b18a4eb3628d4ccdc9e7aec1bc" + ], + "generatedRepoSpecs": { + "postmaster_executor_crates": { + "repoRuleId": "@@rules_rust+//crate_universe/private:crates_vendor.bzl%crates_vendor_remote_repository", + "attributes": { + "contents": { + "BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files(\n [\n \"cargo-bazel.json\",\n \"crates.bzl\",\n \"defs.bzl\",\n ] + glob(\n allow_empty = True,\n include = [\"*.bazel\"],\n ),\n)\n\nfilegroup(\n name = \"srcs\",\n srcs = glob(\n allow_empty = True,\n include = [\n \"*.bazel\",\n \"*.bzl\",\n ],\n ),\n)\n\n# Workspace Member Dependencies\nalias(\n name = \"anyhow-1.0.102\",\n actual = \"@postmaster_executor_crates__anyhow-1.0.102//:anyhow\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"anyhow\",\n actual = \"@postmaster_executor_crates__anyhow-1.0.102//:anyhow\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"async-trait-0.1.89\",\n actual = \"@postmaster_executor_crates__async-trait-0.1.89//:async_trait\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"async-trait\",\n actual = \"@postmaster_executor_crates__async-trait-0.1.89//:async_trait\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"futures-0.3.32\",\n actual = \"@postmaster_executor_crates__futures-0.3.32//:futures\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"futures\",\n actual = \"@postmaster_executor_crates__futures-0.3.32//:futures\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"hex-0.4.3\",\n actual = \"@postmaster_executor_crates__hex-0.4.3//:hex\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"hex\",\n actual = \"@postmaster_executor_crates__hex-0.4.3//:hex\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"libc-0.2.186\",\n actual = \"@postmaster_executor_crates__libc-0.2.186//:libc\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"libc\",\n actual = \"@postmaster_executor_crates__libc-0.2.186//:libc\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde-1.0.228\",\n actual = \"@postmaster_executor_crates__serde-1.0.228//:serde\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde\",\n actual = \"@postmaster_executor_crates__serde-1.0.228//:serde\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde_json-1.0.149\",\n actual = \"@postmaster_executor_crates__serde_json-1.0.149//:serde_json\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde_json\",\n actual = \"@postmaster_executor_crates__serde_json-1.0.149//:serde_json\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"sha2-0.11.0\",\n actual = \"@postmaster_executor_crates__sha2-0.11.0//:sha2\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"sha2\",\n actual = \"@postmaster_executor_crates__sha2-0.11.0//:sha2\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tempfile-3.27.0\",\n actual = \"@postmaster_executor_crates__tempfile-3.27.0//:tempfile\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tempfile\",\n actual = \"@postmaster_executor_crates__tempfile-3.27.0//:tempfile\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tokio-1.52.1\",\n actual = \"@postmaster_executor_crates__tokio-1.52.1//:tokio\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tokio\",\n actual = \"@postmaster_executor_crates__tokio-1.52.1//:tokio\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tracing-0.1.44\",\n actual = \"@postmaster_executor_crates__tracing-0.1.44//:tracing\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tracing\",\n actual = \"@postmaster_executor_crates__tracing-0.1.44//:tracing\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-7.2.0-alpha.2\",\n actual = \"@postmaster_executor_crates__wasmer-7.2.0-alpha.2//:wasmer\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer\",\n actual = \"@postmaster_executor_crates__wasmer-7.2.0-alpha.2//:wasmer\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-types-7.2.0-alpha.2\",\n actual = \"@postmaster_executor_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-types\",\n actual = \"@postmaster_executor_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-vm-7.2.0-alpha.2\",\n actual = \"@postmaster_executor_crates__wasmer-vm-7.2.0-alpha.2//:wasmer_vm\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-vm\",\n actual = \"@postmaster_executor_crates__wasmer-vm-7.2.0-alpha.2//:wasmer_vm\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-wasix-0.702.0-alpha.2\",\n actual = \"@postmaster_executor_crates__wasmer-wasix-0.702.0-alpha.2//:wasmer_wasix\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-wasix\",\n actual = \"@postmaster_executor_crates__wasmer-wasix-0.702.0-alpha.2//:wasmer_wasix\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wat-1.247.0\",\n actual = \"@postmaster_executor_crates__wat-1.247.0//:wat\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wat\",\n actual = \"@postmaster_executor_crates__wat-1.247.0//:wat\",\n tags = [\"manual\"],\n)\n", + "alias_rules.bzl": "\"\"\"Alias that transitions its target to `compilation_mode=opt`. Use `transition_alias=\"opt\"` to enable.\"\"\"\n\nload(\"@rules_cc//cc:defs.bzl\", \"CcInfo\")\nload(\"@rules_rust//rust:rust_common.bzl\", \"COMMON_PROVIDERS\")\n\ndef _transition_alias_impl(ctx):\n # `ctx.attr.actual` is a list of 1 item due to the transition\n providers = [ctx.attr.actual[0][provider] for provider in COMMON_PROVIDERS]\n if CcInfo in ctx.attr.actual[0]:\n providers.append(ctx.attr.actual[0][CcInfo])\n return providers\n\ndef _change_compilation_mode(compilation_mode):\n def _change_compilation_mode_impl(_settings, _attr):\n return {\n \"//command_line_option:compilation_mode\": compilation_mode,\n }\n\n return transition(\n implementation = _change_compilation_mode_impl,\n inputs = [],\n outputs = [\n \"//command_line_option:compilation_mode\",\n ],\n )\n\ndef _transition_alias_rule(compilation_mode):\n return rule(\n implementation = _transition_alias_impl,\n provides = COMMON_PROVIDERS,\n attrs = {\n \"actual\": attr.label(\n mandatory = True,\n doc = \"`rust_library()` target to transition to `compilation_mode=opt`.\",\n providers = COMMON_PROVIDERS,\n cfg = _change_compilation_mode(compilation_mode),\n ),\n \"_allowlist_function_transition\": attr.label(\n default = \"@bazel_tools//tools/allowlists/function_transition_allowlist\",\n ),\n },\n doc = \"Transitions a Rust library crate to the `compilation_mode=opt`.\",\n )\n\ntransition_alias_dbg = _transition_alias_rule(\"dbg\")\ntransition_alias_fastbuild = _transition_alias_rule(\"fastbuild\")\ntransition_alias_opt = _transition_alias_rule(\"opt\")\n", + "crates.bzl": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\"\"\"\n# `crates_repository` API\n\n- [aliases](#aliases)\n- [crate_edition](#crate_edition)\n- [crate_deps](#crate_deps)\n- [all_crate_deps](#all_crate_deps)\n- [crate_repositories](#crate_repositories)\n\n\"\"\"\n\nload(\"@bazel_tools//tools/build_defs/repo:git.bzl\", \"git_repository\")\nload(\"@bazel_tools//tools/build_defs/repo:http.bzl\", \"http_archive\")\nload(\"@bazel_tools//tools/build_defs/repo:utils.bzl\", \"maybe\")\nload(\"@bazel_skylib//lib:selects.bzl\", \"selects\")\nload(\"@rules_rust//crate_universe:defs.bzl\", \"crates_vendor_remote_repository\", \"local_crate_mirror\")\n\n###############################################################################\n# MACROS API\n###############################################################################\n\n# An identifier that represent common dependencies (unconditional).\n_COMMON_CONDITION = \"\"\n\ndef _flatten_dependency_maps(all_dependency_maps):\n \"\"\"Flatten a list of dependency maps into one dictionary.\n\n Dependency maps have the following structure:\n\n ```python\n DEPENDENCIES_MAP = {\n # The first key in the map is a Bazel package\n # name of the workspace this file is defined in.\n \"workspace_member_package\": {\n\n # Not all dependencies are supported for all platforms.\n # the condition key is the condition required to be true\n # on the host platform.\n \"condition\": {\n\n # An alias to a crate target. # The label of the crate target the\n # Aliases are only crate names. # package name refers to.\n \"package_name\": \"@full//:label\",\n }\n }\n }\n ```\n\n Args:\n all_dependency_maps (list): A list of dicts as described above\n\n Returns:\n dict: A dictionary as described above\n \"\"\"\n dependencies = {}\n\n for workspace_deps_map in all_dependency_maps:\n for pkg_name, conditional_deps_map in workspace_deps_map.items():\n if pkg_name not in dependencies:\n non_frozen_map = dict()\n for key, values in conditional_deps_map.items():\n non_frozen_map.update({key: dict(values.items())})\n dependencies.setdefault(pkg_name, non_frozen_map)\n continue\n\n for condition, deps_map in conditional_deps_map.items():\n # If the condition has not been recorded, do so and continue\n if condition not in dependencies[pkg_name]:\n dependencies[pkg_name].setdefault(condition, dict(deps_map.items()))\n continue\n\n # Alert on any miss-matched dependencies\n inconsistent_entries = []\n for crate_name, crate_label in deps_map.items():\n existing = dependencies[pkg_name][condition].get(crate_name)\n if existing and existing != crate_label:\n inconsistent_entries.append((crate_name, existing, crate_label))\n dependencies[pkg_name][condition].update({crate_name: crate_label})\n\n return dependencies\n\ndef crate_deps(deps, package_name = None):\n \"\"\"Finds the fully qualified label of the requested crates for the package where this macro is called.\n\n Args:\n deps (list): The desired list of crate targets.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()`.\n\n Returns:\n list: A list of labels to generated rust targets (str)\n \"\"\"\n\n if not deps:\n return []\n\n if package_name == None:\n package_name = native.package_name()\n\n # Join both sets of dependencies\n dependencies = _flatten_dependency_maps([\n _NORMAL_DEPENDENCIES,\n _NORMAL_DEV_DEPENDENCIES,\n _PROC_MACRO_DEPENDENCIES,\n _PROC_MACRO_DEV_DEPENDENCIES,\n _BUILD_DEPENDENCIES,\n _BUILD_PROC_MACRO_DEPENDENCIES,\n ]).pop(package_name, {})\n\n # Combine all conditional packages so we can easily index over a flat list\n # TODO: Perhaps this should actually return select statements and maintain\n # the conditionals of the dependencies\n flat_deps = {}\n for deps_set in dependencies.values():\n for crate_name, crate_label in deps_set.items():\n flat_deps.update({crate_name: crate_label})\n\n missing_crates = []\n crate_targets = []\n for crate_target in deps:\n if crate_target not in flat_deps:\n missing_crates.append(crate_target)\n else:\n crate_targets.append(flat_deps[crate_target])\n\n if missing_crates:\n fail(\"Could not find crates `{}` among dependencies of `{}`. Available dependencies were `{}`\".format(\n missing_crates,\n package_name,\n dependencies,\n ))\n\n return crate_targets\n\ndef crate_edition(package_name = None):\n \"\"\"Finds the Rust edition for the package where this macro is called.\n\n Args:\n package_name (str, optional): The package name whose edition should be\n looked up. Defaults to `native.package_name()` when unset.\n\n Returns:\n str: The Rust edition declared by the package's Cargo.toml file.\n \"\"\"\n if package_name == None:\n package_name = native.package_name()\n\n if package_name not in _CRATE_EDITIONS:\n fail(\"Tried to get crate_edition for package \" + package_name + \" but that package had no Cargo.toml file\")\n\n return _CRATE_EDITIONS[package_name]\n\ndef all_crate_deps(\n normal = False, \n normal_dev = False, \n proc_macro = False, \n proc_macro_dev = False,\n build = False,\n build_proc_macro = False,\n package_name = None):\n \"\"\"Finds the fully qualified label of all requested direct crate dependencies \\\n for the package where this macro is called.\n\n If no parameters are set, all normal dependencies are returned. Setting any one flag will\n otherwise impact the contents of the returned list.\n\n Args:\n normal (bool, optional): If True, normal dependencies are included in the\n output list.\n normal_dev (bool, optional): If True, normal dev dependencies will be\n included in the output list.\n proc_macro (bool, optional): If True, proc_macro dependencies are included\n in the output list.\n proc_macro_dev (bool, optional): If True, dev proc_macro dependencies are\n included in the output list.\n build (bool, optional): If True, build dependencies are included\n in the output list.\n build_proc_macro (bool, optional): If True, build proc_macro dependencies are\n included in the output list.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()` when unset.\n\n Returns:\n list: A list of labels to generated rust targets (str)\n \"\"\"\n\n if package_name == None:\n package_name = native.package_name()\n\n # Determine the relevant maps to use\n all_dependency_maps = []\n if normal:\n all_dependency_maps.append(_NORMAL_DEPENDENCIES)\n if normal_dev:\n all_dependency_maps.append(_NORMAL_DEV_DEPENDENCIES)\n if proc_macro:\n all_dependency_maps.append(_PROC_MACRO_DEPENDENCIES)\n if proc_macro_dev:\n all_dependency_maps.append(_PROC_MACRO_DEV_DEPENDENCIES)\n if build:\n all_dependency_maps.append(_BUILD_DEPENDENCIES)\n if build_proc_macro:\n all_dependency_maps.append(_BUILD_PROC_MACRO_DEPENDENCIES)\n\n # Default to always using normal dependencies\n if not all_dependency_maps:\n all_dependency_maps.append(_NORMAL_DEPENDENCIES)\n\n dependencies = _flatten_dependency_maps(all_dependency_maps).pop(package_name, None)\n\n if not dependencies:\n if dependencies == None:\n fail(\"Tried to get all_crate_deps for package \" + package_name + \" but that package had no Cargo.toml file\")\n else:\n return []\n\n crate_deps = list(dependencies.pop(_COMMON_CONDITION, {}).values())\n for condition, deps in dependencies.items():\n crate_deps += selects.with_or({\n tuple(_CONDITIONS[condition]): deps.values(),\n \"//conditions:default\": [],\n })\n\n return crate_deps\n\ndef aliases(\n normal = False,\n normal_dev = False,\n proc_macro = False,\n proc_macro_dev = False,\n build = False,\n build_proc_macro = False,\n package_name = None):\n \"\"\"Produces a map of Crate alias names to their original label\n\n If no dependency kinds are specified, `normal` and `proc_macro` are used by default.\n Setting any one flag will otherwise determine the contents of the returned dict.\n\n Args:\n normal (bool, optional): If True, normal dependencies are included in the\n output list.\n normal_dev (bool, optional): If True, normal dev dependencies will be\n included in the output list..\n proc_macro (bool, optional): If True, proc_macro dependencies are included\n in the output list.\n proc_macro_dev (bool, optional): If True, dev proc_macro dependencies are\n included in the output list.\n build (bool, optional): If True, build dependencies are included\n in the output list.\n build_proc_macro (bool, optional): If True, build proc_macro dependencies are\n included in the output list.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()` when unset.\n\n Returns:\n dict: The aliases of all associated packages\n \"\"\"\n if package_name == None:\n package_name = native.package_name()\n\n # Determine the relevant maps to use\n all_aliases_maps = []\n if normal:\n all_aliases_maps.append(_NORMAL_ALIASES)\n if normal_dev:\n all_aliases_maps.append(_NORMAL_DEV_ALIASES)\n if proc_macro:\n all_aliases_maps.append(_PROC_MACRO_ALIASES)\n if proc_macro_dev:\n all_aliases_maps.append(_PROC_MACRO_DEV_ALIASES)\n if build:\n all_aliases_maps.append(_BUILD_ALIASES)\n if build_proc_macro:\n all_aliases_maps.append(_BUILD_PROC_MACRO_ALIASES)\n\n # Default to always using normal aliases\n if not all_aliases_maps:\n all_aliases_maps.append(_NORMAL_ALIASES)\n all_aliases_maps.append(_PROC_MACRO_ALIASES)\n\n aliases = _flatten_dependency_maps(all_aliases_maps).pop(package_name, None)\n\n if not aliases:\n return dict()\n\n common_items = aliases.pop(_COMMON_CONDITION, {}).items()\n\n # If there are only common items in the dictionary, immediately return them\n if not len(aliases.keys()) == 1:\n return dict(common_items)\n\n # Build a single select statement where each conditional has accounted for the\n # common set of aliases.\n crate_aliases = {\"//conditions:default\": dict(common_items)}\n for condition, deps in aliases.items():\n condition_triples = _CONDITIONS[condition]\n for triple in condition_triples:\n if triple in crate_aliases:\n crate_aliases[triple].update(deps)\n else:\n crate_aliases.update({triple: dict(deps.items() + common_items)})\n\n return select(crate_aliases)\n\n###############################################################################\n# WORKSPACE MEMBER DEPS, ALIASES, AND EDITIONS\n###############################################################################\n\n_CRATE_EDITIONS = {\n \"\": \"2024\",\n}\n\n_NORMAL_DEPENDENCIES = {\n \"\": {\n _COMMON_CONDITION: {\n \"anyhow\": Label(\"@postmaster_executor_crates//anyhow-1.0.102\"),\n \"hex\": Label(\"@postmaster_executor_crates//hex-0.4.3\"),\n \"libc\": Label(\"@postmaster_executor_crates//libc-0.2.186\"),\n \"serde\": Label(\"@postmaster_executor_crates//serde-1.0.228\"),\n \"serde_json\": Label(\"@postmaster_executor_crates//serde_json-1.0.149\"),\n \"sha2\": Label(\"@postmaster_executor_crates//sha2-0.11.0\"),\n \"tempfile\": Label(\"@postmaster_executor_crates//tempfile-3.27.0\"),\n \"tokio\": Label(\"@postmaster_executor_crates//tokio-1.52.1\"),\n \"tracing\": Label(\"@postmaster_executor_crates//tracing-0.1.44\"),\n \"wasmer\": Label(\"@postmaster_executor_crates//wasmer-7.2.0-alpha.2\"),\n \"wasmer-types\": Label(\"@postmaster_executor_crates//wasmer-types-7.2.0-alpha.2\"),\n \"wasmer-vm\": Label(\"@postmaster_executor_crates//wasmer-vm-7.2.0-alpha.2\"),\n \"wasmer-wasix\": Label(\"@postmaster_executor_crates//wasmer-wasix-0.702.0-alpha.2\"),\n },\n },\n}\n\n\n_NORMAL_ALIASES = {\n \"\": {\n _COMMON_CONDITION: {\n },\n },\n}\n\n\n_NORMAL_DEV_DEPENDENCIES = {\n \"\": {\n _COMMON_CONDITION: {\n \"futures\": Label(\"@postmaster_executor_crates//futures-0.3.32\"),\n \"wat\": Label(\"@postmaster_executor_crates//wat-1.247.0\"),\n },\n },\n}\n\n\n_NORMAL_DEV_ALIASES = {\n \"\": {\n _COMMON_CONDITION: {\n },\n },\n}\n\n\n_PROC_MACRO_DEPENDENCIES = {\n \"\": {\n _COMMON_CONDITION: {\n \"async-trait\": Label(\"@postmaster_executor_crates//async-trait-0.1.89\"),\n },\n },\n}\n\n\n_PROC_MACRO_ALIASES = {\n \"\": {\n },\n}\n\n\n_PROC_MACRO_DEV_DEPENDENCIES = {\n \"\": {\n },\n}\n\n\n_PROC_MACRO_DEV_ALIASES = {\n \"\": {\n _COMMON_CONDITION: {\n },\n },\n}\n\n\n_BUILD_DEPENDENCIES = {\n \"\": {\n },\n}\n\n\n_BUILD_ALIASES = {\n \"\": {\n },\n}\n\n\n_BUILD_PROC_MACRO_DEPENDENCIES = {\n \"\": {\n },\n}\n\n\n_BUILD_PROC_MACRO_ALIASES = {\n \"\": {\n },\n}\n\n\n_CONDITIONS = {\n \"aarch64-apple-darwin\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\"],\n \"aarch64-linux-android\": [],\n \"aarch64-pc-windows-gnullvm\": [],\n \"aarch64-unknown-linux-gnu\": [\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\"],\n \"cfg(all(any(target_arch = \\\"x86_64\\\", target_arch = \\\"arm64ec\\\"), target_env = \\\"msvc\\\", not(windows_raw_dylib)))\": [],\n \"cfg(all(any(target_os = \\\"linux\\\", target_os = \\\"android\\\"), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\": [],\n \"cfg(all(any(target_os = \\\"linux\\\", target_os = \\\"android\\\"), not(any(all(target_os = \\\"linux\\\", target_env = \\\"\\\"), getrandom_backend = \\\"custom\\\", getrandom_backend = \\\"linux_raw\\\", getrandom_backend = \\\"rdrand\\\", getrandom_backend = \\\"rndr\\\"))))\": [\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\": [\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(all(not(target_arch = \\\"wasm32\\\"), target_os = \\\"windows\\\"))\": [],\n \"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\"],\n \"cfg(all(target_arch = \\\"aarch64\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\": [],\n \"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"android\\\"))\": [],\n \"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"linux\\\"))\": [\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\"],\n \"cfg(all(target_arch = \\\"aarch64\\\", target_vendor = \\\"apple\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\"],\n \"cfg(all(target_arch = \\\"loongarch64\\\", target_os = \\\"linux\\\"))\": [],\n \"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"wasi\\\", target_env = \\\"p2\\\"))\": [],\n \"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"wasi\\\", target_env = \\\"p3\\\"))\": [],\n \"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"gnu\\\", not(target_abi = \\\"llvm\\\"), not(windows_raw_dylib)))\": [],\n \"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\": [],\n \"cfg(all(target_arch = \\\"x86_64\\\", target_env = \\\"gnu\\\", not(target_abi = \\\"llvm\\\"), not(windows_raw_dylib)))\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"wasi\\\"))\": [],\n \"cfg(all(target_os = \\\"macos\\\", target_arch = \\\"aarch64\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\"],\n \"cfg(all(target_os = \\\"uefi\\\", getrandom_backend = \\\"efi_rng\\\"))\": [],\n \"cfg(all(unix, not(target_os = \\\"ios\\\")))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any())\": [],\n \"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(target_arch = \\\"arm\\\", target_pointer_width = \\\"32\\\", target_pointer_width = \\\"64\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(target_arch = \\\"x86\\\", target_arch = \\\"x86_64\\\"))\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(target_family = \\\"unix\\\", all(target_family = \\\"windows\\\", target_env = \\\"gnu\\\")))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(target_os = \\\"android\\\", target_os = \\\"linux\\\", target_os = \\\"macos\\\", target_os = \\\"hurd\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(target_os = \\\"dragonfly\\\", target_os = \\\"freebsd\\\", target_os = \\\"hurd\\\", target_os = \\\"illumos\\\", target_os = \\\"cygwin\\\", all(target_os = \\\"horizon\\\", target_arch = \\\"arm\\\")))\": [],\n \"cfg(any(target_os = \\\"freebsd\\\", target_os = \\\"netbsd\\\"))\": [],\n \"cfg(any(target_os = \\\"haiku\\\", target_os = \\\"redox\\\", target_os = \\\"nto\\\", target_os = \\\"aix\\\"))\": [],\n \"cfg(any(target_os = \\\"ios\\\", target_os = \\\"visionos\\\", target_os = \\\"watchos\\\", target_os = \\\"tvos\\\"))\": [],\n \"cfg(any(target_os = \\\"macos\\\", target_os = \\\"ios\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\"],\n \"cfg(any(target_os = \\\"macos\\\", target_os = \\\"openbsd\\\", target_os = \\\"vita\\\", target_os = \\\"emscripten\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\"],\n \"cfg(any(unix, target_os = \\\"hermit\\\", target_os = \\\"wasi\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(unix, target_os = \\\"wasi\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(windows, target_os = \\\"cygwin\\\"))\": [],\n \"cfg(not(all(windows, target_env = \\\"msvc\\\", not(target_vendor = \\\"uwp\\\"))))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(not(target_arch = \\\"wasm32\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(not(windows))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(target_arch = \\\"spirv\\\")\": [],\n \"cfg(target_arch = \\\"wasm32\\\")\": [],\n \"cfg(target_os = \\\"hermit\\\")\": [],\n \"cfg(target_os = \\\"netbsd\\\")\": [],\n \"cfg(target_os = \\\"redox\\\")\": [],\n \"cfg(target_os = \\\"solaris\\\")\": [],\n \"cfg(target_os = \\\"vxworks\\\")\": [],\n \"cfg(target_os = \\\"wasi\\\")\": [],\n \"cfg(target_os = \\\"windows\\\")\": [],\n \"cfg(target_vendor = \\\"apple\\\")\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\"],\n \"cfg(unix)\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(windows)\": [],\n \"i686-pc-windows-gnullvm\": [],\n \"x86_64-pc-windows-gnullvm\": [],\n \"x86_64-unknown-linux-gnu\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n}\n\n###############################################################################\n\ndef crate_repositories():\n \"\"\"A macro for defining repositories for all generated crates.\n\n Returns:\n A list of repos visible to the module through the module extension.\n \"\"\"\n maybe(\n crates_vendor_remote_repository,\n name = \"postmaster_executor_crates\",\n # Lean interface: just point at `crates.bzl`; the repo rule\n # derives the sibling `BUILD.bazel` and `defs.bzl`.\n crates_module = Label(\"@postmaster_executor_crates//postmaster_executor_crates:crates.bzl\"),\n )\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__addr2line-0.25.1\",\n sha256 = \"1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/addr2line/0.25.1/download\"],\n strip_prefix = \"addr2line-0.25.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.addr2line-0.25.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__adler2-2.0.1\",\n sha256 = \"320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/adler2/2.0.1/download\"],\n strip_prefix = \"adler2-2.0.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.adler2-2.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__aho-corasick-1.1.4\",\n sha256 = \"ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/aho-corasick/1.1.4/download\"],\n strip_prefix = \"aho-corasick-1.1.4\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.aho-corasick-1.1.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__any_ascii-0.1.7\",\n sha256 = \"70033777eb8b5124a81a1889416543dddef2de240019b674c81285a2635a7e1e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/any_ascii/0.1.7/download\"],\n strip_prefix = \"any_ascii-0.1.7\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.any_ascii-0.1.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__anyhow-1.0.102\",\n sha256 = \"7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/anyhow/1.0.102/download\"],\n strip_prefix = \"anyhow-1.0.102\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.anyhow-1.0.102.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__arrayref-0.3.9\",\n sha256 = \"76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/arrayref/0.3.9/download\"],\n strip_prefix = \"arrayref-0.3.9\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.arrayref-0.3.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__arrayvec-0.7.6\",\n sha256 = \"7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/arrayvec/0.7.6/download\"],\n strip_prefix = \"arrayvec-0.7.6\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.arrayvec-0.7.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__async-trait-0.1.89\",\n sha256 = \"9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/async-trait/0.1.89/download\"],\n strip_prefix = \"async-trait-0.1.89\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.async-trait-0.1.89.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__autocfg-1.5.0\",\n sha256 = \"c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/autocfg/1.5.0/download\"],\n strip_prefix = \"autocfg-1.5.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.autocfg-1.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__backtrace-0.3.76\",\n sha256 = \"bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/backtrace/0.3.76/download\"],\n strip_prefix = \"backtrace-0.3.76\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.backtrace-0.3.76.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__base64-0.22.1\",\n sha256 = \"72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/base64/0.22.1/download\"],\n strip_prefix = \"base64-0.22.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.base64-0.22.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__bincode-2.0.1\",\n sha256 = \"36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bincode/2.0.1/download\"],\n strip_prefix = \"bincode-2.0.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.bincode-2.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__bincode_derive-2.0.1\",\n sha256 = \"bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bincode_derive/2.0.1/download\"],\n strip_prefix = \"bincode_derive-2.0.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.bincode_derive-2.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__bindgen-0.72.1\",\n sha256 = \"993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bindgen/0.72.1/download\"],\n strip_prefix = \"bindgen-0.72.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.bindgen-0.72.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__bitflags-1.3.2\",\n sha256 = \"bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bitflags/1.3.2/download\"],\n strip_prefix = \"bitflags-1.3.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.bitflags-1.3.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__bitflags-2.11.1\",\n sha256 = \"c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bitflags/2.11.1/download\"],\n strip_prefix = \"bitflags-2.11.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.bitflags-2.11.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__blake3-1.8.4\",\n sha256 = \"4d2d5991425dfd0785aed03aedcf0b321d61975c9b5b3689c774a2610ae0b51e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/blake3/1.8.4/download\"],\n strip_prefix = \"blake3-1.8.4\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.blake3-1.8.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__block-buffer-0.10.4\",\n sha256 = \"3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/block-buffer/0.10.4/download\"],\n strip_prefix = \"block-buffer-0.10.4\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.block-buffer-0.10.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__block-buffer-0.12.0\",\n sha256 = \"cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/block-buffer/0.12.0/download\"],\n strip_prefix = \"block-buffer-0.12.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.block-buffer-0.12.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__bstr-1.12.1\",\n sha256 = \"63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bstr/1.12.1/download\"],\n strip_prefix = \"bstr-1.12.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.bstr-1.12.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__bumpalo-3.20.2\",\n sha256 = \"5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bumpalo/3.20.2/download\"],\n strip_prefix = \"bumpalo-3.20.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.bumpalo-3.20.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__bytecheck-0.8.2\",\n sha256 = \"0caa33a2c0edca0419d15ac723dff03f1956f7978329b1e3b5fdaaaed9d3ca8b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bytecheck/0.8.2/download\"],\n strip_prefix = \"bytecheck-0.8.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.bytecheck-0.8.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__bytecheck_derive-0.8.2\",\n sha256 = \"89385e82b5d1821d2219e0b095efa2cc1f246cbf99080f3be46a1a85c0d392d9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bytecheck_derive/0.8.2/download\"],\n strip_prefix = \"bytecheck_derive-0.8.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.bytecheck_derive-0.8.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__byteorder-1.5.0\",\n sha256 = \"1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/byteorder/1.5.0/download\"],\n strip_prefix = \"byteorder-1.5.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.byteorder-1.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__bytes-1.11.1\",\n sha256 = \"1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bytes/1.11.1/download\"],\n strip_prefix = \"bytes-1.11.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.bytes-1.11.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__bytesize-2.3.1\",\n sha256 = \"6bd91ee7b2422bcb158d90ef4d14f75ef67f340943fc4149891dcce8f8b972a3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bytesize/2.3.1/download\"],\n strip_prefix = \"bytesize-2.3.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.bytesize-2.3.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__cc-1.2.60\",\n sha256 = \"43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cc/1.2.60/download\"],\n strip_prefix = \"cc-1.2.60\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.cc-1.2.60.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__cexpr-0.6.0\",\n sha256 = \"6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cexpr/0.6.0/download\"],\n strip_prefix = \"cexpr-0.6.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.cexpr-0.6.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__cfg-if-1.0.4\",\n sha256 = \"9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cfg-if/1.0.4/download\"],\n strip_prefix = \"cfg-if-1.0.4\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.cfg-if-1.0.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__chacha20-0.10.0\",\n sha256 = \"6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/chacha20/0.10.0/download\"],\n strip_prefix = \"chacha20-0.10.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.chacha20-0.10.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__chrono-0.4.44\",\n sha256 = \"c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/chrono/0.4.44/download\"],\n strip_prefix = \"chrono-0.4.44\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.chrono-0.4.44.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__ciborium-0.2.2\",\n sha256 = \"42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ciborium/0.2.2/download\"],\n strip_prefix = \"ciborium-0.2.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.ciborium-0.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__ciborium-io-0.2.2\",\n sha256 = \"05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ciborium-io/0.2.2/download\"],\n strip_prefix = \"ciborium-io-0.2.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.ciborium-io-0.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__ciborium-ll-0.2.2\",\n sha256 = \"57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ciborium-ll/0.2.2/download\"],\n strip_prefix = \"ciborium-ll-0.2.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.ciborium-ll-0.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__clang-sys-1.8.1\",\n sha256 = \"0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/clang-sys/1.8.1/download\"],\n strip_prefix = \"clang-sys-1.8.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.clang-sys-1.8.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__cmake-0.1.58\",\n sha256 = \"c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cmake/0.1.58/download\"],\n strip_prefix = \"cmake-0.1.58\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.cmake-0.1.58.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__console-0.16.3\",\n sha256 = \"d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/console/0.16.3/download\"],\n strip_prefix = \"console-0.16.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.console-0.16.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__const-oid-0.10.2\",\n sha256 = \"a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/const-oid/0.10.2/download\"],\n strip_prefix = \"const-oid-0.10.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.const-oid-0.10.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__constant_time_eq-0.4.2\",\n sha256 = \"3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/constant_time_eq/0.4.2/download\"],\n strip_prefix = \"constant_time_eq-0.4.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.constant_time_eq-0.4.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__convert_case-0.10.0\",\n sha256 = \"633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/convert_case/0.10.0/download\"],\n strip_prefix = \"convert_case-0.10.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.convert_case-0.10.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__cooked-waker-5.0.0\",\n sha256 = \"147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cooked-waker/5.0.0/download\"],\n strip_prefix = \"cooked-waker-5.0.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.cooked-waker-5.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__corosensei-0.3.3\",\n sha256 = \"2c54787b605c7df106ceccf798df23da4f2e09918defad66705d1cedf3bb914f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/corosensei/0.3.3/download\"],\n strip_prefix = \"corosensei-0.3.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.corosensei-0.3.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__cpp_demangle-0.4.5\",\n sha256 = \"f2bb79cb74d735044c972aae58ed0aaa9a837e85b01106a54c39e42e97f62253\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cpp_demangle/0.4.5/download\"],\n strip_prefix = \"cpp_demangle-0.4.5\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.cpp_demangle-0.4.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__cpufeatures-0.2.17\",\n sha256 = \"59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cpufeatures/0.2.17/download\"],\n strip_prefix = \"cpufeatures-0.2.17\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.cpufeatures-0.2.17.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__cpufeatures-0.3.0\",\n sha256 = \"8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cpufeatures/0.3.0/download\"],\n strip_prefix = \"cpufeatures-0.3.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.cpufeatures-0.3.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__crc32fast-1.5.0\",\n sha256 = \"9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crc32fast/1.5.0/download\"],\n strip_prefix = \"crc32fast-1.5.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.crc32fast-1.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__crossbeam-channel-0.5.15\",\n sha256 = \"82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crossbeam-channel/0.5.15/download\"],\n strip_prefix = \"crossbeam-channel-0.5.15\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.crossbeam-channel-0.5.15.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__crossbeam-deque-0.8.6\",\n sha256 = \"9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crossbeam-deque/0.8.6/download\"],\n strip_prefix = \"crossbeam-deque-0.8.6\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.crossbeam-deque-0.8.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__crossbeam-epoch-0.9.18\",\n sha256 = \"5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crossbeam-epoch/0.9.18/download\"],\n strip_prefix = \"crossbeam-epoch-0.9.18\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.crossbeam-epoch-0.9.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__crossbeam-queue-0.3.12\",\n sha256 = \"0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crossbeam-queue/0.3.12/download\"],\n strip_prefix = \"crossbeam-queue-0.3.12\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.crossbeam-queue-0.3.12.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__crossbeam-utils-0.8.21\",\n sha256 = \"d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crossbeam-utils/0.8.21/download\"],\n strip_prefix = \"crossbeam-utils-0.8.21\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.crossbeam-utils-0.8.21.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__crunchy-0.2.4\",\n sha256 = \"460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crunchy/0.2.4/download\"],\n strip_prefix = \"crunchy-0.2.4\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.crunchy-0.2.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__crypto-common-0.1.7\",\n sha256 = \"78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crypto-common/0.1.7/download\"],\n strip_prefix = \"crypto-common-0.1.7\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.crypto-common-0.1.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__crypto-common-0.2.1\",\n sha256 = \"77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crypto-common/0.2.1/download\"],\n strip_prefix = \"crypto-common-0.2.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.crypto-common-0.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__darling-0.20.11\",\n sha256 = \"fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/darling/0.20.11/download\"],\n strip_prefix = \"darling-0.20.11\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.darling-0.20.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__darling-0.21.3\",\n sha256 = \"9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/darling/0.21.3/download\"],\n strip_prefix = \"darling-0.21.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.darling-0.21.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__darling_core-0.20.11\",\n sha256 = \"0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/darling_core/0.20.11/download\"],\n strip_prefix = \"darling_core-0.20.11\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.darling_core-0.20.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__darling_core-0.21.3\",\n sha256 = \"1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/darling_core/0.21.3/download\"],\n strip_prefix = \"darling_core-0.21.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.darling_core-0.21.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__darling_macro-0.20.11\",\n sha256 = \"fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/darling_macro/0.20.11/download\"],\n strip_prefix = \"darling_macro-0.20.11\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.darling_macro-0.20.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__darling_macro-0.21.3\",\n sha256 = \"d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/darling_macro/0.21.3/download\"],\n strip_prefix = \"darling_macro-0.21.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.darling_macro-0.21.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__dashmap-6.1.0\",\n sha256 = \"5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/dashmap/6.1.0/download\"],\n strip_prefix = \"dashmap-6.1.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.dashmap-6.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__debugid-0.8.0\",\n sha256 = \"bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/debugid/0.8.0/download\"],\n strip_prefix = \"debugid-0.8.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.debugid-0.8.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__defmt-0.3.100\",\n sha256 = \"f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/defmt/0.3.100/download\"],\n strip_prefix = \"defmt-0.3.100\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.defmt-0.3.100.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__defmt-1.0.1\",\n sha256 = \"548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/defmt/1.0.1/download\"],\n strip_prefix = \"defmt-1.0.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.defmt-1.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__defmt-macros-1.0.1\",\n sha256 = \"3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/defmt-macros/1.0.1/download\"],\n strip_prefix = \"defmt-macros-1.0.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.defmt-macros-1.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__defmt-parser-1.0.0\",\n sha256 = \"10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/defmt-parser/1.0.0/download\"],\n strip_prefix = \"defmt-parser-1.0.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.defmt-parser-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__deranged-0.5.8\",\n sha256 = \"7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/deranged/0.5.8/download\"],\n strip_prefix = \"deranged-0.5.8\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.deranged-0.5.8.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__derive_builder-0.20.2\",\n sha256 = \"507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/derive_builder/0.20.2/download\"],\n strip_prefix = \"derive_builder-0.20.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.derive_builder-0.20.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__derive_builder_core-0.20.2\",\n sha256 = \"2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/derive_builder_core/0.20.2/download\"],\n strip_prefix = \"derive_builder_core-0.20.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.derive_builder_core-0.20.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__derive_builder_macro-0.20.2\",\n sha256 = \"ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/derive_builder_macro/0.20.2/download\"],\n strip_prefix = \"derive_builder_macro-0.20.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.derive_builder_macro-0.20.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__derive_more-2.1.1\",\n sha256 = \"d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/derive_more/2.1.1/download\"],\n strip_prefix = \"derive_more-2.1.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.derive_more-2.1.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__derive_more-impl-2.1.1\",\n sha256 = \"799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/derive_more-impl/2.1.1/download\"],\n strip_prefix = \"derive_more-impl-2.1.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.derive_more-impl-2.1.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__digest-0.10.7\",\n sha256 = \"9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/digest/0.10.7/download\"],\n strip_prefix = \"digest-0.10.7\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.digest-0.10.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__digest-0.11.2\",\n sha256 = \"4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/digest/0.11.2/download\"],\n strip_prefix = \"digest-0.11.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.digest-0.11.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__displaydoc-0.2.5\",\n sha256 = \"97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/displaydoc/0.2.5/download\"],\n strip_prefix = \"displaydoc-0.2.5\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.displaydoc-0.2.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__document-features-0.2.12\",\n sha256 = \"d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/document-features/0.2.12/download\"],\n strip_prefix = \"document-features-0.2.12\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.document-features-0.2.12.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__dunce-1.0.5\",\n sha256 = \"92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/dunce/1.0.5/download\"],\n strip_prefix = \"dunce-1.0.5\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.dunce-1.0.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__dyn-clone-1.0.20\",\n sha256 = \"d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/dyn-clone/1.0.20/download\"],\n strip_prefix = \"dyn-clone-1.0.20\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.dyn-clone-1.0.20.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__either-1.15.0\",\n sha256 = \"48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/either/1.15.0/download\"],\n strip_prefix = \"either-1.15.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.either-1.15.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__encode_unicode-1.0.0\",\n sha256 = \"34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/encode_unicode/1.0.0/download\"],\n strip_prefix = \"encode_unicode-1.0.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.encode_unicode-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__enum-iterator-2.3.0\",\n sha256 = \"a4549325971814bda7a44061bf3fe7e487d447cba01e4220a4b454d630d7a016\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/enum-iterator/2.3.0/download\"],\n strip_prefix = \"enum-iterator-2.3.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.enum-iterator-2.3.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__enum-iterator-derive-1.5.0\",\n sha256 = \"685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/enum-iterator-derive/1.5.0/download\"],\n strip_prefix = \"enum-iterator-derive-1.5.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.enum-iterator-derive-1.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__enumset-1.1.10\",\n sha256 = \"25b07a8dfbbbfc0064c0a6bdf9edcf966de6b1c33ce344bdeca3b41615452634\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/enumset/1.1.10/download\"],\n strip_prefix = \"enumset-1.1.10\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.enumset-1.1.10.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__enumset_derive-0.14.0\",\n sha256 = \"f43e744e4ea338060faee68ed933e46e722fb7f3617e722a5772d7e856d8b3ce\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/enumset_derive/0.14.0/download\"],\n strip_prefix = \"enumset_derive-0.14.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.enumset_derive-0.14.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__equivalent-1.0.2\",\n sha256 = \"877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/equivalent/1.0.2/download\"],\n strip_prefix = \"equivalent-1.0.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.equivalent-1.0.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__errno-0.3.14\",\n sha256 = \"39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/errno/0.3.14/download\"],\n strip_prefix = \"errno-0.3.14\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.errno-0.3.14.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__fastrand-2.4.1\",\n sha256 = \"9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/fastrand/2.4.1/download\"],\n strip_prefix = \"fastrand-2.4.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.fastrand-2.4.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__filetime-0.2.27\",\n sha256 = \"f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/filetime/0.2.27/download\"],\n strip_prefix = \"filetime-0.2.27\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.filetime-0.2.27.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__find-msvc-tools-0.1.9\",\n sha256 = \"5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/find-msvc-tools/0.1.9/download\"],\n strip_prefix = \"find-msvc-tools-0.1.9\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.find-msvc-tools-0.1.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__fixedbitset-0.5.7\",\n sha256 = \"1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/fixedbitset/0.5.7/download\"],\n strip_prefix = \"fixedbitset-0.5.7\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.fixedbitset-0.5.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__flate2-1.1.9\",\n sha256 = \"843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/flate2/1.1.9/download\"],\n strip_prefix = \"flate2-1.1.9\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.flate2-1.1.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__fnv-1.0.7\",\n sha256 = \"3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/fnv/1.0.7/download\"],\n strip_prefix = \"fnv-1.0.7\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.fnv-1.0.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__foldhash-0.1.5\",\n sha256 = \"d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/foldhash/0.1.5/download\"],\n strip_prefix = \"foldhash-0.1.5\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.foldhash-0.1.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__foldhash-0.2.0\",\n sha256 = \"77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/foldhash/0.2.0/download\"],\n strip_prefix = \"foldhash-0.2.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.foldhash-0.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__form_urlencoded-1.2.2\",\n sha256 = \"cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/form_urlencoded/1.2.2/download\"],\n strip_prefix = \"form_urlencoded-1.2.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.form_urlencoded-1.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__fs_extra-1.3.0\",\n sha256 = \"42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/fs_extra/1.3.0/download\"],\n strip_prefix = \"fs_extra-1.3.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.fs_extra-1.3.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__futures-0.3.32\",\n sha256 = \"8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures/0.3.32/download\"],\n strip_prefix = \"futures-0.3.32\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.futures-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__futures-channel-0.3.32\",\n sha256 = \"07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-channel/0.3.32/download\"],\n strip_prefix = \"futures-channel-0.3.32\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.futures-channel-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__futures-core-0.3.32\",\n sha256 = \"7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-core/0.3.32/download\"],\n strip_prefix = \"futures-core-0.3.32\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.futures-core-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__futures-executor-0.3.32\",\n sha256 = \"baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-executor/0.3.32/download\"],\n strip_prefix = \"futures-executor-0.3.32\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.futures-executor-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__futures-io-0.3.32\",\n sha256 = \"cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-io/0.3.32/download\"],\n strip_prefix = \"futures-io-0.3.32\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.futures-io-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__futures-macro-0.3.32\",\n sha256 = \"e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-macro/0.3.32/download\"],\n strip_prefix = \"futures-macro-0.3.32\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.futures-macro-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__futures-sink-0.3.32\",\n sha256 = \"c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-sink/0.3.32/download\"],\n strip_prefix = \"futures-sink-0.3.32\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.futures-sink-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__futures-task-0.3.32\",\n sha256 = \"037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-task/0.3.32/download\"],\n strip_prefix = \"futures-task-0.3.32\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.futures-task-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__futures-util-0.3.32\",\n sha256 = \"389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-util/0.3.32/download\"],\n strip_prefix = \"futures-util-0.3.32\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.futures-util-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__generic-array-0.14.7\",\n sha256 = \"85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/generic-array/0.14.7/download\"],\n strip_prefix = \"generic-array-0.14.7\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.generic-array-0.14.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__getrandom-0.3.4\",\n sha256 = \"899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/getrandom/0.3.4/download\"],\n strip_prefix = \"getrandom-0.3.4\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.getrandom-0.3.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__getrandom-0.4.2\",\n sha256 = \"0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/getrandom/0.4.2/download\"],\n strip_prefix = \"getrandom-0.4.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.getrandom-0.4.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__gimli-0.32.3\",\n sha256 = \"e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/gimli/0.32.3/download\"],\n strip_prefix = \"gimli-0.32.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.gimli-0.32.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__gimli-0.33.0\",\n sha256 = \"0bf7f043f89559805f8c7cacc432749b2fa0d0a0a9ee46ce47164ed5ba7f126c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/gimli/0.33.0/download\"],\n strip_prefix = \"gimli-0.33.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.gimli-0.33.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__glob-0.3.3\",\n sha256 = \"0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/glob/0.3.3/download\"],\n strip_prefix = \"glob-0.3.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.glob-0.3.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__globset-0.4.18\",\n sha256 = \"52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/globset/0.4.18/download\"],\n strip_prefix = \"globset-0.4.18\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.globset-0.4.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__half-2.7.1\",\n sha256 = \"6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/half/2.7.1/download\"],\n strip_prefix = \"half-2.7.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.half-2.7.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__hash32-0.3.1\",\n sha256 = \"47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hash32/0.3.1/download\"],\n strip_prefix = \"hash32-0.3.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.hash32-0.3.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__hashbrown-0.14.5\",\n sha256 = \"e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hashbrown/0.14.5/download\"],\n strip_prefix = \"hashbrown-0.14.5\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.hashbrown-0.14.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__hashbrown-0.15.5\",\n sha256 = \"9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hashbrown/0.15.5/download\"],\n strip_prefix = \"hashbrown-0.15.5\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.hashbrown-0.15.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__hashbrown-0.16.1\",\n sha256 = \"841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hashbrown/0.16.1/download\"],\n strip_prefix = \"hashbrown-0.16.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.hashbrown-0.16.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__hashbrown-0.17.0\",\n sha256 = \"4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hashbrown/0.17.0/download\"],\n strip_prefix = \"hashbrown-0.17.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.hashbrown-0.17.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__heapless-0.9.2\",\n sha256 = \"2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/heapless/0.9.2/download\"],\n strip_prefix = \"heapless-0.9.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.heapless-0.9.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__heck-0.3.3\",\n sha256 = \"6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/heck/0.3.3/download\"],\n strip_prefix = \"heck-0.3.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.heck-0.3.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__heck-0.5.0\",\n sha256 = \"2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/heck/0.5.0/download\"],\n strip_prefix = \"heck-0.5.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.heck-0.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__hermit-abi-0.5.2\",\n sha256 = \"fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hermit-abi/0.5.2/download\"],\n strip_prefix = \"hermit-abi-0.5.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.hermit-abi-0.5.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__hex-0.4.3\",\n sha256 = \"7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hex/0.4.3/download\"],\n strip_prefix = \"hex-0.4.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.hex-0.4.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__http-1.4.0\",\n sha256 = \"e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/http/1.4.0/download\"],\n strip_prefix = \"http-1.4.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.http-1.4.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__hybrid-array-0.4.10\",\n sha256 = \"3944cf8cf766b40e2a1a333ee5e9b563f854d5fa49d6a8ca2764e97c6eddb214\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hybrid-array/0.4.10/download\"],\n strip_prefix = \"hybrid-array-0.4.10\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.hybrid-array-0.4.10.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__icu_collections-2.2.0\",\n sha256 = \"2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_collections/2.2.0/download\"],\n strip_prefix = \"icu_collections-2.2.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.icu_collections-2.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__icu_locale_core-2.2.0\",\n sha256 = \"92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_locale_core/2.2.0/download\"],\n strip_prefix = \"icu_locale_core-2.2.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.icu_locale_core-2.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__icu_normalizer-2.2.0\",\n sha256 = \"c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_normalizer/2.2.0/download\"],\n strip_prefix = \"icu_normalizer-2.2.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.icu_normalizer-2.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__icu_normalizer_data-2.2.0\",\n sha256 = \"da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_normalizer_data/2.2.0/download\"],\n strip_prefix = \"icu_normalizer_data-2.2.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.icu_normalizer_data-2.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__icu_properties-2.2.0\",\n sha256 = \"bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_properties/2.2.0/download\"],\n strip_prefix = \"icu_properties-2.2.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.icu_properties-2.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__icu_properties_data-2.2.0\",\n sha256 = \"8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_properties_data/2.2.0/download\"],\n strip_prefix = \"icu_properties_data-2.2.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.icu_properties_data-2.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__icu_provider-2.2.0\",\n sha256 = \"139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_provider/2.2.0/download\"],\n strip_prefix = \"icu_provider-2.2.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.icu_provider-2.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__id-arena-2.3.0\",\n sha256 = \"3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/id-arena/2.3.0/download\"],\n strip_prefix = \"id-arena-2.3.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.id-arena-2.3.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__ident_case-1.0.1\",\n sha256 = \"b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ident_case/1.0.1/download\"],\n strip_prefix = \"ident_case-1.0.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.ident_case-1.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__idna-1.1.0\",\n sha256 = \"3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/idna/1.1.0/download\"],\n strip_prefix = \"idna-1.1.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.idna-1.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__idna_adapter-1.2.1\",\n sha256 = \"3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/idna_adapter/1.2.1/download\"],\n strip_prefix = \"idna_adapter-1.2.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.idna_adapter-1.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__ignore-0.4.25\",\n sha256 = \"d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ignore/0.4.25/download\"],\n strip_prefix = \"ignore-0.4.25\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.ignore-0.4.25.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__indexmap-2.14.0\",\n sha256 = \"d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/indexmap/2.14.0/download\"],\n strip_prefix = \"indexmap-2.14.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.indexmap-2.14.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__insta-1.47.2\",\n sha256 = \"7b4a6248eb93a4401ed2f37dfe8ea592d3cf05b7cf4f8efa867b6895af7e094e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/insta/1.47.2/download\"],\n strip_prefix = \"insta-1.47.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.insta-1.47.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__ipnet-2.12.0\",\n sha256 = \"d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ipnet/2.12.0/download\"],\n strip_prefix = \"ipnet-2.12.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.ipnet-2.12.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__iprange-0.6.7\",\n sha256 = \"37209be0ad225457e63814401415e748e2453a5297f9b637338f5fb8afa4ec00\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/iprange/0.6.7/download\"],\n strip_prefix = \"iprange-0.6.7\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.iprange-0.6.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__itertools-0.13.0\",\n sha256 = \"413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/itertools/0.13.0/download\"],\n strip_prefix = \"itertools-0.13.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.itertools-0.13.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__itertools-0.14.0\",\n sha256 = \"2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/itertools/0.14.0/download\"],\n strip_prefix = \"itertools-0.14.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.itertools-0.14.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__itoa-1.0.18\",\n sha256 = \"8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/itoa/1.0.18/download\"],\n strip_prefix = \"itoa-1.0.18\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.itoa-1.0.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__jobserver-0.1.34\",\n sha256 = \"9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/jobserver/0.1.34/download\"],\n strip_prefix = \"jobserver-0.1.34\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.jobserver-0.1.34.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__js-sys-0.3.95\",\n sha256 = \"2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/js-sys/0.3.95/download\"],\n strip_prefix = \"js-sys-0.3.95\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.js-sys-0.3.95.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__leb128-0.2.6\",\n sha256 = \"6cc46bac87ef8093eed6f272babb833b6443374399985ac8ed28471ee0918545\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/leb128/0.2.6/download\"],\n strip_prefix = \"leb128-0.2.6\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.leb128-0.2.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__leb128fmt-0.1.0\",\n sha256 = \"09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/leb128fmt/0.1.0/download\"],\n strip_prefix = \"leb128fmt-0.1.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.leb128fmt-0.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__lexical-sort-0.3.1\",\n sha256 = \"c09e4591611e231daf4d4c685a66cb0410cc1e502027a20ae55f2bb9e997207a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/lexical-sort/0.3.1/download\"],\n strip_prefix = \"lexical-sort-0.3.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.lexical-sort-0.3.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__libc-0.2.186\",\n sha256 = \"68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/libc/0.2.186/download\"],\n strip_prefix = \"libc-0.2.186\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.libc-0.2.186.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__libloading-0.8.9\",\n sha256 = \"d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/libloading/0.8.9/download\"],\n strip_prefix = \"libloading-0.8.9\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.libloading-0.8.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__libredox-0.1.16\",\n sha256 = \"e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/libredox/0.1.16/download\"],\n strip_prefix = \"libredox-0.1.16\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.libredox-0.1.16.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__libunwind-1.3.3\",\n sha256 = \"0c6639b70a7ce854b79c70d7e83f16b5dc0137cc914f3d7d03803b513ecc67ac\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/libunwind/1.3.3/download\"],\n strip_prefix = \"libunwind-1.3.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.libunwind-1.3.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__linked-hash-map-0.5.6\",\n sha256 = \"0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/linked-hash-map/0.5.6/download\"],\n strip_prefix = \"linked-hash-map-0.5.6\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.linked-hash-map-0.5.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__linked_hash_set-0.1.6\",\n sha256 = \"984fb35d06508d1e69fc91050cceba9c0b748f983e6739fa2c7a9237154c52c8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/linked_hash_set/0.1.6/download\"],\n strip_prefix = \"linked_hash_set-0.1.6\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.linked_hash_set-0.1.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__linux-raw-sys-0.12.1\",\n sha256 = \"32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/linux-raw-sys/0.12.1/download\"],\n strip_prefix = \"linux-raw-sys-0.12.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.linux-raw-sys-0.12.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__litemap-0.8.2\",\n sha256 = \"92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/litemap/0.8.2/download\"],\n strip_prefix = \"litemap-0.8.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.litemap-0.8.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__litrs-1.0.0\",\n sha256 = \"11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/litrs/1.0.0/download\"],\n strip_prefix = \"litrs-1.0.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.litrs-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__lock_api-0.4.14\",\n sha256 = \"224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/lock_api/0.4.14/download\"],\n strip_prefix = \"lock_api-0.4.14\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.lock_api-0.4.14.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__log-0.4.29\",\n sha256 = \"5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/log/0.4.29/download\"],\n strip_prefix = \"log-0.4.29\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.log-0.4.29.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__lz4_flex-0.13.0\",\n sha256 = \"db9a0d582c2874f68138a16ce1867e0ffde6c0bb0a0df85e1f36d04146db488a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/lz4_flex/0.13.0/download\"],\n strip_prefix = \"lz4_flex-0.13.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.lz4_flex-0.13.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__mach2-0.4.3\",\n sha256 = \"d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/mach2/0.4.3/download\"],\n strip_prefix = \"mach2-0.4.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.mach2-0.4.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__mach2-0.6.0\",\n sha256 = \"dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/mach2/0.6.0/download\"],\n strip_prefix = \"mach2-0.6.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.mach2-0.6.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__macho-unwind-info-0.5.0\",\n sha256 = \"bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/macho-unwind-info/0.5.0/download\"],\n strip_prefix = \"macho-unwind-info-0.5.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.macho-unwind-info-0.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__managed-0.8.0\",\n sha256 = \"0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/managed/0.8.0/download\"],\n strip_prefix = \"managed-0.8.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.managed-0.8.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__memchr-2.8.0\",\n sha256 = \"f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/memchr/2.8.0/download\"],\n strip_prefix = \"memchr-2.8.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.memchr-2.8.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__memmap2-0.6.2\",\n sha256 = \"6d28bba84adfe6646737845bc5ebbfa2c08424eb1c37e94a1fd2a82adb56a872\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/memmap2/0.6.2/download\"],\n strip_prefix = \"memmap2-0.6.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.memmap2-0.6.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__memmap2-0.9.10\",\n sha256 = \"714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/memmap2/0.9.10/download\"],\n strip_prefix = \"memmap2-0.9.10\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.memmap2-0.9.10.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__memoffset-0.9.1\",\n sha256 = \"488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/memoffset/0.9.1/download\"],\n strip_prefix = \"memoffset-0.9.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.memoffset-0.9.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__minimal-lexical-0.2.1\",\n sha256 = \"68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/minimal-lexical/0.2.1/download\"],\n strip_prefix = \"minimal-lexical-0.2.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.minimal-lexical-0.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__miniz_oxide-0.8.9\",\n sha256 = \"1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/miniz_oxide/0.8.9/download\"],\n strip_prefix = \"miniz_oxide-0.8.9\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.miniz_oxide-0.8.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__mio-1.2.0\",\n sha256 = \"50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/mio/1.2.0/download\"],\n strip_prefix = \"mio-1.2.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.mio-1.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__more-asserts-0.3.1\",\n sha256 = \"1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/more-asserts/0.3.1/download\"],\n strip_prefix = \"more-asserts-0.3.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.more-asserts-0.3.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__msvc-demangler-0.11.0\",\n sha256 = \"fbeff6bd154a309b2ada5639b2661ca6ae4599b34e8487dc276d2cd637da2d76\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/msvc-demangler/0.11.0/download\"],\n strip_prefix = \"msvc-demangler-0.11.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.msvc-demangler-0.11.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__munge-0.4.7\",\n sha256 = \"5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/munge/0.4.7/download\"],\n strip_prefix = \"munge-0.4.7\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.munge-0.4.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__munge_macro-0.4.7\",\n sha256 = \"4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/munge_macro/0.4.7/download\"],\n strip_prefix = \"munge_macro-0.4.7\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.munge_macro-0.4.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__nom-5.1.3\",\n sha256 = \"08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/nom/5.1.3/download\"],\n strip_prefix = \"nom-5.1.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.nom-5.1.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__nom-7.1.3\",\n sha256 = \"d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/nom/7.1.3/download\"],\n strip_prefix = \"nom-7.1.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.nom-7.1.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__num-conv-0.2.1\",\n sha256 = \"c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/num-conv/0.2.1/download\"],\n strip_prefix = \"num-conv-0.2.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.num-conv-0.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__num-traits-0.2.19\",\n sha256 = \"071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/num-traits/0.2.19/download\"],\n strip_prefix = \"num-traits-0.2.19\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.num-traits-0.2.19.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__num_cpus-1.17.0\",\n sha256 = \"91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/num_cpus/1.17.0/download\"],\n strip_prefix = \"num_cpus-1.17.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.num_cpus-1.17.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__num_enum-0.7.6\",\n sha256 = \"5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/num_enum/0.7.6/download\"],\n strip_prefix = \"num_enum-0.7.6\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.num_enum-0.7.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__num_enum_derive-0.7.6\",\n sha256 = \"680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/num_enum_derive/0.7.6/download\"],\n strip_prefix = \"num_enum_derive-0.7.6\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.num_enum_derive-0.7.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__object-0.37.3\",\n sha256 = \"ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/object/0.37.3/download\"],\n strip_prefix = \"object-0.37.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.object-0.37.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__object-0.39.1\",\n sha256 = \"2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/object/0.39.1/download\"],\n strip_prefix = \"object-0.39.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.object-0.39.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__once_cell-1.21.4\",\n sha256 = \"9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/once_cell/1.21.4/download\"],\n strip_prefix = \"once_cell-1.21.4\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.once_cell-1.21.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__parking-2.2.1\",\n sha256 = \"f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/parking/2.2.1/download\"],\n strip_prefix = \"parking-2.2.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.parking-2.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__parking_lot-0.12.5\",\n sha256 = \"93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/parking_lot/0.12.5/download\"],\n strip_prefix = \"parking_lot-0.12.5\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.parking_lot-0.12.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__parking_lot_core-0.9.12\",\n sha256 = \"2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/parking_lot_core/0.9.12/download\"],\n strip_prefix = \"parking_lot_core-0.9.12\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.parking_lot_core-0.9.12.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__paste-1.0.15\",\n sha256 = \"57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/paste/1.0.15/download\"],\n strip_prefix = \"paste-1.0.15\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.paste-1.0.15.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__path-clean-1.0.1\",\n sha256 = \"17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/path-clean/1.0.1/download\"],\n strip_prefix = \"path-clean-1.0.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.path-clean-1.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__percent-encoding-2.3.2\",\n sha256 = \"9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/percent-encoding/2.3.2/download\"],\n strip_prefix = \"percent-encoding-2.3.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.percent-encoding-2.3.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__petgraph-0.8.3\",\n sha256 = \"8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/petgraph/0.8.3/download\"],\n strip_prefix = \"petgraph-0.8.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.petgraph-0.8.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__pin-project-1.1.11\",\n sha256 = \"f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pin-project/1.1.11/download\"],\n strip_prefix = \"pin-project-1.1.11\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.pin-project-1.1.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__pin-project-internal-1.1.11\",\n sha256 = \"d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pin-project-internal/1.1.11/download\"],\n strip_prefix = \"pin-project-internal-1.1.11\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.pin-project-internal-1.1.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__pin-project-lite-0.2.17\",\n sha256 = \"a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pin-project-lite/0.2.17/download\"],\n strip_prefix = \"pin-project-lite-0.2.17\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.pin-project-lite-0.2.17.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__pin-utils-0.1.0\",\n sha256 = \"8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pin-utils/0.1.0/download\"],\n strip_prefix = \"pin-utils-0.1.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.pin-utils-0.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__pkg-config-0.3.33\",\n sha256 = \"19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pkg-config/0.3.33/download\"],\n strip_prefix = \"pkg-config-0.3.33\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.pkg-config-0.3.33.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__plain-0.2.3\",\n sha256 = \"b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/plain/0.2.3/download\"],\n strip_prefix = \"plain-0.2.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.plain-0.2.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__potential_utf-0.1.5\",\n sha256 = \"0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/potential_utf/0.1.5/download\"],\n strip_prefix = \"potential_utf-0.1.5\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.potential_utf-0.1.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__powerfmt-0.2.0\",\n sha256 = \"439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/powerfmt/0.2.0/download\"],\n strip_prefix = \"powerfmt-0.2.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.powerfmt-0.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__ppv-lite86-0.2.21\",\n sha256 = \"85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ppv-lite86/0.2.21/download\"],\n strip_prefix = \"ppv-lite86-0.2.21\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.ppv-lite86-0.2.21.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__prettyplease-0.2.37\",\n sha256 = \"479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/prettyplease/0.2.37/download\"],\n strip_prefix = \"prettyplease-0.2.37\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.prettyplease-0.2.37.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__proc-macro-crate-3.5.0\",\n sha256 = \"e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/proc-macro-crate/3.5.0/download\"],\n strip_prefix = \"proc-macro-crate-3.5.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.proc-macro-crate-3.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__proc-macro-error-attr2-2.0.0\",\n sha256 = \"96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/proc-macro-error-attr2/2.0.0/download\"],\n strip_prefix = \"proc-macro-error-attr2-2.0.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.proc-macro-error-attr2-2.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__proc-macro-error2-2.0.1\",\n sha256 = \"11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/proc-macro-error2/2.0.1/download\"],\n strip_prefix = \"proc-macro-error2-2.0.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.proc-macro-error2-2.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__proc-macro2-1.0.106\",\n sha256 = \"8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/proc-macro2/1.0.106/download\"],\n strip_prefix = \"proc-macro2-1.0.106\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.proc-macro2-1.0.106.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__ptr_meta-0.3.1\",\n sha256 = \"0b9a0cf95a1196af61d4f1cbdab967179516d9a4a4312af1f31948f8f6224a79\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ptr_meta/0.3.1/download\"],\n strip_prefix = \"ptr_meta-0.3.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.ptr_meta-0.3.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__ptr_meta_derive-0.3.1\",\n sha256 = \"7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ptr_meta_derive/0.3.1/download\"],\n strip_prefix = \"ptr_meta_derive-0.3.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.ptr_meta_derive-0.3.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__pulldown-cmark-0.8.0\",\n sha256 = \"ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pulldown-cmark/0.8.0/download\"],\n strip_prefix = \"pulldown-cmark-0.8.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.pulldown-cmark-0.8.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__quote-1.0.45\",\n sha256 = \"41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/quote/1.0.45/download\"],\n strip_prefix = \"quote-1.0.45\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.quote-1.0.45.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__r-efi-5.3.0\",\n sha256 = \"69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/r-efi/5.3.0/download\"],\n strip_prefix = \"r-efi-5.3.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.r-efi-5.3.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__r-efi-6.0.0\",\n sha256 = \"f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/r-efi/6.0.0/download\"],\n strip_prefix = \"r-efi-6.0.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.r-efi-6.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__rancor-0.1.1\",\n sha256 = \"a063ea72381527c2a0561da9c80000ef822bdd7c3241b1cc1b12100e3df081ee\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rancor/0.1.1/download\"],\n strip_prefix = \"rancor-0.1.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.rancor-0.1.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__rand-0.10.1\",\n sha256 = \"d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rand/0.10.1/download\"],\n strip_prefix = \"rand-0.10.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.rand-0.10.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__rand-0.9.4\",\n sha256 = \"44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rand/0.9.4/download\"],\n strip_prefix = \"rand-0.9.4\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.rand-0.9.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__rand_chacha-0.9.0\",\n sha256 = \"d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rand_chacha/0.9.0/download\"],\n strip_prefix = \"rand_chacha-0.9.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.rand_chacha-0.9.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__rand_core-0.10.1\",\n sha256 = \"63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rand_core/0.10.1/download\"],\n strip_prefix = \"rand_core-0.10.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.rand_core-0.10.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__rand_core-0.9.5\",\n sha256 = \"76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rand_core/0.9.5/download\"],\n strip_prefix = \"rand_core-0.9.5\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.rand_core-0.9.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__rangemap-1.7.1\",\n sha256 = \"973443cf09a9c8656b574a866ab68dfa19f0867d0340648c7d2f6a71b8a8ea68\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rangemap/1.7.1/download\"],\n strip_prefix = \"rangemap-1.7.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.rangemap-1.7.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__rayon-1.12.0\",\n sha256 = \"fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rayon/1.12.0/download\"],\n strip_prefix = \"rayon-1.12.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.rayon-1.12.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__rayon-core-1.13.0\",\n sha256 = \"22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rayon-core/1.13.0/download\"],\n strip_prefix = \"rayon-core-1.13.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.rayon-core-1.13.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__redox_syscall-0.5.18\",\n sha256 = \"ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/redox_syscall/0.5.18/download\"],\n strip_prefix = \"redox_syscall-0.5.18\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.redox_syscall-0.5.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__redox_syscall-0.7.4\",\n sha256 = \"f450ad9c3b1da563fb6948a8e0fb0fb9269711c9c73d9ea1de5058c79c8d643a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/redox_syscall/0.7.4/download\"],\n strip_prefix = \"redox_syscall-0.7.4\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.redox_syscall-0.7.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__ref-cast-1.0.25\",\n sha256 = \"f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ref-cast/1.0.25/download\"],\n strip_prefix = \"ref-cast-1.0.25\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.ref-cast-1.0.25.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__ref-cast-impl-1.0.25\",\n sha256 = \"b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ref-cast-impl/1.0.25/download\"],\n strip_prefix = \"ref-cast-impl-1.0.25\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.ref-cast-impl-1.0.25.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__regex-1.12.3\",\n sha256 = \"e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/regex/1.12.3/download\"],\n strip_prefix = \"regex-1.12.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.regex-1.12.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__regex-automata-0.4.14\",\n sha256 = \"6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/regex-automata/0.4.14/download\"],\n strip_prefix = \"regex-automata-0.4.14\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.regex-automata-0.4.14.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__regex-syntax-0.8.10\",\n sha256 = \"dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/regex-syntax/0.8.10/download\"],\n strip_prefix = \"regex-syntax-0.8.10\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.regex-syntax-0.8.10.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__region-3.0.2\",\n sha256 = \"e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/region/3.0.2/download\"],\n strip_prefix = \"region-3.0.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.region-3.0.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__rend-0.5.3\",\n sha256 = \"cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rend/0.5.3/download\"],\n strip_prefix = \"rend-0.5.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.rend-0.5.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__replace_with-0.1.8\",\n sha256 = \"51743d3e274e2b18df81c4dc6caf8a5b8e15dbe799e0dca05c7617380094e884\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/replace_with/0.1.8/download\"],\n strip_prefix = \"replace_with-0.1.8\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.replace_with-0.1.8.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__rkyv-0.8.16\",\n sha256 = \"73389e0c99e664f919275ab5b5b0471391fe9a8de61e1dff9b1eaf56a90f16e3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rkyv/0.8.16/download\"],\n strip_prefix = \"rkyv-0.8.16\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.rkyv-0.8.16.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__rkyv_derive-0.8.16\",\n sha256 = \"5d2ed0b54125315fb36bd021e82d314d1c126548f871634b483f46b31d13cac6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rkyv_derive/0.8.16/download\"],\n strip_prefix = \"rkyv_derive-0.8.16\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.rkyv_derive-0.8.16.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__rustc-demangle-0.1.27\",\n sha256 = \"b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustc-demangle/0.1.27/download\"],\n strip_prefix = \"rustc-demangle-0.1.27\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.rustc-demangle-0.1.27.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__rustc-hash-2.1.2\",\n sha256 = \"94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustc-hash/2.1.2/download\"],\n strip_prefix = \"rustc-hash-2.1.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.rustc-hash-2.1.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__rustc_version-0.4.1\",\n sha256 = \"cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustc_version/0.4.1/download\"],\n strip_prefix = \"rustc_version-0.4.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.rustc_version-0.4.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__rustix-1.1.4\",\n sha256 = \"b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustix/1.1.4/download\"],\n strip_prefix = \"rustix-1.1.4\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.rustix-1.1.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__rustversion-1.0.22\",\n sha256 = \"b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustversion/1.0.22/download\"],\n strip_prefix = \"rustversion-1.0.22\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.rustversion-1.0.22.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__rusty_pool-0.7.0\",\n sha256 = \"4ed36cdb20de66d89a17ea04b8883fc7a386f2cf877aaedca5005583ce4876ff\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rusty_pool/0.7.0/download\"],\n strip_prefix = \"rusty_pool-0.7.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.rusty_pool-0.7.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__ruzstd-0.8.2\",\n sha256 = \"e5ff0cc5e135c8870a775d3320910cd9b564ec036b4dc0b8741629020be63f01\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ruzstd/0.8.2/download\"],\n strip_prefix = \"ruzstd-0.8.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.ruzstd-0.8.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__ryu-1.0.23\",\n sha256 = \"9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ryu/1.0.23/download\"],\n strip_prefix = \"ryu-1.0.23\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.ryu-1.0.23.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__saffron-0.1.0\",\n sha256 = \"03fb9a628596fc7590eb7edbf7b0613287be78df107f5f97b118aad59fb2eea9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/saffron/0.1.0/download\"],\n strip_prefix = \"saffron-0.1.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.saffron-0.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__same-file-1.0.6\",\n sha256 = \"93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/same-file/1.0.6/download\"],\n strip_prefix = \"same-file-1.0.6\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.same-file-1.0.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__schemars-1.2.1\",\n sha256 = \"a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/schemars/1.2.1/download\"],\n strip_prefix = \"schemars-1.2.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.schemars-1.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__schemars_derive-1.2.1\",\n sha256 = \"7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/schemars_derive/1.2.1/download\"],\n strip_prefix = \"schemars_derive-1.2.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.schemars_derive-1.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__scopeguard-1.2.0\",\n sha256 = \"94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/scopeguard/1.2.0/download\"],\n strip_prefix = \"scopeguard-1.2.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.scopeguard-1.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__self_cell-1.2.2\",\n sha256 = \"b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/self_cell/1.2.2/download\"],\n strip_prefix = \"self_cell-1.2.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.self_cell-1.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__semver-1.0.28\",\n sha256 = \"8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/semver/1.0.28/download\"],\n strip_prefix = \"semver-1.0.28\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.semver-1.0.28.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__serde-1.0.228\",\n sha256 = \"9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde/1.0.228/download\"],\n strip_prefix = \"serde-1.0.228\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.serde-1.0.228.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__serde-wasm-bindgen-0.6.5\",\n sha256 = \"8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde-wasm-bindgen/0.6.5/download\"],\n strip_prefix = \"serde-wasm-bindgen-0.6.5\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.serde-wasm-bindgen-0.6.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__serde_core-1.0.228\",\n sha256 = \"41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_core/1.0.228/download\"],\n strip_prefix = \"serde_core-1.0.228\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.serde_core-1.0.228.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__serde_derive-1.0.228\",\n sha256 = \"d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_derive/1.0.228/download\"],\n strip_prefix = \"serde_derive-1.0.228\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.serde_derive-1.0.228.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__serde_derive_internals-0.29.1\",\n sha256 = \"18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_derive_internals/0.29.1/download\"],\n strip_prefix = \"serde_derive_internals-0.29.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.serde_derive_internals-0.29.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__serde_json-1.0.149\",\n sha256 = \"83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_json/1.0.149/download\"],\n strip_prefix = \"serde_json-1.0.149\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.serde_json-1.0.149.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__serde_spanned-1.1.1\",\n sha256 = \"6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_spanned/1.1.1/download\"],\n strip_prefix = \"serde_spanned-1.1.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.serde_spanned-1.1.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__serde_yaml-0.9.34-deprecated\",\n sha256 = \"6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_yaml/0.9.34+deprecated/download\"],\n strip_prefix = \"serde_yaml-0.9.34+deprecated\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.serde_yaml-0.9.34+deprecated.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__sha2-0.10.9\",\n sha256 = \"a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/sha2/0.10.9/download\"],\n strip_prefix = \"sha2-0.10.9\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.sha2-0.10.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__sha2-0.11.0\",\n sha256 = \"446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/sha2/0.11.0/download\"],\n strip_prefix = \"sha2-0.11.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.sha2-0.11.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__shared-buffer-0.1.4\",\n sha256 = \"f6c99835bad52957e7aa241d3975ed17c1e5f8c92026377d117a606f36b84b16\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/shared-buffer/0.1.4/download\"],\n strip_prefix = \"shared-buffer-0.1.4\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.shared-buffer-0.1.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__shlex-1.3.0\",\n sha256 = \"0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/shlex/1.3.0/download\"],\n strip_prefix = \"shlex-1.3.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.shlex-1.3.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__simd-adler32-0.3.9\",\n sha256 = \"703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/simd-adler32/0.3.9/download\"],\n strip_prefix = \"simd-adler32-0.3.9\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.simd-adler32-0.3.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__simdutf8-0.1.5\",\n sha256 = \"e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/simdutf8/0.1.5/download\"],\n strip_prefix = \"simdutf8-0.1.5\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.simdutf8-0.1.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__similar-2.7.0\",\n sha256 = \"bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/similar/2.7.0/download\"],\n strip_prefix = \"similar-2.7.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.similar-2.7.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__slab-0.4.12\",\n sha256 = \"0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/slab/0.4.12/download\"],\n strip_prefix = \"slab-0.4.12\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.slab-0.4.12.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__smallvec-1.15.1\",\n sha256 = \"67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/smallvec/1.15.1/download\"],\n strip_prefix = \"smallvec-1.15.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.smallvec-1.15.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__smoltcp-0.13.0\",\n sha256 = \"ac729b0a77bd092a3f06ddaddc59fe0d67f48ba0de45a9abe707c2842c7f8767\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/smoltcp/0.13.0/download\"],\n strip_prefix = \"smoltcp-0.13.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.smoltcp-0.13.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__socket2-0.6.3\",\n sha256 = \"3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/socket2/0.6.3/download\"],\n strip_prefix = \"socket2-0.6.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.socket2-0.6.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__stable_deref_trait-1.2.1\",\n sha256 = \"6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/stable_deref_trait/1.2.1/download\"],\n strip_prefix = \"stable_deref_trait-1.2.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.stable_deref_trait-1.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__strsim-0.11.1\",\n sha256 = \"7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/strsim/0.11.1/download\"],\n strip_prefix = \"strsim-0.11.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.strsim-0.11.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__symbolic-common-12.18.3\",\n sha256 = \"332615d90111d8eeaf86a84dc9bbe9f65d0d8c5cf11b4caccedc37754eb0dcfd\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/symbolic-common/12.18.3/download\"],\n strip_prefix = \"symbolic-common-12.18.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.symbolic-common-12.18.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__symbolic-demangle-12.18.3\",\n sha256 = \"912017718eb4d21930546245af9a3475c9dccf15675a5c215664e76621afc471\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/symbolic-demangle/12.18.3/download\"],\n strip_prefix = \"symbolic-demangle-12.18.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.symbolic-demangle-12.18.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__syn-1.0.109\",\n sha256 = \"72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/syn/1.0.109/download\"],\n strip_prefix = \"syn-1.0.109\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.syn-1.0.109.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__syn-2.0.117\",\n sha256 = \"e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/syn/2.0.117/download\"],\n strip_prefix = \"syn-2.0.117\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.syn-2.0.117.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__synstructure-0.13.2\",\n sha256 = \"728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/synstructure/0.13.2/download\"],\n strip_prefix = \"synstructure-0.13.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.synstructure-0.13.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__tar-0.4.45\",\n sha256 = \"22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tar/0.4.45/download\"],\n strip_prefix = \"tar-0.4.45\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.tar-0.4.45.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__target-lexicon-0.13.5\",\n sha256 = \"adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/target-lexicon/0.13.5/download\"],\n strip_prefix = \"target-lexicon-0.13.5\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.target-lexicon-0.13.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__tempfile-3.27.0\",\n sha256 = \"32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tempfile/3.27.0/download\"],\n strip_prefix = \"tempfile-3.27.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.tempfile-3.27.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__terminal_size-0.4.4\",\n sha256 = \"230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/terminal_size/0.4.4/download\"],\n strip_prefix = \"terminal_size-0.4.4\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.terminal_size-0.4.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__termios-0.3.3\",\n sha256 = \"411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/termios/0.3.3/download\"],\n strip_prefix = \"termios-0.3.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.termios-0.3.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__thiserror-2.0.18\",\n sha256 = \"4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/thiserror/2.0.18/download\"],\n strip_prefix = \"thiserror-2.0.18\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.thiserror-2.0.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__thiserror-impl-2.0.18\",\n sha256 = \"ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/thiserror-impl/2.0.18/download\"],\n strip_prefix = \"thiserror-impl-2.0.18\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.thiserror-impl-2.0.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__time-0.3.47\",\n sha256 = \"743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/time/0.3.47/download\"],\n strip_prefix = \"time-0.3.47\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.time-0.3.47.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__time-core-0.1.8\",\n sha256 = \"7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/time-core/0.1.8/download\"],\n strip_prefix = \"time-core-0.1.8\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.time-core-0.1.8.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__time-macros-0.2.27\",\n sha256 = \"2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/time-macros/0.2.27/download\"],\n strip_prefix = \"time-macros-0.2.27\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.time-macros-0.2.27.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__tinystr-0.8.3\",\n sha256 = \"c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tinystr/0.8.3/download\"],\n strip_prefix = \"tinystr-0.8.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.tinystr-0.8.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__tinyvec-1.11.0\",\n sha256 = \"3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tinyvec/1.11.0/download\"],\n strip_prefix = \"tinyvec-1.11.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.tinyvec-1.11.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__tinyvec_macros-0.1.1\",\n sha256 = \"1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tinyvec_macros/0.1.1/download\"],\n strip_prefix = \"tinyvec_macros-0.1.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.tinyvec_macros-0.1.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__tokio-1.52.1\",\n sha256 = \"b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tokio/1.52.1/download\"],\n strip_prefix = \"tokio-1.52.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.tokio-1.52.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__tokio-macros-2.7.0\",\n sha256 = \"385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tokio-macros/2.7.0/download\"],\n strip_prefix = \"tokio-macros-2.7.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.tokio-macros-2.7.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__tokio-stream-0.1.18\",\n sha256 = \"32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tokio-stream/0.1.18/download\"],\n strip_prefix = \"tokio-stream-0.1.18\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.tokio-stream-0.1.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__tokio-util-0.7.18\",\n sha256 = \"9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tokio-util/0.7.18/download\"],\n strip_prefix = \"tokio-util-0.7.18\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.tokio-util-0.7.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__toml-1.1.2-spec-1.1.0\",\n sha256 = \"81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/toml/1.1.2+spec-1.1.0/download\"],\n strip_prefix = \"toml-1.1.2+spec-1.1.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.toml-1.1.2+spec-1.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__toml_datetime-1.1.1-spec-1.1.0\",\n sha256 = \"3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/toml_datetime/1.1.1+spec-1.1.0/download\"],\n strip_prefix = \"toml_datetime-1.1.1+spec-1.1.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.toml_datetime-1.1.1+spec-1.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__toml_edit-0.25.11-spec-1.1.0\",\n sha256 = \"0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/toml_edit/0.25.11+spec-1.1.0/download\"],\n strip_prefix = \"toml_edit-0.25.11+spec-1.1.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.toml_edit-0.25.11+spec-1.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__toml_parser-1.1.2-spec-1.1.0\",\n sha256 = \"a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/toml_parser/1.1.2+spec-1.1.0/download\"],\n strip_prefix = \"toml_parser-1.1.2+spec-1.1.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.toml_parser-1.1.2+spec-1.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__toml_writer-1.1.1-spec-1.1.0\",\n sha256 = \"756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/toml_writer/1.1.1+spec-1.1.0/download\"],\n strip_prefix = \"toml_writer-1.1.1+spec-1.1.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.toml_writer-1.1.1+spec-1.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__tracing-0.1.44\",\n sha256 = \"63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tracing/0.1.44/download\"],\n strip_prefix = \"tracing-0.1.44\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.tracing-0.1.44.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__tracing-attributes-0.1.31\",\n sha256 = \"7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tracing-attributes/0.1.31/download\"],\n strip_prefix = \"tracing-attributes-0.1.31\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.tracing-attributes-0.1.31.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__tracing-core-0.1.36\",\n sha256 = \"db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tracing-core/0.1.36/download\"],\n strip_prefix = \"tracing-core-0.1.36\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.tracing-core-0.1.36.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__twox-hash-2.1.2\",\n sha256 = \"9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/twox-hash/2.1.2/download\"],\n strip_prefix = \"twox-hash-2.1.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.twox-hash-2.1.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__typenum-1.20.0\",\n sha256 = \"40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/typenum/1.20.0/download\"],\n strip_prefix = \"typenum-1.20.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.typenum-1.20.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__unicase-2.9.0\",\n sha256 = \"dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unicase/2.9.0/download\"],\n strip_prefix = \"unicase-2.9.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.unicase-2.9.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__unicode-ident-1.0.24\",\n sha256 = \"e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unicode-ident/1.0.24/download\"],\n strip_prefix = \"unicode-ident-1.0.24\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.unicode-ident-1.0.24.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__unicode-normalization-0.1.25\",\n sha256 = \"5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unicode-normalization/0.1.25/download\"],\n strip_prefix = \"unicode-normalization-0.1.25\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.unicode-normalization-0.1.25.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__unicode-segmentation-1.13.2\",\n sha256 = \"9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unicode-segmentation/1.13.2/download\"],\n strip_prefix = \"unicode-segmentation-1.13.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.unicode-segmentation-1.13.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__unicode-width-0.2.2\",\n sha256 = \"b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unicode-width/0.2.2/download\"],\n strip_prefix = \"unicode-width-0.2.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.unicode-width-0.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__unicode-xid-0.2.6\",\n sha256 = \"ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unicode-xid/0.2.6/download\"],\n strip_prefix = \"unicode-xid-0.2.6\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.unicode-xid-0.2.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__unsafe-libyaml-0.2.11\",\n sha256 = \"673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unsafe-libyaml/0.2.11/download\"],\n strip_prefix = \"unsafe-libyaml-0.2.11\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.unsafe-libyaml-0.2.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__unty-0.0.4\",\n sha256 = \"6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unty/0.0.4/download\"],\n strip_prefix = \"unty-0.0.4\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.unty-0.0.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__url-2.5.8\",\n sha256 = \"ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/url/2.5.8/download\"],\n strip_prefix = \"url-2.5.8\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.url-2.5.8.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__urlencoding-2.1.3\",\n sha256 = \"daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/urlencoding/2.1.3/download\"],\n strip_prefix = \"urlencoding-2.1.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.urlencoding-2.1.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__utf8_iter-1.0.4\",\n sha256 = \"b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/utf8_iter/1.0.4/download\"],\n strip_prefix = \"utf8_iter-1.0.4\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.utf8_iter-1.0.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__uuid-1.23.1\",\n sha256 = \"ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/uuid/1.23.1/download\"],\n strip_prefix = \"uuid-1.23.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.uuid-1.23.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__version_check-0.9.5\",\n sha256 = \"0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/version_check/0.9.5/download\"],\n strip_prefix = \"version_check-0.9.5\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.version_check-0.9.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__virtual-fs-0.702.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n patches = [\n \"@@+_repo_rules31+postmaster_cargo//:patches/cargo/virtual-fs.patch\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/virtual-fs\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.virtual-fs-0.702.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__virtual-mio-0.702.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n patches = [\n \"@@+_repo_rules31+postmaster_cargo//:patches/cargo/virtual-mio.patch\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/virtual-io\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.virtual-mio-0.702.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__virtual-net-0.702.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n patches = [\n \"@@+_repo_rules31+postmaster_cargo//:patches/cargo/virtual-net.patch\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/virtual-net\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.virtual-net-0.702.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__virtue-0.0.18\",\n sha256 = \"051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/virtue/0.0.18/download\"],\n strip_prefix = \"virtue-0.0.18\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.virtue-0.0.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wai-bindgen-gen-core-0.2.3\",\n sha256 = \"1aa3dc41b510811122b3088197234c27e08fcad63ef936306dd8e11e2803876c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wai-bindgen-gen-core/0.2.3/download\"],\n strip_prefix = \"wai-bindgen-gen-core-0.2.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wai-bindgen-gen-core-0.2.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wai-bindgen-gen-rust-0.2.3\",\n sha256 = \"19bc05e8380515c4337c40ef03b2ff233e391315b178a320de8640703d522efe\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wai-bindgen-gen-rust/0.2.3/download\"],\n strip_prefix = \"wai-bindgen-gen-rust-0.2.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wai-bindgen-gen-rust-0.2.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wai-bindgen-gen-rust-wasm-0.2.3\",\n sha256 = \"d6f35ce5e74086fac87f3a7bd50f643f00fe3559adb75c88521ecaa01c8a6199\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wai-bindgen-gen-rust-wasm/0.2.3/download\"],\n strip_prefix = \"wai-bindgen-gen-rust-wasm-0.2.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wai-bindgen-gen-rust-wasm-0.2.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wai-bindgen-rust-0.2.3\",\n sha256 = \"4e5601c6f448c063e83a5e931b8fefcdf7e01ada424ad42372c948d2e3d67741\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wai-bindgen-rust/0.2.3/download\"],\n strip_prefix = \"wai-bindgen-rust-0.2.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wai-bindgen-rust-0.2.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wai-bindgen-rust-impl-0.2.3\",\n sha256 = \"bdeeb5c1170246de8425a3e123e7ef260dc05ba2b522a1d369fe2315376efea4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wai-bindgen-rust-impl/0.2.3/download\"],\n strip_prefix = \"wai-bindgen-rust-impl-0.2.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wai-bindgen-rust-impl-0.2.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wai-parser-0.2.3\",\n sha256 = \"9bd0acb6d70885ea0c343749019ba74f015f64a9d30542e66db69b49b7e28186\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wai-parser/0.2.3/download\"],\n strip_prefix = \"wai-parser-0.2.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wai-parser-0.2.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__waker-fn-1.2.0\",\n sha256 = \"317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/waker-fn/1.2.0/download\"],\n strip_prefix = \"waker-fn-1.2.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.waker-fn-1.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__walkdir-2.5.0\",\n sha256 = \"29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/walkdir/2.5.0/download\"],\n strip_prefix = \"walkdir-2.5.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.walkdir-2.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wasi-0.11.1-wasi-snapshot-preview1\",\n sha256 = \"ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasi/0.11.1+wasi-snapshot-preview1/download\"],\n strip_prefix = \"wasi-0.11.1+wasi-snapshot-preview1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wasi-0.11.1+wasi-snapshot-preview1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wasip2-1.0.3-wasi-0.2.9\",\n sha256 = \"20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasip2/1.0.3+wasi-0.2.9/download\"],\n strip_prefix = \"wasip2-1.0.3+wasi-0.2.9\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wasip2-1.0.3+wasi-0.2.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wasip3-0.4.0-wasi-0.3.0-rc-2026-01-06\",\n sha256 = \"5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasip3/0.4.0+wasi-0.3.0-rc-2026-01-06/download\"],\n strip_prefix = \"wasip3-0.4.0+wasi-0.3.0-rc-2026-01-06\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wasip3-0.4.0+wasi-0.3.0-rc-2026-01-06.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wasm-bindgen-0.2.118\",\n sha256 = \"0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-bindgen/0.2.118/download\"],\n strip_prefix = \"wasm-bindgen-0.2.118\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wasm-bindgen-0.2.118.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wasm-bindgen-macro-0.2.118\",\n sha256 = \"eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-bindgen-macro/0.2.118/download\"],\n strip_prefix = \"wasm-bindgen-macro-0.2.118\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wasm-bindgen-macro-0.2.118.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wasm-bindgen-macro-support-0.2.118\",\n sha256 = \"9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-bindgen-macro-support/0.2.118/download\"],\n strip_prefix = \"wasm-bindgen-macro-support-0.2.118\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wasm-bindgen-macro-support-0.2.118.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wasm-bindgen-shared-0.2.118\",\n sha256 = \"5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-bindgen-shared/0.2.118/download\"],\n strip_prefix = \"wasm-bindgen-shared-0.2.118\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wasm-bindgen-shared-0.2.118.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wasm-encoder-0.244.0\",\n sha256 = \"990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-encoder/0.244.0/download\"],\n strip_prefix = \"wasm-encoder-0.244.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wasm-encoder-0.244.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wasm-encoder-0.247.0\",\n sha256 = \"30b6733b8b91d010a6ac5b0fb237dc46a19650bc4c67db66857e2e787d437204\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-encoder/0.247.0/download\"],\n strip_prefix = \"wasm-encoder-0.247.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wasm-encoder-0.247.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wasm-metadata-0.244.0\",\n sha256 = \"bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-metadata/0.244.0/download\"],\n strip_prefix = \"wasm-metadata-0.244.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wasm-metadata-0.244.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wasmer-7.2.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n patches = [\n \"@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer.patch\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/api\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wasmer-7.2.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wasmer-compiler-7.2.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n patches = [\n \"@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-compiler.patch\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/compiler\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wasmer-compiler-7.2.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wasmer-config-0.702.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/config\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wasmer-config-0.702.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wasmer-derive-7.2.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/derive\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wasmer-derive-7.2.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wasmer-journal-0.702.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/journal\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wasmer-journal-0.702.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wasmer-package-0.702.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/package\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wasmer-package-0.702.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wasmer-types-7.2.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n patches = [\n \"@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-types.patch\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/types\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wasmer-types-7.2.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wasmer-vm-7.2.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n patches = [\n \"@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-vm.patch\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/vm\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wasmer-vm-7.2.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wasmer-wasix-0.702.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n patches = [\n \"@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-wasix.patch\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/wasix\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wasmer-wasix-0.702.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wasmer-wasix-types-0.702.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/wasi-types\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wasmer-wasix-types-0.702.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wasmparser-0.244.0\",\n sha256 = \"47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasmparser/0.244.0/download\"],\n strip_prefix = \"wasmparser-0.244.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wasmparser-0.244.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wasmparser-0.247.0\",\n sha256 = \"8e6fb4c2bee46c5ea4d40f8cdb5c131725cd976718ec56f1c8e82fbde5fa2a80\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasmparser/0.247.0/download\"],\n strip_prefix = \"wasmparser-0.247.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wasmparser-0.247.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wast-247.0.0\",\n sha256 = \"579d2d47eb33b0cdf9b14723cb115f1e1b7d6e77aac6f0816e5b7c7aeaa418ff\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wast/247.0.0/download\"],\n strip_prefix = \"wast-247.0.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wast-247.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wat-1.247.0\",\n sha256 = \"f3f4091c56437e86f2b57fa2fac72c4f528957a605b3f44f7c0b3b19a17ac5ee\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wat/1.247.0/download\"],\n strip_prefix = \"wat-1.247.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wat-1.247.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__webc-11.0.0\",\n sha256 = \"20b8b523112384e8c1caf77cffdd371ca7e0013779f081e6beafc537f5b5325d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/webc/11.0.0/download\"],\n strip_prefix = \"webc-11.0.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.webc-11.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__weezl-0.1.12\",\n sha256 = \"a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/weezl/0.1.12/download\"],\n strip_prefix = \"weezl-0.1.12\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.weezl-0.1.12.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__which-8.0.2\",\n sha256 = \"81995fafaaaf6ae47a7d0cc83c67caf92aeb7e5331650ae6ff856f7c0c60c459\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/which/8.0.2/download\"],\n strip_prefix = \"which-8.0.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.which-8.0.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__winapi-util-0.1.11\",\n sha256 = \"c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/winapi-util/0.1.11/download\"],\n strip_prefix = \"winapi-util-0.1.11\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.winapi-util-0.1.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__windows-link-0.2.1\",\n sha256 = \"f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-link/0.2.1/download\"],\n strip_prefix = \"windows-link-0.2.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.windows-link-0.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__windows-sys-0.52.0\",\n sha256 = \"282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-sys/0.52.0/download\"],\n strip_prefix = \"windows-sys-0.52.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.windows-sys-0.52.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__windows-sys-0.59.0\",\n sha256 = \"1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-sys/0.59.0/download\"],\n strip_prefix = \"windows-sys-0.59.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.windows-sys-0.59.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__windows-sys-0.61.2\",\n sha256 = \"ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-sys/0.61.2/download\"],\n strip_prefix = \"windows-sys-0.61.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.windows-sys-0.61.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__windows-targets-0.52.6\",\n sha256 = \"9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-targets/0.52.6/download\"],\n strip_prefix = \"windows-targets-0.52.6\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.windows-targets-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__windows_aarch64_gnullvm-0.52.6\",\n sha256 = \"32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_aarch64_gnullvm/0.52.6/download\"],\n strip_prefix = \"windows_aarch64_gnullvm-0.52.6\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.windows_aarch64_gnullvm-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__windows_aarch64_msvc-0.52.6\",\n sha256 = \"09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_aarch64_msvc/0.52.6/download\"],\n strip_prefix = \"windows_aarch64_msvc-0.52.6\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.windows_aarch64_msvc-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__windows_i686_gnu-0.52.6\",\n sha256 = \"8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_i686_gnu/0.52.6/download\"],\n strip_prefix = \"windows_i686_gnu-0.52.6\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.windows_i686_gnu-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__windows_i686_gnullvm-0.52.6\",\n sha256 = \"0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_i686_gnullvm/0.52.6/download\"],\n strip_prefix = \"windows_i686_gnullvm-0.52.6\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.windows_i686_gnullvm-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__windows_i686_msvc-0.52.6\",\n sha256 = \"240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_i686_msvc/0.52.6/download\"],\n strip_prefix = \"windows_i686_msvc-0.52.6\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.windows_i686_msvc-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__windows_x86_64_gnu-0.52.6\",\n sha256 = \"147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_x86_64_gnu/0.52.6/download\"],\n strip_prefix = \"windows_x86_64_gnu-0.52.6\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.windows_x86_64_gnu-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__windows_x86_64_gnullvm-0.52.6\",\n sha256 = \"24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_x86_64_gnullvm/0.52.6/download\"],\n strip_prefix = \"windows_x86_64_gnullvm-0.52.6\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.windows_x86_64_gnullvm-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__windows_x86_64_msvc-0.52.6\",\n sha256 = \"589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_x86_64_msvc/0.52.6/download\"],\n strip_prefix = \"windows_x86_64_msvc-0.52.6\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.windows_x86_64_msvc-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__winnow-1.0.2\",\n sha256 = \"2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/winnow/1.0.2/download\"],\n strip_prefix = \"winnow-1.0.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.winnow-1.0.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wit-bindgen-0.51.0\",\n sha256 = \"d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wit-bindgen/0.51.0/download\"],\n strip_prefix = \"wit-bindgen-0.51.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wit-bindgen-0.51.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wit-bindgen-0.57.1\",\n sha256 = \"1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wit-bindgen/0.57.1/download\"],\n strip_prefix = \"wit-bindgen-0.57.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wit-bindgen-0.57.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wit-bindgen-core-0.51.0\",\n sha256 = \"ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wit-bindgen-core/0.51.0/download\"],\n strip_prefix = \"wit-bindgen-core-0.51.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wit-bindgen-core-0.51.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wit-bindgen-rust-0.51.0\",\n sha256 = \"b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wit-bindgen-rust/0.51.0/download\"],\n strip_prefix = \"wit-bindgen-rust-0.51.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wit-bindgen-rust-0.51.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wit-bindgen-rust-macro-0.51.0\",\n sha256 = \"0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wit-bindgen-rust-macro/0.51.0/download\"],\n strip_prefix = \"wit-bindgen-rust-macro-0.51.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wit-bindgen-rust-macro-0.51.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wit-component-0.244.0\",\n sha256 = \"9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wit-component/0.244.0/download\"],\n strip_prefix = \"wit-component-0.244.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wit-component-0.244.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__wit-parser-0.244.0\",\n sha256 = \"ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wit-parser/0.244.0/download\"],\n strip_prefix = \"wit-parser-0.244.0\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.wit-parser-0.244.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__writeable-0.6.3\",\n sha256 = \"1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/writeable/0.6.3/download\"],\n strip_prefix = \"writeable-0.6.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.writeable-0.6.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__xattr-1.6.1\",\n sha256 = \"32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/xattr/1.6.1/download\"],\n strip_prefix = \"xattr-1.6.1\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.xattr-1.6.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__xxhash-rust-0.8.15\",\n sha256 = \"fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/xxhash-rust/0.8.15/download\"],\n strip_prefix = \"xxhash-rust-0.8.15\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.xxhash-rust-0.8.15.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__yoke-0.8.2\",\n sha256 = \"abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/yoke/0.8.2/download\"],\n strip_prefix = \"yoke-0.8.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.yoke-0.8.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__yoke-derive-0.8.2\",\n sha256 = \"de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/yoke-derive/0.8.2/download\"],\n strip_prefix = \"yoke-derive-0.8.2\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.yoke-derive-0.8.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__zerocopy-0.8.48\",\n sha256 = \"eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerocopy/0.8.48/download\"],\n strip_prefix = \"zerocopy-0.8.48\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.zerocopy-0.8.48.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__zerocopy-derive-0.8.48\",\n sha256 = \"70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerocopy-derive/0.8.48/download\"],\n strip_prefix = \"zerocopy-derive-0.8.48\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.zerocopy-derive-0.8.48.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__zerofrom-0.1.7\",\n sha256 = \"69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerofrom/0.1.7/download\"],\n strip_prefix = \"zerofrom-0.1.7\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.zerofrom-0.1.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__zerofrom-derive-0.1.7\",\n sha256 = \"11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerofrom-derive/0.1.7/download\"],\n strip_prefix = \"zerofrom-derive-0.1.7\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.zerofrom-derive-0.1.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__zerotrie-0.2.4\",\n sha256 = \"0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerotrie/0.2.4/download\"],\n strip_prefix = \"zerotrie-0.2.4\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.zerotrie-0.2.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__zerovec-0.11.6\",\n sha256 = \"90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerovec/0.11.6/download\"],\n strip_prefix = \"zerovec-0.11.6\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.zerovec-0.11.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__zerovec-derive-0.11.3\",\n sha256 = \"625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerovec-derive/0.11.3/download\"],\n strip_prefix = \"zerovec-derive-0.11.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.zerovec-derive-0.11.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__zmij-1.0.21\",\n sha256 = \"b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zmij/1.0.21/download\"],\n strip_prefix = \"zmij-1.0.21\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.zmij-1.0.21.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__zstd-0.13.3\",\n sha256 = \"e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zstd/0.13.3/download\"],\n strip_prefix = \"zstd-0.13.3\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.zstd-0.13.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__zstd-safe-7.2.4\",\n sha256 = \"8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zstd-safe/7.2.4/download\"],\n strip_prefix = \"zstd-safe-7.2.4\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.zstd-safe-7.2.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_executor_crates__zstd-sys-2.0.16-zstd.1.5.7\",\n sha256 = \"91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zstd-sys/2.0.16+zstd.1.5.7/download\"],\n strip_prefix = \"zstd-sys-2.0.16+zstd.1.5.7\",\n build_file = Label(\"@postmaster_executor_crates//postmaster_executor_crates:BUILD.zstd-sys-2.0.16+zstd.1.5.7.bazel\"),\n )\n\n return [\n struct(repo = \"postmaster_executor_crates\", is_dev_dep = False),\n struct(repo=\"postmaster_executor_crates__anyhow-1.0.102\", is_dev_dep = False),\n struct(repo=\"postmaster_executor_crates__async-trait-0.1.89\", is_dev_dep = False),\n struct(repo=\"postmaster_executor_crates__hex-0.4.3\", is_dev_dep = False),\n struct(repo=\"postmaster_executor_crates__libc-0.2.186\", is_dev_dep = False),\n struct(repo=\"postmaster_executor_crates__serde-1.0.228\", is_dev_dep = False),\n struct(repo=\"postmaster_executor_crates__serde_json-1.0.149\", is_dev_dep = False),\n struct(repo=\"postmaster_executor_crates__sha2-0.11.0\", is_dev_dep = False),\n struct(repo=\"postmaster_executor_crates__tempfile-3.27.0\", is_dev_dep = False),\n struct(repo=\"postmaster_executor_crates__tokio-1.52.1\", is_dev_dep = False),\n struct(repo=\"postmaster_executor_crates__tracing-0.1.44\", is_dev_dep = False),\n struct(repo=\"postmaster_executor_crates__wasmer-7.2.0-alpha.2\", is_dev_dep = False),\n struct(repo=\"postmaster_executor_crates__wasmer-types-7.2.0-alpha.2\", is_dev_dep = False),\n struct(repo=\"postmaster_executor_crates__wasmer-vm-7.2.0-alpha.2\", is_dev_dep = False),\n struct(repo=\"postmaster_executor_crates__wasmer-wasix-0.702.0-alpha.2\", is_dev_dep = False),\n struct(repo = \"postmaster_executor_crates__futures-0.3.32\", is_dev_dep = True),\n struct(repo = \"postmaster_executor_crates__wat-1.247.0\", is_dev_dep = True),\n ]\n", + "defs.bzl": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\"\"\"Deprecated: re-exports the crate_universe macros from `:crates.bzl`.\"\"\"\n\nload(\n \":crates.bzl\",\n _aliases = \"aliases\",\n _all_crate_deps = \"all_crate_deps\",\n _crate_deps = \"crate_deps\",\n _crate_edition = \"crate_edition\",\n _crate_repositories = \"crate_repositories\",\n)\n\naliases = _aliases\nall_crate_deps = _all_crate_deps\ncrate_deps = _crate_deps\ncrate_edition = _crate_edition\ncrate_repositories = _crate_repositories\n", + "cargo-bazel.json": "{\"checksum\":\"d4cc5329bb3c785677408314f1649d28d1b486ac4563a9965701fd551bce791c\",\"conditions\":{\"aarch64-apple-darwin\":[\"aarch64-apple-darwin\"],\"aarch64-linux-android\":[],\"aarch64-pc-windows-gnullvm\":[],\"aarch64-unknown-linux-gnu\":[\"aarch64-unknown-linux-gnu\"],\"cfg(all(any(target_arch = \\\"x86_64\\\", target_arch = \\\"arm64ec\\\"), target_env = \\\"msvc\\\", not(windows_raw_dylib)))\":[],\"cfg(all(any(target_os = \\\"linux\\\", target_os = \\\"android\\\"), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\":[],\"cfg(all(any(target_os = \\\"linux\\\", target_os = \\\"android\\\"), not(any(all(target_os = \\\"linux\\\", target_env = \\\"\\\"), getrandom_backend = \\\"custom\\\", getrandom_backend = \\\"linux_raw\\\", getrandom_backend = \\\"rdrand\\\", getrandom_backend = \\\"rndr\\\"))))\":[\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\":[\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(all(not(target_arch = \\\"wasm32\\\"), target_os = \\\"windows\\\"))\":[],\"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\":[\"aarch64-apple-darwin\"],\"cfg(all(target_arch = \\\"aarch64\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\":[],\"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"android\\\"))\":[],\"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"linux\\\"))\":[\"aarch64-unknown-linux-gnu\"],\"cfg(all(target_arch = \\\"aarch64\\\", target_vendor = \\\"apple\\\"))\":[\"aarch64-apple-darwin\"],\"cfg(all(target_arch = \\\"loongarch64\\\", target_os = \\\"linux\\\"))\":[],\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"wasi\\\", target_env = \\\"p2\\\"))\":[],\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"wasi\\\", target_env = \\\"p3\\\"))\":[],\"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"gnu\\\", not(target_abi = \\\"llvm\\\"), not(windows_raw_dylib)))\":[],\"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\":[],\"cfg(all(target_arch = \\\"x86_64\\\", target_env = \\\"gnu\\\", not(target_abi = \\\"llvm\\\"), not(windows_raw_dylib)))\":[\"x86_64-unknown-linux-gnu\"],\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"wasi\\\"))\":[],\"cfg(all(target_os = \\\"macos\\\", target_arch = \\\"aarch64\\\"))\":[\"aarch64-apple-darwin\"],\"cfg(all(target_os = \\\"uefi\\\", getrandom_backend = \\\"efi_rng\\\"))\":[],\"cfg(all(unix, not(target_os = \\\"ios\\\")))\":[\"aarch64-apple-darwin\",\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(any())\":[],\"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\":[\"aarch64-apple-darwin\",\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(any(target_arch = \\\"arm\\\", target_pointer_width = \\\"32\\\", target_pointer_width = \\\"64\\\"))\":[\"aarch64-apple-darwin\",\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(any(target_arch = \\\"x86\\\", target_arch = \\\"x86_64\\\"))\":[\"x86_64-unknown-linux-gnu\"],\"cfg(any(target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\":[\"x86_64-unknown-linux-gnu\"],\"cfg(any(target_family = \\\"unix\\\", all(target_family = \\\"windows\\\", target_env = \\\"gnu\\\")))\":[\"aarch64-apple-darwin\",\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(any(target_os = \\\"android\\\", target_os = \\\"linux\\\", target_os = \\\"macos\\\", target_os = \\\"hurd\\\"))\":[\"aarch64-apple-darwin\",\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(any(target_os = \\\"dragonfly\\\", target_os = \\\"freebsd\\\", target_os = \\\"hurd\\\", target_os = \\\"illumos\\\", target_os = \\\"cygwin\\\", all(target_os = \\\"horizon\\\", target_arch = \\\"arm\\\")))\":[],\"cfg(any(target_os = \\\"freebsd\\\", target_os = \\\"netbsd\\\"))\":[],\"cfg(any(target_os = \\\"haiku\\\", target_os = \\\"redox\\\", target_os = \\\"nto\\\", target_os = \\\"aix\\\"))\":[],\"cfg(any(target_os = \\\"ios\\\", target_os = \\\"visionos\\\", target_os = \\\"watchos\\\", target_os = \\\"tvos\\\"))\":[],\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"ios\\\"))\":[\"aarch64-apple-darwin\"],\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"openbsd\\\", target_os = \\\"vita\\\", target_os = \\\"emscripten\\\"))\":[\"aarch64-apple-darwin\"],\"cfg(any(unix, target_os = \\\"hermit\\\", target_os = \\\"wasi\\\"))\":[\"aarch64-apple-darwin\",\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(any(unix, target_os = \\\"wasi\\\"))\":[\"aarch64-apple-darwin\",\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(any(windows, target_os = \\\"cygwin\\\"))\":[],\"cfg(not(all(windows, target_env = \\\"msvc\\\", not(target_vendor = \\\"uwp\\\"))))\":[\"aarch64-apple-darwin\",\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(not(target_arch = \\\"wasm32\\\"))\":[\"aarch64-apple-darwin\",\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(not(windows))\":[\"aarch64-apple-darwin\",\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(target_arch = \\\"spirv\\\")\":[],\"cfg(target_arch = \\\"wasm32\\\")\":[],\"cfg(target_os = \\\"hermit\\\")\":[],\"cfg(target_os = \\\"netbsd\\\")\":[],\"cfg(target_os = \\\"redox\\\")\":[],\"cfg(target_os = \\\"solaris\\\")\":[],\"cfg(target_os = \\\"vxworks\\\")\":[],\"cfg(target_os = \\\"wasi\\\")\":[],\"cfg(target_os = \\\"windows\\\")\":[],\"cfg(target_vendor = \\\"apple\\\")\":[\"aarch64-apple-darwin\"],\"cfg(unix)\":[\"aarch64-apple-darwin\",\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(windows)\":[],\"i686-pc-windows-gnullvm\":[],\"x86_64-pc-windows-gnullvm\":[],\"x86_64-unknown-linux-gnu\":[\"x86_64-unknown-linux-gnu\"]},\"crates\":{\"addr2line 0.25.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"gimli 0.32.3\",\"target\":\"gimli\"}],\"edition\":\"2018\"},\"library_target_name\":\"addr2line\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"addr2line\",\"package_url\":\"https://github.com/gimli-rs/addr2line\",\"repository\":{\"Http\":{\"sha256\":\"1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b\",\"url\":\"https://static.crates.io/crates/addr2line/0.25.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"addr2line\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.25.1\"},\"adler2 2.0.1\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"adler2\",\"license\":\"0BSD OR MIT OR Apache-2.0\",\"license_file\":\"LICENSE-0BSD\",\"license_ids\":[\"0BSD\",\"Apache-2.0\",\"MIT\"],\"name\":\"adler2\",\"package_url\":\"https://github.com/oyvindln/adler2\",\"repository\":{\"Http\":{\"sha256\":\"320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa\",\"url\":\"https://static.crates.io/crates/adler2/2.0.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"adler2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.0.1\"},\"aho-corasick 1.1.4\":{\"common_attrs\":{\"crate_features\":[\"default\",\"perf-literal\",\"std\"],\"deps\":[{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"}],\"edition\":\"2021\"},\"library_target_name\":\"aho_corasick\",\"license\":\"Unlicense OR MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"aho-corasick\",\"package_url\":\"https://github.com/BurntSushi/aho-corasick\",\"repository\":{\"Http\":{\"sha256\":\"ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301\",\"url\":\"https://static.crates.io/crates/aho-corasick/1.1.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"aho_corasick\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.4\"},\"any_ascii 0.1.7\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"any_ascii\",\"license\":\"ISC\",\"license_file\":\"LICENSE\",\"license_ids\":[\"ISC\"],\"name\":\"any_ascii\",\"package_url\":\"https://github.com/anyascii/anyascii\",\"repository\":{\"Http\":{\"sha256\":\"70033777eb8b5124a81a1889416543dddef2de240019b674c81285a2635a7e1e\",\"url\":\"https://static.crates.io/crates/any_ascii/0.1.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"any_ascii\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.7\"},\"anyhow 1.0.102\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"anyhow\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"anyhow\",\"package_url\":\"https://github.com/dtolnay/anyhow\",\"repository\":{\"Http\":{\"sha256\":\"7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c\",\"url\":\"https://static.crates.io/crates/anyhow/1.0.102/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"anyhow\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.102\"},\"arrayref 0.3.9\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"arrayref\",\"license\":\"BSD-2-Clause\",\"license_file\":\"LICENSE\",\"license_ids\":[\"BSD-2-Clause\"],\"name\":\"arrayref\",\"package_url\":\"https://github.com/droundy/arrayref\",\"repository\":{\"Http\":{\"sha256\":\"76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb\",\"url\":\"https://static.crates.io/crates/arrayref/0.3.9/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"arrayref\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.9\"},\"arrayvec 0.7.6\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"arrayvec\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"arrayvec\",\"package_url\":\"https://github.com/bluss/arrayvec\",\"repository\":{\"Http\":{\"sha256\":\"7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50\",\"url\":\"https://static.crates.io/crates/arrayvec/0.7.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"arrayvec\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.6\"},\"async-trait 0.1.89\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"async_trait\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"async-trait\",\"package_url\":\"https://github.com/dtolnay/async-trait\",\"repository\":{\"Http\":{\"sha256\":\"9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb\",\"url\":\"https://static.crates.io/crates/async-trait/0.1.89/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"async_trait\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.89\"},\"autocfg 1.5.0\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"autocfg\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"autocfg\",\"package_url\":\"https://github.com/cuviper/autocfg\",\"repository\":{\"Http\":{\"sha256\":\"c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8\",\"url\":\"https://static.crates.io/crates/autocfg/1.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"autocfg\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.5.0\"},\"backtrace 0.3.76\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"rustc-demangle 0.1.27\",\"target\":\"rustc_demangle\"}],\"selects\":{\"cfg(any(windows, target_os = \\\"cygwin\\\"))\":[{\"id\":\"windows-link 0.2.1\",\"target\":\"windows_link\"}],\"cfg(not(all(windows, target_env = \\\"msvc\\\", not(target_vendor = \\\"uwp\\\"))))\":[{\"id\":\"addr2line 0.25.1\",\"target\":\"addr2line\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"},{\"id\":\"miniz_oxide 0.8.9\",\"target\":\"miniz_oxide\"},{\"id\":\"object 0.37.3\",\"target\":\"object\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"backtrace\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"backtrace\",\"package_url\":\"https://github.com/rust-lang/backtrace-rs\",\"repository\":{\"Http\":{\"sha256\":\"bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6\",\"url\":\"https://static.crates.io/crates/backtrace/0.3.76/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"backtrace\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.76\"},\"base64 0.22.1\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"base64\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"base64\",\"package_url\":\"https://github.com/marshallpierce/rust-base64\",\"repository\":{\"Http\":{\"sha256\":\"72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6\",\"url\":\"https://static.crates.io/crates/base64/0.22.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"base64\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.22.1\"},\"bincode 2.0.1\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"bincode_derive\",\"default\",\"derive\",\"serde\",\"std\"],\"deps\":[{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"unty 0.0.4\",\"target\":\"unty\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"bincode_derive 2.0.1\",\"target\":\"bincode_derive\"}]},\"library_target_name\":\"bincode\",\"license\":\"MIT\",\"license_file\":\"LICENSE.md\",\"license_ids\":[\"MIT\"],\"name\":\"bincode\",\"package_url\":\"https://github.com/bincode-org/bincode\",\"repository\":{\"Http\":{\"sha256\":\"36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740\",\"url\":\"https://static.crates.io/crates/bincode/2.0.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bincode\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.0.1\"},\"bincode_derive 2.0.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"virtue 0.0.18\",\"target\":\"virtue\"}],\"edition\":\"2021\"},\"library_target_name\":\"bincode_derive\",\"license\":\"MIT\",\"license_file\":\"LICENSE.md\",\"license_ids\":[\"MIT\"],\"name\":\"bincode_derive\",\"package_url\":\"https://github.com/bincode-org/bincode\",\"repository\":{\"Http\":{\"sha256\":\"bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09\",\"url\":\"https://static.crates.io/crates/bincode_derive/2.0.1/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"bincode_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.0.1\"},\"bindgen 0.72.1\":{\"build_script_attrs\":{\"link_deps\":[{\"id\":\"clang-sys 1.8.1\",\"target\":\"clang_sys\"},{\"id\":\"prettyplease 0.2.37\",\"target\":\"prettyplease\"}]},\"common_attrs\":{\"crate_features\":[\"default\",\"logging\",\"prettyplease\",\"runtime\"],\"deps\":[{\"id\":\"bitflags 2.11.1\",\"target\":\"bitflags\"},{\"id\":\"cexpr 0.6.0\",\"target\":\"cexpr\"},{\"id\":\"clang-sys 1.8.1\",\"target\":\"clang_sys\"},{\"id\":\"itertools 0.13.0\",\"target\":\"itertools\"},{\"id\":\"log 0.4.29\",\"target\":\"log\"},{\"id\":\"prettyplease 0.2.37\",\"target\":\"prettyplease\"},{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"regex 1.12.3\",\"target\":\"regex\"},{\"id\":\"rustc-hash 2.1.2\",\"target\":\"rustc_hash\"},{\"id\":\"shlex 1.3.0\",\"target\":\"shlex\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"bindgen\",\"license\":\"BSD-3-Clause\",\"license_file\":\"LICENSE\",\"license_ids\":[\"BSD-3-Clause\"],\"name\":\"bindgen\",\"package_url\":\"https://github.com/rust-lang/rust-bindgen\",\"repository\":{\"Http\":{\"sha256\":\"993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895\",\"url\":\"https://static.crates.io/crates/bindgen/0.72.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bindgen\",\"crate_root\":\"lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.72.1\"},\"bitflags 1.3.2\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"edition\":\"2018\"},\"library_target_name\":\"bitflags\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"bitflags\",\"package_url\":\"https://github.com/bitflags/bitflags\",\"repository\":{\"Http\":{\"sha256\":\"bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a\",\"url\":\"https://static.crates.io/crates/bitflags/1.3.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bitflags\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.3.2\"},\"bitflags 2.11.1\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"bitflags\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"bitflags\",\"package_url\":\"https://github.com/bitflags/bitflags\",\"repository\":{\"Http\":{\"sha256\":\"c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3\",\"url\":\"https://static.crates.io/crates/bitflags/2.11.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bitflags\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.11.1\"},\"blake3 1.8.4\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"cc 1.2.60\",\"target\":\"cc\"}]},\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":{\"common\":[{\"id\":\"arrayref 0.3.9\",\"target\":\"arrayref\"},{\"id\":\"arrayvec 0.7.6\",\"target\":\"arrayvec\"},{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"constant_time_eq 0.4.2\",\"target\":\"constant_time_eq\"}],\"selects\":{\"cfg(any(target_arch = \\\"x86\\\", target_arch = \\\"x86_64\\\"))\":[{\"id\":\"cpufeatures 0.3.0\",\"target\":\"cpufeatures\"}]}},\"edition\":\"2024\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"blake3\",\"license\":\"CC0-1.0 OR Apache-2.0 OR Apache-2.0 WITH LLVM-exception\",\"license_file\":\"LICENSE_A2\",\"license_ids\":[\"Apache-2.0\",\"CC0-1.0\"],\"name\":\"blake3\",\"package_url\":\"https://github.com/BLAKE3-team/BLAKE3\",\"repository\":{\"Http\":{\"sha256\":\"4d2d5991425dfd0785aed03aedcf0b321d61975c9b5b3689c774a2610ae0b51e\",\"url\":\"https://static.crates.io/crates/blake3/1.8.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"blake3\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.8.4\"},\"block-buffer 0.10.4\":{\"common_attrs\":{\"deps\":[{\"id\":\"generic-array 0.14.7\",\"target\":\"generic_array\"}],\"edition\":\"2018\"},\"library_target_name\":\"block_buffer\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"block-buffer\",\"package_url\":\"https://github.com/RustCrypto/utils\",\"repository\":{\"Http\":{\"sha256\":\"3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71\",\"url\":\"https://static.crates.io/crates/block-buffer/0.10.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"block_buffer\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.10.4\"},\"block-buffer 0.12.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"hybrid-array 0.4.10\",\"target\":\"hybrid_array\"}],\"edition\":\"2024\"},\"library_target_name\":\"block_buffer\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"block-buffer\",\"package_url\":\"https://github.com/RustCrypto/utils\",\"repository\":{\"Http\":{\"sha256\":\"cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be\",\"url\":\"https://static.crates.io/crates/block-buffer/0.12.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"block_buffer\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.12.0\"},\"bstr 1.12.1\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"std\"],\"deps\":[{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"}],\"edition\":\"2021\"},\"library_target_name\":\"bstr\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"bstr\",\"package_url\":\"https://github.com/BurntSushi/bstr\",\"repository\":{\"Http\":{\"sha256\":\"63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab\",\"url\":\"https://static.crates.io/crates/bstr/1.12.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bstr\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.12.1\"},\"bumpalo 3.20.2\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"edition\":\"2021\"},\"library_target_name\":\"bumpalo\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"bumpalo\",\"package_url\":\"https://github.com/fitzgen/bumpalo\",\"repository\":{\"Http\":{\"sha256\":\"5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb\",\"url\":\"https://static.crates.io/crates/bumpalo/3.20.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bumpalo\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"3.20.2\"},\"bytecheck 0.8.2\":{\"common_attrs\":{\"crate_features\":[\"default\",\"simdutf8\"],\"deps\":[{\"id\":\"ptr_meta 0.3.1\",\"target\":\"ptr_meta\"},{\"id\":\"rancor 0.1.1\",\"target\":\"rancor\"},{\"id\":\"simdutf8 0.1.5\",\"target\":\"simdutf8\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"bytecheck_derive 0.8.2\",\"target\":\"bytecheck_derive\"}]},\"library_target_name\":\"bytecheck\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"bytecheck\",\"package_url\":\"https://github.com/rkyv/bytecheck\",\"repository\":{\"Http\":{\"sha256\":\"0caa33a2c0edca0419d15ac723dff03f1956f7978329b1e3b5fdaaaed9d3ca8b\",\"url\":\"https://static.crates.io/crates/bytecheck/0.8.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bytecheck\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.2\"},\"bytecheck_derive 0.8.2\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"bytecheck_derive\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"bytecheck_derive\",\"package_url\":\"https://github.com/rkyv/bytecheck\",\"repository\":{\"Http\":{\"sha256\":\"89385e82b5d1821d2219e0b095efa2cc1f246cbf99080f3be46a1a85c0d392d9\",\"url\":\"https://static.crates.io/crates/bytecheck_derive/0.8.2/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"bytecheck_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.2\"},\"byteorder 1.5.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"byteorder\",\"license\":\"Unlicense OR MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"byteorder\",\"package_url\":\"https://github.com/BurntSushi/byteorder\",\"repository\":{\"Http\":{\"sha256\":\"1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b\",\"url\":\"https://static.crates.io/crates/byteorder/1.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"byteorder\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.5.0\"},\"bytes 1.11.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"serde\",\"std\"],\"deps\":[{\"id\":\"serde 1.0.228\",\"target\":\"serde\"}],\"edition\":\"2021\"},\"library_target_name\":\"bytes\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"bytes\",\"package_url\":\"https://github.com/tokio-rs/bytes\",\"repository\":{\"Http\":{\"sha256\":\"1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33\",\"url\":\"https://static.crates.io/crates/bytes/1.11.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bytes\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.11.1\"},\"bytesize 2.3.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"serde\",\"std\"],\"deps\":[{\"id\":\"serde_core 1.0.228\",\"target\":\"serde_core\"}],\"edition\":\"2021\"},\"library_target_name\":\"bytesize\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"bytesize\",\"package_url\":\"https://github.com/bytesize-rs/bytesize\",\"repository\":{\"Http\":{\"sha256\":\"6bd91ee7b2422bcb158d90ef4d14f75ef67f340943fc4149891dcce8f8b972a3\",\"url\":\"https://static.crates.io/crates/bytesize/2.3.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bytesize\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.3.1\"},\"cc 1.2.60\":{\"common_attrs\":{\"crate_features\":[\"parallel\"],\"deps\":[{\"id\":\"find-msvc-tools 0.1.9\",\"target\":\"find_msvc_tools\"},{\"id\":\"jobserver 0.1.34\",\"target\":\"jobserver\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"},{\"id\":\"shlex 1.3.0\",\"target\":\"shlex\"}],\"edition\":\"2018\"},\"library_target_name\":\"cc\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"cc\",\"package_url\":\"https://github.com/rust-lang/cc-rs\",\"repository\":{\"Http\":{\"sha256\":\"43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20\",\"url\":\"https://static.crates.io/crates/cc/1.2.60/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cc\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.60\"},\"cexpr 0.6.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"nom 7.1.3\",\"target\":\"nom\"}],\"edition\":\"2018\"},\"library_target_name\":\"cexpr\",\"license\":\"Apache-2.0/MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"cexpr\",\"package_url\":\"https://github.com/jethrogb/rust-cexpr\",\"repository\":{\"Http\":{\"sha256\":\"6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766\",\"url\":\"https://static.crates.io/crates/cexpr/0.6.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cexpr\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.0\"},\"cfg-if 1.0.4\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"cfg_if\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"cfg-if\",\"package_url\":\"https://github.com/rust-lang/cfg-if\",\"repository\":{\"Http\":{\"sha256\":\"9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801\",\"url\":\"https://static.crates.io/crates/cfg-if/1.0.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cfg_if\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.4\"},\"chacha20 0.10.0\":{\"common_attrs\":{\"crate_features\":[\"rng\"],\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"rand_core 0.10.1\",\"target\":\"rand_core\"}],\"selects\":{\"cfg(any(target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\":[{\"id\":\"cpufeatures 0.3.0\",\"target\":\"cpufeatures\"}]}},\"edition\":\"2024\"},\"library_target_name\":\"chacha20\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"chacha20\",\"package_url\":\"https://github.com/RustCrypto/stream-ciphers\",\"repository\":{\"Http\":{\"sha256\":\"6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601\",\"url\":\"https://static.crates.io/crates/chacha20/0.10.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"chacha20\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.10.0\"},\"chrono 0.4.44\":{\"common_attrs\":{\"crate_features\":[\"alloc\"],\"deps\":[{\"id\":\"num-traits 0.2.19\",\"target\":\"num_traits\"}],\"edition\":\"2021\"},\"library_target_name\":\"chrono\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE.txt\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"chrono\",\"package_url\":\"https://github.com/chronotope/chrono\",\"repository\":{\"Http\":{\"sha256\":\"c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0\",\"url\":\"https://static.crates.io/crates/chrono/0.4.44/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"chrono\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.44\"},\"ciborium 0.2.2\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"ciborium-io 0.2.2\",\"target\":\"ciborium_io\"},{\"id\":\"ciborium-ll 0.2.2\",\"target\":\"ciborium_ll\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"}],\"edition\":\"2021\"},\"library_target_name\":\"ciborium\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"ciborium\",\"package_url\":\"https://github.com/enarx/ciborium\",\"repository\":{\"Http\":{\"sha256\":\"42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e\",\"url\":\"https://static.crates.io/crates/ciborium/0.2.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ciborium\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.2\"},\"ciborium-io 0.2.2\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"ciborium_io\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"ciborium-io\",\"package_url\":\"https://github.com/enarx/ciborium\",\"repository\":{\"Http\":{\"sha256\":\"05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757\",\"url\":\"https://static.crates.io/crates/ciborium-io/0.2.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ciborium_io\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.2\"},\"ciborium-ll 0.2.2\":{\"common_attrs\":{\"deps\":[{\"id\":\"ciborium-io 0.2.2\",\"target\":\"ciborium_io\"},{\"id\":\"half 2.7.1\",\"target\":\"half\"}],\"edition\":\"2021\"},\"library_target_name\":\"ciborium_ll\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"ciborium-ll\",\"package_url\":\"https://github.com/enarx/ciborium\",\"repository\":{\"Http\":{\"sha256\":\"57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9\",\"url\":\"https://static.crates.io/crates/ciborium-ll/0.2.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ciborium_ll\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.2\"},\"clang-sys 1.8.1\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"glob 0.3.3\",\"target\":\"glob\"}],\"links\":\"clang\"},\"common_attrs\":{\"crate_features\":[\"clang_10_0\",\"clang_11_0\",\"clang_3_5\",\"clang_3_6\",\"clang_3_7\",\"clang_3_8\",\"clang_3_9\",\"clang_4_0\",\"clang_5_0\",\"clang_6_0\",\"clang_7_0\",\"clang_8_0\",\"clang_9_0\",\"libloading\",\"runtime\"],\"deps\":[{\"id\":\"glob 0.3.3\",\"target\":\"glob\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"},{\"id\":\"libloading 0.8.9\",\"target\":\"libloading\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"clang_sys\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE.txt\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"clang-sys\",\"package_url\":\"https://github.com/KyleMayes/clang-sys\",\"repository\":{\"Http\":{\"sha256\":\"0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4\",\"url\":\"https://static.crates.io/crates/clang-sys/1.8.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"clang_sys\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.8.1\"},\"cmake 0.1.58\":{\"common_attrs\":{\"deps\":[{\"id\":\"cc 1.2.60\",\"target\":\"cc\"}],\"edition\":\"2021\"},\"library_target_name\":\"cmake\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"cmake\",\"package_url\":\"https://github.com/rust-lang/cmake-rs\",\"repository\":{\"Http\":{\"sha256\":\"c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678\",\"url\":\"https://static.crates.io/crates/cmake/0.1.58/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cmake\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.58\"},\"console 0.16.3\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"std\"],\"deps\":{\"common\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"selects\":{\"cfg(windows)\":[{\"id\":\"encode_unicode 1.0.0\",\"target\":\"encode_unicode\"},{\"id\":\"windows-sys 0.61.2\",\"target\":\"windows_sys\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"console\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"console\",\"package_url\":\"https://github.com/console-rs/console\",\"repository\":{\"Http\":{\"sha256\":\"d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87\",\"url\":\"https://static.crates.io/crates/console/0.16.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"console\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.16.3\"},\"const-oid 0.10.2\":{\"common_attrs\":{\"edition\":\"2024\"},\"library_target_name\":\"const_oid\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"const-oid\",\"package_url\":\"https://github.com/RustCrypto/formats\",\"repository\":{\"Http\":{\"sha256\":\"a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c\",\"url\":\"https://static.crates.io/crates/const-oid/0.10.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"const_oid\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.10.2\"},\"constant_time_eq 0.4.2\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"edition\":\"2024\"},\"library_target_name\":\"constant_time_eq\",\"license\":\"CC0-1.0 OR MIT-0 OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"CC0-1.0\",\"MIT-0\"],\"name\":\"constant_time_eq\",\"package_url\":\"https://github.com/cesarb/constant_time_eq\",\"repository\":{\"Http\":{\"sha256\":\"3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b\",\"url\":\"https://static.crates.io/crates/constant_time_eq/0.4.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"constant_time_eq\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.2\"},\"convert_case 0.10.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"unicode-segmentation 1.13.2\",\"target\":\"unicode_segmentation\"}],\"edition\":\"2021\"},\"library_target_name\":\"convert_case\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"convert_case\",\"package_url\":\"https://github.com/rutrum/convert-case\",\"repository\":{\"Http\":{\"sha256\":\"633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9\",\"url\":\"https://static.crates.io/crates/convert_case/0.10.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"convert_case\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.10.0\"},\"cooked-waker 5.0.0\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"cooked_waker\",\"license\":\"MPL-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MPL-2.0\"],\"name\":\"cooked-waker\",\"package_url\":\"https://github.com/Lucretiel/cooked-waker\",\"repository\":{\"Http\":{\"sha256\":\"147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f\",\"url\":\"https://static.crates.io/crates/cooked-waker/5.0.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cooked_waker\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"5.0.0\"},\"corosensei 0.3.3\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"autocfg 1.5.0\",\"target\":\"autocfg\"}]},\"common_attrs\":{\"crate_features\":[\"default\",\"default-stack\",\"libc\",\"unwind\",\"windows-sys\"],\"deps\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"},{\"id\":\"scopeguard 1.2.0\",\"target\":\"scopeguard\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"corosensei\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"corosensei\",\"package_url\":\"https://github.com/Amanieu/corosensei\",\"repository\":{\"Http\":{\"sha256\":\"2c54787b605c7df106ceccf798df23da4f2e09918defad66705d1cedf3bb914f\",\"url\":\"https://static.crates.io/crates/corosensei/0.3.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"corosensei\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.3.3\"},\"cpp_demangle 0.4.5\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"deps\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"}],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"cpp_demangle\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"cpp_demangle\",\"package_url\":\"https://github.com/gimli-rs/cpp_demangle\",\"repository\":{\"Http\":{\"sha256\":\"f2bb79cb74d735044c972aae58ed0aaa9a837e85b01106a54c39e42e97f62253\",\"url\":\"https://static.crates.io/crates/cpp_demangle/0.4.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cpp_demangle\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.4.5\"},\"cpufeatures 0.2.17\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"aarch64-linux-android\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"linux\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(all(target_arch = \\\"aarch64\\\", target_vendor = \\\"apple\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(all(target_arch = \\\"loongarch64\\\", target_os = \\\"linux\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"cpufeatures\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"cpufeatures\",\"package_url\":\"https://github.com/RustCrypto/utils\",\"repository\":{\"Http\":{\"sha256\":\"59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280\",\"url\":\"https://static.crates.io/crates/cpufeatures/0.2.17/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cpufeatures\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.17\"},\"cpufeatures 0.3.0\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"android\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"linux\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(all(target_arch = \\\"aarch64\\\", target_vendor = \\\"apple\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(all(target_arch = \\\"loongarch64\\\", target_os = \\\"linux\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}]}},\"edition\":\"2024\"},\"library_target_name\":\"cpufeatures\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"cpufeatures\",\"package_url\":\"https://github.com/RustCrypto/utils\",\"repository\":{\"Http\":{\"sha256\":\"8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201\",\"url\":\"https://static.crates.io/crates/cpufeatures/0.3.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cpufeatures\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.0\"},\"crc32fast 1.5.0\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"crc32fast\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"crc32fast\",\"package_url\":\"https://github.com/srijs/rust-crc32fast\",\"repository\":{\"Http\":{\"sha256\":\"9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511\",\"url\":\"https://static.crates.io/crates/crc32fast/1.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crc32fast\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.5.0\"},\"crossbeam-channel 0.5.15\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"crossbeam-utils 0.8.21\",\"target\":\"crossbeam_utils\"}],\"edition\":\"2021\"},\"library_target_name\":\"crossbeam_channel\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"crossbeam-channel\",\"package_url\":\"https://github.com/crossbeam-rs/crossbeam\",\"repository\":{\"Http\":{\"sha256\":\"82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2\",\"url\":\"https://static.crates.io/crates/crossbeam-channel/0.5.15/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crossbeam_channel\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.15\"},\"crossbeam-deque 0.8.6\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"crossbeam-epoch 0.9.18\",\"target\":\"crossbeam_epoch\"},{\"id\":\"crossbeam-utils 0.8.21\",\"target\":\"crossbeam_utils\"}],\"edition\":\"2021\"},\"library_target_name\":\"crossbeam_deque\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"crossbeam-deque\",\"package_url\":\"https://github.com/crossbeam-rs/crossbeam\",\"repository\":{\"Http\":{\"sha256\":\"9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51\",\"url\":\"https://static.crates.io/crates/crossbeam-deque/0.8.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crossbeam_deque\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.6\"},\"crossbeam-epoch 0.9.18\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"std\"],\"deps\":[{\"id\":\"crossbeam-utils 0.8.21\",\"target\":\"crossbeam_utils\"}],\"edition\":\"2021\"},\"library_target_name\":\"crossbeam_epoch\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"crossbeam-epoch\",\"package_url\":\"https://github.com/crossbeam-rs/crossbeam\",\"repository\":{\"Http\":{\"sha256\":\"5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e\",\"url\":\"https://static.crates.io/crates/crossbeam-epoch/0.9.18/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crossbeam_epoch\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.9.18\"},\"crossbeam-queue 0.3.12\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"deps\":[{\"id\":\"crossbeam-utils 0.8.21\",\"target\":\"crossbeam_utils\"}],\"edition\":\"2021\"},\"library_target_name\":\"crossbeam_queue\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"crossbeam-queue\",\"package_url\":\"https://github.com/crossbeam-rs/crossbeam\",\"repository\":{\"Http\":{\"sha256\":\"0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115\",\"url\":\"https://static.crates.io/crates/crossbeam-queue/0.3.12/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crossbeam_queue\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.12\"},\"crossbeam-utils 0.8.21\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"crossbeam_utils\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"crossbeam-utils\",\"package_url\":\"https://github.com/crossbeam-rs/crossbeam\",\"repository\":{\"Http\":{\"sha256\":\"d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28\",\"url\":\"https://static.crates.io/crates/crossbeam-utils/0.8.21/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crossbeam_utils\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.8.21\"},\"crunchy 0.2.4\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"crunchy\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"crunchy\",\"package_url\":\"https://github.com/eira-fransham/crunchy\",\"repository\":{\"Http\":{\"sha256\":\"460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5\",\"url\":\"https://static.crates.io/crates/crunchy/0.2.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crunchy\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.2.4\"},\"crypto-common 0.1.7\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"deps\":[{\"id\":\"generic-array 0.14.7\",\"target\":\"generic_array\"},{\"id\":\"typenum 1.20.0\",\"target\":\"typenum\"}],\"edition\":\"2018\"},\"library_target_name\":\"crypto_common\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"crypto-common\",\"package_url\":\"https://github.com/RustCrypto/traits\",\"repository\":{\"Http\":{\"sha256\":\"78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a\",\"url\":\"https://static.crates.io/crates/crypto-common/0.1.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crypto_common\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.7\"},\"crypto-common 0.2.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"hybrid-array 0.4.10\",\"target\":\"hybrid_array\"}],\"edition\":\"2024\"},\"library_target_name\":\"crypto_common\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"crypto-common\",\"package_url\":\"https://github.com/RustCrypto/traits\",\"repository\":{\"Http\":{\"sha256\":\"77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710\",\"url\":\"https://static.crates.io/crates/crypto-common/0.2.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crypto_common\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.1\"},\"darling 0.20.11\":{\"common_attrs\":{\"crate_features\":[\"default\",\"suggestions\"],\"deps\":[{\"id\":\"darling_core 0.20.11\",\"target\":\"darling_core\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"darling_macro 0.20.11\",\"target\":\"darling_macro\"}]},\"library_target_name\":\"darling\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"darling\",\"package_url\":\"https://github.com/TedDriggs/darling\",\"repository\":{\"Http\":{\"sha256\":\"fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee\",\"url\":\"https://static.crates.io/crates/darling/0.20.11/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"darling\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.20.11\"},\"darling 0.21.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"darling_core 0.21.3\",\"target\":\"darling_core\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"darling_macro 0.21.3\",\"target\":\"darling_macro\"}]},\"library_target_name\":\"darling\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"darling\",\"package_url\":\"https://github.com/TedDriggs/darling\",\"repository\":{\"Http\":{\"sha256\":\"9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0\",\"url\":\"https://static.crates.io/crates/darling/0.21.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"darling\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.21.3\"},\"darling_core 0.20.11\":{\"common_attrs\":{\"crate_features\":[\"strsim\",\"suggestions\"],\"deps\":[{\"id\":\"fnv 1.0.7\",\"target\":\"fnv\"},{\"id\":\"ident_case 1.0.1\",\"target\":\"ident_case\"},{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"strsim 0.11.1\",\"target\":\"strsim\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"darling_core\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"darling_core\",\"package_url\":\"https://github.com/TedDriggs/darling\",\"repository\":{\"Http\":{\"sha256\":\"0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e\",\"url\":\"https://static.crates.io/crates/darling_core/0.20.11/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"darling_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.20.11\"},\"darling_core 0.21.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"fnv 1.0.7\",\"target\":\"fnv\"},{\"id\":\"ident_case 1.0.1\",\"target\":\"ident_case\"},{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"darling_core\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"darling_core\",\"package_url\":\"https://github.com/TedDriggs/darling\",\"repository\":{\"Http\":{\"sha256\":\"1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4\",\"url\":\"https://static.crates.io/crates/darling_core/0.21.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"darling_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.21.3\"},\"darling_macro 0.20.11\":{\"common_attrs\":{\"deps\":[{\"id\":\"darling_core 0.20.11\",\"target\":\"darling_core\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"darling_macro\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"darling_macro\",\"package_url\":\"https://github.com/TedDriggs/darling\",\"repository\":{\"Http\":{\"sha256\":\"fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead\",\"url\":\"https://static.crates.io/crates/darling_macro/0.20.11/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"darling_macro\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.20.11\"},\"darling_macro 0.21.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"darling_core 0.21.3\",\"target\":\"darling_core\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"darling_macro\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"darling_macro\",\"package_url\":\"https://github.com/TedDriggs/darling\",\"repository\":{\"Http\":{\"sha256\":\"d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81\",\"url\":\"https://static.crates.io/crates/darling_macro/0.21.3/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"darling_macro\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.21.3\"},\"dashmap 6.1.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"crossbeam-utils 0.8.21\",\"target\":\"crossbeam_utils\"},{\"id\":\"hashbrown 0.14.5\",\"target\":\"hashbrown\"},{\"id\":\"lock_api 0.4.14\",\"target\":\"lock_api\"},{\"id\":\"once_cell 1.21.4\",\"target\":\"once_cell\"},{\"id\":\"parking_lot_core 0.9.12\",\"target\":\"parking_lot_core\"}],\"edition\":\"2018\"},\"library_target_name\":\"dashmap\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"dashmap\",\"package_url\":\"https://github.com/xacrimon/dashmap\",\"repository\":{\"Http\":{\"sha256\":\"5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf\",\"url\":\"https://static.crates.io/crates/dashmap/6.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"dashmap\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"6.1.0\"},\"debugid 0.8.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"uuid 1.23.1\",\"target\":\"uuid\"}],\"edition\":\"2018\"},\"library_target_name\":\"debugid\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"debugid\",\"package_url\":\"https://github.com/getsentry/rust-debugid\",\"repository\":{\"Http\":{\"sha256\":\"bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d\",\"url\":\"https://static.crates.io/crates/debugid/0.8.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"debugid\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.0\"},\"defmt 0.3.100\":{\"common_attrs\":{\"deps\":[{\"alias\":\"defmt10\",\"id\":\"defmt 1.0.1\",\"target\":\"defmt\"}],\"edition\":\"2021\"},\"library_target_name\":\"defmt\",\"license\":\"MIT OR Apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"defmt\",\"package_url\":\"https://github.com/knurling-rs/defmt\",\"repository\":{\"Http\":{\"sha256\":\"f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad\",\"url\":\"https://static.crates.io/crates/defmt/0.3.100/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"defmt\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.100\"},\"defmt 1.0.1\":{\"build_script_attrs\":{\"links\":\"defmt\"},\"common_attrs\":{\"deps\":[{\"id\":\"bitflags 1.3.2\",\"target\":\"bitflags\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":[{\"id\":\"defmt-macros 1.0.1\",\"target\":\"defmt_macros\"}]},\"library_target_name\":\"defmt\",\"license\":\"MIT OR Apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"defmt\",\"package_url\":\"https://github.com/knurling-rs/defmt\",\"repository\":{\"Http\":{\"sha256\":\"548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78\",\"url\":\"https://static.crates.io/crates/defmt/1.0.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"defmt\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.1\"},\"defmt-macros 1.0.1\":{\"build_script_attrs\":{},\"common_attrs\":{\"deps\":[{\"id\":\"defmt-parser 1.0.0\",\"target\":\"defmt_parser\"},{\"id\":\"proc-macro-error2 2.0.1\",\"target\":\"proc_macro_error2\"},{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"defmt_macros\",\"license\":\"MIT OR Apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"defmt-macros\",\"package_url\":\"https://github.com/knurling-rs/defmt\",\"repository\":{\"Http\":{\"sha256\":\"3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e\",\"url\":\"https://static.crates.io/crates/defmt-macros/1.0.1/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"defmt_macros\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.1\"},\"defmt-parser 1.0.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"}],\"edition\":\"2021\"},\"library_target_name\":\"defmt_parser\",\"license\":\"MIT OR Apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"defmt-parser\",\"package_url\":\"https://github.com/knurling-rs/defmt\",\"repository\":{\"Http\":{\"sha256\":\"10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e\",\"url\":\"https://static.crates.io/crates/defmt-parser/1.0.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"defmt_parser\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.0\"},\"deranged 0.5.8\":{\"common_attrs\":{\"crate_features\":[\"default\",\"powerfmt\"],\"deps\":[{\"id\":\"powerfmt 0.2.0\",\"target\":\"powerfmt\"}],\"edition\":\"2021\"},\"library_target_name\":\"deranged\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-Apache\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"deranged\",\"package_url\":\"https://github.com/jhpratt/deranged\",\"repository\":{\"Http\":{\"sha256\":\"7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c\",\"url\":\"https://static.crates.io/crates/deranged/0.5.8/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"deranged\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.8\"},\"derive_builder 0.20.2\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2018\",\"proc_macro_deps\":[{\"id\":\"derive_builder_macro 0.20.2\",\"target\":\"derive_builder_macro\"}]},\"library_target_name\":\"derive_builder\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"derive_builder\",\"package_url\":\"https://github.com/colin-kiegel/rust-derive-builder\",\"repository\":{\"Http\":{\"sha256\":\"507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947\",\"url\":\"https://static.crates.io/crates/derive_builder/0.20.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"derive_builder\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.20.2\"},\"derive_builder_core 0.20.2\":{\"common_attrs\":{\"crate_features\":[\"lib_has_std\"],\"deps\":[{\"id\":\"darling 0.20.11\",\"target\":\"darling\"},{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2018\"},\"library_target_name\":\"derive_builder_core\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"derive_builder_core\",\"package_url\":\"https://github.com/colin-kiegel/rust-derive-builder\",\"repository\":{\"Http\":{\"sha256\":\"2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8\",\"url\":\"https://static.crates.io/crates/derive_builder_core/0.20.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"derive_builder_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.20.2\"},\"derive_builder_macro 0.20.2\":{\"common_attrs\":{\"crate_features\":[\"lib_has_std\"],\"deps\":[{\"id\":\"derive_builder_core 0.20.2\",\"target\":\"derive_builder_core\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2018\"},\"library_target_name\":\"derive_builder_macro\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"derive_builder_macro\",\"package_url\":\"https://github.com/colin-kiegel/rust-derive-builder\",\"repository\":{\"Http\":{\"sha256\":\"ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c\",\"url\":\"https://static.crates.io/crates/derive_builder_macro/0.20.2/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"derive_builder_macro\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.20.2\"},\"derive_more 2.1.1\":{\"common_attrs\":{\"crate_features\":[\"debug\",\"default\",\"display\",\"from\",\"std\",\"unwrap\"],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"derive_more-impl 2.1.1\",\"target\":\"derive_more_impl\"}]},\"library_target_name\":\"derive_more\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"derive_more\",\"package_url\":\"https://github.com/JelteF/derive_more\",\"repository\":{\"Http\":{\"sha256\":\"d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134\",\"url\":\"https://static.crates.io/crates/derive_more/2.1.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"derive_more\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.1.1\"},\"derive_more-impl 2.1.1\":{\"common_attrs\":{\"crate_features\":[\"debug\",\"default\",\"display\",\"from\",\"unwrap\"],\"deps\":[{\"id\":\"convert_case 0.10.0\",\"target\":\"convert_case\"},{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"},{\"id\":\"unicode-xid 0.2.6\",\"target\":\"unicode_xid\"}],\"edition\":\"2021\"},\"library_target_name\":\"derive_more_impl\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"derive_more-impl\",\"package_url\":\"https://github.com/JelteF/derive_more\",\"repository\":{\"Http\":{\"sha256\":\"799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb\",\"url\":\"https://static.crates.io/crates/derive_more-impl/2.1.1/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"derive_more_impl\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.1.1\"},\"digest 0.10.7\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"block-buffer\",\"core-api\",\"default\",\"std\"],\"deps\":[{\"id\":\"block-buffer 0.10.4\",\"target\":\"block_buffer\"},{\"id\":\"crypto-common 0.1.7\",\"target\":\"crypto_common\"}],\"edition\":\"2018\"},\"library_target_name\":\"digest\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"digest\",\"package_url\":\"https://github.com/RustCrypto/traits\",\"repository\":{\"Http\":{\"sha256\":\"9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292\",\"url\":\"https://static.crates.io/crates/digest/0.10.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"digest\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.10.7\"},\"digest 0.11.2\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"block-api\",\"default\",\"oid\"],\"deps\":[{\"id\":\"block-buffer 0.12.0\",\"target\":\"block_buffer\"},{\"id\":\"const-oid 0.10.2\",\"target\":\"const_oid\"},{\"alias\":\"common\",\"id\":\"crypto-common 0.2.1\",\"target\":\"crypto_common\"}],\"edition\":\"2024\"},\"library_target_name\":\"digest\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"digest\",\"package_url\":\"https://github.com/RustCrypto/traits\",\"repository\":{\"Http\":{\"sha256\":\"4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c\",\"url\":\"https://static.crates.io/crates/digest/0.11.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"digest\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.11.2\"},\"displaydoc 0.2.5\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"displaydoc\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"displaydoc\",\"package_url\":\"https://github.com/yaahc/displaydoc\",\"repository\":{\"Http\":{\"sha256\":\"97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0\",\"url\":\"https://static.crates.io/crates/displaydoc/0.2.5/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"displaydoc\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.5\"},\"document-features 0.2.12\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"deps\":[{\"id\":\"litrs 1.0.0\",\"target\":\"litrs\"}],\"edition\":\"2018\"},\"library_target_name\":\"document_features\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"document-features\",\"package_url\":\"https://github.com/slint-ui/document-features\",\"repository\":{\"Http\":{\"sha256\":\"d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61\",\"url\":\"https://static.crates.io/crates/document-features/0.2.12/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"document_features\",\"crate_root\":\"lib.rs\"}}],\"version\":\"0.2.12\"},\"dunce 1.0.5\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"dunce\",\"license\":\"CC0-1.0 OR MIT-0 OR Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\",\"CC0-1.0\",\"MIT-0\"],\"name\":\"dunce\",\"package_url\":\"https://gitlab.com/kornelski/dunce\",\"repository\":{\"Http\":{\"sha256\":\"92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813\",\"url\":\"https://static.crates.io/crates/dunce/1.0.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"dunce\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.5\"},\"dyn-clone 1.0.20\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"dyn_clone\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"dyn-clone\",\"package_url\":\"https://github.com/dtolnay/dyn-clone\",\"repository\":{\"Http\":{\"sha256\":\"d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555\",\"url\":\"https://static.crates.io/crates/dyn-clone/1.0.20/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"dyn_clone\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.20\"},\"either 1.15.0\":{\"common_attrs\":{\"crate_features\":[\"std\",\"use_std\"],\"edition\":\"2021\"},\"library_target_name\":\"either\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"either\",\"package_url\":\"https://github.com/rayon-rs/either\",\"repository\":{\"Http\":{\"sha256\":\"48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719\",\"url\":\"https://static.crates.io/crates/either/1.15.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"either\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.15.0\"},\"encode_unicode 1.0.0\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"encode_unicode\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"encode_unicode\",\"package_url\":\"https://github.com/tormol/encode_unicode\",\"repository\":{\"Http\":{\"sha256\":\"34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0\",\"url\":\"https://static.crates.io/crates/encode_unicode/1.0.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"encode_unicode\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.0\"},\"enum-iterator 2.3.0\":{\"common_attrs\":{\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"enum-iterator-derive 1.5.0\",\"target\":\"enum_iterator_derive\"}]},\"library_target_name\":\"enum_iterator\",\"license\":\"0BSD\",\"license_file\":\"LICENSE\",\"license_ids\":[\"0BSD\"],\"name\":\"enum-iterator\",\"package_url\":\"https://github.com/stephaneyfx/enum-iterator.git\",\"repository\":{\"Http\":{\"sha256\":\"a4549325971814bda7a44061bf3fe7e487d447cba01e4220a4b454d630d7a016\",\"url\":\"https://static.crates.io/crates/enum-iterator/2.3.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"enum_iterator\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.3.0\"},\"enum-iterator-derive 1.5.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"enum_iterator_derive\",\"license\":\"0BSD\",\"license_file\":\"LICENSE\",\"license_ids\":[\"0BSD\"],\"name\":\"enum-iterator-derive\",\"package_url\":\"https://github.com/stephaneyfx/enum-iterator.git\",\"repository\":{\"Http\":{\"sha256\":\"685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842\",\"url\":\"https://static.crates.io/crates/enum-iterator-derive/1.5.0/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"enum_iterator_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.5.0\"},\"enumset 1.1.10\":{\"common_attrs\":{\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"enumset_derive 0.14.0\",\"target\":\"enumset_derive\"}]},\"library_target_name\":\"enumset\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"enumset\",\"package_url\":\"https://github.com/Lymia/enumset\",\"repository\":{\"Http\":{\"sha256\":\"25b07a8dfbbbfc0064c0a6bdf9edcf966de6b1c33ce344bdeca3b41615452634\",\"url\":\"https://static.crates.io/crates/enumset/1.1.10/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"enumset\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.10\"},\"enumset_derive 0.14.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"darling 0.21.3\",\"target\":\"darling\"},{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"enumset_derive\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"enumset_derive\",\"package_url\":\"https://github.com/Lymia/enumset\",\"repository\":{\"Http\":{\"sha256\":\"f43e744e4ea338060faee68ed933e46e722fb7f3617e722a5772d7e856d8b3ce\",\"url\":\"https://static.crates.io/crates/enumset_derive/0.14.0/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"enumset_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.14.0\"},\"equivalent 1.0.2\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"equivalent\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"equivalent\",\"package_url\":\"https://github.com/indexmap-rs/equivalent\",\"repository\":{\"Http\":{\"sha256\":\"877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f\",\"url\":\"https://static.crates.io/crates/equivalent/1.0.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"equivalent\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.2\"},\"errno 0.3.14\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"deps\":{\"common\":[],\"selects\":{\"cfg(target_os = \\\"hermit\\\")\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(target_os = \\\"wasi\\\")\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(unix)\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(windows)\":[{\"id\":\"windows-sys 0.61.2\",\"target\":\"windows_sys\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"errno\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"errno\",\"package_url\":\"https://github.com/lambda-fairy/rust-errno\",\"repository\":{\"Http\":{\"sha256\":\"39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb\",\"url\":\"https://static.crates.io/crates/errno/0.3.14/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"errno\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.14\"},\"fastrand 2.4.1\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"fastrand\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"fastrand\",\"package_url\":\"https://github.com/smol-rs/fastrand\",\"repository\":{\"Http\":{\"sha256\":\"9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6\",\"url\":\"https://static.crates.io/crates/fastrand/2.4.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"fastrand\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.4.1\"},\"filetime 0.2.27\":{\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"}],\"selects\":{\"cfg(target_os = \\\"redox\\\")\":[{\"id\":\"libredox 0.1.16\",\"target\":\"libredox\"}],\"cfg(unix)\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"filetime\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"filetime\",\"package_url\":\"https://github.com/alexcrichton/filetime\",\"repository\":{\"Http\":{\"sha256\":\"f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db\",\"url\":\"https://static.crates.io/crates/filetime/0.2.27/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"filetime\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.27\"},\"find-msvc-tools 0.1.9\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"find_msvc_tools\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"find-msvc-tools\",\"package_url\":\"https://github.com/rust-lang/cc-rs\",\"repository\":{\"Http\":{\"sha256\":\"5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582\",\"url\":\"https://static.crates.io/crates/find-msvc-tools/0.1.9/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"find_msvc_tools\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.9\"},\"fixedbitset 0.5.7\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"fixedbitset\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"fixedbitset\",\"package_url\":\"https://github.com/petgraph/fixedbitset\",\"repository\":{\"Http\":{\"sha256\":\"1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99\",\"url\":\"https://static.crates.io/crates/fixedbitset/0.5.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"fixedbitset\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.7\"},\"flate2 1.1.9\":{\"common_attrs\":{\"crate_features\":[\"any_impl\",\"default\",\"miniz_oxide\",\"rust_backend\"],\"deps\":[{\"id\":\"crc32fast 1.5.0\",\"target\":\"crc32fast\"},{\"id\":\"miniz_oxide 0.8.9\",\"target\":\"miniz_oxide\"}],\"edition\":\"2018\"},\"library_target_name\":\"flate2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"flate2\",\"package_url\":\"https://github.com/rust-lang/flate2-rs\",\"repository\":{\"Http\":{\"sha256\":\"843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c\",\"url\":\"https://static.crates.io/crates/flate2/1.1.9/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"flate2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.9\"},\"fnv 1.0.7\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2015\"},\"library_target_name\":\"fnv\",\"license\":\"Apache-2.0 / MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"fnv\",\"package_url\":\"https://github.com/servo/rust-fnv\",\"repository\":{\"Http\":{\"sha256\":\"3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1\",\"url\":\"https://static.crates.io/crates/fnv/1.0.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"fnv\",\"crate_root\":\"lib.rs\"}}],\"version\":\"1.0.7\"},\"foldhash 0.1.5\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"foldhash\",\"license\":\"Zlib\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Zlib\"],\"name\":\"foldhash\",\"package_url\":\"https://github.com/orlp/foldhash\",\"repository\":{\"Http\":{\"sha256\":\"d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2\",\"url\":\"https://static.crates.io/crates/foldhash/0.1.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"foldhash\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.5\"},\"foldhash 0.2.0\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"foldhash\",\"license\":\"Zlib\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Zlib\"],\"name\":\"foldhash\",\"package_url\":\"https://github.com/orlp/foldhash\",\"repository\":{\"Http\":{\"sha256\":\"77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb\",\"url\":\"https://static.crates.io/crates/foldhash/0.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"foldhash\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.0\"},\"form_urlencoded 1.2.2\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"std\"],\"deps\":[{\"id\":\"percent-encoding 2.3.2\",\"target\":\"percent_encoding\"}],\"edition\":\"2018\"},\"library_target_name\":\"form_urlencoded\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"form_urlencoded\",\"package_url\":\"https://github.com/servo/rust-url\",\"repository\":{\"Http\":{\"sha256\":\"cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf\",\"url\":\"https://static.crates.io/crates/form_urlencoded/1.2.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"form_urlencoded\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.2\"},\"fs_extra 1.3.0\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"fs_extra\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"fs_extra\",\"package_url\":\"https://github.com/webdesus/fs_extra\",\"repository\":{\"Http\":{\"sha256\":\"42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c\",\"url\":\"https://static.crates.io/crates/fs_extra/1.3.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"fs_extra\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.3.0\"},\"futures 0.3.32\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"async-await\",\"default\",\"executor\",\"futures-executor\",\"std\"],\"deps\":[{\"id\":\"futures-channel 0.3.32\",\"target\":\"futures_channel\"},{\"id\":\"futures-core 0.3.32\",\"target\":\"futures_core\"},{\"id\":\"futures-executor 0.3.32\",\"target\":\"futures_executor\"},{\"id\":\"futures-io 0.3.32\",\"target\":\"futures_io\"},{\"id\":\"futures-sink 0.3.32\",\"target\":\"futures_sink\"},{\"id\":\"futures-task 0.3.32\",\"target\":\"futures_task\"},{\"id\":\"futures-util 0.3.32\",\"target\":\"futures_util\"}],\"edition\":\"2018\"},\"library_target_name\":\"futures\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d\",\"url\":\"https://static.crates.io/crates/futures/0.3.32/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.32\"},\"futures-channel 0.3.32\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"futures-sink\",\"sink\",\"std\"],\"deps\":[{\"id\":\"futures-core 0.3.32\",\"target\":\"futures_core\"},{\"id\":\"futures-sink 0.3.32\",\"target\":\"futures_sink\"}],\"edition\":\"2018\"},\"library_target_name\":\"futures_channel\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-channel\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d\",\"url\":\"https://static.crates.io/crates/futures-channel/0.3.32/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures_channel\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.32\"},\"futures-core 0.3.32\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"futures_core\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-core\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d\",\"url\":\"https://static.crates.io/crates/futures-core/0.3.32/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.32\"},\"futures-executor 0.3.32\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"futures-core 0.3.32\",\"target\":\"futures_core\"},{\"id\":\"futures-task 0.3.32\",\"target\":\"futures_task\"},{\"id\":\"futures-util 0.3.32\",\"target\":\"futures_util\"}],\"edition\":\"2018\"},\"library_target_name\":\"futures_executor\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-executor\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d\",\"url\":\"https://static.crates.io/crates/futures-executor/0.3.32/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures_executor\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.32\"},\"futures-io 0.3.32\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"futures_io\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-io\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718\",\"url\":\"https://static.crates.io/crates/futures-io/0.3.32/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures_io\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.32\"},\"futures-macro 0.3.32\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2018\"},\"library_target_name\":\"futures_macro\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-macro\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b\",\"url\":\"https://static.crates.io/crates/futures-macro/0.3.32/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"futures_macro\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.32\"},\"futures-sink 0.3.32\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"futures_sink\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-sink\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893\",\"url\":\"https://static.crates.io/crates/futures-sink/0.3.32/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures_sink\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.32\"},\"futures-task 0.3.32\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"futures_task\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-task\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393\",\"url\":\"https://static.crates.io/crates/futures-task/0.3.32/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures_task\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.32\"},\"futures-util 0.3.32\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"async-await\",\"async-await-macro\",\"channel\",\"default\",\"futures-channel\",\"futures-io\",\"futures-macro\",\"futures-sink\",\"io\",\"memchr\",\"sink\",\"slab\",\"std\"],\"deps\":[{\"id\":\"futures-channel 0.3.32\",\"target\":\"futures_channel\"},{\"id\":\"futures-core 0.3.32\",\"target\":\"futures_core\"},{\"id\":\"futures-io 0.3.32\",\"target\":\"futures_io\"},{\"id\":\"futures-sink 0.3.32\",\"target\":\"futures_sink\"},{\"id\":\"futures-task 0.3.32\",\"target\":\"futures_task\"},{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"},{\"id\":\"pin-project-lite 0.2.17\",\"target\":\"pin_project_lite\"},{\"id\":\"slab 0.4.12\",\"target\":\"slab\"}],\"edition\":\"2018\",\"proc_macro_deps\":[{\"id\":\"futures-macro 0.3.32\",\"target\":\"futures_macro\"}]},\"library_target_name\":\"futures_util\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-util\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6\",\"url\":\"https://static.crates.io/crates/futures-util/0.3.32/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures_util\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.32\"},\"generic-array 0.14.7\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"version_check 0.9.5\",\"target\":\"version_check\"}]},\"common_attrs\":{\"crate_features\":[\"more_lengths\"],\"deps\":[{\"id\":\"typenum 1.20.0\",\"target\":\"typenum\"}],\"edition\":\"2015\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"generic_array\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"generic-array\",\"package_url\":\"https://github.com/fizyk20/generic-array.git\",\"repository\":{\"Http\":{\"sha256\":\"85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a\",\"url\":\"https://static.crates.io/crates/generic-array/0.14.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"generic_array\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.14.7\"},\"getrandom 0.3.4\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"std\"],\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"}],\"selects\":{\"cfg(all(any(target_os = \\\"linux\\\", target_os = \\\"android\\\"), not(any(all(target_os = \\\"linux\\\", target_env = \\\"\\\"), getrandom_backend = \\\"custom\\\", getrandom_backend = \\\"linux_raw\\\", getrandom_backend = \\\"rdrand\\\", getrandom_backend = \\\"rndr\\\"))))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"wasi\\\", target_env = \\\"p2\\\"))\":[{\"id\":\"wasip2 1.0.3+wasi-0.2.9\",\"target\":\"wasip2\"}],\"cfg(all(target_os = \\\"uefi\\\", getrandom_backend = \\\"efi_rng\\\"))\":[{\"id\":\"r-efi 5.3.0\",\"target\":\"r_efi\"}],\"cfg(any(target_os = \\\"dragonfly\\\", target_os = \\\"freebsd\\\", target_os = \\\"hurd\\\", target_os = \\\"illumos\\\", target_os = \\\"cygwin\\\", all(target_os = \\\"horizon\\\", target_arch = \\\"arm\\\")))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(any(target_os = \\\"haiku\\\", target_os = \\\"redox\\\", target_os = \\\"nto\\\", target_os = \\\"aix\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(any(target_os = \\\"ios\\\", target_os = \\\"visionos\\\", target_os = \\\"watchos\\\", target_os = \\\"tvos\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"openbsd\\\", target_os = \\\"vita\\\", target_os = \\\"emscripten\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(target_os = \\\"netbsd\\\")\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(target_os = \\\"solaris\\\")\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(target_os = \\\"vxworks\\\")\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}]}},\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"getrandom\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"getrandom\",\"package_url\":\"https://github.com/rust-random/getrandom\",\"repository\":{\"Http\":{\"sha256\":\"899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd\",\"url\":\"https://static.crates.io/crates/getrandom/0.3.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"getrandom\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.3.4\"},\"getrandom 0.4.2\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"std\",\"sys_rng\",\"wasm_js\"],\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"rand_core 0.10.1\",\"target\":\"rand_core\"}],\"selects\":{\"cfg(all(any(target_os = \\\"linux\\\", target_os = \\\"android\\\"), not(any(all(target_os = \\\"linux\\\", target_env = \\\"\\\"), getrandom_backend = \\\"custom\\\", getrandom_backend = \\\"linux_raw\\\", getrandom_backend = \\\"rdrand\\\", getrandom_backend = \\\"rndr\\\"))))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"wasi\\\", target_env = \\\"p2\\\"))\":[{\"id\":\"wasip2 1.0.3+wasi-0.2.9\",\"target\":\"wasip2\"}],\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"wasi\\\", target_env = \\\"p3\\\"))\":[{\"id\":\"wasip3 0.4.0+wasi-0.3.0-rc-2026-01-06\",\"target\":\"wasip3\"}],\"cfg(all(target_os = \\\"uefi\\\", getrandom_backend = \\\"efi_rng\\\"))\":[{\"id\":\"r-efi 6.0.0\",\"target\":\"r_efi\"}],\"cfg(any(target_os = \\\"dragonfly\\\", target_os = \\\"freebsd\\\", target_os = \\\"hurd\\\", target_os = \\\"illumos\\\", target_os = \\\"cygwin\\\", all(target_os = \\\"horizon\\\", target_arch = \\\"arm\\\")))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(any(target_os = \\\"haiku\\\", target_os = \\\"redox\\\", target_os = \\\"nto\\\", target_os = \\\"aix\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(any(target_os = \\\"ios\\\", target_os = \\\"visionos\\\", target_os = \\\"watchos\\\", target_os = \\\"tvos\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"openbsd\\\", target_os = \\\"vita\\\", target_os = \\\"emscripten\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(target_os = \\\"netbsd\\\")\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(target_os = \\\"solaris\\\")\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(target_os = \\\"vxworks\\\")\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}]}},\"edition\":\"2024\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"getrandom\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"getrandom\",\"package_url\":\"https://github.com/rust-random/getrandom\",\"repository\":{\"Http\":{\"sha256\":\"0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555\",\"url\":\"https://static.crates.io/crates/getrandom/0.4.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"getrandom\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.4.2\"},\"gimli 0.32.3\":{\"common_attrs\":{\"crate_features\":[\"read\",\"read-core\"],\"edition\":\"2018\"},\"library_target_name\":\"gimli\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"gimli\",\"package_url\":\"https://github.com/gimli-rs/gimli\",\"repository\":{\"Http\":{\"sha256\":\"e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7\",\"url\":\"https://static.crates.io/crates/gimli/0.32.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"gimli\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.32.3\"},\"gimli 0.33.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"endian-reader\",\"read\",\"read-all\",\"read-core\",\"std\",\"write\"],\"deps\":[{\"id\":\"fnv 1.0.7\",\"target\":\"fnv\"},{\"id\":\"hashbrown 0.16.1\",\"target\":\"hashbrown\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"stable_deref_trait 1.2.1\",\"target\":\"stable_deref_trait\"}],\"edition\":\"2024\"},\"library_target_name\":\"gimli\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"gimli\",\"package_url\":\"https://github.com/gimli-rs/gimli\",\"repository\":{\"Http\":{\"sha256\":\"0bf7f043f89559805f8c7cacc432749b2fa0d0a0a9ee46ce47164ed5ba7f126c\",\"url\":\"https://static.crates.io/crates/gimli/0.33.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"gimli\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.33.0\"},\"glob 0.3.3\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"glob\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"glob\",\"package_url\":\"https://github.com/rust-lang/glob\",\"repository\":{\"Http\":{\"sha256\":\"0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280\",\"url\":\"https://static.crates.io/crates/glob/0.3.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"glob\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.3\"},\"globset 0.4.18\":{\"common_attrs\":{\"crate_features\":[\"default\",\"log\"],\"deps\":[{\"id\":\"aho-corasick 1.1.4\",\"target\":\"aho_corasick\"},{\"id\":\"bstr 1.12.1\",\"target\":\"bstr\"},{\"id\":\"log 0.4.29\",\"target\":\"log\"},{\"id\":\"regex-automata 0.4.14\",\"target\":\"regex_automata\"},{\"id\":\"regex-syntax 0.8.10\",\"target\":\"regex_syntax\"}],\"edition\":\"2024\"},\"library_target_name\":\"globset\",\"license\":\"Unlicense OR MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"globset\",\"package_url\":\"https://github.com/BurntSushi/ripgrep/tree/master/crates/globset\",\"repository\":{\"Http\":{\"sha256\":\"52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3\",\"url\":\"https://static.crates.io/crates/globset/0.4.18/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"globset\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.18\"},\"half 2.7.1\":{\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"zerocopy 0.8.48\",\"target\":\"zerocopy\"}],\"selects\":{\"cfg(target_arch = \\\"spirv\\\")\":[{\"id\":\"crunchy 0.2.4\",\"target\":\"crunchy\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"half\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"half\",\"package_url\":\"https://github.com/VoidStarKat/half-rs\",\"repository\":{\"Http\":{\"sha256\":\"6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b\",\"url\":\"https://static.crates.io/crates/half/2.7.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"half\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.7.1\"},\"hash32 0.3.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"byteorder 1.5.0\",\"target\":\"byteorder\"}],\"edition\":\"2015\"},\"library_target_name\":\"hash32\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"hash32\",\"package_url\":\"https://github.com/japaric/hash32\",\"repository\":{\"Http\":{\"sha256\":\"47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606\",\"url\":\"https://static.crates.io/crates/hash32/0.3.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hash32\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.1\"},\"hashbrown 0.14.5\":{\"common_attrs\":{\"crate_features\":[\"raw\"],\"edition\":\"2021\"},\"library_target_name\":\"hashbrown\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"hashbrown\",\"package_url\":\"https://github.com/rust-lang/hashbrown\",\"repository\":{\"Http\":{\"sha256\":\"e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1\",\"url\":\"https://static.crates.io/crates/hashbrown/0.14.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hashbrown\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.14.5\"},\"hashbrown 0.15.5\":{\"common_attrs\":{\"crate_features\":[\"default-hasher\",\"inline-more\"],\"deps\":[{\"id\":\"foldhash 0.1.5\",\"target\":\"foldhash\"}],\"edition\":\"2021\"},\"library_target_name\":\"hashbrown\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"hashbrown\",\"package_url\":\"https://github.com/rust-lang/hashbrown\",\"repository\":{\"Http\":{\"sha256\":\"9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1\",\"url\":\"https://static.crates.io/crates/hashbrown/0.15.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hashbrown\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.15.5\"},\"hashbrown 0.16.1\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"hashbrown\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"hashbrown\",\"package_url\":\"https://github.com/rust-lang/hashbrown\",\"repository\":{\"Http\":{\"sha256\":\"841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100\",\"url\":\"https://static.crates.io/crates/hashbrown/0.16.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hashbrown\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.16.1\"},\"hashbrown 0.17.0\":{\"common_attrs\":{\"crate_features\":[\"default-hasher\"],\"deps\":[{\"id\":\"foldhash 0.2.0\",\"target\":\"foldhash\"}],\"edition\":\"2024\"},\"library_target_name\":\"hashbrown\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"hashbrown\",\"package_url\":\"https://github.com/rust-lang/hashbrown\",\"repository\":{\"Http\":{\"sha256\":\"4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51\",\"url\":\"https://static.crates.io/crates/hashbrown/0.17.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hashbrown\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.17.0\"},\"heapless 0.9.2\":{\"build_script_attrs\":{},\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"hash32 0.3.1\",\"target\":\"hash32\"}],\"selects\":{\"cfg(any(target_arch = \\\"arm\\\", target_pointer_width = \\\"32\\\", target_pointer_width = \\\"64\\\"))\":[{\"id\":\"stable_deref_trait 1.2.1\",\"target\":\"stable_deref_trait\"}]}},\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"heapless\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"heapless\",\"package_url\":\"https://github.com/rust-embedded/heapless\",\"repository\":{\"Http\":{\"sha256\":\"2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed\",\"url\":\"https://static.crates.io/crates/heapless/0.9.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"heapless\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.9.2\"},\"heck 0.3.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"unicode-segmentation 1.13.2\",\"target\":\"unicode_segmentation\"}],\"edition\":\"2018\"},\"library_target_name\":\"heck\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"heck\",\"package_url\":\"https://github.com/withoutboats/heck\",\"repository\":{\"Http\":{\"sha256\":\"6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c\",\"url\":\"https://static.crates.io/crates/heck/0.3.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"heck\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.3\"},\"heck 0.5.0\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"heck\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"heck\",\"package_url\":\"https://github.com/withoutboats/heck\",\"repository\":{\"Http\":{\"sha256\":\"2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea\",\"url\":\"https://static.crates.io/crates/heck/0.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"heck\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.0\"},\"hermit-abi 0.5.2\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"hermit_abi\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"hermit-abi\",\"package_url\":\"https://github.com/hermit-os/hermit-rs\",\"repository\":{\"Http\":{\"sha256\":\"fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c\",\"url\":\"https://static.crates.io/crates/hermit-abi/0.5.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hermit_abi\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.2\"},\"hex 0.4.3\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"hex\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"hex\",\"package_url\":\"https://github.com/KokaKiwi/rust-hex\",\"repository\":{\"Http\":{\"sha256\":\"7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70\",\"url\":\"https://static.crates.io/crates/hex/0.4.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hex\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.3\"},\"http 1.4.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"itoa 1.0.18\",\"target\":\"itoa\"}],\"edition\":\"2021\"},\"library_target_name\":\"http\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"http\",\"package_url\":\"https://github.com/hyperium/http\",\"repository\":{\"Http\":{\"sha256\":\"e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a\",\"url\":\"https://static.crates.io/crates/http/1.4.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"http\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.4.0\"},\"hybrid-array 0.4.10\":{\"common_attrs\":{\"deps\":[{\"id\":\"typenum 1.20.0\",\"target\":\"typenum\"}],\"edition\":\"2024\"},\"library_target_name\":\"hybrid_array\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"hybrid-array\",\"package_url\":\"https://github.com/RustCrypto/hybrid-array\",\"repository\":{\"Http\":{\"sha256\":\"3944cf8cf766b40e2a1a333ee5e9b563f854d5fa49d6a8ca2764e97c6eddb214\",\"url\":\"https://static.crates.io/crates/hybrid-array/0.4.10/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hybrid_array\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.10\"},\"icu_collections 2.2.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"potential_utf 0.1.5\",\"target\":\"potential_utf\"},{\"id\":\"utf8_iter 1.0.4\",\"target\":\"utf8_iter\"},{\"id\":\"yoke 0.8.2\",\"target\":\"yoke\"},{\"id\":\"zerofrom 0.1.7\",\"target\":\"zerofrom\"},{\"id\":\"zerovec 0.11.6\",\"target\":\"zerovec\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"displaydoc 0.2.5\",\"target\":\"displaydoc\"}]},\"library_target_name\":\"icu_collections\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_collections\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c\",\"url\":\"https://static.crates.io/crates/icu_collections/2.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"icu_collections\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.2.0\"},\"icu_locale_core 2.2.0\":{\"common_attrs\":{\"crate_features\":[\"zerovec\"],\"deps\":[{\"id\":\"litemap 0.8.2\",\"target\":\"litemap\"},{\"id\":\"tinystr 0.8.3\",\"target\":\"tinystr\"},{\"id\":\"writeable 0.6.3\",\"target\":\"writeable\"},{\"id\":\"zerovec 0.11.6\",\"target\":\"zerovec\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"displaydoc 0.2.5\",\"target\":\"displaydoc\"}]},\"library_target_name\":\"icu_locale_core\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_locale_core\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29\",\"url\":\"https://static.crates.io/crates/icu_locale_core/2.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"icu_locale_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.2.0\"},\"icu_normalizer 2.2.0\":{\"common_attrs\":{\"crate_features\":[\"compiled_data\"],\"deps\":[{\"id\":\"icu_collections 2.2.0\",\"target\":\"icu_collections\"},{\"id\":\"icu_normalizer_data 2.2.0\",\"target\":\"icu_normalizer_data\"},{\"id\":\"icu_provider 2.2.0\",\"target\":\"icu_provider\"},{\"id\":\"smallvec 1.15.1\",\"target\":\"smallvec\"},{\"id\":\"zerovec 0.11.6\",\"target\":\"zerovec\"}],\"edition\":\"2021\"},\"library_target_name\":\"icu_normalizer\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_normalizer\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4\",\"url\":\"https://static.crates.io/crates/icu_normalizer/2.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"icu_normalizer\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.2.0\"},\"icu_normalizer_data 2.2.0\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"icu_normalizer_data\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_normalizer_data\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38\",\"url\":\"https://static.crates.io/crates/icu_normalizer_data/2.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"icu_normalizer_data\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"2.2.0\"},\"icu_properties 2.2.0\":{\"common_attrs\":{\"crate_features\":[\"compiled_data\"],\"deps\":[{\"id\":\"icu_collections 2.2.0\",\"target\":\"icu_collections\"},{\"id\":\"icu_locale_core 2.2.0\",\"target\":\"icu_locale_core\"},{\"id\":\"icu_properties_data 2.2.0\",\"target\":\"icu_properties_data\"},{\"id\":\"icu_provider 2.2.0\",\"target\":\"icu_provider\"},{\"id\":\"zerotrie 0.2.4\",\"target\":\"zerotrie\"},{\"id\":\"zerovec 0.11.6\",\"target\":\"zerovec\"}],\"edition\":\"2021\"},\"library_target_name\":\"icu_properties\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_properties\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de\",\"url\":\"https://static.crates.io/crates/icu_properties/2.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"icu_properties\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.2.0\"},\"icu_properties_data 2.2.0\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"icu_properties_data\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_properties_data\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14\",\"url\":\"https://static.crates.io/crates/icu_properties_data/2.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"icu_properties_data\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"2.2.0\"},\"icu_provider 2.2.0\":{\"common_attrs\":{\"crate_features\":[\"baked\"],\"deps\":[{\"id\":\"icu_locale_core 2.2.0\",\"target\":\"icu_locale_core\"},{\"id\":\"writeable 0.6.3\",\"target\":\"writeable\"},{\"id\":\"yoke 0.8.2\",\"target\":\"yoke\"},{\"id\":\"zerofrom 0.1.7\",\"target\":\"zerofrom\"},{\"id\":\"zerotrie 0.2.4\",\"target\":\"zerotrie\"},{\"id\":\"zerovec 0.11.6\",\"target\":\"zerovec\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"displaydoc 0.2.5\",\"target\":\"displaydoc\"}]},\"library_target_name\":\"icu_provider\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_provider\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421\",\"url\":\"https://static.crates.io/crates/icu_provider/2.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"icu_provider\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.2.0\"},\"id-arena 2.3.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"id_arena\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"id-arena\",\"package_url\":\"https://github.com/fitzgen/id-arena\",\"repository\":{\"Http\":{\"sha256\":\"3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954\",\"url\":\"https://static.crates.io/crates/id-arena/2.3.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"id_arena\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.3.0\"},\"ident_case 1.0.1\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"ident_case\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"ident_case\",\"package_url\":\"https://github.com/TedDriggs/ident_case\",\"repository\":{\"Http\":{\"sha256\":\"b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39\",\"url\":\"https://static.crates.io/crates/ident_case/1.0.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ident_case\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.1\"},\"idna 1.1.0\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"compiled_data\",\"std\"],\"deps\":[{\"id\":\"idna_adapter 1.2.1\",\"target\":\"idna_adapter\"},{\"id\":\"smallvec 1.15.1\",\"target\":\"smallvec\"},{\"id\":\"utf8_iter 1.0.4\",\"target\":\"utf8_iter\"}],\"edition\":\"2018\"},\"library_target_name\":\"idna\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"idna\",\"package_url\":\"https://github.com/servo/rust-url/\",\"repository\":{\"Http\":{\"sha256\":\"3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de\",\"url\":\"https://static.crates.io/crates/idna/1.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"idna\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.0\"},\"idna_adapter 1.2.1\":{\"common_attrs\":{\"crate_features\":[\"compiled_data\"],\"deps\":[{\"id\":\"icu_normalizer 2.2.0\",\"target\":\"icu_normalizer\"},{\"id\":\"icu_properties 2.2.0\",\"target\":\"icu_properties\"}],\"edition\":\"2021\"},\"library_target_name\":\"idna_adapter\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"idna_adapter\",\"package_url\":\"https://github.com/hsivonen/idna_adapter\",\"repository\":{\"Http\":{\"sha256\":\"3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344\",\"url\":\"https://static.crates.io/crates/idna_adapter/1.2.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"idna_adapter\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.1\"},\"ignore 0.4.25\":{\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"crossbeam-deque 0.8.6\",\"target\":\"crossbeam_deque\"},{\"id\":\"globset 0.4.18\",\"target\":\"globset\"},{\"id\":\"log 0.4.29\",\"target\":\"log\"},{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"},{\"id\":\"regex-automata 0.4.14\",\"target\":\"regex_automata\"},{\"id\":\"same-file 1.0.6\",\"target\":\"same_file\"},{\"id\":\"walkdir 2.5.0\",\"target\":\"walkdir\"}],\"selects\":{\"cfg(windows)\":[{\"id\":\"winapi-util 0.1.11\",\"target\":\"winapi_util\"}]}},\"edition\":\"2024\"},\"library_target_name\":\"ignore\",\"license\":\"Unlicense OR MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"ignore\",\"package_url\":\"https://github.com/BurntSushi/ripgrep/tree/master/crates/ignore\",\"repository\":{\"Http\":{\"sha256\":\"d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a\",\"url\":\"https://static.crates.io/crates/ignore/0.4.25/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ignore\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.25\"},\"indexmap 2.14.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"serde\",\"std\"],\"deps\":[{\"id\":\"equivalent 1.0.2\",\"target\":\"equivalent\"},{\"id\":\"hashbrown 0.17.0\",\"target\":\"hashbrown\"},{\"id\":\"serde_core 1.0.228\",\"target\":\"serde_core\"}],\"edition\":\"2024\"},\"library_target_name\":\"indexmap\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"indexmap\",\"package_url\":\"https://github.com/indexmap-rs/indexmap\",\"repository\":{\"Http\":{\"sha256\":\"d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9\",\"url\":\"https://static.crates.io/crates/indexmap/2.14.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"indexmap\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.14.0\"},\"insta 1.47.2\":{\"common_attrs\":{\"crate_features\":[\"colors\",\"console\",\"default\",\"filters\",\"regex\",\"serde\",\"yaml\"],\"deps\":[{\"id\":\"console 0.16.3\",\"target\":\"console\"},{\"id\":\"once_cell 1.21.4\",\"target\":\"once_cell\"},{\"id\":\"regex 1.12.3\",\"target\":\"regex\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"similar 2.7.0\",\"target\":\"similar\"},{\"id\":\"tempfile 3.27.0\",\"target\":\"tempfile\"}],\"edition\":\"2021\"},\"library_target_name\":\"insta\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"insta\",\"package_url\":\"https://github.com/mitsuhiko/insta\",\"repository\":{\"Http\":{\"sha256\":\"7b4a6248eb93a4401ed2f37dfe8ea592d3cf05b7cf4f8efa867b6895af7e094e\",\"url\":\"https://static.crates.io/crates/insta/1.47.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"insta\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.47.2\"},\"ipnet 2.12.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"ipnet\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"ipnet\",\"package_url\":\"https://github.com/krisprice/ipnet\",\"repository\":{\"Http\":{\"sha256\":\"d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2\",\"url\":\"https://static.crates.io/crates/ipnet/2.12.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ipnet\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.12.0\"},\"iprange 0.6.7\":{\"common_attrs\":{\"deps\":[{\"id\":\"ipnet 2.12.0\",\"target\":\"ipnet\"}],\"edition\":\"2015\"},\"library_target_name\":\"iprange\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"iprange\",\"package_url\":\"https://github.com/sticnarf/iprange-rs\",\"repository\":{\"Http\":{\"sha256\":\"37209be0ad225457e63814401415e748e2453a5297f9b637338f5fb8afa4ec00\",\"url\":\"https://static.crates.io/crates/iprange/0.6.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"iprange\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.7\"},\"itertools 0.13.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"either 1.15.0\",\"target\":\"either\"}],\"edition\":\"2018\"},\"library_target_name\":\"itertools\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"itertools\",\"package_url\":\"https://github.com/rust-itertools/itertools\",\"repository\":{\"Http\":{\"sha256\":\"413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186\",\"url\":\"https://static.crates.io/crates/itertools/0.13.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"itertools\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.13.0\"},\"itertools 0.14.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"use_alloc\",\"use_std\"],\"deps\":[{\"id\":\"either 1.15.0\",\"target\":\"either\"}],\"edition\":\"2018\"},\"library_target_name\":\"itertools\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"itertools\",\"package_url\":\"https://github.com/rust-itertools/itertools\",\"repository\":{\"Http\":{\"sha256\":\"2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285\",\"url\":\"https://static.crates.io/crates/itertools/0.14.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"itertools\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.14.0\"},\"itoa 1.0.18\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"itoa\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"itoa\",\"package_url\":\"https://github.com/dtolnay/itoa\",\"repository\":{\"Http\":{\"sha256\":\"8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682\",\"url\":\"https://static.crates.io/crates/itoa/1.0.18/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"itoa\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.18\"},\"jobserver 0.1.34\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(unix)\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(windows)\":[{\"id\":\"getrandom 0.3.4\",\"target\":\"getrandom\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"jobserver\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"jobserver\",\"package_url\":\"https://github.com/rust-lang/jobserver-rs\",\"repository\":{\"Http\":{\"sha256\":\"9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33\",\"url\":\"https://static.crates.io/crates/jobserver/0.1.34/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"jobserver\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.34\"},\"js-sys 0.3.95\":{\"common_attrs\":{\"deps\":[{\"id\":\"once_cell 1.21.4\",\"target\":\"once_cell\"},{\"id\":\"wasm-bindgen 0.2.118\",\"target\":\"wasm_bindgen\"}],\"edition\":\"2021\"},\"library_target_name\":\"js_sys\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"js-sys\",\"package_url\":\"https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/js-sys\",\"repository\":{\"Http\":{\"sha256\":\"2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca\",\"url\":\"https://static.crates.io/crates/js-sys/0.3.95/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"js_sys\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.95\"},\"leb128 0.2.6\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"leb128\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"leb128\",\"package_url\":\"https://github.com/gimli-rs/leb128\",\"repository\":{\"Http\":{\"sha256\":\"6cc46bac87ef8093eed6f272babb833b6443374399985ac8ed28471ee0918545\",\"url\":\"https://static.crates.io/crates/leb128/0.2.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"leb128\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.6\"},\"leb128fmt 0.1.0\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"leb128fmt\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"leb128fmt\",\"package_url\":\"https://github.com/bluk/leb128fmt\",\"repository\":{\"Http\":{\"sha256\":\"09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2\",\"url\":\"https://static.crates.io/crates/leb128fmt/0.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"leb128fmt\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.0\"},\"lexical-sort 0.3.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"any_ascii 0.1.7\",\"target\":\"any_ascii\"}],\"edition\":\"2018\"},\"library_target_name\":\"lexical_sort\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"lexical-sort\",\"package_url\":\"https://github.com/Aloso/lexical-sort\",\"repository\":{\"Http\":{\"sha256\":\"c09e4591611e231daf4d4c685a66cb0410cc1e502027a20ae55f2bb9e997207a\",\"url\":\"https://static.crates.io/crates/lexical-sort/0.3.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"lexical_sort\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.1\"},\"libc 0.2.186\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"libc\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"libc\",\"package_url\":\"https://github.com/rust-lang/libc\",\"repository\":{\"Http\":{\"sha256\":\"68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66\",\"url\":\"https://static.crates.io/crates/libc/0.2.186/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"libc\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.2.186\"},\"libloading 0.8.9\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(unix)\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"}],\"cfg(windows)\":[{\"id\":\"windows-link 0.2.1\",\"target\":\"windows_link\"}]}},\"edition\":\"2015\"},\"library_target_name\":\"libloading\",\"license\":\"ISC\",\"license_file\":\"LICENSE\",\"license_ids\":[\"ISC\"],\"name\":\"libloading\",\"package_url\":\"https://github.com/nagisa/rust_libloading/\",\"repository\":{\"Http\":{\"sha256\":\"d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55\",\"url\":\"https://static.crates.io/crates/libloading/0.8.9/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"libloading\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.9\"},\"libredox 0.1.16\":{\"common_attrs\":{\"deps\":[{\"id\":\"redox_syscall 0.7.4\",\"target\":\"syscall\"}],\"edition\":\"2021\"},\"library_target_name\":\"libredox\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"libredox\",\"package_url\":\"https://gitlab.redox-os.org/redox-os/libredox.git\",\"repository\":{\"Http\":{\"sha256\":\"e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c\",\"url\":\"https://static.crates.io/crates/libredox/0.1.16/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"libredox\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.16\"},\"libunwind 1.3.3\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"libunwind\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"libunwind\",\"package_url\":\"https://github.com/bluefish43/libunwind-sys\",\"repository\":{\"Http\":{\"sha256\":\"0c6639b70a7ce854b79c70d7e83f16b5dc0137cc914f3d7d03803b513ecc67ac\",\"url\":\"https://static.crates.io/crates/libunwind/1.3.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"libunwind\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.3.3\"},\"linked-hash-map 0.5.6\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"linked_hash_map\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"linked-hash-map\",\"package_url\":\"https://github.com/contain-rs/linked-hash-map\",\"repository\":{\"Http\":{\"sha256\":\"0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f\",\"url\":\"https://static.crates.io/crates/linked-hash-map/0.5.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"linked_hash_map\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.6\"},\"linked_hash_set 0.1.6\":{\"common_attrs\":{\"deps\":[{\"id\":\"linked-hash-map 0.5.6\",\"target\":\"linked_hash_map\"}],\"edition\":\"2024\"},\"library_target_name\":\"linked_hash_set\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"linked_hash_set\",\"package_url\":\"https://github.com/alexheretic/linked-hash-set\",\"repository\":{\"Http\":{\"sha256\":\"984fb35d06508d1e69fc91050cceba9c0b748f983e6739fa2c7a9237154c52c8\",\"url\":\"https://static.crates.io/crates/linked_hash_set/0.1.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"linked_hash_set\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.6\"},\"linux-raw-sys 0.12.1\":{\"common_attrs\":{\"crate_features\":[\"auxvec\",\"elf\",\"errno\",\"general\",\"ioctl\",\"no_std\"],\"edition\":\"2021\"},\"library_target_name\":\"linux_raw_sys\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"linux-raw-sys\",\"package_url\":\"https://github.com/sunfishcode/linux-raw-sys\",\"repository\":{\"Http\":{\"sha256\":\"32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53\",\"url\":\"https://static.crates.io/crates/linux-raw-sys/0.12.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"linux_raw_sys\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.12.1\"},\"litemap 0.8.2\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"litemap\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"litemap\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0\",\"url\":\"https://static.crates.io/crates/litemap/0.8.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"litemap\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.2\"},\"litrs 1.0.0\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"litrs\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"litrs\",\"package_url\":\"https://github.com/LukasKalbertodt/litrs\",\"repository\":{\"Http\":{\"sha256\":\"11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092\",\"url\":\"https://static.crates.io/crates/litrs/1.0.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"litrs\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.0\"},\"lock_api 0.4.14\":{\"common_attrs\":{\"crate_features\":[\"atomic_usize\",\"default\"],\"deps\":[{\"id\":\"scopeguard 1.2.0\",\"target\":\"scopeguard\"}],\"edition\":\"2021\"},\"library_target_name\":\"lock_api\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"lock_api\",\"package_url\":\"https://github.com/Amanieu/parking_lot\",\"repository\":{\"Http\":{\"sha256\":\"224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965\",\"url\":\"https://static.crates.io/crates/lock_api/0.4.14/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"lock_api\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.14\"},\"log 0.4.29\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"log\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"log\",\"package_url\":\"https://github.com/rust-lang/log\",\"repository\":{\"Http\":{\"sha256\":\"5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897\",\"url\":\"https://static.crates.io/crates/log/0.4.29/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"log\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.29\"},\"lz4_flex 0.13.0\":{\"common_attrs\":{\"crate_features\":[\"checked-decode\",\"default\",\"frame\",\"safe-decode\",\"safe-encode\",\"std\"],\"deps\":[{\"id\":\"twox-hash 2.1.2\",\"target\":\"twox_hash\"}],\"edition\":\"2021\"},\"library_target_name\":\"lz4_flex\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"lz4_flex\",\"package_url\":\"https://github.com/pseitz/lz4_flex\",\"repository\":{\"Http\":{\"sha256\":\"db9a0d582c2874f68138a16ce1867e0ffde6c0bb0a0df85e1f36d04146db488a\",\"url\":\"https://static.crates.io/crates/lz4_flex/0.13.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"lz4_flex\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.13.0\"},\"mach2 0.4.3\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"deps\":{\"common\":[],\"selects\":{\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"ios\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}]}},\"edition\":\"2015\"},\"library_target_name\":\"mach2\",\"license\":\"BSD-2-Clause OR MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"BSD-2-Clause\",\"MIT\"],\"name\":\"mach2\",\"package_url\":\"https://github.com/JohnTitor/mach2\",\"repository\":{\"Http\":{\"sha256\":\"d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44\",\"url\":\"https://static.crates.io/crates/mach2/0.4.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"mach2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.3\"},\"mach2 0.6.0\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"edition\":\"2024\"},\"library_target_name\":\"mach2\",\"license\":\"BSD-2-Clause OR MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"BSD-2-Clause\",\"MIT\"],\"name\":\"mach2\",\"package_url\":\"https://github.com/JohnTitor/mach2\",\"repository\":{\"Http\":{\"sha256\":\"dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b\",\"url\":\"https://static.crates.io/crates/mach2/0.6.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"mach2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.0\"},\"macho-unwind-info 0.5.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"zerocopy 0.8.48\",\"target\":\"zerocopy\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"zerocopy-derive 0.8.48\",\"target\":\"zerocopy_derive\"}]},\"library_target_name\":\"macho_unwind_info\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"macho-unwind-info\",\"package_url\":\"https://github.com/mstange/macho-unwind-info\",\"repository\":{\"Http\":{\"sha256\":\"bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149\",\"url\":\"https://static.crates.io/crates/macho-unwind-info/0.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"macho_unwind_info\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.0\"},\"managed 0.8.0\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"map\",\"std\"],\"edition\":\"2015\"},\"library_target_name\":\"managed\",\"license\":\"0BSD\",\"license_file\":\"LICENSE-0BSD.txt\",\"license_ids\":[\"0BSD\"],\"name\":\"managed\",\"package_url\":\"https://github.com/m-labs/rust-managed.git\",\"repository\":{\"Http\":{\"sha256\":\"0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d\",\"url\":\"https://static.crates.io/crates/managed/0.8.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"managed\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.0\"},\"memchr 2.8.0\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"memchr\",\"license\":\"Unlicense OR MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"memchr\",\"package_url\":\"https://github.com/BurntSushi/memchr\",\"repository\":{\"Http\":{\"sha256\":\"f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79\",\"url\":\"https://static.crates.io/crates/memchr/2.8.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"memchr\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.8.0\"},\"memmap2 0.6.2\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(unix)\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"memmap2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"memmap2\",\"package_url\":\"https://github.com/RazrFalcon/memmap2-rs\",\"repository\":{\"Http\":{\"sha256\":\"6d28bba84adfe6646737845bc5ebbfa2c08424eb1c37e94a1fd2a82adb56a872\",\"url\":\"https://static.crates.io/crates/memmap2/0.6.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"memmap2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.2\"},\"memmap2 0.9.10\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(unix)\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"memmap2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"memmap2\",\"package_url\":\"https://github.com/RazrFalcon/memmap2-rs\",\"repository\":{\"Http\":{\"sha256\":\"714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3\",\"url\":\"https://static.crates.io/crates/memmap2/0.9.10/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"memmap2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.9.10\"},\"memoffset 0.9.1\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"autocfg 1.5.0\",\"target\":\"autocfg\"}]},\"common_attrs\":{\"crate_features\":[\"default\"],\"edition\":\"2015\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"memoffset\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"memoffset\",\"package_url\":\"https://github.com/Gilnaa/memoffset\",\"repository\":{\"Http\":{\"sha256\":\"488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a\",\"url\":\"https://static.crates.io/crates/memoffset/0.9.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"memoffset\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.9.1\"},\"minimal-lexical 0.2.1\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"minimal_lexical\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"minimal-lexical\",\"package_url\":\"https://github.com/Alexhuszagh/minimal-lexical\",\"repository\":{\"Http\":{\"sha256\":\"68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a\",\"url\":\"https://static.crates.io/crates/minimal-lexical/0.2.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"minimal_lexical\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.1\"},\"miniz_oxide 0.8.9\":{\"common_attrs\":{\"crate_features\":[\"simd\",\"simd-adler32\",\"with-alloc\"],\"deps\":[{\"id\":\"adler2 2.0.1\",\"target\":\"adler2\"},{\"id\":\"simd-adler32 0.3.9\",\"target\":\"simd_adler32\"}],\"edition\":\"2021\"},\"library_target_name\":\"miniz_oxide\",\"license\":\"MIT OR Zlib OR Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\",\"MIT\",\"Zlib\"],\"name\":\"miniz_oxide\",\"package_url\":\"https://github.com/Frommi/miniz_oxide/tree/master/miniz_oxide\",\"repository\":{\"Http\":{\"sha256\":\"1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316\",\"url\":\"https://static.crates.io/crates/miniz_oxide/0.8.9/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"miniz_oxide\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.9\"},\"mio 1.2.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"log\",\"net\",\"os-ext\",\"os-poll\"],\"deps\":{\"common\":[{\"id\":\"log 0.4.29\",\"target\":\"log\"}],\"selects\":{\"cfg(any(unix, target_os = \\\"hermit\\\", target_os = \\\"wasi\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(target_os = \\\"wasi\\\")\":[{\"id\":\"wasi 0.11.1+wasi-snapshot-preview1\",\"target\":\"wasi\"}],\"cfg(windows)\":[{\"id\":\"windows-sys 0.61.2\",\"target\":\"windows_sys\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"mio\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"mio\",\"package_url\":\"https://github.com/tokio-rs/mio\",\"repository\":{\"Http\":{\"sha256\":\"50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1\",\"url\":\"https://static.crates.io/crates/mio/1.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"mio\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.0\"},\"more-asserts 0.3.1\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"more_asserts\",\"license\":\"Unlicense OR MIT OR Apache-2.0 OR CC0-1.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"CC0-1.0\",\"MIT\",\"Unlicense\"],\"name\":\"more-asserts\",\"package_url\":\"https://github.com/thomcc/rust-more-asserts\",\"repository\":{\"Http\":{\"sha256\":\"1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e\",\"url\":\"https://static.crates.io/crates/more-asserts/0.3.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"more_asserts\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.1\"},\"msvc-demangler 0.11.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"bitflags 2.11.1\",\"target\":\"bitflags\"},{\"id\":\"itoa 1.0.18\",\"target\":\"itoa\"}],\"edition\":\"2021\"},\"library_target_name\":\"msvc_demangler\",\"license\":\"MIT/NCSA\",\"license_file\":\"LICENSE.LLVM\",\"license_ids\":[\"MIT\",\"NCSA\"],\"name\":\"msvc-demangler\",\"package_url\":\"https://github.com/mstange/msvc-demangler-rust\",\"repository\":{\"Http\":{\"sha256\":\"fbeff6bd154a309b2ada5639b2661ca6ae4599b34e8487dc276d2cd637da2d76\",\"url\":\"https://static.crates.io/crates/msvc-demangler/0.11.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"msvc_demangler\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.11.0\"},\"munge 0.4.7\":{\"common_attrs\":{\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"munge_macro 0.4.7\",\"target\":\"munge_macro\"}]},\"library_target_name\":\"munge\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"munge\",\"package_url\":\"https://github.com/djkoloski/munge\",\"repository\":{\"Http\":{\"sha256\":\"5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c\",\"url\":\"https://static.crates.io/crates/munge/0.4.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"munge\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.7\"},\"munge_macro 0.4.7\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"munge_macro\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"munge_macro\",\"package_url\":\"https://github.com/djkoloski/munge\",\"repository\":{\"Http\":{\"sha256\":\"4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931\",\"url\":\"https://static.crates.io/crates/munge_macro/0.4.7/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"munge_macro\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.7\"},\"nom 5.1.3\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"version_check 0.9.5\",\"target\":\"version_check\"}]},\"common_attrs\":{\"deps\":[{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"}],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"nom\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"nom\",\"package_url\":\"https://github.com/Geal/nom\",\"repository\":{\"Http\":{\"sha256\":\"08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b\",\"url\":\"https://static.crates.io/crates/nom/5.1.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"nom\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"5.1.3\"},\"nom 7.1.3\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"std\"],\"deps\":[{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"},{\"id\":\"minimal-lexical 0.2.1\",\"target\":\"minimal_lexical\"}],\"edition\":\"2018\"},\"library_target_name\":\"nom\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"nom\",\"package_url\":\"https://github.com/Geal/nom\",\"repository\":{\"Http\":{\"sha256\":\"d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a\",\"url\":\"https://static.crates.io/crates/nom/7.1.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"nom\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"7.1.3\"},\"num-conv 0.2.1\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"num_conv\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-Apache\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"num-conv\",\"package_url\":\"https://github.com/jhpratt/num-conv\",\"repository\":{\"Http\":{\"sha256\":\"c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967\",\"url\":\"https://static.crates.io/crates/num-conv/0.2.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"num_conv\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.1\"},\"num-traits 0.2.19\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"autocfg 1.5.0\",\"target\":\"autocfg\"}]},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"num_traits\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"num-traits\",\"package_url\":\"https://github.com/rust-num/num-traits\",\"repository\":{\"Http\":{\"sha256\":\"071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841\",\"url\":\"https://static.crates.io/crates/num-traits/0.2.19/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"num_traits\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.2.19\"},\"num_cpus 1.17.0\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(not(windows))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(target_os = \\\"hermit\\\")\":[{\"id\":\"hermit-abi 0.5.2\",\"target\":\"hermit_abi\"}]}},\"edition\":\"2015\"},\"library_target_name\":\"num_cpus\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"num_cpus\",\"package_url\":\"https://github.com/seanmonstar/num_cpus\",\"repository\":{\"Http\":{\"sha256\":\"91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b\",\"url\":\"https://static.crates.io/crates/num_cpus/1.17.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"num_cpus\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.17.0\"},\"num_enum 0.7.6\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"num_enum_derive 0.7.6\",\"target\":\"num_enum_derive\"},{\"id\":\"rustversion 1.0.22\",\"target\":\"rustversion\"}]},\"library_target_name\":\"num_enum\",\"license\":\"BSD-3-Clause OR MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"BSD-3-Clause\",\"MIT\"],\"name\":\"num_enum\",\"package_url\":\"https://github.com/illicitonion/num_enum\",\"repository\":{\"Http\":{\"sha256\":\"5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26\",\"url\":\"https://static.crates.io/crates/num_enum/0.7.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"num_enum\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.6\"},\"num_enum_derive 0.7.6\":{\"common_attrs\":{\"crate_features\":[\"proc-macro-crate\",\"std\"],\"deps\":[{\"id\":\"proc-macro-crate 3.5.0\",\"target\":\"proc_macro_crate\"},{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"num_enum_derive\",\"license\":\"BSD-3-Clause OR MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"BSD-3-Clause\",\"MIT\"],\"name\":\"num_enum_derive\",\"package_url\":\"https://github.com/illicitonion/num_enum\",\"repository\":{\"Http\":{\"sha256\":\"680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8\",\"url\":\"https://static.crates.io/crates/num_enum_derive/0.7.6/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"num_enum_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.6\"},\"object 0.37.3\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"archive\",\"coff\",\"elf\",\"macho\",\"pe\",\"read_core\",\"unaligned\",\"xcoff\"],\"deps\":[{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"}],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"object\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"object\",\"package_url\":\"https://github.com/gimli-rs/object\",\"repository\":{\"Http\":{\"sha256\":\"ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe\",\"url\":\"https://static.crates.io/crates/object/0.37.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"object\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.37.3\"},\"object 0.39.1\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"archive\",\"coff\",\"compression\",\"default\",\"elf\",\"macho\",\"pe\",\"read\",\"read_core\",\"std\",\"write\",\"write_core\",\"write_std\",\"xcoff\"],\"deps\":[{\"id\":\"crc32fast 1.5.0\",\"target\":\"crc32fast\"},{\"id\":\"flate2 1.1.9\",\"target\":\"flate2\"},{\"id\":\"hashbrown 0.17.0\",\"target\":\"hashbrown\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"},{\"id\":\"ruzstd 0.8.2\",\"target\":\"ruzstd\"}],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"object\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"object\",\"package_url\":\"https://github.com/gimli-rs/object\",\"repository\":{\"Http\":{\"sha256\":\"2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b\",\"url\":\"https://static.crates.io/crates/object/0.39.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"object\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.39.1\"},\"oliphaunt-wasix-postmaster-executor 7.2.0-alpha.2\":{\"common_attrs\":{\"crate_features\":[\"default\",\"memory-profile-core\",\"product-executor\"],\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"hex 0.4.3\",\"target\":\"hex\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.149\",\"target\":\"serde_json\"},{\"id\":\"sha2 0.11.0\",\"target\":\"sha2\"},{\"id\":\"tempfile 3.27.0\",\"target\":\"tempfile\"},{\"id\":\"tokio 1.52.1\",\"target\":\"tokio\"},{\"id\":\"tracing 0.1.44\",\"target\":\"tracing\"},{\"id\":\"wasmer 7.2.0-alpha.2\",\"target\":\"wasmer\"},{\"id\":\"wasmer-types 7.2.0-alpha.2\",\"target\":\"wasmer_types\"},{\"id\":\"wasmer-vm 7.2.0-alpha.2\",\"target\":\"wasmer_vm\"},{\"id\":\"wasmer-wasix 0.702.0-alpha.2\",\"target\":\"wasmer_wasix\"}],\"deps_dev\":[{\"id\":\"futures 0.3.32\",\"target\":\"futures\"},{\"id\":\"wat 1.247.0\",\"target\":\"wat\"}],\"edition\":\"2024\",\"proc_macro_deps\":[{\"id\":\"async-trait 0.1.89\",\"target\":\"async_trait\"}]},\"library_target_name\":\"oliphaunt_wasix_postmaster_executor\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"oliphaunt-wasix-postmaster-executor\",\"package_url\":\"https://github.com/f0rr0/oliphaunt\",\"repository\":null,\"targets\":[{\"Library\":{\"crate_name\":\"oliphaunt_wasix_postmaster_executor\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"7.2.0-alpha.2\"},\"once_cell 1.21.4\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"race\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"once_cell\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"once_cell\",\"package_url\":\"https://github.com/matklad/once_cell\",\"repository\":{\"Http\":{\"sha256\":\"9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50\",\"url\":\"https://static.crates.io/crates/once_cell/1.21.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"once_cell\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.21.4\"},\"parking 2.2.1\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"parking\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"parking\",\"package_url\":\"https://github.com/smol-rs/parking\",\"repository\":{\"Http\":{\"sha256\":\"f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba\",\"url\":\"https://static.crates.io/crates/parking/2.2.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"parking\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.2.1\"},\"parking_lot 0.12.5\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"deps\":[{\"id\":\"lock_api 0.4.14\",\"target\":\"lock_api\"},{\"id\":\"parking_lot_core 0.9.12\",\"target\":\"parking_lot_core\"}],\"edition\":\"2021\"},\"library_target_name\":\"parking_lot\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"parking_lot\",\"package_url\":\"https://github.com/Amanieu/parking_lot\",\"repository\":{\"Http\":{\"sha256\":\"93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a\",\"url\":\"https://static.crates.io/crates/parking_lot/0.12.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"parking_lot\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.12.5\"},\"parking_lot_core 0.9.12\":{\"build_script_attrs\":{},\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"smallvec 1.15.1\",\"target\":\"smallvec\"}],\"selects\":{\"cfg(target_os = \\\"redox\\\")\":[{\"id\":\"redox_syscall 0.5.18\",\"target\":\"syscall\"}],\"cfg(unix)\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(windows)\":[{\"id\":\"windows-link 0.2.1\",\"target\":\"windows_link\"}]}},\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"parking_lot_core\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"parking_lot_core\",\"package_url\":\"https://github.com/Amanieu/parking_lot\",\"repository\":{\"Http\":{\"sha256\":\"2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1\",\"url\":\"https://static.crates.io/crates/parking_lot_core/0.9.12/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"parking_lot_core\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.9.12\"},\"paste 1.0.15\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"paste\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"paste\",\"package_url\":\"https://github.com/dtolnay/paste\",\"repository\":{\"Http\":{\"sha256\":\"57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a\",\"url\":\"https://static.crates.io/crates/paste/1.0.15/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"paste\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.15\"},\"path-clean 1.0.1\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"path_clean\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"path-clean\",\"package_url\":\"https://github.com/danreeves/path-clean\",\"repository\":{\"Http\":{\"sha256\":\"17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef\",\"url\":\"https://static.crates.io/crates/path-clean/1.0.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"path_clean\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.1\"},\"percent-encoding 2.3.2\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"percent_encoding\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"percent-encoding\",\"package_url\":\"https://github.com/servo/rust-url/\",\"repository\":{\"Http\":{\"sha256\":\"9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220\",\"url\":\"https://static.crates.io/crates/percent-encoding/2.3.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"percent_encoding\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.3.2\"},\"petgraph 0.8.3\":{\"common_attrs\":{\"crate_features\":[\"default\",\"graphmap\",\"matrix_graph\",\"stable_graph\",\"std\"],\"deps\":[{\"id\":\"fixedbitset 0.5.7\",\"target\":\"fixedbitset\"},{\"id\":\"hashbrown 0.15.5\",\"target\":\"hashbrown\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"}],\"edition\":\"2021\"},\"library_target_name\":\"petgraph\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"petgraph\",\"package_url\":\"https://github.com/petgraph/petgraph\",\"repository\":{\"Http\":{\"sha256\":\"8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455\",\"url\":\"https://static.crates.io/crates/petgraph/0.8.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"petgraph\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.3\"},\"pin-project 1.1.11\":{\"common_attrs\":{\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"pin-project-internal 1.1.11\",\"target\":\"pin_project_internal\"}]},\"library_target_name\":\"pin_project\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"pin-project\",\"package_url\":\"https://github.com/taiki-e/pin-project\",\"repository\":{\"Http\":{\"sha256\":\"f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517\",\"url\":\"https://static.crates.io/crates/pin-project/1.1.11/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"pin_project\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.11\"},\"pin-project-internal 1.1.11\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"pin_project_internal\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"pin-project-internal\",\"package_url\":\"https://github.com/taiki-e/pin-project\",\"repository\":{\"Http\":{\"sha256\":\"d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6\",\"url\":\"https://static.crates.io/crates/pin-project-internal/1.1.11/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"pin_project_internal\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.11\"},\"pin-project-lite 0.2.17\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"pin_project_lite\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"pin-project-lite\",\"package_url\":\"https://github.com/taiki-e/pin-project-lite\",\"repository\":{\"Http\":{\"sha256\":\"a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd\",\"url\":\"https://static.crates.io/crates/pin-project-lite/0.2.17/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"pin_project_lite\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.17\"},\"pin-utils 0.1.0\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"pin_utils\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"pin-utils\",\"package_url\":\"https://github.com/rust-lang-nursery/pin-utils\",\"repository\":{\"Http\":{\"sha256\":\"8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184\",\"url\":\"https://static.crates.io/crates/pin-utils/0.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"pin_utils\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.0\"},\"pkg-config 0.3.33\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"pkg_config\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"pkg-config\",\"package_url\":\"https://github.com/rust-lang/pkg-config-rs\",\"repository\":{\"Http\":{\"sha256\":\"19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e\",\"url\":\"https://static.crates.io/crates/pkg-config/0.3.33/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"pkg_config\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.33\"},\"plain 0.2.3\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"plain\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"plain\",\"package_url\":\"https://github.com/randomites/plain\",\"repository\":{\"Http\":{\"sha256\":\"b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6\",\"url\":\"https://static.crates.io/crates/plain/0.2.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"plain\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.3\"},\"potential_utf 0.1.5\":{\"common_attrs\":{\"crate_features\":[\"zerovec\"],\"deps\":[{\"id\":\"zerovec 0.11.6\",\"target\":\"zerovec\"}],\"edition\":\"2021\"},\"library_target_name\":\"potential_utf\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"potential_utf\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564\",\"url\":\"https://static.crates.io/crates/potential_utf/0.1.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"potential_utf\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.5\"},\"powerfmt 0.2.0\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"powerfmt\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-Apache\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"powerfmt\",\"package_url\":\"https://github.com/jhpratt/powerfmt\",\"repository\":{\"Http\":{\"sha256\":\"439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391\",\"url\":\"https://static.crates.io/crates/powerfmt/0.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"powerfmt\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.0\"},\"ppv-lite86 0.2.21\":{\"common_attrs\":{\"crate_features\":[\"simd\",\"std\"],\"deps\":[{\"id\":\"zerocopy 0.8.48\",\"target\":\"zerocopy\"}],\"edition\":\"2021\"},\"library_target_name\":\"ppv_lite86\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"ppv-lite86\",\"package_url\":\"https://github.com/cryptocorrosion/cryptocorrosion\",\"repository\":{\"Http\":{\"sha256\":\"85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9\",\"url\":\"https://static.crates.io/crates/ppv-lite86/0.2.21/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ppv_lite86\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.21\"},\"prettyplease 0.2.37\":{\"build_script_attrs\":{\"links\":\"prettyplease02\"},\"common_attrs\":{\"crate_features\":[\"verbatim\"],\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"prettyplease\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"prettyplease\",\"package_url\":\"https://github.com/dtolnay/prettyplease\",\"repository\":{\"Http\":{\"sha256\":\"479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b\",\"url\":\"https://static.crates.io/crates/prettyplease/0.2.37/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"prettyplease\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.2.37\"},\"proc-macro-crate 3.5.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"toml_edit 0.25.11+spec-1.1.0\",\"target\":\"toml_edit\"}],\"edition\":\"2021\"},\"library_target_name\":\"proc_macro_crate\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"proc-macro-crate\",\"package_url\":\"https://github.com/bkchr/proc-macro-crate\",\"repository\":{\"Http\":{\"sha256\":\"e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f\",\"url\":\"https://static.crates.io/crates/proc-macro-crate/3.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"proc_macro_crate\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"3.5.0\"},\"proc-macro-error-attr2 2.0.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"}],\"edition\":\"2021\"},\"library_target_name\":\"proc_macro_error_attr2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"proc-macro-error-attr2\",\"package_url\":\"https://github.com/GnomedDev/proc-macro-error-2\",\"repository\":{\"Http\":{\"sha256\":\"96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5\",\"url\":\"https://static.crates.io/crates/proc-macro-error-attr2/2.0.0/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"proc_macro_error_attr2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.0.0\"},\"proc-macro-error2 2.0.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"syn-error\"],\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"proc-macro-error-attr2 2.0.0\",\"target\":\"proc_macro_error_attr2\"}]},\"library_target_name\":\"proc_macro_error2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"proc-macro-error2\",\"package_url\":\"https://github.com/GnomedDev/proc-macro-error-2\",\"repository\":{\"Http\":{\"sha256\":\"11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802\",\"url\":\"https://static.crates.io/crates/proc-macro-error2/2.0.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"proc_macro_error2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.0.1\"},\"proc-macro2 1.0.106\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"proc-macro\"],\"deps\":[{\"id\":\"unicode-ident 1.0.24\",\"target\":\"unicode_ident\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"proc_macro2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"proc-macro2\",\"package_url\":\"https://github.com/dtolnay/proc-macro2\",\"repository\":{\"Http\":{\"sha256\":\"8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934\",\"url\":\"https://static.crates.io/crates/proc-macro2/1.0.106/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"proc_macro2\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.106\"},\"ptr_meta 0.3.1\":{\"common_attrs\":{\"crate_features\":[\"derive\",\"ptr_meta_derive\",\"std\"],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"ptr_meta_derive 0.3.1\",\"target\":\"ptr_meta_derive\"}]},\"library_target_name\":\"ptr_meta\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"ptr_meta\",\"package_url\":\"https://github.com/rkyv/ptr_meta\",\"repository\":{\"Http\":{\"sha256\":\"0b9a0cf95a1196af61d4f1cbdab967179516d9a4a4312af1f31948f8f6224a79\",\"url\":\"https://static.crates.io/crates/ptr_meta/0.3.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ptr_meta\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.1\"},\"ptr_meta_derive 0.3.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"ptr_meta_derive\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"ptr_meta_derive\",\"package_url\":\"https://github.com/rkyv/ptr_meta\",\"repository\":{\"Http\":{\"sha256\":\"7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1\",\"url\":\"https://static.crates.io/crates/ptr_meta_derive/0.3.1/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"ptr_meta_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.1\"},\"pulldown-cmark 0.8.0\":{\"build_script_attrs\":{},\"common_attrs\":{\"deps\":[{\"id\":\"bitflags 1.3.2\",\"target\":\"bitflags\"},{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"},{\"id\":\"unicase 2.9.0\",\"target\":\"unicase\"}],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"pulldown_cmark\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"pulldown-cmark\",\"package_url\":\"https://github.com/raphlinus/pulldown-cmark\",\"repository\":{\"Http\":{\"sha256\":\"ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8\",\"url\":\"https://static.crates.io/crates/pulldown-cmark/0.8.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"pulldown_cmark\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.8.0\"},\"quote 1.0.45\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"proc-macro\"],\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"quote\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"quote\",\"package_url\":\"https://github.com/dtolnay/quote\",\"repository\":{\"Http\":{\"sha256\":\"41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924\",\"url\":\"https://static.crates.io/crates/quote/1.0.45/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"quote\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.45\"},\"r-efi 5.3.0\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"r_efi\",\"license\":\"MIT OR Apache-2.0 OR LGPL-2.1-or-later\",\"license_ids\":[\"Apache-2.0\",\"LGPL-2.1\",\"MIT\"],\"name\":\"r-efi\",\"package_url\":\"https://github.com/r-efi/r-efi\",\"repository\":{\"Http\":{\"sha256\":\"69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f\",\"url\":\"https://static.crates.io/crates/r-efi/5.3.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"r_efi\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"5.3.0\"},\"r-efi 6.0.0\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"r_efi\",\"license\":\"MIT OR Apache-2.0 OR LGPL-2.1-or-later\",\"license_ids\":[\"Apache-2.0\",\"LGPL-2.1\",\"MIT\"],\"name\":\"r-efi\",\"package_url\":\"https://github.com/r-efi/r-efi\",\"repository\":{\"Http\":{\"sha256\":\"f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf\",\"url\":\"https://static.crates.io/crates/r-efi/6.0.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"r_efi\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"6.0.0\"},\"rancor 0.1.1\":{\"common_attrs\":{\"crate_features\":[\"alloc\"],\"deps\":[{\"id\":\"ptr_meta 0.3.1\",\"target\":\"ptr_meta\"}],\"edition\":\"2021\"},\"library_target_name\":\"rancor\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"rancor\",\"package_url\":\"https://github.com/rkyv/rancor\",\"repository\":{\"Http\":{\"sha256\":\"a063ea72381527c2a0561da9c80000ef822bdd7c3241b1cc1b12100e3df081ee\",\"url\":\"https://static.crates.io/crates/rancor/0.1.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rancor\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.1\"},\"rand 0.10.1\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\",\"std_rng\",\"sys_rng\",\"thread_rng\"],\"deps\":[{\"id\":\"chacha20 0.10.0\",\"target\":\"chacha20\"},{\"id\":\"getrandom 0.4.2\",\"target\":\"getrandom\"},{\"id\":\"rand_core 0.10.1\",\"target\":\"rand_core\"}],\"edition\":\"2024\"},\"library_target_name\":\"rand\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rand\",\"package_url\":\"https://github.com/rust-random/rand\",\"repository\":{\"Http\":{\"sha256\":\"d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207\",\"url\":\"https://static.crates.io/crates/rand/0.10.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rand\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.10.1\"},\"rand 0.9.4\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"os_rng\",\"small_rng\",\"std\",\"std_rng\",\"thread_rng\"],\"deps\":[{\"id\":\"rand_chacha 0.9.0\",\"target\":\"rand_chacha\"},{\"id\":\"rand_core 0.9.5\",\"target\":\"rand_core\"}],\"edition\":\"2021\"},\"library_target_name\":\"rand\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rand\",\"package_url\":\"https://github.com/rust-random/rand\",\"repository\":{\"Http\":{\"sha256\":\"44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea\",\"url\":\"https://static.crates.io/crates/rand/0.9.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rand\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.9.4\"},\"rand_chacha 0.9.0\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"deps\":[{\"id\":\"ppv-lite86 0.2.21\",\"target\":\"ppv_lite86\"},{\"id\":\"rand_core 0.9.5\",\"target\":\"rand_core\"}],\"edition\":\"2021\"},\"library_target_name\":\"rand_chacha\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rand_chacha\",\"package_url\":\"https://github.com/rust-random/rand\",\"repository\":{\"Http\":{\"sha256\":\"d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb\",\"url\":\"https://static.crates.io/crates/rand_chacha/0.9.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rand_chacha\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.9.0\"},\"rand_core 0.10.1\":{\"common_attrs\":{\"edition\":\"2024\"},\"library_target_name\":\"rand_core\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rand_core\",\"package_url\":\"https://github.com/rust-random/rand_core\",\"repository\":{\"Http\":{\"sha256\":\"63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69\",\"url\":\"https://static.crates.io/crates/rand_core/0.10.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rand_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.10.1\"},\"rand_core 0.9.5\":{\"common_attrs\":{\"crate_features\":[\"os_rng\",\"std\"],\"deps\":[{\"id\":\"getrandom 0.3.4\",\"target\":\"getrandom\"}],\"edition\":\"2021\"},\"library_target_name\":\"rand_core\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rand_core\",\"package_url\":\"https://github.com/rust-random/rand\",\"repository\":{\"Http\":{\"sha256\":\"76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c\",\"url\":\"https://static.crates.io/crates/rand_core/0.9.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rand_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.9.5\"},\"rangemap 1.7.1\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"rangemap\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rangemap\",\"package_url\":\"https://github.com/jeffparsons/rangemap\",\"repository\":{\"Http\":{\"sha256\":\"973443cf09a9c8656b574a866ab68dfa19f0867d0340648c7d2f6a71b8a8ea68\",\"url\":\"https://static.crates.io/crates/rangemap/1.7.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rangemap\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.7.1\"},\"rayon 1.12.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"either 1.15.0\",\"target\":\"either\"},{\"id\":\"rayon-core 1.13.0\",\"target\":\"rayon_core\"}],\"edition\":\"2021\"},\"library_target_name\":\"rayon\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rayon\",\"package_url\":\"https://github.com/rayon-rs/rayon\",\"repository\":{\"Http\":{\"sha256\":\"fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d\",\"url\":\"https://static.crates.io/crates/rayon/1.12.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rayon\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.12.0\"},\"rayon-core 1.13.0\":{\"build_script_attrs\":{\"links\":\"rayon-core\"},\"common_attrs\":{\"deps\":[{\"id\":\"crossbeam-deque 0.8.6\",\"target\":\"crossbeam_deque\"},{\"id\":\"crossbeam-utils 0.8.21\",\"target\":\"crossbeam_utils\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"rayon_core\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rayon-core\",\"package_url\":\"https://github.com/rayon-rs/rayon\",\"repository\":{\"Http\":{\"sha256\":\"22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91\",\"url\":\"https://static.crates.io/crates/rayon-core/1.13.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rayon_core\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.13.0\"},\"redox_syscall 0.5.18\":{\"common_attrs\":{\"deps\":[{\"id\":\"bitflags 2.11.1\",\"target\":\"bitflags\"}],\"edition\":\"2021\"},\"library_target_name\":\"syscall\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"redox_syscall\",\"package_url\":\"https://gitlab.redox-os.org/redox-os/syscall\",\"repository\":{\"Http\":{\"sha256\":\"ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d\",\"url\":\"https://static.crates.io/crates/redox_syscall/0.5.18/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"syscall\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.18\"},\"redox_syscall 0.7.4\":{\"common_attrs\":{\"deps\":[{\"id\":\"bitflags 2.11.1\",\"target\":\"bitflags\"}],\"edition\":\"2021\"},\"library_target_name\":\"syscall\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"redox_syscall\",\"package_url\":\"https://gitlab.redox-os.org/redox-os/syscall\",\"repository\":{\"Http\":{\"sha256\":\"f450ad9c3b1da563fb6948a8e0fb0fb9269711c9c73d9ea1de5058c79c8d643a\",\"url\":\"https://static.crates.io/crates/redox_syscall/0.7.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"syscall\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.4\"},\"ref-cast 1.0.25\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":[{\"id\":\"ref-cast-impl 1.0.25\",\"target\":\"ref_cast_impl\"}]},\"library_target_name\":\"ref_cast\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"ref-cast\",\"package_url\":\"https://github.com/dtolnay/ref-cast\",\"repository\":{\"Http\":{\"sha256\":\"f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d\",\"url\":\"https://static.crates.io/crates/ref-cast/1.0.25/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ref_cast\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.25\"},\"ref-cast-impl 1.0.25\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"ref_cast_impl\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"ref-cast-impl\",\"package_url\":\"https://github.com/dtolnay/ref-cast\",\"repository\":{\"Http\":{\"sha256\":\"b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da\",\"url\":\"https://static.crates.io/crates/ref-cast-impl/1.0.25/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"ref_cast_impl\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.25\"},\"regex 1.12.3\":{\"common_attrs\":{\"crate_features\":[\"std\",\"unicode\",\"unicode-age\",\"unicode-bool\",\"unicode-case\",\"unicode-gencat\",\"unicode-perl\",\"unicode-script\",\"unicode-segment\"],\"deps\":[{\"id\":\"regex-automata 0.4.14\",\"target\":\"regex_automata\"},{\"id\":\"regex-syntax 0.8.10\",\"target\":\"regex_syntax\"}],\"edition\":\"2021\"},\"library_target_name\":\"regex\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"regex\",\"package_url\":\"https://github.com/rust-lang/regex\",\"repository\":{\"Http\":{\"sha256\":\"e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276\",\"url\":\"https://static.crates.io/crates/regex/1.12.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"regex\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.12.3\"},\"regex-automata 0.4.14\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"dfa-onepass\",\"hybrid\",\"meta\",\"nfa\",\"nfa-backtrack\",\"nfa-pikevm\",\"nfa-thompson\",\"perf\",\"perf-inline\",\"perf-literal\",\"perf-literal-multisubstring\",\"perf-literal-substring\",\"std\",\"syntax\",\"unicode\",\"unicode-age\",\"unicode-bool\",\"unicode-case\",\"unicode-gencat\",\"unicode-perl\",\"unicode-script\",\"unicode-segment\",\"unicode-word-boundary\"],\"deps\":[{\"id\":\"aho-corasick 1.1.4\",\"target\":\"aho_corasick\"},{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"},{\"id\":\"regex-syntax 0.8.10\",\"target\":\"regex_syntax\"}],\"edition\":\"2021\"},\"library_target_name\":\"regex_automata\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"regex-automata\",\"package_url\":\"https://github.com/rust-lang/regex\",\"repository\":{\"Http\":{\"sha256\":\"6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f\",\"url\":\"https://static.crates.io/crates/regex-automata/0.4.14/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"regex_automata\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.14\"},\"regex-syntax 0.8.10\":{\"common_attrs\":{\"crate_features\":[\"std\",\"unicode\",\"unicode-age\",\"unicode-bool\",\"unicode-case\",\"unicode-gencat\",\"unicode-perl\",\"unicode-script\",\"unicode-segment\"],\"edition\":\"2021\"},\"library_target_name\":\"regex_syntax\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"regex-syntax\",\"package_url\":\"https://github.com/rust-lang/regex\",\"repository\":{\"Http\":{\"sha256\":\"dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a\",\"url\":\"https://static.crates.io/crates/regex-syntax/0.8.10/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"regex_syntax\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.10\"},\"region 3.0.2\":{\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"bitflags 1.3.2\",\"target\":\"bitflags\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"selects\":{\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"ios\\\"))\":[{\"id\":\"mach2 0.4.3\",\"target\":\"mach2\"}],\"cfg(windows)\":[{\"id\":\"windows-sys 0.52.0\",\"target\":\"windows_sys\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"region\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"region\",\"package_url\":\"https://github.com/darfink/region-rs\",\"repository\":{\"Http\":{\"sha256\":\"e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7\",\"url\":\"https://static.crates.io/crates/region/3.0.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"region\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"3.0.2\"},\"rend 0.5.3\":{\"common_attrs\":{\"crate_features\":[\"bytecheck\"],\"deps\":[{\"id\":\"bytecheck 0.8.2\",\"target\":\"bytecheck\"}],\"edition\":\"2021\"},\"library_target_name\":\"rend\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"rend\",\"package_url\":\"https://github.com/djkoloski/rend\",\"repository\":{\"Http\":{\"sha256\":\"cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6\",\"url\":\"https://static.crates.io/crates/rend/0.5.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rend\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.3\"},\"replace_with 0.1.8\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"replace_with\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE.txt\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"replace_with\",\"package_url\":\"https://github.com/alecmocatta/replace_with\",\"repository\":{\"Http\":{\"sha256\":\"51743d3e274e2b18df81c4dc6caf8a5b8e15dbe799e0dca05c7617380094e884\",\"url\":\"https://static.crates.io/crates/replace_with/0.1.8/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"replace_with\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.8\"},\"rkyv 0.8.16\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"bytecheck\",\"bytes-1\",\"default\",\"indexmap-2\",\"std\"],\"deps\":[{\"id\":\"bytecheck 0.8.2\",\"target\":\"bytecheck\"},{\"alias\":\"bytes_1\",\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"hashbrown 0.17.0\",\"target\":\"hashbrown\"},{\"alias\":\"indexmap_2\",\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"munge 0.4.7\",\"target\":\"munge\"},{\"id\":\"ptr_meta 0.3.1\",\"target\":\"ptr_meta\"},{\"id\":\"rancor 0.1.1\",\"target\":\"rancor\"},{\"id\":\"rend 0.5.3\",\"target\":\"rend\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"rkyv_derive 0.8.16\",\"target\":\"rkyv_derive\"}]},\"library_target_name\":\"rkyv\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"rkyv\",\"package_url\":\"https://github.com/rkyv/rkyv\",\"repository\":{\"Http\":{\"sha256\":\"73389e0c99e664f919275ab5b5b0471391fe9a8de61e1dff9b1eaf56a90f16e3\",\"url\":\"https://static.crates.io/crates/rkyv/0.8.16/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rkyv\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.16\"},\"rkyv_derive 0.8.16\":{\"common_attrs\":{\"crate_features\":[\"bytecheck\"],\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"rkyv_derive\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"rkyv_derive\",\"package_url\":\"https://github.com/rkyv/rkyv\",\"repository\":{\"Http\":{\"sha256\":\"5d2ed0b54125315fb36bd021e82d314d1c126548f871634b483f46b31d13cac6\",\"url\":\"https://static.crates.io/crates/rkyv_derive/0.8.16/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"rkyv_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.16\"},\"rustc-demangle 0.1.27\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"rustc_demangle\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rustc-demangle\",\"package_url\":\"https://github.com/rust-lang/rustc-demangle\",\"repository\":{\"Http\":{\"sha256\":\"b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d\",\"url\":\"https://static.crates.io/crates/rustc-demangle/0.1.27/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rustc_demangle\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.27\"},\"rustc-hash 2.1.2\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"rustc_hash\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rustc-hash\",\"package_url\":\"https://github.com/rust-lang/rustc-hash\",\"repository\":{\"Http\":{\"sha256\":\"94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe\",\"url\":\"https://static.crates.io/crates/rustc-hash/2.1.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rustc_hash\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.1.2\"},\"rustc_version 0.4.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"semver 1.0.28\",\"target\":\"semver\"}],\"edition\":\"2018\"},\"library_target_name\":\"rustc_version\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rustc_version\",\"package_url\":\"https://github.com/djc/rustc-version-rs\",\"repository\":{\"Http\":{\"sha256\":\"cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92\",\"url\":\"https://static.crates.io/crates/rustc_version/0.4.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rustc_version\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.1\"},\"rustix 1.1.4\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"fs\",\"std\",\"termios\"],\"deps\":{\"common\":[{\"id\":\"bitflags 2.11.1\",\"target\":\"bitflags\"}],\"selects\":{\"aarch64-apple-darwin\":[{\"alias\":\"libc_errno\",\"id\":\"errno 0.3.14\",\"target\":\"errno\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(all(any(target_os = \\\"linux\\\", target_os = \\\"android\\\"), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\":[{\"id\":\"linux-raw-sys 0.12.1\",\"target\":\"linux_raw_sys\"}],\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\":[{\"id\":\"linux-raw-sys 0.12.1\",\"target\":\"linux_raw_sys\"}],\"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\":[{\"alias\":\"libc_errno\",\"id\":\"errno 0.3.14\",\"target\":\"errno\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(windows)\":[{\"alias\":\"libc_errno\",\"id\":\"errno 0.3.14\",\"target\":\"errno\"},{\"id\":\"windows-sys 0.61.2\",\"target\":\"windows_sys\"}]}},\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"rustix\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rustix\",\"package_url\":\"https://github.com/bytecodealliance/rustix\",\"repository\":{\"Http\":{\"sha256\":\"b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190\",\"url\":\"https://static.crates.io/crates/rustix/1.1.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rustix\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.1.4\"},\"rustversion 1.0.22\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"rustversion\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rustversion\",\"package_url\":\"https://github.com/dtolnay/rustversion\",\"repository\":{\"Http\":{\"sha256\":\"b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d\",\"url\":\"https://static.crates.io/crates/rustversion/1.0.22/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"rustversion\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build/build.rs\"}}],\"version\":\"1.0.22\"},\"rusty_pool 0.7.0\":{\"common_attrs\":{\"crate_features\":[\"async\",\"default\",\"futures\"],\"deps\":[{\"id\":\"crossbeam-channel 0.5.15\",\"target\":\"crossbeam_channel\"},{\"id\":\"futures 0.3.32\",\"target\":\"futures\"},{\"id\":\"futures-channel 0.3.32\",\"target\":\"futures_channel\"},{\"id\":\"futures-executor 0.3.32\",\"target\":\"futures_executor\"},{\"id\":\"num_cpus 1.17.0\",\"target\":\"num_cpus\"}],\"edition\":\"2018\"},\"library_target_name\":\"rusty_pool\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"rusty_pool\",\"package_url\":\"https://github.com/robinfriedli/rusty_pool\",\"repository\":{\"Http\":{\"sha256\":\"4ed36cdb20de66d89a17ea04b8883fc7a386f2cf877aaedca5005583ce4876ff\",\"url\":\"https://static.crates.io/crates/rusty_pool/0.7.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rusty_pool\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.0\"},\"ruzstd 0.8.2\":{\"common_attrs\":{\"crate_features\":[\"default\",\"hash\",\"std\"],\"deps\":[{\"id\":\"twox-hash 2.1.2\",\"target\":\"twox_hash\"}],\"edition\":\"2018\"},\"library_target_name\":\"ruzstd\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"ruzstd\",\"package_url\":\"https://github.com/KillingSpark/zstd-rs\",\"repository\":{\"Http\":{\"sha256\":\"e5ff0cc5e135c8870a775d3320910cd9b564ec036b4dc0b8741629020be63f01\",\"url\":\"https://static.crates.io/crates/ruzstd/0.8.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ruzstd\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.2\"},\"ryu 1.0.23\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"ryu\",\"license\":\"Apache-2.0 OR BSL-1.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"BSL-1.0\"],\"name\":\"ryu\",\"package_url\":\"https://github.com/dtolnay/ryu\",\"repository\":{\"Http\":{\"sha256\":\"9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f\",\"url\":\"https://static.crates.io/crates/ryu/1.0.23/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ryu\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.23\"},\"saffron 0.1.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"chrono 0.4.44\",\"target\":\"chrono\"},{\"id\":\"nom 5.1.3\",\"target\":\"nom\"}],\"edition\":\"2018\"},\"library_target_name\":\"saffron\",\"license_file\":\"LICENSE\",\"name\":\"saffron\",\"package_url\":\"https://github.com/cloudflare/saffron\",\"repository\":{\"Http\":{\"sha256\":\"03fb9a628596fc7590eb7edbf7b0613287be78df107f5f97b118aad59fb2eea9\",\"url\":\"https://static.crates.io/crates/saffron/0.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"saffron\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.0\"},\"same-file 1.0.6\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(windows)\":[{\"id\":\"winapi-util 0.1.11\",\"target\":\"winapi_util\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"same_file\",\"license\":\"Unlicense/MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"same-file\",\"package_url\":\"https://github.com/BurntSushi/same-file\",\"repository\":{\"Http\":{\"sha256\":\"93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502\",\"url\":\"https://static.crates.io/crates/same-file/1.0.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"same_file\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.6\"},\"schemars 1.2.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"derive\",\"indexmap2\",\"schemars_derive\",\"std\",\"url2\"],\"deps\":[{\"id\":\"dyn-clone 1.0.20\",\"target\":\"dyn_clone\"},{\"alias\":\"indexmap2\",\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"ref-cast 1.0.25\",\"target\":\"ref_cast\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.149\",\"target\":\"serde_json\"},{\"alias\":\"url2\",\"id\":\"url 2.5.8\",\"target\":\"url\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"schemars_derive 1.2.1\",\"target\":\"schemars_derive\"}]},\"library_target_name\":\"schemars\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"schemars\",\"package_url\":\"https://github.com/GREsau/schemars\",\"repository\":{\"Http\":{\"sha256\":\"a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc\",\"url\":\"https://static.crates.io/crates/schemars/1.2.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"schemars\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.1\"},\"schemars_derive 1.2.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"serde_derive_internals 0.29.1\",\"target\":\"serde_derive_internals\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"schemars_derive\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"schemars_derive\",\"package_url\":\"https://github.com/GREsau/schemars\",\"repository\":{\"Http\":{\"sha256\":\"7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f\",\"url\":\"https://static.crates.io/crates/schemars_derive/1.2.1/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"schemars_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.1\"},\"scopeguard 1.2.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"use_std\"],\"edition\":\"2015\"},\"library_target_name\":\"scopeguard\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"scopeguard\",\"package_url\":\"https://github.com/bluss/scopeguard\",\"repository\":{\"Http\":{\"sha256\":\"94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49\",\"url\":\"https://static.crates.io/crates/scopeguard/1.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"scopeguard\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.0\"},\"self_cell 1.2.2\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"self_cell\",\"license\":\"Apache-2.0 OR GPL-2.0-only\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"GPL-2.0\"],\"name\":\"self_cell\",\"package_url\":\"https://github.com/Voultapher/self_cell\",\"repository\":{\"Http\":{\"sha256\":\"b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89\",\"url\":\"https://static.crates.io/crates/self_cell/1.2.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"self_cell\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.2\"},\"semver 1.0.28\":{\"common_attrs\":{\"crate_features\":[\"default\",\"serde\",\"std\"],\"deps\":[{\"alias\":\"serde\",\"id\":\"serde_core 1.0.228\",\"target\":\"serde_core\"}],\"edition\":\"2021\"},\"library_target_name\":\"semver\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"semver\",\"package_url\":\"https://github.com/dtolnay/semver\",\"repository\":{\"Http\":{\"sha256\":\"8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd\",\"url\":\"https://static.crates.io/crates/semver/1.0.28/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"semver\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.28\"},\"serde 1.0.228\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"derive\",\"rc\",\"serde_derive\",\"std\"],\"deps\":[{\"id\":\"serde_core 1.0.228\",\"target\":\"serde_core\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":[{\"id\":\"serde_derive 1.0.228\",\"target\":\"serde_derive\"}]},\"library_target_name\":\"serde\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"serde\",\"package_url\":\"https://github.com/serde-rs/serde\",\"repository\":{\"Http\":{\"sha256\":\"9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e\",\"url\":\"https://static.crates.io/crates/serde/1.0.228/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"serde\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.228\"},\"serde-wasm-bindgen 0.6.5\":{\"common_attrs\":{\"deps\":[{\"id\":\"js-sys 0.3.95\",\"target\":\"js_sys\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"wasm-bindgen 0.2.118\",\"target\":\"wasm_bindgen\"}],\"edition\":\"2018\"},\"library_target_name\":\"serde_wasm_bindgen\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"serde-wasm-bindgen\",\"package_url\":\"https://github.com/RReverser/serde-wasm-bindgen\",\"repository\":{\"Http\":{\"sha256\":\"8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b\",\"url\":\"https://static.crates.io/crates/serde-wasm-bindgen/0.6.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"serde_wasm_bindgen\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.5\"},\"serde_core 1.0.228\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"rc\",\"result\",\"std\"],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":{\"common\":[],\"selects\":{\"cfg(any())\":[{\"id\":\"serde_derive 1.0.228\",\"target\":\"serde_derive\"}]}}},\"library_target_name\":\"serde_core\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"serde_core\",\"package_url\":\"https://github.com/serde-rs/serde\",\"repository\":{\"Http\":{\"sha256\":\"41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad\",\"url\":\"https://static.crates.io/crates/serde_core/1.0.228/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"serde_core\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.228\"},\"serde_derive 1.0.228\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"serde_derive\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"serde_derive\",\"package_url\":\"https://github.com/serde-rs/serde\",\"repository\":{\"Http\":{\"sha256\":\"d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79\",\"url\":\"https://static.crates.io/crates/serde_derive/1.0.228/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"serde_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.228\"},\"serde_derive_internals 0.29.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2015\"},\"library_target_name\":\"serde_derive_internals\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"serde_derive_internals\",\"package_url\":\"https://github.com/serde-rs/serde\",\"repository\":{\"Http\":{\"sha256\":\"18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711\",\"url\":\"https://static.crates.io/crates/serde_derive_internals/0.29.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"serde_derive_internals\",\"crate_root\":\"lib.rs\"}}],\"version\":\"0.29.1\"},\"serde_json 1.0.149\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"deps\":{\"common\":[{\"id\":\"itoa 1.0.18\",\"target\":\"itoa\"},{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"},{\"id\":\"serde_core 1.0.228\",\"target\":\"serde_core\"},{\"id\":\"zmij 1.0.21\",\"target\":\"zmij\"}],\"selects\":{\"cfg(any())\":[{\"id\":\"serde 1.0.228\",\"target\":\"serde\"}]}},\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"serde_json\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"serde_json\",\"package_url\":\"https://github.com/serde-rs/json\",\"repository\":{\"Http\":{\"sha256\":\"83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86\",\"url\":\"https://static.crates.io/crates/serde_json/1.0.149/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"serde_json\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.149\"},\"serde_spanned 1.1.1\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"serde\",\"std\"],\"deps\":[{\"id\":\"serde_core 1.0.228\",\"target\":\"serde_core\"}],\"edition\":\"2024\"},\"library_target_name\":\"serde_spanned\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"serde_spanned\",\"package_url\":\"https://github.com/toml-rs/toml\",\"repository\":{\"Http\":{\"sha256\":\"6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26\",\"url\":\"https://static.crates.io/crates/serde_spanned/1.1.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"serde_spanned\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.1\"},\"serde_yaml 0.9.34+deprecated\":{\"common_attrs\":{\"deps\":[{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"itoa 1.0.18\",\"target\":\"itoa\"},{\"id\":\"ryu 1.0.23\",\"target\":\"ryu\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"unsafe-libyaml 0.2.11\",\"target\":\"unsafe_libyaml\"}],\"edition\":\"2021\"},\"library_target_name\":\"serde_yaml\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"serde_yaml\",\"package_url\":\"https://github.com/dtolnay/serde-yaml\",\"repository\":{\"Http\":{\"sha256\":\"6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47\",\"url\":\"https://static.crates.io/crates/serde_yaml/0.9.34+deprecated/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"serde_yaml\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.9.34+deprecated\"},\"sha2 0.10.9\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"digest 0.10.7\",\"target\":\"digest\"}],\"selects\":{\"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\":[{\"id\":\"cpufeatures 0.2.17\",\"target\":\"cpufeatures\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"sha2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"sha2\",\"package_url\":\"https://github.com/RustCrypto/hashes\",\"repository\":{\"Http\":{\"sha256\":\"a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283\",\"url\":\"https://static.crates.io/crates/sha2/0.10.9/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"sha2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.10.9\"},\"sha2 0.11.0\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"oid\"],\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"digest 0.11.2\",\"target\":\"digest\"}],\"selects\":{\"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\":[{\"id\":\"cpufeatures 0.3.0\",\"target\":\"cpufeatures\"}]}},\"edition\":\"2024\"},\"library_target_name\":\"sha2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"sha2\",\"package_url\":\"https://github.com/RustCrypto/hashes\",\"repository\":{\"Http\":{\"sha256\":\"446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4\",\"url\":\"https://static.crates.io/crates/sha2/0.11.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"sha2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.11.0\"},\"shared-buffer 0.1.4\":{\"common_attrs\":{\"deps\":[{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"memmap2 0.6.2\",\"target\":\"memmap2\"}],\"edition\":\"2021\"},\"library_target_name\":\"shared_buffer\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE_APACHE.md\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"shared-buffer\",\"package_url\":\"https://github.com/wasmerio/shared-buffer.git\",\"repository\":{\"Http\":{\"sha256\":\"f6c99835bad52957e7aa241d3975ed17c1e5f8c92026377d117a606f36b84b16\",\"url\":\"https://static.crates.io/crates/shared-buffer/0.1.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"shared_buffer\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.4\"},\"shlex 1.3.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2015\"},\"library_target_name\":\"shlex\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"shlex\",\"package_url\":\"https://github.com/comex/rust-shlex\",\"repository\":{\"Http\":{\"sha256\":\"0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64\",\"url\":\"https://static.crates.io/crates/shlex/1.3.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"shlex\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.3.0\"},\"simd-adler32 0.3.9\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"simd_adler32\",\"license\":\"MIT\",\"license_file\":\"LICENSE.md\",\"license_ids\":[\"MIT\"],\"name\":\"simd-adler32\",\"package_url\":\"https://github.com/mcountryman/simd-adler32\",\"repository\":{\"Http\":{\"sha256\":\"703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214\",\"url\":\"https://static.crates.io/crates/simd-adler32/0.3.9/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"simd_adler32\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.9\"},\"simdutf8 0.1.5\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"simdutf8\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-Apache\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"simdutf8\",\"package_url\":\"https://github.com/rusticstuff/simdutf8\",\"repository\":{\"Http\":{\"sha256\":\"e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e\",\"url\":\"https://static.crates.io/crates/simdutf8/0.1.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"simdutf8\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.5\"},\"similar 2.7.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"inline\",\"text\"],\"edition\":\"2018\"},\"library_target_name\":\"similar\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"similar\",\"package_url\":\"https://github.com/mitsuhiko/similar\",\"repository\":{\"Http\":{\"sha256\":\"bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa\",\"url\":\"https://static.crates.io/crates/similar/2.7.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"similar\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.7.0\"},\"slab 0.4.12\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"slab\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"slab\",\"package_url\":\"https://github.com/tokio-rs/slab\",\"repository\":{\"Http\":{\"sha256\":\"0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5\",\"url\":\"https://static.crates.io/crates/slab/0.4.12/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"slab\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.12\"},\"smallvec 1.15.1\":{\"common_attrs\":{\"crate_features\":[\"const_generics\"],\"edition\":\"2018\"},\"library_target_name\":\"smallvec\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"smallvec\",\"package_url\":\"https://github.com/servo/rust-smallvec\",\"repository\":{\"Http\":{\"sha256\":\"67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03\",\"url\":\"https://static.crates.io/crates/smallvec/1.15.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"smallvec\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.15.1\"},\"smoltcp 0.13.0\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"alloc\",\"proto-ipv4\",\"std\"],\"deps\":[{\"id\":\"bitflags 1.3.2\",\"target\":\"bitflags\"},{\"id\":\"byteorder 1.5.0\",\"target\":\"byteorder\"},{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"heapless 0.9.2\",\"target\":\"heapless\"},{\"id\":\"managed 0.8.0\",\"target\":\"managed\"}],\"edition\":\"2024\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"smoltcp\",\"license\":\"0BSD\",\"license_file\":\"LICENSE-0BSD.txt\",\"license_ids\":[\"0BSD\"],\"name\":\"smoltcp\",\"package_url\":\"https://github.com/smoltcp-rs/smoltcp.git\",\"repository\":{\"Http\":{\"sha256\":\"ac729b0a77bd092a3f06ddaddc59fe0d67f48ba0de45a9abe707c2842c7f8767\",\"url\":\"https://static.crates.io/crates/smoltcp/0.13.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"smoltcp\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.13.0\"},\"socket2 0.6.3\":{\"common_attrs\":{\"crate_features\":[\"all\"],\"deps\":{\"common\":[],\"selects\":{\"cfg(any(unix, target_os = \\\"wasi\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(windows)\":[{\"id\":\"windows-sys 0.61.2\",\"target\":\"windows_sys\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"socket2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"socket2\",\"package_url\":\"https://github.com/rust-lang/socket2\",\"repository\":{\"Http\":{\"sha256\":\"3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e\",\"url\":\"https://static.crates.io/crates/socket2/0.6.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"socket2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.3\"},\"stable_deref_trait 1.2.1\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2015\"},\"library_target_name\":\"stable_deref_trait\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"stable_deref_trait\",\"package_url\":\"https://github.com/storyyeller/stable_deref_trait\",\"repository\":{\"Http\":{\"sha256\":\"6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596\",\"url\":\"https://static.crates.io/crates/stable_deref_trait/1.2.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"stable_deref_trait\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.1\"},\"strsim 0.11.1\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"strsim\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"strsim\",\"package_url\":\"https://github.com/rapidfuzz/strsim-rs\",\"repository\":{\"Http\":{\"sha256\":\"7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f\",\"url\":\"https://static.crates.io/crates/strsim/0.11.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"strsim\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.11.1\"},\"symbolic-common 12.18.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"debugid 0.8.0\",\"target\":\"debugid\"},{\"id\":\"memmap2 0.9.10\",\"target\":\"memmap2\"},{\"id\":\"stable_deref_trait 1.2.1\",\"target\":\"stable_deref_trait\"},{\"id\":\"uuid 1.23.1\",\"target\":\"uuid\"}],\"edition\":\"2021\"},\"library_target_name\":\"symbolic_common\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"symbolic-common\",\"package_url\":\"https://github.com/getsentry/symbolic\",\"repository\":{\"Http\":{\"sha256\":\"332615d90111d8eeaf86a84dc9bbe9f65d0d8c5cf11b4caccedc37754eb0dcfd\",\"url\":\"https://static.crates.io/crates/symbolic-common/12.18.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"symbolic_common\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"12.18.3\"},\"symbolic-demangle 12.18.3\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"cpp\",\"cpp_demangle\",\"msvc\",\"msvc-demangler\",\"rust\",\"rustc-demangle\"],\"deps\":[{\"id\":\"cpp_demangle 0.4.5\",\"target\":\"cpp_demangle\"},{\"id\":\"msvc-demangler 0.11.0\",\"target\":\"msvc_demangler\"},{\"id\":\"rustc-demangle 0.1.27\",\"target\":\"rustc_demangle\"},{\"id\":\"symbolic-common 12.18.3\",\"target\":\"symbolic_common\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"symbolic_demangle\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"symbolic-demangle\",\"package_url\":\"https://github.com/getsentry/symbolic\",\"repository\":{\"Http\":{\"sha256\":\"912017718eb4d21930546245af9a3475c9dccf15675a5c215664e76621afc471\",\"url\":\"https://static.crates.io/crates/symbolic-demangle/12.18.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"symbolic_demangle\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"12.18.3\"},\"syn 1.0.109\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"clone-impls\",\"default\",\"derive\",\"parsing\",\"printing\",\"proc-macro\",\"quote\"],\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"unicode-ident 1.0.24\",\"target\":\"unicode_ident\"}],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"syn\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"syn\",\"package_url\":\"https://github.com/dtolnay/syn\",\"repository\":{\"Http\":{\"sha256\":\"72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237\",\"url\":\"https://static.crates.io/crates/syn/1.0.109/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"syn\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.109\"},\"syn 2.0.117\":{\"common_attrs\":{\"crate_features\":[\"clone-impls\",\"default\",\"derive\",\"extra-traits\",\"fold\",\"full\",\"parsing\",\"printing\",\"proc-macro\",\"visit\",\"visit-mut\"],\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"unicode-ident 1.0.24\",\"target\":\"unicode_ident\"}],\"edition\":\"2021\"},\"library_target_name\":\"syn\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"syn\",\"package_url\":\"https://github.com/dtolnay/syn\",\"repository\":{\"Http\":{\"sha256\":\"e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99\",\"url\":\"https://static.crates.io/crates/syn/2.0.117/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"syn\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.0.117\"},\"synstructure 0.13.2\":{\"common_attrs\":{\"crate_features\":[\"default\",\"proc-macro\"],\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2018\"},\"library_target_name\":\"synstructure\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"synstructure\",\"package_url\":\"https://github.com/mystor/synstructure\",\"repository\":{\"Http\":{\"sha256\":\"728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2\",\"url\":\"https://static.crates.io/crates/synstructure/0.13.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"synstructure\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.13.2\"},\"tar 0.4.45\":{\"common_attrs\":{\"crate_features\":[\"default\",\"xattr\"],\"deps\":{\"common\":[{\"id\":\"filetime 0.2.27\",\"target\":\"filetime\"},{\"id\":\"xattr 1.6.1\",\"target\":\"xattr\"}],\"selects\":{\"cfg(unix)\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"tar\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"tar\",\"package_url\":\"https://github.com/alexcrichton/tar-rs\",\"repository\":{\"Http\":{\"sha256\":\"22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973\",\"url\":\"https://static.crates.io/crates/tar/0.4.45/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tar\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.45\"},\"target-lexicon 0.13.5\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"target_lexicon\",\"license\":\"Apache-2.0 WITH LLVM-exception\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"target-lexicon\",\"package_url\":\"https://github.com/bytecodealliance/target-lexicon\",\"repository\":{\"Http\":{\"sha256\":\"adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca\",\"url\":\"https://static.crates.io/crates/target-lexicon/0.13.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"target_lexicon\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.13.5\"},\"tempfile 3.27.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"getrandom\"],\"deps\":{\"common\":[{\"id\":\"fastrand 2.4.1\",\"target\":\"fastrand\"},{\"id\":\"getrandom 0.4.2\",\"target\":\"getrandom\"},{\"id\":\"once_cell 1.21.4\",\"target\":\"once_cell\"}],\"selects\":{\"cfg(any(unix, target_os = \\\"wasi\\\"))\":[{\"id\":\"rustix 1.1.4\",\"target\":\"rustix\"}],\"cfg(windows)\":[{\"id\":\"windows-sys 0.61.2\",\"target\":\"windows_sys\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"tempfile\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"tempfile\",\"package_url\":\"https://github.com/Stebalien/tempfile\",\"repository\":{\"Http\":{\"sha256\":\"32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd\",\"url\":\"https://static.crates.io/crates/tempfile/3.27.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tempfile\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"3.27.0\"},\"terminal_size 0.4.4\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(unix)\":[{\"id\":\"rustix 1.1.4\",\"target\":\"rustix\"}],\"cfg(windows)\":[{\"id\":\"windows-sys 0.61.2\",\"target\":\"windows_sys\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"terminal_size\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"terminal_size\",\"package_url\":\"https://github.com/eminence/terminal-size\",\"repository\":{\"Http\":{\"sha256\":\"230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874\",\"url\":\"https://static.crates.io/crates/terminal_size/0.4.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"terminal_size\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.4\"},\"termios 0.3.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"edition\":\"2015\"},\"library_target_name\":\"termios\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"termios\",\"package_url\":\"https://github.com/dcuddeback/termios-rs\",\"repository\":{\"Http\":{\"sha256\":\"411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b\",\"url\":\"https://static.crates.io/crates/termios/0.3.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"termios\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.3\"},\"thiserror 2.0.18\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":[{\"id\":\"thiserror-impl 2.0.18\",\"target\":\"thiserror_impl\"}]},\"library_target_name\":\"thiserror\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"thiserror\",\"package_url\":\"https://github.com/dtolnay/thiserror\",\"repository\":{\"Http\":{\"sha256\":\"4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4\",\"url\":\"https://static.crates.io/crates/thiserror/2.0.18/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"thiserror\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"2.0.18\"},\"thiserror-impl 2.0.18\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"thiserror_impl\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"thiserror-impl\",\"package_url\":\"https://github.com/dtolnay/thiserror\",\"repository\":{\"Http\":{\"sha256\":\"ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5\",\"url\":\"https://static.crates.io/crates/thiserror-impl/2.0.18/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"thiserror_impl\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.0.18\"},\"time 0.3.47\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"formatting\",\"std\"],\"deps\":[{\"id\":\"deranged 0.5.8\",\"target\":\"deranged\"},{\"id\":\"itoa 1.0.18\",\"target\":\"itoa\"},{\"id\":\"num-conv 0.2.1\",\"target\":\"num_conv\"},{\"id\":\"powerfmt 0.2.0\",\"target\":\"powerfmt\"},{\"id\":\"time-core 0.1.8\",\"target\":\"time_core\"}],\"edition\":\"2024\"},\"library_target_name\":\"time\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-Apache\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"time\",\"package_url\":\"https://github.com/time-rs/time\",\"repository\":{\"Http\":{\"sha256\":\"743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c\",\"url\":\"https://static.crates.io/crates/time/0.3.47/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"time\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.47\"},\"time-core 0.1.8\":{\"common_attrs\":{\"edition\":\"2024\"},\"library_target_name\":\"time_core\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-Apache\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"time-core\",\"package_url\":\"https://github.com/time-rs/time\",\"repository\":{\"Http\":{\"sha256\":\"7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca\",\"url\":\"https://static.crates.io/crates/time-core/0.1.8/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"time_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.8\"},\"time-macros 0.2.27\":{\"common_attrs\":{\"deps\":[{\"id\":\"num-conv 0.2.1\",\"target\":\"num_conv\"},{\"id\":\"time-core 0.1.8\",\"target\":\"time_core\"}],\"edition\":\"2024\"},\"library_target_name\":\"time_macros\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-Apache\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"time-macros\",\"package_url\":\"https://github.com/time-rs/time\",\"repository\":{\"Http\":{\"sha256\":\"2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215\",\"url\":\"https://static.crates.io/crates/time-macros/0.2.27/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"time_macros\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.27\"},\"tinystr 0.8.3\":{\"common_attrs\":{\"crate_features\":[\"zerovec\"],\"deps\":[{\"id\":\"zerovec 0.11.6\",\"target\":\"zerovec\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"displaydoc 0.2.5\",\"target\":\"displaydoc\"}]},\"library_target_name\":\"tinystr\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"tinystr\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d\",\"url\":\"https://static.crates.io/crates/tinystr/0.8.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tinystr\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.3\"},\"tinyvec 1.11.0\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"tinyvec_macros\"],\"deps\":[{\"id\":\"tinyvec_macros 0.1.1\",\"target\":\"tinyvec_macros\"}],\"edition\":\"2018\"},\"library_target_name\":\"tinyvec\",\"license\":\"Zlib OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE.md\",\"license_ids\":[\"Apache-2.0\",\"MIT\",\"Zlib\"],\"name\":\"tinyvec\",\"package_url\":\"https://github.com/Lokathor/tinyvec\",\"repository\":{\"Http\":{\"sha256\":\"3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3\",\"url\":\"https://static.crates.io/crates/tinyvec/1.11.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tinyvec\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.11.0\"},\"tinyvec_macros 0.1.1\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"tinyvec_macros\",\"license\":\"MIT OR Apache-2.0 OR Zlib\",\"license_file\":\"LICENSE-APACHE.md\",\"license_ids\":[\"Apache-2.0\",\"MIT\",\"Zlib\"],\"name\":\"tinyvec_macros\",\"package_url\":\"https://github.com/Soveu/tinyvec_macros\",\"repository\":{\"Http\":{\"sha256\":\"1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20\",\"url\":\"https://static.crates.io/crates/tinyvec_macros/0.1.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tinyvec_macros\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.1\"},\"tokio 1.52.1\":{\"common_attrs\":{\"crate_features\":[\"bytes\",\"default\",\"fs\",\"io-std\",\"io-util\",\"libc\",\"macros\",\"mio\",\"net\",\"rt\",\"rt-multi-thread\",\"socket2\",\"sync\",\"time\",\"tokio-macros\"],\"deps\":[{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"},{\"id\":\"mio 1.2.0\",\"target\":\"mio\"},{\"id\":\"pin-project-lite 0.2.17\",\"target\":\"pin_project_lite\"},{\"id\":\"socket2 0.6.3\",\"target\":\"socket2\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"tokio-macros 2.7.0\",\"target\":\"tokio_macros\"}]},\"library_target_name\":\"tokio\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tokio\",\"package_url\":\"https://github.com/tokio-rs/tokio\",\"repository\":{\"Http\":{\"sha256\":\"b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6\",\"url\":\"https://static.crates.io/crates/tokio/1.52.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tokio\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.52.1\"},\"tokio-macros 2.7.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"tokio_macros\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tokio-macros\",\"package_url\":\"https://github.com/tokio-rs/tokio\",\"repository\":{\"Http\":{\"sha256\":\"385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496\",\"url\":\"https://static.crates.io/crates/tokio-macros/2.7.0/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"tokio_macros\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.7.0\"},\"tokio-stream 0.1.18\":{\"common_attrs\":{\"crate_features\":[\"default\",\"sync\",\"time\",\"tokio-util\"],\"deps\":[{\"id\":\"futures-core 0.3.32\",\"target\":\"futures_core\"},{\"id\":\"pin-project-lite 0.2.17\",\"target\":\"pin_project_lite\"},{\"id\":\"tokio 1.52.1\",\"target\":\"tokio\"},{\"id\":\"tokio-util 0.7.18\",\"target\":\"tokio_util\"}],\"edition\":\"2021\"},\"library_target_name\":\"tokio_stream\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tokio-stream\",\"package_url\":\"https://github.com/tokio-rs/tokio\",\"repository\":{\"Http\":{\"sha256\":\"32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70\",\"url\":\"https://static.crates.io/crates/tokio-stream/0.1.18/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tokio_stream\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.18\"},\"tokio-util 0.7.18\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"deps\":[{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"futures-core 0.3.32\",\"target\":\"futures_core\"},{\"id\":\"futures-sink 0.3.32\",\"target\":\"futures_sink\"},{\"id\":\"pin-project-lite 0.2.17\",\"target\":\"pin_project_lite\"},{\"id\":\"tokio 1.52.1\",\"target\":\"tokio\"}],\"edition\":\"2021\"},\"library_target_name\":\"tokio_util\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tokio-util\",\"package_url\":\"https://github.com/tokio-rs/tokio\",\"repository\":{\"Http\":{\"sha256\":\"9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098\",\"url\":\"https://static.crates.io/crates/tokio-util/0.7.18/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tokio_util\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.18\"},\"toml 1.1.2+spec-1.1.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"display\",\"parse\",\"preserve_order\",\"serde\",\"std\"],\"deps\":[{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"serde_core 1.0.228\",\"target\":\"serde_core\"},{\"id\":\"serde_spanned 1.1.1\",\"target\":\"serde_spanned\"},{\"id\":\"toml_datetime 1.1.1+spec-1.1.0\",\"target\":\"toml_datetime\"},{\"id\":\"toml_parser 1.1.2+spec-1.1.0\",\"target\":\"toml_parser\"},{\"id\":\"toml_writer 1.1.1+spec-1.1.0\",\"target\":\"toml_writer\"},{\"id\":\"winnow 1.0.2\",\"target\":\"winnow\"}],\"edition\":\"2024\"},\"library_target_name\":\"toml\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"toml\",\"package_url\":\"https://github.com/toml-rs/toml\",\"repository\":{\"Http\":{\"sha256\":\"81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee\",\"url\":\"https://static.crates.io/crates/toml/1.1.2+spec-1.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"toml\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.2+spec-1.1.0\"},\"toml_datetime 1.1.1+spec-1.1.0\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"serde\",\"std\"],\"deps\":[{\"id\":\"serde_core 1.0.228\",\"target\":\"serde_core\"}],\"edition\":\"2024\"},\"library_target_name\":\"toml_datetime\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"toml_datetime\",\"package_url\":\"https://github.com/toml-rs/toml\",\"repository\":{\"Http\":{\"sha256\":\"3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7\",\"url\":\"https://static.crates.io/crates/toml_datetime/1.1.1+spec-1.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"toml_datetime\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.1+spec-1.1.0\"},\"toml_edit 0.25.11+spec-1.1.0\":{\"common_attrs\":{\"crate_features\":[\"parse\"],\"deps\":[{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"toml_datetime 1.1.1+spec-1.1.0\",\"target\":\"toml_datetime\"},{\"id\":\"toml_parser 1.1.2+spec-1.1.0\",\"target\":\"toml_parser\"},{\"id\":\"winnow 1.0.2\",\"target\":\"winnow\"}],\"edition\":\"2024\"},\"library_target_name\":\"toml_edit\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"toml_edit\",\"package_url\":\"https://github.com/toml-rs/toml\",\"repository\":{\"Http\":{\"sha256\":\"0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b\",\"url\":\"https://static.crates.io/crates/toml_edit/0.25.11+spec-1.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"toml_edit\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.25.11+spec-1.1.0\"},\"toml_parser 1.1.2+spec-1.1.0\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"deps\":[{\"id\":\"winnow 1.0.2\",\"target\":\"winnow\"}],\"edition\":\"2024\"},\"library_target_name\":\"toml_parser\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"toml_parser\",\"package_url\":\"https://github.com/toml-rs/toml\",\"repository\":{\"Http\":{\"sha256\":\"a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526\",\"url\":\"https://static.crates.io/crates/toml_parser/1.1.2+spec-1.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"toml_parser\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.2+spec-1.1.0\"},\"toml_writer 1.1.1+spec-1.1.0\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"std\"],\"edition\":\"2024\"},\"library_target_name\":\"toml_writer\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"toml_writer\",\"package_url\":\"https://github.com/toml-rs/toml\",\"repository\":{\"Http\":{\"sha256\":\"756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db\",\"url\":\"https://static.crates.io/crates/toml_writer/1.1.1+spec-1.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"toml_writer\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.1+spec-1.1.0\"},\"tracing 0.1.44\":{\"common_attrs\":{\"crate_features\":[\"attributes\",\"default\",\"max_level_off\",\"release_max_level_off\",\"std\",\"tracing-attributes\"],\"deps\":[{\"id\":\"pin-project-lite 0.2.17\",\"target\":\"pin_project_lite\"},{\"id\":\"tracing-core 0.1.36\",\"target\":\"tracing_core\"}],\"edition\":\"2018\",\"proc_macro_deps\":[{\"id\":\"tracing-attributes 0.1.31\",\"target\":\"tracing_attributes\"}]},\"library_target_name\":\"tracing\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tracing\",\"package_url\":\"https://github.com/tokio-rs/tracing\",\"repository\":{\"Http\":{\"sha256\":\"63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100\",\"url\":\"https://static.crates.io/crates/tracing/0.1.44/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tracing\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.44\"},\"tracing-attributes 0.1.31\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2018\"},\"library_target_name\":\"tracing_attributes\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tracing-attributes\",\"package_url\":\"https://github.com/tokio-rs/tracing\",\"repository\":{\"Http\":{\"sha256\":\"7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da\",\"url\":\"https://static.crates.io/crates/tracing-attributes/0.1.31/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"tracing_attributes\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.31\"},\"tracing-core 0.1.36\":{\"common_attrs\":{\"crate_features\":[\"once_cell\",\"std\"],\"deps\":[{\"id\":\"once_cell 1.21.4\",\"target\":\"once_cell\"}],\"edition\":\"2018\"},\"library_target_name\":\"tracing_core\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tracing-core\",\"package_url\":\"https://github.com/tokio-rs/tracing\",\"repository\":{\"Http\":{\"sha256\":\"db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a\",\"url\":\"https://static.crates.io/crates/tracing-core/0.1.36/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tracing_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.36\"},\"twox-hash 2.1.2\":{\"common_attrs\":{\"crate_features\":[\"xxhash32\",\"xxhash64\"],\"edition\":\"2021\"},\"library_target_name\":\"twox_hash\",\"license\":\"MIT\",\"license_file\":\"LICENSE.txt\",\"license_ids\":[\"MIT\"],\"name\":\"twox-hash\",\"package_url\":\"https://github.com/shepmaster/twox-hash\",\"repository\":{\"Http\":{\"sha256\":\"9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c\",\"url\":\"https://static.crates.io/crates/twox-hash/2.1.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"twox_hash\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.1.2\"},\"typenum 1.20.0\":{\"common_attrs\":{\"crate_features\":[\"const-generics\"],\"edition\":\"2018\"},\"library_target_name\":\"typenum\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"typenum\",\"package_url\":\"https://github.com/paholg/typenum\",\"repository\":{\"Http\":{\"sha256\":\"40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de\",\"url\":\"https://static.crates.io/crates/typenum/1.20.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"typenum\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.20.0\"},\"unicase 2.9.0\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"unicase\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"unicase\",\"package_url\":\"https://github.com/seanmonstar/unicase\",\"repository\":{\"Http\":{\"sha256\":\"dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142\",\"url\":\"https://static.crates.io/crates/unicase/2.9.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"unicase\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.9.0\"},\"unicode-ident 1.0.24\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"unicode_ident\",\"license\":\"(MIT OR Apache-2.0) AND Unicode-3.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\",\"Unicode-3.0\"],\"name\":\"unicode-ident\",\"package_url\":\"https://github.com/dtolnay/unicode-ident\",\"repository\":{\"Http\":{\"sha256\":\"e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75\",\"url\":\"https://static.crates.io/crates/unicode-ident/1.0.24/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"unicode_ident\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.24\"},\"unicode-normalization 0.1.25\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"tinyvec 1.11.0\",\"target\":\"tinyvec\"}],\"edition\":\"2018\"},\"library_target_name\":\"unicode_normalization\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"unicode-normalization\",\"package_url\":\"https://github.com/unicode-rs/unicode-normalization\",\"repository\":{\"Http\":{\"sha256\":\"5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8\",\"url\":\"https://static.crates.io/crates/unicode-normalization/0.1.25/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"unicode_normalization\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.25\"},\"unicode-segmentation 1.13.2\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"unicode_segmentation\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"unicode-segmentation\",\"package_url\":\"https://github.com/unicode-rs/unicode-segmentation\",\"repository\":{\"Http\":{\"sha256\":\"9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c\",\"url\":\"https://static.crates.io/crates/unicode-segmentation/1.13.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"unicode_segmentation\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.13.2\"},\"unicode-width 0.2.2\":{\"common_attrs\":{\"crate_features\":[\"cjk\",\"default\"],\"edition\":\"2021\"},\"library_target_name\":\"unicode_width\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"unicode-width\",\"package_url\":\"https://github.com/unicode-rs/unicode-width\",\"repository\":{\"Http\":{\"sha256\":\"b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254\",\"url\":\"https://static.crates.io/crates/unicode-width/0.2.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"unicode_width\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.2\"},\"unicode-xid 0.2.6\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"edition\":\"2015\"},\"library_target_name\":\"unicode_xid\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"unicode-xid\",\"package_url\":\"https://github.com/unicode-rs/unicode-xid\",\"repository\":{\"Http\":{\"sha256\":\"ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853\",\"url\":\"https://static.crates.io/crates/unicode-xid/0.2.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"unicode_xid\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.6\"},\"unsafe-libyaml 0.2.11\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"unsafe_libyaml\",\"license\":\"MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\"],\"name\":\"unsafe-libyaml\",\"package_url\":\"https://github.com/dtolnay/unsafe-libyaml\",\"repository\":{\"Http\":{\"sha256\":\"673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861\",\"url\":\"https://static.crates.io/crates/unsafe-libyaml/0.2.11/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"unsafe_libyaml\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.11\"},\"unty 0.0.4\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"unty\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"unty\",\"package_url\":\"https://github.com/bincode-org/unty\",\"repository\":{\"Http\":{\"sha256\":\"6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae\",\"url\":\"https://static.crates.io/crates/unty/0.0.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"unty\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.0.4\"},\"url 2.5.8\":{\"common_attrs\":{\"crate_features\":[\"default\",\"serde\",\"std\"],\"deps\":[{\"id\":\"form_urlencoded 1.2.2\",\"target\":\"form_urlencoded\"},{\"id\":\"idna 1.1.0\",\"target\":\"idna\"},{\"id\":\"percent-encoding 2.3.2\",\"target\":\"percent_encoding\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"}],\"edition\":\"2018\",\"proc_macro_deps\":[{\"id\":\"serde_derive 1.0.228\",\"target\":\"serde_derive\"}]},\"library_target_name\":\"url\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"url\",\"package_url\":\"https://github.com/servo/rust-url\",\"repository\":{\"Http\":{\"sha256\":\"ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed\",\"url\":\"https://static.crates.io/crates/url/2.5.8/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"url\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.5.8\"},\"urlencoding 2.1.3\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"urlencoding\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"urlencoding\",\"package_url\":\"https://github.com/kornelski/rust_urlencoding\",\"repository\":{\"Http\":{\"sha256\":\"daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da\",\"url\":\"https://static.crates.io/crates/urlencoding/2.1.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"urlencoding\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.1.3\"},\"utf8_iter 1.0.4\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"utf8_iter\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"utf8_iter\",\"package_url\":\"https://github.com/hsivonen/utf8_iter\",\"repository\":{\"Http\":{\"sha256\":\"b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be\",\"url\":\"https://static.crates.io/crates/utf8_iter/1.0.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"utf8_iter\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.4\"},\"uuid 1.23.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"uuid\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"uuid\",\"package_url\":\"https://github.com/uuid-rs/uuid\",\"repository\":{\"Http\":{\"sha256\":\"ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76\",\"url\":\"https://static.crates.io/crates/uuid/1.23.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"uuid\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.23.1\"},\"version_check 0.9.5\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"version_check\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"version_check\",\"package_url\":\"https://github.com/SergioBenitez/version_check\",\"repository\":{\"Http\":{\"sha256\":\"0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a\",\"url\":\"https://static.crates.io/crates/version_check/0.9.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"version_check\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.9.5\"},\"virtual-fs 0.702.0-alpha.2\":{\"common_attrs\":{\"crate_features\":[\"anyhow\",\"filetime\",\"fs_extra\",\"host-fs\",\"libc\",\"webc\",\"webc-fs\"],\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"dashmap 6.1.0\",\"target\":\"dashmap\"},{\"id\":\"derive_more 2.1.1\",\"target\":\"derive_more\"},{\"id\":\"dunce 1.0.5\",\"target\":\"dunce\"},{\"id\":\"filetime 0.2.27\",\"target\":\"filetime\"},{\"id\":\"fs_extra 1.3.0\",\"target\":\"fs_extra\"},{\"id\":\"futures 0.3.32\",\"target\":\"futures\"},{\"id\":\"getrandom 0.4.2\",\"target\":\"getrandom\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"},{\"id\":\"pin-project-lite 0.2.17\",\"target\":\"pin_project_lite\"},{\"id\":\"replace_with 0.1.8\",\"target\":\"replace_with\"},{\"id\":\"shared-buffer 0.1.4\",\"target\":\"shared_buffer\"},{\"id\":\"slab 0.4.12\",\"target\":\"slab\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"tokio 1.52.1\",\"target\":\"tokio\"},{\"id\":\"tracing 0.1.44\",\"target\":\"tracing\"},{\"id\":\"virtual-mio 0.702.0-alpha.2\",\"target\":\"virtual_mio\"},{\"id\":\"wasmer-package 0.702.0-alpha.2\",\"target\":\"wasmer_package\"},{\"id\":\"webc 11.0.0\",\"target\":\"webc\"}],\"edition\":\"2024\",\"proc_macro_deps\":[{\"id\":\"async-trait 0.1.89\",\"target\":\"async_trait\"}]},\"library_target_name\":\"virtual_fs\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"virtual-fs\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[\"@@+_repo_rules31+postmaster_cargo//:patches/cargo/virtual-fs.patch\"],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/virtual-fs\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"virtual_fs\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.702.0-alpha.2\"},\"virtual-mio 0.702.0-alpha.2\":{\"common_attrs\":{\"crate_features\":[\"mio\",\"socket2\",\"sys\"],\"deps\":[{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"futures 0.3.32\",\"target\":\"futures\"},{\"id\":\"mio 1.2.0\",\"target\":\"mio\"},{\"id\":\"parking 2.2.1\",\"target\":\"parking\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"socket2 0.6.3\",\"target\":\"socket2\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"tracing 0.1.44\",\"target\":\"tracing\"}],\"edition\":\"2024\",\"proc_macro_deps\":[{\"id\":\"async-trait 0.1.89\",\"target\":\"async_trait\"}]},\"library_target_name\":\"virtual_mio\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"virtual-mio\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[\"@@+_repo_rules31+postmaster_cargo//:patches/cargo/virtual-mio.patch\"],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/virtual-io\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"virtual_mio\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.702.0-alpha.2\"},\"virtual-net 0.702.0-alpha.2\":{\"common_attrs\":{\"crate_features\":[\"host-net\",\"libc\",\"mio\",\"rkyv\",\"socket2\"],\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"base64 0.22.1\",\"target\":\"base64\"},{\"id\":\"bincode 2.0.1\",\"target\":\"bincode\"},{\"id\":\"bytecheck 0.8.2\",\"target\":\"bytecheck\"},{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"derive_more 2.1.1\",\"target\":\"derive_more\"},{\"id\":\"futures-util 0.3.32\",\"target\":\"futures_util\"},{\"id\":\"ipnet 2.12.0\",\"target\":\"ipnet\"},{\"id\":\"iprange 0.6.7\",\"target\":\"iprange\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"},{\"id\":\"mio 1.2.0\",\"target\":\"mio\"},{\"id\":\"pin-project-lite 0.2.17\",\"target\":\"pin_project_lite\"},{\"id\":\"rkyv 0.8.16\",\"target\":\"rkyv\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"smoltcp 0.13.0\",\"target\":\"smoltcp\"},{\"id\":\"socket2 0.6.3\",\"target\":\"socket2\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"tokio 1.52.1\",\"target\":\"tokio\"},{\"id\":\"tracing 0.1.44\",\"target\":\"tracing\"},{\"id\":\"virtual-mio 0.702.0-alpha.2\",\"target\":\"virtual_mio\"}],\"edition\":\"2024\",\"proc_macro_deps\":[{\"id\":\"async-trait 0.1.89\",\"target\":\"async_trait\"}]},\"library_target_name\":\"virtual_net\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"virtual-net\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[\"@@+_repo_rules31+postmaster_cargo//:patches/cargo/virtual-net.patch\"],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/virtual-net\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"virtual_net\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.702.0-alpha.2\"},\"virtue 0.0.18\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"virtue\",\"license\":\"MIT\",\"license_file\":\"LICENSE.md\",\"license_ids\":[\"MIT\"],\"name\":\"virtue\",\"package_url\":\"https://github.com/bincode-org/virtue\",\"repository\":{\"Http\":{\"sha256\":\"051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1\",\"url\":\"https://static.crates.io/crates/virtue/0.0.18/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"virtue\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.0.18\"},\"wai-bindgen-gen-core 0.2.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"wai-parser 0.2.3\",\"target\":\"wai_parser\"}],\"edition\":\"2021\"},\"library_target_name\":\"wai_bindgen_gen_core\",\"license\":\"Apache-2.0\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"wai-bindgen-gen-core\",\"package_url\":\"https://github.com/wasmerio/wai\",\"repository\":{\"Http\":{\"sha256\":\"1aa3dc41b510811122b3088197234c27e08fcad63ef936306dd8e11e2803876c\",\"url\":\"https://static.crates.io/crates/wai-bindgen-gen-core/0.2.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wai_bindgen_gen_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.3\"},\"wai-bindgen-gen-rust 0.2.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"heck 0.3.3\",\"target\":\"heck\"},{\"id\":\"wai-bindgen-gen-core 0.2.3\",\"target\":\"wai_bindgen_gen_core\"}],\"edition\":\"2021\"},\"library_target_name\":\"wai_bindgen_gen_rust\",\"license\":\"Apache-2.0\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"wai-bindgen-gen-rust\",\"package_url\":\"https://github.com/wasmerio/wai\",\"repository\":{\"Http\":{\"sha256\":\"19bc05e8380515c4337c40ef03b2ff233e391315b178a320de8640703d522efe\",\"url\":\"https://static.crates.io/crates/wai-bindgen-gen-rust/0.2.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wai_bindgen_gen_rust\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.3\"},\"wai-bindgen-gen-rust-wasm 0.2.3\":{\"build_script_attrs\":{},\"common_attrs\":{\"deps\":[{\"id\":\"heck 0.3.3\",\"target\":\"heck\"},{\"id\":\"wai-bindgen-gen-core 0.2.3\",\"target\":\"wai_bindgen_gen_core\"},{\"id\":\"wai-bindgen-gen-rust 0.2.3\",\"target\":\"wai_bindgen_gen_rust\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"wai_bindgen_gen_rust_wasm\",\"license\":\"Apache-2.0\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"wai-bindgen-gen-rust-wasm\",\"package_url\":\"https://github.com/wasmerio/wai\",\"repository\":{\"Http\":{\"sha256\":\"d6f35ce5e74086fac87f3a7bd50f643f00fe3559adb75c88521ecaa01c8a6199\",\"url\":\"https://static.crates.io/crates/wai-bindgen-gen-rust-wasm/0.2.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wai_bindgen_gen_rust_wasm\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.2.3\"},\"wai-bindgen-rust 0.2.3\":{\"common_attrs\":{\"crate_features\":[\"macros\",\"wai-bindgen-rust-impl\"],\"deps\":[{\"id\":\"bitflags 1.3.2\",\"target\":\"bitflags\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"wai-bindgen-rust-impl 0.2.3\",\"target\":\"wai_bindgen_rust_impl\"}]},\"library_target_name\":\"wai_bindgen_rust\",\"license\":\"Apache-2.0\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"wai-bindgen-rust\",\"package_url\":\"https://github.com/wasmerio/wai\",\"repository\":{\"Http\":{\"sha256\":\"4e5601c6f448c063e83a5e931b8fefcdf7e01ada424ad42372c948d2e3d67741\",\"url\":\"https://static.crates.io/crates/wai-bindgen-rust/0.2.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wai_bindgen_rust\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.3\"},\"wai-bindgen-rust-impl 0.2.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"syn 1.0.109\",\"target\":\"syn\"},{\"id\":\"wai-bindgen-gen-core 0.2.3\",\"target\":\"wai_bindgen_gen_core\"},{\"id\":\"wai-bindgen-gen-rust-wasm 0.2.3\",\"target\":\"wai_bindgen_gen_rust_wasm\"}],\"edition\":\"2021\"},\"library_target_name\":\"wai_bindgen_rust_impl\",\"license\":\"Apache-2.0\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"wai-bindgen-rust-impl\",\"package_url\":\"https://github.com/wasmerio/wai\",\"repository\":{\"Http\":{\"sha256\":\"bdeeb5c1170246de8425a3e123e7ef260dc05ba2b522a1d369fe2315376efea4\",\"url\":\"https://static.crates.io/crates/wai-bindgen-rust-impl/0.2.3/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"wai_bindgen_rust_impl\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.3\"},\"wai-parser 0.2.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"id-arena 2.3.0\",\"target\":\"id_arena\"},{\"id\":\"pulldown-cmark 0.8.0\",\"target\":\"pulldown_cmark\"},{\"id\":\"unicode-normalization 0.1.25\",\"target\":\"unicode_normalization\"},{\"id\":\"unicode-xid 0.2.6\",\"target\":\"unicode_xid\"}],\"edition\":\"2021\"},\"library_target_name\":\"wai_parser\",\"license\":\"Apache-2.0\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"wai-parser\",\"package_url\":\"https://github.com/wasmerio/wai\",\"repository\":{\"Http\":{\"sha256\":\"9bd0acb6d70885ea0c343749019ba74f015f64a9d30542e66db69b49b7e28186\",\"url\":\"https://static.crates.io/crates/wai-parser/0.2.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wai_parser\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.3\"},\"waker-fn 1.2.0\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"waker_fn\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"waker-fn\",\"package_url\":\"https://github.com/smol-rs/waker-fn\",\"repository\":{\"Http\":{\"sha256\":\"317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7\",\"url\":\"https://static.crates.io/crates/waker-fn/1.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"waker_fn\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.0\"},\"walkdir 2.5.0\":{\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"same-file 1.0.6\",\"target\":\"same_file\"}],\"selects\":{\"cfg(windows)\":[{\"id\":\"winapi-util 0.1.11\",\"target\":\"winapi_util\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"walkdir\",\"license\":\"Unlicense/MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"walkdir\",\"package_url\":\"https://github.com/BurntSushi/walkdir\",\"repository\":{\"Http\":{\"sha256\":\"29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b\",\"url\":\"https://static.crates.io/crates/walkdir/2.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"walkdir\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.5.0\"},\"wasi 0.11.1+wasi-snapshot-preview1\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"wasi\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasi\",\"package_url\":\"https://github.com/bytecodealliance/wasi\",\"repository\":{\"Http\":{\"sha256\":\"ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b\",\"url\":\"https://static.crates.io/crates/wasi/0.11.1+wasi-snapshot-preview1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasi\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.11.1+wasi-snapshot-preview1\"},\"wasip2 1.0.3+wasi-0.2.9\":{\"common_attrs\":{\"deps\":[{\"id\":\"wit-bindgen 0.57.1\",\"target\":\"wit_bindgen\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasip2\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasip2\",\"package_url\":\"https://github.com/bytecodealliance/wasi-rs\",\"repository\":{\"Http\":{\"sha256\":\"20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6\",\"url\":\"https://static.crates.io/crates/wasip2/1.0.3+wasi-0.2.9/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasip2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.3+wasi-0.2.9\"},\"wasip3 0.4.0+wasi-0.3.0-rc-2026-01-06\":{\"common_attrs\":{\"deps\":[{\"id\":\"wit-bindgen 0.51.0\",\"target\":\"wit_bindgen\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasip3\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasip3\",\"package_url\":\"https://github.com/bytecodealliance/wasi-rs\",\"repository\":{\"Http\":{\"sha256\":\"5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5\",\"url\":\"https://static.crates.io/crates/wasip3/0.4.0+wasi-0.3.0-rc-2026-01-06/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasip3\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.0+wasi-0.3.0-rc-2026-01-06\"},\"wasm-bindgen 0.2.118\":{\"build_script_attrs\":{\"link_deps\":[{\"id\":\"wasm-bindgen-shared 0.2.118\",\"target\":\"wasm_bindgen_shared\"}],\"proc_macro_deps\":[{\"alias\":\"rustversion_compat\",\"id\":\"rustversion 1.0.22\",\"target\":\"rustversion\"}]},\"common_attrs\":{\"deps\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"once_cell 1.21.4\",\"target\":\"once_cell\"},{\"id\":\"wasm-bindgen-shared 0.2.118\",\"target\":\"wasm_bindgen_shared\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":[{\"id\":\"wasm-bindgen-macro 0.2.118\",\"target\":\"wasm_bindgen_macro\"}]},\"library_target_name\":\"wasm_bindgen\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-bindgen\",\"package_url\":\"https://github.com/wasm-bindgen/wasm-bindgen\",\"repository\":{\"Http\":{\"sha256\":\"0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89\",\"url\":\"https://static.crates.io/crates/wasm-bindgen/0.2.118/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasm_bindgen\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.2.118\"},\"wasm-bindgen-macro 0.2.118\":{\"common_attrs\":{\"deps\":[{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"wasm-bindgen-macro-support 0.2.118\",\"target\":\"wasm_bindgen_macro_support\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasm_bindgen_macro\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-bindgen-macro\",\"package_url\":\"https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/macro\",\"repository\":{\"Http\":{\"sha256\":\"eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed\",\"url\":\"https://static.crates.io/crates/wasm-bindgen-macro/0.2.118/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"wasm_bindgen_macro\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.118\"},\"wasm-bindgen-macro-support 0.2.118\":{\"common_attrs\":{\"deps\":[{\"id\":\"bumpalo 3.20.2\",\"target\":\"bumpalo\"},{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"},{\"id\":\"wasm-bindgen-shared 0.2.118\",\"target\":\"wasm_bindgen_shared\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasm_bindgen_macro_support\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-bindgen-macro-support\",\"package_url\":\"https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/macro-support\",\"repository\":{\"Http\":{\"sha256\":\"9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904\",\"url\":\"https://static.crates.io/crates/wasm-bindgen-macro-support/0.2.118/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasm_bindgen_macro_support\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.118\"},\"wasm-bindgen-shared 0.2.118\":{\"build_script_attrs\":{\"links\":\"wasm_bindgen\"},\"common_attrs\":{\"deps\":[{\"id\":\"unicode-ident 1.0.24\",\"target\":\"unicode_ident\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"wasm_bindgen_shared\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-bindgen-shared\",\"package_url\":\"https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/shared\",\"repository\":{\"Http\":{\"sha256\":\"5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129\",\"url\":\"https://static.crates.io/crates/wasm-bindgen-shared/0.2.118/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasm_bindgen_shared\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.2.118\"},\"wasm-encoder 0.244.0\":{\"common_attrs\":{\"crate_features\":[\"component-model\",\"std\",\"wasmparser\"],\"deps\":[{\"id\":\"leb128fmt 0.1.0\",\"target\":\"leb128fmt\"},{\"id\":\"wasmparser 0.244.0\",\"target\":\"wasmparser\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasm_encoder\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-encoder\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-encoder\",\"repository\":{\"Http\":{\"sha256\":\"990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319\",\"url\":\"https://static.crates.io/crates/wasm-encoder/0.244.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasm_encoder\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.244.0\"},\"wasm-encoder 0.247.0\":{\"common_attrs\":{\"crate_features\":[\"component-model\",\"std\"],\"deps\":[{\"id\":\"leb128fmt 0.1.0\",\"target\":\"leb128fmt\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasm_encoder\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-encoder\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-encoder\",\"repository\":{\"Http\":{\"sha256\":\"30b6733b8b91d010a6ac5b0fb237dc46a19650bc4c67db66857e2e787d437204\",\"url\":\"https://static.crates.io/crates/wasm-encoder/0.247.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasm_encoder\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.247.0\"},\"wasm-metadata 0.244.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"wasm-encoder 0.244.0\",\"target\":\"wasm_encoder\"},{\"id\":\"wasmparser 0.244.0\",\"target\":\"wasmparser\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasm_metadata\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-metadata\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-metadata\",\"repository\":{\"Http\":{\"sha256\":\"bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909\",\"url\":\"https://static.crates.io/crates/wasm-metadata/0.244.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasm_metadata\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.244.0\"},\"wasmer 7.2.0-alpha.2\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"bindgen 0.72.1\",\"target\":\"bindgen\"},{\"id\":\"cmake 0.1.58\",\"target\":\"cmake\"},{\"id\":\"tar 0.4.45\",\"target\":\"tar\"}]},\"common_attrs\":{\"crate_features\":[\"experimental-async\",\"headless\",\"std\",\"sys\"],\"deps\":{\"common\":[{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"corosensei 0.3.3\",\"target\":\"corosensei\"},{\"id\":\"derive_more 2.1.1\",\"target\":\"derive_more\"},{\"id\":\"futures 0.3.32\",\"target\":\"futures\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"more-asserts 0.3.1\",\"target\":\"more_asserts\"},{\"id\":\"shared-buffer 0.1.4\",\"target\":\"shared_buffer\"},{\"id\":\"symbolic-demangle 12.18.3\",\"target\":\"symbolic_demangle\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"tracing 0.1.44\",\"target\":\"tracing\"},{\"id\":\"wasmer-compiler 7.2.0-alpha.2\",\"target\":\"wasmer_compiler\"},{\"id\":\"wasmer-vm 7.2.0-alpha.2\",\"target\":\"wasmer_vm\"}],\"selects\":{\"cfg(all(not(target_arch = \\\"wasm32\\\"), target_os = \\\"windows\\\"))\":[{\"id\":\"windows-sys 0.61.2\",\"target\":\"windows_sys\"}],\"cfg(not(target_arch = \\\"wasm32\\\"))\":[{\"id\":\"dashmap 6.1.0\",\"target\":\"dashmap\"},{\"id\":\"target-lexicon 0.13.5\",\"target\":\"target_lexicon\"},{\"id\":\"wasmer-types 7.2.0-alpha.2\",\"target\":\"wasmer_types\"}],\"cfg(target_arch = \\\"wasm32\\\")\":[{\"id\":\"js-sys 0.3.95\",\"target\":\"js_sys\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"serde-wasm-bindgen 0.6.5\",\"target\":\"serde_wasm_bindgen\"},{\"id\":\"target-lexicon 0.13.5\",\"target\":\"target_lexicon\"},{\"id\":\"wasm-bindgen 0.2.118\",\"target\":\"wasm_bindgen\"},{\"id\":\"wasmer-types 7.2.0-alpha.2\",\"target\":\"wasmer_types\"}]}},\"edition\":\"2024\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":{\"common\":[{\"id\":\"paste 1.0.15\",\"target\":\"paste\"}],\"selects\":{\"cfg(not(target_arch = \\\"wasm32\\\"))\":[{\"id\":\"wasmer-derive 7.2.0-alpha.2\",\"target\":\"wasmer_derive\"}],\"cfg(target_arch = \\\"wasm32\\\")\":[{\"id\":\"wasmer-derive 7.2.0-alpha.2\",\"target\":\"wasmer_derive\"}]}}},\"library_target_name\":\"wasmer\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[\"@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer.patch\"],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/api\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"7.2.0-alpha.2\"},\"wasmer-compiler 7.2.0-alpha.2\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":{\"common\":[{\"id\":\"backtrace 0.3.76\",\"target\":\"backtrace\"},{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"enum-iterator 2.3.0\",\"target\":\"enum_iterator\"},{\"id\":\"enumset 1.1.10\",\"target\":\"enumset\"},{\"id\":\"itertools 0.14.0\",\"target\":\"itertools\"},{\"id\":\"leb128 0.2.6\",\"target\":\"leb128\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"},{\"id\":\"memmap2 0.9.10\",\"target\":\"memmap2\"},{\"id\":\"more-asserts 0.3.1\",\"target\":\"more_asserts\"},{\"id\":\"object 0.39.1\",\"target\":\"object\"},{\"id\":\"rangemap 1.7.1\",\"target\":\"rangemap\"},{\"id\":\"rkyv 0.8.16\",\"target\":\"rkyv\"},{\"id\":\"self_cell 1.2.2\",\"target\":\"self_cell\"},{\"id\":\"shared-buffer 0.1.4\",\"target\":\"shared_buffer\"},{\"id\":\"smallvec 1.15.1\",\"target\":\"smallvec\"},{\"id\":\"target-lexicon 0.13.5\",\"target\":\"target_lexicon\"},{\"id\":\"tempfile 3.27.0\",\"target\":\"tempfile\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"wasmer-types 7.2.0-alpha.2\",\"target\":\"wasmer_types\"}],\"selects\":{\"cfg(all(target_os = \\\"macos\\\", target_arch = \\\"aarch64\\\"))\":[{\"id\":\"macho-unwind-info 0.5.0\",\"target\":\"macho_unwind_info\"}],\"cfg(not(target_arch = \\\"wasm32\\\"))\":[{\"id\":\"crossbeam-channel 0.5.15\",\"target\":\"crossbeam_channel\"},{\"id\":\"rayon 1.12.0\",\"target\":\"rayon\"},{\"id\":\"region 3.0.2\",\"target\":\"region\"},{\"id\":\"wasmer-vm 7.2.0-alpha.2\",\"target\":\"wasmer_vm\"},{\"id\":\"which 8.0.2\",\"target\":\"which\"}],\"cfg(target_os = \\\"windows\\\")\":[{\"id\":\"windows-sys 0.61.2\",\"target\":\"windows_sys\"}]}},\"edition\":\"2024\",\"extra_link_deps\":[\"@oliphaunt//build_defs/wasix/postmaster:linked_unwinder\"],\"rustc_flags\":[\"--cfg=oliphaunt_linked_libunwind\"]},\"library_target_name\":\"wasmer_compiler\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer-compiler\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[\"@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-compiler.patch\"],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/compiler\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_compiler\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"7.2.0-alpha.2\"},\"wasmer-config 0.702.0-alpha.2\":{\"common_attrs\":{\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"bytesize 2.3.1\",\"target\":\"bytesize\"},{\"id\":\"ciborium 0.2.2\",\"target\":\"ciborium\"},{\"id\":\"derive_builder 0.20.2\",\"target\":\"derive_builder\"},{\"id\":\"hex 0.4.3\",\"target\":\"hex\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"saffron 0.1.0\",\"target\":\"saffron\"},{\"id\":\"schemars 1.2.1\",\"target\":\"schemars\"},{\"id\":\"semver 1.0.28\",\"target\":\"semver\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.149\",\"target\":\"serde_json\"},{\"id\":\"serde_yaml 0.9.34+deprecated\",\"target\":\"serde_yaml\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"toml 1.1.2+spec-1.1.0\",\"target\":\"toml\"},{\"id\":\"url 2.5.8\",\"target\":\"url\"}],\"edition\":\"2024\"},\"library_target_name\":\"wasmer_config\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer-config\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/config\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_config\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.702.0-alpha.2\"},\"wasmer-derive 7.2.0-alpha.2\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro-error2 2.0.1\",\"target\":\"proc_macro_error2\"},{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2024\"},\"library_target_name\":\"wasmer_derive\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer-derive\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/derive\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"wasmer_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"7.2.0-alpha.2\"},\"wasmer-journal 0.702.0-alpha.2\":{\"common_attrs\":{\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"base64 0.22.1\",\"target\":\"base64\"},{\"id\":\"bincode 2.0.1\",\"target\":\"bincode\"},{\"id\":\"bytecheck 0.8.2\",\"target\":\"bytecheck\"},{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"derive_more 2.1.1\",\"target\":\"derive_more\"},{\"id\":\"lz4_flex 0.13.0\",\"target\":\"lz4_flex\"},{\"id\":\"num_enum 0.7.6\",\"target\":\"num_enum\"},{\"id\":\"rkyv 0.8.16\",\"target\":\"rkyv\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.149\",\"target\":\"serde_json\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"tracing 0.1.44\",\"target\":\"tracing\"},{\"id\":\"virtual-fs 0.702.0-alpha.2\",\"target\":\"virtual_fs\"},{\"id\":\"virtual-net 0.702.0-alpha.2\",\"target\":\"virtual_net\"},{\"id\":\"wasmer 7.2.0-alpha.2\",\"target\":\"wasmer\"},{\"id\":\"wasmer-config 0.702.0-alpha.2\",\"target\":\"wasmer_config\"},{\"id\":\"wasmer-wasix-types 0.702.0-alpha.2\",\"target\":\"wasmer_wasix_types\"}],\"edition\":\"2024\",\"proc_macro_deps\":[{\"id\":\"async-trait 0.1.89\",\"target\":\"async_trait\"}]},\"library_target_name\":\"wasmer_journal\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer-journal\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/journal\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_journal\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.702.0-alpha.2\"},\"wasmer-package 0.702.0-alpha.2\":{\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"ciborium 0.2.2\",\"target\":\"ciborium\"},{\"id\":\"flate2 1.1.9\",\"target\":\"flate2\"},{\"id\":\"ignore 0.4.25\",\"target\":\"ignore\"},{\"id\":\"insta 1.47.2\",\"target\":\"insta\"},{\"id\":\"semver 1.0.28\",\"target\":\"semver\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.149\",\"target\":\"serde_json\"},{\"id\":\"sha2 0.11.0\",\"target\":\"sha2\"},{\"id\":\"shared-buffer 0.1.4\",\"target\":\"shared_buffer\"},{\"id\":\"tar 0.4.45\",\"target\":\"tar\"},{\"id\":\"tempfile 3.27.0\",\"target\":\"tempfile\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"toml 1.1.2+spec-1.1.0\",\"target\":\"toml\"},{\"id\":\"url 2.5.8\",\"target\":\"url\"},{\"id\":\"wasmer-config 0.702.0-alpha.2\",\"target\":\"wasmer_config\"},{\"id\":\"wasmer-types 7.2.0-alpha.2\",\"target\":\"wasmer_types\"},{\"id\":\"webc 11.0.0\",\"target\":\"webc\"}],\"selects\":{\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"wasi\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}]}},\"edition\":\"2024\"},\"library_target_name\":\"wasmer_package\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer-package\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/package\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_package\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.702.0-alpha.2\"},\"wasmer-types 7.2.0-alpha.2\":{\"common_attrs\":{\"crate_features\":[\"default\",\"detect-wasm-features\",\"serde\",\"std\"],\"deps\":[{\"id\":\"bytecheck 0.8.2\",\"target\":\"bytecheck\"},{\"id\":\"crc32fast 1.5.0\",\"target\":\"crc32fast\"},{\"id\":\"enum-iterator 2.3.0\",\"target\":\"enum_iterator\"},{\"id\":\"enumset 1.1.10\",\"target\":\"enumset\"},{\"id\":\"getrandom 0.4.2\",\"target\":\"getrandom\"},{\"id\":\"hex 0.4.3\",\"target\":\"hex\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"itertools 0.14.0\",\"target\":\"itertools\"},{\"id\":\"more-asserts 0.3.1\",\"target\":\"more_asserts\"},{\"id\":\"rkyv 0.8.16\",\"target\":\"rkyv\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"sha2 0.11.0\",\"target\":\"sha2\"},{\"id\":\"target-lexicon 0.13.5\",\"target\":\"target_lexicon\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"wasmparser 0.247.0\",\"target\":\"wasmparser\"}],\"edition\":\"2024\"},\"library_target_name\":\"wasmer_types\",\"license\":\"MIT OR Apache-2.0 WITH LLVM-exception\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasmer-types\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[\"@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-types.patch\"],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/types\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_types\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"7.2.0-alpha.2\"},\"wasmer-vm 7.2.0-alpha.2\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"deps\":{\"common\":[{\"id\":\"backtrace 0.3.76\",\"target\":\"backtrace\"},{\"id\":\"bytesize 2.3.1\",\"target\":\"bytesize\"},{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"corosensei 0.3.3\",\"target\":\"corosensei\"},{\"id\":\"crossbeam-queue 0.3.12\",\"target\":\"crossbeam_queue\"},{\"id\":\"dashmap 6.1.0\",\"target\":\"dashmap\"},{\"id\":\"enum-iterator 2.3.0\",\"target\":\"enum_iterator\"},{\"id\":\"fnv 1.0.7\",\"target\":\"fnv\"},{\"id\":\"gimli 0.33.0\",\"target\":\"gimli\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"itertools 0.14.0\",\"target\":\"itertools\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"},{\"id\":\"memoffset 0.9.1\",\"target\":\"memoffset\"},{\"id\":\"more-asserts 0.3.1\",\"target\":\"more_asserts\"},{\"id\":\"parking_lot 0.12.5\",\"target\":\"parking_lot\"},{\"id\":\"region 3.0.2\",\"target\":\"region\"},{\"id\":\"scopeguard 1.2.0\",\"target\":\"scopeguard\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"wasmer-types 7.2.0-alpha.2\",\"target\":\"wasmer_types\"}],\"selects\":{\"cfg(any(target_family = \\\"unix\\\", all(target_family = \\\"windows\\\", target_env = \\\"gnu\\\")))\":[{\"id\":\"libunwind 1.3.3\",\"target\":\"libunwind\"}],\"cfg(target_os = \\\"windows\\\")\":[{\"id\":\"windows-sys 0.61.2\",\"target\":\"windows_sys\"}],\"cfg(target_vendor = \\\"apple\\\")\":[{\"id\":\"mach2 0.6.0\",\"target\":\"mach2\"}]}},\"edition\":\"2024\"},\"library_target_name\":\"wasmer_vm\",\"license\":\"MIT OR Apache-2.0 WITH LLVM-exception\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasmer-vm\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[\"@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-vm.patch\"],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/vm\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_vm\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"7.2.0-alpha.2\"},\"wasmer-wasix 0.702.0-alpha.2\":{\"common_attrs\":{\"crate_features\":[\"ctrlc\",\"disable-all-logging\",\"host-fs\",\"host-threads\",\"host-vnet\",\"rusty_pool\",\"sys-minimal\",\"sys-poll\",\"sys-thread\"],\"deps\":{\"common\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"base64 0.22.1\",\"target\":\"base64\"},{\"id\":\"bincode 2.0.1\",\"target\":\"bincode\"},{\"id\":\"blake3 1.8.4\",\"target\":\"blake3\"},{\"id\":\"bytecheck 0.8.2\",\"target\":\"bytecheck\"},{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"cooked-waker 5.0.0\",\"target\":\"cooked_waker\"},{\"id\":\"crossbeam-channel 0.5.15\",\"target\":\"crossbeam_channel\"},{\"id\":\"dashmap 6.1.0\",\"target\":\"dashmap\"},{\"id\":\"derive_more 2.1.1\",\"target\":\"derive_more\"},{\"id\":\"flate2 1.1.9\",\"target\":\"flate2\"},{\"id\":\"fnv 1.0.7\",\"target\":\"fnv\"},{\"id\":\"futures 0.3.32\",\"target\":\"futures\"},{\"id\":\"getrandom 0.4.2\",\"target\":\"getrandom\"},{\"id\":\"heapless 0.9.2\",\"target\":\"heapless\"},{\"id\":\"hex 0.4.3\",\"target\":\"hex\"},{\"id\":\"http 1.4.0\",\"target\":\"http\"},{\"id\":\"linked_hash_set 0.1.6\",\"target\":\"linked_hash_set\"},{\"id\":\"lz4_flex 0.13.0\",\"target\":\"lz4_flex\"},{\"id\":\"num_enum 0.7.6\",\"target\":\"num_enum\"},{\"id\":\"once_cell 1.21.4\",\"target\":\"once_cell\"},{\"id\":\"petgraph 0.8.3\",\"target\":\"petgraph\"},{\"id\":\"pin-project 1.1.11\",\"target\":\"pin_project\"},{\"id\":\"pin-utils 0.1.0\",\"target\":\"pin_utils\"},{\"id\":\"rand 0.10.1\",\"target\":\"rand\"},{\"id\":\"rkyv 0.8.16\",\"target\":\"rkyv\"},{\"id\":\"rusty_pool 0.7.0\",\"target\":\"rusty_pool\"},{\"id\":\"semver 1.0.28\",\"target\":\"semver\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.149\",\"target\":\"serde_json\"},{\"id\":\"serde_yaml 0.9.34+deprecated\",\"target\":\"serde_yaml\"},{\"id\":\"sha2 0.11.0\",\"target\":\"sha2\"},{\"id\":\"shared-buffer 0.1.4\",\"target\":\"shared_buffer\"},{\"id\":\"tempfile 3.27.0\",\"target\":\"tempfile\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"tokio 1.52.1\",\"target\":\"tokio\"},{\"id\":\"tokio-stream 0.1.18\",\"target\":\"tokio_stream\"},{\"id\":\"toml 1.1.2+spec-1.1.0\",\"target\":\"toml\"},{\"id\":\"tracing 0.1.44\",\"target\":\"tracing\"},{\"id\":\"url 2.5.8\",\"target\":\"url\"},{\"id\":\"urlencoding 2.1.3\",\"target\":\"urlencoding\"},{\"id\":\"virtual-fs 0.702.0-alpha.2\",\"target\":\"virtual_fs\"},{\"id\":\"virtual-mio 0.702.0-alpha.2\",\"target\":\"virtual_mio\"},{\"id\":\"virtual-net 0.702.0-alpha.2\",\"target\":\"virtual_net\"},{\"id\":\"waker-fn 1.2.0\",\"target\":\"waker_fn\"},{\"id\":\"wasm-encoder 0.247.0\",\"target\":\"wasm_encoder\"},{\"id\":\"wasmer 7.2.0-alpha.2\",\"target\":\"wasmer\"},{\"id\":\"wasmer-config 0.702.0-alpha.2\",\"target\":\"wasmer_config\"},{\"id\":\"wasmer-journal 0.702.0-alpha.2\",\"target\":\"wasmer_journal\"},{\"id\":\"wasmer-package 0.702.0-alpha.2\",\"target\":\"wasmer_package\"},{\"id\":\"wasmer-types 7.2.0-alpha.2\",\"target\":\"wasmer_types\"},{\"id\":\"wasmer-wasix-types 0.702.0-alpha.2\",\"target\":\"wasmer_wasix_types\"},{\"id\":\"wasmparser 0.247.0\",\"target\":\"wasmparser\"},{\"id\":\"webc 11.0.0\",\"target\":\"webc\"},{\"id\":\"weezl 0.1.12\",\"target\":\"weezl\"},{\"id\":\"xxhash-rust 0.8.15\",\"target\":\"xxhash_rust\"}],\"selects\":{\"cfg(all(unix, not(target_os = \\\"ios\\\")))\":[{\"id\":\"termios 0.3.3\",\"target\":\"termios\"}],\"cfg(not(target_arch = \\\"wasm32\\\"))\":[{\"id\":\"terminal_size 0.4.4\",\"target\":\"terminal_size\"},{\"id\":\"zstd 0.13.3\",\"target\":\"zstd\"}],\"cfg(target_arch = \\\"wasm32\\\")\":[{\"alias\":\"getrandom03\",\"id\":\"getrandom 0.3.4\",\"target\":\"getrandom\"}],\"cfg(unix)\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(windows)\":[{\"id\":\"windows-sys 0.61.2\",\"target\":\"windows_sys\"}]}},\"edition\":\"2024\",\"proc_macro_deps\":[{\"id\":\"async-trait 0.1.89\",\"target\":\"async_trait\"},{\"id\":\"serde_derive 1.0.228\",\"target\":\"serde_derive\"}]},\"library_target_name\":\"wasmer_wasix\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer-wasix\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[\"@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-wasix.patch\"],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/wasix\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_wasix\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.702.0-alpha.2\"},\"wasmer-wasix-types 0.702.0-alpha.2\":{\"common_attrs\":{\"crate_features\":[\"enable-serde\",\"serde\"],\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"bitflags 2.11.1\",\"target\":\"bitflags\"},{\"id\":\"byteorder 1.5.0\",\"target\":\"byteorder\"},{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"num_enum 0.7.6\",\"target\":\"num_enum\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"time 0.3.47\",\"target\":\"time\"},{\"id\":\"tracing 0.1.44\",\"target\":\"tracing\"},{\"id\":\"wai-bindgen-gen-core 0.2.3\",\"target\":\"wai_bindgen_gen_core\"},{\"id\":\"wai-bindgen-gen-rust 0.2.3\",\"target\":\"wai_bindgen_gen_rust\"},{\"id\":\"wai-bindgen-gen-rust-wasm 0.2.3\",\"target\":\"wai_bindgen_gen_rust_wasm\"},{\"id\":\"wai-bindgen-rust 0.2.3\",\"target\":\"wai_bindgen_rust\"},{\"id\":\"wai-parser 0.2.3\",\"target\":\"wai_parser\"},{\"id\":\"wasmer 7.2.0-alpha.2\",\"target\":\"wasmer\"},{\"id\":\"wasmer-types 7.2.0-alpha.2\",\"target\":\"wasmer_types\"}],\"edition\":\"2024\",\"proc_macro_deps\":[{\"id\":\"wasmer-derive 7.2.0-alpha.2\",\"target\":\"wasmer_derive\"}]},\"library_target_name\":\"wasmer_wasix_types\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer-wasix-types\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/wasi-types\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_wasix_types\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.702.0-alpha.2\"},\"wasmparser 0.244.0\":{\"common_attrs\":{\"crate_features\":[\"component-model\",\"features\",\"hash-collections\",\"simd\",\"std\",\"validate\"],\"deps\":[{\"id\":\"bitflags 2.11.1\",\"target\":\"bitflags\"},{\"id\":\"hashbrown 0.15.5\",\"target\":\"hashbrown\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"semver 1.0.28\",\"target\":\"semver\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasmparser\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasmparser\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasmparser\",\"repository\":{\"Http\":{\"sha256\":\"47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe\",\"url\":\"https://static.crates.io/crates/wasmparser/0.244.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmparser\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.244.0\"},\"wasmparser 0.247.0\":{\"common_attrs\":{\"crate_features\":[\"features\",\"simd\",\"validate\"],\"deps\":[{\"id\":\"bitflags 2.11.1\",\"target\":\"bitflags\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasmparser\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasmparser\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasmparser\",\"repository\":{\"Http\":{\"sha256\":\"8e6fb4c2bee46c5ea4d40f8cdb5c131725cd976718ec56f1c8e82fbde5fa2a80\",\"url\":\"https://static.crates.io/crates/wasmparser/0.247.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmparser\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.247.0\"},\"wast 247.0.0\":{\"common_attrs\":{\"crate_features\":[\"component-model\",\"wasm-module\"],\"deps\":[{\"id\":\"bumpalo 3.20.2\",\"target\":\"bumpalo\"},{\"id\":\"leb128fmt 0.1.0\",\"target\":\"leb128fmt\"},{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"},{\"id\":\"unicode-width 0.2.2\",\"target\":\"unicode_width\"},{\"id\":\"wasm-encoder 0.247.0\",\"target\":\"wasm_encoder\"}],\"edition\":\"2021\"},\"library_target_name\":\"wast\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wast\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wast\",\"repository\":{\"Http\":{\"sha256\":\"579d2d47eb33b0cdf9b14723cb115f1e1b7d6e77aac6f0816e5b7c7aeaa418ff\",\"url\":\"https://static.crates.io/crates/wast/247.0.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wast\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"247.0.0\"},\"wat 1.247.0\":{\"common_attrs\":{\"crate_features\":[\"component-model\",\"default\"],\"deps\":[{\"id\":\"wast 247.0.0\",\"target\":\"wast\"}],\"edition\":\"2021\"},\"library_target_name\":\"wat\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wat\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wat\",\"repository\":{\"Http\":{\"sha256\":\"f3f4091c56437e86f2b57fa2fac72c4f528957a605b3f44f7c0b3b19a17ac5ee\",\"url\":\"https://static.crates.io/crates/wat/1.247.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wat\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.247.0\"},\"webc 11.0.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"v1\",\"v2\",\"v3\"],\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"base64 0.22.1\",\"target\":\"base64\"},{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"ciborium 0.2.2\",\"target\":\"ciborium\"},{\"id\":\"ignore 0.4.25\",\"target\":\"ignore\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"leb128 0.2.6\",\"target\":\"leb128\"},{\"id\":\"lexical-sort 0.3.1\",\"target\":\"lexical_sort\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"},{\"id\":\"once_cell 1.21.4\",\"target\":\"once_cell\"},{\"id\":\"path-clean 1.0.1\",\"target\":\"path_clean\"},{\"id\":\"rand 0.9.4\",\"target\":\"rand\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.149\",\"target\":\"serde_json\"},{\"id\":\"sha2 0.10.9\",\"target\":\"sha2\"},{\"id\":\"shared-buffer 0.1.4\",\"target\":\"shared_buffer\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"url 2.5.8\",\"target\":\"url\"}],\"edition\":\"2024\",\"proc_macro_deps\":[{\"id\":\"document-features 0.2.12\",\"target\":\"document_features\"}]},\"library_target_name\":\"webc\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"webc\",\"package_url\":\"https://github.com/wasmerio/pirita\",\"repository\":{\"Http\":{\"sha256\":\"20b8b523112384e8c1caf77cffdd371ca7e0013779f081e6beafc537f5b5325d\",\"url\":\"https://static.crates.io/crates/webc/11.0.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"webc\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"11.0.0\"},\"weezl 0.1.12\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"weezl\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"weezl\",\"package_url\":\"https://github.com/image-rs/weezl\",\"repository\":{\"Http\":{\"sha256\":\"a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88\",\"url\":\"https://static.crates.io/crates/weezl/0.1.12/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"weezl\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.12\"},\"which 8.0.2\":{\"common_attrs\":{\"crate_features\":[\"default\",\"real-sys\"],\"deps\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"edition\":\"2021\"},\"library_target_name\":\"which\",\"license\":\"MIT\",\"license_file\":\"LICENSE.txt\",\"license_ids\":[\"MIT\"],\"name\":\"which\",\"package_url\":\"https://github.com/harryfei/which-rs.git\",\"repository\":{\"Http\":{\"sha256\":\"81995fafaaaf6ae47a7d0cc83c67caf92aeb7e5331650ae6ff856f7c0c60c459\",\"url\":\"https://static.crates.io/crates/which/8.0.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"which\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"8.0.2\"},\"winapi-util 0.1.11\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(windows)\":[{\"id\":\"windows-sys 0.61.2\",\"target\":\"windows_sys\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"winapi_util\",\"license\":\"Unlicense OR MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"winapi-util\",\"package_url\":\"https://github.com/BurntSushi/winapi-util\",\"repository\":{\"Http\":{\"sha256\":\"c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22\",\"url\":\"https://static.crates.io/crates/winapi-util/0.1.11/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"winapi_util\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.11\"},\"windows-link 0.2.1\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"windows_link\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows-link\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5\",\"url\":\"https://static.crates.io/crates/windows-link/0.2.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_link\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.1\"},\"windows-sys 0.52.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"windows-targets 0.52.6\",\"target\":\"windows_targets\"}],\"edition\":\"2021\"},\"library_target_name\":\"windows_sys\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows-sys\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d\",\"url\":\"https://static.crates.io/crates/windows-sys/0.52.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_sys\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.52.0\"},\"windows-sys 0.59.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"windows-targets 0.52.6\",\"target\":\"windows_targets\"}],\"edition\":\"2021\"},\"library_target_name\":\"windows_sys\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows-sys\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b\",\"url\":\"https://static.crates.io/crates/windows-sys/0.59.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_sys\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.59.0\"},\"windows-sys 0.61.2\":{\"common_attrs\":{\"deps\":[{\"id\":\"windows-link 0.2.1\",\"target\":\"windows_link\"}],\"edition\":\"2021\"},\"library_target_name\":\"windows_sys\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows-sys\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc\",\"url\":\"https://static.crates.io/crates/windows-sys/0.61.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_sys\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.61.2\"},\"windows-targets 0.52.6\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"aarch64-pc-windows-gnullvm\":[{\"id\":\"windows_aarch64_gnullvm 0.52.6\",\"target\":\"windows_aarch64_gnullvm\"}],\"cfg(all(any(target_arch = \\\"x86_64\\\", target_arch = \\\"arm64ec\\\"), target_env = \\\"msvc\\\", not(windows_raw_dylib)))\":[{\"id\":\"windows_x86_64_msvc 0.52.6\",\"target\":\"windows_x86_64_msvc\"}],\"cfg(all(target_arch = \\\"aarch64\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\":[{\"id\":\"windows_aarch64_msvc 0.52.6\",\"target\":\"windows_aarch64_msvc\"}],\"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"gnu\\\", not(target_abi = \\\"llvm\\\"), not(windows_raw_dylib)))\":[{\"id\":\"windows_i686_gnu 0.52.6\",\"target\":\"windows_i686_gnu\"}],\"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\":[{\"id\":\"windows_i686_msvc 0.52.6\",\"target\":\"windows_i686_msvc\"}],\"cfg(all(target_arch = \\\"x86_64\\\", target_env = \\\"gnu\\\", not(target_abi = \\\"llvm\\\"), not(windows_raw_dylib)))\":[{\"id\":\"windows_x86_64_gnu 0.52.6\",\"target\":\"windows_x86_64_gnu\"}],\"i686-pc-windows-gnullvm\":[{\"id\":\"windows_i686_gnullvm 0.52.6\",\"target\":\"windows_i686_gnullvm\"}],\"x86_64-pc-windows-gnullvm\":[{\"id\":\"windows_x86_64_gnullvm 0.52.6\",\"target\":\"windows_x86_64_gnullvm\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"windows_targets\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows-targets\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973\",\"url\":\"https://static.crates.io/crates/windows-targets/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_targets\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.52.6\"},\"windows_aarch64_gnullvm 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_aarch64_gnullvm\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_aarch64_gnullvm\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3\",\"url\":\"https://static.crates.io/crates/windows_aarch64_gnullvm/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_aarch64_gnullvm\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"windows_aarch64_msvc 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_aarch64_msvc\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_aarch64_msvc\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469\",\"url\":\"https://static.crates.io/crates/windows_aarch64_msvc/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_aarch64_msvc\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"windows_i686_gnu 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_i686_gnu\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_i686_gnu\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b\",\"url\":\"https://static.crates.io/crates/windows_i686_gnu/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_i686_gnu\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"windows_i686_gnullvm 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_i686_gnullvm\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_i686_gnullvm\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66\",\"url\":\"https://static.crates.io/crates/windows_i686_gnullvm/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_i686_gnullvm\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"windows_i686_msvc 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_i686_msvc\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_i686_msvc\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66\",\"url\":\"https://static.crates.io/crates/windows_i686_msvc/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_i686_msvc\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"windows_x86_64_gnu 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_x86_64_gnu\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_x86_64_gnu\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78\",\"url\":\"https://static.crates.io/crates/windows_x86_64_gnu/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_x86_64_gnu\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"windows_x86_64_gnullvm 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_x86_64_gnullvm\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_x86_64_gnullvm\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d\",\"url\":\"https://static.crates.io/crates/windows_x86_64_gnullvm/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_x86_64_gnullvm\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"windows_x86_64_msvc 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_x86_64_msvc\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_x86_64_msvc\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec\",\"url\":\"https://static.crates.io/crates/windows_x86_64_msvc/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_x86_64_msvc\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"winnow 1.0.2\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"ascii\",\"binary\",\"default\",\"parser\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"winnow\",\"license\":\"MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\"],\"name\":\"winnow\",\"package_url\":\"https://github.com/winnow-rs/winnow\",\"repository\":{\"Http\":{\"sha256\":\"2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0\",\"url\":\"https://static.crates.io/crates/winnow/1.0.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"winnow\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.2\"},\"wit-bindgen 0.51.0\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2024\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"wit_bindgen\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wit-bindgen\",\"package_url\":\"https://github.com/bytecodealliance/wit-bindgen\",\"repository\":{\"Http\":{\"sha256\":\"d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5\",\"url\":\"https://static.crates.io/crates/wit-bindgen/0.51.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wit_bindgen\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.51.0\"},\"wit-bindgen 0.57.1\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2024\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"wit_bindgen\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wit-bindgen\",\"package_url\":\"https://github.com/bytecodealliance/wit-bindgen\",\"repository\":{\"Http\":{\"sha256\":\"1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e\",\"url\":\"https://static.crates.io/crates/wit-bindgen/0.57.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wit_bindgen\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.57.1\"},\"wit-bindgen-core 0.51.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"heck 0.5.0\",\"target\":\"heck\"},{\"id\":\"wit-parser 0.244.0\",\"target\":\"wit_parser\"}],\"edition\":\"2024\"},\"library_target_name\":\"wit_bindgen_core\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wit-bindgen-core\",\"package_url\":\"https://github.com/bytecodealliance/wit-bindgen\",\"repository\":{\"Http\":{\"sha256\":\"ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc\",\"url\":\"https://static.crates.io/crates/wit-bindgen-core/0.51.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wit_bindgen_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.51.0\"},\"wit-bindgen-rust 0.51.0\":{\"build_script_attrs\":{\"link_deps\":[{\"id\":\"prettyplease 0.2.37\",\"target\":\"prettyplease\"}]},\"common_attrs\":{\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"heck 0.5.0\",\"target\":\"heck\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"prettyplease 0.2.37\",\"target\":\"prettyplease\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"},{\"id\":\"wasm-metadata 0.244.0\",\"target\":\"wasm_metadata\"},{\"id\":\"wit-bindgen-core 0.51.0\",\"target\":\"wit_bindgen_core\"},{\"id\":\"wit-component 0.244.0\",\"target\":\"wit_component\"}],\"edition\":\"2024\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"wit_bindgen_rust\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wit-bindgen-rust\",\"package_url\":\"https://github.com/bytecodealliance/wit-bindgen\",\"repository\":{\"Http\":{\"sha256\":\"b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21\",\"url\":\"https://static.crates.io/crates/wit-bindgen-rust/0.51.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wit_bindgen_rust\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.51.0\"},\"wit-bindgen-rust-macro 0.51.0\":{\"build_script_attrs\":{\"link_deps\":[{\"id\":\"prettyplease 0.2.37\",\"target\":\"prettyplease\"}]},\"common_attrs\":{\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"prettyplease 0.2.37\",\"target\":\"prettyplease\"},{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"},{\"id\":\"wit-bindgen-core 0.51.0\",\"target\":\"wit_bindgen_core\"},{\"id\":\"wit-bindgen-rust 0.51.0\",\"target\":\"wit_bindgen_rust\"}],\"edition\":\"2024\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"wit_bindgen_rust_macro\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wit-bindgen-rust-macro\",\"package_url\":\"https://github.com/bytecodealliance/wit-bindgen\",\"repository\":{\"Http\":{\"sha256\":\"0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a\",\"url\":\"https://static.crates.io/crates/wit-bindgen-rust-macro/0.51.0/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"wit_bindgen_rust_macro\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.51.0\"},\"wit-component 0.244.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"bitflags 2.11.1\",\"target\":\"bitflags\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"log 0.4.29\",\"target\":\"log\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.149\",\"target\":\"serde_json\"},{\"id\":\"wasm-encoder 0.244.0\",\"target\":\"wasm_encoder\"},{\"id\":\"wasm-metadata 0.244.0\",\"target\":\"wasm_metadata\"},{\"id\":\"wasmparser 0.244.0\",\"target\":\"wasmparser\"},{\"id\":\"wit-parser 0.244.0\",\"target\":\"wit_parser\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"serde_derive 1.0.228\",\"target\":\"serde_derive\"}]},\"library_target_name\":\"wit_component\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wit-component\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wit-component\",\"repository\":{\"Http\":{\"sha256\":\"9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2\",\"url\":\"https://static.crates.io/crates/wit-component/0.244.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wit_component\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.244.0\"},\"wit-parser 0.244.0\":{\"common_attrs\":{\"crate_features\":[\"decoding\",\"default\",\"serde\",\"serde_json\"],\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"id-arena 2.3.0\",\"target\":\"id_arena\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"log 0.4.29\",\"target\":\"log\"},{\"id\":\"semver 1.0.28\",\"target\":\"semver\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.149\",\"target\":\"serde_json\"},{\"id\":\"unicode-xid 0.2.6\",\"target\":\"unicode_xid\"},{\"id\":\"wasmparser 0.244.0\",\"target\":\"wasmparser\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"serde_derive 1.0.228\",\"target\":\"serde_derive\"}]},\"library_target_name\":\"wit_parser\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wit-parser\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wit-parser\",\"repository\":{\"Http\":{\"sha256\":\"ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736\",\"url\":\"https://static.crates.io/crates/wit-parser/0.244.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wit_parser\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.244.0\"},\"writeable 0.6.3\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"writeable\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"writeable\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4\",\"url\":\"https://static.crates.io/crates/writeable/0.6.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"writeable\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.3\"},\"xattr 1.6.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"unsupported\"],\"deps\":{\"common\":[],\"selects\":{\"cfg(any(target_os = \\\"android\\\", target_os = \\\"linux\\\", target_os = \\\"macos\\\", target_os = \\\"hurd\\\"))\":[{\"id\":\"rustix 1.1.4\",\"target\":\"rustix\"}],\"cfg(any(target_os = \\\"freebsd\\\", target_os = \\\"netbsd\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"xattr\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"xattr\",\"package_url\":\"https://github.com/Stebalien/xattr\",\"repository\":{\"Http\":{\"sha256\":\"32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156\",\"url\":\"https://static.crates.io/crates/xattr/1.6.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"xattr\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.6.1\"},\"xxhash-rust 0.8.15\":{\"common_attrs\":{\"crate_features\":[\"xxh64\"],\"edition\":\"2018\"},\"library_target_name\":\"xxhash_rust\",\"license\":\"BSL-1.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"BSL-1.0\"],\"name\":\"xxhash-rust\",\"package_url\":\"https://github.com/DoumanAsh/xxhash-rust\",\"repository\":{\"Http\":{\"sha256\":\"fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3\",\"url\":\"https://static.crates.io/crates/xxhash-rust/0.8.15/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"xxhash_rust\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.15\"},\"yoke 0.8.2\":{\"common_attrs\":{\"crate_features\":[\"derive\",\"zerofrom\"],\"deps\":[{\"id\":\"stable_deref_trait 1.2.1\",\"target\":\"stable_deref_trait\"},{\"id\":\"zerofrom 0.1.7\",\"target\":\"zerofrom\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"yoke-derive 0.8.2\",\"target\":\"yoke_derive\"}]},\"library_target_name\":\"yoke\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"yoke\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca\",\"url\":\"https://static.crates.io/crates/yoke/0.8.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"yoke\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.2\"},\"yoke-derive 0.8.2\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"},{\"id\":\"synstructure 0.13.2\",\"target\":\"synstructure\"}],\"edition\":\"2021\"},\"library_target_name\":\"yoke_derive\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"yoke-derive\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e\",\"url\":\"https://static.crates.io/crates/yoke-derive/0.8.2/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"yoke_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.2\"},\"zerocopy 0.8.48\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"derive\",\"simd\",\"zerocopy-derive\"],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":[{\"id\":\"zerocopy-derive 0.8.48\",\"target\":\"zerocopy_derive\"}]},\"library_target_name\":\"zerocopy\",\"license\":\"BSD-2-Clause OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"BSD-2-Clause\",\"MIT\"],\"name\":\"zerocopy\",\"package_url\":\"https://github.com/google/zerocopy\",\"repository\":{\"Http\":{\"sha256\":\"eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9\",\"url\":\"https://static.crates.io/crates/zerocopy/0.8.48/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"zerocopy\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.8.48\"},\"zerocopy-derive 0.8.48\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"zerocopy_derive\",\"license\":\"BSD-2-Clause OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"BSD-2-Clause\",\"MIT\"],\"name\":\"zerocopy-derive\",\"package_url\":\"https://github.com/google/zerocopy\",\"repository\":{\"Http\":{\"sha256\":\"70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4\",\"url\":\"https://static.crates.io/crates/zerocopy-derive/0.8.48/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"zerocopy_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.48\"},\"zerofrom 0.1.7\":{\"common_attrs\":{\"crate_features\":[\"derive\"],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"zerofrom-derive 0.1.7\",\"target\":\"zerofrom_derive\"}]},\"library_target_name\":\"zerofrom\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"zerofrom\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df\",\"url\":\"https://static.crates.io/crates/zerofrom/0.1.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"zerofrom\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.7\"},\"zerofrom-derive 0.1.7\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"},{\"id\":\"synstructure 0.13.2\",\"target\":\"synstructure\"}],\"edition\":\"2021\"},\"library_target_name\":\"zerofrom_derive\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"zerofrom-derive\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1\",\"url\":\"https://static.crates.io/crates/zerofrom-derive/0.1.7/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"zerofrom_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.7\"},\"zerotrie 0.2.4\":{\"common_attrs\":{\"crate_features\":[\"yoke\",\"zerofrom\"],\"deps\":[{\"id\":\"yoke 0.8.2\",\"target\":\"yoke\"},{\"id\":\"zerofrom 0.1.7\",\"target\":\"zerofrom\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"displaydoc 0.2.5\",\"target\":\"displaydoc\"}]},\"library_target_name\":\"zerotrie\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"zerotrie\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf\",\"url\":\"https://static.crates.io/crates/zerotrie/0.2.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"zerotrie\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.4\"},\"zerovec 0.11.6\":{\"common_attrs\":{\"crate_features\":[\"derive\",\"yoke\"],\"deps\":[{\"id\":\"yoke 0.8.2\",\"target\":\"yoke\"},{\"id\":\"zerofrom 0.1.7\",\"target\":\"zerofrom\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"zerovec-derive 0.11.3\",\"target\":\"zerovec_derive\"}]},\"library_target_name\":\"zerovec\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"zerovec\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239\",\"url\":\"https://static.crates.io/crates/zerovec/0.11.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"zerovec\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.11.6\"},\"zerovec-derive 0.11.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"zerovec_derive\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"zerovec-derive\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555\",\"url\":\"https://static.crates.io/crates/zerovec-derive/0.11.3/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"zerovec_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.11.3\"},\"zmij 1.0.21\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"zmij\",\"license\":\"MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\"],\"name\":\"zmij\",\"package_url\":\"https://github.com/dtolnay/zmij\",\"repository\":{\"Http\":{\"sha256\":\"b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa\",\"url\":\"https://static.crates.io/crates/zmij/1.0.21/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"zmij\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.21\"},\"zstd 0.13.3\":{\"common_attrs\":{\"crate_features\":[\"arrays\",\"default\",\"legacy\",\"zdict_builder\"],\"deps\":[{\"id\":\"zstd-safe 7.2.4\",\"target\":\"zstd_safe\"}],\"edition\":\"2018\"},\"library_target_name\":\"zstd\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"zstd\",\"package_url\":\"https://github.com/gyscos/zstd-rs\",\"repository\":{\"Http\":{\"sha256\":\"e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a\",\"url\":\"https://static.crates.io/crates/zstd/0.13.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"zstd\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.13.3\"},\"zstd-safe 7.2.4\":{\"build_script_attrs\":{\"link_deps\":[{\"id\":\"zstd-sys 2.0.16+zstd.1.5.7\",\"target\":\"zstd_sys\"}]},\"common_attrs\":{\"crate_features\":[\"arrays\",\"legacy\",\"std\",\"zdict_builder\"],\"deps\":[{\"id\":\"zstd-sys 2.0.16+zstd.1.5.7\",\"target\":\"zstd_sys\"}],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"zstd_safe\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"zstd-safe\",\"package_url\":\"https://github.com/gyscos/zstd-rs\",\"repository\":{\"Http\":{\"sha256\":\"8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d\",\"url\":\"https://static.crates.io/crates/zstd-safe/7.2.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"zstd_safe\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"7.2.4\"},\"zstd-sys 2.0.16+zstd.1.5.7\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"cc 1.2.60\",\"target\":\"cc\"},{\"id\":\"pkg-config 0.3.33\",\"target\":\"pkg_config\"}],\"links\":\"zstd\"},\"common_attrs\":{\"crate_features\":[\"legacy\",\"std\",\"zdict_builder\"],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"zstd_sys\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"zstd-sys\",\"package_url\":\"https://github.com/gyscos/zstd-rs\",\"repository\":{\"Http\":{\"sha256\":\"91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748\",\"url\":\"https://static.crates.io/crates/zstd-sys/2.0.16+zstd.1.5.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"zstd_sys\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"2.0.16+zstd.1.5.7\"}},\"direct_deps\":[\"anyhow 1.0.102\",\"async-trait 0.1.89\",\"hex 0.4.3\",\"libc 0.2.186\",\"serde 1.0.228\",\"serde_json 1.0.149\",\"sha2 0.11.0\",\"tempfile 3.27.0\",\"tokio 1.52.1\",\"tracing 0.1.44\",\"wasmer 7.2.0-alpha.2\",\"wasmer-types 7.2.0-alpha.2\",\"wasmer-vm 7.2.0-alpha.2\",\"wasmer-wasix 0.702.0-alpha.2\"],\"direct_dev_deps\":[\"futures 0.3.32\",\"wat 1.247.0\"],\"workspace_members\":{\"oliphaunt-wasix-postmaster-executor 7.2.0-alpha.2\":\"\"}}", + "anyhow-1.0.102/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"anyhow-1.0.102\",\n actual = \"@postmaster_executor_crates__anyhow-1.0.102//:anyhow\",\n tags = [\"manual\"],\n)\n", + "anyhow/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"anyhow\",\n actual = \"@postmaster_executor_crates__anyhow-1.0.102//:anyhow\",\n tags = [\"manual\"],\n)\n", + "async-trait-0.1.89/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"async-trait-0.1.89\",\n actual = \"@postmaster_executor_crates__async-trait-0.1.89//:async_trait\",\n tags = [\"manual\"],\n)\n", + "async-trait/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"async-trait\",\n actual = \"@postmaster_executor_crates__async-trait-0.1.89//:async_trait\",\n tags = [\"manual\"],\n)\n", + "futures-0.3.32/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"futures-0.3.32\",\n actual = \"@postmaster_executor_crates__futures-0.3.32//:futures\",\n tags = [\"manual\"],\n)\n", + "futures/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"futures\",\n actual = \"@postmaster_executor_crates__futures-0.3.32//:futures\",\n tags = [\"manual\"],\n)\n", + "hex-0.4.3/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"hex-0.4.3\",\n actual = \"@postmaster_executor_crates__hex-0.4.3//:hex\",\n tags = [\"manual\"],\n)\n", + "hex/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"hex\",\n actual = \"@postmaster_executor_crates__hex-0.4.3//:hex\",\n tags = [\"manual\"],\n)\n", + "libc-0.2.186/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"libc-0.2.186\",\n actual = \"@postmaster_executor_crates__libc-0.2.186//:libc\",\n tags = [\"manual\"],\n)\n", + "libc/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"libc\",\n actual = \"@postmaster_executor_crates__libc-0.2.186//:libc\",\n tags = [\"manual\"],\n)\n", + "serde-1.0.228/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"serde-1.0.228\",\n actual = \"@postmaster_executor_crates__serde-1.0.228//:serde\",\n tags = [\"manual\"],\n)\n", + "serde/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"serde\",\n actual = \"@postmaster_executor_crates__serde-1.0.228//:serde\",\n tags = [\"manual\"],\n)\n", + "serde_json-1.0.149/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"serde_json-1.0.149\",\n actual = \"@postmaster_executor_crates__serde_json-1.0.149//:serde_json\",\n tags = [\"manual\"],\n)\n", + "serde_json/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"serde_json\",\n actual = \"@postmaster_executor_crates__serde_json-1.0.149//:serde_json\",\n tags = [\"manual\"],\n)\n", + "sha2-0.11.0/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"sha2-0.11.0\",\n actual = \"@postmaster_executor_crates__sha2-0.11.0//:sha2\",\n tags = [\"manual\"],\n)\n", + "sha2/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"sha2\",\n actual = \"@postmaster_executor_crates__sha2-0.11.0//:sha2\",\n tags = [\"manual\"],\n)\n", + "tempfile-3.27.0/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"tempfile-3.27.0\",\n actual = \"@postmaster_executor_crates__tempfile-3.27.0//:tempfile\",\n tags = [\"manual\"],\n)\n", + "tempfile/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"tempfile\",\n actual = \"@postmaster_executor_crates__tempfile-3.27.0//:tempfile\",\n tags = [\"manual\"],\n)\n", + "tokio-1.52.1/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"tokio-1.52.1\",\n actual = \"@postmaster_executor_crates__tokio-1.52.1//:tokio\",\n tags = [\"manual\"],\n)\n", + "tokio/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"tokio\",\n actual = \"@postmaster_executor_crates__tokio-1.52.1//:tokio\",\n tags = [\"manual\"],\n)\n", + "tracing-0.1.44/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"tracing-0.1.44\",\n actual = \"@postmaster_executor_crates__tracing-0.1.44//:tracing\",\n tags = [\"manual\"],\n)\n", + "tracing/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"tracing\",\n actual = \"@postmaster_executor_crates__tracing-0.1.44//:tracing\",\n tags = [\"manual\"],\n)\n", + "wasmer-7.2.0-alpha.2/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-7.2.0-alpha.2\",\n actual = \"@postmaster_executor_crates__wasmer-7.2.0-alpha.2//:wasmer\",\n tags = [\"manual\"],\n)\n", + "wasmer/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer\",\n actual = \"@postmaster_executor_crates__wasmer-7.2.0-alpha.2//:wasmer\",\n tags = [\"manual\"],\n)\n", + "wasmer-types-7.2.0-alpha.2/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-types-7.2.0-alpha.2\",\n actual = \"@postmaster_executor_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\",\n tags = [\"manual\"],\n)\n", + "wasmer-types/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-types\",\n actual = \"@postmaster_executor_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\",\n tags = [\"manual\"],\n)\n", + "wasmer-vm-7.2.0-alpha.2/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-vm-7.2.0-alpha.2\",\n actual = \"@postmaster_executor_crates__wasmer-vm-7.2.0-alpha.2//:wasmer_vm\",\n tags = [\"manual\"],\n)\n", + "wasmer-vm/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-vm\",\n actual = \"@postmaster_executor_crates__wasmer-vm-7.2.0-alpha.2//:wasmer_vm\",\n tags = [\"manual\"],\n)\n", + "wasmer-wasix-0.702.0-alpha.2/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-wasix-0.702.0-alpha.2\",\n actual = \"@postmaster_executor_crates__wasmer-wasix-0.702.0-alpha.2//:wasmer_wasix\",\n tags = [\"manual\"],\n)\n", + "wasmer-wasix/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-wasix\",\n actual = \"@postmaster_executor_crates__wasmer-wasix-0.702.0-alpha.2//:wasmer_wasix\",\n tags = [\"manual\"],\n)\n", + "wat-1.247.0/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wat-1.247.0\",\n actual = \"@postmaster_executor_crates__wat-1.247.0//:wat\",\n tags = [\"manual\"],\n)\n", + "wat/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wat\",\n actual = \"@postmaster_executor_crates__wat-1.247.0//:wat\",\n tags = [\"manual\"],\n)\n" + } + } + }, + "postmaster_executor_crates__addr2line-0.25.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/addr2line/0.25.1/download" + ], + "strip_prefix": "addr2line-0.25.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"addr2line\",\n deps = [\n \"@postmaster_executor_crates__gimli-0.32.3//:gimli\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=addr2line\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.25.1\",\n)\n" + } + }, + "postmaster_executor_crates__adler2-2.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/adler2/2.0.1/download" + ], + "strip_prefix": "adler2-2.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"adler2\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=adler2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.1\",\n)\n" + } + }, + "postmaster_executor_crates__aho-corasick-1.1.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/aho-corasick/1.1.4/download" + ], + "strip_prefix": "aho-corasick-1.1.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"aho_corasick\",\n deps = [\n \"@postmaster_executor_crates__memchr-2.8.0//:memchr\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"perf-literal\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=aho-corasick\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.4\",\n)\n" + } + }, + "postmaster_executor_crates__any_ascii-0.1.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "70033777eb8b5124a81a1889416543dddef2de240019b674c81285a2635a7e1e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/any_ascii/0.1.7/download" + ], + "strip_prefix": "any_ascii-0.1.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"any_ascii\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=any_ascii\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.7\",\n)\n" + } + }, + "postmaster_executor_crates__anyhow-1.0.102": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/anyhow/1.0.102/download" + ], + "strip_prefix": "anyhow-1.0.102", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"anyhow\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=anyhow\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.102\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"anyhow\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=anyhow\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.102\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__arrayref-0.3.9": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/arrayref/0.3.9/download" + ], + "strip_prefix": "arrayref-0.3.9", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"arrayref\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=arrayref\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.9\",\n)\n" + } + }, + "postmaster_executor_crates__arrayvec-0.7.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/arrayvec/0.7.6/download" + ], + "strip_prefix": "arrayvec-0.7.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"arrayvec\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=arrayvec\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.6\",\n)\n" + } + }, + "postmaster_executor_crates__async-trait-0.1.89": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/async-trait/0.1.89/download" + ], + "strip_prefix": "async-trait-0.1.89", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"async_trait\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=async-trait\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.89\",\n)\n" + } + }, + "postmaster_executor_crates__autocfg-1.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/autocfg/1.5.0/download" + ], + "strip_prefix": "autocfg-1.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"autocfg\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=autocfg\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.5.0\",\n)\n" + } + }, + "postmaster_executor_crates__backtrace-0.3.76": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/backtrace/0.3.76/download" + ], + "strip_prefix": "backtrace-0.3.76", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"backtrace\",\n deps = [\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_executor_crates__rustc-demangle-0.1.27//:rustc_demangle\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__addr2line-0.25.1//:addr2line\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@postmaster_executor_crates__miniz_oxide-0.8.9//:miniz_oxide\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@postmaster_executor_crates__object-0.37.3//:object\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__addr2line-0.25.1//:addr2line\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@postmaster_executor_crates__miniz_oxide-0.8.9//:miniz_oxide\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@postmaster_executor_crates__object-0.37.3//:object\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__addr2line-0.25.1//:addr2line\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@postmaster_executor_crates__miniz_oxide-0.8.9//:miniz_oxide\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@postmaster_executor_crates__object-0.37.3//:object\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=backtrace\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.76\",\n)\n" + } + }, + "postmaster_executor_crates__base64-0.22.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/base64/0.22.1/download" + ], + "strip_prefix": "base64-0.22.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"base64\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=base64\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.22.1\",\n)\n" + } + }, + "postmaster_executor_crates__bincode-2.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bincode/2.0.1/download" + ], + "strip_prefix": "bincode-2.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bincode\",\n deps = [\n \"@postmaster_executor_crates__serde-1.0.228//:serde\",\n \"@postmaster_executor_crates__unty-0.0.4//:unty\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__bincode_derive-2.0.1//:bincode_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"bincode_derive\",\n \"default\",\n \"derive\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bincode\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.1\",\n)\n" + } + }, + "postmaster_executor_crates__bincode_derive-2.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bincode_derive/2.0.1/download" + ], + "strip_prefix": "bincode_derive-2.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"bincode_derive\",\n deps = [\n \"@postmaster_executor_crates__virtue-0.0.18//:virtue\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bincode_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.1\",\n)\n" + } + }, + "postmaster_executor_crates__bindgen-0.72.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bindgen/0.72.1/download" + ], + "strip_prefix": "bindgen-0.72.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bindgen\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__bitflags-2.11.1//:bitflags\",\n \"@postmaster_executor_crates__cexpr-0.6.0//:cexpr\",\n \"@postmaster_executor_crates__clang-sys-1.8.1//:clang_sys\",\n \"@postmaster_executor_crates__itertools-0.13.0//:itertools\",\n \"@postmaster_executor_crates__log-0.4.29//:log\",\n \"@postmaster_executor_crates__prettyplease-0.2.37//:prettyplease\",\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__regex-1.12.3//:regex\",\n \"@postmaster_executor_crates__rustc-hash-2.1.2//:rustc_hash\",\n \"@postmaster_executor_crates__shlex-1.3.0//:shlex\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"logging\",\n \"prettyplease\",\n \"runtime\",\n ],\n crate_root = \"lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bindgen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.72.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"logging\",\n \"prettyplease\",\n \"runtime\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n link_deps = [\n \"@postmaster_executor_crates__clang-sys-1.8.1//:clang_sys\",\n \"@postmaster_executor_crates__prettyplease-0.2.37//:prettyplease\",\n ],\n edition = \"2021\",\n pkg_name = \"bindgen\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bindgen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.72.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__bitflags-1.3.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bitflags/1.3.2/download" + ], + "strip_prefix": "bitflags-1.3.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bitflags\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bitflags\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.3.2\",\n)\n" + } + }, + "postmaster_executor_crates__bitflags-2.11.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bitflags/2.11.1/download" + ], + "strip_prefix": "bitflags-2.11.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bitflags\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bitflags\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.11.1\",\n)\n" + } + }, + "postmaster_executor_crates__blake3-1.8.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4d2d5991425dfd0785aed03aedcf0b321d61975c9b5b3689c774a2610ae0b51e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/blake3/1.8.4/download" + ], + "strip_prefix": "blake3-1.8.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"blake3\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__arrayref-0.3.9//:arrayref\",\n \"@postmaster_executor_crates__arrayvec-0.7.6//:arrayvec\",\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_executor_crates__constant_time_eq-0.4.2//:constant_time_eq\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__cpufeatures-0.3.0//:cpufeatures\", # cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=blake3\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.8.4\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@postmaster_executor_crates__cc-1.2.60//:cc\",\n ],\n emit_warnings = False,\n edition = \"2024\",\n pkg_name = \"blake3\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=blake3\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.8.4\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__block-buffer-0.10.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/block-buffer/0.10.4/download" + ], + "strip_prefix": "block-buffer-0.10.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"block_buffer\",\n deps = [\n \"@postmaster_executor_crates__generic-array-0.14.7//:generic_array\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=block-buffer\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.4\",\n)\n" + } + }, + "postmaster_executor_crates__block-buffer-0.12.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/block-buffer/0.12.0/download" + ], + "strip_prefix": "block-buffer-0.12.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"block_buffer\",\n deps = [\n \"@postmaster_executor_crates__hybrid-array-0.4.10//:hybrid_array\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=block-buffer\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.12.0\",\n)\n" + } + }, + "postmaster_executor_crates__bstr-1.12.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bstr/1.12.1/download" + ], + "strip_prefix": "bstr-1.12.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bstr\",\n deps = [\n \"@postmaster_executor_crates__memchr-2.8.0//:memchr\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bstr\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.12.1\",\n)\n" + } + }, + "postmaster_executor_crates__bumpalo-3.20.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bumpalo/3.20.2/download" + ], + "strip_prefix": "bumpalo-3.20.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bumpalo\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bumpalo\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"3.20.2\",\n)\n" + } + }, + "postmaster_executor_crates__bytecheck-0.8.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0caa33a2c0edca0419d15ac723dff03f1956f7978329b1e3b5fdaaaed9d3ca8b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bytecheck/0.8.2/download" + ], + "strip_prefix": "bytecheck-0.8.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bytecheck\",\n deps = [\n \"@postmaster_executor_crates__ptr_meta-0.3.1//:ptr_meta\",\n \"@postmaster_executor_crates__rancor-0.1.1//:rancor\",\n \"@postmaster_executor_crates__simdutf8-0.1.5//:simdutf8\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__bytecheck_derive-0.8.2//:bytecheck_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"simdutf8\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bytecheck\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.2\",\n)\n" + } + }, + "postmaster_executor_crates__bytecheck_derive-0.8.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "89385e82b5d1821d2219e0b095efa2cc1f246cbf99080f3be46a1a85c0d392d9", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bytecheck_derive/0.8.2/download" + ], + "strip_prefix": "bytecheck_derive-0.8.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"bytecheck_derive\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bytecheck_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.2\",\n)\n" + } + }, + "postmaster_executor_crates__byteorder-1.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/byteorder/1.5.0/download" + ], + "strip_prefix": "byteorder-1.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"byteorder\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=byteorder\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.5.0\",\n)\n" + } + }, + "postmaster_executor_crates__bytes-1.11.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bytes/1.11.1/download" + ], + "strip_prefix": "bytes-1.11.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bytes\",\n deps = [\n \"@postmaster_executor_crates__serde-1.0.228//:serde\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bytes\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.11.1\",\n)\n" + } + }, + "postmaster_executor_crates__bytesize-2.3.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6bd91ee7b2422bcb158d90ef4d14f75ef67f340943fc4149891dcce8f8b972a3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bytesize/2.3.1/download" + ], + "strip_prefix": "bytesize-2.3.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bytesize\",\n deps = [\n \"@postmaster_executor_crates__serde_core-1.0.228//:serde_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bytesize\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.3.1\",\n)\n" + } + }, + "postmaster_executor_crates__cc-1.2.60": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cc/1.2.60/download" + ], + "strip_prefix": "cc-1.2.60", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cc\",\n deps = [\n \"@postmaster_executor_crates__find-msvc-tools-0.1.9//:find_msvc_tools\",\n \"@postmaster_executor_crates__jobserver-0.1.34//:jobserver\",\n \"@postmaster_executor_crates__libc-0.2.186//:libc\",\n \"@postmaster_executor_crates__shlex-1.3.0//:shlex\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"parallel\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.60\",\n)\n" + } + }, + "postmaster_executor_crates__cexpr-0.6.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cexpr/0.6.0/download" + ], + "strip_prefix": "cexpr-0.6.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cexpr\",\n deps = [\n \"@postmaster_executor_crates__nom-7.1.3//:nom\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cexpr\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.0\",\n)\n" + } + }, + "postmaster_executor_crates__cfg-if-1.0.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cfg-if/1.0.4/download" + ], + "strip_prefix": "cfg-if-1.0.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cfg_if\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cfg-if\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.4\",\n)\n" + } + }, + "postmaster_executor_crates__chacha20-0.10.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/chacha20/0.10.0/download" + ], + "strip_prefix": "chacha20-0.10.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"chacha20\",\n deps = [\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_executor_crates__rand_core-0.10.1//:rand_core\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__cpufeatures-0.3.0//:cpufeatures\", # cfg(any(target_arch = \"x86_64\", target_arch = \"x86\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"rng\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=chacha20\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.0\",\n)\n" + } + }, + "postmaster_executor_crates__chrono-0.4.44": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/chrono/0.4.44/download" + ], + "strip_prefix": "chrono-0.4.44", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"chrono\",\n deps = [\n \"@postmaster_executor_crates__num-traits-0.2.19//:num_traits\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=chrono\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.44\",\n)\n" + } + }, + "postmaster_executor_crates__ciborium-0.2.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ciborium/0.2.2/download" + ], + "strip_prefix": "ciborium-0.2.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ciborium\",\n deps = [\n \"@postmaster_executor_crates__ciborium-io-0.2.2//:ciborium_io\",\n \"@postmaster_executor_crates__ciborium-ll-0.2.2//:ciborium_ll\",\n \"@postmaster_executor_crates__serde-1.0.228//:serde\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ciborium\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.2\",\n)\n" + } + }, + "postmaster_executor_crates__ciborium-io-0.2.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ciborium-io/0.2.2/download" + ], + "strip_prefix": "ciborium-io-0.2.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ciborium_io\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ciborium-io\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.2\",\n)\n" + } + }, + "postmaster_executor_crates__ciborium-ll-0.2.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ciborium-ll/0.2.2/download" + ], + "strip_prefix": "ciborium-ll-0.2.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ciborium_ll\",\n deps = [\n \"@postmaster_executor_crates__ciborium-io-0.2.2//:ciborium_io\",\n \"@postmaster_executor_crates__half-2.7.1//:half\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ciborium-ll\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.2\",\n)\n" + } + }, + "postmaster_executor_crates__clang-sys-1.8.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/clang-sys/1.8.1/download" + ], + "strip_prefix": "clang-sys-1.8.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"clang_sys\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__glob-0.3.3//:glob\",\n \"@postmaster_executor_crates__libc-0.2.186//:libc\",\n \"@postmaster_executor_crates__libloading-0.8.9//:libloading\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"clang_10_0\",\n \"clang_11_0\",\n \"clang_3_5\",\n \"clang_3_6\",\n \"clang_3_7\",\n \"clang_3_8\",\n \"clang_3_9\",\n \"clang_4_0\",\n \"clang_5_0\",\n \"clang_6_0\",\n \"clang_7_0\",\n \"clang_8_0\",\n \"clang_9_0\",\n \"libloading\",\n \"runtime\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=clang-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.8.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"clang_10_0\",\n \"clang_11_0\",\n \"clang_3_5\",\n \"clang_3_6\",\n \"clang_3_7\",\n \"clang_3_8\",\n \"clang_3_9\",\n \"clang_4_0\",\n \"clang_5_0\",\n \"clang_6_0\",\n \"clang_7_0\",\n \"clang_8_0\",\n \"clang_9_0\",\n \"libloading\",\n \"runtime\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@postmaster_executor_crates__glob-0.3.3//:glob\",\n ],\n emit_warnings = False,\n edition = \"2021\",\n links = \"clang\",\n pkg_name = \"clang-sys\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=clang-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.8.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__cmake-0.1.58": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cmake/0.1.58/download" + ], + "strip_prefix": "cmake-0.1.58", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cmake\",\n deps = [\n \"@postmaster_executor_crates__cc-1.2.60//:cc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cmake\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.58\",\n)\n" + } + }, + "postmaster_executor_crates__console-0.16.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/console/0.16.3/download" + ], + "strip_prefix": "console-0.16.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"console\",\n deps = [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=console\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.16.3\",\n)\n" + } + }, + "postmaster_executor_crates__const-oid-0.10.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/const-oid/0.10.2/download" + ], + "strip_prefix": "const-oid-0.10.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"const_oid\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=const-oid\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.2\",\n)\n" + } + }, + "postmaster_executor_crates__constant_time_eq-0.4.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/constant_time_eq/0.4.2/download" + ], + "strip_prefix": "constant_time_eq-0.4.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"constant_time_eq\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=constant_time_eq\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.2\",\n)\n" + } + }, + "postmaster_executor_crates__convert_case-0.10.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/convert_case/0.10.0/download" + ], + "strip_prefix": "convert_case-0.10.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"convert_case\",\n deps = [\n \"@postmaster_executor_crates__unicode-segmentation-1.13.2//:unicode_segmentation\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=convert_case\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.0\",\n)\n" + } + }, + "postmaster_executor_crates__cooked-waker-5.0.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cooked-waker/5.0.0/download" + ], + "strip_prefix": "cooked-waker-5.0.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cooked_waker\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cooked-waker\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"5.0.0\",\n)\n" + } + }, + "postmaster_executor_crates__corosensei-0.3.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2c54787b605c7df106ceccf798df23da4f2e09918defad66705d1cedf3bb914f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/corosensei/0.3.3/download" + ], + "strip_prefix": "corosensei-0.3.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"corosensei\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_executor_crates__libc-0.2.186//:libc\",\n \"@postmaster_executor_crates__scopeguard-1.2.0//:scopeguard\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"default-stack\",\n \"libc\",\n \"unwind\",\n \"windows-sys\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=corosensei\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.3\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"default-stack\",\n \"libc\",\n \"unwind\",\n \"windows-sys\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@postmaster_executor_crates__autocfg-1.5.0//:autocfg\",\n ],\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"corosensei\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=corosensei\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.3.3\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__cpp_demangle-0.4.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f2bb79cb74d735044c972aae58ed0aaa9a837e85b01106a54c39e42e97f62253", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cpp_demangle/0.4.5/download" + ], + "strip_prefix": "cpp_demangle-0.4.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cpp_demangle\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cpp_demangle\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.5\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"cpp_demangle\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cpp_demangle\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.4.5\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__cpufeatures-0.2.17": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cpufeatures/0.2.17/download" + ], + "strip_prefix": "cpufeatures-0.2.17", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cpufeatures\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(all(target_arch = \"aarch64\", target_vendor = \"apple\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(all(target_arch = \"aarch64\", target_os = \"linux\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cpufeatures\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.17\",\n)\n" + } + }, + "postmaster_executor_crates__cpufeatures-0.3.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cpufeatures/0.3.0/download" + ], + "strip_prefix": "cpufeatures-0.3.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cpufeatures\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(all(target_arch = \"aarch64\", target_vendor = \"apple\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(all(target_arch = \"aarch64\", target_os = \"linux\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cpufeatures\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.0\",\n)\n" + } + }, + "postmaster_executor_crates__crc32fast-1.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crc32fast/1.5.0/download" + ], + "strip_prefix": "crc32fast-1.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crc32fast\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crc32fast\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.5.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"crc32fast\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crc32fast\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.5.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__crossbeam-channel-0.5.15": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crossbeam-channel/0.5.15/download" + ], + "strip_prefix": "crossbeam-channel-0.5.15", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crossbeam_channel\",\n deps = [\n \"@postmaster_executor_crates__crossbeam-utils-0.8.21//:crossbeam_utils\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crossbeam-channel\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.15\",\n)\n" + } + }, + "postmaster_executor_crates__crossbeam-deque-0.8.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crossbeam-deque/0.8.6/download" + ], + "strip_prefix": "crossbeam-deque-0.8.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crossbeam_deque\",\n deps = [\n \"@postmaster_executor_crates__crossbeam-epoch-0.9.18//:crossbeam_epoch\",\n \"@postmaster_executor_crates__crossbeam-utils-0.8.21//:crossbeam_utils\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crossbeam-deque\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.6\",\n)\n" + } + }, + "postmaster_executor_crates__crossbeam-epoch-0.9.18": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crossbeam-epoch/0.9.18/download" + ], + "strip_prefix": "crossbeam-epoch-0.9.18", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crossbeam_epoch\",\n deps = [\n \"@postmaster_executor_crates__crossbeam-utils-0.8.21//:crossbeam_utils\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crossbeam-epoch\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.18\",\n)\n" + } + }, + "postmaster_executor_crates__crossbeam-queue-0.3.12": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crossbeam-queue/0.3.12/download" + ], + "strip_prefix": "crossbeam-queue-0.3.12", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crossbeam_queue\",\n deps = [\n \"@postmaster_executor_crates__crossbeam-utils-0.8.21//:crossbeam_utils\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crossbeam-queue\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.12\",\n)\n" + } + }, + "postmaster_executor_crates__crossbeam-utils-0.8.21": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crossbeam-utils/0.8.21/download" + ], + "strip_prefix": "crossbeam-utils-0.8.21", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crossbeam_utils\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crossbeam-utils\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.21\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"crossbeam-utils\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crossbeam-utils\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.8.21\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__crunchy-0.2.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crunchy/0.2.4/download" + ], + "strip_prefix": "crunchy-0.2.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crunchy\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crunchy\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.4\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"crunchy\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crunchy\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.2.4\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__crypto-common-0.1.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crypto-common/0.1.7/download" + ], + "strip_prefix": "crypto-common-0.1.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crypto_common\",\n deps = [\n \"@postmaster_executor_crates__generic-array-0.14.7//:generic_array\",\n \"@postmaster_executor_crates__typenum-1.20.0//:typenum\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crypto-common\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.7\",\n)\n" + } + }, + "postmaster_executor_crates__crypto-common-0.2.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crypto-common/0.2.1/download" + ], + "strip_prefix": "crypto-common-0.2.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crypto_common\",\n deps = [\n \"@postmaster_executor_crates__hybrid-array-0.4.10//:hybrid_array\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crypto-common\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.1\",\n)\n" + } + }, + "postmaster_executor_crates__darling-0.20.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/darling/0.20.11/download" + ], + "strip_prefix": "darling-0.20.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"darling\",\n deps = [\n \"@postmaster_executor_crates__darling_core-0.20.11//:darling_core\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__darling_macro-0.20.11//:darling_macro\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"suggestions\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=darling\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.20.11\",\n)\n" + } + }, + "postmaster_executor_crates__darling-0.21.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/darling/0.21.3/download" + ], + "strip_prefix": "darling-0.21.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"darling\",\n deps = [\n \"@postmaster_executor_crates__darling_core-0.21.3//:darling_core\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__darling_macro-0.21.3//:darling_macro\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=darling\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.21.3\",\n)\n" + } + }, + "postmaster_executor_crates__darling_core-0.20.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/darling_core/0.20.11/download" + ], + "strip_prefix": "darling_core-0.20.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"darling_core\",\n deps = [\n \"@postmaster_executor_crates__fnv-1.0.7//:fnv\",\n \"@postmaster_executor_crates__ident_case-1.0.1//:ident_case\",\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__strsim-0.11.1//:strsim\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"strsim\",\n \"suggestions\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=darling_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.20.11\",\n)\n" + } + }, + "postmaster_executor_crates__darling_core-0.21.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/darling_core/0.21.3/download" + ], + "strip_prefix": "darling_core-0.21.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"darling_core\",\n deps = [\n \"@postmaster_executor_crates__fnv-1.0.7//:fnv\",\n \"@postmaster_executor_crates__ident_case-1.0.1//:ident_case\",\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=darling_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.21.3\",\n)\n" + } + }, + "postmaster_executor_crates__darling_macro-0.20.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/darling_macro/0.20.11/download" + ], + "strip_prefix": "darling_macro-0.20.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"darling_macro\",\n deps = [\n \"@postmaster_executor_crates__darling_core-0.20.11//:darling_core\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=darling_macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.20.11\",\n)\n" + } + }, + "postmaster_executor_crates__darling_macro-0.21.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/darling_macro/0.21.3/download" + ], + "strip_prefix": "darling_macro-0.21.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"darling_macro\",\n deps = [\n \"@postmaster_executor_crates__darling_core-0.21.3//:darling_core\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=darling_macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.21.3\",\n)\n" + } + }, + "postmaster_executor_crates__dashmap-6.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/dashmap/6.1.0/download" + ], + "strip_prefix": "dashmap-6.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"dashmap\",\n deps = [\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_executor_crates__crossbeam-utils-0.8.21//:crossbeam_utils\",\n \"@postmaster_executor_crates__hashbrown-0.14.5//:hashbrown\",\n \"@postmaster_executor_crates__lock_api-0.4.14//:lock_api\",\n \"@postmaster_executor_crates__once_cell-1.21.4//:once_cell\",\n \"@postmaster_executor_crates__parking_lot_core-0.9.12//:parking_lot_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=dashmap\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"6.1.0\",\n)\n" + } + }, + "postmaster_executor_crates__debugid-0.8.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/debugid/0.8.0/download" + ], + "strip_prefix": "debugid-0.8.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"debugid\",\n deps = [\n \"@postmaster_executor_crates__uuid-1.23.1//:uuid\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=debugid\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.0\",\n)\n" + } + }, + "postmaster_executor_crates__defmt-0.3.100": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/defmt/0.3.100/download" + ], + "strip_prefix": "defmt-0.3.100", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"defmt\",\n deps = [\n \"@postmaster_executor_crates__defmt-1.0.1//:defmt\",\n ],\n aliases = {\n \"@postmaster_executor_crates__defmt-1.0.1//:defmt\": \"defmt10\",\n },\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=defmt\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.100\",\n)\n" + } + }, + "postmaster_executor_crates__defmt-1.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/defmt/1.0.1/download" + ], + "strip_prefix": "defmt-1.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"defmt\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__bitflags-1.3.2//:bitflags\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__defmt-macros-1.0.1//:defmt_macros\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=defmt\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n links = \"defmt\",\n pkg_name = \"defmt\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=defmt\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__defmt-macros-1.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/defmt-macros/1.0.1/download" + ], + "strip_prefix": "defmt-macros-1.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"defmt_macros\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__defmt-parser-1.0.0//:defmt_parser\",\n \"@postmaster_executor_crates__proc-macro-error2-2.0.1//:proc_macro_error2\",\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=defmt-macros\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"defmt-macros\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=defmt-macros\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__defmt-parser-1.0.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/defmt-parser/1.0.0/download" + ], + "strip_prefix": "defmt-parser-1.0.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"defmt_parser\",\n deps = [\n \"@postmaster_executor_crates__thiserror-2.0.18//:thiserror\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=defmt-parser\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.0\",\n)\n" + } + }, + "postmaster_executor_crates__deranged-0.5.8": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/deranged/0.5.8/download" + ], + "strip_prefix": "deranged-0.5.8", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"deranged\",\n deps = [\n \"@postmaster_executor_crates__powerfmt-0.2.0//:powerfmt\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"powerfmt\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=deranged\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.8\",\n)\n" + } + }, + "postmaster_executor_crates__derive_builder-0.20.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/derive_builder/0.20.2/download" + ], + "strip_prefix": "derive_builder-0.20.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"derive_builder\",\n proc_macro_deps = [\n \"@postmaster_executor_crates__derive_builder_macro-0.20.2//:derive_builder_macro\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=derive_builder\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.20.2\",\n)\n" + } + }, + "postmaster_executor_crates__derive_builder_core-0.20.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/derive_builder_core/0.20.2/download" + ], + "strip_prefix": "derive_builder_core-0.20.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"derive_builder_core\",\n deps = [\n \"@postmaster_executor_crates__darling-0.20.11//:darling\",\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"lib_has_std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=derive_builder_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.20.2\",\n)\n" + } + }, + "postmaster_executor_crates__derive_builder_macro-0.20.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/derive_builder_macro/0.20.2/download" + ], + "strip_prefix": "derive_builder_macro-0.20.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"derive_builder_macro\",\n deps = [\n \"@postmaster_executor_crates__derive_builder_core-0.20.2//:derive_builder_core\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"lib_has_std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=derive_builder_macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.20.2\",\n)\n" + } + }, + "postmaster_executor_crates__derive_more-2.1.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/derive_more/2.1.1/download" + ], + "strip_prefix": "derive_more-2.1.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"derive_more\",\n proc_macro_deps = [\n \"@postmaster_executor_crates__derive_more-impl-2.1.1//:derive_more_impl\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"debug\",\n \"default\",\n \"display\",\n \"from\",\n \"std\",\n \"unwrap\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=derive_more\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.1.1\",\n)\n" + } + }, + "postmaster_executor_crates__derive_more-impl-2.1.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/derive_more-impl/2.1.1/download" + ], + "strip_prefix": "derive_more-impl-2.1.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"derive_more_impl\",\n deps = [\n \"@postmaster_executor_crates__convert_case-0.10.0//:convert_case\",\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n \"@postmaster_executor_crates__unicode-xid-0.2.6//:unicode_xid\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"debug\",\n \"default\",\n \"display\",\n \"from\",\n \"unwrap\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=derive_more-impl\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.1.1\",\n)\n" + } + }, + "postmaster_executor_crates__digest-0.10.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/digest/0.10.7/download" + ], + "strip_prefix": "digest-0.10.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"digest\",\n deps = [\n \"@postmaster_executor_crates__block-buffer-0.10.4//:block_buffer\",\n \"@postmaster_executor_crates__crypto-common-0.1.7//:crypto_common\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"block-buffer\",\n \"core-api\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=digest\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.7\",\n)\n" + } + }, + "postmaster_executor_crates__digest-0.11.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/digest/0.11.2/download" + ], + "strip_prefix": "digest-0.11.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"digest\",\n deps = [\n \"@postmaster_executor_crates__block-buffer-0.12.0//:block_buffer\",\n \"@postmaster_executor_crates__const-oid-0.10.2//:const_oid\",\n \"@postmaster_executor_crates__crypto-common-0.2.1//:crypto_common\",\n ],\n aliases = {\n \"@postmaster_executor_crates__crypto-common-0.2.1//:crypto_common\": \"common\",\n },\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"block-api\",\n \"default\",\n \"oid\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=digest\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.11.2\",\n)\n" + } + }, + "postmaster_executor_crates__displaydoc-0.2.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/displaydoc/0.2.5/download" + ], + "strip_prefix": "displaydoc-0.2.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"displaydoc\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=displaydoc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.5\",\n)\n" + } + }, + "postmaster_executor_crates__document-features-0.2.12": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/document-features/0.2.12/download" + ], + "strip_prefix": "document-features-0.2.12", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"document_features\",\n deps = [\n \"@postmaster_executor_crates__litrs-1.0.0//:litrs\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=document-features\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.12\",\n)\n" + } + }, + "postmaster_executor_crates__dunce-1.0.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/dunce/1.0.5/download" + ], + "strip_prefix": "dunce-1.0.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"dunce\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=dunce\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.5\",\n)\n" + } + }, + "postmaster_executor_crates__dyn-clone-1.0.20": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/dyn-clone/1.0.20/download" + ], + "strip_prefix": "dyn-clone-1.0.20", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"dyn_clone\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=dyn-clone\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.20\",\n)\n" + } + }, + "postmaster_executor_crates__either-1.15.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/either/1.15.0/download" + ], + "strip_prefix": "either-1.15.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"either\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n \"use_std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=either\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.15.0\",\n)\n" + } + }, + "postmaster_executor_crates__encode_unicode-1.0.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/encode_unicode/1.0.0/download" + ], + "strip_prefix": "encode_unicode-1.0.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"encode_unicode\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=encode_unicode\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.0\",\n)\n" + } + }, + "postmaster_executor_crates__enum-iterator-2.3.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a4549325971814bda7a44061bf3fe7e487d447cba01e4220a4b454d630d7a016", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/enum-iterator/2.3.0/download" + ], + "strip_prefix": "enum-iterator-2.3.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"enum_iterator\",\n proc_macro_deps = [\n \"@postmaster_executor_crates__enum-iterator-derive-1.5.0//:enum_iterator_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=enum-iterator\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.3.0\",\n)\n" + } + }, + "postmaster_executor_crates__enum-iterator-derive-1.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/enum-iterator-derive/1.5.0/download" + ], + "strip_prefix": "enum-iterator-derive-1.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"enum_iterator_derive\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=enum-iterator-derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.5.0\",\n)\n" + } + }, + "postmaster_executor_crates__enumset-1.1.10": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "25b07a8dfbbbfc0064c0a6bdf9edcf966de6b1c33ce344bdeca3b41615452634", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/enumset/1.1.10/download" + ], + "strip_prefix": "enumset-1.1.10", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"enumset\",\n proc_macro_deps = [\n \"@postmaster_executor_crates__enumset_derive-0.14.0//:enumset_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=enumset\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.10\",\n)\n" + } + }, + "postmaster_executor_crates__enumset_derive-0.14.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f43e744e4ea338060faee68ed933e46e722fb7f3617e722a5772d7e856d8b3ce", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/enumset_derive/0.14.0/download" + ], + "strip_prefix": "enumset_derive-0.14.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"enumset_derive\",\n deps = [\n \"@postmaster_executor_crates__darling-0.21.3//:darling\",\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=enumset_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.14.0\",\n)\n" + } + }, + "postmaster_executor_crates__equivalent-1.0.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/equivalent/1.0.2/download" + ], + "strip_prefix": "equivalent-1.0.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"equivalent\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=equivalent\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.2\",\n)\n" + } + }, + "postmaster_executor_crates__errno-0.3.14": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/errno/0.3.14/download" + ], + "strip_prefix": "errno-0.3.14", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"errno\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=errno\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.14\",\n)\n" + } + }, + "postmaster_executor_crates__fastrand-2.4.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/fastrand/2.4.1/download" + ], + "strip_prefix": "fastrand-2.4.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"fastrand\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=fastrand\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.4.1\",\n)\n" + } + }, + "postmaster_executor_crates__filetime-0.2.27": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/filetime/0.2.27/download" + ], + "strip_prefix": "filetime-0.2.27", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"filetime\",\n deps = [\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=filetime\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.27\",\n)\n" + } + }, + "postmaster_executor_crates__find-msvc-tools-0.1.9": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/find-msvc-tools/0.1.9/download" + ], + "strip_prefix": "find-msvc-tools-0.1.9", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"find_msvc_tools\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=find-msvc-tools\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.9\",\n)\n" + } + }, + "postmaster_executor_crates__fixedbitset-0.5.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/fixedbitset/0.5.7/download" + ], + "strip_prefix": "fixedbitset-0.5.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"fixedbitset\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=fixedbitset\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.7\",\n)\n" + } + }, + "postmaster_executor_crates__flate2-1.1.9": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/flate2/1.1.9/download" + ], + "strip_prefix": "flate2-1.1.9", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"flate2\",\n deps = [\n \"@postmaster_executor_crates__crc32fast-1.5.0//:crc32fast\",\n \"@postmaster_executor_crates__miniz_oxide-0.8.9//:miniz_oxide\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"any_impl\",\n \"default\",\n \"miniz_oxide\",\n \"rust_backend\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=flate2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.9\",\n)\n" + } + }, + "postmaster_executor_crates__fnv-1.0.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/fnv/1.0.7/download" + ], + "strip_prefix": "fnv-1.0.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"fnv\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=fnv\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.7\",\n)\n" + } + }, + "postmaster_executor_crates__foldhash-0.1.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/foldhash/0.1.5/download" + ], + "strip_prefix": "foldhash-0.1.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"foldhash\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=foldhash\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.5\",\n)\n" + } + }, + "postmaster_executor_crates__foldhash-0.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/foldhash/0.2.0/download" + ], + "strip_prefix": "foldhash-0.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"foldhash\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=foldhash\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.0\",\n)\n" + } + }, + "postmaster_executor_crates__form_urlencoded-1.2.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/form_urlencoded/1.2.2/download" + ], + "strip_prefix": "form_urlencoded-1.2.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"form_urlencoded\",\n deps = [\n \"@postmaster_executor_crates__percent-encoding-2.3.2//:percent_encoding\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=form_urlencoded\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.2\",\n)\n" + } + }, + "postmaster_executor_crates__fs_extra-1.3.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/fs_extra/1.3.0/download" + ], + "strip_prefix": "fs_extra-1.3.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"fs_extra\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=fs_extra\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.3.0\",\n)\n" + } + }, + "postmaster_executor_crates__futures-0.3.32": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures/0.3.32/download" + ], + "strip_prefix": "futures-0.3.32", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures\",\n deps = [\n \"@postmaster_executor_crates__futures-channel-0.3.32//:futures_channel\",\n \"@postmaster_executor_crates__futures-core-0.3.32//:futures_core\",\n \"@postmaster_executor_crates__futures-executor-0.3.32//:futures_executor\",\n \"@postmaster_executor_crates__futures-io-0.3.32//:futures_io\",\n \"@postmaster_executor_crates__futures-sink-0.3.32//:futures_sink\",\n \"@postmaster_executor_crates__futures-task-0.3.32//:futures_task\",\n \"@postmaster_executor_crates__futures-util-0.3.32//:futures_util\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"async-await\",\n \"default\",\n \"executor\",\n \"futures-executor\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.32\",\n)\n" + } + }, + "postmaster_executor_crates__futures-channel-0.3.32": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-channel/0.3.32/download" + ], + "strip_prefix": "futures-channel-0.3.32", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures_channel\",\n deps = [\n \"@postmaster_executor_crates__futures-core-0.3.32//:futures_core\",\n \"@postmaster_executor_crates__futures-sink-0.3.32//:futures_sink\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"futures-sink\",\n \"sink\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-channel\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.32\",\n)\n" + } + }, + "postmaster_executor_crates__futures-core-0.3.32": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-core/0.3.32/download" + ], + "strip_prefix": "futures-core-0.3.32", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures_core\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.32\",\n)\n" + } + }, + "postmaster_executor_crates__futures-executor-0.3.32": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-executor/0.3.32/download" + ], + "strip_prefix": "futures-executor-0.3.32", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures_executor\",\n deps = [\n \"@postmaster_executor_crates__futures-core-0.3.32//:futures_core\",\n \"@postmaster_executor_crates__futures-task-0.3.32//:futures_task\",\n \"@postmaster_executor_crates__futures-util-0.3.32//:futures_util\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-executor\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.32\",\n)\n" + } + }, + "postmaster_executor_crates__futures-io-0.3.32": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-io/0.3.32/download" + ], + "strip_prefix": "futures-io-0.3.32", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures_io\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-io\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.32\",\n)\n" + } + }, + "postmaster_executor_crates__futures-macro-0.3.32": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-macro/0.3.32/download" + ], + "strip_prefix": "futures-macro-0.3.32", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"futures_macro\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.32\",\n)\n" + } + }, + "postmaster_executor_crates__futures-sink-0.3.32": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-sink/0.3.32/download" + ], + "strip_prefix": "futures-sink-0.3.32", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures_sink\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-sink\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.32\",\n)\n" + } + }, + "postmaster_executor_crates__futures-task-0.3.32": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-task/0.3.32/download" + ], + "strip_prefix": "futures-task-0.3.32", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures_task\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-task\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.32\",\n)\n" + } + }, + "postmaster_executor_crates__futures-util-0.3.32": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-util/0.3.32/download" + ], + "strip_prefix": "futures-util-0.3.32", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures_util\",\n deps = [\n \"@postmaster_executor_crates__futures-channel-0.3.32//:futures_channel\",\n \"@postmaster_executor_crates__futures-core-0.3.32//:futures_core\",\n \"@postmaster_executor_crates__futures-io-0.3.32//:futures_io\",\n \"@postmaster_executor_crates__futures-sink-0.3.32//:futures_sink\",\n \"@postmaster_executor_crates__futures-task-0.3.32//:futures_task\",\n \"@postmaster_executor_crates__memchr-2.8.0//:memchr\",\n \"@postmaster_executor_crates__pin-project-lite-0.2.17//:pin_project_lite\",\n \"@postmaster_executor_crates__slab-0.4.12//:slab\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__futures-macro-0.3.32//:futures_macro\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"async-await\",\n \"async-await-macro\",\n \"channel\",\n \"default\",\n \"futures-channel\",\n \"futures-io\",\n \"futures-macro\",\n \"futures-sink\",\n \"io\",\n \"memchr\",\n \"sink\",\n \"slab\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-util\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.32\",\n)\n" + } + }, + "postmaster_executor_crates__generic-array-0.14.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/generic-array/0.14.7/download" + ], + "strip_prefix": "generic-array-0.14.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"generic_array\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__typenum-1.20.0//:typenum\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"more_lengths\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=generic-array\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.14.7\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"more_lengths\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@postmaster_executor_crates__version_check-0.9.5//:version_check\",\n ],\n emit_warnings = False,\n edition = \"2015\",\n pkg_name = \"generic-array\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=generic-array\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.14.7\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__getrandom-0.3.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/getrandom/0.3.4/download" + ], + "strip_prefix": "getrandom-0.3.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"getrandom\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(any(target_os = \"macos\", target_os = \"openbsd\", target_os = \"vita\", target_os = \"emscripten\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(all(any(target_os = \"linux\", target_os = \"android\"), not(any(all(target_os = \"linux\", target_env = \"\"), getrandom_backend = \"custom\", getrandom_backend = \"linux_raw\", getrandom_backend = \"rdrand\", getrandom_backend = \"rndr\"))))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(all(any(target_os = \"linux\", target_os = \"android\"), not(any(all(target_os = \"linux\", target_env = \"\"), getrandom_backend = \"custom\", getrandom_backend = \"linux_raw\", getrandom_backend = \"rdrand\", getrandom_backend = \"rndr\"))))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=getrandom\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.4\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"getrandom\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=getrandom\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.3.4\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__getrandom-0.4.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/getrandom/0.4.2/download" + ], + "strip_prefix": "getrandom-0.4.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"getrandom\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_executor_crates__rand_core-0.10.1//:rand_core\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(any(target_os = \"macos\", target_os = \"openbsd\", target_os = \"vita\", target_os = \"emscripten\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(all(any(target_os = \"linux\", target_os = \"android\"), not(any(all(target_os = \"linux\", target_env = \"\"), getrandom_backend = \"custom\", getrandom_backend = \"linux_raw\", getrandom_backend = \"rdrand\", getrandom_backend = \"rndr\"))))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(all(any(target_os = \"linux\", target_os = \"android\"), not(any(all(target_os = \"linux\", target_env = \"\"), getrandom_backend = \"custom\", getrandom_backend = \"linux_raw\", getrandom_backend = \"rdrand\", getrandom_backend = \"rndr\"))))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n \"sys_rng\",\n \"wasm_js\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=getrandom\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.2\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n \"sys_rng\",\n \"wasm_js\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2024\",\n pkg_name = \"getrandom\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=getrandom\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.4.2\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__gimli-0.32.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/gimli/0.32.3/download" + ], + "strip_prefix": "gimli-0.32.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"gimli\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"read\",\n \"read-core\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=gimli\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.32.3\",\n)\n" + } + }, + "postmaster_executor_crates__gimli-0.33.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0bf7f043f89559805f8c7cacc432749b2fa0d0a0a9ee46ce47164ed5ba7f126c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/gimli/0.33.0/download" + ], + "strip_prefix": "gimli-0.33.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"gimli\",\n deps = [\n \"@postmaster_executor_crates__fnv-1.0.7//:fnv\",\n \"@postmaster_executor_crates__hashbrown-0.16.1//:hashbrown\",\n \"@postmaster_executor_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_executor_crates__stable_deref_trait-1.2.1//:stable_deref_trait\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"endian-reader\",\n \"read\",\n \"read-all\",\n \"read-core\",\n \"std\",\n \"write\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=gimli\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.33.0\",\n)\n" + } + }, + "postmaster_executor_crates__glob-0.3.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/glob/0.3.3/download" + ], + "strip_prefix": "glob-0.3.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"glob\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=glob\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.3\",\n)\n" + } + }, + "postmaster_executor_crates__globset-0.4.18": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/globset/0.4.18/download" + ], + "strip_prefix": "globset-0.4.18", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"globset\",\n deps = [\n \"@postmaster_executor_crates__aho-corasick-1.1.4//:aho_corasick\",\n \"@postmaster_executor_crates__bstr-1.12.1//:bstr\",\n \"@postmaster_executor_crates__log-0.4.29//:log\",\n \"@postmaster_executor_crates__regex-automata-0.4.14//:regex_automata\",\n \"@postmaster_executor_crates__regex-syntax-0.8.10//:regex_syntax\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"log\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=globset\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.18\",\n)\n" + } + }, + "postmaster_executor_crates__half-2.7.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/half/2.7.1/download" + ], + "strip_prefix": "half-2.7.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"half\",\n deps = [\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_executor_crates__zerocopy-0.8.48//:zerocopy\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=half\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.7.1\",\n)\n" + } + }, + "postmaster_executor_crates__hash32-0.3.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hash32/0.3.1/download" + ], + "strip_prefix": "hash32-0.3.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hash32\",\n deps = [\n \"@postmaster_executor_crates__byteorder-1.5.0//:byteorder\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hash32\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.1\",\n)\n" + } + }, + "postmaster_executor_crates__hashbrown-0.14.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hashbrown/0.14.5/download" + ], + "strip_prefix": "hashbrown-0.14.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hashbrown\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"raw\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hashbrown\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.14.5\",\n)\n" + } + }, + "postmaster_executor_crates__hashbrown-0.15.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hashbrown/0.15.5/download" + ], + "strip_prefix": "hashbrown-0.15.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hashbrown\",\n deps = [\n \"@postmaster_executor_crates__foldhash-0.1.5//:foldhash\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default-hasher\",\n \"inline-more\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hashbrown\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.15.5\",\n)\n" + } + }, + "postmaster_executor_crates__hashbrown-0.16.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hashbrown/0.16.1/download" + ], + "strip_prefix": "hashbrown-0.16.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hashbrown\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hashbrown\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.16.1\",\n)\n" + } + }, + "postmaster_executor_crates__hashbrown-0.17.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hashbrown/0.17.0/download" + ], + "strip_prefix": "hashbrown-0.17.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hashbrown\",\n deps = [\n \"@postmaster_executor_crates__foldhash-0.2.0//:foldhash\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default-hasher\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hashbrown\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.17.0\",\n)\n" + } + }, + "postmaster_executor_crates__heapless-0.9.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/heapless/0.9.2/download" + ], + "strip_prefix": "heapless-0.9.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"heapless\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__hash32-0.3.1//:hash32\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__stable_deref_trait-1.2.1//:stable_deref_trait\", # cfg(any(target_arch = \"arm\", target_pointer_width = \"32\", target_pointer_width = \"64\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__stable_deref_trait-1.2.1//:stable_deref_trait\", # cfg(any(target_arch = \"arm\", target_pointer_width = \"32\", target_pointer_width = \"64\"))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__stable_deref_trait-1.2.1//:stable_deref_trait\", # cfg(any(target_arch = \"arm\", target_pointer_width = \"32\", target_pointer_width = \"64\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=heapless\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.2\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"heapless\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=heapless\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.9.2\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__heck-0.3.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/heck/0.3.3/download" + ], + "strip_prefix": "heck-0.3.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"heck\",\n deps = [\n \"@postmaster_executor_crates__unicode-segmentation-1.13.2//:unicode_segmentation\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=heck\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.3\",\n)\n" + } + }, + "postmaster_executor_crates__heck-0.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/heck/0.5.0/download" + ], + "strip_prefix": "heck-0.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"heck\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=heck\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.0\",\n)\n" + } + }, + "postmaster_executor_crates__hermit-abi-0.5.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hermit-abi/0.5.2/download" + ], + "strip_prefix": "hermit-abi-0.5.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hermit_abi\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hermit-abi\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.2\",\n)\n" + } + }, + "postmaster_executor_crates__hex-0.4.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hex/0.4.3/download" + ], + "strip_prefix": "hex-0.4.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hex\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hex\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.3\",\n)\n" + } + }, + "postmaster_executor_crates__http-1.4.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/http/1.4.0/download" + ], + "strip_prefix": "http-1.4.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"http\",\n deps = [\n \"@postmaster_executor_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_executor_crates__itoa-1.0.18//:itoa\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=http\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.4.0\",\n)\n" + } + }, + "postmaster_executor_crates__hybrid-array-0.4.10": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3944cf8cf766b40e2a1a333ee5e9b563f854d5fa49d6a8ca2764e97c6eddb214", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hybrid-array/0.4.10/download" + ], + "strip_prefix": "hybrid-array-0.4.10", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hybrid_array\",\n deps = [\n \"@postmaster_executor_crates__typenum-1.20.0//:typenum\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hybrid-array\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.10\",\n)\n" + } + }, + "postmaster_executor_crates__icu_collections-2.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_collections/2.2.0/download" + ], + "strip_prefix": "icu_collections-2.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"icu_collections\",\n deps = [\n \"@postmaster_executor_crates__potential_utf-0.1.5//:potential_utf\",\n \"@postmaster_executor_crates__utf8_iter-1.0.4//:utf8_iter\",\n \"@postmaster_executor_crates__yoke-0.8.2//:yoke\",\n \"@postmaster_executor_crates__zerofrom-0.1.7//:zerofrom\",\n \"@postmaster_executor_crates__zerovec-0.11.6//:zerovec\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__displaydoc-0.2.5//:displaydoc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_collections\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.2.0\",\n)\n" + } + }, + "postmaster_executor_crates__icu_locale_core-2.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_locale_core/2.2.0/download" + ], + "strip_prefix": "icu_locale_core-2.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"icu_locale_core\",\n deps = [\n \"@postmaster_executor_crates__litemap-0.8.2//:litemap\",\n \"@postmaster_executor_crates__tinystr-0.8.3//:tinystr\",\n \"@postmaster_executor_crates__writeable-0.6.3//:writeable\",\n \"@postmaster_executor_crates__zerovec-0.11.6//:zerovec\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__displaydoc-0.2.5//:displaydoc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"zerovec\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_locale_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.2.0\",\n)\n" + } + }, + "postmaster_executor_crates__icu_normalizer-2.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_normalizer/2.2.0/download" + ], + "strip_prefix": "icu_normalizer-2.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"icu_normalizer\",\n deps = [\n \"@postmaster_executor_crates__icu_collections-2.2.0//:icu_collections\",\n \"@postmaster_executor_crates__icu_normalizer_data-2.2.0//:icu_normalizer_data\",\n \"@postmaster_executor_crates__icu_provider-2.2.0//:icu_provider\",\n \"@postmaster_executor_crates__smallvec-1.15.1//:smallvec\",\n \"@postmaster_executor_crates__zerovec-0.11.6//:zerovec\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"compiled_data\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_normalizer\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.2.0\",\n)\n" + } + }, + "postmaster_executor_crates__icu_normalizer_data-2.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_normalizer_data/2.2.0/download" + ], + "strip_prefix": "icu_normalizer_data-2.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"icu_normalizer_data\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_normalizer_data\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.2.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"icu_normalizer_data\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_normalizer_data\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"2.2.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__icu_properties-2.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_properties/2.2.0/download" + ], + "strip_prefix": "icu_properties-2.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"icu_properties\",\n deps = [\n \"@postmaster_executor_crates__icu_collections-2.2.0//:icu_collections\",\n \"@postmaster_executor_crates__icu_locale_core-2.2.0//:icu_locale_core\",\n \"@postmaster_executor_crates__icu_properties_data-2.2.0//:icu_properties_data\",\n \"@postmaster_executor_crates__icu_provider-2.2.0//:icu_provider\",\n \"@postmaster_executor_crates__zerotrie-0.2.4//:zerotrie\",\n \"@postmaster_executor_crates__zerovec-0.11.6//:zerovec\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"compiled_data\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_properties\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.2.0\",\n)\n" + } + }, + "postmaster_executor_crates__icu_properties_data-2.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_properties_data/2.2.0/download" + ], + "strip_prefix": "icu_properties_data-2.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"icu_properties_data\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_properties_data\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.2.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"icu_properties_data\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_properties_data\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"2.2.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__icu_provider-2.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_provider/2.2.0/download" + ], + "strip_prefix": "icu_provider-2.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"icu_provider\",\n deps = [\n \"@postmaster_executor_crates__icu_locale_core-2.2.0//:icu_locale_core\",\n \"@postmaster_executor_crates__writeable-0.6.3//:writeable\",\n \"@postmaster_executor_crates__yoke-0.8.2//:yoke\",\n \"@postmaster_executor_crates__zerofrom-0.1.7//:zerofrom\",\n \"@postmaster_executor_crates__zerotrie-0.2.4//:zerotrie\",\n \"@postmaster_executor_crates__zerovec-0.11.6//:zerovec\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__displaydoc-0.2.5//:displaydoc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"baked\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_provider\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.2.0\",\n)\n" + } + }, + "postmaster_executor_crates__id-arena-2.3.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/id-arena/2.3.0/download" + ], + "strip_prefix": "id-arena-2.3.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"id_arena\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=id-arena\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.3.0\",\n)\n" + } + }, + "postmaster_executor_crates__ident_case-1.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ident_case/1.0.1/download" + ], + "strip_prefix": "ident_case-1.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ident_case\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ident_case\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.1\",\n)\n" + } + }, + "postmaster_executor_crates__idna-1.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/idna/1.1.0/download" + ], + "strip_prefix": "idna-1.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"idna\",\n deps = [\n \"@postmaster_executor_crates__idna_adapter-1.2.1//:idna_adapter\",\n \"@postmaster_executor_crates__smallvec-1.15.1//:smallvec\",\n \"@postmaster_executor_crates__utf8_iter-1.0.4//:utf8_iter\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"compiled_data\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=idna\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.0\",\n)\n" + } + }, + "postmaster_executor_crates__idna_adapter-1.2.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/idna_adapter/1.2.1/download" + ], + "strip_prefix": "idna_adapter-1.2.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"idna_adapter\",\n deps = [\n \"@postmaster_executor_crates__icu_normalizer-2.2.0//:icu_normalizer\",\n \"@postmaster_executor_crates__icu_properties-2.2.0//:icu_properties\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"compiled_data\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=idna_adapter\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.1\",\n)\n" + } + }, + "postmaster_executor_crates__ignore-0.4.25": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ignore/0.4.25/download" + ], + "strip_prefix": "ignore-0.4.25", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ignore\",\n deps = [\n \"@postmaster_executor_crates__crossbeam-deque-0.8.6//:crossbeam_deque\",\n \"@postmaster_executor_crates__globset-0.4.18//:globset\",\n \"@postmaster_executor_crates__log-0.4.29//:log\",\n \"@postmaster_executor_crates__memchr-2.8.0//:memchr\",\n \"@postmaster_executor_crates__regex-automata-0.4.14//:regex_automata\",\n \"@postmaster_executor_crates__same-file-1.0.6//:same_file\",\n \"@postmaster_executor_crates__walkdir-2.5.0//:walkdir\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ignore\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.25\",\n)\n" + } + }, + "postmaster_executor_crates__indexmap-2.14.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/indexmap/2.14.0/download" + ], + "strip_prefix": "indexmap-2.14.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"indexmap\",\n deps = [\n \"@postmaster_executor_crates__equivalent-1.0.2//:equivalent\",\n \"@postmaster_executor_crates__hashbrown-0.17.0//:hashbrown\",\n \"@postmaster_executor_crates__serde_core-1.0.228//:serde_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=indexmap\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.14.0\",\n)\n" + } + }, + "postmaster_executor_crates__insta-1.47.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7b4a6248eb93a4401ed2f37dfe8ea592d3cf05b7cf4f8efa867b6895af7e094e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/insta/1.47.2/download" + ], + "strip_prefix": "insta-1.47.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"insta\",\n deps = [\n \"@postmaster_executor_crates__console-0.16.3//:console\",\n \"@postmaster_executor_crates__once_cell-1.21.4//:once_cell\",\n \"@postmaster_executor_crates__regex-1.12.3//:regex\",\n \"@postmaster_executor_crates__serde-1.0.228//:serde\",\n \"@postmaster_executor_crates__similar-2.7.0//:similar\",\n \"@postmaster_executor_crates__tempfile-3.27.0//:tempfile\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"colors\",\n \"console\",\n \"default\",\n \"filters\",\n \"regex\",\n \"serde\",\n \"yaml\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=insta\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.47.2\",\n)\n" + } + }, + "postmaster_executor_crates__ipnet-2.12.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ipnet/2.12.0/download" + ], + "strip_prefix": "ipnet-2.12.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ipnet\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ipnet\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.12.0\",\n)\n" + } + }, + "postmaster_executor_crates__iprange-0.6.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "37209be0ad225457e63814401415e748e2453a5297f9b637338f5fb8afa4ec00", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/iprange/0.6.7/download" + ], + "strip_prefix": "iprange-0.6.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"iprange\",\n deps = [\n \"@postmaster_executor_crates__ipnet-2.12.0//:ipnet\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=iprange\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.7\",\n)\n" + } + }, + "postmaster_executor_crates__itertools-0.13.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/itertools/0.13.0/download" + ], + "strip_prefix": "itertools-0.13.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"itertools\",\n deps = [\n \"@postmaster_executor_crates__either-1.15.0//:either\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=itertools\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.13.0\",\n)\n" + } + }, + "postmaster_executor_crates__itertools-0.14.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/itertools/0.14.0/download" + ], + "strip_prefix": "itertools-0.14.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"itertools\",\n deps = [\n \"@postmaster_executor_crates__either-1.15.0//:either\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"use_alloc\",\n \"use_std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=itertools\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.14.0\",\n)\n" + } + }, + "postmaster_executor_crates__itoa-1.0.18": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/itoa/1.0.18/download" + ], + "strip_prefix": "itoa-1.0.18", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"itoa\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=itoa\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.18\",\n)\n" + } + }, + "postmaster_executor_crates__jobserver-0.1.34": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/jobserver/0.1.34/download" + ], + "strip_prefix": "jobserver-0.1.34", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"jobserver\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=jobserver\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.34\",\n)\n" + } + }, + "postmaster_executor_crates__js-sys-0.3.95": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/js-sys/0.3.95/download" + ], + "strip_prefix": "js-sys-0.3.95", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"js_sys\",\n deps = [\n \"@postmaster_executor_crates__once_cell-1.21.4//:once_cell\",\n \"@postmaster_executor_crates__wasm-bindgen-0.2.118//:wasm_bindgen\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=js-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.95\",\n)\n" + } + }, + "postmaster_executor_crates__leb128-0.2.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6cc46bac87ef8093eed6f272babb833b6443374399985ac8ed28471ee0918545", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/leb128/0.2.6/download" + ], + "strip_prefix": "leb128-0.2.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"leb128\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=leb128\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.6\",\n)\n" + } + }, + "postmaster_executor_crates__leb128fmt-0.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/leb128fmt/0.1.0/download" + ], + "strip_prefix": "leb128fmt-0.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"leb128fmt\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=leb128fmt\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.0\",\n)\n" + } + }, + "postmaster_executor_crates__lexical-sort-0.3.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c09e4591611e231daf4d4c685a66cb0410cc1e502027a20ae55f2bb9e997207a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/lexical-sort/0.3.1/download" + ], + "strip_prefix": "lexical-sort-0.3.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"lexical_sort\",\n deps = [\n \"@postmaster_executor_crates__any_ascii-0.1.7//:any_ascii\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=lexical-sort\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.1\",\n)\n" + } + }, + "postmaster_executor_crates__libc-0.2.186": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/libc/0.2.186/download" + ], + "strip_prefix": "libc-0.2.186", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"libc\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=libc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.186\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"libc\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=libc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.2.186\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__libloading-0.8.9": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/libloading/0.8.9/download" + ], + "strip_prefix": "libloading-0.8.9", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"libloading\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=libloading\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.9\",\n)\n" + } + }, + "postmaster_executor_crates__libredox-0.1.16": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/libredox/0.1.16/download" + ], + "strip_prefix": "libredox-0.1.16", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"libredox\",\n deps = [\n \"@postmaster_executor_crates__redox_syscall-0.7.4//:syscall\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=libredox\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.16\",\n)\n" + } + }, + "postmaster_executor_crates__libunwind-1.3.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0c6639b70a7ce854b79c70d7e83f16b5dc0137cc914f3d7d03803b513ecc67ac", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/libunwind/1.3.3/download" + ], + "strip_prefix": "libunwind-1.3.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"libunwind\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=libunwind\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.3.3\",\n)\n" + } + }, + "postmaster_executor_crates__linked-hash-map-0.5.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/linked-hash-map/0.5.6/download" + ], + "strip_prefix": "linked-hash-map-0.5.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"linked_hash_map\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=linked-hash-map\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.6\",\n)\n" + } + }, + "postmaster_executor_crates__linked_hash_set-0.1.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "984fb35d06508d1e69fc91050cceba9c0b748f983e6739fa2c7a9237154c52c8", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/linked_hash_set/0.1.6/download" + ], + "strip_prefix": "linked_hash_set-0.1.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"linked_hash_set\",\n deps = [\n \"@postmaster_executor_crates__linked-hash-map-0.5.6//:linked_hash_map\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=linked_hash_set\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.6\",\n)\n" + } + }, + "postmaster_executor_crates__linux-raw-sys-0.12.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/linux-raw-sys/0.12.1/download" + ], + "strip_prefix": "linux-raw-sys-0.12.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"linux_raw_sys\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"auxvec\",\n \"elf\",\n \"errno\",\n \"general\",\n \"ioctl\",\n \"no_std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=linux-raw-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.12.1\",\n)\n" + } + }, + "postmaster_executor_crates__litemap-0.8.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/litemap/0.8.2/download" + ], + "strip_prefix": "litemap-0.8.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"litemap\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=litemap\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.2\",\n)\n" + } + }, + "postmaster_executor_crates__litrs-1.0.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/litrs/1.0.0/download" + ], + "strip_prefix": "litrs-1.0.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"litrs\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=litrs\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.0\",\n)\n" + } + }, + "postmaster_executor_crates__lock_api-0.4.14": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/lock_api/0.4.14/download" + ], + "strip_prefix": "lock_api-0.4.14", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"lock_api\",\n deps = [\n \"@postmaster_executor_crates__scopeguard-1.2.0//:scopeguard\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"atomic_usize\",\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=lock_api\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.14\",\n)\n" + } + }, + "postmaster_executor_crates__log-0.4.29": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/log/0.4.29/download" + ], + "strip_prefix": "log-0.4.29", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"log\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=log\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.29\",\n)\n" + } + }, + "postmaster_executor_crates__lz4_flex-0.13.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "db9a0d582c2874f68138a16ce1867e0ffde6c0bb0a0df85e1f36d04146db488a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/lz4_flex/0.13.0/download" + ], + "strip_prefix": "lz4_flex-0.13.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"lz4_flex\",\n deps = [\n \"@postmaster_executor_crates__twox-hash-2.1.2//:twox_hash\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"checked-decode\",\n \"default\",\n \"frame\",\n \"safe-decode\",\n \"safe-encode\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=lz4_flex\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.13.0\",\n)\n" + } + }, + "postmaster_executor_crates__mach2-0.4.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/mach2/0.4.3/download" + ], + "strip_prefix": "mach2-0.4.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"mach2\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(any(target_os = \"macos\", target_os = \"ios\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=mach2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.3\",\n)\n" + } + }, + "postmaster_executor_crates__mach2-0.6.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/mach2/0.6.0/download" + ], + "strip_prefix": "mach2-0.6.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"mach2\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=mach2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.0\",\n)\n" + } + }, + "postmaster_executor_crates__macho-unwind-info-0.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/macho-unwind-info/0.5.0/download" + ], + "strip_prefix": "macho-unwind-info-0.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"macho_unwind_info\",\n deps = [\n \"@postmaster_executor_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_executor_crates__zerocopy-0.8.48//:zerocopy\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__zerocopy-derive-0.8.48//:zerocopy_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=macho-unwind-info\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.0\",\n)\n" + } + }, + "postmaster_executor_crates__managed-0.8.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/managed/0.8.0/download" + ], + "strip_prefix": "managed-0.8.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"managed\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"map\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=managed\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.0\",\n)\n" + } + }, + "postmaster_executor_crates__memchr-2.8.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/memchr/2.8.0/download" + ], + "strip_prefix": "memchr-2.8.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"memchr\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=memchr\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.8.0\",\n)\n" + } + }, + "postmaster_executor_crates__memmap2-0.6.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6d28bba84adfe6646737845bc5ebbfa2c08424eb1c37e94a1fd2a82adb56a872", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/memmap2/0.6.2/download" + ], + "strip_prefix": "memmap2-0.6.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"memmap2\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=memmap2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.2\",\n)\n" + } + }, + "postmaster_executor_crates__memmap2-0.9.10": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/memmap2/0.9.10/download" + ], + "strip_prefix": "memmap2-0.9.10", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"memmap2\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=memmap2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.10\",\n)\n" + } + }, + "postmaster_executor_crates__memoffset-0.9.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/memoffset/0.9.1/download" + ], + "strip_prefix": "memoffset-0.9.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"memoffset\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=memoffset\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@postmaster_executor_crates__autocfg-1.5.0//:autocfg\",\n ],\n emit_warnings = False,\n edition = \"2015\",\n pkg_name = \"memoffset\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=memoffset\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.9.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__minimal-lexical-0.2.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/minimal-lexical/0.2.1/download" + ], + "strip_prefix": "minimal-lexical-0.2.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"minimal_lexical\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=minimal-lexical\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.1\",\n)\n" + } + }, + "postmaster_executor_crates__miniz_oxide-0.8.9": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/miniz_oxide/0.8.9/download" + ], + "strip_prefix": "miniz_oxide-0.8.9", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"miniz_oxide\",\n deps = [\n \"@postmaster_executor_crates__adler2-2.0.1//:adler2\",\n \"@postmaster_executor_crates__simd-adler32-0.3.9//:simd_adler32\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"simd\",\n \"simd-adler32\",\n \"with-alloc\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=miniz_oxide\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.9\",\n)\n" + } + }, + "postmaster_executor_crates__mio-1.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/mio/1.2.0/download" + ], + "strip_prefix": "mio-1.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"mio\",\n deps = [\n \"@postmaster_executor_crates__log-0.4.29//:log\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(any(unix, target_os = \"hermit\", target_os = \"wasi\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(any(unix, target_os = \"hermit\", target_os = \"wasi\"))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(any(unix, target_os = \"hermit\", target_os = \"wasi\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"log\",\n \"net\",\n \"os-ext\",\n \"os-poll\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=mio\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.0\",\n)\n" + } + }, + "postmaster_executor_crates__more-asserts-0.3.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/more-asserts/0.3.1/download" + ], + "strip_prefix": "more-asserts-0.3.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"more_asserts\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=more-asserts\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.1\",\n)\n" + } + }, + "postmaster_executor_crates__msvc-demangler-0.11.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "fbeff6bd154a309b2ada5639b2661ca6ae4599b34e8487dc276d2cd637da2d76", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/msvc-demangler/0.11.0/download" + ], + "strip_prefix": "msvc-demangler-0.11.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"msvc_demangler\",\n deps = [\n \"@postmaster_executor_crates__bitflags-2.11.1//:bitflags\",\n \"@postmaster_executor_crates__itoa-1.0.18//:itoa\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=msvc-demangler\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.11.0\",\n)\n" + } + }, + "postmaster_executor_crates__munge-0.4.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/munge/0.4.7/download" + ], + "strip_prefix": "munge-0.4.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"munge\",\n proc_macro_deps = [\n \"@postmaster_executor_crates__munge_macro-0.4.7//:munge_macro\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=munge\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.7\",\n)\n" + } + }, + "postmaster_executor_crates__munge_macro-0.4.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/munge_macro/0.4.7/download" + ], + "strip_prefix": "munge_macro-0.4.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"munge_macro\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=munge_macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.7\",\n)\n" + } + }, + "postmaster_executor_crates__nom-5.1.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/nom/5.1.3/download" + ], + "strip_prefix": "nom-5.1.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"nom\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__memchr-2.8.0//:memchr\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=nom\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"5.1.3\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@postmaster_executor_crates__version_check-0.9.5//:version_check\",\n ],\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"nom\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=nom\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"5.1.3\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__nom-7.1.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/nom/7.1.3/download" + ], + "strip_prefix": "nom-7.1.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"nom\",\n deps = [\n \"@postmaster_executor_crates__memchr-2.8.0//:memchr\",\n \"@postmaster_executor_crates__minimal-lexical-0.2.1//:minimal_lexical\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=nom\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"7.1.3\",\n)\n" + } + }, + "postmaster_executor_crates__num-conv-0.2.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/num-conv/0.2.1/download" + ], + "strip_prefix": "num-conv-0.2.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"num_conv\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=num-conv\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.1\",\n)\n" + } + }, + "postmaster_executor_crates__num-traits-0.2.19": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/num-traits/0.2.19/download" + ], + "strip_prefix": "num-traits-0.2.19", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"num_traits\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=num-traits\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.19\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@postmaster_executor_crates__autocfg-1.5.0//:autocfg\",\n ],\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"num-traits\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=num-traits\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.2.19\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__num_cpus-1.17.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/num_cpus/1.17.0/download" + ], + "strip_prefix": "num_cpus-1.17.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"num_cpus\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(not(windows))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(not(windows))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(not(windows))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=num_cpus\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.17.0\",\n)\n" + } + }, + "postmaster_executor_crates__num_enum-0.7.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/num_enum/0.7.6/download" + ], + "strip_prefix": "num_enum-0.7.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"num_enum\",\n proc_macro_deps = [\n \"@postmaster_executor_crates__num_enum_derive-0.7.6//:num_enum_derive\",\n \"@postmaster_executor_crates__rustversion-1.0.22//:rustversion\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=num_enum\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.6\",\n)\n" + } + }, + "postmaster_executor_crates__num_enum_derive-0.7.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/num_enum_derive/0.7.6/download" + ], + "strip_prefix": "num_enum_derive-0.7.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"num_enum_derive\",\n deps = [\n \"@postmaster_executor_crates__proc-macro-crate-3.5.0//:proc_macro_crate\",\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"proc-macro-crate\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=num_enum_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.6\",\n)\n" + } + }, + "postmaster_executor_crates__object-0.37.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/object/0.37.3/download" + ], + "strip_prefix": "object-0.37.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"object\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__memchr-2.8.0//:memchr\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"archive\",\n \"coff\",\n \"elf\",\n \"macho\",\n \"pe\",\n \"read_core\",\n \"unaligned\",\n \"xcoff\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=object\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.37.3\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"archive\",\n \"coff\",\n \"elf\",\n \"macho\",\n \"pe\",\n \"read_core\",\n \"unaligned\",\n \"xcoff\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"object\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=object\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.37.3\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__object-0.39.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/object/0.39.1/download" + ], + "strip_prefix": "object-0.39.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"object\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__crc32fast-1.5.0//:crc32fast\",\n \"@postmaster_executor_crates__flate2-1.1.9//:flate2\",\n \"@postmaster_executor_crates__hashbrown-0.17.0//:hashbrown\",\n \"@postmaster_executor_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_executor_crates__memchr-2.8.0//:memchr\",\n \"@postmaster_executor_crates__ruzstd-0.8.2//:ruzstd\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"archive\",\n \"coff\",\n \"compression\",\n \"default\",\n \"elf\",\n \"macho\",\n \"pe\",\n \"read\",\n \"read_core\",\n \"std\",\n \"write\",\n \"write_core\",\n \"write_std\",\n \"xcoff\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=object\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.39.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"archive\",\n \"coff\",\n \"compression\",\n \"default\",\n \"elf\",\n \"macho\",\n \"pe\",\n \"read\",\n \"read_core\",\n \"std\",\n \"write\",\n \"write_core\",\n \"write_std\",\n \"xcoff\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"object\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=object\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.39.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__once_cell-1.21.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/once_cell/1.21.4/download" + ], + "strip_prefix": "once_cell-1.21.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"once_cell\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"race\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=once_cell\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.21.4\",\n)\n" + } + }, + "postmaster_executor_crates__parking-2.2.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/parking/2.2.1/download" + ], + "strip_prefix": "parking-2.2.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"parking\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=parking\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.2.1\",\n)\n" + } + }, + "postmaster_executor_crates__parking_lot-0.12.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/parking_lot/0.12.5/download" + ], + "strip_prefix": "parking_lot-0.12.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"parking_lot\",\n deps = [\n \"@postmaster_executor_crates__lock_api-0.4.14//:lock_api\",\n \"@postmaster_executor_crates__parking_lot_core-0.9.12//:parking_lot_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=parking_lot\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.12.5\",\n)\n" + } + }, + "postmaster_executor_crates__parking_lot_core-0.9.12": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/parking_lot_core/0.9.12/download" + ], + "strip_prefix": "parking_lot_core-0.9.12", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"parking_lot_core\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_executor_crates__smallvec-1.15.1//:smallvec\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=parking_lot_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.12\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"parking_lot_core\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=parking_lot_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.9.12\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__paste-1.0.15": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/paste/1.0.15/download" + ], + "strip_prefix": "paste-1.0.15", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"paste\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=paste\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.15\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"paste\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=paste\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.15\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__path-clean-1.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/path-clean/1.0.1/download" + ], + "strip_prefix": "path-clean-1.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"path_clean\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=path-clean\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.1\",\n)\n" + } + }, + "postmaster_executor_crates__percent-encoding-2.3.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/percent-encoding/2.3.2/download" + ], + "strip_prefix": "percent-encoding-2.3.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"percent_encoding\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=percent-encoding\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.3.2\",\n)\n" + } + }, + "postmaster_executor_crates__petgraph-0.8.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/petgraph/0.8.3/download" + ], + "strip_prefix": "petgraph-0.8.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"petgraph\",\n deps = [\n \"@postmaster_executor_crates__fixedbitset-0.5.7//:fixedbitset\",\n \"@postmaster_executor_crates__hashbrown-0.15.5//:hashbrown\",\n \"@postmaster_executor_crates__indexmap-2.14.0//:indexmap\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"graphmap\",\n \"matrix_graph\",\n \"stable_graph\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=petgraph\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.3\",\n)\n" + } + }, + "postmaster_executor_crates__pin-project-1.1.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/pin-project/1.1.11/download" + ], + "strip_prefix": "pin-project-1.1.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"pin_project\",\n proc_macro_deps = [\n \"@postmaster_executor_crates__pin-project-internal-1.1.11//:pin_project_internal\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pin-project\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.11\",\n)\n" + } + }, + "postmaster_executor_crates__pin-project-internal-1.1.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/pin-project-internal/1.1.11/download" + ], + "strip_prefix": "pin-project-internal-1.1.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"pin_project_internal\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pin-project-internal\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.11\",\n)\n" + } + }, + "postmaster_executor_crates__pin-project-lite-0.2.17": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/pin-project-lite/0.2.17/download" + ], + "strip_prefix": "pin-project-lite-0.2.17", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"pin_project_lite\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pin-project-lite\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.17\",\n)\n" + } + }, + "postmaster_executor_crates__pin-utils-0.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/pin-utils/0.1.0/download" + ], + "strip_prefix": "pin-utils-0.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"pin_utils\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pin-utils\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.0\",\n)\n" + } + }, + "postmaster_executor_crates__pkg-config-0.3.33": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/pkg-config/0.3.33/download" + ], + "strip_prefix": "pkg-config-0.3.33", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"pkg_config\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pkg-config\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.33\",\n)\n" + } + }, + "postmaster_executor_crates__plain-0.2.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/plain/0.2.3/download" + ], + "strip_prefix": "plain-0.2.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"plain\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=plain\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.3\",\n)\n" + } + }, + "postmaster_executor_crates__potential_utf-0.1.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/potential_utf/0.1.5/download" + ], + "strip_prefix": "potential_utf-0.1.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"potential_utf\",\n deps = [\n \"@postmaster_executor_crates__zerovec-0.11.6//:zerovec\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"zerovec\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=potential_utf\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.5\",\n)\n" + } + }, + "postmaster_executor_crates__powerfmt-0.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/powerfmt/0.2.0/download" + ], + "strip_prefix": "powerfmt-0.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"powerfmt\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=powerfmt\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.0\",\n)\n" + } + }, + "postmaster_executor_crates__ppv-lite86-0.2.21": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ppv-lite86/0.2.21/download" + ], + "strip_prefix": "ppv-lite86-0.2.21", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ppv_lite86\",\n deps = [\n \"@postmaster_executor_crates__zerocopy-0.8.48//:zerocopy\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"simd\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ppv-lite86\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.21\",\n)\n" + } + }, + "postmaster_executor_crates__prettyplease-0.2.37": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/prettyplease/0.2.37/download" + ], + "strip_prefix": "prettyplease-0.2.37", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"prettyplease\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"verbatim\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=prettyplease\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.37\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"verbatim\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n links = \"prettyplease02\",\n pkg_name = \"prettyplease\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=prettyplease\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.2.37\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__proc-macro-crate-3.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/proc-macro-crate/3.5.0/download" + ], + "strip_prefix": "proc-macro-crate-3.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"proc_macro_crate\",\n deps = [\n \"@postmaster_executor_crates__toml_edit-0.25.11-spec-1.1.0//:toml_edit\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=proc-macro-crate\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"3.5.0\",\n)\n" + } + }, + "postmaster_executor_crates__proc-macro-error-attr2-2.0.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/proc-macro-error-attr2/2.0.0/download" + ], + "strip_prefix": "proc-macro-error-attr2-2.0.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"proc_macro_error_attr2\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=proc-macro-error-attr2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.0\",\n)\n" + } + }, + "postmaster_executor_crates__proc-macro-error2-2.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/proc-macro-error2/2.0.1/download" + ], + "strip_prefix": "proc-macro-error2-2.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"proc_macro_error2\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__proc-macro-error-attr2-2.0.0//:proc_macro_error_attr2\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"syn-error\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=proc-macro-error2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.1\",\n)\n" + } + }, + "postmaster_executor_crates__proc-macro2-1.0.106": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/proc-macro2/1.0.106/download" + ], + "strip_prefix": "proc-macro2-1.0.106", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"proc_macro2\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__unicode-ident-1.0.24//:unicode_ident\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"proc-macro\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=proc-macro2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.106\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"proc-macro\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"proc-macro2\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=proc-macro2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.106\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__ptr_meta-0.3.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0b9a0cf95a1196af61d4f1cbdab967179516d9a4a4312af1f31948f8f6224a79", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ptr_meta/0.3.1/download" + ], + "strip_prefix": "ptr_meta-0.3.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ptr_meta\",\n proc_macro_deps = [\n \"@postmaster_executor_crates__ptr_meta_derive-0.3.1//:ptr_meta_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"derive\",\n \"ptr_meta_derive\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ptr_meta\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.1\",\n)\n" + } + }, + "postmaster_executor_crates__ptr_meta_derive-0.3.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ptr_meta_derive/0.3.1/download" + ], + "strip_prefix": "ptr_meta_derive-0.3.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"ptr_meta_derive\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ptr_meta_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.1\",\n)\n" + } + }, + "postmaster_executor_crates__pulldown-cmark-0.8.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/pulldown-cmark/0.8.0/download" + ], + "strip_prefix": "pulldown-cmark-0.8.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"pulldown_cmark\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__bitflags-1.3.2//:bitflags\",\n \"@postmaster_executor_crates__memchr-2.8.0//:memchr\",\n \"@postmaster_executor_crates__unicase-2.9.0//:unicase\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pulldown-cmark\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"pulldown-cmark\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pulldown-cmark\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.8.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__quote-1.0.45": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/quote/1.0.45/download" + ], + "strip_prefix": "quote-1.0.45", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"quote\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"proc-macro\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=quote\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.45\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"proc-macro\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"quote\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=quote\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.45\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__r-efi-5.3.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/r-efi/5.3.0/download" + ], + "strip_prefix": "r-efi-5.3.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"r_efi\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=r-efi\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"5.3.0\",\n)\n" + } + }, + "postmaster_executor_crates__r-efi-6.0.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/r-efi/6.0.0/download" + ], + "strip_prefix": "r-efi-6.0.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"r_efi\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=r-efi\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"6.0.0\",\n)\n" + } + }, + "postmaster_executor_crates__rancor-0.1.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a063ea72381527c2a0561da9c80000ef822bdd7c3241b1cc1b12100e3df081ee", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rancor/0.1.1/download" + ], + "strip_prefix": "rancor-0.1.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rancor\",\n deps = [\n \"@postmaster_executor_crates__ptr_meta-0.3.1//:ptr_meta\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rancor\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.1\",\n)\n" + } + }, + "postmaster_executor_crates__rand-0.10.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rand/0.10.1/download" + ], + "strip_prefix": "rand-0.10.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rand\",\n deps = [\n \"@postmaster_executor_crates__chacha20-0.10.0//:chacha20\",\n \"@postmaster_executor_crates__getrandom-0.4.2//:getrandom\",\n \"@postmaster_executor_crates__rand_core-0.10.1//:rand_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n \"std_rng\",\n \"sys_rng\",\n \"thread_rng\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rand\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.1\",\n)\n" + } + }, + "postmaster_executor_crates__rand-0.9.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rand/0.9.4/download" + ], + "strip_prefix": "rand-0.9.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rand\",\n deps = [\n \"@postmaster_executor_crates__rand_chacha-0.9.0//:rand_chacha\",\n \"@postmaster_executor_crates__rand_core-0.9.5//:rand_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"os_rng\",\n \"small_rng\",\n \"std\",\n \"std_rng\",\n \"thread_rng\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rand\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.4\",\n)\n" + } + }, + "postmaster_executor_crates__rand_chacha-0.9.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rand_chacha/0.9.0/download" + ], + "strip_prefix": "rand_chacha-0.9.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rand_chacha\",\n deps = [\n \"@postmaster_executor_crates__ppv-lite86-0.2.21//:ppv_lite86\",\n \"@postmaster_executor_crates__rand_core-0.9.5//:rand_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rand_chacha\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.0\",\n)\n" + } + }, + "postmaster_executor_crates__rand_core-0.10.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rand_core/0.10.1/download" + ], + "strip_prefix": "rand_core-0.10.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rand_core\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rand_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.1\",\n)\n" + } + }, + "postmaster_executor_crates__rand_core-0.9.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rand_core/0.9.5/download" + ], + "strip_prefix": "rand_core-0.9.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rand_core\",\n deps = [\n \"@postmaster_executor_crates__getrandom-0.3.4//:getrandom\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"os_rng\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rand_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.5\",\n)\n" + } + }, + "postmaster_executor_crates__rangemap-1.7.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "973443cf09a9c8656b574a866ab68dfa19f0867d0340648c7d2f6a71b8a8ea68", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rangemap/1.7.1/download" + ], + "strip_prefix": "rangemap-1.7.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rangemap\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rangemap\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.7.1\",\n)\n" + } + }, + "postmaster_executor_crates__rayon-1.12.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rayon/1.12.0/download" + ], + "strip_prefix": "rayon-1.12.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rayon\",\n deps = [\n \"@postmaster_executor_crates__either-1.15.0//:either\",\n \"@postmaster_executor_crates__rayon-core-1.13.0//:rayon_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rayon\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.12.0\",\n)\n" + } + }, + "postmaster_executor_crates__rayon-core-1.13.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rayon-core/1.13.0/download" + ], + "strip_prefix": "rayon-core-1.13.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rayon_core\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__crossbeam-deque-0.8.6//:crossbeam_deque\",\n \"@postmaster_executor_crates__crossbeam-utils-0.8.21//:crossbeam_utils\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rayon-core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.13.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n links = \"rayon-core\",\n pkg_name = \"rayon-core\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rayon-core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.13.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__redox_syscall-0.5.18": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/redox_syscall/0.5.18/download" + ], + "strip_prefix": "redox_syscall-0.5.18", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"syscall\",\n deps = [\n \"@postmaster_executor_crates__bitflags-2.11.1//:bitflags\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=redox_syscall\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.18\",\n)\n" + } + }, + "postmaster_executor_crates__redox_syscall-0.7.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f450ad9c3b1da563fb6948a8e0fb0fb9269711c9c73d9ea1de5058c79c8d643a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/redox_syscall/0.7.4/download" + ], + "strip_prefix": "redox_syscall-0.7.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"syscall\",\n deps = [\n \"@postmaster_executor_crates__bitflags-2.11.1//:bitflags\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=redox_syscall\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.4\",\n)\n" + } + }, + "postmaster_executor_crates__ref-cast-1.0.25": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ref-cast/1.0.25/download" + ], + "strip_prefix": "ref-cast-1.0.25", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ref_cast\",\n deps = [\n \":build_script_build\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__ref-cast-impl-1.0.25//:ref_cast_impl\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ref-cast\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.25\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"ref-cast\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ref-cast\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.25\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__ref-cast-impl-1.0.25": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ref-cast-impl/1.0.25/download" + ], + "strip_prefix": "ref-cast-impl-1.0.25", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"ref_cast_impl\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ref-cast-impl\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.25\",\n)\n" + } + }, + "postmaster_executor_crates__regex-1.12.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/regex/1.12.3/download" + ], + "strip_prefix": "regex-1.12.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"regex\",\n deps = [\n \"@postmaster_executor_crates__regex-automata-0.4.14//:regex_automata\",\n \"@postmaster_executor_crates__regex-syntax-0.8.10//:regex_syntax\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n \"unicode\",\n \"unicode-age\",\n \"unicode-bool\",\n \"unicode-case\",\n \"unicode-gencat\",\n \"unicode-perl\",\n \"unicode-script\",\n \"unicode-segment\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=regex\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.12.3\",\n)\n" + } + }, + "postmaster_executor_crates__regex-automata-0.4.14": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/regex-automata/0.4.14/download" + ], + "strip_prefix": "regex-automata-0.4.14", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"regex_automata\",\n deps = [\n \"@postmaster_executor_crates__aho-corasick-1.1.4//:aho_corasick\",\n \"@postmaster_executor_crates__memchr-2.8.0//:memchr\",\n \"@postmaster_executor_crates__regex-syntax-0.8.10//:regex_syntax\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"dfa-onepass\",\n \"hybrid\",\n \"meta\",\n \"nfa\",\n \"nfa-backtrack\",\n \"nfa-pikevm\",\n \"nfa-thompson\",\n \"perf\",\n \"perf-inline\",\n \"perf-literal\",\n \"perf-literal-multisubstring\",\n \"perf-literal-substring\",\n \"std\",\n \"syntax\",\n \"unicode\",\n \"unicode-age\",\n \"unicode-bool\",\n \"unicode-case\",\n \"unicode-gencat\",\n \"unicode-perl\",\n \"unicode-script\",\n \"unicode-segment\",\n \"unicode-word-boundary\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=regex-automata\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.14\",\n)\n" + } + }, + "postmaster_executor_crates__regex-syntax-0.8.10": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/regex-syntax/0.8.10/download" + ], + "strip_prefix": "regex-syntax-0.8.10", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"regex_syntax\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n \"unicode\",\n \"unicode-age\",\n \"unicode-bool\",\n \"unicode-case\",\n \"unicode-gencat\",\n \"unicode-perl\",\n \"unicode-script\",\n \"unicode-segment\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=regex-syntax\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.10\",\n)\n" + } + }, + "postmaster_executor_crates__region-3.0.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/region/3.0.2/download" + ], + "strip_prefix": "region-3.0.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"region\",\n deps = [\n \"@postmaster_executor_crates__bitflags-1.3.2//:bitflags\",\n \"@postmaster_executor_crates__libc-0.2.186//:libc\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__mach2-0.4.3//:mach2\", # cfg(any(target_os = \"macos\", target_os = \"ios\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=region\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"3.0.2\",\n)\n" + } + }, + "postmaster_executor_crates__rend-0.5.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rend/0.5.3/download" + ], + "strip_prefix": "rend-0.5.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rend\",\n deps = [\n \"@postmaster_executor_crates__bytecheck-0.8.2//:bytecheck\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"bytecheck\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rend\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.3\",\n)\n" + } + }, + "postmaster_executor_crates__replace_with-0.1.8": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "51743d3e274e2b18df81c4dc6caf8a5b8e15dbe799e0dca05c7617380094e884", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/replace_with/0.1.8/download" + ], + "strip_prefix": "replace_with-0.1.8", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"replace_with\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=replace_with\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.8\",\n)\n" + } + }, + "postmaster_executor_crates__rkyv-0.8.16": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "73389e0c99e664f919275ab5b5b0471391fe9a8de61e1dff9b1eaf56a90f16e3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rkyv/0.8.16/download" + ], + "strip_prefix": "rkyv-0.8.16", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rkyv\",\n deps = [\n \"@postmaster_executor_crates__bytecheck-0.8.2//:bytecheck\",\n \"@postmaster_executor_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_executor_crates__hashbrown-0.17.0//:hashbrown\",\n \"@postmaster_executor_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_executor_crates__munge-0.4.7//:munge\",\n \"@postmaster_executor_crates__ptr_meta-0.3.1//:ptr_meta\",\n \"@postmaster_executor_crates__rancor-0.1.1//:rancor\",\n \"@postmaster_executor_crates__rend-0.5.3//:rend\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__rkyv_derive-0.8.16//:rkyv_derive\",\n ],\n aliases = {\n \"@postmaster_executor_crates__bytes-1.11.1//:bytes\": \"bytes_1\",\n \"@postmaster_executor_crates__indexmap-2.14.0//:indexmap\": \"indexmap_2\",\n },\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"bytecheck\",\n \"bytes-1\",\n \"default\",\n \"indexmap-2\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rkyv\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.16\",\n)\n" + } + }, + "postmaster_executor_crates__rkyv_derive-0.8.16": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5d2ed0b54125315fb36bd021e82d314d1c126548f871634b483f46b31d13cac6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rkyv_derive/0.8.16/download" + ], + "strip_prefix": "rkyv_derive-0.8.16", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"rkyv_derive\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"bytecheck\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rkyv_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.16\",\n)\n" + } + }, + "postmaster_executor_crates__rustc-demangle-0.1.27": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rustc-demangle/0.1.27/download" + ], + "strip_prefix": "rustc-demangle-0.1.27", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rustc_demangle\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustc-demangle\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.27\",\n)\n" + } + }, + "postmaster_executor_crates__rustc-hash-2.1.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rustc-hash/2.1.2/download" + ], + "strip_prefix": "rustc-hash-2.1.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rustc_hash\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustc-hash\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.1.2\",\n)\n" + } + }, + "postmaster_executor_crates__rustc_version-0.4.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rustc_version/0.4.1/download" + ], + "strip_prefix": "rustc_version-0.4.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rustc_version\",\n deps = [\n \"@postmaster_executor_crates__semver-1.0.28//:semver\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustc_version\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.1\",\n)\n" + } + }, + "postmaster_executor_crates__rustix-1.1.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rustix/1.1.4/download" + ], + "strip_prefix": "rustix-1.1.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rustix\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__bitflags-2.11.1//:bitflags\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__errno-0.3.14//:errno\", # aarch64-apple-darwin, cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\")))))))\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # aarch64-apple-darwin, cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\")))))))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__linux-raw-sys-0.12.1//:linux_raw_sys\", # cfg(all(not(rustix_use_libc), not(miri), target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\"))))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__linux-raw-sys-0.12.1//:linux_raw_sys\", # cfg(all(not(rustix_use_libc), not(miri), target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\"))))\n ],\n \"//conditions:default\": [],\n }),\n aliases = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": {\n \"@postmaster_executor_crates__errno-0.3.14//:errno\": \"libc_errno\", # aarch64-apple-darwin, cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\")))))))\n },\n \"//conditions:default\": {},\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"fs\",\n \"std\",\n \"termios\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustix\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.4\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"fs\",\n \"std\",\n \"termios\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"rustix\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustix\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.1.4\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__rustversion-1.0.22": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rustversion/1.0.22/download" + ], + "strip_prefix": "rustversion-1.0.22", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"rustversion\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustversion\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.22\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build/build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"rustversion\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustversion\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.22\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__rusty_pool-0.7.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4ed36cdb20de66d89a17ea04b8883fc7a386f2cf877aaedca5005583ce4876ff", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rusty_pool/0.7.0/download" + ], + "strip_prefix": "rusty_pool-0.7.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rusty_pool\",\n deps = [\n \"@postmaster_executor_crates__crossbeam-channel-0.5.15//:crossbeam_channel\",\n \"@postmaster_executor_crates__futures-0.3.32//:futures\",\n \"@postmaster_executor_crates__futures-channel-0.3.32//:futures_channel\",\n \"@postmaster_executor_crates__futures-executor-0.3.32//:futures_executor\",\n \"@postmaster_executor_crates__num_cpus-1.17.0//:num_cpus\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"async\",\n \"default\",\n \"futures\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rusty_pool\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.0\",\n)\n" + } + }, + "postmaster_executor_crates__ruzstd-0.8.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e5ff0cc5e135c8870a775d3320910cd9b564ec036b4dc0b8741629020be63f01", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ruzstd/0.8.2/download" + ], + "strip_prefix": "ruzstd-0.8.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ruzstd\",\n deps = [\n \"@postmaster_executor_crates__twox-hash-2.1.2//:twox_hash\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"hash\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ruzstd\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.2\",\n)\n" + } + }, + "postmaster_executor_crates__ryu-1.0.23": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ryu/1.0.23/download" + ], + "strip_prefix": "ryu-1.0.23", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ryu\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ryu\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.23\",\n)\n" + } + }, + "postmaster_executor_crates__saffron-0.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "03fb9a628596fc7590eb7edbf7b0613287be78df107f5f97b118aad59fb2eea9", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/saffron/0.1.0/download" + ], + "strip_prefix": "saffron-0.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"saffron\",\n deps = [\n \"@postmaster_executor_crates__chrono-0.4.44//:chrono\",\n \"@postmaster_executor_crates__nom-5.1.3//:nom\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=saffron\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.0\",\n)\n" + } + }, + "postmaster_executor_crates__same-file-1.0.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/same-file/1.0.6/download" + ], + "strip_prefix": "same-file-1.0.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"same_file\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=same-file\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.6\",\n)\n" + } + }, + "postmaster_executor_crates__schemars-1.2.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/schemars/1.2.1/download" + ], + "strip_prefix": "schemars-1.2.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"schemars\",\n deps = [\n \"@postmaster_executor_crates__dyn-clone-1.0.20//:dyn_clone\",\n \"@postmaster_executor_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_executor_crates__ref-cast-1.0.25//:ref_cast\",\n \"@postmaster_executor_crates__serde-1.0.228//:serde\",\n \"@postmaster_executor_crates__serde_json-1.0.149//:serde_json\",\n \"@postmaster_executor_crates__url-2.5.8//:url\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__schemars_derive-1.2.1//:schemars_derive\",\n ],\n aliases = {\n \"@postmaster_executor_crates__indexmap-2.14.0//:indexmap\": \"indexmap2\",\n \"@postmaster_executor_crates__url-2.5.8//:url\": \"url2\",\n },\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"derive\",\n \"indexmap2\",\n \"schemars_derive\",\n \"std\",\n \"url2\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=schemars\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.1\",\n)\n" + } + }, + "postmaster_executor_crates__schemars_derive-1.2.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/schemars_derive/1.2.1/download" + ], + "strip_prefix": "schemars_derive-1.2.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"schemars_derive\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__serde_derive_internals-0.29.1//:serde_derive_internals\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=schemars_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.1\",\n)\n" + } + }, + "postmaster_executor_crates__scopeguard-1.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/scopeguard/1.2.0/download" + ], + "strip_prefix": "scopeguard-1.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"scopeguard\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"use_std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=scopeguard\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.0\",\n)\n" + } + }, + "postmaster_executor_crates__self_cell-1.2.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/self_cell/1.2.2/download" + ], + "strip_prefix": "self_cell-1.2.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"self_cell\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=self_cell\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.2\",\n)\n" + } + }, + "postmaster_executor_crates__semver-1.0.28": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/semver/1.0.28/download" + ], + "strip_prefix": "semver-1.0.28", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"semver\",\n deps = [\n \"@postmaster_executor_crates__serde_core-1.0.228//:serde_core\",\n ],\n aliases = {\n \"@postmaster_executor_crates__serde_core-1.0.228//:serde_core\": \"serde\",\n },\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=semver\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.28\",\n)\n" + } + }, + "postmaster_executor_crates__serde-1.0.228": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde/1.0.228/download" + ], + "strip_prefix": "serde-1.0.228", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__serde_core-1.0.228//:serde_core\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__serde_derive-1.0.228//:serde_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"derive\",\n \"rc\",\n \"serde_derive\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.228\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"derive\",\n \"rc\",\n \"serde_derive\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"serde\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.228\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__serde-wasm-bindgen-0.6.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde-wasm-bindgen/0.6.5/download" + ], + "strip_prefix": "serde-wasm-bindgen-0.6.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde_wasm_bindgen\",\n deps = [\n \"@postmaster_executor_crates__js-sys-0.3.95//:js_sys\",\n \"@postmaster_executor_crates__serde-1.0.228//:serde\",\n \"@postmaster_executor_crates__wasm-bindgen-0.2.118//:wasm_bindgen\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde-wasm-bindgen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.5\",\n)\n" + } + }, + "postmaster_executor_crates__serde_core-1.0.228": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde_core/1.0.228/download" + ], + "strip_prefix": "serde_core-1.0.228", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde_core\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"rc\",\n \"result\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.228\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"rc\",\n \"result\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"serde_core\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.228\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__serde_derive-1.0.228": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde_derive/1.0.228/download" + ], + "strip_prefix": "serde_derive-1.0.228", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"serde_derive\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.228\",\n)\n" + } + }, + "postmaster_executor_crates__serde_derive_internals-0.29.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde_derive_internals/0.29.1/download" + ], + "strip_prefix": "serde_derive_internals-0.29.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde_derive_internals\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_derive_internals\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.29.1\",\n)\n" + } + }, + "postmaster_executor_crates__serde_json-1.0.149": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde_json/1.0.149/download" + ], + "strip_prefix": "serde_json-1.0.149", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde_json\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__itoa-1.0.18//:itoa\",\n \"@postmaster_executor_crates__memchr-2.8.0//:memchr\",\n \"@postmaster_executor_crates__serde_core-1.0.228//:serde_core\",\n \"@postmaster_executor_crates__zmij-1.0.21//:zmij\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_json\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.149\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"serde_json\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_json\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.149\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__serde_spanned-1.1.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde_spanned/1.1.1/download" + ], + "strip_prefix": "serde_spanned-1.1.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde_spanned\",\n deps = [\n \"@postmaster_executor_crates__serde_core-1.0.228//:serde_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_spanned\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.1\",\n)\n" + } + }, + "postmaster_executor_crates__serde_yaml-0.9.34-deprecated": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde_yaml/0.9.34+deprecated/download" + ], + "strip_prefix": "serde_yaml-0.9.34+deprecated", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde_yaml\",\n deps = [\n \"@postmaster_executor_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_executor_crates__itoa-1.0.18//:itoa\",\n \"@postmaster_executor_crates__ryu-1.0.23//:ryu\",\n \"@postmaster_executor_crates__serde-1.0.228//:serde\",\n \"@postmaster_executor_crates__unsafe-libyaml-0.2.11//:unsafe_libyaml\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_yaml\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.34+deprecated\",\n)\n" + } + }, + "postmaster_executor_crates__sha2-0.10.9": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/sha2/0.10.9/download" + ], + "strip_prefix": "sha2-0.10.9", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"sha2\",\n deps = [\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_executor_crates__digest-0.10.7//:digest\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__cpufeatures-0.2.17//:cpufeatures\", # cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__cpufeatures-0.2.17//:cpufeatures\", # cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__cpufeatures-0.2.17//:cpufeatures\", # cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=sha2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.9\",\n)\n" + } + }, + "postmaster_executor_crates__sha2-0.11.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/sha2/0.11.0/download" + ], + "strip_prefix": "sha2-0.11.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"sha2\",\n deps = [\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_executor_crates__digest-0.11.2//:digest\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__cpufeatures-0.3.0//:cpufeatures\", # cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__cpufeatures-0.3.0//:cpufeatures\", # cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__cpufeatures-0.3.0//:cpufeatures\", # cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"oid\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=sha2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.11.0\",\n)\n" + } + }, + "postmaster_executor_crates__shared-buffer-0.1.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f6c99835bad52957e7aa241d3975ed17c1e5f8c92026377d117a606f36b84b16", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/shared-buffer/0.1.4/download" + ], + "strip_prefix": "shared-buffer-0.1.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"shared_buffer\",\n deps = [\n \"@postmaster_executor_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_executor_crates__memmap2-0.6.2//:memmap2\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=shared-buffer\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.4\",\n)\n" + } + }, + "postmaster_executor_crates__shlex-1.3.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/shlex/1.3.0/download" + ], + "strip_prefix": "shlex-1.3.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"shlex\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=shlex\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.3.0\",\n)\n" + } + }, + "postmaster_executor_crates__simd-adler32-0.3.9": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/simd-adler32/0.3.9/download" + ], + "strip_prefix": "simd-adler32-0.3.9", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"simd_adler32\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=simd-adler32\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.9\",\n)\n" + } + }, + "postmaster_executor_crates__simdutf8-0.1.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/simdutf8/0.1.5/download" + ], + "strip_prefix": "simdutf8-0.1.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"simdutf8\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=simdutf8\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.5\",\n)\n" + } + }, + "postmaster_executor_crates__similar-2.7.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/similar/2.7.0/download" + ], + "strip_prefix": "similar-2.7.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"similar\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"inline\",\n \"text\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=similar\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.7.0\",\n)\n" + } + }, + "postmaster_executor_crates__slab-0.4.12": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/slab/0.4.12/download" + ], + "strip_prefix": "slab-0.4.12", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"slab\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=slab\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.12\",\n)\n" + } + }, + "postmaster_executor_crates__smallvec-1.15.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/smallvec/1.15.1/download" + ], + "strip_prefix": "smallvec-1.15.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"smallvec\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"const_generics\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=smallvec\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.15.1\",\n)\n" + } + }, + "postmaster_executor_crates__smoltcp-0.13.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ac729b0a77bd092a3f06ddaddc59fe0d67f48ba0de45a9abe707c2842c7f8767", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/smoltcp/0.13.0/download" + ], + "strip_prefix": "smoltcp-0.13.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"smoltcp\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__bitflags-1.3.2//:bitflags\",\n \"@postmaster_executor_crates__byteorder-1.5.0//:byteorder\",\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_executor_crates__heapless-0.9.2//:heapless\",\n \"@postmaster_executor_crates__managed-0.8.0//:managed\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"proto-ipv4\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=smoltcp\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.13.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"proto-ipv4\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2024\",\n pkg_name = \"smoltcp\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=smoltcp\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.13.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__socket2-0.6.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/socket2/0.6.3/download" + ], + "strip_prefix": "socket2-0.6.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"socket2\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(any(unix, target_os = \"wasi\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(any(unix, target_os = \"wasi\"))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(any(unix, target_os = \"wasi\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"all\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=socket2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.3\",\n)\n" + } + }, + "postmaster_executor_crates__stable_deref_trait-1.2.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/stable_deref_trait/1.2.1/download" + ], + "strip_prefix": "stable_deref_trait-1.2.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"stable_deref_trait\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=stable_deref_trait\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.1\",\n)\n" + } + }, + "postmaster_executor_crates__strsim-0.11.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/strsim/0.11.1/download" + ], + "strip_prefix": "strsim-0.11.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"strsim\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=strsim\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.11.1\",\n)\n" + } + }, + "postmaster_executor_crates__symbolic-common-12.18.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "332615d90111d8eeaf86a84dc9bbe9f65d0d8c5cf11b4caccedc37754eb0dcfd", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/symbolic-common/12.18.3/download" + ], + "strip_prefix": "symbolic-common-12.18.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"symbolic_common\",\n deps = [\n \"@postmaster_executor_crates__debugid-0.8.0//:debugid\",\n \"@postmaster_executor_crates__memmap2-0.9.10//:memmap2\",\n \"@postmaster_executor_crates__stable_deref_trait-1.2.1//:stable_deref_trait\",\n \"@postmaster_executor_crates__uuid-1.23.1//:uuid\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=symbolic-common\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"12.18.3\",\n)\n" + } + }, + "postmaster_executor_crates__symbolic-demangle-12.18.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "912017718eb4d21930546245af9a3475c9dccf15675a5c215664e76621afc471", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/symbolic-demangle/12.18.3/download" + ], + "strip_prefix": "symbolic-demangle-12.18.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"symbolic_demangle\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__cpp_demangle-0.4.5//:cpp_demangle\",\n \"@postmaster_executor_crates__msvc-demangler-0.11.0//:msvc_demangler\",\n \"@postmaster_executor_crates__rustc-demangle-0.1.27//:rustc_demangle\",\n \"@postmaster_executor_crates__symbolic-common-12.18.3//:symbolic_common\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"cpp\",\n \"cpp_demangle\",\n \"msvc\",\n \"msvc-demangler\",\n \"rust\",\n \"rustc-demangle\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=symbolic-demangle\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"12.18.3\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"cpp\",\n \"cpp_demangle\",\n \"msvc\",\n \"msvc-demangler\",\n \"rust\",\n \"rustc-demangle\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"symbolic-demangle\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=symbolic-demangle\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"12.18.3\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__syn-1.0.109": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/syn/1.0.109/download" + ], + "strip_prefix": "syn-1.0.109", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"syn\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__unicode-ident-1.0.24//:unicode_ident\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"clone-impls\",\n \"default\",\n \"derive\",\n \"parsing\",\n \"printing\",\n \"proc-macro\",\n \"quote\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=syn\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.109\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"clone-impls\",\n \"default\",\n \"derive\",\n \"parsing\",\n \"printing\",\n \"proc-macro\",\n \"quote\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"syn\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=syn\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.109\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__syn-2.0.117": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/syn/2.0.117/download" + ], + "strip_prefix": "syn-2.0.117", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"syn\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__unicode-ident-1.0.24//:unicode_ident\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"clone-impls\",\n \"default\",\n \"derive\",\n \"extra-traits\",\n \"fold\",\n \"full\",\n \"parsing\",\n \"printing\",\n \"proc-macro\",\n \"visit\",\n \"visit-mut\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=syn\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.117\",\n)\n" + } + }, + "postmaster_executor_crates__synstructure-0.13.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/synstructure/0.13.2/download" + ], + "strip_prefix": "synstructure-0.13.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"synstructure\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"proc-macro\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=synstructure\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.13.2\",\n)\n" + } + }, + "postmaster_executor_crates__tar-0.4.45": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tar/0.4.45/download" + ], + "strip_prefix": "tar-0.4.45", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tar\",\n deps = [\n \"@postmaster_executor_crates__filetime-0.2.27//:filetime\",\n \"@postmaster_executor_crates__xattr-1.6.1//:xattr\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"xattr\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tar\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.45\",\n)\n" + } + }, + "postmaster_executor_crates__target-lexicon-0.13.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/target-lexicon/0.13.5/download" + ], + "strip_prefix": "target-lexicon-0.13.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"target_lexicon\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=target-lexicon\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.13.5\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"target-lexicon\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=target-lexicon\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.13.5\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__tempfile-3.27.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tempfile/3.27.0/download" + ], + "strip_prefix": "tempfile-3.27.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tempfile\",\n deps = [\n \"@postmaster_executor_crates__fastrand-2.4.1//:fastrand\",\n \"@postmaster_executor_crates__getrandom-0.4.2//:getrandom\",\n \"@postmaster_executor_crates__once_cell-1.21.4//:once_cell\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__rustix-1.1.4//:rustix\", # cfg(any(unix, target_os = \"wasi\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__rustix-1.1.4//:rustix\", # cfg(any(unix, target_os = \"wasi\"))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__rustix-1.1.4//:rustix\", # cfg(any(unix, target_os = \"wasi\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"getrandom\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tempfile\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"3.27.0\",\n)\n" + } + }, + "postmaster_executor_crates__terminal_size-0.4.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/terminal_size/0.4.4/download" + ], + "strip_prefix": "terminal_size-0.4.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"terminal_size\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__rustix-1.1.4//:rustix\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__rustix-1.1.4//:rustix\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__rustix-1.1.4//:rustix\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=terminal_size\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.4\",\n)\n" + } + }, + "postmaster_executor_crates__termios-0.3.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/termios/0.3.3/download" + ], + "strip_prefix": "termios-0.3.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"termios\",\n deps = [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=termios\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.3\",\n)\n" + } + }, + "postmaster_executor_crates__thiserror-2.0.18": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/thiserror/2.0.18/download" + ], + "strip_prefix": "thiserror-2.0.18", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"thiserror\",\n deps = [\n \":build_script_build\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__thiserror-impl-2.0.18//:thiserror_impl\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=thiserror\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.18\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"thiserror\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=thiserror\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"2.0.18\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__thiserror-impl-2.0.18": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/thiserror-impl/2.0.18/download" + ], + "strip_prefix": "thiserror-impl-2.0.18", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"thiserror_impl\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=thiserror-impl\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.18\",\n)\n" + } + }, + "postmaster_executor_crates__time-0.3.47": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/time/0.3.47/download" + ], + "strip_prefix": "time-0.3.47", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"time\",\n deps = [\n \"@postmaster_executor_crates__deranged-0.5.8//:deranged\",\n \"@postmaster_executor_crates__itoa-1.0.18//:itoa\",\n \"@postmaster_executor_crates__num-conv-0.2.1//:num_conv\",\n \"@postmaster_executor_crates__powerfmt-0.2.0//:powerfmt\",\n \"@postmaster_executor_crates__time-core-0.1.8//:time_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"formatting\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=time\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.47\",\n)\n" + } + }, + "postmaster_executor_crates__time-core-0.1.8": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/time-core/0.1.8/download" + ], + "strip_prefix": "time-core-0.1.8", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"time_core\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=time-core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.8\",\n)\n" + } + }, + "postmaster_executor_crates__time-macros-0.2.27": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/time-macros/0.2.27/download" + ], + "strip_prefix": "time-macros-0.2.27", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"time_macros\",\n deps = [\n \"@postmaster_executor_crates__num-conv-0.2.1//:num_conv\",\n \"@postmaster_executor_crates__time-core-0.1.8//:time_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=time-macros\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.27\",\n)\n" + } + }, + "postmaster_executor_crates__tinystr-0.8.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tinystr/0.8.3/download" + ], + "strip_prefix": "tinystr-0.8.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tinystr\",\n deps = [\n \"@postmaster_executor_crates__zerovec-0.11.6//:zerovec\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__displaydoc-0.2.5//:displaydoc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"zerovec\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tinystr\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.3\",\n)\n" + } + }, + "postmaster_executor_crates__tinyvec-1.11.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tinyvec/1.11.0/download" + ], + "strip_prefix": "tinyvec-1.11.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tinyvec\",\n deps = [\n \"@postmaster_executor_crates__tinyvec_macros-0.1.1//:tinyvec_macros\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"tinyvec_macros\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tinyvec\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.11.0\",\n)\n" + } + }, + "postmaster_executor_crates__tinyvec_macros-0.1.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tinyvec_macros/0.1.1/download" + ], + "strip_prefix": "tinyvec_macros-0.1.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tinyvec_macros\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tinyvec_macros\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.1\",\n)\n" + } + }, + "postmaster_executor_crates__tokio-1.52.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tokio/1.52.1/download" + ], + "strip_prefix": "tokio-1.52.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tokio\",\n deps = [\n \"@postmaster_executor_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_executor_crates__libc-0.2.186//:libc\",\n \"@postmaster_executor_crates__mio-1.2.0//:mio\",\n \"@postmaster_executor_crates__pin-project-lite-0.2.17//:pin_project_lite\",\n \"@postmaster_executor_crates__socket2-0.6.3//:socket2\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__tokio-macros-2.7.0//:tokio_macros\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"bytes\",\n \"default\",\n \"fs\",\n \"io-std\",\n \"io-util\",\n \"libc\",\n \"macros\",\n \"mio\",\n \"net\",\n \"rt\",\n \"rt-multi-thread\",\n \"socket2\",\n \"sync\",\n \"time\",\n \"tokio-macros\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tokio\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.52.1\",\n)\n" + } + }, + "postmaster_executor_crates__tokio-macros-2.7.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tokio-macros/2.7.0/download" + ], + "strip_prefix": "tokio-macros-2.7.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"tokio_macros\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tokio-macros\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.7.0\",\n)\n" + } + }, + "postmaster_executor_crates__tokio-stream-0.1.18": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tokio-stream/0.1.18/download" + ], + "strip_prefix": "tokio-stream-0.1.18", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tokio_stream\",\n deps = [\n \"@postmaster_executor_crates__futures-core-0.3.32//:futures_core\",\n \"@postmaster_executor_crates__pin-project-lite-0.2.17//:pin_project_lite\",\n \"@postmaster_executor_crates__tokio-1.52.1//:tokio\",\n \"@postmaster_executor_crates__tokio-util-0.7.18//:tokio_util\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"sync\",\n \"time\",\n \"tokio-util\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tokio-stream\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.18\",\n)\n" + } + }, + "postmaster_executor_crates__tokio-util-0.7.18": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tokio-util/0.7.18/download" + ], + "strip_prefix": "tokio-util-0.7.18", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tokio_util\",\n deps = [\n \"@postmaster_executor_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_executor_crates__futures-core-0.3.32//:futures_core\",\n \"@postmaster_executor_crates__futures-sink-0.3.32//:futures_sink\",\n \"@postmaster_executor_crates__pin-project-lite-0.2.17//:pin_project_lite\",\n \"@postmaster_executor_crates__tokio-1.52.1//:tokio\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tokio-util\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.18\",\n)\n" + } + }, + "postmaster_executor_crates__toml-1.1.2-spec-1.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/toml/1.1.2+spec-1.1.0/download" + ], + "strip_prefix": "toml-1.1.2+spec-1.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"toml\",\n deps = [\n \"@postmaster_executor_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_executor_crates__serde_core-1.0.228//:serde_core\",\n \"@postmaster_executor_crates__serde_spanned-1.1.1//:serde_spanned\",\n \"@postmaster_executor_crates__toml_datetime-1.1.1-spec-1.1.0//:toml_datetime\",\n \"@postmaster_executor_crates__toml_parser-1.1.2-spec-1.1.0//:toml_parser\",\n \"@postmaster_executor_crates__toml_writer-1.1.1-spec-1.1.0//:toml_writer\",\n \"@postmaster_executor_crates__winnow-1.0.2//:winnow\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"display\",\n \"parse\",\n \"preserve_order\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=toml\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.2+spec-1.1.0\",\n)\n" + } + }, + "postmaster_executor_crates__toml_datetime-1.1.1-spec-1.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/toml_datetime/1.1.1+spec-1.1.0/download" + ], + "strip_prefix": "toml_datetime-1.1.1+spec-1.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"toml_datetime\",\n deps = [\n \"@postmaster_executor_crates__serde_core-1.0.228//:serde_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=toml_datetime\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.1+spec-1.1.0\",\n)\n" + } + }, + "postmaster_executor_crates__toml_edit-0.25.11-spec-1.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/toml_edit/0.25.11+spec-1.1.0/download" + ], + "strip_prefix": "toml_edit-0.25.11+spec-1.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"toml_edit\",\n deps = [\n \"@postmaster_executor_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_executor_crates__toml_datetime-1.1.1-spec-1.1.0//:toml_datetime\",\n \"@postmaster_executor_crates__toml_parser-1.1.2-spec-1.1.0//:toml_parser\",\n \"@postmaster_executor_crates__winnow-1.0.2//:winnow\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"parse\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=toml_edit\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.25.11+spec-1.1.0\",\n)\n" + } + }, + "postmaster_executor_crates__toml_parser-1.1.2-spec-1.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/toml_parser/1.1.2+spec-1.1.0/download" + ], + "strip_prefix": "toml_parser-1.1.2+spec-1.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"toml_parser\",\n deps = [\n \"@postmaster_executor_crates__winnow-1.0.2//:winnow\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=toml_parser\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.2+spec-1.1.0\",\n)\n" + } + }, + "postmaster_executor_crates__toml_writer-1.1.1-spec-1.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/toml_writer/1.1.1+spec-1.1.0/download" + ], + "strip_prefix": "toml_writer-1.1.1+spec-1.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"toml_writer\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=toml_writer\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.1+spec-1.1.0\",\n)\n" + } + }, + "postmaster_executor_crates__tracing-0.1.44": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tracing/0.1.44/download" + ], + "strip_prefix": "tracing-0.1.44", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tracing\",\n deps = [\n \"@postmaster_executor_crates__pin-project-lite-0.2.17//:pin_project_lite\",\n \"@postmaster_executor_crates__tracing-core-0.1.36//:tracing_core\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__tracing-attributes-0.1.31//:tracing_attributes\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"attributes\",\n \"default\",\n \"max_level_off\",\n \"release_max_level_off\",\n \"std\",\n \"tracing-attributes\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tracing\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.44\",\n)\n" + } + }, + "postmaster_executor_crates__tracing-attributes-0.1.31": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tracing-attributes/0.1.31/download" + ], + "strip_prefix": "tracing-attributes-0.1.31", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"tracing_attributes\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tracing-attributes\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.31\",\n)\n" + } + }, + "postmaster_executor_crates__tracing-core-0.1.36": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tracing-core/0.1.36/download" + ], + "strip_prefix": "tracing-core-0.1.36", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tracing_core\",\n deps = [\n \"@postmaster_executor_crates__once_cell-1.21.4//:once_cell\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"once_cell\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tracing-core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.36\",\n)\n" + } + }, + "postmaster_executor_crates__twox-hash-2.1.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/twox-hash/2.1.2/download" + ], + "strip_prefix": "twox-hash-2.1.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"twox_hash\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"xxhash32\",\n \"xxhash64\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=twox-hash\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.1.2\",\n)\n" + } + }, + "postmaster_executor_crates__typenum-1.20.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/typenum/1.20.0/download" + ], + "strip_prefix": "typenum-1.20.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"typenum\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"const-generics\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=typenum\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.20.0\",\n)\n" + } + }, + "postmaster_executor_crates__unicase-2.9.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unicase/2.9.0/download" + ], + "strip_prefix": "unicase-2.9.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unicase\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unicase\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.9.0\",\n)\n" + } + }, + "postmaster_executor_crates__unicode-ident-1.0.24": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unicode-ident/1.0.24/download" + ], + "strip_prefix": "unicode-ident-1.0.24", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unicode_ident\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unicode-ident\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.24\",\n)\n" + } + }, + "postmaster_executor_crates__unicode-normalization-0.1.25": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unicode-normalization/0.1.25/download" + ], + "strip_prefix": "unicode-normalization-0.1.25", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unicode_normalization\",\n deps = [\n \"@postmaster_executor_crates__tinyvec-1.11.0//:tinyvec\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unicode-normalization\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.25\",\n)\n" + } + }, + "postmaster_executor_crates__unicode-segmentation-1.13.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unicode-segmentation/1.13.2/download" + ], + "strip_prefix": "unicode-segmentation-1.13.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unicode_segmentation\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unicode-segmentation\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.13.2\",\n)\n" + } + }, + "postmaster_executor_crates__unicode-width-0.2.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unicode-width/0.2.2/download" + ], + "strip_prefix": "unicode-width-0.2.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unicode_width\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"cjk\",\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unicode-width\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.2\",\n)\n" + } + }, + "postmaster_executor_crates__unicode-xid-0.2.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unicode-xid/0.2.6/download" + ], + "strip_prefix": "unicode-xid-0.2.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unicode_xid\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unicode-xid\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.6\",\n)\n" + } + }, + "postmaster_executor_crates__unsafe-libyaml-0.2.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unsafe-libyaml/0.2.11/download" + ], + "strip_prefix": "unsafe-libyaml-0.2.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unsafe_libyaml\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unsafe-libyaml\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.11\",\n)\n" + } + }, + "postmaster_executor_crates__unty-0.0.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unty/0.0.4/download" + ], + "strip_prefix": "unty-0.0.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unty\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unty\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.0.4\",\n)\n" + } + }, + "postmaster_executor_crates__url-2.5.8": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/url/2.5.8/download" + ], + "strip_prefix": "url-2.5.8", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"url\",\n deps = [\n \"@postmaster_executor_crates__form_urlencoded-1.2.2//:form_urlencoded\",\n \"@postmaster_executor_crates__idna-1.1.0//:idna\",\n \"@postmaster_executor_crates__percent-encoding-2.3.2//:percent_encoding\",\n \"@postmaster_executor_crates__serde-1.0.228//:serde\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__serde_derive-1.0.228//:serde_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=url\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.5.8\",\n)\n" + } + }, + "postmaster_executor_crates__urlencoding-2.1.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/urlencoding/2.1.3/download" + ], + "strip_prefix": "urlencoding-2.1.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"urlencoding\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=urlencoding\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.1.3\",\n)\n" + } + }, + "postmaster_executor_crates__utf8_iter-1.0.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/utf8_iter/1.0.4/download" + ], + "strip_prefix": "utf8_iter-1.0.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"utf8_iter\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=utf8_iter\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.4\",\n)\n" + } + }, + "postmaster_executor_crates__uuid-1.23.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/uuid/1.23.1/download" + ], + "strip_prefix": "uuid-1.23.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"uuid\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=uuid\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.23.1\",\n)\n" + } + }, + "postmaster_executor_crates__version_check-0.9.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/version_check/0.9.5/download" + ], + "strip_prefix": "version_check-0.9.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"version_check\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=version_check\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.5\",\n)\n" + } + }, + "postmaster_executor_crates__virtual-fs-0.702.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [ + "@@+_repo_rules31+postmaster_cargo//:patches/cargo/virtual-fs.patch" + ], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/virtual-fs", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"virtual_fs\",\n deps = [\n \"@postmaster_executor_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_executor_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_executor_crates__dashmap-6.1.0//:dashmap\",\n \"@postmaster_executor_crates__derive_more-2.1.1//:derive_more\",\n \"@postmaster_executor_crates__dunce-1.0.5//:dunce\",\n \"@postmaster_executor_crates__filetime-0.2.27//:filetime\",\n \"@postmaster_executor_crates__fs_extra-1.3.0//:fs_extra\",\n \"@postmaster_executor_crates__futures-0.3.32//:futures\",\n \"@postmaster_executor_crates__getrandom-0.4.2//:getrandom\",\n \"@postmaster_executor_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_executor_crates__libc-0.2.186//:libc\",\n \"@postmaster_executor_crates__pin-project-lite-0.2.17//:pin_project_lite\",\n \"@postmaster_executor_crates__replace_with-0.1.8//:replace_with\",\n \"@postmaster_executor_crates__shared-buffer-0.1.4//:shared_buffer\",\n \"@postmaster_executor_crates__slab-0.4.12//:slab\",\n \"@postmaster_executor_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_executor_crates__tokio-1.52.1//:tokio\",\n \"@postmaster_executor_crates__tracing-0.1.44//:tracing\",\n \"@postmaster_executor_crates__virtual-mio-0.702.0-alpha.2//:virtual_mio\",\n \"@postmaster_executor_crates__wasmer-package-0.702.0-alpha.2//:wasmer_package\",\n \"@postmaster_executor_crates__webc-11.0.0//:webc\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__async-trait-0.1.89//:async_trait\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"anyhow\",\n \"filetime\",\n \"fs_extra\",\n \"host-fs\",\n \"libc\",\n \"webc\",\n \"webc-fs\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=virtual-fs\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.702.0-alpha.2\",\n)\n" + } + }, + "postmaster_executor_crates__virtual-mio-0.702.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [ + "@@+_repo_rules31+postmaster_cargo//:patches/cargo/virtual-mio.patch" + ], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/virtual-io", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"virtual_mio\",\n deps = [\n \"@postmaster_executor_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_executor_crates__futures-0.3.32//:futures\",\n \"@postmaster_executor_crates__mio-1.2.0//:mio\",\n \"@postmaster_executor_crates__parking-2.2.1//:parking\",\n \"@postmaster_executor_crates__serde-1.0.228//:serde\",\n \"@postmaster_executor_crates__socket2-0.6.3//:socket2\",\n \"@postmaster_executor_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_executor_crates__tracing-0.1.44//:tracing\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__async-trait-0.1.89//:async_trait\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"mio\",\n \"socket2\",\n \"sys\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=virtual-mio\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.702.0-alpha.2\",\n)\n" + } + }, + "postmaster_executor_crates__virtual-net-0.702.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [ + "@@+_repo_rules31+postmaster_cargo//:patches/cargo/virtual-net.patch" + ], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/virtual-net", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"virtual_net\",\n deps = [\n \"@postmaster_executor_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_executor_crates__base64-0.22.1//:base64\",\n \"@postmaster_executor_crates__bincode-2.0.1//:bincode\",\n \"@postmaster_executor_crates__bytecheck-0.8.2//:bytecheck\",\n \"@postmaster_executor_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_executor_crates__derive_more-2.1.1//:derive_more\",\n \"@postmaster_executor_crates__futures-util-0.3.32//:futures_util\",\n \"@postmaster_executor_crates__ipnet-2.12.0//:ipnet\",\n \"@postmaster_executor_crates__iprange-0.6.7//:iprange\",\n \"@postmaster_executor_crates__libc-0.2.186//:libc\",\n \"@postmaster_executor_crates__mio-1.2.0//:mio\",\n \"@postmaster_executor_crates__pin-project-lite-0.2.17//:pin_project_lite\",\n \"@postmaster_executor_crates__rkyv-0.8.16//:rkyv\",\n \"@postmaster_executor_crates__serde-1.0.228//:serde\",\n \"@postmaster_executor_crates__smoltcp-0.13.0//:smoltcp\",\n \"@postmaster_executor_crates__socket2-0.6.3//:socket2\",\n \"@postmaster_executor_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_executor_crates__tokio-1.52.1//:tokio\",\n \"@postmaster_executor_crates__tracing-0.1.44//:tracing\",\n \"@postmaster_executor_crates__virtual-mio-0.702.0-alpha.2//:virtual_mio\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__async-trait-0.1.89//:async_trait\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"host-net\",\n \"libc\",\n \"mio\",\n \"rkyv\",\n \"socket2\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=virtual-net\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.702.0-alpha.2\",\n)\n" + } + }, + "postmaster_executor_crates__virtue-0.0.18": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/virtue/0.0.18/download" + ], + "strip_prefix": "virtue-0.0.18", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"virtue\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=virtue\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.0.18\",\n)\n" + } + }, + "postmaster_executor_crates__wai-bindgen-gen-core-0.2.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1aa3dc41b510811122b3088197234c27e08fcad63ef936306dd8e11e2803876c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wai-bindgen-gen-core/0.2.3/download" + ], + "strip_prefix": "wai-bindgen-gen-core-0.2.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wai_bindgen_gen_core\",\n deps = [\n \"@postmaster_executor_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_executor_crates__wai-parser-0.2.3//:wai_parser\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wai-bindgen-gen-core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.3\",\n)\n" + } + }, + "postmaster_executor_crates__wai-bindgen-gen-rust-0.2.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "19bc05e8380515c4337c40ef03b2ff233e391315b178a320de8640703d522efe", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wai-bindgen-gen-rust/0.2.3/download" + ], + "strip_prefix": "wai-bindgen-gen-rust-0.2.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wai_bindgen_gen_rust\",\n deps = [\n \"@postmaster_executor_crates__heck-0.3.3//:heck\",\n \"@postmaster_executor_crates__wai-bindgen-gen-core-0.2.3//:wai_bindgen_gen_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wai-bindgen-gen-rust\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.3\",\n)\n" + } + }, + "postmaster_executor_crates__wai-bindgen-gen-rust-wasm-0.2.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d6f35ce5e74086fac87f3a7bd50f643f00fe3559adb75c88521ecaa01c8a6199", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wai-bindgen-gen-rust-wasm/0.2.3/download" + ], + "strip_prefix": "wai-bindgen-gen-rust-wasm-0.2.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wai_bindgen_gen_rust_wasm\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__heck-0.3.3//:heck\",\n \"@postmaster_executor_crates__wai-bindgen-gen-core-0.2.3//:wai_bindgen_gen_core\",\n \"@postmaster_executor_crates__wai-bindgen-gen-rust-0.2.3//:wai_bindgen_gen_rust\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wai-bindgen-gen-rust-wasm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.3\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"wai-bindgen-gen-rust-wasm\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wai-bindgen-gen-rust-wasm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.2.3\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__wai-bindgen-rust-0.2.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4e5601c6f448c063e83a5e931b8fefcdf7e01ada424ad42372c948d2e3d67741", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wai-bindgen-rust/0.2.3/download" + ], + "strip_prefix": "wai-bindgen-rust-0.2.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wai_bindgen_rust\",\n deps = [\n \"@postmaster_executor_crates__bitflags-1.3.2//:bitflags\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__wai-bindgen-rust-impl-0.2.3//:wai_bindgen_rust_impl\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"macros\",\n \"wai-bindgen-rust-impl\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wai-bindgen-rust\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.3\",\n)\n" + } + }, + "postmaster_executor_crates__wai-bindgen-rust-impl-0.2.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bdeeb5c1170246de8425a3e123e7ef260dc05ba2b522a1d369fe2315376efea4", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wai-bindgen-rust-impl/0.2.3/download" + ], + "strip_prefix": "wai-bindgen-rust-impl-0.2.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"wai_bindgen_rust_impl\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__syn-1.0.109//:syn\",\n \"@postmaster_executor_crates__wai-bindgen-gen-core-0.2.3//:wai_bindgen_gen_core\",\n \"@postmaster_executor_crates__wai-bindgen-gen-rust-wasm-0.2.3//:wai_bindgen_gen_rust_wasm\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wai-bindgen-rust-impl\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.3\",\n)\n" + } + }, + "postmaster_executor_crates__wai-parser-0.2.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9bd0acb6d70885ea0c343749019ba74f015f64a9d30542e66db69b49b7e28186", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wai-parser/0.2.3/download" + ], + "strip_prefix": "wai-parser-0.2.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wai_parser\",\n deps = [\n \"@postmaster_executor_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_executor_crates__id-arena-2.3.0//:id_arena\",\n \"@postmaster_executor_crates__pulldown-cmark-0.8.0//:pulldown_cmark\",\n \"@postmaster_executor_crates__unicode-normalization-0.1.25//:unicode_normalization\",\n \"@postmaster_executor_crates__unicode-xid-0.2.6//:unicode_xid\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wai-parser\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.3\",\n)\n" + } + }, + "postmaster_executor_crates__waker-fn-1.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/waker-fn/1.2.0/download" + ], + "strip_prefix": "waker-fn-1.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"waker_fn\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=waker-fn\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.0\",\n)\n" + } + }, + "postmaster_executor_crates__walkdir-2.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/walkdir/2.5.0/download" + ], + "strip_prefix": "walkdir-2.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"walkdir\",\n deps = [\n \"@postmaster_executor_crates__same-file-1.0.6//:same_file\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=walkdir\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.5.0\",\n)\n" + } + }, + "postmaster_executor_crates__wasi-0.11.1-wasi-snapshot-preview1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasi/0.11.1+wasi-snapshot-preview1/download" + ], + "strip_prefix": "wasi-0.11.1+wasi-snapshot-preview1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasi\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasi\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.11.1+wasi-snapshot-preview1\",\n)\n" + } + }, + "postmaster_executor_crates__wasip2-1.0.3-wasi-0.2.9": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasip2/1.0.3+wasi-0.2.9/download" + ], + "strip_prefix": "wasip2-1.0.3+wasi-0.2.9", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasip2\",\n deps = [\n \"@postmaster_executor_crates__wit-bindgen-0.57.1//:wit_bindgen\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasip2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.3+wasi-0.2.9\",\n)\n" + } + }, + "postmaster_executor_crates__wasip3-0.4.0-wasi-0.3.0-rc-2026-01-06": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasip3/0.4.0+wasi-0.3.0-rc-2026-01-06/download" + ], + "strip_prefix": "wasip3-0.4.0+wasi-0.3.0-rc-2026-01-06", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasip3\",\n deps = [\n \"@postmaster_executor_crates__wit-bindgen-0.51.0//:wit_bindgen\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasip3\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.0+wasi-0.3.0-rc-2026-01-06\",\n)\n" + } + }, + "postmaster_executor_crates__wasm-bindgen-0.2.118": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-bindgen/0.2.118/download" + ], + "strip_prefix": "wasm-bindgen-0.2.118", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasm_bindgen\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_executor_crates__once_cell-1.21.4//:once_cell\",\n \"@postmaster_executor_crates__wasm-bindgen-shared-0.2.118//:wasm_bindgen_shared\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__wasm-bindgen-macro-0.2.118//:wasm_bindgen_macro\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.118\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n aliases = {\n \"@postmaster_executor_crates__rustversion-1.0.22//:rustversion\": \"rustversion_compat\",\n },\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n link_deps = [\n \"@postmaster_executor_crates__wasm-bindgen-shared-0.2.118//:wasm_bindgen_shared\",\n ],\n edition = \"2021\",\n pkg_name = \"wasm-bindgen\",\n proc_macro_deps = [\n \"@postmaster_executor_crates__rustversion-1.0.22//:rustversion\",\n ],\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.2.118\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__wasm-bindgen-macro-0.2.118": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-bindgen-macro/0.2.118/download" + ], + "strip_prefix": "wasm-bindgen-macro-0.2.118", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"wasm_bindgen_macro\",\n deps = [\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__wasm-bindgen-macro-support-0.2.118//:wasm_bindgen_macro_support\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen-macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.118\",\n)\n" + } + }, + "postmaster_executor_crates__wasm-bindgen-macro-support-0.2.118": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-bindgen-macro-support/0.2.118/download" + ], + "strip_prefix": "wasm-bindgen-macro-support-0.2.118", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasm_bindgen_macro_support\",\n deps = [\n \"@postmaster_executor_crates__bumpalo-3.20.2//:bumpalo\",\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n \"@postmaster_executor_crates__wasm-bindgen-shared-0.2.118//:wasm_bindgen_shared\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen-macro-support\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.118\",\n)\n" + } + }, + "postmaster_executor_crates__wasm-bindgen-shared-0.2.118": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-bindgen-shared/0.2.118/download" + ], + "strip_prefix": "wasm-bindgen-shared-0.2.118", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasm_bindgen_shared\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__unicode-ident-1.0.24//:unicode_ident\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen-shared\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.118\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n links = \"wasm_bindgen\",\n pkg_name = \"wasm-bindgen-shared\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen-shared\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.2.118\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__wasm-encoder-0.244.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-encoder/0.244.0/download" + ], + "strip_prefix": "wasm-encoder-0.244.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasm_encoder\",\n deps = [\n \"@postmaster_executor_crates__leb128fmt-0.1.0//:leb128fmt\",\n \"@postmaster_executor_crates__wasmparser-0.244.0//:wasmparser\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"component-model\",\n \"std\",\n \"wasmparser\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-encoder\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.244.0\",\n)\n" + } + }, + "postmaster_executor_crates__wasm-encoder-0.247.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "30b6733b8b91d010a6ac5b0fb237dc46a19650bc4c67db66857e2e787d437204", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-encoder/0.247.0/download" + ], + "strip_prefix": "wasm-encoder-0.247.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasm_encoder\",\n deps = [\n \"@postmaster_executor_crates__leb128fmt-0.1.0//:leb128fmt\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"component-model\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-encoder\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.247.0\",\n)\n" + } + }, + "postmaster_executor_crates__wasm-metadata-0.244.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-metadata/0.244.0/download" + ], + "strip_prefix": "wasm-metadata-0.244.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasm_metadata\",\n deps = [\n \"@postmaster_executor_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_executor_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_executor_crates__wasm-encoder-0.244.0//:wasm_encoder\",\n \"@postmaster_executor_crates__wasmparser-0.244.0//:wasmparser\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-metadata\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.244.0\",\n)\n" + } + }, + "postmaster_executor_crates__wasmer-7.2.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [ + "@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer.patch" + ], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/api", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_executor_crates__corosensei-0.3.3//:corosensei\",\n \"@postmaster_executor_crates__derive_more-2.1.1//:derive_more\",\n \"@postmaster_executor_crates__futures-0.3.32//:futures\",\n \"@postmaster_executor_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_executor_crates__more-asserts-0.3.1//:more_asserts\",\n \"@postmaster_executor_crates__shared-buffer-0.1.4//:shared_buffer\",\n \"@postmaster_executor_crates__symbolic-demangle-12.18.3//:symbolic_demangle\",\n \"@postmaster_executor_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_executor_crates__tracing-0.1.44//:tracing\",\n \"@postmaster_executor_crates__wasmer-compiler-7.2.0-alpha.2//:wasmer_compiler\",\n \"@postmaster_executor_crates__wasmer-vm-7.2.0-alpha.2//:wasmer_vm\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__dashmap-6.1.0//:dashmap\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_executor_crates__target-lexicon-0.13.5//:target_lexicon\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_executor_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__dashmap-6.1.0//:dashmap\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_executor_crates__target-lexicon-0.13.5//:target_lexicon\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_executor_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__dashmap-6.1.0//:dashmap\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_executor_crates__target-lexicon-0.13.5//:target_lexicon\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_executor_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"//conditions:default\": [],\n }),\n proc_macro_deps = [\n \"@postmaster_executor_crates__paste-1.0.15//:paste\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__wasmer-derive-7.2.0-alpha.2//:wasmer_derive\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__wasmer-derive-7.2.0-alpha.2//:wasmer_derive\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__wasmer-derive-7.2.0-alpha.2//:wasmer_derive\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"experimental-async\",\n \"headless\",\n \"std\",\n \"sys\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"7.2.0-alpha.2\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"experimental-async\",\n \"headless\",\n \"std\",\n \"sys\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@postmaster_executor_crates__bindgen-0.72.1//:bindgen\",\n \"@postmaster_executor_crates__cmake-0.1.58//:cmake\",\n \"@postmaster_executor_crates__tar-0.4.45//:tar\",\n ],\n emit_warnings = False,\n edition = \"2024\",\n pkg_name = \"wasmer\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"7.2.0-alpha.2\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__wasmer-compiler-7.2.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [ + "@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-compiler.patch" + ], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/compiler", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_compiler\",\n deps = [\n \"@postmaster_executor_crates__backtrace-0.3.76//:backtrace\",\n \"@postmaster_executor_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_executor_crates__enum-iterator-2.3.0//:enum_iterator\",\n \"@postmaster_executor_crates__enumset-1.1.10//:enumset\",\n \"@postmaster_executor_crates__itertools-0.14.0//:itertools\",\n \"@postmaster_executor_crates__leb128-0.2.6//:leb128\",\n \"@postmaster_executor_crates__libc-0.2.186//:libc\",\n \"@postmaster_executor_crates__memmap2-0.9.10//:memmap2\",\n \"@postmaster_executor_crates__more-asserts-0.3.1//:more_asserts\",\n \"@postmaster_executor_crates__object-0.39.1//:object\",\n \"@postmaster_executor_crates__rangemap-1.7.1//:rangemap\",\n \"@postmaster_executor_crates__rkyv-0.8.16//:rkyv\",\n \"@postmaster_executor_crates__self_cell-1.2.2//:self_cell\",\n \"@postmaster_executor_crates__shared-buffer-0.1.4//:shared_buffer\",\n \"@postmaster_executor_crates__smallvec-1.15.1//:smallvec\",\n \"@postmaster_executor_crates__target-lexicon-0.13.5//:target_lexicon\",\n \"@postmaster_executor_crates__tempfile-3.27.0//:tempfile\",\n \"@postmaster_executor_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_executor_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__crossbeam-channel-0.5.15//:crossbeam_channel\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_executor_crates__macho-unwind-info-0.5.0//:macho_unwind_info\", # cfg(all(target_os = \"macos\", target_arch = \"aarch64\"))\n \"@postmaster_executor_crates__rayon-1.12.0//:rayon\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_executor_crates__region-3.0.2//:region\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_executor_crates__wasmer-vm-7.2.0-alpha.2//:wasmer_vm\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_executor_crates__which-8.0.2//:which\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__crossbeam-channel-0.5.15//:crossbeam_channel\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_executor_crates__rayon-1.12.0//:rayon\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_executor_crates__region-3.0.2//:region\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_executor_crates__wasmer-vm-7.2.0-alpha.2//:wasmer_vm\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_executor_crates__which-8.0.2//:which\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__crossbeam-channel-0.5.15//:crossbeam_channel\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_executor_crates__rayon-1.12.0//:rayon\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_executor_crates__region-3.0.2//:region\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_executor_crates__wasmer-vm-7.2.0-alpha.2//:wasmer_vm\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_executor_crates__which-8.0.2//:which\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"//conditions:default\": [],\n }),\n link_deps = [\n \"@@//build_defs/wasix/postmaster:linked_unwinder\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n \"--cfg=oliphaunt_linked_libunwind\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-compiler\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"7.2.0-alpha.2\",\n)\n" + } + }, + "postmaster_executor_crates__wasmer-config-0.702.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/config", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_config\",\n deps = [\n \"@postmaster_executor_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_executor_crates__bytesize-2.3.1//:bytesize\",\n \"@postmaster_executor_crates__ciborium-0.2.2//:ciborium\",\n \"@postmaster_executor_crates__derive_builder-0.20.2//:derive_builder\",\n \"@postmaster_executor_crates__hex-0.4.3//:hex\",\n \"@postmaster_executor_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_executor_crates__saffron-0.1.0//:saffron\",\n \"@postmaster_executor_crates__schemars-1.2.1//:schemars\",\n \"@postmaster_executor_crates__semver-1.0.28//:semver\",\n \"@postmaster_executor_crates__serde-1.0.228//:serde\",\n \"@postmaster_executor_crates__serde_json-1.0.149//:serde_json\",\n \"@postmaster_executor_crates__serde_yaml-0.9.34-deprecated//:serde_yaml\",\n \"@postmaster_executor_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_executor_crates__toml-1.1.2-spec-1.1.0//:toml\",\n \"@postmaster_executor_crates__url-2.5.8//:url\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-config\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.702.0-alpha.2\",\n)\n" + } + }, + "postmaster_executor_crates__wasmer-derive-7.2.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/derive", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"wasmer_derive\",\n deps = [\n \"@postmaster_executor_crates__proc-macro-error2-2.0.1//:proc_macro_error2\",\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"7.2.0-alpha.2\",\n)\n" + } + }, + "postmaster_executor_crates__wasmer-journal-0.702.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/journal", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_journal\",\n deps = [\n \"@postmaster_executor_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_executor_crates__base64-0.22.1//:base64\",\n \"@postmaster_executor_crates__bincode-2.0.1//:bincode\",\n \"@postmaster_executor_crates__bytecheck-0.8.2//:bytecheck\",\n \"@postmaster_executor_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_executor_crates__derive_more-2.1.1//:derive_more\",\n \"@postmaster_executor_crates__lz4_flex-0.13.0//:lz4_flex\",\n \"@postmaster_executor_crates__num_enum-0.7.6//:num_enum\",\n \"@postmaster_executor_crates__rkyv-0.8.16//:rkyv\",\n \"@postmaster_executor_crates__serde-1.0.228//:serde\",\n \"@postmaster_executor_crates__serde_json-1.0.149//:serde_json\",\n \"@postmaster_executor_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_executor_crates__tracing-0.1.44//:tracing\",\n \"@postmaster_executor_crates__virtual-fs-0.702.0-alpha.2//:virtual_fs\",\n \"@postmaster_executor_crates__virtual-net-0.702.0-alpha.2//:virtual_net\",\n \"@postmaster_executor_crates__wasmer-7.2.0-alpha.2//:wasmer\",\n \"@postmaster_executor_crates__wasmer-config-0.702.0-alpha.2//:wasmer_config\",\n \"@postmaster_executor_crates__wasmer-wasix-types-0.702.0-alpha.2//:wasmer_wasix_types\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__async-trait-0.1.89//:async_trait\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-journal\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.702.0-alpha.2\",\n)\n" + } + }, + "postmaster_executor_crates__wasmer-package-0.702.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/package", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_package\",\n deps = [\n \"@postmaster_executor_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_executor_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_executor_crates__ciborium-0.2.2//:ciborium\",\n \"@postmaster_executor_crates__flate2-1.1.9//:flate2\",\n \"@postmaster_executor_crates__ignore-0.4.25//:ignore\",\n \"@postmaster_executor_crates__insta-1.47.2//:insta\",\n \"@postmaster_executor_crates__semver-1.0.28//:semver\",\n \"@postmaster_executor_crates__serde-1.0.228//:serde\",\n \"@postmaster_executor_crates__serde_json-1.0.149//:serde_json\",\n \"@postmaster_executor_crates__sha2-0.11.0//:sha2\",\n \"@postmaster_executor_crates__shared-buffer-0.1.4//:shared_buffer\",\n \"@postmaster_executor_crates__tar-0.4.45//:tar\",\n \"@postmaster_executor_crates__tempfile-3.27.0//:tempfile\",\n \"@postmaster_executor_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_executor_crates__toml-1.1.2-spec-1.1.0//:toml\",\n \"@postmaster_executor_crates__url-2.5.8//:url\",\n \"@postmaster_executor_crates__wasmer-config-0.702.0-alpha.2//:wasmer_config\",\n \"@postmaster_executor_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\",\n \"@postmaster_executor_crates__webc-11.0.0//:webc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-package\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.702.0-alpha.2\",\n)\n" + } + }, + "postmaster_executor_crates__wasmer-types-7.2.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [ + "@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-types.patch" + ], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/types", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_types\",\n deps = [\n \"@postmaster_executor_crates__bytecheck-0.8.2//:bytecheck\",\n \"@postmaster_executor_crates__crc32fast-1.5.0//:crc32fast\",\n \"@postmaster_executor_crates__enum-iterator-2.3.0//:enum_iterator\",\n \"@postmaster_executor_crates__enumset-1.1.10//:enumset\",\n \"@postmaster_executor_crates__getrandom-0.4.2//:getrandom\",\n \"@postmaster_executor_crates__hex-0.4.3//:hex\",\n \"@postmaster_executor_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_executor_crates__itertools-0.14.0//:itertools\",\n \"@postmaster_executor_crates__more-asserts-0.3.1//:more_asserts\",\n \"@postmaster_executor_crates__rkyv-0.8.16//:rkyv\",\n \"@postmaster_executor_crates__serde-1.0.228//:serde\",\n \"@postmaster_executor_crates__sha2-0.11.0//:sha2\",\n \"@postmaster_executor_crates__target-lexicon-0.13.5//:target_lexicon\",\n \"@postmaster_executor_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_executor_crates__wasmparser-0.247.0//:wasmparser\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"detect-wasm-features\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-types\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"7.2.0-alpha.2\",\n)\n" + } + }, + "postmaster_executor_crates__wasmer-vm-7.2.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [ + "@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-vm.patch" + ], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/vm", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_vm\",\n deps = [\n \"@postmaster_executor_crates__backtrace-0.3.76//:backtrace\",\n \"@postmaster_executor_crates__bytesize-2.3.1//:bytesize\",\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_executor_crates__corosensei-0.3.3//:corosensei\",\n \"@postmaster_executor_crates__crossbeam-queue-0.3.12//:crossbeam_queue\",\n \"@postmaster_executor_crates__dashmap-6.1.0//:dashmap\",\n \"@postmaster_executor_crates__enum-iterator-2.3.0//:enum_iterator\",\n \"@postmaster_executor_crates__fnv-1.0.7//:fnv\",\n \"@postmaster_executor_crates__gimli-0.33.0//:gimli\",\n \"@postmaster_executor_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_executor_crates__itertools-0.14.0//:itertools\",\n \"@postmaster_executor_crates__libc-0.2.186//:libc\",\n \"@postmaster_executor_crates__memoffset-0.9.1//:memoffset\",\n \"@postmaster_executor_crates__more-asserts-0.3.1//:more_asserts\",\n \"@postmaster_executor_crates__parking_lot-0.12.5//:parking_lot\",\n \"@postmaster_executor_crates__region-3.0.2//:region\",\n \"@postmaster_executor_crates__scopeguard-1.2.0//:scopeguard\",\n \"@postmaster_executor_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_executor_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__libunwind-1.3.3//:libunwind\", # cfg(any(target_family = \"unix\", all(target_family = \"windows\", target_env = \"gnu\")))\n \"@postmaster_executor_crates__mach2-0.6.0//:mach2\", # cfg(target_vendor = \"apple\")\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libunwind-1.3.3//:libunwind\", # cfg(any(target_family = \"unix\", all(target_family = \"windows\", target_env = \"gnu\")))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libunwind-1.3.3//:libunwind\", # cfg(any(target_family = \"unix\", all(target_family = \"windows\", target_env = \"gnu\")))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-vm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"7.2.0-alpha.2\",\n)\n" + } + }, + "postmaster_executor_crates__wasmer-wasix-0.702.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [ + "@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-wasix.patch" + ], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/wasix", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_wasix\",\n deps = [\n \"@postmaster_executor_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_executor_crates__base64-0.22.1//:base64\",\n \"@postmaster_executor_crates__bincode-2.0.1//:bincode\",\n \"@postmaster_executor_crates__blake3-1.8.4//:blake3\",\n \"@postmaster_executor_crates__bytecheck-0.8.2//:bytecheck\",\n \"@postmaster_executor_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_executor_crates__cooked-waker-5.0.0//:cooked_waker\",\n \"@postmaster_executor_crates__crossbeam-channel-0.5.15//:crossbeam_channel\",\n \"@postmaster_executor_crates__dashmap-6.1.0//:dashmap\",\n \"@postmaster_executor_crates__derive_more-2.1.1//:derive_more\",\n \"@postmaster_executor_crates__flate2-1.1.9//:flate2\",\n \"@postmaster_executor_crates__fnv-1.0.7//:fnv\",\n \"@postmaster_executor_crates__futures-0.3.32//:futures\",\n \"@postmaster_executor_crates__getrandom-0.4.2//:getrandom\",\n \"@postmaster_executor_crates__heapless-0.9.2//:heapless\",\n \"@postmaster_executor_crates__hex-0.4.3//:hex\",\n \"@postmaster_executor_crates__http-1.4.0//:http\",\n \"@postmaster_executor_crates__linked_hash_set-0.1.6//:linked_hash_set\",\n \"@postmaster_executor_crates__lz4_flex-0.13.0//:lz4_flex\",\n \"@postmaster_executor_crates__num_enum-0.7.6//:num_enum\",\n \"@postmaster_executor_crates__once_cell-1.21.4//:once_cell\",\n \"@postmaster_executor_crates__petgraph-0.8.3//:petgraph\",\n \"@postmaster_executor_crates__pin-project-1.1.11//:pin_project\",\n \"@postmaster_executor_crates__pin-utils-0.1.0//:pin_utils\",\n \"@postmaster_executor_crates__rand-0.10.1//:rand\",\n \"@postmaster_executor_crates__rkyv-0.8.16//:rkyv\",\n \"@postmaster_executor_crates__rusty_pool-0.7.0//:rusty_pool\",\n \"@postmaster_executor_crates__semver-1.0.28//:semver\",\n \"@postmaster_executor_crates__serde-1.0.228//:serde\",\n \"@postmaster_executor_crates__serde_json-1.0.149//:serde_json\",\n \"@postmaster_executor_crates__serde_yaml-0.9.34-deprecated//:serde_yaml\",\n \"@postmaster_executor_crates__sha2-0.11.0//:sha2\",\n \"@postmaster_executor_crates__shared-buffer-0.1.4//:shared_buffer\",\n \"@postmaster_executor_crates__tempfile-3.27.0//:tempfile\",\n \"@postmaster_executor_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_executor_crates__tokio-1.52.1//:tokio\",\n \"@postmaster_executor_crates__tokio-stream-0.1.18//:tokio_stream\",\n \"@postmaster_executor_crates__toml-1.1.2-spec-1.1.0//:toml\",\n \"@postmaster_executor_crates__tracing-0.1.44//:tracing\",\n \"@postmaster_executor_crates__url-2.5.8//:url\",\n \"@postmaster_executor_crates__urlencoding-2.1.3//:urlencoding\",\n \"@postmaster_executor_crates__virtual-fs-0.702.0-alpha.2//:virtual_fs\",\n \"@postmaster_executor_crates__virtual-mio-0.702.0-alpha.2//:virtual_mio\",\n \"@postmaster_executor_crates__virtual-net-0.702.0-alpha.2//:virtual_net\",\n \"@postmaster_executor_crates__waker-fn-1.2.0//:waker_fn\",\n \"@postmaster_executor_crates__wasm-encoder-0.247.0//:wasm_encoder\",\n \"@postmaster_executor_crates__wasmer-7.2.0-alpha.2//:wasmer\",\n \"@postmaster_executor_crates__wasmer-config-0.702.0-alpha.2//:wasmer_config\",\n \"@postmaster_executor_crates__wasmer-journal-0.702.0-alpha.2//:wasmer_journal\",\n \"@postmaster_executor_crates__wasmer-package-0.702.0-alpha.2//:wasmer_package\",\n \"@postmaster_executor_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\",\n \"@postmaster_executor_crates__wasmer-wasix-types-0.702.0-alpha.2//:wasmer_wasix_types\",\n \"@postmaster_executor_crates__wasmparser-0.247.0//:wasmparser\",\n \"@postmaster_executor_crates__webc-11.0.0//:webc\",\n \"@postmaster_executor_crates__weezl-0.1.12//:weezl\",\n \"@postmaster_executor_crates__xxhash-rust-0.8.15//:xxhash_rust\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n \"@postmaster_executor_crates__terminal_size-0.4.4//:terminal_size\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_executor_crates__termios-0.3.3//:termios\", # cfg(all(unix, not(target_os = \"ios\")))\n \"@postmaster_executor_crates__zstd-0.13.3//:zstd\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n \"@postmaster_executor_crates__terminal_size-0.4.4//:terminal_size\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_executor_crates__termios-0.3.3//:termios\", # cfg(all(unix, not(target_os = \"ios\")))\n \"@postmaster_executor_crates__zstd-0.13.3//:zstd\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\", # cfg(unix)\n \"@postmaster_executor_crates__terminal_size-0.4.4//:terminal_size\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_executor_crates__termios-0.3.3//:termios\", # cfg(all(unix, not(target_os = \"ios\")))\n \"@postmaster_executor_crates__zstd-0.13.3//:zstd\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"//conditions:default\": [],\n }),\n proc_macro_deps = [\n \"@postmaster_executor_crates__async-trait-0.1.89//:async_trait\",\n \"@postmaster_executor_crates__serde_derive-1.0.228//:serde_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"ctrlc\",\n \"disable-all-logging\",\n \"host-fs\",\n \"host-threads\",\n \"host-vnet\",\n \"rusty_pool\",\n \"sys-minimal\",\n \"sys-poll\",\n \"sys-thread\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-wasix\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.702.0-alpha.2\",\n)\n" + } + }, + "postmaster_executor_crates__wasmer-wasix-types-0.702.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/wasi-types", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_wasix_types\",\n deps = [\n \"@postmaster_executor_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_executor_crates__bitflags-2.11.1//:bitflags\",\n \"@postmaster_executor_crates__byteorder-1.5.0//:byteorder\",\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_executor_crates__num_enum-0.7.6//:num_enum\",\n \"@postmaster_executor_crates__serde-1.0.228//:serde\",\n \"@postmaster_executor_crates__time-0.3.47//:time\",\n \"@postmaster_executor_crates__tracing-0.1.44//:tracing\",\n \"@postmaster_executor_crates__wai-bindgen-gen-core-0.2.3//:wai_bindgen_gen_core\",\n \"@postmaster_executor_crates__wai-bindgen-gen-rust-0.2.3//:wai_bindgen_gen_rust\",\n \"@postmaster_executor_crates__wai-bindgen-gen-rust-wasm-0.2.3//:wai_bindgen_gen_rust_wasm\",\n \"@postmaster_executor_crates__wai-bindgen-rust-0.2.3//:wai_bindgen_rust\",\n \"@postmaster_executor_crates__wai-parser-0.2.3//:wai_parser\",\n \"@postmaster_executor_crates__wasmer-7.2.0-alpha.2//:wasmer\",\n \"@postmaster_executor_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__wasmer-derive-7.2.0-alpha.2//:wasmer_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"enable-serde\",\n \"serde\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-wasix-types\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.702.0-alpha.2\",\n)\n" + } + }, + "postmaster_executor_crates__wasmparser-0.244.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasmparser/0.244.0/download" + ], + "strip_prefix": "wasmparser-0.244.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmparser\",\n deps = [\n \"@postmaster_executor_crates__bitflags-2.11.1//:bitflags\",\n \"@postmaster_executor_crates__hashbrown-0.15.5//:hashbrown\",\n \"@postmaster_executor_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_executor_crates__semver-1.0.28//:semver\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"component-model\",\n \"features\",\n \"hash-collections\",\n \"simd\",\n \"std\",\n \"validate\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmparser\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.244.0\",\n)\n" + } + }, + "postmaster_executor_crates__wasmparser-0.247.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8e6fb4c2bee46c5ea4d40f8cdb5c131725cd976718ec56f1c8e82fbde5fa2a80", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasmparser/0.247.0/download" + ], + "strip_prefix": "wasmparser-0.247.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmparser\",\n deps = [\n \"@postmaster_executor_crates__bitflags-2.11.1//:bitflags\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"features\",\n \"simd\",\n \"validate\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmparser\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.247.0\",\n)\n" + } + }, + "postmaster_executor_crates__wast-247.0.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "579d2d47eb33b0cdf9b14723cb115f1e1b7d6e77aac6f0816e5b7c7aeaa418ff", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wast/247.0.0/download" + ], + "strip_prefix": "wast-247.0.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wast\",\n deps = [\n \"@postmaster_executor_crates__bumpalo-3.20.2//:bumpalo\",\n \"@postmaster_executor_crates__leb128fmt-0.1.0//:leb128fmt\",\n \"@postmaster_executor_crates__memchr-2.8.0//:memchr\",\n \"@postmaster_executor_crates__unicode-width-0.2.2//:unicode_width\",\n \"@postmaster_executor_crates__wasm-encoder-0.247.0//:wasm_encoder\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"component-model\",\n \"wasm-module\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wast\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"247.0.0\",\n)\n" + } + }, + "postmaster_executor_crates__wat-1.247.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f3f4091c56437e86f2b57fa2fac72c4f528957a605b3f44f7c0b3b19a17ac5ee", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wat/1.247.0/download" + ], + "strip_prefix": "wat-1.247.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wat\",\n deps = [\n \"@postmaster_executor_crates__wast-247.0.0//:wast\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"component-model\",\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wat\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.247.0\",\n)\n" + } + }, + "postmaster_executor_crates__webc-11.0.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "20b8b523112384e8c1caf77cffdd371ca7e0013779f081e6beafc537f5b5325d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/webc/11.0.0/download" + ], + "strip_prefix": "webc-11.0.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"webc\",\n deps = [\n \"@postmaster_executor_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_executor_crates__base64-0.22.1//:base64\",\n \"@postmaster_executor_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_executor_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_executor_crates__ciborium-0.2.2//:ciborium\",\n \"@postmaster_executor_crates__ignore-0.4.25//:ignore\",\n \"@postmaster_executor_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_executor_crates__leb128-0.2.6//:leb128\",\n \"@postmaster_executor_crates__lexical-sort-0.3.1//:lexical_sort\",\n \"@postmaster_executor_crates__libc-0.2.186//:libc\",\n \"@postmaster_executor_crates__once_cell-1.21.4//:once_cell\",\n \"@postmaster_executor_crates__path-clean-1.0.1//:path_clean\",\n \"@postmaster_executor_crates__rand-0.9.4//:rand\",\n \"@postmaster_executor_crates__serde-1.0.228//:serde\",\n \"@postmaster_executor_crates__serde_json-1.0.149//:serde_json\",\n \"@postmaster_executor_crates__sha2-0.10.9//:sha2\",\n \"@postmaster_executor_crates__shared-buffer-0.1.4//:shared_buffer\",\n \"@postmaster_executor_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_executor_crates__url-2.5.8//:url\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__document-features-0.2.12//:document_features\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"v1\",\n \"v2\",\n \"v3\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=webc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"11.0.0\",\n)\n" + } + }, + "postmaster_executor_crates__weezl-0.1.12": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/weezl/0.1.12/download" + ], + "strip_prefix": "weezl-0.1.12", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"weezl\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=weezl\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.12\",\n)\n" + } + }, + "postmaster_executor_crates__which-8.0.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "81995fafaaaf6ae47a7d0cc83c67caf92aeb7e5331650ae6ff856f7c0c60c459", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/which/8.0.2/download" + ], + "strip_prefix": "which-8.0.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"which\",\n deps = [\n \"@postmaster_executor_crates__libc-0.2.186//:libc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"real-sys\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=which\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"8.0.2\",\n)\n" + } + }, + "postmaster_executor_crates__winapi-util-0.1.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/winapi-util/0.1.11/download" + ], + "strip_prefix": "winapi-util-0.1.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"winapi_util\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=winapi-util\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.11\",\n)\n" + } + }, + "postmaster_executor_crates__windows-link-0.2.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows-link/0.2.1/download" + ], + "strip_prefix": "windows-link-0.2.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_link\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows-link\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.1\",\n)\n" + } + }, + "postmaster_executor_crates__windows-sys-0.52.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows-sys/0.52.0/download" + ], + "strip_prefix": "windows-sys-0.52.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_sys\",\n deps = [\n \"@postmaster_executor_crates__windows-targets-0.52.6//:windows_targets\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.0\",\n)\n" + } + }, + "postmaster_executor_crates__windows-sys-0.59.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows-sys/0.59.0/download" + ], + "strip_prefix": "windows-sys-0.59.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_sys\",\n deps = [\n \"@postmaster_executor_crates__windows-targets-0.52.6//:windows_targets\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.59.0\",\n)\n" + } + }, + "postmaster_executor_crates__windows-sys-0.61.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows-sys/0.61.2/download" + ], + "strip_prefix": "windows-sys-0.61.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_sys\",\n deps = [\n \"@postmaster_executor_crates__windows-link-0.2.1//:windows_link\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.61.2\",\n)\n" + } + }, + "postmaster_executor_crates__windows-targets-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows-targets/0.52.6/download" + ], + "strip_prefix": "windows-targets-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_targets\",\n deps = select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__windows_x86_64_gnu-0.52.6//:windows_x86_64_gnu\", # cfg(all(target_arch = \"x86_64\", target_env = \"gnu\", not(target_abi = \"llvm\"), not(windows_raw_dylib)))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows-targets\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n" + } + }, + "postmaster_executor_crates__windows_aarch64_gnullvm-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_aarch64_gnullvm/0.52.6/download" + ], + "strip_prefix": "windows_aarch64_gnullvm-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_aarch64_gnullvm\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_aarch64_gnullvm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_aarch64_gnullvm\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_aarch64_gnullvm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__windows_aarch64_msvc-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_aarch64_msvc/0.52.6/download" + ], + "strip_prefix": "windows_aarch64_msvc-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_aarch64_msvc\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_aarch64_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_aarch64_msvc\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_aarch64_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__windows_i686_gnu-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_i686_gnu/0.52.6/download" + ], + "strip_prefix": "windows_i686_gnu-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_i686_gnu\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_i686_gnu\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_i686_gnu\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_i686_gnu\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__windows_i686_gnullvm-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_i686_gnullvm/0.52.6/download" + ], + "strip_prefix": "windows_i686_gnullvm-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_i686_gnullvm\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_i686_gnullvm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_i686_gnullvm\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_i686_gnullvm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__windows_i686_msvc-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_i686_msvc/0.52.6/download" + ], + "strip_prefix": "windows_i686_msvc-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_i686_msvc\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_i686_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_i686_msvc\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_i686_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__windows_x86_64_gnu-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_x86_64_gnu/0.52.6/download" + ], + "strip_prefix": "windows_x86_64_gnu-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_x86_64_gnu\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_gnu\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_x86_64_gnu\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_gnu\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__windows_x86_64_gnullvm-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_x86_64_gnullvm/0.52.6/download" + ], + "strip_prefix": "windows_x86_64_gnullvm-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_x86_64_gnullvm\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_gnullvm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_x86_64_gnullvm\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_gnullvm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__windows_x86_64_msvc-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_x86_64_msvc/0.52.6/download" + ], + "strip_prefix": "windows_x86_64_msvc-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_x86_64_msvc\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_x86_64_msvc\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__winnow-1.0.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/winnow/1.0.2/download" + ], + "strip_prefix": "winnow-1.0.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"winnow\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"ascii\",\n \"binary\",\n \"default\",\n \"parser\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=winnow\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.2\",\n)\n" + } + }, + "postmaster_executor_crates__wit-bindgen-0.51.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wit-bindgen/0.51.0/download" + ], + "strip_prefix": "wit-bindgen-0.51.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wit_bindgen\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wit-bindgen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.51.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2024\",\n pkg_name = \"wit-bindgen\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wit-bindgen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.51.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__wit-bindgen-0.57.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wit-bindgen/0.57.1/download" + ], + "strip_prefix": "wit-bindgen-0.57.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wit_bindgen\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wit-bindgen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.57.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2024\",\n pkg_name = \"wit-bindgen\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wit-bindgen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.57.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__wit-bindgen-core-0.51.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wit-bindgen-core/0.51.0/download" + ], + "strip_prefix": "wit-bindgen-core-0.51.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wit_bindgen_core\",\n deps = [\n \"@postmaster_executor_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_executor_crates__heck-0.5.0//:heck\",\n \"@postmaster_executor_crates__wit-parser-0.244.0//:wit_parser\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wit-bindgen-core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.51.0\",\n)\n" + } + }, + "postmaster_executor_crates__wit-bindgen-rust-0.51.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wit-bindgen-rust/0.51.0/download" + ], + "strip_prefix": "wit-bindgen-rust-0.51.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wit_bindgen_rust\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_executor_crates__heck-0.5.0//:heck\",\n \"@postmaster_executor_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_executor_crates__prettyplease-0.2.37//:prettyplease\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n \"@postmaster_executor_crates__wasm-metadata-0.244.0//:wasm_metadata\",\n \"@postmaster_executor_crates__wit-bindgen-core-0.51.0//:wit_bindgen_core\",\n \"@postmaster_executor_crates__wit-component-0.244.0//:wit_component\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wit-bindgen-rust\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.51.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n link_deps = [\n \"@postmaster_executor_crates__prettyplease-0.2.37//:prettyplease\",\n ],\n edition = \"2024\",\n pkg_name = \"wit-bindgen-rust\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wit-bindgen-rust\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.51.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__wit-bindgen-rust-macro-0.51.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wit-bindgen-rust-macro/0.51.0/download" + ], + "strip_prefix": "wit-bindgen-rust-macro-0.51.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"wit_bindgen_rust_macro\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_executor_crates__prettyplease-0.2.37//:prettyplease\",\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n \"@postmaster_executor_crates__wit-bindgen-core-0.51.0//:wit_bindgen_core\",\n \"@postmaster_executor_crates__wit-bindgen-rust-0.51.0//:wit_bindgen_rust\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wit-bindgen-rust-macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.51.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n link_deps = [\n \"@postmaster_executor_crates__prettyplease-0.2.37//:prettyplease\",\n ],\n edition = \"2024\",\n pkg_name = \"wit-bindgen-rust-macro\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wit-bindgen-rust-macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.51.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__wit-component-0.244.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wit-component/0.244.0/download" + ], + "strip_prefix": "wit-component-0.244.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wit_component\",\n deps = [\n \"@postmaster_executor_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_executor_crates__bitflags-2.11.1//:bitflags\",\n \"@postmaster_executor_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_executor_crates__log-0.4.29//:log\",\n \"@postmaster_executor_crates__serde-1.0.228//:serde\",\n \"@postmaster_executor_crates__serde_json-1.0.149//:serde_json\",\n \"@postmaster_executor_crates__wasm-encoder-0.244.0//:wasm_encoder\",\n \"@postmaster_executor_crates__wasm-metadata-0.244.0//:wasm_metadata\",\n \"@postmaster_executor_crates__wasmparser-0.244.0//:wasmparser\",\n \"@postmaster_executor_crates__wit-parser-0.244.0//:wit_parser\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__serde_derive-1.0.228//:serde_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wit-component\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.244.0\",\n)\n" + } + }, + "postmaster_executor_crates__wit-parser-0.244.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wit-parser/0.244.0/download" + ], + "strip_prefix": "wit-parser-0.244.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wit_parser\",\n deps = [\n \"@postmaster_executor_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_executor_crates__id-arena-2.3.0//:id_arena\",\n \"@postmaster_executor_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_executor_crates__log-0.4.29//:log\",\n \"@postmaster_executor_crates__semver-1.0.28//:semver\",\n \"@postmaster_executor_crates__serde-1.0.228//:serde\",\n \"@postmaster_executor_crates__serde_json-1.0.149//:serde_json\",\n \"@postmaster_executor_crates__unicode-xid-0.2.6//:unicode_xid\",\n \"@postmaster_executor_crates__wasmparser-0.244.0//:wasmparser\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__serde_derive-1.0.228//:serde_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"decoding\",\n \"default\",\n \"serde\",\n \"serde_json\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wit-parser\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.244.0\",\n)\n" + } + }, + "postmaster_executor_crates__writeable-0.6.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/writeable/0.6.3/download" + ], + "strip_prefix": "writeable-0.6.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"writeable\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=writeable\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.3\",\n)\n" + } + }, + "postmaster_executor_crates__xattr-1.6.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/xattr/1.6.1/download" + ], + "strip_prefix": "xattr-1.6.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"xattr\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_executor_crates__rustix-1.1.4//:rustix\", # cfg(any(target_os = \"android\", target_os = \"linux\", target_os = \"macos\", target_os = \"hurd\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__rustix-1.1.4//:rustix\", # cfg(any(target_os = \"android\", target_os = \"linux\", target_os = \"macos\", target_os = \"hurd\"))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_executor_crates__rustix-1.1.4//:rustix\", # cfg(any(target_os = \"android\", target_os = \"linux\", target_os = \"macos\", target_os = \"hurd\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"unsupported\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=xattr\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.6.1\",\n)\n" + } + }, + "postmaster_executor_crates__xxhash-rust-0.8.15": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/xxhash-rust/0.8.15/download" + ], + "strip_prefix": "xxhash-rust-0.8.15", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"xxhash_rust\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"xxh64\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=xxhash-rust\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.15\",\n)\n" + } + }, + "postmaster_executor_crates__yoke-0.8.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/yoke/0.8.2/download" + ], + "strip_prefix": "yoke-0.8.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"yoke\",\n deps = [\n \"@postmaster_executor_crates__stable_deref_trait-1.2.1//:stable_deref_trait\",\n \"@postmaster_executor_crates__zerofrom-0.1.7//:zerofrom\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__yoke-derive-0.8.2//:yoke_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"derive\",\n \"zerofrom\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=yoke\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.2\",\n)\n" + } + }, + "postmaster_executor_crates__yoke-derive-0.8.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/yoke-derive/0.8.2/download" + ], + "strip_prefix": "yoke-derive-0.8.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"yoke_derive\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n \"@postmaster_executor_crates__synstructure-0.13.2//:synstructure\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=yoke-derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.2\",\n)\n" + } + }, + "postmaster_executor_crates__zerocopy-0.8.48": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zerocopy/0.8.48/download" + ], + "strip_prefix": "zerocopy-0.8.48", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"zerocopy\",\n deps = [\n \":build_script_build\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__zerocopy-derive-0.8.48//:zerocopy_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"derive\",\n \"simd\",\n \"zerocopy-derive\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerocopy\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.48\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"derive\",\n \"simd\",\n \"zerocopy-derive\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"zerocopy\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerocopy\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.8.48\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__zerocopy-derive-0.8.48": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zerocopy-derive/0.8.48/download" + ], + "strip_prefix": "zerocopy-derive-0.8.48", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"zerocopy_derive\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerocopy-derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.48\",\n)\n" + } + }, + "postmaster_executor_crates__zerofrom-0.1.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zerofrom/0.1.7/download" + ], + "strip_prefix": "zerofrom-0.1.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"zerofrom\",\n proc_macro_deps = [\n \"@postmaster_executor_crates__zerofrom-derive-0.1.7//:zerofrom_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"derive\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerofrom\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.7\",\n)\n" + } + }, + "postmaster_executor_crates__zerofrom-derive-0.1.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zerofrom-derive/0.1.7/download" + ], + "strip_prefix": "zerofrom-derive-0.1.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"zerofrom_derive\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n \"@postmaster_executor_crates__synstructure-0.13.2//:synstructure\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerofrom-derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.7\",\n)\n" + } + }, + "postmaster_executor_crates__zerotrie-0.2.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zerotrie/0.2.4/download" + ], + "strip_prefix": "zerotrie-0.2.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"zerotrie\",\n deps = [\n \"@postmaster_executor_crates__yoke-0.8.2//:yoke\",\n \"@postmaster_executor_crates__zerofrom-0.1.7//:zerofrom\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__displaydoc-0.2.5//:displaydoc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"yoke\",\n \"zerofrom\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerotrie\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.4\",\n)\n" + } + }, + "postmaster_executor_crates__zerovec-0.11.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zerovec/0.11.6/download" + ], + "strip_prefix": "zerovec-0.11.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"zerovec\",\n deps = [\n \"@postmaster_executor_crates__yoke-0.8.2//:yoke\",\n \"@postmaster_executor_crates__zerofrom-0.1.7//:zerofrom\",\n ],\n proc_macro_deps = [\n \"@postmaster_executor_crates__zerovec-derive-0.11.3//:zerovec_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"derive\",\n \"yoke\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerovec\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.11.6\",\n)\n" + } + }, + "postmaster_executor_crates__zerovec-derive-0.11.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zerovec-derive/0.11.3/download" + ], + "strip_prefix": "zerovec-derive-0.11.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"zerovec_derive\",\n deps = [\n \"@postmaster_executor_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_executor_crates__quote-1.0.45//:quote\",\n \"@postmaster_executor_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerovec-derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.11.3\",\n)\n" + } + }, + "postmaster_executor_crates__zmij-1.0.21": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zmij/1.0.21/download" + ], + "strip_prefix": "zmij-1.0.21", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"zmij\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zmij\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.21\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"zmij\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zmij\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.21\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__zstd-0.13.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zstd/0.13.3/download" + ], + "strip_prefix": "zstd-0.13.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"zstd\",\n deps = [\n \"@postmaster_executor_crates__zstd-safe-7.2.4//:zstd_safe\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"arrays\",\n \"default\",\n \"legacy\",\n \"zdict_builder\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zstd\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.13.3\",\n)\n" + } + }, + "postmaster_executor_crates__zstd-safe-7.2.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zstd-safe/7.2.4/download" + ], + "strip_prefix": "zstd-safe-7.2.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"zstd_safe\",\n deps = [\n \":build_script_build\",\n \"@postmaster_executor_crates__zstd-sys-2.0.16-zstd.1.5.7//:zstd_sys\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"arrays\",\n \"legacy\",\n \"std\",\n \"zdict_builder\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zstd-safe\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"7.2.4\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"arrays\",\n \"legacy\",\n \"std\",\n \"zdict_builder\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n link_deps = [\n \"@postmaster_executor_crates__zstd-sys-2.0.16-zstd.1.5.7//:zstd_sys\",\n ],\n edition = \"2018\",\n pkg_name = \"zstd-safe\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zstd-safe\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"7.2.4\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_executor_crates__zstd-sys-2.0.16-zstd.1.5.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zstd-sys/2.0.16+zstd.1.5.7/download" + ], + "strip_prefix": "zstd-sys-2.0.16+zstd.1.5.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"zstd_sys\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"legacy\",\n \"std\",\n \"zdict_builder\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zstd-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.16+zstd.1.5.7\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"legacy\",\n \"std\",\n \"zdict_builder\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@postmaster_executor_crates__cc-1.2.60//:cc\",\n \"@postmaster_executor_crates__pkg-config-0.3.33//:pkg_config\",\n ],\n emit_warnings = False,\n edition = \"2018\",\n links = \"zstd\",\n pkg_name = \"zstd-sys\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zstd-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"2.0.16+zstd.1.5.7\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates": { + "repoRuleId": "@@rules_rust+//crate_universe/private:crates_vendor.bzl%crates_vendor_remote_repository", + "attributes": { + "contents": { + "BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files(\n [\n \"cargo-bazel.json\",\n \"crates.bzl\",\n \"defs.bzl\",\n ] + glob(\n allow_empty = True,\n include = [\"*.bazel\"],\n ),\n)\n\nfilegroup(\n name = \"srcs\",\n srcs = glob(\n allow_empty = True,\n include = [\n \"*.bazel\",\n \"*.bzl\",\n ],\n ),\n)\n\n# Workspace Member Dependencies\nalias(\n name = \"anyhow-1.0.102\",\n actual = \"@postmaster_compiler_crates__anyhow-1.0.102//:anyhow\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"anyhow\",\n actual = \"@postmaster_compiler_crates__anyhow-1.0.102//:anyhow\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"async-trait-0.1.89\",\n actual = \"@postmaster_compiler_crates__async-trait-0.1.89//:async_trait\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"async-trait\",\n actual = \"@postmaster_compiler_crates__async-trait-0.1.89//:async_trait\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"futures-0.3.32\",\n actual = \"@postmaster_compiler_crates__futures-0.3.32//:futures\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"futures\",\n actual = \"@postmaster_compiler_crates__futures-0.3.32//:futures\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"hex-0.4.3\",\n actual = \"@postmaster_compiler_crates__hex-0.4.3//:hex\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"hex\",\n actual = \"@postmaster_compiler_crates__hex-0.4.3//:hex\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"libc-0.2.186\",\n actual = \"@postmaster_compiler_crates__libc-0.2.186//:libc\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"libc\",\n actual = \"@postmaster_compiler_crates__libc-0.2.186//:libc\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde-1.0.228\",\n actual = \"@postmaster_compiler_crates__serde-1.0.228//:serde\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde\",\n actual = \"@postmaster_compiler_crates__serde-1.0.228//:serde\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde_json-1.0.149\",\n actual = \"@postmaster_compiler_crates__serde_json-1.0.149//:serde_json\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde_json\",\n actual = \"@postmaster_compiler_crates__serde_json-1.0.149//:serde_json\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"sha2-0.11.0\",\n actual = \"@postmaster_compiler_crates__sha2-0.11.0//:sha2\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"sha2\",\n actual = \"@postmaster_compiler_crates__sha2-0.11.0//:sha2\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tempfile-3.27.0\",\n actual = \"@postmaster_compiler_crates__tempfile-3.27.0//:tempfile\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tempfile\",\n actual = \"@postmaster_compiler_crates__tempfile-3.27.0//:tempfile\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tracing-0.1.44\",\n actual = \"@postmaster_compiler_crates__tracing-0.1.44//:tracing\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"tracing\",\n actual = \"@postmaster_compiler_crates__tracing-0.1.44//:tracing\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-7.2.0-alpha.2\",\n actual = \"@postmaster_compiler_crates__wasmer-7.2.0-alpha.2//:wasmer\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer\",\n actual = \"@postmaster_compiler_crates__wasmer-7.2.0-alpha.2//:wasmer\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-compiler-llvm-7.2.0-alpha.2\",\n actual = \"@postmaster_compiler_crates__wasmer-compiler-llvm-7.2.0-alpha.2//:wasmer_compiler_llvm\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-compiler-llvm\",\n actual = \"@postmaster_compiler_crates__wasmer-compiler-llvm-7.2.0-alpha.2//:wasmer_compiler_llvm\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-types-7.2.0-alpha.2\",\n actual = \"@postmaster_compiler_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-types\",\n actual = \"@postmaster_compiler_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-vm-7.2.0-alpha.2\",\n actual = \"@postmaster_compiler_crates__wasmer-vm-7.2.0-alpha.2//:wasmer_vm\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-vm\",\n actual = \"@postmaster_compiler_crates__wasmer-vm-7.2.0-alpha.2//:wasmer_vm\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-wasix-0.702.0-alpha.2\",\n actual = \"@postmaster_compiler_crates__wasmer-wasix-0.702.0-alpha.2//:wasmer_wasix\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmer-wasix\",\n actual = \"@postmaster_compiler_crates__wasmer-wasix-0.702.0-alpha.2//:wasmer_wasix\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmparser-0.247.0\",\n actual = \"@postmaster_compiler_crates__wasmparser-0.247.0//:wasmparser\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmparser\",\n actual = \"@postmaster_compiler_crates__wasmparser-0.247.0//:wasmparser\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wat-1.247.0\",\n actual = \"@postmaster_compiler_crates__wat-1.247.0//:wat\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wat\",\n actual = \"@postmaster_compiler_crates__wat-1.247.0//:wat\",\n tags = [\"manual\"],\n)\n", + "alias_rules.bzl": "\"\"\"Alias that transitions its target to `compilation_mode=opt`. Use `transition_alias=\"opt\"` to enable.\"\"\"\n\nload(\"@rules_cc//cc:defs.bzl\", \"CcInfo\")\nload(\"@rules_rust//rust:rust_common.bzl\", \"COMMON_PROVIDERS\")\n\ndef _transition_alias_impl(ctx):\n # `ctx.attr.actual` is a list of 1 item due to the transition\n providers = [ctx.attr.actual[0][provider] for provider in COMMON_PROVIDERS]\n if CcInfo in ctx.attr.actual[0]:\n providers.append(ctx.attr.actual[0][CcInfo])\n return providers\n\ndef _change_compilation_mode(compilation_mode):\n def _change_compilation_mode_impl(_settings, _attr):\n return {\n \"//command_line_option:compilation_mode\": compilation_mode,\n }\n\n return transition(\n implementation = _change_compilation_mode_impl,\n inputs = [],\n outputs = [\n \"//command_line_option:compilation_mode\",\n ],\n )\n\ndef _transition_alias_rule(compilation_mode):\n return rule(\n implementation = _transition_alias_impl,\n provides = COMMON_PROVIDERS,\n attrs = {\n \"actual\": attr.label(\n mandatory = True,\n doc = \"`rust_library()` target to transition to `compilation_mode=opt`.\",\n providers = COMMON_PROVIDERS,\n cfg = _change_compilation_mode(compilation_mode),\n ),\n \"_allowlist_function_transition\": attr.label(\n default = \"@bazel_tools//tools/allowlists/function_transition_allowlist\",\n ),\n },\n doc = \"Transitions a Rust library crate to the `compilation_mode=opt`.\",\n )\n\ntransition_alias_dbg = _transition_alias_rule(\"dbg\")\ntransition_alias_fastbuild = _transition_alias_rule(\"fastbuild\")\ntransition_alias_opt = _transition_alias_rule(\"opt\")\n", + "crates.bzl": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\"\"\"\n# `crates_repository` API\n\n- [aliases](#aliases)\n- [crate_edition](#crate_edition)\n- [crate_deps](#crate_deps)\n- [all_crate_deps](#all_crate_deps)\n- [crate_repositories](#crate_repositories)\n\n\"\"\"\n\nload(\"@bazel_tools//tools/build_defs/repo:git.bzl\", \"git_repository\")\nload(\"@bazel_tools//tools/build_defs/repo:http.bzl\", \"http_archive\")\nload(\"@bazel_tools//tools/build_defs/repo:utils.bzl\", \"maybe\")\nload(\"@bazel_skylib//lib:selects.bzl\", \"selects\")\nload(\"@rules_rust//crate_universe:defs.bzl\", \"crates_vendor_remote_repository\", \"local_crate_mirror\")\n\n###############################################################################\n# MACROS API\n###############################################################################\n\n# An identifier that represent common dependencies (unconditional).\n_COMMON_CONDITION = \"\"\n\ndef _flatten_dependency_maps(all_dependency_maps):\n \"\"\"Flatten a list of dependency maps into one dictionary.\n\n Dependency maps have the following structure:\n\n ```python\n DEPENDENCIES_MAP = {\n # The first key in the map is a Bazel package\n # name of the workspace this file is defined in.\n \"workspace_member_package\": {\n\n # Not all dependencies are supported for all platforms.\n # the condition key is the condition required to be true\n # on the host platform.\n \"condition\": {\n\n # An alias to a crate target. # The label of the crate target the\n # Aliases are only crate names. # package name refers to.\n \"package_name\": \"@full//:label\",\n }\n }\n }\n ```\n\n Args:\n all_dependency_maps (list): A list of dicts as described above\n\n Returns:\n dict: A dictionary as described above\n \"\"\"\n dependencies = {}\n\n for workspace_deps_map in all_dependency_maps:\n for pkg_name, conditional_deps_map in workspace_deps_map.items():\n if pkg_name not in dependencies:\n non_frozen_map = dict()\n for key, values in conditional_deps_map.items():\n non_frozen_map.update({key: dict(values.items())})\n dependencies.setdefault(pkg_name, non_frozen_map)\n continue\n\n for condition, deps_map in conditional_deps_map.items():\n # If the condition has not been recorded, do so and continue\n if condition not in dependencies[pkg_name]:\n dependencies[pkg_name].setdefault(condition, dict(deps_map.items()))\n continue\n\n # Alert on any miss-matched dependencies\n inconsistent_entries = []\n for crate_name, crate_label in deps_map.items():\n existing = dependencies[pkg_name][condition].get(crate_name)\n if existing and existing != crate_label:\n inconsistent_entries.append((crate_name, existing, crate_label))\n dependencies[pkg_name][condition].update({crate_name: crate_label})\n\n return dependencies\n\ndef crate_deps(deps, package_name = None):\n \"\"\"Finds the fully qualified label of the requested crates for the package where this macro is called.\n\n Args:\n deps (list): The desired list of crate targets.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()`.\n\n Returns:\n list: A list of labels to generated rust targets (str)\n \"\"\"\n\n if not deps:\n return []\n\n if package_name == None:\n package_name = native.package_name()\n\n # Join both sets of dependencies\n dependencies = _flatten_dependency_maps([\n _NORMAL_DEPENDENCIES,\n _NORMAL_DEV_DEPENDENCIES,\n _PROC_MACRO_DEPENDENCIES,\n _PROC_MACRO_DEV_DEPENDENCIES,\n _BUILD_DEPENDENCIES,\n _BUILD_PROC_MACRO_DEPENDENCIES,\n ]).pop(package_name, {})\n\n # Combine all conditional packages so we can easily index over a flat list\n # TODO: Perhaps this should actually return select statements and maintain\n # the conditionals of the dependencies\n flat_deps = {}\n for deps_set in dependencies.values():\n for crate_name, crate_label in deps_set.items():\n flat_deps.update({crate_name: crate_label})\n\n missing_crates = []\n crate_targets = []\n for crate_target in deps:\n if crate_target not in flat_deps:\n missing_crates.append(crate_target)\n else:\n crate_targets.append(flat_deps[crate_target])\n\n if missing_crates:\n fail(\"Could not find crates `{}` among dependencies of `{}`. Available dependencies were `{}`\".format(\n missing_crates,\n package_name,\n dependencies,\n ))\n\n return crate_targets\n\ndef crate_edition(package_name = None):\n \"\"\"Finds the Rust edition for the package where this macro is called.\n\n Args:\n package_name (str, optional): The package name whose edition should be\n looked up. Defaults to `native.package_name()` when unset.\n\n Returns:\n str: The Rust edition declared by the package's Cargo.toml file.\n \"\"\"\n if package_name == None:\n package_name = native.package_name()\n\n if package_name not in _CRATE_EDITIONS:\n fail(\"Tried to get crate_edition for package \" + package_name + \" but that package had no Cargo.toml file\")\n\n return _CRATE_EDITIONS[package_name]\n\ndef all_crate_deps(\n normal = False, \n normal_dev = False, \n proc_macro = False, \n proc_macro_dev = False,\n build = False,\n build_proc_macro = False,\n package_name = None):\n \"\"\"Finds the fully qualified label of all requested direct crate dependencies \\\n for the package where this macro is called.\n\n If no parameters are set, all normal dependencies are returned. Setting any one flag will\n otherwise impact the contents of the returned list.\n\n Args:\n normal (bool, optional): If True, normal dependencies are included in the\n output list.\n normal_dev (bool, optional): If True, normal dev dependencies will be\n included in the output list.\n proc_macro (bool, optional): If True, proc_macro dependencies are included\n in the output list.\n proc_macro_dev (bool, optional): If True, dev proc_macro dependencies are\n included in the output list.\n build (bool, optional): If True, build dependencies are included\n in the output list.\n build_proc_macro (bool, optional): If True, build proc_macro dependencies are\n included in the output list.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()` when unset.\n\n Returns:\n list: A list of labels to generated rust targets (str)\n \"\"\"\n\n if package_name == None:\n package_name = native.package_name()\n\n # Determine the relevant maps to use\n all_dependency_maps = []\n if normal:\n all_dependency_maps.append(_NORMAL_DEPENDENCIES)\n if normal_dev:\n all_dependency_maps.append(_NORMAL_DEV_DEPENDENCIES)\n if proc_macro:\n all_dependency_maps.append(_PROC_MACRO_DEPENDENCIES)\n if proc_macro_dev:\n all_dependency_maps.append(_PROC_MACRO_DEV_DEPENDENCIES)\n if build:\n all_dependency_maps.append(_BUILD_DEPENDENCIES)\n if build_proc_macro:\n all_dependency_maps.append(_BUILD_PROC_MACRO_DEPENDENCIES)\n\n # Default to always using normal dependencies\n if not all_dependency_maps:\n all_dependency_maps.append(_NORMAL_DEPENDENCIES)\n\n dependencies = _flatten_dependency_maps(all_dependency_maps).pop(package_name, None)\n\n if not dependencies:\n if dependencies == None:\n fail(\"Tried to get all_crate_deps for package \" + package_name + \" but that package had no Cargo.toml file\")\n else:\n return []\n\n crate_deps = list(dependencies.pop(_COMMON_CONDITION, {}).values())\n for condition, deps in dependencies.items():\n crate_deps += selects.with_or({\n tuple(_CONDITIONS[condition]): deps.values(),\n \"//conditions:default\": [],\n })\n\n return crate_deps\n\ndef aliases(\n normal = False,\n normal_dev = False,\n proc_macro = False,\n proc_macro_dev = False,\n build = False,\n build_proc_macro = False,\n package_name = None):\n \"\"\"Produces a map of Crate alias names to their original label\n\n If no dependency kinds are specified, `normal` and `proc_macro` are used by default.\n Setting any one flag will otherwise determine the contents of the returned dict.\n\n Args:\n normal (bool, optional): If True, normal dependencies are included in the\n output list.\n normal_dev (bool, optional): If True, normal dev dependencies will be\n included in the output list..\n proc_macro (bool, optional): If True, proc_macro dependencies are included\n in the output list.\n proc_macro_dev (bool, optional): If True, dev proc_macro dependencies are\n included in the output list.\n build (bool, optional): If True, build dependencies are included\n in the output list.\n build_proc_macro (bool, optional): If True, build proc_macro dependencies are\n included in the output list.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()` when unset.\n\n Returns:\n dict: The aliases of all associated packages\n \"\"\"\n if package_name == None:\n package_name = native.package_name()\n\n # Determine the relevant maps to use\n all_aliases_maps = []\n if normal:\n all_aliases_maps.append(_NORMAL_ALIASES)\n if normal_dev:\n all_aliases_maps.append(_NORMAL_DEV_ALIASES)\n if proc_macro:\n all_aliases_maps.append(_PROC_MACRO_ALIASES)\n if proc_macro_dev:\n all_aliases_maps.append(_PROC_MACRO_DEV_ALIASES)\n if build:\n all_aliases_maps.append(_BUILD_ALIASES)\n if build_proc_macro:\n all_aliases_maps.append(_BUILD_PROC_MACRO_ALIASES)\n\n # Default to always using normal aliases\n if not all_aliases_maps:\n all_aliases_maps.append(_NORMAL_ALIASES)\n all_aliases_maps.append(_PROC_MACRO_ALIASES)\n\n aliases = _flatten_dependency_maps(all_aliases_maps).pop(package_name, None)\n\n if not aliases:\n return dict()\n\n common_items = aliases.pop(_COMMON_CONDITION, {}).items()\n\n # If there are only common items in the dictionary, immediately return them\n if not len(aliases.keys()) == 1:\n return dict(common_items)\n\n # Build a single select statement where each conditional has accounted for the\n # common set of aliases.\n crate_aliases = {\"//conditions:default\": dict(common_items)}\n for condition, deps in aliases.items():\n condition_triples = _CONDITIONS[condition]\n for triple in condition_triples:\n if triple in crate_aliases:\n crate_aliases[triple].update(deps)\n else:\n crate_aliases.update({triple: dict(deps.items() + common_items)})\n\n return select(crate_aliases)\n\n###############################################################################\n# WORKSPACE MEMBER DEPS, ALIASES, AND EDITIONS\n###############################################################################\n\n_CRATE_EDITIONS = {\n \"\": \"2024\",\n}\n\n_NORMAL_DEPENDENCIES = {\n \"\": {\n _COMMON_CONDITION: {\n \"anyhow\": Label(\"@postmaster_compiler_crates//anyhow-1.0.102\"),\n \"hex\": Label(\"@postmaster_compiler_crates//hex-0.4.3\"),\n \"libc\": Label(\"@postmaster_compiler_crates//libc-0.2.186\"),\n \"serde\": Label(\"@postmaster_compiler_crates//serde-1.0.228\"),\n \"serde_json\": Label(\"@postmaster_compiler_crates//serde_json-1.0.149\"),\n \"sha2\": Label(\"@postmaster_compiler_crates//sha2-0.11.0\"),\n \"tempfile\": Label(\"@postmaster_compiler_crates//tempfile-3.27.0\"),\n \"tracing\": Label(\"@postmaster_compiler_crates//tracing-0.1.44\"),\n \"wasmer\": Label(\"@postmaster_compiler_crates//wasmer-7.2.0-alpha.2\"),\n \"wasmer-compiler-llvm\": Label(\"@postmaster_compiler_crates//wasmer-compiler-llvm-7.2.0-alpha.2\"),\n \"wasmer-types\": Label(\"@postmaster_compiler_crates//wasmer-types-7.2.0-alpha.2\"),\n \"wasmer-vm\": Label(\"@postmaster_compiler_crates//wasmer-vm-7.2.0-alpha.2\"),\n \"wasmer-wasix\": Label(\"@postmaster_compiler_crates//wasmer-wasix-0.702.0-alpha.2\"),\n \"wasmparser\": Label(\"@postmaster_compiler_crates//wasmparser-0.247.0\"),\n },\n },\n}\n\n\n_NORMAL_ALIASES = {\n \"\": {\n _COMMON_CONDITION: {\n },\n },\n}\n\n\n_NORMAL_DEV_DEPENDENCIES = {\n \"\": {\n _COMMON_CONDITION: {\n \"futures\": Label(\"@postmaster_compiler_crates//futures-0.3.32\"),\n \"wat\": Label(\"@postmaster_compiler_crates//wat-1.247.0\"),\n },\n },\n}\n\n\n_NORMAL_DEV_ALIASES = {\n \"\": {\n _COMMON_CONDITION: {\n },\n },\n}\n\n\n_PROC_MACRO_DEPENDENCIES = {\n \"\": {\n _COMMON_CONDITION: {\n \"async-trait\": Label(\"@postmaster_compiler_crates//async-trait-0.1.89\"),\n },\n },\n}\n\n\n_PROC_MACRO_ALIASES = {\n \"\": {\n },\n}\n\n\n_PROC_MACRO_DEV_DEPENDENCIES = {\n \"\": {\n },\n}\n\n\n_PROC_MACRO_DEV_ALIASES = {\n \"\": {\n _COMMON_CONDITION: {\n },\n },\n}\n\n\n_BUILD_DEPENDENCIES = {\n \"\": {\n },\n}\n\n\n_BUILD_ALIASES = {\n \"\": {\n },\n}\n\n\n_BUILD_PROC_MACRO_DEPENDENCIES = {\n \"\": {\n },\n}\n\n\n_BUILD_PROC_MACRO_ALIASES = {\n \"\": {\n },\n}\n\n\n_CONDITIONS = {\n \"aarch64-apple-darwin\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\"],\n \"aarch64-linux-android\": [],\n \"aarch64-pc-windows-gnullvm\": [],\n \"aarch64-unknown-linux-gnu\": [\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\"],\n \"cfg(all(any(target_arch = \\\"x86_64\\\", target_arch = \\\"arm64ec\\\"), target_env = \\\"msvc\\\", not(windows_raw_dylib)))\": [],\n \"cfg(all(any(target_os = \\\"linux\\\", target_os = \\\"android\\\"), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\": [],\n \"cfg(all(any(target_os = \\\"linux\\\", target_os = \\\"android\\\"), not(any(all(target_os = \\\"linux\\\", target_env = \\\"\\\"), getrandom_backend = \\\"custom\\\", getrandom_backend = \\\"linux_raw\\\", getrandom_backend = \\\"rdrand\\\", getrandom_backend = \\\"rndr\\\"))))\": [\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\": [\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(all(not(target_arch = \\\"wasm32\\\"), target_os = \\\"windows\\\"))\": [],\n \"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\"],\n \"cfg(all(target_arch = \\\"aarch64\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\": [],\n \"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"android\\\"))\": [],\n \"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"linux\\\"))\": [\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\"],\n \"cfg(all(target_arch = \\\"aarch64\\\", target_vendor = \\\"apple\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\"],\n \"cfg(all(target_arch = \\\"loongarch64\\\", target_os = \\\"linux\\\"))\": [],\n \"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"wasi\\\", target_env = \\\"p2\\\"))\": [],\n \"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"wasi\\\", target_env = \\\"p3\\\"))\": [],\n \"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"gnu\\\", not(target_abi = \\\"llvm\\\"), not(windows_raw_dylib)))\": [],\n \"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\": [],\n \"cfg(all(target_arch = \\\"x86_64\\\", target_env = \\\"gnu\\\", not(target_abi = \\\"llvm\\\"), not(windows_raw_dylib)))\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"wasi\\\"))\": [],\n \"cfg(all(target_os = \\\"macos\\\", target_arch = \\\"aarch64\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\"],\n \"cfg(all(target_os = \\\"uefi\\\", getrandom_backend = \\\"efi_rng\\\"))\": [],\n \"cfg(all(unix, not(target_os = \\\"ios\\\")))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any())\": [],\n \"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(target_arch = \\\"arm\\\", target_pointer_width = \\\"32\\\", target_pointer_width = \\\"64\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(target_arch = \\\"x86\\\", target_arch = \\\"x86_64\\\"))\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(target_family = \\\"unix\\\", all(target_family = \\\"windows\\\", target_env = \\\"gnu\\\")))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(target_os = \\\"android\\\", target_os = \\\"linux\\\", target_os = \\\"macos\\\", target_os = \\\"hurd\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(target_os = \\\"dragonfly\\\", target_os = \\\"freebsd\\\", target_os = \\\"hurd\\\", target_os = \\\"illumos\\\", target_os = \\\"cygwin\\\", all(target_os = \\\"horizon\\\", target_arch = \\\"arm\\\")))\": [],\n \"cfg(any(target_os = \\\"freebsd\\\", target_os = \\\"netbsd\\\"))\": [],\n \"cfg(any(target_os = \\\"haiku\\\", target_os = \\\"redox\\\", target_os = \\\"nto\\\", target_os = \\\"aix\\\"))\": [],\n \"cfg(any(target_os = \\\"ios\\\", target_os = \\\"visionos\\\", target_os = \\\"watchos\\\", target_os = \\\"tvos\\\"))\": [],\n \"cfg(any(target_os = \\\"macos\\\", target_os = \\\"ios\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\"],\n \"cfg(any(target_os = \\\"macos\\\", target_os = \\\"openbsd\\\", target_os = \\\"vita\\\", target_os = \\\"emscripten\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\"],\n \"cfg(any(unix, target_os = \\\"wasi\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(any(windows, target_os = \\\"cygwin\\\"))\": [],\n \"cfg(not(all(windows, target_env = \\\"msvc\\\", not(target_vendor = \\\"uwp\\\"))))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(not(target_arch = \\\"wasm32\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(not(windows))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(target_arch = \\\"spirv\\\")\": [],\n \"cfg(target_arch = \\\"wasm32\\\")\": [],\n \"cfg(target_os = \\\"hermit\\\")\": [],\n \"cfg(target_os = \\\"netbsd\\\")\": [],\n \"cfg(target_os = \\\"redox\\\")\": [],\n \"cfg(target_os = \\\"solaris\\\")\": [],\n \"cfg(target_os = \\\"vxworks\\\")\": [],\n \"cfg(target_os = \\\"wasi\\\")\": [],\n \"cfg(target_os = \\\"windows\\\")\": [],\n \"cfg(target_vendor = \\\"apple\\\")\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\"],\n \"cfg(unix)\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"cfg(windows)\": [],\n \"i686-pc-windows-gnullvm\": [],\n \"x86_64-pc-windows-gnullvm\": [],\n \"x86_64-unknown-linux-gnu\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n}\n\n###############################################################################\n\ndef crate_repositories():\n \"\"\"A macro for defining repositories for all generated crates.\n\n Returns:\n A list of repos visible to the module through the module extension.\n \"\"\"\n maybe(\n crates_vendor_remote_repository,\n name = \"postmaster_compiler_crates\",\n # Lean interface: just point at `crates.bzl`; the repo rule\n # derives the sibling `BUILD.bazel` and `defs.bzl`.\n crates_module = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:crates.bzl\"),\n )\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__addr2line-0.25.1\",\n sha256 = \"1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/addr2line/0.25.1/download\"],\n strip_prefix = \"addr2line-0.25.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.addr2line-0.25.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__adler2-2.0.1\",\n sha256 = \"320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/adler2/2.0.1/download\"],\n strip_prefix = \"adler2-2.0.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.adler2-2.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__aho-corasick-1.1.4\",\n sha256 = \"ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/aho-corasick/1.1.4/download\"],\n strip_prefix = \"aho-corasick-1.1.4\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.aho-corasick-1.1.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__any_ascii-0.1.7\",\n sha256 = \"70033777eb8b5124a81a1889416543dddef2de240019b674c81285a2635a7e1e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/any_ascii/0.1.7/download\"],\n strip_prefix = \"any_ascii-0.1.7\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.any_ascii-0.1.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__anyhow-1.0.102\",\n sha256 = \"7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/anyhow/1.0.102/download\"],\n strip_prefix = \"anyhow-1.0.102\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.anyhow-1.0.102.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__arrayref-0.3.9\",\n sha256 = \"76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/arrayref/0.3.9/download\"],\n strip_prefix = \"arrayref-0.3.9\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.arrayref-0.3.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__arrayvec-0.7.6\",\n sha256 = \"7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/arrayvec/0.7.6/download\"],\n strip_prefix = \"arrayvec-0.7.6\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.arrayvec-0.7.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__async-trait-0.1.89\",\n sha256 = \"9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/async-trait/0.1.89/download\"],\n strip_prefix = \"async-trait-0.1.89\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.async-trait-0.1.89.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__autocfg-1.5.0\",\n sha256 = \"c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/autocfg/1.5.0/download\"],\n strip_prefix = \"autocfg-1.5.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.autocfg-1.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__backtrace-0.3.76\",\n sha256 = \"bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/backtrace/0.3.76/download\"],\n strip_prefix = \"backtrace-0.3.76\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.backtrace-0.3.76.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__base64-0.22.1\",\n sha256 = \"72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/base64/0.22.1/download\"],\n strip_prefix = \"base64-0.22.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.base64-0.22.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__bincode-2.0.1\",\n sha256 = \"36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bincode/2.0.1/download\"],\n strip_prefix = \"bincode-2.0.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.bincode-2.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__bincode_derive-2.0.1\",\n sha256 = \"bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bincode_derive/2.0.1/download\"],\n strip_prefix = \"bincode_derive-2.0.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.bincode_derive-2.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__bindgen-0.72.1\",\n sha256 = \"993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bindgen/0.72.1/download\"],\n strip_prefix = \"bindgen-0.72.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.bindgen-0.72.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__bitflags-1.3.2\",\n sha256 = \"bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bitflags/1.3.2/download\"],\n strip_prefix = \"bitflags-1.3.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.bitflags-1.3.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__bitflags-2.11.1\",\n sha256 = \"c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bitflags/2.11.1/download\"],\n strip_prefix = \"bitflags-2.11.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.bitflags-2.11.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__blake3-1.8.4\",\n sha256 = \"4d2d5991425dfd0785aed03aedcf0b321d61975c9b5b3689c774a2610ae0b51e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/blake3/1.8.4/download\"],\n strip_prefix = \"blake3-1.8.4\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.blake3-1.8.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__block-buffer-0.10.4\",\n sha256 = \"3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/block-buffer/0.10.4/download\"],\n strip_prefix = \"block-buffer-0.10.4\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.block-buffer-0.10.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__block-buffer-0.12.0\",\n sha256 = \"cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/block-buffer/0.12.0/download\"],\n strip_prefix = \"block-buffer-0.12.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.block-buffer-0.12.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__bstr-1.12.1\",\n sha256 = \"63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bstr/1.12.1/download\"],\n strip_prefix = \"bstr-1.12.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.bstr-1.12.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__bumpalo-3.20.2\",\n sha256 = \"5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bumpalo/3.20.2/download\"],\n strip_prefix = \"bumpalo-3.20.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.bumpalo-3.20.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__bytecheck-0.8.2\",\n sha256 = \"0caa33a2c0edca0419d15ac723dff03f1956f7978329b1e3b5fdaaaed9d3ca8b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bytecheck/0.8.2/download\"],\n strip_prefix = \"bytecheck-0.8.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.bytecheck-0.8.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__bytecheck_derive-0.8.2\",\n sha256 = \"89385e82b5d1821d2219e0b095efa2cc1f246cbf99080f3be46a1a85c0d392d9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bytecheck_derive/0.8.2/download\"],\n strip_prefix = \"bytecheck_derive-0.8.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.bytecheck_derive-0.8.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__byteorder-1.5.0\",\n sha256 = \"1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/byteorder/1.5.0/download\"],\n strip_prefix = \"byteorder-1.5.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.byteorder-1.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__bytes-1.11.1\",\n sha256 = \"1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bytes/1.11.1/download\"],\n strip_prefix = \"bytes-1.11.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.bytes-1.11.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__bytesize-2.3.1\",\n sha256 = \"6bd91ee7b2422bcb158d90ef4d14f75ef67f340943fc4149891dcce8f8b972a3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bytesize/2.3.1/download\"],\n strip_prefix = \"bytesize-2.3.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.bytesize-2.3.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__cc-1.2.60\",\n sha256 = \"43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cc/1.2.60/download\"],\n strip_prefix = \"cc-1.2.60\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.cc-1.2.60.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__cexpr-0.6.0\",\n sha256 = \"6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cexpr/0.6.0/download\"],\n strip_prefix = \"cexpr-0.6.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.cexpr-0.6.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__cfg-if-1.0.4\",\n sha256 = \"9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cfg-if/1.0.4/download\"],\n strip_prefix = \"cfg-if-1.0.4\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.cfg-if-1.0.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__chacha20-0.10.0\",\n sha256 = \"6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/chacha20/0.10.0/download\"],\n strip_prefix = \"chacha20-0.10.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.chacha20-0.10.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__chrono-0.4.44\",\n sha256 = \"c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/chrono/0.4.44/download\"],\n strip_prefix = \"chrono-0.4.44\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.chrono-0.4.44.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__ciborium-0.2.2\",\n sha256 = \"42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ciborium/0.2.2/download\"],\n strip_prefix = \"ciborium-0.2.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.ciborium-0.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__ciborium-io-0.2.2\",\n sha256 = \"05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ciborium-io/0.2.2/download\"],\n strip_prefix = \"ciborium-io-0.2.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.ciborium-io-0.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__ciborium-ll-0.2.2\",\n sha256 = \"57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ciborium-ll/0.2.2/download\"],\n strip_prefix = \"ciborium-ll-0.2.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.ciborium-ll-0.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__clang-sys-1.8.1\",\n sha256 = \"0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/clang-sys/1.8.1/download\"],\n strip_prefix = \"clang-sys-1.8.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.clang-sys-1.8.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__cmake-0.1.58\",\n sha256 = \"c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cmake/0.1.58/download\"],\n strip_prefix = \"cmake-0.1.58\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.cmake-0.1.58.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__console-0.16.3\",\n sha256 = \"d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/console/0.16.3/download\"],\n strip_prefix = \"console-0.16.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.console-0.16.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__const-oid-0.10.2\",\n sha256 = \"a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/const-oid/0.10.2/download\"],\n strip_prefix = \"const-oid-0.10.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.const-oid-0.10.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__constant_time_eq-0.4.2\",\n sha256 = \"3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/constant_time_eq/0.4.2/download\"],\n strip_prefix = \"constant_time_eq-0.4.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.constant_time_eq-0.4.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__convert_case-0.10.0\",\n sha256 = \"633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/convert_case/0.10.0/download\"],\n strip_prefix = \"convert_case-0.10.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.convert_case-0.10.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__cooked-waker-5.0.0\",\n sha256 = \"147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cooked-waker/5.0.0/download\"],\n strip_prefix = \"cooked-waker-5.0.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.cooked-waker-5.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__corosensei-0.3.3\",\n sha256 = \"2c54787b605c7df106ceccf798df23da4f2e09918defad66705d1cedf3bb914f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/corosensei/0.3.3/download\"],\n strip_prefix = \"corosensei-0.3.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.corosensei-0.3.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__cpp_demangle-0.4.5\",\n sha256 = \"f2bb79cb74d735044c972aae58ed0aaa9a837e85b01106a54c39e42e97f62253\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cpp_demangle/0.4.5/download\"],\n strip_prefix = \"cpp_demangle-0.4.5\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.cpp_demangle-0.4.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__cpufeatures-0.2.17\",\n sha256 = \"59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cpufeatures/0.2.17/download\"],\n strip_prefix = \"cpufeatures-0.2.17\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.cpufeatures-0.2.17.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__cpufeatures-0.3.0\",\n sha256 = \"8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cpufeatures/0.3.0/download\"],\n strip_prefix = \"cpufeatures-0.3.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.cpufeatures-0.3.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__crc32fast-1.5.0\",\n sha256 = \"9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crc32fast/1.5.0/download\"],\n strip_prefix = \"crc32fast-1.5.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.crc32fast-1.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__crossbeam-channel-0.5.15\",\n sha256 = \"82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crossbeam-channel/0.5.15/download\"],\n strip_prefix = \"crossbeam-channel-0.5.15\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.crossbeam-channel-0.5.15.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__crossbeam-deque-0.8.6\",\n sha256 = \"9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crossbeam-deque/0.8.6/download\"],\n strip_prefix = \"crossbeam-deque-0.8.6\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.crossbeam-deque-0.8.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__crossbeam-epoch-0.9.18\",\n sha256 = \"5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crossbeam-epoch/0.9.18/download\"],\n strip_prefix = \"crossbeam-epoch-0.9.18\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.crossbeam-epoch-0.9.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__crossbeam-queue-0.3.12\",\n sha256 = \"0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crossbeam-queue/0.3.12/download\"],\n strip_prefix = \"crossbeam-queue-0.3.12\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.crossbeam-queue-0.3.12.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__crossbeam-utils-0.8.21\",\n sha256 = \"d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crossbeam-utils/0.8.21/download\"],\n strip_prefix = \"crossbeam-utils-0.8.21\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.crossbeam-utils-0.8.21.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__crunchy-0.2.4\",\n sha256 = \"460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crunchy/0.2.4/download\"],\n strip_prefix = \"crunchy-0.2.4\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.crunchy-0.2.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__crypto-common-0.1.7\",\n sha256 = \"78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crypto-common/0.1.7/download\"],\n strip_prefix = \"crypto-common-0.1.7\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.crypto-common-0.1.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__crypto-common-0.2.1\",\n sha256 = \"77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crypto-common/0.2.1/download\"],\n strip_prefix = \"crypto-common-0.2.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.crypto-common-0.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__darling-0.20.11\",\n sha256 = \"fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/darling/0.20.11/download\"],\n strip_prefix = \"darling-0.20.11\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.darling-0.20.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__darling-0.21.3\",\n sha256 = \"9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/darling/0.21.3/download\"],\n strip_prefix = \"darling-0.21.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.darling-0.21.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__darling_core-0.20.11\",\n sha256 = \"0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/darling_core/0.20.11/download\"],\n strip_prefix = \"darling_core-0.20.11\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.darling_core-0.20.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__darling_core-0.21.3\",\n sha256 = \"1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/darling_core/0.21.3/download\"],\n strip_prefix = \"darling_core-0.21.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.darling_core-0.21.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__darling_macro-0.20.11\",\n sha256 = \"fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/darling_macro/0.20.11/download\"],\n strip_prefix = \"darling_macro-0.20.11\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.darling_macro-0.20.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__darling_macro-0.21.3\",\n sha256 = \"d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/darling_macro/0.21.3/download\"],\n strip_prefix = \"darling_macro-0.21.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.darling_macro-0.21.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__dashmap-6.1.0\",\n sha256 = \"5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/dashmap/6.1.0/download\"],\n strip_prefix = \"dashmap-6.1.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.dashmap-6.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__debugid-0.8.0\",\n sha256 = \"bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/debugid/0.8.0/download\"],\n strip_prefix = \"debugid-0.8.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.debugid-0.8.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__defmt-0.3.100\",\n sha256 = \"f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/defmt/0.3.100/download\"],\n strip_prefix = \"defmt-0.3.100\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.defmt-0.3.100.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__defmt-1.0.1\",\n sha256 = \"548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/defmt/1.0.1/download\"],\n strip_prefix = \"defmt-1.0.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.defmt-1.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__defmt-macros-1.0.1\",\n sha256 = \"3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/defmt-macros/1.0.1/download\"],\n strip_prefix = \"defmt-macros-1.0.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.defmt-macros-1.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__defmt-parser-1.0.0\",\n sha256 = \"10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/defmt-parser/1.0.0/download\"],\n strip_prefix = \"defmt-parser-1.0.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.defmt-parser-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__deranged-0.5.8\",\n sha256 = \"7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/deranged/0.5.8/download\"],\n strip_prefix = \"deranged-0.5.8\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.deranged-0.5.8.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__derive_builder-0.20.2\",\n sha256 = \"507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/derive_builder/0.20.2/download\"],\n strip_prefix = \"derive_builder-0.20.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.derive_builder-0.20.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__derive_builder_core-0.20.2\",\n sha256 = \"2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/derive_builder_core/0.20.2/download\"],\n strip_prefix = \"derive_builder_core-0.20.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.derive_builder_core-0.20.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__derive_builder_macro-0.20.2\",\n sha256 = \"ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/derive_builder_macro/0.20.2/download\"],\n strip_prefix = \"derive_builder_macro-0.20.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.derive_builder_macro-0.20.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__derive_more-2.1.1\",\n sha256 = \"d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/derive_more/2.1.1/download\"],\n strip_prefix = \"derive_more-2.1.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.derive_more-2.1.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__derive_more-impl-2.1.1\",\n sha256 = \"799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/derive_more-impl/2.1.1/download\"],\n strip_prefix = \"derive_more-impl-2.1.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.derive_more-impl-2.1.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__digest-0.10.7\",\n sha256 = \"9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/digest/0.10.7/download\"],\n strip_prefix = \"digest-0.10.7\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.digest-0.10.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__digest-0.11.2\",\n sha256 = \"4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/digest/0.11.2/download\"],\n strip_prefix = \"digest-0.11.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.digest-0.11.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__displaydoc-0.2.5\",\n sha256 = \"97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/displaydoc/0.2.5/download\"],\n strip_prefix = \"displaydoc-0.2.5\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.displaydoc-0.2.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__document-features-0.2.12\",\n sha256 = \"d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/document-features/0.2.12/download\"],\n strip_prefix = \"document-features-0.2.12\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.document-features-0.2.12.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__dunce-1.0.5\",\n sha256 = \"92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/dunce/1.0.5/download\"],\n strip_prefix = \"dunce-1.0.5\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.dunce-1.0.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__dyn-clone-1.0.20\",\n sha256 = \"d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/dyn-clone/1.0.20/download\"],\n strip_prefix = \"dyn-clone-1.0.20\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.dyn-clone-1.0.20.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__either-1.15.0\",\n sha256 = \"48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/either/1.15.0/download\"],\n strip_prefix = \"either-1.15.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.either-1.15.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__encode_unicode-1.0.0\",\n sha256 = \"34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/encode_unicode/1.0.0/download\"],\n strip_prefix = \"encode_unicode-1.0.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.encode_unicode-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__enum-iterator-2.3.0\",\n sha256 = \"a4549325971814bda7a44061bf3fe7e487d447cba01e4220a4b454d630d7a016\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/enum-iterator/2.3.0/download\"],\n strip_prefix = \"enum-iterator-2.3.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.enum-iterator-2.3.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__enum-iterator-derive-1.5.0\",\n sha256 = \"685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/enum-iterator-derive/1.5.0/download\"],\n strip_prefix = \"enum-iterator-derive-1.5.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.enum-iterator-derive-1.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__enumset-1.1.10\",\n sha256 = \"25b07a8dfbbbfc0064c0a6bdf9edcf966de6b1c33ce344bdeca3b41615452634\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/enumset/1.1.10/download\"],\n strip_prefix = \"enumset-1.1.10\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.enumset-1.1.10.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__enumset_derive-0.14.0\",\n sha256 = \"f43e744e4ea338060faee68ed933e46e722fb7f3617e722a5772d7e856d8b3ce\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/enumset_derive/0.14.0/download\"],\n strip_prefix = \"enumset_derive-0.14.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.enumset_derive-0.14.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__equivalent-1.0.2\",\n sha256 = \"877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/equivalent/1.0.2/download\"],\n strip_prefix = \"equivalent-1.0.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.equivalent-1.0.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__errno-0.3.14\",\n sha256 = \"39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/errno/0.3.14/download\"],\n strip_prefix = \"errno-0.3.14\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.errno-0.3.14.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__fastrand-2.4.1\",\n sha256 = \"9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/fastrand/2.4.1/download\"],\n strip_prefix = \"fastrand-2.4.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.fastrand-2.4.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__filetime-0.2.27\",\n sha256 = \"f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/filetime/0.2.27/download\"],\n strip_prefix = \"filetime-0.2.27\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.filetime-0.2.27.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__find-msvc-tools-0.1.9\",\n sha256 = \"5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/find-msvc-tools/0.1.9/download\"],\n strip_prefix = \"find-msvc-tools-0.1.9\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.find-msvc-tools-0.1.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__fixedbitset-0.5.7\",\n sha256 = \"1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/fixedbitset/0.5.7/download\"],\n strip_prefix = \"fixedbitset-0.5.7\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.fixedbitset-0.5.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__flate2-1.1.9\",\n sha256 = \"843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/flate2/1.1.9/download\"],\n strip_prefix = \"flate2-1.1.9\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.flate2-1.1.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__fnv-1.0.7\",\n sha256 = \"3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/fnv/1.0.7/download\"],\n strip_prefix = \"fnv-1.0.7\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.fnv-1.0.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__foldhash-0.1.5\",\n sha256 = \"d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/foldhash/0.1.5/download\"],\n strip_prefix = \"foldhash-0.1.5\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.foldhash-0.1.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__foldhash-0.2.0\",\n sha256 = \"77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/foldhash/0.2.0/download\"],\n strip_prefix = \"foldhash-0.2.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.foldhash-0.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__form_urlencoded-1.2.2\",\n sha256 = \"cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/form_urlencoded/1.2.2/download\"],\n strip_prefix = \"form_urlencoded-1.2.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.form_urlencoded-1.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__futures-0.3.32\",\n sha256 = \"8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures/0.3.32/download\"],\n strip_prefix = \"futures-0.3.32\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.futures-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__futures-channel-0.3.32\",\n sha256 = \"07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-channel/0.3.32/download\"],\n strip_prefix = \"futures-channel-0.3.32\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.futures-channel-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__futures-core-0.3.32\",\n sha256 = \"7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-core/0.3.32/download\"],\n strip_prefix = \"futures-core-0.3.32\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.futures-core-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__futures-executor-0.3.32\",\n sha256 = \"baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-executor/0.3.32/download\"],\n strip_prefix = \"futures-executor-0.3.32\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.futures-executor-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__futures-io-0.3.32\",\n sha256 = \"cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-io/0.3.32/download\"],\n strip_prefix = \"futures-io-0.3.32\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.futures-io-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__futures-macro-0.3.32\",\n sha256 = \"e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-macro/0.3.32/download\"],\n strip_prefix = \"futures-macro-0.3.32\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.futures-macro-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__futures-sink-0.3.32\",\n sha256 = \"c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-sink/0.3.32/download\"],\n strip_prefix = \"futures-sink-0.3.32\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.futures-sink-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__futures-task-0.3.32\",\n sha256 = \"037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-task/0.3.32/download\"],\n strip_prefix = \"futures-task-0.3.32\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.futures-task-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__futures-util-0.3.32\",\n sha256 = \"389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/futures-util/0.3.32/download\"],\n strip_prefix = \"futures-util-0.3.32\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.futures-util-0.3.32.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__generic-array-0.14.7\",\n sha256 = \"85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/generic-array/0.14.7/download\"],\n strip_prefix = \"generic-array-0.14.7\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.generic-array-0.14.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__getrandom-0.3.4\",\n sha256 = \"899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/getrandom/0.3.4/download\"],\n strip_prefix = \"getrandom-0.3.4\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.getrandom-0.3.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__getrandom-0.4.2\",\n sha256 = \"0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/getrandom/0.4.2/download\"],\n strip_prefix = \"getrandom-0.4.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.getrandom-0.4.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__gimli-0.32.3\",\n sha256 = \"e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/gimli/0.32.3/download\"],\n strip_prefix = \"gimli-0.32.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.gimli-0.32.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__gimli-0.33.0\",\n sha256 = \"0bf7f043f89559805f8c7cacc432749b2fa0d0a0a9ee46ce47164ed5ba7f126c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/gimli/0.33.0/download\"],\n strip_prefix = \"gimli-0.33.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.gimli-0.33.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__glob-0.3.3\",\n sha256 = \"0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/glob/0.3.3/download\"],\n strip_prefix = \"glob-0.3.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.glob-0.3.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__globset-0.4.18\",\n sha256 = \"52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/globset/0.4.18/download\"],\n strip_prefix = \"globset-0.4.18\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.globset-0.4.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__half-2.7.1\",\n sha256 = \"6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/half/2.7.1/download\"],\n strip_prefix = \"half-2.7.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.half-2.7.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__hash32-0.3.1\",\n sha256 = \"47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hash32/0.3.1/download\"],\n strip_prefix = \"hash32-0.3.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.hash32-0.3.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__hashbrown-0.14.5\",\n sha256 = \"e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hashbrown/0.14.5/download\"],\n strip_prefix = \"hashbrown-0.14.5\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.hashbrown-0.14.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__hashbrown-0.15.5\",\n sha256 = \"9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hashbrown/0.15.5/download\"],\n strip_prefix = \"hashbrown-0.15.5\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.hashbrown-0.15.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__hashbrown-0.16.1\",\n sha256 = \"841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hashbrown/0.16.1/download\"],\n strip_prefix = \"hashbrown-0.16.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.hashbrown-0.16.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__hashbrown-0.17.0\",\n sha256 = \"4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hashbrown/0.17.0/download\"],\n strip_prefix = \"hashbrown-0.17.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.hashbrown-0.17.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__heapless-0.9.2\",\n sha256 = \"2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/heapless/0.9.2/download\"],\n strip_prefix = \"heapless-0.9.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.heapless-0.9.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__heck-0.3.3\",\n sha256 = \"6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/heck/0.3.3/download\"],\n strip_prefix = \"heck-0.3.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.heck-0.3.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__heck-0.5.0\",\n sha256 = \"2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/heck/0.5.0/download\"],\n strip_prefix = \"heck-0.5.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.heck-0.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__hermit-abi-0.5.2\",\n sha256 = \"fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hermit-abi/0.5.2/download\"],\n strip_prefix = \"hermit-abi-0.5.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.hermit-abi-0.5.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__hex-0.4.3\",\n sha256 = \"7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hex/0.4.3/download\"],\n strip_prefix = \"hex-0.4.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.hex-0.4.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__http-1.4.0\",\n sha256 = \"e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/http/1.4.0/download\"],\n strip_prefix = \"http-1.4.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.http-1.4.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__hybrid-array-0.4.10\",\n sha256 = \"3944cf8cf766b40e2a1a333ee5e9b563f854d5fa49d6a8ca2764e97c6eddb214\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hybrid-array/0.4.10/download\"],\n strip_prefix = \"hybrid-array-0.4.10\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.hybrid-array-0.4.10.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__icu_collections-2.2.0\",\n sha256 = \"2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_collections/2.2.0/download\"],\n strip_prefix = \"icu_collections-2.2.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.icu_collections-2.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__icu_locale_core-2.2.0\",\n sha256 = \"92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_locale_core/2.2.0/download\"],\n strip_prefix = \"icu_locale_core-2.2.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.icu_locale_core-2.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__icu_normalizer-2.2.0\",\n sha256 = \"c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_normalizer/2.2.0/download\"],\n strip_prefix = \"icu_normalizer-2.2.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.icu_normalizer-2.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__icu_normalizer_data-2.2.0\",\n sha256 = \"da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_normalizer_data/2.2.0/download\"],\n strip_prefix = \"icu_normalizer_data-2.2.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.icu_normalizer_data-2.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__icu_properties-2.2.0\",\n sha256 = \"bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_properties/2.2.0/download\"],\n strip_prefix = \"icu_properties-2.2.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.icu_properties-2.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__icu_properties_data-2.2.0\",\n sha256 = \"8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_properties_data/2.2.0/download\"],\n strip_prefix = \"icu_properties_data-2.2.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.icu_properties_data-2.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__icu_provider-2.2.0\",\n sha256 = \"139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/icu_provider/2.2.0/download\"],\n strip_prefix = \"icu_provider-2.2.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.icu_provider-2.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__id-arena-2.3.0\",\n sha256 = \"3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/id-arena/2.3.0/download\"],\n strip_prefix = \"id-arena-2.3.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.id-arena-2.3.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__ident_case-1.0.1\",\n sha256 = \"b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ident_case/1.0.1/download\"],\n strip_prefix = \"ident_case-1.0.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.ident_case-1.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__idna-1.1.0\",\n sha256 = \"3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/idna/1.1.0/download\"],\n strip_prefix = \"idna-1.1.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.idna-1.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__idna_adapter-1.2.1\",\n sha256 = \"3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/idna_adapter/1.2.1/download\"],\n strip_prefix = \"idna_adapter-1.2.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.idna_adapter-1.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__ignore-0.4.25\",\n sha256 = \"d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ignore/0.4.25/download\"],\n strip_prefix = \"ignore-0.4.25\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.ignore-0.4.25.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__indexmap-2.14.0\",\n sha256 = \"d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/indexmap/2.14.0/download\"],\n strip_prefix = \"indexmap-2.14.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.indexmap-2.14.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__inkwell-0.9.0\",\n sha256 = \"7decbc9dfa45a4a827a6ff7b822c113b1285678a937e84213417d4ca8a095782\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/inkwell/0.9.0/download\"],\n strip_prefix = \"inkwell-0.9.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.inkwell-0.9.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__inkwell_internals-0.14.0\",\n sha256 = \"6cfe97ee860815a90ed17e09639513269e39420a7440f3f4c996f238c514cf8d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/inkwell_internals/0.14.0/download\"],\n strip_prefix = \"inkwell_internals-0.14.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.inkwell_internals-0.14.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__insta-1.47.2\",\n sha256 = \"7b4a6248eb93a4401ed2f37dfe8ea592d3cf05b7cf4f8efa867b6895af7e094e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/insta/1.47.2/download\"],\n strip_prefix = \"insta-1.47.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.insta-1.47.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__ipnet-2.12.0\",\n sha256 = \"d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ipnet/2.12.0/download\"],\n strip_prefix = \"ipnet-2.12.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.ipnet-2.12.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__iprange-0.6.7\",\n sha256 = \"37209be0ad225457e63814401415e748e2453a5297f9b637338f5fb8afa4ec00\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/iprange/0.6.7/download\"],\n strip_prefix = \"iprange-0.6.7\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.iprange-0.6.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__itertools-0.13.0\",\n sha256 = \"413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/itertools/0.13.0/download\"],\n strip_prefix = \"itertools-0.13.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.itertools-0.13.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__itertools-0.14.0\",\n sha256 = \"2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/itertools/0.14.0/download\"],\n strip_prefix = \"itertools-0.14.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.itertools-0.14.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__itoa-1.0.18\",\n sha256 = \"8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/itoa/1.0.18/download\"],\n strip_prefix = \"itoa-1.0.18\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.itoa-1.0.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__jobserver-0.1.34\",\n sha256 = \"9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/jobserver/0.1.34/download\"],\n strip_prefix = \"jobserver-0.1.34\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.jobserver-0.1.34.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__js-sys-0.3.95\",\n sha256 = \"2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/js-sys/0.3.95/download\"],\n strip_prefix = \"js-sys-0.3.95\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.js-sys-0.3.95.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__lazy_static-1.5.0\",\n sha256 = \"bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/lazy_static/1.5.0/download\"],\n strip_prefix = \"lazy_static-1.5.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.lazy_static-1.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__leb128-0.2.6\",\n sha256 = \"6cc46bac87ef8093eed6f272babb833b6443374399985ac8ed28471ee0918545\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/leb128/0.2.6/download\"],\n strip_prefix = \"leb128-0.2.6\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.leb128-0.2.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__leb128fmt-0.1.0\",\n sha256 = \"09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/leb128fmt/0.1.0/download\"],\n strip_prefix = \"leb128fmt-0.1.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.leb128fmt-0.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__lexical-sort-0.3.1\",\n sha256 = \"c09e4591611e231daf4d4c685a66cb0410cc1e502027a20ae55f2bb9e997207a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/lexical-sort/0.3.1/download\"],\n strip_prefix = \"lexical-sort-0.3.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.lexical-sort-0.3.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__libc-0.2.186\",\n sha256 = \"68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/libc/0.2.186/download\"],\n strip_prefix = \"libc-0.2.186\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.libc-0.2.186.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__libloading-0.8.9\",\n sha256 = \"d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/libloading/0.8.9/download\"],\n strip_prefix = \"libloading-0.8.9\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.libloading-0.8.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__libredox-0.1.16\",\n sha256 = \"e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/libredox/0.1.16/download\"],\n strip_prefix = \"libredox-0.1.16\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.libredox-0.1.16.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__libunwind-1.3.3\",\n sha256 = \"0c6639b70a7ce854b79c70d7e83f16b5dc0137cc914f3d7d03803b513ecc67ac\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/libunwind/1.3.3/download\"],\n strip_prefix = \"libunwind-1.3.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.libunwind-1.3.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__linked-hash-map-0.5.6\",\n sha256 = \"0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/linked-hash-map/0.5.6/download\"],\n strip_prefix = \"linked-hash-map-0.5.6\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.linked-hash-map-0.5.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__linked_hash_set-0.1.6\",\n sha256 = \"984fb35d06508d1e69fc91050cceba9c0b748f983e6739fa2c7a9237154c52c8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/linked_hash_set/0.1.6/download\"],\n strip_prefix = \"linked_hash_set-0.1.6\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.linked_hash_set-0.1.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__linux-raw-sys-0.12.1\",\n sha256 = \"32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/linux-raw-sys/0.12.1/download\"],\n strip_prefix = \"linux-raw-sys-0.12.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.linux-raw-sys-0.12.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__litemap-0.8.2\",\n sha256 = \"92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/litemap/0.8.2/download\"],\n strip_prefix = \"litemap-0.8.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.litemap-0.8.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__litrs-1.0.0\",\n sha256 = \"11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/litrs/1.0.0/download\"],\n strip_prefix = \"litrs-1.0.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.litrs-1.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__llvm-sys-221.0.1\",\n patch_args = [\n \"-p1\",\n ],\n patches = [\n \"@@//build_defs/wasix:llvm-sys-declared-prefix.patch\",\n ],\n sha256 = \"2abcc34a3b190f03c2a61b555f218f529589ff13657bdd2ff8ac3e85f2abe6bb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/llvm-sys/221.0.1/download\"],\n strip_prefix = \"llvm-sys-221.0.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.llvm-sys-221.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__lock_api-0.4.14\",\n sha256 = \"224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/lock_api/0.4.14/download\"],\n strip_prefix = \"lock_api-0.4.14\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.lock_api-0.4.14.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__log-0.4.29\",\n sha256 = \"5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/log/0.4.29/download\"],\n strip_prefix = \"log-0.4.29\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.log-0.4.29.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__lz4_flex-0.13.0\",\n sha256 = \"db9a0d582c2874f68138a16ce1867e0ffde6c0bb0a0df85e1f36d04146db488a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/lz4_flex/0.13.0/download\"],\n strip_prefix = \"lz4_flex-0.13.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.lz4_flex-0.13.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__mach2-0.4.3\",\n sha256 = \"d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/mach2/0.4.3/download\"],\n strip_prefix = \"mach2-0.4.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.mach2-0.4.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__mach2-0.6.0\",\n sha256 = \"dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/mach2/0.6.0/download\"],\n strip_prefix = \"mach2-0.6.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.mach2-0.6.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__macho-unwind-info-0.5.0\",\n sha256 = \"bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/macho-unwind-info/0.5.0/download\"],\n strip_prefix = \"macho-unwind-info-0.5.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.macho-unwind-info-0.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__managed-0.8.0\",\n sha256 = \"0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/managed/0.8.0/download\"],\n strip_prefix = \"managed-0.8.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.managed-0.8.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__memchr-2.8.0\",\n sha256 = \"f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/memchr/2.8.0/download\"],\n strip_prefix = \"memchr-2.8.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.memchr-2.8.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__memmap2-0.6.2\",\n sha256 = \"6d28bba84adfe6646737845bc5ebbfa2c08424eb1c37e94a1fd2a82adb56a872\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/memmap2/0.6.2/download\"],\n strip_prefix = \"memmap2-0.6.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.memmap2-0.6.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__memmap2-0.9.10\",\n sha256 = \"714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/memmap2/0.9.10/download\"],\n strip_prefix = \"memmap2-0.9.10\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.memmap2-0.9.10.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__memoffset-0.9.1\",\n sha256 = \"488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/memoffset/0.9.1/download\"],\n strip_prefix = \"memoffset-0.9.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.memoffset-0.9.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__minimal-lexical-0.2.1\",\n sha256 = \"68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/minimal-lexical/0.2.1/download\"],\n strip_prefix = \"minimal-lexical-0.2.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.minimal-lexical-0.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__miniz_oxide-0.8.9\",\n sha256 = \"1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/miniz_oxide/0.8.9/download\"],\n strip_prefix = \"miniz_oxide-0.8.9\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.miniz_oxide-0.8.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__more-asserts-0.3.1\",\n sha256 = \"1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/more-asserts/0.3.1/download\"],\n strip_prefix = \"more-asserts-0.3.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.more-asserts-0.3.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__msvc-demangler-0.11.0\",\n sha256 = \"fbeff6bd154a309b2ada5639b2661ca6ae4599b34e8487dc276d2cd637da2d76\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/msvc-demangler/0.11.0/download\"],\n strip_prefix = \"msvc-demangler-0.11.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.msvc-demangler-0.11.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__munge-0.4.7\",\n sha256 = \"5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/munge/0.4.7/download\"],\n strip_prefix = \"munge-0.4.7\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.munge-0.4.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__munge_macro-0.4.7\",\n sha256 = \"4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/munge_macro/0.4.7/download\"],\n strip_prefix = \"munge_macro-0.4.7\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.munge_macro-0.4.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__nom-5.1.3\",\n sha256 = \"08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/nom/5.1.3/download\"],\n strip_prefix = \"nom-5.1.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.nom-5.1.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__nom-7.1.3\",\n sha256 = \"d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/nom/7.1.3/download\"],\n strip_prefix = \"nom-7.1.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.nom-7.1.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__num-conv-0.2.1\",\n sha256 = \"c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/num-conv/0.2.1/download\"],\n strip_prefix = \"num-conv-0.2.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.num-conv-0.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__num-traits-0.2.19\",\n sha256 = \"071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/num-traits/0.2.19/download\"],\n strip_prefix = \"num-traits-0.2.19\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.num-traits-0.2.19.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__num_cpus-1.17.0\",\n sha256 = \"91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/num_cpus/1.17.0/download\"],\n strip_prefix = \"num_cpus-1.17.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.num_cpus-1.17.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__num_enum-0.7.6\",\n sha256 = \"5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/num_enum/0.7.6/download\"],\n strip_prefix = \"num_enum-0.7.6\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.num_enum-0.7.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__num_enum_derive-0.7.6\",\n sha256 = \"680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/num_enum_derive/0.7.6/download\"],\n strip_prefix = \"num_enum_derive-0.7.6\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.num_enum_derive-0.7.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__object-0.37.3\",\n sha256 = \"ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/object/0.37.3/download\"],\n strip_prefix = \"object-0.37.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.object-0.37.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__object-0.39.1\",\n sha256 = \"2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/object/0.39.1/download\"],\n strip_prefix = \"object-0.39.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.object-0.39.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__once_cell-1.21.4\",\n sha256 = \"9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/once_cell/1.21.4/download\"],\n strip_prefix = \"once_cell-1.21.4\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.once_cell-1.21.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__parking-2.2.1\",\n sha256 = \"f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/parking/2.2.1/download\"],\n strip_prefix = \"parking-2.2.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.parking-2.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__parking_lot-0.12.5\",\n sha256 = \"93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/parking_lot/0.12.5/download\"],\n strip_prefix = \"parking_lot-0.12.5\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.parking_lot-0.12.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__parking_lot_core-0.9.12\",\n sha256 = \"2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/parking_lot_core/0.9.12/download\"],\n strip_prefix = \"parking_lot_core-0.9.12\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.parking_lot_core-0.9.12.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__paste-1.0.15\",\n sha256 = \"57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/paste/1.0.15/download\"],\n strip_prefix = \"paste-1.0.15\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.paste-1.0.15.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__path-clean-1.0.1\",\n sha256 = \"17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/path-clean/1.0.1/download\"],\n strip_prefix = \"path-clean-1.0.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.path-clean-1.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__percent-encoding-2.3.2\",\n sha256 = \"9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/percent-encoding/2.3.2/download\"],\n strip_prefix = \"percent-encoding-2.3.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.percent-encoding-2.3.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__petgraph-0.8.3\",\n sha256 = \"8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/petgraph/0.8.3/download\"],\n strip_prefix = \"petgraph-0.8.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.petgraph-0.8.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__phf-0.13.1\",\n sha256 = \"c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/phf/0.13.1/download\"],\n strip_prefix = \"phf-0.13.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.phf-0.13.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__phf_generator-0.13.1\",\n sha256 = \"135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/phf_generator/0.13.1/download\"],\n strip_prefix = \"phf_generator-0.13.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.phf_generator-0.13.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__phf_macros-0.13.1\",\n sha256 = \"812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/phf_macros/0.13.1/download\"],\n strip_prefix = \"phf_macros-0.13.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.phf_macros-0.13.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__phf_shared-0.13.1\",\n sha256 = \"e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/phf_shared/0.13.1/download\"],\n strip_prefix = \"phf_shared-0.13.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.phf_shared-0.13.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__pin-project-1.1.11\",\n sha256 = \"f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pin-project/1.1.11/download\"],\n strip_prefix = \"pin-project-1.1.11\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.pin-project-1.1.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__pin-project-internal-1.1.11\",\n sha256 = \"d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pin-project-internal/1.1.11/download\"],\n strip_prefix = \"pin-project-internal-1.1.11\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.pin-project-internal-1.1.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__pin-project-lite-0.2.17\",\n sha256 = \"a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pin-project-lite/0.2.17/download\"],\n strip_prefix = \"pin-project-lite-0.2.17\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.pin-project-lite-0.2.17.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__pin-utils-0.1.0\",\n sha256 = \"8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pin-utils/0.1.0/download\"],\n strip_prefix = \"pin-utils-0.1.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.pin-utils-0.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__pkg-config-0.3.33\",\n sha256 = \"19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pkg-config/0.3.33/download\"],\n strip_prefix = \"pkg-config-0.3.33\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.pkg-config-0.3.33.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__plain-0.2.3\",\n sha256 = \"b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/plain/0.2.3/download\"],\n strip_prefix = \"plain-0.2.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.plain-0.2.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__potential_utf-0.1.5\",\n sha256 = \"0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/potential_utf/0.1.5/download\"],\n strip_prefix = \"potential_utf-0.1.5\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.potential_utf-0.1.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__powerfmt-0.2.0\",\n sha256 = \"439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/powerfmt/0.2.0/download\"],\n strip_prefix = \"powerfmt-0.2.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.powerfmt-0.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__ppv-lite86-0.2.21\",\n sha256 = \"85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ppv-lite86/0.2.21/download\"],\n strip_prefix = \"ppv-lite86-0.2.21\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.ppv-lite86-0.2.21.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__prettyplease-0.2.37\",\n sha256 = \"479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/prettyplease/0.2.37/download\"],\n strip_prefix = \"prettyplease-0.2.37\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.prettyplease-0.2.37.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__proc-macro-crate-3.5.0\",\n sha256 = \"e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/proc-macro-crate/3.5.0/download\"],\n strip_prefix = \"proc-macro-crate-3.5.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.proc-macro-crate-3.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__proc-macro-error-attr2-2.0.0\",\n sha256 = \"96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/proc-macro-error-attr2/2.0.0/download\"],\n strip_prefix = \"proc-macro-error-attr2-2.0.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.proc-macro-error-attr2-2.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__proc-macro-error2-2.0.1\",\n sha256 = \"11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/proc-macro-error2/2.0.1/download\"],\n strip_prefix = \"proc-macro-error2-2.0.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.proc-macro-error2-2.0.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__proc-macro2-1.0.106\",\n sha256 = \"8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/proc-macro2/1.0.106/download\"],\n strip_prefix = \"proc-macro2-1.0.106\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.proc-macro2-1.0.106.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__ptr_meta-0.3.1\",\n sha256 = \"0b9a0cf95a1196af61d4f1cbdab967179516d9a4a4312af1f31948f8f6224a79\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ptr_meta/0.3.1/download\"],\n strip_prefix = \"ptr_meta-0.3.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.ptr_meta-0.3.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__ptr_meta_derive-0.3.1\",\n sha256 = \"7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ptr_meta_derive/0.3.1/download\"],\n strip_prefix = \"ptr_meta_derive-0.3.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.ptr_meta_derive-0.3.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__pulldown-cmark-0.8.0\",\n sha256 = \"ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/pulldown-cmark/0.8.0/download\"],\n strip_prefix = \"pulldown-cmark-0.8.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.pulldown-cmark-0.8.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__quote-1.0.45\",\n sha256 = \"41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/quote/1.0.45/download\"],\n strip_prefix = \"quote-1.0.45\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.quote-1.0.45.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__r-efi-5.3.0\",\n sha256 = \"69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/r-efi/5.3.0/download\"],\n strip_prefix = \"r-efi-5.3.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.r-efi-5.3.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__r-efi-6.0.0\",\n sha256 = \"f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/r-efi/6.0.0/download\"],\n strip_prefix = \"r-efi-6.0.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.r-efi-6.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__rancor-0.1.1\",\n sha256 = \"a063ea72381527c2a0561da9c80000ef822bdd7c3241b1cc1b12100e3df081ee\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rancor/0.1.1/download\"],\n strip_prefix = \"rancor-0.1.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.rancor-0.1.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__rand-0.10.1\",\n sha256 = \"d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rand/0.10.1/download\"],\n strip_prefix = \"rand-0.10.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.rand-0.10.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__rand-0.9.4\",\n sha256 = \"44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rand/0.9.4/download\"],\n strip_prefix = \"rand-0.9.4\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.rand-0.9.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__rand_chacha-0.9.0\",\n sha256 = \"d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rand_chacha/0.9.0/download\"],\n strip_prefix = \"rand_chacha-0.9.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.rand_chacha-0.9.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__rand_core-0.10.1\",\n sha256 = \"63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rand_core/0.10.1/download\"],\n strip_prefix = \"rand_core-0.10.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.rand_core-0.10.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__rand_core-0.9.5\",\n sha256 = \"76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rand_core/0.9.5/download\"],\n strip_prefix = \"rand_core-0.9.5\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.rand_core-0.9.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__rangemap-1.7.1\",\n sha256 = \"973443cf09a9c8656b574a866ab68dfa19f0867d0340648c7d2f6a71b8a8ea68\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rangemap/1.7.1/download\"],\n strip_prefix = \"rangemap-1.7.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.rangemap-1.7.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__rayon-1.12.0\",\n sha256 = \"fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rayon/1.12.0/download\"],\n strip_prefix = \"rayon-1.12.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.rayon-1.12.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__rayon-core-1.13.0\",\n sha256 = \"22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rayon-core/1.13.0/download\"],\n strip_prefix = \"rayon-core-1.13.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.rayon-core-1.13.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__redox_syscall-0.5.18\",\n sha256 = \"ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/redox_syscall/0.5.18/download\"],\n strip_prefix = \"redox_syscall-0.5.18\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.redox_syscall-0.5.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__redox_syscall-0.7.4\",\n sha256 = \"f450ad9c3b1da563fb6948a8e0fb0fb9269711c9c73d9ea1de5058c79c8d643a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/redox_syscall/0.7.4/download\"],\n strip_prefix = \"redox_syscall-0.7.4\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.redox_syscall-0.7.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__ref-cast-1.0.25\",\n sha256 = \"f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ref-cast/1.0.25/download\"],\n strip_prefix = \"ref-cast-1.0.25\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.ref-cast-1.0.25.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__ref-cast-impl-1.0.25\",\n sha256 = \"b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ref-cast-impl/1.0.25/download\"],\n strip_prefix = \"ref-cast-impl-1.0.25\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.ref-cast-impl-1.0.25.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__regex-1.12.3\",\n sha256 = \"e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/regex/1.12.3/download\"],\n strip_prefix = \"regex-1.12.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.regex-1.12.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__regex-automata-0.4.14\",\n sha256 = \"6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/regex-automata/0.4.14/download\"],\n strip_prefix = \"regex-automata-0.4.14\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.regex-automata-0.4.14.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__regex-lite-0.1.9\",\n sha256 = \"cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/regex-lite/0.1.9/download\"],\n strip_prefix = \"regex-lite-0.1.9\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.regex-lite-0.1.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__regex-syntax-0.8.10\",\n sha256 = \"dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/regex-syntax/0.8.10/download\"],\n strip_prefix = \"regex-syntax-0.8.10\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.regex-syntax-0.8.10.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__region-3.0.2\",\n sha256 = \"e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/region/3.0.2/download\"],\n strip_prefix = \"region-3.0.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.region-3.0.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__rend-0.5.3\",\n sha256 = \"cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rend/0.5.3/download\"],\n strip_prefix = \"rend-0.5.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.rend-0.5.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__replace_with-0.1.8\",\n sha256 = \"51743d3e274e2b18df81c4dc6caf8a5b8e15dbe799e0dca05c7617380094e884\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/replace_with/0.1.8/download\"],\n strip_prefix = \"replace_with-0.1.8\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.replace_with-0.1.8.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__rkyv-0.8.16\",\n sha256 = \"73389e0c99e664f919275ab5b5b0471391fe9a8de61e1dff9b1eaf56a90f16e3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rkyv/0.8.16/download\"],\n strip_prefix = \"rkyv-0.8.16\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.rkyv-0.8.16.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__rkyv_derive-0.8.16\",\n sha256 = \"5d2ed0b54125315fb36bd021e82d314d1c126548f871634b483f46b31d13cac6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rkyv_derive/0.8.16/download\"],\n strip_prefix = \"rkyv_derive-0.8.16\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.rkyv_derive-0.8.16.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__rustc-demangle-0.1.27\",\n sha256 = \"b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustc-demangle/0.1.27/download\"],\n strip_prefix = \"rustc-demangle-0.1.27\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.rustc-demangle-0.1.27.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__rustc-hash-2.1.2\",\n sha256 = \"94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustc-hash/2.1.2/download\"],\n strip_prefix = \"rustc-hash-2.1.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.rustc-hash-2.1.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__rustc_version-0.4.1\",\n sha256 = \"cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustc_version/0.4.1/download\"],\n strip_prefix = \"rustc_version-0.4.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.rustc_version-0.4.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__rustix-1.1.4\",\n sha256 = \"b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustix/1.1.4/download\"],\n strip_prefix = \"rustix-1.1.4\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.rustix-1.1.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__rustversion-1.0.22\",\n sha256 = \"b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustversion/1.0.22/download\"],\n strip_prefix = \"rustversion-1.0.22\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.rustversion-1.0.22.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__rusty_pool-0.7.0\",\n sha256 = \"4ed36cdb20de66d89a17ea04b8883fc7a386f2cf877aaedca5005583ce4876ff\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rusty_pool/0.7.0/download\"],\n strip_prefix = \"rusty_pool-0.7.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.rusty_pool-0.7.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__ruzstd-0.8.2\",\n sha256 = \"e5ff0cc5e135c8870a775d3320910cd9b564ec036b4dc0b8741629020be63f01\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ruzstd/0.8.2/download\"],\n strip_prefix = \"ruzstd-0.8.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.ruzstd-0.8.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__ryu-1.0.23\",\n sha256 = \"9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/ryu/1.0.23/download\"],\n strip_prefix = \"ryu-1.0.23\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.ryu-1.0.23.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__saffron-0.1.0\",\n sha256 = \"03fb9a628596fc7590eb7edbf7b0613287be78df107f5f97b118aad59fb2eea9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/saffron/0.1.0/download\"],\n strip_prefix = \"saffron-0.1.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.saffron-0.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__same-file-1.0.6\",\n sha256 = \"93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/same-file/1.0.6/download\"],\n strip_prefix = \"same-file-1.0.6\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.same-file-1.0.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__schemars-1.2.1\",\n sha256 = \"a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/schemars/1.2.1/download\"],\n strip_prefix = \"schemars-1.2.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.schemars-1.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__schemars_derive-1.2.1\",\n sha256 = \"7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/schemars_derive/1.2.1/download\"],\n strip_prefix = \"schemars_derive-1.2.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.schemars_derive-1.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__scopeguard-1.2.0\",\n sha256 = \"94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/scopeguard/1.2.0/download\"],\n strip_prefix = \"scopeguard-1.2.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.scopeguard-1.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__self_cell-1.2.2\",\n sha256 = \"b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/self_cell/1.2.2/download\"],\n strip_prefix = \"self_cell-1.2.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.self_cell-1.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__semver-1.0.28\",\n sha256 = \"8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/semver/1.0.28/download\"],\n strip_prefix = \"semver-1.0.28\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.semver-1.0.28.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__serde-1.0.228\",\n sha256 = \"9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde/1.0.228/download\"],\n strip_prefix = \"serde-1.0.228\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.serde-1.0.228.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__serde-wasm-bindgen-0.6.5\",\n sha256 = \"8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde-wasm-bindgen/0.6.5/download\"],\n strip_prefix = \"serde-wasm-bindgen-0.6.5\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.serde-wasm-bindgen-0.6.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__serde_core-1.0.228\",\n sha256 = \"41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_core/1.0.228/download\"],\n strip_prefix = \"serde_core-1.0.228\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.serde_core-1.0.228.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__serde_derive-1.0.228\",\n sha256 = \"d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_derive/1.0.228/download\"],\n strip_prefix = \"serde_derive-1.0.228\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.serde_derive-1.0.228.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__serde_derive_internals-0.29.1\",\n sha256 = \"18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_derive_internals/0.29.1/download\"],\n strip_prefix = \"serde_derive_internals-0.29.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.serde_derive_internals-0.29.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__serde_json-1.0.149\",\n sha256 = \"83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_json/1.0.149/download\"],\n strip_prefix = \"serde_json-1.0.149\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.serde_json-1.0.149.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__serde_spanned-1.1.1\",\n sha256 = \"6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_spanned/1.1.1/download\"],\n strip_prefix = \"serde_spanned-1.1.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.serde_spanned-1.1.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__serde_yaml-0.9.34-deprecated\",\n sha256 = \"6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_yaml/0.9.34+deprecated/download\"],\n strip_prefix = \"serde_yaml-0.9.34+deprecated\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.serde_yaml-0.9.34+deprecated.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__sha2-0.10.9\",\n sha256 = \"a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/sha2/0.10.9/download\"],\n strip_prefix = \"sha2-0.10.9\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.sha2-0.10.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__sha2-0.11.0\",\n sha256 = \"446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/sha2/0.11.0/download\"],\n strip_prefix = \"sha2-0.11.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.sha2-0.11.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__shared-buffer-0.1.4\",\n sha256 = \"f6c99835bad52957e7aa241d3975ed17c1e5f8c92026377d117a606f36b84b16\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/shared-buffer/0.1.4/download\"],\n strip_prefix = \"shared-buffer-0.1.4\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.shared-buffer-0.1.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__shlex-1.3.0\",\n sha256 = \"0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/shlex/1.3.0/download\"],\n strip_prefix = \"shlex-1.3.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.shlex-1.3.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__simd-adler32-0.3.9\",\n sha256 = \"703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/simd-adler32/0.3.9/download\"],\n strip_prefix = \"simd-adler32-0.3.9\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.simd-adler32-0.3.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__simdutf8-0.1.5\",\n sha256 = \"e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/simdutf8/0.1.5/download\"],\n strip_prefix = \"simdutf8-0.1.5\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.simdutf8-0.1.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__similar-2.7.0\",\n sha256 = \"bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/similar/2.7.0/download\"],\n strip_prefix = \"similar-2.7.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.similar-2.7.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__siphasher-1.0.2\",\n sha256 = \"b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/siphasher/1.0.2/download\"],\n strip_prefix = \"siphasher-1.0.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.siphasher-1.0.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__slab-0.4.12\",\n sha256 = \"0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/slab/0.4.12/download\"],\n strip_prefix = \"slab-0.4.12\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.slab-0.4.12.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__smallvec-1.15.1\",\n sha256 = \"67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/smallvec/1.15.1/download\"],\n strip_prefix = \"smallvec-1.15.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.smallvec-1.15.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__smoltcp-0.13.0\",\n sha256 = \"ac729b0a77bd092a3f06ddaddc59fe0d67f48ba0de45a9abe707c2842c7f8767\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/smoltcp/0.13.0/download\"],\n strip_prefix = \"smoltcp-0.13.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.smoltcp-0.13.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__stable_deref_trait-1.2.1\",\n sha256 = \"6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/stable_deref_trait/1.2.1/download\"],\n strip_prefix = \"stable_deref_trait-1.2.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.stable_deref_trait-1.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__strsim-0.11.1\",\n sha256 = \"7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/strsim/0.11.1/download\"],\n strip_prefix = \"strsim-0.11.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.strsim-0.11.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__symbolic-common-12.18.3\",\n sha256 = \"332615d90111d8eeaf86a84dc9bbe9f65d0d8c5cf11b4caccedc37754eb0dcfd\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/symbolic-common/12.18.3/download\"],\n strip_prefix = \"symbolic-common-12.18.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.symbolic-common-12.18.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__symbolic-demangle-12.18.3\",\n sha256 = \"912017718eb4d21930546245af9a3475c9dccf15675a5c215664e76621afc471\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/symbolic-demangle/12.18.3/download\"],\n strip_prefix = \"symbolic-demangle-12.18.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.symbolic-demangle-12.18.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__syn-1.0.109\",\n sha256 = \"72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/syn/1.0.109/download\"],\n strip_prefix = \"syn-1.0.109\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.syn-1.0.109.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__syn-2.0.117\",\n sha256 = \"e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/syn/2.0.117/download\"],\n strip_prefix = \"syn-2.0.117\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.syn-2.0.117.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__synstructure-0.13.2\",\n sha256 = \"728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/synstructure/0.13.2/download\"],\n strip_prefix = \"synstructure-0.13.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.synstructure-0.13.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__tar-0.4.45\",\n sha256 = \"22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tar/0.4.45/download\"],\n strip_prefix = \"tar-0.4.45\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.tar-0.4.45.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__target-lexicon-0.13.5\",\n sha256 = \"adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/target-lexicon/0.13.5/download\"],\n strip_prefix = \"target-lexicon-0.13.5\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.target-lexicon-0.13.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__tempfile-3.27.0\",\n sha256 = \"32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tempfile/3.27.0/download\"],\n strip_prefix = \"tempfile-3.27.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.tempfile-3.27.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__terminal_size-0.4.4\",\n sha256 = \"230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/terminal_size/0.4.4/download\"],\n strip_prefix = \"terminal_size-0.4.4\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.terminal_size-0.4.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__termios-0.3.3\",\n sha256 = \"411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/termios/0.3.3/download\"],\n strip_prefix = \"termios-0.3.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.termios-0.3.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__thiserror-2.0.18\",\n sha256 = \"4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/thiserror/2.0.18/download\"],\n strip_prefix = \"thiserror-2.0.18\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.thiserror-2.0.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__thiserror-impl-2.0.18\",\n sha256 = \"ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/thiserror-impl/2.0.18/download\"],\n strip_prefix = \"thiserror-impl-2.0.18\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.thiserror-impl-2.0.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__time-0.3.47\",\n sha256 = \"743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/time/0.3.47/download\"],\n strip_prefix = \"time-0.3.47\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.time-0.3.47.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__time-core-0.1.8\",\n sha256 = \"7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/time-core/0.1.8/download\"],\n strip_prefix = \"time-core-0.1.8\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.time-core-0.1.8.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__time-macros-0.2.27\",\n sha256 = \"2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/time-macros/0.2.27/download\"],\n strip_prefix = \"time-macros-0.2.27\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.time-macros-0.2.27.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__tinystr-0.8.3\",\n sha256 = \"c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tinystr/0.8.3/download\"],\n strip_prefix = \"tinystr-0.8.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.tinystr-0.8.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__tinyvec-1.11.0\",\n sha256 = \"3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tinyvec/1.11.0/download\"],\n strip_prefix = \"tinyvec-1.11.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.tinyvec-1.11.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__tinyvec_macros-0.1.1\",\n sha256 = \"1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tinyvec_macros/0.1.1/download\"],\n strip_prefix = \"tinyvec_macros-0.1.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.tinyvec_macros-0.1.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__tokio-1.52.1\",\n sha256 = \"b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tokio/1.52.1/download\"],\n strip_prefix = \"tokio-1.52.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.tokio-1.52.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__tokio-macros-2.7.0\",\n sha256 = \"385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tokio-macros/2.7.0/download\"],\n strip_prefix = \"tokio-macros-2.7.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.tokio-macros-2.7.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__tokio-stream-0.1.18\",\n sha256 = \"32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tokio-stream/0.1.18/download\"],\n strip_prefix = \"tokio-stream-0.1.18\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.tokio-stream-0.1.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__tokio-util-0.7.18\",\n sha256 = \"9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tokio-util/0.7.18/download\"],\n strip_prefix = \"tokio-util-0.7.18\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.tokio-util-0.7.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__toml-1.1.2-spec-1.1.0\",\n sha256 = \"81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/toml/1.1.2+spec-1.1.0/download\"],\n strip_prefix = \"toml-1.1.2+spec-1.1.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.toml-1.1.2+spec-1.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__toml_datetime-1.1.1-spec-1.1.0\",\n sha256 = \"3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/toml_datetime/1.1.1+spec-1.1.0/download\"],\n strip_prefix = \"toml_datetime-1.1.1+spec-1.1.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.toml_datetime-1.1.1+spec-1.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__toml_edit-0.25.11-spec-1.1.0\",\n sha256 = \"0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/toml_edit/0.25.11+spec-1.1.0/download\"],\n strip_prefix = \"toml_edit-0.25.11+spec-1.1.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.toml_edit-0.25.11+spec-1.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__toml_parser-1.1.2-spec-1.1.0\",\n sha256 = \"a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/toml_parser/1.1.2+spec-1.1.0/download\"],\n strip_prefix = \"toml_parser-1.1.2+spec-1.1.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.toml_parser-1.1.2+spec-1.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__toml_writer-1.1.1-spec-1.1.0\",\n sha256 = \"756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/toml_writer/1.1.1+spec-1.1.0/download\"],\n strip_prefix = \"toml_writer-1.1.1+spec-1.1.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.toml_writer-1.1.1+spec-1.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__tracing-0.1.44\",\n sha256 = \"63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tracing/0.1.44/download\"],\n strip_prefix = \"tracing-0.1.44\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.tracing-0.1.44.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__tracing-attributes-0.1.31\",\n sha256 = \"7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tracing-attributes/0.1.31/download\"],\n strip_prefix = \"tracing-attributes-0.1.31\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.tracing-attributes-0.1.31.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__tracing-core-0.1.36\",\n sha256 = \"db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/tracing-core/0.1.36/download\"],\n strip_prefix = \"tracing-core-0.1.36\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.tracing-core-0.1.36.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__twox-hash-2.1.2\",\n sha256 = \"9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/twox-hash/2.1.2/download\"],\n strip_prefix = \"twox-hash-2.1.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.twox-hash-2.1.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__typenum-1.20.0\",\n sha256 = \"40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/typenum/1.20.0/download\"],\n strip_prefix = \"typenum-1.20.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.typenum-1.20.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__unicase-2.9.0\",\n sha256 = \"dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unicase/2.9.0/download\"],\n strip_prefix = \"unicase-2.9.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.unicase-2.9.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__unicode-ident-1.0.24\",\n sha256 = \"e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unicode-ident/1.0.24/download\"],\n strip_prefix = \"unicode-ident-1.0.24\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.unicode-ident-1.0.24.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__unicode-normalization-0.1.25\",\n sha256 = \"5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unicode-normalization/0.1.25/download\"],\n strip_prefix = \"unicode-normalization-0.1.25\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.unicode-normalization-0.1.25.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__unicode-segmentation-1.13.2\",\n sha256 = \"9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unicode-segmentation/1.13.2/download\"],\n strip_prefix = \"unicode-segmentation-1.13.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.unicode-segmentation-1.13.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__unicode-width-0.2.2\",\n sha256 = \"b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unicode-width/0.2.2/download\"],\n strip_prefix = \"unicode-width-0.2.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.unicode-width-0.2.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__unicode-xid-0.2.6\",\n sha256 = \"ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unicode-xid/0.2.6/download\"],\n strip_prefix = \"unicode-xid-0.2.6\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.unicode-xid-0.2.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__unsafe-libyaml-0.2.11\",\n sha256 = \"673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unsafe-libyaml/0.2.11/download\"],\n strip_prefix = \"unsafe-libyaml-0.2.11\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.unsafe-libyaml-0.2.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__unty-0.0.4\",\n sha256 = \"6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unty/0.0.4/download\"],\n strip_prefix = \"unty-0.0.4\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.unty-0.0.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__url-2.5.8\",\n sha256 = \"ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/url/2.5.8/download\"],\n strip_prefix = \"url-2.5.8\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.url-2.5.8.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__urlencoding-2.1.3\",\n sha256 = \"daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/urlencoding/2.1.3/download\"],\n strip_prefix = \"urlencoding-2.1.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.urlencoding-2.1.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__utf8_iter-1.0.4\",\n sha256 = \"b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/utf8_iter/1.0.4/download\"],\n strip_prefix = \"utf8_iter-1.0.4\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.utf8_iter-1.0.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__uuid-1.23.1\",\n sha256 = \"ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/uuid/1.23.1/download\"],\n strip_prefix = \"uuid-1.23.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.uuid-1.23.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__version_check-0.9.5\",\n sha256 = \"0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/version_check/0.9.5/download\"],\n strip_prefix = \"version_check-0.9.5\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.version_check-0.9.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__virtual-fs-0.702.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n patches = [\n \"@@+_repo_rules31+postmaster_cargo//:patches/cargo/virtual-fs.patch\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/virtual-fs\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.virtual-fs-0.702.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__virtual-mio-0.702.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n patches = [\n \"@@+_repo_rules31+postmaster_cargo//:patches/cargo/virtual-mio.patch\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/virtual-io\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.virtual-mio-0.702.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__virtual-net-0.702.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n patches = [\n \"@@+_repo_rules31+postmaster_cargo//:patches/cargo/virtual-net.patch\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/virtual-net\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.virtual-net-0.702.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__virtue-0.0.18\",\n sha256 = \"051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/virtue/0.0.18/download\"],\n strip_prefix = \"virtue-0.0.18\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.virtue-0.0.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wai-bindgen-gen-core-0.2.3\",\n sha256 = \"1aa3dc41b510811122b3088197234c27e08fcad63ef936306dd8e11e2803876c\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wai-bindgen-gen-core/0.2.3/download\"],\n strip_prefix = \"wai-bindgen-gen-core-0.2.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wai-bindgen-gen-core-0.2.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wai-bindgen-gen-rust-0.2.3\",\n sha256 = \"19bc05e8380515c4337c40ef03b2ff233e391315b178a320de8640703d522efe\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wai-bindgen-gen-rust/0.2.3/download\"],\n strip_prefix = \"wai-bindgen-gen-rust-0.2.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wai-bindgen-gen-rust-0.2.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wai-bindgen-gen-rust-wasm-0.2.3\",\n sha256 = \"d6f35ce5e74086fac87f3a7bd50f643f00fe3559adb75c88521ecaa01c8a6199\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wai-bindgen-gen-rust-wasm/0.2.3/download\"],\n strip_prefix = \"wai-bindgen-gen-rust-wasm-0.2.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wai-bindgen-gen-rust-wasm-0.2.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wai-bindgen-rust-0.2.3\",\n sha256 = \"4e5601c6f448c063e83a5e931b8fefcdf7e01ada424ad42372c948d2e3d67741\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wai-bindgen-rust/0.2.3/download\"],\n strip_prefix = \"wai-bindgen-rust-0.2.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wai-bindgen-rust-0.2.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wai-bindgen-rust-impl-0.2.3\",\n sha256 = \"bdeeb5c1170246de8425a3e123e7ef260dc05ba2b522a1d369fe2315376efea4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wai-bindgen-rust-impl/0.2.3/download\"],\n strip_prefix = \"wai-bindgen-rust-impl-0.2.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wai-bindgen-rust-impl-0.2.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wai-parser-0.2.3\",\n sha256 = \"9bd0acb6d70885ea0c343749019ba74f015f64a9d30542e66db69b49b7e28186\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wai-parser/0.2.3/download\"],\n strip_prefix = \"wai-parser-0.2.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wai-parser-0.2.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__waker-fn-1.2.0\",\n sha256 = \"317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/waker-fn/1.2.0/download\"],\n strip_prefix = \"waker-fn-1.2.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.waker-fn-1.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__walkdir-2.5.0\",\n sha256 = \"29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/walkdir/2.5.0/download\"],\n strip_prefix = \"walkdir-2.5.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.walkdir-2.5.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wasip2-1.0.3-wasi-0.2.9\",\n sha256 = \"20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasip2/1.0.3+wasi-0.2.9/download\"],\n strip_prefix = \"wasip2-1.0.3+wasi-0.2.9\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wasip2-1.0.3+wasi-0.2.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wasip3-0.4.0-wasi-0.3.0-rc-2026-01-06\",\n sha256 = \"5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasip3/0.4.0+wasi-0.3.0-rc-2026-01-06/download\"],\n strip_prefix = \"wasip3-0.4.0+wasi-0.3.0-rc-2026-01-06\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wasip3-0.4.0+wasi-0.3.0-rc-2026-01-06.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wasm-bindgen-0.2.118\",\n sha256 = \"0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-bindgen/0.2.118/download\"],\n strip_prefix = \"wasm-bindgen-0.2.118\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wasm-bindgen-0.2.118.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wasm-bindgen-macro-0.2.118\",\n sha256 = \"eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-bindgen-macro/0.2.118/download\"],\n strip_prefix = \"wasm-bindgen-macro-0.2.118\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wasm-bindgen-macro-0.2.118.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wasm-bindgen-macro-support-0.2.118\",\n sha256 = \"9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-bindgen-macro-support/0.2.118/download\"],\n strip_prefix = \"wasm-bindgen-macro-support-0.2.118\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wasm-bindgen-macro-support-0.2.118.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wasm-bindgen-shared-0.2.118\",\n sha256 = \"5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-bindgen-shared/0.2.118/download\"],\n strip_prefix = \"wasm-bindgen-shared-0.2.118\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wasm-bindgen-shared-0.2.118.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wasm-encoder-0.244.0\",\n sha256 = \"990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-encoder/0.244.0/download\"],\n strip_prefix = \"wasm-encoder-0.244.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wasm-encoder-0.244.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wasm-encoder-0.247.0\",\n sha256 = \"30b6733b8b91d010a6ac5b0fb237dc46a19650bc4c67db66857e2e787d437204\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-encoder/0.247.0/download\"],\n strip_prefix = \"wasm-encoder-0.247.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wasm-encoder-0.247.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wasm-metadata-0.244.0\",\n sha256 = \"bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-metadata/0.244.0/download\"],\n strip_prefix = \"wasm-metadata-0.244.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wasm-metadata-0.244.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wasmer-7.2.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n patches = [\n \"@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer.patch\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/api\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wasmer-7.2.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wasmer-compiler-7.2.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n patches = [\n \"@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-compiler.patch\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/compiler\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wasmer-compiler-7.2.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wasmer-compiler-llvm-7.2.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n patches = [\n \"@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-compiler-llvm.patch\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/compiler-llvm\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wasmer-compiler-llvm-7.2.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wasmer-config-0.702.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/config\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wasmer-config-0.702.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wasmer-derive-7.2.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/derive\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wasmer-derive-7.2.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wasmer-journal-0.702.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/journal\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wasmer-journal-0.702.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wasmer-package-0.702.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/package\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wasmer-package-0.702.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wasmer-types-7.2.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n patches = [\n \"@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-types.patch\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/types\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wasmer-types-7.2.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wasmer-vm-7.2.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n patches = [\n \"@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-vm.patch\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/vm\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wasmer-vm-7.2.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wasmer-wasix-0.702.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n patches = [\n \"@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-wasix.patch\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/wasix\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wasmer-wasix-0.702.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wasmer-wasix-types-0.702.0-alpha.2\",\n patch_args = [\n \"-p1\",\n ],\n sha256 = \"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\n type = \"tar.gz\",\n urls = [\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"],\n strip_prefix = \"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/wasi-types\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wasmer-wasix-types-0.702.0-alpha.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wasmparser-0.244.0\",\n sha256 = \"47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasmparser/0.244.0/download\"],\n strip_prefix = \"wasmparser-0.244.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wasmparser-0.244.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wasmparser-0.247.0\",\n sha256 = \"8e6fb4c2bee46c5ea4d40f8cdb5c131725cd976718ec56f1c8e82fbde5fa2a80\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasmparser/0.247.0/download\"],\n strip_prefix = \"wasmparser-0.247.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wasmparser-0.247.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wast-247.0.0\",\n sha256 = \"579d2d47eb33b0cdf9b14723cb115f1e1b7d6e77aac6f0816e5b7c7aeaa418ff\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wast/247.0.0/download\"],\n strip_prefix = \"wast-247.0.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wast-247.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wat-1.247.0\",\n sha256 = \"f3f4091c56437e86f2b57fa2fac72c4f528957a605b3f44f7c0b3b19a17ac5ee\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wat/1.247.0/download\"],\n strip_prefix = \"wat-1.247.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wat-1.247.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__webc-11.0.0\",\n sha256 = \"20b8b523112384e8c1caf77cffdd371ca7e0013779f081e6beafc537f5b5325d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/webc/11.0.0/download\"],\n strip_prefix = \"webc-11.0.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.webc-11.0.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__weezl-0.1.12\",\n sha256 = \"a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/weezl/0.1.12/download\"],\n strip_prefix = \"weezl-0.1.12\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.weezl-0.1.12.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__which-8.0.2\",\n sha256 = \"81995fafaaaf6ae47a7d0cc83c67caf92aeb7e5331650ae6ff856f7c0c60c459\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/which/8.0.2/download\"],\n strip_prefix = \"which-8.0.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.which-8.0.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__winapi-util-0.1.11\",\n sha256 = \"c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/winapi-util/0.1.11/download\"],\n strip_prefix = \"winapi-util-0.1.11\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.winapi-util-0.1.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__windows-link-0.2.1\",\n sha256 = \"f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-link/0.2.1/download\"],\n strip_prefix = \"windows-link-0.2.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.windows-link-0.2.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__windows-sys-0.52.0\",\n sha256 = \"282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-sys/0.52.0/download\"],\n strip_prefix = \"windows-sys-0.52.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.windows-sys-0.52.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__windows-sys-0.59.0\",\n sha256 = \"1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-sys/0.59.0/download\"],\n strip_prefix = \"windows-sys-0.59.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.windows-sys-0.59.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__windows-sys-0.61.2\",\n sha256 = \"ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-sys/0.61.2/download\"],\n strip_prefix = \"windows-sys-0.61.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.windows-sys-0.61.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__windows-targets-0.52.6\",\n sha256 = \"9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows-targets/0.52.6/download\"],\n strip_prefix = \"windows-targets-0.52.6\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.windows-targets-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__windows_aarch64_gnullvm-0.52.6\",\n sha256 = \"32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_aarch64_gnullvm/0.52.6/download\"],\n strip_prefix = \"windows_aarch64_gnullvm-0.52.6\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.windows_aarch64_gnullvm-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__windows_aarch64_msvc-0.52.6\",\n sha256 = \"09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_aarch64_msvc/0.52.6/download\"],\n strip_prefix = \"windows_aarch64_msvc-0.52.6\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.windows_aarch64_msvc-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__windows_i686_gnu-0.52.6\",\n sha256 = \"8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_i686_gnu/0.52.6/download\"],\n strip_prefix = \"windows_i686_gnu-0.52.6\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.windows_i686_gnu-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__windows_i686_gnullvm-0.52.6\",\n sha256 = \"0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_i686_gnullvm/0.52.6/download\"],\n strip_prefix = \"windows_i686_gnullvm-0.52.6\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.windows_i686_gnullvm-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__windows_i686_msvc-0.52.6\",\n sha256 = \"240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_i686_msvc/0.52.6/download\"],\n strip_prefix = \"windows_i686_msvc-0.52.6\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.windows_i686_msvc-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__windows_x86_64_gnu-0.52.6\",\n sha256 = \"147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_x86_64_gnu/0.52.6/download\"],\n strip_prefix = \"windows_x86_64_gnu-0.52.6\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.windows_x86_64_gnu-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__windows_x86_64_gnullvm-0.52.6\",\n sha256 = \"24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_x86_64_gnullvm/0.52.6/download\"],\n strip_prefix = \"windows_x86_64_gnullvm-0.52.6\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.windows_x86_64_gnullvm-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__windows_x86_64_msvc-0.52.6\",\n sha256 = \"589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/windows_x86_64_msvc/0.52.6/download\"],\n strip_prefix = \"windows_x86_64_msvc-0.52.6\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.windows_x86_64_msvc-0.52.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__winnow-1.0.2\",\n sha256 = \"2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/winnow/1.0.2/download\"],\n strip_prefix = \"winnow-1.0.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.winnow-1.0.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wit-bindgen-0.51.0\",\n sha256 = \"d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wit-bindgen/0.51.0/download\"],\n strip_prefix = \"wit-bindgen-0.51.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wit-bindgen-0.51.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wit-bindgen-0.57.1\",\n sha256 = \"1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wit-bindgen/0.57.1/download\"],\n strip_prefix = \"wit-bindgen-0.57.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wit-bindgen-0.57.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wit-bindgen-core-0.51.0\",\n sha256 = \"ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wit-bindgen-core/0.51.0/download\"],\n strip_prefix = \"wit-bindgen-core-0.51.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wit-bindgen-core-0.51.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wit-bindgen-rust-0.51.0\",\n sha256 = \"b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wit-bindgen-rust/0.51.0/download\"],\n strip_prefix = \"wit-bindgen-rust-0.51.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wit-bindgen-rust-0.51.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wit-bindgen-rust-macro-0.51.0\",\n sha256 = \"0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wit-bindgen-rust-macro/0.51.0/download\"],\n strip_prefix = \"wit-bindgen-rust-macro-0.51.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wit-bindgen-rust-macro-0.51.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wit-component-0.244.0\",\n sha256 = \"9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wit-component/0.244.0/download\"],\n strip_prefix = \"wit-component-0.244.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wit-component-0.244.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__wit-parser-0.244.0\",\n sha256 = \"ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wit-parser/0.244.0/download\"],\n strip_prefix = \"wit-parser-0.244.0\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.wit-parser-0.244.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__writeable-0.6.3\",\n sha256 = \"1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/writeable/0.6.3/download\"],\n strip_prefix = \"writeable-0.6.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.writeable-0.6.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__xattr-1.6.1\",\n sha256 = \"32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/xattr/1.6.1/download\"],\n strip_prefix = \"xattr-1.6.1\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.xattr-1.6.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__xxhash-rust-0.8.15\",\n sha256 = \"fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/xxhash-rust/0.8.15/download\"],\n strip_prefix = \"xxhash-rust-0.8.15\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.xxhash-rust-0.8.15.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__yoke-0.8.2\",\n sha256 = \"abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/yoke/0.8.2/download\"],\n strip_prefix = \"yoke-0.8.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.yoke-0.8.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__yoke-derive-0.8.2\",\n sha256 = \"de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/yoke-derive/0.8.2/download\"],\n strip_prefix = \"yoke-derive-0.8.2\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.yoke-derive-0.8.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__zerocopy-0.8.48\",\n sha256 = \"eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerocopy/0.8.48/download\"],\n strip_prefix = \"zerocopy-0.8.48\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.zerocopy-0.8.48.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__zerocopy-derive-0.8.48\",\n sha256 = \"70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerocopy-derive/0.8.48/download\"],\n strip_prefix = \"zerocopy-derive-0.8.48\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.zerocopy-derive-0.8.48.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__zerofrom-0.1.7\",\n sha256 = \"69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerofrom/0.1.7/download\"],\n strip_prefix = \"zerofrom-0.1.7\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.zerofrom-0.1.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__zerofrom-derive-0.1.7\",\n sha256 = \"11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerofrom-derive/0.1.7/download\"],\n strip_prefix = \"zerofrom-derive-0.1.7\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.zerofrom-derive-0.1.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__zerotrie-0.2.4\",\n sha256 = \"0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerotrie/0.2.4/download\"],\n strip_prefix = \"zerotrie-0.2.4\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.zerotrie-0.2.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__zerovec-0.11.6\",\n sha256 = \"90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerovec/0.11.6/download\"],\n strip_prefix = \"zerovec-0.11.6\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.zerovec-0.11.6.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__zerovec-derive-0.11.3\",\n sha256 = \"625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zerovec-derive/0.11.3/download\"],\n strip_prefix = \"zerovec-derive-0.11.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.zerovec-derive-0.11.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__zmij-1.0.21\",\n sha256 = \"b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zmij/1.0.21/download\"],\n strip_prefix = \"zmij-1.0.21\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.zmij-1.0.21.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__zstd-0.13.3\",\n sha256 = \"e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zstd/0.13.3/download\"],\n strip_prefix = \"zstd-0.13.3\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.zstd-0.13.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__zstd-safe-7.2.4\",\n sha256 = \"8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zstd-safe/7.2.4/download\"],\n strip_prefix = \"zstd-safe-7.2.4\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.zstd-safe-7.2.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_compiler_crates__zstd-sys-2.0.16-zstd.1.5.7\",\n sha256 = \"91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zstd-sys/2.0.16+zstd.1.5.7/download\"],\n strip_prefix = \"zstd-sys-2.0.16+zstd.1.5.7\",\n build_file = Label(\"@postmaster_compiler_crates//postmaster_compiler_crates:BUILD.zstd-sys-2.0.16+zstd.1.5.7.bazel\"),\n )\n\n return [\n struct(repo = \"postmaster_compiler_crates\", is_dev_dep = False),\n struct(repo=\"postmaster_compiler_crates__anyhow-1.0.102\", is_dev_dep = False),\n struct(repo=\"postmaster_compiler_crates__async-trait-0.1.89\", is_dev_dep = False),\n struct(repo=\"postmaster_compiler_crates__hex-0.4.3\", is_dev_dep = False),\n struct(repo=\"postmaster_compiler_crates__libc-0.2.186\", is_dev_dep = False),\n struct(repo=\"postmaster_compiler_crates__serde-1.0.228\", is_dev_dep = False),\n struct(repo=\"postmaster_compiler_crates__serde_json-1.0.149\", is_dev_dep = False),\n struct(repo=\"postmaster_compiler_crates__sha2-0.11.0\", is_dev_dep = False),\n struct(repo=\"postmaster_compiler_crates__tempfile-3.27.0\", is_dev_dep = False),\n struct(repo=\"postmaster_compiler_crates__tracing-0.1.44\", is_dev_dep = False),\n struct(repo=\"postmaster_compiler_crates__wasmer-7.2.0-alpha.2\", is_dev_dep = False),\n struct(repo=\"postmaster_compiler_crates__wasmer-compiler-llvm-7.2.0-alpha.2\", is_dev_dep = False),\n struct(repo=\"postmaster_compiler_crates__wasmer-types-7.2.0-alpha.2\", is_dev_dep = False),\n struct(repo=\"postmaster_compiler_crates__wasmer-vm-7.2.0-alpha.2\", is_dev_dep = False),\n struct(repo=\"postmaster_compiler_crates__wasmer-wasix-0.702.0-alpha.2\", is_dev_dep = False),\n struct(repo=\"postmaster_compiler_crates__wasmparser-0.247.0\", is_dev_dep = False),\n struct(repo = \"postmaster_compiler_crates__futures-0.3.32\", is_dev_dep = True),\n struct(repo = \"postmaster_compiler_crates__wat-1.247.0\", is_dev_dep = True),\n ]\n", + "defs.bzl": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\"\"\"Deprecated: re-exports the crate_universe macros from `:crates.bzl`.\"\"\"\n\nload(\n \":crates.bzl\",\n _aliases = \"aliases\",\n _all_crate_deps = \"all_crate_deps\",\n _crate_deps = \"crate_deps\",\n _crate_edition = \"crate_edition\",\n _crate_repositories = \"crate_repositories\",\n)\n\naliases = _aliases\nall_crate_deps = _all_crate_deps\ncrate_deps = _crate_deps\ncrate_edition = _crate_edition\ncrate_repositories = _crate_repositories\n", + "cargo-bazel.json": "{\"checksum\":\"bca02c44e62f562e7eb802854319896649439189db58f2f839d9b20d8da2ab1c\",\"conditions\":{\"aarch64-apple-darwin\":[\"aarch64-apple-darwin\"],\"aarch64-linux-android\":[],\"aarch64-pc-windows-gnullvm\":[],\"aarch64-unknown-linux-gnu\":[\"aarch64-unknown-linux-gnu\"],\"cfg(all(any(target_arch = \\\"x86_64\\\", target_arch = \\\"arm64ec\\\"), target_env = \\\"msvc\\\", not(windows_raw_dylib)))\":[],\"cfg(all(any(target_os = \\\"linux\\\", target_os = \\\"android\\\"), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\":[],\"cfg(all(any(target_os = \\\"linux\\\", target_os = \\\"android\\\"), not(any(all(target_os = \\\"linux\\\", target_env = \\\"\\\"), getrandom_backend = \\\"custom\\\", getrandom_backend = \\\"linux_raw\\\", getrandom_backend = \\\"rdrand\\\", getrandom_backend = \\\"rndr\\\"))))\":[\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\":[\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(all(not(target_arch = \\\"wasm32\\\"), target_os = \\\"windows\\\"))\":[],\"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\":[\"aarch64-apple-darwin\"],\"cfg(all(target_arch = \\\"aarch64\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\":[],\"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"android\\\"))\":[],\"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"linux\\\"))\":[\"aarch64-unknown-linux-gnu\"],\"cfg(all(target_arch = \\\"aarch64\\\", target_vendor = \\\"apple\\\"))\":[\"aarch64-apple-darwin\"],\"cfg(all(target_arch = \\\"loongarch64\\\", target_os = \\\"linux\\\"))\":[],\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"wasi\\\", target_env = \\\"p2\\\"))\":[],\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"wasi\\\", target_env = \\\"p3\\\"))\":[],\"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"gnu\\\", not(target_abi = \\\"llvm\\\"), not(windows_raw_dylib)))\":[],\"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\":[],\"cfg(all(target_arch = \\\"x86_64\\\", target_env = \\\"gnu\\\", not(target_abi = \\\"llvm\\\"), not(windows_raw_dylib)))\":[\"x86_64-unknown-linux-gnu\"],\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"wasi\\\"))\":[],\"cfg(all(target_os = \\\"macos\\\", target_arch = \\\"aarch64\\\"))\":[\"aarch64-apple-darwin\"],\"cfg(all(target_os = \\\"uefi\\\", getrandom_backend = \\\"efi_rng\\\"))\":[],\"cfg(all(unix, not(target_os = \\\"ios\\\")))\":[\"aarch64-apple-darwin\",\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(any())\":[],\"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\":[\"aarch64-apple-darwin\",\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(any(target_arch = \\\"arm\\\", target_pointer_width = \\\"32\\\", target_pointer_width = \\\"64\\\"))\":[\"aarch64-apple-darwin\",\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(any(target_arch = \\\"x86\\\", target_arch = \\\"x86_64\\\"))\":[\"x86_64-unknown-linux-gnu\"],\"cfg(any(target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\":[\"x86_64-unknown-linux-gnu\"],\"cfg(any(target_family = \\\"unix\\\", all(target_family = \\\"windows\\\", target_env = \\\"gnu\\\")))\":[\"aarch64-apple-darwin\",\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(any(target_os = \\\"android\\\", target_os = \\\"linux\\\", target_os = \\\"macos\\\", target_os = \\\"hurd\\\"))\":[\"aarch64-apple-darwin\",\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(any(target_os = \\\"dragonfly\\\", target_os = \\\"freebsd\\\", target_os = \\\"hurd\\\", target_os = \\\"illumos\\\", target_os = \\\"cygwin\\\", all(target_os = \\\"horizon\\\", target_arch = \\\"arm\\\")))\":[],\"cfg(any(target_os = \\\"freebsd\\\", target_os = \\\"netbsd\\\"))\":[],\"cfg(any(target_os = \\\"haiku\\\", target_os = \\\"redox\\\", target_os = \\\"nto\\\", target_os = \\\"aix\\\"))\":[],\"cfg(any(target_os = \\\"ios\\\", target_os = \\\"visionos\\\", target_os = \\\"watchos\\\", target_os = \\\"tvos\\\"))\":[],\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"ios\\\"))\":[\"aarch64-apple-darwin\"],\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"openbsd\\\", target_os = \\\"vita\\\", target_os = \\\"emscripten\\\"))\":[\"aarch64-apple-darwin\"],\"cfg(any(unix, target_os = \\\"wasi\\\"))\":[\"aarch64-apple-darwin\",\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(any(windows, target_os = \\\"cygwin\\\"))\":[],\"cfg(not(all(windows, target_env = \\\"msvc\\\", not(target_vendor = \\\"uwp\\\"))))\":[\"aarch64-apple-darwin\",\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(not(target_arch = \\\"wasm32\\\"))\":[\"aarch64-apple-darwin\",\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(not(windows))\":[\"aarch64-apple-darwin\",\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(target_arch = \\\"spirv\\\")\":[],\"cfg(target_arch = \\\"wasm32\\\")\":[],\"cfg(target_os = \\\"hermit\\\")\":[],\"cfg(target_os = \\\"netbsd\\\")\":[],\"cfg(target_os = \\\"redox\\\")\":[],\"cfg(target_os = \\\"solaris\\\")\":[],\"cfg(target_os = \\\"vxworks\\\")\":[],\"cfg(target_os = \\\"wasi\\\")\":[],\"cfg(target_os = \\\"windows\\\")\":[],\"cfg(target_vendor = \\\"apple\\\")\":[\"aarch64-apple-darwin\"],\"cfg(unix)\":[\"aarch64-apple-darwin\",\"aarch64-unknown-linux-gnu\",\"x86_64-unknown-linux-gnu\"],\"cfg(windows)\":[],\"i686-pc-windows-gnullvm\":[],\"x86_64-pc-windows-gnullvm\":[],\"x86_64-unknown-linux-gnu\":[\"x86_64-unknown-linux-gnu\"]},\"crates\":{\"addr2line 0.25.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"gimli 0.32.3\",\"target\":\"gimli\"}],\"edition\":\"2018\"},\"library_target_name\":\"addr2line\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"addr2line\",\"package_url\":\"https://github.com/gimli-rs/addr2line\",\"repository\":{\"Http\":{\"sha256\":\"1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b\",\"url\":\"https://static.crates.io/crates/addr2line/0.25.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"addr2line\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.25.1\"},\"adler2 2.0.1\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"adler2\",\"license\":\"0BSD OR MIT OR Apache-2.0\",\"license_file\":\"LICENSE-0BSD\",\"license_ids\":[\"0BSD\",\"Apache-2.0\",\"MIT\"],\"name\":\"adler2\",\"package_url\":\"https://github.com/oyvindln/adler2\",\"repository\":{\"Http\":{\"sha256\":\"320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa\",\"url\":\"https://static.crates.io/crates/adler2/2.0.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"adler2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.0.1\"},\"aho-corasick 1.1.4\":{\"common_attrs\":{\"crate_features\":[\"default\",\"perf-literal\",\"std\"],\"deps\":[{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"}],\"edition\":\"2021\"},\"library_target_name\":\"aho_corasick\",\"license\":\"Unlicense OR MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"aho-corasick\",\"package_url\":\"https://github.com/BurntSushi/aho-corasick\",\"repository\":{\"Http\":{\"sha256\":\"ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301\",\"url\":\"https://static.crates.io/crates/aho-corasick/1.1.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"aho_corasick\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.4\"},\"any_ascii 0.1.7\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"any_ascii\",\"license\":\"ISC\",\"license_file\":\"LICENSE\",\"license_ids\":[\"ISC\"],\"name\":\"any_ascii\",\"package_url\":\"https://github.com/anyascii/anyascii\",\"repository\":{\"Http\":{\"sha256\":\"70033777eb8b5124a81a1889416543dddef2de240019b674c81285a2635a7e1e\",\"url\":\"https://static.crates.io/crates/any_ascii/0.1.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"any_ascii\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.7\"},\"anyhow 1.0.102\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"anyhow\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"anyhow\",\"package_url\":\"https://github.com/dtolnay/anyhow\",\"repository\":{\"Http\":{\"sha256\":\"7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c\",\"url\":\"https://static.crates.io/crates/anyhow/1.0.102/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"anyhow\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.102\"},\"arrayref 0.3.9\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"arrayref\",\"license\":\"BSD-2-Clause\",\"license_file\":\"LICENSE\",\"license_ids\":[\"BSD-2-Clause\"],\"name\":\"arrayref\",\"package_url\":\"https://github.com/droundy/arrayref\",\"repository\":{\"Http\":{\"sha256\":\"76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb\",\"url\":\"https://static.crates.io/crates/arrayref/0.3.9/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"arrayref\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.9\"},\"arrayvec 0.7.6\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"arrayvec\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"arrayvec\",\"package_url\":\"https://github.com/bluss/arrayvec\",\"repository\":{\"Http\":{\"sha256\":\"7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50\",\"url\":\"https://static.crates.io/crates/arrayvec/0.7.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"arrayvec\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.6\"},\"async-trait 0.1.89\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"async_trait\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"async-trait\",\"package_url\":\"https://github.com/dtolnay/async-trait\",\"repository\":{\"Http\":{\"sha256\":\"9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb\",\"url\":\"https://static.crates.io/crates/async-trait/0.1.89/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"async_trait\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.89\"},\"autocfg 1.5.0\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"autocfg\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"autocfg\",\"package_url\":\"https://github.com/cuviper/autocfg\",\"repository\":{\"Http\":{\"sha256\":\"c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8\",\"url\":\"https://static.crates.io/crates/autocfg/1.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"autocfg\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.5.0\"},\"backtrace 0.3.76\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"rustc-demangle 0.1.27\",\"target\":\"rustc_demangle\"}],\"selects\":{\"cfg(any(windows, target_os = \\\"cygwin\\\"))\":[{\"id\":\"windows-link 0.2.1\",\"target\":\"windows_link\"}],\"cfg(not(all(windows, target_env = \\\"msvc\\\", not(target_vendor = \\\"uwp\\\"))))\":[{\"id\":\"addr2line 0.25.1\",\"target\":\"addr2line\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"},{\"id\":\"miniz_oxide 0.8.9\",\"target\":\"miniz_oxide\"},{\"id\":\"object 0.37.3\",\"target\":\"object\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"backtrace\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"backtrace\",\"package_url\":\"https://github.com/rust-lang/backtrace-rs\",\"repository\":{\"Http\":{\"sha256\":\"bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6\",\"url\":\"https://static.crates.io/crates/backtrace/0.3.76/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"backtrace\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.76\"},\"base64 0.22.1\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"base64\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"base64\",\"package_url\":\"https://github.com/marshallpierce/rust-base64\",\"repository\":{\"Http\":{\"sha256\":\"72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6\",\"url\":\"https://static.crates.io/crates/base64/0.22.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"base64\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.22.1\"},\"bincode 2.0.1\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"bincode_derive\",\"default\",\"derive\",\"serde\",\"std\"],\"deps\":[{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"unty 0.0.4\",\"target\":\"unty\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"bincode_derive 2.0.1\",\"target\":\"bincode_derive\"}]},\"library_target_name\":\"bincode\",\"license\":\"MIT\",\"license_file\":\"LICENSE.md\",\"license_ids\":[\"MIT\"],\"name\":\"bincode\",\"package_url\":\"https://github.com/bincode-org/bincode\",\"repository\":{\"Http\":{\"sha256\":\"36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740\",\"url\":\"https://static.crates.io/crates/bincode/2.0.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bincode\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.0.1\"},\"bincode_derive 2.0.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"virtue 0.0.18\",\"target\":\"virtue\"}],\"edition\":\"2021\"},\"library_target_name\":\"bincode_derive\",\"license\":\"MIT\",\"license_file\":\"LICENSE.md\",\"license_ids\":[\"MIT\"],\"name\":\"bincode_derive\",\"package_url\":\"https://github.com/bincode-org/bincode\",\"repository\":{\"Http\":{\"sha256\":\"bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09\",\"url\":\"https://static.crates.io/crates/bincode_derive/2.0.1/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"bincode_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.0.1\"},\"bindgen 0.72.1\":{\"build_script_attrs\":{\"link_deps\":[{\"id\":\"clang-sys 1.8.1\",\"target\":\"clang_sys\"},{\"id\":\"prettyplease 0.2.37\",\"target\":\"prettyplease\"}]},\"common_attrs\":{\"crate_features\":[\"default\",\"logging\",\"prettyplease\",\"runtime\"],\"deps\":[{\"id\":\"bitflags 2.11.1\",\"target\":\"bitflags\"},{\"id\":\"cexpr 0.6.0\",\"target\":\"cexpr\"},{\"id\":\"clang-sys 1.8.1\",\"target\":\"clang_sys\"},{\"id\":\"itertools 0.13.0\",\"target\":\"itertools\"},{\"id\":\"log 0.4.29\",\"target\":\"log\"},{\"id\":\"prettyplease 0.2.37\",\"target\":\"prettyplease\"},{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"regex 1.12.3\",\"target\":\"regex\"},{\"id\":\"rustc-hash 2.1.2\",\"target\":\"rustc_hash\"},{\"id\":\"shlex 1.3.0\",\"target\":\"shlex\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"bindgen\",\"license\":\"BSD-3-Clause\",\"license_file\":\"LICENSE\",\"license_ids\":[\"BSD-3-Clause\"],\"name\":\"bindgen\",\"package_url\":\"https://github.com/rust-lang/rust-bindgen\",\"repository\":{\"Http\":{\"sha256\":\"993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895\",\"url\":\"https://static.crates.io/crates/bindgen/0.72.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bindgen\",\"crate_root\":\"lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.72.1\"},\"bitflags 1.3.2\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"edition\":\"2018\"},\"library_target_name\":\"bitflags\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"bitflags\",\"package_url\":\"https://github.com/bitflags/bitflags\",\"repository\":{\"Http\":{\"sha256\":\"bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a\",\"url\":\"https://static.crates.io/crates/bitflags/1.3.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bitflags\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.3.2\"},\"bitflags 2.11.1\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"bitflags\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"bitflags\",\"package_url\":\"https://github.com/bitflags/bitflags\",\"repository\":{\"Http\":{\"sha256\":\"c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3\",\"url\":\"https://static.crates.io/crates/bitflags/2.11.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bitflags\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.11.1\"},\"blake3 1.8.4\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"cc 1.2.60\",\"target\":\"cc\"}]},\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":{\"common\":[{\"id\":\"arrayref 0.3.9\",\"target\":\"arrayref\"},{\"id\":\"arrayvec 0.7.6\",\"target\":\"arrayvec\"},{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"constant_time_eq 0.4.2\",\"target\":\"constant_time_eq\"}],\"selects\":{\"cfg(any(target_arch = \\\"x86\\\", target_arch = \\\"x86_64\\\"))\":[{\"id\":\"cpufeatures 0.3.0\",\"target\":\"cpufeatures\"}]}},\"edition\":\"2024\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"blake3\",\"license\":\"CC0-1.0 OR Apache-2.0 OR Apache-2.0 WITH LLVM-exception\",\"license_file\":\"LICENSE_A2\",\"license_ids\":[\"Apache-2.0\",\"CC0-1.0\"],\"name\":\"blake3\",\"package_url\":\"https://github.com/BLAKE3-team/BLAKE3\",\"repository\":{\"Http\":{\"sha256\":\"4d2d5991425dfd0785aed03aedcf0b321d61975c9b5b3689c774a2610ae0b51e\",\"url\":\"https://static.crates.io/crates/blake3/1.8.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"blake3\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.8.4\"},\"block-buffer 0.10.4\":{\"common_attrs\":{\"deps\":[{\"id\":\"generic-array 0.14.7\",\"target\":\"generic_array\"}],\"edition\":\"2018\"},\"library_target_name\":\"block_buffer\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"block-buffer\",\"package_url\":\"https://github.com/RustCrypto/utils\",\"repository\":{\"Http\":{\"sha256\":\"3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71\",\"url\":\"https://static.crates.io/crates/block-buffer/0.10.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"block_buffer\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.10.4\"},\"block-buffer 0.12.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"hybrid-array 0.4.10\",\"target\":\"hybrid_array\"}],\"edition\":\"2024\"},\"library_target_name\":\"block_buffer\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"block-buffer\",\"package_url\":\"https://github.com/RustCrypto/utils\",\"repository\":{\"Http\":{\"sha256\":\"cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be\",\"url\":\"https://static.crates.io/crates/block-buffer/0.12.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"block_buffer\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.12.0\"},\"bstr 1.12.1\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"std\"],\"deps\":[{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"}],\"edition\":\"2021\"},\"library_target_name\":\"bstr\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"bstr\",\"package_url\":\"https://github.com/BurntSushi/bstr\",\"repository\":{\"Http\":{\"sha256\":\"63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab\",\"url\":\"https://static.crates.io/crates/bstr/1.12.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bstr\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.12.1\"},\"bumpalo 3.20.2\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"edition\":\"2021\"},\"library_target_name\":\"bumpalo\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"bumpalo\",\"package_url\":\"https://github.com/fitzgen/bumpalo\",\"repository\":{\"Http\":{\"sha256\":\"5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb\",\"url\":\"https://static.crates.io/crates/bumpalo/3.20.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bumpalo\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"3.20.2\"},\"bytecheck 0.8.2\":{\"common_attrs\":{\"crate_features\":[\"default\",\"simdutf8\"],\"deps\":[{\"id\":\"ptr_meta 0.3.1\",\"target\":\"ptr_meta\"},{\"id\":\"rancor 0.1.1\",\"target\":\"rancor\"},{\"id\":\"simdutf8 0.1.5\",\"target\":\"simdutf8\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"bytecheck_derive 0.8.2\",\"target\":\"bytecheck_derive\"}]},\"library_target_name\":\"bytecheck\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"bytecheck\",\"package_url\":\"https://github.com/rkyv/bytecheck\",\"repository\":{\"Http\":{\"sha256\":\"0caa33a2c0edca0419d15ac723dff03f1956f7978329b1e3b5fdaaaed9d3ca8b\",\"url\":\"https://static.crates.io/crates/bytecheck/0.8.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bytecheck\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.2\"},\"bytecheck_derive 0.8.2\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"bytecheck_derive\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"bytecheck_derive\",\"package_url\":\"https://github.com/rkyv/bytecheck\",\"repository\":{\"Http\":{\"sha256\":\"89385e82b5d1821d2219e0b095efa2cc1f246cbf99080f3be46a1a85c0d392d9\",\"url\":\"https://static.crates.io/crates/bytecheck_derive/0.8.2/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"bytecheck_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.2\"},\"byteorder 1.5.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"byteorder\",\"license\":\"Unlicense OR MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"byteorder\",\"package_url\":\"https://github.com/BurntSushi/byteorder\",\"repository\":{\"Http\":{\"sha256\":\"1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b\",\"url\":\"https://static.crates.io/crates/byteorder/1.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"byteorder\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.5.0\"},\"bytes 1.11.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"serde\",\"std\"],\"deps\":[{\"id\":\"serde 1.0.228\",\"target\":\"serde\"}],\"edition\":\"2021\"},\"library_target_name\":\"bytes\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"bytes\",\"package_url\":\"https://github.com/tokio-rs/bytes\",\"repository\":{\"Http\":{\"sha256\":\"1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33\",\"url\":\"https://static.crates.io/crates/bytes/1.11.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bytes\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.11.1\"},\"bytesize 2.3.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"serde\",\"std\"],\"deps\":[{\"id\":\"serde_core 1.0.228\",\"target\":\"serde_core\"}],\"edition\":\"2021\"},\"library_target_name\":\"bytesize\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"bytesize\",\"package_url\":\"https://github.com/bytesize-rs/bytesize\",\"repository\":{\"Http\":{\"sha256\":\"6bd91ee7b2422bcb158d90ef4d14f75ef67f340943fc4149891dcce8f8b972a3\",\"url\":\"https://static.crates.io/crates/bytesize/2.3.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"bytesize\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.3.1\"},\"cc 1.2.60\":{\"common_attrs\":{\"crate_features\":[\"parallel\"],\"deps\":[{\"id\":\"find-msvc-tools 0.1.9\",\"target\":\"find_msvc_tools\"},{\"id\":\"jobserver 0.1.34\",\"target\":\"jobserver\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"},{\"id\":\"shlex 1.3.0\",\"target\":\"shlex\"}],\"edition\":\"2018\"},\"library_target_name\":\"cc\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"cc\",\"package_url\":\"https://github.com/rust-lang/cc-rs\",\"repository\":{\"Http\":{\"sha256\":\"43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20\",\"url\":\"https://static.crates.io/crates/cc/1.2.60/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cc\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.60\"},\"cexpr 0.6.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"nom 7.1.3\",\"target\":\"nom\"}],\"edition\":\"2018\"},\"library_target_name\":\"cexpr\",\"license\":\"Apache-2.0/MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"cexpr\",\"package_url\":\"https://github.com/jethrogb/rust-cexpr\",\"repository\":{\"Http\":{\"sha256\":\"6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766\",\"url\":\"https://static.crates.io/crates/cexpr/0.6.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cexpr\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.0\"},\"cfg-if 1.0.4\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"cfg_if\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"cfg-if\",\"package_url\":\"https://github.com/rust-lang/cfg-if\",\"repository\":{\"Http\":{\"sha256\":\"9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801\",\"url\":\"https://static.crates.io/crates/cfg-if/1.0.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cfg_if\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.4\"},\"chacha20 0.10.0\":{\"common_attrs\":{\"crate_features\":[\"rng\"],\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"rand_core 0.10.1\",\"target\":\"rand_core\"}],\"selects\":{\"cfg(any(target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\":[{\"id\":\"cpufeatures 0.3.0\",\"target\":\"cpufeatures\"}]}},\"edition\":\"2024\"},\"library_target_name\":\"chacha20\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"chacha20\",\"package_url\":\"https://github.com/RustCrypto/stream-ciphers\",\"repository\":{\"Http\":{\"sha256\":\"6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601\",\"url\":\"https://static.crates.io/crates/chacha20/0.10.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"chacha20\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.10.0\"},\"chrono 0.4.44\":{\"common_attrs\":{\"crate_features\":[\"alloc\"],\"deps\":[{\"id\":\"num-traits 0.2.19\",\"target\":\"num_traits\"}],\"edition\":\"2021\"},\"library_target_name\":\"chrono\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE.txt\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"chrono\",\"package_url\":\"https://github.com/chronotope/chrono\",\"repository\":{\"Http\":{\"sha256\":\"c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0\",\"url\":\"https://static.crates.io/crates/chrono/0.4.44/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"chrono\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.44\"},\"ciborium 0.2.2\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"ciborium-io 0.2.2\",\"target\":\"ciborium_io\"},{\"id\":\"ciborium-ll 0.2.2\",\"target\":\"ciborium_ll\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"}],\"edition\":\"2021\"},\"library_target_name\":\"ciborium\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"ciborium\",\"package_url\":\"https://github.com/enarx/ciborium\",\"repository\":{\"Http\":{\"sha256\":\"42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e\",\"url\":\"https://static.crates.io/crates/ciborium/0.2.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ciborium\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.2\"},\"ciborium-io 0.2.2\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"ciborium_io\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"ciborium-io\",\"package_url\":\"https://github.com/enarx/ciborium\",\"repository\":{\"Http\":{\"sha256\":\"05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757\",\"url\":\"https://static.crates.io/crates/ciborium-io/0.2.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ciborium_io\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.2\"},\"ciborium-ll 0.2.2\":{\"common_attrs\":{\"deps\":[{\"id\":\"ciborium-io 0.2.2\",\"target\":\"ciborium_io\"},{\"id\":\"half 2.7.1\",\"target\":\"half\"}],\"edition\":\"2021\"},\"library_target_name\":\"ciborium_ll\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"ciborium-ll\",\"package_url\":\"https://github.com/enarx/ciborium\",\"repository\":{\"Http\":{\"sha256\":\"57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9\",\"url\":\"https://static.crates.io/crates/ciborium-ll/0.2.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ciborium_ll\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.2\"},\"clang-sys 1.8.1\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"glob 0.3.3\",\"target\":\"glob\"}],\"links\":\"clang\"},\"common_attrs\":{\"crate_features\":[\"clang_10_0\",\"clang_11_0\",\"clang_3_5\",\"clang_3_6\",\"clang_3_7\",\"clang_3_8\",\"clang_3_9\",\"clang_4_0\",\"clang_5_0\",\"clang_6_0\",\"clang_7_0\",\"clang_8_0\",\"clang_9_0\",\"libloading\",\"runtime\"],\"deps\":[{\"id\":\"glob 0.3.3\",\"target\":\"glob\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"},{\"id\":\"libloading 0.8.9\",\"target\":\"libloading\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"clang_sys\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE.txt\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"clang-sys\",\"package_url\":\"https://github.com/KyleMayes/clang-sys\",\"repository\":{\"Http\":{\"sha256\":\"0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4\",\"url\":\"https://static.crates.io/crates/clang-sys/1.8.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"clang_sys\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.8.1\"},\"cmake 0.1.58\":{\"common_attrs\":{\"deps\":[{\"id\":\"cc 1.2.60\",\"target\":\"cc\"}],\"edition\":\"2021\"},\"library_target_name\":\"cmake\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"cmake\",\"package_url\":\"https://github.com/rust-lang/cmake-rs\",\"repository\":{\"Http\":{\"sha256\":\"c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678\",\"url\":\"https://static.crates.io/crates/cmake/0.1.58/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cmake\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.58\"},\"console 0.16.3\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"std\"],\"deps\":{\"common\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"selects\":{\"cfg(windows)\":[{\"id\":\"encode_unicode 1.0.0\",\"target\":\"encode_unicode\"},{\"id\":\"windows-sys 0.61.2\",\"target\":\"windows_sys\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"console\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"console\",\"package_url\":\"https://github.com/console-rs/console\",\"repository\":{\"Http\":{\"sha256\":\"d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87\",\"url\":\"https://static.crates.io/crates/console/0.16.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"console\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.16.3\"},\"const-oid 0.10.2\":{\"common_attrs\":{\"edition\":\"2024\"},\"library_target_name\":\"const_oid\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"const-oid\",\"package_url\":\"https://github.com/RustCrypto/formats\",\"repository\":{\"Http\":{\"sha256\":\"a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c\",\"url\":\"https://static.crates.io/crates/const-oid/0.10.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"const_oid\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.10.2\"},\"constant_time_eq 0.4.2\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"edition\":\"2024\"},\"library_target_name\":\"constant_time_eq\",\"license\":\"CC0-1.0 OR MIT-0 OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"CC0-1.0\",\"MIT-0\"],\"name\":\"constant_time_eq\",\"package_url\":\"https://github.com/cesarb/constant_time_eq\",\"repository\":{\"Http\":{\"sha256\":\"3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b\",\"url\":\"https://static.crates.io/crates/constant_time_eq/0.4.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"constant_time_eq\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.2\"},\"convert_case 0.10.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"unicode-segmentation 1.13.2\",\"target\":\"unicode_segmentation\"}],\"edition\":\"2021\"},\"library_target_name\":\"convert_case\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"convert_case\",\"package_url\":\"https://github.com/rutrum/convert-case\",\"repository\":{\"Http\":{\"sha256\":\"633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9\",\"url\":\"https://static.crates.io/crates/convert_case/0.10.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"convert_case\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.10.0\"},\"cooked-waker 5.0.0\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"cooked_waker\",\"license\":\"MPL-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MPL-2.0\"],\"name\":\"cooked-waker\",\"package_url\":\"https://github.com/Lucretiel/cooked-waker\",\"repository\":{\"Http\":{\"sha256\":\"147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f\",\"url\":\"https://static.crates.io/crates/cooked-waker/5.0.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cooked_waker\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"5.0.0\"},\"corosensei 0.3.3\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"autocfg 1.5.0\",\"target\":\"autocfg\"}]},\"common_attrs\":{\"crate_features\":[\"default\",\"default-stack\",\"libc\",\"unwind\",\"windows-sys\"],\"deps\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"},{\"id\":\"scopeguard 1.2.0\",\"target\":\"scopeguard\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"corosensei\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"corosensei\",\"package_url\":\"https://github.com/Amanieu/corosensei\",\"repository\":{\"Http\":{\"sha256\":\"2c54787b605c7df106ceccf798df23da4f2e09918defad66705d1cedf3bb914f\",\"url\":\"https://static.crates.io/crates/corosensei/0.3.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"corosensei\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.3.3\"},\"cpp_demangle 0.4.5\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"deps\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"}],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"cpp_demangle\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"cpp_demangle\",\"package_url\":\"https://github.com/gimli-rs/cpp_demangle\",\"repository\":{\"Http\":{\"sha256\":\"f2bb79cb74d735044c972aae58ed0aaa9a837e85b01106a54c39e42e97f62253\",\"url\":\"https://static.crates.io/crates/cpp_demangle/0.4.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cpp_demangle\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.4.5\"},\"cpufeatures 0.2.17\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"aarch64-linux-android\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"linux\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(all(target_arch = \\\"aarch64\\\", target_vendor = \\\"apple\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(all(target_arch = \\\"loongarch64\\\", target_os = \\\"linux\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"cpufeatures\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"cpufeatures\",\"package_url\":\"https://github.com/RustCrypto/utils\",\"repository\":{\"Http\":{\"sha256\":\"59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280\",\"url\":\"https://static.crates.io/crates/cpufeatures/0.2.17/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cpufeatures\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.17\"},\"cpufeatures 0.3.0\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"android\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"linux\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(all(target_arch = \\\"aarch64\\\", target_vendor = \\\"apple\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(all(target_arch = \\\"loongarch64\\\", target_os = \\\"linux\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}]}},\"edition\":\"2024\"},\"library_target_name\":\"cpufeatures\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"cpufeatures\",\"package_url\":\"https://github.com/RustCrypto/utils\",\"repository\":{\"Http\":{\"sha256\":\"8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201\",\"url\":\"https://static.crates.io/crates/cpufeatures/0.3.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"cpufeatures\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.0\"},\"crc32fast 1.5.0\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"crc32fast\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"crc32fast\",\"package_url\":\"https://github.com/srijs/rust-crc32fast\",\"repository\":{\"Http\":{\"sha256\":\"9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511\",\"url\":\"https://static.crates.io/crates/crc32fast/1.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crc32fast\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.5.0\"},\"crossbeam-channel 0.5.15\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"crossbeam-utils 0.8.21\",\"target\":\"crossbeam_utils\"}],\"edition\":\"2021\"},\"library_target_name\":\"crossbeam_channel\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"crossbeam-channel\",\"package_url\":\"https://github.com/crossbeam-rs/crossbeam\",\"repository\":{\"Http\":{\"sha256\":\"82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2\",\"url\":\"https://static.crates.io/crates/crossbeam-channel/0.5.15/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crossbeam_channel\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.15\"},\"crossbeam-deque 0.8.6\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"crossbeam-epoch 0.9.18\",\"target\":\"crossbeam_epoch\"},{\"id\":\"crossbeam-utils 0.8.21\",\"target\":\"crossbeam_utils\"}],\"edition\":\"2021\"},\"library_target_name\":\"crossbeam_deque\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"crossbeam-deque\",\"package_url\":\"https://github.com/crossbeam-rs/crossbeam\",\"repository\":{\"Http\":{\"sha256\":\"9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51\",\"url\":\"https://static.crates.io/crates/crossbeam-deque/0.8.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crossbeam_deque\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.6\"},\"crossbeam-epoch 0.9.18\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"std\"],\"deps\":[{\"id\":\"crossbeam-utils 0.8.21\",\"target\":\"crossbeam_utils\"}],\"edition\":\"2021\"},\"library_target_name\":\"crossbeam_epoch\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"crossbeam-epoch\",\"package_url\":\"https://github.com/crossbeam-rs/crossbeam\",\"repository\":{\"Http\":{\"sha256\":\"5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e\",\"url\":\"https://static.crates.io/crates/crossbeam-epoch/0.9.18/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crossbeam_epoch\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.9.18\"},\"crossbeam-queue 0.3.12\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"deps\":[{\"id\":\"crossbeam-utils 0.8.21\",\"target\":\"crossbeam_utils\"}],\"edition\":\"2021\"},\"library_target_name\":\"crossbeam_queue\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"crossbeam-queue\",\"package_url\":\"https://github.com/crossbeam-rs/crossbeam\",\"repository\":{\"Http\":{\"sha256\":\"0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115\",\"url\":\"https://static.crates.io/crates/crossbeam-queue/0.3.12/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crossbeam_queue\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.12\"},\"crossbeam-utils 0.8.21\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"crossbeam_utils\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"crossbeam-utils\",\"package_url\":\"https://github.com/crossbeam-rs/crossbeam\",\"repository\":{\"Http\":{\"sha256\":\"d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28\",\"url\":\"https://static.crates.io/crates/crossbeam-utils/0.8.21/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crossbeam_utils\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.8.21\"},\"crunchy 0.2.4\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"crunchy\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"crunchy\",\"package_url\":\"https://github.com/eira-fransham/crunchy\",\"repository\":{\"Http\":{\"sha256\":\"460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5\",\"url\":\"https://static.crates.io/crates/crunchy/0.2.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crunchy\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.2.4\"},\"crypto-common 0.1.7\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"deps\":[{\"id\":\"generic-array 0.14.7\",\"target\":\"generic_array\"},{\"id\":\"typenum 1.20.0\",\"target\":\"typenum\"}],\"edition\":\"2018\"},\"library_target_name\":\"crypto_common\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"crypto-common\",\"package_url\":\"https://github.com/RustCrypto/traits\",\"repository\":{\"Http\":{\"sha256\":\"78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a\",\"url\":\"https://static.crates.io/crates/crypto-common/0.1.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crypto_common\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.7\"},\"crypto-common 0.2.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"hybrid-array 0.4.10\",\"target\":\"hybrid_array\"}],\"edition\":\"2024\"},\"library_target_name\":\"crypto_common\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"crypto-common\",\"package_url\":\"https://github.com/RustCrypto/traits\",\"repository\":{\"Http\":{\"sha256\":\"77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710\",\"url\":\"https://static.crates.io/crates/crypto-common/0.2.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"crypto_common\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.1\"},\"darling 0.20.11\":{\"common_attrs\":{\"crate_features\":[\"default\",\"suggestions\"],\"deps\":[{\"id\":\"darling_core 0.20.11\",\"target\":\"darling_core\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"darling_macro 0.20.11\",\"target\":\"darling_macro\"}]},\"library_target_name\":\"darling\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"darling\",\"package_url\":\"https://github.com/TedDriggs/darling\",\"repository\":{\"Http\":{\"sha256\":\"fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee\",\"url\":\"https://static.crates.io/crates/darling/0.20.11/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"darling\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.20.11\"},\"darling 0.21.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"darling_core 0.21.3\",\"target\":\"darling_core\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"darling_macro 0.21.3\",\"target\":\"darling_macro\"}]},\"library_target_name\":\"darling\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"darling\",\"package_url\":\"https://github.com/TedDriggs/darling\",\"repository\":{\"Http\":{\"sha256\":\"9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0\",\"url\":\"https://static.crates.io/crates/darling/0.21.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"darling\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.21.3\"},\"darling_core 0.20.11\":{\"common_attrs\":{\"crate_features\":[\"strsim\",\"suggestions\"],\"deps\":[{\"id\":\"fnv 1.0.7\",\"target\":\"fnv\"},{\"id\":\"ident_case 1.0.1\",\"target\":\"ident_case\"},{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"strsim 0.11.1\",\"target\":\"strsim\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"darling_core\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"darling_core\",\"package_url\":\"https://github.com/TedDriggs/darling\",\"repository\":{\"Http\":{\"sha256\":\"0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e\",\"url\":\"https://static.crates.io/crates/darling_core/0.20.11/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"darling_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.20.11\"},\"darling_core 0.21.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"fnv 1.0.7\",\"target\":\"fnv\"},{\"id\":\"ident_case 1.0.1\",\"target\":\"ident_case\"},{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"darling_core\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"darling_core\",\"package_url\":\"https://github.com/TedDriggs/darling\",\"repository\":{\"Http\":{\"sha256\":\"1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4\",\"url\":\"https://static.crates.io/crates/darling_core/0.21.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"darling_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.21.3\"},\"darling_macro 0.20.11\":{\"common_attrs\":{\"deps\":[{\"id\":\"darling_core 0.20.11\",\"target\":\"darling_core\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"darling_macro\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"darling_macro\",\"package_url\":\"https://github.com/TedDriggs/darling\",\"repository\":{\"Http\":{\"sha256\":\"fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead\",\"url\":\"https://static.crates.io/crates/darling_macro/0.20.11/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"darling_macro\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.20.11\"},\"darling_macro 0.21.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"darling_core 0.21.3\",\"target\":\"darling_core\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"darling_macro\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"darling_macro\",\"package_url\":\"https://github.com/TedDriggs/darling\",\"repository\":{\"Http\":{\"sha256\":\"d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81\",\"url\":\"https://static.crates.io/crates/darling_macro/0.21.3/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"darling_macro\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.21.3\"},\"dashmap 6.1.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"crossbeam-utils 0.8.21\",\"target\":\"crossbeam_utils\"},{\"id\":\"hashbrown 0.14.5\",\"target\":\"hashbrown\"},{\"id\":\"lock_api 0.4.14\",\"target\":\"lock_api\"},{\"id\":\"once_cell 1.21.4\",\"target\":\"once_cell\"},{\"id\":\"parking_lot_core 0.9.12\",\"target\":\"parking_lot_core\"}],\"edition\":\"2018\"},\"library_target_name\":\"dashmap\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"dashmap\",\"package_url\":\"https://github.com/xacrimon/dashmap\",\"repository\":{\"Http\":{\"sha256\":\"5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf\",\"url\":\"https://static.crates.io/crates/dashmap/6.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"dashmap\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"6.1.0\"},\"debugid 0.8.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"uuid 1.23.1\",\"target\":\"uuid\"}],\"edition\":\"2018\"},\"library_target_name\":\"debugid\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"debugid\",\"package_url\":\"https://github.com/getsentry/rust-debugid\",\"repository\":{\"Http\":{\"sha256\":\"bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d\",\"url\":\"https://static.crates.io/crates/debugid/0.8.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"debugid\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.0\"},\"defmt 0.3.100\":{\"common_attrs\":{\"deps\":[{\"alias\":\"defmt10\",\"id\":\"defmt 1.0.1\",\"target\":\"defmt\"}],\"edition\":\"2021\"},\"library_target_name\":\"defmt\",\"license\":\"MIT OR Apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"defmt\",\"package_url\":\"https://github.com/knurling-rs/defmt\",\"repository\":{\"Http\":{\"sha256\":\"f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad\",\"url\":\"https://static.crates.io/crates/defmt/0.3.100/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"defmt\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.100\"},\"defmt 1.0.1\":{\"build_script_attrs\":{\"links\":\"defmt\"},\"common_attrs\":{\"deps\":[{\"id\":\"bitflags 1.3.2\",\"target\":\"bitflags\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":[{\"id\":\"defmt-macros 1.0.1\",\"target\":\"defmt_macros\"}]},\"library_target_name\":\"defmt\",\"license\":\"MIT OR Apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"defmt\",\"package_url\":\"https://github.com/knurling-rs/defmt\",\"repository\":{\"Http\":{\"sha256\":\"548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78\",\"url\":\"https://static.crates.io/crates/defmt/1.0.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"defmt\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.1\"},\"defmt-macros 1.0.1\":{\"build_script_attrs\":{},\"common_attrs\":{\"deps\":[{\"id\":\"defmt-parser 1.0.0\",\"target\":\"defmt_parser\"},{\"id\":\"proc-macro-error2 2.0.1\",\"target\":\"proc_macro_error2\"},{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"defmt_macros\",\"license\":\"MIT OR Apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"defmt-macros\",\"package_url\":\"https://github.com/knurling-rs/defmt\",\"repository\":{\"Http\":{\"sha256\":\"3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e\",\"url\":\"https://static.crates.io/crates/defmt-macros/1.0.1/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"defmt_macros\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.1\"},\"defmt-parser 1.0.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"}],\"edition\":\"2021\"},\"library_target_name\":\"defmt_parser\",\"license\":\"MIT OR Apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"defmt-parser\",\"package_url\":\"https://github.com/knurling-rs/defmt\",\"repository\":{\"Http\":{\"sha256\":\"10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e\",\"url\":\"https://static.crates.io/crates/defmt-parser/1.0.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"defmt_parser\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.0\"},\"deranged 0.5.8\":{\"common_attrs\":{\"crate_features\":[\"default\",\"powerfmt\"],\"deps\":[{\"id\":\"powerfmt 0.2.0\",\"target\":\"powerfmt\"}],\"edition\":\"2021\"},\"library_target_name\":\"deranged\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-Apache\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"deranged\",\"package_url\":\"https://github.com/jhpratt/deranged\",\"repository\":{\"Http\":{\"sha256\":\"7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c\",\"url\":\"https://static.crates.io/crates/deranged/0.5.8/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"deranged\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.8\"},\"derive_builder 0.20.2\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2018\",\"proc_macro_deps\":[{\"id\":\"derive_builder_macro 0.20.2\",\"target\":\"derive_builder_macro\"}]},\"library_target_name\":\"derive_builder\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"derive_builder\",\"package_url\":\"https://github.com/colin-kiegel/rust-derive-builder\",\"repository\":{\"Http\":{\"sha256\":\"507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947\",\"url\":\"https://static.crates.io/crates/derive_builder/0.20.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"derive_builder\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.20.2\"},\"derive_builder_core 0.20.2\":{\"common_attrs\":{\"crate_features\":[\"lib_has_std\"],\"deps\":[{\"id\":\"darling 0.20.11\",\"target\":\"darling\"},{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2018\"},\"library_target_name\":\"derive_builder_core\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"derive_builder_core\",\"package_url\":\"https://github.com/colin-kiegel/rust-derive-builder\",\"repository\":{\"Http\":{\"sha256\":\"2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8\",\"url\":\"https://static.crates.io/crates/derive_builder_core/0.20.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"derive_builder_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.20.2\"},\"derive_builder_macro 0.20.2\":{\"common_attrs\":{\"crate_features\":[\"lib_has_std\"],\"deps\":[{\"id\":\"derive_builder_core 0.20.2\",\"target\":\"derive_builder_core\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2018\"},\"library_target_name\":\"derive_builder_macro\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"derive_builder_macro\",\"package_url\":\"https://github.com/colin-kiegel/rust-derive-builder\",\"repository\":{\"Http\":{\"sha256\":\"ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c\",\"url\":\"https://static.crates.io/crates/derive_builder_macro/0.20.2/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"derive_builder_macro\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.20.2\"},\"derive_more 2.1.1\":{\"common_attrs\":{\"crate_features\":[\"debug\",\"default\",\"display\",\"from\",\"std\",\"unwrap\"],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"derive_more-impl 2.1.1\",\"target\":\"derive_more_impl\"}]},\"library_target_name\":\"derive_more\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"derive_more\",\"package_url\":\"https://github.com/JelteF/derive_more\",\"repository\":{\"Http\":{\"sha256\":\"d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134\",\"url\":\"https://static.crates.io/crates/derive_more/2.1.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"derive_more\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.1.1\"},\"derive_more-impl 2.1.1\":{\"common_attrs\":{\"crate_features\":[\"debug\",\"default\",\"display\",\"from\",\"unwrap\"],\"deps\":[{\"id\":\"convert_case 0.10.0\",\"target\":\"convert_case\"},{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"},{\"id\":\"unicode-xid 0.2.6\",\"target\":\"unicode_xid\"}],\"edition\":\"2021\"},\"library_target_name\":\"derive_more_impl\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"derive_more-impl\",\"package_url\":\"https://github.com/JelteF/derive_more\",\"repository\":{\"Http\":{\"sha256\":\"799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb\",\"url\":\"https://static.crates.io/crates/derive_more-impl/2.1.1/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"derive_more_impl\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.1.1\"},\"digest 0.10.7\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"block-buffer\",\"core-api\",\"default\",\"std\"],\"deps\":[{\"id\":\"block-buffer 0.10.4\",\"target\":\"block_buffer\"},{\"id\":\"crypto-common 0.1.7\",\"target\":\"crypto_common\"}],\"edition\":\"2018\"},\"library_target_name\":\"digest\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"digest\",\"package_url\":\"https://github.com/RustCrypto/traits\",\"repository\":{\"Http\":{\"sha256\":\"9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292\",\"url\":\"https://static.crates.io/crates/digest/0.10.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"digest\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.10.7\"},\"digest 0.11.2\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"block-api\",\"default\",\"oid\"],\"deps\":[{\"id\":\"block-buffer 0.12.0\",\"target\":\"block_buffer\"},{\"id\":\"const-oid 0.10.2\",\"target\":\"const_oid\"},{\"alias\":\"common\",\"id\":\"crypto-common 0.2.1\",\"target\":\"crypto_common\"}],\"edition\":\"2024\"},\"library_target_name\":\"digest\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"digest\",\"package_url\":\"https://github.com/RustCrypto/traits\",\"repository\":{\"Http\":{\"sha256\":\"4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c\",\"url\":\"https://static.crates.io/crates/digest/0.11.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"digest\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.11.2\"},\"displaydoc 0.2.5\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"displaydoc\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"displaydoc\",\"package_url\":\"https://github.com/yaahc/displaydoc\",\"repository\":{\"Http\":{\"sha256\":\"97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0\",\"url\":\"https://static.crates.io/crates/displaydoc/0.2.5/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"displaydoc\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.5\"},\"document-features 0.2.12\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"deps\":[{\"id\":\"litrs 1.0.0\",\"target\":\"litrs\"}],\"edition\":\"2018\"},\"library_target_name\":\"document_features\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"document-features\",\"package_url\":\"https://github.com/slint-ui/document-features\",\"repository\":{\"Http\":{\"sha256\":\"d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61\",\"url\":\"https://static.crates.io/crates/document-features/0.2.12/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"document_features\",\"crate_root\":\"lib.rs\"}}],\"version\":\"0.2.12\"},\"dunce 1.0.5\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"dunce\",\"license\":\"CC0-1.0 OR MIT-0 OR Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\",\"CC0-1.0\",\"MIT-0\"],\"name\":\"dunce\",\"package_url\":\"https://gitlab.com/kornelski/dunce\",\"repository\":{\"Http\":{\"sha256\":\"92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813\",\"url\":\"https://static.crates.io/crates/dunce/1.0.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"dunce\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.5\"},\"dyn-clone 1.0.20\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"dyn_clone\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"dyn-clone\",\"package_url\":\"https://github.com/dtolnay/dyn-clone\",\"repository\":{\"Http\":{\"sha256\":\"d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555\",\"url\":\"https://static.crates.io/crates/dyn-clone/1.0.20/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"dyn_clone\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.20\"},\"either 1.15.0\":{\"common_attrs\":{\"crate_features\":[\"std\",\"use_std\"],\"edition\":\"2021\"},\"library_target_name\":\"either\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"either\",\"package_url\":\"https://github.com/rayon-rs/either\",\"repository\":{\"Http\":{\"sha256\":\"48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719\",\"url\":\"https://static.crates.io/crates/either/1.15.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"either\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.15.0\"},\"encode_unicode 1.0.0\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"encode_unicode\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"encode_unicode\",\"package_url\":\"https://github.com/tormol/encode_unicode\",\"repository\":{\"Http\":{\"sha256\":\"34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0\",\"url\":\"https://static.crates.io/crates/encode_unicode/1.0.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"encode_unicode\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.0\"},\"enum-iterator 2.3.0\":{\"common_attrs\":{\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"enum-iterator-derive 1.5.0\",\"target\":\"enum_iterator_derive\"}]},\"library_target_name\":\"enum_iterator\",\"license\":\"0BSD\",\"license_file\":\"LICENSE\",\"license_ids\":[\"0BSD\"],\"name\":\"enum-iterator\",\"package_url\":\"https://github.com/stephaneyfx/enum-iterator.git\",\"repository\":{\"Http\":{\"sha256\":\"a4549325971814bda7a44061bf3fe7e487d447cba01e4220a4b454d630d7a016\",\"url\":\"https://static.crates.io/crates/enum-iterator/2.3.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"enum_iterator\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.3.0\"},\"enum-iterator-derive 1.5.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"enum_iterator_derive\",\"license\":\"0BSD\",\"license_file\":\"LICENSE\",\"license_ids\":[\"0BSD\"],\"name\":\"enum-iterator-derive\",\"package_url\":\"https://github.com/stephaneyfx/enum-iterator.git\",\"repository\":{\"Http\":{\"sha256\":\"685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842\",\"url\":\"https://static.crates.io/crates/enum-iterator-derive/1.5.0/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"enum_iterator_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.5.0\"},\"enumset 1.1.10\":{\"common_attrs\":{\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"enumset_derive 0.14.0\",\"target\":\"enumset_derive\"}]},\"library_target_name\":\"enumset\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"enumset\",\"package_url\":\"https://github.com/Lymia/enumset\",\"repository\":{\"Http\":{\"sha256\":\"25b07a8dfbbbfc0064c0a6bdf9edcf966de6b1c33ce344bdeca3b41615452634\",\"url\":\"https://static.crates.io/crates/enumset/1.1.10/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"enumset\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.10\"},\"enumset_derive 0.14.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"darling 0.21.3\",\"target\":\"darling\"},{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"enumset_derive\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"enumset_derive\",\"package_url\":\"https://github.com/Lymia/enumset\",\"repository\":{\"Http\":{\"sha256\":\"f43e744e4ea338060faee68ed933e46e722fb7f3617e722a5772d7e856d8b3ce\",\"url\":\"https://static.crates.io/crates/enumset_derive/0.14.0/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"enumset_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.14.0\"},\"equivalent 1.0.2\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"equivalent\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"equivalent\",\"package_url\":\"https://github.com/indexmap-rs/equivalent\",\"repository\":{\"Http\":{\"sha256\":\"877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f\",\"url\":\"https://static.crates.io/crates/equivalent/1.0.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"equivalent\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.2\"},\"errno 0.3.14\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"deps\":{\"common\":[],\"selects\":{\"cfg(target_os = \\\"hermit\\\")\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(target_os = \\\"wasi\\\")\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(unix)\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(windows)\":[{\"id\":\"windows-sys 0.61.2\",\"target\":\"windows_sys\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"errno\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"errno\",\"package_url\":\"https://github.com/lambda-fairy/rust-errno\",\"repository\":{\"Http\":{\"sha256\":\"39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb\",\"url\":\"https://static.crates.io/crates/errno/0.3.14/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"errno\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.14\"},\"fastrand 2.4.1\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"fastrand\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"fastrand\",\"package_url\":\"https://github.com/smol-rs/fastrand\",\"repository\":{\"Http\":{\"sha256\":\"9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6\",\"url\":\"https://static.crates.io/crates/fastrand/2.4.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"fastrand\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.4.1\"},\"filetime 0.2.27\":{\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"}],\"selects\":{\"cfg(target_os = \\\"redox\\\")\":[{\"id\":\"libredox 0.1.16\",\"target\":\"libredox\"}],\"cfg(unix)\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"filetime\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"filetime\",\"package_url\":\"https://github.com/alexcrichton/filetime\",\"repository\":{\"Http\":{\"sha256\":\"f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db\",\"url\":\"https://static.crates.io/crates/filetime/0.2.27/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"filetime\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.27\"},\"find-msvc-tools 0.1.9\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"find_msvc_tools\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"find-msvc-tools\",\"package_url\":\"https://github.com/rust-lang/cc-rs\",\"repository\":{\"Http\":{\"sha256\":\"5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582\",\"url\":\"https://static.crates.io/crates/find-msvc-tools/0.1.9/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"find_msvc_tools\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.9\"},\"fixedbitset 0.5.7\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"fixedbitset\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"fixedbitset\",\"package_url\":\"https://github.com/petgraph/fixedbitset\",\"repository\":{\"Http\":{\"sha256\":\"1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99\",\"url\":\"https://static.crates.io/crates/fixedbitset/0.5.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"fixedbitset\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.7\"},\"flate2 1.1.9\":{\"common_attrs\":{\"crate_features\":[\"any_impl\",\"default\",\"miniz_oxide\",\"rust_backend\"],\"deps\":[{\"id\":\"crc32fast 1.5.0\",\"target\":\"crc32fast\"},{\"id\":\"miniz_oxide 0.8.9\",\"target\":\"miniz_oxide\"}],\"edition\":\"2018\"},\"library_target_name\":\"flate2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"flate2\",\"package_url\":\"https://github.com/rust-lang/flate2-rs\",\"repository\":{\"Http\":{\"sha256\":\"843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c\",\"url\":\"https://static.crates.io/crates/flate2/1.1.9/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"flate2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.9\"},\"fnv 1.0.7\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2015\"},\"library_target_name\":\"fnv\",\"license\":\"Apache-2.0 / MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"fnv\",\"package_url\":\"https://github.com/servo/rust-fnv\",\"repository\":{\"Http\":{\"sha256\":\"3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1\",\"url\":\"https://static.crates.io/crates/fnv/1.0.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"fnv\",\"crate_root\":\"lib.rs\"}}],\"version\":\"1.0.7\"},\"foldhash 0.1.5\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"foldhash\",\"license\":\"Zlib\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Zlib\"],\"name\":\"foldhash\",\"package_url\":\"https://github.com/orlp/foldhash\",\"repository\":{\"Http\":{\"sha256\":\"d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2\",\"url\":\"https://static.crates.io/crates/foldhash/0.1.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"foldhash\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.5\"},\"foldhash 0.2.0\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"foldhash\",\"license\":\"Zlib\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Zlib\"],\"name\":\"foldhash\",\"package_url\":\"https://github.com/orlp/foldhash\",\"repository\":{\"Http\":{\"sha256\":\"77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb\",\"url\":\"https://static.crates.io/crates/foldhash/0.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"foldhash\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.0\"},\"form_urlencoded 1.2.2\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"std\"],\"deps\":[{\"id\":\"percent-encoding 2.3.2\",\"target\":\"percent_encoding\"}],\"edition\":\"2018\"},\"library_target_name\":\"form_urlencoded\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"form_urlencoded\",\"package_url\":\"https://github.com/servo/rust-url\",\"repository\":{\"Http\":{\"sha256\":\"cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf\",\"url\":\"https://static.crates.io/crates/form_urlencoded/1.2.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"form_urlencoded\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.2\"},\"futures 0.3.32\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"async-await\",\"default\",\"executor\",\"futures-executor\",\"std\"],\"deps\":[{\"id\":\"futures-channel 0.3.32\",\"target\":\"futures_channel\"},{\"id\":\"futures-core 0.3.32\",\"target\":\"futures_core\"},{\"id\":\"futures-executor 0.3.32\",\"target\":\"futures_executor\"},{\"id\":\"futures-io 0.3.32\",\"target\":\"futures_io\"},{\"id\":\"futures-sink 0.3.32\",\"target\":\"futures_sink\"},{\"id\":\"futures-task 0.3.32\",\"target\":\"futures_task\"},{\"id\":\"futures-util 0.3.32\",\"target\":\"futures_util\"}],\"edition\":\"2018\"},\"library_target_name\":\"futures\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d\",\"url\":\"https://static.crates.io/crates/futures/0.3.32/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.32\"},\"futures-channel 0.3.32\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"futures-sink\",\"sink\",\"std\"],\"deps\":[{\"id\":\"futures-core 0.3.32\",\"target\":\"futures_core\"},{\"id\":\"futures-sink 0.3.32\",\"target\":\"futures_sink\"}],\"edition\":\"2018\"},\"library_target_name\":\"futures_channel\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-channel\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d\",\"url\":\"https://static.crates.io/crates/futures-channel/0.3.32/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures_channel\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.32\"},\"futures-core 0.3.32\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"futures_core\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-core\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d\",\"url\":\"https://static.crates.io/crates/futures-core/0.3.32/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.32\"},\"futures-executor 0.3.32\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"futures-core 0.3.32\",\"target\":\"futures_core\"},{\"id\":\"futures-task 0.3.32\",\"target\":\"futures_task\"},{\"id\":\"futures-util 0.3.32\",\"target\":\"futures_util\"}],\"edition\":\"2018\"},\"library_target_name\":\"futures_executor\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-executor\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d\",\"url\":\"https://static.crates.io/crates/futures-executor/0.3.32/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures_executor\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.32\"},\"futures-io 0.3.32\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"futures_io\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-io\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718\",\"url\":\"https://static.crates.io/crates/futures-io/0.3.32/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures_io\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.32\"},\"futures-macro 0.3.32\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2018\"},\"library_target_name\":\"futures_macro\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-macro\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b\",\"url\":\"https://static.crates.io/crates/futures-macro/0.3.32/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"futures_macro\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.32\"},\"futures-sink 0.3.32\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"futures_sink\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-sink\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893\",\"url\":\"https://static.crates.io/crates/futures-sink/0.3.32/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures_sink\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.32\"},\"futures-task 0.3.32\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"futures_task\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-task\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393\",\"url\":\"https://static.crates.io/crates/futures-task/0.3.32/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures_task\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.32\"},\"futures-util 0.3.32\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"async-await\",\"async-await-macro\",\"channel\",\"default\",\"futures-channel\",\"futures-io\",\"futures-macro\",\"futures-sink\",\"io\",\"memchr\",\"sink\",\"slab\",\"std\"],\"deps\":[{\"id\":\"futures-channel 0.3.32\",\"target\":\"futures_channel\"},{\"id\":\"futures-core 0.3.32\",\"target\":\"futures_core\"},{\"id\":\"futures-io 0.3.32\",\"target\":\"futures_io\"},{\"id\":\"futures-sink 0.3.32\",\"target\":\"futures_sink\"},{\"id\":\"futures-task 0.3.32\",\"target\":\"futures_task\"},{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"},{\"id\":\"pin-project-lite 0.2.17\",\"target\":\"pin_project_lite\"},{\"id\":\"slab 0.4.12\",\"target\":\"slab\"}],\"edition\":\"2018\",\"proc_macro_deps\":[{\"id\":\"futures-macro 0.3.32\",\"target\":\"futures_macro\"}]},\"library_target_name\":\"futures_util\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"futures-util\",\"package_url\":\"https://github.com/rust-lang/futures-rs\",\"repository\":{\"Http\":{\"sha256\":\"389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6\",\"url\":\"https://static.crates.io/crates/futures-util/0.3.32/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"futures_util\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.32\"},\"generic-array 0.14.7\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"version_check 0.9.5\",\"target\":\"version_check\"}]},\"common_attrs\":{\"crate_features\":[\"more_lengths\"],\"deps\":[{\"id\":\"typenum 1.20.0\",\"target\":\"typenum\"}],\"edition\":\"2015\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"generic_array\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"generic-array\",\"package_url\":\"https://github.com/fizyk20/generic-array.git\",\"repository\":{\"Http\":{\"sha256\":\"85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a\",\"url\":\"https://static.crates.io/crates/generic-array/0.14.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"generic_array\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.14.7\"},\"getrandom 0.3.4\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"std\"],\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"}],\"selects\":{\"cfg(all(any(target_os = \\\"linux\\\", target_os = \\\"android\\\"), not(any(all(target_os = \\\"linux\\\", target_env = \\\"\\\"), getrandom_backend = \\\"custom\\\", getrandom_backend = \\\"linux_raw\\\", getrandom_backend = \\\"rdrand\\\", getrandom_backend = \\\"rndr\\\"))))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"wasi\\\", target_env = \\\"p2\\\"))\":[{\"id\":\"wasip2 1.0.3+wasi-0.2.9\",\"target\":\"wasip2\"}],\"cfg(all(target_os = \\\"uefi\\\", getrandom_backend = \\\"efi_rng\\\"))\":[{\"id\":\"r-efi 5.3.0\",\"target\":\"r_efi\"}],\"cfg(any(target_os = \\\"dragonfly\\\", target_os = \\\"freebsd\\\", target_os = \\\"hurd\\\", target_os = \\\"illumos\\\", target_os = \\\"cygwin\\\", all(target_os = \\\"horizon\\\", target_arch = \\\"arm\\\")))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(any(target_os = \\\"haiku\\\", target_os = \\\"redox\\\", target_os = \\\"nto\\\", target_os = \\\"aix\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(any(target_os = \\\"ios\\\", target_os = \\\"visionos\\\", target_os = \\\"watchos\\\", target_os = \\\"tvos\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"openbsd\\\", target_os = \\\"vita\\\", target_os = \\\"emscripten\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(target_os = \\\"netbsd\\\")\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(target_os = \\\"solaris\\\")\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(target_os = \\\"vxworks\\\")\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}]}},\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"getrandom\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"getrandom\",\"package_url\":\"https://github.com/rust-random/getrandom\",\"repository\":{\"Http\":{\"sha256\":\"899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd\",\"url\":\"https://static.crates.io/crates/getrandom/0.3.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"getrandom\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.3.4\"},\"getrandom 0.4.2\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"std\",\"sys_rng\",\"wasm_js\"],\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"rand_core 0.10.1\",\"target\":\"rand_core\"}],\"selects\":{\"cfg(all(any(target_os = \\\"linux\\\", target_os = \\\"android\\\"), not(any(all(target_os = \\\"linux\\\", target_env = \\\"\\\"), getrandom_backend = \\\"custom\\\", getrandom_backend = \\\"linux_raw\\\", getrandom_backend = \\\"rdrand\\\", getrandom_backend = \\\"rndr\\\"))))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"wasi\\\", target_env = \\\"p2\\\"))\":[{\"id\":\"wasip2 1.0.3+wasi-0.2.9\",\"target\":\"wasip2\"}],\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"wasi\\\", target_env = \\\"p3\\\"))\":[{\"id\":\"wasip3 0.4.0+wasi-0.3.0-rc-2026-01-06\",\"target\":\"wasip3\"}],\"cfg(all(target_os = \\\"uefi\\\", getrandom_backend = \\\"efi_rng\\\"))\":[{\"id\":\"r-efi 6.0.0\",\"target\":\"r_efi\"}],\"cfg(any(target_os = \\\"dragonfly\\\", target_os = \\\"freebsd\\\", target_os = \\\"hurd\\\", target_os = \\\"illumos\\\", target_os = \\\"cygwin\\\", all(target_os = \\\"horizon\\\", target_arch = \\\"arm\\\")))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(any(target_os = \\\"haiku\\\", target_os = \\\"redox\\\", target_os = \\\"nto\\\", target_os = \\\"aix\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(any(target_os = \\\"ios\\\", target_os = \\\"visionos\\\", target_os = \\\"watchos\\\", target_os = \\\"tvos\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"openbsd\\\", target_os = \\\"vita\\\", target_os = \\\"emscripten\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(target_os = \\\"netbsd\\\")\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(target_os = \\\"solaris\\\")\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(target_os = \\\"vxworks\\\")\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}]}},\"edition\":\"2024\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"getrandom\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"getrandom\",\"package_url\":\"https://github.com/rust-random/getrandom\",\"repository\":{\"Http\":{\"sha256\":\"0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555\",\"url\":\"https://static.crates.io/crates/getrandom/0.4.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"getrandom\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.4.2\"},\"gimli 0.32.3\":{\"common_attrs\":{\"crate_features\":[\"read\",\"read-core\"],\"edition\":\"2018\"},\"library_target_name\":\"gimli\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"gimli\",\"package_url\":\"https://github.com/gimli-rs/gimli\",\"repository\":{\"Http\":{\"sha256\":\"e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7\",\"url\":\"https://static.crates.io/crates/gimli/0.32.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"gimli\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.32.3\"},\"gimli 0.33.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"endian-reader\",\"read\",\"read-all\",\"read-core\",\"std\",\"write\"],\"deps\":[{\"id\":\"fnv 1.0.7\",\"target\":\"fnv\"},{\"id\":\"hashbrown 0.16.1\",\"target\":\"hashbrown\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"stable_deref_trait 1.2.1\",\"target\":\"stable_deref_trait\"}],\"edition\":\"2024\"},\"library_target_name\":\"gimli\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"gimli\",\"package_url\":\"https://github.com/gimli-rs/gimli\",\"repository\":{\"Http\":{\"sha256\":\"0bf7f043f89559805f8c7cacc432749b2fa0d0a0a9ee46ce47164ed5ba7f126c\",\"url\":\"https://static.crates.io/crates/gimli/0.33.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"gimli\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.33.0\"},\"glob 0.3.3\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"glob\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"glob\",\"package_url\":\"https://github.com/rust-lang/glob\",\"repository\":{\"Http\":{\"sha256\":\"0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280\",\"url\":\"https://static.crates.io/crates/glob/0.3.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"glob\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.3\"},\"globset 0.4.18\":{\"common_attrs\":{\"crate_features\":[\"default\",\"log\"],\"deps\":[{\"id\":\"aho-corasick 1.1.4\",\"target\":\"aho_corasick\"},{\"id\":\"bstr 1.12.1\",\"target\":\"bstr\"},{\"id\":\"log 0.4.29\",\"target\":\"log\"},{\"id\":\"regex-automata 0.4.14\",\"target\":\"regex_automata\"},{\"id\":\"regex-syntax 0.8.10\",\"target\":\"regex_syntax\"}],\"edition\":\"2024\"},\"library_target_name\":\"globset\",\"license\":\"Unlicense OR MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"globset\",\"package_url\":\"https://github.com/BurntSushi/ripgrep/tree/master/crates/globset\",\"repository\":{\"Http\":{\"sha256\":\"52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3\",\"url\":\"https://static.crates.io/crates/globset/0.4.18/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"globset\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.18\"},\"half 2.7.1\":{\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"zerocopy 0.8.48\",\"target\":\"zerocopy\"}],\"selects\":{\"cfg(target_arch = \\\"spirv\\\")\":[{\"id\":\"crunchy 0.2.4\",\"target\":\"crunchy\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"half\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"half\",\"package_url\":\"https://github.com/VoidStarKat/half-rs\",\"repository\":{\"Http\":{\"sha256\":\"6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b\",\"url\":\"https://static.crates.io/crates/half/2.7.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"half\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.7.1\"},\"hash32 0.3.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"byteorder 1.5.0\",\"target\":\"byteorder\"}],\"edition\":\"2015\"},\"library_target_name\":\"hash32\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"hash32\",\"package_url\":\"https://github.com/japaric/hash32\",\"repository\":{\"Http\":{\"sha256\":\"47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606\",\"url\":\"https://static.crates.io/crates/hash32/0.3.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hash32\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.1\"},\"hashbrown 0.14.5\":{\"common_attrs\":{\"crate_features\":[\"raw\"],\"edition\":\"2021\"},\"library_target_name\":\"hashbrown\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"hashbrown\",\"package_url\":\"https://github.com/rust-lang/hashbrown\",\"repository\":{\"Http\":{\"sha256\":\"e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1\",\"url\":\"https://static.crates.io/crates/hashbrown/0.14.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hashbrown\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.14.5\"},\"hashbrown 0.15.5\":{\"common_attrs\":{\"crate_features\":[\"default-hasher\",\"inline-more\"],\"deps\":[{\"id\":\"foldhash 0.1.5\",\"target\":\"foldhash\"}],\"edition\":\"2021\"},\"library_target_name\":\"hashbrown\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"hashbrown\",\"package_url\":\"https://github.com/rust-lang/hashbrown\",\"repository\":{\"Http\":{\"sha256\":\"9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1\",\"url\":\"https://static.crates.io/crates/hashbrown/0.15.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hashbrown\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.15.5\"},\"hashbrown 0.16.1\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"hashbrown\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"hashbrown\",\"package_url\":\"https://github.com/rust-lang/hashbrown\",\"repository\":{\"Http\":{\"sha256\":\"841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100\",\"url\":\"https://static.crates.io/crates/hashbrown/0.16.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hashbrown\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.16.1\"},\"hashbrown 0.17.0\":{\"common_attrs\":{\"crate_features\":[\"default-hasher\"],\"deps\":[{\"id\":\"foldhash 0.2.0\",\"target\":\"foldhash\"}],\"edition\":\"2024\"},\"library_target_name\":\"hashbrown\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"hashbrown\",\"package_url\":\"https://github.com/rust-lang/hashbrown\",\"repository\":{\"Http\":{\"sha256\":\"4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51\",\"url\":\"https://static.crates.io/crates/hashbrown/0.17.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hashbrown\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.17.0\"},\"heapless 0.9.2\":{\"build_script_attrs\":{},\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"hash32 0.3.1\",\"target\":\"hash32\"}],\"selects\":{\"cfg(any(target_arch = \\\"arm\\\", target_pointer_width = \\\"32\\\", target_pointer_width = \\\"64\\\"))\":[{\"id\":\"stable_deref_trait 1.2.1\",\"target\":\"stable_deref_trait\"}]}},\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"heapless\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"heapless\",\"package_url\":\"https://github.com/rust-embedded/heapless\",\"repository\":{\"Http\":{\"sha256\":\"2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed\",\"url\":\"https://static.crates.io/crates/heapless/0.9.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"heapless\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.9.2\"},\"heck 0.3.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"unicode-segmentation 1.13.2\",\"target\":\"unicode_segmentation\"}],\"edition\":\"2018\"},\"library_target_name\":\"heck\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"heck\",\"package_url\":\"https://github.com/withoutboats/heck\",\"repository\":{\"Http\":{\"sha256\":\"6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c\",\"url\":\"https://static.crates.io/crates/heck/0.3.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"heck\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.3\"},\"heck 0.5.0\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"heck\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"heck\",\"package_url\":\"https://github.com/withoutboats/heck\",\"repository\":{\"Http\":{\"sha256\":\"2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea\",\"url\":\"https://static.crates.io/crates/heck/0.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"heck\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.0\"},\"hermit-abi 0.5.2\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"hermit_abi\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"hermit-abi\",\"package_url\":\"https://github.com/hermit-os/hermit-rs\",\"repository\":{\"Http\":{\"sha256\":\"fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c\",\"url\":\"https://static.crates.io/crates/hermit-abi/0.5.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hermit_abi\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.2\"},\"hex 0.4.3\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"hex\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"hex\",\"package_url\":\"https://github.com/KokaKiwi/rust-hex\",\"repository\":{\"Http\":{\"sha256\":\"7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70\",\"url\":\"https://static.crates.io/crates/hex/0.4.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hex\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.3\"},\"http 1.4.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"itoa 1.0.18\",\"target\":\"itoa\"}],\"edition\":\"2021\"},\"library_target_name\":\"http\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"http\",\"package_url\":\"https://github.com/hyperium/http\",\"repository\":{\"Http\":{\"sha256\":\"e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a\",\"url\":\"https://static.crates.io/crates/http/1.4.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"http\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.4.0\"},\"hybrid-array 0.4.10\":{\"common_attrs\":{\"deps\":[{\"id\":\"typenum 1.20.0\",\"target\":\"typenum\"}],\"edition\":\"2024\"},\"library_target_name\":\"hybrid_array\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"hybrid-array\",\"package_url\":\"https://github.com/RustCrypto/hybrid-array\",\"repository\":{\"Http\":{\"sha256\":\"3944cf8cf766b40e2a1a333ee5e9b563f854d5fa49d6a8ca2764e97c6eddb214\",\"url\":\"https://static.crates.io/crates/hybrid-array/0.4.10/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"hybrid_array\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.10\"},\"icu_collections 2.2.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"potential_utf 0.1.5\",\"target\":\"potential_utf\"},{\"id\":\"utf8_iter 1.0.4\",\"target\":\"utf8_iter\"},{\"id\":\"yoke 0.8.2\",\"target\":\"yoke\"},{\"id\":\"zerofrom 0.1.7\",\"target\":\"zerofrom\"},{\"id\":\"zerovec 0.11.6\",\"target\":\"zerovec\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"displaydoc 0.2.5\",\"target\":\"displaydoc\"}]},\"library_target_name\":\"icu_collections\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_collections\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c\",\"url\":\"https://static.crates.io/crates/icu_collections/2.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"icu_collections\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.2.0\"},\"icu_locale_core 2.2.0\":{\"common_attrs\":{\"crate_features\":[\"zerovec\"],\"deps\":[{\"id\":\"litemap 0.8.2\",\"target\":\"litemap\"},{\"id\":\"tinystr 0.8.3\",\"target\":\"tinystr\"},{\"id\":\"writeable 0.6.3\",\"target\":\"writeable\"},{\"id\":\"zerovec 0.11.6\",\"target\":\"zerovec\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"displaydoc 0.2.5\",\"target\":\"displaydoc\"}]},\"library_target_name\":\"icu_locale_core\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_locale_core\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29\",\"url\":\"https://static.crates.io/crates/icu_locale_core/2.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"icu_locale_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.2.0\"},\"icu_normalizer 2.2.0\":{\"common_attrs\":{\"crate_features\":[\"compiled_data\"],\"deps\":[{\"id\":\"icu_collections 2.2.0\",\"target\":\"icu_collections\"},{\"id\":\"icu_normalizer_data 2.2.0\",\"target\":\"icu_normalizer_data\"},{\"id\":\"icu_provider 2.2.0\",\"target\":\"icu_provider\"},{\"id\":\"smallvec 1.15.1\",\"target\":\"smallvec\"},{\"id\":\"zerovec 0.11.6\",\"target\":\"zerovec\"}],\"edition\":\"2021\"},\"library_target_name\":\"icu_normalizer\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_normalizer\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4\",\"url\":\"https://static.crates.io/crates/icu_normalizer/2.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"icu_normalizer\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.2.0\"},\"icu_normalizer_data 2.2.0\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"icu_normalizer_data\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_normalizer_data\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38\",\"url\":\"https://static.crates.io/crates/icu_normalizer_data/2.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"icu_normalizer_data\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"2.2.0\"},\"icu_properties 2.2.0\":{\"common_attrs\":{\"crate_features\":[\"compiled_data\"],\"deps\":[{\"id\":\"icu_collections 2.2.0\",\"target\":\"icu_collections\"},{\"id\":\"icu_locale_core 2.2.0\",\"target\":\"icu_locale_core\"},{\"id\":\"icu_properties_data 2.2.0\",\"target\":\"icu_properties_data\"},{\"id\":\"icu_provider 2.2.0\",\"target\":\"icu_provider\"},{\"id\":\"zerotrie 0.2.4\",\"target\":\"zerotrie\"},{\"id\":\"zerovec 0.11.6\",\"target\":\"zerovec\"}],\"edition\":\"2021\"},\"library_target_name\":\"icu_properties\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_properties\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de\",\"url\":\"https://static.crates.io/crates/icu_properties/2.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"icu_properties\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.2.0\"},\"icu_properties_data 2.2.0\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"icu_properties_data\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_properties_data\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14\",\"url\":\"https://static.crates.io/crates/icu_properties_data/2.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"icu_properties_data\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"2.2.0\"},\"icu_provider 2.2.0\":{\"common_attrs\":{\"crate_features\":[\"baked\"],\"deps\":[{\"id\":\"icu_locale_core 2.2.0\",\"target\":\"icu_locale_core\"},{\"id\":\"writeable 0.6.3\",\"target\":\"writeable\"},{\"id\":\"yoke 0.8.2\",\"target\":\"yoke\"},{\"id\":\"zerofrom 0.1.7\",\"target\":\"zerofrom\"},{\"id\":\"zerotrie 0.2.4\",\"target\":\"zerotrie\"},{\"id\":\"zerovec 0.11.6\",\"target\":\"zerovec\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"displaydoc 0.2.5\",\"target\":\"displaydoc\"}]},\"library_target_name\":\"icu_provider\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"icu_provider\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421\",\"url\":\"https://static.crates.io/crates/icu_provider/2.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"icu_provider\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.2.0\"},\"id-arena 2.3.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"id_arena\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"id-arena\",\"package_url\":\"https://github.com/fitzgen/id-arena\",\"repository\":{\"Http\":{\"sha256\":\"3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954\",\"url\":\"https://static.crates.io/crates/id-arena/2.3.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"id_arena\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.3.0\"},\"ident_case 1.0.1\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"ident_case\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"ident_case\",\"package_url\":\"https://github.com/TedDriggs/ident_case\",\"repository\":{\"Http\":{\"sha256\":\"b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39\",\"url\":\"https://static.crates.io/crates/ident_case/1.0.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ident_case\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.1\"},\"idna 1.1.0\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"compiled_data\",\"std\"],\"deps\":[{\"id\":\"idna_adapter 1.2.1\",\"target\":\"idna_adapter\"},{\"id\":\"smallvec 1.15.1\",\"target\":\"smallvec\"},{\"id\":\"utf8_iter 1.0.4\",\"target\":\"utf8_iter\"}],\"edition\":\"2018\"},\"library_target_name\":\"idna\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"idna\",\"package_url\":\"https://github.com/servo/rust-url/\",\"repository\":{\"Http\":{\"sha256\":\"3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de\",\"url\":\"https://static.crates.io/crates/idna/1.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"idna\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.0\"},\"idna_adapter 1.2.1\":{\"common_attrs\":{\"crate_features\":[\"compiled_data\"],\"deps\":[{\"id\":\"icu_normalizer 2.2.0\",\"target\":\"icu_normalizer\"},{\"id\":\"icu_properties 2.2.0\",\"target\":\"icu_properties\"}],\"edition\":\"2021\"},\"library_target_name\":\"idna_adapter\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"idna_adapter\",\"package_url\":\"https://github.com/hsivonen/idna_adapter\",\"repository\":{\"Http\":{\"sha256\":\"3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344\",\"url\":\"https://static.crates.io/crates/idna_adapter/1.2.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"idna_adapter\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.1\"},\"ignore 0.4.25\":{\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"crossbeam-deque 0.8.6\",\"target\":\"crossbeam_deque\"},{\"id\":\"globset 0.4.18\",\"target\":\"globset\"},{\"id\":\"log 0.4.29\",\"target\":\"log\"},{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"},{\"id\":\"regex-automata 0.4.14\",\"target\":\"regex_automata\"},{\"id\":\"same-file 1.0.6\",\"target\":\"same_file\"},{\"id\":\"walkdir 2.5.0\",\"target\":\"walkdir\"}],\"selects\":{\"cfg(windows)\":[{\"id\":\"winapi-util 0.1.11\",\"target\":\"winapi_util\"}]}},\"edition\":\"2024\"},\"library_target_name\":\"ignore\",\"license\":\"Unlicense OR MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"ignore\",\"package_url\":\"https://github.com/BurntSushi/ripgrep/tree/master/crates/ignore\",\"repository\":{\"Http\":{\"sha256\":\"d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a\",\"url\":\"https://static.crates.io/crates/ignore/0.4.25/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ignore\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.25\"},\"indexmap 2.14.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"serde\",\"std\"],\"deps\":[{\"id\":\"equivalent 1.0.2\",\"target\":\"equivalent\"},{\"id\":\"hashbrown 0.17.0\",\"target\":\"hashbrown\"},{\"id\":\"serde_core 1.0.228\",\"target\":\"serde_core\"}],\"edition\":\"2024\"},\"library_target_name\":\"indexmap\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"indexmap\",\"package_url\":\"https://github.com/indexmap-rs/indexmap\",\"repository\":{\"Http\":{\"sha256\":\"d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9\",\"url\":\"https://static.crates.io/crates/indexmap/2.14.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"indexmap\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.14.0\"},\"inkwell 0.9.0\":{\"build_script_attrs\":{\"link_deps\":[{\"alias\":\"llvm_sys_221\",\"id\":\"llvm-sys 221.0.1\",\"target\":\"llvm_sys\"}]},\"common_attrs\":{\"crate_features\":[\"llvm-sys-221\",\"llvm22-1\",\"llvm22-1-prefer-static\",\"target-aarch64\",\"target-loongarch\",\"target-riscv\",\"target-x86\"],\"deps\":[{\"id\":\"bitflags 2.11.1\",\"target\":\"bitflags\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"},{\"alias\":\"llvm_sys_221\",\"id\":\"llvm-sys 221.0.1\",\"target\":\"llvm_sys\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"}],\"edition\":\"2024\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":[{\"id\":\"inkwell_internals 0.14.0\",\"target\":\"inkwell_internals\"}]},\"library_target_name\":\"inkwell\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"inkwell\",\"package_url\":\"https://github.com/TheDan64/inkwell\",\"repository\":{\"Http\":{\"sha256\":\"7decbc9dfa45a4a827a6ff7b822c113b1285678a937e84213417d4ca8a095782\",\"url\":\"https://static.crates.io/crates/inkwell/0.9.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"inkwell\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.9.0\"},\"inkwell_internals 0.14.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2024\"},\"library_target_name\":\"inkwell_internals\",\"license\":\"Apache-2.0\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"inkwell_internals\",\"package_url\":\"https://github.com/TheDan64/inkwell\",\"repository\":{\"Http\":{\"sha256\":\"6cfe97ee860815a90ed17e09639513269e39420a7440f3f4c996f238c514cf8d\",\"url\":\"https://static.crates.io/crates/inkwell_internals/0.14.0/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"inkwell_internals\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.14.0\"},\"insta 1.47.2\":{\"common_attrs\":{\"crate_features\":[\"colors\",\"console\",\"default\",\"filters\",\"regex\",\"serde\",\"yaml\"],\"deps\":[{\"id\":\"console 0.16.3\",\"target\":\"console\"},{\"id\":\"once_cell 1.21.4\",\"target\":\"once_cell\"},{\"id\":\"regex 1.12.3\",\"target\":\"regex\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"similar 2.7.0\",\"target\":\"similar\"},{\"id\":\"tempfile 3.27.0\",\"target\":\"tempfile\"}],\"edition\":\"2021\"},\"library_target_name\":\"insta\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"insta\",\"package_url\":\"https://github.com/mitsuhiko/insta\",\"repository\":{\"Http\":{\"sha256\":\"7b4a6248eb93a4401ed2f37dfe8ea592d3cf05b7cf4f8efa867b6895af7e094e\",\"url\":\"https://static.crates.io/crates/insta/1.47.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"insta\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.47.2\"},\"ipnet 2.12.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"ipnet\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"ipnet\",\"package_url\":\"https://github.com/krisprice/ipnet\",\"repository\":{\"Http\":{\"sha256\":\"d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2\",\"url\":\"https://static.crates.io/crates/ipnet/2.12.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ipnet\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.12.0\"},\"iprange 0.6.7\":{\"common_attrs\":{\"deps\":[{\"id\":\"ipnet 2.12.0\",\"target\":\"ipnet\"}],\"edition\":\"2015\"},\"library_target_name\":\"iprange\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"iprange\",\"package_url\":\"https://github.com/sticnarf/iprange-rs\",\"repository\":{\"Http\":{\"sha256\":\"37209be0ad225457e63814401415e748e2453a5297f9b637338f5fb8afa4ec00\",\"url\":\"https://static.crates.io/crates/iprange/0.6.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"iprange\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.7\"},\"itertools 0.13.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"either 1.15.0\",\"target\":\"either\"}],\"edition\":\"2018\"},\"library_target_name\":\"itertools\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"itertools\",\"package_url\":\"https://github.com/rust-itertools/itertools\",\"repository\":{\"Http\":{\"sha256\":\"413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186\",\"url\":\"https://static.crates.io/crates/itertools/0.13.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"itertools\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.13.0\"},\"itertools 0.14.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"use_alloc\",\"use_std\"],\"deps\":[{\"id\":\"either 1.15.0\",\"target\":\"either\"}],\"edition\":\"2018\"},\"library_target_name\":\"itertools\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"itertools\",\"package_url\":\"https://github.com/rust-itertools/itertools\",\"repository\":{\"Http\":{\"sha256\":\"2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285\",\"url\":\"https://static.crates.io/crates/itertools/0.14.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"itertools\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.14.0\"},\"itoa 1.0.18\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"itoa\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"itoa\",\"package_url\":\"https://github.com/dtolnay/itoa\",\"repository\":{\"Http\":{\"sha256\":\"8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682\",\"url\":\"https://static.crates.io/crates/itoa/1.0.18/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"itoa\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.18\"},\"jobserver 0.1.34\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(unix)\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(windows)\":[{\"id\":\"getrandom 0.3.4\",\"target\":\"getrandom\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"jobserver\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"jobserver\",\"package_url\":\"https://github.com/rust-lang/jobserver-rs\",\"repository\":{\"Http\":{\"sha256\":\"9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33\",\"url\":\"https://static.crates.io/crates/jobserver/0.1.34/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"jobserver\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.34\"},\"js-sys 0.3.95\":{\"common_attrs\":{\"deps\":[{\"id\":\"once_cell 1.21.4\",\"target\":\"once_cell\"},{\"id\":\"wasm-bindgen 0.2.118\",\"target\":\"wasm_bindgen\"}],\"edition\":\"2021\"},\"library_target_name\":\"js_sys\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"js-sys\",\"package_url\":\"https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/js-sys\",\"repository\":{\"Http\":{\"sha256\":\"2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca\",\"url\":\"https://static.crates.io/crates/js-sys/0.3.95/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"js_sys\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.95\"},\"lazy_static 1.5.0\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"lazy_static\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"lazy_static\",\"package_url\":\"https://github.com/rust-lang-nursery/lazy-static.rs\",\"repository\":{\"Http\":{\"sha256\":\"bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe\",\"url\":\"https://static.crates.io/crates/lazy_static/1.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"lazy_static\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.5.0\"},\"leb128 0.2.6\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"leb128\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"leb128\",\"package_url\":\"https://github.com/gimli-rs/leb128\",\"repository\":{\"Http\":{\"sha256\":\"6cc46bac87ef8093eed6f272babb833b6443374399985ac8ed28471ee0918545\",\"url\":\"https://static.crates.io/crates/leb128/0.2.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"leb128\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.6\"},\"leb128fmt 0.1.0\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"leb128fmt\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"leb128fmt\",\"package_url\":\"https://github.com/bluk/leb128fmt\",\"repository\":{\"Http\":{\"sha256\":\"09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2\",\"url\":\"https://static.crates.io/crates/leb128fmt/0.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"leb128fmt\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.0\"},\"lexical-sort 0.3.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"any_ascii 0.1.7\",\"target\":\"any_ascii\"}],\"edition\":\"2018\"},\"library_target_name\":\"lexical_sort\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"lexical-sort\",\"package_url\":\"https://github.com/Aloso/lexical-sort\",\"repository\":{\"Http\":{\"sha256\":\"c09e4591611e231daf4d4c685a66cb0410cc1e502027a20ae55f2bb9e997207a\",\"url\":\"https://static.crates.io/crates/lexical-sort/0.3.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"lexical_sort\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.1\"},\"libc 0.2.186\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"libc\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"libc\",\"package_url\":\"https://github.com/rust-lang/libc\",\"repository\":{\"Http\":{\"sha256\":\"68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66\",\"url\":\"https://static.crates.io/crates/libc/0.2.186/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"libc\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.2.186\"},\"libloading 0.8.9\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(unix)\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"}],\"cfg(windows)\":[{\"id\":\"windows-link 0.2.1\",\"target\":\"windows_link\"}]}},\"edition\":\"2015\"},\"library_target_name\":\"libloading\",\"license\":\"ISC\",\"license_file\":\"LICENSE\",\"license_ids\":[\"ISC\"],\"name\":\"libloading\",\"package_url\":\"https://github.com/nagisa/rust_libloading/\",\"repository\":{\"Http\":{\"sha256\":\"d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55\",\"url\":\"https://static.crates.io/crates/libloading/0.8.9/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"libloading\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.9\"},\"libredox 0.1.16\":{\"common_attrs\":{\"deps\":[{\"id\":\"redox_syscall 0.7.4\",\"target\":\"syscall\"}],\"edition\":\"2021\"},\"library_target_name\":\"libredox\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"libredox\",\"package_url\":\"https://gitlab.redox-os.org/redox-os/libredox.git\",\"repository\":{\"Http\":{\"sha256\":\"e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c\",\"url\":\"https://static.crates.io/crates/libredox/0.1.16/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"libredox\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.16\"},\"libunwind 1.3.3\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"libunwind\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"libunwind\",\"package_url\":\"https://github.com/bluefish43/libunwind-sys\",\"repository\":{\"Http\":{\"sha256\":\"0c6639b70a7ce854b79c70d7e83f16b5dc0137cc914f3d7d03803b513ecc67ac\",\"url\":\"https://static.crates.io/crates/libunwind/1.3.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"libunwind\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.3.3\"},\"linked-hash-map 0.5.6\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"linked_hash_map\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"linked-hash-map\",\"package_url\":\"https://github.com/contain-rs/linked-hash-map\",\"repository\":{\"Http\":{\"sha256\":\"0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f\",\"url\":\"https://static.crates.io/crates/linked-hash-map/0.5.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"linked_hash_map\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.6\"},\"linked_hash_set 0.1.6\":{\"common_attrs\":{\"deps\":[{\"id\":\"linked-hash-map 0.5.6\",\"target\":\"linked_hash_map\"}],\"edition\":\"2024\"},\"library_target_name\":\"linked_hash_set\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"linked_hash_set\",\"package_url\":\"https://github.com/alexheretic/linked-hash-set\",\"repository\":{\"Http\":{\"sha256\":\"984fb35d06508d1e69fc91050cceba9c0b748f983e6739fa2c7a9237154c52c8\",\"url\":\"https://static.crates.io/crates/linked_hash_set/0.1.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"linked_hash_set\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.6\"},\"linux-raw-sys 0.12.1\":{\"common_attrs\":{\"crate_features\":[\"auxvec\",\"elf\",\"errno\",\"general\",\"ioctl\",\"no_std\"],\"edition\":\"2021\"},\"library_target_name\":\"linux_raw_sys\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"linux-raw-sys\",\"package_url\":\"https://github.com/sunfishcode/linux-raw-sys\",\"repository\":{\"Http\":{\"sha256\":\"32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53\",\"url\":\"https://static.crates.io/crates/linux-raw-sys/0.12.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"linux_raw_sys\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.12.1\"},\"litemap 0.8.2\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"litemap\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"litemap\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0\",\"url\":\"https://static.crates.io/crates/litemap/0.8.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"litemap\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.2\"},\"litrs 1.0.0\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"litrs\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"litrs\",\"package_url\":\"https://github.com/LukasKalbertodt/litrs\",\"repository\":{\"Http\":{\"sha256\":\"11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092\",\"url\":\"https://static.crates.io/crates/litrs/1.0.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"litrs\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.0\"},\"llvm-sys 221.0.1\":{\"build_script_attrs\":{\"build_script_env_files\":{\"common\":[\"@oliphaunt//build_defs/wasix:wasmer_llvm_env\"],\"selects\":{\"x86_64-unknown-linux-gnu\":[\"@oliphaunt//build_defs/wasix:wasmer_llvm_gnu_env\"]}},\"data\":{\"common\":[\"@oliphaunt//build_defs/wasix:wasmer_llvm_files\"],\"selects\":{\"x86_64-unknown-linux-gnu\":[\"@oliphaunt//build_defs/wasix:wasmer_llvm_gnu_files\"]}},\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"cc 1.2.60\",\"target\":\"cc\"},{\"id\":\"lazy_static 1.5.0\",\"target\":\"lazy_static\"},{\"id\":\"regex-lite 0.1.9\",\"target\":\"regex_lite\"},{\"id\":\"semver 1.0.28\",\"target\":\"semver\"}],\"links\":\"llvm-22\"},\"common_attrs\":{\"crate_features\":[\"prefer-static\"],\"deps\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"],\"extra_link_deps\":{\"common\":[\"@oliphaunt//build_defs/wasix/postmaster:llvm_zstd\"],\"selects\":{\"aarch64-unknown-linux-gnu\":[\"@oliphaunt//build_defs/wasix:llvm_libxml2_arm64\"],\"x86_64-unknown-linux-gnu\":[\"@oliphaunt//build_defs/extensions/postgis:libxml2\",\"@oliphaunt//build_defs/wasix:wasmer_llvm_gnu_link\"]}}},\"library_target_name\":\"llvm_sys\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"llvm-sys\",\"package_url\":\"https://gitlab.com/taricorp/llvm-sys.rs\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[\"@@//build_defs/wasix:llvm-sys-declared-prefix.patch\"],\"sha256\":\"2abcc34a3b190f03c2a61b555f218f529589ff13657bdd2ff8ac3e85f2abe6bb\",\"url\":\"https://static.crates.io/crates/llvm-sys/221.0.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"llvm_sys\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"221.0.1\"},\"lock_api 0.4.14\":{\"common_attrs\":{\"crate_features\":[\"atomic_usize\",\"default\"],\"deps\":[{\"id\":\"scopeguard 1.2.0\",\"target\":\"scopeguard\"}],\"edition\":\"2021\"},\"library_target_name\":\"lock_api\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"lock_api\",\"package_url\":\"https://github.com/Amanieu/parking_lot\",\"repository\":{\"Http\":{\"sha256\":\"224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965\",\"url\":\"https://static.crates.io/crates/lock_api/0.4.14/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"lock_api\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.14\"},\"log 0.4.29\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"log\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"log\",\"package_url\":\"https://github.com/rust-lang/log\",\"repository\":{\"Http\":{\"sha256\":\"5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897\",\"url\":\"https://static.crates.io/crates/log/0.4.29/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"log\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.29\"},\"lz4_flex 0.13.0\":{\"common_attrs\":{\"crate_features\":[\"checked-decode\",\"default\",\"frame\",\"safe-decode\",\"safe-encode\",\"std\"],\"deps\":[{\"id\":\"twox-hash 2.1.2\",\"target\":\"twox_hash\"}],\"edition\":\"2021\"},\"library_target_name\":\"lz4_flex\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"lz4_flex\",\"package_url\":\"https://github.com/pseitz/lz4_flex\",\"repository\":{\"Http\":{\"sha256\":\"db9a0d582c2874f68138a16ce1867e0ffde6c0bb0a0df85e1f36d04146db488a\",\"url\":\"https://static.crates.io/crates/lz4_flex/0.13.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"lz4_flex\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.13.0\"},\"mach2 0.4.3\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"deps\":{\"common\":[],\"selects\":{\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"ios\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}]}},\"edition\":\"2015\"},\"library_target_name\":\"mach2\",\"license\":\"BSD-2-Clause OR MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"BSD-2-Clause\",\"MIT\"],\"name\":\"mach2\",\"package_url\":\"https://github.com/JohnTitor/mach2\",\"repository\":{\"Http\":{\"sha256\":\"d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44\",\"url\":\"https://static.crates.io/crates/mach2/0.4.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"mach2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.3\"},\"mach2 0.6.0\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"edition\":\"2024\"},\"library_target_name\":\"mach2\",\"license\":\"BSD-2-Clause OR MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"BSD-2-Clause\",\"MIT\"],\"name\":\"mach2\",\"package_url\":\"https://github.com/JohnTitor/mach2\",\"repository\":{\"Http\":{\"sha256\":\"dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b\",\"url\":\"https://static.crates.io/crates/mach2/0.6.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"mach2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.0\"},\"macho-unwind-info 0.5.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"zerocopy 0.8.48\",\"target\":\"zerocopy\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"zerocopy-derive 0.8.48\",\"target\":\"zerocopy_derive\"}]},\"library_target_name\":\"macho_unwind_info\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"macho-unwind-info\",\"package_url\":\"https://github.com/mstange/macho-unwind-info\",\"repository\":{\"Http\":{\"sha256\":\"bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149\",\"url\":\"https://static.crates.io/crates/macho-unwind-info/0.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"macho_unwind_info\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.0\"},\"managed 0.8.0\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"map\",\"std\"],\"edition\":\"2015\"},\"library_target_name\":\"managed\",\"license\":\"0BSD\",\"license_file\":\"LICENSE-0BSD.txt\",\"license_ids\":[\"0BSD\"],\"name\":\"managed\",\"package_url\":\"https://github.com/m-labs/rust-managed.git\",\"repository\":{\"Http\":{\"sha256\":\"0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d\",\"url\":\"https://static.crates.io/crates/managed/0.8.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"managed\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.0\"},\"memchr 2.8.0\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"memchr\",\"license\":\"Unlicense OR MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"memchr\",\"package_url\":\"https://github.com/BurntSushi/memchr\",\"repository\":{\"Http\":{\"sha256\":\"f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79\",\"url\":\"https://static.crates.io/crates/memchr/2.8.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"memchr\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.8.0\"},\"memmap2 0.6.2\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(unix)\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"memmap2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"memmap2\",\"package_url\":\"https://github.com/RazrFalcon/memmap2-rs\",\"repository\":{\"Http\":{\"sha256\":\"6d28bba84adfe6646737845bc5ebbfa2c08424eb1c37e94a1fd2a82adb56a872\",\"url\":\"https://static.crates.io/crates/memmap2/0.6.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"memmap2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.2\"},\"memmap2 0.9.10\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(unix)\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"memmap2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"memmap2\",\"package_url\":\"https://github.com/RazrFalcon/memmap2-rs\",\"repository\":{\"Http\":{\"sha256\":\"714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3\",\"url\":\"https://static.crates.io/crates/memmap2/0.9.10/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"memmap2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.9.10\"},\"memoffset 0.9.1\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"autocfg 1.5.0\",\"target\":\"autocfg\"}]},\"common_attrs\":{\"crate_features\":[\"default\"],\"edition\":\"2015\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"memoffset\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"memoffset\",\"package_url\":\"https://github.com/Gilnaa/memoffset\",\"repository\":{\"Http\":{\"sha256\":\"488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a\",\"url\":\"https://static.crates.io/crates/memoffset/0.9.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"memoffset\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.9.1\"},\"minimal-lexical 0.2.1\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"minimal_lexical\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"minimal-lexical\",\"package_url\":\"https://github.com/Alexhuszagh/minimal-lexical\",\"repository\":{\"Http\":{\"sha256\":\"68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a\",\"url\":\"https://static.crates.io/crates/minimal-lexical/0.2.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"minimal_lexical\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.1\"},\"miniz_oxide 0.8.9\":{\"common_attrs\":{\"crate_features\":[\"simd\",\"simd-adler32\",\"with-alloc\"],\"deps\":[{\"id\":\"adler2 2.0.1\",\"target\":\"adler2\"},{\"id\":\"simd-adler32 0.3.9\",\"target\":\"simd_adler32\"}],\"edition\":\"2021\"},\"library_target_name\":\"miniz_oxide\",\"license\":\"MIT OR Zlib OR Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\",\"MIT\",\"Zlib\"],\"name\":\"miniz_oxide\",\"package_url\":\"https://github.com/Frommi/miniz_oxide/tree/master/miniz_oxide\",\"repository\":{\"Http\":{\"sha256\":\"1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316\",\"url\":\"https://static.crates.io/crates/miniz_oxide/0.8.9/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"miniz_oxide\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.9\"},\"more-asserts 0.3.1\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"more_asserts\",\"license\":\"Unlicense OR MIT OR Apache-2.0 OR CC0-1.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"CC0-1.0\",\"MIT\",\"Unlicense\"],\"name\":\"more-asserts\",\"package_url\":\"https://github.com/thomcc/rust-more-asserts\",\"repository\":{\"Http\":{\"sha256\":\"1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e\",\"url\":\"https://static.crates.io/crates/more-asserts/0.3.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"more_asserts\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.1\"},\"msvc-demangler 0.11.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"bitflags 2.11.1\",\"target\":\"bitflags\"},{\"id\":\"itoa 1.0.18\",\"target\":\"itoa\"}],\"edition\":\"2021\"},\"library_target_name\":\"msvc_demangler\",\"license\":\"MIT/NCSA\",\"license_file\":\"LICENSE.LLVM\",\"license_ids\":[\"MIT\",\"NCSA\"],\"name\":\"msvc-demangler\",\"package_url\":\"https://github.com/mstange/msvc-demangler-rust\",\"repository\":{\"Http\":{\"sha256\":\"fbeff6bd154a309b2ada5639b2661ca6ae4599b34e8487dc276d2cd637da2d76\",\"url\":\"https://static.crates.io/crates/msvc-demangler/0.11.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"msvc_demangler\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.11.0\"},\"munge 0.4.7\":{\"common_attrs\":{\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"munge_macro 0.4.7\",\"target\":\"munge_macro\"}]},\"library_target_name\":\"munge\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"munge\",\"package_url\":\"https://github.com/djkoloski/munge\",\"repository\":{\"Http\":{\"sha256\":\"5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c\",\"url\":\"https://static.crates.io/crates/munge/0.4.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"munge\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.7\"},\"munge_macro 0.4.7\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"munge_macro\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"munge_macro\",\"package_url\":\"https://github.com/djkoloski/munge\",\"repository\":{\"Http\":{\"sha256\":\"4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931\",\"url\":\"https://static.crates.io/crates/munge_macro/0.4.7/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"munge_macro\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.7\"},\"nom 5.1.3\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"version_check 0.9.5\",\"target\":\"version_check\"}]},\"common_attrs\":{\"deps\":[{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"}],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"nom\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"nom\",\"package_url\":\"https://github.com/Geal/nom\",\"repository\":{\"Http\":{\"sha256\":\"08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b\",\"url\":\"https://static.crates.io/crates/nom/5.1.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"nom\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"5.1.3\"},\"nom 7.1.3\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"std\"],\"deps\":[{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"},{\"id\":\"minimal-lexical 0.2.1\",\"target\":\"minimal_lexical\"}],\"edition\":\"2018\"},\"library_target_name\":\"nom\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"nom\",\"package_url\":\"https://github.com/Geal/nom\",\"repository\":{\"Http\":{\"sha256\":\"d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a\",\"url\":\"https://static.crates.io/crates/nom/7.1.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"nom\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"7.1.3\"},\"num-conv 0.2.1\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"num_conv\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-Apache\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"num-conv\",\"package_url\":\"https://github.com/jhpratt/num-conv\",\"repository\":{\"Http\":{\"sha256\":\"c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967\",\"url\":\"https://static.crates.io/crates/num-conv/0.2.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"num_conv\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.1\"},\"num-traits 0.2.19\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"autocfg 1.5.0\",\"target\":\"autocfg\"}]},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"num_traits\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"num-traits\",\"package_url\":\"https://github.com/rust-num/num-traits\",\"repository\":{\"Http\":{\"sha256\":\"071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841\",\"url\":\"https://static.crates.io/crates/num-traits/0.2.19/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"num_traits\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.2.19\"},\"num_cpus 1.17.0\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(not(windows))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(target_os = \\\"hermit\\\")\":[{\"id\":\"hermit-abi 0.5.2\",\"target\":\"hermit_abi\"}]}},\"edition\":\"2015\"},\"library_target_name\":\"num_cpus\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"num_cpus\",\"package_url\":\"https://github.com/seanmonstar/num_cpus\",\"repository\":{\"Http\":{\"sha256\":\"91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b\",\"url\":\"https://static.crates.io/crates/num_cpus/1.17.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"num_cpus\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.17.0\"},\"num_enum 0.7.6\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"num_enum_derive 0.7.6\",\"target\":\"num_enum_derive\"},{\"id\":\"rustversion 1.0.22\",\"target\":\"rustversion\"}]},\"library_target_name\":\"num_enum\",\"license\":\"BSD-3-Clause OR MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"BSD-3-Clause\",\"MIT\"],\"name\":\"num_enum\",\"package_url\":\"https://github.com/illicitonion/num_enum\",\"repository\":{\"Http\":{\"sha256\":\"5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26\",\"url\":\"https://static.crates.io/crates/num_enum/0.7.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"num_enum\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.6\"},\"num_enum_derive 0.7.6\":{\"common_attrs\":{\"crate_features\":[\"proc-macro-crate\",\"std\"],\"deps\":[{\"id\":\"proc-macro-crate 3.5.0\",\"target\":\"proc_macro_crate\"},{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"num_enum_derive\",\"license\":\"BSD-3-Clause OR MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"BSD-3-Clause\",\"MIT\"],\"name\":\"num_enum_derive\",\"package_url\":\"https://github.com/illicitonion/num_enum\",\"repository\":{\"Http\":{\"sha256\":\"680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8\",\"url\":\"https://static.crates.io/crates/num_enum_derive/0.7.6/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"num_enum_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.6\"},\"object 0.37.3\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"archive\",\"coff\",\"elf\",\"macho\",\"pe\",\"read_core\",\"unaligned\",\"xcoff\"],\"deps\":[{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"}],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"object\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"object\",\"package_url\":\"https://github.com/gimli-rs/object\",\"repository\":{\"Http\":{\"sha256\":\"ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe\",\"url\":\"https://static.crates.io/crates/object/0.37.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"object\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.37.3\"},\"object 0.39.1\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"archive\",\"coff\",\"compression\",\"default\",\"elf\",\"macho\",\"pe\",\"read\",\"read_core\",\"std\",\"write\",\"write_core\",\"write_std\",\"xcoff\"],\"deps\":[{\"id\":\"crc32fast 1.5.0\",\"target\":\"crc32fast\"},{\"id\":\"flate2 1.1.9\",\"target\":\"flate2\"},{\"id\":\"hashbrown 0.17.0\",\"target\":\"hashbrown\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"},{\"id\":\"ruzstd 0.8.2\",\"target\":\"ruzstd\"}],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"object\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"object\",\"package_url\":\"https://github.com/gimli-rs/object\",\"repository\":{\"Http\":{\"sha256\":\"2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b\",\"url\":\"https://static.crates.io/crates/object/0.39.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"object\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.39.1\"},\"oliphaunt-wasix-postmaster-executor 7.2.0-alpha.2\":{\"common_attrs\":{\"crate_features\":[\"default\",\"memory-profile-core\",\"memory-profile-tool\",\"product-compiler\"],\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"hex 0.4.3\",\"target\":\"hex\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.149\",\"target\":\"serde_json\"},{\"id\":\"sha2 0.11.0\",\"target\":\"sha2\"},{\"id\":\"tempfile 3.27.0\",\"target\":\"tempfile\"},{\"id\":\"tracing 0.1.44\",\"target\":\"tracing\"},{\"id\":\"wasmer 7.2.0-alpha.2\",\"target\":\"wasmer\"},{\"id\":\"wasmer-compiler-llvm 7.2.0-alpha.2\",\"target\":\"wasmer_compiler_llvm\"},{\"id\":\"wasmer-types 7.2.0-alpha.2\",\"target\":\"wasmer_types\"},{\"id\":\"wasmer-vm 7.2.0-alpha.2\",\"target\":\"wasmer_vm\"},{\"id\":\"wasmer-wasix 0.702.0-alpha.2\",\"target\":\"wasmer_wasix\"},{\"id\":\"wasmparser 0.247.0\",\"target\":\"wasmparser\"}],\"deps_dev\":[{\"id\":\"futures 0.3.32\",\"target\":\"futures\"},{\"id\":\"wat 1.247.0\",\"target\":\"wat\"}],\"edition\":\"2024\",\"proc_macro_deps\":[{\"id\":\"async-trait 0.1.89\",\"target\":\"async_trait\"}]},\"library_target_name\":\"oliphaunt_wasix_postmaster_executor\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"oliphaunt-wasix-postmaster-executor\",\"package_url\":\"https://github.com/f0rr0/oliphaunt\",\"repository\":null,\"targets\":[{\"Library\":{\"crate_name\":\"oliphaunt_wasix_postmaster_executor\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"7.2.0-alpha.2\"},\"once_cell 1.21.4\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"race\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"once_cell\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"once_cell\",\"package_url\":\"https://github.com/matklad/once_cell\",\"repository\":{\"Http\":{\"sha256\":\"9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50\",\"url\":\"https://static.crates.io/crates/once_cell/1.21.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"once_cell\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.21.4\"},\"parking 2.2.1\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"parking\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"parking\",\"package_url\":\"https://github.com/smol-rs/parking\",\"repository\":{\"Http\":{\"sha256\":\"f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba\",\"url\":\"https://static.crates.io/crates/parking/2.2.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"parking\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.2.1\"},\"parking_lot 0.12.5\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"deps\":[{\"id\":\"lock_api 0.4.14\",\"target\":\"lock_api\"},{\"id\":\"parking_lot_core 0.9.12\",\"target\":\"parking_lot_core\"}],\"edition\":\"2021\"},\"library_target_name\":\"parking_lot\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"parking_lot\",\"package_url\":\"https://github.com/Amanieu/parking_lot\",\"repository\":{\"Http\":{\"sha256\":\"93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a\",\"url\":\"https://static.crates.io/crates/parking_lot/0.12.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"parking_lot\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.12.5\"},\"parking_lot_core 0.9.12\":{\"build_script_attrs\":{},\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"smallvec 1.15.1\",\"target\":\"smallvec\"}],\"selects\":{\"cfg(target_os = \\\"redox\\\")\":[{\"id\":\"redox_syscall 0.5.18\",\"target\":\"syscall\"}],\"cfg(unix)\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(windows)\":[{\"id\":\"windows-link 0.2.1\",\"target\":\"windows_link\"}]}},\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"parking_lot_core\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"parking_lot_core\",\"package_url\":\"https://github.com/Amanieu/parking_lot\",\"repository\":{\"Http\":{\"sha256\":\"2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1\",\"url\":\"https://static.crates.io/crates/parking_lot_core/0.9.12/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"parking_lot_core\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.9.12\"},\"paste 1.0.15\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"paste\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"paste\",\"package_url\":\"https://github.com/dtolnay/paste\",\"repository\":{\"Http\":{\"sha256\":\"57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a\",\"url\":\"https://static.crates.io/crates/paste/1.0.15/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"paste\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.15\"},\"path-clean 1.0.1\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"path_clean\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"path-clean\",\"package_url\":\"https://github.com/danreeves/path-clean\",\"repository\":{\"Http\":{\"sha256\":\"17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef\",\"url\":\"https://static.crates.io/crates/path-clean/1.0.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"path_clean\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.1\"},\"percent-encoding 2.3.2\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"percent_encoding\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"percent-encoding\",\"package_url\":\"https://github.com/servo/rust-url/\",\"repository\":{\"Http\":{\"sha256\":\"9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220\",\"url\":\"https://static.crates.io/crates/percent-encoding/2.3.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"percent_encoding\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.3.2\"},\"petgraph 0.8.3\":{\"common_attrs\":{\"crate_features\":[\"default\",\"graphmap\",\"matrix_graph\",\"stable_graph\",\"std\"],\"deps\":[{\"id\":\"fixedbitset 0.5.7\",\"target\":\"fixedbitset\"},{\"id\":\"hashbrown 0.15.5\",\"target\":\"hashbrown\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"}],\"edition\":\"2021\"},\"library_target_name\":\"petgraph\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"petgraph\",\"package_url\":\"https://github.com/petgraph/petgraph\",\"repository\":{\"Http\":{\"sha256\":\"8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455\",\"url\":\"https://static.crates.io/crates/petgraph/0.8.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"petgraph\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.3\"},\"phf 0.13.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"macros\",\"phf_macros\",\"std\"],\"deps\":[{\"id\":\"phf_shared 0.13.1\",\"target\":\"phf_shared\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"phf_macros 0.13.1\",\"target\":\"phf_macros\"}]},\"library_target_name\":\"phf\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"phf\",\"package_url\":\"https://github.com/rust-phf/rust-phf\",\"repository\":{\"Http\":{\"sha256\":\"c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf\",\"url\":\"https://static.crates.io/crates/phf/0.13.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"phf\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.13.1\"},\"phf_generator 0.13.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"fastrand 2.4.1\",\"target\":\"fastrand\"},{\"id\":\"phf_shared 0.13.1\",\"target\":\"phf_shared\"}],\"edition\":\"2021\"},\"library_target_name\":\"phf_generator\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"phf_generator\",\"package_url\":\"https://github.com/rust-phf/rust-phf\",\"repository\":{\"Http\":{\"sha256\":\"135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737\",\"url\":\"https://static.crates.io/crates/phf_generator/0.13.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"phf_generator\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.13.1\"},\"phf_macros 0.13.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"phf_generator 0.13.1\",\"target\":\"phf_generator\"},{\"id\":\"phf_shared 0.13.1\",\"target\":\"phf_shared\"},{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"phf_macros\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"phf_macros\",\"package_url\":\"https://github.com/rust-phf/rust-phf\",\"repository\":{\"Http\":{\"sha256\":\"812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef\",\"url\":\"https://static.crates.io/crates/phf_macros/0.13.1/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"phf_macros\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.13.1\"},\"phf_shared 0.13.1\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"deps\":[{\"id\":\"siphasher 1.0.2\",\"target\":\"siphasher\"}],\"edition\":\"2021\"},\"library_target_name\":\"phf_shared\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"phf_shared\",\"package_url\":\"https://github.com/rust-phf/rust-phf\",\"repository\":{\"Http\":{\"sha256\":\"e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266\",\"url\":\"https://static.crates.io/crates/phf_shared/0.13.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"phf_shared\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.13.1\"},\"pin-project 1.1.11\":{\"common_attrs\":{\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"pin-project-internal 1.1.11\",\"target\":\"pin_project_internal\"}]},\"library_target_name\":\"pin_project\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"pin-project\",\"package_url\":\"https://github.com/taiki-e/pin-project\",\"repository\":{\"Http\":{\"sha256\":\"f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517\",\"url\":\"https://static.crates.io/crates/pin-project/1.1.11/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"pin_project\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.11\"},\"pin-project-internal 1.1.11\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"pin_project_internal\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"pin-project-internal\",\"package_url\":\"https://github.com/taiki-e/pin-project\",\"repository\":{\"Http\":{\"sha256\":\"d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6\",\"url\":\"https://static.crates.io/crates/pin-project-internal/1.1.11/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"pin_project_internal\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.11\"},\"pin-project-lite 0.2.17\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"pin_project_lite\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"pin-project-lite\",\"package_url\":\"https://github.com/taiki-e/pin-project-lite\",\"repository\":{\"Http\":{\"sha256\":\"a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd\",\"url\":\"https://static.crates.io/crates/pin-project-lite/0.2.17/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"pin_project_lite\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.17\"},\"pin-utils 0.1.0\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"pin_utils\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"pin-utils\",\"package_url\":\"https://github.com/rust-lang-nursery/pin-utils\",\"repository\":{\"Http\":{\"sha256\":\"8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184\",\"url\":\"https://static.crates.io/crates/pin-utils/0.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"pin_utils\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.0\"},\"pkg-config 0.3.33\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"pkg_config\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"pkg-config\",\"package_url\":\"https://github.com/rust-lang/pkg-config-rs\",\"repository\":{\"Http\":{\"sha256\":\"19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e\",\"url\":\"https://static.crates.io/crates/pkg-config/0.3.33/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"pkg_config\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.33\"},\"plain 0.2.3\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"plain\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"plain\",\"package_url\":\"https://github.com/randomites/plain\",\"repository\":{\"Http\":{\"sha256\":\"b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6\",\"url\":\"https://static.crates.io/crates/plain/0.2.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"plain\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.3\"},\"potential_utf 0.1.5\":{\"common_attrs\":{\"crate_features\":[\"zerovec\"],\"deps\":[{\"id\":\"zerovec 0.11.6\",\"target\":\"zerovec\"}],\"edition\":\"2021\"},\"library_target_name\":\"potential_utf\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"potential_utf\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564\",\"url\":\"https://static.crates.io/crates/potential_utf/0.1.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"potential_utf\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.5\"},\"powerfmt 0.2.0\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"powerfmt\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-Apache\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"powerfmt\",\"package_url\":\"https://github.com/jhpratt/powerfmt\",\"repository\":{\"Http\":{\"sha256\":\"439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391\",\"url\":\"https://static.crates.io/crates/powerfmt/0.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"powerfmt\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.0\"},\"ppv-lite86 0.2.21\":{\"common_attrs\":{\"crate_features\":[\"simd\",\"std\"],\"deps\":[{\"id\":\"zerocopy 0.8.48\",\"target\":\"zerocopy\"}],\"edition\":\"2021\"},\"library_target_name\":\"ppv_lite86\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"ppv-lite86\",\"package_url\":\"https://github.com/cryptocorrosion/cryptocorrosion\",\"repository\":{\"Http\":{\"sha256\":\"85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9\",\"url\":\"https://static.crates.io/crates/ppv-lite86/0.2.21/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ppv_lite86\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.21\"},\"prettyplease 0.2.37\":{\"build_script_attrs\":{\"links\":\"prettyplease02\"},\"common_attrs\":{\"crate_features\":[\"verbatim\"],\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"prettyplease\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"prettyplease\",\"package_url\":\"https://github.com/dtolnay/prettyplease\",\"repository\":{\"Http\":{\"sha256\":\"479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b\",\"url\":\"https://static.crates.io/crates/prettyplease/0.2.37/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"prettyplease\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.2.37\"},\"proc-macro-crate 3.5.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"toml_edit 0.25.11+spec-1.1.0\",\"target\":\"toml_edit\"}],\"edition\":\"2021\"},\"library_target_name\":\"proc_macro_crate\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"proc-macro-crate\",\"package_url\":\"https://github.com/bkchr/proc-macro-crate\",\"repository\":{\"Http\":{\"sha256\":\"e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f\",\"url\":\"https://static.crates.io/crates/proc-macro-crate/3.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"proc_macro_crate\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"3.5.0\"},\"proc-macro-error-attr2 2.0.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"}],\"edition\":\"2021\"},\"library_target_name\":\"proc_macro_error_attr2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"proc-macro-error-attr2\",\"package_url\":\"https://github.com/GnomedDev/proc-macro-error-2\",\"repository\":{\"Http\":{\"sha256\":\"96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5\",\"url\":\"https://static.crates.io/crates/proc-macro-error-attr2/2.0.0/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"proc_macro_error_attr2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.0.0\"},\"proc-macro-error2 2.0.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"syn-error\"],\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"proc-macro-error-attr2 2.0.0\",\"target\":\"proc_macro_error_attr2\"}]},\"library_target_name\":\"proc_macro_error2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"proc-macro-error2\",\"package_url\":\"https://github.com/GnomedDev/proc-macro-error-2\",\"repository\":{\"Http\":{\"sha256\":\"11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802\",\"url\":\"https://static.crates.io/crates/proc-macro-error2/2.0.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"proc_macro_error2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.0.1\"},\"proc-macro2 1.0.106\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"proc-macro\"],\"deps\":[{\"id\":\"unicode-ident 1.0.24\",\"target\":\"unicode_ident\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"proc_macro2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"proc-macro2\",\"package_url\":\"https://github.com/dtolnay/proc-macro2\",\"repository\":{\"Http\":{\"sha256\":\"8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934\",\"url\":\"https://static.crates.io/crates/proc-macro2/1.0.106/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"proc_macro2\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.106\"},\"ptr_meta 0.3.1\":{\"common_attrs\":{\"crate_features\":[\"derive\",\"ptr_meta_derive\",\"std\"],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"ptr_meta_derive 0.3.1\",\"target\":\"ptr_meta_derive\"}]},\"library_target_name\":\"ptr_meta\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"ptr_meta\",\"package_url\":\"https://github.com/rkyv/ptr_meta\",\"repository\":{\"Http\":{\"sha256\":\"0b9a0cf95a1196af61d4f1cbdab967179516d9a4a4312af1f31948f8f6224a79\",\"url\":\"https://static.crates.io/crates/ptr_meta/0.3.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ptr_meta\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.1\"},\"ptr_meta_derive 0.3.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"ptr_meta_derive\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"ptr_meta_derive\",\"package_url\":\"https://github.com/rkyv/ptr_meta\",\"repository\":{\"Http\":{\"sha256\":\"7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1\",\"url\":\"https://static.crates.io/crates/ptr_meta_derive/0.3.1/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"ptr_meta_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.1\"},\"pulldown-cmark 0.8.0\":{\"build_script_attrs\":{},\"common_attrs\":{\"deps\":[{\"id\":\"bitflags 1.3.2\",\"target\":\"bitflags\"},{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"},{\"id\":\"unicase 2.9.0\",\"target\":\"unicase\"}],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"pulldown_cmark\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"pulldown-cmark\",\"package_url\":\"https://github.com/raphlinus/pulldown-cmark\",\"repository\":{\"Http\":{\"sha256\":\"ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8\",\"url\":\"https://static.crates.io/crates/pulldown-cmark/0.8.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"pulldown_cmark\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.8.0\"},\"quote 1.0.45\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"proc-macro\"],\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"quote\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"quote\",\"package_url\":\"https://github.com/dtolnay/quote\",\"repository\":{\"Http\":{\"sha256\":\"41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924\",\"url\":\"https://static.crates.io/crates/quote/1.0.45/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"quote\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.45\"},\"r-efi 5.3.0\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"r_efi\",\"license\":\"MIT OR Apache-2.0 OR LGPL-2.1-or-later\",\"license_ids\":[\"Apache-2.0\",\"LGPL-2.1\",\"MIT\"],\"name\":\"r-efi\",\"package_url\":\"https://github.com/r-efi/r-efi\",\"repository\":{\"Http\":{\"sha256\":\"69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f\",\"url\":\"https://static.crates.io/crates/r-efi/5.3.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"r_efi\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"5.3.0\"},\"r-efi 6.0.0\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"r_efi\",\"license\":\"MIT OR Apache-2.0 OR LGPL-2.1-or-later\",\"license_ids\":[\"Apache-2.0\",\"LGPL-2.1\",\"MIT\"],\"name\":\"r-efi\",\"package_url\":\"https://github.com/r-efi/r-efi\",\"repository\":{\"Http\":{\"sha256\":\"f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf\",\"url\":\"https://static.crates.io/crates/r-efi/6.0.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"r_efi\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"6.0.0\"},\"rancor 0.1.1\":{\"common_attrs\":{\"crate_features\":[\"alloc\"],\"deps\":[{\"id\":\"ptr_meta 0.3.1\",\"target\":\"ptr_meta\"}],\"edition\":\"2021\"},\"library_target_name\":\"rancor\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"rancor\",\"package_url\":\"https://github.com/rkyv/rancor\",\"repository\":{\"Http\":{\"sha256\":\"a063ea72381527c2a0561da9c80000ef822bdd7c3241b1cc1b12100e3df081ee\",\"url\":\"https://static.crates.io/crates/rancor/0.1.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rancor\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.1\"},\"rand 0.10.1\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\",\"std_rng\",\"sys_rng\",\"thread_rng\"],\"deps\":[{\"id\":\"chacha20 0.10.0\",\"target\":\"chacha20\"},{\"id\":\"getrandom 0.4.2\",\"target\":\"getrandom\"},{\"id\":\"rand_core 0.10.1\",\"target\":\"rand_core\"}],\"edition\":\"2024\"},\"library_target_name\":\"rand\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rand\",\"package_url\":\"https://github.com/rust-random/rand\",\"repository\":{\"Http\":{\"sha256\":\"d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207\",\"url\":\"https://static.crates.io/crates/rand/0.10.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rand\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.10.1\"},\"rand 0.9.4\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"os_rng\",\"small_rng\",\"std\",\"std_rng\",\"thread_rng\"],\"deps\":[{\"id\":\"rand_chacha 0.9.0\",\"target\":\"rand_chacha\"},{\"id\":\"rand_core 0.9.5\",\"target\":\"rand_core\"}],\"edition\":\"2021\"},\"library_target_name\":\"rand\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rand\",\"package_url\":\"https://github.com/rust-random/rand\",\"repository\":{\"Http\":{\"sha256\":\"44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea\",\"url\":\"https://static.crates.io/crates/rand/0.9.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rand\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.9.4\"},\"rand_chacha 0.9.0\":{\"common_attrs\":{\"crate_features\":[\"std\"],\"deps\":[{\"id\":\"ppv-lite86 0.2.21\",\"target\":\"ppv_lite86\"},{\"id\":\"rand_core 0.9.5\",\"target\":\"rand_core\"}],\"edition\":\"2021\"},\"library_target_name\":\"rand_chacha\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rand_chacha\",\"package_url\":\"https://github.com/rust-random/rand\",\"repository\":{\"Http\":{\"sha256\":\"d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb\",\"url\":\"https://static.crates.io/crates/rand_chacha/0.9.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rand_chacha\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.9.0\"},\"rand_core 0.10.1\":{\"common_attrs\":{\"edition\":\"2024\"},\"library_target_name\":\"rand_core\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rand_core\",\"package_url\":\"https://github.com/rust-random/rand_core\",\"repository\":{\"Http\":{\"sha256\":\"63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69\",\"url\":\"https://static.crates.io/crates/rand_core/0.10.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rand_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.10.1\"},\"rand_core 0.9.5\":{\"common_attrs\":{\"crate_features\":[\"os_rng\",\"std\"],\"deps\":[{\"id\":\"getrandom 0.3.4\",\"target\":\"getrandom\"}],\"edition\":\"2021\"},\"library_target_name\":\"rand_core\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rand_core\",\"package_url\":\"https://github.com/rust-random/rand\",\"repository\":{\"Http\":{\"sha256\":\"76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c\",\"url\":\"https://static.crates.io/crates/rand_core/0.9.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rand_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.9.5\"},\"rangemap 1.7.1\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"rangemap\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rangemap\",\"package_url\":\"https://github.com/jeffparsons/rangemap\",\"repository\":{\"Http\":{\"sha256\":\"973443cf09a9c8656b574a866ab68dfa19f0867d0340648c7d2f6a71b8a8ea68\",\"url\":\"https://static.crates.io/crates/rangemap/1.7.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rangemap\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.7.1\"},\"rayon 1.12.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"either 1.15.0\",\"target\":\"either\"},{\"id\":\"rayon-core 1.13.0\",\"target\":\"rayon_core\"}],\"edition\":\"2021\"},\"library_target_name\":\"rayon\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rayon\",\"package_url\":\"https://github.com/rayon-rs/rayon\",\"repository\":{\"Http\":{\"sha256\":\"fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d\",\"url\":\"https://static.crates.io/crates/rayon/1.12.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rayon\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.12.0\"},\"rayon-core 1.13.0\":{\"build_script_attrs\":{\"links\":\"rayon-core\"},\"common_attrs\":{\"deps\":[{\"id\":\"crossbeam-deque 0.8.6\",\"target\":\"crossbeam_deque\"},{\"id\":\"crossbeam-utils 0.8.21\",\"target\":\"crossbeam_utils\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"rayon_core\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rayon-core\",\"package_url\":\"https://github.com/rayon-rs/rayon\",\"repository\":{\"Http\":{\"sha256\":\"22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91\",\"url\":\"https://static.crates.io/crates/rayon-core/1.13.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rayon_core\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.13.0\"},\"redox_syscall 0.5.18\":{\"common_attrs\":{\"deps\":[{\"id\":\"bitflags 2.11.1\",\"target\":\"bitflags\"}],\"edition\":\"2021\"},\"library_target_name\":\"syscall\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"redox_syscall\",\"package_url\":\"https://gitlab.redox-os.org/redox-os/syscall\",\"repository\":{\"Http\":{\"sha256\":\"ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d\",\"url\":\"https://static.crates.io/crates/redox_syscall/0.5.18/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"syscall\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.18\"},\"redox_syscall 0.7.4\":{\"common_attrs\":{\"deps\":[{\"id\":\"bitflags 2.11.1\",\"target\":\"bitflags\"}],\"edition\":\"2021\"},\"library_target_name\":\"syscall\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"redox_syscall\",\"package_url\":\"https://gitlab.redox-os.org/redox-os/syscall\",\"repository\":{\"Http\":{\"sha256\":\"f450ad9c3b1da563fb6948a8e0fb0fb9269711c9c73d9ea1de5058c79c8d643a\",\"url\":\"https://static.crates.io/crates/redox_syscall/0.7.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"syscall\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.4\"},\"ref-cast 1.0.25\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":[{\"id\":\"ref-cast-impl 1.0.25\",\"target\":\"ref_cast_impl\"}]},\"library_target_name\":\"ref_cast\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"ref-cast\",\"package_url\":\"https://github.com/dtolnay/ref-cast\",\"repository\":{\"Http\":{\"sha256\":\"f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d\",\"url\":\"https://static.crates.io/crates/ref-cast/1.0.25/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ref_cast\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.25\"},\"ref-cast-impl 1.0.25\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"ref_cast_impl\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"ref-cast-impl\",\"package_url\":\"https://github.com/dtolnay/ref-cast\",\"repository\":{\"Http\":{\"sha256\":\"b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da\",\"url\":\"https://static.crates.io/crates/ref-cast-impl/1.0.25/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"ref_cast_impl\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.25\"},\"regex 1.12.3\":{\"common_attrs\":{\"crate_features\":[\"default\",\"perf\",\"perf-backtrack\",\"perf-cache\",\"perf-dfa\",\"perf-inline\",\"perf-literal\",\"perf-onepass\",\"std\",\"unicode\",\"unicode-age\",\"unicode-bool\",\"unicode-case\",\"unicode-gencat\",\"unicode-perl\",\"unicode-script\",\"unicode-segment\"],\"deps\":[{\"id\":\"aho-corasick 1.1.4\",\"target\":\"aho_corasick\"},{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"},{\"id\":\"regex-automata 0.4.14\",\"target\":\"regex_automata\"},{\"id\":\"regex-syntax 0.8.10\",\"target\":\"regex_syntax\"}],\"edition\":\"2021\"},\"library_target_name\":\"regex\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"regex\",\"package_url\":\"https://github.com/rust-lang/regex\",\"repository\":{\"Http\":{\"sha256\":\"e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276\",\"url\":\"https://static.crates.io/crates/regex/1.12.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"regex\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.12.3\"},\"regex-automata 0.4.14\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"dfa-onepass\",\"hybrid\",\"meta\",\"nfa\",\"nfa-backtrack\",\"nfa-pikevm\",\"nfa-thompson\",\"perf\",\"perf-inline\",\"perf-literal\",\"perf-literal-multisubstring\",\"perf-literal-substring\",\"std\",\"syntax\",\"unicode\",\"unicode-age\",\"unicode-bool\",\"unicode-case\",\"unicode-gencat\",\"unicode-perl\",\"unicode-script\",\"unicode-segment\",\"unicode-word-boundary\"],\"deps\":[{\"id\":\"aho-corasick 1.1.4\",\"target\":\"aho_corasick\"},{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"},{\"id\":\"regex-syntax 0.8.10\",\"target\":\"regex_syntax\"}],\"edition\":\"2021\"},\"library_target_name\":\"regex_automata\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"regex-automata\",\"package_url\":\"https://github.com/rust-lang/regex\",\"repository\":{\"Http\":{\"sha256\":\"6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f\",\"url\":\"https://static.crates.io/crates/regex-automata/0.4.14/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"regex_automata\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.14\"},\"regex-lite 0.1.9\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\",\"string\"],\"edition\":\"2021\"},\"library_target_name\":\"regex_lite\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"regex-lite\",\"package_url\":\"https://github.com/rust-lang/regex\",\"repository\":{\"Http\":{\"sha256\":\"cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973\",\"url\":\"https://static.crates.io/crates/regex-lite/0.1.9/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"regex_lite\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.9\"},\"regex-syntax 0.8.10\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\",\"unicode\",\"unicode-age\",\"unicode-bool\",\"unicode-case\",\"unicode-gencat\",\"unicode-perl\",\"unicode-script\",\"unicode-segment\"],\"edition\":\"2021\"},\"library_target_name\":\"regex_syntax\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"regex-syntax\",\"package_url\":\"https://github.com/rust-lang/regex\",\"repository\":{\"Http\":{\"sha256\":\"dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a\",\"url\":\"https://static.crates.io/crates/regex-syntax/0.8.10/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"regex_syntax\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.10\"},\"region 3.0.2\":{\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"bitflags 1.3.2\",\"target\":\"bitflags\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"selects\":{\"cfg(any(target_os = \\\"macos\\\", target_os = \\\"ios\\\"))\":[{\"id\":\"mach2 0.4.3\",\"target\":\"mach2\"}],\"cfg(windows)\":[{\"id\":\"windows-sys 0.52.0\",\"target\":\"windows_sys\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"region\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"region\",\"package_url\":\"https://github.com/darfink/region-rs\",\"repository\":{\"Http\":{\"sha256\":\"e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7\",\"url\":\"https://static.crates.io/crates/region/3.0.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"region\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"3.0.2\"},\"rend 0.5.3\":{\"common_attrs\":{\"crate_features\":[\"bytecheck\"],\"deps\":[{\"id\":\"bytecheck 0.8.2\",\"target\":\"bytecheck\"}],\"edition\":\"2021\"},\"library_target_name\":\"rend\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"rend\",\"package_url\":\"https://github.com/djkoloski/rend\",\"repository\":{\"Http\":{\"sha256\":\"cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6\",\"url\":\"https://static.crates.io/crates/rend/0.5.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rend\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.5.3\"},\"replace_with 0.1.8\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"replace_with\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE.txt\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"replace_with\",\"package_url\":\"https://github.com/alecmocatta/replace_with\",\"repository\":{\"Http\":{\"sha256\":\"51743d3e274e2b18df81c4dc6caf8a5b8e15dbe799e0dca05c7617380094e884\",\"url\":\"https://static.crates.io/crates/replace_with/0.1.8/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"replace_with\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.8\"},\"rkyv 0.8.16\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"bytecheck\",\"bytes-1\",\"default\",\"indexmap-2\",\"std\"],\"deps\":[{\"id\":\"bytecheck 0.8.2\",\"target\":\"bytecheck\"},{\"alias\":\"bytes_1\",\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"hashbrown 0.17.0\",\"target\":\"hashbrown\"},{\"alias\":\"indexmap_2\",\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"munge 0.4.7\",\"target\":\"munge\"},{\"id\":\"ptr_meta 0.3.1\",\"target\":\"ptr_meta\"},{\"id\":\"rancor 0.1.1\",\"target\":\"rancor\"},{\"id\":\"rend 0.5.3\",\"target\":\"rend\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"rkyv_derive 0.8.16\",\"target\":\"rkyv_derive\"}]},\"library_target_name\":\"rkyv\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"rkyv\",\"package_url\":\"https://github.com/rkyv/rkyv\",\"repository\":{\"Http\":{\"sha256\":\"73389e0c99e664f919275ab5b5b0471391fe9a8de61e1dff9b1eaf56a90f16e3\",\"url\":\"https://static.crates.io/crates/rkyv/0.8.16/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rkyv\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.16\"},\"rkyv_derive 0.8.16\":{\"common_attrs\":{\"crate_features\":[\"bytecheck\"],\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"rkyv_derive\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"rkyv_derive\",\"package_url\":\"https://github.com/rkyv/rkyv\",\"repository\":{\"Http\":{\"sha256\":\"5d2ed0b54125315fb36bd021e82d314d1c126548f871634b483f46b31d13cac6\",\"url\":\"https://static.crates.io/crates/rkyv_derive/0.8.16/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"rkyv_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.16\"},\"rustc-demangle 0.1.27\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"rustc_demangle\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rustc-demangle\",\"package_url\":\"https://github.com/rust-lang/rustc-demangle\",\"repository\":{\"Http\":{\"sha256\":\"b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d\",\"url\":\"https://static.crates.io/crates/rustc-demangle/0.1.27/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rustc_demangle\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.27\"},\"rustc-hash 2.1.2\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"rustc_hash\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rustc-hash\",\"package_url\":\"https://github.com/rust-lang/rustc-hash\",\"repository\":{\"Http\":{\"sha256\":\"94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe\",\"url\":\"https://static.crates.io/crates/rustc-hash/2.1.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rustc_hash\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.1.2\"},\"rustc_version 0.4.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"semver 1.0.28\",\"target\":\"semver\"}],\"edition\":\"2018\"},\"library_target_name\":\"rustc_version\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rustc_version\",\"package_url\":\"https://github.com/djc/rustc-version-rs\",\"repository\":{\"Http\":{\"sha256\":\"cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92\",\"url\":\"https://static.crates.io/crates/rustc_version/0.4.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rustc_version\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.1\"},\"rustix 1.1.4\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"fs\",\"std\",\"termios\"],\"deps\":{\"common\":[{\"id\":\"bitflags 2.11.1\",\"target\":\"bitflags\"}],\"selects\":{\"aarch64-apple-darwin\":[{\"alias\":\"libc_errno\",\"id\":\"errno 0.3.14\",\"target\":\"errno\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(all(any(target_os = \\\"linux\\\", target_os = \\\"android\\\"), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\":[{\"id\":\"linux-raw-sys 0.12.1\",\"target\":\"linux_raw_sys\"}],\"cfg(all(not(rustix_use_libc), not(miri), target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\"))))\":[{\"id\":\"linux-raw-sys 0.12.1\",\"target\":\"linux_raw_sys\"}],\"cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \\\"linux\\\", any(target_endian = \\\"little\\\", any(target_arch = \\\"s390x\\\", target_arch = \\\"powerpc\\\")), any(target_arch = \\\"arm\\\", all(target_arch = \\\"aarch64\\\", target_pointer_width = \\\"64\\\"), target_arch = \\\"riscv64\\\", all(rustix_use_experimental_asm, target_arch = \\\"powerpc\\\"), all(rustix_use_experimental_asm, target_arch = \\\"powerpc64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"s390x\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips32r6\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64\\\"), all(rustix_use_experimental_asm, target_arch = \\\"mips64r6\\\"), target_arch = \\\"x86\\\", all(target_arch = \\\"x86_64\\\", target_pointer_width = \\\"64\\\")))))))\":[{\"alias\":\"libc_errno\",\"id\":\"errno 0.3.14\",\"target\":\"errno\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(windows)\":[{\"alias\":\"libc_errno\",\"id\":\"errno 0.3.14\",\"target\":\"errno\"},{\"id\":\"windows-sys 0.61.2\",\"target\":\"windows_sys\"}]}},\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"rustix\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rustix\",\"package_url\":\"https://github.com/bytecodealliance/rustix\",\"repository\":{\"Http\":{\"sha256\":\"b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190\",\"url\":\"https://static.crates.io/crates/rustix/1.1.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rustix\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.1.4\"},\"rustversion 1.0.22\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"rustversion\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"rustversion\",\"package_url\":\"https://github.com/dtolnay/rustversion\",\"repository\":{\"Http\":{\"sha256\":\"b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d\",\"url\":\"https://static.crates.io/crates/rustversion/1.0.22/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"rustversion\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build/build.rs\"}}],\"version\":\"1.0.22\"},\"rusty_pool 0.7.0\":{\"common_attrs\":{\"crate_features\":[\"async\",\"default\",\"futures\"],\"deps\":[{\"id\":\"crossbeam-channel 0.5.15\",\"target\":\"crossbeam_channel\"},{\"id\":\"futures 0.3.32\",\"target\":\"futures\"},{\"id\":\"futures-channel 0.3.32\",\"target\":\"futures_channel\"},{\"id\":\"futures-executor 0.3.32\",\"target\":\"futures_executor\"},{\"id\":\"num_cpus 1.17.0\",\"target\":\"num_cpus\"}],\"edition\":\"2018\"},\"library_target_name\":\"rusty_pool\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"rusty_pool\",\"package_url\":\"https://github.com/robinfriedli/rusty_pool\",\"repository\":{\"Http\":{\"sha256\":\"4ed36cdb20de66d89a17ea04b8883fc7a386f2cf877aaedca5005583ce4876ff\",\"url\":\"https://static.crates.io/crates/rusty_pool/0.7.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"rusty_pool\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.0\"},\"ruzstd 0.8.2\":{\"common_attrs\":{\"crate_features\":[\"default\",\"hash\",\"std\"],\"deps\":[{\"id\":\"twox-hash 2.1.2\",\"target\":\"twox_hash\"}],\"edition\":\"2018\"},\"library_target_name\":\"ruzstd\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"ruzstd\",\"package_url\":\"https://github.com/KillingSpark/zstd-rs\",\"repository\":{\"Http\":{\"sha256\":\"e5ff0cc5e135c8870a775d3320910cd9b564ec036b4dc0b8741629020be63f01\",\"url\":\"https://static.crates.io/crates/ruzstd/0.8.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ruzstd\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.2\"},\"ryu 1.0.23\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"ryu\",\"license\":\"Apache-2.0 OR BSL-1.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"BSL-1.0\"],\"name\":\"ryu\",\"package_url\":\"https://github.com/dtolnay/ryu\",\"repository\":{\"Http\":{\"sha256\":\"9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f\",\"url\":\"https://static.crates.io/crates/ryu/1.0.23/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"ryu\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.23\"},\"saffron 0.1.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"chrono 0.4.44\",\"target\":\"chrono\"},{\"id\":\"nom 5.1.3\",\"target\":\"nom\"}],\"edition\":\"2018\"},\"library_target_name\":\"saffron\",\"license_file\":\"LICENSE\",\"name\":\"saffron\",\"package_url\":\"https://github.com/cloudflare/saffron\",\"repository\":{\"Http\":{\"sha256\":\"03fb9a628596fc7590eb7edbf7b0613287be78df107f5f97b118aad59fb2eea9\",\"url\":\"https://static.crates.io/crates/saffron/0.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"saffron\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.0\"},\"same-file 1.0.6\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(windows)\":[{\"id\":\"winapi-util 0.1.11\",\"target\":\"winapi_util\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"same_file\",\"license\":\"Unlicense/MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"same-file\",\"package_url\":\"https://github.com/BurntSushi/same-file\",\"repository\":{\"Http\":{\"sha256\":\"93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502\",\"url\":\"https://static.crates.io/crates/same-file/1.0.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"same_file\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.6\"},\"schemars 1.2.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"derive\",\"indexmap2\",\"schemars_derive\",\"std\",\"url2\"],\"deps\":[{\"id\":\"dyn-clone 1.0.20\",\"target\":\"dyn_clone\"},{\"alias\":\"indexmap2\",\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"ref-cast 1.0.25\",\"target\":\"ref_cast\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.149\",\"target\":\"serde_json\"},{\"alias\":\"url2\",\"id\":\"url 2.5.8\",\"target\":\"url\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"schemars_derive 1.2.1\",\"target\":\"schemars_derive\"}]},\"library_target_name\":\"schemars\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"schemars\",\"package_url\":\"https://github.com/GREsau/schemars\",\"repository\":{\"Http\":{\"sha256\":\"a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc\",\"url\":\"https://static.crates.io/crates/schemars/1.2.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"schemars\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.1\"},\"schemars_derive 1.2.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"serde_derive_internals 0.29.1\",\"target\":\"serde_derive_internals\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"schemars_derive\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"schemars_derive\",\"package_url\":\"https://github.com/GREsau/schemars\",\"repository\":{\"Http\":{\"sha256\":\"7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f\",\"url\":\"https://static.crates.io/crates/schemars_derive/1.2.1/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"schemars_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.1\"},\"scopeguard 1.2.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"use_std\"],\"edition\":\"2015\"},\"library_target_name\":\"scopeguard\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"scopeguard\",\"package_url\":\"https://github.com/bluss/scopeguard\",\"repository\":{\"Http\":{\"sha256\":\"94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49\",\"url\":\"https://static.crates.io/crates/scopeguard/1.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"scopeguard\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.0\"},\"self_cell 1.2.2\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"self_cell\",\"license\":\"Apache-2.0 OR GPL-2.0-only\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"GPL-2.0\"],\"name\":\"self_cell\",\"package_url\":\"https://github.com/Voultapher/self_cell\",\"repository\":{\"Http\":{\"sha256\":\"b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89\",\"url\":\"https://static.crates.io/crates/self_cell/1.2.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"self_cell\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.2\"},\"semver 1.0.28\":{\"common_attrs\":{\"crate_features\":[\"default\",\"serde\",\"std\"],\"deps\":[{\"alias\":\"serde\",\"id\":\"serde_core 1.0.228\",\"target\":\"serde_core\"}],\"edition\":\"2021\"},\"library_target_name\":\"semver\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"semver\",\"package_url\":\"https://github.com/dtolnay/semver\",\"repository\":{\"Http\":{\"sha256\":\"8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd\",\"url\":\"https://static.crates.io/crates/semver/1.0.28/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"semver\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.28\"},\"serde 1.0.228\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"derive\",\"rc\",\"serde_derive\",\"std\"],\"deps\":[{\"id\":\"serde_core 1.0.228\",\"target\":\"serde_core\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":[{\"id\":\"serde_derive 1.0.228\",\"target\":\"serde_derive\"}]},\"library_target_name\":\"serde\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"serde\",\"package_url\":\"https://github.com/serde-rs/serde\",\"repository\":{\"Http\":{\"sha256\":\"9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e\",\"url\":\"https://static.crates.io/crates/serde/1.0.228/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"serde\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.228\"},\"serde-wasm-bindgen 0.6.5\":{\"common_attrs\":{\"deps\":[{\"id\":\"js-sys 0.3.95\",\"target\":\"js_sys\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"wasm-bindgen 0.2.118\",\"target\":\"wasm_bindgen\"}],\"edition\":\"2018\"},\"library_target_name\":\"serde_wasm_bindgen\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"serde-wasm-bindgen\",\"package_url\":\"https://github.com/RReverser/serde-wasm-bindgen\",\"repository\":{\"Http\":{\"sha256\":\"8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b\",\"url\":\"https://static.crates.io/crates/serde-wasm-bindgen/0.6.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"serde_wasm_bindgen\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.5\"},\"serde_core 1.0.228\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"rc\",\"result\",\"std\"],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":{\"common\":[],\"selects\":{\"cfg(any())\":[{\"id\":\"serde_derive 1.0.228\",\"target\":\"serde_derive\"}]}}},\"library_target_name\":\"serde_core\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"serde_core\",\"package_url\":\"https://github.com/serde-rs/serde\",\"repository\":{\"Http\":{\"sha256\":\"41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad\",\"url\":\"https://static.crates.io/crates/serde_core/1.0.228/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"serde_core\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.228\"},\"serde_derive 1.0.228\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"serde_derive\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"serde_derive\",\"package_url\":\"https://github.com/serde-rs/serde\",\"repository\":{\"Http\":{\"sha256\":\"d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79\",\"url\":\"https://static.crates.io/crates/serde_derive/1.0.228/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"serde_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.228\"},\"serde_derive_internals 0.29.1\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2015\"},\"library_target_name\":\"serde_derive_internals\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"serde_derive_internals\",\"package_url\":\"https://github.com/serde-rs/serde\",\"repository\":{\"Http\":{\"sha256\":\"18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711\",\"url\":\"https://static.crates.io/crates/serde_derive_internals/0.29.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"serde_derive_internals\",\"crate_root\":\"lib.rs\"}}],\"version\":\"0.29.1\"},\"serde_json 1.0.149\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"deps\":{\"common\":[{\"id\":\"itoa 1.0.18\",\"target\":\"itoa\"},{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"},{\"id\":\"serde_core 1.0.228\",\"target\":\"serde_core\"},{\"id\":\"zmij 1.0.21\",\"target\":\"zmij\"}],\"selects\":{\"cfg(any())\":[{\"id\":\"serde 1.0.228\",\"target\":\"serde\"}]}},\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"serde_json\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"serde_json\",\"package_url\":\"https://github.com/serde-rs/json\",\"repository\":{\"Http\":{\"sha256\":\"83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86\",\"url\":\"https://static.crates.io/crates/serde_json/1.0.149/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"serde_json\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.149\"},\"serde_spanned 1.1.1\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"serde\",\"std\"],\"deps\":[{\"id\":\"serde_core 1.0.228\",\"target\":\"serde_core\"}],\"edition\":\"2024\"},\"library_target_name\":\"serde_spanned\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"serde_spanned\",\"package_url\":\"https://github.com/toml-rs/toml\",\"repository\":{\"Http\":{\"sha256\":\"6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26\",\"url\":\"https://static.crates.io/crates/serde_spanned/1.1.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"serde_spanned\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.1\"},\"serde_yaml 0.9.34+deprecated\":{\"common_attrs\":{\"deps\":[{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"itoa 1.0.18\",\"target\":\"itoa\"},{\"id\":\"ryu 1.0.23\",\"target\":\"ryu\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"unsafe-libyaml 0.2.11\",\"target\":\"unsafe_libyaml\"}],\"edition\":\"2021\"},\"library_target_name\":\"serde_yaml\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"serde_yaml\",\"package_url\":\"https://github.com/dtolnay/serde-yaml\",\"repository\":{\"Http\":{\"sha256\":\"6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47\",\"url\":\"https://static.crates.io/crates/serde_yaml/0.9.34+deprecated/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"serde_yaml\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.9.34+deprecated\"},\"sha2 0.10.9\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"digest 0.10.7\",\"target\":\"digest\"}],\"selects\":{\"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\":[{\"id\":\"cpufeatures 0.2.17\",\"target\":\"cpufeatures\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"sha2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"sha2\",\"package_url\":\"https://github.com/RustCrypto/hashes\",\"repository\":{\"Http\":{\"sha256\":\"a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283\",\"url\":\"https://static.crates.io/crates/sha2/0.10.9/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"sha2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.10.9\"},\"sha2 0.11.0\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"oid\"],\"deps\":{\"common\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"digest 0.11.2\",\"target\":\"digest\"}],\"selects\":{\"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\":[{\"id\":\"cpufeatures 0.3.0\",\"target\":\"cpufeatures\"}]}},\"edition\":\"2024\"},\"library_target_name\":\"sha2\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"sha2\",\"package_url\":\"https://github.com/RustCrypto/hashes\",\"repository\":{\"Http\":{\"sha256\":\"446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4\",\"url\":\"https://static.crates.io/crates/sha2/0.11.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"sha2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.11.0\"},\"shared-buffer 0.1.4\":{\"common_attrs\":{\"deps\":[{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"memmap2 0.6.2\",\"target\":\"memmap2\"}],\"edition\":\"2021\"},\"library_target_name\":\"shared_buffer\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE_APACHE.md\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"shared-buffer\",\"package_url\":\"https://github.com/wasmerio/shared-buffer.git\",\"repository\":{\"Http\":{\"sha256\":\"f6c99835bad52957e7aa241d3975ed17c1e5f8c92026377d117a606f36b84b16\",\"url\":\"https://static.crates.io/crates/shared-buffer/0.1.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"shared_buffer\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.4\"},\"shlex 1.3.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2015\"},\"library_target_name\":\"shlex\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"shlex\",\"package_url\":\"https://github.com/comex/rust-shlex\",\"repository\":{\"Http\":{\"sha256\":\"0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64\",\"url\":\"https://static.crates.io/crates/shlex/1.3.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"shlex\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.3.0\"},\"simd-adler32 0.3.9\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"simd_adler32\",\"license\":\"MIT\",\"license_file\":\"LICENSE.md\",\"license_ids\":[\"MIT\"],\"name\":\"simd-adler32\",\"package_url\":\"https://github.com/mcountryman/simd-adler32\",\"repository\":{\"Http\":{\"sha256\":\"703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214\",\"url\":\"https://static.crates.io/crates/simd-adler32/0.3.9/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"simd_adler32\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.9\"},\"simdutf8 0.1.5\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"simdutf8\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-Apache\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"simdutf8\",\"package_url\":\"https://github.com/rusticstuff/simdutf8\",\"repository\":{\"Http\":{\"sha256\":\"e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e\",\"url\":\"https://static.crates.io/crates/simdutf8/0.1.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"simdutf8\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.5\"},\"similar 2.7.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"inline\",\"text\"],\"edition\":\"2018\"},\"library_target_name\":\"similar\",\"license\":\"Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"similar\",\"package_url\":\"https://github.com/mitsuhiko/similar\",\"repository\":{\"Http\":{\"sha256\":\"bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa\",\"url\":\"https://static.crates.io/crates/similar/2.7.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"similar\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.7.0\"},\"siphasher 1.0.2\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"siphasher\",\"license\":\"MIT/Apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"siphasher\",\"package_url\":\"https://github.com/jedisct1/rust-siphash\",\"repository\":{\"Http\":{\"sha256\":\"b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e\",\"url\":\"https://static.crates.io/crates/siphasher/1.0.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"siphasher\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.2\"},\"slab 0.4.12\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"slab\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"slab\",\"package_url\":\"https://github.com/tokio-rs/slab\",\"repository\":{\"Http\":{\"sha256\":\"0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5\",\"url\":\"https://static.crates.io/crates/slab/0.4.12/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"slab\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.12\"},\"smallvec 1.15.1\":{\"common_attrs\":{\"crate_features\":[\"const_generics\"],\"edition\":\"2018\"},\"library_target_name\":\"smallvec\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"smallvec\",\"package_url\":\"https://github.com/servo/rust-smallvec\",\"repository\":{\"Http\":{\"sha256\":\"67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03\",\"url\":\"https://static.crates.io/crates/smallvec/1.15.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"smallvec\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.15.1\"},\"smoltcp 0.13.0\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"alloc\",\"proto-ipv4\",\"std\"],\"deps\":[{\"id\":\"bitflags 1.3.2\",\"target\":\"bitflags\"},{\"id\":\"byteorder 1.5.0\",\"target\":\"byteorder\"},{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"heapless 0.9.2\",\"target\":\"heapless\"},{\"id\":\"managed 0.8.0\",\"target\":\"managed\"}],\"edition\":\"2024\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"smoltcp\",\"license\":\"0BSD\",\"license_file\":\"LICENSE-0BSD.txt\",\"license_ids\":[\"0BSD\"],\"name\":\"smoltcp\",\"package_url\":\"https://github.com/smoltcp-rs/smoltcp.git\",\"repository\":{\"Http\":{\"sha256\":\"ac729b0a77bd092a3f06ddaddc59fe0d67f48ba0de45a9abe707c2842c7f8767\",\"url\":\"https://static.crates.io/crates/smoltcp/0.13.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"smoltcp\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.13.0\"},\"stable_deref_trait 1.2.1\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2015\"},\"library_target_name\":\"stable_deref_trait\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"stable_deref_trait\",\"package_url\":\"https://github.com/storyyeller/stable_deref_trait\",\"repository\":{\"Http\":{\"sha256\":\"6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596\",\"url\":\"https://static.crates.io/crates/stable_deref_trait/1.2.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"stable_deref_trait\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.1\"},\"strsim 0.11.1\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"strsim\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"strsim\",\"package_url\":\"https://github.com/rapidfuzz/strsim-rs\",\"repository\":{\"Http\":{\"sha256\":\"7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f\",\"url\":\"https://static.crates.io/crates/strsim/0.11.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"strsim\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.11.1\"},\"symbolic-common 12.18.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"debugid 0.8.0\",\"target\":\"debugid\"},{\"id\":\"memmap2 0.9.10\",\"target\":\"memmap2\"},{\"id\":\"stable_deref_trait 1.2.1\",\"target\":\"stable_deref_trait\"},{\"id\":\"uuid 1.23.1\",\"target\":\"uuid\"}],\"edition\":\"2021\"},\"library_target_name\":\"symbolic_common\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"symbolic-common\",\"package_url\":\"https://github.com/getsentry/symbolic\",\"repository\":{\"Http\":{\"sha256\":\"332615d90111d8eeaf86a84dc9bbe9f65d0d8c5cf11b4caccedc37754eb0dcfd\",\"url\":\"https://static.crates.io/crates/symbolic-common/12.18.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"symbolic_common\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"12.18.3\"},\"symbolic-demangle 12.18.3\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"cpp\",\"cpp_demangle\",\"msvc\",\"msvc-demangler\",\"rust\",\"rustc-demangle\"],\"deps\":[{\"id\":\"cpp_demangle 0.4.5\",\"target\":\"cpp_demangle\"},{\"id\":\"msvc-demangler 0.11.0\",\"target\":\"msvc_demangler\"},{\"id\":\"rustc-demangle 0.1.27\",\"target\":\"rustc_demangle\"},{\"id\":\"symbolic-common 12.18.3\",\"target\":\"symbolic_common\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"symbolic_demangle\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"symbolic-demangle\",\"package_url\":\"https://github.com/getsentry/symbolic\",\"repository\":{\"Http\":{\"sha256\":\"912017718eb4d21930546245af9a3475c9dccf15675a5c215664e76621afc471\",\"url\":\"https://static.crates.io/crates/symbolic-demangle/12.18.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"symbolic_demangle\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"12.18.3\"},\"syn 1.0.109\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"clone-impls\",\"default\",\"derive\",\"parsing\",\"printing\",\"proc-macro\",\"quote\"],\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"unicode-ident 1.0.24\",\"target\":\"unicode_ident\"}],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"syn\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"syn\",\"package_url\":\"https://github.com/dtolnay/syn\",\"repository\":{\"Http\":{\"sha256\":\"72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237\",\"url\":\"https://static.crates.io/crates/syn/1.0.109/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"syn\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.109\"},\"syn 2.0.117\":{\"common_attrs\":{\"crate_features\":[\"clone-impls\",\"default\",\"derive\",\"extra-traits\",\"fold\",\"full\",\"parsing\",\"printing\",\"proc-macro\",\"visit\",\"visit-mut\"],\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"unicode-ident 1.0.24\",\"target\":\"unicode_ident\"}],\"edition\":\"2021\"},\"library_target_name\":\"syn\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"syn\",\"package_url\":\"https://github.com/dtolnay/syn\",\"repository\":{\"Http\":{\"sha256\":\"e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99\",\"url\":\"https://static.crates.io/crates/syn/2.0.117/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"syn\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.0.117\"},\"synstructure 0.13.2\":{\"common_attrs\":{\"crate_features\":[\"default\",\"proc-macro\"],\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2018\"},\"library_target_name\":\"synstructure\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"synstructure\",\"package_url\":\"https://github.com/mystor/synstructure\",\"repository\":{\"Http\":{\"sha256\":\"728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2\",\"url\":\"https://static.crates.io/crates/synstructure/0.13.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"synstructure\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.13.2\"},\"tar 0.4.45\":{\"common_attrs\":{\"crate_features\":[\"default\",\"xattr\"],\"deps\":{\"common\":[{\"id\":\"filetime 0.2.27\",\"target\":\"filetime\"},{\"id\":\"xattr 1.6.1\",\"target\":\"xattr\"}],\"selects\":{\"cfg(unix)\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"tar\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"tar\",\"package_url\":\"https://github.com/alexcrichton/tar-rs\",\"repository\":{\"Http\":{\"sha256\":\"22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973\",\"url\":\"https://static.crates.io/crates/tar/0.4.45/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tar\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.45\"},\"target-lexicon 0.13.5\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"target_lexicon\",\"license\":\"Apache-2.0 WITH LLVM-exception\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"target-lexicon\",\"package_url\":\"https://github.com/bytecodealliance/target-lexicon\",\"repository\":{\"Http\":{\"sha256\":\"adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca\",\"url\":\"https://static.crates.io/crates/target-lexicon/0.13.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"target_lexicon\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.13.5\"},\"tempfile 3.27.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"getrandom\"],\"deps\":{\"common\":[{\"id\":\"fastrand 2.4.1\",\"target\":\"fastrand\"},{\"id\":\"getrandom 0.4.2\",\"target\":\"getrandom\"},{\"id\":\"once_cell 1.21.4\",\"target\":\"once_cell\"}],\"selects\":{\"cfg(any(unix, target_os = \\\"wasi\\\"))\":[{\"id\":\"rustix 1.1.4\",\"target\":\"rustix\"}],\"cfg(windows)\":[{\"id\":\"windows-sys 0.61.2\",\"target\":\"windows_sys\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"tempfile\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"tempfile\",\"package_url\":\"https://github.com/Stebalien/tempfile\",\"repository\":{\"Http\":{\"sha256\":\"32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd\",\"url\":\"https://static.crates.io/crates/tempfile/3.27.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tempfile\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"3.27.0\"},\"terminal_size 0.4.4\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(unix)\":[{\"id\":\"rustix 1.1.4\",\"target\":\"rustix\"}],\"cfg(windows)\":[{\"id\":\"windows-sys 0.61.2\",\"target\":\"windows_sys\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"terminal_size\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"terminal_size\",\"package_url\":\"https://github.com/eminence/terminal-size\",\"repository\":{\"Http\":{\"sha256\":\"230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874\",\"url\":\"https://static.crates.io/crates/terminal_size/0.4.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"terminal_size\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.4\"},\"termios 0.3.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"edition\":\"2015\"},\"library_target_name\":\"termios\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"termios\",\"package_url\":\"https://github.com/dcuddeback/termios-rs\",\"repository\":{\"Http\":{\"sha256\":\"411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b\",\"url\":\"https://static.crates.io/crates/termios/0.3.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"termios\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.3\"},\"thiserror 2.0.18\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":[{\"id\":\"thiserror-impl 2.0.18\",\"target\":\"thiserror_impl\"}]},\"library_target_name\":\"thiserror\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"thiserror\",\"package_url\":\"https://github.com/dtolnay/thiserror\",\"repository\":{\"Http\":{\"sha256\":\"4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4\",\"url\":\"https://static.crates.io/crates/thiserror/2.0.18/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"thiserror\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"2.0.18\"},\"thiserror-impl 2.0.18\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"thiserror_impl\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"thiserror-impl\",\"package_url\":\"https://github.com/dtolnay/thiserror\",\"repository\":{\"Http\":{\"sha256\":\"ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5\",\"url\":\"https://static.crates.io/crates/thiserror-impl/2.0.18/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"thiserror_impl\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.0.18\"},\"time 0.3.47\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"formatting\",\"std\"],\"deps\":[{\"id\":\"deranged 0.5.8\",\"target\":\"deranged\"},{\"id\":\"itoa 1.0.18\",\"target\":\"itoa\"},{\"id\":\"num-conv 0.2.1\",\"target\":\"num_conv\"},{\"id\":\"powerfmt 0.2.0\",\"target\":\"powerfmt\"},{\"id\":\"time-core 0.1.8\",\"target\":\"time_core\"}],\"edition\":\"2024\"},\"library_target_name\":\"time\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-Apache\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"time\",\"package_url\":\"https://github.com/time-rs/time\",\"repository\":{\"Http\":{\"sha256\":\"743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c\",\"url\":\"https://static.crates.io/crates/time/0.3.47/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"time\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.3.47\"},\"time-core 0.1.8\":{\"common_attrs\":{\"edition\":\"2024\"},\"library_target_name\":\"time_core\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-Apache\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"time-core\",\"package_url\":\"https://github.com/time-rs/time\",\"repository\":{\"Http\":{\"sha256\":\"7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca\",\"url\":\"https://static.crates.io/crates/time-core/0.1.8/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"time_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.8\"},\"time-macros 0.2.27\":{\"common_attrs\":{\"deps\":[{\"id\":\"num-conv 0.2.1\",\"target\":\"num_conv\"},{\"id\":\"time-core 0.1.8\",\"target\":\"time_core\"}],\"edition\":\"2024\"},\"library_target_name\":\"time_macros\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-Apache\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"time-macros\",\"package_url\":\"https://github.com/time-rs/time\",\"repository\":{\"Http\":{\"sha256\":\"2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215\",\"url\":\"https://static.crates.io/crates/time-macros/0.2.27/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"time_macros\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.27\"},\"tinystr 0.8.3\":{\"common_attrs\":{\"crate_features\":[\"zerovec\"],\"deps\":[{\"id\":\"zerovec 0.11.6\",\"target\":\"zerovec\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"displaydoc 0.2.5\",\"target\":\"displaydoc\"}]},\"library_target_name\":\"tinystr\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"tinystr\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d\",\"url\":\"https://static.crates.io/crates/tinystr/0.8.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tinystr\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.3\"},\"tinyvec 1.11.0\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"tinyvec_macros\"],\"deps\":[{\"id\":\"tinyvec_macros 0.1.1\",\"target\":\"tinyvec_macros\"}],\"edition\":\"2018\"},\"library_target_name\":\"tinyvec\",\"license\":\"Zlib OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE.md\",\"license_ids\":[\"Apache-2.0\",\"MIT\",\"Zlib\"],\"name\":\"tinyvec\",\"package_url\":\"https://github.com/Lokathor/tinyvec\",\"repository\":{\"Http\":{\"sha256\":\"3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3\",\"url\":\"https://static.crates.io/crates/tinyvec/1.11.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tinyvec\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.11.0\"},\"tinyvec_macros 0.1.1\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"tinyvec_macros\",\"license\":\"MIT OR Apache-2.0 OR Zlib\",\"license_file\":\"LICENSE-APACHE.md\",\"license_ids\":[\"Apache-2.0\",\"MIT\",\"Zlib\"],\"name\":\"tinyvec_macros\",\"package_url\":\"https://github.com/Soveu/tinyvec_macros\",\"repository\":{\"Http\":{\"sha256\":\"1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20\",\"url\":\"https://static.crates.io/crates/tinyvec_macros/0.1.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tinyvec_macros\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.1\"},\"tokio 1.52.1\":{\"common_attrs\":{\"crate_features\":[\"bytes\",\"default\",\"fs\",\"io-util\",\"macros\",\"rt\",\"rt-multi-thread\",\"sync\",\"time\",\"tokio-macros\"],\"deps\":[{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"pin-project-lite 0.2.17\",\"target\":\"pin_project_lite\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"tokio-macros 2.7.0\",\"target\":\"tokio_macros\"}]},\"library_target_name\":\"tokio\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tokio\",\"package_url\":\"https://github.com/tokio-rs/tokio\",\"repository\":{\"Http\":{\"sha256\":\"b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6\",\"url\":\"https://static.crates.io/crates/tokio/1.52.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tokio\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.52.1\"},\"tokio-macros 2.7.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"tokio_macros\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tokio-macros\",\"package_url\":\"https://github.com/tokio-rs/tokio\",\"repository\":{\"Http\":{\"sha256\":\"385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496\",\"url\":\"https://static.crates.io/crates/tokio-macros/2.7.0/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"tokio_macros\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.7.0\"},\"tokio-stream 0.1.18\":{\"common_attrs\":{\"crate_features\":[\"default\",\"sync\",\"time\",\"tokio-util\"],\"deps\":[{\"id\":\"futures-core 0.3.32\",\"target\":\"futures_core\"},{\"id\":\"pin-project-lite 0.2.17\",\"target\":\"pin_project_lite\"},{\"id\":\"tokio 1.52.1\",\"target\":\"tokio\"},{\"id\":\"tokio-util 0.7.18\",\"target\":\"tokio_util\"}],\"edition\":\"2021\"},\"library_target_name\":\"tokio_stream\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tokio-stream\",\"package_url\":\"https://github.com/tokio-rs/tokio\",\"repository\":{\"Http\":{\"sha256\":\"32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70\",\"url\":\"https://static.crates.io/crates/tokio-stream/0.1.18/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tokio_stream\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.18\"},\"tokio-util 0.7.18\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"deps\":[{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"futures-core 0.3.32\",\"target\":\"futures_core\"},{\"id\":\"futures-sink 0.3.32\",\"target\":\"futures_sink\"},{\"id\":\"pin-project-lite 0.2.17\",\"target\":\"pin_project_lite\"},{\"id\":\"tokio 1.52.1\",\"target\":\"tokio\"}],\"edition\":\"2021\"},\"library_target_name\":\"tokio_util\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tokio-util\",\"package_url\":\"https://github.com/tokio-rs/tokio\",\"repository\":{\"Http\":{\"sha256\":\"9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098\",\"url\":\"https://static.crates.io/crates/tokio-util/0.7.18/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tokio_util\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.7.18\"},\"toml 1.1.2+spec-1.1.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"display\",\"parse\",\"preserve_order\",\"serde\",\"std\"],\"deps\":[{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"serde_core 1.0.228\",\"target\":\"serde_core\"},{\"id\":\"serde_spanned 1.1.1\",\"target\":\"serde_spanned\"},{\"id\":\"toml_datetime 1.1.1+spec-1.1.0\",\"target\":\"toml_datetime\"},{\"id\":\"toml_parser 1.1.2+spec-1.1.0\",\"target\":\"toml_parser\"},{\"id\":\"toml_writer 1.1.1+spec-1.1.0\",\"target\":\"toml_writer\"},{\"id\":\"winnow 1.0.2\",\"target\":\"winnow\"}],\"edition\":\"2024\"},\"library_target_name\":\"toml\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"toml\",\"package_url\":\"https://github.com/toml-rs/toml\",\"repository\":{\"Http\":{\"sha256\":\"81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee\",\"url\":\"https://static.crates.io/crates/toml/1.1.2+spec-1.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"toml\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.2+spec-1.1.0\"},\"toml_datetime 1.1.1+spec-1.1.0\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"serde\",\"std\"],\"deps\":[{\"id\":\"serde_core 1.0.228\",\"target\":\"serde_core\"}],\"edition\":\"2024\"},\"library_target_name\":\"toml_datetime\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"toml_datetime\",\"package_url\":\"https://github.com/toml-rs/toml\",\"repository\":{\"Http\":{\"sha256\":\"3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7\",\"url\":\"https://static.crates.io/crates/toml_datetime/1.1.1+spec-1.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"toml_datetime\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.1+spec-1.1.0\"},\"toml_edit 0.25.11+spec-1.1.0\":{\"common_attrs\":{\"crate_features\":[\"parse\"],\"deps\":[{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"toml_datetime 1.1.1+spec-1.1.0\",\"target\":\"toml_datetime\"},{\"id\":\"toml_parser 1.1.2+spec-1.1.0\",\"target\":\"toml_parser\"},{\"id\":\"winnow 1.0.2\",\"target\":\"winnow\"}],\"edition\":\"2024\"},\"library_target_name\":\"toml_edit\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"toml_edit\",\"package_url\":\"https://github.com/toml-rs/toml\",\"repository\":{\"Http\":{\"sha256\":\"0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b\",\"url\":\"https://static.crates.io/crates/toml_edit/0.25.11+spec-1.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"toml_edit\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.25.11+spec-1.1.0\"},\"toml_parser 1.1.2+spec-1.1.0\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"deps\":[{\"id\":\"winnow 1.0.2\",\"target\":\"winnow\"}],\"edition\":\"2024\"},\"library_target_name\":\"toml_parser\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"toml_parser\",\"package_url\":\"https://github.com/toml-rs/toml\",\"repository\":{\"Http\":{\"sha256\":\"a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526\",\"url\":\"https://static.crates.io/crates/toml_parser/1.1.2+spec-1.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"toml_parser\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.2+spec-1.1.0\"},\"toml_writer 1.1.1+spec-1.1.0\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"std\"],\"edition\":\"2024\"},\"library_target_name\":\"toml_writer\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"toml_writer\",\"package_url\":\"https://github.com/toml-rs/toml\",\"repository\":{\"Http\":{\"sha256\":\"756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db\",\"url\":\"https://static.crates.io/crates/toml_writer/1.1.1+spec-1.1.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"toml_writer\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.1.1+spec-1.1.0\"},\"tracing 0.1.44\":{\"common_attrs\":{\"crate_features\":[\"attributes\",\"default\",\"log\",\"std\",\"tracing-attributes\"],\"deps\":[{\"id\":\"log 0.4.29\",\"target\":\"log\"},{\"id\":\"pin-project-lite 0.2.17\",\"target\":\"pin_project_lite\"},{\"id\":\"tracing-core 0.1.36\",\"target\":\"tracing_core\"}],\"edition\":\"2018\",\"proc_macro_deps\":[{\"id\":\"tracing-attributes 0.1.31\",\"target\":\"tracing_attributes\"}]},\"library_target_name\":\"tracing\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tracing\",\"package_url\":\"https://github.com/tokio-rs/tracing\",\"repository\":{\"Http\":{\"sha256\":\"63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100\",\"url\":\"https://static.crates.io/crates/tracing/0.1.44/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tracing\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.44\"},\"tracing-attributes 0.1.31\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2018\"},\"library_target_name\":\"tracing_attributes\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tracing-attributes\",\"package_url\":\"https://github.com/tokio-rs/tracing\",\"repository\":{\"Http\":{\"sha256\":\"7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da\",\"url\":\"https://static.crates.io/crates/tracing-attributes/0.1.31/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"tracing_attributes\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.31\"},\"tracing-core 0.1.36\":{\"common_attrs\":{\"crate_features\":[\"once_cell\",\"std\"],\"deps\":[{\"id\":\"once_cell 1.21.4\",\"target\":\"once_cell\"}],\"edition\":\"2018\"},\"library_target_name\":\"tracing_core\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"tracing-core\",\"package_url\":\"https://github.com/tokio-rs/tracing\",\"repository\":{\"Http\":{\"sha256\":\"db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a\",\"url\":\"https://static.crates.io/crates/tracing-core/0.1.36/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"tracing_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.36\"},\"twox-hash 2.1.2\":{\"common_attrs\":{\"crate_features\":[\"xxhash32\",\"xxhash64\"],\"edition\":\"2021\"},\"library_target_name\":\"twox_hash\",\"license\":\"MIT\",\"license_file\":\"LICENSE.txt\",\"license_ids\":[\"MIT\"],\"name\":\"twox-hash\",\"package_url\":\"https://github.com/shepmaster/twox-hash\",\"repository\":{\"Http\":{\"sha256\":\"9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c\",\"url\":\"https://static.crates.io/crates/twox-hash/2.1.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"twox_hash\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.1.2\"},\"typenum 1.20.0\":{\"common_attrs\":{\"crate_features\":[\"const-generics\"],\"edition\":\"2018\"},\"library_target_name\":\"typenum\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"typenum\",\"package_url\":\"https://github.com/paholg/typenum\",\"repository\":{\"Http\":{\"sha256\":\"40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de\",\"url\":\"https://static.crates.io/crates/typenum/1.20.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"typenum\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.20.0\"},\"unicase 2.9.0\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"unicase\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"unicase\",\"package_url\":\"https://github.com/seanmonstar/unicase\",\"repository\":{\"Http\":{\"sha256\":\"dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142\",\"url\":\"https://static.crates.io/crates/unicase/2.9.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"unicase\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.9.0\"},\"unicode-ident 1.0.24\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"unicode_ident\",\"license\":\"(MIT OR Apache-2.0) AND Unicode-3.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\",\"Unicode-3.0\"],\"name\":\"unicode-ident\",\"package_url\":\"https://github.com/dtolnay/unicode-ident\",\"repository\":{\"Http\":{\"sha256\":\"e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75\",\"url\":\"https://static.crates.io/crates/unicode-ident/1.0.24/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"unicode_ident\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.24\"},\"unicode-normalization 0.1.25\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"deps\":[{\"id\":\"tinyvec 1.11.0\",\"target\":\"tinyvec\"}],\"edition\":\"2018\"},\"library_target_name\":\"unicode_normalization\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"unicode-normalization\",\"package_url\":\"https://github.com/unicode-rs/unicode-normalization\",\"repository\":{\"Http\":{\"sha256\":\"5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8\",\"url\":\"https://static.crates.io/crates/unicode-normalization/0.1.25/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"unicode_normalization\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.25\"},\"unicode-segmentation 1.13.2\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"unicode_segmentation\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"unicode-segmentation\",\"package_url\":\"https://github.com/unicode-rs/unicode-segmentation\",\"repository\":{\"Http\":{\"sha256\":\"9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c\",\"url\":\"https://static.crates.io/crates/unicode-segmentation/1.13.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"unicode_segmentation\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.13.2\"},\"unicode-width 0.2.2\":{\"common_attrs\":{\"crate_features\":[\"cjk\",\"default\"],\"edition\":\"2021\"},\"library_target_name\":\"unicode_width\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"unicode-width\",\"package_url\":\"https://github.com/unicode-rs/unicode-width\",\"repository\":{\"Http\":{\"sha256\":\"b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254\",\"url\":\"https://static.crates.io/crates/unicode-width/0.2.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"unicode_width\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.2\"},\"unicode-xid 0.2.6\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"edition\":\"2015\"},\"library_target_name\":\"unicode_xid\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"unicode-xid\",\"package_url\":\"https://github.com/unicode-rs/unicode-xid\",\"repository\":{\"Http\":{\"sha256\":\"ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853\",\"url\":\"https://static.crates.io/crates/unicode-xid/0.2.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"unicode_xid\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.6\"},\"unsafe-libyaml 0.2.11\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"unsafe_libyaml\",\"license\":\"MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\"],\"name\":\"unsafe-libyaml\",\"package_url\":\"https://github.com/dtolnay/unsafe-libyaml\",\"repository\":{\"Http\":{\"sha256\":\"673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861\",\"url\":\"https://static.crates.io/crates/unsafe-libyaml/0.2.11/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"unsafe_libyaml\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.11\"},\"unty 0.0.4\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"unty\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"unty\",\"package_url\":\"https://github.com/bincode-org/unty\",\"repository\":{\"Http\":{\"sha256\":\"6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae\",\"url\":\"https://static.crates.io/crates/unty/0.0.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"unty\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.0.4\"},\"url 2.5.8\":{\"common_attrs\":{\"crate_features\":[\"default\",\"serde\",\"std\"],\"deps\":[{\"id\":\"form_urlencoded 1.2.2\",\"target\":\"form_urlencoded\"},{\"id\":\"idna 1.1.0\",\"target\":\"idna\"},{\"id\":\"percent-encoding 2.3.2\",\"target\":\"percent_encoding\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"}],\"edition\":\"2018\",\"proc_macro_deps\":[{\"id\":\"serde_derive 1.0.228\",\"target\":\"serde_derive\"}]},\"library_target_name\":\"url\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"url\",\"package_url\":\"https://github.com/servo/rust-url\",\"repository\":{\"Http\":{\"sha256\":\"ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed\",\"url\":\"https://static.crates.io/crates/url/2.5.8/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"url\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.5.8\"},\"urlencoding 2.1.3\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"urlencoding\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"urlencoding\",\"package_url\":\"https://github.com/kornelski/rust_urlencoding\",\"repository\":{\"Http\":{\"sha256\":\"daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da\",\"url\":\"https://static.crates.io/crates/urlencoding/2.1.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"urlencoding\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.1.3\"},\"utf8_iter 1.0.4\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"utf8_iter\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"utf8_iter\",\"package_url\":\"https://github.com/hsivonen/utf8_iter\",\"repository\":{\"Http\":{\"sha256\":\"b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be\",\"url\":\"https://static.crates.io/crates/utf8_iter/1.0.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"utf8_iter\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.4\"},\"uuid 1.23.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"uuid\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"uuid\",\"package_url\":\"https://github.com/uuid-rs/uuid\",\"repository\":{\"Http\":{\"sha256\":\"ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76\",\"url\":\"https://static.crates.io/crates/uuid/1.23.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"uuid\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.23.1\"},\"version_check 0.9.5\":{\"common_attrs\":{\"edition\":\"2015\"},\"library_target_name\":\"version_check\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"version_check\",\"package_url\":\"https://github.com/SergioBenitez/version_check\",\"repository\":{\"Http\":{\"sha256\":\"0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a\",\"url\":\"https://static.crates.io/crates/version_check/0.9.5/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"version_check\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.9.5\"},\"virtual-fs 0.702.0-alpha.2\":{\"common_attrs\":{\"crate_features\":[\"anyhow\",\"webc\",\"webc-fs\"],\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"dashmap 6.1.0\",\"target\":\"dashmap\"},{\"id\":\"derive_more 2.1.1\",\"target\":\"derive_more\"},{\"id\":\"dunce 1.0.5\",\"target\":\"dunce\"},{\"id\":\"futures 0.3.32\",\"target\":\"futures\"},{\"id\":\"getrandom 0.4.2\",\"target\":\"getrandom\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"pin-project-lite 0.2.17\",\"target\":\"pin_project_lite\"},{\"id\":\"replace_with 0.1.8\",\"target\":\"replace_with\"},{\"id\":\"shared-buffer 0.1.4\",\"target\":\"shared_buffer\"},{\"id\":\"slab 0.4.12\",\"target\":\"slab\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"tokio 1.52.1\",\"target\":\"tokio\"},{\"id\":\"tracing 0.1.44\",\"target\":\"tracing\"},{\"id\":\"virtual-mio 0.702.0-alpha.2\",\"target\":\"virtual_mio\"},{\"id\":\"wasmer-package 0.702.0-alpha.2\",\"target\":\"wasmer_package\"},{\"id\":\"webc 11.0.0\",\"target\":\"webc\"}],\"edition\":\"2024\",\"proc_macro_deps\":[{\"id\":\"async-trait 0.1.89\",\"target\":\"async_trait\"}]},\"library_target_name\":\"virtual_fs\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"virtual-fs\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[\"@@+_repo_rules31+postmaster_cargo//:patches/cargo/virtual-fs.patch\"],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/virtual-fs\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"virtual_fs\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.702.0-alpha.2\"},\"virtual-mio 0.702.0-alpha.2\":{\"common_attrs\":{\"deps\":[{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"futures 0.3.32\",\"target\":\"futures\"},{\"id\":\"parking 2.2.1\",\"target\":\"parking\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"tracing 0.1.44\",\"target\":\"tracing\"}],\"edition\":\"2024\",\"proc_macro_deps\":[{\"id\":\"async-trait 0.1.89\",\"target\":\"async_trait\"}]},\"library_target_name\":\"virtual_mio\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"virtual-mio\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[\"@@+_repo_rules31+postmaster_cargo//:patches/cargo/virtual-mio.patch\"],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/virtual-io\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"virtual_mio\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.702.0-alpha.2\"},\"virtual-net 0.702.0-alpha.2\":{\"common_attrs\":{\"crate_features\":[\"rkyv\"],\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"base64 0.22.1\",\"target\":\"base64\"},{\"id\":\"bincode 2.0.1\",\"target\":\"bincode\"},{\"id\":\"bytecheck 0.8.2\",\"target\":\"bytecheck\"},{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"derive_more 2.1.1\",\"target\":\"derive_more\"},{\"id\":\"futures-util 0.3.32\",\"target\":\"futures_util\"},{\"id\":\"ipnet 2.12.0\",\"target\":\"ipnet\"},{\"id\":\"iprange 0.6.7\",\"target\":\"iprange\"},{\"id\":\"pin-project-lite 0.2.17\",\"target\":\"pin_project_lite\"},{\"id\":\"rkyv 0.8.16\",\"target\":\"rkyv\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"smoltcp 0.13.0\",\"target\":\"smoltcp\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"tokio 1.52.1\",\"target\":\"tokio\"},{\"id\":\"tracing 0.1.44\",\"target\":\"tracing\"},{\"id\":\"virtual-mio 0.702.0-alpha.2\",\"target\":\"virtual_mio\"}],\"edition\":\"2024\",\"proc_macro_deps\":[{\"id\":\"async-trait 0.1.89\",\"target\":\"async_trait\"}]},\"library_target_name\":\"virtual_net\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"virtual-net\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[\"@@+_repo_rules31+postmaster_cargo//:patches/cargo/virtual-net.patch\"],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/virtual-net\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"virtual_net\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.702.0-alpha.2\"},\"virtue 0.0.18\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"virtue\",\"license\":\"MIT\",\"license_file\":\"LICENSE.md\",\"license_ids\":[\"MIT\"],\"name\":\"virtue\",\"package_url\":\"https://github.com/bincode-org/virtue\",\"repository\":{\"Http\":{\"sha256\":\"051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1\",\"url\":\"https://static.crates.io/crates/virtue/0.0.18/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"virtue\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.0.18\"},\"wai-bindgen-gen-core 0.2.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"wai-parser 0.2.3\",\"target\":\"wai_parser\"}],\"edition\":\"2021\"},\"library_target_name\":\"wai_bindgen_gen_core\",\"license\":\"Apache-2.0\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"wai-bindgen-gen-core\",\"package_url\":\"https://github.com/wasmerio/wai\",\"repository\":{\"Http\":{\"sha256\":\"1aa3dc41b510811122b3088197234c27e08fcad63ef936306dd8e11e2803876c\",\"url\":\"https://static.crates.io/crates/wai-bindgen-gen-core/0.2.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wai_bindgen_gen_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.3\"},\"wai-bindgen-gen-rust 0.2.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"heck 0.3.3\",\"target\":\"heck\"},{\"id\":\"wai-bindgen-gen-core 0.2.3\",\"target\":\"wai_bindgen_gen_core\"}],\"edition\":\"2021\"},\"library_target_name\":\"wai_bindgen_gen_rust\",\"license\":\"Apache-2.0\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"wai-bindgen-gen-rust\",\"package_url\":\"https://github.com/wasmerio/wai\",\"repository\":{\"Http\":{\"sha256\":\"19bc05e8380515c4337c40ef03b2ff233e391315b178a320de8640703d522efe\",\"url\":\"https://static.crates.io/crates/wai-bindgen-gen-rust/0.2.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wai_bindgen_gen_rust\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.3\"},\"wai-bindgen-gen-rust-wasm 0.2.3\":{\"build_script_attrs\":{},\"common_attrs\":{\"deps\":[{\"id\":\"heck 0.3.3\",\"target\":\"heck\"},{\"id\":\"wai-bindgen-gen-core 0.2.3\",\"target\":\"wai_bindgen_gen_core\"},{\"id\":\"wai-bindgen-gen-rust 0.2.3\",\"target\":\"wai_bindgen_gen_rust\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"wai_bindgen_gen_rust_wasm\",\"license\":\"Apache-2.0\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"wai-bindgen-gen-rust-wasm\",\"package_url\":\"https://github.com/wasmerio/wai\",\"repository\":{\"Http\":{\"sha256\":\"d6f35ce5e74086fac87f3a7bd50f643f00fe3559adb75c88521ecaa01c8a6199\",\"url\":\"https://static.crates.io/crates/wai-bindgen-gen-rust-wasm/0.2.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wai_bindgen_gen_rust_wasm\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.2.3\"},\"wai-bindgen-rust 0.2.3\":{\"common_attrs\":{\"crate_features\":[\"macros\",\"wai-bindgen-rust-impl\"],\"deps\":[{\"id\":\"bitflags 1.3.2\",\"target\":\"bitflags\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"wai-bindgen-rust-impl 0.2.3\",\"target\":\"wai_bindgen_rust_impl\"}]},\"library_target_name\":\"wai_bindgen_rust\",\"license\":\"Apache-2.0\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"wai-bindgen-rust\",\"package_url\":\"https://github.com/wasmerio/wai\",\"repository\":{\"Http\":{\"sha256\":\"4e5601c6f448c063e83a5e931b8fefcdf7e01ada424ad42372c948d2e3d67741\",\"url\":\"https://static.crates.io/crates/wai-bindgen-rust/0.2.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wai_bindgen_rust\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.3\"},\"wai-bindgen-rust-impl 0.2.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"syn 1.0.109\",\"target\":\"syn\"},{\"id\":\"wai-bindgen-gen-core 0.2.3\",\"target\":\"wai_bindgen_gen_core\"},{\"id\":\"wai-bindgen-gen-rust-wasm 0.2.3\",\"target\":\"wai_bindgen_gen_rust_wasm\"}],\"edition\":\"2021\"},\"library_target_name\":\"wai_bindgen_rust_impl\",\"license\":\"Apache-2.0\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"wai-bindgen-rust-impl\",\"package_url\":\"https://github.com/wasmerio/wai\",\"repository\":{\"Http\":{\"sha256\":\"bdeeb5c1170246de8425a3e123e7ef260dc05ba2b522a1d369fe2315376efea4\",\"url\":\"https://static.crates.io/crates/wai-bindgen-rust-impl/0.2.3/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"wai_bindgen_rust_impl\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.3\"},\"wai-parser 0.2.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"id-arena 2.3.0\",\"target\":\"id_arena\"},{\"id\":\"pulldown-cmark 0.8.0\",\"target\":\"pulldown_cmark\"},{\"id\":\"unicode-normalization 0.1.25\",\"target\":\"unicode_normalization\"},{\"id\":\"unicode-xid 0.2.6\",\"target\":\"unicode_xid\"}],\"edition\":\"2021\"},\"library_target_name\":\"wai_parser\",\"license\":\"Apache-2.0\",\"license_ids\":[\"Apache-2.0\"],\"name\":\"wai-parser\",\"package_url\":\"https://github.com/wasmerio/wai\",\"repository\":{\"Http\":{\"sha256\":\"9bd0acb6d70885ea0c343749019ba74f015f64a9d30542e66db69b49b7e28186\",\"url\":\"https://static.crates.io/crates/wai-parser/0.2.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wai_parser\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.3\"},\"waker-fn 1.2.0\":{\"common_attrs\":{\"edition\":\"2018\"},\"library_target_name\":\"waker_fn\",\"license\":\"Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"waker-fn\",\"package_url\":\"https://github.com/smol-rs/waker-fn\",\"repository\":{\"Http\":{\"sha256\":\"317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7\",\"url\":\"https://static.crates.io/crates/waker-fn/1.2.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"waker_fn\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.2.0\"},\"walkdir 2.5.0\":{\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"same-file 1.0.6\",\"target\":\"same_file\"}],\"selects\":{\"cfg(windows)\":[{\"id\":\"winapi-util 0.1.11\",\"target\":\"winapi_util\"}]}},\"edition\":\"2018\"},\"library_target_name\":\"walkdir\",\"license\":\"Unlicense/MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"walkdir\",\"package_url\":\"https://github.com/BurntSushi/walkdir\",\"repository\":{\"Http\":{\"sha256\":\"29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b\",\"url\":\"https://static.crates.io/crates/walkdir/2.5.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"walkdir\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"2.5.0\"},\"wasip2 1.0.3+wasi-0.2.9\":{\"common_attrs\":{\"deps\":[{\"id\":\"wit-bindgen 0.57.1\",\"target\":\"wit_bindgen\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasip2\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasip2\",\"package_url\":\"https://github.com/bytecodealliance/wasi-rs\",\"repository\":{\"Http\":{\"sha256\":\"20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6\",\"url\":\"https://static.crates.io/crates/wasip2/1.0.3+wasi-0.2.9/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasip2\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.3+wasi-0.2.9\"},\"wasip3 0.4.0+wasi-0.3.0-rc-2026-01-06\":{\"common_attrs\":{\"deps\":[{\"id\":\"wit-bindgen 0.51.0\",\"target\":\"wit_bindgen\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasip3\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasip3\",\"package_url\":\"https://github.com/bytecodealliance/wasi-rs\",\"repository\":{\"Http\":{\"sha256\":\"5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5\",\"url\":\"https://static.crates.io/crates/wasip3/0.4.0+wasi-0.3.0-rc-2026-01-06/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasip3\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.4.0+wasi-0.3.0-rc-2026-01-06\"},\"wasm-bindgen 0.2.118\":{\"build_script_attrs\":{\"link_deps\":[{\"id\":\"wasm-bindgen-shared 0.2.118\",\"target\":\"wasm_bindgen_shared\"}],\"proc_macro_deps\":[{\"alias\":\"rustversion_compat\",\"id\":\"rustversion 1.0.22\",\"target\":\"rustversion\"}]},\"common_attrs\":{\"deps\":[{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"once_cell 1.21.4\",\"target\":\"once_cell\"},{\"id\":\"wasm-bindgen-shared 0.2.118\",\"target\":\"wasm_bindgen_shared\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":[{\"id\":\"wasm-bindgen-macro 0.2.118\",\"target\":\"wasm_bindgen_macro\"}]},\"library_target_name\":\"wasm_bindgen\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-bindgen\",\"package_url\":\"https://github.com/wasm-bindgen/wasm-bindgen\",\"repository\":{\"Http\":{\"sha256\":\"0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89\",\"url\":\"https://static.crates.io/crates/wasm-bindgen/0.2.118/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasm_bindgen\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.2.118\"},\"wasm-bindgen-macro 0.2.118\":{\"common_attrs\":{\"deps\":[{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"wasm-bindgen-macro-support 0.2.118\",\"target\":\"wasm_bindgen_macro_support\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasm_bindgen_macro\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-bindgen-macro\",\"package_url\":\"https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/macro\",\"repository\":{\"Http\":{\"sha256\":\"eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed\",\"url\":\"https://static.crates.io/crates/wasm-bindgen-macro/0.2.118/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"wasm_bindgen_macro\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.118\"},\"wasm-bindgen-macro-support 0.2.118\":{\"common_attrs\":{\"deps\":[{\"id\":\"bumpalo 3.20.2\",\"target\":\"bumpalo\"},{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"},{\"id\":\"wasm-bindgen-shared 0.2.118\",\"target\":\"wasm_bindgen_shared\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasm_bindgen_macro_support\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-bindgen-macro-support\",\"package_url\":\"https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/macro-support\",\"repository\":{\"Http\":{\"sha256\":\"9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904\",\"url\":\"https://static.crates.io/crates/wasm-bindgen-macro-support/0.2.118/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasm_bindgen_macro_support\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.118\"},\"wasm-bindgen-shared 0.2.118\":{\"build_script_attrs\":{\"links\":\"wasm_bindgen\"},\"common_attrs\":{\"deps\":[{\"id\":\"unicode-ident 1.0.24\",\"target\":\"unicode_ident\"}],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"wasm_bindgen_shared\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-bindgen-shared\",\"package_url\":\"https://github.com/wasm-bindgen/wasm-bindgen/tree/master/crates/shared\",\"repository\":{\"Http\":{\"sha256\":\"5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129\",\"url\":\"https://static.crates.io/crates/wasm-bindgen-shared/0.2.118/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasm_bindgen_shared\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.2.118\"},\"wasm-encoder 0.244.0\":{\"common_attrs\":{\"crate_features\":[\"component-model\",\"std\",\"wasmparser\"],\"deps\":[{\"id\":\"leb128fmt 0.1.0\",\"target\":\"leb128fmt\"},{\"id\":\"wasmparser 0.244.0\",\"target\":\"wasmparser\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasm_encoder\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-encoder\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-encoder\",\"repository\":{\"Http\":{\"sha256\":\"990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319\",\"url\":\"https://static.crates.io/crates/wasm-encoder/0.244.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasm_encoder\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.244.0\"},\"wasm-encoder 0.247.0\":{\"common_attrs\":{\"crate_features\":[\"component-model\",\"std\"],\"deps\":[{\"id\":\"leb128fmt 0.1.0\",\"target\":\"leb128fmt\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasm_encoder\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-encoder\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-encoder\",\"repository\":{\"Http\":{\"sha256\":\"30b6733b8b91d010a6ac5b0fb237dc46a19650bc4c67db66857e2e787d437204\",\"url\":\"https://static.crates.io/crates/wasm-encoder/0.247.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasm_encoder\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.247.0\"},\"wasm-metadata 0.244.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"wasm-encoder 0.244.0\",\"target\":\"wasm_encoder\"},{\"id\":\"wasmparser 0.244.0\",\"target\":\"wasmparser\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasm_metadata\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasm-metadata\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasm-metadata\",\"repository\":{\"Http\":{\"sha256\":\"bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909\",\"url\":\"https://static.crates.io/crates/wasm-metadata/0.244.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasm_metadata\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.244.0\"},\"wasmer 7.2.0-alpha.2\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"bindgen 0.72.1\",\"target\":\"bindgen\"},{\"id\":\"cmake 0.1.58\",\"target\":\"cmake\"},{\"id\":\"tar 0.4.45\",\"target\":\"tar\"}]},\"common_attrs\":{\"crate_features\":[\"compiler\",\"experimental-async\",\"headless\",\"llvm\",\"std\",\"sys\",\"wasmer-compiler-llvm\"],\"deps\":{\"common\":[{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"corosensei 0.3.3\",\"target\":\"corosensei\"},{\"id\":\"derive_more 2.1.1\",\"target\":\"derive_more\"},{\"id\":\"futures 0.3.32\",\"target\":\"futures\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"more-asserts 0.3.1\",\"target\":\"more_asserts\"},{\"id\":\"shared-buffer 0.1.4\",\"target\":\"shared_buffer\"},{\"id\":\"symbolic-demangle 12.18.3\",\"target\":\"symbolic_demangle\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"tracing 0.1.44\",\"target\":\"tracing\"},{\"id\":\"wasmer-compiler 7.2.0-alpha.2\",\"target\":\"wasmer_compiler\"},{\"id\":\"wasmer-compiler-llvm 7.2.0-alpha.2\",\"target\":\"wasmer_compiler_llvm\"},{\"id\":\"wasmer-vm 7.2.0-alpha.2\",\"target\":\"wasmer_vm\"}],\"selects\":{\"cfg(all(not(target_arch = \\\"wasm32\\\"), target_os = \\\"windows\\\"))\":[{\"id\":\"windows-sys 0.61.2\",\"target\":\"windows_sys\"}],\"cfg(not(target_arch = \\\"wasm32\\\"))\":[{\"id\":\"dashmap 6.1.0\",\"target\":\"dashmap\"},{\"id\":\"target-lexicon 0.13.5\",\"target\":\"target_lexicon\"},{\"id\":\"wasmer-types 7.2.0-alpha.2\",\"target\":\"wasmer_types\"}],\"cfg(target_arch = \\\"wasm32\\\")\":[{\"id\":\"js-sys 0.3.95\",\"target\":\"js_sys\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"serde-wasm-bindgen 0.6.5\",\"target\":\"serde_wasm_bindgen\"},{\"id\":\"target-lexicon 0.13.5\",\"target\":\"target_lexicon\"},{\"id\":\"wasm-bindgen 0.2.118\",\"target\":\"wasm_bindgen\"},{\"id\":\"wasmer-types 7.2.0-alpha.2\",\"target\":\"wasmer_types\"}]}},\"edition\":\"2024\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":{\"common\":[{\"id\":\"paste 1.0.15\",\"target\":\"paste\"}],\"selects\":{\"cfg(not(target_arch = \\\"wasm32\\\"))\":[{\"id\":\"wasmer-derive 7.2.0-alpha.2\",\"target\":\"wasmer_derive\"}],\"cfg(target_arch = \\\"wasm32\\\")\":[{\"id\":\"wasmer-derive 7.2.0-alpha.2\",\"target\":\"wasmer_derive\"}]}}},\"library_target_name\":\"wasmer\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[\"@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer.patch\"],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/api\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"7.2.0-alpha.2\"},\"wasmer-compiler 7.2.0-alpha.2\":{\"common_attrs\":{\"crate_features\":[\"compiler\",\"default\",\"std\",\"translator\",\"wasmparser\"],\"deps\":{\"common\":[{\"id\":\"backtrace 0.3.76\",\"target\":\"backtrace\"},{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"enum-iterator 2.3.0\",\"target\":\"enum_iterator\"},{\"id\":\"enumset 1.1.10\",\"target\":\"enumset\"},{\"id\":\"itertools 0.14.0\",\"target\":\"itertools\"},{\"id\":\"leb128 0.2.6\",\"target\":\"leb128\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"},{\"id\":\"memmap2 0.9.10\",\"target\":\"memmap2\"},{\"id\":\"more-asserts 0.3.1\",\"target\":\"more_asserts\"},{\"id\":\"object 0.39.1\",\"target\":\"object\"},{\"id\":\"rangemap 1.7.1\",\"target\":\"rangemap\"},{\"id\":\"rkyv 0.8.16\",\"target\":\"rkyv\"},{\"id\":\"self_cell 1.2.2\",\"target\":\"self_cell\"},{\"id\":\"shared-buffer 0.1.4\",\"target\":\"shared_buffer\"},{\"id\":\"smallvec 1.15.1\",\"target\":\"smallvec\"},{\"id\":\"target-lexicon 0.13.5\",\"target\":\"target_lexicon\"},{\"id\":\"tempfile 3.27.0\",\"target\":\"tempfile\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"wasmer-types 7.2.0-alpha.2\",\"target\":\"wasmer_types\"},{\"id\":\"wasmparser 0.247.0\",\"target\":\"wasmparser\"}],\"selects\":{\"cfg(all(target_os = \\\"macos\\\", target_arch = \\\"aarch64\\\"))\":[{\"id\":\"macho-unwind-info 0.5.0\",\"target\":\"macho_unwind_info\"}],\"cfg(not(target_arch = \\\"wasm32\\\"))\":[{\"id\":\"crossbeam-channel 0.5.15\",\"target\":\"crossbeam_channel\"},{\"id\":\"rayon 1.12.0\",\"target\":\"rayon\"},{\"id\":\"region 3.0.2\",\"target\":\"region\"},{\"id\":\"wasmer-vm 7.2.0-alpha.2\",\"target\":\"wasmer_vm\"},{\"id\":\"which 8.0.2\",\"target\":\"which\"}],\"cfg(target_os = \\\"windows\\\")\":[{\"id\":\"windows-sys 0.61.2\",\"target\":\"windows_sys\"}]}},\"edition\":\"2024\",\"extra_link_deps\":[\"@oliphaunt//build_defs/wasix/postmaster:linked_unwinder\"],\"rustc_flags\":[\"--cfg=oliphaunt_linked_libunwind\"]},\"library_target_name\":\"wasmer_compiler\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer-compiler\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[\"@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-compiler.patch\"],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/compiler\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_compiler\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"7.2.0-alpha.2\"},\"wasmer-compiler-llvm 7.2.0-alpha.2\":{\"common_attrs\":{\"deps\":[{\"id\":\"byteorder 1.5.0\",\"target\":\"byteorder\"},{\"id\":\"crossbeam-channel 0.5.15\",\"target\":\"crossbeam_channel\"},{\"id\":\"enum-iterator 2.3.0\",\"target\":\"enum_iterator\"},{\"id\":\"enumset 1.1.10\",\"target\":\"enumset\"},{\"id\":\"inkwell 0.9.0\",\"target\":\"inkwell\"},{\"id\":\"itertools 0.14.0\",\"target\":\"itertools\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"},{\"id\":\"object 0.39.1\",\"target\":\"object\"},{\"id\":\"phf 0.13.1\",\"target\":\"phf\"},{\"id\":\"rayon 1.12.0\",\"target\":\"rayon\"},{\"id\":\"smallvec 1.15.1\",\"target\":\"smallvec\"},{\"id\":\"target-lexicon 0.13.5\",\"target\":\"target_lexicon\"},{\"id\":\"tracing 0.1.44\",\"target\":\"tracing\"},{\"id\":\"wasmer-compiler 7.2.0-alpha.2\",\"target\":\"wasmer_compiler\"},{\"id\":\"wasmer-types 7.2.0-alpha.2\",\"target\":\"wasmer_types\"},{\"id\":\"wasmer-vm 7.2.0-alpha.2\",\"target\":\"wasmer_vm\"}],\"edition\":\"2024\"},\"library_target_name\":\"wasmer_compiler_llvm\",\"license_file\":\"LICENSE\",\"name\":\"wasmer-compiler-llvm\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[\"@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-compiler-llvm.patch\"],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/compiler-llvm\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_compiler_llvm\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"7.2.0-alpha.2\"},\"wasmer-config 0.702.0-alpha.2\":{\"common_attrs\":{\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"bytesize 2.3.1\",\"target\":\"bytesize\"},{\"id\":\"ciborium 0.2.2\",\"target\":\"ciborium\"},{\"id\":\"derive_builder 0.20.2\",\"target\":\"derive_builder\"},{\"id\":\"hex 0.4.3\",\"target\":\"hex\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"saffron 0.1.0\",\"target\":\"saffron\"},{\"id\":\"schemars 1.2.1\",\"target\":\"schemars\"},{\"id\":\"semver 1.0.28\",\"target\":\"semver\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.149\",\"target\":\"serde_json\"},{\"id\":\"serde_yaml 0.9.34+deprecated\",\"target\":\"serde_yaml\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"toml 1.1.2+spec-1.1.0\",\"target\":\"toml\"},{\"id\":\"url 2.5.8\",\"target\":\"url\"}],\"edition\":\"2024\"},\"library_target_name\":\"wasmer_config\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer-config\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/config\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_config\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.702.0-alpha.2\"},\"wasmer-derive 7.2.0-alpha.2\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro-error2 2.0.1\",\"target\":\"proc_macro_error2\"},{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2024\"},\"library_target_name\":\"wasmer_derive\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer-derive\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/derive\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"wasmer_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"7.2.0-alpha.2\"},\"wasmer-journal 0.702.0-alpha.2\":{\"common_attrs\":{\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"base64 0.22.1\",\"target\":\"base64\"},{\"id\":\"bincode 2.0.1\",\"target\":\"bincode\"},{\"id\":\"bytecheck 0.8.2\",\"target\":\"bytecheck\"},{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"derive_more 2.1.1\",\"target\":\"derive_more\"},{\"id\":\"lz4_flex 0.13.0\",\"target\":\"lz4_flex\"},{\"id\":\"num_enum 0.7.6\",\"target\":\"num_enum\"},{\"id\":\"rkyv 0.8.16\",\"target\":\"rkyv\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.149\",\"target\":\"serde_json\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"tracing 0.1.44\",\"target\":\"tracing\"},{\"id\":\"virtual-fs 0.702.0-alpha.2\",\"target\":\"virtual_fs\"},{\"id\":\"virtual-net 0.702.0-alpha.2\",\"target\":\"virtual_net\"},{\"id\":\"wasmer 7.2.0-alpha.2\",\"target\":\"wasmer\"},{\"id\":\"wasmer-config 0.702.0-alpha.2\",\"target\":\"wasmer_config\"},{\"id\":\"wasmer-wasix-types 0.702.0-alpha.2\",\"target\":\"wasmer_wasix_types\"}],\"edition\":\"2024\",\"proc_macro_deps\":[{\"id\":\"async-trait 0.1.89\",\"target\":\"async_trait\"}]},\"library_target_name\":\"wasmer_journal\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer-journal\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/journal\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_journal\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.702.0-alpha.2\"},\"wasmer-package 0.702.0-alpha.2\":{\"common_attrs\":{\"deps\":{\"common\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"ciborium 0.2.2\",\"target\":\"ciborium\"},{\"id\":\"flate2 1.1.9\",\"target\":\"flate2\"},{\"id\":\"ignore 0.4.25\",\"target\":\"ignore\"},{\"id\":\"insta 1.47.2\",\"target\":\"insta\"},{\"id\":\"semver 1.0.28\",\"target\":\"semver\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.149\",\"target\":\"serde_json\"},{\"id\":\"sha2 0.11.0\",\"target\":\"sha2\"},{\"id\":\"shared-buffer 0.1.4\",\"target\":\"shared_buffer\"},{\"id\":\"tar 0.4.45\",\"target\":\"tar\"},{\"id\":\"tempfile 3.27.0\",\"target\":\"tempfile\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"toml 1.1.2+spec-1.1.0\",\"target\":\"toml\"},{\"id\":\"url 2.5.8\",\"target\":\"url\"},{\"id\":\"wasmer-config 0.702.0-alpha.2\",\"target\":\"wasmer_config\"},{\"id\":\"wasmer-types 7.2.0-alpha.2\",\"target\":\"wasmer_types\"},{\"id\":\"webc 11.0.0\",\"target\":\"webc\"}],\"selects\":{\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"wasi\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}]}},\"edition\":\"2024\"},\"library_target_name\":\"wasmer_package\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer-package\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/package\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_package\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.702.0-alpha.2\"},\"wasmer-types 7.2.0-alpha.2\":{\"common_attrs\":{\"crate_features\":[\"default\",\"detect-wasm-features\",\"serde\",\"std\"],\"deps\":[{\"id\":\"bytecheck 0.8.2\",\"target\":\"bytecheck\"},{\"id\":\"crc32fast 1.5.0\",\"target\":\"crc32fast\"},{\"id\":\"enum-iterator 2.3.0\",\"target\":\"enum_iterator\"},{\"id\":\"enumset 1.1.10\",\"target\":\"enumset\"},{\"id\":\"getrandom 0.4.2\",\"target\":\"getrandom\"},{\"id\":\"hex 0.4.3\",\"target\":\"hex\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"itertools 0.14.0\",\"target\":\"itertools\"},{\"id\":\"more-asserts 0.3.1\",\"target\":\"more_asserts\"},{\"id\":\"rkyv 0.8.16\",\"target\":\"rkyv\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"sha2 0.11.0\",\"target\":\"sha2\"},{\"id\":\"target-lexicon 0.13.5\",\"target\":\"target_lexicon\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"wasmparser 0.247.0\",\"target\":\"wasmparser\"}],\"edition\":\"2024\"},\"library_target_name\":\"wasmer_types\",\"license\":\"MIT OR Apache-2.0 WITH LLVM-exception\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasmer-types\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[\"@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-types.patch\"],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/types\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_types\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"7.2.0-alpha.2\"},\"wasmer-vm 7.2.0-alpha.2\":{\"common_attrs\":{\"crate_features\":[\"default\"],\"deps\":{\"common\":[{\"id\":\"backtrace 0.3.76\",\"target\":\"backtrace\"},{\"id\":\"bytesize 2.3.1\",\"target\":\"bytesize\"},{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"corosensei 0.3.3\",\"target\":\"corosensei\"},{\"id\":\"crossbeam-queue 0.3.12\",\"target\":\"crossbeam_queue\"},{\"id\":\"dashmap 6.1.0\",\"target\":\"dashmap\"},{\"id\":\"enum-iterator 2.3.0\",\"target\":\"enum_iterator\"},{\"id\":\"fnv 1.0.7\",\"target\":\"fnv\"},{\"id\":\"gimli 0.33.0\",\"target\":\"gimli\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"itertools 0.14.0\",\"target\":\"itertools\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"},{\"id\":\"memoffset 0.9.1\",\"target\":\"memoffset\"},{\"id\":\"more-asserts 0.3.1\",\"target\":\"more_asserts\"},{\"id\":\"parking_lot 0.12.5\",\"target\":\"parking_lot\"},{\"id\":\"region 3.0.2\",\"target\":\"region\"},{\"id\":\"scopeguard 1.2.0\",\"target\":\"scopeguard\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"wasmer-types 7.2.0-alpha.2\",\"target\":\"wasmer_types\"}],\"selects\":{\"cfg(any(target_family = \\\"unix\\\", all(target_family = \\\"windows\\\", target_env = \\\"gnu\\\")))\":[{\"id\":\"libunwind 1.3.3\",\"target\":\"libunwind\"}],\"cfg(target_os = \\\"windows\\\")\":[{\"id\":\"windows-sys 0.61.2\",\"target\":\"windows_sys\"}],\"cfg(target_vendor = \\\"apple\\\")\":[{\"id\":\"mach2 0.6.0\",\"target\":\"mach2\"}]}},\"edition\":\"2024\"},\"library_target_name\":\"wasmer_vm\",\"license\":\"MIT OR Apache-2.0 WITH LLVM-exception\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasmer-vm\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[\"@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-vm.patch\"],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/vm\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_vm\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"7.2.0-alpha.2\"},\"wasmer-wasix 0.702.0-alpha.2\":{\"common_attrs\":{\"crate_features\":[\"rusty_pool\",\"sys-minimal\",\"sys-thread\"],\"deps\":{\"common\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"base64 0.22.1\",\"target\":\"base64\"},{\"id\":\"bincode 2.0.1\",\"target\":\"bincode\"},{\"id\":\"blake3 1.8.4\",\"target\":\"blake3\"},{\"id\":\"bytecheck 0.8.2\",\"target\":\"bytecheck\"},{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"cooked-waker 5.0.0\",\"target\":\"cooked_waker\"},{\"id\":\"crossbeam-channel 0.5.15\",\"target\":\"crossbeam_channel\"},{\"id\":\"dashmap 6.1.0\",\"target\":\"dashmap\"},{\"id\":\"derive_more 2.1.1\",\"target\":\"derive_more\"},{\"id\":\"flate2 1.1.9\",\"target\":\"flate2\"},{\"id\":\"fnv 1.0.7\",\"target\":\"fnv\"},{\"id\":\"futures 0.3.32\",\"target\":\"futures\"},{\"id\":\"getrandom 0.4.2\",\"target\":\"getrandom\"},{\"id\":\"heapless 0.9.2\",\"target\":\"heapless\"},{\"id\":\"hex 0.4.3\",\"target\":\"hex\"},{\"id\":\"http 1.4.0\",\"target\":\"http\"},{\"id\":\"linked_hash_set 0.1.6\",\"target\":\"linked_hash_set\"},{\"id\":\"lz4_flex 0.13.0\",\"target\":\"lz4_flex\"},{\"id\":\"num_enum 0.7.6\",\"target\":\"num_enum\"},{\"id\":\"once_cell 1.21.4\",\"target\":\"once_cell\"},{\"id\":\"petgraph 0.8.3\",\"target\":\"petgraph\"},{\"id\":\"pin-project 1.1.11\",\"target\":\"pin_project\"},{\"id\":\"pin-utils 0.1.0\",\"target\":\"pin_utils\"},{\"id\":\"rand 0.10.1\",\"target\":\"rand\"},{\"id\":\"rkyv 0.8.16\",\"target\":\"rkyv\"},{\"id\":\"rusty_pool 0.7.0\",\"target\":\"rusty_pool\"},{\"id\":\"semver 1.0.28\",\"target\":\"semver\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.149\",\"target\":\"serde_json\"},{\"id\":\"serde_yaml 0.9.34+deprecated\",\"target\":\"serde_yaml\"},{\"id\":\"sha2 0.11.0\",\"target\":\"sha2\"},{\"id\":\"shared-buffer 0.1.4\",\"target\":\"shared_buffer\"},{\"id\":\"tempfile 3.27.0\",\"target\":\"tempfile\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"tokio 1.52.1\",\"target\":\"tokio\"},{\"id\":\"tokio-stream 0.1.18\",\"target\":\"tokio_stream\"},{\"id\":\"toml 1.1.2+spec-1.1.0\",\"target\":\"toml\"},{\"id\":\"tracing 0.1.44\",\"target\":\"tracing\"},{\"id\":\"url 2.5.8\",\"target\":\"url\"},{\"id\":\"urlencoding 2.1.3\",\"target\":\"urlencoding\"},{\"id\":\"virtual-fs 0.702.0-alpha.2\",\"target\":\"virtual_fs\"},{\"id\":\"virtual-mio 0.702.0-alpha.2\",\"target\":\"virtual_mio\"},{\"id\":\"virtual-net 0.702.0-alpha.2\",\"target\":\"virtual_net\"},{\"id\":\"waker-fn 1.2.0\",\"target\":\"waker_fn\"},{\"id\":\"wasm-encoder 0.247.0\",\"target\":\"wasm_encoder\"},{\"id\":\"wasmer 7.2.0-alpha.2\",\"target\":\"wasmer\"},{\"id\":\"wasmer-config 0.702.0-alpha.2\",\"target\":\"wasmer_config\"},{\"id\":\"wasmer-journal 0.702.0-alpha.2\",\"target\":\"wasmer_journal\"},{\"id\":\"wasmer-package 0.702.0-alpha.2\",\"target\":\"wasmer_package\"},{\"id\":\"wasmer-types 7.2.0-alpha.2\",\"target\":\"wasmer_types\"},{\"id\":\"wasmer-wasix-types 0.702.0-alpha.2\",\"target\":\"wasmer_wasix_types\"},{\"id\":\"wasmparser 0.247.0\",\"target\":\"wasmparser\"},{\"id\":\"webc 11.0.0\",\"target\":\"webc\"},{\"id\":\"weezl 0.1.12\",\"target\":\"weezl\"},{\"id\":\"xxhash-rust 0.8.15\",\"target\":\"xxhash_rust\"}],\"selects\":{\"cfg(all(unix, not(target_os = \\\"ios\\\")))\":[{\"id\":\"termios 0.3.3\",\"target\":\"termios\"}],\"cfg(not(target_arch = \\\"wasm32\\\"))\":[{\"id\":\"terminal_size 0.4.4\",\"target\":\"terminal_size\"},{\"id\":\"zstd 0.13.3\",\"target\":\"zstd\"}],\"cfg(target_arch = \\\"wasm32\\\")\":[{\"alias\":\"getrandom03\",\"id\":\"getrandom 0.3.4\",\"target\":\"getrandom\"}],\"cfg(unix)\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"cfg(windows)\":[{\"id\":\"windows-sys 0.61.2\",\"target\":\"windows_sys\"}]}},\"edition\":\"2024\",\"proc_macro_deps\":[{\"id\":\"async-trait 0.1.89\",\"target\":\"async_trait\"},{\"id\":\"serde_derive 1.0.228\",\"target\":\"serde_derive\"}]},\"library_target_name\":\"wasmer_wasix\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer-wasix\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[\"@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-wasix.patch\"],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/wasix\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_wasix\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.702.0-alpha.2\"},\"wasmer-wasix-types 0.702.0-alpha.2\":{\"common_attrs\":{\"crate_features\":[\"enable-serde\",\"serde\"],\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"bitflags 2.11.1\",\"target\":\"bitflags\"},{\"id\":\"byteorder 1.5.0\",\"target\":\"byteorder\"},{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"num_enum 0.7.6\",\"target\":\"num_enum\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"time 0.3.47\",\"target\":\"time\"},{\"id\":\"tracing 0.1.44\",\"target\":\"tracing\"},{\"id\":\"wai-bindgen-gen-core 0.2.3\",\"target\":\"wai_bindgen_gen_core\"},{\"id\":\"wai-bindgen-gen-rust 0.2.3\",\"target\":\"wai_bindgen_gen_rust\"},{\"id\":\"wai-bindgen-gen-rust-wasm 0.2.3\",\"target\":\"wai_bindgen_gen_rust_wasm\"},{\"id\":\"wai-bindgen-rust 0.2.3\",\"target\":\"wai_bindgen_rust\"},{\"id\":\"wai-parser 0.2.3\",\"target\":\"wai_parser\"},{\"id\":\"wasmer 7.2.0-alpha.2\",\"target\":\"wasmer\"},{\"id\":\"wasmer-types 7.2.0-alpha.2\",\"target\":\"wasmer_types\"}],\"edition\":\"2024\",\"proc_macro_deps\":[{\"id\":\"wasmer-derive 7.2.0-alpha.2\",\"target\":\"wasmer_derive\"}]},\"library_target_name\":\"wasmer_wasix_types\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"wasmer-wasix-types\",\"package_url\":\"https://github.com/wasmerio/wasmer\",\"repository\":{\"Http\":{\"patch_args\":[\"-p1\"],\"patches\":[],\"sha256\":\"f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912\",\"strip_prefix\":\"wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/wasi-types\",\"url\":\"https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmer_wasix_types\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.702.0-alpha.2\"},\"wasmparser 0.244.0\":{\"common_attrs\":{\"crate_features\":[\"component-model\",\"features\",\"hash-collections\",\"simd\",\"std\",\"validate\"],\"deps\":[{\"id\":\"bitflags 2.11.1\",\"target\":\"bitflags\"},{\"id\":\"hashbrown 0.15.5\",\"target\":\"hashbrown\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"semver 1.0.28\",\"target\":\"semver\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasmparser\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasmparser\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasmparser\",\"repository\":{\"Http\":{\"sha256\":\"47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe\",\"url\":\"https://static.crates.io/crates/wasmparser/0.244.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmparser\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.244.0\"},\"wasmparser 0.247.0\":{\"common_attrs\":{\"crate_features\":[\"features\",\"simd\",\"validate\"],\"deps\":[{\"id\":\"bitflags 2.11.1\",\"target\":\"bitflags\"}],\"edition\":\"2021\"},\"library_target_name\":\"wasmparser\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wasmparser\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wasmparser\",\"repository\":{\"Http\":{\"sha256\":\"8e6fb4c2bee46c5ea4d40f8cdb5c131725cd976718ec56f1c8e82fbde5fa2a80\",\"url\":\"https://static.crates.io/crates/wasmparser/0.247.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wasmparser\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.247.0\"},\"wast 247.0.0\":{\"common_attrs\":{\"crate_features\":[\"component-model\",\"wasm-module\"],\"deps\":[{\"id\":\"bumpalo 3.20.2\",\"target\":\"bumpalo\"},{\"id\":\"leb128fmt 0.1.0\",\"target\":\"leb128fmt\"},{\"id\":\"memchr 2.8.0\",\"target\":\"memchr\"},{\"id\":\"unicode-width 0.2.2\",\"target\":\"unicode_width\"},{\"id\":\"wasm-encoder 0.247.0\",\"target\":\"wasm_encoder\"}],\"edition\":\"2021\"},\"library_target_name\":\"wast\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wast\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wast\",\"repository\":{\"Http\":{\"sha256\":\"579d2d47eb33b0cdf9b14723cb115f1e1b7d6e77aac6f0816e5b7c7aeaa418ff\",\"url\":\"https://static.crates.io/crates/wast/247.0.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wast\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"247.0.0\"},\"wat 1.247.0\":{\"common_attrs\":{\"crate_features\":[\"component-model\",\"default\"],\"deps\":[{\"id\":\"wast 247.0.0\",\"target\":\"wast\"}],\"edition\":\"2021\"},\"library_target_name\":\"wat\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wat\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wat\",\"repository\":{\"Http\":{\"sha256\":\"f3f4091c56437e86f2b57fa2fac72c4f528957a605b3f44f7c0b3b19a17ac5ee\",\"url\":\"https://static.crates.io/crates/wat/1.247.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wat\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.247.0\"},\"webc 11.0.0\":{\"common_attrs\":{\"crate_features\":[\"default\",\"v1\",\"v2\",\"v3\"],\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"base64 0.22.1\",\"target\":\"base64\"},{\"id\":\"bytes 1.11.1\",\"target\":\"bytes\"},{\"id\":\"cfg-if 1.0.4\",\"target\":\"cfg_if\"},{\"id\":\"ciborium 0.2.2\",\"target\":\"ciborium\"},{\"id\":\"ignore 0.4.25\",\"target\":\"ignore\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"leb128 0.2.6\",\"target\":\"leb128\"},{\"id\":\"lexical-sort 0.3.1\",\"target\":\"lexical_sort\"},{\"id\":\"libc 0.2.186\",\"target\":\"libc\"},{\"id\":\"once_cell 1.21.4\",\"target\":\"once_cell\"},{\"id\":\"path-clean 1.0.1\",\"target\":\"path_clean\"},{\"id\":\"rand 0.9.4\",\"target\":\"rand\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.149\",\"target\":\"serde_json\"},{\"id\":\"sha2 0.10.9\",\"target\":\"sha2\"},{\"id\":\"shared-buffer 0.1.4\",\"target\":\"shared_buffer\"},{\"id\":\"thiserror 2.0.18\",\"target\":\"thiserror\"},{\"id\":\"url 2.5.8\",\"target\":\"url\"}],\"edition\":\"2024\",\"proc_macro_deps\":[{\"id\":\"document-features 0.2.12\",\"target\":\"document_features\"}]},\"library_target_name\":\"webc\",\"license\":\"MIT\",\"license_ids\":[\"MIT\"],\"name\":\"webc\",\"package_url\":\"https://github.com/wasmerio/pirita\",\"repository\":{\"Http\":{\"sha256\":\"20b8b523112384e8c1caf77cffdd371ca7e0013779f081e6beafc537f5b5325d\",\"url\":\"https://static.crates.io/crates/webc/11.0.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"webc\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"11.0.0\"},\"weezl 0.1.12\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"default\",\"std\"],\"edition\":\"2018\"},\"library_target_name\":\"weezl\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"weezl\",\"package_url\":\"https://github.com/image-rs/weezl\",\"repository\":{\"Http\":{\"sha256\":\"a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88\",\"url\":\"https://static.crates.io/crates/weezl/0.1.12/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"weezl\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.12\"},\"which 8.0.2\":{\"common_attrs\":{\"crate_features\":[\"default\",\"real-sys\"],\"deps\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}],\"edition\":\"2021\"},\"library_target_name\":\"which\",\"license\":\"MIT\",\"license_file\":\"LICENSE.txt\",\"license_ids\":[\"MIT\"],\"name\":\"which\",\"package_url\":\"https://github.com/harryfei/which-rs.git\",\"repository\":{\"Http\":{\"sha256\":\"81995fafaaaf6ae47a7d0cc83c67caf92aeb7e5331650ae6ff856f7c0c60c459\",\"url\":\"https://static.crates.io/crates/which/8.0.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"which\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"8.0.2\"},\"winapi-util 0.1.11\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"cfg(windows)\":[{\"id\":\"windows-sys 0.61.2\",\"target\":\"windows_sys\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"winapi_util\",\"license\":\"Unlicense OR MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\",\"Unlicense\"],\"name\":\"winapi-util\",\"package_url\":\"https://github.com/BurntSushi/winapi-util\",\"repository\":{\"Http\":{\"sha256\":\"c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22\",\"url\":\"https://static.crates.io/crates/winapi-util/0.1.11/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"winapi_util\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.11\"},\"windows-link 0.2.1\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"windows_link\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows-link\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5\",\"url\":\"https://static.crates.io/crates/windows-link/0.2.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_link\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.1\"},\"windows-sys 0.52.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"windows-targets 0.52.6\",\"target\":\"windows_targets\"}],\"edition\":\"2021\"},\"library_target_name\":\"windows_sys\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows-sys\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d\",\"url\":\"https://static.crates.io/crates/windows-sys/0.52.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_sys\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.52.0\"},\"windows-sys 0.59.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"windows-targets 0.52.6\",\"target\":\"windows_targets\"}],\"edition\":\"2021\"},\"library_target_name\":\"windows_sys\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows-sys\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b\",\"url\":\"https://static.crates.io/crates/windows-sys/0.59.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_sys\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.59.0\"},\"windows-sys 0.61.2\":{\"common_attrs\":{\"deps\":[{\"id\":\"windows-link 0.2.1\",\"target\":\"windows_link\"}],\"edition\":\"2021\"},\"library_target_name\":\"windows_sys\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows-sys\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc\",\"url\":\"https://static.crates.io/crates/windows-sys/0.61.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_sys\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.61.2\"},\"windows-targets 0.52.6\":{\"common_attrs\":{\"deps\":{\"common\":[],\"selects\":{\"aarch64-pc-windows-gnullvm\":[{\"id\":\"windows_aarch64_gnullvm 0.52.6\",\"target\":\"windows_aarch64_gnullvm\"}],\"cfg(all(any(target_arch = \\\"x86_64\\\", target_arch = \\\"arm64ec\\\"), target_env = \\\"msvc\\\", not(windows_raw_dylib)))\":[{\"id\":\"windows_x86_64_msvc 0.52.6\",\"target\":\"windows_x86_64_msvc\"}],\"cfg(all(target_arch = \\\"aarch64\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\":[{\"id\":\"windows_aarch64_msvc 0.52.6\",\"target\":\"windows_aarch64_msvc\"}],\"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"gnu\\\", not(target_abi = \\\"llvm\\\"), not(windows_raw_dylib)))\":[{\"id\":\"windows_i686_gnu 0.52.6\",\"target\":\"windows_i686_gnu\"}],\"cfg(all(target_arch = \\\"x86\\\", target_env = \\\"msvc\\\", not(windows_raw_dylib)))\":[{\"id\":\"windows_i686_msvc 0.52.6\",\"target\":\"windows_i686_msvc\"}],\"cfg(all(target_arch = \\\"x86_64\\\", target_env = \\\"gnu\\\", not(target_abi = \\\"llvm\\\"), not(windows_raw_dylib)))\":[{\"id\":\"windows_x86_64_gnu 0.52.6\",\"target\":\"windows_x86_64_gnu\"}],\"i686-pc-windows-gnullvm\":[{\"id\":\"windows_i686_gnullvm 0.52.6\",\"target\":\"windows_i686_gnullvm\"}],\"x86_64-pc-windows-gnullvm\":[{\"id\":\"windows_x86_64_gnullvm 0.52.6\",\"target\":\"windows_x86_64_gnullvm\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"windows_targets\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows-targets\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973\",\"url\":\"https://static.crates.io/crates/windows-targets/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_targets\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.52.6\"},\"windows_aarch64_gnullvm 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_aarch64_gnullvm\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_aarch64_gnullvm\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3\",\"url\":\"https://static.crates.io/crates/windows_aarch64_gnullvm/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_aarch64_gnullvm\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"windows_aarch64_msvc 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_aarch64_msvc\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_aarch64_msvc\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469\",\"url\":\"https://static.crates.io/crates/windows_aarch64_msvc/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_aarch64_msvc\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"windows_i686_gnu 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_i686_gnu\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_i686_gnu\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b\",\"url\":\"https://static.crates.io/crates/windows_i686_gnu/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_i686_gnu\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"windows_i686_gnullvm 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_i686_gnullvm\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_i686_gnullvm\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66\",\"url\":\"https://static.crates.io/crates/windows_i686_gnullvm/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_i686_gnullvm\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"windows_i686_msvc 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_i686_msvc\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_i686_msvc\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66\",\"url\":\"https://static.crates.io/crates/windows_i686_msvc/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_i686_msvc\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"windows_x86_64_gnu 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_x86_64_gnu\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_x86_64_gnu\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78\",\"url\":\"https://static.crates.io/crates/windows_x86_64_gnu/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_x86_64_gnu\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"windows_x86_64_gnullvm 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_x86_64_gnullvm\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_x86_64_gnullvm\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d\",\"url\":\"https://static.crates.io/crates/windows_x86_64_gnullvm/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_x86_64_gnullvm\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"windows_x86_64_msvc 0.52.6\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"windows_x86_64_msvc\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"license-apache-2.0\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"windows_x86_64_msvc\",\"package_url\":\"https://github.com/microsoft/windows-rs\",\"repository\":{\"Http\":{\"sha256\":\"589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec\",\"url\":\"https://static.crates.io/crates/windows_x86_64_msvc/0.52.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"windows_x86_64_msvc\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.52.6\"},\"winnow 1.0.2\":{\"common_attrs\":{\"crate_features\":[\"alloc\",\"ascii\",\"binary\",\"default\",\"parser\",\"std\"],\"edition\":\"2021\"},\"library_target_name\":\"winnow\",\"license\":\"MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\"],\"name\":\"winnow\",\"package_url\":\"https://github.com/winnow-rs/winnow\",\"repository\":{\"Http\":{\"sha256\":\"2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0\",\"url\":\"https://static.crates.io/crates/winnow/1.0.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"winnow\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.0.2\"},\"wit-bindgen 0.51.0\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2024\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"wit_bindgen\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wit-bindgen\",\"package_url\":\"https://github.com/bytecodealliance/wit-bindgen\",\"repository\":{\"Http\":{\"sha256\":\"d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5\",\"url\":\"https://static.crates.io/crates/wit-bindgen/0.51.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wit_bindgen\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.51.0\"},\"wit-bindgen 0.57.1\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2024\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"wit_bindgen\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wit-bindgen\",\"package_url\":\"https://github.com/bytecodealliance/wit-bindgen\",\"repository\":{\"Http\":{\"sha256\":\"1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e\",\"url\":\"https://static.crates.io/crates/wit-bindgen/0.57.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wit_bindgen\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.57.1\"},\"wit-bindgen-core 0.51.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"heck 0.5.0\",\"target\":\"heck\"},{\"id\":\"wit-parser 0.244.0\",\"target\":\"wit_parser\"}],\"edition\":\"2024\"},\"library_target_name\":\"wit_bindgen_core\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wit-bindgen-core\",\"package_url\":\"https://github.com/bytecodealliance/wit-bindgen\",\"repository\":{\"Http\":{\"sha256\":\"ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc\",\"url\":\"https://static.crates.io/crates/wit-bindgen-core/0.51.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wit_bindgen_core\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.51.0\"},\"wit-bindgen-rust 0.51.0\":{\"build_script_attrs\":{\"link_deps\":[{\"id\":\"prettyplease 0.2.37\",\"target\":\"prettyplease\"}]},\"common_attrs\":{\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"heck 0.5.0\",\"target\":\"heck\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"prettyplease 0.2.37\",\"target\":\"prettyplease\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"},{\"id\":\"wasm-metadata 0.244.0\",\"target\":\"wasm_metadata\"},{\"id\":\"wit-bindgen-core 0.51.0\",\"target\":\"wit_bindgen_core\"},{\"id\":\"wit-component 0.244.0\",\"target\":\"wit_component\"}],\"edition\":\"2024\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"wit_bindgen_rust\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wit-bindgen-rust\",\"package_url\":\"https://github.com/bytecodealliance/wit-bindgen\",\"repository\":{\"Http\":{\"sha256\":\"b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21\",\"url\":\"https://static.crates.io/crates/wit-bindgen-rust/0.51.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wit_bindgen_rust\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.51.0\"},\"wit-bindgen-rust-macro 0.51.0\":{\"build_script_attrs\":{\"link_deps\":[{\"id\":\"prettyplease 0.2.37\",\"target\":\"prettyplease\"}]},\"common_attrs\":{\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"prettyplease 0.2.37\",\"target\":\"prettyplease\"},{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"},{\"id\":\"wit-bindgen-core 0.51.0\",\"target\":\"wit_bindgen_core\"},{\"id\":\"wit-bindgen-rust 0.51.0\",\"target\":\"wit_bindgen_rust\"}],\"edition\":\"2024\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"wit_bindgen_rust_macro\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wit-bindgen-rust-macro\",\"package_url\":\"https://github.com/bytecodealliance/wit-bindgen\",\"repository\":{\"Http\":{\"sha256\":\"0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a\",\"url\":\"https://static.crates.io/crates/wit-bindgen-rust-macro/0.51.0/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"wit_bindgen_rust_macro\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.51.0\"},\"wit-component 0.244.0\":{\"common_attrs\":{\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"bitflags 2.11.1\",\"target\":\"bitflags\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"log 0.4.29\",\"target\":\"log\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.149\",\"target\":\"serde_json\"},{\"id\":\"wasm-encoder 0.244.0\",\"target\":\"wasm_encoder\"},{\"id\":\"wasm-metadata 0.244.0\",\"target\":\"wasm_metadata\"},{\"id\":\"wasmparser 0.244.0\",\"target\":\"wasmparser\"},{\"id\":\"wit-parser 0.244.0\",\"target\":\"wit_parser\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"serde_derive 1.0.228\",\"target\":\"serde_derive\"}]},\"library_target_name\":\"wit_component\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wit-component\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wit-component\",\"repository\":{\"Http\":{\"sha256\":\"9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2\",\"url\":\"https://static.crates.io/crates/wit-component/0.244.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wit_component\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.244.0\"},\"wit-parser 0.244.0\":{\"common_attrs\":{\"crate_features\":[\"decoding\",\"default\",\"serde\",\"serde_json\"],\"deps\":[{\"id\":\"anyhow 1.0.102\",\"target\":\"anyhow\"},{\"id\":\"id-arena 2.3.0\",\"target\":\"id_arena\"},{\"id\":\"indexmap 2.14.0\",\"target\":\"indexmap\"},{\"id\":\"log 0.4.29\",\"target\":\"log\"},{\"id\":\"semver 1.0.28\",\"target\":\"semver\"},{\"id\":\"serde 1.0.228\",\"target\":\"serde\"},{\"id\":\"serde_json 1.0.149\",\"target\":\"serde_json\"},{\"id\":\"unicode-xid 0.2.6\",\"target\":\"unicode_xid\"},{\"id\":\"wasmparser 0.244.0\",\"target\":\"wasmparser\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"serde_derive 1.0.228\",\"target\":\"serde_derive\"}]},\"library_target_name\":\"wit_parser\",\"license\":\"Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"wit-parser\",\"package_url\":\"https://github.com/bytecodealliance/wasm-tools/tree/main/crates/wit-parser\",\"repository\":{\"Http\":{\"sha256\":\"ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736\",\"url\":\"https://static.crates.io/crates/wit-parser/0.244.0/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"wit_parser\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.244.0\"},\"writeable 0.6.3\":{\"common_attrs\":{\"edition\":\"2021\"},\"library_target_name\":\"writeable\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"writeable\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4\",\"url\":\"https://static.crates.io/crates/writeable/0.6.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"writeable\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.6.3\"},\"xattr 1.6.1\":{\"common_attrs\":{\"crate_features\":[\"default\",\"unsupported\"],\"deps\":{\"common\":[],\"selects\":{\"cfg(any(target_os = \\\"android\\\", target_os = \\\"linux\\\", target_os = \\\"macos\\\", target_os = \\\"hurd\\\"))\":[{\"id\":\"rustix 1.1.4\",\"target\":\"rustix\"}],\"cfg(any(target_os = \\\"freebsd\\\", target_os = \\\"netbsd\\\"))\":[{\"id\":\"libc 0.2.186\",\"target\":\"libc\"}]}},\"edition\":\"2021\"},\"library_target_name\":\"xattr\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"xattr\",\"package_url\":\"https://github.com/Stebalien/xattr\",\"repository\":{\"Http\":{\"sha256\":\"32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156\",\"url\":\"https://static.crates.io/crates/xattr/1.6.1/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"xattr\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"1.6.1\"},\"xxhash-rust 0.8.15\":{\"common_attrs\":{\"crate_features\":[\"xxh64\"],\"edition\":\"2018\"},\"library_target_name\":\"xxhash_rust\",\"license\":\"BSL-1.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"BSL-1.0\"],\"name\":\"xxhash-rust\",\"package_url\":\"https://github.com/DoumanAsh/xxhash-rust\",\"repository\":{\"Http\":{\"sha256\":\"fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3\",\"url\":\"https://static.crates.io/crates/xxhash-rust/0.8.15/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"xxhash_rust\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.15\"},\"yoke 0.8.2\":{\"common_attrs\":{\"crate_features\":[\"derive\",\"zerofrom\"],\"deps\":[{\"id\":\"stable_deref_trait 1.2.1\",\"target\":\"stable_deref_trait\"},{\"id\":\"zerofrom 0.1.7\",\"target\":\"zerofrom\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"yoke-derive 0.8.2\",\"target\":\"yoke_derive\"}]},\"library_target_name\":\"yoke\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"yoke\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca\",\"url\":\"https://static.crates.io/crates/yoke/0.8.2/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"yoke\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.2\"},\"yoke-derive 0.8.2\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"},{\"id\":\"synstructure 0.13.2\",\"target\":\"synstructure\"}],\"edition\":\"2021\"},\"library_target_name\":\"yoke_derive\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"yoke-derive\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e\",\"url\":\"https://static.crates.io/crates/yoke-derive/0.8.2/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"yoke_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.2\"},\"zerocopy 0.8.48\":{\"build_script_attrs\":{},\"common_attrs\":{\"crate_features\":[\"derive\",\"simd\",\"zerocopy-derive\"],\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"],\"proc_macro_deps\":[{\"id\":\"zerocopy-derive 0.8.48\",\"target\":\"zerocopy_derive\"}]},\"library_target_name\":\"zerocopy\",\"license\":\"BSD-2-Clause OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"BSD-2-Clause\",\"MIT\"],\"name\":\"zerocopy\",\"package_url\":\"https://github.com/google/zerocopy\",\"repository\":{\"Http\":{\"sha256\":\"eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9\",\"url\":\"https://static.crates.io/crates/zerocopy/0.8.48/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"zerocopy\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"0.8.48\"},\"zerocopy-derive 0.8.48\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"zerocopy_derive\",\"license\":\"BSD-2-Clause OR Apache-2.0 OR MIT\",\"license_file\":\"LICENSE-APACHE\",\"license_ids\":[\"Apache-2.0\",\"BSD-2-Clause\",\"MIT\"],\"name\":\"zerocopy-derive\",\"package_url\":\"https://github.com/google/zerocopy\",\"repository\":{\"Http\":{\"sha256\":\"70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4\",\"url\":\"https://static.crates.io/crates/zerocopy-derive/0.8.48/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"zerocopy_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.8.48\"},\"zerofrom 0.1.7\":{\"common_attrs\":{\"crate_features\":[\"derive\"],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"zerofrom-derive 0.1.7\",\"target\":\"zerofrom_derive\"}]},\"library_target_name\":\"zerofrom\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"zerofrom\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df\",\"url\":\"https://static.crates.io/crates/zerofrom/0.1.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"zerofrom\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.7\"},\"zerofrom-derive 0.1.7\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"},{\"id\":\"synstructure 0.13.2\",\"target\":\"synstructure\"}],\"edition\":\"2021\"},\"library_target_name\":\"zerofrom_derive\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"zerofrom-derive\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1\",\"url\":\"https://static.crates.io/crates/zerofrom-derive/0.1.7/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"zerofrom_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.1.7\"},\"zerotrie 0.2.4\":{\"common_attrs\":{\"crate_features\":[\"yoke\",\"zerofrom\"],\"deps\":[{\"id\":\"yoke 0.8.2\",\"target\":\"yoke\"},{\"id\":\"zerofrom 0.1.7\",\"target\":\"zerofrom\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"displaydoc 0.2.5\",\"target\":\"displaydoc\"}]},\"library_target_name\":\"zerotrie\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"zerotrie\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf\",\"url\":\"https://static.crates.io/crates/zerotrie/0.2.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"zerotrie\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.2.4\"},\"zerovec 0.11.6\":{\"common_attrs\":{\"crate_features\":[\"derive\",\"yoke\"],\"deps\":[{\"id\":\"yoke 0.8.2\",\"target\":\"yoke\"},{\"id\":\"zerofrom 0.1.7\",\"target\":\"zerofrom\"}],\"edition\":\"2021\",\"proc_macro_deps\":[{\"id\":\"zerovec-derive 0.11.3\",\"target\":\"zerovec_derive\"}]},\"library_target_name\":\"zerovec\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"zerovec\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239\",\"url\":\"https://static.crates.io/crates/zerovec/0.11.6/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"zerovec\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.11.6\"},\"zerovec-derive 0.11.3\":{\"common_attrs\":{\"deps\":[{\"id\":\"proc-macro2 1.0.106\",\"target\":\"proc_macro2\"},{\"id\":\"quote 1.0.45\",\"target\":\"quote\"},{\"id\":\"syn 2.0.117\",\"target\":\"syn\"}],\"edition\":\"2021\"},\"library_target_name\":\"zerovec_derive\",\"license\":\"Unicode-3.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Unicode-3.0\"],\"name\":\"zerovec-derive\",\"package_url\":\"https://github.com/unicode-org/icu4x\",\"repository\":{\"Http\":{\"sha256\":\"625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555\",\"url\":\"https://static.crates.io/crates/zerovec-derive/0.11.3/download\"}},\"targets\":[{\"ProcMacro\":{\"crate_name\":\"zerovec_derive\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.11.3\"},\"zmij 1.0.21\":{\"build_script_attrs\":{},\"common_attrs\":{\"edition\":\"2021\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"zmij\",\"license\":\"MIT\",\"license_file\":\"LICENSE-MIT\",\"license_ids\":[\"MIT\"],\"name\":\"zmij\",\"package_url\":\"https://github.com/dtolnay/zmij\",\"repository\":{\"Http\":{\"sha256\":\"b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa\",\"url\":\"https://static.crates.io/crates/zmij/1.0.21/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"zmij\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"1.0.21\"},\"zstd 0.13.3\":{\"common_attrs\":{\"crate_features\":[\"arrays\",\"default\",\"legacy\",\"zdict_builder\"],\"deps\":[{\"id\":\"zstd-safe 7.2.4\",\"target\":\"zstd_safe\"}],\"edition\":\"2018\"},\"library_target_name\":\"zstd\",\"license\":\"MIT\",\"license_file\":\"LICENSE\",\"license_ids\":[\"MIT\"],\"name\":\"zstd\",\"package_url\":\"https://github.com/gyscos/zstd-rs\",\"repository\":{\"Http\":{\"sha256\":\"e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a\",\"url\":\"https://static.crates.io/crates/zstd/0.13.3/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"zstd\",\"crate_root\":\"src/lib.rs\"}}],\"version\":\"0.13.3\"},\"zstd-safe 7.2.4\":{\"build_script_attrs\":{\"link_deps\":[{\"id\":\"zstd-sys 2.0.16+zstd.1.5.7\",\"target\":\"zstd_sys\"}]},\"common_attrs\":{\"crate_features\":[\"arrays\",\"legacy\",\"std\",\"zdict_builder\"],\"deps\":[{\"id\":\"zstd-sys 2.0.16+zstd.1.5.7\",\"target\":\"zstd_sys\"}],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"zstd_safe\",\"license\":\"MIT OR Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"zstd-safe\",\"package_url\":\"https://github.com/gyscos/zstd-rs\",\"repository\":{\"Http\":{\"sha256\":\"8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d\",\"url\":\"https://static.crates.io/crates/zstd-safe/7.2.4/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"zstd_safe\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"7.2.4\"},\"zstd-sys 2.0.16+zstd.1.5.7\":{\"build_script_attrs\":{\"deps\":[{\"id\":\"cc 1.2.60\",\"target\":\"cc\"},{\"id\":\"pkg-config 0.3.33\",\"target\":\"pkg_config\"}],\"links\":\"zstd\"},\"common_attrs\":{\"crate_features\":[\"legacy\",\"std\",\"zdict_builder\"],\"edition\":\"2018\",\"extra_deps\":[\":build_script_build\"]},\"library_target_name\":\"zstd_sys\",\"license\":\"MIT/Apache-2.0\",\"license_file\":\"LICENSE\",\"license_ids\":[\"Apache-2.0\",\"MIT\"],\"name\":\"zstd-sys\",\"package_url\":\"https://github.com/gyscos/zstd-rs\",\"repository\":{\"Http\":{\"sha256\":\"91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748\",\"url\":\"https://static.crates.io/crates/zstd-sys/2.0.16+zstd.1.5.7/download\"}},\"targets\":[{\"Library\":{\"crate_name\":\"zstd_sys\",\"crate_root\":\"src/lib.rs\"}},{\"BuildScript\":{\"crate_name\":\"build_script_build\",\"crate_root\":\"build.rs\"}}],\"version\":\"2.0.16+zstd.1.5.7\"}},\"direct_deps\":[\"anyhow 1.0.102\",\"async-trait 0.1.89\",\"hex 0.4.3\",\"libc 0.2.186\",\"serde 1.0.228\",\"serde_json 1.0.149\",\"sha2 0.11.0\",\"tempfile 3.27.0\",\"tracing 0.1.44\",\"wasmer 7.2.0-alpha.2\",\"wasmer-compiler-llvm 7.2.0-alpha.2\",\"wasmer-types 7.2.0-alpha.2\",\"wasmer-vm 7.2.0-alpha.2\",\"wasmer-wasix 0.702.0-alpha.2\",\"wasmparser 0.247.0\"],\"direct_dev_deps\":[\"futures 0.3.32\",\"wat 1.247.0\"],\"workspace_members\":{\"oliphaunt-wasix-postmaster-executor 7.2.0-alpha.2\":\"\"}}", + "anyhow-1.0.102/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"anyhow-1.0.102\",\n actual = \"@postmaster_compiler_crates__anyhow-1.0.102//:anyhow\",\n tags = [\"manual\"],\n)\n", + "anyhow/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"anyhow\",\n actual = \"@postmaster_compiler_crates__anyhow-1.0.102//:anyhow\",\n tags = [\"manual\"],\n)\n", + "async-trait-0.1.89/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"async-trait-0.1.89\",\n actual = \"@postmaster_compiler_crates__async-trait-0.1.89//:async_trait\",\n tags = [\"manual\"],\n)\n", + "async-trait/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"async-trait\",\n actual = \"@postmaster_compiler_crates__async-trait-0.1.89//:async_trait\",\n tags = [\"manual\"],\n)\n", + "futures-0.3.32/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"futures-0.3.32\",\n actual = \"@postmaster_compiler_crates__futures-0.3.32//:futures\",\n tags = [\"manual\"],\n)\n", + "futures/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"futures\",\n actual = \"@postmaster_compiler_crates__futures-0.3.32//:futures\",\n tags = [\"manual\"],\n)\n", + "hex-0.4.3/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"hex-0.4.3\",\n actual = \"@postmaster_compiler_crates__hex-0.4.3//:hex\",\n tags = [\"manual\"],\n)\n", + "hex/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"hex\",\n actual = \"@postmaster_compiler_crates__hex-0.4.3//:hex\",\n tags = [\"manual\"],\n)\n", + "libc-0.2.186/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"libc-0.2.186\",\n actual = \"@postmaster_compiler_crates__libc-0.2.186//:libc\",\n tags = [\"manual\"],\n)\n", + "libc/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"libc\",\n actual = \"@postmaster_compiler_crates__libc-0.2.186//:libc\",\n tags = [\"manual\"],\n)\n", + "serde-1.0.228/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"serde-1.0.228\",\n actual = \"@postmaster_compiler_crates__serde-1.0.228//:serde\",\n tags = [\"manual\"],\n)\n", + "serde/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"serde\",\n actual = \"@postmaster_compiler_crates__serde-1.0.228//:serde\",\n tags = [\"manual\"],\n)\n", + "serde_json-1.0.149/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"serde_json-1.0.149\",\n actual = \"@postmaster_compiler_crates__serde_json-1.0.149//:serde_json\",\n tags = [\"manual\"],\n)\n", + "serde_json/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"serde_json\",\n actual = \"@postmaster_compiler_crates__serde_json-1.0.149//:serde_json\",\n tags = [\"manual\"],\n)\n", + "sha2-0.11.0/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"sha2-0.11.0\",\n actual = \"@postmaster_compiler_crates__sha2-0.11.0//:sha2\",\n tags = [\"manual\"],\n)\n", + "sha2/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"sha2\",\n actual = \"@postmaster_compiler_crates__sha2-0.11.0//:sha2\",\n tags = [\"manual\"],\n)\n", + "tempfile-3.27.0/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"tempfile-3.27.0\",\n actual = \"@postmaster_compiler_crates__tempfile-3.27.0//:tempfile\",\n tags = [\"manual\"],\n)\n", + "tempfile/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"tempfile\",\n actual = \"@postmaster_compiler_crates__tempfile-3.27.0//:tempfile\",\n tags = [\"manual\"],\n)\n", + "tracing-0.1.44/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"tracing-0.1.44\",\n actual = \"@postmaster_compiler_crates__tracing-0.1.44//:tracing\",\n tags = [\"manual\"],\n)\n", + "tracing/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"tracing\",\n actual = \"@postmaster_compiler_crates__tracing-0.1.44//:tracing\",\n tags = [\"manual\"],\n)\n", + "wasmer-7.2.0-alpha.2/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-7.2.0-alpha.2\",\n actual = \"@postmaster_compiler_crates__wasmer-7.2.0-alpha.2//:wasmer\",\n tags = [\"manual\"],\n)\n", + "wasmer/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer\",\n actual = \"@postmaster_compiler_crates__wasmer-7.2.0-alpha.2//:wasmer\",\n tags = [\"manual\"],\n)\n", + "wasmer-compiler-llvm-7.2.0-alpha.2/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-compiler-llvm-7.2.0-alpha.2\",\n actual = \"@postmaster_compiler_crates__wasmer-compiler-llvm-7.2.0-alpha.2//:wasmer_compiler_llvm\",\n tags = [\"manual\"],\n)\n", + "wasmer-compiler-llvm/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-compiler-llvm\",\n actual = \"@postmaster_compiler_crates__wasmer-compiler-llvm-7.2.0-alpha.2//:wasmer_compiler_llvm\",\n tags = [\"manual\"],\n)\n", + "wasmer-types-7.2.0-alpha.2/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-types-7.2.0-alpha.2\",\n actual = \"@postmaster_compiler_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\",\n tags = [\"manual\"],\n)\n", + "wasmer-types/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-types\",\n actual = \"@postmaster_compiler_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\",\n tags = [\"manual\"],\n)\n", + "wasmer-vm-7.2.0-alpha.2/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-vm-7.2.0-alpha.2\",\n actual = \"@postmaster_compiler_crates__wasmer-vm-7.2.0-alpha.2//:wasmer_vm\",\n tags = [\"manual\"],\n)\n", + "wasmer-vm/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-vm\",\n actual = \"@postmaster_compiler_crates__wasmer-vm-7.2.0-alpha.2//:wasmer_vm\",\n tags = [\"manual\"],\n)\n", + "wasmer-wasix-0.702.0-alpha.2/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-wasix-0.702.0-alpha.2\",\n actual = \"@postmaster_compiler_crates__wasmer-wasix-0.702.0-alpha.2//:wasmer_wasix\",\n tags = [\"manual\"],\n)\n", + "wasmer-wasix/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmer-wasix\",\n actual = \"@postmaster_compiler_crates__wasmer-wasix-0.702.0-alpha.2//:wasmer_wasix\",\n tags = [\"manual\"],\n)\n", + "wasmparser-0.247.0/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmparser-0.247.0\",\n actual = \"@postmaster_compiler_crates__wasmparser-0.247.0//:wasmparser\",\n tags = [\"manual\"],\n)\n", + "wasmparser/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmparser\",\n actual = \"@postmaster_compiler_crates__wasmparser-0.247.0//:wasmparser\",\n tags = [\"manual\"],\n)\n", + "wat-1.247.0/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wat-1.247.0\",\n actual = \"@postmaster_compiler_crates__wat-1.247.0//:wat\",\n tags = [\"manual\"],\n)\n", + "wat/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wat\",\n actual = \"@postmaster_compiler_crates__wat-1.247.0//:wat\",\n tags = [\"manual\"],\n)\n" + } + } + }, + "postmaster_compiler_crates__addr2line-0.25.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/addr2line/0.25.1/download" + ], + "strip_prefix": "addr2line-0.25.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"addr2line\",\n deps = [\n \"@postmaster_compiler_crates__gimli-0.32.3//:gimli\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=addr2line\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.25.1\",\n)\n" + } + }, + "postmaster_compiler_crates__adler2-2.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/adler2/2.0.1/download" + ], + "strip_prefix": "adler2-2.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"adler2\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=adler2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.1\",\n)\n" + } + }, + "postmaster_compiler_crates__aho-corasick-1.1.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/aho-corasick/1.1.4/download" + ], + "strip_prefix": "aho-corasick-1.1.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"aho_corasick\",\n deps = [\n \"@postmaster_compiler_crates__memchr-2.8.0//:memchr\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"perf-literal\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=aho-corasick\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.4\",\n)\n" + } + }, + "postmaster_compiler_crates__any_ascii-0.1.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "70033777eb8b5124a81a1889416543dddef2de240019b674c81285a2635a7e1e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/any_ascii/0.1.7/download" + ], + "strip_prefix": "any_ascii-0.1.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"any_ascii\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=any_ascii\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.7\",\n)\n" + } + }, + "postmaster_compiler_crates__anyhow-1.0.102": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/anyhow/1.0.102/download" + ], + "strip_prefix": "anyhow-1.0.102", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"anyhow\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=anyhow\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.102\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"anyhow\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=anyhow\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.102\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__arrayref-0.3.9": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/arrayref/0.3.9/download" + ], + "strip_prefix": "arrayref-0.3.9", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"arrayref\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=arrayref\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.9\",\n)\n" + } + }, + "postmaster_compiler_crates__arrayvec-0.7.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/arrayvec/0.7.6/download" + ], + "strip_prefix": "arrayvec-0.7.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"arrayvec\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=arrayvec\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.6\",\n)\n" + } + }, + "postmaster_compiler_crates__async-trait-0.1.89": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/async-trait/0.1.89/download" + ], + "strip_prefix": "async-trait-0.1.89", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"async_trait\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=async-trait\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.89\",\n)\n" + } + }, + "postmaster_compiler_crates__autocfg-1.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/autocfg/1.5.0/download" + ], + "strip_prefix": "autocfg-1.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"autocfg\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=autocfg\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.5.0\",\n)\n" + } + }, + "postmaster_compiler_crates__backtrace-0.3.76": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/backtrace/0.3.76/download" + ], + "strip_prefix": "backtrace-0.3.76", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"backtrace\",\n deps = [\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_compiler_crates__rustc-demangle-0.1.27//:rustc_demangle\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__addr2line-0.25.1//:addr2line\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@postmaster_compiler_crates__miniz_oxide-0.8.9//:miniz_oxide\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@postmaster_compiler_crates__object-0.37.3//:object\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__addr2line-0.25.1//:addr2line\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@postmaster_compiler_crates__miniz_oxide-0.8.9//:miniz_oxide\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@postmaster_compiler_crates__object-0.37.3//:object\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__addr2line-0.25.1//:addr2line\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@postmaster_compiler_crates__miniz_oxide-0.8.9//:miniz_oxide\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n \"@postmaster_compiler_crates__object-0.37.3//:object\", # cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=backtrace\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.76\",\n)\n" + } + }, + "postmaster_compiler_crates__base64-0.22.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/base64/0.22.1/download" + ], + "strip_prefix": "base64-0.22.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"base64\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=base64\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.22.1\",\n)\n" + } + }, + "postmaster_compiler_crates__bincode-2.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bincode/2.0.1/download" + ], + "strip_prefix": "bincode-2.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bincode\",\n deps = [\n \"@postmaster_compiler_crates__serde-1.0.228//:serde\",\n \"@postmaster_compiler_crates__unty-0.0.4//:unty\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__bincode_derive-2.0.1//:bincode_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"bincode_derive\",\n \"default\",\n \"derive\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bincode\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.1\",\n)\n" + } + }, + "postmaster_compiler_crates__bincode_derive-2.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bincode_derive/2.0.1/download" + ], + "strip_prefix": "bincode_derive-2.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"bincode_derive\",\n deps = [\n \"@postmaster_compiler_crates__virtue-0.0.18//:virtue\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bincode_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.1\",\n)\n" + } + }, + "postmaster_compiler_crates__bindgen-0.72.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bindgen/0.72.1/download" + ], + "strip_prefix": "bindgen-0.72.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bindgen\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__bitflags-2.11.1//:bitflags\",\n \"@postmaster_compiler_crates__cexpr-0.6.0//:cexpr\",\n \"@postmaster_compiler_crates__clang-sys-1.8.1//:clang_sys\",\n \"@postmaster_compiler_crates__itertools-0.13.0//:itertools\",\n \"@postmaster_compiler_crates__log-0.4.29//:log\",\n \"@postmaster_compiler_crates__prettyplease-0.2.37//:prettyplease\",\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__regex-1.12.3//:regex\",\n \"@postmaster_compiler_crates__rustc-hash-2.1.2//:rustc_hash\",\n \"@postmaster_compiler_crates__shlex-1.3.0//:shlex\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"logging\",\n \"prettyplease\",\n \"runtime\",\n ],\n crate_root = \"lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bindgen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.72.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"logging\",\n \"prettyplease\",\n \"runtime\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n link_deps = [\n \"@postmaster_compiler_crates__clang-sys-1.8.1//:clang_sys\",\n \"@postmaster_compiler_crates__prettyplease-0.2.37//:prettyplease\",\n ],\n edition = \"2021\",\n pkg_name = \"bindgen\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bindgen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.72.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__bitflags-1.3.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bitflags/1.3.2/download" + ], + "strip_prefix": "bitflags-1.3.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bitflags\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bitflags\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.3.2\",\n)\n" + } + }, + "postmaster_compiler_crates__bitflags-2.11.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bitflags/2.11.1/download" + ], + "strip_prefix": "bitflags-2.11.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bitflags\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bitflags\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.11.1\",\n)\n" + } + }, + "postmaster_compiler_crates__blake3-1.8.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4d2d5991425dfd0785aed03aedcf0b321d61975c9b5b3689c774a2610ae0b51e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/blake3/1.8.4/download" + ], + "strip_prefix": "blake3-1.8.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"blake3\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__arrayref-0.3.9//:arrayref\",\n \"@postmaster_compiler_crates__arrayvec-0.7.6//:arrayvec\",\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_compiler_crates__constant_time_eq-0.4.2//:constant_time_eq\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__cpufeatures-0.3.0//:cpufeatures\", # cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=blake3\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.8.4\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@postmaster_compiler_crates__cc-1.2.60//:cc\",\n ],\n emit_warnings = False,\n edition = \"2024\",\n pkg_name = \"blake3\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=blake3\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.8.4\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__block-buffer-0.10.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/block-buffer/0.10.4/download" + ], + "strip_prefix": "block-buffer-0.10.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"block_buffer\",\n deps = [\n \"@postmaster_compiler_crates__generic-array-0.14.7//:generic_array\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=block-buffer\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.4\",\n)\n" + } + }, + "postmaster_compiler_crates__block-buffer-0.12.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/block-buffer/0.12.0/download" + ], + "strip_prefix": "block-buffer-0.12.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"block_buffer\",\n deps = [\n \"@postmaster_compiler_crates__hybrid-array-0.4.10//:hybrid_array\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=block-buffer\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.12.0\",\n)\n" + } + }, + "postmaster_compiler_crates__bstr-1.12.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bstr/1.12.1/download" + ], + "strip_prefix": "bstr-1.12.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bstr\",\n deps = [\n \"@postmaster_compiler_crates__memchr-2.8.0//:memchr\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bstr\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.12.1\",\n)\n" + } + }, + "postmaster_compiler_crates__bumpalo-3.20.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bumpalo/3.20.2/download" + ], + "strip_prefix": "bumpalo-3.20.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bumpalo\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bumpalo\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"3.20.2\",\n)\n" + } + }, + "postmaster_compiler_crates__bytecheck-0.8.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0caa33a2c0edca0419d15ac723dff03f1956f7978329b1e3b5fdaaaed9d3ca8b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bytecheck/0.8.2/download" + ], + "strip_prefix": "bytecheck-0.8.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bytecheck\",\n deps = [\n \"@postmaster_compiler_crates__ptr_meta-0.3.1//:ptr_meta\",\n \"@postmaster_compiler_crates__rancor-0.1.1//:rancor\",\n \"@postmaster_compiler_crates__simdutf8-0.1.5//:simdutf8\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__bytecheck_derive-0.8.2//:bytecheck_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"simdutf8\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bytecheck\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.2\",\n)\n" + } + }, + "postmaster_compiler_crates__bytecheck_derive-0.8.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "89385e82b5d1821d2219e0b095efa2cc1f246cbf99080f3be46a1a85c0d392d9", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bytecheck_derive/0.8.2/download" + ], + "strip_prefix": "bytecheck_derive-0.8.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"bytecheck_derive\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bytecheck_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.2\",\n)\n" + } + }, + "postmaster_compiler_crates__byteorder-1.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/byteorder/1.5.0/download" + ], + "strip_prefix": "byteorder-1.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"byteorder\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=byteorder\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.5.0\",\n)\n" + } + }, + "postmaster_compiler_crates__bytes-1.11.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bytes/1.11.1/download" + ], + "strip_prefix": "bytes-1.11.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bytes\",\n deps = [\n \"@postmaster_compiler_crates__serde-1.0.228//:serde\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bytes\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.11.1\",\n)\n" + } + }, + "postmaster_compiler_crates__bytesize-2.3.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6bd91ee7b2422bcb158d90ef4d14f75ef67f340943fc4149891dcce8f8b972a3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bytesize/2.3.1/download" + ], + "strip_prefix": "bytesize-2.3.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bytesize\",\n deps = [\n \"@postmaster_compiler_crates__serde_core-1.0.228//:serde_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bytesize\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.3.1\",\n)\n" + } + }, + "postmaster_compiler_crates__cc-1.2.60": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cc/1.2.60/download" + ], + "strip_prefix": "cc-1.2.60", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cc\",\n deps = [\n \"@postmaster_compiler_crates__find-msvc-tools-0.1.9//:find_msvc_tools\",\n \"@postmaster_compiler_crates__jobserver-0.1.34//:jobserver\",\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\",\n \"@postmaster_compiler_crates__shlex-1.3.0//:shlex\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"parallel\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.60\",\n)\n" + } + }, + "postmaster_compiler_crates__cexpr-0.6.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cexpr/0.6.0/download" + ], + "strip_prefix": "cexpr-0.6.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cexpr\",\n deps = [\n \"@postmaster_compiler_crates__nom-7.1.3//:nom\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cexpr\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.0\",\n)\n" + } + }, + "postmaster_compiler_crates__cfg-if-1.0.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cfg-if/1.0.4/download" + ], + "strip_prefix": "cfg-if-1.0.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cfg_if\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cfg-if\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.4\",\n)\n" + } + }, + "postmaster_compiler_crates__chacha20-0.10.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/chacha20/0.10.0/download" + ], + "strip_prefix": "chacha20-0.10.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"chacha20\",\n deps = [\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_compiler_crates__rand_core-0.10.1//:rand_core\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__cpufeatures-0.3.0//:cpufeatures\", # cfg(any(target_arch = \"x86_64\", target_arch = \"x86\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"rng\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=chacha20\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.0\",\n)\n" + } + }, + "postmaster_compiler_crates__chrono-0.4.44": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/chrono/0.4.44/download" + ], + "strip_prefix": "chrono-0.4.44", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"chrono\",\n deps = [\n \"@postmaster_compiler_crates__num-traits-0.2.19//:num_traits\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=chrono\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.44\",\n)\n" + } + }, + "postmaster_compiler_crates__ciborium-0.2.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ciborium/0.2.2/download" + ], + "strip_prefix": "ciborium-0.2.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ciborium\",\n deps = [\n \"@postmaster_compiler_crates__ciborium-io-0.2.2//:ciborium_io\",\n \"@postmaster_compiler_crates__ciborium-ll-0.2.2//:ciborium_ll\",\n \"@postmaster_compiler_crates__serde-1.0.228//:serde\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ciborium\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.2\",\n)\n" + } + }, + "postmaster_compiler_crates__ciborium-io-0.2.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ciborium-io/0.2.2/download" + ], + "strip_prefix": "ciborium-io-0.2.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ciborium_io\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ciborium-io\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.2\",\n)\n" + } + }, + "postmaster_compiler_crates__ciborium-ll-0.2.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ciborium-ll/0.2.2/download" + ], + "strip_prefix": "ciborium-ll-0.2.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ciborium_ll\",\n deps = [\n \"@postmaster_compiler_crates__ciborium-io-0.2.2//:ciborium_io\",\n \"@postmaster_compiler_crates__half-2.7.1//:half\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ciborium-ll\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.2\",\n)\n" + } + }, + "postmaster_compiler_crates__clang-sys-1.8.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/clang-sys/1.8.1/download" + ], + "strip_prefix": "clang-sys-1.8.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"clang_sys\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__glob-0.3.3//:glob\",\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\",\n \"@postmaster_compiler_crates__libloading-0.8.9//:libloading\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"clang_10_0\",\n \"clang_11_0\",\n \"clang_3_5\",\n \"clang_3_6\",\n \"clang_3_7\",\n \"clang_3_8\",\n \"clang_3_9\",\n \"clang_4_0\",\n \"clang_5_0\",\n \"clang_6_0\",\n \"clang_7_0\",\n \"clang_8_0\",\n \"clang_9_0\",\n \"libloading\",\n \"runtime\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=clang-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.8.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"clang_10_0\",\n \"clang_11_0\",\n \"clang_3_5\",\n \"clang_3_6\",\n \"clang_3_7\",\n \"clang_3_8\",\n \"clang_3_9\",\n \"clang_4_0\",\n \"clang_5_0\",\n \"clang_6_0\",\n \"clang_7_0\",\n \"clang_8_0\",\n \"clang_9_0\",\n \"libloading\",\n \"runtime\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@postmaster_compiler_crates__glob-0.3.3//:glob\",\n ],\n emit_warnings = False,\n edition = \"2021\",\n links = \"clang\",\n pkg_name = \"clang-sys\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=clang-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.8.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__cmake-0.1.58": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cmake/0.1.58/download" + ], + "strip_prefix": "cmake-0.1.58", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cmake\",\n deps = [\n \"@postmaster_compiler_crates__cc-1.2.60//:cc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cmake\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.58\",\n)\n" + } + }, + "postmaster_compiler_crates__console-0.16.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/console/0.16.3/download" + ], + "strip_prefix": "console-0.16.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"console\",\n deps = [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=console\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.16.3\",\n)\n" + } + }, + "postmaster_compiler_crates__const-oid-0.10.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/const-oid/0.10.2/download" + ], + "strip_prefix": "const-oid-0.10.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"const_oid\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=const-oid\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.2\",\n)\n" + } + }, + "postmaster_compiler_crates__constant_time_eq-0.4.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/constant_time_eq/0.4.2/download" + ], + "strip_prefix": "constant_time_eq-0.4.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"constant_time_eq\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=constant_time_eq\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.2\",\n)\n" + } + }, + "postmaster_compiler_crates__convert_case-0.10.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/convert_case/0.10.0/download" + ], + "strip_prefix": "convert_case-0.10.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"convert_case\",\n deps = [\n \"@postmaster_compiler_crates__unicode-segmentation-1.13.2//:unicode_segmentation\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=convert_case\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.0\",\n)\n" + } + }, + "postmaster_compiler_crates__cooked-waker-5.0.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cooked-waker/5.0.0/download" + ], + "strip_prefix": "cooked-waker-5.0.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cooked_waker\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cooked-waker\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"5.0.0\",\n)\n" + } + }, + "postmaster_compiler_crates__corosensei-0.3.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2c54787b605c7df106ceccf798df23da4f2e09918defad66705d1cedf3bb914f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/corosensei/0.3.3/download" + ], + "strip_prefix": "corosensei-0.3.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"corosensei\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\",\n \"@postmaster_compiler_crates__scopeguard-1.2.0//:scopeguard\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"default-stack\",\n \"libc\",\n \"unwind\",\n \"windows-sys\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=corosensei\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.3\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"default-stack\",\n \"libc\",\n \"unwind\",\n \"windows-sys\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@postmaster_compiler_crates__autocfg-1.5.0//:autocfg\",\n ],\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"corosensei\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=corosensei\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.3.3\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__cpp_demangle-0.4.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f2bb79cb74d735044c972aae58ed0aaa9a837e85b01106a54c39e42e97f62253", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cpp_demangle/0.4.5/download" + ], + "strip_prefix": "cpp_demangle-0.4.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cpp_demangle\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cpp_demangle\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.5\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"cpp_demangle\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cpp_demangle\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.4.5\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__cpufeatures-0.2.17": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cpufeatures/0.2.17/download" + ], + "strip_prefix": "cpufeatures-0.2.17", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cpufeatures\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(all(target_arch = \"aarch64\", target_vendor = \"apple\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(all(target_arch = \"aarch64\", target_os = \"linux\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cpufeatures\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.17\",\n)\n" + } + }, + "postmaster_compiler_crates__cpufeatures-0.3.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cpufeatures/0.3.0/download" + ], + "strip_prefix": "cpufeatures-0.3.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cpufeatures\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(all(target_arch = \"aarch64\", target_vendor = \"apple\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(all(target_arch = \"aarch64\", target_os = \"linux\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cpufeatures\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.0\",\n)\n" + } + }, + "postmaster_compiler_crates__crc32fast-1.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crc32fast/1.5.0/download" + ], + "strip_prefix": "crc32fast-1.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crc32fast\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crc32fast\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.5.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"crc32fast\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crc32fast\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.5.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__crossbeam-channel-0.5.15": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crossbeam-channel/0.5.15/download" + ], + "strip_prefix": "crossbeam-channel-0.5.15", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crossbeam_channel\",\n deps = [\n \"@postmaster_compiler_crates__crossbeam-utils-0.8.21//:crossbeam_utils\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crossbeam-channel\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.15\",\n)\n" + } + }, + "postmaster_compiler_crates__crossbeam-deque-0.8.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crossbeam-deque/0.8.6/download" + ], + "strip_prefix": "crossbeam-deque-0.8.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crossbeam_deque\",\n deps = [\n \"@postmaster_compiler_crates__crossbeam-epoch-0.9.18//:crossbeam_epoch\",\n \"@postmaster_compiler_crates__crossbeam-utils-0.8.21//:crossbeam_utils\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crossbeam-deque\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.6\",\n)\n" + } + }, + "postmaster_compiler_crates__crossbeam-epoch-0.9.18": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crossbeam-epoch/0.9.18/download" + ], + "strip_prefix": "crossbeam-epoch-0.9.18", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crossbeam_epoch\",\n deps = [\n \"@postmaster_compiler_crates__crossbeam-utils-0.8.21//:crossbeam_utils\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crossbeam-epoch\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.18\",\n)\n" + } + }, + "postmaster_compiler_crates__crossbeam-queue-0.3.12": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crossbeam-queue/0.3.12/download" + ], + "strip_prefix": "crossbeam-queue-0.3.12", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crossbeam_queue\",\n deps = [\n \"@postmaster_compiler_crates__crossbeam-utils-0.8.21//:crossbeam_utils\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crossbeam-queue\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.12\",\n)\n" + } + }, + "postmaster_compiler_crates__crossbeam-utils-0.8.21": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crossbeam-utils/0.8.21/download" + ], + "strip_prefix": "crossbeam-utils-0.8.21", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crossbeam_utils\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crossbeam-utils\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.21\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"crossbeam-utils\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crossbeam-utils\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.8.21\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__crunchy-0.2.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crunchy/0.2.4/download" + ], + "strip_prefix": "crunchy-0.2.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crunchy\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crunchy\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.4\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"crunchy\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crunchy\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.2.4\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__crypto-common-0.1.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crypto-common/0.1.7/download" + ], + "strip_prefix": "crypto-common-0.1.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crypto_common\",\n deps = [\n \"@postmaster_compiler_crates__generic-array-0.14.7//:generic_array\",\n \"@postmaster_compiler_crates__typenum-1.20.0//:typenum\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crypto-common\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.7\",\n)\n" + } + }, + "postmaster_compiler_crates__crypto-common-0.2.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crypto-common/0.2.1/download" + ], + "strip_prefix": "crypto-common-0.2.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crypto_common\",\n deps = [\n \"@postmaster_compiler_crates__hybrid-array-0.4.10//:hybrid_array\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crypto-common\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.1\",\n)\n" + } + }, + "postmaster_compiler_crates__darling-0.20.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/darling/0.20.11/download" + ], + "strip_prefix": "darling-0.20.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"darling\",\n deps = [\n \"@postmaster_compiler_crates__darling_core-0.20.11//:darling_core\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__darling_macro-0.20.11//:darling_macro\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"suggestions\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=darling\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.20.11\",\n)\n" + } + }, + "postmaster_compiler_crates__darling-0.21.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/darling/0.21.3/download" + ], + "strip_prefix": "darling-0.21.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"darling\",\n deps = [\n \"@postmaster_compiler_crates__darling_core-0.21.3//:darling_core\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__darling_macro-0.21.3//:darling_macro\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=darling\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.21.3\",\n)\n" + } + }, + "postmaster_compiler_crates__darling_core-0.20.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/darling_core/0.20.11/download" + ], + "strip_prefix": "darling_core-0.20.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"darling_core\",\n deps = [\n \"@postmaster_compiler_crates__fnv-1.0.7//:fnv\",\n \"@postmaster_compiler_crates__ident_case-1.0.1//:ident_case\",\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__strsim-0.11.1//:strsim\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"strsim\",\n \"suggestions\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=darling_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.20.11\",\n)\n" + } + }, + "postmaster_compiler_crates__darling_core-0.21.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/darling_core/0.21.3/download" + ], + "strip_prefix": "darling_core-0.21.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"darling_core\",\n deps = [\n \"@postmaster_compiler_crates__fnv-1.0.7//:fnv\",\n \"@postmaster_compiler_crates__ident_case-1.0.1//:ident_case\",\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=darling_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.21.3\",\n)\n" + } + }, + "postmaster_compiler_crates__darling_macro-0.20.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/darling_macro/0.20.11/download" + ], + "strip_prefix": "darling_macro-0.20.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"darling_macro\",\n deps = [\n \"@postmaster_compiler_crates__darling_core-0.20.11//:darling_core\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=darling_macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.20.11\",\n)\n" + } + }, + "postmaster_compiler_crates__darling_macro-0.21.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/darling_macro/0.21.3/download" + ], + "strip_prefix": "darling_macro-0.21.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"darling_macro\",\n deps = [\n \"@postmaster_compiler_crates__darling_core-0.21.3//:darling_core\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=darling_macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.21.3\",\n)\n" + } + }, + "postmaster_compiler_crates__dashmap-6.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/dashmap/6.1.0/download" + ], + "strip_prefix": "dashmap-6.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"dashmap\",\n deps = [\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_compiler_crates__crossbeam-utils-0.8.21//:crossbeam_utils\",\n \"@postmaster_compiler_crates__hashbrown-0.14.5//:hashbrown\",\n \"@postmaster_compiler_crates__lock_api-0.4.14//:lock_api\",\n \"@postmaster_compiler_crates__once_cell-1.21.4//:once_cell\",\n \"@postmaster_compiler_crates__parking_lot_core-0.9.12//:parking_lot_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=dashmap\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"6.1.0\",\n)\n" + } + }, + "postmaster_compiler_crates__debugid-0.8.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/debugid/0.8.0/download" + ], + "strip_prefix": "debugid-0.8.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"debugid\",\n deps = [\n \"@postmaster_compiler_crates__uuid-1.23.1//:uuid\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=debugid\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.0\",\n)\n" + } + }, + "postmaster_compiler_crates__defmt-0.3.100": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/defmt/0.3.100/download" + ], + "strip_prefix": "defmt-0.3.100", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"defmt\",\n deps = [\n \"@postmaster_compiler_crates__defmt-1.0.1//:defmt\",\n ],\n aliases = {\n \"@postmaster_compiler_crates__defmt-1.0.1//:defmt\": \"defmt10\",\n },\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=defmt\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.100\",\n)\n" + } + }, + "postmaster_compiler_crates__defmt-1.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "548d977b6da32fa1d1fda2876453da1e7df63ad0304c8b3dae4dbe7b96f39b78", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/defmt/1.0.1/download" + ], + "strip_prefix": "defmt-1.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"defmt\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__bitflags-1.3.2//:bitflags\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__defmt-macros-1.0.1//:defmt_macros\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=defmt\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n links = \"defmt\",\n pkg_name = \"defmt\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=defmt\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__defmt-macros-1.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3d4fc12a85bcf441cfe44344c4b72d58493178ce635338a3f3b78943aceb258e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/defmt-macros/1.0.1/download" + ], + "strip_prefix": "defmt-macros-1.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"defmt_macros\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__defmt-parser-1.0.0//:defmt_parser\",\n \"@postmaster_compiler_crates__proc-macro-error2-2.0.1//:proc_macro_error2\",\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=defmt-macros\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"defmt-macros\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=defmt-macros\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__defmt-parser-1.0.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/defmt-parser/1.0.0/download" + ], + "strip_prefix": "defmt-parser-1.0.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"defmt_parser\",\n deps = [\n \"@postmaster_compiler_crates__thiserror-2.0.18//:thiserror\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=defmt-parser\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.0\",\n)\n" + } + }, + "postmaster_compiler_crates__deranged-0.5.8": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/deranged/0.5.8/download" + ], + "strip_prefix": "deranged-0.5.8", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"deranged\",\n deps = [\n \"@postmaster_compiler_crates__powerfmt-0.2.0//:powerfmt\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"powerfmt\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=deranged\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.8\",\n)\n" + } + }, + "postmaster_compiler_crates__derive_builder-0.20.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/derive_builder/0.20.2/download" + ], + "strip_prefix": "derive_builder-0.20.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"derive_builder\",\n proc_macro_deps = [\n \"@postmaster_compiler_crates__derive_builder_macro-0.20.2//:derive_builder_macro\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=derive_builder\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.20.2\",\n)\n" + } + }, + "postmaster_compiler_crates__derive_builder_core-0.20.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/derive_builder_core/0.20.2/download" + ], + "strip_prefix": "derive_builder_core-0.20.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"derive_builder_core\",\n deps = [\n \"@postmaster_compiler_crates__darling-0.20.11//:darling\",\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"lib_has_std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=derive_builder_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.20.2\",\n)\n" + } + }, + "postmaster_compiler_crates__derive_builder_macro-0.20.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/derive_builder_macro/0.20.2/download" + ], + "strip_prefix": "derive_builder_macro-0.20.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"derive_builder_macro\",\n deps = [\n \"@postmaster_compiler_crates__derive_builder_core-0.20.2//:derive_builder_core\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"lib_has_std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=derive_builder_macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.20.2\",\n)\n" + } + }, + "postmaster_compiler_crates__derive_more-2.1.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/derive_more/2.1.1/download" + ], + "strip_prefix": "derive_more-2.1.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"derive_more\",\n proc_macro_deps = [\n \"@postmaster_compiler_crates__derive_more-impl-2.1.1//:derive_more_impl\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"debug\",\n \"default\",\n \"display\",\n \"from\",\n \"std\",\n \"unwrap\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=derive_more\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.1.1\",\n)\n" + } + }, + "postmaster_compiler_crates__derive_more-impl-2.1.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/derive_more-impl/2.1.1/download" + ], + "strip_prefix": "derive_more-impl-2.1.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"derive_more_impl\",\n deps = [\n \"@postmaster_compiler_crates__convert_case-0.10.0//:convert_case\",\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n \"@postmaster_compiler_crates__unicode-xid-0.2.6//:unicode_xid\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"debug\",\n \"default\",\n \"display\",\n \"from\",\n \"unwrap\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=derive_more-impl\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.1.1\",\n)\n" + } + }, + "postmaster_compiler_crates__digest-0.10.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/digest/0.10.7/download" + ], + "strip_prefix": "digest-0.10.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"digest\",\n deps = [\n \"@postmaster_compiler_crates__block-buffer-0.10.4//:block_buffer\",\n \"@postmaster_compiler_crates__crypto-common-0.1.7//:crypto_common\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"block-buffer\",\n \"core-api\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=digest\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.7\",\n)\n" + } + }, + "postmaster_compiler_crates__digest-0.11.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/digest/0.11.2/download" + ], + "strip_prefix": "digest-0.11.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"digest\",\n deps = [\n \"@postmaster_compiler_crates__block-buffer-0.12.0//:block_buffer\",\n \"@postmaster_compiler_crates__const-oid-0.10.2//:const_oid\",\n \"@postmaster_compiler_crates__crypto-common-0.2.1//:crypto_common\",\n ],\n aliases = {\n \"@postmaster_compiler_crates__crypto-common-0.2.1//:crypto_common\": \"common\",\n },\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"block-api\",\n \"default\",\n \"oid\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=digest\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.11.2\",\n)\n" + } + }, + "postmaster_compiler_crates__displaydoc-0.2.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/displaydoc/0.2.5/download" + ], + "strip_prefix": "displaydoc-0.2.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"displaydoc\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=displaydoc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.5\",\n)\n" + } + }, + "postmaster_compiler_crates__document-features-0.2.12": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/document-features/0.2.12/download" + ], + "strip_prefix": "document-features-0.2.12", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"document_features\",\n deps = [\n \"@postmaster_compiler_crates__litrs-1.0.0//:litrs\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=document-features\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.12\",\n)\n" + } + }, + "postmaster_compiler_crates__dunce-1.0.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/dunce/1.0.5/download" + ], + "strip_prefix": "dunce-1.0.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"dunce\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=dunce\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.5\",\n)\n" + } + }, + "postmaster_compiler_crates__dyn-clone-1.0.20": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/dyn-clone/1.0.20/download" + ], + "strip_prefix": "dyn-clone-1.0.20", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"dyn_clone\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=dyn-clone\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.20\",\n)\n" + } + }, + "postmaster_compiler_crates__either-1.15.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/either/1.15.0/download" + ], + "strip_prefix": "either-1.15.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"either\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n \"use_std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=either\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.15.0\",\n)\n" + } + }, + "postmaster_compiler_crates__encode_unicode-1.0.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/encode_unicode/1.0.0/download" + ], + "strip_prefix": "encode_unicode-1.0.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"encode_unicode\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=encode_unicode\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.0\",\n)\n" + } + }, + "postmaster_compiler_crates__enum-iterator-2.3.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a4549325971814bda7a44061bf3fe7e487d447cba01e4220a4b454d630d7a016", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/enum-iterator/2.3.0/download" + ], + "strip_prefix": "enum-iterator-2.3.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"enum_iterator\",\n proc_macro_deps = [\n \"@postmaster_compiler_crates__enum-iterator-derive-1.5.0//:enum_iterator_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=enum-iterator\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.3.0\",\n)\n" + } + }, + "postmaster_compiler_crates__enum-iterator-derive-1.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/enum-iterator-derive/1.5.0/download" + ], + "strip_prefix": "enum-iterator-derive-1.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"enum_iterator_derive\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=enum-iterator-derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.5.0\",\n)\n" + } + }, + "postmaster_compiler_crates__enumset-1.1.10": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "25b07a8dfbbbfc0064c0a6bdf9edcf966de6b1c33ce344bdeca3b41615452634", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/enumset/1.1.10/download" + ], + "strip_prefix": "enumset-1.1.10", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"enumset\",\n proc_macro_deps = [\n \"@postmaster_compiler_crates__enumset_derive-0.14.0//:enumset_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=enumset\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.10\",\n)\n" + } + }, + "postmaster_compiler_crates__enumset_derive-0.14.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f43e744e4ea338060faee68ed933e46e722fb7f3617e722a5772d7e856d8b3ce", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/enumset_derive/0.14.0/download" + ], + "strip_prefix": "enumset_derive-0.14.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"enumset_derive\",\n deps = [\n \"@postmaster_compiler_crates__darling-0.21.3//:darling\",\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=enumset_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.14.0\",\n)\n" + } + }, + "postmaster_compiler_crates__equivalent-1.0.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/equivalent/1.0.2/download" + ], + "strip_prefix": "equivalent-1.0.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"equivalent\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=equivalent\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.2\",\n)\n" + } + }, + "postmaster_compiler_crates__errno-0.3.14": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/errno/0.3.14/download" + ], + "strip_prefix": "errno-0.3.14", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"errno\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=errno\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.14\",\n)\n" + } + }, + "postmaster_compiler_crates__fastrand-2.4.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/fastrand/2.4.1/download" + ], + "strip_prefix": "fastrand-2.4.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"fastrand\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=fastrand\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.4.1\",\n)\n" + } + }, + "postmaster_compiler_crates__filetime-0.2.27": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/filetime/0.2.27/download" + ], + "strip_prefix": "filetime-0.2.27", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"filetime\",\n deps = [\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=filetime\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.27\",\n)\n" + } + }, + "postmaster_compiler_crates__find-msvc-tools-0.1.9": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/find-msvc-tools/0.1.9/download" + ], + "strip_prefix": "find-msvc-tools-0.1.9", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"find_msvc_tools\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=find-msvc-tools\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.9\",\n)\n" + } + }, + "postmaster_compiler_crates__fixedbitset-0.5.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/fixedbitset/0.5.7/download" + ], + "strip_prefix": "fixedbitset-0.5.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"fixedbitset\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=fixedbitset\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.7\",\n)\n" + } + }, + "postmaster_compiler_crates__flate2-1.1.9": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/flate2/1.1.9/download" + ], + "strip_prefix": "flate2-1.1.9", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"flate2\",\n deps = [\n \"@postmaster_compiler_crates__crc32fast-1.5.0//:crc32fast\",\n \"@postmaster_compiler_crates__miniz_oxide-0.8.9//:miniz_oxide\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"any_impl\",\n \"default\",\n \"miniz_oxide\",\n \"rust_backend\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=flate2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.9\",\n)\n" + } + }, + "postmaster_compiler_crates__fnv-1.0.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/fnv/1.0.7/download" + ], + "strip_prefix": "fnv-1.0.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"fnv\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=fnv\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.7\",\n)\n" + } + }, + "postmaster_compiler_crates__foldhash-0.1.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/foldhash/0.1.5/download" + ], + "strip_prefix": "foldhash-0.1.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"foldhash\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=foldhash\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.5\",\n)\n" + } + }, + "postmaster_compiler_crates__foldhash-0.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/foldhash/0.2.0/download" + ], + "strip_prefix": "foldhash-0.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"foldhash\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=foldhash\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.0\",\n)\n" + } + }, + "postmaster_compiler_crates__form_urlencoded-1.2.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/form_urlencoded/1.2.2/download" + ], + "strip_prefix": "form_urlencoded-1.2.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"form_urlencoded\",\n deps = [\n \"@postmaster_compiler_crates__percent-encoding-2.3.2//:percent_encoding\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=form_urlencoded\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.2\",\n)\n" + } + }, + "postmaster_compiler_crates__futures-0.3.32": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures/0.3.32/download" + ], + "strip_prefix": "futures-0.3.32", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures\",\n deps = [\n \"@postmaster_compiler_crates__futures-channel-0.3.32//:futures_channel\",\n \"@postmaster_compiler_crates__futures-core-0.3.32//:futures_core\",\n \"@postmaster_compiler_crates__futures-executor-0.3.32//:futures_executor\",\n \"@postmaster_compiler_crates__futures-io-0.3.32//:futures_io\",\n \"@postmaster_compiler_crates__futures-sink-0.3.32//:futures_sink\",\n \"@postmaster_compiler_crates__futures-task-0.3.32//:futures_task\",\n \"@postmaster_compiler_crates__futures-util-0.3.32//:futures_util\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"async-await\",\n \"default\",\n \"executor\",\n \"futures-executor\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.32\",\n)\n" + } + }, + "postmaster_compiler_crates__futures-channel-0.3.32": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-channel/0.3.32/download" + ], + "strip_prefix": "futures-channel-0.3.32", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures_channel\",\n deps = [\n \"@postmaster_compiler_crates__futures-core-0.3.32//:futures_core\",\n \"@postmaster_compiler_crates__futures-sink-0.3.32//:futures_sink\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"futures-sink\",\n \"sink\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-channel\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.32\",\n)\n" + } + }, + "postmaster_compiler_crates__futures-core-0.3.32": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-core/0.3.32/download" + ], + "strip_prefix": "futures-core-0.3.32", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures_core\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.32\",\n)\n" + } + }, + "postmaster_compiler_crates__futures-executor-0.3.32": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-executor/0.3.32/download" + ], + "strip_prefix": "futures-executor-0.3.32", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures_executor\",\n deps = [\n \"@postmaster_compiler_crates__futures-core-0.3.32//:futures_core\",\n \"@postmaster_compiler_crates__futures-task-0.3.32//:futures_task\",\n \"@postmaster_compiler_crates__futures-util-0.3.32//:futures_util\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-executor\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.32\",\n)\n" + } + }, + "postmaster_compiler_crates__futures-io-0.3.32": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-io/0.3.32/download" + ], + "strip_prefix": "futures-io-0.3.32", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures_io\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-io\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.32\",\n)\n" + } + }, + "postmaster_compiler_crates__futures-macro-0.3.32": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-macro/0.3.32/download" + ], + "strip_prefix": "futures-macro-0.3.32", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"futures_macro\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.32\",\n)\n" + } + }, + "postmaster_compiler_crates__futures-sink-0.3.32": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-sink/0.3.32/download" + ], + "strip_prefix": "futures-sink-0.3.32", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures_sink\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-sink\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.32\",\n)\n" + } + }, + "postmaster_compiler_crates__futures-task-0.3.32": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-task/0.3.32/download" + ], + "strip_prefix": "futures-task-0.3.32", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures_task\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-task\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.32\",\n)\n" + } + }, + "postmaster_compiler_crates__futures-util-0.3.32": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/futures-util/0.3.32/download" + ], + "strip_prefix": "futures-util-0.3.32", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"futures_util\",\n deps = [\n \"@postmaster_compiler_crates__futures-channel-0.3.32//:futures_channel\",\n \"@postmaster_compiler_crates__futures-core-0.3.32//:futures_core\",\n \"@postmaster_compiler_crates__futures-io-0.3.32//:futures_io\",\n \"@postmaster_compiler_crates__futures-sink-0.3.32//:futures_sink\",\n \"@postmaster_compiler_crates__futures-task-0.3.32//:futures_task\",\n \"@postmaster_compiler_crates__memchr-2.8.0//:memchr\",\n \"@postmaster_compiler_crates__pin-project-lite-0.2.17//:pin_project_lite\",\n \"@postmaster_compiler_crates__slab-0.4.12//:slab\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__futures-macro-0.3.32//:futures_macro\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"async-await\",\n \"async-await-macro\",\n \"channel\",\n \"default\",\n \"futures-channel\",\n \"futures-io\",\n \"futures-macro\",\n \"futures-sink\",\n \"io\",\n \"memchr\",\n \"sink\",\n \"slab\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=futures-util\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.32\",\n)\n" + } + }, + "postmaster_compiler_crates__generic-array-0.14.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/generic-array/0.14.7/download" + ], + "strip_prefix": "generic-array-0.14.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"generic_array\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__typenum-1.20.0//:typenum\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"more_lengths\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=generic-array\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.14.7\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"more_lengths\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@postmaster_compiler_crates__version_check-0.9.5//:version_check\",\n ],\n emit_warnings = False,\n edition = \"2015\",\n pkg_name = \"generic-array\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=generic-array\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.14.7\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__getrandom-0.3.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/getrandom/0.3.4/download" + ], + "strip_prefix": "getrandom-0.3.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"getrandom\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(any(target_os = \"macos\", target_os = \"openbsd\", target_os = \"vita\", target_os = \"emscripten\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(all(any(target_os = \"linux\", target_os = \"android\"), not(any(all(target_os = \"linux\", target_env = \"\"), getrandom_backend = \"custom\", getrandom_backend = \"linux_raw\", getrandom_backend = \"rdrand\", getrandom_backend = \"rndr\"))))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(all(any(target_os = \"linux\", target_os = \"android\"), not(any(all(target_os = \"linux\", target_env = \"\"), getrandom_backend = \"custom\", getrandom_backend = \"linux_raw\", getrandom_backend = \"rdrand\", getrandom_backend = \"rndr\"))))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=getrandom\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.4\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"getrandom\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=getrandom\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.3.4\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__getrandom-0.4.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/getrandom/0.4.2/download" + ], + "strip_prefix": "getrandom-0.4.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"getrandom\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_compiler_crates__rand_core-0.10.1//:rand_core\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(any(target_os = \"macos\", target_os = \"openbsd\", target_os = \"vita\", target_os = \"emscripten\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(all(any(target_os = \"linux\", target_os = \"android\"), not(any(all(target_os = \"linux\", target_env = \"\"), getrandom_backend = \"custom\", getrandom_backend = \"linux_raw\", getrandom_backend = \"rdrand\", getrandom_backend = \"rndr\"))))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(all(any(target_os = \"linux\", target_os = \"android\"), not(any(all(target_os = \"linux\", target_env = \"\"), getrandom_backend = \"custom\", getrandom_backend = \"linux_raw\", getrandom_backend = \"rdrand\", getrandom_backend = \"rndr\"))))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n \"sys_rng\",\n \"wasm_js\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=getrandom\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.2\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n \"sys_rng\",\n \"wasm_js\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2024\",\n pkg_name = \"getrandom\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=getrandom\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.4.2\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__gimli-0.32.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/gimli/0.32.3/download" + ], + "strip_prefix": "gimli-0.32.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"gimli\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"read\",\n \"read-core\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=gimli\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.32.3\",\n)\n" + } + }, + "postmaster_compiler_crates__gimli-0.33.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0bf7f043f89559805f8c7cacc432749b2fa0d0a0a9ee46ce47164ed5ba7f126c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/gimli/0.33.0/download" + ], + "strip_prefix": "gimli-0.33.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"gimli\",\n deps = [\n \"@postmaster_compiler_crates__fnv-1.0.7//:fnv\",\n \"@postmaster_compiler_crates__hashbrown-0.16.1//:hashbrown\",\n \"@postmaster_compiler_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_compiler_crates__stable_deref_trait-1.2.1//:stable_deref_trait\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"endian-reader\",\n \"read\",\n \"read-all\",\n \"read-core\",\n \"std\",\n \"write\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=gimli\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.33.0\",\n)\n" + } + }, + "postmaster_compiler_crates__glob-0.3.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/glob/0.3.3/download" + ], + "strip_prefix": "glob-0.3.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"glob\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=glob\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.3\",\n)\n" + } + }, + "postmaster_compiler_crates__globset-0.4.18": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/globset/0.4.18/download" + ], + "strip_prefix": "globset-0.4.18", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"globset\",\n deps = [\n \"@postmaster_compiler_crates__aho-corasick-1.1.4//:aho_corasick\",\n \"@postmaster_compiler_crates__bstr-1.12.1//:bstr\",\n \"@postmaster_compiler_crates__log-0.4.29//:log\",\n \"@postmaster_compiler_crates__regex-automata-0.4.14//:regex_automata\",\n \"@postmaster_compiler_crates__regex-syntax-0.8.10//:regex_syntax\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"log\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=globset\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.18\",\n)\n" + } + }, + "postmaster_compiler_crates__half-2.7.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/half/2.7.1/download" + ], + "strip_prefix": "half-2.7.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"half\",\n deps = [\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_compiler_crates__zerocopy-0.8.48//:zerocopy\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=half\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.7.1\",\n)\n" + } + }, + "postmaster_compiler_crates__hash32-0.3.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hash32/0.3.1/download" + ], + "strip_prefix": "hash32-0.3.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hash32\",\n deps = [\n \"@postmaster_compiler_crates__byteorder-1.5.0//:byteorder\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hash32\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.1\",\n)\n" + } + }, + "postmaster_compiler_crates__hashbrown-0.14.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hashbrown/0.14.5/download" + ], + "strip_prefix": "hashbrown-0.14.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hashbrown\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"raw\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hashbrown\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.14.5\",\n)\n" + } + }, + "postmaster_compiler_crates__hashbrown-0.15.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hashbrown/0.15.5/download" + ], + "strip_prefix": "hashbrown-0.15.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hashbrown\",\n deps = [\n \"@postmaster_compiler_crates__foldhash-0.1.5//:foldhash\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default-hasher\",\n \"inline-more\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hashbrown\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.15.5\",\n)\n" + } + }, + "postmaster_compiler_crates__hashbrown-0.16.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hashbrown/0.16.1/download" + ], + "strip_prefix": "hashbrown-0.16.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hashbrown\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hashbrown\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.16.1\",\n)\n" + } + }, + "postmaster_compiler_crates__hashbrown-0.17.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hashbrown/0.17.0/download" + ], + "strip_prefix": "hashbrown-0.17.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hashbrown\",\n deps = [\n \"@postmaster_compiler_crates__foldhash-0.2.0//:foldhash\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default-hasher\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hashbrown\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.17.0\",\n)\n" + } + }, + "postmaster_compiler_crates__heapless-0.9.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2af2455f757db2b292a9b1768c4b70186d443bcb3b316252d6b540aec1cd89ed", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/heapless/0.9.2/download" + ], + "strip_prefix": "heapless-0.9.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"heapless\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__hash32-0.3.1//:hash32\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__stable_deref_trait-1.2.1//:stable_deref_trait\", # cfg(any(target_arch = \"arm\", target_pointer_width = \"32\", target_pointer_width = \"64\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__stable_deref_trait-1.2.1//:stable_deref_trait\", # cfg(any(target_arch = \"arm\", target_pointer_width = \"32\", target_pointer_width = \"64\"))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__stable_deref_trait-1.2.1//:stable_deref_trait\", # cfg(any(target_arch = \"arm\", target_pointer_width = \"32\", target_pointer_width = \"64\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=heapless\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.2\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"heapless\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=heapless\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.9.2\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__heck-0.3.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/heck/0.3.3/download" + ], + "strip_prefix": "heck-0.3.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"heck\",\n deps = [\n \"@postmaster_compiler_crates__unicode-segmentation-1.13.2//:unicode_segmentation\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=heck\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.3\",\n)\n" + } + }, + "postmaster_compiler_crates__heck-0.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/heck/0.5.0/download" + ], + "strip_prefix": "heck-0.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"heck\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=heck\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.0\",\n)\n" + } + }, + "postmaster_compiler_crates__hermit-abi-0.5.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hermit-abi/0.5.2/download" + ], + "strip_prefix": "hermit-abi-0.5.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hermit_abi\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hermit-abi\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.2\",\n)\n" + } + }, + "postmaster_compiler_crates__hex-0.4.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hex/0.4.3/download" + ], + "strip_prefix": "hex-0.4.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hex\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hex\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.3\",\n)\n" + } + }, + "postmaster_compiler_crates__http-1.4.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/http/1.4.0/download" + ], + "strip_prefix": "http-1.4.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"http\",\n deps = [\n \"@postmaster_compiler_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_compiler_crates__itoa-1.0.18//:itoa\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=http\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.4.0\",\n)\n" + } + }, + "postmaster_compiler_crates__hybrid-array-0.4.10": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3944cf8cf766b40e2a1a333ee5e9b563f854d5fa49d6a8ca2764e97c6eddb214", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hybrid-array/0.4.10/download" + ], + "strip_prefix": "hybrid-array-0.4.10", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hybrid_array\",\n deps = [\n \"@postmaster_compiler_crates__typenum-1.20.0//:typenum\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hybrid-array\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.10\",\n)\n" + } + }, + "postmaster_compiler_crates__icu_collections-2.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_collections/2.2.0/download" + ], + "strip_prefix": "icu_collections-2.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"icu_collections\",\n deps = [\n \"@postmaster_compiler_crates__potential_utf-0.1.5//:potential_utf\",\n \"@postmaster_compiler_crates__utf8_iter-1.0.4//:utf8_iter\",\n \"@postmaster_compiler_crates__yoke-0.8.2//:yoke\",\n \"@postmaster_compiler_crates__zerofrom-0.1.7//:zerofrom\",\n \"@postmaster_compiler_crates__zerovec-0.11.6//:zerovec\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__displaydoc-0.2.5//:displaydoc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_collections\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.2.0\",\n)\n" + } + }, + "postmaster_compiler_crates__icu_locale_core-2.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_locale_core/2.2.0/download" + ], + "strip_prefix": "icu_locale_core-2.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"icu_locale_core\",\n deps = [\n \"@postmaster_compiler_crates__litemap-0.8.2//:litemap\",\n \"@postmaster_compiler_crates__tinystr-0.8.3//:tinystr\",\n \"@postmaster_compiler_crates__writeable-0.6.3//:writeable\",\n \"@postmaster_compiler_crates__zerovec-0.11.6//:zerovec\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__displaydoc-0.2.5//:displaydoc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"zerovec\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_locale_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.2.0\",\n)\n" + } + }, + "postmaster_compiler_crates__icu_normalizer-2.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_normalizer/2.2.0/download" + ], + "strip_prefix": "icu_normalizer-2.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"icu_normalizer\",\n deps = [\n \"@postmaster_compiler_crates__icu_collections-2.2.0//:icu_collections\",\n \"@postmaster_compiler_crates__icu_normalizer_data-2.2.0//:icu_normalizer_data\",\n \"@postmaster_compiler_crates__icu_provider-2.2.0//:icu_provider\",\n \"@postmaster_compiler_crates__smallvec-1.15.1//:smallvec\",\n \"@postmaster_compiler_crates__zerovec-0.11.6//:zerovec\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"compiled_data\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_normalizer\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.2.0\",\n)\n" + } + }, + "postmaster_compiler_crates__icu_normalizer_data-2.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_normalizer_data/2.2.0/download" + ], + "strip_prefix": "icu_normalizer_data-2.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"icu_normalizer_data\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_normalizer_data\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.2.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"icu_normalizer_data\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_normalizer_data\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"2.2.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__icu_properties-2.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_properties/2.2.0/download" + ], + "strip_prefix": "icu_properties-2.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"icu_properties\",\n deps = [\n \"@postmaster_compiler_crates__icu_collections-2.2.0//:icu_collections\",\n \"@postmaster_compiler_crates__icu_locale_core-2.2.0//:icu_locale_core\",\n \"@postmaster_compiler_crates__icu_properties_data-2.2.0//:icu_properties_data\",\n \"@postmaster_compiler_crates__icu_provider-2.2.0//:icu_provider\",\n \"@postmaster_compiler_crates__zerotrie-0.2.4//:zerotrie\",\n \"@postmaster_compiler_crates__zerovec-0.11.6//:zerovec\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"compiled_data\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_properties\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.2.0\",\n)\n" + } + }, + "postmaster_compiler_crates__icu_properties_data-2.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_properties_data/2.2.0/download" + ], + "strip_prefix": "icu_properties_data-2.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"icu_properties_data\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_properties_data\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.2.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"icu_properties_data\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_properties_data\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"2.2.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__icu_provider-2.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/icu_provider/2.2.0/download" + ], + "strip_prefix": "icu_provider-2.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"icu_provider\",\n deps = [\n \"@postmaster_compiler_crates__icu_locale_core-2.2.0//:icu_locale_core\",\n \"@postmaster_compiler_crates__writeable-0.6.3//:writeable\",\n \"@postmaster_compiler_crates__yoke-0.8.2//:yoke\",\n \"@postmaster_compiler_crates__zerofrom-0.1.7//:zerofrom\",\n \"@postmaster_compiler_crates__zerotrie-0.2.4//:zerotrie\",\n \"@postmaster_compiler_crates__zerovec-0.11.6//:zerovec\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__displaydoc-0.2.5//:displaydoc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"baked\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=icu_provider\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.2.0\",\n)\n" + } + }, + "postmaster_compiler_crates__id-arena-2.3.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/id-arena/2.3.0/download" + ], + "strip_prefix": "id-arena-2.3.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"id_arena\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=id-arena\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.3.0\",\n)\n" + } + }, + "postmaster_compiler_crates__ident_case-1.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ident_case/1.0.1/download" + ], + "strip_prefix": "ident_case-1.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ident_case\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ident_case\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.1\",\n)\n" + } + }, + "postmaster_compiler_crates__idna-1.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/idna/1.1.0/download" + ], + "strip_prefix": "idna-1.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"idna\",\n deps = [\n \"@postmaster_compiler_crates__idna_adapter-1.2.1//:idna_adapter\",\n \"@postmaster_compiler_crates__smallvec-1.15.1//:smallvec\",\n \"@postmaster_compiler_crates__utf8_iter-1.0.4//:utf8_iter\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"compiled_data\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=idna\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.0\",\n)\n" + } + }, + "postmaster_compiler_crates__idna_adapter-1.2.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/idna_adapter/1.2.1/download" + ], + "strip_prefix": "idna_adapter-1.2.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"idna_adapter\",\n deps = [\n \"@postmaster_compiler_crates__icu_normalizer-2.2.0//:icu_normalizer\",\n \"@postmaster_compiler_crates__icu_properties-2.2.0//:icu_properties\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"compiled_data\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=idna_adapter\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.1\",\n)\n" + } + }, + "postmaster_compiler_crates__ignore-0.4.25": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ignore/0.4.25/download" + ], + "strip_prefix": "ignore-0.4.25", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ignore\",\n deps = [\n \"@postmaster_compiler_crates__crossbeam-deque-0.8.6//:crossbeam_deque\",\n \"@postmaster_compiler_crates__globset-0.4.18//:globset\",\n \"@postmaster_compiler_crates__log-0.4.29//:log\",\n \"@postmaster_compiler_crates__memchr-2.8.0//:memchr\",\n \"@postmaster_compiler_crates__regex-automata-0.4.14//:regex_automata\",\n \"@postmaster_compiler_crates__same-file-1.0.6//:same_file\",\n \"@postmaster_compiler_crates__walkdir-2.5.0//:walkdir\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ignore\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.25\",\n)\n" + } + }, + "postmaster_compiler_crates__indexmap-2.14.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/indexmap/2.14.0/download" + ], + "strip_prefix": "indexmap-2.14.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"indexmap\",\n deps = [\n \"@postmaster_compiler_crates__equivalent-1.0.2//:equivalent\",\n \"@postmaster_compiler_crates__hashbrown-0.17.0//:hashbrown\",\n \"@postmaster_compiler_crates__serde_core-1.0.228//:serde_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=indexmap\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.14.0\",\n)\n" + } + }, + "postmaster_compiler_crates__inkwell-0.9.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7decbc9dfa45a4a827a6ff7b822c113b1285678a937e84213417d4ca8a095782", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/inkwell/0.9.0/download" + ], + "strip_prefix": "inkwell-0.9.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"inkwell\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__bitflags-2.11.1//:bitflags\",\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\",\n \"@postmaster_compiler_crates__llvm-sys-221.0.1//:llvm_sys\",\n \"@postmaster_compiler_crates__thiserror-2.0.18//:thiserror\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__inkwell_internals-0.14.0//:inkwell_internals\",\n ],\n aliases = {\n \"@postmaster_compiler_crates__llvm-sys-221.0.1//:llvm_sys\": \"llvm_sys_221\",\n },\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"llvm-sys-221\",\n \"llvm22-1\",\n \"llvm22-1-prefer-static\",\n \"target-aarch64\",\n \"target-loongarch\",\n \"target-riscv\",\n \"target-x86\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=inkwell\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"llvm-sys-221\",\n \"llvm22-1\",\n \"llvm22-1-prefer-static\",\n \"target-aarch64\",\n \"target-loongarch\",\n \"target-riscv\",\n \"target-x86\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n link_deps = [\n \"@postmaster_compiler_crates__llvm-sys-221.0.1//:llvm_sys\",\n ],\n edition = \"2024\",\n pkg_name = \"inkwell\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=inkwell\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.9.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__inkwell_internals-0.14.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6cfe97ee860815a90ed17e09639513269e39420a7440f3f4c996f238c514cf8d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/inkwell_internals/0.14.0/download" + ], + "strip_prefix": "inkwell_internals-0.14.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"inkwell_internals\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=inkwell_internals\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.14.0\",\n)\n" + } + }, + "postmaster_compiler_crates__insta-1.47.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7b4a6248eb93a4401ed2f37dfe8ea592d3cf05b7cf4f8efa867b6895af7e094e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/insta/1.47.2/download" + ], + "strip_prefix": "insta-1.47.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"insta\",\n deps = [\n \"@postmaster_compiler_crates__console-0.16.3//:console\",\n \"@postmaster_compiler_crates__once_cell-1.21.4//:once_cell\",\n \"@postmaster_compiler_crates__regex-1.12.3//:regex\",\n \"@postmaster_compiler_crates__serde-1.0.228//:serde\",\n \"@postmaster_compiler_crates__similar-2.7.0//:similar\",\n \"@postmaster_compiler_crates__tempfile-3.27.0//:tempfile\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"colors\",\n \"console\",\n \"default\",\n \"filters\",\n \"regex\",\n \"serde\",\n \"yaml\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=insta\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.47.2\",\n)\n" + } + }, + "postmaster_compiler_crates__ipnet-2.12.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ipnet/2.12.0/download" + ], + "strip_prefix": "ipnet-2.12.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ipnet\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ipnet\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.12.0\",\n)\n" + } + }, + "postmaster_compiler_crates__iprange-0.6.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "37209be0ad225457e63814401415e748e2453a5297f9b637338f5fb8afa4ec00", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/iprange/0.6.7/download" + ], + "strip_prefix": "iprange-0.6.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"iprange\",\n deps = [\n \"@postmaster_compiler_crates__ipnet-2.12.0//:ipnet\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=iprange\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.7\",\n)\n" + } + }, + "postmaster_compiler_crates__itertools-0.13.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/itertools/0.13.0/download" + ], + "strip_prefix": "itertools-0.13.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"itertools\",\n deps = [\n \"@postmaster_compiler_crates__either-1.15.0//:either\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=itertools\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.13.0\",\n)\n" + } + }, + "postmaster_compiler_crates__itertools-0.14.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/itertools/0.14.0/download" + ], + "strip_prefix": "itertools-0.14.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"itertools\",\n deps = [\n \"@postmaster_compiler_crates__either-1.15.0//:either\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"use_alloc\",\n \"use_std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=itertools\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.14.0\",\n)\n" + } + }, + "postmaster_compiler_crates__itoa-1.0.18": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/itoa/1.0.18/download" + ], + "strip_prefix": "itoa-1.0.18", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"itoa\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=itoa\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.18\",\n)\n" + } + }, + "postmaster_compiler_crates__jobserver-0.1.34": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/jobserver/0.1.34/download" + ], + "strip_prefix": "jobserver-0.1.34", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"jobserver\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=jobserver\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.34\",\n)\n" + } + }, + "postmaster_compiler_crates__js-sys-0.3.95": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/js-sys/0.3.95/download" + ], + "strip_prefix": "js-sys-0.3.95", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"js_sys\",\n deps = [\n \"@postmaster_compiler_crates__once_cell-1.21.4//:once_cell\",\n \"@postmaster_compiler_crates__wasm-bindgen-0.2.118//:wasm_bindgen\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=js-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.95\",\n)\n" + } + }, + "postmaster_compiler_crates__lazy_static-1.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/lazy_static/1.5.0/download" + ], + "strip_prefix": "lazy_static-1.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"lazy_static\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=lazy_static\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.5.0\",\n)\n" + } + }, + "postmaster_compiler_crates__leb128-0.2.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6cc46bac87ef8093eed6f272babb833b6443374399985ac8ed28471ee0918545", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/leb128/0.2.6/download" + ], + "strip_prefix": "leb128-0.2.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"leb128\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=leb128\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.6\",\n)\n" + } + }, + "postmaster_compiler_crates__leb128fmt-0.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/leb128fmt/0.1.0/download" + ], + "strip_prefix": "leb128fmt-0.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"leb128fmt\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=leb128fmt\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.0\",\n)\n" + } + }, + "postmaster_compiler_crates__lexical-sort-0.3.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c09e4591611e231daf4d4c685a66cb0410cc1e502027a20ae55f2bb9e997207a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/lexical-sort/0.3.1/download" + ], + "strip_prefix": "lexical-sort-0.3.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"lexical_sort\",\n deps = [\n \"@postmaster_compiler_crates__any_ascii-0.1.7//:any_ascii\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=lexical-sort\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.1\",\n)\n" + } + }, + "postmaster_compiler_crates__libc-0.2.186": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/libc/0.2.186/download" + ], + "strip_prefix": "libc-0.2.186", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"libc\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=libc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.186\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"libc\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=libc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.2.186\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__libloading-0.8.9": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/libloading/0.8.9/download" + ], + "strip_prefix": "libloading-0.8.9", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"libloading\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=libloading\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.9\",\n)\n" + } + }, + "postmaster_compiler_crates__libredox-0.1.16": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/libredox/0.1.16/download" + ], + "strip_prefix": "libredox-0.1.16", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"libredox\",\n deps = [\n \"@postmaster_compiler_crates__redox_syscall-0.7.4//:syscall\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=libredox\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.16\",\n)\n" + } + }, + "postmaster_compiler_crates__libunwind-1.3.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0c6639b70a7ce854b79c70d7e83f16b5dc0137cc914f3d7d03803b513ecc67ac", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/libunwind/1.3.3/download" + ], + "strip_prefix": "libunwind-1.3.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"libunwind\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=libunwind\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.3.3\",\n)\n" + } + }, + "postmaster_compiler_crates__linked-hash-map-0.5.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/linked-hash-map/0.5.6/download" + ], + "strip_prefix": "linked-hash-map-0.5.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"linked_hash_map\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=linked-hash-map\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.6\",\n)\n" + } + }, + "postmaster_compiler_crates__linked_hash_set-0.1.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "984fb35d06508d1e69fc91050cceba9c0b748f983e6739fa2c7a9237154c52c8", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/linked_hash_set/0.1.6/download" + ], + "strip_prefix": "linked_hash_set-0.1.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"linked_hash_set\",\n deps = [\n \"@postmaster_compiler_crates__linked-hash-map-0.5.6//:linked_hash_map\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=linked_hash_set\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.6\",\n)\n" + } + }, + "postmaster_compiler_crates__linux-raw-sys-0.12.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/linux-raw-sys/0.12.1/download" + ], + "strip_prefix": "linux-raw-sys-0.12.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"linux_raw_sys\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"auxvec\",\n \"elf\",\n \"errno\",\n \"general\",\n \"ioctl\",\n \"no_std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=linux-raw-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.12.1\",\n)\n" + } + }, + "postmaster_compiler_crates__litemap-0.8.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/litemap/0.8.2/download" + ], + "strip_prefix": "litemap-0.8.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"litemap\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=litemap\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.2\",\n)\n" + } + }, + "postmaster_compiler_crates__litrs-1.0.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/litrs/1.0.0/download" + ], + "strip_prefix": "litrs-1.0.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"litrs\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=litrs\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.0\",\n)\n" + } + }, + "postmaster_compiler_crates__llvm-sys-221.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [ + "@@//build_defs/wasix:llvm-sys-declared-prefix.patch" + ], + "remote_patch_strip": 1, + "sha256": "2abcc34a3b190f03c2a61b555f218f529589ff13657bdd2ff8ac3e85f2abe6bb", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/llvm-sys/221.0.1/download" + ], + "strip_prefix": "llvm-sys-221.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"llvm_sys\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\",\n ],\n link_deps = [\n \"@@//build_defs/wasix/postmaster:llvm_zstd\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@@//build_defs/wasix:llvm_libxml2_arm64\", # aarch64-unknown-linux-gnu\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@@//build_defs/extensions/postgis:libxml2\", # x86_64-unknown-linux-gnu\n \"@@//build_defs/wasix:wasmer_llvm_gnu_link\", # x86_64-unknown-linux-gnu\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"prefer-static\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=llvm-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"221.0.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n \"@@//build_defs/wasix:wasmer_llvm_env\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@@//build_defs/wasix:wasmer_llvm_gnu_env\", # x86_64-unknown-linux-gnu\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"prefer-static\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ) + [\n \"@@//build_defs/wasix:wasmer_llvm_files\",\n ] + select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@@//build_defs/wasix:wasmer_llvm_gnu_files\", # x86_64-unknown-linux-gnu\n ],\n \"//conditions:default\": [],\n }),\n deps = [\n \"@postmaster_compiler_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_compiler_crates__cc-1.2.60//:cc\",\n \"@postmaster_compiler_crates__lazy_static-1.5.0//:lazy_static\",\n \"@postmaster_compiler_crates__regex-lite-0.1.9//:regex_lite\",\n \"@postmaster_compiler_crates__semver-1.0.28//:semver\",\n ],\n emit_warnings = False,\n edition = \"2021\",\n links = \"llvm-22\",\n pkg_name = \"llvm-sys\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=llvm-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"221.0.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__lock_api-0.4.14": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/lock_api/0.4.14/download" + ], + "strip_prefix": "lock_api-0.4.14", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"lock_api\",\n deps = [\n \"@postmaster_compiler_crates__scopeguard-1.2.0//:scopeguard\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"atomic_usize\",\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=lock_api\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.14\",\n)\n" + } + }, + "postmaster_compiler_crates__log-0.4.29": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/log/0.4.29/download" + ], + "strip_prefix": "log-0.4.29", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"log\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=log\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.29\",\n)\n" + } + }, + "postmaster_compiler_crates__lz4_flex-0.13.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "db9a0d582c2874f68138a16ce1867e0ffde6c0bb0a0df85e1f36d04146db488a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/lz4_flex/0.13.0/download" + ], + "strip_prefix": "lz4_flex-0.13.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"lz4_flex\",\n deps = [\n \"@postmaster_compiler_crates__twox-hash-2.1.2//:twox_hash\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"checked-decode\",\n \"default\",\n \"frame\",\n \"safe-decode\",\n \"safe-encode\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=lz4_flex\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.13.0\",\n)\n" + } + }, + "postmaster_compiler_crates__mach2-0.4.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/mach2/0.4.3/download" + ], + "strip_prefix": "mach2-0.4.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"mach2\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(any(target_os = \"macos\", target_os = \"ios\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=mach2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.3\",\n)\n" + } + }, + "postmaster_compiler_crates__mach2-0.6.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/mach2/0.6.0/download" + ], + "strip_prefix": "mach2-0.6.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"mach2\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=mach2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.0\",\n)\n" + } + }, + "postmaster_compiler_crates__macho-unwind-info-0.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/macho-unwind-info/0.5.0/download" + ], + "strip_prefix": "macho-unwind-info-0.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"macho_unwind_info\",\n deps = [\n \"@postmaster_compiler_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_compiler_crates__zerocopy-0.8.48//:zerocopy\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__zerocopy-derive-0.8.48//:zerocopy_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=macho-unwind-info\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.0\",\n)\n" + } + }, + "postmaster_compiler_crates__managed-0.8.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/managed/0.8.0/download" + ], + "strip_prefix": "managed-0.8.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"managed\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"map\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=managed\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.0\",\n)\n" + } + }, + "postmaster_compiler_crates__memchr-2.8.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/memchr/2.8.0/download" + ], + "strip_prefix": "memchr-2.8.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"memchr\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=memchr\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.8.0\",\n)\n" + } + }, + "postmaster_compiler_crates__memmap2-0.6.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6d28bba84adfe6646737845bc5ebbfa2c08424eb1c37e94a1fd2a82adb56a872", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/memmap2/0.6.2/download" + ], + "strip_prefix": "memmap2-0.6.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"memmap2\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=memmap2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.2\",\n)\n" + } + }, + "postmaster_compiler_crates__memmap2-0.9.10": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/memmap2/0.9.10/download" + ], + "strip_prefix": "memmap2-0.9.10", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"memmap2\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=memmap2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.10\",\n)\n" + } + }, + "postmaster_compiler_crates__memoffset-0.9.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/memoffset/0.9.1/download" + ], + "strip_prefix": "memoffset-0.9.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"memoffset\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=memoffset\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@postmaster_compiler_crates__autocfg-1.5.0//:autocfg\",\n ],\n emit_warnings = False,\n edition = \"2015\",\n pkg_name = \"memoffset\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=memoffset\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.9.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__minimal-lexical-0.2.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/minimal-lexical/0.2.1/download" + ], + "strip_prefix": "minimal-lexical-0.2.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"minimal_lexical\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=minimal-lexical\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.1\",\n)\n" + } + }, + "postmaster_compiler_crates__miniz_oxide-0.8.9": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/miniz_oxide/0.8.9/download" + ], + "strip_prefix": "miniz_oxide-0.8.9", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"miniz_oxide\",\n deps = [\n \"@postmaster_compiler_crates__adler2-2.0.1//:adler2\",\n \"@postmaster_compiler_crates__simd-adler32-0.3.9//:simd_adler32\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"simd\",\n \"simd-adler32\",\n \"with-alloc\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=miniz_oxide\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.9\",\n)\n" + } + }, + "postmaster_compiler_crates__more-asserts-0.3.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/more-asserts/0.3.1/download" + ], + "strip_prefix": "more-asserts-0.3.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"more_asserts\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=more-asserts\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.1\",\n)\n" + } + }, + "postmaster_compiler_crates__msvc-demangler-0.11.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "fbeff6bd154a309b2ada5639b2661ca6ae4599b34e8487dc276d2cd637da2d76", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/msvc-demangler/0.11.0/download" + ], + "strip_prefix": "msvc-demangler-0.11.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"msvc_demangler\",\n deps = [\n \"@postmaster_compiler_crates__bitflags-2.11.1//:bitflags\",\n \"@postmaster_compiler_crates__itoa-1.0.18//:itoa\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=msvc-demangler\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.11.0\",\n)\n" + } + }, + "postmaster_compiler_crates__munge-0.4.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/munge/0.4.7/download" + ], + "strip_prefix": "munge-0.4.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"munge\",\n proc_macro_deps = [\n \"@postmaster_compiler_crates__munge_macro-0.4.7//:munge_macro\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=munge\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.7\",\n)\n" + } + }, + "postmaster_compiler_crates__munge_macro-0.4.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/munge_macro/0.4.7/download" + ], + "strip_prefix": "munge_macro-0.4.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"munge_macro\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=munge_macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.7\",\n)\n" + } + }, + "postmaster_compiler_crates__nom-5.1.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/nom/5.1.3/download" + ], + "strip_prefix": "nom-5.1.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"nom\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__memchr-2.8.0//:memchr\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=nom\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"5.1.3\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@postmaster_compiler_crates__version_check-0.9.5//:version_check\",\n ],\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"nom\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=nom\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"5.1.3\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__nom-7.1.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/nom/7.1.3/download" + ], + "strip_prefix": "nom-7.1.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"nom\",\n deps = [\n \"@postmaster_compiler_crates__memchr-2.8.0//:memchr\",\n \"@postmaster_compiler_crates__minimal-lexical-0.2.1//:minimal_lexical\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=nom\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"7.1.3\",\n)\n" + } + }, + "postmaster_compiler_crates__num-conv-0.2.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/num-conv/0.2.1/download" + ], + "strip_prefix": "num-conv-0.2.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"num_conv\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=num-conv\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.1\",\n)\n" + } + }, + "postmaster_compiler_crates__num-traits-0.2.19": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/num-traits/0.2.19/download" + ], + "strip_prefix": "num-traits-0.2.19", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"num_traits\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=num-traits\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.19\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@postmaster_compiler_crates__autocfg-1.5.0//:autocfg\",\n ],\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"num-traits\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=num-traits\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.2.19\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__num_cpus-1.17.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/num_cpus/1.17.0/download" + ], + "strip_prefix": "num_cpus-1.17.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"num_cpus\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(not(windows))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(not(windows))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(not(windows))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=num_cpus\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.17.0\",\n)\n" + } + }, + "postmaster_compiler_crates__num_enum-0.7.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/num_enum/0.7.6/download" + ], + "strip_prefix": "num_enum-0.7.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"num_enum\",\n proc_macro_deps = [\n \"@postmaster_compiler_crates__num_enum_derive-0.7.6//:num_enum_derive\",\n \"@postmaster_compiler_crates__rustversion-1.0.22//:rustversion\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=num_enum\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.6\",\n)\n" + } + }, + "postmaster_compiler_crates__num_enum_derive-0.7.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/num_enum_derive/0.7.6/download" + ], + "strip_prefix": "num_enum_derive-0.7.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"num_enum_derive\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro-crate-3.5.0//:proc_macro_crate\",\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"proc-macro-crate\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=num_enum_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.6\",\n)\n" + } + }, + "postmaster_compiler_crates__object-0.37.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/object/0.37.3/download" + ], + "strip_prefix": "object-0.37.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"object\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__memchr-2.8.0//:memchr\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"archive\",\n \"coff\",\n \"elf\",\n \"macho\",\n \"pe\",\n \"read_core\",\n \"unaligned\",\n \"xcoff\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=object\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.37.3\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"archive\",\n \"coff\",\n \"elf\",\n \"macho\",\n \"pe\",\n \"read_core\",\n \"unaligned\",\n \"xcoff\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"object\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=object\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.37.3\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__object-0.39.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/object/0.39.1/download" + ], + "strip_prefix": "object-0.39.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"object\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__crc32fast-1.5.0//:crc32fast\",\n \"@postmaster_compiler_crates__flate2-1.1.9//:flate2\",\n \"@postmaster_compiler_crates__hashbrown-0.17.0//:hashbrown\",\n \"@postmaster_compiler_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_compiler_crates__memchr-2.8.0//:memchr\",\n \"@postmaster_compiler_crates__ruzstd-0.8.2//:ruzstd\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"archive\",\n \"coff\",\n \"compression\",\n \"default\",\n \"elf\",\n \"macho\",\n \"pe\",\n \"read\",\n \"read_core\",\n \"std\",\n \"write\",\n \"write_core\",\n \"write_std\",\n \"xcoff\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=object\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.39.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"archive\",\n \"coff\",\n \"compression\",\n \"default\",\n \"elf\",\n \"macho\",\n \"pe\",\n \"read\",\n \"read_core\",\n \"std\",\n \"write\",\n \"write_core\",\n \"write_std\",\n \"xcoff\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"object\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=object\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.39.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__once_cell-1.21.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/once_cell/1.21.4/download" + ], + "strip_prefix": "once_cell-1.21.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"once_cell\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"race\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=once_cell\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.21.4\",\n)\n" + } + }, + "postmaster_compiler_crates__parking-2.2.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/parking/2.2.1/download" + ], + "strip_prefix": "parking-2.2.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"parking\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=parking\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.2.1\",\n)\n" + } + }, + "postmaster_compiler_crates__parking_lot-0.12.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/parking_lot/0.12.5/download" + ], + "strip_prefix": "parking_lot-0.12.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"parking_lot\",\n deps = [\n \"@postmaster_compiler_crates__lock_api-0.4.14//:lock_api\",\n \"@postmaster_compiler_crates__parking_lot_core-0.9.12//:parking_lot_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=parking_lot\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.12.5\",\n)\n" + } + }, + "postmaster_compiler_crates__parking_lot_core-0.9.12": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/parking_lot_core/0.9.12/download" + ], + "strip_prefix": "parking_lot_core-0.9.12", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"parking_lot_core\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_compiler_crates__smallvec-1.15.1//:smallvec\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=parking_lot_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.12\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"parking_lot_core\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=parking_lot_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.9.12\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__paste-1.0.15": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/paste/1.0.15/download" + ], + "strip_prefix": "paste-1.0.15", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"paste\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=paste\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.15\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"paste\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=paste\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.15\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__path-clean-1.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/path-clean/1.0.1/download" + ], + "strip_prefix": "path-clean-1.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"path_clean\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=path-clean\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.1\",\n)\n" + } + }, + "postmaster_compiler_crates__percent-encoding-2.3.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/percent-encoding/2.3.2/download" + ], + "strip_prefix": "percent-encoding-2.3.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"percent_encoding\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=percent-encoding\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.3.2\",\n)\n" + } + }, + "postmaster_compiler_crates__petgraph-0.8.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/petgraph/0.8.3/download" + ], + "strip_prefix": "petgraph-0.8.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"petgraph\",\n deps = [\n \"@postmaster_compiler_crates__fixedbitset-0.5.7//:fixedbitset\",\n \"@postmaster_compiler_crates__hashbrown-0.15.5//:hashbrown\",\n \"@postmaster_compiler_crates__indexmap-2.14.0//:indexmap\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"graphmap\",\n \"matrix_graph\",\n \"stable_graph\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=petgraph\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.3\",\n)\n" + } + }, + "postmaster_compiler_crates__phf-0.13.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/phf/0.13.1/download" + ], + "strip_prefix": "phf-0.13.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"phf\",\n deps = [\n \"@postmaster_compiler_crates__phf_shared-0.13.1//:phf_shared\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__phf_macros-0.13.1//:phf_macros\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"macros\",\n \"phf_macros\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=phf\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.13.1\",\n)\n" + } + }, + "postmaster_compiler_crates__phf_generator-0.13.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/phf_generator/0.13.1/download" + ], + "strip_prefix": "phf_generator-0.13.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"phf_generator\",\n deps = [\n \"@postmaster_compiler_crates__fastrand-2.4.1//:fastrand\",\n \"@postmaster_compiler_crates__phf_shared-0.13.1//:phf_shared\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=phf_generator\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.13.1\",\n)\n" + } + }, + "postmaster_compiler_crates__phf_macros-0.13.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/phf_macros/0.13.1/download" + ], + "strip_prefix": "phf_macros-0.13.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"phf_macros\",\n deps = [\n \"@postmaster_compiler_crates__phf_generator-0.13.1//:phf_generator\",\n \"@postmaster_compiler_crates__phf_shared-0.13.1//:phf_shared\",\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=phf_macros\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.13.1\",\n)\n" + } + }, + "postmaster_compiler_crates__phf_shared-0.13.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/phf_shared/0.13.1/download" + ], + "strip_prefix": "phf_shared-0.13.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"phf_shared\",\n deps = [\n \"@postmaster_compiler_crates__siphasher-1.0.2//:siphasher\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=phf_shared\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.13.1\",\n)\n" + } + }, + "postmaster_compiler_crates__pin-project-1.1.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/pin-project/1.1.11/download" + ], + "strip_prefix": "pin-project-1.1.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"pin_project\",\n proc_macro_deps = [\n \"@postmaster_compiler_crates__pin-project-internal-1.1.11//:pin_project_internal\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pin-project\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.11\",\n)\n" + } + }, + "postmaster_compiler_crates__pin-project-internal-1.1.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/pin-project-internal/1.1.11/download" + ], + "strip_prefix": "pin-project-internal-1.1.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"pin_project_internal\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pin-project-internal\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.11\",\n)\n" + } + }, + "postmaster_compiler_crates__pin-project-lite-0.2.17": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/pin-project-lite/0.2.17/download" + ], + "strip_prefix": "pin-project-lite-0.2.17", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"pin_project_lite\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pin-project-lite\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.17\",\n)\n" + } + }, + "postmaster_compiler_crates__pin-utils-0.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/pin-utils/0.1.0/download" + ], + "strip_prefix": "pin-utils-0.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"pin_utils\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pin-utils\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.0\",\n)\n" + } + }, + "postmaster_compiler_crates__pkg-config-0.3.33": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/pkg-config/0.3.33/download" + ], + "strip_prefix": "pkg-config-0.3.33", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"pkg_config\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pkg-config\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.33\",\n)\n" + } + }, + "postmaster_compiler_crates__plain-0.2.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/plain/0.2.3/download" + ], + "strip_prefix": "plain-0.2.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"plain\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=plain\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.3\",\n)\n" + } + }, + "postmaster_compiler_crates__potential_utf-0.1.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/potential_utf/0.1.5/download" + ], + "strip_prefix": "potential_utf-0.1.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"potential_utf\",\n deps = [\n \"@postmaster_compiler_crates__zerovec-0.11.6//:zerovec\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"zerovec\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=potential_utf\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.5\",\n)\n" + } + }, + "postmaster_compiler_crates__powerfmt-0.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/powerfmt/0.2.0/download" + ], + "strip_prefix": "powerfmt-0.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"powerfmt\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=powerfmt\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.0\",\n)\n" + } + }, + "postmaster_compiler_crates__ppv-lite86-0.2.21": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ppv-lite86/0.2.21/download" + ], + "strip_prefix": "ppv-lite86-0.2.21", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ppv_lite86\",\n deps = [\n \"@postmaster_compiler_crates__zerocopy-0.8.48//:zerocopy\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"simd\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ppv-lite86\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.21\",\n)\n" + } + }, + "postmaster_compiler_crates__prettyplease-0.2.37": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/prettyplease/0.2.37/download" + ], + "strip_prefix": "prettyplease-0.2.37", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"prettyplease\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"verbatim\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=prettyplease\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.37\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"verbatim\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n links = \"prettyplease02\",\n pkg_name = \"prettyplease\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=prettyplease\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.2.37\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__proc-macro-crate-3.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/proc-macro-crate/3.5.0/download" + ], + "strip_prefix": "proc-macro-crate-3.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"proc_macro_crate\",\n deps = [\n \"@postmaster_compiler_crates__toml_edit-0.25.11-spec-1.1.0//:toml_edit\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=proc-macro-crate\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"3.5.0\",\n)\n" + } + }, + "postmaster_compiler_crates__proc-macro-error-attr2-2.0.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/proc-macro-error-attr2/2.0.0/download" + ], + "strip_prefix": "proc-macro-error-attr2-2.0.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"proc_macro_error_attr2\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=proc-macro-error-attr2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.0\",\n)\n" + } + }, + "postmaster_compiler_crates__proc-macro-error2-2.0.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/proc-macro-error2/2.0.1/download" + ], + "strip_prefix": "proc-macro-error2-2.0.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"proc_macro_error2\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__proc-macro-error-attr2-2.0.0//:proc_macro_error_attr2\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"syn-error\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=proc-macro-error2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.1\",\n)\n" + } + }, + "postmaster_compiler_crates__proc-macro2-1.0.106": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/proc-macro2/1.0.106/download" + ], + "strip_prefix": "proc-macro2-1.0.106", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"proc_macro2\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__unicode-ident-1.0.24//:unicode_ident\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"proc-macro\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=proc-macro2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.106\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"proc-macro\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"proc-macro2\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=proc-macro2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.106\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__ptr_meta-0.3.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0b9a0cf95a1196af61d4f1cbdab967179516d9a4a4312af1f31948f8f6224a79", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ptr_meta/0.3.1/download" + ], + "strip_prefix": "ptr_meta-0.3.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ptr_meta\",\n proc_macro_deps = [\n \"@postmaster_compiler_crates__ptr_meta_derive-0.3.1//:ptr_meta_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"derive\",\n \"ptr_meta_derive\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ptr_meta\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.1\",\n)\n" + } + }, + "postmaster_compiler_crates__ptr_meta_derive-0.3.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ptr_meta_derive/0.3.1/download" + ], + "strip_prefix": "ptr_meta_derive-0.3.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"ptr_meta_derive\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ptr_meta_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.1\",\n)\n" + } + }, + "postmaster_compiler_crates__pulldown-cmark-0.8.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/pulldown-cmark/0.8.0/download" + ], + "strip_prefix": "pulldown-cmark-0.8.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"pulldown_cmark\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__bitflags-1.3.2//:bitflags\",\n \"@postmaster_compiler_crates__memchr-2.8.0//:memchr\",\n \"@postmaster_compiler_crates__unicase-2.9.0//:unicase\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pulldown-cmark\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"pulldown-cmark\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=pulldown-cmark\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.8.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__quote-1.0.45": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/quote/1.0.45/download" + ], + "strip_prefix": "quote-1.0.45", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"quote\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"proc-macro\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=quote\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.45\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"proc-macro\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"quote\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=quote\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.45\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__r-efi-5.3.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/r-efi/5.3.0/download" + ], + "strip_prefix": "r-efi-5.3.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"r_efi\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=r-efi\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"5.3.0\",\n)\n" + } + }, + "postmaster_compiler_crates__r-efi-6.0.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/r-efi/6.0.0/download" + ], + "strip_prefix": "r-efi-6.0.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"r_efi\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=r-efi\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"6.0.0\",\n)\n" + } + }, + "postmaster_compiler_crates__rancor-0.1.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a063ea72381527c2a0561da9c80000ef822bdd7c3241b1cc1b12100e3df081ee", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rancor/0.1.1/download" + ], + "strip_prefix": "rancor-0.1.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rancor\",\n deps = [\n \"@postmaster_compiler_crates__ptr_meta-0.3.1//:ptr_meta\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rancor\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.1\",\n)\n" + } + }, + "postmaster_compiler_crates__rand-0.10.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rand/0.10.1/download" + ], + "strip_prefix": "rand-0.10.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rand\",\n deps = [\n \"@postmaster_compiler_crates__chacha20-0.10.0//:chacha20\",\n \"@postmaster_compiler_crates__getrandom-0.4.2//:getrandom\",\n \"@postmaster_compiler_crates__rand_core-0.10.1//:rand_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n \"std_rng\",\n \"sys_rng\",\n \"thread_rng\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rand\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.1\",\n)\n" + } + }, + "postmaster_compiler_crates__rand-0.9.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rand/0.9.4/download" + ], + "strip_prefix": "rand-0.9.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rand\",\n deps = [\n \"@postmaster_compiler_crates__rand_chacha-0.9.0//:rand_chacha\",\n \"@postmaster_compiler_crates__rand_core-0.9.5//:rand_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"os_rng\",\n \"small_rng\",\n \"std\",\n \"std_rng\",\n \"thread_rng\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rand\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.4\",\n)\n" + } + }, + "postmaster_compiler_crates__rand_chacha-0.9.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rand_chacha/0.9.0/download" + ], + "strip_prefix": "rand_chacha-0.9.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rand_chacha\",\n deps = [\n \"@postmaster_compiler_crates__ppv-lite86-0.2.21//:ppv_lite86\",\n \"@postmaster_compiler_crates__rand_core-0.9.5//:rand_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rand_chacha\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.0\",\n)\n" + } + }, + "postmaster_compiler_crates__rand_core-0.10.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rand_core/0.10.1/download" + ], + "strip_prefix": "rand_core-0.10.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rand_core\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rand_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.1\",\n)\n" + } + }, + "postmaster_compiler_crates__rand_core-0.9.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rand_core/0.9.5/download" + ], + "strip_prefix": "rand_core-0.9.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rand_core\",\n deps = [\n \"@postmaster_compiler_crates__getrandom-0.3.4//:getrandom\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"os_rng\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rand_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.5\",\n)\n" + } + }, + "postmaster_compiler_crates__rangemap-1.7.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "973443cf09a9c8656b574a866ab68dfa19f0867d0340648c7d2f6a71b8a8ea68", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rangemap/1.7.1/download" + ], + "strip_prefix": "rangemap-1.7.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rangemap\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rangemap\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.7.1\",\n)\n" + } + }, + "postmaster_compiler_crates__rayon-1.12.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rayon/1.12.0/download" + ], + "strip_prefix": "rayon-1.12.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rayon\",\n deps = [\n \"@postmaster_compiler_crates__either-1.15.0//:either\",\n \"@postmaster_compiler_crates__rayon-core-1.13.0//:rayon_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rayon\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.12.0\",\n)\n" + } + }, + "postmaster_compiler_crates__rayon-core-1.13.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rayon-core/1.13.0/download" + ], + "strip_prefix": "rayon-core-1.13.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rayon_core\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__crossbeam-deque-0.8.6//:crossbeam_deque\",\n \"@postmaster_compiler_crates__crossbeam-utils-0.8.21//:crossbeam_utils\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rayon-core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.13.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n links = \"rayon-core\",\n pkg_name = \"rayon-core\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rayon-core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.13.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__redox_syscall-0.5.18": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/redox_syscall/0.5.18/download" + ], + "strip_prefix": "redox_syscall-0.5.18", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"syscall\",\n deps = [\n \"@postmaster_compiler_crates__bitflags-2.11.1//:bitflags\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=redox_syscall\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.18\",\n)\n" + } + }, + "postmaster_compiler_crates__redox_syscall-0.7.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f450ad9c3b1da563fb6948a8e0fb0fb9269711c9c73d9ea1de5058c79c8d643a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/redox_syscall/0.7.4/download" + ], + "strip_prefix": "redox_syscall-0.7.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"syscall\",\n deps = [\n \"@postmaster_compiler_crates__bitflags-2.11.1//:bitflags\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=redox_syscall\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.4\",\n)\n" + } + }, + "postmaster_compiler_crates__ref-cast-1.0.25": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ref-cast/1.0.25/download" + ], + "strip_prefix": "ref-cast-1.0.25", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ref_cast\",\n deps = [\n \":build_script_build\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__ref-cast-impl-1.0.25//:ref_cast_impl\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ref-cast\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.25\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"ref-cast\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ref-cast\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.25\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__ref-cast-impl-1.0.25": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ref-cast-impl/1.0.25/download" + ], + "strip_prefix": "ref-cast-impl-1.0.25", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"ref_cast_impl\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ref-cast-impl\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.25\",\n)\n" + } + }, + "postmaster_compiler_crates__regex-1.12.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/regex/1.12.3/download" + ], + "strip_prefix": "regex-1.12.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"regex\",\n deps = [\n \"@postmaster_compiler_crates__aho-corasick-1.1.4//:aho_corasick\",\n \"@postmaster_compiler_crates__memchr-2.8.0//:memchr\",\n \"@postmaster_compiler_crates__regex-automata-0.4.14//:regex_automata\",\n \"@postmaster_compiler_crates__regex-syntax-0.8.10//:regex_syntax\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"perf\",\n \"perf-backtrack\",\n \"perf-cache\",\n \"perf-dfa\",\n \"perf-inline\",\n \"perf-literal\",\n \"perf-onepass\",\n \"std\",\n \"unicode\",\n \"unicode-age\",\n \"unicode-bool\",\n \"unicode-case\",\n \"unicode-gencat\",\n \"unicode-perl\",\n \"unicode-script\",\n \"unicode-segment\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=regex\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.12.3\",\n)\n" + } + }, + "postmaster_compiler_crates__regex-automata-0.4.14": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/regex-automata/0.4.14/download" + ], + "strip_prefix": "regex-automata-0.4.14", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"regex_automata\",\n deps = [\n \"@postmaster_compiler_crates__aho-corasick-1.1.4//:aho_corasick\",\n \"@postmaster_compiler_crates__memchr-2.8.0//:memchr\",\n \"@postmaster_compiler_crates__regex-syntax-0.8.10//:regex_syntax\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"dfa-onepass\",\n \"hybrid\",\n \"meta\",\n \"nfa\",\n \"nfa-backtrack\",\n \"nfa-pikevm\",\n \"nfa-thompson\",\n \"perf\",\n \"perf-inline\",\n \"perf-literal\",\n \"perf-literal-multisubstring\",\n \"perf-literal-substring\",\n \"std\",\n \"syntax\",\n \"unicode\",\n \"unicode-age\",\n \"unicode-bool\",\n \"unicode-case\",\n \"unicode-gencat\",\n \"unicode-perl\",\n \"unicode-script\",\n \"unicode-segment\",\n \"unicode-word-boundary\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=regex-automata\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.14\",\n)\n" + } + }, + "postmaster_compiler_crates__regex-lite-0.1.9": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/regex-lite/0.1.9/download" + ], + "strip_prefix": "regex-lite-0.1.9", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"regex_lite\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n \"string\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=regex-lite\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.9\",\n)\n" + } + }, + "postmaster_compiler_crates__regex-syntax-0.8.10": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/regex-syntax/0.8.10/download" + ], + "strip_prefix": "regex-syntax-0.8.10", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"regex_syntax\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n \"unicode\",\n \"unicode-age\",\n \"unicode-bool\",\n \"unicode-case\",\n \"unicode-gencat\",\n \"unicode-perl\",\n \"unicode-script\",\n \"unicode-segment\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=regex-syntax\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.10\",\n)\n" + } + }, + "postmaster_compiler_crates__region-3.0.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/region/3.0.2/download" + ], + "strip_prefix": "region-3.0.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"region\",\n deps = [\n \"@postmaster_compiler_crates__bitflags-1.3.2//:bitflags\",\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__mach2-0.4.3//:mach2\", # cfg(any(target_os = \"macos\", target_os = \"ios\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=region\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"3.0.2\",\n)\n" + } + }, + "postmaster_compiler_crates__rend-0.5.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rend/0.5.3/download" + ], + "strip_prefix": "rend-0.5.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rend\",\n deps = [\n \"@postmaster_compiler_crates__bytecheck-0.8.2//:bytecheck\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"bytecheck\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rend\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.5.3\",\n)\n" + } + }, + "postmaster_compiler_crates__replace_with-0.1.8": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "51743d3e274e2b18df81c4dc6caf8a5b8e15dbe799e0dca05c7617380094e884", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/replace_with/0.1.8/download" + ], + "strip_prefix": "replace_with-0.1.8", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"replace_with\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=replace_with\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.8\",\n)\n" + } + }, + "postmaster_compiler_crates__rkyv-0.8.16": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "73389e0c99e664f919275ab5b5b0471391fe9a8de61e1dff9b1eaf56a90f16e3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rkyv/0.8.16/download" + ], + "strip_prefix": "rkyv-0.8.16", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rkyv\",\n deps = [\n \"@postmaster_compiler_crates__bytecheck-0.8.2//:bytecheck\",\n \"@postmaster_compiler_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_compiler_crates__hashbrown-0.17.0//:hashbrown\",\n \"@postmaster_compiler_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_compiler_crates__munge-0.4.7//:munge\",\n \"@postmaster_compiler_crates__ptr_meta-0.3.1//:ptr_meta\",\n \"@postmaster_compiler_crates__rancor-0.1.1//:rancor\",\n \"@postmaster_compiler_crates__rend-0.5.3//:rend\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__rkyv_derive-0.8.16//:rkyv_derive\",\n ],\n aliases = {\n \"@postmaster_compiler_crates__bytes-1.11.1//:bytes\": \"bytes_1\",\n \"@postmaster_compiler_crates__indexmap-2.14.0//:indexmap\": \"indexmap_2\",\n },\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"bytecheck\",\n \"bytes-1\",\n \"default\",\n \"indexmap-2\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rkyv\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.16\",\n)\n" + } + }, + "postmaster_compiler_crates__rkyv_derive-0.8.16": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5d2ed0b54125315fb36bd021e82d314d1c126548f871634b483f46b31d13cac6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rkyv_derive/0.8.16/download" + ], + "strip_prefix": "rkyv_derive-0.8.16", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"rkyv_derive\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"bytecheck\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rkyv_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.16\",\n)\n" + } + }, + "postmaster_compiler_crates__rustc-demangle-0.1.27": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rustc-demangle/0.1.27/download" + ], + "strip_prefix": "rustc-demangle-0.1.27", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rustc_demangle\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustc-demangle\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.27\",\n)\n" + } + }, + "postmaster_compiler_crates__rustc-hash-2.1.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rustc-hash/2.1.2/download" + ], + "strip_prefix": "rustc-hash-2.1.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rustc_hash\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustc-hash\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.1.2\",\n)\n" + } + }, + "postmaster_compiler_crates__rustc_version-0.4.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rustc_version/0.4.1/download" + ], + "strip_prefix": "rustc_version-0.4.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rustc_version\",\n deps = [\n \"@postmaster_compiler_crates__semver-1.0.28//:semver\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustc_version\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.1\",\n)\n" + } + }, + "postmaster_compiler_crates__rustix-1.1.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rustix/1.1.4/download" + ], + "strip_prefix": "rustix-1.1.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rustix\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__bitflags-2.11.1//:bitflags\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__errno-0.3.14//:errno\", # aarch64-apple-darwin, cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\")))))))\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # aarch64-apple-darwin, cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\")))))))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__linux-raw-sys-0.12.1//:linux_raw_sys\", # cfg(all(not(rustix_use_libc), not(miri), target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\"))))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__linux-raw-sys-0.12.1//:linux_raw_sys\", # cfg(all(not(rustix_use_libc), not(miri), target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\"))))\n ],\n \"//conditions:default\": [],\n }),\n aliases = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": {\n \"@postmaster_compiler_crates__errno-0.3.14//:errno\": \"libc_errno\", # aarch64-apple-darwin, cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\")))))))\n },\n \"//conditions:default\": {},\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"fs\",\n \"std\",\n \"termios\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustix\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.4\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"fs\",\n \"std\",\n \"termios\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"rustix\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustix\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.1.4\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__rustversion-1.0.22": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rustversion/1.0.22/download" + ], + "strip_prefix": "rustversion-1.0.22", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"rustversion\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustversion\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.22\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build/build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"rustversion\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rustversion\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.22\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__rusty_pool-0.7.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4ed36cdb20de66d89a17ea04b8883fc7a386f2cf877aaedca5005583ce4876ff", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/rusty_pool/0.7.0/download" + ], + "strip_prefix": "rusty_pool-0.7.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"rusty_pool\",\n deps = [\n \"@postmaster_compiler_crates__crossbeam-channel-0.5.15//:crossbeam_channel\",\n \"@postmaster_compiler_crates__futures-0.3.32//:futures\",\n \"@postmaster_compiler_crates__futures-channel-0.3.32//:futures_channel\",\n \"@postmaster_compiler_crates__futures-executor-0.3.32//:futures_executor\",\n \"@postmaster_compiler_crates__num_cpus-1.17.0//:num_cpus\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"async\",\n \"default\",\n \"futures\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=rusty_pool\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.0\",\n)\n" + } + }, + "postmaster_compiler_crates__ruzstd-0.8.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e5ff0cc5e135c8870a775d3320910cd9b564ec036b4dc0b8741629020be63f01", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ruzstd/0.8.2/download" + ], + "strip_prefix": "ruzstd-0.8.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ruzstd\",\n deps = [\n \"@postmaster_compiler_crates__twox-hash-2.1.2//:twox_hash\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"hash\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ruzstd\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.2\",\n)\n" + } + }, + "postmaster_compiler_crates__ryu-1.0.23": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/ryu/1.0.23/download" + ], + "strip_prefix": "ryu-1.0.23", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"ryu\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=ryu\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.23\",\n)\n" + } + }, + "postmaster_compiler_crates__saffron-0.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "03fb9a628596fc7590eb7edbf7b0613287be78df107f5f97b118aad59fb2eea9", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/saffron/0.1.0/download" + ], + "strip_prefix": "saffron-0.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"saffron\",\n deps = [\n \"@postmaster_compiler_crates__chrono-0.4.44//:chrono\",\n \"@postmaster_compiler_crates__nom-5.1.3//:nom\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=saffron\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.0\",\n)\n" + } + }, + "postmaster_compiler_crates__same-file-1.0.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/same-file/1.0.6/download" + ], + "strip_prefix": "same-file-1.0.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"same_file\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=same-file\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.6\",\n)\n" + } + }, + "postmaster_compiler_crates__schemars-1.2.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/schemars/1.2.1/download" + ], + "strip_prefix": "schemars-1.2.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"schemars\",\n deps = [\n \"@postmaster_compiler_crates__dyn-clone-1.0.20//:dyn_clone\",\n \"@postmaster_compiler_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_compiler_crates__ref-cast-1.0.25//:ref_cast\",\n \"@postmaster_compiler_crates__serde-1.0.228//:serde\",\n \"@postmaster_compiler_crates__serde_json-1.0.149//:serde_json\",\n \"@postmaster_compiler_crates__url-2.5.8//:url\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__schemars_derive-1.2.1//:schemars_derive\",\n ],\n aliases = {\n \"@postmaster_compiler_crates__indexmap-2.14.0//:indexmap\": \"indexmap2\",\n \"@postmaster_compiler_crates__url-2.5.8//:url\": \"url2\",\n },\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"derive\",\n \"indexmap2\",\n \"schemars_derive\",\n \"std\",\n \"url2\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=schemars\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.1\",\n)\n" + } + }, + "postmaster_compiler_crates__schemars_derive-1.2.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7d115b50f4aaeea07e79c1912f645c7513d81715d0420f8bc77a18c6260b307f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/schemars_derive/1.2.1/download" + ], + "strip_prefix": "schemars_derive-1.2.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"schemars_derive\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__serde_derive_internals-0.29.1//:serde_derive_internals\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=schemars_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.1\",\n)\n" + } + }, + "postmaster_compiler_crates__scopeguard-1.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/scopeguard/1.2.0/download" + ], + "strip_prefix": "scopeguard-1.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"scopeguard\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"use_std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=scopeguard\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.0\",\n)\n" + } + }, + "postmaster_compiler_crates__self_cell-1.2.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/self_cell/1.2.2/download" + ], + "strip_prefix": "self_cell-1.2.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"self_cell\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=self_cell\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.2\",\n)\n" + } + }, + "postmaster_compiler_crates__semver-1.0.28": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/semver/1.0.28/download" + ], + "strip_prefix": "semver-1.0.28", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"semver\",\n deps = [\n \"@postmaster_compiler_crates__serde_core-1.0.228//:serde_core\",\n ],\n aliases = {\n \"@postmaster_compiler_crates__serde_core-1.0.228//:serde_core\": \"serde\",\n },\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=semver\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.28\",\n)\n" + } + }, + "postmaster_compiler_crates__serde-1.0.228": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde/1.0.228/download" + ], + "strip_prefix": "serde-1.0.228", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__serde_core-1.0.228//:serde_core\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__serde_derive-1.0.228//:serde_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"derive\",\n \"rc\",\n \"serde_derive\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.228\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"derive\",\n \"rc\",\n \"serde_derive\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"serde\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.228\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__serde-wasm-bindgen-0.6.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde-wasm-bindgen/0.6.5/download" + ], + "strip_prefix": "serde-wasm-bindgen-0.6.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde_wasm_bindgen\",\n deps = [\n \"@postmaster_compiler_crates__js-sys-0.3.95//:js_sys\",\n \"@postmaster_compiler_crates__serde-1.0.228//:serde\",\n \"@postmaster_compiler_crates__wasm-bindgen-0.2.118//:wasm_bindgen\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde-wasm-bindgen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.5\",\n)\n" + } + }, + "postmaster_compiler_crates__serde_core-1.0.228": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde_core/1.0.228/download" + ], + "strip_prefix": "serde_core-1.0.228", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde_core\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"rc\",\n \"result\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.228\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"rc\",\n \"result\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"serde_core\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.228\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__serde_derive-1.0.228": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde_derive/1.0.228/download" + ], + "strip_prefix": "serde_derive-1.0.228", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"serde_derive\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.228\",\n)\n" + } + }, + "postmaster_compiler_crates__serde_derive_internals-0.29.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde_derive_internals/0.29.1/download" + ], + "strip_prefix": "serde_derive_internals-0.29.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde_derive_internals\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_derive_internals\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.29.1\",\n)\n" + } + }, + "postmaster_compiler_crates__serde_json-1.0.149": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde_json/1.0.149/download" + ], + "strip_prefix": "serde_json-1.0.149", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde_json\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__itoa-1.0.18//:itoa\",\n \"@postmaster_compiler_crates__memchr-2.8.0//:memchr\",\n \"@postmaster_compiler_crates__serde_core-1.0.228//:serde_core\",\n \"@postmaster_compiler_crates__zmij-1.0.21//:zmij\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_json\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.149\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"serde_json\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_json\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.149\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__serde_spanned-1.1.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde_spanned/1.1.1/download" + ], + "strip_prefix": "serde_spanned-1.1.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde_spanned\",\n deps = [\n \"@postmaster_compiler_crates__serde_core-1.0.228//:serde_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_spanned\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.1\",\n)\n" + } + }, + "postmaster_compiler_crates__serde_yaml-0.9.34-deprecated": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde_yaml/0.9.34+deprecated/download" + ], + "strip_prefix": "serde_yaml-0.9.34+deprecated", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde_yaml\",\n deps = [\n \"@postmaster_compiler_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_compiler_crates__itoa-1.0.18//:itoa\",\n \"@postmaster_compiler_crates__ryu-1.0.23//:ryu\",\n \"@postmaster_compiler_crates__serde-1.0.228//:serde\",\n \"@postmaster_compiler_crates__unsafe-libyaml-0.2.11//:unsafe_libyaml\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_yaml\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.34+deprecated\",\n)\n" + } + }, + "postmaster_compiler_crates__sha2-0.10.9": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/sha2/0.10.9/download" + ], + "strip_prefix": "sha2-0.10.9", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"sha2\",\n deps = [\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_compiler_crates__digest-0.10.7//:digest\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__cpufeatures-0.2.17//:cpufeatures\", # cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__cpufeatures-0.2.17//:cpufeatures\", # cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__cpufeatures-0.2.17//:cpufeatures\", # cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=sha2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.9\",\n)\n" + } + }, + "postmaster_compiler_crates__sha2-0.11.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/sha2/0.11.0/download" + ], + "strip_prefix": "sha2-0.11.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"sha2\",\n deps = [\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_compiler_crates__digest-0.11.2//:digest\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__cpufeatures-0.3.0//:cpufeatures\", # cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__cpufeatures-0.3.0//:cpufeatures\", # cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__cpufeatures-0.3.0//:cpufeatures\", # cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"oid\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=sha2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.11.0\",\n)\n" + } + }, + "postmaster_compiler_crates__shared-buffer-0.1.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f6c99835bad52957e7aa241d3975ed17c1e5f8c92026377d117a606f36b84b16", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/shared-buffer/0.1.4/download" + ], + "strip_prefix": "shared-buffer-0.1.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"shared_buffer\",\n deps = [\n \"@postmaster_compiler_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_compiler_crates__memmap2-0.6.2//:memmap2\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=shared-buffer\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.4\",\n)\n" + } + }, + "postmaster_compiler_crates__shlex-1.3.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/shlex/1.3.0/download" + ], + "strip_prefix": "shlex-1.3.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"shlex\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=shlex\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.3.0\",\n)\n" + } + }, + "postmaster_compiler_crates__simd-adler32-0.3.9": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/simd-adler32/0.3.9/download" + ], + "strip_prefix": "simd-adler32-0.3.9", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"simd_adler32\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=simd-adler32\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.9\",\n)\n" + } + }, + "postmaster_compiler_crates__simdutf8-0.1.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/simdutf8/0.1.5/download" + ], + "strip_prefix": "simdutf8-0.1.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"simdutf8\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=simdutf8\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.5\",\n)\n" + } + }, + "postmaster_compiler_crates__similar-2.7.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/similar/2.7.0/download" + ], + "strip_prefix": "similar-2.7.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"similar\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"inline\",\n \"text\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=similar\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.7.0\",\n)\n" + } + }, + "postmaster_compiler_crates__siphasher-1.0.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/siphasher/1.0.2/download" + ], + "strip_prefix": "siphasher-1.0.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"siphasher\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=siphasher\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.2\",\n)\n" + } + }, + "postmaster_compiler_crates__slab-0.4.12": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/slab/0.4.12/download" + ], + "strip_prefix": "slab-0.4.12", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"slab\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=slab\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.12\",\n)\n" + } + }, + "postmaster_compiler_crates__smallvec-1.15.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/smallvec/1.15.1/download" + ], + "strip_prefix": "smallvec-1.15.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"smallvec\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"const_generics\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=smallvec\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.15.1\",\n)\n" + } + }, + "postmaster_compiler_crates__smoltcp-0.13.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ac729b0a77bd092a3f06ddaddc59fe0d67f48ba0de45a9abe707c2842c7f8767", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/smoltcp/0.13.0/download" + ], + "strip_prefix": "smoltcp-0.13.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"smoltcp\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__bitflags-1.3.2//:bitflags\",\n \"@postmaster_compiler_crates__byteorder-1.5.0//:byteorder\",\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_compiler_crates__heapless-0.9.2//:heapless\",\n \"@postmaster_compiler_crates__managed-0.8.0//:managed\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"proto-ipv4\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=smoltcp\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.13.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"proto-ipv4\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2024\",\n pkg_name = \"smoltcp\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=smoltcp\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.13.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__stable_deref_trait-1.2.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/stable_deref_trait/1.2.1/download" + ], + "strip_prefix": "stable_deref_trait-1.2.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"stable_deref_trait\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=stable_deref_trait\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.1\",\n)\n" + } + }, + "postmaster_compiler_crates__strsim-0.11.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/strsim/0.11.1/download" + ], + "strip_prefix": "strsim-0.11.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"strsim\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=strsim\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.11.1\",\n)\n" + } + }, + "postmaster_compiler_crates__symbolic-common-12.18.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "332615d90111d8eeaf86a84dc9bbe9f65d0d8c5cf11b4caccedc37754eb0dcfd", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/symbolic-common/12.18.3/download" + ], + "strip_prefix": "symbolic-common-12.18.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"symbolic_common\",\n deps = [\n \"@postmaster_compiler_crates__debugid-0.8.0//:debugid\",\n \"@postmaster_compiler_crates__memmap2-0.9.10//:memmap2\",\n \"@postmaster_compiler_crates__stable_deref_trait-1.2.1//:stable_deref_trait\",\n \"@postmaster_compiler_crates__uuid-1.23.1//:uuid\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=symbolic-common\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"12.18.3\",\n)\n" + } + }, + "postmaster_compiler_crates__symbolic-demangle-12.18.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "912017718eb4d21930546245af9a3475c9dccf15675a5c215664e76621afc471", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/symbolic-demangle/12.18.3/download" + ], + "strip_prefix": "symbolic-demangle-12.18.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"symbolic_demangle\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__cpp_demangle-0.4.5//:cpp_demangle\",\n \"@postmaster_compiler_crates__msvc-demangler-0.11.0//:msvc_demangler\",\n \"@postmaster_compiler_crates__rustc-demangle-0.1.27//:rustc_demangle\",\n \"@postmaster_compiler_crates__symbolic-common-12.18.3//:symbolic_common\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"cpp\",\n \"cpp_demangle\",\n \"msvc\",\n \"msvc-demangler\",\n \"rust\",\n \"rustc-demangle\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=symbolic-demangle\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"12.18.3\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"cpp\",\n \"cpp_demangle\",\n \"msvc\",\n \"msvc-demangler\",\n \"rust\",\n \"rustc-demangle\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"symbolic-demangle\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=symbolic-demangle\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"12.18.3\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__syn-1.0.109": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/syn/1.0.109/download" + ], + "strip_prefix": "syn-1.0.109", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"syn\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__unicode-ident-1.0.24//:unicode_ident\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"clone-impls\",\n \"default\",\n \"derive\",\n \"parsing\",\n \"printing\",\n \"proc-macro\",\n \"quote\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=syn\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.109\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"clone-impls\",\n \"default\",\n \"derive\",\n \"parsing\",\n \"printing\",\n \"proc-macro\",\n \"quote\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"syn\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=syn\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.109\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__syn-2.0.117": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/syn/2.0.117/download" + ], + "strip_prefix": "syn-2.0.117", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"syn\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__unicode-ident-1.0.24//:unicode_ident\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"clone-impls\",\n \"default\",\n \"derive\",\n \"extra-traits\",\n \"fold\",\n \"full\",\n \"parsing\",\n \"printing\",\n \"proc-macro\",\n \"visit\",\n \"visit-mut\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=syn\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.117\",\n)\n" + } + }, + "postmaster_compiler_crates__synstructure-0.13.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/synstructure/0.13.2/download" + ], + "strip_prefix": "synstructure-0.13.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"synstructure\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"proc-macro\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=synstructure\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.13.2\",\n)\n" + } + }, + "postmaster_compiler_crates__tar-0.4.45": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tar/0.4.45/download" + ], + "strip_prefix": "tar-0.4.45", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tar\",\n deps = [\n \"@postmaster_compiler_crates__filetime-0.2.27//:filetime\",\n \"@postmaster_compiler_crates__xattr-1.6.1//:xattr\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"xattr\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tar\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.45\",\n)\n" + } + }, + "postmaster_compiler_crates__target-lexicon-0.13.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/target-lexicon/0.13.5/download" + ], + "strip_prefix": "target-lexicon-0.13.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"target_lexicon\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=target-lexicon\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.13.5\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2018\",\n pkg_name = \"target-lexicon\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=target-lexicon\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.13.5\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__tempfile-3.27.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tempfile/3.27.0/download" + ], + "strip_prefix": "tempfile-3.27.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tempfile\",\n deps = [\n \"@postmaster_compiler_crates__fastrand-2.4.1//:fastrand\",\n \"@postmaster_compiler_crates__getrandom-0.4.2//:getrandom\",\n \"@postmaster_compiler_crates__once_cell-1.21.4//:once_cell\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__rustix-1.1.4//:rustix\", # cfg(any(unix, target_os = \"wasi\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__rustix-1.1.4//:rustix\", # cfg(any(unix, target_os = \"wasi\"))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__rustix-1.1.4//:rustix\", # cfg(any(unix, target_os = \"wasi\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"getrandom\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tempfile\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"3.27.0\",\n)\n" + } + }, + "postmaster_compiler_crates__terminal_size-0.4.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/terminal_size/0.4.4/download" + ], + "strip_prefix": "terminal_size-0.4.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"terminal_size\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__rustix-1.1.4//:rustix\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__rustix-1.1.4//:rustix\", # cfg(unix)\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__rustix-1.1.4//:rustix\", # cfg(unix)\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=terminal_size\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.4\",\n)\n" + } + }, + "postmaster_compiler_crates__termios-0.3.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/termios/0.3.3/download" + ], + "strip_prefix": "termios-0.3.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"termios\",\n deps = [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=termios\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.3\",\n)\n" + } + }, + "postmaster_compiler_crates__thiserror-2.0.18": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/thiserror/2.0.18/download" + ], + "strip_prefix": "thiserror-2.0.18", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"thiserror\",\n deps = [\n \":build_script_build\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__thiserror-impl-2.0.18//:thiserror_impl\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=thiserror\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.18\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"thiserror\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=thiserror\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"2.0.18\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__thiserror-impl-2.0.18": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/thiserror-impl/2.0.18/download" + ], + "strip_prefix": "thiserror-impl-2.0.18", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"thiserror_impl\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=thiserror-impl\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.18\",\n)\n" + } + }, + "postmaster_compiler_crates__time-0.3.47": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/time/0.3.47/download" + ], + "strip_prefix": "time-0.3.47", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"time\",\n deps = [\n \"@postmaster_compiler_crates__deranged-0.5.8//:deranged\",\n \"@postmaster_compiler_crates__itoa-1.0.18//:itoa\",\n \"@postmaster_compiler_crates__num-conv-0.2.1//:num_conv\",\n \"@postmaster_compiler_crates__powerfmt-0.2.0//:powerfmt\",\n \"@postmaster_compiler_crates__time-core-0.1.8//:time_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"formatting\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=time\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.47\",\n)\n" + } + }, + "postmaster_compiler_crates__time-core-0.1.8": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/time-core/0.1.8/download" + ], + "strip_prefix": "time-core-0.1.8", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"time_core\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=time-core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.8\",\n)\n" + } + }, + "postmaster_compiler_crates__time-macros-0.2.27": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/time-macros/0.2.27/download" + ], + "strip_prefix": "time-macros-0.2.27", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"time_macros\",\n deps = [\n \"@postmaster_compiler_crates__num-conv-0.2.1//:num_conv\",\n \"@postmaster_compiler_crates__time-core-0.1.8//:time_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=time-macros\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.27\",\n)\n" + } + }, + "postmaster_compiler_crates__tinystr-0.8.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tinystr/0.8.3/download" + ], + "strip_prefix": "tinystr-0.8.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tinystr\",\n deps = [\n \"@postmaster_compiler_crates__zerovec-0.11.6//:zerovec\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__displaydoc-0.2.5//:displaydoc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"zerovec\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tinystr\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.3\",\n)\n" + } + }, + "postmaster_compiler_crates__tinyvec-1.11.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tinyvec/1.11.0/download" + ], + "strip_prefix": "tinyvec-1.11.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tinyvec\",\n deps = [\n \"@postmaster_compiler_crates__tinyvec_macros-0.1.1//:tinyvec_macros\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"tinyvec_macros\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tinyvec\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.11.0\",\n)\n" + } + }, + "postmaster_compiler_crates__tinyvec_macros-0.1.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tinyvec_macros/0.1.1/download" + ], + "strip_prefix": "tinyvec_macros-0.1.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tinyvec_macros\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tinyvec_macros\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.1\",\n)\n" + } + }, + "postmaster_compiler_crates__tokio-1.52.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tokio/1.52.1/download" + ], + "strip_prefix": "tokio-1.52.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tokio\",\n deps = [\n \"@postmaster_compiler_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_compiler_crates__pin-project-lite-0.2.17//:pin_project_lite\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__tokio-macros-2.7.0//:tokio_macros\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"bytes\",\n \"default\",\n \"fs\",\n \"io-util\",\n \"macros\",\n \"rt\",\n \"rt-multi-thread\",\n \"sync\",\n \"time\",\n \"tokio-macros\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tokio\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.52.1\",\n)\n" + } + }, + "postmaster_compiler_crates__tokio-macros-2.7.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tokio-macros/2.7.0/download" + ], + "strip_prefix": "tokio-macros-2.7.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"tokio_macros\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tokio-macros\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.7.0\",\n)\n" + } + }, + "postmaster_compiler_crates__tokio-stream-0.1.18": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tokio-stream/0.1.18/download" + ], + "strip_prefix": "tokio-stream-0.1.18", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tokio_stream\",\n deps = [\n \"@postmaster_compiler_crates__futures-core-0.3.32//:futures_core\",\n \"@postmaster_compiler_crates__pin-project-lite-0.2.17//:pin_project_lite\",\n \"@postmaster_compiler_crates__tokio-1.52.1//:tokio\",\n \"@postmaster_compiler_crates__tokio-util-0.7.18//:tokio_util\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"sync\",\n \"time\",\n \"tokio-util\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tokio-stream\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.18\",\n)\n" + } + }, + "postmaster_compiler_crates__tokio-util-0.7.18": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tokio-util/0.7.18/download" + ], + "strip_prefix": "tokio-util-0.7.18", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tokio_util\",\n deps = [\n \"@postmaster_compiler_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_compiler_crates__futures-core-0.3.32//:futures_core\",\n \"@postmaster_compiler_crates__futures-sink-0.3.32//:futures_sink\",\n \"@postmaster_compiler_crates__pin-project-lite-0.2.17//:pin_project_lite\",\n \"@postmaster_compiler_crates__tokio-1.52.1//:tokio\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tokio-util\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.7.18\",\n)\n" + } + }, + "postmaster_compiler_crates__toml-1.1.2-spec-1.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/toml/1.1.2+spec-1.1.0/download" + ], + "strip_prefix": "toml-1.1.2+spec-1.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"toml\",\n deps = [\n \"@postmaster_compiler_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_compiler_crates__serde_core-1.0.228//:serde_core\",\n \"@postmaster_compiler_crates__serde_spanned-1.1.1//:serde_spanned\",\n \"@postmaster_compiler_crates__toml_datetime-1.1.1-spec-1.1.0//:toml_datetime\",\n \"@postmaster_compiler_crates__toml_parser-1.1.2-spec-1.1.0//:toml_parser\",\n \"@postmaster_compiler_crates__toml_writer-1.1.1-spec-1.1.0//:toml_writer\",\n \"@postmaster_compiler_crates__winnow-1.0.2//:winnow\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"display\",\n \"parse\",\n \"preserve_order\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=toml\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.2+spec-1.1.0\",\n)\n" + } + }, + "postmaster_compiler_crates__toml_datetime-1.1.1-spec-1.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/toml_datetime/1.1.1+spec-1.1.0/download" + ], + "strip_prefix": "toml_datetime-1.1.1+spec-1.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"toml_datetime\",\n deps = [\n \"@postmaster_compiler_crates__serde_core-1.0.228//:serde_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=toml_datetime\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.1+spec-1.1.0\",\n)\n" + } + }, + "postmaster_compiler_crates__toml_edit-0.25.11-spec-1.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/toml_edit/0.25.11+spec-1.1.0/download" + ], + "strip_prefix": "toml_edit-0.25.11+spec-1.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"toml_edit\",\n deps = [\n \"@postmaster_compiler_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_compiler_crates__toml_datetime-1.1.1-spec-1.1.0//:toml_datetime\",\n \"@postmaster_compiler_crates__toml_parser-1.1.2-spec-1.1.0//:toml_parser\",\n \"@postmaster_compiler_crates__winnow-1.0.2//:winnow\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"parse\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=toml_edit\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.25.11+spec-1.1.0\",\n)\n" + } + }, + "postmaster_compiler_crates__toml_parser-1.1.2-spec-1.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/toml_parser/1.1.2+spec-1.1.0/download" + ], + "strip_prefix": "toml_parser-1.1.2+spec-1.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"toml_parser\",\n deps = [\n \"@postmaster_compiler_crates__winnow-1.0.2//:winnow\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=toml_parser\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.2+spec-1.1.0\",\n)\n" + } + }, + "postmaster_compiler_crates__toml_writer-1.1.1-spec-1.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/toml_writer/1.1.1+spec-1.1.0/download" + ], + "strip_prefix": "toml_writer-1.1.1+spec-1.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"toml_writer\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=toml_writer\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.1.1+spec-1.1.0\",\n)\n" + } + }, + "postmaster_compiler_crates__tracing-0.1.44": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tracing/0.1.44/download" + ], + "strip_prefix": "tracing-0.1.44", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tracing\",\n deps = [\n \"@postmaster_compiler_crates__log-0.4.29//:log\",\n \"@postmaster_compiler_crates__pin-project-lite-0.2.17//:pin_project_lite\",\n \"@postmaster_compiler_crates__tracing-core-0.1.36//:tracing_core\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__tracing-attributes-0.1.31//:tracing_attributes\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"attributes\",\n \"default\",\n \"log\",\n \"std\",\n \"tracing-attributes\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tracing\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.44\",\n)\n" + } + }, + "postmaster_compiler_crates__tracing-attributes-0.1.31": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tracing-attributes/0.1.31/download" + ], + "strip_prefix": "tracing-attributes-0.1.31", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"tracing_attributes\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tracing-attributes\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.31\",\n)\n" + } + }, + "postmaster_compiler_crates__tracing-core-0.1.36": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/tracing-core/0.1.36/download" + ], + "strip_prefix": "tracing-core-0.1.36", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"tracing_core\",\n deps = [\n \"@postmaster_compiler_crates__once_cell-1.21.4//:once_cell\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"once_cell\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=tracing-core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.36\",\n)\n" + } + }, + "postmaster_compiler_crates__twox-hash-2.1.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/twox-hash/2.1.2/download" + ], + "strip_prefix": "twox-hash-2.1.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"twox_hash\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"xxhash32\",\n \"xxhash64\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=twox-hash\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.1.2\",\n)\n" + } + }, + "postmaster_compiler_crates__typenum-1.20.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/typenum/1.20.0/download" + ], + "strip_prefix": "typenum-1.20.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"typenum\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"const-generics\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=typenum\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.20.0\",\n)\n" + } + }, + "postmaster_compiler_crates__unicase-2.9.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unicase/2.9.0/download" + ], + "strip_prefix": "unicase-2.9.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unicase\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unicase\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.9.0\",\n)\n" + } + }, + "postmaster_compiler_crates__unicode-ident-1.0.24": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unicode-ident/1.0.24/download" + ], + "strip_prefix": "unicode-ident-1.0.24", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unicode_ident\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unicode-ident\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.24\",\n)\n" + } + }, + "postmaster_compiler_crates__unicode-normalization-0.1.25": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unicode-normalization/0.1.25/download" + ], + "strip_prefix": "unicode-normalization-0.1.25", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unicode_normalization\",\n deps = [\n \"@postmaster_compiler_crates__tinyvec-1.11.0//:tinyvec\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unicode-normalization\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.25\",\n)\n" + } + }, + "postmaster_compiler_crates__unicode-segmentation-1.13.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unicode-segmentation/1.13.2/download" + ], + "strip_prefix": "unicode-segmentation-1.13.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unicode_segmentation\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unicode-segmentation\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.13.2\",\n)\n" + } + }, + "postmaster_compiler_crates__unicode-width-0.2.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unicode-width/0.2.2/download" + ], + "strip_prefix": "unicode-width-0.2.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unicode_width\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"cjk\",\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unicode-width\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.2\",\n)\n" + } + }, + "postmaster_compiler_crates__unicode-xid-0.2.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unicode-xid/0.2.6/download" + ], + "strip_prefix": "unicode-xid-0.2.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unicode_xid\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unicode-xid\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.6\",\n)\n" + } + }, + "postmaster_compiler_crates__unsafe-libyaml-0.2.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unsafe-libyaml/0.2.11/download" + ], + "strip_prefix": "unsafe-libyaml-0.2.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unsafe_libyaml\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unsafe-libyaml\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.11\",\n)\n" + } + }, + "postmaster_compiler_crates__unty-0.0.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unty/0.0.4/download" + ], + "strip_prefix": "unty-0.0.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unty\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unty\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.0.4\",\n)\n" + } + }, + "postmaster_compiler_crates__url-2.5.8": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/url/2.5.8/download" + ], + "strip_prefix": "url-2.5.8", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"url\",\n deps = [\n \"@postmaster_compiler_crates__form_urlencoded-1.2.2//:form_urlencoded\",\n \"@postmaster_compiler_crates__idna-1.1.0//:idna\",\n \"@postmaster_compiler_crates__percent-encoding-2.3.2//:percent_encoding\",\n \"@postmaster_compiler_crates__serde-1.0.228//:serde\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__serde_derive-1.0.228//:serde_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=url\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.5.8\",\n)\n" + } + }, + "postmaster_compiler_crates__urlencoding-2.1.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/urlencoding/2.1.3/download" + ], + "strip_prefix": "urlencoding-2.1.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"urlencoding\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=urlencoding\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.1.3\",\n)\n" + } + }, + "postmaster_compiler_crates__utf8_iter-1.0.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/utf8_iter/1.0.4/download" + ], + "strip_prefix": "utf8_iter-1.0.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"utf8_iter\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=utf8_iter\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.4\",\n)\n" + } + }, + "postmaster_compiler_crates__uuid-1.23.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/uuid/1.23.1/download" + ], + "strip_prefix": "uuid-1.23.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"uuid\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=uuid\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.23.1\",\n)\n" + } + }, + "postmaster_compiler_crates__version_check-0.9.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/version_check/0.9.5/download" + ], + "strip_prefix": "version_check-0.9.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"version_check\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=version_check\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.5\",\n)\n" + } + }, + "postmaster_compiler_crates__virtual-fs-0.702.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [ + "@@+_repo_rules31+postmaster_cargo//:patches/cargo/virtual-fs.patch" + ], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/virtual-fs", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"virtual_fs\",\n deps = [\n \"@postmaster_compiler_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_compiler_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_compiler_crates__dashmap-6.1.0//:dashmap\",\n \"@postmaster_compiler_crates__derive_more-2.1.1//:derive_more\",\n \"@postmaster_compiler_crates__dunce-1.0.5//:dunce\",\n \"@postmaster_compiler_crates__futures-0.3.32//:futures\",\n \"@postmaster_compiler_crates__getrandom-0.4.2//:getrandom\",\n \"@postmaster_compiler_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_compiler_crates__pin-project-lite-0.2.17//:pin_project_lite\",\n \"@postmaster_compiler_crates__replace_with-0.1.8//:replace_with\",\n \"@postmaster_compiler_crates__shared-buffer-0.1.4//:shared_buffer\",\n \"@postmaster_compiler_crates__slab-0.4.12//:slab\",\n \"@postmaster_compiler_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_compiler_crates__tokio-1.52.1//:tokio\",\n \"@postmaster_compiler_crates__tracing-0.1.44//:tracing\",\n \"@postmaster_compiler_crates__virtual-mio-0.702.0-alpha.2//:virtual_mio\",\n \"@postmaster_compiler_crates__wasmer-package-0.702.0-alpha.2//:wasmer_package\",\n \"@postmaster_compiler_crates__webc-11.0.0//:webc\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__async-trait-0.1.89//:async_trait\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"anyhow\",\n \"webc\",\n \"webc-fs\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=virtual-fs\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.702.0-alpha.2\",\n)\n" + } + }, + "postmaster_compiler_crates__virtual-mio-0.702.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [ + "@@+_repo_rules31+postmaster_cargo//:patches/cargo/virtual-mio.patch" + ], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/virtual-io", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"virtual_mio\",\n deps = [\n \"@postmaster_compiler_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_compiler_crates__futures-0.3.32//:futures\",\n \"@postmaster_compiler_crates__parking-2.2.1//:parking\",\n \"@postmaster_compiler_crates__serde-1.0.228//:serde\",\n \"@postmaster_compiler_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_compiler_crates__tracing-0.1.44//:tracing\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__async-trait-0.1.89//:async_trait\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=virtual-mio\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.702.0-alpha.2\",\n)\n" + } + }, + "postmaster_compiler_crates__virtual-net-0.702.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [ + "@@+_repo_rules31+postmaster_cargo//:patches/cargo/virtual-net.patch" + ], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/virtual-net", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"virtual_net\",\n deps = [\n \"@postmaster_compiler_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_compiler_crates__base64-0.22.1//:base64\",\n \"@postmaster_compiler_crates__bincode-2.0.1//:bincode\",\n \"@postmaster_compiler_crates__bytecheck-0.8.2//:bytecheck\",\n \"@postmaster_compiler_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_compiler_crates__derive_more-2.1.1//:derive_more\",\n \"@postmaster_compiler_crates__futures-util-0.3.32//:futures_util\",\n \"@postmaster_compiler_crates__ipnet-2.12.0//:ipnet\",\n \"@postmaster_compiler_crates__iprange-0.6.7//:iprange\",\n \"@postmaster_compiler_crates__pin-project-lite-0.2.17//:pin_project_lite\",\n \"@postmaster_compiler_crates__rkyv-0.8.16//:rkyv\",\n \"@postmaster_compiler_crates__serde-1.0.228//:serde\",\n \"@postmaster_compiler_crates__smoltcp-0.13.0//:smoltcp\",\n \"@postmaster_compiler_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_compiler_crates__tokio-1.52.1//:tokio\",\n \"@postmaster_compiler_crates__tracing-0.1.44//:tracing\",\n \"@postmaster_compiler_crates__virtual-mio-0.702.0-alpha.2//:virtual_mio\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__async-trait-0.1.89//:async_trait\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"rkyv\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=virtual-net\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.702.0-alpha.2\",\n)\n" + } + }, + "postmaster_compiler_crates__virtue-0.0.18": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/virtue/0.0.18/download" + ], + "strip_prefix": "virtue-0.0.18", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"virtue\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=virtue\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.0.18\",\n)\n" + } + }, + "postmaster_compiler_crates__wai-bindgen-gen-core-0.2.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1aa3dc41b510811122b3088197234c27e08fcad63ef936306dd8e11e2803876c", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wai-bindgen-gen-core/0.2.3/download" + ], + "strip_prefix": "wai-bindgen-gen-core-0.2.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wai_bindgen_gen_core\",\n deps = [\n \"@postmaster_compiler_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_compiler_crates__wai-parser-0.2.3//:wai_parser\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wai-bindgen-gen-core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.3\",\n)\n" + } + }, + "postmaster_compiler_crates__wai-bindgen-gen-rust-0.2.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "19bc05e8380515c4337c40ef03b2ff233e391315b178a320de8640703d522efe", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wai-bindgen-gen-rust/0.2.3/download" + ], + "strip_prefix": "wai-bindgen-gen-rust-0.2.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wai_bindgen_gen_rust\",\n deps = [\n \"@postmaster_compiler_crates__heck-0.3.3//:heck\",\n \"@postmaster_compiler_crates__wai-bindgen-gen-core-0.2.3//:wai_bindgen_gen_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wai-bindgen-gen-rust\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.3\",\n)\n" + } + }, + "postmaster_compiler_crates__wai-bindgen-gen-rust-wasm-0.2.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d6f35ce5e74086fac87f3a7bd50f643f00fe3559adb75c88521ecaa01c8a6199", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wai-bindgen-gen-rust-wasm/0.2.3/download" + ], + "strip_prefix": "wai-bindgen-gen-rust-wasm-0.2.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wai_bindgen_gen_rust_wasm\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__heck-0.3.3//:heck\",\n \"@postmaster_compiler_crates__wai-bindgen-gen-core-0.2.3//:wai_bindgen_gen_core\",\n \"@postmaster_compiler_crates__wai-bindgen-gen-rust-0.2.3//:wai_bindgen_gen_rust\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wai-bindgen-gen-rust-wasm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.3\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"wai-bindgen-gen-rust-wasm\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wai-bindgen-gen-rust-wasm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.2.3\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__wai-bindgen-rust-0.2.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4e5601c6f448c063e83a5e931b8fefcdf7e01ada424ad42372c948d2e3d67741", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wai-bindgen-rust/0.2.3/download" + ], + "strip_prefix": "wai-bindgen-rust-0.2.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wai_bindgen_rust\",\n deps = [\n \"@postmaster_compiler_crates__bitflags-1.3.2//:bitflags\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__wai-bindgen-rust-impl-0.2.3//:wai_bindgen_rust_impl\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"macros\",\n \"wai-bindgen-rust-impl\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wai-bindgen-rust\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.3\",\n)\n" + } + }, + "postmaster_compiler_crates__wai-bindgen-rust-impl-0.2.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bdeeb5c1170246de8425a3e123e7ef260dc05ba2b522a1d369fe2315376efea4", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wai-bindgen-rust-impl/0.2.3/download" + ], + "strip_prefix": "wai-bindgen-rust-impl-0.2.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"wai_bindgen_rust_impl\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__syn-1.0.109//:syn\",\n \"@postmaster_compiler_crates__wai-bindgen-gen-core-0.2.3//:wai_bindgen_gen_core\",\n \"@postmaster_compiler_crates__wai-bindgen-gen-rust-wasm-0.2.3//:wai_bindgen_gen_rust_wasm\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wai-bindgen-rust-impl\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.3\",\n)\n" + } + }, + "postmaster_compiler_crates__wai-parser-0.2.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9bd0acb6d70885ea0c343749019ba74f015f64a9d30542e66db69b49b7e28186", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wai-parser/0.2.3/download" + ], + "strip_prefix": "wai-parser-0.2.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wai_parser\",\n deps = [\n \"@postmaster_compiler_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_compiler_crates__id-arena-2.3.0//:id_arena\",\n \"@postmaster_compiler_crates__pulldown-cmark-0.8.0//:pulldown_cmark\",\n \"@postmaster_compiler_crates__unicode-normalization-0.1.25//:unicode_normalization\",\n \"@postmaster_compiler_crates__unicode-xid-0.2.6//:unicode_xid\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wai-parser\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.3\",\n)\n" + } + }, + "postmaster_compiler_crates__waker-fn-1.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/waker-fn/1.2.0/download" + ], + "strip_prefix": "waker-fn-1.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"waker_fn\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=waker-fn\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.2.0\",\n)\n" + } + }, + "postmaster_compiler_crates__walkdir-2.5.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/walkdir/2.5.0/download" + ], + "strip_prefix": "walkdir-2.5.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"walkdir\",\n deps = [\n \"@postmaster_compiler_crates__same-file-1.0.6//:same_file\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=walkdir\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.5.0\",\n)\n" + } + }, + "postmaster_compiler_crates__wasip2-1.0.3-wasi-0.2.9": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasip2/1.0.3+wasi-0.2.9/download" + ], + "strip_prefix": "wasip2-1.0.3+wasi-0.2.9", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasip2\",\n deps = [\n \"@postmaster_compiler_crates__wit-bindgen-0.57.1//:wit_bindgen\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasip2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.3+wasi-0.2.9\",\n)\n" + } + }, + "postmaster_compiler_crates__wasip3-0.4.0-wasi-0.3.0-rc-2026-01-06": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasip3/0.4.0+wasi-0.3.0-rc-2026-01-06/download" + ], + "strip_prefix": "wasip3-0.4.0+wasi-0.3.0-rc-2026-01-06", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasip3\",\n deps = [\n \"@postmaster_compiler_crates__wit-bindgen-0.51.0//:wit_bindgen\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasip3\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.0+wasi-0.3.0-rc-2026-01-06\",\n)\n" + } + }, + "postmaster_compiler_crates__wasm-bindgen-0.2.118": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-bindgen/0.2.118/download" + ], + "strip_prefix": "wasm-bindgen-0.2.118", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasm_bindgen\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_compiler_crates__once_cell-1.21.4//:once_cell\",\n \"@postmaster_compiler_crates__wasm-bindgen-shared-0.2.118//:wasm_bindgen_shared\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__wasm-bindgen-macro-0.2.118//:wasm_bindgen_macro\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.118\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n aliases = {\n \"@postmaster_compiler_crates__rustversion-1.0.22//:rustversion\": \"rustversion_compat\",\n },\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n link_deps = [\n \"@postmaster_compiler_crates__wasm-bindgen-shared-0.2.118//:wasm_bindgen_shared\",\n ],\n edition = \"2021\",\n pkg_name = \"wasm-bindgen\",\n proc_macro_deps = [\n \"@postmaster_compiler_crates__rustversion-1.0.22//:rustversion\",\n ],\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.2.118\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__wasm-bindgen-macro-0.2.118": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-bindgen-macro/0.2.118/download" + ], + "strip_prefix": "wasm-bindgen-macro-0.2.118", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"wasm_bindgen_macro\",\n deps = [\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__wasm-bindgen-macro-support-0.2.118//:wasm_bindgen_macro_support\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen-macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.118\",\n)\n" + } + }, + "postmaster_compiler_crates__wasm-bindgen-macro-support-0.2.118": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-bindgen-macro-support/0.2.118/download" + ], + "strip_prefix": "wasm-bindgen-macro-support-0.2.118", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasm_bindgen_macro_support\",\n deps = [\n \"@postmaster_compiler_crates__bumpalo-3.20.2//:bumpalo\",\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n \"@postmaster_compiler_crates__wasm-bindgen-shared-0.2.118//:wasm_bindgen_shared\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen-macro-support\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.118\",\n)\n" + } + }, + "postmaster_compiler_crates__wasm-bindgen-shared-0.2.118": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-bindgen-shared/0.2.118/download" + ], + "strip_prefix": "wasm-bindgen-shared-0.2.118", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasm_bindgen_shared\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__unicode-ident-1.0.24//:unicode_ident\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen-shared\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.118\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n links = \"wasm_bindgen\",\n pkg_name = \"wasm-bindgen-shared\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-bindgen-shared\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.2.118\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__wasm-encoder-0.244.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-encoder/0.244.0/download" + ], + "strip_prefix": "wasm-encoder-0.244.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasm_encoder\",\n deps = [\n \"@postmaster_compiler_crates__leb128fmt-0.1.0//:leb128fmt\",\n \"@postmaster_compiler_crates__wasmparser-0.244.0//:wasmparser\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"component-model\",\n \"std\",\n \"wasmparser\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-encoder\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.244.0\",\n)\n" + } + }, + "postmaster_compiler_crates__wasm-encoder-0.247.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "30b6733b8b91d010a6ac5b0fb237dc46a19650bc4c67db66857e2e787d437204", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-encoder/0.247.0/download" + ], + "strip_prefix": "wasm-encoder-0.247.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasm_encoder\",\n deps = [\n \"@postmaster_compiler_crates__leb128fmt-0.1.0//:leb128fmt\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"component-model\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-encoder\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.247.0\",\n)\n" + } + }, + "postmaster_compiler_crates__wasm-metadata-0.244.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-metadata/0.244.0/download" + ], + "strip_prefix": "wasm-metadata-0.244.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasm_metadata\",\n deps = [\n \"@postmaster_compiler_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_compiler_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_compiler_crates__wasm-encoder-0.244.0//:wasm_encoder\",\n \"@postmaster_compiler_crates__wasmparser-0.244.0//:wasmparser\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-metadata\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.244.0\",\n)\n" + } + }, + "postmaster_compiler_crates__wasmer-7.2.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [ + "@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer.patch" + ], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/api", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_compiler_crates__corosensei-0.3.3//:corosensei\",\n \"@postmaster_compiler_crates__derive_more-2.1.1//:derive_more\",\n \"@postmaster_compiler_crates__futures-0.3.32//:futures\",\n \"@postmaster_compiler_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_compiler_crates__more-asserts-0.3.1//:more_asserts\",\n \"@postmaster_compiler_crates__shared-buffer-0.1.4//:shared_buffer\",\n \"@postmaster_compiler_crates__symbolic-demangle-12.18.3//:symbolic_demangle\",\n \"@postmaster_compiler_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_compiler_crates__tracing-0.1.44//:tracing\",\n \"@postmaster_compiler_crates__wasmer-compiler-7.2.0-alpha.2//:wasmer_compiler\",\n \"@postmaster_compiler_crates__wasmer-compiler-llvm-7.2.0-alpha.2//:wasmer_compiler_llvm\",\n \"@postmaster_compiler_crates__wasmer-vm-7.2.0-alpha.2//:wasmer_vm\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__dashmap-6.1.0//:dashmap\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_compiler_crates__target-lexicon-0.13.5//:target_lexicon\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_compiler_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__dashmap-6.1.0//:dashmap\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_compiler_crates__target-lexicon-0.13.5//:target_lexicon\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_compiler_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__dashmap-6.1.0//:dashmap\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_compiler_crates__target-lexicon-0.13.5//:target_lexicon\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_compiler_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"//conditions:default\": [],\n }),\n proc_macro_deps = [\n \"@postmaster_compiler_crates__paste-1.0.15//:paste\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__wasmer-derive-7.2.0-alpha.2//:wasmer_derive\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__wasmer-derive-7.2.0-alpha.2//:wasmer_derive\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__wasmer-derive-7.2.0-alpha.2//:wasmer_derive\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"compiler\",\n \"experimental-async\",\n \"headless\",\n \"llvm\",\n \"std\",\n \"sys\",\n \"wasmer-compiler-llvm\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"7.2.0-alpha.2\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"compiler\",\n \"experimental-async\",\n \"headless\",\n \"llvm\",\n \"std\",\n \"sys\",\n \"wasmer-compiler-llvm\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@postmaster_compiler_crates__bindgen-0.72.1//:bindgen\",\n \"@postmaster_compiler_crates__cmake-0.1.58//:cmake\",\n \"@postmaster_compiler_crates__tar-0.4.45//:tar\",\n ],\n emit_warnings = False,\n edition = \"2024\",\n pkg_name = \"wasmer\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"7.2.0-alpha.2\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__wasmer-compiler-7.2.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [ + "@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-compiler.patch" + ], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/compiler", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_compiler\",\n deps = [\n \"@postmaster_compiler_crates__backtrace-0.3.76//:backtrace\",\n \"@postmaster_compiler_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_compiler_crates__enum-iterator-2.3.0//:enum_iterator\",\n \"@postmaster_compiler_crates__enumset-1.1.10//:enumset\",\n \"@postmaster_compiler_crates__itertools-0.14.0//:itertools\",\n \"@postmaster_compiler_crates__leb128-0.2.6//:leb128\",\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\",\n \"@postmaster_compiler_crates__memmap2-0.9.10//:memmap2\",\n \"@postmaster_compiler_crates__more-asserts-0.3.1//:more_asserts\",\n \"@postmaster_compiler_crates__object-0.39.1//:object\",\n \"@postmaster_compiler_crates__rangemap-1.7.1//:rangemap\",\n \"@postmaster_compiler_crates__rkyv-0.8.16//:rkyv\",\n \"@postmaster_compiler_crates__self_cell-1.2.2//:self_cell\",\n \"@postmaster_compiler_crates__shared-buffer-0.1.4//:shared_buffer\",\n \"@postmaster_compiler_crates__smallvec-1.15.1//:smallvec\",\n \"@postmaster_compiler_crates__target-lexicon-0.13.5//:target_lexicon\",\n \"@postmaster_compiler_crates__tempfile-3.27.0//:tempfile\",\n \"@postmaster_compiler_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_compiler_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\",\n \"@postmaster_compiler_crates__wasmparser-0.247.0//:wasmparser\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__crossbeam-channel-0.5.15//:crossbeam_channel\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_compiler_crates__macho-unwind-info-0.5.0//:macho_unwind_info\", # cfg(all(target_os = \"macos\", target_arch = \"aarch64\"))\n \"@postmaster_compiler_crates__rayon-1.12.0//:rayon\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_compiler_crates__region-3.0.2//:region\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_compiler_crates__wasmer-vm-7.2.0-alpha.2//:wasmer_vm\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_compiler_crates__which-8.0.2//:which\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__crossbeam-channel-0.5.15//:crossbeam_channel\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_compiler_crates__rayon-1.12.0//:rayon\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_compiler_crates__region-3.0.2//:region\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_compiler_crates__wasmer-vm-7.2.0-alpha.2//:wasmer_vm\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_compiler_crates__which-8.0.2//:which\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__crossbeam-channel-0.5.15//:crossbeam_channel\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_compiler_crates__rayon-1.12.0//:rayon\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_compiler_crates__region-3.0.2//:region\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_compiler_crates__wasmer-vm-7.2.0-alpha.2//:wasmer_vm\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_compiler_crates__which-8.0.2//:which\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"//conditions:default\": [],\n }),\n link_deps = [\n \"@@//build_defs/wasix/postmaster:linked_unwinder\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"compiler\",\n \"default\",\n \"std\",\n \"translator\",\n \"wasmparser\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n \"--cfg=oliphaunt_linked_libunwind\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-compiler\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"7.2.0-alpha.2\",\n)\n" + } + }, + "postmaster_compiler_crates__wasmer-compiler-llvm-7.2.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [ + "@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-compiler-llvm.patch" + ], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/compiler-llvm", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_compiler_llvm\",\n deps = [\n \"@postmaster_compiler_crates__byteorder-1.5.0//:byteorder\",\n \"@postmaster_compiler_crates__crossbeam-channel-0.5.15//:crossbeam_channel\",\n \"@postmaster_compiler_crates__enum-iterator-2.3.0//:enum_iterator\",\n \"@postmaster_compiler_crates__enumset-1.1.10//:enumset\",\n \"@postmaster_compiler_crates__inkwell-0.9.0//:inkwell\",\n \"@postmaster_compiler_crates__itertools-0.14.0//:itertools\",\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\",\n \"@postmaster_compiler_crates__object-0.39.1//:object\",\n \"@postmaster_compiler_crates__phf-0.13.1//:phf\",\n \"@postmaster_compiler_crates__rayon-1.12.0//:rayon\",\n \"@postmaster_compiler_crates__smallvec-1.15.1//:smallvec\",\n \"@postmaster_compiler_crates__target-lexicon-0.13.5//:target_lexicon\",\n \"@postmaster_compiler_crates__tracing-0.1.44//:tracing\",\n \"@postmaster_compiler_crates__wasmer-compiler-7.2.0-alpha.2//:wasmer_compiler\",\n \"@postmaster_compiler_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\",\n \"@postmaster_compiler_crates__wasmer-vm-7.2.0-alpha.2//:wasmer_vm\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-compiler-llvm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"7.2.0-alpha.2\",\n)\n" + } + }, + "postmaster_compiler_crates__wasmer-config-0.702.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/config", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_config\",\n deps = [\n \"@postmaster_compiler_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_compiler_crates__bytesize-2.3.1//:bytesize\",\n \"@postmaster_compiler_crates__ciborium-0.2.2//:ciborium\",\n \"@postmaster_compiler_crates__derive_builder-0.20.2//:derive_builder\",\n \"@postmaster_compiler_crates__hex-0.4.3//:hex\",\n \"@postmaster_compiler_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_compiler_crates__saffron-0.1.0//:saffron\",\n \"@postmaster_compiler_crates__schemars-1.2.1//:schemars\",\n \"@postmaster_compiler_crates__semver-1.0.28//:semver\",\n \"@postmaster_compiler_crates__serde-1.0.228//:serde\",\n \"@postmaster_compiler_crates__serde_json-1.0.149//:serde_json\",\n \"@postmaster_compiler_crates__serde_yaml-0.9.34-deprecated//:serde_yaml\",\n \"@postmaster_compiler_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_compiler_crates__toml-1.1.2-spec-1.1.0//:toml\",\n \"@postmaster_compiler_crates__url-2.5.8//:url\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-config\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.702.0-alpha.2\",\n)\n" + } + }, + "postmaster_compiler_crates__wasmer-derive-7.2.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/derive", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"wasmer_derive\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro-error2-2.0.1//:proc_macro_error2\",\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"7.2.0-alpha.2\",\n)\n" + } + }, + "postmaster_compiler_crates__wasmer-journal-0.702.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/journal", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_journal\",\n deps = [\n \"@postmaster_compiler_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_compiler_crates__base64-0.22.1//:base64\",\n \"@postmaster_compiler_crates__bincode-2.0.1//:bincode\",\n \"@postmaster_compiler_crates__bytecheck-0.8.2//:bytecheck\",\n \"@postmaster_compiler_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_compiler_crates__derive_more-2.1.1//:derive_more\",\n \"@postmaster_compiler_crates__lz4_flex-0.13.0//:lz4_flex\",\n \"@postmaster_compiler_crates__num_enum-0.7.6//:num_enum\",\n \"@postmaster_compiler_crates__rkyv-0.8.16//:rkyv\",\n \"@postmaster_compiler_crates__serde-1.0.228//:serde\",\n \"@postmaster_compiler_crates__serde_json-1.0.149//:serde_json\",\n \"@postmaster_compiler_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_compiler_crates__tracing-0.1.44//:tracing\",\n \"@postmaster_compiler_crates__virtual-fs-0.702.0-alpha.2//:virtual_fs\",\n \"@postmaster_compiler_crates__virtual-net-0.702.0-alpha.2//:virtual_net\",\n \"@postmaster_compiler_crates__wasmer-7.2.0-alpha.2//:wasmer\",\n \"@postmaster_compiler_crates__wasmer-config-0.702.0-alpha.2//:wasmer_config\",\n \"@postmaster_compiler_crates__wasmer-wasix-types-0.702.0-alpha.2//:wasmer_wasix_types\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__async-trait-0.1.89//:async_trait\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-journal\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.702.0-alpha.2\",\n)\n" + } + }, + "postmaster_compiler_crates__wasmer-package-0.702.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/package", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_package\",\n deps = [\n \"@postmaster_compiler_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_compiler_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_compiler_crates__ciborium-0.2.2//:ciborium\",\n \"@postmaster_compiler_crates__flate2-1.1.9//:flate2\",\n \"@postmaster_compiler_crates__ignore-0.4.25//:ignore\",\n \"@postmaster_compiler_crates__insta-1.47.2//:insta\",\n \"@postmaster_compiler_crates__semver-1.0.28//:semver\",\n \"@postmaster_compiler_crates__serde-1.0.228//:serde\",\n \"@postmaster_compiler_crates__serde_json-1.0.149//:serde_json\",\n \"@postmaster_compiler_crates__sha2-0.11.0//:sha2\",\n \"@postmaster_compiler_crates__shared-buffer-0.1.4//:shared_buffer\",\n \"@postmaster_compiler_crates__tar-0.4.45//:tar\",\n \"@postmaster_compiler_crates__tempfile-3.27.0//:tempfile\",\n \"@postmaster_compiler_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_compiler_crates__toml-1.1.2-spec-1.1.0//:toml\",\n \"@postmaster_compiler_crates__url-2.5.8//:url\",\n \"@postmaster_compiler_crates__wasmer-config-0.702.0-alpha.2//:wasmer_config\",\n \"@postmaster_compiler_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\",\n \"@postmaster_compiler_crates__webc-11.0.0//:webc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-package\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.702.0-alpha.2\",\n)\n" + } + }, + "postmaster_compiler_crates__wasmer-types-7.2.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [ + "@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-types.patch" + ], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/types", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_types\",\n deps = [\n \"@postmaster_compiler_crates__bytecheck-0.8.2//:bytecheck\",\n \"@postmaster_compiler_crates__crc32fast-1.5.0//:crc32fast\",\n \"@postmaster_compiler_crates__enum-iterator-2.3.0//:enum_iterator\",\n \"@postmaster_compiler_crates__enumset-1.1.10//:enumset\",\n \"@postmaster_compiler_crates__getrandom-0.4.2//:getrandom\",\n \"@postmaster_compiler_crates__hex-0.4.3//:hex\",\n \"@postmaster_compiler_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_compiler_crates__itertools-0.14.0//:itertools\",\n \"@postmaster_compiler_crates__more-asserts-0.3.1//:more_asserts\",\n \"@postmaster_compiler_crates__rkyv-0.8.16//:rkyv\",\n \"@postmaster_compiler_crates__serde-1.0.228//:serde\",\n \"@postmaster_compiler_crates__sha2-0.11.0//:sha2\",\n \"@postmaster_compiler_crates__target-lexicon-0.13.5//:target_lexicon\",\n \"@postmaster_compiler_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_compiler_crates__wasmparser-0.247.0//:wasmparser\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"detect-wasm-features\",\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-types\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"7.2.0-alpha.2\",\n)\n" + } + }, + "postmaster_compiler_crates__wasmer-vm-7.2.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [ + "@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-vm.patch" + ], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/vm", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_vm\",\n deps = [\n \"@postmaster_compiler_crates__backtrace-0.3.76//:backtrace\",\n \"@postmaster_compiler_crates__bytesize-2.3.1//:bytesize\",\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_compiler_crates__corosensei-0.3.3//:corosensei\",\n \"@postmaster_compiler_crates__crossbeam-queue-0.3.12//:crossbeam_queue\",\n \"@postmaster_compiler_crates__dashmap-6.1.0//:dashmap\",\n \"@postmaster_compiler_crates__enum-iterator-2.3.0//:enum_iterator\",\n \"@postmaster_compiler_crates__fnv-1.0.7//:fnv\",\n \"@postmaster_compiler_crates__gimli-0.33.0//:gimli\",\n \"@postmaster_compiler_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_compiler_crates__itertools-0.14.0//:itertools\",\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\",\n \"@postmaster_compiler_crates__memoffset-0.9.1//:memoffset\",\n \"@postmaster_compiler_crates__more-asserts-0.3.1//:more_asserts\",\n \"@postmaster_compiler_crates__parking_lot-0.12.5//:parking_lot\",\n \"@postmaster_compiler_crates__region-3.0.2//:region\",\n \"@postmaster_compiler_crates__scopeguard-1.2.0//:scopeguard\",\n \"@postmaster_compiler_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_compiler_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__libunwind-1.3.3//:libunwind\", # cfg(any(target_family = \"unix\", all(target_family = \"windows\", target_env = \"gnu\")))\n \"@postmaster_compiler_crates__mach2-0.6.0//:mach2\", # cfg(target_vendor = \"apple\")\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libunwind-1.3.3//:libunwind\", # cfg(any(target_family = \"unix\", all(target_family = \"windows\", target_env = \"gnu\")))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libunwind-1.3.3//:libunwind\", # cfg(any(target_family = \"unix\", all(target_family = \"windows\", target_env = \"gnu\")))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-vm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"7.2.0-alpha.2\",\n)\n" + } + }, + "postmaster_compiler_crates__wasmer-wasix-0.702.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [ + "@@+_repo_rules31+postmaster_cargo//:patches/cargo/wasmer-wasix.patch" + ], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/wasix", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_wasix\",\n deps = [\n \"@postmaster_compiler_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_compiler_crates__base64-0.22.1//:base64\",\n \"@postmaster_compiler_crates__bincode-2.0.1//:bincode\",\n \"@postmaster_compiler_crates__blake3-1.8.4//:blake3\",\n \"@postmaster_compiler_crates__bytecheck-0.8.2//:bytecheck\",\n \"@postmaster_compiler_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_compiler_crates__cooked-waker-5.0.0//:cooked_waker\",\n \"@postmaster_compiler_crates__crossbeam-channel-0.5.15//:crossbeam_channel\",\n \"@postmaster_compiler_crates__dashmap-6.1.0//:dashmap\",\n \"@postmaster_compiler_crates__derive_more-2.1.1//:derive_more\",\n \"@postmaster_compiler_crates__flate2-1.1.9//:flate2\",\n \"@postmaster_compiler_crates__fnv-1.0.7//:fnv\",\n \"@postmaster_compiler_crates__futures-0.3.32//:futures\",\n \"@postmaster_compiler_crates__getrandom-0.4.2//:getrandom\",\n \"@postmaster_compiler_crates__heapless-0.9.2//:heapless\",\n \"@postmaster_compiler_crates__hex-0.4.3//:hex\",\n \"@postmaster_compiler_crates__http-1.4.0//:http\",\n \"@postmaster_compiler_crates__linked_hash_set-0.1.6//:linked_hash_set\",\n \"@postmaster_compiler_crates__lz4_flex-0.13.0//:lz4_flex\",\n \"@postmaster_compiler_crates__num_enum-0.7.6//:num_enum\",\n \"@postmaster_compiler_crates__once_cell-1.21.4//:once_cell\",\n \"@postmaster_compiler_crates__petgraph-0.8.3//:petgraph\",\n \"@postmaster_compiler_crates__pin-project-1.1.11//:pin_project\",\n \"@postmaster_compiler_crates__pin-utils-0.1.0//:pin_utils\",\n \"@postmaster_compiler_crates__rand-0.10.1//:rand\",\n \"@postmaster_compiler_crates__rkyv-0.8.16//:rkyv\",\n \"@postmaster_compiler_crates__rusty_pool-0.7.0//:rusty_pool\",\n \"@postmaster_compiler_crates__semver-1.0.28//:semver\",\n \"@postmaster_compiler_crates__serde-1.0.228//:serde\",\n \"@postmaster_compiler_crates__serde_json-1.0.149//:serde_json\",\n \"@postmaster_compiler_crates__serde_yaml-0.9.34-deprecated//:serde_yaml\",\n \"@postmaster_compiler_crates__sha2-0.11.0//:sha2\",\n \"@postmaster_compiler_crates__shared-buffer-0.1.4//:shared_buffer\",\n \"@postmaster_compiler_crates__tempfile-3.27.0//:tempfile\",\n \"@postmaster_compiler_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_compiler_crates__tokio-1.52.1//:tokio\",\n \"@postmaster_compiler_crates__tokio-stream-0.1.18//:tokio_stream\",\n \"@postmaster_compiler_crates__toml-1.1.2-spec-1.1.0//:toml\",\n \"@postmaster_compiler_crates__tracing-0.1.44//:tracing\",\n \"@postmaster_compiler_crates__url-2.5.8//:url\",\n \"@postmaster_compiler_crates__urlencoding-2.1.3//:urlencoding\",\n \"@postmaster_compiler_crates__virtual-fs-0.702.0-alpha.2//:virtual_fs\",\n \"@postmaster_compiler_crates__virtual-mio-0.702.0-alpha.2//:virtual_mio\",\n \"@postmaster_compiler_crates__virtual-net-0.702.0-alpha.2//:virtual_net\",\n \"@postmaster_compiler_crates__waker-fn-1.2.0//:waker_fn\",\n \"@postmaster_compiler_crates__wasm-encoder-0.247.0//:wasm_encoder\",\n \"@postmaster_compiler_crates__wasmer-7.2.0-alpha.2//:wasmer\",\n \"@postmaster_compiler_crates__wasmer-config-0.702.0-alpha.2//:wasmer_config\",\n \"@postmaster_compiler_crates__wasmer-journal-0.702.0-alpha.2//:wasmer_journal\",\n \"@postmaster_compiler_crates__wasmer-package-0.702.0-alpha.2//:wasmer_package\",\n \"@postmaster_compiler_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\",\n \"@postmaster_compiler_crates__wasmer-wasix-types-0.702.0-alpha.2//:wasmer_wasix_types\",\n \"@postmaster_compiler_crates__wasmparser-0.247.0//:wasmparser\",\n \"@postmaster_compiler_crates__webc-11.0.0//:webc\",\n \"@postmaster_compiler_crates__weezl-0.1.12//:weezl\",\n \"@postmaster_compiler_crates__xxhash-rust-0.8.15//:xxhash_rust\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n \"@postmaster_compiler_crates__terminal_size-0.4.4//:terminal_size\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_compiler_crates__termios-0.3.3//:termios\", # cfg(all(unix, not(target_os = \"ios\")))\n \"@postmaster_compiler_crates__zstd-0.13.3//:zstd\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n \"@postmaster_compiler_crates__terminal_size-0.4.4//:terminal_size\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_compiler_crates__termios-0.3.3//:termios\", # cfg(all(unix, not(target_os = \"ios\")))\n \"@postmaster_compiler_crates__zstd-0.13.3//:zstd\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\", # cfg(unix)\n \"@postmaster_compiler_crates__terminal_size-0.4.4//:terminal_size\", # cfg(not(target_arch = \"wasm32\"))\n \"@postmaster_compiler_crates__termios-0.3.3//:termios\", # cfg(all(unix, not(target_os = \"ios\")))\n \"@postmaster_compiler_crates__zstd-0.13.3//:zstd\", # cfg(not(target_arch = \"wasm32\"))\n ],\n \"//conditions:default\": [],\n }),\n proc_macro_deps = [\n \"@postmaster_compiler_crates__async-trait-0.1.89//:async_trait\",\n \"@postmaster_compiler_crates__serde_derive-1.0.228//:serde_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"rusty_pool\",\n \"sys-minimal\",\n \"sys-thread\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-wasix\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.702.0-alpha.2\",\n)\n" + } + }, + "postmaster_compiler_crates__wasmer-wasix-types-0.702.0-alpha.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [ + "-p1" + ], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912", + "type": "tar.gz", + "urls": [ + "https://codeload.github.com/wasmerio/wasmer/tar.gz/1d1b3420beef28550afbb4692b664bd7f6bc2581" + ], + "strip_prefix": "wasmer-1d1b3420beef28550afbb4692b664bd7f6bc2581/lib/wasi-types", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmer_wasix_types\",\n deps = [\n \"@postmaster_compiler_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_compiler_crates__bitflags-2.11.1//:bitflags\",\n \"@postmaster_compiler_crates__byteorder-1.5.0//:byteorder\",\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_compiler_crates__num_enum-0.7.6//:num_enum\",\n \"@postmaster_compiler_crates__serde-1.0.228//:serde\",\n \"@postmaster_compiler_crates__time-0.3.47//:time\",\n \"@postmaster_compiler_crates__tracing-0.1.44//:tracing\",\n \"@postmaster_compiler_crates__wai-bindgen-gen-core-0.2.3//:wai_bindgen_gen_core\",\n \"@postmaster_compiler_crates__wai-bindgen-gen-rust-0.2.3//:wai_bindgen_gen_rust\",\n \"@postmaster_compiler_crates__wai-bindgen-gen-rust-wasm-0.2.3//:wai_bindgen_gen_rust_wasm\",\n \"@postmaster_compiler_crates__wai-bindgen-rust-0.2.3//:wai_bindgen_rust\",\n \"@postmaster_compiler_crates__wai-parser-0.2.3//:wai_parser\",\n \"@postmaster_compiler_crates__wasmer-7.2.0-alpha.2//:wasmer\",\n \"@postmaster_compiler_crates__wasmer-types-7.2.0-alpha.2//:wasmer_types\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__wasmer-derive-7.2.0-alpha.2//:wasmer_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"enable-serde\",\n \"serde\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmer-wasix-types\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.702.0-alpha.2\",\n)\n" + } + }, + "postmaster_compiler_crates__wasmparser-0.244.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasmparser/0.244.0/download" + ], + "strip_prefix": "wasmparser-0.244.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmparser\",\n deps = [\n \"@postmaster_compiler_crates__bitflags-2.11.1//:bitflags\",\n \"@postmaster_compiler_crates__hashbrown-0.15.5//:hashbrown\",\n \"@postmaster_compiler_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_compiler_crates__semver-1.0.28//:semver\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"component-model\",\n \"features\",\n \"hash-collections\",\n \"simd\",\n \"std\",\n \"validate\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmparser\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.244.0\",\n)\n" + } + }, + "postmaster_compiler_crates__wasmparser-0.247.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8e6fb4c2bee46c5ea4d40f8cdb5c131725cd976718ec56f1c8e82fbde5fa2a80", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasmparser/0.247.0/download" + ], + "strip_prefix": "wasmparser-0.247.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmparser\",\n deps = [\n \"@postmaster_compiler_crates__bitflags-2.11.1//:bitflags\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"features\",\n \"simd\",\n \"validate\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmparser\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.247.0\",\n)\n" + } + }, + "postmaster_compiler_crates__wast-247.0.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "579d2d47eb33b0cdf9b14723cb115f1e1b7d6e77aac6f0816e5b7c7aeaa418ff", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wast/247.0.0/download" + ], + "strip_prefix": "wast-247.0.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wast\",\n deps = [\n \"@postmaster_compiler_crates__bumpalo-3.20.2//:bumpalo\",\n \"@postmaster_compiler_crates__leb128fmt-0.1.0//:leb128fmt\",\n \"@postmaster_compiler_crates__memchr-2.8.0//:memchr\",\n \"@postmaster_compiler_crates__unicode-width-0.2.2//:unicode_width\",\n \"@postmaster_compiler_crates__wasm-encoder-0.247.0//:wasm_encoder\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"component-model\",\n \"wasm-module\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wast\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"247.0.0\",\n)\n" + } + }, + "postmaster_compiler_crates__wat-1.247.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f3f4091c56437e86f2b57fa2fac72c4f528957a605b3f44f7c0b3b19a17ac5ee", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wat/1.247.0/download" + ], + "strip_prefix": "wat-1.247.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wat\",\n deps = [\n \"@postmaster_compiler_crates__wast-247.0.0//:wast\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"component-model\",\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wat\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.247.0\",\n)\n" + } + }, + "postmaster_compiler_crates__webc-11.0.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "20b8b523112384e8c1caf77cffdd371ca7e0013779f081e6beafc537f5b5325d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/webc/11.0.0/download" + ], + "strip_prefix": "webc-11.0.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"webc\",\n deps = [\n \"@postmaster_compiler_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_compiler_crates__base64-0.22.1//:base64\",\n \"@postmaster_compiler_crates__bytes-1.11.1//:bytes\",\n \"@postmaster_compiler_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_compiler_crates__ciborium-0.2.2//:ciborium\",\n \"@postmaster_compiler_crates__ignore-0.4.25//:ignore\",\n \"@postmaster_compiler_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_compiler_crates__leb128-0.2.6//:leb128\",\n \"@postmaster_compiler_crates__lexical-sort-0.3.1//:lexical_sort\",\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\",\n \"@postmaster_compiler_crates__once_cell-1.21.4//:once_cell\",\n \"@postmaster_compiler_crates__path-clean-1.0.1//:path_clean\",\n \"@postmaster_compiler_crates__rand-0.9.4//:rand\",\n \"@postmaster_compiler_crates__serde-1.0.228//:serde\",\n \"@postmaster_compiler_crates__serde_json-1.0.149//:serde_json\",\n \"@postmaster_compiler_crates__sha2-0.10.9//:sha2\",\n \"@postmaster_compiler_crates__shared-buffer-0.1.4//:shared_buffer\",\n \"@postmaster_compiler_crates__thiserror-2.0.18//:thiserror\",\n \"@postmaster_compiler_crates__url-2.5.8//:url\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__document-features-0.2.12//:document_features\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"v1\",\n \"v2\",\n \"v3\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=webc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"11.0.0\",\n)\n" + } + }, + "postmaster_compiler_crates__weezl-0.1.12": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/weezl/0.1.12/download" + ], + "strip_prefix": "weezl-0.1.12", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"weezl\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=weezl\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.12\",\n)\n" + } + }, + "postmaster_compiler_crates__which-8.0.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "81995fafaaaf6ae47a7d0cc83c67caf92aeb7e5331650ae6ff856f7c0c60c459", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/which/8.0.2/download" + ], + "strip_prefix": "which-8.0.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"which\",\n deps = [\n \"@postmaster_compiler_crates__libc-0.2.186//:libc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"real-sys\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=which\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"8.0.2\",\n)\n" + } + }, + "postmaster_compiler_crates__winapi-util-0.1.11": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/winapi-util/0.1.11/download" + ], + "strip_prefix": "winapi-util-0.1.11", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"winapi_util\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=winapi-util\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.11\",\n)\n" + } + }, + "postmaster_compiler_crates__windows-link-0.2.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows-link/0.2.1/download" + ], + "strip_prefix": "windows-link-0.2.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_link\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows-link\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.1\",\n)\n" + } + }, + "postmaster_compiler_crates__windows-sys-0.52.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows-sys/0.52.0/download" + ], + "strip_prefix": "windows-sys-0.52.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_sys\",\n deps = [\n \"@postmaster_compiler_crates__windows-targets-0.52.6//:windows_targets\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.0\",\n)\n" + } + }, + "postmaster_compiler_crates__windows-sys-0.59.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows-sys/0.59.0/download" + ], + "strip_prefix": "windows-sys-0.59.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_sys\",\n deps = [\n \"@postmaster_compiler_crates__windows-targets-0.52.6//:windows_targets\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.59.0\",\n)\n" + } + }, + "postmaster_compiler_crates__windows-sys-0.61.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows-sys/0.61.2/download" + ], + "strip_prefix": "windows-sys-0.61.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_sys\",\n deps = [\n \"@postmaster_compiler_crates__windows-link-0.2.1//:windows_link\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.61.2\",\n)\n" + } + }, + "postmaster_compiler_crates__windows-targets-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows-targets/0.52.6/download" + ], + "strip_prefix": "windows-targets-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_targets\",\n deps = select({\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__windows_x86_64_gnu-0.52.6//:windows_x86_64_gnu\", # cfg(all(target_arch = \"x86_64\", target_env = \"gnu\", not(target_abi = \"llvm\"), not(windows_raw_dylib)))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows-targets\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n" + } + }, + "postmaster_compiler_crates__windows_aarch64_gnullvm-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_aarch64_gnullvm/0.52.6/download" + ], + "strip_prefix": "windows_aarch64_gnullvm-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_aarch64_gnullvm\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_aarch64_gnullvm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_aarch64_gnullvm\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_aarch64_gnullvm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__windows_aarch64_msvc-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_aarch64_msvc/0.52.6/download" + ], + "strip_prefix": "windows_aarch64_msvc-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_aarch64_msvc\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_aarch64_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_aarch64_msvc\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_aarch64_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__windows_i686_gnu-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_i686_gnu/0.52.6/download" + ], + "strip_prefix": "windows_i686_gnu-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_i686_gnu\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_i686_gnu\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_i686_gnu\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_i686_gnu\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__windows_i686_gnullvm-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_i686_gnullvm/0.52.6/download" + ], + "strip_prefix": "windows_i686_gnullvm-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_i686_gnullvm\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_i686_gnullvm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_i686_gnullvm\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_i686_gnullvm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__windows_i686_msvc-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_i686_msvc/0.52.6/download" + ], + "strip_prefix": "windows_i686_msvc-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_i686_msvc\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_i686_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_i686_msvc\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_i686_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__windows_x86_64_gnu-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_x86_64_gnu/0.52.6/download" + ], + "strip_prefix": "windows_x86_64_gnu-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_x86_64_gnu\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_gnu\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_x86_64_gnu\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_gnu\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__windows_x86_64_gnullvm-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_x86_64_gnullvm/0.52.6/download" + ], + "strip_prefix": "windows_x86_64_gnullvm-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_x86_64_gnullvm\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_gnullvm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_x86_64_gnullvm\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_gnullvm\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__windows_x86_64_msvc-0.52.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/windows_x86_64_msvc/0.52.6/download" + ], + "strip_prefix": "windows_x86_64_msvc-0.52.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"windows_x86_64_msvc\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.52.6\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"windows_x86_64_msvc\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=windows_x86_64_msvc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.52.6\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__winnow-1.0.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/winnow/1.0.2/download" + ], + "strip_prefix": "winnow-1.0.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"winnow\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"ascii\",\n \"binary\",\n \"default\",\n \"parser\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=winnow\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.2\",\n)\n" + } + }, + "postmaster_compiler_crates__wit-bindgen-0.51.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wit-bindgen/0.51.0/download" + ], + "strip_prefix": "wit-bindgen-0.51.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wit_bindgen\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wit-bindgen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.51.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2024\",\n pkg_name = \"wit-bindgen\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wit-bindgen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.51.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__wit-bindgen-0.57.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wit-bindgen/0.57.1/download" + ], + "strip_prefix": "wit-bindgen-0.57.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wit_bindgen\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wit-bindgen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.57.1\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2024\",\n pkg_name = \"wit-bindgen\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wit-bindgen\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.57.1\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__wit-bindgen-core-0.51.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wit-bindgen-core/0.51.0/download" + ], + "strip_prefix": "wit-bindgen-core-0.51.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wit_bindgen_core\",\n deps = [\n \"@postmaster_compiler_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_compiler_crates__heck-0.5.0//:heck\",\n \"@postmaster_compiler_crates__wit-parser-0.244.0//:wit_parser\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wit-bindgen-core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.51.0\",\n)\n" + } + }, + "postmaster_compiler_crates__wit-bindgen-rust-0.51.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wit-bindgen-rust/0.51.0/download" + ], + "strip_prefix": "wit-bindgen-rust-0.51.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wit_bindgen_rust\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_compiler_crates__heck-0.5.0//:heck\",\n \"@postmaster_compiler_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_compiler_crates__prettyplease-0.2.37//:prettyplease\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n \"@postmaster_compiler_crates__wasm-metadata-0.244.0//:wasm_metadata\",\n \"@postmaster_compiler_crates__wit-bindgen-core-0.51.0//:wit_bindgen_core\",\n \"@postmaster_compiler_crates__wit-component-0.244.0//:wit_component\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wit-bindgen-rust\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.51.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n link_deps = [\n \"@postmaster_compiler_crates__prettyplease-0.2.37//:prettyplease\",\n ],\n edition = \"2024\",\n pkg_name = \"wit-bindgen-rust\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wit-bindgen-rust\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.51.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__wit-bindgen-rust-macro-0.51.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wit-bindgen-rust-macro/0.51.0/download" + ], + "strip_prefix": "wit-bindgen-rust-macro-0.51.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"wit_bindgen_rust_macro\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_compiler_crates__prettyplease-0.2.37//:prettyplease\",\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n \"@postmaster_compiler_crates__wit-bindgen-core-0.51.0//:wit_bindgen_core\",\n \"@postmaster_compiler_crates__wit-bindgen-rust-0.51.0//:wit_bindgen_rust\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wit-bindgen-rust-macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.51.0\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n link_deps = [\n \"@postmaster_compiler_crates__prettyplease-0.2.37//:prettyplease\",\n ],\n edition = \"2024\",\n pkg_name = \"wit-bindgen-rust-macro\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wit-bindgen-rust-macro\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.51.0\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__wit-component-0.244.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wit-component/0.244.0/download" + ], + "strip_prefix": "wit-component-0.244.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wit_component\",\n deps = [\n \"@postmaster_compiler_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_compiler_crates__bitflags-2.11.1//:bitflags\",\n \"@postmaster_compiler_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_compiler_crates__log-0.4.29//:log\",\n \"@postmaster_compiler_crates__serde-1.0.228//:serde\",\n \"@postmaster_compiler_crates__serde_json-1.0.149//:serde_json\",\n \"@postmaster_compiler_crates__wasm-encoder-0.244.0//:wasm_encoder\",\n \"@postmaster_compiler_crates__wasm-metadata-0.244.0//:wasm_metadata\",\n \"@postmaster_compiler_crates__wasmparser-0.244.0//:wasmparser\",\n \"@postmaster_compiler_crates__wit-parser-0.244.0//:wit_parser\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__serde_derive-1.0.228//:serde_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wit-component\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.244.0\",\n)\n" + } + }, + "postmaster_compiler_crates__wit-parser-0.244.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wit-parser/0.244.0/download" + ], + "strip_prefix": "wit-parser-0.244.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wit_parser\",\n deps = [\n \"@postmaster_compiler_crates__anyhow-1.0.102//:anyhow\",\n \"@postmaster_compiler_crates__id-arena-2.3.0//:id_arena\",\n \"@postmaster_compiler_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_compiler_crates__log-0.4.29//:log\",\n \"@postmaster_compiler_crates__semver-1.0.28//:semver\",\n \"@postmaster_compiler_crates__serde-1.0.228//:serde\",\n \"@postmaster_compiler_crates__serde_json-1.0.149//:serde_json\",\n \"@postmaster_compiler_crates__unicode-xid-0.2.6//:unicode_xid\",\n \"@postmaster_compiler_crates__wasmparser-0.244.0//:wasmparser\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__serde_derive-1.0.228//:serde_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"decoding\",\n \"default\",\n \"serde\",\n \"serde_json\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wit-parser\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.244.0\",\n)\n" + } + }, + "postmaster_compiler_crates__writeable-0.6.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/writeable/0.6.3/download" + ], + "strip_prefix": "writeable-0.6.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"writeable\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=writeable\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.6.3\",\n)\n" + } + }, + "postmaster_compiler_crates__xattr-1.6.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/xattr/1.6.1/download" + ], + "strip_prefix": "xattr-1.6.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"xattr\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_compiler_crates__rustix-1.1.4//:rustix\", # cfg(any(target_os = \"android\", target_os = \"linux\", target_os = \"macos\", target_os = \"hurd\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__rustix-1.1.4//:rustix\", # cfg(any(target_os = \"android\", target_os = \"linux\", target_os = \"macos\", target_os = \"hurd\"))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_compiler_crates__rustix-1.1.4//:rustix\", # cfg(any(target_os = \"android\", target_os = \"linux\", target_os = \"macos\", target_os = \"hurd\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"unsupported\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=xattr\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.6.1\",\n)\n" + } + }, + "postmaster_compiler_crates__xxhash-rust-0.8.15": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/xxhash-rust/0.8.15/download" + ], + "strip_prefix": "xxhash-rust-0.8.15", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"xxhash_rust\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"xxh64\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=xxhash-rust\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.15\",\n)\n" + } + }, + "postmaster_compiler_crates__yoke-0.8.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/yoke/0.8.2/download" + ], + "strip_prefix": "yoke-0.8.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"yoke\",\n deps = [\n \"@postmaster_compiler_crates__stable_deref_trait-1.2.1//:stable_deref_trait\",\n \"@postmaster_compiler_crates__zerofrom-0.1.7//:zerofrom\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__yoke-derive-0.8.2//:yoke_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"derive\",\n \"zerofrom\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=yoke\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.2\",\n)\n" + } + }, + "postmaster_compiler_crates__yoke-derive-0.8.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/yoke-derive/0.8.2/download" + ], + "strip_prefix": "yoke-derive-0.8.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"yoke_derive\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n \"@postmaster_compiler_crates__synstructure-0.13.2//:synstructure\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=yoke-derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.2\",\n)\n" + } + }, + "postmaster_compiler_crates__zerocopy-0.8.48": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zerocopy/0.8.48/download" + ], + "strip_prefix": "zerocopy-0.8.48", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"zerocopy\",\n deps = [\n \":build_script_build\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__zerocopy-derive-0.8.48//:zerocopy_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"derive\",\n \"simd\",\n \"zerocopy-derive\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerocopy\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.48\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"derive\",\n \"simd\",\n \"zerocopy-derive\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"zerocopy\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerocopy\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.8.48\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__zerocopy-derive-0.8.48": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zerocopy-derive/0.8.48/download" + ], + "strip_prefix": "zerocopy-derive-0.8.48", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"zerocopy_derive\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerocopy-derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.8.48\",\n)\n" + } + }, + "postmaster_compiler_crates__zerofrom-0.1.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zerofrom/0.1.7/download" + ], + "strip_prefix": "zerofrom-0.1.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"zerofrom\",\n proc_macro_deps = [\n \"@postmaster_compiler_crates__zerofrom-derive-0.1.7//:zerofrom_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"derive\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerofrom\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.7\",\n)\n" + } + }, + "postmaster_compiler_crates__zerofrom-derive-0.1.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zerofrom-derive/0.1.7/download" + ], + "strip_prefix": "zerofrom-derive-0.1.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"zerofrom_derive\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n \"@postmaster_compiler_crates__synstructure-0.13.2//:synstructure\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerofrom-derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.7\",\n)\n" + } + }, + "postmaster_compiler_crates__zerotrie-0.2.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zerotrie/0.2.4/download" + ], + "strip_prefix": "zerotrie-0.2.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"zerotrie\",\n deps = [\n \"@postmaster_compiler_crates__yoke-0.8.2//:yoke\",\n \"@postmaster_compiler_crates__zerofrom-0.1.7//:zerofrom\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__displaydoc-0.2.5//:displaydoc\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"yoke\",\n \"zerofrom\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerotrie\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.4\",\n)\n" + } + }, + "postmaster_compiler_crates__zerovec-0.11.6": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zerovec/0.11.6/download" + ], + "strip_prefix": "zerovec-0.11.6", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"zerovec\",\n deps = [\n \"@postmaster_compiler_crates__yoke-0.8.2//:yoke\",\n \"@postmaster_compiler_crates__zerofrom-0.1.7//:zerofrom\",\n ],\n proc_macro_deps = [\n \"@postmaster_compiler_crates__zerovec-derive-0.11.3//:zerovec_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"derive\",\n \"yoke\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerovec\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.11.6\",\n)\n" + } + }, + "postmaster_compiler_crates__zerovec-derive-0.11.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zerovec-derive/0.11.3/download" + ], + "strip_prefix": "zerovec-derive-0.11.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"zerovec_derive\",\n deps = [\n \"@postmaster_compiler_crates__proc-macro2-1.0.106//:proc_macro2\",\n \"@postmaster_compiler_crates__quote-1.0.45//:quote\",\n \"@postmaster_compiler_crates__syn-2.0.117//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zerovec-derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.11.3\",\n)\n" + } + }, + "postmaster_compiler_crates__zmij-1.0.21": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zmij/1.0.21/download" + ], + "strip_prefix": "zmij-1.0.21", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"zmij\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zmij\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.21\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"zmij\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zmij\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.21\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__zstd-0.13.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zstd/0.13.3/download" + ], + "strip_prefix": "zstd-0.13.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"zstd\",\n deps = [\n \"@postmaster_compiler_crates__zstd-safe-7.2.4//:zstd_safe\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"arrays\",\n \"default\",\n \"legacy\",\n \"zdict_builder\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zstd\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.13.3\",\n)\n" + } + }, + "postmaster_compiler_crates__zstd-safe-7.2.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zstd-safe/7.2.4/download" + ], + "strip_prefix": "zstd-safe-7.2.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"zstd_safe\",\n deps = [\n \":build_script_build\",\n \"@postmaster_compiler_crates__zstd-sys-2.0.16-zstd.1.5.7//:zstd_sys\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"arrays\",\n \"legacy\",\n \"std\",\n \"zdict_builder\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zstd-safe\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"7.2.4\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"arrays\",\n \"legacy\",\n \"std\",\n \"zdict_builder\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n link_deps = [\n \"@postmaster_compiler_crates__zstd-sys-2.0.16-zstd.1.5.7//:zstd_sys\",\n ],\n edition = \"2018\",\n pkg_name = \"zstd-safe\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zstd-safe\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"7.2.4\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_compiler_crates__zstd-sys-2.0.16-zstd.1.5.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zstd-sys/2.0.16+zstd.1.5.7/download" + ], + "strip_prefix": "zstd-sys-2.0.16+zstd.1.5.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"zstd_sys\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"legacy\",\n \"std\",\n \"zdict_builder\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zstd-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.16+zstd.1.5.7\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"legacy\",\n \"std\",\n \"zdict_builder\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@postmaster_compiler_crates__cc-1.2.60//:cc\",\n \"@postmaster_compiler_crates__pkg-config-0.3.33//:pkg_config\",\n ],\n emit_warnings = False,\n edition = \"2018\",\n links = \"zstd\",\n pkg_name = \"zstd-sys\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zstd-sys\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"2.0.16+zstd.1.5.7\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_sealing_crates": { + "repoRuleId": "@@rules_rust+//crate_universe/private:crates_vendor.bzl%crates_vendor_remote_repository", + "attributes": { + "contents": { + "BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files(\n [\n \"cargo-bazel.json\",\n \"crates.bzl\",\n \"defs.bzl\",\n ] + glob(\n allow_empty = True,\n include = [\"*.bazel\"],\n ),\n)\n\nfilegroup(\n name = \"srcs\",\n srcs = glob(\n allow_empty = True,\n include = [\n \"*.bazel\",\n \"*.bzl\",\n ],\n ),\n)\n\n# Workspace Member Dependencies\nalias(\n name = \"anyhow-1.0.104\",\n actual = \"@postmaster_sealing_crates__anyhow-1.0.104//:anyhow\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"anyhow\",\n actual = \"@postmaster_sealing_crates__anyhow-1.0.104//:anyhow\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"hex-0.4.3\",\n actual = \"@postmaster_sealing_crates__hex-0.4.3//:hex\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"hex\",\n actual = \"@postmaster_sealing_crates__hex-0.4.3//:hex\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde-1.0.229\",\n actual = \"@postmaster_sealing_crates__serde-1.0.229//:serde\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde\",\n actual = \"@postmaster_sealing_crates__serde-1.0.229//:serde\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde_json-1.0.151\",\n actual = \"@postmaster_sealing_crates__serde_json-1.0.151//:serde_json\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"serde_json\",\n actual = \"@postmaster_sealing_crates__serde_json-1.0.151//:serde_json\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"sha2-0.10.9\",\n actual = \"@postmaster_sealing_crates__sha2-0.10.9//:sha2\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"sha2\",\n actual = \"@postmaster_sealing_crates__sha2-0.10.9//:sha2\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasm-encoder-0.247.0\",\n actual = \"@postmaster_sealing_crates__wasm-encoder-0.247.0//:wasm_encoder\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasm-encoder\",\n actual = \"@postmaster_sealing_crates__wasm-encoder-0.247.0//:wasm_encoder\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmparser-0.247.0\",\n actual = \"@postmaster_sealing_crates__wasmparser-0.247.0//:wasmparser\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"wasmparser\",\n actual = \"@postmaster_sealing_crates__wasmparser-0.247.0//:wasmparser\",\n tags = [\"manual\"],\n)\n", + "alias_rules.bzl": "\"\"\"Alias that transitions its target to `compilation_mode=opt`. Use `transition_alias=\"opt\"` to enable.\"\"\"\n\nload(\"@rules_cc//cc:defs.bzl\", \"CcInfo\")\nload(\"@rules_rust//rust:rust_common.bzl\", \"COMMON_PROVIDERS\")\n\ndef _transition_alias_impl(ctx):\n # `ctx.attr.actual` is a list of 1 item due to the transition\n providers = [ctx.attr.actual[0][provider] for provider in COMMON_PROVIDERS]\n if CcInfo in ctx.attr.actual[0]:\n providers.append(ctx.attr.actual[0][CcInfo])\n return providers\n\ndef _change_compilation_mode(compilation_mode):\n def _change_compilation_mode_impl(_settings, _attr):\n return {\n \"//command_line_option:compilation_mode\": compilation_mode,\n }\n\n return transition(\n implementation = _change_compilation_mode_impl,\n inputs = [],\n outputs = [\n \"//command_line_option:compilation_mode\",\n ],\n )\n\ndef _transition_alias_rule(compilation_mode):\n return rule(\n implementation = _transition_alias_impl,\n provides = COMMON_PROVIDERS,\n attrs = {\n \"actual\": attr.label(\n mandatory = True,\n doc = \"`rust_library()` target to transition to `compilation_mode=opt`.\",\n providers = COMMON_PROVIDERS,\n cfg = _change_compilation_mode(compilation_mode),\n ),\n \"_allowlist_function_transition\": attr.label(\n default = \"@bazel_tools//tools/allowlists/function_transition_allowlist\",\n ),\n },\n doc = \"Transitions a Rust library crate to the `compilation_mode=opt`.\",\n )\n\ntransition_alias_dbg = _transition_alias_rule(\"dbg\")\ntransition_alias_fastbuild = _transition_alias_rule(\"fastbuild\")\ntransition_alias_opt = _transition_alias_rule(\"opt\")\n", + "crates.bzl": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\"\"\"\n# `crates_repository` API\n\n- [aliases](#aliases)\n- [crate_edition](#crate_edition)\n- [crate_deps](#crate_deps)\n- [all_crate_deps](#all_crate_deps)\n- [crate_repositories](#crate_repositories)\n\n\"\"\"\n\nload(\"@bazel_tools//tools/build_defs/repo:git.bzl\", \"git_repository\")\nload(\"@bazel_tools//tools/build_defs/repo:http.bzl\", \"http_archive\")\nload(\"@bazel_tools//tools/build_defs/repo:utils.bzl\", \"maybe\")\nload(\"@bazel_skylib//lib:selects.bzl\", \"selects\")\nload(\"@rules_rust//crate_universe:defs.bzl\", \"crates_vendor_remote_repository\", \"local_crate_mirror\")\n\n###############################################################################\n# MACROS API\n###############################################################################\n\n# An identifier that represent common dependencies (unconditional).\n_COMMON_CONDITION = \"\"\n\ndef _flatten_dependency_maps(all_dependency_maps):\n \"\"\"Flatten a list of dependency maps into one dictionary.\n\n Dependency maps have the following structure:\n\n ```python\n DEPENDENCIES_MAP = {\n # The first key in the map is a Bazel package\n # name of the workspace this file is defined in.\n \"workspace_member_package\": {\n\n # Not all dependencies are supported for all platforms.\n # the condition key is the condition required to be true\n # on the host platform.\n \"condition\": {\n\n # An alias to a crate target. # The label of the crate target the\n # Aliases are only crate names. # package name refers to.\n \"package_name\": \"@full//:label\",\n }\n }\n }\n ```\n\n Args:\n all_dependency_maps (list): A list of dicts as described above\n\n Returns:\n dict: A dictionary as described above\n \"\"\"\n dependencies = {}\n\n for workspace_deps_map in all_dependency_maps:\n for pkg_name, conditional_deps_map in workspace_deps_map.items():\n if pkg_name not in dependencies:\n non_frozen_map = dict()\n for key, values in conditional_deps_map.items():\n non_frozen_map.update({key: dict(values.items())})\n dependencies.setdefault(pkg_name, non_frozen_map)\n continue\n\n for condition, deps_map in conditional_deps_map.items():\n # If the condition has not been recorded, do so and continue\n if condition not in dependencies[pkg_name]:\n dependencies[pkg_name].setdefault(condition, dict(deps_map.items()))\n continue\n\n # Alert on any miss-matched dependencies\n inconsistent_entries = []\n for crate_name, crate_label in deps_map.items():\n existing = dependencies[pkg_name][condition].get(crate_name)\n if existing and existing != crate_label:\n inconsistent_entries.append((crate_name, existing, crate_label))\n dependencies[pkg_name][condition].update({crate_name: crate_label})\n\n return dependencies\n\ndef crate_deps(deps, package_name = None):\n \"\"\"Finds the fully qualified label of the requested crates for the package where this macro is called.\n\n Args:\n deps (list): The desired list of crate targets.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()`.\n\n Returns:\n list: A list of labels to generated rust targets (str)\n \"\"\"\n\n if not deps:\n return []\n\n if package_name == None:\n package_name = native.package_name()\n\n # Join both sets of dependencies\n dependencies = _flatten_dependency_maps([\n _NORMAL_DEPENDENCIES,\n _NORMAL_DEV_DEPENDENCIES,\n _PROC_MACRO_DEPENDENCIES,\n _PROC_MACRO_DEV_DEPENDENCIES,\n _BUILD_DEPENDENCIES,\n _BUILD_PROC_MACRO_DEPENDENCIES,\n ]).pop(package_name, {})\n\n # Combine all conditional packages so we can easily index over a flat list\n # TODO: Perhaps this should actually return select statements and maintain\n # the conditionals of the dependencies\n flat_deps = {}\n for deps_set in dependencies.values():\n for crate_name, crate_label in deps_set.items():\n flat_deps.update({crate_name: crate_label})\n\n missing_crates = []\n crate_targets = []\n for crate_target in deps:\n if crate_target not in flat_deps:\n missing_crates.append(crate_target)\n else:\n crate_targets.append(flat_deps[crate_target])\n\n if missing_crates:\n fail(\"Could not find crates `{}` among dependencies of `{}`. Available dependencies were `{}`\".format(\n missing_crates,\n package_name,\n dependencies,\n ))\n\n return crate_targets\n\ndef crate_edition(package_name = None):\n \"\"\"Finds the Rust edition for the package where this macro is called.\n\n Args:\n package_name (str, optional): The package name whose edition should be\n looked up. Defaults to `native.package_name()` when unset.\n\n Returns:\n str: The Rust edition declared by the package's Cargo.toml file.\n \"\"\"\n if package_name == None:\n package_name = native.package_name()\n\n if package_name not in _CRATE_EDITIONS:\n fail(\"Tried to get crate_edition for package \" + package_name + \" but that package had no Cargo.toml file\")\n\n return _CRATE_EDITIONS[package_name]\n\ndef all_crate_deps(\n normal = False, \n normal_dev = False, \n proc_macro = False, \n proc_macro_dev = False,\n build = False,\n build_proc_macro = False,\n package_name = None):\n \"\"\"Finds the fully qualified label of all requested direct crate dependencies \\\n for the package where this macro is called.\n\n If no parameters are set, all normal dependencies are returned. Setting any one flag will\n otherwise impact the contents of the returned list.\n\n Args:\n normal (bool, optional): If True, normal dependencies are included in the\n output list.\n normal_dev (bool, optional): If True, normal dev dependencies will be\n included in the output list.\n proc_macro (bool, optional): If True, proc_macro dependencies are included\n in the output list.\n proc_macro_dev (bool, optional): If True, dev proc_macro dependencies are\n included in the output list.\n build (bool, optional): If True, build dependencies are included\n in the output list.\n build_proc_macro (bool, optional): If True, build proc_macro dependencies are\n included in the output list.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()` when unset.\n\n Returns:\n list: A list of labels to generated rust targets (str)\n \"\"\"\n\n if package_name == None:\n package_name = native.package_name()\n\n # Determine the relevant maps to use\n all_dependency_maps = []\n if normal:\n all_dependency_maps.append(_NORMAL_DEPENDENCIES)\n if normal_dev:\n all_dependency_maps.append(_NORMAL_DEV_DEPENDENCIES)\n if proc_macro:\n all_dependency_maps.append(_PROC_MACRO_DEPENDENCIES)\n if proc_macro_dev:\n all_dependency_maps.append(_PROC_MACRO_DEV_DEPENDENCIES)\n if build:\n all_dependency_maps.append(_BUILD_DEPENDENCIES)\n if build_proc_macro:\n all_dependency_maps.append(_BUILD_PROC_MACRO_DEPENDENCIES)\n\n # Default to always using normal dependencies\n if not all_dependency_maps:\n all_dependency_maps.append(_NORMAL_DEPENDENCIES)\n\n dependencies = _flatten_dependency_maps(all_dependency_maps).pop(package_name, None)\n\n if not dependencies:\n if dependencies == None:\n fail(\"Tried to get all_crate_deps for package \" + package_name + \" but that package had no Cargo.toml file\")\n else:\n return []\n\n crate_deps = list(dependencies.pop(_COMMON_CONDITION, {}).values())\n for condition, deps in dependencies.items():\n crate_deps += selects.with_or({\n tuple(_CONDITIONS[condition]): deps.values(),\n \"//conditions:default\": [],\n })\n\n return crate_deps\n\ndef aliases(\n normal = False,\n normal_dev = False,\n proc_macro = False,\n proc_macro_dev = False,\n build = False,\n build_proc_macro = False,\n package_name = None):\n \"\"\"Produces a map of Crate alias names to their original label\n\n If no dependency kinds are specified, `normal` and `proc_macro` are used by default.\n Setting any one flag will otherwise determine the contents of the returned dict.\n\n Args:\n normal (bool, optional): If True, normal dependencies are included in the\n output list.\n normal_dev (bool, optional): If True, normal dev dependencies will be\n included in the output list..\n proc_macro (bool, optional): If True, proc_macro dependencies are included\n in the output list.\n proc_macro_dev (bool, optional): If True, dev proc_macro dependencies are\n included in the output list.\n build (bool, optional): If True, build dependencies are included\n in the output list.\n build_proc_macro (bool, optional): If True, build proc_macro dependencies are\n included in the output list.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()` when unset.\n\n Returns:\n dict: The aliases of all associated packages\n \"\"\"\n if package_name == None:\n package_name = native.package_name()\n\n # Determine the relevant maps to use\n all_aliases_maps = []\n if normal:\n all_aliases_maps.append(_NORMAL_ALIASES)\n if normal_dev:\n all_aliases_maps.append(_NORMAL_DEV_ALIASES)\n if proc_macro:\n all_aliases_maps.append(_PROC_MACRO_ALIASES)\n if proc_macro_dev:\n all_aliases_maps.append(_PROC_MACRO_DEV_ALIASES)\n if build:\n all_aliases_maps.append(_BUILD_ALIASES)\n if build_proc_macro:\n all_aliases_maps.append(_BUILD_PROC_MACRO_ALIASES)\n\n # Default to always using normal aliases\n if not all_aliases_maps:\n all_aliases_maps.append(_NORMAL_ALIASES)\n all_aliases_maps.append(_PROC_MACRO_ALIASES)\n\n aliases = _flatten_dependency_maps(all_aliases_maps).pop(package_name, None)\n\n if not aliases:\n return dict()\n\n common_items = aliases.pop(_COMMON_CONDITION, {}).items()\n\n # If there are only common items in the dictionary, immediately return them\n if not len(aliases.keys()) == 1:\n return dict(common_items)\n\n # Build a single select statement where each conditional has accounted for the\n # common set of aliases.\n crate_aliases = {\"//conditions:default\": dict(common_items)}\n for condition, deps in aliases.items():\n condition_triples = _CONDITIONS[condition]\n for triple in condition_triples:\n if triple in crate_aliases:\n crate_aliases[triple].update(deps)\n else:\n crate_aliases.update({triple: dict(deps.items() + common_items)})\n\n return select(crate_aliases)\n\n###############################################################################\n# WORKSPACE MEMBER DEPS, ALIASES, AND EDITIONS\n###############################################################################\n\n_CRATE_EDITIONS = {\n \"src/wasix/postmaster/tools/sealed-export-closure\": \"2024\",\n}\n\n_NORMAL_DEPENDENCIES = {\n \"src/wasix/postmaster/tools/sealed-export-closure\": {\n _COMMON_CONDITION: {\n \"anyhow\": Label(\"@postmaster_sealing_crates//anyhow-1.0.104\"),\n \"hex\": Label(\"@postmaster_sealing_crates//hex-0.4.3\"),\n \"serde\": Label(\"@postmaster_sealing_crates//serde-1.0.229\"),\n \"serde_json\": Label(\"@postmaster_sealing_crates//serde_json-1.0.151\"),\n \"sha2\": Label(\"@postmaster_sealing_crates//sha2-0.10.9\"),\n \"wasm-encoder\": Label(\"@postmaster_sealing_crates//wasm-encoder-0.247.0\"),\n \"wasmparser\": Label(\"@postmaster_sealing_crates//wasmparser-0.247.0\"),\n },\n },\n}\n\n\n_NORMAL_ALIASES = {\n \"src/wasix/postmaster/tools/sealed-export-closure\": {\n _COMMON_CONDITION: {\n },\n },\n}\n\n\n_NORMAL_DEV_DEPENDENCIES = {\n \"src/wasix/postmaster/tools/sealed-export-closure\": {\n },\n}\n\n\n_NORMAL_DEV_ALIASES = {\n \"src/wasix/postmaster/tools/sealed-export-closure\": {\n },\n}\n\n\n_PROC_MACRO_DEPENDENCIES = {\n \"src/wasix/postmaster/tools/sealed-export-closure\": {\n },\n}\n\n\n_PROC_MACRO_ALIASES = {\n \"src/wasix/postmaster/tools/sealed-export-closure\": {\n },\n}\n\n\n_PROC_MACRO_DEV_DEPENDENCIES = {\n \"src/wasix/postmaster/tools/sealed-export-closure\": {\n },\n}\n\n\n_PROC_MACRO_DEV_ALIASES = {\n \"src/wasix/postmaster/tools/sealed-export-closure\": {\n },\n}\n\n\n_BUILD_DEPENDENCIES = {\n \"src/wasix/postmaster/tools/sealed-export-closure\": {\n },\n}\n\n\n_BUILD_ALIASES = {\n \"src/wasix/postmaster/tools/sealed-export-closure\": {\n },\n}\n\n\n_BUILD_PROC_MACRO_DEPENDENCIES = {\n \"src/wasix/postmaster/tools/sealed-export-closure\": {\n },\n}\n\n\n_BUILD_PROC_MACRO_ALIASES = {\n \"src/wasix/postmaster/tools/sealed-export-closure\": {\n },\n}\n\n\n_CONDITIONS = {\n \"aarch64-apple-darwin\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\"],\n \"aarch64-linux-android\": [],\n \"aarch64-unknown-linux-gnu\": [\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\"],\n \"cfg(all(target_arch = \\\"aarch64\\\", target_os = \\\"linux\\\"))\": [\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\"],\n \"cfg(all(target_arch = \\\"aarch64\\\", target_vendor = \\\"apple\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\"],\n \"cfg(all(target_arch = \\\"loongarch64\\\", target_os = \\\"linux\\\"))\": [],\n \"cfg(any())\": [],\n \"cfg(any(target_arch = \\\"aarch64\\\", target_arch = \\\"x86_64\\\", target_arch = \\\"x86\\\"))\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\",\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\",\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"x86_64-unknown-linux-gnu\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n}\n\n###############################################################################\n\ndef crate_repositories():\n \"\"\"A macro for defining repositories for all generated crates.\n\n Returns:\n A list of repos visible to the module through the module extension.\n \"\"\"\n maybe(\n crates_vendor_remote_repository,\n name = \"postmaster_sealing_crates\",\n # Lean interface: just point at `crates.bzl`; the repo rule\n # derives the sibling `BUILD.bazel` and `defs.bzl`.\n crates_module = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:crates.bzl\"),\n )\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__anyhow-1.0.104\",\n sha256 = \"330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/anyhow/1.0.104/download\"],\n strip_prefix = \"anyhow-1.0.104\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.anyhow-1.0.104.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__bitflags-2.13.1\",\n sha256 = \"b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/bitflags/2.13.1/download\"],\n strip_prefix = \"bitflags-2.13.1\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.bitflags-2.13.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__block-buffer-0.10.4\",\n sha256 = \"3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/block-buffer/0.10.4/download\"],\n strip_prefix = \"block-buffer-0.10.4\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.block-buffer-0.10.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__cfg-if-1.0.4\",\n sha256 = \"9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cfg-if/1.0.4/download\"],\n strip_prefix = \"cfg-if-1.0.4\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.cfg-if-1.0.4.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__cpufeatures-0.2.17\",\n sha256 = \"59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/cpufeatures/0.2.17/download\"],\n strip_prefix = \"cpufeatures-0.2.17\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.cpufeatures-0.2.17.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__crypto-common-0.1.7\",\n sha256 = \"78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/crypto-common/0.1.7/download\"],\n strip_prefix = \"crypto-common-0.1.7\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.crypto-common-0.1.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__digest-0.10.7\",\n sha256 = \"9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/digest/0.10.7/download\"],\n strip_prefix = \"digest-0.10.7\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.digest-0.10.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__equivalent-1.0.2\",\n sha256 = \"877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/equivalent/1.0.2/download\"],\n strip_prefix = \"equivalent-1.0.2\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.equivalent-1.0.2.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__foldhash-0.2.0\",\n sha256 = \"77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/foldhash/0.2.0/download\"],\n strip_prefix = \"foldhash-0.2.0\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.foldhash-0.2.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__generic-array-0.14.7\",\n sha256 = \"85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/generic-array/0.14.7/download\"],\n strip_prefix = \"generic-array-0.14.7\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.generic-array-0.14.7.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__hashbrown-0.17.1\",\n sha256 = \"ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hashbrown/0.17.1/download\"],\n strip_prefix = \"hashbrown-0.17.1\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.hashbrown-0.17.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__hex-0.4.3\",\n sha256 = \"7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/hex/0.4.3/download\"],\n strip_prefix = \"hex-0.4.3\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.hex-0.4.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__indexmap-2.14.0\",\n sha256 = \"d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/indexmap/2.14.0/download\"],\n strip_prefix = \"indexmap-2.14.0\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.indexmap-2.14.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__itoa-1.0.18\",\n sha256 = \"8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/itoa/1.0.18/download\"],\n strip_prefix = \"itoa-1.0.18\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.itoa-1.0.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__leb128fmt-0.1.0\",\n sha256 = \"09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/leb128fmt/0.1.0/download\"],\n strip_prefix = \"leb128fmt-0.1.0\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.leb128fmt-0.1.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__libc-0.2.189\",\n sha256 = \"3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/libc/0.2.189/download\"],\n strip_prefix = \"libc-0.2.189\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.libc-0.2.189.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__memchr-2.8.3\",\n sha256 = \"cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/memchr/2.8.3/download\"],\n strip_prefix = \"memchr-2.8.3\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.memchr-2.8.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__proc-macro2-1.0.107\",\n sha256 = \"985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/proc-macro2/1.0.107/download\"],\n strip_prefix = \"proc-macro2-1.0.107\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.proc-macro2-1.0.107.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__quote-1.0.47\",\n sha256 = \"1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/quote/1.0.47/download\"],\n strip_prefix = \"quote-1.0.47\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.quote-1.0.47.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__semver-1.0.28\",\n sha256 = \"8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/semver/1.0.28/download\"],\n strip_prefix = \"semver-1.0.28\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.semver-1.0.28.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__serde-1.0.229\",\n sha256 = \"4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde/1.0.229/download\"],\n strip_prefix = \"serde-1.0.229\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.serde-1.0.229.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__serde_core-1.0.229\",\n sha256 = \"67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_core/1.0.229/download\"],\n strip_prefix = \"serde_core-1.0.229\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.serde_core-1.0.229.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__serde_derive-1.0.229\",\n sha256 = \"e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_derive/1.0.229/download\"],\n strip_prefix = \"serde_derive-1.0.229\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.serde_derive-1.0.229.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__serde_json-1.0.151\",\n sha256 = \"c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/serde_json/1.0.151/download\"],\n strip_prefix = \"serde_json-1.0.151\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.serde_json-1.0.151.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__sha2-0.10.9\",\n sha256 = \"a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/sha2/0.10.9/download\"],\n strip_prefix = \"sha2-0.10.9\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.sha2-0.10.9.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__syn-3.0.3\",\n sha256 = \"53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/syn/3.0.3/download\"],\n strip_prefix = \"syn-3.0.3\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.syn-3.0.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__typenum-1.20.1\",\n sha256 = \"b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/typenum/1.20.1/download\"],\n strip_prefix = \"typenum-1.20.1\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.typenum-1.20.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__unicode-ident-1.0.24\",\n sha256 = \"e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unicode-ident/1.0.24/download\"],\n strip_prefix = \"unicode-ident-1.0.24\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.unicode-ident-1.0.24.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__version_check-0.9.5\",\n sha256 = \"0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/version_check/0.9.5/download\"],\n strip_prefix = \"version_check-0.9.5\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.version_check-0.9.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__wasm-encoder-0.247.0\",\n sha256 = \"30b6733b8b91d010a6ac5b0fb237dc46a19650bc4c67db66857e2e787d437204\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasm-encoder/0.247.0/download\"],\n strip_prefix = \"wasm-encoder-0.247.0\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.wasm-encoder-0.247.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__wasmparser-0.247.0\",\n sha256 = \"8e6fb4c2bee46c5ea4d40f8cdb5c131725cd976718ec56f1c8e82fbde5fa2a80\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/wasmparser/0.247.0/download\"],\n strip_prefix = \"wasmparser-0.247.0\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.wasmparser-0.247.0.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"postmaster_sealing_crates__zmij-1.0.23\",\n sha256 = \"29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/zmij/1.0.23/download\"],\n strip_prefix = \"zmij-1.0.23\",\n build_file = Label(\"@postmaster_sealing_crates//postmaster_sealing_crates:BUILD.zmij-1.0.23.bazel\"),\n )\n\n return [\n struct(repo = \"postmaster_sealing_crates\", is_dev_dep = False),\n struct(repo=\"postmaster_sealing_crates__anyhow-1.0.104\", is_dev_dep = False),\n struct(repo=\"postmaster_sealing_crates__hex-0.4.3\", is_dev_dep = False),\n struct(repo=\"postmaster_sealing_crates__serde-1.0.229\", is_dev_dep = False),\n struct(repo=\"postmaster_sealing_crates__serde_json-1.0.151\", is_dev_dep = False),\n struct(repo=\"postmaster_sealing_crates__sha2-0.10.9\", is_dev_dep = False),\n struct(repo=\"postmaster_sealing_crates__wasm-encoder-0.247.0\", is_dev_dep = False),\n struct(repo=\"postmaster_sealing_crates__wasmparser-0.247.0\", is_dev_dep = False),\n ]\n", + "defs.bzl": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\"\"\"Deprecated: re-exports the crate_universe macros from `:crates.bzl`.\"\"\"\n\nload(\n \":crates.bzl\",\n _aliases = \"aliases\",\n _all_crate_deps = \"all_crate_deps\",\n _crate_deps = \"crate_deps\",\n _crate_edition = \"crate_edition\",\n _crate_repositories = \"crate_repositories\",\n)\n\naliases = _aliases\nall_crate_deps = _all_crate_deps\ncrate_deps = _crate_deps\ncrate_edition = _crate_edition\ncrate_repositories = _crate_repositories\n", + "anyhow-1.0.104/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"anyhow-1.0.104\",\n actual = \"@postmaster_sealing_crates__anyhow-1.0.104//:anyhow\",\n tags = [\"manual\"],\n)\n", + "anyhow/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"anyhow\",\n actual = \"@postmaster_sealing_crates__anyhow-1.0.104//:anyhow\",\n tags = [\"manual\"],\n)\n", + "hex-0.4.3/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"hex-0.4.3\",\n actual = \"@postmaster_sealing_crates__hex-0.4.3//:hex\",\n tags = [\"manual\"],\n)\n", + "hex/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"hex\",\n actual = \"@postmaster_sealing_crates__hex-0.4.3//:hex\",\n tags = [\"manual\"],\n)\n", + "serde-1.0.229/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"serde-1.0.229\",\n actual = \"@postmaster_sealing_crates__serde-1.0.229//:serde\",\n tags = [\"manual\"],\n)\n", + "serde/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"serde\",\n actual = \"@postmaster_sealing_crates__serde-1.0.229//:serde\",\n tags = [\"manual\"],\n)\n", + "serde_json-1.0.151/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"serde_json-1.0.151\",\n actual = \"@postmaster_sealing_crates__serde_json-1.0.151//:serde_json\",\n tags = [\"manual\"],\n)\n", + "serde_json/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"serde_json\",\n actual = \"@postmaster_sealing_crates__serde_json-1.0.151//:serde_json\",\n tags = [\"manual\"],\n)\n", + "sha2-0.10.9/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"sha2-0.10.9\",\n actual = \"@postmaster_sealing_crates__sha2-0.10.9//:sha2\",\n tags = [\"manual\"],\n)\n", + "sha2/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"sha2\",\n actual = \"@postmaster_sealing_crates__sha2-0.10.9//:sha2\",\n tags = [\"manual\"],\n)\n", + "wasm-encoder-0.247.0/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasm-encoder-0.247.0\",\n actual = \"@postmaster_sealing_crates__wasm-encoder-0.247.0//:wasm_encoder\",\n tags = [\"manual\"],\n)\n", + "wasm-encoder/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasm-encoder\",\n actual = \"@postmaster_sealing_crates__wasm-encoder-0.247.0//:wasm_encoder\",\n tags = [\"manual\"],\n)\n", + "wasmparser-0.247.0/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmparser-0.247.0\",\n actual = \"@postmaster_sealing_crates__wasmparser-0.247.0//:wasmparser\",\n tags = [\"manual\"],\n)\n", + "wasmparser/BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nalias(\n name = \"wasmparser\",\n actual = \"@postmaster_sealing_crates__wasmparser-0.247.0//:wasmparser\",\n tags = [\"manual\"],\n)\n" + } + } + }, + "postmaster_sealing_crates__anyhow-1.0.104": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/anyhow/1.0.104/download" + ], + "strip_prefix": "anyhow-1.0.104", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"anyhow\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=anyhow\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.104\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"anyhow\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=anyhow\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.104\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_sealing_crates__bitflags-2.13.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/bitflags/2.13.1/download" + ], + "strip_prefix": "bitflags-2.13.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"bitflags\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=bitflags\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.13.1\",\n)\n" + } + }, + "postmaster_sealing_crates__block-buffer-0.10.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/block-buffer/0.10.4/download" + ], + "strip_prefix": "block-buffer-0.10.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"block_buffer\",\n deps = [\n \"@postmaster_sealing_crates__generic-array-0.14.7//:generic_array\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=block-buffer\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.4\",\n)\n" + } + }, + "postmaster_sealing_crates__cfg-if-1.0.4": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cfg-if/1.0.4/download" + ], + "strip_prefix": "cfg-if-1.0.4", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cfg_if\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cfg-if\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.4\",\n)\n" + } + }, + "postmaster_sealing_crates__cpufeatures-0.2.17": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/cpufeatures/0.2.17/download" + ], + "strip_prefix": "cpufeatures-0.2.17", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"cpufeatures\",\n deps = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_sealing_crates__libc-0.2.189//:libc\", # cfg(all(target_arch = \"aarch64\", target_vendor = \"apple\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_sealing_crates__libc-0.2.189//:libc\", # cfg(all(target_arch = \"aarch64\", target_os = \"linux\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=cpufeatures\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.17\",\n)\n" + } + }, + "postmaster_sealing_crates__crypto-common-0.1.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/crypto-common/0.1.7/download" + ], + "strip_prefix": "crypto-common-0.1.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"crypto_common\",\n deps = [\n \"@postmaster_sealing_crates__generic-array-0.14.7//:generic_array\",\n \"@postmaster_sealing_crates__typenum-1.20.1//:typenum\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=crypto-common\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.7\",\n)\n" + } + }, + "postmaster_sealing_crates__digest-0.10.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/digest/0.10.7/download" + ], + "strip_prefix": "digest-0.10.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"digest\",\n deps = [\n \"@postmaster_sealing_crates__block-buffer-0.10.4//:block_buffer\",\n \"@postmaster_sealing_crates__crypto-common-0.1.7//:crypto_common\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"block-buffer\",\n \"core-api\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=digest\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.7\",\n)\n" + } + }, + "postmaster_sealing_crates__equivalent-1.0.2": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/equivalent/1.0.2/download" + ], + "strip_prefix": "equivalent-1.0.2", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"equivalent\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=equivalent\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.2\",\n)\n" + } + }, + "postmaster_sealing_crates__foldhash-0.2.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/foldhash/0.2.0/download" + ], + "strip_prefix": "foldhash-0.2.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"foldhash\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=foldhash\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.0\",\n)\n" + } + }, + "postmaster_sealing_crates__generic-array-0.14.7": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/generic-array/0.14.7/download" + ], + "strip_prefix": "generic-array-0.14.7", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"generic_array\",\n deps = [\n \":build_script_build\",\n \"@postmaster_sealing_crates__typenum-1.20.1//:typenum\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"more_lengths\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=generic-array\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.14.7\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"more_lengths\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n deps = [\n \"@postmaster_sealing_crates__version_check-0.9.5//:version_check\",\n ],\n emit_warnings = False,\n edition = \"2015\",\n pkg_name = \"generic-array\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=generic-array\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.14.7\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_sealing_crates__hashbrown-0.17.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hashbrown/0.17.1/download" + ], + "strip_prefix": "hashbrown-0.17.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hashbrown\",\n deps = [\n \"@postmaster_sealing_crates__foldhash-0.2.0//:foldhash\",\n \"@postmaster_sealing_crates__serde_core-1.0.229//:serde_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default-hasher\",\n \"serde\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hashbrown\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.17.1\",\n)\n" + } + }, + "postmaster_sealing_crates__hex-0.4.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/hex/0.4.3/download" + ], + "strip_prefix": "hex-0.4.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"hex\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=hex\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.4.3\",\n)\n" + } + }, + "postmaster_sealing_crates__indexmap-2.14.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/indexmap/2.14.0/download" + ], + "strip_prefix": "indexmap-2.14.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"indexmap\",\n deps = [\n \"@postmaster_sealing_crates__equivalent-1.0.2//:equivalent\",\n \"@postmaster_sealing_crates__hashbrown-0.17.1//:hashbrown\",\n \"@postmaster_sealing_crates__serde_core-1.0.229//:serde_core\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"serde\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2024\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=indexmap\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.14.0\",\n)\n" + } + }, + "postmaster_sealing_crates__itoa-1.0.18": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/itoa/1.0.18/download" + ], + "strip_prefix": "itoa-1.0.18", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"itoa\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=itoa\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.18\",\n)\n" + } + }, + "postmaster_sealing_crates__leb128fmt-0.1.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/leb128fmt/0.1.0/download" + ], + "strip_prefix": "leb128fmt-0.1.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"leb128fmt\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=leb128fmt\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.1.0\",\n)\n" + } + }, + "postmaster_sealing_crates__libc-0.2.189": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/libc/0.2.189/download" + ], + "strip_prefix": "libc-0.2.189", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"libc\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=libc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.2.189\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"libc\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=libc\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.2.189\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_sealing_crates__memchr-2.8.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/memchr/2.8.3/download" + ], + "strip_prefix": "memchr-2.8.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"memchr\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=memchr\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.8.3\",\n)\n" + } + }, + "postmaster_sealing_crates__proc-macro2-1.0.107": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/proc-macro2/1.0.107/download" + ], + "strip_prefix": "proc-macro2-1.0.107", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"proc_macro2\",\n deps = [\n \":build_script_build\",\n \"@postmaster_sealing_crates__unicode-ident-1.0.24//:unicode_ident\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"proc-macro\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=proc-macro2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.107\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"proc-macro\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"proc-macro2\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=proc-macro2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.107\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_sealing_crates__quote-1.0.47": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/quote/1.0.47/download" + ], + "strip_prefix": "quote-1.0.47", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"quote\",\n deps = [\n \":build_script_build\",\n \"@postmaster_sealing_crates__proc-macro2-1.0.107//:proc_macro2\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"proc-macro\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=quote\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.47\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"proc-macro\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"quote\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=quote\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.47\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_sealing_crates__semver-1.0.28": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/semver/1.0.28/download" + ], + "strip_prefix": "semver-1.0.28", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"semver\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=semver\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.28\",\n)\n" + } + }, + "postmaster_sealing_crates__serde-1.0.229": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde/1.0.229/download" + ], + "strip_prefix": "serde-1.0.229", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde\",\n deps = [\n \":build_script_build\",\n \"@postmaster_sealing_crates__serde_core-1.0.229//:serde_core\",\n ],\n proc_macro_deps = [\n \"@postmaster_sealing_crates__serde_derive-1.0.229//:serde_derive\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"derive\",\n \"serde_derive\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.229\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"default\",\n \"derive\",\n \"serde_derive\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"serde\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.229\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_sealing_crates__serde_core-1.0.229": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde_core/1.0.229/download" + ], + "strip_prefix": "serde_core-1.0.229", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde_core\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"result\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.229\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"alloc\",\n \"result\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"serde_core\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_core\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.229\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_sealing_crates__serde_derive-1.0.229": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde_derive/1.0.229/download" + ], + "strip_prefix": "serde_derive-1.0.229", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"serde_derive\",\n deps = [\n \"@postmaster_sealing_crates__proc-macro2-1.0.107//:proc_macro2\",\n \"@postmaster_sealing_crates__quote-1.0.47//:quote\",\n \"@postmaster_sealing_crates__syn-3.0.3//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_derive\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.229\",\n)\n" + } + }, + "postmaster_sealing_crates__serde_json-1.0.151": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/serde_json/1.0.151/download" + ], + "strip_prefix": "serde_json-1.0.151", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"serde_json\",\n deps = [\n \":build_script_build\",\n \"@postmaster_sealing_crates__itoa-1.0.18//:itoa\",\n \"@postmaster_sealing_crates__memchr-2.8.3//:memchr\",\n \"@postmaster_sealing_crates__serde_core-1.0.229//:serde_core\",\n \"@postmaster_sealing_crates__zmij-1.0.23//:zmij\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_json\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.151\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"serde_json\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=serde_json\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.151\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + }, + "postmaster_sealing_crates__sha2-0.10.9": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/sha2/0.10.9/download" + ], + "strip_prefix": "sha2-0.10.9", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"sha2\",\n deps = [\n \"@postmaster_sealing_crates__cfg-if-1.0.4//:cfg_if\",\n \"@postmaster_sealing_crates__digest-0.10.7//:digest\",\n ] + select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [\n \"@postmaster_sealing_crates__cpufeatures-0.2.17//:cpufeatures\", # cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))\n ],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [\n \"@postmaster_sealing_crates__cpufeatures-0.2.17//:cpufeatures\", # cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))\n ],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [\n \"@postmaster_sealing_crates__cpufeatures-0.2.17//:cpufeatures\", # cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))\n ],\n \"//conditions:default\": [],\n }),\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=sha2\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.10.9\",\n)\n" + } + }, + "postmaster_sealing_crates__syn-3.0.3": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/syn/3.0.3/download" + ], + "strip_prefix": "syn-3.0.3", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"syn\",\n deps = [\n \"@postmaster_sealing_crates__proc-macro2-1.0.107//:proc_macro2\",\n \"@postmaster_sealing_crates__quote-1.0.47//:quote\",\n \"@postmaster_sealing_crates__unicode-ident-1.0.24//:unicode_ident\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"clone-impls\",\n \"derive\",\n \"parsing\",\n \"printing\",\n \"proc-macro\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=syn\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"3.0.3\",\n)\n" + } + }, + "postmaster_sealing_crates__typenum-1.20.1": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/typenum/1.20.1/download" + ], + "strip_prefix": "typenum-1.20.1", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"typenum\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2018\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=typenum\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.20.1\",\n)\n" + } + }, + "postmaster_sealing_crates__unicode-ident-1.0.24": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/unicode-ident/1.0.24/download" + ], + "strip_prefix": "unicode-ident-1.0.24", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unicode_ident\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unicode-ident\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.24\",\n)\n" + } + }, + "postmaster_sealing_crates__version_check-0.9.5": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/version_check/0.9.5/download" + ], + "strip_prefix": "version_check-0.9.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"version_check\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2015\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=version_check\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.9.5\",\n)\n" + } + }, + "postmaster_sealing_crates__wasm-encoder-0.247.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "30b6733b8b91d010a6ac5b0fb237dc46a19650bc4c67db66857e2e787d437204", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasm-encoder/0.247.0/download" + ], + "strip_prefix": "wasm-encoder-0.247.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasm_encoder\",\n deps = [\n \"@postmaster_sealing_crates__leb128fmt-0.1.0//:leb128fmt\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"component-model\",\n \"default\",\n \"std\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasm-encoder\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.247.0\",\n)\n" + } + }, + "postmaster_sealing_crates__wasmparser-0.247.0": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "8e6fb4c2bee46c5ea4d40f8cdb5c131725cd976718ec56f1c8e82fbde5fa2a80", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/wasmparser/0.247.0/download" + ], + "strip_prefix": "wasmparser-0.247.0", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"wasmparser\",\n deps = [\n \"@postmaster_sealing_crates__bitflags-2.13.1//:bitflags\",\n \"@postmaster_sealing_crates__hashbrown-0.17.1//:hashbrown\",\n \"@postmaster_sealing_crates__indexmap-2.14.0//:indexmap\",\n \"@postmaster_sealing_crates__semver-1.0.28//:semver\",\n \"@postmaster_sealing_crates__serde-1.0.229//:serde\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"component-model\",\n \"default\",\n \"features\",\n \"hash-collections\",\n \"serde\",\n \"simd\",\n \"std\",\n \"validate\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=wasmparser\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.247.0\",\n)\n" + } + }, + "postmaster_sealing_crates__zmij-1.0.23": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "patch_args": [], + "patch_tool": "", + "patches": [], + "remote_patch_strip": 1, + "sha256": "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b", + "type": "tar.gz", + "urls": [ + "https://static.crates.io/crates/zmij/1.0.23/download" + ], + "strip_prefix": "zmij-1.0.23", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'oliphaunt'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"zmij\",\n deps = [\n \":build_script_build\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zmij\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.23\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n build_script_env_files = [\n \":cargo_toml_env_vars\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n emit_warnings = False,\n edition = \"2021\",\n pkg_name = \"zmij\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=zmij\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"1.0.23\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + } + } + } + } + }, + "@@aspect_tools_telemetry+//:extension.bzl%telemetry": { + "general": { + "bzlTransitiveDigest": "ihzLOoAnQP6Y5iSYOhEjvb6uxEbA6ZgH8Qikau2lGRU=", + "usagesDigest": "volr0ZHn2VAADxanzsqMFz4xRhpWZ2j6EgKK3zYnWQo=", + "recordedInputs": [ + "REPO_MAPPING:aspect_tools_telemetry+,bazel_lib bazel_lib+", + "REPO_MAPPING:aspect_tools_telemetry+,bazel_skylib bazel_skylib+", + "ENV:ASPECT_TOOLS_TELEMETRY_TEST \\0" + ], + "generatedRepoSpecs": { + "aspect_tools_telemetry_report": { + "repoRuleId": "@@aspect_tools_telemetry+//:extension.bzl%tel_repository", + "attributes": { + "deps": { + "aspect_rules_js": "3.5.1", + "aspect_rules_ts": "3.10.1", + "aspect_tools_telemetry": "0.5.2" + }, + "last_notice": 0 + } + } + }, + "moduleExtensionMetadata": { + "useAllRepos": "NO", + "reproducible": false + } + } + }, + "@@gcc_toolchain+//:internal.bzl%non_bazel_dependencies": { + "general": { + "bzlTransitiveDigest": "1puLndQgz4p7d72pLwHLCbhcXIjcSLLZHMgUZvD5RBI=", + "usagesDigest": "13mSQ09nHZ81WiU4i3SNGXBI5svRCTTyl8M9oydMMbI=", + "recordedInputs": [ + "REPO_MAPPING:gcc_toolchain+,bazel_tools bazel_tools", + "REPO_MAPPING:gcc_toolchain+,lapack gcc_toolchain++non_bazel_dependencies+lapack" + ], + "generatedRepoSpecs": { + "openssl": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "build_file_content": "filegroup(\n name = \"srcs\",\n srcs = glob(\n include = [\"**\"],\n exclude = [\"**/* *\"],\n ),\n visibility = [\"//visibility:public\"],\n)\n", + "sha256": "40dceb51a4f6a5275bde0e6bf20ef4b91bfc32ed57c0552e2e8e15463372b17a", + "strip_prefix": "openssl-1.1.1n", + "url": "https://www.openssl.org/source/openssl-1.1.1n.tar.gz" + } + }, + "lapack": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "build_file_content": "filegroup(\n name = \"srcs\",\n srcs = glob(\n include = [\"**\"],\n exclude = [\"**/* *\"],\n ),\n visibility = [\"//visibility:public\"],\n)\n", + "patch_cmds": [ + "cat > make.inc < +#include + +static_assert(__ANDROID_API__ == 24, "runtime must compile against the public API 24 contract"); + +extern "C" int oliphaunt_android_abi_smoke(const char *text) { + // Exercise libc++ rather than proving static-runtime settings from flags. + return static_cast(std::string(text).size()) + android_get_device_api_level(); +} diff --git a/build_defs/android/abi.test.mts b/build_defs/android/abi.test.mts new file mode 100644 index 000000000..96d0c6fc7 --- /dev/null +++ b/build_defs/android/abi.test.mts @@ -0,0 +1,15 @@ +import { expect, test } from 'bun:test'; +import { readFileSync } from 'node:fs'; +import { inspectPlatformBinaryBuffer } from '../../tools/packaging/platform-binary-contract.mts'; + +for (const [name, target] of [ + ['arm64', 'android-arm64-v8a'], + ['x86_64', 'android-x86_64'], +] as const) { + test(`${target}: native ELF meets the Android platform policy`, () => { + const label = `build_defs/android/libabi_smoke_${name}.so`; + const bytes = readFileSync(label); + const inspected = inspectPlatformBinaryBuffer(bytes, { target, label }); + expect(inspected.format).toBe('elf'); + }); +} diff --git a/build_defs/android/app-query-test.bzl b/build_defs/android/app-query-test.bzl new file mode 100644 index 000000000..647dfae31 --- /dev/null +++ b/build_defs/android/app-query-test.bzl @@ -0,0 +1,266 @@ +"""The mobile example uses the actual selected or completed TS supplier.""" + +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts", "unittest") +load(":app.bzl", "android_app_configuration", "android_workspace_npm", "mobile_query_input") +load("@rules_android//rules:min_sdk_version.bzl", "min_sdk_version") +load("@rules_android//rules:android_platforms_transition.bzl", platforms_transition = "testing") +load("@rules_android//rules:desugar.bzl", "desugar") +load("@rules_android//rules:dex.bzl", "dex") +load("@rules_android//rules/android_binary:impl.bzl", "PROCESSORS") +load("@rules_android//android:rules.bzl", "android_binary") +load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo", "int_flag") +load("//build_defs/release:shipping.bzl", "ShippingExportInfo", "ShippingInfo") + +def _query_input_test_impl(ctx): + env = unittest.begin(ctx) + owner = "oliphaunt-query-ts" + key = owner + "/0.1.1/npm:@oliphaunt/ts-query" + suppliers = {key: { + "publication": {"product": owner, "version": "0.1.1"}, + "artifact": "npm:@oliphaunt/ts-query", + "file": {"path": "@oliphaunt_metadata//:held-query.tgz", "sha256": "a" * 64, "size": 123}, + }} + # Equal versions do not make unpublished bytes a completed supplier. + held = mobile_query_input(owner, "0.1.1", "0.1.1", "0.1.1", [], suppliers) + asserts.equals(env, "@oliphaunt_metadata//:held-query.tgz", held["archive"]) + asserts.equals(env, "completed-supplier", held["metadata"]["origin"]) + asserts.equals(env, "a" * 64, held["metadata"]["sourceSha256"]) + for selected in [[], [owner]]: + major = mobile_query_input(owner, "0.1.1", "1.0.0", "1.0.0", selected, suppliers) + asserts.equals(env, held, major) + stale = mobile_query_input(owner, "0.1.1", "0.1.1", "0.2.0", [owner], suppliers) + asserts.equals(env, held, stale) + rust = mobile_query_input(owner, "0.1.1", "0.1.1", "0.1.1", ["oliphaunt-query"], suppliers) + asserts.equals(env, held, rust) + prepared = mobile_query_input(owner, "0.1.1", "0.1.1", "0.1.1", [owner], suppliers) + asserts.equals(env, "//src/query/ts:npm", prepared["archive"]) + asserts.equals(env, "prepared-source", prepared["metadata"]["origin"]) + empty = mobile_query_input(owner, "0.1.1", "0.1.1", "0.1.1", [], {}) + asserts.equals(env, None, empty["archive"]) + asserts.equals(env, "Mobile app requires the genuine completed query supplier " + key, empty["error"]) + return unittest.end(env) + +_query_input_test = unittest.make(_query_input_test_impl) + +def _missing_query_test_impl(ctx): + env = analysistest.begin(ctx) + asserts.expect_failure(env, "Mobile app requires the genuine completed query supplier oliphaunt-query-ts/0.1.1/npm:@oliphaunt/ts-query") + return analysistest.end(env) + +_missing_query_test = analysistest.make(_missing_query_test_impl, expect_failure = True) + +def mobile_query_input_tests(): + _query_input_test(name = "mobile_query_input_test") + missing = mobile_query_input("oliphaunt-query-ts", "0.1.1", "0.1.1", "0.1.1", [], {}) + android_workspace_npm(name = "missing_query_subject", archive = missing["archive"], + error = missing["error"], package_name = missing["metadata"]["package"], + version = missing["metadata"]["version"], tags = ["manual"]) + _missing_query_test(name = "missing_query_test", target_under_test = ":missing_query_subject") + +def _android_min_sdk_test_impl(ctx): + env = analysistest.begin(ctx) + # Exercise the actual maintained provider reader, including its unchanged default. + for configured, expected in [(0, 23), (23, 23), (24, 24), (26, 26)]: + subject = struct(attr = struct(_min_sdk_version = {BuildSettingInfo: BuildSettingInfo(value = configured)})) + asserts.equals(env, expected, min_sdk_version.get(subject)) + for abi, platform in [("arm64-v8a", "arm64"), ("x86_64", "x86_64")]: + for minimum in [24, 26]: + configuration = android_app_configuration({}, struct(abi = abi, min_sdk_version = minimum)) + asserts.equals(env, minimum, configuration[str(Label("@rules_android//rules:min_sdk_version"))]) + asserts.equals(env, ["//build_defs/android:android_" + platform], configuration["//command_line_option:android_platforms"]) + asserts.equals(env, "opt", configuration["//command_line_option:compilation_mode"]) + # The maintained dependency transition preserves an incoming SDK + # rather than invoking its dormant clamp or lowering the setting. + settings = { + "//command_line_option:android_platforms": configuration["//command_line_option:android_platforms"], + "//command_line_option:platforms": ["//build_defs/native:linux_x86_64_glibc_2_28"], + min_sdk_version.SETTING: minimum, + } + for declared in [0, 24, 26]: + transitioned = platforms_transition.impl(settings, struct(min_sdk_version = declared)) + asserts.equals(env, minimum, transitioned[min_sdk_version.SETTING]) + asserts.equals(env, configuration["//command_line_option:android_platforms"], transitioned["//command_line_option:platforms"]) + # An authored minimum also propagates from an unconfigured root. + settings[min_sdk_version.SETTING] = 0 + transitioned = platforms_transition.impl(settings, struct(min_sdk_version = minimum)) + asserts.equals(env, minimum, transitioned[min_sdk_version.SETTING]) + + subject = analysistest.target_under_test(env) + cases = subject[_MinimumSdkCases].cases + flags = { + "Desugar": "--min_sdk_version", + "DexBuilder": "--min_sdk_version", + "DexMerger": "--min_sdk_version", + "AndroidDexer": "--min-sdk-version", + } + observed = [] + for action in analysistest.target_actions(env): + if action.mnemonic not in flags: + continue + output = action.outputs.to_list()[0] + case = [name for name in cases if name in output.path.split("/")][0] + minimum = cases[case] + flag = flags[action.mnemonic] + observed.append((case, action.mnemonic)) + if minimum: + asserts.equals(env, 1, len([arg for arg in action.argv if arg == flag])) + asserts.equals(env, str(minimum), action.argv[action.argv.index(flag) + 1]) + else: + asserts.false(env, flag in action.argv) + if action.mnemonic == "AndroidDexer": + asserts.false(env, "--min_sdk_version" in action.argv) + asserts.equals(env, sorted([(case, mnemonic) for case in cases for mnemonic in flags]), sorted(observed)) + return analysistest.end(env) + +_MinimumSdkCases = provider(fields = ["cases"]) + +def _android_dex_actions_impl(ctx): + tool = ctx.actions.declare_file(ctx.label.name + "/tool") + source = ctx.actions.declare_file(ctx.label.name + "/input.jar") + config = ctx.actions.declare_file(ctx.label.name + "/desugar.json") + ctx.actions.write(tool, "#!/bin/sh\nexit 1\n", is_executable = True) + ctx.actions.write(source, "analysis-only jar") + ctx.actions.write(config, "{}") + cases = {} + outputs = [] + for index, (configured, declared, expected) in enumerate([(0, 0, 0), (23, 0, 23), (24, 0, 24), (26, 0, 26), (24, 26, 26)]): + case = ctx.label.name + "_" + str(index) + subject = struct( + actions = ctx.actions, + attr = struct( + min_sdk_version = declared, + manifest_values = {"minSdkVersion": str(expected)} if expected else {}, + _min_sdk_version = {BuildSettingInfo: BuildSettingInfo(value = configured)}, + _java_toolchain = ctx.attr._java_toolchain, + ), + file = struct(manifest = None), + fragments = ctx.fragments, + label = struct(name = case), + var = ctx.var, + ) + manifest = PROCESSORS["ManifestProcessor"](subject).value + if manifest.processed_min_sdk_version != expected: + fail("Configured/declared minimum SDK did not reach the app manifest processor") + minimum = min_sdk_version.clamp(manifest.processed_min_sdk_version) + cases[case] = expected + desugared = ctx.actions.declare_file(case + "/desugared.jar") + incremental = ctx.actions.declare_file(case + "/incremental.dex.zip") + merged = ctx.actions.declare_file(case + "/merged.dex.zip") + monolithic = ctx.actions.declare_file(case + "/monolithic.dex.zip") + desugar.desugar(subject, input = source, output = desugared, classpath = depset(), + min_sdk_version = minimum, desugar_exec = tool, desugared_lib_config = config) + dex.dex(subject, input = desugared, output = incremental, min_sdk_version = minimum, dex_exec = tool) + dex.dex_merge(subject, inputs = [incremental], output = merged, min_sdk_version = minimum, dexmerger = tool) + dex.process_monolithic_dexing(subject, input = desugared, output = monolithic, + min_sdk_version = manifest.processed_min_sdk_version, dexbuilder = tool) + outputs.extend([desugared, incremental, merged, monolithic]) + return [DefaultInfo(files = depset(outputs)), _MinimumSdkCases(cases = cases)] + +_android_dex_actions = rule( + implementation = _android_dex_actions_impl, + attrs = {"_java_toolchain": attr.label(default = Label("@bazel_tools//tools/jdk:current_java_toolchain"))}, + fragments = ["android"], + toolchains = ["@bazel_tools//tools/jdk:toolchain_type"], +) + +_android_min_sdk_test = analysistest.make(_android_min_sdk_test_impl) + +_FinalDataFiles = provider(fields = ["files", "attributes", "abis"]) + +def _final_data_files_impl(_target, ctx): + inherited = [] + for name in ["apk", "deps", "assets", "aar"]: + dependencies = getattr(ctx.rule.attr, name, []) + if type(dependencies) != "list": + dependencies = [dependencies] if dependencies else [] + inherited += [dependency[_FinalDataFiles] for dependency in dependencies if _FinalDataFiles in dependency] + files, attributes, abis = [], [], [] + if ctx.rule.kind in ["android_final_aar", "android_app_runtime_assets"]: + names = ["source"] if ctx.rule.kind == "android_final_aar" else ["payload", "icu", "leaves"] + for name in names: + dependencies = getattr(ctx.rule.attr, name) + if type(dependencies) != "list": + dependencies = [dependencies] if dependencies else [] + files += [file for dependency in dependencies for file in dependency[DefaultInfo].files.to_list()] + attributes.append(name) + if ctx.rule.kind == "android_app_runtime_assets": + abis.append(ctx.rule.attr.abi) + return [_FinalDataFiles( + files = depset(files, transitive = [data.files for data in inherited]), + attributes = depset(attributes, transitive = [data.attributes for data in inherited]), + abis = depset(abis, transitive = [data.abis for data in inherited]), + )] + +_final_data_files = aspect(implementation = _final_data_files_impl, attr_aspects = ["apk", "deps", "assets", "aar"]) + +def _android_binary_min_sdk_test_impl(ctx): + env = analysistest.begin(ctx) + flags = {"AndroidDexer": "--min-sdk-version", "Desugar": "--min_sdk_version", "ValidateManifest": "--expected_min_sdk_version"} + observed = {} + for action in analysistest.target_actions(env): + if action.mnemonic in flags: + flag = flags[action.mnemonic] + asserts.equals(env, "26", action.argv[action.argv.index(flag) + 1]) + observed[action.mnemonic] = True + asserts.equals(env, sorted(flags), sorted(observed)) + # The existing Android qualifier already owns these apps and producers. + # Inspect their configured Files without adding any app/producer outputs to + # this analysis test's executable or runfiles. + producers = {file: True for package in ctx.attr.shipping[ShippingExportInfo].packages for file in package[ShippingInfo].files.to_list()} + producers.update({file: True for dependency in ctx.attr.shared_data for file in dependency[DefaultInfo].files.to_list()}) + data = [app[_FinalDataFiles] for app in ctx.attr.installed_apps] + asserts.equals(env, ["arm64-v8a", "x86_64"], sorted(depset(transitive = [item.abis for item in data]).to_list())) + asserts.equals(env, ["icu", "leaves", "payload", "source"], sorted(depset(transitive = [item.attributes for item in data]).to_list())) + files = depset(transitive = [item.files for item in data]).to_list() + asserts.true(env, bool(files), "installed Android apps must reach their actual final data") + for file in files: + asserts.true(env, file in producers, "installed Android final data differs from its original producer File: " + file.path) + return analysistest.end(env) + +_android_binary_min_sdk_test = analysistest.make( + _android_binary_min_sdk_test_impl, + config_settings = { + str(Label("@rules_android//rules:min_sdk_version")): 26, + "//command_line_option:android_platforms": [str(Label("//build_defs/android:android_x86_64"))], + }, + attrs = { + "installed_apps": attr.label_list(default = [Label("//src/examples/native/react-native-expo:" + name) for name in ["android_release", "android_release_x86_64"]], aspects = [_final_data_files]), + "shipping": attr.label(default = Label("//:native_android_shipping_export"), providers = [ShippingExportInfo]), + "shared_data": attr.label_list(default = [Label("//src/native/runtime:public_payload"), Label("//src/database-resources:icu_payload"), Label("//src/native/sdks/kotlin:android_maven_archive")]), + }, +) + +def _android_manifest_subject_impl(ctx): + PROCESSORS["ManifestProcessor"](ctx) + return [DefaultInfo()] + +_android_manifest_subject = rule( + implementation = _android_manifest_subject_impl, + attrs = { + "_min_sdk_version": attr.label(default = Label(":android_min_sdk_conflict_setting"), providers = [BuildSettingInfo]), + "min_sdk_version": attr.int(), + "manifest_values": attr.string_dict(), + "manifest": attr.label(allow_single_file = True), + }, +) + +def _android_min_sdk_conflict_test_impl(ctx): + env = analysistest.begin(ctx) + asserts.expect_failure(env, "Configured minimum SDK 26 exceeds authored min_sdk_version 24") + return analysistest.end(env) + +_android_min_sdk_conflict_test = analysistest.make( + _android_min_sdk_conflict_test_impl, + expect_failure = True, +) + +def android_app_configuration_tests(): + _android_dex_actions(name = "android_min_sdk_actions", tags = ["manual"]) + _android_min_sdk_test(name = "android_min_sdk_test", target_under_test = ":android_min_sdk_actions") + android_binary(name = "android_min_sdk_binary", manifest = "min-sdk-test.xml", custom_package = "dev.oliphaunt.min_sdk_test", + manifest_values = {"minSdkVersion": "26"}, multidex = "native", incremental_dexing = 0, tags = ["manual"]) + _android_binary_min_sdk_test(name = "android_binary_min_sdk_test", target_under_test = ":android_min_sdk_binary") + # Upstream's private setting remains private; this is a real local provider. + int_flag(name = "android_min_sdk_conflict_setting", build_setting_default = 26) + _android_manifest_subject(name = "android_min_sdk_conflict", min_sdk_version = 24, tags = ["manual"]) + _android_min_sdk_conflict_test(name = "android_min_sdk_conflict_test", target_under_test = ":android_min_sdk_conflict") diff --git a/build_defs/android/app.bzl b/build_defs/android/app.bzl new file mode 100644 index 000000000..bae57b702 --- /dev/null +++ b/build_defs/android/app.bzl @@ -0,0 +1,469 @@ +"""Declared Expo/RN generation edges; maintained Android/Kotlin/C++ rules compile.""" + +load("@aspect_rules_js//npm:providers.bzl", "NpmPackageInfo") +load("@rules_android//providers:providers.bzl", "AndroidSdkInfo", "ApkInfo") +load("@rules_cc//cc:defs.bzl", "cc_import", "cc_library") +load("@rules_cc//cc/common:cc_common.bzl", "cc_common") +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") +load("@rules_java//java/common:java_common.bzl", "java_common") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_file_action", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/extensions:mobile.bzl", "MobileExtensionInfo") +load("//build_defs/extensions:final_leaf.bzl", "ExtensionFinalLeafInfo") +load("@oliphaunt_metadata//:metadata.bzl", "EXTENSIONS") + +_DESCRIPTORS = {row["sql-name"]: row for row in EXTENSIONS.values()} + +def _module_stems(sql_names): + return {name: _DESCRIPTORS[name]["native-module-file"][:-3] if _DESCRIPTORS[name].get("native-module-file") else None for name in sql_names} + +_NODE = "@rules_nodejs//nodejs:toolchain_type" +_TAR = "@tar.bzl//tar/toolchain:type" +_HELPERS = [ + Label("//:tools/packaging/archive-directory.mts"), + Label("//:tools/packaging/portable-archive.mts"), +] + +def _input_path(ctx, file, runfiles): + if not runfiles: + return file.path + return file.short_path[3:] if file.short_path.startswith("../") else ctx.workspace_name + "/" + file.short_path + +def _sources(ctx, runfiles = False): + inputs, sources, names = [], [], {} + for target, destination in ctx.attr.sources.items(): + for file in target[DefaultInfo].files.to_list(): + relative = destination + if not destination or destination.endswith("/"): + prefix = target.label.package + "/" + if not file.short_path.startswith(prefix): + fail("App source group must retain its declared package path: " + file.short_path) + relative += file.short_path[len(prefix):] + if relative in names: + fail("Duplicate app source destination " + relative) + names[relative] = True + inputs.append(file) + sources.append({"source": _input_path(ctx, file, runfiles), "destination": relative}) + return sources, inputs + +def _node_inputs(ctx, runfiles = False): + if sorted(ctx.attr.package_inputs.values()) != sorted(ctx.attr.package_identities.keys()): + fail("App packages must cover their exact conventional lock closure") + packages, inputs = {}, [] + for target, identity in ctx.attr.package_inputs.items(): + package = target[NpmPackageInfo] + row = json.decode(ctx.attr.package_identities[identity]) + if row["package"] != package.package or row["version"] != package.version: + fail("App package identity differs from the canonical acquisition " + identity) + packages[identity] = row | {"source": _input_path(ctx, package.src, runfiles)} + inputs.append(package.src) + roots = dict(ctx.attr.package_roots) + for target, identity in ctx.attr.workspace_inputs.items(): + package = target[NpmPackageInfo] + row = json.decode(ctx.attr.workspace_identities[identity]) + if row["package"] != package.package or row["version"] != package.version: + fail("App workspace package differs from its source artifact " + identity) + if identity in packages: + fail("App workspace package collides with an acquired package " + identity) + packages[identity] = row | {"source": _input_path(ctx, package.src, runfiles), "local": True, "integrity": ""} + roots[package.package] = identity + inputs.append(package.src) + sources, source_files = _sources(ctx, runfiles) + node = ctx.toolchains[_NODE].nodeinfo + tar = ctx.toolchains[_TAR] + return {"sources": sources, "packages": packages, "roots": roots, "node": _input_path(ctx, node.node, runfiles), + "tar": _input_path(ctx, tar.tarinfo.binary, runfiles), "tarEnvironment": tar.tarinfo.default_env}, inputs + source_files + [node.node] + tar.default.files.to_list() + +app_node_inputs = _node_inputs + +def _action(ctx, operation, specification, inputs, outputs, mnemonic, tools = []): + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode(specification) + "\n") + bun_file_action(ctx, entry_point = ctx.file._runner, + arguments = [operation, spec.path], + inputs = inputs + [spec, ctx.file._runner] + ctx.files._helpers, + source_files = [ctx.file._runner] + ctx.files._helpers, + outputs = outputs, tools = tools, + execution_requirements = {"block-network": "1"}, mnemonic = mnemonic) + +_RUNNER = { + "_runner": attr.label(default = Label("//build_defs/android:app.mts"), allow_single_file = True), + "_helpers": attr.label_list(default = _HELPERS, allow_files = True), +} +_NODE_INPUTS = dict(_RUNNER, **{ + "sources": attr.label_keyed_string_dict(allow_files = True, mandatory = True), + "package_inputs": attr.label_keyed_string_dict(providers = [NpmPackageInfo], mandatory = True), + "package_identities": attr.string_dict(mandatory = True), + "package_roots": attr.string_dict(mandatory = True), + "workspace_inputs": attr.label_keyed_string_dict(providers = [NpmPackageInfo]), + "workspace_identities": attr.string_dict(), +}) + +APP_NODE_INPUT_ATTRS = _NODE_INPUTS + +def _autolinking_test_impl(ctx): + specification, inputs = _node_inputs(ctx, runfiles = True) + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode(specification | {"icuArchive": _input_path(ctx, ctx.file.icu_archive, True)}) + "\n") + helpers = ctx.files._helpers + [ctx.file._fixture] + return bun_test_entrypoint(ctx, ctx.file._runner, ["autolinking-test", spec], + inputs + [spec, ctx.file.icu_archive, ctx.file._runner] + helpers, + source_files = [ctx.file._runner] + helpers, + runfiles_environment = ["OLIPHAUNT_BAZEL_RUNFILES"]) + +_expo_autolinking_test = rule(implementation = _autolinking_test_impl, test = True, + toolchains = BUN_SOURCE_TOOLCHAINS + [_NODE, _TAR], + attrs = _NODE_INPUTS | BUN_TEST_ENTRYPOINT_ATTRS | { + "icu_archive": attr.label(mandatory = True, allow_single_file = [".tgz"]), + "_fixture": attr.label(default = Label("//src/native/sdks/react-native:tools/icu-autolinking-fixture.mts"), allow_single_file = True), + }) + +def expo_autolinking_test(name, **kwargs): + _expo_autolinking_test(name = name, args = bun_test_entrypoint_args(name), size = "medium", **kwargs) + +def _codegen_impl(ctx): + specification, inputs = _node_inputs(ctx) + schema = ctx.actions.declare_file(ctx.label.name + "/schema.json") + java = ctx.actions.declare_file(ctx.label.name + "/generated.srcjar") + native = ctx.actions.declare_directory(ctx.label.name + "/cpp") + headers = ctx.actions.declare_directory(ctx.label.name + "/include") + _action(ctx, "codegen", specification | { + "libraryName": ctx.attr.library_name, + "javaPackageName": ctx.attr.java_package_name, + "specs": ctx.attr.specs, + "schema": schema.path, "javaSources": java.path, + "nativeSources": native.path, "nativeHeaders": headers.path, + }, inputs, [schema, java, native, headers], "ReactNativeAndroidCodegen") + return [DefaultInfo(files = depset([java])), OutputGroupInfo( + schema = depset([schema]), java = depset([java]), cpp = depset([native]), headers = depset([headers]))] + +react_native_android_codegen = rule( + implementation = _codegen_impl, toolchains = BUN_SOURCE_TOOLCHAINS + [_NODE, _TAR], + attrs = dict(_NODE_INPUTS, **{ + "library_name": attr.string(mandatory = True), + "java_package_name": attr.string(mandatory = True), + "specs": attr.string_list(mandatory = True), + }), +) + +def _project_impl(ctx): + specification, inputs = _node_inputs(ctx) + manifest = ctx.actions.declare_file(ctx.label.name + "/AndroidManifest.xml") + java = ctx.actions.declare_file(ctx.label.name + "/app.srcjar") + resources = ctx.actions.declare_directory(ctx.label.name + "/res") + project = ctx.actions.declare_file(ctx.label.name + "/project.json") + registry = ctx.actions.declare_file(ctx.label.name + "/expo-registry.srcjar") + cpp = ctx.actions.declare_directory(ctx.label.name + "/native-cpp") + headers = ctx.actions.declare_directory(ctx.label.name + "/native-headers") + assets = ctx.actions.declare_directory(ctx.label.name + "/expo-assets") + autolinking = ctx.actions.declare_file(ctx.label.name + "/autolinking.json") + keystore = ctx.actions.declare_file(ctx.label.name + "/debug.keystore") + _action(ctx, "project", specification | { + "manifest": manifest.path, "javaSources": java.path, "resources": resources.path, + "project": project.path, + "expoRegistry": registry.path, "nativeSources": cpp.path, "nativeHeaders": headers.path, + "expoAssets": assets.path, "autolinking": autolinking.path, "keystore": keystore.path, + }, inputs, [manifest, java, resources, project, registry, cpp, headers, assets, autolinking, keystore], "ExpoAndroidProjectSources") + return [DefaultInfo(files = depset([java])), OutputGroupInfo( + manifest = depset([manifest]), java = depset([java]), resources = depset([resources]), project = depset([project]), + expo_registry = depset([registry]), native_cpp = depset([cpp]), native_headers = depset([headers]), + expo_assets = depset([assets]), autolinking = depset([autolinking]), keystore = depset([keystore]))] + +expo_android_project = rule(implementation = _project_impl, attrs = _NODE_INPUTS, + toolchains = BUN_SOURCE_TOOLCHAINS + [_NODE, _TAR]) + +def _bundle_impl(ctx): + specification, inputs = _node_inputs(ctx) + bundle = ctx.actions.declare_file(ctx.label.name + "/index.android.bundle") + source_map = ctx.actions.declare_file(ctx.label.name + "/index.android.bundle.map") + resources = ctx.actions.declare_directory(ctx.label.name + "/res") + assets = ctx.actions.declare_directory(ctx.label.name + "/assets") + _action(ctx, "bundle", specification | { + "entry": ctx.attr.entry, "environment": ctx.attr.environment, + "selectedExtensions": ctx.attr.selected_extensions, "catalogProfile": ctx.attr.catalog_profile, + "profileProbe": ctx.file.catalog_profile_probe.path, + "bundle": bundle.path, "sourceMap": source_map.path, + "resources": resources.path, "assets": assets.path, + }, inputs + [ctx.file.catalog_profile_probe], [bundle, source_map, resources, assets], "ExpoAndroidHermesBundle") + return [DefaultInfo(files = depset([bundle])), OutputGroupInfo( + bundle = depset([bundle]), source_map = depset([source_map]), resources = depset([resources]), assets = depset([assets]))] + +expo_android_bundle = rule( + implementation = _bundle_impl, toolchains = BUN_SOURCE_TOOLCHAINS + [_NODE, _TAR], + attrs = dict(_NODE_INPUTS, **{ + "entry": attr.string(default = "index.ts"), "environment": attr.string_dict(), + "selected_extensions": attr.string_list(mandatory = True), + "catalog_profile": attr.string(mandatory = True, values = ["standard", "icu"]), + "catalog_profile_probe": attr.label(mandatory = True, allow_single_file = [".json"]), + }), +) + +def _prefab_impl(ctx): + headers = ctx.actions.declare_directory(ctx.label.name + "/include") + library = ctx.actions.declare_file(ctx.label.name + "/lib" + ctx.attr.module + ".so") + _action(ctx, "prefab", {"aar": ctx.file.aar.path, "abi": ctx.attr.abi, "module": ctx.attr.module, + "headers": headers.path, "library": library.path}, + [ctx.file.aar], [headers, library], "AndroidPrefabAbi") + return [DefaultInfo(files = depset([library])), OutputGroupInfo(headers = depset([headers]), library = depset([library]))] + +_prefab = rule(implementation = _prefab_impl, toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(_RUNNER, **{"aar": attr.label(allow_single_file = [".aar"], mandatory = True), + "abi": attr.string(mandatory = True, values = ["arm64-v8a", "x86_64"]), + "module": attr.string(mandatory = True)})) + +def android_prefab_import(name, aar, abi, module, **kwargs): + """Expose the exact Maven prefab ABI through maintained C++ imports.""" + _prefab(name = name + "_files", aar = aar, abi = abi, module = module, **kwargs) + native.filegroup(name = name + "_headers", srcs = [":" + name + "_files"], output_group = "headers") + native.filegroup(name = name + "_library", srcs = [":" + name + "_files"], output_group = "library") + cc_import(name = name + "_import", shared_library = ":" + name + "_library", hdrs = [":" + name + "_headers"], **kwargs) + android_header_tree(name = name + "_includes", headers = ":" + name + "_headers", quote_includes = False, **kwargs) + cc_library(name = name, deps = [":" + name + "_import", ":" + name + "_includes"], **kwargs) + +def _header_tree_impl(ctx): + headers = ctx.files.headers + if len(headers) != 1 or not headers[0].is_directory: + fail("Generated Android headers need one declared header tree") + paths = [headers[0].path + ("/" + suffix if suffix else "") for suffix in ctx.attr.include_suffixes] + context = cc_common.create_compilation_context(headers = depset(headers), + system_includes = depset(paths), quote_includes = depset(paths) if ctx.attr.quote_includes else depset()) + return [DefaultInfo(files = depset(headers)), CcInfo(compilation_context = context)] + +android_header_tree = rule(implementation = _header_tree_impl, attrs = { + "headers": attr.label(mandatory = True, allow_files = True), + "include_suffixes": attr.string_list(default = [""]), + "quote_includes": attr.bool(default = True), +}) + +def _source_headers_impl(ctx): + prefix = ctx.label.workspace_root + ("/" if ctx.label.workspace_root else "") + ctx.label.package + paths = [(prefix + "/" if prefix else "") + directory for directory in ctx.attr.include_dirs] + return [CcInfo(compilation_context = cc_common.create_compilation_context( + headers = depset(ctx.files.headers), includes = depset(paths)))] + +android_source_headers = rule(implementation = _source_headers_impl, attrs = { + "headers": attr.label_list(mandatory = True, allow_files = True), + "include_dirs": attr.string_list(mandatory = True), +}) + +def _aar_native_impl(ctx): + library = ctx.actions.declare_file(ctx.label.name + "/" + ctx.attr.library) + runtime = ctx.attr._java_runtime[java_common.JavaRuntimeInfo] + _action(ctx, "aar-native", {"aar": ctx.file.aar.path, "abi": ctx.attr.abi, + "library": ctx.attr.library, "output": library.path, "jar": runtime.java_home + "/bin/jar"}, + [ctx.file.aar] + runtime.files.to_list(), [library], "AndroidAarNativeAbi") + return [DefaultInfo(files = depset([library]))] + +android_aar_native = rule(implementation = _aar_native_impl, toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(_RUNNER, **{"aar": attr.label(mandatory = True, allow_single_file = [".aar"]), + "abi": attr.string(mandatory = True, values = ["arm64-v8a", "x86_64"]), + "library": attr.string(mandatory = True), + "_java_runtime": attr.label(default = Label("@bazel_tools//tools/jdk:current_java_runtime"), cfg = "exec", providers = [java_common.JavaRuntimeInfo])})) + +def _final_aar_impl(ctx): + if len(ctx.files.source) != 1: + fail("A final Android carrier must expose one File or Maven tree") + source = ctx.files.source[0] + output = ctx.actions.declare_file(ctx.label.name + ".aar") + if source.is_directory or ctx.attr.kind != "aar": + _action(ctx, "final-aar", {"source": source.path, "output": output.path, + "kind": ctx.attr.kind, "package": ctx.attr.package, "abi": ctx.attr.abi, "catalogProfile": ctx.attr.catalog_profile}, [source], [output], "AndroidFinalMavenAar") + else: + if source.extension != "aar": + fail("Installed Android classes must come from the actual final AAR") + ctx.actions.symlink(output = output, target_file = source) + return [DefaultInfo(files = depset([output]))] + +_ANDROID_MIN_SDK = str(Label("@rules_android//rules:min_sdk_version")) + +def _final_data_impl(settings, _attr): + # Final carriers are data from the same host-side producers exported by the + # Android request. Keep their Files out of the app's ABI and tool configs. + return { + "//command_line_option:platforms": [str(settings["//command_line_option:host_platform"])], + "//command_line_option:android_platforms": [], + "//command_line_option:Android configuration distinguisher": "main", + "//command_line_option:dynamic_mode": "default", + _ANDROID_MIN_SDK: 0, + } + +_final_data = transition(implementation = _final_data_impl, + inputs = ["//command_line_option:host_platform"], + outputs = ["//command_line_option:platforms", "//command_line_option:android_platforms", + "//command_line_option:Android configuration distinguisher", "//command_line_option:dynamic_mode", _ANDROID_MIN_SDK]) + +android_final_aar = rule(implementation = _final_aar_impl, toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(_RUNNER, **{"source": attr.label(mandatory = True, allow_files = True, cfg = _final_data), + "kind": attr.string(default = "aar", values = ["aar", "runtime", "seed"]), + "catalog_profile": attr.string(default = "standard", values = ["standard", "icu"]), + "package": attr.string(), "abi": attr.string(default = "", values = ["", "arm64-v8a", "x86_64"]), + "_allowlist_function_transition": attr.label(default = Label("@bazel_tools//tools/allowlists/function_transition_allowlist"))})) + +def mobile_query_input(owner, requirement, source_version, final_version, selected_products, suppliers): + """Admit the prepared TS owner, otherwise retain its genuine completed dependency.""" + package = "@oliphaunt/ts-query" + if owner in selected_products and source_version == final_version and source_version == requirement: + return {"archive": "//src/query/ts:npm", "metadata": { + "package": package, "version": source_version, "dependencies": {}, "origin": "prepared-source"}} + key = owner + "/" + requirement + "/npm:" + package + if key not in suppliers: + return {"archive": None, "metadata": {"package": package, "version": requirement, "dependencies": {}}, + "error": "Mobile app requires the genuine completed query supplier " + key} + supplier = suppliers[key] + if supplier["publication"]["product"] != owner or supplier["publication"]["version"] != requirement or supplier["artifact"] != "npm:" + package: + return {"archive": None, "metadata": {"package": package, "version": requirement, "dependencies": {}}, + "error": "Mobile query supplier differs from the conventional owner requirement " + key} + return {"archive": supplier["file"]["path"], "metadata": { + "package": package, "version": requirement, "dependencies": {}, "origin": "completed-supplier", + "sourceSha256": supplier["file"]["sha256"], "sourceSize": supplier["file"]["size"]}} + +def _exec_npm_impl(ctx): + if ctx.attr.error: + fail(ctx.attr.error) + if not ctx.file.archive: + fail("App npm input requires one actual source or completed archive File") + return [DefaultInfo(files = depset([ctx.file.archive])), + NpmPackageInfo(package = ctx.attr.package_name, version = ctx.attr.version, + src = ctx.file.archive, npm_package_store_infos = depset())] + +android_workspace_npm = rule(implementation = _exec_npm_impl, attrs = { + "archive": attr.label(allow_single_file = [".tgz"], cfg = "exec"), + "error": attr.string(), + "package_name": attr.string(mandatory = True), "version": attr.string(mandatory = True), +}) + +def _link_receipt_impl(ctx): + members, inputs = [], [ctx.file.library, ctx.file.registry] + for target in ctx.attr.members: + member = target[MobileExtensionInfo] + members.append({"archive": member.archive.path, "registration": member.registration.path}) + inputs += [member.archive, member.registration] + nm = [file for file in ctx.files._nm if file.basename == "llvm-nm"] + if len(nm) != 1: + fail("Static extension proof needs the actual pinned NDK nm tool") + output = ctx.actions.declare_file(ctx.label.name + ".json") + _action(ctx, "extension-receipt", {"library": ctx.file.library.path, "registry": ctx.file.registry.path, + "members": members, "selectedExtensions": ctx.attr.selected_extensions, "moduleStems": _module_stems(ctx.attr.selected_extensions), "abi": ctx.attr.abi, "nm": nm[0].path, "output": output.path}, + inputs + ctx.files._nm, [output], "AndroidSelectedStaticExtensionLink") + return [DefaultInfo(files = depset([output]))] + +android_extension_receipt = rule(implementation = _link_receipt_impl, toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(_RUNNER, **{ + "library": attr.label(mandatory = True, allow_single_file = True), + "registry": attr.label(mandatory = True, allow_single_file = [".c"]), + "members": attr.label_list(mandatory = True, providers = [MobileExtensionInfo]), + "selected_extensions": attr.string_list(mandatory = True), + "abi": attr.string(mandatory = True, values = ["arm64-v8a", "x86_64"]), + "_nm": attr.label(default = Label("@android_ndk//:nm"), cfg = "exec", allow_files = True), + })) + +_STATIC_CARRIER_HELPERS = _HELPERS + [ + Label("//build_defs/native/apple:static-carrier-consumer.mts"), + Label("//build_defs/native/apple:framework_helpers"), + Label("//src/native/sdks/swift:generator_sources"), +] + +def _runtime_assets_impl(ctx): + output = ctx.actions.declare_directory(ctx.label.name + "/assets") + if len(ctx.files.payload) != 1 or not ctx.files.payload[0].is_directory: + fail("App runtime assets need the actual declared native payload tree") + leaves, inputs = [], [] + target = "android-" + ctx.attr.abi + for dependency in ctx.attr.leaves: + leaf = dependency[ExtensionFinalLeafInfo] + if leaf.family != "native" or leaf.target != target or leaf.metadata["runtimeVersion"] != ctx.attr.version: + fail("App selected carrier differs from the declared Android ABI or native version") + members = leaf.metadata.get("members", [leaf.metadata]) + leaves.append({"product": leaf.product, "owner": leaf.owner, "version": leaf.version, "target": leaf.target, + "runtimeVersion": leaf.metadata["runtimeVersion"], "sqlNames": sorted([member["sqlName"] for member in members]), + "github": [file.path for file in leaf.github], "frozen": leaf.frozen.path}) + inputs += leaf.github + [leaf.frozen] + ([leaf.validation] if leaf.validation else []) + _action(ctx, "runtime-assets", {"leaves": leaves, "abi": ctx.attr.abi, "payload": ctx.files.payload[0].path, "formatter": ctx.executable._formatter.path, + "version": ctx.attr.version, "selectedExtensions": ctx.attr.selected_extensions, "moduleStems": _module_stems(ctx.attr.selected_extensions), "mobileStaticModules": ctx.attr.mobile_static_modules, + "icu": ctx.file.icu.path if ctx.file.icu else None, + "receipt": ctx.file.receipt.path, "output": output.path}, + ctx.files.payload + [ctx.file.receipt] + ctx.files.icu + inputs, [output], "ExpoSelectedRuntimeAssets", tools = [ctx.attr._formatter[DefaultInfo].files_to_run]) + return [DefaultInfo(files = depset([output]))] + +android_app_runtime_assets = rule(implementation = _runtime_assets_impl, toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(_RUNNER, **{ + "payload": attr.label(default = Label("//src/native/runtime:public_payload"), cfg = _final_data, allow_files = True), + "icu": attr.label(allow_single_file = True, cfg = _final_data), + "version": attr.string(mandatory = True), "selected_extensions": attr.string_list(mandatory = True), + "mobile_static_modules": attr.string_list(mandatory = True), "receipt": attr.label(mandatory = True, allow_single_file = [".json"]), + "abi": attr.string(mandatory = True, values = ["arm64-v8a", "x86_64"]), + "leaves": attr.label_list(mandatory = True, providers = [ExtensionFinalLeafInfo], cfg = _final_data), + "_helpers": attr.label_list(default = _STATIC_CARRIER_HELPERS, allow_files = True), + "_formatter": attr.label(default = Label("//src/native/runtime/packaging:resources"), cfg = "exec", executable = True), + "_allowlist_function_transition": attr.label(default = Label("@bazel_tools//tools/allowlists/function_transition_allowlist")), + })) + +def _jni_aar_impl(ctx): + libraries, inputs = [], [] + for target, destination in ctx.attr.libraries.items(): + physical = target[DefaultInfo].files.to_list() + if len(physical) != 1: + fail("JNI package needs one declared linked library " + str(target.label)) + libraries.append({"source": physical[0].path, "destination": destination}) + inputs += physical + output = ctx.actions.declare_file(ctx.label.name + ".aar") + _action(ctx, "jni-aar", {"libraries": libraries, "output": output.path, "package": ctx.attr.package}, + inputs, [output], "AndroidDeclaredJniEnvelope") + return [DefaultInfo(files = depset([output]))] + +android_jni_aar = rule(implementation = _jni_aar_impl, toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(_RUNNER, **{"libraries": attr.label_keyed_string_dict(allow_files = True, mandatory = True), + "package": attr.string(mandatory = True)})) + +def _apk_abi_impl(settings, attr): + platform = "//build_defs/android:android_" + ("arm64" if attr.abi == "arm64-v8a" else "x86_64") + return {"//command_line_option:android_platforms": [platform], "//command_line_option:compilation_mode": "opt", + _ANDROID_MIN_SDK: attr.min_sdk_version} + +_apk_abi = transition(implementation = _apk_abi_impl, inputs = [], + outputs = ["//command_line_option:android_platforms", "//command_line_option:compilation_mode", _ANDROID_MIN_SDK]) + +android_app_configuration = _apk_abi_impl + +def _verify_impl(ctx): + sdk = ctx.attr._sdk[AndroidSdkInfo] + compiled = ctx.attr.apk[0][ApkInfo] + apk = ctx.actions.declare_file(ctx.label.name + ".apk") + runtime = ctx.attr._java_runtime[java_common.JavaRuntimeInfo] + proof = ctx.actions.declare_file(ctx.label.name + ".json") + objdump = [file for file in ctx.files._elf_tools if file.basename == "llvm-objdump"] + if len(objdump) != 1: + fail("APK link proof needs the actual pinned NDK objdump tool") + _action(ctx, "verify", {"apk": apk.path, "unsignedApk": compiled.unsigned_apk.path, "keystore": ctx.file.keystore.path, "abi": ctx.attr.abi, + "zipalign": sdk.zip_align.executable.path, "apksigner": sdk.apk_signer.executable.path, + "aapt": sdk.aapt.executable.path, + "objdump": objdump[0].path, + "output": proof.path, "selectedExtensions": ctx.attr.selected_extensions, "moduleStems": _module_stems(ctx.attr.selected_extensions), + "catalogProfile": ctx.attr.catalog_profile, "profileProbe": ctx.file.catalog_profile_probe.path, + "expectedClasses": ctx.attr.expected_classes, + "environment": {"JAVA_HOME": runtime.java_home}}, + [compiled.unsigned_apk, ctx.file.keystore, ctx.file.catalog_profile_probe] + runtime.files.to_list() + ctx.files._elf_tools, [apk, proof], "ExpoAndroidApkProof", + tools = [sdk.zip_align, sdk.apk_signer, sdk.aapt]) + return [DefaultInfo(files = depset([apk, proof])), OutputGroupInfo(apk = depset([apk]), proof = depset([proof]))] + +android_apk_proof = rule( + implementation = _verify_impl, toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(_RUNNER, **{ + "apk": attr.label(providers = [ApkInfo], mandatory = True, cfg = _apk_abi), + "abi": attr.string(mandatory = True, values = ["arm64-v8a", "x86_64"]), + "min_sdk_version": attr.int(mandatory = True), + "selected_extensions": attr.string_list(mandatory = True), + "catalog_profile": attr.string(mandatory = True, values = ["standard", "icu"]), + "catalog_profile_probe": attr.label(mandatory = True, allow_single_file = [".json"]), + "expected_classes": attr.string_list(mandatory = True), + "_helpers": attr.label_list(default = _HELPERS + [ + Label("//src/native/runtime:tools/native-runtime-carrier-contract.mts"), + Label("//src/database-resources:contracts/native-manifest.mts"), + Label("//src/database-resources:contracts/contract.json"), + ], allow_files = True), + "keystore": attr.label(mandatory = True, allow_single_file = True, cfg = "exec"), + "_sdk": attr.label(default = Label("@oliphaunt_android_sdk//:sdk"), providers = [AndroidSdkInfo]), + "_java_runtime": attr.label(default = Label("@bazel_tools//tools/jdk:current_java_runtime"), cfg = "exec", providers = [java_common.JavaRuntimeInfo]), + "_elf_tools": attr.label(default = Label("@android_ndk//:tools"), cfg = "exec", allow_files = True), + "_allowlist_function_transition": attr.label(default = Label("@bazel_tools//tools/allowlists/function_transition_allowlist")), + }), +) diff --git a/build_defs/android/app.mts b/build_defs/android/app.mts new file mode 100644 index 000000000..a2b910ec8 --- /dev/null +++ b/build_defs/android/app.mts @@ -0,0 +1,1649 @@ +import assert from 'node:assert/strict'; +import { execFileSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + copyFileSync, + cpSync, + existsSync, + lstatSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + realpathSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { createDeterministicZip } from '../../tools/packaging/archive-directory.mts'; +import { + extractPortableArchiveTree, + readAndroidApkEntries, + readPortableArchiveEntries, +} from '../../tools/packaging/portable-archive.mts'; + +export type Source = { source: string; destination: string }; +export type NpmPackage = { + package: string; + version: string; + integrity: string; + source: string; + dependencies: Record; + local?: boolean; + origin?: string; + sourceSha256?: string; + sourceSize?: number; +}; +export type NodeInputs = { + packages: Record; + roots: Record; + sources: Source[]; + node: string; + tar: string; + tarEnvironment?: Record; +}; + +function member(name: string) { + assert( + name && + !path.isAbsolute(name) && + !/[\\\0]/u.test(name) && + name.split('/').every((part) => part && part !== '.' && part !== '..'), + `Unsafe declared Android app path ${name}`, + ); + return name; +} +function put(root: string, name: string, bytes: Buffer | string) { + const destination = path.join(root, member(name)); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, bytes, { mode: 0o644 }); +} +function packageName(name: string) { + assert(/^(?:@[a-z0-9._-]+\/)?[a-z0-9._-]+$/iu.test(name), `Invalid npm name ${name}`); + return name; +} + +/** Resolve only declared archives; package managers never run in app actions. */ +export function stageNodeInputs(root: string, inputs: NodeInputs) { + const stores: Record = {}; + const manifests: Record< + string, + { + name: string; + version: string; + dependencies?: Record; + optionalDependencies?: Record; + peerDependencies?: Record; + } + > = {}; + function requireVersion(name: string, id: string, requirement: string, parent: string) { + assert(stores[id], `Undeclared npm dependency ${name}/${id}`); + assert.equal(manifests[id].name, name, `npm dependency identity ${parent}/${name}`); + const range = requirement.startsWith('workspace:') + ? requirement.slice('workspace:'.length) + : requirement; + assert( + Bun.semver.satisfies(manifests[id].version, ['^', '~'].includes(range) ? '*' : range), + `npm dependency ${parent}/${name}@${manifests[id].version} does not satisfy ${requirement}`, + ); + } + for (const [id, row] of Object.entries(inputs.packages)) { + assert(/^[a-z0-9_]+$/iu.test(id), `Invalid npm package ID ${id}`); + assert( + row.local || /^sha512-[A-Za-z0-9+/]+=*$/u.test(row.integrity), + `Missing npm integrity ${id}`, + ); + const destination = path.join(root, '.packages', id, 'node_modules', packageName(row.package)); + const physical = realpathSync(row.source); + if (row.origin === 'completed-supplier') + assert( + row.sourceSha256 && row.sourceSize !== undefined, + `Missing completed npm File identity ${id}`, + ); + if (row.sourceSha256 !== undefined) { + assert(lstatSync(physical).isFile(), `Completed npm supplier must be an archive File ${id}`); + assert.match(row.sourceSha256, /^[a-f0-9]{64}$/u, `Invalid npm supplier SHA256 ${id}`); + const bytes = readFileSync(physical); + assert.equal(bytes.length, row.sourceSize, `npm supplier File size ${id}`); + assert.equal( + createHash('sha256').update(bytes).digest('hex'), + row.sourceSha256, + `npm supplier File SHA256 ${id}`, + ); + } + if (lstatSync(physical).isDirectory()) cpSync(row.source, destination, { recursive: true }); + else { + const archive = realpathSync(row.source); + if (!row.local) + assert.equal( + `sha512-${createHash('sha512').update(readFileSync(archive)).digest('base64')}`, + row.integrity, + `npm archive integrity ${id}`, + ); + mkdirSync(destination, { recursive: true }); + execFileSync( + realpathSync(inputs.tar), + [ + '--extract', + '--no-same-owner', + '--no-same-permissions', + '--strip-components', + '1', + '--file', + archive, + '--directory', + destination, + ], + { env: { ...process.env, ...inputs.tarEnvironment } }, + ); + } + const manifest = JSON.parse(readFileSync(path.join(destination, 'package.json'), 'utf8')); + assert.equal(manifest.name, row.package, `npm package identity ${id}`); + assert.equal(manifest.version, row.version, `npm package version ${id}`); + stores[id] = destination; + manifests[id] = manifest; + } + function link(directory: string, name: string, id: string) { + assert(stores[id], `Undeclared npm dependency ${name}/${id}`); + const destination = path.join(directory, 'node_modules', packageName(name)); + mkdirSync(path.dirname(destination), { recursive: true }); + symlinkSync(path.relative(path.dirname(destination), stores[id]), destination, 'dir'); + } + for (const [id, row] of Object.entries(inputs.packages)) { + for (const [name, dependency] of Object.entries(row.dependencies)) { + assert(stores[dependency], `Undeclared npm dependency ${name}/${dependency}`); + if (row.local) { + const requirement = + manifests[id].dependencies?.[name] ?? + manifests[id].optionalDependencies?.[name] ?? + manifests[id].peerDependencies?.[name]; + assert( + requirement, + `npm dependency absent from its conventional manifest ${row.package}/${name}`, + ); + requireVersion(name, dependency, requirement, row.package); + } + link(stores[id], name, dependency); + } + if (row.local) + for (const [name, requirement] of Object.entries(manifests[id].dependencies ?? {})) + requireVersion(name, row.dependencies[name], requirement, row.package); + } + for (const [name, id] of Object.entries(inputs.roots)) link(root, name, id); + const seen = new Set(); + for (const source of inputs.sources) { + assert(!seen.has(member(source.destination)), `Duplicate app input ${source.destination}`); + seen.add(source.destination); + const physical = realpathSync(source.source); + assert(lstatSync(physical).isFile(), `App input is not a file ${source.destination}`); + put(root, source.destination, readFileSync(physical)); + } + const manifestFile = path.join(root, 'package.json'); + if (existsSync(manifestFile)) { + const manifest = JSON.parse(readFileSync(manifestFile, 'utf8')); + for (const [name, id] of Object.entries(inputs.roots)) { + if (!inputs.packages[id].local || !manifest.dependencies?.[name]) continue; + requireVersion(name, id, manifest.dependencies[name], manifest.name); + if (manifest.dependencies[name].startsWith('workspace:')) + manifest.dependencies[name] = inputs.packages[id].version; + } + writeFileSync(manifestFile, JSON.stringify(manifest, null, 2) + '\n'); + } + return stores; +} +function invoke( + node: string, + script: string, + args: string[], + cwd: string, + environment: Record = {}, +) { + execFileSync(realpathSync(node), [script, ...args], { + cwd, + stdio: 'inherit', + env: { + PATH: path.dirname(realpathSync(node)), + CI: '1', + NODE_ENV: 'production', + EXPO_OFFLINE: '1', + EXPO_NO_TELEMETRY: '1', + EXPO_NO_GIT_STATUS: '1', + ...environment, + }, + }); +} +function invokeJson(node: string, script: string, args: string[], cwd: string) { + return JSON.parse( + execFileSync(realpathSync(node), [script, ...args], { + cwd, + encoding: 'utf8', + env: { + PATH: path.dirname(realpathSync(node)), + CI: '1', + NODE_ENV: 'production', + EXPO_OFFLINE: '1', + EXPO_NO_TELEMETRY: '1', + }, + maxBuffer: 16 * 1024 * 1024, + }), + ); +} + +/** Preserve the original packed SDK/ICU consumer checks with declared CLI Files. */ +export async function runAutolinkingConsumer(spec: NodeInputs & { icuArchive: string }) { + const runfiles = process.env.OLIPHAUNT_BAZEL_RUNFILES; + assert(runfiles && path.isAbsolute(runfiles), 'Autolinking requires declared runfiles'); + const input = (file: string) => path.join(runfiles, member(file)); + const inputs: NodeInputs = { + ...spec, + sources: spec.sources.map((source) => ({ ...source, source: input(source.source) })), + packages: Object.fromEntries( + Object.entries(spec.packages).map(([id, row]) => [id, { ...row, source: input(row.source) }]), + ), + node: input(spec.node), + tar: input(spec.tar), + }; + const fixture = fileURLToPath( + new URL( + '../../src/native/sdks/react-native/tools/icu-autolinking-fixture.mts', + import.meta.url, + ), + ); + await scratch(async (root) => { + const tools = path.join(root, 'tools'); + mkdirSync(tools); + const stores = stageNodeInputs(tools, inputs); + const work = path.join(root, 'fixture'); + mkdirSync(work); + const sdk = inputs.packages[inputs.roots['@oliphaunt/react-native']]; + assert(sdk, 'Autolinking requires the declared final React Native npm package'); + invoke( + process.execPath, + fixture, + [ + 'prepare-packed', + work, + realpathSync(sdk.source), + realpathSync(input(spec.icuArchive)), + tools, + ], + tools, + ); + const consumer = path.join(work, 'consumer'); + const bareCli = readFileSync(path.join(work, 'cli'), 'utf8'); + const expoAutolinker = + stores[inputs.packages[inputs.roots.expo].dependencies['expo-modules-autolinking']]; + assert(expoAutolinker, 'Declared Expo closure omitted its autolinker'); + const bin = JSON.parse(readFileSync(path.join(expoAutolinker, 'package.json'), 'utf8')).bin; + const expoCli = path.join( + expoAutolinker, + typeof bin === 'string' ? bin : bin['expo-modules-autolinking'], + ); + for (const kind of ['candidate', 'control']) { + if (kind === 'control') invoke(process.execPath, fixture, ['control', work], consumer); + for (const platform of kind === 'candidate' ? ['ios', 'android'] : ['ios']) { + for (const cli of [ + { + script: expoCli, + args: [ + 'react-native-config', + path.join(consumer, 'node_modules'), + '--project-root', + consumer, + '--platform', + platform, + '--json', + ], + }, + { script: bareCli, args: ['config', '--platform', platform] }, + ]) { + const output = path.join(work, 'config.json'); + writeFileSync( + output, + JSON.stringify(invokeJson(inputs.node, cli.script, cli.args, consumer)), + ); + invoke( + inputs.node, + '--experimental-strip-types', + [fixture, 'check', work, kind, platform, output], + consumer, + ); + } + } + } + console.log('Packed React Native and ICU Expo/bare autolinking passed'); + }); +} +function kotlinTemplate(file: string, name: string) { + const source = readFileSync(file, 'utf8'); + const match = source.match(new RegExp(`val ${name}\\s*=\\s*"""([\\s\\S]*?)"""`, 'u')); + assert(match, `Declared RN Gradle source no longer exposes ${name}`); + const lines = match[1].replace(/^\n|\n\s*$/gu, '').split('\n'); + const indent = Math.min( + ...lines.filter((line) => line.trim()).map((line) => line.match(/^\s*/u)![0].length), + ); + return lines.map((line) => line.slice(indent)).join('\n') + '\n'; +} +function javaName(name: string) { + assert( + /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)+$/u.test(name), + `Invalid Android classifier ${name}`, + ); + return name; +} +function expoRegistry(configuration: any, templateFile: string) { + const projects = configuration.modules.flatMap((module: any) => + module.projects.map((project: any) => ({ ...project, packageName: module.packageName })), + ); + const packages = projects + .filter((project: any) => project.packageName !== 'expo') + .flatMap((project: any) => project.packages ?? []); + const modules = projects.flatMap((project: any) => project.modules ?? []); + const services = projects.flatMap((project: any) => project.services ?? []); + const map = modules.map((module: any) => { + const classifier = + typeof module === 'string' ? module : (module.classifier ?? module.className); + assert(typeof classifier === 'string'); + return `${javaName(classifier)}::class.java to ${module.name ? JSON.stringify(module.name) : 'null'}`; + }); + const template = readFileSync(templateFile, 'utf8').match( + /return\s+"""([\s\S]*?)"""\.trimIndent\(\)/u, + )?.[1]; + assert(template, 'Declared Expo Gradle generator no longer exposes its package-list template'); + const values = [ + packages.map((name: string) => ` ${javaName(name)}()`).join(',\n'), + map.map((value) => ` ${value}`).join(',\n'), + services.map((name: string) => ` ${javaName(name)}::class.java`).join(',\n'), + ]; + const result = template + .replace('${namespace.get()}', 'expo.modules') + .replace(/\$\{\n[\s\S]*?\n \}/gu, () => { + assert(values.length, 'Expo registry template gained an unsupported projection'); + return values.shift()!; + }); + assert.equal(values.length, 0, 'Expo registry template lost a required projection'); + assert(!result.includes('${'), 'Expo registry retains an unresolved Kotlin interpolation'); + return result.trimEnd() + '\n'; +} + +async function generateAndroidAutolinking( + root: string, + stores: Record, + spec: NodeInputs & { + expoRegistry: string; + nativeSources: string; + nativeHeaders: string; + expoAssets: string; + autolinking: string; + }, +) { + const reactNative = stores[spec.roots['react-native']]; + const plugin = + stores[spec.packages[spec.roots['react-native']].dependencies['@react-native/gradle-plugin']]; + const expo = stores[spec.roots.expo]; + const expoCli = path.join(expo, 'bin/autolinking'); + const resolved = invokeJson( + spec.node, + expoCli, + ['resolve', '--platform', 'android', '--json'], + root, + ); + assert.deepEqual( + resolved.coreFeatures, + [], + 'App source/compiler graph must explicitly handle new Expo core features', + ); + assert.deepEqual( + resolved.extraDependencies, + [], + 'App source/compiler graph must explicitly handle new Expo native Maven inputs', + ); + const config = invokeJson( + spec.node, + expoCli, + ['react-native-config', '--platform', 'android', '--json'], + root, + ); + const packageName = javaName(config.project.android.packageName); + const dependencies = Object.values(config.dependencies) + .map((dependency: any) => dependency.platforms?.android) + .filter(Boolean) as any[]; + const tasks = path.join( + plugin, + 'react-native-gradle-plugin/src/main/kotlin/com/facebook/react/tasks', + ); + const instances = dependencies + .filter((dependency) => !dependency.isPureCxxDependency) + .map((dependency) => { + assert( + typeof dependency.packageImportPath === 'string' && + typeof dependency.packageInstance === 'string', + ); + const name = dependency.packageImportPath.match(/import\s+([\w.]+)\s*;/u)?.[1]; + assert(name, 'RN autolinking package import must name one Java classifier'); + const fqcn = javaName(name); + const short = name.split('.').at(-1)!; + return dependency.packageInstance + .replace(new RegExp(`\\b${short}\\b`, 'gu'), fqcn) + .replace( + /([^\w.])(BuildConfig|R)(\W)/gu, + (_match: string, prefix: string, name: string, suffix: string) => + `${prefix}${packageName}.${name}${suffix}`, + ); + }); + put( + root, + 'android/app/src/main/java/com/facebook/react/PackageList.java', + kotlinTemplate( + path.join(tasks, 'GeneratePackageListTask.kt'), + 'generatedFileContentsTemplate', + ).replace( + '{{ packageClassInstances }}', + instances.length ? ',\n ' + instances.join(',\n ') : '', + ), + ); + put( + root, + 'android/app/src/main/java/com/facebook/react/ReactNativeApplicationEntryPoint.java', + kotlinTemplate( + path.join(tasks, 'GenerateEntryPointTask.kt'), + 'generatedFileContentsTemplate', + ).replaceAll('{{packageName}}', packageName), + ); + const properties = readFileSync(path.join(root, 'android/gradle.properties'), 'utf8'); + const appManifest = JSON.parse(readFileSync(path.join(root, 'app.json'), 'utf8')).expo; + const fields = { + DEBUG: 'false', + IS_NEW_ARCHITECTURE_ENABLED: 'true', + IS_HERMES_ENABLED: 'true', + IS_EDGE_TO_EDGE_ENABLED: /^edgeToEdgeEnabled=true$/mu.test(properties) ? 'true' : 'false', + REACT_NATIVE_RELEASE_LEVEL: JSON.stringify('stable'), + VERSION_NAME: JSON.stringify(appManifest.version), + APPLICATION_ID: JSON.stringify(packageName), + BUILD_TYPE: JSON.stringify('release'), + VERSION_CODE: '1', + }; + put( + root, + `android/app/src/main/java/${packageName.replaceAll('.', '/')}/BuildConfig.java`, + `package ${packageName};\npublic final class BuildConfig {\n` + + Object.entries(fields) + .map( + ([name, value]) => + ` public static final ${value.startsWith('"') ? 'String' : name === 'VERSION_CODE' ? 'int' : 'boolean'} ${name} = ${value};`, + ) + .join('\n') + + '\n}\n', + ); + const registry = path.join(root, 'expo-registry'); + const expoAutolinker = + stores[spec.packages[spec.roots.expo].dependencies['expo-modules-autolinking']]; + assert(expoAutolinker); + put( + registry, + 'expo/modules/ExpoModulesPackageList.kt', + expoRegistry( + resolved, + path.join( + expoAutolinker, + 'android/expo-gradle-plugin/expo-autolinking-plugin/src/main/kotlin/expo/modules/plugin/GeneratePackagesListTask.kt', + ), + ), + ); + writeFileSync(spec.expoRegistry, await createDeterministicZip(registry)); + const libraries = dependencies.filter((dependency) => dependency.libraryName); + const includes: string[] = [], + javaProviders: string[] = [], + cxxProviders: string[] = [], + descriptors: string[] = []; + for (const dependency of libraries) { + const library = dependency.libraryName; + assert(/^[A-Za-z_][A-Za-z0-9_]*$/u.test(library)); + includes.push(`#include <${library}.h>`); + if (dependency.componentDescriptors?.length) { + includes.push(`#include `); + for (const descriptor of dependency.componentDescriptors) { + assert(/^[A-Za-z_][A-Za-z0-9_]*$/u.test(descriptor)); + descriptors.push( + `providerRegistry->add(concreteComponentDescriptorProvider<${descriptor}>());`, + ); + } + } + javaProviders.push( + `if (auto module = ${library}_ModuleProvider(moduleName, params)) return module;`, + ); + if (dependency.cxxModuleHeaderName) { + const header = dependency.cxxModuleHeaderName; + assert(/^[A-Za-z_][A-Za-z0-9_]*$/u.test(header)); + includes.push(`#include <${header}.h>`); + cxxProviders.push( + `if (moduleName == ${header}::kModuleName) return std::make_shared<${header}>(jsInvoker);`, + ); + } + } + const cppTask = path.join(tasks, 'GenerateAutolinkingNewArchitecturesFileTask.kt'); + put( + spec.nativeSources, + 'autolinking.cpp', + kotlinTemplate(cppTask, 'CPP_TEMPLATE') + .replace('{{ autolinkingCppIncludes }}', includes.join('\n')) + .replace('{{ autolinkingCppTurboModuleJavaProviders }}', javaProviders.join('\n')) + .replace('{{ autolinkingCppTurboModuleCxxProviders }}', cxxProviders.join('\n')) + .replace('{{ autolinkingCppComponentDescriptors }}', descriptors.join('\n')), + ); + put(spec.nativeHeaders, 'autolinking.h', kotlinTemplate(cppTask, 'hTemplate')); + const constantsId = Object.keys(spec.packages).find( + (id) => spec.packages[id].package === 'expo-constants', + ); + assert(constantsId); + mkdirSync(spec.expoAssets, { recursive: true }); + invoke( + spec.node, + path.join(stores[constantsId], 'scripts/getAppConfig.js'), + [root, path.resolve(spec.expoAssets)], + root, + ); + function normalized(value: any): any { + if (typeof value === 'string') return value.replaceAll(root + '/', ''); + if (Array.isArray(value)) return value.map(normalized); + if (value && typeof value === 'object') + return Object.fromEntries( + Object.entries(value).map(([key, child]) => [key, normalized(child)]), + ); + return value; + } + writeFileSync( + spec.autolinking, + JSON.stringify(normalized({ expo: resolved, reactNative: config }), null, 2) + '\n', + ); +} +async function scratch(operation: (root: string) => T | Promise) { + const root = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'oliphaunt-expo-')); + try { + return await operation(root); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} +function files(root: string, predicate = (_name: string) => true): Source[] { + if (!existsSync(root)) return []; + return readdirSync(root, { recursive: true }) + .map(String) + .sort() + .flatMap((name) => { + const file = path.join(root, name); + return lstatSync(file).isFile() && predicate(name) + ? [{ source: file, destination: name.replaceAll(path.sep, '/') }] + : []; + }); +} +async function sourceJar(root: string, sources: Source[], output: string) { + assert(sources.length, 'Android compiler input must contain source files'); + for (const source of sources) put(root, source.destination, readFileSync(source.source)); + writeFileSync(output, await createDeterministicZip(root)); +} + +export async function generateReactNativeCodegen( + spec: NodeInputs & { + libraryName: string; + javaPackageName: string; + specs: string[]; + schema: string; + javaSources: string; + nativeSources: string; + nativeHeaders: string; + }, +) { + return scratch(async (root) => { + const stores = stageNodeInputs(root, spec); + const codegenId = + spec.roots['@react-native/codegen'] ?? + spec.packages[spec.roots['react-native']]?.dependencies['@react-native/codegen']; + const codegen = stores[codegenId]; + const reactNative = stores[spec.roots['react-native']]; + assert(codegen && reactNative, 'RN codegen requires the declared RN/codegen packages'); + const schema = path.join(root, 'schema.json'); + const output = path.join(root, 'generated'); + invoke( + spec.node, + path.join(codegen, 'lib/cli/combine/combine-js-to-schema-cli.js'), + [schema, ...spec.specs.map((name) => path.join(root, member(name)))], + root, + ); + invoke( + spec.node, + path.join(reactNative, 'scripts/generate-specs-cli.js'), + [ + '--platform', + 'android', + '--schemaPath', + schema, + '--outputDir', + output, + '--libraryName', + spec.libraryName, + '--javaPackageName', + spec.javaPackageName, + ], + root, + ); + assert( + Object.keys(JSON.parse(readFileSync(schema, 'utf8')).modules).length, + 'RN codegen produced an empty schema', + ); + copyFileSync(schema, spec.schema); + await sourceJar(path.join(root, 'srcjar'), files(path.join(output, 'java')), spec.javaSources); + for (const [destination, predicate] of [ + [spec.nativeSources, (name: string) => /\.(?:c|cc|cpp)$/u.test(name)], + [spec.nativeHeaders, (name: string) => /\.(?:h|hpp)$/u.test(name)], + ] as const) { + mkdirSync(destination, { recursive: true }); + const selected = files(path.join(output, 'jni'), predicate); + assert(selected.length, `RN codegen omitted native files ${destination}`); + for (const source of selected) + put(destination, source.destination, readFileSync(source.source)); + } + }); +} + +/** Expo prebuild generates sources/resources, while Bazel owns compilation. */ +export async function generateExpoAndroidProject( + spec: NodeInputs & { + manifest: string; + javaSources: string; + resources: string; + project: string; + expoRegistry?: string; + nativeSources?: string; + nativeHeaders?: string; + expoAssets?: string; + autolinking?: string; + keystore?: string; + }, +) { + return scratch(async (root) => { + const stores = stageNodeInputs(root, spec); + const expo = stores[spec.roots.expo]; + assert( + expo && existsSync(path.join(expo, 'template.tgz')), + 'Declared Expo must carry its template', + ); + invoke( + spec.node, + path.join(expo, 'bin/cli'), + [ + 'prebuild', + '--platform', + 'android', + '--no-install', + '--template', + path.join(expo, 'template.tgz'), + ], + root, + ); + if (spec.expoRegistry) { + assert(spec.nativeSources && spec.nativeHeaders && spec.expoAssets && spec.autolinking); + await generateAndroidAutolinking( + root, + stores, + spec as Parameters[2], + ); + } + const app = path.join(root, 'android/app/src/main'); + copyFileSync(path.join(app, 'AndroidManifest.xml'), spec.manifest); + await sourceJar( + path.join(root, 'srcjar'), + files(path.join(app, 'java'), (name) => /\.(?:java|kt)$/u.test(name)), + spec.javaSources, + ); + cpSync(path.join(app, 'res'), spec.resources, { recursive: true }); + if (spec.keystore) copyFileSync(path.join(root, 'android/app/debug.keystore'), spec.keystore); + const declaredProject = JSON.parse(readFileSync(path.join(root, 'app.json'), 'utf8')); + assert.equal(typeof declaredProject.expo?.android?.package, 'string'); + writeFileSync( + spec.project, + JSON.stringify( + { + package: declaredProject.expo.android.package, + generatedGradle: readFileSync(path.join(root, 'android/app/build.gradle'), 'utf8'), + gradleProperties: readFileSync(path.join(root, 'android/gradle.properties'), 'utf8'), + reactNativeVersion: JSON.parse( + readFileSync(path.join(stores[spec.roots['react-native']], 'package.json'), 'utf8'), + ).version, + }, + null, + 2, + ) + '\n', + ); + }); +} + +export function mobileBundleEnvironment( + environment: Record, + selectedExtensions: readonly string[], + catalogProfile: string, + profileProbe: string, +): Record { + assert(['standard', 'icu'].includes(catalogProfile), 'Unsupported packaged catalog profile'); + assert.equal( + new Set(selectedExtensions).size, + selectedExtensions.length, + 'Duplicate packaged extensions', + ); + assert( + selectedExtensions.every((name) => /^[a-z][a-z0-9_-]*$/u.test(name)), + 'Invalid packaged extension', + ); + const probe = JSON.parse(readFileSync(profileProbe, 'utf8')); + assert.equal(probe.schema, 'oliphaunt-cluster-seed-profile-probe-v1'); + const row = probe.profiles?.[catalogProfile]; + assert(typeof row?.sql === 'string' && row.sql.length > 0, 'Missing catalog profile SQL'); + assert( + typeof row?.expected === 'string' && row.expected.length > 0, + 'Missing catalog profile expectation', + ); + const canonical = { + EXPO_PUBLIC_OLIPHAUNT_EXTENSIONS: selectedExtensions.join(','), + EXPO_PUBLIC_OLIPHAUNT_CATALOG_PROFILE: catalogProfile, + EXPO_PUBLIC_OLIPHAUNT_CATALOG_PROFILE_PROBE_SQL: row.sql, + EXPO_PUBLIC_OLIPHAUNT_CATALOG_PROFILE_PROBE_EXPECTED: row.expected, + }; + for (const [name, value] of Object.entries(canonical)) + assert( + environment[name] === undefined || environment[name] === value, + 'Conflicting packaged mobile environment ' + name, + ); + return { ...environment, ...canonical }; +} + +export async function bundleExpoAndroid( + spec: NodeInputs & { + entry: string; + bundle: string; + resources: string; + assets: string; + sourceMap: string; + environment: Record; + selectedExtensions: string[]; + catalogProfile: string; + profileProbe: string; + }, +) { + return scratch(async (root) => { + const stores = stageNodeInputs(root, spec); + const expo = stores[spec.roots.expo]; + const reactNativeId = spec.roots['react-native']; + const hermesId = spec.packages[reactNativeId]?.dependencies['hermes-compiler']; + assert( + expo && hermesId && spec.packages[hermesId]?.package === 'hermes-compiler', + 'Release bundling requires declared Expo and the RN-selected Hermes compiler', + ); + assert.equal( + spec.packages[hermesId].version, + JSON.parse(readFileSync(path.join(stores[reactNativeId], 'package.json'), 'utf8')) + .dependencies['hermes-compiler'], + 'Hermes compiler differs from the original RN dependency', + ); + const compiler = path.join(stores[hermesId], 'hermesc/linux64-bin/hermesc'); + assert(existsSync(compiler), 'Locked Hermes compiler has no Linux execution artifact'); + chmodSync(compiler, 0o755); + const bundle = path.join(root, 'index.android.bundle'); + const resources = path.join(root, 'res'); + const sourceMap = path.join(root, 'index.android.bundle.map'); + invoke( + spec.node, + path.join(expo, 'bin/cli'), + [ + 'export:embed', + '--platform', + 'android', + '--dev', + 'false', + '--entry-file', + member(spec.entry), + '--bundle-output', + bundle, + '--assets-dest', + resources, + '--sourcemap-output', + sourceMap, + ], + root, + { + ...mobileBundleEnvironment( + spec.environment, + spec.selectedExtensions, + spec.catalogProfile, + spec.profileProbe, + ), + TMPDIR: root, + }, + ); + const bytecode = path.join(root, 'index.android.hbc'); + execFileSync( + compiler, + ['-w', '-O', '-emit-binary', '-out', path.basename(bytecode), path.basename(bundle)], + { + cwd: root, + stdio: 'inherit', + }, + ); + const bytes = readFileSync(bytecode); + assertHermesBytecode(bytes); + copyFileSync(bytecode, spec.bundle); + copyFileSync(sourceMap, spec.sourceMap); + mkdirSync(spec.resources, { recursive: true }); + if (existsSync(resources)) cpSync(resources, spec.resources, { recursive: true }); + mkdirSync(spec.assets, { recursive: true }); + put(spec.assets, 'index.android.bundle', bytes); + }); +} + +export function extractPrefab(spec: { + aar: string; + abi: string; + module: string; + headers: string; + library: string; +}) { + assert(['arm64-v8a', 'x86_64'].includes(spec.abi)); + const entries = readPortableArchiveEntries(realpathSync(spec.aar), { format: 'zip' }); + const prefix = `prefab/modules/${member(spec.module)}`; + const abi = entries.get(`${prefix}/libs/android.${spec.abi}/abi.json`); + assert(abi?.isFile, `Missing prefab ABI metadata ${spec.module}/${spec.abi}`); + assert.equal(JSON.parse(Buffer.from(abi.data()).toString('utf8')).abi, spec.abi); + const shared = entries.get(`${prefix}/libs/android.${spec.abi}/lib${spec.module}.so`); + assert(shared?.isFile, `Missing prefab library ${spec.module}/${spec.abi}`); + writeFileSync(spec.library, shared.data()); + mkdirSync(spec.headers, { recursive: true }); + const selected = [...entries].filter( + ([name, entry]) => name.startsWith(`${prefix}/include/`) && entry.isFile, + ); + assert(selected.length, `Missing prefab headers ${spec.module}`); + for (const [name, entry] of selected) + put(spec.headers, name.slice(`${prefix}/include/`.length), Buffer.from(entry.data())); +} + +export async function extractAarNative(spec: { + aar: string; + abi: string; + library: string; + output: string; + jar: string; +}) { + assert(['arm64-v8a', 'x86_64'].includes(spec.abi)); + assert(/^lib[^/]+\.so$/u.test(spec.library)); + // The maintained JDK reader handles upstream AAR ZIP64 metadata. Extraction + // names one declared member, while final release archives retain strict ZIP. + await scratch((root) => { + const name = `jni/${spec.abi}/${spec.library}`; + execFileSync(realpathSync(spec.jar), ['xf', realpathSync(spec.aar), name], { + cwd: root, + stdio: 'inherit', + }); + assert(existsSync(path.join(root, name)), `Pinned Android AAR omitted ${name}`); + const bytes = readFileSync(path.join(root, name)); + assertAndroidElf(bytes, spec.abi); + writeFileSync(spec.output, bytes); + }); +} + +function finalMavenCarriers(root: string, extension: string): { source: string }[] { + const result: { source: string }[] = []; + const visit = (directory: string) => { + for (const entry of readdirSync(directory, { withFileTypes: true })) { + const file = path.join(directory, entry.name); + if (entry.isDirectory()) visit(file); + else { + // Bazel expands declared TreeArtifact inputs as directories of File + // transport links. Resolve those Files; archive members remain strict. + const physical = realpathSync(file); + assert( + lstatSync(physical).isFile(), + 'Canonical Maven Tree must contain regular File leaves', + ); + if (entry.name.endsWith(extension)) result.push({ source: physical }); + } + } + }; + visit(root); + return result; +} + +export async function extractFinalAar(spec: { + source: string; + output: string; + kind?: 'aar' | 'runtime' | 'seed'; + catalogProfile?: 'standard' | 'icu'; + package?: string; + abi?: string; +}) { + const extension = !spec.kind || spec.kind === 'aar' ? '.aar' : '.tar.gz'; + const source = realpathSync(spec.source); + const candidates = lstatSync(source).isDirectory() + ? finalMavenCarriers(source, extension) + : [{ source }]; + assert.equal( + candidates.length, + 1, + `A canonical Maven tree must contain exactly one final ${extension} carrier`, + ); + if (extension === '.aar') { + copyFileSync(candidates[0].source, spec.output); + return; + } + assert(spec.package && /^[a-z][A-Za-z0-9_]*(?:\.[A-Za-z0-9_]+)+$/u.test(spec.package)); + const entries = readPortableArchiveEntries(candidates[0].source); + const seedPrefix = spec.catalogProfile === 'icu' ? 'cluster-seed-icu/' : 'cluster-seed/'; + if (spec.kind === 'runtime') { + assert(spec.abi === 'arm64-v8a' || spec.abi === 'x86_64'); + const library = entries.get(`jni/${spec.abi}/liboliphaunt.so`); + assert(library?.isFile, 'Canonical Android runtime TAR omitted its selected JNI library'); + for (const [name, entry] of entries) + if (entry.isFile && name.startsWith('jni/')) { + assert( + name.startsWith(`jni/${spec.abi}/`), + `Canonical Android runtime TAR includes foreign ABI ${name}`, + ); + if (name.endsWith('.so')) assertAndroidElf(Buffer.from(entry.data()), spec.abi); + } + } else + assert( + entries.get(seedPrefix + 'manifest.properties')?.isFile, + 'Canonical Android seed TAR omitted its resource manifest', + ); + await scratch(async (root) => { + for (const [name, entry] of entries) + if (entry.isFile) + put( + root, + spec.kind === 'seed' && name.startsWith(seedPrefix) ? `assets/oliphaunt/${name}` : name, + Buffer.from(entry.data()), + ); + assert( + !existsSync(path.join(root, 'AndroidManifest.xml')) && + !existsSync(path.join(root, 'classes.jar')), + 'Maven TAR collides with the app-private Android envelope', + ); + put( + root, + 'AndroidManifest.xml', + `\n`, + ); + const classes = path.join(root, 'classes'); + mkdirSync(classes); + put(root, 'classes.jar', await createDeterministicZip(classes)); + rmSync(classes, { recursive: true }); + writeFileSync(spec.output, await createDeterministicZip(root)); + }); +} + +/** SQL-only extensions require resources; compiled extensions require exact original registrations. */ +export function assertAndroidStaticMembers( + selectedExtensions: string[], + moduleStems: Record, + members: { sqlName: string; nativeModuleStem: string }[], +) { + assert.deepEqual( + Object.keys(moduleStems).sort(), + [...selectedExtensions].sort(), + 'Canonical SQL cohort differs', + ); + const compiled = Object.keys(moduleStems) + .filter((name) => moduleStems[name] !== null) + .sort(); + assert.deepEqual( + members.map((row) => row.sqlName).sort(), + compiled, + 'Compiled registration cohort differs', + ); + for (const row of members) + assert.equal( + row.nativeModuleStem, + moduleStems[row.sqlName], + 'Canonical native module stem differs', + ); + return compiled.map((name) => moduleStems[name]!); +} + +export function extensionLinkReceipt(spec: { + library: string; + registry: string; + members: { archive: string; registration: string }[]; + selectedExtensions: string[]; + moduleStems: Record; + abi: string; + nm: string; + output: string; +}) { + const bytes = readFileSync(spec.library); + assertAndroidElf(bytes, spec.abi); + const result = Bun.spawnSync( + [realpathSync(spec.nm), '-D', '--defined-only', realpathSync(spec.library)], + { env: { LC_ALL: 'C', LANG: 'C' }, stdout: 'pipe', stderr: 'pipe' }, + ); + assert.equal(result.exitCode, 0, `declared llvm-nm failed: ${result.stderr.toString('utf8')}`); + const symbols = result.stdout.toString('utf8'); + const defined = new Set( + symbols + .split('\n') + .filter(Boolean) + .map((line) => line.trim().split(/\s+/u).at(-1)!), + ); + assert( + defined.has('liboliphaunt_selected_static_extensions'), + 'Linked static extension registry is absent', + ); + const members = spec.members + .map((member) => { + const row = JSON.parse(readFileSync(member.registration, 'utf8')); + for (const symbol of [ + row.magicSymbol, + row.initSymbol, + ...row.symbols.map((symbol: any) => symbol.address), + ].filter(Boolean)) + assert( + defined.has(symbol), + `Linked APK extension omitted actual archive definition ${row.sqlName}/${symbol}`, + ); + return { + sqlName: row.sqlName, + nativeModuleStem: row.nativeModuleStem, + archiveSha256: createHash('sha256').update(readFileSync(member.archive)).digest('hex'), + registrationSha256: createHash('sha256') + .update(readFileSync(member.registration)) + .digest('hex'), + definedSymbols: [ + row.magicSymbol, + row.initSymbol, + ...row.symbols.map((symbol: any) => symbol.address), + ] + .filter(Boolean) + .sort(), + }; + }) + .sort((a, b) => a.sqlName.localeCompare(b.sqlName)); + assertAndroidStaticMembers(spec.selectedExtensions, spec.moduleStems, members); + writeFileSync( + spec.output, + JSON.stringify( + { + schema: 'oliphaunt-android-static-extension-link-v1', + abi: spec.abi, + linkedSha256: createHash('sha256').update(bytes).digest('hex'), + registrySha256: createHash('sha256').update(readFileSync(spec.registry)).digest('hex'), + selectedExtensions: [...spec.selectedExtensions].sort(), + members, + }, + null, + 2, + ) + '\n', + ); +} + +export async function stageAndroidSelectedResources(spec: any, root: string) { + const { stageNativeStaticLeaf } = await import('../native/apple/static-carrier-consumer.mts'); + const receipt = JSON.parse(readFileSync(spec.receipt, 'utf8')); + assert.equal(receipt.abi, spec.abi, 'Selected resource ABI differs from its actual link proof'); + assert.deepEqual(receipt.selectedExtensions, [...spec.selectedExtensions].sort()); + assertAndroidStaticMembers(spec.selectedExtensions, spec.moduleStems, receipt.members); + const selected = new Set(spec.selectedExtensions); + const linkedMembers = new Map(receipt.members.map((row: any) => [row.sqlName, row])); + const covered = new Set(), + archives: string[] = []; + for (const [index, leaf] of spec.leaves.entries()) { + assert.equal(leaf.target, 'android-' + spec.abi); + const staged = stageNativeStaticLeaf( + leaf, + path.join(root, 'leaf-' + index), + spec.version, + leaf.target, + ); + const frozen = JSON.parse(readFileSync(staged.output, 'utf8')); + for (const row of frozen.extensions ?? [frozen]) { + if (!selected.has(row.sqlName)) continue; + assert.equal( + row.nativeModuleStem, + spec.moduleStems[row.sqlName], + 'Frozen native module stem differs', + ); + assert(!covered.has(row.sqlName), 'Repeated selected carrier member'); + covered.add(row.sqlName); + const assets = row.assets.filter((asset: any) => asset.kind === 'runtime'); + assert.equal(assets.length, 1, 'Selected member must have one exact runtime archive'); + const archivePath = realpathSync(assets[0].path); + const linked: any = linkedMembers.get(row.sqlName); + if (linked) { + const entries = readPortableArchiveEntries(archivePath); + const archive = entries.get( + `mobile-static/${leaf.target}/extensions/${linked.nativeModuleStem}/liboliphaunt_extension_${linked.nativeModuleStem}.a`, + ); + assert(archive?.isFile, 'Selected resource carrier lacks its linked static archive'); + assert.equal( + createHash('sha256').update(archive.data()).digest('hex'), + linked.archiveSha256, + 'Selected carrier static archive differs from actual app link', + ); + } + archives.push(archivePath); + } + } + assert.deepEqual( + [...covered].sort(), + [...spec.selectedExtensions].sort(), + 'Selected resource carriers differ from the linked cohort', + ); + return archives; +} + +export async function prepareAppRuntimeAssets(spec: { + payload: string; + abi: string; + leaves: any[]; + formatter: string; + version: string; + selectedExtensions: string[]; + moduleStems: Record; + mobileStaticModules: string[]; + icu?: string; + receipt: string; + output: string; +}) { + const { finalizeNativeRuntimeCarrier } = await import( + '../../src/native/runtime/tools/finalize-native-runtime-carrier.mts' + ); + return scratch(async (root) => { + const receipt = JSON.parse(readFileSync(spec.receipt, 'utf8')); + const modules = assertAndroidStaticMembers( + spec.selectedExtensions, + spec.moduleStems, + receipt.members, + ); + assert.deepEqual( + [...spec.mobileStaticModules].sort(), + modules.sort(), + 'Selected native modules differ', + ); + assert.deepEqual(receipt.selectedExtensions, [...spec.selectedExtensions].sort()); + const icu = path.join(root, 'icu'); + if (spec.icu) extractPortableArchiveTree(realpathSync(spec.icu), icu); + const stage = path.join(root, 'resources'); + const archives = await stageAndroidSelectedResources(spec, root); + const identity = createHash('sha256').update(readFileSync(spec.receipt)).digest('hex'); + execFileSync( + realpathSync(spec.formatter), + [ + '--output', + stage, + '--liboliphaunt-native-version', + spec.version, + '--extension-target', + 'android-' + spec.abi, + '--runtime-cache-identity', + `android-app-${identity}`, + '--require-mobile-static-registry', + ...(spec.icu ? ['--runtime-feature', 'icu'] : []), + ...archives.flatMap((archive) => ['--prebuilt-extension', archive]), + ...spec.selectedExtensions.flatMap((name) => ['--extension', name]), + ...spec.mobileStaticModules.flatMap((name) => ['--mobile-static-module', name]), + ], + { + cwd: root, + stdio: 'inherit', + env: { + HOME: root, + TMPDIR: root, + LC_ALL: 'C', + LANG: 'C', + OLIPHAUNT_INSTALL_DIR: path.join(realpathSync(spec.payload), 'runtime'), + OLIPHAUNT_EMBEDDED_MODULE_DIR: path.join(realpathSync(spec.payload), 'lib/modules'), + OLIPHAUNT_RUNTIME_CACHE_DIR: path.join(root, 'cache'), + ...(spec.icu ? { OLIPHAUNT_ICU_DATA_DIR: path.join(icu, 'share/icu') } : {}), + }, + }, + ); + const closure = path.join(stage, 'oliphaunt'); + put(closure, 'static-registry/link-receipt.json', readFileSync(spec.receipt)); + finalizeNativeRuntimeCarrier(closure, 'android-datum64'); + cpSync(closure, path.join(spec.output, 'oliphaunt'), { recursive: true }); + }); +} + +export async function assertAndroidRuntimeManifest(bytes: Buffer) { + const { bindNativeRuntimeResourceManifest } = await import( + '../../src/native/runtime/tools/native-runtime-carrier-contract.mts' + ); + assert( + bytes.equals(bindNativeRuntimeResourceManifest(bytes, 'android-datum64')), + 'Android app runtime manifest must be canonical for android-datum64', + ); +} + +export async function nativeLibrariesAar(spec: { + libraries: Source[]; + output: string; + package: string; +}) { + return scratch(async (root) => { + assert(/^[a-z][A-Za-z0-9_]*(?:\.[A-Za-z0-9_]+)+$/u.test(spec.package)); + assert(spec.libraries.length, 'JNI carrier cannot be empty'); + const seen = new Set(); + for (const file of spec.libraries) { + assert(/^jni\/(?:arm64-v8a|x86_64)\/lib[^/]+\.so$/u.test(file.destination)); + assert(!seen.has(file.destination), `Duplicate JNI library ${file.destination}`); + seen.add(file.destination); + const bytes = readFileSync(file.source); + assertAndroidElf(bytes, file.destination.includes('/arm64-v8a/') ? 'arm64-v8a' : 'x86_64'); + put(root, file.destination, bytes); + } + put( + root, + 'AndroidManifest.xml', + `\n`, + ); + const classes = path.join(root, 'classes'); + mkdirSync(classes); + put(root, 'classes.jar', await createDeterministicZip(classes)); + rmSync(classes, { recursive: true }); + writeFileSync(spec.output, await createDeterministicZip(root)); + }); +} + +export function assertHermesBytecode(bytes: Buffer) { + assert( + bytes.length > 128 && bytes.readBigUInt64LE() === 0x1f1903c103bc1fc6n, + 'Release APK must contain actual Hermes bytecode', + ); + assert.equal(bytes.readUInt32LE(32), bytes.length, 'Hermes bytecode is truncated'); + assert.equal( + createHash('sha1').update(bytes.subarray(0, -20)).digest('hex'), + bytes.subarray(-20).toString('hex'), + 'Hermes bytecode checksum differs', + ); +} +export function assertAndroidElf(bytes: Buffer, abi: string) { + assert(bytes.length > 64 && bytes.subarray(0, 4).equals(Buffer.from([0x7f, 0x45, 0x4c, 0x46]))); + assert.equal(bytes[4], 2, 'Android APK JNI libraries must use ELF64'); + assert.equal(bytes[5], 1, 'Android ELF must be little endian'); + assert.equal( + bytes.readUInt16LE(18), + abi === 'arm64-v8a' ? 183 : 62, + 'Android ELF machine differs', + ); + const headerSize = bytes.readUInt16LE(54); + const count = bytes.readUInt16LE(56); + const offset = Number(bytes.readBigUInt64LE(32)); + assert( + headerSize >= 56 && offset + headerSize * count <= bytes.length, + 'Truncated ELF program headers', + ); + const alignments: bigint[] = []; + for (let index = 0; index < count; index++) { + const header = offset + index * headerSize; + if (bytes.readUInt32LE(header) !== 1) continue; + const alignment = bytes.readBigUInt64LE(header + 48); + assert(alignment >= 16384n, 'JNI library lost 16 KiB ELF page alignment'); + assert.equal( + bytes.readBigUInt64LE(header + 8) % alignment, + bytes.readBigUInt64LE(header + 16) % alignment, + 'ELF LOAD offset/address are incongruent', + ); + alignments.push(alignment); + } + assert(alignments.length, 'JNI library has no ELF LOAD segments'); +} + +/** class_defs identifies definitions, so an unused DEX string cannot satisfy proof. */ +export function dexDefinedClasses(bytes: Buffer): Set { + assert(bytes.subarray(0, 4).equals(Buffer.from('dex\n')), 'APK bytecode must be standard DEX'); + assert( + bytes.length >= 112 && + bytes.readUInt32LE(32) === bytes.length && + bytes.readUInt32LE(36) === 112, + ); + assert.equal(bytes.readUInt32LE(40), 0x12345678, 'Unsupported DEX endianness'); + function table(countOffset: number, offsetOffset: number, stride: number) { + const count = bytes.readUInt32LE(countOffset); + const offset = bytes.readUInt32LE(offsetOffset); + assert(offset + count * stride <= bytes.length, 'Truncated DEX table'); + return { count, offset }; + } + const strings = table(56, 60, 4); + const types = table(64, 68, 4); + const definitions = table(96, 100, 32); + // AOSP DEX SimpleNameChar includes hyphens and these Unicode ranges. + const characters = String.raw`A-Za-z0-9_$\u00a1-\u1fff\u2010-\u2027\u2030-\ud7ff\ue000-\uffef\u{10000}-\u{10ffff}`; + const spaces = + Number(bytes.subarray(4, 7).toString('ascii')) >= 40 + ? String.raw`\u0020\u00a0\u2000-\u200a\u202f` + : ''; + const simpleName = new RegExp(`^[${characters}${spaces}-]+$`, 'u'); + function descriptor(type: number) { + assert(type < types.count, 'DEX definition has invalid type index'); + const string = bytes.readUInt32LE(types.offset + type * 4); + assert(string < strings.count, 'DEX definition has invalid descriptor index'); + let offset = bytes.readUInt32LE(strings.offset + string * 4); + assert(offset < bytes.length, 'DEX descriptor is outside the file'); + let encodedLength = 0; + let utf16Length = 0; + let lengthByte = 0; + do { + assert(offset < bytes.length && encodedLength < 5, 'Invalid DEX UTF length'); + lengthByte = bytes[offset++]; + utf16Length += (lengthByte & 0x7f) * 2 ** (7 * encodedLength++); + } while (lengthByte & 0x80); + assert(utf16Length <= 0xffffffff, 'Invalid DEX UTF length'); + const end = bytes.indexOf(0, offset); + assert(end > offset, 'Invalid DEX class descriptor'); + // DEX MUTF-8 encodes supplemental characters as surrogate pairs. + let result = ''; + for (let cursor = offset; cursor < end; ) { + let unit = bytes[cursor++]; + if (unit >= 0x80) { + const width = (unit & 0xe0) === 0xc0 ? 1 : (unit & 0xf0) === 0xe0 ? 2 : 0; + assert(width && cursor + width <= end, 'Invalid DEX MUTF-8 descriptor'); + unit &= width === 1 ? 0x1f : 0x0f; + for (let index = 0; index < width; index++) { + const next = bytes[cursor++]; + assert((next & 0xc0) === 0x80, 'Invalid DEX MUTF-8 continuation'); + unit = (unit << 6) | (next & 0x3f); + } + assert(unit >= (width === 1 ? 0x80 : 0x800), 'Noncanonical DEX MUTF-8 descriptor'); + } + result += String.fromCharCode(unit); + } + assert.equal(result.length, utf16Length, 'DEX MUTF-8 UTF16 length differs'); + assert( + result.startsWith('L') && + result.endsWith(';') && + result + .slice(1, -1) + .split('/') + .every((name) => simpleName.test(name)), + `Invalid defined DEX class ${result}`, + ); + return result.slice(1, -1).replaceAll('/', '.'); + } + const result = new Set(); + for (let index = 0; index < definitions.count; index++) + result.add(descriptor(bytes.readUInt32LE(definitions.offset + index * 32))); + return result; +} + +/** Android imports need conventional runtime names, never Bazel output paths. */ +export function androidDynamicLinkMetadata(output: string, library: string) { + const sonames = [...output.matchAll(/^\s*SONAME\s+(\S+)\s*$/gmu)].map((row) => row[1]); + const needed = [...output.matchAll(/^\s*NEEDED\s+(\S+)\s*$/gmu)].map((row) => row[1]); + assert(sonames.length <= 1, `JNI library has multiple SONAME entries ${library}`); + if (sonames.length) + assert.equal(sonames[0], library, `JNI SONAME differs from packaged name ${library}`); + for (const dependency of needed) + assert( + /^[A-Za-z0-9_+.-]+\.so(?:\.[0-9]+)*$/u.test(dependency), + `JNI dependency has a build path ${library}/${dependency}`, + ); + if ( + [ + 'libexpo-modules-core.so', + 'libreact_codegen_safeareacontext.so', + 'libappmodules.so', + 'liboliphauntreactnative.so', + 'liboliphaunt_extensions.so', + ].includes(library) + ) + assert.deepEqual( + sonames, + [library], + `Source-built JNI library omitted its conventional SONAME ${library}`, + ); + if (library === 'liboliphaunt_extensions.so') + assert( + needed.includes('liboliphaunt.so'), + 'Selected extension link omitted its native runtime dependency', + ); + return { soname: sonames[0] ?? null, needed }; +} + +export async function verifyAndroidApk(spec: { + apk: string; + abi: string; + zipalign: string; + apksigner: string; + aapt: string; + objdump: string; + output: string; + selectedExtensions: string[]; + moduleStems: Record; + expectedClasses: string[]; + catalogProfile: string; + profileProbe: string; + environment?: Record; + unsignedApk?: string; + keystore?: string; +}) { + if (spec.unsignedApk) { + assert(spec.keystore, 'Release APK must retain the original generated signing key'); + const aligned = spec.apk + '.aligned'; + execFileSync( + path.resolve(spec.zipalign), + ['-P', '16', '-f', '4', realpathSync(spec.unsignedApk), aligned], + { stdio: 'inherit' }, + ); + execFileSync( + path.resolve(spec.apksigner), + [ + 'sign', + '--ks', + realpathSync(spec.keystore), + '--ks-key-alias', + 'androiddebugkey', + '--ks-pass', + 'pass:android', + '--key-pass', + 'pass:android', + '--out', + spec.apk, + aligned, + ], + { + stdio: 'inherit', + env: { ...process.env, ...spec.environment }, + }, + ); + rmSync(aligned); + } + const apk = realpathSync(spec.apk); + const badging = execFileSync(path.resolve(spec.aapt), ['dump', 'badging', apk], { + encoding: 'utf8', + }); + assert( + /^package: name='dev\.oliphaunt\.reactnative\.example'/mu.test(badging), + 'Compiled APK application identity differs', + ); + assert(/^sdkVersion:'24'$/mu.test(badging), 'Compiled APK minimum Android API differs'); + assert(/^targetSdkVersion:'36'$/mu.test(badging), 'Compiled APK target Android API differs'); + assert( + /^launchable-activity: name='dev\.oliphaunt\.reactnative\.example\.MainActivity'/mu.test( + badging, + ), + 'Compiled APK omitted its actual launcher', + ); + execFileSync(path.resolve(spec.zipalign), ['-c', '-P', '16', '4', apk], { stdio: 'inherit' }); + execFileSync(path.resolve(spec.apksigner), ['verify', '--verbose', apk], { + stdio: 'inherit', + env: { ...process.env, ...spec.environment }, + }); + const entries = readAndroidApkEntries(apk); + const runtimeManifestEntry = entries.get('assets/oliphaunt/runtime/manifest.properties'); + assert(runtimeManifestEntry?.isFile, 'Full Expo APK omitted its runtime manifest'); + const runtimeManifest = Buffer.from(runtimeManifestEntry.data()); + await assertAndroidRuntimeManifest(runtimeManifest); + const seedPrefix = spec.catalogProfile === 'icu' ? 'cluster-seed-icu' : 'cluster-seed'; + assert.equal( + runtimeManifest + .toString('utf8') + .match(/^runtimeFeatures=(.*)$/mu)?.[1] + ?.split(',') + .includes('icu'), + spec.catalogProfile === 'icu', + 'APK runtime features differ from its catalog profile', + ); + for (const name of [ + `lib/${spec.abi}/liboliphaunt.so`, + `lib/${spec.abi}/liboliphaunt_mobile_bindings.so`, + `lib/${spec.abi}/liboliphauntreactnative.so`, + `lib/${spec.abi}/libreactnative.so`, + `lib/${spec.abi}/libhermesvm.so`, + `lib/${spec.abi}/libfbjni.so`, + `lib/${spec.abi}/libappmodules.so`, + `lib/${spec.abi}/libexpo-modules-core.so`, + `lib/${spec.abi}/libjsi.so`, + `lib/${spec.abi}/libc++_shared.so`, + `lib/${spec.abi}/libreact_codegen_safeareacontext.so`, + `lib/${spec.abi}/liboliphaunt_extensions.so`, + `lib/${spec.abi}/libjnidispatch.so`, + `assets/oliphaunt/${seedPrefix}/manifest.properties`, + 'assets/oliphaunt/static-registry/link-receipt.json', + 'assets/index.android.bundle', + ]) + assert(entries.get(name)?.isFile, `Full Expo APK omitted ${name}`); + const bytecode = Buffer.from(entries.get('assets/index.android.bundle')!.data()); + assertHermesBytecode(bytecode); + const bundleEnvironment = mobileBundleEnvironment( + {}, + spec.selectedExtensions, + spec.catalogProfile, + spec.profileProbe, + ); + for (const name of [ + 'EXPO_PUBLIC_OLIPHAUNT_CATALOG_PROFILE_PROBE_SQL', + 'EXPO_PUBLIC_OLIPHAUNT_CATALOG_PROFILE_PROBE_EXPECTED', + ]) + assert( + bytecode.includes(Buffer.from(bundleEnvironment[name])), + 'APK bundle omitted its original catalog expectation ' + name, + ); + const seedManifest = Buffer.from( + entries.get(`assets/oliphaunt/${seedPrefix}/manifest.properties`)!.data(), + ).toString('utf8'); + assert.equal( + seedManifest.match(/^catalogProfile=(.*)$/mu)?.[1], + spec.catalogProfile, + 'APK seed profile differs from its bundle expectation', + ); + const classes = new Set(); + const nativeLibraries: { + name: string; + sha256: string; + soname: string | null; + needed: string[]; + }[] = []; + const nativeProof = mkdtempSync( + path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'oliphaunt-apk-link-'), + ); + try { + for (const [name, entry] of entries) { + if (/^classes(?:\d+)?\.dex$/u.test(name)) + for (const className of dexDefinedClasses(Buffer.from(entry.data()))) + classes.add(className); + if (/^lib\/[^/]+\/[^/]+\.so$/u.test(name)) { + assert(name.startsWith(`lib/${spec.abi}/`), `APK includes unselected ABI ${name}`); + const bytes = Buffer.from(entry.data()); + assertAndroidElf(bytes, spec.abi); + const library = path.basename(name); + const file = path.join(nativeProof, library); + writeFileSync(file, bytes); + const dynamic = androidDynamicLinkMetadata( + execFileSync(realpathSync(spec.objdump), ['-p', file], { encoding: 'utf8' }), + library, + ); + nativeLibraries.push({ + name, + sha256: createHash('sha256').update(bytes).digest('hex'), + ...dynamic, + }); + } + } + } finally { + rmSync(nativeProof, { recursive: true, force: true }); + } + for (const name of [ + 'dev.oliphaunt.DatabaseStorage$TemporaryDirectory', + 'com.sun.jna.Native', + 'dev.oliphaunt.reactnative.OliphauntModule', + 'dev.oliphaunt.reactnative.NativeOliphauntSpec', + 'expo.modules.ExpoModulesPackageList', + 'expo.modules.kotlin.AppContext', + ...spec.expectedClasses, + ]) + assert(classes.has(name), `Full Expo APK omitted defined bytecode ${name}`); + const selected = runtimeManifest + .toString('utf8') + .match(/^selectedExtensions=(.*)$/mu)?.[1] + ?.split(',') + .filter(Boolean) + .sort(); + assert.deepEqual(selected, [...spec.selectedExtensions].sort(), 'APK selected extensions differ'); + const receipt = JSON.parse( + Buffer.from(entries.get('assets/oliphaunt/static-registry/link-receipt.json')!.data()).toString( + 'utf8', + ), + ); + assert.equal(receipt.schema, 'oliphaunt-android-static-extension-link-v1'); + assert.equal(receipt.abi, spec.abi); + assert.deepEqual(receipt.selectedExtensions, [...spec.selectedExtensions].sort()); + assertAndroidStaticMembers(spec.selectedExtensions, spec.moduleStems, receipt.members); + assert.equal( + receipt.linkedSha256, + createHash('sha256') + .update(entries.get(`lib/${spec.abi}/liboliphaunt_extensions.so`)!.data()) + .digest('hex'), + 'APK static extension library differs from the actual verified link', + ); + writeFileSync( + spec.output, + JSON.stringify( + { + schema: 'oliphaunt-expo-android-apk-proof-v1', + abi: spec.abi, + apkSha256: createHash('sha256').update(readFileSync(apk)).digest('hex'), + applicationId: 'dev.oliphaunt.reactnative.example', + minSdk: 24, + targetSdk: 36, + selectedExtensions: selected, + catalogProfile: spec.catalogProfile, + catalogProbeSha256: createHash('sha256') + .update(readFileSync(spec.profileProbe)) + .digest('hex'), + bundleSha256: createHash('sha256').update(bytecode).digest('hex'), + definedClasses: [...classes].sort(), + nativeLibraries, + deviceExecution: false, + }, + null, + 2, + ) + '\n', + ); +} + +if (import.meta.main) { + const [mode, file] = Bun.argv.slice(2); + assert(mode && file, 'Android app action needs a mode and declared specification'); + const spec = JSON.parse(readFileSync(file, 'utf8')); + if (mode === 'codegen') await generateReactNativeCodegen(spec); + else if (mode === 'autolinking-test') await runAutolinkingConsumer(spec); + else if (mode === 'project') await generateExpoAndroidProject(spec); + else if (mode === 'bundle') await bundleExpoAndroid(spec); + else if (mode === 'prefab') extractPrefab(spec); + else if (mode === 'aar-native') await extractAarNative(spec); + else if (mode === 'final-aar') await extractFinalAar(spec); + else if (mode === 'extension-receipt') extensionLinkReceipt(spec); + else if (mode === 'runtime-assets') await prepareAppRuntimeAssets(spec); + else if (mode === 'jni-aar') await nativeLibrariesAar(spec); + else if (mode === 'verify') await verifyAndroidApk(spec); + else throw new Error(`Unknown Android app action ${mode}`); +} diff --git a/build_defs/android/app.test.mts b/build_defs/android/app.test.mts new file mode 100644 index 000000000..5a705733a --- /dev/null +++ b/build_defs/android/app.test.mts @@ -0,0 +1,980 @@ +import { test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { nativeRuntimeResourceManifestFixture } from '../../src/native/runtime/tools/testdata/native-runtime-fixture.mts'; +import { + createDeterministicTar, + createDeterministicZip, +} from '../../tools/packaging/archive-directory.mts'; +import { + canonicalGzipSync, + readPortableArchiveEntries, +} from '../../tools/packaging/portable-archive.mts'; +import { + androidDynamicLinkMetadata, + assertAndroidElf, + assertAndroidRuntimeManifest, + assertAndroidStaticMembers, + assertHermesBytecode, + dexDefinedClasses, + extractFinalAar, + extensionLinkReceipt, + mobileBundleEnvironment, + prepareAppRuntimeAssets, + stageAndroidSelectedResources, + stageNodeInputs, + verifyAndroidApk, +} from './app.mts'; + +function dex(names: string[], definitions: number[]) { + const strings = 112; + const types = strings + names.length * 4; + const classes = types + names.length * 4; + const data = classes + definitions.length * 32; + const encoded = names.map((name) => { + const value = `L${name.replaceAll('.', '/')};`; + assert(value.length < 128); + const units = Array.from({ length: value.length }, (_, index) => value.charCodeAt(index)); + return Buffer.from([ + value.length, + ...units.flatMap((unit) => + unit < 0x80 + ? [unit] + : unit < 0x800 + ? [0xc0 | (unit >> 6), 0x80 | (unit & 0x3f)] + : [0xe0 | (unit >> 12), 0x80 | ((unit >> 6) & 0x3f), 0x80 | (unit & 0x3f)], + ), + 0, + ]); + }); + const bytes = Buffer.alloc(data + encoded.reduce((total, row) => total + row.length, 0)); + bytes.write('dex\n035\x00', 0, 'binary'); + for (const [offset, value] of [ + [32, bytes.length], + [36, 112], + [40, 0x12345678], + [56, names.length], + [60, strings], + [64, names.length], + [68, types], + [96, definitions.length], + [100, classes], + ]) + bytes.writeUInt32LE(value, offset); + let cursor = data; + for (let index = 0; index < names.length; index++) { + bytes.writeUInt32LE(cursor, strings + index * 4); + bytes.writeUInt32LE(index, types + index * 4); + encoded[index].copy(bytes, cursor); + cursor += encoded[index].length; + } + for (let index = 0; index < definitions.length; index++) + bytes.writeUInt32LE(definitions[index], classes + index * 32); + return bytes; +} + +test('APK bytecode proof distinguishes actual class definitions from references', () => { + const names = ['dev.oliphaunt.DatabaseStorage$TemporaryDirectory', 'com.sun.jna.Native']; + assert.deepEqual([...dexDefinedClasses(dex(names, [0]))], [names[0]]); + assert.deepEqual([...dexDefinedClasses(dex(names, [0, 1]))], names); + const companion = 'androidx.compose.animation.AnimatedContentTransitionScope$-CC'; + assert.deepEqual([...dexDefinedClasses(dex([companion], [0]))], [companion]); + assert.deepEqual([...dexDefinedClasses(dex([companion], []))], []); + const unicode = 'dev.example.É漢�'; + assert.deepEqual([...dexDefinedClasses(dex([unicode], [0]))], [unicode]); + const canonical = dex(['dev.example.Valid'], [0]); + const stringData = canonical.readUInt32LE(canonical.readUInt32LE(60)); + for (const overlong of [ + [0xc1, 0x8c], + [0xe0, 0x81, 0x8c], + ]) { + const malformed = Buffer.concat([ + canonical.subarray(0, stringData + 1), + Buffer.from(overlong), + canonical.subarray(stringData + 2), + ]); + malformed.writeUInt32LE(malformed.length, 32); + assert.throws(() => dexDefinedClasses(malformed), /Noncanonical DEX MUTF-8/u); + } + const wrongLength = Buffer.from(canonical); + wrongLength[stringData]++; + assert.throws(() => dexDefinedClasses(wrongLength), /UTF16 length differs/u); + for (const name of ['androidx..compose.Broken', '/Bad', 'Bad/', 'Bad;Other', 'Bad[Array']) + assert.throws(() => dexDefinedClasses(dex([name], [0])), /Invalid defined DEX class/u); + assert.throws(() => dexDefinedClasses(dex(names, [2])), /invalid type index/u); + const truncated = dex(names, [0]).subarray(0, 140); + assert.throws(() => dexDefinedClasses(truncated)); +}); + +test('selected Android resources use frozen carrier bytes and bind both ABI static archives to the link receipt', async () => { + const root = mkdtempSync(path.join(tmpdir(), 'android-selected-resources-')); + try { + for (const abi of ['arm64-v8a', 'x86_64']) { + const directory = path.join(root, abi); + const payload = path.join(directory, 'payload'); + mkdirSync(path.join(payload, 'files/share/postgresql/extension'), { recursive: true }); + mkdirSync(path.join(payload, 'files/share/postgresql/data'), { recursive: true }); + mkdirSync(path.join(payload, `mobile-static/android-${abi}/extensions/vector`), { + recursive: true, + }); + writeFileSync( + path.join(payload, 'files/share/postgresql/extension/vector.control'), + 'default_version=fixture\n', + ); + writeFileSync( + path.join(payload, 'files/share/postgresql/extension/vector--fixture.sql'), + 'original install SQL\n', + ); + writeFileSync( + path.join(payload, 'files/share/postgresql/data/value'), + 'original declared runtime data\n', + ); + const archive = Buffer.from('original static archive fixture'); + writeFileSync( + path.join( + payload, + `mobile-static/android-${abi}/extensions/vector/liboliphaunt_extension_vector.a`, + ), + archive, + ); + const github = path.join(directory, 'github'); + mkdirSync(github); + const file = path.join(github, 'vector.tar.gz'); + writeFileSync(file, canonicalGzipSync(await createDeterministicTar(payload))); + const frozen = path.join(directory, 'frozen.json'); + writeFileSync( + frozen, + JSON.stringify({ + product: 'vector-product', + releaseProduct: 'vector-owner', + version: '1.2.3', + compatibility: { nativeRuntimeVersion: '3.3.3' }, + sqlName: 'vector', + nativeModuleStem: 'vector', + dataFiles: ['postgresql/data'], + assets: [ + { + name: 'vector.tar.gz', + family: 'native', + target: `android-${abi}`, + kind: 'runtime', + bytes: readFileSync(file).length, + sha256: createHash('sha256').update(readFileSync(file)).digest('hex'), + }, + ], + }), + ); + const leaf = { + product: 'vector-product', + owner: 'vector-owner', + version: '1.2.3', + runtimeVersion: '3.3.3', + target: `android-${abi}`, + sqlNames: ['vector'], + github: [github], + frozen, + }; + const sqlPayload = path.join(directory, 'pgtap-payload'); + mkdirSync(path.join(sqlPayload, 'files/share/postgresql/extension'), { recursive: true }); + const pgtapSql = Buffer.from('original SQL-only install fixture\n'); + writeFileSync( + path.join(sqlPayload, 'files/share/postgresql/extension/pgtap.control'), + 'default_version=fixture\n', + ); + writeFileSync( + path.join(sqlPayload, 'files/share/postgresql/extension/pgtap--fixture.sql'), + pgtapSql, + ); + const sqlArchive = path.join(directory, 'pgtap.tar.gz'); + writeFileSync(sqlArchive, canonicalGzipSync(await createDeterministicTar(sqlPayload))); + const sqlFrozen = path.join(directory, 'pgtap-frozen.json'); + writeFileSync( + sqlFrozen, + JSON.stringify({ + product: 'pgtap-product', + releaseProduct: 'pgtap-owner', + version: '1.2.3', + compatibility: { nativeRuntimeVersion: '3.3.3' }, + sqlName: 'pgtap', + nativeModuleStem: null, + assets: [ + { + name: 'pgtap.tar.gz', + family: 'native', + target: `android-${abi}`, + kind: 'runtime', + bytes: readFileSync(sqlArchive).length, + sha256: createHash('sha256').update(readFileSync(sqlArchive)).digest('hex'), + }, + ], + }), + ); + const sqlLeaf = { + product: 'pgtap-product', + owner: 'pgtap-owner', + version: '1.2.3', + runtimeVersion: '3.3.3', + target: `android-${abi}`, + sqlNames: ['pgtap'], + github: [sqlArchive], + frozen: sqlFrozen, + }; + const receipt = path.join(directory, 'receipt.json'); + const link = { + abi, + selectedExtensions: ['pgtap', 'vector'], + members: [ + { + sqlName: 'vector', + nativeModuleStem: 'vector', + archiveSha256: createHash('sha256').update(archive).digest('hex'), + }, + ], + }; + writeFileSync(receipt, JSON.stringify(link)); + const spec = { + abi, + selectedExtensions: ['pgtap', 'vector'], + moduleStems: { pgtap: null, vector: 'vector' }, + version: '3.3.3', + leaves: [leaf, sqlLeaf], + receipt, + }; + const staged = await stageAndroidSelectedResources(spec, path.join(directory, 'valid')); + assert.equal(staged.length, 2); + assert(readFileSync(staged[0]).equals(readFileSync(file))); + assert(readFileSync(staged[1]).equals(readFileSync(sqlArchive))); + const stagedSql = readPortableArchiveEntries(staged[1]).get( + 'files/share/postgresql/extension/pgtap--fixture.sql', + ); + assert(stagedSql?.isFile); + assert(Buffer.from(stagedSql.data()).equals(pgtapSql)); + await assert.rejects( + stageAndroidSelectedResources( + { ...spec, leaves: [leaf] }, + path.join(directory, 'missing-sql'), + ), + /Selected resource carriers differ/u, + ); + const originalSqlFrozen = readFileSync(sqlFrozen); + writeFileSync( + sqlFrozen, + JSON.stringify({ + ...JSON.parse(originalSqlFrozen.toString('utf8')), + nativeModuleStem: 'pgtap', + }), + ); + await assert.rejects( + stageAndroidSelectedResources(spec, path.join(directory, 'wrong-sql-module')), + /module stem/u, + ); + writeFileSync(sqlFrozen, originalSqlFrozen); + assert.throws( + () => + assertAndroidStaticMembers(spec.selectedExtensions, { vector: 'vector' }, link.members), + /Canonical SQL cohort differs/u, + ); + assert.throws( + () => + assertAndroidStaticMembers(spec.selectedExtensions, spec.moduleStems, [ + ...link.members, + { sqlName: 'pgtap', nativeModuleStem: 'pgtap' }, + ]), + /Compiled registration cohort differs/u, + ); + assert.throws( + () => + assertAndroidStaticMembers(spec.selectedExtensions, spec.moduleStems, [ + { ...link.members[0], nativeModuleStem: 'wrong-vector' }, + ]), + /Canonical native module stem differs/u, + ); + const intermediate = path.join(directory, 'formatter-intermediate'); + const data = Buffer.from('runtime resource bytes'); + const registry = Buffer.from('source static registration'); + const icuBytes = + abi === 'x86_64' ? Buffer.from('immutable ICU fixture bytes') : Buffer.alloc(0); + let icu: string | undefined; + let icuDigest = ''; + if (icuBytes.length) { + const icuRoot = path.join(directory, 'icu'); + const icuData = path.join(icuRoot, 'share/icu'); + mkdirSync(icuData, { recursive: true }); + writeFileSync(path.join(icuData, 'icudt76l.dat'), icuBytes); + icuDigest = 'a'.repeat(64); + icu = path.join(directory, 'icu.tar.gz'); + writeFileSync(icu, canonicalGzipSync(await createDeterministicTar(icuRoot))); + mkdirSync(path.join(intermediate, 'runtime/files/share/icu'), { recursive: true }); + writeFileSync(path.join(intermediate, 'runtime/files/share/icu/icudt76l.dat'), icuBytes); + } + mkdirSync(path.join(intermediate, 'runtime/files/share/postgresql'), { recursive: true }); + mkdirSync(path.join(intermediate, 'static-registry')); + writeFileSync(path.join(intermediate, 'runtime/files/share/postgresql/data'), data); + writeFileSync( + path.join(intermediate, 'static-registry/oliphaunt_static_registry.c'), + registry, + ); + const intermediateManifest = nativeRuntimeResourceManifestFixture({ + overrides: { + runtimeFeatures: icu ? 'icu' : '', + icuDataTreeSha256: icuDigest, + selectedExtensions: 'pgtap,vector', + extensions: 'pgtap,vector', + mobileStaticRegistryState: 'complete', + mobileStaticRegistryRegistered: 'vector', + nativeModuleStems: 'vector', + mobileStaticRegistrySource: 'static-registry/oliphaunt_static_registry.c', + }, + }); + writeFileSync(path.join(intermediate, 'runtime/manifest.properties'), intermediateManifest); + writeFileSync( + path.join(intermediate, 'package-size.tsv'), + 'kind\tid\textensions\tfiles\tbytes\npackage\ttotal\t-\t-\t0\nextension\tvector\tvector\t2\t99\n', + ); + const formatter = path.join(directory, 'formatter.mts'); + writeFileSync( + formatter, + `#!${process.execPath}\nimport assert from 'node:assert/strict';\nimport { cpSync, readFileSync } from 'node:fs';\nimport path from 'node:path';\nconst args=process.argv.slice(2);\nassert.equal(args.includes('--runtime-feature'),${Boolean(icu)});\nif(${Boolean(icu)}) { assert.equal(args[args.indexOf('--runtime-feature')+1],'icu'); assert(readFileSync(path.join(process.env.OLIPHAUNT_ICU_DATA_DIR,'icudt76l.dat')).equals(Buffer.from(${JSON.stringify(icuBytes.toString('hex'))},'hex'))); } else assert.equal(process.env.OLIPHAUNT_ICU_DATA_DIR,undefined);\nassert.equal(args.filter(arg=>arg==='--prebuilt-extension').length,2);\ncpSync(${JSON.stringify(intermediate)},path.join(args[args.indexOf('--output')+1],'oliphaunt'),{recursive:true});\n`, + ); + chmodSync(formatter, 0o755); + const output = path.join(directory, 'app-assets'); + const assetSpec = { + ...spec, + payload, + formatter, + mobileStaticModules: ['vector'], + icu, + output, + }; + await assert.rejects( + prepareAppRuntimeAssets({ ...assetSpec, mobileStaticModules: [] }), + /Selected native modules differ/u, + ); + await prepareAppRuntimeAssets(assetSpec); + const closure = path.join(output, 'oliphaunt'); + const manifest = readFileSync(path.join(closure, 'runtime/manifest.properties')); + await assertAndroidRuntimeManifest(manifest); + assert( + manifest.equals( + Buffer.from( + intermediateManifest + .toString('utf8') + .replace('clusterSeedTarget=\n', 'clusterSeedTarget=android-datum64\n'), + ), + ), + ); + assert(readFileSync(path.join(closure, 'runtime/files/share/postgresql/data')).equals(data)); + if (icu) + assert( + readFileSync(path.join(closure, 'runtime/files/share/icu/icudt76l.dat')).equals(icuBytes), + ); + assert( + readFileSync(path.join(closure, 'static-registry/link-receipt.json')).equals( + readFileSync(receipt), + ), + ); + const report = readFileSync(path.join(closure, 'package-size.tsv'), 'utf8'); + assert( + report.includes( + `package\ttotal\t-\t-\t${data.length + icuBytes.length + registry.length + readFileSync(receipt).length}\n`, + ), + ); + assert(report.includes('extension\tvector\tvector\t2\t99\n')); + await assert.rejects( + assertAndroidRuntimeManifest( + readFileSync(path.join(intermediate, 'runtime/manifest.properties')), + ), + /canonical for android-datum64/u, + ); + await assert.rejects( + assertAndroidRuntimeManifest( + Buffer.from( + manifest + .toString('utf8') + .replace('clusterSeedTarget=android-datum64', 'clusterSeedTarget=ios-datum64'), + ), + ), + /incompatible native-direct contract/u, + ); + await assert.rejects( + stageAndroidSelectedResources( + { ...spec, abi: abi === 'arm64-v8a' ? 'x86_64' : 'arm64-v8a' }, + path.join(directory, 'wrong-abi'), + ), + /ABI differs/u, + ); + writeFileSync( + receipt, + JSON.stringify({ + ...link, + members: [{ ...link.members[0], archiveSha256: '0'.repeat(64) }], + }), + ); + await assert.rejects( + stageAndroidSelectedResources(spec, path.join(directory, 'wrong-link')), + /differs from actual app link/u, + ); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +function elf(alignment: bigint, machine = 183) { + const bytes = Buffer.alloc(128); + bytes.set([0x7f, 0x45, 0x4c, 0x46, 2, 1]); + bytes.writeUInt16LE(machine, 18); + bytes.writeBigUInt64LE(64n, 32); + bytes.writeUInt16LE(56, 54); + bytes.writeUInt16LE(1, 56); + bytes.writeUInt32LE(1, 64); + bytes.writeBigUInt64LE(alignment, 112); + return bytes; +} + +test('static extension link proof retains required definitions beyond the child output buffer limit', () => { + const root = mkdtempSync(path.join(tmpdir(), 'android-static-symbol-output-')); + try { + const library = path.join(root, 'linked.so'); + const archive = path.join(root, 'vector.a'); + const registration = path.join(root, 'vector.json'); + const registry = path.join(root, 'registry.c'); + const nm = path.join(root, 'fixture-nm.mts'); + const symbols = path.join(root, 'symbols.txt'); + const status = path.join(root, 'status.txt'); + writeFileSync(library, elf(16384n)); + writeFileSync(archive, 'original static archive fixture bytes'); + writeFileSync(registry, 'original generated registry fixture bytes'); + const required = [ + 'liboliphaunt_selected_static_extensions', + 'oliphaunt_static_vector_Pg_magic_func', + 'oliphaunt_static_vector__PG_init', + 'vector_dims', + ]; + writeFileSync( + registration, + JSON.stringify({ + sqlName: 'vector', + nativeModuleStem: 'vector', + magicSymbol: required[1], + initSymbol: required[2], + symbols: [{ name: 'vector_dims', address: required[3] }], + }), + ); + const filler = Array.from( + { length: 30_000 }, + (_, index) => + `0000000000000000 T oliphaunt_boundary_export_abcdefghijklmnopqrstuvwxyz_${String(index).padStart(5, '0')}\n`, + ).join(''); + assert(Buffer.byteLength(filler) > 1024 * 1024); + const definitions = (names: string[]) => + filler + names.map((name) => `0000000000000000 T ${name}\n`).join(''); + writeFileSync(symbols, definitions(required)); + writeFileSync(status, '0'); + writeFileSync( + nm, + `#!${process.execPath}\nimport { readFileSync } from 'node:fs';\nprocess.stdout.write(readFileSync(new URL('./symbols.txt', import.meta.url)));\nprocess.exitCode = Number(readFileSync(new URL('./status.txt', import.meta.url), 'utf8'));\nif (process.exitCode) process.stderr.write('fixture nm child failed');\n`, + ); + chmodSync(nm, 0o755); + const spec = { + library, + registry, + members: [{ archive, registration }], + selectedExtensions: ['pgtap', 'vector'], + moduleStems: { pgtap: null, vector: 'vector' }, + abi: 'arm64-v8a', + nm, + output: path.join(root, 'receipt.json'), + }; + extensionLinkReceipt(spec); + const receipt = JSON.parse(readFileSync(spec.output, 'utf8')); + const digest = (file: string) => createHash('sha256').update(readFileSync(file)).digest('hex'); + assert.equal(receipt.linkedSha256, digest(library)); + assert.equal(receipt.registrySha256, digest(registry)); + assert.deepEqual(receipt.selectedExtensions, spec.selectedExtensions); + assert.equal(receipt.members[0].archiveSha256, digest(archive)); + assert.equal(receipt.members[0].registrationSha256, digest(registration)); + assert.deepEqual(receipt.members[0].definedSymbols, required.slice(1).sort()); + rmSync(spec.output); + writeFileSync(status, '7'); + assert.throws( + () => extensionLinkReceipt(spec), + /declared llvm-nm failed: fixture nm child failed/u, + ); + assert.throws(() => readFileSync(spec.output), { code: 'ENOENT' }); + writeFileSync(status, '0'); + writeFileSync(symbols, definitions(required.filter((name) => name !== 'vector_dims'))); + assert.throws( + () => extensionLinkReceipt(spec), + /omitted actual archive definition vector\/vector_dims/u, + ); + assert.throws(() => readFileSync(spec.output), { code: 'ENOENT' }); + writeFileSync(symbols, definitions(required.slice(1))); + assert.throws(() => extensionLinkReceipt(spec), /Linked static extension registry is absent/u); + assert.throws(() => readFileSync(spec.output), { code: 'ENOENT' }); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('actual APK proof rejects an unbound runtime manifest before deeper bytecode inspection', async () => { + const root = mkdtempSync(path.join(tmpdir(), 'android-runtime-manifest-proof-')); + try { + const tree = path.join(root, 'apk'); + mkdirSync(path.join(tree, 'assets/oliphaunt/runtime'), { recursive: true }); + const manifest = path.join(tree, 'assets/oliphaunt/runtime/manifest.properties'); + writeFileSync(manifest, nativeRuntimeResourceManifestFixture()); + const apk = path.join(root, 'installed.apk'); + writeFileSync(apk, await createDeterministicZip(tree)); + const tool = path.join(root, 'sdk-tool.mts'); + const badging = + "package: name='dev.oliphaunt.reactnative.example'\nsdkVersion:'24'\ntargetSdkVersion:'36'\nlaunchable-activity: name='dev.oliphaunt.reactnative.example.MainActivity'\n"; + writeFileSync( + tool, + `#!${process.execPath}\nif(process.argv[2]==='dump') console.log(${JSON.stringify(badging)});\n`, + ); + chmodSync(tool, 0o755); + const spec = { + apk, + abi: 'x86_64', + zipalign: tool, + apksigner: tool, + aapt: tool, + objdump: tool, + output: path.join(root, 'proof.json'), + selectedExtensions: [], + moduleStems: {}, + expectedClasses: [], + catalogProfile: 'standard', + profileProbe: '', + }; + await assert.rejects(verifyAndroidApk(spec), /canonical for android-datum64/u); + writeFileSync(manifest, nativeRuntimeResourceManifestFixture({ target: 'android-datum64' })); + writeFileSync(apk, await createDeterministicZip(tree)); + await assert.rejects(verifyAndroidApk(spec), /Full Expo APK omitted lib/u); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('JNI proof rejects ABI mismatch and libraries with 4 KiB ELF segments', () => { + assertAndroidElf(elf(16384n), 'arm64-v8a'); + assert.throws(() => assertAndroidElf(elf(4096n), 'arm64-v8a'), /16 KiB/u); + assert.throws(() => assertAndroidElf(elf(16384n), 'x86_64'), /machine differs/u); + const inconsistent = elf(16384n); + inconsistent.writeBigUInt64LE(128n, 72); + assert.throws(() => assertAndroidElf(inconsistent, 'arm64-v8a'), /incongruent/u); +}); + +test('release JS proof rejects source text and truncated Hermes files', () => { + const bytes = Buffer.alloc(256); + bytes.writeBigUInt64LE(0x1f1903c103bc1fc6n); + bytes.writeUInt32LE(bytes.length, 32); + createHash('sha1') + .update(bytes.subarray(0, -20)) + .digest() + .copy(bytes, bytes.length - 20); + assertHermesBytecode(bytes); + assert.throws(() => + assertHermesBytecode(Buffer.from('globalThis.__OLIPHAUNT_EXPO_SMOKE_PASS=true;')), + ); + assert.throws(() => assertHermesBytecode(bytes.subarray(0, 8))); +}); + +test('APK native link proof rejects absent SONAME and build-path dependencies', () => { + const valid = + 'Dynamic Section:\n NEEDED liboliphaunt.so\n SONAME liboliphaunt_extensions.so\n'; + assert.deepEqual(androidDynamicLinkMetadata(valid, 'liboliphaunt_extensions.so'), { + soname: 'liboliphaunt_extensions.so', + needed: ['liboliphaunt.so'], + }); + assert.throws( + () => androidDynamicLinkMetadata(' NEEDED liboliphaunt.so\n', 'liboliphaunt_extensions.so'), + /omitted its conventional SONAME/u, + ); + assert.throws( + () => + androidDynamicLinkMetadata( + valid.replace('liboliphaunt.so', 'bazel-out/android/bin/liboliphaunt.so'), + 'liboliphaunt_extensions.so', + ), + /build path/u, + ); + assert.throws( + () => + androidDynamicLinkMetadata( + valid.replace('liboliphaunt.so', 'libc.so'), + 'liboliphaunt_extensions.so', + ), + /omitted its native runtime dependency/u, + ); + assert.throws(() => androidDynamicLinkMetadata(valid, 'libappmodules.so'), /SONAME differs/u); +}); + +test('declared node staging rejects missing dependency and duplicate app input', () => { + const root = mkdtempSync(path.join(tmpdir(), 'expo-input-test-')); + try { + const source = path.join(root, 'input'); + mkdirSync(source); + writeFileSync( + path.join(source, 'package.json'), + JSON.stringify({ name: 'first', version: '1.0.0' }), + ); + const packages = { + a: { + package: 'first', + version: '1.0.0', + integrity: 'sha512-AA==', + source, + dependencies: { absent: 'b' }, + }, + }; + assert.throws( + () => + stageNodeInputs(path.join(root, 'missing'), { + packages, + roots: { first: 'a' }, + sources: [], + node: '', + tar: '', + }), + /Undeclared npm dependency/u, + ); + const sources = [0, 1].map(() => ({ + source: path.join(source, 'package.json'), + destination: 'app.json', + })); + assert.throws( + () => + stageNodeInputs(path.join(root, 'duplicate'), { + packages: { a: { ...packages.a, dependencies: {} } }, + roots: { first: 'a' }, + sources, + node: '', + tar: '', + }), + /Duplicate app input/u, + ); + const valid = path.join(root, 'valid'); + stageNodeInputs(valid, { + packages: { a: { ...packages.a, dependencies: {} } }, + roots: { first: 'a' }, + sources: [sources[0]], + node: '', + tar: '', + }); + assert.equal( + readFileSync(path.join(valid, 'app.json'), 'utf8'), + readFileSync(sources[0].source, 'utf8'), + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('app-private Android envelope preserves canonical Maven runtime and seed TAR bytes', async () => { + const root = mkdtempSync(path.join(tmpdir(), 'expo-maven-test-')); + try { + const runtime = path.join(root, 'runtime'); + mkdirSync(path.join(runtime, 'jni/arm64-v8a'), { recursive: true }); + const library = elf(16384n); + writeFileSync(path.join(runtime, 'jni/arm64-v8a/liboliphaunt.so'), library); + const archive = path.join(root, 'runtime.tar.gz'); + writeFileSync(archive, canonicalGzipSync(await createDeterministicTar(runtime))); + const output = path.join(root, 'runtime.aar'); + await extractFinalAar({ + source: archive, + output, + kind: 'runtime', + package: 'dev.oliphaunt.runtime', + abi: 'arm64-v8a', + }); + assert( + Buffer.from( + readPortableArchiveEntries(output).get('jni/arm64-v8a/liboliphaunt.so')!.data(), + ).equals(library), + ); + await assert.rejects( + extractFinalAar({ + source: archive, + output, + kind: 'runtime', + package: 'dev.oliphaunt.runtime', + abi: 'x86_64', + }), + /selected JNI/u, + ); + for (const catalogProfile of ['standard', 'icu'] as const) { + const prefix = catalogProfile === 'icu' ? 'cluster-seed-icu' : 'cluster-seed'; + const seed = path.join(root, `seed-${catalogProfile}`); + mkdirSync(path.join(seed, prefix, 'files'), { recursive: true }); + const manifest = Buffer.from(`catalogProfile=${catalogProfile}\nphysicalFormat=datum64\n`); + writeFileSync(path.join(seed, prefix, 'manifest.properties'), manifest); + writeFileSync(path.join(seed, prefix, 'files/PG_VERSION'), '18\n'); + const seedArchive = path.join(root, `seed-${catalogProfile}.tar.gz`); + writeFileSync(seedArchive, canonicalGzipSync(await createDeterministicTar(seed))); + const seedOutput = path.join(root, `seed-${catalogProfile}.aar`); + const spec = { + source: seedArchive, + output: seedOutput, + kind: 'seed' as const, + package: 'dev.oliphaunt.resources', + catalogProfile, + }; + await extractFinalAar(spec); + const entries = readPortableArchiveEntries(seedOutput); + assert.equal( + Buffer.from(entries.get(`assets/oliphaunt/${prefix}/files/PG_VERSION`)!.data()).toString(), + '18\n', + ); + assert( + Buffer.from(entries.get(`assets/oliphaunt/${prefix}/manifest.properties`)!.data()).equals( + manifest, + ), + ); + await assert.rejects( + extractFinalAar({ ...spec, catalogProfile: catalogProfile === 'icu' ? 'standard' : 'icu' }), + /seed TAR omitted its resource manifest/u, + ); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('mobile bundle embeds the source-owned selected catalog and extension expectations', () => { + const file = new URL('../../src/database-resources/contracts/profile-probe.json', import.meta.url) + .pathname; + const source = JSON.parse(readFileSync(file, 'utf8')); + const actual = mobileBundleEnvironment( + { EXPO_PUBLIC_OLIPHAUNT_RUNNER: 'smoke' }, + ['vector'], + 'standard', + file, + ); + assert.equal(actual.EXPO_PUBLIC_OLIPHAUNT_EXTENSIONS, 'vector'); + assert.equal(actual.EXPO_PUBLIC_OLIPHAUNT_CATALOG_PROFILE, 'standard'); + assert.equal( + actual.EXPO_PUBLIC_OLIPHAUNT_CATALOG_PROFILE_PROBE_SQL, + source.profiles.standard.sql, + ); + assert.equal( + actual.EXPO_PUBLIC_OLIPHAUNT_CATALOG_PROFILE_PROBE_EXPECTED, + source.profiles.standard.expected, + ); + assert.equal(actual.EXPO_PUBLIC_OLIPHAUNT_RUNNER, 'smoke'); + assert.equal( + mobileBundleEnvironment({}, [], 'icu', file) + .EXPO_PUBLIC_OLIPHAUNT_CATALOG_PROFILE_PROBE_EXPECTED, + source.profiles.icu.expected, + ); + assert.throws( + () => mobileBundleEnvironment({}, ['vector', 'vector'], 'standard', file), + /Duplicate packaged/u, + ); + assert.throws( + () => mobileBundleEnvironment({}, ['vector'], 'unknown', file), + /Unsupported packaged/u, + ); + assert.throws( + () => + mobileBundleEnvironment( + { EXPO_PUBLIC_OLIPHAUNT_EXTENSIONS: '' }, + ['vector'], + 'standard', + file, + ), + /Conflicting packaged/u, + ); +}); + +test('canonical Maven input Tree resolves sandbox File links and rejects directory links or duplicate carriers', async () => { + const root = mkdtempSync(path.join(tmpdir(), 'maven-tree-transport-')); + try { + const payload = path.join(root, 'payload.aar'); + const bytes = Buffer.from('declared original AAR bytes'); + writeFileSync(payload, bytes); + const tree = path.join(root, 'tree'); + const coordinate = path.join(tree, 'dev/example/artifact/1.0.0'); + mkdirSync(coordinate, { recursive: true }); + symlinkSync(payload, path.join(coordinate, 'artifact-1.0.0.aar')); + const output = path.join(root, 'installed.aar'); + await extractFinalAar({ source: tree, output }); + assert(readFileSync(output).equals(bytes)); + symlinkSync(payload, path.join(coordinate, 'second-1.0.0.aar')); + await assert.rejects(extractFinalAar({ source: tree, output }), /exactly one final/u); + rmSync(path.join(coordinate, 'second-1.0.0.aar')); + symlinkSync(root, path.join(tree, 'directory-link')); + await assert.rejects(extractFinalAar({ source: tree, output }), /regular File leaves/u); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('actual source package requirements reject an independently advanced query and undeclared edges', () => { + const root = mkdtempSync(path.join(tmpdir(), 'app-query-requirement-')); + try { + function source(name: string, version: string, dependencies = {}) { + const directory = path.join(root, name.replaceAll('/', '_')); + mkdirSync(directory, { recursive: true }); + writeFileSync( + path.join(directory, 'package.json'), + JSON.stringify({ name, version, dependencies }), + ); + return { + package: name, + version, + dependencies: {}, + source: directory, + integrity: '', + local: true, + }; + } + const rn = source('@oliphaunt/react-native', '0.3.2', { '@oliphaunt/ts-query': '0.1.1' }); + const query = source('@oliphaunt/ts-query', '1.0.0'); + const specification = { + packages: { rn: { ...rn, dependencies: { '@oliphaunt/ts-query': 'query' } }, query }, + roots: { '@oliphaunt/react-native': 'rn' }, + sources: [], + node: '', + tar: '', + }; + assert.throws( + () => stageNodeInputs(path.join(root, 'major'), specification), + /does not satisfy 0\.1\.1/u, + ); + assert.throws( + () => + stageNodeInputs(path.join(root, 'missing'), { + ...specification, + packages: { ...specification.packages, rn }, + }), + /Undeclared npm dependency/u, + ); + assert.throws( + () => + stageNodeInputs(path.join(root, 'extra'), { + ...specification, + packages: { ...specification.packages, rn: { ...rn, dependencies: { wrong: 'query' } } }, + }), + /absent from its conventional manifest/u, + ); + writeFileSync( + path.join(query.source, 'package.json'), + JSON.stringify({ name: query.package, version: '0.1.1' }), + ); + const valid = { + ...specification, + packages: { ...specification.packages, query: { ...query, version: '0.1.1' } }, + }; + stageNodeInputs(path.join(root, 'valid'), valid); + const app = path.join(root, 'app.json'); + writeFileSync( + app, + JSON.stringify({ name: 'app', dependencies: { '@oliphaunt/react-native': '^1.0.0' } }), + ); + assert.throws( + () => + stageNodeInputs(path.join(root, 'app-major'), { + ...valid, + sources: [{ source: app, destination: 'package.json' }], + }), + /does not satisfy \^1\.0\.0/u, + ); + writeFileSync( + app, + JSON.stringify({ name: 'app', dependencies: { '@oliphaunt/react-native': 'workspace:*' } }), + ); + const staged = path.join(root, 'app-workspace'); + stageNodeInputs(staged, { ...valid, sources: [{ source: app, destination: 'package.json' }] }); + assert.equal( + JSON.parse(readFileSync(path.join(staged, 'package.json'), 'utf8')).dependencies[ + '@oliphaunt/react-native' + ], + '0.3.2', + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('completed query bytes retain their File identity despite an equal-version candidate', async () => { + const root = mkdtempSync(path.join(tmpdir(), 'app-query-byte-origin-')); + try { + const packageRoot = path.join(root, 'package'); + mkdirSync(packageRoot); + writeFileSync( + path.join(packageRoot, 'package.json'), + JSON.stringify({ name: '@oliphaunt/ts-query', version: '0.1.1' }), + ); + writeFileSync(path.join(packageRoot, 'query.txt'), 'genuine completed fixture'); + const held = path.join(root, 'held.tgz'); + writeFileSync( + held, + canonicalGzipSync(await createDeterministicTar(packageRoot, { keepParent: true })), + ); + const row = { + package: '@oliphaunt/ts-query', + version: '0.1.1', + dependencies: {}, + integrity: '', + local: true, + origin: 'completed-supplier', + source: held, + sourceSha256: createHash('sha256').update(readFileSync(held)).digest('hex'), + sourceSize: readFileSync(held).length, + }; + writeFileSync(path.join(packageRoot, 'query.txt'), 'unpublished same-version candidate'); + const candidate = path.join(root, 'candidate.tgz'); + writeFileSync( + candidate, + canonicalGzipSync(await createDeterministicTar(packageRoot, { keepParent: true })), + ); + assert.notEqual( + createHash('sha256').update(readFileSync(candidate)).digest('hex'), + row.sourceSha256, + ); + assert.equal( + Buffer.from(readPortableArchiveEntries(held).get('package/query.txt')!.data()).toString(), + 'genuine completed fixture', + ); + const specification = { + packages: { query: row }, + roots: { '@oliphaunt/ts-query': 'query' }, + sources: [], + node: '', + tar: '', + }; + assert.throws( + () => + stageNodeInputs(path.join(root, 'candidate'), { + ...specification, + packages: { + query: { ...row, source: candidate, sourceSize: readFileSync(candidate).length }, + }, + }), + /npm supplier File SHA256/u, + ); + assert.throws( + () => + stageNodeInputs(path.join(root, 'missing-identity'), { + ...specification, + packages: { query: { ...row, sourceSha256: undefined } }, + }), + /Missing completed npm File identity/u, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/build_defs/android/expo_jna_maven_install.json b/build_defs/android/expo_jna_maven_install.json new file mode 100644 index 000000000..21c72e8eb --- /dev/null +++ b/build_defs/android/expo_jna_maven_install.json @@ -0,0 +1,27 @@ +{ + "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL", + "__INPUT_ARTIFACTS_HASH": { + "net.java.dev.jna:jna": -851618841, + "repositories": 514854214 + }, + "__RESOLVED_ARTIFACTS_HASH": { + "net.java.dev.jna:jna:aar": -1226094333 + }, + "artifacts": { + "net.java.dev.jna:jna:aar": { + "shasums": { + "jar": "7f053e3ec99e14dd71259c82c1c8a02738d64a13c31226b2acc170f3060951e0" + }, + "version": "5.18.1" + } + }, + "dependencies": {}, + "packages": {}, + "repositories": { + "https://repo.maven.apache.org/maven2/": [ + "net.java.dev.jna:jna:aar" + ] + }, + "services": {}, + "version": "3" +} diff --git a/build_defs/android/expo_maven_install.json b/build_defs/android/expo_maven_install.json new file mode 100644 index 000000000..60ba85544 --- /dev/null +++ b/build_defs/android/expo_maven_install.json @@ -0,0 +1,2521 @@ +{ + "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL", + "__INPUT_ARTIFACTS_HASH": { + "androidx.annotation:annotation": 1204500264, + "androidx.appcompat:appcompat": 1070792409, + "androidx.appcompat:appcompat-resources": 154212437, + "androidx.autofill:autofill": 967372325, + "androidx.compose.foundation:foundation-android": -834442323, + "androidx.core:core": -1281591424, + "androidx.core:core-ktx": -647332258, + "androidx.core:core-splashscreen": -413729492, + "androidx.documentfile:documentfile": -691246737, + "androidx.swiperefreshlayout:swiperefreshlayout": 353460823, + "androidx.tracing:tracing": 65690631, + "androidx.tracing:tracing-ktx": 1999013030, + "com.facebook.fbjni:fbjni": 940408534, + "com.facebook.fresco:fresco": 684101034, + "com.facebook.fresco:imagepipeline-okhttp3": -817463667, + "com.facebook.fresco:middleware": -1335294634, + "com.facebook.fresco:ui-common": 1225849810, + "com.facebook.hermes:hermes-android": -980353210, + "com.facebook.infer.annotation:infer-annotation": 784609357, + "com.facebook.react:react-android": 1268250470, + "com.facebook.soloader:soloader": -1885653465, + "com.facebook.yoga:proguard-annotations": -308338581, + "com.google.android.material:material": -1189918518, + "com.google.code.findbugs:jsr305": 495355163, + "com.google.code.gson:gson": 1725166461, + "com.squareup.okhttp3:okhttp": 1637802636, + "com.squareup.okhttp3:okhttp-urlconnection": -617628699, + "com.squareup.okio:okio": 1266173280, + "com.squareup.zstd:zstd-kmp-android": 58644506, + "com.squareup.zstd:zstd-kmp-okio-android": -491907265, + "commons-codec:commons-codec": -897489010, + "commons-io:commons-io": -2127699401, + "io.github.lukmccall.pika:pika-api": 1609302375, + "io.github.lukmccall.pika:pika-compiler": -1366226676, + "javax.inject:javax.inject": -297932879, + "net.java.dev.jna:jna": -851618841, + "org.brotli:dec": 1898842695, + "org.jetbrains.kotlin:kotlin-compose-compiler-plugin-embeddable": -2050093030, + "org.jetbrains.kotlin:kotlin-reflect": 361580265, + "org.jetbrains.kotlin:kotlin-serialization-compiler-plugin-embeddable": -97338948, + "org.jetbrains.kotlin:kotlin-stdlib": 52847824, + "org.jetbrains.kotlin:kotlin-stdlib-jdk7": 392332541, + "org.jetbrains.kotlinx:kotlinx-coroutines-android": 1790404246, + "org.jetbrains.kotlinx:kotlinx-coroutines-core": -636748508, + "org.jetbrains:annotations": -628031479, + "repositories": 752543690 + }, + "__RESOLVED_ARTIFACTS_HASH": { + "androidx.activity:activity-ktx:aar": -1566264141, + "androidx.activity:activity:aar": -1964149830, + "androidx.annotation:annotation": 670452758, + "androidx.annotation:annotation-experimental:aar": -274875434, + "androidx.annotation:annotation-jvm": 860215148, + "androidx.appcompat:appcompat-resources:aar": 534245391, + "androidx.appcompat:appcompat:aar": 607027156, + "androidx.arch.core:core-common": 611202792, + "androidx.arch.core:core-runtime:aar": -1655012322, + "androidx.autofill:autofill:aar": 1453288710, + "androidx.cardview:cardview:aar": -1717005938, + "androidx.collection:collection": -298879095, + "androidx.collection:collection-jvm": -908782130, + "androidx.collection:collection-ktx": 943031206, + "androidx.compose.animation:animation-android:aar": 130593434, + "androidx.compose.animation:animation-core-android:aar": 1165819485, + "androidx.compose.animation:animation-core:aar": -2030831694, + "androidx.compose.animation:animation:aar": -503913910, + "androidx.compose.foundation:foundation-android:aar": -913192711, + "androidx.compose.foundation:foundation-layout-android:aar": -1124497629, + "androidx.compose.foundation:foundation-layout:aar": -663822561, + "androidx.compose.runtime:runtime-android:aar": -118768132, + "androidx.compose.runtime:runtime-annotation": -102727280, + "androidx.compose.runtime:runtime-annotation-android:aar": -866072773, + "androidx.compose.runtime:runtime-saveable-android:aar": -1022202291, + "androidx.compose.runtime:runtime-saveable:aar": -1043804509, + "androidx.compose.runtime:runtime:aar": -942141702, + "androidx.compose.ui:ui-android:aar": 1270763253, + "androidx.compose.ui:ui-geometry-android:aar": -637848484, + "androidx.compose.ui:ui-geometry:aar": 1067583561, + "androidx.compose.ui:ui-graphics-android:aar": -1864148199, + "androidx.compose.ui:ui-graphics:aar": -1798852103, + "androidx.compose.ui:ui-text-android:aar": -1429676560, + "androidx.compose.ui:ui-text:aar": -1566004660, + "androidx.compose.ui:ui-unit-android:aar": 1703756212, + "androidx.compose.ui:ui-unit:aar": 1569803646, + "androidx.compose.ui:ui-util-android:aar": -1684311234, + "androidx.compose.ui:ui-util:aar": -2068405563, + "androidx.compose.ui:ui:aar": 1694247292, + "androidx.concurrent:concurrent-futures": -322766184, + "androidx.constraintlayout:constraintlayout-core": 1111076278, + "androidx.constraintlayout:constraintlayout:aar": 1843267340, + "androidx.coordinatorlayout:coordinatorlayout:aar": -1164645966, + "androidx.core:core-ktx:aar": -306684369, + "androidx.core:core-splashscreen:aar": -95496056, + "androidx.core:core-viewtree:aar": 681232394, + "androidx.core:core:aar": 1527284464, + "androidx.cursoradapter:cursoradapter:aar": 193286740, + "androidx.customview:customview-poolingcontainer:aar": -514020606, + "androidx.customview:customview:aar": -298274720, + "androidx.documentfile:documentfile:aar": 660970343, + "androidx.drawerlayout:drawerlayout:aar": -910663570, + "androidx.dynamicanimation:dynamicanimation:aar": 453126862, + "androidx.emoji2:emoji2-views-helper:aar": 1026351345, + "androidx.emoji2:emoji2:aar": -1197561607, + "androidx.fragment:fragment:aar": -1579488496, + "androidx.graphics:graphics-path:aar": 1235981221, + "androidx.graphics:graphics-shapes-android:aar": 1745120114, + "androidx.graphics:graphics-shapes:aar": 1673344018, + "androidx.interpolator:interpolator:aar": 336960548, + "androidx.lifecycle:lifecycle-common": 1628418018, + "androidx.lifecycle:lifecycle-common-jvm": -2007191835, + "androidx.lifecycle:lifecycle-livedata-core-ktx:aar": 1385965451, + "androidx.lifecycle:lifecycle-livedata-core:aar": -421692909, + "androidx.lifecycle:lifecycle-livedata:aar": -345994677, + "androidx.lifecycle:lifecycle-process:aar": 2085929459, + "androidx.lifecycle:lifecycle-runtime-android:aar": -1520648592, + "androidx.lifecycle:lifecycle-runtime-compose-android:aar": -2062594912, + "androidx.lifecycle:lifecycle-runtime-compose:aar": -1345383877, + "androidx.lifecycle:lifecycle-runtime-ktx-android:aar": -1277031917, + "androidx.lifecycle:lifecycle-runtime-ktx:aar": 353146637, + "androidx.lifecycle:lifecycle-runtime:aar": 1944698140, + "androidx.lifecycle:lifecycle-viewmodel-android:aar": -1576885417, + "androidx.lifecycle:lifecycle-viewmodel-ktx:aar": 1404444154, + "androidx.lifecycle:lifecycle-viewmodel-savedstate-android:aar": 292905621, + "androidx.lifecycle:lifecycle-viewmodel-savedstate:aar": 794964695, + "androidx.lifecycle:lifecycle-viewmodel:aar": 1240547690, + "androidx.loader:loader:aar": 1182176909, + "androidx.profileinstaller:profileinstaller:aar": 1064257532, + "androidx.recyclerview:recyclerview:aar": -1582089546, + "androidx.resourceinspection:resourceinspection-annotation": -799871569, + "androidx.savedstate:savedstate-android:aar": 1589562896, + "androidx.savedstate:savedstate-compose-android:aar": -49292896, + "androidx.savedstate:savedstate-compose:aar": -1967127729, + "androidx.savedstate:savedstate-ktx:aar": 355338903, + "androidx.savedstate:savedstate:aar": -1742409190, + "androidx.startup:startup-runtime:aar": 1396418698, + "androidx.swiperefreshlayout:swiperefreshlayout:aar": 685310026, + "androidx.tracing:tracing-ktx:aar": -538594267, + "androidx.tracing:tracing:aar": -581712443, + "androidx.transition:transition:aar": 1585467511, + "androidx.vectordrawable:vectordrawable-animated:aar": 1802847116, + "androidx.vectordrawable:vectordrawable:aar": 913853864, + "androidx.versionedparcelable:versionedparcelable:aar": -1328431944, + "androidx.viewpager2:viewpager2:aar": -1953168621, + "androidx.viewpager:viewpager:aar": 956186941, + "com.facebook.fbjni:fbjni:aar": 409630615, + "com.facebook.fresco:drawee:aar": 404023186, + "com.facebook.fresco:fbcore:aar": -745044185, + "com.facebook.fresco:fresco:aar": -1403366594, + "com.facebook.fresco:imagepipeline-base:aar": 2020738791, + "com.facebook.fresco:imagepipeline-native:aar": -1760927562, + "com.facebook.fresco:imagepipeline-okhttp3:aar": 1975189950, + "com.facebook.fresco:imagepipeline:aar": -2063270345, + "com.facebook.fresco:memory-type-ashmem:aar": 1730953998, + "com.facebook.fresco:memory-type-java:aar": -1306638398, + "com.facebook.fresco:memory-type-native:aar": -794999941, + "com.facebook.fresco:middleware:aar": -1090572361, + "com.facebook.fresco:nativeimagefilters:aar": -1495639660, + "com.facebook.fresco:nativeimagetranscoder:aar": 1211846972, + "com.facebook.fresco:soloader:aar": -680301725, + "com.facebook.fresco:ui-common:aar": -571836737, + "com.facebook.fresco:ui-core:aar": -577510773, + "com.facebook.fresco:urimod:aar": -133293819, + "com.facebook.fresco:vito-source:aar": -1142318020, + "com.facebook.hermes:hermes-android:aar:release": -1327370613, + "com.facebook.infer.annotation:infer-annotation": 139112115, + "com.facebook.react:react-android:aar:release": 1256812193, + "com.facebook.soloader:annotation": 399608007, + "com.facebook.soloader:nativeloader": 1275333757, + "com.facebook.soloader:soloader:aar": 129190513, + "com.facebook.yoga:proguard-annotations": 1383582976, + "com.google.android.material:material:aar": 1062780163, + "com.google.code.findbugs:jsr305": -1038659426, + "com.google.code.gson:gson": -2013579704, + "com.google.errorprone:error_prone_annotations": 1149435946, + "com.google.guava:listenablefuture": -534320814, + "com.parse.bolts:bolts-tasks": -1177529627, + "com.squareup.okhttp3:okhttp": -480529162, + "com.squareup.okhttp3:okhttp-urlconnection": 1122032419, + "com.squareup.okio:okio": 1543097805, + "com.squareup.okio:okio-jvm": -1621716948, + "com.squareup.zstd:zstd-kmp": 977668887, + "com.squareup.zstd:zstd-kmp-android:aar": -1830699819, + "com.squareup.zstd:zstd-kmp-okio-android:aar": 74668321, + "commons-codec:commons-codec": 1115495587, + "commons-io:commons-io": -339874389, + "io.github.lukmccall.pika:pika-api": 639508902, + "io.github.lukmccall.pika:pika-compiler": -674030170, + "javax.inject:javax.inject": -1284481446, + "net.java.dev.jna:jna": -1951542637, + "org.brotli:dec": -359995081, + "org.jetbrains.kotlin:kotlin-annotations-jvm": -1273351479, + "org.jetbrains.kotlin:kotlin-bom": 657634799, + "org.jetbrains.kotlin:kotlin-compose-compiler-plugin-embeddable": 1189931157, + "org.jetbrains.kotlin:kotlin-reflect": -536831069, + "org.jetbrains.kotlin:kotlin-serialization-compiler-plugin-embeddable": 993625312, + "org.jetbrains.kotlin:kotlin-stdlib": -1768306952, + "org.jetbrains.kotlin:kotlin-stdlib-jdk7": -488193720, + "org.jetbrains.kotlin:kotlin-stdlib-jdk8": -550128248, + "org.jetbrains.kotlinx:kotlinx-coroutines-android": 447574043, + "org.jetbrains.kotlinx:kotlinx-coroutines-bom": 1007727196, + "org.jetbrains.kotlinx:kotlinx-coroutines-core": -1637989699, + "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm": 105386653, + "org.jetbrains.kotlinx:kotlinx-serialization-bom": -1951286355, + "org.jetbrains.kotlinx:kotlinx-serialization-core": 1178860864, + "org.jetbrains.kotlinx:kotlinx-serialization-core-jvm": -814436072, + "org.jetbrains:annotations": 1311519737, + "org.jspecify:jspecify": -1402924792 + }, + "artifacts": { + "androidx.activity:activity-ktx:aar": { + "shasums": { + "jar": "bfee12c1c88c3f74954fbf6e6766bc183956f37478b7c024fae7f5b38493d7a5" + }, + "version": "1.8.0" + }, + "androidx.activity:activity:aar": { + "shasums": { + "jar": "d3a676709dea04f2a8506e2ae85052fff763db526ac7f16b04de50fdd05b0720" + }, + "version": "1.8.0" + }, + "androidx.annotation:annotation": { + "shasums": { + "jar": "38322afa7345c37e29c65ec8852178ae1c26e23096a0634d07a4a3893931f58c" + }, + "version": "1.9.1" + }, + "androidx.annotation:annotation-experimental:aar": { + "shasums": { + "jar": "6bd4c7c7476f8260cd3bdbb81183583e93fc9f790c27dea7dc314181cbf87aa0" + }, + "version": "1.4.1" + }, + "androidx.annotation:annotation-jvm": { + "shasums": { + "jar": "1e343917ebf27ba96fe4dc52b1cad7fd32b738fbc6355bb6cd5b3b305d7212d0" + }, + "version": "1.9.1" + }, + "androidx.appcompat:appcompat-resources:aar": { + "shasums": { + "jar": "8e2db31224ca53b108c784da2b361959062716d416b210cfef3d5a3828306df0" + }, + "version": "1.7.1" + }, + "androidx.appcompat:appcompat:aar": { + "shasums": { + "jar": "2ad334a323b28046e89b738c77d184cb3dcca32a551ab048851b2fda23a3ba26" + }, + "version": "1.7.1" + }, + "androidx.arch.core:core-common": { + "shasums": { + "jar": "65308a06b1c00ee186cb9e19321383f043b993813f1522c47f4a3e3303bdba41" + }, + "version": "2.2.0" + }, + "androidx.arch.core:core-runtime:aar": { + "shasums": { + "jar": "a1be5e0caa2b07623862af6ae21b3ab0718123245184d0e30dea81b53f990a47" + }, + "version": "2.2.0" + }, + "androidx.autofill:autofill:aar": { + "shasums": { + "jar": "67ceb8267c274557c35758ebbe44890a203a5579bd2b084df34d70763c72f80f" + }, + "version": "1.1.0" + }, + "androidx.cardview:cardview:aar": { + "shasums": { + "jar": "1193c04c22a3d6b5946dae9f4e8c59d6adde6a71b6bd5d87fb99d82dda1afec7" + }, + "version": "1.0.0" + }, + "androidx.collection:collection": { + "shasums": { + "jar": "f5ffb8f461c4b5d6f2883a2c7047977773b31d5b23ef030c057514c0c9eceb47" + }, + "version": "1.5.0" + }, + "androidx.collection:collection-jvm": { + "shasums": { + "jar": "70b35924e4babcdffa37d0e575ee039c56a2d97123342624c48b603233704341" + }, + "version": "1.5.0" + }, + "androidx.collection:collection-ktx": { + "shasums": { + "jar": "939b4a8697640e77d83e4e8b4c4a9d18f8130198c5961194af8dd9db9dc7c353" + }, + "version": "1.5.0" + }, + "androidx.compose.animation:animation-android:aar": { + "shasums": { + "jar": "788eeac00159aaedd97f685067cf2c87cbf114c21746732653970e3055231322" + }, + "version": "1.9.0" + }, + "androidx.compose.animation:animation-core-android:aar": { + "shasums": { + "jar": "5f90fa63a7cf526dde0ed37e3b65bd18674989006e4beb6d38056c85364401e0" + }, + "version": "1.9.0" + }, + "androidx.compose.animation:animation-core:aar": { + "shasums": { + "jar": "869315419d25ec4faa1f0c9ff3143bc4b9c40efa31046edfa061b867c13a99c8" + }, + "version": "1.9.0" + }, + "androidx.compose.animation:animation:aar": { + "shasums": { + "jar": "2862307e00a841f3fa2e1d98fd309f5b77713dee4ad74b69537c2c2a8db04363" + }, + "version": "1.9.0" + }, + "androidx.compose.foundation:foundation-android:aar": { + "shasums": { + "jar": "691ba463d1e0a5b32d94f0448d692572faadf7a10a9c7460af41b2c430b36782" + }, + "version": "1.9.0" + }, + "androidx.compose.foundation:foundation-layout-android:aar": { + "shasums": { + "jar": "9354b415148840ccbaf216b53161ff2c55ccbec90a94d3466e5e573b4b41f34e" + }, + "version": "1.9.0" + }, + "androidx.compose.foundation:foundation-layout:aar": { + "shasums": { + "jar": "042c31c9970282231bd4fc5ccf6bc4616f8d7c9125cf70b88a1e827620e49eb5" + }, + "version": "1.9.0" + }, + "androidx.compose.runtime:runtime-android:aar": { + "shasums": { + "jar": "6a7036a07bd63778a50d224713a503d11e3a7a42259b5c54a8a46da09d2e5ed7" + }, + "version": "1.9.0" + }, + "androidx.compose.runtime:runtime-annotation": { + "shasums": { + "jar": "a4ad4eb1139a80737755b3ddb7da993697f758f6555486d6eaae59cb8dca19d2" + }, + "version": "1.9.0" + }, + "androidx.compose.runtime:runtime-annotation-android:aar": { + "shasums": { + "jar": "3fba9d6be5307d998403038f6dfaa3fedd924c5618cb45a49f56a5bf6282509d" + }, + "version": "1.9.0" + }, + "androidx.compose.runtime:runtime-saveable-android:aar": { + "shasums": { + "jar": "26efa54576534271d65c5bdf93c34ee9c89dbeca345873730b8f1ac923da3faa" + }, + "version": "1.9.0" + }, + "androidx.compose.runtime:runtime-saveable:aar": { + "shasums": { + "jar": "1803ac4ec6fb62ce5f53b63c636165dff4b93536fc87bb8c4fc8574c0b075108" + }, + "version": "1.9.0" + }, + "androidx.compose.runtime:runtime:aar": { + "shasums": { + "jar": "89130aeb9190b10956ca03e205f70d0378c0a2b1e7989d6b9d33c5c0bde0b145" + }, + "version": "1.9.0" + }, + "androidx.compose.ui:ui-android:aar": { + "shasums": { + "jar": "1393c820e9ae061b58aaddb034003fa9a0e01786928ac628a2e12d2826fbde43" + }, + "version": "1.9.0" + }, + "androidx.compose.ui:ui-geometry-android:aar": { + "shasums": { + "jar": "41c5fa42c90fc24b4d656e837f83cefe0410acc7d114ad78c62bac45098ac6a4" + }, + "version": "1.9.0" + }, + "androidx.compose.ui:ui-geometry:aar": { + "shasums": { + "jar": "8b746413b90d0e28f14b0fabf63bab52962d754e9ae19d009c84af1acc274f62" + }, + "version": "1.9.0" + }, + "androidx.compose.ui:ui-graphics-android:aar": { + "shasums": { + "jar": "d015cda06cdb03ab5471a63960e424941e5f217e6f87e339abd7ceee3929209a" + }, + "version": "1.9.0" + }, + "androidx.compose.ui:ui-graphics:aar": { + "shasums": { + "jar": "28b1cd1773a6b0a7545a554543ae0ded377f584db8dfcd33b5b03090761bd3aa" + }, + "version": "1.9.0" + }, + "androidx.compose.ui:ui-text-android:aar": { + "shasums": { + "jar": "2605e2406625ff0338c888937da22c437af653a2f42afadacaad2174717f5e82" + }, + "version": "1.9.0" + }, + "androidx.compose.ui:ui-text:aar": { + "shasums": { + "jar": "6fcba5c775d19167b490f7d22a506c6783d183d863ce668c644791f16b5118ad" + }, + "version": "1.9.0" + }, + "androidx.compose.ui:ui-unit-android:aar": { + "shasums": { + "jar": "dbeda1aaea03bbd2da1f4df10180346e32cbe8a58239a24f9b8b8cb24202fd8c" + }, + "version": "1.9.0" + }, + "androidx.compose.ui:ui-unit:aar": { + "shasums": { + "jar": "0476675a95ebee3331606711631f80680087363ae1827d35a79e2647ce651d76" + }, + "version": "1.9.0" + }, + "androidx.compose.ui:ui-util-android:aar": { + "shasums": { + "jar": "9376cbd1ddf0655e7105886637ea1451461fcfd3a3ceeecffecceaeebb53410b" + }, + "version": "1.9.0" + }, + "androidx.compose.ui:ui-util:aar": { + "shasums": { + "jar": "5a41f1370ec493812d51e7ad1aa1075dbfaf87631cd08499ab98b9b4d149ee11" + }, + "version": "1.9.0" + }, + "androidx.compose.ui:ui:aar": { + "shasums": { + "jar": "db91d6d907f421761baf918040c4c7ca099670f7ad2bf7a18492b81bf52350ad" + }, + "version": "1.9.0" + }, + "androidx.concurrent:concurrent-futures": { + "shasums": { + "jar": "0ce067c514a0d1049d1bebdf709e344ed3266fe9744275682937cdcb13334e9e" + }, + "version": "1.1.0" + }, + "androidx.constraintlayout:constraintlayout-core": { + "shasums": { + "jar": "496c8c79664bd970c6a6be7a960a20dd157dfc5aa2f18e5b8333767ffbc59911" + }, + "version": "1.0.0" + }, + "androidx.constraintlayout:constraintlayout:aar": { + "shasums": { + "jar": "a458a7562363bd59c209a7dea847326a0e2b26b37a883dc3e29065a79a1c788b" + }, + "version": "2.1.0" + }, + "androidx.coordinatorlayout:coordinatorlayout:aar": { + "shasums": { + "jar": "44a9e30abf56af1025c52a0af506fee9c4131aa55efda52f9fd9451211c5e8cb" + }, + "version": "1.1.0" + }, + "androidx.core:core-ktx:aar": { + "shasums": { + "jar": "4d23190b8623b8abb3c5247a0a7727eca347062d026335c427a09e82711b15f8" + }, + "version": "1.17.0" + }, + "androidx.core:core-splashscreen:aar": { + "shasums": { + "jar": "5ace865c4eb7e0f24369790d2c76eddafd0dbb1ebea3288f55c18d9605ea0ee0" + }, + "version": "1.2.0" + }, + "androidx.core:core-viewtree:aar": { + "shasums": { + "jar": "dc1b678d58ebcf2bfa1587be68ff826694ce3d221251b9ef30d4d4b36297e6de" + }, + "version": "1.0.0" + }, + "androidx.core:core:aar": { + "shasums": { + "jar": "e1bd22bbcf5cee3a992dedb7d2d3c3b31c9f761c01e56d00ea443c8aaa981182" + }, + "version": "1.17.0" + }, + "androidx.cursoradapter:cursoradapter:aar": { + "shasums": { + "jar": "a81c8fe78815fa47df5b749deb52727ad11f9397da58b16017f4eb2c11e28564" + }, + "version": "1.0.0" + }, + "androidx.customview:customview-poolingcontainer:aar": { + "shasums": { + "jar": "3584102fc49bf399c56e3b7be4bfe12000c46112320cd8cf85cc0a8f93f3e752" + }, + "version": "1.0.0" + }, + "androidx.customview:customview:aar": { + "shasums": { + "jar": "01f76ab043770a97b054046f9815717b82ce0355c02967d16c61981359dc189a" + }, + "version": "1.1.0" + }, + "androidx.documentfile:documentfile:aar": { + "shasums": { + "jar": "684e0ffcb21a660c939d1bb814521f42c4bd74816f4a117291fe6a101cf3a822" + }, + "version": "1.1.0" + }, + "androidx.drawerlayout:drawerlayout:aar": { + "shasums": { + "jar": "2c5f0dca378eb78ca2c4403f9889c77daa3059302260f26a07fe9f63c08926fe" + }, + "version": "1.1.1" + }, + "androidx.dynamicanimation:dynamicanimation:aar": { + "shasums": { + "jar": "9062cc6637136a49ad17f8603c72519052ff9a569e617fc1b6db7086304da88f" + }, + "version": "1.1.0" + }, + "androidx.emoji2:emoji2-views-helper:aar": { + "shasums": { + "jar": "ed5d3ed772a5fbf0d570f7526f585cd61a180e60f9372584c328a68e2cff3375" + }, + "version": "1.4.0" + }, + "androidx.emoji2:emoji2:aar": { + "shasums": { + "jar": "433febd3434a45667176c76a64f3f205ca6335a6b544c5b5d57f25a38a375242" + }, + "version": "1.4.0" + }, + "androidx.fragment:fragment:aar": { + "shasums": { + "jar": "bc3c2431dda42e94bb9511c587eae890d276e4aafe393a8da7b00169186dafde" + }, + "version": "1.5.4" + }, + "androidx.graphics:graphics-path:aar": { + "shasums": { + "jar": "8ca4032b6d79b351f0b59ad4b580eddbb9423e1652f7c958830687f1eee2ec03" + }, + "version": "1.0.1" + }, + "androidx.graphics:graphics-shapes-android:aar": { + "shasums": { + "jar": "7171269a4122feabb071768df46d10b362e47ac75fd0aa8dbcafa1f44f61b40c" + }, + "version": "1.0.1" + }, + "androidx.graphics:graphics-shapes:aar": { + "shasums": { + "jar": "b4c92f6af4b4c8febd5091303fbb2e1f7a5f15ea0de3da38eb5c5b02f99dff9a" + }, + "version": "1.0.1" + }, + "androidx.interpolator:interpolator:aar": { + "shasums": { + "jar": "33193135a64fe21fa2c35eec6688f1a76e512606c0fc83dc1b689e37add7732a" + }, + "version": "1.0.0" + }, + "androidx.lifecycle:lifecycle-common": { + "shasums": { + "jar": "0ee8e154c0d4ef0aca4815c4401043e50d1f6f1f6239823ef8abdb69d9b5ee79" + }, + "version": "2.9.0" + }, + "androidx.lifecycle:lifecycle-common-jvm": { + "shasums": { + "jar": "37d89b2101f074ac6c260917dabb185607645ee200aa3018c7c5bde70edcf184" + }, + "version": "2.9.0" + }, + "androidx.lifecycle:lifecycle-livedata-core-ktx:aar": { + "shasums": { + "jar": "f265a665819e51322b3eea2a6ff2ab90186cadf1787a81dd8bef0ce93c4a600a" + }, + "version": "2.9.0" + }, + "androidx.lifecycle:lifecycle-livedata-core:aar": { + "shasums": { + "jar": "64f96b52c70895807f3020e2e8fa11f3ec2da9c157f62aae21a2c9d3b484a747" + }, + "version": "2.9.0" + }, + "androidx.lifecycle:lifecycle-livedata:aar": { + "shasums": { + "jar": "46382ddfba348db97846cfa81d67d72304dc156bb96224358b429fe748bc6ab4" + }, + "version": "2.9.0" + }, + "androidx.lifecycle:lifecycle-process:aar": { + "shasums": { + "jar": "c15ce972cc28936a596a9cd256b32f22768a61d5dd810fa56ba945522a0ee7a5" + }, + "version": "2.9.0" + }, + "androidx.lifecycle:lifecycle-runtime-android:aar": { + "shasums": { + "jar": "d4223ae6a8447677267dff22863b6d6988ca68b4d27ca6d74b81046b04794257" + }, + "version": "2.9.0" + }, + "androidx.lifecycle:lifecycle-runtime-compose-android:aar": { + "shasums": { + "jar": "5f68bcea0cf1daac5320a2fd57157237e30945cf7e6586717fbc714b35b32e6f" + }, + "version": "2.9.0" + }, + "androidx.lifecycle:lifecycle-runtime-compose:aar": { + "shasums": { + "jar": "f0725c1f0c6a0aa334cf109197f902fbebaa734ccc03c03f0ed0ad88e2a107e1" + }, + "version": "2.9.0" + }, + "androidx.lifecycle:lifecycle-runtime-ktx-android:aar": { + "shasums": { + "jar": "333fa2ce6db70ac372b791dfeba99c02c0d97b1a8b4ab4a84d4762466d12b207" + }, + "version": "2.9.0" + }, + "androidx.lifecycle:lifecycle-runtime-ktx:aar": { + "shasums": { + "jar": "f1c6b56258cfb8a994721997ef2c5da59ae3933a809ccf778a3bf78bba76479f" + }, + "version": "2.9.0" + }, + "androidx.lifecycle:lifecycle-runtime:aar": { + "shasums": { + "jar": "142b8d22e93e4a6f3871901493c26e2bdfe1d5da1f88f2d8031d46ec6b6cc12b" + }, + "version": "2.9.0" + }, + "androidx.lifecycle:lifecycle-viewmodel-android:aar": { + "shasums": { + "jar": "fa9d7511a8fe0d5edc53099706d64f37621dcfeb9f2c557369ed83645fc87a23" + }, + "version": "2.9.0" + }, + "androidx.lifecycle:lifecycle-viewmodel-ktx:aar": { + "shasums": { + "jar": "af42fd84f4e52b44dcabaf9ecf94120553929bc1a059beb2240a9ec1dbee814f" + }, + "version": "2.9.0" + }, + "androidx.lifecycle:lifecycle-viewmodel-savedstate-android:aar": { + "shasums": { + "jar": "db367838716e55866823c6deed62fcec23fce487bf2a8fa565a36f149ab3d1ef" + }, + "version": "2.9.0" + }, + "androidx.lifecycle:lifecycle-viewmodel-savedstate:aar": { + "shasums": { + "jar": "ae70b02386c0733b193644c58a42608ad3e4f8e7731eda859f7888405b5f36b9" + }, + "version": "2.9.0" + }, + "androidx.lifecycle:lifecycle-viewmodel:aar": { + "shasums": { + "jar": "cab404b05d5faed209104a2aef14c0cbb316ab9fabe4a8f037b043e5d2f43435" + }, + "version": "2.9.0" + }, + "androidx.loader:loader:aar": { + "shasums": { + "jar": "11f735cb3b55c458d470bed9e25254375b518b4b1bad6926783a7026db0f5025" + }, + "version": "1.0.0" + }, + "androidx.profileinstaller:profileinstaller:aar": { + "shasums": { + "jar": "d502141fcce902430f62b674c32aecd0f75262e7ee2cd15c74adb617cd13130a" + }, + "version": "1.4.0" + }, + "androidx.recyclerview:recyclerview:aar": { + "shasums": { + "jar": "a1ea0329ee6d938305dfd0f8ce5c48dea2aac14e5606d23e7fb60afcfb655d6e" + }, + "version": "1.2.1" + }, + "androidx.resourceinspection:resourceinspection-annotation": { + "shasums": { + "jar": "8cff870ec6fb31db48a52f4a792335b4bf8de07e03bd37823181526433ccd5cb" + }, + "version": "1.0.1" + }, + "androidx.savedstate:savedstate-android:aar": { + "shasums": { + "jar": "210b6909bbd515dbf415905cbb220fca93a87fa546838f754077ebc8e0488590" + }, + "version": "1.3.0" + }, + "androidx.savedstate:savedstate-compose-android:aar": { + "shasums": { + "jar": "ab71562c138019ad6084dc8fc690af6cb9359bfe2743a79062065b28bdef7c6e" + }, + "version": "1.3.0" + }, + "androidx.savedstate:savedstate-compose:aar": { + "shasums": { + "jar": "ddaf6bbd26865e0c22832990d7331a5df1917bc8ce916e79f56ca4dc945f17c4" + }, + "version": "1.3.0" + }, + "androidx.savedstate:savedstate-ktx:aar": { + "shasums": { + "jar": "45c5f6412840f50de7bf7d9b1c4a8c81ea236832487a1138cb320b8c997416f2" + }, + "version": "1.3.0" + }, + "androidx.savedstate:savedstate:aar": { + "shasums": { + "jar": "85ea36f18a33c4acf6ed62747a1b4cbef191f218121ab37a51175d82c5be89ad" + }, + "version": "1.3.0" + }, + "androidx.startup:startup-runtime:aar": { + "shasums": { + "jar": "e0a6329a371262fe4c450372b70fdaf33b769ef6917094723787cfce896b1dd3" + }, + "version": "1.1.1" + }, + "androidx.swiperefreshlayout:swiperefreshlayout:aar": { + "shasums": { + "jar": "2ce7906cd1dea05aec81975db22d54382359c05a21b2527ad848bc60f6b27293" + }, + "version": "1.1.0" + }, + "androidx.tracing:tracing-ktx:aar": { + "shasums": { + "jar": "c33f9cbd931e6190ca38aa09bf8a7a8a19391d4b0fb7a7605a6b59f2d42580d1" + }, + "version": "1.2.0" + }, + "androidx.tracing:tracing:aar": { + "shasums": { + "jar": "6faa90390d1fdbf0adb9a99bf99de67b94c6c6f35aea9510593a9d17973736a2" + }, + "version": "1.2.0" + }, + "androidx.transition:transition:aar": { + "shasums": { + "jar": "0aa66a0ea406d25a1091f96a3b753b4b12e44fdc43b91ec52c17831e9c31f54b" + }, + "version": "1.5.0" + }, + "androidx.vectordrawable:vectordrawable-animated:aar": { + "shasums": { + "jar": "76da2c502371d9c38054df5e2b248d00da87809ed058f3363eae87ce5e2403f8" + }, + "version": "1.1.0" + }, + "androidx.vectordrawable:vectordrawable:aar": { + "shasums": { + "jar": "46fd633ac01b49b7fcabc263bf098c5a8b9e9a69774d234edcca04fb02df8e26" + }, + "version": "1.1.0" + }, + "androidx.versionedparcelable:versionedparcelable:aar": { + "shasums": { + "jar": "57e8d93260d18d5b9007c9eed3c64ad159de90c8609ebfc74a347cbd514535a4" + }, + "version": "1.1.1" + }, + "androidx.viewpager2:viewpager2:aar": { + "shasums": { + "jar": "e95c0031d4cc247cd48196c6287e58d2cee54d9c79b85afea7c90920330275af" + }, + "version": "1.0.0" + }, + "androidx.viewpager:viewpager:aar": { + "shasums": { + "jar": "147af4e14a1984010d8f155e5e19d781f03c1d70dfed02a8e0d18428b8fc8682" + }, + "version": "1.0.0" + }, + "com.facebook.fbjni:fbjni:aar": { + "shasums": { + "jar": "7e319ae110ac5e5ef18904170aea5c3e753e915d196699d7fd39d36c8e1dfe36" + }, + "version": "0.7.0" + }, + "com.facebook.fresco:drawee:aar": { + "shasums": { + "jar": "60435519cb76cee78739d928c46aada918f76cb993b75af92ab17e9d746b0277" + }, + "version": "3.6.0" + }, + "com.facebook.fresco:fbcore:aar": { + "shasums": { + "jar": "6fd98c2b5737ee56a9c90f1c34d87d24e5d3324fd7fc2cca6d6e74b1c0b43ce9" + }, + "version": "3.6.0" + }, + "com.facebook.fresco:fresco:aar": { + "shasums": { + "jar": "db82128c0b0d209b2f48afd84292c5f54b3bfe407b28fa32babfde95914b03f9" + }, + "version": "3.6.0" + }, + "com.facebook.fresco:imagepipeline-base:aar": { + "shasums": { + "jar": "69caad07fe3700b48f3b56662504f9c1235da2e977b8eacd9df251321e9649c6" + }, + "version": "3.6.0" + }, + "com.facebook.fresco:imagepipeline-native:aar": { + "shasums": { + "jar": "5cbeafb0f7d91c078e256bb1af2981493f37b2a386df43593109d6abef7792d9" + }, + "version": "3.6.0" + }, + "com.facebook.fresco:imagepipeline-okhttp3:aar": { + "shasums": { + "jar": "faa01ed0394a5ec86cfe9c06e106a32179e4fb8378e7aeefde58321594ba6593" + }, + "version": "3.6.0" + }, + "com.facebook.fresco:imagepipeline:aar": { + "shasums": { + "jar": "57f04195e5d7273671ce467d0e23c487b3c2c8746ac6257f2a2753cc0771f69f" + }, + "version": "3.6.0" + }, + "com.facebook.fresco:memory-type-ashmem:aar": { + "shasums": { + "jar": "0b2b1a8d7d6e5806312c4b7b46a15537e3ad12a7aa9fc3ac262465303082b946" + }, + "version": "3.6.0" + }, + "com.facebook.fresco:memory-type-java:aar": { + "shasums": { + "jar": "4504fdc563e699748b300f3e35279be0918c04981e7ef61f919663dbd69e683f" + }, + "version": "3.6.0" + }, + "com.facebook.fresco:memory-type-native:aar": { + "shasums": { + "jar": "cdc0cce108bcab69da2b761eed389e4792f994b03b524bd826316c2932eb0cf8" + }, + "version": "3.6.0" + }, + "com.facebook.fresco:middleware:aar": { + "shasums": { + "jar": "9661f47cb1156a0a7246819802c9b017ba5170f6ae7abedf31fd2cf662e3dc10" + }, + "version": "3.6.0" + }, + "com.facebook.fresco:nativeimagefilters:aar": { + "shasums": { + "jar": "5044745e85fb35177e8e2b80df82c02a968a6db88affe711e4fb0038924d32bd" + }, + "version": "3.6.0" + }, + "com.facebook.fresco:nativeimagetranscoder:aar": { + "shasums": { + "jar": "0d8f8559617c88763dc75e6005fc60e37bfd6bb20fe5b97a187cabefc2b11a7c" + }, + "version": "3.6.0" + }, + "com.facebook.fresco:soloader:aar": { + "shasums": { + "jar": "fbbe0a37d91b86d4320d0728040c3264599a94b31a1de41f92a25e147f7f35ef" + }, + "version": "3.6.0" + }, + "com.facebook.fresco:ui-common:aar": { + "shasums": { + "jar": "001e310264c8bace79243d16ac03fb60bae7adfc2c4ac0c66b0006c249208ff0" + }, + "version": "3.6.0" + }, + "com.facebook.fresco:ui-core:aar": { + "shasums": { + "jar": "b515c69ba120c61ea157e2596ddf3a9226339c0e6acfc96b50bf966149b1c141" + }, + "version": "3.6.0" + }, + "com.facebook.fresco:urimod:aar": { + "shasums": { + "jar": "54bc0886e579eb0833297492b7d89cb4c613ca95c379bacc41adfe29539a91f7" + }, + "version": "3.6.0" + }, + "com.facebook.fresco:vito-source:aar": { + "shasums": { + "jar": "b5c3c5c087dab199ac8afe8397fa89ccf386df7b29a8db77b36125576af2e491" + }, + "version": "3.6.0" + }, + "com.facebook.hermes:hermes-android:aar": { + "shasums": { + "release": "1496dd015a2c224a93863e3e0de7681f80808d7f6796c5fee65494c48bdc8949" + }, + "version": "250829098.0.10" + }, + "com.facebook.infer.annotation:infer-annotation": { + "shasums": { + "jar": "caefba935643dc962758a760f1627a402215af034d96c0f484d63b7fddca992f" + }, + "version": "0.18.0" + }, + "com.facebook.react:react-android:aar": { + "shasums": { + "release": "435467261a5ea8a8203eb07fb0c024cc928c17fa3fe06b2fec8b094d842af52f" + }, + "version": "0.85.3" + }, + "com.facebook.soloader:annotation": { + "shasums": { + "jar": "f6ddd55268bf1824225df7a35ec1b8b33cf98855a6c9c153d189899e5ef4a418" + }, + "version": "0.12.1" + }, + "com.facebook.soloader:nativeloader": { + "shasums": { + "jar": "971ded86009c0ac56fb2275e128f852e7dcbc41a40cd799688f8a1aebde5195d" + }, + "version": "0.12.1" + }, + "com.facebook.soloader:soloader:aar": { + "shasums": { + "jar": "5bc6e15d712f90a0a3890d22db0eef5fe89ef3fcb3ae8aa1f8f6a6d99547c892" + }, + "version": "0.12.1" + }, + "com.facebook.yoga:proguard-annotations": { + "shasums": { + "jar": "fb65f706eea05b5640fb6b93d21d6c41f9e2b4e7a6e6d9f28ce9d2a574474995" + }, + "version": "1.19.0" + }, + "com.google.android.material:material:aar": { + "shasums": { + "jar": "6d5e1cbb67c05bcdcbbf84005787dafd354a155f59a4d3800fd45fa7eb3689f5" + }, + "version": "1.13.0" + }, + "com.google.code.findbugs:jsr305": { + "shasums": { + "jar": "766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7" + }, + "version": "3.0.2" + }, + "com.google.code.gson:gson": { + "shasums": { + "jar": "c8fb4839054d280b3033f800d1f5a97de2f028eb8ba2eb458ad287e536f3f25f" + }, + "version": "2.8.6" + }, + "com.google.errorprone:error_prone_annotations": { + "shasums": { + "jar": "067047714349e7789a5bdbfad9d1c0af9f3a1eb28c55a0ee3f68e682f905c4eb" + }, + "version": "2.15.0" + }, + "com.google.guava:listenablefuture": { + "shasums": { + "jar": "e4ad7607e5c0477c6f890ef26a49cb8d1bb4dffb650bab4502afee64644e3069" + }, + "version": "1.0" + }, + "com.parse.bolts:bolts-tasks": { + "shasums": { + "jar": "9bc51e3eca853a9df2fbac62c2317db2c9ea619b95b5531c30440243daaccee2" + }, + "version": "1.4.0" + }, + "com.squareup.okhttp3:okhttp": { + "shasums": { + "jar": "3b2ee1b768c1df28c30d2fe6b38dda4d2c519210e30ca3d27950618c563c92de" + }, + "version": "4.9.2" + }, + "com.squareup.okhttp3:okhttp-urlconnection": { + "shasums": { + "jar": "0e1c39aa89668f9625c9207acd4a8784dc868ad0d5a2011d9e15e0674f3b7d11" + }, + "version": "4.9.2" + }, + "com.squareup.okio:okio": { + "shasums": { + "jar": "e1710de2b36b3bbc6e610623db8062a7fbfd0659d7ec83a07a71b63ed1e43337" + }, + "version": "3.16.0" + }, + "com.squareup.okio:okio-jvm": { + "shasums": { + "jar": "c737c035ca675187bf11a67ddb9581954bf0d5ca9f3e048e838b3267cf32b5c3" + }, + "version": "3.16.0" + }, + "com.squareup.zstd:zstd-kmp": { + "shasums": { + "jar": "b283270922372f5b6f5a25e36f4de5d06af58fb63e09484136a1a0c7e298cf09" + }, + "version": "0.4.0" + }, + "com.squareup.zstd:zstd-kmp-android:aar": { + "shasums": { + "jar": "2778570454ae78026df42ace7168b8a6500f2521a5d497f2ab2fc0f804247826" + }, + "version": "0.4.0" + }, + "com.squareup.zstd:zstd-kmp-okio-android:aar": { + "shasums": { + "jar": "8461ece75b646bfe30f6f53a559c2eac82f745f3575d76648386182ffa7c873d" + }, + "version": "0.4.0" + }, + "commons-codec:commons-codec": { + "shasums": { + "jar": "4241dfa94e711d435f29a4604a3e2de5c4aa3c165e23bd066be6fc1fc4309569" + }, + "version": "1.10" + }, + "commons-io:commons-io": { + "shasums": { + "jar": "a7f713593007813bf07d19bd1df9f81c86c0719e9a0bb2ef1b98b78313fc940d" + }, + "version": "1.4" + }, + "io.github.lukmccall.pika:pika-api": { + "shasums": { + "jar": "60d7fb7d2231daf6ce48c6616c07ec9f0fcd10ae9954ef16ddbb27f99cf9da6e" + }, + "version": "0.3.2" + }, + "io.github.lukmccall.pika:pika-compiler": { + "shasums": { + "jar": "d3354c1859cddfaaca638db5ae852e34adc296d9d9a3bf8a3b07de7f24714e9e" + }, + "version": "0.3.2-2.2.21" + }, + "javax.inject:javax.inject": { + "shasums": { + "jar": "91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff" + }, + "version": "1" + }, + "net.java.dev.jna:jna": { + "shasums": { + "jar": "260c4b1e22b1db9e110ee441c4f13ce115f841fa48c41d78750986214b395557" + }, + "version": "5.18.1" + }, + "org.brotli:dec": { + "shasums": { + "jar": "615c0c3efef990d77831104475fba6a1f7971388691d4bad1471ad84101f6d52" + }, + "version": "0.1.2" + }, + "org.jetbrains.kotlin:kotlin-annotations-jvm": { + "shasums": { + "jar": "3ee3a56dd451e33f8352e0d2803a55ca1b9156d7f8a8e0759bf8e187ff8db24a" + }, + "version": "1.3.72" + }, + "org.jetbrains.kotlin:kotlin-bom": { + "shasums": { + "jar": null + }, + "version": "1.8.22" + }, + "org.jetbrains.kotlin:kotlin-compose-compiler-plugin-embeddable": { + "shasums": { + "jar": "bd6b2db8bbf5ef1c12888ae885b72054e70cea7ef4d6e8bb5eca4faa0539393f" + }, + "version": "2.2.21" + }, + "org.jetbrains.kotlin:kotlin-reflect": { + "shasums": { + "jar": "44380abf37d245ce5c0f294f43512d1c39a59642bfa463922c74e96877cf49f8" + }, + "version": "2.2.21" + }, + "org.jetbrains.kotlin:kotlin-serialization-compiler-plugin-embeddable": { + "shasums": { + "jar": "c5e725c13ccb9f0d2d978cb10997b2972d7d46bef4a5aaa502637ec307478f46" + }, + "version": "2.2.21" + }, + "org.jetbrains.kotlin:kotlin-stdlib": { + "shasums": { + "jar": "6558a3d233da56a20934b32159f9db5f86ed5816ef098f78a2c223dc6abb79dd" + }, + "version": "2.2.21" + }, + "org.jetbrains.kotlin:kotlin-stdlib-jdk7": { + "shasums": { + "jar": "b785922f11e6d91a6dd1d75cb0aef1ce37b83f8de0e3a2139139dfb823bb8a2c" + }, + "version": "2.2.21" + }, + "org.jetbrains.kotlin:kotlin-stdlib-jdk8": { + "shasums": { + "jar": "4198b0eaf090a4f25b6f7e5a59581f4314ba8c9f6cd1d13ee9d348e65ed8f707" + }, + "version": "1.8.22" + }, + "org.jetbrains.kotlinx:kotlinx-coroutines-android": { + "shasums": { + "jar": "e713f1f874244115a07571065cffa0f24f5e78300e9720fea16de3af1d75fd41" + }, + "version": "1.10.2" + }, + "org.jetbrains.kotlinx:kotlinx-coroutines-bom": { + "shasums": { + "jar": null + }, + "version": "1.10.2" + }, + "org.jetbrains.kotlinx:kotlinx-coroutines-core": { + "shasums": { + "jar": "319b653009d49c70982f98df29cc84fc7025b092cb0571c8e7532e3ad4366dae" + }, + "version": "1.10.2" + }, + "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm": { + "shasums": { + "jar": "5ca175b38df331fd64155b35cd8cae1251fa9ee369709b36d42e0a288ccce3fd" + }, + "version": "1.10.2" + }, + "org.jetbrains.kotlinx:kotlinx-serialization-bom": { + "shasums": { + "jar": null + }, + "version": "1.7.3" + }, + "org.jetbrains.kotlinx:kotlinx-serialization-core": { + "shasums": { + "jar": "4850682e0e5976862695330d84eb8699f1dc5d50849f625263995cc88bc6f37b" + }, + "version": "1.7.3" + }, + "org.jetbrains.kotlinx:kotlinx-serialization-core-jvm": { + "shasums": { + "jar": "f0adde45864144475385cf4aa7e0b7feb27f61fcf9472665ed98cc971b06b1eb" + }, + "version": "1.7.3" + }, + "org.jetbrains:annotations": { + "shasums": { + "jar": "7b0f19724082cbfcbc66e5abea2b9bc92cf08a1ea11e191933ed43801eb3cd05" + }, + "version": "23.0.0" + }, + "org.jspecify:jspecify": { + "shasums": { + "jar": "1fad6e6be7557781e4d33729d49ae1cdc8fdda6fe477bb0cc68ce351eafdfbab" + }, + "version": "1.0.0" + } + }, + "conflict_resolution": { + "androidx.activity:activity-ktx:aar:1.7.0": "androidx.activity:activity-ktx:aar:1.8.0", + "androidx.activity:activity:aar:1.5.1": "androidx.activity:activity:aar:1.8.0", + "androidx.annotation:annotation-experimental:aar:1.0.0": "androidx.annotation:annotation-experimental:aar:1.4.1", + "androidx.appcompat:appcompat-resources:aar:1.7.0": "androidx.appcompat:appcompat-resources:aar:1.7.1", + "androidx.collection:collection-ktx:1.4.2": "androidx.collection:collection-ktx:1.5.0", + "androidx.collection:collection:1.4.2": "androidx.collection:collection:1.5.0", + "androidx.compose.animation:animation-core:aar:1.2.1": "androidx.compose.animation:animation-core:aar:1.9.0", + "androidx.compose.runtime:runtime:aar:1.7.1": "androidx.compose.runtime:runtime:aar:1.9.0", + "androidx.concurrent:concurrent-futures:1.0.0": "androidx.concurrent:concurrent-futures:1.1.0", + "androidx.customview:customview:aar:1.0.0": "androidx.customview:customview:aar:1.1.0", + "androidx.drawerlayout:drawerlayout:aar:1.0.0": "androidx.drawerlayout:drawerlayout:aar:1.1.1", + "androidx.dynamicanimation:dynamicanimation:aar:1.0.0": "androidx.dynamicanimation:dynamicanimation:aar:1.1.0", + "androidx.emoji2:emoji2-views-helper:aar:1.2.0": "androidx.emoji2:emoji2-views-helper:aar:1.4.0", + "androidx.emoji2:emoji2:aar:1.3.0": "androidx.emoji2:emoji2:aar:1.4.0", + "androidx.fragment:fragment:aar:1.2.5": "androidx.fragment:fragment:aar:1.5.4", + "androidx.lifecycle:lifecycle-common:2.6.2": "androidx.lifecycle:lifecycle-common:2.9.0", + "androidx.lifecycle:lifecycle-livedata-core:aar:2.5.1": "androidx.lifecycle:lifecycle-livedata-core:aar:2.9.0", + "androidx.lifecycle:lifecycle-livedata:aar:2.0.0": "androidx.lifecycle:lifecycle-livedata:aar:2.9.0", + "androidx.lifecycle:lifecycle-process:aar:2.4.1": "androidx.lifecycle:lifecycle-process:aar:2.9.0", + "androidx.lifecycle:lifecycle-runtime-compose:aar:2.8.7": "androidx.lifecycle:lifecycle-runtime-compose:aar:2.9.0", + "androidx.lifecycle:lifecycle-runtime-ktx:aar:2.6.1": "androidx.lifecycle:lifecycle-runtime-ktx:aar:2.9.0", + "androidx.lifecycle:lifecycle-runtime:aar:2.0.0": "androidx.lifecycle:lifecycle-runtime:aar:2.9.0", + "androidx.lifecycle:lifecycle-viewmodel-ktx:aar:2.8.7": "androidx.lifecycle:lifecycle-viewmodel-ktx:aar:2.9.0", + "androidx.lifecycle:lifecycle-viewmodel-savedstate:aar:2.5.1": "androidx.lifecycle:lifecycle-viewmodel-savedstate:aar:2.9.0", + "androidx.lifecycle:lifecycle-viewmodel:aar:2.0.0": "androidx.lifecycle:lifecycle-viewmodel:aar:2.9.0", + "androidx.profileinstaller:profileinstaller:aar:1.3.0": "androidx.profileinstaller:profileinstaller:aar:1.4.0", + "androidx.recyclerview:recyclerview:aar:1.1.0": "androidx.recyclerview:recyclerview:aar:1.2.1", + "androidx.savedstate:savedstate-ktx:aar:1.2.1": "androidx.savedstate:savedstate-ktx:aar:1.3.0", + "androidx.savedstate:savedstate:aar:1.2.1": "androidx.savedstate:savedstate:aar:1.3.0", + "androidx.startup:startup-runtime:aar:1.0.0": "androidx.startup:startup-runtime:aar:1.1.1", + "androidx.tracing:tracing:aar:1.0.0": "androidx.tracing:tracing:aar:1.2.0", + "com.facebook.soloader:annotation:0.11.0": "com.facebook.soloader:annotation:0.12.1", + "com.facebook.soloader:nativeloader:0.10.5": "com.facebook.soloader:nativeloader:0.12.1", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.10": "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22" + }, + "dependencies": { + "androidx.activity:activity-ktx:aar": [ + "androidx.activity:activity:aar", + "androidx.core:core-ktx:aar", + "androidx.lifecycle:lifecycle-runtime-ktx:aar", + "androidx.lifecycle:lifecycle-viewmodel-ktx:aar", + "androidx.savedstate:savedstate-ktx:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.activity:activity:aar": [ + "androidx.annotation:annotation", + "androidx.collection:collection", + "androidx.core:core:aar", + "androidx.lifecycle:lifecycle-runtime:aar", + "androidx.lifecycle:lifecycle-viewmodel-savedstate:aar", + "androidx.lifecycle:lifecycle-viewmodel:aar", + "androidx.profileinstaller:profileinstaller:aar", + "androidx.savedstate:savedstate:aar", + "androidx.tracing:tracing:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.annotation:annotation": [ + "androidx.annotation:annotation-jvm" + ], + "androidx.annotation:annotation-experimental:aar": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.annotation:annotation-jvm": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.appcompat:appcompat-resources:aar": [ + "androidx.annotation:annotation", + "androidx.collection:collection", + "androidx.core:core:aar", + "androidx.vectordrawable:vectordrawable-animated:aar", + "androidx.vectordrawable:vectordrawable:aar" + ], + "androidx.appcompat:appcompat:aar": [ + "androidx.activity:activity:aar", + "androidx.annotation:annotation", + "androidx.appcompat:appcompat-resources:aar", + "androidx.collection:collection", + "androidx.core:core-ktx:aar", + "androidx.core:core:aar", + "androidx.cursoradapter:cursoradapter:aar", + "androidx.drawerlayout:drawerlayout:aar", + "androidx.emoji2:emoji2-views-helper:aar", + "androidx.emoji2:emoji2:aar", + "androidx.fragment:fragment:aar", + "androidx.lifecycle:lifecycle-runtime:aar", + "androidx.lifecycle:lifecycle-viewmodel:aar", + "androidx.profileinstaller:profileinstaller:aar", + "androidx.resourceinspection:resourceinspection-annotation", + "androidx.savedstate:savedstate:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.arch.core:core-common": [ + "androidx.annotation:annotation" + ], + "androidx.arch.core:core-runtime:aar": [ + "androidx.annotation:annotation", + "androidx.arch.core:core-common" + ], + "androidx.autofill:autofill:aar": [ + "androidx.core:core:aar" + ], + "androidx.cardview:cardview:aar": [ + "androidx.annotation:annotation" + ], + "androidx.collection:collection": [ + "androidx.collection:collection-jvm" + ], + "androidx.collection:collection-jvm": [ + "androidx.annotation:annotation", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.collection:collection-ktx": [ + "androidx.collection:collection" + ], + "androidx.compose.animation:animation-android:aar": [ + "androidx.annotation:annotation", + "androidx.annotation:annotation-experimental:aar", + "androidx.collection:collection", + "androidx.compose.animation:animation-core:aar", + "androidx.compose.foundation:foundation-layout:aar", + "androidx.compose.runtime:runtime:aar", + "androidx.compose.ui:ui-geometry:aar", + "androidx.compose.ui:ui-graphics:aar", + "androidx.compose.ui:ui-util:aar", + "androidx.compose.ui:ui:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.compose.animation:animation-core-android:aar": [ + "androidx.annotation:annotation", + "androidx.collection:collection", + "androidx.compose.runtime:runtime:aar", + "androidx.compose.ui:ui-graphics:aar", + "androidx.compose.ui:ui-unit:aar", + "androidx.compose.ui:ui-util:aar", + "androidx.compose.ui:ui:aar", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlinx:kotlinx-coroutines-core" + ], + "androidx.compose.animation:animation-core:aar": [ + "androidx.compose.animation:animation-core-android:aar" + ], + "androidx.compose.animation:animation:aar": [ + "androidx.compose.animation:animation-android:aar" + ], + "androidx.compose.foundation:foundation-android:aar": [ + "androidx.annotation:annotation", + "androidx.annotation:annotation-experimental:aar", + "androidx.collection:collection", + "androidx.compose.animation:animation:aar", + "androidx.compose.foundation:foundation-layout:aar", + "androidx.compose.runtime:runtime:aar", + "androidx.compose.ui:ui-text:aar", + "androidx.compose.ui:ui-util:aar", + "androidx.compose.ui:ui:aar", + "androidx.core:core:aar", + "androidx.emoji2:emoji2:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.compose.foundation:foundation-layout-android:aar": [ + "androidx.annotation:annotation", + "androidx.annotation:annotation-experimental:aar", + "androidx.collection:collection", + "androidx.compose.animation:animation-core:aar", + "androidx.compose.runtime:runtime:aar", + "androidx.compose.ui:ui-unit:aar", + "androidx.compose.ui:ui-util:aar", + "androidx.compose.ui:ui:aar", + "androidx.core:core:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.compose.foundation:foundation-layout:aar": [ + "androidx.compose.foundation:foundation-layout-android:aar" + ], + "androidx.compose.runtime:runtime-android:aar": [ + "androidx.annotation:annotation-experimental:aar", + "androidx.collection:collection", + "androidx.compose.runtime:runtime-annotation", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlinx:kotlinx-coroutines-android", + "org.jetbrains.kotlinx:kotlinx-coroutines-core" + ], + "androidx.compose.runtime:runtime-annotation": [ + "androidx.compose.runtime:runtime-annotation-android:aar" + ], + "androidx.compose.runtime:runtime-annotation-android:aar": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.compose.runtime:runtime-saveable-android:aar": [ + "androidx.annotation:annotation", + "androidx.collection:collection", + "androidx.compose.runtime:runtime:aar", + "androidx.lifecycle:lifecycle-runtime-compose:aar", + "androidx.savedstate:savedstate-compose:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.compose.runtime:runtime-saveable:aar": [ + "androidx.compose.runtime:runtime-saveable-android:aar" + ], + "androidx.compose.runtime:runtime:aar": [ + "androidx.compose.runtime:runtime-android:aar" + ], + "androidx.compose.ui:ui-android:aar": [ + "androidx.activity:activity-ktx:aar", + "androidx.annotation:annotation", + "androidx.annotation:annotation-experimental:aar", + "androidx.autofill:autofill:aar", + "androidx.collection:collection", + "androidx.compose.runtime:runtime-saveable:aar", + "androidx.compose.runtime:runtime:aar", + "androidx.compose.ui:ui-geometry:aar", + "androidx.compose.ui:ui-graphics:aar", + "androidx.compose.ui:ui-text:aar", + "androidx.compose.ui:ui-unit:aar", + "androidx.compose.ui:ui-util:aar", + "androidx.core:core:aar", + "androidx.customview:customview-poolingcontainer:aar", + "androidx.emoji2:emoji2:aar", + "androidx.lifecycle:lifecycle-runtime-compose:aar", + "androidx.lifecycle:lifecycle-viewmodel-ktx:aar", + "androidx.lifecycle:lifecycle-viewmodel:aar", + "androidx.profileinstaller:profileinstaller:aar", + "androidx.savedstate:savedstate-compose:aar", + "androidx.savedstate:savedstate-ktx:aar", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlinx:kotlinx-coroutines-android", + "org.jetbrains.kotlinx:kotlinx-coroutines-core", + "org.jspecify:jspecify" + ], + "androidx.compose.ui:ui-geometry-android:aar": [ + "androidx.annotation:annotation", + "androidx.compose.runtime:runtime:aar", + "androidx.compose.ui:ui-util:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.compose.ui:ui-geometry:aar": [ + "androidx.compose.ui:ui-geometry-android:aar" + ], + "androidx.compose.ui:ui-graphics-android:aar": [ + "androidx.annotation:annotation", + "androidx.annotation:annotation-experimental:aar", + "androidx.collection:collection", + "androidx.compose.runtime:runtime:aar", + "androidx.compose.ui:ui-unit:aar", + "androidx.compose.ui:ui-util:aar", + "androidx.core:core:aar", + "androidx.graphics:graphics-path:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.compose.ui:ui-graphics:aar": [ + "androidx.compose.ui:ui-graphics-android:aar" + ], + "androidx.compose.ui:ui-text-android:aar": [ + "androidx.annotation:annotation", + "androidx.annotation:annotation-experimental:aar", + "androidx.collection:collection", + "androidx.compose.runtime:runtime-saveable:aar", + "androidx.compose.runtime:runtime:aar", + "androidx.compose.ui:ui-graphics:aar", + "androidx.compose.ui:ui-unit:aar", + "androidx.compose.ui:ui-util:aar", + "androidx.core:core:aar", + "androidx.emoji2:emoji2:aar", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlinx:kotlinx-coroutines-core" + ], + "androidx.compose.ui:ui-text:aar": [ + "androidx.compose.ui:ui-text-android:aar" + ], + "androidx.compose.ui:ui-unit-android:aar": [ + "androidx.annotation:annotation", + "androidx.annotation:annotation-experimental:aar", + "androidx.collection:collection", + "androidx.collection:collection-ktx", + "androidx.compose.runtime:runtime:aar", + "androidx.compose.ui:ui-geometry:aar", + "androidx.compose.ui:ui-util:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.compose.ui:ui-unit:aar": [ + "androidx.compose.ui:ui-unit-android:aar" + ], + "androidx.compose.ui:ui-util-android:aar": [ + "androidx.annotation:annotation-experimental:aar", + "androidx.collection:collection", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.compose.ui:ui-util:aar": [ + "androidx.compose.ui:ui-util-android:aar" + ], + "androidx.compose.ui:ui:aar": [ + "androidx.compose.ui:ui-android:aar" + ], + "androidx.concurrent:concurrent-futures": [ + "androidx.annotation:annotation", + "com.google.guava:listenablefuture" + ], + "androidx.constraintlayout:constraintlayout:aar": [ + "androidx.appcompat:appcompat:aar", + "androidx.constraintlayout:constraintlayout-core", + "androidx.core:core:aar" + ], + "androidx.coordinatorlayout:coordinatorlayout:aar": [ + "androidx.annotation:annotation", + "androidx.collection:collection", + "androidx.core:core:aar", + "androidx.customview:customview:aar" + ], + "androidx.core:core-ktx:aar": [ + "androidx.annotation:annotation", + "androidx.core:core:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.core:core-splashscreen:aar": [ + "androidx.annotation:annotation", + "androidx.appcompat:appcompat-resources:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.core:core-viewtree:aar": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.core:core:aar": [ + "androidx.annotation:annotation", + "androidx.annotation:annotation-experimental:aar", + "androidx.collection:collection", + "androidx.concurrent:concurrent-futures", + "androidx.core:core-viewtree:aar", + "androidx.interpolator:interpolator:aar", + "androidx.lifecycle:lifecycle-common", + "androidx.lifecycle:lifecycle-runtime:aar", + "androidx.tracing:tracing:aar", + "androidx.versionedparcelable:versionedparcelable:aar", + "com.google.guava:listenablefuture", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlinx:kotlinx-coroutines-core", + "org.jspecify:jspecify" + ], + "androidx.cursoradapter:cursoradapter:aar": [ + "androidx.annotation:annotation" + ], + "androidx.customview:customview-poolingcontainer:aar": [ + "androidx.core:core-ktx:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.customview:customview:aar": [ + "androidx.annotation:annotation", + "androidx.collection:collection", + "androidx.core:core:aar" + ], + "androidx.documentfile:documentfile:aar": [ + "androidx.annotation:annotation", + "androidx.core:core:aar", + "org.jspecify:jspecify" + ], + "androidx.drawerlayout:drawerlayout:aar": [ + "androidx.annotation:annotation", + "androidx.core:core:aar", + "androidx.customview:customview:aar" + ], + "androidx.dynamicanimation:dynamicanimation:aar": [ + "androidx.collection:collection", + "androidx.core:core:aar", + "org.jspecify:jspecify" + ], + "androidx.emoji2:emoji2-views-helper:aar": [ + "androidx.collection:collection", + "androidx.core:core:aar", + "androidx.emoji2:emoji2:aar" + ], + "androidx.emoji2:emoji2:aar": [ + "androidx.annotation:annotation", + "androidx.collection:collection", + "androidx.core:core:aar", + "androidx.lifecycle:lifecycle-process:aar", + "androidx.startup:startup-runtime:aar" + ], + "androidx.fragment:fragment:aar": [ + "androidx.activity:activity:aar", + "androidx.annotation:annotation", + "androidx.annotation:annotation-experimental:aar", + "androidx.collection:collection", + "androidx.core:core-ktx:aar", + "androidx.lifecycle:lifecycle-livedata-core:aar", + "androidx.lifecycle:lifecycle-viewmodel-savedstate:aar", + "androidx.lifecycle:lifecycle-viewmodel:aar", + "androidx.loader:loader:aar", + "androidx.savedstate:savedstate:aar", + "androidx.viewpager:viewpager:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.graphics:graphics-path:aar": [ + "androidx.core:core:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.graphics:graphics-shapes-android:aar": [ + "androidx.annotation:annotation", + "androidx.annotation:annotation-experimental:aar", + "androidx.collection:collection", + "androidx.core:core-ktx:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.graphics:graphics-shapes:aar": [ + "androidx.graphics:graphics-shapes-android:aar" + ], + "androidx.interpolator:interpolator:aar": [ + "androidx.annotation:annotation" + ], + "androidx.lifecycle:lifecycle-common": [ + "androidx.lifecycle:lifecycle-common-jvm" + ], + "androidx.lifecycle:lifecycle-common-jvm": [ + "androidx.annotation:annotation", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlinx:kotlinx-coroutines-core", + "org.jspecify:jspecify" + ], + "androidx.lifecycle:lifecycle-livedata-core-ktx:aar": [ + "androidx.lifecycle:lifecycle-livedata-core:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.lifecycle:lifecycle-livedata-core:aar": [ + "androidx.arch.core:core-common", + "androidx.arch.core:core-runtime:aar", + "androidx.lifecycle:lifecycle-common", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jspecify:jspecify" + ], + "androidx.lifecycle:lifecycle-livedata:aar": [ + "androidx.arch.core:core-common", + "androidx.arch.core:core-runtime:aar", + "androidx.lifecycle:lifecycle-livedata-core-ktx:aar", + "androidx.lifecycle:lifecycle-livedata-core:aar", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlinx:kotlinx-coroutines-core", + "org.jspecify:jspecify" + ], + "androidx.lifecycle:lifecycle-process:aar": [ + "androidx.annotation:annotation", + "androidx.lifecycle:lifecycle-runtime:aar", + "androidx.startup:startup-runtime:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.lifecycle:lifecycle-runtime-android:aar": [ + "androidx.annotation:annotation", + "androidx.arch.core:core-common", + "androidx.arch.core:core-runtime:aar", + "androidx.core:core-viewtree:aar", + "androidx.lifecycle:lifecycle-common", + "androidx.profileinstaller:profileinstaller:aar", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlinx:kotlinx-coroutines-android", + "org.jspecify:jspecify" + ], + "androidx.lifecycle:lifecycle-runtime-compose-android:aar": [ + "androidx.annotation:annotation", + "androidx.compose.runtime:runtime:aar", + "androidx.lifecycle:lifecycle-runtime-ktx:aar", + "androidx.lifecycle:lifecycle-runtime:aar" + ], + "androidx.lifecycle:lifecycle-runtime-compose:aar": [ + "androidx.lifecycle:lifecycle-runtime-compose-android:aar" + ], + "androidx.lifecycle:lifecycle-runtime-ktx-android:aar": [ + "androidx.annotation:annotation", + "androidx.lifecycle:lifecycle-runtime:aar", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlinx:kotlinx-coroutines-android" + ], + "androidx.lifecycle:lifecycle-runtime-ktx:aar": [ + "androidx.lifecycle:lifecycle-runtime-ktx-android:aar" + ], + "androidx.lifecycle:lifecycle-runtime:aar": [ + "androidx.lifecycle:lifecycle-runtime-android:aar" + ], + "androidx.lifecycle:lifecycle-viewmodel-android:aar": [ + "androidx.annotation:annotation", + "androidx.core:core-viewtree:aar", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlinx:kotlinx-coroutines-android", + "org.jetbrains.kotlinx:kotlinx-coroutines-core" + ], + "androidx.lifecycle:lifecycle-viewmodel-ktx:aar": [ + "androidx.lifecycle:lifecycle-viewmodel:aar", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlinx:kotlinx-coroutines-android" + ], + "androidx.lifecycle:lifecycle-viewmodel-savedstate-android:aar": [ + "androidx.annotation:annotation", + "androidx.core:core-ktx:aar", + "androidx.lifecycle:lifecycle-livedata-core:aar", + "androidx.lifecycle:lifecycle-viewmodel:aar", + "androidx.savedstate:savedstate:aar", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlinx:kotlinx-coroutines-android", + "org.jetbrains.kotlinx:kotlinx-coroutines-core", + "org.jetbrains.kotlinx:kotlinx-serialization-core" + ], + "androidx.lifecycle:lifecycle-viewmodel-savedstate:aar": [ + "androidx.lifecycle:lifecycle-viewmodel-savedstate-android:aar" + ], + "androidx.lifecycle:lifecycle-viewmodel:aar": [ + "androidx.lifecycle:lifecycle-viewmodel-android:aar" + ], + "androidx.loader:loader:aar": [ + "androidx.annotation:annotation", + "androidx.core:core:aar", + "androidx.lifecycle:lifecycle-livedata:aar", + "androidx.lifecycle:lifecycle-viewmodel:aar" + ], + "androidx.profileinstaller:profileinstaller:aar": [ + "androidx.annotation:annotation", + "androidx.concurrent:concurrent-futures", + "androidx.startup:startup-runtime:aar", + "com.google.guava:listenablefuture" + ], + "androidx.recyclerview:recyclerview:aar": [ + "androidx.annotation:annotation", + "androidx.collection:collection", + "androidx.core:core:aar", + "androidx.customview:customview:aar" + ], + "androidx.resourceinspection:resourceinspection-annotation": [ + "androidx.annotation:annotation" + ], + "androidx.savedstate:savedstate-android:aar": [ + "androidx.annotation:annotation", + "androidx.core:core-ktx:aar", + "androidx.core:core-viewtree:aar", + "androidx.lifecycle:lifecycle-common", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlinx:kotlinx-coroutines-core", + "org.jetbrains.kotlinx:kotlinx-serialization-core" + ], + "androidx.savedstate:savedstate-compose-android:aar": [ + "androidx.annotation:annotation", + "androidx.compose.runtime:runtime:aar", + "androidx.core:core-ktx:aar", + "androidx.savedstate:savedstate:aar" + ], + "androidx.savedstate:savedstate-compose:aar": [ + "androidx.savedstate:savedstate-compose-android:aar" + ], + "androidx.savedstate:savedstate-ktx:aar": [ + "androidx.savedstate:savedstate:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.savedstate:savedstate:aar": [ + "androidx.savedstate:savedstate-android:aar" + ], + "androidx.startup:startup-runtime:aar": [ + "androidx.annotation:annotation", + "androidx.tracing:tracing:aar" + ], + "androidx.swiperefreshlayout:swiperefreshlayout:aar": [ + "androidx.annotation:annotation", + "androidx.core:core:aar", + "androidx.interpolator:interpolator:aar" + ], + "androidx.tracing:tracing-ktx:aar": [ + "androidx.tracing:tracing:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "androidx.tracing:tracing:aar": [ + "androidx.annotation:annotation" + ], + "androidx.transition:transition:aar": [ + "androidx.annotation:annotation", + "androidx.collection:collection", + "androidx.core:core:aar", + "androidx.dynamicanimation:dynamicanimation:aar" + ], + "androidx.vectordrawable:vectordrawable-animated:aar": [ + "androidx.collection:collection", + "androidx.interpolator:interpolator:aar", + "androidx.vectordrawable:vectordrawable:aar" + ], + "androidx.vectordrawable:vectordrawable:aar": [ + "androidx.annotation:annotation", + "androidx.collection:collection", + "androidx.core:core:aar" + ], + "androidx.versionedparcelable:versionedparcelable:aar": [ + "androidx.annotation:annotation", + "androidx.collection:collection" + ], + "androidx.viewpager2:viewpager2:aar": [ + "androidx.annotation:annotation", + "androidx.collection:collection", + "androidx.core:core:aar", + "androidx.fragment:fragment:aar", + "androidx.recyclerview:recyclerview:aar" + ], + "androidx.viewpager:viewpager:aar": [ + "androidx.annotation:annotation", + "androidx.core:core:aar", + "androidx.customview:customview:aar" + ], + "com.facebook.fbjni:fbjni:aar": [ + "com.facebook.soloader:nativeloader" + ], + "com.facebook.fresco:drawee:aar": [ + "com.facebook.fresco:fbcore:aar", + "com.facebook.fresco:imagepipeline-native:aar", + "com.facebook.fresco:imagepipeline:aar", + "com.facebook.fresco:memory-type-ashmem:aar", + "com.facebook.fresco:memory-type-java:aar", + "com.facebook.fresco:memory-type-native:aar", + "com.facebook.fresco:middleware:aar", + "com.facebook.fresco:ui-common:aar", + "com.facebook.fresco:ui-core:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.facebook.fresco:fbcore:aar": [ + "androidx.core:core:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.facebook.fresco:fresco:aar": [ + "com.facebook.fresco:drawee:aar", + "com.facebook.fresco:fbcore:aar", + "com.facebook.fresco:imagepipeline-native:aar", + "com.facebook.fresco:imagepipeline:aar", + "com.facebook.fresco:memory-type-ashmem:aar", + "com.facebook.fresco:memory-type-java:aar", + "com.facebook.fresco:memory-type-native:aar", + "com.facebook.fresco:middleware:aar", + "com.facebook.fresco:nativeimagefilters:aar", + "com.facebook.fresco:nativeimagetranscoder:aar", + "com.facebook.fresco:soloader:aar", + "com.facebook.fresco:ui-common:aar", + "com.facebook.fresco:ui-core:aar", + "com.facebook.soloader:nativeloader", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.facebook.fresco:imagepipeline-base:aar": [ + "com.facebook.fresco:fbcore:aar", + "com.facebook.fresco:middleware:aar", + "com.facebook.infer.annotation:infer-annotation", + "com.facebook.soloader:annotation", + "com.parse.bolts:bolts-tasks", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.facebook.fresco:imagepipeline-native:aar": [ + "com.facebook.fresco:fbcore:aar", + "com.facebook.fresco:imagepipeline:aar", + "com.facebook.soloader:soloader:aar" + ], + "com.facebook.fresco:imagepipeline-okhttp3:aar": [ + "com.facebook.fresco:fbcore:aar", + "com.facebook.fresco:imagepipeline-native:aar", + "com.facebook.fresco:imagepipeline:aar", + "com.facebook.fresco:memory-type-ashmem:aar", + "com.facebook.fresco:memory-type-java:aar", + "com.facebook.fresco:memory-type-native:aar", + "com.facebook.fresco:middleware:aar", + "com.squareup.okhttp3:okhttp", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.facebook.fresco:imagepipeline:aar": [ + "com.facebook.fresco:fbcore:aar", + "com.facebook.fresco:imagepipeline-base:aar", + "com.facebook.fresco:middleware:aar", + "com.facebook.fresco:urimod:aar", + "com.facebook.soloader:annotation", + "com.facebook.soloader:nativeloader", + "com.parse.bolts:bolts-tasks", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.facebook.fresco:memory-type-ashmem:aar": [ + "com.facebook.fresco:fbcore:aar", + "com.facebook.fresco:imagepipeline:aar" + ], + "com.facebook.fresco:memory-type-java:aar": [ + "com.facebook.fresco:fbcore:aar", + "com.facebook.fresco:imagepipeline-native:aar", + "com.facebook.fresco:imagepipeline:aar" + ], + "com.facebook.fresco:memory-type-native:aar": [ + "com.facebook.fresco:fbcore:aar", + "com.facebook.fresco:imagepipeline-native:aar", + "com.facebook.fresco:imagepipeline:aar", + "com.facebook.soloader:nativeloader" + ], + "com.facebook.fresco:middleware:aar": [ + "com.facebook.fresco:fbcore:aar", + "com.facebook.fresco:ui-common:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.facebook.fresco:nativeimagefilters:aar": [ + "com.facebook.fresco:fbcore:aar", + "com.facebook.fresco:imagepipeline-native:aar", + "com.facebook.fresco:imagepipeline:aar", + "com.facebook.fresco:memory-type-ashmem:aar", + "com.facebook.fresco:memory-type-java:aar", + "com.facebook.fresco:memory-type-native:aar", + "com.facebook.soloader:nativeloader", + "com.parse.bolts:bolts-tasks" + ], + "com.facebook.fresco:nativeimagetranscoder:aar": [ + "com.facebook.fresco:fbcore:aar", + "com.facebook.fresco:imagepipeline-base:aar", + "com.facebook.soloader:nativeloader", + "com.parse.bolts:bolts-tasks" + ], + "com.facebook.fresco:soloader:aar": [ + "com.facebook.fresco:fbcore:aar", + "com.facebook.soloader:soloader:aar" + ], + "com.facebook.fresco:ui-common:aar": [ + "com.facebook.fresco:fbcore:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.facebook.fresco:ui-core:aar": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.facebook.fresco:urimod:aar": [ + "com.facebook.fresco:fbcore:aar", + "com.facebook.fresco:ui-core:aar", + "com.facebook.fresco:vito-source:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.facebook.fresco:vito-source:aar": [ + "com.facebook.fresco:middleware:aar", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.facebook.infer.annotation:infer-annotation": [ + "com.google.code.findbugs:jsr305", + "org.jetbrains.kotlin:kotlin-annotations-jvm" + ], + "com.facebook.soloader:soloader:aar": [ + "com.facebook.soloader:annotation", + "com.facebook.soloader:nativeloader" + ], + "com.google.android.material:material:aar": [ + "androidx.activity:activity:aar", + "androidx.annotation:annotation", + "androidx.annotation:annotation-experimental:aar", + "androidx.appcompat:appcompat:aar", + "androidx.cardview:cardview:aar", + "androidx.constraintlayout:constraintlayout:aar", + "androidx.coordinatorlayout:coordinatorlayout:aar", + "androidx.core:core:aar", + "androidx.drawerlayout:drawerlayout:aar", + "androidx.dynamicanimation:dynamicanimation:aar", + "androidx.fragment:fragment:aar", + "androidx.graphics:graphics-shapes:aar", + "androidx.lifecycle:lifecycle-runtime:aar", + "androidx.recyclerview:recyclerview:aar", + "androidx.resourceinspection:resourceinspection-annotation", + "androidx.transition:transition:aar", + "androidx.vectordrawable:vectordrawable:aar", + "androidx.viewpager2:viewpager2:aar", + "com.google.errorprone:error_prone_annotations", + "org.jetbrains.kotlin:kotlin-bom" + ], + "com.squareup.okhttp3:okhttp": [ + "com.squareup.okio:okio", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.squareup.okhttp3:okhttp-urlconnection": [ + "com.squareup.okhttp3:okhttp", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "com.squareup.okio:okio": [ + "com.squareup.okio:okio-jvm" + ], + "com.squareup.okio:okio-jvm": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.squareup.zstd:zstd-kmp": [ + "com.squareup.zstd:zstd-kmp-android:aar" + ], + "com.squareup.zstd:zstd-kmp-android:aar": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.squareup.zstd:zstd-kmp-okio-android:aar": [ + "com.squareup.okio:okio", + "com.squareup.zstd:zstd-kmp", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "io.github.lukmccall.pika:pika-api": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "io.github.lukmccall.pika:pika-compiler": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "org.jetbrains.kotlin:kotlin-reflect": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "org.jetbrains.kotlin:kotlin-stdlib": [ + "org.jetbrains:annotations" + ], + "org.jetbrains.kotlin:kotlin-stdlib-jdk7": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "org.jetbrains.kotlin:kotlin-stdlib-jdk8": [ + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlin:kotlin-stdlib-jdk7" + ], + "org.jetbrains.kotlinx:kotlinx-coroutines-android": [ + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlinx:kotlinx-coroutines-bom", + "org.jetbrains.kotlinx:kotlinx-coroutines-core" + ], + "org.jetbrains.kotlinx:kotlinx-coroutines-core": [ + "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm" + ], + "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm": [ + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlinx:kotlinx-coroutines-bom", + "org.jetbrains:annotations" + ], + "org.jetbrains.kotlinx:kotlinx-serialization-core": [ + "org.jetbrains.kotlinx:kotlinx-serialization-core-jvm" + ], + "org.jetbrains.kotlinx:kotlinx-serialization-core-jvm": [ + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlinx:kotlinx-serialization-bom" + ] + }, + "packages": { + "androidx.annotation:annotation-jvm": [ + "androidx.annotation" + ], + "androidx.arch.core:core-common": [ + "androidx.arch.core.internal", + "androidx.arch.core.util" + ], + "androidx.collection:collection-jvm": [ + "androidx.collection", + "androidx.collection.internal" + ], + "androidx.concurrent:concurrent-futures": [ + "androidx.concurrent.futures" + ], + "androidx.constraintlayout:constraintlayout-core": [ + "androidx.constraintlayout.core", + "androidx.constraintlayout.core.motion", + "androidx.constraintlayout.core.motion.key", + "androidx.constraintlayout.core.motion.parse", + "androidx.constraintlayout.core.motion.utils", + "androidx.constraintlayout.core.parser", + "androidx.constraintlayout.core.state", + "androidx.constraintlayout.core.state.helpers", + "androidx.constraintlayout.core.widgets", + "androidx.constraintlayout.core.widgets.analyzer" + ], + "androidx.lifecycle:lifecycle-common-jvm": [ + "androidx.lifecycle" + ], + "androidx.resourceinspection:resourceinspection-annotation": [ + "androidx.resourceinspection.annotation" + ], + "com.facebook.infer.annotation:infer-annotation": [ + "com.facebook.infer.annotation" + ], + "com.facebook.soloader:annotation": [ + "com.facebook.soloader" + ], + "com.facebook.soloader:nativeloader": [ + "com.facebook.soloader.nativeloader" + ], + "com.facebook.yoga:proguard-annotations": [ + "com.facebook.proguard.annotations" + ], + "com.google.code.findbugs:jsr305": [ + "javax.annotation", + "javax.annotation.concurrent", + "javax.annotation.meta" + ], + "com.google.code.gson:gson": [ + "com.google.gson", + "com.google.gson.annotations", + "com.google.gson.internal", + "com.google.gson.internal.bind", + "com.google.gson.internal.bind.util", + "com.google.gson.internal.reflect", + "com.google.gson.reflect", + "com.google.gson.stream" + ], + "com.google.errorprone:error_prone_annotations": [ + "com.google.errorprone.annotations", + "com.google.errorprone.annotations.concurrent" + ], + "com.google.guava:listenablefuture": [ + "com.google.common.util.concurrent" + ], + "com.parse.bolts:bolts-tasks": [ + "bolts" + ], + "com.squareup.okhttp3:okhttp": [ + "okhttp3", + "okhttp3.internal", + "okhttp3.internal.authenticator", + "okhttp3.internal.cache", + "okhttp3.internal.cache2", + "okhttp3.internal.concurrent", + "okhttp3.internal.connection", + "okhttp3.internal.http", + "okhttp3.internal.http1", + "okhttp3.internal.http2", + "okhttp3.internal.io", + "okhttp3.internal.platform", + "okhttp3.internal.platform.android", + "okhttp3.internal.proxy", + "okhttp3.internal.publicsuffix", + "okhttp3.internal.tls", + "okhttp3.internal.ws" + ], + "com.squareup.okhttp3:okhttp-urlconnection": [ + "okhttp3" + ], + "com.squareup.okio:okio-jvm": [ + "okio", + "okio.internal" + ], + "commons-codec:commons-codec": [ + "org.apache.commons.codec", + "org.apache.commons.codec.binary", + "org.apache.commons.codec.digest", + "org.apache.commons.codec.language", + "org.apache.commons.codec.language.bm", + "org.apache.commons.codec.net" + ], + "commons-io:commons-io": [ + "org.apache.commons.io", + "org.apache.commons.io.comparator", + "org.apache.commons.io.filefilter", + "org.apache.commons.io.input", + "org.apache.commons.io.output" + ], + "io.github.lukmccall.pika:pika-api": [ + "io.github.lukmccall.pika" + ], + "io.github.lukmccall.pika:pika-compiler": [ + "io.github.lukmccall.pika", + "io.github.lukmccall.pika.bytecode", + "io.github.lukmccall.pika.fir", + "io.github.lukmccall.pika.intrinsic", + "io.github.lukmccall.pika.ir", + "io.github.lukmccall.pika.symbols" + ], + "javax.inject:javax.inject": [ + "javax.inject" + ], + "net.java.dev.jna:jna": [ + "com.sun.jna", + "com.sun.jna.internal", + "com.sun.jna.ptr", + "com.sun.jna.win32" + ], + "org.brotli:dec": [ + "org.brotli.dec" + ], + "org.jetbrains.kotlin:kotlin-annotations-jvm": [ + "kotlin.annotations.jvm" + ], + "org.jetbrains.kotlin:kotlin-compose-compiler-plugin-embeddable": [ + "androidx.compose.compiler.plugins.kotlin", + "androidx.compose.compiler.plugins.kotlin.analysis", + "androidx.compose.compiler.plugins.kotlin.inference", + "androidx.compose.compiler.plugins.kotlin.k1", + "androidx.compose.compiler.plugins.kotlin.k2", + "androidx.compose.compiler.plugins.kotlin.lower", + "androidx.compose.compiler.plugins.kotlin.lower.hiddenfromobjc" + ], + "org.jetbrains.kotlin:kotlin-reflect": [ + "kotlin.reflect.full", + "kotlin.reflect.jvm", + "kotlin.reflect.jvm.internal", + "kotlin.reflect.jvm.internal.calls", + "kotlin.reflect.jvm.internal.impl", + "kotlin.reflect.jvm.internal.impl.builtins", + "kotlin.reflect.jvm.internal.impl.builtins.functions", + "kotlin.reflect.jvm.internal.impl.builtins.jvm", + "kotlin.reflect.jvm.internal.impl.descriptors", + "kotlin.reflect.jvm.internal.impl.descriptors.annotations", + "kotlin.reflect.jvm.internal.impl.descriptors.deserialization", + "kotlin.reflect.jvm.internal.impl.descriptors.impl", + "kotlin.reflect.jvm.internal.impl.descriptors.java", + "kotlin.reflect.jvm.internal.impl.descriptors.runtime.components", + "kotlin.reflect.jvm.internal.impl.descriptors.runtime.structure", + "kotlin.reflect.jvm.internal.impl.incremental", + "kotlin.reflect.jvm.internal.impl.incremental.components", + "kotlin.reflect.jvm.internal.impl.km", + "kotlin.reflect.jvm.internal.impl.km.internal", + "kotlin.reflect.jvm.internal.impl.km.internal.common", + "kotlin.reflect.jvm.internal.impl.km.internal.extensions", + "kotlin.reflect.jvm.internal.impl.km.jvm", + "kotlin.reflect.jvm.internal.impl.km.jvm.internal", + "kotlin.reflect.jvm.internal.impl.load.java", + "kotlin.reflect.jvm.internal.impl.load.java.components", + "kotlin.reflect.jvm.internal.impl.load.java.descriptors", + "kotlin.reflect.jvm.internal.impl.load.java.lazy", + "kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors", + "kotlin.reflect.jvm.internal.impl.load.java.lazy.types", + "kotlin.reflect.jvm.internal.impl.load.java.sources", + "kotlin.reflect.jvm.internal.impl.load.java.structure", + "kotlin.reflect.jvm.internal.impl.load.java.typeEnhancement", + "kotlin.reflect.jvm.internal.impl.load.kotlin", + "kotlin.reflect.jvm.internal.impl.load.kotlin.header", + "kotlin.reflect.jvm.internal.impl.metadata", + "kotlin.reflect.jvm.internal.impl.metadata.builtins", + "kotlin.reflect.jvm.internal.impl.metadata.deserialization", + "kotlin.reflect.jvm.internal.impl.metadata.jvm", + "kotlin.reflect.jvm.internal.impl.metadata.jvm.deserialization", + "kotlin.reflect.jvm.internal.impl.metadata.serialization", + "kotlin.reflect.jvm.internal.impl.name", + "kotlin.reflect.jvm.internal.impl.platform", + "kotlin.reflect.jvm.internal.impl.protobuf", + "kotlin.reflect.jvm.internal.impl.renderer", + "kotlin.reflect.jvm.internal.impl.resolve", + "kotlin.reflect.jvm.internal.impl.resolve.calls.inference", + "kotlin.reflect.jvm.internal.impl.resolve.constants", + "kotlin.reflect.jvm.internal.impl.resolve.deprecation", + "kotlin.reflect.jvm.internal.impl.resolve.descriptorUtil", + "kotlin.reflect.jvm.internal.impl.resolve.jvm", + "kotlin.reflect.jvm.internal.impl.resolve.sam", + "kotlin.reflect.jvm.internal.impl.resolve.scopes", + "kotlin.reflect.jvm.internal.impl.resolve.scopes.receivers", + "kotlin.reflect.jvm.internal.impl.serialization", + "kotlin.reflect.jvm.internal.impl.serialization.deserialization", + "kotlin.reflect.jvm.internal.impl.serialization.deserialization.builtins", + "kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors", + "kotlin.reflect.jvm.internal.impl.storage", + "kotlin.reflect.jvm.internal.impl.types", + "kotlin.reflect.jvm.internal.impl.types.checker", + "kotlin.reflect.jvm.internal.impl.types.error", + "kotlin.reflect.jvm.internal.impl.types.extensions", + "kotlin.reflect.jvm.internal.impl.types.model", + "kotlin.reflect.jvm.internal.impl.types.typeUtil", + "kotlin.reflect.jvm.internal.impl.types.typesApproximation", + "kotlin.reflect.jvm.internal.impl.util", + "kotlin.reflect.jvm.internal.impl.util.capitalizeDecapitalize", + "kotlin.reflect.jvm.internal.impl.util.collectionUtils", + "kotlin.reflect.jvm.internal.impl.utils", + "kotlin.reflect.jvm.internal.impl.utils.addToStdlib" + ], + "org.jetbrains.kotlin:kotlin-serialization-compiler-plugin-embeddable": [ + "org.jetbrains.kotlinx.serialization.compiler.backend.ir", + "org.jetbrains.kotlinx.serialization.compiler.diagnostic", + "org.jetbrains.kotlinx.serialization.compiler.extensions", + "org.jetbrains.kotlinx.serialization.compiler.fir", + "org.jetbrains.kotlinx.serialization.compiler.fir.checkers", + "org.jetbrains.kotlinx.serialization.compiler.fir.services", + "org.jetbrains.kotlinx.serialization.compiler.resolve" + ], + "org.jetbrains.kotlin:kotlin-stdlib": [ + "kotlin", + "kotlin.annotation", + "kotlin.collections", + "kotlin.collections.builders", + "kotlin.collections.jdk8", + "kotlin.collections.unsigned", + "kotlin.comparisons", + "kotlin.concurrent", + "kotlin.concurrent.atomics", + "kotlin.concurrent.internal", + "kotlin.contracts", + "kotlin.coroutines", + "kotlin.coroutines.cancellation", + "kotlin.coroutines.intrinsics", + "kotlin.coroutines.jvm.internal", + "kotlin.enums", + "kotlin.experimental", + "kotlin.internal", + "kotlin.internal.jdk7", + "kotlin.internal.jdk8", + "kotlin.io", + "kotlin.io.encoding", + "kotlin.io.path", + "kotlin.jdk7", + "kotlin.js", + "kotlin.jvm", + "kotlin.jvm.functions", + "kotlin.jvm.internal", + "kotlin.jvm.internal.markers", + "kotlin.jvm.internal.unsafe", + "kotlin.jvm.jdk8", + "kotlin.jvm.optionals", + "kotlin.math", + "kotlin.properties", + "kotlin.random", + "kotlin.random.jdk8", + "kotlin.ranges", + "kotlin.reflect", + "kotlin.sequences", + "kotlin.streams.jdk8", + "kotlin.system", + "kotlin.text", + "kotlin.text.jdk8", + "kotlin.time", + "kotlin.time.jdk8", + "kotlin.uuid" + ], + "org.jetbrains.kotlinx:kotlinx-coroutines-android": [ + "kotlinx.coroutines.android" + ], + "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm": [ + "_COROUTINE", + "kotlinx.coroutines", + "kotlinx.coroutines.channels", + "kotlinx.coroutines.debug.internal", + "kotlinx.coroutines.flow", + "kotlinx.coroutines.flow.internal", + "kotlinx.coroutines.future", + "kotlinx.coroutines.internal", + "kotlinx.coroutines.intrinsics", + "kotlinx.coroutines.scheduling", + "kotlinx.coroutines.selects", + "kotlinx.coroutines.stream", + "kotlinx.coroutines.sync", + "kotlinx.coroutines.time" + ], + "org.jetbrains.kotlinx:kotlinx-serialization-core-jvm": [ + "kotlinx.serialization", + "kotlinx.serialization.builtins", + "kotlinx.serialization.descriptors", + "kotlinx.serialization.encoding", + "kotlinx.serialization.internal", + "kotlinx.serialization.modules" + ], + "org.jetbrains:annotations": [ + "org.intellij.lang.annotations", + "org.jetbrains.annotations" + ], + "org.jspecify:jspecify": [ + "org.jspecify.annotations" + ] + }, + "repositories": { + "https://repo.maven.apache.org/maven2/": [ + "com.facebook.fbjni:fbjni:aar", + "com.facebook.fresco:drawee:aar", + "com.facebook.fresco:fbcore:aar", + "com.facebook.fresco:fresco:aar", + "com.facebook.fresco:imagepipeline-base:aar", + "com.facebook.fresco:imagepipeline-native:aar", + "com.facebook.fresco:imagepipeline-okhttp3:aar", + "com.facebook.fresco:imagepipeline:aar", + "com.facebook.fresco:memory-type-ashmem:aar", + "com.facebook.fresco:memory-type-java:aar", + "com.facebook.fresco:memory-type-native:aar", + "com.facebook.fresco:middleware:aar", + "com.facebook.fresco:nativeimagefilters:aar", + "com.facebook.fresco:nativeimagetranscoder:aar", + "com.facebook.fresco:soloader:aar", + "com.facebook.fresco:ui-common:aar", + "com.facebook.fresco:ui-core:aar", + "com.facebook.fresco:urimod:aar", + "com.facebook.fresco:vito-source:aar", + "com.facebook.hermes:hermes-android:aar:release", + "com.facebook.infer.annotation:infer-annotation", + "com.facebook.react:react-android:aar:release", + "com.facebook.soloader:annotation", + "com.facebook.soloader:nativeloader", + "com.facebook.soloader:soloader:aar", + "com.facebook.yoga:proguard-annotations", + "com.google.code.findbugs:jsr305", + "com.google.code.gson:gson", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:listenablefuture", + "com.parse.bolts:bolts-tasks", + "com.squareup.okhttp3:okhttp", + "com.squareup.okhttp3:okhttp-urlconnection", + "com.squareup.okio:okio", + "com.squareup.okio:okio-jvm", + "com.squareup.zstd:zstd-kmp", + "com.squareup.zstd:zstd-kmp-android:aar", + "com.squareup.zstd:zstd-kmp-okio-android:aar", + "commons-codec:commons-codec", + "commons-io:commons-io", + "io.github.lukmccall.pika:pika-api", + "io.github.lukmccall.pika:pika-compiler", + "javax.inject:javax.inject", + "net.java.dev.jna:jna", + "org.brotli:dec", + "org.jetbrains.kotlin:kotlin-annotations-jvm", + "org.jetbrains.kotlin:kotlin-bom", + "org.jetbrains.kotlin:kotlin-compose-compiler-plugin-embeddable", + "org.jetbrains.kotlin:kotlin-reflect", + "org.jetbrains.kotlin:kotlin-serialization-compiler-plugin-embeddable", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlin:kotlin-stdlib-jdk7", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8", + "org.jetbrains.kotlinx:kotlinx-coroutines-android", + "org.jetbrains.kotlinx:kotlinx-coroutines-bom", + "org.jetbrains.kotlinx:kotlinx-coroutines-core", + "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm", + "org.jetbrains.kotlinx:kotlinx-serialization-bom", + "org.jetbrains.kotlinx:kotlinx-serialization-core", + "org.jetbrains.kotlinx:kotlinx-serialization-core-jvm", + "org.jetbrains:annotations", + "org.jspecify:jspecify" + ], + "https://dl.google.com/dl/android/maven2/": [ + "androidx.activity:activity-ktx:aar", + "androidx.activity:activity:aar", + "androidx.annotation:annotation", + "androidx.annotation:annotation-experimental:aar", + "androidx.annotation:annotation-jvm", + "androidx.appcompat:appcompat-resources:aar", + "androidx.appcompat:appcompat:aar", + "androidx.arch.core:core-common", + "androidx.arch.core:core-runtime:aar", + "androidx.autofill:autofill:aar", + "androidx.cardview:cardview:aar", + "androidx.collection:collection", + "androidx.collection:collection-jvm", + "androidx.collection:collection-ktx", + "androidx.compose.animation:animation-android:aar", + "androidx.compose.animation:animation-core-android:aar", + "androidx.compose.animation:animation-core:aar", + "androidx.compose.animation:animation:aar", + "androidx.compose.foundation:foundation-android:aar", + "androidx.compose.foundation:foundation-layout-android:aar", + "androidx.compose.foundation:foundation-layout:aar", + "androidx.compose.runtime:runtime-android:aar", + "androidx.compose.runtime:runtime-annotation", + "androidx.compose.runtime:runtime-annotation-android:aar", + "androidx.compose.runtime:runtime-saveable-android:aar", + "androidx.compose.runtime:runtime-saveable:aar", + "androidx.compose.runtime:runtime:aar", + "androidx.compose.ui:ui-android:aar", + "androidx.compose.ui:ui-geometry-android:aar", + "androidx.compose.ui:ui-geometry:aar", + "androidx.compose.ui:ui-graphics-android:aar", + "androidx.compose.ui:ui-graphics:aar", + "androidx.compose.ui:ui-text-android:aar", + "androidx.compose.ui:ui-text:aar", + "androidx.compose.ui:ui-unit-android:aar", + "androidx.compose.ui:ui-unit:aar", + "androidx.compose.ui:ui-util-android:aar", + "androidx.compose.ui:ui-util:aar", + "androidx.compose.ui:ui:aar", + "androidx.concurrent:concurrent-futures", + "androidx.constraintlayout:constraintlayout-core", + "androidx.constraintlayout:constraintlayout:aar", + "androidx.coordinatorlayout:coordinatorlayout:aar", + "androidx.core:core-ktx:aar", + "androidx.core:core-splashscreen:aar", + "androidx.core:core-viewtree:aar", + "androidx.core:core:aar", + "androidx.cursoradapter:cursoradapter:aar", + "androidx.customview:customview-poolingcontainer:aar", + "androidx.customview:customview:aar", + "androidx.documentfile:documentfile:aar", + "androidx.drawerlayout:drawerlayout:aar", + "androidx.dynamicanimation:dynamicanimation:aar", + "androidx.emoji2:emoji2-views-helper:aar", + "androidx.emoji2:emoji2:aar", + "androidx.fragment:fragment:aar", + "androidx.graphics:graphics-path:aar", + "androidx.graphics:graphics-shapes-android:aar", + "androidx.graphics:graphics-shapes:aar", + "androidx.interpolator:interpolator:aar", + "androidx.lifecycle:lifecycle-common", + "androidx.lifecycle:lifecycle-common-jvm", + "androidx.lifecycle:lifecycle-livedata-core-ktx:aar", + "androidx.lifecycle:lifecycle-livedata-core:aar", + "androidx.lifecycle:lifecycle-livedata:aar", + "androidx.lifecycle:lifecycle-process:aar", + "androidx.lifecycle:lifecycle-runtime-android:aar", + "androidx.lifecycle:lifecycle-runtime-compose-android:aar", + "androidx.lifecycle:lifecycle-runtime-compose:aar", + "androidx.lifecycle:lifecycle-runtime-ktx-android:aar", + "androidx.lifecycle:lifecycle-runtime-ktx:aar", + "androidx.lifecycle:lifecycle-runtime:aar", + "androidx.lifecycle:lifecycle-viewmodel-android:aar", + "androidx.lifecycle:lifecycle-viewmodel-ktx:aar", + "androidx.lifecycle:lifecycle-viewmodel-savedstate-android:aar", + "androidx.lifecycle:lifecycle-viewmodel-savedstate:aar", + "androidx.lifecycle:lifecycle-viewmodel:aar", + "androidx.loader:loader:aar", + "androidx.profileinstaller:profileinstaller:aar", + "androidx.recyclerview:recyclerview:aar", + "androidx.resourceinspection:resourceinspection-annotation", + "androidx.savedstate:savedstate-android:aar", + "androidx.savedstate:savedstate-compose-android:aar", + "androidx.savedstate:savedstate-compose:aar", + "androidx.savedstate:savedstate-ktx:aar", + "androidx.savedstate:savedstate:aar", + "androidx.startup:startup-runtime:aar", + "androidx.swiperefreshlayout:swiperefreshlayout:aar", + "androidx.tracing:tracing-ktx:aar", + "androidx.tracing:tracing:aar", + "androidx.transition:transition:aar", + "androidx.vectordrawable:vectordrawable-animated:aar", + "androidx.vectordrawable:vectordrawable:aar", + "androidx.versionedparcelable:versionedparcelable:aar", + "androidx.viewpager2:viewpager2:aar", + "androidx.viewpager:viewpager:aar", + "com.google.android.material:material:aar" + ] + }, + "services": { + "io.github.lukmccall.pika:pika-compiler": { + "org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor": [ + "io.github.lukmccall.pika.PikaCommandLineProcessor" + ], + "org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar": [ + "io.github.lukmccall.pika.PikaPluginComponentRegistrar" + ] + }, + "org.jetbrains.kotlin:kotlin-compose-compiler-plugin-embeddable": { + "org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor": [ + "androidx.compose.compiler.plugins.kotlin.ComposeCommandLineProcessor" + ], + "org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar": [ + "androidx.compose.compiler.plugins.kotlin.ComposePluginRegistrar" + ], + "org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages$Extension": [ + "androidx.compose.compiler.plugins.kotlin.k1.ComposeErrorMessages" + ], + "org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar": [ + "androidx.compose.compiler.plugins.kotlin.k2.ComposeFirExtensionRegistrar" + ] + }, + "org.jetbrains.kotlin:kotlin-reflect": { + "kotlin.reflect.jvm.internal.impl.builtins.BuiltInsLoader": [ + "kotlin.reflect.jvm.internal.impl.serialization.deserialization.builtins.BuiltInsLoaderImpl" + ], + "kotlin.reflect.jvm.internal.impl.km.internal.extensions.MetadataExtensions": [ + "kotlin.reflect.jvm.internal.impl.km.jvm.internal.JvmMetadataExtensions" + ], + "kotlin.reflect.jvm.internal.impl.resolve.ExternalOverridabilityCondition": [ + "kotlin.reflect.jvm.internal.impl.load.java.ErasedOverridabilityCondition", + "kotlin.reflect.jvm.internal.impl.load.java.FieldOverridabilityCondition", + "kotlin.reflect.jvm.internal.impl.load.java.JavaIncompatibilityRulesOverridabilityCondition" + ] + }, + "org.jetbrains.kotlin:kotlin-serialization-compiler-plugin-embeddable": { + "org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor": [ + "org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationPluginOptions" + ], + "org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar": [ + "org.jetbrains.kotlinx.serialization.compiler.extensions.SerializationComponentRegistrar" + ] + }, + "org.jetbrains.kotlinx:kotlinx-coroutines-android": { + "kotlinx.coroutines.CoroutineExceptionHandler": [ + "kotlinx.coroutines.android.AndroidExceptionPreHandler" + ], + "kotlinx.coroutines.internal.MainDispatcherFactory": [ + "kotlinx.coroutines.android.AndroidDispatcherFactory" + ] + } + }, + "skipped": [ + "org.jetbrains.kotlin:kotlin-bom", + "org.jetbrains.kotlinx:kotlinx-coroutines-bom", + "org.jetbrains.kotlinx:kotlinx-serialization-bom" + ], + "version": "3" +} diff --git a/build_defs/android/installed-app.bzl b/build_defs/android/installed-app.bzl new file mode 100644 index 000000000..092919a8c --- /dev/null +++ b/build_defs/android/installed-app.bzl @@ -0,0 +1,106 @@ +"""Local installed smoke over the exact existing final signed APK.""" +load("@rules_android//providers:providers.bzl", "AndroidSdkInfo") +load("@rules_java//java/common:java_common.bzl", "java_common") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/foundation:bun-sources.bzl", "bun_source_tree", "bun_source_runfile") + +_NODE = "@rules_nodejs//nodejs:toolchain_type" +InstalledAndroidToolsInfo = provider(fields = ["node", "metadata", "adb", "files", "specification", "runner", "sources"]) + +def _tools_impl(ctx): + sdk = ctx.attr.android_sdk[AndroidSdkInfo] + if sdk.adb.executable not in ctx.files.platform_tools: + fail("Installed Android qualification requires the declared original platform-tools adb binary") + node = ctx.toolchains[_NODE].nodeinfo.node + runtime = ctx.attr._java_runtime[java_common.JavaRuntimeInfo] + files, helper_rows, sdk_rows = [], [], [] + for file in ctx.files.helpers: + helper_rows.append({"relative": file.short_path, "index": len(files)}) + files.append(file) + emulator_root = ctx.file.emulator_metadata.dirname + "/" + for file in ctx.files.emulator_files: + if not file.path.startswith(emulator_root): + fail("Emulator Files must belong to their exact acquisition repository") + sdk_rows.append({"relative": file.path[len(emulator_root):], "index": len(files)}) + files.append(file) + for file in ctx.files.platform_tools: + marker = "/platform-tools/" + if marker not in file.path: + fail("Platform tool File lacks its canonical SDK path") + sdk_rows.append({"relative": "platform-tools/" + file.path.split(marker)[-1], "index": len(files)}) + files.append(file) + java = [file for file in runtime.files.to_list() if file.path.endswith("/bin/java")] + if len(java) != 1: + fail("Installed Android qualification requires its exact declared Java executable") + java_index = len(files) + files.append(java[0]) + files += [file for file in runtime.files.to_list() if file != java[0]] + tool_spec = {"helpers": helper_rows, "sdkFiles": sdk_rows, "java": java_index} + sources = [ctx.file._runner, ctx.file._candidate_helpers, ctx.file._archive_parser, ctx.file._metadata_helpers] + runner_sources = bun_source_tree(ctx, ctx.label.name + ".installed-sources", sources) + descriptor = ctx.actions.declare_file(ctx.label.name + ".tools.json") + ctx.actions.write(descriptor, json.encode({ + "schema": "oliphaunt-installed-mobile-tools-v1", "platform": "android", "toolSpec": tool_spec, + "runnerRunfile": bun_source_runfile(ctx, runner_sources, ctx.file._runner), "fileCount": len(files), + }) + "\n") + return bun_test_entrypoint(ctx, ctx.file._manifest_runner, + arguments = [descriptor, node, ctx.file.emulator_metadata, sdk.adb.executable] + files, + files = [descriptor, node, ctx.file.emulator_metadata, sdk.adb.executable] + files, + source_files = [], runfiles_argument = True, + additional_runfiles = ctx.runfiles(transitive_files = runner_sources.files)) + [InstalledAndroidToolsInfo( + node = node, metadata = ctx.file.emulator_metadata, adb = sdk.adb.executable, + files = files, specification = tool_spec, runner = ctx.file._runner, sources = sources)] + +def _installed_impl(ctx): + tools = ctx.attr.tools[InstalledAndroidToolsInfo] + specification = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(specification, json.encode(dict(tools.specification, **{ + "extensions": ctx.attr.extensions, "timeoutSeconds": ctx.attr.timeout_seconds, + "replay": {"schema": "oliphaunt-installed-mobile-replay-v1", "platform": "android", + "files": {"apk": ctx.file.apk.path, "proof": ctx.file.proof.path, "sdk": ctx.file.sdk.path}}, + })) + "\n") + arguments = [specification, ctx.file.apk, ctx.file.proof, ctx.file.sdk, tools.node, tools.metadata, tools.adb] + tools.files + return bun_test_entrypoint(ctx, tools.runner, arguments = arguments, files = arguments, + source_files = tools.sources) + [ + OutputGroupInfo(observation_inputs = depset([specification, ctx.file.apk, ctx.file.proof, ctx.file.sdk])), + RunEnvironmentInfo(inherited_environment = [ + "OLIPHAUNT_MOBILE_CANDIDATE_CHECKOUT", "OLIPHAUNT_MOBILE_CANDIDATE_SHA", "OLIPHAUNT_MOBILE_CANDIDATE_TREE", + ]), + ] + +_installed_tools = rule(implementation = _tools_impl, executable = True, + toolchains = BUN_SOURCE_TOOLCHAINS + [_NODE], attrs = BUN_TEST_ENTRYPOINT_ATTRS | { + "helpers": attr.label_list(mandatory = True, allow_files = True), + "android_sdk": attr.label(default = Label("@oliphaunt_android_sdk//:sdk"), providers = [AndroidSdkInfo]), + "platform_tools": attr.label(default = Label("@oliphaunt_android_sdk//:platform_tools_files"), allow_files = True), + "emulator_metadata": attr.label(default = Label("@oliphaunt_android_emulator//:emulator.json"), allow_single_file = [".json"]), + "emulator_files": attr.label(default = Label("@oliphaunt_android_emulator//:files"), allow_files = True), + "_java_runtime": attr.label(default = Label("@bazel_tools//tools/jdk:current_java_runtime"), cfg = "exec", providers = [java_common.JavaRuntimeInfo]), + "_manifest_runner": attr.label(default = Label("//build_defs/apple:installed-tools.mts"), allow_single_file = True), + "_runner": attr.label(default = Label("//build_defs/android:installed-app.mts"), allow_single_file = True), + "_candidate_helpers": attr.label(default = Label("//build_defs/apple:installed-app.mts"), allow_single_file = True), + "_archive_parser": attr.label(default = Label("//:tools/packaging/portable-archive.mts"), allow_single_file = True), + "_metadata_helpers": attr.label(default = Label("//build_defs/languages/jvm:android-sdk-metadata.mts"), allow_single_file = True), + }) + +_installed_test = rule(implementation = _installed_impl, test = True, + toolchains = BUN_SOURCE_TOOLCHAINS, attrs = BUN_TEST_ENTRYPOINT_ATTRS | { + "tools": attr.label(mandatory = True, providers = [InstalledAndroidToolsInfo]), + "apk": attr.label(mandatory = True, allow_single_file = [".apk"]), + "proof": attr.label(mandatory = True, allow_single_file = [".json"]), + "sdk": attr.label(mandatory = True, allow_single_file = [".tgz"]), + "extensions": attr.string_list(mandatory = True), + "timeout_seconds": attr.int(default = 600), + }) + +def expo_android_installed_test(name, helpers, **kwargs): + compatible = ["@platforms//os:linux", "@platforms//cpu:x86_64"] + tool_attrs = {} + for key in ["android_sdk", "platform_tools", "emulator_metadata", "emulator_files"]: + if key in kwargs: + tool_attrs[key] = kwargs.pop(key) + _installed_tools(name = name + "_tools", helpers = helpers, args = bun_test_entrypoint_args(name + "_tools"), + target_compatible_with = compatible, **tool_attrs) + _installed_test(name = name, tools = ":" + name + "_tools", args = bun_test_entrypoint_args(name), + tags = ["local", "exclusive", "no-remote", "no-sandbox", "external"], + target_compatible_with = compatible, size = "large", timeout = "long", **kwargs) diff --git a/build_defs/android/installed-app.mts b/build_defs/android/installed-app.mts new file mode 100644 index 000000000..b1700bf7e --- /dev/null +++ b/build_defs/android/installed-app.mts @@ -0,0 +1,472 @@ +/** Execute the existing installed-app assertions on the final Bazel APK. */ +import assert from 'node:assert/strict'; +import { createHash, randomUUID } from 'node:crypto'; +import { + accessSync, + chmodSync, + constants, + copyFileSync, + createReadStream, + lstatSync, + mkdirSync, + mkdtempSync, + readFileSync, + realpathSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import net from 'node:net'; +import path from 'node:path'; +import { assertCandidateCheckout, assertLifecycleReceipt } from '../apple/installed-app.mts'; + +import { verifyAndroidEmulator } from '../languages/jvm/android-sdk-metadata.mts'; + +const digest = (file: string) => + createHash('sha256') + .update(readFileSync(realpathSync(file))) + .digest('hex'); +const shellQuote = (value: string) => "'" + value.replaceAll("'", "'\\''") + "'"; + +export function assertKvmAvailable(device = '/dev/kvm') { + try { + assert(lstatSync(device).isCharacterDevice()); + accessSync(device, constants.R_OK | constants.W_OK); + } catch { + throw new Error( + 'Installed Android qualification requires readable/writable /dev/kvm; provision runner KVM access. No device test was executed.', + ); + } +} + +export function assertInstalledApk(apk: string, proofFile: string, extensions: string[]) { + const proof = JSON.parse(readFileSync(proofFile, 'utf8')); + assert.equal(proof.schema, 'oliphaunt-expo-android-apk-proof-v1'); + assert.equal(proof.abi, 'x86_64', 'Installed APK must target its actual emulator ABI'); + assert.equal(proof.applicationId, 'dev.oliphaunt.reactnative.example'); + assert.deepEqual(proof.selectedExtensions, [...extensions].sort()); + assert.equal( + proof.apkSha256, + digest(apk), + 'Installed APK differs from the exact final signed/verified File', + ); + return proof; +} + +export function stageSdkFiles( + root: string, + rows: { relative: string; index: number }[], + files: string[], +) { + const names = new Set(); + for (const row of rows) { + assert( + row.relative && + !path.isAbsolute(row.relative) && + !row.relative.includes('\\') && + row.relative.split('/').every((part) => part && part !== '.' && part !== '..'), + 'Unsafe declared Android SDK path', + ); + assert(!names.has(row.relative), 'Repeated declared Android SDK File'); + names.add(row.relative); + const source = realpathSync(files[row.index]); + assert(lstatSync(source).isFile(), 'Declared Android SDK input must resolve to a regular File'); + const destination = path.join(root, row.relative); + mkdirSync(path.dirname(destination), { recursive: true }); + // The launcher discovers its SDK through its own path; image/tool bytes stay read-only aliases. + if (row.relative.endsWith('/bin/avdmanager')) { + copyFileSync(source, destination); + chmodSync(destination, 0o755); + } else symlinkSync(source, destination); + } +} + +export function emulatorArguments(name: string, port: number, sdk: string) { + assert(/^oliphaunt-bazel-[a-f0-9-]+$/u.test(name)); + assert(Number.isInteger(port) && port >= 5554 && port <= 5680 && port % 2 === 0); + return [ + '-avd', + name, + '-port', + String(port), + '-no-window', + '-no-audio', + '-no-boot-anim', + '-no-snapshot', + '-no-snapshot-load', + '-no-snapshot-save', + '-wipe-data', + '-no-cache', + '-no-metrics', + '-accel', + 'on', + '-gpu', + 'software', + '-partition-size', + '6144', + '-sysdir', + path.join(sdk, 'system-images/android-35/google_atd/x86_64'), + ]; +} + +/** Retain device diagnostics before the owned emulator and ADB server are stopped. */ +export function captureInstalledAndroidFailure( + adb: string, + serverPort: number, + serial: string, + output: string, + cwd: string, + env: NodeJS.ProcessEnv, +) { + for (const [name, args] of [ + ['failure-logcat.log', ['logcat', '-d', '-v', 'threadtime', '-t', '2000']], + ['failure-activity.txt', ['shell', 'dumpsys', 'activity', 'top']], + ] as const) { + const file = Bun.file(path.join(output, name)); + try { + Bun.spawnSync([adb, '-P', String(serverPort), '-s', serial, ...args], { + cwd, + env, + stdout: file, + stderr: file, + timeout: 5000, + killSignal: 'SIGKILL', + }); + } catch (error) { + writeFileSync(path.join(output, name), `${String(error)}\n`); + } + } +} + +async function unusedPort(port = 0) { + const server = net.createServer(); + await new Promise((resolve, reject) => { + server.once('error', reject); + server.listen(port, '127.0.0.1', resolve); + }); + const address = server.address(); + assert(address && typeof address !== 'string'); + await new Promise((resolve) => server.close(() => resolve())); + return address.port; +} + +async function emulatorPort() { + for (let port = 5554; port <= 5680; port += 2) { + try { + await unusedPort(port); + await unusedPort(port + 1); + return port; + } catch { + /* Try the next owned console/ADB pair. */ + } + } + throw new Error('No private emulator console/ADB port pair is available'); +} + +function command( + binary: string, + args: string[], + cwd: string, + env: NodeJS.ProcessEnv, + input?: string, + timeout = 30_000, +) { + const result = Bun.spawnSync([binary, ...args], { + cwd, + env, + stdin: input ? new TextEncoder().encode(input) : 'ignore', + stdout: 'pipe', + stderr: 'pipe', + timeout, + killSignal: 'SIGKILL', + }); + assert.equal( + result.exitCode, + 0, + `${path.basename(binary)} ${args.join(' ')}:\n${result.stdout}\n${result.stderr}`, + ); + return result.stdout.toString().trim(); +} + +async function fileDigest(file: string) { + const hash = createHash('sha256'); + for await (const bytes of createReadStream(realpathSync(file))) hash.update(bytes); + return hash.digest('hex'); +} + +export async function runInstalledAndroid(args: string[]) { + assert.equal(process.platform, 'linux'); + assert.equal(process.arch, 'x64'); + assertKvmAvailable(); + const [specFile, apkFile, proofFile, sdkPackage, node, metadataFile, adbFile, ...files] = args; + const spec = JSON.parse(readFileSync(specFile, 'utf8')); + const metadata = JSON.parse(readFileSync(metadataFile, 'utf8')); + const apk = realpathSync(apkFile); + const proof = assertInstalledApk(apk, proofFile, spec.extensions); + const helpers = spec.helpers.map((helper: any) => ({ + relative: helper.relative, + file: files[helper.index], + })); + const checkout = process.env.OLIPHAUNT_MOBILE_CANDIDATE_CHECKOUT ?? ''; + const sha = process.env.OLIPHAUNT_MOBILE_CANDIDATE_SHA ?? ''; + const tree = process.env.OLIPHAUNT_MOBILE_CANDIDATE_TREE ?? ''; + assertCandidateCheckout(checkout, sha, tree, helpers); + assert.equal(metadata.api, 35); + assert.equal(metadata.tag, 'google_atd'); + assert.equal(metadata.abi, 'x86_64'); + assert( + Number.isInteger(spec.timeoutSeconds) && + spec.timeoutSeconds >= 60 && + spec.timeoutSeconds <= 800, + ); + const scratch = mkdtempSync( + path.join(process.env.TEST_TMPDIR ?? '/tmp', 'oliphaunt-android-installed-'), + ); + try { + const output = process.env.TEST_UNDECLARED_OUTPUTS_DIR ?? path.join(scratch, 'evidence'); + mkdirSync(output, { recursive: true }); + const sdk = path.join(scratch, 'sdk'), + home = path.join(scratch, 'home'), + bin = path.join(scratch, 'bin'); + const env: NodeJS.ProcessEnv = { ...process.env }; + for (const name of Object.keys(env)) + if (/^(?:OLIPHAUNT_|EXPO_PUBLIC_|NODE_|BUN_|ANDROID_|ADB_|JAVA_|JDK_|LD_)/u.test(name)) + delete env[name]; + mkdirSync(home); + mkdirSync(bin); + mkdirSync(path.join(scratch, 'tmp')); + mkdirSync(path.join(home, 'avd')); + stageSdkFiles(sdk, spec.sdkFiles, files); + verifyAndroidEmulator(sdk, metadata); + symlinkSync(realpathSync(node), path.join(bin, 'node')); + symlinkSync(process.execPath, path.join(bin, 'bun')); + const adb = realpathSync(adbFile), + serverPort = await unusedPort(), + port = await emulatorPort(); + const serial = `127.0.0.1:${port + 1}`; + const adbWrapper = path.join(sdk, 'platform-tools/adb'); + rmSync(adbWrapper); + writeFileSync( + adbWrapper, + `#!/bin/sh\nexec ${shellQuote(adb)} -P ${shellQuote(String(serverPort))} "$@"\n`, + { mode: 0o755 }, + ); + Object.assign(env, { + HOME: home, + TMPDIR: path.join(scratch, 'tmp'), + PATH: bin + ':/usr/bin:/bin:/usr/sbin:/sbin', + JAVA_HOME: path.dirname(path.dirname(realpathSync(files[spec.java]))), + JAVA_TOOL_OPTIONS: + '-Dhttp.proxyHost=127.0.0.1 -Dhttp.proxyPort=9 -Dhttps.proxyHost=127.0.0.1 -Dhttps.proxyPort=9', + ANDROID_HOME: sdk, + ANDROID_SDK_ROOT: sdk, + ANDROID_USER_HOME: home, + ANDROID_EMULATOR_HOME: home, + ANDROID_AVD_HOME: path.join(home, 'avd'), + ANDROID_SERIAL: serial, + ADB_SERVER_SOCKET: `tcp:127.0.0.1:${serverPort}`, + ANDROID_ADB_SERVER_PORT: String(serverPort), + }); + const avd = 'oliphaunt-bazel-' + randomUUID(); + const emulator = path.join(sdk, 'emulator/emulator'); + let processHandle: ReturnType | undefined; + const deadline = Date.now() + spec.timeoutSeconds * 1000; + const remaining = () => { + const value = deadline - Date.now(); + assert(value > 0, 'Installed Android qualification exceeded its bounded budget'); + return value; + }; + try { + command( + path.join(sdk, 'cmdline-tools/latest/bin/avdmanager'), + [ + 'create', + 'avd', + '--name', + avd, + '--package', + `system-images;android-${metadata.api};${metadata.tag};${metadata.abi}`, + '--path', + path.join(env.ANDROID_AVD_HOME!, avd + '.avd'), + '--force', + '--device', + 'pixel_2', + ], + checkout, + env, + 'no\n', + Math.min(120_000, remaining()), + ); + command(adb, ['-P', String(serverPort), 'start-server'], checkout, env); + const emulatorLog = Bun.file(path.join(output, 'emulator.log')); + processHandle = Bun.spawn([emulator, ...emulatorArguments(avd, port, sdk)], { + cwd: scratch, + env, + stdout: emulatorLog, + stderr: emulatorLog, + }); + let booted = false; + while (Date.now() < deadline) { + assert( + processHandle.exitCode === null, + 'Pinned emulator exited before boot; inspect emulator.log', + ); + Bun.spawnSync([adb, '-P', String(serverPort), 'connect', serial], { + cwd: scratch, + env, + stdout: 'ignore', + stderr: 'ignore', + timeout: Math.min(10_000, remaining()), + killSignal: 'SIGKILL', + }); + const boot = Bun.spawnSync( + [adb, '-P', String(serverPort), '-s', serial, 'shell', 'getprop', 'sys.boot_completed'], + { + cwd: scratch, + env, + stdout: 'pipe', + stderr: 'ignore', + timeout: Math.min(10_000, remaining()), + killSignal: 'SIGKILL', + }, + ); + if (boot.exitCode === 0 && boot.stdout.toString().trim() === '1') { + booted = true; + break; + } + await Bun.sleep(2000); + } + assert(booted, 'Pinned Android emulator failed to boot within the bounded budget'); + const actualAbi = command( + adb, + ['-P', String(serverPort), '-s', serial, 'shell', 'getprop', 'ro.product.cpu.abi'], + checkout, + env, + ); + const actualApi = command( + adb, + ['-P', String(serverPort), '-s', serial, 'shell', 'getprop', 'ro.build.version.sdk'], + checkout, + env, + ); + assert.equal(actualAbi, metadata.abi); + assert.equal(actualApi, String(metadata.api)); + const pack = path.join(scratch, 'pack'); + mkdirSync(pack); + const packageManifest = JSON.parse( + readFileSync(path.join(checkout, 'src/native/sdks/react-native/package.json'), 'utf8'), + ); + symlinkSync( + realpathSync(sdkPackage), + path.join( + pack, + packageManifest.name.replace(/^@/u, '').replace('/', '-') + + '-' + + packageManifest.version + + '.tgz', + ), + ); + Object.assign(env, { + CI_HEAD_SHA: sha, + OLIPHAUNT_MOBILE_E2E_CANDIDATE_SHA: sha, + OLIPHAUNT_EXPO_ANDROID_APK: apk, + OLIPHAUNT_EXPO_ANDROID_BUILD_TYPE: 'release', + OLIPHAUNT_EXPO_ANDROID_RUNNER: 'smoke', + OLIPHAUNT_EXPO_ANDROID_EXTENSIONS: spec.extensions.join(','), + OLIPHAUNT_EXPO_ANDROID_LIFECYCLE_SMOKE: '1', + OLIPHAUNT_EXPO_ANDROID_SCRATCH: output, + OLIPHAUNT_EXPO_ANDROID_PACK_DIR: pack, + OLIPHAUNT_EXPO_ANDROID_TIMEOUT_SECONDS: String(Math.floor(remaining() / 1000)), + }); + const child = Bun.spawn( + [ + '/bin/bash', + path.join(checkout, 'src/native/sdks/react-native/tools/mobile-e2e.sh'), + 'android', + ], + { + cwd: checkout, + env, + stdout: 'inherit', + stderr: 'inherit', + timeout: remaining(), + killSignal: 'SIGKILL', + }, + ); + assert.equal( + await child.exited, + 0, + 'Original installed Android SQL/reopen/lifecycle qualification failed', + ); + assertLifecycleReceipt(readFileSync(path.join(output, 'logs/smoke-logcat.log'), 'utf8')); + assertInstalledApk(apk, proofFile, spec.extensions); + assertCandidateCheckout(checkout, sha, tree, helpers); + const identities = await Promise.all( + [ + 'emulator/emulator', + 'emulator/qemu/linux-x86_64/qemu-system-x86_64-headless', + `${metadata.imagePath}/system.img`, + `${metadata.imagePath}/vendor.img`, + `${metadata.imagePath}/kernel-ranchu`, + `${metadata.imagePath}/ramdisk.img`, + ].map(async (relative) => ({ + relative, + sha256: await fileDigest(path.join(sdk, relative)), + })), + ); + writeFileSync( + path.join(output, 'installed-apk.json'), + JSON.stringify( + { + schema: 'oliphaunt-native-installed-android-apk-v1', + source: { commit: sha, tree }, + apkSha256: proof.apkSha256, + adbSha256: digest(adb), + acquisition: metadata, + actualDevice: { serial, abi: actualAbi, api: Number(actualApi) }, + files: identities, + lifecycle: true, + extensionReceipt: JSON.parse( + readFileSync(path.join(output, 'reports/smoke-extension-receipt.json'), 'utf8'), + ), + }, + null, + 2, + ) + '\n', + ); + } catch (error) { + captureInstalledAndroidFailure(adb, serverPort, serial, output, scratch, env); + console.error(`Installed Android failure diagnostics retained in ${output}`); + throw error; + } finally { + Bun.spawnSync([adb, '-P', String(serverPort), '-s', `emulator-${port}`, 'emu', 'kill'], { + cwd: scratch, + env, + stdout: 'ignore', + stderr: 'ignore', + timeout: 5000, + killSignal: 'SIGKILL', + }); + if (processHandle && processHandle.exitCode === null) { + processHandle.kill(); + await Promise.race([processHandle.exited, Bun.sleep(5000)]); + if (processHandle.exitCode === null) { + processHandle.kill('SIGKILL'); + await processHandle.exited; + } + } + Bun.spawnSync([adb, '-P', String(serverPort), 'kill-server'], { + cwd: scratch, + env, + stdout: 'ignore', + stderr: 'ignore', + timeout: 5000, + killSignal: 'SIGKILL', + }); + } + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +} + +if (import.meta.main) await runInstalledAndroid(process.argv.slice(2)); diff --git a/build_defs/android/installed-app.test.mts b/build_defs/android/installed-app.test.mts new file mode 100644 index 000000000..d6cf510cb --- /dev/null +++ b/build_defs/android/installed-app.test.mts @@ -0,0 +1,176 @@ +import { test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { chmodSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + assertInstalledApk, + assertKvmAvailable, + captureInstalledAndroidFailure, + emulatorArguments, + stageSdkFiles, +} from './installed-app.mts'; +import { assertLifecycleReceipt } from '../apple/installed-app.mts'; + +test('installed test binds the exact final signed APK, selected extensions and emulator ABI', () => { + const root = mkdtempSync(path.join(tmpdir(), 'android-installed-contract-')); + try { + const apk = path.join(root, 'final.apk'), + file = path.join(root, 'proof.json'); + writeFileSync(apk, 'real File fixture, not a device execution claim'); + const proof = { + schema: 'oliphaunt-expo-android-apk-proof-v1', + abi: 'x86_64', + applicationId: 'dev.oliphaunt.reactnative.example', + selectedExtensions: ['vector'], + apkSha256: createHash('sha256').update(readFileSync(apk)).digest('hex'), + }; + writeFileSync(file, JSON.stringify(proof)); + assert.equal(assertInstalledApk(apk, file, ['vector']).apkSha256, proof.apkSha256); + assert.throws(() => assertInstalledApk(apk, file, [])); + writeFileSync(file, JSON.stringify({ ...proof, abi: 'arm64-v8a' })); + assert.throws(() => assertInstalledApk(apk, file, ['vector']), /emulator ABI/u); + writeFileSync(file, JSON.stringify(proof)); + writeFileSync(apk, 'substituted APK'); + assert.throws(() => assertInstalledApk(apk, file, ['vector']), /exact final/u); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('read-only SDK inputs retain declared paths while only the avdmanager launcher is copied', () => { + const root = mkdtempSync(path.join(tmpdir(), 'android-sdk-transport-')); + try { + const file = path.join(root, 'original'); + writeFileSync(file, 'original declared bytes'); + const output = path.join(root, 'sdk'); + stageSdkFiles( + output, + [ + { relative: 'cmdline-tools/latest/bin/avdmanager', index: 0 }, + { relative: 'system-images/android-35/google_atd/x86_64/system.img', index: 0 }, + ], + [file], + ); + assert.equal( + readFileSync(path.join(output, 'cmdline-tools/latest/bin/avdmanager'), 'utf8'), + readFileSync(file, 'utf8'), + ); + assert.equal( + readFileSync( + path.join(output, 'system-images/android-35/google_atd/x86_64/system.img'), + 'utf8', + ), + readFileSync(file, 'utf8'), + ); + assert.throws( + () => stageSdkFiles(path.join(root, 'escape'), [{ relative: '../escape', index: 0 }], [file]), + /Unsafe/u, + ); + assert.throws( + () => + stageSdkFiles( + path.join(root, 'duplicate'), + [ + { relative: 'file', index: 0 }, + { relative: 'file', index: 0 }, + ], + [file], + ), + /Repeated/u, + ); + const directory = path.join(root, 'directory'); + mkdirSync(directory); + assert.throws( + () => stageSdkFiles(path.join(root, 'dir'), [{ relative: 'file', index: 0 }], [directory]), + /regular/u, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('private emulator launch always uses KVM and requires actual lifecycle receipt stages', () => { + const args = emulatorArguments('oliphaunt-bazel-1234abcd', 5554, '/private/sdk'); + assert(args.includes('-wipe-data')); + assert(args.includes('-no-snapshot')); + assert.equal(args[args.indexOf('-accel') + 1], 'on'); + assert.equal(args[args.indexOf('-port') + 1], '5554'); + for (const port of [5555, 0, 5682]) + assert.throws(() => emulatorArguments('oliphaunt-bazel-1234abcd', port, '/sdk')); + assert.throws( + () => assertKvmAvailable('/definitely-absent-oliphaunt-kvm'), + /No device test was executed/u, + ); + const events = [ + { stage: 'lifecycle:ready', state: 'active' }, + { stage: 'lifecycle:state', state: 'background' }, + { stage: 'lifecycle:state', state: 'active' }, + { stage: 'lifecycle:sql:done' }, + ]; + const lines = events.map((event) => 'OLIPHAUNT_EXPO_SMOKE_STAGE ' + JSON.stringify(event)); + lines.push('OLIPHAUNT_EXPO_SMOKE_PASS {"lifecycleResume":true}'); + const stages = lines.join('\n'); + assertLifecycleReceipt(stages); + assert.throws(() => assertLifecycleReceipt('OLIPHAUNT_EXPO_SMOKE_PASS {}'), /omitted/u); + assert.throws( + () => assertLifecycleReceipt(stages.replaceAll('background', 'active')), + /background/u, + ); + assert.throws( + () => assertLifecycleReceipt(stages.replaceAll('background', 'inactive')), + /background/u, + ); + for (let omitted = 0; omitted < lines.length; omitted++) + assert.throws( + () => assertLifecycleReceipt(lines.filter((_, index) => index !== omitted).join('\n')), + /ordered/u, + ); + for (let index = 0; index < lines.length - 1; index++) { + const reordered = [...lines]; + [reordered[index], reordered[index + 1]] = [reordered[index + 1], reordered[index]]; + assert.throws(() => assertLifecycleReceipt(reordered.join('\n')), /ordered/u); + } +}); + +test.skipIf(process.platform !== 'linux')( + 'failure diagnostics retain bounded Linux device output from a failed adb', + () => { + const root = mkdtempSync(path.join(tmpdir(), 'android-installed-failure-')); + try { + const adb = path.join(root, 'fixture-adb'); + writeFileSync(adb, '#!/bin/sh\nprintf "%s\\n" "$*"\nexit 7\n'); + chmodSync(adb, 0o755); + captureInstalledAndroidFailure(adb, 56789, '127.0.0.1:5555', root, root, {}); + assert.equal( + readFileSync(path.join(root, 'failure-logcat.log'), 'utf8'), + '-P 56789 -s 127.0.0.1:5555 logcat -d -v threadtime -t 2000\n', + ); + assert.equal( + readFileSync(path.join(root, 'failure-activity.txt'), 'utf8'), + '-P 56789 -s 127.0.0.1:5555 shell dumpsys activity top\n', + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }, +); + +test('failure diagnostics retain a missing adb error on every host', () => { + const root = mkdtempSync(path.join(tmpdir(), 'android-installed-missing-adb-')); + try { + captureInstalledAndroidFailure( + path.join(root, 'missing-adb'), + 56789, + 'fixture', + root, + root, + {}, + ); + for (const file of ['failure-logcat.log', 'failure-activity.txt']) + assert(readFileSync(path.join(root, file), 'utf8').includes('ENOENT')); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/build_defs/android/jvm.bzl b/build_defs/android/jvm.bzl new file mode 100644 index 000000000..2451cfdb6 --- /dev/null +++ b/build_defs/android/jvm.bzl @@ -0,0 +1,103 @@ +"""Release source sets and exact bundled Expo AARs using maintained JVM rules.""" + +load("@rules_android//android:rules.bzl", "aar_import", "android_library") +load("@rules_kotlin//kotlin:android.bzl", "kt_android_library") +load("@rules_kotlin//kotlin:core.bzl", "kt_compiler_plugin", "kt_javac_options", "kt_plugin_cfg") +load("@oliphaunt_kotlin_manifest//:metadata.bzl", "KOTLIN") + +def _name(name): + return name.replace("@", "_").replace("/", "_").replace("-", "_").replace(".", "_") + +def _maven(coordinate): + parts = coordinate.split(":") + if parts[:2] == ["com.facebook.react", "react-android"] and len(parts) == 5 and parts[3] == "release": + return ":react_android_release" + classifier = "_" + parts[3] if len(parts) == 5 else "" + return "@expo_android_maven//:" + _name(parts[0] + "_" + parts[1] + classifier) + +def expo_android_jvm(metadata, safe_area_codegen): + """All original release sources, original module namespaces and plugins.""" + # Classifier-only AAR acquisition omits its Gradle variant dependency edges. + # Restore every original RN catalog dependency on the imported provider so + # its own desugar action has the same classpath as the upstream compilation. + aar_import( + name = "react_android_release", + aar = "@expo_android_maven//:com_facebook_react_react_android_aar_release_" + _name(metadata["reactNative"]) + "_extension", + deps = [_maven(coordinate) for coordinate in metadata["reactNativeDependencies"]] + [_maven("org.jetbrains.kotlin:kotlin-stdlib:" + metadata["kotlin"])], + ) + # The original upstream Gradle Java compiler has no Error Prone analyzer. + # Keep real javac diagnostics and the conventional JDK release unchanged. + kt_javac_options(name = "upstream_java_options", release = KOTLIN["jvmTarget"], x_ep_disable_all_checks = True) + kt_compiler_plugin( + name = "pika_compiler", + id = "io.github.lukmccall.pika", + target_embedded_compiler = True, + deps = ["@expo_android_maven//:io_github_lukmccall_pika_pika_compiler"], + options = {"enabled": "true"}, + ) + kt_plugin_cfg( + name = "pika_expo_annotations", + plugin = ":pika_compiler", + options = {"introspectableAnnotation": ["expo.modules.kotlin.types.OptimizedRecord", "expo.modules.kotlin.views.OptimizedComposeProps"]}, + ) + kt_compiler_plugin( + name = "compose_compiler", + id = "androidx.compose.compiler.plugins.kotlin", + target_embedded_compiler = True, + deps = ["@expo_android_maven//:org_jetbrains_kotlin_kotlin_compose_compiler_plugin_embeddable"], + ) + kt_compiler_plugin( + name = "serialization_compiler", + id = "org.jetbrains.kotlinx.serialization", + target_embedded_compiler = True, + deps = ["@expo_android_maven//:org_jetbrains_kotlin_kotlin_serialization_compiler_plugin_embeddable"], + ) + sources, resources, dependencies, published = [], [], {}, [] + safe_area = None + for module in metadata["modules"]: + name = _name(module["name"]) + deps = sorted({_maven(coordinate): True for coordinate in module["dependencies"]}.keys()) + if module["aar"]: + # ExpoModuleGradlePlugin adds its original modules-core project as + # compileOnly. Preserve that provider edge for published AAR desugar. + core = [":expo_release_classes"] if module["pika"] else [] + aar_import(name = name, aar = module["aar"], package = module["namespace"], deps = deps + core) + published.append(":" + name) + continue + android_library( + name = name + "_resources", + manifest = module["manifest"], + resource_files = [":" + name + "_resource_files"], + custom_package = module["namespace"], + deps = deps, + ) + if module["name"] == "react-native-safe-area-context": + safe_area = module + continue + sources += ([":" + name + "_sources"] if module["sources"] else []) + ["generated/" + name + "/BuildConfig.java"] + resources.append(":" + name + "_resources") + dependencies.update({dependency: True for dependency in deps}) + # Expo's release modules are compiled together, preserving their distinct + # R/BuildConfig namespaces and every original release source selector. + # The package registry is a separate app output so it can reference all + # compiled source modules and the pinned published AARs without a cycle. + kt_android_library( + name = "expo_release_classes", + javac_opts = ":upstream_java_options", + srcs = sources, + manifest = "source-manifest.xml", + custom_package = "expo.modules", + deps = resources + dependencies.keys(), + plugins = [":pika_expo_annotations", ":compose_compiler", ":serialization_compiler"], + ) + if not safe_area: + fail("The actual app autolinks react-native-safe-area-context") + kt_android_library( + name = "safe_area_classes", + javac_opts = ":upstream_java_options", + srcs = [":react_native_safe_area_context_sources", "generated/react_native_safe_area_context/BuildConfig.java", safe_area_codegen], + manifest = "source-manifest.xml", + custom_package = safe_area["namespace"], + deps = [":react_native_safe_area_context_resources"] + sorted({_maven(coordinate): True for coordinate in safe_area["dependencies"]}.keys()), + ) + android_library(name = "expo_modules", manifest = "source-manifest.xml", custom_package = "expo.modules", deps = [":expo_release_classes", ":safe_area_classes"] + published) diff --git a/build_defs/android/maven.bzl b/build_defs/android/maven.bzl new file mode 100644 index 000000000..0da603a2f --- /dev/null +++ b/build_defs/android/maven.bzl @@ -0,0 +1,3 @@ +"""A separate documented extension identity for the app's maintained Maven resolver.""" +load("@rules_jvm_external//:extensions.bzl", _maven = "maven") +maven = _maven diff --git a/build_defs/android/metadata.mts b/build_defs/android/metadata.mts new file mode 100644 index 000000000..66b54b531 --- /dev/null +++ b/build_defs/android/metadata.mts @@ -0,0 +1,51 @@ +import { PLATFORM_COMPATIBILITY_POLICY } from '../../tools/release/platform-compatibility-policy.mts'; + +export function androidNdkMetadata(value: unknown) { + const manifest = value as { + packages?: { ndk?: unknown }; + ndk?: { linux?: { url?: unknown; sha256?: unknown; strip_prefix?: unknown } }; + }; + const revision = manifest.packages?.ndk; + const archive = manifest.ndk?.linux; + if (typeof revision !== 'string' || !/^\d+\.\d+\.\d+$/u.test(revision)) { + throw new Error('Android native NDK must have an exact packages.ndk revision'); + } + if ( + typeof archive?.url !== 'string' || + !/^https:\/\/dl\.google\.com\/android\/repository\/android-ndk-r\d+[a-z]?-linux\.zip$/u.test( + archive.url, + ) || + typeof archive.sha256 !== 'string' || + !/^[a-f0-9]{64}$/u.test(archive.sha256) || + typeof archive.strip_prefix !== 'string' || + archive.strip_prefix !== archive.url.split('/').at(-1)?.replace('-linux.zip', '') + ) { + throw new Error('Android native NDK needs one checksummed canonical Google Linux archive'); + } + const api = PLATFORM_COMPATIBILITY_POLICY['android-arm64-v8a'].elf.androidApiLevel; + if (api !== PLATFORM_COMPATIBILITY_POLICY['android-x86_64'].elf.androidApiLevel) { + throw new Error('Android native targets must use the same canonical minimum API'); + } + const pageAlignment = + PLATFORM_COMPATIBILITY_POLICY['android-arm64-v8a'].elf.minimumLoadSegmentAlignment; + if ( + pageAlignment !== + PLATFORM_COMPATIBILITY_POLICY['android-x86_64'].elf.minimumLoadSegmentAlignment + ) { + throw new Error('Android native targets must use the same canonical ELF page alignment'); + } + return { + revision, + api, + page_alignment: pageAlignment, + url: archive.url, + sha256: archive.sha256, + strip_prefix: archive.strip_prefix, + }; +} + +if (import.meta.main) { + const source = process.argv[2]; + if (!source) throw new Error('usage: metadata.mts android-sdk.toml'); + console.log(JSON.stringify(androidNdkMetadata(Bun.TOML.parse(await Bun.file(source).text())))); +} diff --git a/build_defs/android/metadata.test.mts b/build_defs/android/metadata.test.mts new file mode 100644 index 000000000..9231e6cc5 --- /dev/null +++ b/build_defs/android/metadata.test.mts @@ -0,0 +1,177 @@ +import { expect, test } from 'bun:test'; +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { androidNdkMetadata } from './metadata.mts'; +import { + androidAppMinimumSdk, + androidReleaseDependencies, + nativeAndroidPackages, + reactNativeRuntimeDependencies, +} from './native-metadata.mts'; + +const input = { + packages: { ndk: '27.0.12077973', expo_ndk: '27.1.12297006' }, + ndk: { + linux: { + url: 'https://dl.google.com/android/repository/android-ndk-r27-linux.zip', + sha256: 'a'.repeat(64), + strip_prefix: 'android-ndk-r27', + }, + }, +}; + +test('app desugar SDK follows its original catalog and respects the native SDK floor', () => { + const sdk = 'android {\n defaultConfig {\n minSdk = 24\n }\n}'; + for (const minimum of [24, 26]) + expect(androidAppMinimumSdk('[versions]\nminSdk = "' + minimum + '"', sdk)).toBe(minimum); + expect(() => androidAppMinimumSdk('[versions]\nminSdk = "23"', sdk)).toThrow('supported minimum'); + for (const value of ['0', '-1', '24.5', 'latest']) + expect(() => androidAppMinimumSdk('[versions]\nminSdk = "' + value + '"', sdk)).toThrow( + 'valid minimum', + ); + expect(() => androidAppMinimumSdk('[versions]')).toThrow('valid minimum'); + expect(() => + androidAppMinimumSdk('[versions]\nminSdk = "24"', 'minSdk = project.minimum'), + ).toThrow('supported minimum'); +}); + +test('native Android reads the canonical NDK and minimum platform API', () => { + expect(androidNdkMetadata(input)).toEqual({ + revision: '27.0.12077973', + api: 24, + page_alignment: 16_384, + ...input.ndk.linux, + }); + expect( + androidNdkMetadata({ + ...input, + ndk: { linux: { ...input.ndk.linux, api: 99, revision: '1.0.0', page_alignment: 4096 } }, + }), + ).toEqual(androidNdkMetadata(input)); +}); + +test('native Android cannot import unpinned, foreign or inconsistent archives', () => { + expect(() => androidNdkMetadata({ ...input, packages: { ndk: 'latest' } })).toThrow(); + for (const patch of [ + { sha256: '' }, + { url: 'https://example.invalid/ndk.zip' }, + { strip_prefix: '../ndk' }, + ]) { + expect(() => + androidNdkMetadata({ ...input, ndk: { linux: { ...input.ndk.linux, ...patch } } }), + ).toThrow(); + } +}); + +test('native discovery preserves duplicate JS tools and excludes unrelated Expo prefixes', () => { + const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-native-discovery-')); + try { + const packages = [ + { package: '@expo/json-file', version: '1.0.0', root: path.join(root, 'json-one') }, + { package: '@expo/json-file', version: '2.0.0', root: path.join(root, 'json-two') }, + { package: 'exponential-backoff', version: '1.0.0', root: path.join(root, 'unrelated') }, + { package: 'expo-source-module', version: '56.0.0', root: path.join(root, 'native') }, + ]; + for (const row of packages) mkdirSync(row.root, { recursive: true }); + for (const row of packages.slice(2)) { + mkdirSync(path.join(row.root, 'android')); + writeFileSync( + path.join(row.root, 'android/build.gradle'), + 'namespace "expo.modules.fixture"', + ); + } + expect(nativeAndroidPackages(packages)).toEqual([packages[3]]); + expect(packages.slice(0, 2).map((row) => row.version)).toEqual(['1.0.0', '2.0.0']); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('native discovery rejects ambiguous actual Android implementations', () => { + const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-native-discovery-')); + try { + const packages = ['56.0.0', '56.0.1'].map((version) => ({ + package: 'expo-source-module', + version, + root: path.join(root, version), + })); + for (const row of packages) { + mkdirSync(path.join(row.root, 'android'), { recursive: true }); + writeFileSync( + path.join(row.root, 'android/build.gradle'), + 'namespace "expo.modules.fixture"', + ); + } + expect(() => nativeAndroidPackages(packages)).toThrow('one exact locked package identity'); + expect(nativeAndroidPackages([packages[0], packages[0]])).toEqual([packages[0]]); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('withoutCompose release preserves active roots and omits the disabled Gradle branch', () => { + const source = ` +dependencies { + implementation 'androidx.core:core-ktx:1.17.0' + if (shouldIncludeCompose) { + // A commented closing brace } cannot end the branch. + if (enabled) { + implementation "androidx.compose.foundation:foundation-android:\${composeVersion}" + } + } + releaseCompileOnly 'androidx.compose.foundation:foundation-android:1.9.0' + implementation 'com.facebook.react:react-android' +} +`; + expect(androidReleaseDependencies(source, '2.2.21', '0.85.3', true)).toEqual([ + 'androidx.core:core-ktx:1.17.0', + 'androidx.compose.foundation:foundation-android:1.9.0', + 'com.facebook.react:react-android:aar:release:0.85.3', + ]); + expect(() => + androidReleaseDependencies('if (shouldIncludeCompose) {', '2.2.21', '0.85.3', true), + ).toThrow('Unterminated'); +}); + +test('Compose-enabled projection retains its source-declared dependency version', () => { + const source = `def composeVersion = "1.7.6" +dependencies { + if (shouldIncludeCompose) { + implementation "androidx.compose.foundation:foundation-android:$composeVersion" + } +}`; + expect(androidReleaseDependencies(source, '2.2.21', '0.85.3')).toEqual([ + 'androidx.compose.foundation:foundation-android:1.7.6', + ]); + expect(androidReleaseDependencies(source, '2.2.21', '0.85.3', true)).toEqual([]); +}); + +test('React Native release runtime follows source catalog aliases and excludes test/compile-only roots', () => { + const source = `dependencies { + api(libs.fresco.imagepipeline.okhttp3) + implementation(libs.soloader) + runtimeOnly(libs.fresco) + compileOnly(libs.javax.annotation.api) + testImplementation(libs.junit) +}`; + const catalog = `[versions] +fresco = "3.6.0" +soloader = "0.12.1" +[libraries] +fresco-imagepipeline-okhttp3 = { module = "com.facebook.fresco:imagepipeline-okhttp3", version.ref = "fresco" } +fresco = { module = "com.facebook.fresco:fresco", version.ref = "fresco" } +soloader = { group = "com.facebook.soloader", name = "soloader", version.ref = "soloader" } +`; + expect(reactNativeRuntimeDependencies(source, catalog)).toEqual([ + 'com.facebook.fresco:fresco:3.6.0', + 'com.facebook.fresco:imagepipeline-okhttp3:3.6.0', + 'com.facebook.soloader:soloader:0.12.1', + ]); + expect(() => reactNativeRuntimeDependencies('api(libs.missing)', catalog)).toThrow( + 'alias missing', + ); + expect(() => reactNativeRuntimeDependencies('testImplementation(libs.junit)', catalog)).toThrow( + 'declarations are missing', + ); +}); diff --git a/build_defs/android/min-sdk-test.xml b/build_defs/android/min-sdk-test.xml new file mode 100644 index 000000000..2be606bc5 --- /dev/null +++ b/build_defs/android/min-sdk-test.xml @@ -0,0 +1,4 @@ + + + + diff --git a/build_defs/android/native-cpp.bzl b/build_defs/android/native-cpp.bzl new file mode 100644 index 000000000..1ec2ef380 --- /dev/null +++ b/build_defs/android/native-cpp.bzl @@ -0,0 +1,125 @@ +"""Original Expo and RN application C++ sources over declared prefab CcInfo.""" + +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_import", "cc_library") + +_ANDROID = ["@platforms//os:android"] +_FOLLY_DEFINES = [ + "FOLLY_NO_CONFIG=1", + "FOLLY_HAVE_CLOCK_GETTIME=1", + "FOLLY_USE_LIBCPP=1", + "FOLLY_CFG_NO_COROUTINES=1", + "FOLLY_MOBILE=1", + "FOLLY_HAVE_RECVMMSG=1", + "FOLLY_HAVE_PTHREAD=1", + "FOLLY_HAVE_XSI_STRERROR_R=1", +] +_RN_COPTS = ["-Wall", "-Werror", "-fexceptions", "-frtti", "-std=c++20"] +_RN_DEFINES = _FOLLY_DEFINES + ["ANDROID", "NDEBUG=1", "LOG_TAG=\"ReactNative\"", "RN_SERIALIZABLE_STATE"] +REACT_NATIVE_RELEASE_DEFINES = _RN_DEFINES +_SHARED_LINKOPTS = ["-Wl,-z,max-page-size=16384", "-Wl,-z,common-page-size=16384", "-Wl,-z,defs"] + +def _sources(patterns): + files = native.glob(patterns, allow_empty = True) + if not files: + fail("Original native source selector has no translation units: " + str(patterns)) + return files + +def expo_core_cpp(name, root, react_native_deps, fbjni, cxx_runtime, shared_runtime_features, react_native_jni_root, react_native_minor = 85, worklets = None, worklets_include_dirs = []): + """CMake jsi/main/common selectors, normal release flags and semantic PCH.""" + if bool(worklets) != bool(worklets_include_dirs): + fail("Expo Worklets integration requires its actual CcInfo and source include directories together") + if "-static_link_cpp_runtimes" not in shared_runtime_features: + fail("RN prefab consumers require the maintained NDK's static_link_cpp_runtimes feature disabled and its actual shared runtime CcInfo") + common = root + "/common/cpp" + android = root + "/android/src" + main = android + "/main/cpp" + pch = main + "/ExpoHeader.pch" + headers = native.glob([common + "/**/*.h", main + "/**/*.h"]) + native.glob([common + "/**/*.hpp", main + "/**/*.hpp", android + "/fabric/**/*.h"], allow_empty = True) + copts = ["-std=c++20", "-O2", "-frtti", "-fexceptions", "-Wall", "-fstack-protector-all", "-include", "$(location " + pch + ")"] + defines = _FOLLY_DEFINES + [ + "ANDROID", "NDEBUG=1", "USE_HERMES=0", "UNIT_TEST=0", "IS_NEW_ARCHITECTURE_ENABLED=1", + "RN_FABRIC_ENABLED=1", "RN_SERIALIZABLE_STATE=1", + "REACT_NATIVE_TARGET_VERSION=" + str(react_native_minor), + "REACT_NATIVE_MINOR_VERSION=" + str(react_native_minor), + ] + dependencies = react_native_deps + [fbjni, cxx_runtime] + cc_library( + name = name + "_jsi", + srcs = native.glob([common + "/JSI/*.cpp", android + "/jsi/*.cpp"]), + hdrs = native.glob([android + "/jsi/*.h"]) + headers, + textual_hdrs = [pch], + additional_compiler_inputs = [pch], + includes = [common + "/JSI", android + "/jsi", common, common + "/fabric", android + "/fabric", react_native_jni_root], + copts = copts, + local_defines = defines, + features = shared_runtime_features, + deps = dependencies, + target_compatible_with = _ANDROID, + ) + cc_library( + name = name + "_sources", + srcs = _sources([common + "/*.cpp", common + "/fabric/*.cpp"] + + [main + "/" + folder + "*.cpp" for folder in ["", "types/", "javaclasses/", "decorators/", "installers/", "worklets/", "fabric/"]]), + includes = [react_native_jni_root, android + "/fabric", common, common + "/fabric"] + worklets_include_dirs, + hdrs = headers, + textual_hdrs = [pch], + additional_compiler_inputs = [pch], + copts = copts, + local_defines = defines + (["WORKLETS_ENABLED=1"] if worklets else []), + features = shared_runtime_features, + deps = dependencies + [":" + name + "_jsi"] + ([worklets] if worklets else []), + alwayslink = True, + target_compatible_with = _ANDROID, + ) + cc_binary(name = "libexpo-modules-core.so", deps = [":" + name + "_sources"], + features = shared_runtime_features, linkshared = True, linkstatic = True, + linkopts = _SHARED_LINKOPTS + ["-Wl,-soname,libexpo-modules-core.so", "-llog", "-landroid"], target_compatible_with = _ANDROID) + return ":libexpo-modules-core.so" + +def safe_area_cpp(name, root, generated_sources, generated_headers, generated_include_dirs, react_native_deps, fbjni, cxx_runtime, shared_runtime_features, react_native_copts = [], react_native_defines = []): + """Upstream Fabric custom sources plus the actual generated codegen Files.""" + common = root + "/common/cpp" + jni = root + "/android/src/main/jni" + library = "libreact_codegen_safeareacontext.so" + cc_library( + name = name + "_sources", + srcs = _sources([jni + "/*.cpp", common + "/react/renderer/components/safeareacontext/*.cpp"]) + generated_sources, + hdrs = native.glob([jni + "/*.h", common + "/**/*.h"]) + generated_headers, + includes = [jni, common] + generated_include_dirs, + copts = _RN_COPTS + ["-Wpedantic", "-Wno-gnu-zero-variadic-macro-arguments", "-Wno-dollar-in-identifier-extension"] + react_native_copts, + local_defines = _RN_DEFINES + react_native_defines, + features = shared_runtime_features, + deps = react_native_deps + [fbjni, cxx_runtime], + alwayslink = True, + target_compatible_with = _ANDROID, + ) + cc_binary(name = library, deps = [":" + name + "_sources"], features = shared_runtime_features, + linkshared = True, linkstatic = True, linkopts = _SHARED_LINKOPTS + ["-Wl,-soname," + library], target_compatible_with = _ANDROID) + cc_import(name = name + "_shared", shared_library = ":" + library, target_compatible_with = _ANDROID) + # Its actual headers and shared binary are consumed by application autolinking. + cc_library( + name = name, + hdrs = native.glob([jni + "/*.h", common + "/**/*.h"]) + generated_headers, + includes = [jni, common] + generated_include_dirs, + deps = react_native_deps + [fbjni, cxx_runtime, ":" + name + "_shared"], + target_compatible_with = _ANDROID, + ) + return ":" + library + +def react_native_app_cpp(name, react_native_root, autolinking_sources, autolinking_headers, autolinking_include_dirs, generated_sources, generated_headers, generated_include_dirs, react_native_deps, fbjni, cxx_runtime, shared_runtime_features, native_module_deps, react_native_copts = [], react_native_defines = []): + """Original RN OnLoad, original generated autolinking and app codegen graph.""" + cc_library( + name = name + "_sources", + srcs = native.glob([react_native_root + "/ReactAndroid/cmake-utils/default-app-setup/*.cpp"]) + autolinking_sources + generated_sources, + hdrs = autolinking_headers + generated_headers, + includes = autolinking_include_dirs + generated_include_dirs, + copts = _RN_COPTS + react_native_copts, + local_defines = _RN_DEFINES + react_native_defines, + features = shared_runtime_features, + deps = react_native_deps + [fbjni, cxx_runtime] + native_module_deps, + alwayslink = True, + target_compatible_with = _ANDROID, + ) + cc_binary(name = "libappmodules.so", deps = [":" + name + "_sources"], features = shared_runtime_features, + linkshared = True, linkstatic = True, linkopts = _SHARED_LINKOPTS + ["-Wl,-soname,libappmodules.so"], target_compatible_with = _ANDROID) + return ":libappmodules.so" diff --git a/build_defs/android/native-metadata.mts b/build_defs/android/native-metadata.mts new file mode 100644 index 000000000..d0a968eea --- /dev/null +++ b/build_defs/android/native-metadata.mts @@ -0,0 +1,490 @@ +import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; + +type Package = { package: string; version: string; root: string }; +type Module = { + name: string; + namespace: string; + root: string; + sources: string[]; + resources: string[]; + manifest: string; + aar?: string; + dependencies: string[]; + buildConfig: Record; + pika: boolean; +}; +const text = (file: string) => readFileSync(file, 'utf8'); +export function nativeAndroidPackages(packages: Package[]) { + const identities = new Map(); + for (const row of packages) { + const candidate = + row.package === 'react-native' || + row.package === 'react-native-safe-area-context' || + row.package === 'expo' || + row.package.startsWith('expo-') || + row.package.startsWith('@expo/'); + const native = + candidate && + (existsSync(path.join(row.root, 'android/build.gradle')) || + existsSync(path.join(row.root, 'android/build.gradle.kts')) || + (row.package === 'react-native' && + existsSync(path.join(row.root, 'ReactAndroid/gradle.properties')))); + if (!native) continue; + const previous = identities.get(row.package); + if ( + previous && + (previous.version !== row.version || path.resolve(previous.root) !== path.resolve(row.root)) + ) + throw new Error( + `Native Android autolinking needs one exact locked package identity: ${row.package}`, + ); + identities.set(row.package, row); + } + return [...identities.values()]; +} +function required(source: string, expression: RegExp, description: string) { + const value = source.match(expression)?.[1]; + if (!value) throw new Error(`Conventional Android metadata is missing ${description}`); + return value; +} +function properties(source: string) { + return Object.fromEntries( + source + .split(/\r?\n/) + .filter((line) => line && !line.startsWith('#')) + .map((line) => { + const at = line.indexOf('='); + return [line.slice(0, at), line.slice(at + 1)]; + }), + ); +} +const coordinateLabel = (coordinate: string) => + coordinate + .split(':') + .slice(0, 2) + .join('_') + .replaceAll(/[^A-Za-z0-9_]/g, '_'); +export function reactNativeRuntimeDependencies(source: string, catalogSource: string): string[] { + const catalog = Bun.TOML.parse(catalogSource) as { + versions: Record; + libraries: Record< + string, + { module?: string; group?: string; name?: string; version: string | { ref: string } } + >; + }; + const result = new Set(); + for (const match of source.matchAll( + /^\s*(?:api|implementation|runtimeOnly)\(libs\.([\w.]+)\)/gm, + )) { + const alias = match[1].replaceAll('.', '-'); + const library = catalog.libraries[alias]; + if (!library) throw new Error(`Missing conventional React Native catalog alias ${alias}`); + const module = library.module ?? `${library.group}:${library.name}`; + const version = + typeof library.version === 'string' ? library.version : catalog.versions[library.version.ref]; + if (!/^[\w.-]+:[\w.-]+$/.test(module) || !version) + throw new Error(`Incomplete conventional React Native runtime dependency ${alias}`); + result.add(`${module}:${version}`); + } + if (!result.size) + throw new Error('React Native release runtime dependency declarations are missing'); + return [...result].sort(); +} +function disabledComposeBranches(source: string) { + const branches: [number, number][] = []; + for (const match of source.matchAll(/\bif\s*\(shouldIncludeCompose\)\s*\{/g)) { + const start = match.index!; + let depth = 1, + at = start + match[0].length; + for (; at < source.length && depth; at++) { + const char = source[at]; + if (char === '"' || char === "'") { + const quote = char; + for (at++; at < source.length; at++) { + if (source[at] === '\\') at++; + else if (source[at] === quote) break; + } + } else if (char === '/' && source[at + 1] === '/') { + while (at < source.length && source[at] !== '\n') at++; + } else if (char === '/' && source[at + 1] === '*') { + const end = source.indexOf('*/', at + 2); + if (end < 0) throw new Error('Unterminated conventional Android comment'); + at = end + 1; + } else if (char === '{') depth++; + else if (char === '}') depth--; + } + if (depth) throw new Error('Unterminated conventional Android Compose branch'); + branches.push([start, at]); + } + return branches; +} +export function androidReleaseDependencies( + source: string, + kotlin: string, + rn: string, + withoutCompose = false, +): string[] { + const variables = Object.fromEntries( + [...source.matchAll(/(?:def|val)\s+(\w+)\s*=\s*['"]([^'"]+)['"]/g)].map((match) => [ + match[1], + match[2], + ]), + ); + variables.kotlinVersion = kotlin; + variables.kotlin_version = kotlin; + const result: string[] = []; + const disabled = withoutCompose ? disabledComposeBranches(source) : []; + for (const match of source.matchAll( + /^\s*(?:implementation|api|compileOnly|releaseCompileOnly)\s*\(?\s*['"]([^'"]+)['"]/gm, + )) { + if (disabled.some(([start, end]) => match.index! >= start && match.index! < end)) continue; + let coordinate = match[1].replaceAll(/\$\{?(\w+)\}?/g, (_, name: string) => { + if (!variables[name]) + throw new Error(`Unresolved conventional Android dependency variable ${name}`); + return variables[name]; + }); + if ( + coordinate === 'com.facebook.react:react-android' || + coordinate === 'com.facebook.react:react-native:+' + ) + coordinate = `com.facebook.react:react-android:aar:release:${rn}`; + // The upstream Gradle module redirects the androidJvm release variant to + // this AAR; its common metadata JAR contains no Android implementation. + if (coordinate.startsWith('com.squareup.zstd:zstd-kmp-okio:')) + coordinate = `com.squareup.zstd:zstd-kmp-okio-android:aar:${coordinate.split(':').at(-1)}`; + if ( + coordinate === 'com.facebook.react:hermes-android' || + coordinate.includes('org.webkit:android-jsc:') + ) + continue; // Only the upstream androidTest branch. + if (!/^[\w.-]+:[\w.-]+:[\w.+-]+(?::[\w.+-]+)*$/.test(coordinate)) + throw new Error(`Unsupported conventional Android dependency ${coordinate}`); + result.push(coordinate); + } + return [...new Set(result)]; +} +function pomDependencies(source: string, rn: string) { + return [...source.matchAll(/([\s\S]*?)<\/dependency>/g)] + .map((match) => { + const body = match[1]; + const module = ['groupId', 'artifactId'] + .map((tag) => required(body, new RegExp(`<${tag}>([^<]+)<\\/${tag}>`), `published ${tag}`)) + .join(':'); + if (module === 'com.facebook.react:react-android') return `${module}:aar:release:${rn}`; + const version = required(body, /([^<]+)<\/version>/, `${module} published version`); + return `${module}:${version}`; + }) + .filter( + (coordinate) => + !coordinate.startsWith('host.exp.exponent:') && !coordinate.startsWith('expo.modules.'), + ); +} +const sourceSets: Record = { + 'expo-modules-core': ['src/main/java', 'src/main/kotlin', 'src/withoutCompose'], + expo: ['src/main/java', 'src/main/kotlin', 'src/release/java', 'src/release/kotlin'], + 'expo-dev-launcher': ['src/main/java', 'src/main/kotlin', 'src/disableInRelease/java'], + 'expo-dev-menu': ['src/main/java', 'src/main/kotlin', 'src/disableInRelease/java'], + '@expo/log-box': ['src/main'], + 'react-native-safe-area-context': ['src/main/java', 'src/main/kotlin', 'src/fabric/java'], +}; + +export function androidAppMinimumSdk(catalogSource: string, sdkGradleSource?: string) { + const value = (Bun.TOML.parse(catalogSource).versions as Record | undefined) + ?.minSdk; + if ( + typeof value !== 'string' || + !/^\d+$/.test(value) || + !Number.isSafeInteger(Number(value)) || + Number(value) < 1 + ) + throw new Error('Conventional React Native catalog lacks a valid minimum SDK'); + const minimum = Number(value); + if (sdkGradleSource) { + const supportedMinimum = Number( + required( + sdkGradleSource, + /^\s*minSdk\s*=\s*(\d+)\s*$/m, + 'React Native SDK supported minimum', + ), + ); + if (minimum < supportedMinimum) + throw new Error('Expo app minimum SDK is below its native SDK supported minimum'); + } + return minimum; +} + +export function androidNativeMetadata( + packages: Package[], + kotlin: string, + sdkGradleSource?: string, +) { + packages = nativeAndroidPackages(packages); + const byName = new Map(packages.map((row) => [row.package, row])); + const rn = byName.get('react-native'); + if (!rn) throw new Error('Native Expo construction requires the locked React Native package'); + const rnProperties = properties(text(path.join(rn.root, 'ReactAndroid/gradle.properties'))); + const hermes = properties(text(path.join(rn.root, 'sdks/hermes-engine/version.properties'))); + if (rnProperties.VERSION_NAME !== rn.version) + throw new Error('React Native package/Android release version differs'); + const rnCatalog = text(path.join(rn.root, 'gradle/libs.versions.toml')); + const minSdkVersion = androidAppMinimumSdk(rnCatalog, sdkGradleSource); + const reactNativeDependencies = reactNativeRuntimeDependencies( + text(path.join(rn.root, 'ReactAndroid/build.gradle.kts')), + rnCatalog, + ); + const maven = new Set([ + ...reactNativeDependencies, + `com.facebook.react:react-android:aar:release:${rn.version}`, + `${rnProperties['react.internal.hermesPublishingGroup']}:hermes-android:aar:release:${hermes.HERMES_V1_VERSION_NAME}`, + ]); + const modules: Module[] = []; + for (const row of packages) { + const android = path.join(row.root, 'android'); + const gradleFile = path.join(android, 'build.gradle'); + if (!existsSync(gradleFile)) continue; + const gradle = text(gradleFile); + const namespace = required( + gradle, + /namespace\s*(?:=\s*)?["']([^"']+)["']/, + `${row.package} namespace`, + ); + const configFile = path.join(row.root, 'expo-module.config.json'); + const config = existsSync(configFile) ? (JSON.parse(text(configFile)).android ?? {}) : {}; + const publication = config.publication; + let aar: string | undefined; + let deps = androidReleaseDependencies( + gradle, + kotlin, + rn.version, + row.package === 'expo-modules-core', + ); + if (publication) { + const directory = path.join( + row.root, + publication.repository, + ...publication.groupId.split('.'), + publication.artifactId, + publication.version, + ); + aar = path.join(directory, `${publication.artifactId}-${publication.version}.aar`); + if (!existsSync(aar)) throw new Error(`Missing pinned Expo published AAR ${row.package}`); + deps = pomDependencies( + text(path.join(directory, `${publication.artifactId}-${publication.version}.pom`)), + rn.version, + ); + deps = deps.map((coordinate) => + coordinate.startsWith('com.facebook.react:react-android:') + ? `com.facebook.react:react-android:aar:release:${rn.version}` + : coordinate, + ); + } + if (row.package === 'expo-modules-core') { + const extension = text( + path.join( + row.root, + 'expo-module-gradle-plugin/src/main/kotlin/expo/modules/plugin/gradle/ExpoModuleExtension.kt', + ), + ); + if (!/enableCompileTimeOptimization[\s\S]*default\s*=\s*true/.test(extension)) + throw new Error('Expo compile-time optimization default changed'); + const plugin = text(path.join(row.root, 'expo-module-gradle-plugin/build.gradle.kts')); + const pika = required( + plugin, + /io\.github\.lukmccall\.pika:pika-gradle:([^"']+)/, + 'Expo Pika plugin version', + ); + maven.add(`io.github.lukmccall.pika:pika-compiler:${pika}-${kotlin}`); + maven.add(`org.jetbrains.kotlin:kotlin-compose-compiler-plugin-embeddable:${kotlin}`); + maven.add(`org.jetbrains.kotlin:kotlin-serialization-compiler-plugin-embeddable:${kotlin}`); + } + // Release disables dev-launcher/menu debug source sets. Their release-only + // stubs still compile with the originally applied compiler plugins. + if (row.package === 'expo-dev-menu') + deps = deps.filter((coordinate) => coordinate.startsWith('androidx.compose.foundation:')); + for (const coordinate of deps) { + maven.add(coordinate); + if (coordinate.startsWith('com.squareup.zstd:zstd-kmp-okio-android:')) + maven.add(`com.squareup.zstd:zstd-kmp-android:aar:${coordinate.split(':').at(-1)}`); + } + const buildConfig: Record = { + DEBUG: 'false', + LIBRARY_PACKAGE_NAME: JSON.stringify(namespace), + BUILD_TYPE: '"release"', + }; + if (row.package === 'expo-modules-core') + Object.assign(buildConfig, { + EXPO_MODULES_CORE_VERSION: JSON.stringify(row.version), + IS_NEW_ARCHITECTURE_ENABLED: 'true', + }); + if (row.package === 'expo-dev-launcher' || row.package === 'expo-dev-client') + buildConfig.VERSION = JSON.stringify(row.version); + if (row.package === 'expo-dev-menu') buildConfig.AUTO_INITIALIZATION = 'false'; + if (row.package === '@expo/log-box') buildConfig.EXPO_UNSTABLE_LOG_BOX = 'false'; + if (row.package === 'react-native-safe-area-context') + buildConfig.IS_NEW_ARCHITECTURE_ENABLED = 'true'; + modules.push({ + name: row.package, + namespace, + root: row.root, + aar, + dependencies: deps, + buildConfig, + pika: /expo-module-gradle-plugin/.test(gradle), + sources: (sourceSets[row.package] ?? ['src/main/java', 'src/main/kotlin']) + .map((directory) => path.join(android, directory)) + .filter(existsSync), + resources: [ + 'src/main/res', + ...(row.package === 'expo-dev-launcher' || row.package === 'expo-dev-menu' + ? ['src/disableInRelease/res'] + : ['src/release/res']), + ] + .map((directory) => path.join(android, directory)) + .filter(existsSync), + manifest: path.join(android, 'src/main/AndroidManifest.xml'), + }); + } + // Follow the RN-pinned ABI dependencies; Gradle resolves the older Expo + // compile-only fbjni request to RN's actual pinned version. + const fbjni = required(rnCatalog, /^fbjni\s*=\s*"([^"]+)"/m, 'React Native fbjni version'); + for (const coordinate of maven) + if (coordinate.startsWith('com.facebook.fbjni:fbjni:')) maven.delete(coordinate); + maven.add(`com.facebook.fbjni:fbjni:${fbjni}`); + for (const coordinate of [...maven]) + if (coordinate.startsWith('org.jetbrains.kotlin:')) { + maven.delete(coordinate); + maven.add(coordinate.split(':').slice(0, 2).join(':') + ':' + kotlin); + } + return { + modules, + maven: [...maven].sort(), + reactNative: rn.version, + minSdkVersion, + reactNativeDependencies, + hermes: hermes.HERMES_V1_VERSION_NAME, + kotlin, + fbjni, + }; +} + +function bzl(value: unknown): string { + if (value === undefined || value === null) return 'None'; + if (typeof value === 'boolean') return value ? 'True' : 'False'; + if (Array.isArray(value)) return `[${value.map(bzl).join(', ')}]`; + if (typeof value === 'object') + return `{${Object.entries(value) + .map(([key, item]) => `${bzl(key)}: ${bzl(item)}`) + .join(', ')}}`; + return JSON.stringify(value); +} + +export function emitAndroidNativeMetadata( + packages: Package[], + kotlin: string, + output: string, + sdkGradle?: string, +) { + const source = sdkGradle ? text(sdkGradle) : undefined; + const metadata = androidNativeMetadata(packages, kotlin, source); + if (source) { + const jna = required( + source, + /net\.java\.dev\.jna:jna:([^"']+)@aar/, + 'React Native Android JNA release', + ); + const topology = required( + source, + /def oliphauntTopology\s*=\s*\(oliphauntProperty\("oliphauntTopology"\)\s*\?:\s*"([^"]+)"/, + 'React Native default native topology', + ); + const namespace = required(source, /namespace\s*=\s*"([^"]+)"/, 'React Native SDK namespace'); + metadata.maven.push(`net.java.dev.jna:jna:aar:${jna}`); + metadata.maven.sort(); + writeFileSync( + path.join(output, 'jna-android.versions.toml'), + `[libraries]\njnaAndroid = ${JSON.stringify(`net.java.dev.jna:jna:aar:${jna}`)}\n`, + ); + Object.assign(metadata, { reactNativeSdk: { jna, namespace, topology } }); + const directory = path.join(output, 'generated/oliphaunt_react_native'); + mkdirSync(directory, { recursive: true }); + writeFileSync( + path.join(directory, 'BuildConfig.java'), + `package ${namespace};\npublic final class BuildConfig {\n public static final String OLIPHAUNT_TOPOLOGY = ${JSON.stringify(topology)};\n}\n`, + ); + } + const relative = (file: string) => path.relative(output, file).replaceAll(path.sep, '/'); + const modules = metadata.modules.map((row) => ({ + ...row, + root: relative(row.root), + aar: row.aar && relative(row.aar), + manifest: relative(row.manifest), + sources: row.sources.map(relative), + resources: row.resources.map(relative), + })); + writeFileSync( + path.join(output, 'metadata.bzl'), + `ANDROID_NATIVE = ${bzl({ ...metadata, modules })}\n`, + ); + writeFileSync( + path.join(output, 'maven.versions.toml'), + `[libraries]\n${metadata.maven.map((coordinate, index) => `native${index} = ${JSON.stringify(coordinate)}`).join('\n')}\n`, + ); + const build = [ + 'load("@oliphaunt//build_defs/android:jvm.bzl", "expo_android_jvm")', + 'load("@oliphaunt//build_defs/android:native-targets.bzl", "expo_android_native")', + 'load(":metadata.bzl", "ANDROID_NATIVE")', + 'package(default_visibility = ["//visibility:public"])', + `exports_files(${bzl(['metadata.bzl', 'maven.versions.toml', ...(sdkGradle ? ['jna-android.versions.toml'] : [])])})`, + ]; + for (const row of modules) { + const name = coordinateLabel(row.name); + build.push( + `filegroup(name = ${JSON.stringify(name + '_sources')}, srcs = glob(${bzl(row.sources.flatMap((directory) => [directory + '/**/*.kt', directory + '/**/*.java']))}, allow_empty = True))`, + ); + build.push( + `filegroup(name = ${JSON.stringify(name + '_resource_files')}, srcs = glob(${bzl(row.resources.map((directory) => directory + '/**/*'))}, allow_empty = True))`, + ); + if (!row.aar) { + const directory = path.join(output, 'generated', name); + mkdirSync(directory, { recursive: true }); + writeFileSync( + path.join(directory, 'BuildConfig.java'), + `package ${row.namespace};\npublic final class BuildConfig {\n${Object.entries( + row.buildConfig, + ) + .map( + ([name, value]) => + ` public static final ${value.startsWith('"') ? 'String' : 'boolean'} ${name} = ${value};`, + ) + .join('\n')}\n}\n`, + ); + } + if (row.aar) build.push(`exports_files([${JSON.stringify(row.aar)}])`); + if (existsSync(path.join(output, row.manifest))) + build.push(`exports_files([${JSON.stringify(row.manifest)}])`); + } + writeFileSync( + path.join(output, 'source-manifest.xml'), + '\n', + ); + build.push( + 'exports_files(glob(["packages/react-native/ReactAndroid/cmake-utils/default-app-setup/*.cpp", "packages/expo-modules-core/android/src/main/cpp/ExpoHeader.pch", "generated/oliphaunt_react_native/BuildConfig.java"]))', + ); + build.push( + 'expo_android_jvm(metadata = ANDROID_NATIVE, safe_area_codegen = "@oliphaunt//src/examples/native/react-native-expo:safe_area_codegen")', + ); + build.push('expo_android_native(metadata = ANDROID_NATIVE)'); + writeFileSync(path.join(output, 'BUILD.bazel'), build.join('\n') + '\n'); + return metadata; +} + +if (import.meta.main) { + const [input, catalog, output, sdkGradle] = process.argv.slice(2); + emitAndroidNativeMetadata( + JSON.parse(text(input)), + (Bun.TOML.parse(text(catalog)) as any).versions.kotlin, + output, + sdkGradle, + ); +} diff --git a/build_defs/android/native-repository.bzl b/build_defs/android/native-repository.bzl new file mode 100644 index 000000000..c3f403226 --- /dev/null +++ b/build_defs/android/native-repository.bzl @@ -0,0 +1,82 @@ +"""Native Android inputs from the same conventional Expo npm lock graph.""" + +def _impl(ctx): + data = json.decode(ctx.read(ctx.attr.metadata)) + packages = data["packages"] + rows, apple_rows, identities, acquired = [], [], {}, {} + for key in sorted(packages): + row = packages[key] + name = row["package"] + if not (name == "react-native" or name == "react-native-safe-area-context" or name == "expo" or name.startswith("expo-") or name.startswith("@expo/")): + continue + identity = json.encode([name, row["version"], row["integrity"]]) + if identity in acquired: + continue + acquired[identity] = True + basename = name.split("/")[-1] + output = "acquired/" + key + ctx.download_and_extract( + url = "https://registry.npmjs.org/" + name + "/-/" + basename + "-" + row["version"] + ".tgz", + integrity = row["integrity"], + output = output, + stripPrefix = "package", + ) + apple_rows.append({"package": name, "version": row["version"], "integrity": row["integrity"], "root": str(ctx.path(output))}) + native_source = ctx.path(output + "/android/build.gradle").exists or ctx.path(output + "/android/build.gradle.kts").exists or name == "react-native" and ctx.path(output + "/ReactAndroid/gradle.properties").exists + if not native_source: + continue + if name in identities: + fail("Native Android autolinking needs one exact locked package identity: " + name) + identities[name] = [row["version"], row["integrity"]] + logical = "packages/" + name + ctx.symlink(ctx.path(output), logical) + rows.append({"package": name, "version": row["version"], "root": str(ctx.path(logical))}) + ctx.read(ctx.attr.kotlin_catalog) + ctx.read(ctx.attr.sdk_gradle) + ctx.read(ctx.attr.converter) + ctx.watch(ctx.path(ctx.attr.bun)) + ctx.file("native-inputs.json", json.encode(rows)) + result = ctx.execute([str(ctx.path(ctx.attr.bun)), str(ctx.path(ctx.attr.converter)), str(ctx.path("native-inputs.json")), str(ctx.path(ctx.attr.kotlin_catalog)), str(ctx.path(".")), str(ctx.path(ctx.attr.sdk_gradle))], timeout = 60, quiet = True) + if result.return_code: + fail("Cannot project Expo release native compiler inputs:\n" + result.stdout + result.stderr) + # The same original package Files also own the Apple source projection. + # Acquire once; platform projections do not resolve or redownload dependencies. + ctx.read(ctx.attr.apple_converter) + ctx.read(ctx.attr.sdk_manifest) + ctx.file("apple-inputs.json", json.encode(apple_rows)) + apple = ctx.execute([str(ctx.path(ctx.attr.bun)), str(ctx.path(ctx.attr.apple_converter)), str(ctx.path("apple-inputs.json")), str(ctx.path(".")), str(ctx.path(ctx.attr.sdk_manifest))], timeout = 60, quiet = True) + if apple.return_code: + fail("Cannot project Expo release Apple compiler inputs:\n" + apple.stdout + apple.stderr) + metadata = json.decode(ctx.read("apple-metadata.json")) + for framework in metadata["frameworks"]: + ctx.extract(archive = ctx.path(framework["archive"]), output = "apple-prebuilt") + loads = 'load("@oliphaunt//build_defs/apple:native.bzl", "expo_apple_modules")\nload(":apple-metadata.bzl", "APPLE_NATIVE")\n' + ctx.file("BUILD.bazel", loads + ctx.read("BUILD.bazel") + """ +exports_files(["apple-metadata.json", "apple-metadata.bzl"]) +expo_apple_modules( + metadata = APPLE_NATIVE, + react = "@react_native_apple_release//:React", + hermes = "@react_native_apple_release//:hermes", + dependencies = "@react_native_apple_release//:dependencies", + react_headers = "@oliphaunt//src/examples/native/react-native-expo:ios_react_headers", + react_jsi_headers = "@oliphaunt//src/examples/native/react-native-expo:ios_react_jsi_header", + react_module_map = "@oliphaunt//src/examples/native/react-native-expo:ios_react_module_map", + app_dependency_provider = "@oliphaunt//src/examples/native/react-native-expo:ios_ReactAppDependencyProvider", + app_codegen = "@oliphaunt//src/examples/native/react-native-expo:ios_ReactCodegen", + constants_config = "@oliphaunt//src/examples/native/react-native-expo:ios_constants_config", +) +""") + return ctx.repo_metadata(reproducible = True) + +expo_android_sources_repository = repository_rule( + implementation = _impl, + attrs = { + "metadata": attr.label(mandatory = True, allow_single_file = [".json"]), + "kotlin_catalog": attr.label(default = Label("//src/native/sdks/kotlin:gradle/libs.versions.toml"), allow_single_file = True), + "sdk_gradle": attr.label(default = Label("//src/native/sdks/react-native:android/build.gradle"), allow_single_file = True), + "converter": attr.label(default = Label("//build_defs/android:native-metadata.mts"), allow_single_file = True), + "apple_converter": attr.label(default = Label("//build_defs/apple:native-metadata.mts"), allow_single_file = True), + "sdk_manifest": attr.label(default = Label("//src/native/sdks/react-native:package.json"), allow_single_file = True), + "bun": attr.label(default = Label("@bun_runtime//:bun"), allow_single_file = True), + }, +) diff --git a/build_defs/android/native-targets.bzl b/build_defs/android/native-targets.bzl new file mode 100644 index 000000000..adc4cbc2b --- /dev/null +++ b/build_defs/android/native-targets.bzl @@ -0,0 +1,48 @@ +"""Real new-architecture RN/Expo native link graph over locked prefab ABIs.""" + +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_import", "cc_library") +load(":app.bzl", "android_aar_native", "android_header_tree", "android_prefab_import", "android_source_headers") +load(":native-cpp.bzl", "REACT_NATIVE_RELEASE_DEFINES", "expo_core_cpp", "react_native_app_cpp", "safe_area_cpp") + +_APP = "@oliphaunt//src/examples/native/react-native-expo:" + +def _select(arm64, x64): + return select({"@platforms//cpu:aarch64": arm64, "@platforms//cpu:x86_64": x64}) + +def _raw(coordinate): + # The maintained Maven pin exposes each exact downloaded artifact File. + return "@expo_android_maven//:" + coordinate.replace(".", "_").replace("-", "_").replace(":", "_") + "_extension" + +def expo_android_native(metadata): + rn = _raw("com.facebook.react:react-android:aar:release:" + metadata["reactNative"]) + fbjni = _raw("com.facebook.fbjni:fbjni:aar:" + metadata["fbjni"]) + for platform, abi in [("arm64", "arm64-v8a"), ("x86_64", "x86_64")]: + for name, aar in [("jsi", rn), ("reactnative", rn), ("fbjni", fbjni)]: + android_prefab_import(name = name + "_" + platform, aar = aar, abi = abi, module = name) + android_aar_native(name = "cxx_runtime_" + platform, aar = rn, abi = abi, library = "libc++_shared.so") + cc_import(name = "cxx_runtime_" + platform + "_import", shared_library = ":cxx_runtime_" + platform) + android_header_tree(name = "reactnative_includes_" + platform, headers = ":reactnative_" + platform + "_headers", include_suffixes = ["react", "react/fabric"]) + cc_library(name = "react_native_prefab", deps = _select([":jsi_arm64", ":reactnative_arm64", ":reactnative_includes_arm64"], [":jsi_x86_64", ":reactnative_x86_64", ":reactnative_includes_x86_64"])) + cc_library(name = "fbjni", deps = _select([":fbjni_arm64"], [":fbjni_x86_64"])) + cc_library(name = "shared_cxx_runtime", deps = _select([":cxx_runtime_arm64_import"], [":cxx_runtime_x86_64_import"])) + cc_library(name = "react_native_jni_headers", hdrs = native.glob(["packages/react-native/ReactAndroid/src/main/jni/**/*.h"]), includes = ["packages/react-native/ReactAndroid/src/main/jni"]) + dependencies = [":react_native_prefab", ":react_native_jni_headers"] + shared = ["-static_link_cpp_runtimes"] + expo_core_cpp(name = "expo_core", root = "packages/expo-modules-core", react_native_deps = dependencies, + fbjni = ":fbjni", cxx_runtime = ":shared_cxx_runtime", shared_runtime_features = shared, + react_native_jni_root = "packages/react-native/ReactAndroid/src/main/jni", + react_native_minor = int(metadata["reactNative"].split(".")[1])) + cc_library(name = "oliphaunt_codegen", srcs = [_APP + "android_codegen_cpp"], + hdrs = [_APP + "android_codegen_headers"], deps = dependencies + [":fbjni", ":shared_cxx_runtime", _APP + "android_codegen_includes"], + features = shared, copts = ["-std=c++20", "-fexceptions", "-frtti"], local_defines = REACT_NATIVE_RELEASE_DEFINES) + android_source_headers(name = "safe_area_source_includes", + headers = native.glob(["packages/react-native-safe-area-context/android/src/main/jni/*.h", "packages/react-native-safe-area-context/common/cpp/**/*.h"]), + include_dirs = ["packages/react-native-safe-area-context/android/src/main/jni", "packages/react-native-safe-area-context/common/cpp"]) + safe_area_cpp(name = "safe_area", root = "packages/react-native-safe-area-context", + generated_sources = [_APP + "safe_area_codegen_cpp"], generated_headers = [_APP + "safe_area_codegen_headers"], generated_include_dirs = [], + react_native_deps = dependencies + [":safe_area_source_includes", _APP + "safe_area_codegen_includes"], fbjni = ":fbjni", cxx_runtime = ":shared_cxx_runtime", shared_runtime_features = shared) + react_native_app_cpp(name = "appmodules", react_native_root = "packages/react-native", + autolinking_sources = [_APP + "android_autolinking_cpp"], autolinking_headers = [_APP + "android_autolinking_headers"], autolinking_include_dirs = [], + generated_sources = [], generated_headers = [], generated_include_dirs = [], + react_native_deps = dependencies + [_APP + "android_autolinking_includes"], fbjni = ":fbjni", cxx_runtime = ":shared_cxx_runtime", shared_runtime_features = shared, + native_module_deps = [":oliphaunt_codegen", ":safe_area"]) diff --git a/build_defs/android/ndk.BUILD.bazel b/build_defs/android/ndk.BUILD.bazel new file mode 100644 index 000000000..51efbd26a --- /dev/null +++ b/build_defs/android/ndk.BUILD.bazel @@ -0,0 +1,74 @@ +load("@rules_cc//cc/toolchains:cc_toolchain.bzl", "cc_toolchain") +load("@oliphaunt//build_defs/android:toolchain.bzl", "android_cc_config") +load(":ndk.bzl", "NDK") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["source.properties", "ndk.bzl", NDK["prefix"] + "/bin/llvm-nm"]) + +_PREFIX = NDK["prefix"] +alias(name = "nm", actual = _PREFIX + "/bin/llvm-nm") +_TARGETS = { + "arm64": ("aarch64-linux-android", "aarch64", "arm64-v8a"), + "x86_64": ("x86_64-linux-android", "x86_64", "x86_64"), +} + +filegroup(name = "compiler_binaries", srcs = [_PREFIX + "/bin/clang", _PREFIX + "/bin/clang++", _PREFIX + "/bin/clang-" + NDK["resource"]]) +filegroup(name = "linker_binaries", srcs = [":compiler_binaries", _PREFIX + "/bin/ld.lld", _PREFIX + "/bin/lld"]) +filegroup(name = "ar_files", srcs = [_PREFIX + "/bin/llvm-ar"]) +filegroup(name = "dwp_files", srcs = [_PREFIX + "/bin/llvm-dwp"]) +filegroup(name = "coverage_files", srcs = [_PREFIX + "/bin/llvm-cov", _PREFIX + "/bin/llvm-profdata"]) +filegroup(name = "objcopy_files", srcs = [_PREFIX + "/bin/llvm-objcopy"]) +filegroup(name = "strip_files", srcs = [":objcopy_files", _PREFIX + "/bin/llvm-strip"]) +filegroup(name = "tools", srcs = [":linker_binaries", ":ar_files", ":dwp_files", ":coverage_files", ":strip_files", _PREFIX + "/bin/llvm-nm", _PREFIX + "/bin/llvm-objdump"]) +filegroup(name = "includes", srcs = glob([_PREFIX + "/sysroot/usr/include/**", _PREFIX + "/lib/clang/" + NDK["resource"] + "/include/**"])) + +[filegroup( + name = "runtime_" + name, + srcs = [_PREFIX + "/sysroot/usr/lib/" + triple + "/libc++_static.a", _PREFIX + "/sysroot/usr/lib/" + triple + "/libc++abi.a"], +) for name, (triple, _, _) in _TARGETS.items()] + +[filegroup( + name = "libraries_" + name, + srcs = glob([ + _PREFIX + "/sysroot/usr/lib/" + triple + "/*.a", + _PREFIX + "/sysroot/usr/lib/" + triple + "/" + str(NDK["api"]) + "/*", + _PREFIX + "/lib/clang/" + NDK["resource"] + "/lib/linux/*-" + cpu + "-android.a", + _PREFIX + "/lib/clang/" + NDK["resource"] + "/lib/linux/" + cpu + "/*", + ]), +) for name, (triple, cpu, _) in _TARGETS.items()] + +[filegroup(name = "compiler_files_" + name, srcs = [":compiler_binaries", ":includes"]) for name in _TARGETS] +[filegroup(name = "linker_files_" + name, srcs = [":linker_binaries", ":libraries_" + name]) for name in _TARGETS] +[filegroup(name = "files_" + name, srcs = [":tools", ":includes", ":libraries_" + name]) for name in _TARGETS] + +[android_cc_config( + name = "config_" + name, + prefix = _PREFIX, + resource = NDK["resource"], + revision = NDK["revision"], + api = NDK["api"], + page_alignment = NDK["page_alignment"], + triple = triple, + cpu = cpu, +) for name, (triple, _, cpu) in _TARGETS.items()] + +[cc_toolchain( + name = "cc_" + name, + toolchain_identifier = "oliphaunt-ndk-" + NDK["revision"] + "-" + triple, + toolchain_config = ":config_" + name, + all_files = ":files_" + name, + ar_files = ":ar_files", + as_files = ":compiler_binaries", + compiler_files = ":compiler_files_" + name, + dwp_files = ":dwp_files", + coverage_files = ":coverage_files", + linker_files = ":linker_files_" + name, + objcopy_files = ":objcopy_files", + strip_files = ":strip_files", + static_runtime_lib = ":runtime_" + name, + dynamic_runtime_lib = ":empty", + supports_param_files = 1, +) for name, (triple, _, _) in _TARGETS.items()] + +filegroup(name = "empty", srcs = []) diff --git a/build_defs/android/repositories.bzl b/build_defs/android/repositories.bzl new file mode 100644 index 000000000..6ec5e1674 --- /dev/null +++ b/build_defs/android/repositories.bzl @@ -0,0 +1,38 @@ +"""Checksummed NDK acquisition from the existing SDK and platform authorities.""" + +def _android_ndk_impl(ctx): + # All imported inputs are watched explicitly; the program is just a TOML/ + # conventional-policy projection, not a compiler or SDK-install handoff. + for source in [ctx.attr.manifest, ctx.attr.converter, ctx.attr.policy]: + ctx.read(source) + ctx.watch(ctx.path(ctx.attr.bun)) + result = ctx.execute([ctx.path(ctx.attr.bun), ctx.path(ctx.attr.converter), ctx.path(ctx.attr.manifest)], quiet = True) + if result.return_code: + fail("Cannot import Android native NDK metadata: " + result.stderr) + metadata = json.decode(result.stdout) + ctx.download_and_extract(url = metadata["url"], sha256 = metadata["sha256"], stripPrefix = metadata["strip_prefix"]) + revision = None + for line in ctx.read("source.properties").splitlines(): + key, separator, value = line.partition("=") + if separator and key.strip() == "Pkg.Revision": + revision = value.strip() + if revision != metadata["revision"]: + fail("Acquired Android NDK revision %s differs from packages.ndk %s" % (revision, metadata["revision"])) + prefix = "toolchains/llvm/prebuilt/linux-x86_64" + resources = [path.basename for path in ctx.path(prefix + "/lib/clang").readdir() if path.is_dir] + if len(resources) != 1: + fail("Android NDK must expose exactly one declared Clang resource directory") + ctx.file("ndk.bzl", "NDK = " + repr(metadata | {"prefix": prefix, "resource": resources[0]}) + "\n") + ctx.symlink(ctx.attr.build_file, "BUILD.bazel") + return ctx.repo_metadata(reproducible = True) + +android_ndk_repository = repository_rule( + implementation = _android_ndk_impl, + attrs = { + "manifest": attr.label(default = Label("//tools/dev:android-sdk.toml"), allow_single_file = True), + "converter": attr.label(default = Label("//build_defs/android:metadata.mts"), allow_single_file = True), + "policy": attr.label(default = Label("//tools/release:platform-compatibility-policy.mts"), allow_single_file = True), + "bun": attr.label(default = Label("@bun_runtime//:bun"), allow_single_file = True), + "build_file": attr.label(default = Label("//build_defs/android:ndk.BUILD.bazel"), allow_single_file = True), + }, +) diff --git a/build_defs/android/rules-android-min-sdk.patch b/build_defs/android/rules-android-min-sdk.patch new file mode 100644 index 000000000..afa0cafed --- /dev/null +++ b/build_defs/android/rules-android-min-sdk.patch @@ -0,0 +1,128 @@ +diff --git a/rules/min_sdk_version.bzl b/rules/min_sdk_version.bzl +index 1f5e91b1..00005472 100644 +--- a/rules/min_sdk_version.bzl ++++ b/rules/min_sdk_version.bzl +@@ -23,9 +23,8 @@ load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") + + visibility(PROJECT_VISIBILITY) + +-_SETTING = "//rules/flags:min_sdk_version" ++_SETTING = "//rules:min_sdk_version" + _DEPOT_FLOOR = 23 +-_MIN_SDK_LEVELS = sorted([_DEPOT_FLOOR, 24]) + + _ATTRS = dict( + _min_sdk_version = attr.label( +@@ -35,26 +34,16 @@ _ATTRS = dict( + ) + + def _clamp(min_sdk_version): +- # TODO(asinclair): Uncomment this once android_binary is Starlarkified and the order of the +- # Android Platforms Transition and Feature Flags transition is swapped. +- # clamped = _MIN_SDK_LEVELS[0] +- # for m in _MIN_SDK_LEVELS: +- # if m > min_sdk_version: +- # return clamped +- # clamped = m +- # return clamped +- return 0 ++ # All app dependencies share one setting; lowering it changes legal bytecode. ++ return min_sdk_version + + def _get(ctx): + # This is the case when an android_binary target does not set a value explicitly. + # The configuration value defaults to 0 + # So in this case we use the depot floor. +- # TODO(asinclair): Uncomment this once android_binary is Starlarkified and the order of the +- # Android Platforms Transition and Feature Flags transition is swapped. +- # if not ctx.attr._min_sdk_version[BuildSettingInfo].value: +- # return _DEPOT_FLOOR +- # return ctx.attr._min_sdk_version[BuildSettingInfo].value +- return _DEPOT_FLOOR ++ # An explicit app transition supplies the existing minimum-SDK setting. ++ # Preserve the upstream depot floor for unrelated/default configurations. ++ return ctx.attr._min_sdk_version[BuildSettingInfo].value or _DEPOT_FLOOR + + min_sdk_version = struct( + attrs = _ATTRS, +diff --git a/rules/android_binary/impl.bzl b/rules/android_binary/impl.bzl +index 8d0ef2f1..1419c599 100644 +--- a/rules/android_binary/impl.bzl ++++ b/rules/android_binary/impl.bzl +@@ -75,11 +75,14 @@ def _base_validations_processor(ctx, **_unused_ctxs): + ) + + def _process_manifest(ctx, **unused_ctxs): ++ configured_min_sdk_version = ctx.attr._min_sdk_version[BuildSettingInfo].value ++ if ctx.attr.min_sdk_version and configured_min_sdk_version > ctx.attr.min_sdk_version: ++ fail("Configured minimum SDK %d exceeds authored min_sdk_version %d" % (configured_min_sdk_version, ctx.attr.min_sdk_version)) + manifest_ctx = _resources.bump_min_sdk( + ctx, + manifest = ctx.file.manifest, + manifest_values = ctx.attr.manifest_values, +- min_sdk_version = ctx.attr.min_sdk_version, ++ min_sdk_version = ctx.attr.min_sdk_version or configured_min_sdk_version, + ) + + return ProviderInfo( +diff --git a/rules/dex.bzl b/rules/dex.bzl +index c570af38..418597da 100644 +--- a/rules/dex.bzl ++++ b/rules/dex.bzl +@@ -228,7 +228,7 @@ def _process_monolithic_dexing( + args.add("--dex") + args.add_all(dexopts) + if min_sdk_version > 0: +- args.add("--min_sdk_version", min_sdk_version) ++ args.add("--min-sdk-version", min_sdk_version) + args.add("--multi-dex") + if main_dex_list: + args.add(main_dex_list, format = "--main-dex-list=%s") +diff --git a/rules/android_binary/r8.bzl b/rules/android_binary/r8.bzl +index 973bc4d1..2c7393b2 100644 +--- a/rules/android_binary/r8.bzl ++++ b/rules/android_binary/r8.bzl +@@ -35,12 +35,13 @@ load("//rules:visibility.bzl", "PROJECT_VISIBILITY") + + visibility(PROJECT_VISIBILITY) + +-def process_r8(ctx, validation_ctx, jvm_ctx, packaged_resources_ctx, build_info_ctx, **_unused_ctxs): ++def process_r8(ctx, validation_ctx, manifest_ctx, jvm_ctx, packaged_resources_ctx, build_info_ctx, **_unused_ctxs): + """Runs R8 for desugaring, optimization, and dexing. + + Args: + ctx: Rule contxt. + validation_ctx: Context from the base valdations processor. ++ manifest_ctx: Context from the manifest processor. + jvm_ctx: Context from the java processor. + packaged_resources_ctx: Context from resource processing. + build_info_ctx: Context from build info processor. +@@ -80,7 +81,7 @@ def process_r8(ctx, validation_ctx, jvm_ctx, packaged_resources_ctx, build_info_ + + android_jar = get_android_sdk(ctx).android_jar + proguard_specs = proguard.get_proguard_specs(ctx, packaged_resources_ctx.resource_proguard_config) +- min_sdk_version = getattr(ctx.attr, "min_sdk_version", None) ++ min_sdk_version = manifest_ctx.processed_min_sdk_version + + neverlink_infos = utils.collect_providers(StarlarkAndroidNeverlinkInfo, ctx.attr.deps) + neverlink_jars = depset(transitive = [info.transitive_neverlink_libraries for info in neverlink_infos]) +diff --git a/rules/android_binary/attrs.bzl b/rules/android_binary/attrs.bzl +index 506578c8..b9618bdc 100644 +--- a/rules/android_binary/attrs.bzl ++++ b/rules/android_binary/attrs.bzl +@@ -22,6 +22,7 @@ load( + _attrs = "attrs", + ) + load("//rules:dex_desugar_aspect.bzl", "dex_desugar_aspect") ++load("//rules:min_sdk_version.bzl", "min_sdk_version") + load( + "//rules:native_deps.bzl", + "split_config_aspect", +@@ -248,6 +249,7 @@ ATTRS = _attrs.replace( + ), + ), + _attrs.compilation_attributes(apply_android_transition = True), ++ min_sdk_version.attrs, + _attrs.DATA_CONTEXT, + _attrs.ANDROID_TOOLCHAIN_ATTRS, + _attrs.AUTOMATIC_EXEC_GROUPS_ENABLED, diff --git a/build_defs/android/rules-jvm-external-android-gradle.patch b/build_defs/android/rules-jvm-external-android-gradle.patch new file mode 100644 index 000000000..25a12f906 --- /dev/null +++ b/build_defs/android/rules-jvm-external-android-gradle.patch @@ -0,0 +1,237 @@ +diff --git a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleBuildScriptGenerator.java b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleBuildScriptGenerator.java +--- a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleBuildScriptGenerator.java ++++ b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleBuildScriptGenerator.java +@@ -102,6 +102,10 @@ + Map contextMap = new HashMap<>(); + + contextMap.put("isUsingM2Local", isUsingM2Local); ++ // An explicitly requested AAR declares an Android consumer. Preserve JVM ++ // defaults for acquisition requests containing only JVM artifacts. ++ contextMap.put("isAndroidConsumer", ++ dependencies.stream().anyMatch(dep -> "aar".equals(dep.getExtension()))); + contextMap.put( + "repositories", + repositories.stream() +diff --git a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/data/build.gradle.hbs b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/data/build.gradle.hbs +--- a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/data/build.gradle.hbs ++++ b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/data/build.gradle.hbs +@@ -1,5 +1,50 @@ + apply plugin: 'java' + ++{{~#if isAndroidConsumer}} ++// Exact matching policy from KotlinPlatformType in the pinned Kotlin 2.2.21 API: ++// https://github.com/JetBrains/kotlin/blob/v2.2.21/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlatformType.kt ++class KotlinPlatformCompatibility implements org.gradle.api.attributes.AttributeCompatibilityRule { ++ void execute(org.gradle.api.attributes.CompatibilityCheckDetails details) { ++ if (details.producerValue == 'jvm' && details.consumerValue == 'androidJvm') details.compatible() ++ if (details.consumerValue == 'common') details.compatible() ++ } ++} ++class KotlinPlatformDisambiguation implements org.gradle.api.attributes.AttributeDisambiguationRule { ++ void execute(org.gradle.api.attributes.MultipleCandidatesDetails details) { ++ if (details.candidateValues.contains(details.consumerValue)) { ++ details.closestMatch(details.consumerValue) ++ } else if (details.consumerValue == null && details.candidateValues.containsAll(['androidJvm', 'jvm'])) { ++ details.closestMatch('jvm') ++ } else if (details.candidateValues.contains('common') && !details.candidateValues.contains('jvm') && ++ !details.candidateValues.contains('androidJvm')) { ++ details.closestMatch('common') ++ } ++ } ++} ++def kotlinPlatform = org.gradle.api.attributes.Attribute.of('org.jetbrains.kotlin.platform.type', String) ++dependencies.attributesSchema.attribute(kotlinPlatform) { ++ compatibilityRules.add(KotlinPlatformCompatibility) ++ disambiguationRules.add(KotlinPlatformDisambiguation) ++} ++configurations.create('bazelAndroidRuntimeClasspath') { ++ canBeResolved = true ++ canBeConsumed = false ++ extendsFrom(configurations.implementation) ++ attributes { ++ attribute(kotlinPlatform, 'androidJvm') ++ attribute(org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE, ++ objects.named(org.gradle.api.attributes.Usage, ++ org.gradle.api.attributes.Usage.JAVA_RUNTIME)) ++ attribute(org.gradle.api.attributes.Category.CATEGORY_ATTRIBUTE, ++ objects.named(org.gradle.api.attributes.Category, ++ org.gradle.api.attributes.Category.LIBRARY)) ++ attribute(org.gradle.api.attributes.java.TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE, ++ objects.named(org.gradle.api.attributes.java.TargetJvmEnvironment, ++ org.gradle.api.attributes.java.TargetJvmEnvironment.ANDROID)) ++ } ++} ++{{~/if}} ++ + repositories { + {{~#if isUsingM2Local}} + mavenLocal() +diff --git a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/plugin/GradleDependencyModelBuilder.java b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/plugin/GradleDependencyModelBuilder.java +--- a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/plugin/GradleDependencyModelBuilder.java ++++ b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/plugin/GradleDependencyModelBuilder.java +@@ -82,7 +82,10 @@ + GradleDependencyModel gradleDependencyModel = new GradleDependencyModelImpl(); + // We only resolve dependencies and fetch artifacts for this configuration + // similar to how we do in the Maven resolver +- Configuration cfg = project.getConfigurations().getByName("runtimeClasspath"); ++ Configuration cfg = project.getConfigurations().findByName("bazelAndroidRuntimeClasspath"); ++ if (cfg == null) { ++ cfg = project.getConfigurations().getByName("runtimeClasspath"); ++ } + + List declaredDeps = collectDeclaredDependencies(cfg); + // This stores the mapping between coordinates to the GradleResolvedDependency interface +@@ -120,6 +123,10 @@ + + Configuration detachedCfg = + project.getConfigurations().detachedConfiguration(detachedDeps.toArray(new Dependency[0])); ++ // The retry must consume the same platform variants as the requested graph. ++ for (Attribute attribute : cfg.getAttributes().keySet()) { ++ detachedCfg.getAttributes().attribute(attribute, cfg.getAttributes().getAttribute(attribute)); ++ } + // Ensure the detached configuration respects the same exclude rules as the original + // configuration + if (!cfg.getExcludeRules().isEmpty()) { +diff --git a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleResolver.java b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleResolver.java +--- a/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleResolver.java ++++ b/private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleResolver.java +@@ -206,7 +206,8 @@ + artifactsByNode.computeIfAbsent(coordinates, k -> new ArrayList<>()).add(artifact); + + File artifactFile = artifact.getFile(); +- if (artifactFile != null && artifactFile.exists()) { ++ if (artifactFile != null && artifactFile.exists() ++ && !artifactFile.getName().endsWith(".pom")) { + paths.put(coordinates, artifactFile.toPath()); + } + +@@ -306,11 +307,12 @@ + break; + } + } +- // Fallback: any existing file (including pom) ++ // POM files describe the graph; their bytes are never a binary artifact. ++ // Metadata-only nodes are acquired by Downloader from their real coordinate. + if (bestFile == null) { + for (GradleResolvedArtifact artifact : entry.getValue()) { + File file = artifact.getFile(); +- if (file != null && file.exists()) { ++ if (file != null && file.exists() && !file.getName().endsWith(".pom")) { + bestFile = file; + break; + } +@@ -318,6 +320,8 @@ + } + if (bestFile != null) { + paths.put(coords, bestFile.toPath()); ++ } else { ++ paths.remove(coords); + } + } + +diff --git a/tests/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleResolverTest.java b/tests/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleResolverTest.java +--- a/tests/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleResolverTest.java ++++ b/tests/com/github/bazelbuild/rules_jvm_external/resolver/gradle/GradleResolverTest.java +@@ -75,10 +75,11 @@ + String jvmMetadata = Files.readString(jvmMetadataPath); + moduleMetadataHelper.addToMavenRepo(jvmCoordinates, jvmMetadata); + +- Graph resolved = +- resolver +- .resolve(prepareRequestFor(mavenRepo.getPath().toUri(), baseCoordinates)) +- .getResolution(); ++ ResolutionResult result = ++ resolver.resolve(prepareRequestFor(mavenRepo.getPath().toUri(), baseCoordinates)); ++ Graph resolved = result.getResolution(); ++ assertFalse(result.getPaths().values().stream() ++ .anyMatch(path -> path.getFileName().toString().endsWith(".pom"))); + + assertEquals(2, resolved.nodes().size()); + // sample-jvm resolves indirectly through sample using the gradle module metadata redirect +@@ -137,6 +138,44 @@ + } + + @Test ++ public void explicitAarConsumerResolvesAndroidGraphAndBinaryPaths() ++ throws IOException, XMLStreamException { ++ Coordinates base = new Coordinates("com.example:sample:1.0"); ++ Coordinates jvm = new Coordinates("com.example:sample-jvm:1.0"); ++ Coordinates android = new Coordinates("com.example:sample-android:aar:1.0"); ++ Coordinates release = new Coordinates("com.example:android-marker:aar:release:1.0"); ++ Coordinates javaUtil = new Coordinates("com.example:java-util:1.0"); ++ MavenRepo repo = MavenRepo.create().add(release).add(javaUtil); ++ GradleModuleMetadataHelper helper = new GradleModuleMetadataHelper(repo); ++ Runfiles runfiles = Runfiles.preload() ++ .withSourceRepository(AutoBazelRepository_GradleResolverTest.NAME); ++ String fixtureRoot = "rules_jvm_external/tests/com/github/bazelbuild/" ++ + "rules_jvm_external/resolver/gradle/fixtures/jvmAndAndroidVariants/"; ++ // This older GMM has no JVM environment attributes. Select Android through ++ // the official Kotlin platform scheme, while accepting a genuine JVM fallback. ++ String baseMetadata = Files.readString(Paths.get(runfiles.rlocation( ++ fixtureRoot + "sample-1.0.module"))); ++ helper.addToMavenRepo(base, baseMetadata); ++ helper.addToMavenRepo(jvm, Files.readString(Paths.get(runfiles.rlocation( ++ fixtureRoot + "sample-jvm-1.0.module")))); ++ helper.addToMavenRepo(javaUtil, Files.readString(Paths.get(runfiles.rlocation( ++ fixtureRoot + "sample-jvm-1.0.module"))).replace("sample-jvm", "java-util")); ++ helper.addToMavenRepo(android, Files.readString(Paths.get(runfiles.rlocation( ++ fixtureRoot + "sample-android-1.0.module")))); ++ ResolutionResult result = resolver.resolve(prepareRequestFor(repo.getPath().toUri(), base, release, javaUtil)); ++ Graph graph = result.getResolution(); ++ assertTrue(graph.nodes().contains(android)); ++ assertTrue(graph.nodes().contains(release)); ++ assertTrue(graph.nodes().contains(javaUtil)); ++ assertFalse(graph.nodes().contains(jvm)); ++ assertTrue(graph.successors(base).contains(android)); ++ assertFalse(result.getPaths().values().stream() ++ .anyMatch(path -> path.getFileName().toString().endsWith(".pom"))); ++ assertTrue(result.getPaths().get(android).getFileName().toString().endsWith(".aar")); ++ assertTrue(result.getPaths().get(javaUtil).getFileName().toString().endsWith(".jar")); ++ } ++ ++ @Test + public void throwsAnExceptionIfASingleDependencyWasNotResolved() throws IOException { + Coordinates validCoordinates = new Coordinates("com.example:sample:1.0"); + Coordinates invalidCoordinates = new Coordinates("com.example:does-not-exist:1.0"); +diff --git a/tests/com/github/bazelbuild/rules_jvm_external/resolver/BUILD b/tests/com/github/bazelbuild/rules_jvm_external/resolver/BUILD +--- a/tests/com/github/bazelbuild/rules_jvm_external/resolver/BUILD ++++ b/tests/com/github/bazelbuild/rules_jvm_external/resolver/BUILD +@@ -24,10 +24,7 @@ + "com.google.guava:guava", + repository_name = "rules_jvm_external_deps", + ), +- artifact( +- "junit:junit", +- repository_name = "regression_testing_coursier", +- ), ++ "@@//build_defs/android:resolver_junit", + artifact( + "org.apache.maven:maven-model", + repository_name = "rules_jvm_external_deps", +diff --git a/tests/com/github/bazelbuild/rules_jvm_external/resolver/gradle/BUILD b/tests/com/github/bazelbuild/rules_jvm_external/resolver/gradle/BUILD +--- a/tests/com/github/bazelbuild/rules_jvm_external/resolver/gradle/BUILD ++++ b/tests/com/github/bazelbuild/rules_jvm_external/resolver/gradle/BUILD +@@ -8,10 +8,7 @@ + deps = [ + "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle", + "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/models", +- artifact( +- "junit:junit", +- repository_name = "regression_testing_coursier", +- ), ++ "@@//build_defs/android:resolver_junit", + ], + ) + +@@ -39,10 +36,7 @@ + "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/gradle/models", + "//private/tools/java/com/github/bazelbuild/rules_jvm_external/resolver/netrc", + "//tests/com/github/bazelbuild/rules_jvm_external/resolver", +- artifact( +- "junit:junit", +- repository_name = "regression_testing_coursier", +- ), ++ "@@//build_defs/android:resolver_junit", + artifact( + "com.google.guava:guava", + repository_name = "rules_jvm_external_deps", diff --git a/build_defs/android/toolchain.bzl b/build_defs/android/toolchain.bzl new file mode 100644 index 000000000..7f2297184 --- /dev/null +++ b/build_defs/android/toolchain.bzl @@ -0,0 +1,99 @@ +"""Maintained Android Clang configuration, declared SDK files and runtime ABI.""" + +load("@rules_android_ndk//:ndk_cc_toolchain_config.bzl", "ndk_cc_toolchain_config") +load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES") +load("@rules_cc//cc:cc_toolchain_config_lib.bzl", "feature", "flag_group", "flag_set") +load("@rules_cc//cc/common:cc_common.bzl", "cc_common") +load("@rules_cc//cc/toolchains:cc_toolchain_config_info.bzl", "CcToolchainConfigInfo") +load("//build_defs/release:supplier.bzl", "ShippingSupplierInfo") + +def _android_cc_config_impl(ctx): + # This is a qualification bound, not a second version authority. An SDK or + # minimum-API update must review the independently proven Bionic PG profile. + if ctx.attr.revision != "27.0.12077973" or ctx.attr.api != 24 or ctx.attr.page_alignment != 16384: + fail("Native Android runtime configuration is qualified only for NDK 27.0.12077973 / API 24 / 16 KiB ELF pages; review the Bionic PostgreSQL profile and ABI checks before updating the canonical SDK/platform policy") + prefix = ctx.attr.prefix + config = ndk_cc_toolchain_config( + api_level = ctx.attr.api, + target_system_name = ctx.attr.triple, + tools = {name: prefix + "/bin/" + binary for name, binary in { + "clang": "clang", + "gcc": "clang", + "cpp": "clang++", + "ar": "llvm-ar", + "dwp": "llvm-dwp", + "gcov": "llvm-cov", + "ld": "ld.lld", + "nm": "llvm-nm", + "objcopy": "llvm-objcopy", + "objdump": "llvm-objdump", + "strip": "llvm-strip", + }.items()}, + cxx_builtin_include_directories = [ + prefix + "/sysroot/usr/include/c++/v1", + prefix + "/sysroot/usr/include/" + ctx.attr.triple, + prefix + "/sysroot/usr/include", + prefix + "/lib/clang/" + ctx.attr.resource + "/include", + ], + builtin_sysroot = prefix + "/sysroot", + toolchain_identifier = "oliphaunt-ndk-" + ctx.attr.revision + "-" + ctx.attr.triple, + host_system_name = "x86_64-unknown-linux-gnu", + target_cpu = ctx.attr.cpu, + target_libc = "bionic", + compiler = "clang", + abi_version = ctx.attr.triple, + abi_libc_version = str(ctx.attr.api), + cc_target_os = "android", + ) + # rules_android_ndk enables static C++ runtimes. Its legacy arm64 linker + # flags still select 4 KiB; this final feature sets our 16 KiB runtime ABI. + config["features"] += [feature( + name = "android_runtime_page_alignment", + enabled = True, + flag_sets = [flag_set( + actions = [ACTION_NAMES.cpp_link_executable, ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library], + flag_groups = [flag_group(flags = ["-Wl,-z,max-page-size=" + str(ctx.attr.page_alignment), "-Wl,-z,common-page-size=" + str(ctx.attr.page_alignment)])], + )], + )] + return [cc_common.create_cc_toolchain_config_info(ctx = ctx, **config)] + +android_cc_config = rule( + implementation = _android_cc_config_impl, + attrs = { + "prefix": attr.string(mandatory = True), + "resource": attr.string(mandatory = True), + "revision": attr.string(mandatory = True), + "api": attr.int(mandatory = True), + "page_alignment": attr.int(mandatory = True), + "triple": attr.string(mandatory = True, values = ["aarch64-linux-android", "x86_64-linux-android"]), + "cpu": attr.string(mandatory = True), + }, + provides = [CcToolchainConfigInfo], +) + +def _platform_impl(settings, attr): + return {"//command_line_option:platforms": [str(attr.platform)]} + +_android_platform = transition(implementation = _platform_impl, inputs = [], outputs = ["//command_line_option:platforms"]) + +def _android_artifact_impl(ctx): + artifact = ctx.attr.artifact[0] + files = artifact[DefaultInfo].files + if ctx.attr.output: + physical = files.to_list() + if len(physical) != 1: + fail("A named Android configuration artifact must have exactly one output") + output = ctx.actions.declare_file(ctx.attr.output) + ctx.actions.symlink(output = output, target_file = physical[0]) + files = depset([output]) + return [DefaultInfo(files = files)] + ([artifact[ShippingSupplierInfo]] if ShippingSupplierInfo in artifact else []) + +android_artifact = rule( + implementation = _android_artifact_impl, + attrs = { + "artifact": attr.label(mandatory = True, cfg = _android_platform), + "platform": attr.label(mandatory = True), + "output": attr.string(default = ""), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), + }, +) diff --git a/build_defs/apple/BUILD.bazel b/build_defs/apple/BUILD.bazel new file mode 100644 index 000000000..7d0f162ab --- /dev/null +++ b/build_defs/apple/BUILD.bazel @@ -0,0 +1,127 @@ +load("@bazel_skylib//rules:build_test.bzl", "build_test") +load("@bazel_skylib//rules:select_file.bzl", "select_file") +load("@bazel_lib//lib:copy_file.bzl", "copy_file") +load("@rules_cc//cc:cc_library.bzl", "cc_library") +load("@rules_apple//apple:ios.bzl", "ios_build_test") +load("@rules_apple//apple:apple.bzl", "apple_dynamic_framework_import") +load("@rules_swift//swift:swift_library.bzl", "swift_library") +load("@rules_swift//swift:swift_interop_hint.bzl", "swift_interop_hint") +load(":native.bzl", "apple_swift_cxx_copts", "expo_apple_swift_library", "react_apple_swift_copts") +load("//build_defs/foundation:bun.bzl", "bun_test") +load(":requirement-selection-test.bzl", "requirement_selection_test") +load(":slices-test.bzl", "apple_slices_test") +load("//build_defs/quality:sources.bzl", "source_quality_files") + +package(default_visibility = ["//visibility:public"]) + +exports_files(glob(["*.bzl", "*.mts", "*.json", "*.plist", "*.patch"])) + +bun_test( + name = "app_action_test", + entry_point = "app.test.mts", + data = ["app.mts", "testdata/expo56-original-apple-resolve.json", "//build_defs/android:app.mts", "//:tools/packaging/archive-directory.mts", "//:tools/packaging/portable-archive.mts"], + size = "small", +) + +bun_test( + name = "captured_swift_source_test", + entry_point = "captured-swift-source.test.mts", + data = ["captured-swift-source.mts", "captured-file.mts", "captured-archive.mts", "resources.mts", "testdata/swift-0.8.2-original-Package.swift", "//src/native/sdks/swift:tools/prepare-swift-release-consumer.mts", "//:tools/packaging/portable-archive.mts", "//:tools/packaging/archive-directory.mts", "//src/native/sdks/swift:tools/swift-native-carrier-contract.mts", "//build_defs/release:testdata/swift-0.8.2-carrier.json", "//build_defs/languages/swift:source-package.fixture.mts", "//build_defs/native/apple:static-carrier-consumer.mts", "//build_defs/native/apple:framework_helpers", "//src/native/sdks/swift:generator_sources", "//src/native/sdks/react-native:tools/stage-ios-app.mts", "//src/native/sdks/react-native:tools/native-resource-closure.mts", "//src/native/sdks/react-native:src/generated/extensions.json", "//src/database-resources:contracts/native-manifest.mts", "//src/database-resources:contracts/contract.json"], + size = "small", +) + +bun_test( + name = "installed_app_boundary_test", + entry_point = "installed-app.test.mts", + data = ["installed-app.mts", "//:tools/packaging/portable-archive.mts", "//:tools/packaging/archive-directory.mts"], + size = "small", + target_compatible_with = ["@platforms//os:linux"], +) + + +# The original maintained rule tools execute licensed host paths selected by +# the same Xcode policy. Their runfiles carry those watched bytes and receipt. +filegroup( + name = "licensed_app_tools", + srcs = ["@native_apple_sdk//:app_tools"], + target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:aarch64"], +) + +source_quality_files() + +requirement_selection_test(name = "requirement_selection_test") +apple_slices_test(name = "slices_test") +bun_test(name = "final_libraries_test", entry_point = "final-libraries.test.mts", data = ["final-libraries.mts", "//build_defs/native/apple:static-carrier-consumer.mts", "//build_defs/native/apple:framework_helpers", "//src/native/sdks/swift:generator_sources", "//:tools/packaging/testdata/zip-fixture.mts"], size = "small") + +# Rebuild a Swift 6 textual interface under the real Swift 5 React import profile. +_SWIFT_CONTEXT = "testdata/swift-context/" +_SWIFT_CONTEXT_MAC = ["@platforms//os:macos", "@platforms//cpu:aarch64", "//build_defs/host:apple_package"] +swift_interop_hint(name = "swift_context_cbridge_hint", module_name = "CBridge", module_map = _SWIFT_CONTEXT + "module.modulemap") +cc_library( + name = "swift_context_cbridge", hdrs = [_SWIFT_CONTEXT + "Bridge.h", _SWIFT_CONTEXT + "CallInvoker.h"], + aspect_hints = [":swift_context_cbridge_hint"], testonly = True, target_compatible_with = _SWIFT_CONTEXT_MAC, +) +swift_library( + name = "swift_context_emitter", module_name = "Bridge", srcs = [_SWIFT_CONTEXT + "Bridge.swift"], + deps = [":swift_context_cbridge"], library_evolution = True, + copts = ["-swift-version", "6", "-cxx-interoperability-mode=off"], + features = ["swift.add_target_name_to_output"], testonly = True, target_compatible_with = _SWIFT_CONTEXT_MAC, +) +select_file(name = "swift_context_interface", srcs = ":swift_context_emitter", subpath = "swift_context_emitter/Bridge.swiftinterface", testonly = True) +# Copy only the interface: even without a sandbox, its search directory has no binary fallback. +copy_file(name = "swift_context_interface_only", src = ":swift_context_interface", out = "swift_context_interfaces/Bridge.swiftinterface", testonly = True) +swift_library( + name = "swift_context_consumer", module_name = "SwiftContextConsumer", srcs = [_SWIFT_CONTEXT + "Consumer.swift"], + deps = [":swift_context_cbridge"], swiftc_inputs = [":swift_context_interface_only", _SWIFT_CONTEXT + "react.yaml"], + copts = ["-swift-version", "5", "-I$(BINDIR)/build_defs/apple/swift_context_interfaces"] + + react_apple_swift_copts(_SWIFT_CONTEXT + "react.yaml") + + ["-Xcc", "-Ioliphaunt-swift-context/Headers", "-Xcc", "-DOLIPHAUNT_SWIFT_CONTEXT_REQUIRED=17"], + testonly = True, target_compatible_with = _SWIFT_CONTEXT_MAC, +) +build_test(name = "swift_interface_context_test", targets = [":swift_context_consumer"], target_compatible_with = _SWIFT_CONTEXT_MAC, size = "small") + +# CocoaPods supplies UIKit to Swift and Clang; private headers may import generated Swift declarations. +_EXPO_UMBRELLA = "testdata/expo-umbrella/" +_EXPO_UMBRELLA_IOS = ["@platforms//os:ios", "@platforms//cpu:aarch64"] +apple_dynamic_framework_import( + name = "expo_umbrella_alias_framework", + framework_imports = glob([_EXPO_UMBRELLA + "AliasFixture.framework/**"]), + testonly = True, target_compatible_with = _EXPO_UMBRELLA_IOS, +) +expo_apple_swift_library( + name = "expo_umbrella_headerless", module_name = "ExpoUmbrellaHeaderless", + swift_srcs = [_EXPO_UMBRELLA + "Headerless.swift"], clang_srcs = [], + swift_copts = ["-swift-version", "5"] + apple_swift_cxx_copts(), + testonly = True, target_compatible_with = _EXPO_UMBRELLA_IOS, +) +# A prebuilt Swift dependency supplies an Objective-C header without a C++ API. +swift_library( + name = "expo_umbrella_base", module_name = "ExpoUmbrellaBase", + srcs = [_EXPO_UMBRELLA + "Base.swift"], generates_header = True, + generated_header_name = "ExpoUmbrellaBase-Swift.h", + copts = ["-swift-version", "5", "-cxx-interoperability-mode=off"], + testonly = True, target_compatible_with = _EXPO_UMBRELLA_IOS, +) +expo_apple_swift_library( + name = "expo_umbrella_mixed", module_name = "ExpoUmbrellaMixed", + swift_srcs = [_EXPO_UMBRELLA + "Mixed.swift"], clang_srcs = [_EXPO_UMBRELLA + "Mixed.m"], + hdrs = [_EXPO_UMBRELLA + "Mixed.h", _EXPO_UMBRELLA + "include/ExpoUmbrellaMixed/Nested.h"], + includes = [_EXPO_UMBRELLA + "include"], + deps = [":expo_umbrella_alias_framework", ":expo_umbrella_base"], + clang_module_maps = [_EXPO_UMBRELLA + "AliasFixture.framework/Modules/module.modulemap"], + swiftc_inputs = [_EXPO_UMBRELLA + "MixedPrivate.h"], + additional_objc_compiler_inputs = [_EXPO_UMBRELLA + "MixedPrivate.h"], + swift_copts = ["-swift-version", "5"] + apple_swift_cxx_copts(), + testonly = True, target_compatible_with = _EXPO_UMBRELLA_IOS, +) +swift_library( + name = "expo_umbrella_consumer", module_name = "ExpoUmbrellaConsumer", + srcs = [_EXPO_UMBRELLA + "Consumer.swift"], deps = [":expo_umbrella_mixed"], + copts = ["-swift-version", "5"] + apple_swift_cxx_copts(), + testonly = True, target_compatible_with = _EXPO_UMBRELLA_IOS, +) +ios_build_test( + name = "expo_umbrella_test", minimum_os_version = "17.0", + targets = [":expo_umbrella_headerless", ":expo_umbrella_mixed", ":expo_umbrella_consumer"], + target_compatible_with = _EXPO_UMBRELLA_IOS, size = "small", +) diff --git a/build_defs/apple/app.bzl b/build_defs/apple/app.bzl new file mode 100644 index 000000000..0f1b63c4d --- /dev/null +++ b/build_defs/apple/app.bzl @@ -0,0 +1,90 @@ +"""Original Expo/RN generation; stock Apple and Swift rules own compilation.""" +load("//build_defs/android:app.bzl", "APP_NODE_INPUT_ATTRS", "app_node_inputs") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") +load(":generated-files.bzl", "IOS_GENERATED_FILES") + +_NODE = "@rules_nodejs//nodejs:toolchain_type" +_TAR = "@tar.bzl//tar/toolchain:type" +IosProjectInfo = provider(fields = {"files": "Original individual generator output Files"}) + +def ios_project_file_name(relative): + return "ios_" + relative.replace("/", "_").replace(".", "_").replace(" ", "_").replace("-", "_") + +def _action(ctx, operation, specification, inputs, outputs, mnemonic): + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode(specification) + "\n") + bun_file_action( + ctx, entry_point = ctx.file._apple_runner, arguments = [operation, spec.path], + inputs = inputs + [spec, ctx.file._apple_runner] + ctx.files._apple_helpers, + source_files = [ctx.file._apple_runner] + ctx.files._apple_helpers, + outputs = outputs, execution_requirements = {"block-network": "1"}, mnemonic = mnemonic, + ) + +_APPLE_INPUTS = dict(APP_NODE_INPUT_ATTRS, **{ + "_apple_runner": attr.label(default = Label("//build_defs/apple:app.mts"), allow_single_file = True), + "_apple_helpers": attr.label_list(default = [ + Label("//build_defs/android:app.mts"), + Label("//:tools/packaging/archive-directory.mts"), + Label("//:tools/packaging/portable-archive.mts"), + ], allow_files = True), +}) + +def _project_impl(ctx): + spec, inputs = app_node_inputs(ctx) + outputs = {name: ctx.actions.declare_file(ctx.label.name + "/" + name) for name in IOS_GENERATED_FILES} + resolved = ctx.actions.declare_file(ctx.label.name + "/autolinking.json") + constants = ctx.actions.declare_file(ctx.label.name + "/constants/app.config") + _action(ctx, "project", spec | { + "targetName": ctx.attr.target_name, "expectedModules": ctx.attr.expected_modules, + "outputs": {name: file.path for name, file in outputs.items()}, "autolinking": resolved.path, + "constantsConfig": constants.path, + "swiftSdkVersion": ctx.attr.swift_sdk_version, + }, inputs, outputs.values() + [resolved, constants], "ExpoAppleOriginalSources") + return [ + DefaultInfo(files = depset(outputs.values() + [resolved, constants])), + IosProjectInfo(files = outputs), + OutputGroupInfo(autolinking = depset([resolved]), constants = depset([constants])), + ] + +expo_ios_project = rule( + implementation = _project_impl, toolchains = BUN_SOURCE_TOOLCHAINS + [_NODE, _TAR], + attrs = dict(_APPLE_INPUTS, **{ + "target_name": attr.string(mandatory = True), + "expected_modules": attr.string_dict(mandatory = True), + "swift_sdk_version": attr.string(mandatory = True), + }), +) + +def _file_impl(ctx): + project = ctx.attr.project[IosProjectInfo] + if ctx.attr.path not in project.files: + fail("Original Expo/RN generation has no declared File " + ctx.attr.path) + return [DefaultInfo(files = depset([project.files[ctx.attr.path]]))] + +ios_project_file = rule(implementation = _file_impl, attrs = { + "project": attr.label(mandatory = True, providers = [IosProjectInfo]), + "path": attr.string(mandatory = True), +}) + +def _bundle_impl(ctx): + spec, inputs = app_node_inputs(ctx) + bundle = ctx.actions.declare_file(ctx.label.name + "/main.jsbundle") + source_map = ctx.actions.declare_file(ctx.label.name + "/main.jsbundle.map") + resources = ctx.actions.declare_directory(ctx.label.name + "/assets") + _action(ctx, "bundle", spec | { + "entry": ctx.attr.entry, "environment": ctx.attr.environment, + "selectedExtensions": ctx.attr.selected_extensions, "catalogProfile": ctx.attr.catalog_profile, + "profileProbe": ctx.file.catalog_profile_probe.path, + "bundle": bundle.path, "sourceMap": source_map.path, "resources": resources.path, + }, inputs + [ctx.file.catalog_profile_probe], [bundle, source_map, resources], "ExpoAppleHermesBundle") + return [ + DefaultInfo(files = depset([bundle])), + OutputGroupInfo(bundle = depset([bundle]), source_map = depset([source_map]), resources = depset([resources])), + ] + +expo_ios_bundle = rule( + implementation = _bundle_impl, toolchains = BUN_SOURCE_TOOLCHAINS + [_NODE, _TAR], + attrs = dict(_APPLE_INPUTS, **{"entry": attr.string(default = "index.ts"), "environment": attr.string_dict(), + "selected_extensions": attr.string_list(mandatory = True), "catalog_profile": attr.string(default = "standard", values = ["standard", "icu"]), + "catalog_profile_probe": attr.label(default = Label("//src/database-resources:contracts/profile-probe.json"), allow_single_file = [".json"])}), +) diff --git a/build_defs/apple/app.mts b/build_defs/apple/app.mts new file mode 100644 index 000000000..2b03d64f1 --- /dev/null +++ b/build_defs/apple/app.mts @@ -0,0 +1,342 @@ +import assert from 'node:assert/strict'; +import { execFileSync } from 'node:child_process'; +import { + chmodSync, + copyFileSync, + cpSync, + existsSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + realpathSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { mobileBundleEnvironment, type NodeInputs, stageNodeInputs } from '../android/app.mts'; + +type IosSpec = NodeInputs & { + targetName: string; + expectedModules: Record; + outputs: Record; + autolinking: string; + constantsConfig: string; + swiftSdkVersion: string; +}; +function put(file: string, contents: Buffer | string) { + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, contents); +} +function invoke( + inputs: NodeInputs, + script: string, + args: string[], + root: string, + environment: Record = {}, +) { + return execFileSync(realpathSync(inputs.node), [script, ...args], { + cwd: root, + encoding: 'utf8', + maxBuffer: 32 * 1024 * 1024, + env: { + PATH: path.dirname(realpathSync(inputs.node)), + CI: '1', + NODE_ENV: 'production', + EXPO_OFFLINE: '1', + EXPO_NO_TELEMETRY: '1', + EXPO_NO_GIT_STATUS: '1', + ...environment, + }, + }); +} +function scratch(callback: (root: string) => T): T { + const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-ios-app-')); + try { + return callback(root); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} +function files(root: string): string[] { + const result: string[] = []; + function walk(directory: string) { + for (const entry of readdirSync(directory, { withFileTypes: true })) { + const file = path.join(directory, entry.name); + if (entry.isDirectory()) walk(file); + else if (entry.isFile()) result.push(path.relative(root, file).split(path.sep).join('/')); + } + } + walk(root); + return result.sort(); +} +export function assertIosAutolinking(resolved: any, expectedModules: Record) { + assert.deepEqual( + resolved.extraDependencies, + [], + 'Declare new Expo Apple dependencies in the app construction graph', + ); + assert.deepEqual( + resolved.coreFeatures, + [], + 'Declare new Expo Apple features in the app construction graph', + ); + assert.equal( + new Set(resolved.modules.map((row: any) => row.packageName)).size, + resolved.modules.length, + 'Actual Expo Apple modules must occur exactly once', + ); + assert.deepEqual( + Object.fromEntries(resolved.modules.map((row: any) => [row.packageName, row.packageVersion])), + expectedModules, + 'Actual Expo Apple autolinking differs from the declared native source closure', + ); + for (const row of resolved.modules) { + assert(row.pods.length && row.swiftModuleNames.length); + assert.equal( + row.debugOnly, + ['expo-dev-launcher', 'expo-dev-menu'].includes(row.packageName), + 'The release graph must explicitly model changed Expo debug module conditions', + ); + } +} +export function projectExpoIos(spec: IosSpec) { + return scratch((root) => { + const stores = stageNodeInputs(root, spec); + const expo = stores[spec.roots.expo]; + const rn = stores[spec.roots['react-native']]; + const sdk = stores[spec.roots['@oliphaunt/react-native']]; + assert(expo && rn, 'The Apple app needs its declared Expo and React Native sources'); + assert(sdk, 'Compile the genuine delivered React Native SDK sources'); + const sdkManifest = JSON.parse(readFileSync(path.join(sdk, 'package.json'), 'utf8')); + assert.equal( + sdkManifest.oliphaunt.swiftSdkVersion, + spec.swiftSdkVersion, + 'Retain the actual SDK conventional Swift requirement', + ); + console.log( + invoke( + spec, + path.join(expo, 'bin/cli'), + [ + 'prebuild', + '--platform', + 'ios', + '--no-install', + '--template', + path.join(expo, 'template.tgz'), + ], + root, + ), + ); + const resolved = JSON.parse( + invoke( + spec, + path.join(expo, 'bin/autolinking'), + ['resolve', '--platform', 'apple', '--json'], + root, + ), + ); + assertIosAutolinking(resolved, spec.expectedModules); + const propertiesFile = path.join(root, 'ios/Podfile.properties.json'); + const properties = JSON.parse(readFileSync(propertiesFile, 'utf8')); + assert.equal(properties['expo.jsEngine'], 'hermes'); + assert( + !Object.keys(properties).some((key) => key.startsWith('expo.sqlite.')), + 'Declare the changed SQLite source/compiler profile in the Apple graph', + ); + const app = path.join(root, 'ios', spec.targetName); + const entitlements = readFileSync(path.join(app, spec.targetName + '.entitlements'), 'utf8'); + assert( + entitlements.includes('') && !entitlements.includes(''), + 'Nonempty application entitlements require declared plist-tool consumption by the original Expo generator', + ); + const generated = path.join(root, 'generated'); + mkdirSync(generated); + console.log( + invoke( + spec, + path.join(expo, 'bin/autolinking'), + [ + 'generate-modules-provider', + '--platform', + 'apple', + '--target', + path.join(generated, 'ExpoModulesProvider.swift'), + '--target-name', + spec.targetName, + '--app-root', + root, + '--podfile-properties-file-path', + propertiesFile, + '--packages', + ...resolved.modules.map((row: any) => row.packageName), + ], + root, + ), + ); + console.log( + invoke( + spec, + path.join(rn, 'scripts/generate-codegen-artifacts.js'), + ['-p', root, '-t', 'ios', '-o', path.join(generated, 'codegen')], + root, + ), + ); + const constantsId = Object.keys(spec.packages).find( + (id) => spec.packages[id].package === 'expo-constants', + ); + assert(constantsId); + const configDirectory = path.join(generated, 'constants'); + mkdirSync(configDirectory); + console.log( + invoke( + spec, + path.join(stores[constantsId], 'scripts/getAppConfig.js'), + [root, configDirectory], + root, + ), + ); + put(spec.constantsConfig, readFileSync(path.join(configDirectory, 'app.config'))); + const codegen = path.join(generated, 'codegen/build/generated/ios'); + const actualCode = files(codegen).filter((name) => /\.(?:h|mm|cpp)$/u.test(name)); + const expectedCode = Object.keys(spec.outputs) + .filter((name) => name.startsWith('codegen/')) + .map((name) => name.slice(8)) + .sort(); + assert.deepEqual( + actualCode, + expectedCode, + 'Declare the original React Native generator output changes before compilation', + ); + for (const [relative, output] of Object.entries(spec.outputs)) { + assert( + !path.isAbsolute(relative) && + relative.split('/').every((part) => part && part !== '.' && part !== '..'), + ); + const source = + relative === 'ExpoModulesProvider.swift' + ? path.join(generated, relative) + : relative.startsWith('app/') + ? path.join(app, relative.slice(4)) + : relative.startsWith('sdk/') + ? path.join(sdk, relative.slice(4)) + : relative.startsWith('codegen/') + ? path.join(codegen, relative.slice(8)) + : null; + assert( + source && existsSync(source), + 'Original Expo/RN generation did not produce ' + relative, + ); + mkdirSync(path.dirname(output), { recursive: true }); + if (relative.endsWith('.xcassets') || relative.endsWith('.icon')) + cpSync(source, output, { recursive: true }); + else copyFileSync(source, output); + } + // The release app preserves the generator's plist, with the original default Metro port. + const plistOutput = spec.outputs['app/Info.plist']; + if (plistOutput) + put(plistOutput, readFileSync(plistOutput, 'utf8').replaceAll('$(RCT_METRO_PORT)', '8081')); + const normalized = JSON.stringify(resolved, null, 2).replaceAll(root + '/', ''); + put(spec.autolinking, normalized + '\n'); + }); +} +export function bundleExpoIos( + spec: NodeInputs & { + entry: string; + bundle: string; + resources: string; + sourceMap: string; + environment?: Record; + selectedExtensions: string[]; + catalogProfile: string; + profileProbe: string; + }, +) { + return scratch((root) => { + const stores = stageNodeInputs(root, spec); + const expo = stores[spec.roots.expo]; + const rnRow = spec.packages[spec.roots['react-native']]; + const hermesId = rnRow.dependencies['hermes-compiler']; + assert(expo && hermesId, 'The release app needs the locked original Hermes compiler'); + assert.equal(spec.packages[hermesId].package, 'hermes-compiler'); + const rn = stores[spec.roots['react-native']]; + const rnManifest = JSON.parse(readFileSync(path.join(rn, 'package.json'), 'utf8')); + assert.equal( + spec.packages[hermesId].version, + rnManifest.dependencies['hermes-compiler'], + 'Use the exact RN-declared compiler', + ); + const host = + process.platform === 'darwin' + ? 'osx-bin' + : process.platform === 'linux' + ? 'linux64-bin' + : null; + assert(host, 'The declared Apple bundling executor must support the original Hermes compiler'); + const compiler = path.join(stores[hermesId], 'hermesc', host, 'hermesc'); + assert(existsSync(compiler)); + chmodSync(compiler, 0o755); + const js = path.join(root, 'main.jsbundle'), + assets = path.join(root, 'bundle-assets'); + const map = path.join(root, 'main.jsbundle.map'); + console.log( + invoke( + spec, + path.join(expo, 'bin/cli'), + [ + 'export:embed', + '--platform', + 'ios', + '--dev', + 'false', + '--entry-file', + spec.entry, + '--bundle-output', + js, + '--assets-dest', + assets, + '--sourcemap-output', + map, + ], + root, + { + ...mobileBundleEnvironment( + spec.environment ?? {}, + spec.selectedExtensions, + spec.catalogProfile, + spec.profileProbe, + ), + TMPDIR: root, + }, + ), + ); + const hbc = path.join(root, 'main.hbc'); + execFileSync( + compiler, + ['-w', '-O', '-emit-binary', '-out', path.basename(hbc), path.basename(js)], + { + cwd: root, + stdio: 'inherit', + }, + ); + const bytes = readFileSync(hbc); + assert.equal( + bytes.subarray(0, 8).toString('hex'), + 'c61fbc03c103191f', + 'The app must contain actual Hermes bytecode', + ); + put(spec.bundle, bytes); + put(spec.sourceMap, readFileSync(map)); + mkdirSync(spec.resources, { recursive: true }); + if (existsSync(assets)) cpSync(assets, spec.resources, { recursive: true }); + }); +} +if (import.meta.main) { + const [operation, file] = process.argv.slice(2); + const spec = JSON.parse(readFileSync(file, 'utf8')); + if (operation === 'project') projectExpoIos(spec); + else if (operation === 'bundle') bundleExpoIos(spec); + else throw new Error('Unsupported Apple app operation ' + operation); +} diff --git a/build_defs/apple/app.test.mts b/build_defs/apple/app.test.mts new file mode 100644 index 000000000..f0517c55c --- /dev/null +++ b/build_defs/apple/app.test.mts @@ -0,0 +1,65 @@ +import { describe, expect, test } from 'bun:test'; +import { readFileSync } from 'node:fs'; +import { assertIosAutolinking } from './app.mts'; + +const actual = JSON.parse( + readFileSync(new URL('./testdata/expo56-original-apple-resolve.json', import.meta.url), 'utf8'), +); +const expected = Object.fromEntries( + actual.modules.map((row: any) => [row.packageName, row.packageVersion]), +); +describe('the original Expo Apple resolve is the compiled release closure', () => { + test('retains all real modules including explicitly guarded debug modules', () => { + expect(Object.keys(expected)).toHaveLength(20); + assertIosAutolinking(actual, expected); + }); + test('rejects duplicate native registration even when package version is unchanged', () => { + const changed = structuredClone(actual); + changed.modules.push(structuredClone(changed.modules[0])); + expect(() => assertIosAutolinking(changed, expected)).toThrow(/exactly once/); + }); + test.each([ + 'expo-sqlite', + 'expo-modules-jsi', + 'expo', + 'expo-dev-launcher', + ])('rejects missing actual native module %s', (name: string) => { + const changed = structuredClone(actual); + changed.modules = changed.modules.filter((row: any) => row.packageName !== name); + expect(() => assertIosAutolinking(changed, expected)).toThrow(/declared native source closure/); + }); + test('rejects a wrong independently held native dependency version', () => { + const changed = structuredClone(actual); + changed.modules.find((row: any) => row.packageName === 'expo-modules-jsi').packageVersion = + '56.0.15'; + expect(() => assertIosAutolinking(changed, expected)).toThrow(/declared native source closure/); + }); + test.each([ + 'extraDependencies', + 'coreFeatures', + ])('fails before compile on undeclared %s', (field: string) => { + const changed = structuredClone(actual); + changed[field] = ['future-native-input']; + expect(() => assertIosAutolinking(changed, expected)).toThrow(/Declare new Expo Apple/); + }); + test('does not omit an existing release module just because it has no registered Swift Module class', () => { + const changed = structuredClone(actual); + changed.modules = changed.modules.filter( + (row: any) => row.packageName !== 'expo-updates-interface', + ); + expect(() => assertIosAutolinking(changed, expected)).toThrow(); + }); + test('rejects changed debug-only module semantics before provider/library linking', () => { + const changed = structuredClone(actual); + changed.modules.find((row: any) => row.packageName === 'expo-dev-menu').debugOnly = false; + expect(() => assertIosAutolinking(changed, expected)).toThrow(/debug module conditions/); + }); + test('retains deterministic closure matching when original discovery order changes', () => { + for (let seed = 0; seed < 30; seed++) { + const changed = structuredClone(actual); + const offset = seed % changed.modules.length; + changed.modules = [...changed.modules.slice(offset), ...changed.modules.slice(0, offset)]; + assertIosAutolinking(changed, expected); + } + }); +}); diff --git a/build_defs/apple/captured-archive.mts b/build_defs/apple/captured-archive.mts new file mode 100644 index 000000000..eea3b88ba --- /dev/null +++ b/build_defs/apple/captured-archive.mts @@ -0,0 +1,53 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import { readPortableArchiveEntries } from '../../tools/packaging/portable-archive.mts'; +import { verifyCapturedFile } from './captured-file.mts'; +export function verifyAppleCapturedArchive(archive: string, row: any) { + assert(row && (row.publication?.product ?? row.owner) === 'liboliphaunt-native'); + const version = row.publication?.version ?? row.version; + const expected = path.basename(archive); + if (row.publication) assert.equal(row.artifact, `github-release:${expected}`); + else { + assert.equal( + row.file.member, + undefined, + 'Current Apple archive must be its whole producer File', + ); + assert.equal( + row.file.producer.root, + `//src/native/runtime:${expected.endsWith('-apple-spm-xcframework.zip') ? 'apple_swiftpm_shipping' : 'apple_resources_shipping'}`, + ); + } + const physical = verifyCapturedFile(archive, row.file); + assert(/^\d+\.\d+\.\d+$/u.test(version)); + const framework = expected === 'liboliphaunt-' + version + '-apple-spm-xcframework.zip'; + const resources = + expected === 'liboliphaunt-' + version + '-runtime-resources-ios-datum64.tar.gz'; + assert(framework || resources, 'The captured native artifact has no Apple construction role'); + const entries = readPortableArchiveEntries(physical, { format: framework ? 'zip' : 'tar.gz' }); + for (const [name, entry] of entries) + assert( + !entry.isSymbolicLink, + 'Native public archive must contain original regular Files: ' + name, + ); + const required = framework + ? [ + 'liboliphaunt.xcframework/Info.plist', + 'liboliphaunt.xcframework/ios-arm64/liboliphaunt.framework/liboliphaunt', + 'liboliphaunt.xcframework/ios-arm64-simulator/liboliphaunt.framework/liboliphaunt', + 'liboliphaunt.xcframework/ios-arm64-simulator/liboliphaunt.framework/Headers/oliphaunt.h', + ] + : ['oliphaunt/runtime/manifest.properties']; + for (const name of required) + assert(entries.get(name)?.isFile, 'Captured Apple artifact lost required member ' + name); + return { version, framework, resources }; +} +if (import.meta.main) { + const [archive, descriptor] = process.argv.slice(2); + console.log( + JSON.stringify( + verifyAppleCapturedArchive(archive, JSON.parse(readFileSync(descriptor, 'utf8'))), + ), + ); +} diff --git a/build_defs/apple/captured-file.mts b/build_defs/apple/captured-file.mts new file mode 100644 index 000000000..36a62bad0 --- /dev/null +++ b/build_defs/apple/captured-file.mts @@ -0,0 +1,19 @@ +/** Authenticate a declared supplier File, including Bazel's outer File aliases. */ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { lstatSync, readFileSync, realpathSync } from 'node:fs'; + +export type FileIdentity = { size: number; sha256: string }; + +export function verifyCapturedFile(file: string, identity: FileIdentity) { + const physical = realpathSync(file); + const stat = lstatSync(physical); + assert(stat.isFile(), 'Captured supplier File must resolve to a regular File'); + assert.equal(stat.size, identity.size, 'Captured supplier File size differs'); + assert.equal( + createHash('sha256').update(readFileSync(physical)).digest('hex'), + identity.sha256, + 'Captured supplier File SHA differs', + ); + return physical; +} diff --git a/build_defs/apple/captured-repository.bzl b/build_defs/apple/captured-repository.bzl new file mode 100644 index 000000000..39a789b43 --- /dev/null +++ b/build_defs/apple/captured-repository.bzl @@ -0,0 +1,67 @@ +"""Expose original completed-publication archive bytes as stock Apple import Files.""" + +def _captured_impl(ctx): + catalog = json.decode(ctx.read(ctx.attr.catalog)) + current = json.decode(ctx.read(ctx.attr.current_native)) + selected = json.decode(ctx.read(ctx.attr.selected_products)) + construction = json.decode(ctx.read(ctx.attr.swift_construction)) + version = construction["nativeVersion"] + native = "liboliphaunt-native/" + version + "/github-release:liboliphaunt-" + version + roles = [ + ("framework", "-apple-spm-xcframework.zip"), + ("resources", "-runtime-resources-ios-datum64.tar.gz"), + ] + ctx.watch(ctx.path(ctx.attr.bun)) + for helper in [ctx.attr.verifier, ctx.attr.file_verifier, ctx.attr.archive_parser]: + ctx.read(helper) + keys = [native + suffix for _, suffix in roles] + found = [key in catalog for key in keys] + if found[0] != found[1]: + fail("The completed native Apple supplier tuple is incomplete") + if not found[0] and (not current or current["version"] != version or "liboliphaunt-native" not in selected): + fail("Unpublished native requirement needs its exact selected final producer Files") + for role, suffix in roles: + key = native + suffix + row = catalog[key] if found[0] else {"owner": current["owner"], "version": current["version"], "file": current[role]} + if role == "framework" and row["file"]["sha256"] != construction["nativeChecksum"]: + fail("Genuine Package.swift native checksum differs from its supplier File") + # Labels are derived by the existing snapshot serializer from authenticated Files. + archive = ctx.path(Label(row["file"]["path"])) + ctx.watch(archive) + descriptor = role + ".json" + ctx.file(descriptor, json.encode(row)) + verified = ctx.execute([str(ctx.path(ctx.attr.bun)), str(ctx.path(ctx.attr.verifier)), + str(archive), str(ctx.path(descriptor))], timeout = 60, quiet = True) + if verified.return_code: + fail("Cannot expose the genuine completed Apple archive:\n" + verified.stdout + verified.stderr) + ctx.symlink(archive, "archives/" + archive.basename) + ctx.extract(archive = archive, output = role) + ctx.file("BUILD.bazel", """ +load("@rules_apple//apple:apple.bzl", "apple_dynamic_xcframework_import") +load("@rules_cc//cc:defs.bzl", "cc_library") +package(default_visibility = ["//visibility:public"]) +filegroup(name = "archive", srcs = glob(["archives/*-apple-spm-xcframework.zip"])) +filegroup(name = "resources_archive", srcs = glob(["archives/*-runtime-resources-ios-datum64.tar.gz"])) +filegroup(name = "xcframework_files", srcs = glob(["framework/liboliphaunt.xcframework/**"])) +filegroup(name = "ios_device_files", srcs = glob(["framework/liboliphaunt.xcframework/ios-arm64/**"]) + ["framework/liboliphaunt.xcframework/Info.plist"]) +filegroup(name = "ios_simulator_files", srcs = glob(["framework/liboliphaunt.xcframework/ios-arm64-simulator/**"]) + ["framework/liboliphaunt.xcframework/Info.plist"]) +filegroup(name = "runtime_resources", srcs = glob(["resources/oliphaunt/**"])) +# The original stageIosApp owns the single app resource bundle. Keep compiler/ +# runtime framework Files genuine while avoiding a second embedded runtime tree. +apple_dynamic_xcframework_import(name = "runtime", xcframework_imports = glob(["framework/liboliphaunt.xcframework/**"], exclude = ["**/Resources/oliphaunt/**"])) +cc_library(name = "runtime_headers", hdrs = ["framework/liboliphaunt.xcframework/ios-arm64-simulator/liboliphaunt.framework/Headers/oliphaunt.h"], + includes = ["framework/liboliphaunt.xcframework/ios-arm64-simulator/liboliphaunt.framework/Headers"]) +exports_files(["framework/liboliphaunt.xcframework/ios-arm64-simulator/liboliphaunt.framework/Headers/oliphaunt.h"]) +""") + return ctx.repo_metadata(reproducible = True) + +apple_captured_archives_repository = repository_rule(implementation = _captured_impl, attrs = { + "catalog": attr.label(mandatory = True, allow_single_file = [".json"]), + "current_native": attr.label(mandatory = True, allow_single_file = [".json"]), + "selected_products": attr.label(mandatory = True, allow_single_file = [".json"]), + "swift_construction": attr.label(mandatory = True, allow_single_file = [".json"]), + "bun": attr.label(default = Label("@bun_runtime//:bun"), allow_single_file = True), + "verifier": attr.label(default = Label("//build_defs/apple:captured-archive.mts"), allow_single_file = True), + "file_verifier": attr.label(default = Label("//build_defs/apple:captured-file.mts"), allow_single_file = True), + "archive_parser": attr.label(default = Label("//:tools/packaging/portable-archive.mts"), allow_single_file = True), +}) diff --git a/build_defs/apple/captured-swift-repository.bzl b/build_defs/apple/captured-swift-repository.bzl new file mode 100644 index 000000000..2406c2575 --- /dev/null +++ b/build_defs/apple/captured-swift-repository.bzl @@ -0,0 +1,82 @@ +"""Expose authenticated historical Swift source and its conventional binding archive.""" + +load(":requirement-selection.bzl", "swift_requirement_inputs") + +def _captured_swift_impl(ctx): + catalog = json.decode(ctx.read(ctx.attr.catalog)) + manifest = json.decode(ctx.read(ctx.attr.manifest)) + selected = json.decode(ctx.read(ctx.attr.selected_products)) + current = json.decode(ctx.read(ctx.attr.current_source)) + version = manifest["oliphaunt"]["swiftSdkVersion"] + decision = swift_requirement_inputs(version, selected, catalog, current) + if "error" in decision: + fail(decision["error"] + " at " + version) + source, bindings, has_source = decision["source"], decision["bindings"], decision["completed"] + if has_source: + source_file, source_operation, source_prefix = source["file"], "source", "" + else: + source_file, source_operation, source_prefix = current["archive"], "current-source", "package" + carrier = ctx.path(Label(current["carrier"]["path"])) + ctx.watch(carrier) + ctx.symlink(carrier, "carrier.json") + source = dict(current, carrier = dict(current["carrier"], path = str(carrier))) + ctx.watch(ctx.path(ctx.attr.bun)) + for helper in [ctx.attr.verifier, ctx.attr.file_verifier, ctx.attr.archive_parser, ctx.attr.manifest_parser, ctx.attr.carrier_parser, ctx.attr.package_rule]: + ctx.read(helper) + archives = {} + for role, row in [("source", source), ("bindings", bindings)]: + archive = ctx.path(Label((source_file if role == "source" else row["file"])["path"])) + ctx.watch(archive) + descriptor = role + ".json" + ctx.file(descriptor, json.encode(row)) + result = ctx.execute([str(ctx.path(ctx.attr.bun)), str(ctx.path(ctx.attr.verifier)), + source_operation if role == "source" else "file", str(archive), str(ctx.path(descriptor)), + str(ctx.path("construction.json")) if role == "source" else ""], timeout = 60, quiet = True) + if result.return_code: + fail("Cannot construct the genuine held Swift package:\n" + result.stdout + result.stderr) + ctx.symlink(archive, "archives/" + archive.basename) + archives[role] = "archives/" + archive.basename + ctx.extract(archive = archive, stripPrefix = source_prefix if role == "source" else "") + construction = json.decode(ctx.read("construction.json")) + if construction["bindingsChecksum"] != bindings["file"]["sha256"]: + fail("Held Swift source does not require the captured original bindings File") + source_origin = {"kind": "completed-publication", "publication": source["publication"], "artifact": source["artifact"]} if has_source else {"kind": "current-source", "producer": dict(current["carrier"]["producer"], **({"member": current["carrier"]["member"]} if "member" in current["carrier"] else {}))} + ctx.file("construction.bzl", "SWIFT_CONSTRUCTION = " + repr(construction) + "\n") + ctx.file("BUILD.bazel", "\n".join([ + 'load("@rules_apple//apple:apple.bzl", "apple_static_xcframework_import")', + 'load("@oliphaunt//build_defs/release:identity.bzl", "release_identity")', + 'load("@oliphaunt//build_defs/release:supplier.bzl", "file_shipping_supplier")', + 'load("@oliphaunt//build_defs/release:supplier.bzl", "shipping_suppliers")', + 'load("@oliphaunt//build_defs/extensions:declared_final_inputs.bzl", "native_declared_apple_base")', + 'load(%s, "captured_swift_package")' % repr(str(ctx.attr.package_rule)), + 'load(":construction.bzl", "SWIFT_CONSTRUCTION")', + 'package(default_visibility = ["//visibility:public"])', + 'exports_files(["Package.swift", "construction.json", "construction.bzl"])', + 'filegroup(name = "source_archive", srcs = [%s])' % repr(archives["source"]), + 'filegroup(name = "bindings_archive", srcs = [%s])' % repr(archives["bindings"]), + 'filegroup(name = "carrier", srcs = [%s])' % repr(construction["carrierMember"]), + 'release_identity(name = "source_owner", product_id = "oliphaunt-swift", version = %s)' % repr(version), + 'file_shipping_supplier(name = "carrier_supplier", inputs = {":carrier": %s}, owner = ":source_owner", configuration = "portable", binding = %s, origin = %s)' % (repr(source["source"]["member"] if has_source else ""), repr("compiled-input" if has_source else "abi-contract"), repr(json.encode(source_origin))), + 'native_declared_apple_base(name = "native_requirement", version = SWIFT_CONSTRUCTION["nativeVersion"])', + 'filegroup(name = "xcframework_archive", srcs = [":native_requirement"], output_group = "framework")', + 'filegroup(name = "runtime_resources_archive", srcs = [":native_requirement"], output_group = "resources")', + 'shipping_suppliers(name = "package_suppliers", inputs = [":carrier_supplier", ":native_requirement"])', + 'apple_static_xcframework_import(name = "OliphauntNativeBindingsFFI", xcframework_imports = glob(["OliphauntNativeBindingsFFI.xcframework/**"]))', + 'captured_swift_package(runtime = %s, targets = SWIFT_CONSTRUCTION["targets"], language_version = SWIFT_CONSTRUCTION["languageVersion"])' % repr(str(ctx.attr.runtime)), + ]) + "\n") + return ctx.repo_metadata(reproducible = True) + +apple_captured_swift_repository = repository_rule(implementation = _captured_swift_impl, attrs = { + "catalog": attr.label(mandatory = True, allow_single_file = [".json"]), + "manifest": attr.label(mandatory = True, allow_single_file = [".json"]), + "selected_products": attr.label(mandatory = True, allow_single_file = [".json"]), + "current_source": attr.label(mandatory = True, allow_single_file = [".json"]), + "runtime": attr.label(mandatory = True), + "bun": attr.label(default = Label("@bun_runtime//:bun"), allow_single_file = True), + "verifier": attr.label(default = Label("//build_defs/apple:captured-swift-source.mts"), allow_single_file = True), + "file_verifier": attr.label(default = Label("//build_defs/apple:captured-file.mts"), allow_single_file = True), + "archive_parser": attr.label(default = Label("//:tools/packaging/portable-archive.mts"), allow_single_file = True), + "manifest_parser": attr.label(default = Label("//src/native/sdks/swift:tools/prepare-swift-release-consumer.mts"), allow_single_file = True), + "carrier_parser": attr.label(default = Label("//src/native/sdks/swift:tools/swift-native-carrier-contract.mts"), allow_single_file = True), + "package_rule": attr.label(default = Label("//build_defs/apple:captured-swift.bzl"), allow_single_file = True), +}) diff --git a/build_defs/apple/captured-swift-source.mts b/build_defs/apple/captured-swift-source.mts new file mode 100644 index 000000000..386e0dd20 --- /dev/null +++ b/build_defs/apple/captured-swift-source.mts @@ -0,0 +1,204 @@ +/** Construction from the existing authenticated Swift source delivery and supplier Files. */ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { readFileSync, writeFileSync } from 'node:fs'; +import { parseSwiftReleaseBinaryTarget } from '../../src/native/sdks/swift/tools/prepare-swift-release-consumer.mts'; +import { validateFrozenNativeCarrierIdentity } from '../../src/native/sdks/swift/tools/swift-native-carrier-contract.mts'; +import { readPortableArchiveEntries } from '../../tools/packaging/portable-archive.mts'; +import { type FileIdentity, verifyCapturedFile } from './captured-file.mts'; + +export { verifyCapturedFile } from './captured-file.mts'; +export type SourceDelivery = { + publication: { product: string; version: string }; + source: { commit: string; tree: string; member: string; blob: string }; + file: FileIdentity; +}; +const sha = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +function carrierConstruction( + bytes: Uint8Array, + construction: ReturnType, + swiftVersion: string, +) { + const carrier = validateFrozenNativeCarrierIdentity({ + carrier: JSON.parse(Buffer.from(bytes).toString('utf8')), + expectedNativeVersion: construction.nativeVersion, + }); + assert.equal( + carrier.base.assets.find((asset) => asset.role === 'base-xcframework').sha256, + construction.nativeChecksum, + 'Actual Swift carrier and Package.swift require different native Files', + ); + return { ...construction, swiftVersion, carrierFile: { size: bytes.length, sha256: sha(bytes) } }; +} +export function swiftPackageConstruction(manifest: string, swiftVersion: string) { + const native = parseSwiftReleaseBinaryTarget(manifest, 'genuine captured Package.swift'); + const nativeVersion = + /^https:\/\/github\.com\/f0rr0\/oliphaunt\/releases\/download\/liboliphaunt-native-v(\d+\.\d+\.\d+)\/liboliphaunt-\1-apple-spm-xcframework\.zip$/u.exec( + native.url, + )?.[1]; + assert(nativeVersion, 'Swift native requirement must be its canonical exact public target'); + const bindings = [ + ...manifest.matchAll( + /\.binaryTarget\(\s*name:\s*"OliphauntNativeBindingsFFI"\s*,\s*url:\s*"([^"]+)"\s*,\s*checksum:\s*"([0-9a-f]{64})"\s*\)/gmu, + ), + ]; + assert.equal(bindings.length, 1, 'Swift package must declare its genuine bindings target once'); + assert.equal( + bindings[0][1], + `https://github.com/f0rr0/oliphaunt/releases/download/oliphaunt-swift-v${swiftVersion}/oliphaunt-swift-${swiftVersion}-bindings.xcframework.zip`, + ); + assert.equal( + [...manifest.matchAll(/\.binaryTarget\(/gu)].length, + 2, + 'Unexpected additional binary target', + ); + const sourceTargets = [ + ...manifest.matchAll( + /\.target\(\s*name:\s*"([^"]+)"\s*,\s*dependencies:\s*\[([^\]]*)\]\s*,\s*path:\s*"([^"]+)"(?:\s*,\s*publicHeadersPath:\s*"([^"]+)"\s*,\s*cSettings:\s*\[\.define\("([^"]+)"\)\])?\s*\)/gmu, + ), + ]; + assert.equal( + sourceTargets.length, + [...manifest.matchAll(/\.target\(/gu)].length, + 'Unsupported source-target expression in captured Package.swift', + ); + assert(sourceTargets.length > 0, 'Swift package has no source targets'); + const targets: Record< + string, + { path: string; dependencies: string[]; publicHeaders?: string; define?: string } + > = {}; + for (const [, name, dependencyText, sourcePath, publicHeaders, define] of sourceTargets) { + assert(!targets[name], 'Duplicate conventional Swift target: ' + name); + const dependencies = [...dependencyText.matchAll(/"([A-Za-z][A-Za-z0-9_]*)"/gu)].map( + (match) => match[1], + ); + assert.equal( + dependencyText.replace(/"[A-Za-z][A-Za-z0-9_]*"|[\s,]/gu, ''), + '', + 'Unsupported Swift dependency expression', + ); + assert( + /^[A-Za-z][A-Za-z0-9_]*$/u.test(name) && + /^[A-Za-z0-9_./-]+$/u.test(sourcePath) && + !sourcePath.split('/').includes('..'), + 'Unsafe Swift source target', + ); + if (publicHeaders) assert.equal(publicHeaders, 'include', 'Unsupported C public header layout'); + targets[name] = { + path: sourcePath, + dependencies, + ...(publicHeaders ? { publicHeaders, define } : {}), + }; + } + for (const target of Object.values(targets)) + for (const dependency of target.dependencies) + assert( + targets[dependency] || ['liboliphaunt', 'OliphauntNativeBindingsFFI'].includes(dependency), + 'Missing conventional Swift dependency: ' + dependency, + ); + const languageVersion = /^\/\/ swift-tools-version: (\d+)\.\d+$/mu.exec(manifest)?.[1]; + assert(languageVersion, 'Captured package has no declared Swift tools floor'); + return { + nativeVersion, + nativeChecksum: native.checksum, + bindingsChecksum: bindings[0][2], + targets, + languageVersion, + }; +} + +export function verifyCapturedSwiftSource(archive: string, delivery: SourceDelivery) { + assert.equal(delivery.publication.product, 'oliphaunt-swift'); + for (const value of [delivery.source.commit, delivery.source.tree]) + assert.match(value, /^[0-9a-f]{40}$/u); + const physical = verifyCapturedFile(archive, delivery.file); + const entries = readPortableArchiveEntries(physical, { format: 'tar.gz' }); + for (const [name, entry] of entries) { + // Acquisition has already authenticated the complete Git inventory before + // retaining this SHA-bound archive. Construction adds no second authority. + assert( + !entry.isSymbolicLink && (entry.isFile || entry.isDirectory), + 'Captured source archive must expose genuine regular Files: ' + name, + ); + } + const manifest = entries.get('Package.swift'); + assert(manifest?.isFile, 'Genuine source delivery must include root Package.swift'); + const bytes = typeof manifest.data === 'function' ? manifest.data() : manifest.data; + const construction = swiftPackageConstruction( + bytes.toString('utf8'), + delivery.publication.version, + ); + for (const [name, target] of Object.entries(construction.targets)) { + assert( + [...entries.keys()].some( + (member) => + member.startsWith(target.path + '/') && + (target.publicHeaders ? member.endsWith('.c') : member.endsWith('.swift')), + ), + 'Missing genuine source Files for ' + name, + ); + } + const carrier = entries.get(delivery.source.member); + assert(carrier?.isFile, 'Genuine source delivery lacks its original carrier member'); + const carrierBytes = carrier.data(); + assert.equal( + createHash('sha1') + .update(Buffer.from(`blob ${carrierBytes.length}\0`)) + .update(carrierBytes) + .digest('hex'), + delivery.source.blob, + 'Original carrier Git blob differs', + ); + return { + ...carrierConstruction(carrierBytes, construction, delivery.publication.version), + carrierMember: delivery.source.member, + }; +} + +export function verifyCurrentSwiftSource( + archive: string, + input: { + owner: string; + version: string; + archive: FileIdentity; + carrier: FileIdentity & { path: string }; + }, +) { + assert.equal(input.owner, 'oliphaunt-swift'); + const physical = verifyCapturedFile(archive, input.archive); + const entries = readPortableArchiveEntries(physical, { format: 'zip' }); + const version = entries.get('package/VERSION'), + manifest = entries.get('package/Package.swift'); + assert( + version?.isFile && manifest?.isFile, + 'Current Swift producer must deliver its original standalone package', + ); + assert.equal( + version.data().toString().trim(), + input.version, + 'Current source archive version cannot be relabelled', + ); + const carrier = verifyCapturedFile(input.carrier.path, input.carrier); + return { + ...carrierConstruction( + readFileSync(carrier), + swiftPackageConstruction(manifest.data().toString('utf8'), input.version), + input.version, + ), + carrierMember: 'carrier.json', + }; +} + +if (import.meta.main) { + const [operation, file, descriptor, output] = process.argv.slice(2); + const identity = JSON.parse(readFileSync(descriptor, 'utf8')); + const result = + operation === 'source' + ? verifyCapturedSwiftSource(file, identity) + : operation === 'current-source' + ? verifyCurrentSwiftSource(file, identity) + : operation === 'file' + ? verifyCapturedFile(file, identity.file) + : assert.fail('Unknown captured Swift operation'); + if (output) writeFileSync(output, JSON.stringify(result) + '\n'); +} diff --git a/build_defs/apple/captured-swift-source.test.mts b/build_defs/apple/captured-swift-source.test.mts new file mode 100644 index 000000000..6dc3ac17f --- /dev/null +++ b/build_defs/apple/captured-swift-source.test.mts @@ -0,0 +1,225 @@ +import { describe, expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { buildIosCarrierManifest } from '../../src/native/sdks/swift/tools/ios-carrier-manifest.mts'; +import { createDeterministicZip } from '../../tools/packaging/archive-directory.mts'; +import { fixture as swiftSourceFixture } from '../languages/swift/source-package.fixture.mts'; +import { verifyAppleCapturedArchive } from './captured-archive.mts'; +import { verifyCapturedFile } from './captured-file.mts'; +import { swiftPackageConstruction, verifyCurrentSwiftSource } from './captured-swift-source.mts'; +import { iosResourceBaseFiles } from './resources.mts'; + +const manifest = readFileSync( + new URL('./testdata/swift-0.8.2-original-Package.swift', import.meta.url), + 'utf8', +); +describe('genuine independently held Swift source construction', () => { + test('resource construction resolves producer File aliases without changing their captured identities', async () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'ios-resource-file-alias-')); + try { + const spec = await swiftSourceFixture(root); + const original = JSON.parse(readFileSync(spec.carrier, 'utf8')); + const baseManifest = path.join(root, 'carrier-alias.json'); + symlinkSync(spec.carrier, baseManifest); + const archives = Object.fromEntries( + original.base.assets.map((asset) => { + const physical = + asset.role === 'base-xcframework' ? spec.xcframework : spec.runtimeResources; + const alias = path.join(root, 'alias-' + asset.name); + symlinkSync(physical, alias); + return [asset.role, { path: alias, size: asset.bytes, sha256: asset.sha256 }]; + }), + ); + const inputs = iosResourceBaseFiles({ baseManifest, archives }); + const actual = buildIosCarrierManifest({ + ...inputs, + baseRuntimeVersion: spec.nativeVersion, + baseTag: `liboliphaunt-native-v${spec.nativeVersion}`, + declaredProducts: {}, + }); + expect(actual.base).toEqual(original.base); + expect(actual.legal.base).toEqual(original.legal.base); + expect(archives['base-xcframework'].path).toContain('/alias-'); + expect(() => + buildIosCarrierManifest({ + ...inputs, + baseRuntimeVersion: spec.nativeVersion, + baseTag: `liboliphaunt-native-v${spec.nativeVersion}`, + declaredProducts: {}, + baseArchiveInputs: { + ...inputs.baseArchiveInputs, + 'base-xcframework': { + ...inputs.baseArchiveInputs['base-xcframework'], + sha256: '0'.repeat(64), + }, + }, + }), + ).toThrow(/SHA|sha256|identity|frozen/i); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }); + test('current source construction consumes its original package layout and rejects version relabeling', async () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'current-swift-archive-fixture-')); + try { + const source = path.join(root, 'package'); + mkdirSync(source); + writeFileSync(path.join(source, 'VERSION'), '0.8.2\n'); + writeFileSync( + path.join(source, 'Package.swift'), + manifest.replaceAll('"src/sdks/swift/Sources/', '"Sources/'), + ); + const bytes = await createDeterministicZip(source, { keepParent: true }); + const physicalArchive = path.join(root, 'source-output'); + writeFileSync(physicalArchive, bytes); + const archive = path.join(root, 'Oliphaunt-source.zip'); + symlinkSync(physicalArchive, archive); + const input = { + owner: 'oliphaunt-swift', + version: '0.8.2', + archive: { size: bytes.length, sha256: createHash('sha256').update(bytes).digest('hex') }, + carrier: (() => { + const bytes = readFileSync( + new URL('../release/testdata/swift-0.8.2-carrier.json', import.meta.url), + ); + const file = path.join(root, 'carrier.json'); + writeFileSync(file, bytes); + return { + path: file, + size: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + }; + })(), + }; + expect(verifyCurrentSwiftSource(archive, input).targets.Oliphaunt.path).toBe( + 'Sources/Oliphaunt', + ); + expect(() => verifyCurrentSwiftSource(archive, { ...input, version: '0.8.3' })).toThrow( + /cannot be relabelled/, + ); + expect(() => + verifyCurrentSwiftSource(archive, { + ...input, + archive: { ...input.archive, sha256: '0'.repeat(64) }, + }), + ).toThrow(/SHA differs/); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }); + test('authenticates outer declared File aliases while rejecting corrupt and non-file targets', async () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'captured-apple-alias-')); + try { + const source = path.join(root, 'framework'); + for (const member of [ + 'liboliphaunt.xcframework/Info.plist', + 'liboliphaunt.xcframework/ios-arm64/liboliphaunt.framework/liboliphaunt', + 'liboliphaunt.xcframework/ios-arm64-simulator/liboliphaunt.framework/liboliphaunt', + 'liboliphaunt.xcframework/ios-arm64-simulator/liboliphaunt.framework/Headers/oliphaunt.h', + ]) { + mkdirSync(path.dirname(path.join(source, member)), { recursive: true }); + writeFileSync(path.join(source, member), member); + } + const bytes = await createDeterministicZip(source); + const physical = path.join(root, 'archive-output'); + const alias = path.join(root, 'liboliphaunt-0.3.3-apple-spm-xcframework.zip'); + writeFileSync(physical, bytes); + symlinkSync(physical, alias); + const identity = { + size: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + }; + expect(verifyCapturedFile(alias, identity)).toBe(physical); + expect( + verifyAppleCapturedArchive(alias, { + publication: { product: 'liboliphaunt-native', version: '0.3.3' }, + artifact: 'github-release:' + path.basename(alias), + file: identity, + }), + ).toEqual({ version: '0.3.3', framework: true, resources: false }); + expect(() => verifyCapturedFile(alias, { ...identity, sha256: '0'.repeat(64) })).toThrow( + /SHA differs/, + ); + expect(() => verifyCapturedFile(alias, { ...identity, size: identity.size + 1 })).toThrow( + /size differs/, + ); + writeFileSync(physical, Buffer.alloc(bytes.length)); + expect(() => verifyCapturedFile(alias, identity)).toThrow(/SHA differs/); + const directoryAlias = path.join(root, 'directory-alias'); + symlinkSync(source, directoryAlias); + expect(() => verifyCapturedFile(directoryAlias, identity)).toThrow(/regular File/); + const missingAlias = path.join(root, 'missing-alias'); + symlinkSync(path.join(root, 'absent'), missingAlias); + expect(() => verifyCapturedFile(missingAlias, identity)).toThrow(); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }); + test('uses the delivered conventional manifest without expecting an absent legacy pin file', () => { + const result = swiftPackageConstruction(manifest, '0.8.2'); + expect(result.nativeVersion).toBe('0.3.3'); + expect(result.bindingsChecksum).toBe( + '118c2fc8634e2e6d652797b279f45a693cbe2a5be314fb40760c02204d844441', + ); + expect(result.targets.OliphauntNativeBindings.dependencies).toEqual([ + 'OliphauntNativeBindingsFFI', + ]); + expect(result.targets.Oliphaunt.path).toBe('src/sdks/swift/Sources/Oliphaunt'); + expect(result.targets.Oliphaunt.dependencies).toEqual([ + 'COliphaunt', + 'OliphauntCore', + 'OliphauntNativeBindings', + ]); + expect(result.targets.COliphaunt).toEqual({ + path: 'src/sdks/swift/Sources/COliphaunt', + dependencies: ['liboliphaunt'], + publicHeaders: 'include', + define: 'OLIPHAUNT_LINK_RUNTIME', + }); + }); + test('does not accept current source under a different required Swift version', () => { + expect(() => swiftPackageConstruction(manifest, '0.8.3')).toThrow(); + }); + test('rejects native URL/name version disagreement', () => { + expect(() => + swiftPackageConstruction( + manifest.replace('liboliphaunt-native-v0.3.3/', 'liboliphaunt-native-v0.3.4/'), + '0.8.2', + ), + ).toThrow(/canonical exact/); + }); + test('projects genuine dependency changes instead of keeping a parallel source graph', () => { + const changed = manifest.replace( + 'dependencies: ["COliphaunt", "OliphauntCore", "OliphauntNativeBindings"]', + 'dependencies: ["COliphaunt", "OliphauntCore"]', + ); + expect(swiftPackageConstruction(changed, '0.8.2').targets.Oliphaunt.dependencies).toEqual([ + 'COliphaunt', + 'OliphauntCore', + ]); + }); + test('fails closed when the conventional source package introduces an unsupported expression', () => { + expect(() => + swiftPackageConstruction( + manifest.replace( + 'dependencies: ["OliphauntNativeBindingsFFI"]', + 'dependencies: [.product(name: "Other", package: "Other")]', + ), + '0.8.2', + ), + ).toThrow(/Unsupported Swift dependency/); + }); + test('rejects an undeclared dependency before attempting compilation', () => { + expect(() => + swiftPackageConstruction( + manifest.replace( + 'dependencies: ["OliphauntNativeBindingsFFI"]', + 'dependencies: ["UnknownFFI"]', + ), + '0.8.2', + ), + ).toThrow(/Missing conventional/); + }); +}); diff --git a/build_defs/apple/captured-swift.bzl b/build_defs/apple/captured-swift.bzl new file mode 100644 index 000000000..1ff129aaa --- /dev/null +++ b/build_defs/apple/captured-swift.bzl @@ -0,0 +1,21 @@ +"""Compile the authenticated conventional held Swift source package.""" +load("@rules_swift//swift:swift_library.bzl", "swift_library") +load("@rules_swift//swift:swift_interop_hint.bzl", "swift_interop_hint") +load("@rules_cc//cc:defs.bzl", "cc_library") + +def captured_swift_package(runtime, targets, language_version): + """Project paths/edges from genuine Package.swift; maintained rules compile.""" + native.alias(name = "liboliphaunt", actual = runtime) + for module, target in targets.items(): + dependencies = [":" + name for name in target["dependencies"]] + if target.get("publicHeaders"): + include = target["path"] + "/" + target["publicHeaders"] + hint = module + "_module" + swift_interop_hint(name = hint, module_name = module, module_map = include + "/module.modulemap") + cc_library(name = module, srcs = native.glob([target["path"] + "/*.c"]), + hdrs = native.glob([include + "/*.h"]), includes = [include], + defines = [target["define"]], deps = dependencies, aspect_hints = [":" + hint]) + else: + swift_library(name = module, module_name = module, package_name = "Oliphaunt", + srcs = native.glob([target["path"] + "/*.swift"]), + deps = dependencies, copts = ["-swift-version", language_version]) diff --git a/build_defs/apple/declared-app-tools.patch b/build_defs/apple/declared-app-tools.patch new file mode 100644 index 000000000..be399e5f1 --- /dev/null +++ b/build_defs/apple/declared-app-tools.patch @@ -0,0 +1,41 @@ +diff --git a/tools/wrapper_common/BUILD b/tools/wrapper_common/BUILD +--- a/tools/wrapper_common/BUILD ++++ b/tools/wrapper_common/BUILD +@@ -9,6 +9,10 @@ py_library( + "__init__.py", + "execute.py", + ], ++ data = select({ ++ "@platforms//os:macos": ["@@//build_defs/apple:licensed_app_tools"], ++ "//conditions:default": [], ++ }), + srcs_version = "PY3", + visibility = [ + "//tools/bitcode_strip:__pkg__", +diff --git a/apple/internal/xcframework_rules.bzl b/apple/internal/xcframework_rules.bzl +--- a/apple/internal/xcframework_rules.bzl ++++ b/apple/internal/xcframework_rules.bzl +@@ -925,6 +925,12 @@ + xcode_config = xcode_config, + ) + ++ # These are the identical selected Files consumed by the final bundle. ++ framework_output_groups.append({ ++ "apple_slice_" + identifier: depset([output.binary]) ++ for identifier, output in link_outputs_by_library_identifier.items() ++ }) ++ + processor_output = [ + # Limiting the contents of AppleBundleInfo to what is necessary for testing and validation. + new_applebundleinfo( +@@ -1357,6 +1363,10 @@ + DefaultInfo( + files = depset([outputs_archive]), + ), ++ OutputGroupInfo(**{ ++ "apple_slice_" + identifier: depset([output.binary]) ++ for identifier, output in link_outputs_by_library_identifier.items() ++ }), + ] + + apple_static_xcframework = rule_factory.create_apple_rule( diff --git a/build_defs/apple/final-libraries.bzl b/build_defs/apple/final-libraries.bzl new file mode 100644 index 000000000..66715d501 --- /dev/null +++ b/build_defs/apple/final-libraries.bzl @@ -0,0 +1,68 @@ +"""Regular final archive members feed the maintained C linker directly.""" +load("@oliphaunt_metadata//:metadata.bzl", "EXTENSIONS", "EXTENSION_RELEASE_METADATA", "NATIVE_MOBILE_COMPONENT_CLOSURES") +load("@rules_cc//cc:defs.bzl", "cc_import", "cc_library") +load("//build_defs/extensions:final_leaf.bzl", "ExtensionFinalLeafInfo", "NativeAppleBaseInfo") +load("//build_defs/extensions:declared_final_inputs.bzl", "native_extension_declared_final_import") +load("//build_defs/extensions:owner_carriers.bzl", "native_owner_carrier_helpers") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") + +def _archive_impl(ctx): + leaf = ctx.attr.leaf[ExtensionFinalLeafInfo] + base = ctx.attr.base[NativeAppleBaseInfo] + if leaf.family != "native" or leaf.target != "ios-xcframework" or leaf.metadata["runtimeVersion"] != base.version: + fail("The linked final carrier must hold the app's exact native requirement") + members = leaf.metadata.get("members", [leaf.metadata]) + output = ctx.actions.declare_file(ctx.label.name + ".a") + specification = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + validation = [leaf.validation] if leaf.validation else [] + ctx.actions.write(specification, json.encode({"leaf": {"product": leaf.product, "owner": leaf.owner, "version": leaf.version, + "runtimeVersion": leaf.metadata["runtimeVersion"], "sqlNames": sorted([member["sqlName"] for member in members]), + "github": [file.path for file in leaf.github], "frozen": leaf.frozen.path}, + "runtimeVersion": base.version, "sqlName": ctx.attr.sql_name, "kind": ctx.attr.kind, + "identity": ctx.attr.identity, "slice": ctx.attr.slice, "output": output.path})) + bun_file_action(ctx, ctx.file._runner, arguments = [specification.path], + inputs = leaf.github + [leaf.frozen, base.file, specification] + validation, + source_files = [ctx.file._runner] + ctx.files._helpers, + outputs = [output], mnemonic = "FinalIosCarrierLibrary") + return [DefaultInfo(files = depset([output]))] + +_archive = rule(implementation = _archive_impl, toolchains = BUN_SOURCE_TOOLCHAINS, attrs = { + "leaf": attr.label(mandatory = True, providers = [ExtensionFinalLeafInfo], cfg = "exec"), + "base": attr.label(mandatory = True, providers = [NativeAppleBaseInfo]), + "sql_name": attr.string(mandatory = True), "identity": attr.string(mandatory = True), + "kind": attr.string(mandatory = True, values = ["ios-xcframework", "ios-dependency-xcframework"]), + "slice": attr.string(mandatory = True), + "_runner": attr.label(default = Label("//build_defs/apple:final-libraries.mts"), allow_single_file = True), + "_helpers": attr.label_list(default = native_owner_carrier_helpers() + [Label("//build_defs/native/apple:static-carrier-consumer.mts"), Label("//build_defs/native/apple:framework_helpers"), Label("//src/native/sdks/swift:generator_sources")], allow_files = True), +}) + +def expo_ios_final_libraries(name, extensions, base): + native.config_setting(name = name + "_simulator", constraint_values = ["@apple_support//constraints:simulator"]) + slice = select({":" + name + "_simulator": "ios-arm64-simulator", "//conditions:default": "ios-arm64"}) + rows = {row["sqlName"]: row for row in EXTENSION_RELEASE_METADATA if row["sqlName"] in extensions} + leaves = {} + for product in sorted({row["artifactProduct"]: True for row in rows.values()}): + imported = name + "_" + product.replace("-", "_") + "_original" + native_extension_declared_final_import(name = imported, product = product, family = "native", target = "ios-xcframework") + leaves[product] = ":" + imported + descriptors = {row["sql-name"]: row for row in EXTENSIONS.values()} + units = {} + for sql_name in extensions: + row = rows[sql_name] + leaf = leaves[row["artifactProduct"]] + # The canonical final manifest owns each extension/dependency role. + module = descriptors[sql_name].get("native-module-file") + if not module: + continue + stem = module[:-3] + units["extension_" + stem] = (leaf, sql_name, "ios-xcframework", stem) + for identity in NATIVE_MOBILE_COMPONENT_CLOSURES[sql_name]["ios-xcframework"]["linkUnits"]: + units["dependency_" + identity] = (leaf, sql_name, "ios-dependency-xcframework", identity) + imports = [] + for unit, (leaf, sql_name, kind, identity) in sorted(units.items()): + archive = name + "_" + unit.replace("-", "_") + _archive(name = archive + "_archive", leaf = leaf, base = base, sql_name = sql_name, kind = kind, identity = identity, slice = slice) + cc_import(name = archive, static_library = ":" + archive + "_archive", alwayslink = True) + imports.append(":" + archive) + cc_library(name = name, deps = imports) + return leaves.values() diff --git a/build_defs/apple/final-libraries.mts b/build_defs/apple/final-libraries.mts new file mode 100644 index 000000000..aa38fde8c --- /dev/null +++ b/build_defs/apple/final-libraries.mts @@ -0,0 +1,49 @@ +/** Link the actual final carrier's static library bytes, not a source recipe. */ +import assert from 'node:assert/strict'; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { readPortableArchiveEntries } from '../../tools/packaging/portable-archive.mts'; +import { stageAppleStaticLeaf } from '../native/apple/static-carrier-consumer.mts'; + +export function finalIosLibraryBytes(archive: string, bundle: string, slice: string) { + assert(['ios-arm64', 'ios-arm64-simulator'].includes(slice), 'Unexpected app library slice'); + assert(/^[A-Za-z_][A-Za-z0-9_.-]*$/u.test(bundle), 'Unsafe final framework identity'); + const member = `${bundle}.xcframework/${slice}/${bundle}.framework/${bundle}`; + const entry = readPortableArchiveEntries(archive, { format: 'zip' }).get(member); + assert( + entry?.isFile && !entry.isSymbolicLink, + `Final XCFramework lacks exact app slice ${member}`, + ); + const bytes = entry.data(); + assert( + bytes.subarray(0, 8).equals(Buffer.from('!\n')), + 'Final framework binary must be its actual static ar library', + ); + return bytes; +} + +export function extractFinalIosLibrary(spec: any) { + const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-final-app-library-')); + try { + const staged = stageAppleStaticLeaf(spec.leaf, root, spec.runtimeVersion); + const frozen = JSON.parse(readFileSync(staged.output, 'utf8')); + const members = frozen.extensions ?? [frozen]; + const member = members.find((row: any) => row.sqlName === spec.sqlName); + assert(member, 'Selected app library is absent from its actual final carrier'); + const assets = member.assets.filter( + (row: any) => row.kind === spec.kind && row.identity === spec.identity, + ); + assert.equal( + assets.length, + 1, + 'Actual final carrier must declare the selected framework role once', + ); + const bundle = `liboliphaunt_${spec.kind === 'ios-xcframework' ? 'extension' : 'dependency'}_${spec.identity}`; + writeFileSync(spec.output, finalIosLibraryBytes(assets[0].path, bundle, spec.slice)); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +if (import.meta.main) extractFinalIosLibrary(JSON.parse(readFileSync(process.argv[2], 'utf8'))); diff --git a/build_defs/apple/final-libraries.test.mts b/build_defs/apple/final-libraries.test.mts new file mode 100644 index 000000000..b15e962e9 --- /dev/null +++ b/build_defs/apple/final-libraries.test.mts @@ -0,0 +1,40 @@ +import { expect, test } from 'bun:test'; +import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { zipArchive } from '../../tools/packaging/testdata/zip-fixture.mts'; +import { finalIosLibraryBytes } from './final-libraries.mts'; + +test('app link input is the exact selected final device/simulator library and refuses substitutions', async () => { + const root = mkdtempSync(path.join(tmpdir(), 'final-ios-link-fixture-')); + try { + const bundle = 'liboliphaunt_extension_vector'; + const archive = path.join(root, 'final.xcframework.zip'); + const rows = ['ios-arm64', 'ios-arm64-simulator'].map((slice) => ({ + name: `${bundle}.xcframework/${slice}/${bundle}.framework/${bundle}`, + data: Buffer.from(`!\n${slice}-original-binary`), + })); + writeFileSync(archive, zipArchive(rows)); + for (const row of rows) + expect( + finalIosLibraryBytes( + archive, + bundle, + row.name.includes('simulator') ? 'ios-arm64-simulator' : 'ios-arm64', + ), + ).toEqual(row.data); + expect(() => finalIosLibraryBytes(archive, bundle, 'macos-arm64')).toThrow(); + expect(() => finalIosLibraryBytes(archive, 'another_framework', 'ios-arm64')).toThrow(); + expect(() => finalIosLibraryBytes(archive, '../vector', 'ios-arm64')).toThrow(); + writeFileSync( + archive, + zipArchive([{ ...rows[0], data: Buffer.from('dynamic/stub substitute') }]), + ); + expect(() => finalIosLibraryBytes(archive, bundle, 'ios-arm64')).toThrow(/static ar/); + expect(() => finalIosLibraryBytes(archive, bundle, 'ios-arm64-simulator')).toThrow( + /lacks exact/, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/build_defs/apple/framework-info.plist b/build_defs/apple/framework-info.plist new file mode 100644 index 000000000..35affe28b --- /dev/null +++ b/build_defs/apple/framework-info.plist @@ -0,0 +1,3 @@ + + +CFBundlePackageTypeFMWK diff --git a/build_defs/apple/generated-files.bzl b/build_defs/apple/generated-files.bzl new file mode 100644 index 000000000..731b31411 --- /dev/null +++ b/build_defs/apple/generated-files.bzl @@ -0,0 +1,49 @@ +IOS_GENERATED_FILES = [ + "codegen/ReactAppDependencyProvider/RCTAppDependencyProvider.h", + "codegen/ReactAppDependencyProvider/RCTAppDependencyProvider.mm", + "codegen/ReactCodegen/OliphauntReactNativeSpec/OliphauntReactNativeSpec-generated.mm", + "codegen/ReactCodegen/OliphauntReactNativeSpec/OliphauntReactNativeSpec.h", + "codegen/ReactCodegen/OliphauntReactNativeSpecJSI.h", + "codegen/ReactCodegen/RCTModuleProviders.h", + "codegen/ReactCodegen/RCTModuleProviders.mm", + "codegen/ReactCodegen/RCTModulesConformingToProtocolsProvider.h", + "codegen/ReactCodegen/RCTModulesConformingToProtocolsProvider.mm", + "codegen/ReactCodegen/RCTThirdPartyComponentsProvider.h", + "codegen/ReactCodegen/RCTThirdPartyComponentsProvider.mm", + "codegen/ReactCodegen/RCTUnstableModulesRequiringMainQueueSetupProvider.h", + "codegen/ReactCodegen/RCTUnstableModulesRequiringMainQueueSetupProvider.mm", + "codegen/ReactCodegen/react/renderer/components/safeareacontext/ComponentDescriptors.cpp", + "codegen/ReactCodegen/react/renderer/components/safeareacontext/ComponentDescriptors.h", + "codegen/ReactCodegen/react/renderer/components/safeareacontext/EventEmitters.cpp", + "codegen/ReactCodegen/react/renderer/components/safeareacontext/EventEmitters.h", + "codegen/ReactCodegen/react/renderer/components/safeareacontext/Props.cpp", + "codegen/ReactCodegen/react/renderer/components/safeareacontext/Props.h", + "codegen/ReactCodegen/react/renderer/components/safeareacontext/RCTComponentViewHelpers.h", + "codegen/ReactCodegen/react/renderer/components/safeareacontext/ShadowNodes.cpp", + "codegen/ReactCodegen/react/renderer/components/safeareacontext/ShadowNodes.h", + "codegen/ReactCodegen/react/renderer/components/safeareacontext/States.cpp", + "codegen/ReactCodegen/react/renderer/components/safeareacontext/States.h", + "codegen/ReactCodegen/safeareacontext/safeareacontext-generated.mm", + "codegen/ReactCodegen/safeareacontext/safeareacontext.h", + "codegen/ReactCodegen/safeareacontextJSI.h", + "app/AppDelegate.swift", + "app/Images.xcassets/AppIcon.appiconset/Contents.json", + "app/Images.xcassets/Contents.json", + "app/Images.xcassets/SplashScreenBackground.colorset/Contents.json", + "app/Info.plist", + "app/SplashScreen.storyboard", + "app/Supporting/Expo.plist", + "app/expo.icon/Assets/expo-symbol 2.svg", + "app/expo.icon/Assets/grid.png", + "app/expo.icon/icon.json", + "app/reactnativeoliphauntexpo-Bridging-Header.h", + "app/reactnativeoliphauntexpo.entitlements", + "ExpoModulesProvider.swift", + "sdk/package.json", + "sdk/ios/OliphauntAdapter.swift", + "sdk/ios/Oliphaunt.mm", + "sdk/ios/OliphauntAdapter.h", + "sdk/ios/OliphauntReactNative.h", + "sdk/cpp/Jsi.h", + "sdk/cpp/Lifecycle.h" +] diff --git a/build_defs/apple/installed-app.bzl b/build_defs/apple/installed-app.bzl new file mode 100644 index 000000000..9705444c4 --- /dev/null +++ b/build_defs/apple/installed-app.bzl @@ -0,0 +1,91 @@ +"""Actual local simulator test over a stock application and genuine candidate checkout.""" +load("@rules_apple//apple:providers.bzl", "AppleBundleInfo") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/foundation:bun-sources.bzl", "bun_source_tree", "bun_source_runfile") + +_NODE = "@rules_nodejs//nodejs:toolchain_type" +InstalledAppleToolsInfo = provider(fields = ["node", "receipt", "files", "specification", "runner", "sources"]) + +def _simulator_transition(_settings, _attr): + return {"//command_line_option:platforms": ["//build_defs/host:ios_simulator_arm64"]} + +_SIMULATOR = transition(implementation = _simulator_transition, inputs = [], outputs = ["//command_line_option:platforms"]) + +def _tools_impl(ctx): + node = ctx.toolchains[_NODE].nodeinfo.node + tools, helper_rows, files = {}, [], [] + for file in ctx.files.apple_tools + [ctx.file.plutil]: + if file.basename in ["xcrun", "plutil"]: + tools[file.basename] = len(files) + files.append(file) + for file in ctx.files.helpers: + helper_rows.append({"relative": file.short_path, "index": len(files)}) + files.append(file) + if sorted(tools.keys()) != ["plutil", "xcrun"]: + fail("Installed simulator proof requires the actual declared Xcode xcrun/plutil Files") + tool_spec = {"helpers": helper_rows, "tools": tools} + sources = [ctx.file._runner, ctx.file._archive_parser] + runner_sources = bun_source_tree(ctx, ctx.label.name + ".installed-sources", sources) + descriptor = ctx.actions.declare_file(ctx.label.name + ".tools.json") + ctx.actions.write(descriptor, json.encode({ + "schema": "oliphaunt-installed-mobile-tools-v1", "platform": "ios", "toolSpec": tool_spec, + "runnerRunfile": bun_source_runfile(ctx, runner_sources, ctx.file._runner), "fileCount": len(files), + }) + "\n") + return bun_test_entrypoint(ctx, ctx.file._manifest_runner, + arguments = [descriptor, node, ctx.file.receipt] + files, files = [descriptor, node, ctx.file.receipt] + files, + source_files = [], runfiles_argument = True, + additional_runfiles = ctx.runfiles(transitive_files = runner_sources.files)) + [InstalledAppleToolsInfo( + node = node, receipt = ctx.file.receipt, files = files, specification = tool_spec, + runner = ctx.file._runner, sources = sources)] + +def _installed_impl(ctx): + # A function transition can return a one-element configured target list. + app = ctx.attr.application[0] if type(ctx.attr.application) == "list" else ctx.attr.application + archive = app[AppleBundleInfo].archive + tools = ctx.attr.tools[InstalledAppleToolsInfo] + specification = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(specification, json.encode(dict(tools.specification, **{ + "extensions": ctx.attr.extensions, + "replay": {"schema": "oliphaunt-installed-mobile-replay-v1", "platform": "ios", + "files": {"application": archive.path, "sdk": ctx.file.sdk.path}}, + })) + "\n") + arguments = [specification, archive, ctx.file.sdk, tools.node, tools.receipt] + tools.files + return bun_test_entrypoint(ctx, tools.runner, arguments = arguments, files = arguments, + source_files = tools.sources) + [ + OutputGroupInfo(observation_inputs = depset([specification, archive, ctx.file.sdk])), + RunEnvironmentInfo(inherited_environment = [ + "OLIPHAUNT_MOBILE_CANDIDATE_CHECKOUT", "OLIPHAUNT_MOBILE_CANDIDATE_SHA", "OLIPHAUNT_MOBILE_CANDIDATE_TREE", + ]), + ] + +_installed_tools = rule(implementation = _tools_impl, executable = True, + toolchains = BUN_SOURCE_TOOLCHAINS + [_NODE], attrs = BUN_TEST_ENTRYPOINT_ATTRS | { + "helpers": attr.label_list(mandatory = True, allow_files = True), + "apple_tools": attr.label(default = Label("@native_apple_sdk//:app_tools")), + "receipt": attr.label(default = Label("@native_apple_sdk//:receipt.json"), allow_single_file = [".json"]), + "plutil": attr.label(default = Label("@native_apple_sdk//:tools/plutil"), allow_single_file = True), + "_manifest_runner": attr.label(default = Label("//build_defs/apple:installed-tools.mts"), allow_single_file = True), + "_runner": attr.label(default = Label("//build_defs/apple:installed-app.mts"), allow_single_file = True), + "_archive_parser": attr.label(default = Label("//:tools/packaging/portable-archive.mts"), allow_single_file = True), + }) + +_installed_test = rule(implementation = _installed_impl, test = True, + toolchains = BUN_SOURCE_TOOLCHAINS, attrs = BUN_TEST_ENTRYPOINT_ATTRS | { + "tools": attr.label(mandatory = True, providers = [InstalledAppleToolsInfo]), + "application": attr.label(mandatory = True, providers = [AppleBundleInfo], cfg = _SIMULATOR), + "sdk": attr.label(mandatory = True, allow_single_file = [".tgz"]), + "extensions": attr.string_list(mandatory = True), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), + }) + +def expo_ios_installed_test(name, helpers, **kwargs): + compatible = ["@platforms//os:macos", "@platforms//cpu:aarch64"] + tool_attrs = {} + for key in ["apple_tools", "receipt", "plutil"]: + if key in kwargs: + tool_attrs[key] = kwargs.pop(key) + _installed_tools(name = name + "_tools", helpers = helpers, args = bun_test_entrypoint_args(name + "_tools"), + target_compatible_with = compatible, **tool_attrs) + _installed_test(name = name, tools = ":" + name + "_tools", args = bun_test_entrypoint_args(name), + tags = ["local", "exclusive", "no-remote", "external"], + target_compatible_with = compatible, size = "large", timeout = "long", **kwargs) diff --git a/build_defs/apple/installed-app.mts b/build_defs/apple/installed-app.mts new file mode 100644 index 000000000..84e731dfc --- /dev/null +++ b/build_defs/apple/installed-app.mts @@ -0,0 +1,261 @@ +/** Run the existing installed Expo smoke on a real source checkout and stock app archive. */ +import assert from 'node:assert/strict'; +import { createHash, randomUUID } from 'node:crypto'; +import { + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + realpathSync, + rmSync, + symlinkSync, +} from 'node:fs'; +import path from 'node:path'; +import { extractPortableArchiveTree } from '../../tools/packaging/portable-archive.mts'; + +type Helper = { relative: string; file: string }; +function command(binary: string, args: string[], cwd: string, env = process.env) { + const result = Bun.spawnSync([binary, ...args], { cwd, env, stdout: 'pipe', stderr: 'pipe' }); + assert.equal( + result.exitCode, + 0, + `${path.basename(binary)} ${args.join(' ')}:\n${result.stdout}\n${result.stderr}`, + ); + return result.stdout.toString().trim(); +} +const digest = (file: string) => createHash('sha256').update(readFileSync(file)).digest('hex'); +export function extractInstalledAppArchive(archive: string, output: string) { + extractPortableArchiveTree(realpathSync(archive), output, '', { format: 'zip' }); + const roots = [output, path.join(output, 'Payload')]; + const apps = roots.flatMap((root) => { + try { + return readdirSync(root, { withFileTypes: true }) + .filter((entry) => entry.isDirectory() && entry.name.endsWith('.app')) + .map((entry) => path.join(root, entry.name)); + } catch { + return []; + } + }); + assert.equal( + apps.length, + 1, + 'Stock application archive must contain exactly one actual app bundle', + ); + return apps[0]; +} +export function assertCandidateCheckout( + root: string, + sha: string, + tree: string, + helpers: Helper[], + git = '/usr/bin/git', +) { + assert( + path.isAbsolute(root), + 'Installed app test requires an explicit actual candidate checkout', + ); + for (const value of [sha, tree]) + assert.match(value, /^[0-9a-f]{40}$/u, 'Installed app test requires exact candidate SHA/tree'); + assert.equal( + realpathSync(command(git, ['rev-parse', '--show-toplevel'], root)), + realpathSync(root), + 'Candidate path must be the real checkout root', + ); + assert.equal( + command(git, ['rev-parse', 'HEAD'], root), + sha, + 'Installed app checkout commit differs', + ); + assert.equal( + command(git, ['rev-parse', 'HEAD^{tree}'], root), + tree, + 'Installed app checkout tree differs', + ); + assert.equal( + command(git, ['status', '--porcelain', '--untracked-files=no'], root), + '', + 'Installed app candidate checkout has tracked modifications', + ); + for (const helper of helpers) { + assert( + helper.relative && + !path.isAbsolute(helper.relative) && + !helper.relative.split('/').includes('..'), + 'Unsafe declared mobile helper path', + ); + assert.equal( + digest(path.join(root, helper.relative)), + digest(helper.file), + 'Actual candidate helper differs from its declared File: ' + helper.relative, + ); + } +} + +export function simulatorTemplate(value: any) { + assert(value && typeof value.devices === 'object', 'simctl must return actual device inventory'); + const choices = Object.entries(value.devices) + .filter(([runtime]) => runtime.startsWith('com.apple.CoreSimulator.SimRuntime.iOS-')) + .flatMap(([runtime, devices]) => + (devices as any[]) + .filter( + (device) => + device.isAvailable === true && + typeof device.deviceTypeIdentifier === 'string' && + device.deviceTypeIdentifier.startsWith('com.apple.CoreSimulator.SimDeviceType.iPhone-'), + ) + .map((device) => ({ runtime, type: device.deviceTypeIdentifier })), + ); + choices.sort( + (left, right) => + right.runtime.localeCompare(left.runtime, 'en', { numeric: true }) || + left.type.localeCompare(right.type), + ); + assert( + choices.length, + 'Selected Xcode must have an available real iPhone simulator runtime/device type', + ); + return choices[0]; +} + +/** The same captured launch must finish background/resume SQL before its PASS. */ +export function assertLifecycleReceipt(log: string) { + const stages = [ + /OLIPHAUNT_EXPO_SMOKE_STAGE.*"stage":"lifecycle:ready"/u, + /OLIPHAUNT_EXPO_SMOKE_STAGE.*"stage":"lifecycle:state".*"state":"background"/u, + /OLIPHAUNT_EXPO_SMOKE_STAGE.*"stage":"lifecycle:state".*"state":"active"/u, + /OLIPHAUNT_EXPO_SMOKE_STAGE.*"stage":"lifecycle:sql:done"/u, + /OLIPHAUNT_EXPO_SMOKE_PASS/u, + ]; + let next = 0; + for (const line of log.split('\n')) { + if (stages[next]?.test(line)) next++; + } + assert.equal( + next, + stages.length, + 'Installed smoke omitted ordered background/resume SQL before PASS', + ); +} + +async function installedApp(args: string[]) { + assert.equal(process.platform, 'darwin', 'Actual iOS installed test requires the Mac host'); + const [specFile, archive, sdk, node, receiptFile, ...files] = args; + const spec = JSON.parse(readFileSync(specFile, 'utf8')); + const receipt = JSON.parse(readFileSync(receiptFile, 'utf8')); + const helpers = spec.helpers.map((helper: any) => ({ + relative: helper.relative, + file: files[helper.index], + })); + const checkout = process.env.OLIPHAUNT_MOBILE_CANDIDATE_CHECKOUT ?? ''; + const sha = process.env.OLIPHAUNT_MOBILE_CANDIDATE_SHA ?? ''; + const tree = process.env.OLIPHAUNT_MOBILE_CANDIDATE_TREE ?? ''; + assertCandidateCheckout(checkout, sha, tree, helpers); + assert( + receipt.developerDirectory && path.isAbsolute(receipt.developerDirectory), + 'Declared Apple SDK must retain its selected Developer directory', + ); + const scratch = mkdtempSync( + path.join(process.env.TEST_TMPDIR ?? '/tmp', 'oliphaunt-ios-installed-'), + ); + const output = process.env.TEST_UNDECLARED_OUTPUTS_DIR ?? path.join(scratch, 'evidence'); + const env: NodeJS.ProcessEnv = { ...process.env, DEVELOPER_DIR: receipt.developerDirectory }; + for (const name of Object.keys(env)) + if (/^(?:OLIPHAUNT_|EXPO_PUBLIC_|NODE_|BUN_|DYLD_)/u.test(name)) delete env[name]; + const bin = path.join(scratch, 'bin'); + mkdirSync(bin); + symlinkSync(node, path.join(bin, 'node')); + symlinkSync(process.execPath, path.join(bin, 'bun')); + for (const [name, index] of Object.entries(spec.tools)) + symlinkSync(files[index as number], path.join(bin, name)); + env.PATH = bin + ':/usr/bin:/bin:/usr/sbin:/sbin'; + env.TMPDIR = scratch; + const xcrun = path.join(bin, 'xcrun'); + const simctl = receipt.components.find((component: any) => component.name === 'tools/simctl'); + assert(simctl, 'Selected Apple capture must declare its actual simulator tool'); + const selectedSimctl = command(xcrun, ['--find', 'simctl'], checkout, env); + assert.equal( + realpathSync(selectedSimctl), + simctl.resolvedPath, + 'Installed smoke must execute the captured selected Xcode simulator tool', + ); + assert.equal( + digest(selectedSimctl), + receipt.observations.simctl_sha256, + 'Selected simulator tool bytes changed after capture', + ); + let simulator = ''; + try { + const template = simulatorTemplate( + JSON.parse(command(xcrun, ['simctl', 'list', 'devices', 'available', '-j'], checkout, env)), + ); + simulator = command( + xcrun, + ['simctl', 'create', 'Oliphaunt-Bazel-' + randomUUID(), template.type, template.runtime], + checkout, + env, + ); + assert.match( + simulator, + /^[0-9A-Fa-f-]{36}$/u, + 'simctl create must return the actual owned simulator', + ); + console.log(`Installed iOS simulator ${simulator}: ${template.type} (${template.runtime})`); + const extracted = path.join(scratch, 'app'); + const app = extractInstalledAppArchive(archive, extracted); + const pack = path.join(scratch, 'pack'); + mkdirSync(pack); + // Original metrics uses the SDK's actual package name/version to find this + // genuine archive. Preserve its bytes and conventional manifest unchanged. + const packageManifest = JSON.parse( + readFileSync(path.join(checkout, 'src/native/sdks/react-native/package.json'), 'utf8'), + ); + symlinkSync( + sdk, + path.join( + pack, + packageManifest.name.replace(/^@/u, '').replace('/', '-') + + '-' + + packageManifest.version + + '.tgz', + ), + ); + Object.assign(env, { + OLIPHAUNT_EXPO_IOS_APP: app, + OLIPHAUNT_EXPO_IOS_CONFIGURATION: 'Release', + OLIPHAUNT_EXPO_IOS_SDK: 'iphonesimulator', + OLIPHAUNT_EXPO_IOS_RUNNER: 'smoke', + OLIPHAUNT_EXPO_IOS_EXTENSIONS: spec.extensions.join(','), + OLIPHAUNT_EXPO_IOS_SIMULATOR_UDID: simulator, + OLIPHAUNT_EXPO_IOS_LIFECYCLE_SMOKE: '1', + OLIPHAUNT_EXPO_IOS_CLEAN_INSTALL: '1', + OLIPHAUNT_EXPO_IOS_SCRATCH: output, + OLIPHAUNT_EXPO_IOS_PACK_DIR: pack, + OLIPHAUNT_MOBILE_E2E_CANDIDATE_SHA: sha, + }); + const child = Bun.spawn( + ['/bin/bash', path.join(checkout, 'src/native/sdks/react-native/tools/mobile-e2e.sh'), 'ios'], + { cwd: checkout, env, stdout: 'inherit', stderr: 'inherit' }, + ); + assert.equal( + await child.exited, + 0, + 'Original actual installed app lifecycle/SQL/receipt qualification failed', + ); + assertLifecycleReceipt( + readFileSync(path.join(output, 'logs/smoke-simulator-unified.log'), 'utf8'), + ); + assertCandidateCheckout(checkout, sha, tree, helpers); + } finally { + if (simulator) { + Bun.spawnSync([xcrun, 'simctl', 'shutdown', simulator], { + cwd: checkout, + env, + stdout: 'ignore', + stderr: 'inherit', + }); + command(xcrun, ['simctl', 'delete', simulator], checkout, env); + } + rmSync(scratch, { recursive: true, force: true }); + } +} +if (import.meta.main) await installedApp(process.argv.slice(2)); diff --git a/build_defs/apple/installed-app.test.mts b/build_defs/apple/installed-app.test.mts new file mode 100644 index 000000000..9d4dd15ac --- /dev/null +++ b/build_defs/apple/installed-app.test.mts @@ -0,0 +1,148 @@ +import { afterEach, describe, expect, test } from 'bun:test'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { createDeterministicZip } from '../../tools/packaging/archive-directory.mts'; +import { + assertCandidateCheckout, + extractInstalledAppArchive, + simulatorTemplate, +} from './installed-app.mts'; + +const roots: string[] = []; +afterEach(() => { + for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); +}); +function fixture() { + const root = mkdtempSync(path.join(os.tmpdir(), 'ios-real-checkout-')); + roots.push(root); + const git = (...args: string[]) => { + const result = Bun.spawnSync(['/usr/bin/git', ...args], { + cwd: root, + stdout: 'pipe', + stderr: 'pipe', + }); + if (result.exitCode) throw new Error(result.stderr.toString()); + return result.stdout.toString().trim(); + }; + git('init', '-q'); + writeFileSync(path.join(root, 'runner.sh'), '# original candidate helper\n'); + git('add', 'runner.sh'); + git( + '-c', + 'user.name=Fixture', + '-c', + 'user.email=fixture@example.invalid', + 'commit', + '-qm', + 'fixture', + ); + const declared = path.join(root, 'declared.sh'); + writeFileSync(declared, readFileSync(path.join(root, 'runner.sh'))); + return { + root, + sha: git('rev-parse', 'HEAD'), + tree: git('rev-parse', 'HEAD^{tree}'), + helpers: [{ relative: 'runner.sh', file: declared }], + }; +} +describe('actual installed app qualification boundary', () => { + test('extracts a stock app archive through its declared runfiles File alias', async () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'installed-app-alias-')); + roots.push(root); + const bundle = path.join(root, 'bundle/Payload/Smoke.app'); + mkdirSync(bundle, { recursive: true }); + writeFileSync(path.join(bundle, 'Smoke'), 'fixture executable'); + const archive = path.join(root, 'archive-output'); + writeFileSync(archive, await createDeterministicZip(path.join(root, 'bundle'))); + const alias = path.join(root, 'runfiles-app.ipa'); + symlinkSync(archive, alias); + const output = path.join(root, 'extracted'); + const app = extractInstalledAppArchive(alias, output); + expect(app).toBe(path.join(output, 'Payload/Smoke.app')); + expect(readFileSync(path.join(app, 'Smoke'), 'utf8')).toBe('fixture executable'); + }); + test('accepts the real clean candidate and identical declared helper Files', () => { + const f = fixture(); + assertCandidateCheckout(f.root, f.sha, f.tree, f.helpers); + }); + test('rejects a different commit and a different source tree', () => { + const f = fixture(); + expect(() => assertCandidateCheckout(f.root, '0'.repeat(40), f.tree, f.helpers)).toThrow( + /commit differs/, + ); + expect(() => assertCandidateCheckout(f.root, f.sha, '0'.repeat(40), f.helpers)).toThrow( + /tree differs/, + ); + }); + test('does not accept a package subdirectory as candidate root', () => { + const f = fixture(); + const child = path.join(f.root, 'subdirectory'); + mkdirSync(child); + expect(() => assertCandidateCheckout(child, f.sha, f.tree, f.helpers)).toThrow( + /real checkout root/, + ); + }); + test('detects source modifications after the initial guard', () => { + const f = fixture(); + assertCandidateCheckout(f.root, f.sha, f.tree, f.helpers); + writeFileSync(path.join(f.root, 'runner.sh'), '# changed during smoke\n'); + expect(() => assertCandidateCheckout(f.root, f.sha, f.tree, f.helpers)).toThrow( + /tracked modifications/, + ); + }); + test('rejects a declared helper from a different candidate even when checkout is clean', () => { + const f = fixture(); + writeFileSync(f.helpers[0].file, '# different compiler input\n'); + expect(() => assertCandidateCheckout(f.root, f.sha, f.tree, f.helpers)).toThrow( + /declared File/, + ); + }); + test('uses an available iPhone on the newest eligible runtime and excludes iPads', () => { + const phone = 'com.apple.CoreSimulator.SimDeviceType.iPhone-16'; + const phonePro = 'com.apple.CoreSimulator.SimDeviceType.iPhone-16-Pro'; + const ipad = 'com.apple.CoreSimulator.SimDeviceType.iPad-Pro-11-inch-M4-8GB'; + const rows = { + 'com.apple.CoreSimulator.SimRuntime.visionOS-99-0': [ + { isAvailable: true, deviceTypeIdentifier: phone }, + ], + 'com.apple.CoreSimulator.SimRuntime.iOS-26-3': [ + { isAvailable: true, deviceTypeIdentifier: phone }, + ], + 'com.apple.CoreSimulator.SimRuntime.iOS-26-6': [ + { isAvailable: true, deviceTypeIdentifier: ipad }, + ], + 'com.apple.CoreSimulator.SimRuntime.iOS-26-5': [ + { isAvailable: false, deviceTypeIdentifier: phone }, + ], + 'com.apple.CoreSimulator.SimRuntime.iOS-26-4': [ + { isAvailable: true, deviceTypeIdentifier: ipad }, + { isAvailable: true, deviceTypeIdentifier: phonePro }, + { isAvailable: true, deviceTypeIdentifier: phone }, + ], + }; + expect(simulatorTemplate({ devices: rows })).toEqual({ + runtime: 'com.apple.CoreSimulator.SimRuntime.iOS-26-4', + type: phone, + }); + expect( + simulatorTemplate({ + devices: Object.fromEntries( + Object.entries(rows) + .reverse() + .map(([runtime, devices]) => [runtime, [...devices].reverse()]), + ), + }), + ).toEqual(simulatorTemplate({ devices: rows })); + expect(() => simulatorTemplate({ devices: {} })).toThrow(/available real iPhone/); + expect(() => + simulatorTemplate({ + devices: { + 'com.apple.CoreSimulator.SimRuntime.iOS-26-6': [ + { isAvailable: true, deviceTypeIdentifier: ipad }, + ], + }, + }), + ).toThrow(/available real iPhone/); + }); +}); diff --git a/build_defs/apple/installed-tools.mts b/build_defs/apple/installed-tools.mts new file mode 100644 index 000000000..a2ff0068f --- /dev/null +++ b/build_defs/apple/installed-tools.mts @@ -0,0 +1,99 @@ +/** Resolve only the actual declared installed-test tools; never construct an application. */ +import assert from 'node:assert/strict'; +import { lstatSync, readFileSync, realpathSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; + +function regularFile(value: string) { + assert(path.isAbsolute(value), 'Installed replay tools require absolute declared Files'); + const file = realpathSync(value); + assert(lstatSync(file).isFile(), 'Installed replay tools require regular declared Files'); + return file; +} + +export function installedToolManifest(args: string[], bun = process.execPath) { + const descriptor = JSON.parse(readFileSync(regularFile(args[0]), 'utf8')); + assert.deepEqual( + Object.keys(descriptor).sort(), + ['schema', 'platform', 'toolSpec', 'runnerRunfile', 'fileCount'].sort(), + ); + assert.equal(descriptor.schema, 'oliphaunt-installed-mobile-tools-v1'); + assert(['android', 'ios'].includes(descriptor.platform)); + assert(Number.isSafeInteger(descriptor.fileCount) && descriptor.fileCount > 0); + const prefix = descriptor.platform === 'android' ? 4 : 3; + assert.equal( + args.length, + prefix + descriptor.fileCount + 3, + 'Installed replay tools require only their declared Files and --output destination', + ); + const root = args[prefix + descriptor.fileCount]; + assert(path.isAbsolute(root)); + const relative = descriptor.runnerRunfile; + assert( + typeof relative === 'string' && + relative.length > 0 && + !path.isAbsolute(relative) && + !relative.includes('\\') && + relative.split('/').every((part) => part && part !== '.' && part !== '..'), + ); + const files = args.slice(prefix, prefix + descriptor.fileCount).map(regularFile); + const toolSpec = descriptor.toolSpec; + assert(toolSpec && typeof toolSpec === 'object' && !Array.isArray(toolSpec)); + assert.deepEqual( + Object.keys(toolSpec).sort(), + (descriptor.platform === 'android' + ? ['helpers', 'sdkFiles', 'java'] + : ['helpers', 'tools'] + ).sort(), + ); + const index = (value: unknown) => + assert(Number.isSafeInteger(value) && Number(value) >= 0 && Number(value) < files.length); + for (const key of ['helpers', ...(descriptor.platform === 'android' ? ['sdkFiles'] : [])]) { + assert(Array.isArray(toolSpec[key])); + const names = new Set(); + for (const row of toolSpec[key]) { + assert.deepEqual(Object.keys(row).sort(), ['index', 'relative']); + assert( + typeof row.relative === 'string' && + row.relative.length > 0 && + !path.isAbsolute(row.relative) && + !row.relative.includes('\\') && + row.relative.split('/').every((part: string) => part && part !== '.' && part !== '..'), + ); + assert(!names.has(row.relative)); + names.add(row.relative); + index(row.index); + } + } + if (descriptor.platform === 'android') index(toolSpec.java); + else { + assert(toolSpec.tools && typeof toolSpec.tools === 'object' && !Array.isArray(toolSpec.tools)); + assert.deepEqual(Object.keys(toolSpec.tools).sort(), ['plutil', 'xcrun']); + Object.values(toolSpec.tools).forEach(index); + } + assert.equal(args.at(-2), '--output'); + const output = args[args.length - 1]; + assert( + path.isAbsolute(output), + 'Installed replay tools require an absolute --output destination', + ); + return { + output, + manifest: { + schema: descriptor.schema, + platform: descriptor.platform, + toolSpec, + files, + bun: regularFile(bun), + node: regularFile(args[1]), + runner: regularFile(path.join(root, relative)), + ...(descriptor.platform === 'android' + ? { emulatorMetadata: regularFile(args[2]), adb: regularFile(args[3]) } + : { receipt: regularFile(args[2]) }), + }, + }; +} + +if (import.meta.main) { + const { output, manifest } = installedToolManifest(process.argv.slice(2)); + writeFileSync(output, `${JSON.stringify(manifest)}\n`, { flag: 'wx', mode: 0o600 }); +} diff --git a/build_defs/apple/installed-tools.test.mts b/build_defs/apple/installed-tools.test.mts new file mode 100644 index 000000000..8124f62c1 --- /dev/null +++ b/build_defs/apple/installed-tools.test.mts @@ -0,0 +1,153 @@ +import { expect, test } from 'bun:test'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { installedToolManifest } from './installed-tools.mts'; + +function fixture(platform: 'android' | 'ios') { + const root = mkdtempSync(path.join(tmpdir(), 'installed-tools-')); + const runner = path.join(root, 'sources/build_defs/installed-app.mts'); + mkdirSync(path.dirname(runner), { recursive: true }); + writeFileSync(runner, '// declared regular module\n'); + const files = [0, 1, 2].map((index) => { + const file = path.join(root, `declared-${index}`); + writeFileSync(file, 'declared tool/helper bytes'); + return file; + }); + const descriptor = { + schema: 'oliphaunt-installed-mobile-tools-v1', + platform, + toolSpec: + platform === 'android' + ? { + helpers: [{ relative: 'src/helper.mts', index: 0 }], + sdkFiles: [{ relative: 'platform-tools/adb', index: 1 }], + java: 2, + } + : { helpers: [{ relative: 'src/helper.mts', index: 2 }], tools: { plutil: 0, xcrun: 1 } }, + runnerRunfile: 'sources/build_defs/installed-app.mts', + fileCount: files.length, + }; + const input = path.join(root, 'descriptor.json'); + const output = path.join(root, 'manifest.json'); + const rewrite = () => writeFileSync(input, JSON.stringify(descriptor)); + rewrite(); + const args = [ + input, + process.execPath, + files[0], + ...(platform === 'android' ? [files[1]] : []), + ...files, + root, + '--output', + output, + ]; + return { + root, + runner, + files, + descriptor, + output, + args, + rewrite, + cleanup: () => rmSync(root, { recursive: true, force: true }), + }; +} + +for (const platform of ['android', 'ios'] as const) { + test(`${platform} tools manifest keeps actual provider indices and regular declared runtime paths`, () => { + const f = fixture(platform); + try { + const { output, manifest } = installedToolManifest(f.args); + expect(output).toBe(f.output); + expect(manifest.toolSpec).toEqual(f.descriptor.toolSpec); + expect(manifest.files).toEqual(f.files); + expect(manifest.runner).toBe(f.runner); + expect(manifest.bun).toBe(manifest.node); + expect(Object.keys(manifest).sort()).toEqual( + [ + 'schema', + 'platform', + 'toolSpec', + 'files', + 'bun', + 'node', + 'runner', + ...(platform === 'android' ? ['emulatorMetadata', 'adb'] : ['receipt']), + ].sort(), + ); + } finally { + f.cleanup(); + } + }); +} + +test('tools manifest rejects extra arguments, unsafe runner paths and invalid provider indices', () => { + const f = fixture('android'); + try { + expect(() => installedToolManifest([...f.args, 'extra'])).toThrow(); + expect(() => installedToolManifest([...f.args.slice(0, -1), 'relative.json'])).toThrow( + /absolute/, + ); + for (const mutation of [ + (value) => { + value.schema = 'unknown'; + }, + (value) => { + value.platform = 'unknown'; + }, + (value) => { + value.unexpected = true; + }, + (value) => { + value.runnerRunfile = '../unowned.mts'; + }, + (value) => { + value.fileCount++; + }, + (value) => { + value.toolSpec.java = 3; + }, + (value) => { + value.toolSpec.helpers[0].relative = '../unowned.mts'; + }, + (value) => { + value.toolSpec.helpers.push(value.toolSpec.helpers[0]); + }, + ]) { + const original = JSON.parse(JSON.stringify(f.descriptor)); + const altered = JSON.parse(JSON.stringify(f.descriptor)); + mutation(altered); + writeFileSync(f.args[0], JSON.stringify(altered)); + expect(() => installedToolManifest(f.args)).toThrow(); + writeFileSync(f.args[0], JSON.stringify(original)); + } + rmSync(f.files[0]); + expect(() => installedToolManifest(f.args)).toThrow(); + } finally { + f.cleanup(); + } +}); + +test('actual tools CLI writes an explicit new regular manifest and refuses destination substitution', () => { + const f = fixture('ios'); + try { + const command = [ + process.execPath, + '--no-install', + '--no-env-file', + path.join(import.meta.dir, 'installed-tools.mts'), + ...f.args, + ]; + const run = () => Bun.spawnSync(command, { stdout: 'pipe', stderr: 'pipe' }); + const first = run(); + expect(first.exitCode).toBe(0); + expect(first.stdout.toString()).toBe(''); + expect(JSON.parse(readFileSync(f.output, 'utf8')).runner).toBe(f.runner); + const bytes = readFileSync(f.output); + expect(run().exitCode).not.toBe(0); + expect(readFileSync(f.output)).toEqual(bytes); + } finally { + f.cleanup(); + } +}); diff --git a/build_defs/apple/native-metadata.mts b/build_defs/apple/native-metadata.mts new file mode 100644 index 000000000..1f9ebcb87 --- /dev/null +++ b/build_defs/apple/native-metadata.mts @@ -0,0 +1,269 @@ +import assert from 'node:assert/strict'; +import { + existsSync, + mkdirSync, + readdirSync, + readFileSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; + +type AcquiredPackage = { package: string; version: string; integrity: string; root: string }; +type Profile = { + package: string; + module: string; + directory: string; + deps?: string[]; + exclude?: string[]; + swift?: string; + podspec?: string; +}; +const profiles: Profile[] = [ + { package: '@expo/dom-webview', module: 'ExpoDomWebView', directory: 'ios', swift: '5' }, + { package: '@expo/log-box', module: 'ExpoLogBox', directory: 'ios', deps: ['React'] }, + { + package: 'expo', + module: 'Expo', + directory: 'ios', + swift: '6', + deps: ['ExpoModulesCore', 'ExpoModulesJSI', 'React', '@app//:ReactAppDependencyProvider'], + exclude: ['ios/Tests'], + }, + { package: 'expo-asset', module: 'ExpoAsset', directory: 'ios', swift: '5' }, + { package: 'expo-constants', module: 'EXConstants', directory: 'ios', swift: '5' }, + { + package: 'expo-dev-menu-interface', + module: 'expo_dev_menu_interface', + directory: 'ios', + deps: [], + swift: '5', + }, + { package: 'expo-json-utils', module: 'EXJSONUtils', directory: 'ios/EXJSONUtils', deps: [] }, + { package: 'expo-keep-awake', module: 'ExpoKeepAwake', directory: 'ios', swift: '5' }, + { package: 'expo-manifests', module: 'EXManifests', directory: 'ios/EXManifests', swift: '5' }, + { package: 'expo-splash-screen', module: 'ExpoSplashScreen', directory: 'ios' }, + { + package: 'expo-sqlite', + module: 'ExpoSQLite', + directory: 'ios', + exclude: ['ios/SQLiteModuleLibSQL.swift', 'ios/libsql', 'ios/libsql.xcframework'], + }, + { package: 'expo-system-ui', module: 'ExpoSystemUI', directory: 'ios/ExpoSystemUI', swift: '5' }, + { + package: 'expo-updates-interface', + module: 'EXUpdatesInterface', + directory: 'ios/EXUpdatesInterface', + swift: '5', + }, +]; +const imported = { + 'expo-modules-core': ['ExpoModulesCore', 'ExpoModulesWorklets'], + 'expo-file-system': ['ExpoFileSystem'], + 'expo-font': ['ExpoFont'], +}; +const releaseEmpty = ['expo-dev-client']; +const debugOnly = ['expo-dev-launcher', 'expo-dev-menu']; + +function walk(root: string): string[] { + const result: string[] = []; + function descend(directory: string) { + for (const entry of readdirSync(directory, { withFileTypes: true })) { + if (entry.name === 'node_modules' || entry.isSymbolicLink()) continue; + const file = path.join(directory, entry.name); + if (entry.isDirectory()) descend(file); + else if (entry.isFile()) result.push(path.relative(root, file).split(path.sep).join('/')); + } + } + descend(root); + return result.sort(); +} +/** Extend the existing native npm source projection; it does not acquire or resolve packages. */ +export function projectAppleNativeInputs( + packages: AcquiredPackage[], + repository: string, + sdkManifestFile: string, +) { + const sdk = JSON.parse(readFileSync(sdkManifestFile, 'utf8')); + assert.equal(sdk.name, '@oliphaunt/react-native'); + assert.match(sdk.oliphaunt.swiftSdkVersion, /^\d+\.\d+\.\d+$/u); + const expected = [ + ...profiles.map((row) => row.package), + ...Object.keys(imported), + ...releaseEmpty, + ...debugOnly, + 'expo-modules-jsi', + ]; + const nativeNames = new Set([...expected, 'react-native', 'react-native-safe-area-context']); + const byName = new Map(); + for (const row of packages) { + if (!nativeNames.has(row.package)) continue; + const previous = byName.get(row.package); + if (previous) + assert.deepEqual( + [previous.version, previous.integrity], + [row.version, row.integrity], + 'Apple native modules require one exact locked source identity: ' + row.package, + ); + byName.set(row.package, row); + } + function requireInput(name: string) { + const row = byName.get(name); + assert(row, 'Missing acquired Apple module ' + name); + return row; + } + const expectedModules: Record = {}; + const rows: Record[] = []; + for (const name of expected) { + const row = requireInput(name); + const manifest = JSON.parse(readFileSync(path.join(row.root, 'package.json'), 'utf8')); + assert.equal(manifest.name, name); + assert.equal(manifest.version, row.version); + expectedModules[name] = row.version; + } + for (const profile of profiles) { + const row = requireInput(profile.package); + const files = walk(row.root); + const podspecs = files.filter((name) => name.endsWith('.podspec') && !name.includes('Tests')); + assert.equal( + podspecs.length, + 1, + 'Review changed Apple Podspec/subspec composition for ' + profile.package, + ); + const spec = readFileSync(path.join(row.root, podspecs[0]), 'utf8'); + assert( + spec.includes(profile.module.replaceAll('_', '-')) || spec.includes(profile.module), + 'Apple module identity differs from its original Podspec: ' + profile.module, + ); + assert( + spec.includes('s.source_files'), + 'Original Apple module no longer declares source_files', + ); + const sources = files.filter( + (name) => + name.startsWith(profile.directory + '/') && + /\.(?:swift|h|m|mm|cpp|c)$/u.test(name) && + !/(?:^|\/)(?:Tests|[^/]*Tests)(?:\/|\.)/u.test(name) && + !(profile.exclude ?? []).some( + (excluded) => name === excluded || name.startsWith(excluded + '/'), + ), + ); + const prefix = path.relative(repository, row.root).split(path.sep).join('/'); + assert( + !prefix.startsWith('../') && !path.isAbsolute(prefix), + 'Native sources must belong to their captured repository', + ); + const headers: string[] = [], + privateHeaders: string[] = []; + const names = new Set(); + for (const source of sources.filter((name) => name.endsWith('.h'))) { + privateHeaders.push(prefix + '/' + source); + const basename = path.basename(source); + assert( + !names.has(basename), + 'Ambiguous CocoaPods public header name ' + profile.module + '/' + basename, + ); + names.add(basename); + if (profile.module === 'Expo' && basename === 'Swift.h') continue; + const alias = 'apple-headers/' + profile.module + '/' + basename; + const destination = path.join(repository, alias); + mkdirSync(path.dirname(destination), { recursive: true }); + if (!existsSync(destination)) + symlinkSync( + path.relative(path.dirname(destination), path.join(row.root, source)), + destination, + ); + headers.push(alias); + } + rows.push({ + ...profile, + root: prefix, + sources: sources.filter((name) => !name.endsWith('.h')).map((name) => prefix + '/' + name), + headers, + privateHeaders, + deps: profile.deps ?? ['ExpoModulesCore'], + privacy: files + .filter((name) => name.endsWith('PrivacyInfo.xcprivacy')) + .map((name) => prefix + '/' + name), + podspec: prefix + '/' + podspecs[0], + }); + } + const frameworks = Object.entries(imported).flatMap(([name, modules]) => { + const row = requireInput(name); + return modules.map((module) => { + const archive = path.join( + row.root, + 'prebuilds/output/release/xcframeworks', + module + '.tar.gz', + ); + assert(existsSync(archive), 'Use original Expo release XCFramework ' + module); + return { + module, + archive: path.relative(repository, archive).split(path.sep).join('/'), + privacy: walk(row.root) + .filter((name) => name.endsWith('PrivacyInfo.xcprivacy')) + .map((name) => + path.relative(repository, path.join(row.root, name)).split(path.sep).join('/'), + ), + }; + }); + }); + const rn = requireInput('react-native'); + const rnManifest = JSON.parse(readFileSync(path.join(rn.root, 'package.json'), 'utf8')); + const rnHelpers = readFileSync(path.join(rn.root, 'scripts/cocoapods/helpers.rb'), 'utf8'); + const follyFlags = rnHelpers.match( + /@@folly_config\s*=\s*\{[^}]*:compiler_flags\s*=>\s*'([^']+)'/u, + )?.[1]; + assert(follyFlags, 'Original RN Apple recipe must declare Folly compiler flags'); + const follyCompilerFlags = follyFlags.trim().split(/\s+/u); + assert( + follyCompilerFlags.every((flag) => /^-[A-Za-z0-9=_+.-]+$/u.test(flag)), + 'Review changed original RN Folly compiler flags', + ); + const hermesProperties = readFileSync( + path.join(rn.root, 'sdks/hermes-engine/version.properties'), + 'utf8', + ); + const hermes = hermesProperties.match(/^HERMES_V1_VERSION_NAME=(.+)$/mu)?.[1]; + assert(hermes); + const result = { + expectedModules, + modules: rows, + frameworks, + swiftSdkVersion: sdk.oliphaunt.swiftSdkVersion, + reactNativeVersion: rnManifest.version, + hermesVersion: hermes, + follyCompilerFlags, + jsiRoot: path + .relative(repository, requireInput('expo-modules-jsi').root) + .split(path.sep) + .join('/'), + safeAreaRoot: path + .relative(repository, requireInput('react-native-safe-area-context').root) + .split(path.sep) + .join('/'), + sqliteRoot: path + .relative(repository, requireInput('expo-sqlite').root) + .split(path.sep) + .join('/'), + }; + writeFileSync( + path.join(repository, 'apple-metadata.json'), + JSON.stringify(result, null, 2) + '\n', + ); + writeFileSync( + path.join(repository, 'apple-metadata.bzl'), + 'APPLE_NATIVE = ' + + JSON.stringify(result, null, 4) + .replaceAll(': false', ': False') + .replaceAll(': true', ': True') + + '\n', + ); + return result; +} + +if (import.meta.main) { + const [inputs, repository, sdkManifest] = process.argv.slice(2); + assert(inputs && repository && sdkManifest, 'Expected acquired inputs, repository, SDK manifest'); + projectAppleNativeInputs(JSON.parse(readFileSync(inputs, 'utf8')), repository, sdkManifest); +} diff --git a/build_defs/apple/native.bzl b/build_defs/apple/native.bzl new file mode 100644 index 000000000..ecaf45da2 --- /dev/null +++ b/build_defs/apple/native.bzl @@ -0,0 +1,163 @@ +"""Finite original Expo Apple module declarations, compiled by maintained rules.""" +load("@bazel_skylib//rules:write_file.bzl", "write_file") +load("@rules_swift//swift:swift_library.bzl", "swift_library") +load("@rules_swift//mixed_language:mixed_language_library.bzl", "mixed_language_library") +load("@rules_swift//swift:swift_interop_hint.bzl", "swift_interop_hint") +load("@rules_swift//swift:providers.bzl", "SwiftInfo") +load("@rules_swift//swift:swift_clang_module_aspect.bzl", "swift_clang_module_aspect") +load("@rules_cc//cc:defs.bzl", "cc_library") +load("@rules_cc//cc:objc_library.bzl", "objc_library") +load("@rules_cc//cc/common:cc_common.bzl", "cc_common") +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") +load("@rules_apple//apple:apple.bzl", "apple_dynamic_xcframework_import") +load("@rules_apple//apple:resources.bzl", "apple_resource_bundle") +load("@rules_apple//apple:ios.bzl", "ios_dynamic_framework") + +def _react_headers_impl(ctx): + headers = ctx.attr.react[CcInfo].compilation_context.direct_headers + roots = {header.path.split("/React.framework/")[0] + "/React.framework": True for header in headers if "/React.framework/" in header.path} + if len(roots) != 1: + fail("React header projection requires one selected React.framework") + root = roots.keys()[0] + jsi = [header for header in headers if header.path == root + "/Headers/React_jsi/jsi/jsi.h"] + if len(jsi) != 1: + fail("Selected React.framework must provide exactly one jsi.h") + module_maps = [module.clang.module_map for module in ctx.attr.react[SwiftInfo].direct_modules if module.name == "React" and module.clang and type(module.clang.module_map) == "File"] + if len(module_maps) != 1 or module_maps[0].path != root + "/Modules/module.modulemap": + fail("React module map must belong to the selected React.framework") + overlay = ctx.actions.declare_file(ctx.label.name + ".yaml") + ctx.actions.expand_template(template = ctx.file.template, output = overlay, + substitutions = {"${ROOT_PATH}": root}) + # The upstream overlay and selected module map must name the same physical headers. + prefix = root + "/Headers" + hermes = ctx.file.hermes_header.dirname.removesuffix("/hermes") + dependencies = ctx.file.dependencies_header.dirname.removesuffix("/folly") + swift_headers = ctx.file.swift_bridging.dirname.removesuffix("/swift") + return [ + DefaultInfo(files = depset([overlay])), + OutputGroupInfo(jsi_header = depset(jsi), module_map = depset(module_maps)), + CcInfo(compilation_context = cc_common.create_compilation_context( + headers = depset(headers + module_maps + ctx.files.headers + ctx.files.swift_headers + [overlay]), + system_includes = depset([prefix, hermes, dependencies, swift_headers]), + )), + ] + +react_apple_headers = rule(implementation = _react_headers_impl, attrs = { + "react": attr.label(mandatory = True, providers = [CcInfo], aspects = [swift_clang_module_aspect]), + "template": attr.label(mandatory = True, allow_single_file = [".yaml"]), + "hermes_header": attr.label(mandatory = True, allow_single_file = [".h"]), + "dependencies_header": attr.label(mandatory = True, allow_single_file = [".h"]), + "headers": attr.label_list(mandatory = True, allow_files = True), + "swift_bridging": attr.label(mandatory = True, allow_single_file = True), + "swift_headers": attr.label_list(mandatory = True, allow_files = True), +}) + +def apple_swift_cxx_copts(): + """Import C++ without exporting unannotated Swift declarations as C++.""" + return [ + "-Xfrontend", "-clang-header-expose-decls=has-expose-attr", + "-cxx-interoperability-mode=default", "-Xcc", "-std=c++20", + ] + +def react_apple_swift_copts(react_headers): + """Keep RN's C++ import context when rebuilding textual Swift interfaces.""" + return apple_swift_cxx_copts() + [ + "-Xcc", "-ivfsoverlay", "-Xcc", "$(location " + react_headers + ")", + "-Xfrontend", "-strict-implicit-module-context", + ] + +def expo_apple_swift_library(name, hdrs = [], clang_copts = [], clang_module_maps = [], additional_objc_compiler_inputs = [], **kwargs): + """Preserve CocoaPods' UIKit prefix and re-exporting underlying module.""" + umbrella = name + "_pod_umbrella" + write_file( + name = umbrella, + out = umbrella + ".h", + content = ["#ifdef __OBJC__", "#import ", "#endif", ""], + target_compatible_with = kwargs.get("target_compatible_with", []), + visibility = ["//visibility:private"], + ) + mixed_language_library( + name = name, hdrs = [":" + umbrella] + hdrs, enable_modules = True, + clang_copts = ["-include", "$(location :" + umbrella + ")"] + + ["-fmodule-map-file=$(location " + module_map + ")" for module_map in clang_module_maps] + clang_copts, + additional_objc_compiler_inputs = additional_objc_compiler_inputs + clang_module_maps, + **kwargs + ) + +_SQLITE = ["HAVE_USLEEP=1", "SQLITE_ENABLE_LOCKING_STYLE=0", "SQLITE_ENABLE_BYTECODE_VTAB=1", + "SQLITE_TEMP_STORE=2", "SQLITE_ENABLE_SESSION=1", "SQLITE_ENABLE_PREUPDATE_HOOK=1", + "SQLITE_ENABLE_MATH_FUNCTIONS=1", "SQLITE_ENABLE_FTS4=1", "SQLITE_ENABLE_FTS3_PARENTHESIS=1", "SQLITE_ENABLE_FTS5=1"] + +def expo_apple_modules(metadata, react, hermes, dependencies, react_headers, react_jsi_headers, react_module_map, app_dependency_provider, app_codegen, constants_config): + """Build the real release closure declared by the exact original Apple resolve.""" + common = [react, hermes, dependencies, react_headers] + overlay = "$(location " + react_headers + ")" + clang = ["-ivfsoverlay", overlay, "-DREACT_NATIVE_MINOR_VERSION=" + metadata["reactNativeVersion"].split(".")[1], "-DRCT_NEW_ARCH_ENABLED=1"] + metadata["follyCompilerFlags"] + swift = react_apple_swift_copts(react_headers) + [flag for option in metadata["follyCompilerFlags"] for flag in ["-Xcc", option]] + root = metadata["jsiRoot"] + "/apple" + swift_interop_hint(name = "jsi_module_hint", module_name = "jsi") + cc_library(name = "jsi_module", hdrs = [react_jsi_headers], deps = common, aspect_hints = [":jsi_module_hint"]) + swift_interop_hint(name = "ExpoModulesJSI_Cxx_module", module_name = "ExpoModulesJSI_Cxx") + cc_library( + name = "ExpoModulesJSI_Cxx", srcs = native.glob([root + "/Sources/ExpoModulesJSI-Cxx/*.cpp"]), + hdrs = native.glob([root + "/Sources/ExpoModulesJSI-Cxx/include/*.h"]), + includes = [root + "/Sources/ExpoModulesJSI-Cxx/include"], aspect_hints = [":ExpoModulesJSI_Cxx_module"], + deps = common, copts = ["-std=c++20"] + clang, additional_compiler_inputs = [react_headers], + ) + swift_library( + name = "ExpoModulesJSI_sources", module_name = "ExpoModulesJSI", + srcs = native.glob([root + "/Sources/ExpoModulesJSI/**/*.swift"]), + deps = [":ExpoModulesJSI_Cxx", ":jsi_module"] + common, + copts = ["-swift-version", "6", "-enable-upcoming-feature", "NonisolatedNonsendingByDefault", + "-enable-upcoming-feature", "InferIsolatedConformances", "-no-verify-emitted-module-interface"] + swift + + ["-Xcc", "-iapinotes-modules", "-Xcc", "external/" + native.repository_name().removeprefix("@") + "/" + root + "/APINotes"], + swiftc_inputs = [react_headers] + native.glob([root + "/APINotes/**"]), + library_evolution = True, + ) + ios_dynamic_framework(name = "ExpoModulesJSI", bundle_id = "expo.modules.jsi", minimum_os_version = "17.0", + families = ["iphone"], infoplists = [Label("//build_defs/apple:framework-info.plist")], + deps = [":ExpoModulesJSI_sources"], tags = ["no-remote"], visibility = ["//visibility:public"]) + for row in metadata["frameworks"]: + apple_dynamic_xcframework_import( + name = row["module"], xcframework_imports = native.glob(["apple-prebuilt/" + row["module"] + ".xcframework/**"], exclude = ["**/._*"]), + deps = [":ExpoModulesJSI_sources"] if row["module"] == "ExpoModulesCore" else [":ExpoModulesCore", ":ExpoModulesJSI_sources"], + ) + if row["privacy"]: + apple_resource_bundle(name = row["module"] + "_privacy", bundle_name = row["module"] + "_privacy", resources = row["privacy"]) + for row in metadata["modules"]: + defines = _SQLITE if row["module"] == "ExpoSQLite" else [] + sqlite_headers = "external/" + native.repository_name().removeprefix("@") + "/" + metadata["sqliteRoot"] + "/vendor/sqlite3" + deps = [app_dependency_provider if dep.startswith("@app//") else react if dep == "React" else ":ExpoModulesJSI_sources" if dep == "ExpoModulesJSI" else ":" + dep for dep in row["deps"]] + if not any([source.endswith(".swift") for source in row["sources"]]): + objc_library(name = row["module"], module_name = row["module"], enable_modules = True, + srcs = row["sources"] + row["privateHeaders"], hdrs = row["headers"], + includes = ["apple-headers"], + deps = deps + [react_headers], alwayslink = True, copts = clang, + data = [react_headers]) + continue + expo_apple_swift_library( + name = row["module"], module_name = row["module"], + swift_srcs = [source for source in row["sources"] if source.endswith(".swift")], + clang_srcs = [source for source in row["sources"] if not source.endswith(".swift")] + ([metadata["sqliteRoot"] + "/vendor/sqlite3/sqlite3.c"] if defines else []), + hdrs = row["headers"] + ([metadata["sqliteRoot"] + "/vendor/sqlite3/sqlite3.h"] if defines else []), + includes = ["apple-headers"], + deps = deps + [react_headers], alwayslink = True, + swift_copts = ["-swift-version", row.get("swift", "5")] + swift + (["-Xcc", "-I" + sqlite_headers] + [flag for define in defines for flag in ["-Xcc", "-D" + define]] if defines else []), + clang_copts = clang + ["-D" + define for define in defines] + (["-I" + sqlite_headers] if defines else []), + clang_module_maps = [react_module_map], + # Original relative includes remain available without importing private Swift.h into its own module. + swiftc_inputs = [react_headers] + row["privateHeaders"], + additional_objc_compiler_inputs = [react_headers] + row["privateHeaders"], + ) + if row["privacy"]: + apple_resource_bundle(name = row["module"] + "_privacy", bundle_name = row["module"] + "_privacy", + resources = row["privacy"]) + safe_area = metadata["safeAreaRoot"] + objc_library(name = "SafeAreaContext", srcs = native.glob([safe_area + "/ios/**/*.m", safe_area + "/ios/**/*.mm", safe_area + "/common/cpp/**/*.cpp"]), + hdrs = native.glob([safe_area + "/ios/**/*.h", safe_area + "/common/cpp/**/*.h"]), + includes = [safe_area + "/ios", safe_area + "/ios/Fabric", safe_area + "/common/cpp"], + deps = common + [app_codegen], defines = ["RCT_NEW_ARCH_ENABLED=1"], alwayslink = True, + copts = clang, data = [react_headers]) + # Release-only wrapper: the original podspec has no compiled sources. + native.alias(name = "expo_dev_client", actual = ":expo_dev_menu_interface") + apple_resource_bundle(name = "EXConstants_config", bundle_name = "EXConstants", resources = [constants_config]) diff --git a/build_defs/apple/react-native-artifacts.json b/build_defs/apple/react-native-artifacts.json new file mode 100644 index 000000000..18dd83923 --- /dev/null +++ b/build_defs/apple/react-native-artifacts.json @@ -0,0 +1,9 @@ +{ + "reactNativeVersion": "0.85.3", + "hermesVersion": "250829098.0.10", + "archives": { + "reactnative-core-release": "bffa15d491a7d938a304bdbf0f8391ffcac29e7de54a3be53209b4557879a3f3", + "reactnative-dependencies-release": "e5f311bb17d10930d323a74b3e5f2a30021d25faddd08839157a59961d481d81", + "hermes-ios-release": "23f8f1b2f771a76e66c81be7d5bae82fb9e58eef18b597de3718bffad7adab51" + } +} diff --git a/build_defs/apple/react-native-repository.bzl b/build_defs/apple/react-native-repository.bzl new file mode 100644 index 000000000..bf6b59fbc --- /dev/null +++ b/build_defs/apple/react-native-repository.bzl @@ -0,0 +1,30 @@ +"""Immutable official RN/Hermes release inputs, matched to original npm recipes.""" + +def _release_impl(ctx): + source = json.decode(ctx.read(ctx.attr.native_metadata)) + locked = json.decode(ctx.read(ctx.attr.integrities)) + for key in ["reactNativeVersion", "hermesVersion"]: + if locked[key] != source[key]: + fail("Refresh immutable Apple release archive integrity for changed original npm " + key) + version, hermes = source["reactNativeVersion"], source["hermesVersion"] + for classifier in ["reactnative-core-release", "reactnative-dependencies-release"]: + url = "https://repo.maven.apache.org/maven2/com/facebook/react/react-native-artifacts/" + version + "/react-native-artifacts-" + version + "-" + classifier + ".tar.gz" + ctx.download_and_extract(url = url, sha256 = locked["archives"][classifier], output = ".") + url = "https://repo.maven.apache.org/maven2/com/facebook/hermes/hermes-ios/" + hermes + "/hermes-ios-" + hermes + "-hermes-ios-release.tar.gz" + ctx.download_and_extract(url = url, sha256 = locked["archives"]["hermes-ios-release"], output = ".") + ctx.file("BUILD.bazel", """ +load("@rules_apple//apple:apple.bzl", "apple_dynamic_xcframework_import") +package(default_visibility = ["//visibility:public"]) +exports_files(glob(["React.xcframework/Headers/**", "React.xcframework/*.yaml", "destroot/include/**", "packages/react-native/third-party/ReactNativeDependencies.xcframework/Headers/**"])) +filegroup(name = "hermes_headers", srcs = glob(["destroot/include/**"])) +filegroup(name = "dependency_headers", srcs = glob(["packages/react-native/third-party/ReactNativeDependencies.xcframework/Headers/**"])) +apple_dynamic_xcframework_import(name = "hermes", xcframework_imports = glob(["destroot/Library/Frameworks/universal/hermesvm.xcframework/**"])) +apple_dynamic_xcframework_import(name = "dependencies", xcframework_imports = glob(["packages/react-native/third-party/ReactNativeDependencies.xcframework/**"])) +apple_dynamic_xcframework_import(name = "React", xcframework_imports = glob(["React.xcframework/**"]), deps = [":hermes", ":dependencies"]) +""") + return ctx.repo_metadata(reproducible = True) + +react_native_apple_release_repository = repository_rule(implementation = _release_impl, attrs = { + "native_metadata": attr.label(mandatory = True, allow_single_file = [".json"]), + "integrities": attr.label(default = Label("//build_defs/apple:react-native-artifacts.json"), allow_single_file = [".json"]), +}) diff --git a/build_defs/apple/requirement-selection-test.bzl b/build_defs/apple/requirement-selection-test.bzl new file mode 100644 index 000000000..0c5f69595 --- /dev/null +++ b/build_defs/apple/requirement-selection-test.bzl @@ -0,0 +1,51 @@ +"""Exercise the actual factory decisions over successive release cycles.""" +load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest") +load(":requirement-selection.bzl", "native_apple_requirement_inputs", "swift_requirement_inputs") + +def _native_pair(version): + return {role: {"publication": {"product": "liboliphaunt-native", "version": version}, "file": {"path": version + "/" + role}} for role in ["base-xcframework", "runtime-resources"]} + +def _swift_pair(version): + return {"oliphaunt-swift/" + version + "/" + artifact: {"file": {"path": version + "/" + artifact}} for artifact in ["swift-source-tag:" + version, "github-release:oliphaunt-swift-" + version + "-bindings.xcframework.zip"]} + +def _selection_test(ctx): + env = unittest.begin(ctx) + # Native hold -> intentional adoption -> completed hold, twice. Current + # compiler labels never enter either held branch. + for held, adopted, newer in [("0.3.3", "0.3.4", "0.3.5"), ("0.3.4", "0.3.5", "0.3.6")]: + old = _native_pair(held) + hold = native_apple_requirement_inputs(held, adopted, ["liboliphaunt-native"], old, None, True) + asserts.equals(env, old, hold["archives"]) + asserts.false(env, hold["local_current"]) + asserts.true(env, "error" in native_apple_requirement_inputs(adopted, adopted, [], {}, None, True)) + adopt = native_apple_requirement_inputs(adopted, adopted, ["liboliphaunt-native"], {}, None, True) + asserts.true(env, adopt["local_current"]) + asserts.equals(env, "//src/native/runtime:apple_swiftpm", adopt["archives"]["base-xcframework"]["file"]["path"]) + captured = {"owner": "liboliphaunt-native", "version": adopted, "file": {"path": "real/ios.json"}, "framework": {"path": "real/base.zip", "producer": {"invocationId": "final"}}, "resources": {"path": "real/resources.tar.gz", "producer": {"invocationId": "final"}}} + imported = native_apple_requirement_inputs(adopted, adopted, ["liboliphaunt-native"], {}, captured) + asserts.equals(env, captured["framework"], imported["archives"]["base-xcframework"]["file"]) + asserts.true(env, "error" in native_apple_requirement_inputs(adopted, adopted, ["liboliphaunt-native"], {}, dict(captured, version = held))) + published = _native_pair(adopted) + next_hold = native_apple_requirement_inputs(adopted, newer, ["liboliphaunt-native"], published, captured, True) + asserts.equals(env, published, next_hold["archives"]) + asserts.false(env, next_hold["local_current"]) + asserts.true(env, "error" in native_apple_requirement_inputs(adopted, adopted, ["liboliphaunt-native"], {"base-xcframework": published["base-xcframework"]}, captured, True)) + for held, adopted in [("0.8.2", "0.8.3"), ("0.8.3", "0.8.4")]: + old = _swift_pair(held) + captured = {"owner": "oliphaunt-swift", "version": adopted, "archive": {"path": "real/Oliphaunt-source.zip"}, "bindingsArchive": {"path": "real/" + adopted + "-bindings.zip", "producer": {"invocationId": "final"}}} + hold = swift_requirement_inputs(held, ["oliphaunt-swift"], old, captured) + asserts.true(env, hold["completed"]) + asserts.true(env, "error" in swift_requirement_inputs(adopted, [], {}, captured)) + asserts.true(env, "error" in swift_requirement_inputs(adopted, ["oliphaunt-swift"], {}, dict(captured, version = held))) + adopt = swift_requirement_inputs(adopted, ["oliphaunt-swift"], {}, captured) + asserts.false(env, adopt["completed"]) + asserts.equals(env, captured["bindingsArchive"], adopt["bindings"]["file"]) + published = _swift_pair(adopted) + next_hold = swift_requirement_inputs(adopted, [], published, captured) + asserts.true(env, next_hold["completed"]) + asserts.equals(env, published["oliphaunt-swift/" + adopted + "/github-release:oliphaunt-swift-" + adopted + "-bindings.xcframework.zip"], next_hold["bindings"]) + source = "oliphaunt-swift/" + adopted + "/swift-source-tag:" + adopted + asserts.true(env, "error" in swift_requirement_inputs(adopted, ["oliphaunt-swift"], {source: published[source]}, captured)) + return unittest.end(env) + +requirement_selection_test = unittest.make(_selection_test) diff --git a/build_defs/apple/requirement-selection.bzl b/build_defs/apple/requirement-selection.bzl new file mode 100644 index 000000000..5504eb16d --- /dev/null +++ b/build_defs/apple/requirement-selection.bzl @@ -0,0 +1,27 @@ +"""Conventional pins choose genuine completed Files or explicit current producers.""" + +def native_apple_requirement_inputs(required, current_version, selected, completed, current, local_current = False): + if completed: + if sorted(completed) != ["base-xcframework", "runtime-resources"]: + return {"error": "completed Apple native archive tuple is incomplete"} + return {"record": {}, "archives": completed, "local_current": False} + if "liboliphaunt-native" not in selected or required != current_version: + return {"error": "unpublished Apple native requirement must be explicitly selected at its conventional version"} + if current and current["owner"] == "liboliphaunt-native" and current["version"] == required: + return {"record": current, "archives": {role: {"owner": current["owner"], "version": current["version"], "file": current[group]} for role, group in [("base-xcframework", "framework"), ("runtime-resources", "resources")]}, "local_current": False} + if local_current: + return {"record": {"owner": "liboliphaunt-native", "version": required, "file": {"path": "//src/native/runtime:apple_ios_manifest"}}, + "archives": {role: {"owner": "liboliphaunt-native", "version": required, "file": {"path": label}} for role, label in [("base-xcframework", "//src/native/runtime:apple_swiftpm"), ("runtime-resources", "//src/native/runtime:apple_resources")]}, "local_current": True} + return {"error": "unpublished Apple native requirement needs its final Mac producer capture"} + +def swift_requirement_inputs(required, selected, catalog, current): + source_key = "oliphaunt-swift/" + required + "/swift-source-tag:" + required + binding_key = "oliphaunt-swift/" + required + "/github-release:oliphaunt-swift-" + required + "-bindings.xcframework.zip" + source, bindings = catalog.get(source_key), catalog.get(binding_key) + if bool(source) != bool(bindings): + return {"error": "completed Swift source/binding supplier tuple is incomplete"} + if source: + return {"source": source, "bindings": bindings, "completed": True} + if "oliphaunt-swift" in selected and current and current["owner"] == "oliphaunt-swift" and current["version"] == required: + return {"source": current, "bindings": {"file": current["bindingsArchive"]}, "completed": False} + return {"error": "Swift requirement needs its completed Files or explicitly selected final source producer"} diff --git a/build_defs/apple/resources.bzl b/build_defs/apple/resources.bzl new file mode 100644 index 000000000..3b5fdac0f --- /dev/null +++ b/build_defs/apple/resources.bzl @@ -0,0 +1,58 @@ +"""The original SDK's selected app resource/registry construction.""" +load("@oliphaunt_metadata//:metadata.bzl", "EXTENSION_RELEASE_METADATA") +load("//build_defs/extensions:final_leaf.bzl", "ExtensionFinalLeafInfo", "NativeAppleBaseInfo") +load("//build_defs/extensions:owner_carriers.bzl", "native_owner_carrier_legal") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") + +def _resources_impl(ctx): + base = ctx.attr.base[NativeAppleBaseInfo] + if len(base.archives) != 2 or len(base.archive_files) != 2: + fail("App construction requires the two genuine declared native archive Files") + if not ctx.attr.extensions: + fail("The mandatory installed app must exercise a nonempty selected extension cohort") + inputs = [base.file, ctx.file.seed] + base.archive_files + ctx.files.legal + leaves = [] + for target in ctx.attr.leaves: + leaf = target[ExtensionFinalLeafInfo] + if leaf.family != "native" or leaf.target != "ios-xcframework" or leaf.metadata["runtimeVersion"] != base.version: + fail("App carrier must hold the actual declared Apple native host") + inputs += leaf.github + [leaf.frozen] + if leaf.validation: + inputs.append(leaf.validation) + members = leaf.metadata.get("members", [leaf.metadata]) + leaves.append({"product":leaf.product,"owner":leaf.owner,"version":leaf.version, + "runtimeVersion":leaf.metadata["runtimeVersion"],"sqlNames":sorted([member["sqlName"] for member in members]), + "github":[file.path for file in leaf.github],"frozen":leaf.frozen.path}) + resources = ctx.actions.declare_directory(ctx.label.name + "/oliphaunt") + registry = ctx.actions.declare_file(ctx.label.name + "/oliphaunt_static_registry.c") + selection = ctx.actions.declare_file(ctx.label.name + "/selection.json") + seed_resources = ctx.actions.declare_directory(ctx.label.name + "/cluster-seed") + specification = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(specification,json.encode({"version":base.version,"baseManifest":base.file.path, + "archives":base.archives,"leaves":leaves,"extensions":ctx.attr.extensions, + "resources":resources.path,"registry":registry.path,"selection":selection.path, + "seed":ctx.file.seed.path,"seedResources":seed_resources.path}) + "\n") + bun_file_action(ctx,ctx.file._runner,arguments=[specification.path], + inputs=inputs+[specification],source_files=[ctx.file._runner]+ctx.files._helpers+ctx.files.legal, + outputs=[resources,registry,selection,seed_resources],execution_requirements={"block-network":"1"},mnemonic="ExpoAppleSelectedResources") + return [DefaultInfo(files=depset([resources])),OutputGroupInfo(resources=depset([resources]),registry=depset([registry]),selection=depset([selection]),seed=depset([seed_resources]))] + +_resources = rule(implementation=_resources_impl,toolchains=BUN_SOURCE_TOOLCHAINS,attrs={ + "base":attr.label(mandatory=True,providers=[NativeAppleBaseInfo]), + "leaves":attr.label_list(mandatory=True,providers=[ExtensionFinalLeafInfo],cfg="exec"), + "extensions":attr.string_list(mandatory=True), + "legal":attr.label_list(allow_files=True), + "seed":attr.label(mandatory=True,allow_single_file=[".tgz"],cfg="exec"), + "_runner":attr.label(default=Label("//build_defs/apple:resources.mts"),allow_single_file=True), + "_helpers":attr.label_list(default=[ + Label("//build_defs/native/apple:static-carrier-consumer.mts"),Label("//build_defs/native/apple:framework_helpers"), + Label("//src/native/sdks/swift:generator_sources"),Label("//src/native/sdks/react-native:tools/stage-ios-app.mts"), + Label("//src/native/sdks/react-native:tools/native-resource-closure.mts"),Label("//src/native/sdks/react-native:src/generated/extensions.json"), + Label("//src/database-resources:contracts/native-manifest.mts"), Label("//src/database-resources:contracts/contract.json"), + ],allow_files=True), +}) + +def expo_ios_resources(name, extensions, **kwargs): + products = {row["artifactProduct"]: True for row in EXTENSION_RELEASE_METADATA if row["sqlName"] in extensions} + legal = {label: True for product in products for label in native_owner_carrier_legal(product)} + _resources(name=name, extensions=extensions, legal=sorted(legal), **kwargs) diff --git a/build_defs/apple/resources.mts b/build_defs/apple/resources.mts new file mode 100644 index 000000000..4115d7be2 --- /dev/null +++ b/build_defs/apple/resources.mts @@ -0,0 +1,118 @@ +/** Compose the real app resource/registration closure with the original SDK policy. */ +import assert from 'node:assert/strict'; +import { + copyFileSync, + cpSync, + mkdirSync, + mkdtempSync, + readFileSync, + realpathSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { validateNativeClusterSeedDirectory } from '../../src/database-resources/contracts/native-manifest.mts'; +import { stageIosApp } from '../../src/native/sdks/react-native/tools/stage-ios-app.mts'; +import { buildIosCarrierManifest } from '../../src/native/sdks/swift/tools/ios-carrier-manifest.mts'; +import { extractPortableArchiveTree } from '../../tools/packaging/portable-archive.mts'; +import { stageAppleStaticLeaf } from '../native/apple/static-carrier-consumer.mts'; + +export function iosResourceBaseFiles(spec: any) { + return { + baseCarrierManifest: realpathSync(spec.baseManifest), + baseArchiveInputs: Object.fromEntries( + ['base-xcframework', 'runtime-resources'].map((role) => [ + role, + { ...spec.archives[role], path: realpathSync(spec.archives[role].path) }, + ]), + ), + }; +} + +export async function composeIosResources(spec: any) { + const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-apple-resources-')); + try { + assert( + spec.version && spec.extensions.length, + 'App resources require an exact host and nonempty selection', + ); + const base = iosResourceBaseFiles(spec); + const staged = spec.leaves.map((leaf: any, index: number) => + stageAppleStaticLeaf(leaf, path.join(root, `leaf-${index}`), spec.version), + ); + const products = Object.fromEntries( + spec.leaves.map((leaf: any) => [ + leaf.product, + { + product: leaf.product, + releaseProduct: leaf.owner, + version: leaf.version, + sqlNames: [...leaf.sqlNames].sort(), + tag: `${leaf.owner}-v${leaf.version}`, + }, + ]), + ); + assert.equal(Object.keys(products).length, spec.leaves.length, 'Repeated app carrier owner'); + const carrier = buildIosCarrierManifest({ + baseRuntimeVersion: spec.version, + baseTag: `liboliphaunt-native-v${spec.version}`, + ...base, + declaredProducts: products, + extensionManifests: staged.map((leaf: any) => leaf.output), + }); + const cache = path.join(root, 'cache'); + mkdirSync(path.join(cache, 'objects'), { recursive: true }); + for (const row of carrier.base.assets) { + const source = base.baseArchiveInputs[row.role]; + assert.equal(row.bytes, source.size); + assert.equal(row.sha256, source.sha256); + copyFileSync(source.path, path.join(cache, 'objects', `${row.sha256}-${row.name}`)); + } + for (const row of staged.flatMap((leaf: any) => leaf.archives)) + copyFileSync(row.path, path.join(cache, 'objects', `${row.sha256}-${row.name}`)); + const document = path.join(root, 'ios.json'); + writeFileSync(document, JSON.stringify(carrier)); + const output = path.join(root, 'app'); + const selection = await stageIosApp({ + carriers: [document], + extensions: spec.extensions, + cacheDir: cache, + outputDir: output, + seedProfile: 'standard', + }); + assert.deepEqual( + [...selection.selected].sort(), + [...spec.extensions].sort(), + 'App resource selection differs from its linked registration cohort', + ); + mkdirSync(path.dirname(spec.resources), { recursive: true }); + cpSync( + path.join(output, 'resources/OliphauntReactNativeResources.bundle/oliphaunt'), + spec.resources, + { recursive: true }, + ); + mkdirSync(path.dirname(spec.registry), { recursive: true }); + copyFileSync( + path.join(output, 'generated/static-registry/oliphaunt_static_registry.c'), + spec.registry, + ); + mkdirSync(path.dirname(spec.selection), { recursive: true }); + copyFileSync(path.join(output, 'selection.json'), spec.selection); + // The original Podspec dependency selects this separate carrier. Bazel + // declares its real Files directly; a profile string carries no seed bytes. + extractPortableArchiveTree( + realpathSync(spec.seed), + spec.seedResources, + 'package/OliphauntSeedNativeIOSStandard.bundle/cluster-seed', + { format: 'tar.gz' }, + ); + validateNativeClusterSeedDirectory(spec.seedResources, 'standard', { target: 'ios-datum64' }); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + await composeIosResources(JSON.parse(readFileSync(process.argv[2], 'utf8'))); +} diff --git a/build_defs/apple/slices-test.bzl b/build_defs/apple/slices-test.bzl new file mode 100644 index 000000000..289adae48 --- /dev/null +++ b/build_defs/apple/slices-test.bzl @@ -0,0 +1,45 @@ +"""Packaging aliases preserve exact slice Files; compiler aliases stay narrow.""" + +load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest") +load(":slices.bzl", "apple_slice_filegroup", "apple_slice_groups") + +def _producer_impl(ctx): + selected = ctx.actions.declare_file(ctx.label.name + ".selected.a") + alternative = ctx.actions.declare_file(ctx.label.name + ".unused.a") + archive = ctx.actions.declare_file(ctx.label.name + ".zip") + ctx.actions.write(selected, "selected") + ctx.actions.write(alternative, "unused") + ctx.actions.expand_template(output = archive, template = selected, substitutions = {}) + return [DefaultInfo(files = depset([archive])), OutputGroupInfo( + archive = depset([archive]), + compiled_core = depset([selected]), + unused = depset([alternative]), + apple_slice_ios_arm64 = depset([selected]), + )] + +_producer = rule(implementation = _producer_impl) + +def _test_impl(ctx): + env = unittest.begin(ctx) + source = ctx.attr.producer[OutputGroupInfo] + selected = source.apple_slice_ios_arm64.to_list() + groups = apple_slice_groups([ctx.attr.alias, ctx.attr.alias, ctx.attr.compiled]) + asserts.equals(env, ["apple_slice_ios_arm64"], groups.keys()) + asserts.equals(env, selected, groups["apple_slice_ios_arm64"].to_list()) + asserts.equals(env, source.archive.to_list(), ctx.attr.alias[DefaultInfo].files.to_list()) + asserts.equals(env, selected, ctx.attr.compiled[DefaultInfo].files.to_list()) + asserts.equals(env, {}, apple_slice_groups([ctx.attr.compiled])) + asserts.false(env, source.unused.to_list()[0] in groups["apple_slice_ios_arm64"].to_list()) + return unittest.end(env) + +_test = unittest.make(_test_impl, attrs = { + "producer": attr.label(), + "alias": attr.label(), + "compiled": attr.label(), +}) + +def apple_slices_test(name): + _producer(name = name + "_producer", testonly = True) + apple_slice_filegroup(name = name + "_archive", src = ":" + name + "_producer", output_group = "archive", testonly = True) + native.filegroup(name = name + "_compiled", srcs = [":" + name + "_producer"], output_group = "compiled_core", testonly = True) + _test(name = name, producer = ":" + name + "_producer", alias = ":" + name + "_archive", compiled = ":" + name + "_compiled") diff --git a/build_defs/apple/slices.bzl b/build_defs/apple/slices.bzl new file mode 100644 index 000000000..59f0846fb --- /dev/null +++ b/build_defs/apple/slices.bzl @@ -0,0 +1,31 @@ +"""Schedule exact package prerequisites by SDK without changing their actions.""" + +def apple_slice_groups(targets): + """Union the selected slice Files already consumed by these producers.""" + groups = {} + for target in targets: + if OutputGroupInfo not in target: + continue + info = target[OutputGroupInfo] + for name in dir(info): + if name.startswith("apple_slice_"): + groups.setdefault(name, []).append(getattr(info, name)) + return {name: depset(transitive = files) for name, files in groups.items()} + +def _alias_impl(ctx): + source = ctx.attr.src + files = getattr(source[OutputGroupInfo], ctx.attr.output_group) + return [ + DefaultInfo(files = files, runfiles = ctx.runfiles(transitive_files = files)), + OutputGroupInfo(**apple_slice_groups([source])), + ] + +# Use only for outputs of a constructor that consumes every forwarded slice. +# Compiler-output aliases can bypass that constructor and must use filegroup. +apple_slice_filegroup = rule( + implementation = _alias_impl, + attrs = { + "src": attr.label(mandatory = True), + "output_group": attr.string(mandatory = True), + }, +) diff --git a/build_defs/apple/testdata/expo-umbrella/AliasFixture.framework/Headers/AliasFixture/Root.h b/build_defs/apple/testdata/expo-umbrella/AliasFixture.framework/Headers/AliasFixture/Root.h new file mode 100644 index 000000000..da78ac7e6 --- /dev/null +++ b/build_defs/apple/testdata/expo-umbrella/AliasFixture.framework/Headers/AliasFixture/Root.h @@ -0,0 +1,3 @@ +#pragma once + +typedef int ExpoUmbrellaRootValue; diff --git a/build_defs/apple/testdata/expo-umbrella/AliasFixture.framework/Headers/AliasFixture_Alias/Alias.h b/build_defs/apple/testdata/expo-umbrella/AliasFixture.framework/Headers/AliasFixture_Alias/Alias.h new file mode 100644 index 000000000..fcbf6d27e --- /dev/null +++ b/build_defs/apple/testdata/expo-umbrella/AliasFixture.framework/Headers/AliasFixture_Alias/Alias.h @@ -0,0 +1,4 @@ +#import + +@interface ExpoUmbrellaAliasValue : NSObject +@end diff --git a/build_defs/apple/testdata/expo-umbrella/AliasFixture.framework/Info.plist b/build_defs/apple/testdata/expo-umbrella/AliasFixture.framework/Info.plist new file mode 100644 index 000000000..53b4a3ef3 --- /dev/null +++ b/build_defs/apple/testdata/expo-umbrella/AliasFixture.framework/Info.plist @@ -0,0 +1,14 @@ + + + + + CFBundleIdentifier + dev.oliphaunt.test.aliasfixture + CFBundleName + AliasFixture + CFBundlePackageType + FMWK + CFBundleVersion + 1 + + diff --git a/build_defs/apple/testdata/expo-umbrella/AliasFixture.framework/Modules/module.modulemap b/build_defs/apple/testdata/expo-umbrella/AliasFixture.framework/Modules/module.modulemap new file mode 100644 index 000000000..790f44c4e --- /dev/null +++ b/build_defs/apple/testdata/expo-umbrella/AliasFixture.framework/Modules/module.modulemap @@ -0,0 +1,11 @@ +framework module AliasFixture { + umbrella header "AliasFixture/Root.h" + export * + module * { export * } +} + +framework module AliasFixture_Alias { + umbrella header "AliasFixture_Alias/Alias.h" + export * + module * { export * } +} diff --git a/build_defs/apple/testdata/expo-umbrella/Base.swift b/build_defs/apple/testdata/expo-umbrella/Base.swift new file mode 100644 index 000000000..783877060 --- /dev/null +++ b/build_defs/apple/testdata/expo-umbrella/Base.swift @@ -0,0 +1,3 @@ +open class ExpoUmbrellaSwiftBase { + public init() {} +} diff --git a/build_defs/apple/testdata/expo-umbrella/Consumer.swift b/build_defs/apple/testdata/expo-umbrella/Consumer.swift new file mode 100644 index 000000000..a898fa342 --- /dev/null +++ b/build_defs/apple/testdata/expo-umbrella/Consumer.swift @@ -0,0 +1,9 @@ +import ExpoUmbrellaMixed + +public func expoUmbrellaChild() -> ExpoUmbrellaSwiftChild.Type { + ExpoUmbrellaSwiftChild.self +} + +public func expoUmbrellaNestedValue() -> Int32 { + expo_umbrella_nested_value() +} diff --git a/build_defs/apple/testdata/expo-umbrella/Headerless.swift b/build_defs/apple/testdata/expo-umbrella/Headerless.swift new file mode 100644 index 000000000..ecf415ab1 --- /dev/null +++ b/build_defs/apple/testdata/expo-umbrella/Headerless.swift @@ -0,0 +1,5 @@ +private let headerlessQueue = DispatchQueue(label: "oliphaunt.expo.headerless") + +func headerlessPodView(_ view: UIView) -> UIView { + headerlessQueue.sync { view } +} diff --git a/build_defs/apple/testdata/expo-umbrella/Mixed.h b/build_defs/apple/testdata/expo-umbrella/Mixed.h new file mode 100644 index 000000000..7217a625e --- /dev/null +++ b/build_defs/apple/testdata/expo-umbrella/Mixed.h @@ -0,0 +1,16 @@ +#ifndef OLIPHAUNT_EXPO_UMBRELLA_MIXED_H +#define OLIPHAUNT_EXPO_UMBRELLA_MIXED_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int expo_umbrella_fixture_value(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/build_defs/apple/testdata/expo-umbrella/Mixed.m b/build_defs/apple/testdata/expo-umbrella/Mixed.m new file mode 100644 index 000000000..7ade04945 --- /dev/null +++ b/build_defs/apple/testdata/expo-umbrella/Mixed.m @@ -0,0 +1,14 @@ +#import "Mixed.h" +@import AliasFixture_Alias; + +@interface ExpoUmbrellaObjcView : UIView +@end + +#import "MixedPrivate.h" + +@implementation ExpoUmbrellaObjcView +@end + +int expo_umbrella_fixture_value(void) { + return [ExpoUmbrellaSwiftValue value]; +} diff --git a/build_defs/apple/testdata/expo-umbrella/Mixed.swift b/build_defs/apple/testdata/expo-umbrella/Mixed.swift new file mode 100644 index 000000000..e1cd34802 --- /dev/null +++ b/build_defs/apple/testdata/expo-umbrella/Mixed.swift @@ -0,0 +1,21 @@ +import AliasFixture_Alias +import ExpoUmbrellaBase + +public final class ExpoUmbrellaSwiftChild: ExpoUmbrellaSwiftBase {} + +private let mixedQueue = DispatchQueue(label: "oliphaunt.expo.mixed") + +@objc public class ExpoUmbrellaSwiftValue: NSObject { + @objc public static func value() -> Int32 { 17 } + + @objc public static func aliasValue(_ value: ExpoUmbrellaAliasValue?) -> ExpoUmbrellaAliasValue? { + value + } +} + +func mixedPodView(_ view: UIView) -> UIView { + mixedQueue.sync { + precondition(expo_umbrella_fixture_value() == 17) + return view + } +} diff --git a/build_defs/apple/testdata/expo-umbrella/MixedPrivate.h b/build_defs/apple/testdata/expo-umbrella/MixedPrivate.h new file mode 100644 index 000000000..42e80f005 --- /dev/null +++ b/build_defs/apple/testdata/expo-umbrella/MixedPrivate.h @@ -0,0 +1,5 @@ +#if __has_include() +#import +#else +#import "ExpoUmbrellaMixed-Swift.h" +#endif diff --git a/build_defs/apple/testdata/expo-umbrella/include/ExpoUmbrellaMixed/Nested.h b/build_defs/apple/testdata/expo-umbrella/include/ExpoUmbrellaMixed/Nested.h new file mode 100644 index 000000000..a2fd60c4b --- /dev/null +++ b/build_defs/apple/testdata/expo-umbrella/include/ExpoUmbrellaMixed/Nested.h @@ -0,0 +1,6 @@ +#ifndef OLIPHAUNT_EXPO_UMBRELLA_NESTED_H +#define OLIPHAUNT_EXPO_UMBRELLA_NESTED_H + +static inline int expo_umbrella_nested_value(void) { return 17; } + +#endif diff --git a/build_defs/apple/testdata/expo56-original-apple-resolve.json b/build_defs/apple/testdata/expo56-original-apple-resolve.json new file mode 100644 index 000000000..362f82d4a --- /dev/null +++ b/build_defs/apple/testdata/expo56-original-apple-resolve.json @@ -0,0 +1,382 @@ +{ + "extraDependencies": [], + "coreFeatures": [], + "modules": [ + { + "packageName": "@expo/dom-webview", + "pods": [ + { + "podName": "ExpoDomWebView", + "podspecDir": ".packages/p_02b0918d72d615f3/node_modules/@expo/dom-webview/ios" + } + ], + "swiftModuleNames": ["ExpoDomWebView"], + "modules": [ + { + "name": null, + "class": "DomWebViewModule" + } + ], + "appDelegateSubscribers": [], + "reactDelegateHandlers": [], + "debugOnly": false, + "packageVersion": "56.0.6" + }, + { + "packageName": "@expo/log-box", + "pods": [ + { + "podName": "ExpoLogBox", + "podspecDir": ".packages/p_626e089100717ef8/node_modules/@expo/log-box" + } + ], + "swiftModuleNames": ["ExpoLogBox"], + "modules": [], + "appDelegateSubscribers": [], + "reactDelegateHandlers": [], + "debugOnly": false, + "packageVersion": "56.0.14" + }, + { + "packageName": "expo", + "pods": [ + { + "podName": "Expo", + "podspecDir": ".packages/p_05dc46537e801f37/node_modules/expo" + } + ], + "swiftModuleNames": ["Expo"], + "modules": [ + { + "name": null, + "class": "ExpoFetchModule" + } + ], + "appDelegateSubscribers": [], + "reactDelegateHandlers": [], + "debugOnly": false, + "packageVersion": "56.0.23" + }, + { + "packageName": "expo-asset", + "pods": [ + { + "podName": "ExpoAsset", + "podspecDir": ".packages/p_b1a7c87ee2d0fccf/node_modules/expo-asset/ios" + } + ], + "swiftModuleNames": ["ExpoAsset"], + "modules": [ + { + "name": null, + "class": "AssetModule" + } + ], + "appDelegateSubscribers": [], + "reactDelegateHandlers": [], + "debugOnly": false, + "packageVersion": "56.0.25" + }, + { + "packageName": "expo-constants", + "pods": [ + { + "podName": "EXConstants", + "podspecDir": ".packages/p_50f81f1ad14aaf61/node_modules/expo-constants/ios" + } + ], + "swiftModuleNames": ["EXConstants"], + "modules": [ + { + "name": null, + "class": "ConstantsModule" + } + ], + "appDelegateSubscribers": [], + "reactDelegateHandlers": [], + "debugOnly": false, + "packageVersion": "56.0.27" + }, + { + "packageName": "expo-dev-client", + "pods": [ + { + "podName": "expo-dev-client", + "podspecDir": ".packages/p_2b0adbd587a11921/node_modules/expo-dev-client/ios" + } + ], + "swiftModuleNames": ["expo_dev_client"], + "modules": [], + "appDelegateSubscribers": [], + "reactDelegateHandlers": [], + "debugOnly": false, + "packageVersion": "56.0.27" + }, + { + "packageName": "expo-dev-launcher", + "pods": [ + { + "podName": "expo-dev-launcher", + "podspecDir": ".packages/p_b4f4bd8c4d14525b/node_modules/expo-dev-launcher" + } + ], + "swiftModuleNames": ["EXDevLauncher"], + "modules": [ + { + "name": null, + "class": "DevLauncherModule" + } + ], + "appDelegateSubscribers": ["ExpoDevLauncherAppDelegateSubscriber"], + "reactDelegateHandlers": ["ExpoDevLauncherReactDelegateHandler"], + "debugOnly": true, + "packageVersion": "56.0.28" + }, + { + "packageName": "expo-dev-menu", + "pods": [ + { + "podName": "expo-dev-menu", + "podspecDir": ".packages/p_d4532a828717181d/node_modules/expo-dev-menu" + } + ], + "swiftModuleNames": ["EXDevMenu"], + "modules": [ + { + "name": null, + "class": "DevMenuModule" + }, + { + "name": null, + "class": "DevMenuPreferences" + } + ], + "appDelegateSubscribers": [], + "reactDelegateHandlers": [], + "debugOnly": true, + "packageVersion": "56.0.23" + }, + { + "packageName": "expo-dev-menu-interface", + "pods": [ + { + "podName": "expo-dev-menu-interface", + "podspecDir": ".packages/p_bd960b9594aa4235/node_modules/expo-dev-menu-interface/ios" + } + ], + "swiftModuleNames": ["expo_dev_menu_interface"], + "modules": [], + "appDelegateSubscribers": [], + "reactDelegateHandlers": [], + "debugOnly": false, + "packageVersion": "56.0.1" + }, + { + "packageName": "expo-file-system", + "pods": [ + { + "podName": "ExpoFileSystem", + "podspecDir": ".packages/p_9899a5eea7cae290/node_modules/expo-file-system/ios" + } + ], + "swiftModuleNames": ["ExpoFileSystem"], + "modules": [ + { + "name": null, + "class": "FileSystemModule" + }, + { + "name": null, + "class": "FileSystemLegacyModule" + } + ], + "appDelegateSubscribers": ["FileSystemBackgroundSessionHandler"], + "reactDelegateHandlers": [], + "debugOnly": false, + "packageVersion": "56.0.11" + }, + { + "packageName": "expo-font", + "pods": [ + { + "podName": "ExpoFont", + "podspecDir": ".packages/p_6403c4eef8623a02/node_modules/expo-font/ios" + } + ], + "swiftModuleNames": ["ExpoFont"], + "modules": [ + { + "name": null, + "class": "FontLoaderModule" + }, + { + "name": null, + "class": "FontUtilsModule" + } + ], + "appDelegateSubscribers": [], + "reactDelegateHandlers": [], + "debugOnly": false, + "packageVersion": "56.0.7" + }, + { + "packageName": "expo-json-utils", + "pods": [ + { + "podName": "EXJSONUtils", + "podspecDir": ".packages/p_245fc051c25ff0dd/node_modules/expo-json-utils/ios" + } + ], + "swiftModuleNames": ["EXJSONUtils"], + "modules": [], + "appDelegateSubscribers": [], + "reactDelegateHandlers": [], + "debugOnly": false, + "packageVersion": "56.0.0" + }, + { + "packageName": "expo-keep-awake", + "pods": [ + { + "podName": "ExpoKeepAwake", + "podspecDir": ".packages/p_f48a24ce71dc7f34/node_modules/expo-keep-awake/ios" + } + ], + "swiftModuleNames": ["ExpoKeepAwake"], + "modules": [ + { + "name": null, + "class": "KeepAwakeModule" + } + ], + "appDelegateSubscribers": [], + "reactDelegateHandlers": [], + "debugOnly": false, + "packageVersion": "56.0.3" + }, + { + "packageName": "expo-manifests", + "pods": [ + { + "podName": "EXManifests", + "podspecDir": ".packages/p_133ae131d6ea0497/node_modules/expo-manifests/ios" + } + ], + "swiftModuleNames": ["EXManifests"], + "modules": [], + "appDelegateSubscribers": [], + "reactDelegateHandlers": [], + "debugOnly": false, + "packageVersion": "56.0.4" + }, + { + "packageName": "expo-modules-core", + "pods": [ + { + "podName": "ExpoModulesCore", + "podspecDir": ".packages/p_0a3cd85a01520463/node_modules/expo-modules-core" + }, + { + "podName": "ExpoModulesWorklets", + "podspecDir": ".packages/p_0a3cd85a01520463/node_modules/expo-modules-core" + } + ], + "swiftModuleNames": ["ExpoModulesCore", "ExpoModulesWorklets"], + "modules": [], + "appDelegateSubscribers": [], + "reactDelegateHandlers": [], + "debugOnly": false, + "packageVersion": "56.0.27" + }, + { + "packageName": "expo-modules-jsi", + "pods": [ + { + "podName": "ExpoModulesJSI", + "podspecDir": ".packages/p_afffe0fa04af4c2d/node_modules/expo-modules-jsi/apple" + } + ], + "swiftModuleNames": ["ExpoModulesJSI"], + "modules": [], + "appDelegateSubscribers": [], + "reactDelegateHandlers": [], + "debugOnly": false, + "packageVersion": "56.0.14" + }, + { + "packageName": "expo-splash-screen", + "pods": [ + { + "podName": "ExpoSplashScreen", + "podspecDir": ".packages/p_2485d80995f2dc5d/node_modules/expo-splash-screen/ios" + } + ], + "swiftModuleNames": ["ExpoSplashScreen"], + "modules": [ + { + "name": null, + "class": "SplashScreenModule" + } + ], + "appDelegateSubscribers": ["SplashScreenAppDelegateSubscriber"], + "reactDelegateHandlers": [], + "debugOnly": false, + "packageVersion": "56.0.15" + }, + { + "packageName": "expo-sqlite", + "pods": [ + { + "podName": "ExpoSQLite", + "podspecDir": ".packages/p_289920bd2cf70733/node_modules/expo-sqlite/ios" + } + ], + "swiftModuleNames": ["ExpoSQLite"], + "modules": [ + { + "name": null, + "class": "SQLiteModule" + } + ], + "appDelegateSubscribers": [], + "reactDelegateHandlers": [], + "debugOnly": false, + "packageVersion": "56.0.6" + }, + { + "packageName": "expo-system-ui", + "pods": [ + { + "podName": "ExpoSystemUI", + "podspecDir": ".packages/p_f37028bbc1e5a22c/node_modules/expo-system-ui/ios" + } + ], + "swiftModuleNames": ["ExpoSystemUI"], + "modules": [ + { + "name": null, + "class": "ExpoSystemUIModule" + } + ], + "appDelegateSubscribers": [], + "reactDelegateHandlers": [], + "debugOnly": false, + "packageVersion": "56.0.5" + }, + { + "packageName": "expo-updates-interface", + "pods": [ + { + "podName": "EXUpdatesInterface", + "podspecDir": ".packages/p_17b4e767f0c555d5/node_modules/expo-updates-interface/ios" + } + ], + "swiftModuleNames": ["EXUpdatesInterface"], + "modules": [], + "appDelegateSubscribers": [], + "reactDelegateHandlers": [], + "debugOnly": false, + "packageVersion": "56.0.2" + } + ] +} diff --git a/build_defs/apple/testdata/swift-0.8.2-original-Package.swift b/build_defs/apple/testdata/swift-0.8.2-original-Package.swift new file mode 100644 index 000000000..27ee71012 --- /dev/null +++ b/build_defs/apple/testdata/swift-0.8.2-original-Package.swift @@ -0,0 +1,73 @@ +// swift-tools-version: 6.0 + +import PackageDescription + +// Generated by src/native/sdks/swift/tools/render_swiftpm_release_package.mts. +// This is the public SwiftPM release manifest. The source package under +// src/native/sdks/swift remains the local development package. +// Exact PostgreSQL extensions are released as separate opt-in extension +// artifacts. The base Swift package must not require or publish extension files. +let package = Package( + name: "Oliphaunt", + platforms: [ + .iOS(.v17), + .macOS(.v14) + ], + products: [ + .library(name: "COliphaunt", targets: ["COliphaunt"]), + .library(name: "Oliphaunt", targets: ["Oliphaunt"]), + .library(name: "OliphauntCore", targets: ["OliphauntCore"]), + .library(name: "OliphauntBroker", targets: ["OliphauntBroker"]), + .library(name: "OliphauntBrokerExtension", targets: ["OliphauntBrokerExtension"]), + .library(name: "OliphauntExtensionSupport", targets: ["OliphauntExtensionSupport"]) + ], + targets: [ + .binaryTarget( + name: "OliphauntNativeBindingsFFI", + url: "https://github.com/f0rr0/oliphaunt/releases/download/oliphaunt-swift-v0.8.2/oliphaunt-swift-0.8.2-bindings.xcframework.zip", + checksum: "118c2fc8634e2e6d652797b279f45a693cbe2a5be314fb40760c02204d844441" + ), + .target( + name: "OliphauntNativeBindings", + dependencies: ["OliphauntNativeBindingsFFI"], + path: "src/sdks/swift/Sources/OliphauntNativeBindings" + ), + .binaryTarget( + name: "liboliphaunt", + url: "https://github.com/f0rr0/oliphaunt/releases/download/liboliphaunt-native-v0.3.3/liboliphaunt-0.3.3-apple-spm-xcframework.zip", + checksum: "e6311658046cb2714bc0c1a7c5610f6ce36cda2156c8092aea21500cce7f2ba1" + ), + .target( + name: "COliphaunt", + dependencies: ["liboliphaunt"], + path: "src/sdks/swift/Sources/COliphaunt", + publicHeadersPath: "include", + cSettings: [.define("OLIPHAUNT_LINK_RUNTIME")] + ), + .target( + name: "OliphauntCore", + dependencies: ["OliphauntNativeBindings"], + path: "src/sdks/swift/Sources/OliphauntCore" + ), + .target( + name: "OliphauntBroker", + dependencies: ["OliphauntCore", "OliphauntNativeBindings"], + path: "src/sdks/swift/Sources/OliphauntBroker" + ), + .target( + name: "OliphauntBrokerExtension", + dependencies: ["Oliphaunt", "OliphauntCore", "OliphauntNativeBindings"], + path: "src/sdks/swift/Sources/OliphauntBrokerExtension" + ), + .target( + name: "Oliphaunt", + dependencies: ["COliphaunt", "OliphauntCore", "OliphauntNativeBindings"], + path: "src/sdks/swift/Sources/Oliphaunt" + ), + .target( + name: "OliphauntExtensionSupport", + dependencies: ["COliphaunt", "Oliphaunt"], + path: "src/sdks/swift/Sources/OliphauntExtensionSupport" + ) + ] +) diff --git a/build_defs/apple/testdata/swift-context/Bridge.h b/build_defs/apple/testdata/swift-context/Bridge.h new file mode 100644 index 000000000..4237d8f53 --- /dev/null +++ b/build_defs/apple/testdata/swift-context/Bridge.h @@ -0,0 +1,7 @@ +#ifndef OLIPHAUNT_SWIFT_CONTEXT_BRIDGE_H +#define OLIPHAUNT_SWIFT_CONTEXT_BRIDGE_H +#ifdef __cplusplus +#include +#endif +static inline int bridge_marker(void) { return 42; } +#endif diff --git a/build_defs/apple/testdata/swift-context/Bridge.swift b/build_defs/apple/testdata/swift-context/Bridge.swift new file mode 100644 index 000000000..4094746ba --- /dev/null +++ b/build_defs/apple/testdata/swift-context/Bridge.swift @@ -0,0 +1,2 @@ +@_exported import CBridge +public func bridgeMarker() -> Int { 42 } diff --git a/build_defs/apple/testdata/swift-context/CallInvoker.h b/build_defs/apple/testdata/swift-context/CallInvoker.h new file mode 100644 index 000000000..862073f6f --- /dev/null +++ b/build_defs/apple/testdata/swift-context/CallInvoker.h @@ -0,0 +1,10 @@ +#ifndef OLIPHAUNT_SWIFT_CONTEXT_CALL_INVOKER_H +#define OLIPHAUNT_SWIFT_CONTEXT_CALL_INVOKER_H +#if !defined(__cplusplus) || __cplusplus < 202002L +#error OLIPHAUNT_SWIFT_CONTEXT_CXX20_REQUIRED +#endif +#if !defined(OLIPHAUNT_SWIFT_CONTEXT_REQUIRED) || OLIPHAUNT_SWIFT_CONTEXT_REQUIRED != 17 +#error OLIPHAUNT_SWIFT_CONTEXT_DEFINE_REQUIRED +#endif +static inline int oliphaunt_swift_context_marker(void) { return 17; } +#endif diff --git a/build_defs/apple/testdata/swift-context/Consumer.swift b/build_defs/apple/testdata/swift-context/Consumer.swift new file mode 100644 index 000000000..644d5405f --- /dev/null +++ b/build_defs/apple/testdata/swift-context/Consumer.swift @@ -0,0 +1,4 @@ +import Bridge +public func consumerMarker() -> Int { + bridgeMarker() + Int(oliphaunt_swift_context_marker()) +} diff --git a/build_defs/apple/testdata/swift-context/module.modulemap b/build_defs/apple/testdata/swift-context/module.modulemap new file mode 100644 index 000000000..930f63e4c --- /dev/null +++ b/build_defs/apple/testdata/swift-context/module.modulemap @@ -0,0 +1,4 @@ +module CBridge { + header "Bridge.h" + export * +} diff --git a/build_defs/apple/testdata/swift-context/react.yaml b/build_defs/apple/testdata/swift-context/react.yaml new file mode 100644 index 000000000..9d3ea9b60 --- /dev/null +++ b/build_defs/apple/testdata/swift-context/react.yaml @@ -0,0 +1,8 @@ +{ + "version": 0, + "roots": [{"type": "directory", "name": "oliphaunt-swift-context/Headers", "contents": [ + {"type": "directory", "name": "ReactCommon", "contents": [ + {"type": "file", "name": "CallInvoker.h", "external-contents": "build_defs/apple/testdata/swift-context/CallInvoker.h"} + ]} + ]}] +} diff --git a/build_defs/extensions/BUILD.bazel b/build_defs/extensions/BUILD.bazel new file mode 100644 index 000000000..7160ffc69 --- /dev/null +++ b/build_defs/extensions/BUILD.bazel @@ -0,0 +1,320 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/foundation:bun.bzl", "bun_binary", "bun_test") +load("@rules_cc//cc:defs.bzl", "cc_binary") +load("@rules_shell//shell:sh_test.bzl", "sh_test") +load(":extensions.bzl", "extension_default_version", "extension_perl_runtime") +load(":smoke.bzl", "desktop_members_sql_test", "native_extension_sql_test") +load("@oliphaunt_metadata//:metadata.bzl", "CONTRIB_MEMBERS", "EXTENSION_COMPATIBILITY") +load("//build_defs/extensions:platforms.bzl", NATIVE_EXTENSION_COMPATIBLE = "NATIVE_EXTENSION_LINUX_COMPATIBLE", NATIVE_EXTENSION_DESKTOP_COMPATIBLE = "NATIVE_EXTENSION_COMPATIBLE") +load(":native_carriers.bzl", "native_extension_carrier_helpers", "native_extension_carrier_legal", "native_extension_carrier_unit_inputs") +load("//build_defs/foundation:bun.bzl", "bun_script_test") +load(":contrib_carriers.bzl", "native_contrib_carrier_legal", "native_contrib_carrier_unit_inputs") +load(":owner_carriers.bzl", "native_extension_final_collection", "native_extension_final_contract_test", "native_extension_final_import", "native_extension_final_receipt_fixture", "native_owner_carrier_helpers", "native_owner_carrier_legal") +load(":construction.bzl", "desktop_member_payloads", "desktop_members_construction_test") +load(":wasix_carriers.bzl", "wasix_sql_carrier_helpers", "wasix_sql_carrier_unit_inputs") +load(":declared_final_inputs.bzl", "native_declared_apple_base") +load(":family_carriers.bzl", "native_extension_final_families") +load(":forced_header_inputs_test.bzl", "native_forced_header_input_tests") +load(":windows_module_test.bzl", "native_windows_module_tests") +load(":mobile_host_profile_test.bzl", "mobile_host_profile_tests") + +package(default_visibility = ["//visibility:public"]) + +native_forced_header_input_tests() +native_windows_module_tests() +mobile_host_profile_tests() + +exports_files(["contrib.bzl", "extensions.bzl", "repositories.bzl", "uuid_config.h", "pgtap_upstream_parity_test.mts", "validate_member_payload.mts"]) +exports_files(["native_extension_all_sql_test.sh"]) +exports_files(["native_carriers.bzl", "native_carriers.mts", "native_carriers_installed.test.mts"]) +exports_files(["contrib_carriers.bzl", "contrib_carriers.mts", "contrib_carriers_installed.test.mts"]) +exports_files(["native_carrier_install_helpers.mts"]) +exports_files(["final_leaf.bzl", "owner_carriers.bzl", "owner_carriers.mts", "final_receipt_fixture.mts", "final_contract.test.mts"]) +exports_files(["wasix_carriers.bzl", "wasix_carriers.mts", "wasix_carriers.test.mts"]) +exports_files(["mobile.bzl", "mobile_carriers.bzl", "mobile_carriers.mts", "mobile_registration.mts", "mobile_members.bzl", "mobile_consumer.c", "mobile_maven.mts"]) +exports_files(["declared_final_inputs.bzl", "declared_final_inputs.mts", "family_carriers.bzl", "family_contract.test.mts"]) +exports_files(["imported_members.bzl", "imported_member.mts"]) + +native_declared_apple_base(name = "declared_native_apple_base") +native_extension_final_families(base_carrier_manifest = ":declared_native_apple_base") + +bun_test( + name = "imported_member_test", + entry_point = "imported_member.test.mts", + data = {label: True for label in ["imported_member.mts", "member_payload.mts", "owner_carriers.mts", "declared_final_inputs.mts", + "//build_defs/native:rust-runtime-test.mts", "//build_defs/native:host-runtime-test-helpers.mts", + "//:tools/packaging/testdata/release-fixture-utils.mts", + "//src/extensions/catalog:extensions.source.json", "//src/extensions/contrib:postgres18.toml"] + + native_owner_carrier_helpers() + native_owner_carrier_legal("oliphaunt-extension-vector") + + native_owner_carrier_legal("oliphaunt-extension-contrib-pg18")}.keys(), + size = "small", +) + +bun_test( + name = "declared_final_inputs_test", + entry_point = "declared_final_inputs.test.mts", + data = ["declared_final_inputs.mts", "owner_carriers.mts", "//tools/release:native-extension-final-inputs.mts", "//build_defs/release:testdata/swift-0.8.2-carrier.json"] + native_owner_carrier_helpers(), + size = "small", +) + +bun_test( + name = "declared_apple_archives_test", + entry_point = "declared_apple_archives.test.mts", + data = native_owner_carrier_helpers(), + size = "small", +) + +bun_test(name = "mobile_registration_test", entry_point = "mobile_registration.test.mts", data = ["mobile_registration.mts", "//:src/extensions/artifacts/native/tools/ios-extension-registration.mts"] + native_extension_carrier_helpers(), size = "small") +bun_test(name = "mobile_carriers_test", entry_point = "mobile_carriers.test.mts", data = ["mobile_carriers.mts", "mobile_registration.mts", "//src/native/sdks/swift:tools/swift-xcframework-contract.mts"] + native_owner_carrier_helpers(), size = "small") +bun_test(name = "mobile_maven_test", entry_point = "mobile_maven.test.mts", data = ["@pgvector_compiler_rt//:LICENSE.TXT", "//:tools/packaging/build-maven-artifact-manifest.mts", "//:tools/packaging/maven-artifact-manifest.mts", "//:tools/packaging/maven-artifact-staging.mts", "//:tools/packaging/maven-central-contract.mts", "//:tools/packaging/atomic-directory.mts", "//tools/release:compatibility-version-policy.mts", "//tools/release:product-version.mts"] + native_owner_carrier_helpers() + native_owner_carrier_legal("oliphaunt-extension-vector"), size = "small") + +wasix_sql_carrier_unit_inputs(name = "wasix_sql_carrier_unit_inputs") +bun_script_test( + name = "wasix_sql_carriers_test", + entry_point = "wasix_carriers.test.mts", + args = ["$(location :wasix_sql_carrier_unit_inputs)"], + data = [":wasix_sql_carrier_unit_inputs", "wasix_carriers.mts"] + wasix_sql_carrier_helpers() + native_extension_carrier_legal("pgtap"), + target_compatible_with = ["@platforms//os:linux"], + size = "small", +) + +native_extension_final_contract_test( + name = "native_final_contract_test", + target_compatible_with = NATIVE_EXTENSION_COMPATIBLE, + size = "medium", +) +native_extension_final_contract_test( + name = "desktop_final_contract_test", + desktop = True, + target_compatible_with = NATIVE_EXTENSION_DESKTOP_COMPATIBLE, + size = "medium", +) +native_extension_final_contract_test( + name = "desktop_all_final_contract_test", + desktop = True, + include_postgis = True, + target_compatible_with = NATIVE_EXTENSION_DESKTOP_COMPATIBLE, + size = "medium", +) +exports_files(["construction.mts"]) +exports_files(["desktop_sql.test.mts"]) + +native_extension_final_receipt_fixture(name = "native_pgtap_receipt_fixture", leaf = "//src/extensions/external/pgtap:native_carriers", testonly = True, target_compatible_with = NATIVE_EXTENSION_COMPATIBLE) +native_extension_final_import( + name = "native_pgtap_import_fixture", product = "oliphaunt-extension-pgtap", target = "linux-x64-gnu", testonly = True, + github = ["//src/extensions/external/pgtap:native_github_shipping_files"], npm = ["//src/extensions/external/pgtap:native_npm_shipping_files"], cargo = ["//src/extensions/external/pgtap:native_cargo_shipping_files"], + manifest = "//src/extensions/external/pgtap:native_manifest_shipping_files", frozen = "//src/extensions/external/pgtap:native_frozen_shipping_files", receipt = ":native_pgtap_receipt_fixture", + source_commit = "1" * 40, source_tree = "2" * 40, run_id = "123", run_attempt = 1, job = "test-only-receipt-fixture", target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) +filegroup(name = "native_pgtap_import_fixture_validation", srcs = [":native_pgtap_import_fixture"], output_group = "validation", testonly = True) +native_extension_final_collection(name = "native_pgtap_import_collection_fixture", product = "oliphaunt-extension-pgtap", leaves = [":native_pgtap_import_fixture"], testonly = True, target_compatible_with = NATIVE_EXTENSION_COMPATIBLE) + +native_extension_final_collection( + name = "native_pgtap_final_collection", + product = "oliphaunt-extension-pgtap", + leaves = ["//src/extensions/external/pgtap:native_carriers"], + target_compatible_with = NATIVE_EXTENSION_DESKTOP_COMPATIBLE, +) +native_extension_final_collection( + name = "native_contrib_final_collection", + product = "oliphaunt-extension-contrib-pg18", + leaves = ["//src/extensions/contrib:native_carriers"], + target_compatible_with = NATIVE_EXTENSION_DESKTOP_COMPATIBLE, +) +native_extension_final_collection( + name = "native_postgis_final_collection", + product = "oliphaunt-extension-postgis", + leaves = ["//src/extensions/external/postgis:native_carriers"], + target_compatible_with = NATIVE_EXTENSION_COMPATIBLE, +) +filegroup(name = "native_pgtap_final_collection_spec", srcs = [":native_pgtap_final_collection"], output_group = "spec") +filegroup(name = "native_contrib_final_collection_spec", srcs = [":native_contrib_final_collection"], output_group = "spec") +filegroup(name = "native_postgis_final_collection_spec", srcs = [":native_postgis_final_collection"], output_group = "spec") +bun_script_test( + name = "native_final_composition_test", + entry_point = "owner_carriers.test.mts", + args = ["$(location :native_pgtap_final_collection_spec)", "$(location :native_contrib_final_collection_spec)", "$(location :native_pgtap_final_collection)", "$(location :native_contrib_final_collection)", "$(location :native_pgtap_import_fixture_validation)", "$(location :native_postgis_final_collection_spec)", "$(location :native_postgis_final_collection)", "$(location :native_pgtap_import_collection_fixture)"], + data = {label: True for label in [":native_pgtap_final_collection_spec", ":native_contrib_final_collection_spec", ":native_postgis_final_collection_spec", ":native_pgtap_final_collection", ":native_contrib_final_collection", ":native_postgis_final_collection", ":native_pgtap_import_fixture_validation", ":native_pgtap_import_collection_fixture", "//src/extensions/external/pgtap:native_carriers", "//src/extensions/external/postgis:native_carriers", "//src/extensions/contrib:native_carriers", "owner_carriers.mts", "//src/extensions/catalog:native-components.toml"] + native_owner_carrier_helpers() + native_owner_carrier_legal("oliphaunt-extension-contrib-pg18") + native_owner_carrier_legal("oliphaunt-extension-pgtap") + native_owner_carrier_legal("oliphaunt-extension-postgis")}.keys(), + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + size = "medium", +) + +ARCHIVE_HELPERS = ["//:tools/packaging/archive-directory.mts", "//:tools/packaging/portable-archive.mts"] +BINARY_HELPERS = ["//:tools/packaging/platform-binary-contract.mts", "//:tools/packaging/windows-vc-runtime-closure.mts", "//:tools/packaging/windows-vc-runtime-policy.json", "//tools/release:platform-compatibility-policy.mts", "//:src/extensions/artifacts/native/tools/stage-windows-binary-contract.mts"] + +desktop_members_construction_test(name = "desktop_members_construction_test", size = "medium") +desktop_members_construction_test(name = "desktop_all_members_construction_test", include_postgis = True, size = "medium") +desktop_members_sql_test(name = "desktop_members_sql_test") +FROZEN_DESKTOP_HOST_COMPATIBLE = select({ + "//build_defs/native:linux_x86_64": [], + "//build_defs/native:macos_arm64": [], + "//build_defs/native:windows_x64": [], + "//conditions:default": ["@platforms//:incompatible"], +}) +filegroup( + name = "desktop_frozen_runtime_archive", + srcs = select({ + "//build_defs/native:macos_arm64": ["@extension_frozen_native_macos//:archive_macos_arm64"], + "//build_defs/native:windows_x64": ["@extension_frozen_native_windows//:archive_windows_x64_msvc"], + "//conditions:default": ["@extension_frozen_native//:archive_linux_x64_gnu"], + }), + testonly = True, + target_compatible_with = FROZEN_DESKTOP_HOST_COMPATIBLE, +) +desktop_members_sql_test( + name = "desktop_members_frozen_sql_test", + runtime = ":desktop_frozen_runtime_archive", + consumer = ":native_frozen_extension_smoke", + host_version = EXTENSION_COMPATIBILITY["vector"]["native_runtime_version"], + host_product = EXTENSION_COMPATIBILITY["vector"]["native_runtime_product"], + runtime_prefix = "runtime", + published_runtime = True, + target_compatible_with = FROZEN_DESKTOP_HOST_COMPATIBLE, +) +desktop_members_sql_test( + name = "desktop_all_members_frozen_sql_test", + include_postgis = True, + runtime = ":desktop_frozen_runtime_archive", + consumer = ":native_frozen_extension_smoke", + host_version = EXTENSION_COMPATIBILITY["postgis"]["native_runtime_version"], + host_product = EXTENSION_COMPATIBILITY["postgis"]["native_runtime_product"], + runtime_prefix = "runtime", + published_runtime = True, + target_compatible_with = FROZEN_DESKTOP_HOST_COMPATIBLE, +) +filegroup(name = "desktop_members_construction_inventory", srcs = [":desktop_members_construction_test"], output_group = "inventory", testonly = True) +filegroup(name = "desktop_all_members_construction_inventory", srcs = [":desktop_all_members_construction_test"], output_group = "inventory", testonly = True) +bun_test( + name = "desktop_construction_test", + entry_point = "construction.test.mts", + data = ["construction.mts", "validate_member_payload.mts"] + ARCHIVE_HELPERS + BINARY_HELPERS, + size = "small", +) + +native_extension_carrier_unit_inputs(name = "native_carrier_unit_inputs") +native_contrib_carrier_unit_inputs(name = "contrib_carrier_unit_inputs") +bun_script_test( + name = "contrib_carriers_test", + entry_point = "contrib_carriers.test.mts", + args = ["$(location :contrib_carrier_unit_inputs)"], + data = [":contrib_carrier_unit_inputs", "contrib_carriers.mts", "native_carriers.mts", "//:src/extensions/artifacts/packages/tools/bundle-carrier-assets.mts"] + native_extension_carrier_helpers() + native_contrib_carrier_legal(), + size = "small", +) +test_suite( + name = "native_final_carriers_tests", + tests = ["//src/extensions/external/" + name + ":native_carriers_test" for name in sorted(EXTENSION_COMPATIBILITY.keys())], +) + +bun_script_test( + name = "native_carriers_test", + entry_point = "native_carriers.test.mts", + args = ["$(location :native_carrier_unit_inputs)"] + select({"//build_defs/native:windows_x64": [], "//conditions:default": ["$(location //src/native/runtime/packaging:resources)"]}), + data = {label: True for label in [":native_carrier_unit_inputs", "native_carriers.mts", "member_payload.mts", "//:tools/packaging/npm-package.test.mts", "//:tools/packaging/testdata/release-fixture-utils.mts"] + native_extension_carrier_helpers() + native_extension_carrier_legal("pgtap") + native_extension_carrier_legal("postgis")}.keys() + select({"//build_defs/native:windows_x64": [], "//conditions:default": ["//src/native/runtime/packaging:resources"]}), + size = "small", +) + +bun_binary(name = "pgtap_sql", entry_point = "pgtap_sql.mts") +bun_binary(name = "windows_source_inputs", entry_point = "windows_source_inputs.mts", data = ["windows_source_portability.mts"]) +bun_test(name = "windows_source_portability_test", entry_point = "windows_source_portability.test.mts", data = ["windows_source_portability.mts"], size = "small") +bun_test(name = "windows_source_inputs_test", entry_point = "windows_source_inputs.test.mts", data = ["windows_source_inputs.mts", "windows_source_portability.mts"], size = "small") +extension_perl_runtime(name = "perl_runtime") +filegroup(name = "perl", srcs = [":perl_runtime"], output_group = "interpreter") +filegroup(name = "perl_options", srcs = [":perl_runtime"], output_group = "options") +bun_binary(name = "smoke_plan", entry_point = "smoke_plan.mts") +bun_binary(name = "member_payload", entry_point = "member_payload.mts", data = ARCHIVE_HELPERS) +bun_binary(name = "validate_member_payload", entry_point = "validate_member_payload.mts", data = ["//:tools/packaging/portable-archive.mts"] + BINARY_HELPERS) +bun_binary( + name = "sdk_projections", + entry_point = "sdk_projections.mts", + data = [ + "//src/extensions/tools:extension-projections.mts", + "//src/extensions/tools:native-component-contract.mts", + "//src/extensions/contracts:extension-target-profiles.mts", + ], +) + +bun_test( + name = "pgtap_sql_test", + entry_point = "pgtap_sql.test.mts", + data = ["pgtap_sql.mts"], + size = "small", +) + +native_extension_sql_test( + name = "native_built_extension_sql_test", + members = ["//src/extensions/contrib:" + member["id"] + "_native_payload" for member in CONTRIB_MEMBERS] + + ["//src/extensions/external/" + name + ":native_payload" for name in ["pg_hashids", "pg_uuidv7", "pg_ivm", "pg_textsearch", "pgtap", "vector", "postgis"]], +) + +native_extension_sql_test( + name = "native_postgis_sql_test", + members = ["//src/extensions/external/postgis:native_payload"], +) + +native_extension_sql_test( + name = "native_frozen_postgis_sql_test", + members = ["//src/extensions/external/postgis:native_payload"], + runtime = "@extension_frozen_native//:archive_linux_x64_gnu", + consumer = ":native_frozen_extension_smoke", + host_version = EXTENSION_COMPATIBILITY["postgis"]["native_runtime_version"], + host_product = EXTENSION_COMPATIBILITY["postgis"]["native_runtime_product"], + runtime_prefix = "runtime", + library_prefix = "lib", + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) + +native_extension_sql_test( + name = "native_frozen_extension_sql_test", + members = desktop_member_payloads() + ["//src/extensions/external/postgis:native_payload"], + runtime = "@extension_frozen_native//:archive_linux_x64_gnu", + consumer = ":native_frozen_extension_smoke", + host_version = EXTENSION_COMPATIBILITY["postgis"]["native_runtime_version"], + host_product = EXTENSION_COMPATIBILITY["postgis"]["native_runtime_product"], + runtime_prefix = "runtime", + library_prefix = "lib", + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) + +cc_binary( + name = "native_extension_smoke", + srcs = ["native_extension_smoke.c"], + deps = ["//src/native/runtime:liboliphaunt"], + copts = select({"//build_defs/native:windows_x64": ["/std:c11"], "//conditions:default": ["-std=c11", "-Wall", "-Wextra", "-Werror"]}), + target_compatible_with = NATIVE_EXTENSION_DESKTOP_COMPATIBLE, +) + +cc_binary( + name = "native_frozen_extension_smoke", + srcs = ["native_extension_smoke.c"], + deps = select({ + "//build_defs/native:macos_arm64": ["@extension_frozen_native_macos//:cc_macos_arm64"], + "//build_defs/native:windows_x64": ["@extension_frozen_native_windows//:cc_windows_x64_msvc"], + "//conditions:default": ["@extension_frozen_native//:cc_linux_x64_gnu"], + }), + copts = select({"//build_defs/native:windows_x64": ["/std:c11"], "//conditions:default": ["-std=c11", "-Wall", "-Wextra", "-Werror"]}), + target_compatible_with = FROZEN_DESKTOP_HOST_COMPATIBLE, +) + +filegroup(name = "pgtap_archive", srcs = ["//src/extensions/external/pgtap:native_payload"], output_group = "archive") +filegroup(name = "pg_trgm_archive", srcs = ["//src/extensions/contrib:pg_trgm_native_payload"], output_group = "archive") +filegroup(name = "vector_archive", srcs = ["//src/extensions/external/vector:native_payload"], output_group = "archive") + +sh_test( + name = "native_extension_sql_test", + srcs = ["native_extension_sql_test.sh"], + args = ["$(location //src/native/runtime:runtime_payload)", "$(location :native_extension_smoke)", + extension_default_version("pg_trgm"), extension_default_version("vector"), extension_default_version("pgtap"), + "$(location :pgtap_archive)", "$(location :pg_trgm_archive)", "$(location :vector_archive)"], + data = ["//src/native/runtime:runtime_payload", ":native_extension_smoke", ":pgtap_archive", ":pg_trgm_archive", ":vector_archive"], + target_compatible_with = NATIVE_EXTENSION_COMPATIBLE, + size = "medium", +) + +bun_test( + name = "member_payload_test", + entry_point = "member_payload.test.mts", + data = ["member_payload.mts", "validate_member_payload.mts", "//:tools/packaging/testdata/release-fixture-utils.mts"] + ARCHIVE_HELPERS + BINARY_HELPERS, + size = "small", +) + +source_quality_files() diff --git a/build_defs/extensions/README.md b/build_defs/extensions/README.md new file mode 100644 index 000000000..a8d975bd1 --- /dev/null +++ b/build_defs/extensions/README.md @@ -0,0 +1,88 @@ +# Native extension construction + +The native graph constructs all 32 PostgreSQL 18 contrib members and the seven +external extensions on Linux. The qualified Linux x86_64 glibc 2.28 profile has +passed actual SQL consumers for all 39 members, with separate archive validators. Linux +ARM64 has passed the earlier 37-member construction batch; the completed +pgcrypto/PostGIS graph and latest vector recipe still require ARM64 qualification. +The extension rules remain incompatible with other native platforms until their +module and dependency recipes are implemented and tested. + +Source pins, SQL defaults, release identities, carrier ownership and permitted +resources come from `@oliphaunt_metadata`, imported from existing descriptors. +External source repositories use full immutable Git commits. The Bazel importer +uses the reviewed Git mirror as the fetch remote when one is declared, +while preserving the canonical upstream URL and exact commit as source identity. +Stock Bazel Git repository rules accept one remote; they do not implement +canonical-to-mirror failover. Archive sources retain their declared URL list. +The pgTAP tool expands the pinned SQL inputs and compatibility patches with +TypeScript using pinned Bun, then invokes the exact upstream gencore and uninstall Perl code +through the declared Perl toolchain. It does not invoke PGXS, Make or pg_config. +Its Makefile recipe fingerprint fails closed when installation semantics change. +The per-pin parity test compares all installed bytes with real upstream +patch/Perl execution; it never calls the production TypeScript patch implementation. + +C members compile twice through ordinary CcInfo: server headers for +`lib/postgresql`, and embedded headers plus liboliphaunt for `lib/modules`. +Those files are independent compiler outputs. Packaging maps resource paths +explicitly and emits deterministic internal tar archives and inventories. +The independent reader inspects actual archive entries, SQL installation paths, +checksums, module ELF architecture and expected carrier identity. + +Contrib generation uses the declared Perl, Bison, Flex and M4 toolchains. +pgcrypto consumes the pinned OpenSSL provider. PostGIS builds its six pinned +dependency libraries, upstream scanner and SQL generators, and PROJ database +from declared sources. Its current generated configuration is specific to Linux +LP64 and cannot establish WASIX or mobile support. + +The qualified Zig Linux x86_64 vector recipe preserves upstream CPU dispatch. +It enables the compiler's EVEX width support without raising the default AVX +CPU baseline, and links the matching immutable LLVM compiler-rt CPU-model +provider. The member archive carries that provider's source receipt and license; +independent validation rejects a missing or modified notice. + +These archives use `ecosystem = "internal"`, `role = "extension-member"`. +They are construction inputs, not final registry envelopes. Recorded workspace +PostgreSQL source pins are build-input facts; they do not +replace an external product's published compatibility requirements or prove +compatibility with a released runtime binary after workspace changes. + +Run the focused generator tests separately when those inputs change: + +```sh +tools/dev/bazel.sh test \ + //build_defs/extensions:pgtap_sql_test \ + //build_defs/extensions:member_payload_test \ + //src/extensions/external/pgtap:upstream_sql_parity_test +``` + +Run the broad installed SQL consumers with the qualified compiler profile: + +```sh +tools/dev/bazel.sh test \ + //build_defs/extensions:native_built_extension_sql_test \ + //build_defs/extensions:native_frozen_extension_sql_test \ + --platforms=//build_defs/native:linux_x86_64_glibc_2_28 \ + --host_platform=//build_defs/native:linux_x86_64_glibc_2_28 +``` + +The candidate consumer overlays all 39 actual member archives onto the built +runtime payload. The frozen consumer overlays the seven independently versioned +external members onto the actual immutable published native 0.3.3 archive and +compiles against that archive's header and library. Each selected member must +declare that exact host requirement; the acquisition binding alone does not +prove compatibility. Contrib members follow their runtime owner and are tested +with the candidate runtime. + +Both consumers install and execute extensions through the embedded C ABI, +reopen the persisted database in a new process, and separately execute the +server modules through the extracted PostgreSQL executable. Consumers are +relocated outside source runfiles and use only extracted library directories. +Removing the runtime library must fail loading; removing a PostGIS dependency +must fail each module layout independently. No workstation PostgreSQL supplies +the runtime or modules. + +Final registry envelopes, all remaining platform qualification, WASIX +pgcrypto/PostGIS dependencies and full publication integration remain separate +migration gates. Internal member archives do not satisfy those gates by +themselves. diff --git a/build_defs/extensions/compile_data.bzl b/build_defs/extensions/compile_data.bzl new file mode 100644 index 000000000..efdc05e5b --- /dev/null +++ b/build_defs/extensions/compile_data.bzl @@ -0,0 +1,11 @@ +"""Project exact authored compile data alongside generated crate sources.""" + +def _compile_data_impl(ctx): + output = ctx.actions.declare_file(ctx.file.src.basename) + ctx.actions.symlink(output = output, target_file = ctx.file.src) + return [DefaultInfo(files = depset([output]))] + +extension_compile_data = rule( + implementation = _compile_data_impl, + attrs = {"src": attr.label(allow_single_file = True, mandatory = True)}, +) diff --git a/build_defs/extensions/compiler_rt/BUILD.bazel b/build_defs/extensions/compiler_rt/BUILD.bazel new file mode 100644 index 000000000..ee6861a92 --- /dev/null +++ b/build_defs/extensions/compiler_rt/BUILD.bazel @@ -0,0 +1,6 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +package(default_visibility = ["//visibility:public"]) + +exports_files(["source.json", "repositories.bzl"]) + +source_quality_files() diff --git a/build_defs/extensions/compiler_rt/repositories.bzl b/build_defs/extensions/compiler_rt/repositories.bzl new file mode 100644 index 000000000..b7e44b899 --- /dev/null +++ b/build_defs/extensions/compiler_rt/repositories.bzl @@ -0,0 +1,52 @@ +"""The upstream CPU-model provider required by Clang function multiversioning.""" + +_BUILD = """ +load("@rules_cc//cc:defs.bzl", "cc_library") +package(default_visibility = ["//visibility:public"]) +exports_files(["LICENSE.TXT", "SOURCE.json", "source.bzl"]) +cc_library( + name = "cpu_model", + srcs = ["x86.c"], + hdrs = ["cpu_model.h"], + copts = ["-fPIC"], + alwayslink = True, + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) +""" + +def _compiler_rt_impl(ctx): + source = json.decode(ctx.read(ctx.attr.source)) + if source.get("schema") != "oliphaunt-compiler-runtime-source-v1" or source.get("project") != "llvm-compiler-rt": + fail("invalid compiler-runtime source identity") + commit = source.get("commit", "") + if len(commit) != 40 or any([c not in "0123456789abcdef" for c in commit.elems()]): + fail("compiler-runtime acquisition requires an immutable LLVM commit") + expected = { + "x86.c": "compiler-rt/lib/builtins/cpu_model/x86.c", + "cpu_model.h": "compiler-rt/lib/builtins/cpu_model/cpu_model.h", + "LICENSE.TXT": "compiler-rt/LICENSE.TXT", + } + seen = [] + for file in source["files"]: + destination = file["destination"] + if destination in seen or expected.get(destination) != file["path"]: + fail("compiler-runtime acquisition differs from the reviewed CPU-model closure") + seen.append(destination) + digest = file["sha256"] + if len(digest) != 64 or any([c not in "0123456789abcdef" for c in digest.elems()]): + fail("compiler-runtime file requires SHA256") + ctx.download( + url = "https://raw.githubusercontent.com/llvm/llvm-project/%s/%s" % (commit, file["path"]), + output = destination, + sha256 = digest, + ) + if sorted(seen) != sorted(expected.keys()): + fail("compiler-runtime acquisition must include C source, header, and license") + ctx.file("SOURCE.json", json.encode(source)) + ctx.file("source.bzl", "COMPILER_RT_SOURCE = " + repr(source) + "\n") + ctx.file("BUILD.bazel", _BUILD) + +compiler_rt_repository = repository_rule( + implementation = _compiler_rt_impl, + attrs = {"source": attr.label(allow_single_file = True, default = Label("//build_defs/extensions/compiler_rt:source.json"))}, +) diff --git a/build_defs/extensions/compiler_rt/source.json b/build_defs/extensions/compiler_rt/source.json new file mode 100644 index 000000000..9b5e0fcd0 --- /dev/null +++ b/build_defs/extensions/compiler_rt/source.json @@ -0,0 +1,24 @@ +{ + "schema": "oliphaunt-compiler-runtime-source-v1", + "project": "llvm-compiler-rt", + "version": "20.1.2", + "commit": "58df0ef89dd64126512e4ee27b4ac3fd8ddf6247", + "license": "Apache-2.0 WITH LLVM-exception", + "files": [ + { + "path": "compiler-rt/lib/builtins/cpu_model/x86.c", + "destination": "x86.c", + "sha256": "961bcc58c10576374e4e59178b5d53b1bccf42601f85eb6034ae2466058d0735" + }, + { + "path": "compiler-rt/lib/builtins/cpu_model/cpu_model.h", + "destination": "cpu_model.h", + "sha256": "4b374f7dcba5cbb9520b621ab596dc691af356772fc019246ab419f4c1c0f77c" + }, + { + "path": "compiler-rt/LICENSE.TXT", + "destination": "LICENSE.TXT", + "sha256": "1a8f1058753f1ba890de984e48f0242a3a5c29a6a8f2ed9fd813f36985387e8d" + } + ] +} diff --git a/build_defs/extensions/construction.bzl b/build_defs/extensions/construction.bzl new file mode 100644 index 000000000..cefe52c27 --- /dev/null +++ b/build_defs/extensions/construction.bzl @@ -0,0 +1,116 @@ +"""Complete desktop member construction coverage, separate from SQL lifecycle.""" + +load("@oliphaunt_metadata//:metadata.bzl", "CONTRIB_MEMBERS", "CONTRIB_OWNERS", "EXTENSIONS", "EXTENSION_SOURCES", "PRODUCTS") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") +load(":extensions.bzl", "ExtensionMemberInfo", "extension_default_version") +load(":platforms.bzl", "NATIVE_EXTENSION_COMPATIBLE", "NATIVE_EXTENSION_CONFIGURATION") + +def _desktop_members(include_postgis = False): + # The independently selected PostGIS dependency recipe requires its own + # complete host qualification; the existing bounded cohort stays unchanged. + descriptors = {row["sql-name"]: row for row in EXTENSIONS.values() if include_postgis or row["sql-name"] != "postgis"} + if len(descriptors) != len(EXTENSIONS) - (0 if include_postgis else 1) or "postgis" not in EXTENSION_SOURCES: + fail("desktop construction requires unique canonical members and explicit PostGIS selection") + result = [] + for name in sorted(descriptors.keys()): + descriptor = descriptors[name] + if descriptor["source-kind"] == "postgres-contrib": + matches = [member for member in CONTRIB_MEMBERS if member["sql-name"] == name] + if len(matches) != 1: + fail("desktop construction lacks a unique contrib member: " + name) + owner = CONTRIB_OWNERS["native"] + label = "//src/extensions/contrib:" + matches[0]["id"] + "_native_payload" + else: + owner = EXTENSION_SOURCES[name]["product"] + label = "//" + PRODUCTS[owner]["path"] + ":native_payload" + result.append(struct(name = name, owner = owner, label = label, descriptor = descriptor)) + return result + +def _construction_test_impl(ctx): + expected = _desktop_members(ctx.attr.include_postgis) + selected = {} + for target in ctx.attr.members: + member = target[ExtensionMemberInfo] + if member.sql_name in selected: + fail("desktop construction repeats member: " + member.sql_name) + selected[member.sql_name] = target + if sorted(selected.keys()) != [row.name for row in expected]: + fail("desktop construction must request every canonical desktop member exactly once") + archives = [] + rows = [] + for row in expected: + target = selected[row.name] + member = target[ExtensionMemberInfo] + if target.label != Label(row.label) or member.owner != row.owner or member.configuration != ctx.attr.configuration: + fail("desktop construction member differs from canonical label, owner, or configuration: " + row.name) + module = row.descriptor.get("native-module-file", "") + if module: + if not module.endswith(".so"): + fail("canonical desktop module must declare its native .so stem") + module = module[:-3] + {"macos-arm64": ".dylib", "windows-x64-msvc": ".dll"}.get(ctx.attr.configuration, ".so") + rows.append({ + "sql_name": row.name, + "label": row.label, + "archive": member.archive.path, + "inventory": member.inventory.path, + "owner": row.owner, + "version": PRODUCTS[row.owner]["version"], + "source_kind": row.descriptor["source-kind"], + "default_version": extension_default_version(row.name), + "creates_extension": row.descriptor["lifecycle"]["create-extension"], + "module_file": module, + }) + archives.append(member.archive) + inventory = ctx.actions.declare_file(ctx.label.name + ".inventory.json") + plan = { + "schema": "oliphaunt-desktop-extension-construction-v1", + "configuration": ctx.attr.configuration, + "excluded": [] if ctx.attr.include_postgis else ["postgis"], + "members": rows, + } + if ctx.attr.include_postgis: + plan["include_postgis"] = True + ctx.actions.write(inventory, json.encode(plan)) + sources = [ctx.file._runner] + ctx.files._helpers + return bun_test_entrypoint(ctx, ctx.file._runner, [inventory] + archives, [inventory] + archives + sources, source_files = sources) + [OutputGroupInfo(inventory = depset([inventory]))] + +_desktop_members_construction_test = rule( + implementation = _construction_test_impl, + test = True, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "members": attr.label_list(mandatory = True, providers = [ExtensionMemberInfo]), + "include_postgis": attr.bool(), + "configuration": attr.string(mandatory = True, values = ["linux-x64-gnu", "linux-arm64-gnu", "macos-arm64", "windows-x64-msvc"]), + "_runner": attr.label(default = "//build_defs/extensions:construction.mts", allow_single_file = True), + "_helpers": attr.label_list(default = [ + "//build_defs/extensions:validate_member_payload.mts", + "//:tools/packaging/portable-archive.mts", + "//:tools/packaging/platform-binary-contract.mts", + "//:tools/packaging/windows-vc-runtime-closure.mts", + "//:tools/packaging/windows-vc-runtime-policy.json", + "//tools/release:platform-compatibility-policy.mts", + "//:src/extensions/artifacts/native/tools/stage-windows-binary-contract.mts", + ], allow_files = True), + }), +) + +def desktop_members_construction_test(name, include_postgis = False, **kwargs): + """One test fails if any supported member is absent or invalid.""" + _desktop_members_construction_test( + name = name, + members = desktop_member_payloads(include_postgis), + include_postgis = include_postgis, + configuration = NATIVE_EXTENSION_CONFIGURATION, + args = bun_test_entrypoint_args(name), + target_compatible_with = NATIVE_EXTENSION_COMPATIBLE, + **kwargs + ) + +def desktop_member_payloads(include_postgis = False): + """Actual archive roots for the canonical desktop construction slice.""" + return [row.label for row in _desktop_members(include_postgis)] + +def desktop_member_inventory(include_postgis = False): + """Canonical identities shared by member and final-carrier qualification.""" + return _desktop_members(include_postgis) diff --git a/build_defs/extensions/construction.mts b/build_defs/extensions/construction.mts new file mode 100644 index 000000000..1cb6b61fb --- /dev/null +++ b/build_defs/extensions/construction.mts @@ -0,0 +1,93 @@ +/** Validate every requested desktop member; this proves construction, not SQL execution. */ +import { readFileSync } from 'node:fs'; +import { inspect } from './validate_member_payload.mts'; + +function record(value: unknown): Record { + if (!value || typeof value !== 'object' || Array.isArray(value)) { + throw new Error('desktop construction inventory must contain objects'); + } + return value as Record; +} + +export function validateDesktopConstruction(inventory: unknown, archives: readonly string[]) { + const plan = record(inventory); + const configuration = plan.configuration; + const includePostgis = plan.include_postgis ?? false; + if ( + plan.schema !== 'oliphaunt-desktop-extension-construction-v1' || + !['linux-x64-gnu', 'linux-arm64-gnu', 'macos-arm64', 'windows-x64-msvc'].includes( + configuration as string, + ) || + !Array.isArray(plan.excluded) || + typeof includePostgis !== 'boolean' || + (includePostgis + ? plan.excluded.length !== 0 + : plan.excluded.length !== 1 || plan.excluded[0] !== 'postgis') || + !Array.isArray(plan.members) || + plan.members.length === 0 + ) { + throw new Error('desktop construction inventory has an unsupported profile or membership'); + } + if (archives.length !== plan.members.length) { + throw new Error('desktop construction requires one actual archive for every requested member'); + } + const selected = new Set(); + let compiled = 0; + for (const [index, value] of plan.members.entries()) { + const member = record(value); + const name = member.sql_name; + if ( + typeof name !== 'string' || + !/^[a-z][a-z0-9_-]*$/u.test(name) || + (name === 'postgis' && !includePostgis) || + selected.has(name) || + typeof member.owner !== 'string' || + !member.owner || + typeof member.label !== 'string' || + !member.label.startsWith('//src/extensions/') || + typeof member.version !== 'string' || + typeof member.source_kind !== 'string' || + typeof member.creates_extension !== 'boolean' || + (member.default_version !== null && typeof member.default_version !== 'string') || + typeof member.module_file !== 'string' + ) { + throw new Error('desktop construction inventory has a repeated or invalid member'); + } + selected.add(name); + const descriptor = inspect(archives[index], name, member.owner); + for (const key of [ + 'version', + 'source_kind', + 'default_version', + 'creates_extension', + 'module_file', + ]) { + // Starlark serializes an absent contrib default version as JSON null. + if ((descriptor[key] ?? null) !== (member[key] ?? null)) { + throw new Error(`${name} archive disagrees with canonical ${key}`); + } + } + if (descriptor.configuration !== configuration) { + throw new Error(`${name} archive differs from the requested construction configuration`); + } + if (member.module_file) compiled += 1; + } + if (selected.has('postgis') !== includePostgis) + throw new Error('desktop construction differs from explicit PostGIS selection'); + return { configuration, members: [...selected], compiled, sqlOnly: selected.size - compiled }; +} + +if (import.meta.main) { + try { + const [inventory, ...archives] = process.argv.slice(2); + if (!inventory) + throw new Error('usage: construction.mts '); + const plan = JSON.parse( + new TextDecoder('utf-8', { fatal: true }).decode(readFileSync(inventory)), + ); + console.log(JSON.stringify(validateDesktopConstruction(plan, archives))); + } catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exitCode = 2; + } +} diff --git a/build_defs/extensions/construction.test.mts b/build_defs/extensions/construction.test.mts new file mode 100644 index 000000000..b069f031b --- /dev/null +++ b/build_defs/extensions/construction.test.mts @@ -0,0 +1,175 @@ +/** Real archives exercise complete requested membership and canonical module binding. */ +import { afterEach, expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { gzipSync } from 'node:zlib'; +import { validateDesktopConstruction } from './construction.mts'; + +const temporary = new Set(); +afterEach(() => { + for (const path of temporary) rmSync(path, { recursive: true, force: true }); + temporary.clear(); +}); + +type Member = { + sql_name: string; + label: string; + owner: string; + version: string; + source_kind: string; + default_version: string; + creates_extension: boolean; + module_file: string; +}; + +function member(name = 'pgtap', compiled = false): Member { + return { + sql_name: name, + label: `//src/extensions/external/${name}:native_payload`, + owner: `oliphaunt-extension-${name}`, + version: '1.2.3', + source_kind: 'oliphaunt-other-extension', + default_version: '1.2.3', + creates_extension: true, + module_file: compiled ? `${name}.so` : '', + }; +} + +function plan(members: Member[], configuration = 'linux-x64-gnu') { + return { + schema: 'oliphaunt-desktop-extension-construction-v1', + configuration, + excluded: ['postgis'], + members, + }; +} + +async function archive(row: Member, overrides: Record = {}): Promise { + const root = mkdtempSync(join(process.env.TEST_TMPDIR ?? tmpdir(), 'extension-construction-')); + temporary.add(root); + const files = new Map([ + [ + `share/postgresql/extension/${row.sql_name}.control`, + Buffer.from(`default_version = '${row.default_version}'\n`), + ], + [ + `share/postgresql/extension/${row.sql_name}--${row.default_version}.sql`, + Buffer.from('SELECT 1;\n'), + ], + ]); + if (row.module_file) { + const elf = Buffer.alloc(64); + elf.set([0x7f, 0x45, 0x4c, 0x46, 2, 1]); + elf.writeUInt16LE(3, 16); + elf.writeUInt16LE(62, 18); + for (const profile of ['postgresql', 'modules']) { + files.set(`lib/${profile}/${row.module_file}`, elf); + } + } + const descriptor = { + schema: 'oliphaunt-extension-member-payload-v1', + ...row, + configuration: 'linux-x64-gnu', + family: 'native', + module_profiles: row.module_file ? ['postgresql', 'modules'] : [], + ...overrides, + files: [...files].map(([path, bytes]) => ({ + path, + sha256: createHash('sha256').update(bytes).digest('hex'), + })), + }; + files.set('extension.json', Buffer.from(JSON.stringify(descriptor))); + const path = join(root, 'payload.tar.gz'); + writeFileSync( + path, + gzipSync(Buffer.from(await new Bun.Archive(Object.fromEntries(files)).bytes())), + ); + return path; +} + +test('one root independently validates every requested archive including both module ABIs', async () => { + const sql = member(); + const compiled = member('pg_hashids', true); + expect( + validateDesktopConstruction(plan([sql, compiled]), [ + await archive(sql), + await archive(compiled), + ]), + ).toEqual({ + configuration: 'linux-x64-gnu', + members: ['pgtap', 'pg_hashids'], + compiled: 1, + sqlOnly: 1, + }); +}); + +test('missing, duplicate, swapped, and foreign-owner archives cannot masquerade as complete', async () => { + const sql = member(); + const compiled = member('pg_hashids', true); + const files = [await archive(sql), await archive(compiled)]; + expect(() => validateDesktopConstruction(plan([sql, compiled]), files.slice(0, 1))).toThrow( + /every requested/, + ); + expect(() => validateDesktopConstruction(plan([sql, sql]), [files[0], files[0]])).toThrow( + /repeated/, + ); + expect(() => validateDesktopConstruction(plan([sql, compiled]), files.toReversed())).toThrow( + /SQL identity/, + ); + const foreign = await archive(sql, { owner: 'another-product' }); + expect(() => validateDesktopConstruction(plan([sql]), [foreign])).toThrow(/carrier owner/); +}); + +test('compiled members require actual module bytes and canonical current identity/configuration', async () => { + const compiled = member('pg_hashids', true); + const sqlOnly = await archive({ ...compiled, module_file: '' }); + expect(() => validateDesktopConstruction(plan([compiled]), [sqlOnly])).toThrow(/module_file/); + const valid = await archive(compiled); + expect(() => validateDesktopConstruction(plan([compiled], 'macos-arm64'), [valid])).toThrow( + /configuration/, + ); + const stale = await archive(compiled, { version: '1.2.2' }); + expect(() => validateDesktopConstruction(plan([compiled]), [stale])).toThrow(/version/); + const changed = await archive(compiled, { source_kind: 'postgres-contrib' }); + expect(() => validateDesktopConstruction(plan([compiled]), [changed])).toThrow(/source_kind/); +}); + +test('empty, PostGIS, and mobile plans fail before claiming host construction coverage', async () => { + expect(() => validateDesktopConstruction(plan([]), [])).toThrow(/membership/); + const sql = member(); + const path = await archive(sql); + expect(() => validateDesktopConstruction(plan([sql], 'ios-xcframework'), [path])).toThrow( + /profile/, + ); + expect(() => validateDesktopConstruction(plan([member('postgis')]), [path])).toThrow(/invalid/); + expect(() => validateDesktopConstruction({ ...plan([sql]), excluded: [] }, [path])).toThrow( + /membership/, + ); +}); + +test('explicit complete desktop selection includes PostGIS and rejects an incomplete or ambiguous plan', async () => { + const sql = member(); + const postgis = member('postgis', true); + const files = [await archive(sql), await archive(postgis)]; + const complete = { ...plan([sql, postgis]), include_postgis: true, excluded: [] }; + expect(validateDesktopConstruction(complete, files)).toEqual({ + configuration: 'linux-x64-gnu', + members: ['pgtap', 'postgis'], + compiled: 1, + sqlOnly: 1, + }); + expect(() => validateDesktopConstruction({ ...complete, members: [sql] }, [files[0]])).toThrow( + /explicit PostGIS selection/, + ); + expect(() => validateDesktopConstruction({ ...complete, excluded: ['postgis'] }, files)).toThrow( + /membership/, + ); + expect(() => + validateDesktopConstruction({ ...complete, include_postgis: 'true' }, files), + ).toThrow(/membership/); + expect(() => validateDesktopConstruction({ ...complete, include_postgis: false }, files)).toThrow( + /membership/, + ); +}); diff --git a/build_defs/extensions/contrib.bzl b/build_defs/extensions/contrib.bzl new file mode 100644 index 000000000..7703a8a05 --- /dev/null +++ b/build_defs/extensions/contrib.bzl @@ -0,0 +1,181 @@ +"""Reviewed PostgreSQL 18.4 contrib units and their actual upstream generators. + +Release membership, versions, module identities and ownership are imported from +the canonical metadata. These lists only replace the pinned PGXS object recipes. +""" + +load("@rules_cc//cc/common:cc_common.bzl", "cc_common") +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") +load("@oliphaunt_metadata//:metadata.bzl", "CONTRIB_MEMBERS") +load("//build_defs/release:shipping.bzl", "shipping_package") +load("//build_defs/native:generators.bzl", "postgres_bison", "postgres_flex", "postgres_perl") +load(":extensions.bzl", "NATIVE_EXTENSION_CONFIGURATION", "extension_identity", "extension_member_payload", "extension_member_validation_test", "native_extension_modules") + +CONTRIB_C_SOURCES = { + "amcheck": ["verify_common", "verify_gin", "verify_heapam", "verify_nbtree"], + "auto_explain": ["auto_explain"], + "bloom": ["blcost", "blinsert", "blscan", "blutils", "blvacuum", "blvalidate"], + "btree_gin": ["btree_gin"], + "btree_gist": ["btree_bit", "btree_bool", "btree_bytea", "btree_cash", "btree_date", "btree_enum", "btree_float4", "btree_float8", "btree_gist", "btree_inet", "btree_int2", "btree_int4", "btree_int8", "btree_interval", "btree_macaddr", "btree_macaddr8", "btree_numeric", "btree_oid", "btree_text", "btree_time", "btree_ts", "btree_utils_num", "btree_utils_var", "btree_uuid"], + "citext": ["citext"], + "cube": ["cube"], + "dict_int": ["dict_int"], + "dict_xsyn": ["dict_xsyn"], + "earthdistance": ["earthdistance"], + "file_fdw": ["file_fdw"], + "fuzzystrmatch": ["daitch_mokotoff", "dmetaphone", "fuzzystrmatch"], + "hstore": ["hstore_compat", "hstore_gin", "hstore_gist", "hstore_io", "hstore_op", "hstore_subs"], + "intarray": ["_int_bool", "_int_gin", "_int_gist", "_int_op", "_int_selfuncs", "_int_tool", "_intbig_gist"], + "isn": ["isn"], + "lo": ["lo"], + "ltree": ["_ltree_gist", "_ltree_op", "crc32", "lquery_op", "ltree_gist", "ltree_io", "ltree_op", "ltxtquery_io", "ltxtquery_op"], + "pageinspect": ["brinfuncs", "btreefuncs", "fsmfuncs", "ginfuncs", "gistfuncs", "hashfuncs", "heapfuncs", "rawpage"], + "pg_buffercache": ["pg_buffercache_pages"], + "pg_freespacemap": ["pg_freespacemap"], + "pg_surgery": ["heap_surgery"], + "pg_trgm": ["trgm_gin", "trgm_gist", "trgm_op", "trgm_regexp"], + "pg_visibility": ["pg_visibility"], + "pg_walinspect": ["pg_walinspect"], + "pgcrypto": ["crypt-blowfish", "crypt-des", "crypt-gensalt", "crypt-md5", "crypt-sha", "mbuf", "openssl", "pgcrypto", "pgp-armor", "pgp-cfb", "pgp-compress", "pgp-decrypt", "pgp-encrypt", "pgp-info", "pgp-mpi", "pgp-mpi-openssl", "pgp-pgsql", "pgp-pubdec", "pgp-pubenc", "pgp-pubkey", "pgp-s2k", "pgp", "px-crypt", "px-hmac", "px"], + "seg": ["seg"], + "tablefunc": ["tablefunc"], + "tcn": ["tcn"], + "tsm_system_rows": ["tsm_system_rows"], + "tsm_system_time": ["tsm_system_time"], + "unaccent": ["unaccent"], + "uuid_ossp": ["uuid-ossp"], +} + +CONTRIB_HEADERS = { + "amcheck": ["verify_common.h"], + "bloom": ["bloom.h"], + "btree_gist": ["btree_gist.h", "btree_utils_num.h", "btree_utils_var.h"], + "cube": ["cubedata.h"], + "hstore": ["hstore.h"], + "intarray": ["_int.h"], + "isn": ["EAN13.h", "ISBN.h", "ISMN.h", "ISSN.h", "UPC.h", "isn.h"], + "ltree": ["crc32.h", "ltree.h"], + "pageinspect": ["pageinspect.h"], + "pg_trgm": ["trgm.h"], + "pgcrypto": ["mbuf.h", "pgcrypto.h", "pgp.h", "px-crypt.h", "px.h"], + "seg": ["segdata.h"], +} + +def _generated_sources_impl(ctx): + generated = ctx.files.srcs + headers = ctx.files.include_headers + [file for file in generated if file.basename.endswith(".h")] + include_directories = {file.dirname: True for file in headers} + return [ + DefaultInfo(files = depset(generated)), + CcInfo(compilation_context = cc_common.create_compilation_context( + headers = depset(headers), + includes = depset(include_directories.keys()), + )), + ] + +_contrib_generated_inputs = rule( + implementation = _generated_sources_impl, + attrs = { + "srcs": attr.label_list(allow_files = True), + "include_headers": attr.label_list(allow_files = True), + }, +) + +def contrib_generated_sources(name, grammar = None, scanner = None, header_script = None, include_headers = [], grammar_options = ["-d"], scanner_options = [], scanner_rule = postgres_flex): + """Invoke upstream recipes through the maintained execution toolchains.""" + generated = [] + if grammar: + stem = grammar.split("/")[-1][:-2] + target = name + "_parser" + postgres_bison(name = target, src = grammar, outs = [name + "/" + stem + ".c", name + "/" + stem + ".h"], options = grammar_options) + generated.append(":" + target) + if scanner: + stem = scanner.split("/")[-1][:-2] + target = name + "_scanner" + scanner_rule(name = target, src = scanner, outs = [name + "/" + stem + ".c"], options = scanner_options) + generated.append(":" + target) + if header_script: + target = name + "_header" + postgres_perl(name = target, script = header_script, outs = [name + "/daitch_mokotoff.h"], arguments = ["$@"]) + generated.append(":" + target) + _contrib_generated_inputs(name = name, srcs = generated, include_headers = include_headers) + +def contrib_extension_inputs(name, member, crypto = None, uuid_provider = None): + """One upstream object/generator inventory, with an explicit UUID component seam.""" + identity = member["id"] + if identity not in CONTRIB_C_SOURCES: + fail("contrib member %s has no reviewed PostgreSQL 18.4 source recipe" % identity) + if identity == "pgcrypto" and crypto == None: + fail("pgcrypto construction requires an actual CcInfo OpenSSL input") + prefix = "@postgres//:contrib/" + member["contrib-dir"] + "/" + sources = [prefix + source + ".c" for source in CONTRIB_C_SOURCES[identity]] + headers = [prefix + header for header in CONTRIB_HEADERS.get(identity, [])] + deps, includes, copts = [], [], [] + if identity in ["cube", "seg"]: + generated = name + "_generated" + contrib_generated_sources(name = generated, grammar = prefix + identity + "parse.y", scanner = prefix + identity + "scan.l", include_headers = headers) + sources.append(":" + generated) + deps.append(":" + generated) + elif identity == "fuzzystrmatch": + generated = name + "_generated" + contrib_generated_sources(name = generated, header_script = prefix + "daitch_mokotoff_header.pl") + sources.append(":" + generated) + deps.append(":" + generated) + elif identity == "uuid_ossp": + if uuid_provider: + deps.append(uuid_provider) + else: + sources.append("portable-uuid/portable_uuid.c") + headers.append("portable-uuid/include/uuid/uuid.h") + includes.append("portable-uuid/include") + headers.append("//build_defs/extensions:uuid_config.h") + # pg_config.h undefines optional UUID macros. Select the explicit provider + # after that header, without changing the PostgreSQL host configuration. + copts += select({"//build_defs/native:windows_x64": ["/FI$(location //build_defs/extensions:uuid_config.h)"], "//conditions:default": ["-include", "build_defs/extensions/uuid_config.h"]}) + elif identity == "pgcrypto": + deps.append(crypto) + linkopts = select({"//build_defs/native:windows_x64": [], "//conditions:default": ["-lm"]}) if identity in ["btree_gist", "cube", "earthdistance", "tsm_system_time"] else [] + return {"srcs": sources, "hdrs": headers, "deps": deps, "defines": [], "includes": includes, "copts": copts, "linkopts": linkopts} + +def native_contrib_members(crypto = None): + """Construct each admitted member; crypto requires an actual CcInfo input.""" + for member in CONTRIB_MEMBERS: + name = member["id"] + directory = member["contrib-dir"] + if name == "pgcrypto" and crypto == None: + continue + inputs = contrib_extension_inputs(name = name, member = member, crypto = crypto) + native_extension_modules( + name = name, + additional_compiler_inputs = ["//build_defs/extensions:uuid_config.h"] if name == "uuid_ossp" else [], + **inputs + ) + resources = name + "_sql_resources" + native.filegroup( + name = resources, + srcs = ["@postgres//:contrib_" + directory.replace("-", "_") + "_resources"] if member.get("default-version") else [], + ) + payload = name + "_native_payload" + construction_licenses = {} + if name == "pgcrypto": + construction_licenses = {"//src/third-party/openssl:LICENSE.txt": "share/licenses/openssl-native/LICENSE.txt", "//src/third-party/openssl:source.toml": "share/licenses/openssl-native/SOURCE.toml"} + extension_member_payload( + name = payload, + sql_name = member["sql-name"], + owner = extension_identity(member["sql-name"]), + resources = [":" + resources], + server_module = ":" + name + "_server_module", + embedded_module = ":" + name + "_embedded_module", + construction_licenses = construction_licenses, + ) + shipping_package( + name = name + "_native_member", + owner = extension_identity(member["sql-name"]), + artifacts = [":" + payload], + suppliers = ":" + payload, + ecosystem = "internal", + package_name = member["sql-name"], + configuration = NATIVE_EXTENSION_CONFIGURATION, + role = "extension-member", + ) + extension_member_validation_test(name = payload + "_test", payload = ":" + payload, sql_name = member["sql-name"]) diff --git a/build_defs/extensions/contrib_carriers.bzl b/build_defs/extensions/contrib_carriers.bzl new file mode 100644 index 000000000..27f22d896 --- /dev/null +++ b/build_defs/extensions/contrib_carriers.bzl @@ -0,0 +1,139 @@ +"""Runtime-owned native contrib final envelopes from the canonical distribution.""" + +load("@oliphaunt_metadata//:metadata.bzl", "CONTRIB_MEMBERS", "CONTRIB_OWNERS", "EXTENSIONS", "EXTENSION_RELEASE_METADATA", "POSTGRES_SOURCE", "PRODUCTS", "PUBLICATION_CARRIERS") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action", "bun_script_test") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") +load("//build_defs/release:supplier.bzl", "ShippingSupplierInfo", "merge_shipping_suppliers") +load(":extensions.bzl", "ExtensionMemberInfo", "extension_identity") +load(":final_leaf.bzl", "ExtensionFinalLeafInfo") +load(":native_carriers.bzl", "native_extension_carrier_helpers", "native_extension_carrier_legal") +load(":platforms.bzl", "NATIVE_EXTENSION_COMPATIBLE", "NATIVE_EXTENSION_LINUX_COMPATIBLE") +load(":smoke.bzl", "extension_smoke_plan") + +_TARGETS = {"//build_defs/native:linux_x86_64": "linux-x64-gnu", "//build_defs/native:linux_aarch64_gnu_2_28": "linux-arm64-gnu", "//build_defs/native:macos_arm64": "macos-arm64", "//build_defs/native:windows_x64": "windows-x64-msvc"} + +def native_contrib_carrier_legal(): + return ["//:LICENSE", "//:THIRD_PARTY_NOTICES.md", "//src/third-party/postgres:COPYRIGHT", "//src/third-party/postgres:source.toml", "//src/third-party/openssl:LICENSE.txt", "//src/third-party/openssl:source.toml"] + +def native_contrib_carrier_metadata(target, family = "native"): + rows = [row for row in EXTENSION_RELEASE_METADATA if row["class"] == "contrib"] + expected = sorted([member["sql-name"] for member in CONTRIB_MEMBERS]) + if sorted([row["sqlName"] for row in rows]) != expected: + fail("contrib carrier metadata must cover every canonical member exactly once") + metadata = rows[0] + product = metadata["artifactProduct"] + owner = CONTRIB_OWNERS[family] + compatibility = metadata["compatibility"] + common = {"product": product, "owner": owner, "version": PRODUCTS[owner]["version"], "runtimeVersion": PRODUCTS[owner]["version"], "target": target, + "compatibility": {"extension_runtime_contract": compatibility["extensionRuntimeContract"], "native_runtime_product": compatibility["nativeRuntimeProduct"], "native_runtime_version": compatibility["nativeRuntimeVersion"], "postgres_major": compatibility["postgresMajor"], "wasix_runtime_product": compatibility["wasixRuntimeProduct"], "wasix_runtime_version": compatibility["wasixRuntimeVersion"]}, + "source": POSTGRES_SOURCE, "carriers": [row for row in PUBLICATION_CARRIERS if row["product"] == owner and (row["name"] == metadata["npmPackage"] or row["name"].startswith(metadata["npmPackage"] + "-") or row["name"] == metadata["cargoPackage"] or row["name"].startswith(metadata["cargoPackage"] + "-"))]} + members = [] + for member in CONTRIB_MEMBERS: + sql_name = member["sql-name"] + descriptors = [descriptor for descriptor in EXTENSIONS.values() if descriptor["sql-name"] == sql_name] + if len(descriptors) != 1: + fail("contrib final carrier requires exactly one canonical SQL descriptor") + descriptor = descriptors[0] + spec = dict(common) + spec.update({"sqlName": sql_name, "contrib": member, "descriptor": descriptor, "recipe": {}, "selectedDependencies": sorted([name for name in descriptor.get("dependencies", []) if name in expected])}) + members.append(spec) + common.update({"sqlName": "", "descriptor": {}, "recipe": {}, "selectedDependencies": [], "expectedMembers": expected, "members": members, "sourceIdentity": metadata["sourceIdentity"]}) + return common + +def _leaf(spec, ecosystem): + facades = [row for row in spec["carriers"] if row["ecosystem"] == "npm" and row["target"] == None] + if len(facades) != 1: + fail("contrib final carrier requires its unique canonical npm facade") + name = (facades[0]["name"] if ecosystem == "npm" else spec["product"]) + "-" + spec["target"] + rows = [row for row in spec["carriers"] if row["ecosystem"] == ecosystem and row["name"] == name and row["target"] == spec["target"]] + if len(rows) != 1: + fail("contrib final carrier requires exactly one canonical " + ecosystem + " leaf") + return rows[0] + +def _carriers_impl(ctx): + typed = [target[ExtensionMemberInfo] for target in ctx.attr.members] + if not typed: + fail("contrib final carrier requires all canonical typed member producers") + spec = native_contrib_carrier_metadata(typed[0].configuration) + actual = {member.sql_name: member for member in typed} + if len(actual) != len(typed) or sorted(actual.keys()) != spec["expectedMembers"]: + fail("contrib final carrier must consume every canonical member exactly once") + member_inputs = [] + for member in spec["members"]: + producer = actual[member["sqlName"]] + if producer.owner != spec["owner"] or producer.configuration != spec["target"]: + fail("contrib member owner/configuration differs from its bundle") + member["archive"] = producer.archive.path + member_inputs += [producer.archive, producer.inventory] + github = ctx.actions.declare_file(spec["product"] + "-" + spec["version"] + "-native-" + spec["target"] + "-bundle.tar.gz") + npm = ctx.actions.declare_file(_leaf(spec, "npm")["name"].replace("@", "").replace("/", "-") + "-" + spec["version"] + ".tgz") + cargo = ctx.actions.declare_directory(ctx.label.name + "/cargo") + manifest = ctx.actions.declare_file(ctx.label.name + "/" + spec["product"] + "-" + spec["version"] + "-manifest.json") + frozen = ctx.actions.declare_file(ctx.label.name + "/extension-artifacts.json") + spec["outputs"] = {"github": github.path, "npm": npm.path, "cargo": cargo.path, "manifest": manifest.path, "frozen": frozen.path} + inputs = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(inputs, json.encode(spec)) + bun_file_action(ctx, ctx.file._tool, arguments = [inputs.path], inputs = member_inputs + [inputs] + ctx.files.legal, + source_files = [ctx.file._tool] + ctx.files._helpers + ctx.files.legal, + outputs = [github, npm, cargo, manifest, frozen], mnemonic = "NativeContribEnvelopes") + suppliers = merge_shipping_suppliers([member[ShippingSupplierInfo] for member in ctx.attr.members]) + return [DefaultInfo(files = depset([github, npm, cargo, manifest, frozen])), suppliers, + ExtensionFinalLeafInfo(product = spec["product"], owner = spec["owner"], version = spec["version"], family = "native", target = spec["target"], metadata = spec, github = [github], npm = [npm], cargo = [cargo], manifest = manifest, frozen = frozen, spec = inputs, validation = None, receipt = None, origin = None), + OutputGroupInfo(github = depset([github]), npm = depset([npm]), cargo = depset([cargo]), manifest = depset([manifest]), frozen = depset([frozen]), spec = depset([inputs]))] + +_native_contrib_carriers = rule(implementation = _carriers_impl, toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = {"members": attr.label_list(mandatory = True, providers = [ExtensionMemberInfo, ShippingSupplierInfo]), "legal": attr.label_list(allow_files = True), + "_tool": attr.label(default = "//build_defs/extensions:contrib_carriers.mts", allow_single_file = True), + "_helpers": attr.label_list(default = native_extension_carrier_helpers() + ["//build_defs/extensions:native_carriers.mts", "//:src/extensions/artifacts/packages/tools/bundle-carrier-assets.mts"], allow_files = True)}) + +def native_contrib_carriers(): + members = [":" + member["id"] + "_native_payload" for member in CONTRIB_MEMBERS] + _native_contrib_carriers(name = "native_carriers", members = members, legal = native_contrib_carrier_legal(), target_compatible_with = NATIVE_EXTENSION_COMPATIBLE) + metadata = {condition: native_contrib_carrier_metadata(target) for condition, target in _TARGETS.items()} + owner = extension_identity(CONTRIB_MEMBERS[0]["sql-name"]) + packages = [] + for ecosystem in ["github", "npm", "cargo"]: + name = "native_" + ecosystem + "_shipping" + native.filegroup(name = name + "_files", srcs = [":native_carriers"], output_group = ecosystem) + names, roles = {}, {} + for condition, spec in metadata.items(): + if ecosystem == "github": + names[condition] = spec["product"] + "-" + spec["version"] + "-native-" + spec["target"] + "-bundle.tar.gz" + roles[condition] = "github-release-asset" + else: + row = _leaf(spec, ecosystem) + names[condition], roles[condition] = row["name"], row["role"] + shipping_package(name = name, owner = owner, artifacts = [":" + name + "_files"], ecosystem = ecosystem, + package_name = select(names), configuration = select(_TARGETS), role = select(roles), suppliers = ":native_carriers", target_compatible_with = NATIVE_EXTENSION_COMPATIBLE) + packages.append(":" + name) + for group in ["manifest", "frozen"]: + name = "native_" + group + "_shipping" + native.filegroup(name = name + "_files", srcs = [":native_carriers"], output_group = group) + shipping_package(name = name, owner = owner, artifacts = [":" + name + "_files"], ecosystem = "internal", + package_name = "contrib-native-" + group, configuration = select(_TARGETS), role = "extension-release-" + group + "-input", suppliers = ":native_carriers", target_compatible_with = NATIVE_EXTENSION_COMPATIBLE) + packages.append(":" + name) + shipping_export(name = "native_shipping_export", packages = packages, qualification = select({ + condition: [":native_carriers_test"] if target.startswith("linux-") else [ + "//build_defs/extensions:desktop_all_final_contract_test", + "//build_defs/extensions:desktop_all_members_frozen_sql_test", + ] for condition, target in _TARGETS.items() + }), testonly = True, target_compatible_with = NATIVE_EXTENSION_COMPATIBLE) + native.filegroup(name = "native_carrier_spec", srcs = [":native_carriers"], output_group = "spec") + extension_smoke_plan(name = "native_final_plan", members = [":cube_native_payload", ":pg_trgm_native_payload", "//src/extensions/external/pgtap:native_payload"], fixtures = ["//src/test-fixtures/extensions:sql"]) + plans = [] + for group in ["install", "smoke", "startup"]: + native.filegroup(name = "native_final_" + group, srcs = [":native_final_plan"], output_group = group) + plans.append(":native_final_" + group) + inputs = [":native_carrier_spec", ":native_github_shipping_files", ":native_npm_shipping_files", ":native_cargo_shipping_files", "//src/native/runtime:runtime_payload", "//build_defs/extensions:native_extension_smoke"] + plans + [":native_manifest_shipping_files", ":native_frozen_shipping_files", "//src/extensions/external/pgtap:native_npm_shipping_files"] + data = inputs + native_extension_carrier_helpers() + native_contrib_carrier_legal() + native_extension_carrier_legal("pgtap") + ["//src/native/sdks/ts:native_asset_sources", "//build_defs/extensions:native_carriers.mts", "//build_defs/extensions:contrib_carriers.mts", "//build_defs/extensions:native_carrier_install_helpers.mts", "//:src/extensions/artifacts/packages/tools/bundle-carrier-assets.mts"] + bun_script_test(name = "native_carriers_test", entry_point = "//build_defs/extensions:contrib_carriers_installed.test.mts", + args = ["$(location %s)" % label for label in inputs], + data = {label: True for label in data}.keys(), + target_compatible_with = NATIVE_EXTENSION_LINUX_COMPATIBLE, size = "medium") + +def _unit_inputs_impl(ctx): + output = ctx.actions.declare_file(ctx.label.name + ".json") + ctx.actions.write(output, json.encode(native_contrib_carrier_metadata("linux-x64-gnu"))) + return [DefaultInfo(files = depset([output]))] + +native_contrib_carrier_unit_inputs = rule(implementation = _unit_inputs_impl) diff --git a/build_defs/extensions/contrib_carriers.mts b/build_defs/extensions/contrib_carriers.mts new file mode 100644 index 000000000..9fe03f549 --- /dev/null +++ b/build_defs/extensions/contrib_carriers.mts @@ -0,0 +1,127 @@ +/** Runtime-owned native contrib envelopes from all canonical typed members. */ +import assert from 'node:assert/strict'; +import { copyFileSync, mkdirSync, mkdtempSync, readFileSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { bundleCarrierAssets } from '../../src/extensions/artifacts/packages/tools/bundle-carrier-assets.mts'; +import { extensionRuntimeAssetContract } from '../../src/extensions/artifacts/packages/tools/extension-runtime-asset-contract.mts'; +import { + assemblePublicNativeMember, + type NativeCarrierSpec, + nativeCarrierCompatibility, + nativeCarrierLeaves, + stageNativeRegistryCarriers, + writeJson, +} from './native_carriers.mts'; + +export interface NativeContribCarrierSpec extends NativeCarrierSpec { + owner: string; + expectedMembers: string[]; + members: NativeCarrierSpec[]; + sourceIdentity: Record; +} + +export function validateNativeContribInputs(spec: NativeContribCarrierSpec) { + assert.deepEqual(spec.members.map((member) => member.sqlName).sort(), spec.expectedMembers); + assert.equal(new Set(spec.expectedMembers).size, spec.expectedMembers.length); + assert.equal( + spec.version, + spec.runtimeVersion, + 'contrib package version must follow its runtime owner', + ); + assert.equal(spec.owner, spec.compatibility.native_runtime_product); + for (const member of spec.members) { + assert.equal(member.owner, spec.owner); + assert.equal(member.product, spec.product); + assert.equal(member.version, spec.version); + assert.equal(member.target, spec.target); + assert.equal(member.runtimeVersion, spec.runtimeVersion); + assert.deepEqual(member.compatibility, spec.compatibility); + assert.equal(member.descriptor['source-kind'], 'postgres-contrib'); + assert.equal(member.contrib?.['sql-name'], member.sqlName); + assert.deepEqual(member.source, spec.source); + } + nativeCarrierLeaves(spec); + assert.equal( + path.basename(spec.outputs.github), + `${spec.product}-${spec.version}-native-${spec.target}-bundle.tar.gz`, + ); +} + +export function packageNativeContribCarriers(spec: NativeContribCarrierSpec) { + validateNativeContribInputs(spec); + const root = mkdtempSync(path.join(tmpdir(), 'native-contrib-envelopes-')); + for (const output of Object.values(spec.outputs)) + mkdirSync(path.dirname(path.resolve(output)), { recursive: true }); + try { + const productRoot = path.join(root, 'product'); + mkdirSync(path.join(productRoot, 'release-assets'), { recursive: true }); + const members = spec.members.map((member) => { + const archive = path.join( + productRoot, + 'member-assets', + member.sqlName, + `${spec.product}-${spec.version}-native-${spec.target}-runtime.tar.gz`, + ); + const { metadata, asset } = assemblePublicNativeMember(member, archive); + return { + ...metadata, + assets: [{ ...asset, path: path.relative(root, archive).split(path.sep).join('/') }], + }; + }); + const compatibility = nativeCarrierCompatibility(spec); + const assets = bundleCarrierAssets( + spec.product, + spec.version, + productRoot, + members, + compatibility, + { root }, + ); + assert.equal(assets.length, 1, 'selected contrib target must produce one complete bundle'); + const asset = assets[0]; + assert.equal(asset.memberCount, spec.expectedMembers.length); + assert.equal(asset.name, path.basename(spec.outputs.github)); + copyFileSync(path.join(root, asset.path), spec.outputs.github); + const ownership = { releaseProduct: spec.owner, family: 'native' }; + const manifestPath = path.join( + productRoot, + 'release-assets', + `${spec.product}-${spec.version}-manifest.json`, + ); + writeJson(path.join(productRoot, 'extension-artifacts.json'), { + schema: 'oliphaunt-extension-ci-artifacts-v2', + product: spec.product, + ...ownership, + version: spec.version, + compatibility, + extensions: members, + carrierAssets: assets, + }); + writeJson(manifestPath, { + schema: 'oliphaunt-extension-release-manifest-v2', + product: spec.product, + ...ownership, + version: spec.version, + extensionClass: 'contrib', + versioning: 'runtime-bound', + sourceIdentity: spec.sourceIdentity, + compatibility, + extensions: members.map((member) => ({ + ...member, + assets: member.assets.map(extensionRuntimeAssetContract), + })), + assets: assets.map(extensionRuntimeAssetContract), + }); + copyFileSync(path.join(productRoot, 'extension-artifacts.json'), spec.outputs.frozen); + copyFileSync(manifestPath, spec.outputs.manifest); + stageNativeRegistryCarriers(spec, productRoot, root); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + assert.equal(process.argv.length, 3, 'usage: contrib_carriers.mts '); + packageNativeContribCarriers(JSON.parse(readFileSync(process.argv[2], 'utf8'))); +} diff --git a/build_defs/extensions/contrib_carriers.test.mts b/build_defs/extensions/contrib_carriers.test.mts new file mode 100644 index 000000000..66943241d --- /dev/null +++ b/build_defs/extensions/contrib_carriers.test.mts @@ -0,0 +1,149 @@ +/** Canonical contrib ownership, source facts and deterministic bundle byte contracts. */ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { bundleCarrierAssets } from '../../src/extensions/artifacts/packages/tools/bundle-carrier-assets.mts'; +import { nativeExtensionConstructionLicenseInventory } from '../../src/extensions/tools/extension-upstream-licenses.mts'; +import { readPortableArchiveEntries } from '../../tools/packaging/portable-archive.mts'; +import { type NativeContribCarrierSpec, validateNativeContribInputs } from './contrib_carriers.mts'; +import { frozenNativeMember, nativeCarrierCompatibility } from './native_carriers.mts'; + +const [input] = process.argv.slice(2); +assert(input, 'expected canonical contrib carrier metadata'); +const metadata = JSON.parse(readFileSync(input, 'utf8')); +const root = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'contrib-carrier-unit-')); +const spec: NativeContribCarrierSpec = { + ...metadata, + outputs: { + github: path.join( + root, + `${metadata.product}-${metadata.version}-native-${metadata.target}-bundle.tar.gz`, + ), + npm: path.join(root, 'npm.tgz'), + cargo: path.join(root, 'cargo'), + manifest: path.join(root, 'manifest.json'), + frozen: path.join(root, 'extension-artifacts.json'), + }, +}; +const digest = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +try { + validateNativeContribInputs(spec); + assert.equal(spec.expectedMembers.length, 32); + const members = spec.members.map((member) => { + const construction = + member.sqlName === 'pgcrypto' + ? nativeExtensionConstructionLicenseInventory(member.sqlName, member.target) + : []; + const actual = { + owner: member.owner, + version: member.version, + sql_name: member.sqlName, + configuration: member.target, + source_kind: 'postgres-contrib', + postgres_source: member.source, + default_version: member.contrib!['default-version'] ?? null, + creates_extension: member.descriptor.lifecycle['create-extension'], + dependencies: member.descriptor.dependencies, + data_files: member.contrib!['data-files'] ?? [], + sql_files: [], + sql_prefixes: [], + module_file: member.descriptor['native-module-file'], + dependency_modules: [], + construction_licenses: construction.map((row) => row.path), + }; + const frozen = frozenNativeMember(member, actual); + assert.equal(frozen.sqlName, member.sqlName); + assert.equal(frozen.nativeModuleStem + '.so', member.contrib!['module-file']); + assert.equal(frozen.createsExtension, member.sqlName !== 'auto_explain'); + for (const invalid of [ + { ...actual, owner: 'unrelated-owner' }, + { ...actual, version: '99.0.0' }, + { ...actual, postgres_source: {} }, + { ...actual, default_version: 'foreign' }, + { ...actual, data_files: ['share/postgresql/foreign'] }, + { ...actual, construction_licenses: ['share/licenses/foreign.txt'] }, + ]) + assert.throws(() => frozenNativeMember(member, invalid)); + const name = `${spec.product}-${spec.version}-native-${spec.target}-runtime.tar.gz`; + const file = path.join(root, 'members', member.sqlName, name); + mkdirSync(path.dirname(file), { recursive: true }); + // Opaque bytes exercise bundle assembly; installed qualification owns real ELF/SQL proof. + const bytes = Buffer.from('canonical bundle member ' + member.sqlName); + writeFileSync(file, bytes); + return { + ...frozen, + assets: [ + { + name, + path: path.relative(root, file), + family: 'native', + target: spec.target, + kind: 'runtime', + identity: null, + sha256: digest(bytes), + bytes: bytes.length, + }, + ], + }; + }); + const run = (directory: string, values = structuredClone(members)) => { + const productRoot = path.join(root, directory); + mkdirSync(path.join(productRoot, 'release-assets'), { recursive: true }); + const assets = bundleCarrierAssets( + spec.product, + spec.version, + productRoot, + values, + nativeCarrierCompatibility(spec), + { root }, + ); + assert.equal(assets.length, 1); + return { values, assets, file: path.join(root, assets[0].path) }; + }; + const first = run('first'), + second = run('second', [...structuredClone(members)].reverse()); + assert.deepEqual(readFileSync(first.file), readFileSync(second.file)); + const archive = readPortableArchiveEntries(first.file); + const prefix = path.basename(first.file, '.tar.gz'); + const bundle = JSON.parse(archive.get(`${prefix}/bundle-manifest.json`)!.data().toString('utf8')); + assert.equal(bundle.licenseProfile, 'contrib-native-openssl'); + assert.deepEqual( + bundle.members.map((row: any) => row.sqlName), + spec.expectedMembers, + ); + for (const member of first.values) { + const asset = member.assets[0]; + assert.equal(asset.carrierAsset, first.assets[0].name); + assert.equal(asset.carrierRoot, prefix); + assert.equal(asset.memberPath, `extensions/${member.sqlName}/${asset.name}`); + const entry = archive.get(`${prefix}/${asset.memberPath}`)!; + assert.equal(entry.mode, 0o644); + assert.equal(digest(entry.data()), asset.sha256); + assert.equal(entry.data().length, asset.bytes); + } + assert.throws(() => validateNativeContribInputs({ ...spec, members: spec.members.slice(1) })); + assert.throws(() => + validateNativeContribInputs({ + ...spec, + members: [spec.members[0], ...spec.members.slice(0, -1)], + }), + ); + assert.throws(() => validateNativeContribInputs({ ...spec, version: '99.0.0' })); + const missing = structuredClone(members); + missing[0].assets = []; + assert.throws(() => run('missing', missing), /missing exact members/); + const changed = structuredClone(members); + changed[0].assets[0].sha256 = '0'.repeat(64); + assert.throws(() => run('changed', changed), /changed.*member bytes/); + const escaping = structuredClone(members); + escaping[0].assets[0].path = '../foreign'; + assert.throws(() => run('escaping', escaping), /root-relative/); + assert.throws(() => run('duplicate', [members[0], ...members]), /must be unique/); + console.log( + 'All 32 canonical contrib facts, runtime ownership, pinned construction legal receipt, exact nested locators and deterministic bundle bytes verified.', + ); +} finally { + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/extensions/contrib_carriers_installed.test.mts b/build_defs/extensions/contrib_carriers_installed.test.mts new file mode 100644 index 000000000..e66d3278e --- /dev/null +++ b/build_defs/extensions/contrib_carriers_installed.test.mts @@ -0,0 +1,326 @@ +/** Verify the complete contrib bundle and execute only selected installed members. */ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + existsSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + realpathSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { validateExtensionArtifactArchive } from '../../src/extensions/artifacts/packages/tools/extension-artifact-inventory.mts'; +import { nativeExtensionConstructionLicenseInventory } from '../../src/extensions/tools/extension-upstream-licenses.mts'; +import { readPortableArchiveEntries } from '../../tools/packaging/portable-archive.mts'; +import { + assertReleaseNoticesInArchive, + releaseNoticeRows, +} from '../../tools/packaging/release-notices.mts'; +import { type NativeContribCarrierSpec, validateNativeContribInputs } from './contrib_carriers.mts'; +import { + exerciseNativeCarrierSql, + prepareNativeCarrierSdk, + readNativeCargoPayload, + writableDirectories, +} from './native_carrier_install_helpers.mts'; +import { nativeCarrierCompatibility, nativeCarrierLeaves } from './native_carriers.mts'; + +const [ + specFile, + githubFile, + npmFile, + cargoDirectory, + runtimeFile, + consumerFile, + installSql, + smokeSql, + startupFile, + manifestFile, + frozenFile, + pgtapNpm, +] = process.argv.slice(2); +const spec = JSON.parse(readFileSync(specFile, 'utf8')) as NativeContribCarrierSpec; +spec.outputs = { + github: githubFile, + npm: npmFile, + cargo: cargoDirectory, + manifest: manifestFile, + frozen: frozenFile, +}; +validateNativeContribInputs(spec); +const identities = nativeCarrierLeaves(spec); +const digest = (data: Uint8Array) => createHash('sha256').update(data).digest('hex'); +const root = mkdtempSync(path.join(tmpdir(), 'native-contrib-final-install-')); +const caches = new Set(); +try { + const gh = readPortableArchiveEntries(realpathSync(githubFile)); + const prefix = path.basename(githubFile, '.tar.gz'); + const bundle = JSON.parse(gh.get(`${prefix}/bundle-manifest.json`)!.data().toString('utf8')); + assert.equal(bundle.schema, 'oliphaunt-extension-bundle-v1'); + assert.equal(bundle.product, spec.product); + assert.equal(bundle.version, spec.version); + assert.equal(bundle.family, 'native'); + assert.equal(bundle.target, spec.target); + assert.deepEqual(bundle.compatibility, nativeCarrierCompatibility(spec)); + assert.deepEqual( + bundle.members.map((member: any) => member.sqlName), + spec.expectedMembers, + ); + assert.equal(bundle.licenseProfile, 'contrib-native-openssl'); + assert.deepEqual(bundle.licenseFiles, []); + assertReleaseNoticesInArchive(realpathSync(githubFile), { + prefix, + profile: bundle.licenseProfile, + }); + assert.deepEqual( + [...gh.keys()].sort(), + [ + `${prefix}/bundle-manifest.json`, + ...bundle.members.map((member: any) => `${prefix}/${member.path}`), + ...releaseNoticeRows({ profile: bundle.licenseProfile }).map( + (row) => `${prefix}/${row.member}`, + ), + ].sort(), + 'contrib bundle must contain only canonical members and legal files', + ); + for (const entry of gh.values()) { + assert(entry.isFile); + assert.equal(entry.mode, 0o644); + } + + const npm = readPortableArchiveEntries(realpathSync(npmFile)); + const packageJson = JSON.parse(npm.get('package/package.json')!.data().toString('utf8')); + assert.equal(packageJson.name, identities.npm.name); + assert.equal(packageJson.version, spec.version); + assert.equal(packageJson.oliphaunt.liboliphauntVersion, spec.runtimeVersion); + assert.deepEqual(packageJson.os, ['linux']); + assert(['linux-x64-gnu', 'linux-arm64-gnu'].includes(spec.target)); + assert.deepEqual(packageJson.cpu, [spec.target === 'linux-arm64-gnu' ? 'arm64' : 'x64']); + assert.deepEqual(packageJson.libc, ['glibc']); + const contracts = JSON.parse(npm.get('package/extension-contract.json')!.data().toString('utf8')); + assert.deepEqual( + contracts.members.map((member: any) => member.sqlName), + spec.expectedMembers, + ); + const npmBundle = JSON.parse(npm.get('package/bundle-manifest.json')!.data().toString('utf8')); + assert.equal(npmBundle.schema, 'oliphaunt-npm-extension-bundle-v1'); + assert.deepEqual( + npmBundle.members.map((member: any) => member.sqlName), + spec.expectedMembers, + ); + const cargo = readNativeCargoPayload(cargoDirectory, identities.cargo.name, spec.version, [ + 'MIT', + 'PostgreSQL', + 'Apache-2.0', + ]); + const expectedCargo = new Map(); + const publicEntries = new Map>(); + for (const member of bundle.members) { + const bytes = gh.get(`${prefix}/${member.path}`)!.data(); + assert.equal(member.identity, null); + assert.equal(member.kind, 'runtime'); + assert.equal( + member.path, + `extensions/${member.sqlName}/${spec.product}-${spec.version}-native-${spec.target}-runtime.tar.gz`, + ); + assert.equal(member.bytes, bytes.length); + assert.equal(member.sha256, digest(bytes)); + const nested = path.join(root, member.sqlName + '.tar.gz'); + writeFileSync(nested, bytes); + const contract = contracts.members.find((row: any) => row.sqlName === member.sqlName); + assert(contract); + const metadata = { + ...contract, + nativeConstructionLicenseFiles: nativeExtensionConstructionLicenseInventory( + member.sqlName, + spec.target, + ), + }; + validateExtensionArtifactArchive({ + file: nested, + metadata, + product: spec.product, + target: spec.target, + nativeRuntimeVersion: spec.runtimeVersion, + }); + const entries = readPortableArchiveEntries(nested); + publicEntries.set(member.sqlName, entries); + const npmMember = npmBundle.members.find((row: any) => row.sqlName === member.sqlName); + assert.equal(npmMember.path, member.path); + assert.equal(npmMember.sha256, member.sha256); + assert.equal(npmMember.bytes, member.bytes); + assert.deepEqual(npm.get('package/' + npmMember.path)!.data(), bytes); + for (const [name, entry] of entries) + if (name.startsWith('files/')) { + const relative = name.slice('files/'.length); + assert.deepEqual( + npm.get(`package/${npmMember.runtimeRelativePath}/${relative}`)!.data(), + entry.data(), + ); + expectedCargo.set(`extensions/${member.sqlName}/${relative}`, digest(entry.data())); + } + } + assert.deepEqual( + cargo, + expectedCargo, + 'Cargo and npm must carry the same exact nested GitHub payload bytes', + ); + + for (const [file, schema] of [ + [frozenFile, 'oliphaunt-extension-ci-artifacts-v2'], + [manifestFile, 'oliphaunt-extension-release-manifest-v2'], + ]) { + const release = JSON.parse(readFileSync(file, 'utf8')); + assert.equal(release.schema, schema); + assert.equal(release.product, spec.product); + assert.equal(release.releaseProduct, spec.owner); + assert.equal(release.family, 'native'); + assert.equal(release.version, spec.version); + assert.deepEqual(release.compatibility, nativeCarrierCompatibility(spec)); + assert.deepEqual( + release.extensions.map((member: any) => member.sqlName), + spec.expectedMembers, + ); + const assets = release.carrierAssets ?? release.assets; + assert.equal( + assets.length, + 1, + 'selected Linux manifest input cannot invent complete release coverage', + ); + assert.equal(assets[0].name, path.basename(githubFile)); + assert.equal(assets[0].sha256, digest(readFileSync(githubFile))); + assert.equal(assets[0].bytes, readFileSync(githubFile).length); + assert.equal(assets[0].memberCount, spec.expectedMembers.length); + for (const member of release.extensions) { + assert.equal(member.assets.length, 1); + const asset = member.assets[0], + nested = bundle.members.find((row: any) => row.sqlName === member.sqlName); + assert.equal(asset.carrierAsset, assets[0].name); + assert.equal(asset.carrierRoot, prefix); + assert.equal(asset.memberPath, nested.path); + assert.equal(asset.sha256, nested.sha256); + assert.equal(asset.bytes, nested.bytes); + } + } + + const facade = spec.carriers.find((row) => row.ecosystem === 'npm' && row.target === null)!; + const desktopOwnerFixture = { + name: facade.name, + version: facade.version, + oliphauntQualificationFixture: { + schema: 'oliphaunt-selected-desktop-owner-fixture-v1', + target: spec.target, + testOnly: true, + completeShippingFacade: false, + }, + oliphaunt: { + kind: 'exact-extension-bundle', + product: spec.product, + members: spec.expectedMembers, + liboliphauntVersion: spec.runtimeVersion, + targetPackageNames: Object.fromEntries( + spec.carriers + .filter((row) => row.ecosystem === 'npm' && row.role === 'platform-leaf') + .map((row) => [row.target, row.name]), + ), + }, + }; + const fixtureDirectory = path.join(root, 'node_modules', facade.name); + mkdirSync(fixtureDirectory, { recursive: true }); + writeFileSync( + path.join(fixtureDirectory, 'package.json'), + JSON.stringify(desktopOwnerFixture, null, 2), + ); + assert.equal( + JSON.parse(readFileSync(path.join(fixtureDirectory, 'package.json'), 'utf8')) + .oliphauntQualificationFixture.testOnly, + true, + ); + console.log( + 'Using serialized test-only desktop owner metadata; complete shipping facade remains unproduced.', + ); + const { assets, install, runtime, packages, materialize, sdkRuntimeVersion } = + await prepareNativeCarrierSdk({ + root, + runtimeFile, + npmFiles: [npmFile, pgtapNpm], + runtimeVersion: spec.runtimeVersion, + selected: ['cube', 'pg_trgm'], + }); + const selected = ['cube', 'pg_trgm']; + const descriptor = new Map(spec.members.map((member) => [member.sqlName, member.descriptor])); + const assertSelected = (materialized: any, selectedSql: string[]) => { + assert(materialized.runtimeDirectory); + assert(materialized.moduleDirectory); + caches.add(path.dirname(materialized.runtimeDirectory)); + const expectedModules = selectedSql + .filter((sql) => descriptor.has(sql)) + .map((sql) => descriptor.get(sql)!['native-module-file']) + .sort(); + const baseModules = [path.join(runtime, 'lib/modules'), path.join(runtime, 'modules')].flatMap( + (directory) => (existsSync(directory) ? readdirSync(directory) : []), + ); + assert.deepEqual( + readdirSync(materialized.moduleDirectory).sort(), + [...new Set([...baseModules, ...expectedModules])].sort(), + ); + for (const member of spec.members) { + const wanted = selectedSql.includes(member.sqlName); + for (const [name, entry] of publicEntries.get(member.sqlName)!) + if (name.startsWith('files/')) { + const relative = name.slice('files/'.length); + if (wanted) + assert.deepEqual( + readFileSync(path.join(materialized.runtimeDirectory, relative)), + entry.data(), + ); + else if (relative.startsWith('lib/') || relative.startsWith('share/postgresql/')) + assert( + !existsSync(path.join(materialized.runtimeDirectory, relative)), + `unselected contrib payload staged: ${member.sqlName}/${relative}`, + ); + } + } + }; + const contribOnly = await materialize(selected); + assertSelected(contribOnly, selected); + const combined = await materialize([...selected, 'pgtap']); + assertSelected(combined, [...selected, 'pgtap']); + assert( + existsSync(path.join(combined.runtimeDirectory, 'share/postgresql/extension/pgtap.control')), + ); + exerciseNativeCarrierSql({ + root, + runtime, + materialized: combined, + consumerFile, + plans: [installSql, smokeSql, startupFile], + }); + await assert.rejects( + () => materialize(['not_a_catalogued_extension']), + /unknown|unsupported|catalog/i, + ); + if (sdkRuntimeVersion === spec.runtimeVersion) { + const unused = path.join( + packages[0].directory, + 'extensions/amcheck/runtime/lib/modules/foreign.so', + ); + mkdirSync(path.dirname(unused), { recursive: true }); + writeFileSync(unused, 'undeclared module'); + await assert.rejects( + () => assets.materializeExtensionInstall(install, ['amcheck']), + /undeclared runtime file/, + ); + } + console.log( + `${spec.product}@${spec.version}: all ${spec.expectedMembers.length} runtime-owned nested GitHub/npm/Cargo members verified; only cube/pg_trgm selected, pgtap combined, ${sdkRuntimeVersion === spec.runtimeVersion ? 'matching source SDK asset staging' : 'explicit runtime-directory staging with held SDK rejection'}, actual supplier/embedded restart/server SQL proved.`, + ); +} finally { + for (const cache of caches) rmSync(cache, { recursive: true, force: true }); + writableDirectories(root); + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/extensions/declared_apple_archives.test.mts b/build_defs/extensions/declared_apple_archives.test.mts new file mode 100644 index 000000000..da06c7fbd --- /dev/null +++ b/build_defs/extensions/declared_apple_archives.test.mts @@ -0,0 +1,122 @@ +import { test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + buildIosCarrierManifest, + iosBaseLegalMetadataFromArchives, +} from '../../src/native/sdks/swift/tools/ios-carrier-manifest.mts'; +import { + createDeterministicTar, + createDeterministicZip, +} from '../../tools/packaging/archive-directory.mts'; +import { canonicalGzipSync } from '../../tools/packaging/portable-archive.mts'; +import { releaseNoticeDeclaration } from '../../tools/packaging/release-notices.mts'; +import { fileIdentity } from '../../tools/release/native-file-identity.mts'; + +test('held Apple archives preserve exact old legal bytes independently of current core and Swift pins', async () => { + const root = mkdtempSync(path.join(tmpdir(), 'completed-apple-base-')); + try { + const archives = {}; + for (const [role, profile, prefix, format] of [ + ['base-xcframework', 'native-runtime', 'liboliphaunt.xcframework', 'zip'], + ['runtime-resources', 'native-runtime-resources', '', 'tar.gz'], + ]) { + const stage = path.join(root, role); + mkdirSync(stage, { recursive: true }); + const declaration = releaseNoticeDeclaration(profile); + for (const member of declaration.members) { + const target = path.join(stage, prefix, member); + mkdirSync(path.dirname(target), { recursive: true }); + writeFileSync(target, `genuine fixture old3.4 bytes ${member}\n`, { mode: 0o644 }); + } + const inner = path.join(stage, prefix || 'oliphaunt/runtime'); + mkdirSync(inner, { recursive: true }); + writeFileSync( + path.join(inner, format === 'zip' ? 'Info.plist' : 'fixture.txt'), + 'old3.4 original payload\n', + ); + const name = + role === 'base-xcframework' + ? 'liboliphaunt-0.3.4-apple-spm-xcframework.zip' + : 'liboliphaunt-0.3.4-runtime-resources-ios-datum64.tar.gz'; + const destination = path.join(root, name); + writeFileSync( + destination, + format === 'zip' + ? await createDeterministicZip(path.join(stage, prefix), { keepParent: true }) + : canonicalGzipSync(await createDeterministicTar(stage)), + ); + const identity = fileIdentity(destination); + archives[role] = { path: destination, size: identity.size, sha256: identity.sha256 }; + } + const currentCore = '0.3.5', + heldSwift = '0.3.3'; + assert.notEqual(currentCore, '0.3.4'); + assert.notEqual(heldSwift, '0.3.4'); + const projected = buildIosCarrierManifest({ + baseRuntimeVersion: '0.3.4', + baseArchiveInputs: archives, + baseAssetDir: path.join(root, 'deliberately-missing-current3.5'), + extensionManifests: [], + }); + assert.equal(projected.base.version, '0.3.4'); + assert.equal(projected.base.tag, 'liboliphaunt-native-v0.3.4'); + assert.deepEqual(projected.carriers, []); + assert.deepEqual(projected.extensions, []); + assert.deepEqual(projected.legal.base, iosBaseLegalMetadataFromArchives(archives)); + assert.equal(projected.base.assets[0].sha256, archives['base-xcframework'].sha256); + assert.equal(projected.base.assets[1].sha256, archives['runtime-resources'].sha256); + assert( + projected.legal.base.every((g) => + g.files.every((f) => f.bytes > 0 && /^[a-f0-9]{64}$/.test(f.sha256)), + ), + ); + const originalDoc = path.join(root, 'projected-ios.json'); + writeFileSync(originalDoc, JSON.stringify(projected)); + assert.deepEqual( + buildIosCarrierManifest({ + baseRuntimeVersion: '0.3.4', + baseArchiveInputs: archives, + baseCarrierManifest: originalDoc, + }), + projected, + ); + assert.throws( + () => + buildIosCarrierManifest({ + baseRuntimeVersion: '0.3.4', + baseArchiveInputs: { + ...archives, + 'base-xcframework': { ...archives['base-xcframework'], sha256: '0'.repeat(64) }, + }, + }), + /archive identity differs/, + ); + assert.throws( + () => buildIosCarrierManifest({ baseRuntimeVersion: '4.7.0', baseArchiveInputs: archives }), + /archive identity differs/, + ); + assert.throws(() => + buildIosCarrierManifest({ + baseRuntimeVersion: '0.3.4', + baseArchiveInputs: { 'base-xcframework': archives['base-xcframework'] }, + }), + ); + const changed = structuredClone(projected); + changed.legal.base[0].files[0].sha256 = '0'.repeat(64); + writeFileSync(originalDoc, JSON.stringify(changed)); + assert.throws( + () => + buildIosCarrierManifest({ + baseRuntimeVersion: '0.3.4', + baseArchiveInputs: archives, + baseCarrierManifest: originalDoc, + }), + /exact declared public archives\/legal bytes/, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/build_defs/extensions/declared_final_inputs.bzl b/build_defs/extensions/declared_final_inputs.bzl new file mode 100644 index 000000000..99e98a2f5 --- /dev/null +++ b/build_defs/extensions/declared_final_inputs.bzl @@ -0,0 +1,151 @@ +"""Typed aliases of the controller's original qualified final constructor Files.""" + +load("@oliphaunt_metadata//:metadata.bzl", "CONTRIB_OWNERS", "EXTENSION_FINAL_INPUTS", "COMPLETED_SUPPLIER_ARTIFACTS", "NATIVE_APPLE_BASE_INPUT", "NATIVE_RUNTIME_ARTIFACTS", "NATIVE_SWIFT_SOURCE_INPUT", "PREPARED_NATIVE_SELECTED_PRODUCTS", "PRODUCTS") +load("//build_defs/apple:requirement-selection.bzl", "native_apple_requirement_inputs") +load("//build_defs/apple:slices.bzl", "apple_slice_groups") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") +load("//build_defs/release:supplier.bzl", "ShippingSupplierInfo") +load(":final_leaf.bzl", "ExtensionFinalLeafInfo", "NativeAppleBaseInfo") +load(":owner_carriers.bzl", "native_owner_carrier_helpers", "native_owner_carrier_metadata") + +def _declared_import_impl(ctx): + record = json.decode(ctx.attr.record) + if not record: + fail("extension family requires its original authenticated source/run File inputs: " + ctx.attr.slot) + spec = native_owner_carrier_metadata(record["product"]) + owner = CONTRIB_OWNERS[record["family"]] if spec["releaseMetadata"]["class"] == "contrib" else spec["owner"] + if record["owner"] != owner or record["version"] != PRODUCTS[owner]["version"]: + fail("extension imported Files differ from their conventional owner/version") + if record["family"] == "native" and record["target"] not in [row["target"] for row in spec["profiles"]]: + fail("imported native target is absent from canonical extension profiles") + if record["family"] == "wasix" and record["target"] != "wasix-portable": + fail("imported WASIX family must retain its actual portable constructor cohort") + aliases = {} + for target, alias in ctx.attr.inputs.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1 or files[0].is_directory: + fail("extension original inputs require actual regular Files") + aliases[alias] = files[0] + groups = {} + for name in ["github", "npm", "cargo", "manifest", "frozen"]: + values = record[name] if name in ["github", "npm", "cargo"] else [record[name]] + groups[name] = [aliases[value["path"]] for value in values] + projected = [dict(value, path = aliases[value["path"]].path) for value in values] + record[name] = projected if name in ["github", "npm", "cargo"] else projected[0] + action = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(action, json.encode({"input": record, "canonical": { + "owner": owner, "version": PRODUCTS[owner]["version"], + "sqlNames": [member["sqlName"] for member in spec["members"]], + "sourceIdentity": spec["releaseMetadata"]["sourceIdentity"], + "compatibility": spec["releaseMetadata"]["compatibility"], + "extensionClass": spec["releaseMetadata"]["class"], "versioning": spec["releaseMetadata"]["versioning"], + "targets": [row["target"] for row in spec["allProfiles"] if row["family"] == record["family"]], + }})) + validation = ctx.actions.declare_file(ctx.label.name + ".validated.json") + bun_file_action(ctx, ctx.file._runner, arguments = [action.path, validation.path], + inputs = aliases.values() + [action], source_files = [ctx.file._runner] + ctx.files._helpers, + outputs = [validation], mnemonic = "ImportQualifiedExtensionFinalFiles") + info = ExtensionFinalLeafInfo( + product = record["product"], owner = owner, version = record["version"], + family = record["family"], target = record["target"], metadata = spec, + github = groups["github"], npm = groups["npm"], cargo = groups["cargo"], + manifest = groups["manifest"][0], frozen = groups["frozen"][0], spec = action, + validation = validation, receipt = None, origin = None, original_files = validation, + ) + # These Files are ABI/provenance reuse, not new local compiler inputs. + # The controller retains compiled relationships on the original host root. + suppliers = ShippingSupplierInfo(suppliers = [{ + "product": owner, "version": record["version"], "configuration": record["target"], + "binding": "abi-contract", "origin": {"kind": "current-source", "producer": dict(value["producer"], **({"member": value["member"]} if "member" in value else {}))}, + "files": [{"path": value["path"]}], + } for value in record["github"]], files = depset(groups["github"])) + return [DefaultInfo(files = depset(aliases.values() + [validation])), info, suppliers, + OutputGroupInfo(validation = depset([validation]), spec = depset([action]))] + +_declared_import = rule(implementation = _declared_import_impl, toolchains = BUN_SOURCE_TOOLCHAINS, attrs = { + "slot": attr.string(mandatory = True), "record": attr.string(mandatory = True), + "inputs": attr.label_keyed_string_dict(allow_files = True), + "_runner": attr.label(default = "//build_defs/extensions:declared_final_inputs.mts", allow_single_file = True), + "_helpers": attr.label_list(default = native_owner_carrier_helpers(), allow_files = True), +}) + +def native_extension_declared_final_import(name, product, family, target, **kwargs): + slot = product + "/" + family + "/" + target + record = EXTENSION_FINAL_INPUTS.get(slot, {}) + files = [file for group in ["github", "npm", "cargo"] for file in record.get(group, [])] + files += [record[group] for group in ["manifest", "frozen"] if group in record] + _declared_import(name = name, slot = slot, record = json.encode(record), + inputs = {file["path"]: file["path"] for file in files}, **kwargs) + +def _apple_base_impl(ctx): + if ctx.attr.error: + fail(ctx.attr.error + " at " + ctx.attr.version) + record = json.decode(ctx.attr.record) + archive_records = json.decode(ctx.attr.archive_records) + archive_inputs = {} + files = [] + supplier_rows = [] + for target, role in ctx.attr.archives.items(): + archive = target[DefaultInfo].files.to_list() + if len(archive) != 1 or archive[0].is_directory: + fail("completed Apple archive requires its exact regular File") + captured = archive_records[role] + archive_inputs[role] = dict(captured["file"], path = archive[0].path) + files.append(archive[0]) + completed = "publication" in captured + origin = {"kind": "completed-publication", "publication": captured["publication"], "artifact": captured["artifact"]} if completed else {"kind": "current-source"} + if not completed and "producer" in captured["file"]: + origin["producer"] = captured["file"]["producer"] + supplier_rows.append({"product": captured["publication"]["product"] if completed else captured["owner"], "version": captured["publication"]["version"] if completed else captured["version"], + "configuration": "apple-spm-xcframework" if role == "base-xcframework" else "ios-datum64", "binding": "abi-contract", + "origin": origin, + "files": [{"path": archive[0].path}]}) + if not record and len(archive_inputs) != 2: + fail("extension native facade is missing exact completed Apple archive inputs at its declared version " + ctx.attr.version) + if record: + if not ctx.file.input: + fail("original Apple base document is missing its declared File") + record["file"]["path"] = ctx.file.input.path + files.append(ctx.file.input) + origin = {"kind": "current-source"} + if not ctx.attr.local_current: + origin["producer"] = dict(record["file"]["producer"], **({"member": record["file"]["member"]} if "member" in record["file"] else {})) + supplier_rows.append({"product": record["owner"], "version": record["version"], + "configuration": "ios-xcframework" if record["owner"] == "liboliphaunt-native" else "portable", + "binding": "abi-contract", "origin": origin, + "files": [{"path": ctx.file.input.path}]}) + action = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(action, json.encode({"input": record, "archives": archive_inputs, "localCurrent": ctx.attr.local_current, + "canonical": {"kind": "native-apple-base", "version": ctx.attr.version}})) + output = ctx.actions.declare_file(ctx.label.name + "/ios.json") + bun_file_action(ctx, ctx.file._runner, arguments = [action.path, output.path], inputs = files + [action], + source_files = [ctx.file._runner] + ctx.files._helpers, outputs = [output], mnemonic = "DeclaredNativeAppleBase") + return [DefaultInfo(files = depset([output])), + NativeAppleBaseInfo(version = ctx.attr.version, file = output, archives = archive_inputs, archive_files = [file for file in files if file != ctx.file.input]), + ShippingSupplierInfo(suppliers = supplier_rows, files = depset(files)), + OutputGroupInfo(framework = depset([file for file in files if file.path == archive_inputs.get("base-xcframework", {}).get("path")]), resources = depset([file for file in files if file.path == archive_inputs.get("runtime-resources", {}).get("path")]), **apple_slice_groups(ctx.attr.archives.keys()))] + +_apple_base_import = rule(implementation = _apple_base_impl, toolchains = BUN_SOURCE_TOOLCHAINS, attrs = { + "record": attr.string(mandatory = True), "version": attr.string(mandatory = True), "input": attr.label(allow_single_file = True), "archives": attr.label_keyed_string_dict(allow_files = True), "archive_records": attr.string(mandatory = True), "local_current": attr.bool(), "error": attr.string(), + "_runner": attr.label(default = "//build_defs/extensions:declared_final_inputs.mts", allow_single_file = True), + "_helpers": attr.label_list(default = native_owner_carrier_helpers(), allow_files = True), +}) + +def native_declared_apple_base(name, version = None, local_current = False, **kwargs): + required = version or PRODUCTS["liboliphaunt-native"]["version"] + archives = {} + for role, kind, target in [("base-xcframework", "apple-swiftpm-binary", "apple-spm-xcframework"), ("runtime-resources", "runtime-resources", "ios-datum64")]: + rows = [row for row in NATIVE_RUNTIME_ARTIFACTS if row["product"] == "liboliphaunt-native" and row["kind"] == kind and row["target"] == target and "github-release" in row["surfaces"]] + if len(rows) != 1: + fail("native Apple base requires one conventional archive declaration for " + role) + artifact = "github-release:" + rows[0]["asset"].replace("{version}", required) + captured = COMPLETED_SUPPLIER_ARTIFACTS.get("liboliphaunt-native/" + required + "/" + artifact) + if captured: + archives[role] = captured + decision = native_apple_requirement_inputs(required, PRODUCTS["liboliphaunt-native"]["version"], PREPARED_NATIVE_SELECTED_PRODUCTS, archives, NATIVE_APPLE_BASE_INPUT, local_current) + record, archives = decision.get("record", {}), decision.get("archives", {}) + _apple_base_import(name = name, record = json.encode(record), version = required, + local_current = decision.get("local_current", False), error = decision.get("error", ""), + input = record["file"]["path"] if record else None, + archives = {capture["file"]["path"]: role for role, capture in archives.items()}, + archive_records = json.encode(archives), **kwargs) diff --git a/build_defs/extensions/declared_final_inputs.mts b/build_defs/extensions/declared_final_inputs.mts new file mode 100644 index 000000000..b1f4af1de --- /dev/null +++ b/build_defs/extensions/declared_final_inputs.mts @@ -0,0 +1,198 @@ +/** Check actual imported final Files; authentication stays with the original controller. */ +import assert from 'node:assert/strict'; +import { copyFileSync, readFileSync, realpathSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { composeExtensionReleaseDocuments } from '../../src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts'; +import { buildIosCarrierManifest } from '../../src/native/sdks/swift/tools/ios-carrier-manifest.mts'; +import { validateSelectionNeutralSwiftSourceCarrier } from '../../src/native/sdks/swift/tools/swift-native-carrier-contract.mts'; +import type { + ExtensionFinalInput, + NativeAppleBaseInput, +} from '../../tools/release/native-extension-final-inputs.mts'; +import { fileIdentity } from '../../tools/release/native-file-identity.mts'; + +export function validateDeclaredNativeAppleBase( + input: + | NativeAppleBaseInput + | { owner: 'oliphaunt-swift'; version: string; file: NativeAppleBaseInput['file'] }, + version: string, +) { + if (input.owner === 'liboliphaunt-native') { + assert.equal(input.version, version); + assert.equal(path.basename(input.file.path), 'ios.json'); + assert.equal(input.file.producer.root, '//src/native/runtime:apple_ios_manifest_shipping'); + assert.equal(input.file.member, undefined); + } else { + assert.equal(input.owner, 'oliphaunt-swift'); + assert.match(input.version, /^\d+\.\d+\.\d+$/u); + assert.equal(path.basename(input.file.path), 'oliphaunt-react-native-ios-carriers.json'); + assert.equal( + input.file.producer.root, + '//src/native/sdks/swift:shipping_oliphaunt-react-native-ios-carriers_json', + ); + assert.equal( + input.file.member, + 'src/sdks/swift/Carriers/oliphaunt-react-native-ios-carriers.json', + ); + } + const actual = fileIdentity(realpathSync(input.file.path)); + assert.deepEqual( + { size: actual.size, sha256: actual.sha256 }, + { size: input.file.size, sha256: input.file.sha256 }, + 'imported Apple base original File bytes differ', + ); + const manifest = JSON.parse(readFileSync(input.file.path, 'utf8')); + validateSelectionNeutralSwiftSourceCarrier(manifest, 'original native Apple base'); + assert.equal(manifest.base.version, version); + assert.equal(manifest.base.tag, `liboliphaunt-native-v${version}`); + return input; +} + +/** Construct from retained completed-publication Files when no original + * document exists. The original document, if supplied, must match those bytes. */ +export function declaredNativeAppleBaseManifest( + input, + version, + archives = {}, + localCurrent = false, +) { + if (localCurrent) { + assert.equal(input.owner, 'liboliphaunt-native'); + assert.equal(input.version, version); + assert.deepEqual(Object.keys(archives).sort(), ['base-xcframework', 'runtime-resources']); + archives = Object.fromEntries( + Object.entries(archives).map(([role, file]) => [ + role, + { ...fileIdentity(realpathSync(file.path)), path: realpathSync(file.path) }, + ]), + ); + } else if (input && Object.keys(input).length) validateDeclaredNativeAppleBase(input, version); + if (Object.keys(archives).length) { + return buildIosCarrierManifest({ + baseRuntimeVersion: version, + // The rule supplies declared Files through Bazel's repository aliases. + // Preserve expected byte identities; resolve only their outer transport. + baseArchiveInputs: Object.fromEntries( + Object.entries(archives).map(([role, file]) => [ + role, + { ...file, path: realpathSync(file.path) }, + ]), + ), + baseCarrierManifest: input?.file ? realpathSync(input.file.path) : undefined, + baseTag: `liboliphaunt-native-v${version}`, + declaredProducts: {}, + extensionManifests: [], + }); + } + assert(input?.owner, `missing original Apple base inputs at declared version ${version}`); + return JSON.parse(readFileSync(input.file.path, 'utf8')); +} + +export function validateDeclaredExtensionFinalInput( + input: ExtensionFinalInput, + canonical: { + owner: string; + version: string; + sqlNames: string[]; + sourceIdentity: unknown; + compatibility: unknown; + extensionClass: string; + versioning: string; + targets: string[]; + }, +) { + assert.equal(input.owner, canonical.owner); + assert.equal(input.version, canonical.version); + const files = [...input.github, ...input.npm, ...input.cargo, input.manifest, input.frozen]; + for (const file of files) { + // Bazel supplies declared repository aliases through its input symlink forest. + const actual = fileIdentity(realpathSync(file.path)); + assert.deepEqual( + { size: actual.size, sha256: actual.sha256 }, + { size: file.size, sha256: file.sha256 }, + 'imported extension original File bytes differ', + ); + } + const frozen = JSON.parse(readFileSync(input.frozen.path, 'utf8')); + const manifest = JSON.parse(readFileSync(input.manifest.path, 'utf8')); + const members = frozen.extensions ?? [frozen]; + const version = members.length > 1 ? 2 : 1; + assert.equal(frozen.schema, `oliphaunt-extension-ci-artifacts-v${version}`); + assert.equal(manifest.schema, `oliphaunt-extension-release-manifest-v${version}`); + for (const document of [frozen, manifest]) { + assert.equal(document.product, input.product); + assert.equal(document.releaseProduct ?? document.product, input.owner); + assert.equal(document.version, input.version); + assert.deepEqual(document.compatibility, canonical.compatibility); + if (document.family !== undefined) + assert.equal( + document.family, + input.family, + 'selected constructor document belongs to another family', + ); + } + assert.deepEqual(manifest.sourceIdentity, canonical.sourceIdentity); + assert.deepEqual(members.map((member) => member.sqlName).sort(), [...canonical.sqlNames].sort()); + const assets = frozen.carrierAssets ?? members[0].assets; + const releaseData = composeExtensionReleaseDocuments({ + product: input.product, + releaseProduct: input.owner, + family: frozen.family ?? null, + version: input.version, + members, + directAssets: assets, + releaseMetadata: { + class: canonical.extensionClass, + versioning: canonical.versioning, + sourceIdentity: canonical.sourceIdentity, + compatibility: canonical.compatibility, + }, + }).releaseData; + assert.deepEqual( + manifest, + JSON.parse(JSON.stringify(releaseData)), + 'selected public manifest differs from its frozen member/assets contract', + ); + const github = new Map(input.github.map((file) => [path.basename(file.path), file])); + assert.equal(github.size, input.github.length, 'imported GH File names repeat'); + assert.deepEqual( + [...github.keys()].sort(), + assets.map((asset) => asset.name).sort(), + 'imported GH Files differ from their frozen asset set', + ); + for (const member of members) + for (const asset of member.assets) { + assert.equal(asset.family, input.family); + assert(canonical.targets.includes(asset.target), 'imported member target is undeclared'); + // A portable WASIX constructor owns its portable and configured AOT + // envelopes. Native constructors each own exactly one target cohort. + if (input.family === 'native') assert.equal(asset.target, input.target); + } + for (const asset of assets) { + assert.equal(asset.family, input.family); + assert(canonical.targets.includes(asset.target), 'imported carrier target is undeclared'); + const file = github.get(asset.name)!; + assert.equal(asset.sha256, file.sha256); + assert.equal(asset.bytes, file.size); + } + return input; +} + +if (import.meta.main) { + const [specification, output] = process.argv.slice(2); + assert.equal(process.argv.length, 4); + const { input, archives, canonical, localCurrent } = JSON.parse( + readFileSync(specification, 'utf8'), + ); + if (canonical.kind === 'native-apple-base') { + const manifest = declaredNativeAppleBaseManifest( + input, + canonical.version, + archives, + localCurrent, + ); + if (input?.owner && !Object.keys(archives ?? {}).length) copyFileSync(input.file.path, output); + else writeFileSync(output, JSON.stringify(manifest, null, 2) + '\n'); + } else + writeFileSync(output, JSON.stringify(validateDeclaredExtensionFinalInput(input, canonical))); +} diff --git a/build_defs/extensions/declared_final_inputs.test.mts b/build_defs/extensions/declared_final_inputs.test.mts new file mode 100644 index 000000000..352e8f78d --- /dev/null +++ b/build_defs/extensions/declared_final_inputs.test.mts @@ -0,0 +1,598 @@ +/** Document/File transport fixtures; these never claim foreign package or runtime qualification. */ +import { afterEach, expect, test } from 'bun:test'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + composeExtensionReleaseDocuments, + writeReleaseControls, +} from '../../src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts'; +import { archiveDirectory } from '../../tools/packaging/archive-directory.mts'; +import { releaseNoticeDeclaration } from '../../tools/packaging/release-notices.mts'; +import type { ExtensionFinalInput } from '../../tools/release/native-extension-final-inputs.mts'; +import { fileIdentity } from '../../tools/release/native-file-identity.mts'; +import { + declaredNativeAppleBaseManifest, + validateDeclaredExtensionFinalInput, + validateDeclaredNativeAppleBase, +} from './declared_final_inputs.mts'; +import { + mergeNativeFinalMembers, + type NativeOwnerSpec, + ownerFamilyCompleteness, + stageDeclaredFinalLeaf, +} from './owner_carriers.mts'; + +const directories: string[] = []; +afterEach(() => { + for (const directory of directories.splice(0)) + rmSync(directory, { recursive: true, force: true }); +}); +const product = 'oliphaunt-extension-pgtap'; +const compatibility = { + nativeRuntimeProduct: 'liboliphaunt-native', + nativeRuntimeVersion: '1.2.3', + wasixRuntimeProduct: 'liboliphaunt-wasix', + wasixRuntimeVersion: '4.5.6', +}; +const sourceIdentity = { type: 'git', commit: 'a'.repeat(40) }; + +test('original Apple base stays selection-neutral and pins the actual conventional runtime', () => { + const directory = mkdtempSync(path.join(tmpdir(), 'declared-original-apple-base-')); + directories.push(directory); + const source = path.join(directory, 'ios.json'); + writeFileSync( + source, + readFileSync(path.resolve(import.meta.dir, '../release/testdata/swift-0.8.2-carrier.json')), + ); + const identity = fileIdentity(source); + const input = { + owner: 'liboliphaunt-native' as const, + version: '0.3.3', + file: { + path: source, + size: identity.size, + sha256: identity.sha256, + producer: { + evidenceDigest: `sha256:${'1'.repeat(64)}`, + invocationId: 'document-fixture', + root: '//src/native/runtime:apple_ios_manifest_shipping', + configuration: '2'.repeat(64), + output: 'bazel-out/config/bin/apple_release_assets/ios.json', + }, + }, + }; + expect(validateDeclaredNativeAppleBase(input, '0.3.3')).toBe(input); + expect(() => validateDeclaredNativeAppleBase(input, '0.3.4')).toThrow(); + expect(() => + validateDeclaredNativeAppleBase( + { ...input, file: { ...input.file, sha256: '0'.repeat(64) } }, + '0.3.3', + ), + ).toThrow(); + const changed = JSON.parse(readFileSync(source, 'utf8')); + changed.extensions.push({ sqlName: 'invented' }); + writeFileSync(source, JSON.stringify(changed)); + const changedIdentity = fileIdentity(source); + expect(() => + validateDeclaredNativeAppleBase( + { + ...input, + file: { ...input.file, size: changedIdentity.size, sha256: changedIdentity.sha256 }, + }, + '0.3.3', + ), + ).toThrow(/selection-neutral/); +}); +const canonical = { + owner: product, + version: '7.8.9', + sqlNames: ['pgtap'], + sourceIdentity, + compatibility, + extensionClass: 'external', + versioning: 'upstream-bound', + targets: ['linux-x64-gnu', 'ios-xcframework', 'wasix-portable'], +}; +function fixture(family: 'native' | 'wasix' = 'native') { + const root = mkdtempSync(path.join(tmpdir(), 'declared-extension-contract-')); + directories.push(root); + const target = family === 'native' ? 'linux-x64-gnu' : 'wasix-portable'; + const file = (name: string, contents: string) => { + const destination = path.join(root, name); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, contents); + const identity = fileIdentity(destination); + return { + path: destination, + size: identity.size, + sha256: identity.sha256, + producer: { + evidenceDigest: `sha256:${'1'.repeat(64)}`, + invocationId: 'document-fixture', + root: '//fixture:shipping', + configuration: '2'.repeat(64), + output: `bazel-out/config/bin/fixture/${name}`, + }, + }; + }; + const github = file( + `${product}-7.8.9-${family === 'native' ? 'native-linux-x64-gnu-runtime.tar.gz' : 'wasix-portable.tar.zst'}`, + 'metadata fixture; no binary qualification', + ); + const member = { + sqlName: 'pgtap', + dependencies: [], + dataFiles: [], + extensionSqlFileNames: [], + extensionSqlFilePrefixes: [], + createsExtension: true, + nativeModuleStem: null, + iosNativeDependencies: [], + iosRegistration: null, + wasixInstall: + family === 'wasix' + ? { schema: 'installed-contract-fixture', installedFiles: ['pgtap.control'] } + : null, + sharedPreloadLibraries: [], + assets: [ + { + name: path.basename(github.path), + family, + target, + kind: family === 'native' ? 'runtime' : 'wasix-runtime', + identity: null, + bytes: github.size, + sha256: github.sha256, + }, + ], + }; + const documents = composeExtensionReleaseDocuments({ + product, + releaseProduct: product, + family: family === 'native' ? 'native' : null, + version: '7.8.9', + members: [member], + directAssets: member.assets, + releaseMetadata: { + class: 'external', + versioning: 'upstream-bound', + sourceIdentity, + compatibility, + }, + }); + const input: ExtensionFinalInput = { + product, + owner: product, + version: '7.8.9', + family, + target, + github: [github], + npm: [file('candidate.tgz', 'npm document fixture')], + cargo: [file('candidate.crate', 'cargo document fixture')], + manifest: file('selected-manifest.json', JSON.stringify(documents.releaseData)), + frozen: file('extension-artifacts.json', JSON.stringify(documents.manifest)), + }; + const originalFiles = path.join(root, 'original-files.json'); + writeFileSync(originalFiles, JSON.stringify(input)); + const leaf = { + ...input, + github: input.github.map((value) => value.path), + npm: input.npm.map((value) => value.path), + cargo: input.cargo.map((value) => value.path), + manifest: input.manifest.path, + frozen: input.frozen.path, + originalFiles, + }; + const spec = { + product, + owner: product, + version: '7.8.9', + members: [{ sqlName: 'pgtap' }], + profiles: [{ target: 'linux-x64-gnu' }, { target: 'ios-xcframework' }], + ownerFamilies: ['native', 'wasix'], + } as NativeOwnerSpec; + return { root, input, documents, member, leaf, spec }; +} +function replaceDocument( + input: ExtensionFinalInput, + which: 'manifest' | 'frozen', + mutate: (value: any) => void, +) { + const value = JSON.parse(readFileSync(input[which].path, 'utf8')); + mutate(value); + writeFileSync(input[which].path, JSON.stringify(value)); + const identity = fileIdentity(input[which].path); + input[which].size = identity.size; + input[which].sha256 = identity.sha256; +} + +test('checks original bytes and canonical documents without treating fixtures as runtime proof', () => { + for (const family of ['native', 'wasix'] as const) { + const { input } = fixture(family); + expect(validateDeclaredExtensionFinalInput(input, canonical)).toBe(input); + writeFileSync(input.github[0].path, 'changed original bytes'); + expect(() => validateDeclaredExtensionFinalInput(input, canonical)).toThrow( + 'original File bytes differ', + ); + } +}); +test('rejects changed Apple/WASIX/member fields even when document hashes are freshly captured', () => { + for (const field of [ + 'iosRegistration', + 'wasixInstall', + 'dependencies', + 'extensionClass', + 'sourceIdentity', + ]) { + const { input } = fixture(); + replaceDocument(input, 'manifest', (document) => { + document[field] = { changed: field }; + }); + expect(() => validateDeclaredExtensionFinalInput(input, canonical)).toThrow(); + } + const { input } = fixture(); + replaceDocument(input, 'frozen', (document) => { + document.assets[0].target = 'made-up-platform'; + }); + replaceDocument(input, 'manifest', (document) => { + document.assets[0].target = 'made-up-platform'; + }); + expect(() => validateDeclaredExtensionFinalInput(input, canonical)).toThrow( + 'target is undeclared', + ); + const wrongFamily = fixture(); + replaceDocument(wrongFamily.input, 'frozen', (document) => { + document.family = 'wasix'; + }); + replaceDocument(wrongFamily.input, 'manifest', (document) => { + document.family = 'wasix'; + }); + expect(() => validateDeclaredExtensionFinalInput(wrongFamily.input, canonical)).toThrow( + 'another family', + ); +}); +test('rejects missing, repeated and substituted physical GH Files independently of labels', () => { + for (const alter of [ + (input: ExtensionFinalInput) => { + input.github = []; + }, + (input: ExtensionFinalInput) => { + input.github.push(input.github[0]); + }, + (input: ExtensionFinalInput) => { + input.github = [input.npm[0]]; + }, + ]) { + const { input } = fixture(); + alter(input); + expect(() => validateDeclaredExtensionFinalInput(input, canonical)).toThrow(); + } +}); +test('stages only the original File map and rejects a path relabeling', () => { + const { leaf, spec, root, input } = fixture(); + validateDeclaredExtensionFinalInput(input, canonical); + const staged = stageDeclaredFinalLeaf(spec, leaf, path.join(root, 'stage')); + expect( + readFileSync(path.join(path.dirname(staged.productRoot), staged.directAssets[0].path)), + ).toEqual(readFileSync(leaf.github[0])); + expect(staged.members[0].sqlName).toBe('pgtap'); + expect(() => + stageDeclaredFinalLeaf(spec, { ...leaf, github: leaf.npm }, path.join(root, 'other')), + ).toThrow(); +}); +test('complete external owner requires all native targets plus the genuine WASIX cohort', () => { + const native = fixture(), + wasix = fixture('wasix'); + expect(ownerFamilyCompleteness(native.spec, [native.leaf]).missingNativeTargets).toEqual([ + 'ios-xcframework', + ]); + const ios = { ...native.leaf, target: 'ios-xcframework' }; + expect(ownerFamilyCompleteness(native.spec, [native.leaf, ios]).missingOwnerFamilies).toEqual([ + 'wasix', + ]); + expect( + ownerFamilyCompleteness(native.spec, [native.leaf, ios, wasix.leaf]) + .completeExtensionDistribution, + ).toBe(true); + expect(() => ownerFamilyCompleteness(native.spec, [native.leaf, native.leaf])).toThrow( + 'repeated', + ); + expect(() => + ownerFamilyCompleteness(native.spec, [{ ...wasix.leaf, target: 'wasix-aot-made-up' }]), + ).toThrow('portable constructor'); + expect(() => + ownerFamilyCompleteness({ ...native.spec, ownerFamilies: ['native'] }, [ + native.leaf, + ios, + wasix.leaf, + ]), + ).toThrow('undeclared'); +}); +test('merge keeps distinct genuine Apple and WASIX contracts and rejects common SQL disagreement', () => { + const native = fixture(), + wasix = fixture('wasix'); + const ios = { + ...native.member, + iosRegistration: { symbolPrefix: 'pgtap' }, + assets: native.member.assets.map((asset) => ({ ...asset, target: 'ios-xcframework' })), + }; + const cohorts = [{ members: [native.member] }, { members: [ios] }, { members: [wasix.member] }]; + const merged = mergeNativeFinalMembers(native.spec, cohorts); + expect(merged[0].iosRegistration).toEqual(ios.iosRegistration); + expect(merged[0].wasixInstall).toEqual(wasix.member.wasixInstall); + expect(merged[0].assets).toHaveLength(3); + expect(() => + mergeNativeFinalMembers(native.spec, [...cohorts, { members: [wasix.member] }]), + ).toThrow(); + wasix.member.dependencies = ['different'] as never[]; + expect(() => mergeNativeFinalMembers(native.spec, cohorts)).toThrow('differs across original'); +}); + +test('final single and bundle controls supply absent Apple fields without changing frozen cohorts', () => { + const native = fixture(), + wasix = fixture('wasix'); + const compact = ({ iosNativeDependencies, iosRegistration, ...member }: typeof native.member) => + member; + const ios = { + ...native.member, + iosNativeDependencies: ['actual-link-unit'], + iosRegistration: { symbolPrefix: 'pgtap' }, + assets: native.member.assets.map((asset) => ({ ...asset, target: 'ios-xcframework' })), + }; + for (const count of [1, 2]) { + for (const rows of [ + [compact(native.member)], + [compact(wasix.member)], + [compact(native.member), compact(wasix.member)], + [compact(native.member), ios, compact(wasix.member)], + ]) { + const cohorts = rows.map((row) => ({ + members: Array.from({ length: count }, (_, index) => ({ + ...row, + sqlName: `member${index}`, + })), + })); + const before = structuredClone(cohorts); + const members = mergeNativeFinalMembers( + { + ...native.spec, + members: cohorts[0].members.map(({ sqlName }) => ({ sqlName })), + } as NativeOwnerSpec, + cohorts, + ); + const hasIos = rows.includes(ios); + for (const member of members) { + expect(member.iosNativeDependencies).toEqual(hasIos ? ios.iosNativeDependencies : []); + expect(member.iosRegistration).toEqual(hasIos ? ios.iosRegistration : null); + expect(member.wasixInstall).toEqual( + rows.length === 1 && rows[0].wasixInstall === null ? null : wasix.member.wasixInstall, + ); + } + const inputs = { + product: count === 1 ? product : 'oliphaunt-extension-contrib-pg18', + releaseProduct: + count === 1 + ? product + : rows[0].assets[0].family === 'wasix' + ? 'liboliphaunt-wasix' + : 'liboliphaunt-native', + family: rows.length === 1 ? rows[0].assets[0].family : null, + version: native.spec.version, + members, + directAssets: [], + releaseMetadata: { + class: count === 1 ? 'external' : 'contrib', + versioning: count === 1 ? 'upstream-bound' : 'runtime-bound', + sourceIdentity, + compatibility, + }, + }; + const productRoot = path.join(native.root, `controls-${count}-${rows.length}-${hasIos}`); + mkdirSync(path.join(productRoot, 'release-assets'), { recursive: true }); + const controls = writeReleaseControls({ + ...inputs, + ...composeExtensionReleaseDocuments(inputs), + productRoot, + root: native.root, + }); + const release = JSON.parse(readFileSync(controls.releaseManifest, 'utf8')); + for (const member of release.extensions ?? [release]) { + expect(member.iosNativeDependencies).toEqual(hasIos ? ios.iosNativeDependencies : []); + expect(member.iosRegistration).toEqual(hasIos ? ios.iosRegistration : null); + } + expect(readFileSync(controls.propertiesManifest, 'utf8')).toContain( + `iosNativeDependencies=${hasIos ? 'actual-link-unit' : ''}\n`, + ); + expect(cohorts).toEqual(before); + } + } +}); + +test('completed Apple archive factory accepts its actual empty document record and rejects malformed original documents', async () => { + const root = mkdtempSync(path.join(tmpdir(), 'completed-apple-base-factory-')); + directories.push(root); + const version = '9.0.0'; + const archives: Record = {}; + for (const [role, name, profile, member] of [ + [ + 'base-xcframework', + 'liboliphaunt-' + version + '-apple-spm-xcframework.zip', + 'native-runtime', + 'liboliphaunt.xcframework', + ], + [ + 'runtime-resources', + 'liboliphaunt-' + version + '-runtime-resources-ios-datum64.tar.gz', + 'native-runtime-resources', + 'oliphaunt', + ], + ]) { + const stage = path.join(root, role); + const leaf = path.join(stage, member); + mkdirSync(leaf, { recursive: true }); + writeFileSync( + path.join(leaf, 'fixture.txt'), + 'archive contract fixture; no runtime qualification', + ); + const notices = role === 'runtime-resources' ? stage : leaf; + for (const member of releaseNoticeDeclaration(profile).members) { + const file = path.join(notices, member); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, 'controlled notice fixture: ' + member + '\n'); + } + const file = path.join(root, name); + await archiveDirectory(role === 'runtime-resources' ? stage : leaf, file, { + keepParent: role === 'base-xcframework', + }); + const { size, sha256 } = fileIdentity(file); + archives[role] = { path: file, size, sha256 }; + } + const result = declaredNativeAppleBaseManifest({}, version, archives); + expect(result.base.version).toBe(version); + for (const role of ['base-xcframework', 'runtime-resources']) + expect(result.base.assets.find((row: any) => row.role === role).sha256).toBe( + archives[role].sha256, + ); + const aliases = path.join(root, 'declared-inputs'); + mkdirSync(aliases); + const aliasedArchives = Object.fromEntries( + Object.entries(archives).map(([role, file]) => { + const alias = path.join(aliases, path.basename(file.path)); + symlinkSync(file.path, alias); + return [role, { ...file, path: alias }]; + }), + ); + expect(declaredNativeAppleBaseManifest({}, version, aliasedArchives)).toEqual(result); + expect( + declaredNativeAppleBaseManifest( + { owner: 'liboliphaunt-native', version }, + version, + aliasedArchives, + true, + ), + ).toEqual(result); + const document = path.join(root, 'ios.json'); + writeFileSync(document, JSON.stringify(result)); + const documentAlias = path.join(aliases, 'ios.json'); + symlinkSync(document, documentAlias); + const documentIdentity = fileIdentity(document); + const original = { + owner: 'liboliphaunt-native', + version, + file: { + path: documentAlias, + size: documentIdentity.size, + sha256: documentIdentity.sha256, + producer: { + evidenceDigest: 'sha256:' + '1'.repeat(64), + invocationId: 'document-fixture', + root: '//src/native/runtime:apple_ios_manifest_shipping', + configuration: '2'.repeat(64), + output: 'bazel-out/config/bin/apple_release_assets/ios.json', + }, + }, + }; + expect(declaredNativeAppleBaseManifest(original, version, aliasedArchives)).toEqual(result); + expect(() => + declaredNativeAppleBaseManifest( + { ...original, file: { ...original.file, sha256: '0'.repeat(64) } }, + version, + aliasedArchives, + ), + ).toThrow('original File bytes differ'); + expect(() => + declaredNativeAppleBaseManifest({}, version, { + ...aliasedArchives, + 'runtime-resources': { ...aliasedArchives['runtime-resources'], sha256: '0'.repeat(64) }, + }), + ).toThrow('archive identity differs'); + expect(() => + declaredNativeAppleBaseManifest({ file: { path: 'invented.json' } }, version, archives), + ).toThrow(); + expect(() => + declaredNativeAppleBaseManifest({ owner: 'liboliphaunt-native', version }, version, archives), + ).toThrow(); + expect(() => + declaredNativeAppleBaseManifest({}, version, { + 'base-xcframework': archives['base-xcframework'], + }), + ).toThrow(); + expect(() => + declaredNativeAppleBaseManifest({}, version, { + ...archives, + 'runtime-resources': { ...archives['runtime-resources'], sha256: '0'.repeat(64) }, + }), + ).toThrow(); +}); + +test('nested closed bundle follows only its declared outer File alias and retains original identities', async () => { + const { root, input, member, spec, leaf } = fixture(); + const prefix = 'closed-bundle'; + const nested = readFileSync(input.github[0].path); + const members = ['pgtap', 'second-document-fixture'].map((sqlName) => ({ + ...member, + sqlName, + assets: member.assets.map((asset) => ({ + ...asset, + carrierAsset: 'closed-bundle.tar.gz', + carrierRoot: prefix, + memberPath: `${sqlName}/${asset.name}`, + })), + })); + const stage = path.join(root, prefix); + for (const member of members) { + const file = path.join(stage, member.assets[0].memberPath); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, nested); + } + const archive = path.join(root, 'closed-bundle.tar.gz'); + await archiveDirectory(stage, archive, { keepParent: true }); + const alias = path.join(root, 'runfiles', path.basename(archive)); + mkdirSync(path.dirname(alias), { recursive: true }); + symlinkSync(archive, alias); + const { size, sha256 } = fileIdentity(archive); + input.github = [{ ...input.github[0], path: alias, size, sha256 }]; + const documents = composeExtensionReleaseDocuments({ + product, + releaseProduct: product, + family: 'native', + version: input.version, + members, + directAssets: [{ ...member.assets[0], name: path.basename(alias), bytes: size, sha256 }], + releaseMetadata: { + class: 'external', + versioning: 'upstream-bound', + sourceIdentity, + compatibility, + }, + }); + replaceDocument(input, 'manifest', (value) => { + for (const key of Object.keys(value)) delete value[key]; + Object.assign(value, documents.releaseData); + }); + replaceDocument(input, 'frozen', (value) => { + for (const key of Object.keys(value)) delete value[key]; + Object.assign(value, documents.manifest); + }); + leaf.github = [alias]; + writeFileSync(leaf.originalFiles, JSON.stringify(input)); + validateDeclaredExtensionFinalInput(input, { + ...canonical, + sqlNames: members.map((m) => m.sqlName), + }); + const staged = stageDeclaredFinalLeaf(spec, leaf, path.join(root, 'staged-alias')); + expect(staged.leaf).toBe(leaf); + expect(staged.leaf.github).toEqual([alias]); + for (const member of staged.members) + expect( + readFileSync(path.join(path.dirname(staged.productRoot), member.assets[0].path)), + ).toEqual(nested); + expect(staged.inventory.find((row) => row.path === 'github/closed-bundle.tar.gz')).toMatchObject({ + bytes: size, + sha256, + }); + expect(() => + stageDeclaredFinalLeaf(spec, { ...leaf, github: [archive] }, path.join(root, 'relabel')), + ).toThrow(); +}); diff --git a/build_defs/extensions/desktop_sql.test.mts b/build_defs/extensions/desktop_sql.test.mts new file mode 100644 index 000000000..d073974e7 --- /dev/null +++ b/build_defs/extensions/desktop_sql.test.mts @@ -0,0 +1,327 @@ +/** The canonical extension SQL plan against relocated candidate desktop bytes. */ +import assert from 'node:assert/strict'; +import { + chmodSync, + copyFileSync, + mkdirSync, + mkdtempSync, + readFileSync, + realpathSync, + renameSync, + rmSync, + statSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join, resolve } from 'node:path'; +import { parseArgs } from 'node:util'; +import { + extractPortableArchiveTree, + readPortableArchiveEntries, +} from '../../tools/packaging/portable-archive.mts'; +import { + assertMissingHostRuntime, + extractNativePayload, + hostRuntimeEnvironment, + runHostBinary, +} from '../native/host-runtime-test-helpers.mts'; +import { validateDesktopConstruction } from './construction.mts'; + +const { values, positionals } = parseArgs({ + allowPositionals: true, + options: { + 'runtime-prefix': { type: 'string', default: '.' }, + 'library-prefix': { type: 'string', default: process.platform === 'win32' ? 'bin' : 'lib' }, + 'published-runtime': { type: 'boolean', default: false }, + 'restricted-launcher': { type: 'string' }, + }, +}); +for (const prefix of [values['runtime-prefix'], values['library-prefix']]) + assert( + prefix === '.' || /^[A-Za-z0-9_-]+(?:\/[A-Za-z0-9_-]+)*$/u.test(prefix), + 'host layout must stay within its declared carrier', + ); +const inputs = positionals.map((file) => resolve(file)); +assert( + inputs.length > 8, + 'expected runtime, consumer, five SQL plan files, inventory, and archives', +); +const [payload, sourceConsumer, install, smoke, startup, environment, dependencies, inventory] = + inputs; +assert( + payload && + sourceConsumer && + install && + smoke && + startup && + environment && + dependencies && + inventory, +); +// Resolve only the declared Bazel runfile projection before the strict reader. +const archives = inputs.slice(8).map((file) => realpathSync(file)); +const text = (file: string) => new TextDecoder('utf-8', { fatal: true }).decode(readFileSync(file)); +const plan = JSON.parse(text(inventory)); +const construction = validateDesktopConstruction(plan, archives); +const configurations: Record = { + 'linux/x64': 'linux-x64-gnu', + 'linux/arm64': 'linux-arm64-gnu', + 'darwin/arm64': 'macos-arm64', + 'win32/x64': 'windows-x64-msvc', +}; +assert.equal( + construction.configuration, + configurations[`${process.platform}/${process.arch}`], + 'desktop installed SQL must execute on the actual candidate native host', +); +const root = mkdtempSync(join(process.env.TEST_TMPDIR ?? tmpdir(), 'desktop-extensions-')); +const carrier = join(root, 'carrier'); +const runtime = join(carrier, values['runtime-prefix']); +const libraryDirectory = join(carrier, values['library-prefix']); +const windows = process.platform === 'win32'; +const suffix = windows ? '.exe' : ''; +const launcher = join(root, 'launcher', 'restricted process.exe'); +const libraryName = windows + ? 'oliphaunt.dll' + : process.platform === 'darwin' + ? 'liboliphaunt.dylib' + : 'liboliphaunt.so'; +const library = join(libraryDirectory, libraryName); +const consumer = join(root, 'consumer', 'bin', windows ? 'extension smoke.exe' : 'extension-smoke'); +const env = hostRuntimeEnvironment(runtime, root); +if (windows) { + env.PATH = `${join(carrier, 'bin')};${env.PATH}`; + // Published Windows ICU uses its exact colocated data DLL, not a .dat path. + if (values['published-runtime']) delete env.ICU_DATA; +} else { + env[process.platform === 'darwin' ? 'DYLD_LIBRARY_PATH' : 'LD_LIBRARY_PATH'] = + `${libraryDirectory}:${join(runtime, 'lib')}`; +} +env.OLIPHAUNT_SMOKE_MODULE_DIR = join(carrier, 'lib', 'modules'); +const run = (binary: string, args: string[], overrides: NodeJS.ProcessEnv = {}) => + runHostBinary(binary, args, { ...env, ...overrides }, root); + +function initialize(name: string): string { + const database = join(root, name); + mkdirSync(database); + const pgdata = join(database, 'pgdata'); + run( + join(runtime, 'bin', `initdb${suffix}`), + [ + '-D', + pgdata, + '-U', + 'postgres', + '--auth=trust', + '--no-sync', + '--locale-provider=libc', + '--locale=C', + '--encoding=UTF8', + ], + { + OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY: '1', + OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY: '1', + }, + ); + writeFileSync( + join(database, '.oliphaunt.json'), + `${JSON.stringify({ + schema: 'oliphaunt-database-root-v1', + engineFamily: 'native', + pgdata: 'pgdata', + postgresMajor: 18, + physicalFormat: 'native-pg18-v1', + })}\n`, + ); + return pgdata; +} + +const startupArgs = text(startup) + .split('\n') + .filter(Boolean) + .flatMap((assignment) => ['-c', assignment]); +const sql = (text(install) + text(smoke)).replace(/^-- oliphaunt-statement$/gmu, ''); +const embedded = (pgdata: string) => + Bun.spawnSync([consumer, pgdata, runtime, '--sql-plan', install, smoke, startup], { + env, + cwd: root, + stdout: 'pipe', + stderr: 'pipe', + }); +const server = (pgdata: string) => + Bun.spawnSync( + [ + ...(windows ? [launcher] : []), + join(runtime, 'bin', `postgres${suffix}`), + '--single', + '-j', + '-D', + pgdata, + ...startupArgs, + 'postgres', + ], + { env, cwd: root, stdin: Buffer.from(sql), stdout: 'pipe', stderr: 'pipe' }, + ); + +try { + if (values['published-runtime']) extractPortableArchiveTree(realpathSync(payload), carrier); + else await extractNativePayload(payload, carrier); + const selectedFiles = new Set(); + const memberDependencies = new Map(); + for (const archive of archives) { + const entries = readPortableArchiveEntries(archive, { format: 'tar.gz' }); + // validateDesktopConstruction has already checked these descriptors, every + // recorded byte digest, both module ABIs, and the full resource inventory. + const descriptorEntry = entries.get('extension.json'); + assert(descriptorEntry); + const descriptor = JSON.parse(descriptorEntry.data().toString('utf8')); + for (const name of descriptor.dependency_modules ?? []) { + assert(!memberDependencies.has(name), 'candidate members repeat a dependency module'); + memberDependencies.set(name, descriptor.sql_name); + } + for (const [name, entry] of entries) { + if (name === 'extension.json') continue; + assert( + entry.isFile && !selectedFiles.has(name), + 'candidate members overlap or contain non-files', + ); + selectedFiles.add(name); + const output = join(name.startsWith('lib/modules/') ? carrier : runtime, name); + mkdirSync(dirname(output), { recursive: true }); + writeFileSync(output, entry.data(), { mode: entry.mode }); + chmodSync(output, entry.mode); + } + } + assert(statSync(library).isFile(), 'candidate runtime is missing its native library'); + mkdirSync(dirname(consumer), { recursive: true }); + copyFileSync(sourceConsumer, consumer); + if (!windows) chmodSync(consumer, 0o755); + else { + const sourceLauncher = values['restricted-launcher']; + assert(sourceLauncher, 'Windows server SQL requires its restricted launcher'); + mkdirSync(dirname(launcher), { recursive: true }); + copyFileSync(resolve(sourceLauncher), launcher); + } + for (const setting of text(environment).split('\n').filter(Boolean)) { + const [name, path, required] = setting.split('\t'); + assert(name && path && required && statSync(join(runtime, path, required)).isFile()); + env[name] = join(runtime, path); + } + const dependencyNames = text(dependencies).split('\n').filter(Boolean); + assert.deepEqual( + dependencyNames, + [...memberDependencies.keys()].sort(), + 'canonical dependency plan must equal the actual candidate member inventories', + ); + + const baseline = Bun.spawnSync([consumer], { env, cwd: root, stdout: 'pipe', stderr: 'pipe' }); + assert.equal( + baseline.exitCode, + 2, + 'consumer must load the candidate before the missing-library probe', + ); + renameSync(library, `${library}.disabled`); + try { + assertMissingHostRuntime( + Bun.spawnSync([consumer], { env, cwd: root, stdout: 'pipe', stderr: 'pipe' }), + libraryName, + ); + } finally { + renameSync(`${library}.disabled`, library); + } + + const pgdata = initialize('embedded'); + for (let attempt = 0; attempt < 2; attempt++) { + const result = embedded(pgdata); + assert.equal(result.exitCode, 0, result.stderr.toString() + result.stdout.toString()); + } + const result = server(initialize(windows ? 'server with spaces' : 'server')); + const response = result.stderr.toString() + result.stdout.toString(); + assert.equal(result.exitCode, 0, response); + assert( + response.includes('candidate-extension-smoke-ok') && !/ERROR:|FATAL:|not ok/u.test(response), + response, + ); + + if (windows) { + assert( + result.stdout.toString().includes('candidate-extension-smoke-ok'), + 'restricted server must preserve SQL stdin/stdout', + ); + const missing = 'missing server database'; + const rejected = server(join(root, missing)); + const diagnostic = rejected.stderr.toString() + rejected.stdout.toString(); + assert.equal(rejected.exitCode, 1, diagnostic); + assert( + rejected.stderr.toString().includes(missing), + 'restricted server must preserve its error stream', + ); + } + + for (const name of dependencyNames) { + const owner = memberDependencies.get(name); + assert(owner); + for (const profile of ['modules', 'postgresql']) { + assert(selectedFiles.has(`lib/${profile}/${name}`)); + const module = join(profile === 'modules' ? carrier : runtime, 'lib', profile, name); + const pgdata = initialize(`missing-dependency-${profile}-${name}`); + renameSync(module, `${module}.disabled`); + try { + const result = profile === 'modules' ? embedded(pgdata) : server(pgdata); + const response = result.stderr.toString() + result.stdout.toString(); + // LoadLibrary reports the owning module when an imported DLL is absent; + // POSIX loaders also identify the missing dependency itself. + assert( + response.includes(name) || (windows && response.includes(owner)), + `${profile} ${name} (exit ${result.exitCode}): expected missing dependency or Windows owner identity\n${response}`, + ); + if (profile === 'modules') + assert.notEqual(result.exitCode, 0, 'embedded consumer accepted a missing dependency'); + else + assert(/ERROR:|FATAL:/u.test(response), 'server consumer accepted a missing dependency'); + } finally { + renameSync(`${module}.disabled`, module); + } + } + } + + const missingMember = plan.members.find((member: { module_file: string }) => member.module_file); + assert(missingMember, 'desktop member inventory must include compiled modules'); + for (const profile of ['modules', 'postgresql']) { + const module = join( + profile === 'modules' ? carrier : runtime, + 'lib', + profile, + missingMember.module_file, + ); + const pgdata = initialize(`missing-${profile}`); + renameSync(module, `${module}.disabled`); + try { + const result = profile === 'modules' ? embedded(pgdata) : server(pgdata); + const response = result.stderr.toString() + result.stdout.toString(); + assert( + response.includes(missingMember.sql_name), + `${profile} ${missingMember.sql_name} (exit ${result.exitCode}): expected missing module identity\n${response}`, + ); + if (profile === 'modules') + assert.notEqual( + result.exitCode, + 0, + 'embedded consumer accepted a missing candidate module', + ); + else + assert( + /ERROR:|FATAL:/u.test(response), + 'server consumer accepted a missing candidate module', + ); + } finally { + renameSync(`${module}.disabled`, module); + } + } + + console.log( + `${construction.members.length} candidate desktop members: embedded reopen, server SQL and missing candidate loader/module/dependency probes PASS`, + ); +} finally { + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/extensions/extensions.bzl b/build_defs/extensions/extensions.bzl new file mode 100644 index 000000000..bdf126ca4 --- /dev/null +++ b/build_defs/extensions/extensions.bzl @@ -0,0 +1,383 @@ +"""Native member construction; publication ownership stays in imported metadata.""" + +load("//build_defs/native:platform_config.bzl", "NATIVE_EMBEDDED_MODULE_LINKOPTS", "NATIVE_MACOS_COMPATIBLE", "NATIVE_MODULE_LINKOPTS", "NATIVE_RELEASE_LINKOPTS", "NATIVE_WINDOWS_COMPATIBLE") +load("//build_defs/native:windows_config.bzl", "WINDOWS_COPTS") +load("@oliphaunt_metadata//:metadata.bzl", "CONTRIB_MEMBERS", "CONTRIB_OWNERS", "EXTENSIONS", "EXTENSION_PROFILES", "EXTENSION_RECIPES", "EXTENSION_SOURCES", "POSTGRES_SOURCE") +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_shared_library") +load("@rules_cc//cc/common:cc_common.bzl", "cc_common") +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") +load("//build_defs/foundation:bun.bzl", "BunScriptInfo", "bun_action", "bun_script_test") +load("//build_defs/extensions:platforms.bzl", "NATIVE_EXTENSION_COMPATIBLE", "NATIVE_EXTENSION_LINUX_COMPATIBLE", "NATIVE_EXTENSION_PROFILES", _native_configuration = "NATIVE_EXTENSION_CONFIGURATION") +load("//build_defs/release:identity.bzl", "ReleaseIdentityInfo") +load("//build_defs/release:supplier.bzl", "ShippingSupplierInfo") + +ExtensionMemberInfo = provider(fields = ["sql_name", "configuration", "owner", "inventory", "archive"]) +NATIVE_EXTENSION_CONFIGURATION = _native_configuration + +def _module_suffix(configuration): + return {"macos-arm64": ".dylib", "windows-x64-msvc": ".dll"}.get(configuration, ".so") + +def extension_native_dependency_modules(paths, configuration, by_target = {}): + """Project the canonical recipe stems into the selected desktop profile.""" + for target, selected in by_target.items(): + if target not in NATIVE_EXTENSION_PROFILES.values(): + fail("native dependency module override requires a desktop native target") + if type(selected) != "list" or any([path not in paths for path in selected]): + fail("native dependency module override must select declared module paths") + result = [] + for path in by_target.get(configuration, paths): + if not path.startswith("lib/postgresql/") or "/" in path[len("lib/postgresql/"):]: + fail("native dependency module requires its canonical PostgreSQL destination") + basename = path.split("/")[-1] + if not basename.endswith(".so"): + fail("canonical native dependency module must declare its .so stem") + result.append(basename[:-3] + _module_suffix(configuration)) + return result + +def _descriptor(sql_name): + for descriptor in EXTENSIONS.values(): + if descriptor["sql-name"] == sql_name: + return descriptor + fail("SQL member %s is absent from the canonical extension catalog" % sql_name) + +def _extension_product(sql_name, family = "native"): + descriptor = _descriptor(sql_name) + if descriptor["source-kind"] == "postgres-contrib": + product = CONTRIB_OWNERS[family] + else: + product = EXTENSION_SOURCES[sql_name]["product"] + return product + +def extension_identity(sql_name, family = "native"): + return "@oliphaunt_metadata//:product_" + _extension_product(sql_name, family) + +def extension_default_version(sql_name): + descriptor = _descriptor(sql_name) + if descriptor["source-kind"] == "postgres-contrib": + members = [member for member in CONTRIB_MEMBERS if member["sql-name"] == sql_name] + if len(members) != 1: + fail("contrib member must occur exactly once in its canonical distribution") + return members[0].get("default-version") + return EXTENSION_SOURCES[sql_name]["extension-control"]["default-version"] + +def _require_native_profile(ctx): + linux = ctx.target_platform_has_constraint(ctx.attr._linux[platform_common.ConstraintValueInfo]) + macos = ctx.target_platform_has_constraint(ctx.attr._macos[platform_common.ConstraintValueInfo]) + windows = ctx.target_platform_has_constraint(ctx.attr._windows[platform_common.ConstraintValueInfo]) + x64 = ctx.target_platform_has_constraint(ctx.attr._x86_64[platform_common.ConstraintValueInfo]) + arm64 = ctx.target_platform_has_constraint(ctx.attr._aarch64[platform_common.ConstraintValueInfo]) + if linux and x64: + configuration = "linux-x64-gnu" + elif linux and arm64: + configuration = "linux-arm64-gnu" + elif macos and arm64: + configuration = "macos-arm64" + elif windows and x64: + configuration = "windows-x64-msvc" + else: + fail("this native dynamic extension recipe requires a declared desktop OS/CPU; mobile static registries use their own producer") + if POSTGRES_SOURCE["postgresql"]["version"].split(".")[0] != "18": + fail("this native extension construction slice supports PostgreSQL 18 only") + declared = [target for profile in EXTENSION_PROFILES["profiles"] for target in profile["targets"] + if target["target"] == configuration and target["family"] == "native" and target["kind"] == "native-dynamic"] + if len(declared) != 1: + fail("%s native support is absent or duplicated in the canonical target profiles" % configuration) + return configuration + +_PLATFORM_ATTRS = { + "_linux": attr.label(default = "@platforms//os:linux"), + "_macos": attr.label(default = "@platforms//os:macos"), + "_windows": attr.label(default = "@platforms//os:windows"), + "_x86_64": attr.label(default = "@platforms//cpu:x86_64"), + "_aarch64": attr.label(default = "@platforms//cpu:aarch64"), +} + +_PGTAP_TARGET_OS = { + "//build_defs/native:macos_arm64": "darwin", + "//build_defs/native:windows_x64": "MSWin32", + "//conditions:default": "linux", +} +PGTAP_TARGET_OS = select(_PGTAP_TARGET_OS) +PGTAP_TARGET_OS_ARGS = select({condition: ["--os", os_name] for condition, os_name in _PGTAP_TARGET_OS.items()}) + +def _pgtap_sql_impl(ctx): + configuration = _require_native_profile(ctx) + directory = ctx.actions.declare_directory(ctx.label.name + ".sql") + args = ctx.actions.args() + args.add("--source", ctx.file.control.dirname) + args.add("--output", directory.path) + args.add("--os", ctx.attr.target_os) + args.add("--version", extension_default_version("pgtap")) + perl = ctx.toolchains["@rules_perl//perl:exec_toolchain_type"].perl_runtime + args.add("--perl", perl.interpreter) + for option in perl.perlopt: + args.add("--perl-option=" + option) + bun_action( + ctx, ctx.attr._generator, + inputs = depset(ctx.files.inputs + [ctx.file.control], transitive = [perl.runtime]), + outputs = [directory], + arguments = [args], + mnemonic = "PgtapSql", + progress_message = "Generate pinned pgTAP SQL for %s" % configuration, + ) + return [DefaultInfo(files = depset([directory]))] + +_pgtap_sql = rule( + implementation = _pgtap_sql_impl, + attrs = dict(_PLATFORM_ATTRS, **{ + "inputs": attr.label_list(allow_files = True, mandatory = True), + "control": attr.label(allow_single_file = True, mandatory = True), + "target_os": attr.string(mandatory = True, values = ["linux", "darwin", "MSWin32"]), + "_generator": attr.label(default = "//build_defs/extensions:pgtap_sql", providers = [BunScriptInfo], cfg = "exec"), + }), + toolchains = ["@rules_perl//perl:exec_toolchain_type"], +) + +def pgtap_sql(name, **kwargs): + _pgtap_sql(name = name, target_os = PGTAP_TARGET_OS, target_compatible_with = NATIVE_EXTENSION_COMPATIBLE, **kwargs) + +def _perl_runtime_impl(ctx): + perl = ctx.toolchains["@rules_perl//perl:exec_toolchain_type"].perl_runtime + options = ctx.actions.declare_file(ctx.label.name + ".options.json") + ctx.actions.write(options, json.encode(perl.perlopt)) + return [DefaultInfo(files = depset([options], transitive = [perl.runtime])), + OutputGroupInfo(interpreter = depset([perl.interpreter]), options = depset([options]))] + +extension_perl_runtime = rule( + implementation = _perl_runtime_impl, + toolchains = ["@rules_perl//perl:exec_toolchain_type"], +) + +def _payload_impl(ctx): + configuration = _require_native_profile(ctx) + descriptor = _descriptor(ctx.attr.sql_name) + identity = ctx.attr.owner[ReleaseIdentityInfo] + if str(ctx.attr.owner.label) != str(Label(extension_identity(ctx.attr.sql_name))): + fail("member owner differs from canonical %s carrier ownership" % ctx.attr.sql_name) + source_kind = descriptor["source-kind"] + data_files = [] + recipe_artifacts = EXTENSION_RECIPES.get(ctx.attr.sql_name, {}).get("artifacts", {}) + if source_kind == "postgres-contrib": + members = [member for member in CONTRIB_MEMBERS if member["sql-name"] == ctx.attr.sql_name] + if len(members) != 1: + fail("contrib member must occur exactly once in its canonical distribution") + data_files = members[0].get("data-files", []) + else: + data_files = recipe_artifacts.get("data_files", []) + profiles = [] + mappings = [] + for file in ctx.files.resources: + if file.is_directory: + mappings.append({"source": file.path, "destination": "share/postgresql/extension", "tree": True}) + elif file.basename.endswith(".sql") or file.basename.endswith(".control"): + mappings.append({"source": file.path, "destination": "share/postgresql/extension/" + file.basename}) + else: + destinations = [destination for destination in data_files if destination.split("/")[-1] == file.basename] + if len(destinations) != 1: + fail("resource %s has no unique canonical member destination" % file.basename) + mappings.append({"source": file.path, "destination": destinations[0]}) + data_inputs = [] + construction_licenses = [] + for target, destination in ctx.attr.construction_licenses.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1 or files[0].is_directory or not destination.startswith("share/licenses/"): + fail("construction licenses require one declared file beneath share/licenses") + mappings.append({"source": files[0].path, "destination": destination}) + data_inputs.append(files[0]) + construction_licenses.append(destination) + for target, destination in ctx.attr.data_resources.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1: + fail("mapped member data must provide exactly one file or directory") + file = files[0] + if file.is_directory: + if not any([path.startswith(destination + "/") for path in data_files]): + fail("mapped member data directory is absent from the canonical recipe") + mappings.append({"source": file.path, "destination": destination, "tree": True}) + else: + if destination not in data_files: + fail("mapped member data file is absent from the canonical recipe") + mappings.append({"source": file.path, "destination": destination}) + data_inputs.append(file) + module_file = descriptor.get("native-module-file", "") + module_stem = module_file[:-3] if module_file.endswith(".so") else "" + if module_stem: + module_file = module_stem + _module_suffix(configuration) + if ctx.files.server_module and ctx.files.server_module == ctx.files.embedded_module: + fail("server and embedded ABI profiles require independently produced module files") + if ctx.file.main_sql: + mappings.append({ + "source": ctx.file.main_sql.path, + "destination": "share/postgresql/extension/%s--%s.sql" % (ctx.attr.sql_name, extension_default_version(ctx.attr.sql_name)), + }) + for profile, files in [("postgresql", ctx.files.server_module), ("modules", ctx.files.embedded_module)]: + if files: + if len(files) != 1 or not module_stem: + fail("native module must provide exactly one file for a compiled catalog member") + profiles.append(profile) + mappings.append({"source": files[0].path, "destination": "lib/%s/%s" % (profile, module_file)}) + if module_stem and profiles != ["postgresql", "modules"]: + fail("compiled member payload requires independently built server and embedded modules") + dependency_paths = recipe_artifacts.get("native_dependency_modules", []) + dependency_basenames = extension_native_dependency_modules(dependency_paths, configuration, recipe_artifacts.get("native_dependency_modules_by_target", {})) + if sorted([file.basename for file in ctx.files.dependency_modules]) != sorted(dependency_basenames): + fail("native dependency modules differ from the canonical extension recipe") + for file in ctx.files.dependency_modules: + for profile in profiles: + mappings.append({"source": file.path, "destination": "lib/%s/%s" % (profile, file.basename)}) + facts = { + "schema": "oliphaunt-extension-member-payload-v1", + "sql_name": ctx.attr.sql_name, + "owner": identity.id, + "version": identity.version, + "family": "native", + "configuration": configuration, + "source_kind": source_kind, + "postgres_major": 18, + "postgres_source": POSTGRES_SOURCE, + "default_version": extension_default_version(ctx.attr.sql_name), + "creates_extension": descriptor["lifecycle"]["create-extension"], + "dependencies": descriptor.get("dependencies", []), + "module_profiles": profiles, + "module_file": module_file, + "dependency_modules": dependency_basenames, + "data_files": data_files, + "sql_prefixes": recipe_artifacts.get("extension_sql_file_prefixes", []), + "sql_files": recipe_artifacts.get("extension_sql_file_names", []), + } + if source_kind != "postgres-contrib": + facts["source"] = EXTENSION_SOURCES[ctx.attr.sql_name] + if construction_licenses: + facts["construction_licenses"] = sorted(construction_licenses) + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + archive = ctx.actions.declare_file(ctx.label.name + ".tar.gz") + inventory = ctx.actions.declare_file(ctx.label.name + ".inventory.json") + ctx.actions.write(spec, json.encode({"descriptor": facts, "inputs": mappings})) + args = ctx.actions.args() + args.add("--spec", spec) + args.add("--output", archive) + args.add("--inventory", inventory) + bun_action( + ctx, ctx.attr._assembler, + inputs = depset([spec] + ctx.files.resources + ctx.files.main_sql + ctx.files.server_module + ctx.files.embedded_module + ctx.files.dependency_modules + data_inputs), + outputs = [archive, inventory], + arguments = [args], + mnemonic = "ExtensionMemberPayload", + progress_message = "Assemble %s native member payload" % ctx.attr.sql_name, + ) + # The same actual library File is reached through the embedded linker. + # SQL-only and server headers do not claim incorporation of the core. + supplier = ctx.attr.core_supplier[ShippingSupplierInfo] if ctx.attr.core_supplier else ShippingSupplierInfo(suppliers = [], files = depset()) + return [DefaultInfo(files = depset([archive, inventory])), supplier, + OutputGroupInfo(archive = depset([archive]), inventory = depset([inventory])), + ExtensionMemberInfo(sql_name = ctx.attr.sql_name, owner = identity.id, + configuration = configuration, inventory = inventory, archive = archive)] + +_extension_member_payload = rule( + implementation = _payload_impl, + attrs = dict(_PLATFORM_ATTRS, **{ + "sql_name": attr.string(mandatory = True), + "owner": attr.label(mandatory = True, providers = [ReleaseIdentityInfo]), + "resources": attr.label_list(allow_files = True, mandatory = True), + "main_sql": attr.label(allow_single_file = True), + "server_module": attr.label(allow_files = True), + "embedded_module": attr.label(allow_files = True), + "dependency_modules": attr.label_list(allow_files = True), + "data_resources": attr.label_keyed_string_dict(allow_files = True), + "construction_licenses": attr.label_keyed_string_dict(allow_files = True), + "core_supplier": attr.label(providers = [ShippingSupplierInfo]), + "_assembler": attr.label(default = "//build_defs/extensions:member_payload", providers = [BunScriptInfo], cfg = "exec"), + }), +) + +def extension_member_payload(name, **kwargs): + compiled = bool(_descriptor(kwargs["sql_name"]).get("native-module-file")) + _extension_member_payload(name = name, core_supplier = "//build_defs/release:current_native_core_supplier" if compiled else None, target_compatible_with = NATIVE_EXTENSION_COMPATIBLE, **kwargs) + +def extension_member_validation_test(name, payload, sql_name): + """Validate the actual archive with a reader independent of its assembler.""" + archive = name + "_archive" + native.filegroup(name = archive, srcs = [payload], output_group = "archive") + bun_script_test( + name = name, + entry_point = "//build_defs/extensions:validate_member_payload.mts", + args = ["$(location :%s)" % archive, "--sql-name", sql_name, + "--owner", _extension_product(sql_name)], + data = [":" + archive, "//:tools/packaging/portable-archive.mts", "//:tools/packaging/platform-binary-contract.mts", "//:tools/packaging/windows-vc-runtime-closure.mts", "//:tools/packaging/windows-vc-runtime-policy.json", "//tools/release:platform-compatibility-policy.mts", "//:src/extensions/artifacts/native/tools/stage-windows-binary-contract.mts"], + size = "small", + ) + +def _source_headers_impl(ctx): + return [CcInfo(compilation_context = cc_common.create_compilation_context( + headers = depset(ctx.files.hdrs), + includes = depset([ctx.file.include_root.dirname]), + ))] + +extension_source_headers = rule( + implementation = _source_headers_impl, + attrs = { + "hdrs": attr.label_list(allow_files = True, mandatory = True), + "include_root": attr.label(allow_single_file = True, mandatory = True), + }, +) + +def native_extension_modules(name, srcs, hdrs = [], copts = [], deps = [], includes = [], defines = [], linkopts = [], dynamic_deps = [], linux_only = False, additional_compiler_inputs = []): + """Compile separate PostgreSQL-server and embedded ABI variants directly.""" + for variant, headers, runtime_deps in [ + ("server", "//src/native/runtime:postgres_server_headers", select({"//build_defs/native:windows_x64": ["@postgres//:server_import_library"], "//conditions:default": []})), + ("embedded", "//src/native/runtime:postgres_embedded_headers", ["//src/native/runtime:liboliphaunt"]), + ]: + cc_library( + name = name + "_" + variant + "_objects", + srcs = srcs, + hdrs = hdrs, + additional_compiler_inputs = additional_compiler_inputs, + deps = [headers] + deps, + copts = copts + select({"//build_defs/native:windows_x64": WINDOWS_COPTS, "//conditions:default": []}), + includes = includes, + defines = defines, + alwayslink = True, + target_compatible_with = NATIVE_EXTENSION_LINUX_COMPATIBLE if linux_only else NATIVE_EXTENSION_COMPATIBLE, + ) + cc_binary( + name = name + "_" + variant + ".so", + deps = [":" + name + "_" + variant + "_objects"] + runtime_deps, + linkshared = True, + linkstatic = True, + dynamic_deps = dynamic_deps, + linkopts = linkopts + NATIVE_RELEASE_LINKOPTS + (["-Wl,-z,defs"] if variant == "embedded" else []), + target_compatible_with = NATIVE_EXTENSION_LINUX_COMPATIBLE, + ) + if not linux_only: + module_linkopts = NATIVE_MODULE_LINKOPTS if variant == "server" else NATIVE_EMBEDDED_MODULE_LINKOPTS + cc_binary( + name = name + "_" + variant + ".dylib", + deps = [":" + name + "_" + variant + "_objects"] + runtime_deps, + linkshared = True, + linkstatic = True, + dynamic_deps = dynamic_deps, + linkopts = linkopts + module_linkopts, + target_compatible_with = NATIVE_MACOS_COMPATIBLE, + ) + # Imported runtimes stay transitive; the stock shared-library rule + # derives exports from the objects retained after dynamic_deps pruning. + windows_link = name + "_" + variant + "_windows_link" + cc_library( + name = windows_link, + deps = [":" + name + "_" + variant + "_objects"] + runtime_deps, + target_compatible_with = NATIVE_WINDOWS_COMPATIBLE, + ) + cc_shared_library( + name = name + "_" + variant + ".dll", + shared_lib_name = name + "_" + variant + ".dll", + deps = [":" + windows_link], + dynamic_deps = dynamic_deps, + features = ["windows_export_all_symbols"], + user_link_flags = linkopts, + target_compatible_with = NATIVE_WINDOWS_COMPATIBLE, + ) + native.alias(name = name + "_" + variant + "_module", actual = select({ + "//build_defs/native:macos_arm64": ":" + name + "_" + variant + ".dylib", + "//build_defs/native:windows_x64": ":" + name + "_" + variant + ".dll", + "//conditions:default": ":" + name + "_" + variant + ".so", + })) diff --git a/build_defs/extensions/external.bzl b/build_defs/extensions/external.bzl new file mode 100644 index 000000000..11338c4a3 --- /dev/null +++ b/build_defs/extensions/external.bzl @@ -0,0 +1,159 @@ +"""Reviewed external C units, shared by explicit platform construction profiles.""" + +load("@oliphaunt_metadata//:metadata.bzl", "EXTENSION_SOURCES") +load("@rules_cc//cc/common:cc_common.bzl", "cc_common") +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") +load("//build_defs/foundation:bun.bzl", "BunScriptInfo", "bun_action") +load("//build_defs/native:platform_config.bzl", "NATIVE_WINDOWS_COMPATIBLE") +load(":extensions.bzl", "extension_default_version", "extension_source_headers", "native_extension_modules") + +EXTERNAL_C_SOURCES = { + "pg_hashids": ["pg_hashids.c", "hashids.c"], + "pg_uuidv7": ["pg_uuidv7.c"], + "pg_ivm": ["createas.c", "matview.c", "pg_ivm.c", "ruleutils.c", "subselect.c"], + "pg_textsearch": ["src/" + unit + ".c" for unit in [ + "mod", "layout_check", + "access/handler", "access/build", "access/build_context", "access/build_merge", "access/build_parallel", "access/compaction_api", "access/boolean", "access/rls", "access/scan", "access/vacuum", + "memtable/arena", "memtable/cache", "memtable/cache_source", "memtable/chain_source", "memtable/chain_walker", "memtable/expull", "memtable/log", "memtable/page", "memtable/posting", "memtable/scan", "memtable/stringtable", + "segment/segment", "segment/graph_snapshot", "segment/dictionary", "segment/scan", "segment/merge", "segment/compaction", "segment/tombstone", "segment/docmap", "segment/alive_bitset", "segment/compression", "segment/fieldnorm", + "scoring/bmw", "scoring/bm25", "scoring/snapshot", "types/array", "types/vector", "types/query", + "index/compaction_job", "index/compaction_request", "index/state", "index/registry", "index/metapage", "index/freepage", "index/limit", "index/resolve", "index/source", + "planner/hooks", "planner/cost", "debug/injection", "debug/dump", + ]], + "vector": ["src/" + unit + ".c" for unit in [ + "bitutils", "bitvec", "halfutils", "halfvec", "hnsw", "hnswbuild", + "hnswinsert", "hnswscan", "hnswutils", "hnswvacuum", "ivfbuild", + "ivfflat", "ivfinsert", "ivfkmeans", "ivfscan", "ivfutils", "ivfvacuum", + "sparsevec", "vector", + ]], +} + +EXTERNAL_HEADERS = { + "pg_hashids": ["hashids.h"], + "pg_ivm": ["pg_ivm.h", "ruleutils_13.c", "ruleutils_14.c"], +} + +VECTOR_COPTS = ["-ftree-vectorize", "-fassociative-math", "-fno-signed-zeros", "-fno-trapping-math"] + +def _windows_sources_impl(ctx): + anchor = ctx.file.anchor + root = anchor.path[:-len(ctx.attr.anchor_name)] + source_paths = {file.path: True for file in ctx.files.srcs} + sources = [] + headers = [] + compatibility = [] + companion_inputs = [] + rows = [] + seen = {} + for file in ctx.files.srcs + ctx.files.hdrs: + if file.path in seen: + continue + seen[file.path] = True + if file.is_directory or not file.path.startswith(root): + fail("Windows source preparation requires declared regular files in the pinned source repository") + relative = file.path[len(root):] + if not relative or any([part in ["", ".", ".."] for part in relative.split("/")]): + fail("Windows source input escapes its pinned repository root") + output = ctx.actions.declare_file(ctx.label.name + "/" + relative) + rows.append({"name": relative, "source": file.path, "output": output.path}) + if file.path in source_paths: + sources.append(output) + else: + headers.append(output) + for target, relative in ctx.attr.companions.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1 or files[0].is_directory or not relative or any([part in ["", ".", ".."] for part in relative.split("/")]): + fail("Windows companion header requires one regular file and a safe declared destination") + output = ctx.actions.declare_file(ctx.label.name + "/" + relative) + rows.append({"name": relative, "source": files[0].path, "output": output.path}) + headers.append(output) + compatibility.append(output) + companion_inputs.append(files[0]) + generated = [] + if ctx.attr.sql_name == "pg_textsearch": + for relative in ["src/unistd.h"]: + output = ctx.actions.declare_file(ctx.label.name + "/" + relative) + headers.append(output) + generated.append({"name": relative, "output": output.path}) + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode({"extension": ctx.attr.sql_name, "files": rows, "headers": generated})) + args = ctx.actions.args() + args.add(spec) + bun_action(ctx, ctx.attr._generator, arguments = [args], inputs = depset([spec] + ctx.files.srcs + ctx.files.hdrs + companion_inputs), outputs = sources + headers, mnemonic = "WindowsExtensionSources") + output_root = (sources + headers)[0].path[:-len(rows[0]["name"])] + groups = {"compatibility_header": depset(compatibility), "source_spec": depset([spec])} + for directory in ctx.attr.source_groups: + group = directory.split("/")[-1] + "_sources" + if group in groups or any([part in ["", ".", ".."] for part in directory.split("/")]): + fail("Windows source group requires a unique safe source directory") + groups[group] = depset([file for file in sources if file.path.startswith(output_root + directory + "/")]) + return [ + DefaultInfo(files = depset(sources)), + CcInfo(compilation_context = cc_common.create_compilation_context(headers = depset(headers), includes = depset([output_root + directory for directory in ctx.attr.include_dirs]))), + OutputGroupInfo(**groups), + ] + +_windows_sources = rule( + implementation = _windows_sources_impl, + attrs = { + "sql_name": attr.string(mandatory = True), + "srcs": attr.label_list(allow_files = True, mandatory = True), + "hdrs": attr.label_list(allow_files = True), + "companions": attr.label_keyed_string_dict(allow_files = True), + "source_groups": attr.string_list(), + "anchor": attr.label(allow_single_file = True, mandatory = True), + "anchor_name": attr.string(mandatory = True), + "include_dirs": attr.string_list(), + "_generator": attr.label(default = "//build_defs/extensions:windows_source_inputs", providers = [BunScriptInfo], cfg = "exec"), + }, +) + +# The PostGIS recipe uses the same declared projection and pure source transforms. +windows_extension_sources = _windows_sources + +def external_extension_inputs(name, sql_name, link_profile = "native"): + """C source inputs only; callers supply their actual host/profile headers.""" + if link_profile not in ["native", "wasix"]: + fail("unknown external extension link profile: " + link_profile) + if sql_name not in EXTERNAL_C_SOURCES: + fail("%s has no reviewed external C construction recipe" % sql_name) + prefix = "@" + EXTENSION_SOURCES[sql_name]["name"] + "//:" + attrs = { + "srcs": [prefix + source for source in EXTERNAL_C_SOURCES[sql_name]], + "hdrs": [prefix + header for header in EXTERNAL_HEADERS.get(sql_name, [])], + } + if sql_name == "vector": + attrs["hdrs"].append(prefix + "headers") + if sql_name == "pg_textsearch": + headers = name + "_source_headers" + extension_source_headers(name = headers, hdrs = [prefix + "headers"], include_root = prefix + "src/constants.h") + attrs["deps"] = [":" + headers] + attrs["copts"] = ["-DPG_TEXTSEARCH_VERSION=\\\"%s\\\"" % extension_default_version(sql_name)] + if sql_name == "pg_hashids": + attrs["linkopts"] = ["-lm"] if link_profile == "wasix" else select({"//build_defs/native:windows_x64": [], "//conditions:default": ["-lm"]}) + return attrs + +def native_external_extension_modules(name, sql_name = None): + sql_name = sql_name or name + attrs = external_extension_inputs(name = name, sql_name = sql_name) + if sql_name in ["pg_uuidv7", "pg_textsearch"]: + prepared = name + "_windows_sources" + prefix = "@" + EXTENSION_SOURCES[sql_name]["name"] + "//:" + anchor = "src/constants.h" if sql_name == "pg_textsearch" else "pg_uuidv7.c" + _windows_sources(name = prepared, sql_name = sql_name, srcs = attrs["srcs"], hdrs = [prefix + "headers"] if sql_name == "pg_textsearch" else [], anchor = prefix + anchor, anchor_name = anchor, include_dirs = ["src"] if sql_name == "pg_textsearch" else [""], target_compatible_with = NATIVE_WINDOWS_COMPATIBLE) + attrs["srcs"] = select({"//build_defs/native:windows_x64": [":" + prepared], "//conditions:default": attrs["srcs"]}) + attrs["hdrs"] = select({"//build_defs/native:windows_x64": [], "//conditions:default": attrs.get("hdrs", [])}) + attrs["deps"] = select({"//build_defs/native:windows_x64": [":" + prepared], "//conditions:default": attrs.get("deps", [])}) + if sql_name == "vector": + # Clang's EVEX width permission preserves upstream's optional AVX512 + # dispatch without enabling AVX instructions in baseline functions. + attrs["copts"] = select({"//build_defs/native:windows_x64": ["/fp:fast"], "//conditions:default": VECTOR_COPTS + ["-fPIC"]}) + select({ + "//build_defs/native:linux_x86_64_gnu_2_28": ["-mevex512"], + "//conditions:default": [], + }) + if sql_name in ["vector", "pg_textsearch"]: + attrs["deps"] = attrs.get("deps", []) + select({ + "//build_defs/native:linux_x86_64_gnu_2_28": ["@pgvector_compiler_rt//:cpu_model"], + "//conditions:default": [], + }) + native_extension_modules(name = name, **attrs) diff --git a/build_defs/extensions/family_carriers.bzl b/build_defs/extensions/family_carriers.bzl new file mode 100644 index 000000000..fe2490ac7 --- /dev/null +++ b/build_defs/extensions/family_carriers.bzl @@ -0,0 +1,82 @@ +"""One final facade/control owner join over original qualified constructor Files.""" + +load("@oliphaunt_metadata//:metadata.bzl", "EXTENSION_GITHUB_ARTIFACTS", "EXTENSION_RELEASE_METADATA", "PRODUCTS") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/release:identity.bzl", "release_identity") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") +load(":declared_final_inputs.bzl", "native_declared_apple_base", "native_extension_declared_final_import") +load(":owner_carriers.bzl", "native_extension_family_carriers", "native_owner_carrier_helpers", "native_owner_carrier_legal", "native_owner_carrier_metadata") + +def _runfile(ctx, file): + return file.short_path[3:] if file.short_path.startswith("../") else ctx.workspace_name + "/" + file.short_path + +def _contract_impl(ctx): + spec = ctx.attr.family[OutputGroupInfo].spec.to_list() + if len(spec) != 1: + fail("extension family contract requires its actual construction spec") + files = depset(ctx.files.legal, transitive = [ctx.attr.family[DefaultInfo].files] + [target[DefaultInfo].files for target in ctx.attr.inputs]).to_list() + locations = ctx.actions.declare_file(ctx.label.name + ".locations.json") + ctx.actions.write(locations, json.encode({file.path: _runfile(ctx, file) for file in files})) + return bun_test_entrypoint(ctx, ctx.file._runner, [spec[0], locations], files + [locations] + ctx.files._helpers, + source_files = [ctx.file._runner] + ctx.files._helpers + ctx.files.legal, runfiles_argument = True) + +_family_contract_test = rule(implementation = _contract_impl, test = True, toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "family": attr.label(mandatory = True), "inputs": attr.label_list(allow_files = True), "legal": attr.label_list(allow_files = True), + "_runner": attr.label(default = "//build_defs/extensions:family_contract.test.mts", allow_single_file = True), + "_helpers": attr.label_list(default = native_owner_carrier_helpers() + ["//build_defs/extensions:owner_carriers.mts", "//tools/release:checksum-manifest.mts"], allow_files = True), + })) + +def _family(name, product, base_carrier_manifest, family = "native"): + spec = native_owner_carrier_metadata(product, family) + leaves, wasix_leaves = [], [] + for profile in spec["profiles"]: + imported = name + "_" + profile["target"].replace("-", "_") + native_extension_declared_final_import(name = imported, product = product, family = "native", target = profile["target"]) + leaves.append(":" + imported) + if "wasix" in spec["ownerFamilies"]: + imported = name + "_wasix_portable" + native_extension_declared_final_import(name = imported, product = product, family = "wasix", target = "wasix-portable") + wasix_leaves.append(":" + imported) + base = base_carrier_manifest if "native" in spec["ownerFamilies"] else None + if base and spec["runtimeVersion"] != PRODUCTS["liboliphaunt-native"]["version"]: + native_declared_apple_base(name = name + "_base", version = spec["runtimeVersion"]) + base = ":" + name + "_base" + native_extension_family_carriers(name = name, product = product, leaves = leaves, wasix_leaves = wasix_leaves, + base_carrier_manifest = base, family = family) + owner = name + "_owner" + release_identity(name = owner, product_id = spec["owner"], version = spec["version"]) + rows = [struct(group = "frozen", ecosystem = "internal", name = product + "-" + family + "-release-family", role = "extension-release-family-input")] + if "native" in spec["ownerFamilies"]: + for ecosystem in ["npm", "cargo"]: + facade = [row for row in spec["carriers"] if row["ecosystem"] == ecosystem and row["role"] == "facade" and row["target"] == None] + if len(facade) != 1: + fail("extension family requires one canonical " + ecosystem + " facade") + rows.append(struct(group = ecosystem, ecosystem = ecosystem, name = facade[0]["name"], role = "facade")) + rows += [struct(group = "control_" + row["kind"], ecosystem = "github", name = row["name"], role = row["role"]) + for row in EXTENSION_GITHUB_ARTIFACTS if row["artifactProduct"] == product and row["owner"] == spec["owner"] and row.get("control", False)] + packages = [] + for index, row in enumerate(rows): + output = name + "_files_" + str(index) + native.filegroup(name = output, srcs = [":" + name], output_group = row.group) + package = name + "_shipping_" + str(index) + shipping_package(name = package, owner = ":" + owner, artifacts = [":" + output], ecosystem = row.ecosystem, + package_name = row.name, configuration = "portable", role = row.role, suppliers = ":" + name) + packages.append(":" + package) + _family_contract_test(name = name + "_contract_test", family = ":" + name, + inputs = leaves + wasix_leaves + ([base] if base else []), legal = native_owner_carrier_legal(product), args = bun_test_entrypoint_args(name + "_contract_test"), size = "medium") + shipping_export(name = name + "_shipping_export", packages = packages, + qualification = [":" + name + "_contract_test"], testonly = True) + +def native_extension_final_families(base_carrier_manifest): + """Derive each distribution from the same canonical release metadata once.""" + products = sorted({row["artifactProduct"]: True for row in EXTENSION_RELEASE_METADATA}) + for product in products: + rows = [row for row in EXTENSION_RELEASE_METADATA if row["artifactProduct"] == product] + if rows[0]["class"] == "contrib": + _family("contrib_native_family", product, base_carrier_manifest) + _family("contrib_wasix_family", product, None, family = "wasix") + else: + if len(rows) != 1: + fail("external family requires its one canonical SQL member") + _family(rows[0]["sqlName"] + "_family", product, base_carrier_manifest) diff --git a/build_defs/extensions/family_contract.test.mts b/build_defs/extensions/family_contract.test.mts new file mode 100644 index 000000000..d821be683 --- /dev/null +++ b/build_defs/extensions/family_contract.test.mts @@ -0,0 +1,282 @@ +/** Actual final facade/control bytes; original hosts retain their own runtime qualification. */ +import assert from 'node:assert/strict'; +import { mkdtempSync, readFileSync, realpathSync, rmSync } from 'node:fs'; +import { createRequire } from 'node:module'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; +import { + composeExtensionReleaseDocuments, + extensionReleasePropertiesText, +} from '../../src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts'; +import { + extractPortableArchiveTree, + readPortableArchiveEntries, +} from '../../tools/packaging/portable-archive.mts'; +import { rustNativeTargetCfg } from '../../tools/packaging/rust-native-targets.mts'; +import { validateChecksumManifest } from '../../tools/release/checksum-manifest.mts'; +import { + mergeNativeFinalMembers, + type NativeOwnerSpec, + ownerFamilyCompleteness, +} from './owner_carriers.mts'; + +const json = (file: string) => JSON.parse(readFileSync(file, 'utf8')); +const [specFile, locationsFile, runfiles] = process.argv.slice(2); +assert.equal(process.argv.length, 5); +const locations = json(locationsFile); +const resolve = (value: any): any => + typeof value === 'string' && locations[value] + ? realpathSync(path.join(runfiles, locations[value])) + : Array.isArray(value) + ? value.map(resolve) + : value && typeof value === 'object' + ? Object.fromEntries(Object.entries(value).map(([key, item]) => [key, resolve(item)])) + : value; +const spec = resolve(json(specFile)) as NativeOwnerSpec; +const completeness = ownerFamilyCompleteness(spec, spec.leaves); +assert(completeness.completeExtensionDistribution); +const cohorts = spec.leaves.map((leaf) => { + const frozen = json(leaf.frozen); + return { members: frozen.extensions ?? [frozen], assets: frozen.carrierAssets ?? frozen.assets }; +}); +const members = mergeNativeFinalMembers(spec, cohorts); +const directAssets = cohorts.flatMap((cohort) => cohort.assets); +const family = spec.ownerFamilies.length > 1 ? null : spec.ownerFamilies[0]; +const documents = composeExtensionReleaseDocuments({ + product: spec.product, + releaseProduct: spec.owner, + version: spec.version, + family, + members, + directAssets, + releaseMetadata: spec.releaseMetadata, +}); +const frozen = json(spec.outputs.frozen); +const manifest = json(spec.outputs['control_manifest-json']); +const schemaVersion = spec.members.length > 1 ? 2 : 1; +const hasOwnership = spec.owner !== spec.product || family !== null; +for (const [document, schema] of [ + [frozen, `oliphaunt-extension-ci-artifacts-v${schemaVersion}`], + [manifest, `oliphaunt-extension-release-manifest-v${schemaVersion}`], +] as const) { + assert.equal(document.schema, schema); + assert.equal(document.product, spec.product); + assert.equal(document.version, spec.version); + assert.deepEqual(document.compatibility, spec.releaseMetadata.compatibility); + assert.equal(Object.hasOwn(document, 'releaseProduct'), hasOwnership); + assert.equal(Object.hasOwn(document, 'family'), hasOwnership); + if (hasOwnership) { + assert.equal(document.releaseProduct, spec.owner); + assert.equal(document.family, family ?? 'combined'); + } +} +const withoutAssetLocators = (value: any) => { + const result = structuredClone(value); + for (const asset of [ + ...(result.carrierAssets ?? []), + ...(result.extensions ?? [result]).flatMap((member) => member.assets), + ]) { + delete asset.path; + delete asset.source; + } + return result; +}; +assert.deepEqual( + withoutAssetLocators(frozen), + withoutAssetLocators(JSON.parse(JSON.stringify(documents.manifest))), +); +for (const asset of frozen.carrierAssets ?? frozen.assets) + assert.equal(asset.path, `product/release-assets/${asset.name}`); +if (frozen.extensions) + for (const member of frozen.extensions) + for (const asset of member.assets) + assert.equal(asset.path, `product/member-assets/${member.sqlName}/${asset.name}`); +assert.deepEqual(manifest, JSON.parse(JSON.stringify(documents.releaseData))); +assert.equal( + readFileSync(spec.outputs['control_manifest-properties'], 'utf8'), + extensionReleasePropertiesText({ + product: spec.product, + releaseProduct: spec.owner, + family, + version: spec.version, + manifest: documents.manifest, + releaseData: documents.releaseData, + directAssets, + compatibility: spec.releaseMetadata.compatibility, + }), +); +const controls = Object.entries(spec.outputs) + .filter(([key]) => key.startsWith('control_') && key !== 'control_checksums') + .map(([, file]) => file); +validateChecksumManifest( + spec.outputs.control_checksums, + [...spec.leaves.flatMap((leaf) => leaf.github), ...controls], + spec.product, +); +if (spec.outputs.cargo) { + const archive = readPortableArchiveEntries(spec.outputs.cargo); + const cargo = Bun.TOML.parse( + archive.get(`${spec.product}-${spec.version}/Cargo.toml`)!.data().toString('utf8'), + ) as any; + assert.equal(cargo.package.name, spec.product); + assert.equal(cargo.package.version, spec.version); + assert.deepEqual(cargo.features.default, ['native']); + const dependencies = new Map(Object.entries(cargo.dependencies ?? {})); + for (const row of Object.values(cargo.target ?? {}) as any[]) + for (const [name, dependency] of Object.entries(row.dependencies ?? {})) { + assert(!dependencies.has(name), 'final facade repeats a target dependency'); + dependencies.set(name, dependency); + } + const leafNames = spec.carriers + .filter((row) => row.ecosystem === 'cargo' && row.target !== null) + .map((row) => row.name); + const allowed = new Set([ + ...leafNames, + 'liboliphaunt-native-bindings', + ...(spec.ownerFamilies.includes('wasix') ? ['oliphaunt-wasix'] : []), + ]); + assert.deepEqual([...dependencies.keys()].sort(), [...allowed].sort()); + for (const name of leafNames) { + assert.equal(dependencies.get(name).version, `=${spec.version}`); + assert.equal(dependencies.get(name).path, undefined); + assert.equal(dependencies.get(name).optional, true); + } + assert.equal( + dependencies.get('liboliphaunt-native-bindings').version, + `^${spec.cargoFacadeMetadata.bindingVersion}`, + ); + assert.equal( + cargo['build-dependencies']['oliphaunt-build'].version, + `^${spec.cargoFacadeMetadata.sdkVersion}`, + ); + for (const target of spec.cargoFacadeMetadata.targets.nativeCargoTargets) { + const cfg = rustNativeTargetCfg(target); + const expected = spec.carriers.find( + (row) => row.ecosystem === 'cargo' && row.target === target, + ); + assert(expected && cargo.target[`cfg(${cfg})`].dependencies[expected.name]); + } + if (spec.ownerFamilies.includes('wasix')) { + assert.equal( + dependencies.get('oliphaunt-wasix').version, + `^${spec.cargoFacadeMetadata.wasixSdkVersion}`, + ); + assert(cargo.features.wasix.includes('dep:oliphaunt-wasix')); + } else assert.equal(cargo.features.wasix, undefined); +} +if (spec.outputs.npm) { + const archive = readPortableArchiveEntries(spec.outputs.npm); + const manifest = JSON.parse(archive.get('package/package.json')!.data().toString('utf8')); + const facade = spec.carriers.find( + (row) => row.ecosystem === 'npm' && row.target === null && row.role === 'facade', + ); + assert.equal(manifest.name, facade.name); + assert.equal(manifest.version, spec.version); + const targets = spec.profiles + .filter((row) => row.kind === 'native-dynamic') + .map((row) => row.target); + const leaves = spec.carriers.filter( + (row) => + row.ecosystem === 'npm' && + targets.includes(row.target) && + row.name === `${facade.name}-${row.target}`, + ); + assert.deepEqual( + leaves.map((row) => row.target).sort(), + [...targets].sort(), + 'final facade requires exactly one native npm carrier for every dynamic target', + ); + assert.deepEqual( + manifest.optionalDependencies, + Object.fromEntries(leaves.map((row) => [row.name, spec.version])), + ); + assert.deepEqual( + manifest.oliphaunt.targetPackageNames, + Object.fromEntries(leaves.map((row) => [row.target, row.name])), + ); + assert.deepEqual( + [...manifest.oliphaunt.members].sort(), + spec.members.map((row) => row.sqlName).sort(), + ); + assert.equal(manifest.oliphaunt.liboliphauntVersion, spec.runtimeVersion); + assert.equal( + manifest.oliphaunt.runtimeBound, + spec.releaseMetadata.versioning === 'runtime-bound', + ); + const ios = JSON.parse( + archive + .get(`package/${manifest.oliphaunt.iosCarrierManifest.slice(2)}`)! + .data() + .toString('utf8'), + ); + const base = json(spec.baseCarrierManifest!); + assert.deepEqual(ios.base, base.base); + assert.deepEqual(ios.legal.base, base.legal.base); + assert.deepEqual( + ios.extensions.map((row) => row.sqlName).sort(), + spec.members.map((row) => row.sqlName).sort(), + ); + const root = realpathSync( + mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'final-extension-facade-')), + ); + try { + const directory = path.join(root, 'node_modules', manifest.name); + extractPortableArchiveTree(spec.outputs.npm, directory, 'package'); + const require = createRequire(path.join(root, 'consumer.cjs')); + const packageJson = path.join(directory, 'package.json'); + assert.equal(require.resolve(`${manifest.name}/package.json`), packageJson); + assert.equal(require.resolve(manifest.name), path.join(directory, 'index.js')); + const host = spec.leaves + .filter((leaf) => leaf.family === 'native') + .flatMap((leaf) => leaf.npm) + .map((file) => ({ + file, + manifest: JSON.parse( + readPortableArchiveEntries(file).get('package/package.json')!.data().toString('utf8'), + ), + })) + .filter( + ({ manifest: leaf }) => + leaf.os?.includes(process.platform) && leaf.cpu?.includes(process.arch), + ); + assert.equal(host.length, 1, 'final facade requires its one original host npm carrier'); + const leaf = host[0].manifest; + assert.equal(manifest.optionalDependencies[leaf.name], leaf.version); + assert.equal(manifest.oliphaunt.targetPackageNames[leaf.oliphaunt.target], leaf.name); + assert.equal(leaf.version, spec.version); + assert.equal(leaf.oliphaunt.product, spec.product); + assert.equal(leaf.oliphaunt.liboliphauntVersion, spec.runtimeVersion); + assert.deepEqual([...leaf.oliphaunt.members].sort(), [...manifest.oliphaunt.members].sort()); + const targetDirectory = path.join(root, 'node_modules', leaf.name); + extractPortableArchiveTree(host[0].file, targetDirectory, 'package'); + assert.equal( + createRequire(packageJson).resolve(`${leaf.name}/package.json`), + path.join(targetDirectory, 'package.json'), + ); + for (const name of ['index.js', 'mobile.js']) { + const file = path.join(directory, name); + const module = await import(pathToFileURL(file).href); + assert.deepEqual( + Object.keys(module).sort(), + spec.members.map((row) => row.sqlName.replaceAll('-', '_')).sort(), + ); + for (const member of spec.members) { + const descriptor = module[member.sqlName.replaceAll('-', '_')]; + assert(Object.isFrozen(descriptor)); + const { packageJsonUrl, ...identity } = descriptor; + assert.deepEqual(identity, { + schema: 'oliphaunt-native-extension-v1', + sqlName: member.sqlName, + product: spec.product, + packageName: facade.name, + version: spec.version, + }); + assert.equal(typeof packageJsonUrl, name === 'index.js' ? 'string' : 'undefined'); + if (name === 'index.js') assert.equal(fileURLToPath(packageJsonUrl), packageJson); + } + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +} diff --git a/build_defs/extensions/final_contract.test.mts b/build_defs/extensions/final_contract.test.mts new file mode 100644 index 000000000..351833bac --- /dev/null +++ b/build_defs/extensions/final_contract.test.mts @@ -0,0 +1,54 @@ +/** Validate actual target carriers on the execution host; never execute target SQL. */ +import assert from 'node:assert/strict'; +import { mkdtempSync, readFileSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { type NativeOwnerSpec, validateNativeFinalLeaf } from './owner_carriers.mts'; + +const inventory = JSON.parse(readFileSync(process.argv[2], 'utf8')); +assert.equal(inventory.schema, 'oliphaunt-native-extension-final-contract-test-v1'); +assert.equal(inventory.scope, 'construction'); +assert(inventory.products.length > 0); +const runfiles = process.env.TEST_SRCDIR; +assert(runfiles, 'final contract requires declared Bazel runfiles'); +const root = mkdtempSync(path.join(tmpdir(), 'native-final-contract-')); +const declared = (file: string) => + path.join( + runfiles, + process.env.TEST_WORKSPACE ?? '_main', + file.replace(/^bazel-out\/[^/]+\/bin\//u, ''), + ); +try { + const products = new Set(); + const sqlNames: string[] = []; + let members = 0; + for (const spec of inventory.products as NativeOwnerSpec[]) { + assert(!products.has(spec.product), 'final contract repeats a distribution'); + products.add(spec.product); + assert.equal(spec.leaves.length, 1); + const leaf = spec.leaves[0]; + assert.equal(leaf.target, inventory.target); + spec.components = declared(spec.components); + for (const group of ['github', 'npm', 'cargo'] as const) + leaf[group] = leaf[group].map(declared); + leaf.manifest = declared(leaf.manifest); + leaf.frozen = declared(leaf.frozen); + if (leaf.receipt) leaf.receipt = declared(leaf.receipt); + const validated = validateNativeFinalLeaf(spec, leaf, path.join(root, spec.product)); + assert.equal(validated.members.length, spec.members.length); + members += validated.members.length; + sqlNames.push(...validated.members.map((member) => member.sqlName)); + console.log( + `${spec.product}: actual ${inventory.target} final files, exact member inventory, platform binaries, and legal bytes PASS`, + ); + } + assert.deepEqual(sqlNames.sort(), inventory.members); + assert(inventory.excluded.every((name: string) => !sqlNames.includes(name))); + console.log( + `${products.size} native distributions / ${members} SQL members validated on ${process.platform}/${process.arch}; this content proof does not execute ${inventory.target} SQL.`, + ); + if (inventory.excluded.length > 0) + console.log(`Excluded canonical members: ${inventory.excluded.join(', ')}.`); +} finally { + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/extensions/final_leaf.bzl b/build_defs/extensions/final_leaf.bzl new file mode 100644 index 000000000..d19021240 --- /dev/null +++ b/build_defs/extensions/final_leaf.bzl @@ -0,0 +1,11 @@ +"""Typed final extension files; imported bytes never replace member producers.""" + +ExtensionFinalLeafInfo = provider(fields = [ + "product", "owner", "version", "family", "target", "metadata", + "github", "npm", "cargo", "manifest", "frozen", "spec", "validation", "receipt", "origin", + "original_files", +]) + +# A source-owned projection of actual original Apple inputs, rather than a +# claim that a copied historical document was built at this checkout. +NativeAppleBaseInfo = provider(fields = ["version", "file", "archives", "archive_files"]) diff --git a/build_defs/extensions/final_receipt_fixture.mts b/build_defs/extensions/final_receipt_fixture.mts new file mode 100644 index 000000000..844646c4a --- /dev/null +++ b/build_defs/extensions/final_receipt_fixture.mts @@ -0,0 +1,19 @@ +/** Test-only receipt identity; the bound package bytes are actual Bazel leaves. */ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { writeJson } from './native_carriers.mts'; +import { finalFileInventory } from './owner_carriers.mts'; + +const spec = JSON.parse(readFileSync(process.argv[2], 'utf8')); +assert.equal(spec.qualificationFixture.schema, 'oliphaunt-final-file-receipt-fixture-v1'); +assert.equal(spec.qualificationFixture.testOnly, true); +writeJson(spec.output, { + schema: 'oliphaunt-extension-final-files-v1', + scope: 'construction', + product: spec.leaf.product, + owner: spec.leaf.owner, + version: spec.leaf.version, + target: spec.leaf.target, + source: spec.source, + files: finalFileInventory(spec.leaf), +}); diff --git a/build_defs/extensions/forced_header_inputs_test.bzl b/build_defs/extensions/forced_header_inputs_test.bzl new file mode 100644 index 000000000..4d478ea82 --- /dev/null +++ b/build_defs/extensions/forced_header_inputs_test.bzl @@ -0,0 +1,51 @@ +"""Real object-rule analysis proves forced headers are declared compiler inputs.""" + +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") +load(":extensions.bzl", "native_extension_modules") + +def _header_impl(ctx): + header = ctx.actions.declare_file(ctx.label.name + ".h") + ctx.actions.write(header, "/* Declared forced-header fixture. */\n") + return [DefaultInfo(files = depset([header]))] + +_header = rule(implementation = _header_impl) + +def _inputs_test_impl(ctx): + env = analysistest.begin(ctx) + target = analysistest.target_under_test(env) + headers = [file for file in target[CcInfo].compilation_context.headers.to_list() if file.basename == "forced_header_fixture.h"] + asserts.equals(env, 1, len(headers)) + ordinary_headers = [file for file in target[CcInfo].compilation_context.headers.to_list() if file.basename == "ordinary_header_fixture.h"] + asserts.equals(env, 1, len(ordinary_headers)) + compiles = [action for action in analysistest.target_actions(env) if action.mnemonic == "CppCompile"] + asserts.true(env, len(compiles) > 0, "object target must retain its real C compile actions") + for header in headers: + for action in compiles: + asserts.true(env, header.path in [file.path for file in action.inputs.to_list()], "forced header is absent from compile inputs") + asserts.true(env, "-include" in action.argv and header.path in action.argv, "forced-header location is not expanded in compile flags") + for header in ordinary_headers: + for action in compiles: + asserts.false(env, header.path in [file.path for file in action.inputs.to_list()], "ordinary headers must remain eligible for input discovery") + return analysistest.end(env) + +_inputs_test = analysistest.make(_inputs_test_impl) + +def native_forced_header_input_tests(): + _header(name = "forced_header_fixture", tags = ["manual"]) + _header(name = "ordinary_header_fixture", tags = ["manual"]) + native.filegroup(name = "forced_header_inputs", srcs = [":forced_header_fixture"], tags = ["manual"]) + native_extension_modules( + name = "forced_header_location", + srcs = [":native_extension_smoke.c"], + hdrs = [":forced_header_inputs", ":ordinary_header_fixture"], + additional_compiler_inputs = [":forced_header_inputs"], + copts = ["-include", "$(location :forced_header_inputs)"], + linux_only = True, + ) + for variant in ["server", "embedded"]: + _inputs_test( + name = "forced_header_" + variant + "_inputs_test", + target_under_test = ":forced_header_location_" + variant + "_objects", + target_compatible_with = ["@platforms//os:linux"], + ) diff --git a/build_defs/extensions/imported_member.mts b/build_defs/extensions/imported_member.mts new file mode 100644 index 000000000..1ca65adbf --- /dev/null +++ b/build_defs/extensions/imported_member.mts @@ -0,0 +1,127 @@ +/** Normalize original public extension Files into private runtime sidecars. */ +import assert from 'node:assert/strict'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + isDesktopNativeTarget, + validateExtensionArtifactArchive, +} from '../../src/extensions/artifacts/packages/tools/extension-artifact-inventory.mts'; +import { + extensionRuntimeAssetContract, + projectNativeRuntimeAssetMember, +} from '../../src/extensions/artifacts/packages/tools/extension-runtime-asset-contract.mts'; +import { assemble } from './member_payload.mts'; +import { type FinalLeaf, type NativeOwnerSpec, stageDeclaredFinalLeaf } from './owner_carriers.mts'; +import { inspect } from './validate_member_payload.mts'; + +export interface ImportedMemberSpec { + configuration: string; + owner: string; + version: string; + leaf: FinalLeaf; + canonical: NativeOwnerSpec; + members: { sqlName: string; archive: string; inventory: string }[]; +} + +export async function importMembers(spec: ImportedMemberSpec): Promise { + const { canonical, leaf, configuration } = spec; + assert.equal(leaf.family, 'native'); + assert(isDesktopNativeTarget(configuration), 'imported runtime sidecar needs a desktop target'); + assert.equal(leaf.target, configuration, 'imported member target differs from its configuration'); + for (const name of ['owner', 'version'] as const) { + assert.equal(leaf[name], spec[name]); + assert.equal(canonical[name], spec[name]); + } + assert.equal(canonical.product, leaf.product); + assert(canonical.profiles.some((profile) => profile.target === configuration)); + assert(spec.members.length > 0, 'imported runtime sidecar needs requested members'); + assert.equal(new Set(spec.members.map((member) => member.sqlName)).size, spec.members.length); + const outputs = spec.members.flatMap((member) => [member.archive, member.inventory]); + assert.equal(new Set(outputs).size, outputs.length, 'imported member outputs must not repeat'); + + const root = mkdtempSync( + path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'imported-native-members-'), + ); + try { + // One owner leaf stages and parses a closed contrib bundle once for all requested members. + const staged = stageDeclaredFinalLeaf(canonical, leaf, root); + assert(leaf.originalFiles, 'imported members need the validated original File map'); + const originalFiles = JSON.parse(readFileSync(leaf.originalFiles, 'utf8')); + for (const request of spec.members) { + const authored = canonical.members.filter((member) => member.sqlName === request.sqlName); + const frozen = staged.members.filter((member: any) => member.sqlName === request.sqlName); + assert.equal(authored.length, 1, 'requested member is absent from its canonical owner'); + assert.equal(frozen.length, 1, 'requested member is absent from the original frozen leaf'); + const assets = frozen[0].assets.filter( + (asset: any) => + asset.family === 'native' && asset.kind === 'runtime' && asset.target === configuration, + ); + assert.equal(assets.length, 1, 'requested member needs exactly one selected runtime asset'); + const asset = assets[0]; + const selected = projectNativeRuntimeAssetMember(frozen[0], asset); + const runtime = validateExtensionArtifactArchive({ + file: path.join(root, asset.path), + metadata: selected, + product: leaf.product, + target: configuration, + nativeRuntimeVersion: canonical.runtimeVersion, + }); + const metadata = runtime.metadata; + const inputs = runtime.runtimeFiles.map((row: any) => { + const source = path.join(root, 'runtime', request.sqlName, row.path); + mkdirSync(path.dirname(source), { recursive: true }); + const entry = runtime.entries.get(`files/${row.path}`); + assert(entry, 'validated public runtime row is absent'); + writeFileSync(source, entry.data); + return { source, destination: row.path }; + }); + const member = authored[0]; + const descriptor = { + schema: 'oliphaunt-extension-member-payload-v1', + sql_name: request.sqlName, + owner: spec.owner, + version: spec.version, + family: 'native', + configuration, + source_kind: member.descriptor['source-kind'], + postgres_major: 18, + default_version: member.contrib + ? (member.contrib['default-version'] ?? null) + : member.source['extension-control']['default-version'], + creates_extension: metadata.createsExtension, + dependencies: metadata.dependencies, + module_profiles: metadata.nativeModuleStem === null ? [] : ['postgresql', 'modules'], + module_file: runtime.properties.get('nativeModuleFile'), + dependency_modules: metadata.nativeDependencyModules, + data_files: metadata.dataFiles.map((file: string) => `share/postgresql/${file}`), + sql_prefixes: metadata.extensionSqlFilePrefixes, + sql_files: metadata.extensionSqlFileNames, + construction_licenses: runtime.runtimeFiles + .map((row: any) => row.path) + .filter((file: string) => file.startsWith('share/licenses/')), + ...(member.contrib ? { postgres_source: member.source } : { source: member.source }), + imported: { + schema: 'oliphaunt-imported-extension-runtime-sidecar-v1', + scope: 'private-runtime-sidecar', + originalFiles, + publicAsset: extensionRuntimeAssetContract(asset), + publicLegalFiles: runtime.legalFiles, + licenseProfile: runtime.properties.get('licenseProfile'), + originalFileInventory: staged.inventory, + }, + }; + for (const output of [request.archive, request.inventory]) + mkdirSync(path.dirname(output), { recursive: true }); + await assemble({ descriptor, inputs }, request.archive, request.inventory); + inspect(request.archive, request.sqlName, spec.owner); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + assert.equal(process.argv.length, 3, 'usage: imported_member.mts SPECIFICATION'); + await importMembers(JSON.parse(readFileSync(process.argv[2], 'utf8'))); +} diff --git a/build_defs/extensions/imported_member.test.mts b/build_defs/extensions/imported_member.test.mts new file mode 100644 index 000000000..91f624481 --- /dev/null +++ b/build_defs/extensions/imported_member.test.mts @@ -0,0 +1,283 @@ +/** Production formatters over parsing fixtures; these tests grant no artifact admission. */ +import { afterEach, expect, test } from 'bun:test'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { composeExtensionReleaseDocuments } from '../../src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts'; +import { bundleCarrierAssets } from '../../src/extensions/artifacts/packages/tools/bundle-carrier-assets.mts'; +import { readPortableArchiveEntries } from '../../tools/packaging/portable-archive.mts'; +import { elfFixture } from '../../tools/packaging/testdata/release-fixture-utils.mts'; +import { fileIdentity } from '../../tools/release/native-file-identity.mts'; +import { stageNativeRustExtensions } from '../native/rust-runtime-test.mts'; +import { validateDeclaredExtensionFinalInput } from './declared_final_inputs.mts'; +import { type ImportedMemberSpec, importMembers } from './imported_member.mts'; +import { assemble } from './member_payload.mts'; +import { + assemblePublicNativeMember, + type NativeCarrierSpec, + nativeCarrierCompatibility, +} from './native_carriers.mts'; +import type { NativeOwnerSpec } from './owner_carriers.mts'; +import { inspect } from './validate_member_payload.mts'; + +const roots = new Set(); +const repository = path.resolve(import.meta.dir, '../..'); +const catalog = JSON.parse( + readFileSync(path.join(repository, 'src/extensions/catalog/extensions.source.json'), 'utf8'), +).extensions; +const contrib = Bun.TOML.parse( + readFileSync(path.join(repository, 'src/extensions/contrib/postgres18.toml'), 'utf8'), +).extensions; +afterEach(() => { + for (const root of roots) rmSync(root, { recursive: true, force: true }); + roots.clear(); +}); + +async function fixture(sqlNames: string[]): Promise { + const root = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'imported-member-test-')); + roots.add(root); + const external = sqlNames[0] === 'vector'; + const product = external ? 'oliphaunt-extension-vector' : 'oliphaunt-extension-contrib-pg18'; + const owner = external ? product : 'liboliphaunt-native'; + const configuration = external ? 'linux-arm64-gnu' : 'linux-x64-gnu'; + const version = '1.2.3'; + const members: NativeCarrierSpec[] = []; + const frozen: any[] = []; + for (const sqlName of sqlNames) { + const descriptor = catalog.find((row: any) => row['sql-name'] === sqlName); + const contributed = contrib.find((row: any) => row['sql-name'] === sqlName); + const source = external + ? { + ...Bun.TOML.parse( + readFileSync( + path.join(repository, 'src/extensions/external/vector/source.toml'), + 'utf8', + ), + ), + product, + } + : { parsingFixture: 'postgres-contrib' }; + const member = { + product, + owner, + version, + sqlName, + target: configuration, + runtimeVersion: '3.4.5', + descriptor, + source, + contrib: external ? undefined : contributed, + recipe: {}, + selectedDependencies: descriptor.dependencies, + compatibility: { + extension_runtime_contract: 'src/extensions/contracts/contract.toml', + native_runtime_product: 'liboliphaunt-native', + native_runtime_version: '3.4.5', + postgres_major: '18', + wasix_runtime_product: 'liboliphaunt-wasix', + wasix_runtime_version: '3.4.5', + }, + carriers: [], + archive: path.join(root, `${sqlName}-original-internal.tar.gz`), + } as NativeCarrierSpec; + const inputs: { source: string; destination: string }[] = []; + const add = (destination: string, bytes: Buffer | string) => { + const source = path.join(root, 'fixture', sqlName, destination); + mkdirSync(path.dirname(source), { recursive: true }); + writeFileSync(source, bytes); + inputs.push({ source, destination }); + }; + const defaultVersion = external + ? source['extension-control']['default-version'] + : contributed['default-version']; + add(`share/postgresql/extension/${sqlName}.control`, `default_version = '${defaultVersion}'\n`); + add(`share/postgresql/extension/${sqlName}--${defaultVersion}.sql`, 'SELECT 1;\n'); + const moduleFile = descriptor['native-module-file']; + for (const profile of ['postgresql', 'modules']) + add(`lib/${profile}/${moduleFile}`, elfFixture({ machine: external ? 183 : 62 })); + for (const resource of contributed?.['data-files'] ?? []) + add(resource, 'original auxiliary data\n'); + await assemble( + { + descriptor: { + schema: 'oliphaunt-extension-member-payload-v1', + owner, + version, + sql_name: sqlName, + family: 'native', + configuration, + source_kind: descriptor['source-kind'], + default_version: defaultVersion, + creates_extension: true, + dependencies: descriptor.dependencies, + module_profiles: ['postgresql', 'modules'], + module_file: moduleFile, + dependency_modules: [], + data_files: contributed?.['data-files'] ?? [], + sql_files: [], + sql_prefixes: [], + ...(external ? { source } : { postgres_source: source }), + }, + inputs, + }, + member.archive, + path.join(root, `${sqlName}-original-internal.json`), + ); + const publicFile = path.join( + root, + sqlName, + `${product}-${version}-native-${configuration}-runtime.tar.gz`, + ); + const result = assemblePublicNativeMember(member, publicFile); + members.push(member); + frozen.push({ + ...result.metadata, + assets: [{ ...result.asset, path: path.relative(root, publicFile) }], + }); + } + const productRoot = path.join(root, 'product'); + mkdirSync(path.join(productRoot, 'release-assets'), { recursive: true }); + const compatibility = nativeCarrierCompatibility(members[0]); + const directAssets = external + ? frozen[0].assets + : bundleCarrierAssets(product, version, productRoot, frozen, compatibility, { root }); + const releaseMetadata = { + class: external ? 'external' : 'contrib', + versioning: external ? 'upstream-bound' : 'runtime-bound', + sourceIdentity: { parsingFixture: product }, + compatibility, + }; + const documents = composeExtensionReleaseDocuments({ + product, + releaseProduct: owner, + family: 'native', + version, + members: frozen, + directAssets, + releaseMetadata, + }); + const file = (name: string, bytes: string) => { + const value = path.join(root, name); + writeFileSync(value, bytes); + return { path: value, ...fileIdentity(value) }; + }; + const original = { + product, + owner, + version, + family: 'native' as const, + target: configuration, + github: directAssets.map((asset: any) => { + const file = path.join(root, asset.path); + return { path: file, ...fileIdentity(file) }; + }), + npm: [file('npm-document-fixture.tgz', 'not registry admission')], + cargo: [file('cargo-document-fixture.crate', 'not registry admission')], + manifest: file('public-manifest.json', JSON.stringify(documents.releaseData)), + frozen: file('frozen.json', JSON.stringify(documents.manifest)), + }; + validateDeclaredExtensionFinalInput(original as any, { + owner, + version, + sqlNames, + sourceIdentity: releaseMetadata.sourceIdentity, + compatibility, + extensionClass: releaseMetadata.class, + versioning: releaseMetadata.versioning, + targets: [configuration], + }); + const originalFiles = file('original-files.json', JSON.stringify(original)).path; + return { + configuration, + owner, + version, + leaf: { + ...original, + github: original.github.map((value) => value.path), + npm: original.npm.map((value) => value.path), + cargo: original.cargo.map((value) => value.path), + manifest: original.manifest.path, + frozen: original.frozen.path, + originalFiles, + }, + canonical: { + product, + owner, + version, + runtimeVersion: members[0].runtimeVersion, + members, + profiles: [{ target: configuration }], + } as NativeOwnerSpec, + members: sqlNames.map((sqlName) => ({ + sqlName, + archive: path.join(root, 'normalized', `${sqlName}.tar.gz`), + inventory: path.join(root, 'normalized', `${sqlName}.json`), + })), + }; +} + +test('imports the public vector formatter and preserves both ABI profiles and original attribution', async () => { + const spec = await fixture(['vector']); + await importMembers(spec); + const request = spec.members[0]; + const descriptor = inspect(request.archive, 'vector', spec.owner) as any; + expect(descriptor.module_profiles).toEqual(['postgresql', 'modules']); + expect(descriptor.imported.scope).toBe('private-runtime-sidecar'); + expect(descriptor.imported.publicAsset.sha256).toBe(fileIdentity(spec.leaf.github[0]).sha256); + const publicFiles = readPortableArchiveEntries(spec.leaf.github[0]); + const sidecar = readPortableArchiveEntries(request.archive); + for (const [name, row] of publicFiles) + if (name.startsWith('files/')) expect(sidecar.get(name.slice(6))?.data()).toEqual(row.data()); + expect(sidecar.has('manifest.properties')).toBe(false); + expect(descriptor.imported.publicLegalFiles.length).toBeGreaterThan(0); +}); + +test('imports requested contrib nested originals once and the unchanged wrapper stages their data', async () => { + const spec = await fixture(['dict_xsyn', 'unaccent']); + await importMembers(spec); + const root = path.dirname(spec.leaf.frozen); + mkdirSync(path.join(root, 'wrapper')); + const resources = stageNativeRustExtensions( + path.join(root, 'wrapper'), + spec.members.map((member) => member.sqlName), + spec.members.map((member) => member.archive), + ); + if (!resources) throw new Error('wrapper did not stage requested extensions'); + for (const request of spec.members) { + const descriptor = inspect(request.archive, request.sqlName, spec.owner) as any; + expect(descriptor.imported.publicAsset.carrierAsset).toBe(path.basename(spec.leaf.github[0])); + expect(descriptor.imported.publicAsset.memberPath).toContain(`extensions/${request.sqlName}/`); + for (const file of descriptor.data_files) + expect(readFileSync(path.join(resources, 'extension', request.sqlName, file), 'utf8')).toBe( + 'original auxiliary data\n', + ); + } +}); + +test('rejects wrong configurations, absent members and changed original or nested hashes', async () => { + const spec = await fixture(['dict_xsyn', 'unaccent']); + await expect(importMembers({ ...spec, configuration: 'linux-arm64-gnu' })).rejects.toThrow( + 'target differs', + ); + await expect( + importMembers({ ...spec, members: [{ ...spec.members[0], sqlName: 'absent_member' }] }), + ).rejects.toThrow('canonical owner'); + const frozen = JSON.parse(readFileSync(spec.leaf.frozen, 'utf8')); + const original = readFileSync(spec.leaf.frozen); + for (const mutation of [ + (asset: any) => { + asset.memberPath = 'extensions/missing/member.tar.gz'; + }, + (asset: any) => { + asset.sha256 = '0'.repeat(64); + }, + ]) { + const modified = structuredClone(frozen); + mutation(modified.extensions[0].assets[0]); + writeFileSync(spec.leaf.frozen, JSON.stringify(modified)); + await expect(importMembers(spec)).rejects.toThrow(); + } + writeFileSync(spec.leaf.frozen, original); + writeFileSync(spec.leaf.github[0], 'altered public archive'); + await expect(importMembers(spec)).rejects.toThrow(); +}); diff --git a/build_defs/extensions/imported_members.bzl b/build_defs/extensions/imported_members.bzl new file mode 100644 index 000000000..640ecb180 --- /dev/null +++ b/build_defs/extensions/imported_members.bzl @@ -0,0 +1,83 @@ +"""Private runtime sidecars from original qualified extension owner Files.""" + +load("@oliphaunt_metadata//:metadata.bzl", "EXTENSION_RELEASE_METADATA", "NATIVE_CURRENT_ARTIFACTS") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") +load(":construction.bzl", "desktop_member_inventory", "desktop_member_payloads") +load(":declared_final_inputs.bzl", "native_extension_declared_final_import") +load(":extensions.bzl", "ExtensionMemberInfo") +load(":final_leaf.bzl", "ExtensionFinalLeafInfo") +load(":owner_carriers.bzl", "native_final_leaf_files", "native_final_leaf_input", "native_owner_carrier_helpers", "native_owner_carrier_legal") + +_LINUX_X64 = ["@platforms//os:linux", "@platforms//cpu:x86_64"] +_ImportedMembersInfo = provider(fields = ["members"]) + +def _import_members_impl(ctx): + leaf = ctx.attr.leaf[ExtensionFinalLeafInfo] + if leaf.family != "native" or leaf.target != "linux-x64-gnu" or not leaf.validation or not hasattr(leaf, "original_files") or not leaf.original_files: + fail("Rust runtime extensions require validated original Linux x64 final Files") + names = sorted([member["sqlName"] for member in leaf.metadata["members"]]) + if ctx.attr.sql_names != names or len({name: True for name in names}) != len(names): + fail("imported runtime members must cover their exact canonical owner") + outputs, members, rows = [], {}, [] + for name in names: + archive = ctx.actions.declare_file(ctx.label.name + "/" + name + ".tar.gz") + inventory = ctx.actions.declare_file(ctx.label.name + "/" + name + ".inventory.json") + outputs += [archive, inventory] + rows.append({"sqlName": name, "archive": archive.path, "inventory": inventory.path}) + members[name] = ExtensionMemberInfo(sql_name = name, owner = leaf.owner, configuration = leaf.target, + archive = archive, inventory = inventory) + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode({"members": rows, "configuration": leaf.target, + "owner": leaf.owner, "version": leaf.version, "canonical": leaf.metadata, + "leaf": native_final_leaf_input(leaf)})) + bun_file_action(ctx, ctx.file._runner, arguments = [spec.path], + inputs = native_final_leaf_files(leaf) + [spec], + source_files = [ctx.file._runner] + ctx.files._helpers + ctx.files.legal, + outputs = outputs, mnemonic = "ImportNativeRuntimeExtensionMembers") + return [DefaultInfo(files = depset(outputs)), _ImportedMembersInfo(members = members)] + +_import_members = rule(implementation = _import_members_impl, toolchains = BUN_SOURCE_TOOLCHAINS, attrs = { + "leaf": attr.label(mandatory = True, providers = [ExtensionFinalLeafInfo]), + "sql_names": attr.string_list(mandatory = True), + "legal": attr.label_list(allow_files = True), + "_runner": attr.label(default = "//build_defs/extensions:imported_member.mts", allow_single_file = True), + "_helpers": attr.label_list(default = native_owner_carrier_helpers() + [ + "//build_defs/extensions:owner_carriers.mts", "//build_defs/extensions:member_payload.mts", + ], allow_files = True), +}) + +def _member_impl(ctx): + member = ctx.attr.members[_ImportedMembersInfo].members[ctx.attr.sql_name] + return [DefaultInfo(files = depset([member.archive, member.inventory])), member, + OutputGroupInfo(archive = depset([member.archive]), inventory = depset([member.inventory]))] + +_member = rule(implementation = _member_impl, attrs = { + "members": attr.label(mandatory = True, providers = [_ImportedMembersInfo]), + "sql_name": attr.string(mandatory = True), +}) + +def desktop_runtime_member_payloads(name, include_postgis = False): + """Keep construction local; late runtime qualification consumes original Files.""" + if NATIVE_CURRENT_ARTIFACTS == None: + return desktop_member_payloads(include_postgis) + products = {row["sqlName"]: row["artifactProduct"] for row in EXTENSION_RELEASE_METADATA} + rows = desktop_member_inventory(include_postgis) + groups = {} + for row in rows: + product = products[row.name] + if product not in groups: + groups[product] = [] + groups[product].append(row.name) + labels = {} + for product, names in groups.items(): + group = name + "_" + product.replace("-", "_") + native_extension_declared_final_import(name = group + "_original", product = product, + family = "native", target = "linux-x64-gnu", testonly = True, target_compatible_with = _LINUX_X64) + _import_members(name = group, leaf = ":" + group + "_original", sql_names = sorted(names), legal = native_owner_carrier_legal(product), + testonly = True, target_compatible_with = _LINUX_X64) + for sql_name in names: + member = name + "_" + sql_name + _member(name = member, members = ":" + group, sql_name = sql_name, + testonly = True, target_compatible_with = _LINUX_X64) + labels[sql_name] = ":" + member + return [labels[row.name] for row in rows] diff --git a/build_defs/extensions/member_payload.mts b/build_defs/extensions/member_payload.mts new file mode 100644 index 000000000..5968bd145 --- /dev/null +++ b/build_defs/extensions/member_payload.mts @@ -0,0 +1,159 @@ +/** Assemble an internal native member payload from explicit Bazel inputs. */ +import { createHash } from 'node:crypto'; +import { lstat, readdir, readFile, realpath, stat, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import { parseArgs } from 'node:util'; +import { gzipSync } from 'node:zlib'; +import { tarHeader } from '../../tools/packaging/archive-directory.mts'; +import { portableMemberName } from '../../tools/packaging/portable-archive.mts'; + +export interface MemberSpec { + descriptor: Record; + inputs: { source: string; destination: string; tree?: boolean }[]; +} + +function compareText(left: string, right: string): number { + const a = Array.from(left, (character) => character.codePointAt(0) ?? 0); + const b = Array.from(right, (character) => character.codePointAt(0) ?? 0); + for (let index = 0; index < Math.min(a.length, b.length); index += 1) { + if (a[index] !== b[index]) return a[index] - b[index]; + } + return a.length - b.length; +} + +// Preserve the prior inventory's sorted keys, two-space indentation and ASCII +// escaping, including nested objects, integer-like keys and UTF-16 surrogate pairs. +function inventoryJson(value: unknown, depth = 0): string { + const indent = ' '.repeat(depth); + const childIndent = `${indent} `; + if (Array.isArray(value)) { + return value.length + ? `[\n${value.map((item) => childIndent + inventoryJson(item, depth + 1)).join(',\n')}\n${indent}]` + : '[]'; + } + if (value !== null && typeof value === 'object') { + const record = value as Record; + const keys = Object.keys(record).sort(compareText); + return keys.length + ? `{\n${keys.map((key) => `${childIndent}${inventoryJson(key)}: ${inventoryJson(record[key], depth + 1)}`).join(',\n')}\n${indent}}` + : '{}'; + } + const text = JSON.stringify(value); + if (text === undefined || (typeof value === 'number' && !Number.isFinite(value))) { + throw new Error('member inventory must contain JSON values'); + } + return text.replace( + /[\u007f-\uffff]/g, + (character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, '0')}`, + ); +} + +export function safePath(value: string): string { + if ( + !value || + value.startsWith('/') || + value.includes('\\') || + value.split('/').some((part) => !part || part === '.' || part === '..') + ) { + throw new Error(`unsafe member destination: ${value}`); + } + portableMemberName(value, 'file', value); + return value; +} + +async function treeFiles(directory: string): Promise { + const files: string[] = []; + for (const entry of await readdir(directory, { withFileTypes: true })) { + const file = path.join(directory, entry.name); + if ((await lstat(file)).isDirectory()) files.push(...(await treeFiles(file))); + else files.push(file); + } + return files; +} + +export async function assemble(spec: MemberSpec, output: string, inventory: string): Promise { + if (!spec.descriptor || typeof spec.descriptor !== 'object' || Array.isArray(spec.descriptor)) { + throw new Error('member specification must declare a descriptor object'); + } + const contents = new Map(); + for (const entry of spec.inputs) { + if (typeof entry.destination !== 'string') { + throw new Error('member input must declare a destination string'); + } + // Flatten Bazel's projected file links, without following directory links + // into undeclared trees. Every emitted archive entry is a regular file. + const source = await realpath(entry.source); + const files = entry.tree ? await treeFiles(source) : [source]; + for (const file of files) { + const metadata = await stat(file); + if (metadata.isDirectory()) continue; + if (!metadata.isFile()) throw new Error(`member input is not a regular file: ${file}`); + const destination = safePath( + entry.tree + ? `${entry.destination}/${path.relative(source, file).split(path.sep).join('/')}` + : entry.destination, + ); + if (contents.has(destination) || destination === 'extension.json') { + throw new Error(`duplicate member destination: ${destination}`); + } + contents.set(destination, await readFile(file)); + } + } + const names = [...contents.keys()].sort(compareText); + const descriptor = { + ...spec.descriptor, + files: names.map((name) => ({ + path: name, + sha256: createHash('sha256') + .update(contents.get(name) ?? Buffer.alloc(0)) + .digest('hex'), + })), + }; + const json = `${inventoryJson(descriptor)}\n`; + contents.set('extension.json', Buffer.from(json)); + const chunks: Buffer[] = []; + for (const name of [...contents.keys()].sort(compareText)) { + const data = contents.get(name); + if (!data) throw new Error(`missing member content: ${name}`); + chunks.push( + tarHeader({ name, isDirectory: false }, data.length, name.startsWith('lib/') ? 0o755 : 0o644), + data, + Buffer.alloc((512 - (data.length % 512)) % 512), + ); + } + chunks.push(Buffer.alloc(1024)); + const length = chunks.reduce((total, chunk) => total + chunk.length, 0); + chunks.push(Buffer.alloc((10_240 - (length % 10_240)) % 10_240)); + // Retain the internal format's level-9 XFL=2/OS=255 header and 10 KiB tar + // record framing. The compressed deflate stream belongs to the pinned Bun. + const compressed = gzipSync(Buffer.concat(chunks), { level: 9 }); + compressed.fill(0, 4, 8); + compressed[8] = 2; + compressed[9] = 255; + await writeFile(output, compressed); + await writeFile(inventory, json); +} + +if (import.meta.main) { + try { + const { values } = parseArgs({ + options: { + spec: { type: 'string' }, + output: { type: 'string' }, + inventory: { type: 'string' }, + }, + }); + if (!values.spec || !values.output || !values.inventory) { + throw new Error( + 'usage: member_payload.mts --spec --output --inventory ', + ); + } + const text = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode( + await readFile(values.spec), + ); + await assemble(JSON.parse(text), values.output, values.inventory); + } catch (cause) { + console.error(cause instanceof Error ? cause.message : String(cause)); + process.exitCode = 2; + } +} diff --git a/build_defs/extensions/member_payload.test.mts b/build_defs/extensions/member_payload.test.mts new file mode 100644 index 000000000..ed120704f --- /dev/null +++ b/build_defs/extensions/member_payload.test.mts @@ -0,0 +1,684 @@ +/** Real archive tests with an independent native writer and frozen Python oracle. */ +import { afterEach, expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdtempSync, readFileSync, rmSync } from 'node:fs'; +import { mkdir, readFile, symlink, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { gunzipSync, gzipSync } from 'node:zlib'; +import { + arFixture, + elfFixture, + machoFixture, +} from '../../tools/packaging/testdata/release-fixture-utils.mts'; +import { assemble, type MemberSpec, safePath } from './member_payload.mts'; +import { inspect, inspectStaticArchiveBytes } from './validate_member_payload.mts'; + +const directories = new Set(); +function temporary(): string { + const directory = mkdtempSync(join(process.env.TEST_TMPDIR ?? tmpdir(), 'member-payload-')); + directories.add(directory); + return directory; +} +afterEach(() => { + for (const directory of directories) rmSync(directory, { recursive: true, force: true }); + directories.clear(); +}); + +function descriptor(overrides: Record = {}): Record { + return { + schema: 'oliphaunt-extension-member-payload-v1', + sql_name: 'pgtap', + owner: 'fixture-owner', + version: '1.3.5', + configuration: 'linux-x64-gnu', + family: 'native', + creates_extension: true, + default_version: '1.3.5', + module_profiles: [], + data_files: [], + sql_prefixes: [], + sql_files: [], + ...overrides, + }; +} + +const sqlPrefix = 'share/postgresql/extension/'; +function sqlFiles(): Map { + return new Map([ + [`${sqlPrefix}pgtap.control`, Buffer.from("default_version = '1.3.5'\n")], + [ + `${sqlPrefix}pgtap--1.3.5.sql`, + Buffer.from("CREATE FUNCTION ok() RETURNS text AS 'SELECT 1' LANGUAGE sql;\n"), + ], + ]); +} + +function headerChecksum(header: Buffer): void { + header.fill(0x20, 148, 156); + const checksum = header.reduce((total, byte) => total + byte, 0); + header.write(`${checksum.toString(8).padStart(6, '0')}\0 `, 148, 'ascii'); +} + +function physicalName(header: Buffer, name: string): void { + if (Buffer.byteLength(name) > 100) throw new Error('test archive path exceeds header field'); + header.fill(0, 0, 100); + header.fill(0, 345, 500); + header.write(name, 0, 'utf8'); + headerChecksum(header); +} + +interface OracleOptions { + extra?: { name: string; type?: number }; + rename?: (name: string) => string; + prefixBOM?: boolean; + inventory?: { path: string; sha256: string }[]; + omitDescriptor?: boolean; +} + +async function writeArchive( + file: string, + files: Map, + facts = descriptor(), + options: OracleOptions = {}, +): Promise { + const recorded = + options.inventory ?? + [...files].map(([name, data]) => ({ + path: name, + sha256: createHash('sha256').update(data).digest('hex'), + })); + const contents = new Map(files); + if (!options.omitDescriptor) { + contents.set('extension.json', Buffer.from(JSON.stringify({ ...facts, files: recorded }))); + } + // Bun's independent libarchive writer provides genuine USTAR fixtures. Raw + // header mutations exercise cases archive-writing APIs deliberately forbid. + let tar = Buffer.from(await new Bun.Archive(Object.fromEntries(contents)).bytes()); + let offset = 0; + while (tar.subarray(offset, offset + 512).some((byte) => byte !== 0)) { + const header = tar.subarray(offset, offset + 512); + const size = Number.parseInt(header.subarray(124, 136).toString('ascii'), 8); + if (options.rename) { + physicalName(header, options.rename(header.subarray(0, 100).toString('utf8').split('\0')[0])); + } + if (options.prefixBOM) { + header.write('\uFEFF', 345, 'utf8'); + headerChecksum(header); + } + offset += 512 + Math.ceil(size / 512) * 512; + } + if (options.extra) { + const independent = Buffer.from(await new Bun.Archive({ extra: '' }).bytes()); + const header = independent.subarray(0, 512); + physicalName(header, options.extra.name); + header[156] = options.extra.type ?? 0x30; + if (header[156] === 0x35) header.write('0000755\0', 100, 'ascii'); + if (header[156] === 0x31 || header[156] === 0x32) header.write('target', 157, 'ascii'); + headerChecksum(header); + tar = Buffer.concat([tar.subarray(0, offset), header, Buffer.alloc(1024)]); + } + await writeFile(file, gzipSync(tar)); +} + +// Captured from the replaced Python writer: Unicode metadata, an empty nested +// resource and a projected file symlink. No Python interpreter is needed now. +const PYTHON_ORACLE = Buffer.from( + 'H4sIAAAAAAAC/+2XXXKbMBDH/exTMDwHB4GQUa9SZzxCrGIyIChIrt1MDtRz9GIVHyW2J+20D3Y6k/098LFapD/aXQlyYcS9FOrH95U5mMVVCB2M0uHsuDw76Mm1s5NwTdjCCxc3wHZGtG74xcdEFSUskA9L3te/hs5Afg9VY47vUv8X14RE4Rrr/2bxb9r6CaRLgf9m/U+SCOOP6z9ybeBgQHdFrVdPXa3fpf4Jo9Fl/bME1/+b8Lz0PF/WWhWPthXGJYL/yfPLQttDcGA0eNTWvxt8WhAGuu2cMM5PibKDobXfRrb9WtI582dnmWz9r8XGhiHw/vdi6OlXy+lHx1nDvBv5zvgwdg9K2NJs99BOQ/ujKiWqojz299qJ38NkPRPyPByduRFm17v+Vpjz6XYiSljvFWdcxkmqYqZCEZOMiTwGQlUccrmWivBUSB5RBmlMmOISEhrnSUa4kGGUpaE/dPly9wcNb0zBmQSIs1BSGvFUSSIJ5UJlisqUc6YyN3a0FkAJUEZ5xmMqBeUJ5yRbp4lTkCR/IeF1sq83BXMYqzq3JWzdmHOExoZxItz9KNIXc/A8T9uynLWNIRv7fZiS5ptzNq2F5fSqvq7N0Lk/x9jb2DyNc3eUJN3oMUvqrxra3k0VB2NbCEbD0NbJHVS9Cr8ui2YnrDbBnPlBBVUGbdCIY1mLPNiT6aEv5fbixXqTFhWcDPPq27TgbKfuJ/lNVuHKTeDLEvcoBEEQBEEQBEEQBEEQBEEQBEH+jZ94nzpnACgAAA==', + 'base64', +); + +test('independent reader requires construction notices and verifies exact pinned license bytes', async () => { + const root = temporary(); + const archive = join(root, 'payload.tar.gz'); + const prefix = 'share/licenses/llvm-compiler-rt/'; + const license = Buffer.from('fixture upstream license\n'); + const facts = descriptor({ + construction_licenses: [`${prefix}LICENSE.TXT`, `${prefix}SOURCE.json`], + }); + const files = sqlFiles(); + files.set(`${prefix}LICENSE.TXT`, license); + files.set( + `${prefix}SOURCE.json`, + Buffer.from( + JSON.stringify({ + schema: 'oliphaunt-compiler-runtime-source-v1', + files: [ + { + destination: 'LICENSE.TXT', + sha256: createHash('sha256').update(license).digest('hex'), + }, + ], + }), + ), + ); + await writeArchive(archive, files, facts); + expect(inspect(archive).construction_licenses).toEqual(facts.construction_licenses); + files.delete(`${prefix}LICENSE.TXT`); + await writeArchive(archive, files, facts); + expect(() => inspect(archive)).toThrow('missing a required construction license'); + files.set(`${prefix}LICENSE.TXT`, Buffer.from('different license bytes\n')); + await writeArchive(archive, files, facts); + expect(() => inspect(archive)).toThrow('license bytes differ from their upstream source pin'); +}); + +test('writer preserves the frozen tar/inventory oracle and deterministic gzip framing', async () => { + const root = temporary(); + await mkdir(join(root, 'tree/nested'), { recursive: true }); + await writeFile(join(root, 'tree/café.txt'), 'file'); + await writeFile(join(root, 'tree/nested/empty'), ''); + await symlink(join(root, 'tree/café.txt'), join(root, 'tree/projected')); + const spec = { + descriptor: descriptor({ + sql_name: 'fixture', + version: '1.0.0', + creates_extension: false, + default_version: '', + data_files: ['data/café.txt', 'data/nested/empty', 'data/projected'], + notes: 'café �\n', + nested: { z: true, a: [null, 'é'] }, + }), + inputs: [{ source: join(root, 'tree'), destination: 'data', tree: true }], + }; + for (const name of ['first', 'second']) { + await assemble(spec, join(root, `${name}.tar.gz`), join(root, `${name}.json`)); + } + const archive = await readFile(join(root, 'first.tar.gz')); + expect(await readFile(join(root, 'second.tar.gz'))).toEqual(archive); + expect([...archive.subarray(0, 10)]).toEqual([31, 139, 8, 0, 0, 0, 0, 0, 2, 255]); + expect(gunzipSync(archive)).toEqual(gunzipSync(PYTHON_ORACLE)); + const oracleFiles = await new Bun.Archive(PYTHON_ORACLE).files(); + expect(await readFile(join(root, 'first.json'), 'utf8')).toBe( + await oracleFiles.get('extension.json')?.text(), + ); + const files = await new Bun.Archive(archive).files(); + expect([...files.keys()]).toEqual([ + 'data/café.txt', + 'data/nested/empty', + 'data/projected', + 'extension.json', + ]); + expect(await files.get('data/projected')?.text()).toBe('file'); + expect(await files.get('data/nested/empty')?.bytes()).toEqual(new Uint8Array()); + expect(inspect(join(root, 'first.tar.gz'), 'fixture', 'fixture-owner')).toEqual( + JSON.parse(await readFile(join(root, 'first.json'), 'utf8')), + ); +}); + +test('writer flattens projected files, skips linked directories and rejects malformed mappings', async () => { + const root = temporary(); + await mkdir(join(root, 'sql')); + await mkdir(join(root, 'outside')); + await writeFile(join(root, 'file'), 'file'); + await writeFile(join(root, 'outside/undeclared'), 'outside'); + await symlink(join(root, 'file'), join(root, 'sql/projected')); + await symlink(join(root, 'outside'), join(root, 'sql/linked-directory')); + await symlink(join(root, 'sql'), join(root, 'sql/cycle')); + const output = join(root, 'payload.tar.gz'); + const inventory = join(root, 'inventory.json'); + const entry = { source: join(root, 'file'), destination: 'safe/file' }; + await expect( + assemble({ descriptor: descriptor(), inputs: [entry, entry] }, output, inventory), + ).rejects.toThrow('duplicate'); + await expect( + assemble( + { descriptor: descriptor(), inputs: [{ ...entry, destination: 'extension.json' }] }, + output, + inventory, + ), + ).rejects.toThrow('duplicate'); + for (const path of [ + '', + '../escape', + '/absolute', + 'safe/../escape', + 'safe\\escape', + 'safe//empty', + './relative', + ]) { + expect(() => safePath(path)).toThrow(); + } + await expect(assemble({ inputs: [entry] } as MemberSpec, output, inventory)).rejects.toThrow( + 'descriptor', + ); + await expect( + assemble( + { + descriptor: descriptor(), + inputs: [{ source: join(root, 'sql'), tree: true }], + } as MemberSpec, + output, + inventory, + ), + ).rejects.toThrow('destination'); + await assemble( + { + descriptor: descriptor(), + inputs: [{ source: join(root, 'sql'), destination: 'sql', tree: true }], + }, + output, + inventory, + ); + const files = await new Bun.Archive(await readFile(output)).files(); + expect([...files.keys()]).toEqual(['extension.json', 'sql/projected']); + expect(await files.get('sql/projected')?.text()).toBe('file'); +}); + +test('validator accepts independently written SQL, additional resources and projected archive links', async () => { + const root = temporary(); + const archive = join(root, 'payload.tar.gz'); + const files = sqlFiles(); + files.set(`${sqlPrefix}utility_helpers.sql`, Buffer.from('helper')); + files.set(`${sqlPrefix}uninstall.sql`, Buffer.from('uninstall')); + files.set('share/postgresql/tsearch_data/fixture.rules', Buffer.from('data')); + await writeArchive( + archive, + files, + descriptor({ + sql_prefixes: ['utility_'], + sql_files: ['uninstall.sql'], + data_files: ['share/postgresql/tsearch_data/fixture.rules'], + }), + ); + await symlink(archive, join(root, 'projected.tar.gz')); + expect(inspect(join(root, 'projected.tar.gz'), 'pgtap', 'fixture-owner').default_version).toBe( + '1.3.5', + ); + expect(() => inspect(archive, 'other')).toThrow('requested extension'); + expect(() => inspect(archive, 'pgtap', 'other-owner')).toThrow('canonical ownership'); +}); + +test('validator rejects physical links, directories, traversal, dot prefixes and duplicate paths', async () => { + const archive = join(temporary(), 'payload.tar.gz'); + for (const extra of [ + { name: '../escape' }, + { name: '/absolute' }, + { name: 'safe\\escape' }, + { name: 'safe//empty' }, + { name: 'link', type: 0x32 }, + { name: 'hardlink', type: 0x31 }, + { name: 'directory', type: 0x35 }, + { name: '.', type: 0x35 }, + ]) { + await writeArchive(archive, sqlFiles(), descriptor(), { extra }); + expect(() => inspect(archive)).toThrow(); + } + await writeArchive(archive, sqlFiles(), descriptor(), { rename: (name) => `./${name}` }); + expect(() => inspect(archive)).toThrow('safe regular'); + await writeArchive(archive, sqlFiles(), descriptor(), { rename: (name) => `\uFEFF${name}` }); + expect(() => inspect(archive)).toThrow('safe regular'); + await writeArchive(archive, sqlFiles(), descriptor(), { prefixBOM: true }); + expect(() => inspect(archive)).toThrow('safe regular'); + await writeArchive(archive, sqlFiles(), descriptor(), { + extra: { name: `${sqlPrefix}pgtap.control` }, + }); + expect(() => inspect(archive)).toThrow('repeats'); +}); + +test('validator rejects malformed descriptors, missing inventory, checksum drift and foreign resources', async () => { + const archive = join(temporary(), 'payload.tar.gz'); + for (const [field, value, message] of [ + ['schema', 'unknown', 'schema'], + ['sql_name', 'pgTAP', 'SQL identity'], + ['sql_name', 'pgtap\n', 'SQL identity'], + ['configuration', 'android-arm64-v8a', 'unsupported'], + ['family', 'wasix', 'unsupported'], + ['creates_extension', undefined, 'creates_extension'], + ['data_files', ['share/postgresql/tsearch_data/missing.rules'], 'data resource'], + ['data_files', null, 'resource arrays'], + ['sql_prefixes', null, 'resource arrays'], + ['sql_files', null, 'resource arrays'], + ['module_profiles', ['modules'], 'ABI profile'], + ['module_profiles', ['modules', 'postgresql'], 'ABI profile'], + ] as const) { + await writeArchive(archive, sqlFiles(), descriptor({ [field]: value })); + expect(() => inspect(archive)).toThrow(message); + } + await writeArchive(archive, sqlFiles(), descriptor(), { omitDescriptor: true }); + expect(() => inspect(archive)).toThrow('no descriptor'); + const row = { path: `${sqlPrefix}pgtap.control`, sha256: '0'.repeat(64) }; + for (const inventory of [[], [row, row], [row, { ...row, path: 'missing' }]]) { + await writeArchive(archive, sqlFiles(), descriptor(), { inventory }); + expect(() => inspect(archive)).toThrow('inventory'); + } + await writeArchive(archive, sqlFiles(), descriptor(), { + inventory: [...sqlFiles()].map(([path]) => ({ path, sha256: '0'.repeat(64) })), + }); + expect(() => inspect(archive)).toThrow('checksum'); + const files = sqlFiles(); + files.set(`${sqlPrefix}foreign.control`, Buffer.from('foreign')); + await writeArchive(archive, files); + expect(() => inspect(archive)).toThrow('foreign'); + files.delete(`${sqlPrefix}foreign.control`); + files.set('undeclared/resource', Buffer.from('foreign')); + await writeArchive(archive, files); + expect(() => inspect(archive)).toThrow('undeclared'); +}); + +test('validator requires both real ELF x86_64 shared-object profiles', async () => { + const archive = join(temporary(), 'payload.tar.gz'); + const facts = descriptor({ + module_profiles: ['postgresql', 'modules'], + module_file: 'fixture.so', + }); + const elf = Buffer.alloc(64); + Buffer.from([0x7f, 0x45, 0x4c, 0x46, 2, 1]).copy(elf); + elf.writeUInt16LE(3, 16); + elf.writeUInt16LE(62, 18); + const files = sqlFiles(); + for (const profile of ['postgresql', 'modules']) files.set(`lib/${profile}/fixture.so`, elf); + await writeArchive(archive, files, facts); + expect(inspect(archive).module_profiles).toEqual(['postgresql', 'modules']); + for (const invalid of [Buffer.alloc(63), Buffer.from(elf)]) { + if (invalid.length === 64) invalid.writeUInt16LE(183, 18); + files.set('lib/modules/fixture.so', invalid); + await writeArchive(archive, files, facts); + expect(() => inspect(archive)).toThrow('ELF x86_64'); + } + files.delete('lib/modules/fixture.so'); + await writeArchive(archive, files, facts); + expect(() => inspect(archive)).toThrow('required ABI'); + await writeArchive( + archive, + sqlFiles(), + descriptor({ module_profiles: ['postgresql', 'modules'] }), + ); + expect(() => inspect(archive)).toThrow('module file'); + await writeArchive(archive, sqlFiles(), descriptor({ module_file: 'fixture.so' })); + expect(() => inspect(archive)).toThrow('both ABI'); +}); + +test('validator checks AArch64 modules against the archive target identity', async () => { + const archive = join(temporary(), 'payload.tar.gz'); + const facts = descriptor({ + configuration: 'linux-arm64-gnu', + module_profiles: ['postgresql', 'modules'], + module_file: 'fixture.so', + }); + const elf = Buffer.alloc(64); + Buffer.from([0x7f, 0x45, 0x4c, 0x46, 2, 1]).copy(elf); + elf.writeUInt16LE(3, 16); + elf.writeUInt16LE(183, 18); + const files = sqlFiles(); + for (const profile of ['postgresql', 'modules']) files.set(`lib/${profile}/fixture.so`, elf); + await writeArchive(archive, files, facts); + expect(inspect(archive).configuration).toBe('linux-arm64-gnu'); + elf.writeUInt16LE(62, 18); + await writeArchive(archive, files, facts); + expect(() => inspect(archive)).toThrow('ELF aarch64'); + await writeArchive(archive, files, { ...facts, configuration: 'linux-arm64-musl' }); + expect(() => inspect(archive)).toThrow('configuration'); +}); + +function desktopImage(configuration: string, provider = 'KERNEL32.dll'): Buffer { + if (configuration === 'macos-arm64') { + const data = Buffer.alloc(56); + data.writeUInt32LE(0xfeedfacf, 0); + data.writeUInt32LE(0x0100000c, 4); + data.writeUInt32LE(6, 12); + data.writeUInt32LE(1, 16); + data.writeUInt32LE(24, 20); + data.writeUInt32LE(0x32, 32); + data.writeUInt32LE(24, 36); + data.writeUInt32LE(1, 40); + data.writeUInt32LE(11 << 16, 44); + return data; + } + const data = Buffer.alloc(1024); + data.write('MZ'); + data.writeUInt32LE(0x80, 0x3c); + data.write('PE\0\0', 0x80); + const coff = 0x84; + data.writeUInt16LE(0x8664, coff); + data.writeUInt16LE(1, coff + 2); + data.writeUInt16LE(240, coff + 16); + data.writeUInt16LE(0x2022, coff + 18); + const optional = coff + 20; + data.writeUInt16LE(0x20b, optional); + data.writeUInt32LE(512, optional + 60); + data.writeUInt32LE(16, optional + 108); + data.writeUInt32LE(0x1000, optional + 120); + data.writeUInt32LE(40, optional + 124); + const section = optional + 240; + data.write('.rdata', section); + data.writeUInt32LE(512, section + 8); + data.writeUInt32LE(0x1000, section + 12); + data.writeUInt32LE(512, section + 16); + data.writeUInt32LE(512, section + 20); + data.writeUInt32LE(0x1080, 512 + 12); + data.write(`${provider}\0`, 640); + return data; +} + +test('Apple static members inspect their actual cohort and deployment floor before packaging', () => { + const cohorts = [ + ['macos-arm64', 1, [14, 0, 0]], + ['ios-device', 2, [17, 0, 0]], + ['ios-simulator', 7, [17, 0, 0]], + ] as const; + for (const [target, platform, minos] of cohorts) { + const image = machoFixture({ platform, minos: [...minos] }); + image.writeUInt32LE(1, 12); + const archive = arFixture([['fixture.o', image]]); + expect(inspectStaticArchiveBytes(archive, target, target).platforms).toEqual([platform]); + for (const [other] of cohorts) { + if (other !== target) + expect(() => inspectStaticArchiveBytes(archive, other, target)).toThrow('is missing'); + } + expect(() => inspectStaticArchiveBytes(image, target, target)).toThrow( + 'ordinary object archive', + ); + const highFloor = Buffer.from(image); + highFloor.writeUInt32LE((minos[0] + 1) << 16, 44); + expect(() => + inspectStaticArchiveBytes(arFixture([['high.o', highFloor]]), target, target), + ).toThrow('minimum OS'); + const wrongCpu = Buffer.from(image); + wrongCpu.writeUInt32LE(0x01000007, 4); + expect(() => + inspectStaticArchiveBytes(arFixture([['wrong.o', wrongCpu]]), target, target), + ).toThrow('not arm64'); + } +}); + +test('mobile static archive inspection preserves both Android architecture contracts', () => { + for (const [target, machine, other] of [ + ['android-arm64-v8a', 183, 'android-x86_64'], + ['android-x86_64', 62, 'android-arm64-v8a'], + ] as const) { + const image = elfFixture({ machine, type: 1 }); + const archive = arFixture([['fixture.o', image]]); + expect(inspectStaticArchiveBytes(archive, target, target).binaries).toBe(1); + expect(() => inspectStaticArchiveBytes(archive, other, target)).toThrow('ELF machine'); + expect(() => inspectStaticArchiveBytes(image, target, target)).toThrow( + 'ordinary object archive', + ); + } +}); + +test('desktop member archives validate actual Mach-O and PE profiles with the shared binary policy', async () => { + const archive = join(temporary(), 'desktop.tar.gz'); + for (const configuration of ['macos-arm64', 'windows-x64-msvc']) { + const module = configuration === 'macos-arm64' ? 'fixture.dylib' : 'fixture.dll'; + const facts = descriptor({ + configuration, + module_file: module, + module_profiles: ['postgresql', 'modules'], + }); + const files = sqlFiles(); + files.set(`lib/postgresql/${module}`, desktopImage(configuration, 'postgres.exe')); + files.set(`lib/modules/${module}`, desktopImage(configuration, 'oliphaunt.dll')); + await writeArchive(archive, files, facts); + expect(inspect(archive).configuration).toBe(configuration); + const invalid = desktopImage(configuration); + if (configuration === 'macos-arm64') invalid.writeUInt32LE(0x01000007, 4); + else invalid.writeUInt16LE(0xaa64, 0x84); + files.set(`lib/modules/${module}`, invalid); + await writeArchive(archive, files, facts); + expect(() => inspect(archive)).toThrow(); + const object = desktopImage(configuration); + if (configuration === 'macos-arm64') object.writeUInt32LE(1, 12); + else object.writeUInt16LE(0x22, 0x84 + 18); + files.set(`lib/modules/${module}`, object); + await writeArchive(archive, files, facts); + expect(() => inspect(archive)).toThrow( + configuration === 'macos-arm64' ? 'dylib or bundle' : 'DLL', + ); + await writeArchive(archive, files, { ...facts, module_file: 'fixture.so' }); + expect(() => inspect(archive)).toThrow('module file'); + } +}); + +test('desktop module validation rejects provider swaps, high deployment floors and mobile substitution', async () => { + const archive = join(temporary(), 'desktop.tar.gz'); + const files = sqlFiles(); + for (const profile of ['postgresql', 'modules']) + files.set(`lib/${profile}/fixture.dll`, desktopImage('windows-x64-msvc', 'oliphaunt.dll')); + const facts = descriptor({ + configuration: 'windows-x64-msvc', + module_file: 'fixture.dll', + module_profiles: ['postgresql', 'modules'], + }); + await writeArchive(archive, files, facts); + expect(() => inspect(archive)).toThrow('standalone PostgreSQL'); + files.set('lib/postgresql/fixture.dll', desktopImage('windows-x64-msvc', 'postgres.exe')); + files.set('lib/modules/fixture.dll', desktopImage('windows-x64-msvc', 'postgres.exe')); + await writeArchive(archive, files, facts); + expect(() => inspect(archive)).toThrow('embedded extension'); + const macho = desktopImage('macos-arm64'); + for (const profile of ['postgresql', 'modules']) files.set(`lib/${profile}/fixture.dylib`, macho); + files.delete('lib/postgresql/fixture.dll'); + files.delete('lib/modules/fixture.dll'); + const macFacts = { ...facts, configuration: 'macos-arm64', module_file: 'fixture.dylib' }; + macho.writeUInt32LE(14 << 16, 44); + await writeArchive(archive, files, macFacts); + expect(() => inspect(archive)).toThrow('exceeds'); + macho.writeUInt32LE(11 << 16, 44); + macho.writeUInt32LE(2, 40); + await writeArchive(archive, files, macFacts); + expect(() => inspect(archive)).toThrow('unsupported iOS'); + await writeArchive(archive, files, { ...macFacts, configuration: 'ios-xcframework' }); + expect(() => inspect(archive)).toThrow('configuration'); +}); + +test('validator requires dependency ELF bytes in both ABI layouts and exact data resources', async () => { + const archive = join(temporary(), 'payload.tar.gz'); + const facts = descriptor({ + module_profiles: ['postgresql', 'modules'], + module_file: 'fixture.so', + dependency_modules: ['fixture_deps.so'], + data_files: ['share/postgresql/contrib/fixture/install.sql'], + }); + const elf = Buffer.alloc(64); + Buffer.from([0x7f, 0x45, 0x4c, 0x46, 2, 1]).copy(elf); + elf.writeUInt16LE(3, 16); + elf.writeUInt16LE(62, 18); + const files = sqlFiles(); + for (const profile of ['postgresql', 'modules']) { + for (const module of ['fixture.so', 'fixture_deps.so']) + files.set(`lib/${profile}/${module}`, elf); + } + files.set('share/postgresql/contrib/fixture/install.sql', Buffer.from('SELECT 1;\n')); + await writeArchive(archive, files, facts); + expect(inspect(archive).dependency_modules).toEqual(['fixture_deps.so']); + files.delete('lib/modules/fixture_deps.so'); + await writeArchive(archive, files, facts); + expect(() => inspect(archive)).toThrow('required ABI'); + files.set('lib/modules/fixture_deps.so', Buffer.alloc(64)); + await writeArchive(archive, files, facts); + expect(() => inspect(archive)).toThrow('ELF x86_64'); + files.set('lib/modules/fixture_deps.so', elf); + files.delete('share/postgresql/contrib/fixture/install.sql'); + await writeArchive(archive, files, facts); + expect(() => inspect(archive)).toThrow('data resource'); +}); + +test('validator recognizes the upstream PostGIS upgrade template without creating a version edge', async () => { + const archive = join(temporary(), 'payload.tar.gz'); + const files = new Map([ + [`${sqlPrefix}postgis.control`, Buffer.from("default_version = '3.6.3'\n")], + [`${sqlPrefix}postgis--3.6.3.sql`, Buffer.from('SELECT 1;\n')], + [`${sqlPrefix}postgis--TEMPLATED--TO--ANY.sql`, Buffer.from('-- upstream upgrade template\n')], + ]); + await writeArchive(archive, files, descriptor({ sql_name: 'postgis', default_version: '3.6.3' })); + expect(inspect(archive).default_version).toBe('3.6.3'); + files.delete(`${sqlPrefix}postgis--3.6.3.sql`); + await writeArchive(archive, files, descriptor({ sql_name: 'postgis', default_version: '3.6.3' })); + expect(() => inspect(archive)).toThrow('not installable'); +}); + +test('validator checks control UTF-8/default version and SQL graph reachability through cycles', async () => { + const archive = join(temporary(), 'payload.tar.gz'); + const files = sqlFiles(); + files.delete(`${sqlPrefix}pgtap--1.3.5.sql`); + files.set(`${sqlPrefix}pgtap--1.3.3.sql`, Buffer.from('base')); + files.set(`${sqlPrefix}pgtap--1.3.3--1.3.4.sql`, Buffer.from('upgrade')); + files.set(`${sqlPrefix}pgtap--1.3.4--1.3.3.sql`, Buffer.from('cycle')); + await writeArchive(archive, files); + expect(() => inspect(archive)).toThrow('not installable'); + files.set(`${sqlPrefix}pgtap--1.3.4--1.3.5.sql`, Buffer.from('upgrade')); + await writeArchive(archive, files); + expect(inspect(archive).default_version).toBe('1.3.5'); + files.set(`${sqlPrefix}pgtap--a--b--c.sql`, Buffer.from('invalid')); + await writeArchive(archive, files); + expect(() => inspect(archive)).toThrow('SQL version path'); + files.delete(`${sqlPrefix}pgtap--a--b--c.sql`); + for (const control of [ + Buffer.from("default_version = 'other'\n"), + Buffer.from("\ufeffdefault_version = '1.3.5'\n"), + Buffer.from([0xff]), + ]) { + files.set(`${sqlPrefix}pgtap.control`, control); + await writeArchive(archive, files); + expect(() => inspect(archive)).toThrow(); + } + files.delete(`${sqlPrefix}pgtap.control`); + await writeArchive(archive, files); + expect(() => inspect(archive)).toThrow('required extension control'); + // PostgreSQL contrib versions have no required three-component spelling. + await writeArchive( + archive, + new Map([ + [`${sqlPrefix}pgtap.control`, Buffer.from("default_version = '1.6'\n")], + [`${sqlPrefix}pgtap--1.6.sql`, Buffer.from('base')], + ]), + descriptor({ default_version: '1.6' }), + ); + expect(inspect(archive).default_version).toBe('1.6'); +}); + +test('writer CLI fails closed on missing arguments and malformed UTF-8 or BOM specs', async () => { + const root = temporary(); + const script = fileURLToPath(new URL('./member_payload.mts', import.meta.url)); + expect(Bun.spawnSync([process.execPath, script], { stderr: 'pipe' }).exitCode).not.toBe(0); + for (const bytes of [ + Buffer.concat([ + Buffer.from('{"descriptor":{"note":"'), + Buffer.from([0xff]), + Buffer.from('"},"inputs":[]}'), + ]), + Buffer.concat([ + Buffer.from('\ufeff'), + Buffer.from(JSON.stringify({ descriptor: descriptor(), inputs: [] })), + ]), + ]) { + const spec = join(root, 'spec.json'); + await writeFile(spec, bytes); + const result = Bun.spawnSync( + [ + process.execPath, + script, + '--spec', + spec, + '--output', + join(root, 'out.tar.gz'), + '--inventory', + join(root, 'out.json'), + ], + { stderr: 'pipe' }, + ); + expect(result.exitCode).not.toBe(0); + } + expect(() => readFileSync(join(root, 'out.tar.gz'))).toThrow(); +}); diff --git a/build_defs/extensions/mobile.bzl b/build_defs/extensions/mobile.bzl new file mode 100644 index 000000000..0d6bfd588 --- /dev/null +++ b/build_defs/extensions/mobile.bzl @@ -0,0 +1,150 @@ +"""Actual target static archives; desktop producers retain their existing graph.""" + +load("@oliphaunt_metadata//:metadata.bzl", "EXTENSIONS", "EXTENSION_COMPATIBILITY", "EXTENSION_SOURCES", "NATIVE_COMPONENTS", "NATIVE_MOBILE_MEMBER_ALIASES", "POSTGRES_SOURCE") +load("@rules_cc//cc:cc_static_library.bzl", "cc_static_library") +load("@rules_cc//cc:defs.bzl", "cc_import", "cc_library") +load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain", "use_cc_toolchain") +load("@rules_cc//cc/common:cc_common.bzl", "cc_common") +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") +load("//build_defs/native:platform_config.bzl", "NATIVE_COPTS") +load(":extensions.bzl", "extension_identity") +load(":native_carriers.bzl", "native_extension_carrier_helpers") +load("//build_defs/release:identity.bzl", "ReleaseIdentityInfo") + +# macOS is the real third slice of the public extension XCFramework. It does +# not widen the ordinary desktop extension member/profile guard. +_STATIC_PROFILES = { + "//build_defs/native:android_arm64": "android-arm64-v8a", + "//build_defs/native:android_x86_64": "android-x86_64", + "//build_defs/native:ios_arm64": "ios-device", + "//build_defs/native:ios_arm64_simulator": "ios-simulator", + "//build_defs/native:macos_arm64": "macos-arm64", +} +MOBILE_EXTENSION_CONFIGURATION = select(_STATIC_PROFILES, no_match_error = "Static extension construction requires a declared Android or Apple slice.") +MOBILE_EXTENSION_COMPATIBLE = select({condition: [] for condition in _STATIC_PROFILES} | {"//conditions:default": ["@platforms//:incompatible"]}) +_APPLE = ["//build_defs/native:ios_arm64", "//build_defs/native:ios_arm64_simulator", "//build_defs/native:macos_arm64"] + +MobileExtensionInfo = provider(fields = ["sql_name", "stem", "owner", "version", "runtime_version", "configuration", "source", "archive", "registration", "nm", "tools", "apple", "aliases"]) +MobileComponentInfo = provider(fields = ["identity", "configuration", "source", "archive"]) + +def _descriptor(sql_name): + rows = [row for row in EXTENSIONS.values() if row["sql-name"] == sql_name] + if len(rows) != 1: + fail("static member requires exactly one canonical SQL descriptor") + return rows[0] + +def _own_objects_impl(ctx): + infos = [] + inputs = [] + for root in ctx.attr.roots: + infos.append(root[CcInfo]) + owned = [item for item in root[CcInfo].linking_context.linker_inputs.to_list() if item.owner == root.label] + if not owned or not any([library.objects or library.pic_objects for item in owned for library in item.libraries]): + fail("static archive requires actual objects owned by its explicit root " + str(root.label)) + inputs += owned + return [CcInfo( + compilation_context = cc_common.merge_cc_infos(cc_infos = infos).compilation_context, + linking_context = cc_common.create_linking_context(linker_inputs = depset(inputs, order = "topological")), + )] + +_own_objects = rule(implementation = _own_objects_impl, attrs = {"roots": attr.label_list(mandatory = True, providers = [CcInfo])}) + +def mobile_static_archive(name, roots, **kwargs): + """Keep separately declared component/runtime objects out of this archive.""" + _own_objects(name = name + "_own_objects", roots = roots, **kwargs) + cc_static_library(name = name, deps = [":" + name + "_own_objects"], **kwargs) + +def _member_impl(ctx): + descriptor = _descriptor(ctx.attr.sql_name) + stem = descriptor.get("native-module-file", "") + if not stem.endswith(".so") or stem[:-3] != ctx.attr.stem: + fail("static member stem differs from the canonical compiled member") + identity = ctx.attr.owner[ReleaseIdentityInfo] + if str(ctx.attr.owner.label) != str(Label(extension_identity(ctx.attr.sql_name))): + fail("static member owner differs from its canonical release product") + if ctx.file.archive.basename != "liboliphaunt_extension_" + ctx.attr.stem + ".a": + fail("static member archive differs from its canonical basename") + source = POSTGRES_SOURCE if descriptor["source-kind"] == "postgres-contrib" else EXTENSION_SOURCES[ctx.attr.sql_name] + symbols = ctx.actions.declare_file(ctx.label.name + ".symbols.txt") + toolchain = find_cc_toolchain(ctx) + registration = ctx.actions.declare_file(ctx.label.name + ".registration.json") + unit = ctx.actions.declare_file(ctx.label.name + ".registry.c") + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode({"sqlName": ctx.attr.sql_name, "stem": ctx.attr.stem, "apple": ctx.attr.apple, "aliases": [{"name": name, "address": address} for name, address in ctx.attr.aliases.items()], + "nm": ctx.file.nm.path, "archive": ctx.file.archive.path, "symbols": symbols.path, "registration": registration.path, "source": unit.path})) + bun_file_action(ctx, ctx.file._registration, source_files = [ctx.file._registration] + ctx.files._helpers, + arguments = [spec.path], inputs = depset([spec, ctx.file.archive, ctx.file.nm] + ctx.files.nm_runtime, transitive = [toolchain.all_files]), outputs = [symbols, registration, unit], execution_requirements = {"no-remote": "1"} if ctx.attr.apple else {}, mnemonic = "MobileExtensionRegistration") + return [DefaultInfo(files = depset([ctx.file.archive, registration])), + OutputGroupInfo(archive = depset([ctx.file.archive]), registration = depset([registration]), registry_source = depset([unit])), + MobileExtensionInfo(sql_name = ctx.attr.sql_name, stem = ctx.attr.stem, owner = identity.id, version = identity.version, + runtime_version = identity.version if descriptor["source-kind"] == "postgres-contrib" else EXTENSION_COMPATIBILITY[ctx.attr.sql_name]["native_runtime_version"], configuration = ctx.attr.configuration, source = source, archive = ctx.file.archive, registration = registration, + nm = ctx.file.nm, tools = depset([ctx.file.nm] + ctx.files.nm_runtime, transitive = [toolchain.all_files]), apple = ctx.attr.apple, aliases = ctx.attr.aliases)] + +def _component_impl(ctx): + units = [unit for component in NATIVE_COMPONENTS["components"] for unit in component["link-units"] if unit["id"] == ctx.attr.identity] + if len(units) != 1 or ctx.file.archive.basename not in [path.split("/")[-1] for path in units[0]["archive-candidates"]]: + fail("static component archive differs from its canonical link unit") + return [DefaultInfo(files = depset([ctx.file.archive])), MobileComponentInfo(identity = ctx.attr.identity, configuration = ctx.attr.configuration, source = json.decode(ctx.attr.source), archive = ctx.file.archive)] + +_component = rule(implementation = _component_impl, attrs = {"identity": attr.string(mandatory = True), "configuration": attr.string(mandatory = True), "source": attr.string(mandatory = True), "archive": attr.label(mandatory = True, allow_single_file = [".a"])}) + +def mobile_static_component(name, identity, archive, source): + _component(name = name, identity = identity, archive = archive, source = json.encode(source), configuration = MOBILE_EXTENSION_CONFIGURATION, target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) + +_REGISTRATION_HELPERS = native_extension_carrier_helpers() + ["//:src/extensions/artifacts/native/tools/ios-extension-registration.mts"] + +_member = rule(implementation = _member_impl, toolchains = use_cc_toolchain() + BUN_SOURCE_TOOLCHAINS, + attrs = {"sql_name": attr.string(mandatory = True), "stem": attr.string(mandatory = True), + "owner": attr.label(mandatory = True, providers = [ReleaseIdentityInfo]), + "configuration": attr.string(mandatory = True), "archive": attr.label(mandatory = True, allow_single_file = [".a"]), + "apple": attr.bool(), "aliases": attr.string_dict(), "nm": attr.label(mandatory = True, allow_single_file = True, cfg = "exec"), + "nm_runtime": attr.label_list(allow_files = True, cfg = "exec"), + "_registration": attr.label(default = "//build_defs/extensions:mobile_registration.mts", allow_single_file = True), + "_helpers": attr.label_list(default = _REGISTRATION_HELPERS, allow_files = True)}, fragments = ["cpp"]) + +def native_mobile_extension(name, sql_name, srcs, hdrs = [], deps = [], copts = [], includes = [], defines = [], linkopts = [], object_roots = [], consumer_deps = None): + """Compile the existing units with the static hook namespace and target SDK.""" + descriptor = _descriptor(sql_name) + stem = descriptor.get("native-module-file", "") + if not stem.endswith(".so"): + fail("SQL-only members do not have a static compiler target") + stem = stem[:-3] + aliases = NATIVE_MOBILE_MEMBER_ALIASES[sql_name] + prefix = "oliphaunt_static_" + stem.replace("-", "_") + local_defines = ["Pg_magic_func=" + prefix + "_Pg_magic_func", "_PG_init=" + prefix + "__PG_init"] + local_defines += [key + "=" + value for key, value in aliases.items()] + cc_library(name = name + "_objects", srcs = srcs, hdrs = hdrs, + deps = ["//src/native/runtime:postgres_embedded_headers"] + deps, includes = includes, defines = defines, + local_defines = local_defines, copts = copts + NATIVE_COPTS + ["-g0"], alwayslink = True, + target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) + archive = "oliphaunt_extension_" + stem + mobile_static_archive(name = archive, roots = [":" + name + "_objects"] + object_roots, target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) + _member(name = name, sql_name = sql_name, stem = stem, owner = extension_identity(sql_name), configuration = MOBILE_EXTENSION_CONFIGURATION, + archive = ":" + archive, aliases = aliases, + apple = select({condition: True for condition in _APPLE} | {"//conditions:default": False}), + nm = select({condition: "@native_apple_sdk//:tools/nm_files" for condition in _APPLE} | {"//conditions:default": "@android_ndk//:nm"}), + nm_runtime = select({condition: ["@native_apple_sdk//:toolchain_files"] for condition in _APPLE} | {"//conditions:default": []}), + target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) + cc_import(name = name + "_import", static_library = ":" + archive, alwayslink = True, target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) + cc_library(name = name + "_library", deps = [":" + name + "_import"] + (deps if consumer_deps == None else consumer_deps), linkopts = linkopts, target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) + +def _registry_impl(ctx): + members = [target[MobileExtensionInfo] for target in ctx.attr.members] + names = sorted([member.sql_name for member in members]) + if names != sorted(ctx.attr.sql_names) or len(names) != len({name: True for name in names}): + fail("static registry must include every selected actual member once") + if len({member.configuration: True for member in members}) != 1: + fail("static registry cannot mix target configurations") + output = ctx.actions.declare_file(ctx.label.name + ".c") + specification = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(specification, json.encode({"registrations": [member.registration.path for member in members], "source": output.path})) + bun_file_action(ctx, ctx.file._registration, arguments = [specification.path], + source_files = [ctx.file._registration] + ctx.files._helpers, + inputs = [specification] + [member.registration for member in members], outputs = [output], mnemonic = "MobileExtensionCombinedRegistry") + return [DefaultInfo(files = depset([output]))] + +mobile_extension_registry = rule(implementation = _registry_impl, toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = {"members": attr.label_list(mandatory = True, providers = [MobileExtensionInfo]), "sql_names": attr.string_list(mandatory = True), + "_registration": attr.label(default = "//build_defs/extensions:mobile_registration.mts", allow_single_file = True), + "_helpers": attr.label_list(default = _REGISTRATION_HELPERS, allow_files = True)}) diff --git a/build_defs/extensions/mobile/BUILD.bazel b/build_defs/extensions/mobile/BUILD.bazel new file mode 100644 index 000000000..5df0e89e3 --- /dev/null +++ b/build_defs/extensions/mobile/BUILD.bazel @@ -0,0 +1,27 @@ +load("@rules_cc//cc:defs.bzl", "cc_binary") +load("//build_defs/extensions:mobile.bzl", "MOBILE_EXTENSION_COMPATIBLE", "mobile_extension_registry") +load("//build_defs/extensions:mobile_members.bzl", "MOBILE_MEMBER_LIBRARIES", "MOBILE_MEMBER_TARGETS", "mobile_extension_members") +load("//build_defs/android:toolchain.bzl", "android_artifact") + +package(default_visibility = ["//visibility:public"]) + +mobile_extension_members() + +mobile_extension_registry(name = "pg_uuidv7_registry", members = [MOBILE_MEMBER_TARGETS["pg_uuidv7"]], sql_names = ["pg_uuidv7"], + target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) +mobile_extension_registry(name = "all_members_registry", members = MOBILE_MEMBER_TARGETS.values(), sql_names = MOBILE_MEMBER_TARGETS.keys(), + target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) + +cc_binary(name = "pg_uuidv7_consumer", srcs = ["//build_defs/extensions:mobile_consumer.c", ":pg_uuidv7_registry"], + deps = [MOBILE_MEMBER_LIBRARIES["pg_uuidv7"]] + + select({"@platforms//os:ios": ["//src/native/runtime:mobile_static"], "//conditions:default": ["//src/native/runtime:liboliphaunt"]}), + copts = ["-std=gnu11", "-g0"], target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) +cc_binary(name = "all_members_consumer", srcs = ["//build_defs/extensions:mobile_consumer.c", ":all_members_registry"], + deps = MOBILE_MEMBER_LIBRARIES.values() + + select({"@platforms//os:ios": ["//src/native/runtime:mobile_static"], "//conditions:default": ["//src/native/runtime:liboliphaunt"]}), + copts = ["-std=gnu11", "-g0"], target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) + +[android_artifact(name = "android_" + architecture + "_" + group, artifact = ":" + group, + platform = "//build_defs/android:android_" + architecture, + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"]) + for architecture in ["arm64", "x86_64"] for group in ["compiled_members", "pg_uuidv7_consumer", "all_members_consumer"]] diff --git a/build_defs/extensions/mobile/final/BUILD.bazel b/build_defs/extensions/mobile/final/BUILD.bazel new file mode 100644 index 000000000..b212df00a --- /dev/null +++ b/build_defs/extensions/mobile/final/BUILD.bazel @@ -0,0 +1,5 @@ +load("//build_defs/extensions:mobile_carriers.bzl", "mobile_final_carrier_targets") + +package(default_visibility = ["//visibility:public"]) + +mobile_final_carrier_targets() diff --git a/build_defs/extensions/mobile_carriers.bzl b/build_defs/extensions/mobile_carriers.bzl new file mode 100644 index 000000000..72486fbaa --- /dev/null +++ b/build_defs/extensions/mobile_carriers.bzl @@ -0,0 +1,248 @@ +"""Canonical mobile final leaves from actual host modules and static SDK slices.""" + +load("@oliphaunt_metadata//:metadata.bzl", "EXTENSIONS", "EXTENSION_GITHUB_ARTIFACTS", "EXTENSION_RELEASE_METADATA", "NATIVE_COMPONENT_SOURCES", "NATIVE_MOBILE_COMPONENT_CLOSURES", "PUBLICATION_CARRIERS") +load("@oliphaunt_toolchain_metadata//:apple-platforms.bzl", "APPLE_DEPLOYMENT_TARGETS") +load("@rules_apple//apple:apple.bzl", "apple_static_xcframework") +load("//build_defs/apple:slices.bzl", "apple_slice_filegroup", "apple_slice_groups") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") +load("//build_defs/release:supplier.bzl", "ShippingSupplierInfo", "merge_shipping_suppliers") +load(":construction.bzl", "desktop_member_inventory") +load(":extensions.bzl", "ExtensionMemberInfo", "extension_identity") +load(":final_leaf.bzl", "ExtensionFinalLeafInfo") +load(":mobile.bzl", "MobileComponentInfo", "MobileExtensionInfo") +load(":mobile_members.bzl", "MOBILE_COMPONENT_ARCHIVE_OBJECTS", "MOBILE_COMPONENT_TARGETS", "MOBILE_MEMBER_ARCHIVE_OBJECTS", "MOBILE_MEMBER_TARGETS") +load(":owner_carriers.bzl", "native_extension_final_contract_test", "native_final_leaf_files", "native_final_leaf_input", "native_owner_carrier_helpers", "native_owner_carrier_legal", "native_owner_carrier_metadata") + +_TARGET_PLATFORMS = {"android-arm64-v8a": "//build_defs/android:android_arm64", "android-x86_64": "//build_defs/android:android_x86_64", "macos-arm64": "//build_defs/host:apple_package_macos_arm64", "ios-device": "//build_defs/host:ios_device_arm64", "ios-simulator": "//build_defs/host:ios_simulator_arm64"} +_TARGETS = ["android-arm64-v8a", "android-x86_64", "ios-xcframework"] +_MAC = ["@platforms//os:macos", "@platforms//cpu:aarch64"] +_LINUX = ["@platforms//os:linux", "@platforms//cpu:x86_64"] + +def _slices_impl(settings, attr): + targets = ["macos-arm64", "ios-device", "ios-simulator"] if attr.target == "ios-xcframework" else [attr.target] + return {target: {"//command_line_option:platforms": [str(Label(_TARGET_PLATFORMS[target]))]} for target in targets} + +_slices = transition(implementation = _slices_impl, inputs = [], outputs = ["//command_line_option:platforms"]) + +def _host_impl(settings, attr): + # Reused desktop dylibs retain the direct carrier contract, unlike XCFramework slices. + target = "//build_defs/host:native_macos_arm64" if attr.target == "ios-xcframework" else "//build_defs/native:linux_x86_64_glibc_2_28" + return {"//command_line_option:platforms": [str(Label(target))]} + +mobile_host_transition = transition(implementation = _host_impl, inputs = [], outputs = ["//command_line_option:platforms"]) + +_MACOS_PROFILE = "@apple_support//platforms:macos_arm64_platform" +def _apple_package_impl(settings, attr): + return {_MACOS_PROFILE: str(Label("//build_defs/host:apple_package_macos_arm64"))} + +_apple_package = transition(implementation = _apple_package_impl, inputs = [], outputs = [_MACOS_PROFILE]) + +def _framework_impl(ctx): + archive = ctx.attr.archive[0] + return [archive[DefaultInfo], OutputGroupInfo(**apple_slice_groups([archive]))] + +_framework = rule(implementation = _framework_impl, attrs = {"archive": attr.label(mandatory = True, cfg = _apple_package), "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist")}) + +def mobile_carrier_helpers(): + return native_owner_carrier_helpers() + ["//build_defs/extensions:mobile_registration.mts", "//src/native/sdks/swift:tools/swift-xcframework-contract.mts"] + +def _static_row(member): + return {"sqlName": member.sql_name, "owner": member.owner, "version": member.version, "runtimeVersion": member.runtime_version, "source": member.source, + "target": member.configuration, "archive": member.archive.path, "registration": member.registration.path, "nm": {"path": member.nm.path, "apple": member.apple}, "aliases": member.aliases} + +def _carriers_impl(ctx): + metadata = native_owner_carrier_metadata(ctx.attr.product) + expected = sorted([member["sqlName"] for member in metadata["members"]]) + host_members = ctx.split_attr.host.values()[0] + host = {target[ExtensionMemberInfo].sql_name: target[ExtensionMemberInfo] for target in host_members} + if sorted(host.keys()) != expected or len(host) != len(host_members): + fail("mobile final leaf must consume every canonical host member exactly once") + compiled = sorted([member["sqlName"] for member in metadata["members"] if member["descriptor"].get("native-module-file")]) + statics = {target: {member[MobileExtensionInfo].sql_name: member[MobileExtensionInfo] for member in members} for target, members in ctx.split_attr.members.items()} + dependencies = {target: {item[MobileComponentInfo].identity: item[MobileComponentInfo] for item in rows} for target, rows in ctx.split_attr.dependencies.items()} + inputs = [ctx.file._components] + ctx.files.legal + slice_files = {target: [] for target in (statics | dependencies)} if ctx.attr.target == "ios-xcframework" else {} + tools = [] + for target, rows in statics.items(): + if sorted(rows.keys()) != compiled or len(rows) != len(ctx.split_attr.members[target]): + fail("mobile static slice differs from canonical compiled member cohort") + for member in rows.values(): + inputs += [member.archive, member.registration] + if target in slice_files: + slice_files[target].append(member.archive) + tools.append(member.tools) + dependency_ids = sorted({identity: True for name in expected for identity in NATIVE_MOBILE_COMPONENT_CLOSURES[name][ctx.attr.target]["linkUnits"]}.keys()) + for target, rows in dependencies.items(): + if sorted(rows.keys()) != dependency_ids or len(rows) != len(ctx.split_attr.dependencies[target]): + fail("mobile component slice differs from canonical member closure") + for component in rows.values(): + inputs.append(component.archive) + if target in slice_files: + slice_files[target].append(component.archive) + frameworks = {} + for target, identity in ctx.attr.frameworks.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1 or not files[0].basename.endswith(".xcframework.zip") or identity in frameworks: + fail("iOS envelope requires one actual maintained framework output per role") + frameworks[identity] = files[0] + inputs += files + members = [] + for canonical in metadata["members"]: + name = canonical["sqlName"] + member = dict(canonical) + producer = host[name] + host_target = "macos-arm64" if ctx.attr.target == "ios-xcframework" else "linux-x64-gnu" + if producer.owner != metadata["owner"] or producer.configuration != host_target: + fail("mobile host member differs from its actual owner/configuration") + inputs += [producer.archive, producer.inventory] + if ctx.attr.target == "ios-xcframework": + slice_files.setdefault("macos-arm64", []).append(producer.archive) + member.update({"target": ctx.attr.target, "hostArchive": producer.archive.path, "components": ctx.file._components.path, + "catalogSqlNames": metadata["catalogSqlNames"], "allProfiles": metadata["allProfiles"], "dependencySources": NATIVE_COMPONENT_SOURCES, + "staticArchives": [_static_row(rows[name]) for rows in statics.values()] if name in compiled else [], + "dependencyArchives": [{"target": cohort, "identity": identity, "archive": rows[identity].archive.path, "source": rows[identity].source} for cohort, rows in dependencies.items() for identity in NATIVE_MOBILE_COMPONENT_CLOSURES[name][ctx.attr.target]["linkUnits"]], "frameworks": []}) + if ctx.attr.target == "ios-xcframework" and name in compiled: + stem = canonical["descriptor"]["native-module-file"][:-3] + member["frameworks"] = [{"kind": "ios-xcframework", "identity": stem, "file": frameworks["extension:" + name].path, "bundleName": "liboliphaunt_extension_" + stem}] + member["frameworks"] += [{"kind": "ios-dependency-xcframework", "identity": identity, "file": frameworks["dependency:" + identity].path, "bundleName": "liboliphaunt_dependency_" + identity} for identity in NATIVE_MOBILE_COMPONENT_CLOSURES[name][ctx.attr.target]["linkUnits"]] + members.append(member) + github = ctx.actions.declare_directory(ctx.label.name + "/github") + frozen = ctx.actions.declare_file(ctx.label.name + "/extension-artifacts.json") + manifest = ctx.actions.declare_file(ctx.label.name + "/" + metadata["product"] + "-" + metadata["version"] + "-manifest.json") + specification = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + spec = dict(metadata) + spec.update({"operation": "package", "target": ctx.attr.target, "expectedMembers": expected, "members": members, "outputs": {"github": github.path, "frozen": frozen.path, "manifest": manifest.path}}) + ctx.actions.write(specification, json.encode(spec)) + bun_file_action(ctx, ctx.file._tool, arguments = [specification.path], inputs = depset(inputs + [specification], transitive = tools), source_files = [ctx.file._tool] + ctx.files._helpers + ctx.files.legal, + outputs = [github, frozen, manifest], execution_requirements = {"no-remote": "1"} if ctx.attr.target == "ios-xcframework" else {}, mnemonic = "MobileExtensionFinalEnvelopes") + slice_groups = apple_slice_groups(ctx.attr.frameworks.keys()) + for target, files in slice_files.items(): + name = "apple_slice_" + {"macos-arm64": "macos-arm64", "ios-device": "ios-arm64", "ios-simulator": "ios-arm64-simulator"}[target] + slice_groups[name] = depset(files, transitive = [slice_groups[name]] if name in slice_groups else []) + suppliers = merge_shipping_suppliers([target[ShippingSupplierInfo] for target in host_members]) + return [DefaultInfo(files = depset([github, frozen, manifest])), suppliers, ExtensionFinalLeafInfo(product = metadata["product"], owner = metadata["owner"], version = metadata["version"], family = "native", target = ctx.attr.target, metadata = spec, + github = [github], npm = [], cargo = [], manifest = manifest, frozen = frozen, spec = specification, validation = None, receipt = None, origin = None), + OutputGroupInfo(github = depset([github]), manifest = depset([manifest]), frozen = depset([frozen]), spec = depset([specification]), **slice_groups)] + +_mobile_carriers = rule(implementation = _carriers_impl, toolchains = BUN_SOURCE_TOOLCHAINS, attrs = { + "product": attr.string(mandatory = True), "target": attr.string(mandatory = True, values = _TARGETS), "host": attr.label_list(mandatory = True, providers = [ExtensionMemberInfo, ShippingSupplierInfo], cfg = mobile_host_transition), + "members": attr.label_list(providers = [MobileExtensionInfo], cfg = _slices), "dependencies": attr.label_list(providers = [MobileComponentInfo], cfg = _slices), "frameworks": attr.label_keyed_string_dict(allow_files = True), "legal": attr.label_list(allow_files = True), + "_tool": attr.label(default = "//build_defs/extensions:mobile_carriers.mts", allow_single_file = True), "_helpers": attr.label_list(default = mobile_carrier_helpers(), allow_files = True), "_components": attr.label(default = "//src/extensions/catalog:native-components.toml", allow_single_file = True), "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), +}) + +def mobile_native_carriers(name, product, target, frameworks = {}): + metadata = native_owner_carrier_metadata(product) + names = [member["sqlName"] for member in metadata["members"]] + hosts = {row.name: row.label for row in desktop_member_inventory(include_postgis = True)} + units = sorted({identity: True for sql_name in names for identity in NATIVE_MOBILE_COMPONENT_CLOSURES[sql_name][target]["linkUnits"]}.keys()) + compatible = _MAC if target == "ios-xcframework" else _LINUX + _mobile_carriers(name = name, product = product, target = target, host = [hosts[sql_name] for sql_name in names], members = [MOBILE_MEMBER_TARGETS[sql_name] for sql_name in names if sql_name in MOBILE_MEMBER_TARGETS], + dependencies = [MOBILE_COMPONENT_TARGETS[identity] for identity in units], frameworks = frameworks, legal = native_owner_carrier_legal(product), target_compatible_with = compatible) + owner = extension_identity(names[0]) + packages = [] + github_files = name + "_github_files" + apple_slice_filegroup(name = github_files, src = ":" + name, output_group = "github", target_compatible_with = compatible) + github_rows = [row for row in EXTENSION_GITHUB_ARTIFACTS if row["artifactProduct"] == product and row["product"] == metadata["owner"] and row["version"] == metadata["version"] and row["target"] == target and row["role"] == "github-release-asset"] + if not github_rows or len({row["name"]: True for row in github_rows}) != len(github_rows): + fail("mobile shipping requires exact unique canonical GitHub asset identities") + for index, row in enumerate(github_rows): + package = name + "_github_" + str(index) + "_shipping" + shipping_package(name = package, owner = owner, artifacts = [":" + github_files], ecosystem = "github", package_name = row["name"], + configuration = row["target"], role = row["role"], suppliers = ":" + name, target_compatible_with = compatible) + packages.append(":" + package) + for group in ["manifest", "frozen"]: + files = name + "_" + group + "_files" + apple_slice_filegroup(name = files, src = ":" + name, output_group = group, target_compatible_with = compatible) + package = name + "_" + group + "_shipping" + shipping_package(name = package, owner = owner, artifacts = [":" + files], ecosystem = "internal", package_name = product + "-" + target + "-" + group, + configuration = target, role = "extension-release-" + group + "-input", suppliers = ":" + name, target_compatible_with = compatible) + packages.append(":" + package) + shipping_export(name = name + "_shipping_export", packages = packages, target_compatible_with = compatible) + return packages + +def _maven_rows(metadata): + return [row for row in PUBLICATION_CARRIERS if row["product"] == metadata["owner"] and row["ecosystem"] == "maven" and row["name"].startswith("dev.oliphaunt.extensions:" + metadata["product"] + "-")] + +def _maven_impl(ctx): + metadata = native_owner_carrier_metadata(ctx.attr.product) + leaves = [target[ExtensionFinalLeafInfo] for target in ctx.attr.leaves] + if sorted([leaf.target for leaf in leaves]) != ["android-arm64-v8a", "android-x86_64"]: + fail("Maven must consume both actual Android final cohorts once") + if any([leaf.product != metadata["product"] or leaf.owner != metadata["owner"] or leaf.version != metadata["version"] or leaf.family != "native" for leaf in leaves]): + fail("Maven final leaves differ from their canonical distribution") + rows = _maven_rows(metadata) + if len(rows) != 2 or len({row["name"]: True for row in rows}) != 2: + fail("Maven requires both unique canonical publication identities") + outputs = {row["name"]: ctx.actions.declare_directory(ctx.label.name + "/" + row["name"].replace(":", "/")) for row in rows} + spec = dict(metadata) + spec.update({"leaves": [native_final_leaf_input(leaf) for leaf in leaves], "components": ctx.file._components.path, "mavenCoordinates": sorted(outputs.keys()), "outputs": {name: file.path for name, file in outputs.items()}}) + specification = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(specification, json.encode(spec)) + bun_file_action(ctx, ctx.file._tool, arguments = [specification.path], source_files = [ctx.file._tool] + ctx.files._helpers + ctx.files.legal, + inputs = [specification, ctx.file._components] + [file for leaf in leaves for file in native_final_leaf_files(leaf)] + ctx.files.legal, + outputs = outputs.values(), mnemonic = "MobileExtensionMavenEnvelopes") + suppliers = merge_shipping_suppliers([target[ShippingSupplierInfo] for target in ctx.attr.leaves]) + return [DefaultInfo(files = depset(outputs.values())), suppliers, OutputGroupInfo(**{row["name"].split(":")[1].replace("-", "_"): depset([outputs[row["name"]]]) for row in rows})] + +_mobile_maven = rule(implementation = _maven_impl, toolchains = BUN_SOURCE_TOOLCHAINS, attrs = { + "product": attr.string(mandatory = True), "leaves": attr.label_list(mandatory = True, providers = [ExtensionFinalLeafInfo, ShippingSupplierInfo]), "legal": attr.label_list(allow_files = True), + "_tool": attr.label(default = "//build_defs/extensions:mobile_maven.mts", allow_single_file = True), "_components": attr.label(default = "//src/extensions/catalog:native-components.toml", allow_single_file = True), + "_helpers": attr.label_list(default = mobile_carrier_helpers() + ["//build_defs/extensions:owner_carriers.mts", "//:tools/packaging/build-maven-artifact-manifest.mts", "//:tools/packaging/maven-artifact-manifest.mts", "//:tools/packaging/maven-artifact-staging.mts", "//:tools/packaging/maven-central-contract.mts", "//:tools/packaging/atomic-directory.mts", "//tools/release:compatibility-version-policy.mts", "//tools/release:product-version.mts"], allow_files = True), +}) + +def mobile_maven_carriers(name, product, leaves): + metadata = native_owner_carrier_metadata(product) + _mobile_maven(name = name, product = product, leaves = leaves, legal = native_owner_carrier_legal(product), target_compatible_with = _LINUX) + packages = [] + target_packages = {"android-arm64-v8a": [], "android-x86_64": []} + for row in _maven_rows(metadata): + group = row["name"].split(":")[1].replace("-", "_") + files = name + "_" + group + "_files" + native.filegroup(name = files, srcs = [":" + name], output_group = group, target_compatible_with = _LINUX) + package = name + "_" + group + "_shipping" + shipping_package(name = package, owner = extension_identity(metadata["members"][0]["sqlName"]), artifacts = [":" + files], ecosystem = "maven", package_name = row["name"], configuration = row["target"] or "android", role = row["role"], suppliers = ":" + name, target_compatible_with = _LINUX) + packages.append(":" + package) + if row["target"] not in target_packages: + fail("mobile Maven identity must declare its exact Android ABI") + target_packages[row["target"]].append(":" + package) + shipping_export(name = name + "_shipping_export", packages = packages, target_compatible_with = _LINUX) + return target_packages + +def mobile_final_carrier_targets(): + frameworks = {} + descriptors = {row["sql-name"]: row for row in EXTENSIONS.values()} + for identity, objects in MOBILE_MEMBER_ARCHIVE_OBJECTS.items(): + name = "framework_extension_" + identity.replace("-", "_") + bundle = "liboliphaunt_extension_" + descriptors[identity]["native-module-file"][:-3] + apple_static_xcframework(name = name + "_raw", bundle_name = bundle, deps = [objects], ios = {"device": ["arm64"], "simulator": ["arm64"]}, macos = ["arm64"], families_required = {"ios": ["iphone"]}, minimum_os_versions = {"macos": APPLE_DEPLOYMENT_TARGETS["package_macos"], "ios": APPLE_DEPLOYMENT_TARGETS["ios"]}, tags = ["no-remote"], target_compatible_with = _MAC) + _framework(name = name, archive = ":" + name + "_raw", target_compatible_with = _MAC) + frameworks[":" + name] = "extension:" + identity + for identity, objects in MOBILE_COMPONENT_ARCHIVE_OBJECTS.items(): + name = "framework_dependency_" + identity.replace("-", "_") + apple_static_xcframework(name = name + "_raw", bundle_name = "liboliphaunt_dependency_" + identity, deps = [objects], ios = {"device": ["arm64"], "simulator": ["arm64"]}, macos = ["arm64"], families_required = {"ios": ["iphone"]}, minimum_os_versions = {"macos": APPLE_DEPLOYMENT_TARGETS["package_macos"], "ios": APPLE_DEPLOYMENT_TARGETS["ios"]}, tags = ["no-remote"], target_compatible_with = _MAC) + _framework(name = name, archive = ":" + name + "_raw", target_compatible_with = _MAC) + frameworks[":" + name] = "dependency:" + identity + products = sorted({row["artifactProduct"]: True for row in EXTENSION_RELEASE_METADATA}.keys()) + packages = {target: [] for target in _TARGETS} + for product in products: + metadata = native_owner_carrier_metadata(product) + names = [member["sqlName"] for member in metadata["members"]] + units = {unit: True for name in names for unit in NATIVE_MOBILE_COMPONENT_CLOSURES[name]["ios-xcframework"]["linkUnits"]} + selected_frameworks = {label: role for label, role in frameworks.items() if (role.startswith("extension:") and role[len("extension:"):] in names) or (role.startswith("dependency:") and role[len("dependency:"):] in units)} + for target in _TARGETS: + packages[target] += mobile_native_carriers(name = product.replace("-", "_") + "_" + target.replace("-", "_"), product = product, target = target, frameworks = selected_frameworks if target == "ios-xcframework" else {}) + maven = mobile_maven_carriers(name = product.replace("-", "_") + "_maven", product = product, leaves = [":" + product.replace("-", "_") + "_" + target.replace("-", "_") for target in _TARGETS if target.startswith("android-")]) + for target, rows in maven.items(): + packages[target] += rows + for target in _TARGETS: + suffix = target.replace("-", "_") + compatible = _MAC if target == "ios-xcframework" else _LINUX + shipping_export(name = suffix + "_shipping_export", packages = packages[target], qualification = [":" + suffix + "_final_contract_test"], testonly = True, target_compatible_with = compatible) + native_extension_final_contract_test(name = suffix + "_final_contract_test", products = products, + leaves = [":" + product.replace("-", "_") + "_" + suffix for product in products], target_compatible_with = compatible, size = "medium") + selected = sorted({row["artifactProduct"]: True for row in EXTENSION_RELEASE_METADATA if row["sqlName"] in ["pg_uuidv7", "pgtap"]}.keys()) + native_extension_final_contract_test(name = suffix + "_small_final_contract_test", products = selected, + leaves = [":" + product.replace("-", "_") + "_" + suffix for product in selected], target_compatible_with = compatible, size = "medium") + shipping_export(name = "android_shipping_export", packages = {label: True for target in _TARGETS if target.startswith("android-") for label in packages[target]}.keys(), qualification = [":" + target.replace("-", "_") + "_final_contract_test" for target in _TARGETS if target.startswith("android-")], testonly = True, target_compatible_with = _LINUX) + native.filegroup(name = "android_maven_carriers", srcs = [":" + product.replace("-", "_") + "_maven" for product in products], target_compatible_with = _LINUX) diff --git a/build_defs/extensions/mobile_carriers.mts b/build_defs/extensions/mobile_carriers.mts new file mode 100644 index 000000000..dbb2906fa --- /dev/null +++ b/build_defs/extensions/mobile_carriers.mts @@ -0,0 +1,496 @@ +/** Public mobile member envelopes from declared host and target producers. */ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + copyFileSync, + mkdirSync, + mkdtempSync, + readFileSync, + realpathSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + composeExtensionReleaseDocuments, + nativeAssetNameForRow, +} from '../../src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts'; +import { bundleCarrierAssets } from '../../src/extensions/artifacts/packages/tools/bundle-carrier-assets.mts'; +import { + EXTENSION_ARTIFACT_PROPERTY_KEYS, + nativeModuleHostTarget, + validateExtensionArtifactArchive, +} from '../../src/extensions/artifacts/packages/tools/extension-artifact-inventory.mts'; +import { + extensionCarrierLegalContract, + stageExtensionUpstreamLicenses, +} from '../../src/extensions/tools/extension-upstream-licenses.mts'; +import { + resolveNativeComponentClosure, + validateNativeComponentContract, +} from '../../src/extensions/tools/native-component-contract.mts'; +import { validateAppleXcframeworkAsset } from '../../src/native/sdks/swift/tools/swift-xcframework-contract.mts'; +import { inspectPlatformBinaryEntries } from '../../tools/packaging/platform-binary-contract.mts'; +import { readPortableArchiveEntries } from '../../tools/packaging/portable-archive.mts'; +import { stageReleaseNotices } from '../../tools/packaging/release-notices.mts'; +import { + deriveStaticRegistration, + type StaticRegistration, + staticSymbolPrefix, +} from './mobile_registration.mts'; +import { + exactArchive, + frozenNativeMember, + type NativeCarrierSpec, + nativeCarrierCompatibility, + validateNativeShippingModule, + writeJson, +} from './native_carriers.mts'; +import { inspect, inspectStaticArchiveBytes } from './validate_member_payload.mts'; + +export interface MobileStaticArchive { + target: string; + archive: string; + registration: string; + nm: { path: string; apple: boolean }; + aliases?: Record; + sqlName: string; + owner: string; + version: string; + runtimeVersion: string; + source: Record; +} +export interface MobileDependencyArchive { + target: string; + identity: string; + archive: string; + source: Record; +} +export interface MobileCarrierSpec extends Omit { + hostArchive: string; + components: string; + catalogSqlNames: string[]; + allProfiles: { target: string; family: string; kind: string }[]; + staticArchives: MobileStaticArchive[]; + dependencyArchives: MobileDependencyArchive[]; + dependencySources: Record>; + frameworks?: { + kind: 'ios-xcframework' | 'ios-dependency-xcframework'; + identity: string; + file: string; + bundleName: string; + }[]; +} + +const mobileTargets = new Set(['ios-xcframework', 'android-arm64-v8a', 'android-x86_64']); +const sorted = (values: string[]) => [...values].sort(); +const runtimeCohorts = (target: string) => + target === 'ios-xcframework' ? ['ios-device', 'ios-simulator'] : [target]; +const staticCohorts = (target: string) => + target === 'ios-xcframework' ? ['macos-arm64', ...runtimeCohorts(target)] : [target]; + +/** Resolve paths from the canonical graph, never from an independently authored recipe. */ +export function mobileArchivePlan(spec: MobileCarrierSpec, components: any) { + assert(mobileTargets.has(spec.target), 'mobile member requires a canonical static target'); + const moduleFile = spec.descriptor['native-module-file']; + assert( + moduleFile === undefined || (typeof moduleFile === 'string' && moduleFile.endsWith('.so')), + 'canonical mobile module must declare its .so stem', + ); + const stem = moduleFile === undefined ? null : moduleFile.slice(0, -3); + assert(stem === null || /^[a-z_][a-z0-9_-]*$/u.test(stem), 'mobile module stem must be portable'); + const closure = resolveNativeComponentClosure(components, { + extension: spec.sqlName, + family: 'native', + kind: 'native-static-registry', + target: spec.target, + }); + const cohorts = stem === null ? [] : staticCohorts(spec.target); + assert.deepEqual( + sorted(spec.staticArchives.map((row) => row.target)), + sorted(cohorts), + 'static member must cover its exact target cohorts once', + ); + const files: { source: string; destination: string; target: string }[] = []; + for (const row of spec.staticArchives) { + for (const [key, wanted] of Object.entries({ + sqlName: spec.sqlName, + owner: spec.owner ?? spec.product, + version: spec.version, + runtimeVersion: spec.runtimeVersion, + source: spec.source, + })) + assert.deepEqual( + row[key as keyof MobileStaticArchive], + wanted, + `static producer ${key} differs from canonical member`, + ); + assert.equal( + row.nm.apple, + spec.target === 'ios-xcframework', + 'nm convention differs from target', + ); + if (runtimeCohorts(spec.target).includes(row.target)) + files.push({ + source: row.archive, + destination: `mobile-static/${row.target}/extensions/${stem}/liboliphaunt_extension_${stem}.a`, + target: row.target, + }); + } + const expectedDependencies = cohorts.flatMap((target) => + closure.linkUnits.map((identity: string) => `${target}:${identity}`), + ); + assert.deepEqual( + sorted(spec.dependencyArchives.map((row) => `${row.target}:${row.identity}`)), + sorted(expectedDependencies), + 'dependency archives differ from the exact target component closure', + ); + for (const row of spec.dependencyArchives) { + const component = components.components.find((item: any) => + item.linkUnits.some((unit: any) => unit.id === row.identity), + ); + assert(component, 'static dependency must have a canonical component owner'); + const source = + component.sourcePath === null + ? spec.dependencySources[component.source] + : { path: component.sourcePath }; + assert(source, `component ${component.id} requires its canonical source identity`); + assert.deepEqual( + row.source, + source, + 'static dependency source differs from canonical acquisition', + ); + const unit = component.linkUnits.find((item: any) => item.id === row.identity); + const basenames = [ + ...new Set(unit.archiveCandidates.map((name: string) => path.posix.basename(name))), + ]; + assert.equal( + basenames.length, + 1, + 'component link unit requires one canonical archive basename', + ); + if (runtimeCohorts(spec.target).includes(row.target)) + files.push({ + source: row.archive, + destination: `mobile-static/${row.target}/dependencies/${row.identity}/${basenames[0]}`, + target: row.target, + }); + } + files.sort((a, b) => + a.destination < b.destination ? -1 : a.destination > b.destination ? 1 : 0, + ); + return { + stem, + closure, + files, + mobileContract: { + target: spec.target, + archives: files + .filter((row) => row.destination.includes('/extensions/')) + .map((row) => `${row.target}:${row.destination}`) + .sort(), + dependencies: files + .filter((row) => row.destination.includes('/dependencies/')) + .map((row) => `${row.target}:${row.destination.split('/')[3]}:${row.destination}`) + .sort(), + symbolPrefix: stem === null ? '' : staticSymbolPrefix(stem), + }, + }; +} + +function actualRegistration(row: MobileStaticArchive, stem: string, work: string) { + inspectStaticArchiveBytes(readFileSync(realpathSync(row.archive)), row.target, row.archive); + const receipt = JSON.parse( + readFileSync(realpathSync(row.registration), 'utf8'), + ) as StaticRegistration; + assert( + Array.isArray(receipt.symbols), + 'static producer requires a registration symbol inventory', + ); + const result = Bun.spawnSync( + [ + realpathSync(row.nm.path), + ...(row.nm.apple ? ['-g', '-U', '-m'] : ['-g', '--defined-only']), + realpathSync(row.archive), + ], + { cwd: work, env: { LC_ALL: 'C', LANG: 'C' }, stdout: 'pipe', stderr: 'pipe' }, + ); + assert.equal(result.exitCode, 0, `declared nm failed: ${result.stderr.toString('utf8')}`); + const registration = deriveStaticRegistration( + row.sqlName, + stem, + result.stdout.toString('utf8'), + row.nm.apple, + Object.entries(row.aliases ?? {}).map(([name, address]) => ({ name, address })), + ); + assert.deepEqual(receipt, registration, 'registration differs from actual archive definitions'); + return registration; +} + +/** Final binary and inventory readers inspect the bytes written by the shared archive writer. */ +export function assemblePublicMobileMember(spec: MobileCarrierSpec, output: string) { + const components = validateNativeComponentContract( + Bun.TOML.parse(readFileSync(spec.components, 'utf8')), + { + checkSourcePaths: false, + knownExtensions: new Set(spec.catalogSqlNames), + targetProfiles: new Map( + spec.allProfiles.map((row) => [row.target, `${row.family}\0${row.kind}`]), + ), + }, + ); + const plan = mobileArchivePlan(spec, components); + const hostTarget = nativeModuleHostTarget(spec.target); + const actual = inspect(spec.hostArchive, spec.sqlName, spec.owner ?? spec.product); + const metadata = frozenNativeMember( + { ...spec, archive: spec.hostArchive, target: hostTarget } as NativeCarrierSpec, + actual, + ); + assert.equal(metadata.nativeModuleStem, plan.stem); + assert( + plan.closure.runtimeFiles.every((file: string) => metadata.dataFiles.includes(file)), + 'component runtime data is missing from the canonical host member', + ); + const root = mkdtempSync(path.join(tmpdir(), 'mobile-extension-member-')); + mkdirSync(path.dirname(path.resolve(output)), { recursive: true }); + try { + const registrations = spec.staticArchives.map((row) => { + assert(plan.stem !== null, 'compiled static member requires its canonical stem'); + return actualRegistration(row, plan.stem, root); + }); + for (const registration of registrations) + assert.deepEqual( + registration, + registrations[0], + 'target slice registration metadata differs', + ); + for (const row of spec.dependencyArchives) + inspectStaticArchiveBytes(readFileSync(realpathSync(row.archive)), row.target, row.archive); + const iosRegistration = spec.target === 'ios-xcframework' ? (registrations[0] ?? null) : null; + const aliases = + registrations[0]?.symbols + .filter((row) => row.name !== row.address) + .map((row) => `${row.name}:${row.address}`) + .sort() ?? []; + const mobileContract = { ...plan.mobileContract, symbolAliases: aliases }; + const publicRoot = path.join(root, 'public'); + mkdirSync(publicRoot); + for (const [name, entry] of readPortableArchiveEntries(realpathSync(spec.hostArchive))) { + if (name === 'extension.json' || name.startsWith('lib/modules/')) continue; + const destination = path.join(publicRoot, 'files', name); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, entry.data(), { mode: name.startsWith('lib/') ? 0o755 : 0o644 }); + if (name.startsWith('lib/')) validateNativeShippingModule(entry.data(), hostTarget, name); + } + for (const row of plan.files) { + const destination = path.join(publicRoot, row.destination); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, readFileSync(realpathSync(row.source)), { mode: 0o644 }); + } + stageExtensionUpstreamLicenses(spec.sqlName, path.join(publicRoot, 'files')); + const legal = extensionCarrierLegalContract(spec.product, [spec.sqlName], { + family: 'native', + target: spec.target, + memberContracts: [metadata], + }); + stageReleaseNotices(publicRoot, { profile: legal.profile }); + const compatibility = nativeCarrierCompatibility(spec as NativeCarrierSpec); + const properties: Record = { + packageLayout: 'oliphaunt-extension-artifact-v1', + pgMajor: '18', + sqlName: spec.sqlName, + createsExtension: metadata.createsExtension ? 'yes' : 'no', + nativeModuleStem: metadata.nativeModuleStem ?? '', + nativeModuleFile: String(actual.module_file), + nativeTarget: spec.target, + nativeRuntimeProduct: compatibility.nativeRuntimeProduct, + nativeRuntimeVersion: compatibility.nativeRuntimeVersion, + dependencies: metadata.dependencies.join(','), + dataFiles: metadata.dataFiles.join(','), + extensionSqlFileNames: metadata.extensionSqlFileNames.join(','), + extensionSqlFilePrefixes: metadata.extensionSqlFilePrefixes.join(','), + sharedPreloadLibraries: metadata.sharedPreloadLibraries.join(','), + mobilePrebuilt: metadata.nativeModuleStem === null ? 'no' : 'yes', + mobileStaticArchives: mobileContract.archives.join(','), + mobileStaticDependencyArchives: mobileContract.dependencies.join(','), + staticSymbolPrefix: mobileContract.symbolPrefix, + staticSymbolAliases: aliases.join(','), + licenseFiles: [ + ...legal.licenseFiles, + ...(metadata.nativeConstructionLicenseFiles ?? []).map((row) => row.path), + ] + .sort() + .join(','), + licenseProfile: legal.profile, + files: 'files', + }; + writeFileSync( + path.join(publicRoot, 'manifest.properties'), + EXTENSION_ARTIFACT_PROPERTY_KEYS.map((key) => `${key}=${properties[key]}\n`).join(''), + ); + exactArchive(publicRoot, output); + const final = validateExtensionArtifactArchive({ + file: output, + metadata, + product: spec.product, + target: spec.target, + nativeRuntimeVersion: compatibility.nativeRuntimeVersion, + mobileContract, + }); + for (const row of plan.files) { + const entry = final.entries.get(row.destination); + assert(entry, 'written mobile archive is missing a declared static input'); + inspectStaticArchiveBytes(entry.data, row.target, row.destination); + } + const bytes = readFileSync(output); + const name = nativeAssetNameForRow(spec.product, spec.version, { + target: spec.target, + kind: 'runtime', + asset: output, + }); + assert.equal( + path.basename(output), + name, + 'mobile runtime asset requires its canonical filename', + ); + return { + metadata: { + ...metadata, + iosRegistration, + iosNativeDependencies: + spec.target === 'ios-xcframework' ? sorted(plan.closure.linkUnits) : [], + wasixInstall: null, + }, + asset: { + name, + family: 'native', + target: spec.target, + kind: 'runtime', + identity: null, + bytes: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + }, + }; + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +export async function packageMobileCarriers(spec: { + product: string; + owner: string; + version: string; + target: string; + expectedMembers: string[]; + members: MobileCarrierSpec[]; + releaseMetadata: any; + outputs: { github: string; manifest: string; frozen: string }; +}) { + assert.deepEqual(spec.members.map((row) => row.sqlName).sort(), spec.expectedMembers); + assert.equal(new Set(spec.expectedMembers).size, spec.expectedMembers.length); + const root = mkdtempSync(path.join(tmpdir(), 'mobile-extension-envelopes-')); + try { + const productRoot = path.join(root, 'product'); + mkdirSync(path.join(productRoot, 'release-assets'), { recursive: true }); + mkdirSync(spec.outputs.github, { recursive: true }); + const members = []; + for (const member of spec.members) { + assert.equal(member.product, spec.product); + assert.equal(member.owner ?? member.product, spec.owner); + assert.equal(member.version, spec.version); + assert.equal(member.target, spec.target); + const directory = path.join(productRoot, 'member-assets', member.sqlName); + mkdirSync(directory, { recursive: true }); + const name = nativeAssetNameForRow(spec.product, spec.version, { + target: spec.target, + kind: 'runtime', + asset: 'runtime.tar.gz', + }); + const archive = path.join(directory, name); + const { metadata, asset } = assemblePublicMobileMember(member, archive); + const assets = [{ ...asset, path: path.relative(root, archive).split(path.sep).join('/') }]; + const frameworks = member.frameworks ?? []; + const required = + spec.target === 'ios-xcframework' && metadata.nativeModuleStem !== null + ? [ + `ios-xcframework:${metadata.nativeModuleStem}`, + ...metadata.iosNativeDependencies.map( + (identity: string) => `ios-dependency-xcframework:${identity}`, + ), + ].sort() + : []; + assert.deepEqual( + frameworks.map((row) => `${row.kind}:${row.identity}`).sort(), + required, + 'iOS final member requires each canonical framework role once', + ); + for (const framework of frameworks) { + const physicalFramework = realpathSync(framework.file); + await validateAppleXcframeworkAsset(physicalFramework, framework.bundleName); + inspectPlatformBinaryEntries( + [...readPortableArchiveEntries(physicalFramework)].map(([entryName, entry]) => ({ + ...entry, + name: entryName, + })), + { + target: 'ios-xcframework', + rootLabel: framework.file, + }, + ); + const frameworkName = nativeAssetNameForRow(spec.product, spec.version, { + ...framework, + target: spec.target, + asset: framework.file, + }); + const output = path.join(directory, frameworkName); + copyFileSync(physicalFramework, output); + const bytes = readFileSync(output); + assets.push({ + name: frameworkName, + family: 'native', + target: spec.target, + kind: framework.kind, + identity: framework.identity, + bytes: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + path: path.relative(root, output).split(path.sep).join('/'), + }); + } + members.push({ ...metadata, assets }); + } + const directAssets = + spec.members.length > 1 + ? bundleCarrierAssets( + spec.product, + spec.version, + productRoot, + members, + nativeCarrierCompatibility(spec.members[0] as NativeCarrierSpec), + { root }, + ) + : members[0].assets; + for (const asset of directAssets) + copyFileSync(path.join(root, asset.path), path.join(spec.outputs.github, asset.name)); + const documents = composeExtensionReleaseDocuments({ + product: spec.product, + releaseProduct: spec.owner, + family: 'native', + version: spec.version, + members, + directAssets, + releaseMetadata: spec.releaseMetadata, + }); + writeJson(spec.outputs.frozen, documents.manifest); + writeJson(spec.outputs.manifest, documents.releaseData); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + assert.equal(process.argv.length, 3, 'usage: mobile_carriers.mts '); + const inputs = JSON.parse(readFileSync(process.argv[2], 'utf8')); + if (inputs.operation === 'package') await packageMobileCarriers(inputs); + else writeJson(inputs.inventory, assemblePublicMobileMember(inputs.spec, inputs.output)); +} diff --git a/build_defs/extensions/mobile_carriers.test.mts b/build_defs/extensions/mobile_carriers.test.mts new file mode 100644 index 000000000..c62357988 --- /dev/null +++ b/build_defs/extensions/mobile_carriers.test.mts @@ -0,0 +1,245 @@ +import { test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { validateNativeComponentContract } from '../../src/extensions/tools/native-component-contract.mts'; +import { type MobileCarrierSpec, mobileArchivePlan } from './mobile_carriers.mts'; + +// These synthetic inputs test contract boundaries; they are not construction evidence. +const source = { name: 'fixture', commit: '1'.repeat(40) }; +const dependencySource = { name: 'dependency', commit: '2'.repeat(40) }; +const profiles = [ + { target: 'ios-xcframework', family: 'native', kind: 'native-static-registry' }, + { target: 'android-arm64-v8a', family: 'native', kind: 'native-static-registry' }, + { target: 'android-x86_64', family: 'native', kind: 'native-static-registry' }, +]; +const graph = (local = false) => + validateNativeComponentContract( + { + schema: 'oliphaunt-native-components-v1', + components: [ + { + id: 'dependency', + ...(local ? { 'source-path': 'src/fixture' } : { source: 'dependency' }), + 'depends-on': [], + 'runtime-files': [], + 'link-units': [ + { id: 'dependency-c', 'archive-candidates': ['dependency/lib/libdependency_c.a'] }, + { id: 'dependency', 'archive-candidates': ['dependency/lib/libdependency.a'] }, + ], + }, + ], + requirements: [ + { + extension: 'fixture', + family: 'native', + kind: 'native-static-registry', + targets: profiles.map((row) => row.target), + roots: ['dependency'], + }, + ], + }, + { + checkSourcePaths: false, + knownExtensions: new Set(['fixture', 'sql_only']), + targetProfiles: new Map(profiles.map((row) => [row.target, `${row.family}\0${row.kind}`])), + }, + ); + +function specification(target = 'android-arm64-v8a'): MobileCarrierSpec { + const cohorts = + target === 'ios-xcframework' ? ['macos-arm64', 'ios-device', 'ios-simulator'] : [target]; + return { + product: 'fixture-product', + version: '1.0.0', + sqlName: 'fixture', + target, + runtimeVersion: '0.3.3', + descriptor: { 'native-module-file': 'fixture.so' }, + recipe: {}, + source, + selectedDependencies: [], + compatibility: {}, + carriers: [], + hostArchive: '/declared/host.tar.gz', + components: '/declared/components.toml', + catalogSqlNames: ['fixture', 'sql_only'], + allProfiles: profiles, + dependencySources: { dependency: dependencySource }, + staticArchives: cohorts.map((cohort) => ({ + target: cohort, + archive: `/declared/${cohort}/fixture.a`, + registration: `/declared/${cohort}/registration.json`, + nm: { path: '/declared/nm', apple: target === 'ios-xcframework' }, + sqlName: 'fixture', + owner: 'fixture-product', + version: '1.0.0', + runtimeVersion: '0.3.3', + source, + })), + dependencyArchives: cohorts.flatMap((cohort) => + ['dependency', 'dependency-c'].map((identity) => ({ + target: cohort, + identity, + archive: `/declared/${cohort}/${identity}.a`, + source: dependencySource, + })), + ), + }; +} + +test('Android paths use each canonical component archive basename and actual target', () => { + for (const target of ['android-arm64-v8a', 'android-x86_64']) { + const plan = mobileArchivePlan(specification(target), graph()); + assert.equal(plan.stem, 'fixture'); + assert.equal(plan.mobileContract.symbolPrefix, 'oliphaunt_static_fixture'); + assert.deepEqual(plan.mobileContract.archives, [ + `${target}:mobile-static/${target}/extensions/fixture/liboliphaunt_extension_fixture.a`, + ]); + assert.deepEqual(plan.mobileContract.dependencies, [ + `${target}:dependency-c:mobile-static/${target}/dependencies/dependency-c/libdependency_c.a`, + `${target}:dependency:mobile-static/${target}/dependencies/dependency/libdependency.a`, + ]); + assert.equal(plan.files.length, 3); + } +}); + +test('iOS requires real three-slice inputs and stages only device and simulator archives', () => { + const spec = specification('ios-xcframework'); + const plan = mobileArchivePlan(spec, graph()); + assert.equal(plan.files.length, 6); + assert(plan.files.every((row) => !row.destination.includes('macos-arm64'))); + assert.deepEqual(plan.mobileContract.archives, [ + 'ios-device:mobile-static/ios-device/extensions/fixture/liboliphaunt_extension_fixture.a', + 'ios-simulator:mobile-static/ios-simulator/extensions/fixture/liboliphaunt_extension_fixture.a', + ]); + assert.throws( + () => mobileArchivePlan({ ...spec, staticArchives: spec.staticArchives.slice(1) }, graph()), + /exact target cohorts/u, + ); + assert.throws( + () => + mobileArchivePlan({ ...spec, dependencyArchives: spec.dependencyArchives.slice(2) }, graph()), + /component closure/u, + ); +}); + +test('producer owner, runtime and immutable source must match canonical member metadata', () => { + const spec = specification(); + for (const changed of [ + { owner: 'foreign-owner' }, + { runtimeVersion: '0.3.2' }, + { source: { ...source, commit: '3'.repeat(40) } }, + ]) { + assert.throws( + () => + mobileArchivePlan( + { ...spec, staticArchives: [{ ...spec.staticArchives[0], ...changed }] }, + graph(), + ), + /differs from canonical member/u, + ); + } + assert.throws( + () => + mobileArchivePlan( + { ...spec, dependencyArchives: spec.dependencyArchives.map((row) => ({ ...row, source })) }, + graph(), + ), + /canonical acquisition/u, + ); + assert.throws( + () => mobileArchivePlan({ ...spec, dependencySources: {} }, graph()), + /canonical source identity/u, + ); +}); + +test('missing, duplicate, foreign and incorrectly named target archives fail closed', () => { + const spec = specification(); + assert.throws( + () => mobileArchivePlan({ ...spec, target: 'linux-x64-gnu' }, graph()), + /canonical static target/u, + ); + assert.throws( + () => mobileArchivePlan({ ...spec, staticArchives: [] }, graph()), + /exact target cohorts/u, + ); + assert.throws( + () => + mobileArchivePlan( + { ...spec, staticArchives: [...spec.staticArchives, ...spec.staticArchives] }, + graph(), + ), + /exact target cohorts/u, + ); + assert.throws( + () => + mobileArchivePlan( + { ...spec, dependencyArchives: [...spec.dependencyArchives, spec.dependencyArchives[0]] }, + graph(), + ), + /component closure/u, + ); + assert.throws( + () => + mobileArchivePlan( + { + ...spec, + staticArchives: [ + { ...spec.staticArchives[0], nm: { path: '/declared/nm', apple: true } }, + ], + }, + graph(), + ), + /nm convention/u, + ); + assert.throws( + () => + mobileArchivePlan( + { ...spec, descriptor: { 'native-module-file': 'fixture.dylib' } }, + graph(), + ), + /canonical mobile module/u, + ); + assert.throws( + () => + mobileArchivePlan( + { ...spec, descriptor: { 'native-module-file': '../fixture.so' } }, + graph(), + ), + /module stem/u, + ); +}); + +test('local component source identity comes from its declared source path', () => { + const spec = specification(); + const actual = { + ...spec, + dependencyArchives: spec.dependencyArchives.map((row) => ({ + ...row, + source: { path: 'src/fixture' }, + })), + }; + assert.equal(mobileArchivePlan(actual, graph(true)).files.length, 3); + assert.throws(() => mobileArchivePlan(spec, graph(true)), /canonical acquisition/u); +}); + +test('SQL-only members carry no static or registration roles', () => { + const spec = { + ...specification('ios-xcframework'), + sqlName: 'sql_only', + descriptor: {}, + staticArchives: [], + dependencyArchives: [], + }; + const plan = mobileArchivePlan(spec, graph()); + assert.equal(plan.stem, null); + assert.equal(plan.mobileContract.symbolPrefix, ''); + assert.deepEqual(plan.files, []); + assert.throws( + () => + mobileArchivePlan( + { ...spec, staticArchives: specification('ios-xcframework').staticArchives }, + graph(), + ), + /exact target cohorts/u, + ); +}); diff --git a/build_defs/extensions/mobile_consumer.c b/build_defs/extensions/mobile_consumer.c new file mode 100644 index 000000000..ec7d186f9 --- /dev/null +++ b/build_defs/extensions/mobile_consumer.c @@ -0,0 +1,12 @@ +#include +#include "oliphaunt.h" + +extern const OliphauntStaticExtension *liboliphaunt_selected_static_extensions(size_t *count); + +/* The target linker must resolve every actual registration address and public API. */ +int main(void) { + size_t count = 0; + const OliphauntStaticExtension *members = liboliphaunt_selected_static_extensions(&count); + if (members == NULL || count == 0) return 1; + return oliphaunt_register_static_extensions(members, count) == 0 ? 0 : 1; +} diff --git a/build_defs/extensions/mobile_host_profile_test.bzl b/build_defs/extensions/mobile_host_profile_test.bzl new file mode 100644 index 000000000..45d48f192 --- /dev/null +++ b/build_defs/extensions/mobile_host_profile_test.bzl @@ -0,0 +1,39 @@ +"""Exercise the real desktop-member transition without acquiring an Apple SDK.""" + +load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest") +load(":mobile_carriers.bzl", "mobile_host_transition") + +_HostProfileInfo = provider(fields = ["macos", "linux", "apple_package"]) + +def _profile_impl(ctx): + return [_HostProfileInfo(**{name: ctx.target_platform_has_constraint(getattr(ctx.attr, name)[platform_common.ConstraintValueInfo]) for name in ["macos", "linux", "apple_package"]})] + +_profile = rule(implementation = _profile_impl, attrs = { + "macos": attr.label(default = "@platforms//os:macos"), + "linux": attr.label(default = "@platforms//os:linux"), + "apple_package": attr.label(default = "//build_defs/host:apple_package"), +}) + +def _host_profile_test_impl(ctx): + env = unittest.begin(ctx) + profile = ctx.attr.probe[0][_HostProfileInfo] + asserts.equals(env, ctx.attr.target == "ios-xcframework", profile.macos) + asserts.equals(env, ctx.attr.target != "ios-xcframework", profile.linux) + asserts.false(env, profile.apple_package, "desktop members must retain the direct carrier deployment contract") + return unittest.end(env) + +_host_profile_test = unittest.make(_host_profile_test_impl, attrs = { + "probe": attr.label(cfg = mobile_host_transition), + "target": attr.string(), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), +}) + +def mobile_host_profile_tests(): + _profile(name = "mobile_host_profile_fixture", testonly = True, tags = ["manual"]) + for target in ["ios-xcframework", "android-arm64-v8a", "android-x86_64"]: + _host_profile_test( + name = "mobile_host_" + target.replace("-", "_") + "_test", + probe = ":mobile_host_profile_fixture", + target = target, + size = "small", + ) diff --git a/build_defs/extensions/mobile_maven.mts b/build_defs/extensions/mobile_maven.mts new file mode 100644 index 000000000..333b1dbbe --- /dev/null +++ b/build_defs/extensions/mobile_maven.mts @@ -0,0 +1,80 @@ +/** Two genuine Android final leaves feed the existing Maven writers. */ +import assert from 'node:assert/strict'; +import { copyFileSync, mkdirSync, mkdtempSync, readFileSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { buildMavenArtifactManifest } from '../../tools/packaging/build-maven-artifact-manifest.mts'; +import { stageMavenArtifactManifest } from '../../tools/packaging/maven-artifact-staging.mts'; +import { type NativeOwnerSpec, validateNativeFinalLeaf } from './owner_carriers.mts'; + +export async function packageMobileMaven( + spec: NativeOwnerSpec & { mavenCoordinates: string[]; outputs: Record }, +) { + assert.deepEqual( + spec.leaves.map((leaf) => leaf.target).sort(), + ['android-arm64-v8a', 'android-x86_64'], + 'Maven requires both actual Android final leaves once', + ); + const root = mkdtempSync(path.join(tmpdir(), 'mobile-extension-maven-')); + try { + const productRoot = path.join(root, 'product'); + mkdirSync(path.join(productRoot, 'release-assets'), { recursive: true }); + const memberContracts = {}; + for (const leaf of spec.leaves) { + const stagedRoot = path.join(root, leaf.target); + const validated = validateNativeFinalLeaf(spec, leaf, stagedRoot); + memberContracts[leaf.target] = validated.members; + for (const asset of validated.directAssets) + copyFileSync( + path.join(stagedRoot, asset.path), + path.join(productRoot, 'release-assets', asset.name), + ); + } + const manifest = path.join(root, 'maven.tsv'); + await buildMavenArtifactManifest(manifest, { + extensions: true, + extensionProducts: [spec.product], + context: { + extensions: { + [spec.product]: { + productRoot, + releaseProduct: spec.owner, + version: spec.version, + sqlNames: spec.members.map((member) => member.sqlName), + compatibility: spec.releaseMetadata.compatibility, + runtimeSourceVersion: spec.runtimeVersion, + targets: spec.profiles.filter( + (profile) => + profile.kind === 'native-static-registry' && profile.target.startsWith('android-'), + ), + registryPackages: spec.mavenCoordinates, + memberContracts, + }, + }, + }, + }); + const staged = await stageMavenArtifactManifest(manifest, path.join(root, 'staged')); + assert.deepEqual( + staged.map((row) => `${row.groupId}:${row.artifactId}`).sort(), + spec.mavenCoordinates.slice().sort(), + ); + assert.deepEqual(Object.keys(spec.outputs).sort(), spec.mavenCoordinates.slice().sort()); + for (const row of staged) { + const output = spec.outputs[`${row.groupId}:${row.artifactId}`]; + mkdirSync(output, { recursive: true }); + for (const file of row.files) + copyFileSync(path.join(row.directory, file), path.join(output, file)); + } + return staged.map((row) => ({ + ...row, + directory: spec.outputs[`${row.groupId}:${row.artifactId}`], + })); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + assert.equal(process.argv.length, 3, 'usage: mobile_maven.mts '); + await packageMobileMaven(JSON.parse(readFileSync(process.argv[2], 'utf8'))); +} diff --git a/build_defs/extensions/mobile_maven.test.mts b/build_defs/extensions/mobile_maven.test.mts new file mode 100644 index 000000000..81811a52c --- /dev/null +++ b/build_defs/extensions/mobile_maven.test.mts @@ -0,0 +1,190 @@ +import { expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + nativeExtensionConstructionLicenseInventory, + stageExtensionUpstreamLicenses, +} from '../../src/extensions/tools/extension-upstream-licenses.mts'; +import { archiveDirectory } from '../../tools/packaging/archive-directory.mts'; +import { buildMavenArtifactManifest } from '../../tools/packaging/build-maven-artifact-manifest.mts'; +import { parseMavenArtifactManifest } from '../../tools/packaging/maven-artifact-manifest.mts'; +import { renderMavenArtifactPom } from '../../tools/packaging/maven-artifact-staging.mts'; +import { stageReleaseNotices } from '../../tools/packaging/release-notices.mts'; +import { declaredExtensionMetadata } from '../../tools/release/extension-release-metadata.mts'; + +function compilerRuntimeLicenseFixture() { + if (process.env.OLIPHAUNT_TEST_COMPILER_RT_LICENSE) + return process.env.OLIPHAUNT_TEST_COMPILER_RT_LICENSE; + const runfiles = process.env.RUNFILES_DIR ?? process.env.TEST_SRCDIR; + if (!runfiles) return undefined; + const mapping = readFileSync(path.join(runfiles, '_repo_mapping'), 'utf8') + .trim() + .split('\n') + .map((line) => line.split(',')); + const roots = new Set( + mapping.filter((row) => row[1] === 'pgvector_compiler_rt').map((row) => row[2]), + ); + expect(roots.size, 'Bazel Maven regression requires its declared compiler-runtime license').toBe( + 1, + ); + return path.join(runfiles, [...roots][0], 'LICENSE.TXT'); +} + +const compilerRuntimeLicense = compilerRuntimeLicenseFixture(); + +test.skipIf(!compilerRuntimeLicense)( + 'declared vector Maven inputs require exact construction receipts for both Android targets', + async () => { + // Payloads exercise legal validation only. The acquired license is bound to + // its canonical source pin; these archives are not target binary evidence. + if (!compilerRuntimeLicense) throw new Error('compiler-runtime license fixture is required'); + const repository = path.resolve(import.meta.dir, '../..'); + const release = Bun.TOML.parse( + readFileSync(path.join(repository, 'src/extensions/external/vector/release.toml'), 'utf8'), + ); + const extensionSource = Bun.TOML.parse( + readFileSync(path.join(repository, release.extension.source.path), 'utf8'), + ); + const product = release.id; + const version = extensionSource['extension-control']['default-version']; + const metadata = declaredExtensionMetadata(product, release.extension); + const targets = ['android-arm64-v8a', 'android-x86_64']; + const source = JSON.parse( + readFileSync(path.join(import.meta.dir, 'compiler_rt/source.json'), 'utf8'), + ); + const sourceBytes = Buffer.from( + JSON.stringify(source, (_key, value) => + value && typeof value === 'object' && !Array.isArray(value) + ? Object.fromEntries( + Object.keys(value) + .sort() + .map((key) => [key, value[key]]), + ) + : value, + ), + ); + const licenseBytes = readFileSync(compilerRuntimeLicense); + const licensePath = 'share/licenses/llvm-compiler-rt/LICENSE.TXT'; + const sourcePath = 'share/licenses/llvm-compiler-rt/SOURCE.json'; + const constructionFiles = new Map([ + [licensePath, licenseBytes], + [sourcePath, sourceBytes], + ]); + const memberContracts = Object.fromEntries( + targets.map((target) => { + const files = nativeExtensionConstructionLicenseInventory('vector', target); + for (const file of files) { + expect(createHash('sha256').update(constructionFiles.get(file.path)).digest('hex')).toBe( + file.sha256, + ); + } + return [target, [{ sqlName: 'vector', nativeConstructionLicenseFiles: files }]]; + }), + ); + const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-mobile-maven-legal-')); + try { + const productRoot = path.join(root, 'product'); + const assets = path.join(productRoot, 'release-assets'); + mkdirSync(assets, { recursive: true }); + async function payload(target, files = constructionFiles) { + const stage = path.join(root, target); + rmSync(stage, { recursive: true, force: true }); + mkdirSync(stage, { recursive: true }); + stageReleaseNotices(stage, { profile: 'external-native' }); + stageExtensionUpstreamLicenses('vector', path.join(stage, 'files')); + for (const [name, bytes] of files) { + const destination = path.join(stage, 'files', name); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, bytes, { mode: 0o644 }); + } + await archiveDirectory( + stage, + path.join(assets, `${product}-${version}-native-${target}-runtime.tar.gz`), + ); + } + for (const target of targets) await payload(target); + const row = { + productRoot, + releaseProduct: product, + version, + sqlNames: metadata.sqlNames, + compatibility: metadata.compatibility, + runtimeSourceVersion: metadata.compatibility.nativeRuntimeVersion, + targets: targets.map((target) => ({ + target, + family: 'native', + kind: 'native-static-registry', + })), + registryPackages: release.registry_packages + .filter((coordinate) => coordinate.startsWith('maven:')) + .map((coordinate) => coordinate.slice('maven:'.length)), + memberContracts, + }; + const manifest = path.join(root, 'vector.tsv'); + const build = (contracts = memberContracts) => + buildMavenArtifactManifest(manifest, { + extensions: true, + extensionProducts: [product], + context: { extensions: { [product]: { ...row, memberContracts: contracts } } }, + }); + await build(); + const records = parseMavenArtifactManifest(manifest); + expect(records.map((record) => record.artifactId)).toEqual( + targets.map((target) => `${product}-${target}`), + ); + for (const record of records) { + expect(record.licenseSpdx).toContain('Apache-2.0 WITH LLVM-exception'); + expect(renderMavenArtifactPom(record)).toContain( + `https://github.com/llvm/llvm-project/blob/${source.commit}/${source.files.find((file) => file.destination === 'LICENSE.TXT').path}`, + ); + } + for (const target of targets) { + for (const [files, pattern] of [ + [new Map([[licensePath, licenseBytes]]), /packed upstream license members differ/u], + [ + new Map([ + [licensePath, Buffer.from('changed license')], + [sourcePath, sourceBytes], + ]), + /packed upstream license bytes changed/u, + ], + [ + new Map([ + ...constructionFiles, + ['share/licenses/foreign/LICENSE', Buffer.from('extra license')], + ]), + /unexpected (?:file|directory) member/u, + ], + ] as const) { + await payload(target, files); + await expect(build()).rejects.toThrow(pattern); + } + await payload(target); + const files = memberContracts[target][0].nativeConstructionLicenseFiles; + for (const invalid of [ + [], + [{ ...files[0], sha256: '0'.repeat(64) }, files[1]], + [...files, { ...files[0], path: 'share/licenses/foreign/LICENSE' }], + ]) { + await expect( + build({ + ...memberContracts, + [target]: [{ sqlName: 'vector', nativeConstructionLicenseFiles: invalid }], + }), + ).rejects.toThrow( + invalid.length === 0 + ? /unexpected (?:file|directory) member/u + : /immutable construction source/u, + ); + } + await expect( + build({ ...memberContracts, [target]: [], 'linux-x64-gnu': memberContracts[target] }), + ).rejects.toThrow(/unexpected (?:file|directory) member/u); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } + }, +); diff --git a/build_defs/extensions/mobile_members.bzl b/build_defs/extensions/mobile_members.bzl new file mode 100644 index 000000000..c600fb80c --- /dev/null +++ b/build_defs/extensions/mobile_members.bzl @@ -0,0 +1,72 @@ +"""Actual compiled mobile cohort from the canonical extension and component model.""" + +load("@oliphaunt_metadata//:metadata.bzl", "CONTRIB_MEMBERS", "EXTENSIONS", "EXTENSION_SOURCES", "NATIVE_COMPONENTS", "NATIVE_COMPONENT_SOURCES") +load("@rules_cc//cc:defs.bzl", "cc_import", "cc_library") +load("//build_defs/native:platform_config.bzl", "NATIVE_COPTS") +load("//build_defs/extensions/postgis:mobile.bzl", "POSTGIS_MOBILE_ARCHIVES", "POSTGIS_MOBILE_LIBRARIES") +load(":contrib.bzl", "contrib_extension_inputs") +load(":external.bzl", "VECTOR_COPTS", "external_extension_inputs") +load(":mobile.bzl", "MOBILE_EXTENSION_COMPATIBLE", "mobile_static_archive", "mobile_static_component", "native_mobile_extension") + +_PACKAGE = "//build_defs/extensions/mobile:" +_DESCRIPTORS = {descriptor["sql-name"]: descriptor for descriptor in EXTENSIONS.values()} +_EXTERNAL_MEMBERS = [name for name in sorted(EXTENSION_SOURCES) if _DESCRIPTORS[name].get("native-module-file")] +_MEMBER_NAMES = {member["sql-name"]: member["id"] for member in CONTRIB_MEMBERS} | {name: name for name in _EXTERNAL_MEMBERS} + +MOBILE_MEMBER_TARGETS = {sql_name: _PACKAGE + name for sql_name, name in _MEMBER_NAMES.items()} +MOBILE_MEMBER_LIBRARIES = {sql_name: target + "_library" for sql_name, target in MOBILE_MEMBER_TARGETS.items()} +MOBILE_MEMBER_ARCHIVE_OBJECTS = { + sql_name: _PACKAGE + "oliphaunt_extension_" + _DESCRIPTORS[sql_name]["native-module-file"][:-3] + "_own_objects" + for sql_name in _MEMBER_NAMES +} | {"postgis": "//build_defs/extensions/postgis/mobile:oliphaunt_extension_postgis-3_own_objects"} +MOBILE_SQL_ONLY_MEMBERS = [name for name in sorted(_DESCRIPTORS) if not _DESCRIPTORS[name].get("native-module-file")] + +MOBILE_COMPONENT_ARCHIVES = POSTGIS_MOBILE_ARCHIVES | {"openssl": _PACKAGE + "crypto", "uuid": _PACKAGE + "uuid"} +MOBILE_COMPONENT_LIBRARIES = POSTGIS_MOBILE_LIBRARIES | {"openssl": _PACKAGE + "crypto_library", "uuid": _PACKAGE + "uuid_library"} +MOBILE_COMPONENT_ARCHIVE_OBJECTS = {identity: archive + "_own_objects" for identity, archive in MOBILE_COMPONENT_ARCHIVES.items()} +MOBILE_COMPONENT_TARGETS = {identity: _PACKAGE + "component_" + identity.replace("-", "_") for identity in MOBILE_COMPONENT_ARCHIVES} + +def _component_source(identity): + owners = [component for component in NATIVE_COMPONENTS["components"] if any([unit["id"] == identity for unit in component["link-units"]])] + if len(owners) != 1: + fail("static link unit requires exactly one canonical source owner: " + identity) + component = owners[0] + if component.get("source-path"): + return {"path": component["source-path"]} + if component["source"] not in NATIVE_COMPONENT_SOURCES: + fail("static link unit lacks its canonical acquisition: " + identity) + return NATIVE_COMPONENT_SOURCES[component["source"]] + +def mobile_extension_members(): + """Build the existing units and separately owned dependency archives.""" + cc_library(name = "uuid_objects", + srcs = ["//src/extensions/contrib:portable-uuid/portable_uuid.c"], + hdrs = ["//src/extensions/contrib:portable-uuid/include/uuid/uuid.h"], + strip_include_prefix = "/src/extensions/contrib/portable-uuid/include", + deps = ["//src/native/runtime:postgres_embedded_headers"], + copts = NATIVE_COPTS + ["-g0"], target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) + mobile_static_archive(name = "uuid", roots = [":uuid_objects"], target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) + cc_import(name = "uuid_import", static_library = ":uuid", target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) + cc_library(name = "uuid_library", deps = [":uuid_import"], target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) + mobile_static_archive(name = "crypto", roots = ["@openssl//:crypto"], target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) + cc_import(name = "crypto_import", static_library = ":crypto", target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) + cc_library(name = "crypto_library", deps = [":crypto_import"], + linkopts = select({"//build_defs/native:android": ["-ldl", "-pthread"], "//conditions:default": ["-pthread"]}), + target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) + for identity, archive in MOBILE_COMPONENT_ARCHIVES.items(): + mobile_static_component(name = "component_" + identity.replace("-", "_"), identity = identity, archive = archive, source = _component_source(identity)) + for member in CONTRIB_MEMBERS: + name = member["id"] + inputs = contrib_extension_inputs(name = name, member = member, crypto = "@openssl//:crypto", uuid_provider = ":uuid_objects") + consumer_deps = [":crypto_library"] if name == "pgcrypto" else [":uuid_library"] if name == "uuid_ossp" else None + native_mobile_extension(name = name, sql_name = member["sql-name"], consumer_deps = consumer_deps, **inputs) + for sql_name in _EXTERNAL_MEMBERS: + if sql_name == "postgis": + native.alias(name = sql_name, actual = "//build_defs/extensions/postgis/mobile:extension") + native.alias(name = sql_name + "_library", actual = "//build_defs/extensions/postgis/mobile:extension_library") + else: + inputs = external_extension_inputs(name = sql_name, sql_name = sql_name) + if sql_name == "vector": + inputs["copts"] = inputs.get("copts", []) + VECTOR_COPTS + ["-fPIC"] + native_mobile_extension(name = sql_name, sql_name = sql_name, **inputs) + native.filegroup(name = "compiled_members", srcs = MOBILE_MEMBER_TARGETS.values(), target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) diff --git a/build_defs/extensions/mobile_registration.mts b/build_defs/extensions/mobile_registration.mts new file mode 100644 index 000000000..5dc1bd781 --- /dev/null +++ b/build_defs/extensions/mobile_registration.mts @@ -0,0 +1,221 @@ +/** Registration is derived from the actual target archive's global definitions. */ +import assert from 'node:assert/strict'; +import { readFileSync, writeFileSync } from 'node:fs'; +import { + assertDefinedRegistrationAddresses, + assertStaticMemberAliases, + staticSymbolPrefix, +} from '../../src/extensions/artifacts/native/tools/ios-extension-registration.mts'; + +export { staticSymbolPrefix } from '../../src/extensions/artifacts/native/tools/ios-extension-registration.mts'; + +const identifier = /^[A-Za-z_][A-Za-z0-9_]*$/u; +const portable = /^[A-Za-z0-9._-]{1,128}$/u; +export interface StaticRegistration { + schema: 'oliphaunt-ios-extension-registration-v1'; + sqlName: string; + nativeModuleStem: string; + magicSymbol: string; + initSymbol: string | null; + symbols: { name: string; address: string }[]; +} + +/** Decode portable nm columns or Apple's detailed section and binding output. */ +export function globalDefinitions(text: string, apple: boolean) { + assert(Buffer.byteLength(text) <= 64 * 1024 * 1024, 'nm output exceeds 64 MiB'); + const definitions = new Map(); + for (const raw of text.split(/\r?\n/u)) { + const fields = raw.trim().split(/\s+/u); + if (fields.length < 2) continue; + let type = fields[fields.length - 2]; + const external = fields[fields.length - 1]; + if (apple) { + // Mach-O BSD output prints weak text as T; -m preserves its weak binding. + const attributes = fields.slice(2, -1); + if ( + !/^[0-9a-f]+$/iu.test(fields[0]) || + !attributes.includes('external') || + attributes.includes('non-external') + ) + continue; + const textSection = fields[1] === '(__TEXT,__text)'; + type = attributes.includes('weak') ? (textSection ? 'W' : 'V') : textSection ? 'T' : 'D'; + } + if (!/^[A-Z]$/u.test(type) || type === 'U') continue; + const name = apple && external.startsWith('_') ? external.slice(1) : external; + if (!identifier.test(name)) continue; + const previous = definitions.get(name); + // C++ template instantiations may repeat weak definitions in ordinary + // archives. They are not SQL registrations; repeated strong symbols fail. + assert( + previous === undefined || (previous === type && (type === 'W' || type === 'V')), + `static archive repeats global definition ${name}`, + ); + definitions.set(name, type); + } + return definitions; +} + +export function deriveStaticRegistration( + sqlName: string, + nativeModuleStem: string, + text: string, + apple: boolean, + aliases: { name: string; address: string }[] = [], +): StaticRegistration { + assert(portable.test(sqlName), 'SQL member name must be portable'); + const prefix = staticSymbolPrefix(nativeModuleStem); + const definitions = globalDefinitions(text, apple); + const magicSymbol = `${prefix}_Pg_magic_func`; + const init = `${prefix}__PG_init`; + assert.equal( + definitions.get(magicSymbol), + 'T', + 'static member lacks its prefixed magic function', + ); + assert( + !definitions.has('Pg_magic_func') && !definitions.has('_PG_init'), + 'static member retains an unprefixed PostgreSQL hook', + ); + if (definitions.has(init)) + assert.equal(definitions.get(init), 'T', 'static init hook must be a function'); + const symbols = [...definitions] + .filter(([name, type]) => type === 'T' && !name.startsWith(`${prefix}_`)) + .map(([name]) => ({ name, address: name })); + for (const alias of aliases) { + assert( + identifier.test(alias.name) && identifier.test(alias.address), + 'registration alias must contain C identifiers', + ); + assert.notEqual(alias.name, alias.address, 'registration alias must change the linked address'); + assert.equal( + definitions.get(alias.address), + 'T', + `registration alias address ${alias.address} must be a defined function`, + ); + } + symbols.push(...aliases); + symbols.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0)); + assert.equal( + new Set(symbols.map(({ name }) => name)).size, + symbols.length, + 'static registration repeats a SQL symbol', + ); + assertStaticMemberAliases(sqlName, nativeModuleStem, aliases); + assert( + symbols.length > 0 || definitions.has(init), + 'static member has neither SQL functions nor an init hook', + ); + assertDefinedRegistrationAddresses(symbols, new Set(definitions.keys()), sqlName); + return { + schema: 'oliphaunt-ios-extension-registration-v1', + sqlName, + nativeModuleStem, + magicSymbol, + initSymbol: definitions.has(init) ? init : null, + symbols, + }; +} + +/** This unit links against oliphaunt.h; it does not duplicate the public ABI. */ +export function staticRegistrySource(registrations: StaticRegistration[]) { + assert(registrations.length > 0, 'a static registry requires actual compiled members'); + const ordered = [...registrations].sort((a, b) => + a.sqlName < b.sqlName ? -1 : a.sqlName > b.sqlName ? 1 : 0, + ); + assert.equal( + new Set(ordered.map((row) => row.nativeModuleStem)).size, + ordered.length, + 'static registry repeats a module', + ); + const lines = [ + '/* Generated from declared target archive definitions. */', + '#include ', + '#include "oliphaunt.h"', + '', + ]; + const addresses = new Set(); + for (const row of ordered) { + assert.equal(row.magicSymbol, `${staticSymbolPrefix(row.nativeModuleStem)}_Pg_magic_func`); + assert.equal( + row.initSymbol === null || + row.initSymbol === `${staticSymbolPrefix(row.nativeModuleStem)}__PG_init`, + true, + ); + lines.push(`extern const void *${row.magicSymbol}(void);`); + if (row.initSymbol) lines.push(`extern void ${row.initSymbol}(void);`); + for (const { name, address } of row.symbols) { + assert(identifier.test(name) && identifier.test(address)); + if (!addresses.has(address)) lines.push(`extern void ${address}(void);`); + addresses.add(address); + } + } + for (const row of ordered) { + if (row.symbols.length === 0) continue; + const prefix = staticSymbolPrefix(row.nativeModuleStem); + lines.push('', `static const OliphauntStaticExtensionSymbol ${prefix}_symbols[] = {`); + for (const { name, address } of row.symbols) + lines.push(` { .name = "${name}", .address = (void *)${address} },`); + lines.push('};'); + } + lines.push('', 'static const OliphauntStaticExtension liboliphaunt_static_extensions[] = {'); + for (const row of ordered) { + const symbols = + row.symbols.length === 0 ? 'NULL' : `${staticSymbolPrefix(row.nativeModuleStem)}_symbols`; + const count = row.symbols.length === 0 ? '0' : `sizeof(${symbols}) / sizeof(${symbols}[0])`; + lines.push( + ' {', + ' .abi_version = OLIPHAUNT_STATIC_EXTENSION_ABI_VERSION,', + ` .name = "${row.nativeModuleStem}",`, + ` .magic = ${row.magicSymbol},`, + ` .init = ${row.initSymbol ?? 'NULL'},`, + ` .symbols = ${symbols},`, + ` .symbol_count = ${count},`, + ' .reserved_flags = 0,', + ' },', + ); + } + lines.push( + '};', + '', + 'const OliphauntStaticExtension *liboliphaunt_selected_static_extensions(size_t *count) {', + ' if (count != NULL) {', + ' *count = sizeof(liboliphaunt_static_extensions) / sizeof(liboliphaunt_static_extensions[0]);', + ' }', + ' return liboliphaunt_static_extensions;', + '}', + '', + ); + return lines.join('\n'); +} + +if (import.meta.main) { + assert.equal(process.argv.length, 3, 'usage: mobile_registration.mts '); + const spec = JSON.parse(readFileSync(process.argv[2], 'utf8')); + if (spec.registrations) { + writeFileSync( + spec.source, + staticRegistrySource( + spec.registrations.map((file: string) => JSON.parse(readFileSync(file, 'utf8'))), + ), + ); + process.exit(0); + } + if (spec.nm) { + const result = Bun.spawnSync( + [spec.nm, ...(spec.apple ? ['-g', '-U', '-m'] : ['-g', '--defined-only']), spec.archive], + { env: { LC_ALL: 'C', LANG: 'C' }, stdout: 'pipe', stderr: 'pipe' }, + ); + assert.equal(result.exitCode, 0, `declared nm failed: ${result.stderr.toString('utf8')}`); + writeFileSync(spec.symbols, result.stdout); + } + const registration = deriveStaticRegistration( + spec.sqlName, + spec.stem, + readFileSync(spec.symbols, 'utf8'), + spec.apple, + spec.aliases, + ); + writeFileSync(spec.registration, `${JSON.stringify(registration, null, 2)}\n`); + writeFileSync(spec.source, staticRegistrySource([registration])); +} diff --git a/build_defs/extensions/mobile_registration.test.mts b/build_defs/extensions/mobile_registration.test.mts new file mode 100644 index 000000000..7211c1062 --- /dev/null +++ b/build_defs/extensions/mobile_registration.test.mts @@ -0,0 +1,168 @@ +import { describe, expect, test } from 'bun:test'; +import { staticMemberAliases } from '../../src/extensions/artifacts/native/tools/ios-extension-registration.mts'; +import { + deriveStaticRegistration, + globalDefinitions, + staticRegistrySource, +} from './mobile_registration.mts'; + +const llvm = `member.o:\n0000000000000000 T oliphaunt_static_cube_Pg_magic_func\n0000000000000040 T cube_in\n0000000000000080 T pg_finfo_cube_in\n U palloc\n0000000000000020 t internal\n0000000000000100 D cube_data\n`; +const apple = `member.o:\n0000000000000000 (__TEXT,__text) external _oliphaunt_static_cube_Pg_magic_func\n0000000000000040 (__TEXT,__text) external _cube_in\n0000000000000080 (__TEXT,__text) external _pg_finfo_cube_in\n0000000000000100 (__DATA,__data) external _cube_data\n`; +describe('actual mobile archive registration', () => { + test('uses global functions and preserves the ELF underscore spelling', () => { + const row = deriveStaticRegistration('cube', 'cube', llvm, false); + expect(row.initSymbol).toBeNull(); + expect(row.symbols).toEqual([ + { name: 'cube_in', address: 'cube_in' }, + { name: 'pg_finfo_cube_in', address: 'pg_finfo_cube_in' }, + ]); + expect(globalDefinitions('00000000 T _call\n', false).has('_call')).toBe(true); + }); + test('Apple removes exactly its external-symbol underscore', () => { + expect(deriveStaticRegistration('cube', 'cube', apple, true)).toEqual( + deriveStaticRegistration('cube', 'cube', llvm, false), + ); + expect(globalDefinitions('00000000 (__TEXT,__text) external __call\n', true).has('_call')).toBe( + true, + ); + }); + test('coalesces repeated weak archive definitions without registering them', () => { + const text = `${llvm}0 W template_instantiation\n0 W template_instantiation\n0 V weak_data\n0 V weak_data\n`; + expect(deriveStaticRegistration('cube', 'cube', text, false)).toEqual( + deriveStaticRegistration('cube', 'cube', llvm, false), + ); + expect(() => globalDefinitions('0 W collision\n1 T collision\n', false)).toThrow( + 'repeats global', + ); + }); + test('Darwin output preserves weak private bindings and rejects strong or mixed collisions', () => { + // Captured from real Clang 21 Mach-O arm64 objects with nm -g -U -m. + const weak = `000000000000002c (__TEXT,__text) weak private external __ZNSt12length_errorC1B9nqe210106EPKc\n0000000000000088 (__DATA,__data) weak external _weak_data\n0000000000000060 (__TEXT,__text) weak external _weak_function\n`; + expect(deriveStaticRegistration('cube', 'cube', apple + weak + weak, true)).toEqual( + deriveStaticRegistration('cube', 'cube', apple, true), + ); + expect(globalDefinitions(weak, true).get('_ZNSt12length_errorC1B9nqe210106EPKc')).toBe('W'); + expect( + globalDefinitions('0 (__TEXT,__text) non-external (was a private external) _local\n', true) + .size, + ).toBe(0); + for (const bindings of [ + ['external', 'external'], + ['weak external', 'external'], + ['external', 'weak external'], + ]) + expect(() => + globalDefinitions( + bindings + .map((binding, index) => `${index} (__TEXT,__text) ${binding} _collision\n`) + .join(''), + true, + ), + ).toThrow('repeats global'); + for (const name of ['weak', 'external']) + expect(() => + globalDefinitions( + `0 (__TEXT,__text) external ${name}\n1 (__TEXT,__text) external ${name}\n`, + true, + ), + ).toThrow('repeats global'); + expect(() => + deriveStaticRegistration( + 'cube', + 'cube', + apple.replace( + 'external _oliphaunt_static_cube_Pg_magic_func', + 'weak external _oliphaunt_static_cube_Pg_magic_func', + ), + true, + ), + ).toThrow('magic'); + expect(() => + deriveStaticRegistration( + 'cube', + 'cube', + `${apple}0 (__TEXT,__text) external _Pg_magic_func\n`, + true, + ), + ).toThrow('unprefixed'); + }); + test('an init-only member has a null function table', () => { + const row = deriveStaticRegistration( + 'auto_explain', + 'auto_explain', + '0 T oliphaunt_static_auto_explain_Pg_magic_func\n1 T oliphaunt_static_auto_explain__PG_init\n', + false, + ); + expect(row.symbols).toEqual([]); + expect(staticRegistrySource([row])).toContain('.symbols = NULL,\n .symbol_count = 0,'); + }); + test('PostGIS aliases point to actual prefixed definitions', () => { + const aliases = [ + { name: 'difference', address: 'oliphaunt_static_postgis_3_difference' }, + { name: 'pg_finfo_difference', address: 'pg_finfo_oliphaunt_static_postgis_3_difference' }, + ]; + const text = + '0 T oliphaunt_static_postgis_3_Pg_magic_func\n1 T oliphaunt_static_postgis_3_difference\n2 T pg_finfo_oliphaunt_static_postgis_3_difference\n'; + const row = deriveStaticRegistration('postgis', 'postgis-3', text, false, aliases); + expect(row.symbols).toContainEqual(aliases[0]); + expect(row.symbols).toContainEqual(aliases[1]); + expect(() => + deriveStaticRegistration('postgis', 'postgis-3', text.replace('1 T', '1 D'), false, aliases), + ).toThrow('defined function'); + expect(staticMemberAliases('postgis', 'postgis-3')).toEqual(aliases); + for (const apple of [false, true]) { + const symbols = apple ? text.replaceAll(' T ', ' (__TEXT,__text) external _') : text; + expect(deriveStaticRegistration('postgis', 'postgis-3', symbols, apple, aliases)).toEqual( + row, + ); + for (const incorrect of [ + [], + aliases.slice(0, 1), + [...aliases, { name: 'extra', address: aliases[0].address }], + ]) + expect(() => + deriveStaticRegistration('postgis', 'postgis-3', symbols, apple, incorrect), + ).toThrow('canonical namespace'); + const wrong = aliases.map((alias) => ({ ...alias, address: `${alias.address}_wrong` })); + const wrongSymbols = `${symbols}${wrong.map(({ address }) => `3 ${apple ? '(__TEXT,__text) external _' : 'T '}${address}\n`).join('')}`; + expect(() => + deriveStaticRegistration('postgis', 'postgis-3', wrongSymbols, apple, wrong), + ).toThrow('canonical namespace'); + } + expect(staticMemberAliases('cube', 'cube')).toEqual([]); + expect(staticMemberAliases('pgtap', null)).toEqual([]); + }); + test('rejects incomplete, duplicate and unprefixed hooks', () => { + expect(() => + deriveStaticRegistration( + 'cube', + 'cube', + llvm.replace( + 'T oliphaunt_static_cube_Pg_magic_func', + 'U oliphaunt_static_cube_Pg_magic_func', + ), + false, + ), + ).toThrow('magic'); + expect(() => + deriveStaticRegistration('cube', 'cube', `${llvm}0 T Pg_magic_func\n`, false), + ).toThrow('unprefixed'); + expect(() => deriveStaticRegistration('cube', 'cube', `${llvm}0 T cube_in\n`, false)).toThrow( + 'repeats global', + ); + expect(() => + deriveStaticRegistration('cube', 'cube', llvm, false, [ + { name: 'cube_in', address: 'pg_finfo_cube_in' }, + ]), + ).toThrow('repeats a SQL symbol'); + }); + test('generated source uses the public ABI with the actual magic and addresses', () => { + const row = deriveStaticRegistration('cube', 'cube', llvm, false); + const source = staticRegistrySource([row]); + expect(source).toContain('#include "oliphaunt.h"'); + expect(source).toContain('.magic = oliphaunt_static_cube_Pg_magic_func,'); + expect(source).toContain('{ .name = "cube_in", .address = (void *)cube_in },'); + expect(source).toContain('OLIPHAUNT_STATIC_EXTENSION_ABI_VERSION'); + expect(() => staticRegistrySource([row, row])).toThrow('repeats a module'); + }); +}); diff --git a/build_defs/extensions/native_carrier_install_helpers.mts b/build_defs/extensions/native_carrier_install_helpers.mts new file mode 100644 index 000000000..0c3746007 --- /dev/null +++ b/build_defs/extensions/native_carrier_install_helpers.mts @@ -0,0 +1,327 @@ +/** Installed native carrier qualification shared across member and bundle tests. */ +import { CString, dlopen } from 'bun:ffi'; +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + cpSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + realpathSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { readPortableArchiveEntries } from '../../tools/packaging/portable-archive.mts'; + +const digest = (data: Uint8Array) => createHash('sha256').update(data).digest('hex'); + +export function readNativeCargoPayload( + directory: string, + leaf: string, + version: string, + licenses: string[] = ['MIT'], +) { + const cargoPayload = new Map(); + const chunks = new Map(); + const parts: string[] = []; + let parentDependencies: Record = {}; + let parent = false; + for (const file of readdirSync(realpathSync(directory)).filter((name) => + name.endsWith('.crate'), + )) { + const archive = readPortableArchiveEntries(realpathSync(path.join(directory, file))); + const prefix = file.slice(0, -6); + const cargo = Bun.TOML.parse(archive.get(`${prefix}/Cargo.toml`)!.data().toString('utf8')); + assert.equal(cargo.package.version, version); + if (cargo.package.name === leaf) { + parent = true; + parentDependencies = cargo['build-dependencies'] ?? {}; + } else { + assert( + cargo.package.name.startsWith(`${leaf}-part-`) && + /-part-[0-9]{3}$/u.test(cargo.package.name), + 'undeclared Cargo payload identity', + ); + parts.push(cargo.package.name); + } + for (const license of licenses) assert(cargo.package.license.includes(license)); + for (const [name, entry] of archive) + if (name.startsWith(`${prefix}/payload/`) && entry.isFile) { + let relative = name.slice(`${prefix}/payload/`.length); + if (relative.startsWith('chunks/')) { + const match = /^(.*)\.part([0-9]{3})$/u.exec(relative.slice('chunks/'.length)); + assert(match, 'invalid split Cargo chunk name'); + const rows = chunks.get(match[1]) ?? []; + rows.push({ index: Number(match[2]), bytes: entry.data() }); + chunks.set(match[1], rows); + continue; + } + if (relative.startsWith('files/')) relative = relative.slice('files/'.length); + assert( + !cargoPayload.has(relative), + 'Cargo payload parts must not duplicate file ownership', + ); + cargoPayload.set(relative, digest(entry.data())); + } + } + assert(parent, 'missing canonical Cargo parent carrier'); + assert.deepEqual( + parts.sort(), + parts.map((_, index) => `${leaf}-part-${String(index + 1).padStart(3, '0')}`), + ); + assert.deepEqual( + Object.keys(parentDependencies) + .filter((name) => name.startsWith(`${leaf}-part-`)) + .sort(), + parts, + ); + for (const name of parts) assert.equal(parentDependencies[name].version, `=${version}`); + for (const [relative, rows] of chunks) { + assert(!cargoPayload.has(relative), 'split and whole Cargo payload ownership overlap'); + rows.sort((a, b) => a.index - b.index); + assert.deepEqual( + rows.map((row) => row.index), + rows.map((_, index) => index), + 'Cargo chunks must have contiguous unique indexes', + ); + const hash = createHash('sha256'); + for (const row of rows) hash.update(row.bytes); + cargoPayload.set(relative, hash.digest('hex')); + } + return cargoPayload; +} + +export function writableDirectories(directory: string) { + chmodSync(directory, 0o755); + for (const row of readdirSync(directory, { withFileTypes: true })) + if (row.isDirectory()) writableDirectories(path.join(directory, row.name)); +} + +export function extractNativeArchive(file: string, directory: string, prefix = '') { + mkdirSync(directory, { recursive: true }); + for (const [name, entry] of readPortableArchiveEntries(realpathSync(file))) { + if (!entry.isFile || !name.startsWith(prefix)) continue; + const output = path.join(directory, name.slice(prefix.length)); + mkdirSync(path.dirname(output), { recursive: true }); + writeFileSync(output, entry.data()); + chmodSync(output, entry.mode); + } +} + +export function runNative(args: string[], env: Record, stdin?: string) { + const result = Bun.spawnSync(args, { + env: { ...process.env, ...env }, + stdin: stdin === undefined ? 'ignore' : Buffer.from(stdin), + stdout: 'pipe', + stderr: 'pipe', + }); + const output = result.stdout.toString() + result.stderr.toString(); + assert.equal(result.exitCode, 0, `${args[0]} failed: ${output}`); + assert(!output.includes('ERROR:') && !output.includes('FATAL:'), output); + return output; +} + +export async function prepareNativeCarrierSdk({ + root, + runtimeFile, + npmFiles, + runtimeVersion, + selected, +}: { + root: string; + runtimeFile: string; + npmFiles: string[]; + runtimeVersion: string; + selected: string[]; +}) { + const sdk = path.join(root, 'node_modules/@oliphaunt/ts'); + cpSync(path.resolve(import.meta.dirname, '../../src/native/sdks/ts'), sdk, { recursive: true }); + writableDirectories(sdk); + const packages = npmFiles.map((file) => { + const entries = readPortableArchiveEntries(realpathSync(file)); + const manifest = JSON.parse(entries.get('package/package.json')!.data().toString('utf8')); + const directory = path.join(root, 'node_modules', manifest.name); + extractNativeArchive(file, directory, 'package/'); + return { manifest, directory }; + }); + const runtime = path.join(root, 'host'); + mkdirSync(runtime, { recursive: true }); + runNative(['tar', '-xf', realpathSync(runtimeFile), '-C', runtime], {}); + const library = path.join(runtime, 'lib/liboliphaunt.so'); + const ffi = dlopen(library, { oliphaunt_version: { args: [], returns: 'ptr' } }); + try { + assert.equal( + new CString(ffi.symbols.oliphaunt_version()).toString(), + runtimeVersion, + 'actual incorporated supplier identity differs from extension host pin', + ); + } finally { + ffi.close(); + } + const sdkManifestFile = path.join(sdk, 'package.json'); + const sdkManifestBytes = readFileSync(sdkManifestFile); + const sdkManifest = JSON.parse(sdkManifestBytes.toString('utf8')); + const sdkRuntimeVersion = sdkManifest.oliphaunt.liboliphauntVersion; + const assets = await import(pathToFileURL(path.join(sdk, 'src/native/assets.ts')).href); + const install = { libraryPath: library, runtimeDirectory: runtime }; + if (sdkRuntimeVersion !== runtimeVersion) { + await assert.rejects( + () => assets.materializeExtensionInstall(install, selected), + /does not match @oliphaunt\/ts liboliphauntVersion/, + 'source SDK must reject a carrier outside its unchanged declared host requirement', + ); + console.log( + `Source SDK host ${sdkRuntimeVersion} rejects extension host ${runtimeVersion}; constructor SQL uses the explicit runtime-directory API. Default adoption requires the generated SDK and frozen installed consumers.`, + ); + } + const extensionRuntime = await import( + pathToFileURL(path.join(sdk, 'src/native/extension-runtime.ts')).href + ); + const materialize = async (extensions: string[]) => { + assert.deepEqual(readFileSync(sdkManifestFile), sdkManifestBytes, 'SDK manifest was altered'); + if (sdkRuntimeVersion === runtimeVersion) + return assets.materializeExtensionInstall(install, extensions); + // A producer can change before release preparation adopts its exact host in + // an independently versioned SDK. Qualify those real bytes through the + // supported explicit-runtime API without changing any SDK requirements. + const selected = extensionRuntime.selectedExtensionClosure(extensions) as string[]; + const stage = mkdtempSync(path.join(tmpdir(), 'native-explicit-extension-')); + const runtimeDirectory = path.join(stage, 'runtime'); + try { + cpSync(runtime, runtimeDirectory, { recursive: true }); + for (const sqlName of selected) { + const owners = packages.filter(({ manifest }) => + manifest.oliphaunt.members.includes(sqlName), + ); + assert.equal( + owners.length, + 1, + `selected extension ${sqlName} has no unique installed carrier`, + ); + const { manifest, directory } = owners[0]; + const relative = + manifest.oliphaunt.memberRuntimeRelativePaths?.[sqlName] ?? + manifest.oliphaunt.runtimeRelativePath; + assert.equal( + typeof relative, + 'string', + `selected extension ${sqlName} has no runtime payload`, + ); + cpSync(assets.resolvePackageRelativePath(directory, relative, sqlName), runtimeDirectory, { + recursive: true, + }); + } + const prepared = await assets.prepareExtensionInstall( + { ...install, runtimeDirectory, packageManaged: false }, + extensions, + { explicitRuntimeDirectory: true }, + ); + assert.deepEqual(readFileSync(sdkManifestFile), sdkManifestBytes, 'SDK manifest was altered'); + return prepared; + } catch (error) { + rmSync(stage, { recursive: true, force: true }); + throw error; + } + }; + return { assets, install, runtime, packages, materialize, sdkRuntimeVersion }; +} + +export function exerciseNativeCarrierSql({ + root, + runtime, + materialized, + consumerFile, + plans, + environment = [], +}: { + root: string; + runtime: string; + materialized: { runtimeDirectory: string; moduleDirectory: string }; + consumerFile: string; + plans: string[]; + environment?: { name: string; path: string }[]; +}) { + const [installSql, smokeSql, startupFile] = plans; + const consumer = path.join(root, 'consumer'); + cpSync(realpathSync(consumerFile), consumer); + chmodSync(consumer, 0o755); + const env: Record = { + LD_LIBRARY_PATH: path.join(runtime, 'lib'), + OLIPHAUNT_SMOKE_MODULE_DIR: materialized.moduleDirectory, + OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY: '1', + OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY: '1', + }; + for (const row of environment) env[row.name] = path.join(materialized.runtimeDirectory, row.path); + const initialize = (database: string) => { + mkdirSync(database, { recursive: true }); + runNative( + [ + path.join(runtime, 'bin/initdb'), + '-D', + path.join(database, 'pgdata'), + '-U', + 'postgres', + '--auth=trust', + '--no-sync', + '--locale-provider=libc', + '--locale=C', + '--encoding=UTF8', + ], + env, + ); + writeFileSync( + path.join(database, '.oliphaunt.json'), + JSON.stringify({ + schema: 'oliphaunt-database-root-v1', + engineFamily: 'native', + pgdata: 'pgdata', + postgresMajor: 18, + physicalFormat: 'native-pg18-v1', + }), + ); + }; + const embedded = path.join(root, 'embedded'); + initialize(embedded); + for (let restart = 0; restart < 2; restart++) + runNative( + [ + consumer, + path.join(embedded, 'pgdata'), + materialized.runtimeDirectory, + '--sql-plan', + realpathSync(installSql), + realpathSync(smokeSql), + realpathSync(startupFile), + ], + env, + ); + const server = path.join(root, 'server'); + initialize(server); + const sql = [installSql, smokeSql] + .map((file) => readFileSync(file, 'utf8').replace(/^-- oliphaunt-statement$/gmu, '')) + .join('\n'); + const startup = readFileSync(startupFile, 'utf8') + .trim() + .split('\n') + .filter(Boolean) + .flatMap((assignment) => ['-c', assignment]); + const output = runNative( + [ + path.join(materialized.runtimeDirectory, 'bin/postgres'), + '--single', + '-j', + '-D', + path.join(server, 'pgdata'), + ...startup, + 'postgres', + ], + env, + sql, + ); + assert(output.includes('candidate-extension-smoke-ok')); +} diff --git a/build_defs/extensions/native_carriers.bzl b/build_defs/extensions/native_carriers.bzl new file mode 100644 index 000000000..36d6943d7 --- /dev/null +++ b/build_defs/extensions/native_carriers.bzl @@ -0,0 +1,180 @@ +"""Selected desktop extension final envelopes from their typed member producers.""" + +load("@oliphaunt_metadata//:metadata.bzl", "EXTENSIONS", "EXTENSION_COMPATIBILITY", "EXTENSION_DEPENDENCIES", "EXTENSION_RECIPES", "EXTENSION_RELEASE_METADATA", "EXTENSION_SOURCES", "PRODUCTS", "PUBLICATION_CARRIERS") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action", "bun_script_test") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") +load("//build_defs/release:supplier.bzl", "ShippingSupplierInfo") +load(":extensions.bzl", "ExtensionMemberInfo", "extension_identity") +load(":final_leaf.bzl", "ExtensionFinalLeafInfo") +load(":platforms.bzl", "NATIVE_EXTENSION_COMPATIBLE", "NATIVE_EXTENSION_LINUX_COMPATIBLE") +load(":smoke.bzl", "extension_smoke_plan") + +_LINUX_TARGETS = {"//build_defs/native:linux_x86_64": "linux-x64-gnu", "//build_defs/native:linux_aarch64_gnu_2_28": "linux-arm64-gnu"} +_TARGETS = _LINUX_TARGETS | {"//build_defs/native:macos_arm64": "macos-arm64", "//build_defs/native:windows_x64": "windows-x64-msvc"} + +def native_extension_carrier_helpers(): + return [ + "//build_defs/extensions:validate_member_payload.mts", + "//:src/extensions/artifacts/native/tools/stage-windows-binary-contract.mts", + "//src/database-resources:seeds/carrier-identities.mts", + "//:src/extensions/artifacts/packages/tools/contrib-carriers.mts", + "//:src/extensions/artifacts/packages/tools/extension-artifact-inventory.mts", + "//:src/extensions/artifacts/packages/tools/extension-registry-packages.mts", + "//:src/extensions/artifacts/packages/tools/extension-runtime-asset-contract.mts", + "//:src/extensions/artifacts/packages/tools/package-extension-release-carriers.mts", + "//src/extensions/contracts:extension-target-profiles.mts", + "//src/extensions/contracts:wasix-extension-install.mts", + "//src/extensions/contracts:extension-artifact-archive-policy.properties", + "//src/extensions/tools:extension-artifact-archive-policy.mts", + "//src/extensions/tools:extension-upstream-licenses.mts", + "//build_defs/extensions/compiler_rt:source.json", + "//src/native/mobile-bindings:tools/dependency-license-contract.mts", + "//src/native/sdks/swift:tools/ios-carrier-manifest.mts", + "//src/native/sdks/swift:tools/native-legal-source-basis.mts", + "//src/native/sdks/swift:tools/swift-native-carrier-contract.mts", + "//src/native/sdks/ts:src/native/extension-contract.ts", + "//src/wasix/runtime:tools/check-release-assets.mts", + "//src/wasix/runtime:tools/wasix-aot-manifest.mts", + "//src/wasix/runtime:tools/wasix-cargo-artifact-contract.mts", + "//src/wasix/runtime:tools/wasix-cargo-toolchain-policy.mts", + "//src/wasix/runtime:tools/wasix-runtime-npm-contract.mts", + "//:tools/packaging/archive-directory.mts", + "//:tools/packaging/cargo-manifest.mts", + "//:tools/packaging/cargo-source-package.mts", + "//:tools/packaging/npm-package.mts", + "//:tools/packaging/npm-trusted-publishing.mts", + "//:tools/packaging/package-archive.mts", + "//:tools/packaging/platform-binary-contract.mts", + "//:tools/packaging/portable-archive.mts", + "//:tools/packaging/release-directory-safety.mts", + "//:tools/packaging/release-notices.mts", + "//:tools/packaging/rust-build-script-sha256.mts", + "//:tools/packaging/rust-dependency-license-contract.mts", + "//:tools/packaging/windows-vc-runtime-closure.mts", + "//:tools/packaging/windows-vc-runtime-policy.json", + "//tools/release:compatibility-version-parser.mts", + "//tools/release:extension-release-metadata.mts", + "//tools/release:platform-compatibility-policy.mts", + "//tools/release:release-artifact-targets.mts", + "//tools/release:release-graph.mts", + "//tools/release:release-history.mts", + ] + +def native_extension_carrier_legal(sql_name): + inputs = ["//:LICENSE", "//:THIRD_PARTY_NOTICES.md"] + package = "//src/extensions/external/" + sql_name + ":" + inputs += [package + name for name in ["release.toml", "source.toml", "upstream-license-data.json"]] + if sql_name in EXTENSION_RECIPES: + inputs.append(package + "recipe.toml") + # Each audited license source is checked against its immutable source manifest. + inputs += [package + "dependencies/" + name + "/source.toml" for name in EXTENSION_DEPENDENCIES.get(sql_name, {})] + return inputs + +def native_external_carrier_metadata(sql_name, target, products = PRODUCTS): + product = EXTENSION_SOURCES[sql_name]["product"] + release = [row for row in EXTENSION_RELEASE_METADATA if row["sqlName"] == sql_name] + if len(release) != 1: + fail("external final carrier requires exactly one canonical release metadata row") + return {"product": product, "version": products[product]["version"], "sqlName": sql_name, "target": target, "runtimeVersion": EXTENSION_COMPATIBILITY[sql_name]["native_runtime_version"], + "descriptor": EXTENSIONS[sql_name], "recipe": EXTENSION_RECIPES.get(sql_name, {}), "source": EXTENSION_SOURCES[sql_name], + "selectedDependencies": sorted([name for name in EXTENSIONS[sql_name].get("dependencies", []) if name in EXTENSIONS]), + "compatibility": EXTENSION_COMPATIBILITY[sql_name], "releaseMetadata": release[0], "carriers": [row for row in PUBLICATION_CARRIERS if row["product"] == product]} + +def _leaf(spec, ecosystem): + facades = [row for row in spec["carriers"] if row["ecosystem"] == "npm" and row["target"] == None] + if len(facades) != 1: + fail("native extension envelope requires exactly its canonical npm facade") + name = (facades[0]["name"] if ecosystem == "npm" else spec["product"]) + "-" + spec["target"] + rows = [row for row in spec["carriers"] if row["ecosystem"] == ecosystem and row["target"] == spec["target"] and row["name"] == name] + if len(rows) != 1: + fail("native extension envelope must have exactly one canonical " + ecosystem + " identity") + return rows[0] + +def _carriers_impl(ctx): + member = ctx.attr.member[ExtensionMemberInfo] + spec = native_external_carrier_metadata(member.sql_name, member.configuration) + if spec["product"] != member.owner: + fail("final extension envelope owner differs from its canonical member producer") + github = ctx.actions.declare_file(spec["product"] + "-" + spec["version"] + "-native-" + member.configuration + "-runtime.tar.gz") + npm = ctx.actions.declare_file(_leaf(spec, "npm")["name"].replace("@", "").replace("/", "-") + "-" + spec["version"] + ".tgz") + cargo = ctx.actions.declare_directory(ctx.label.name + "/cargo") + manifest = ctx.actions.declare_file(ctx.label.name + "/" + spec["product"] + "-" + spec["version"] + "-manifest.json") + frozen = ctx.actions.declare_file(ctx.label.name + "/extension-artifacts.json") + spec.update({"archive": member.archive.path, "outputs": {"github": github.path, "npm": npm.path, "cargo": cargo.path, "manifest": manifest.path, "frozen": frozen.path}}) + inputs = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(inputs, json.encode(spec)) + bun_file_action(ctx, ctx.file._tool, arguments = [inputs.path], inputs = [member.archive, member.inventory, inputs] + ctx.files.legal, + source_files = [ctx.file._tool] + ctx.files._helpers + ctx.files.legal, + outputs = [github, npm, cargo, manifest, frozen], mnemonic = "NativeExtensionEnvelopes") + return [DefaultInfo(files = depset([github, npm, cargo, manifest, frozen])), ctx.attr.member[ShippingSupplierInfo], + ExtensionFinalLeafInfo(product = spec["product"], owner = member.owner, version = spec["version"], family = "native", target = member.configuration, metadata = spec, github = [github], npm = [npm], cargo = [cargo], manifest = manifest, frozen = frozen, spec = inputs, validation = None, receipt = None, origin = None), + OutputGroupInfo(github = depset([github]), npm = depset([npm]), cargo = depset([cargo]), manifest = depset([manifest]), frozen = depset([frozen]), spec = depset([inputs]))] + +_native_extension_carriers = rule(implementation = _carriers_impl, toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = {"member": attr.label(mandatory = True, providers = [ExtensionMemberInfo, ShippingSupplierInfo]), "legal": attr.label_list(allow_files = True), + "_tool": attr.label(default = "//build_defs/extensions:native_carriers.mts", allow_single_file = True), + "_helpers": attr.label_list(default = native_extension_carrier_helpers(), allow_files = True)}) + +def native_external_extension_carriers(sql_name, member = ":native_payload", additional_qualification = []): + # PostGIS's foreign dependency recipes are not inherited from generic desktop modules. + targets = _TARGETS + compatible = NATIVE_EXTENSION_COMPATIBLE + _native_extension_carriers(name = "native_carriers", member = member, legal = native_extension_carrier_legal(sql_name), target_compatible_with = compatible) + metadata = {condition: native_external_carrier_metadata(sql_name, target) for condition, target in targets.items()} + packages = [] + for ecosystem in ["github", "npm", "cargo"]: + name = "native_" + ecosystem + "_shipping" + native.filegroup(name = name + "_files", srcs = [":native_carriers"], output_group = ecosystem) + names, roles = {}, {} + for condition, spec in metadata.items(): + if ecosystem == "github": + names[condition] = spec["product"] + "-" + spec["version"] + "-native-" + spec["target"] + "-runtime.tar.gz" + roles[condition] = "github-release-asset" + else: + row = _leaf(spec, ecosystem) + names[condition], roles[condition] = row["name"], row["role"] + shipping_package(name = name, owner = extension_identity(sql_name), artifacts = [":" + name + "_files"], ecosystem = ecosystem, + package_name = select(names), configuration = select(targets), role = select(roles), suppliers = ":native_carriers", target_compatible_with = compatible) + packages.append(":" + name) + # These selected-target rows are inputs to owner-wide release assembly. A + # single target's manifest cannot advertise the complete release asset set. + for group in ["manifest", "frozen"]: + name = "native_" + group + "_shipping" + native.filegroup(name = name + "_files", srcs = [":native_carriers"], output_group = group) + shipping_package(name = name, owner = extension_identity(sql_name), artifacts = [":" + name + "_files"], ecosystem = "internal", + package_name = sql_name + "-native-" + group, configuration = select(targets), role = "extension-release-" + group + "-input", suppliers = ":native_carriers", target_compatible_with = compatible) + packages.append(":" + name) + shipping_export(name = "native_shipping_export", packages = packages, qualification = select({ + condition: [":native_carriers_test"] if target.startswith("linux-") else [ + "//build_defs/extensions:desktop_all_final_contract_test", + "//build_defs/extensions:desktop_all_members_frozen_sql_test", + ] for condition, target in targets.items() + }) + additional_qualification, testonly = True, target_compatible_with = compatible) + native.filegroup(name = "native_carrier_spec", srcs = [":native_carriers"], output_group = "spec") + extension_smoke_plan(name = "native_final_plan", members = [member], fixtures = ["//src/test-fixtures/extensions:sql"]) + plans = [] + for group in ["install", "smoke", "startup"]: + native.filegroup(name = "native_final_" + group, srcs = [":native_final_plan"], output_group = group) + plans.append(":native_final_" + group) + inputs = [":native_carrier_spec", ":native_github_shipping_files", ":native_npm_shipping_files", ":native_cargo_shipping_files", "//src/native/runtime:runtime_payload", "//build_defs/extensions:native_extension_smoke"] + plans + inputs += [":native_manifest_shipping_files", ":native_frozen_shipping_files"] + bun_script_test(name = "native_carriers_test", entry_point = "//build_defs/extensions:native_carriers_installed.test.mts", + args = ["$(location %s)" % label for label in inputs], + data = inputs + native_extension_carrier_helpers() + native_extension_carrier_legal(sql_name) + ["//src/native/sdks/ts:native_asset_sources", "//build_defs/extensions:native_carriers.mts", "//build_defs/extensions:native_carrier_install_helpers.mts"], + target_compatible_with = NATIVE_EXTENSION_LINUX_COMPATIBLE, size = "medium") + +def _unit_inputs_impl(ctx): + output = ctx.actions.declare_file(ctx.label.name + ".json") + metadata = native_external_carrier_metadata("pgtap", "linux-x64-gnu") + metadata["compiledMember"] = native_external_carrier_metadata("pg_uuidv7", "linux-x64-gnu") + metadata["postgisMember"] = native_external_carrier_metadata("postgis", "linux-x64-gnu") + products = dict(PRODUCTS) + runtime = dict(products["liboliphaunt-native"]) + parts = runtime["version"].split(".") + runtime["version"] = ".".join(parts[:2] + [str(int(parts[2]) + 1)]) + products["liboliphaunt-native"] = runtime + metadata["newCoreMember"] = native_external_carrier_metadata("pg_uuidv7", "linux-x64-gnu", products = products) + ctx.actions.write(output, json.encode(metadata)) + return [DefaultInfo(files = depset([output]))] + +native_extension_carrier_unit_inputs = rule(implementation = _unit_inputs_impl) diff --git a/build_defs/extensions/native_carriers.mts b/build_defs/extensions/native_carriers.mts new file mode 100644 index 000000000..abf723608 --- /dev/null +++ b/build_defs/extensions/native_carriers.mts @@ -0,0 +1,401 @@ +/** Adapt declared native member bytes to the existing exact extension envelopes. */ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + copyFileSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + realpathSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + EXTENSION_ARTIFACT_PROPERTY_KEYS, + moduleSuffix, + nativeDependencyModuleBasenames, + validateExtensionArtifactArchive, +} from '../../src/extensions/artifacts/packages/tools/extension-artifact-inventory.mts'; +import { + packageNativeExtensionCargoCrates, + stageExtensionNativeNpmPackages, +} from '../../src/extensions/artifacts/packages/tools/package-extension-release-carriers.mts'; +import { + extensionCarrierLegalContract, + nativeExtensionConstructionLicenseInventory, + stageExtensionUpstreamLicenses, +} from '../../src/extensions/tools/extension-upstream-licenses.mts'; +import { tarHeader } from '../../tools/packaging/archive-directory.mts'; +import { inspectPlatformBinaryBuffer } from '../../tools/packaging/platform-binary-contract.mts'; +import { + canonicalGzipSync, + readPortableArchiveEntries, +} from '../../tools/packaging/portable-archive.mts'; +import { stageReleaseNotices } from '../../tools/packaging/release-notices.mts'; +import { inspect, validateNativeMemberModule } from './validate_member_payload.mts'; + +interface Carrier { + product: string; + ecosystem: string; + name: string; + version: string; + target: string | null; + role: string; +} +export interface NativeCarrierSpec { + product: string; + owner?: string; + contrib?: Record; + version: string; + sqlName: string; + target: string; + runtimeVersion: string; + descriptor: Record; + recipe: Record; + source: Record; + selectedDependencies: string[]; + compatibility: Record; + carriers: Carrier[]; + releaseMetadata?: Record; + archive: string; + outputs: { github: string; npm: string; cargo: string; manifest: string; frozen: string }; +} + +/** Apply the existing release platform policy before accepting a compiled member. */ +export function validateNativeShippingModule(bytes: Buffer, target: string, modulePath: string) { + const result = inspectPlatformBinaryBuffer(bytes, { + target, + label: 'native extension shipping module', + }); + validateNativeMemberModule(bytes, target, modulePath); + return result; +} + +export function frozenNativeMember(spec: NativeCarrierSpec, actual: Record) { + assert.equal( + actual.owner, + spec.owner ?? spec.product, + 'member owner differs from its release product', + ); + assert.equal(actual.version, spec.version, 'member version differs from its release product'); + assert.equal(actual.sql_name, spec.sqlName); + assert.equal(actual.configuration, spec.target); + assert.equal( + spec.runtimeVersion, + spec.compatibility.native_runtime_version, + 'public native host differs from the declared extension compatibility', + ); + assert.equal(actual.source_kind, spec.descriptor['source-kind']); + assert.deepEqual( + spec.contrib ? actual.postgres_source : actual.source, + spec.source, + 'member source pin differs from canonical acquisition', + ); + assert.equal( + actual.default_version, + spec.contrib + ? (spec.contrib['default-version'] ?? null) + : spec.source['extension-control']['default-version'], + ); + assert.equal(actual.creates_extension, spec.descriptor.lifecycle['create-extension']); + const artifact = spec.recipe.artifacts ?? {}; + const canonical = (values: string[] = []) => [...values].sort(); + assert.deepEqual(canonical(actual.dependencies), canonical(spec.descriptor.dependencies)); + assert.deepEqual( + canonical(actual.data_files), + canonical(spec.contrib ? spec.contrib['data-files'] : artifact.data_files), + ); + assert.deepEqual(canonical(actual.sql_files), canonical(artifact.extension_sql_file_names)); + assert.deepEqual(canonical(actual.sql_prefixes), canonical(artifact.extension_sql_file_prefixes)); + const canonicalModule = spec.descriptor['native-module-file'] ?? ''; + assert( + !canonicalModule || canonicalModule.endsWith('.so'), + 'canonical native module must declare its .so stem', + ); + const stem = canonicalModule ? canonicalModule.slice(0, -3) : null; + assert.equal(actual.module_file, stem === null ? '' : stem + moduleSuffix(spec.target)); + const nativeDependencyModules = nativeDependencyModuleBasenames( + artifact.native_dependency_modules, + spec.target, + artifact.native_dependency_modules_by_target, + ); + assert.deepEqual( + actual.dependency_modules, + nativeDependencyModules, + 'native dependency modules differ from the canonical recipe', + ); + const nativeConstructionLicenseFiles = nativeExtensionConstructionLicenseInventory( + spec.sqlName, + spec.target, + ); + assert.deepEqual( + actual.construction_licenses ?? [], + nativeConstructionLicenseFiles.map((row) => row.path), + 'construction notices differ from the immutable construction source', + ); + const startup = spec.descriptor.lifecycle['startup-config'] ?? []; + const sharedPreloadLibraries = startup + .flatMap((value: string) => + value.startsWith('shared_preload_libraries=') + ? value.slice('shared_preload_libraries='.length).split(',') + : [], + ) + .sort(); + return { + sqlName: spec.sqlName, + createsExtension: actual.creates_extension, + nativeModuleStem: stem, + dependencies: spec.selectedDependencies, + dataFiles: canonical(actual.data_files).map((file) => { + assert( + file.startsWith('share/postgresql/'), + 'extension data must have its canonical share destination', + ); + return file.slice('share/postgresql/'.length); + }), + extensionSqlFileNames: canonical(actual.sql_files), + extensionSqlFilePrefixes: canonical(actual.sql_prefixes), + sharedPreloadLibraries, + ...(nativeDependencyModules.length === 0 ? {} : { nativeDependencyModules }), + ...(nativeConstructionLicenseFiles.length === 0 ? {} : { nativeConstructionLicenseFiles }), + }; +} + +export function writeJson(file: string, value: unknown) { + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, JSON.stringify(value, null, 2) + '\n'); +} + +export function exactArchive(directory: string, output: string) { + const rows: { name: string; data: Buffer; mode: number }[] = []; + const visit = (current: string, prefix = '') => { + for (const entry of readdirSync(current, { withFileTypes: true })) { + const name = prefix + entry.name; + if (entry.isDirectory()) visit(path.join(current, entry.name), name + '/'); + else { + assert(entry.isFile(), 'exact extension archive requires regular files'); + rows.push({ + name, + data: readFileSync(path.join(current, entry.name)), + mode: name.startsWith('files/lib/') ? 0o755 : 0o644, + }); + } + } + }; + visit(directory); + const blocks = rows + .sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0)) + .flatMap(({ name, data, mode }) => [ + tarHeader({ name, owner: 'root' }, data.length, mode), + data, + Buffer.alloc((512 - (data.length % 512)) % 512), + ]); + blocks.push(Buffer.alloc(1024)); + writeFileSync(output, canonicalGzipSync(Buffer.concat(blocks))); +} + +export function nativeCarrierCompatibility(spec: NativeCarrierSpec) { + return { + extensionRuntimeContract: spec.compatibility.extension_runtime_contract, + nativeRuntimeProduct: spec.compatibility.native_runtime_product, + nativeRuntimeVersion: spec.compatibility.native_runtime_version, + postgresMajor: spec.compatibility.postgres_major, + wasixRuntimeProduct: spec.compatibility.wasix_runtime_product, + wasixRuntimeVersion: spec.compatibility.wasix_runtime_version, + }; +} + +export function nativeCarrierLeaves(spec: NativeCarrierSpec) { + const facades = spec.carriers.filter((row) => row.ecosystem === 'npm' && row.target === null); + assert.equal(facades.length, 1, 'canonical extension npm facade must be unique'); + const selected = ['npm', 'cargo'].map((ecosystem) => { + const name = `${ecosystem === 'npm' ? facades[0].name : spec.product}-${spec.target}`; + const rows = spec.carriers.filter( + (row) => row.ecosystem === ecosystem && row.target === spec.target && row.name === name, + ); + assert.equal(rows.length, 1, `canonical ${ecosystem} extension leaf must be unique`); + const row = rows[0]; + assert.equal(row.product, spec.owner ?? spec.product); + assert.equal(row.version, spec.version); + return row; + }); + return { npm: selected[0], cargo: selected[1] }; +} + +export function validateNativeCarrierIdentities(spec: NativeCarrierSpec) { + const selected = nativeCarrierLeaves(spec); + assert.equal( + path.basename(spec.outputs.github), + `${spec.product}-${spec.version}-native-${spec.target}-runtime.tar.gz`, + ); + return selected; +} + +export function assemblePublicNativeMember(spec: NativeCarrierSpec, output: string) { + const actual = inspect(spec.archive, spec.sqlName, spec.owner ?? spec.product); + const metadata = frozenNativeMember(spec, actual); + const root = mkdtempSync(path.join(tmpdir(), 'native-extension-member-')); + mkdirSync(path.dirname(path.resolve(output)), { recursive: true }); + try { + const publicRoot = path.join(root, 'public'); + mkdirSync(publicRoot, { recursive: true }); + for (const [name, entry] of readPortableArchiveEntries(realpathSync(spec.archive))) { + if (name === 'extension.json') continue; + const output = path.join(publicRoot, 'files', name); + mkdirSync(path.dirname(output), { recursive: true }); + writeFileSync(output, entry.data(), { mode: name.startsWith('lib/') ? 0o755 : 0o644 }); + if (name.startsWith('lib/')) validateNativeShippingModule(entry.data(), spec.target, name); + } + stageExtensionUpstreamLicenses(spec.sqlName, path.join(publicRoot, 'files')); + const legal = extensionCarrierLegalContract(spec.product, [spec.sqlName], { + family: 'native', + target: spec.target, + memberContracts: [metadata], + }); + stageReleaseNotices(publicRoot, { profile: legal.profile }); + const compatibility = nativeCarrierCompatibility(spec); + const properties: Record = { + packageLayout: 'oliphaunt-extension-artifact-v1', + pgMajor: '18', + sqlName: spec.sqlName, + createsExtension: metadata.createsExtension ? 'yes' : 'no', + nativeModuleStem: metadata.nativeModuleStem ?? '', + nativeModuleFile: actual.module_file, + nativeTarget: spec.target, + nativeRuntimeProduct: compatibility.nativeRuntimeProduct, + nativeRuntimeVersion: compatibility.nativeRuntimeVersion, + dependencies: metadata.dependencies.join(','), + dataFiles: metadata.dataFiles.join(','), + extensionSqlFileNames: metadata.extensionSqlFileNames.join(','), + extensionSqlFilePrefixes: metadata.extensionSqlFilePrefixes.join(','), + sharedPreloadLibraries: metadata.sharedPreloadLibraries.join(','), + mobilePrebuilt: 'no', + mobileStaticArchives: '', + mobileStaticDependencyArchives: '', + staticSymbolPrefix: '', + staticSymbolAliases: '', + licenseFiles: [ + ...legal.licenseFiles, + ...(metadata.nativeConstructionLicenseFiles ?? []).map((row) => row.path), + ] + .sort() + .join(','), + licenseProfile: legal.profile, + files: 'files', + }; + writeFileSync( + path.join(publicRoot, 'manifest.properties'), + EXTENSION_ARTIFACT_PROPERTY_KEYS.map((key) => `${key}=${properties[key]}\n`).join(''), + ); + exactArchive(publicRoot, output); + validateExtensionArtifactArchive({ + file: output, + metadata, + product: spec.product, + target: spec.target, + nativeRuntimeVersion: compatibility.nativeRuntimeVersion, + }); + const asset = { + name: path.basename(output), + family: 'native', + target: spec.target, + kind: 'runtime', + identity: null, + bytes: readFileSync(output).length, + sha256: createHash('sha256').update(readFileSync(output)).digest('hex'), + }; + return { metadata, asset }; + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +export function stageNativeRegistryCarriers( + spec: NativeCarrierSpec, + productRoot: string, + root: string, +) { + const identities = nativeCarrierLeaves(spec); + const result = { staged: [], skipped: [] }; + const npmRoot = stageExtensionNativeNpmPackages( + [productRoot], + path.join(root, 'npm'), + spec.target, + result, + { metaTargets: [] }, + ); + assert(npmRoot, `native npm packaging failed: ${result.skipped.join('; ')}`); + const npmFiles = result.staged.filter((file) => file.endsWith('.tgz')); + assert.equal(npmFiles.length, 1); + const npm = npmFiles[0]; + const npmManifest = JSON.parse( + readPortableArchiveEntries(npm).get('package/package.json')!.data().toString('utf8'), + ); + assert.equal(npmManifest.name, identities.npm.name); + assert.equal(npmManifest.version, identities.npm.version); + copyFileSync(npm, spec.outputs.npm); + const crates = packageNativeExtensionCargoCrates( + [productRoot], + path.join(root, 'cargo'), + spec.target, + true, + result, + ); + assert(crates.length > 0, `native Cargo packaging failed: ${result.skipped.join('; ')}`); + assert( + crates.some((file) => path.basename(file) === `${identities.cargo.name}-${spec.version}.crate`), + ); + mkdirSync(spec.outputs.cargo, { recursive: true }); + for (const crate of crates) + copyFileSync(crate, path.join(spec.outputs.cargo, path.basename(crate))); +} + +export function packageNativeCarriers(spec: NativeCarrierSpec) { + validateNativeCarrierIdentities(spec); + const { metadata, asset } = assemblePublicNativeMember(spec, spec.outputs.github); + const root = mkdtempSync(path.join(tmpdir(), 'native-extension-envelopes-')); + for (const output of Object.values(spec.outputs)) + mkdirSync(path.dirname(path.resolve(output)), { recursive: true }); + try { + const productRoot = path.join(root, 'product'); + const compatibility = nativeCarrierCompatibility(spec); + mkdirSync(path.join(productRoot, 'release-assets'), { recursive: true }); + copyFileSync(spec.outputs.github, path.join(productRoot, 'release-assets', asset.name)); + const member = { ...metadata, assets: [asset] }; + writeJson(path.join(productRoot, 'extension-artifacts.json'), { + schema: 'oliphaunt-extension-ci-artifacts-v1', + product: spec.product, + version: spec.version, + compatibility, + ...member, + }); + writeJson( + path.join(productRoot, 'release-assets', `${spec.product}-${spec.version}-manifest.json`), + { + schema: 'oliphaunt-extension-release-manifest-v1', + product: spec.product, + version: spec.version, + extensionClass: spec.releaseMetadata?.class ?? 'external', + versioning: 'upstream-bound', + ...(spec.releaseMetadata ? { sourceIdentity: spec.releaseMetadata.sourceIdentity } : {}), + compatibility, + ...member, + }, + ); + copyFileSync(path.join(productRoot, 'extension-artifacts.json'), spec.outputs.frozen); + copyFileSync( + path.join(productRoot, 'release-assets', `${spec.product}-${spec.version}-manifest.json`), + spec.outputs.manifest, + ); + stageNativeRegistryCarriers(spec, productRoot, root); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} +if (import.meta.main) { + assert.equal(process.argv.length, 3, 'usage: native_carriers.mts '); + packageNativeCarriers(JSON.parse(readFileSync(process.argv[2], 'utf8'))); +} diff --git a/build_defs/extensions/native_carriers.test.mts b/build_defs/extensions/native_carriers.test.mts new file mode 100644 index 000000000..d83ea5d1f --- /dev/null +++ b/build_defs/extensions/native_carriers.test.mts @@ -0,0 +1,530 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { + nativeDependencyModuleBasenames, + validateExtensionArtifactArchive, +} from '../../src/extensions/artifacts/packages/tools/extension-artifact-inventory.mts'; +import { + extractPortableArchiveTree, + readPortableArchiveEntries, +} from '../../tools/packaging/portable-archive.mts'; +import { + elfFixture, + machoFixture, + windowsPeFixture, +} from '../../tools/packaging/testdata/release-fixture-utils.mts'; +import { assemble } from './member_payload.mts'; +import { + exactArchive, + frozenNativeMember, + type NativeCarrierSpec, + packageNativeCarriers, + validateNativeCarrierIdentities, + validateNativeShippingModule, +} from './native_carriers.mts'; + +const [input, resourcesCli] = process.argv.slice(2); +assert(input, 'expected canonical pgtap carrier metadata'); +if (process.platform !== 'win32') assert(resourcesCli, 'expected declared Rust resources CLI'); +const metadata = JSON.parse(readFileSync(input, 'utf8')); +const modes = Bun.spawnSync({ + cmd: [ + process.execPath, + '--no-env-file', + '--no-install', + 'test', + fileURLToPath(new URL('../../tools/packaging/npm-package.test.mts', import.meta.url)), + ], + stdout: 'pipe', + stderr: 'pipe', +}); +assert.equal( + modes.exitCode, + 0, + `${Buffer.from(modes.stdout).toString('utf8')}\n${Buffer.from(modes.stderr).toString('utf8')}`.slice( + -8000, + ), +); +assert.throws( + () => + validateNativeShippingModule( + Buffer.from('foreign module'), + metadata.target, + 'lib/modules/foreign.so', + ), + /does not contain a recognized/, +); + +for (const profile of ['postgresql', 'modules']) { + const modulePath = `lib/${profile}/fixture.dylib`; + const result = validateNativeShippingModule(machoFixture(), 'macos-arm64', modulePath); + assert.equal(result.format, 'macho'); + assert.equal(result.slices[0].machine, 'arm64'); + assert.deepEqual(result.platforms, [1]); + const bundle = machoFixture(); + bundle.writeUInt32LE(8, 12); + assert.equal(validateNativeShippingModule(bundle, 'macos-arm64', modulePath).format, 'macho'); + for (const [bytes, expected] of [ + [machoFixture({ cpu: 0x01000007 }), /not arm64/u], + [machoFixture({ cpuSubtype: 2 }), /not generic ARM64_ALL/u], + [machoFixture({ platform: 2 }), /unsupported iOS/u], + [machoFixture({ minos: [14, 0, 0] }), /minimum OS.*exceeds/u], + [windowsPeFixture(), /PE content does not match/u], + ] as const) { + assert.throws(() => validateNativeShippingModule(bytes, 'macos-arm64', modulePath), expected); + } + const object = machoFixture(); + object.writeUInt32LE(1, 12); + assert.throws( + () => validateNativeShippingModule(object, 'macos-arm64', modulePath), + /dylib or bundle/u, + ); + assert.throws( + () => validateNativeShippingModule(machoFixture(), 'macos-arm64', `lib/${profile}/fixture.so`), + /unsupported configuration or layout/u, + ); +} + +for (const [profile, provider, wrongProvider, expected] of [ + ['postgresql', 'postgres.exe', 'oliphaunt.dll', /standalone PostgreSQL extension DLLs/u], + ['modules', 'oliphaunt.dll', 'postgres.exe', /embedded extension DLLs/u], +] as const) { + const modulePath = `lib/${profile}/fixture.dll`; + for (const imports of [[provider], ['KERNEL32.dll']]) { + const result = validateNativeShippingModule( + windowsPeFixture({ imports }), + 'windows-x64-msvc', + modulePath, + ); + assert.equal(result.format, 'pe'); + assert.equal(result.slices[0].machine, 'x64'); + } + for (const importField of ['imports', 'delayImports']) { + assert.throws( + () => + validateNativeShippingModule( + windowsPeFixture({ [importField]: [wrongProvider] }), + 'windows-x64-msvc', + modulePath, + ), + expected, + ); + } + assert.throws( + () => + validateNativeShippingModule( + windowsPeFixture({ machine: 0xaa64 }), + 'windows-x64-msvc', + modulePath, + ), + /PE machine.*not x64/u, + ); + const executable = windowsPeFixture(); + executable.writeUInt16LE(0x22, executable.readUInt32LE(0x3c) + 4 + 18); + assert.throws( + () => validateNativeShippingModule(executable, 'windows-x64-msvc', modulePath), + /must be a PE x64 DLL/u, + ); + assert.throws( + () => validateNativeShippingModule(machoFixture(), 'windows-x64-msvc', modulePath), + /MACHO content does not match/u, + ); + assert.throws( + () => + validateNativeShippingModule( + windowsPeFixture(), + 'windows-x64-msvc', + `lib/${profile}/fixture.so`, + ), + /unsupported configuration or layout/u, + ); +} + +const compiled = metadata.compiledMember; +assert.equal(compiled?.sqlName, 'pg_uuidv7', 'expected canonical compiled extension metadata'); +assert.deepEqual( + metadata.newCoreMember, + compiled, + 'an unrelated core version must not adopt a new extension host', +); +const canonicalModule = compiled.descriptor['native-module-file']; +assert.equal(typeof canonicalModule, 'string'); +assert(canonicalModule.endsWith('.so')); +const canonicalStem = canonicalModule.slice(0, -3); +const compiledArtifacts = compiled.recipe.artifacts ?? {}; +for (const [target, suffix, wrongSuffix] of [ + ['macos-arm64', '.dylib', '.dll'], + ['windows-x64-msvc', '.dll', '.dylib'], +] as const) { + const spec = { ...compiled, target } as NativeCarrierSpec; + const actual = { + sql_name: compiled.sqlName, + owner: compiled.owner ?? compiled.product, + version: compiled.version, + configuration: target, + source_kind: compiled.descriptor['source-kind'], + source: compiled.source, + default_version: compiled.source['extension-control']['default-version'], + creates_extension: compiled.descriptor.lifecycle['create-extension'], + dependencies: compiled.descriptor.dependencies, + data_files: compiledArtifacts.data_files ?? [], + sql_files: compiledArtifacts.extension_sql_file_names ?? [], + sql_prefixes: compiledArtifacts.extension_sql_file_prefixes ?? [], + module_profiles: ['postgresql', 'modules'], + module_file: canonicalStem + suffix, + dependency_modules: [], + construction_licenses: [], + }; + assert.equal(frozenNativeMember(spec, actual).nativeModuleStem, canonicalStem); + for (const module_file of [canonicalModule, canonicalStem + wrongSuffix, 'foreign' + suffix]) { + assert.throws(() => frozenNativeMember(spec, { ...actual, module_file })); + } +} + +const root = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'extension-carrier-test-')); +try { + for (const [target, os, cpu, libc] of [ + ['linux-x64-gnu', 'linux', 'x64', 'glibc'], + ['linux-arm64-gnu', 'linux', 'arm64', 'glibc'], + ['macos-arm64', 'darwin', 'arm64', null], + ['windows-x64-msvc', 'win32', 'x64', null], + ] as const) { + const selected = { ...metadata, target }; + const directory = path.join(root, target); + mkdirSync(directory, { recursive: true }); + const actual = { + schema: 'oliphaunt-extension-member-payload-v1', + sql_name: 'pgtap', + owner: metadata.product, + version: metadata.version, + family: 'native', + configuration: target, + source_kind: metadata.descriptor['source-kind'], + postgres_major: 18, + default_version: metadata.source['extension-control']['default-version'], + creates_extension: true, + dependencies: metadata.descriptor.dependencies, + module_profiles: [], + module_file: '', + dependency_modules: [], + data_files: [], + sql_prefixes: metadata.recipe.artifacts.extension_sql_file_prefixes ?? [], + sql_files: metadata.recipe.artifacts.extension_sql_file_names ?? [], + source: metadata.source, + }; + const control = path.join(directory, 'pgtap.control'); + const sql = path.join(directory, 'pgtap.sql'); + writeFileSync(control, `default_version = '${actual.default_version}'\nrelocatable = true\n`); + writeFileSync(sql, 'SELECT 1;\n'); + const archive = path.join(directory, 'member.tar.gz'); + await assemble( + { + descriptor: actual, + inputs: [ + { source: control, destination: 'share/postgresql/extension/pgtap.control' }, + { + source: sql, + destination: `share/postgresql/extension/pgtap--${actual.default_version}.sql`, + }, + ...actual.sql_files.map((name: string) => ({ + source: sql, + destination: 'share/postgresql/extension/' + name, + })), + ], + }, + archive, + path.join(directory, 'inventory.json'), + ); + const makeSpec = (directory: string): NativeCarrierSpec => ({ + ...selected, + archive, + outputs: { + github: path.join( + directory, + `${metadata.product}-${metadata.version}-native-${target}-runtime.tar.gz`, + ), + npm: path.join(directory, 'npm.tgz'), + cargo: path.join(directory, 'cargo'), + manifest: path.join(directory, `${metadata.product}-${metadata.version}-manifest.json`), + frozen: path.join(directory, 'extension-artifacts.json'), + }, + }); + const spec = makeSpec(path.join(directory, 'first')); + packageNativeCarriers(spec); + const github = readPortableArchiveEntries(spec.outputs.github); + assert(github.has('manifest.properties')); + assert(github.has('files/share/postgresql/extension/pgtap.control')); + assert( + !github.has('extension.json'), + 'internal descriptor must not leak into public runtime layout', + ); + const npm = readPortableArchiveEntries(spec.outputs.npm); + const manifest = JSON.parse(npm.get('package/package.json')!.data().toString('utf8')); + assert.equal( + manifest.name, + metadata.carriers.find((row: any) => row.ecosystem === 'npm' && row.target === target).name, + ); + assert.equal(manifest.version, metadata.version); + assert.equal( + manifest.oliphaunt.liboliphauntVersion, + metadata.compatibility.native_runtime_version, + ); + assert.deepEqual(manifest.os, [os]); + assert.deepEqual(manifest.cpu, [cpu]); + assert.deepEqual(manifest.libc, libc === null ? undefined : [libc]); + assert(npm.has('package/extension-contract.json')); + assert(npm.has('package/runtime/share/postgresql/extension/pgtap.control')); + assert([...npm.keys()].some((name) => name.startsWith('package/runtime/share/licenses/'))); + const crates = readdirSync(spec.outputs.cargo).filter((name) => name.endsWith('.crate')); + assert.equal(crates.length, 1); + const crate = readPortableArchiveEntries(path.join(spec.outputs.cargo, crates[0])); + for (const [name, entry] of crate) + assert.equal(entry.mode, entry.isDirectory ? 0o755 : 0o644, name); + const crateRoot = crates[0].slice(0, -'.crate'.length); + const cargo = Bun.TOML.parse(crate.get(`${crateRoot}/Cargo.toml`)!.data().toString('utf8')); + assert.equal( + cargo.package.name, + metadata.carriers.find((row: any) => row.ecosystem === 'cargo' && row.target === target).name, + ); + assert.equal(cargo.package.version, metadata.version); + assert(crate.has(`${crateRoot}/payload/share/postgresql/extension/pgtap.control`)); + assert(crate.has(`${crateRoot}/build.rs`)); + assert([...crate.keys()].some((name) => name.startsWith(`${crateRoot}/share/licenses/`))); + const second = makeSpec(path.join(directory, 'second')); + packageNativeCarriers(second); + const digest = (file: string) => createHash('sha256').update(readFileSync(file)).digest('hex'); + assert.equal(digest(spec.outputs.github), digest(second.outputs.github)); + assert.equal(digest(spec.outputs.npm), digest(second.outputs.npm)); + assert.equal(digest(spec.outputs.manifest), digest(second.outputs.manifest)); + assert.equal(digest(spec.outputs.frozen), digest(second.outputs.frozen)); + assert.equal( + digest(path.join(spec.outputs.cargo, crates[0])), + digest(path.join(second.outputs.cargo, crates[0])), + ); + for (const invalid of [ + { ...actual, version: '99.0.0' }, + { ...actual, configuration: target === 'macos-arm64' ? 'linux-x64-gnu' : 'macos-arm64' }, + { ...actual, source: { ...actual.source, commit: '0'.repeat(40) } }, + { ...actual, dependency_modules: ['foreign.so'] }, + { ...actual, construction_licenses: ['share/licenses/foreign.txt'] }, + ]) + assert.throws(() => frozenNativeMember(spec, invalid)); + assert.throws(() => + validateNativeCarrierIdentities({ + ...spec, + carriers: spec.carriers.filter((row) => row.ecosystem !== 'cargo'), + }), + ); + assert.throws(() => + validateNativeCarrierIdentities({ + ...spec, + outputs: { ...spec.outputs, github: path.join(root, 'wrong.tar.gz') }, + }), + ); + } + const postgis = metadata.postgisMember; + assert.equal(postgis.sqlName, 'postgis'); + const directory = path.join(root, 'postgis'); + const put = (name: string, bytes: string | Buffer, mode = 0o644): string => { + const file = path.join(directory, name); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, bytes, { mode }); + return file; + }; + const artifacts = postgis.recipe.artifacts; + const moduleFile = path.posix.basename(postgis.descriptor['native-module-file']); + const dependencyModules = nativeDependencyModuleBasenames( + artifacts.native_dependency_modules, + postgis.target, + ); + assert(dependencyModules.length > 0, 'canonical PostGIS must exercise dependency modules'); + // Cross the real Cargo split threshold once without adding a production test flag. + const splitPayload = Buffer.alloc(10 * 1024 * 1024); + let state = 0x5eed; + for (let offset = 0; offset < splitPayload.length; offset += 4) { + state ^= state << 13; + state ^= state >>> 17; + state ^= state << 5; + splitPayload.writeUInt32LE(state >>> 0, offset); + } + const actual = { + schema: 'oliphaunt-extension-member-payload-v1', + sql_name: postgis.sqlName, + owner: postgis.product, + version: postgis.version, + family: 'native', + configuration: postgis.target, + source_kind: postgis.descriptor['source-kind'], + postgres_major: 18, + default_version: postgis.source['extension-control']['default-version'], + creates_extension: postgis.descriptor.lifecycle['create-extension'], + dependencies: postgis.descriptor.dependencies, + module_profiles: ['postgresql', 'modules'], + module_file: moduleFile, + dependency_modules: dependencyModules, + data_files: artifacts.data_files ?? [], + sql_prefixes: artifacts.extension_sql_file_prefixes ?? [], + sql_files: artifacts.extension_sql_file_names ?? [], + source: postgis.source, + }; + const inputs = [ + ...[ + `${postgis.sqlName}.control`, + `${postgis.sqlName}--${actual.default_version}.sql`, + ...actual.sql_files, + ].map((name) => ({ + source: put( + `inputs/sql/${name}`, + name.endsWith('.control') + ? `default_version = '${actual.default_version}'\nrelocatable = false\n` + : 'SELECT 1;\n', + ), + destination: `share/postgresql/extension/${name}`, + })), + ...actual.data_files.map((name: string) => ({ + source: put(`inputs/${name}`, `fixture ${name}\n`), + destination: name, + })), + ...actual.module_profiles.flatMap((profile) => + [moduleFile, ...dependencyModules].map((name) => ({ + source: put( + `inputs/lib/${profile}/${name}`, + Buffer.concat([ + elfFixture(), + profile === 'modules' && name === moduleFile + ? splitPayload + : Buffer.from(`${profile}/${name}`), + ]), + ), + destination: `lib/${profile}/${name}`, + })), + ), + ]; + const archive = path.join(directory, 'member.tar.gz'); + await assemble({ descriptor: actual, inputs }, archive, path.join(directory, 'inventory.json')); + const spec: NativeCarrierSpec = { + ...postgis, + archive, + outputs: { + github: path.join( + directory, + `${postgis.product}-${postgis.version}-native-${postgis.target}-runtime.tar.gz`, + ), + npm: path.join(directory, 'npm.tgz'), + cargo: path.join(directory, 'cargo'), + manifest: path.join(directory, 'manifest.json'), + frozen: path.join(directory, 'extension-artifacts.json'), + }, + }; + assert.throws(() => frozenNativeMember(spec, { ...actual, dependency_modules: [] })); + packageNativeCarriers(spec); + const splitCrates = readdirSync(spec.outputs.cargo).filter((name) => name.endsWith('.crate')); + assert( + splitCrates.some((name) => name.includes('-part-')), + 'expected actual split part crates', + ); + assert.equal(splitCrates.filter((name) => !name.includes('-part-')).length, 1); + for (const file of splitCrates) + for (const [name, entry] of readPortableArchiveEntries(path.join(spec.outputs.cargo, file))) + assert.equal(entry.mode, entry.isDirectory ? 0o755 : 0o644, name); + const artifact = path.join(directory, 'public'); + extractPortableArchiveTree(spec.outputs.github, artifact); + const sidecar = dependencyModules[0]; + const sidecarPaths = actual.module_profiles.map((profile) => + path.join(artifact, 'files/lib', profile, sidecar), + ); + const sidecarBytes = sidecarPaths.map((file) => readFileSync(file)); + for (const file of sidecarPaths) rmSync(file); + const missingArchive = path.join(directory, 'missing-sidecars.tar.gz'); + exactArchive(artifact, missingArchive); + assert.throws(() => + validateExtensionArtifactArchive({ + file: missingArchive, + metadata: frozenNativeMember(spec, actual), + product: spec.product, + target: spec.target, + nativeRuntimeVersion: spec.runtimeVersion, + }), + ); + for (const [index, file] of sidecarPaths.entries()) + writeFileSync(file, sidecarBytes[index], { mode: 0o755 }); + if (process.platform !== 'win32') { + // Match the resources CLI's existing prepared-install fixture; no native binary is executed. + const install = path.join(directory, 'install'); + for (const tool of ['postgres', 'initdb', 'pg_ctl', 'pg_basebackup', 'pg_dump', 'psql']) + put(`install/bin/${tool}`, tool, 0o755); + put('install/share/postgresql/postgresql.conf.sample', '# sample\n'); + put('install/share/postgresql/extension/plpgsql.control', "comment = 'PL/pgSQL'\n"); + put('install/share/postgresql/extension/plpgsql--1.0.sql', "SELECT 'plpgsql';\n"); + mkdirSync(path.join(install, 'lib/postgresql'), { recursive: true }); + for (const name of ['dict_snowball', 'plpgsql']) + put(`out/modules/${name}${process.platform === 'darwin' ? '.dylib' : '.so'}`, 'core fixture'); + const run = (input: string, name: string) => + Bun.spawnSync({ + cmd: [ + resourcesCli!, + '--output', + path.join(directory, name), + '--prebuilt-extension', + input, + '--extension-target', + spec.target, + '--liboliphaunt-native-version', + spec.runtimeVersion, + ], + env: { + ...process.env, + OLIPHAUNT_RESOURCES_DIR: undefined, + OLIPHAUNT_POSTGRES: undefined, + OLIPHAUNT_INITDB: undefined, + OLIPHAUNT_INSTALL_DIR: install, + OLIPHAUNT_RUNTIME_CACHE_DIR: path.join(directory, 'runtime-cache'), + OLIPHAUNT_EMBEDDED_MODULE_DIR: path.join(directory, 'out/modules'), + }, + stdout: 'pipe', + stderr: 'pipe', + }); + const accepted = run(spec.outputs.github, 'accepted'); + assert.equal(accepted.exitCode, 0, accepted.stderr.toString()); + const runtime = path.join(directory, 'accepted/oliphaunt/runtime/files'); + for (const name of [moduleFile, ...dependencyModules]) + assert.deepEqual( + readFileSync(path.join(runtime, 'lib/postgresql', name)), + readFileSync(path.join(artifact, 'files/lib/modules', name)), + ); + const delivered = [...readPortableArchiveEntries(spec.outputs.github).values()].filter( + (entry) => + !entry.isDirectory && + entry.name.startsWith('files/') && + !entry.name.startsWith('files/lib/postgresql/'), + ); + const report = readFileSync(path.join(directory, 'accepted/oliphaunt/package-size.tsv'), 'utf8') + .split('\n') + .find((line) => line.startsWith('extension\tpostgis\t'))! + .split('\t'); + assert.equal(Number(report[3]), delivered.length); + assert.equal( + Number(report[4]), + delivered.reduce((bytes, entry) => bytes + entry.data().length, 0), + ); + rmSync(sidecarPaths[1]); + const missing = run(artifact, 'missing'); + assert.notEqual(missing.exitCode, 0); + assert(missing.stderr.toString().includes(sidecar), missing.stderr.toString()); + writeFileSync(sidecarPaths[1], sidecarBytes[1], { mode: 0o755 }); + const extra = path.join(artifact, 'files/lib/modules/undeclared.so'); + writeFileSync(extra, sidecarBytes[1], { mode: 0o755 }); + const undeclared = run(artifact, 'extra'); + assert.notEqual(undeclared.exitCode, 0); + assert.match(undeclared.stderr.toString(), /undeclared/u); + } + console.log( + 'Native extension final envelopes preserve canonical identities, compatibility, legal files, payload layout and deterministic bytes.', + ); +} finally { + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/extensions/native_carriers_installed.test.mts b/build_defs/extensions/native_carriers_installed.test.mts new file mode 100644 index 000000000..47f3e49d5 --- /dev/null +++ b/build_defs/extensions/native_carriers_installed.test.mts @@ -0,0 +1,233 @@ +/** Validate final leaves and their real SDK host contract, then load both native ABIs. */ + +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + realpathSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + readCanonicalExtensionArtifactArchive, + validateExtensionArtifactArchive, + validateExtensionArtifactEntries, +} from '../../src/extensions/artifacts/packages/tools/extension-artifact-inventory.mts'; +import { nativeExtensionConstructionLicenseInventory } from '../../src/extensions/tools/extension-upstream-licenses.mts'; +import { readPortableArchiveEntries } from '../../tools/packaging/portable-archive.mts'; +import { + exerciseNativeCarrierSql, + prepareNativeCarrierSdk, + readNativeCargoPayload, + writableDirectories, +} from './native_carrier_install_helpers.mts'; +import { type NativeCarrierSpec, validateNativeCarrierIdentities } from './native_carriers.mts'; + +const [ + specFile, + githubFile, + npmFile, + cargoDirectory, + runtimeFile, + consumerFile, + installSql, + smokeSql, + startupFile, + manifestFile, + frozenFile, +] = process.argv.slice(2); +const spec = JSON.parse(readFileSync(specFile, 'utf8')) as NativeCarrierSpec; +spec.outputs = { + github: githubFile, + npm: npmFile, + cargo: cargoDirectory, + manifest: manifestFile, + frozen: frozenFile, +}; +const identities = validateNativeCarrierIdentities(spec); +const npm = readPortableArchiveEntries(realpathSync(npmFile)); +const manifest = JSON.parse(npm.get('package/package.json')!.data().toString('utf8')); +const contracts = JSON.parse(npm.get('package/extension-contract.json')!.data().toString('utf8')); +const member = contracts.members[0]; +for (const [file, schema] of [ + [manifestFile, 'oliphaunt-extension-release-manifest-v1'], + [frozenFile, 'oliphaunt-extension-ci-artifacts-v1'], +]) { + const release = JSON.parse(readFileSync(file, 'utf8')); + assert.equal(release.schema, schema); + assert.equal(release.product, spec.product); + assert.equal(release.version, spec.version); + assert.equal(release.sqlName, spec.sqlName); + assert.deepEqual( + release.compatibility, + Object.fromEntries( + Object.entries(spec.compatibility).map(([name, value]) => [ + name.replace(/_([a-z])/gu, (_, letter) => letter.toUpperCase()), + value, + ]), + ), + ); + assert.equal( + release.assets.length, + 1, + 'selected target manifest input must not invent other platform assets', + ); + const asset = release.assets[0]; + assert.equal(asset.name, path.basename(githubFile)); + assert.equal(asset.family, 'native'); + assert.equal(asset.target, spec.target); + const bytes = readFileSync(githubFile); + assert.equal(asset.bytes, bytes.length); + assert.equal(asset.sha256, createHash('sha256').update(bytes).digest('hex')); +} +assert.equal(manifest.name, identities.npm.name); +assert.equal(manifest.version, spec.version); +assert.equal(manifest.oliphaunt.liboliphauntVersion, spec.runtimeVersion); +assert.deepEqual( + contracts.members.map((row) => row.sqlName), + [spec.sqlName], +); +const metadata = { + ...member, + nativeConstructionLicenseFiles: nativeExtensionConstructionLicenseInventory( + spec.sqlName, + spec.target, + ), +}; +validateExtensionArtifactArchive({ + file: realpathSync(githubFile), + metadata, + product: spec.product, + target: spec.target, + nativeRuntimeVersion: spec.runtimeVersion, +}); +const gh = readPortableArchiveEntries(realpathSync(githubFile)); +const canonicalEntries = readCanonicalExtensionArtifactArchive(realpathSync(githubFile)); +const validateEntries = (entries = canonicalEntries, inventory = metadata) => + validateExtensionArtifactEntries({ + entries, + metadata: inventory, + product: spec.product, + target: spec.target, + nativeRuntimeVersion: spec.runtimeVersion, + label: 'final public negative fixture', + }); +const foreignEntries = new Map(canonicalEntries); +foreignEntries.set('files/lib/modules/foreign.so', canonicalEntries.values().next().value!); +assert.throws(() => validateEntries(foreignEntries), /undeclared:/); +for (const dependency of member.nativeDependencyModules ?? []) { + const missing = new Map(canonicalEntries); + missing.delete(`files/lib/modules/${dependency}`); + assert.throws(() => validateEntries(missing), /missing:/); + assert.throws( + () => + validateEntries(canonicalEntries, { ...metadata, nativeDependencyModules: ['foreign.so'] }), + /differ from the canonical recipe/, + ); +} +for (const construction of metadata.nativeConstructionLicenseFiles) { + const missing = new Map(canonicalEntries); + missing.delete(`files/${construction.path}`); + assert.throws(() => validateEntries(missing), /missing:/); + const changed = new Map(canonicalEntries); + changed.set(`files/${construction.path}`, { + ...changed.get(`files/${construction.path}`), + sha256: '0'.repeat(64), + }); + assert.throws(() => validateEntries(changed), /does not match canonical bytes/); +} +const digest = (data: Uint8Array) => createHash('sha256').update(data).digest('hex'); +const cargoPayload = readNativeCargoPayload(cargoDirectory, identities.cargo.name, spec.version, [ + 'MIT', + ...(metadata.nativeConstructionLicenseFiles.some((row) => + row.path.startsWith('share/licenses/llvm-compiler-rt/'), + ) + ? ['Apache-2.0 WITH LLVM-exception'] + : []), +]); +for (const name of gh.keys()) + if (name.startsWith('files/')) { + const relative = name.slice('files/'.length); + assert.deepEqual( + digest(npm.get(`package/runtime/${relative}`)!.data()), + digest(gh.get(name)!.data()), + `npm differs from final GitHub member ${relative}`, + ); + assert.deepEqual( + cargoPayload.get(relative), + digest(gh.get(name)!.data()), + `Cargo differs from final GitHub member ${relative}`, + ); + } +assert.equal(cargoPayload.size, [...gh.keys()].filter((name) => name.startsWith('files/')).length); + +const root = mkdtempSync(path.join(tmpdir(), 'native-final-install-')); +let materialized: { runtimeDirectory?: string; moduleDirectory?: string } | undefined; +try { + const { assets, install, runtime, packages, materialize, sdkRuntimeVersion } = + await prepareNativeCarrierSdk({ + root, + runtimeFile, + npmFiles: [npmFile], + runtimeVersion: spec.runtimeVersion, + selected: [spec.sqlName], + }); + const targetRoot = packages[0].directory; + materialized = await materialize([spec.sqlName]); + assert(materialized.runtimeDirectory); + assert(materialized.moduleDirectory); + for (const name of gh.keys()) + if (name.startsWith('files/')) { + const relative = name.slice('files/'.length); + assert.deepEqual( + readFileSync(path.join(materialized.runtimeDirectory, relative)), + gh.get(name)!.data(), + ); + if (relative.startsWith('lib/modules/')) + assert.deepEqual( + readFileSync(path.join(materialized.moduleDirectory, path.basename(relative))), + gh.get(name)!.data(), + ); + } + exerciseNativeCarrierSql({ + root, + runtime, + materialized: materialized as { runtimeDirectory: string; moduleDirectory: string }, + consumerFile, + plans: [installSql, smokeSql, startupFile], + environment: spec.recipe.runtime_environment ?? [], + }); + if (sdkRuntimeVersion === spec.runtimeVersion) { + for (const dependency of member.nativeDependencyModules ?? []) { + const file = path.join(targetRoot, 'runtime/lib/modules', dependency); + const bytes = readFileSync(file); + rmSync(file); + await assert.rejects( + () => assets.materializeExtensionInstall(install, [spec.sqlName]), + /missing declared native dependency module/, + ); + writeFileSync(file, bytes, { mode: 0o755 }); + } + const foreign = path.join(targetRoot, 'runtime/lib/modules/foreign.so'); + mkdirSync(path.dirname(foreign), { recursive: true }); + writeFileSync(foreign, 'undeclared module'); + await assert.rejects( + () => assets.materializeExtensionInstall(install, [spec.sqlName]), + /undeclared runtime file/, + ); + } + console.log( + `${spec.product}@${spec.version}: exact final GitHub/npm/Cargo bytes, ${sdkRuntimeVersion === spec.runtimeVersion ? 'matching source SDK asset staging' : 'explicit runtime-directory staging with held SDK rejection'}, supplier identity, restart and server SQL verified.`, + ); +} finally { + if (materialized?.runtimeDirectory) + rmSync(path.dirname(materialized.runtimeDirectory), { recursive: true, force: true }); + writableDirectories(root); + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/extensions/native_extension_all_sql_test.sh b/build_defs/extensions/native_extension_all_sql_test.sh new file mode 100755 index 000000000..2d14810e8 --- /dev/null +++ b/build_defs/extensions/native_extension_all_sql_test.sh @@ -0,0 +1,96 @@ +#!/usr/bin/env bash +set -euo pipefail + +carrier="$TEST_TMPDIR/host" +runtime="$carrier/$8" +library="$carrier/$9" +consumer="$TEST_TMPDIR/consumer/bin/extension-smoke" +install="$PWD/$3" +smoke="$PWD/$4" +startup="$PWD/$5" +environment="$PWD/$6" +dependencies="$PWD/$7" +mkdir -p "$carrier" "${consumer%/*}" +cp "$PWD/$2" "$consumer" +tar -xf "$PWD/$1" -C "$carrier" +test -d "$runtime" +test -f "$library/liboliphaunt.so" +runtime=$(cd "$runtime" && pwd -P) +library=$(cd "$library" && pwd -P) +shift 9 +for member in "$@"; do + tar -xzf "$PWD/$member" -C "$runtime" --exclude=extension.json +done +if [[ "$library" != "$runtime/lib" && -d "$runtime/lib/modules" ]]; then + mkdir -p "$library/modules" + cp -a "$runtime/lib/modules/." "$library/modules/" + rm -rf "$runtime/lib/modules" +fi +while IFS=$'\t' read -r name relative required_file; do + [[ -z "$name" ]] && continue + test -f "$runtime/$relative/$required_file" + export "$name=$runtime/$relative" +done < "$environment" +export LD_LIBRARY_PATH="$library:$runtime/lib" +mv "$library/liboliphaunt.so" "$library/liboliphaunt.so.hidden" +set +e +"$consumer" > "$TEST_TMPDIR/missing-library.log" 2>&1 +status=$? +set -e +mv "$library/liboliphaunt.so.hidden" "$library/liboliphaunt.so" +if [[ "$status" != 127 ]]; then + printf 'relocated consumer accepted a missing candidate library (status %s)\n' "$status" >&2 + exit 1 +fi + +initialize() { + local database="$1" + mkdir -p "$database" + OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY=1 OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY=1 \ + "$runtime/bin/initdb" -D "$database/pgdata" -U postgres --auth=trust --no-sync --locale-provider=libc --locale=C --encoding=UTF8 + printf '%s\n' '{"schema":"oliphaunt-database-root-v1","engineFamily":"native","pgdata":"pgdata","postgresMajor":18,"physicalFormat":"native-pg18-v1"}' > "$database/.oliphaunt.json" +} + +while IFS= read -r name; do + [[ -z "$name" ]] && continue + for profile in postgresql modules; do + directory="$runtime/lib/postgresql" + [[ "$profile" == modules ]] && directory="$library/modules" + mv "$directory/$name" "$directory/$name.hidden" + database="$TEST_TMPDIR/missing-dependency-$profile-$name" + initialize "$database" + set +e + if [[ "$profile" == modules ]]; then + "$consumer" "$database/pgdata" "$runtime" --sql-plan "$install" "$smoke" "$startup" > "$database/consumer.log" 2>&1 + else + cat "$install" "$smoke" | sed 's/^-- oliphaunt-statement$//' | "$runtime/bin/postgres" --single -j -D "$database/pgdata" postgres > "$database/consumer.log" 2>&1 + fi + status=$? + set -e + mv "$directory/$name.hidden" "$directory/$name" + response=$(<"$database/consumer.log") + if [[ "$response" != *"$name"* || ( "$profile" == modules && "$status" == 0 ) || ( "$profile" == postgresql && "$response" != *ERROR:* && "$response" != *FATAL:* ) ]]; then + printf 'relocated %s consumer did not reject missing candidate dependency %s (status %s)\n%s\n' "$profile" "$name" "$status" "$response" >&2 + exit 1 + fi + done +done < "$dependencies" + +database="$TEST_TMPDIR/embedded" +initialize "$database" +"$consumer" "$database/pgdata" "$runtime" --sql-plan "$install" "$smoke" "$startup" +"$consumer" "$database/pgdata" "$runtime" --sql-plan "$install" "$smoke" "$startup" + +database="$TEST_TMPDIR/server" +initialize "$database" +startup_args=() +while IFS= read -r assignment; do + [[ -z "$assignment" ]] || startup_args+=(-c "$assignment") +done < "$startup" +log="$TEST_TMPDIR/server.log" +cat "$install" "$smoke" | sed 's/^-- oliphaunt-statement$//' | "$runtime/bin/postgres" --single -j -D "$database/pgdata" "${startup_args[@]}" postgres > "$log" 2>&1 +response=$(<"$log") +if [[ "$response" != *candidate-extension-smoke-ok* || "$response" == *ERROR:* || "$response" == *FATAL:* || "$response" == *"not ok"* ]]; then + printf '%s\n' "$response" >&2 + exit 1 +fi diff --git a/build_defs/extensions/native_extension_smoke.c b/build_defs/extensions/native_extension_smoke.c new file mode 100644 index 000000000..4510d7f37 --- /dev/null +++ b/build_defs/extensions/native_extension_smoke.c @@ -0,0 +1,122 @@ +#include "oliphaunt.h" + +#include +#include +#include +#include + +static char *read_text(const char *path) { + FILE *file = fopen(path, "rb"); + if (file == NULL) return NULL; + if (fseek(file, 0, SEEK_END)) { fclose(file); return NULL; } + long length = ftell(file); + if (length < 0 || fseek(file, 0, SEEK_SET)) { fclose(file); return NULL; } + char *text = malloc((size_t)length + 1); + if (text == NULL) { fclose(file); return NULL; } + size_t actual = fread(text, 1, (size_t)length, file); + int failed = ferror(file) || actual != (size_t)length; + fclose(file); + if (failed) { free(text); return NULL; } + text[actual] = '\0'; + return text; +} + +static uint32_t read_u32(const uint8_t *data) { + return ((uint32_t)data[0] << 24) | ((uint32_t)data[1] << 16) | + ((uint32_t)data[2] << 8) | (uint32_t)data[3]; +} + +static int query(OliphauntHandle *database, const char *sql, const char *expected) { + OliphauntResponse response = {0}; + OliphauntErrorCapture error = {0}; + if (oliphaunt_exec_simple_query_with_error(database, sql, strlen(sql), &response, &error)) { + fprintf(stderr, "extension query failed: %s: %s\n", sql, error.message); + return 1; + } + int failed = 0, complete = 0, ready = 0, matched = expected == NULL; + size_t cursor = 0; + while (cursor < response.len) { + if (response.len - cursor < 5) { failed = 1; break; } + const uint8_t *message = response.data + cursor; + uint32_t length = read_u32(message + 1); + if (length < 4 || (size_t)length + 1 > response.len - cursor) { failed = 1; break; } + if (message[0] == 'E') failed = 1; + if (message[0] == 'C') complete = 1; + if (message[0] == 'Z') ready = 1; + if (message[0] == 'D' && expected != NULL && length >= 10 && + message[5] == 0 && message[6] == 1) { + uint32_t value_length = read_u32(message + 7); + if ((size_t)value_length == strlen(expected) && value_length == length - 10 && + memcmp(message + 11, expected, value_length) == 0) matched = 1; + } + cursor += (size_t)length + 1; + } + if (failed || !complete || !ready || !matched) { + fprintf(stderr, "extension query had unexpected PostgreSQL response: %s\n", sql); + failed = 1; + } + oliphaunt_free_response(&response); + return failed; +} + +static int query_plan(OliphauntHandle *database, char *sql, const char *expected) { + const char *separator = "\n-- oliphaunt-statement\n"; + while (sql != NULL) { + char *next = strstr(sql, separator); + if (next != NULL) { *next = '\0'; next += strlen(separator); } + if (query(database, sql, next == NULL ? expected : NULL)) return 1; + sql = next; + } + return 0; +} + +int main(int argc, char **argv) { + int plan = argc == 7 && strcmp(argv[3], "--sql-plan") == 0; + if (!plan && argc != 6) return 2; + char *install = NULL, *smoke = NULL, *startup = NULL; + const char *startup_args[128]; + size_t startup_arg_count = 0; + if (plan) { + install = read_text(argv[4]); + smoke = read_text(argv[5]); + startup = read_text(argv[6]); + if (install == NULL || smoke == NULL || startup == NULL) return 2; + for (char *assignment = strtok(startup, "\n"); assignment != NULL; assignment = strtok(NULL, "\n")) { + if (startup_arg_count + 2 > sizeof(startup_args) / sizeof(startup_args[0])) return 2; + startup_args[startup_arg_count++] = "-c"; + startup_args[startup_arg_count++] = assignment; + } + } + OliphauntConfig config = { + .abi_version = OLIPHAUNT_ABI_VERSION, + .pgdata = argv[1], .runtime_dir = argv[2], + .module_dir = getenv("OLIPHAUNT_SMOKE_MODULE_DIR"), + .username = "postgres", .database = "postgres", + .startup_args = startup_arg_count ? startup_args : NULL, + .startup_arg_count = startup_arg_count, + }; + OliphauntHandle *database = NULL; + OliphauntErrorCapture error = {0}; + if (oliphaunt_init_with_error(&config, &database, &error) || database == NULL) { + fprintf(stderr, "extension runtime initialization failed: %s\n", error.message); + return 1; + } + int failed; + if (plan) failed = query_plan(database, install, NULL) || query_plan(database, smoke, "candidate-extension-smoke-ok"); + else failed = + query(database, "CREATE EXTENSION IF NOT EXISTS pg_trgm", NULL) || + query(database, "CREATE EXTENSION IF NOT EXISTS vector", NULL) || + query(database, "CREATE EXTENSION IF NOT EXISTS pgtap", NULL) || + query(database, "SELECT extversion FROM pg_extension WHERE extname = 'pg_trgm'", argv[3]) || + query(database, "SELECT extversion FROM pg_extension WHERE extname = 'vector'", argv[4]) || + query(database, "SELECT extversion FROM pg_extension WHERE extname = 'pgtap'", argv[5]) || + query(database, "SELECT plan(2)", "1..2") || + query(database, "SELECT ok(similarity('same', 'same') = 1, 'compiled contrib')", "ok 1 - compiled contrib") || + query(database, "SELECT is(('[1,2,3]'::vector <-> '[1,2,4]'::vector)::numeric, 1::numeric, 'compiled external')", "ok 2 - compiled external") || + query(database, "SELECT count(*) FROM finish()", "0"); + if (oliphaunt_close(database)) failed = 1; + free(install); + free(smoke); + free(startup); + return failed; +} diff --git a/build_defs/extensions/native_extension_sql_test.sh b/build_defs/extensions/native_extension_sql_test.sh new file mode 100755 index 000000000..0efd7efe9 --- /dev/null +++ b/build_defs/extensions/native_extension_sql_test.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +set -euo pipefail + +runtime="$TEST_TMPDIR/runtime" +smoke="$TEST_TMPDIR/consumer/bin/extension-smoke" +versions=("$3" "$4" "$5") +mkdir -p "$runtime" "${smoke%/*}" +cp "$PWD/$2" "$smoke" +tar -xf "$PWD/$1" -C "$runtime" +shift 5 +for member in "$@"; do + tar -xzf "$PWD/$member" -C "$runtime" --exclude=extension.json +done +export LD_LIBRARY_PATH="$runtime/lib" +# Relocation removes the consumer's source-runfiles RUNPATH fallback. Prove the +# actual candidate shared library is necessary before any positive SQL test. +mv "$runtime/lib/liboliphaunt.so" "$runtime/lib/liboliphaunt.so.hidden" +set +e +"$smoke" > "$TEST_TMPDIR/missing-library.log" 2>&1 +status=$? +set -e +mv "$runtime/lib/liboliphaunt.so.hidden" "$runtime/lib/liboliphaunt.so" +if [[ "$status" != 127 ]]; then + printf 'relocated consumer accepted a missing candidate library (status %s)\n' "$status" >&2 + exit 1 +fi + +initialize() { + local database="$1" + mkdir -p "$database" + OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY=1 OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY=1 \ + "$runtime/bin/initdb" -D "$database/pgdata" -U postgres --auth=trust --no-sync --locale-provider=libc --locale=C --encoding=UTF8 + printf '%s\n' '{"schema":"oliphaunt-database-root-v1","engineFamily":"native","pgdata":"pgdata","postgresMajor":18,"physicalFormat":"native-pg18-v1"}' > "$database/.oliphaunt.json" +} + +database="$TEST_TMPDIR/embedded" +initialize "$database" +# Fresh installation and a new process reopening the persisted extensions. +"$smoke" "$database/pgdata" "$runtime" "${versions[@]}" +"$smoke" "$database/pgdata" "$runtime" "${versions[@]}" + +# Independently exercise the ordinary PostgreSQL ABI variants from the same +# archive. Single-user mode avoids an ambient pg_ctl or workstation server. +database="$TEST_TMPDIR/server" +initialize "$database" +log="$TEST_TMPDIR/server.log" +"$runtime/bin/postgres" --single -D "$database/pgdata" postgres > "$log" 2>&1 <<'SQL' +CREATE EXTENSION pg_trgm; +CREATE EXTENSION vector; +CREATE EXTENSION pgtap; +SELECT 'server-extensions-ok' WHERE similarity('same', 'same') = 1 AND ('[1,2,3]'::vector <-> '[1,2,4]'::vector) = 1; +SELECT plan(1); +SELECT ok(similarity('same', 'same') = 1, 'server contrib'); +SELECT count(*) FROM finish(); +SQL +response=$(<"$log") +if [[ "$response" != *server-extensions-ok* || "$response" != *"ok 1 - server contrib"* || "$response" == *ERROR:* || "$response" == *FATAL:* ]]; then + printf '%s\n' "$response" >&2 + exit 1 +fi diff --git a/build_defs/extensions/owner_carriers.bzl b/build_defs/extensions/owner_carriers.bzl new file mode 100644 index 000000000..1e3e357f8 --- /dev/null +++ b/build_defs/extensions/owner_carriers.bzl @@ -0,0 +1,267 @@ +"""Declared final-file imports and exhaustive native extension family composition. + +Foreign-host files are inputs to these rules, never replacements for a typed C +producer. Collections are internal partial evidence. Complete family carriers +require every canonical native target and the genuine WASIX constructor for +external owners. Contrib retains separate native and WASIX runtime owners. +""" + +load("@oliphaunt_metadata//:metadata.bzl", "CONTRIB_OWNERS", "EXTENSIONS", "EXTENSION_GITHUB_ARTIFACTS", "EXTENSION_PROFILES", "EXTENSION_RELEASE_METADATA", "PRODUCTS") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_file_action", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/release:supplier.bzl", "ShippingSupplierInfo", "merge_shipping_suppliers") +load(":contrib_carriers.bzl", "native_contrib_carrier_legal", "native_contrib_carrier_metadata") +load(":construction.bzl", "desktop_member_inventory") +load(":final_leaf.bzl", "ExtensionFinalLeafInfo", "NativeAppleBaseInfo") +load(":native_carriers.bzl", "native_extension_carrier_helpers", "native_extension_carrier_legal", "native_external_carrier_metadata") + +def native_owner_carrier_helpers(): + return native_extension_carrier_helpers() + [ + "//build_defs/extensions:native_carriers.mts", + "//:src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts", + "//:src/extensions/artifacts/packages/tools/bundle-carrier-assets.mts", + "//:src/extensions/artifacts/packages/tools/package-extension-cargo-facades.mts", + "//:tools/packaging/rust-native-targets.mts", + "//src/extensions/tools:native-component-contract.mts", + "//:src/extensions/artifacts/native/tools/ios-extension-registration.mts", + "//tools/release:native-file-identity.mts", + "//tools/release:native-extension-release-files.mts", + ] + +def native_owner_carrier_metadata(product, family = "native"): + releases = [row for row in EXTENSION_RELEASE_METADATA if row["artifactProduct"] == product] + if not releases: + fail("native final join requires a canonical extension distribution: " + product) + release = releases[0] + if family not in ["native", "wasix"] or (family == "wasix" and release["class"] != "contrib"): + fail("separate WASIX owner composition only applies to runtime-owned contrib") + targets = [target for profile in EXTENSION_PROFILES["profiles"] for target in profile["targets"] if target["family"] == "native"] + target_names = sorted([target["target"] for target in targets]) + if release["class"] == "contrib": + leaf = native_contrib_carrier_metadata(target_names[0]) + members = leaf["members"] + owner = CONTRIB_OWNERS["native"] + wasix_owner = CONTRIB_OWNERS["wasix"] + else: + if len(releases) != 1: + fail("external native join requires one exact SQL member") + leaf = native_external_carrier_metadata(release["sqlName"], target_names[0]) + members = [leaf] + owner, wasix_owner = product, product + if sorted([member["sqlName"] for member in members]) != sorted([row["sqlName"] for row in releases]): + fail("native final join member set differs from canonical release metadata") + dynamic = sorted([row["target"] for row in targets if row["kind"] == "native-dynamic"]) + if family == "wasix": + owner = wasix_owner + return { + "schema": "oliphaunt-native-extension-final-join-inputs-v1", "product": product, + "owner": owner, "version": PRODUCTS[owner]["version"], "runtimeVersion": leaf["runtimeVersion"], + "releaseMetadata": release, "profiles": targets if family == "native" else [], "allProfiles": [target for profile in EXTENSION_PROFILES["profiles"] for target in profile["targets"]], + "catalogSqlNames": sorted([row["sql-name"] for row in EXTENSIONS.values()]), "members": members, "carriers": leaf["carriers"], + "ownerFamilies": ["wasix"] if family == "wasix" else (["native"] if owner != wasix_owner else ["native", "wasix"]), + "cargoFacadeMetadata": { + "nativeOwner": owner, "wasixOwner": wasix_owner, "version": leaf["version"], + "sqlNames": sorted([member["sqlName"] for member in members]), + "targets": {"nativeCargoTargets": dynamic, "includeWasixAot": any([member["descriptor"].get("native-module-file") for member in members])}, + "sdkVersion": PRODUCTS["oliphaunt-rust"]["version"], "bindingVersion": PRODUCTS["liboliphaunt-native-bindings"]["version"], + "wasixSdkVersion": PRODUCTS["oliphaunt-wasix-rust"]["version"], "compatibility": release["compatibility"], + }, + } + +def native_owner_carrier_legal(product): + spec = native_owner_carrier_metadata(product) + if spec["releaseMetadata"]["class"] == "contrib": + return native_contrib_carrier_legal() + return native_extension_carrier_legal(spec["members"][0]["sqlName"]) + +def _leaf_input(leaf): + return {"product": leaf.product, "owner": leaf.owner, "version": leaf.version, "family": leaf.family, "target": leaf.target, + "github": [file.path for file in leaf.github], "npm": [file.path for file in leaf.npm], "cargo": [file.path for file in leaf.cargo], + "manifest": leaf.manifest.path, "frozen": leaf.frozen.path, "validation": leaf.validation.path if leaf.validation else None, + "receipt": leaf.receipt.path if leaf.receipt else None, "expectedOrigin": leaf.origin, + "originalFiles": leaf.original_files.path if hasattr(leaf, "original_files") and leaf.original_files else None} + +def _leaf_files(leaf): + return leaf.github + leaf.npm + leaf.cargo + [leaf.manifest, leaf.frozen, leaf.spec] + ([leaf.validation] if leaf.validation else []) + ([leaf.receipt] if leaf.receipt else []) + +# The mobile Maven action consumes the same serialized physical final leaves. +native_final_leaf_input = _leaf_input +native_final_leaf_files = _leaf_files + +def _import_impl(ctx): + spec = native_owner_carrier_metadata(ctx.attr.product) + if ctx.attr.target not in [row["target"] for row in spec["profiles"]]: + fail("import target is absent from canonical native extension profiles") + if len(ctx.attr.source_commit) != 40 or len(ctx.attr.source_tree) != 40: + fail("foreign final files require exact Git commit and tree identities") + leaf = {"product": spec["product"], "owner": spec["owner"], "version": spec["version"], "family": "native", "target": ctx.attr.target, + "github": [file.path for file in ctx.files.github], "npm": [file.path for file in ctx.files.npm], "cargo": [file.path for file in ctx.files.cargo], + "manifest": ctx.file.manifest.path, "frozen": ctx.file.frozen.path, "receipt": ctx.file.receipt.path, + "expectedOrigin": {"commit": ctx.attr.source_commit, "tree": ctx.attr.source_tree, "runId": ctx.attr.run_id, "runAttempt": ctx.attr.run_attempt, "job": ctx.attr.job}} + spec.update({"operation": "import", "leaves": [leaf]}) + inputs = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(inputs, json.encode(spec)) + validation = ctx.actions.declare_file(ctx.label.name + ".validated.json") + spec["outputs"] = {"collection": validation.path} + # The action JSON is kept separate from the transported frozen documents. + action = ctx.actions.declare_file(ctx.label.name + ".run.json") + spec["components"] = ctx.file._components.path + ctx.actions.write(action, json.encode(spec)) + files = ctx.files.github + ctx.files.npm + ctx.files.cargo + [ctx.file.manifest, ctx.file.frozen, ctx.file.receipt, ctx.file._components] + bun_file_action(ctx, ctx.file._tool, arguments = [action.path], inputs = files + [action] + ctx.files.legal, + source_files = [ctx.file._tool] + ctx.files._helpers + ctx.files.legal, outputs = [validation], mnemonic = "ImportNativeExtensionFinalFiles") + info = ExtensionFinalLeafInfo(product = spec["product"], owner = spec["owner"], version = spec["version"], family = "native", target = ctx.attr.target, + metadata = spec, github = ctx.files.github, npm = ctx.files.npm, cargo = ctx.files.cargo, + manifest = ctx.file.manifest, frozen = ctx.file.frozen, spec = inputs, validation = validation, receipt = ctx.file.receipt, origin = leaf["expectedOrigin"]) + return [DefaultInfo(files = depset(files + [validation])), info, OutputGroupInfo(validation = depset([validation]), spec = depset([inputs]))] + +_TOOLS = {"_tool": attr.label(default = "//build_defs/extensions:owner_carriers.mts", allow_single_file = True), + "_components": attr.label(default = "//src/extensions/catalog:native-components.toml", allow_single_file = True), + "_helpers": attr.label_list(default = native_owner_carrier_helpers(), allow_files = True)} + +_native_extension_final_import = rule(implementation = _import_impl, toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(_TOOLS, **{"product": attr.string(mandatory = True), "target": attr.string(mandatory = True), + "github": attr.label_list(allow_files = True, mandatory = True), "npm": attr.label_list(allow_files = True), "cargo": attr.label_list(allow_files = True), + "manifest": attr.label(allow_single_file = True, mandatory = True), "frozen": attr.label(allow_single_file = True, mandatory = True), + "receipt": attr.label(allow_single_file = True, mandatory = True), "legal": attr.label_list(allow_files = True), + "source_commit": attr.string(mandatory = True), "source_tree": attr.string(mandatory = True), + "run_id": attr.string(mandatory = True), "run_attempt": attr.int(mandatory = True), "job": attr.string(mandatory = True)})) + +def native_extension_final_import(name, product, **kwargs): + _native_extension_final_import(name = name, product = product, legal = native_owner_carrier_legal(product), **kwargs) + +def _receipt_fixture_impl(ctx): + if not ctx.attr.testonly: + fail("receipt fixtures are only available to testonly targets") + leaf = ctx.attr.leaf[ExtensionFinalLeafInfo] + output = ctx.actions.declare_file(ctx.label.name + ".json") + inputs = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(inputs, json.encode({"qualificationFixture": {"schema": "oliphaunt-final-file-receipt-fixture-v1", "testOnly": True}, + "leaf": _leaf_input(leaf), "source": {"commit": "1" * 40, "tree": "2" * 40, "runId": "123", "runAttempt": 1, "job": "test-only-receipt-fixture"}, "output": output.path})) + bun_file_action(ctx, ctx.file._tool, arguments = [inputs.path], inputs = _leaf_files(leaf) + [inputs] + ctx.files._helpers, + source_files = [ctx.file._tool] + ctx.files._helpers, outputs = [output], mnemonic = "FinalFileReceiptFixture") + return [DefaultInfo(files = depset([output]))] + +native_extension_final_receipt_fixture = rule(implementation = _receipt_fixture_impl, toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = {"leaf": attr.label(mandatory = True, providers = [ExtensionFinalLeafInfo]), + "_tool": attr.label(default = "//build_defs/extensions:final_receipt_fixture.mts", allow_single_file = True), + "_helpers": attr.label_list(default = native_owner_carrier_helpers() + ["//build_defs/extensions:owner_carriers.mts"], allow_files = True)}) + +def _join_impl(ctx): + spec = native_owner_carrier_metadata(ctx.attr.product, ctx.attr.family) + leaves = [target[ExtensionFinalLeafInfo] for target in ctx.attr.leaves + ctx.attr.wasix_leaves] + for leaf in leaves: + if leaf.product != spec["product"] or leaf.owner != spec["owner"] or leaf.version != spec["version"] or leaf.family not in spec["ownerFamilies"]: + fail("final extension files differ from their canonical distribution owner/version") + slots = [leaf.family + "/" + leaf.target for leaf in leaves] + targets = [leaf.target for leaf in leaves if leaf.family == "native"] + if len(slots) != len({slot: True for slot in slots}): + fail("final extension join contains repeated target cohorts") + if ctx.attr.complete and sorted(targets) != sorted([row["target"] for row in spec["profiles"]]): + fail("complete native extension family requires every canonical native target; got " + ", ".join(sorted(targets))) + if ctx.attr.complete and "wasix" in spec["ownerFamilies"]: + if [leaf.target for leaf in leaves if leaf.family == "wasix"] != ["wasix-portable"]: + fail("complete extension owner requires its one genuine portable WASIX constructor") + outputs = {"collection": ctx.actions.declare_file(ctx.label.name + ".collection.json")} + if ctx.attr.complete: + outputs["frozen"] = ctx.actions.declare_file(ctx.label.name + "/extension-artifacts.json") + if "native" in spec["ownerFamilies"]: + rows = [row for row in spec["carriers"] if row["ecosystem"] == "npm" and row["target"] == None and row["role"] == "facade"] + if len(rows) != 1: + fail("complete native family requires its one canonical npm facade") + outputs["npm"] = ctx.actions.declare_file(ctx.label.name + "/npm/" + rows[0]["name"].replace("@", "").replace("/", "-") + "-" + spec["version"] + ".tgz") + outputs["cargo"] = ctx.actions.declare_file(ctx.label.name + "/cargo/" + spec["product"] + "-" + spec["version"] + ".crate") + if not ctx.file.base_carrier_manifest: + fail("complete native npm facade requires the actual native base iOS carrier manifest") + controls = [row for row in EXTENSION_GITHUB_ARTIFACTS if row["artifactProduct"] == spec["product"] and row["owner"] == spec["owner"] and row["version"] == spec["version"] and row.get("control", False)] + if not controls or len(controls) != len({row["kind"]: True for row in controls}): + fail("complete extension owner requires its canonical unique control inventory") + for row in controls: + outputs["control_" + row["kind"]] = ctx.actions.declare_file(ctx.label.name + "/github/" + row["name"]) + base = ctx.attr.base_carrier_manifest[NativeAppleBaseInfo] if ctx.attr.base_carrier_manifest and NativeAppleBaseInfo in ctx.attr.base_carrier_manifest else None + spec.update({"operation": "compose" if ctx.attr.complete else "collect", "leaves": [_leaf_input(leaf) for leaf in leaves], + "baseCarrierManifest": ctx.file.base_carrier_manifest.path if ctx.file.base_carrier_manifest else None, + "baseArchiveInputs": base.archives if base else None, + "components": ctx.file._components.path, + "outputs": {name: file.path for name, file in outputs.items()}}) + action = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(action, json.encode(spec)) + files = [file for leaf in leaves for file in _leaf_files(leaf)] + [action, ctx.file._components] + ctx.files.legal + ctx.files.base_carrier_manifest + (base.archive_files if base else []) + bun_file_action(ctx, ctx.file._tool, arguments = [action.path], inputs = files, + source_files = [ctx.file._tool] + ctx.files._helpers + ctx.files.legal, + outputs = outputs.values(), mnemonic = "NativeExtensionFamilyJoin") + groups = {name: depset([file]) for name, file in outputs.items()} + groups["spec"] = depset([action]) + targets = ctx.attr.leaves + ctx.attr.wasix_leaves + ([ctx.attr.base_carrier_manifest] if ctx.attr.base_carrier_manifest else []) + suppliers = [target[ShippingSupplierInfo] for target in targets if ShippingSupplierInfo in target] + supplier = merge_shipping_suppliers(suppliers) if len(suppliers) == len(targets) else ShippingSupplierInfo(suppliers = None, files = depset(transitive = [info.files for info in suppliers])) + return [DefaultInfo(files = depset(outputs.values())), OutputGroupInfo(**groups), supplier] + +_native_extension_final_join = rule(implementation = _join_impl, toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(_TOOLS, **{"product": attr.string(mandatory = True), "leaves": attr.label_list(providers = [ExtensionFinalLeafInfo], mandatory = True), + "wasix_leaves": attr.label_list(providers = [ExtensionFinalLeafInfo]), "family": attr.string(default = "native", values = ["native", "wasix"]), + "complete": attr.bool(default = False), "base_carrier_manifest": attr.label(allow_single_file = True), "legal": attr.label_list(allow_files = True)})) + +def native_extension_final_collection(name, product, leaves, **kwargs): + _native_extension_final_join(name = name, product = product, leaves = leaves, legal = native_owner_carrier_legal(product), **kwargs) + +def native_extension_family_carriers(name, product, leaves, base_carrier_manifest = None, wasix_leaves = [], family = "native", **kwargs): + _native_extension_final_join(name = name, product = product, leaves = leaves, complete = True, + wasix_leaves = wasix_leaves, family = family, + base_carrier_manifest = base_carrier_manifest, legal = native_owner_carrier_legal(product), **kwargs) + +def _final_contract_test_impl(ctx): + leaves = [target[ExtensionFinalLeafInfo] for target in ctx.attr.leaves] + if sorted([leaf.product for leaf in leaves]) != sorted(ctx.attr.products): + fail("final contract cohort must contain each selected canonical distribution exactly once") + targets = {leaf.target: True for leaf in leaves} + if len(targets) != 1: + fail("final contract cohort must use one actual native target") + specs = [] + for leaf in leaves: + spec = native_owner_carrier_metadata(leaf.product) + if leaf.owner != spec["owner"] or leaf.version != spec["version"] or leaf.family != "native": + fail("final contract leaf differs from its canonical native owner") + spec.update({"operation": "collect", "leaves": [_leaf_input(leaf)], "components": ctx.file._components.path, "outputs": {}}) + specs.append(spec) + members = sorted([member["sqlName"] for spec in specs for member in spec["members"]]) + if ctx.attr.members and members != sorted(ctx.attr.members): + fail("final contract leaves differ from the declared construction member cohort") + inventory = ctx.actions.declare_file(ctx.label.name + ".inventory.json") + ctx.actions.write(inventory, json.encode({"schema": "oliphaunt-native-extension-final-contract-test-v1", "scope": "construction", "target": targets.keys()[0], "products": specs, "members": members, "excluded": sorted(ctx.attr.excluded)})) + sources = [ctx.file._runner] + ctx.files._helpers + ctx.files.legal + files = [inventory, ctx.file._components] + [file for leaf in leaves for file in _leaf_files(leaf)] + sources + return bun_test_entrypoint(ctx, ctx.file._runner, [inventory], files, source_files = sources) + [OutputGroupInfo(inventory = depset([inventory]))] + +_native_extension_final_contract_test = rule(implementation = _final_contract_test_impl, test = True, toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "products": attr.string_list(mandatory = True), "leaves": attr.label_list(mandatory = True, providers = [ExtensionFinalLeafInfo]), + "members": attr.string_list(), "excluded": attr.string_list(), + "legal": attr.label_list(allow_files = True), + "_runner": attr.label(default = "//build_defs/extensions:final_contract.test.mts", allow_single_file = True), + "_components": _TOOLS["_components"], + "_helpers": attr.label_list(default = native_owner_carrier_helpers() + ["//build_defs/extensions:owner_carriers.mts"], allow_files = True), + })) + +def native_extension_final_contract_test(name, products = None, desktop = False, include_postgis = False, leaves = None, **kwargs): + """Validate genuine final packages on the execution host, without target SQL.""" + if include_postgis and not desktop: + fail("explicit PostGIS cohort selection requires the canonical desktop inventory") + members, excluded = [], [] + if desktop: + if products != None: + fail("desktop final contract uses the existing complete desktop construction inventory") + members = [row.name for row in desktop_member_inventory(include_postgis)] + selected = sorted({row["artifactProduct"]: True for row in EXTENSION_RELEASE_METADATA if row["sqlName"] in members}.keys()) + excluded = sorted([row["sql-name"] for row in EXTENSIONS.values() if row["sql-name"] not in members]) + else: + selected = sorted({row["artifactProduct"]: True for row in EXTENSION_RELEASE_METADATA}.keys()) if products == None else sorted(products) + if not selected or len(selected) != len({product: True for product in selected}): + fail("final contract qualification requires unique canonical distributions") + selected_leaves, legal = [], {} + for product in selected: + spec = native_owner_carrier_metadata(product) + package = "src/extensions/contrib" if spec["releaseMetadata"]["class"] == "contrib" else PRODUCTS[product]["path"] + selected_leaves.append("//" + package + ":native_carriers") + for label in native_owner_carrier_legal(product): + legal[label] = True + _native_extension_final_contract_test(name = name, products = selected, members = members, excluded = excluded, leaves = selected_leaves if leaves == None else leaves, legal = legal.keys(), args = bun_test_entrypoint_args(name), **kwargs) diff --git a/build_defs/extensions/owner_carriers.mts b/build_defs/extensions/owner_carriers.mts new file mode 100644 index 000000000..049ea026e --- /dev/null +++ b/build_defs/extensions/owner_carriers.mts @@ -0,0 +1,1026 @@ +/** Join final extension files without invoking or replacing their producers. */ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + copyFileSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + realpathSync, + rmSync, + statSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + assertStaticMemberAliases, + staticMemberAliases, + staticSymbolPrefix, +} from '../../src/extensions/artifacts/native/tools/ios-extension-registration.mts'; +import { + composeExtensionReleaseDocuments, + nativeAssetNameForRow, + writeReleaseControls, +} from '../../src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts'; +import { + isDesktopNativeTarget, + nativeDependencyModuleBasenames, + nativeModuleHostTarget, + validateExtensionArtifactArchive, +} from '../../src/extensions/artifacts/packages/tools/extension-artifact-inventory.mts'; +import { + expectedExtensionRoles, + projectNativeRuntimeAssetMember, +} from '../../src/extensions/artifacts/packages/tools/extension-runtime-asset-contract.mts'; +import { packageExtensionCargoFacades } from '../../src/extensions/artifacts/packages/tools/package-extension-cargo-facades.mts'; +import { + frozenExtensionMemberInventory, + stageExtensionNativeNpmFacade, +} from '../../src/extensions/artifacts/packages/tools/package-extension-release-carriers.mts'; +import { + extensionCarrierLegalContract, + nativeExtensionConstructionLicenseInventory, +} from '../../src/extensions/tools/extension-upstream-licenses.mts'; +import { + resolveNativeComponentClosure, + validateNativeComponentContract, +} from '../../src/extensions/tools/native-component-contract.mts'; +import { + buildIosCarrierManifest, + buildSwiftExtensionCarrierManifest, +} from '../../src/native/sdks/swift/tools/ios-carrier-manifest.mts'; +import { inspectPlatformBinaryEntries } from '../../tools/packaging/platform-binary-contract.mts'; +import { readPortableArchiveEntries } from '../../tools/packaging/portable-archive.mts'; +import { + assertReleaseNoticesInArchive, + releaseNoticeRows, +} from '../../tools/packaging/release-notices.mts'; +import type { ExtensionFinalInput } from '../../tools/release/native-extension-final-inputs.mts'; +import { stageDeclaredExtensionReleaseFiles } from '../../tools/release/native-extension-release-files.mts'; +import { safeRelative } from '../../tools/release/native-file-identity.mts'; +import { + type NativeCarrierSpec, + stageNativeRegistryCarriers, + writeJson, +} from './native_carriers.mts'; +import { + inspectStaticArchiveBytes, + validateNativeMemberModule, +} from './validate_member_payload.mts'; + +export interface FinalLeaf { + product: string; + owner: string; + version: string; + family: 'native' | 'wasix'; + target: string; + github: string[]; + npm: string[]; + cargo: string[]; + manifest: string; + frozen: string; + receipt?: string; + expectedOrigin?: Record; + validation?: string; + /** The existing controller-authenticated File map checked by the importer. */ + originalFiles?: string; +} +export interface NativeOwnerSpec { + schema: string; + product: string; + owner: string; + version: string; + runtimeVersion: string; + releaseMetadata: Record; + members: NativeCarrierSpec[]; + profiles: any[]; + allProfiles: any[]; + catalogSqlNames: string[]; + carriers: any[]; + ownerFamilies: string[]; + cargoFacadeMetadata: any; + components: string; + leaves: FinalLeaf[]; + operation: 'import' | 'collect' | 'compose'; + baseCarrierManifest?: string; + baseArchiveInputs?: Record; + outputs: Record; +} + +/** Stage the original qualified constructor bytes, without requalifying foreign binaries. */ +export function stageDeclaredFinalLeaf(spec: NativeOwnerSpec, leaf: FinalLeaf, root: string) { + assert(leaf.originalFiles, 'declared final leaf requires its original File map'); + const original = json(leaf.originalFiles) as ExtensionFinalInput; + for (const name of ['product', 'owner', 'version', 'family', 'target'] as const) + assert.equal( + original[name], + leaf[name], + 'imported final leaf differs from its original constructor', + ); + for (const name of ['github', 'npm', 'cargo'] as const) + assert.deepEqual( + original[name].map((file) => file.path), + leaf[name], + ); + assert.equal(original.manifest.path, leaf.manifest); + assert.equal(original.frozen.path, leaf.frozen); + assert.equal(leaf.product, spec.product); + assert.equal(leaf.owner, spec.owner); + assert.equal(leaf.version, spec.version); + const productRoot = path.join(root, 'product'); + const staged = stageDeclaredExtensionReleaseFiles( + json(leaf.frozen), + leaf.github, + productRoot, + root, + ); + return { + leaf, + members: staged.members, + directAssets: staged.directAssets, + inventory: finalFileInventory(leaf), + productRoot, + }; +} +const digest = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +const json = (file: string) => JSON.parse(readFileSync(file, 'utf8')); +const role = (asset: any) => + `${asset.family}:${asset.target}:${asset.kind}:${asset.identity ?? ''}`; +const relative = (root: string, file: string) => + path.relative(root, file).split(path.sep).join('/'); +const sorted = (values: string[] = []) => [...values].sort(); + +function filesAt(input: string): string[] { + const file = realpathSync(input); + if (statSync(file).isFile()) return [file]; + assert(statSync(file).isDirectory(), 'final file input must be a regular file or declared tree'); + return readdirSync(file, { withFileTypes: true }) + .flatMap((entry) => { + // Declared tree inputs use Bazel's file symlink forest. Follow regular + // file aliases only; archive member safety is checked independently. + assert( + entry.isFile() || + entry.isDirectory() || + (entry.isSymbolicLink() && statSync(path.join(file, entry.name)).isFile()), + 'final carrier tree aliases must resolve to regular files', + ); + return filesAt(path.join(file, entry.name)); + }) + .sort(); +} + +/** Transport binds only declared final files, not compiler outputs or ambient paths. */ +export function finalFileInventory(leaf: FinalLeaf) { + const inputs = [ + ...leaf.github.flatMap((file) => filesAt(file).map((name) => ['github', name])), + ...leaf.npm.flatMap((file) => filesAt(file).map((name) => ['npm', name])), + ...leaf.cargo.flatMap((file) => filesAt(file).map((name) => ['cargo', name])), + ['control', realpathSync(leaf.manifest)], + ['control', realpathSync(leaf.frozen)], + ]; + const rows = inputs + .map(([ecosystem, file]) => ({ + path: `${ecosystem}/${path.basename(file)}`, + sha256: digest(readFileSync(file)), + bytes: statSync(file).size, + })) + .sort((a, b) => a.path.localeCompare(b.path)); + assert.equal( + new Set(rows.map((row) => row.path)).size, + rows.length, + 'repeated final-file identity', + ); + return rows; +} + +export function validateFinalFileReceipt(leaf: FinalLeaf) { + assert( + leaf.receipt && leaf.expectedOrigin, + 'imported final files require an immutable source/run receipt', + ); + const receipt = json(leaf.receipt); + assert.deepEqual(Object.keys(receipt).sort(), [ + 'files', + 'owner', + 'product', + 'schema', + 'scope', + 'source', + 'target', + 'version', + ]); + assert.equal(receipt.schema, 'oliphaunt-extension-final-files-v1'); + assert.equal(receipt.scope, 'construction', 'final-file transport is construction evidence'); + for (const key of ['product', 'owner', 'version', 'target']) + assert.equal(receipt[key], leaf[key as keyof FinalLeaf]); + assert.deepEqual( + receipt.source, + leaf.expectedOrigin, + 'foreign final files belong to a different source or producing run', + ); + assert.deepEqual(Object.keys(receipt.source).sort(), [ + 'commit', + 'job', + 'runAttempt', + 'runId', + 'tree', + ]); + for (const key of ['commit', 'tree']) assert.match(receipt.source[key], /^[0-9a-f]{40}$/u); + assert.match(receipt.source.runId, /^[1-9][0-9]*$/u); + assert(Number.isSafeInteger(receipt.source.runAttempt) && receipt.source.runAttempt > 0); + assert.match(receipt.source.job, /^[A-Za-z0-9_-]+$/u); + assert.deepEqual( + receipt.files, + finalFileInventory(leaf), + 'transported final bytes differ from their immutable receipt', + ); +} + +function expectedMember(spec: NativeCarrierSpec, target: string, selected?: any) { + const artifact = spec.recipe.artifacts ?? {}; + const startup = spec.descriptor.lifecycle['startup-config'] ?? []; + return { + sqlName: spec.sqlName, + createsExtension: spec.descriptor.lifecycle['create-extension'], + nativeModuleStem: spec.descriptor['native-module-file']?.replace(/\.[^.]+$/u, '') ?? null, + dependencies: sorted(spec.selectedDependencies), + dataFiles: sorted(spec.contrib ? spec.contrib['data-files'] : artifact.data_files).map( + (file) => { + assert(file.startsWith('share/postgresql/')); + return file.slice('share/postgresql/'.length); + }, + ), + extensionSqlFileNames: sorted(artifact.extension_sql_file_names), + extensionSqlFilePrefixes: sorted(artifact.extension_sql_file_prefixes), + sharedPreloadLibraries: startup + .flatMap((value: string) => + value.startsWith('shared_preload_libraries=') + ? value.slice('shared_preload_libraries='.length).split(',') + : [], + ) + .sort(), + nativeDependencyModules: + isDesktopNativeTarget(target) || selected?.nativeDependencyModules?.length > 0 + ? nativeDependencyModuleBasenames( + artifact.native_dependency_modules, + target, + artifact.native_dependency_modules_by_target, + ) + : [], + nativeConstructionLicenseFiles: + isDesktopNativeTarget(target) || selected?.nativeConstructionLicenseFiles?.length > 0 + ? nativeExtensionConstructionLicenseInventory(spec.sqlName, target) + : [], + }; +} + +function declaredApple(spec: NativeOwnerSpec) { + return { + declaredProducts: { + [spec.product]: { + product: spec.product, + releaseProduct: spec.owner, + version: spec.version, + sqlNames: spec.members.map((member) => member.sqlName).sort(), + tag: `${spec.owner}-v${spec.version}`, + }, + }, + baseTag: `liboliphaunt-native-v${spec.runtimeVersion}`, + }; +} + +function componentContract(spec: NativeOwnerSpec) { + return validateNativeComponentContract(Bun.TOML.parse(readFileSync(spec.components, 'utf8')), { + checkSourcePaths: false, + knownExtensions: new Set(spec.catalogSqlNames), + targetProfiles: new Map( + spec.allProfiles.map((row) => [row.target, `${row.family}\0${row.kind}`]), + ), + }); +} + +function mobileRuntimeContract(member: any, target: string, components: any) { + const targets = target === 'ios-xcframework' ? ['ios-device', 'ios-simulator'] : [target]; + const closure = resolveNativeComponentClosure(components, { + extension: member.sqlName, + family: 'native', + kind: 'native-static-registry', + target, + }); + const units = components.components.flatMap((component: any) => component.linkUnits); + const dependencies = closure.linkUnits + .flatMap((identity: string) => { + const unit = units.find((item: any) => item.id === identity); + const names = [ + ...new Set(unit.archiveCandidates.map((file: string) => path.posix.basename(file))), + ]; + assert.equal(names.length, 1, 'canonical mobile link unit requires one archive basename'); + return targets.map( + (cohort) => + `${cohort}:${identity}:mobile-static/${cohort}/dependencies/${identity}/${names[0]}`, + ); + }) + .sort(); + const stem = member.nativeModuleStem; + if (target === 'ios-xcframework' && stem !== null) + assertStaticMemberAliases( + member.sqlName, + stem, + (member.iosRegistration?.symbols ?? []).filter((row: any) => row.name !== row.address), + ); + return { + target, + archives: + stem === null + ? [] + : targets + .map( + (cohort) => + `${cohort}:mobile-static/${cohort}/extensions/${stem}/liboliphaunt_extension_${stem}.a`, + ) + .sort(), + dependencies, + symbolPrefix: stem === null ? '' : staticSymbolPrefix(stem), + symbolAliases: staticMemberAliases(member.sqlName, stem) + .map((row) => `${row.name}:${row.address}`) + .sort(), + }; +} + +function assertAsset(asset: any, file: string) { + assert.equal(path.basename(file), asset.name, 'final asset name differs from its manifest'); + assert.equal( + digest(readFileSync(file)), + asset.sha256, + 'final asset SHA differs from its manifest', + ); + assert.equal(statSync(file).size, asset.bytes, 'final asset size differs from its manifest'); +} + +function copyAsset(asset: any, file: string, destination: string, root: string) { + mkdirSync(path.dirname(destination), { recursive: true }); + copyFileSync(file, destination); + return { + ...asset, + path: relative(root, destination), + source: asset.source ?? relative(root, destination), + }; +} + +function compareFinalRegistryFiles(expected: string[], actual: string[], label: string) { + const inventory = (files: string[]) => + files + .flatMap(filesAt) + .map((file) => ({ + name: path.basename(file), + sha256: digest(readFileSync(file)), + bytes: statSync(file).size, + })) + .sort((a, b) => a.name.localeCompare(b.name)); + assert.deepEqual( + inventory(actual), + inventory(expected), + `${label} final packages differ from the canonical writer applied to the verified public payload`, + ); +} + +/** Validate one actual native target, including registry leaves and nested legal bytes. */ +export function validateNativeFinalLeaf(spec: NativeOwnerSpec, leaf: FinalLeaf, root: string) { + for (const [key, wanted] of [ + ['product', spec.product], + ['owner', spec.owner], + ['version', spec.version], + ['family', 'native'], + ]) + assert.equal(leaf[key as keyof FinalLeaf], wanted); + const profile = spec.profiles.find((row) => row.target === leaf.target); + assert(profile, 'final leaf target is absent from canonical native profiles'); + if (leaf.receipt) validateFinalFileReceipt(leaf); + const frozen = json(leaf.frozen); + const release = json(leaf.manifest); + const bundle = spec.members.length > 1; + assert.equal(frozen.schema, `oliphaunt-extension-ci-artifacts-v${bundle ? 2 : 1}`); + assert.equal(release.schema, `oliphaunt-extension-release-manifest-v${bundle ? 2 : 1}`); + for (const document of [frozen, release]) { + assert.equal(document.product, spec.product); + assert.equal(document.version, spec.version); + assert.equal(document.releaseProduct ?? document.product, spec.owner); + assert.deepEqual(document.compatibility, spec.releaseMetadata.compatibility); + } + assert.deepEqual( + release.sourceIdentity, + spec.releaseMetadata.sourceIdentity, + 'final leaf source identity differs from canonical immutable acquisition', + ); + assert.equal(release.extensionClass, spec.releaseMetadata.class); + assert.equal(release.versioning, spec.releaseMetadata.versioning); + const members = bundle ? frozen.extensions : [frozen]; + assert.deepEqual( + members.map((member: any) => member.sqlName).sort(), + spec.members.map((member) => member.sqlName).sort(), + 'final leaf member set differs from canonical distribution', + ); + const physical = new Map(leaf.github.flatMap(filesAt).map((file) => [path.basename(file), file])); + assert.equal(physical.size, leaf.github.flatMap(filesAt).length); + const directAssets = bundle ? frozen.carrierAssets : members[0].assets; + assert.equal(frozen.family ?? 'native', 'native'); + const declaredRelease = composeExtensionReleaseDocuments({ + product: spec.product, + releaseProduct: spec.owner, + family: frozen.family ?? null, + version: spec.version, + members, + directAssets, + releaseMetadata: spec.releaseMetadata, + }).releaseData; + assert.deepEqual( + release, + JSON.parse(JSON.stringify(declaredRelease)), + 'transported public manifest differs from its frozen member/assets contract', + ); + assert.equal(new Set(directAssets.map((asset: any) => asset.name)).size, directAssets.length); + assert.deepEqual( + [...physical.keys()].sort(), + directAssets.map((asset: any) => asset.name).sort(), + 'declared GitHub files must cover the frozen assets exactly', + ); + const productRoot = path.join(root, 'product'); + mkdirSync(path.join(productRoot, 'release-assets'), { recursive: true }); + const direct = directAssets.map((asset: any) => { + assert.equal(asset.family, 'native'); + assert.equal(asset.target, leaf.target); + const file = physical.get(asset.name)!; + assertAsset(asset, file); + if (bundle) { + assert.equal(asset.kind, 'extension-bundle'); + assert.equal( + asset.name, + `${spec.product}-${spec.version}-native-${leaf.target}-bundle.tar.gz`, + ); + } + return copyAsset(asset, file, path.join(productRoot, 'release-assets', asset.name), root); + }); + const nested = new Map(); + if (bundle) { + assert.equal(direct.length, 1, 'one target cohort requires one closed final contrib bundle'); + const outer = readPortableArchiveEntries(physical.get(direct[0].name)!); + const prefix = path.basename(direct[0].name, '.tar.gz'); + const index = JSON.parse(outer.get(`${prefix}/bundle-manifest.json`)!.data().toString('utf8')); + assert.equal(index.schema, 'oliphaunt-extension-bundle-v1'); + for (const [key, wanted] of [ + ['product', spec.product], + ['version', spec.version], + ['family', 'native'], + ['target', leaf.target], + ]) + assert.equal(index[key], wanted); + assert.deepEqual(index.compatibility, spec.releaseMetadata.compatibility); + const legal = extensionCarrierLegalContract( + spec.product, + spec.members.map((member) => member.sqlName), + { + family: 'native', + target: leaf.target, + memberContracts: members.map((member: any) => { + const asset = member.assets.find( + (row: any) => + row.family === 'native' && row.kind === 'runtime' && row.target === leaf.target, + ); + return projectNativeRuntimeAssetMember(member, asset); + }), + }, + ); + assert.equal(index.licenseProfile, legal.profile); + assert.deepEqual(index.licenseFiles, legal.licenseFiles); + assert.equal( + index.members.length, + members.reduce((count: number, member: any) => count + member.assets.length, 0), + ); + assertReleaseNoticesInArchive(physical.get(direct[0].name)!, { + prefix, + profile: index.licenseProfile, + }); + assert.deepEqual( + [...outer.keys()].sort(), + [ + `${prefix}/bundle-manifest.json`, + ...index.members.map((member: any) => `${prefix}/${member.path}`), + ...releaseNoticeRows({ profile: index.licenseProfile }).map( + (row) => `${prefix}/${row.member}`, + ), + ].sort(), + 'contrib outer archive contains undeclared files', + ); + for (const member of members) + for (const asset of member.assets) { + const row = index.members.find( + (item: any) => + item.sqlName === member.sqlName && + item.kind === asset.kind && + item.identity === asset.identity, + ); + assert(row, 'nested frozen asset is missing from its closed bundle'); + assert.equal(asset.carrierAsset, direct[0].name); + assert.equal(asset.carrierRoot, prefix); + assert.equal(asset.memberPath, row.path); + assert.equal(asset.sha256, row.sha256); + assert.equal(asset.bytes, row.bytes); + assert.equal(row.path, `extensions/${member.sqlName}/${asset.name}`); + const bytes = outer.get(`${prefix}/${row.path}`)!.data(); + assert.equal(digest(bytes), row.sha256); + assert.equal(bytes.length, row.bytes); + const destination = path.join(productRoot, 'member-assets', member.sqlName, asset.name); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, bytes); + nested.set(`${member.sqlName}\0${role(asset)}`, destination); + } + } + const components = componentContract(spec); + const staged = members.map((member: any) => { + const canonical = spec.members.find((item) => item.sqlName === member.sqlName)!; + const runtimeAsset = member.assets.find( + (asset: any) => + asset.family === 'native' && asset.kind === 'runtime' && asset.target === leaf.target, + ); + assert(runtimeAsset, 'final leaf requires its actual native runtime asset'); + const selectedMember = projectNativeRuntimeAssetMember(member, runtimeAsset); + const expected = expectedMember(canonical, leaf.target, selectedMember); + for (const [key, wanted] of Object.entries(expected)) { + assert.deepEqual( + selectedMember[key] ?? (Array.isArray(wanted) ? [] : wanted), + wanted, + `${member.sqlName}.${key} differs from canonical source contract`, + ); + } + const iosNativeDependencies = member.iosNativeDependencies ?? []; + const iosRegistration = member.iosRegistration ?? null; + const ios = leaf.target === 'ios-xcframework'; + const dependencyIds = ios + ? resolveNativeComponentClosure(components, { + extension: member.sqlName, + family: 'native', + kind: 'native-static-registry', + target: leaf.target, + }).linkUnits.sort() + : []; + assert.deepEqual( + iosNativeDependencies, + dependencyIds, + 'iOS dependency identities differ from the canonical component closure', + ); + if (!ios || expected.nativeModuleStem === null) assert.equal(iosRegistration, null); + else assert(iosRegistration, 'compiled iOS member requires build-derived registration'); + const normalized = { ...expected, iosNativeDependencies, iosRegistration, wasixInstall: null }; + if (normalized.nativeDependencyModules.length === 0) delete normalized.nativeDependencyModules; + if (normalized.nativeConstructionLicenseFiles.length === 0) + delete normalized.nativeConstructionLicenseFiles; + const actualRoles = member.assets.map(role).sort(); + assert.equal(new Set(actualRoles).size, actualRoles.length, 'repeated final member role'); + assert.deepEqual( + actualRoles, + expectedExtensionRoles(normalized, [leaf.target]), + 'final member roles differ from canonical profiles and component closure', + ); + const assets = member.assets.map((asset: any) => { + if ( + ['nativeDependencyModules', 'nativeConstructionLicenseFiles'].some((field) => + Object.hasOwn(asset, field), + ) + ) + frozenExtensionMemberInventory(member, { + product: spec.product, + version: spec.version, + target: asset.target, + asset, + }); + const file = bundle + ? nested.get(`${member.sqlName}\0${role(asset)}`)! + : physical.get(asset.name)!; + assert.equal( + asset.name, + nativeAssetNameForRow(spec.product, spec.version, { ...asset, asset: file }), + ); + assertAsset(asset, file); + if (asset.kind === 'runtime') { + const mobileContract = + profile.kind === 'native-static-registry' + ? mobileRuntimeContract(normalized, leaf.target, components) + : undefined; + const runtime = validateExtensionArtifactArchive({ + file, + metadata: normalized, + product: spec.product, + target: leaf.target, + nativeRuntimeVersion: spec.runtimeVersion, + mobileContract, + }); + const hostTarget = nativeModuleHostTarget(leaf.target); + for (const [name, entry] of runtime.entries) { + if (name.startsWith('files/lib/')) + validateNativeMemberModule(entry.data, hostTarget, name.slice('files/'.length)); + } + for (const row of [ + ...(mobileContract?.archives ?? []), + ...(mobileContract?.dependencies ?? []), + ]) { + const cohort = row.slice(0, row.indexOf(':')); + const name = row.slice(row.lastIndexOf(':') + 1); + const entry = runtime.entries.get(name)!; + inspectStaticArchiveBytes(entry.data, cohort, asset.name); + } + } else { + inspectPlatformBinaryEntries( + [...readPortableArchiveEntries(file)].map(([name, entry]) => ({ ...entry, name })), + { + target: 'ios-xcframework', + rootLabel: asset.name, + }, + ); + } + return { + ...asset, + path: relative(root, bundle ? file : path.join(productRoot, 'release-assets', asset.name)), + }; + }); + return { ...normalized, assets }; + }); + const documents = composeExtensionReleaseDocuments({ + product: spec.product, + releaseProduct: spec.owner, + family: 'native', + version: spec.version, + members: staged, + directAssets: direct, + releaseMetadata: spec.releaseMetadata, + }); + writeJson(path.join(productRoot, 'extension-artifacts.json'), documents.manifest); + writeJson( + path.join(productRoot, 'release-assets', `${spec.product}-${spec.version}-manifest.json`), + documents.releaseData, + ); + if (leaf.target === 'ios-xcframework') + buildSwiftExtensionCarrierManifest({ + extensionManifest: path.join(productRoot, 'extension-artifacts.json'), + assetRoot: root, + nativeRuntimeVersion: spec.runtimeVersion, + ...declaredApple(spec), + }); + if (profile.kind === 'native-dynamic') { + const canonical = spec.members[0]; + const facades = spec.carriers.filter( + (row) => row.ecosystem === 'npm' && row.target === null && row.role === 'facade', + ); + assert.equal(facades.length, 1, 'native registry cohort requires its canonical npm facade'); + const npm = spec.carriers.filter( + (row) => + row.ecosystem === 'npm' && + row.target === leaf.target && + row.name === `${facades[0].name}-${leaf.target}`, + ); + const cargo = spec.carriers.filter( + (row) => + row.ecosystem === 'cargo' && + row.target === leaf.target && + row.name === `${spec.product}-${leaf.target}`, + ); + assert.equal(npm.length, 1); + assert.equal(cargo.length, 1); + const outputs = { + github: physical.get(direct[0].name)!, + npm: path.join( + root, + 'registry', + npm[0].name.replace('@', '').replace('/', '-') + '-' + spec.version + '.tgz', + ), + cargo: path.join(root, 'registry', 'cargo'), + manifest: '', + frozen: '', + }; + mkdirSync(path.dirname(outputs.npm), { recursive: true }); + const registrySpec = { + ...canonical, + product: spec.product, + owner: spec.owner, + target: leaf.target, + version: spec.version, + runtimeVersion: spec.runtimeVersion, + carriers: spec.carriers, + outputs, + }; + stageNativeRegistryCarriers(registrySpec, productRoot, root); + compareFinalRegistryFiles([outputs.npm], leaf.npm, 'npm'); + compareFinalRegistryFiles([outputs.cargo], leaf.cargo, 'Cargo'); + } else { + assert.equal(leaf.npm.length, 0, 'mobile cohort has no native npm target leaf'); + assert.equal(leaf.cargo.length, 0, 'mobile cohort has no native Cargo target leaf'); + } + return { + leaf, + members: staged, + directAssets: direct, + inventory: finalFileInventory(leaf), + productRoot, + }; +} + +export function nativeFamilyCompleteness(spec: NativeOwnerSpec, targets: string[]) { + assert.equal(new Set(targets).size, targets.length, 'repeated final target cohort'); + const wanted = spec.profiles.map((row) => row.target).sort(); + assert( + targets.every((target) => wanted.includes(target)), + 'undeclared native final target', + ); + const missingNativeTargets = wanted.filter((target) => !targets.includes(target)); + return { + completeNativeFamily: missingNativeTargets.length === 0, + missingNativeTargets, + completeExtensionDistribution: + missingNativeTargets.length === 0 && spec.ownerFamilies.length === 1, + missingOwnerFamilies: spec.ownerFamilies.filter((family) => family !== 'native'), + }; +} + +export function ownerFamilyCompleteness(spec: NativeOwnerSpec, leaves: FinalLeaf[]) { + const slots = leaves.map((leaf) => `${leaf.family}/${leaf.target}`); + assert.equal(new Set(slots).size, slots.length, 'repeated final owner cohort'); + const native = nativeFamilyCompleteness( + spec, + leaves.filter((leaf) => leaf.family === 'native').map((leaf) => leaf.target), + ); + const families = new Set(leaves.map((leaf) => leaf.family)); + assert( + leaves.every((leaf) => spec.ownerFamilies.includes(leaf.family)), + 'undeclared final owner family', + ); + assert( + leaves + .filter((leaf) => leaf.family === 'wasix') + .every((leaf) => leaf.target === 'wasix-portable'), + 'WASIX final cohort must come from its portable constructor', + ); + const missingOwnerFamilies = spec.ownerFamilies.filter( + (family) => !families.has(family as FinalLeaf['family']), + ); + return { + ...native, + missingOwnerFamilies, + completeExtensionDistribution: native.completeNativeFamily && missingOwnerFamilies.length === 0, + }; +} + +/** Keep common SQL metadata once and bind construction facts to their payload. */ +export function mergeNativeFinalMembers(spec: NativeOwnerSpec, cohorts: { members: any[] }[]) { + return spec.members.map((canonical) => { + const rows = cohorts.map((cohort) => + cohort.members.find((member: any) => member.sqlName === canonical.sqlName), + ); + assert(rows.every(Boolean), 'final join is missing a canonical SQL member'); + for (const field of [ + 'createsExtension', + 'nativeModuleStem', + 'dependencies', + 'dataFiles', + 'extensionSqlFileNames', + 'extensionSqlFilePrefixes', + 'sharedPreloadLibraries', + ]) { + const value = rows[0][field]; + for (const row of rows.slice(1)) + assert.deepEqual( + row[field], + value, + `final ${canonical.sqlName}.${field} differs across original constructor cohorts`, + ); + } + const ios = rows.find((member: any) => + member.assets.some((asset: any) => asset.target === 'ios-xcframework'), + ); + const base = { iosNativeDependencies: [], iosRegistration: null, ...(ios ?? rows[0]) }; + const wasix = rows.filter((member) => member.wasixInstall != null); + assert(wasix.length <= 1, 'final member repeats its original WASIX install contract'); + base.wasixInstall = wasix[0]?.wasixInstall ?? null; + delete base.nativeConstructionLicenseFiles; + delete base.nativeDependencyModules; + const assets = rows.flatMap((member: any) => + member.assets.map((asset: any) => { + if (asset.family !== 'native' || asset.kind !== 'runtime') return asset; + const inventory = frozenExtensionMemberInventory(member, { + product: spec.product, + version: spec.version, + target: asset.target, + asset, + }); + const result = { ...asset }; + for (const field of ['nativeDependencyModules', 'nativeConstructionLicenseFiles']) { + if (inventory[field] !== undefined) result[field] = inventory[field]; + } + return result; + }), + ); + assert.equal( + new Set(assets.map(role)).size, + assets.length, + 'repeated final member role across constructors', + ); + return { ...base, assets }; + }); +} + +export function composeNativeFinalCarriers(spec: NativeOwnerSpec) { + assert.equal(spec.schema, 'oliphaunt-native-extension-final-join-inputs-v1'); + assert(spec.leaves.length > 0, 'final join requires actual declared final files'); + const completeness = ownerFamilyCompleteness(spec, spec.leaves); + if (spec.operation === 'compose') { + assert( + completeness.completeNativeFamily, + `missing native final targets: ${completeness.missingNativeTargets.join(', ')}`, + ); + assert( + completeness.completeExtensionDistribution, + `missing owner families: ${completeness.missingOwnerFamilies.join(', ')}`, + ); + } + const root = mkdtempSync(path.join(tmpdir(), 'native-extension-final-join-')); + try { + const validated = spec.leaves.map((leaf, index) => + leaf.originalFiles + ? stageDeclaredFinalLeaf(spec, leaf, path.join(root, String(index))) + : validateNativeFinalLeaf(spec, leaf, path.join(root, String(index))), + ); + const collection = { + schema: 'oliphaunt-native-extension-final-collection-v1', + scope: 'construction', + product: spec.product, + releaseProduct: spec.owner, + version: spec.version, + ...completeness, + targets: spec.leaves.map((leaf) => leaf.target).sort(), + members: spec.members.map((member) => member.sqlName).sort(), + compatibility: spec.releaseMetadata.compatibility, + sourceIdentity: spec.releaseMetadata.sourceIdentity, + imports: spec.leaves + .filter((leaf) => leaf.receipt) + .map((leaf) => ({ target: leaf.target, source: leaf.expectedOrigin })), + files: validated.flatMap(({ leaf, inventory }) => + inventory.map((row) => ({ target: leaf.target, ...row })), + ), + }; + if (spec.operation === 'compose') { + if (spec.outputs.npm) + assert( + spec.baseCarrierManifest, + 'complete native npm facade requires actual frozen base Apple carriers', + ); + // Host payloads remain original shipping roots. Only the resulting + // facade/control Files leave this temporary composition directory. + const productRoot = path.resolve(spec.outputs.github ?? path.join(root, 'family', 'product')); + const outputRoot = path.dirname(productRoot); + mkdirSync(path.join(productRoot, 'release-assets'), { recursive: true }); + const directAssets = validated.flatMap((cohort) => + cohort.directAssets.map((asset) => + copyAsset( + asset, + path.join(path.dirname(cohort.productRoot), asset.path), + path.join(productRoot, 'release-assets', asset.name), + outputRoot, + ), + ), + ); + const members = mergeNativeFinalMembers(spec, validated).map((member) => ({ + ...member, + assets: member.assets.map((asset: any) => { + if (spec.members.length === 1) + return { ...asset, ...directAssets.find((item) => role(item) === role(asset)) }; + const cohort = validated.find((item) => item.leaf.target === asset.target)!; + const file = path.join(path.dirname(cohort.productRoot), asset.path); + return copyAsset( + asset, + file, + path.join(productRoot, 'member-assets', member.sqlName, asset.name), + outputRoot, + ); + }), + })); + const family = spec.ownerFamilies.length > 1 ? null : spec.ownerFamilies[0]; + const documents = composeExtensionReleaseDocuments({ + product: spec.product, + releaseProduct: spec.owner, + family, + version: spec.version, + members, + directAssets, + releaseMetadata: spec.releaseMetadata, + }); + const controls = writeReleaseControls({ + product: spec.product, + releaseProduct: spec.owner, + family, + version: spec.version, + productRoot, + root: outputRoot, + ...documents, + releaseMetadata: spec.releaseMetadata, + directAssets, + swiftOptions: { ...declaredApple(spec), assetRoot: outputRoot }, + }); + mkdirSync(path.dirname(spec.outputs.frozen), { recursive: true }); + copyFileSync(path.join(productRoot, 'extension-artifacts.json'), spec.outputs.frozen); + if (spec.outputs.npm) { + const iosCarrier = buildIosCarrierManifest({ + assetRoot: outputRoot, + baseCarrierManifest: spec.baseCarrierManifest + ? realpathSync(spec.baseCarrierManifest) + : undefined, + baseArchiveInputs: spec.baseArchiveInputs + ? Object.fromEntries( + Object.entries(spec.baseArchiveInputs).map(([role, file]) => [ + role, + { ...file, path: realpathSync(file.path) }, + ]), + ) + : undefined, + baseRuntimeVersion: spec.runtimeVersion, + extensionManifests: [path.join(productRoot, 'extension-artifacts.json')], + ...declaredApple(spec), + }); + const result = { staged: [], skipped: [] }; + const facade = stageExtensionNativeNpmFacade( + path.join(root, 'npm-source'), + path.dirname(spec.outputs.npm), + { + product: spec.product, + version: spec.version, + members: members.map((member) => member.sqlName), + targets: spec.profiles + .filter((profile) => profile.kind === 'native-dynamic') + .map((profile) => profile.target) + .sort(), + iosCarrier, + liboliphauntVersion: spec.runtimeVersion, + runtimeBound: spec.releaseMetadata.versioning === 'runtime-bound', + }, + result, + ); + assert(facade, 'canonical npm facade exceeded the shipping size cap'); + assert.equal( + path.basename(facade), + path.basename(spec.outputs.npm), + 'npm facade output differs from canonical identity', + ); + if (path.resolve(facade) !== path.resolve(spec.outputs.npm)) + copyFileSync(facade, spec.outputs.npm); + } + if (spec.outputs.cargo) { + assert( + completeness.completeExtensionDistribution, + 'external Cargo facade also requires the genuine WASIX final leaves', + ); + const packages = packageExtensionCargoFacades( + [spec.product], + path.join(root, 'cargo-facade'), + { + metadataByProduct: { [spec.product]: spec.cargoFacadeMetadata }, + }, + ); + assert.equal(packages.length, 1); + assert.equal( + path.basename(packages[0].cratePath), + path.basename(spec.outputs.cargo), + 'Cargo facade output differs from canonical identity', + ); + mkdirSync(path.dirname(spec.outputs.cargo), { recursive: true }); + copyFileSync(packages[0].cratePath, spec.outputs.cargo); + } + collection['controls'] = Object.fromEntries( + Object.entries(controls) + .filter(([, file]) => file !== null) + .map(([kind, file]) => [kind, path.basename(file as string)]), + ); + for (const [kind, field] of Object.entries({ + 'manifest-json': 'releaseManifest', + 'manifest-properties': 'propertiesManifest', + 'swift-extension-carrier': 'swiftCarrier', + checksums: 'checksumManifest', + })) { + const file = controls[field]; + const output = spec.outputs[`control_${kind}`]; + if (output) { + assert(file, `canonical control ${kind} is absent`); + mkdirSync(path.dirname(output), { recursive: true }); + copyFileSync(file, output); + } + } + } + writeJson(spec.outputs.collection, collection); + return collection; + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + assert.equal(process.argv.length, 3, 'usage: owner_carriers.mts '); + composeNativeFinalCarriers(json(process.argv[2])); +} diff --git a/build_defs/extensions/owner_carriers.test.mts b/build_defs/extensions/owner_carriers.test.mts new file mode 100644 index 000000000..9a2ce3ee9 --- /dev/null +++ b/build_defs/extensions/owner_carriers.test.mts @@ -0,0 +1,385 @@ +/** Actual Linux leaves remain partial; immutable import rejects changed bytes. */ +import assert from 'node:assert/strict'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { composeExtensionReleaseDocuments } from '../../src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts'; +import { frozenExtensionMemberInventory } from '../../src/extensions/artifacts/packages/tools/package-extension-release-carriers.mts'; +import { stageNativeRegistryCarriers, writeJson } from './native_carriers.mts'; +import { + composeNativeFinalCarriers, + finalFileInventory, + mergeNativeFinalMembers, + type NativeOwnerSpec, + nativeFamilyCompleteness, + validateFinalFileReceipt, + validateNativeFinalLeaf, +} from './owner_carriers.mts'; + +const [ + pgtapSpecFile, + contribSpecFile, + pgtapCollectionFile, + contribCollectionFile, + importedFixtureFile, + postgisSpecFile, + postgisCollectionFile, + importedCollectionFile, +] = process.argv.slice(2); +const root = mkdtempSync(path.join(tmpdir(), 'native-final-composition-test-')); +const read = (file: string) => JSON.parse(readFileSync(file, 'utf8')); +const declared = (file: string) => + path.join( + process.env.TEST_SRCDIR!, + process.env.TEST_WORKSPACE ?? '_main', + file.replace(/^bazel-out\/[^/]+\/bin\//u, ''), + ); +function specAt(file: string): NativeOwnerSpec { + const spec = read(file); + spec.components = declared(spec.components); + for (const leaf of spec.leaves) { + for (const group of ['github', 'npm', 'cargo']) leaf[group] = leaf[group].map(declared); + leaf.manifest = declared(leaf.manifest); + leaf.frozen = declared(leaf.frozen); + } + return spec; +} + +function projectedRegistryIdentity( + spec: NativeOwnerSpec, + cohort: ReturnType, + members: any[], + metadataOnlyTarget: string, +) { + const fixture = { + schema: 'oliphaunt-mixed-native-inventory-fixture-v1', + testOnly: true, + actualTargets: ['linux-x64-gnu'], + metadataOnlyTargets: [metadataOnlyTarget], + completeShippingFamily: false, + }; + const documents = composeExtensionReleaseDocuments({ + product: spec.product, + releaseProduct: spec.owner, + family: 'native', + version: spec.version, + members, + directAssets: cohort.directAssets, + releaseMetadata: spec.releaseMetadata, + }); + documents.manifest.qualificationFixture = fixture; + documents.releaseData.qualificationFixture = fixture; + writeJson(path.join(cohort.productRoot, 'extension-artifacts.json'), documents.manifest); + writeJson( + path.join( + cohort.productRoot, + 'release-assets', + `${spec.product}-${spec.version}-manifest.json`, + ), + documents.releaseData, + ); + const outputs = { + github: spec.leaves[0].github[0], + npm: path.join(root, spec.product, 'projected-registry', path.basename(spec.leaves[0].npm[0])), + cargo: path.join(root, spec.product, 'projected-registry', 'cargo'), + manifest: '', + frozen: '', + }; + mkdirSync(path.dirname(outputs.npm), { recursive: true }); + stageNativeRegistryCarriers( + { + ...spec.members[0], + owner: spec.owner, + product: spec.product, + target: 'linux-x64-gnu', + version: spec.version, + runtimeVersion: spec.runtimeVersion, + carriers: spec.carriers, + outputs, + }, + cohort.productRoot, + path.join(root, spec.product, 'projected-staging'), + ); + assert.deepEqual( + finalFileInventory({ ...spec.leaves[0], npm: [outputs.npm], cargo: [outputs.cargo] }), + finalFileInventory(spec.leaves[0]), + 'mixed-target projection preserves every actual Linux registry byte and legal receipt', + ); +} + +try { + const pgtap = specAt(pgtapSpecFile), + contrib = specAt(contribSpecFile), + postgis = specAt(postgisSpecFile); + const importedFixture = read(importedFixtureFile); + assert.equal(importedFixture.completeNativeFamily, false); + assert.deepEqual(importedFixture.files, read(pgtapCollectionFile).files); + assert.equal(importedFixture.imports[0].source.job, 'test-only-receipt-fixture'); + assert.deepEqual( + read(importedCollectionFile), + importedFixture, + 'typed imported leaves preserve their immutable source/run receipt through subsequent collection', + ); + for (const [spec, file, count] of [ + [pgtap, pgtapCollectionFile, 1], + [contrib, contribCollectionFile, 32], + [postgis, postgisCollectionFile, 1], + ] as const) { + const collection = read(file); + assert.equal(collection.schema, 'oliphaunt-native-extension-final-collection-v1'); + assert.equal(collection.scope, 'construction'); + assert.equal(collection.completeNativeFamily, false); + assert.equal(collection.completeExtensionDistribution, false); + assert.equal(collection.members.length, count); + assert.deepEqual(collection.targets, ['linux-x64-gnu']); + assert.deepEqual( + collection.missingNativeTargets, + spec.profiles + .map((row) => row.target) + .filter((target) => target !== 'linux-x64-gnu') + .sort(), + ); + assert.deepEqual( + collection.files, + finalFileInventory(spec.leaves[0]).map((row) => ({ target: 'linux-x64-gnu', ...row })), + ); + assert.throws( + () => composeNativeFinalCarriers({ ...spec, operation: 'compose' }), + /missing native final targets/u, + ); + assert.throws( + () => nativeFamilyCompleteness(spec, ['linux-x64-gnu', 'linux-x64-gnu']), + /repeated/u, + ); + assert.throws(() => nativeFamilyCompleteness(spec, ['fabricated-platform']), /undeclared/u); + } + const allTargets = pgtap.profiles.map((row) => row.target); + const native = nativeFamilyCompleteness(pgtap, allTargets); + assert.equal(native.completeNativeFamily, true); + assert.equal(native.completeExtensionDistribution, false); + assert.deepEqual(native.missingOwnerFamilies, ['wasix']); + assert.equal(nativeFamilyCompleteness(contrib, allTargets).completeExtensionDistribution, true); + for (const spec of [pgtap, contrib]) { + const changed = read(spec.leaves[0].manifest); + if (changed.extensions) changed.extensions[0].dependencies = ['undeclared-member']; + else changed.assets[0].sha256 = '0'.repeat(64); + const manifest = path.join(root, `${spec.product}-changed-public.json`); + writeJson(manifest, changed); + assert.throws( + () => + validateNativeFinalLeaf( + spec, + { ...spec.leaves[0], manifest }, + path.join(root, `${spec.product}-changed-public`), + ), + /public manifest differs from its frozen/u, + ); + } + + const actualLinux = validateNativeFinalLeaf( + contrib, + contrib.leaves[0], + path.join(root, 'actual-linux'), + ); + // This second cohort is explicitly a metadata fixture. Its Android roles + // exercise inventory selection; no foreign binary is produced or accepted. + const metadataOnly = { + members: structuredClone(actualLinux.members).map((member: any) => { + delete member.nativeConstructionLicenseFiles; + delete member.nativeDependencyModules; + member.assets = member.assets.map((asset: any) => ({ + ...asset, + target: 'android-arm64-v8a', + name: asset.name.replace('linux-x64-gnu', 'android-arm64-v8a'), + carrierAsset: asset.carrierAsset.replace('linux-x64-gnu', 'android-arm64-v8a'), + carrierRoot: asset.carrierRoot.replace('linux-x64-gnu', 'android-arm64-v8a'), + memberPath: asset.memberPath.replace('linux-x64-gnu', 'android-arm64-v8a'), + })); + return member; + }), + }; + const mixed = mergeNativeFinalMembers(contrib, [actualLinux, metadataOnly]); + const crypto = mixed.find((member) => member.sqlName === 'pgcrypto')!; + assert.equal( + crypto.nativeConstructionLicenseFiles, + undefined, + 'joined member must not globally assert a target-specific incorporation', + ); + const linuxAsset = crypto.assets.find((asset: any) => asset.target === 'linux-x64-gnu')!; + const androidAsset = crypto.assets.find((asset: any) => asset.target === 'android-arm64-v8a')!; + assert.equal(linuxAsset.nativeConstructionLicenseFiles.length, 2); + assert.equal(androidAsset.nativeConstructionLicenseFiles, undefined); + const selected = (asset: any) => + frozenExtensionMemberInventory(crypto, { + product: contrib.product, + version: contrib.version, + target: asset.target, + asset, + }); + assert.equal(selected(linuxAsset).nativeConstructionLicenseFiles.length, 2); + assert.equal(selected(androidAsset).nativeConstructionLicenseFiles, undefined); + assert.equal( + selected({ + ...androidAsset, + nativeConstructionLicenseFiles: linuxAsset.nativeConstructionLicenseFiles, + }).nativeConstructionLicenseFiles.length, + 2, + 'mobile metadata accepts only the canonical construction receipts from its declared host', + ); + assert.throws( + () => + selected({ + ...androidAsset, + nativeConstructionLicenseFiles: linuxAsset.nativeConstructionLicenseFiles.map( + (row: any, index: number) => + index === 0 ? { ...row, path: 'share/licenses/undeclared-source/LICENSE' } : row, + ), + }), + /construction|immutable|inventory/u, + ); + assert.throws( + () => + selected({ + ...linuxAsset, + nativeConstructionLicenseFiles: linuxAsset.nativeConstructionLicenseFiles.map( + (row: any, index: number) => (index === 0 ? { ...row, sha256: '0'.repeat(64) } : row), + ), + }), + /construction|immutable|inventory/u, + ); + assert.throws( + () => + selected({ + ...linuxAsset, + kind: 'ios-xcframework', + nativeConstructionLicenseFiles: linuxAsset.nativeConstructionLicenseFiles, + }), + /native runtime/u, + ); + const oldGlobal = actualLinux.members.find((member: any) => member.sqlName === 'pgcrypto')!; + assert.deepEqual( + frozenExtensionMemberInventory(oldGlobal).nativeConstructionLicenseFiles, + selected(linuxAsset).nativeConstructionLicenseFiles, + 'old member-global defaults remain supported', + ); + projectedRegistryIdentity(contrib, actualLinux, mixed, 'android-arm64-v8a'); + + const actualPostgis = validateNativeFinalLeaf( + postgis, + postgis.leaves[0], + path.join(root, 'actual-postgis'), + ); + const metadataOnlyMac = { + members: structuredClone(actualPostgis.members).map((member: any) => { + delete member.nativeDependencyModules; + member.assets = member.assets.map((asset: any) => ({ + ...asset, + target: 'macos-arm64', + name: asset.name.replace('linux-x64-gnu', 'macos-arm64'), + })); + return member; + }), + }; + const mixedPostgis = mergeNativeFinalMembers(postgis, [actualPostgis, metadataOnlyMac]); + const postgisMember = mixedPostgis[0]; + assert.equal(postgisMember.nativeDependencyModules, undefined); + const postgisLinuxAsset = postgisMember.assets.find( + (asset: any) => asset.target === 'linux-x64-gnu', + ); + const postgisMacAsset = postgisMember.assets.find((asset: any) => asset.target === 'macos-arm64'); + assert.deepEqual(postgisLinuxAsset.nativeDependencyModules, ['liboliphaunt_postgis_deps.so']); + assert.equal(postgisMacAsset.nativeDependencyModules, undefined); + assert.deepEqual( + frozenExtensionMemberInventory(postgisMember, { + product: postgis.product, + version: postgis.version, + asset: postgisLinuxAsset, + }).nativeDependencyModules, + ['liboliphaunt_postgis_deps.so'], + ); + assert.throws( + () => + frozenExtensionMemberInventory(postgisMember, { + asset: postgisLinuxAsset, + target: 'macos-arm64', + }), + /target/u, + ); + projectedRegistryIdentity(postgis, actualPostgis, mixedPostgis, 'macos-arm64'); + + // Only source/run identities below are fixtures. Every transported package + // and digest is from the actual declared Linux producer, never a foreign leaf. + const leaf = { + ...pgtap.leaves[0], + receipt: path.join(root, 'receipt.json'), + expectedOrigin: { + commit: '1'.repeat(40), + tree: '2'.repeat(40), + runId: '123', + runAttempt: 1, + job: 'source-fixture-linux', + }, + }; + const receipt = { + schema: 'oliphaunt-extension-final-files-v1', + scope: 'construction', + product: leaf.product, + owner: leaf.owner, + version: leaf.version, + target: leaf.target, + source: leaf.expectedOrigin, + files: finalFileInventory(leaf), + }; + writeFileSync(leaf.receipt, JSON.stringify(receipt)); + validateFinalFileReceipt(leaf); + const imported = composeNativeFinalCarriers({ + ...pgtap, + operation: 'import', + leaves: [leaf], + outputs: { collection: path.join(root, 'imported.json') }, + }); + assert.equal(imported.completeNativeFamily, false); + assert.deepEqual(imported.files, read(pgtapCollectionFile).files); + assert.throws( + () => + validateFinalFileReceipt({ + ...leaf, + expectedOrigin: { ...leaf.expectedOrigin, commit: '3'.repeat(40) }, + }), + /different source/u, + ); + writeFileSync(leaf.receipt, JSON.stringify({ ...receipt, files: receipt.files.slice(1) })); + assert.throws(() => validateFinalFileReceipt(leaf), /immutable receipt/u); + writeFileSync( + leaf.receipt, + JSON.stringify({ + ...receipt, + files: receipt.files.map((row, index) => + index === 0 ? { ...row, sha256: '0'.repeat(64) } : row, + ), + }), + ); + assert.throws(() => validateFinalFileReceipt(leaf), /immutable receipt/u); + const forged = read(contrib.leaves[0].frozen); + forged.extensions[0].dependencies = ['foreign_extension']; + const forgedFile = path.join(root, 'extension-artifacts.json'); + writeFileSync(forgedFile, JSON.stringify(forged)); + const forgedRelease = read(contrib.leaves[0].manifest); + forgedRelease.extensions[0].dependencies = ['foreign_extension']; + const forgedManifest = path.join(root, 'forged-public-manifest.json'); + writeJson(forgedManifest, forgedRelease); + assert.throws( + () => + validateNativeFinalLeaf( + contrib, + { ...contrib.leaves[0], frozen: forgedFile, manifest: forgedManifest }, + path.join(root, 'forged'), + ), + /canonical source contract/u, + ); + console.log( + 'Actual Linux pgtap, PostGIS, and all32 contrib final-file joins PASS; mixed-target inventory metadata fixtures preserve every Linux package byte; immutable source/run fixtures tested; six native targets remain absent; external WASIX owner join remains absent.', + ); +} finally { + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/extensions/pgtap_sql.mts b/build_defs/extensions/pgtap_sql.mts new file mode 100644 index 000000000..cfde0d1b8 --- /dev/null +++ b/build_defs/extensions/pgtap_sql.mts @@ -0,0 +1,210 @@ +/** Expand the pinned pgTAP SQL inputs without running the PGXS scheduler. */ +import { spawnSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { parseArgs } from 'node:util'; + +// Admission guard for the qualified upstream PG18 installation recipes. A +// changed Makefile requires upstream-byte parity review before this is updated. +const QUALIFIED_MAKEFILE_SHA256 = + '24288f38f6a50a61fa351903716bef0d76b892ca1e88f21f396adf067ef24fe7'; +const utf8 = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }); + +function readText(file: string): string { + return utf8.decode(readFileSync(file)).replace(/\r\n?/g, '\n'); +} + +function linesWithEnds(text: string): string[] { + // Keep all line endings, including a final unterminated line, as splitlines + // did in the original generator. Exact patch context must not lose bytes. + return ( + text.match( + /[^\r\n\v\f\x1c-\x1e\x85\u2028\u2029]*(?:\r\n|[\r\n\v\f\x1c-\x1e\x85\u2028\u2029])|[^\r\n\v\f\x1c-\x1e\x85\u2028\u2029]+$/g, + ) ?? [] + ); +} + +/** Apply a single-file upstream compatibility patch with exact context. */ +export function applyPatch(text: string, patch: string): string { + const source = linesWithEnds(text); + const lines = linesWithEnds(patch); + if (lines[0] !== '--- sql/pgtap.sql\n' || lines[1] !== '+++ sql/pgtap.sql\n') { + throw new Error('pgTAP compatibility patch must modify sql/pgtap.sql only'); + } + const result: string[] = []; + let cursor = 0; + let index = 2; + while (index < lines.length) { + const header = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@[^\n]*\n$/.exec(lines[index]); + if (!header || header[0] !== lines[index]) { + throw new Error('invalid pgTAP compatibility hunk'); + } + const oldCount = Number(header[2] ?? 1); + const newCount = Number(header[4] ?? 1); + index += 1; + const before: string[] = []; + const after: string[] = []; + while (index < lines.length && !lines[index].startsWith('@@ ')) { + const line = lines[index]; + if (![' ', '+', '-'].includes(line[0])) { + throw new Error('invalid pgTAP compatibility patch line'); + } + if (line[0] !== '+') before.push(line.slice(1)); + if (line[0] !== '-') after.push(line.slice(1)); + index += 1; + } + if (before.length !== oldCount || after.length !== newCount) { + throw new Error('pgTAP compatibility hunk counts disagree'); + } + const matches: number[] = []; + for (let position = cursor; position <= source.length - before.length; position += 1) { + if (before.every((line, offset) => source[position + offset] === line)) { + matches.push(position); + } + } + if (matches.length !== 1) { + throw new Error('pgTAP compatibility patch context is missing or ambiguous'); + } + const position = matches[0]; + result.push(...source.slice(cursor, position), ...after); + cursor = position + before.length; + } + result.push(...source.slice(cursor)); + return result.join(''); +} + +export function expand(text: string, osName: string, version: string, module = 'pgtap'): string { + if (/^[a-zA-Z0-9_]+$/.exec(osName)?.[0] !== osName) { + throw new Error('pgTAP OS must be an explicit portable target name'); + } + if (/^\d+\.\d+\.\d+$/.exec(version)?.[0] !== version) { + throw new Error('pgTAP default version must have three numeric components'); + } + return text + .replaceAll('MODULE_PATHNAME', () => module) + .replaceAll('__OS__', osName) + .replaceAll('__VERSION__', version.split('.').slice(0, 2).join('.')); +} + +export function uninstallRecipe(makefile: string): string { + const contents = readFileSync(makefile); + if (createHash('sha256').update(contents).digest('hex') !== QUALIFIED_MAKEFILE_SHA256) { + throw new Error( + 'pgTAP Makefile installation semantics require upstream-byte parity qualification', + ); + } + const match = + /^sql\/uninstall_pgtap\.sql: sql\/pgtap\.sql test\/setup\.sql\n\t\$\(PERL\) -e '([^\n]+)' \$< > \$@\n(?=\n)/m.exec( + utf8.decode(contents), + ); + if (!match) throw new Error('unsupported upstream pgTAP uninstall recipe'); + return match[1].replaceAll('$$', '$'); +} + +export function runPerl( + perl: string, + libraries: string[], + arguments_: string[], + sql: string, + options: string[] = [], +): string { + const result = spawnSync(perl, [...options, ...arguments_], { + input: Buffer.from(sql), + env: { + ...process.env, + PERL5LIB: libraries.join(path.delimiter), + PERL5OPT: '', + PERL_UNICODE: '', + LC_ALL: 'C', + }, + stdio: ['pipe', 'pipe', 'inherit'], + maxBuffer: 16 * 1024 * 1024, + }); + if (result.error) throw result.error; + if (result.status !== 0) { + throw new Error(`pgTAP Perl generator failed: ${result.signal ?? result.status}`); + } + return utf8.decode(result.stdout); +} + +export function generate( + source: string, + output: string, + osName: string, + version: string, + perl: string, + libraries: string[], + perlOptions: string[] = [], +): void { + const uninstall = uninstallRecipe(path.join(source, 'Makefile')); + const control = readText(path.join(source, 'pgtap.control')); + const actual = /^default_version\s*=\s*'([^']+)'/m.exec(control); + if (!actual || actual[1] !== version) { + throw new Error('pinned pgTAP control disagrees with the canonical default version'); + } + const template = readText(path.join(source, 'sql/pgtap.sql.in')); + const main = expand(template, osName, version); + let staticSql = template; + for (const patch of readdirSync(path.join(source, 'compat')) + .filter((name) => name.startsWith('install-') && name.endsWith('.patch')) + .sort() + .reverse()) { + staticSql = applyPatch(staticSql, readText(path.join(source, 'compat', patch))); + } + staticSql = expand(staticSql, osName, version, '$libdir/pgtap'); + const files = new Map([ + ['pgtap.control', control], + [`pgtap--${version}.sql`, main], + [ + `pgtap-core--${version}.sql`, + runPerl(perl, libraries, [path.join(source, 'compat/gencore'), '0'], staticSql, perlOptions), + ], + [ + `pgtap-schema--${version}.sql`, + runPerl(perl, libraries, [path.join(source, 'compat/gencore'), '1'], staticSql, perlOptions), + ], + ['uninstall_pgtap.sql', runPerl(perl, libraries, ['-e', uninstall], main, perlOptions)], + ]); + for (const file of readdirSync(path.join(source, 'sql')).sort()) { + if (file.startsWith('pgtap--') && (file.endsWith('.sql') || file.endsWith('.sql.in'))) { + const name = file.endsWith('.in') ? file.slice(0, -3) : file; + if (files.has(name)) throw new Error(`duplicate pgTAP installed SQL identity: ${name}`); + files.set(name, readText(path.join(source, 'sql', file))); + } + } + mkdirSync(output, { recursive: true }); + if (readdirSync(output).length) throw new Error('pgTAP SQL output directory must be empty'); + for (const name of [...files.keys()].sort()) { + writeFileSync(path.join(output, name), files.get(name) as string); + } +} + +if (import.meta.main) { + const { values } = parseArgs({ + args: Bun.argv.slice(2), + options: { + source: { type: 'string' }, + output: { type: 'string' }, + os: { type: 'string' }, + version: { type: 'string' }, + perl: { type: 'string' }, + 'perl-lib': { type: 'string', multiple: true, default: [] }, + 'perl-option': { type: 'string', multiple: true, default: [] }, + }, + allowPositionals: false, + }); + const { source, output, os, version, perl } = values; + if ( + source === undefined || + output === undefined || + os === undefined || + version === undefined || + perl === undefined + ) { + throw new Error( + 'usage: pgtap_sql.mts --source DIR --output DIR --os OS --version VERSION --perl PATH [--perl-lib DIR ...]', + ); + } + generate(source, output, os, version, perl, values['perl-lib'], values['perl-option']); +} diff --git a/build_defs/extensions/pgtap_sql.test.mts b/build_defs/extensions/pgtap_sql.test.mts new file mode 100644 index 000000000..c70ad2f3e --- /dev/null +++ b/build_defs/extensions/pgtap_sql.test.mts @@ -0,0 +1,61 @@ +/** Independent SQL-content checks for the bounded pgTAP generator. */ +import assert from 'node:assert/strict'; +import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import { applyPatch, expand, runPerl, uninstallRecipe } from './pgtap_sql.mts'; + +test('compatibility patch context must match once', () => { + const patch = '--- sql/pgtap.sql\n+++ sql/pgtap.sql\n@@ -2,2 +2,1 @@\n keep\n-remove\n'; + assert.equal(applyPatch('begin\nkeep\nremove\nend\n', patch), 'begin\nkeep\nend\n'); + assert.throws(() => applyPatch('keep\nremove\nkeep\nremove\n', patch), /missing or ambiguous/); + assert.throws(() => applyPatch('begin\nchanged\nremove\n', patch), /missing or ambiguous/); + assert.equal(applyPatch('begin\nkeep\nremove\nend', patch), 'begin\nkeep\nend'); +}); + +test('compatibility patches cannot change other files or use malformed hunks', () => { + assert.throws(() => applyPatch('x\n', '--- other.sql\n+++ other.sql\n'), /only/); + assert.throws( + () => applyPatch('x\n', '--- sql/pgtap.sql\n+++ sql/pgtap.sql\n@@ -1,2 +1,1 @@\n-x\n+y\n'), + /counts/, + ); +}); + +test('target OS and SQL version are explicit', () => { + assert.equal(expand('__OS__ __VERSION__ MODULE_PATHNAME', 'linux', '1.3.5'), 'linux 1.3 pgtap'); + assert.equal(expand('MODULE_PATHNAME', 'linux', '1.3.5', '$libdir/pgtap'), '$libdir/pgtap'); + assert.equal(expand('MODULE_PATHNAME', 'linux', '1.3.5', '$& $$'), '$& $$'); + assert.throws(() => expand('__OS__', '../linux', '1.3.5'), /OS/); + assert.throws(() => expand('__OS__', 'linux\n', '1.3.5'), /OS/); + assert.throws(() => expand('__VERSION__', 'linux', 'latest'), /version/); + assert.throws(() => expand('__VERSION__', 'linux', '1.3.5\n'), /version/); +}); + +test('changed upstream installation semantics fail closed', () => { + const directory = mkdtempSync(path.join(tmpdir(), 'oliphaunt-pgtap-makefile-')); + try { + const makefile = path.join(directory, 'Makefile'); + writeFileSync(makefile, 'sql/pgtap.sql: changed-generation\n'); + assert.throws(() => uninstallRecipe(makefile), /upstream-byte parity qualification/); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('generator output rejects invalid UTF8 and preserves a UTF8 BOM', () => { + // The declared Bun executable supplies controlled stdout bytes; this test + // needs no additional Perl installation or upstream source inputs. + assert.throws(() => + runPerl(process.execPath, [], ['-e', 'process.stdout.write(Buffer.from([0xff]))'], ''), + ); + assert.equal( + runPerl( + process.execPath, + [], + ['-e', 'process.stdout.write(Buffer.from([0xef, 0xbb, 0xbf, 0x61]))'], + '', + ), + '\ufeffa', + ); +}); diff --git a/build_defs/extensions/pgtap_upstream_parity_test.mts b/build_defs/extensions/pgtap_upstream_parity_test.mts new file mode 100644 index 000000000..3548f9d88 --- /dev/null +++ b/build_defs/extensions/pgtap_upstream_parity_test.mts @@ -0,0 +1,162 @@ +/** Compare the actual installed tree with qualified upstream PG18 recipes. */ +import { spawnSync } from 'node:child_process'; +import { + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + realpathSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { parseArgs } from 'node:util'; + +const utf8 = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }); + +function readText(file: string): string { + return utf8.decode(readFileSync(file)).replace(/\r\n?/g, '\n'); +} + +export function compare( + control: string, + installed: string, + perl: string, + patch: string, + perlOptions: string[] = [], + osName = 'linux', +): void { + if (!['linux', 'darwin', 'MSWin32'].includes(osName)) + throw new Error('upstream parity requires an explicit supported pgTAP target OS'); + const source = path.dirname(control); + const libraries = readdirSync(path.dirname(perl)) + .filter((name) => name.startsWith('perl_lib_')) + .sort((a, b) => Number(a.slice(9)) - Number(b.slice(9))) + .map((name) => path.join(path.dirname(perl), name)); + const environment = { + ...process.env, + PERL5LIB: libraries.join(path.delimiter), + PERL5OPT: '', + PERL_UNICODE: '', + LC_ALL: 'C', + }; + const version = /^default_version\s*=\s*'([^']+)'/m.exec(readText(control))?.[1]; + if (!version) throw new Error('pinned pgTAP control has no default version'); + const numeric = version.split('.').slice(0, 2).join('.'); + const template = readText(path.join(source, 'sql/pgtap.sql.in')); + const main = template + .replaceAll('MODULE_PATHNAME', 'pgtap') + .replaceAll('__OS__', osName) + .replaceAll('__VERSION__', numeric); + const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-pgtap-parity-')); + try { + mkdirSync(path.join(root, 'sql')); + const staticPath = path.join(root, 'sql/pgtap.sql'); + writeFileSync(staticPath, template); + // Actual upstream patch execution is independent of the production + // TypeScript patch implementation. Refuse fuzzy matches in this proof. + for (const compatibility of readdirSync(path.join(source, 'compat')) + .filter((name) => name.startsWith('install-') && name.endsWith('.patch')) + .sort() + .reverse()) { + const result = spawnSync(realpathSync(patch), ['--batch', '--fuzz=0', '-p0'], { + input: readFileSync(path.join(source, 'compat', compatibility)), + cwd: root, + env: environment, + stdio: ['pipe', 'ignore', 'inherit'], + }); + if (result.error) throw result.error; + if (result.status !== 0) { + throw new Error(`upstream pgTAP patch failed: ${result.signal ?? result.status}`); + } + } + const staticSql = readText(staticPath) + .replaceAll('MODULE_PATHNAME', '$libdir/pgtap') + .replaceAll('__OS__', osName) + .replaceAll('__VERSION__', numeric); + const recipe = + /^sql\/uninstall_pgtap\.sql: sql\/pgtap\.sql test\/setup\.sql\n\t\$\(PERL\) -e '([^\n]+)' \$< > \$@\n/m.exec( + readText(path.join(source, 'Makefile')), + )?.[1]; + if (!recipe) throw new Error('pinned pgTAP Makefile has no uninstall recipe'); + const expected = new Map([ + ['pgtap.control', readFileSync(control)], + [`pgtap--${version}.sql`, Buffer.from(main)], + ]); + // Use the pinned upstream Perl scripts directly; do not import the generator. + const runPerl = (arguments_: string[], input: string): Buffer => { + const result = spawnSync(perl, [...perlOptions, ...arguments_], { + input: Buffer.from(input), + env: environment, + stdio: ['pipe', 'pipe', 'inherit'], + maxBuffer: 16 * 1024 * 1024, + }); + if (result.error) throw result.error; + if (result.status !== 0) { + throw new Error(`upstream pgTAP Perl failed: ${result.signal ?? result.status}`); + } + return result.stdout; + }; + for (const [kind, invert] of [ + ['core', '0'], + ['schema', '1'], + ]) { + expected.set( + `pgtap-${kind}--${version}.sql`, + runPerl([path.join(source, 'compat/gencore'), invert], staticSql), + ); + } + expected.set('uninstall_pgtap.sql', runPerl(['-e', recipe.replaceAll('$$', '$')], main)); + for (const file of readdirSync(path.join(source, 'sql'))) { + if (file.startsWith('pgtap--') && (file.endsWith('.sql') || file.endsWith('.sql.in'))) { + const name = file.endsWith('.in') ? file.slice(0, -3) : file; + expected.set(name, readFileSync(path.join(source, 'sql', file))); + } + } + const actual = new Map( + readdirSync(installed).map((name) => [name, readFileSync(path.join(installed, name))]), + ); + if (actual.size !== expected.size || [...expected.keys()].some((name) => !actual.has(name))) { + throw new Error('installed resource set differs from pinned upstream'); + } + for (const [name, data] of expected) { + if (!actual.get(name)?.equals(data)) { + throw new Error(`installed resource differs from upstream bytes: ${name}`); + } + } + console.log(`Upstream-byte parity: ${expected.size} installed resources for ${osName}`); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + const { values } = parseArgs({ + args: Bun.argv.slice(2), + options: { + control: { type: 'string' }, + installed: { type: 'string' }, + perl: { type: 'string' }, + patch: { type: 'string' }, + os: { type: 'string', default: 'linux' }, + 'perl-options': { type: 'string' }, + }, + allowPositionals: false, + }); + const { control, installed, perl, patch } = values; + if ( + control === undefined || + installed === undefined || + perl === undefined || + patch === undefined + ) { + throw new Error( + 'usage: pgtap_upstream_parity_test.mts --control PATH --installed DIR --perl PATH --patch PATH [--os linux|darwin|MSWin32]', + ); + } + const options = values['perl-options'] ? JSON.parse(readText(values['perl-options'])) : []; + if (!Array.isArray(options) || !options.every((value) => typeof value === 'string')) + throw new Error('execution Perl options must be a string array'); + compare(control, installed, perl, patch, options, values.os); +} diff --git a/build_defs/extensions/platforms.bzl b/build_defs/extensions/platforms.bzl new file mode 100644 index 000000000..c90d07f24 --- /dev/null +++ b/build_defs/extensions/platforms.bzl @@ -0,0 +1,21 @@ +"""Actual extension construction profiles, separate from runtime availability.""" + +# Construction support is distinct from the installed Linux lifecycle recipe. +# PostGIS's dependency configuration and mobile's static registry are separate +# recipes; neither inherits support from a desktop runtime target. +_LINUX_PROFILES = { + "//build_defs/native:linux_x86_64": "linux-x64-gnu", + "//build_defs/native:linux_aarch64_gnu_2_28": "linux-arm64-gnu", +} +NATIVE_EXTENSION_PROFILES = _LINUX_PROFILES | { + "//build_defs/native:macos_arm64": "macos-arm64", + "//build_defs/native:windows_x64": "windows-x64-msvc", +} + +NATIVE_EXTENSION_CONFIGURATION = select(NATIVE_EXTENSION_PROFILES, no_match_error = "No extension construction profile for this native platform.") +NATIVE_EXTENSION_COMPATIBLE = select({condition: [] for condition in NATIVE_EXTENSION_PROFILES} | { + "//conditions:default": ["@platforms//:incompatible"], +}) +NATIVE_EXTENSION_LINUX_COMPATIBLE = select({condition: [] for condition in _LINUX_PROFILES} | { + "//conditions:default": ["@platforms//:incompatible"], +}) diff --git a/build_defs/extensions/postgis/BUILD.bazel b/build_defs/extensions/postgis/BUILD.bazel new file mode 100644 index 000000000..ccecf0ab7 --- /dev/null +++ b/build_defs/extensions/postgis/BUILD.bazel @@ -0,0 +1,45 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("@bazel_lib//lib:copy_file.bzl", "copy_file") +load("//build_defs/foundation:bun.bzl", "bun_binary", "bun_script_test", "bun_test") +load(":compiler_facts.bzl", "postgis_compiler_facts") +load(":sqlite.bzl", "postgis_sqlite") +load(":libraries.bzl", "postgis_geos", "postgis_iconv", "postgis_json_c", "postgis_libxml2", "postgis_proj") +load(":proj_db.bzl", "proj_database") +load(":modules.bzl", "postgis_dependency_module", "postgis_standalone") +load(":sql.bzl", "postgis_sql") + +package(default_visibility = ["//visibility:public"]) + +exports_files(glob(["*.bzl", "*.mts"])) +bun_binary(name = "sqlite_generate", entry_point = "sqlite_generate.mts") +bun_binary(name = "configure_headers", entry_point = "configure_headers.mts") +copy_file(name = "libiconv_config_template", src = "@postgis_libiconv//:lib/config.h.in", out = "libiconv_templates/lib/config.h.in") +copy_file(name = "libiconv_iconv_template", src = "@postgis_libiconv//:include/iconv.h.build.in", out = "libiconv_templates/include/iconv.h.build.in") +copy_file(name = "libiconv_localcharset_template", src = "@postgis_libiconv//:libcharset/include/localcharset.h.build.in", out = "libiconv_templates/libcharset/include/localcharset.h.build.in") +copy_file(name = "libiconv_libcharset_template", src = "@postgis_libiconv//:libcharset/include/libcharset.h.build.in", out = "libiconv_templates/libcharset/include/libcharset.h.build.in") +bun_test(name = "configure_headers_test", entry_point = "configure_headers.test.mts", data = ["configure_headers.mts", ":libiconv_config_template", ":libiconv_iconv_template", ":libiconv_localcharset_template", ":libiconv_libcharset_template"], size = "small") +bun_script_test( + name = "gpp_test", + entry_point = "gpp.test.mts", + args = ["$(location @postgis_gpp//:gpp)"], + data = ["@postgis_gpp//:gpp"], + size = "small", +) +bun_binary(name = "proj_db", entry_point = "proj_db.mts") +bun_binary(name = "sql", entry_point = "sql.mts") +postgis_compiler_facts() +postgis_sqlite(name = "sqlite") +postgis_geos(name = "geos") +postgis_json_c(name = "json_c") +postgis_proj(name = "proj", sqlite = ":sqlite") +postgis_iconv(name = "iconv") +postgis_libxml2(name = "libxml2", iconv = ":iconv") +proj_database(name = "database") +postgis_standalone(name = "postgis") +postgis_dependency_module(name = "dependency_module") +postgis_sql(name = "sql_resources", configuration = ":postgis_config", headers = ":postgis_headers") +filegroup(name = "extension_sql", srcs = [":sql_resources"], output_group = "extension_sql") +filegroup(name = "data_sql", srcs = [":sql_resources"], output_group = "data_sql") +filegroup(name = "control", srcs = [":postgis_config"], output_group = "control") + +source_quality_files() diff --git a/build_defs/extensions/postgis/compiler_facts.bzl b/build_defs/extensions/postgis/compiler_facts.bzl new file mode 100644 index 000000000..7657fb5bc --- /dev/null +++ b/build_defs/extensions/postgis/compiler_facts.bzl @@ -0,0 +1,181 @@ +"""PostGIS dependency facts from the selected NDK, Apple, or MSVC compiler. + +The qualified Linux templates do not depend on these targets. The maintained +checker compiles and links against the target SDK without running target code. +Unavailable features remain undefined, as required by upstream #ifdef checks. +""" + +load("@bazel_skylib//rules:write_file.bzl", "write_file") +load("@rules_cc_autoconf//autoconf:autoconf.bzl", "autoconf") +load("@rules_cc_autoconf//autoconf:autoconf_hdr.bzl", "autoconf_hdr") +load("@rules_cc_autoconf//autoconf:checks.bzl", "checks", "macros", "utils") + +POSTGIS_COMPILER_FACTS = select({ + "//build_defs/native:macos_arm64": ":macos_compiler_facts_header", + "//build_defs/native:windows_x64": ":windows_compiler_facts_header", + "//conditions:default": None, +}) + +_MOBILE_TARGETS = { + "android_arm64": ("//build_defs/native:android_arm64", "android-arm64-v8a"), + "android_x86_64": ("//build_defs/native:android_x86_64", "android-x86_64"), + "ios_device": ("//build_defs/native:ios_arm64", "ios-device"), + "ios_simulator": ("//build_defs/native:ios_arm64_simulator", "ios-simulator"), + "macos": ("//build_defs/native:macos_arm64", "macos-arm64"), +} +POSTGIS_MOBILE_COMPILER_FACTS = select({setting: ":mobile_" + prefix + "_compiler_facts_header" for prefix, (setting, _) in _MOBILE_TARGETS.items()}, no_match_error = "PostGIS static configuration requires a declared mobile slice.") + +def _mobile_guard(target): + if target.startswith("android-"): + architecture = "__aarch64__" if target == "android-arm64-v8a" else "__x86_64__" + return "#include \n", "!defined(__ANDROID__) || !defined(__BIONIC__) || !defined(__ANDROID_API__) || __ANDROID_API__ != 24 || !defined(" + architecture + ")" + platform = "!TARGET_OS_OSX || TARGET_OS_IPHONE" if target == "macos-arm64" else "!TARGET_OS_IOS || " + ("!TARGET_OS_SIMULATOR" if target == "ios-simulator" else "TARGET_OS_SIMULATOR") + return "#include \n", "!defined(__APPLE__) || !defined(__MACH__) || !defined(__aarch64__) || " + platform + +def _target_fact(target): + return "HAVE_POSTGIS_TARGET_" + target.upper().replace("-", "_") + +_HEADERS = [ + "dlfcn.h", "endian.h", "fcntl.h", "inttypes.h", "limits.h", "locale.h", + "memory.h", "poll.h", "pthread.h", "stdarg.h", "stddef.h", "stdint.h", + "stdio.h", "stdlib.h", "strings.h", "string.h", "syslog.h", "sys/cdefs.h", + "sys/param.h", "sys/random.h", "sys/resource.h", "sys/stat.h", "sys/types.h", + "unistd.h", "wchar.h", "xlocale.h", "bsd/stdlib.h", +] + +_FUNCTIONS = [ + "arc4random", "fseeko", "getc_unlocked", "getrandom", "getrusage", + "localeconv", "mbrtowc", "open", "realloc", "setlocale", "snprintf", + "strcasecmp", "strdup", "strerror", "strncasecmp", "strtoll", "strtoull", + "uselocale", "vasprintf", "vprintf", "vsnprintf", "vsyslog", "wcrtomb", + "_strtoi64", "_strtoui64", +] + +_COMPILE_FEATURES = { + # Expressions used by the pinned json-c and libxml2 configurations. + "HAVE_FUNC_ATTRIBUTE_DESTRUCTOR": "void __attribute__((destructor)) f(void) {} int main(void) { return 0; }", + "HAVE_VISIBILITY": "__attribute__((visibility(\"hidden\"))) int f(void) { return 0; }", + "HAVE___THREAD": "__thread int v; int main(void) { return v; }", + "HAVE_DECLSPEC_THREAD": "__declspec(thread) int v; int main(void) { return v; }", + "HAVE_C_THREAD_LOCAL": "_Thread_local int v; int main(void) { return v; }", + "HAVE_INLINE": "static inline int f(void) { return 0; } int main(void) { return f(); }", + "HAVE___INLINE": "static __inline int f(void) { return 0; } int main(void) { return f(); }", + "STDC_HEADERS": "#include \n#include \n#include \n#include \nint main(void) { return 0; }", + "WORDS_LITTLEENDIAN": "#if !defined(_WIN32) && (!defined(__BYTE_ORDER__) || __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__)\n#error not little endian\n#endif\nint main(void) { return 0; }", +} + +def _compiler_checks(windows, mobile_target = None): + probes = macros.AC_CHECK_HEADERS(_HEADERS) + macros.AC_CHECK_FUNCS(_FUNCTIONS) + probes += [ + checks.AC_CHECK_DECL(symbol, includes = ["#include "], define = "HAVE_DECL_" + symbol.upper()) + for symbol in ["INFINITY", "isinf", "isnan", "nan", "_finite", "_isnan"] + ] + probes += [ + # Use libxml2's exact header requirements, including the headers that + # dict.c includes whenever HAVE_DECL_GETENTROPY is enabled. + checks.AC_CHECK_DECL("getentropy", includes = ["#include ", "#include "], define = "HAVE_DECL_GETENTROPY"), + checks.AC_CHECK_DECL("glob", includes = ["#include "], define = "HAVE_DECL_GLOB"), + checks.AC_CHECK_DECL("mmap", includes = ["#include "], define = "HAVE_DECL_MMAP"), + checks.AC_CHECK_TYPE("mbstate_t", includes = ["#include "], define = "HAVE_MBSTATE_T"), + checks.AC_CHECK_TYPE("mode_t", includes = ["#include "], define = "HAVE_MODE_T"), + checks.AC_CHECK_TYPE("ssize_t", includes = ["#include "], define = "HAVE_SSIZE_T"), + checks.AC_COMPUTE_INT("EILSEQ", "EILSEQ", includes = ["#include "]), + # json-c's check_c_source_compiles links the atomic operation. + checks.AC_TRY_LINK( + code = "int main(void) { int x = 0; return __sync_add_and_fetch(&x, 1); }", + define = "HAVE_ATOMIC_BUILTINS", + if_false = None, + ), + checks.AC_TRY_LINK( + code = utils.AC_LANG_PROGRAM(["#include "], "return nl_langinfo(CODESET) == 0;"), + define = "HAVE_LANGINFO_CODESET", + if_false = None, + ), + checks.AC_TRY_LINK( + code = utils.AC_LANG_PROGRAM(["#include "], "return dlopen(0, RTLD_NOW) == 0;"), + define = "HAVE_DLOPEN", + if_false = None, + ), + checks.AC_CHECK_LIB("dl", "dlopen", define = "HAVE_LIBDL", if_false = None), + checks.AC_DEFINE("JSON_C_HAVE_INTTYPES_H", condition = "ac_cv_header_inttypes_h", if_true = 1, if_false = None), + checks.AC_DEFINE("JSON_C_HAVE_STDINT_H", condition = "ac_cv_header_stdint_h", if_true = 1, if_false = None), + ] + probes += [ + checks.AC_CHECK_SIZEOF(t, includes = ["#include ", "#include "], define = d) + for t, d in [ + ("int", "SIZEOF_INT"), ("int64_t", "SIZEOF_INT64_T"), + ("long", "SIZEOF_LONG"), ("long long", "SIZEOF_LONG_LONG"), + ("size_t", "SIZEOF_SIZE_T"), ("void *", "SIZEOF_VOID_P"), + ] + ] + # json-c's upstream MSVC configuration measures SSIZE_T from BaseTsd.h. + probes.append(checks.AC_CHECK_SIZEOF( + "SSIZE_T" if windows else "ssize_t", + includes = ["#include " if windows else "#include "], + define = "SIZEOF_SSIZE_T", + )) + probes += [checks.AC_TRY_COMPILE(code = code, define = define) for define, code in _COMPILE_FEATURES.items()] + target_guard = "!defined(_WIN32) || !defined(_M_X64) || !defined(_MSC_VER)" if windows else "!defined(__APPLE__) || !defined(__MACH__) || !defined(__aarch64__)" + preamble = "" + if mobile_target: + preamble, target_guard = _mobile_guard(mobile_target) + sanity = preamble + "#if " + target_guard + "\n#error incorrect PostGIS compiler target\n#endif\n#include \n#include \nint main(void) { void *p = malloc(8); printf(\"%p\\n\", p); free(p); return 0; }" + probes.append(checks.AC_TRY_LINK( + code = sanity, + define = "HAVE_POSTGIS_COMPILER_SANITY", + if_false = None, + )) + if mobile_target: + # The sanity program already proves the exact SDK/architecture guard. + # Identical probes share one result in the maintained checker; derive + # the additional target marker from that actual result explicitly. + probes.append(checks.AC_DEFINE(_target_fact(mobile_target), condition = "ac_cv_try_link_HAVE_POSTGIS_COMPILER_SANITY", if_true = 1, if_false = None)) + # Match production's MSVC C mode and feature visibility. Values are integers + # so the checker's generated preamble never defines a C string literal. + definitions = ["_CRT_SECURE_NO_WARNINGS", "_CRT_NONSTDC_NO_WARNINGS", "_USE_MATH_DEFINES"] if windows else ["_GNU_SOURCE"] + configured = [] + for probe in probes: + check = json.decode(probe) | {"copts": ["/std:c11"] if windows else [], "compile_defines": definitions} + # AC_CHECK_DECL defaults to a defined zero on failure. Our fact header + # uses the same undefined convention as all other optional probes. + if check["type"] == "decl": + check["define_value_fail"] = None + configured.append(json.encode(check)) + return [checks.AC_DEFINE(define, 1) for define in definitions] + configured + +def postgis_compiler_facts(): + """Declare only foreign-profile probes and their required result headers.""" + for prefix, windows, setting in [ + ("macos", False, "//build_defs/native:macos_arm64"), + ("windows", True, "//build_defs/native:windows_x64"), + ]: + name = prefix + "_compiler_facts" + compatible = select({setting: [], "//conditions:default": ["@platforms//:incompatible"]}) + probes = _compiler_checks(windows) + autoconf(name = name, checks = probes, target_compatible_with = compatible) + write_file( + name = name + "_template", + out = name + ".h.in", + content = ["#undef " + json.decode(probe)["define"] for probe in probes] + [""], + target_compatible_with = compatible, + ) + autoconf_hdr( + name = name + "_header", + out = name + ".h", + template = ":" + name + "_template", + deps = [":" + name], + defaults = False, + target_compatible_with = compatible, + ) + +def postgis_mobile_compiler_facts(): + """Compile and link facts against each actual NDK or licensed Apple SDK.""" + for prefix, (setting, target) in _MOBILE_TARGETS.items(): + name = "mobile_" + prefix + "_compiler_facts" + compatible = select({setting: [], "//conditions:default": ["@platforms//:incompatible"]}) + probes = _compiler_checks(False, mobile_target = target) + autoconf(name = name, checks = probes, target_compatible_with = compatible) + write_file(name = name + "_template", out = name + ".h.in", + content = ["#undef " + json.decode(probe)["define"] for probe in probes] + [""], target_compatible_with = compatible) + autoconf_hdr(name = name + "_header", out = name + ".h", template = ":" + name + "_template", + deps = [":" + name], defaults = False, target_compatible_with = compatible) diff --git a/build_defs/extensions/postgis/configure_headers.mts b/build_defs/extensions/postgis/configure_headers.mts new file mode 100644 index 000000000..f5d38528b --- /dev/null +++ b/build_defs/extensions/postgis/configure_headers.mts @@ -0,0 +1,369 @@ +/** Canonical upstream templates, with declared compiler facts for foreign hosts. */ +import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import { dirname, join, resolve } from 'node:path'; +import { parseArgs } from 'node:util'; + +type Values = Record; +const targets = new Set(['linux-x64-gnu', 'linux-arm64-gnu', 'macos-arm64', 'windows-x64-msvc']); +const mobileTargets = new Set([ + 'android-arm64-v8a', + 'android-x86_64', + 'ios-device', + 'ios-simulator', + 'macos-arm64', +]); +const utf8 = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }); +function read(path: string): string { + return utf8.decode(readFileSync(path)); +} + +export function configure(template: string, values: Values): string { + let configured = template.replace(/^#undef (\w+)$/gmu, (line, key: string) => + values[key] === undefined ? line : `#define ${key} ${values[key]}`, + ); + configured = configured.replace( + /^#cmakedefine(01)?\s+(\w+)([^\n]*)$/gmu, + (_line, numeric: string | undefined, key: string, tail: string) => { + const enabled = values[key] !== undefined && !['0', '', 'OFF', 'FALSE'].includes(values[key]); + if (numeric) return `#define ${key} ${enabled ? '1' : '0'}`; + return enabled ? `#define ${key}${tail}` : `/* #undef ${key} */`; + }, + ); + configured = configured.replace( + /@([A-Za-z_][A-Za-z_0-9]*)@|\$\{([A-Za-z_][A-Za-z_0-9]*)\}/gu, + (_token, at: string | undefined, dollar: string | undefined) => { + const key = at ?? dollar ?? ''; + if (values[key] === undefined) throw new Error(`unconfigured upstream template key ${key}`); + return values[key]; + }, + ); + if (configured.includes('@@')) throw new Error('unconfigured anonymous upstream template token'); + return configured; +} + +function enabled(names: string): Values { + return Object.fromEntries( + names + .split(' ') + .filter(Boolean) + .map((key) => [key, '1']), + ); +} + +/** Only the maintained checker's explicit defines become template substitutions. */ +export function compilerFacts(header: string): Values { + const result: Values = {}; + for (const line of header.split(/\r?\n/u)) { + const match = /^#define ([A-Z][A-Z_0-9]*) (.+)$/u.exec(line); + if (!match) continue; + if (Object.hasOwn(result, match[1])) throw new Error(`duplicate compiler fact ${match[1]}`); + result[match[1]] = match[2]; + } + return result; +} + +export function targetSubstitutions( + original: Values, + target: string, + facts?: Values, + profile = 'desktop', +): Values { + if (profile !== 'desktop' && profile !== 'mobile-static') + throw new Error(`unsupported PostGIS profile ${profile}`); + const mobile = profile === 'mobile-static'; + if (!(mobile ? mobileTargets : targets).has(target)) + throw new Error(`unsupported PostGIS configuration target ${target}`); + if (!mobile && target.startsWith('linux-')) { + if (facts) throw new Error('the qualified Linux profile does not consume foreign facts'); + return original; + } + if ( + !facts || + facts.HAVE_POSTGIS_COMPILER_SANITY !== '1' || + !facts.SIZEOF_LONG || + !facts.SIZEOF_SIZE_T || + !facts.SIZEOF_VOID_P + ) + throw new Error('foreign PostGIS configuration requires declared compiler facts'); + const expectedLong = target === 'windows-x64-msvc' ? '4' : '8'; + if ( + facts.SIZEOF_LONG !== expectedLong || + facts.SIZEOF_SIZE_T !== '8' || + facts.SIZEOF_VOID_P !== '8' + ) + throw new Error(`compiler facts disagree with ${target} ABI`); + if (mobile && facts[`HAVE_POSTGIS_TARGET_${target.toUpperCase().replaceAll('-', '_')}`] !== '1') + throw new Error(`compiler facts do not prove the ${target} static target`); + const result = { ...original }; + for (const key of Object.keys(result)) { + if (key.startsWith('HAVE_') || key.startsWith('SIZEOF_')) delete result[key]; + } + Object.assign(result, facts); + if (Object.hasOwn(original, 'JSON_C_HAVE_INTTYPES_H')) + result.JSON_C_HAVE_INTTYPES_H = facts.HAVE_INTTYPES_H ?? '0'; + if (Object.hasOwn(original, 'JSON_C_HAVE_STDINT_H')) + result.JSON_C_HAVE_STDINT_H = facts.HAVE_STDINT_H ?? '0'; + // These facts describe the declared dependency graph, rather than libc probes. + for (const key of Object.keys(original)) { + if ( + /^HAVE_(?:ICONV(?:CTL)?|LIB(?:GEOS_C|ICONVCTL|JSON|PROJ|XML2|XML_(?:PARSER|TREE|XPATHINTERNALS|XPATH)_H))$/u.test( + key, + ) + ) + result[key] = original[key]; + } + if (Object.hasOwn(result, 'SPEC___THREAD')) { + result.SPEC___THREAD = facts.HAVE___THREAD ? '__thread' : '__declspec(thread)'; + if (!facts.HAVE___THREAD && !facts.HAVE_DECLSPEC_THREAD) delete result.SPEC___THREAD; + } + if (Object.hasOwn(result, 'EILSEQ')) { + if (!facts.EILSEQ) throw new Error('libiconv requires compiler-derived EILSEQ'); + result.EILSEQ = facts.EILSEQ; + result.HAVE_VISIBILITY = facts.HAVE_VISIBILITY ?? '0'; + result.USE_MBSTATE_T = facts.HAVE_MBSTATE_T ? '1' : '0'; + if (!facts.HAVE_INLINE) { + if (!facts.HAVE___INLINE) throw new Error('libiconv requires a supported inline spelling'); + result.inline = '__inline'; + } + if (!facts.HAVE_MODE_T) result.mode_t = 'int'; + // srcm4/ssize_t.m4 uses long long for the selected _WIN64 profile. + if (!facts.HAVE_SSIZE_T) result.ssize_t = 'long long'; + } + if (Object.hasOwn(result, 'MODULE_EXTENSION')) + result.MODULE_EXTENSION = + target === 'windows-x64-msvc' ? '.dll' : target.startsWith('android-') ? '.so' : '.dylib'; + if (mobile) { + for (const key of ['WITH_ICONV', 'WITH_THREADS', 'WITH_MODULES']) { + if (Object.hasOwn(result, key)) result[key] = '0'; + } + // PROJ resolves only its declared embedded resources in this profile. + delete result.HAVE_LIBDL; + if (!target.startsWith('android-')) { + for (const key of ['HAVE_ICONV', 'HAVE_ICONVCTL', 'HAVE_LIBICONVCTL']) delete result[key]; + } + } + return result; +} + +if (import.meta.main) { + const { values } = parseArgs({ + options: { + kind: { type: 'string' }, + source: { type: 'string' }, + output: { type: 'string' }, + identity: { type: 'string' }, + target: { type: 'string', default: 'linux-x64-gnu' }, + facts: { type: 'string' }, + profile: { type: 'string', default: 'desktop' }, + }, + }); + if (!values.kind || !values.source || !values.output) + throw new Error('expected --kind --source --output'); + const source = resolve(values.source); + const output = resolve(values.output); + const facts = values.facts ? compilerFacts(read(values.facts)) : undefined; + const emit = (input: string, path: string, substitutions: Values): void => { + const destination = join(output, path); + mkdirSync(dirname(destination), { recursive: true }); + writeFileSync( + destination, + configure( + read(join(source, input)), + targetSubstitutions(substitutions, values.target, facts, values.profile), + ), + ); + }; + if (values.kind === 'geos') { + const version = Object.fromEntries( + [...read(join(source, 'Version.txt')).matchAll(/^(\w+)=(.*)$/gmu)].map((match) => [ + match[1], + match[2], + ]), + ); + const major = version.GEOS_VERSION_MAJOR; + const minor = version.GEOS_VERSION_MINOR; + const patch = version.GEOS_VERSION_PATCH; + const apiMajor = Number(version.CAPI_INTERFACE_CURRENT) - Number(version.CAPI_INTERFACE_AGE); + if (!major || !minor || !patch || !Number.isInteger(apiMajor)) + throw new Error('invalid GEOS upstream Version.txt'); + const substitutions = { + VERSION_MAJOR: major, + VERSION_MINOR: minor, + VERSION_PATCH: patch, + VERSION: `${major}.${minor}.${patch}${version.GEOS_PATCH_WORD ?? ''}`, + JTS_PORT: version.JTS_PORT, + CAPI_VERSION_MAJOR: String(apiMajor), + CAPI_VERSION_MINOR: version.CAPI_INTERFACE_AGE, + CAPI_VERSION_PATCH: version.CAPI_INTERFACE_REVISION, + CAPI_VERSION: `${apiMajor}.${version.CAPI_INTERFACE_AGE}.${version.CAPI_INTERFACE_REVISION}`, + }; + emit('include/geos/version.h.in', 'geos/version.h', substitutions); + emit('capi/geos_c.h.in', 'geos_c.h', substitutions); + } else if (values.kind === 'json_c') { + const cmake = read(join(source, 'CMakeLists.txt')); + const version = /project\(json-c LANGUAGES C VERSION ([0-9]+)\.([0-9]+)\)/u.exec(cmake); + if (!version) throw new Error('review json-c upstream version syntax'); + const substitutions = { + ...enabled( + 'HAVE_DLFCN_H HAVE_ENDIAN_H HAVE_FCNTL_H HAVE_INTTYPES_H HAVE_LIMITS_H HAVE_LOCALE_H HAVE_MEMORY_H HAVE_STDARG_H HAVE_STDINT_H HAVE_STDLIB_H HAVE_STRINGS_H HAVE_STRING_H HAVE_SYSLOG_H HAVE_SYS_CDEFS_H HAVE_SYS_PARAM_H HAVE_SYS_RANDOM_H HAVE_SYS_RESOURCE_H HAVE_SYS_STAT_H HAVE_SYS_TYPES_H HAVE_UNISTD_H HAVE_ATOMIC_BUILTINS HAVE_DECL_INFINITY HAVE_DECL_ISINF HAVE_DECL_ISNAN HAVE_DECL_NAN HAVE_OPEN HAVE_REALLOC HAVE_SETLOCALE HAVE_SNPRINTF HAVE_STRCASECMP HAVE_STRDUP HAVE_STRERROR HAVE_STRNCASECMP HAVE_USELOCALE HAVE_VASPRINTF HAVE_VPRINTF HAVE_VSNPRINTF HAVE_VSYSLOG HAVE_GETRANDOM HAVE_GETRUSAGE HAVE_STRTOLL HAVE_STRTOULL HAVE___THREAD JSON_C_HAVE_INTTYPES_H JSON_C_HAVE_STDINT_H STDC_HEADERS', + ), + PROJECT_NAME: 'json-c', + JSON_C_BUGREPORT: 'json-c@googlegroups.com', + CPACK_PACKAGE_VERSION_MAJOR: version[1], + CPACK_PACKAGE_VERSION_MINOR: version[2], + CPACK_PACKAGE_VERSION_PATCH: '0', + SIZEOF_INT: '4', + SIZEOF_INT64_T: '8', + SIZEOF_LONG: '8', + SIZEOF_LONG_LONG: '8', + SIZEOF_SIZE_T: '8', + SIZEOF_SSIZE_T: '8', + SPEC___THREAD: '__thread', + json_c_strtoll: 'strtoll', + json_c_strtoull: 'strtoull', + JSON_H_JSON_POINTER: '#include "json_pointer.h"', + JSON_H_JSON_PATCH: '#include "json_patch.h"', + }; + emit('cmake/config.h.in', 'config.h', substitutions); + emit('cmake/json_config.h.in', 'json_config.h', substitutions); + emit('json.h.cmakein', 'json.h', substitutions); + } else if (values.kind === 'libxml2') { + const version = read(join(source, 'VERSION')).trim(); + const parts = version.split('.').map(Number); + if (parts.length !== 3 || parts.some((part) => !Number.isInteger(part))) + throw new Error('invalid libxml2 VERSION'); + const substitutions = { + ...enabled( + 'HAVE_DECL_GETENTROPY HAVE_DECL_GLOB HAVE_DECL_MMAP HAVE_FUNC_ATTRIBUTE_DESTRUCTOR HAVE_DLOPEN HAVE_POLL_H HAVE_STDINT_H WITH_C14N WITH_CATALOG WITH_DEBUG WITH_HTML WITH_ICONV WITH_ISO8859X WITH_MODULES WITH_OUTPUT WITH_PATTERN WITH_PUSH WITH_READER WITH_REGEXPS WITH_RELAXNG WITH_SAX1 WITH_SCHEMAS WITH_SCHEMATRON WITH_THREADS WITH_VALID WITH_WRITER WITH_XINCLUDE WITH_XPATH WITH_XPTR', + ), + VERSION: version, + LIBXML_VERSION_NUMBER: String(parts[0] * 10000 + parts[1] * 100 + parts[2]), + LIBXML_VERSION_EXTRA: '', + MODULE_EXTENSION: '.so', + XML_SYSCONFDIR: '/oliphaunt/runtime/etc', + WITH_HTTP: '0', + WITH_ICU: '0', + WITH_LZMA: '0', + WITH_THREAD_ALLOC: '0', + WITH_ZLIB: '0', + }; + emit('config.h.cmake.in', 'config.h', substitutions); + emit('include/libxml/xmlversion.h.in', 'libxml/xmlversion.h', substitutions); + } else if (values.kind === 'proj') { + emit( + 'cmake/proj_config.cmake.in', + 'proj_config.h', + enabled('HAVE_LIBDL HAVE_LOCALECONV HAVE_STRERROR'), + ); + } else if (values.kind === 'libiconv') { + const substitutions = { + ...enabled( + 'HAVE_GETC_UNLOCKED HAVE_LANGINFO_CODESET HAVE_MBRTOWC HAVE_SETLOCALE HAVE_STDDEF_H HAVE_STDLIB_H HAVE_STRING_H HAVE_VISIBILITY HAVE_WCRTOMB HAVE_WORKING_O_NOFOLLOW WORDS_LITTLEENDIAN HAVE_STDIO_H HAVE_STRINGS_H HAVE_SYS_STAT_H HAVE_SYS_TYPES_H HAVE_UNISTD_H HAVE_INTTYPES_H HAVE_STDINT_H', + ), + DLL_VARIABLE: '', + ICONV_CONST: '', + EILSEQ: '84', + USE_MBSTATE_T: '1', + BROKEN_WCHAR_H: '0', + INSTALLPREFIX: '"/oliphaunt/runtime"', + prefix: '/oliphaunt/runtime', + }; + emit('lib/config.h.in', 'config.h', substitutions); + emit('include/iconv.h.build.in', 'iconv.h', substitutions); + emit('libcharset/include/localcharset.h.build.in', 'localcharset.h', substitutions); + emit('libcharset/include/libcharset.h.build.in', 'libcharset.h', substitutions); + } else if (values.kind === 'postgis') { + if (!values.identity) throw new Error('PostGIS configuration requires declared --identity'); + const identity = JSON.parse(read(values.identity)) as { + commit: string; + source_date_epoch: number; + default_version: string; + postgres_major: number; + postgres_version: string; + dependencies: Record; + }; + const version = Object.fromEntries( + [...read(join(source, 'Version.config')).matchAll(/^(\w+)=(.*)$/gmu)].map((match) => [ + match[1], + match[2], + ]), + ); + const major = version.POSTGIS_MAJOR_VERSION; + const minor = version.POSTGIS_MINOR_VERSION; + const micro = version.POSTGIS_MICRO_VERSION; + const fullVersion = `${major}.${minor}.${micro}`; + if ( + fullVersion !== identity.default_version || + identity.postgres_major !== 18 || + !/^[0-9a-f]{40}$/u.test(identity.commit) + ) { + throw new Error('PostGIS source/configuration disagrees with canonical identity'); + } + const dependencyVersion = (name: string): string => { + const value = identity.dependencies[name].branch.replace(/^v/u, ''); + if (!/^\d+\.\d+\.\d+$/u.test(value)) throw new Error(`invalid pinned ${name} version`); + return value; + }; + const number = (value: string): string => + value + .split('.') + .map((part, index) => (index ? part.padStart(2, '0') : part)) + .join(''); + const date = new Date(identity.source_date_epoch * 1000); + if ( + !Number.isSafeInteger(identity.source_date_epoch) || + identity.source_date_epoch <= 0 || + Number.isNaN(date.valueOf()) + ) + throw new Error('invalid canonical PostGIS build epoch'); + const buildDate = date.toISOString().slice(0, 19).replace('T', ' '); + const displayVersion = `${major}.${minor} USE_GEOS=1 USE_PROJ=1 USE_STATS=1`; + const substitutions = { + ...enabled( + 'HAVE_FSEEKO HAVE_ICONV HAVE_ICONVCTL HAVE_LIBGEOS_C HAVE_LIBICONVCTL HAVE_LIBJSON HAVE_LIBPROJ HAVE_LIBXML2 HAVE_LIBXML_PARSER_H HAVE_LIBXML_TREE_H HAVE_LIBXML_XPATHINTERNALS_H HAVE_LIBXML_XPATH_H HAVE_UNISTD_H STDC_HEADERS YYTEXT_POINTER', + ), + POSTGIS_LIB_VERSION: fullVersion, + POSTGIS_MAJOR_VERSION: major, + POSTGIS_MINOR_VERSION: minor, + POSTGIS_MICRO_VERSION: micro, + POSTGIS_GEOS_VERSION: number(dependencyVersion('geos')), + POSTGIS_PROJ_VERSION: number(dependencyVersion('proj')), + POSTGIS_LIBXML2_VERSION: dependencyVersion('libxml2'), + POSTGIS_SFCGAL_VERSION: '0', + POSTGIS_PGSQL_VERSION: '180', + POSTGIS_PGSQL_HR_VERSION: identity.postgres_version, + POSTGIS_VERSION: displayVersion, + POSTGIS_BUILD_DATE: buildDate, + POSTGIS_SCRIPTS_VERSION: fullVersion, + SRID_MAX: '999999', + SRID_USR_MAX: '998999', + EXTVERSION: fullVersion, + EXTENSION: 'postgis', + MODULEPATH: '$libdir/postgis-3', + }; + const quoted = { + ...substitutions, + POSTGIS_LIB_VERSION: JSON.stringify(fullVersion), + POSTGIS_LIBXML2_VERSION: JSON.stringify(substitutions.POSTGIS_LIBXML2_VERSION), + POSTGIS_VERSION: JSON.stringify(displayVersion), + POSTGIS_BUILD_DATE: JSON.stringify(buildDate), + POSTGIS_SCRIPTS_VERSION: JSON.stringify(fullVersion), + PGSQL_LOCALEDIR: '"/oliphaunt/runtime/share/locale"', + LT_OBJDIR: '".libs/"', + }; + emit('postgis_config.h.in', 'postgis_config.h', quoted); + emit('liblwgeom/liblwgeom.h.in', 'liblwgeom/liblwgeom.h', substitutions); + emit('postgis/sqldefines.h.in', 'postgis/sqldefines.h', substitutions); + emit( + 'extensions/postgis/postgis.control.in', + 'extensions/postgis/postgis.control', + substitutions, + ); + writeFileSync( + join(output, 'postgis_revision.h'), + `#define POSTGIS_REVISION ${identity.commit}\n`, + ); + } else { + throw new Error(`unknown configuration ${values.kind}`); + } +} diff --git a/build_defs/extensions/postgis/configure_headers.test.mts b/build_defs/extensions/postgis/configure_headers.test.mts new file mode 100644 index 000000000..55496cac0 --- /dev/null +++ b/build_defs/extensions/postgis/configure_headers.test.mts @@ -0,0 +1,241 @@ +import { test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { compilerFacts, configure, targetSubstitutions } from './configure_headers.mts'; + +const facts = (target: string) => + compilerFacts( + [ + '#define HAVE_POSTGIS_COMPILER_SANITY 1', + `#define SIZEOF_LONG ${target === 'windows-x64-msvc' ? 4 : 8}`, + '#define SIZEOF_SIZE_T 8', + '#define SIZEOF_VOID_P 8', + '#define EILSEQ 42', + '#define HAVE_STDINT_H 1', + '#define HAVE_INTTYPES_H 1', + '#define HAVE_INLINE 1', + '#define HAVE_MBSTATE_T 1', + '#define HAVE_DECLSPEC_THREAD 1', + '/* #undef HAVE_GETRANDOM */', + '/* #undef HAVE_UNISTD_H */', + ].join('\n'), + ); + +test('foreign substitutions consume explicit facts and retain incorporated dependency policy', () => { + const before = { + HAVE_GETRANDOM: '1', + HAVE_UNISTD_H: '1', + SIZEOF_LONG: '8', + HAVE_ICONV: '1', + HAVE_LIBGEOS_C: '1', + WITH_ICONV: '1', + WITH_THREADS: '1', + MODULE_EXTENSION: '.so', + }; + for (const target of ['macos-arm64', 'windows-x64-msvc']) { + const after = targetSubstitutions(before, target, facts(target)); + assert.equal(after.SIZEOF_LONG, target === 'windows-x64-msvc' ? '4' : '8'); + assert(!Object.hasOwn(after, 'HAVE_GETRANDOM')); + assert(!Object.hasOwn(after, 'HAVE_UNISTD_H')); + assert.equal(after.HAVE_ICONV, '1'); + assert.equal(after.HAVE_LIBGEOS_C, '1'); + assert.equal(after.WITH_ICONV, '1'); + assert.equal(after.WITH_THREADS, '1'); + assert.equal(after.MODULE_EXTENSION, target === 'macos-arm64' ? '.dylib' : '.dll'); + assert(!Object.hasOwn(after, 'XML_THREAD_LOCAL'), 'TLS policy remains disabled'); + assert.equal( + configure( + '#undef HAVE_GETRANDOM\n#cmakedefine01 HAVE_UNISTD_H\n#cmakedefine SIZEOF_LONG @SIZEOF_LONG@\n', + after, + ), + '#undef HAVE_GETRANDOM\n#define HAVE_UNISTD_H 0\n#define SIZEOF_LONG ' + + after.SIZEOF_LONG + + '\n', + ); + } +}); + +test('Linux returns its qualified profile unchanged and rejects foreign fact injection', () => { + const before = { HAVE_GETRANDOM: '1', SIZEOF_LONG: '8' }; + for (const target of ['linux-x64-gnu', 'linux-arm64-gnu']) { + assert.strictEqual(targetSubstitutions(before, target), before); + assert.throws( + () => targetSubstitutions(before, target, facts('macos-arm64')), + /does not consume/u, + ); + } +}); + +test('missing sanity, mismatched ABI, unsupported targets and duplicate facts fail closed', () => { + assert.throws(() => targetSubstitutions({}, 'macos-arm64'), /requires declared/u); + assert.throws( + () => + targetSubstitutions({}, 'macos-arm64', { + ...facts('macos-arm64'), + HAVE_POSTGIS_COMPILER_SANITY: '0', + }), + /requires declared/u, + ); + assert.throws(() => targetSubstitutions({}, 'windows-x64-msvc', facts('macos-arm64')), /ABI/u); + assert.throws( + () => targetSubstitutions({}, 'macos-arm64', { ...facts('macos-arm64'), SIZEOF_SIZE_T: '4' }), + /ABI/u, + ); + assert.throws( + () => targetSubstitutions({}, 'ios-xcframework', facts('macos-arm64')), + /unsupported/u, + ); + assert.throws( + () => compilerFacts('#define SIZEOF_LONG 4\n#define SIZEOF_LONG 8\n'), + /duplicate/u, + ); +}); + +test('libiconv retains upstream type fallbacks and source-bound EILSEQ; JSON type headers use facts', () => { + const original = { + EILSEQ: '84', + USE_MBSTATE_T: '1', + SPEC___THREAD: '__thread', + JSON_C_HAVE_INTTYPES_H: '1', + JSON_C_HAVE_STDINT_H: '1', + }; + const selected = facts('windows-x64-msvc'); + const result = targetSubstitutions(original, 'windows-x64-msvc', selected); + assert.equal(result.EILSEQ, '42'); + assert.equal(result.ssize_t, 'long long'); + assert.equal(result.mode_t, 'int'); + assert.equal(result.USE_MBSTATE_T, '1'); + assert.equal(result.SPEC___THREAD, '__declspec(thread)'); + assert.equal(result.JSON_C_HAVE_STDINT_H, '1'); + assert.throws( + () => targetSubstitutions(original, 'windows-x64-msvc', { ...selected, EILSEQ: '' }), + /EILSEQ/u, + ); +}); + +test('static profiles require the actual target proof and disable mobile XML/runtime features', () => { + const original = { + WITH_ICONV: '1', + WITH_THREADS: '1', + WITH_MODULES: '1', + HAVE_LIBDL: '1', + HAVE_ICONV: '1', + HAVE_ICONVCTL: '1', + HAVE_LIBICONVCTL: '1', + HAVE_LIBGEOS_C: '1', + MODULE_EXTENSION: '.so', + }; + for (const target of [ + 'android-arm64-v8a', + 'android-x86_64', + 'ios-device', + 'ios-simulator', + 'macos-arm64', + ]) { + const proof = `HAVE_POSTGIS_TARGET_${target.toUpperCase().replaceAll('-', '_')}`; + const selected = { ...facts(target), [proof]: '1' }; + const configured = targetSubstitutions(original, target, selected, 'mobile-static'); + assert.equal(configured.WITH_ICONV, '0'); + assert.equal(configured.WITH_THREADS, '0'); + assert.equal(configured.WITH_MODULES, '0'); + assert(!Object.hasOwn(configured, 'HAVE_LIBDL')); + assert.equal(configured.HAVE_LIBGEOS_C, '1'); + assert.equal(configured.HAVE_ICONV, target.startsWith('android-') ? '1' : undefined); + assert.equal(configured.MODULE_EXTENSION, target.startsWith('android-') ? '.so' : '.dylib'); + assert.equal( + configure( + '#cmakedefine01 WITH_THREADS\n#cmakedefine WITH_MODULES\n#undef HAVE_LIBDL\n', + configured, + ), + '#define WITH_THREADS 0\n/* #undef WITH_MODULES */\n#undef HAVE_LIBDL\n', + ); + assert.throws( + () => targetSubstitutions(original, target, facts(target), 'mobile-static'), + /do not prove/u, + ); + assert.throws( + () => targetSubstitutions(original, target, { ...selected, [proof]: '0' }, 'mobile-static'), + /do not prove/u, + ); + } +}); + +test('mobile and desktop configuration selectors cannot substitute one another', () => { + assert.throws( + () => targetSubstitutions({}, 'android-arm64-v8a', facts('macos-arm64')), + /unsupported/u, + ); + assert.throws( + () => targetSubstitutions({}, 'linux-x64-gnu', undefined, 'mobile-static'), + /unsupported/u, + ); + assert.throws( + () => targetSubstitutions({}, 'macos-arm64', facts('macos-arm64'), 'unknown'), + /unsupported PostGIS profile/u, + ); +}); + +test('libiconv configures every pinned template with numeric visibility and preserves strict unknown keys', () => { + const root = mkdtempSync(join(tmpdir(), 'libiconv-template-')); + try { + for (const visibility of [undefined, '0', '1']) { + const expected = visibility ?? '0'; + const selected = { + ...facts('windows-x64-msvc'), + ...(visibility === undefined ? {} : { HAVE_VISIBILITY: visibility }), + }; + const header = join(root, 'facts.h'); + writeFileSync( + header, + Object.entries(selected) + .map(([key, value]) => '#define ' + key + ' ' + value) + .join('\n'), + ); + const output = join(root, visibility ?? 'absent'); + const result = Bun.spawnSync( + [ + process.execPath, + '--no-install', + '--no-env-file', + fileURLToPath(new URL('./configure_headers.mts', import.meta.url)), + '--kind', + 'libiconv', + '--source', + fileURLToPath(new URL('./libiconv_templates/', import.meta.url)), + '--output', + output, + '--target', + 'windows-x64-msvc', + '--facts', + header, + ], + { stdout: 'pipe', stderr: 'pipe' }, + ); + assert.equal(result.exitCode, 0, Buffer.from(result.stderr).toString('utf8').slice(-8000)); + assert.match( + readFileSync(join(output, 'config.h'), 'utf8'), + new RegExp('^#define HAVE_VISIBILITY ' + expected + '$', 'mu'), + ); + for (const name of ['iconv.h', 'localcharset.h', 'libcharset.h']) { + const configured = readFileSync(join(output, name), 'utf8'); + assert.match(configured, new RegExp('^#if ' + expected + ' && BUILDING_LIB', 'mu')); + assert.match(configured, /^#elif defined _MSC_VER && BUILDING_LIB/mu); + } + for (const name of ['config.h', 'iconv.h', 'localcharset.h', 'libcharset.h']) + assert.doesNotMatch( + readFileSync(join(output, name), 'utf8'), + /@[A-Za-z_][A-Za-z_0-9]*@|\$\{[A-Za-z_][A-Za-z_0-9]*\}/u, + ); + } + assert.throws( + () => configure('@UNKNOWN_UPSTREAM_KEY@', {}), + /unconfigured upstream template key UNKNOWN_UPSTREAM_KEY/u, + ); + assert.equal(configure('#undef HAVE_UNAVAILABLE\n', {}), '#undef HAVE_UNAVAILABLE\n'); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/build_defs/extensions/postgis/generators.bzl b/build_defs/extensions/postgis/generators.bzl new file mode 100644 index 000000000..ed2c728f1 --- /dev/null +++ b/build_defs/extensions/postgis/generators.bzl @@ -0,0 +1,46 @@ +"""Upstream PostGIS scanner execution with its fixed outfile option preserved.""" + +load("//build_defs/native:generators.bzl", "PERL_CAPTURE_STDOUT") + +def _flex_stdout_impl(ctx): + flex = ctx.toolchains["@rules_flex//flex:toolchain_type"].flex_toolchain + m4 = ctx.toolchains["@rules_m4//m4:toolchain_type"].m4_toolchain + perl = ctx.toolchains["@rules_perl//perl:exec_toolchain_type"].perl_runtime + if len(ctx.outputs.outs) != 1: + fail("the upstream PostGIS scanner must declare exactly one C output") + environment = dict(flex.flex_env) + environment.update({ + "M4": m4.m4_tool.executable.path, + "M4_SYSCMD_SHELL": ctx.executable._deny_shell.path, + "PERL5LIB": "", + "PERL5OPT": "", + }) + # -t takes precedence over the upstream source's %option outfile. The + # declared interpreter redirects stdout without editing that source or + # invoking an ambient shell, matching the shared PostgreSQL Perl helper. + ctx.actions.run( + executable = perl.interpreter, + arguments = perl.perlopt + [ + "-e", + PERL_CAPTURE_STDOUT, + ctx.outputs.outs[0].path, + flex.flex_tool.executable.path, + ] + ctx.attr.options + ["-t", ctx.file.src.path], + inputs = depset([ctx.file.src], transitive = [flex.all_files, m4.all_files, perl.runtime]), + tools = [flex.flex_tool, m4.m4_tool, ctx.executable._deny_shell], + outputs = ctx.outputs.outs, + env = environment, + mnemonic = "PostgisFlex", + ) + return [DefaultInfo(files = depset(ctx.outputs.outs))] + +postgis_flex = rule( + implementation = _flex_stdout_impl, + attrs = { + "src": attr.label(mandatory = True, allow_single_file = True), + "outs": attr.output_list(mandatory = True), + "options": attr.string_list(), + "_deny_shell": attr.label(default = "@rules_flex//flex/internal:m4_deny_shell", executable = True, cfg = "exec"), + }, + toolchains = ["@rules_flex//flex:toolchain_type", "@rules_m4//m4:toolchain_type", "@rules_perl//perl:exec_toolchain_type"], +) diff --git a/build_defs/extensions/postgis/gpp.test.mts b/build_defs/extensions/postgis/gpp.test.mts new file mode 100644 index 000000000..2ee1a0502 --- /dev/null +++ b/build_defs/extensions/postgis/gpp.test.mts @@ -0,0 +1,41 @@ +/** Exercise the pinned execution tool with PostGIS's upstream SQLPP string mode. */ +import assert from 'node:assert/strict'; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join, resolve } from 'node:path'; + +const [gpp] = process.argv.slice(2); +assert(gpp, 'required: declared GPP executable'); +const normalize = (output: string) => output.replaceAll('\r\n', '\n'); +function run(args: string[]) { + const result = Bun.spawnSync([resolve(gpp), ...args], { + stdin: 'ignore', + stdout: 'pipe', + stderr: 'pipe', + }); + assert.equal(result.exitCode, 0, result.stderr.toString()); + return normalize(result.stdout.toString()); +} + +assert.equal(run(['--version']).split('\n')[0], 'GPP 2.28'); +const expected = "\nSELECT text, 'text';\n"; +// A single CRLF conversion must not hide GPP/CRT double conversion. +const doubledCr = "\r\r\nSELECT text, 'text';\r\r\n"; +assert.equal(normalize(doubledCr), "\r\nSELECT text, 'text';\r\n"); +assert.notEqual(normalize(doubledCr), expected); + +const directory = mkdtempSync(join(tmpdir(), 'oliphaunt-gpp-')); +try { + for (const [name, newline] of [ + ['lf', '\n'], + ['crlf', '\r\n'], + ]) { + const input = join(directory, `${name}.sql.in`); + const output = join(directory, `${name}.sql`); + writeFileSync(input, `#define TYPE text${newline}SELECT TYPE, 'TYPE';${newline}`); + run(['+z', '-C', '-s', "'", '-o', output, input]); + assert.equal(normalize(readFileSync(output, 'utf8')), expected); + } +} finally { + rmSync(directory, { recursive: true, force: true }); +} diff --git a/build_defs/extensions/postgis/gpp_repositories.bzl b/build_defs/extensions/postgis/gpp_repositories.bzl new file mode 100644 index 000000000..1acae4b5e --- /dev/null +++ b/build_defs/extensions/postgis/gpp_repositories.bzl @@ -0,0 +1,38 @@ +"""Pinned source-built GPP execution tool, supported by upstream PostGIS SQLPP.""" + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +_BUILD = """ +load("@bazel_skylib//rules:write_file.bzl", "write_file") +load("@rules_cc//cc:defs.bzl", "cc_binary") +package(default_visibility = ["//visibility:public"]) +exports_files(["configure.ac", "src/Makefile.am", "COPYING", "COPYING.LESSER"]) +write_file( + name = "config", + out = "config.h", + content = ['#define PACKAGE_STRING "GPP 2.28"', ""], +) +cc_binary( + name = "gpp", + srcs = ["src/gpp.c", ":config"], + includes = ["."], + # gpp.c's upstream WIN_NT branch owns CRT aliases and its fnmatch fallback. + defines = ["HAVE_CONFIG_H=1"] + select({ + "@platforms//os:windows": ["WIN_NT"], + "//conditions:default": ["HAVE_FNMATCH_H=1", "HAVE_STRDUP=1", "HAVE_STRCASECMP=1"], + }), + target_compatible_with = select({ + "@platforms//os:linux": [], "@platforms//os:macos": [], "@platforms//os:windows": [], + "//conditions:default": ["@platforms//:incompatible"], + }), +) +""" + +def _impl(_module_ctx): + http_archive(name = "postgis_gpp", + urls = ["https://codeload.github.com/logological/gpp/tar.gz/fc9cc00078999dabd795b782eebc94780cf39a29"], + sha256 = "c172969881f7f76918c18b5406a8bf8ac3aeca6ea859628e4edabe4e8a7fbcd1", + type = "tar.gz", + strip_prefix = "gpp-fc9cc00078999dabd795b782eebc94780cf39a29", build_file_content = _BUILD) + +postgis_gpp = module_extension(implementation = _impl) diff --git a/build_defs/extensions/postgis/libraries.bzl b/build_defs/extensions/postgis/libraries.bzl new file mode 100644 index 000000000..ca3ba0a77 --- /dev/null +++ b/build_defs/extensions/postgis/libraries.bzl @@ -0,0 +1,214 @@ +"""Direct target C/C++ libraries for the pinned PostGIS dependency closure.""" + +load("@oliphaunt_metadata//:metadata.bzl", "EXTENSION_DEPENDENCIES", "EXTENSION_SOURCES", "POSTGRES_SOURCE") +load("@rules_cc//cc:defs.bzl", "cc_library") +load("@rules_cc//cc/common:cc_common.bzl", "cc_common") +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") +load("//build_defs/extensions:platforms.bzl", "NATIVE_EXTENSION_COMPATIBLE", "NATIVE_EXTENSION_CONFIGURATION") +load("//build_defs/extensions:mobile.bzl", "MOBILE_EXTENSION_COMPATIBLE", "MOBILE_EXTENSION_CONFIGURATION") +load("//build_defs/foundation:bun.bzl", "BunScriptInfo", "bun_action") +load("//build_defs/wasix/dependencies:proj_resources.bzl", "wasix_proj_embed") +load(":compiler_facts.bzl", "POSTGIS_COMPILER_FACTS", "POSTGIS_MOBILE_COMPILER_FACTS") + +POSTGIS_NATIVE_COPTS = select({"//build_defs/native:windows_x64": ["/std:c11", "/D_CRT_SECURE_NO_WARNINGS", "/D_CRT_NONSTDC_NO_WARNINGS", "/D_USE_MATH_DEFINES"], "//conditions:default": []}) +POSTGIS_NATIVE_CXX_COPTS = select({"//build_defs/native:windows_x64": ["/std:c++17", "/D_CRT_SECURE_NO_WARNINGS", "/D_USE_MATH_DEFINES"], "//conditions:default": ["-std=c++17"]}) +POSTGIS_MATH_LINKOPTS = select({"//build_defs/native:windows_x64": [], "//build_defs/native:macos_arm64": [], "//conditions:default": ["-lm"]}) +POSTGIS_THREAD_LINKOPTS = select({"//build_defs/native:windows_x64": [], "//build_defs/native:macos_arm64": [], "//conditions:default": ["-lm", "-pthread"]}) +POSTGIS_DL_LINKOPTS = select({"//build_defs/native:windows_x64": [], "//build_defs/native:macos_arm64": [], "//conditions:default": ["-lm", "-pthread", "-ldl"]}) + +def postgis_profile(profile): + if profile == "desktop": + return struct(compatible = NATIVE_EXTENSION_COMPATIBLE, c = POSTGIS_NATIVE_COPTS, cxx = POSTGIS_NATIVE_CXX_COPTS) + if profile == "mobile-static": + return struct(compatible = MOBILE_EXTENSION_COMPATIBLE, c = ["-std=gnu11", "-g0"], cxx = ["-std=c++17", "-g0"]) + fail("unsupported PostGIS construction profile " + profile) + +def _headers_impl(ctx): + outputs = [ctx.actions.declare_file(ctx.label.name + "/" + path) for path in ctx.attr.outs] + args = ctx.actions.args() + args.add("--kind", ctx.attr.kind) + args.add("--source", ctx.file.root.dirname) + args.add("--output", outputs[0].path[:-len(ctx.attr.outs[0])]) + if ctx.attr.profile != "desktop": + args.add("--profile", ctx.attr.profile) + inputs = ctx.files.inputs + [ctx.file.root] + if not ctx.attr.target.startswith("linux-"): + if not ctx.file.facts: + fail("foreign PostGIS templates require the selected target compiler facts") + args.add("--target", ctx.attr.target) + args.add("--facts", ctx.file.facts) + inputs.append(ctx.file.facts) + if ctx.attr.kind == "postgis": + source = EXTENSION_SOURCES["postgis"] + identity = ctx.actions.declare_file(ctx.label.name + ".identity.json") + ctx.actions.write(identity, json.encode({"commit": source["commit"], "source_date_epoch": source["source_date_epoch"], + "default_version": source["extension-control"]["default-version"], + "postgres_major": int(POSTGRES_SOURCE["postgresql"]["version"].split(".")[0]), + "postgres_version": POSTGRES_SOURCE["postgresql"]["version"], + "dependencies": EXTENSION_DEPENDENCIES["postgis"]})) + args.add("--identity", identity) + inputs.append(identity) + bun_action(ctx, ctx.attr._generator, + inputs = inputs, outputs = outputs, + arguments = [args], mnemonic = "PostgisDependencyConfig") + return [DefaultInfo(files = depset(outputs)), + OutputGroupInfo(control = depset([file for file in outputs if file.basename.endswith(".control")])), + CcInfo(compilation_context = cc_common.create_compilation_context( + headers = depset(outputs), includes = depset([outputs[0].path[:-len(ctx.attr.outs[0])].rstrip("/") + ("/" + directory if directory else "") for directory in ctx.attr.include_dirs])))] + +_headers_rule = rule( + implementation = _headers_impl, + attrs = { + "kind": attr.string(mandatory = True), "root": attr.label(allow_single_file = True, mandatory = True), + "inputs": attr.label_list(allow_files = True), "outs": attr.string_list(mandatory = True), + "include_dirs": attr.string_list(default = [""]), + "target": attr.string(mandatory = True), + "profile": attr.string(default = "desktop", values = ["desktop", "mobile-static"]), + "facts": attr.label(allow_single_file = True), + "_generator": attr.label(default = "//build_defs/extensions/postgis:configure_headers", providers = [BunScriptInfo], cfg = "exec"), + }, +) + +def _headers(profile = "desktop", **kwargs): + postgis_profile(profile) + _headers_rule(target = NATIVE_EXTENSION_CONFIGURATION if profile == "desktop" else MOBILE_EXTENSION_CONFIGURATION, + facts = POSTGIS_COMPILER_FACTS if profile == "desktop" else POSTGIS_MOBILE_COMPILER_FACTS, + profile = profile, **kwargs) + +def _source_headers_impl(ctx): + root = ctx.file.root.dirname + return [CcInfo(compilation_context = cc_common.create_compilation_context( + headers = depset(ctx.files.headers), + includes = depset([root + "/" + directory for directory in ctx.attr.include_dirs]), + ))] + +_source_headers = rule( + implementation = _source_headers_impl, + attrs = {"root": attr.label(allow_single_file = True, mandatory = True), + "headers": attr.label_list(allow_files = True), "include_dirs": attr.string_list(mandatory = True)}, +) + +postgis_source_headers = _source_headers + +def postgis_configuration(name, profile = "desktop"): + if EXTENSION_SOURCES["postgis"]["commit"] != "3d12666588a84b23a3147618eaa9b40b0fe5e796": + fail("review the PostGIS source/configuration recipe before changing its canonical source pin") + prefix = "@postgis//:" + _headers(name = name, profile = profile, kind = "postgis", root = prefix + "Version.config", + inputs = [prefix + path for path in ["postgis_config.h.in", "liblwgeom/liblwgeom.h.in", "postgis/sqldefines.h.in", "extensions/postgis/postgis.control.in"]], + outs = ["postgis_config.h", "liblwgeom/liblwgeom.h", "postgis/sqldefines.h", "extensions/postgis/postgis.control", "postgis_revision.h"], + include_dirs = ["", "liblwgeom", "postgis"]) + +def _pin(name, commit): + if EXTENSION_DEPENDENCIES["postgis"][name]["commit"] != commit: + fail("review the native %s source/configuration recipe before updating its canonical pin" % name) + +def postgis_geos(name, profile = "desktop", capi_name = None): + settings = postgis_profile(profile) + _pin("geos", "c389f532d25fe6228861d9b19339f9cb57ca4bdb") + prefix = "@postgis_geos//:" + _headers(name = name + "_config", profile = profile, kind = "geos", root = prefix + "Version.txt", + inputs = [prefix + "include/geos/version.h.in", prefix + "capi/geos_c.h.in"], + outs = ["geos_c.h", "geos/version.h"]) + _source_headers(name = name + "_headers", root = prefix + "Version.txt", headers = [prefix + "headers"], + include_dirs = ["include", "src/deps"]) + # Upstream src/CMakeLists.txt and src/deps/CMakeLists.txt recursively admit + # precisely these C++ and Ryu C files. The C API adds its two capi units. + cc_library(name = name + "_ryu", srcs = [prefix + "native_c_sources"], hdrs = [prefix + "headers"], + deps = [":" + name + "_headers"], copts = settings.c, target_compatible_with = settings.compatible) + cc_library(name = name, srcs = [prefix + ("native_sources" if profile == "desktop" else "native_core_sources")], hdrs = [prefix + "headers"], + deps = [":" + name + "_config", ":" + name + "_headers", ":" + name + "_ryu"], + copts = settings.cxx + (select({"//build_defs/native:macos_arm64": ["-ffp-contract=off"], "//build_defs/native:windows_x64": ["/fp:precise"], "//conditions:default": []}) if profile == "desktop" else ["-ffp-contract=off"]), + defines = ["USE_UNSTABLE_GEOS_CPP_API", "HAVE_FENV"], + linkopts = POSTGIS_THREAD_LINKOPTS, target_compatible_with = settings.compatible) + if profile == "mobile-static": + if not capi_name: + fail("mobile GEOS requires its separate canonical C API object root") + cc_library(name = capi_name, srcs = [prefix + "native_capi_sources"], hdrs = [prefix + "headers"], + deps = [":" + name + "_config", ":" + name + "_headers", ":" + name], + copts = settings.cxx + ["-ffp-contract=off"], defines = ["USE_UNSTABLE_GEOS_CPP_API", "HAVE_FENV"], + target_compatible_with = settings.compatible) + +def postgis_json_c(name, profile = "desktop"): + settings = postgis_profile(profile) + _pin("json-c", "41a55cfcedb54d9c1874f2f0eb07b504091d7e37") + prefix = "@postgis_json_c//:" + _headers(name = name + "_config", profile = profile, kind = "json_c", root = prefix + "CMakeLists.txt", + inputs = [prefix + "cmake/config.h.in", prefix + "cmake/json_config.h.in", prefix + "json.h.cmakein"], + outs = ["config.h", "json_config.h", "json.h"]) + _source_headers(name = name + "_headers", root = prefix + "CMakeLists.txt", headers = [prefix + "headers"], include_dirs = ["."]) + cc_library(name = name, + srcs = [prefix + stem + ".c" for stem in ["arraylist", "debug", "json_c_version", "json_object", "json_object_iterator", "json_tokener", "json_util", "json_visit", "linkhash", "printbuf", "random_seed", "strerror_override", "json_pointer", "json_patch"]], + hdrs = [prefix + "headers"], deps = [":" + name + "_config", ":" + name + "_headers"], + copts = settings.c, + defines = select({"//build_defs/native:windows_x64": [], "//conditions:default": ["_GNU_SOURCE"]}), + linkopts = POSTGIS_MATH_LINKOPTS + select({"//build_defs/native:windows_x64": ["advapi32.lib"], "//conditions:default": []}), target_compatible_with = settings.compatible) + +def postgis_libxml2(name, iconv = None, profile = "desktop"): + settings = postgis_profile(profile) + if profile == "desktop" and not iconv: + fail("desktop libxml2 requires its pinned iconv dependency") + _pin("libxml2", "d23960a130c5bb82779c9405fbbf85e65fb3c57c") + prefix = "@postgis_libxml2//:" + _headers(name = name + "_config", profile = profile, kind = "libxml2", root = prefix + "VERSION", + inputs = [prefix + "config.h.cmake.in", prefix + "include/libxml/xmlversion.h.in"], + outs = ["config.h", "libxml/xmlversion.h"]) + _source_headers(name = name + "_headers", root = prefix + "VERSION", headers = [prefix + "headers"], include_dirs = ["include", "."]) + cc_library(name = name, + srcs = [prefix + stem + ".c" for stem in ["HTMLparser", "HTMLtree", "SAX2", "buf", "c14n", "catalog", "chvalid", "debugXML", "dict", "encoding", "entities", "error", "globals", "hash", "list", "nanohttp", "parser", "parserInternals", "pattern", "relaxng", "schematron", "threads", "tree", "uri", "valid", "xinclude", "xlink", "xmlIO", "xmlmemory", "xmlmodule", "xmlreader", "xmlregexp", "xmlsave", "xmlschemas", "xmlschemastypes", "xmlstring", "xmlunicode", "xmlwriter", "xpath", "xpointer", "xzlib"]], + hdrs = [prefix + "headers"], + deps = [":" + name + "_config", ":" + name + "_headers"] + ([iconv] if profile == "desktop" else []), + copts = settings.c, + defines = select({"//build_defs/native:windows_x64": ["LIBXML_STATIC"], "//conditions:default": ["HAVE_PTHREAD_H", "HAVE_STRINGS_H", "HAVE_UNISTD_H"]}) if profile == "desktop" else ["HAVE_STRINGS_H", "HAVE_UNISTD_H"], + linkopts = POSTGIS_DL_LINKOPTS + select({"//build_defs/native:windows_x64": ["bcrypt.lib"], "//conditions:default": []}) if profile == "desktop" else POSTGIS_MATH_LINKOPTS, + target_compatible_with = settings.compatible) + +def postgis_proj(name, sqlite, profile = "desktop", database = None): + settings = postgis_profile(profile) + _pin("proj", "f08fa86c478c4bbbf003b1ec751dd84aa6eca486") + prefix = "@postgis_proj//:" + _headers(name = name + "_config", profile = profile, kind = "proj", root = prefix + "CMakeLists.txt", + inputs = [prefix + "cmake/proj_config.cmake.in"], outs = ["proj_config.h"]) + _source_headers(name = name + "_headers", root = prefix + "CMakeLists.txt", headers = [prefix + "headers"], include_dirs = ["include", "src"]) + embedded_sources = [] + embedded_deps = [] + embedded_defines = [] + if profile == "mobile-static": + if not database: + fail("mobile PROJ requires the declared execution database") + wasix_proj_embed(name = name + "_embedded", database = database, target_compatible_with = settings.compatible) + native.filegroup(name = name + "_embedded_sources", srcs = [":" + name + "_embedded"], output_group = "library_sources") + embedded_sources = [prefix + "src/embedded_resources.c", prefix + "src/memvfs.c", ":" + name + "_embedded_sources"] + embedded_deps = [":" + name + "_embedded", sqlite] + embedded_defines = ["PROJ_DLL=", "EMBED_RESOURCE_FILES=1", "USE_ONLY_EMBEDDED_RESOURCE_FILES=1"] + cc_library(name = name + "_c", srcs = [prefix + "native_c_sources"] + embedded_sources, hdrs = [prefix + "headers"], + deps = [":" + name + "_config", ":" + name + "_headers"] + embedded_deps, + defines = embedded_defines, copts = settings.c, target_compatible_with = settings.compatible) + cc_library(name = name, srcs = [prefix + "native_sources"], hdrs = [prefix + "headers"], + deps = [":" + name + "_config", ":" + name + "_headers", ":" + name + "_c", sqlite], + copts = settings.cxx, + defines = ["PROJ_DLL="] + select({"//build_defs/native:windows_x64": [], "//conditions:default": ["PROJ_HAS_PTHREADS"]}) + (embedded_defines[1:] if profile == "mobile-static" else []), + linkopts = select({"//build_defs/native:windows_x64": ["shell32.lib", "ole32.lib"], "//build_defs/native:macos_arm64": [], "//conditions:default": ["-ldl", "-lm", "-pthread"]}) if profile == "desktop" else POSTGIS_THREAD_LINKOPTS, + target_compatible_with = settings.compatible) + +def postgis_iconv(name, profile = "desktop", charset_name = None): + settings = postgis_profile(profile) + source = EXTENSION_DEPENDENCIES["postgis"]["libiconv"] + if source["sha256"] != "88dd96a8c0464eca144fc791ae60cd31cd8ee78321e67397e25fc095c4a19aa6": + fail("review native libiconv headers/object recipe before changing the canonical archive pin") + prefix = "@postgis_libiconv//:" + _headers(name = name + "_config", profile = profile, kind = "libiconv", root = prefix + "configure", + inputs = [prefix + path for path in ["lib/config.h.in", "include/iconv.h.build.in", "libcharset/include/localcharset.h.build.in", "libcharset/include/libcharset.h.build.in"]], + outs = ["config.h", "iconv.h", "localcharset.h", "libcharset.h"]) + _source_headers(name = name + "_headers", root = prefix + "configure", headers = [prefix + "headers", prefix + "lib/encodings.def", prefix + "lib/encodings_local.def"] + select({"//build_defs/native:windows_x64": [prefix + "lib/encodings_dos.def"], "//conditions:default": []}), include_dirs = ["lib", "include", "libcharset/include"]) + cc_library(name = name, + srcs = [prefix + path for path in (["lib/iconv.c", "lib/compat.c", "libcharset/lib/localcharset.c", "libcharset/lib/relocatable-stub.c"] if profile == "desktop" else ["lib/iconv.c", "lib/compat.c", "libcharset/lib/localcharset.c"])], + hdrs = [prefix + "headers"], deps = [":" + name + "_config", ":" + name + "_headers"], + copts = settings.c, + local_defines = ["BUILDING_LIBICONV", "BUILDING_LIBCHARSET"], target_compatible_with = settings.compatible) + if profile == "mobile-static": + if not charset_name: + fail("mobile libiconv requires its separate charset object root") + cc_library(name = charset_name, srcs = [prefix + path for path in ["libcharset/lib/localcharset.c", "libcharset/lib/relocatable-stub.c"]], + hdrs = [prefix + "headers"], deps = [":" + name + "_config", ":" + name + "_headers"], + copts = settings.c, local_defines = ["BUILDING_LIBCHARSET"], target_compatible_with = settings.compatible) diff --git a/build_defs/extensions/postgis/mobile.bzl b/build_defs/extensions/postgis/mobile.bzl new file mode 100644 index 000000000..0a42fc9e0 --- /dev/null +++ b/build_defs/extensions/postgis/mobile.bzl @@ -0,0 +1,66 @@ +"""Canonical static PostGIS component archives and actual mobile module objects.""" + +load("@rules_cc//cc:defs.bzl", "cc_import", "cc_library") +load("//build_defs/extensions:mobile.bzl", "MOBILE_EXTENSION_COMPATIBLE", "mobile_static_archive", "native_mobile_extension") +load(":compiler_facts.bzl", "postgis_mobile_compiler_facts") +load(":libraries.bzl", "POSTGIS_MATH_LINKOPTS", "POSTGIS_THREAD_LINKOPTS", "postgis_geos", "postgis_iconv", "postgis_json_c", "postgis_libxml2", "postgis_proj") +load(":modules.bzl", "POSTGIS_PG_SOURCES", "postgis_standalone") +load(":sqlite.bzl", "postgis_sqlite") + +POSTGIS_MOBILE_ARCHIVES = { + "geos-c": "//build_defs/extensions/postgis/mobile:geos_c", + "geos": "//build_defs/extensions/postgis/mobile:geos", + "proj": "//build_defs/extensions/postgis/mobile:proj", + "sqlite": "//build_defs/extensions/postgis/mobile:sqlite3", + "libxml2": "//build_defs/extensions/postgis/mobile:xml2", + "json-c": "//build_defs/extensions/postgis/mobile:json-c", + "libiconv": "//build_defs/extensions/postgis/mobile:iconv", + "libcharset": "//build_defs/extensions/postgis/mobile:charset", +} +POSTGIS_MOBILE_LIBRARIES = {identity: archive + "_library" for identity, archive in POSTGIS_MOBILE_ARCHIVES.items()} + +_ANDROID = select({"//build_defs/native:android": [":iconv_objects"], "//conditions:default": []}) +_ANDROID_LIBRARIES = select({"//build_defs/native:android": [":iconv_library", ":charset_library"], "//conditions:default": []}) + +def _database_impl(ctx): + return [DefaultInfo(files = ctx.attr.database[DefaultInfo].files)] + +_execution_database = rule(implementation = _database_impl, attrs = { + "database": attr.label(default = "//build_defs/extensions/postgis:database", cfg = "exec", allow_single_file = True), +}) + +def _archive(name, roots, link_deps = [], linkopts = []): + mobile_static_archive(name = name, roots = roots, target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) + # Ordinary dependency imports allow libiconv/libcharset to resolve their + # shared localcharset unit once, as their upstream static link recipe does. + cc_import(name = name + "_import", static_library = ":" + name, target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) + cc_library(name = name + "_library", deps = [":" + name + "_import"] + link_deps, linkopts = linkopts, + target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) + +def mobile_postgis(): + profile = "mobile-static" + postgis_mobile_compiler_facts() + _execution_database(name = "database", target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) + postgis_sqlite(name = "sqlite_objects", profile = profile) + postgis_geos(name = "geos_objects", capi_name = "geos_c_objects", profile = profile) + postgis_json_c(name = "json_c_objects", profile = profile) + postgis_proj(name = "proj_objects", sqlite = ":sqlite_objects", database = ":database", profile = profile) + postgis_iconv(name = "iconv_objects", charset_name = "charset_objects", profile = profile) + postgis_libxml2(name = "xml2_objects", profile = profile) + _archive(name = "sqlite3", roots = [":sqlite_objects"]) + _archive(name = "geos", roots = [":geos_objects", ":geos_objects_ryu"], linkopts = POSTGIS_THREAD_LINKOPTS) + _archive(name = "geos_c", roots = [":geos_c_objects"], link_deps = [":geos_library"]) + _archive(name = "json-c", roots = [":json_c_objects"], linkopts = POSTGIS_MATH_LINKOPTS) + _archive(name = "proj", roots = [":proj_objects", ":proj_objects_c"], link_deps = [":sqlite3_library"], linkopts = POSTGIS_THREAD_LINKOPTS) + _archive(name = "iconv", roots = [":iconv_objects"]) + _archive(name = "charset", roots = [":charset_objects"]) + _archive(name = "xml2", roots = [":xml2_objects"], linkopts = POSTGIS_MATH_LINKOPTS) + postgis_standalone(name = "postgis", profile = profile) + native_mobile_extension(name = "extension", sql_name = "postgis", + srcs = ["@postgis//:" + source for source in POSTGIS_PG_SOURCES], + deps = [":postgis_config", ":postgis_headers", ":postgis_lwgeom", ":postgis_flatgeobuf", ":xml2_objects"] + _ANDROID, + object_roots = [":postgis_lwgeom", ":postgis_flatgeobuf", ":postgis_ryu"], + consumer_deps = [":geos_c_library", ":proj_library", ":json-c_library", ":xml2_library"] + _ANDROID_LIBRARIES) + native.filegroup(name = "dependency_archives", srcs = [":" + name for name in ["geos_c", "geos", "proj", "sqlite3", "xml2", "json-c"]] + + select({"//build_defs/native:android": [":iconv", ":charset"], "//conditions:default": []}), + target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) diff --git a/build_defs/extensions/postgis/mobile/BUILD.bazel b/build_defs/extensions/postgis/mobile/BUILD.bazel new file mode 100644 index 000000000..7540de8aa --- /dev/null +++ b/build_defs/extensions/postgis/mobile/BUILD.bazel @@ -0,0 +1,5 @@ +load("//build_defs/extensions/postgis:mobile.bzl", "mobile_postgis") + +package(default_visibility = ["//visibility:public"]) + +mobile_postgis() diff --git a/build_defs/extensions/postgis/modules.bzl b/build_defs/extensions/postgis/modules.bzl new file mode 100644 index 000000000..70aa62bda --- /dev/null +++ b/build_defs/extensions/postgis/modules.bzl @@ -0,0 +1,119 @@ +"""Pinned PostGIS standalone libraries and independently compiled PG ABI modules.""" + +load("@rules_cc//cc:defs.bzl", "cc_library", "cc_shared_library") +load("//build_defs/extensions:contrib.bzl", "contrib_generated_sources") +load("//build_defs/extensions:extensions.bzl", "extension_native_dependency_modules", "native_extension_modules") +load("@oliphaunt_metadata//:metadata.bzl", "EXTENSION_RECIPES") +load("//build_defs/extensions:external.bzl", "windows_extension_sources") +load("//build_defs/extensions:platforms.bzl", "NATIVE_EXTENSION_COMPATIBLE", "NATIVE_EXTENSION_PROFILES") +load("//build_defs/extensions:mobile.bzl", "MOBILE_EXTENSION_COMPATIBLE") +load("//build_defs/native:platform_config.bzl", "NATIVE_RELEASE_LINKOPTS", "NATIVE_WINDOWS_COMPATIBLE") +load(":libraries.bzl", "POSTGIS_MATH_LINKOPTS", "POSTGIS_NATIVE_COPTS", "POSTGIS_NATIVE_CXX_COPTS", "postgis_configuration", "postgis_profile", "postgis_source_headers") +load(":generators.bzl", "postgis_flex") +load(":windows_sources_test.bzl", "postgis_windows_sources_test") + +# liblwgeom/Makefile.in SA_OBJS and NM_OBJS, with optional SFCGAL disabled. +_LWGEOM = "stringbuffer optionlist stringlist bytebuffer measures measures3d ptarray lookup3 lwgeom_api lwgeom lwpoint lwline lwpoly lwtriangle lwmpoint lwmline lwmpoly lwboundingcircle lwcollection lwcircstring lwcompound lwcurvepoly lwmcurve lwmsurface lwpsurface lwtin lwout_wkb lwin_geojson lwin_wkb lwin_twkb lwiterator lwgeom_median lwout_wkt lwout_twkb lwin_wkt lwin_encoded_polyline lwutil lwhomogenize intervaltree lwalgorithm lwstroke lwlinearreferencing lwprint gbox gserialized gserialized1 gserialized2 lwgeodetic lwgeodetic_measures lwgeodetic_tree lwrandom lwtree lwout_gml lwout_kml lwout_geojson lwout_svg lwout_x3d lwout_encoded_polyline lwgeom_debug lwgeom_geos lwgeom_geos_clean lwgeom_geos_cluster lwgeom_geos_node lwgeom_geos_split topo/lwgeom_topo topo/lwgeom_topo_polygonizer topo/lwt_edgeend topo/lwt_edgeend_star topo/lwt_node_edges lwgeom_transform lwgeom_wrapx lwunionfind effectivearea lwchaikins lwmval lwkmeans varint lwgeom_remove_irrelevant_points_for_view lwspheroid".split(" ") + +# postgis/Makefile.in PG_OBJS + the PostgreSQL 18 SPGIST_OBJ recipe. +# Protobuf/SFCGAL optional profiles are disabled in the generated configuration. +_PG = "postgis_module lwgeom_accum lwgeom_union lwgeom_spheroid lwgeom_ogc lwgeom_functions_analytic lwgeom_functions_basic lwgeom_inout lwgeom_btree lwgeom_box lwgeom_box3d lwgeom_geos lwgeom_geos_predicates lwgeom_geos_prepared lwgeom_geos_clean lwgeom_geos_relatematch lwgeom_generate_grid lwgeom_export lwgeom_in_gml lwgeom_in_kml lwgeom_in_marc21 lwgeom_out_marc21 lwgeom_in_geohash lwgeom_in_geojson lwgeom_in_encoded_polyline lwgeom_triggers lwgeom_dump lwgeom_dumppoints lwgeom_functions_lrs lwgeom_functions_temporal lwgeom_rectree lwgeom_itree lwgeom_sqlmm lwgeom_transform lwgeom_window gserialized_typmod gserialized_gist_2d gserialized_gist_nd gserialized_supportfn gserialized_spgist_2d gserialized_spgist_3d gserialized_spgist_nd brin_2d brin_nd brin_common gserialized_estimate geography_inout geography_btree geography_centroid geography_measurement geography_measurement_trees geometry_inout postgis_libprotobuf mvt lwgeom_out_mvt geobuf lwgeom_out_geobuf lwgeom_out_geojson flatgeobuf lwgeom_in_flatgeobuf lwgeom_out_flatgeobuf lwgeom_remove_irrelevant_points_for_view lwgeom_remove_small_parts postgis_legacy".split(" ") +_PGCOMMON = "gserialized_gist lwgeom_transform lwgeom_cache lwgeom_pg shared_gserialized".split(" ") + +POSTGIS_LWGEOM_SOURCES = ["liblwgeom/" + source + ".c" for source in _LWGEOM] +POSTGIS_PG_SOURCES = ["postgis/" + source + ".c" for source in _PG] + ["libpgcommon/" + source + ".c" for source in _PGCOMMON] + +def postgis_standalone(name, profile = "desktop"): + if profile != "desktop": + _mobile_standalone(name, profile) + return + prefix = "@postgis//:" + flatgeobuf_sources = ["deps/flatgeobuf/" + source + ".cpp" for source in ["flatgeobuf_c", "geometrywriter", "geometryreader", "packedrtree"]] + windows_srcs = [prefix + source for source in POSTGIS_LWGEOM_SOURCES + POSTGIS_PG_SOURCES + flatgeobuf_sources] + windows_hdrs = [prefix + "postgis_headers"] + windows_companions = {"//src/extensions/external/postgis:tools/windows/postgis-compat.h": "oliphaunt_postgis_windows_compat.h", "//src/extensions/external/postgis:tools/windows/flatgeobuf-compat.h": "oliphaunt_flatgeobuf_windows_compat.h"} + windows_extension_sources( + name = name + "_windows_sources", sql_name = "postgis", + srcs = windows_srcs, hdrs = windows_hdrs, anchor = prefix + "Version.config", anchor_name = "Version.config", + companions = windows_companions, + include_dirs = ["liblwgeom", "libpgcommon", "postgis", "deps", "deps/flatgeobuf", "deps/flatgeobuf/include", ""], + source_groups = ["liblwgeom", "postgis", "libpgcommon", "deps/flatgeobuf"], target_compatible_with = NATIVE_WINDOWS_COMPATIBLE, + ) + postgis_windows_sources_test(name = name + "_windows_sources_test", prepared = ":" + name + "_windows_sources", + srcs = windows_srcs, hdrs = windows_hdrs, anchor = prefix + "Version.config", anchor_name = "Version.config", companions = windows_companions) + for group in ["liblwgeom", "postgis", "libpgcommon", "flatgeobuf"]: + native.filegroup(name = name + "_windows_" + group, srcs = [":" + name + "_windows_sources"], output_group = group + "_sources") + native.filegroup(name = name + "_windows_pg_sources", srcs = [":" + name + "_windows_postgis", ":" + name + "_windows_libpgcommon"]) + postgis_configuration(name = name + "_config") + postgis_source_headers(name = name + "_headers", root = prefix + "Version.config", + headers = [prefix + "postgis_headers"], + include_dirs = ["liblwgeom", "libpgcommon", "postgis", "deps", "deps/flatgeobuf", "deps/flatgeobuf/include", ""]) + contrib_generated_sources(name = name + "_wkt", grammar = prefix + "liblwgeom/lwin_wkt_parse.y", + scanner = prefix + "liblwgeom/lwin_wkt_lex.l", + grammar_options = ["-d", "-p", "wkt_yy"], scanner_options = ["-i"], scanner_rule = postgis_flex) + cc_library(name = name + "_ryu", srcs = [prefix + "deps/ryu/d2s.c"], + deps = [":" + name + "_headers"], defines = ["RYU_NO_TRAILING_ZEROS"], copts = POSTGIS_NATIVE_COPTS, + target_compatible_with = NATIVE_EXTENSION_COMPATIBLE) + cc_library(name = name + "_lwgeom", + srcs = select({"//build_defs/native:windows_x64": [":" + name + "_windows_liblwgeom"], "//conditions:default": [prefix + source for source in POSTGIS_LWGEOM_SOURCES]}) + [":" + name + "_wkt"], + deps = [":" + name + "_config"] + select({"//build_defs/native:windows_x64": [":" + name + "_windows_sources"], "//conditions:default": [":" + name + "_headers"]}) + [":" + name + "_wkt", ":" + name + "_ryu", + "//build_defs/extensions/postgis:geos", "//build_defs/extensions/postgis:proj", "//build_defs/extensions/postgis:json_c"], + copts = POSTGIS_NATIVE_COPTS + select({"//build_defs/native:windows_x64": ["/FI$(location //src/extensions/external/postgis:tools/windows/postgis-compat.h)"], "//conditions:default": []}), + local_defines = select({"//build_defs/native:windows_x64": ["YY_NO_UNISTD_H"], "//conditions:default": []}), + additional_compiler_inputs = select({"//build_defs/native:windows_x64": ["//src/extensions/external/postgis:tools/windows/postgis-compat.h"], "//conditions:default": []}), + linkopts = POSTGIS_MATH_LINKOPTS, target_compatible_with = NATIVE_EXTENSION_COMPATIBLE) + cc_library(name = name + "_flatgeobuf", + srcs = select({"//build_defs/native:windows_x64": [":" + name + "_windows_flatgeobuf"], "//conditions:default": [prefix + source for source in flatgeobuf_sources]}), + deps = [":" + name + "_config"] + select({"//build_defs/native:windows_x64": [":" + name + "_windows_sources"], "//conditions:default": [":" + name + "_headers"]}) + ["//build_defs/extensions/postgis:proj"], + copts = POSTGIS_NATIVE_CXX_COPTS + select({"//build_defs/native:windows_x64": ["/FI$(location //src/extensions/external/postgis:tools/windows/flatgeobuf-compat.h)"], "//conditions:default": []}), + additional_compiler_inputs = select({"//build_defs/native:windows_x64": ["//src/extensions/external/postgis:tools/windows/flatgeobuf-compat.h"], "//conditions:default": []}), + defines = ["flatbuffers=postgis_flatbuffers"], + target_compatible_with = NATIVE_EXTENSION_COMPATIBLE) + +_DEPENDENCY_ARTIFACTS = EXTENSION_RECIPES["postgis"]["artifacts"] +_DEPENDENCY_MODULES = {condition: extension_native_dependency_modules(_DEPENDENCY_ARTIFACTS.get("native_dependency_modules", []), configuration, _DEPENDENCY_ARTIFACTS.get("native_dependency_modules_by_target", {})) for condition, configuration in NATIVE_EXTENSION_PROFILES.items()} + +def postgis_dependency_module_labels(label): + """Use the dependency DLL only in profiles whose recipe carries one.""" + return select({condition: [label] if modules else [] for condition, modules in _DEPENDENCY_MODULES.items()} | {"//conditions:default": []}) + +def postgis_dependency_module(name): + # A maintained direct shared-library rule whole-archives the six real roots; + # module consumers use dynamic_deps to prevent a second static dependency copy. + cc_shared_library(name = name, shared_lib_name = select({"//build_defs/native:windows_x64": "liboliphaunt_postgis_deps.dll", "//build_defs/native:macos_arm64": "liboliphaunt_postgis_deps.dylib", "//conditions:default": "liboliphaunt_postgis_deps.so"}), + deps = ["//build_defs/extensions/postgis:" + library for library in ["geos", "proj", "json_c", "libxml2", "iconv", "sqlite"]], + features = select({"//build_defs/native:windows_x64": ["windows_export_all_symbols"], "//conditions:default": []}), + user_link_flags = select({"//build_defs/native:windows_x64": [], "//build_defs/native:macos_arm64": ["-Wl,-install_name,@rpath/liboliphaunt_postgis_deps.dylib"], "//conditions:default": ["-Wl,-z,defs"]}) + NATIVE_RELEASE_LINKOPTS, target_compatible_with = select({condition: [] if modules else ["@platforms//:incompatible"] for condition, modules in _DEPENDENCY_MODULES.items()} | {"//conditions:default": ["@platforms//:incompatible"]})) + +def native_postgis_modules(name, standalone, dependency_module): + prefix = "@postgis//:" + compatibility_inputs = select({"//build_defs/native:windows_x64": ["//src/extensions/external/postgis:tools/windows/postgis-compat.h"], "//conditions:default": []}) + native_extension_modules(name = name, + srcs = select({"//build_defs/native:windows_x64": [standalone + "_windows_pg_sources"], "//conditions:default": [prefix + source for source in POSTGIS_PG_SOURCES]}), + deps = [standalone + "_config"] + select({"//build_defs/native:windows_x64": [standalone + "_windows_sources"], "//conditions:default": [standalone + "_headers"]}) + [standalone + "_lwgeom", standalone + "_flatgeobuf", "//build_defs/extensions/postgis:libxml2"], + copts = select({"//build_defs/native:windows_x64": ["/D_USE_MATH_DEFINES", "/FI$(location //src/extensions/external/postgis:tools/windows/postgis-compat.h)"], "//conditions:default": []}), + hdrs = compatibility_inputs, + additional_compiler_inputs = compatibility_inputs, + dynamic_deps = postgis_dependency_module_labels(dependency_module), linkopts = select({"//build_defs/native:windows_x64": [], "//build_defs/native:macos_arm64": ["-Wl,-rpath,@loader_path"], "//conditions:default": ["-Wl,-rpath,$$ORIGIN"]})) + +def _mobile_standalone(name, profile): + settings = postgis_profile(profile) + prefix = "@postgis//:" + dependencies = "//build_defs/extensions/postgis/mobile:" + postgis_configuration(name = name + "_config", profile = profile) + postgis_source_headers(name = name + "_headers", root = prefix + "Version.config", + headers = [prefix + "postgis_headers"], + include_dirs = ["liblwgeom", "libpgcommon", "postgis", "deps", "deps/flatgeobuf", "deps/flatgeobuf/include", ""]) + contrib_generated_sources(name = name + "_wkt", grammar = prefix + "liblwgeom/lwin_wkt_parse.y", + scanner = prefix + "liblwgeom/lwin_wkt_lex.l", + grammar_options = ["-d", "-p", "wkt_yy"], scanner_options = ["-i"], scanner_rule = postgis_flex) + cc_library(name = name + "_ryu", srcs = [prefix + "deps/ryu/d2s.c"], deps = [":" + name + "_headers"], + defines = ["RYU_NO_TRAILING_ZEROS"], copts = settings.c, target_compatible_with = settings.compatible) + cc_library(name = name + "_lwgeom", srcs = [prefix + source for source in POSTGIS_LWGEOM_SOURCES] + [":" + name + "_wkt"], + deps = [":" + name + "_config", ":" + name + "_headers", ":" + name + "_wkt", ":" + name + "_ryu"] + + [dependencies + component for component in ["geos_c_objects", "proj_objects", "json_c_objects"]], + copts = settings.c, linkopts = POSTGIS_MATH_LINKOPTS, target_compatible_with = settings.compatible) + cc_library(name = name + "_flatgeobuf", + srcs = [prefix + "deps/flatgeobuf/" + source + ".cpp" for source in ["flatgeobuf_c", "geometrywriter", "geometryreader", "packedrtree"]], + deps = [":" + name + "_config", ":" + name + "_headers", dependencies + "proj_objects"], + copts = settings.cxx, defines = ["flatbuffers=postgis_flatbuffers"], target_compatible_with = MOBILE_EXTENSION_COMPATIBLE) diff --git a/build_defs/extensions/postgis/proj_db.bzl b/build_defs/extensions/postgis/proj_db.bzl new file mode 100644 index 000000000..7e71b7389 --- /dev/null +++ b/build_defs/extensions/postgis/proj_db.bzl @@ -0,0 +1,31 @@ +"""Build PROJ's canonical data SQL with the source-built execution SQLite.""" + +load("//build_defs/extensions:platforms.bzl", "NATIVE_EXTENSION_COMPATIBLE") +load("//build_defs/foundation:bun.bzl", "BunScriptInfo", "bun_action") + +def _impl(ctx): + output = ctx.actions.declare_file(ctx.label.name + "/proj.db") + args = ctx.actions.args() + args.add("--source", ctx.file.root.dirname) + args.add("--output", output) + args.add("--sqlite", ctx.executable.sqlite) + bun_action(ctx, ctx.attr._generator, + tools = [ctx.attr.sqlite[DefaultInfo].files_to_run], + inputs = ctx.files.inputs + [ctx.file.root], outputs = [output], + arguments = [args], mnemonic = "ProjDatabase") + return [DefaultInfo(files = depset([output]))] + +_proj_database = rule( + implementation = _impl, + attrs = { + "root": attr.label(allow_single_file = True, mandatory = True), + "inputs": attr.label_list(allow_files = True), + "sqlite": attr.label(executable = True, cfg = "exec", mandatory = True), + "_generator": attr.label(default = "//build_defs/extensions/postgis:proj_db", providers = [BunScriptInfo], cfg = "exec"), + }, +) + +def proj_database(name): + _proj_database(name = name, root = "@postgis_proj//:CMakeLists.txt", + inputs = ["@postgis_proj//:all_sources"], sqlite = "//build_defs/extensions/postgis:sqlite_cli", + target_compatible_with = NATIVE_EXTENSION_COMPATIBLE) diff --git a/build_defs/extensions/postgis/proj_db.mts b/build_defs/extensions/postgis/proj_db.mts new file mode 100644 index 000000000..3fd30f156 --- /dev/null +++ b/build_defs/extensions/postgis/proj_db.mts @@ -0,0 +1,109 @@ +/** Bounded translation of the pinned PROJ database-only CMake recipe. + * Recipe bytes are guarded; the SQL file list remains upstream-owned. + */ +import { createHash } from 'node:crypto'; +import { mkdirSync, readFileSync } from 'node:fs'; +import { dirname, join, resolve } from 'node:path'; +import { parseArgs } from 'node:util'; + +const decoder = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }); +function read(path: string): string { + return decoder.decode(readFileSync(path)); +} + +export function databaseSql(source: string): string { + const recipes = { + 'data/sql_filelist.cmake': 'd187728c432ce56160083f4ffab4329c34f4adb0404bbf03f1a8343aa82f59f6', + 'data/generate_proj_db.cmake': + 'eb458b6a382dbd394ce35b0f6b6d66a5068cad92f72dc70c3d3daeee6fe9dfbf', + 'data/CMakeLists.txt': '709bb6a4e24d5a198c721269e9557abdf2bfa05cd5a0343a917c1463d89e5da7', + }; + for (const [path, expected] of Object.entries(recipes)) { + if ( + createHash('sha256') + .update(readFileSync(join(source, path))) + .digest('hex') !== expected + ) { + throw new Error(`review PROJ's upstream database recipe before changing ${path}`); + } + } + const vars: Record = { CMAKE_CURRENT_LIST_DIR: [join(source, 'data')] }; + let enabled = true; + const recipe = read(join(source, 'data/sql_filelist.cmake')).replace(/^\s*#.*$/gm, ''); + for (const match of recipe.matchAll(/(set|list|if|else|endif)\s*\(([^)]*)\)/g)) { + const [, command, body] = match; + if (command === 'if') { + if (!['PROJ_DB_EXTRA_VALIDATION', 'NOT PROJ_DB_EXTRA_VALIDATION'].includes(body.trim())) { + throw new Error('unexpected PROJ SQL list condition'); + } + enabled = body.trim().startsWith('NOT '); + } else if (command === 'else') { + enabled = !enabled; + } else if (command === 'endif') { + enabled = true; + } else if (enabled) { + const tokens = Array.from( + body.matchAll(/"([^"]*)"|([^\s"]+)/g), + (token) => token[1] ?? token[2], + ); + if (command === 'list' && tokens.shift() !== 'APPEND') + throw new Error('unexpected PROJ SQL list operation'); + const name = tokens.shift(); + if (!name) throw new Error('missing PROJ SQL list variable'); + const values = tokens.flatMap((token) => { + const variable = /^\$\{(\w+)\}$/.exec(token); + if (variable) { + if (!vars[variable[1]]) throw new Error(`unknown PROJ SQL variable ${variable[1]}`); + return vars[variable[1]]; + } + return [ + token.replace(/\$\{(\w+)\}/g, (_match, key: string) => { + if (vars[key]?.length !== 1) throw new Error(`unknown PROJ SQL path ${key}`); + return vars[key][0]; + }), + ]; + }); + vars[name] = command === 'list' ? [...(vars[name] ?? []), ...values] : values; + } + } + const paths = vars.SQL_FILES; + if (!paths?.length || new Set(paths).size !== paths.length) + throw new Error('invalid PROJ SQL input list'); + const sql = paths.map((path) => read(path)).join(''); + const expectedMd5 = /set\(PROJ_DB_SQL_EXPECTED_MD5 "([a-f0-9]{32})"\)/.exec( + read(join(source, 'data/CMakeLists.txt')), + )?.[1]; + // Exact upstream generate_proj_db.cmake metadata-independent SQL checksum. + const md5 = createHash('md5') + .update(sql.replace(/INSERT INTO "metadata"[^\n]*\n?/g, '')) + .digest('hex'); + if (md5 !== expectedMd5) throw new Error(`PROJ SQL checksum differs from upstream: ${md5}`); + const header = read(join(source, 'src/proj.h')); + const version = ['MAJOR', 'MINOR', 'PATCH'] + .map((component) => { + const value = new RegExp(`#define PROJ_VERSION_${component} (\\d+)`).exec(header)?.[1]; + if (!value) throw new Error('missing PROJ source version'); + return value; + }) + .join('.'); + // biome-ignore lint/suspicious/noTemplateCurlyInString: literal upstream CMake variable. + return sql.replaceAll('${PROJ_VERSION}', () => version); +} + +if (import.meta.main) { + const { values } = parseArgs({ + options: { source: { type: 'string' }, output: { type: 'string' }, sqlite: { type: 'string' } }, + }); + if (!values.source || !values.output || !values.sqlite) + throw new Error('required: --source --output --sqlite'); + const output = resolve(values.output); + mkdirSync(dirname(output), { recursive: true }); + const result = Bun.spawnSync([resolve(values.sqlite), '-bail', output], { + stdin: Buffer.from(databaseSql(resolve(values.source))), + stdout: 'pipe', + stderr: 'pipe', + env: { ...process.env, LC_ALL: 'C', SQLITE_HISTORY: '/dev/null' }, + }); + if (result.exitCode !== 0) + throw new Error(`PROJ database construction failed: ${result.stderr.toString('utf8')}`); +} diff --git a/build_defs/extensions/postgis/sql.bzl b/build_defs/extensions/postgis/sql.bzl new file mode 100644 index 000000000..3e450f8df --- /dev/null +++ b/build_defs/extensions/postgis/sql.bzl @@ -0,0 +1,63 @@ +"""PostGIS SQL uses pinned upstream GPP and Perl generators.""" + +load("@oliphaunt_metadata//:metadata.bzl", "EXTENSION_SOURCES", "POSTGRES_SOURCE") +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") +load("//build_defs/extensions:platforms.bzl", "NATIVE_EXTENSION_COMPATIBLE") +load("//build_defs/foundation:bun.bzl", "BunScriptInfo", "bun_action") + +def _preprocess_impl(ctx): + contexts = [dep[CcInfo].compilation_context for dep in ctx.attr.headers] + outputs = [] + for source in ctx.files.srcs: + output = ctx.actions.declare_file(ctx.label.name + "/" + source.basename[:-3]) + # Keep configure.ac's SQL string mode without duplicate Windows CR insertion. + args = ctx.actions.args() + args.add_all(["+z", "-C", "-s", "'", "-o", output.path]) + args.add_all(depset(transitive = [context.includes for context in contexts]), format_each = "-I%s") + args.add(source) + ctx.actions.run(executable = ctx.attr._gpp[DefaultInfo].files_to_run, + arguments = [args], + inputs = depset(ctx.files.inputs + [source], transitive = [context.headers for context in contexts]), + outputs = [output], mnemonic = "PostgisSqlPreprocess") + outputs.append(output) + return [DefaultInfo(files = depset(outputs))] + +_preprocess = rule(implementation = _preprocess_impl, + attrs = {"srcs": attr.label_list(allow_files = True), "inputs": attr.label_list(allow_files = True), "headers": attr.label_list(providers = [CcInfo]), + "_gpp": attr.label(default = "@postgis_gpp//:gpp", executable = True, cfg = "exec")}) + +def _sql_impl(ctx): + extension = ctx.actions.declare_directory(ctx.label.name + "/extension") + data = ctx.actions.declare_directory(ctx.label.name + "/contrib") + source = EXTENSION_SOURCES["postgis"] + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode({"source": ctx.file.root.dirname, "extension": extension.path, "data": data.path, + "preprocessed": {file.basename: file.path for file in ctx.files.preprocessed}, + "source_date_epoch": source["source_date_epoch"], "version": source["extension-control"]["default-version"], + "postgres_version": int(POSTGRES_SOURCE["postgresql"]["version"].split(".")[0]) * 10})) + perl = ctx.toolchains["@rules_perl//perl:exec_toolchain_type"].perl_runtime + args = ctx.actions.args() + args.add("--spec", spec) + args.add("--perl", perl.interpreter) + for option in perl.perlopt: + args.add("--perl-option=" + option) + bun_action(ctx, ctx.attr._generator, + inputs = depset([spec, ctx.file.root] + ctx.files.inputs + ctx.files.preprocessed, transitive = [perl.runtime]), + outputs = [extension, data], arguments = [args], mnemonic = "PostgisUpstreamSql") + return [DefaultInfo(files = depset([extension, data])), OutputGroupInfo(extension_sql = depset([extension]), data_sql = depset([data]))] + +_sql = rule(implementation = _sql_impl, + attrs = {"root": attr.label(allow_single_file = True), "inputs": attr.label_list(allow_files = True), "preprocessed": attr.label_list(allow_files = True), + "_generator": attr.label(default = "//build_defs/extensions/postgis:sql", providers = [BunScriptInfo], cfg = "exec")}, + toolchains = ["@rules_perl//perl:exec_toolchain_type"]) + +def postgis_sql(name, configuration, headers, target_compatible_with = NATIVE_EXTENSION_COMPATIBLE): + prefix = "@postgis//:" + inputs = [prefix + "postgis_sql_inputs", prefix + "spatial_ref_sys.sql"] + preprocessed = name + "_preprocessed" + _preprocess(name = preprocessed, + srcs = [prefix + "postgis/" + source + ".sql.in" for source in ["postgis", "legacy", "legacy_minimal", "legacy_gist"]] + + [prefix + "raster/rt_pg/" + source + ".sql.in" for source in ["rtpostgis", "rtpostgis_drop", "rtpostgis_upgrade_cleanup"]] + + [prefix + "extensions/postgis_extension_helper.sql.in"], + inputs = inputs, headers = [configuration, headers], target_compatible_with = target_compatible_with) + _sql(name = name, root = prefix + "Version.config", inputs = inputs, preprocessed = [":" + preprocessed], target_compatible_with = target_compatible_with) diff --git a/build_defs/extensions/postgis/sql.mts b/build_defs/extensions/postgis/sql.mts new file mode 100644 index 000000000..06513dcf9 --- /dev/null +++ b/build_defs/extensions/postgis/sql.mts @@ -0,0 +1,204 @@ +/** Orchestrate guarded upstream PostGIS SQL recipes and actual Perl generators. */ +import { createHash } from 'node:crypto'; +import { + copyFileSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join, resolve } from 'node:path'; +import { parseArgs } from 'node:util'; + +const { values } = parseArgs({ + options: { + spec: { type: 'string' }, + perl: { type: 'string' }, + 'perl-option': { type: 'string', multiple: true }, + }, +}); +if (!values.spec || !values.perl) throw new Error('required: --spec --perl'); +const decoder = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }); +const read = (path: string) => decoder.decode(readFileSync(path)); +const spec = JSON.parse(read(values.spec)) as { + source: string; + extension: string; + data: string; + preprocessed: Record; + source_date_epoch: number; + version: string; + postgres_version: number; +}; +const source = resolve(spec.source), + extension = resolve(spec.extension), + data = resolve(spec.data); +const perl = resolve(values.perl), + options = values['perl-option'] ?? []; +const work = mkdtempSync(join(process.env.TMPDIR ?? tmpdir(), 'postgis-sql-')); +const postgisWork = join(work, 'postgis'); +const extensionWork = join(work, 'extensions', 'postgis'); +const rasterWork = join(work, 'raster', 'rt_pg'); +for (const directory of [postgisWork, join(extensionWork, 'sql'), rasterWork]) + mkdirSync(directory, { recursive: true }); +// Upstream generators print $0 and input names in their output. Preserve their +// source-relative invocation paths rather than embedding a sandbox directory. +symlinkSync(join(source, 'utils'), join(work, 'utils')); +symlinkSync(join(source, 'spatial_ref_sys.sql'), join(work, 'spatial_ref_sys.sql')); +const recipes = { + 'postgis/Makefile.in': 'ac57d73d0905731ca270e6cbfc730292c40ffa059958ab334e476c3d7d526f24', + 'extensions/Makefile.in': 'f1d5c44837e1395181e8f21bfb14ac8a19faab2ea433fbea997b3a661bbbd6a5', + 'extensions/postgis/Makefile.in': + 'c127707c0d30ab2cf3a787ed6149703b722d86b143bd8bbb2618d4fb17f844f9', + 'extensions/upgrade-paths-rules.mk': + '6653c117a96c45c26cfd028c4e5bba3bf4a8dd4f7652b1a3f08d131575da88fa', + 'raster/rt_pg/Makefile.in': '21fc84b18248f4ee7d345541900aff4f59aa3832a2b048be6d46ad8c5b370a1d', +}; +for (const [path, digest] of Object.entries(recipes)) { + if ( + createHash('sha256') + .update(readFileSync(join(source, path))) + .digest('hex') !== digest + ) { + throw new Error(`review the upstream PostGIS SQL recipe before changing ${path}`); + } +} +if ( + !/^\d+\.\d+\.\d+$/.test(spec.version) || + !Number.isSafeInteger(spec.source_date_epoch) || + spec.postgres_version !== 180 +) { + throw new Error('unsupported PostGIS SQL source identity'); +} +function run(args: string[], stdin?: string, cwd = postgisWork): string { + const result = Bun.spawnSync([perl, ...options, ...args], { + cwd, + stdin: stdin === undefined ? 'ignore' : Buffer.from(stdin), + stdout: 'pipe', + stderr: 'pipe', + env: { + ...process.env, + SOURCE_DATE_EPOCH: String(spec.source_date_epoch), + LC_ALL: 'C', + TZ: 'UTC', + PERL5LIB: '', + PERL5OPT: '', + PERL_UNICODE: '', + }, + }); + if (result.exitCode !== 0) + throw new Error(`PostGIS upstream Perl failed: ${result.stderr.toString('utf8')}`); + return decoder.decode(result.stdout); +} +const transform = (program: string, text: string, lines = false) => + run([lines ? '-lpe' : '-pe', program], text); +const strip = (text: string) => transform('s/BEGIN\\;//g ; s/COMMIT\\;//g', text); +const upstream = (name: string, args: string[], stdin?: string, cwd = postgisWork) => + run([`${cwd === postgisWork ? '..' : '../..'}/utils/${name}.pl`, ...args], stdin, cwd); +const file = (name: string, text: string, cwd = postgisWork) => { + writeFileSync(join(cwd, name), text); + return name; +}; +function preprocessed(name: string, module: string, removeSchema: boolean): string { + const input = spec.preprocessed[`${name}.sql`]; + if (!input) throw new Error(`missing declared preprocessed SQL ${name}`); + const text = read(resolve(input)).replace(/^#.*\n?/gm, ''); + const replaced = transform(`s'MODULE_PATHNAME'${module}'g`, text, true); + return removeSchema ? transform("s'@extschema@\\.''g", replaced, true) : replaced; +} +try { + mkdirSync(extension, { recursive: true }); + mkdirSync(data, { recursive: true }); + const module = `$libdir/postgis-${spec.version.split('.')[0]}`; + const main = preprocessed('postgis', module, true); + file('postgis.sql', main); + writeFileSync(join(data, 'postgis.sql'), main); + for (const name of ['legacy', 'legacy_minimal', 'legacy_gist']) { + const text = preprocessed(name, module, true); + file(`${name}.sql`, text); + writeFileSync(join(data, `${name}.sql`), text); + } + for (const name of ['postgis', 'legacy']) { + const text = upstream('create_uninstall', [`${name}.sql`, String(spec.postgres_version)]); + writeFileSync(join(data, `uninstall_${name}.sql`), text); + if (name === 'postgis') writeFileSync(join(extension, 'uninstall_postgis.sql'), text); + } + copyFileSync(join(source, 'spatial_ref_sys.sql'), join(data, 'spatial_ref_sys.sql')); + const upgradeParts = (body: string) => + ['common_before_upgrade.sql', 'postgis_before_upgrade.sql'] + .map((name) => read(join(source, 'postgis', name))) + .join('') + + body + + ['postgis_after_upgrade.sql', 'common_after_upgrade.sql'] + .map((name) => read(join(source, 'postgis', name))) + .join(''); + writeFileSync( + join(data, 'postgis_upgrade.sql'), + `BEGIN;\n${upgradeParts(upstream('create_upgrade', ['postgis.sql']))}COMMIT;\n`, + ); + const forExtension = strip(preprocessed('postgis', module, false)); + file('sql/postgis_for_extension.sql', forExtension, extensionWork); + const spatial = strip(read(join(source, 'spatial_ref_sys.sql'))); + const dump = upstream( + 'create_spatial_ref_sys_config_dump', + ['../../spatial_ref_sys.sql'], + undefined, + extensionWork, + ); + const guard = '\\echo Use "CREATE EXTENSION postgis" to load this file. \\quit\n'; + const install = guard + forExtension + dump + spatial; + writeFileSync(join(extension, `postgis--${spec.version}.sql`), install); + const extensionUpgrade = strip( + upgradeParts( + upstream('create_upgrade', ['sql/postgis_for_extension.sql'], undefined, extensionWork), + ), + ); + const safeUpgrade = transform( + "s/^(DROP .*)\\;/SELECT \\@extschema\\@.postgis_extension_drop_if_exists('postgis', '\\1');\\n\\1\\;/", + extensionUpgrade, + true, + ); + const rasterModule = `$libdir/rtpostgis-${spec.version.split('.')[0]}`; + const rasterMain = preprocessed('rtpostgis', rasterModule, true); + file('rtpostgis.sql', rasterMain, rasterWork); + const rasterDrops = + preprocessed('rtpostgis_upgrade_cleanup', rasterModule, true) + + preprocessed('rtpostgis_drop', rasterModule, true) + + upstream( + 'create_uninstall', + ['rtpostgis.sql', String(spec.postgres_version)], + undefined, + rasterWork, + ); + const unpackage = read(join(source, 'extensions/postgis/unpackage_raster_if_needed.sql')); + const markers = Array.from(unpackage.matchAll(/^.*UNPACKAGE_CODE.*\n/gm)); + if (markers.length !== 1) + throw new Error('unsupported upstream raster unpackage insertion recipe'); + const marker = markers[0].index + markers[0][0].length; + const rasterUnpackage = + unpackage.slice(0, marker) + + upstream('create_extension_unpackage', ['postgis'], rasterDrops, extensionWork) + + unpackage.slice(marker); + const anyUpgrade = + guard + + preprocessed('postgis_extension_helper', '', false) + + rasterUnpackage + + safeUpgrade + + spatial + + dump + + read(join(source, 'extensions/postgis_extension_helper_uninstall.sql')); + writeFileSync(join(extension, `postgis--ANY--${spec.version}.sql`), anyUpgrade); + writeFileSync( + join(extension, `postgis--unpackaged--${spec.version}.sql`), + upstream('create_unpackaged', ['postgis'], install, extensionWork) + anyUpgrade, + ); + writeFileSync(join(extension, 'postgis--unpackaged.sql'), '-- Nothing to do here\n'); + const date = new Date(spec.source_date_epoch * 1000).toISOString().slice(0, 19).replace('T', ' '); + const template = `-- Just tag extension postgis version as "ANY"\n-- Installed by postgis ${spec.version}\n-- Built on ${date}\n`; + writeFileSync(join(extension, 'postgis--TEMPLATED--TO--ANY.sql'), template); + writeFileSync(join(extension, `postgis--${spec.version}--ANY.sql`), template); +} finally { + rmSync(work, { recursive: true, force: true }); +} diff --git a/build_defs/extensions/postgis/sqlite.bzl b/build_defs/extensions/postgis/sqlite.bzl new file mode 100644 index 000000000..6167d36d4 --- /dev/null +++ b/build_defs/extensions/postgis/sqlite.bzl @@ -0,0 +1,105 @@ +"""Direct SQLite 3.53.1 construction from its canonical Git source. + +The source-built execution Jim/Lemon helpers run upstream Tcl generators; the +target library compiles the individual upstream non-amalgamation object recipe. +This private SQLite profile supports PROJ database construction and lookup. +""" + +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") +load("@rules_cc//cc/common:cc_common.bzl", "cc_common") +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") +load("@oliphaunt_metadata//:metadata.bzl", "EXTENSION_DEPENDENCIES") +load("//build_defs/extensions:platforms.bzl", "NATIVE_EXTENSION_COMPATIBLE") +load(":libraries.bzl", "POSTGIS_NATIVE_COPTS", "POSTGIS_THREAD_LINKOPTS", "postgis_profile", "postgis_source_headers") +load("//build_defs/foundation:bun.bzl", "BunScriptInfo", "bun_action") + +_CORE = "alter analyze attach auth backup bitvec btmutex btree build callback carray complete date dbpage dbstat delete expr fault fkey func global hash insert json legacy loadext main malloc mem0 mem1 mem2 mem3 mem5 memdb memjournal mutex mutex_noop mutex_unix mutex_w32 notify os os_kv os_unix os_win pager pcache pcache1 pragma prepare printf random resolve rowset select status table threads tokenize treeview trigger update upsert utf util vacuum vdbe vdbeapi vdbeaux vdbeblob vdbemem vdbesort vdbetrace vdbevtab vtab wal walker where wherecode whereexpr window".split(" ") +_FTS3 = "fts3 fts3_aux fts3_expr fts3_hash fts3_icu fts3_porter fts3_snippet fts3_tokenizer fts3_tokenizer1 fts3_tokenize_vtab fts3_unicode fts3_unicode2 fts3_write".split(" ") +_GENERATED = ["sqlite3.h", "parse.c", "parse.h", "keywordhash.h", "pragma.h", "ctime.c", "opcodes.h", "opcodes.c", "shell.c"] + +def _generate_impl(ctx): + outputs = [ctx.actions.declare_file(ctx.label.name + "/" + name) for name in _GENERATED] + args = ctx.actions.args() + args.add("--source", ctx.file.version.dirname) + args.add("--output", outputs[0].dirname) + for name in ["jim", "lemon", "mksourceid", "mkkeywordhash"]: + args.add("--" + name, getattr(ctx.executable, name)) + bun_action( + ctx, ctx.attr._generator, + inputs = ctx.files.inputs + [ctx.file.version], + tools = [getattr(ctx.attr, name)[DefaultInfo].files_to_run for name in ["jim", "lemon", "mksourceid", "mkkeywordhash"]], + outputs = outputs, + arguments = [args], + mnemonic = "SqliteUpstreamGenerators", + use_default_shell_env = True, + ) + headers = [file for file in outputs if file.basename.endswith(".h")] + return [DefaultInfo(files = depset(outputs)), + OutputGroupInfo(library_sources = depset([file for file in outputs if file.basename in ["parse.c", "ctime.c", "opcodes.c"]]), + headers = depset(headers), shell = depset([file for file in outputs if file.basename == "shell.c"])), + CcInfo(compilation_context = cc_common.create_compilation_context(headers = depset(headers), includes = depset([outputs[0].dirname])))] + +_sqlite_generate = rule( + implementation = _generate_impl, + attrs = { + "inputs": attr.label_list(allow_files = True), + "version": attr.label(allow_single_file = True, mandatory = True), + "jim": attr.label(executable = True, cfg = "exec", mandatory = True), + "lemon": attr.label(executable = True, cfg = "exec", mandatory = True), + "mksourceid": attr.label(executable = True, cfg = "exec", mandatory = True), + "mkkeywordhash": attr.label(executable = True, cfg = "exec", mandatory = True), + "_generator": attr.label(default = "//build_defs/extensions/postgis:sqlite_generate", providers = [BunScriptInfo], cfg = "exec"), + }, +) + +# The same upstream object/generator inventory also serves the WASI producer; +# its target feature profile is declared separately from this native library. +SQLITE_CORE_SOURCES = _CORE +SQLITE_FTS3_SOURCES = _FTS3 +sqlite_generate = _sqlite_generate + +def postgis_sqlite(name, profile = "desktop"): + settings = postgis_profile(profile) + if EXTENSION_DEPENDENCIES["postgis"]["sqlite"]["commit"] != "ccd445d76a9362c63add000354fac84ba9022176": + fail("review the upstream SQLite object/generator recipe before changing its canonical source pin") + prefix = "@postgis_sqlite//:" + for tool in (["jim", "lemon", "mksourceid", "mkkeywordhash"] if profile == "desktop" else []): + source = "autosetup/jimsh0.c" if tool == "jim" else "tool/" + tool + ".c" + cc_binary( + name = name + "_" + tool, + srcs = [prefix + source], + defines = select({"//build_defs/native:windows_x64": ["HAVE__FULLPATH"], "//conditions:default": ["HAVE_REALPATH"]}) if tool == "jim" else [], + copts = POSTGIS_NATIVE_COPTS, + linkopts = select({"//build_defs/native:windows_x64": [], "//build_defs/native:macos_arm64": [], "//conditions:default": ["-lm", "-ldl"]}) if tool == "jim" else [], + target_compatible_with = NATIVE_EXTENSION_COMPATIBLE, + ) + generated = ":" + name + "_generated" if profile == "desktop" else "//build_defs/extensions/postgis:sqlite_generated" + if profile == "desktop": + _sqlite_generate(name = name + "_generated", inputs = [prefix + "all_sources"], version = prefix + "VERSION", + jim = ":" + name + "_jim", lemon = ":" + name + "_lemon", + mksourceid = ":" + name + "_mksourceid", mkkeywordhash = ":" + name + "_mkkeywordhash") + native.filegroup(name = name + "_generated_sources", srcs = [generated], output_group = "library_sources") + if profile == "desktop": + native.filegroup(name = name + "_shell_source", srcs = [generated], output_group = "shell") + # main.mk T.cc.sqlite carries these upstream extension header roots. + postgis_source_headers(name = name + "_source_headers", root = prefix + "VERSION", + headers = [prefix + "headers", prefix + "ext/rtree/geopoly.c"], + include_dirs = ["src", "ext/rtree", "ext/icu", "ext/fts3", "ext/session"]) + cc_library( + name = name, + srcs = [prefix + "src/" + source + ".c" for source in _CORE] + + [prefix + "ext/fts3/" + source + ".c" for source in _FTS3] + + [prefix + path for path in ["ext/icu/icu.c", "ext/rtree/rtree.c", "ext/session/sqlite3session.c", "ext/rbu/sqlite3rbu.c", "ext/misc/stmt.c"]] + + [":" + name + "_generated_sources"], + hdrs = [prefix + "headers"], + deps = [generated, ":" + name + "_source_headers"], + local_defines = ["SQLITE_CORE"], + defines = ["SQLITE_THREADSAFE=1", "SQLITE_OMIT_LOAD_EXTENSION", "SQLITE_ENABLE_RTREE", "SQLITE_ENABLE_COLUMN_METADATA"] if profile == "desktop" else ["SQLITE_THREADSAFE=0", "SQLITE_OMIT_LOAD_EXTENSION"], + includes = [], + copts = settings.c, + linkopts = POSTGIS_THREAD_LINKOPTS if profile == "desktop" else [], + target_compatible_with = settings.compatible, + ) + if profile == "desktop": + cc_binary(name = name + "_cli", srcs = [":" + name + "_shell_source"], deps = [":" + name], + defines = ["SQLITE_OMIT_LOAD_EXTENSION"], target_compatible_with = NATIVE_EXTENSION_COMPATIBLE) diff --git a/build_defs/extensions/postgis/sqlite_generate.mts b/build_defs/extensions/postgis/sqlite_generate.mts new file mode 100644 index 000000000..1cfb0264c --- /dev/null +++ b/build_defs/extensions/postgis/sqlite_generate.mts @@ -0,0 +1,76 @@ +/** Invoke SQLite's pinned upstream generators using declared execution tools. */ +import { copyFileSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { basename, join, resolve } from 'node:path'; +import { parseArgs } from 'node:util'; + +const { values } = parseArgs({ + options: Object.fromEntries( + ['source', 'output', 'jim', 'lemon', 'mksourceid', 'mkkeywordhash'].map((name) => [ + name, + { type: 'string' }, + ]), + ), +}); +for (const name of ['source', 'output', 'jim', 'lemon', 'mksourceid', 'mkkeywordhash']) { + if (!values[name]) throw new Error(`missing --${name}`); +} +const source = resolve(values.source as string); +const output = resolve(values.output as string); +const tools = Object.fromEntries( + ['jim', 'lemon', 'mksourceid', 'mkkeywordhash'].map((name) => [ + name, + resolve(values[name] as string), + ]), +); +const work = mkdtempSync(join(process.env.TMPDIR ?? tmpdir(), 'sqlite-generators-')); +mkdirSync(output, { recursive: true }); + +function run(tool: string, args: string[], stdout?: string, stdin?: Uint8Array): void { + // Upstream Tcl also parses paths as list elements, which interpret backslashes. + if (process.platform === 'win32') args = args.map((argument) => argument.replaceAll('\\', '/')); + const result = Bun.spawnSync([tool, ...args], { + cwd: work, + env: { ...process.env, LC_ALL: 'C', TCLLIBPATH: '', TCL_LIBRARY: '', JIMLIB: '' }, + stdin: stdin ?? 'ignore', + stdout: 'pipe', + stderr: 'pipe', + }); + if (result.exitCode !== 0) { + throw new Error( + `${basename(tool)} ${args.join(' ')} failed (${result.exitCode}): ${result.stderr.toString('utf8')}`, + ); + } + if (stdout) writeFileSync(join(output, stdout), result.stdout); +} + +try { + // mksqlite3h.tcl executes this explicitly named helper from its working dir. + // All pinned source files are declared inputs because mksourceid verifies the + // Fossil manifest's individual source hashes when calculating SQLITE_SOURCE_ID. + copyFileSync( + tools.mksourceid, + join(work, /\.exe$/iu.test(tools.mksourceid) ? 'mksourceid.exe' : 'mksourceid'), + ); + run(tools.jim, [join(source, 'tool/mksqlite3h.tcl'), source, '-o', join(output, 'sqlite3.h')]); + copyFileSync(join(source, 'src/parse.y'), join(work, 'parse.y')); + run(tools.lemon, ['-S', `-T${join(source, 'tool/lempar.c')}`, 'parse.y']); + for (const name of ['parse.c', 'parse.h']) copyFileSync(join(work, name), join(output, name)); + run(tools.mkkeywordhash, [], 'keywordhash.h'); + run(tools.jim, [join(source, 'tool/mkpragmatab.tcl')]); + copyFileSync(join(work, 'pragma.h'), join(output, 'pragma.h')); + run(tools.jim, [join(source, 'tool/mkctimec.tcl'), join(output, 'ctime.c')]); + run( + tools.jim, + [join(source, 'tool/mkopcodeh.tcl')], + 'opcodes.h', + Buffer.concat([ + readFileSync(join(output, 'parse.h')), + readFileSync(join(source, 'src/vdbe.c')), + ]), + ); + run(tools.jim, [join(source, 'tool/mkopcodec.tcl'), join(output, 'opcodes.h')], 'opcodes.c'); + run(tools.jim, [join(source, 'tool/mkshellc.tcl'), join(output, 'shell.c')]); +} finally { + rmSync(work, { recursive: true, force: true }); +} diff --git a/build_defs/extensions/postgis/windows_sources.test.mts b/build_defs/extensions/postgis/windows_sources.test.mts new file mode 100644 index 000000000..ef98426a0 --- /dev/null +++ b/build_defs/extensions/postgis/windows_sources.test.mts @@ -0,0 +1,310 @@ +/** Independent byte oracle for the pre-existing PostGIS MSVC source rewrites. */ +import assert from 'node:assert/strict'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { prepareWindowsSources, type WindowsSourceInputs } from '../windows_source_inputs.mts'; + +const utf8 = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }); +const read = (file: string) => utf8.decode(readFileSync(file)); +const companions = ['oliphaunt_flatgeobuf_windows_compat.h', 'oliphaunt_postgis_windows_compat.h']; + +// Captured from windows-extension-sources.mts before 3b7718a9. Do not call the +// shared transform to compute expected bytes: this checks its extraction. +function oldPostgisSource(file: string, text: string): string { + if (/^(postgis|libpgcommon|liblwgeom)\/.*\.[ch]$/u.test(file)) + text = text.replace( + /^[ \t]*(?!(?:extern\s+)?PGDLLEXPORT\s+)(?:extern\s+)?Datum\s+(\w+)\s*\(PG_FUNCTION_ARGS\);\r?$/gm, + 'extern PGDLLEXPORT Datum $1(PG_FUNCTION_ARGS);', + ); + if (file === 'postgis/postgis_legacy.c') { + const macro = /^([ \t]*)Datum[ \t]+funcname[ \t]*\(PG_FUNCTION_ARGS\);[ \t]*\\\r?$/gm; + assert.equal([...text.matchAll(macro)].length, 1, 'pinned funcname macro anchor'); + text = text.replace(macro, '$1extern PGDLLEXPORT Datum funcname(PG_FUNCTION_ARGS); \\'); + } + if (file === 'deps/flatgeobuf/geometryreader.cpp') { + const replacements = [ + ['pt = (POINT4D) { x, y, z, m };', 'pt.x = x;\npt.y = y;\npt.z = z;\npt.m = m;'], + ['pt = (POINT4D) { xv, yv, zv, mv };', 'pt.x = xv;\npt.y = yv;\npt.z = zv;\npt.m = mv;'], + ]; + for (const [before, after] of replacements) { + assert.equal(text.split(before).length - 1, 1, `pinned POINT4D anchor: ${before}`); + text = text.replace(before, after); + } + } + return text; +} + +// Independent literal oracle for every external-inline definition in the pin. +// Keep the historical source rewrites above intact; production has no name list. +const externalInlineSignatures: Record = { + 'postgis/gserialized_gist_2d.c': [ + 'bool box2df_is_empty(', + 'void box2df_set_empty(', + 'void box2df_set_finite(', + 'void box2df_validate(', + ], + 'postgis/gserialized_gist_nd.c': ['bool\ngidx_is_unknown('], + 'liblwgeom/lwgeom_api.c': ['float\nnext_float_down(', 'float\nnext_float_up('], + 'liblwgeom/lwlinearreferencing.c': [ + 'double\nlwpoint_get_ordinate(', + 'void\nlwpoint_set_ordinate(', + 'int\npoint_interpolate(', + ], + 'liblwgeom/measures.c': ['double\ndistance2d_pt_pt('], + 'postgis/unit.c': ['int external_body(', 'int extern_body('], +}; + +function expectedPostgisSource(file: string, original: string): string { + let text = oldPostgisSource(file, original); + for (const signature of externalInlineSignatures[file] ?? []) { + const before = `inline ${signature}`; + assert.equal( + text.split(before).length - 1, + 1, + `pinned external inline anchor: ${file} ${signature}`, + ); + text = text.replace(before, signature); + } + return text; +} + +function verifySources( + spec: WindowsSourceInputs, + expected: { name: string; source: string }[], + outputs: string[], + declared: (file: string) => string, +): number { + assert.equal(spec.extension, 'postgis'); + assert.deepEqual(spec.headers, [], 'PostGIS companions are copied inputs'); + const names = spec.files.map((row) => row.name); + assert.equal(new Set(names).size, names.length, 'unique prepared source names'); + assert.deepEqual( + [...names].sort(), + expected.map((row) => row.name).sort(), + 'exact source roster', + ); + assert.deepEqual( + spec.files.map((row) => row.output).sort(), + [...outputs].sort(), + 'exact output roster', + ); + assert.equal(new Set(outputs).size, outputs.length, 'unique prepared output paths'); + assert.deepEqual(names.filter((name) => companions.includes(name)).sort(), companions); + assert(names.includes('postgis/postgis_legacy.c')); + assert(names.includes('deps/flatgeobuf/geometryreader.cpp')); + const inputs = new Map(expected.map((row) => [row.name, row.source])); + const roots = new Set(); + let changed = 0; + for (const row of spec.files) { + assert( + !row.name.includes('\\') && + row.name.split('/').every((part) => part && part !== '.' && part !== '..'), + ); + assert.equal(row.source, inputs.get(row.name), `declared original for ${row.name}`); + assert(row.output.endsWith('/' + row.name), `prepared filename for ${row.name}`); + roots.add(row.output.slice(0, -row.name.length)); + const original = read(declared(row.source)); + const after = expectedPostgisSource(row.name, original); + assert.deepEqual( + readFileSync(declared(row.output)), + Buffer.from(after), + `source bytes: ${row.name}`, + ); + if (companions.includes(row.name)) + assert.deepEqual( + readFileSync(declared(row.output)), + readFileSync(declared(row.source)), + `unchanged companion: ${row.name}`, + ); + if (after !== original) changed++; + } + assert.equal(roots.size, 1, 'one prepared source root'); + assert(changed > 0, 'actual pinned source adaptations were exercised'); + return changed; +} + +interface SourceTestInventory { + schema: string; + source: Record; + pin: string; + anchor: string; + spec: string; + expected: { name: string; source: string }[]; + outputs: string[]; + runfiles: Record; +} + +function verifyInventory(inventory: SourceTestInventory, runfiles: string): number { + assert.equal(inventory.schema, 'oliphaunt-postgis-windows-source-test-v1'); + const declared = (file: string): string => { + const relative = inventory.runfiles[file]; + assert( + relative && !path.isAbsolute(relative) && !relative.includes('\\'), + `undeclared or unsafe runfile: ${file}`, + ); + assert(relative.split('/').every((part) => part && part !== '.' && part !== '..')); + return path.join(runfiles, relative); + }; + const pin = Bun.TOML.parse(read(declared(inventory.pin))) as Record; + assert.deepEqual( + Object.fromEntries(Object.keys(inventory.source).map((key) => [key, pin[key]])), + inventory.source, + 'canonical declared PostGIS source pin', + ); + assert(/^[0-9a-f]{40}$/u.test(inventory.source.commit)); + assert.equal(inventory.source.name, 'postgis'); + const version = Object.fromEntries( + [...read(declared(inventory.anchor)).matchAll(/^(POSTGIS_\w+_VERSION)=(.*)$/gm)].map( + (match) => [match[1], match[2]], + ), + ); + assert.equal( + ['MAJOR', 'MINOR', 'MICRO'].map((part) => version[`POSTGIS_${part}_VERSION`]).join('.'), + inventory.source['extension-control']['default-version'], + 'pinned source Version.config', + ); + return verifySources( + JSON.parse(read(declared(inventory.spec))), + inventory.expected, + inventory.outputs, + declared, + ); +} + +function fixtureTests(): void { + const root = mkdtempSync(path.join(tmpdir(), 'postgis-windows-source-test-')); + try { + const fixture: Record = { + 'postgis/unit.c': + '/* π */\r\n Datum one(PG_FUNCTION_ARGS);\r\nextern PGDLLEXPORT Datum done(PG_FUNCTION_ARGS);\r\nextern Datum unrelated(void);\r\ninline int external_body(void) { return 1; }\r\nextern inline int extern_body(void) { return 2; }\r\nstatic inline int local_body(void) { return 3; }\r\ninline static int reverse_body(void) { return 4; }\r\n', + 'libpgcommon/unit.h': 'extern Datum two(PG_FUNCTION_ARGS);\n', + 'liblwgeom/nested/unit.h': 'Datum three(PG_FUNCTION_ARGS);\n', + 'postgis/postgis_legacy.c': '\tDatum funcname(PG_FUNCTION_ARGS); \\\r\n', + 'deps/flatgeobuf/geometryreader.cpp': + 'pt = (POINT4D) { x, y, z, m };\npt = (POINT4D) { xv, yv, zv, mv };\n', + 'deps/unrelated.h': 'Datum unchanged(PG_FUNCTION_ARGS);\r\n', + 'oliphaunt_flatgeobuf_windows_compat.h': '/* exact flatgeobuf companion bytes λ */\r\n', + 'oliphaunt_postgis_windows_compat.h': '/* exact PostGIS companion bytes λ */\r\n', + }; + const spec: WindowsSourceInputs = { extension: 'postgis', files: [], headers: [] }; + for (const [name, text] of Object.entries(fixture)) { + const source = path.join(root, 'original', name); + mkdirSync(path.dirname(source), { recursive: true }); + writeFileSync(source, text); + spec.files.push({ + name, + source, + output: path.join(root, 'prepared', name).replaceAll('\\', '/'), + }); + } + prepareWindowsSources(spec); + const expected = spec.files.map(({ name, source }) => ({ name, source })); + const outputs = spec.files.map(({ output }) => output); + assert.equal( + verifySources(spec, expected, outputs, (file) => file), + 5, + ); + assert.throws( + () => + verifySources({ ...spec, files: spec.files.slice(1) }, expected, outputs, (file) => file), + /source roster/u, + ); + assert.throws( + () => + verifySources( + { ...spec, files: [...spec.files, spec.files[0]] }, + expected, + outputs, + (file) => file, + ), + /unique prepared/u, + ); + assert.throws( + () => verifySources(spec, expected, outputs.slice(1), (file) => file), + /output roster/u, + ); + const wrongSource = structuredClone(spec); + wrongSource.files[0].source = spec.files[1].source; + assert.throws( + () => verifySources(wrongSource, expected, outputs, (file) => file), + /declared original/u, + ); + writeFileSync(spec.files[0].output, 'incorrect transformation'); + assert.throws(() => verifySources(spec, expected, outputs, (file) => file), /source bytes/u); + prepareWindowsSources(spec); + const copiedHeader = spec.files.find((row) => companions.includes(row.name))!; + writeFileSync(copiedHeader.output, 'changed compatibility header'); + assert.throws(() => verifySources(spec, expected, outputs, (file) => file), /source bytes/u); + prepareWindowsSources(spec); + // This identity belongs only to the temporary fixture. Actual source proof + // receives its identity from canonical metadata and declared source.toml. + const pin = path.join(root, 'source.toml'); + const anchor = path.join(root, 'Version.config'); + const specFile = path.join(root, 'inputs.json'); + const source = { + name: 'postgis', + commit: '1'.repeat(40), + 'extension-control': { 'default-version': '1.2.3' }, + }; + writeFileSync( + pin, + `name = "postgis"\ncommit = "${source.commit}"\n[extension-control]\ndefault-version = "1.2.3"\n`, + ); + writeFileSync( + anchor, + 'POSTGIS_MAJOR_VERSION=1\nPOSTGIS_MINOR_VERSION=2\nPOSTGIS_MICRO_VERSION=3\n', + ); + writeFileSync(specFile, JSON.stringify(spec)); + const inventory: SourceTestInventory = { + schema: 'oliphaunt-postgis-windows-source-test-v1', + source, + pin, + anchor, + spec: specFile, + expected, + outputs, + runfiles: Object.fromEntries( + [pin, anchor, specFile, ...expected.map((row) => row.source), ...outputs].map((file) => [ + file, + path.relative(root, file).replaceAll('\\', '/'), + ]), + ), + }; + assert.equal(verifyInventory(inventory, root), 5); + assert.throws( + () => verifyInventory({ ...inventory, source: { ...source, commit: '2'.repeat(40) } }, root), + /source pin/u, + ); + writeFileSync( + anchor, + 'POSTGIS_MAJOR_VERSION=9\nPOSTGIS_MINOR_VERSION=2\nPOSTGIS_MICRO_VERSION=3\n', + ); + assert.throws(() => verifyInventory(inventory, root), /Version.config/u); + assert.throws(() => verifyInventory({ ...inventory, runfiles: {} }, root), /undeclared/u); + for (const invalid of ['', fixture['postgis/postgis_legacy.c'].repeat(2)]) + assert.throws(() => oldPostgisSource('postgis/postgis_legacy.c', invalid), /funcname/u); + for (const invalid of ['', fixture['deps/flatgeobuf/geometryreader.cpp'].repeat(2)]) + assert.throws( + () => oldPostgisSource('deps/flatgeobuf/geometryreader.cpp', invalid), + /POINT4D/u, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +fixtureTests(); +const [inventory, runfiles, ...extra] = process.argv.slice(2); +assert( + !extra.length && Boolean(inventory) === Boolean(runfiles), + 'expected optional inventory JSON and runfiles root', +); +if (inventory) { + const changed = verifyInventory(JSON.parse(read(inventory)), runfiles); + console.log( + `Declared PostGIS Windows source bytes match the reviewed adaptations (${changed} changed files).`, + ); +} else { + console.log('PostGIS Windows source oracle fixtures and rejection checks passed.'); +} diff --git a/build_defs/extensions/postgis/windows_sources_test.bzl b/build_defs/extensions/postgis/windows_sources_test.bzl new file mode 100644 index 000000000..deffca666 --- /dev/null +++ b/build_defs/extensions/postgis/windows_sources_test.bzl @@ -0,0 +1,72 @@ +"""Byte proof for declared PostGIS Windows source preparation, without C tools.""" + +load("@oliphaunt_metadata//:metadata.bzl", "EXTENSION_SOURCES") +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/native:platform_config.bzl", "NATIVE_WINDOWS_COMPATIBLE") + +def _runfile(ctx, file): + return file.short_path[3:] if file.short_path.startswith("../") else ctx.workspace_name + "/" + file.short_path + +def _impl(ctx): + prepared = ctx.attr.prepared + specs = prepared[OutputGroupInfo].source_spec.to_list() + if len(specs) != 1: + fail("PostGIS Windows source proof requires one declared source spec") + anchor = ctx.file.anchor + if not anchor.path.endswith(ctx.attr.anchor_name): + fail("PostGIS Windows source anchor differs from the pinned source root") + root = anchor.path[:-len(ctx.attr.anchor_name)] + inputs, expected, seen = [], [], {} + for file in ctx.files.srcs + ctx.files.hdrs: + if file.path in seen: + continue + seen[file.path] = True + if file.is_directory or not file.path.startswith(root): + fail("PostGIS Windows source proof requires declared pinned regular inputs") + expected.append({"name": file.path[len(root):], "source": file.path}) + inputs.append(file) + for target, name in ctx.attr.companions.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1 or files[0].is_directory: + fail("PostGIS Windows companion proof requires one declared regular input") + expected.append({"name": name, "source": files[0].path}) + inputs.append(files[0]) + outputs = prepared[DefaultInfo].files.to_list() + prepared[CcInfo].compilation_context.headers.to_list() + files = {file.path: file for file in inputs + outputs + specs + [anchor, ctx.file._pin]} + source = EXTENSION_SOURCES["postgis"] + inventory = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(inventory, json.encode({ + "schema": "oliphaunt-postgis-windows-source-test-v1", + "source": {key: source[key] for key in ["name", "url", "branch", "commit", "source_date_epoch", "extension-control"]}, + "pin": ctx.file._pin.path, "anchor": anchor.path, "spec": specs[0].path, + "expected": expected, + "outputs": sorted({file.path: True for file in outputs}.keys()), + "runfiles": {key: _runfile(ctx, file) for key, file in files.items()}, + })) + sources = [ctx.file._runner] + ctx.files._helpers + return bun_test_entrypoint(ctx, ctx.file._runner, [inventory], files.values() + [inventory] + sources, + source_files = sources, runfiles_argument = True) + +_test = rule( + implementation = _impl, + test = True, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "prepared": attr.label(mandatory = True, providers = [CcInfo]), + "srcs": attr.label_list(mandatory = True, allow_files = True), + "hdrs": attr.label_list(allow_files = True), + "anchor": attr.label(mandatory = True, allow_single_file = True), + "anchor_name": attr.string(mandatory = True), + "companions": attr.label_keyed_string_dict(allow_files = True), + "_pin": attr.label(default = "//src/extensions/external/postgis:source.toml", allow_single_file = True), + "_runner": attr.label(default = "//build_defs/extensions/postgis:windows_sources.test.mts", allow_single_file = True), + "_helpers": attr.label_list(default = ["//build_defs/extensions:windows_source_inputs.mts", "//build_defs/extensions:windows_source_portability.mts"], allow_files = True), + }), +) + +def postgis_windows_sources_test(name, prepared, srcs, hdrs, anchor, anchor_name, companions): + """Check the actual source action on the native Bun execution host.""" + _test(name = name, prepared = prepared, srcs = srcs, hdrs = hdrs, anchor = anchor, + anchor_name = anchor_name, companions = companions, + args = bun_test_entrypoint_args(name), size = "small", target_compatible_with = NATIVE_WINDOWS_COMPATIBLE) diff --git a/build_defs/extensions/repositories.bzl b/build_defs/extensions/repositories.bzl new file mode 100644 index 000000000..469c8128d --- /dev/null +++ b/build_defs/extensions/repositories.bzl @@ -0,0 +1,103 @@ +"""Import immutable external extension sources from the canonical metadata.""" + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +load("@oliphaunt_metadata//:extension-sources.bzl", "EXTENSION_DEPENDENCIES", "EXTENSION_SOURCES") +load("//build_defs/native:repositories.bzl", "source_string_values") + +_BUILD = """ +package(default_visibility = ["//visibility:public"]) +exports_files(glob(["**"], exclude = ["BUILD", "BUILD.bazel", "WORKSPACE", "WORKSPACE.bazel", "MODULE.bazel"], allow_empty = True)) +filegroup( + name = "sql_inputs", + srcs = glob(["*.control", "sql/*.sql", "sql/*.sql.in", "compat/install-*.patch", "compat/gencore", "Makefile"], allow_empty = True), +) +filegroup(name = "headers", srcs = glob(["src/**/*.h"], allow_empty = True)) +filegroup(name = "sql_resources", srcs = glob(["*.control", "*--*.sql", "sql/*--*.sql"], allow_empty = True)) +filegroup(name = "sql_upgrade_resources", srcs = glob(["*--*--*.sql", "sql/*--*--*.sql"], allow_empty = True)) +filegroup(name = "test_inputs", srcs = glob(["Makefile", "test/sql/*.sql", "test/expected/*.out", "test/scripts/gen*_bm25vector.py"], allow_empty = True)) +""" + +_DEPENDENCY_BUILD = """ +package(default_visibility = ["//visibility:public"]) +exports_files(glob(["**"], exclude = ["BUILD", "BUILD.bazel", "WORKSPACE", "WORKSPACE.bazel", "MODULE.bazel"], allow_empty = True)) +filegroup(name = "all_sources", srcs = glob(["**"], exclude = ["BUILD", "BUILD.bazel", "WORKSPACE", "WORKSPACE.bazel", "MODULE.bazel"], allow_empty = True)) +filegroup(name = "headers", srcs = glob(["**/*.h", "**/*.hpp", "**/*.inl", "**/*.inc"], allow_empty = True)) +""" + +_DEPENDENCY_INPUTS = { + "geos": '\nfilegroup(name = "native_sources", srcs = glob(["src/**/*.cpp", "capi/*.cpp"]))\nfilegroup(name = "native_c_sources", srcs = glob(["src/deps/**/*.c"]))\nfilegroup(name = "native_core_sources", srcs = glob(["src/**/*.cpp"]))\nfilegroup(name = "native_capi_sources", srcs = glob(["capi/*.cpp"]))\n', + "proj": '\nfilegroup(name = "native_sources", srcs = glob(["src/*.cpp", "src/projections/*.cpp", "src/conversions/*.cpp", "src/transformations/*.cpp", "src/iso19111/**/*.cpp"]))\nfilegroup(name = "native_c_sources", srcs = glob(["src/*.c"], exclude = ["src/embedded_resources.c", "src/memvfs.c"]))\n', +} + +_POSTGIS_INPUTS = """ +filegroup(name = "postgis_headers", srcs = glob(["**/*.h", "**/*.hpp", "**/*.inl", "**/*.inc"], allow_empty = True)) +filegroup(name = "postgis_sql_inputs", srcs = glob(["Version.config", "postgis/*.sql.in", "postgis/*.sql.in.*", "postgis/*.sql", "postgis/*.h", "libpgcommon/*.h", "extensions/**/*.sql", "extensions/**/*.sql.in", "extensions/**/Makefile.in", "extensions/upgrade-paths-rules.mk", "utils/*.pl", "raster/rt_pg/*.sql.in", "raster/rt_pg/*.sql.in.*", "raster/rt_pg/*.sql", "postgis/Makefile.in", "raster/rt_pg/Makefile.in"], allow_empty = True)) +""" + +def _git_source_archive(name, source, build_file_content): + archive = source["archive"] + http_archive( + name = name, + urls = [archive["url"]], + sha256 = archive["sha256"], + strip_prefix = archive["strip_prefix"], + type = "tar.gz", + build_file_content = build_file_content, + ) + +def _extension_sources_impl(module_ctx): + for sql_name, source in EXTENSION_SOURCES.items(): + _git_source_archive( + name = source["name"], + source = source, + build_file_content = _BUILD + (_POSTGIS_INPUTS if sql_name == "postgis" else ""), + ) + for sql_name, dependencies in EXTENSION_DEPENDENCIES.items(): + for directory, source in dependencies.items(): + name = sql_name.replace("-", "_") + "_" + directory.replace("-", "_") + kind = source.get("kind", "git") + if kind == "git": + _git_source_archive( + name = name, + source = source, + build_file_content = _DEPENDENCY_BUILD + _DEPENDENCY_INPUTS.get(directory, ""), + ) + elif kind == "archive": + digest = source.get("sha256", "") + if len(digest) != 64 or any([character not in "0123456789abcdef" for character in digest.elems()]): + fail("dependency %s/%s requires an immutable archive SHA256" % (sql_name, directory)) + http_archive( + name = name, + urls = [source["url"]] + ([source["mirror_url"]] if source.get("mirror_url") else []), + sha256 = digest, + strip_prefix = source["strip_prefix"], + build_file_content = _DEPENDENCY_BUILD + _DEPENDENCY_INPUTS.get(directory, ""), + ) + else: + fail("unsupported dependency source kind %s for %s/%s" % (kind, sql_name, directory)) + +extension_sources = module_extension(implementation = _extension_sources_impl) + +def _extension_test_source_impl(ctx): + source = source_string_values(ctx.read(ctx.attr.source_manifest)) + commit = source.get("commit", "") + digest = source.get("sha256", "") + remote = source.get("url", "") + parts = (remote[:-4] if remote.endswith(".git") else remote).split("/") + if len(commit) != 40 or len(digest) != 64 or any([character not in "0123456789abcdef" for character in (commit + digest).elems()]): + fail("extension test source requires exact commit and archive SHA256") + if len(parts) != 5 or parts[:3] != ["https:", "", "github.com"] or any([not part or part in [".", ".."] for part in parts[3:]]): + fail("extension test source requires its declared canonical GitHub origin") + ctx.download_and_extract( + url = "https://codeload.github.com/%s/%s/tar.gz/%s" % (parts[3], parts[4], commit), + sha256 = digest, + stripPrefix = parts[4] + "-" + commit, + type = "tar.gz", + ) + ctx.file("BUILD.bazel", _BUILD.replace("package(default_visibility", "package(default_testonly = True, default_visibility"), executable = False) + +# An old upgrade input is source-only test material, never another release product. +extension_test_source = repository_rule( + implementation = _extension_test_source_impl, + attrs = {"source_manifest": attr.label(mandatory = True, allow_single_file = True)}, +) diff --git a/build_defs/extensions/sdk_projections.bzl b/build_defs/extensions/sdk_projections.bzl new file mode 100644 index 000000000..254a473bf --- /dev/null +++ b/build_defs/extensions/sdk_projections.bzl @@ -0,0 +1,75 @@ +"""SDK metadata generation from the canonical, explicitly imported inputs.""" + +load("@oliphaunt_metadata//:metadata.bzl", "CONTRIB_MEMBERS", "EXTENSIONS", "EXTENSION_PROFILES", "EXTENSION_RECIPES", "EXTENSION_RELEASE_METADATA") +load("//build_defs/foundation:bun.bzl", "BunScriptInfo", "bun_action") + +def _spec(ctx): + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode({ + "schema": "oliphaunt-native-sdk-extension-projections-v1", + "catalog": {"extensions": EXTENSIONS.values()}, + "releases": EXTENSION_RELEASE_METADATA, + "contrib": CONTRIB_MEMBERS, + "profiles": EXTENSION_PROFILES, + "recipes": EXTENSION_RECIPES, + })) + return spec + +def _sdk_extension_projections_impl(ctx): + spec = _spec(ctx) + args = ctx.actions.args() + args.add("--spec", spec) + args.add("--components", ctx.file._components) + args.add("--sdk", ctx.attr.sdk) + args.add("--generated", ctx.outputs.generated) + args.add("--descriptors", ctx.outputs.descriptors) + bun_action( + ctx, ctx.attr._generator, + arguments = [args], + inputs = depset([spec, ctx.file._components]), + outputs = [ctx.outputs.generated, ctx.outputs.descriptors], + mnemonic = "NativeSdkExtensionProjections", + progress_message = "Generate %s SDK extension metadata from declared canonical inputs" % ctx.attr.sdk, + ) + return [ + DefaultInfo(files = depset([ctx.outputs.generated, ctx.outputs.descriptors])), + OutputGroupInfo(generated = depset([ctx.outputs.generated]), descriptors = depset([ctx.outputs.descriptors])), + ] + +_sdk_extension_projections = rule( + implementation = _sdk_extension_projections_impl, + attrs = { + "sdk": attr.string(mandatory = True, values = ["ts", "react-native", "kotlin"]), + "generated": attr.output(mandatory = True), + "descriptors": attr.output(mandatory = True), + "_components": attr.label(default = "//src/extensions/catalog:native-components.toml", allow_single_file = True), + "_generator": attr.label(default = "//build_defs/extensions:sdk_projections", providers = [BunScriptInfo], cfg = "exec"), + }, +) + +def sdk_extension_projections(name, sdk = "ts", generated = "src/generated/extensions.ts", descriptors = "src/extensions.ts"): + _sdk_extension_projections(name = name, sdk = sdk, generated = generated, descriptors = descriptors) + +def _metadata_impl(ctx): + spec = _spec(ctx) + args = ctx.actions.args() + args.add("--spec", spec) + args.add("--components", ctx.file._components) + args.add("--metadata", ctx.outputs.out) + bun_action( + ctx, ctx.attr._generator, + arguments = [args], + inputs = depset([spec, ctx.file._components]), + outputs = [ctx.outputs.out], + mnemonic = "NativeSdkExtensionMetadata", + ) + return [DefaultInfo(files = depset([ctx.outputs.out]))] + +sdk_extension_metadata = rule( + implementation = _metadata_impl, + attrs = { + "out": attr.output(mandatory = True), + "_components": attr.label(default = "//src/extensions/catalog:native-components.toml", allow_single_file = True), + "_generator": attr.label(default = "//build_defs/extensions:sdk_projections", providers = [BunScriptInfo], cfg = "exec"), + }, +) diff --git a/build_defs/extensions/sdk_projections.mts b/build_defs/extensions/sdk_projections.mts new file mode 100644 index 000000000..342afe898 --- /dev/null +++ b/build_defs/extensions/sdk_projections.mts @@ -0,0 +1,74 @@ +import assert from 'node:assert/strict'; +import { readFileSync, writeFileSync } from 'node:fs'; +import { parseArgs } from 'node:util'; +import { extensionProjections } from '../../src/extensions/tools/extension-projections.mts'; +import { + nativeComponentInventory, + validateNativeComponentContract, +} from '../../src/extensions/tools/native-component-contract.mts'; + +const { values } = parseArgs({ + args: Bun.argv.slice(2), + options: { + spec: { type: 'string' }, + components: { type: 'string' }, + sdk: { type: 'string' }, + generated: { type: 'string' }, + descriptors: { type: 'string' }, + metadata: { type: 'string' }, + }, + strict: true, +}); +assert(values.spec && values.components); +if (!values.metadata) { + assert(values.generated && values.descriptors); + assert( + values.sdk === 'ts' || values.sdk === 'react-native' || values.sdk === 'kotlin', + 'unsupported native SDK projection', + ); +} +const spec = JSON.parse(readFileSync(values.spec, 'utf8')); +assert.equal(spec.schema, 'oliphaunt-native-sdk-extension-projections-v1'); +const profiles = new Map(); +for (const profile of spec.profiles.profiles) + for (const row of profile.targets) { + assert(!profiles.has(row.target), `duplicate target profile ${row.target}`); + profiles.set(row.target, `${row.family}\0${row.kind}`); + } +const contract = validateNativeComponentContract( + Bun.TOML.parse(readFileSync(values.components, 'utf8')), + { + targetProfiles: profiles, + knownExtensions: new Set(spec.catalog.extensions.map((row: any) => row['sql-name'])), + checkSourcePaths: false, + }, +); +const outputs = extensionProjections(spec.catalog, spec.releases, { + context: { + inventory: nativeComponentInventory(contract), + contrib: spec.contrib, + recipes: new Map(Object.entries(spec.recipes)), + }, + sdkOnly: values.sdk as 'ts' | 'react-native' | 'kotlin' | undefined, + metadataOnly: Boolean(values.metadata), +}); +if (values.metadata) { + const metadata = outputs.get('src/extensions/generated/sdk/extensions.json'); + assert(metadata, 'SDK projection renderer omitted metadata'); + writeFileSync(values.metadata, metadata); + process.exit(0); +} +const base = + values.sdk === 'kotlin' + ? 'src/native/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt' + : `src/native/sdks/${values.sdk}/src`; +const generated = outputs.get( + `${base}/${values.sdk === 'kotlin' ? 'GeneratedExtensions.kt' : 'generated/extensions.ts'}`, +); +const descriptors = outputs.get( + `${base}/${values.sdk === 'kotlin' ? 'OliphauntExtension.kt' : 'extensions.ts'}`, +); +assert(generated && descriptors, 'SDK projection renderer omitted a required output'); +assert(values.generated && values.descriptors); +writeFileSync(values.generated, generated); +writeFileSync(values.descriptors, descriptors); diff --git a/build_defs/extensions/smoke.bzl b/build_defs/extensions/smoke.bzl new file mode 100644 index 000000000..511b00ee3 --- /dev/null +++ b/build_defs/extensions/smoke.bzl @@ -0,0 +1,151 @@ +"""SQL proof from selected candidate payloads and canonical lifecycle fixtures.""" + +load("@oliphaunt_metadata//:metadata.bzl", "EXTENSIONS", "EXTENSION_COMPATIBILITY", "EXTENSION_RECIPES", "PRODUCTS") +load("@rules_shell//shell:sh_test.bzl", "sh_test") +load("//build_defs/extensions:platforms.bzl", NATIVE_EXTENSION_COMPATIBLE = "NATIVE_EXTENSION_LINUX_COMPATIBLE", _desktop_compatible = "NATIVE_EXTENSION_COMPATIBLE") +load(":extensions.bzl", "ExtensionMemberInfo", "extension_default_version", "extension_native_dependency_modules") +load(":construction.bzl", "desktop_member_payloads") +load("//build_defs/foundation:bun.bzl", "BunScriptInfo", "bun_action", "bun_script_test") + +def _smoke_plan_impl(ctx): + fixtures = {file.basename[:-4]: file for file in ctx.files.fixtures} + members = [] + selected = {} + for target in ctx.attr.members: + member = target[ExtensionMemberInfo] + name = member.sql_name + if name in selected: + fail("candidate smoke plan repeats %s" % name) + selected[name] = True + if name not in fixtures: + fail("candidate smoke plan lacks an independent SQL fixture for %s" % name) + matches = [row for row in EXTENSIONS.values() if row["sql-name"] == name] + if len(matches) != 1: + fail("candidate smoke plan lacks canonical descriptor for %s" % name) + descriptor = matches[0] + if ctx.attr.host_version: + contrib = descriptor["source-kind"] == "postgres-contrib" + requirement = PRODUCTS[member.owner]["version"] if contrib else EXTENSION_COMPATIBILITY[name]["native_runtime_version"] + product = member.owner if contrib else EXTENSION_COMPATIBILITY[name]["native_runtime_product"] + if product != ctx.attr.host_product: + fail("%s declares native host product %s, not supplied immutable host %s" % (name, product, ctx.attr.host_product)) + if requirement != ctx.attr.host_version: + fail("%s declares native host %s, not supplied immutable host %s" % (name, requirement, ctx.attr.host_version)) + members.append({ + "sql_name": name, + "default_version": extension_default_version(name), + "dependencies": descriptor.get("dependencies", []), + "lifecycle": descriptor["lifecycle"], + "fixture": fixtures[name].path, + "runtime_environment": EXTENSION_RECIPES.get(name, {}).get("runtime_environment", []), + "dependency_modules": ["lib/postgresql/" + basename for basename in extension_native_dependency_modules(EXTENSION_RECIPES.get(name, {}).get("artifacts", {}).get("native_dependency_modules", []), member.configuration, EXTENSION_RECIPES.get(name, {}).get("artifacts", {}).get("native_dependency_modules_by_target", {}))], + }) + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode({"schema": "oliphaunt-native-extension-smoke-plan-v1", "members": members})) + install = ctx.actions.declare_file(ctx.label.name + ".install.sql") + smoke = ctx.actions.declare_file(ctx.label.name + ".smoke.sql") + startup = ctx.actions.declare_file(ctx.label.name + ".startup.txt") + environment = ctx.actions.declare_file(ctx.label.name + ".environment.tsv") + dependencies = ctx.actions.declare_file(ctx.label.name + ".dependencies.tsv") + args = ctx.actions.args() + args.add("--spec", spec) + args.add("--install", install) + args.add("--smoke", smoke) + args.add("--startup", startup) + args.add("--environment", environment) + args.add("--dependencies", dependencies) + bun_action( + ctx, ctx.attr._generator, + inputs = depset([spec] + [fixtures[row["sql_name"]] for row in members]), + outputs = [install, smoke, startup, environment, dependencies], + arguments = [args], + mnemonic = "NativeExtensionSmokePlan", + ) + return [DefaultInfo(files = depset([install, smoke, startup, environment, dependencies])), OutputGroupInfo( + install = depset([install]), smoke = depset([smoke]), startup = depset([startup]), + environment = depset([environment]), + dependencies = depset([dependencies]), + )] + +extension_smoke_plan = rule( + implementation = _smoke_plan_impl, + attrs = { + "members": attr.label_list(mandatory = True, providers = [ExtensionMemberInfo]), + "fixtures": attr.label_list(mandatory = True, allow_files = [".sql"]), + "host_version": attr.string(), + "host_product": attr.string(), + "_generator": attr.label(default = "//build_defs/extensions:smoke_plan", providers = [BunScriptInfo], cfg = "exec"), + }, +) + +def native_extension_sql_test(name, members, runtime = "//src/native/runtime:runtime_payload", consumer = "//build_defs/extensions:native_extension_smoke", host_version = "", host_product = "", runtime_prefix = ".", library_prefix = "lib", target_compatible_with = NATIVE_EXTENSION_COMPATIBLE): + """Exercise selected archives in the embedded and ordinary PG ABI profiles.""" + plan = name + "_plan" + if bool(host_version) != bool(host_product): + fail("immutable host tests require both the canonical product and version") + for prefix in [runtime_prefix, library_prefix]: + if prefix != "." and any([not part or part in [".", ".."] or "\\" in part for part in prefix.split("/")]): + fail("native host layout must use a safe carrier-relative directory") + extension_smoke_plan(name = plan, members = members, fixtures = ["//src/test-fixtures/extensions:sql"], host_version = host_version, host_product = host_product) + plans = [] + for group in ["install", "smoke", "startup", "environment", "dependencies"]: + label = name + "_" + group + native.filegroup(name = label, srcs = [":" + plan], output_group = group) + plans.append(":" + label) + archives = [] + for index, member in enumerate(members): + label = name + "_archive_" + str(index) + native.filegroup(name = label, srcs = [member], output_group = "archive") + archives.append(":" + label) + data = [runtime, consumer] + plans + archives + sh_test( + name = name, + srcs = ["//build_defs/extensions:native_extension_all_sql_test.sh"], + args = ["$(location %s)" % label for label in [runtime, consumer] + plans] + + [runtime_prefix, library_prefix] + ["$(location %s)" % label for label in archives], + data = data, + size = "medium", + target_compatible_with = target_compatible_with, + ) + +def desktop_members_sql_test(name, runtime = "//src/native/runtime:runtime_payload", consumer = "//build_defs/extensions:native_extension_smoke", host_version = "", host_product = "", runtime_prefix = ".", library_prefix = None, published_runtime = False, include_postgis = False, target_compatible_with = _desktop_compatible): + """Use the maintained SQL plan and consumer on each native desktop host.""" + if bool(host_version) != bool(host_product) or published_runtime != bool(host_version): + fail("published desktop host tests require the canonical host product and version") + for prefix in [runtime_prefix] + ([library_prefix] if library_prefix != None else []): + if prefix != "." and any([not part or part in [".", ".."] or "\\" in part or ":" in part for part in prefix.split("/")]): + fail("desktop host layout must use a safe carrier-relative directory") + library_args = select({"//build_defs/native:windows_x64": ["--library-prefix=bin"], "//conditions:default": ["--library-prefix=lib"]}) if library_prefix == None else ["--library-prefix=" + library_prefix] + members = desktop_member_payloads(include_postgis) + plan = name + "_plan" + extension_smoke_plan(name = plan, members = members, fixtures = ["//src/test-fixtures/extensions:sql"], host_version = host_version, host_product = host_product) + plans = [] + for group in ["install", "smoke", "startup", "environment", "dependencies"]: + label = name + "_" + group + native.filegroup(name = label, srcs = [":" + plan], output_group = group) + plans.append(":" + label) + archives = [] + for index, member in enumerate(members): + label = name + "_archive_" + str(index) + native.filegroup(name = label, srcs = [member], output_group = "archive") + archives.append(":" + label) + inventory = "//build_defs/extensions:desktop_all_members_construction_inventory" if include_postgis else "//build_defs/extensions:desktop_members_construction_inventory" + inputs = [runtime, consumer] + plans + [inventory] + archives + launcher = "//build_defs/native:windows_restricted_process" + launcher_args = select({"//build_defs/native:windows_x64": ["--restricted-launcher=$(location %s)" % launcher], "//conditions:default": []}) + launcher_data = select({"//build_defs/native:windows_x64": [launcher], "//conditions:default": []}) + bun_script_test( + name = name, + entry_point = "//build_defs/extensions:desktop_sql.test.mts", + args = ["--runtime-prefix=" + runtime_prefix] + library_args + launcher_args + + (["--published-runtime"] if published_runtime else []) + ["$(location %s)" % label for label in inputs], + data = inputs + launcher_data + [ + "//build_defs/extensions:construction.mts", "//build_defs/extensions:validate_member_payload.mts", + "//build_defs/native:host-runtime-test-helpers.mts", "//:tools/packaging/portable-archive.mts", + "//:tools/packaging/platform-binary-contract.mts", "//:tools/packaging/windows-vc-runtime-closure.mts", + "//:tools/packaging/windows-vc-runtime-policy.json", "//tools/release:platform-compatibility-policy.mts", + "//:src/extensions/artifacts/native/tools/stage-windows-binary-contract.mts", + ], + size = "medium", + target_compatible_with = target_compatible_with, + ) diff --git a/build_defs/extensions/smoke_plan.mts b/build_defs/extensions/smoke_plan.mts new file mode 100644 index 000000000..45eabbb87 --- /dev/null +++ b/build_defs/extensions/smoke_plan.mts @@ -0,0 +1,145 @@ +import assert from 'node:assert/strict'; +import { readFileSync, writeFileSync } from 'node:fs'; +import { parseArgs } from 'node:util'; + +const { values } = parseArgs({ + args: Bun.argv.slice(2), + options: { + spec: { type: 'string' }, + install: { type: 'string' }, + smoke: { type: 'string' }, + startup: { type: 'string' }, + environment: { type: 'string' }, + dependencies: { type: 'string' }, + }, + strict: true, +}); +assert( + values.spec && + values.install && + values.smoke && + values.startup && + values.environment && + values.dependencies, +); +const spec = JSON.parse(readFileSync(values.spec, 'utf8')); +assert.equal(spec.schema, 'oliphaunt-native-extension-smoke-plan-v1'); +const members = new Map(spec.members.map((row: any) => [row.sql_name, row])); +assert.equal(members.size, spec.members.length, 'duplicate SQL member in smoke plan'); +const order: any[] = []; +const visiting = new Set(); +const visited = new Set(); +function visit(sql: string) { + assert(!visiting.has(sql), `extension dependency cycle at ${sql}`); + if (visited.has(sql)) return; + const row = members.get(sql); + assert(row, `extension dependency ${sql} has no candidate payload`); + visiting.add(sql); + for (const dependency of row.dependencies) { + if (dependency === 'plpgsql') continue; + visit(dependency); + } + visiting.delete(sql); + visited.add(sql); + order.push(row); +} +for (const name of [...members.keys()].sort()) visit(name); +const identifier = (name: string) => `"${name.replaceAll('"', '""')}"`; +const literal = (value: string) => `'${value.replaceAll("'", "''")}'`; +const install: string[] = []; +const smoke: string[] = []; +const startup = new Map(); +const preload = new Set(); +const environment = new Map(); +const dependencies = new Set(); +for (const row of order) { + const lifecycle = row.lifecycle; + for (const path of row.dependency_modules ?? []) { + assert( + /^lib\/postgresql\/[A-Za-z0-9_.-]+\.(?:so|dylib|dll)$/u.test(path), + `invalid native dependency module for ${row.sql_name}`, + ); + dependencies.add(path.slice('lib/postgresql/'.length)); + } + for (const setting of row.runtime_environment ?? []) { + const { name, path, required_file: requiredFile } = setting; + assert(/^[A-Z_][A-Z0-9_]*$/.test(name), `invalid runtime environment name for ${row.sql_name}`); + for (const relative of [path, requiredFile]) { + assert( + typeof relative === 'string' && + relative && + relative + .split('/') + .every((part) => part && part !== '.' && part !== '..' && !/[\\\t\r\n]/.test(part)), + `invalid runtime environment path for ${row.sql_name}`, + ); + } + const value = `${path}\t${requiredFile}`; + assert( + !environment.has(name) || environment.get(name) === value, + `conflicting runtime environment ${name}`, + ); + environment.set(name, value); + } + for (const assignment of lifecycle['startup-config'] ?? []) { + const separator = assignment.indexOf('='); + assert( + separator > 0 && !assignment.includes('\n'), + `invalid startup assignment for ${row.sql_name}`, + ); + const key = assignment.slice(0, separator); + const value = assignment.slice(separator + 1); + if (key === 'shared_preload_libraries') { + for (const library of value.split(',')) preload.add(library.trim()); + } else { + assert(!startup.has(key) || startup.get(key) === value, `conflicting startup setting ${key}`); + startup.set(key, value); + } + } + if (lifecycle['create-extension']) { + assert(typeof row.default_version === 'string' && row.default_version); + // Native consumers use PostgreSQL's installed control/SQL schema contract. + // The catalog's create-schema is consumed by the WASIX activation harness. + install.push(`CREATE EXTENSION IF NOT EXISTS ${identifier(row.sql_name)};`); + install.push( + `DO $oliphaunt_version$ BEGIN IF (SELECT extversion FROM pg_extension WHERE extname = ${literal(row.sql_name)}) IS DISTINCT FROM ${literal(row.default_version)} THEN RAISE EXCEPTION 'candidate extension version differs for %', ${literal(row.sql_name)}; END IF; END $oliphaunt_version$;`, + ); + } + install.push(...(lifecycle['load-sql'] ?? []), ...(lifecycle['post-create-sql'] ?? [])); + const fixture = readFileSync(row.fixture, 'utf8'); + assert(fixture.trim(), `empty smoke fixture for ${row.sql_name}`); + const statements = fixture + .split('-- oliphaunt-statement') + .map((sql: string) => sql.trim()) + .filter(Boolean); + assert(statements.length, `empty smoke fixture for ${row.sql_name}`); + smoke.push(...statements.map((sql: string) => `-- Candidate extension ${row.sql_name}\n${sql}`)); +} +if (preload.size) startup.set('shared_preload_libraries', [...preload].sort().join(',')); +const separator = '\n-- oliphaunt-statement\n'; +writeFileSync(values.install, `${install.join(separator)}\n`); +writeFileSync( + values.smoke, + `${[...smoke, "SELECT 'candidate-extension-smoke-ok';"].join(separator)}\n`, +); +writeFileSync( + values.startup, + [...startup] + .sort() + .map(([key, value]) => `${key}=${value}\n`) + .join(''), +); +writeFileSync( + values.environment, + [...environment] + .sort() + .map(([name, value]) => `${name}\t${value}\n`) + .join(''), +); +writeFileSync( + values.dependencies, + [...dependencies] + .sort() + .map((name) => `${name}\n`) + .join(''), +); diff --git a/build_defs/extensions/uuid_config.h b/build_defs/extensions/uuid_config.h new file mode 100644 index 000000000..7d4efb931 --- /dev/null +++ b/build_defs/extensions/uuid_config.h @@ -0,0 +1,10 @@ +/* Module-local UUID provider selection, after PostgreSQL's configuration. */ +#ifndef OLIPHAUNT_EXTENSION_UUID_CONFIG_H +#define OLIPHAUNT_EXTENSION_UUID_CONFIG_H + +#include "postgres.h" + +#define HAVE_UUID_E2FS 1 +#define HAVE_UUID_UUID_H 1 + +#endif diff --git a/build_defs/extensions/validate_member_payload.mts b/build_defs/extensions/validate_member_payload.mts new file mode 100644 index 000000000..bbbb1316f --- /dev/null +++ b/build_defs/extensions/validate_member_payload.mts @@ -0,0 +1,370 @@ +/** Inspect actual internal member archives independently of their writer. */ +import { createHash } from 'node:crypto'; +import { readFileSync, realpathSync } from 'node:fs'; +import { parseArgs } from 'node:util'; +import { + validateWindowsEmbeddedModuleImports, + validateWindowsServerModuleImports, +} from '../../src/extensions/artifacts/native/tools/stage-windows-binary-contract.mts'; +import { + inspectPlatformBinaryBuffer, + inspectPlatformBinaryEntries, +} from '../../tools/packaging/platform-binary-contract.mts'; +import { + DEFAULT_PORTABLE_ARCHIVE_LIMITS, + readPortableArchiveEntries, + strictGunzip, +} from '../../tools/packaging/portable-archive.mts'; +import { APPLE_PLATFORM_COMPATIBILITY } from '../../tools/release/platform-compatibility-policy.mts'; + +function record(value: unknown): Record { + if (!value || typeof value !== 'object' || Array.isArray(value)) { + throw new Error('member descriptor must be an object'); + } + return value as Record; +} + +function strings(value: unknown): string[] { + if (!Array.isArray(value) || value.some((item) => typeof item !== 'string')) { + throw new Error('member descriptor must declare resource arrays'); + } + return value; +} + +function fullMatch(pattern: RegExp, value: unknown): value is string { + return typeof value === 'string' && pattern.exec(value)?.[0] === value; +} + +/** Shared static-member policy for construction and final carrier inspection. */ +export function inspectStaticArchiveBytes(bytes: Buffer, target: string, label: string) { + if (!bytes.subarray(0, 8).equals(Buffer.from('!\n'))) + throw new Error('static producer must emit an ordinary object archive'); + const apple = + target === 'macos-arm64' + ? APPLE_PLATFORM_COMPATIBILITY.macos + : target === 'ios-device' + ? APPLE_PLATFORM_COMPATIBILITY.ios + : target === 'ios-simulator' + ? APPLE_PLATFORM_COMPATIBILITY.iosSimulator + : undefined; + return inspectPlatformBinaryEntries([{ name: 'member.a', data: bytes, isFile: true }], { + target: apple ? 'ios-xcframework' : target, + rootLabel: label, + ...(apple + ? { + requiredApplePlatforms: [apple.id], + } + : {}), + }); +} + +/** Shared dynamic-member policy for internal archives and imported final leaves. */ +export function validateNativeMemberModule( + data: Buffer, + configuration: string, + module: string, +): void { + const architecture = + configuration === 'linux-x64-gnu' + ? { machine: 62, name: 'x86_64' } + : configuration === 'linux-arm64-gnu' + ? { machine: 183, name: 'aarch64' } + : undefined; + const suffix = + configuration === 'macos-arm64' + ? 'dylib' + : configuration === 'windows-x64-msvc' + ? 'dll' + : architecture + ? 'so' + : undefined; + if ( + !suffix || + !fullMatch( + new RegExp(`^lib/(?:postgresql|modules)/[a-z_][a-z0-9_-]*\\.${suffix}$`, 'u'), + module, + ) + ) { + throw new Error('native member module has an unsupported configuration or layout'); + } + if (configuration === 'macos-arm64') { + inspectPlatformBinaryBuffer(data, { target: configuration, label: module }); + const little = data.length >= 16 && data.readUInt32LE(0) === 0xfeedfacf; + const big = data.length >= 16 && data.readUInt32BE(0) === 0xfeedfacf; + const type = little ? data.readUInt32LE(12) : big ? data.readUInt32BE(12) : 0; + if (type !== 6 && type !== 8) + throw new Error('native module must be a thin Mach-O arm64 dylib or bundle'); + } else if (configuration === 'windows-x64-msvc') { + if (module.startsWith('lib/postgresql/')) validateWindowsServerModuleImports(data, module); + else validateWindowsEmbeddedModuleImports(data, module); + // The shared parser has already bounded the PE/COFF header. + const coff = data.readUInt32LE(0x3c) + 4; + if ((data.readUInt16LE(coff + 18) & 0x2000) === 0) + throw new Error('native module must be a PE x64 DLL'); + } else if ( + data.length < 64 || + !data.subarray(0, 6).equals(Buffer.from([0x7f, 0x45, 0x4c, 0x46, 2, 1])) || + data.readUInt16LE(16) !== 3 || + data.readUInt16LE(18) !== architecture?.machine + ) { + throw new Error(`native module must be an ELF ${architecture?.name} shared object`); + } +} + +// The portable reader permits and omits tar's conventional root directory +// marker and normalizes './' prefixes. Internal members permit neither. +// Check physical header spelling too, after the independent reader bounds and +// validates their sizes/checksums/paths/compression before exposing any bytes. +function requireRegularHeaders(archive: string, entryPaths: ReadonlySet): void { + const tar = strictGunzip( + readFileSync(archive), + archive, + DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxExpandedBytes, + ); + for (let offset = 0; offset < tar.length; ) { + const header = tar.subarray(offset, offset + 512); + if (header.every((byte) => byte === 0)) break; + if (header[156] !== 0 && header[156] !== 0x30) { + throw new Error('member archive must contain safe regular files only'); + } + const name = header.subarray(0, 100).toString('utf8').split('\0')[0]; + const prefix = header.subarray(345, 500).toString('utf8').split('\0')[0]; + const physicalPath = prefix ? `${prefix}/${name}` : name; + if ( + physicalPath.startsWith('/') || + physicalPath.includes('\\') || + physicalPath.split('/').some((part) => !part || part === '.' || part === '..') || + !entryPaths.has(physicalPath) + ) { + throw new Error('member archive must contain safe regular files only'); + } + const size = Number.parseInt( + header.subarray(124, 136).toString('ascii').replace(/[\0 ]/g, ''), + 8, + ); + offset += 512 + Math.ceil(size / 512) * 512; + } +} + +export function inspect( + archivePath: string, + expectedName?: string, + expectedOwner?: string, +): Record { + // Bazel runfiles are projected links; inspect the resolved regular artifact. + const archive = realpathSync(archivePath); + const entries = readPortableArchiveEntries(archive, { format: 'tar.gz' }); + requireRegularHeaders(archive, new Set(entries.keys())); + const files = new Map(); + for (const [name, entry] of entries) { + if ( + !entry.isFile || + name.startsWith('/') || + name.includes('\\') || + name.split('/').some((part) => !part || part === '.' || part === '..') + ) { + throw new Error('member archive must contain safe regular files only'); + } + files.set(name, entry.data()); + } + const descriptorBytes = files.get('extension.json'); + if (!descriptorBytes) throw new Error('member archive has no descriptor'); + files.delete('extension.json'); + const descriptor = record( + JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(descriptorBytes)), + ); + if (descriptor.schema !== 'oliphaunt-extension-member-payload-v1') { + throw new Error('unknown member payload schema'); + } + const architecture = + descriptor.configuration === 'linux-x64-gnu' + ? { machine: 62, name: 'x86_64' } + : descriptor.configuration === 'linux-arm64-gnu' + ? { machine: 183, name: 'aarch64' } + : undefined; + const desktop = + descriptor.configuration === 'macos-arm64' || descriptor.configuration === 'windows-x64-msvc'; + if ((!architecture && !desktop) || descriptor.family !== 'native') { + throw new Error('member payload configuration is unsupported by this native slice'); + } + const name = descriptor.sql_name; + if (!fullMatch(/^[a-z][a-z0-9_-]*$/u, name)) throw new Error('invalid member SQL identity'); + if (expectedName !== undefined && name !== expectedName) { + throw new Error('member SQL identity disagrees with the requested extension'); + } + if (expectedOwner !== undefined && descriptor.owner !== expectedOwner) { + throw new Error('member carrier owner disagrees with canonical ownership'); + } + if (!Array.isArray(descriptor.files)) throw new Error('member descriptor inventory is missing'); + const recorded = descriptor.files.map(record); + const recordedPaths = recorded.map((item) => item.path); + if ( + new Set(recordedPaths).size !== recordedPaths.length || + recordedPaths.length !== files.size || + recordedPaths.some((item) => typeof item !== 'string' || !files.has(item)) + ) { + throw new Error('member descriptor inventory disagrees with the actual archive'); + } + for (const item of recorded) { + const data = files.get(item.path as string); + if (!data || item.sha256 !== createHash('sha256').update(data).digest('hex')) { + throw new Error('member payload checksum mismatch'); + } + } + const sqlPrefix = 'share/postgresql/extension/'; + const profiles = strings(descriptor.module_profiles); + if ( + profiles.length !== 0 && + (profiles.length !== 2 || profiles[0] !== 'postgresql' || profiles[1] !== 'modules') + ) { + throw new Error('member archive has an unsupported ABI profile declaration'); + } + const moduleFile = descriptor.module_file ?? ''; + const modulePattern = + descriptor.configuration === 'macos-arm64' + ? /^[a-z_][a-z0-9_-]*\.dylib$/u + : descriptor.configuration === 'windows-x64-msvc' + ? /^[a-z_][a-z0-9_-]*\.dll$/u + : /^[a-z_][a-z0-9_-]*\.so$/u; + if (profiles.length && !fullMatch(modulePattern, moduleFile)) { + throw new Error('compiled member has an invalid module file declaration'); + } + if (Boolean(moduleFile) !== Boolean(profiles.length)) { + throw new Error('compiled member must declare both ABI profiles'); + } + const modules = new Set(profiles.map((profile) => `lib/${profile}/${moduleFile}`)); + const dependencyModules = strings(descriptor.dependency_modules ?? []); + if ( + dependencyModules.length && + (!profiles.length || + new Set(dependencyModules).size !== dependencyModules.length || + dependencyModules.some((module) => !fullMatch(modulePattern, module))) + ) { + throw new Error('member archive has invalid native dependency modules'); + } + for (const profile of profiles) { + for (const module of dependencyModules) modules.add(`lib/${profile}/${module}`); + } + const dataFiles = new Set( + strings(descriptor.data_files === undefined ? [] : descriptor.data_files), + ); + const constructionLicenses = new Set(strings(descriptor.construction_licenses ?? [])); + if ([...constructionLicenses].some((file) => !file.startsWith('share/licenses/'))) { + throw new Error('construction licenses must be beneath share/licenses'); + } + const sqlPrefixes = strings(descriptor.sql_prefixes === undefined ? [] : descriptor.sql_prefixes); + const sqlFiles = strings(descriptor.sql_files === undefined ? [] : descriptor.sql_files); + for (const filename of files.keys()) { + if (filename.startsWith(sqlPrefix)) { + const basename = filename.slice(sqlPrefix.length); + const valid = + basename === `${name}.control` || + (basename.endsWith('.sql') && basename.startsWith(`${name}--`)) || + sqlPrefixes.some((prefix) => basename.startsWith(prefix) && basename.endsWith('.sql')) || + sqlFiles.includes(basename); + if (!valid) throw new Error('member archive contains foreign SQL/control resources'); + } else if ( + !modules.has(filename) && + !dataFiles.has(filename) && + !constructionLicenses.has(filename) + ) { + throw new Error('member archive contains an undeclared resource'); + } + } + if ([...modules].some((module) => !files.has(module))) { + throw new Error('member archive is missing a required ABI profile'); + } + if ([...dataFiles].some((file) => !files.has(file))) { + throw new Error('member archive is missing a required data resource'); + } + if ([...constructionLicenses].some((file) => !files.has(file))) { + throw new Error('member archive is missing a required construction license'); + } + for (const receipt of constructionLicenses) { + if (!receipt.endsWith('/SOURCE.json')) continue; + const source = record( + JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(files.get(receipt))), + ); + if (source.schema !== 'oliphaunt-compiler-runtime-source-v1' || !Array.isArray(source.files)) { + throw new Error('construction license has an invalid source receipt'); + } + const license = source.files.map(record).find((file) => file.destination === 'LICENSE.TXT'); + const destination = receipt.replace(/SOURCE\.json$/u, 'LICENSE.TXT'); + const data = files.get(destination); + if ( + !license || + !constructionLicenses.has(destination) || + !data || + license.sha256 !== createHash('sha256').update(data).digest('hex') + ) { + throw new Error('construction license bytes differ from their upstream source pin'); + } + } + for (const module of modules) { + const data = files.get(module); + if (!data) throw new Error('member archive is missing a required ABI profile'); + validateNativeMemberModule(data, descriptor.configuration as string, module); + } + if (typeof descriptor.creates_extension !== 'boolean') { + throw new Error('member descriptor must declare creates_extension'); + } + if (descriptor.creates_extension) { + const controlBytes = files.get(`${sqlPrefix}${name}.control`); + if (!controlBytes) throw new Error('member has no required extension control'); + const control = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(controlBytes); + const match = /^default_version\s*=\s*'([^']+)'/m.exec(control); + if (!match || match[1] !== descriptor.default_version) { + throw new Error('member control disagrees with the canonical default version'); + } + const reachable = new Set(); + const edges = new Map(); + const prefix = `${sqlPrefix}${name}--`; + for (const filename of files.keys()) { + if (!filename.startsWith(prefix) || !filename.endsWith('.sql')) continue; + const versionsPart = filename.slice(prefix.length, -'.sql'.length); + if (!versionsPart || versionsPart.includes('/')) continue; + // Upstream extensions/upgrade-paths-rules.mk installs this PostGIS + // template beside its real version-to-ANY edges. It is not a version edge. + if (name === 'postgis' && versionsPart === 'TEMPLATED--TO--ANY') continue; + const versions = versionsPart.split('--'); + if (versions.length === 1) reachable.add(versions[0]); + else if (versions.length === 2) + edges.set(versions[0], [...(edges.get(versions[0]) ?? []), versions[1]]); + else throw new Error('invalid member SQL version path'); + } + const queue = [...reachable]; + for (let index = 0; index < queue.length; index += 1) { + for (const target of edges.get(queue[index]) ?? []) { + if (!reachable.has(target)) { + reachable.add(target); + queue.push(target); + } + } + } + if ( + typeof descriptor.default_version !== 'string' || + !reachable.has(descriptor.default_version) + ) { + throw new Error('member default SQL version is not installable'); + } + } + return descriptor; +} + +if (import.meta.main) { + try { + const { positionals, values } = parseArgs({ + allowPositionals: true, + options: { 'sql-name': { type: 'string' }, owner: { type: 'string' } }, + }); + if (positionals.length !== 1) { + throw new Error( + 'usage: validate_member_payload.mts [--sql-name ] [--owner ]', + ); + } + inspect(positionals[0], values['sql-name'], values.owner); + } catch (cause) { + console.error(cause instanceof Error ? cause.message : String(cause)); + process.exitCode = 2; + } +} diff --git a/build_defs/extensions/wasix/BUILD.bazel b/build_defs/extensions/wasix/BUILD.bazel new file mode 100644 index 000000000..e2f1ac4be --- /dev/null +++ b/build_defs/extensions/wasix/BUILD.bazel @@ -0,0 +1,140 @@ +load("//build_defs/extensions:wasix_carriers.bzl", "wasix_compiled_extension_carriers", "wasix_compiled_extension_installed_test", "wasix_compiled_extension_shipping", "wasix_extension_declared_host", "wasix_compiled_extension_qualification", "wasix_extension_current_host") +load(":contrib_carriers.bzl", "wasix_contrib_extension_carriers", "wasix_contrib_extension_incremental_installed_test", "wasix_contrib_extension_installed_test", "wasix_contrib_extension_shipping") +load("@oliphaunt_metadata//:metadata.bzl", "EXTENSION_RECIPES") +load("//build_defs/quality:sources.bzl", "source_quality_files") +load(":link_inputs_test.bzl", "wasix_extension_link_input_tests") +load("//build_defs/foundation:bun.bzl", "bun_test") +load("//build_defs/extensions:wasix_carriers.bzl", "wasix_sql_carrier_helpers") +load("//build_defs/extensions:contrib_carriers.bzl", "native_contrib_carrier_legal") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["compiled_carriers.test.mts", "installed_consumer.mts", "contrib_carriers.mts", "contrib_carriers.bzl", "contrib_installed.test.mts"]) + +bun_test( + name = "resource_inputs_test", + entry_point = "resource_inputs.test.mts", + data = ["//build_defs/extensions:wasix_carriers.mts", "//:src/extensions/artifacts/packages/tools/bundle-carrier-assets.mts"] + wasix_sql_carrier_helpers() + native_contrib_carrier_legal(), + size = "small", +) + +bun_test( + name = "cargo_parts_test", + entry_point = "cargo_parts.test.mts", + data = ["//build_defs/extensions:wasix_carriers.mts"] + wasix_sql_carrier_helpers(), + size = "small", +) + +wasix_extension_declared_host(name = "declared_host", sql_name = "pg_hashids") +wasix_extension_current_host(name = "current_host") +wasix_contrib_extension_carriers(name = "contrib", host = ":current_host") +wasix_contrib_extension_installed_test(name = "contrib_installed_test", leaf = ":contrib", host = ":current_host", size = "large", timeout = "long", tags = ["manual", "installed-consumer"]) +wasix_contrib_extension_incremental_installed_test(name = "contrib_incremental_installed_test", leaf = ":contrib", host = ":current_host", size = "large", timeout = "long", tags = ["manual", "installed-consumer"]) +wasix_contrib_extension_shipping( + name = "contrib", + carriers = ":contrib", + qualification = [ + ":contrib_installed_test", + ":contrib_incremental_installed_test", + ":link_inputs_test", + ":invalid_link_profile_test", + ":unhandled_linkopts_test", + ":resource_inputs_test", + "//src/wasix/runtime/tools/xtask:export_policy_test", + ], +) + +wasix_compiled_extension_carriers( + name = "pg_hashids", + sql_name = "pg_hashids", + module = "//src/wasix/runtime:external_pg_hashids", + host = ":declared_host", + resources = ["@pg_hashids//:sql_resources"], +) + +wasix_compiled_extension_installed_test( + name = "pg_hashids_installed_test", + sql_name = "pg_hashids", + leaf = ":pg_hashids", + module = "//src/wasix/runtime:external_pg_hashids", + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + size = "large", + timeout = "long", + tags = ["manual", "installed-consumer"], +) + +wasix_compiled_extension_shipping( + name = "pg_hashids", + sql_name = "pg_hashids", + carriers = ":pg_hashids", + qualification = [ + ":pg_hashids_installed_test", + ":link_inputs_test", + ":invalid_link_profile_test", + ":unhandled_linkopts_test", + ":resource_inputs_test", + "//src/wasix/runtime/tools/xtask:export_policy_test", + ], +) + +wasix_extension_declared_host(name = "pg_uuidv7_declared_host", sql_name = "pg_uuidv7") +wasix_compiled_extension_carriers( + name = "pg_uuidv7", + sql_name = "pg_uuidv7", + module = "//src/wasix/runtime:external_pg_uuidv7", + host = ":pg_uuidv7_declared_host", + resources = ["@pg_uuidv7//:sql_resources"], +) + +wasix_extension_declared_host(name = "vector_declared_host", sql_name = "vector") +wasix_compiled_extension_carriers( + name = "vector", + sql_name = "vector", + module = "//src/wasix/runtime:external_vector", + host = ":vector_declared_host", + resources = ["@pgvector//:sql_resources"], + main_sql = "@pgvector//:sql/vector.sql", +) + +wasix_extension_declared_host(name = "pg_ivm_declared_host", sql_name = "pg_ivm") +wasix_compiled_extension_carriers( + name = "pg_ivm", + sql_name = "pg_ivm", + module = "//src/wasix/runtime:external_pg_ivm", + host = ":pg_ivm_declared_host", + resources = ["@pg_ivm//:sql_resources"], +) + +wasix_extension_declared_host(name = "pg_textsearch_declared_host", sql_name = "pg_textsearch") +wasix_compiled_extension_carriers( + name = "pg_textsearch", + sql_name = "pg_textsearch", + module = "//src/wasix/runtime:external_pg_textsearch", + host = ":pg_textsearch_declared_host", + resources = ["//src/extensions/external/pg_textsearch:sql_resources"], +) + +_POSTGIS_DATA = EXTENSION_RECIPES["postgis"]["artifacts"]["data_files"] +wasix_extension_declared_host(name = "postgis_declared_host", sql_name = "postgis") +wasix_compiled_extension_carriers( + name = "postgis", + sql_name = "postgis", + module = "//build_defs/wasix/dependencies:postgis", + support_modules = ["//build_defs/wasix/dependencies:postgis_dependency_module"], + host = ":postgis_declared_host", + resources = ["//build_defs/wasix/dependencies:postgis_extension_sql", "//build_defs/wasix/dependencies:postgis_control"], + data_resources = { + "//build_defs/wasix/dependencies:postgis_data_sql": "/".join([path for path in _POSTGIS_DATA if path.endswith("/postgis.sql")][0].split("/")[:-1]), + "//build_defs/wasix/dependencies:proj_database": [path for path in _POSTGIS_DATA if path.endswith("/proj.db")][0], + }, +) +wasix_compiled_extension_qualification(name = "postgis", sql_name = "postgis", module = "//build_defs/wasix/dependencies:postgis") + +[ + wasix_compiled_extension_qualification(name = sql_name, sql_name = sql_name, module = "//src/wasix/runtime:external_" + sql_name) + for sql_name in ["pg_uuidv7", "vector", "pg_ivm", "pg_textsearch"] +] + +source_quality_files() + +wasix_extension_link_input_tests() diff --git a/build_defs/extensions/wasix/cargo_parts.test.mts b/build_defs/extensions/wasix/cargo_parts.test.mts new file mode 100644 index 000000000..09813a697 --- /dev/null +++ b/build_defs/extensions/wasix/cargo_parts.test.mts @@ -0,0 +1,202 @@ +import { test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + copyFileSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { createDeterministicTar } from '../../../tools/packaging/cargo-source-package.mts'; +import { canonicalGzipSync } from '../../../tools/packaging/portable-archive.mts'; +import { readWasixCargoCarrierPayload, readWasixCargoCarrierSet } from '../wasix_carriers.mts'; + +test('canonical Cargo parents bind their complete bounded parts and reconstructed physical payload', () => { + const root = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'wasix-cargo-parts-')); + const parent = { + product: 'fixture', + ecosystem: 'cargo', + name: 'fixture-aot-linux-x64', + version: '1.0.0', + role: 'aot-leaf', + target: 'x86_64-unknown-linux-gnu', + }; + function archive(name: string, dependencies: string[], payload: Record = {}) { + const source = path.join(root, name); + rmSync(source, { recursive: true, force: true }); + mkdirSync(source, { recursive: true }); + writeFileSync( + path.join(source, 'Cargo.toml'), + `[package]\nname=${JSON.stringify(name)}\nversion="1.0.0"\n[build-dependencies]\n${dependencies.map((name) => `${name}={version="=1.0.0"}`).join('\n')}\n`, + ); + for (const [relative, bytes] of Object.entries(payload)) { + const file = path.join(source, 'payload', relative); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, bytes); + } + const file = path.join(root, `${name}-1.0.0.crate`); + writeFileSync( + file, + canonicalGzipSync( + createDeterministicTar(source, `${name}-1.0.0`, { + fail: (message: string) => { + throw new Error(message); + }, + }), + ), + ); + return file; + } + try { + const first = `${parent.name}-part-001`, + second = `${parent.name}-part-002`; + const base = archive(parent.name, [first, second]); + const part1 = archive(first, [], { 'files/one': 'one', 'chunks/two.part000000': 'tw' }); + const part2 = archive(second, [], { 'chunks/two.part000001': 'o' }); + const files = [base, part1, part2]; + const rows = readWasixCargoCarrierSet([parent], files); + const declared = rows.find((row) => row.declared); + assert(declared); + assert.deepEqual( + [...readWasixCargoCarrierPayload(rows, declared)].map(([name, bytes]) => [ + name, + bytes.toString(), + ]), + [ + ['one', 'one'], + ['two', 'two'], + ], + ); + assert.throws( + () => readWasixCargoCarrierSet([parent], [base, part1]), + /complete Cargo payload part set/u, + ); + const extra = archive(`${parent.name}-part-003`, []); + assert.throws( + () => readWasixCargoCarrierSet([parent], [...files, extra]), + /complete Cargo payload part set/u, + ); + const invalid = archive(`${parent.name}-part-1000`, []); + assert.throws( + () => readWasixCargoCarrierSet([parent], [...files, invalid]), + /not a Cargo payload part crate/u, + ); + const zero = archive(`${parent.name}-part-000`, []); + assert.throws(() => readWasixCargoCarrierSet([parent], [...files, zero]), /1-based/u); + const oversized = path.join(root, 'oversized.crate'); + writeFileSync(oversized, Buffer.alloc(10 * 1024 * 1024 + 1)); + assert.throws(() => readWasixCargoCarrierSet([parent], [oversized]), /10 MiB package limit/u); + const produced = rows.map((row) => ({ + name: row.name, + target: row.target, + size: row.size, + sha256: row.sha256, + })); + assert.throws( + () => + readWasixCargoCarrierSet( + [parent], + files, + produced.map((row, index) => + index === 1 ? { ...row, target: 'aarch64-apple-darwin' } : row, + ), + ), + /inventory target/u, + ); + assert.throws( + () => + readWasixCargoCarrierSet( + [parent], + files, + produced.map((row, index) => (index === 1 ? { ...row, sha256: '0'.repeat(64) } : row)), + ), + /AssertionError/u, + ); + assert.throws( + () => readWasixCargoCarrierSet([parent], [...files, part1]), + /repeated Cargo carrier/u, + ); + const missingChunk = archive(second, [], { 'chunks/two.part000002': 'o' }); + const missingRows = readWasixCargoCarrierSet([parent], [base, part1, missingChunk]); + const missingParent = missingRows.find((row) => row.declared); + assert(missingParent); + assert.throws( + () => readWasixCargoCarrierPayload(missingRows, missingParent), + /non-contiguous Cargo payload chunks/u, + ); + assert.equal(createHash('sha256').update(readFileSync(base)).digest('hex'), produced[0].sha256); + const omittedDirectory = path.join(root, 'omitted-runfiles', parent.name); + assert.throws( + () => readWasixCargoCarrierSet([parent], [base, omittedDirectory]), + /must have between 1 and 999 Cargo payload parts/u, + ); + const partsDirectory = path.join(root, 'parts', parent.name); + mkdirSync(partsDirectory, { recursive: true }); + copyFileSync(part1, path.join(partsDirectory, path.basename(part1))); + copyFileSync( + archive(second, [], { 'chunks/two.part000001': 'o' }), + path.join(partsDirectory, path.basename(part2)), + ); + const directoryRows = readWasixCargoCarrierSet([parent], [base, partsDirectory]); + assert.equal(directoryRows.length, 3); + const directoryParent = directoryRows.find((row) => row.declared); + assert(directoryParent); + assert.equal( + readWasixCargoCarrierPayload(directoryRows, directoryParent).get('two')?.toString(), + 'two', + ); + mkdirSync(path.dirname(omittedDirectory), { recursive: true }); + symlinkSync(partsDirectory, omittedDirectory, 'dir'); + assert.equal(readWasixCargoCarrierSet([parent], [base, omittedDirectory]).length, 3); + rmSync(omittedDirectory); + mkdirSync(omittedDirectory); + for (const file of [part1, part2]) + symlinkSync( + path.join(partsDirectory, path.basename(file)), + path.join(omittedDirectory, path.basename(file)), + ); + assert.equal(readWasixCargoCarrierSet([parent], [base, omittedDirectory]).length, 3); + rmSync(omittedDirectory, { recursive: true }); + const unsplit = archive(parent.name, [], { 'files/one': 'one' }); + const unsplitRows = readWasixCargoCarrierSet([parent], [unsplit, omittedDirectory]); + assert.equal(unsplitRows.length, 1); + assert.equal( + readWasixCargoCarrierPayload(unsplitRows, unsplitRows[0]).get('one')?.toString(), + 'one', + ); + mkdirSync(omittedDirectory); + assert.equal(readWasixCargoCarrierSet([parent], [unsplit, omittedDirectory]).length, 1); + assert.throws( + () => readWasixCargoCarrierSet([parent], [unsplit, `${omittedDirectory}-wrong-parent`]), + /Cargo parts directory has no canonical parent/u, + ); + symlinkSync(part1, path.join(omittedDirectory, path.basename(part1))); + assert.throws( + () => readWasixCargoCarrierSet([parent], [unsplit, omittedDirectory]), + /outside its canonical parent/u, + ); + const alias = path.join(omittedDirectory, path.basename(part1)); + rmSync(alias); + symlinkSync(path.join(partsDirectory, path.basename(part2)), alias); + assert.throws( + () => readWasixCargoCarrierSet([parent], [unsplit, omittedDirectory]), + /changed its archive filename/u, + ); + rmSync(alias); + symlinkSync(partsDirectory, alias, 'dir'); + assert.throws( + () => readWasixCargoCarrierSet([parent], [unsplit, omittedDirectory]), + /resolve to a regular archive/u, + ); + console.log( + 'Canonical dynamic Cargo parts: complete parents, physical hashes, targets, bounds, chunk reconstruction and omitted empty runfiles directories PASS', + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/build_defs/extensions/wasix/compiled_carriers.test.mts b/build_defs/extensions/wasix/compiled_carriers.test.mts new file mode 100644 index 000000000..26d614fa3 --- /dev/null +++ b/build_defs/extensions/wasix/compiled_carriers.test.mts @@ -0,0 +1,396 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { mkdtempSync, readdirSync, readFileSync, realpathSync, rmSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { + assertWasixExtensionArchiveInstall, + WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA, +} from '../../../src/extensions/contracts/wasix-extension-install.mts'; +import { + assertSingleWasixNapiAddonMember, + assertWasixNapiCarrierManifest, + assertWasixNapiConstructionData, + assertWasixTypescriptNativeCarrier, +} from '../../../src/wasix/node-addon/tools/carrier-contract.mts'; +import { assertWasixAotArtifactPayloads } from '../../../src/wasix/runtime/tools/check-release-assets.mts'; +import { assertCanonicalWasixAotManifest } from '../../../src/wasix/runtime/tools/wasix-aot-manifest.mts'; +import { AOT_TARGET_TRIPLES } from '../../../src/wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; +import { + extractPortableArchiveTree, + readPortableArchiveEntries, +} from '../../../tools/packaging/portable-archive.mts'; +import { readWasixCargoCarrierPayload, readWasixCargoCarrierSet } from '../wasix_carriers.mts'; + +const [ + input, + githubInput, + npmInput, + cargoInput, + frozenInput, + moduleInput, + addonInput, + node, + consumerInput, + linkInput, + fixtureInput, + hostModuleInput, + hostManifestInput, + napiInput, + facadeInput, + addonTemplateInput, + currentAddonInput, +] = process.argv.slice(2); +const napiContract = JSON.parse(readFileSync(napiInput, 'utf8')); +const addonTemplate = JSON.parse(readFileSync(addonTemplateInput, 'utf8')); +const hostManifestBytes = readFileSync(hostManifestInput); +const hostManifest = JSON.parse(hostManifestBytes.toString()); +const githubRoot = path.dirname(githubInput); +const npmRoot = path.dirname(npmInput); +const cargoRoot = path.dirname(cargoInput); +const spec = JSON.parse(readFileSync(input, 'utf8')); +const partInputs = process.argv.slice(19); +const partParents = Object.keys(spec.outputs.cargoParts ?? {}); +assert.equal(process.argv.length, 19 + partParents.length); +if (partParents.length) + assert.deepEqual( + partParents.sort(), + spec.carriers + .filter((row: { ecosystem: string }) => row.ecosystem === 'cargo') + .map((row: { name: string }) => row.name) + .sort(), + ); +assert.deepEqual(partInputs.map((file) => path.basename(file)).sort(), partParents.sort()); +const frozen = JSON.parse(readFileSync(frozenInput, 'utf8')); +const compiled = moduleInput !== '-'; +const linkContract = compiled ? JSON.parse(readFileSync(linkInput, 'utf8')) : null; +const selection = linkContract?.runtimeSelection; +if (selection) { + assert(['completed-publication', 'current-source'].includes(selection.kind)); + for (const key of ['declaredModuleSha256', 'currentModuleSha256', 'selectedModuleSha256']) + assert.match(selection[key], /^[a-f0-9]{64}$/u); + assert.deepEqual(selection.missingExports, [...new Set(selection.missingExports)].sort()); + assert( + selection.missingExports.every((name: unknown) => typeof name === 'string' && name.length > 0), + ); + assert.equal(selection.kind === 'current-source', selection.missingExports.length > 0); + assert.equal( + selection.selectedModuleSha256, + selection.kind === 'current-source' + ? selection.currentModuleSha256 + : selection.declaredModuleSha256, + ); + assert.equal(selection.selectedModuleSha256, hostManifest.runtime['module-sha256']); +} +const current = selection?.kind === 'current-source'; +if (current) + assert.notEqual( + currentAddonInput, + '-', + 'selected current core requires its actual source addon carrier', + ); +const napi = current + ? { + ...napiContract, + current: true, + version: napiContract.currentVersion, + constructionContract: napiContract.currentConstructionContract, + } + : napiContract; +const selectedFacadeInput = current ? '-' : facadeInput; +assert.equal(compiled, frozen.wasixInstall.nativeModules.length > 0); +const root = mkdtempSync( + path.join(process.env.TEST_TMPDIR ?? os.tmpdir(), 'installed-wasix-member-'), +); +const digest = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +assert.equal(hostManifest['format-version'], 2); +assert.equal(hostManifest['source-lane'], 'stable'); +assert.equal(hostManifest.runtime['runtime-kind'], 'wasix-dynamic-main'); +assert.equal(digest(readFileSync(hostModuleInput)), hostManifest.runtime['module-sha256']); +function assertMemberAot(aot: any, target: string, readArtifact: (relative: string) => Buffer) { + assertCanonicalWasixAotManifest(aot, { expectedTarget: target }); + assertWasixAotArtifactPayloads(aot, { readArtifact }); + assert.equal(aot.artifacts.length, frozen.wasixInstall.nativeModules.length); + for (const artifact of aot.artifacts) { + const name = + artifact.name === `extension:${spec.sqlName}` + ? spec.sqlName + : artifact.name.slice(`extension:${spec.sqlName}:`.length); + const module = frozen.wasixInstall.nativeModules.find( + (row: { name: string }) => row.name === name, + ); + assert(module, 'AOT member has no exact compiled module'); + assert.equal(artifact['module-sha256'], module.moduleSha256); + } +} +try { + assert.equal(frozen.product, spec.product); + assert.equal(frozen.version, spec.version); + assert.equal(frozen.compatibility.wasixRuntimeVersion, spec.compatibility.wasix_runtime_version); + const asset = frozen.assets[0]; + const archive = readFileSync(path.join(githubRoot, asset.name)); + assertWasixExtensionArchiveInstall(archive, { + schema: WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA, + sqlName: spec.sqlName, + archive: `extensions/${spec.sqlName}.tar.zst`, + sha256: asset.sha256, + size: asset.bytes, + install: frozen.wasixInstall, + }); + const portable = readPortableArchiveEntries(realpathSync(path.join(githubRoot, asset.name))); + if (compiled) { + assert.deepEqual( + portable.get(`lib/postgresql/${spec.descriptor['native-module-file']}`)!.data(), + readFileSync(moduleInput), + 'GitHub member changed the real compiler output', + ); + assert(frozen.wasixInstall.coreExportsRequired.length > 0); + assert.deepEqual(frozen.wasixInstall.unresolvedImports, []); + assert.equal(linkContract.sourceFingerprint, hostManifest['source-fingerprint']); + assert.equal(linkContract.postgresVersion, hostManifest.runtime['postgres-version']); + const link = linkContract.moduleLinkMetadata[spec.sqlName]; + const exports = new Set(link.exports.map((row: { name: string }) => row.name)); + const callable = new Set(); + for (const [name, entry] of portable) + if (name.endsWith('.sql')) + for (const match of entry + .data() + .toString() + .matchAll(/\bAS\s+'(?:MODULE_PATHNAME|\$libdir\/[^']+)'\s*,\s*'([^']+)'/giu)) + callable.add(match[1]); + for (const name of ['Pg_magic_func', ...callable]) + assert(exports.has(name), `compiled member lost PostgreSQL export ${name}`); + for (const name of callable) + assert(exports.has(`pg_finfo_${name}`), `compiled member lost function metadata ${name}`); + if (['vector', 'pg_ivm', 'pg_textsearch', 'postgis'].includes(spec.sqlName)) + assert(exports.has('_PG_init'), 'compiled member lost its PostgreSQL initializer'); + if (spec.sqlName === 'vector') + for (const name of ['HnswParallelBuildMain', 'IvfflatParallelBuildMain']) + assert(exports.has(name), `compiled vector lost parallel worker export ${name}`); + if (spec.sqlName === 'pg_textsearch') + assert( + exports.has('tp_parallel_build_worker_main'), + 'compiled textsearch lost parallel worker', + ); + if (spec.sqlName === 'pg_hashids') { + for (const name of ['hashids_encode_hex', 'hashids_decode_hex', 'malloc', 'calloc', 'free']) + assert(!exports.has(name), `compiled member exports internal helper or allocator ${name}`); + for (const name of ['palloc0', 'pfree']) + assert( + link.imports.some( + (row: { name: string; module: string }) => row.module === 'env' && row.name === name, + ), + `compiled member lost core allocator import ${name}`, + ); + } + } else { + assert.equal(linkInput, '-'); + assert.equal(frozen.nativeModuleStem, null); + assert.deepEqual(frozen.wasixInstall.coreExportsRequired, []); + assert.deepEqual(frozen.wasixInstall.unresolvedImports, []); + assert( + [...portable] + .filter(([, entry]) => entry.isFile) + .every(([file]) => file.startsWith('share/postgresql/extension/')), + ); + } + const installed = new Map(); + for (const filename of readdirSync(npmRoot).filter((name) => name.endsWith('.tgz'))) { + const archivePath = realpathSync(path.join(npmRoot, filename)); + const entries = readPortableArchiveEntries(archivePath); + const manifest = JSON.parse(entries.get('package/package.json')!.data().toString()); + assert.equal(manifest.version, spec.version); + assert.equal(manifest.oliphaunt.product, spec.product); + const destination = path.join(root, 'node_modules', manifest.name); + extractPortableArchiveTree(archivePath, destination, 'package'); + installed.set(manifest.name, destination); + if (manifest.oliphaunt.kind === 'exact-extension-wasix') + assert.deepEqual( + entries.get(`package/extensions/${spec.sqlName}/extension.tar.zst`)!.data(), + archive, + ); + else { + const aot = JSON.parse(entries.get('package/aot-manifest.json')!.data().toString()); + assertMemberAot(aot, AOT_TARGET_TRIPLES[manifest.oliphaunt.target], (relative) => + Buffer.from(entries.get(`package/${relative}`)!.data()), + ); + assert.equal( + frozen.wasixInstall.nativeModules[0].moduleSha256, + digest(readFileSync(moduleInput)), + ); + } + } + assert.equal(installed.size, compiled ? Object.keys(AOT_TARGET_TRIPLES).length + 1 : 1); + const crates = readdirSync(cargoRoot) + .filter((name) => name.endsWith('.crate')) + .map((name) => realpathSync(path.join(cargoRoot, name))); + const cargo = readWasixCargoCarrierSet(spec.carriers, [...crates, ...partInputs]); + assert.equal(cargo.filter((row) => row.declared).length, installed.size); + for (const carrier of cargo.filter((row) => row.declared)) { + const files = readWasixCargoCarrierPayload(cargo, carrier); + if (carrier.name.endsWith('-wasix')) { + assert.deepEqual([...files.keys()], [`extensions/${spec.sqlName}/extension.tar.zst`]); + assert.deepEqual(files.get(`extensions/${spec.sqlName}/extension.tar.zst`), archive); + } else { + const aot = JSON.parse( + carrier.entries.get(`${carrier.prefix}/manifests/${spec.sqlName}.json`)!.data().toString(), + ); + assert.deepEqual( + [...files.keys()].sort(), + aot.artifacts + .map((row: { path: string }) => `extensions/${spec.sqlName}/${row.path}`) + .sort(), + ); + assertMemberAot( + aot, + carrier.target, + (relative) => files.get(`extensions/${spec.sqlName}/${relative}`)!, + ); + } + } + const addonArchive = realpathSync(current ? currentAddonInput : addonInput); + const addonEntries = readPortableArchiveEntries(addonArchive); + const addonMember = (name: string) => { + const entry = addonEntries.get(name); + assert(entry?.isFile && !entry.isSymbolicLink, `missing regular addon member ${name}`); + const bytes = Buffer.from(entry.data()); + assert(bytes.length > 0, `empty addon member ${name}`); + return bytes; + }; + const addonManifest = JSON.parse(addonMember('package/package.json').toString()); + let runtimeContract; + if (napi.current) { + assert.equal(selectedFacadeInput, '-'); + assert.equal(addonTemplate.version, napi.version); + runtimeContract = { ...addonTemplate.oliphaunt, packageLicense: addonTemplate.license }; + } else { + const originalBytes = readFileSync(addonArchive); + assert.equal(digest(originalBytes), napi.original.file.sha256); + assert.equal(originalBytes.length, napi.original.file.size); + const facadeBytes = readFileSync(selectedFacadeInput); + assert.equal(digest(facadeBytes), napi.facade.file.sha256); + assert.equal(facadeBytes.length, napi.facade.file.size); + const facadeEntries = readPortableArchiveEntries(realpathSync(selectedFacadeInput)); + const facadePackage = facadeEntries.get('package/package.json'); + assert(facadePackage?.isFile && !facadePackage.isSymbolicLink); + const facadeManifest = JSON.parse(facadePackage.data().toString()); + assert.equal(`npm:${facadeManifest.name}`, napi.facade.artifact); + assert.equal(facadeManifest.version, napi.facade.publication.version); + assert.equal(`npm:${addonManifest.name}`, napi.original.artifact); + assert.equal(addonManifest.version, napi.original.publication.version); + assertWasixTypescriptNativeCarrier(facadeManifest, addonManifest); + runtimeContract = { + runtimeProduct: facadeManifest.oliphaunt.runtimeProduct, + runtimeVersion: facadeManifest.oliphaunt.runtimeVersion, + addonAbiVersion: facadeManifest.oliphaunt.wasixAddonAbiVersion, + nodeApiVersion: facadeManifest.oliphaunt.nodeApiVersion, + packageLicense: addonTemplate.license, + }; + } + assert.equal(runtimeContract.runtimeVersion, spec.compatibility.wasix_runtime_version); + assertWasixNapiCarrierManifest( + addonManifest, + { + target: napi.target.target, + npmPackage: napi.target.npm_package, + npmOs: napi.target.npm_os, + npmCpu: napi.target.npm_cpu, + npmLibc: napi.target.npm_libc ?? undefined, + }, + napi.version, + 'installed declared WASIX addon', + runtimeContract, + ); + assertSingleWasixNapiAddonMember(addonEntries, 'package/prebuilds/oliphaunt_wasix_napi.node'); + const addonProvenance = JSON.parse(addonMember('package/artifact-provenance.json').toString()); + const heldSource = + !napi.current && addonProvenance.schema === 'oliphaunt-wasix-napi-construction-data-v3'; + const constructed = + napi.current || + heldSource || + addonProvenance.schema === 'oliphaunt-wasix-napi-construction-data-v2'; + if (napi.current || heldSource) { + // Completed carriers retain their own historical SDK/extension contract; + // the original archive and facade identities were authenticated above. + const contract = heldSource + ? { + targetTriple: addonProvenance.buildInputs.targetTriple, + sdkVersion: addonProvenance.buildInputs.sdk.version, + sqlNames: addonProvenance.buildInputs.inputs.extensionArtifacts.flatMap((row: any) => + row.portableArchives.map((member: any) => member.sqlName), + ), + } + : napi.constructionContract; + assert(contract, 'source addon requires its actual producer construction contract'); + assertWasixNapiConstructionData( + addonProvenance, + napi.target.target, + digest(addonMember('package/prebuilds/oliphaunt_wasix_napi.node')), + { + ...contract, + runtimeVersion: addonManifest.oliphaunt.runtimeVersion, + }, + ); + } else { + if (!constructed) assert.equal(addonProvenance.schema, 'oliphaunt-wasix-napi-provenance-v1'); + assert.equal( + addonProvenance.buildInputs.schema, + constructed ? 'oliphaunt-wasix-napi-build-inputs-v2' : 'oliphaunt-wasix-napi-build-inputs-v1', + ); + } + assert.equal( + addonProvenance.buildInputs.inputs.portableManifest.sha256, + digest(hostManifestBytes), + ); + if (constructed) { + assert.equal( + addonProvenance.buildInputs.inputs.portableManifest.size, + hostManifestBytes.length, + ); + assert.equal( + addonProvenance.buildInputs.inputs.runtimeArchive.sha256, + hostManifest.runtime.sha256, + ); + assert( + Number.isSafeInteger(addonProvenance.buildInputs.inputs.runtimeArchive.size) && + addonProvenance.buildInputs.inputs.runtimeArchive.size > 0, + ); + } + assert.equal( + addonProvenance.binary.sha256, + digest(addonMember('package/prebuilds/oliphaunt_wasix_napi.node')), + ); + extractPortableArchiveTree( + addonArchive, + path.join(root, 'node_modules', addonManifest.name), + 'package', + ); + const env = { ...process.env, NODE_OPTIONS: '', NODE_PATH: '' }; + for (const key of Object.keys(env)) + if (/^(?:BUN_|RUNFILES|TEST_SRCDIR)/u.test(key)) delete env[key]; + const result = Bun.spawnSync( + [ + realpathSync(node), + '--experimental-strip-types', + '--preserve-symlinks-main', + realpathSync(consumerInput), + addonManifest.name, + spec.product, + spec.sqlName, + realpathSync(input), + realpathSync(frozenInput), + realpathSync(fixtureInput), + realpathSync(hostManifestInput), + ], + { cwd: root, env, stdout: 'pipe', stderr: 'pipe', timeout: 240_000 }, + ); + assert.equal(result.exitCode, 0, `${result.stderr.toString()}\n${result.stdout.toString()}`); + console.log(result.stdout.toString().trim()); + console.log( + compiled + ? 'Real compiled WASIX portable + four AOT Cargo/npm carriers preserve exact compiler bytes and installed owner/version contracts: PASS' + : 'Real SQL-only WASIX portable Cargo/npm/GitHub carriers preserve exact installed owner/version contracts: PASS', + ); +} finally { + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/extensions/wasix/contrib_carriers.bzl b/build_defs/extensions/wasix/contrib_carriers.bzl new file mode 100644 index 000000000..7841fb3d8 --- /dev/null +++ b/build_defs/extensions/wasix/contrib_carriers.bzl @@ -0,0 +1,216 @@ +"""Runtime-owned WASIX contrib envelopes from the existing portable module graph.""" + +load("@oliphaunt_metadata//:metadata.bzl", "CONTRIB_MEMBERS", "EXTENSION_RELEASE_METADATA", "PRODUCTS", "PUBLICATION_CARRIERS") +load("@wasix_tool_metadata//:targets.bzl", "WASIX_AOT_TARGETS") +load("//build_defs/extensions:contrib_carriers.bzl", "native_contrib_carrier_legal", "native_contrib_carrier_metadata") +load("//build_defs/extensions:extensions.bzl", "extension_identity") +load("//build_defs/extensions:final_leaf.bzl", "ExtensionFinalLeafInfo") +load("//build_defs/extensions:wasix_carriers.bzl", "WasixExtensionHostInfo", "wasix_sql_carrier_helpers") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") +load("//build_defs/foundation:bun.bzl", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/release:identity.bzl", "ReleaseIdentityInfo") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") +load("//build_defs/release:supplier.bzl", "ShippingSupplierInfo") +load("//build_defs/wasix:aot.bzl", "WasixAotInfo", "wasix_aot") +load("//build_defs/wasix:platform.bzl", "WASIX_PORTABLE_TRANSITION") +load("//build_defs/wasix:wasm.bzl", "WasmModuleInfo") +load("//build_defs/wasix:npm.bzl", "RUNTIME_NPM_NOTICES") + +def _metadata(): + spec = native_contrib_carrier_metadata("wasix-portable", family = "wasix") + releases = {row["sqlName"]: row for row in EXTENSION_RELEASE_METADATA if row["class"] == "contrib"} + spec["releaseMetadata"] = releases[spec["expectedMembers"][0]] + spec["carriers"] = [row for row in spec["carriers"] if row["target"] == "wasix-portable" or (row["ecosystem"] == "cargo" and row["role"] == "aot-leaf") or (row["ecosystem"] == "npm" and row["name"] == spec["releaseMetadata"]["npmPackage"] + "-wasix")] + for member in spec["members"]: + member["releaseMetadata"] = releases[member["sqlName"]] + member["source"] = dict(member["source"]) + member["source"]["extension-control"] = {"default-version": member["contrib"].get("default-version")} + member["recipe"] = {"artifacts": {"data_files": member["contrib"].get("data-files", [])}} + member["carriers"] = spec["carriers"] + return spec + +def _carriers_impl(ctx): + spec = _metadata() + owner = ctx.attr.owner[ReleaseIdentityInfo] + host = ctx.attr.host[WasixExtensionHostInfo] + if owner.id != spec["owner"] or owner.version != spec["version"]: + fail("WASIX contrib bundle differs from its canonical runtime owner") + if host.version != spec["version"] or host.version != spec["compatibility"]["wasix_runtime_version"]: + fail("WASIX contrib requires its current runtime owner's exact host") + modules = {target[WasmModuleInfo].module.basename: target[WasmModuleInfo].module for target in ctx.attr.modules} + expected = [member["contrib"]["module-file"] for member in spec["members"]] + if len(modules) != len(ctx.attr.modules) or sorted(modules.keys()) != sorted(expected): + fail("WASIX contrib must consume all canonical portable members exactly once") + resource_names = [member["sqlName"] for member in spec["members"] if member["descriptor"]["lifecycle"]["create-extension"] or member["contrib"].get("data-files", [])] + if sorted(ctx.attr.resources.values()) != sorted(resource_names): + fail("WASIX contrib requires every canonical resource producer exactly once") + resources = {name: [] for name in spec["expectedMembers"]} + resources.update({sql_name: target[DefaultInfo].files.to_list() for target, sql_name in ctx.attr.resources.items()}) + images = [target[WasixAotInfo] for target in ctx.attr.aot] + if len(images) != len(spec["members"]) * len(WASIX_AOT_TARGETS): + fail("WASIX contrib requires only its complete canonical AOT cohort") + image_files = [file for image in images for file in [image.image, image.module]] + member_inputs = [] + links = [] + resource_files = [] + for member in spec["members"]: + sql_name = member["sqlName"] + module = modules[member["contrib"]["module-file"]] + module_rows = [{"name": sql_name, "path": module.path, "runtime_path": "lib/postgresql/" + module.basename}] + link_spec = ctx.actions.declare_file(ctx.label.name + "/links/" + sql_name + ".inputs.json") + link = ctx.actions.declare_file(ctx.label.name + "/links/" + sql_name + ".json") + ctx.actions.write(link_spec, json.encode({"sql_name": sql_name, "runtime": host.module.path, "runtime_manifest": host.manifest.path, "modules": module_rows})) + args = ctx.actions.args() + args.add_all(["assets", "declared-extension-link", "--spec", link_spec, "--output", link]) + ctx.actions.run(executable = ctx.executable._analyzer, arguments = [args], inputs = [module, host.module, host.manifest, link_spec], outputs = [link], mnemonic = "WasixContribLinkContract") + links.append(link) + member_resources = [] + data = {destination.split("/")[-1]: destination for destination in member["contrib"].get("data-files", [])} + for file in resources[sql_name]: + if file.is_directory: + fail("WASIX contrib resources require exact upstream files") + if file.basename.endswith(".control") or file.basename.endswith(".sql"): + destination = "share/postgresql/extension/" + file.basename + elif file.basename in data: + destination = data[file.basename] + else: + fail("WASIX contrib resource has no canonical destination: " + file.basename) + member_resources.append({"source": file.path, "destination": destination}) + resource_files += resources[sql_name] + member_images = [image for image in images if image.module.path == module.path] + if len(member_images) != len(WASIX_AOT_TARGETS) or sorted([image.target for image in member_images]) != sorted(WASIX_AOT_TARGETS.values()): + fail("WASIX contrib member requires its exact four serialized AOT targets") + member.update({"operation": "compiled", "modules": module_rows, "resources": member_resources, "link": link.path, "toolchain": ctx.file.toolchain.path, + "aot": [{"target": image.target, "image": image.image.path, "module": module.path, "name": "extension:" + sql_name} for image in member_images]}) + member_inputs += [module, link] + outputs = {"npm": [], "cargo": []} + carrier_groups = {} + for index, row in enumerate(spec["carriers"]): + suffix = ".tgz" if row["ecosystem"] == "npm" else ".crate" + filename = row["name"].replace("@", "").replace("/", "-") + "-" + spec["version"] + suffix + file = ctx.actions.declare_file(ctx.label.name + "/" + row["ecosystem"] + "/" + filename) + outputs[row["ecosystem"]].append(file) + carrier_groups["carrier_" + str(index)] = depset([file]) + if len(outputs["npm"]) != 1 or len(outputs["cargo"]) != len(WASIX_AOT_TARGETS) + 1: + fail("WASIX contrib requires its canonical npm portable and Cargo portable/AOT carriers") + outputs["github"] = [ctx.actions.declare_file(ctx.label.name + "/release-assets/" + spec["product"] + "-" + spec["version"] + "-wasix-wasix-portable-bundle.tar.gz")] + outputs["manifest"] = [ctx.actions.declare_file(ctx.label.name + "/" + spec["product"] + "-" + spec["version"] + "-manifest.json")] + outputs["frozen"] = [ctx.actions.declare_file(ctx.label.name + "/extension-artifacts.json")] + output_files = [file for files in outputs.values() for file in files] + spec.update({"operation": "contrib", "outputs": {name: files[0].dirname if name in ["npm", "cargo"] else files[0].path for name, files in outputs.items()}}) + for member in spec["members"]: + member["outputs"] = spec["outputs"] + inputs = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(inputs, json.encode(spec)) + bun_file_action(ctx, ctx.file._tool, arguments = [inputs.path], inputs = member_inputs + resource_files + image_files + [inputs, ctx.file.toolchain] + ctx.files.legal, + source_files = [ctx.file._tool] + ctx.files._helpers + ctx.files.legal, outputs = output_files, mnemonic = "WasixContribEnvelopes") + return [DefaultInfo(files = depset(output_files)), ctx.attr._suppliers[ShippingSupplierInfo], + ExtensionFinalLeafInfo(product = spec["product"], owner = owner.id, version = owner.version, family = "wasix", target = "wasix-portable", metadata = spec, + github = outputs["github"], npm = outputs["npm"], cargo = outputs["cargo"], manifest = outputs["manifest"][0], frozen = outputs["frozen"][0], spec = inputs, validation = None, receipt = None, origin = None), + OutputGroupInfo(**{name: depset(files) for name, files in outputs.items()} | carrier_groups | {"spec": depset([inputs]), "link": depset(links)})] + +_wasix_contrib_carriers = rule(implementation = _carriers_impl, toolchains = BUN_SOURCE_TOOLCHAINS, attrs = { + "modules": attr.label_list(mandatory = True, providers = [WasmModuleInfo], cfg = WASIX_PORTABLE_TRANSITION), + "resources": attr.label_keyed_string_dict(mandatory = True, allow_files = True), "aot": attr.label_list(mandatory = True, providers = [WasixAotInfo]), + "host": attr.label(mandatory = True, providers = [WasixExtensionHostInfo]), "owner": attr.label(mandatory = True, providers = [ReleaseIdentityInfo]), "legal": attr.label_list(allow_files = True), + "toolchain": attr.label(default = "//src/wasix/runtime:toolchain.toml", allow_single_file = True), + "_tool": attr.label(default = "//build_defs/extensions/wasix:contrib_carriers.mts", allow_single_file = True), + "_helpers": attr.label_list(default = wasix_sql_carrier_helpers() + ["//build_defs/extensions:wasix_carriers.mts", "//:src/extensions/artifacts/packages/tools/bundle-carrier-assets.mts", "//:src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts"], allow_files = True), + "_analyzer": attr.label(default = "//src/wasix/runtime/tools/xtask:xtask", executable = True, cfg = "exec"), + "_suppliers": attr.label(default = "//build_defs/release:no_suppliers", providers = [ShippingSupplierInfo]), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), +}) + +def wasix_contrib_extension_carriers(name, host): + """Package all 32 existing members together under the current WASIX runtime.""" + modules = [] + resources = {} + aot = [] + for member in CONTRIB_MEMBERS: + module = "//src/wasix/runtime:contrib_" + member["id"] + modules.append(module) + if member.get("default-version"): + resources["@postgres_wasix//:contrib_" + member["contrib-dir"].replace("-", "_") + "_resources"] = member["sql-name"] + for target_id in WASIX_AOT_TARGETS: + image = name + "_aot_" + target_id.replace("-", "_") + "_" + member["id"] + wasix_aot(name = image, module = module, target_id = target_id, output_name = member["sql-name"] + "-llvm-opta.bin.zst", + exec_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64", "@zig_sdk//libc:gnu.2.34"]) + aot.append(":" + image) + _wasix_contrib_carriers(name = name, modules = modules, resources = resources, aot = aot, host = host, + owner = extension_identity(CONTRIB_MEMBERS[0]["sql-name"], family = "wasix"), legal = native_contrib_carrier_legal(), + exec_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"]) + +def _installed_impl(ctx): + leaf = ctx.attr.leaf[ExtensionFinalLeafInfo] + host = ctx.attr.host[WasixExtensionHostInfo] + binary = ctx.attr.binary[DefaultInfo].files_to_run.executable + if len(leaf.cargo) != len(WASIX_AOT_TARGETS) + 1 or any([file.is_directory for file in leaf.cargo]): + fail("contrib installed test requires its exact five regular Cargo carriers") + arguments = [leaf.spec, leaf.npm[0], leaf.cargo[0], leaf.frozen, host.module, host.manifest, binary] + files = leaf.github + leaf.npm + leaf.cargo + [leaf.spec, leaf.frozen, host.module, host.manifest, binary] + ctx.files._helpers + runfiles = ctx.attr.binary[DefaultInfo].default_runfiles + incremental = ctx.attr.server_binary != None + if incremental != (ctx.attr.tools_portable != None) or incremental != (ctx.attr.tools_aot != None): + fail("contrib incremental proof requires both final tools carriers and its server binary") + if incremental: + target = WASIX_AOT_TARGETS["linux-x64-gnu"] + rows = [row for row in PUBLICATION_CARRIERS if row["product"] == "postgres-tools-wasix" and row["ecosystem"] == "cargo"] + portable = [row for row in rows if row["target"] == None] + aot = [row for row in rows if row["target"] == target] + if len(portable) != 1 or len(aot) != 1: + fail("incremental contrib proof requires its unique canonical tools Cargo identities") + tools = ctx.actions.declare_file(ctx.label.name + ".tools.json") + ctx.actions.write(tools, json.encode({"version": PRODUCTS["postgres-tools-wasix"]["version"], "runtimeVersion": host.version, + "portableName": portable[0]["name"], "aotName": aot[0]["name"], "target": target})) + server = ctx.attr.server_binary[DefaultInfo].files_to_run.executable + arguments += [tools, ctx.file.tools_portable, ctx.file.tools_aot, server] + files += [tools, ctx.file.tools_portable, ctx.file.tools_aot, server] + ctx.files.additional_helpers + runfiles = runfiles.merge(ctx.attr.server_binary[DefaultInfo].default_runfiles) + elif ctx.files.additional_helpers: + fail("ordinary contrib lifecycle proof must not carry unused incremental helpers") + return bun_test_entrypoint(ctx, ctx.file._runner, arguments, files, + source_files = [ctx.file._runner] + ctx.files._helpers + ctx.files.additional_helpers, additional_runfiles = runfiles) + +_wasix_contrib_installed_test = rule(implementation = _installed_impl, test = True, toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "leaf": attr.label(mandatory = True, providers = [ExtensionFinalLeafInfo]), "host": attr.label(mandatory = True, providers = [WasixExtensionHostInfo]), + "binary": attr.label(default = "//src/wasix/sdks/rust:extension_carrier_unit_test", executable = True, cfg = "target"), + "server_binary": attr.label(executable = True, cfg = "target"), + "tools_portable": attr.label(allow_single_file = [".crate"]), + "tools_aot": attr.label(allow_single_file = [".crate"]), + "additional_helpers": attr.label_list(allow_files = True), + "_runner": attr.label(default = "//build_defs/extensions/wasix:contrib_installed.test.mts", allow_single_file = True), + "_helpers": attr.label_list(default = wasix_sql_carrier_helpers(), allow_files = True), + })) + +def wasix_contrib_extension_installed_test(name, **kwargs): + _wasix_contrib_installed_test(name = name, args = bun_test_entrypoint_args(name), **kwargs) + +def wasix_contrib_extension_incremental_installed_test(name, **kwargs): + """Run logical restore and server cases from one shared extracted contrib packet.""" + wasix_contrib_extension_installed_test(name = name, + binary = "//src/wasix/sdks/rust:extension_carrier_tools_unit_test", + server_binary = "//src/wasix/pgwire-server:contrib_carrier_server_test", + tools_portable = "//src/wasix/postgres-tools:portable_cargo", + tools_aot = "//src/wasix/postgres-tools:linux_x64_gnu_cargo", + additional_helpers = ["//src/wasix/postgres-tools:tools/package-assets.mts", "//src/wasix/runtime:tools/package-release-assets.mts"] + RUNTIME_NPM_NOTICES.keys(), + **kwargs) + +def wasix_contrib_extension_shipping(name, carriers, qualification): + """Expose canonical runtime-owned bundle Files through existing shipping rules.""" + spec = _metadata() + owner = extension_identity(CONTRIB_MEMBERS[0]["sql-name"], family = "wasix") + packages = [] + for index, row in enumerate(spec["carriers"]): + package = name + "_" + row["ecosystem"] + "_shipping_" + str(index) + native.filegroup(name = package + "_files", srcs = [carriers], output_group = "carrier_" + str(index)) + shipping_package(name = package, owner = owner, artifacts = [":" + package + "_files"], ecosystem = row["ecosystem"], package_name = row["name"], configuration = row["target"] or "portable", role = row["role"], suppliers = carriers) + packages.append(":" + package) + for group in ["github", "manifest", "frozen"]: + package = name + "_" + group + "_shipping" + native.filegroup(name = package + "_files", srcs = [carriers], output_group = group) + package_name = spec["product"] + "-" + spec["version"] + "-wasix-" + spec["target"] + "-bundle.tar.gz" if group == "github" else "contrib-wasix-" + group + shipping_package(name = package, owner = owner, artifacts = [":" + package + "_files"], ecosystem = "github" if group == "github" else "internal", package_name = package_name, + configuration = spec["target"], role = "github-release-asset" if group == "github" else "extension-release-" + group + "-input", suppliers = carriers) + packages.append(":" + package) + shipping_export(name = name + "_shipping_export", packages = packages, qualification = qualification, testonly = True) diff --git a/build_defs/extensions/wasix/contrib_carriers.mts b/build_defs/extensions/wasix/contrib_carriers.mts new file mode 100644 index 000000000..653d251e2 --- /dev/null +++ b/build_defs/extensions/wasix/contrib_carriers.mts @@ -0,0 +1,215 @@ +/** Runtime-owned WASIX contrib envelopes from the complete declared module cohort. */ +import assert from 'node:assert/strict'; +import { copyFileSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { composeExtensionReleaseDocuments } from '../../../src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts'; +import { bundleCarrierAssets } from '../../../src/extensions/artifacts/packages/tools/bundle-carrier-assets.mts'; +import { stageExtensionWasixNpmPackages } from '../../../src/extensions/artifacts/packages/tools/package-extension-release-carriers.mts'; +import { packageDeclaredWasixExtensionCargo } from '../../../src/wasix/runtime/tools/package_liboliphaunt_wasix_cargo_artifacts.mts'; +import { AOT_TARGET_TRIPLES } from '../../../src/wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; +import { readPortableArchiveEntries } from '../../../tools/packaging/portable-archive.mts'; +import { extensionCompatibilityMetadata } from '../../../tools/release/extension-release-metadata.mts'; +import { stageCompiledWasixMember, type WasixCompiledCarrierSpec } from '../wasix_carriers.mts'; + +interface WasixContribMemberSpec extends WasixCompiledCarrierSpec { + owner: string; + runtimeVersion: string; + contrib: Record; +} + +export interface WasixContribCarrierSpec + extends Omit { + operation: 'contrib'; + owner: string; + runtimeVersion: string; + expectedMembers: string[]; + members: WasixContribMemberSpec[]; + sourceIdentity: Record; +} + +function writeJson(file: string, value: unknown) { + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`); +} + +export function validateWasixContribInputs(spec: WasixContribCarrierSpec) { + assert.equal(spec.product, 'oliphaunt-extension-contrib-pg18'); + assert.equal(spec.owner, 'liboliphaunt-wasix'); + assert.equal(spec.target, 'wasix-portable'); + assert.equal(spec.version, spec.runtimeVersion, 'contrib follows its runtime owner version'); + assert.equal(spec.version, spec.compatibility.wasix_runtime_version); + assert.equal(spec.owner, spec.compatibility.wasix_runtime_product); + assert.equal(spec.releaseMetadata.class, 'contrib'); + assert.equal(spec.releaseMetadata.versioning, 'runtime-bound'); + assert.deepEqual( + spec.releaseMetadata.compatibility, + extensionCompatibilityMetadata(spec.compatibility), + ); + assert.equal( + spec.expectedMembers.length, + 32, + 'contrib must contain the complete canonical inventory', + ); + assert.equal(new Set(spec.expectedMembers).size, spec.expectedMembers.length); + assert.deepEqual(spec.members.map((member) => member.sqlName).sort(), spec.expectedMembers); + for (const member of spec.members) { + assert.equal(member.owner, spec.owner); + assert.equal(member.product, spec.product); + assert.equal(member.version, spec.version); + assert.equal(member.runtimeVersion, spec.runtimeVersion); + assert.equal(member.target, spec.target); + assert.deepEqual(member.compatibility, spec.compatibility); + assert.equal(member.descriptor['source-kind'], 'postgres-contrib'); + assert.equal(member.contrib['sql-name'], member.sqlName); + assert.equal(member.descriptor['native-module-file'], member.contrib['module-file']); + assert.deepEqual(member.recipe.artifacts.data_files, member.contrib['data-files'] ?? []); + assert.deepEqual(member.releaseMetadata.sourceIdentity, spec.sourceIdentity); + if (member.descriptor.lifecycle['create-extension']) + assert.equal( + member.source['extension-control']['default-version'], + member.contrib['default-version'], + ); + } + const npm = spec.carriers.filter((row) => row.ecosystem === 'npm'); + const cargo = spec.carriers.filter((row) => row.ecosystem === 'cargo'); + assert.equal(npm.length, 1, 'contrib has one canonical npm portable bundle'); + assert.equal(npm[0].name, '@oliphaunt/extension-contrib-pg18-wasix'); + assert.equal(npm[0].target, null); + assert.equal(npm[0].role, 'facade'); + assert.equal(cargo.length, Object.keys(AOT_TARGET_TRIPLES).length + 1); + assert.equal( + new Set(spec.carriers.map((row) => `${row.ecosystem}:${row.name}`)).size, + spec.carriers.length, + ); + for (const row of spec.carriers) { + assert.equal(row.product, spec.owner); + assert.equal(row.version, spec.version); + } + assert.equal( + path.basename(spec.outputs.github), + `${spec.product}-${spec.version}-wasix-wasix-portable-bundle.tar.gz`, + ); +} + +export async function packageWasixContribCarriers(spec: WasixContribCarrierSpec) { + validateWasixContribInputs(spec); + const root = mkdtempSync( + path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'wasix-contrib-envelopes-'), + ); + try { + const productRoot = path.join(root, 'product'); + const staged = []; + for (const member of spec.members) { + const row = await stageCompiledWasixMember( + member, + [], + productRoot, + path.join(productRoot, 'member-assets', member.sqlName), + ); + staged.push(row); + } + const members = staged.map(({ member, archive }) => ({ + ...member, + assets: member.assets.map((asset) => ({ + ...asset, + path: path.relative(root, archive).split(path.sep).join('/'), + })), + })); + const compatibility = extensionCompatibilityMetadata(spec.compatibility); + mkdirSync(path.join(productRoot, 'release-assets'), { recursive: true }); + const assets = bundleCarrierAssets( + spec.product, + spec.version, + productRoot, + members, + compatibility, + { root }, + ); + assert.equal(assets.length, 1, 'contrib must produce one complete portable bundle'); + assert.equal(assets[0].memberCount, spec.expectedMembers.length); + assert.equal(assets[0].name, path.basename(spec.outputs.github)); + const { manifest, releaseData } = composeExtensionReleaseDocuments({ + product: spec.product, + releaseProduct: spec.owner, + family: 'wasix', + version: spec.version, + members, + directAssets: assets, + releaseMetadata: spec.releaseMetadata, + sourceIdentity: spec.sourceIdentity, + }); + const frozen = path.join(productRoot, 'extension-artifacts.json'); + const releaseManifest = path.join( + productRoot, + 'release-assets', + path.basename(spec.outputs.manifest), + ); + writeJson(frozen, manifest); + writeJson(releaseManifest, releaseData); + const result = { staged: [] as string[], skipped: [] as string[] }; + assert(stageExtensionWasixNpmPackages([productRoot], path.join(root, 'npm-stage'), result)); + assert.equal(result.staged.length, 1, 'contrib must retain its single canonical npm bundle'); + mkdirSync(spec.outputs.npm, { recursive: true }); + const npm = result.staged[0]; + const npmEntry = readPortableArchiveEntries(npm).get('package/package.json'); + assert( + npmEntry?.isFile && !npmEntry.isSymbolicLink, + 'npm bundle must contain a regular manifest', + ); + const npmMetadata = JSON.parse(npmEntry.data().toString()); + const npmRow = spec.carriers.find((row) => row.ecosystem === 'npm'); + assert(npmRow, 'npm bundle must retain its declared carrier identity'); + assert.equal(npmMetadata.name, npmRow.name); + assert.equal(npmMetadata.version, spec.version); + copyFileSync(npm, path.join(spec.outputs.npm, path.basename(npm))); + const cargo = packageDeclaredWasixExtensionCargo( + { + product: spec.product, + version: spec.version, + runtimeProduct: spec.owner, + runtimeVersion: spec.runtimeVersion, + versioning: 'runtime-bound', + extensionRoot: productRoot, + members: staged.map(({ member, archive, asset, wasixInstall }) => ({ + sqlName: member.sqlName, + dependencies: member.dependencies, + nativeModuleStem: member.nativeModuleStem, + archive, + sha256: asset.sha256, + size: asset.bytes, + install: wasixInstall, + })), + }, + { outputDir: path.join(root, 'cargo-stage'), workDir: path.join(root, 'cargo-work') }, + ); + const expectedCargo = spec.carriers + .filter((row) => row.ecosystem === 'cargo') + .map((row) => row.name) + .sort(); + assert.deepEqual( + cargo.map((row) => row.name).sort(), + expectedCargo, + 'measured contrib carriers must retain exactly five canonical Cargo identities; split parts require declared outputs', + ); + mkdirSync(spec.outputs.cargo, { recursive: true }); + for (const row of cargo) { + copyFileSync(row.cratePath, path.join(spec.outputs.cargo, path.basename(row.cratePath))); + } + for (const [source, destination] of [ + [path.join(root, assets[0].path), spec.outputs.github], + [frozen, spec.outputs.frozen], + [releaseManifest, spec.outputs.manifest], + ]) { + mkdirSync(path.dirname(destination), { recursive: true }); + copyFileSync(source, destination); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + assert.equal(process.argv.length, 3, 'usage: contrib_carriers.mts '); + await packageWasixContribCarriers(JSON.parse(readFileSync(process.argv[2], 'utf8'))); +} diff --git a/build_defs/extensions/wasix/contrib_installed.test.mts b/build_defs/extensions/wasix/contrib_installed.test.mts new file mode 100644 index 000000000..23cedd2fd --- /dev/null +++ b/build_defs/extensions/wasix/contrib_installed.test.mts @@ -0,0 +1,326 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + realpathSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { + assertWasixExtensionArchiveInstall, + EXTENSION_RUNTIME_CONTRACT_SCHEMA, + WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA, +} from '../../../src/extensions/contracts/wasix-extension-install.mts'; +import { assertWasixAotArtifactPayloads } from '../../../src/wasix/runtime/tools/check-release-assets.mts'; +import { assertCanonicalWasixAotManifest } from '../../../src/wasix/runtime/tools/wasix-aot-manifest.mts'; +import { AOT_TARGET_TRIPLES } from '../../../src/wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; +import { readPortableArchiveEntries } from '../../../tools/packaging/portable-archive.mts'; + +assert( + [9, 13].includes(process.argv.length), + 'contrib installed test requires seven inputs or its four additional incremental inputs', +); +const [specInput, npmInput, cargoInput, frozenInput, coreInput, coreManifestInput, binary] = + process.argv.slice(2); +const [toolsSpecInput, toolsPortableInput, toolsAotInput, serverBinary] = process.argv.slice(9); +const incremental = process.argv.length === 13; +if (incremental) + assert([toolsSpecInput, toolsPortableInput, toolsAotInput, serverBinary].every(Boolean)); +const spec = JSON.parse(readFileSync(specInput, 'utf8')); +const frozen = JSON.parse(readFileSync(frozenInput, 'utf8')); +const root = mkdtempSync( + path.join(process.env.TEST_TMPDIR ?? os.tmpdir(), 'installed-wasix-contrib-'), +); +const digest = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +function write(relative: string, bytes: Uint8Array | string) { + const file = path.join(root, relative); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, bytes); + return file; +} +try { + assert.equal(spec.owner, 'liboliphaunt-wasix'); + assert.equal(spec.product, 'oliphaunt-extension-contrib-pg18'); + assert.equal(spec.version, spec.runtimeVersion); + assert.equal(frozen.product, spec.product); + assert.equal(frozen.version, spec.version); + assert.deepEqual(frozen.compatibility, spec.releaseMetadata.compatibility); + const core = JSON.parse(readFileSync(coreManifestInput, 'utf8')); + const coreModuleSha256 = digest(readFileSync(coreInput)); + assert.equal(core.runtime['module-sha256'], coreModuleSha256); + const npm = readPortableArchiveEntries(realpathSync(npmInput)); + const metadata = JSON.parse(npm.get('package/package.json')!.data().toString()); + assert.equal(metadata.name, '@oliphaunt/extension-contrib-pg18-wasix'); + assert.equal(metadata.version, spec.version); + assert.equal(metadata.oliphaunt.product, spec.product); + assert.equal(metadata.oliphaunt.kind, 'exact-extension-wasix-bundle'); + assert.equal(metadata.oliphaunt.runtime, 'wasix'); + assert.equal(metadata.oliphaunt.target, spec.target); + assert.equal(metadata.oliphaunt.wasixRuntimeProduct, spec.compatibility.wasix_runtime_product); + assert.equal(metadata.oliphaunt.wasixRuntimeVersion, spec.compatibility.wasix_runtime_version); + assert.equal(metadata.oliphaunt.runtimeBound, true); + assert.deepEqual([...metadata.oliphaunt.members].sort(), spec.expectedMembers); + assert.deepEqual(Object.keys(metadata.oliphaunt.carriers).sort(), spec.expectedMembers); + assert.deepEqual( + frozen.extensions.map((row: { sqlName: string }) => row.sqlName).sort(), + spec.expectedMembers, + ); + const archives = spec.expectedMembers.map((sqlName: string) => { + const carrier = metadata.oliphaunt.carriers[sqlName]; + const member = frozen.extensions.find((row: { sqlName: string }) => row.sqlName === sqlName); + assert.deepEqual( + member.dataFiles.map((relative: string) => `share/postgresql/${relative}`).sort(), + member.wasixInstall.installedFiles + .filter( + (relative: string) => + relative.startsWith('share/postgresql/') && + !relative.startsWith('share/postgresql/extension/'), + ) + .sort(), + `${sqlName} frozen auxiliary data must name its exact physical installation inventory`, + ); + const entry = npm.get(`package/${carrier.path}`); + assert(entry?.isFile && !entry.isSymbolicLink); + const bytes = Buffer.from(entry.data()); + assertWasixExtensionArchiveInstall(bytes, { + schema: WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA, + sqlName, + archive: `extensions/${sqlName}.tar.zst`, + sha256: carrier.sha256, + size: carrier.size, + install: member.wasixInstall, + }); + return { sqlName, path: write(`npm/${carrier.path}`, bytes), sha256: carrier.sha256 }; + }); + for (const sqlName of spec.expectedMembers) { + const relative = metadata.oliphaunt.memberExports[sqlName]; + assert.equal(relative, `./${sqlName}`); + const descriptorPath = metadata.exports[relative].import; + assert.equal(descriptorPath, `./descriptors/${sqlName}.js`); + const descriptorEntry = npm.get(`package/${descriptorPath.slice(2)}`); + assert(descriptorEntry?.isFile && !descriptorEntry.isSymbolicLink); + const descriptorFile = write(`npm/${descriptorPath.slice(2)}`, descriptorEntry.data()); + const { default: descriptor } = await import(pathToFileURL(descriptorFile).href); + assert.equal(descriptor.schema, metadata.oliphaunt.descriptorSchema); + assert.equal(descriptor.runtime, metadata.oliphaunt.runtime); + assert.equal(descriptor.product, spec.product); + assert.equal(descriptor.version, spec.version); + assert.equal(descriptor.sqlName, sqlName); + assert.deepEqual(descriptor.compatibility, { + extensionRuntimeContract: EXTENSION_RUNTIME_CONTRACT_SCHEMA, + postgresMajor: frozen.compatibility.postgresMajor, + wasixRuntimeProduct: frozen.compatibility.wasixRuntimeProduct, + wasixRuntimeVersion: frozen.compatibility.wasixRuntimeVersion, + }); + assert(descriptor.carriers.some((carrier: { sqlName: string }) => carrier.sqlName === sqlName)); + assert.equal( + new Set(descriptor.carriers.map((carrier: { sqlName: string }) => carrier.sqlName)).size, + descriptor.carriers.length, + ); + for (const carrier of descriptor.carriers) { + const member = frozen.extensions.find( + (row: { sqlName: string }) => row.sqlName === carrier.sqlName, + ); + const archive = archives.find((row: { sqlName: string }) => row.sqlName === carrier.sqlName); + assert(member && archive, 'public descriptor references an undeclared contrib member'); + assert.equal(carrier.product, spec.product); + assert.equal(carrier.version, spec.version); + assert.equal(carrier.archive, `extensions/${carrier.sqlName}.tar.zst`); + assert.equal(carrier.sha256, archive.sha256); + assert.equal(carrier.size, readFileSync(archive.path).length); + assert.equal(carrier.source.href, pathToFileURL(archive.path).href); + assert.deepEqual(carrier.install, member.wasixInstall); + } + } + const crates = readdirSync(path.dirname(cargoInput)) + .filter((name) => name.endsWith('.crate')) + .map((name) => path.join(path.dirname(cargoInput), name)); + const cargoRows = crates.map((file) => { + const entries = readPortableArchiveEntries(realpathSync(file)); + const prefix = path.basename(file, '.crate'); + const cargo = Bun.TOML.parse(entries.get(`${prefix}/Cargo.toml`)!.data().toString()); + assert.equal(cargo.package.version, spec.version); + return { name: cargo.package.name, prefix, entries }; + }); + const base = spec.carriers.filter((row: { ecosystem: string }) => row.ecosystem === 'cargo'); + assert.deepEqual( + cargoRows.map((row) => row.name).sort(), + base.map((row: { name: string }) => row.name).sort(), + ); + const portable = cargoRows.find((row) => row.name.endsWith('-wasix'))!; + for (const archive of archives) + assert.deepEqual( + portable.entries + .get(`${portable.prefix}/payload/files/extensions/${archive.sqlName}/extension.tar.zst`)! + .data(), + readFileSync(archive.path), + 'Cargo and npm contrib portable bytes differ', + ); + let host: { aotManifest: string; aotArtifacts: { path: string; source: string }[] } | undefined; + for (const target of Object.values(AOT_TARGET_TRIPLES)) { + const row = base.find((row: { target: string }) => row.target === target); + assert(row, 'missing canonical contrib AOT identity'); + const owner = cargoRows.find((carrier) => carrier.name === row.name)!; + const files = new Map(); + for (const [name, entry] of owner.entries) + if (name.startsWith(`${owner.prefix}/payload/files/`) && entry.isFile) + files.set(name.slice(`${owner.prefix}/payload/files/`.length), Buffer.from(entry.data())); + const manifests = spec.expectedMembers.map((sqlName: string) => { + const manifest = JSON.parse( + owner.entries.get(`${owner.prefix}/manifests/${sqlName}.json`)!.data().toString(), + ); + assertCanonicalWasixAotManifest(manifest, { expectedTarget: target }); + assertWasixAotArtifactPayloads(manifest, { + readArtifact: (relative: string) => files.get(`extensions/${sqlName}/${relative}`)!, + }); + const member = frozen.extensions.find( + (member: { sqlName: string }) => member.sqlName === sqlName, + ); + assert.equal(manifest.artifacts.length, member.wasixInstall.nativeModules.length); + for (const artifact of manifest.artifacts) + assert.equal( + artifact['module-sha256'], + member.wasixInstall.nativeModules.find( + (module: { name: string }) => + artifact.name === + `extension:${sqlName}${module.name === sqlName ? '' : `:${module.name}`}`, + ).moduleSha256, + ); + return { + ...manifest, + artifacts: manifest.artifacts.map((artifact: { path: string }) => ({ + ...artifact, + path: `extensions/${sqlName}/${artifact.path}`, + })), + }; + }); + const header = (manifest: { artifacts: unknown }) => { + const { artifacts: _artifacts, ...rest } = manifest; + return rest; + }; + for (const manifest of manifests) assert.deepEqual(header(manifest), header(manifests[0])); + const merged = { + ...header(manifests[0]), + artifacts: manifests.flatMap((manifest: { artifacts: unknown[] }) => manifest.artifacts), + }; + assertCanonicalWasixAotManifest(merged, { expectedTarget: target }); + assertWasixAotArtifactPayloads(merged, { + readArtifact: (relative: string) => files.get(relative)!, + }); + if (target === 'x86_64-unknown-linux-gnu') + host = { + aotManifest: write('host-aot/manifest.json', JSON.stringify(merged)), + aotArtifacts: merged.artifacts.map((artifact: { path: string }) => ({ + path: artifact.path, + source: write(`host-aot/${artifact.path}`, files.get(artifact.path)!), + })), + }; + } + assert(host, 'installed contrib test requires its declared GNU host cohort'); + const packet = write( + 'packet.json', + JSON.stringify({ + product: spec.product, + version: spec.version, + runtimeVersion: spec.runtimeVersion, + archives, + ...host, + coreModuleSha256, + coreManifest: realpathSync(coreManifestInput), + }), + ); + const run = (executable: string, test: string, extraEnv: Record = {}) => { + const result = Bun.spawnSync( + [realpathSync(executable), '--ignored', '--exact', test, '--nocapture', '--test-threads=1'], + { + env: { ...process.env, OLIPHAUNT_DECLARED_EXTENSION_PACKET: packet, ...extraEnv }, + cwd: process.cwd(), + stdout: 'pipe', + stderr: 'pipe', + timeout: 900000, + }, + ); + assert.equal(result.exitCode, 0, `${result.stderr.toString()}\n${result.stdout.toString()}`); + assert.match(result.stdout.toString(), /1 passed; 0 failed/u); + console.log(result.stdout.toString().trim()); + if (incremental && result.stderr.length) console.log(result.stderr.toString().trim()); + }; + if (incremental) { + const { validatePortableToolsPayload, validateToolsAotPayload } = await import( + '../../../src/wasix/postgres-tools/tools/package-assets.mts' + ); + const tools = JSON.parse(readFileSync(toolsSpecInput, 'utf8')); + assert.equal(tools.runtimeVersion, spec.runtimeVersion); + const extractTools = (input: string, name: string, directory: string) => { + const entries = readPortableArchiveEntries(realpathSync(input)); + const prefix = `${name}-${tools.version}`; + const cargo = Bun.TOML.parse(entries.get(`${prefix}/Cargo.toml`)!.data().toString()); + assert.equal(cargo.package.name, name); + assert.equal(cargo.package.version, tools.version); + for (const [member, entry] of entries) + if (member.startsWith(`${prefix}/${directory}/`)) { + assert(entry.isDirectory || (entry.isFile && !entry.isSymbolicLink)); + if (entry.isFile) + write( + `tools/${directory}/${member.slice(`${prefix}/${directory}/`.length)}`, + entry.data(), + ); + } + return path.join(root, 'tools', directory); + }; + const portable = extractTools(toolsPortableInput, tools.portableName, 'payload'); + const aot = extractTools(toolsAotInput, tools.aotName, 'artifacts'); + const sourceFingerprint = core['source-fingerprint']; + assert.equal(typeof sourceFingerprint, 'string'); + const portableManifest = validatePortableToolsPayload(portable, tools.version, { + runtimeVersion: tools.runtimeVersion, + sourceFingerprint, + }); + const aotManifest = validateToolsAotPayload(aot, tools.target, { sourceFingerprint }); + const tool = (key: 'pgDump' | 'psql') => { + const module = portableManifest[key]; + const image = aotManifest.artifacts.find( + (artifact: { name: string }) => artifact.name === `tool:${module.name}`, + ); + assert(image, 'declared tools AOT has no portable command identity'); + assert.equal(image['module-sha256'], module.sha256); + return { + wasm: path.join(portable, module.path), + aot: path.join(aot, image.path), + manifest: path.join(aot, 'manifest.json'), + }; + }; + const toolsPacket = write( + 'tools/packet.json', + JSON.stringify({ + version: tools.version, + runtimeVersion: tools.runtimeVersion, + pgDump: tool('pgDump'), + psql: tool('psql'), + }), + ); + run( + binary, + 'oliphaunt::extensions::extension_tests::declared_contrib_carriers_pass_logical_dump_restore', + { OLIPHAUNT_DECLARED_TOOLS_PACKET: toolsPacket }, + ); + run(serverBinary, 'declared_contrib_carriers_pass_server_smoke'); + console.log('Actual 32-member WASIX contrib logical dump/restore and pgwire server SQL: PASS'); + } else { + run( + binary, + 'oliphaunt::extensions::extension_tests::declared_contrib_carriers_pass_full_lifecycle', + ); + console.log( + 'Actual 32-member WASIX contrib npm/Cargo portable and four AOT cohorts with exact source-built core lifecycle: PASS', + ); + } +} finally { + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/extensions/wasix/installed_consumer.mts b/build_defs/extensions/wasix/installed_consumer.mts new file mode 100644 index 000000000..21469190a --- /dev/null +++ b/build_defs/extensions/wasix/installed_consumer.mts @@ -0,0 +1,274 @@ +import assert from 'node:assert/strict'; +import { existsSync, mkdirSync, readdirSync, readFileSync } from 'node:fs'; +import { createRequire } from 'node:module'; +import path from 'node:path'; +import { + connect, + onceClosed, + onceConnected, + readExchange, + simpleQuery, + startupPacket, +} from '../../../src/wasix/sdks/ts/tools/pgwire-client.mts'; + +const [addonName, product, sqlName, specPath, frozenPath, fixturePath, hostManifestPath] = + process.argv.slice(2); +assert.equal(process.argv.length, 9); +const hostManifest = JSON.parse(readFileSync(hostManifestPath, 'utf8')); +assert( + addonName && product && sqlName && specPath && frozenPath && fixturePath && hostManifestPath, +); +const spec = JSON.parse(readFileSync(specPath, 'utf8')); +const frozen = JSON.parse(readFileSync(frozenPath, 'utf8')); +assert.equal(spec.product, product); +assert.equal(spec.sqlName, sqlName); +assert.equal(frozen.product, product); +assert.equal(frozen.sqlName, sqlName); +const lifecycle = frozen.wasixInstall.lifecycle; +const defaultVersion = spec.source['extension-control']['default-version']; +const quoteIdentifier = (value: string) => `"${value.replaceAll('"', '""')}"`; +const quoteLiteral = (value: string) => `'${value.replaceAll("'", "''")}'`; +const fixture = readFileSync(fixturePath, 'utf8'); +const statements = (sql: string) => + sql + .split('-- oliphaunt-statement') + .map((statement) => statement.trim()) + .filter(Boolean); +const smoke = statements(fixture); +const verification = statements( + fixture.includes('-- oliphaunt-verify') + ? fixture.slice(fixture.indexOf('-- oliphaunt-verify') + '-- oliphaunt-verify'.length) + : fixture, +); +assert(smoke.length > 0 && verification.length > 0); +const startupGucs: Record = {}; +for (const assignment of lifecycle.startupConfig) { + const equals = assignment.indexOf('='); + assert(equals > 0, `invalid canonical startup assignment ${assignment}`); + const name = assignment.slice(0, equals); + const value = assignment.slice(equals + 1); + assert(!Object.hasOwn(startupGucs, name) || startupGucs[name] === value); + startupGucs[name] = value; +} +// The pinned host keeps directory-database runtime overlays in temporary workspaces. +const workspaces = path.join(process.cwd(), 'runtime-workspaces'); +mkdirSync(workspaces); +process.env.TMPDIR = workspaces; +const require = createRequire(path.join(process.cwd(), 'consumer-package.json')); +const addon = require(require.resolve(`${addonName}/oliphaunt_wasix_napi.node`)); +const addonManifest = require(require.resolve(`${addonName}/package.json`)); +assert.equal(addon.addonAbiVersion(), addonManifest.oliphaunt.addonAbiVersion); +assert.equal(addon.nodeApiVersion(), addonManifest.oliphaunt.nodeApiVersion); +assert.equal(addon.runtimeVersion(), spec.compatibility.wasix_runtime_version); +const runtimeIdentity = addon.payloadIdentity('runtimeArchive'); +assert.match(runtimeIdentity, /^[0-9a-f]{64}:[1-9][0-9]*$/u); +assert.equal( + runtimeIdentity.split(':')[0], + hostManifest.runtime.sha256, + 'executing addon embeds a different declared host archive', +); +const packageName = `@oliphaunt/${product.slice('oliphaunt-'.length)}-wasix`; +const packageJson = require.resolve(`${packageName}/package.json`); +const manifest = require(packageJson); +assert.equal(manifest.version, spec.version); +assert.equal(frozen.version, spec.version); +const carrier = manifest.oliphaunt.carriers[sqlName]; +const extensionPackage = { + sqlName, + product, + version: manifest.version, + packageJson, + archiveSha256: carrier.sha256, + archiveSize: carrier.size, + ...(frozen.wasixInstall.nativeModules.length > 0 + ? { aotPackageJson: require.resolve(`${packageName}-linux-x64-gnu/package.json`) } + : {}), +}; +const options = { + profile: 'standard', + storage: { kind: 'memory' }, + username: 'postgres', + database: 'postgres', + startupGucs, + extensions: [sqlName], + extensionPackages: [extensionPackage], +}; +function queryErrors(database: any, statement: string) { + const response = Buffer.from(database.execProtocolRaw(simpleQuery(statement))); + const errors: string[] = []; + let ready = false; + for (let offset = 0; offset < response.length; ) { + assert(offset + 5 <= response.length, 'truncated PostgreSQL response header'); + const length = response.readUInt32BE(offset + 1); + assert(length >= 4 && offset + length + 1 <= response.length); + const tag = String.fromCharCode(response[offset]); + if (tag === 'E') errors.push(response.subarray(offset + 5, offset + length + 1).toString()); + if (tag === 'Z') ready = true; + offset += length + 1; + } + assert(ready, 'PostgreSQL response has no ReadyForQuery'); + return errors; +} +function sql(database: any, statement: string) { + assert.deepEqual(queryErrors(database, statement), [], `${sqlName}: ${statement}`); +} + +type Execute = (statement: string) => void | Promise; +const stagedSql = `DO $$ BEGIN IF EXISTS (SELECT FROM pg_extension WHERE extname = ${quoteLiteral(sqlName)}) THEN RAISE EXCEPTION 'staging installed extension'; END IF; END $$`; +const versionSql = `DO $$ BEGIN IF (SELECT extversion FROM pg_extension WHERE extname = ${quoteLiteral(sqlName)}) IS DISTINCT FROM ${quoteLiteral(defaultVersion)} THEN RAISE EXCEPTION 'installed extension version differs from pinned source'; END IF; END $$`; +const stronger = + sqlName === 'pg_hashids' + ? [ + "DO $$ BEGIN IF id_encode(1001) IS DISTINCT FROM 'jNl' OR id_decode_once('jNl') IS DISTINCT FROM 1001 THEN RAISE EXCEPTION 'pg_hashids known roundtrip failed'; END IF; FOR i IN 1..2000 LOOP IF id_decode_once(id_encode(i)) IS DISTINCT FROM i OR id_decode(id_encode(ARRAY[i::bigint, (i + 1)::bigint])) IS DISTINCT FROM ARRAY[i::bigint, (i + 1)::bigint] THEN RAISE EXCEPTION 'pg_hashids repeated allocation failed'; END IF; END LOOP; END $$", + ] + : sqlName === 'pg_uuidv7' + ? [ + "DO $$ DECLARE id uuid; BEGIN id := uuid_generate_v7(); IF length(id::text) IS DISTINCT FROM 36 OR substring(id::text FROM 15 FOR 1) IS DISTINCT FROM '7' THEN RAISE EXCEPTION 'uuidv7 generation failed'; END IF; IF uuid_v7_to_timestamptz('018570bb-4a7d-7000-8000-000000000000') IS DISTINCT FROM timestamptz '2023-01-02 04:26:40.637+00' OR uuid_v7_to_timestamp('018570bb-4a7d-7000-8000-000000000000') IS DISTINCT FROM timestamp '2023-01-02 04:26:40.637' OR uuid_timestamptz_to_v7(timestamptz '2023-01-02 04:26:40.637+00', true) IS DISTINCT FROM uuid '018570bb-4a7d-7000-8000-000000000000' OR uuid_timestamp_to_v7(timestamp '2023-01-02 04:26:40.637', true) IS DISTINCT FROM uuid '018570bb-4a7d-7000-8000-000000000000' THEN RAISE EXCEPTION 'uuidv7 timestamp conversion failed'; END IF; END $$", + ] + : sqlName === 'vector' + ? [ + "DO $$ BEGIN IF current_setting('hnsw.ef_search', true) IS NULL OR current_setting('ivfflat.probes', true) IS NULL THEN RAISE EXCEPTION 'vector initializer did not register index options'; END IF; END $$", + ] + : sqlName === 'postgis' + ? [ + "DO $$ DECLARE i int; BEGIN IF ST_Distance(ST_GeomFromText('POINT(0 0)'), ST_GeomFromText('POINT(3 4)')) IS DISTINCT FROM 5 THEN RAISE EXCEPTION 'postgis geometry distance failed'; END IF; IF ST_Within(ST_GeomFromText('POINT(0.5 0.5)'), ST_GeomFromText('POLYGON((0 0,0 1,1 1,1 0,0 0))')) IS DISTINCT FROM true THEN RAISE EXCEPTION 'postgis within failed'; END IF; IF ST_SRID(ST_Transform(ST_SetSRID(ST_MakePoint(-71.060316, 48.432044), 4326), 3857)) IS DISTINCT FROM 3857 THEN RAISE EXCEPTION 'postgis transform failed'; END IF; IF (ST_Area(ST_Transform(ST_GeomFromText('POLYGON((-71.18 42.39,-71.18 42.40,-71.17 42.40,-71.17 42.39,-71.18 42.39))', 4326), 26986)) > 0) IS DISTINCT FROM true THEN RAISE EXCEPTION 'postgis projected area failed'; END IF; IF ST_NumGeometries(ST_Polygonize(ARRAY[ST_GeomFromText('LINESTRING(0 0,1 0)'), ST_GeomFromText('LINESTRING(1 0,1 1)'), ST_GeomFromText('LINESTRING(1 1,0 1)'), ST_GeomFromText('LINESTRING(0 1,0 0)')])) IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'postgis polygonize failed'; END IF; FOR i IN 1..200 LOOP IF (ST_Area(ST_Buffer(ST_MakePoint(i::float8, i::float8), 1)) > 3) IS DISTINCT FROM true OR (ST_X(ST_Transform(ST_SetSRID(ST_MakePoint(i::float8 / 1000, i::float8 / 1000), 4326), 3857)) > 0) IS DISTINCT FROM true THEN RAISE EXCEPTION 'postgis repeated GEOS/PROJ allocation failed'; END IF; END LOOP; END $$", + ] + : sqlName === 'pgtap' + ? [ + "DO $$ BEGIN IF num_failed() IS DISTINCT FROM 0 OR _get('curr_test') IS DISTINCT FROM 2 OR _get('plan') IS DISTINCT FROM 2 THEN RAISE EXCEPTION 'canonical pgTAP fixture failed or did not execute its exact plan'; END IF; END $$", + 'SELECT _cleanup()', + 'SELECT plan(2)', + "DO $$ BEGIN IF ok(true, 'declared SQL-only carrier executes') IS DISTINCT FROM 'ok 1 - declared SQL-only carrier executes' OR is(1, 1, 'declared SQL-only carrier compares') IS DISTINCT FROM 'ok 2 - declared SQL-only carrier compares' THEN RAISE EXCEPTION 'pgTAP returned a failing or missing assertion'; END IF; END $$", + 'SELECT * FROM finish(true)', + 'SELECT _cleanup()', + ] + : []; + +async function runStatements(execute: Execute, rows: string[]) { + for (const statement of rows) await execute(statement); +} +async function activate(execute: Execute) { + await execute(stagedSql); + await runStatements(execute, lifecycle.loadSql); + if (lifecycle.createExtension) { + const schema = lifecycle.createSchema; + if (schema && schema !== 'pg_catalog') + await execute(`CREATE SCHEMA IF NOT EXISTS ${quoteIdentifier(schema)}`); + await execute( + `CREATE EXTENSION ${quoteIdentifier(sqlName)}${schema ? ` WITH SCHEMA ${quoteIdentifier(schema)}` : ''}`, + ); + } + await runStatements(execute, lifecycle.postCreateSql); + if (lifecycle.createExtension) await execute(versionSql); + await runStatements(execute, [...smoke, ...stronger]); +} +async function verify(execute: Execute) { + if (lifecycle.createExtension) await execute(versionSql); + await runStatements(execute, [...verification, ...stronger]); +} +function assertSelectedModules() { + const prefix = 'lib/postgresql/'; + const expected = new Set( + frozen.wasixInstall.nativeModules.map((module: { path: string }) => { + assert(module.path.startsWith(prefix)); + return module.path.slice(prefix.length); + }), + ); + for (const module of spec.descriptor['native-support-modules'] ?? []) { + assert(module['runtime-path'].startsWith(prefix)); + expected.add(module['runtime-path'].slice(prefix.length)); + } + const roots = readdirSync(workspaces, { withFileTypes: true }) + .filter((entry) => entry.isDirectory()) + .map((entry) => path.join(workspaces, entry.name, 'tmp/oliphaunt')) + .filter((directory) => existsSync(directory)); + assert.equal(roots.length, 1, 'expected one active pinned-host runtime workspace'); + const files = (directory: string, relative = ''): string[] => + readdirSync(directory, { withFileTypes: true }).flatMap((entry) => { + const name = path.join(relative, entry.name); + if (entry.isDirectory()) return files(path.join(directory, entry.name), name); + assert(entry.isFile(), 'runtime module must be a regular file'); + return [name]; + }); + const libraryRoot = path.join(roots[0], 'lib/postgresql'); + assert.deepEqual( + existsSync(libraryRoot) ? files(libraryRoot).sort() : [], + [...expected].sort(), + 'staged unselected modules', + ); +} + +const memory = addon.NativeWasixDatabase.open(options); +try { + assert(queryErrors(memory, 'SELECT 1 / 0').length > 0, 'SQL errors were not recognized'); + sql(memory, 'SELECT 1'); + await activate((statement) => sql(memory, statement)); +} finally { + memory.close(); +} + +const storage = { kind: 'directory', path: path.join(process.cwd(), 'persistent-database') }; +const direct = addon.NativeWasixDatabase.open({ ...options, storage }); +try { + assertSelectedModules(); + await activate((statement) => sql(direct, statement)); + sql( + direct, + 'CREATE TABLE wasix_extension_probe(value bigint); INSERT INTO wasix_extension_probe VALUES (12345)', + ); +} finally { + direct.close(); +} +const retainedSql = + "DO $$ BEGIN IF (SELECT value FROM wasix_extension_probe) IS DISTINCT FROM 12345 THEN RAISE EXCEPTION 'physical restore probe was not retained'; END IF; END $$"; +const reopened = addon.NativeWasixDatabase.open({ ...options, storage }); +let backup: Uint8Array; +try { + assertSelectedModules(); + sql(reopened, retainedSql); + await verify((statement) => sql(reopened, statement)); + backup = reopened.backup(); + assert(backup.byteLength > 0, 'physical backup is empty'); +} finally { + reopened.close(); +} +const restoredStorage = { kind: 'directory', path: path.join(process.cwd(), 'restored-database') }; +addon.restoreDirect(restoredStorage.path, backup); +const restored = addon.NativeWasixDatabase.open({ ...options, storage: restoredStorage }); +try { + assertSelectedModules(); + sql(restored, retainedSql); + await verify((statement) => sql(restored, statement)); +} finally { + restored.close(); +} + +const server = await addon.NativeWasixServer.open({ ...options, listen: { transport: 'tcp' } }); +let socket: ReturnType | undefined; +try { + const connectedSocket = connect(server.connectionString); + socket = connectedSocket; + await onceConnected(connectedSocket); + const startup = readExchange(connectedSocket); + connectedSocket.write(startupPacket(options.username, options.database)); + await startup; + await activate(async (statement) => { + const response = readExchange(connectedSocket); + connectedSocket.write(simpleQuery(statement)); + try { + await response; + } catch (cause) { + throw new Error(`${sqlName} server SQL failed: ${statement}`, { cause }); + } + }); +} finally { + if (socket) { + const closed = onceClosed(socket); + socket.destroy(); + await closed; + } + await server.close(); +} +console.log( + `Installed ${sqlName} on declared WASIX host ${spec.compatibility.wasix_runtime_version}: staging, canonical activation, fixture SQL, reopen, physical backup/restore and server: PASS`, +); diff --git a/build_defs/extensions/wasix/link_inputs_test.bzl b/build_defs/extensions/wasix/link_inputs_test.bzl new file mode 100644 index 000000000..acfe80f23 --- /dev/null +++ b/build_defs/extensions/wasix/link_inputs_test.bzl @@ -0,0 +1,52 @@ +"""Source helper flags stay explicit; opaque CcInfo link flags fail closed.""" + +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts", "unittest") +load("@rules_cc//cc:defs.bzl", "cc_library") +load("//build_defs/extensions:external.bzl", "external_extension_inputs") +load("//build_defs/extensions:wasix_carriers.bzl", "wasix_extension_source_candidate", "wasix_extension_uses_current_host") +load("//build_defs/wasix:wasm.bzl", "wasix_module") +load("@oliphaunt_metadata//:metadata.bzl", "EXTENSION_COMPATIBILITY") + +def _inputs_test_impl(ctx): + env = unittest.begin(ctx) + flags = external_extension_inputs(name = "probe", sql_name = "pg_hashids", link_profile = "wasix")["linkopts"] + asserts.equals(env, "list", type(flags)) + asserts.equals(env, ["-lm"], flags) + asserts.equals(env, None, external_extension_inputs(name = "probe", sql_name = "pg_uuidv7", link_profile = "wasix").get("linkopts")) + names = sorted(EXTENSION_COMPATIBILITY.keys()) + # Few, partial and full adoption preserve each unchanged immutable host. + for count in [1, len(names) // 2, len(names)]: + requirements = {name: "0.3.3" if index < count else "0.3.2" for index, name in enumerate(names)} + selected = [name for name in names if wasix_extension_uses_current_host(requirements[name], "0.3.3", ["liboliphaunt-wasix"])] + asserts.equals(env, names[:count], selected) + asserts.false(env, wasix_extension_uses_current_host("0.3.3", "0.3.3", [])) + asserts.false(env, wasix_extension_uses_current_host("0.3.3", "0.3.3", ["oliphaunt-extension-vector"])) + asserts.false(env, wasix_extension_uses_current_host("0.3.2", "0.3.3", ["liboliphaunt-wasix"])) + asserts.true(env, wasix_extension_source_candidate("0.3.2", "0.3.2", False)) + asserts.false(env, wasix_extension_source_candidate("0.3.2", "0.3.3", False)) + # An explicitly empty prepared selection still forbids source fallback. + asserts.false(env, wasix_extension_source_candidate("0.3.2", "0.3.2", True)) + return unittest.end(env) + +_inputs_test = unittest.make(_inputs_test_impl) + +def _invalid_profile_impl(ctx): + external_extension_inputs(name = "probe", sql_name = "pg_hashids", link_profile = "undeclared") + return [] + +_invalid_profile = rule(implementation = _invalid_profile_impl) + +def _rejected_impl(ctx): + env = analysistest.begin(ctx) + asserts.expect_failure(env, ctx.attr.message) + return analysistest.end(env) + +_rejected_test = analysistest.make(_rejected_impl, expect_failure = True, attrs = {"message": attr.string()}) + +def wasix_extension_link_input_tests(): + _inputs_test(name = "link_inputs_test") + _invalid_profile(name = "invalid_link_profile_subject", tags = ["manual"]) + _rejected_test(name = "invalid_link_profile_test", target_under_test = ":invalid_link_profile_subject", message = "unknown external extension link profile") + cc_library(name = "unhandled_linkopts_inputs", linkopts = ["-lundeclared"], linkstatic = True, tags = ["manual"]) + wasix_module(name = "unhandled_linkopts_subject", output_name = "rejected.so", deps = [":unhandled_linkopts_inputs"], tags = ["manual"]) + _rejected_test(name = "unhandled_linkopts_test", target_under_test = ":unhandled_linkopts_subject", message = "WASIX static archive link needs explicit handling of CcInfo flags/additional inputs") diff --git a/build_defs/extensions/wasix/resource_inputs.test.mts b/build_defs/extensions/wasix/resource_inputs.test.mts new file mode 100644 index 000000000..b3645f9ac --- /dev/null +++ b/build_defs/extensions/wasix/resource_inputs.test.mts @@ -0,0 +1,198 @@ +import { test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { bundleCarrierAssets } from '../../../src/extensions/artifacts/packages/tools/bundle-carrier-assets.mts'; +import { AOT_TARGET_TRIPLES } from '../../../src/wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; +import { + readPortableArchiveEntries, + releaseZstdCompressSync, +} from '../../../tools/packaging/portable-archive.mts'; +import { + assertDeclaredWasixResource, + stageCompiledWasixMember, + type WasixCompiledCarrierSpec, +} from '../wasix_carriers.mts'; + +test('compiled contrib members retain canonical basenames within distinct aggregate locators', async () => { + const root = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? os.tmpdir(), 'wasix-member-')); + try { + const product = 'oliphaunt-extension-contrib-pg18'; + const version = '1.2.3'; + const basename = 'oliphaunt-extension-contrib-pg18-1.2.3-wasix-portable.tar.zst'; + const productRoot = path.join(root, 'product'); + const staged = []; + for (const sqlName of ['btree_gin', 'pgcrypto']) { + const module = path.join(root, `${sqlName}.wasm`); + const moduleBytes = Buffer.from(`fixture module ${sqlName}`); + writeFileSync(module, moduleBytes); + const moduleSha256 = createHash('sha256').update(moduleBytes).digest('hex'); + const runtimePath = `lib/postgresql/${sqlName}.so`; + const link = path.join(root, `${sqlName}-link.json`); + writeFileSync( + link, + JSON.stringify({ + schema: 'oliphaunt-declared-wasix-extension-link-v1', + sqlName, + unresolvedImports: [], + nativeModules: [ + { + name: sqlName, + path: runtimePath, + sha256: moduleSha256, + moduleSha256, + size: moduleBytes.length, + }, + ], + coreExportsRequired: [], + sourceFingerprint: 'fixture', + postgresVersion: '18', + }), + ); + const image = path.join(root, `${sqlName}-aot.bin.zst`); + writeFileSync(image, releaseZstdCompressSync(Buffer.from(`fixture AOT ${sqlName}`))); + const spec: WasixCompiledCarrierSpec = { + operation: 'compiled', + product, + version, + sqlName, + target: 'wasix-portable', + descriptor: { + 'native-module-file': `${sqlName}.so`, + dependencies: [], + lifecycle: { + 'create-extension': false, + 'load-sql': [], + 'post-create-sql': [], + 'startup-config': [], + 'preload-required': false, + 'restart-required': false, + 'shared-memory-required': false, + }, + }, + recipe: {}, + source: {}, + selectedDependencies: [], + compatibility: { + postgres_major: '18', + extension_runtime_contract: 'oliphaunt-extension-runtime-v1', + native_runtime_product: 'liboliphaunt-native', + native_runtime_version: version, + wasix_runtime_product: 'liboliphaunt-wasix', + wasix_runtime_version: version, + }, + releaseMetadata: {}, + carriers: [], + outputs: { github: '', npm: '', cargo: '', manifest: '', frozen: '' }, + modules: [{ name: sqlName, path: module, runtime_path: runtimePath }], + resources: [], + link, + toolchain: '', + aot: Object.values(AOT_TARGET_TRIPLES).map((target) => ({ + name: `extension:${sqlName}`, + target, + module, + image, + })), + }; + const memberRoot = path.join(productRoot, 'member-assets', sqlName); + const row = await stageCompiledWasixMember(spec, [], productRoot, memberRoot); + assert.equal(row.archiveName, basename); + assert.equal(row.asset.name, basename); + assert.equal(row.archive, path.join(memberRoot, basename)); + staged.push(row); + } + assert.notEqual(staged[0].archive, staged[1].archive); + const members = staged.map(({ member, archive }) => ({ + ...member, + assets: member.assets.map((asset) => ({ + ...asset, + path: path.relative(root, archive).split(path.sep).join('/'), + })), + })); + mkdirSync(path.join(productRoot, 'release-assets')); + const carriers = bundleCarrierAssets( + product, + version, + productRoot, + members, + staged[0].member.compatibility, + { root }, + ); + assert.equal(carriers.length, 1); + assert.equal( + carriers[0].name, + 'oliphaunt-extension-contrib-pg18-1.2.3-wasix-wasix-portable-bundle.tar.gz', + ); + assert.equal(carriers[0].memberCount, 2); + const entries = readPortableArchiveEntries(path.resolve(root, carriers[0].path)); + for (const [index, member] of members.entries()) { + const asset = member.assets[0]; + assert.equal(asset.memberPath, `extensions/${member.sqlName}/${basename}`); + assert.equal(asset.carrierAsset, carriers[0].name); + assert.equal( + asset.carrierRoot, + 'oliphaunt-extension-contrib-pg18-1.2.3-wasix-wasix-portable-bundle', + ); + assert.deepEqual( + entries.get(`${asset.carrierRoot}/${asset.memberPath}`)!.data(), + readFileSync(staged[index].archive), + ); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('empty delivered upgrade SQL stays valid while missing, nonregular and unsafe inputs fail', () => { + const root = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? os.tmpdir(), 'wasix-resource-')); + try { + const source = path.join(root, 'pg_ivm--1.12--1.13.sql'); + writeFileSync(source, ''); + assertDeclaredWasixResource({ + source, + destination: 'share/postgresql/extension/pg_ivm--1.12--1.13.sql', + }); + for (const destination of [ + 'lib/postgresql/pg_ivm.so', + 'share/postgresql/extension/pg_ivm.control', + 'share/postgresql/tsearch_data/dict.rules', + 'share/postgresql/contrib/data.sql', + ]) + assert.throws( + () => assertDeclaredWasixResource({ source, destination }), + /must be nonempty/u, + ); + assert.throws( + () => + assertDeclaredWasixResource({ + source: path.join(root, 'missing.sql'), + destination: 'share/postgresql/extension/missing.sql', + }), + /ENOENT/u, + ); + const directory = path.join(root, 'directory.sql'); + mkdirSync(directory); + assert.throws( + () => + assertDeclaredWasixResource({ + source: directory, + destination: 'share/postgresql/extension/directory.sql', + }), + /regular file/u, + ); + for (const destination of [ + 'share/postgresql/extension/../escape.sql', + '/share/postgresql/extension/absolute.sql', + 'share/postgresql//empty.sql', + ]) + assert.throws( + () => assertDeclaredWasixResource({ source, destination }), + /unsafe member destination/u, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/build_defs/extensions/wasix_carriers.bzl b/build_defs/extensions/wasix_carriers.bzl new file mode 100644 index 000000000..5a9ff98b5 --- /dev/null +++ b/build_defs/extensions/wasix_carriers.bzl @@ -0,0 +1,430 @@ +"""Declared portable/AOT extension inputs and canonical final envelopes.""" + +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_file_action", "bun_script_test", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/release:identity.bzl", "ReleaseIdentityInfo") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") +load("//build_defs/release:supplier.bzl", "ShippingSupplierInfo", "file_shipping_supplier", "merge_shipping_suppliers") +load("//build_defs/wasix:cargo.bzl", "RUNTIME_CARGO_HELPERS") +load("//build_defs/wasix:aot.bzl", "WasixAotInfo", "wasix_aot") +load("//build_defs/wasix:platform.bzl", "WASIX_PORTABLE_TRANSITION") +load("//build_defs/wasix:wasm.bzl", "WasmModuleInfo") +load("//build_defs/wasix:napi.bzl", "WasixNapiCarrierInfo") +load("@wasix_tool_metadata//:targets.bzl", "WASIX_AOT_TARGETS") +load("@oliphaunt_metadata//:metadata.bzl", "COMPLETED_SUPPLIER_ARTIFACTS", "PREPARED_NATIVE_INPUTS", "PREPARED_NATIVE_SELECTED_PRODUCTS", "PRODUCTS", "PUBLICATION_CARRIERS", "WASIX_ARTIFACTS", "WASIX_EXTENSIONS") +load(":extensions.bzl", "extension_identity") +load(":final_leaf.bzl", "ExtensionFinalLeafInfo") +load(":native_carriers.bzl", "native_extension_carrier_helpers", "native_extension_carrier_legal", "native_external_carrier_metadata") + +def wasix_sql_carrier_helpers(): + # Both public canonical writers import the shared extension/runtime contracts. + return {label: True for label in native_extension_carrier_helpers() + RUNTIME_CARGO_HELPERS + ["//build_defs/wasix:package.mts", "//src/wasix/runtime:toolchain.toml", "//tools/release:cargo-payload-part-contract.mts", "//tools/release:publication-catalog.mts"]}.keys() + +def _metadata(sql_name): + if sql_name != "pgtap": + fail("only the qualified pgTAP SQL-only WASIX producer is admitted") + metadata = native_external_carrier_metadata(sql_name, "wasix-portable") + metadata.pop("runtimeVersion") + metadata["carriers"] = [row for row in metadata["carriers"] if row["target"] == "wasix-portable"] + return metadata + +def _leaf(spec, ecosystem): + rows = [row for row in spec["carriers"] if row["ecosystem"] == ecosystem and row["target"] == "wasix-portable" and row["role"] == "portable-leaf"] + if len(rows) != 1: + fail("SQL-only WASIX envelope requires exactly its canonical " + ecosystem + " portable leaf") + return rows[0] + +def _carriers_impl(ctx): + owner = ctx.attr.owner[ReleaseIdentityInfo] + spec = _metadata(ctx.attr.sql_name) + if owner.id != spec["product"] or owner.version != spec["version"]: + fail("SQL-only WASIX member differs from its canonical release owner") + sql = ctx.attr.sql[DefaultInfo].files.to_list() + if len(sql) != 1 or not sql[0].is_directory: + fail("SQL-only WASIX member requires exactly the production SQL TreeArtifact") + github = ctx.actions.declare_file(spec["product"] + "-" + spec["version"] + "-wasix-portable.tar.zst") + npm = ctx.actions.declare_file(_leaf(spec, "npm")["name"].replace("@", "").replace("/", "-") + "-" + spec["version"] + ".tgz") + cargo = ctx.actions.declare_file(_leaf(spec, "cargo")["name"] + "-" + spec["version"] + ".crate") + manifest = ctx.actions.declare_file(ctx.label.name + "/" + spec["product"] + "-" + spec["version"] + "-manifest.json") + frozen = ctx.actions.declare_file(ctx.label.name + "/extension-artifacts.json") + spec.update({"sqlRoot": sql[0].path, "outputs": {"github": github.path, "npm": npm.path, "cargo": cargo.path, "manifest": manifest.path, "frozen": frozen.path}}) + inputs = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(inputs, json.encode(spec)) + leaves = ctx.actions.args() + leaves.add_all(sql, expand_directories = True) + leaves.use_param_file("--sql-files=%s", use_always = True) + leaves.set_param_file_format("multiline") + bun_file_action(ctx, ctx.file._tool, arguments = [inputs.path, leaves], inputs = sql + [inputs] + ctx.files.legal, + source_files = [ctx.file._tool] + ctx.files._helpers + ctx.files.legal, + outputs = [github, npm, cargo, manifest, frozen], mnemonic = "WasixSqlExtensionEnvelopes") + return [DefaultInfo(files = depset([github, npm, cargo, manifest, frozen])), ctx.attr._suppliers[ShippingSupplierInfo], + ExtensionFinalLeafInfo(product = spec["product"], owner = owner.id, version = owner.version, family = "wasix", target = "wasix-portable", metadata = spec, github = [github], npm = [npm], cargo = [cargo], manifest = manifest, frozen = frozen, spec = inputs, validation = None, receipt = None, origin = None), + OutputGroupInfo(github = depset([github]), npm = depset([npm]), cargo = depset([cargo]), manifest = depset([manifest]), frozen = depset([frozen]), spec = depset([inputs]), sql = depset(sql))] + +_wasix_sql_carriers = rule(implementation = _carriers_impl, toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = {"sql_name": attr.string(mandatory = True), "sql": attr.label(mandatory = True, cfg = "exec"), + "owner": attr.label(mandatory = True, providers = [ReleaseIdentityInfo]), "legal": attr.label_list(allow_files = True), + "_suppliers": attr.label(default = "//build_defs/release:no_suppliers", providers = [ShippingSupplierInfo]), + "_tool": attr.label(default = "//build_defs/extensions:wasix_carriers.mts", allow_single_file = True), + "_helpers": attr.label_list(default = wasix_sql_carrier_helpers(), allow_files = True)}) + +def wasix_sql_extension_carriers(sql_name, sql = ":sql"): + spec = _metadata(sql_name) + _wasix_sql_carriers(name = "wasix_carriers", sql_name = sql_name, sql = sql, owner = extension_identity(sql_name, family = "wasix"), legal = native_extension_carrier_legal(sql_name), exec_compatible_with = ["@platforms//os:linux"]) + packages = [] + for ecosystem in ["github", "npm", "cargo", "manifest", "frozen"]: + name = "wasix_" + ecosystem + "_shipping" + native.filegroup(name = name + "_files", srcs = [":wasix_carriers"], output_group = ecosystem) + if ecosystem == "github": + package_name, role = spec["product"] + "-" + spec["version"] + "-wasix-portable.tar.zst", "github-release-asset" + elif ecosystem in ["npm", "cargo"]: + row = _leaf(spec, ecosystem) + package_name, role = row["name"], row["role"] + else: + package_name, role = sql_name + "-wasix-" + ecosystem, "extension-release-" + ecosystem + "-input" + shipping_package(name = name, owner = extension_identity(sql_name, family = "wasix"), artifacts = [":" + name + "_files"], ecosystem = ecosystem if ecosystem in ["github", "npm", "cargo"] else "internal", package_name = package_name, configuration = "wasix-portable", role = role, suppliers = ":wasix_carriers") + packages.append(":" + name) + wasix_extension_declared_host(name = "wasix_declared_host", sql_name = sql_name) + wasix_compiled_extension_installed_test(name = "wasix_installed_test", sql_name = sql_name, leaf = ":wasix_carriers", host = ":wasix_declared_host", + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], size = "large", timeout = "long", tags = ["manual", "installed-consumer"]) + # This family's selected inputs do not advertise the complete external owner. + shipping_export(name = "wasix_shipping_export", packages = packages, + qualification = [":wasix_installed_test", ":wasix_carriers_test", ":upstream_sql_parity_test"], testonly = True) + native.filegroup(name = "wasix_carrier_spec", srcs = [":wasix_carriers"], output_group = "spec") + native.filegroup(name = "wasix_sql_input", srcs = [":wasix_carriers"], output_group = "sql") + inputs = [":wasix_carrier_spec"] + [":wasix_" + group + "_shipping_files" for group in ["github", "npm", "cargo", "manifest", "frozen"]] + [":wasix_sql_input"] + bun_script_test(name = "wasix_carriers_test", entry_point = "//build_defs/extensions:wasix_carriers.test.mts", args = ["$(location %s)" % label for label in inputs], data = inputs + ["//build_defs/extensions:wasix_carriers.mts"] + wasix_sql_carrier_helpers() + native_extension_carrier_legal(sql_name), target_compatible_with = ["@platforms//os:linux"], size = "small") + +def _unit_inputs_impl(ctx): + output = ctx.actions.declare_file(ctx.label.name + ".json") + ctx.actions.write(output, json.encode(_metadata("pgtap"))) + return [DefaultInfo(files = depset([output]))] + +wasix_sql_carrier_unit_inputs = rule(implementation = _unit_inputs_impl) + +WasixExtensionHostInfo = provider(fields = ["module", "manifest", "version", "candidate"]) + +def _compiled_metadata(sql_name): + spec = native_external_carrier_metadata(sql_name, "wasix-portable") + spec.pop("runtimeVersion") + spec["descriptor"] = dict(spec["descriptor"], **WASIX_EXTENSIONS[sql_name]) + spec["carriers"] = [row for row in spec["carriers"] if row["target"] == "wasix-portable" or (row["ecosystem"] == "cargo" and row["role"] == "aot-leaf") or (row["ecosystem"] == "npm" and "-wasix-" in row["name"])] + return spec + +def _compiled_carriers_impl(ctx): + spec = _compiled_metadata(ctx.attr.sql_name) + owner = ctx.attr.owner[ReleaseIdentityInfo] + if owner.id != spec["product"] or owner.version != spec["version"]: + fail("compiled WASIX extension differs from its canonical release owner") + modules = [ctx.attr.module[0][WasmModuleInfo].module] + [target[WasmModuleInfo].module for target in ctx.attr.support_modules] + expected = [spec["descriptor"]["native-module-file"]] + [path.split("/")[-1] for path in spec["recipe"].get("artifacts", {}).get("native_dependency_modules", [])] + if sorted([file.basename for file in modules]) != sorted(expected): + fail("compiled WASIX module closure differs from its canonical recipe") + host = ctx.attr.host[WasixExtensionHostInfo] + if host.version != spec["compatibility"]["wasix_runtime_version"]: + fail("compiled WASIX extension host differs from its conventional compatibility requirement") + runtime = host.module + portable = [host.manifest] + support = {row["runtime-path"]: row["name"] for row in spec["descriptor"]["native-support-modules"]} + if sorted(support.keys()) != sorted(spec["recipe"].get("artifacts", {}).get("native_dependency_modules", [])): + fail("compiled WASIX support closure differs from its canonical target definition") + module_rows = [{"name": ctx.attr.sql_name if file == modules[0] else support["lib/postgresql/" + file.basename], "path": file.path, "runtime_path": "lib/postgresql/" + file.basename} for file in modules] + link_spec = ctx.actions.declare_file(ctx.label.name + ".link-inputs.json") + link = ctx.actions.declare_file(ctx.label.name + ".link.json") + link_inputs = {"sql_name": ctx.attr.sql_name, "runtime": runtime.path, "runtime_manifest": host.manifest.path, "modules": module_rows} + link_files = modules + portable + [runtime, link_spec] + link_outputs = [link] + selected_host = host + if getattr(host, "candidate", None): + selected_runtime = ctx.actions.declare_file(ctx.label.name + "/selected-host/postgres.wasm") + selected_manifest = ctx.actions.declare_file(ctx.label.name + "/selected-host/manifest.json") + candidate = host.candidate + link_inputs["candidate"] = {"runtime": candidate.module.path, "runtime_manifest": candidate.manifest.path, + "selected_runtime": selected_runtime.path, "selected_runtime_manifest": selected_manifest.path} + link_files += [candidate.module, candidate.manifest] + link_outputs += [selected_runtime, selected_manifest] + selected_host = WasixExtensionHostInfo(module = selected_runtime, manifest = selected_manifest, version = host.version) + ctx.actions.write(link_spec, json.encode(link_inputs)) + args = ctx.actions.args() + args.add_all(["assets", "declared-extension-link", "--spec", link_spec, "--output", link]) + ctx.actions.run(executable = ctx.executable._analyzer, arguments = [args], inputs = link_files, outputs = link_outputs, mnemonic = "WasixExtensionLinkContract") + resources = [] + resource_files = list(ctx.files.resources) + for file in resource_files: + if file.is_directory: + resources.append({"source": file.path, "destination": "share/postgresql/extension", "tree": True}) + elif file.basename.endswith(".control") or file.basename.endswith(".sql"): + resources.append({"source": file.path, "destination": "share/postgresql/extension/" + file.basename}) + else: + fail("compiled WASIX SQL resource needs a canonical SQL/control destination") + if ctx.file.main_sql: + resources.append({"source": ctx.file.main_sql.path, "destination": "share/postgresql/extension/" + ctx.attr.sql_name + "--" + spec["source"]["extension-control"]["default-version"] + ".sql"}) + resource_files = resource_files + [ctx.file.main_sql] + for target, destination in ctx.attr.data_resources.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1: + fail("compiled WASIX mapped data requires one declared file or directory") + resources.append({"source": files[0].path, "destination": destination, "tree": files[0].is_directory}) + resource_files += files + images = [] + image_files = [] + for target in ctx.attr.aot: + image = target[WasixAotInfo] + image_files += [image.image, image.module] + matches = [row for row in module_rows if row["path"] == image.module.path] + if len(matches) != 1: + fail("WASIX AOT image is outside its member's exact portable closure") + row = matches[0] + images.append({"target": image.target, "image": image.image.path, "module": image.module.path, "name": "extension:" + ctx.attr.sql_name + (":" + row["name"] if row["name"] != ctx.attr.sql_name else "")}) + outputs = {"npm": [], "cargo": []} + cargo_parts = {} + carrier_groups = {} + for index, row in enumerate(spec["carriers"]): + suffix = ".tgz" if row["ecosystem"] == "npm" else ".crate" + filename = row["name"].replace("@", "").replace("/", "-") + "-" + spec["version"] + suffix + file = ctx.actions.declare_file(ctx.label.name + "/" + row["ecosystem"] + "/" + filename) + outputs[row["ecosystem"]].append(file) + group = [file] + if row["ecosystem"] == "cargo": + parts = ctx.actions.declare_directory(ctx.label.name + "/cargo-parts/" + row["name"]) + cargo_parts[row["name"]] = parts + group.append(parts) + carrier_groups["carrier_" + str(index)] = depset(group) + outputs["github"] = [ctx.actions.declare_file(ctx.label.name + "/release-assets/" + spec["product"] + "-" + spec["version"] + "-wasix-portable.tar.zst")] + outputs["manifest"] = [ctx.actions.declare_file(ctx.label.name + "/" + spec["product"] + "-" + spec["version"] + "-manifest.json")] + outputs["frozen"] = [ctx.actions.declare_file(ctx.label.name + "/extension-artifacts.json")] + output_files = [file for files in outputs.values() for file in files] + cargo_parts.values() + spec.update({"operation": "compiled", "modules": module_rows, "resources": resources, "link": link.path, "aot": images, "toolchain": ctx.file.toolchain.path, + "outputs": {name: files[0].dirname if name in ["github", "npm", "cargo"] else files[0].path for name, files in outputs.items()}}) + if cargo_parts: + spec["outputs"]["cargoParts"] = {name: file.path for name, file in cargo_parts.items()} + inputs = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(inputs, json.encode(spec)) + leaves = ctx.actions.args() + leaves.add_all([file for file in resource_files if file.is_directory], expand_directories = True) + leaves.use_param_file("--resource-files=%s", use_always = True) + leaves.set_param_file_format("multiline") + bun_file_action(ctx, ctx.file._tool, arguments = [inputs.path, leaves], inputs = modules + resource_files + image_files + [link, inputs, ctx.file.toolchain] + ctx.files.legal, + source_files = [ctx.file._tool] + ctx.files._helpers + ctx.files.legal, outputs = output_files, mnemonic = "WasixCompiledExtensionEnvelopes") + supplier = ctx.attr.host[ShippingSupplierInfo] if ShippingSupplierInfo in ctx.attr.host else ShippingSupplierInfo(suppliers = None, files = depset([host.module, host.manifest])) + return [DefaultInfo(files = depset(output_files)), supplier, selected_host, ExtensionFinalLeafInfo(product = spec["product"], owner = owner.id, version = owner.version, family = "wasix", target = "wasix-portable", metadata = spec, + github = outputs["github"], npm = outputs["npm"], cargo = outputs["cargo"] + cargo_parts.values(), manifest = outputs["manifest"][0], frozen = outputs["frozen"][0], spec = inputs, validation = link, receipt = None, origin = None), + OutputGroupInfo(**{name: depset(files + (cargo_parts.values() if name == "cargo" else [])) for name, files in outputs.items()} | carrier_groups | {"spec": depset([inputs]), "link": depset([link])})] + +_wasix_compiled_carriers = rule(implementation = _compiled_carriers_impl, toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = {"sql_name": attr.string(mandatory = True), "module": attr.label(mandatory = True, cfg = WASIX_PORTABLE_TRANSITION), + "support_modules": attr.label_list(providers = [WasmModuleInfo], cfg = WASIX_PORTABLE_TRANSITION), + "resources": attr.label_list(allow_files = True, cfg = WASIX_PORTABLE_TRANSITION), "main_sql": attr.label(allow_single_file = True, cfg = WASIX_PORTABLE_TRANSITION), "data_resources": attr.label_keyed_string_dict(allow_files = True, cfg = WASIX_PORTABLE_TRANSITION), + "aot": attr.label_list(providers = [WasixAotInfo], mandatory = True), "owner": attr.label(mandatory = True, providers = [ReleaseIdentityInfo]), "legal": attr.label_list(allow_files = True), + "host": attr.label(mandatory = True, providers = [WasixExtensionHostInfo]), + "toolchain": attr.label(default = "//src/wasix/runtime:toolchain.toml", allow_single_file = True), + "_tool": attr.label(default = "//build_defs/extensions:wasix_carriers.mts", allow_single_file = True), "_helpers": attr.label_list(default = wasix_sql_carrier_helpers(), allow_files = True), + "_analyzer": attr.label(default = "//src/wasix/runtime/tools/xtask:xtask", executable = True, cfg = "exec"), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist")}) + +def wasix_compiled_extension_carriers(name, sql_name, module, resources, host, support_modules = [], data_resources = {}, main_sql = None): + """Reuse the admitted portable module graph and canonical serializer for one owner.""" + aot = [] + for target_id in WASIX_AOT_TARGETS: + for index, source in enumerate([module] + support_modules): + image = name + "_aot_" + target_id.replace("-", "_") + "_" + str(index) + wasix_aot(name = image, module = source, target_id = target_id, output_name = sql_name + "_" + str(index) + "-llvm-opta.bin.zst", + exec_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64", "@zig_sdk//libc:gnu.2.34"]) + aot.append(":" + image) + _wasix_compiled_carriers(name = name, sql_name = sql_name, module = module, resources = resources, main_sql = main_sql, host = host, support_modules = support_modules, data_resources = data_resources, + aot = aot, owner = extension_identity(sql_name, family = "wasix"), legal = native_extension_carrier_legal(sql_name), exec_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"]) + +def wasix_compiled_extension_shipping(name, sql_name, carriers, qualification): + """Expose this member's canonical WASIX leaves through existing owner rules.""" + spec = _compiled_metadata(sql_name) + owner = extension_identity(sql_name, family = "wasix") + packages = [] + for index, row in enumerate(spec["carriers"]): + package = name + "_" + row["ecosystem"] + "_shipping_" + str(index) + native.filegroup(name = package + "_files", srcs = [carriers], output_group = "carrier_" + str(index)) + shipping_package(name = package, owner = owner, artifacts = [":" + package + "_files"], ecosystem = row["ecosystem"], package_name = row["name"], configuration = row["target"], role = row["role"], suppliers = carriers) + packages.append(":" + package) + for group in ["github", "manifest", "frozen", "link"]: + package = name + "_" + group + "_shipping" + native.filegroup(name = package + "_files", srcs = [carriers], output_group = group) + package_name = spec["product"] + "-" + spec["version"] + "-wasix-portable.tar.zst" if group == "github" else sql_name + "-wasix-" + group + if group == "link": + package_name = sql_name + "-wasix-" + ("final" if PREPARED_NATIVE_INPUTS else "pre-version") + "-link" + shipping_package(name = package, owner = owner, artifacts = [":" + package + "_files"], ecosystem = "github" if group == "github" else "internal", package_name = package_name, + configuration = "wasix-portable", role = "github-release-asset" if group == "github" else "extension-release-" + group + "-input", suppliers = carriers) + packages.append(":" + package) + shipping_export(name = name + "_shipping_export", packages = packages, qualification = qualification, testonly = True) + +def _host_impl(ctx): + expected = native_external_carrier_metadata(ctx.attr.sql_name, "wasix-portable")["compatibility"]["wasix_runtime_version"] + archive = ctx.file.archive + if not archive or not ctx.attr.origin: + fail("WASIX host qualification requires its retained completed portable Cargo archive input") + runtime = ctx.actions.declare_file(ctx.label.name + "/postgres.wasm") + manifest = ctx.actions.declare_file(ctx.label.name + "/manifest.json") + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode({"operation": "host", "version": expected, "archive": archive.path, "module": runtime.path, "manifest": manifest.path})) + bun_file_action(ctx, ctx.file._tool, arguments = [spec.path], inputs = [archive, spec], source_files = [ctx.file._tool] + ctx.files._helpers, outputs = [runtime, manifest], mnemonic = "DeclaredWasixExtensionHost") + carriers = [row for row in PUBLICATION_CARRIERS if row["product"] == "liboliphaunt-wasix" and row["ecosystem"] == "cargo" and row["name"] == "liboliphaunt-wasix-portable"] + if len(carriers) != 1: + fail("declared WASIX host requires its unique canonical portable Cargo carrier") + carrier = carriers[0] + origin = json.decode(ctx.attr.origin) + publication = origin["publication"] + if origin["kind"] != "completed-publication" or origin["artifact"] != "cargo:" + carrier["name"] or publication["product"] != carrier["product"] or publication["version"] != expected: + fail("declared WASIX ABI supplier differs from its conventional host requirement") + # The extractor validates the core from this original completed archive; + # its derived Files never become a substitute supplier origin. + supplier = ShippingSupplierInfo(suppliers = [{"product": carrier["product"], "version": expected, "configuration": carrier["target"] or "portable", "binding": "abi-contract", + "origin": origin, "files": [{"path": archive.path}]}], files = depset([archive])) + candidate = None + if ctx.attr.candidate: + candidate = ctx.attr.candidate[WasixExtensionHostInfo] + if candidate.version != expected: + fail("source WASIX candidate differs from its declared host version") + supplier = merge_shipping_suppliers([supplier, ctx.attr.candidate[ShippingSupplierInfo]]) + return [DefaultInfo(files = depset([runtime, manifest])), supplier, WasixExtensionHostInfo(module = runtime, manifest = manifest, version = expected, candidate = candidate)] + +_wasix_extension_host = rule(implementation = _host_impl, toolchains = BUN_SOURCE_TOOLCHAINS, attrs = { + "sql_name": attr.string(mandatory = True), "archive": attr.label(allow_single_file = True), "origin": attr.string(), + "candidate": attr.label(providers = [WasixExtensionHostInfo, ShippingSupplierInfo]), + "_tool": attr.label(default = "//build_defs/extensions:wasix_carriers.mts", allow_single_file = True), "_helpers": attr.label_list(default = wasix_sql_carrier_helpers(), allow_files = True)}) + +def wasix_extension_uses_current_host(required_version, current_version, selected_products): + return "liboliphaunt-wasix" in selected_products and required_version == current_version + +def wasix_extension_source_candidate(required_version, current_version, prepared): + return not prepared and required_version == current_version + +def wasix_extension_declared_host(name, sql_name): + version = native_external_carrier_metadata(sql_name, "wasix-portable")["compatibility"]["wasix_runtime_version"] + current_version = PRODUCTS["liboliphaunt-wasix"]["version"] + if PREPARED_NATIVE_INPUTS and wasix_extension_uses_current_host(version, current_version, PREPARED_NATIVE_SELECTED_PRODUCTS): + wasix_extension_current_host(name = name) + else: + candidate = None + if wasix_extension_source_candidate(version, current_version, PREPARED_NATIVE_INPUTS): + wasix_extension_current_host(name = name + "_current_candidate") + candidate = ":" + name + "_current_candidate" + original = COMPLETED_SUPPLIER_ARTIFACTS.get("liboliphaunt-wasix/" + version + "/cargo:liboliphaunt-wasix-portable") + _wasix_extension_host(name = name, sql_name = sql_name, archive = original["file"]["path"] if original else None, + origin = json.encode({"kind": "completed-publication", "publication": original["publication"], "artifact": original["artifact"]}) if original else "", candidate = candidate) + +def _current_host_impl(ctx): + owner = ctx.attr.owner[ReleaseIdentityInfo] + if owner.id != "liboliphaunt-wasix": + fail("current WASIX extension host requires its canonical runtime owner") + archive = ctx.file.archive + if archive.is_source or archive.is_directory or archive.owner != ctx.attr.archive.label: + fail("current WASIX extension host requires the original source-built runtime archive File") + runtime = ctx.actions.declare_file(ctx.label.name + "/postgres.wasm") + manifest = ctx.actions.declare_file(ctx.label.name + "/manifest.json") + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode({"operation": "current-host", "archive": archive.path, "module": runtime.path, "manifest": manifest.path})) + bun_file_action(ctx, ctx.file._tool, arguments = [spec.path], inputs = [archive, spec], source_files = [ctx.file._tool] + ctx.files._helpers, outputs = [runtime, manifest], mnemonic = "CurrentWasixExtensionHost") + supplier = ShippingSupplierInfo(suppliers = [{"product": owner.id, "version": owner.version, "configuration": "wasix-portable", "binding": "abi-contract", + "origin": {"kind": "current-source"}, "files": [{"path": archive.path}]}], files = depset([archive])) + return [DefaultInfo(files = depset([runtime, manifest])), supplier, WasixExtensionHostInfo(module = runtime, manifest = manifest, version = owner.version)] + +wasix_extension_current_host = rule(implementation = _current_host_impl, toolchains = BUN_SOURCE_TOOLCHAINS, attrs = { + "archive": attr.label(default = "//src/wasix/runtime:release_archive_portable", allow_single_file = True), + "owner": attr.label(default = "@oliphaunt_metadata//:product_liboliphaunt-wasix", providers = [ReleaseIdentityInfo]), + "_tool": attr.label(default = "//build_defs/extensions:wasix_carriers.mts", allow_single_file = True), "_helpers": attr.label_list(default = wasix_sql_carrier_helpers(), allow_files = True)}) + +def _compiled_installed_impl(ctx): + leaf = ctx.attr.leaf[ExtensionFinalLeafInfo] + module = ctx.attr.module[0][WasmModuleInfo].module if ctx.attr.module else None + if module == None and leaf.metadata["descriptor"].get("native-module-file"): + fail("compiled WASIX installed test requires its actual declared module") + if module != None and leaf.validation == None: + fail("compiled WASIX installed test requires its actual strict link contract") + host_target = ctx.attr.leaf if WasixExtensionHostInfo in ctx.attr.leaf else ctx.attr.host + if not host_target or WasixExtensionHostInfo not in host_target: + fail("installed WASIX extension requires its exact selected host Files") + host = host_target[WasixExtensionHostInfo] + if ctx.attr.host and ctx.attr.host[WasixExtensionHostInfo].version != host.version: + fail("explicit WASIX host differs from the leaf's selected host identity") + if host.version != leaf.metadata["compatibility"]["wasix_runtime_version"]: + fail("installed WASIX host differs from its owner's conventional requirement") + if not ctx.attr.addon: + fail("installed WASIX extension requires unambiguous original addon/facade Files for its declared host " + host.version) + napi = json.decode(ctx.attr.napi_contract) + if WasixNapiCarrierInfo in ctx.attr.addon: + carrier = ctx.attr.addon[WasixNapiCarrierInfo] + if carrier.target != napi["target"]["target"]: + fail("installed WASIX addon target differs from its canonical carrier") + addon = carrier.npm + napi["constructionContract"] = carrier.construction_contract + else: + originals = ctx.attr.addon[DefaultInfo].files.to_list() + if len(originals) != 1 or originals[0].is_directory: + fail("installed held WASIX addon requires one original npm archive File") + addon = originals[0] + current_addon = None + if ctx.attr.current_addon: + current_carrier = ctx.attr.current_addon[WasixNapiCarrierInfo] + if current_carrier.target != napi["target"]["target"]: + fail("current WASIX addon target differs from its canonical carrier") + current_addon = current_carrier.npm + napi["currentConstructionContract"] = current_carrier.construction_contract + napi_input = ctx.actions.declare_file(ctx.label.name + ".napi.json") + ctx.actions.write(napi_input, json.encode(napi)) + node = ctx.toolchains["@rules_nodejs//nodejs:toolchain_type"].nodeinfo.node + fixtures = [file for file in ctx.files._fixtures if file.basename == leaf.metadata["sqlName"] + ".sql"] + if len(fixtures) != 1: + fail("compiled WASIX installed test requires its canonical source-owned SQL fixture") + files = leaf.github + leaf.npm + leaf.cargo + [leaf.manifest, leaf.frozen, leaf.spec, addon, node, ctx.file._runner, ctx.file._consumer, host.module, host.manifest, napi_input, ctx.file.addon_template] + ([current_addon] if current_addon else []) + ([ctx.file.addon_facade] if ctx.file.addon_facade else []) + ([module, leaf.validation] if module else []) + fixtures + ctx.files._helpers + parts = [file for file in leaf.cargo if file.is_directory] + return bun_test_entrypoint(ctx, ctx.file._runner, [leaf.spec, leaf.github[0], leaf.npm[0], leaf.cargo[0], leaf.frozen, module or "-", addon, node, ctx.file._consumer, leaf.validation or "-", fixtures[0], host.module, host.manifest, napi_input, ctx.file.addon_facade or "-", ctx.file.addon_template, current_addon or "-"] + parts, files, source_files = [ctx.file._runner, ctx.file._consumer] + ctx.files._helpers) + +_compiled_installed_test = rule(implementation = _compiled_installed_impl, test = True, toolchains = BUN_SOURCE_TOOLCHAINS + ["@rules_nodejs//nodejs:toolchain_type"], attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "leaf": attr.label(mandatory = True, providers = [ExtensionFinalLeafInfo]), "module": attr.label(cfg = WASIX_PORTABLE_TRANSITION), + "host": attr.label(providers = [WasixExtensionHostInfo]), + "addon": attr.label(providers = [[WasixNapiCarrierInfo], [ShippingSupplierInfo]]), + "addon_facade": attr.label(allow_single_file = True), "addon_template": attr.label(allow_single_file = True, mandatory = True), + "current_addon": attr.label(providers = [WasixNapiCarrierInfo]), + "napi_contract": attr.string(mandatory = True), + "_runner": attr.label(default = "//build_defs/extensions/wasix:compiled_carriers.test.mts", allow_single_file = True), + "_consumer": attr.label(default = "//build_defs/extensions/wasix:installed_consumer.mts", allow_single_file = True), + "_fixtures": attr.label_list(default = ["//src/test-fixtures/extensions:sql"], allow_files = True), + "_helpers": attr.label_list(default = wasix_sql_carrier_helpers() + ["//src/wasix/sdks/ts:tools/pgwire-client.mts", "//src/wasix/node-addon:tools/carrier-contract.mts", "//build_defs/extensions:wasix_carriers.mts"], allow_files = True), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist")})) + +def wasix_compiled_extension_installed_test(name, sql_name, **kwargs): + target_rows = [row for row in WASIX_ARTIFACTS if row["product"] == "oliphaunt-wasix-napi" and row["kind"] == "wasix-napi-addon" and row["target"] == "linux-x64-gnu"] + if len(target_rows) != 1: + fail("installed WASIX extension requires its canonical GNU x64 addon target") + target = target_rows[0] + requirement = native_external_carrier_metadata(sql_name, "wasix-portable")["compatibility"]["wasix_runtime_version"] + current = PREPARED_NATIVE_INPUTS and wasix_extension_uses_current_host(requirement, PRODUCTS["liboliphaunt-wasix"]["version"], PREPARED_NATIVE_SELECTED_PRODUCTS) + candidate = kwargs.get("module") and wasix_extension_source_candidate(requirement, PRODUCTS["liboliphaunt-wasix"]["version"], PREPARED_NATIVE_INPUTS) + napi = {"current": current, "version": PRODUCTS["oliphaunt-wasix-napi"]["version"], "target": target} + if candidate: + napi["currentVersion"] = PRODUCTS["oliphaunt-wasix-napi"]["version"] + addon = "//src/wasix/node-addon:release_carriers" if current else None + facade = None + if not current: + sdk_carriers = [row for row in PUBLICATION_CARRIERS if row["product"] == "oliphaunt-wasix-ts" and row["ecosystem"] == "npm"] + if len(sdk_carriers) != 1: + fail("held WASIX addon requires its canonical TypeScript facade") + originals = [row for row in COMPLETED_SUPPLIER_ARTIFACTS.values() if row["publication"]["product"] == "oliphaunt-wasix-napi" and row["artifact"] == "npm:" + target["npm_package"]] + facades = [row for row in COMPLETED_SUPPLIER_ARTIFACTS.values() if row["publication"]["product"] == "oliphaunt-wasix-ts" and row["artifact"] == "npm:" + sdk_carriers[0]["name"]] + if len(originals) == 1 and len(facades) == 1: + original = originals[0] + file_shipping_supplier(name = name + "_held_addon", inputs = {original["file"]["path"]: ""}, + owner = "@oliphaunt_metadata//:product_oliphaunt-wasix-napi", configuration = target["target"], binding = "abi-contract", + origin = json.encode({"kind": "completed-publication", "publication": original["publication"], "artifact": original["artifact"]})) + addon = ":" + name + "_held_addon" + facade = facades[0]["file"]["path"] + napi.update({"version": original["publication"]["version"], "original": original, "facade": facades[0]}) + directory = target["npm_os"] + "-" + target["npm_cpu"] + "-gnu" + _compiled_installed_test(name = name, args = bun_test_entrypoint_args(name), addon = addon, addon_facade = facade, + addon_template = "//src/wasix/node-addon:packages/" + directory + "/package.json", napi_contract = json.encode(napi), + current_addon = "//src/wasix/node-addon:release_carriers" if candidate else None, **kwargs) + +def wasix_compiled_extension_qualification(name, sql_name, module): + wasix_compiled_extension_installed_test(name = name + "_installed_test", sql_name = sql_name, leaf = ":" + name, module = module, + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], size = "large", timeout = "long", tags = ["manual", "installed-consumer"]) + wasix_compiled_extension_shipping(name = name, sql_name = sql_name, carriers = ":" + name, qualification = [ + ":" + name + "_installed_test", ":link_inputs_test", ":invalid_link_profile_test", ":unhandled_linkopts_test", + ":resource_inputs_test", ":cargo_parts_test", "//src/wasix/runtime/tools/xtask:export_policy_test", + ]) diff --git a/build_defs/extensions/wasix_carriers.mts b/build_defs/extensions/wasix_carriers.mts new file mode 100644 index 000000000..dc4c7e986 --- /dev/null +++ b/build_defs/extensions/wasix_carriers.mts @@ -0,0 +1,909 @@ +/** Canonical WASIX extension envelopes from explicitly declared producer outputs. */ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + copyFileSync, + lstatSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + realpathSync, + rmSync, + statSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { stageExtensionWasixNpmPackages } from '../../src/extensions/artifacts/packages/tools/package-extension-release-carriers.mts'; +import { + assertWasixExtensionArchiveInstall, + WASIX_EXTENSION_INSTALL_SCHEMA, + WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA, +} from '../../src/extensions/contracts/wasix-extension-install.mts'; +import { assertWasixAotArtifactPayloads } from '../../src/wasix/runtime/tools/check-release-assets.mts'; +import { + packageDeclaredWasixExtensionCargo, + packageSqlOnlyWasixExtensionCargo, +} from '../../src/wasix/runtime/tools/package_liboliphaunt_wasix_cargo_artifacts.mts'; +import { + assertCanonicalWasixAotManifest, + canonicalWasixAotMetadata, +} from '../../src/wasix/runtime/tools/wasix-aot-manifest.mts'; +import { AOT_TARGET_TRIPLES } from '../../src/wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; +import { createDeterministicTar as payloadTar } from '../../tools/packaging/archive-directory.mts'; +import { createDeterministicTar } from '../../tools/packaging/package-archive.mts'; +import { + decompressSingleZstdFrame, + readPortableArchiveEntries, + readPortableTarZstdBufferEntries, + releaseZstdCompressSync, +} from '../../tools/packaging/portable-archive.mts'; +import { validateCrateSize } from '../../tools/packaging/wasix-cargo-payload.mts'; +import { validateCargoPayloadPartSets } from '../../tools/release/cargo-payload-part-contract.mts'; +import { + extensionCompatibilityMetadata, + extensionSourceMetadata, +} from '../../tools/release/extension-release-metadata.mts'; +import { resolveActualCarrier } from '../../tools/release/publication-catalog.mts'; +import { expandDeclaredTrees } from '../wasix/package.mts'; + +interface Carrier { + product: string; + ecosystem: string; + name: string; + version: string; + target: string | null; + role: string; +} +export interface WasixSqlCarrierSpec { + product: string; + version: string; + sqlName: string; + target: string; + descriptor: Record; + recipe: Record; + source: Record; + selectedDependencies: string[]; + compatibility: Record; + releaseMetadata: Record; + carriers: Carrier[]; + sqlRoot: string; + outputs: { + github: string; + npm: string; + cargo: string; + manifest: string; + frozen: string; + cargoParts?: Record; + }; +} + +/** Authenticate complete canonical parents and their dynamic Cargo parts together. */ +export function readWasixCargoCarrierSet( + carriers: Carrier[], + inputs: string[], + produced?: { name: string; target: string; size: number; sha256: string }[], +) { + const declared = carriers.filter((row) => row.ecosystem === 'cargo'); + const catalog = { + carriers: declared.map((row) => ({ ...row, id: `cargo:${row.name}`, declared: true })), + }; + const parents = new Set(declared.map((row) => row.name)); + const files = inputs.flatMap((input) => { + const entry = lstatSync(input, { throwIfNoEntry: false }); + if (entry?.isFile()) return [input]; + const parent = path.basename(input); + assert(parents.has(parent), 'Cargo parts directory has no canonical parent'); + // Bazel runfiles omit empty TreeArtifact directories. Required parts still + // come from the packed parent manifest and must pass the complete-set check. + if (!entry) return []; + const directory = realpathSync(input); + assert(lstatSync(directory).isDirectory(), 'Cargo parts input must be a directory'); + return readdirSync(directory, { withFileTypes: true }).map((part) => { + assert( + (part.isFile() || part.isSymbolicLink()) && part.name.endsWith('.crate'), + 'Cargo parts output must contain only regular part archives', + ); + assert( + part.name.startsWith(`${parent}-part-`), + 'Cargo part output belongs to a different parent', + ); + // Sandboxed runfiles can materialize a Tree as individual file symlinks. + // Bind each resolved regular file to the same canonical parent and name. + const file = realpathSync(path.join(directory, part.name)); + assert(lstatSync(file).isFile(), 'Cargo part must resolve to a regular archive'); + assert.equal(path.basename(file), part.name, 'Cargo part changed its archive filename'); + assert.equal( + path.basename(path.dirname(file)), + parent, + 'Cargo part resolved outside its canonical parent', + ); + return file; + }); + }); + const records = files.map((file) => { + assert(lstatSync(file).isFile() && !lstatSync(file).isSymbolicLink()); + validateCrateSize(file); + const bytes = readFileSync(file); + const sha256 = createHash('sha256').update(bytes).digest('hex'); + const entries = readPortableArchiveEntries(file); + const prefix = path.basename(file, '.crate'); + const entry = entries.get(`${prefix}/Cargo.toml`); + assert( + entry?.isFile && !entry.isSymbolicLink, + 'Cargo carrier requires its exact packed manifest', + ); + const manifest = Bun.TOML.parse(entry.data().toString()); + assert.equal(prefix, `${manifest.package.name}-${manifest.package.version}`); + const carrier = resolveActualCarrier(catalog, 'cargo', manifest.package.name); + assert.equal(manifest.package.version, carrier.version); + const packageDependencies = Object.entries({ + ...manifest.dependencies, + ...manifest['build-dependencies'], + }).map(([name, declaration]) => { + const requirement = + typeof declaration === 'string' + ? declaration + : (declaration as { version: string }).version; + if (name.startsWith(`${carrier.name}-part-`)) + assert.equal(requirement, `=${carrier.version}`); + return { ecosystem: 'cargo', name, requirement }; + }); + if (produced) { + const row = produced.find((row) => row.name === carrier.name); + assert(row, 'Cargo archive has no produced inventory row'); + assert.equal( + row.target, + carrier.target, + 'Cargo inventory target differs from its canonical parent', + ); + assert.equal(row.size, bytes.length); + assert.equal(row.sha256, sha256); + } + return { ...carrier, packageDependencies, entries, prefix, file, size: bytes.length, sha256 }; + }); + assert.equal( + new Set(records.map((row) => row.id)).size, + records.length, + 'repeated Cargo carrier', + ); + if (produced) + assert.deepEqual(records.map((row) => row.name).sort(), produced.map((row) => row.name).sort()); + assert.deepEqual( + records + .filter((row) => row.declared) + .map((row) => row.name) + .sort(), + declared.map((row) => row.name).sort(), + 'Cargo leaves differ from canonical carrier identities', + ); + validateCargoPayloadPartSets(records); + return records; +} + +/** Read the same complete files/chunks that the canonical Cargo build script consumes. */ +export function readWasixCargoCarrierPayload( + records: ReturnType, + parent: ReturnType[number], +) { + const roots = parent.packageDependencies.some((row) => + row.name.startsWith(`${parent.name}-part-`), + ) + ? records.filter((row) => row.parentCarrier === parent.id) + : [parent]; + const files = new Map(); + const chunks = new Map(); + for (const owner of roots) + for (const [name, entry] of owner.entries) { + const prefix = `${owner.prefix}/payload/`; + if (!name.startsWith(prefix)) continue; + assert(entry.isDirectory || (entry.isFile && !entry.isSymbolicLink)); + if (entry.isDirectory) continue; + const relative = name.slice(prefix.length); + if (relative.startsWith('files/')) { + const destination = relative.slice('files/'.length); + assert(!files.has(destination) && !chunks.has(destination), 'repeated Cargo payload file'); + files.set(destination, Buffer.from(entry.data())); + } else { + const match = /^chunks\/(.+)\.part([0-9]{6})$/u.exec(relative); + assert(match && !files.has(match[1]), 'unexpected Cargo payload member'); + const rows = chunks.get(match[1]) ?? []; + rows.push({ index: Number(match[2]), bytes: Buffer.from(entry.data()) }); + chunks.set(match[1], rows); + } + } + for (const [name, rows] of chunks) { + rows.sort((left, right) => left.index - right.index); + assert.deepEqual( + rows.map((row) => row.index), + rows.map((_, index) => index), + 'non-contiguous Cargo payload chunks', + ); + files.set(name, Buffer.concat(rows.map((row) => row.bytes))); + } + return files; +} + +function writeJson(file: string, value: unknown) { + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`); +} + +export function wasixSqlCarrierLeaves(spec: WasixSqlCarrierSpec) { + assert.equal(spec.sqlName, 'pgtap', 'only the qualified pgTAP SQL producer is admitted'); + assert.equal(spec.product, `oliphaunt-extension-${spec.sqlName.replaceAll('_', '-')}`); + assert.equal(spec.target, 'wasix-portable'); + assert.equal(spec.releaseMetadata.class, 'external'); + assert.equal(spec.releaseMetadata.versioning, 'upstream-bound'); + assert.equal(spec.releaseMetadata.product, spec.product); + assert.equal(spec.releaseMetadata.sqlName, spec.sqlName); + assert.equal( + spec.descriptor['native-module-file'] ?? null, + null, + 'compiled WASIX members require their complete AOT closure', + ); + const artifacts = spec.recipe.artifacts; + for (const key of ['native_modules', 'native_dependency_modules', 'data_files', 'headers']) + assert.deepEqual(artifacts[key] ?? [], [], `SQL-only member cannot carry ${key}`); + const compatibility = extensionCompatibilityMetadata(spec.compatibility); + assert.equal(compatibility.wasixRuntimeProduct, 'liboliphaunt-wasix'); + assert.deepEqual( + spec.releaseMetadata.compatibility, + compatibility, + 'release compatibility differs from its declared package metadata', + ); + assert.deepEqual( + spec.releaseMetadata.sourceIdentity, + extensionSourceMetadata(spec.product, spec.releaseMetadata, spec.source, spec.version), + 'release source identity differs from its pinned SQL producer', + ); + const leaves = ['npm', 'cargo'].map((ecosystem) => { + const rows = spec.carriers.filter( + (row) => + row.ecosystem === ecosystem && row.target === spec.target && row.role === 'portable-leaf', + ); + assert.equal(rows.length, 1, `portable ${ecosystem} leaf must have one canonical identity`); + const row = rows[0]; + assert.equal(row.product, spec.product); + assert.equal(row.version, spec.version); + assert.equal( + row.name, + ecosystem === 'npm' ? `@oliphaunt/extension-${spec.sqlName}-wasix` : `${spec.product}-wasix`, + ); + return row; + }); + assert.equal( + path.basename(spec.outputs.github), + `${spec.product}-${spec.version}-${spec.target}.tar.zst`, + ); + assert.equal(path.basename(spec.outputs.cargo), `${leaves[1].name}-${spec.version}.crate`); + return { npm: leaves[0], cargo: leaves[1], compatibility }; +} + +/** Read exactly the TreeArtifact leaves passed by Bazel's directory expansion. */ +export function declaredSqlFiles(spec: WasixSqlCarrierSpec, files: string[]) { + const root = path.resolve(spec.sqlRoot); + assert( + lstatSync(root).isDirectory() && !lstatSync(root).isSymbolicLink(), + 'SQL root must be a real declared directory', + ); + const names = files + .map((file) => { + const absolute = path.resolve(file); + assert.equal( + path.dirname(absolute), + root, + 'SQL leaf must belong directly to the declared producer tree', + ); + // Bazel sandboxes materialize declared TreeArtifact files as input links. + // Their copied archive destinations are always regular files. + const stat = statSync(absolute); + assert(stat.isFile(), 'SQL leaf must resolve to a regular declared file'); + const name = path.basename(file); + const artifacts = spec.recipe.artifacts; + const allowed = + name === `${spec.sqlName}.control` || + (name.startsWith(`${spec.sqlName}--`) && name.endsWith('.sql')) || + (artifacts.extension_sql_file_names ?? []).includes(name) || + (artifacts.extension_sql_file_prefixes ?? []).some( + (prefix: string) => name.startsWith(`${prefix}--`) && name.endsWith('.sql'), + ); + assert(allowed, `unexpected SQL producer leaf: ${name}`); + assert(stat.size > 0, `empty SQL producer leaf: ${name}`); + return name; + }) + .sort(); + assert.equal(new Set(names).size, names.length, 'SQL producer leaves must be unique'); + const version = spec.source['extension-control']['default-version']; + const required = [ + `${spec.sqlName}.control`, + `${spec.sqlName}--${version}.sql`, + ...(spec.recipe.artifacts.extension_sql_file_names ?? []), + ...(spec.recipe.artifacts.extension_sql_file_prefixes ?? []).map( + (prefix: string) => `${prefix}--${version}.sql`, + ), + ]; + for (const name of required) + assert(names.includes(name), `missing canonical SQL producer leaf: ${name}`); + const control = readFileSync(path.join(root, `${spec.sqlName}.control`), 'utf8'); + assert.equal( + /^default_version\s*=\s*'([^']+)'\s*$/mu.exec(control)?.[1], + version, + 'control default version differs from its pinned producer', + ); + const requires = /^requires\s*=\s*'([^']*)'\s*$/mu.exec(control)?.[1] ?? ''; + assert.deepEqual( + requires + .split(',') + .map((name) => name.trim()) + .filter(Boolean) + .sort(), + [...spec.descriptor.dependencies].sort(), + 'control dependencies differ from the install descriptor', + ); + return names; +} + +export function assembleSqlOnlyWasixMember( + spec: WasixSqlCarrierSpec, + files: string[], + staging: string, +) { + const { compatibility } = wasixSqlCarrierLeaves(spec); + const names = declaredSqlFiles(spec, files); + const destination = path.join(staging, 'share/postgresql/extension'); + mkdirSync(destination, { recursive: true }); + for (const name of names) + copyFileSync(path.join(spec.sqlRoot, name), path.join(destination, name)); + const bytes = releaseZstdCompressSync( + createDeterministicTar(path.join(staging, 'share'), 'share', { fixedFileMode: 0o644 }), + ); + mkdirSync(path.dirname(spec.outputs.github), { recursive: true }); + writeFileSync(spec.outputs.github, bytes); + const lifecycle = spec.descriptor.lifecycle; + const wasixInstall = { + schema: WASIX_EXTENSION_INSTALL_SCHEMA, + name: spec.sqlName, + nativeModule: null, + nativeModules: [], + coreExportsRequired: [], + dependencies: [...spec.descriptor.dependencies].sort(), + loadOrder: spec.descriptor['load-order'] ?? [], + lifecycle: { + createExtension: lifecycle['create-extension'], + createSchema: lifecycle['create-schema'] ?? null, + loadSql: lifecycle['load-sql'], + postCreateSql: lifecycle['post-create-sql'], + startupConfig: lifecycle['startup-config'], + preloadRequired: lifecycle['preload-required'], + restartRequired: lifecycle['restart-required'], + sharedMemoryRequired: lifecycle['shared-memory-required'], + }, + installedFiles: names.map((name) => `share/postgresql/extension/${name}`), + unresolvedImports: [], + }; + const asset = { + name: path.basename(spec.outputs.github), + family: 'wasix', + target: spec.target, + kind: 'wasix-runtime', + identity: null, + bytes: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + }; + assertWasixExtensionArchiveInstall(bytes, { + schema: WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA, + sqlName: spec.sqlName, + archive: `extensions/${spec.sqlName}.tar.zst`, + sha256: asset.sha256, + size: asset.bytes, + install: wasixInstall, + }); + return { + compatibility, + sqlName: spec.sqlName, + createsExtension: lifecycle['create-extension'], + nativeModuleStem: null, + dependencies: spec.selectedDependencies, + dataFiles: [], + extensionSqlFileNames: [...(spec.recipe.artifacts.extension_sql_file_names ?? [])].sort(), + extensionSqlFilePrefixes: [...(spec.recipe.artifacts.extension_sql_file_prefixes ?? [])].sort(), + sharedPreloadLibraries: [], + wasixInstall, + assets: [asset], + }; +} + +export function packageSqlOnlyWasixCarriers(spec: WasixSqlCarrierSpec, files: string[]) { + const leaves = wasixSqlCarrierLeaves(spec); + for (const output of Object.values(spec.outputs)) + mkdirSync(path.dirname(output), { recursive: true }); + const root = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'wasix-sql-envelopes-')); + try { + const member = assembleSqlOnlyWasixMember(spec, files, path.join(root, 'payload')); + const productRoot = path.join(root, 'product'); + const assets = path.join(productRoot, 'release-assets'); + mkdirSync(assets, { recursive: true }); + copyFileSync(spec.outputs.github, path.join(assets, path.basename(spec.outputs.github))); + const frozen = { + schema: 'oliphaunt-extension-ci-artifacts-v1', + product: spec.product, + version: spec.version, + ...member, + }; + const manifest = { + schema: 'oliphaunt-extension-release-manifest-v1', + product: spec.product, + version: spec.version, + extensionClass: 'external', + versioning: 'upstream-bound', + sourceIdentity: spec.releaseMetadata.sourceIdentity, + ...member, + }; + writeJson(path.join(productRoot, 'extension-artifacts.json'), frozen); + writeJson(path.join(assets, path.basename(spec.outputs.manifest)), manifest); + const result = { staged: [] as string[], skipped: [] as string[] }; + assert( + stageExtensionWasixNpmPackages([productRoot], path.join(root, 'npm'), result), + 'canonical WASIX npm writer must produce the declared portable leaf', + ); + assert.equal( + result.staged.length, + 1, + 'SQL-only npm writer must not invent AOT or other leaves', + ); + const npm = result.staged[0]; + const packageJson = JSON.parse( + readPortableArchiveEntries(npm).get('package/package.json')!.data().toString(), + ); + assert.equal(packageJson.name, leaves.npm.name); + assert.equal(packageJson.version, spec.version); + copyFileSync(npm, spec.outputs.npm); + const asset = member.assets[0]; + const cargo = packageSqlOnlyWasixExtensionCargo( + { + product: spec.product, + version: spec.version, + runtimeProduct: leaves.compatibility.wasixRuntimeProduct, + runtimeVersion: leaves.compatibility.wasixRuntimeVersion, + member: { + sqlName: spec.sqlName, + dependencies: spec.selectedDependencies, + archive: spec.outputs.github, + sha256: asset.sha256, + size: asset.bytes, + install: member.wasixInstall, + }, + }, + { outputDir: path.join(root, 'cargo'), workDir: path.join(root, 'cargo-work') }, + ); + assert.equal(cargo.length, 1, 'SQL-only Cargo writer must produce exactly its declared leaf'); + assert.equal(cargo[0].name, leaves.cargo.name); + copyFileSync(cargo[0].cratePath, spec.outputs.cargo); + writeJson(spec.outputs.frozen, frozen); + writeJson(spec.outputs.manifest, manifest); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +export interface WasixCompiledCarrierSpec extends Omit { + operation: 'compiled'; + modules: { name: string; path: string; runtime_path: string }[]; + resources: { source: string; destination: string; tree?: boolean }[]; + link: string; + toolchain: string; + aot: { name: string; target: string; module: string; image: string }[]; +} + +export function stageDeclaredWasixExtensionHost(spec: { + version: string; + archive: string; + module: string; + manifest: string; +}) { + const entries = readPortableArchiveEntries(realpathSync(spec.archive), { format: 'tar.gz' }); + const prefix = `liboliphaunt-wasix-portable-${spec.version}`; + const cargo = Bun.TOML.parse(hostArchiveMember(entries, `${prefix}/Cargo.toml`).toString('utf8')); + assert.equal(cargo.package.name, 'liboliphaunt-wasix-portable'); + assert.equal(cargo.package.version, spec.version); + stageWasixExtensionHostBytes( + spec, + hostArchiveMember(entries, `${prefix}/payload/manifest.json`), + hostArchiveMember(entries, `${prefix}/payload/oliphaunt.wasix.tar.zst`), + ); +} + +export function stageCurrentWasixExtensionHost(spec: { + archive: string; + module: string; + manifest: string; +}) { + const entries = readPortableArchiveEntries(realpathSync(spec.archive), { format: 'tar.zst' }); + const member = (name: string) => + hostArchiveMember(entries, `target/oliphaunt-wasix/assets/${name}`); + stageWasixExtensionHostBytes(spec, member('manifest.json'), member('oliphaunt.wasix.tar.zst')); +} + +function hostArchiveMember(entries: ReturnType, name: string) { + const entry = entries.get(name); + assert(entry?.isFile && !entry.isSymbolicLink, 'host requires original regular archive members'); + return Buffer.from(entry.data()); +} + +function stageWasixExtensionHostBytes( + spec: { module: string; manifest: string }, + manifestBytes: Buffer, + bytes: Buffer, +) { + const manifest = JSON.parse(manifestBytes.toString('utf8')); + assert.equal(manifest['format-version'], 2); + assert.equal(manifest['source-lane'], 'stable'); + assert.equal(manifest.runtime['runtime-kind'], 'wasix-dynamic-main'); + assert.equal(createHash('sha256').update(bytes).digest('hex'), manifest.runtime.sha256); + const entry = readPortableTarZstdBufferEntries(bytes).get('oliphaunt/bin/postgres'); + assert(entry?.isFile && !entry.isSymbolicLink, 'declared host has no physical core module'); + const module = Buffer.from(entry.data()); + assert.equal( + createHash('sha256').update(module).digest('hex'), + manifest.runtime['module-sha256'], + ); + assert.deepEqual(module.subarray(0, 8), Buffer.from([0, 97, 115, 109, 1, 0, 0, 0])); + mkdirSync(path.dirname(spec.module), { recursive: true }); + writeFileSync(spec.module, module); + writeJson(spec.manifest, manifest); +} + +/** Package only the declared compiled member; the canonical writers own registry bytes. */ +export function assertDeclaredWasixResource(entry: { source: string; destination: string }) { + assert( + /^(?:lib\/postgresql\/|share\/postgresql\/)/u.test(entry.destination) && + !entry.destination.split('/').some((part) => !part || part === '.' || part === '..'), + 'unsafe member destination', + ); + const file = statSync(entry.source); + assert(file.isFile(), 'member input must be a declared regular file'); + // PostgreSQL delivers empty upgrade scripts when a version needs no SQL changes. + // Keep those exact files; compiled modules, control files and data remain nonempty. + assert( + file.size > 0 || + (entry.destination.startsWith('share/postgresql/extension/') && + entry.destination.endsWith('.sql')), + 'member input must be nonempty', + ); +} + +export async function stageCompiledWasixMember( + spec: WasixCompiledCarrierSpec, + files: string[], + productRoot: string, + releaseAssets: string, +) { + assert.equal(spec.target, 'wasix-portable'); + const compatibility = extensionCompatibilityMetadata(spec.compatibility); + const link = JSON.parse(readFileSync(spec.link, 'utf8')); + assert.equal(link.schema, 'oliphaunt-declared-wasix-extension-link-v1'); + assert.equal(link.sqlName, spec.sqlName); + assert.deepEqual(link.unresolvedImports, [], 'compiled member has unresolved core imports'); + assert.equal(link.nativeModules.length, spec.modules.length); + const root = mkdtempSync( + path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'wasix-compiled-envelopes-'), + ); + try { + const stage = path.join(root, 'member'); + mkdirSync(releaseAssets, { recursive: true }); + const destinations = new Set(); + const entries = [ + ...expandDeclaredTrees(spec.resources, files), + ...spec.modules.map((row) => ({ source: row.path, destination: row.runtime_path })), + ]; + for (const entry of entries) { + assertDeclaredWasixResource(entry); + assert(!destinations.has(entry.destination), 'duplicate member destination'); + destinations.add(entry.destination); + const destination = path.join(stage, entry.destination); + mkdirSync(path.dirname(destination), { recursive: true }); + copyFileSync(entry.source, destination); + chmodSync(destination, 0o644); + } + const lifecycle = spec.descriptor.lifecycle; + if (lifecycle['create-extension']) { + const version = spec.source['extension-control']['default-version']; + const controlName = `share/postgresql/extension/${spec.sqlName}.control`; + assert(destinations.has(controlName), 'missing canonical compiled control resource'); + const control = readFileSync(path.join(stage, controlName), 'utf8'); + assert.equal(/^default_version\s*=\s*'([^']+)'\s*$/mu.exec(control)?.[1], version); + const modulePath = /^module_pathname\s*=\s*'([^']+)'\s*$/mu.exec(control)?.[1]; + if (modulePath !== undefined) + assert.equal(modulePath, `$libdir/${spec.descriptor['native-module-file'].slice(0, -3)}`); + // PostgreSQL may reach default_version through delivered upgrade scripts. + assert( + entries.some((entry) => { + const name = path.posix.basename(entry.destination); + return ( + name.startsWith(`${spec.sqlName}--`) && + name.endsWith('.sql') && + name.slice(spec.sqlName.length + 2, -4).split('--').length === 1 && + statSync(entry.source).size > 0 + ); + }), + 'missing nonempty compiled base installation SQL', + ); + } + const archiveName = `${spec.product}-${spec.version}-wasix-portable.tar.zst`; + const archive = path.join(releaseAssets, archiveName); + const bytes = releaseZstdCompressSync(await payloadTar(stage)); + writeFileSync(archive, bytes); + const asset = { + name: archiveName, + family: 'wasix', + target: 'wasix-portable', + kind: 'wasix-runtime', + identity: null, + bytes: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + }; + const wasixInstall = { + schema: WASIX_EXTENSION_INSTALL_SCHEMA, + name: spec.sqlName, + nativeModule: spec.descriptor['native-module-file'], + nativeModules: link.nativeModules, + coreExportsRequired: link.coreExportsRequired, + dependencies: [...spec.descriptor.dependencies].sort(), + loadOrder: spec.descriptor['load-order'] ?? [], + lifecycle: { + createExtension: lifecycle['create-extension'], + createSchema: lifecycle['create-schema'] ?? null, + loadSql: lifecycle['load-sql'], + postCreateSql: lifecycle['post-create-sql'], + startupConfig: lifecycle['startup-config'], + preloadRequired: lifecycle['preload-required'], + restartRequired: lifecycle['restart-required'], + sharedMemoryRequired: lifecycle['shared-memory-required'], + }, + installedFiles: [...destinations].sort(), + unresolvedImports: link.unresolvedImports, + }; + assertWasixExtensionArchiveInstall(bytes, { + schema: WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA, + sqlName: spec.sqlName, + archive: `extensions/${spec.sqlName}.tar.zst`, + sha256: asset.sha256, + size: asset.bytes, + install: wasixInstall, + }); + const member = { + compatibility, + sqlName: spec.sqlName, + createsExtension: lifecycle['create-extension'], + nativeModuleStem: spec.descriptor['native-module-file'].slice(0, -3), + dependencies: spec.selectedDependencies, + dataFiles: (spec.recipe.artifacts?.data_files ?? []) + .map((file: string) => { + assert(file.startsWith('share/postgresql/'), 'data resource must use PostgreSQL share'); + return file.slice('share/postgresql/'.length); + }) + .sort(), + extensionSqlFileNames: spec.recipe.artifacts?.extension_sql_file_names ?? [], + extensionSqlFilePrefixes: spec.recipe.artifacts?.extension_sql_file_prefixes ?? [], + sharedPreloadLibraries: lifecycle['startup-config'] + .flatMap((value: string) => + value.startsWith('shared_preload_libraries=') + ? value.slice('shared_preload_libraries='.length).split(',') + : [], + ) + .sort(), + wasixInstall, + assets: [asset], + }; + const canonical = canonicalWasixAotMetadata(); + const targets = Object.entries(AOT_TARGET_TRIPLES); + const bundle = spec.product === 'oliphaunt-extension-contrib-pg18'; + assert.equal( + spec.aot.length, + targets.length * spec.modules.length, + 'compiled member requires every canonical AOT image', + ); + for (const [targetId, triple] of targets) { + const images = spec.aot.filter((row) => row.target === triple); + assert.equal(images.length, spec.modules.length, `incomplete AOT closure for ${targetId}`); + assert.equal(new Set(images.map((row) => row.name)).size, images.length); + const sourceDir = path.join( + productRoot, + 'wasix-aot', + targetId, + ...(bundle ? [spec.sqlName] : []), + ); + mkdirSync(sourceDir, { recursive: true }); + const artifacts = images + .map((row) => { + const module = spec.modules.find((module) => module.path === row.module); + assert(module, 'AOT image has no exact portable member input'); + const name = `extension:${spec.sqlName}${module.name === spec.sqlName ? '' : `:${module.name}`}`; + assert.equal(row.name, name); + const filename = `${module.name}-llvm-opta.bin.zst`; + const compressed = readFileSync(row.image); + const raw = decompressSingleZstdFrame(compressed); + copyFileSync(row.image, path.join(sourceDir, filename)); + return { + name, + path: filename, + sha256: createHash('sha256').update(compressed).digest('hex'), + 'raw-sha256': createHash('sha256').update(raw).digest('hex'), + 'raw-size': raw.length, + 'module-sha256': createHash('sha256').update(readFileSync(row.module)).digest('hex'), + compressed: true, + }; + }) + .sort((left, right) => left.name.localeCompare(right.name)); + const aotManifest = { + 'format-version': 1, + 'source-lane': canonical.sourceLane, + 'source-fingerprint': link.sourceFingerprint, + 'postgres-version': link.postgresVersion, + 'target-triple': triple, + engine: canonical.engine, + 'wasmer-version': canonical.wasmerVersion, + 'wasmer-wasix-version': canonical.wasmerWasixVersion, + artifacts, + }; + assertCanonicalWasixAotManifest(aotManifest, { expectedTarget: triple }); + assertWasixAotArtifactPayloads(aotManifest, { + readArtifact: (relative: string) => readFileSync(path.join(sourceDir, relative)), + }); + writeJson(path.join(sourceDir, 'manifest.json'), aotManifest); + } + return { member, archive, archiveName, asset, wasixInstall }; + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +export async function packageCompiledWasixCarriers( + spec: WasixCompiledCarrierSpec, + files: string[], +) { + assert.equal(spec.product, `oliphaunt-extension-${spec.sqlName.replaceAll('_', '-')}`); + assert.equal(spec.releaseMetadata.versioning, 'upstream-bound'); + assert.equal(spec.releaseMetadata.sqlName, spec.sqlName); + const compatibility = extensionCompatibilityMetadata(spec.compatibility); + assert.deepEqual(spec.releaseMetadata.compatibility, compatibility); + const root = mkdtempSync( + path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'wasix-final-envelopes-'), + ); + try { + const productRoot = path.join(root, 'product'); + const { member, archive, archiveName, asset, wasixInstall } = await stageCompiledWasixMember( + spec, + files, + productRoot, + path.join(productRoot, 'release-assets'), + ); + const frozen = { + schema: 'oliphaunt-extension-ci-artifacts-v1', + product: spec.product, + version: spec.version, + ...member, + }; + const manifest = { + schema: 'oliphaunt-extension-release-manifest-v1', + product: spec.product, + version: spec.version, + extensionClass: 'external', + versioning: 'upstream-bound', + sourceIdentity: spec.releaseMetadata.sourceIdentity, + ...member, + }; + writeJson(path.join(productRoot, 'extension-artifacts.json'), frozen); + writeJson( + path.join(productRoot, 'release-assets', path.basename(spec.outputs.manifest)), + manifest, + ); + const targets = Object.entries(AOT_TARGET_TRIPLES); + const result = { staged: [] as string[], skipped: [] as string[] }; + assert(stageExtensionWasixNpmPackages([productRoot], path.join(root, 'npm-stage'), result)); + assert.equal( + result.staged.length, + targets.length + 1, + 'canonical npm writer must produce portable and all AOT leaves', + ); + mkdirSync(spec.outputs.npm, { recursive: true }); + const npmNames = []; + for (const file of result.staged) { + const metadata = JSON.parse( + readPortableArchiveEntries(file).get('package/package.json')!.data().toString(), + ); + assert.equal(metadata.version, spec.version); + npmNames.push(metadata.name); + copyFileSync(file, path.join(spec.outputs.npm, path.basename(file))); + } + assert.deepEqual( + npmNames.sort(), + spec.carriers + .filter((row) => row.ecosystem === 'npm') + .map((row) => row.name) + .sort(), + 'npm leaves differ from canonical carrier identities', + ); + const cargoPackages = packageDeclaredWasixExtensionCargo( + { + product: spec.product, + version: spec.version, + runtimeProduct: compatibility.wasixRuntimeProduct, + runtimeVersion: compatibility.wasixRuntimeVersion, + versioning: 'upstream-bound', + extensionRoot: productRoot, + members: [ + { + sqlName: spec.sqlName, + dependencies: spec.selectedDependencies, + nativeModuleStem: member.nativeModuleStem, + archive, + sha256: asset.sha256, + size: asset.bytes, + install: wasixInstall, + }, + ], + }, + { outputDir: path.join(root, 'cargo-packages'), workDir: path.join(root, 'cargo-work') }, + ); + const cargo = readWasixCargoCarrierSet( + spec.carriers, + cargoPackages.map((row) => row.cratePath), + cargoPackages, + ); + const parts = cargo.filter((row) => !row.declared); + const partRoots = spec.outputs.cargoParts ?? {}; + if (Object.keys(partRoots).length) + assert.deepEqual( + Object.keys(partRoots).sort(), + cargo + .filter((row) => row.declared) + .map((row) => row.name) + .sort(), + ); + else + assert.equal(parts.length, 0, 'generated Cargo parts require their declared parent outputs'); + for (const directory of Object.values(partRoots)) mkdirSync(directory, { recursive: true }); + mkdirSync(spec.outputs.cargo, { recursive: true }); + for (const carrier of cargo) + copyFileSync( + carrier.file, + path.join( + carrier.declared + ? spec.outputs.cargo + : partRoots[carrier.parentCarrier.slice('cargo:'.length)], + path.basename(carrier.file), + ), + ); + mkdirSync(spec.outputs.github, { recursive: true }); + copyFileSync(archive, path.join(spec.outputs.github, archiveName)); + writeJson(spec.outputs.frozen, frozen); + writeJson(spec.outputs.manifest, manifest); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + const [input, leaves] = process.argv.slice(2); + const spec = JSON.parse(readFileSync(input, 'utf8')); + if (spec.operation === 'host') stageDeclaredWasixExtensionHost(spec); + else if (spec.operation === 'current-host') stageCurrentWasixExtensionHost(spec); + else if (spec.operation === 'compiled') { + assert(leaves?.startsWith('--resource-files=')); + const inventory = readFileSync(leaves.slice('--resource-files='.length), 'utf8').trim(); + await packageCompiledWasixCarriers(spec, inventory ? inventory.split('\n') : []); + } else { + assert( + input && leaves?.startsWith('--sql-files='), + 'usage: wasix_carriers.mts --sql-files=', + ); + packageSqlOnlyWasixCarriers( + spec, + readFileSync(leaves.slice('--sql-files='.length), 'utf8').trimEnd().split('\n'), + ); + } +} diff --git a/build_defs/extensions/wasix_carriers.test.mts b/build_defs/extensions/wasix_carriers.test.mts new file mode 100644 index 000000000..267ceca9b --- /dev/null +++ b/build_defs/extensions/wasix_carriers.test.mts @@ -0,0 +1,408 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + realpathSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { + assertWasixExtensionArchiveInstall, + WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA, +} from '../../src/extensions/contracts/wasix-extension-install.mts'; +import { packageSqlOnlyWasixExtensionCargo } from '../../src/wasix/runtime/tools/package_liboliphaunt_wasix_cargo_artifacts.mts'; +import { createDeterministicTar } from '../../tools/packaging/archive-directory.mts'; +import { + canonicalGzipSync, + readPortableArchiveEntries, + releaseZstdCompressSync, +} from '../../tools/packaging/portable-archive.mts'; +import { extensionCompatibilityMetadata } from '../../tools/release/extension-release-metadata.mts'; +import { + declaredSqlFiles, + packageSqlOnlyWasixCarriers, + stageCurrentWasixExtensionHost, + stageDeclaredWasixExtensionHost, + type WasixSqlCarrierSpec, + wasixSqlCarrierLeaves, +} from './wasix_carriers.mts'; + +const [input, github, npm, cargo, manifest, frozen, sqlRoot] = process.argv.slice(2); +assert(input, 'expected canonical pgTAP WASIX carrier metadata'); +const metadata = JSON.parse(readFileSync(input, 'utf8')); +const readJson = (file: string) => JSON.parse(readFileSync(file, 'utf8')); +const digest = (file: string) => createHash('sha256').update(readFileSync(file)).digest('hex'); + +async function checkCarriers(spec: WasixSqlCarrierSpec, sql: string[]) { + const leaves = wasixSqlCarrierLeaves(spec); + const bytes = readFileSync(spec.outputs.github); + const frozen = readJson(spec.outputs.frozen); + const manifest = readJson(spec.outputs.manifest); + assert.deepEqual(frozen.compatibility, extensionCompatibilityMetadata(spec.compatibility)); + assert.deepEqual(manifest.compatibility, frozen.compatibility); + assert.deepEqual(manifest.sourceIdentity, spec.releaseMetadata.sourceIdentity); + assert.equal(frozen.product, spec.product); + assert.equal(frozen.version, spec.version); + assert.equal(frozen.nativeModuleStem, null); + assert.equal(frozen.assets.length, 1); + const asset = frozen.assets[0]; + assert.equal(asset.sha256, digest(spec.outputs.github)); + assert.deepEqual(manifest.assets, frozen.assets); + assertWasixExtensionArchiveInstall(bytes, { + schema: WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA, + sqlName: spec.sqlName, + archive: `extensions/${spec.sqlName}.tar.zst`, + sha256: asset.sha256, + size: asset.bytes, + install: frozen.wasixInstall, + }); + const portable = readPortableArchiveEntries(spec.outputs.github); + const files = [...portable].filter(([, row]) => row.isFile).map(([name]) => name); + assert.deepEqual( + files, + sql.map((file) => `share/postgresql/extension/${path.basename(file)}`).sort(), + ); + for (const file of sql) + assert.deepEqual( + portable.get(`share/postgresql/extension/${path.basename(file)}`)!.data(), + readFileSync(file), + ); + const npmFiles = readPortableArchiveEntries(spec.outputs.npm); + const packageJson = JSON.parse(npmFiles.get('package/package.json')!.data().toString()); + assert.equal(packageJson.name, leaves.npm.name); + assert.equal(packageJson.version, spec.version); + assert.equal(packageJson.oliphaunt.runtime, 'wasix'); + assert.deepEqual( + npmFiles.get(`package/extensions/${spec.sqlName}/extension.tar.zst`)!.data(), + bytes, + ); + const installation = mkdtempSync( + path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'installed-wasix-sql-'), + ); + try { + for (const [file, entry] of npmFiles) { + if (!entry.isFile) continue; + const destination = path.join(installation, file); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, entry.data()); + } + const entry = path.join(installation, 'package', packageJson.exports['.'].import); + const { default: descriptor } = await import(pathToFileURL(entry).href); + assert.equal(descriptor.product, spec.product); + assert.equal(descriptor.version, spec.version); + assert.equal( + descriptor.compatibility.wasixRuntimeVersion, + spec.compatibility.wasix_runtime_version, + ); + assert(Object.isFrozen(descriptor) && Object.isFrozen(descriptor.carriers[0].install)); + assert.equal(descriptor.carriers.length, 1); + assert.deepEqual(descriptor.carriers[0].install, frozen.wasixInstall); + assert.deepEqual(readFileSync(descriptor.carriers[0].source), bytes); + } finally { + rmSync(installation, { recursive: true, force: true }); + } + const cargoFiles = readPortableArchiveEntries(spec.outputs.cargo); + const prefix = `${leaves.cargo.name}-${spec.version}`; + const cargoToml = Bun.TOML.parse(cargoFiles.get(`${prefix}/Cargo.toml`)!.data().toString()); + assert.equal(cargoToml.package.name, leaves.cargo.name); + assert.equal(cargoToml.package.version, spec.version); + assert.deepEqual( + cargoFiles.get(`${prefix}/payload/files/extensions/${spec.sqlName}/extension.tar.zst`)!.data(), + bytes, + ); + const build = cargoFiles.get(`${prefix}/build.rs`)!.data().toString(); + assert( + build.includes( + `const RUNTIME_VERSION: &str = ${JSON.stringify(spec.compatibility.wasix_runtime_version)};`, + ), + ); + assert([...npmFiles.keys()].some((file) => file.startsWith('package/share/licenses/pgtap/'))); + assert([...cargoFiles.keys()].some((file) => file.startsWith(`${prefix}/share/licenses/pgtap/`))); + assert( + ![...npmFiles.keys(), ...cargoFiles.keys()].some( + (file) => file.endsWith('.wasmu') || file.endsWith('.wasm'), + ), + ); +} + +if (github) { + assert( + npm && cargo && manifest && frozen && sqlRoot, + 'production proof requires all final envelopes and their sole SQL input', + ); + const production = realpathSync(sqlRoot); + await checkCarriers( + { + ...metadata, + sqlRoot: production, + outputs: { + github: realpathSync(github), + npm: realpathSync(npm), + cargo: realpathSync(cargo), + manifest: realpathSync(manifest), + frozen: realpathSync(frozen), + }, + }, + readdirSync(production).map((name) => path.join(production, name)), + ); + console.log('installed pgTAP WASIX npm/Cargo/GitHub envelopes preserve the exact production SQL'); + process.exit(0); +} + +const root = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'wasix-sql-carrier-test-')); +try { + // Both host paths validate the same physical inner runtime. The current path + // must obtain it from the original release archive, never an adapter payload. + const outer = path.join(root, 'runtime-release'); + const assets = path.join(outer, 'target/oliphaunt-wasix/assets'); + const runtime = path.join(root, 'runtime'); + mkdirSync(path.join(runtime, 'oliphaunt/bin'), { recursive: true }); + const core = Buffer.from([0, 97, 115, 109, 1, 0, 0, 0]); + writeFileSync(path.join(runtime, 'oliphaunt/bin/postgres'), core); + const runtimeBytes = releaseZstdCompressSync(await createDeterministicTar(runtime)); + const hash = (bytes: Buffer) => createHash('sha256').update(bytes).digest('hex'); + const hostManifest = { + 'format-version': 2, + 'source-lane': 'stable', + runtime: { + 'runtime-kind': 'wasix-dynamic-main', + sha256: hash(runtimeBytes), + 'module-sha256': hash(core), + }, + }; + mkdirSync(assets, { recursive: true }); + writeFileSync(path.join(assets, 'manifest.json'), JSON.stringify(hostManifest)); + writeFileSync(path.join(assets, 'oliphaunt.wasix.tar.zst'), runtimeBytes); + const archive = path.join(root, 'liboliphaunt-wasix.tar.zst'); + writeFileSync(archive, releaseZstdCompressSync(await createDeterministicTar(outer))); + const currentHost = { + archive, + module: path.join(root, 'current-host/postgres.wasm'), + manifest: path.join(root, 'current-host/manifest.json'), + }; + stageCurrentWasixExtensionHost(currentHost); + const version = metadata.compatibility.wasix_runtime_version; + const crateRoot = path.join(root, 'portable-crate'); + const cratePackage = path.join(crateRoot, `liboliphaunt-wasix-portable-${version}`); + mkdirSync(path.join(cratePackage, 'payload'), { recursive: true }); + writeFileSync( + path.join(cratePackage, 'Cargo.toml'), + `[package]\nname="liboliphaunt-wasix-portable"\nversion="${version}"\n`, + ); + writeFileSync(path.join(cratePackage, 'payload/manifest.json'), JSON.stringify(hostManifest)); + writeFileSync(path.join(cratePackage, 'payload/oliphaunt.wasix.tar.zst'), runtimeBytes); + const crate = path.join(root, 'retained-portable-input'); + writeFileSync(crate, canonicalGzipSync(await createDeterministicTar(crateRoot))); + const heldHost = { + archive: crate, + version, + module: path.join(root, 'held-host/postgres.wasm'), + manifest: path.join(root, 'held-host/manifest.json'), + }; + stageDeclaredWasixExtensionHost(heldHost); + assert.throws( + () => stageDeclaredWasixExtensionHost({ ...heldHost, version: '99.0.0' }), + /original regular archive members/u, + ); + assert.deepEqual(readFileSync(currentHost.module), core); + assert.deepEqual(readFileSync(currentHost.module), readFileSync(heldHost.module)); + assert.deepEqual(readFileSync(currentHost.manifest), readFileSync(heldHost.manifest)); + // A changed inner payload cannot borrow the original manifest's hash, and a + // failed extraction must leave the previously validated outputs untouched. + writeFileSync(path.join(assets, 'oliphaunt.wasix.tar.zst'), Buffer.from('wrong runtime')); + writeFileSync(archive, releaseZstdCompressSync(await createDeterministicTar(outer))); + assert.throws(() => stageCurrentWasixExtensionHost(currentHost)); + assert.deepEqual(readFileSync(currentHost.module), core); + rmSync(path.join(assets, 'manifest.json')); + writeFileSync(archive, releaseZstdCompressSync(await createDeterministicTar(outer))); + assert.throws( + () => stageCurrentWasixExtensionHost(currentHost), + /original regular archive members/u, + ); + const sqlRoot = path.join(root, 'sql'); + mkdirSync(sqlRoot); + const defaultVersion = metadata.source['extension-control']['default-version']; + const sql = [ + ['pgtap.control', `default_version = '${defaultVersion}'\nrequires = 'plpgsql'\n`], + [`pgtap--${defaultVersion}.sql`, '-- canonical fixture SQL\nSELECT 1;\n'], + [`pgtap-core--${defaultVersion}.sql`, '-- canonical core SQL\n'], + [`pgtap-schema--${defaultVersion}.sql`, '-- canonical schema SQL\n'], + ['uninstall_pgtap.sql', '-- canonical uninstall SQL\n'], + ['pgtap--1.3.4--1.3.5.sql', '-- canonical upgrade SQL\n'], + ].map(([name, bytes]) => { + const file = path.join(sqlRoot, name); + writeFileSync(file, bytes); + return file; + }); + const specAt = (name: string): WasixSqlCarrierSpec => { + const out = path.join(root, name); + return { + ...structuredClone(metadata), + sqlRoot, + outputs: { + github: path.join(out, `${metadata.product}-${metadata.version}-wasix-portable.tar.zst`), + npm: path.join(out, `oliphaunt-extension-pgtap-wasix-${metadata.version}.tgz`), + cargo: path.join(out, `oliphaunt-extension-pgtap-wasix-${metadata.version}.crate`), + manifest: path.join(out, `${metadata.product}-${metadata.version}-manifest.json`), + frozen: path.join(out, 'extension-artifacts.json'), + }, + }; + }; + const first = specAt('first'); + packageSqlOnlyWasixCarriers(first, sql); + await checkCarriers(first, sql); + const second = specAt('second'); + packageSqlOnlyWasixCarriers(second, [...sql].reverse()); + for (const key of Object.keys(first.outputs) as (keyof WasixSqlCarrierSpec['outputs'])[]) + assert.deepEqual( + readFileSync(first.outputs[key]), + readFileSync(second.outputs[key]), + `nondeterministic ${key} envelope`, + ); + writeFileSync(sql[1], '-- changed source SQL\nSELECT 2;\n'); + const changed = specAt('changed'); + packageSqlOnlyWasixCarriers(changed, sql); + await checkCarriers(changed, sql); + for (const key of ['github', 'npm', 'cargo'] as const) + assert.notEqual( + digest(first.outputs[key]), + digest(changed.outputs[key]), + `${key} failed to propagate changed SQL`, + ); + assert.deepEqual( + readJson(first.outputs.frozen).compatibility, + readJson(changed.outputs.frozen).compatibility, + 'changing SQL must preserve the declared held runtime versions', + ); + // Replay few/many changes through public envelopes with a reproducible seed. + let seed = 294; + const random = () => (seed = (Math.imul(seed, 1664525) + 1013904223) >>> 0); + for (const count of [0, 3, 64]) { + const additional = Array.from({ length: count }, (_, index) => { + const file = path.join(sqlRoot, `pgtap--8.${index}.0--8.${index}.1.sql`); + writeFileSync(file, `-- scenario seed 294\nSELECT ${random()};\n`); + return file; + }); + const scenario = specAt(`scenario-${count}`); + scenario.version = count === 64 ? '1.0.0' : count === 3 ? '0.4.0' : '0.3.3'; + for (const carrier of scenario.carriers) carrier.version = scenario.version; + const out = path.dirname(scenario.outputs.github); + scenario.outputs.github = path.join( + out, + `${scenario.product}-${scenario.version}-wasix-portable.tar.zst`, + ); + scenario.outputs.cargo = path.join(out, `${scenario.product}-wasix-${scenario.version}.crate`); + scenario.outputs.manifest = path.join( + out, + `${scenario.product}-${scenario.version}-manifest.json`, + ); + packageSqlOnlyWasixCarriers(scenario, [...additional, ...sql]); + await checkCarriers(scenario, [...sql, ...additional]); + assert.deepEqual( + readJson(scenario.outputs.frozen).compatibility, + readJson(first.outputs.frozen).compatibility, + ); + for (const file of additional) rmSync(file); + } + for (const missing of sql.slice(0, 5)) + assert.throws( + () => + declaredSqlFiles( + first, + sql.filter((file) => file !== missing), + ), + /missing canonical SQL/u, + ); + assert.throws(() => declaredSqlFiles(first, [...sql, sql[1]]), /unique/u); + const unexpected = path.join(sqlRoot, 'foreign.wasm'); + writeFileSync(unexpected, '\0asm'); + assert.throws(() => declaredSqlFiles(first, [...sql, unexpected]), /unexpected SQL/u); + const foreign = path.join(root, path.basename(sql[1])); + writeFileSync(foreign, '-- undeclared source'); + assert.throws( + () => declaredSqlFiles(first, [foreign, ...sql.slice(1)]), + /declared producer tree/u, + ); + const directory = path.join(sqlRoot, 'pgtap--9.9.9.sql'); + mkdirSync(directory); + assert.throws(() => declaredSqlFiles(first, [...sql, directory]), /regular declared file/u); + const declaredLinks = path.join(root, 'declared-links'); + mkdirSync(declaredLinks); + const linkFiles = sql.map((file) => { + const link = path.join(declaredLinks, path.basename(file)); + symlinkSync(file, link); + return link; + }); + assert.deepEqual( + declaredSqlFiles({ ...first, sqlRoot: declaredLinks }, linkFiles), + declaredSqlFiles(first, sql), + 'Bazel input links must preserve the declared regular SQL file inventory', + ); + writeFileSync(sql[0], "default_version = '99.0.0'\n"); + assert.throws(() => declaredSqlFiles(first, sql), /control default version/u); + for (const mutate of [ + (spec: WasixSqlCarrierSpec) => { + spec.product = 'oliphaunt-extension-vector'; + }, + (spec: WasixSqlCarrierSpec) => { + spec.target = 'linux-x64-gnu'; + }, + (spec: WasixSqlCarrierSpec) => { + spec.descriptor['native-module-file'] = 'pgtap.so'; + }, + (spec: WasixSqlCarrierSpec) => { + spec.carriers.find( + (row) => row.role === 'portable-leaf' && row.ecosystem === 'npm', + )!.version = '99.0.0'; + }, + (spec: WasixSqlCarrierSpec) => { + spec.recipe.artifacts.data_files = ['share/postgresql/foreign']; + }, + (spec: WasixSqlCarrierSpec) => { + spec.source.commit = '0'.repeat(40); + }, + (spec: WasixSqlCarrierSpec) => { + spec.compatibility.wasix_runtime_version = '99.0.0'; + }, + ]) { + const corrupt = specAt('corrupt'); + mutate(corrupt); + assert.throws(() => wasixSqlCarrierLeaves(corrupt)); + } + const member = readJson(first.outputs.frozen); + const asset = member.assets[0]; + const cargoSpec = { + product: first.product, + version: first.version, + runtimeProduct: first.compatibility.wasix_runtime_product, + runtimeVersion: first.compatibility.wasix_runtime_version, + member: { + sqlName: first.sqlName, + dependencies: first.selectedDependencies, + archive: first.outputs.github, + sha256: '0'.repeat(64), + size: asset.bytes, + install: member.wasixInstall, + }, + }; + assert.throws( + () => + packageSqlOnlyWasixExtensionCargo(cargoSpec, { + outputDir: path.join(root, 'bad-cargo'), + workDir: path.join(root, 'bad-work'), + }), + /digest differs/u, + ); + console.log( + 'pgTAP WASIX final envelopes preserve exact production SQL, compatibility, determinism, legal bytes, and canonical Cargo/npm identities', + ); +} finally { + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/extensions/windows_module_test.bzl b/build_defs/extensions/windows_module_test.bzl new file mode 100644 index 000000000..a5e4fb6e1 --- /dev/null +++ b/build_defs/extensions/windows_module_test.bzl @@ -0,0 +1,89 @@ +"""Actual Windows module actions must agree on their static/shared boundary.""" + +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") +load("@rules_cc//cc/common:cc_shared_library_info.bzl", "CcSharedLibraryInfo") +load("//build_defs/native:platform_config.bzl", "NATIVE_WINDOWS_COMPATIBLE") + +def _objects(linker_input): + result = [] + for library in linker_input.libraries: + result.extend((library.pic_objects if library.pic_static_library else library.objects) or []) + return result + +def _impl(ctx): + env = analysistest.begin(ctx) + target = analysistest.target_under_test(env) + asserts.equals(env, [ctx.attr.dll_name], [file.basename for file in target[DefaultInfo].files.to_list()]) + asserts.true(env, CcSharedLibraryInfo in target, "Windows modules must use the stock shared-library ownership rule") + if CcSharedLibraryInfo not in target: + return analysistest.end(env) + actions = analysistest.target_actions(env) + parsers = [action for action in actions if action.mnemonic == "DefParser"] + links = [action for action in actions if action.mnemonic == "CppLink"] + asserts.equals(env, 1, len(parsers)) + asserts.equals(env, 1, len(links)) + if len(parsers) != 1 or len(links) != 1: + return analysistest.end(env) + definition_inputs = {file.path: True for file in parsers[0].inputs.to_list()} + for library in ctx.attr.static_libraries: + if library.label.name in ["libxml2", ctx.attr.dll_name[:-4] + "_objects"]: + asserts.true(env, "LIBXML_STATIC" in library[CcInfo].compilation_context.defines.to_list(), "libxml2 static mode must reach its owner and real module consumer: " + str(library.label)) + own_objects = [file for entry in library[CcInfo].linking_context.linker_inputs.to_list() if entry.owner == library.label for file in _objects(entry)] + asserts.true(env, len(own_objects) > 0, "static module fixture must contribute actual compiled objects: " + str(library.label)) + for file in own_objects: + asserts.true(env, file.path in definition_inputs, "static module object missing from DEF: " + file.path) + link_inputs = {file.path: True for file in links[0].inputs.to_list()} + for file in parsers[0].outputs.to_list(): + asserts.true(env, file.path in link_inputs, "link must consume the actual stock-generated DEF") + asserts.true(env, ctx.file.runtime_interface.path in link_inputs, "link must retain its actual PostgreSQL ABI import library") + asserts.false(env, any(["liboliphaunt_postgis_deps" in file.basename for file in links[0].inputs.to_list()]), "Windows PostGIS must incorporate its dependency objects without a private DLL import") + return analysistest.end(env) + +_test = analysistest.make(_impl, attrs = { + "dll_name": attr.string(mandatory = True), + "static_libraries": attr.label_list(mandatory = True, providers = [CcInfo]), + "runtime_interface": attr.label(mandatory = True, allow_single_file = True), +}) + +def _crypto_impl(ctx): + env = analysistest.begin(ctx) + target = analysistest.target_under_test(env) + crypto = ctx.attr.crypto + expected = ["ws2_32.lib", "gdi32.lib", "advapi32.lib", "crypt32.lib", "user32.lib"] + owner_flags = [flag for entry in crypto[CcInfo].linking_context.linker_inputs.to_list() if entry.owner == crypto.label for flag in entry.user_link_flags] + asserts.equals(env, sorted(expected), sorted(owner_flags), "libcrypto must own its canonical Windows system requirements") + asserts.equals(env, [ctx.attr.dll_name], [file.basename for file in target[DefaultInfo].files.to_list()]) + asserts.true(env, CcSharedLibraryInfo in target, "pgcrypto must retain the stock module rule") + links = [action for action in analysistest.target_actions(env) if action.mnemonic == "CppLink"] + asserts.equals(env, 1, len(links)) + if len(links) == 1: + for flag in expected: + asserts.true(env, flag in links[0].argv, "libcrypto system requirement missing from actual pgcrypto link: " + flag) + return analysistest.end(env) + +_crypto_test = analysistest.make(_crypto_impl, attrs = { + "crypto": attr.label(mandatory = True, providers = [CcInfo]), + "dll_name": attr.string(mandatory = True), +}) + +def native_windows_module_tests(): + for variant in ["server", "embedded"]: + objects = "//src/extensions/external/postgis:postgis_" + variant + "_objects" + _test( + name = "postgis_" + variant + "_windows_link_test", + target_under_test = "//src/extensions/external/postgis:postgis_" + variant + ".dll", + dll_name = "postgis_" + variant + ".dll", + static_libraries = [objects, "//build_defs/extensions/postgis:postgis_lwgeom", "//build_defs/extensions/postgis:postgis_flatgeobuf"] + ["//build_defs/extensions/postgis:" + name for name in ["geos", "proj", "json_c", "libxml2", "iconv", "sqlite"]], + runtime_interface = "@postgres//:server_windows_interface" if variant == "server" else "//src/native/runtime:runtime_windows_interface", + target_compatible_with = NATIVE_WINDOWS_COMPATIBLE, + size = "small", + ) + _crypto_test( + name = "pgcrypto_" + variant + "_windows_link_test", + target_under_test = "//src/extensions/contrib:pgcrypto_" + variant + ".dll", + dll_name = "pgcrypto_" + variant + ".dll", + crypto = "@openssl//:crypto", + target_compatible_with = NATIVE_WINDOWS_COMPATIBLE, + size = "small", + ) diff --git a/build_defs/extensions/windows_source_inputs.mts b/build_defs/extensions/windows_source_inputs.mts new file mode 100644 index 000000000..9bc160b7c --- /dev/null +++ b/build_defs/extensions/windows_source_inputs.mts @@ -0,0 +1,69 @@ +/** Transform only the explicitly declared pinned extension source files. */ +import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { windowsExtensionHeaders, windowsExtensionSource } from './windows_source_portability.mts'; + +export interface WindowsSourceInputs { + extension: string; + files: { name: string; source: string; output: string }[]; + headers: { name: string; output: string }[]; +} + +export function prepareWindowsSources(spec: WindowsSourceInputs): void { + if (!['pg_uuidv7', 'pg_textsearch', 'postgis'].includes(spec.extension)) { + throw new Error('Windows source preparation requires an existing pinned source adaptation'); + } + const generated = windowsExtensionHeaders(spec.extension); + const names = new Set(); + const outputs = new Set(); + const validate = (name: string, output: string) => { + if ( + typeof name !== 'string' || + !name || + name.includes('\\') || + name.split('/').some((part) => !part || part === '.' || part === '..') + ) { + throw new Error('Windows extension source requires a safe relative name'); + } + if ( + typeof output !== 'string' || + !output || + names.has(name) || + outputs.has(path.resolve(output)) + ) { + throw new Error('Windows extension source has missing or duplicate declared outputs'); + } + names.add(name); + outputs.add(path.resolve(output)); + }; + for (const file of spec.files) validate(file.name, file.output); + for (const file of spec.headers) validate(file.name, file.output); + if ( + JSON.stringify(spec.headers.map((file) => file.name).sort()) !== + JSON.stringify(Object.keys(generated).sort()) + ) { + throw new Error('Windows compatibility headers differ from the shared source recipe'); + } + const utf8 = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }); + // Validate every source and transformation before writing any output. + const transformed = spec.files.map((file) => ({ + ...file, + text: windowsExtensionSource(spec.extension, file.name, utf8.decode(readFileSync(file.source))), + })); + for (const file of [ + ...transformed, + ...spec.headers.map((file) => ({ ...file, text: generated[file.name] })), + ]) { + mkdirSync(path.dirname(file.output), { recursive: true }); + writeFileSync(file.output, file.text); + } +} + +if (import.meta.main) { + const [file, ...extra] = process.argv.slice(2); + if (!file || extra.length) + throw new Error('usage: windows_source_inputs.mts DECLARED_INPUTS.json'); + prepareWindowsSources( + JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(readFileSync(file))), + ); +} diff --git a/build_defs/extensions/windows_source_inputs.test.mts b/build_defs/extensions/windows_source_inputs.test.mts new file mode 100644 index 000000000..39c192ded --- /dev/null +++ b/build_defs/extensions/windows_source_inputs.test.mts @@ -0,0 +1,85 @@ +import { afterEach, expect, test } from 'bun:test'; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { prepareWindowsSources, type WindowsSourceInputs } from './windows_source_inputs.mts'; + +const directories: string[] = []; +function fixture(): { root: string; spec: WindowsSourceInputs } { + const root = mkdtempSync( + path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'windows-extension-inputs-'), + ); + directories.push(root); + const source = path.join(root, 'uuid.c'); + writeFileSync( + source, + '// pinned source café\r\n#define EPOCH_DIFF_USECS ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * USECS_PER_DAY)\r\n', + ); + return { + root, + spec: { + extension: 'pg_uuidv7', + files: [{ name: 'pg_uuidv7.c', source, output: path.join(root, 'declared/pg_uuidv7.c') }], + headers: [], + }, + }; +} +afterEach(() => { + for (const directory of directories.splice(0)) + rmSync(directory, { recursive: true, force: true }); +}); + +test('declared source transformation preserves original files and unchanged nested input bytes', () => { + const { root, spec } = fixture(); + const original = readFileSync(spec.files[0].source); + const nested = path.join(root, 'header'); + const bytes = Buffer.from('\ufeff// unrelated source café\r\n'); + writeFileSync(nested, bytes); + spec.files.push({ + name: 'include/nested/header.h', + source: nested, + output: path.join(root, 'declared/include/nested/header.h'), + }); + prepareWindowsSources(spec); + expect(readFileSync(spec.files[0].source)).toEqual(original); + expect(readFileSync(spec.files[0].output, 'utf8')).toContain( + 'GetCurrentTimestamp() + EPOCH_DIFF_USECS', + ); + expect(readFileSync(spec.files[1].output)).toEqual(bytes); +}); + +test('missing, ambiguous or malformed source rejects before any output is written', () => { + for (const bytes of [ + Buffer.from('missing anchor\n'), + Buffer.from([0xff]), + Buffer.from( + '#define EPOCH_DIFF_USECS ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * USECS_PER_DAY)\n'.repeat( + 2, + ), + ), + ]) { + const { spec } = fixture(); + writeFileSync(spec.files[0].source, bytes); + expect(() => prepareWindowsSources(spec)).toThrow(); + expect(() => readFileSync(spec.files[0].output)).toThrow(); + } +}); + +test('declared output names, membership and compatibility headers are checked before copying', () => { + const unknown = fixture(); + unknown.spec.extension = 'unreviewed'; + expect(() => prepareWindowsSources(unknown.spec)).toThrow('existing pinned'); + for (const name of ['', '../escape', '/absolute', 'dir//empty', 'dir\\file']) { + const { spec } = fixture(); + spec.files[0].name = name; + expect(() => prepareWindowsSources(spec)).toThrow('safe relative'); + } + const { spec } = fixture(); + spec.files.push({ ...spec.files[0] }); + expect(() => prepareWindowsSources(spec)).toThrow('duplicate'); + spec.files.pop(); + spec.headers.push({ name: 'invented.h', output: spec.files[0].output }); + expect(() => prepareWindowsSources(spec)).toThrow('duplicate'); + spec.headers[0].output += '.other'; + expect(() => prepareWindowsSources(spec)).toThrow('shared source recipe'); +}); diff --git a/build_defs/extensions/windows_source_portability.mts b/build_defs/extensions/windows_source_portability.mts new file mode 100644 index 000000000..d511c40cf --- /dev/null +++ b/build_defs/extensions/windows_source_portability.mts @@ -0,0 +1,72 @@ +/** Exact source adaptations shared with the existing native MSVC producer. */ +import assert from 'node:assert/strict'; + +const uuidEpoch = + '#define EPOCH_DIFF_USECS ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * USECS_PER_DAY)'; +const uuidClock = `${uuidEpoch}\n#ifdef _WIN32\n#ifndef CLOCK_REALTIME\n#define CLOCK_REALTIME 0\n#endif\nstatic int oliphaunt_pg_uuidv7_clock_gettime(int clock_id, struct timespec *ts) {\n TimestampTz unix_usecs;\n if (clock_id != CLOCK_REALTIME || ts == NULL) return -1;\n unix_usecs = GetCurrentTimestamp() + EPOCH_DIFF_USECS;\n ts->tv_sec = (time_t) (unix_usecs / USECS_PER_SEC);\n ts->tv_nsec = (long) ((unix_usecs % USECS_PER_SEC) * 1000);\n return 0;\n}\n#define clock_gettime oliphaunt_pg_uuidv7_clock_gettime\n#endif`; + +function replaceOne(text: string, before: string | RegExp, after: string, file: string) { + const count = + typeof before === 'string' + ? text.split(before).length - 1 + : [...text.matchAll(new RegExp(before.source, before.flags.replaceAll('g', '') + 'g'))] + .length; + assert.equal(count, 1, `expected one Windows source patch anchor in ${file}, found ${count}`); + return text.replace(before, after); +} + +/** Generated companions are declared separately from unchanged source inputs. */ +export function windowsExtensionHeaders(extension: string): Record { + if (extension !== 'pg_textsearch') return {}; + return { + 'src/unistd.h': '/* Provided by PostgreSQL on Windows. */\n', + }; +} + +/** Transform only the reviewed named files; retain every other source byte. */ +export function windowsExtensionSource(extension: string, file: string, text: string): string { + if (extension === 'postgis') { + if (/^(?:postgis|libpgcommon|liblwgeom)\/.*\.[ch]$/u.test(file)) { + if (file.endsWith('.c')) { + // These cross-unit definitions need an out-of-line body under MSVC. + text = text.replace( + /\/\*[\s\S]*?\*\/|\/\/(?:\\\r?\n|[^\r\n])*|"(?:\\[\s\S]|[^"\\])*"|'(?:\\[\s\S]|[^'\\])*'|^([ \t]*(?:extern[ \t]+)?)inline[ \t]+(?![ \t]*static\b)/gm, + (match, prefix: string | undefined) => (prefix === undefined ? match : prefix), + ); + } + text = text.replace( + /^[ \t]*(?!(?:extern\s+)?PGDLLEXPORT\s+)(?:extern\s+)?Datum\s+(\w+)\s*\(PG_FUNCTION_ARGS\);\r?$/gm, + 'extern PGDLLEXPORT Datum $1(PG_FUNCTION_ARGS);', + ); + } + if (file === 'postgis/postgis_legacy.c') { + text = replaceOne( + text, + /^([ \t]*)Datum[ \t]+funcname[ \t]*\(PG_FUNCTION_ARGS\);[ \t]*\\\r?$/gm, + '$1extern PGDLLEXPORT Datum funcname(PG_FUNCTION_ARGS); \\', + file, + ); + } + if (file === 'deps/flatgeobuf/geometryreader.cpp') { + for (const variables of [ + ['x', 'y', 'z', 'm'], + ['xv', 'yv', 'zv', 'mv'], + ]) { + text = replaceOne( + text, + `pt = (POINT4D) { ${variables.join(', ')} };`, + ['x', 'y', 'z', 'm'] + .map((field, index) => `pt.${field} = ${variables[index]};`) + .join('\n'), + file, + ); + } + } + return text; + } + if (extension === 'pg_uuidv7' && file === 'pg_uuidv7.c') { + assert(!text.includes('oliphaunt_pg_uuidv7_clock_gettime'), `${file} is already adapted`); + return replaceOne(text, uuidEpoch, uuidClock, file); + } + return text; +} diff --git a/build_defs/extensions/windows_source_portability.test.mts b/build_defs/extensions/windows_source_portability.test.mts new file mode 100644 index 000000000..42cb2483a --- /dev/null +++ b/build_defs/extensions/windows_source_portability.test.mts @@ -0,0 +1,136 @@ +import { test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { windowsExtensionHeaders, windowsExtensionSource } from './windows_source_portability.mts'; + +const epoch = + '#define EPOCH_DIFF_USECS ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * USECS_PER_DAY)'; + +test('textsearch 1.5.1 retains upstream MSVC layouts and exports without source patches', () => { + const sources = { + 'src/segment/segment.h': + '#ifdef _MSC_VER\n#pragma pack(push, 1)\n#endif\ntypedef struct TpSegmentPosting\n{ ItemPointerData ctid; } TP_PACKED TpSegmentPosting;\n#ifdef _MSC_VER\n#pragma pack(pop)\n#endif\n', + 'src/memtable/expull.h': + '#ifdef _MSC_VER\n#pragma pack(push, 1)\n#endif\ntypedef struct TpExpullEntry\n{ uint32 doc_id; uint16 frequency; uint8 fieldnorm; } TP_PACKED TpExpullEntry;\n#ifdef _MSC_VER\n#pragma pack(pop)\n#endif\n', + 'src/segment/format.h': + 'typedef struct TpDictEntryV3\n{ uint32 skip_index_offset; } pg_attribute_aligned(4) TpDictEntryV3;\n', + 'src/layout_check.c': 'StaticAssertDecl(sizeof(TpExpullEntry) == 7, "TpExpullEntry size");\n', + 'src/types/vector.h': 'PGDLLEXPORT Datum tpvector_in(PG_FUNCTION_ARGS);\n', + 'src/types/query.h': 'PGDLLEXPORT Datum tpquery_in(PG_FUNCTION_ARGS);\n', + }; + for (const [file, text] of Object.entries(sources)) { + const before = `/* upstream π 😀 */\r\n${text.replaceAll('\n', '\r\n')}`; + assert.equal(windowsExtensionSource('pg_textsearch', file, before), before); + } +}); + +test('the UUID clock adaptation retains the previous PostgreSQL epoch conversion and error handling bytes', () => { + const before = `/* π */\r\n${epoch}\r\nint unchanged;\r\n`; + const clock = [ + epoch, + '#ifdef _WIN32', + '#ifndef CLOCK_REALTIME', + '#define CLOCK_REALTIME 0', + '#endif', + 'static int oliphaunt_pg_uuidv7_clock_gettime(int clock_id, struct timespec *ts) {', + ' TimestampTz unix_usecs;', + ' if (clock_id != CLOCK_REALTIME || ts == NULL) return -1;', + ' unix_usecs = GetCurrentTimestamp() + EPOCH_DIFF_USECS;', + ' ts->tv_sec = (time_t) (unix_usecs / USECS_PER_SEC);', + ' ts->tv_nsec = (long) ((unix_usecs % USECS_PER_SEC) * 1000);', + ' return 0;', + '}', + '#define clock_gettime oliphaunt_pg_uuidv7_clock_gettime', + '#endif', + ].join('\n'); + assert.equal( + windowsExtensionSource('pg_uuidv7', 'pg_uuidv7.c', before), + `/* π */\r\n${clock}\r\nint unchanged;\r\n`, + ); + for (const invalid of [ + '', + `${epoch}\n${epoch}`, + windowsExtensionSource('pg_uuidv7', 'pg_uuidv7.c', before), + ]) + assert.throws( + () => windowsExtensionSource('pg_uuidv7', 'pg_uuidv7.c', invalid), + /anchor|already adapted/u, + ); +}); + +test('other named inputs retain Unicode, CRLF and source text without filename guessing', () => { + const text = `/* π 😀 */\r\n${epoch}\r\nDatum untouched(PG_FUNCTION_ARGS);\r\n`; + for (const [extension, file] of [ + ['pg_uuidv7', 'src/pg_uuidv7.c'], + ['pg_uuidv7', 'pg_uuidv7.h'], + ['pg_textsearch', 'src/segment/segment.c'], + ['pg_textsearch', 'src/types/query_extra.h'], + ['vector', 'pg_uuidv7.c'], + ]) + assert.equal(windowsExtensionSource(extension, file, text), text); +}); + +test('textsearch only declares the PostgreSQL unistd companion', () => { + assert.deepEqual(windowsExtensionHeaders('pg_textsearch'), { + 'src/unistd.h': '/* Provided by PostgreSQL on Windows. */\n', + }); + assert.deepEqual(windowsExtensionHeaders('pg_uuidv7'), {}); + assert.deepEqual(windowsExtensionHeaders('vector'), {}); + const modified = windowsExtensionHeaders('pg_textsearch'); + modified['src/unistd.h'] = 'changed'; + assert.notEqual(windowsExtensionHeaders('pg_textsearch')['src/unistd.h'], 'changed'); +}); + +test('PostGIS external C inline definitions retain bodies, static linkage and non-code bytes', () => { + const unchanged = [ + '/* inline int one(void) { return 1; } */', + '/* comment\ninline int two(void) { return 2; }\n*/', + '// comment \\\r\ninline int three(void) { return 3; }', + 'const char *text = "inline int four(void) { return 4; }";', + 'const char *continued = "line \\\r\ninline text";', + "int quote = '\\'';", + 'static inline int local(void) { return 5; }', + 'inline static int reverse(void) { return 6; }', + 'inline\t static int spaced(void) { return 7; }', + ].join('\r\n'); + const before = `${unchanged}\r\ninline bool external(const BOX2DF *a)\r\n{ return a->xmin != 0; }\r\nextern inline\tvoid other(BOX2DF *a) { a->xmin = 1; }\r\n`; + const after = `${unchanged}\r\nbool external(const BOX2DF *a)\r\n{ return a->xmin != 0; }\r\nextern void other(BOX2DF *a) { a->xmin = 1; }\r\n`; + for (const directory of ['postgis', 'libpgcommon', 'liblwgeom']) { + assert.equal(windowsExtensionSource('postgis', `${directory}/unit.c`, before), after); + assert.equal(windowsExtensionSource('postgis', `${directory}/unit.h`, before), before); + } + assert.equal(windowsExtensionSource('postgis', 'deps/unit.c', before), before); + assert.equal(windowsExtensionSource('vector', 'postgis/unit.c', before), before); +}); + +test('PostGIS preserves the existing DLL export and POINT4D source adaptations', () => { + const declaration = + '/* π */\r\n Datum one(PG_FUNCTION_ARGS);\r\nextern PGDLLEXPORT Datum done(PG_FUNCTION_ARGS);\r\nextern Datum unrelated(void);\r\n'; + for (const directory of ['postgis', 'libpgcommon', 'liblwgeom']) { + assert.equal( + windowsExtensionSource('postgis', `${directory}/unit.h`, declaration), + '/* π */\r\nextern PGDLLEXPORT Datum one(PG_FUNCTION_ARGS);\nextern PGDLLEXPORT Datum done(PG_FUNCTION_ARGS);\r\nextern Datum unrelated(void);\r\n', + ); + } + const legacy = '\tDatum funcname(PG_FUNCTION_ARGS); \\\r\n'; + assert.equal( + windowsExtensionSource('postgis', 'postgis/postgis_legacy.c', legacy), + '\textern PGDLLEXPORT Datum funcname(PG_FUNCTION_ARGS); \\\n', + ); + const geometry = 'pt = (POINT4D) { x, y, z, m };\npt = (POINT4D) { xv, yv, zv, mv };\n'; + assert.equal( + windowsExtensionSource('postgis', 'deps/flatgeobuf/geometryreader.cpp', geometry), + 'pt.x = x;\npt.y = y;\npt.z = z;\npt.m = m;\npt.x = xv;\npt.y = yv;\npt.z = zv;\npt.m = mv;\n', + ); + assert.equal(windowsExtensionSource('postgis', 'deps/unrelated.h', declaration), declaration); + for (const invalid of ['', geometry + geometry]) + assert.throws( + () => windowsExtensionSource('postgis', 'deps/flatgeobuf/geometryreader.cpp', invalid), + /anchor/u, + ); + for (const invalid of ['', legacy + legacy]) + assert.throws( + () => windowsExtensionSource('postgis', 'postgis/postgis_legacy.c', invalid), + /anchor/u, + ); + assert.deepEqual(windowsExtensionHeaders('postgis'), {}); +}); diff --git a/build_defs/foundation/BUILD.bazel b/build_defs/foundation/BUILD.bazel new file mode 100644 index 000000000..56dac4b61 --- /dev/null +++ b/build_defs/foundation/BUILD.bazel @@ -0,0 +1,74 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load(":bun.bzl", "bun_binary", "bun_source_output", "bun_test", "bun_toolchain_test") +load(":native-entry-test.bzl", "native_entry_test") + +package(default_visibility = ["//visibility:public"]) + +toolchain_type(name = "bun_toolchain_type") +bun_toolchain_test(name = "bun_toolchain_test", size = "small") + +bun_binary( + name = "native_entry_generator", + entry_point = "native-entry-generator.mts", + data = ["native-entry-helper.mts"], +) + +bun_source_output( + name = "native_entry_fixture", + source = "native-entry-fixture.txt", + tool = ":native_entry_generator", + out = "native-entry-fixture.json", +) + +native_entry_test( + name = "native_entry_test", + source = "native-entry-fixture.txt", + generated = ":native_entry_fixture", + args = ["forwarded"], + size = "small", +) + +bun_test( + name = "toolchain_metadata_test", + size = "small", + entry_point = "toolchain-metadata.test.mts", + data = ["toolchain-metadata.mts", "//tools/release:platform-compatibility-policy.mts", "//build_defs/host:deployment-policy.mts"], +) + +exports_files([ + "bun.bzl", + "bun-sources.bzl", + "bun-test-entrypoint.mts.tpl", + "bun-toolchain.bzl", + "bun-toolchain-test.mts", + "extensions.bzl", + "repositories.bzl", + "toolchain-metadata.mts", +]) + +platform( + name = "linux_x86_64", + constraint_values = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) + +platform( + name = "linux_aarch64", + constraint_values = ["@platforms//os:linux", "@platforms//cpu:aarch64"], +) + +platform( + name = "macos_x86_64", + constraint_values = ["@platforms//os:macos", "@platforms//cpu:x86_64"], +) + +platform( + name = "macos_aarch64", + constraint_values = ["@platforms//os:macos", "@platforms//cpu:aarch64"], +) + +platform( + name = "windows_x86_64", + constraint_values = ["@platforms//os:windows", "@platforms//cpu:x86_64"], +) + +source_quality_files() diff --git a/build_defs/foundation/README.md b/build_defs/foundation/README.md new file mode 100644 index 000000000..bf073b567 --- /dev/null +++ b/build_defs/foundation/README.md @@ -0,0 +1,42 @@ +Run native targets with `tools/dev/bazel.sh`. It reads `.bazelversion` and verifies +the downloaded executable against `tools/dev/bazel-checksums.tsv`, including cached +copies. Bazel bundles its Java runtime. No hosted execution or cache is configured. +Ordinary commands require the committed module lockfile. After an intentional +module/toolchain dependency change, refresh it with +`tools/dev/bazel.sh mod deps --lockfile_mode=update` and review the generated diff. + +The source pins remain in `.prototools`, `rust-toolchain.toml`, `Cargo.toml`, +`tools/dev/bun.toml`, and `bun.lock`. The tracked repository importer reads these +inputs before invoking pinned Bun. Generated metadata is a one-way projection; +it does not select new dependency versions or run an install. Rule releases and +their dependencies are pinned in `MODULE.bazel` and its lockfile. Authored +TypeScript build scripts use the existing pinned Bun runtime. +Upstream Bazel rules retain their own tooling; for example, `rules_pkg` uses +Python internally. The repository does not add Python scripts for this migration. +Language acquisition reads only Rust version, edition, and locked Node declaration +dependencies. Query package name, version, and module type have separate projections; +changing those package facts cannot change the language acquisition lock inputs. + +The Bun lock importer currently covers the query workspace's TypeScript compiler, +Node declarations, and their `undici-types` dependency. It checks the manifest, +catalog, supported lock schema, resolved versions, and integrity fields. Changes +requiring unsupported resolution behavior fail before the native build. + +The Rust query slice imports crate name, version, edition, minimum compiler, and +Cargo package environment from the conventional manifests. Its current contract +is the default library target with inherited workspace edition and compiler +minimum, without dependencies, features, target-specific configuration, or build +scripts and additional automatically discovered Cargo targets. Adding such inputs +fails until the native graph represents them. A Rust +package version is a compiler environment input and can require recompilation. + +The TypeScript CommonJS target validates the source package's effective `type`. +It does not depend on unrelated package metadata. The packaged consumer check +uses Node to exercise both ESM import and CommonJS require. + +The platform labels describe configurations; they do not grant release support. +Native C currently uses the local host compiler and declared local generator +tools. That lane must remain outside hermetic release qualification until its +compiler, sysroot, and generator toolchains have been qualified. Source crate +consumer tooling and the existing publication checks remain necessary for the +public Cargo package contract. diff --git a/build_defs/foundation/bazel-disk-cache-gc.bzl b/build_defs/foundation/bazel-disk-cache-gc.bzl new file mode 100644 index 000000000..2896daa6c --- /dev/null +++ b/build_defs/foundation/bazel-disk-cache-gc.bzl @@ -0,0 +1,49 @@ +"""Pinned stock Bazel disk cache collector, without a Bazel source build.""" + +def _bazel_disk_cache_gc_impl(ctx): + version = ctx.read(ctx.attr.version).strip() + os = ctx.os.name.lower() + os = "darwin" if os.startswith("mac") else "windows" if os.startswith("windows") else os + arch = {"amd64": "x86_64", "arm64": "arm64", "aarch64": "arm64"}.get(ctx.os.arch.lower(), ctx.os.arch.lower()) + asset = "bazel-%s-%s-%s%s" % (version, os, arch, ".exe" if os == "windows" else "") + hashes = [fields[2] for line in ctx.read(ctx.attr.checksums).splitlines() for fields in [line.split("\t")] if len(fields) == 3 and fields[:2] == [version, asset]] + if len(hashes) != 1: + fail("Expected one pinned Bazel checksum for " + asset) + + # Official binaries are ZIP self-extractors. Rename before stripping so the + # stock extractor reads only the server library, retaining its JNI resources. + ctx.download_and_extract( + url = "https://releases.bazel.build/%s/release/%s" % (version, asset), + sha256 = hashes[0], + type = "zip", + rename_files = {"A-server.jar": "gc/A-server.jar"}, + strip_prefix = "gc", + ) + ctx.download( + url = "https://raw.githubusercontent.com/bazelbuild/bazel/%s/src/tools/diskcache/Gc.java" % version, + sha256 = ctx.attr.source_sha256, + output = "Gc.java", + ) + ctx.file("BUILD.bazel", """load("@rules_java//java:defs.bzl", "java_binary", "java_import") +package(default_visibility = ["//visibility:public"]) +# Restore the upstream util:blocker, unsafe:string and skyframe/serialization +# module access metadata, which is not carried by a precompiled JAR. +java_import( + name = "server", + jars = ["A-server.jar"], + add_exports = ["java.base/jdk.internal.misc"], + add_opens = ["java.base/java.lang", "java.base/java.lang.invoke"], +) +java_binary(name = "gc", srcs = ["Gc.java"], deps = [":server"], main_class = "diskcache.Gc") +""") + return ctx.repo_metadata(reproducible = True) + +bazel_disk_cache_gc_repository = repository_rule( + implementation = _bazel_disk_cache_gc_impl, + attrs = { + "version": attr.label(default = Label("//:.bazelversion"), allow_single_file = True), + "checksums": attr.label(default = Label("//tools/dev:bazel-checksums.tsv"), allow_single_file = True), + # Unchanged upstream 8.8.1 source; review this pin when updating Bazel. + "source_sha256": attr.string(default = "f96bc004ae64e2ad8440eaf9ecb94eb9760b7085864fc195f578a712b2b6d547"), + }, +) diff --git a/build_defs/foundation/bun-sources.bzl b/build_defs/foundation/bun-sources.bzl new file mode 100644 index 000000000..6dae9bd46 --- /dev/null +++ b/build_defs/foundation/bun-sources.bzl @@ -0,0 +1,66 @@ +"""Regular, declared module files for Bun's executable import boundary.""" + +load("@bazel_lib//lib:copy_to_directory.bzl", "copy_to_directory_bin_action") +load(":bun-toolchain.bzl", "BUN_TOOLCHAIN_TYPE") + +_COPY_TOOLCHAIN = Label("@bazel_lib//lib:copy_to_directory_toolchain_type") +BUN_SOURCE_TOOLCHAINS = [Label(BUN_TOOLCHAIN_TYPE), _COPY_TOOLCHAIN] + +def _identity(ctx, file): + if file.short_path.startswith("../"): + parts = file.short_path[3:].split("/", 1) + return parts[0], parts[1] + return ctx.workspace_name, file.short_path + +def bun_source_tree(ctx, name, files): + """Copy individual declared files; keep artifact directories as explicit data. + + Bun 1.4.2 resolves symlinked modules to their real source directories even + with preserve-symlinks flags. Each repository therefore gets a regular-file + import tree. Directory artifacts are data inputs, never implicit code roots. + """ + groups = {} + destinations = {} + for file in files: + if file.is_directory: + continue + repository, relative = _identity(ctx, file) + key = repository + "/" + relative + if key in destinations: + if destinations[key] != file: + fail("Distinct Bun module inputs share an import path: " + key) + continue + destinations[key] = file + groups.setdefault(repository, []).append(file) + trees = {} + for repository, sources in groups.items(): + tree = ctx.actions.declare_directory(name + "/" + repository) + copy_to_directory_bin_action( + ctx, + name = name + "_" + repository, + dst = tree, + copy_to_directory_bin = ctx.toolchains[_COPY_TOOLCHAIN].copy_to_directory_info.bin, + files = sources, + root_paths = [], + include_external_repositories = [repository], + allow_overwrites = False, + hardlink = "off", + ) + trees[repository] = tree + return struct(trees = trees, files = depset(trees.values()), members = destinations) + +def bun_source_path(ctx, sources, file): + repository, relative = _identity(ctx, file) + if repository not in sources.trees: + fail("Bun entrypoint has no declared import tree: " + file.short_path) + return sources.trees[repository].path + "/" + relative + +def bun_source_directory(ctx, sources, file): + repository, _ = _identity(ctx, file) + return sources.trees[repository] + +def bun_source_runfile(ctx, sources, file): + repository, relative = _identity(ctx, file) + tree = sources.trees[repository] + root = tree.short_path[3:] if tree.short_path.startswith("../") else ctx.workspace_name + "/" + tree.short_path + return root + "/" + relative diff --git a/build_defs/foundation/bun-test-entrypoint.mts.tpl b/build_defs/foundation/bun-test-entrypoint.mts.tpl new file mode 100644 index 000000000..14da1bdb4 --- /dev/null +++ b/build_defs/foundation/bun-test-entrypoint.mts.tpl @@ -0,0 +1,32 @@ +import { isAbsolute, join, resolve } from "node:path"; + +const configuration = @@CONFIG@@; +const declaredRoot = process.env.RUNFILES_DIR ?? process.env.TEST_SRCDIR ?? join(import.meta.dir, configuration.runfilesSibling); +if (!declaredRoot || !isAbsolute(declaredRoot)) { + throw new Error("Bazel Bun entrypoints require an absolute directory runfiles root"); +} +const root = resolve(declaredRoot); +const args = configuration.arguments.map((argument) => + "file" in argument ? join(root, argument.file) : argument.literal, +); +if (configuration.runfilesArgument) args.push(root); +args.push(...process.argv.slice(2)); +const testArguments = configuration.testRunner ? ["test"] : []; +if (configuration.testRunner && !args.some((argument) => argument === "--timeout" || argument.startsWith("--timeout="))) { + testArguments.push("--timeout=30000"); +} +const environment = { ...process.env, ...configuration.environment }; +for (const name of configuration.runfilesEnvironment) environment[name] = root; +// Execute the authored runner as the main module: importing it would skip +// runners guarded by import.meta.main. No script interpreter or shell is used. +const result = Bun.spawnSync( + [process.execPath, "--no-install", "--no-env-file", ...testArguments, join(root, configuration.runner), ...args], + { + cwd: join(root, configuration.testRunner ? configuration.sourceRoot : configuration.workspace), + env: environment, + stdin: "inherit", + stdout: "inherit", + stderr: "inherit", + }, +); +process.exit(result.exitCode); diff --git a/build_defs/foundation/bun-toolchain-test.mts b/build_defs/foundation/bun-toolchain-test.mts new file mode 100644 index 000000000..349c560aa --- /dev/null +++ b/build_defs/foundation/bun-toolchain-test.mts @@ -0,0 +1,14 @@ +/** Exercise the selected executable, independently of its declared platform. */ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { readFileSync } from 'node:fs'; + +const expectedPlatform = process.env.OLIPHAUNT_BUN_RUNTIME_PLATFORM; +const expectedDigest = process.env.OLIPHAUNT_BUN_BINARY_SHA256; +const os = process.platform === 'win32' ? 'windows' : process.platform; +const arch = process.arch === 'arm64' ? 'aarch64' : process.arch; +assert.equal(`${os}-${arch}`, expectedPlatform); +assert.equal( + createHash('sha256').update(readFileSync(process.execPath)).digest('hex'), + expectedDigest, +); diff --git a/build_defs/foundation/bun-toolchain.bzl b/build_defs/foundation/bun-toolchain.bzl new file mode 100644 index 000000000..fc5bdf955 --- /dev/null +++ b/build_defs/foundation/bun-toolchain.bzl @@ -0,0 +1,19 @@ +"""Pinned Bun selected for the action execution platform.""" + +BUN_TOOLCHAIN_TYPE = "//build_defs/foundation:bun_toolchain_type" + +def _bun_runtime_toolchain_impl(ctx): + return [platform_common.ToolchainInfo( + bun = ctx.executable.binary, + runtime_platform = ctx.attr.runtime_platform, + binary_sha256 = ctx.attr.binary_sha256, + )] + +bun_runtime_toolchain = rule( + implementation = _bun_runtime_toolchain_impl, + attrs = { + "binary": attr.label(mandatory = True, executable = True, allow_single_file = True, cfg = "exec"), + "runtime_platform": attr.string(mandatory = True), + "binary_sha256": attr.string(mandatory = True), + }, +) diff --git a/build_defs/foundation/bun.bzl b/build_defs/foundation/bun.bzl new file mode 100644 index 000000000..53c50e1b0 --- /dev/null +++ b/build_defs/foundation/bun.bzl @@ -0,0 +1,151 @@ +"""Native Bun entrypoints and action execution with declared TypeScript inputs.""" + +load(":bun-toolchain.bzl", "BUN_TOOLCHAIN_TYPE") +load(":bun-sources.bzl", "bun_source_directory", "bun_source_path", "bun_source_runfile", "bun_source_tree", _BUN_SOURCE_TOOLCHAINS = "BUN_SOURCE_TOOLCHAINS") + +BUN_SOURCE_TOOLCHAINS = _BUN_SOURCE_TOOLCHAINS + +BunScriptInfo = provider(fields = ["bun", "entry_point", "entry_path", "files", "sources"]) + +BUN_TEST_ENTRYPOINT_ATTRS = { + "_bun_test_entrypoint_template": attr.label(default = "//build_defs/foundation:bun-test-entrypoint.mts.tpl", allow_single_file = True), +} + +def _runfile(ctx, file): + return file.short_path[3:] if file.short_path.startswith("../") else ctx.workspace_name + "/" + file.short_path + +def _bun_test_entrypoint(ctx, runner, arguments, files, environment = {}, runfiles_argument = False, runfiles_environment = [], source_files = None, test_runner = False, additional_runfiles = None): + """Launch computed test arguments through native Bun, including on Windows. + + File arguments are resolved through declared directory runfiles. Literal + strings remain literal; this API does not accept shell expressions. + """ + runtime = ctx.toolchains[BUN_TOOLCHAIN_TYPE] + sources = bun_source_tree(ctx, ctx.label.name + ".sources", [runner] + (files if source_files == None else source_files)) + executable = ctx.actions.declare_file(ctx.label.name + (".exe" if runtime.runtime_platform.startswith("windows-") else "")) + ctx.actions.symlink(output = executable, target_file = runtime.bun, is_executable = True) + entry = ctx.actions.declare_file(ctx.label.name + ".entry.mts") + if not hasattr(ctx.attr, "args") or not ctx.attr.args or ctx.attr.args[0] != entry.short_path: + fail("Bun entrypoint requires args[0] = %r; use bun_test_entrypoint_args(%r) in the declaration macro" % (entry.short_path, ctx.label.name)) + argument_files = [argument for argument in arguments if type(argument) == "File"] + ctx.actions.expand_template( + template = ctx.file._bun_test_entrypoint_template, + output = entry, + substitutions = {"@@CONFIG@@": json.encode({ + "workspace": ctx.workspace_name, + "runfilesSibling": executable.basename + ".runfiles", + "runner": bun_source_runfile(ctx, sources, runner), + "testRunner": test_runner, + "sourceRoot": _runfile(ctx, sources.trees.get(ctx.workspace_name, bun_source_directory(ctx, sources, runner))), + "arguments": [{"file": _runfile(ctx, argument)} if type(argument) == "File" else {"literal": argument} for argument in arguments], + "environment": environment, + "runfilesArgument": runfiles_argument, + "runfilesEnvironment": runfiles_environment, + })}, + ) + runfiles = ctx.runfiles(files = files + argument_files + [entry, runner, runtime.bun], transitive_files = sources.files) + if additional_runfiles != None: + runfiles = runfiles.merge(additional_runfiles) + return struct(info = DefaultInfo(executable = executable, runfiles = runfiles), executable = executable, sources = sources) + +def bun_test_entrypoint(ctx, runner, arguments, files, **kwargs): + return [_bun_test_entrypoint(ctx, runner, arguments, files, **kwargs).info] + +def bun_test_entrypoint_args(name): + label = native.package_relative_label(":" + name) + # Bazel launches native executables from the main repository's runfiles. + repository = "../" + label.repo_name + "/" if label.repo_name else "" + package = label.package + "/" if label.package else "" + return [repository + package + name + ".entry.mts"] + +def _bun_impl(ctx): + runtime = ctx.toolchains[BUN_TOOLCHAIN_TYPE] + result = _bun_test_entrypoint(ctx, ctx.file.entry_point, [], ctx.files.data, test_runner = ctx.attr.test_runner, + source_files = ctx.files.source_files if ctx.attr.source_files else None) + info = result.info + runfiles = info.default_runfiles + for dep in ctx.attr.data: + runfiles = runfiles.merge(dep[DefaultInfo].default_runfiles) + return [ + DefaultInfo(executable = result.executable, runfiles = runfiles), + BunScriptInfo(bun = runtime.bun, entry_point = ctx.file.entry_point, entry_path = bun_source_path(ctx, result.sources, ctx.file.entry_point), files = runfiles.files, sources = result.sources), + ] + +def bun_action(ctx, tool, arguments = [], inputs = [], **kwargs): + """Run a Bun tool as an action, without executing a script or shell launcher.""" + script = tool[BunScriptInfo] + prefix = ctx.actions.args() + prefix.add_all(["--no-install", "--no-env-file", script.entry_path]) + declared = inputs if type(inputs) == "depset" else depset(inputs) + ctx.actions.run( + executable = script.bun, + arguments = [prefix] + arguments, + inputs = depset(transitive = [declared, script.files]), + **kwargs + ) + +def bun_file_action(ctx, entry_point, arguments = [], inputs = [], source_files = None, sources = None, **kwargs): + """Run an individual Bun entrypoint from its declared regular module tree.""" + declared = inputs if type(inputs) == "depset" else depset(inputs) + if sources == None: + sources = bun_source_tree(ctx, ctx.label.name + ".sources", [entry_point] + (declared.to_list() if source_files == None else source_files)) + prefix = ctx.actions.args() + prefix.add_all(["--no-install", "--no-env-file", bun_source_path(ctx, sources, entry_point)]) + ctx.actions.run( + executable = ctx.toolchains[BUN_TOOLCHAIN_TYPE].bun, + arguments = [prefix] + arguments, + inputs = depset(transitive = [declared, sources.files]), + **kwargs + ) + +_ATTRS = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "entry_point": attr.label(allow_single_file = [".ts", ".mts"], mandatory = True), + "data": attr.label_list(allow_files = True), + # An empty list preserves the existing data-as-module-inputs default. + "source_files": attr.label_list(allow_files = True), + "test_runner": attr.bool(default = False), +}) + +_bun_binary = rule(implementation = _bun_impl, attrs = _ATTRS, toolchains = BUN_SOURCE_TOOLCHAINS, executable = True) +_bun_test = rule(implementation = _bun_impl, attrs = _ATTRS, toolchains = BUN_SOURCE_TOOLCHAINS, test = True) + +def bun_binary(name, entry_point, data = [], args = [], **kwargs): + _bun_binary(name = name, entry_point = entry_point, data = data + [entry_point], args = bun_test_entrypoint_args(name) + args, **kwargs) + +def bun_test(name, entry_point, data = [], args = [], **kwargs): + _bun_test(name = name, entry_point = entry_point, data = data + [entry_point], args = bun_test_entrypoint_args(name) + args, test_runner = True, **kwargs) + +def bun_script_test(name, entry_point, data = [], args = [], **kwargs): + _bun_test(name = name, entry_point = entry_point, data = data + [entry_point], args = bun_test_entrypoint_args(name) + args, **kwargs) + +def _bun_toolchain_test_impl(ctx): + runtime = ctx.toolchains[BUN_TOOLCHAIN_TYPE] + return _bun_impl(ctx) + [RunEnvironmentInfo(environment = { + "OLIPHAUNT_BUN_RUNTIME_PLATFORM": runtime.runtime_platform, + "OLIPHAUNT_BUN_BINARY_SHA256": runtime.binary_sha256, + })] + +_bun_toolchain_test = rule( + implementation = _bun_toolchain_test_impl, + attrs = _ATTRS, + toolchains = BUN_SOURCE_TOOLCHAINS, + test = True, +) + +def bun_toolchain_test(name, entry_point = Label(":bun-toolchain-test.mts"), data = [], args = [], **kwargs): + _bun_toolchain_test(name = name, entry_point = entry_point, data = data + [entry_point], args = bun_test_entrypoint_args(name) + args, **kwargs) + +def _source_output_impl(ctx): + arguments = ctx.actions.args() + arguments.add_all([ctx.file.source, ctx.outputs.out]) + bun_action(ctx, ctx.attr.tool, arguments = [arguments], inputs = [ctx.file.source], outputs = [ctx.outputs.out], mnemonic = "BunSourceOutput") + return [DefaultInfo(files = depset([ctx.outputs.out]))] + +bun_source_output = rule( + implementation = _source_output_impl, + attrs = { + "tool": attr.label(mandatory = True, providers = [BunScriptInfo], cfg = "exec"), + "source": attr.label(mandatory = True, allow_single_file = True), + "out": attr.output(mandatory = True), + }, +) diff --git a/build_defs/foundation/extensions.bzl b/build_defs/foundation/extensions.bzl new file mode 100644 index 000000000..b82ca9aed --- /dev/null +++ b/build_defs/foundation/extensions.bzl @@ -0,0 +1,72 @@ +"""Use existing manifest pins with the standard native language rules.""" + +# rules_rust's own extension uses this macro. Pinning the ruleset and testing this +# import keeps the absent version-from-manifest API at this one boundary. +load("@rules_rust//rust/private:repositories.bzl", "rust_register_toolchains", "rust_toolchain_tools_repository") +load("@rules_rust//rust/platform:triple.bzl", "get_host_triple") +load("@aspect_rules_js//npm:repositories.bzl", "npm_import") + +def _toolchain_metadata(ctx): + configurations = [] + for module in ctx.modules: + if module.tags.configure and not module.is_root: + fail("Only the root module may configure the repository's language tools") + configurations.extend(module.tags.configure) + if len(configurations) != 1: + fail("Exactly one root language toolchain metadata import is required") + return json.decode(ctx.read(configurations[0].metadata)) + +def _languages_impl(ctx): + data = _toolchain_metadata(ctx) + rust_register_toolchains( + hub_name = "rust_toolchains", + versions = [data["rust"]], + edition = data["edition"], + extra_target_triples = data["rust_targets"], + ) + for name, key in [("query_types_node", "types_node"), ("query_undici_types", "undici_types")]: + package = data[key] + npm_import( + name = name, + package = package["package"], + version = package["version"], + integrity = package["integrity"], + lifecycle_hooks = [], + ) + return ctx.extension_metadata( + root_module_direct_deps = ["rust_toolchains", "query_types_node", "query_undici_types"], + root_module_direct_dev_deps = [], + reproducible = True, + ) + +def _rust_host_tools_impl(ctx): + data = _toolchain_metadata(ctx) + host = get_host_triple(ctx) + rust_toolchain_tools_repository( + name = "rust_host_tools", + exec_triple = host.str, + target_triple = host.str, + version = data["rust"], + edition = data["edition"], + ) + return ctx.extension_metadata( + root_module_direct_deps = ["rust_host_tools"], + root_module_direct_dev_deps = [], + reproducible = True, + ) + +_CONFIGURE_TAG = tag_class(attrs = {"metadata": attr.label(mandatory = True)}) + +languages = module_extension( + implementation = _languages_impl, + tag_classes = {"configure": _CONFIGURE_TAG}, +) + +# Like rules_rust's own host-tools extension, acquisition follows the host. +# Language toolchain registration and npm imports above remain host-independent. +rust_host_tools = module_extension( + implementation = _rust_host_tools_impl, + tag_classes = {"configure": _CONFIGURE_TAG}, + os_dependent = True, + arch_dependent = True, +) diff --git a/build_defs/foundation/fixtures/bun_external/entry.test.mts b/build_defs/foundation/fixtures/bun_external/entry.test.mts new file mode 100644 index 000000000..09c135cf1 --- /dev/null +++ b/build_defs/foundation/fixtures/bun_external/entry.test.mts @@ -0,0 +1,12 @@ +import assert from 'node:assert/strict'; +import { lstatSync, realpathSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { test } from 'bun:test'; +import { marker } from './helper.mts'; + +test('external repository entrypoint loads declared regular modules', () => { + assert.equal(marker, 'external Bun entrypoint'); + const helper = new URL('./helper.mts', import.meta.url); + assert(lstatSync(helper).isFile()); + assert.equal(realpathSync(helper), fileURLToPath(helper)); +}); diff --git a/build_defs/foundation/fixtures/bun_external/fixture.BUILD.bazel b/build_defs/foundation/fixtures/bun_external/fixture.BUILD.bazel new file mode 100644 index 000000000..05e4afffe --- /dev/null +++ b/build_defs/foundation/fixtures/bun_external/fixture.BUILD.bazel @@ -0,0 +1,11 @@ +load("//:test-entries.bzl", "external_bun_entries") + +package(default_visibility = ["//visibility:public"]) + +exports_files([ + "entry.test.mts", + "helper.mts", + "script.mts", +]) + +external_bun_entries() diff --git a/build_defs/foundation/fixtures/bun_external/helper.mts b/build_defs/foundation/fixtures/bun_external/helper.mts new file mode 100644 index 000000000..dc891e8c8 --- /dev/null +++ b/build_defs/foundation/fixtures/bun_external/helper.mts @@ -0,0 +1 @@ +export const marker = 'external Bun entrypoint'; diff --git a/build_defs/foundation/fixtures/bun_external/nested.fixture.BUILD.bazel b/build_defs/foundation/fixtures/bun_external/nested.fixture.BUILD.bazel new file mode 100644 index 000000000..f9bfba4fc --- /dev/null +++ b/build_defs/foundation/fixtures/bun_external/nested.fixture.BUILD.bazel @@ -0,0 +1,6 @@ +load("//:test-entries.bzl", "external_bun_entries") + +package(default_visibility = ["//visibility:public"]) + +# Entrypoints and their imports belong to the repository root package. +external_bun_entries() diff --git a/build_defs/foundation/fixtures/bun_external/script.mts b/build_defs/foundation/fixtures/bun_external/script.mts new file mode 100644 index 000000000..03fa8bd0c --- /dev/null +++ b/build_defs/foundation/fixtures/bun_external/script.mts @@ -0,0 +1,6 @@ +import assert from 'node:assert/strict'; +import { marker } from './helper.mts'; + +assert.equal(marker, 'external Bun entrypoint'); +assert.equal(process.argv.at(-1), 'external literal'); +console.log(marker); diff --git a/build_defs/foundation/fixtures/bun_external/test-entries.bzl b/build_defs/foundation/fixtures/bun_external/test-entries.bzl new file mode 100644 index 000000000..3165990cf --- /dev/null +++ b/build_defs/foundation/fixtures/bun_external/test-entries.bzl @@ -0,0 +1,25 @@ +"""Actual native Bun entrypoints owned by an injected external repository.""" + +load("@oliphaunt//build_defs/foundation:bun.bzl", "bun_binary", "bun_script_test", "bun_test", "bun_toolchain_test") + +def external_bun_entries(): + bun_test( + name = "test", + entry_point = "//:entry.test.mts", + data = ["//:helper.mts"], + size = "small", + ) + bun_script_test( + name = "script_test", + entry_point = "//:script.mts", + data = ["//:helper.mts"], + args = ['"external literal"'], + size = "small", + ) + bun_binary( + name = "binary", + entry_point = "//:script.mts", + data = ["//:helper.mts"], + args = ['"external literal"'], + ) + bun_toolchain_test(name = "toolchain_test", size = "small") diff --git a/build_defs/foundation/fixtures/bun_imports/BUILD.bazel b/build_defs/foundation/fixtures/bun_imports/BUILD.bazel new file mode 100644 index 000000000..820971ef0 --- /dev/null +++ b/build_defs/foundation/fixtures/bun_imports/BUILD.bazel @@ -0,0 +1,37 @@ +load("//build_defs/foundation:bun.bzl", "bun_binary", "bun_test") +load(":external-test.bzl", "external_source_test", "invalid_entrypoint_test") + +package(default_visibility = ["//visibility:public"]) + +_MODULES = [ + "sibling.mts", + "nested/helper.mts", + "nested/deep/value.mts", +] + +bun_test( + name = "module_boundary_test", + entry_point = "module-boundary.test.mts", + data = _MODULES, + size = "small", +) + +bun_binary( + name = "module_launcher", + entry_point = "launcher.mts", + data = _MODULES, + args = ['"declared launcher"'], +) + +external_source_test( + name = "external_collision_test", + modules = ["@rules_cc//:MODULE.bazel", "@rules_rust//:MODULE.bazel"], + size = "small", +) + +invalid_entrypoint_test(name = "missing_entry_argument_test") + +invalid_entrypoint_test( + name = "wrong_entry_argument_test", + entrypoint_args = ["build_defs/foundation/fixtures/bun_imports/module_boundary_test.entry.mts"], +) diff --git a/build_defs/foundation/fixtures/bun_imports/external-source.test.mts b/build_defs/foundation/fixtures/bun_imports/external-source.test.mts new file mode 100644 index 000000000..ad2c9a129 --- /dev/null +++ b/build_defs/foundation/fixtures/bun_imports/external-source.test.mts @@ -0,0 +1,23 @@ +import assert from 'node:assert/strict'; +import { lstatSync, readFileSync, realpathSync } from 'node:fs'; +import path from 'node:path'; + +assert.equal(import.meta.main, true); +const [first, firstTree, firstName, second, secondTree, secondName] = process.argv.slice(2); +assert.equal(process.argv.length, 8); +assert.equal(firstName, 'MODULE.bazel'); +assert.equal(secondName, firstName); +assert.notEqual(firstTree, secondTree); +const copies = [path.join(firstTree, firstName), path.join(secondTree, secondName)]; +for (const [index, original] of [first, second].entries()) { + // Directory runfiles may project each regular output through a symlink. + // Its target must be a distinct copied file, rather than the authored source. + const actual = realpathSync(copies[index]); + assert(lstatSync(actual).isFile()); + assert.notEqual(actual, realpathSync(original)); + assert.deepEqual(readFileSync(copies[index]), readFileSync(original)); +} +assert.notDeepEqual(readFileSync(copies[0]), readFileSync(copies[1])); +console.log( + 'Declared Bun sources: distinct external MODULE.bazel files retain their repository identity.', +); diff --git a/build_defs/foundation/fixtures/bun_imports/external-test.bzl b/build_defs/foundation/fixtures/bun_imports/external-test.bzl new file mode 100644 index 000000000..a16afcb86 --- /dev/null +++ b/build_defs/foundation/fixtures/bun_imports/external-test.bzl @@ -0,0 +1,34 @@ +"""Exercise repository-relative collisions through the actual source copier.""" + +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/foundation:bun-sources.bzl", "bun_source_directory", "bun_source_tree") + +def _impl(ctx): + sources = bun_source_tree(ctx, ctx.label.name + ".repositories", ctx.files.modules) + arguments = [] + for module in ctx.files.modules: + arguments.extend([module, bun_source_directory(ctx, sources, module), module.basename]) + return bun_test_entrypoint( + ctx, + runner = ctx.file._runner, + arguments = arguments, + files = ctx.files.modules + sources.trees.values(), + source_files = [ctx.file._runner], + ) + +_external_source_test = rule( + implementation = _impl, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "modules": attr.label_list(mandatory = True, allow_files = True), + "_runner": attr.label(default = ":external-source.test.mts", allow_single_file = True), + }), + toolchains = BUN_SOURCE_TOOLCHAINS, + test = True, +) + +def external_source_test(name, args = [], **kwargs): + _external_source_test(name = name, args = bun_test_entrypoint_args(name) + args, **kwargs) + +def invalid_entrypoint_test(name, entrypoint_args = []): + """Analysis-negative fixtures must never invoke Bun or masquerade as tests.""" + _external_source_test(name = name, modules = [], args = entrypoint_args, tags = ["manual"]) diff --git a/build_defs/foundation/fixtures/bun_imports/launcher.mts b/build_defs/foundation/fixtures/bun_imports/launcher.mts new file mode 100644 index 000000000..57877ac1a --- /dev/null +++ b/build_defs/foundation/fixtures/bun_imports/launcher.mts @@ -0,0 +1,7 @@ +import assert from 'node:assert/strict'; +import { sibling } from './sibling.mts'; + +assert.equal(import.meta.main, true); +assert.equal(sibling, 'declared:nested:leaf'); +assert.deepEqual(process.argv.slice(2), ['declared launcher', 'forwarded argument']); +console.log('Declared Bun launcher: sibling/nested imports and forwarded arguments passed.'); diff --git a/build_defs/foundation/fixtures/bun_imports/module-boundary.test.mts b/build_defs/foundation/fixtures/bun_imports/module-boundary.test.mts new file mode 100644 index 000000000..de50e7e21 --- /dev/null +++ b/build_defs/foundation/fixtures/bun_imports/module-boundary.test.mts @@ -0,0 +1,21 @@ +import assert from 'node:assert/strict'; +import { existsSync, lstatSync, realpathSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { test } from 'bun:test'; +import { sibling } from './sibling.mts'; + +test('declared sibling and nested imports execute from regular copied modules', () => { + assert.equal(sibling, 'declared:nested:leaf'); + for (const relative of ['./sibling.mts', './nested/helper.mts', './nested/deep/value.mts']) { + const file = new URL(relative, import.meta.url); + assert(lstatSync(file).isFile()); + assert.equal(realpathSync(file), fileURLToPath(file)); + } +}); + +test('existing but undeclared siblings cannot escape the copied module boundary', async () => { + for (const relative of ['./undeclared.mts', './nested/undeclared.mts']) { + assert.equal(existsSync(new URL(relative, import.meta.url)), false); + await assert.rejects(import(relative), (error: any) => error?.code === 'ERR_MODULE_NOT_FOUND'); + } +}); diff --git a/build_defs/foundation/fixtures/bun_imports/nested/deep/value.mts b/build_defs/foundation/fixtures/bun_imports/nested/deep/value.mts new file mode 100644 index 000000000..51e85994f --- /dev/null +++ b/build_defs/foundation/fixtures/bun_imports/nested/deep/value.mts @@ -0,0 +1 @@ +export const leaf = 'leaf'; diff --git a/build_defs/foundation/fixtures/bun_imports/nested/helper.mts b/build_defs/foundation/fixtures/bun_imports/nested/helper.mts new file mode 100644 index 000000000..e9bde0c38 --- /dev/null +++ b/build_defs/foundation/fixtures/bun_imports/nested/helper.mts @@ -0,0 +1,3 @@ +import { leaf } from './deep/value.mts'; + +export const nested = `nested:${leaf}`; diff --git a/build_defs/foundation/fixtures/bun_imports/nested/undeclared.mts b/build_defs/foundation/fixtures/bun_imports/nested/undeclared.mts new file mode 100644 index 000000000..acddf3ebf --- /dev/null +++ b/build_defs/foundation/fixtures/bun_imports/nested/undeclared.mts @@ -0,0 +1 @@ +throw new Error('UNDECLARED_NESTED_SIBLING_WAS_EXECUTED'); diff --git a/build_defs/foundation/fixtures/bun_imports/sibling.mts b/build_defs/foundation/fixtures/bun_imports/sibling.mts new file mode 100644 index 000000000..d7a54d2d5 --- /dev/null +++ b/build_defs/foundation/fixtures/bun_imports/sibling.mts @@ -0,0 +1,3 @@ +import { nested } from './nested/helper.mts'; + +export const sibling = `declared:${nested}`; diff --git a/build_defs/foundation/fixtures/bun_imports/undeclared.mts b/build_defs/foundation/fixtures/bun_imports/undeclared.mts new file mode 100644 index 000000000..a1c0e0dfa --- /dev/null +++ b/build_defs/foundation/fixtures/bun_imports/undeclared.mts @@ -0,0 +1 @@ +throw new Error('UNDECLARED_SIBLING_WAS_EXECUTED'); diff --git a/build_defs/foundation/native-entry-fixture.txt b/build_defs/foundation/native-entry-fixture.txt new file mode 100644 index 000000000..a612ec798 --- /dev/null +++ b/build_defs/foundation/native-entry-fixture.txt @@ -0,0 +1 @@ +native action input diff --git a/build_defs/foundation/native-entry-generator.mts b/build_defs/foundation/native-entry-generator.mts new file mode 100644 index 000000000..8290ed25f --- /dev/null +++ b/build_defs/foundation/native-entry-generator.mts @@ -0,0 +1,8 @@ +import { readFileSync, writeFileSync } from 'node:fs'; +import { decorate } from './native-entry-helper.mts'; + +const [source, output] = process.argv.slice(2); +if (!source || !output || process.argv.length !== 4) { + throw new Error('native entry generator requires exactly source and output'); +} +writeFileSync(output, JSON.stringify({ value: decorate(readFileSync(source, 'utf8')) })); diff --git a/build_defs/foundation/native-entry-helper.mts b/build_defs/foundation/native-entry-helper.mts new file mode 100644 index 000000000..0895379ca --- /dev/null +++ b/build_defs/foundation/native-entry-helper.mts @@ -0,0 +1 @@ +export const decorate = (value: string): string => `declared:${value.trim()}`; diff --git a/build_defs/foundation/native-entry-test.bzl b/build_defs/foundation/native-entry-test.bzl new file mode 100644 index 000000000..3396add90 --- /dev/null +++ b/build_defs/foundation/native-entry-test.bzl @@ -0,0 +1,28 @@ +"""Regression for declared native Bun actions and computed test arguments.""" + +load(":bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") + +def _impl(ctx): + return bun_test_entrypoint( + ctx, + runner = ctx.file._runner, + arguments = [ctx.file.source, ctx.file.generated, "$literal `&\"' space\n"], + files = [ctx.file.source, ctx.file.generated, ctx.file._helper], + environment = {"OLIPHAUNT_NATIVE_ENTRY_FIXTURE": "literal value"}, + runfiles_environment = ["OLIPHAUNT_NATIVE_ENTRY_RUNFILES"], + ) + +_native_entry_test = rule( + implementation = _impl, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "source": attr.label(mandatory = True, allow_single_file = True), + "generated": attr.label(mandatory = True, allow_single_file = True), + "_runner": attr.label(default = "//build_defs/foundation:native-entry.test.mts", allow_single_file = True), + "_helper": attr.label(default = "//build_defs/foundation:native-entry-helper.mts", allow_single_file = True), + }), + toolchains = BUN_SOURCE_TOOLCHAINS, + test = True, +) + +def native_entry_test(name, args = [], **kwargs): + _native_entry_test(name = name, args = bun_test_entrypoint_args(name) + args, **kwargs) diff --git a/build_defs/foundation/native-entry.test.mts b/build_defs/foundation/native-entry.test.mts new file mode 100644 index 000000000..ffe00db71 --- /dev/null +++ b/build_defs/foundation/native-entry.test.mts @@ -0,0 +1,16 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { isAbsolute } from 'node:path'; +import { decorate } from './native-entry-helper.mts'; + +assert.equal(import.meta.main, true, 'authored runner must execute as main'); +const [source, generated, literal, forwarded] = process.argv.slice(2); +assert.equal(process.argv.length, 6); +assert.equal(forwarded, 'forwarded'); +assert.ok(source && generated && isAbsolute(source) && isAbsolute(generated)); +assert.equal(literal, '$literal `&"\' space\n'); +assert.deepEqual(JSON.parse(readFileSync(generated, 'utf8')), { + value: decorate(readFileSync(source, 'utf8')), +}); +assert.equal(process.env.OLIPHAUNT_NATIVE_ENTRY_FIXTURE, 'literal value'); +assert.ok(isAbsolute(process.env.OLIPHAUNT_NATIVE_ENTRY_RUNFILES ?? '')); diff --git a/build_defs/foundation/repositories.bzl b/build_defs/foundation/repositories.bzl new file mode 100644 index 000000000..3a8de58ef --- /dev/null +++ b/build_defs/foundation/repositories.bzl @@ -0,0 +1,204 @@ +"""Tracked projections of the existing pinned language tools and lockfile.""" + +def _quoted_assignments(text): + """Read the quoted scalar assignments used by the runtime acquisition manifests.""" + result = {} + section = "" + for raw in text.splitlines(): + line = raw.strip() + if not line or line.startswith("#"): + continue + if line.startswith("[") and line.endswith("]"): + section = line[1:-1] + result[section] = {} + elif "=" in line: + key, value = line.split("=", 1) + value = value.strip() + if not section or not value.startswith('"') or not value.endswith('"'): + fail("Expected a section and quoted scalar in a runtime acquisition manifest: " + line) + result[section][key.strip()] = value[1:-1] + else: + fail("Unsupported runtime acquisition manifest entry: " + line) + return result + +def _host_bun_platform(ctx): + os = ctx.os.name.lower() + if os.startswith("mac"): + os = "darwin" + elif os.startswith("windows"): + os = "windows" + elif os != "linux": + fail("No declared Bun asset for host OS " + ctx.os.name) + arch = ctx.os.arch.lower() + arch = {"amd64": "x64", "x86_64": "x64", "arm64": "aarch64"}.get(arch, arch) + return os + "-" + arch + +def _download_bun(ctx, platform, output): + asset = _quoted_assignments(ctx.read(ctx.attr.manifest)).get("assets." + platform) + if not asset: + fail("No declared Bun asset for " + platform) + for field in ["url", "sha256", "binary_path", "binary_sha256"]: + if not asset.get(field): + fail("Bun asset %s is missing %s" % (platform, field)) + ctx.download_and_extract(url = asset["url"], sha256 = asset["sha256"]) + ctx.symlink(asset["binary_path"], output) + ctx.file("BUILD.bazel", 'exports_files([%s], visibility = ["//visibility:public"])\n' % repr(output)) + return ctx.repo_metadata(reproducible = True) + +def _bun_runtime_impl(ctx): + return _download_bun(ctx, _host_bun_platform(ctx), "bun") + +bun_runtime_repository = repository_rule( + implementation = _bun_runtime_impl, + attrs = {"manifest": attr.label(default = Label("//tools/dev:bun.toml"), allow_single_file = True)}, +) + +def _deno_linux_x64_impl(ctx): + asset = _quoted_assignments(ctx.read(ctx.attr.manifest)).get("assets.x86_64-unknown-linux-gnu") + if not asset: + fail("No declared Deno asset for x86_64-unknown-linux-gnu") + for field in ["url", "mirror_url", "sha256", "binary_path"]: + if not asset.get(field): + fail("Deno Linux x64 asset is missing " + field) + ctx.download_and_extract(url = [asset["url"], asset["mirror_url"]], sha256 = asset["sha256"]) + ctx.file("BUILD.bazel", 'exports_files([%s], visibility = ["//visibility:public"])\n' % repr(asset["binary_path"])) + return ctx.repo_metadata(reproducible = True) + +deno_linux_x64_repository = repository_rule( + implementation = _deno_linux_x64_impl, + attrs = {"manifest": attr.label(default = Label("//tools/dev:deno.toml"), allow_single_file = True)}, +) + +_BUN_PLATFORMS = { + "darwin-aarch64": ["@platforms//os:macos", "@platforms//cpu:aarch64"], + "darwin-x64": ["@platforms//os:macos", "@platforms//cpu:x86_64"], + "linux-aarch64": ["@platforms//os:linux", "@platforms//cpu:aarch64"], + "linux-x64": ["@platforms//os:linux", "@platforms//cpu:x86_64"], + "windows-x64": ["@platforms//os:windows", "@platforms//cpu:x86_64"], +} + +def _bun_asset_impl(ctx): + platform = ctx.attr.runtime_platform + return _download_bun(ctx, platform, "bun.exe" if platform.startswith("windows-") else "bun") + +_bun_asset_repository = repository_rule( + implementation = _bun_asset_impl, + attrs = { + "manifest": attr.label(allow_single_file = True, mandatory = True), + "runtime_platform": attr.string(mandatory = True, values = _BUN_PLATFORMS.keys()), + }, +) + +def _bun_toolchains_repository_impl(ctx): + lines = [ + 'load(%s, "bun_runtime_toolchain")' % repr(str(ctx.attr.definition)), + 'package(default_visibility = ["//visibility:public"])', + ] + for platform in sorted(ctx.attr.binary_sha256s): + name = platform.replace("-", "_") + binary = "bun.exe" if platform.startswith("windows-") else "bun" + lines.extend([ + "bun_runtime_toolchain(name = %s, binary = %s, runtime_platform = %s, binary_sha256 = %s)" % ( + repr(name + "_runtime"), + repr("@bun_" + name + "//:" + binary), + repr(platform), + repr(ctx.attr.binary_sha256s[platform]), + ), + "toolchain(name = %s, toolchain = %s, toolchain_type = %s, exec_compatible_with = %s)" % ( + repr(name), + repr(":" + name + "_runtime"), + repr(str(ctx.attr.toolchain_type)), + repr(_BUN_PLATFORMS[platform]), + ), + ]) + ctx.file("BUILD.bazel", "\n".join(lines) + "\n") + return ctx.repo_metadata(reproducible = True) + +_bun_toolchains_repository = repository_rule( + implementation = _bun_toolchains_repository_impl, + attrs = { + "binary_sha256s": attr.string_dict(mandatory = True), + "definition": attr.label(default = Label("//build_defs/foundation:bun-toolchain.bzl")), + "toolchain_type": attr.label(default = Label("//build_defs/foundation:bun_toolchain_type")), + }, +) + +def _bun_toolchains_impl(ctx): + manifest = Label("//tools/dev:bun.toml") + assets = _quoted_assignments(ctx.read(manifest)) + hashes = {} + for section, asset in assets.items(): + if not section.startswith("assets."): + fail("Unknown Bun manifest section: " + section) + platform = section[len("assets."):] + if platform not in _BUN_PLATFORMS: + fail("No declared Bazel execution constraints for Bun asset " + platform) + digest = asset.get("binary_sha256", "") + if len(digest) != 64 or any([character not in "0123456789abcdef" for character in digest.elems()]): + fail("Bun asset %s has an invalid binary SHA-256" % platform) + hashes[platform] = digest + _bun_asset_repository(name = "bun_" + platform.replace("-", "_"), manifest = manifest, runtime_platform = platform) + if not hashes: + fail("Bun manifest declares no execution assets") + _bun_toolchains_repository(name = "bun_toolchains", binary_sha256s = hashes) + return ctx.extension_metadata(root_module_direct_deps = ["bun_toolchains"], root_module_direct_dev_deps = [], reproducible = True) + +bun_toolchains = module_extension(implementation = _bun_toolchains_impl) + +def _toolchain_metadata_impl(ctx): + ctx.watch(ctx.path(ctx.attr.bun)) + # An external process opening a path does not register a repository read. + # Watch every source and the converter before invoking the pinned runtime. + for source in [ctx.attr.converter, ctx.attr.compatibility, ctx.attr.deployment_policy, ctx.attr.versions, ctx.attr.rust, ctx.attr.package, ctx.attr.query, ctx.attr.lockfile, ctx.attr.cargo, ctx.attr.query_rust]: + ctx.read(source) + # Cargo discovers scripts and additional targets even without manifest keys. + query_root = ctx.path(ctx.attr.query_rust).dirname + for relative in ["build.rs", "src/main.rs", "src/bin", "tests", "examples", "benches"]: + additional_target = query_root.get_child(relative) + ctx.watch(additional_target) + if additional_target.exists: + fail("Native query Rust does not yet support an automatically discovered " + relative) + result = ctx.execute([ + ctx.path(ctx.attr.bun), + ctx.path(ctx.attr.converter), + ctx.path(ctx.attr.versions), + ctx.path(ctx.attr.rust), + ctx.path(ctx.attr.package), + ctx.path(ctx.attr.query), + ctx.path(ctx.attr.lockfile), + ctx.path(ctx.attr.cargo), + ctx.path(ctx.attr.query_rust), + ], quiet = True) + if result.return_code: + fail("Cannot import pinned language tools: " + result.stderr) + data = json.decode(result.stdout) + ctx.file("apple-platforms.bzl", "APPLE_DEPLOYMENT_TARGETS = " + repr(data["apple_deployment_targets"]) + "\n") + ctx.file("toolchains.json", json.encode(data["language_acquisition"])) + ctx.file("node-version", data["node"] + "\n") + ctx.file("typescript.json", json.encode({ + "$schema": "https://docs.aspect.build/rules/aspect_rules_js/docs/npm_translate_lock", + "version": data["typescript"]["version"], + "integrity": data["typescript"]["integrity"], + })) + ctx.file("query-package-type.bzl", "QUERY_PACKAGE_TYPE = " + repr(data["query_package_type"]) + "\nQUERY_NPM_NAME = " + repr(data["query_npm_name"]) + "\n") + rust = data["query_rust"] + ctx.file("query-rust.bzl", "QUERY_RUST_CRATE_NAME = " + repr(rust["crate_name"]) + "\nQUERY_RUST_EDITION = " + repr(rust["edition"]) + "\nQUERY_RUST_VERSION = " + repr(rust["version"]) + "\nQUERY_RUST_ENV = " + repr(rust["env"]) + "\n") + ctx.file("BUILD.bazel", 'exports_files(["toolchains.json", "node-version", "typescript.json", "query-package-type.bzl", "query-rust.bzl", "apple-platforms.bzl"], visibility = ["//visibility:public"])\n') + return ctx.repo_metadata(reproducible = True) + +toolchain_metadata_repository = repository_rule( + implementation = _toolchain_metadata_impl, + attrs = { + "bun": attr.label(default = Label("@bun_runtime//:bun"), allow_single_file = True), + "converter": attr.label(default = Label("//build_defs/foundation:toolchain-metadata.mts"), allow_single_file = True), + "deployment_policy": attr.label(default = Label("//build_defs/host:deployment-policy.mts"), allow_single_file = True), + "versions": attr.label(default = Label("//:.prototools"), allow_single_file = True), + "rust": attr.label(default = Label("//:rust-toolchain.toml"), allow_single_file = True), + "package": attr.label(default = Label("//:package.json"), allow_single_file = True), + "query": attr.label(default = Label("//src/query/ts:package.json"), allow_single_file = True), + "lockfile": attr.label(default = Label("//:bun.lock"), allow_single_file = True), + "cargo": attr.label(default = Label("//:Cargo.toml"), allow_single_file = True), + "query_rust": attr.label(default = Label("//src/query/rust:Cargo.toml"), allow_single_file = True), + "compatibility": attr.label(default = Label("//tools/release:platform-compatibility-policy.mts"), allow_single_file = True), + }, +) diff --git a/build_defs/foundation/toolchain-metadata.mts b/build_defs/foundation/toolchain-metadata.mts new file mode 100644 index 000000000..c3ea1f1d6 --- /dev/null +++ b/build_defs/foundation/toolchain-metadata.mts @@ -0,0 +1,211 @@ +import { readFileSync } from 'node:fs'; +import { platformCompatibilityContract } from '../../tools/release/platform-compatibility-policy.mts'; +import { appleDeploymentTargets } from '../host/deployment-policy.mts'; + +export function mobileRustTargets(): string[] { + const apple = platformCompatibilityContract('ios-xcframework'); + if ( + apple.architecture !== 'arm64' || + apple.apple.requiredPlatforms.join(',') !== 'macos,ios,iosSimulator' + ) + throw new Error('Unsupported Apple slice contract for Rust target acquisition'); + return [ + 'aarch64-apple-ios', + 'aarch64-apple-ios-sim', + ...(['android-arm64-v8a', 'android-x86_64'] as const).map((target) => { + const contract = platformCompatibilityContract(target); + if (contract.format !== 'elf') throw new Error(`Unsupported ${target} format`); + if (contract.architecture === 'arm64') return 'aarch64-linux-android'; + if (contract.architecture === 'x64') return 'x86_64-linux-android'; + throw new Error(`Unsupported ${target} architecture`); + }), + ]; +} + +type LockRecord = [string, string, { dependencies?: Record }, string]; + +export function importToolchainMetadata( + versions: Record, + rust: { toolchain: { channel: string } }, + root: { workspaces: { catalog?: Record }; overrides?: Record }, + query: { name: string; type?: string; devDependencies: Record }, + lock: { + lockfileVersion: number; + configVersion: number; + catalog?: Record; + workspaces: Record }>; + packages: Record; + }, + cargo: { + workspace: { package: { edition: string; 'rust-version': string; [key: string]: unknown } }; + }, + queryRust: { + package: { + name: string; + version: string; + edition: { workspace: boolean }; + 'rust-version': { workspace: boolean }; + build?: false; + [key: string]: unknown; + }; + [section: string]: unknown; + }, +) { + if ( + queryRust.package.edition?.workspace !== true || + queryRust.package['rust-version']?.workspace !== true + ) + throw new Error('Native query Rust currently requires workspace edition and rust-version'); + for (const section of [ + 'dependencies', + 'dev-dependencies', + 'build-dependencies', + 'target', + 'features', + 'lib', + 'bin', + 'test', + 'example', + 'bench', + 'workspace', + ]) + if (queryRust[section] && Object.keys(queryRust[section] as object).length) + throw new Error(`Native query Rust does not yet support Cargo [${section}]`); + if (queryRust.package.build !== undefined && queryRust.package.build !== false) + throw new Error('Native query Rust does not yet support a Cargo build script'); + if (queryRust.package.links !== undefined) + throw new Error('Native query Rust does not yet support Cargo package.links'); + if (queryRust.package.autolib === false) + throw new Error('Native query Rust requires the default Cargo library target'); + if (lock.lockfileVersion !== 2 || lock.configVersion !== 1) + throw new Error('Unsupported Bun lockfile schema; update the bounded import before using it'); + if (lock.workspaces['src/query/ts']?.name !== query.name) + throw new Error('bun.lock query workspace does not match its package.json'); + + function record(packageName: string, parent: string, requirement: string) { + if (root.overrides?.[packageName]) + throw new Error(`Query lock import does not support an override for ${packageName}`); + const key = + `${parent}/${packageName}` in lock.packages ? `${parent}/${packageName}` : packageName; + const row = lock.packages[key]; + if (!row?.[0].startsWith(`${packageName}@`) || !row[3]?.startsWith('sha512-')) + throw new Error(`Missing integrity-bearing lock record for ${key}`); + const version = row[0].slice(packageName.length + 1); + if (!Bun.semver.satisfies(version, requirement)) + throw new Error(`Locked ${key}@${version} does not satisfy ${requirement}`); + return { key, row, package: packageName, version, integrity: row[3] }; + } + + function direct(packageName: string) { + let requirement = query.devDependencies[packageName]; + if (lock.workspaces['src/query/ts'].devDependencies?.[packageName] !== requirement) + throw new Error(`bun.lock has a stale query declaration for ${packageName}`); + if (requirement === 'catalog:') { + requirement = root.workspaces.catalog?.[packageName] ?? ''; + if (lock.catalog?.[packageName] !== requirement) + throw new Error(`bun.lock has a stale catalog declaration for ${packageName}`); + } + if (!requirement) throw new Error(`Missing query requirement for ${packageName}`); + return record(packageName, query.name, requirement); + } + + const typescript = direct('typescript'); + const typesNode = direct('@types/node'); + const undiciRequirement = typesNode.row[2].dependencies?.['undici-types']; + if (!undiciRequirement) throw new Error('Locked @types/node has no undici-types dependency'); + const undiciTypes = record('undici-types', typesNode.key, undiciRequirement); + const projection = ({ package: name, version, integrity }: ReturnType) => ({ + package: name, + version, + integrity, + }); + if (!/^\d+\.\d+\.\d+$/.test(rust.toolchain.channel) || !/^\d+\.\d+\.\d+$/.test(versions.node)) + throw new Error('Rust and Node toolchains require exact versions'); + if (!Bun.semver.satisfies(rust.toolchain.channel, `>=${cargo.workspace.package['rust-version']}`)) + throw new Error('Pinned Rust toolchain is below the Cargo workspace rust-version'); + const version = queryRust.package.version; + const semver = /^(\d+)\.(\d+)\.(\d+)(?:-([\dA-Za-z.-]+))?(?:\+[\dA-Za-z.-]+)?$/.exec(version); + if (!semver) throw new Error('Query Cargo package requires an explicit semantic version'); + function inherited(name: string) { + const value = queryRust.package[name]; + return value && typeof value === 'object' && 'workspace' in value && value.workspace === true + ? cargo.workspace.package[name] + : value; + } + function scalar(name: string) { + const value = inherited(name); + if (value === undefined) return ''; + if (typeof value !== 'string') throw new Error(`Unsupported query Cargo package.${name}`); + return value; + } + const authors = inherited('authors') ?? []; + if (!Array.isArray(authors) || !authors.every((author) => typeof author === 'string')) + throw new Error('Query Cargo authors must be strings'); + const cargoEnv = { + CARGO_PKG_NAME: queryRust.package.name, + CARGO_PKG_VERSION: version, + CARGO_PKG_VERSION_MAJOR: semver[1], + CARGO_PKG_VERSION_MINOR: semver[2], + CARGO_PKG_VERSION_PATCH: semver[3], + CARGO_PKG_VERSION_PRE: semver[4] ?? '', + CARGO_PKG_AUTHORS: authors.join(':'), + CARGO_PKG_DESCRIPTION: scalar('description'), + CARGO_PKG_HOMEPAGE: scalar('homepage'), + CARGO_PKG_REPOSITORY: scalar('repository'), + CARGO_PKG_LICENSE: scalar('license'), + CARGO_PKG_LICENSE_FILE: scalar('license-file'), + CARGO_PKG_README: scalar('readme'), + CARGO_PKG_RUST_VERSION: cargo.workspace.package['rust-version'], + }; + return { + apple_deployment_targets: appleDeploymentTargets(), + node: versions.node, + bun: versions.bun, + typescript: projection(typescript), + // Only this projection is read by the language acquisition extension. + language_acquisition: { + rust: rust.toolchain.channel, + rust_targets: mobileRustTargets(), + edition: cargo.workspace.package.edition, + types_node: projection(typesNode), + undici_types: projection(undiciTypes), + }, + query_npm_name: query.name, + query_package_type: query.type ?? 'commonjs', + query_rust: { + crate_name: queryRust.package.name.replaceAll('-', '_'), + edition: cargo.workspace.package.edition, + minimum: cargo.workspace.package['rust-version'], + version, + env: cargoEnv, + }, + }; +} + +if (import.meta.main) { + const [versions, rust, root, query, lockfile, cargo, queryRust] = process.argv.slice(2); + if (!versions || !rust || !root || !query || !lockfile || !cargo || !queryRust) + throw new Error( + 'Expected toolchain and workspace manifests, lockfile, and query Rust manifest', + ); + const pins = Bun.TOML.parse(readFileSync(versions, 'utf8')); + if (process.versions.bun !== pins.bun) + throw new Error('Bun acquisition manifest does not match .prototools'); + console.log( + JSON.stringify( + importToolchainMetadata( + pins, + Bun.TOML.parse(readFileSync(rust, 'utf8')) as Parameters[1], + JSON.parse(readFileSync(root, 'utf8')), + JSON.parse(readFileSync(query, 'utf8')), + Bun.JSONC.parse(readFileSync(lockfile, 'utf8')), + Bun.TOML.parse(readFileSync(cargo, 'utf8')) as Parameters< + typeof importToolchainMetadata + >[5], + Bun.TOML.parse(readFileSync(queryRust, 'utf8')) as Parameters< + typeof importToolchainMetadata + >[6], + ), + ), + ); +} diff --git a/build_defs/foundation/toolchain-metadata.test.mts b/build_defs/foundation/toolchain-metadata.test.mts new file mode 100644 index 000000000..f746b4dae --- /dev/null +++ b/build_defs/foundation/toolchain-metadata.test.mts @@ -0,0 +1,184 @@ +import { expect, test } from 'bun:test'; +import { importToolchainMetadata, mobileRustTargets } from './toolchain-metadata.mts'; + +test('mobile Rust std acquisition follows the public slice and architecture contracts', () => { + expect(mobileRustTargets()).toEqual([ + 'aarch64-apple-ios', + 'aarch64-apple-ios-sim', + 'aarch64-linux-android', + 'x86_64-linux-android', + ]); +}); + +function fixture() { + const versions = { node: '22.22.3', bun: '1.4.2' }; + const rust = { toolchain: { channel: '1.93.1' } }; + const root = { workspaces: { catalog: { typescript: '^6.0.3' } } }; + const query: Parameters[3] = { + name: '@oliphaunt/ts-query', + devDependencies: { typescript: 'catalog:', '@types/node': '^24.10.1' }, + }; + const lock = { + lockfileVersion: 2, + configVersion: 1, + catalog: structuredClone(root.workspaces.catalog), + workspaces: { 'src/query/ts': structuredClone(query) }, + packages: { + '@oliphaunt/ts-query/typescript': ['typescript@6.0.3', '', {}, 'sha512-typescript'], + '@oliphaunt/ts-query/@types/node': [ + '@types/node@24.12.4', + '', + { dependencies: { 'undici-types': '7.16.0' } }, + 'sha512-node', + ], + '@oliphaunt/ts-query/@types/node/undici-types': [ + 'undici-types@7.16.0', + '', + {}, + 'sha512-undici', + ], + typescript: ['typescript@5.9.3', '', {}, 'sha512-older-root-copy'], + }, + } as Parameters[4]; + const cargo = { workspace: { package: { edition: '2024', 'rust-version': '1.93' } } }; + const queryRust = { + package: { + name: 'oliphaunt-query', + version: '0.1.1', + edition: { workspace: true }, + 'rust-version': { workspace: true }, + }, + } as Parameters[6]; + return [versions, rust, root, query, lock, cargo, queryRust] as const; +} + +test('imports the scoped locked dependency, rather than a different root copy', () => { + const args = fixture(); + expect(importToolchainMetadata(...args).typescript.version).toBe('6.0.3'); + expect(importToolchainMetadata(...args).language_acquisition.undici_types.version).toBe('7.16.0'); +}); + +test('Apple construction floors project the public compatibility policy without SDK discovery', () => { + expect(importToolchainMetadata(...fixture()).apple_deployment_targets).toEqual({ + native_macos: '11.0.0', + package_macos: '14.0.0', + ios: '17.0.0', + ios_simulator: '17.0.0', + }); +}); + +test.each([ + 'Cargo version', + 'npm type', + 'npm name', +] as const)('%s metadata cannot change language acquisition', (change) => { + const args = fixture(); + const before = importToolchainMetadata(...args); + expect(Object.keys(before.language_acquisition).sort()).toEqual([ + 'edition', + 'rust', + 'rust_targets', + 'types_node', + 'undici_types', + ]); + if (change === 'Cargo version') { + args[6].package.version = '0.2.0'; + } else if (change === 'npm type') { + args[3].type = 'module'; + } else { + const oldName = args[3].name; + args[3].name = '@oliphaunt/renamed-query'; + args[4].workspaces['src/query/ts'].name = args[3].name; + for (const key of Object.keys(args[4].packages)) { + if (!key.startsWith(`${oldName}/`)) continue; + args[4].packages[`${args[3].name}${key.slice(oldName.length)}`] = args[4].packages[key]; + delete args[4].packages[key]; + } + } + const after = importToolchainMetadata(...args); + expect(after.language_acquisition).toEqual(before.language_acquisition); + if (change === 'Cargo version') { + expect(after.query_rust.version).toBe('0.2.0'); + expect(after.query_rust.env.CARGO_PKG_VERSION).toBe('0.2.0'); + } else if (change === 'npm type') { + expect(after.query_package_type).toBe('module'); + } else { + expect(after.query_npm_name).toBe('@oliphaunt/renamed-query'); + } +}); + +test('rejects a stale lock declaration before using resolved versions', () => { + const args = fixture(); + args[4].workspaces['src/query/ts'].devDependencies = { typescript: '^5.0.0' }; + expect(() => importToolchainMetadata(...args)).toThrow('stale query declaration'); +}); + +test('rejects stale catalog declarations and unsupported lock schemas', () => { + const args = fixture(); + args[4].catalog = { typescript: '^6.0.2' }; + expect(() => importToolchainMetadata(...args)).toThrow('stale catalog declaration'); + args[4].catalog = { typescript: '^6.0.3' }; + args[4].lockfileVersion = 3; + expect(() => importToolchainMetadata(...args)).toThrow('Unsupported Bun lockfile schema'); +}); + +test('rejects missing or incompatible scoped dependencies', () => { + const args = fixture(); + delete args[4].packages['@oliphaunt/ts-query/typescript']; + expect(() => importToolchainMetadata(...args)).toThrow('does not satisfy'); +}); + +test('rejects an incompatible transitive package or absent integrity', () => { + const args = fixture(); + args[4].packages['@oliphaunt/ts-query/@types/node/undici-types'][0] = 'undici-types@6.21.0'; + expect(() => importToolchainMetadata(...args)).toThrow('does not satisfy'); + args[4].packages['@oliphaunt/ts-query/@types/node/undici-types'][0] = 'undici-types@7.16.0'; + args[4].packages['@oliphaunt/ts-query/@types/node/undici-types'][3] = ''; + expect(() => importToolchainMetadata(...args)).toThrow('integrity-bearing'); +}); + +test('unrelated lock records cannot change the imported toolchain closure', () => { + const args = fixture(); + const before = importToolchainMetadata(...args); + args[4].packages.unrelated = ['unrelated@99.0.0', '', {}, 'sha512-unrelated']; + expect(importToolchainMetadata(...args)).toEqual(before); +}); + +test('rejects a compiler below the conventional Cargo minimum', () => { + const args = fixture(); + args[1].toolchain.channel = '1.92.0'; + expect(() => importToolchainMetadata(...args)).toThrow('below the Cargo workspace rust-version'); +}); + +test('query Rust compile facts come from Cargo and unsupported changes fail closed', () => { + const args = fixture(); + expect(importToolchainMetadata(...args).query_rust).toMatchObject({ + crate_name: 'oliphaunt_query', + edition: '2024', + minimum: '1.93', + version: '0.1.1', + }); + args[6].package.edition.workspace = false; + expect(() => importToolchainMetadata(...args)).toThrow('requires workspace edition'); + args[6].package.edition.workspace = true; + args[6].dependencies = { serde: '1' }; + expect(() => importToolchainMetadata(...args)).toThrow( + 'does not yet support Cargo [dependencies]', + ); +}); + +test('preserves Cargo version and inherited metadata in compiler environment', () => { + const args = fixture(); + args[6].package.version = '0.2.0-beta.1+build'; + args[6].package.license = { workspace: true }; + args[5].workspace.package.license = 'MIT'; + args[6].package.authors = ['First Author', 'Second Author']; + expect(importToolchainMetadata(...args).query_rust.env).toMatchObject({ + CARGO_PKG_NAME: 'oliphaunt-query', + CARGO_PKG_VERSION: '0.2.0-beta.1+build', + CARGO_PKG_VERSION_PATCH: '0', + CARGO_PKG_VERSION_PRE: 'beta.1', + CARGO_PKG_LICENSE: 'MIT', + CARGO_PKG_AUTHORS: 'First Author:Second Author', + }); +}); diff --git a/build_defs/host/BUILD.bazel b/build_defs/host/BUILD.bazel new file mode 100644 index 000000000..fc161dadc --- /dev/null +++ b/build_defs/host/BUILD.bazel @@ -0,0 +1,63 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/foundation:bun.bzl", "bun_binary", "bun_test") +load("@rules_cc//cc:cc_test.bzl", "cc_test") +load("@rules_shell//shell:sh_test.bzl", "sh_test") +load("@rules_swift//swift:swift.bzl", "swift_binary") +load("@rules_swift//swift/toolchains:xcode_swift_toolchain.bzl", "xcode_swift_toolchain") +load(":profile-test.bzl", "profile_test") +load(":rust-dependency-paths-test.bzl", "rust_dependency_paths_tests") +load(":cc-profiles.bzl", "host_cc_profiles") + +package(default_visibility = ["//visibility:public"]) + +exports_files(glob(["*.bzl", "*.mts", "*.patch"])) +exports_files(["sdk-smoke.sh"]) + +constraint_setting(name = "apple_product_profile") +constraint_value(name = "apple_package", constraint_setting = ":apple_product_profile") + +platform(name = "native_macos_arm64", constraint_values = ["@platforms//os:macos", "@platforms//cpu:aarch64", "@apple_support//constraints:apple"]) +platform(name = "apple_package_macos_arm64", constraint_values = ["@platforms//os:macos", "@platforms//cpu:aarch64", "@apple_support//constraints:apple", ":apple_package"]) +platform(name = "native_windows_x64", constraint_values = ["@platforms//os:windows", "@platforms//cpu:x86_64"]) +platform(name = "ios_device_arm64", constraint_values = ["@platforms//os:ios", "@platforms//cpu:aarch64", "@apple_support//constraints:apple", "@apple_support//constraints:device"]) +platform(name = "ios_simulator_arm64", constraint_values = ["@platforms//os:ios", "@platforms//cpu:aarch64", "@apple_support//constraints:apple", "@apple_support//constraints:simulator"]) + +bun_test(name = "host_sdk_test", entry_point = "host-sdk.test.mts", data = ["host-sdk.mts", "apple-app-tools.mts", "deployment-policy.mts", "//tools/dev:native-host-toolchains.json", "//tools/release:platform-compatibility-policy.mts", "//:tools/packaging/windows-vc-runtime-closure.mts", "//:tools/packaging/windows-vc-runtime-policy.json"], size = "small") +bun_test(name = "apple_app_tools_test", entry_point = "apple-app-tools.test.mts", data = ["apple-app-tools.mts"], size = "small") +bun_binary(name = "sdk_tree_conformance", entry_point = "sdk-tree-conformance.mts", data = ["sdk-tree.bzl"], tags = ["manual"]) +profile_test(name = "profile_analysis_test", size = "small") +rust_dependency_paths_tests() + +xcode_swift_toolchain( + name = "xcode_swift_base", + features = ["swift.module_map_no_private_headers"], + tags = ["manual"], +) + +cc_test( + name = "host_c_smoke", + srcs = ["sdk-smoke.c"], + target_compatible_with = select({ + "@platforms//os:macos": ["@platforms//cpu:aarch64"], + "@platforms//os:windows": ["@platforms//cpu:x86_64"], + "//conditions:default": ["@platforms//:incompatible"], + }), + size = "small", +) + +swift_binary( + name = "swift_sdk_smoke_binary", + srcs = ["sdk-smoke.swift"], + target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:aarch64", ":apple_package"], +) + +sh_test( + name = "host_swift_smoke", + srcs = ["sdk-smoke.sh"], + args = ["$(location :swift_sdk_smoke_binary)"], + data = [":swift_sdk_smoke_binary"], + target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:aarch64", ":apple_package"], + size = "small", +) + +source_quality_files() diff --git a/build_defs/host/app-tool-inputs.bzl b/build_defs/host/app-tool-inputs.bzl new file mode 100644 index 000000000..640cdef63 --- /dev/null +++ b/build_defs/host/app-tool-inputs.bzl @@ -0,0 +1,35 @@ +"""Bind maintained Apple action selection to the same licensed SDK capture.""" +load("@apple_support//lib:apple_support.bzl", "apple_support") + +def apple_app_configuration_error(info, observation, sdk_versions): + """Reject CLI overrides that would execute different ambient tool/SDK bytes.""" + versions = [line.removeprefix("Xcode ") for line in observation.split("\n") if line.startswith("Xcode ")] + builds = [line.removeprefix("Build version ") for line in observation.split("\n") if line.startswith("Build version ")] + if len(versions) != 1 or len(builds) != 1: + return "Captured Xcode version/build observation is malformed" + version, build = versions[0], builds[0] + selected = str(info.xcode_version()).split(".") + if len(selected) < 2 or selected[-1].lower() != build.lower(): + return "Stock Apple actions must select the captured Xcode build" + if apple_common.dotted_version(".".join(selected[:-1])).compare_to(apple_common.dotted_version(version)) != 0: + return "Stock Apple actions must select the captured Xcode version" + for sdk, platform in [("macosx", apple_common.platform.macos), ("iphoneos", apple_common.platform.ios_device), ("iphonesimulator", apple_common.platform.ios_simulator)]: + if info.sdk_version_for_platform(platform).compare_to(apple_common.dotted_version(sdk_versions[sdk])) != 0: + return "Stock Apple actions must select the captured " + sdk + " SDK" + # Explicit stock Xcode configurations have UNKNOWN availability. Locality + # is enforced by the licensed action owners, not this input filegroup. + if "no-local" in info.execution_info(): + return "The licensed application tools cannot use a remote-only Xcode configuration" + return None + +def _app_tools_impl(ctx): + error = apple_app_configuration_error(ctx.attr._xcode_config[apple_common.XcodeVersionConfig], ctx.attr.xcode_observation, ctx.attr.sdk_versions) + if error: + fail(error) + return [DefaultInfo(files = depset(ctx.files.tools))] + +declared_apple_app_tools = rule(implementation = _app_tools_impl, attrs = apple_support.action_required_attrs() | { + "tools": attr.label_list(mandatory = True, allow_files = True), + "xcode_observation": attr.string(mandatory = True), + "sdk_versions": attr.string_dict(mandatory = True), +}) diff --git a/build_defs/host/apple-app-tools.mts b/build_defs/host/apple-app-tools.mts new file mode 100644 index 000000000..be82e03b3 --- /dev/null +++ b/build_defs/host/apple-app-tools.mts @@ -0,0 +1,44 @@ +/** Licensed application/device tools from the same selected Xcode/OS boundary. */ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { readFileSync, realpathSync, statSync } from 'node:fs'; +import type { Component } from './host-sdk.mts'; + +export const APPLE_APP_TOOL_NAMES = [ + 'actool', + 'ibtool', + 'codesign', + 'codesign_allocate', + 'ditto', + 'lipo', + 'swift-stdlib-tool', + 'simctl', +] as const; +export function captureAppleAppTools(developer: string, find: (name: string) => string) { + const components: Component[] = [], + tools: Record = {}, + observations: Record = {}; + for (const name of APPLE_APP_TOOL_NAMES) { + const file = find(name), + physical = realpathSync(file); + assert(statSync(physical).isFile(), 'Licensed application tool must be a file: ' + name); + if (name !== 'codesign' && name !== 'ditto') + assert( + physical.startsWith(realpathSync(developer) + '/'), + 'Application tool must come from the selected Xcode: ' + name, + ); + const logical = 'tools/' + name; + components.push({ + name: logical, + path: file, + resolvedPath: physical, + directory: false, + roles: [], + }); + tools[name] = logical; + observations[name + '_sha256'] = createHash('sha256') + .update(readFileSync(physical)) + .digest('hex'); + } + return { components, tools, observations }; +} diff --git a/build_defs/host/apple-app-tools.test.mts b/build_defs/host/apple-app-tools.test.mts new file mode 100644 index 000000000..3a8690feb --- /dev/null +++ b/build_defs/host/apple-app-tools.test.mts @@ -0,0 +1,56 @@ +import { expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { APPLE_APP_TOOL_NAMES, captureAppleAppTools } from './apple-app-tools.mts'; + +function fixture(run: (root: string, developer: string, files: Record) => void) { + const root = mkdtempSync(path.join(tmpdir(), 'apple-app-tools-')); + try { + const developer = path.join(root, 'Xcode/Contents/Developer'); + const files: Record = {}; + for (const name of APPLE_APP_TOOL_NAMES) { + const directory = name === 'codesign' || name === 'ditto' ? root : developer; + mkdirSync(directory, { recursive: true }); + files[name] = path.join(directory, name); + writeFileSync(files[name], 'original ' + name); + } + run(root, developer, files); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +test('captures exact original application tools as inputs without adding them to C/Swift compiler closure', () => { + fixture((_root, developer, files) => { + const captured = captureAppleAppTools(developer, (name) => files[name]); + expect(captured.components).toHaveLength(APPLE_APP_TOOL_NAMES.length); + expect(captured.components.every((row) => !row.directory && row.roles.length === 0)).toBeTrue(); + expect(captured.observations.actool_sha256).toBe( + createHash('sha256').update('original actool').digest('hex'), + ); + writeFileSync(files.actool, 'different tool bytes'); + expect( + captureAppleAppTools(developer, (name) => files[name]).observations.actool_sha256, + ).not.toBe(captured.observations.actool_sha256); + }); +}); +test('rejects a compiler from another Xcode even through a symlink inside the selected developer tree', () => { + fixture((root, developer, files) => { + const outside = path.join(root, 'other-actool'); + writeFileSync(outside, 'other Xcode'); + rmSync(files.actool); + symlinkSync(outside, files.actool); + expect(() => captureAppleAppTools(developer, (name) => files[name])).toThrow(/selected Xcode/); + }); +}); +test('rejects directories and missing actual executables', () => { + fixture((_root, developer, files) => { + expect(() => + captureAppleAppTools(developer, (name) => (name === 'actool' ? developer : files[name])), + ).toThrow(/must be a file/); + rmSync(files.actool); + expect(() => captureAppleAppTools(developer, (name) => files[name])).toThrow(); + }); +}); diff --git a/build_defs/host/apple-support-objcxx-flags.patch b/build_defs/host/apple-support-objcxx-flags.patch new file mode 100644 index 000000000..01535f575 --- /dev/null +++ b/build_defs/host/apple-support-objcxx-flags.patch @@ -0,0 +1,11 @@ +diff --git a/crosstool/cc_toolchain_config.bzl b/crosstool/cc_toolchain_config.bzl +--- a/crosstool/cc_toolchain_config.bzl ++++ b/crosstool/cc_toolchain_config.bzl +@@ -1934,6 +1934,7 @@ + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_module_compile, ++ ACTION_NAMES.objcpp_compile, + ], + flag_groups = ([ + flag_group( diff --git a/build_defs/host/cc-profiles.bzl b/build_defs/host/cc-profiles.bzl new file mode 100644 index 000000000..9a5732937 --- /dev/null +++ b/build_defs/host/cc-profiles.bzl @@ -0,0 +1,191 @@ +"""Standard compiler configurations backed by the declared host SDK files.""" + +load("@rules_cc//cc/private/toolchain:unix_cc_toolchain_config.bzl", unix_config = "cc_toolchain_config") +load("@rules_cc//cc/private/toolchain:windows_cc_toolchain_config.bzl", windows_config = "cc_toolchain_config") +load("@rules_cc//cc/toolchains:cc_toolchain.bzl", "cc_toolchain") +load("@rules_cc//cc:cc_binary.bzl", "cc_binary") +load("@apple_support//crosstool:cc_toolchain_config.bzl", apple_config = "cc_toolchain_config") +load("@apple_support//crosstool:universal_exec_tool.bzl", "force_exec") + +def _driver_alias_impl(ctx): + output = ctx.actions.declare_file(ctx.label.name) + ctx.actions.symlink(output = output, target_file = ctx.file.binary, is_executable = True) + return [DefaultInfo(files = depset([output]), executable = output)] + +_driver_alias = rule(implementation = _driver_alias_impl, executable = True, attrs = {"binary": attr.label(allow_single_file = True, mandatory = True)}) + +_USE_LIBTOOL_ON_MACOS = str(Label("@rules_cc//cc/toolchains/args/archiver_flags:use_libtool_on_macos")) + +def _deployment_impl(settings, attr): + # The standard Apple configuration reads its triple from these fragments. + # Bind them to the selected public profile rather than the runner default. + return {"//command_line_option:macos_minimum_os": attr.macos_floor, "//command_line_option:ios_minimum_os": attr.ios_floor, _USE_LIBTOOL_ON_MACOS: False if attr.use_ar else settings[_USE_LIBTOOL_ON_MACOS]} + +_deployment = transition(implementation = _deployment_impl, inputs = [_USE_LIBTOOL_ON_MACOS], outputs = ["//command_line_option:macos_minimum_os", "//command_line_option:ios_minimum_os", _USE_LIBTOOL_ON_MACOS]) + +def _configuration_impl(ctx): + return [ctx.attr.configuration[0][CcToolchainConfigInfo]] + +_configuration = rule( + implementation = _configuration_impl, + attrs = { + "configuration": attr.label(mandatory = True, providers = [CcToolchainConfigInfo], cfg = _deployment), + "macos_floor": attr.string(mandatory = True), + "ios_floor": attr.string(mandatory = True), + "use_ar": attr.bool(default = False), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), + }, +) + +def host_builtin_include_directories(prefix, directories): + """Builtin paths need an explicit execroot base, unlike compiler flags.""" + return ["%workspace%/" + prefix + directory for directory in directories] + +def host_cc_profiles(sdk): + """Bind standard C/C++ configurations to the declared host SDK.""" + prefix = "external/" + native.repository_name()[1:] + "/" + if sdk["family"] == "msvc": + includes = ["compiler_include"] + ["sdk_include/" + name for name in ["ucrt", "shared", "um", "winrt", "cppwinrt"]] + libraries = ["compiler_lib", "sdk_lib_ucrt", "sdk_lib_um"] + windows_config( + name = "configuration", + cpu = "x64_windows", + compiler = "msvc-cl", + host_system_name = "x86_64-pc-windows-msvc", + target_system_name = "x86_64-pc-windows-msvc", + target_libc = "ucrt", + abi_version = sdk["observations"]["VCToolsVersion"], + abi_libc_version = sdk["observations"]["WindowsSDKVersion"], + toolchain_identifier = "oliphaunt_msvc_x64", + msvc_cl_path = "compiler_bin/cl.exe", + msvc_ml_path = "compiler_bin/ml64.exe", + msvc_link_path = "compiler_bin/link.exe", + msvc_lib_path = "compiler_bin/lib.exe", + msvc_env_include = ";".join([prefix + directory for directory in includes]), + msvc_env_lib = ";".join([prefix + directory for directory in libraries]), + msvc_env_path = ";".join([prefix + directory for directory in ["compiler_bin", "sdk_bin", "crt"]]), + msvc_env_tmp = sdk["temporaryDirectory"], + cxx_builtin_include_directories = host_builtin_include_directories(prefix, includes), + tool_paths = { + "ar": "compiler_bin/lib.exe", + "ml": "compiler_bin/ml64.exe", + "cpp": "compiler_bin/cl.exe", + "gcc": "compiler_bin/cl.exe", + "ld": "compiler_bin/link.exe", + "nm": "compiler_bin/dumpbin.exe", + "dumpbin": "compiler_bin/dumpbin.exe", + "gcov": "unsupported.bat", + "objcopy": "unsupported.bat", + "objdump": "unsupported.bat", + "strip": "unsupported.bat", + }, + archiver_flags = ["/MACHINE:X64"], + default_link_flags = ["/MACHINE:X64"], + fastbuild_mode_debug_flag = "/DEBUG", + dbg_mode_debug_flag = "/DEBUG", + supports_parse_showincludes = True, + shorten_virtual_includes = True, + ) + _compiler("cc_compiler", ":configuration", sdk, []) + else: + for name, minimum in [("native", sdk["deploymentTargets"]["native_macos"])]: + unix_config( + name = "unix_configuration_" + name, + cpu = "darwin_arm64", + compiler = "clang", + host_system_name = "aarch64-apple-darwin", + target_system_name = "arm64-apple-macosx" + minimum, + target_libc = "macosx", + abi_version = sdk["observations"]["xcode"], + abi_libc_version = sdk["observations"]["macosx_version"], + toolchain_identifier = "oliphaunt_apple_arm64_" + name, + builtin_sysroot = prefix + "sdk_macosx", + cxx_builtin_include_directories = host_builtin_include_directories(prefix, [sdk["resourceDirectory"] + "/include", "sdk_macosx/usr/include", "sdk_macosx/System/Library/Frameworks", "toolchain/include/c++/v1"]), + tool_paths = { + "gcc": sdk["tools"]["clang"], + "cpp": sdk["tools"]["clang"], + "ar": sdk["tools"]["ar"], + "ld": sdk["tools"]["ld"], + "nm": sdk["tools"]["nm"], + "strip": sdk["tools"]["strip"], + "gcov": "unsupported.sh", + "objcopy": "unsupported.sh", + "objdump": "unsupported.sh", + }, + compile_flags = ["-target", "arm64-apple-macosx" + minimum, "-resource-dir", prefix + sdk["resourceDirectory"], "-isysroot", prefix + "sdk_macosx"], + cxx_flags = ["-std=c++17"], + link_flags = ["-target", "arm64-apple-macosx" + minimum, "-resource-dir", prefix + sdk["resourceDirectory"], "-isysroot", prefix + "sdk_macosx"], + link_libs = ["-lc++"], + unfiltered_compile_flags = ["-Wno-overriding-option"], + supports_start_end_lib = False, + ) + _configuration( + name = "configuration_" + name, + configuration = ":unix_configuration_" + name, + macos_floor = minimum, + ios_floor = sdk["deploymentTargets"]["ios"], + use_ar = True, + ) + _compiler("cc_" + name, ":configuration_" + name, sdk, [component for other in ["iphoneos", "iphonesimulator"] for component in ["sdk_" + other, "platform_" + other + "/Library", "platform_" + other + "/usr/lib"]]) + # Build the pinned standard Apple drivers with the declared native + # compiler. Upstream's universal_exec_tool uses an ambient shell compiler. + cc_binary(name = "wrapped_clang", srcs = ["wrapped_clang.cc"], copts = ["-std=c++17"]) + _driver_alias(name = "wrapped_clang_pp", binary = ":wrapped_clang") + cc_binary(name = "libtool", srcs = ["libtool.cc"], copts = ["-std=c++17"]) + for driver in ["wrapped_clang", "wrapped_clang_pp", "libtool"]: + force_exec(name = "exec_" + driver, target = ":" + driver) + # Match apple_support's disabled-layering configuration: a label whose + # DefaultInfo contains no module map, rather than an absent label. + native.filegroup(name = "modulemap", srcs = []) + for name, cpu, selected_sdk in [ + ("package", "darwin_arm64", "macosx"), + ("ios", "ios_arm64", "iphoneos"), + ("ios_simulator", "ios_sim_arm64", "iphonesimulator"), + ]: + apple_config( + name = "apple_configuration_" + name, + cpu = cpu, + wrapped_clang = ":exec_wrapped_clang", + wrapped_clang_pp = ":exec_wrapped_clang_pp", + libtool = ":exec_libtool", + module_map = ":modulemap", + c_flags = ["-resource-dir", prefix + sdk["resourceDirectory"]], + link_flags = ["-resource-dir", prefix + sdk["resourceDirectory"]], + cxx_flags = ["-std=c++20"] if selected_sdk in ["iphoneos", "iphonesimulator"] else [], + cxx_builtin_include_directories = host_builtin_include_directories(prefix, [sdk["resourceDirectory"] + "/include", "sdk_" + selected_sdk + "/usr/include", "sdk_" + selected_sdk + "/System/Library/Frameworks", "toolchain/include/c++/v1"]), + # Bazel owns the reserved Xcode environment; drivers consume our captured paths. + # Rust expands ${pwd} before changing cwd; native drivers keep paths relative. + extra_env = {"OLIPHAUNT_APPLE_DEVELOPER_DIRECTORY": "${pwd}/" + prefix.removesuffix("/"), "OLIPHAUNT_APPLE_SDKROOT": "${pwd}/" + prefix + "sdk_" + selected_sdk, "OLIPHAUNT_APPLE_TOOL_DIRECTORY": "${pwd}/" + prefix + "tools"}, + # Tool metadata is relative to this package, unlike action Files or env/flag paths. + tool_paths_overrides = {"ar": sdk["tools"]["ar"], "cpp": sdk["tools"]["clang"], "ld": sdk["tools"]["ld"], "nm": sdk["tools"]["nm"], "strip": sdk["tools"]["strip"], "gcov": "unsupported.sh", "objdump": "unsupported.sh"}, + ) + _configuration( + name = "configuration_" + name, + configuration = ":apple_configuration_" + name, + macos_floor = sdk["deploymentTargets"]["package_macos"], + ios_floor = sdk["deploymentTargets"]["ios"], + ) + _compiler("cc_" + name, ":configuration_" + name, sdk, [component for other in ["macosx", "iphoneos", "iphonesimulator"] if other != selected_sdk for component in ["sdk_" + other, "platform_" + other + "/Library", "platform_" + other + "/usr/lib"]], drivers = True) + +def _compiler(name, configuration, sdk, exclude, drivers = False): + components = [component for component in sdk["components"] if component["name"] not in exclude] + for role in ["compile", "link"]: + native.filegroup( + name = name + "_" + role + "_files", + srcs = [":receipt.json", ":unsupported.bat", ":unsupported.sh"] + ([":exec_wrapped_clang", ":exec_wrapped_clang_pp", ":exec_libtool"] if drivers else []) + [":" + component["name"] + ("_compile_files" if sdk["family"] == "apple" and role == "compile" else "_files") for component in components if role in component["roles"]], + ) + native.filegroup(name = name + "_all_files", srcs = [":" + name + "_compile_files", ":" + name + "_link_files"]) + cc_toolchain( + name = name, + toolchain_identifier = name, + toolchain_config = configuration, + all_files = ":" + name + "_all_files", + ar_files = ":" + name + "_link_files", + as_files = ":" + name + "_compile_files", + compiler_files = ":" + name + "_compile_files", + linker_files = ":" + name + "_link_files", + strip_files = ":" + name + "_link_files", + dwp_files = ":" + name + "_link_files", + objcopy_files = ":" + name + "_link_files", + supports_param_files = True, + ) diff --git a/build_defs/host/declared-apple-drivers.patch b/build_defs/host/declared-apple-drivers.patch new file mode 100644 index 000000000..6f2314af8 --- /dev/null +++ b/build_defs/host/declared-apple-drivers.patch @@ -0,0 +1,146 @@ +diff --git a/wrapped_clang.cc b/wrapped_clang.cc +--- a/wrapped_clang.cc ++++ b/wrapped_clang.cc +@@ -94,12 +94,12 @@ static std::string Unescape(const std::string& arg) { + } + + // Converts an array of string arguments to char *arguments. +-// The first arg is reduced to its basename as per execve conventions. ++// Preserve the executable path: Clang uses argv[0] for subprocess discovery. + // Note that the lifetime of the char* arguments in the returned array + // are controlled by the lifetime of the strings in args. + std::vector ConvertToCArgs(const std::vector& args) { + std::vector c_args; +- c_args.push_back(Basename(args[0].c_str())); ++ c_args.push_back(args[0].c_str()); + for (int i = 1; i < args.size(); i++) { + c_args.push_back(args[i].c_str()); + } +@@ -173,7 +173,12 @@ + std::cerr << "Error: " << var_name << " not set.\n"; + exit(EXIT_FAILURE); + } +- return env_value; ++ std::string value = env_value; ++ const std::string prefix = "${pwd}/"; ++ if (value.compare(0, prefix.size(), prefix) == 0) { ++ return value.substr(prefix.size()); ++ } ++ return value; + } + + // Returns true if `str` starts with the specified `prefix`. +@@ -393,6 +398,14 @@ + FindAndReplace("__BAZEL_EXECUTION_ROOT_CANONICAL__", canonical_cwd, + &new_arg); + } ++ FindAndReplace("__BAZEL_XCODE_DEVELOPER_DIR__/Toolchains/XcodeDefault.xctoolchain/usr", ++ developer_dir + "/toolchain", &new_arg); ++ FindAndReplace("__BAZEL_XCODE_DEVELOPER_DIR__/Platforms/MacOSX.platform/Developer", ++ developer_dir + "/platform_macosx", &new_arg); ++ FindAndReplace("__BAZEL_XCODE_DEVELOPER_DIR__/Platforms/iPhoneOS.platform/Developer", ++ developer_dir + "/platform_iphoneos", &new_arg); ++ FindAndReplace("__BAZEL_XCODE_DEVELOPER_DIR__/Platforms/iPhoneSimulator.platform/Developer", ++ developer_dir + "/platform_iphonesimulator", &new_arg); + FindAndReplace("__BAZEL_XCODE_DEVELOPER_DIR__", developer_dir, &new_arg); + FindAndReplace("__BAZEL_XCODE_SDKROOT__", sdk_root, &new_arg); + if (!toolchain_path.empty()) { +@@ -439,11 +452,12 @@ + const char* toolchain_id = getenv("TOOLCHAINS"); + std::string toolchain_path = ""; + if (toolchain_id != nullptr) { +- toolchain_path = GetToolchainPath(toolchain_id); ++ std::cerr << "The declared Apple profile does not support TOOLCHAINS overrides\n"; ++ return EXIT_FAILURE; + } + +- std::string developer_dir = GetMandatoryEnvVar("DEVELOPER_DIR"); +- std::string sdk_root = GetMandatoryEnvVar("SDKROOT"); ++ std::string developer_dir = GetMandatoryEnvVar("OLIPHAUNT_APPLE_DEVELOPER_DIRECTORY"); ++ std::string sdk_root = GetMandatoryEnvVar("OLIPHAUNT_APPLE_SDKROOT"); + std::string linked_binary, dsym_path; + bool strip_debug_symbols = false; + +@@ -453,7 +467,8 @@ + canonical_cwd = GetCanonicalPath(cwd); + } + +- std::vector invocation_args = {"/usr/bin/xcrun", tool_name}; ++ std::vector invocation_args = { ++ GetMandatoryEnvVar("OLIPHAUNT_APPLE_TOOL_DIRECTORY") + "/" + tool_name}; + std::vector processed_args = {}; + + auto consumer = [&](const std::string& arg) { +@@ -514,7 +529,7 @@ + dsym_path.length() - bundle_suffix.length(); + + std::vector dsymutil_args = { +- "/usr/bin/xcrun", "dsymutil", ++ GetMandatoryEnvVar("OLIPHAUNT_APPLE_TOOL_DIRECTORY") + "/dsymutil", + linked_binary, "-o", + dsym_path, "--no-swiftmodule-timestamp"}; + if (!is_bundle) { +@@ -530,8 +545,9 @@ + // When stripping is requested, we should still strip the binary + // before returning + if (strip_debug_symbols) { +- std::vector strip_args = {"/usr/bin/xcrun", "strip", "-S", +- linked_binary}; ++ std::vector strip_args = { ++ GetMandatoryEnvVar("OLIPHAUNT_APPLE_TOOL_DIRECTORY") + "/strip", "-S", ++ linked_binary}; + if (!RunSubProcess(strip_args)) { + return 2; + } +diff --git a/libtool.cc b/libtool.cc +--- a/libtool.cc ++++ b/libtool.cc +@@ -72,7 +72,12 @@ + std::cerr << "error: " << var_name << " not set.\n"; + exit(EXIT_FAILURE); + } +- return env_value; ++ std::string value = env_value; ++ const std::string prefix = "${pwd}/"; ++ if (value.compare(0, prefix.size(), prefix) == 0) { ++ return value.substr(prefix.size()); ++ } ++ return value; + } + + // Returns the base name of the given filepath. For example, given +@@ -184,6 +189,14 @@ + std::string rewriteArg(const std::string arg, const std::string developer_dir, + const std::string sdk_root) { + auto new_arg = arg; ++ findAndReplace("__BAZEL_XCODE_DEVELOPER_DIR__/Toolchains/XcodeDefault.xctoolchain/usr", ++ developer_dir + "/toolchain", &new_arg); ++ findAndReplace("__BAZEL_XCODE_DEVELOPER_DIR__/Platforms/MacOSX.platform/Developer", ++ developer_dir + "/platform_macosx", &new_arg); ++ findAndReplace("__BAZEL_XCODE_DEVELOPER_DIR__/Platforms/iPhoneOS.platform/Developer", ++ developer_dir + "/platform_iphoneos", &new_arg); ++ findAndReplace("__BAZEL_XCODE_DEVELOPER_DIR__/Platforms/iPhoneSimulator.platform/Developer", ++ developer_dir + "/platform_iphonesimulator", &new_arg); + findAndReplace("__BAZEL_XCODE_DEVELOPER_DIR__", developer_dir, &new_arg); + findAndReplace("__BAZEL_XCODE_SDKROOT__", sdk_root, &new_arg); + return new_arg; +@@ -272,8 +285,8 @@ + args.push_back(argv[i]); + } + +- std::string developer_dir = getMandatoryEnvVar("DEVELOPER_DIR"); +- std::string sdk_root = getMandatoryEnvVar("SDKROOT"); ++ std::string developer_dir = getMandatoryEnvVar("OLIPHAUNT_APPLE_DEVELOPER_DIRECTORY"); ++ std::string sdk_root = getMandatoryEnvVar("OLIPHAUNT_APPLE_SDKROOT"); + + // NOTE: Order of libtool flags interspersed with files does not matter, but + // maintaining file order might? +@@ -310,7 +323,6 @@ + response_file_stream.close(); + + std::vector invocation_args = { +- "/usr/bin/xcrun", +- "libtool", ++ getMandatoryEnvVar("OLIPHAUNT_APPLE_TOOL_DIRECTORY") + "/libtool", + "@" + response_file.u8string(), + }; diff --git a/build_defs/host/deployment-policy.mts b/build_defs/host/deployment-policy.mts new file mode 100644 index 000000000..46155f51b --- /dev/null +++ b/build_defs/host/deployment-policy.mts @@ -0,0 +1,13 @@ +import { platformCompatibilityContract } from '../../tools/release/platform-compatibility-policy.mts'; + +/** Compiler and packaging projections of the canonical public Apple contracts. */ +export function appleDeploymentTargets(): Record { + const native = platformCompatibilityContract('macos-arm64').apple.platforms; + const carrier = platformCompatibilityContract('ios-xcframework').apple.platforms; + return { + native_macos: native.macos.maximumMinimumOs.join('.'), + package_macos: carrier.macos.maximumMinimumOs.join('.'), + ios: carrier.ios.maximumMinimumOs.join('.'), + ios_simulator: carrier.iosSimulator.maximumMinimumOs.join('.'), + }; +} diff --git a/build_defs/host/desktop-profile.bzl b/build_defs/host/desktop-profile.bzl new file mode 100644 index 000000000..a6583302a --- /dev/null +++ b/build_defs/host/desktop-profile.bzl @@ -0,0 +1,10 @@ +"""Desktop artifacts retain their contract when consumed by Apple packages.""" + +_PLATFORMS = "//command_line_option:platforms" +_PACKAGE = Label("//build_defs/host:apple_package_macos_arm64") +_DESKTOP = Label("//build_defs/host:native_macos_arm64") + +def _desktop_profile_impl(settings, _attr): + return {_PLATFORMS: [str(_DESKTOP) if Label(str(platform)) == _PACKAGE else str(platform) for platform in settings[_PLATFORMS]]} + +desktop_profile = transition(implementation = _desktop_profile_impl, inputs = [_PLATFORMS], outputs = [_PLATFORMS]) diff --git a/build_defs/host/host-sdk.mts b/build_defs/host/host-sdk.mts new file mode 100644 index 000000000..2e8feaa13 --- /dev/null +++ b/build_defs/host/host-sdk.mts @@ -0,0 +1,353 @@ +/** Import the selected, licensed host SDK into declared Bazel inputs. */ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { existsSync, readFileSync, realpathSync, statSync } from 'node:fs'; +import { release } from 'node:os'; +import path from 'node:path'; +import { windowsVcRuntimeProfileNames } from '../../tools/packaging/windows-vc-runtime-closure.mts'; +import { captureAppleAppTools } from './apple-app-tools.mts'; +import { appleDeploymentTargets } from './deployment-policy.mts'; + +export { appleDeploymentTargets } from './deployment-policy.mts'; + +export interface HostPolicy { + apple: { + xcode_version: string; + developer_dir: string; + }; + windows: { + visual_studio_major: number; + vc_toolset_major: number; + vc_toolset_minor_min: number; + vc_toolset_minor_max_exclusive: number; + windows_sdk_major: number; + crt_family: string; + }; +} + +export interface Component { + name: string; + path: string; + resolvedPath: string; + directory: boolean; + roles: ('compile' | 'link' | 'swift')[]; +} + +export interface HostSdk { + family: 'apple' | 'msvc'; + components: Component[]; + observations: Record; + tools: Record; + resourceDirectory?: string; + temporaryDirectory?: string; + deploymentTargets?: Record; + developerDirectory?: string; + runtimeDlls?: string[]; +} + +function scalar(value: unknown, name: string): string { + assert.equal(typeof value, 'string', `${name} must be a string`); + assert.ok( + (value as string).length > 0 && !/[\r\n\0]/.test(value as string), + `${name} is empty or contains a control character`, + ); + return value as string; +} + +export function parsePolicy(value: unknown): HostPolicy { + assert.ok( + value && typeof value === 'object' && !Array.isArray(value), + 'host policy must be an object', + ); + const policy = value as HostPolicy; + assert.ok(policy.apple && policy.windows, 'host policy needs Apple and Windows sections'); + for (const [key, version] of Object.entries(policy.apple)) { + scalar(version, `apple.${key}`); + if (key !== 'developer_dir') assert.match(version, /^\d+(?:\.\d+)+$/, `invalid apple.${key}`); + } + for (const key of ['xcode_version', 'developer_dir'] as const) + scalar(policy.apple[key], `apple.${key}`); + assert.equal( + policy.apple.developer_dir, + `/Applications/Xcode_${policy.apple.xcode_version}.app/Contents/Developer`, + 'Xcode path must identify the supported version', + ); + for (const key of [ + 'visual_studio_major', + 'vc_toolset_major', + 'vc_toolset_minor_min', + 'vc_toolset_minor_max_exclusive', + 'windows_sdk_major', + ] as const) { + assert.ok( + Number.isSafeInteger(policy.windows[key]) && policy.windows[key] > 0, + `invalid windows.${key}`, + ); + } + assert.ok( + policy.windows.vc_toolset_minor_min < policy.windows.vc_toolset_minor_max_exclusive, + 'empty VC toolset family', + ); + assert.match(scalar(policy.windows.crt_family, 'windows.crt_family'), /^VC\d+$/); + return policy; +} + +function run( + executable: string, + args: string[], + env: NodeJS.ProcessEnv = process.env, + allowedStatus = [0], +): string { + const result = spawnSync(executable, args, { + env, + encoding: 'utf8', + timeout: 30_000, + maxBuffer: 4 * 1024 * 1024, + }); + assert.equal(result.error, undefined, `${executable}: ${result.error}`); + assert.ok( + result.status !== null && allowedStatus.includes(result.status), + `${executable} failed: ${result.stderr}`, + ); + return `${result.stdout}${result.stderr}`.trim(); +} + +function component( + name: string, + input: string, + directory: boolean, + roles: Component['roles'], +): Component { + const physical = realpathSync(input); + assert.equal(statSync(physical).isDirectory(), directory, `${input} has the wrong file type`); + return { + name, + // Preserve logical SDK paths for declared inputs and file/directory watches. + path: path.resolve(input).replaceAll('\\', '/'), + resolvedPath: physical.replaceAll('\\', '/'), + directory, + roles, + }; +} + +function digest(file: string): string { + return createHash('sha256').update(readFileSync(file)).digest('hex'); +} + +function version(value: string, name: string): number[] { + assert.match(value, /^\d+(?:\.\d+){1,3}$/, `${name} must be a numeric version`); + return value.split('.').map(Number); +} + +export function verifyWindowsVersions(env: NodeJS.ProcessEnv, policy: HostPolicy['windows']) { + const command = version(scalar(env.VSCMD_VER, 'VSCMD_VER'), 'VSCMD_VER'); + const vc = version( + scalar(env.VCToolsVersion, 'VCToolsVersion').replace(/[\\/]+$/, ''), + 'VCToolsVersion', + ); + const sdk = version( + scalar(env.WindowsSDKVersion, 'WindowsSDKVersion').replace(/[\\/]+$/, ''), + 'WindowsSDKVersion', + ); + assert.equal(command[0], policy.visual_studio_major, 'unsupported Visual Studio family'); + assert.equal(vc[0], policy.vc_toolset_major, 'unsupported VC toolset major'); + assert.ok( + vc[1] >= policy.vc_toolset_minor_min && vc[1] < policy.vc_toolset_minor_max_exclusive, + 'unsupported VC toolset family', + ); + assert.equal(sdk[0], policy.windows_sdk_major, 'unsupported Windows SDK family'); + assert.equal(env.VSCMD_ARG_HOST_ARCH, 'x64', 'MSVC host must be x64'); + assert.equal(env.VSCMD_ARG_TGT_ARCH, 'x64', 'MSVC target must be x64'); +} + +function captureWindows(policy: HostPolicy, env: NodeJS.ProcessEnv): HostSdk { + verifyWindowsVersions(env, policy.windows); + const vc = scalar(env.VCToolsInstallDir, 'VCToolsInstallDir'); + const sdkRoot = scalar(env.WindowsSdkDir, 'WindowsSdkDir'); + const sdkVersion = scalar(env.WindowsSDKVersion, 'WindowsSDKVersion').replace(/[\\/]+$/, ''); + assert.equal( + path.basename(vc.replace(/[\\/]+$/, '')), + scalar(env.VCToolsVersion, 'VCToolsVersion').replace(/[\\/]+$/, ''), + 'VCToolsInstallDir must identify the selected exact toolset', + ); + const binary = path.join(vc, 'bin', 'HostX64', 'x64'); + const crt = path.join( + scalar(env.VCToolsRedistDir, 'VCToolsRedistDir'), + 'x64', + `Microsoft.${policy.windows.crt_family}.CRT`, + ); + const components = [ + component('compiler_bin', binary, true, ['compile', 'link']), + component('compiler_include', path.join(vc, 'include'), true, ['compile']), + component('compiler_lib', path.join(vc, 'lib', 'x64'), true, ['link']), + component('sdk_include', path.join(sdkRoot, 'Include', sdkVersion), true, ['compile']), + component('sdk_lib_ucrt', path.join(sdkRoot, 'Lib', sdkVersion, 'ucrt', 'x64'), true, ['link']), + component('sdk_lib_um', path.join(sdkRoot, 'Lib', sdkVersion, 'um', 'x64'), true, ['link']), + component('sdk_bin', path.join(sdkRoot, 'bin', sdkVersion, 'x64'), true, ['link']), + component('crt', crt, true, ['compile', 'link']), + ]; + const tools: Record = {}; + for (const name of ['cl', 'link', 'lib', 'dumpbin', 'ml64']) { + const file = path.join(binary, `${name}.exe`); + assert.ok(existsSync(file), `MSVC is missing ${file}`); + tools[name] = `compiler_bin/${name}.exe`; + } + const resourceCompiler = path.join(sdkRoot, 'bin', sdkVersion, 'x64', 'rc.exe'); + assert.ok(statSync(resourceCompiler).isFile(), `Windows SDK is missing ${resourceCompiler}`); + tools.rc = 'sdk_bin/rc.exe'; + const runtimeDlls = windowsVcRuntimeProfileNames('provider'); + assert.ok(runtimeDlls.length > 0, 'Windows provider runtime profile must not be empty'); + for (const name of runtimeDlls) + assert.ok(statSync(path.join(crt, name)).isFile(), `missing regular CRT ${name}`); + return { + family: 'msvc', + components, + tools, + runtimeDlls: runtimeDlls.map((name) => `crt/${name}`), + temporaryDirectory: scalar(env.TEMP ?? env.TMP, 'MSVC temporary directory'), + observations: { + VSCMD_VER: scalar(env.VSCMD_VER, 'VSCMD_VER'), + VCToolsVersion: scalar(env.VCToolsVersion, 'VCToolsVersion'), + WindowsSDKVersion: sdkVersion, + compiler: run(path.join(binary, 'cl.exe'), ['/Bv'], env, [0, 2]), + compiler_sha256: digest(path.join(binary, 'cl.exe')), + linker_sha256: digest(path.join(binary, 'link.exe')), + dumpbin_sha256: digest(path.join(binary, 'dumpbin.exe')), + resource_compiler_sha256: digest(resourceCompiler), + os_build: release(), + ImageOS: env.ImageOS ?? '', + ImageVersion: env.ImageVersion ?? '', + }, + }; +} + +function captureApple(policy: HostPolicy, env: NodeJS.ProcessEnv): HostSdk { + assert.equal( + env.TOOLCHAINS, + undefined, + 'the declared Apple profile does not support TOOLCHAINS overrides', + ); + assert.equal( + env.DEVELOPER_DIR, + policy.apple.developer_dir, + 'DEVELOPER_DIR must select the supported Xcode bundle', + ); + const xcode = run('/usr/bin/xcodebuild', ['-version'], env); + assert.equal( + /^Xcode (.+)$/m.exec(xcode)?.[1], + policy.apple.xcode_version, + 'unsupported Xcode version', + ); + assert.match(xcode, /^Build version \S+$/m, 'Xcode build identity is missing'); + const developer = realpathSync(policy.apple.developer_dir); + const toolchain = path.join(developer, 'Toolchains', 'XcodeDefault.xctoolchain', 'usr'); + const components = [component('toolchain', toolchain, true, ['compile', 'link', 'swift'])]; + const observations: Record = { + xcode, + os_build: run('/usr/bin/sw_vers', ['-buildVersion']), + ImageOS: env.ImageOS ?? '', + ImageVersion: env.ImageVersion ?? '', + }; + for (const [sdk, platform] of [ + ['macosx', 'MacOSX'], + ['iphoneos', 'iPhoneOS'], + ['iphonesimulator', 'iPhoneSimulator'], + ]) { + const platformDeveloper = path.join( + developer, + 'Platforms', + `${platform}.platform`, + 'Developer', + ); + for (const directory of ['Library', 'usr/lib']) + components.push( + component(`platform_${sdk}/${directory}`, path.join(platformDeveloper, directory), true, [ + 'compile', + 'link', + 'swift', + ]), + ); + const sdkPath = run('/usr/bin/xcrun', ['--sdk', sdk, '--show-sdk-path'], env); + assert.ok( + realpathSync(sdkPath).startsWith(`${developer}/`), + `${sdk} must come from the selected Xcode bundle`, + ); + components.push(component(`sdk_${sdk}`, sdkPath, true, ['compile', 'link', 'swift'])); + observations[`${sdk}_version`] = run( + '/usr/bin/xcrun', + ['--sdk', sdk, '--show-sdk-version'], + env, + ); + version(observations[`${sdk}_version`], `${sdk} SDK`); + } + const tools: Record = {}; + for (const name of [ + 'clang', + 'clang++', + 'libtool', + 'ar', + 'ld', + 'nm', + 'strip', + 'install_name_tool', + 'otool', + 'plutil', + 'dsymutil', + 'swiftc', + 'swift-symbolgraph-extract', + 'swift-synthesize-interface', + ]) { + const tool = run('/usr/bin/xcrun', ['--find', name], env); + components.push(component(`tools/${name}`, tool, false, ['compile', 'link', 'swift'])); + tools[name] = `tools/${name}`; + observations[`${name}_sha256`] = digest(tool); + } + const resource = realpathSync(run('/usr/bin/xcrun', ['clang', '-print-resource-dir'], env)); + assert.ok( + resource.startsWith(`${realpathSync(toolchain)}/`), + 'Clang resource directory must come from the selected toolchain', + ); + observations.swift = run('/usr/bin/xcrun', ['swiftc', '--version'], env); + components.push(component('tools/xcrun', '/usr/bin/xcrun', false, ['compile', 'link', 'swift'])); + const appTools = captureAppleAppTools(developer, (name) => + name === 'ditto' ? '/usr/bin/ditto' : run('/usr/bin/xcrun', ['--find', name], env), + ); + components.push(...appTools.components); + Object.assign(tools, appTools.tools); + Object.assign(observations, appTools.observations); + // Standard Apple strip actions invoke the operating-system tool directly. + components.push(component('system/strip', '/usr/bin/strip', false, ['link'])); + return { + family: 'apple', + components, + tools, + observations, + developerDirectory: developer, + resourceDirectory: `toolchain/${path.relative(realpathSync(toolchain), resource)}`, + }; +} + +export function captureHostSdk(policy: HostPolicy, family: string): HostSdk { + assert.ok(family === 'apple' || family === 'msvc', 'unknown host SDK family'); + assert.equal( + process.platform, + family === 'apple' ? 'darwin' : 'win32', + 'host SDK cannot be acquired from an incompatible host', + ); + assert.equal( + process.arch, + family === 'apple' ? 'arm64' : 'x64', + 'host SDK profile has no compiler declaration for this CPU', + ); + const sdk = + family === 'apple' ? captureApple(policy, process.env) : captureWindows(policy, process.env); + if (family === 'apple') sdk.deploymentTargets = appleDeploymentTargets(); + return sdk; +} + +if (import.meta.main) { + const [policyFile, family] = process.argv.slice(2); + const policy = parsePolicy(JSON.parse(readFileSync(policyFile, 'utf8'))); + process.stdout.write(JSON.stringify(captureHostSdk(policy, family))); +} diff --git a/build_defs/host/host-sdk.test.mts b/build_defs/host/host-sdk.test.mts new file mode 100644 index 000000000..f79d25510 --- /dev/null +++ b/build_defs/host/host-sdk.test.mts @@ -0,0 +1,69 @@ +import { describe, expect, test } from 'bun:test'; +import { readFileSync } from 'node:fs'; +import { + appleDeploymentTargets, + captureHostSdk, + parsePolicy, + verifyWindowsVersions, +} from './host-sdk.mts'; + +const policy = JSON.parse(readFileSync('tools/dev/native-host-toolchains.json', 'utf8')); +const environment = { + VSCMD_VER: '18.0.4', + VCToolsVersion: '14.50.35717\\', + WindowsSDKVersion: '10.0.26100.0\\', + VSCMD_ARG_HOST_ARCH: 'x64', + VSCMD_ARG_TGT_ARCH: 'x64', +}; + +describe('declared native host SDK policy', () => { + test('deployment profiles project the existing public artifact compatibility contract', () => { + expect(appleDeploymentTargets()).toEqual({ + native_macos: '11.0.0', + package_macos: '14.0.0', + ios: '17.0.0', + ios_simulator: '17.0.0', + }); + }); + test('existing supported toolset family accepts exact selected versions', () => { + const parsed = parsePolicy(policy); + verifyWindowsVersions(environment, parsed.windows); + verifyWindowsVersions({ ...environment, VCToolsVersion: '14.59.1' }, parsed.windows); + }); + test('unsupported families, architecture and missing identities fail', () => { + for (const mutation of [ + { VSCMD_VER: '17.0.1' }, + { VCToolsVersion: '14.49.1' }, + { VCToolsVersion: '14.60.1' }, + { WindowsSDKVersion: '11.0.1' }, + { VSCMD_ARG_HOST_ARCH: 'arm64' }, + { VSCMD_ARG_TGT_ARCH: 'arm64' }, + { VCToolsVersion: undefined }, + { WindowsSDKVersion: '10.0\n26100' }, + ]) + expect(() => + verifyWindowsVersions({ ...environment, ...mutation }, policy.windows), + ).toThrow(); + }); + test('malformed policy does not provide a default or silently widen support', () => { + for (const mutation of [ + null, + {}, + { ...policy, apple: {} }, + { + ...policy, + apple: { ...policy.apple, developer_dir: '/Applications/Xcode.app/Contents/Developer' }, + }, + { ...policy, windows: { ...policy.windows, vc_toolset_minor_max_exclusive: 50 } }, + { ...policy, windows: { ...policy.windows, visual_studio_major: '18' } }, + ]) + expect(() => parsePolicy(mutation)).toThrow(); + }); + test('licensed SDK acquisition rejects this Linux client', () => { + if (process.platform === 'linux') { + expect(() => captureHostSdk(policy, 'apple')).toThrow('incompatible host'); + expect(() => captureHostSdk(policy, 'msvc')).toThrow('incompatible host'); + } + expect(() => captureHostSdk(policy, 'unknown')).toThrow('unknown host SDK'); + }); +}); diff --git a/build_defs/host/profile-test.bzl b/build_defs/host/profile-test.bzl new file mode 100644 index 000000000..665d27f2e --- /dev/null +++ b/build_defs/host/profile-test.bzl @@ -0,0 +1,266 @@ +"""Analysis tests exercise provider rebinding, not native-host qualification.""" + +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") +load("@apple_support//xcode:xcode_config.bzl", "xcode_config") +load("@apple_support//xcode:xcode_version.bzl", "xcode_version") +load("@rules_cc//cc/private/toolchain:unix_cc_toolchain_config.bzl", unix_config = "cc_toolchain_config") +load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES") +load("@apple_support//crosstool:cc_toolchain_config.bzl", apple_config = "cc_toolchain_config") +load("@rules_cc//cc/toolchains:cc_toolchain.bzl", "cc_toolchain") +load("@rules_swift//swift:providers.bzl", "SwiftToolchainInfo") +load("@rules_swift//swift/toolchains/config:tool_config.bzl", "ToolConfigInfo") +load("@rules_swift//swift/toolchains/config:action_config.bzl", "ActionConfigInfo", "add_arg") +load("@rules_swift//swift/toolchains/config:compile_config.bzl", "compiler_plugin_search_path_configurator") +load("@rules_swift//swift/internal:actions.bzl", "compiler_plugin_directory_error", "run_toolchain_action") +load("@rules_swift//swift/internal:action_names.bzl", "SWIFT_ACTION_COMPILE", "SWIFT_ACTION_DERIVE_FILES", "SWIFT_ACTION_COMPILE_MODULE_INTERFACE", "SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT", "all_action_names", "all_compile_action_names", "compiler_plugin_action_names") +load("@rules_swift//swift/internal:developer_dirs.bzl", "swift_developer_lib_dir") +load(":swift-profile.bzl", "declared_swift_path", "declared_xcode_info") +load(":repositories.bzl", "apple_cc_compile_files", "apple_swift_test_runtime_files") +load(":app-tool-inputs.bzl", "apple_app_configuration_error") +load(":cc-profiles.bzl", "host_builtin_include_directories") + +_APPLE_SDKS = ["macosx", "iphoneos", "iphonesimulator"] +_USE_LIBTOOL_ON_MACOS = str(Label("@rules_cc//cc/toolchains/args/archiver_flags:use_libtool_on_macos")) + +def _archive_fixture_impl(_settings, attr): + return {_USE_LIBTOOL_ON_MACOS: False, "//command_line_option:xcode_version_config": str(attr.xcode_configuration)} + +_archive_fixture = transition(implementation = _archive_fixture_impl, inputs = [], outputs = [_USE_LIBTOOL_ON_MACOS, "//command_line_option:xcode_version_config"]) + +def _builtin_directories(sdk): + return ["toolchain/lib/clang/20/include", "sdk_" + sdk + "/usr/include", "sdk_" + sdk + "/System/Library/Frameworks", "toolchain/include/c++/v1"] + +def _plugin_arguments(source, directory, include_developer, action): + arguments = [] + actions = struct( + args = lambda: struct(add = lambda flag, value = None, format = None: arguments.append([flag, value])), + run = lambda **kwargs: None, + ) + fields = { + "tool_configs": {action: ToolConfigInfo(executable = source)}, + "action_configs": [ + ActionConfigInfo(actions = [action], configurators = [add_arg("-marker", "preserved")]), + ActionConfigInfo(actions = compiler_plugin_action_names(), configurators = [compiler_plugin_search_path_configurator("__BAZEL_XCODE_DEVELOPER_DIR__/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/host/plugins/testing")]), + ActionConfigInfo(actions = all_compile_action_names(), configurators = [compiler_plugin_search_path_configurator("__BAZEL_SWIFT_TOOLCHAIN_PATH__/usr/lib/swift/host/plugins/testing", developer_search_only = True)]), + ], + } + if directory != None: + fields["compiler_plugin_directory"] = directory + run_toolchain_action( + actions = actions, + action_name = action, + feature_configuration = None, + prerequisites = struct(include_dev_srch_paths = include_developer), + swift_toolchain = SwiftToolchainInfo(**fields), + toolchain_type = "fixture", + ) + return arguments + +def _profile_test(ctx): + env = analysistest.begin(ctx) + prefix = "external/selected_sdk/" + # Inspect the actual CcToolchainInfo expansion in a non-root package: bare + # execroot paths would be prefixed again by this toolchain's package path. + for sdk, compiler in zip(_APPLE_SDKS, ctx.attr.cc_profiles): + asserts.equals(env, [prefix + directory for directory in _builtin_directories(sdk)], compiler[cc_common.CcToolchainInfo].built_in_include_directories) + resource = "toolchain/lib/clang/20" + compiler_files = [ + "toolchain/bin/swiftc", "toolchain/include/swift/bridging", "toolchain/include/c++/v1/vector", + resource + "/include/stddef.h", resource + "/lib/darwin/libclang_rt.osx.a", resource + "/retained.swiftmodule", + "toolchain/lib/swift/host/libCompilerPlugin.dylib", "tools/clang", "tools/ld", + "toolchain/lib/swift/Foo.swiftmodule/Interop.h", "toolchain/lib/swift/Foo.swiftmodule/cache.pcm", + ] + ["sdk_" + sdk + "/System/Library/Frameworks/Foo.framework/" + suffix for sdk in _APPLE_SDKS for suffix in ["Headers/Foo.h", "Modules/module.modulemap", "Modules/cache.pcm"]] + swift_modules = [ + "toolchain/lib/swift/macosx/Foo.swiftmodule/arm64-apple-macos.swiftinterface", + "toolchain/lib/swift/macosx/Foo.swiftmodule/arm64-apple-macos.swiftdoc", + ] + ["sdk_" + sdk + "/System/Library/Frameworks/Foo.framework/Modules/arm64.swiftmodule" for sdk in _APPLE_SDKS] + asserts.equals(env, compiler_files, apple_cc_compile_files(compiler_files + swift_modules, resource)) + # Inspect stock archive expansion: native ar metadata and Apple libtool + # actions have distinct interfaces even when they expose the same AR path. + for index, compiler in enumerate(ctx.attr.archive_profiles): + toolchain = compiler[cc_common.CcToolchainInfo] + features = cc_common.configure_features(ctx = ctx, cc_toolchain = toolchain) + variables = cc_common.create_link_variables(cc_toolchain = toolchain, feature_configuration = features, output_file = "fixture.a", is_using_linker = False) + tool = cc_common.get_tool_for_action(feature_configuration = features, action_name = ACTION_NAMES.cpp_link_static_library) + flags = cc_common.get_memory_inefficient_command_line(feature_configuration = features, action_name = ACTION_NAMES.cpp_link_static_library, variables = variables) + expected_ar = "/".join([part for part in [compiler.label.workspace_root, compiler.label.package, "tools/ar"] if part]) + asserts.equals(env, expected_ar, toolchain.ar_executable) + asserts.equals(env, expected_ar if index == 0 else ctx.file.libtool.path, tool) + asserts.true(env, "fixture.a" in flags) + if index == 0: + asserts.true(env, "rcs" in flags) + asserts.false(env, "-static" in flags) + asserts.false(env, "-o" in flags) + else: + asserts.true(env, "-D" in flags) + asserts.true(env, "-static" in flags) + asserts.true(env, "-o" in flags) + if "-o" in flags: + asserts.equals(env, ["fixture.a"], flags[flags.index("-o") + 1:flags.index("-o") + 2]) + if index > 0: + for action, source in [(ACTION_NAMES.c_compile, "fixture.c"), (ACTION_NAMES.objc_compile, "fixture.m"), (ACTION_NAMES.cpp_compile, "fixture.cpp"), (ACTION_NAMES.objcpp_compile, "fixture.mm")]: + variables = cc_common.create_compile_variables(cc_toolchain = toolchain, feature_configuration = features, source_file = source, output_file = "fixture.o") + flags = cc_common.get_memory_inefficient_command_line(feature_configuration = features, action_name = action, variables = variables) + standards = [flag for flag in flags if flag.startswith("-std=")] + if index == 2 and (source.endswith(".cpp") or source.endswith(".mm")): + asserts.equals(env, "-std=c++20", standards[-1] if standards else None, source + " must use the configured C++20 dialect after toolchain defaults") + elif source.endswith(".mm"): + asserts.equals(env, ["-std=gnu++17"], standards, "an empty C++ profile preserves the upstream Objective-C++ default") + else: + asserts.equals(env, [], standards, "C++ profile flags must not reach C or Objective-C") + observed_xcode = "Xcode 26.5\nBuild version 17F42" + captured_sdks = {"macosx": "26.5", "iphoneos": "26.5", "iphonesimulator": "26.5"} + # Explicit stock Xcode configurations report UNKNOWN availability even + # when the selected version is installed locally. + configured = ctx.attr.xcode_configuration[apple_common.XcodeVersionConfig] + asserts.equals(env, "unknown", configured.availability()) + asserts.equals(env, None, apple_app_configuration_error(configured, observed_xcode, captured_sdks)) + asserts.equals(env, "Stock Apple actions must select the captured Xcode build", apple_app_configuration_error(configured, "Xcode 26.5\nBuild version 17F43", captured_sdks)) + asserts.equals(env, "Stock Apple actions must select the captured Xcode version", apple_app_configuration_error(configured, "Xcode 26.4\nBuild version 17F42", captured_sdks)) + asserts.equals(env, "Stock Apple actions must select the captured iphoneos SDK", apple_app_configuration_error(configured, observed_xcode, captured_sdks | {"iphoneos": "26.4"})) + remote = struct(xcode_version = configured.xcode_version, sdk_version_for_platform = configured.sdk_version_for_platform, execution_info = lambda: {"no-local": ""}) + asserts.equals(env, "The licensed application tools cannot use a remote-only Xcode configuration", apple_app_configuration_error(remote, observed_xcode, captured_sdks)) + asserts.equals(env, "Captured Xcode version/build observation is malformed", apple_app_configuration_error(configured, "Xcode 26.5", captured_sdks)) + runtime_prefix = "/selected/output-base/external/selected_sdk/" + implicit_flags = [ + "-L__BAZEL_XCODE_DEVELOPER_DIR__/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx", + "-F__BAZEL_XCODE_DEVELOPER_DIR__/Platforms/MacOSX.platform/Developer/Library/Frameworks", + "-Wl,-rpath,/var/db/xcode_select_link/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift-6.2/macosx", + "-L/usr/lib/swift", + ] + expected = [ + "-L" + prefix + "toolchain/lib/swift/macosx", + "-F" + prefix + "platform_macosx/Library/Frameworks", + "-Wl,-rpath," + prefix + "toolchain/lib/swift-6.2/macosx", + "-L/usr/lib/swift", + ] + info = CcInfo(linking_context = cc_common.create_linking_context(linker_inputs = depset([ + cc_common.create_linker_input(owner = ctx.label, user_link_flags = implicit_flags), + ]))) + test_linking = cc_common.create_linking_context(linker_inputs = depset([ + cc_common.create_linker_input(owner = ctx.label, user_link_flags = [ + "-Wl,-rpath,/private/var/select/developer_dir/Platforms/MacOSX.platform/Developer/Library/Frameworks", + "-Wl,-rpath,/var/db/xcode_select_link/Platforms/MacOSX.platform/Developer/Library/PrivateFrameworks", + "-Wl,-rpath,__BAZEL_XCODE_DEVELOPER_DIR__/Platforms/MacOSX.platform/Developer/usr/lib", + ]), + ])) + stock_env = {"XCODE_VERSION_OVERRIDE": "26.5.0.17f42", "APPLE_SDK_PLATFORM": "MacOSX", "APPLE_SDK_VERSION_OVERRIDE": "26.5"} + original = SwiftToolchainInfo( + action_configs = [], + developer_dirs = [struct(developer_path_label = "platform", path = "__BAZEL_XCODE_DEVELOPER_DIR__/Platforms/MacOSX.platform/Developer/Library/Frameworks")], + implicit_deps_providers = struct(cc_infos = [info], swift_infos = []), + test_configuration = struct(test_linking_contexts = [test_linking]), + tool_configs = {"compile": ToolConfigInfo(executable = "swiftc", env = stock_env)}, + ) + rebound = declared_xcode_info(original, {"swiftc": ctx.file.source}, struct( + files = struct(sdk = [ctx.file.source]), + attr = struct(prefix = prefix, runtime_prefix = runtime_prefix, sdkroot = prefix + "sdk_macosx", sdk_name = "macosx", resource_directory = prefix + "toolchain/lib/swift", target_triple = "arm64-apple-macosx14.0.0"), + )) + input = rebound.implicit_deps_providers.cc_infos[0].linking_context.linker_inputs.to_list()[0] + asserts.equals(env, expected, input.user_link_flags) + asserts.equals(env, [ctx.file.source], input.additional_inputs) + asserts.equals(env, prefix + "platform_macosx/Library/Frameworks", rebound.developer_dirs[0].path) + asserts.equals(env, prefix + "platform_macosx/usr/lib", swift_developer_lib_dir(rebound.developer_dirs)) + test_expected = [ + "-Wl,-rpath," + runtime_prefix + "platform_macosx/Library/Frameworks", + "-Wl,-rpath," + runtime_prefix + "platform_macosx/Library/PrivateFrameworks", + "-Wl,-rpath," + runtime_prefix + "platform_macosx/usr/lib", + ] + asserts.equals(env, test_expected, rebound.test_configuration.test_linking_contexts[0].linker_inputs.to_list()[0].user_link_flags) + compatibility_input = rebound.test_configuration.test_linking_contexts[1].linker_inputs.to_list()[0] + asserts.equals(env, ["-Wl,-rpath," + runtime_prefix + "toolchain/lib/swift-6.2/macosx"], compatibility_input.user_link_flags) + asserts.equals(env, [], compatibility_input.libraries) + framework = "platform_macosx/Library/Frameworks/XCTest.framework/" + private = "platform_macosx/Library/PrivateFrameworks/XCTAutomationSupport.framework/" + runtime_files = { + "platform_macosx/Library": [framework + "XCTest", framework + "Versions/A/XCTest", framework + "Resources/Info.plist", framework + "Versions/A/Resources/en.lproj/Messages.strings", private + "XCTAutomationSupport", private + "Resources/Helpers.bundle/Contents/MacOS/helper"], + "platform_macosx/usr/lib": ["platform_macosx/usr/lib/libTesting.dylib", "platform_macosx/usr/lib/swift/libTesting.dylib"], + "toolchain": ["toolchain/lib/swift/macosx/libswiftCore.dylib", "toolchain/lib/swift-6.2/macosx/libTesting.dylib", "toolchain/lib/swift/macosx/Testing.framework/Versions/A/Testing"], + } + compile_files = { + "platform_macosx/Library": [framework + "Headers/XCTest.h", framework + "Versions/A/Modules/module.modulemap", framework + "Modules/libCompileOnly.dylib", private + "PrivateHeaders/XCTAutomationSupport.h"], + "platform_macosx/usr/lib": ["platform_macosx/usr/lib/libTesting.tbd"], + "toolchain": ["toolchain/lib/swift/iphonesimulator/libswiftCore.dylib", "toolchain/lib/swift/host/libTestingMacros.dylib", "toolchain/lib/swift_static/macosx/libswiftCore.dylib", "toolchain/bin/swiftc", "toolchain/lib/swift/macosx/Testing.swiftmodule/arm64.swiftinterface"], + } + asserts.equals(env, sorted([source for sources in runtime_files.values() for source in sources]), apple_swift_test_runtime_files({component: runtime_files[component] + compile_files[component] for component in runtime_files})) + asserts.equals(env, ctx.file.source, rebound.tool_configs["compile"].executable) + asserts.equals(env, [ctx.file.source], rebound.tool_configs["compile"].additional_tools) + asserts.equals(env, stock_env, rebound.tool_configs["compile"].env) + asserts.equals(env, prefix + "toolchain/lib/swift/host/plugins/testing", rebound.compiler_plugin_directory) + asserts.equals(env, "1", rebound.tool_configs["compile"].execution_requirements["no-remote"]) + asserts.equals(env, prefix + "sdk_macosx/usr/include", declared_swift_path("__BAZEL_XCODE_SDKROOT__/usr/include", prefix)) + for sdk, platform in [("iphoneos", "iPhoneOS"), ("iphonesimulator", "iPhoneSimulator")]: + asserts.equals(env, prefix + "sdk_" + sdk + "/usr/include", declared_swift_path("__BAZEL_XCODE_SDKROOT__/usr/include", prefix, sdk)) + asserts.equals(env, "-F" + prefix + "platform_" + sdk + "/Library/Frameworks", declared_swift_path("-F__BAZEL_XCODE_DEVELOPER_DIR__/Platforms/" + platform + ".platform/Developer/Library/Frameworks", prefix, sdk)) + arguments = [] + recorder = struct(add = lambda flag, value, format = None: arguments.append([flag, value])) + for configure in rebound.action_configs[-1].configurators: + configure(None, recorder) + asserts.equals(env, [["-target", "arm64-apple-macosx14.0.0"], ["-sdk", prefix + "sdk_macosx"], ["-resource-dir", prefix + "toolchain/lib/swift"]], arguments) + legacy_xcode = ["-plugin-path", "__BAZEL_XCODE_DEVELOPER_DIR__/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/host/plugins/testing"] + legacy_toolchain = ["-plugin-path", "__BAZEL_SWIFT_TOOLCHAIN_PATH__/usr/lib/swift/host/plugins/testing"] + marker = ["-marker", "preserved"] + stock_plugin_actions = [SWIFT_ACTION_COMPILE, SWIFT_ACTION_DERIVE_FILES, SWIFT_ACTION_COMPILE_MODULE_INTERFACE, SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT] + asserts.equals(env, stock_plugin_actions, compiler_plugin_action_names()) + for action in all_action_names(): + for include_developer in [False, True]: + defaults = [marker] + ([legacy_xcode] if action in stock_plugin_actions else []) + ([legacy_toolchain] if include_developer and action in all_compile_action_names() else []) + asserts.equals(env, defaults, _plugin_arguments(ctx.file.source, None, include_developer, action)) + # The actual stock pipeline replaces both paths once, only for + # actions in their original scope; other driver modes get no flag. + captured = ([["-plugin-path", rebound.compiler_plugin_directory]] if action in stock_plugin_actions else []) + [marker] + asserts.equals(env, captured, _plugin_arguments(ctx.file.source, rebound.compiler_plugin_directory, include_developer, action)) + asserts.equals(env, None, compiler_plugin_directory_error(None)) + asserts.equals(env, None, compiler_plugin_directory_error(rebound.compiler_plugin_directory)) + for invalid in ["", 23, []]: + asserts.equals(env, "compiler_plugin_directory must be a non-empty directory path", compiler_plugin_directory_error(invalid)) + missing = prefix + "missing-plugins" + asserts.equals(env, [["-plugin-path", missing], marker], _plugin_arguments(ctx.file.source, missing, True, compiler_plugin_action_names()[0])) + return analysistest.end(env) + +_profile_rule_test = analysistest.make(_profile_test, fragments = ["cpp"], attrs = {"source": attr.label(default = ":sdk-smoke.c", allow_single_file = True), "libtool": attr.label(default = "@apple_support//crosstool:libtool.cc", allow_single_file = True), "cc_profiles": attr.label_list(providers = [cc_common.CcToolchainInfo]), "archive_profiles": attr.label_list(providers = [cc_common.CcToolchainInfo], cfg = _archive_fixture), "xcode_configuration": attr.label(providers = [apple_common.XcodeVersionConfig]), "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist")}) + +def profile_test(name, **kwargs): + """Exercise builtin path interpretation without acquiring a licensed SDK.""" + xcode_version(name = name + "_xcode_version", version = "26.5.0.17f42", default_macos_sdk_version = "26.5", default_ios_sdk_version = "26.5") + xcode_config(name = name + "_xcode_configuration", versions = [":" + name + "_xcode_version"], default = ":" + name + "_xcode_version") + profiles = [] + for sdk in _APPLE_SDKS + ["native_archive", "package_archive", "ios_cpp_archive"]: + profile = name + "_" + sdk + selected_sdk = "macosx" if sdk in ["native_archive", "package_archive"] else "iphonesimulator" if sdk == "ios_cpp_archive" else sdk + includes = host_builtin_include_directories("external/selected_sdk/", _builtin_directories(selected_sdk)) + if sdk in ["package_archive", "ios_cpp_archive"]: + apple_config( + name = profile + "_configuration", + cpu = "ios_sim_arm64" if sdk == "ios_cpp_archive" else "darwin_arm64", + wrapped_clang = ":sdk-smoke.c", + wrapped_clang_pp = ":sdk-smoke.c", + libtool = "@apple_support//crosstool:libtool.cc", + module_map = ":" + profile + "_files", + cxx_builtin_include_directories = includes, + cxx_flags = ["-std=c++20"] if sdk == "ios_cpp_archive" else [], + tool_paths_overrides = {"ar": "tools/ar"}, + testonly = True, + ) + else: + unix_config( + name = profile + "_configuration", + cpu = "darwin_arm64", + compiler = "clang", + host_system_name = "fixture", + target_system_name = "fixture", + target_libc = "macosx" if sdk == "native_archive" else "fixture", + abi_version = "fixture", + abi_libc_version = "fixture", + toolchain_identifier = profile, + cxx_builtin_include_directories = includes, + tool_paths = {tool: "/bin/false" for tool in ["ar", "cpp", "gcc", "gcov", "ld", "nm", "objdump", "strip"]} | ({"ar": "tools/ar"} if sdk == "native_archive" else {}), + testonly = True, + ) + native.filegroup(name = profile + "_files", srcs = [], testonly = True) + cc_toolchain(name = profile, toolchain_identifier = profile, toolchain_config = ":" + profile + "_configuration", + all_files = ":" + profile + "_files", ar_files = ":" + profile + "_files", as_files = ":" + profile + "_files", + compiler_files = ":" + profile + "_files", dwp_files = ":" + profile + "_files", linker_files = ":" + profile + "_files", + objcopy_files = ":" + profile + "_files", strip_files = ":" + profile + "_files", testonly = True) + profiles.append(":" + profile) + _profile_rule_test(name = name, target_under_test = profiles[0], cc_profiles = profiles[:3], archive_profiles = profiles[3:], xcode_configuration = ":" + name + "_xcode_configuration", **kwargs) diff --git a/build_defs/host/repositories.bzl b/build_defs/host/repositories.bzl new file mode 100644 index 000000000..a8abc609c --- /dev/null +++ b/build_defs/host/repositories.bzl @@ -0,0 +1,175 @@ +"""Lazy native-host SDK profiles; incompatible client hosts fail acquisition.""" + +load(":sdk-tree.bzl", "apple_sdk_documentation_directories", "watch_sdk_directory") + +def apple_cc_compile_files(files, resource_directory): + """C-family actions keep compiler resources, excluding Swift module formats.""" + return [source for source in files if source.startswith(resource_directory + "/") or not (source.endswith(".swiftmodule") or source.endswith(".swiftinterface") or source.endswith(".swiftdoc"))] + +def apple_swift_test_runtime_files(component_files): + """Keep runtime dylibs and framework resources, excluding compile inputs.""" + runtime = [] + for component in ["toolchain", "platform_macosx/Library", "platform_macosx/usr/lib"]: + for source in component_files[component]: + if component == "toolchain": + parts = source.split("/") + if len(parts) < 5 or parts[:2] != ["toolchain", "lib"] or not (parts[2] == "swift" or parts[2].startswith("swift-")) or parts[3] != "macosx": + continue + if ".framework/" in source and any([part in source for part in ["/Headers/", "/PrivateHeaders/", "/Modules/"]]): + continue + if source.endswith(".dylib") or ".framework/" in source: + runtime.append(source) + return sorted(runtime) + +def _host_sdk_impl(ctx): + expected_os = "mac os x" if ctx.attr.family == "apple" else "windows" + if not ctx.os.name.lower().startswith(expected_os): + fail("The %s SDK profile requires its native %s client host; no cross-host SDK acquisition is declared." % (ctx.attr.family, expected_os)) + for source in [ctx.attr.collector, ctx.attr.policy, ctx.attr.compatibility, ctx.attr.deployment_policy, ctx.attr._app_tools, ctx.attr._vc_runtime_contract, ctx.attr._vc_runtime_policy]: + ctx.read(source) + ctx.watch(ctx.path(ctx.attr.bun)) + result = ctx.execute([ctx.path(ctx.attr.bun), ctx.path(ctx.attr.collector), ctx.path(ctx.attr.policy), ctx.attr.family], timeout = 120, quiet = True) + if result.return_code: + fail("Cannot declare the selected host SDK: " + result.stderr) + sdk = json.decode(result.stdout) + if ctx.attr.family == "apple": + # Retain the pinned standard drivers' argument/response-file behavior, + # while executing the exact tools in this declared SDK projection. + for name, source in [("wrapped_clang.cc", ctx.attr._wrapped_clang), ("libtool.cc", ctx.attr._libtool)]: + ctx.file(name, ctx.read(source)) + ctx.read(ctx.attr._driver_patch) + ctx.patch(ctx.attr._driver_patch, strip = 1) + component_files = {} + for component in sdk["components"]: + source = ctx.path(component["path"]) + if component["directory"]: + # Perl manual names include colons, which cannot be Bazel labels. + # Manual pages are not clang/Swift tools, headers, modules, or libs. + excluded = apple_sdk_documentation_directories(component["name"]) if ctx.attr.family == "apple" else [] + component_files[component["name"]] = [component["name"] + "/" + relative for relative in watch_sdk_directory(ctx, source, excluded)] + else: + ctx.watch(source) + component_files[component["name"]] = [component["name"]] + ctx.symlink(source, component["name"]) + # Collector observations derive from these executable bytes independently + # of the SDK's directory membership and ordinary action-file digests. + if ctx.attr.family == "apple": + for tool in ["/usr/bin/xcodebuild", "/usr/bin/sw_vers"]: + ctx.watch(ctx.path(tool)) + for logical in sdk["tools"].values(): + matched = False + for component in sdk["components"]: + if logical == component["name"]: + ctx.watch(ctx.path(component["path"])) + matched = True + break + if component["directory"] and logical.startswith(component["name"] + "/"): + ctx.watch(ctx.path(component["path"]).get_child(logical[len(component["name"]) + 1:])) + matched = True + break + if not matched: + fail("The selected host SDK tool has no declared component: " + logical) + ctx.file("receipt.json", json.encode_indent(sdk)) + ctx.file("sdk.bzl", "HOST_SDK = " + repr(sdk) + "\n") + ctx.file("unsupported.bat", "@echo off\r\necho This operation is not supported by the declared host compiler profile. 1>&2\r\nexit /b 1\r\n", executable = True) + ctx.file("unsupported.sh", "#!/usr/bin/env bash\necho 'This operation is not supported by the declared host compiler profile.' >&2\nexit 1\n", executable = True) + lines = [ + 'load(%s, "host_cc_profiles")' % repr(str(ctx.attr.cc_profiles)), + 'load(":sdk.bzl", "HOST_SDK")', + 'package(default_visibility = ["//visibility:public"])', + 'exports_files(["receipt.json", "unsupported.bat", "unsupported.sh"])', + ] + for component in sdk["components"]: + # glob exclusions are applied after traversal and cannot stop SDK cycles. + sources = repr(component_files[component["name"]]) + lines.append("filegroup(name = %s, srcs = %s)" % (repr(component["name"] + "_files"), sources)) + if ctx.attr.family == "apple" and "compile" in component["roles"]: + compile_sources = apple_cc_compile_files(component_files[component["name"]], sdk["resourceDirectory"]) + lines.append("filegroup(name = %s, srcs = %s)" % (repr(component["name"] + "_compile_files"), repr(compile_sources))) + if ctx.attr.family == "msvc": + lines.append("exports_files(%s)" % repr([sdk["tools"]["dumpbin"], sdk["tools"]["rc"]])) + lines.append('filegroup(name = "runtime_dlls", srcs = %s)' % repr(sdk["runtimeDlls"])) + lines.append("host_cc_profiles(HOST_SDK)") + if ctx.attr.family == "apple": + lines.insert(0, 'load(%s, "declared_apple_app_tools")' % repr(str(ctx.attr.app_tools_profile))) + app_tools = [":receipt.json"] + [":" + sdk["tools"][name] + "_files" for name in ["actool", "ibtool", "codesign", "codesign_allocate", "ditto", "lipo", "swift-stdlib-tool", "simctl", "otool"]] + [":tools/xcrun_files"] + lines.append('declared_apple_app_tools(name = "app_tools", tools = %s, xcode_observation = %s, sdk_versions = %s)' % (repr(app_tools), repr(sdk["observations"]["xcode"]), repr({name: sdk["observations"][name + "_version"] for name in ["macosx", "iphoneos", "iphonesimulator"]}))) + lines.append('exports_files(%s)' % repr([sdk["tools"][name] for name in ["actool", "ibtool", "codesign", "codesign_allocate", "ditto", "lipo", "swift-stdlib-tool", "simctl"]])) + lines.append('filegroup(name = "swift_interop_headers", srcs = %s)' % repr([file for file in component_files["toolchain"] if file.startswith("toolchain/include/swift/")])) + lines.append('exports_files(["toolchain/include/swift/bridging"])') + lines.append("exports_files(%s)" % repr([sdk["tools"][name] for name in ["install_name_tool", "otool", "plutil"]])) + lines.insert(0, 'load(%s, "declared_xcode_swift_toolchain")' % repr(str(ctx.attr.swift_profile))) + prefix = "external/" + ctx.name + "/" + runtime_prefix = str(ctx.path(".")) + "/" + tools = {":" + sdk["tools"][mode]: mode for mode in ["swiftc", "swift-symbolgraph-extract", "swift-synthesize-interface"]} + lines.append('filegroup(name = "swift_test_runtime", srcs = %s)' % repr(["receipt.json"] + apple_swift_test_runtime_files(component_files))) + for name, selected_sdk, target_triple in [ + ("swift", "macosx", "arm64-apple-macosx" + sdk["deploymentTargets"]["package_macos"]), + ("swift_native", "macosx", "arm64-apple-macosx" + sdk["deploymentTargets"]["native_macos"]), + ("swift_ios", "iphoneos", "arm64-apple-ios" + sdk["deploymentTargets"]["ios"]), + ("swift_ios_simulator", "iphonesimulator", "arm64-apple-ios" + sdk["deploymentTargets"]["ios"] + "-simulator"), + ]: + inputs = [":receipt.json", ":toolchain_files", ":sdk_" + selected_sdk + "_files", ":platform_" + selected_sdk + "/Library_files", ":platform_" + selected_sdk + "/usr/lib_files", ":tools/xcrun_files"] + lines.append('declared_xcode_swift_toolchain(name = %s, sdk = %s, tools = %s, sdkroot = %s, sdk_name = %s, resource_directory = %s, prefix = %s, runtime_prefix = %s, target_triple = %s)' % (repr(name), repr(inputs), repr(tools), repr(prefix + "sdk_" + selected_sdk), repr(selected_sdk), repr(prefix + "toolchain/lib/swift"), repr(prefix), repr(runtime_prefix), repr(target_triple))) + ctx.file("BUILD.bazel", "\n".join(lines) + "\n") + return ctx.repo_metadata(reproducible = False) + +_host_sdk_repository = repository_rule( + implementation = _host_sdk_impl, + configure = True, + attrs = { + "family": attr.string(mandatory = True, values = ["apple", "msvc"]), + "bun": attr.label(default = Label("@bun_runtime//:bun"), allow_single_file = True), + "policy": attr.label(default = Label("//tools/dev:native-host-toolchains.json"), allow_single_file = True), + "compatibility": attr.label(default = Label("//tools/release:platform-compatibility-policy.mts"), allow_single_file = True), + "collector": attr.label(default = Label("//build_defs/host:host-sdk.mts"), allow_single_file = True), + "deployment_policy": attr.label(default = Label("//build_defs/host:deployment-policy.mts"), allow_single_file = True), + "cc_profiles": attr.label(default = Label("//build_defs/host:cc-profiles.bzl"), allow_single_file = True), + "swift_profile": attr.label(default = Label("//build_defs/host:swift-profile.bzl"), allow_single_file = True), + "app_tools_profile": attr.label(default = Label("//build_defs/host:app-tool-inputs.bzl"), allow_single_file = True), + "_vc_runtime_contract": attr.label(default = Label("//:tools/packaging/windows-vc-runtime-closure.mts"), allow_single_file = True), + "_vc_runtime_policy": attr.label(default = Label("//:tools/packaging/windows-vc-runtime-policy.json"), allow_single_file = True), + "_app_tools": attr.label(default = Label("//build_defs/host:apple-app-tools.mts"), allow_single_file = True), + "_wrapped_clang": attr.label(default = Label("@apple_support//crosstool:wrapped_clang.cc"), allow_single_file = True), + "_libtool": attr.label(default = Label("@apple_support//crosstool:libtool.cc"), allow_single_file = True), + "_driver_patch": attr.label(default = Label("//build_defs/host:declared-apple-drivers.patch"), allow_single_file = True), + }, + environ = ["DEVELOPER_DIR", "TOOLCHAINS", "VSCMD_VER", "VSCMD_ARG_HOST_ARCH", "VSCMD_ARG_TGT_ARCH", "VCToolsInstallDir", "VCToolsVersion", "VCToolsRedistDir", "WindowsSdkDir", "WindowsSDKVersion", "TEMP", "TMP", "ImageOS", "ImageVersion"], +) + +def _host_toolchains_impl(ctx): + lines = ['package(default_visibility = ["//visibility:public"])'] + for name, repository, compiler, os, cpu, extra, kind in [ + ("msvc_x64", "native_msvc_sdk", "cc_compiler", "windows", "x86_64", [], "@bazel_tools//tools/cpp:toolchain_type"), + ("apple_macos_package", "native_apple_sdk", "cc_package", "macos", "aarch64", [str(ctx.attr.apple_package)], "@bazel_tools//tools/cpp:toolchain_type"), + ("apple_macos_runtime", "native_apple_sdk", "cc_native", "macos", "aarch64", [], "@bazel_tools//tools/cpp:toolchain_type"), + ("apple_swift_package", "native_apple_sdk", "swift", "macos", "aarch64", [str(ctx.attr.apple_package)], str(ctx.attr.swift_type)), + ("apple_swift_runtime", "native_apple_sdk", "swift_native", "macos", "aarch64", [], str(ctx.attr.swift_type)), + ("apple_swift_ios", "native_apple_sdk", "swift_ios", "ios", "aarch64", [str(ctx.attr.apple_device)], str(ctx.attr.swift_type)), + ("apple_swift_ios_simulator", "native_apple_sdk", "swift_ios_simulator", "ios", "aarch64", [str(ctx.attr.apple_simulator)], str(ctx.attr.swift_type)), + ("apple_ios", "native_apple_sdk", "cc_ios", "ios", "aarch64", [str(ctx.attr.apple_device)], "@bazel_tools//tools/cpp:toolchain_type"), + ("apple_ios_simulator", "native_apple_sdk", "cc_ios_simulator", "ios", "aarch64", [str(ctx.attr.apple_simulator)], "@bazel_tools//tools/cpp:toolchain_type"), + ]: + constraints = ["@platforms//os:" + os, "@platforms//cpu:" + cpu] + execution = ["@platforms//os:macos", "@platforms//cpu:aarch64"] if os == "ios" else constraints + lines.append("toolchain(name = %s, toolchain = %s, toolchain_type = %s, exec_compatible_with = %s, target_compatible_with = %s)" % (repr(name), repr("@" + repository + "//:" + compiler), repr(kind), repr(execution), repr(constraints + extra))) + ctx.file("BUILD.bazel", "\n".join(lines) + "\n") + return ctx.repo_metadata(reproducible = True) + +_host_toolchains_repository = repository_rule( + implementation = _host_toolchains_impl, + attrs = { + "apple_package": attr.label(default = Label("//build_defs/host:apple_package")), + "swift_type": attr.label(default = Label("@rules_swift//toolchains:toolchain_type")), + "apple_device": attr.label(default = Label("@apple_support//constraints:device")), + "apple_simulator": attr.label(default = Label("@apple_support//constraints:simulator")), + }, +) + +def _native_host_toolchains_impl(ctx): + _host_sdk_repository(name = "native_apple_sdk", family = "apple") + _host_sdk_repository(name = "native_msvc_sdk", family = "msvc") + _host_toolchains_repository(name = "native_host_toolchains") + return ctx.extension_metadata(root_module_direct_deps = ["native_host_toolchains", "native_apple_sdk", "native_msvc_sdk"], root_module_direct_dev_deps = [], reproducible = True) + +native_host_toolchains = module_extension(implementation = _native_host_toolchains_impl) diff --git a/build_defs/host/rules-rust-declared-archiver.patch b/build_defs/host/rules-rust-declared-archiver.patch new file mode 100644 index 000000000..cea22e13b --- /dev/null +++ b/build_defs/host/rules-rust-declared-archiver.patch @@ -0,0 +1,9 @@ +diff --git a/cargo/private/cargo_build_script.bzl b/cargo/private/cargo_build_script.bzl +--- a/cargo/private/cargo_build_script.bzl ++++ b/cargo/private/cargo_build_script.bzl +@@ -551,3 +551,4 @@ + # one was never included in the unix_cc_toolchain_config. ++ # Apple archive actions use libtool flags; Cargo needs the ar interface. +- if not env["AR"]: ++ if not env["AR"] or "libtool" in paths.basename(env["AR"]): + env["AR"] = cc_toolchain.ar_executable diff --git a/build_defs/host/rules-rust-windows-dependency-paths.patch b/build_defs/host/rules-rust-windows-dependency-paths.patch new file mode 100644 index 000000000..db78faf54 --- /dev/null +++ b/build_defs/host/rules-rust-windows-dependency-paths.patch @@ -0,0 +1,134 @@ +diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl +--- a/rust/private/rustc.bzl ++++ b/rust/private/rustc.bzl +@@ -984,7 +984,8 @@ + require_explicit_unstable_features = False, + error_format = None, + allowed_unstable_rust_features = None, +- link_std_dylib = False): ++ link_std_dylib = False, ++ dependency_files = None): + """Builds an Args object containing common rustc flags + + Args: +@@ -1057,6 +1058,7 @@ + error_format (str, optional): Error format to pass to the `--error-format` command line argument. If set to None, uses the "_error_format" entry in `attr`. + allowed_unstable_rust_features (list, optional): List of unstable Rust language features allowed for this target. + link_std_dylib (bool): Whether to dynamically link the Rust standard library using `--prefer-dynamic`. ++ dependency_files (list[File], optional): Files providing the dependency search directories. + + Returns: + tuple: A tuple of the following items +@@ -1397,7 +1399,7 @@ + use_metadata = _depend_on_metadata(crate_info, force_depend_on_objects) + + # These always need to be added, even if not linking this crate. +- add_crate_link_flags(rustc_flags, dep_info, force_all_deps_direct, use_metadata) ++ add_crate_link_flags(rustc_flags, dep_info, force_all_deps_direct, use_metadata, dependency_files) + + needs_extern_proc_macro_flag = _is_proc_macro(crate_info) and crate_info.edition != "2015" + if needs_extern_proc_macro_flag: +@@ -1669,6 +1671,35 @@ + + return profiling_dir, profiling_flags + ++def _windows_dependency_files(ctx, toolchain, crate_info, dep_info): ++ """Consolidates static crate search paths on Windows compiler hosts.""" ++ if toolchain.exec_triple.system != "windows": ++ return None ++ ++ # https://github.com/bazelbuild/rules_rust/issues/3767: rustc extends PATH with -L directories. ++ # Remove after upgrading to upstream Windows dependency path consolidation that preserves configured artifacts. ++ use_metadata = _depend_on_metadata(crate_info, False) ++ dependency_files = [] ++ for index, crate in enumerate(dep_info.transitive_crates.to_list()): ++ artifact = crate.metadata if use_metadata else crate.output ++ if not artifact or (use_metadata and not crate.metadata_supports_pipelining): ++ artifact = crate.output ++ if artifact.extension in ("rlib", "rmeta"): ++ # Keep the crate prefix; the ordinal preserves same-basename configured artifacts. ++ stem = artifact.basename[:-len(artifact.extension) - 1] ++ alias = ctx.actions.declare_file("_rust_deps/{}/{}-{}.{}".format( ++ crate_info.output.basename, ++ stem, ++ index, ++ artifact.extension, ++ )) ++ ctx.actions.symlink(output = alias, target_file = artifact) ++ dependency_files.append(alias) ++ else: ++ # DLLs retain their original directories for native dependency lookup. ++ dependency_files.append(artifact) ++ return dependency_files ++ + def rustc_compile_action( + *, + ctx, +@@ -1781,6 +1812,10 @@ + stamp = stamp, + experimental_use_cc_common_link = experimental_use_cc_common_link, + ) ++ ++ dependency_files = _windows_dependency_files(ctx, toolchain, crate_info, dep_info) ++ if dependency_files != None: ++ compile_inputs = depset(dependency_files, transitive = [compile_inputs]) + + # The types of rustc outputs to emit. + # If we build metadata, we need to keep the command line of the two invocations +@@ -1880,6 +1915,7 @@ + require_explicit_unstable_features = require_explicit_unstable_features, + allowed_unstable_rust_features = allowed_unstable_rust_features, + link_std_dylib = link_std_dylib, ++ dependency_files = dependency_files, + ) + + args_metadata = None +@@ -1909,6 +1945,7 @@ + require_explicit_unstable_features = require_explicit_unstable_features, + allowed_unstable_rust_features = allowed_unstable_rust_features, + link_std_dylib = link_std_dylib, ++ dependency_files = dependency_files, + ) + + env = dict(ctx.configuration.default_shell_env) +@@ -2706,7 +2743,7 @@ + dirs[f.dirname] = None + return dirs.keys() + +-def add_crate_link_flags(args, dep_info, force_all_deps_direct = False, use_metadata = False): ++def add_crate_link_flags(args, dep_info, force_all_deps_direct = False, use_metadata = False, dependency_files = None): + """Adds link flags to an Args object reference + + Args: +@@ -2715,6 +2752,7 @@ + force_all_deps_direct (bool, optional): Whether to pass the transitive rlibs with --extern + to the commandline as opposed to -L. + use_metadata (bool, optional): Build command line arguments using metadata for crates that provide it. ++ dependency_files (list[File], optional): Files providing the dependency search directories. + """ + + direct_crates = depset( +@@ -2728,7 +2766,7 @@ + args.add_all(direct_crates, uniquify = True, map_each = crate_to_link_flags) + + args.add_all( +- dep_info.transitive_crates, ++ dep_info.transitive_crates if dependency_files == None else dependency_files, + map_each = _get_crate_dirname, + uniquify = True, + format_each = "-Ldependency=%s", +@@ -2780,12 +2818,12 @@ + """A helper macro used by `add_crate_link_flags` for getting the directory name of the current crate's output path + + Args: +- crate (CrateInfo): A CrateInfo provider from the current rule ++ crate (CrateInfo|File): A crate provider or dependency artifact from the current rule + + Returns: + str: The directory name of the the output File that will be produced. + """ +- return crate.output.dirname ++ return getattr(crate, "output", crate).dirname + + def portable_link_flags( + lib, diff --git a/build_defs/host/rules-swift-declared-plugin-directory.patch b/build_defs/host/rules-swift-declared-plugin-directory.patch new file mode 100644 index 000000000..cbfa41a0d --- /dev/null +++ b/build_defs/host/rules-swift-declared-plugin-directory.patch @@ -0,0 +1,124 @@ +diff --git a/swift/providers.bzl b/swift/providers.bzl +--- a/swift/providers.bzl ++++ b/swift/providers.bzl +@@ -316,4 +316,8 @@ + This field is an internal implementation detail of the build rules. + """, ++ "compiler_plugin_directory": """\ ++Optional directory for compiler plugins. When set, it replaces the Xcode and ++developer-search plugin directories in compile action configuration. ++""", + "cc_language": """\ + The `language` that should be passed to `cc_common` APIs that take it as an +diff --git a/swift/internal/actions.bzl b/swift/internal/actions.bzl +--- a/swift/internal/actions.bzl ++++ b/swift/internal/actions.bzl +@@ -18,4 +18,12 @@ + load("//swift/toolchains/config:action_config.bzl", "ConfigResultInfo") + load(":features.bzl", "are_all_features_enabled", "gather_toolchains") ++load(":utils.bzl", "struct_fields") ++load(":action_names.bzl", "compiler_plugin_action_names") ++ ++def compiler_plugin_directory_error(directory): ++ """Returns the error for an invalid optional compiler-plugin directory.""" ++ if directory != None and (type(directory) != "string" or not directory): ++ return "compiler_plugin_directory must be a non-empty directory path" ++ return None + + def _apply_action_configs( +@@ -41,4 +49,11 @@ + inputs of the action, as determined by the configurators. + """ ++ compiler_plugin_directory = getattr(swift_toolchain, "compiler_plugin_directory", None) ++ error = compiler_plugin_directory_error(compiler_plugin_directory) ++ if error: ++ fail(error) ++ if compiler_plugin_directory != None and action_name in compiler_plugin_action_names(): ++ args.add("-plugin-path", compiler_plugin_directory) ++ prerequisites = struct(**(struct_fields(prerequisites) | {"compiler_plugin_directory": compiler_plugin_directory})) + additional_tools = [] + inputs = [] +diff --git a/swift/toolchains/config/compile_config.bzl b/swift/toolchains/config/compile_config.bzl +--- a/swift/toolchains/config/compile_config.bzl ++++ b/swift/toolchains/config/compile_config.bzl +@@ -1023,5 +1023,8 @@ + ActionConfigInfo( + actions = all_compile_action_names(), +- configurators = [_plugin_search_paths_configurator], ++ configurators = [compiler_plugin_search_path_configurator( ++ "__BAZEL_SWIFT_TOOLCHAIN_PATH__/usr/lib/swift/host/plugins/testing", ++ developer_search_only = True, ++ )], + ), + +@@ -2377,11 +2380,19 @@ + ) + +-def _plugin_search_paths_configurator(prerequisites, args): +- """Adds plugin search paths to the command line.""" +- if prerequisites.include_dev_srch_paths: +- args.add( +- "-plugin-path", +- "__BAZEL_SWIFT_TOOLCHAIN_PATH__/usr/lib/swift/host/plugins/testing", +- ) ++def compiler_plugin_search_path_configurator(default_directory, developer_search_only = False): ++ """Adds the default plugin path unless the toolchain supplies its own.""" ++ return lambda prerequisites, args: _add_compiler_plugin_search_path( ++ prerequisites, ++ args, ++ default_directory, ++ developer_search_only, ++ ) ++ ++def _add_compiler_plugin_search_path(prerequisites, args, default_directory, developer_search_only): ++ if getattr(prerequisites, "compiler_plugin_directory", None) != None: ++ return ++ if developer_search_only and not prerequisites.include_dev_srch_paths: ++ return ++ args.add("-plugin-path", default_directory) + + def _cross_import_overlays_configurator(prerequisites, args): +diff --git a/swift/toolchains/xcode_swift_toolchain.bzl b/swift/toolchains/xcode_swift_toolchain.bzl +--- a/swift/toolchains/xcode_swift_toolchain.bzl ++++ b/swift/toolchains/xcode_swift_toolchain.bzl +@@ -44,4 +44,5 @@ + "SWIFT_ACTION_SYNTHESIZE_INTERFACE", + "all_compile_action_names", ++ "compiler_plugin_action_names", + ) + load("//swift/internal:attrs.bzl", "swift_toolchain_driver_attrs") +@@ -101,4 +102,5 @@ + "command_line_objc_copts", + "compile_action_configs", ++ "compiler_plugin_search_path_configurator", + ) + load( +@@ -596,11 +598,7 @@ + action_configs.append( + ActionConfigInfo( +- actions = all_compile_action_names() + [ +- SWIFT_ACTION_COMPILE_MODULE_INTERFACE, +- SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT, +- ], ++ actions = compiler_plugin_action_names(), + configurators = [ +- add_arg( +- "-plugin-path", ++ compiler_plugin_search_path_configurator( + "{resource_dir}/host/plugins/testing".format( + resource_dir = _resource_dir_path(apple_toolchain), +diff --git a/swift/internal/action_names.bzl b/swift/internal/action_names.bzl +--- a/swift/internal/action_names.bzl ++++ b/swift/internal/action_names.bzl +@@ -64,4 +64,11 @@ + ) + ++def compiler_plugin_action_names(): ++ """Returns the Xcode actions that search for Swift compiler plugins.""" ++ return all_compile_action_names() + [ ++ SWIFT_ACTION_COMPILE_MODULE_INTERFACE, ++ SWIFT_ACTION_SYMBOL_GRAPH_EXTRACT, ++ ] ++ + def all_compile_action_names(): + """Returns all actions that compile source files.""" diff --git a/build_defs/host/rust-dependency-paths-fixture.rs b/build_defs/host/rust-dependency-paths-fixture.rs new file mode 100644 index 000000000..ace84d377 --- /dev/null +++ b/build_defs/host/rust-dependency-paths-fixture.rs @@ -0,0 +1 @@ +pub fn fixture() {} diff --git a/build_defs/host/rust-dependency-paths-test.bzl b/build_defs/host/rust-dependency-paths-test.bzl new file mode 100644 index 000000000..a48100546 --- /dev/null +++ b/build_defs/host/rust-dependency-paths-test.bzl @@ -0,0 +1,131 @@ +"""Exercise real Rust compile actions without executing a foreign compiler.""" + +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") +load("@rules_rust//rust:defs.bzl", "rust_common") +load("@rules_rust//rust/platform:triple.bzl", "triple") + +# buildifier: disable=bzl-visibility +load("@rules_rust//rust/private:rustc.bzl", "rustc_compile_action") + +_FixtureInfo = provider(fields = ["archives", "metadata", "dll", "uses_metadata"]) +_DEPENDENCIES = 400 + +def _fixture_impl(ctx): + real_toolchain = ctx.toolchains["@rules_rust//rust:toolchain_type"] + fields = {name: getattr(real_toolchain, name) for name in dir(real_toolchain)} + fields["exec_triple"] = triple("x86_64-pc-windows-msvc" if ctx.attr.windows_host else "x86_64-unknown-linux-gnu") + # A Windows target on a Linux compiler host must keep the ordinary search paths. + if not ctx.attr.windows_host: + fields["target_os"] = "windows" + toolchain = struct(**fields) + + empty_dep_info = rust_common.dep_info(**{ + name: depset([]) + for name in [ + "direct_crates", "transitive_crates", "transitive_data", "transitive_proc_macro_data", + "transitive_noncrates", "transitive_crate_outputs", "transitive_metadata_outputs", + "transitive_build_infos", "link_search_path_files", + ] + } | {"dep_env": None}) + archives, metadata, deps = [], [], [] + for index in range(_DEPENDENCIES): + directory = ctx.label.name + "/search/" + str(index) + "/" + "long_dependency_directory_" * 4 + # Identical names in different directories model configured crate variants. + stem = "libcollision-123" if index < 2 else "libdep_" + str(index) + "-123" + archive = ctx.actions.declare_file(directory + "/" + stem + ".rlib") + meta = ctx.actions.declare_file(directory + "/" + stem + ".rmeta") + ctx.actions.write(archive, "archive " + str(index)) + ctx.actions.write(meta, "metadata " + str(index)) + archives.append(archive) + metadata.append(meta) + crate = rust_common.create_crate_info( + name = "dep_" + str(index), type = "rlib", output = archive, + metadata = meta, metadata_supports_pipelining = index != 2, + owner = ctx.label, rustc_env_files = (), + ) + deps.append(rust_common.dep_variant_info(crate_info = crate, dep_info = empty_dep_info, cc_info = None, build_info = None)) + + dll = ctx.actions.declare_file(ctx.label.name + "/macro/fixture_macro.dll") + ctx.actions.write(dll, "proc-macro fixture") + macro = rust_common.create_crate_info(name = "fixture_macro", type = "proc-macro", output = dll, owner = ctx.label, rustc_env_files = ()) + output = ctx.actions.declare_file("lib" + ctx.label.name + (".rlib" if ctx.attr.kind == "rlib" else ".so")) + uses_metadata = ctx.attr.kind == "rlib" + providers = rustc_compile_action( + ctx = ctx, attr = ctx.attr, toolchain = toolchain, + crate_info_dict = dict( + name = ctx.label.name, type = ctx.attr.kind, root = ctx.file.source, srcs = [ctx.file.source], + deps = deps, + proc_macro_deps = [rust_common.dep_variant_info(crate_info = macro, dep_info = empty_dep_info, cc_info = None, build_info = None)], + aliases = {}, output = output, + metadata = ctx.actions.declare_file("lib" + ctx.label.name + ".rmeta") if uses_metadata else None, + metadata_supports_pipelining = uses_metadata, + owner = ctx.label, edition = "2021", is_test = False, + compile_data = depset([]), compile_data_targets = depset([]), rustc_env = {}, + ), + ) + return providers + [_FixtureInfo(archives = archives, metadata = metadata, dll = dll, uses_metadata = uses_metadata)] + +_fixture = rule( + implementation = _fixture_impl, + attrs = { + "windows_host": attr.bool(default = True), + "kind": attr.string(default = "rlib"), + "source": attr.label(default = ":rust-dependency-paths-fixture.rs", allow_single_file = True), + "_always_enable_metadata_output_groups": attr.label(default = "@rules_rust//rust/settings:always_enable_metadata_output_groups"), + "_error_format": attr.label(default = "@rules_rust//rust/settings:error_format"), + "_process_wrapper": attr.label(default = "@rules_rust//util/process_wrapper", executable = True, cfg = "exec"), + }, + toolchains = ["@rules_rust//rust:toolchain_type", config_common.toolchain_type("@bazel_tools//tools/cpp:toolchain_type", mandatory = False)], + fragments = ["cpp"], +) + +def _paths_impl(ctx): + env = analysistest.begin(ctx) + target = analysistest.target_under_test(env) + fixture = target[_FixtureInfo] + original_dirs = [file.dirname for file in fixture.archives] + [fixture.dll.dirname] + asserts.true(env, len(";".join(original_dirs)) > 32767, "fixture must exceed the Windows PATH limit") + actions = analysistest.target_actions(env) + aliases = [action for action in actions if action.mnemonic == "Symlink" and "/_rust_deps/" in action.outputs.to_list()[0].path] + rust_actions = [action for action in actions if action.mnemonic in ["Rustc", "RustcMetadata"]] + asserts.equals(env, 2 if fixture.uses_metadata else 1, len(rust_actions)) + expected = [meta if fixture.uses_metadata and index != 2 else fixture.archives[index] for index, meta in enumerate(fixture.metadata)] + if ctx.attr.consolidated: + asserts.equals(env, _DEPENDENCIES, len(aliases)) + alias_files = [action.outputs.to_list()[0] for action in aliases] + asserts.equals(env, _DEPENDENCIES, len({file.basename: True for file in alias_files}), "same-basename crate variants must survive") + asserts.equals(env, sorted([file.path for file in expected]), sorted([action.inputs.to_list()[0].path for action in aliases])) + expected_dirs = {file.dirname: True for file in alias_files} | {fixture.dll.dirname: True} + asserts.equals(env, 2, len(expected_dirs)) + asserts.true(env, len(";".join(expected_dirs.keys())) < 32767) + else: + asserts.equals(env, 0, len(aliases), "a Windows target alone must not consolidate compiler search paths") + alias_files = [] + expected_dirs = {directory: True for directory in original_dirs} + + for action in rust_actions: + actual_dirs = [arg.removeprefix("-Ldependency=") for arg in action.argv if arg.startswith("-Ldependency=")] + asserts.equals(env, sorted(expected_dirs.keys()), sorted(actual_dirs)) + inputs = action.inputs.to_list() + for file in alias_files + [fixture.dll]: + asserts.true(env, file in inputs, "search artifacts must be declared Rust inputs: " + file.path) + asserts.true(env, "--extern=dep_0=" + expected[0].path in action.argv, "direct dependency identities must remain unchanged") + asserts.true(env, "--extern=fixture_macro=" + fixture.dll.path in action.argv) + if fixture.uses_metadata: + asserts.false(env, fixture.archives[0] in inputs, "metadata consumers must not wait for full archives") + asserts.true(env, fixture.archives[2] in inputs, "non-pipelined dependencies still require full archives") + return analysistest.end(env) + +_paths_test = analysistest.make(_paths_impl, attrs = {"consolidated": attr.bool(default = True)}) + +def rust_dependency_paths_tests(): + tests = [] + for name, kind, windows_host in [ + ("windows_rust_metadata_paths", "rlib", True), + ("windows_rust_link_paths", "cdylib", True), + ("nonwindows_rust_paths", "rlib", False), + ]: + _fixture(name = name + "_fixture", kind = kind, windows_host = windows_host, tags = ["manual"]) + _paths_test(name = name + "_test", target_under_test = ":" + name + "_fixture", consolidated = windows_host, size = "small") + tests.append(":" + name + "_test") + native.test_suite(name = "rust_dependency_paths_tests", tests = tests) diff --git a/build_defs/host/sdk-smoke.c b/build_defs/host/sdk-smoke.c new file mode 100644 index 000000000..c1ebfb775 --- /dev/null +++ b/build_defs/host/sdk-smoke.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include +#if defined(_WIN32) +#include +#else +#include +#endif + +int main(void) { + assert(sizeof(void *) == 8); + uint64_t *number = malloc(sizeof(*number)); + assert(number != NULL); + *number = UINT64_C(0x1234567890abcdef); + assert(*number == UINT64_C(0x1234567890abcdef)); + free(number); +#if defined(_WIN32) + assert(GetCurrentProcessId() != 0); +#else + assert(getpid() > 0); +#endif + puts("native SDK compile, link and execution passed"); + return 0; +} diff --git a/build_defs/host/sdk-smoke.sh b/build_defs/host/sdk-smoke.sh new file mode 100755 index 000000000..fba8b0ce9 --- /dev/null +++ b/build_defs/host/sdk-smoke.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -euo pipefail +exec "$1" diff --git a/build_defs/host/sdk-smoke.swift b/build_defs/host/sdk-smoke.swift new file mode 100644 index 000000000..1456c9531 --- /dev/null +++ b/build_defs/host/sdk-smoke.swift @@ -0,0 +1,11 @@ +import Foundation + +@main +enum SDKSmoke { + static func main() { + let value = UUID(uuidString: "12345678-1234-5678-9abc-123456789abc")! + precondition(value.uuidString.lowercased() == "12345678-1234-5678-9abc-123456789abc") + precondition(URL(fileURLWithPath: "/native/sdk").lastPathComponent == "sdk") + print("Swift SDK compile, link and execution passed") + } +} diff --git a/build_defs/host/sdk-tree-conformance.mts b/build_defs/host/sdk-tree-conformance.mts new file mode 100644 index 000000000..b37c0c192 --- /dev/null +++ b/build_defs/host/sdk-tree-conformance.mts @@ -0,0 +1,321 @@ +/** + * Actual pinned-Bazel SDK input regressions; no SDK or compiler required. + * The selected SDK topology stays fixed during qualification. These regressions + * exercise observable names, types, and bytes; Bazel 8.8 does not record a + * directory symlink's canonical identity when those observations all match. + */ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { + copyFileSync, + mkdirSync, + mkdtempSync, + readFileSync, + renameSync, + rmSync, + statSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; + +const [binary] = process.argv.slice(2); +assert.ok(binary && path.isAbsolute(binary), 'pass the absolute pinned Bazel executable'); +const sourceRoot = process.env.BUILD_WORKSPACE_DIRECTORY ?? path.resolve(import.meta.dir, '../..'); +const version = readFileSync(path.join(sourceRoot, '.bazelversion'), 'utf8').trim(); +const scratch = mkdtempSync(path.join(tmpdir(), 'oliphaunt-sdk-tree-')); +const workspace = path.join(scratch, 'workspace'); +const output = path.join(scratch, 'output'); +const sdk = path.join(scratch, 'sdk'); +const alias = path.join(scratch, 'selected-sdk'); +const records: string[] = []; + +function file(relative: string, content: string, root = sdk) { + const target = path.join(root, relative); + mkdirSync(path.dirname(target), { recursive: true }); + writeFileSync(target, content); +} +function link(relative: string, target: string, root = sdk) { + const destination = path.join(root, relative); + rmSync(destination, { force: true }); + symlinkSync(target, destination); +} +function runBuild(outputBase: string, inventory = false) { + return spawnSync( + binary, + [ + '--batch', + '--nosystem_rc', + '--nohome_rc', + `--output_base=${outputBase}`, + '--host_jvm_args=-Xmx512m', + 'build', + inventory ? '//:inventory_sdk' : '//:read_sdk', + '--noshow_progress', + '--lockfile_mode=off', + '--incompatible_autoload_externally=', + '--host_platform=//:host', + '--platforms=//:host', + `--execution_log_json_file=${path.join(workspace, 'execution.json')}`, + ], + { cwd: workspace, encoding: 'utf8', timeout: 60_000 }, + ); +} +function build(outputBase = output, inventory = false) { + const result = runBuild(outputBase, inventory); + assert.equal(result.error, undefined, String(result.error)); + assert.equal(result.status, 0, result.stderr); + const repository = path.join(outputBase, 'external', '+_repo_rules+sdk'); + const rows = readFileSync( + path.join(workspace, 'bazel-bin', inventory ? 'inventory_sdk.txt' : 'read_sdk.txt'), + 'utf8', + ).replace(/\n$/u, ''); + const prefix = 'external/+_repo_rules+sdk/sdk/'; + const files = Object.fromEntries( + rows + ? rows.split('\n').map((row) => { + const separator = row.indexOf('\t'); + assert.ok(separator >= 0 && row.startsWith(prefix), `unexpected action output: ${row}`); + return [row.slice(prefix.length, separator), row.slice(separator + 1)]; + }) + : [], + ); + return { + files, + modified: statSync(path.join(repository, 'BUILD.bazel')).mtimeMs, + executed: readFileSync(path.join(workspace, 'execution.json'), 'utf8').includes('SdkRead'), + watchInputs: readFileSync(path.join(outputBase, 'external', '@+_repo_rules+sdk.marker'), 'utf8') + .split('\n') + .filter((row) => /^(FILE|DIRENTS|DIRTREE):/u.test(row)), + }; +} +function check(name: string, verify: (files: Record) => void) { + console.log(JSON.stringify({ scenario: name })); + const { files } = build(); + verify(files); + records.push(name); +} + +try { + mkdirSync(workspace, { recursive: true }); + const identity = spawnSync( + binary, + ['--batch', '--host_jvm_args=-Xmx512m', 'version', '--gnu_format'], + { + cwd: workspace, + encoding: 'utf8', + timeout: 60_000, + }, + ); + assert.equal(identity.status, 0, identity.stderr); + assert.ok(identity.stdout.includes(`bazel ${version}`), 'Bazel must match the repository pin'); + copyFileSync(path.join(import.meta.dir, 'sdk-tree.bzl'), path.join(workspace, 'sdk-tree.bzl')); + writeFileSync( + path.join(workspace, 'BUILD.bazel'), + 'load(":read-sdk.bzl", "read_sdk")\nplatform(name="host")\nread_sdk(name="read_sdk", srcs=["@sdk//:all"])\nread_sdk(name="inventory_sdk", srcs=["@sdk//:all"], inventory=True)\nexports_files(["sdk-tree.bzl"])\n', + ); + writeFileSync( + path.join(workspace, 'read-sdk.bzl'), + `def _impl(ctx): + output = ctx.actions.declare_file(ctx.label.name + ".txt") + inputs = ctx.files.srcs + read = "" if ctx.attr.inventory else 'cat "$source"; ' + ctx.actions.run_shell(inputs = inputs, outputs = [output], arguments = [output.path] + [source.path for source in inputs], command = 'set -eu; output="$1"; shift; for source in "$@"; do printf "%s\\\\t" "$source"; ' + read + 'printf "\\\\n"; done > "$output"', mnemonic = "SdkRead") + return [DefaultInfo(files = depset([output]))] +read_sdk = rule(implementation = _impl, attrs = {"srcs": attr.label_list(allow_files = True), "inventory": attr.bool()}) +`, + ); + writeFileSync( + path.join(workspace, 'MODULE.bazel'), + `module(name = "sdk_tree_probe")\nsdk = use_repo_rule("//:sdk.bzl", "sdk_repo")\nsdk(name = "sdk", path = ${JSON.stringify(alias)})\n`, + ); + writeFileSync( + path.join(workspace, 'sdk.bzl'), + `load(":sdk-tree.bzl", "apple_sdk_documentation_directories", "watch_sdk_directory") +def _impl(ctx): + root = ctx.path(ctx.attr.path) + files = watch_sdk_directory(ctx, root, apple_sdk_documentation_directories("sdk_macosx")) + ctx.symlink(root, "sdk") + ctx.file("BUILD.bazel", 'filegroup(name="all", srcs=' + repr(["sdk/" + relative for relative in files]) + ', visibility=["//visibility:public"])') +sdk_repo = repository_rule(implementation = _impl, attrs = {"path": attr.string()}) +`, + ); + for (const [version, content] of [ + ['2.6', 'first'], + ['2.7', 'second'], + ]) { + file(`Framework/Versions/${version}/Headers/ruby.h`, content); + link(`Framework/Versions/${version}/Headers/ruby`, '.'); + } + link('Framework/Versions/Current', '2.6'); + link('Framework/Headers', 'Versions/Current/Headers'); + file('Ordinary/A/header.h', 'same'); + file('Ordinary/B/header.h', 'same'); + mkdirSync(path.join(sdk, 'Ordinary/A/nested'), { recursive: true }); + file('Ordinary/B/nested/extra.h', 'extra'); + link('ordinary-alias', 'Ordinary/A'); + link('file-alias.h', 'Framework/Headers/ruby.h'); + link('dangling.h', path.join(scratch, 'missing.h')); + file('type-switch', 'file'); + file('usr/share/man/man3/APR::Base64.3pm', 'manual'); + file('usr/include/api.h', 'sysroot-header'); + file('usr/lib/libSystem.tbd', 'sysroot-library'); + symlinkSync(sdk, alias); + check( + 'colon manual-page documentation is excluded while sysroot inputs remain declared', + (files) => { + assert.equal(files['usr/include/api.h'], 'sysroot-header'); + assert.equal(files['usr/lib/libSystem.tbd'], 'sysroot-library'); + assert.ok(!Object.keys(files).some((name) => name.startsWith('usr/share/man/'))); + }, + ); + check('recursive SDK alias is finite; physical headers and framework aliases remain', (files) => { + assert.equal(files['Framework/Versions/2.6/Headers/ruby.h'], 'first'); + assert.equal(files['Framework/Versions/2.7/Headers/ruby.h'], 'second'); + assert.equal(files['Framework/Versions/Current/Headers/ruby.h'], 'first'); + assert.equal(files['Framework/Headers/ruby.h'], 'first'); + assert.equal(files['file-alias.h'], 'first'); + assert.ok(!Object.keys(files).some((name) => name.includes('/ruby/'))); + }); + rmSync(path.join(sdk, 'type-switch')); + file('type-switch/inside.h', 'directory'); + check('same-name file becomes a directory with declared child inputs', (files) => { + assert.ok(!('type-switch' in files)); + assert.equal(files['type-switch/inside.h'], 'directory'); + }); + const warm = build(); + assert.equal(warm.executed, false, 'unchanged SDK must reuse the action cache'); + const unchanged = build(); + assert.equal(unchanged.modified, warm.modified, 'unchanged SDK must reuse repository'); + assert.equal(unchanged.executed, false, 'unchanged SDK must reuse the action cache'); + records.push('warm unchanged repository and action reuse'); + file('usr/share/man/man3/New::Manual.3pm', 'new-manual'); + file('usr/share/man/man3/APR::Base64.3pm', 'changed-manual'); + const manuals = build(); + assert.equal(manuals.executed, false, 'manual bytes and membership are not compiler inputs'); + assert.ok(!Object.keys(manuals.files).some((name) => name.startsWith('usr/share/man/'))); + records.push('manual-page edits do not alter the declared compiler action'); + file('usr/include/api.h', 'changed-sysroot-header'); + check('sysroot header content remains a declared action input', (files) => + assert.equal(files['usr/include/api.h'], 'changed-sysroot-header'), + ); + link('ordinary-alias', 'Ordinary/B'); + check( + 'directory alias retarget declares existing target additions without byte edits', + (files) => { + assert.equal(files['ordinary-alias/header.h'], 'same'); + assert.equal(files['ordinary-alias/nested/extra.h'], 'extra'); + }, + ); + link('ordinary-alias', 'Ordinary/A'); + check('directory alias retarget removes existing target members without byte edits', (files) => { + assert.equal(files['ordinary-alias/header.h'], 'same'); + assert.ok(!('ordinary-alias/nested/extra.h' in files)); + }); + file('Framework/Versions/2.6/Headers/ruby.h', 'changed'); + check('existing file contents invalidate the declared input action', (files) => + assert.equal(files['Framework/Headers/ruby.h'], 'changed'), + ); + file('extra header.h', 'new'); + check('file addition invalidates', (files) => assert.equal(files['extra header.h'], 'new')); + renameSync(path.join(sdk, 'extra header.h'), path.join(sdk, 'renamed header.h')); + check('file rename invalidates', (files) => { + assert.equal(files['renamed header.h'], 'new'); + assert.ok(!('extra header.h' in files)); + }); + rmSync(path.join(sdk, 'renamed header.h')); + check('file deletion invalidates', (files) => assert.ok(!('renamed header.h' in files))); + link('Framework/Versions/Current', '2.7'); + check('directory alias retarget updates action bytes with identical entry names', (files) => + assert.equal(files['Framework/Headers/ruby.h'], 'second'), + ); + link('file-alias.h', 'Framework/Versions/2.6/Headers/ruby.h'); + check('file alias retarget invalidates', (files) => + assert.equal(files['file-alias.h'], 'changed'), + ); + link('Framework/Versions/2.6/Headers/ruby', '../../2.7/Headers'); + check('cycle alias retarget observes newly reachable files', (files) => + assert.equal(files['Framework/Versions/2.6/Headers/ruby/ruby.h'], 'second'), + ); + file('missing.h', 'appeared', scratch); + check('dangling alias becomes a declared file', (files) => + assert.equal(files['dangling.h'], 'appeared'), + ); + const alternate = path.join(scratch, 'alternate-sdk'); + file('alternate.h', 'different', alternate); + rmSync(alias); + symlinkSync(alternate, alias); + // Bazel 8's recorded directory-listing watcher cannot transparently refetch + // after a previously watched directory disappears. It must fail closed; + // reacquiring into a fresh output base observes the newly selected SDK. + const replaced = runBuild(output); + assert.equal(replaced.error, undefined, String(replaced.error)); + assert.notEqual(replaced.status, 0); + assert.match(replaced.stderr, /no longer an existing directory/); + records.push('structurally unrelated SDK replacement fails closed'); + assert.deepEqual(build(path.join(scratch, 'fresh-output')).files, { 'alternate.h': 'different' }); + records.push('fresh acquisition observes replaced SDK'); + file('usr/include/APR::Base64.h', 'usable-header', alternate); + const illegalHeader = runBuild(path.join(scratch, 'illegal-header-output')); + assert.equal(illegalHeader.error, undefined, String(illegalHeader.error)); + assert.notEqual(illegalHeader.status, 0); + assert.match(illegalHeader.stderr, /invalid label .*usr\/include\/APR::Base64\.h/u); + records.push('illegal labels outside documentation fail closed without dropping usable inputs'); + + // Framework version aliases plus a Ruby-style header cycle reproduce the + // SDK's repeated logical paths without needing an installed Apple SDK. + const largeSdk = path.join(scratch, 'large-sdk'); + let physicalHeaders = 0; + for (let framework = 0; framework < 16; framework++) { + const prefix = `Frameworks/F${framework}.framework`; + for (let header = 0; header < (framework === 0 ? 4 : 64); header++) { + file(`${prefix}/Versions/A/Headers/h${header}.h`, `header-${framework}-${header}`, largeSdk); + physicalHeaders++; + } + link(`${prefix}/Versions/Current`, 'A', largeSdk); + link(`${prefix}/Headers`, 'Versions/Current/Headers', largeSdk); + } + link('Frameworks/F0.framework/Versions/A/Headers/ruby', '.', largeSdk); + mkdirSync(path.join(largeSdk, 'FrameworkAliases')); + link('FrameworkAliases/Current', '../Frameworks', largeSdk); + link('FrameworkAliases/Compat', '../Frameworks', largeSdk); + file('usr/share/man/man3/Excluded::Manual.3pm', 'manual', largeSdk); + rmSync(alias); + symlinkSync(largeSdk, alias); + const largeOutput = path.join(scratch, 'large-output'); + const started = performance.now(); + const large = build(largeOutput, true); + const elapsedMs = Math.round(performance.now() - started); + assert.equal(Object.keys(large.files).length, physicalHeaders * 9); + assert.ok(!Object.keys(large.files).some((name) => name.includes('/ruby/'))); + assert.ok(!large.watchInputs.some((row) => row.includes('/usr/share/man/'))); + assert.ok( + large.watchInputs.length < Object.keys(large.files).length / 8, + `SDK repository watches must coalesce aliases: ${large.watchInputs.length} inputs for ${Object.keys(large.files).length} files`, + ); + console.log( + JSON.stringify({ + scenario: 'large framework alias graph coalesces actual recorded repository inputs', + physicalHeaders, + declaredFiles: Object.keys(large.files).length, + recordedWatchInputs: large.watchInputs.length, + elapsedMs, + }), + ); + records.push('large framework alias graph coalesces actual recorded repository inputs'); + link('Frameworks/F1.framework/Versions/A/Headers/new-cycle', '.', largeSdk); + const newCycle = runBuild(largeOutput, true); + assert.equal(newCycle.error, undefined, String(newCycle.error)); + assert.notEqual(newCycle.status, 0, 'a cyclic replacement must not reuse an acyclic tree watch'); + assert.match(newCycle.stderr, /cycle|cyclic/iu); + records.push('acyclic watched subtree becoming cyclic fails closed'); + const reacquired = build(path.join(scratch, 'large-cycle-output'), true); + assert.equal(Object.keys(reacquired.files).length, physicalHeaders * 9); + assert.ok(!Object.keys(reacquired.files).some((name) => name.includes('/new-cycle/'))); + records.push('fresh acquisition bounds the newly cyclic subtree'); + console.log(JSON.stringify({ passed: records.length, scenarios: records })); +} finally { + if (process.env.OLIPHAUNT_KEEP_SDK_PROBE === '1') console.log(JSON.stringify({ scratch })); + else rmSync(scratch, { recursive: true, force: true }); +} diff --git a/build_defs/host/sdk-tree.bzl b/build_defs/host/sdk-tree.bzl new file mode 100644 index 000000000..a63ac556e --- /dev/null +++ b/build_defs/host/sdk-tree.bzl @@ -0,0 +1,115 @@ +"""Watch and enumerate SDK files without recursively expanding directory cycles.""" + +def apple_sdk_documentation_directories(component): + """Manual pages are outside the configured compiler/sysroot input profile.""" + if component == "toolchain": + return ["share/man"] + if component.startswith("sdk_"): + return ["usr/share/man"] + return [] + +def _directory_graph(root): + """Read each physical directory once, marking trees that contain cycles.""" + directories = {} + states = {} + complete_trees = {} + pending = [(root.realpath, False)] + for _ in range(2000000): + if not pending: + return directories, complete_trees + source, finishing = pending.pop() + physical = str(source) + if finishing: + complete_trees[physical] = complete_trees.get(physical, True) and all([complete_trees[child] for child in directories[physical][1]]) + states[physical] = 2 + continue + state = states.get(physical, 0) + if state: + if state == 1: + complete_trees[physical] = False + continue + states[physical] = 1 + entries = source.readdir(watch = "no") + children = [child.realpath for child in entries if child.exists and child.is_dir] + directories[physical] = ([child.basename for child in entries], [str(child) for child in children]) + pending.append((source, True)) + pending.extend([(child, False) for child in children]) + fail("The selected host SDK exceeds the bounded physical directory traversal; no partial SDK is declared.") + +def watch_sdk_directory(ctx, root, excluded_directories = []): + """Return finite relative file paths, retaining noncyclic SDK aliases. + + Complete acyclic subtrees use one recursive watch instead of a separate + Skyframe dependency for every aliased file. Cyclic and documentation-excluded + boundaries retain explicit membership, type, and content watches. A link back + to an ancestor receives one finite watch pass without declaring cyclic inputs. + + The selected SDK installation's topology is fixed for an output base. + Bazel 8.8 watches directory names, file types, and bytes, not a directory + link's canonical identity; an identical-content cycle retarget can therefore + leave observations unchanged. These watches do not qualify live SDK swaps. + + If a structurally replaced SDK removes a watched logical directory, Bazel + 8.8.1 may reject the old watch state before refetching. This fails closed; + reacquire the selected SDK using a fresh output base. + """ + files = [] + directory_graph, complete_trees = _directory_graph(root) + watched_directories = {} + watched_files = {} + watched_trees = {} + pending = [(root, "", [], True, False, str(root), False)] + for _ in range(2000000): + if not pending: + return sorted(files) + source, relative, ancestors, declare, aliased, expected_path, covered = pending.pop() + # Exclude named documentation trees, never files based on characters: + # usable headers/resources with invalid labels must still fail closed. + if relative in excluded_directories: + continue + # Match glob's handling of dangling links while watching their creation. + if not source.exists: + ctx.watch(source) + continue + canonical = source.realpath + physical = str(canonical) + aliased = aliased or expected_path != physical + if source.is_dir: + if physical in ancestors: + if not declare: + if not covered: + ctx.watch(source) + continue + ancestors = [] + declare = False + aliased = True + contains_exclusion = any([excluded.startswith(relative + "/") if relative else True for excluded in excluded_directories]) + if not covered: + if complete_trees[physical] and not contains_exclusion: + # watch_tree follows aliases and observes deep retarget changes. + for tree in [source, canonical]: + identity = str(tree) + if identity not in watched_trees: + ctx.watch_tree(tree) + watched_trees[identity] = True + covered = True + else: + ctx.watch(source) + # Names alone do not identify a directory link's target. + watched = source if aliased else canonical + identity = str(watched) + if identity not in watched_directories: + watched.readdir(watch = "yes") + watched_directories[identity] = True + for basename in directory_graph[physical][0]: + child_relative = relative + "/" + basename if relative else basename + pending.append((source.get_child(basename), child_relative, ancestors + [physical], declare, aliased, str(canonical.get_child(basename)), covered)) + else: + if not covered and physical not in watched_files: + ctx.watch(canonical) + watched_files[physical] = True + if not covered and aliased: + ctx.watch(source) + if declare: + files.append(relative) + fail("The selected host SDK exceeds the bounded directory traversal; no partial SDK is declared.") diff --git a/build_defs/host/swift-profile.bzl b/build_defs/host/swift-profile.bzl new file mode 100644 index 000000000..6f11f210d --- /dev/null +++ b/build_defs/host/swift-profile.bzl @@ -0,0 +1,100 @@ +"""Declare the Xcode tools and SDK used by the standard Swift actions.""" + +load("@rules_swift//swift:providers.bzl", "SwiftToolchainInfo") +load("@rules_swift//swift/toolchains/config:action_config.bzl", "ActionConfigInfo", "add_arg") +load("@rules_swift//swift/toolchains/config:tool_config.bzl", "ToolConfigInfo") + +def declared_swift_path(value, prefix, selected_sdk = "macosx"): + """Bind stock Xcode paths to this repository's watched SDK projection.""" + for developer in ["__BAZEL_XCODE_DEVELOPER_DIR__", "/private/var/select/developer_dir", "/var/db/xcode_select_link"]: + value = value.replace(developer + "/Toolchains/XcodeDefault.xctoolchain/usr/", prefix + "toolchain/") + for sdk, platform in [("macosx", "MacOSX"), ("iphoneos", "iPhoneOS"), ("iphonesimulator", "iPhoneSimulator")]: + value = value.replace(developer + "/Platforms/" + platform + ".platform/Developer/Library", prefix + "platform_" + sdk + "/Library") + value = value.replace(developer + "/Platforms/" + platform + ".platform/Developer/usr/lib", prefix + "platform_" + sdk + "/usr/lib") + value = value.replace("__BAZEL_XCODE_SDKROOT__", prefix + "sdk_" + selected_sdk) + if "__BAZEL_XCODE_" in value or "/var/select/developer_dir" in value or "/xcode_select_link" in value: + fail("Unsupported ambient Xcode path in the declared Swift profile: " + value) + return value + +def _declared_link_flag(flag, ctx, test_runtime): + # Tests run from their runfiles workspace, not the compile execroot. This + # licensed local profile loads only the same watched repository projection. + prefix = ctx.attr.runtime_prefix if test_runtime and flag.startswith("-Wl,-rpath,") else ctx.attr.prefix + return declared_swift_path(flag, prefix, ctx.attr.sdk_name) + +def _declared_linking_context(context, ctx, test_runtime = False, runtime_only = False): + return cc_common.create_linking_context(linker_inputs = depset([ + cc_common.create_linker_input( + owner = item.owner, + libraries = depset([] if runtime_only else item.libraries), + additional_inputs = depset(ctx.files.sdk + item.additional_inputs), + user_link_flags = [_declared_link_flag(flag, ctx, test_runtime) for flag in item.user_link_flags if not runtime_only or flag.startswith("-Wl,-rpath,")], + ) + for item in context.linker_inputs.to_list() + ])) + +def _declared_implicit(providers, ctx): + return struct( + cc_infos = [CcInfo(compilation_context = info.compilation_context, linking_context = _declared_linking_context(info.linking_context, ctx)) for info in providers.cc_infos], + swift_infos = providers.swift_infos, + ) + +def _fields(value): + return {name: getattr(value, name) for name in dir(value) if name not in ["to_json", "to_proto"]} + +def declared_xcode_info(original, tools, ctx): + """Rebind a standard Swift provider without changing its action model.""" + fields = _fields(original) + fields["compiler_plugin_directory"] = ctx.attr.resource_directory + "/host/plugins/testing" + fields["developer_dirs"] = [struct(developer_path_label = item.developer_path_label, path = declared_swift_path(item.path, ctx.attr.prefix, ctx.attr.sdk_name)) for item in original.developer_dirs] + fields["implicit_deps_providers"] = _declared_implicit(original.implicit_deps_providers, ctx) + test = _fields(original.test_configuration) + test["test_linking_contexts"] = [_declared_linking_context(context, ctx, test_runtime = True) for context in test["test_linking_contexts"]] + # Xcode puts Swift compatibility-library rpaths in its production context. + # Copy only those runtime paths into the test context; do not duplicate libs + # or make production binaries carry absolute local SDK paths. + test["test_linking_contexts"] += [_declared_linking_context(info.linking_context, ctx, test_runtime = True, runtime_only = True) for info in original.implicit_deps_providers.cc_infos] + fields["test_configuration"] = struct(**test) + configs = {} + for action, configuration in original.tool_configs.items(): + values = _fields(configuration) + values["additional_tools"] = values["additional_tools"] + ctx.files.sdk + mode = values["executable"].rsplit("/", 1)[-1] + if mode not in tools: + fail("The declared Xcode profile has no tool for Swift driver mode " + mode) + values["executable"] = tools[mode] + # This profile imports a licensed SDK from the local Apple host. + values["execution_requirements"] = values["execution_requirements"] | {"no-remote": "1"} + configs[action] = ToolConfigInfo(**values) + fields["tool_configs"] = configs + # Last SDK/resource flags bind stock Xcode action configuration to our inputs. + fields["action_configs"] = fields["action_configs"] + [ActionConfigInfo( + actions = configs.keys(), + configurators = [ + add_arg("-target", ctx.attr.target_triple), + add_arg("-sdk", ctx.attr.sdkroot), + add_arg("-resource-dir", ctx.attr.resource_directory), + ], + )] + info = SwiftToolchainInfo(**fields) + return info + +def _declared_xcode_swift_impl(ctx): + tools = {mode: target.files.to_list()[0] for target, mode in ctx.attr.tools.items()} + info = declared_xcode_info(ctx.attr.base[SwiftToolchainInfo], tools, ctx) + return [platform_common.ToolchainInfo(swift_toolchain = info), info] + +declared_xcode_swift_toolchain = rule( + implementation = _declared_xcode_swift_impl, + attrs = { + "base": attr.label(default = Label("//build_defs/host:xcode_swift_base"), providers = [SwiftToolchainInfo]), + "sdk": attr.label_list(allow_files = True, mandatory = True), + "tools": attr.label_keyed_string_dict(allow_files = True, mandatory = True), + "sdkroot": attr.string(mandatory = True), + "sdk_name": attr.string(default = "macosx", values = ["macosx", "iphoneos", "iphonesimulator"]), + "resource_directory": attr.string(mandatory = True), + "prefix": attr.string(mandatory = True), + "runtime_prefix": attr.string(mandatory = True), + "target_triple": attr.string(mandatory = True), + }, +) diff --git a/build_defs/languages/BUILD.bazel b/build_defs/languages/BUILD.bazel new file mode 100644 index 000000000..f9f190aff --- /dev/null +++ b/build_defs/languages/BUILD.bazel @@ -0,0 +1,47 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/foundation:bun.bzl", "bun_test") +load(":napi-artifact-test.bzl", "napi_artifact_tests") +load(":source.bzl", "cargo_source_contract_test") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["mobile-compiled-inputs.bzl"]) + +config_setting( + name = "release", + values = {"compilation_mode": "opt"}, +) + +exports_files(["cargo-metadata.mts", "repositories.bzl", "rust.bzl", "napi-noop.bzl", "mobile.bzl", "source.bzl", "source-package.mts", "source-contract.mts", "uniffi.mts", "mobile-legal.mts", "wasix.bzl", "cargo-environment.mts", "cargo-toolchain.bzl", "isolated-cache-test.mts"]) + +bun_test( + name = "cargo_metadata_test", + size = "small", + entry_point = "cargo-metadata.test.mts", + data = ["cargo-metadata.mts", "//:tools/packaging/cargo-manifest.mts"], +) + +bun_test( + name = "source_package_test", + size = "small", + entry_point = "source-package.test.mts", + data = ["source-package.mts", "//:tools/packaging/cargo-manifest.mts", "//:tools/packaging/cargo-source-package.mts", "//:tools/packaging/package-archive.mts", "//:tools/packaging/archive-directory.mts", "//:tools/packaging/portable-archive.mts", "//:tools/packaging/release-notices.mts", "//:tools/packaging/release-directory-safety.mts", "//:tools/packaging/rust-native-targets.mts"], +) + +cargo_source_contract_test( + name = "sdk_source_package_test", + packages = ["//src/native/sdks/rust:crate", "//src/native/sdks/rust/crates/oliphaunt-build:crate", "//src/wasix/sdks/rust:crate"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + size = "small", +) + +bun_test( + name = "source_contract_test", + entry_point = "source-contract.test.mts", + data = ["source-contract.mts", "source-package.mts", "//build_defs/query:package.mts", "//:tools/packaging/cargo-manifest.mts", "//:tools/packaging/cargo-dependencies.mts", "//:tools/packaging/cargo-source-package.mts", "//:tools/packaging/package-archive.mts", "//:tools/packaging/archive-directory.mts", "//:tools/packaging/portable-archive.mts", "//:tools/packaging/release-notices.mts", "//:tools/packaging/release-directory-safety.mts", "//:tools/packaging/rust-native-targets.mts"], + size = "small", +) + +source_quality_files() + +napi_artifact_tests() diff --git a/build_defs/languages/cargo-environment.mts b/build_defs/languages/cargo-environment.mts new file mode 100644 index 000000000..8124d35b2 --- /dev/null +++ b/build_defs/languages/cargo-environment.mts @@ -0,0 +1,50 @@ +import path from 'node:path'; + +export interface CargoLinkConfiguration { + linker: string; + args: string[]; + env: Record; + roots: Record; + cc?: string; + cxx?: string; + ar?: string; + cflags?: string[]; + cxxflags?: string[]; +} + +export function cargoLinkEnvironment(configuration: CargoLinkConfiguration, runfiles: string) { + const roots = Object.entries(configuration.roots).sort(([a], [b]) => b.length - a.length); + const relocate = (input: string) => { + let value = input; + for (const [source, destination] of roots) { + const output = path.join(runfiles, destination); + if (value === source) return output; + value = value.replaceAll(`${source}/`, `${output}/`); + } + return value; + }; + const quote = (value: string) => + `"${relocate(value).replaceAll('\\', '\\\\').replaceAll('"', '\\"')}"`; + return { + ...Object.fromEntries( + Object.entries(configuration.env).map(([key, value]) => [key, relocate(value)]), + ), + ...(configuration.cc ? { CC: relocate(configuration.cc) } : {}), + ...(configuration.cxx ? { CXX: relocate(configuration.cxx) } : {}), + ...(configuration.ar ? { AR: relocate(configuration.ar) } : {}), + ...(configuration.cflags ? { CFLAGS: configuration.cflags.map(quote).join(' ') } : {}), + ...(configuration.cxxflags ? { CXXFLAGS: configuration.cxxflags.map(quote).join(' ') } : {}), + ...(configuration.cflags || configuration.cxxflags + ? { + // cc-rs otherwise splits quotes literally and guesses a new target + // profile. These flags already come from the declared C/C++ provider. + CC_SHELL_ESCAPED_FLAGS: '1', + CRATE_CC_NO_DEFAULTS: '1', + } + : {}), + CARGO_ENCODED_RUSTFLAGS: [ + `-Clinker=${relocate(configuration.linker)}`, + ...configuration.args.map((argument) => `-Clink-arg=${relocate(argument)}`), + ].join('\x1f'), + }; +} diff --git a/build_defs/languages/cargo-metadata.mts b/build_defs/languages/cargo-metadata.mts new file mode 100644 index 000000000..127064801 --- /dev/null +++ b/build_defs/languages/cargo-metadata.mts @@ -0,0 +1,321 @@ +import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { + cargoSatisfies, + renderCargoToml as renderToml, + resolveCargoWorkspaceInheritance, +} from '../../tools/packaging/cargo-manifest.mts'; + +export { + cargoSatisfies, + renderCargoToml as renderToml, +} from '../../tools/packaging/cargo-manifest.mts'; + +type Table = Record; +const dependencySections = ['dependencies', 'dev-dependencies', 'build-dependencies']; + +function dependencyTables(manifest: Table): Table[] { + return [manifest, ...Object.values(manifest.target ?? {})].flatMap((table) => + dependencySections.flatMap((section) => (table[section] ? [table[section]] : [])), + ); +} + +function inheritedPackage(manifest: Table, workspace: Table): Table { + return Object.fromEntries( + Object.entries(manifest.package).map(([key, value]) => [ + key, + value && typeof value === 'object' && (value as Table).workspace === true + ? workspace.package?.[key] + : value, + ]), + ); +} + +export function projectCargoWorkspace( + workspace: Table, + lock: Table, + roots: string[], + readManifest: (relative: string) => Table, + sourceExists: (relative: string) => boolean, + activations: Record = {}, + workspacePrefix = '', +) { + if (lock.version !== 4) throw new Error('Native Cargo import requires lockfile schema 4'); + if (!workspace.workspace || (workspace.package && !workspacePrefix)) + throw new Error('Native Cargo import requires a conventional workspace'); + if (workspace.patch || workspace.replace) + throw new Error('Native Cargo import does not yet represent workspace patch/replace sources'); + const releaseKeys = Object.keys(workspace.profile?.release ?? {}); + if (releaseKeys.some((key) => key !== 'strip')) + throw new Error( + `Unrepresented authored Cargo release profile fields: ${releaseKeys.join(', ')}`, + ); + const releaseStrip = workspace.profile?.release?.strip ?? null; + if (releaseStrip !== null && releaseStrip !== 'symbols') + throw new Error(`Unsupported conventional Cargo release strip setting: ${releaseStrip}`); + const members = new Map(); + const declaredMembers = workspace.workspace.members.map((member: string) => + path.posix.normalize(path.posix.join(workspacePrefix, member)), + ); + const pending = roots.length ? [...roots] : [...declaredMembers]; + for (const candidate of pending) { + const relative = path.posix.normalize(candidate); + if (relative.startsWith('../') || relative === '..' || path.posix.isAbsolute(relative)) + throw new Error(`Cargo path dependency escapes the workspace: ${relative}`); + if (members.has(relative)) continue; + if (!declaredMembers.includes(relative)) + throw new Error(`Cargo package is not a declared workspace member: ${relative}`); + const manifest = readManifest(`${relative}/Cargo.toml`); + if ( + !manifest.package || + (manifest.workspace && relative !== workspacePrefix) || + manifest.patch || + manifest.replace + ) + throw new Error(`Unsupported Cargo member shape: ${relative}`); + const copy = resolveCargoWorkspaceInheritance(manifest, workspace.workspace); + delete copy.workspace; + const originalDependencyTables = dependencyTables(manifest); + for (const [index, table] of dependencyTables(copy).entries()) { + for (const [name, declaration] of Object.entries(table)) { + const dependency = declaration as Table; + if (dependency?.path && originalDependencyTables[index]?.[name]?.workspace === true) + dependency.path = path.posix.relative( + relative, + path.posix.join(workspacePrefix, dependency.path), + ); + const resolved = table[name]; + if (resolved?.path) pending.push(path.posix.join(relative, resolved.path)); + } + } + members.set(relative, copy); + } + const byName = new Map(); + for (const [relative, manifest] of members) { + if (byName.has(manifest.package.name)) + throw new Error(`Duplicate Cargo package ${manifest.package.name}`); + byName.set(manifest.package.name, relative); + } + const candidates = new Map(); + for (const item of lock.package) + candidates.set(item.name, [...(candidates.get(item.name) ?? []), item]); + function lockedDependency(text: string): Table { + const identity = /^([^ ]+)(?: ([^ ]+)(?: \(([^)]+)\))?)?$/u.exec(text); + if (!identity) throw new Error(`Invalid canonical Cargo lock dependency: ${text}`); + const [, name, version, source] = identity; + let matches = (candidates.get(name) ?? []).filter( + (item) => (!version || item.version === version) && (!source || item.source === source), + ); + // Cargo includes a source qualifier for registry identities when a local + // package has the same name and version; the unqualified identity is local. + if (!source && version && matches.length > 1) matches = matches.filter((item) => !item.source); + if (matches.length !== 1) + throw new Error(`Missing or ambiguous canonical Cargo lock dependency: ${text}`); + return matches[0]; + } + const facts: Table = {}; + const files: Record = {}; + const watched = new Set(); + for (const [relative, sourceManifest] of members) { + const manifest = structuredClone(sourceManifest); + const actual = inheritedPackage(manifest, workspace.workspace); + if ( + typeof actual.version !== 'string' || + typeof actual.edition !== 'string' || + typeof actual['rust-version'] !== 'string' + ) + throw new Error(`Missing conventional Cargo version/edition/MSRV: ${relative}`); + const localLock = (candidates.get(actual.name) ?? []).filter((item) => !item.source); + if (localLock.length !== 1) + throw new Error(`Missing canonical Cargo lock member: ${actual.name}`); + for (const table of dependencyTables(manifest)) { + for (const [name, declaration] of Object.entries(table)) { + const dependency = declaration as Table; + if (!dependency?.path) { + if (dependency?.git || dependency?.registry) + throw new Error( + `Native Cargo import does not yet represent git/custom-registry dependency ${name}`, + ); + const packageName = dependency?.package ?? name; + const locked = (localLock[0].dependencies ?? []) + .map(lockedDependency) + .filter((item: Table) => item.name === packageName); + const requirement = typeof declaration === 'string' ? declaration : dependency.version; + if ( + !requirement || + !locked.some((item: Table) => cargoSatisfies(item.version, requirement)) + ) + throw new Error(`Stale canonical Cargo lock dependency: ${actual.name} -> ${name}`); + continue; + } + const dependencyPath = path.posix.normalize(path.posix.join(relative, dependency.path)); + const dependencyManifest = members.get(dependencyPath); + if (!dependencyManifest) throw new Error(`Missing Cargo path member: ${dependencyPath}`); + const target = inheritedPackage(dependencyManifest, workspace.workspace); + if ( + (dependency.package && dependency.package !== target.name) || + (!dependency.package && name !== target.name) + ) + throw new Error(`Cargo path/name mismatch: ${relative} -> ${name}`); + if (dependency.version && !cargoSatisfies(target.version, dependency.version)) + throw new Error(`Cargo path/version mismatch: ${relative} -> ${name}`); + dependency.version = '=0.0.0'; + } + } + const targetPaths = new Set(); + for (const target of [ + manifest.lib, + ...(manifest.bin ?? []), + ...(manifest.test ?? []), + ...(manifest.example ?? []), + ...(manifest.bench ?? []), + ]) + if (target?.path) targetPaths.add(target.path); + for (const candidate of ['src/lib.rs', 'src/main.rs', 'build.rs']) { + const file = `${relative}/${candidate}`; + watched.add(file); + if (sourceExists(file)) targetPaths.add(candidate); + } + // Automatic source discovery must be preserved as a graph input, not discarded. + for (const directory of ['src/bin', 'tests', 'examples', 'benches']) + watched.add(`${relative}/${directory}`); + watched.add(`${relative}/README.md`); + if (typeof actual.build === 'string') targetPaths.add(actual.build); + const library = + manifest.lib?.path ?? (sourceExists(`${relative}/src/lib.rs`) ? 'src/lib.rs' : null); + facts[relative] = { + name: actual.name, + crate_name: (manifest.lib?.name ?? actual.name).replaceAll('-', '_'), + version: actual.version, + edition: actual.edition, + minimum: actual['rust-version'], + library, + crate_types: manifest.lib?.['crate-type'] ?? ['rlib'], + binaries: (manifest.bin ?? []).map((target: Table) => ({ + ...target, + path: target.path ? path.posix.normalize(target.path) : `src/bin/${target.name}.rs`, + })), + readme: + actual.readme === false + ? null + : (actual.readme ?? (sourceExists(`${relative}/README.md`) ? 'README.md' : null)), + features: structuredClone(manifest.features ?? {}), + dependencies: structuredClone(manifest.dependencies ?? {}), + dev_dependencies: structuredClone(manifest['dev-dependencies'] ?? {}), + build_dependencies: structuredClone(manifest['build-dependencies'] ?? {}), + target_dependencies: structuredClone(manifest.target ?? {}), + metadata: actual.metadata ?? {}, + build: actual.build ?? (sourceExists(`${relative}/build.rs`) ? 'build.rs' : false), + links: actual.links ?? null, + release_strip: releaseStrip, + }; + const projectedPackage: Table = { + name: actual.name, + version: '0.0.0', + edition: actual.edition, + 'rust-version': actual['rust-version'], + }; + for (const key of [ + 'build', + 'links', + 'autolib', + 'autobins', + 'autotests', + 'autoexamples', + 'autobenches', + ]) + if (actual[key] !== undefined) projectedPackage[key] = actual[key]; + manifest.package = projectedPackage; + for (const feature of activations[relative] ?? []) { + if (!Object.hasOwn(manifest.features ?? {}, feature)) + throw new Error(`Unknown Cargo tool feature: ${relative}/${feature}`); + manifest.features.default = [...new Set([...(manifest.features.default ?? []), feature])]; + } + files[`${relative}/Cargo.toml`] = renderToml(manifest); + for (const source of [...targetPaths].sort()) { + if (source.startsWith('../') || path.posix.isAbsolute(source)) + throw new Error(`Cargo target escapes its member: ${relative}/${source}`); + files[`${relative}/${source}`] = source === 'src/lib.rs' ? '' : 'fn main() {}\n'; + } + } + const included = new Set(); + const frontier = [...byName.keys()].map((name) => { + const local = (candidates.get(name) ?? []).filter((item) => !item.source); + if (local.length !== 1) throw new Error(`Missing canonical Cargo lock member: ${name}`); + return local[0]; + }); + for (const item of frontier) { + if (included.has(item)) continue; + included.add(item); + for (const dependency of item.dependencies ?? []) frontier.push(lockedDependency(dependency)); + } + const projectedLock = { + version: lock.version, + package: [...included] + .map((item) => ({ + ...item, + ...(!item.source ? { version: '0.0.0' } : {}), + ...(item.dependencies + ? { + dependencies: item.dependencies.map((text: string) => { + const dependency = lockedDependency(text); + return !dependency.source && text.includes(' ') ? `${dependency.name} 0.0.0` : text; + }), + } + : {}), + })) + .sort((a, b) => { + const left = `${a.name}@${a.version}`; + const right = `${b.name}@${b.version}`; + return left < right ? -1 : left > right ? 1 : 0; + }), + }; + files['Cargo.toml'] = renderToml({ + workspace: { + members: [...members.keys()].sort(), + resolver: workspace.workspace.resolver ?? '3', + }, + }); + files['Cargo.lock'] = renderToml(projectedLock); + for (const member of Object.keys(activations)) + if (!members.has(member)) throw new Error(`Unknown Cargo tool member: ${member}`); + return { + files, + facts, + watched: [...watched].sort(), + manifests: [...members.keys()].map((member) => `${member}/Cargo.toml`).sort(), + }; +} + +if (import.meta.main) { + const [workspaceFile, lockFile, output, ...options] = process.argv.slice(2); + if (!workspaceFile || !lockFile || !output) + throw new Error('Expected canonical workspace, lockfile, and output directory'); + const prefixIndex = options.indexOf('--workspace-prefix'); + const workspacePrefix = prefixIndex < 0 ? '' : options.splice(prefixIndex, 2)[1]; + const root = workspacePrefix + ? path.resolve(path.dirname(workspaceFile), path.relative(workspacePrefix, '.')) + : path.dirname(workspaceFile); + const activationIndex = options.indexOf('--activate'); + const activations = activationIndex < 0 ? {} : JSON.parse(options[activationIndex + 1]); + const roots = activationIndex < 0 ? options : options.slice(0, activationIndex); + if (activationIndex >= 0 && activationIndex !== options.length - 2) + throw new Error('Expected --activate followed by one feature-map JSON argument'); + const result = projectCargoWorkspace( + Bun.TOML.parse(readFileSync(workspaceFile, 'utf8')), + Bun.TOML.parse(readFileSync(lockFile, 'utf8')), + roots, + (relative) => Bun.TOML.parse(readFileSync(path.join(root, relative), 'utf8')), + (relative) => existsSync(path.join(root, relative)), + activations, + workspacePrefix, + ); + for (const [relative, text] of Object.entries(result.files)) { + const destination = path.join(output, relative); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, text); + } + console.log( + JSON.stringify({ facts: result.facts, watched: result.watched, manifests: result.manifests }), + ); +} diff --git a/build_defs/languages/cargo-metadata.test.mts b/build_defs/languages/cargo-metadata.test.mts new file mode 100644 index 000000000..a7a845115 --- /dev/null +++ b/build_defs/languages/cargo-metadata.test.mts @@ -0,0 +1,404 @@ +import { expect, test } from 'bun:test'; +import { projectCargoWorkspace, renderToml } from './cargo-metadata.mts'; + +function fixture() { + const workspace = { + workspace: { + members: ['core', 'sdk'], + resolver: '3', + package: { edition: '2024', 'rust-version': '1.93', license: 'MIT' }, + }, + }; + const manifests: Record = { + 'core/Cargo.toml': { + package: { + name: 'core', + version: '0.2.0', + edition: { workspace: true }, + 'rust-version': { workspace: true }, + description: 'Core', + }, + dependencies: { serde: { version: '1', features: ['derive'] } }, + }, + 'sdk/Cargo.toml': { + package: { + name: 'sdk', + version: '0.3.0', + edition: { workspace: true }, + 'rust-version': { workspace: true }, + build: 'build.rs', + links: 'resources', + }, + features: { default: ['desktop'], desktop: ['dep:core'] }, + dependencies: { core: { path: '../core', version: '0.2.0', optional: true } }, + target: { 'cfg(unix)': { 'dev-dependencies': { libc: '0.2' } } }, + }, + }; + const lock = { + version: 4, + package: [ + { name: 'core', version: '0.2.0', dependencies: ['serde'] }, + { name: 'sdk', version: '0.3.0', dependencies: ['core', 'libc'] }, + { + name: 'serde', + version: '1.0.228', + source: 'registry+https://github.com/rust-lang/crates.io-index', + checksum: 'serde-sha256', + dependencies: ['serde_derive'], + }, + { + name: 'serde_derive', + version: '1.0.228', + source: 'registry+https://github.com/rust-lang/crates.io-index', + checksum: 'derive-sha256', + }, + { + name: 'libc', + version: '0.2.183', + source: 'registry+https://github.com/rust-lang/crates.io-index', + checksum: 'libc-sha256', + }, + { + name: 'unrelated', + version: '99.0.0', + source: 'registry+https://github.com/rust-lang/crates.io-index', + checksum: 'other-sha256', + }, + ], + }; + const project = () => + projectCargoWorkspace( + workspace, + lock, + ['sdk'], + (relative) => manifests[relative], + (relative) => relative.endsWith('/src/lib.rs') || relative === 'sdk/build.rs', + ); + return { workspace, manifests, lock, project }; +} + +test('a conventional adapter workspace keeps sibling members within declared repository paths', () => { + const { workspace, manifests, lock } = fixture(); + const owner = { + ...manifests['sdk/Cargo.toml'], + workspace: { ...workspace.workspace, members: ['.', '../core'] }, + }; + const sources = { + 'nested/adapter/Cargo.toml': owner, + 'nested/core/Cargo.toml': { + ...manifests['core/Cargo.toml'], + package: { ...manifests['core/Cargo.toml'].package, workspace: '../adapter' }, + }, + }; + const result = projectCargoWorkspace( + owner, + lock, + [], + (relative) => sources[relative], + (relative) => relative.endsWith('/src/lib.rs'), + {}, + 'nested/adapter', + ); + expect(Object.keys(result.facts).sort()).toEqual(['nested/adapter', 'nested/core']); + expect(Bun.TOML.parse(result.files['Cargo.toml']).workspace.members).toEqual([ + 'nested/adapter', + 'nested/core', + ]); + expect(Bun.TOML.parse(result.files['nested/core/Cargo.toml']).package.workspace).toBeUndefined(); + expect(() => + projectCargoWorkspace( + { workspace: { members: ['../../../outside'] } }, + lock, + [], + () => ({}), + () => false, + {}, + 'nested/adapter', + ), + ).toThrow('escapes'); +}); + +test('preserves resolver, feature, optional, target/dev, generator and exact external lock facts', () => { + const { project } = fixture(); + const result = project(); + const sdk = Bun.TOML.parse(result.files['sdk/Cargo.toml']); + expect(sdk.features).toEqual({ default: ['desktop'], desktop: ['dep:core'] }); + expect(sdk.dependencies.core).toEqual({ path: '../core', version: '=0.0.0', optional: true }); + expect(sdk.target['cfg(unix)']['dev-dependencies']).toEqual({ libc: '0.2' }); + expect(sdk.package).toMatchObject({ + build: 'build.rs', + links: 'resources', + edition: '2024', + 'rust-version': '1.93', + }); + expect(Bun.TOML.parse(result.files['Cargo.toml']).workspace).toEqual({ + members: ['core', 'sdk'], + resolver: '3', + }); + const lock = Bun.TOML.parse(result.files['Cargo.lock']); + expect(lock.package.map((item) => item.name)).toEqual([ + 'core', + 'libc', + 'sdk', + 'serde', + 'serde_derive', + ]); + expect(lock.package.find((item) => item.name === 'serde')).toMatchObject({ + version: '1.0.228', + checksum: 'serde-sha256', + }); + expect(result.watched).toContain('sdk/build.rs'); + expect(result.watched).toContain('sdk/tests'); +}); + +test('coherent public version and package metadata edits do not change acquisition files', () => { + const { project, manifests, lock } = fixture(); + const before = project(); + manifests['core/Cargo.toml'].package.version = '0.2.1'; + manifests['core/Cargo.toml'].package.description = 'New description'; + manifests['sdk/Cargo.toml'].dependencies.core.version = '0.2.1'; + manifests['sdk/Cargo.toml'].package.version = '0.3.1'; + for (const item of lock.package) { + if (item.name === 'core') item.version = '0.2.1'; + if (item.name === 'sdk') item.version = '0.3.1'; + } + const after = project(); + expect(after.files).toEqual(before.files); + expect(after.facts.sdk.version).toBe('0.3.1'); + expect(after.facts.core.version).toBe('0.2.1'); +}); + +test('an independently released workspace library does not retarget an SDK registry requirement', () => { + const { workspace, manifests, lock } = fixture(); + manifests['sdk/Cargo.toml'].dependencies.core = { version: '=0.2.0' }; + for (const item of lock.package) + if (item.name === 'sdk') + item.dependencies = [ + 'core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)', + 'libc', + ]; + lock.package.push({ + name: 'core', + version: '0.2.0', + source: 'registry+https://github.com/rust-lang/crates.io-index', + checksum: 'held-core-sha256', + }); + const project = () => + projectCargoWorkspace( + workspace, + lock, + [], + (relative) => manifests[relative], + (relative) => relative.endsWith('/src/lib.rs') || relative === 'sdk/build.rs', + ); + const before = project(); + manifests['core/Cargo.toml'].package.version = '1.0.0'; + for (const item of lock.package) if (item.name === 'core' && !item.source) item.version = '1.0.0'; + const after = project(); + expect(after.files).toEqual(before.files); + expect(after.facts.core.version).toBe('1.0.0'); + expect(Bun.TOML.parse(after.files['sdk/Cargo.toml']).dependencies.core).toEqual({ + version: '=0.2.0', + }); + expect( + Bun.TOML.parse(after.files['Cargo.lock']).package.filter((item) => item.name === 'core'), + ).toEqual([ + { name: 'core', version: '0.0.0', dependencies: ['serde'] }, + { + name: 'core', + version: '0.2.0', + source: 'registry+https://github.com/rust-lang/crates.io-index', + checksum: 'held-core-sha256', + }, + ]); +}); + +test('same-version local and registry lock identities retain their distinct sources', () => { + const { project, lock } = fixture(); + for (const item of lock.package) + if (item.name === 'sdk') item.dependencies = ['core 0.2.0', 'libc']; + lock.package.push({ + name: 'core', + version: '0.2.0', + source: 'registry+https://github.com/rust-lang/crates.io-index', + checksum: 'unused-registry-core-sha256', + }); + const selected = Bun.TOML.parse(project().files['Cargo.lock']).package; + expect(selected.find((item) => item.name === 'core')).toEqual({ + name: 'core', + version: '0.0.0', + dependencies: ['serde'], + }); + expect(selected.filter((item) => item.name === 'core')).toHaveLength(1); +}); + +test('dependency features and compiler minimum change their acquisition contract', () => { + const { project, manifests, workspace } = fixture(); + const before = project(); + manifests['core/Cargo.toml'].dependencies.serde.features.push('rc'); + workspace.workspace.package['rust-version'] = '1.94'; + expect(project().files['core/Cargo.toml']).not.toBe(before.files['core/Cargo.toml']); +}); + +test('authored release stripping changes compiler facts without changing acquisition', () => { + const { project, workspace } = fixture(); + const before = project(); + (workspace as any).profile = { release: { strip: 'symbols' } }; + const after = project(); + expect(after.files).toEqual(before.files); + expect(after.facts.sdk.release_strip).toBe('symbols'); + expect(after.facts.core.release_strip).toBe('symbols'); + (workspace as any).profile.release.strip = 'unrepresented'; + expect(project).toThrow('Unsupported conventional Cargo release strip setting'); + (workspace as any).profile.release = { strip: 'symbols', lto: true }; + expect(project).toThrow('Unrepresented authored Cargo release profile fields'); +}); + +test('rejects missing locks, incompatible path versions and unknown source overrides', () => { + const { project, manifests, workspace } = fixture(); + manifests['core/Cargo.toml'].dependencies.new_dependency = '1'; + expect(project).toThrow('Stale canonical Cargo lock dependency'); + delete manifests['core/Cargo.toml'].dependencies.new_dependency; + manifests['sdk/Cargo.toml'].dependencies.core.version = '0.4'; + expect(project).toThrow('Cargo path/version mismatch'); + manifests['sdk/Cargo.toml'].dependencies.core.version = '0.2'; + (workspace as any).patch = { 'crates-io': {} }; + expect(project).toThrow('workspace patch/replace'); +}); + +test('TOML serializer preserves manifests with nested tables and target arrays', () => { + const value = { + package: { name: 'tool', version: '0.1.0' }, + bin: [ + { name: 'first', path: 'src/first.rs' }, + { name: 'second', path: 'src/second.rs' }, + ], + target: { + 'cfg(unix)': { + dependencies: { + renamed: { package: 'actual', version: '=1.2.3', 'default-features': false }, + }, + }, + }, + }; + expect(Bun.TOML.parse(renderToml(value))).toEqual(value); +}); + +test('tool feature activation changes only the requested acquisition view, retaining canonical pins', () => { + const { workspace, manifests, lock, project } = fixture(); + manifests['sdk/Cargo.toml'].features.bindgen = []; + const before = project(); + const activated = projectCargoWorkspace( + workspace, + lock, + [], + (relative) => manifests[relative], + (relative) => relative.endsWith('/src/lib.rs') || relative === 'sdk/build.rs', + { sdk: ['bindgen'] }, + ); + expect(activated.files['Cargo.lock']).toBe(before.files['Cargo.lock']); + expect(Bun.TOML.parse(activated.files['sdk/Cargo.toml']).features.default).toEqual([ + 'desktop', + 'bindgen', + ]); + expect(activated.facts).toEqual(before.facts); + expect(manifests['sdk/Cargo.toml'].features.default).toEqual(['desktop']); + expect(() => + projectCargoWorkspace( + workspace, + lock, + [], + (p) => manifests[p], + () => true, + { sdk: ['unknown'] }, + ), + ).toThrow('Unknown Cargo tool feature'); + expect(() => + projectCargoWorkspace( + workspace, + lock, + [], + (p) => manifests[p], + () => true, + { absent: ['desktop'] }, + ), + ).toThrow('Unknown Cargo tool member'); +}); + +test('Cargo dependency version checks ignore registry build metadata', () => { + const { manifests, lock, project } = fixture(); + manifests['core/Cargo.toml'].dependencies.serde.version = '=1.0.228'; + for (const item of lock.package) if (item.name === 'serde') item.version = '1.0.228+upstream'; + expect(project().files['Cargo.lock']).toContain('1.0.228+upstream'); +}); + +test('workspace source composition resolves inherited paths and rejects an unadopted incompatible API', () => { + const { workspace, manifests, lock } = fixture(); + Object.assign(workspace.workspace, { + dependencies: { core: { path: 'core', version: '0.2.0' } }, + }); + manifests['sdk/Cargo.toml'].dependencies.core = { workspace: true, optional: true }; + const project = () => + projectCargoWorkspace( + workspace, + lock, + ['sdk'], + (relative) => manifests[relative], + (relative) => relative.endsWith('/src/lib.rs') || relative === 'sdk/build.rs', + ); + const result = project(); + expect(Object.keys(result.facts).sort()).toEqual(['core', 'sdk']); + expect(result.facts.sdk.dependencies.core).toEqual({ + path: '../core', + version: '=0.0.0', + optional: true, + }); + expect( + Bun.TOML.parse(result.files['Cargo.lock']).package.find((item) => item.name === 'core'), + ).toEqual({ name: 'core', version: '0.0.0', dependencies: ['serde'] }); + // Selecting workspace source does not relax the authored public API requirement. + manifests['core/Cargo.toml'].package.version = '1.0.0'; + for (const item of lock.package) if (item.name === 'core') item.version = '1.0.0'; + expect(project).toThrow('Cargo path/version mismatch'); +}); + +test('optional source adapters keep one shared Rust dependency identity throughout their closure', () => { + const { workspace, manifests, lock } = fixture(); + workspace.workspace.members.push('broker'); + manifests['broker/Cargo.toml'] = { + ...manifests['core/Cargo.toml'], + package: { ...manifests['core/Cargo.toml'].package, name: 'broker', version: '0.3.1' }, + dependencies: { core: { path: '../core', version: '0.2.0' } }, + }; + manifests['sdk/Cargo.toml'].dependencies.broker = { + path: '../broker', + version: '0.3.1', + optional: true, + }; + manifests['sdk/Cargo.toml'].features.desktop.push('dep:broker'); + lock.package.find((item) => item.name === 'sdk').dependencies.push('broker'); + lock.package.push({ name: 'broker', version: '0.3.1', dependencies: ['core'] }); + const project = () => + projectCargoWorkspace( + workspace, + lock, + ['sdk'], + (relative) => manifests[relative], + (relative) => relative.endsWith('/src/lib.rs') || relative === 'sdk/build.rs', + ); + const result = project(); + expect(Object.keys(result.facts).sort()).toEqual(['broker', 'core', 'sdk']); + const selected = Bun.TOML.parse(result.files['Cargo.lock']).package; + expect(selected.filter((item) => item.name === 'core')).toHaveLength(1); + expect(selected.find((item) => item.name === 'broker').dependencies).toEqual(['core']); + expect(result.facts.sdk.dependencies.broker.optional).toBe(true); + expect(result.facts.sdk.features.desktop).toContain('dep:broker'); + expect(Bun.TOML.parse(result.files['sdk/Cargo.toml']).dependencies.broker).toEqual({ + path: '../broker', + version: '=0.0.0', + optional: true, + }); + // An adapter API requirement cannot be bypassed by the local source projection. + manifests['sdk/Cargo.toml'].dependencies.broker.version = '=9.0.0'; + expect(project).toThrow('Cargo path/version mismatch'); +}); diff --git a/build_defs/languages/cargo-toolchain.bzl b/build_defs/languages/cargo-toolchain.bzl new file mode 100644 index 000000000..b35a6b72a --- /dev/null +++ b/build_defs/languages/cargo-toolchain.bzl @@ -0,0 +1,41 @@ +"""Declared compiler/linker inputs for conventional installed Cargo tests.""" + +load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES") +load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain") +load("@rules_cc//cc/common:cc_common.bzl", "cc_common") + +def _runfile(ctx, file): + return file.short_path[3:] if file.short_path.startswith("../") else ctx.workspace_name + "/" + file.short_path + +def cargo_test_toolchain(ctx): + cc = find_cc_toolchain(ctx) + features = cc_common.configure_features(ctx = ctx, cc_toolchain = cc, requested_features = ctx.features, unsupported_features = ctx.disabled_features) + files = cc.all_files.to_list() + roots = {} + for file in files: + if file.path.startswith("external/"): + roots["/".join(file.path.split("/")[:2])] = _runfile(ctx, file).split("/")[0] + tools = {} + for name, action in {"linker": ACTION_NAMES.cpp_link_executable, "cc": ACTION_NAMES.c_compile, "cxx": ACTION_NAMES.cpp_compile, "ar": ACTION_NAMES.cpp_link_static_library}.items(): + tool = cc_common.get_tool_for_action(feature_configuration = features, action_name = action) + if not tool.startswith("/"): + matches = [file for file in files if file.path == tool] + if len(matches) != 1: + fail("installed Cargo compiler must be a declared toolchain file: " + tool) + roots[tool] = _runfile(ctx, matches[0]) + tools[name] = tool + link = cc_common.create_link_variables(cc_toolchain = cc, feature_configuration = features, user_link_flags = ctx.fragments.cpp.linkopts, is_linking_dynamic_library = False, is_static_linking_mode = True) + compile_flags = {} + for name, action, flags in [ + ("cflags", ACTION_NAMES.c_compile, ctx.fragments.cpp.copts + ctx.fragments.cpp.conlyopts), + ("cxxflags", ACTION_NAMES.cpp_compile, ctx.fragments.cpp.copts + ctx.fragments.cpp.cxxopts), + ]: + variables = cc_common.create_compile_variables(cc_toolchain = cc, feature_configuration = features, user_compile_flags = flags, use_pic = cc_common.is_enabled(feature_configuration = features, feature_name = "supports_pic")) + compile_flags[name] = cc_common.get_memory_inefficient_command_line(feature_configuration = features, action_name = action, variables = variables) + configuration = ctx.actions.declare_file(ctx.label.name + ".compiler.json") + ctx.actions.write(configuration, json.encode(tools | compile_flags | { + "args": cc_common.get_memory_inefficient_command_line(feature_configuration = features, action_name = ACTION_NAMES.cpp_link_executable, variables = link), + "env": cc_common.get_environment_variables(feature_configuration = features, action_name = ACTION_NAMES.cpp_link_executable, variables = link), + "roots": roots, + })) + return struct(configuration = configuration, files = files) diff --git a/build_defs/languages/carriers/BUILD.bazel b/build_defs/languages/carriers/BUILD.bazel new file mode 100644 index 000000000..b0d10b646 --- /dev/null +++ b/build_defs/languages/carriers/BUILD.bazel @@ -0,0 +1,54 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("@javascript_consumer_packages//:roots.bzl", "CONSUMER_PACKAGES", "CONSUMER_TOOLS") +load("//build_defs/languages/ts:defs.bzl", "npm_dependency_closure") +load("@rules_cc//cc:defs.bzl", "cc_binary") +load("//build_defs/foundation:bun.bzl", "bun_script_test") +load("//build_defs/native:platform_config.bzl", "NATIVE_COMPATIBLE") +load(":defs.bzl", "native_helper_test_data", "native_helper_unit_inputs", "native_installed_sql_test") + +package(default_visibility = ["//visibility:public"]) + +exports_files(glob(["*.bzl", "*.mts"])) + +native_helper_unit_inputs(name = "unit_inputs") + +# A tiny constructed host binary exercises envelope formatting. Installed SQL below +# separately consumes the actual Rust addon and broker, never this fixture. +cc_binary(name = "envelope_fixture", srcs = ["envelope-fixture.c"], target_compatible_with = NATIVE_COMPATIBLE) + +bun_script_test( + name = "package_test", + entry_point = "package.test.mts", + args = ["$(location :unit_inputs)", "$(location :envelope_fixture)"], + data = [":unit_inputs", ":envelope_fixture"] + native_helper_test_data(), + target_compatible_with = NATIVE_COMPATIBLE, + size = "small", +) + +_PG_ROOT = CONSUMER_TOOLS["@oliphaunt/ts"]["pg"] +_PG_PACKAGES = npm_dependency_closure(CONSUMER_PACKAGES, [_PG_ROOT]) + +native_installed_sql_test( + name = "installed_sql_test", + sdk = "//src/native/sdks/ts:npm", + query = "//src/query/ts:npm", + addon = "//src/native/node-addon:npm", + broker = "//src/native/broker:npm", + runtime = select({ + "//build_defs/native:linux_x86_64": "@node_frozen_native//:archive", + "//build_defs/native:linux_aarch64_gnu_2_28": "@node_frozen_native_linux_arm64_gnu//:archive", + "//build_defs/native:macos_arm64": "@node_frozen_native_macos_arm64//:archive", + "//build_defs/native:windows_x64": "@node_frozen_native_windows_x64_msvc//:archive", + }), + artifact_crate = "//src/native/broker:artifact_crate", + server_packages = {"@javascript_consumer_packages//:" + key: key for key in _PG_PACKAGES}, + server_metadata = {key: json.encode(CONSUMER_PACKAGES[key]) for key in _PG_PACKAGES}, + server_roots = {"pg": _PG_ROOT}, + restricted_launcher = select({"//build_defs/native:windows_x64": "//build_defs/native:windows_restricted_process", "//conditions:default": None}), + deno = select({"//build_defs/native:linux_x86_64": "@deno_linux_x64//:deno", "//conditions:default": None}), + contract_hosts = select({"//build_defs/native:linux_x86_64": ["node", "bun", "deno"], "//conditions:default": ["node"]}), + target_compatible_with = NATIVE_COMPATIBLE, + size = "medium", +) + +source_quality_files() diff --git a/build_defs/languages/carriers/cargo-consumer.mts b/build_defs/languages/carriers/cargo-consumer.mts new file mode 100644 index 000000000..6df268a17 --- /dev/null +++ b/build_defs/languages/carriers/cargo-consumer.mts @@ -0,0 +1,203 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { copyFileSync, mkdirSync, readFileSync, renameSync } from 'node:fs'; +import path from 'node:path'; +import { + extractPortableArchiveTree, + readPortableArchiveEntries, +} from '../../../tools/packaging/portable-archive.mts'; +import { + WINDOWS_VC_RUNTIME_RECEIPT, + verifyWindowsVcRuntimeClosure, +} from '../../../tools/packaging/windows-vc-runtime-closure.mts'; +import { type CargoLinkConfiguration, cargoLinkEnvironment } from '../cargo-environment.mts'; + +/** A genuine std-only Cargo consumer; Cargo never constructs a product here. */ +export function verifyInstalledBrokerCargo(inputs: { + archive: string; + cargo: string; + rustc: string; + rustdoc: string; + compiler: string; + runfiles: string; + root: string; + broker: Record; +}): void { + const archive = path.join(inputs.root, 'broker-input.crate'); + copyFileSync(inputs.archive, archive); + const entries = readPortableArchiveEntries(archive); + const manifests = [...entries.keys()].filter((name) => name.endsWith('/Cargo.toml')); + assert.equal(manifests.length, 1, 'broker Cargo carrier must have one conventional manifest'); + const manifestMember = manifests[0]; + assert(manifestMember); + const prefix = path.posix.dirname(manifestMember); + const crate = path.join(inputs.root, 'broker-cargo'); + extractPortableArchiveTree(archive, crate, prefix); + const manifest = Bun.TOML.parse(readFileSync(path.join(crate, 'Cargo.toml'), 'utf8')); + assert.equal(manifest.package.version, inputs.broker.version); + const constants = Object.fromEntries( + [ + ...readFileSync(path.join(crate, 'src/lib.rs'), 'utf8').matchAll( + /pub const ([A-Z_]+): &str = "([^"]+)";/gu, + ), + ].map((match) => [match[1], match[2]]), + ); + assert.equal(constants.PRODUCT, inputs.broker.oliphaunt.brokerHelper); + assert.equal(constants.RELEASE_TARGET, inputs.broker.oliphaunt.target); + assert.equal(constants.EXECUTABLE_RELATIVE_PATH, inputs.broker.oliphaunt.executableRelativePath); + assert(constants.CARGO_TARGET); + const cargoHome = path.join(inputs.root, 'cargo-home'); + const target = path.join(inputs.root, 'cargo-target'); + mkdirSync(cargoHome); + const linkEnv = cargoLinkEnvironment( + JSON.parse(readFileSync(inputs.compiler, 'utf8')) as CargoLinkConfiguration, + inputs.runfiles, + ); + const providerPath = Object.entries(linkEnv).find(([key]) => key.toLowerCase() === 'path')?.[1]; + const env: NodeJS.ProcessEnv = { + ...linkEnv, + CARGO_HOME: cargoHome, + CARGO_TARGET_DIR: target, + CARGO_NET_OFFLINE: 'true', + RUSTC: inputs.rustc, + RUSTDOC: inputs.rustdoc, + PATH: [path.dirname(inputs.rustc), providerPath].filter(Boolean).join(path.delimiter), + HOME: inputs.root, + TMPDIR: inputs.root, + TMP: inputs.root, + TEMP: inputs.root, + OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD: '1', + }; + for (const key of Object.keys(env)) + if (key !== 'PATH' && key.toLowerCase() === 'path') delete env[key]; + if (process.platform === 'win32') { + const systemRoot = Object.entries(process.env).find( + ([key]) => key.toLowerCase() === 'systemroot', + )?.[1]; + assert(systemRoot && path.win32.isAbsolute(systemRoot), 'Windows Cargo requires OS SystemRoot'); + env.SystemRoot = systemRoot; + env.PATH = [env.PATH, path.join(systemRoot, 'System32'), systemRoot].join(path.delimiter); + } + const compilerVersion = Bun.spawnSync([inputs.rustc, '-vV'], { + cwd: crate, + env, + stdout: 'pipe', + stderr: 'pipe', + }); + assert.equal(compilerVersion.exitCode, 0); + assert.equal( + compilerVersion.stdout.toString().match(/^host: (.+)$/mu)?.[1], + constants.CARGO_TARGET, + 'this installed Cargo proof requires the actual declared host to match its native leaf', + ); + const locked = Bun.spawnSync( + [ + inputs.cargo, + 'generate-lockfile', + '--offline', + '--manifest-path', + path.join(crate, 'Cargo.toml'), + ], + { cwd: crate, env, stdout: 'pipe', stderr: 'pipe', timeout: 90_000 }, + ); + assert.equal(locked.exitCode, 0, `closed broker Cargo context: ${locked.stderr.toString()}`); + const check = () => + Bun.spawnSync( + [ + inputs.cargo, + 'check', + '--locked', + '--offline', + '--jobs', + '2', + '--manifest-path', + path.join(crate, 'Cargo.toml'), + ], + { + cwd: crate, + env, + stdout: 'pipe', + stderr: 'pipe', + timeout: 90_000, + }, + ); + const checked = check(); + assert.equal(checked.exitCode, 0, `installed broker Cargo leaf: ${checked.stderr.toString()}`); + const generated = [ + ...new Bun.Glob('**/out/oliphaunt-artifact.toml').scanSync({ cwd: target, onlyFiles: true }), + ]; + assert.equal(generated.length, 1, 'real Cargo build script must emit its artifact manifest'); + const generatedManifest = generated[0]; + assert(generatedManifest); + const artifact = Bun.TOML.parse(readFileSync(path.join(target, generatedManifest), 'utf8')); + assert.equal(artifact.schema, 'oliphaunt-artifact-manifest-v1'); + assert.equal(artifact.product, constants.PRODUCT); + assert.equal(artifact.kind, constants.KIND); + assert.equal(artifact.target, constants.CARGO_TARGET); + assert.equal(artifact.version, manifest.package.version); + const payload = path.join(crate, 'payload'); + const windows = constants.RELEASE_TARGET === 'windows-x64-msvc'; + const expectedMembers = [constants.EXECUTABLE_RELATIVE_PATH]; + if (windows) { + const closure = verifyWindowsVcRuntimeClosure({ + root: payload, + searchRoots: [path.join(payload, 'bin')], + }); + assert(closure.required.length > 0, 'Windows broker must bind its app-local VC runtime'); + expectedMembers.push( + `bin/${WINDOWS_VC_RUNTIME_RECEIPT}`, + ...closure.required.map((name: string) => `bin/${name}`), + ); + } + expectedMembers.sort(); + assert.deepEqual( + [...entries] + .filter( + ([name, entry]) => + entry.isFile && + name.startsWith(`${prefix}/payload/`) && + name !== `${prefix}/payload/sha256`, + ) + .map(([name]) => name.slice(`${prefix}/payload/`.length)) + .sort(), + expectedMembers, + 'broker Cargo payload must contain exactly its executable and declared runtime closure', + ); + assert.deepEqual( + artifact.files.map((file: { relative: string }) => file.relative).sort(), + expectedMembers, + 'real Cargo build script must bind every packaged payload member exactly once', + ); + for (const file of artifact.files) { + const physical = path.join(payload, file.relative); + assert.equal(path.normalize(file.source), physical); + assert.equal(file.executable, file.relative === constants.EXECUTABLE_RELATIVE_PATH); + assert.equal(file.sha256, createHash('sha256').update(readFileSync(physical)).digest('hex')); + } + if (windows) + assert.equal( + readFileSync(path.join(payload, 'sha256'), 'utf8'), + artifact.files + .map((file: { sha256: string; relative: string }) => `${file.sha256} ${file.relative}\n`) + .join(''), + 'Windows Cargo checksum inventory must match its emitted artifact manifest', + ); + for (const relative of expectedMembers) { + const file = path.join(payload, relative); + renameSync(file, `${file}.removed`); + try { + const missing = check(); + assert.notEqual( + missing.exitCode, + 0, + `Cargo accepted missing required broker payload ${relative}`, + ); + assert.match( + missing.stderr.toString(), + /missing packaged oliphaunt-broker payload|read packaged Windows VC runtime receipt/u, + ); + } finally { + renameSync(`${file}.removed`, file); + } + } +} diff --git a/build_defs/languages/carriers/defs.bzl b/build_defs/languages/carriers/defs.bzl new file mode 100644 index 000000000..87ef5a028 --- /dev/null +++ b/build_defs/languages/carriers/defs.bzl @@ -0,0 +1,306 @@ +"""Public native helper envelopes from constructed binaries and canonical rows.""" + +load("@oliphaunt_metadata//:metadata.bzl", "COMPLETED_SUPPLIER_PUBLICATIONS", "NATIVE_HELPER_ARTIFACTS", "PRODUCTS", "PUBLICATION_CARRIERS") +load("@native_cargo_metadata//:cargo.bzl", "CARGO") +load("@aspect_rules_js//npm:providers.bzl", "NpmPackageInfo") +load("@cargo_crates//:defs.bzl", "crate_deps") +load("@rules_cc//cc:find_cc_toolchain.bzl", "use_cc_toolchain") +load("@bazel_skylib//lib:paths.bzl", "paths") +load("//build_defs/extensions:platforms.bzl", "NATIVE_EXTENSION_CONFIGURATION") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_file_action", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/languages:cargo-toolchain.bzl", "cargo_test_toolchain") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") +load("//build_defs/release:supplier.bzl", "rust_shipping_supplier", "shipping_suppliers") + +_CONFIGURATIONS = { + "linux-x64-gnu": "//build_defs/native:linux_x86_64", + "linux-arm64-gnu": "//build_defs/native:linux_aarch64_gnu_2_28", + "macos-arm64": "//build_defs/native:macos_arm64", + "windows-x64-msvc": "//build_defs/native:windows_x64", +} +_HELPERS = [ + "//src/native/node-addon:tools/dependency-license-contract.mts", + "//src/native/broker:tools/broker-dependency-license-contract.mts", + "//:tools/packaging/archive-directory.mts", + "//:tools/packaging/cargo-source-package.mts", + "//:tools/packaging/cargo-manifest.mts", + "//:tools/packaging/npm-trusted-publishing.mts", + "//:tools/packaging/package-archive.mts", + "//:tools/packaging/platform-binary-contract.mts", + "//:tools/packaging/portable-archive.mts", + "//:tools/packaging/release-notices.mts", + "//:tools/packaging/release-directory-safety.mts", + "//:tools/packaging/rust-dependency-license-contract.mts", + "//:tools/packaging/windows-vc-runtime-closure.mts", + "//:tools/packaging/windows-vc-runtime-policy.json", + "//tools/release:platform-compatibility-policy.mts", +] + +def _input_paths(entries, inputs): + result = {} + for target, destination in entries.items(): + for file in target[DefaultInfo].files.to_list(): + name = destination + if destination.endswith("/"): + prefix = target.label.package + "/" + if not file.short_path.startswith(prefix): + fail("native helper source is outside its declared package: " + file.short_path) + name += file.short_path[len(prefix):] + if name in result: + fail("duplicate native helper input " + name) + result[name] = file.path + inputs.append(file) + return result + +def _package_impl(ctx): + inputs = [ctx.file.binary, ctx.file._packager] + ctx.files._helpers + github = ctx.actions.declare_file(ctx.attr.github_out) + npm = ctx.actions.declare_file(ctx.attr.npm_out) + outputs = [github, npm] + specification = json.decode(ctx.attr.metadata) + specification.update({ + "binary": ctx.file.binary.path, + "sources": _input_paths(ctx.attr.sources, inputs), + "legal": _input_paths(ctx.attr.legal, inputs), + "windowsRuntime": {file.basename: file.path for file in ctx.files.windows_runtime}, + "outputs": {"github": github.path, "npm": npm.path}, + }) + inputs += ctx.files.windows_runtime + groups = {"github": depset([github]), "npm": depset([npm])} + if ctx.attr.cargo_out: + cargo = ctx.actions.declare_file(ctx.attr.cargo_out) + specification["outputs"]["cargo"] = cargo.path + outputs.append(cargo) + groups["cargo"] = depset([cargo]) + manifest = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(manifest, json.encode(specification)) + arguments = ctx.actions.args() + arguments.add(manifest) + bun_file_action(ctx, entry_point = ctx.file._packager, source_files = [ctx.file._packager] + ctx.files._helpers, arguments = [arguments], inputs = depset(inputs + [manifest]), outputs = outputs, mnemonic = "NativeHelperEnvelope") + return [DefaultInfo(files = depset(outputs)), OutputGroupInfo(**groups)] + +_native_helper_package = rule( + implementation = _package_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = { + "binary": attr.label(allow_single_file = True, mandatory = True), + "metadata": attr.string(mandatory = True), + "sources": attr.label_keyed_string_dict(allow_files = True), + "legal": attr.label_keyed_string_dict(allow_files = True), + "windows_runtime": attr.label_list(allow_files = True), + "github_out": attr.string(mandatory = True), + "npm_out": attr.string(mandatory = True), + "cargo_out": attr.string(), + "_packager": attr.label(default = Label("//build_defs/languages/carriers:package.mts"), allow_single_file = True), + "_helpers": attr.label_list(default = [Label(label) for label in _HELPERS], allow_files = True), + }, +) + +def _compiled_suppliers(name, path_dependencies): + inputs = [] + for dependency, declaration in CARGO[native.package_name()]["dependencies"].items(): + rows = [row for row in PUBLICATION_CARRIERS if row["ecosystem"] == "cargo" and row["name"] == dependency] + if not rows: + continue + if len(rows) != 1: + fail("native helper supplier must identify one conventional Cargo owner: " + dependency) + row = rows[0] + supplier = name + "_" + dependency.replace("-", "_") + if type(declaration) == "dict" and "path" in declaration: + source = paths.normalize(paths.join(native.package_name(), declaration["path"])) + owner = PRODUCTS[row["product"]] + if source != owner["path"] or source not in CARGO or CARGO[source]["name"] != dependency or CARGO[source]["version"] != owner["version"]: + fail("native helper path supplier differs from its conventional release owner: " + dependency) + if dependency not in path_dependencies: + fail("native helper path supplier needs the same declared compiler dependency: " + dependency) + rust_shipping_supplier(name = supplier, producer = path_dependencies[dependency], owner = "@oliphaunt_metadata//:product_" + row["product"], + current_source = True, source_package = source, configuration = NATIVE_EXTENSION_CONFIGURATION) + inputs.append(":" + supplier) + continue + version = declaration if type(declaration) == "string" else declaration["version"] + key = row["product"] + "@" + version.removeprefix("=") + producers = crate_deps([dependency], package_name = native.package_name()) + if len(producers) != 1: + fail("native helper supplier must identify one actual registry crate target") + rust_shipping_supplier(name = supplier, producer = producers[0], owner = "@oliphaunt_metadata//:product_" + row["product"], + origin = json.encode({"kind": "completed-publication", "publication": COMPLETED_SUPPLIER_PUBLICATIONS[key], "artifact": "cargo:" + dependency}) if key in COMPLETED_SUPPLIER_PUBLICATIONS else "") + inputs.append(":" + supplier) + shipping_suppliers(name = name, inputs = inputs) + +def native_helper_carriers(product, binary, qualification, path_dependencies = {}): + _compiled_suppliers("native_compiled_suppliers", path_dependencies) + suppliers = ":native_compiled_suppliers" + descriptor = PRODUCTS[product] + rows = [row for row in NATIVE_HELPER_ARTIFACTS if row["product"] == product and row["kind"] in ["broker-helper", "node-direct-addon"]] + carriers = [row for row in PUBLICATION_CARRIERS if row["product"] == product] + metadata = {} + sources = {} + github_names = {} + physical_targets = {} + npm_names = {} + npm_identities = {} + npm_targets = {} + npm_roles = {} + cargo_names = {} + cargo_identities = {} + cargo_roles = {} + compatible = {} + for artifact in rows: + target = artifact["target"] + if target not in _CONFIGURATIONS: + fail("no native helper configuration for declared target " + target) + configuration = _CONFIGURATIONS[target] + metadata[configuration] = json.encode({"product": product, "version": descriptor["version"], "artifact": artifact, "carriers": carriers}) + npm = [row for row in carriers if row["ecosystem"] == "npm" and row["name"] == artifact["npm_package"]] + if len(npm) != 1: + fail("canonical npm helper identity is not unique for " + target) + npm = npm[0] + directory = "packages/" + npm["target"] + sources[configuration] = {directory + "/package.json": "package.json", directory + "/README.md": "README.md"} + github_names[configuration] = artifact["asset"].replace("{version}", descriptor["version"]) + physical_targets[configuration] = target + npm_names[configuration] = npm["name"].replace("@", "").replace("/", "-") + "-" + npm["version"] + ".tgz" + npm_identities[configuration] = npm["name"] + npm_targets[configuration] = npm["target"] + npm_roles[configuration] = npm["role"] + compatible[configuration] = [] + if product == "oliphaunt-broker": + cargo = [row for row in carriers if row["ecosystem"] == "cargo" and row["target"] == target and row["role"] != "facade"] + if len(cargo) != 1: + fail("canonical Cargo helper identity is not unique for " + target) + cargo = cargo[0] + sources[configuration].update({file: "cargo/" + file[len("crates/" + target + "/"):] for file in native.glob(["crates/" + target + "/**"], exclude = ["**/target/**"])}) + cargo_names[configuration] = cargo["name"] + "-" + cargo["version"] + ".crate" + cargo_identities[configuration] = cargo["name"] + cargo_roles[configuration] = cargo["role"] + legal = {"//:" + name: name for name in ["LICENSE", "THIRD_PARTY_NOTICES.md", "Cargo.lock"]} + legal["dependency-licenses.json"] = descriptor["path"] + "/dependency-licenses.json" + legal.update({file: descriptor["path"] + "/" + file for file in native.glob(["dependency-license-blobs/*.base64"])}) + _native_helper_package( + name = "native_carriers", binary = binary, metadata = select(metadata), sources = select(sources), legal = legal, + windows_runtime = select({"//build_defs/native:windows_x64": ["@native_msvc_sdk//:runtime_dlls"], "//conditions:default": []}), + github_out = select(github_names), npm_out = select(npm_names), cargo_out = select(cargo_names) if cargo_names else "", + target_compatible_with = select(compatible | {"//conditions:default": ["@platforms//:incompatible"]}), + ) + native.filegroup(name = "github_archive", srcs = [":native_carriers"], output_group = "github") + native.filegroup(name = "npm", srcs = [":native_carriers"], output_group = "npm") + shipping_package(name = "native_github_shipping", owner = "@oliphaunt_metadata//:product_" + product, artifacts = [":github_archive"], ecosystem = "github", package_name = select(github_names), configuration = select(physical_targets), role = "github-release-asset", suppliers = suppliers) + shipping_package(name = "native_npm_shipping", owner = "@oliphaunt_metadata//:product_" + product, artifacts = [":npm"], ecosystem = "npm", package_name = select(npm_identities), configuration = select(npm_targets), role = select(npm_roles), suppliers = suppliers) + shipping = [":native_github_shipping", ":native_npm_shipping"] + if cargo_names: + native.filegroup(name = "artifact_crate", srcs = [":native_carriers"], output_group = "cargo") + shipping_package(name = "native_cargo_shipping", owner = "@oliphaunt_metadata//:product_" + product, artifacts = [":artifact_crate"], ecosystem = "cargo", package_name = select(cargo_identities), configuration = select(physical_targets), role = select(cargo_roles), suppliers = suppliers) + shipping.append(":native_cargo_shipping") + shipping_export(name = "native_shipping_export", packages = shipping, qualification = qualification, testonly = True) + +def _unit_inputs_impl(ctx): + inputs = [] + sources = _input_paths(ctx.attr.sources, inputs) + legal = _input_paths(ctx.attr.legal, inputs) + inputs += ctx.files.windows_runtime + cases = [] + for metadata in json.decode(ctx.attr.metadata): + owner = PRODUCTS[metadata["product"]]["path"] + npm = [row for row in metadata["carriers"] if row["ecosystem"] == "npm" and row["name"] == metadata["artifact"]["npm_package"]][0] + directory = owner + "/packages/" + npm["target"] + entries = {"package.json": sources[directory + "/package.json"], "README.md": sources[directory + "/README.md"]} + if metadata["product"] == "oliphaunt-broker": + prefix = owner + "/crates/" + metadata["artifact"]["target"] + "/" + entries.update({"cargo/" + name[len(prefix):]: file for name, file in sources.items() if name.startswith(prefix)}) + metadata.update({ + "sources": entries, + "legal": {name: file for name, file in legal.items() if name in ["LICENSE", "THIRD_PARTY_NOTICES.md", "Cargo.lock"] or name.startswith(owner + "/")}, + "windowsRuntime": {file.basename: file.short_path for file in ctx.files.windows_runtime} if metadata["artifact"]["target"] == "windows-x64-msvc" else {}, + }) + cases.append(metadata) + output = ctx.actions.declare_file(ctx.label.name + ".json") + ctx.actions.write(output, json.encode(cases)) + return [DefaultInfo(files = depset([output]), runfiles = ctx.runfiles(files = inputs + [output]))] + +_native_helper_unit_inputs = rule( + implementation = _unit_inputs_impl, + attrs = {"metadata": attr.string(mandatory = True), "sources": attr.label_keyed_string_dict(allow_files = True), "legal": attr.label_keyed_string_dict(allow_files = True), "windows_runtime": attr.label_list(allow_files = True)}, +) + +def native_helper_unit_inputs(name): + sources = {} + legal = {"//:" + file: file for file in ["LICENSE", "THIRD_PARTY_NOTICES.md", "Cargo.lock"]} + for product in ["oliphaunt-node-direct", "oliphaunt-broker"]: + owner = PRODUCTS[product]["path"] + sources["//" + owner + ":carrier_template_sources"] = owner + "/" + legal["//" + owner + ":carrier_legal_sources"] = owner + "/" + _native_helper_unit_inputs(name = name, sources = sources, legal = legal, windows_runtime = select({"//build_defs/native:windows_x64": ["@native_msvc_sdk//:runtime_dlls"], "//conditions:default": []}), metadata = json.encode([ + {"product": row["product"], "version": PRODUCTS[row["product"]]["version"], "artifact": row, "carriers": [carrier for carrier in PUBLICATION_CARRIERS if carrier["product"] == row["product"]]} + for row in NATIVE_HELPER_ARTIFACTS if row["kind"] in ["broker-helper", "node-direct-addon"] + ])) + +def native_helper_test_data(): + return _HELPERS + ["package.mts"] + +def _runfile(ctx, file): + return file.short_path[3:] if file.short_path.startswith("../") else ctx.workspace_name + "/" + file.short_path + +def _installed_sql_impl(ctx): + node = ctx.toolchains["@rules_nodejs//nodejs:toolchain_type"].nodeinfo.node + if not node: + fail("Installed native SDK consumers require the pinned Node executable") + rust = ctx.toolchains["@rules_rust//rust:toolchain_type"] + if not rust.cargo: + fail("Installed broker Cargo leaf requires the pinned Cargo executable") + if "deno" in ctx.attr.contract_hosts and not ctx.executable.deno: + fail("Installed native SDK contracts require the declared pinned Deno executable") + cc = cargo_test_toolchain(ctx) + server_packages = {} + server_files = [ctx.file._server_contract] + for target, identity in ctx.attr.server_packages.items(): + package = target[NpmPackageInfo] + row = json.decode(ctx.attr.server_metadata[identity]) + if package.package != row["package"] or package.version != row["version"] or package.src.is_directory: + fail("Installed server driver differs from its declared npm archive identity") + server_packages[identity] = dict(row, archive = _runfile(ctx, package.src)) + server_files.append(package.src) + if sorted(server_packages.keys()) != sorted(ctx.attr.server_metadata.keys()): + fail("Installed server driver archive closure differs from its metadata") + server = ctx.actions.declare_file(ctx.label.name + ".server.json") + ctx.actions.write(server, json.encode({ + "contract": _runfile(ctx, ctx.file._server_contract), + "packages": server_packages, + "roots": ctx.attr.server_roots, + "restrictedLauncher": _runfile(ctx, ctx.executable.restricted_launcher) if ctx.executable.restricted_launcher else None, + })) + server_files += [ctx.executable.restricted_launcher] if ctx.executable.restricted_launcher else [] + arguments = [ctx.file.sdk, ctx.file.query, ctx.file.addon, ctx.file.broker, ctx.file.runtime, node, ctx.file._consumer, ctx.file.artifact_crate, rust.cargo, rust.rustc, rust.rust_doc, cc.configuration, + ctx.file._contract_entry, ctx.file._contract_assertions, ctx.executable.deno or "", json.encode(ctx.attr.contract_hosts), server] + files = arguments[:14] + [server] + server_files + ([ctx.executable.deno] if ctx.executable.deno else []) + ctx.files._helpers + rust.all_files.to_list() + cc.files + return bun_test_entrypoint(ctx, runner = ctx.file._runner, arguments = arguments, files = files, runfiles_argument = True, source_files = [ctx.file._runner] + ctx.files._helpers, + additional_runfiles = ctx.attr.deno[DefaultInfo].default_runfiles if ctx.attr.deno else None) + +_native_installed_sql_test = rule( + implementation = _installed_sql_impl, + test = True, + fragments = ["cpp"], + toolchains = BUN_SOURCE_TOOLCHAINS + ["@rules_nodejs//nodejs:toolchain_type", "@rules_rust//rust:toolchain_type"] + use_cc_toolchain(), + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "sdk": attr.label(mandatory = True, allow_single_file = [".tgz"]), + "query": attr.label(mandatory = True, allow_single_file = [".tgz"]), + "addon": attr.label(mandatory = True, allow_single_file = [".tgz"]), + "broker": attr.label(mandatory = True, allow_single_file = [".tgz"]), + "runtime": attr.label(mandatory = True, allow_single_file = [".tgz"]), + "artifact_crate": attr.label(mandatory = True, allow_single_file = [".crate"]), + "deno": attr.label(executable = True, cfg = "exec", allow_files = True), + "contract_hosts": attr.string_list(default = ["node"]), + "server_packages": attr.label_keyed_string_dict(providers = [NpmPackageInfo], mandatory = True), + "server_metadata": attr.string_dict(mandatory = True), + "server_roots": attr.string_dict(mandatory = True), + "restricted_launcher": attr.label(executable = True, cfg = "target", allow_files = True), + "_server_contract": attr.label(default = Label("//src/native/sdks/ts:src/__tests__/native-server-smoke.ts"), allow_single_file = True), + "_contract_entry": attr.label(default = Label("//src/native/sdks/ts:src/__tests__/native-smoke.mts"), allow_single_file = True), + "_contract_assertions": attr.label(default = Label("//src/native/sdks/ts:src/__tests__/native-direct-contract.mts"), allow_single_file = True), + "_runner": attr.label(default = Label("//build_defs/languages/carriers:installed-sql.test.mts"), allow_single_file = True), + "_consumer": attr.label(default = Label("//build_defs/languages/carriers:sql-consumer.mts"), allow_single_file = True), + "_helpers": attr.label_list(default = [Label("//:tools/packaging/portable-archive.mts"), Label("//:tools/packaging/windows-vc-runtime-closure.mts"), Label("//:tools/packaging/windows-vc-runtime-policy.json"), Label("//build_defs/native:host-runtime-test-helpers.mts"), Label("//build_defs/languages:cargo-environment.mts"), Label("//build_defs/languages/carriers:cargo-consumer.mts")], allow_files = True), + }), +) + +def native_installed_sql_test(name, args = [], **kwargs): + _native_installed_sql_test(name = name, args = bun_test_entrypoint_args(name) + args, **kwargs) diff --git a/build_defs/languages/carriers/envelope-fixture.c b/build_defs/languages/carriers/envelope-fixture.c new file mode 100644 index 000000000..78f2de106 --- /dev/null +++ b/build_defs/languages/carriers/envelope-fixture.c @@ -0,0 +1 @@ +int main(void) { return 0; } diff --git a/build_defs/languages/carriers/installed-sql.test.mts b/build_defs/languages/carriers/installed-sql.test.mts new file mode 100644 index 000000000..84eb3fbb5 --- /dev/null +++ b/build_defs/languages/carriers/installed-sql.test.mts @@ -0,0 +1,319 @@ +import assert from 'node:assert/strict'; +import { + copyFileSync, + mkdirSync, + mkdtempSync, + readFileSync, + realpathSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + extractPortableArchiveTree, + readPortableArchiveEntries, +} from '../../../tools/packaging/portable-archive.mts'; +import { hostRuntimeEnvironment } from '../../native/host-runtime-test-helpers.mts'; +import { verifyInstalledBrokerCargo } from './cargo-consumer.mts'; + +const [ + sdk, + query, + addon, + broker, + runtime, + node, + source, + artifactCrate, + cargo, + rustc, + rustdoc, + compiler, + contractEntry, + contractAssertions, + deno, + contractHostsJson, + serverSpecification, + runfiles, +] = process.argv.slice(2); +assert( + sdk && + query && + addon && + broker && + runtime && + node && + source && + artifactCrate && + cargo && + rustc && + rustdoc && + compiler && + contractEntry && + contractAssertions && + contractHostsJson && + serverSpecification && + runfiles, + 'expected actual npm carriers and pinned Node consumer tools', +); +const root = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'installed-native-sdk-')); +try { + const packages = new Map }>(); + for (const [index, declaredArchive] of [sdk, query, addon, broker, runtime].entries()) { + const archive = path.join(root, `${index}-input.tgz`); + copyFileSync(declaredArchive, archive); + const entries = readPortableArchiveEntries(archive); + assert( + [...entries.keys()].every((name) => name === 'package' || name.startsWith('package/')), + 'npm archive must contain only its package root', + ); + const metadata = entries.get('package/package.json'); + assert(metadata?.isFile, 'npm carrier missing conventional package.json'); + const manifest = JSON.parse(metadata.data().toString()); + assert(typeof manifest.name === 'string' && /^@oliphaunt\/[a-z0-9-]+$/u.test(manifest.name)); + assert(!packages.has(manifest.name), 'installed carrier identity duplicated'); + const directory = path.join(root, 'node_modules', manifest.name); + extractPortableArchiveTree(archive, directory, 'package'); + packages.set(manifest.name, { directory, manifest }); + } + const sdkPackage = packages.get('@oliphaunt/ts'); + const queryPackage = packages.get('@oliphaunt/ts-query'); + assert(sdkPackage && queryPackage); + assert.equal( + queryPackage.manifest.version, + sdkPackage.manifest.dependencies[queryPackage.manifest.name], + ); + const optional = [...packages.values()].filter(({ manifest }) => manifest.optional === true); + assert.equal(optional.length, 3, 'the runtime, Node addon and broker packages must be installed'); + for (const { manifest } of optional) + assert.equal( + manifest.version, + sdkPackage.manifest.optionalDependencies[manifest.name], + `SDK optional requirement differs from installed ${manifest.name}`, + ); + const brokerPackage = optional.find(({ manifest }) => manifest.oliphaunt?.brokerHelper); + assert(brokerPackage, 'actual installed broker package missing'); + verifyInstalledBrokerCargo({ + archive: artifactCrate, + cargo, + rustc, + rustdoc, + compiler, + runfiles, + root, + broker: brokerPackage.manifest, + }); + const held = optional.find(({ manifest }) => manifest.oliphaunt?.libraryRelativePath); + assert(held, 'held native runtime package missing'); + assert.equal( + held.manifest.version, + sdkPackage.manifest.oliphaunt.liboliphauntVersion, + 'runtime must retain the SDK conventional held pin', + ); + const runtimeDirectory = path.join(held.directory, held.manifest.oliphaunt.runtimeRelativePath); + const env = hostRuntimeEnvironment(runtimeDirectory, root); + const libraryDirectory = path.dirname( + path.join(held.directory, held.manifest.oliphaunt.libraryRelativePath), + ); + if (process.platform === 'win32') env.PATH = [libraryDirectory, env.PATH].join(path.delimiter); + else { + const loader = process.platform === 'darwin' ? 'DYLD_LIBRARY_PATH' : 'LD_LIBRARY_PATH'; + env[loader] = [libraryDirectory, env[loader]].join(path.delimiter); + } + for (const key of Object.keys(env)) + if (/^(?:NODE_|BUN_|RUNFILES|TEST_SRCDIR)/iu.test(key)) delete env[key]; + env.NODE_PATH = ''; + env.NODE_OPTIONS = ''; + env.TMPDIR = path.join(root, 'tmp'); + env.TMP = env.TMPDIR; + env.TEMP = env.TMPDIR; + mkdirSync(env.TMPDIR); + const consumer = path.join(root, 'consumer.mjs'); + writeFileSync( + consumer, + new Bun.Transpiler({ loader: 'ts', target: 'node' }).transformSync( + readFileSync(source, 'utf8'), + ), + ); + const run = (mode: string, phase: string) => + Bun.spawnSync([node, consumer, mode, phase, path.join(root, `${mode}-database`)], { + cwd: root, + env, + stdout: 'pipe', + stderr: 'pipe', + timeout: 90_000, + }); + for (const mode of ['direct', 'broker']) + for (const phase of ['write', 'read']) { + const result = run(mode, phase); + assert.equal( + result.exitCode, + 0, + `${mode}/${phase}: ${result.stderr.toString()}\n${result.stdout.toString()}`, + ); + } + for (const package_ of optional) { + const metadata = path.join(package_.directory, 'package.json'); + writeFileSync(metadata, JSON.stringify({ ...package_.manifest, version: '99.0.0' })); + try { + const result = run(package_.manifest.oliphaunt?.brokerHelper ? 'broker' : 'direct', 'read'); + assert.notEqual( + result.exitCode, + 0, + 'SDK accepted an incompatible installed optional version', + ); + assert.match(result.stderr.toString(), /version 99\.0\.0 does not match @oliphaunt\/ts/iu); + } finally { + writeFileSync(metadata, JSON.stringify(package_.manifest)); + } + } + const contractHosts = JSON.parse(contractHostsJson) as string[]; + assert( + Array.isArray(contractHosts) && + contractHosts.length > 0 && + new Set(contractHosts).size === contractHosts.length && + contractHosts.every((host) => ['node', 'bun', 'deno'].includes(host)), + 'native SDK contracts require explicit unique supported hosts', + ); + if (contractHosts.includes('deno')) assert(deno, 'pinned Deno is required'); + const contracts = path.join(root, 'contracts'); + mkdirSync(contracts); + const contractDatabases = path.join(root, 'contract-databases'); + mkdirSync(contractDatabases); + const entry = path.join(contracts, 'native-smoke.mts'); + copyFileSync(contractEntry, entry); + copyFileSync(contractAssertions, path.join(contracts, 'native-direct-contract.mts')); + for (const host of contractHosts) { + const command = + host === 'node' + ? [node, '--experimental-strip-types', entry] + : host === 'bun' + ? [process.execPath, '--no-install', '--no-env-file', entry] + : [deno, 'run', '--no-config', '--node-modules-dir=manual', '--allow-all', entry]; + for (const phase of ['source', 'restored']) { + const result = Bun.spawnSync(command, { + cwd: root, + env: { + ...env, + OLIPHAUNT_SMOKE_SDK: path.join(sdkPackage.directory, 'lib/index.js'), + OLIPHAUNT_SMOKE_ROOT: contractDatabases, + OLIPHAUNT_SMOKE_HOST: host, + OLIPHAUNT_SMOKE_PHASE: phase, + LIBOLIPHAUNT_PATH: path.join(held.directory, held.manifest.oliphaunt.libraryRelativePath), + OLIPHAUNT_INSTALL_DIR: runtimeDirectory, + OLIPHAUNT_RUNTIME_DIR: runtimeDirectory, + OLIPHAUNT_BROKER: path.join( + brokerPackage.directory, + brokerPackage.manifest.oliphaunt.executableRelativePath, + ), + }, + stdout: 'pipe', + stderr: 'pipe', + timeout: 90_000, + killSignal: 'SIGKILL', + }); + assert.equal( + result.exitCode, + 0, + `original native SDK contract ${host}/${phase}: ${result.stderr.toString()}\n${result.stdout.toString()}`, + ); + } + } + const server = JSON.parse(readFileSync(serverSpecification, 'utf8')) as { + contract: string; + packages: Record< + string, + { package: string; version: string; dependencies: Record; archive: string } + >; + roots: Record; + restrictedLauncher: string | null; + }; + const stores: Record = {}; + for (const [identity, row] of Object.entries(server.packages)) { + const directory = path.join(root, '.server-packages', identity, 'node_modules', row.package); + extractPortableArchiveTree( + realpathSync(path.join(runfiles, row.archive)), + directory, + 'package', + ); + const manifest = JSON.parse(readFileSync(path.join(directory, 'package.json'), 'utf8')); + assert.equal(manifest.name, row.package); + assert.equal(manifest.version, row.version); + stores[identity] = directory; + } + for (const [identity, row] of Object.entries(server.packages)) + for (const [name, dependency] of Object.entries(row.dependencies)) { + assert(stores[dependency], 'missing installed server driver dependency ' + name); + const destination = path.join(stores[identity], 'node_modules', name); + mkdirSync(path.dirname(destination), { recursive: true }); + symlinkSync( + stores[dependency], + destination, + process.platform === 'win32' ? 'junction' : 'dir', + ); + } + assert.deepEqual(Object.keys(server.roots), ['pg']); + for (const [name, identity] of Object.entries(server.roots)) { + assert(stores[identity], 'missing installed server driver ' + name); + symlinkSync( + stores[identity], + path.join(root, 'node_modules', name), + process.platform === 'win32' ? 'junction' : 'dir', + ); + } + const serverContract = path.join(contracts, 'native-server-smoke.mts'); + copyFileSync(path.join(runfiles, server.contract), serverContract); + const serverEntry = path.join(root, 'server-consumer.mjs'); + writeFileSync( + serverEntry, + "import { assertNativeServerContract } from './contracts/native-server-smoke.mts';\nawait assertNativeServerContract(process.argv[2]);\n", + ); + const serverCommand = [ + node, + '--experimental-strip-types', + serverEntry, + path.join(runtimeDirectory, 'bin', process.platform === 'win32' ? 'postgres.exe' : 'postgres'), + ]; + if (process.platform === 'win32') { + assert(server.restrictedLauncher, 'Windows SDK server smoke requires its restricted launcher'); + const launcherDirectory = path.join(root, 'server-launcher'); + mkdirSync(launcherDirectory); + const launcher = path.join(launcherDirectory, 'restricted server smoke.exe'); + copyFileSync(path.join(runfiles, server.restrictedLauncher), launcher); + serverCommand.unshift(launcher); + } + const serverResult = Bun.spawnSync(serverCommand, { + cwd: root, + env: { + ...env, + OLIPHAUNT_SMOKE_SDK: path.join(sdkPackage.directory, 'lib/index.js'), + OLIPHAUNT_POSTGRES_TOOL_DIR: path.join(runtimeDirectory, 'bin'), + }, + stdin: 'ignore', + stdout: 'pipe', + stderr: 'pipe', + timeout: 90_000, + killSignal: 'SIGKILL', + }); + assert.equal( + serverResult.exitCode, + 0, + 'original installed SDK server contract: ' + + serverResult.stderr.toString() + + '\n' + + serverResult.stdout.toString(), + ); + console.log( + 'Original installed native SDK server: parameterized SQL, two fresh roots, distinct system identifiers, close: PASS', + ); + console.log( + `Original installed native SDK contracts: ${contractHosts.join(', ')} source/restored: PASS`, + ); + console.log( + 'Installed public native SDK: default optional resolution, held runtime, direct/broker init + process reopen, broker reap, three incompatible-version rejections: PASS', + ); +} finally { + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/languages/carriers/package.mts b/build_defs/languages/carriers/package.mts new file mode 100644 index 000000000..c39372145 --- /dev/null +++ b/build_defs/languages/carriers/package.mts @@ -0,0 +1,393 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + copyFileSync, + mkdirSync, + mkdtempSync, + readFileSync, + realpathSync, + rmSync, + statSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { createBrokerDependencyLicenseContract } from '../../../src/native/broker/tools/broker-dependency-license-contract.mts'; +import { createNodeDependencyLicenseContract } from '../../../src/native/node-addon/tools/dependency-license-contract.mts'; +import { archiveDirectory } from '../../../tools/packaging/archive-directory.mts'; +import { packageGeneratedCargoSource } from '../../../tools/packaging/cargo-source-package.mts'; +import { validateNpmTrustedPublishingManifest } from '../../../tools/packaging/npm-trusted-publishing.mts'; +import { createDeterministicTar } from '../../../tools/packaging/package-archive.mts'; +import { inspectPlatformBinaryEntries } from '../../../tools/packaging/platform-binary-contract.mts'; +import { + canonicalGzipSync, + readPortableArchiveEntries, +} from '../../../tools/packaging/portable-archive.mts'; +import { + assertReleaseNoticesInEntries, + stageReleaseNotices, +} from '../../../tools/packaging/release-notices.mts'; +import { + renderWindowsVcRuntimeSourceReceipt, + stageWindowsVcRuntime, + WINDOWS_VC_RUNTIME_RECEIPT, +} from '../../../tools/packaging/windows-vc-runtime-closure.mts'; + +export interface CarrierRow { + product: string; + ecosystem: string; + name: string; + version: string; + target: string | null; + role: string; +} +export interface HelperArtifact { + product: string; + target: string; + triple: string; + asset: string; + kind: string; + library_relative_path?: string; + executable_relative_path?: string; + npm_package: string; + npm_os: string; + npm_cpu: string; + npm_libc?: string | null; +} +export interface HelperPackageSpec { + product: string; + version: string; + artifact: HelperArtifact; + carriers: CarrierRow[]; + binary: string; + sources: Record; + legal: Record; + windowsRuntime: Record; + outputs: { github: string; npm: string; cargo?: string }; +} + +function copy(source: string, destination: string, mode = 0o644): void { + const physical = realpathSync(source); + assert(statSync(physical).isFile(), `expected regular declared input ${source}`); + mkdirSync(path.dirname(destination), { recursive: true }); + copyFileSync(physical, destination); + chmodSync(destination, mode); +} +function member(root: string, name: string): string { + assert( + name && + !name.includes('\\') && + !path.posix.isAbsolute(name) && + name.split('/').every((part) => part && part !== '.' && part !== '..'), + `unsafe carrier member ${name}`, + ); + return path.join(root, ...name.split('/')); +} +const digest = (data: Buffer) => createHash('sha256').update(data).digest('hex'); + +export function validateHelperNpmManifest( + manifest: Record, + spec: Pick, + payloadLicense: string, +): CarrierRow { + const row = spec.carriers.find( + (candidate) => candidate.ecosystem === 'npm' && candidate.name === spec.artifact.npm_package, + ); + assert(row, `canonical npm carrier missing for ${spec.artifact.target}`); + assert.equal(row.product, spec.product, 'npm product disagrees with canonical carrier'); + assert.equal(row.version, spec.version, 'npm version disagrees with canonical carrier'); + validateNpmTrustedPublishingManifest(manifest, row.name); + assert.equal(manifest.name, row.name, 'npm identity disagrees with canonical carrier'); + assert.equal( + manifest.version, + row.version, + 'npm version disagrees with conventional product version', + ); + assert.equal( + manifest.license, + payloadLicense, + 'npm payload license disagrees with audited dependency closure', + ); + assert.equal( + manifest.oliphaunt?.target, + spec.artifact.target, + 'npm physical target disagrees with its constructed binary', + ); + assert.deepEqual(manifest.os, [spec.artifact.npm_os]); + assert.deepEqual(manifest.cpu, [spec.artifact.npm_cpu]); + if (spec.artifact.npm_libc) assert.deepEqual(manifest.libc, [spec.artifact.npm_libc]); + else assert.equal(manifest.libc, undefined); + assert( + Array.isArray(manifest.files) && + manifest.files.every((name: unknown) => typeof name === 'string' && name), + 'npm files allowlist is required', + ); + assert.equal( + new Set(manifest.files).size, + manifest.files.length, + 'npm files allowlist repeats members', + ); + for (const name of [ + 'LICENSE', + 'THIRD_PARTY_NOTICES.md', + 'THIRD_PARTY_LICENSES', + spec.artifact.kind === 'node-direct-addon' ? 'prebuilds' : 'bin', + ]) + assert(manifest.files.includes(name), `npm files allowlist omits ${name}`); + assert.equal( + manifest.exports?.['./package.json'], + './package.json', + 'SDK optional-package resolution requires the conventional package.json export', + ); + if (spec.artifact.kind === 'node-direct-addon') + assert.equal(manifest.exports?.['./oliphaunt_node.node'], './prebuilds/oliphaunt_node.node'); + else { + assert.equal(manifest.oliphaunt?.brokerHelper, spec.product); + assert.equal( + manifest.oliphaunt?.executableRelativePath, + spec.artifact.executable_relative_path, + ); + assert.deepEqual(manifest.publishConfig?.executableFiles, [ + `./${spec.artifact.executable_relative_path}`, + ]); + } + return row; +} + +function legalContract(spec: HelperPackageSpec, sourceRoot: string) { + const owner = + spec.product === 'oliphaunt-node-direct' ? 'src/native/node-addon' : 'src/native/broker'; + const contract = + spec.product === 'oliphaunt-node-direct' + ? createNodeDependencyLicenseContract(sourceRoot) + : createBrokerDependencyLicenseContract(sourceRoot); + const required = [ + 'LICENSE', + 'THIRD_PARTY_NOTICES.md', + 'Cargo.lock', + `${owner}/dependency-licenses.json`, + ]; + for (const name of required) assert(spec.legal[name], `missing declared legal source ${name}`); + for (const [name, source] of Object.entries(spec.legal)) { + assert( + required.includes(name) || name.startsWith(`${owner}/dependency-license-blobs/`), + `unexpected legal source ${name}`, + ); + assert( + contract.hasSafeRustSourceFilesystemMode(statSync(realpathSync(source)).mode), + `unsafe legal source mode ${name}`, + ); + copy(source, member(sourceRoot, name)); + } + contract.loadRustDependencyLicenseContract({ auditLock: true }); + return contract; +} + +function archiveEntries(file: string, prefix = '') { + return new Map( + [...readPortableArchiveEntries(file)].map(([name, entry]) => { + assert(!prefix || name.startsWith(`${prefix}/`), `member outside ${prefix}: ${name}`); + return [prefix ? name.slice(prefix.length + 1) : name, entry]; + }), + ); +} + +/** One bounded envelope action: the caller has already constructed the binary. */ +export async function packageNativeHelper(spec: HelperPackageSpec): Promise { + assert( + ['oliphaunt-node-direct', 'oliphaunt-broker'].includes(spec.product), + 'unsupported native helper product', + ); + assert.equal(spec.artifact.product, spec.product); + assert( + spec.artifact.asset.includes('{version}'), + 'canonical GitHub asset must carry the version placeholder', + ); + const root = mkdtempSync(path.join(tmpdir(), 'native-helper-carrier-')); + try { + const sourceRoot = path.join(root, 'sources'); + const contract = legalContract(spec, sourceRoot); + const profile = spec.artifact.kind === 'node-direct-addon' ? 'node-direct-addon' : 'broker'; + const notices = { profile, sourceRoot }; + const target = spec.artifact.target; + const github = path.join(root, 'github'); + const binaryMember = + spec.artifact.library_relative_path ?? spec.artifact.executable_relative_path; + assert(binaryMember, 'canonical artifact omitted its binary member'); + copy(spec.binary, member(github, binaryMember), 0o755); + const windows = target === 'windows-x64-msvc'; + assert( + windows || Object.keys(spec.windowsRuntime).length === 0, + 'non-Windows helper cannot carry CRT files', + ); + const windowsSource = path.join(root, 'crt-source'); + if (windows) { + for (const [name, source] of Object.entries(spec.windowsRuntime)) { + assert.equal( + path.posix.basename(name), + name, + 'declared CRT input must have a simple basename', + ); + copy(source, member(windowsSource, name)); + } + writeFileSync( + member(windowsSource, WINDOWS_VC_RUNTIME_RECEIPT), + renderWindowsVcRuntimeSourceReceipt({ + sourceDirectory: windowsSource, + profile: 'provider', + }), + ); + } + const stageCrt = (destination: string, binaryPath: string) => + windows && + stageWindowsVcRuntime({ + root: destination, + sourceDirectory: windowsSource, + destinations: [path.dirname(member(destination, binaryPath))], + }); + const githubCrt = stageCrt(github, binaryMember); + if (spec.artifact.kind === 'broker-helper') + writeFileSync( + member(github, 'manifest.properties'), + [ + 'schema=oliphaunt-broker-release-assets-v1', + `product=${spec.product}`, + `version=${spec.version}`, + `target=${target}`, + `binary=${binaryMember}`, + ...(githubCrt && githubCrt.required.length + ? [`windowsVcRuntimeDlls=${githubCrt.required.join(',')}`] + : []), + '', + ].join('\n'), + { mode: 0o644 }, + ); + const stageLegal = (destination: string) => { + stageReleaseNotices(destination, notices); + contract.stageRustDependencyLicenses(destination, target); + }; + stageLegal(github); + await archiveDirectory(github, spec.outputs.github); + const validate = (file: string, prefix = '', payloadPrefix = '') => { + const entries = archiveEntries(file, prefix); + assertReleaseNoticesInEntries( + new Map([...entries].filter(([name]) => !name.startsWith('THIRD_PARTY_LICENSES/rust'))), + notices, + ); + contract.assertRustDependencyLicensesInEntries(entries, { target }); + const binaries = [...entries].map(([name, entry]) => ({ + ...entry, + name: + payloadPrefix && name.startsWith(payloadPrefix) ? name.slice(payloadPrefix.length) : name, + })); + inspectPlatformBinaryEntries(binaries, { target, rootLabel: file }); + return entries; + }; + validate(spec.outputs.github); + const npm = path.join(root, 'npm'); + const manifest = JSON.parse(readFileSync(spec.sources['package.json'], 'utf8')); + validateHelperNpmManifest(manifest, spec, contract.RUST_PAYLOAD_LICENSE); + copy(spec.sources['package.json'], member(npm, 'package.json')); + copy(spec.sources['README.md'], member(npm, 'README.md')); + const npmBinary = + spec.artifact.kind === 'node-direct-addon' ? `prebuilds/${binaryMember}` : binaryMember; + copy(spec.binary, member(npm, npmBinary), 0o755); + stageCrt(npm, npmBinary); + stageLegal(npm); + writeFileSync(spec.outputs.npm, canonicalGzipSync(createDeterministicTar(npm, 'package', {}))); + const npmEntries = validate(spec.outputs.npm, 'package'); + const packagedBinary = npmEntries.get(npmBinary); + assert(packagedBinary?.isFile, 'npm envelope omitted its constructed binary'); + assert.equal( + digest(packagedBinary.data()), + digest(readFileSync(spec.binary)), + 'npm envelope changed constructed binary bytes', + ); + if (spec.outputs.cargo) { + const row = spec.carriers.find( + (candidate) => + candidate.ecosystem === 'cargo' && + candidate.target === target && + candidate.role !== 'facade', + ); + assert(row, `canonical Cargo helper carrier missing for ${target}`); + for (const name of ['Cargo.toml', 'build.rs', 'src/lib.rs', 'README.md']) + assert(spec.sources[`cargo/${name}`], `missing declared Cargo target source ${name}`); + const cargo = path.join(root, 'cargo'); + for (const [name, source] of Object.entries(spec.sources)) + if (name.startsWith('cargo/')) copy(source, member(cargo, name.slice(6))); + const cargoManifest = Bun.TOML.parse(readFileSync(member(cargo, 'Cargo.toml'), 'utf8')); + assert.equal(cargoManifest.package?.name, row.name); + assert.equal(cargoManifest.package?.version, row.version); + assert.equal(cargoManifest.package?.license, contract.RUST_PAYLOAD_LICENSE); + assert.equal(cargoManifest.package?.build, 'build.rs'); + assert.equal( + cargoManifest.package?.readme, + 'README.md', + 'Cargo readme must name its declared source', + ); + assert.equal( + cargoManifest.lib?.path, + 'src/lib.rs', + 'Cargo lib.path must name its declared target source', + ); + assert.equal( + cargoManifest.package?.links, + `oliphaunt_artifact_broker_${target.replaceAll('-', '_')}`, + ); + const constants = Object.fromEntries( + [ + ...readFileSync(member(cargo, 'src/lib.rs'), 'utf8').matchAll( + /pub const ([A-Z_]+): &str = "([^"]+)";/gu, + ), + ].map((match) => [match[1], match[2]]), + ); + for (const [key, value] of Object.entries({ + PRODUCT: spec.product, + KIND: spec.artifact.kind, + RELEASE_TARGET: target, + CARGO_TARGET: spec.artifact.triple, + EXECUTABLE_RELATIVE_PATH: binaryMember, + })) + assert.equal(constants[key], value, `Cargo ${key} disagrees with canonical artifact`); + const payloadMembers = [...readPortableArchiveEntries(spec.outputs.github)] + .filter( + ([name, entry]) => + entry.isFile && (name === binaryMember || (windows && name.startsWith('bin/'))), + ) + .map(([name]) => name) + .sort(); + for (const name of payloadMembers) + copy( + member(github, name), + member(cargo, `payload/${name}`), + name === binaryMember ? 0o755 : 0o644, + ); + writeFileSync( + member(cargo, 'payload/sha256'), + windows + ? payloadMembers + .map((name) => `${digest(readFileSync(member(cargo, `payload/${name}`)))} ${name}\n`) + .join('') + : `${digest(readFileSync(spec.binary))}\n`, + ); + stageLegal(cargo); + const archive = packageGeneratedCargoSource( + member(cargo, 'Cargo.toml'), + path.join(root, 'cargo-output'), + ); + copy(archive, spec.outputs.cargo); + validate(spec.outputs.cargo, `${row.name}-${row.version}`, 'payload/'); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + assert.equal(process.argv.length, 3, 'expected one declared envelope specification'); + const specification = process.argv[2]; + assert(specification); + await packageNativeHelper(JSON.parse(readFileSync(specification, 'utf8'))); +} diff --git a/build_defs/languages/carriers/package.test.mts b/build_defs/languages/carriers/package.test.mts new file mode 100644 index 000000000..2ec00361a --- /dev/null +++ b/build_defs/languages/carriers/package.test.mts @@ -0,0 +1,149 @@ +import assert from 'node:assert/strict'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { readPortableArchiveEntries } from '../../../tools/packaging/portable-archive.mts'; +import { + type HelperPackageSpec, + packageNativeHelper, + validateHelperNpmManifest, +} from './package.mts'; + +const [inputs, binary] = process.argv.slice(2); +assert(inputs && binary, 'expected canonical carrier fixtures and constructed host binary'); +const cases: HelperPackageSpec[] = JSON.parse(readFileSync(inputs, 'utf8')); +const license = 'MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause'; +let valid = 0; +let rejected = 0; +for (const spec of cases) { + const manifestPath = spec.sources['package.json']; + assert(manifestPath); + const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')); + validateHelperNpmManifest(manifest, spec, license); + valid++; + for (const mutation of [ + (value: any) => (value.name = '@oliphaunt/wrong'), + (value: any) => (value.version = '99.0.0'), + (value: any) => (value.oliphaunt.target = 'wrong-target'), + (value: any) => (value.os = ['wrong']), + (value: any) => (value.cpu = ['wrong']), + (value: any) => + (value.files = value.files.filter((name: string) => name !== 'THIRD_PARTY_LICENSES')), + (value: any) => delete value.exports['./package.json'], + ]) { + const altered = structuredClone(manifest); + mutation(altered); + assert.throws(() => validateHelperNpmManifest(altered, spec, license)); + rejected++; + } +} +assert.equal(valid, 8); +assert.equal(rejected, 56); +const root = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'native-carrier-unit-')); +try { + let outputs = 0; + for (const original of cases.filter( + (spec) => spec.artifact.npm_os === process.platform && spec.artifact.npm_cpu === process.arch, + )) { + const directory = path.join(root, original.product); + mkdirSync(directory); + const spec = { + ...original, + binary: path.resolve(binary), + outputs: { + github: path.join( + directory, + original.artifact.asset.replace('{version}', original.version), + ), + npm: path.join(directory, 'npm.tgz'), + ...(original.product === 'oliphaunt-broker' + ? { cargo: path.join(directory, 'broker.crate') } + : {}), + }, + }; + await packageNativeHelper(spec); + if (spec.product === 'oliphaunt-broker') { + const entries = readPortableArchiveEntries(spec.outputs.github); + const manifest = entries.get('manifest.properties'); + assert(manifest?.isFile, 'GitHub broker carrier omitted its conventional manifest'); + const values = Object.fromEntries( + manifest + .data() + .toString('utf8') + .trimEnd() + .split('\n') + .map((line) => line.split('=')), + ); + assert.deepEqual( + Object.fromEntries( + Object.entries(values).filter(([key]) => key !== 'windowsVcRuntimeDlls'), + ), + { + schema: 'oliphaunt-broker-release-assets-v1', + product: spec.product, + version: spec.version, + target: spec.artifact.target, + binary: spec.artifact.executable_relative_path, + }, + ); + const runtime = [...entries.keys()] + .filter((name) => name.startsWith('bin/') && name.endsWith('.dll')) + .map((name) => path.posix.basename(name)) + .sort(); + assert.equal(values.windowsVcRuntimeDlls, runtime.length ? runtime.join(',') : undefined); + } + const first = Object.values(spec.outputs).map((file) => readFileSync(file)); + await packageNativeHelper(spec); + Object.values(spec.outputs).forEach((file, index) => { + const original = first[index]; + assert(original); + assert(readFileSync(file).equals(original), 'envelopes must be byte deterministic'); + }); + outputs += first.length; + const wrongTarget = cases.find( + (candidate) => + candidate.product === spec.product && + candidate.artifact.npm_os === 'linux' && + candidate.artifact.npm_cpu !== process.arch, + ); + assert(wrongTarget); + await assert.rejects( + packageNativeHelper({ ...wrongTarget, binary: spec.binary, outputs: spec.outputs }), + /ELF|Mach-O|PE|architecture/u, + ); + const missing = structuredClone(spec); + delete missing.legal['Cargo.lock']; + await assert.rejects(packageNativeHelper(missing), /missing declared legal source Cargo.lock/u); + const changed = structuredClone(spec); + changed.version = '99.0.0'; + await assert.rejects(packageNativeHelper(changed), /version|canonical/u); + if (spec.outputs.cargo) { + const missingBuild = structuredClone(spec); + delete missingBuild.sources['cargo/build.rs']; + await assert.rejects( + packageNativeHelper(missingBuild), + /missing declared Cargo target source build\.rs/u, + ); + const manifest = spec.sources['cargo/Cargo.toml']; + assert(manifest); + const invalidManifest = path.join(directory, 'invalid-Cargo.toml'); + writeFileSync( + invalidManifest, + readFileSync(manifest, 'utf8').replace('path = "src/lib.rs"', 'path = "src/missing.rs"'), + ); + await assert.rejects( + packageNativeHelper({ + ...spec, + sources: { ...spec.sources, 'cargo/Cargo.toml': invalidManifest }, + }), + /Cargo lib\.path/u, + ); + } + } + assert.equal(outputs, 5, 'both Node envelopes and all three broker envelopes must be exercised'); + console.log( + `Native carrier manifests ${valid}, rejected mutations ${rejected}, deterministic host-binary envelopes ${outputs}: PASS`, + ); +} finally { + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/languages/carriers/sql-consumer.mts b/build_defs/languages/carriers/sql-consumer.mts new file mode 100644 index 000000000..8e3864ee2 --- /dev/null +++ b/build_defs/languages/carriers/sql-consumer.mts @@ -0,0 +1,39 @@ +import assert from 'node:assert/strict'; + +const [mode, phase, directory] = process.argv.slice(2); +assert(mode === 'direct' || mode === 'broker'); +assert(phase === 'write' || phase === 'read'); +assert(directory); +const { Oliphaunt } = await import(`@oliphaunt/ts/${mode}`); +const database = await Oliphaunt.open({ storage: { kind: 'directory', path: directory } }); +let brokerPid: number | undefined; +try { + assert.deepEqual((await database.query('SELECT 42 AS answer')).rows, [{ answer: 42 }]); + assert.match((await database.query('SHOW server_version')).rows[0].server_version, /^18\./u); + if (mode === 'broker') { + brokerPid = (await database.query('SELECT pg_backend_pid() AS pid')).rows[0].pid; + assert( + typeof brokerPid === 'number' && Number.isInteger(brokerPid) && brokerPid !== process.pid, + 'broker SQL must execute in its companion process', + ); + process.kill(brokerPid, 0); + } + if (phase === 'write') { + await database.exec('CREATE TABLE carrier_probe (value text NOT NULL)'); + await database.query('INSERT INTO carrier_probe VALUES ($1)', [`installed-${mode}`]); + } + assert.deepEqual((await database.query('SELECT value FROM carrier_probe')).rows, [ + { value: `installed-${mode}` }, + ]); +} finally { + await database.close(); +} +if (brokerPid !== undefined) { + const pid = brokerPid; + assert.throws( + () => process.kill(pid, 0), + (error) => (error as NodeJS.ErrnoException).code === 'ESRCH', + 'closing the installed broker SDK must reap its companion process', + ); +} +console.log(`Installed ${mode} SQL ${phase}: PASS`); diff --git a/build_defs/languages/installed/BUILD.bazel b/build_defs/languages/installed/BUILD.bazel new file mode 100644 index 000000000..9279069f0 --- /dev/null +++ b/build_defs/languages/installed/BUILD.bazel @@ -0,0 +1,84 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/foundation:bun.bzl", "bun_test") +load(":defs.bzl", "installed_cargo_tests") +load(":source-compile.bzl", "source_compile_selection_test", "source_compile_test") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["context.mts", "consumer.mts", "capture.mts", "repositories.bzl", "fixture/Cargo.toml", "fixture/Cargo.lock", "fixture/registry-index.json", "fixture/main.rs", "fixture/build.rs"]) + +bun_test( + name = "context_test", + entry_point = "context.test.mts", + data = ["context.mts", "fixture/Cargo.lock", "fixture/registry-index.json"], +) + +bun_test( + name = "candidate_context_test", + entry_point = "consumer.test.mts", + data = ["consumer.mts", "fixture/Cargo.toml", "//src/native/sdks/rust:Cargo.toml", "//build_defs/query:package.mts", "//build_defs/languages:cargo-environment.mts", "//build_defs/languages:cargo-metadata.mts", "//:tools/packaging/cargo-manifest.mts", "//:tools/packaging/archive-directory.mts", "//:tools/packaging/frozen-cargo.mts", "//:tools/packaging/portable-archive.mts"], +) + +installed_cargo_tests( + name = "consumer", + size = "large", timeout = "long", tags = ["manual", "installed-consumer"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + archives = ["//src/native/sdks/rust:crate", "//src/native/sdks/rust/crates/oliphaunt-build:crate", "//src/native/rust-bindings:crate", "//src/native/broker:crate", "//src/query/rust:crate"], + cargo_home = "@installed_cargo_inputs//:cargo_home", + manifest = "fixture/Cargo.toml", lock = "fixture/Cargo.lock", source = "fixture/main.rs", + core_source = "fixture/core.rs", build_script = "fixture/build.rs", + core_build_script = "fixture/core-build.rs", +) + +source_quality_files() + +exports_files([ + "source-compile.bzl", "source-compile.mts", "source-compile.test.mts", + "wasix/sdk/Cargo.lock", "wasix/sdk/registry-index.json", + "wasix/server/Cargo.lock", "wasix/server/registry-index.json", + "wasix/query/Cargo.lock", "wasix/query/registry-index.json", +]) + +source_compile_selection_test( + name = "source_compile_selection_test", + entry_point = "source-compile.test.mts", + data = [ + "source-compile.mts", "consumer.mts", "context.mts", + "//build_defs/languages:cargo-environment.mts", + "//build_defs/languages:cargo-metadata.mts", + "//:tools/packaging/cargo-manifest.mts", "//:tools/packaging/frozen-cargo.mts", + "//:tools/packaging/portable-archive.mts", "//:tools/packaging/archive-directory.mts", + ], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) + +source_compile_test( + name = "wasix_sdk_source_compile_test", + archive = "//src/wasix/sdks/rust:crate", + dependencies = ["//src/query/rust:crate"], + cargo_home = "@installed_wasix_sdk_cargo_inputs//:cargo_home", + lock = "wasix/sdk/Cargo.lock", + index = "wasix/sdk/registry-index.json", + cargo_args = ["--no-default-features", "--features", "extensions,tools,icu"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + size = "large", timeout = "long", tags = ["manual", "installed-consumer"], +) +source_compile_test( + name = "pgwire_source_compile_test", + archive = "//src/wasix/pgwire-server:crate", + dependencies = ["//src/wasix/sdks/rust:crate", "//src/query/rust:crate"], + cargo_home = "@installed_pgwire_cargo_inputs//:cargo_home", + lock = "wasix/server/Cargo.lock", + index = "wasix/server/registry-index.json", + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + size = "large", timeout = "long", tags = ["manual", "installed-consumer"], +) +source_compile_test( + name = "query_source_compile_test", + archive = "//src/query/rust:crate", + cargo_home = "@installed_query_cargo_inputs//:cargo_home", + lock = "wasix/query/Cargo.lock", + index = "wasix/query/registry-index.json", + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + size = "small", tags = ["manual", "installed-consumer"], +) diff --git a/build_defs/languages/installed/README.md b/build_defs/languages/installed/README.md new file mode 100644 index 000000000..1f8e7bf80 --- /dev/null +++ b/build_defs/languages/installed/README.md @@ -0,0 +1,77 @@ +This is a closed installed Cargo consumer test for the current checkout. It uses +actual constructed source crates, a genuine Cargo-generated lockfile, captured +sparse index records, and registry archives authenticated by that lockfile. +It does not authorize publication or establish completed release origins. +Archive acquisition uses Cargo's selected Linux host graph; the remaining +cross-target index records support offline resolution without downloading their +unused platform archives. + +`consumer_test` runs three common preparation cases: the current SDK/helper +composition with its declared candidate dependency closure, a direct packaged +Core public API consumer, and the current helper with the genuine held SDK and +runtime. Each case compiles and executes SQL/reopen checks. The direct Core case +leaves the held SDK's requirements unchanged. + +`consumer_minimum_test` checks the additional declared internal source floors +for a prepared selected native SDK or Broker. The SDK case runs SQL/reopen; the +Broker case installs its original binary source envelope independently of SDK +constraints and dev requirements, then checks Cargo's compiled manifest paths. +Each floor uses its exact retained completed archive or an explicitly selected +current producer at that version. A newer compatible input cannot prove the +floor. The source-owned final policy requires this test for these selected +carriers; preparation alone cannot satisfy that requirement. +Cargo resolves both tests' compositions offline from the conventional manifests +and captured inputs. For SDK compositions, independently held runtime +requirements remain the SDK manifest's requirements. Results record which +source candidates Cargo actually selected; an unused patch is not qualification +of that candidate. + +The WASIX `source_compile_test` cases compile each extracted package's original +tests, including dev requirements. Registry-only source dependencies retain their +completed captured identities while the packaged requirements still accept them. +An authored local path can select its actual +current dependency before release version calculation; its original manifest +must identify the explicitly supplied dependency archive's source manifest. +Co-selection alone does not change a registry requirement or a held dependency. +For prepared selected source owners with local dependencies, the same worker +additionally compiles the declared production floors. Library owners compile as +dependencies, so their dev requirements cannot raise the qualified floor. Binary +owners use Cargo's offline install of the original envelope to compile both +library and binary production targets. These cases share a Cargo cache and target +directory, preserve original source manifests, and verify the compiler-reported +manifest paths. Their results distinguish source test compilation from production +floor compilation. Selection stays within the captured one-identity-per-local-name +closure; it is not a general minimal-version resolver. The existing selector test +uses tiny controlled archives and declared tools to exercise these phases; its +fixtures have no completed-publication provenance claim. + +Each case also supplies its original exact runtime, helper and data payload +archives. Completed bytes take precedence, including at the same version. +Current payloads are eligible only when their actual source consumer and producer +are prepared selected at the constructed versions and the original manifest pins +that exact producer version. The held SDK case retains its own payload pins. +Native multipart inputs retain the original part set; WASIX current inputs are +the original configured Cargo carrier Files from the same invocation. Workers +stage only requested archives, keep the third-party context unchanged, and let +offline Cargo generate the lock before locked compilation. They do not edit +source manifests or manufacture registry entries for unpublished inputs. +These installed qualifiers require the source-bound native release input +snapshot's actual completed payload pool. A matching archive in the captured +registry cache cannot replace a missing required completed input. Prepared late +qualification additionally receives actual current producer Files. This input +requirement establishes the test composition; it does not establish publication +admission by itself. + +Registry requirement changes need explicit qualification preflight. Run +`capture.mts` with the pinned Cargo and rustc executable paths, an output +directory, and the constructed source archive paths. The updater invokes real +Cargo resolution and fetch, verifies each downloaded archive against its lock +checksum and sparse index record, and emits `Cargo.lock` plus +`registry-index.json`. Replace both fixture files together with these generated +outputs, review the dependency changes, refresh the module acquisition lock if +needed, then run the closed test. No manually edited resolution graph is used. + +The production frozen consumer adapter independently authenticates selected +candidate and held origins from its publication capsule before sharing the same +source-envelope stager. This checkout test intentionally has no publication +capsule or production origin claim. diff --git a/build_defs/languages/installed/capture.mts b/build_defs/languages/installed/capture.mts new file mode 100644 index 000000000..7986d7037 --- /dev/null +++ b/build_defs/languages/installed/capture.mts @@ -0,0 +1,301 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + copyFileSync, + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + writeFileSync, +} from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { stageCargoCarrierInputs } from '../../../tools/packaging/frozen-cargo.mts'; +import { candidateConsumerManifest, cargoCandidate, resolvedSdkRuntime } from './consumer.mts'; +import { type RegistryContext, validateRegistryContext } from './context.mts'; + +const digest = (bytes: Buffer | string) => createHash('sha256').update(bytes).digest('hex'); +export function capturedRegistryContext( + lockText: string, + metadata: any, + cargoHome: string, + cargo: string, + target: string, + candidates: { name: string; version: string }[], + acquiredArchives?: { name: string; version: string }[], +) { + const lock = Bun.TOML.parse(lockText); + const repository = 'index.crates.io-1949cf8c6b5b557f'; + // Cargo fetch acquires its genuine lock closure, including optional packages. + // Record those real files rather than inventing a second + // dependency selection from compile-feature metadata. + const archives = + acquiredArchives ?? + lock.package + .filter( + (pkg: any) => + pkg.source && + existsSync( + path.join(cargoHome, 'registry/cache', repository, `${pkg.name}-${pkg.version}.crate`), + ), + ) + .map((pkg: any) => ({ name: pkg.name, version: pkg.version })) + .sort((a: any, b: any) => `${a.name}@${a.version}`.localeCompare(`${b.name}@${b.version}`)); + const selected = new Set(archives.map((pkg: any) => `${pkg.name}@${pkg.version}`)); + for (const pkg of metadata.packages.filter((pkg: any) => pkg.source)) + assert( + selected.has(`${pkg.name}@${pkg.version}`), + `Actual Cargo metadata references an uncaptured archive: ${pkg.name}@${pkg.version}`, + ); + const index = path.join(cargoHome, 'registry/index', repository); + const groups = new Map(); + for (const pkg of lock.package) { + if (!pkg.source) { + assert( + candidates.some( + (candidate) => candidate.name === pkg.name && candidate.version === pkg.version, + ), + `Unexpected captured local package: ${pkg.name}@${pkg.version}`, + ); + continue; + } + assert.equal(pkg.source, 'registry+https://github.com/rust-lang/crates.io-index'); + if (selected.has(`${pkg.name}@${pkg.version}`)) + assert.equal( + digest( + readFileSync( + path.join(cargoHome, 'registry/cache', repository, `${pkg.name}-${pkg.version}.crate`), + ), + ), + pkg.checksum, + ); + const name = pkg.name.toLowerCase(); + const key = + name.length === 1 + ? `1/${name}` + : name.length === 2 + ? `2/${name}` + : name.length === 3 + ? `3/${name[0]}/${name}` + : `${name.slice(0, 2)}/${name.slice(2, 4)}/${name}`; + const bytes = readFileSync(path.join(index, '.cache', key)); + const records = bytes + .toString('utf8') + .split('\0') + .filter((row) => row.startsWith('{')) + .map((row) => JSON.parse(row)); + const record = records.find((row) => row.name === pkg.name && row.vers === pkg.version); + assert.equal( + record?.cksum, + pkg.checksum, + `Sparse index differs from genuine lock: ${pkg.name}@${pkg.version}`, + ); + if (!groups.has(key)) + groups.set(key, { + path: key, + header: bytes.subarray(0, bytes.indexOf(0, 5) + 1).toString('base64'), + records: [], + }); + const group = groups.get(key); + assert(group); + group.records.push(record); + } + const configFile = path.join(index, 'config.json'); + if (!existsSync(configFile)) + assert.equal(groups.size, 0, 'A resolved registry context is missing its actual configuration'); + const context: RegistryContext = { + schema: 'oliphaunt-installed-cargo-fixture-v1', + cargo, + repository, + target, + archives, + config: existsSync(configFile) ? JSON.parse(readFileSync(configFile, 'utf8')) : {}, + indexes: [...groups.values()].sort((a, b) => a.path.localeCompare(b.path)), + }; + validateRegistryContext(lockText, context); + return context; +} +/** Explicit network-enabled qualification preflight; Cargo is the only resolver. */ +export async function captureCargoContext( + cargo: string, + rustc: string, + archives: string[], + output: string, +) { + const scratch = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-cargo-capture-')); + const candidates = archives.map(cargoCandidate); + const config = stageCargoCarrierInputs(candidates, scratch); + const fixture = path.join(import.meta.dir, 'fixture'); + const consumer = path.join(scratch, 'consumer'); + const cargoHome = path.join(scratch, 'cargo-home'); + mkdirSync(path.join(consumer, 'src'), { recursive: true }); + writeFileSync( + path.join(consumer, 'Cargo.toml'), + candidateConsumerManifest(readFileSync(path.join(fixture, 'Cargo.toml'), 'utf8'), candidates), + ); + copyFileSync(path.join(fixture, 'Cargo.lock'), path.join(consumer, 'Cargo.lock')); + copyFileSync(path.join(fixture, 'main.rs'), path.join(consumer, 'src/main.rs')); + copyFileSync(path.join(fixture, 'build.rs'), path.join(consumer, 'build.rs')); + const env = { PATH: path.dirname(cargo), HOME: scratch, CARGO_HOME: cargoHome, RUSTC: rustc }; + const target = 'x86_64-unknown-linux-gnu'; + for (const command of [['generate-lockfile'], ['fetch', '--locked', '--target', target]]) { + const result = Bun.spawnSync( + [cargo, '--config', config, ...command, '--manifest-path', path.join(consumer, 'Cargo.toml')], + { cwd: consumer, env, stdout: 'inherit', stderr: 'inherit' }, + ); + assert.equal(result.exitCode, 0, `real Cargo preflight failed: ${command.join(' ')}`); + } + const lockText = readFileSync(path.join(consumer, 'Cargo.lock'), 'utf8'); + resolvedSdkRuntime( + readFileSync(path.join(consumer, 'Cargo.toml'), 'utf8'), + lockText, + candidates, + cargoHome, + ); + const metadata = Bun.spawnSync( + [ + cargo, + '--config', + config, + 'metadata', + '--locked', + '--offline', + '--filter-platform', + target, + '--format-version', + '1', + '--manifest-path', + path.join(consumer, 'Cargo.toml'), + ], + { cwd: consumer, env, stderr: 'inherit' }, + ); + assert.equal(metadata.exitCode, 0, 'real Cargo selected-platform metadata failed'); + const acquiredArchives = JSON.parse(metadata.stdout.toString('utf8')) + .packages.filter((pkg: any) => pkg.source) + .map((pkg: any) => ({ name: pkg.name, version: pkg.version })) + .sort((a: any, b: any) => `${a.name}@${a.version}`.localeCompare(`${b.name}@${b.version}`)); + const version = Bun.spawnSync([cargo, '--version'], { env }); + assert.equal(version.exitCode, 0); + const context = capturedRegistryContext( + lockText, + JSON.parse(metadata.stdout.toString('utf8')), + cargoHome, + version.stdout.toString('utf8').trim().split(' ')[1] ?? '', + target, + [ + ...candidates, + Bun.TOML.parse(readFileSync(path.join(consumer, 'Cargo.toml'), 'utf8')).package, + ], + acquiredArchives, + ); + mkdirSync(output, { recursive: true }); + writeFileSync(path.join(output, 'Cargo.lock'), lockText); + writeFileSync(path.join(output, 'registry-index.json'), `${JSON.stringify(context, null, 2)}\n`); + return { + scratch, + packages: Bun.TOML.parse(lockText).package.length, + registryPackages: context.indexes.reduce((total, entry) => total + entry.records.length, 0), + }; +} + +export async function captureSourceCargoContext(spec: { + cargo: string; + rustc: string; + archives: string[]; + flags: string[]; + output: string; +}) { + const scratch = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-source-cargo-capture-')); + const archiveDirectory = path.join(scratch, 'archives'); + mkdirSync(archiveDirectory); + const candidates = spec.archives.map((archive, index) => { + const copied = path.join(archiveDirectory, `${index}-${path.basename(archive)}`); + copyFileSync(archive, copied); + return cargoCandidate(copied); + }); + assert(candidates.length > 0); + const config = stageCargoCarrierInputs(candidates, scratch); + const candidate = candidates[0]; + const directory = path.join(scratch, 'crates', `${candidate.name}-${candidate.version}`); + const manifest = path.join(directory, 'Cargo.toml'); + const cargoHome = path.join(scratch, 'cargo-home'); + const env = { + PATH: path.dirname(spec.rustc), + HOME: scratch, + CARGO_HOME: cargoHome, + RUSTC: spec.rustc, + }; + const target = 'x86_64-unknown-linux-gnu'; + async function command(name: string, args: string[]) { + const stdout = path.join(scratch, `${name}.stdout`), + stderr = path.join(scratch, `${name}.stderr`); + const child = Bun.spawn( + [spec.cargo, '--config', config, ...args, '--manifest-path', manifest], + { cwd: directory, env, stdin: 'ignore', stdout: Bun.file(stdout), stderr: Bun.file(stderr) }, + ); + assert.equal(await child.exited, 0, `Actual source capture ${name} failed; ${stderr}`); + return readFileSync(stdout, 'utf8'); + } + await command('generate-lockfile', ['generate-lockfile']); + // Cargo's test preparation reads cross-target locked package manifests too. + // Let Cargo acquire its complete lock closure; compilation stays on target. + await command('fetch', ['fetch', '--locked']); + const metadata = JSON.parse( + await command('metadata', [ + 'metadata', + '--locked', + '--offline', + '--filter-platform', + target, + '--format-version', + '1', + ...spec.flags, + ]), + ); + const selected = metadata.packages.find((pkg: any) => pkg.id === metadata.resolve.root); + assert.equal(selected.name, candidate.name); + assert.equal(selected.version, candidate.version); + assert.equal(selected.source, null); + const version = Bun.spawnSync([spec.cargo, '--version'], { env }); + assert.equal(version.exitCode, 0); + const lockText = readFileSync(path.join(directory, 'Cargo.lock'), 'utf8'); + const context = capturedRegistryContext( + lockText, + metadata, + cargoHome, + version.stdout.toString().trim().split(' ')[1], + target, + candidates, + ); + mkdirSync(spec.output, { recursive: true }); + writeFileSync(path.join(spec.output, 'Cargo.lock'), lockText); + writeFileSync( + path.join(spec.output, 'registry-index.json'), + `${JSON.stringify(context, null, 2)}\n`, + ); + const receipt = { + scratch, + cargoHome, + name: candidate.name, + version: candidate.version, + candidates: candidates.map(({ name, version, sha256 }) => ({ name, version, sha256 })), + cargoLockSha256: digest(lockText), + registryIndexSha256: digest(readFileSync(path.join(spec.output, 'registry-index.json'))), + registryPackages: context.indexes.reduce((count, index) => count + index.records.length, 0), + acquiredArchives: context.archives.length, + }; + writeFileSync(path.join(spec.output, 'capture.json'), `${JSON.stringify(receipt, null, 2)}\n`); + return receipt; +} +if (import.meta.main) { + const [cargo, rustc, output, ...archives] = process.argv.slice(2); + if (cargo === '--source') { + assert(rustc && !output); + console.log( + JSON.stringify(await captureSourceCargoContext(JSON.parse(readFileSync(rustc, 'utf8')))), + ); + } else { + assert(cargo && rustc && output); + console.log(JSON.stringify(await captureCargoContext(cargo, rustc, archives, output))); + } +} diff --git a/build_defs/languages/installed/consumer.mts b/build_defs/languages/installed/consumer.mts new file mode 100644 index 000000000..18874c8a7 --- /dev/null +++ b/build_defs/languages/installed/consumer.mts @@ -0,0 +1,889 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { copyFileSync, lstatSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { cargoDependencyMinimum } from '../../../tools/packaging/cargo-manifest.mts'; +import { + assertCargoSourceArtifacts, + stageCargoCarrierInputs, +} from '../../../tools/packaging/frozen-cargo.mts'; +import { readPortableArchiveEntries } from '../../../tools/packaging/portable-archive.mts'; +import { type CargoLinkConfiguration, cargoLinkEnvironment } from '../cargo-environment.mts'; +import { cargoSatisfies } from '../cargo-metadata.mts'; + +export function cargoCandidate(file: string) { + const entries = readPortableArchiveEntries(file); + for (const entry of entries.values()) + assert( + (entry.isFile && entry.mode === 0o644) || (entry.isDirectory && entry.mode === 0o755), + `candidate member ${entry.name} must be a regular 0644 file or 0755 directory`, + ); + return cargoArchiveIdentity(file, entries); +} + +function cargoArchiveIdentity( + file: string, + entries: ReturnType, +) { + const manifests = [...entries].filter(([name]) => name.endsWith('/Cargo.toml')); + assert.equal(manifests.length, 1, 'candidate envelope must have one conventional manifest'); + const entry = manifests[0]; + assert(entry?.[1].isFile, 'Cargo manifest must be a regular archive member'); + const manifest = Bun.TOML.parse(Buffer.from(entry[1].data()).toString('utf8')); + assert.equal(typeof manifest.package?.name, 'string'); + assert.equal(typeof manifest.package?.version, 'string'); + const root = `${manifest.package.name}-${manifest.package.version}`; + for (const [name, entry] of entries) + assert( + (name === root && entry.isDirectory) || name.startsWith(`${root}/`), + `Cargo archive member ${name} is outside declared package ${root}`, + ); + return { + file, + name: manifest.package.name, + version: manifest.package.version, + sha256: createHash('sha256').update(readFileSync(file)).digest('hex'), + manifest, + }; +} + +type CargoCandidate = ReturnType; +export type CargoOwner = { product: string; version: string }; +export type CargoPayloadRow = { + product: string; + version: string; + artifact: string; + file: { path: string; size?: number; sha256?: string }; +}; +export type CargoPayloadPool = { + completed: CargoPayloadInput[]; + current: CargoPayloadInput[]; + owners: Record; + read: (input: CargoPayloadInput) => CargoCandidate & { product: string }; +}; +type CargoPayloadInput = { + name: string; + version: string; + product: string; + sha256?: string; + rows: CargoPayloadRow[]; + destination: string; +}; + +/** Read original declared Files; imported rows retain their authenticated byte identity. */ +export function cargoPayloadPool( + specification: { + completed: CargoPayloadRow[]; + current: CargoPayloadRow[]; + owners: Record; + }, + sourceOwners: Record, + file: (name: string) => string, + directory: string, +): CargoPayloadPool { + const index = (rows: CargoPayloadRow[], phase: string) => { + const inputs = new Map(); + for (const [index, row] of rows.entries()) { + assert( + /^[0-9A-Za-z][0-9A-Za-z.+-]*$/u.test(row.version), + 'Payload package version is unsafe', + ); + assert( + row.artifact.startsWith('cargo:') || + (row.artifact.startsWith('github-release:') && row.artifact.endsWith('.crate')), + 'Payload input is not an original Cargo archive', + ); + const suffix = `-${row.version}.crate`; + if (row.artifact.startsWith('github-release:')) + assert(row.artifact.endsWith(suffix), 'Payload asset version differs'); + const name = row.artifact.startsWith('cargo:') + ? row.artifact.slice('cargo:'.length) + : row.artifact.slice('github-release:'.length, -suffix.length); + assert(/^[A-Za-z0-9][A-Za-z0-9_-]*$/u.test(name), 'Payload package name is unsafe'); + if (Object.hasOwn(sourceOwners, name)) continue; + const owner = specification.owners[name]; + if (owner) { + assert.equal(row.product, owner.product, 'Payload owner differs'); + if (phase === 'current') + assert.equal(row.version, owner.version, 'Current payload version differs'); + } + const key = `${name}@${row.version}`; + const previous = inputs.get(key); + assert( + !previous || + (previous.product === row.product && + (!previous.sha256 || !row.file.sha256 || previous.sha256 === row.file.sha256)), + 'Conflicting original payload archive: ' + key, + ); + if (previous) previous.rows.push(row); + else + inputs.set(key, { + name, + version: row.version, + product: row.product, + sha256: row.file.sha256, + rows: [row], + destination: path.join(directory, `${phase}-${index}-${name}-${row.version}.crate`), + }); + } + return [...inputs.values()]; + }; + const loaded = new Map(); + return { + completed: index(specification.completed, 'completed'), + current: index(specification.current, 'current'), + owners: specification.owners, + read(input) { + const previous = loaded.get(input); + if (previous) return previous; + let candidate: CargoCandidate | undefined; + for (const [index, row] of input.rows.entries()) { + const copied = index ? `${input.destination}.alias-${index}` : input.destination; + copyFileSync(file(row.file.path), copied); + assert(lstatSync(copied).isFile(), 'Payload input is not a regular File'); + const actual = cargoArchiveIdentity(copied, readPortableArchiveEntries(copied)); + assert.equal(actual.name, input.name, 'Payload package name differs'); + assert.equal(actual.version, input.version, 'Payload package version differs'); + if (row.file.size !== undefined) + assert.equal(readFileSync(copied).length, row.file.size, 'Payload archive size differs'); + if (row.file.sha256 !== undefined) + assert.equal(actual.sha256, row.file.sha256, 'Payload archive SHA differs'); + if (candidate) + assert.equal(actual.sha256, candidate.sha256, 'Conflicting original payload alias bytes'); + else candidate = actual; + if (index) rmSync(copied); + } + assert(candidate); + const result = { ...candidate, product: input.product }; + loaded.set(input, result); + return result; + }, + }; +} + +/** Compose exact payload requirements from original manifests; Cargo remains the resolver. */ +export function cargoPayloadInputs( + roots: CargoCandidate[], + pool: CargoPayloadPool, + { + currentSources, + sourceOwners, + selectedProducts, + includeDev = true, + consumer, + }: { + currentSources: CargoCandidate[]; + sourceOwners: Record; + selectedProducts: string[]; + includeDev?: boolean; + consumer?: { manifest: any; source: CargoCandidate }; + }, +) { + const currentSource = (source: CargoCandidate) => { + const owner = sourceOwners[source.name]; + return ( + currentSources.includes(source) && + owner?.version === source.version && + selectedProducts.includes(owner.product) + ); + }; + const known = new Set([ + ...Object.keys(pool.owners), + ...pool.completed.map((row) => row.name), + ...pool.current.map((row) => row.name), + ]); + const selected = new Map(); + const selectedInputs = new Map(); + const pending = roots.map((candidate) => ({ + manifest: candidate.manifest, + source: currentSource(candidate) ? candidate : undefined, + })); + if (consumer) + pending.push({ + manifest: consumer.manifest, + source: currentSource(consumer.source) ? consumer.source : undefined, + }); + for (const { manifest, source } of pending) { + for (const table of [manifest, ...Object.values(manifest.target ?? {})] as any[]) { + for (const section of [ + 'dependencies', + 'build-dependencies', + ...(includeDev ? ['dev-dependencies'] : []), + ]) { + for (const [alias, raw] of Object.entries(table[section] ?? {}) as [string, any][]) { + const requirement = typeof raw === 'string' ? { version: raw } : raw; + const name = requirement.package ?? alias; + if (!known.has(name)) continue; + assert( + typeof requirement.version === 'string' && + /^=\s*[0-9]/u.test(requirement.version) && + !requirement.path && + !requirement.git && + !requirement.workspace && + !requirement.registry, + 'Payload requirement is not an exact conventional registry pin: ' + name, + ); + const version = requirement.version.slice(1).trim(); + const previous = selected.get(name); + if (previous) { + assert.equal( + previous.version, + version, + 'Conflicting exact payload requirement: ' + name, + ); + const selectedInput = selectedInputs.get(name); + assert(selectedInput); + assert( + source || pool.completed.includes(selectedInput), + 'Held source cannot consume current payload bytes: ' + name, + ); + continue; + } + const held = pool.completed.filter((row) => row.name === name && row.version === version); + assert(held.length <= 1, 'Ambiguous completed payload: ' + name); + const current = pool.current.filter( + (row) => row.name === name && row.version === version, + ); + assert(current.length <= 1, 'Ambiguous current payload: ' + name); + const input = + held[0] ?? + (source && current[0] && selectedProducts.includes(current[0].product) + ? current[0] + : undefined); + assert(input, 'Missing actual exact payload archive: ' + name + '@' + version); + const candidate = pool.read(input); + selected.set(name, candidate); + selectedInputs.set(name, input); + // A held wrapper requires its original completed parts even when a + // same-version current producer happens to be selected independently. + pending.push({ manifest: candidate.manifest, source: held.length ? undefined : source }); + } + } + } + } + return [...selected.values()]; +} + +function heldSdkCandidate(lockText: string, cargoHome: string) { + const rows = Bun.TOML.parse(lockText).package.filter((row: any) => row.name === 'oliphaunt'); + assert.equal(rows.length, 1, 'Held consumer needs one genuine SDK identity'); + const row = rows[0]; + assert.equal(row.source, 'registry+https://github.com/rust-lang/crates.io-index'); + const file = path.join( + cargoHome, + 'registry/cache/index.crates.io-1949cf8c6b5b557f', + `oliphaunt-${row.version}.crate`, + ); + const candidate = cargoArchiveIdentity(file, readPortableArchiveEntries(file)); + assert.equal(candidate.sha256, row.checksum, 'Held SDK archive differs from genuine Cargo lock'); + return candidate; +} + +export function candidateConsumerManifest( + template: string, + candidates: ReturnType[], +) { + const sdk = candidates.find((candidate) => candidate.name === 'oliphaunt'); + const helper = candidates.find((candidate) => candidate.name === 'oliphaunt-build'); + const core = candidates.find((candidate) => candidate.name === 'liboliphaunt-native-bindings'); + let text = template; + for (const candidate of [sdk, helper].filter((value) => value !== undefined)) { + const expression = new RegExp(`^${candidate.name}\\s*=\\s*"[^"]*"`, 'mu'); + assert(expression.test(text), `missing fixture candidate requirement: ${candidate.name}`); + text = text.replace(expression, `${candidate.name} = "=${candidate.version}"`); + } + // Unselected roots retain the fixture's explicit published requirements. Their + // authentic resolved SDK manifest is checked after Cargo generates the lock. + if (!sdk) { + if (core) { + text = text.replace(/^oliphaunt\s*=\s*"[^"]*"/mu, `${core.name} = "=${core.version}"`); + text = text.replace(/^\[package\]$/mu, '[package]\nbuild = "core-build.rs"'); + } + return text; + } + const runtime = sdk.manifest.package.metadata.oliphaunt['native-version']; + assert.equal(typeof runtime, 'string'); + text = text.replace( + /^liboliphaunt-native-linux-x64-gnu\s*=\s*"[^"]*"/mu, + `liboliphaunt-native-linux-x64-gnu = "=${runtime}"`, + ); + text = text.replace(/^runtime-version\s*=\s*"[^"]*"/mu, `runtime-version = "${runtime}"`); + return text; +} + +/** Stage only declared candidate dependencies; Cargo still resolves the actual composition. */ +export function candidateDependencyInputs( + roots: ReturnType[], + pool: ReturnType[], + lockText: string, + preferHeld = false, +) { + const held = Bun.TOML.parse(lockText).package; + const selected = new Map(roots.map((candidate) => [candidate.name, candidate])); + const pending = [...roots]; + for (const candidate of pending) + for (const table of [ + candidate.manifest, + ...Object.values(candidate.manifest.target ?? {}), + ] as any[]) + for (const section of ['dependencies', 'build-dependencies']) + for (const [alias, declaration] of Object.entries(table[section] ?? {})) { + const dependency = + typeof declaration === 'string' ? { version: declaration } : (declaration as any); + const name = dependency.package ?? alias; + if (selected.has(name)) continue; + const current = pool.find((row) => row.name === name); + if (!current) continue; + assert.equal( + typeof dependency.version, + 'string', + `candidate dependency needs its conventional requirement: ${name}`, + ); + const compatibleHeld = held.some( + (row: any) => + row.name === name && row.source && cargoSatisfies(row.version, dependency.version), + ); + if (preferHeld && compatibleHeld) continue; + if (!cargoSatisfies(current.version, dependency.version)) { + assert( + compatibleHeld, + `candidate dependency lacks a compatible declared input: ${name}`, + ); + continue; + } + selected.set(name, current); + pending.push(current); + } + return [...selected.values()]; +} + +export type InstalledCargoFloorPool = { + archives: ReturnType[]; + owners: Record; +}; +export type InstalledCargoMinimum = { + floors: { name: string; version: string }[]; + heldInputs: ReturnType[]; + /** Broker minimum compiles its original source envelope; installed SQL is separate. */ + source?: ReturnType; +}; +export type InstalledConsumerCase = [ + name: string, + inputs: ReturnType[], + minimum?: InstalledCargoMinimum, +]; + +function minimumSourceCase( + source: ReturnType, + candidates: ReturnType[], + fixtureLock: string, + selectedProducts: string[], + floorPool: InstalledCargoFloorPool, +): InstalledConsumerCase { + assert( + selectedProducts.includes(floorPool.owners[source.name]), + 'Minimum needs its selected source owner', + ); + const locked = Bun.TOML.parse(fixtureLock).package; + const held = new Map>(); + for (const row of floorPool.archives) { + const key = row.name + '@' + row.version; + const previous = held.get(key); + assert( + !previous || previous.sha256 === row.sha256, + 'Conflicting completed floor archive: ' + key, + ); + held.set(key, row); + } + const dependencies = (row: ReturnType) => + [row.manifest, ...Object.values(row.manifest.target ?? {})].flatMap((table: any) => + ['dependencies', 'build-dependencies'].flatMap((section) => + Object.entries(table[section] ?? {}).flatMap(([alias, raw]: [string, any]) => { + const declaration = typeof raw === 'string' ? { version: raw } : raw; + const name = declaration.package ?? alias; + if (!Object.hasOwn(floorPool.owners, name)) return []; + assert( + typeof declaration.version === 'string' && + !declaration.path && + !declaration.git && + !declaration.workspace && + !declaration.registry, + 'Source floor dependency is not a conventional registry requirement: ' + name, + ); + return [{ name, requirement: declaration.version as string }]; + }), + ), + ); + const selected = new Map([[source.name, source]]); + const heldInputs = new Set>(); + const currentExact = (name: string, version: string) => { + if (!selectedProducts.includes(floorPool.owners[name])) return undefined; + const matches = candidates.filter((row) => row.name === name && row.version === version); + assert(matches.length <= 1, 'Ambiguous current floor archive: ' + name + '@' + version); + return matches[0]; + }; + const retain = (name: string, version: string) => { + const row = held.get(name + '@' + version); + if (!row) return undefined; + for (const lock of locked.filter((item: any) => item.name === name && item.version === version)) + if (lock.source) { + assert.equal(lock.source, 'registry+https://github.com/rust-lang/crates.io-index'); + assert.equal( + lock.checksum, + row.sha256, + 'Completed floor differs from fixture lock: ' + name, + ); + } + heldInputs.add(row); + return row; + }; + // Fix every direct source floor before visiting weaker transitive requirements. + const directRequirements = new Map(); + for (const { name, requirement } of dependencies(source)) { + directRequirements.set(name, [...(directRequirements.get(name) ?? []), requirement]); + } + for (const [name, requirements] of directRequirements) { + const version = cargoDependencyMinimum(requirements); + const row = retain(name, version) ?? currentExact(name, version); + assert(row, 'Missing exact source dependency floor archive: ' + name + '@' + version); + selected.set(name, row); + } + const pending = [...selected.values()]; + for (const row of pending) + for (const { name, requirement } of dependencies(row)) { + const chosen = selected.get(name); + if (chosen) { + assert( + cargoSatisfies(chosen.version, requirement), + 'Source floor conflicts with downstream requirement: ' + name + ' ' + requirement, + ); + continue; + } + const retained = locked.filter( + (item: any) => + item.name === name && + item.source === 'registry+https://github.com/rust-lang/crates.io-index' && + cargoSatisfies(item.version, requirement) && + held.has(name + '@' + item.version), + ); + assert(retained.length <= 1, 'Ambiguous held source dependency: ' + name); + const dependency = retained.length + ? retain(name, retained[0].version) + : currentExact(name, cargoDependencyMinimum(requirement)); + assert( + dependency, + 'Missing actual held or selected exact source dependency: ' + name + ' ' + requirement, + ); + selected.set(name, dependency); + pending.push(dependency); + } + const inputs = [...selected.values()]; + return [ + source.name === 'oliphaunt' ? 'sdk' : 'broker', + inputs, + { + floors: inputs + .filter((row) => row.name !== source.name) + .map(({ name, version }) => ({ name, version })), + heldInputs: [...heldInputs], + ...(source.name === 'oliphaunt-broker' ? { source } : {}), + }, + ]; +} + +/** Verify all exact archive patches after Cargo has completed every precise update. */ +export function assertInstalledCargoMinimum( + lockText: string, + inputs: ReturnType[], + minimum: InstalledCargoMinimum, +) { + const lock = Bun.TOML.parse(lockText).package; + for (const floor of minimum.floors) { + const archive = inputs.filter( + (row) => row.name === floor.name && row.version === floor.version, + ); + assert.equal(archive.length, 1, 'Missing staged source floor identity: ' + floor.name); + const resolved = lock.filter((row: any) => row.name === floor.name); + assert.equal(resolved.length, 1, 'Ambiguous resolved source floor: ' + floor.name); + assert.equal( + resolved[0].version, + floor.version, + 'Resolved source dependency is not its exact floor: ' + floor.name, + ); + assert.equal( + resolved[0].source, + undefined, + 'Source floor did not use its explicit archive patch: ' + floor.name, + ); + for (const held of minimum.heldInputs.filter((row) => row.name === floor.name)) + assert.equal( + archive[0].sha256, + held.sha256, + 'Staged completed floor identity differs: ' + floor.name, + ); + } +} + +export function installedConsumerCases( + candidates: ReturnType[], + fixtureLock: string, + selectedProducts: string[], + minimum: boolean, + floorPool?: InstalledCargoFloorPool, +): InstalledConsumerCase[] { + const sdkRoots = candidates.filter((candidate) => + ['oliphaunt', 'oliphaunt-build'].includes(candidate.name), + ); + const core = candidates.filter((candidate) => candidate.name === 'liboliphaunt-native-bindings'); + assert.equal(core.length, 1, 'installed Core consumer needs one actual candidate envelope'); + if (minimum) { + const roots = [ + ['oliphaunt', 'oliphaunt-rust'], + ['oliphaunt-broker', 'oliphaunt-broker'], + ].filter(([, owner]) => selectedProducts.includes(owner)); + assert(roots.length, 'declared minimum qualification requires its prepared selected owner'); + assert(floorPool, 'Source minimum requires actual completed floor inputs and source owners'); + return roots.flatMap(([name, owner]) => { + const source = candidates.filter((row) => row.name === name); + assert.equal(source.length, 1, 'Minimum needs one current source archive: ' + name); + assert.equal(floorPool.owners[name], owner, 'Minimum source owner differs: ' + name); + const result = minimumSourceCase( + source[0], + candidates, + fixtureLock, + selectedProducts, + floorPool, + ); + return result[2]!.floors.length ? [result] : []; + }); + } + const helper = candidates.filter((row) => row.name === 'oliphaunt-build'); + assert.equal(helper.length, 1, 'Installed helper consumer needs one current helper archive'); + const helperInputs = candidateDependencyInputs(helper, candidates, fixtureLock, true); + assert( + !helperInputs.some((row) => row.name === 'oliphaunt'), + 'Helper consumer must retain its genuine held SDK', + ); + return [ + ['checkout', candidateDependencyInputs(sdkRoots, candidates, fixtureLock)], + [ + 'liboliphaunt-native-bindings', + candidateDependencyInputs(core, candidates, fixtureLock, true), + ], + ['helper-held-sdk', helperInputs], + ]; +} + +export function resolvedSdkRuntime( + consumerText: string, + lockText: string, + candidates: ReturnType[], + cargoHome: string, +) { + const consumer = Bun.TOML.parse(consumerText); + const lock = Bun.TOML.parse(lockText); + const rows = lock.package.filter((pkg: any) => pkg.name === 'oliphaunt'); + assert.equal(rows.length, 1, 'consumer must resolve one SDK identity'); + const sdk = rows[0]; + let archive; + if (sdk.source) { + assert.equal(sdk.source, 'registry+https://github.com/rust-lang/crates.io-index'); + const file = path.join( + cargoHome, + 'registry/cache/index.crates.io-1949cf8c6b5b557f', + `oliphaunt-${sdk.version}.crate`, + ); + // Genuine registry and canonical candidate archives both permit safe + // directory entries inside their conventional package root. + archive = cargoArchiveIdentity(file, readPortableArchiveEntries(file)); + assert.equal(archive.sha256, sdk.checksum, 'held SDK archive differs from genuine Cargo lock'); + } else { + archive = candidates.find( + (candidate) => candidate.name === sdk.name && candidate.version === sdk.version, + ); + assert(archive, 'resolved local SDK is not an explicitly selected candidate'); + } + const runtime = archive.manifest.package.metadata.oliphaunt['native-version']; + assert.equal(typeof runtime, 'string'); + assert.equal(consumer.package.metadata.oliphaunt['runtime-version'], runtime); + assert.equal(consumer.dependencies['liboliphaunt-native-linux-x64-gnu'], `=${runtime}`); + return runtime; +} + +async function main(args: string[]) { + const [specification, runfiles] = args; + assert(specification && runfiles && process.env.TEST_TMPDIR); + const spec = JSON.parse(readFileSync(specification, 'utf8')); + const file = (name: string) => path.join(runfiles, name); + const root = path.join(process.env.TEST_TMPDIR, 'installed-cargo'); + const cargoHome = path.join(root, 'cargo-home'); + for (const [input, destination] of Object.entries(spec.cargoHome) as [string, string][]) { + const output = path.join(cargoHome, 'registry', destination); + mkdirSync(path.dirname(output), { recursive: true }); + copyFileSync(file(input), output); + } + const archiveDirectory = path.join(root, 'archives'); + mkdirSync(archiveDirectory); + const candidates = spec.archives.map((archive: string, index: number) => { + // Runfiles are declared projections; strict archive validation operates on + // ordinary private copies, preserving its non-symlink filesystem contract. + const copied = path.join(archiveDirectory, `${index}-${path.basename(archive)}`); + copyFileSync(file(archive), copied); + return cargoCandidate(copied); + }); + const floorPool: InstalledCargoFloorPool | undefined = spec.floorPool && { + owners: spec.floorPool.owners, + archives: spec.floorPool.archives.map( + ( + row: { file: string; name: string; version: string; size: number; sha256: string }, + index: number, + ) => { + const copied = path.join( + archiveDirectory, + 'held-floor-' + index + '-' + path.basename(row.file), + ); + copyFileSync(file(row.file), copied); + const held = cargoArchiveIdentity(copied, readPortableArchiveEntries(copied)); + assert.equal(readFileSync(copied).length, row.size, 'Completed floor archive size differs'); + assert.equal(held.name, row.name, 'Completed floor package name differs'); + assert.equal(held.version, row.version, 'Completed floor package version differs'); + assert.equal(held.sha256, row.sha256, 'Completed floor archive checksum differs'); + return held; + }, + ), + }; + const payloadPool = cargoPayloadPool( + spec.payloadPool ?? { completed: [], current: [], owners: {} }, + spec.sourceOwners ?? {}, + file, + archiveDirectory, + ); + const env: Record = { + ...cargoLinkEnvironment( + JSON.parse(readFileSync(file(spec.compiler), 'utf8')) as CargoLinkConfiguration, + runfiles, + ), + CARGO_HOME: cargoHome, + CARGO_TARGET_DIR: path.join(root, 'target'), + CARGO_NET_OFFLINE: 'true', + RUSTC: file(spec.rustc), + RUSTDOC: file(spec.rustdoc), + PATH: path.dirname(file(spec.rustc)), + HOME: root, + TMPDIR: root, + }; + const fixtureLock = readFileSync(file(spec.lock), 'utf8'); + const cases = installedConsumerCases( + candidates, + fixtureLock, + spec.selectedProducts, + spec.minimum, + floorPool, + ); + const receipts = []; + for (const [name, selectedCandidates, minimum] of cases) { + const directory = path.join(root, name); + const consumer = minimum?.source + ? path.join(directory, 'crates', minimum.source.name + '-' + minimum.source.version) + : path.join(directory, 'consumer'); + const storage = path.join(directory, 'database-storage'); + if (!minimum?.source) mkdirSync(path.join(consumer, 'src'), { recursive: true }); + const sourceManifest = + minimum?.source && + readPortableArchiveEntries(minimum.source.file).get( + `${minimum.source.name}-${minimum.source.version}/Cargo.toml`, + ); + if (minimum?.source) assert(sourceManifest?.isFile, 'Original source manifest is missing'); + const manifest = sourceManifest + ? Buffer.from(sourceManifest.data()).toString('utf8') + : candidateConsumerManifest(readFileSync(file(spec.manifest), 'utf8'), selectedCandidates); + const sdk = + name === 'helper-held-sdk' + ? heldSdkCandidate(fixtureLock, cargoHome) + : selectedCandidates.find((row) => row.name === 'oliphaunt'); + const source = + minimum?.source ?? + sdk ?? + selectedCandidates.find((row) => row.name === 'liboliphaunt-native-bindings'); + assert(source, 'Installed case has no actual source owner'); + const payloadInputs = cargoPayloadInputs( + sdk && !selectedCandidates.includes(sdk) ? [...selectedCandidates, sdk] : selectedCandidates, + payloadPool, + { + currentSources: candidates, + sourceOwners: spec.sourceOwners ?? {}, + selectedProducts: spec.selectedProducts, + includeDev: !minimum, + ...(minimum?.source ? {} : { consumer: { manifest: Bun.TOML.parse(manifest), source } }), + }, + ); + const stagedCandidates = [...selectedCandidates, ...payloadInputs]; + const config = stageCargoCarrierInputs(stagedCandidates, directory); + const origin = (candidate: CargoCandidate) => + payloadPool.completed.some( + (row) => + row.name === candidate.name && + row.version === candidate.version && + row.sha256 === candidate.sha256, + ) + ? 'completed-payload' + : payloadInputs.includes(candidate) + ? 'current-payload' + : minimum?.heldInputs.includes(candidate) + ? 'completed-floor' + : 'current-source'; + if (!minimum?.source) writeFileSync(path.join(consumer, 'Cargo.toml'), manifest); + if (!minimum?.source) { + copyFileSync(file(spec.lock), path.join(consumer, 'Cargo.lock')); + copyFileSync( + file(name === 'liboliphaunt-native-bindings' ? spec.coreSource : spec.source), + path.join(consumer, 'src/main.rs'), + ); + if (name === 'liboliphaunt-native-bindings') + copyFileSync(file(spec.coreBuildScript), path.join(consumer, 'core-build.rs')); + else copyFileSync(file(spec.buildScript), path.join(consumer, 'build.rs')); + } + const cargo = (command: string[], captureMessages = false) => { + const result = Bun.spawnSync( + [ + file(spec.cargo), + '--config', + config, + ...command, + '--offline', + ...(command[0] === 'install' + ? [] + : ['--manifest-path', path.join(consumer, 'Cargo.toml')]), + ], + { + cwd: consumer, + env: { ...env, OLIPHAUNT_INSTALLED_STORAGE: storage }, + stdout: captureMessages ? 'pipe' : 'inherit', + stderr: 'inherit', + }, + ); + assert.equal( + result.exitCode, + 0, + `installed Cargo qualification failed: ${command.join(' ')}`, + ); + return captureMessages ? result.stdout.toString('utf8') : ''; + }; + if (minimum?.source) { + // Stock install compiles the original binary package's production graph. + // It ignores the packaged root/dev lock without rewriting authored inputs. + const messages = cargo( + [ + 'install', + '--path', + consumer, + '--root', + path.join(directory, 'installed'), + '--debug', + '--jobs', + '2', + '--message-format', + 'json', + ], + true, + ); + const compiled = assertCargoSourceArtifacts( + messages, + stagedCandidates.map((candidate) => ({ + name: candidate.name, + version: candidate.version, + manifestPath: path.join( + directory, + 'crates', + candidate.name + '-' + candidate.version, + 'Cargo.toml', + ), + })), + [minimum.source.name], + ); + receipts.push({ + case: name, + candidates: stagedCandidates.map((candidate) => ({ + name: candidate.name, + version: candidate.version, + sha256: candidate.sha256, + origin: origin(candidate), + selected: compiled.some((source) => source.name === candidate.name), + })), + compiled, + }); + continue; + } + // Genuine Cargo reconciles candidate versions using the closed registry context. + // This is qualification/preflight, never construction or a publication baseline. + cargo(['generate-lockfile']); + for (const floor of minimum?.floors ?? []) + cargo(['update', '-p', floor.name, '--precise', floor.version]); + const lockText = readFileSync(path.join(consumer, 'Cargo.lock'), 'utf8'); + if (minimum) assertInstalledCargoMinimum(lockText, selectedCandidates, minimum); + const lock = Bun.TOML.parse(lockText); + const runtime = + name === 'liboliphaunt-native-bindings' + ? Bun.TOML.parse(manifest).package.metadata.oliphaunt['runtime-version'] + : resolvedSdkRuntime(manifest, lockText, selectedCandidates, cargoHome); + for (const pkg of lock.package) { + if (pkg.source || pkg.name === 'frozen-consumer') continue; + assert( + stagedCandidates.some( + (candidate) => candidate.name === pkg.name && candidate.version === pkg.version, + ), + `unselected package was resolved from local source: ${pkg.name}@${pkg.version}`, + ); + } + for (const candidate of selectedCandidates) { + if (minimum?.heldInputs.includes(candidate)) continue; + const selected = lock.package.find((pkg: any) => pkg.name === candidate.name && !pkg.source); + if (['oliphaunt', 'oliphaunt-build'].includes(candidate.name)) + assert(selected, `consumer root candidate not selected: ${candidate.name}`); + if (name === 'liboliphaunt-native-bindings') + assert(selected, `Core-only consumer did not select candidate: ${candidate.name}`); + if (selected) + assert.equal( + selected.version, + candidate.version, + `candidate identity differs: ${candidate.name}`, + ); + } + cargo(['run', '--locked', '--jobs', '2']); + rmSync(storage, { recursive: true }); + receipts.push({ + case: name, + runtime, + candidates: stagedCandidates.map((candidate) => ({ + name: candidate.name, + version: candidate.version, + sha256: candidate.sha256, + origin: origin(candidate), + selected: lock.package.some( + (pkg: any) => + pkg.name === candidate.name && pkg.version === candidate.version && !pkg.source, + ), + })), + cargoLockSha256: createHash('sha256').update(lockText).digest('hex'), + }); + } + writeFileSync( + path.join(root, 'qualification.json'), + `${JSON.stringify( + { + scope: 'checkout-composition-installed-consumer', + status: 'passed', + cases: spec.minimum + ? cases.map(([name]) => + name === 'broker' ? 'broker-declared-floor-source-compile' : 'sdk-declared-minimum', + ) + : ['direct-sql-reopen', 'broker-sql-reopen', 'core-direct-sql-reopen'], + compositions: receipts, + }, + null, + 2, + )}\n`, + ); +} + +if (import.meta.main) await main(process.argv.slice(2)); diff --git a/build_defs/languages/installed/consumer.test.mts b/build_defs/languages/installed/consumer.test.mts new file mode 100644 index 000000000..0b0aea738 --- /dev/null +++ b/build_defs/languages/installed/consumer.test.mts @@ -0,0 +1,847 @@ +import { expect, test } from 'bun:test'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { basename, dirname, join } from 'node:path'; +import { createDeterministicTar } from '../../../tools/packaging/archive-directory.mts'; +import { assertCargoSourceArtifacts } from '../../../tools/packaging/frozen-cargo.mts'; +import { canonicalGzipSync } from '../../../tools/packaging/portable-archive.mts'; +import { archive } from '../../query/package.mts'; +import { + assertInstalledCargoMinimum, + candidateConsumerManifest, + candidateDependencyInputs, + cargoCandidate, + cargoPayloadInputs, + cargoPayloadPool, + installedConsumerCases, + resolvedSdkRuntime, +} from './consumer.mts'; + +const template = readFileSync(`${import.meta.dir}/fixture/Cargo.toml`, 'utf8'); +const sdkManifest = Bun.TOML.parse( + readFileSync(new URL('../../../src/native/sdks/rust/Cargo.toml', import.meta.url), 'utf8'), +); +const heldRuntime = sdkManifest.package.metadata.oliphaunt['native-version']; + +test('exact payload composition prefers completed bytes and materializes only requested archives', () => { + const directory = mkdtempSync(join(tmpdir(), 'oliphaunt-payload-pool-')); + try { + const make = (name: string, version: string, source: string, dependencies = {}) => { + const file = join(directory, `${name}-${version}-${source}.crate`); + writeFileSync( + file, + archive({ + [`${name}-${version}/Cargo.toml`]: Buffer.from( + `[package]\nname="${name}"\nversion="${version}"\n[dependencies]\n${Object.entries( + dependencies, + ) + .map(([name, version]) => `${name}="${version}"`) + .join('\n')}\n`, + ), + [`${name}-${version}/src/lib.rs`]: Buffer.from(`pub fn ${source}() {}\n`), + }), + ); + return cargoCandidate(file); + }; + const root = make('fixture-sdk', '1.1.0', 'sdk', { 'fixture-payload': '=2.1.0' }); + const held = make('fixture-payload', '2.1.0', 'held'); + const current = make(held.name, held.version, 'current'); + const row = (candidate: typeof held) => ({ + product: 'runtime', + version: candidate.version, + artifact: `cargo:${candidate.name}`, + file: { + path: candidate.file, + size: readFileSync(candidate.file).length, + sha256: candidate.sha256, + }, + }); + const copied = join(directory, 'copied'); + mkdirSync(copied); + const sourceOwners = { [root.name]: { product: 'sdk', version: root.version } }; + const pool = cargoPayloadPool( + { + completed: [row(held)], + current: [ + row(current), + { + ...row(current), + artifact: 'cargo:unused', + file: { path: '/deliberately-unavailable-unused.crate' }, + }, + ], + owners: { [held.name]: { product: 'runtime', version: held.version } }, + }, + sourceOwners, + (name) => name, + copied, + ); + const options = { currentSources: [root], sourceOwners, selectedProducts: ['sdk', 'runtime'] }; + expect(cargoPayloadInputs([root], pool, options)[0].sha256).toBe(held.sha256); + const currentOnly = cargoPayloadPool( + { completed: [], current: [row(current)], owners: pool.owners }, + sourceOwners, + (name) => name, + copied, + ); + expect(cargoPayloadInputs([root], currentOnly, options)[0].sha256).toBe(current.sha256); + const aliasRoot = { + ...root, + manifest: { + ...root.manifest, + dependencies: { payload_alias: { package: held.name, version: '= 2.1.0' } }, + }, + }; + expect( + cargoPayloadInputs([aliasRoot], currentOnly, { ...options, currentSources: [aliasRoot] })[0] + .sha256, + ).toBe(current.sha256); + for (const selectedProducts of [[], ['sdk'], ['runtime']]) + expect(() => + cargoPayloadInputs([root], currentOnly, { ...options, selectedProducts }), + ).toThrow('Missing actual exact payload'); + expect(() => + cargoPayloadInputs([root], currentOnly, { ...options, currentSources: [] }), + ).toThrow('Missing actual exact payload'); + expect(() => + cargoPayloadInputs([root], currentOnly, { + ...options, + sourceOwners: { [root.name]: { product: 'sdk', version: '1.2.0' } }, + }), + ).toThrow('Missing actual exact payload'); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('payload aliases, all target pins and original part requirements reject missing or conflicting inputs', () => { + const directory = mkdtempSync(join(tmpdir(), 'oliphaunt-payload-targets-')); + try { + const make = (name: string, version: string, manifest = '') => { + const file = join(directory, `${name}-${version}.crate`); + writeFileSync( + file, + archive({ + [`${name}-${version}/Cargo.toml`]: Buffer.from( + `[package]\nname="${name}"\nversion="${version}"\n${manifest}`, + ), + [`${name}-${version}/src/lib.rs`]: Buffer.from('pub fn payload() {}\n'), + }), + ); + return cargoCandidate(file); + }; + const part = make('fixture-part', '2.1.0'); + const payload = make( + 'fixture-payload', + '2.1.0', + '[build-dependencies]\nfixture-part="=2.1.0"\n', + ); + const root = make( + 'fixture-sdk', + '1.1.0', + `[target.'cfg(unix)'.dependencies]\nleft={package="${payload.name}",version="=2.1.0"}\n[target.'cfg(windows)'.dependencies]\nright={package="${part.name}",version="=2.1.0"}\n`, + ); + const row = (candidate: typeof part) => ({ + product: 'runtime', + version: candidate.version, + artifact: `github-release:${candidate.name}-${candidate.version}.crate`, + file: { + path: candidate.file, + size: readFileSync(candidate.file).length, + sha256: candidate.sha256, + }, + }); + const sourceOwners = { [root.name]: { product: 'sdk', version: root.version } }; + const owners = { + [payload.name]: { product: 'runtime', version: payload.version }, + [part.name]: { product: 'runtime', version: part.version }, + }; + const options = { currentSources: [root], sourceOwners, selectedProducts: ['sdk', 'runtime'] }; + let count = 0; + const pool = (completed: any[], current: any[]) => { + const copied = join(directory, `copied-${count++}`); + mkdirSync(copied); + return cargoPayloadPool({ completed, current, owners }, sourceOwners, (name) => name, copied); + }; + expect( + cargoPayloadInputs([root], pool([], [row(payload), row(part)]), options) + .map((value) => value.name) + .sort(), + ).toEqual([part.name, payload.name]); + expect(() => cargoPayloadInputs([root], pool([], [row(payload)]), options)).toThrow( + 'Missing actual exact payload archive: fixture-part', + ); + expect(() => cargoPayloadInputs([root], pool([row(payload)], [row(part)]), options)).toThrow( + 'Held source cannot consume current payload bytes: fixture-part', + ); + const higher = make(part.name, '2.2.0'); + expect(() => + cargoPayloadInputs([root], pool([row(payload), row(higher)], []), options), + ).toThrow('Missing actual exact payload archive: fixture-part'); + expect(() => pool([], [{ ...row(payload), product: 'wrong' }])).toThrow( + 'Payload owner differs', + ); + expect(() => + cargoPayloadInputs( + [root], + pool( + [], + [{ ...row(payload), file: { ...row(payload).file, sha256: '0'.repeat(64) } }, row(part)], + ), + options, + ), + ).toThrow('Payload archive SHA differs'); + expect(() => + cargoPayloadInputs( + [root], + pool([], [{ ...row(payload), artifact: 'cargo:fixture-part' }]), + options, + ), + ).toThrow(); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('Cargo compiler artifacts join staged manifests without parsing opaque package IDs', () => { + const directory = mkdtempSync(join(tmpdir(), 'oliphaunt-cargo-artifacts-')); + try { + const sources = ['broker', 'core', 'inactive'].map((name) => { + const manifestPath = join(directory, name, 'Cargo.toml'); + mkdirSync(dirname(manifestPath), { recursive: true }); + writeFileSync(manifestPath, `[package]\nname="${name}"\nversion="0.2.1"\n`); + return { name, version: '0.2.1', manifestPath }; + }); + const messages = sources + .slice(0, 2) + .map((source) => + JSON.stringify({ + reason: 'compiler-artifact', + manifest_path: source.manifestPath, + package_id: 'opaque and deliberately not a package spec', + fresh: true, + }), + ) + .join('\n'); + expect(assertCargoSourceArtifacts(messages, sources, ['broker'])).toEqual(sources.slice(0, 2)); + const ancestorAlias = join(directory, 'ancestor-alias'); + symlinkSync(directory, ancestorAlias, 'dir'); + expect( + assertCargoSourceArtifacts( + JSON.stringify({ + reason: 'compiler-artifact', + manifest_path: join(ancestorAlias, 'core', 'Cargo.toml'), + }), + sources, + ['core'], + ), + ).toEqual([sources[1]]); + expect(() => assertCargoSourceArtifacts(messages, sources, ['inactive'])).toThrow( + 'Cargo source was not compiled: inactive', + ); + const alias = join(directory, 'alias.toml'); + writeFileSync(alias, readFileSync(sources[1].manifestPath)); + expect(() => + assertCargoSourceArtifacts( + JSON.stringify({ reason: 'compiler-artifact', manifest_path: alias }), + sources, + ), + ).toThrow('Cargo compiled source differs: core@0.2.1'); + writeFileSync(alias, '[package]\nname="core"\nversion="0.2.2"\n'); + expect(() => + assertCargoSourceArtifacts( + JSON.stringify({ reason: 'compiler-artifact', manifest_path: alias }), + sources, + ), + ).toThrow('Cargo compiled source differs: core@0.2.1'); + expect(() => + assertCargoSourceArtifacts( + JSON.stringify({ reason: 'compiler-artifact', manifest_path: 'Cargo.toml' }), + sources, + ), + ).toThrow('absolute manifest path'); + expect(() => assertCargoSourceArtifacts(messages, [sources[0], sources[0]])).toThrow( + 'names are duplicated', + ); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); +function candidates(sdk = '0.3.2', helper = '0.3.2', broker = '0.3.1') { + return [ + { + name: 'oliphaunt', + version: sdk, + manifest: sdkManifest, + }, + { name: 'oliphaunt-build', version: helper }, + { name: 'oliphaunt-broker', version: broker }, + ] as Parameters[1]; +} + +test('candidate identity comes from the final archive manifest bytes', () => { + const directory = mkdtempSync(join(tmpdir(), 'oliphaunt-candidate-test-')); + try { + const file = join(directory, 'candidate.crate'); + writeFileSync( + file, + archive({ + [`${sdkManifest.package.name}-${sdkManifest.package.version}/Cargo.toml`]: Buffer.from( + readFileSync(new URL('../../../src/native/sdks/rust/Cargo.toml', import.meta.url)), + ), + }), + ); + const candidate = cargoCandidate(file); + expect(candidate.name).toBe(sdkManifest.package.name); + expect(candidate.version).toBe(sdkManifest.package.version); + expect(candidate.manifest.package.metadata.oliphaunt['native-version']).toBe(heldRuntime); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('canonical Cargo directories are accepted while mode and package boundaries stay strict', async () => { + const directory = mkdtempSync(join(tmpdir(), 'oliphaunt-cargo-directories-')); + try { + const root = join(directory, `${sdkManifest.package.name}-${sdkManifest.package.version}`); + mkdirSync(join(root, 'src'), { recursive: true }); + writeFileSync( + join(root, 'Cargo.toml'), + readFileSync(new URL('../../../src/native/sdks/rust/Cargo.toml', import.meta.url)), + ); + writeFileSync(join(root, 'src/lib.rs'), 'pub fn source() {}\n', { mode: 0o644 }); + const file = join(directory, 'canonical.crate'); + writeFileSync( + file, + canonicalGzipSync(await createDeterministicTar(root, { keepParent: true })), + ); + expect(cargoCandidate(file).name).toBe(sdkManifest.package.name); + writeFileSync( + file, + archive({ + [`${sdkManifest.package.name}-${sdkManifest.package.version}/Cargo.toml`]: readFileSync( + join(root, 'Cargo.toml'), + ), + 'outside.rs': Buffer.from('outside'), + }), + ); + expect(() => cargoCandidate(file)).toThrow('outside declared package'); + const executable = join(root, 'src/executable.rs'); + writeFileSync(executable, 'pub fn source() {}\n', { mode: 0o755 }); + writeFileSync( + file, + canonicalGzipSync( + await createDeterministicTar(root, { + keepParent: true, + modes: { [`${basename(root)}/src/executable.rs`]: 0o755 }, + }), + ), + ); + expect(() => cargoCandidate(file)).toThrow('0644'); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('candidate SDK/helper bumps update their consumer constraints and hold runtime', () => { + const manifest = Bun.TOML.parse( + candidateConsumerManifest(template, candidates('0.3.3', '0.3.4')), + ); + expect(manifest.dependencies.oliphaunt).toBe('=0.3.3'); + expect(manifest['build-dependencies']['oliphaunt-build']).toBe('=0.3.4'); + expect(manifest.dependencies['liboliphaunt-native-linux-x64-gnu']).toBe(`=${heldRuntime}`); + expect(manifest.package.metadata.oliphaunt['runtime-version']).toBe(heldRuntime); +}); + +test('broker-only candidate version changes do not retarget SDK or its runtime', () => { + expect( + candidateConsumerManifest( + template, + candidates('0.3.2', '0.3.2', '0.3.2').filter( + (candidate) => candidate.name === 'oliphaunt-broker', + ), + ), + ).toBe(template); + expect(candidateConsumerManifest(template, [])).toBe(template); +}); + +test('selected SDK/helper roots change only their own authored consumer constraints', () => { + const selectedSdk = candidates('0.3.3').filter((candidate) => candidate.name === 'oliphaunt'); + const sdkOnly = Bun.TOML.parse(candidateConsumerManifest(template, selectedSdk)); + expect(sdkOnly.dependencies.oliphaunt).toBe('=0.3.3'); + expect(sdkOnly['build-dependencies']['oliphaunt-build']).toBe('=0.3.2'); + const helperOnly = Bun.TOML.parse( + candidateConsumerManifest( + template, + candidates('0.3.2', '0.3.4').filter((candidate) => candidate.name === 'oliphaunt-build'), + ), + ); + expect(helperOnly.dependencies.oliphaunt).toBe('=0.3.2'); + expect(helperOnly['build-dependencies']['oliphaunt-build']).toBe('=0.3.4'); +}); + +test('held SDK runtime comes from the checksum-authenticated resolved archive', () => { + const directory = mkdtempSync(join(tmpdir(), 'oliphaunt-held-sdk-test-')); + try { + const file = join( + directory, + 'registry/cache/index.crates.io-1949cf8c6b5b557f/oliphaunt-0.3.2.crate', + ); + mkdirSync(dirname(file), { recursive: true }); + writeFileSync( + file, + archive({ + 'oliphaunt-0.3.2/Cargo.toml': Buffer.from( + `[package]\nname="oliphaunt"\nversion="0.3.2"\n[package.metadata.oliphaunt]\nnative-version="${heldRuntime}"\n`, + ), + }), + ); + const selected = cargoCandidate(file); + const lock = `[[package]]\nname="oliphaunt"\nversion="0.3.2"\nsource="registry+https://github.com/rust-lang/crates.io-index"\nchecksum="${selected.sha256}"\n`; + expect(resolvedSdkRuntime(template, lock, [], directory)).toBe(heldRuntime); + expect(() => + resolvedSdkRuntime(template, lock.replace(selected.sha256, '0'.repeat(64)), [], directory), + ).toThrow('held SDK archive differs'); + expect(() => + resolvedSdkRuntime( + template.replace(`runtime-version = "${heldRuntime}"`, 'runtime-version = "9.0.0"'), + lock, + [], + directory, + ), + ).toThrow(); + expect(() => + resolvedSdkRuntime( + template, + '[[package]]\nname="oliphaunt"\nversion="0.3.2"\n', + [], + directory, + ), + ).toThrow('explicitly selected candidate'); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('installed candidate staging follows declared future-major dependencies and retains compatible minimums', () => { + const candidate = (name: string, version: string, dependencies = {}) => + ({ name, version, manifest: { dependencies } }) as ReturnType; + const oldCore = 'liboliphaunt-native-bindings'; + const core = candidate(oldCore, '0.3.0'); + const broker = candidate('oliphaunt-broker', '0.4.0', { [oldCore]: '0.3.0' }); + const sdk = candidate('oliphaunt', '0.4.0', { [oldCore]: '0.3.0', 'oliphaunt-broker': '0.4.0' }); + const unrelated = candidate('oliphaunt-query', '1.0.0'); + const lock = `version=4\n[[package]]\nname="${oldCore}"\nversion="0.2.0"\nsource="registry+https://github.com/rust-lang/crates.io-index"\n[[package]]\nname="oliphaunt-broker"\nversion="0.3.1"\nsource="registry+https://github.com/rust-lang/crates.io-index"\n`; + expect( + candidateDependencyInputs([sdk], [sdk, core, broker, unrelated], lock, true).map( + (row) => row.name, + ), + ).toEqual(['oliphaunt', oldCore, 'oliphaunt-broker']); + expect( + candidateDependencyInputs([broker], [sdk, core, broker, unrelated], lock, true).map( + (row) => row.name, + ), + ).toEqual(['oliphaunt-broker', oldCore]); + const patch = candidate(oldCore, '0.2.1'); + const compatibleSdk = candidate('oliphaunt', '0.3.3', { [oldCore]: '0.2.0' }); + expect(candidateDependencyInputs([compatibleSdk], [compatibleSdk, patch], lock, true)).toEqual([ + compatibleSdk, + ]); + expect(candidateDependencyInputs([compatibleSdk], [compatibleSdk, patch], lock)).toEqual([ + compatibleSdk, + patch, + ]); +}); + +test('Core-only public consumer is independent of the held SDK requirement', () => { + const core = { name: 'liboliphaunt-native-bindings', version: '0.3.0' } as ReturnType< + typeof cargoCandidate + >; + const manifest = Bun.TOML.parse(candidateConsumerManifest(template, [core])); + expect(manifest.package.build).toBe('core-build.rs'); + expect(manifest.dependencies.oliphaunt).toBeUndefined(); + expect(manifest.dependencies['oliphaunt-broker']).toBeUndefined(); + expect(manifest.dependencies[core.name]).toBe('=0.3.0'); + expect(manifest.dependencies['liboliphaunt-native-linux-x64-gnu']).toBe(`=${heldRuntime}`); + expect(manifest['build-dependencies']['oliphaunt-build']).toBe('=0.3.2'); + expect(manifest.package.metadata.oliphaunt['runtime-version']).toBe(heldRuntime); + expect(candidateConsumerManifest(template, [])).toBe(template); +}); + +test('preparation keeps common and genuine held cases; final adds only the declared SDK minimum', () => { + const core = { + name: 'liboliphaunt-native-bindings', + version: '0.2.0', + manifest: { dependencies: {} }, + } as ReturnType; + const pool = [ + ...candidates().map((row) => ({ + ...row, + manifest: { + dependencies: row.name === 'oliphaunt' ? { 'liboliphaunt-native-bindings': '0.2.0' } : {}, + }, + })), + core, + ]; + const lock = + 'version=4\n[[package]]\nname="liboliphaunt-native-bindings"\nversion="0.2.0"\nsource="registry+https://github.com/rust-lang/crates.io-index"\nchecksum="' + + 'b'.repeat(64) + + '"\n'; + expect(installedConsumerCases(pool, lock, [], false).map(([name]) => name)).toEqual([ + 'checkout', + 'liboliphaunt-native-bindings', + 'helper-held-sdk', + ]); + expect(() => installedConsumerCases(pool, lock, [], true)).toThrow('prepared selected owner'); + expect(() => installedConsumerCases(pool, lock, ['liboliphaunt-native-bindings'], true)).toThrow( + 'prepared selected owner', + ); + expect( + installedConsumerCases(pool, lock, ['oliphaunt-rust'], true, { + archives: [sourceArchive(core.name, core.version, {}, {}, 'b'.repeat(64))], + owners: { + oliphaunt: 'oliphaunt-rust', + 'liboliphaunt-native-bindings': 'liboliphaunt-native-bindings', + }, + }).map(([name]) => name), + ).toEqual(['sdk']); +}); + +const sourceOwners = { + oliphaunt: 'oliphaunt-rust', + 'oliphaunt-build': 'oliphaunt-rust', + 'liboliphaunt-native-bindings': 'liboliphaunt-native-bindings', + 'oliphaunt-broker': 'oliphaunt-broker', + 'oliphaunt-query': 'oliphaunt-query', +}; +const sourceArchive = ( + name: string, + version: string, + dependencies = {}, + buildDependencies = {}, + sha256 = 'a'.repeat(64), +) => + ({ + name, + version, + sha256, + manifest: { + dependencies, + 'build-dependencies': buildDependencies, + package: { metadata: { oliphaunt: { 'native-version': heldRuntime } } }, + }, + }) as ReturnType; +const heldCoreLock = + 'version=4\n[[package]]\nname="liboliphaunt-native-bindings"\nversion="0.2.0"\nsource="registry+https://github.com/rust-lang/crates.io-index"\nchecksum="' + + 'b'.repeat(64) + + '"\n'; + +test('minimum cannot substitute a compatible higher unselected Core or omit actual floor facts', () => { + const sdk = sourceArchive('oliphaunt', '0.3.3', { 'liboliphaunt-native-bindings': '^0.2.1' }); + const core = sourceArchive('liboliphaunt-native-bindings', '0.2.2'); + const helper = sourceArchive('oliphaunt-build', '0.3.4'); + const pool = [sdk, core, helper]; + expect(() => installedConsumerCases(pool, heldCoreLock, ['oliphaunt-rust'], true)).toThrow( + 'actual completed floor inputs', + ); + expect(() => + installedConsumerCases(pool, heldCoreLock, ['oliphaunt-rust'], true, { + archives: [sourceArchive(core.name, '0.2.0', {}, {}, 'b'.repeat(64))], + owners: sourceOwners, + }), + ).toThrow('Missing exact source dependency floor archive: liboliphaunt-native-bindings@0.2.1'); +}); + +test('minimum stages exact retained Core and the SDK declared build-helper floor with separate origin facts', () => { + const sdk = sourceArchive( + 'oliphaunt', + '0.3.3', + { 'liboliphaunt-native-bindings': '^0.2.1', serde: '^1' }, + { 'oliphaunt-build': '^0.3.2' }, + ); + const core = sourceArchive('liboliphaunt-native-bindings', '0.2.2'); + const helper = sourceArchive('oliphaunt-build', '0.3.4'); + const held = [ + sourceArchive(core.name, '0.2.1', {}, {}, 'c'.repeat(64)), + sourceArchive(helper.name, '0.3.2', {}, {}, 'd'.repeat(64)), + ]; + const [name, inputs, minimum] = installedConsumerCases( + [sdk, core, helper], + heldCoreLock, + ['oliphaunt-rust'], + true, + { + archives: held, + owners: sourceOwners, + }, + )[0]; + expect(name).toBe('sdk'); + expect(inputs).toEqual([sdk, ...held]); + expect(minimum!.heldInputs).toEqual(held); + expect(minimum!.floors).toEqual(held.map(({ name, version }) => ({ name, version }))); + const manifest = Bun.TOML.parse(candidateConsumerManifest(template, inputs)); + expect(manifest['build-dependencies']['oliphaunt-build']).toBe('=0.3.2'); + expect(manifest.dependencies.oliphaunt).toBe('=0.3.3'); +}); + +test('SDK direct floors govern weaker actual downstream requirements and reject stronger conflicts', () => { + const sdk = sourceArchive('oliphaunt', '0.3.3', { + core: { package: 'liboliphaunt-native-bindings', version: '^0.2.1' }, + 'oliphaunt-broker': '^0.3.1', + 'oliphaunt-query': '^0.1.1', + }); + const core = sourceArchive('liboliphaunt-native-bindings', '0.2.2'); + const helper = sourceArchive('oliphaunt-build', '0.3.4'); + const floors = [ + sourceArchive(core.name, '0.2.1', {}, {}, 'c'.repeat(64)), + sourceArchive('oliphaunt-broker', '0.3.1', { + [core.name]: '^0.2.0', + 'oliphaunt-query': '^0.1.1', + }), + sourceArchive('oliphaunt-query', '0.1.1'), + ]; + const cases = installedConsumerCases( + [sdk, core, helper], + heldCoreLock, + ['oliphaunt-rust'], + true, + { + archives: floors, + owners: sourceOwners, + }, + ); + expect(cases[0][1]).toEqual([sdk, ...floors]); + const conflicting = structuredClone(floors); + conflicting[1].manifest.dependencies[core.name] = '^0.2.2'; + expect(() => + installedConsumerCases([sdk, core, helper], heldCoreLock, ['oliphaunt-rust'], true, { + archives: conflicting, + owners: sourceOwners, + }), + ).toThrow('Source floor conflicts with downstream requirement'); +}); + +test('exact current Core is allowed only for its selected source owner and never overwrites retained bytes', () => { + const sdk = sourceArchive('oliphaunt', '0.3.3', { 'liboliphaunt-native-bindings': '^0.2.1' }); + const core = sourceArchive('liboliphaunt-native-bindings', '0.2.1'); + const helper = sourceArchive('oliphaunt-build', '0.3.4'); + const pool = [sdk, core, helper]; + expect(() => + installedConsumerCases(pool, heldCoreLock, ['oliphaunt-rust'], true, { + archives: [], + owners: sourceOwners, + }), + ).toThrow('Missing exact source dependency floor archive'); + const current = installedConsumerCases(pool, heldCoreLock, ['oliphaunt-rust', core.name], true, { + archives: [], + owners: sourceOwners, + })[0]; + expect(current[1]).toEqual([sdk, core]); + expect(current[2]!.heldInputs).toEqual([]); + const retained = sourceArchive(core.name, core.version, {}, {}, 'c'.repeat(64)); + const completed = installedConsumerCases( + pool, + heldCoreLock, + ['oliphaunt-rust', core.name], + true, + { + archives: [retained], + owners: sourceOwners, + }, + )[0]; + expect(completed[1]).toEqual([sdk, retained]); + expect(completed[2]!.heldInputs).toEqual([retained]); +}); + +test('completed floor identities reject lock checksum conflicts and duplicate archive byte claims', () => { + const sdk = sourceArchive('oliphaunt', '0.3.3', { 'liboliphaunt-native-bindings': '^0.2.0' }); + const core = sourceArchive('liboliphaunt-native-bindings', '0.2.2'); + const helper = sourceArchive('oliphaunt-build', '0.3.4'); + const retained = sourceArchive(core.name, '0.2.0', {}, {}, 'c'.repeat(64)); + expect(() => + installedConsumerCases([sdk, core, helper], heldCoreLock, ['oliphaunt-rust'], true, { + archives: [retained], + owners: sourceOwners, + }), + ).toThrow('Completed floor differs from fixture lock'); + expect(() => + installedConsumerCases([sdk, core, helper], heldCoreLock, ['oliphaunt-rust'], true, { + archives: [retained, { ...retained, sha256: 'd'.repeat(64) }], + owners: sourceOwners, + }), + ).toThrow('Conflicting completed floor archive'); +}); + +test('the final minimum lock rejects higher versions, ambiguous rows and lost archive patch identity', () => { + const sdk = sourceArchive('oliphaunt', '0.3.3'); + const held = sourceArchive('liboliphaunt-native-bindings', '0.2.1', {}, {}, 'c'.repeat(64)); + const minimum = { floors: [{ name: held.name, version: held.version }], heldInputs: [held] }; + const lock = 'version=4\n[[package]]\nname="' + held.name + '"\nversion="0.2.1"\n'; + expect(() => assertInstalledCargoMinimum(lock, [sdk, held], minimum)).not.toThrow(); + expect(() => + assertInstalledCargoMinimum(lock.replace('0.2.1', '0.2.2'), [sdk, held], minimum), + ).toThrow('not its exact floor'); + expect(() => + assertInstalledCargoMinimum(lock + lock.replace('version=4\n', ''), [sdk, held], minimum), + ).toThrow('Ambiguous resolved source floor'); + expect(() => + assertInstalledCargoMinimum( + lock + 'source="registry+https://github.com/rust-lang/crates.io-index"\n', + [sdk, held], + minimum, + ), + ).toThrow('explicit archive patch'); + expect(() => + assertInstalledCargoMinimum(lock, [sdk, { ...held, sha256: 'd'.repeat(64) }], minimum), + ).toThrow('Staged completed floor identity differs'); +}); + +test('the third common case qualifies current helper against the unchanged genuine held SDK requirement', () => { + const sdk = sourceArchive('oliphaunt', '0.4.0'); + const core = sourceArchive('liboliphaunt-native-bindings', '0.2.2'); + const helper = sourceArchive('oliphaunt-build', '0.4.0'); + const cases = installedConsumerCases([sdk, core, helper], heldCoreLock, [], false); + expect(cases).toHaveLength(3); + expect(cases[2]).toEqual(['helper-held-sdk', [helper]]); + const manifest = Bun.TOML.parse(candidateConsumerManifest(template, cases[2][1])); + expect(manifest.dependencies.oliphaunt).toBe('=0.3.2'); + expect(manifest['build-dependencies']['oliphaunt-build']).toBe('=0.4.0'); + expect(manifest.dependencies['liboliphaunt-native-linux-x64-gnu']).toBe('=' + heldRuntime); +}); + +test('Broker-only minimum uses its own Core/query floors and original source envelope independently of SDK', () => { + const sdk = sourceArchive('oliphaunt', '0.3.3', { 'liboliphaunt-native-bindings': '^0.2.2' }); + const core = sourceArchive('liboliphaunt-native-bindings', '0.2.2'); + const helper = sourceArchive('oliphaunt-build', '0.3.4'); + const broker = sourceArchive('oliphaunt-broker', '0.3.1', { + [core.name]: '^0.2.1', + 'oliphaunt-query': '^0.1.1', + }); + broker.manifest['dev-dependencies'] = { [core.name]: '^0.2.2' }; + const floors = [ + sourceArchive(core.name, '0.2.1', {}, {}, 'c'.repeat(64)), + sourceArchive('oliphaunt-query', '0.1.1'), + ]; + const pool = [sdk, core, helper, broker]; + const cases = installedConsumerCases(pool, heldCoreLock, ['oliphaunt-broker'], true, { + archives: floors, + owners: sourceOwners, + }); + expect(cases).toHaveLength(1); + expect(cases[0][0]).toBe('broker'); + expect(cases[0][1]).toEqual([broker, ...floors]); + expect(cases[0][2]!.source).toBe(broker); + expect(cases[0][1]).not.toContain(sdk); + expect(cases[0][1]).not.toContain(helper); + expect(() => + installedConsumerCases(pool, heldCoreLock, ['oliphaunt-broker'], true, { + archives: floors.slice(1), + owners: sourceOwners, + }), + ).toThrow('Missing exact source dependency floor archive'); + expect(() => + installedConsumerCases(pool, heldCoreLock, ['oliphaunt-query'], true, { + archives: floors, + owners: sourceOwners, + }), + ).toThrow('prepared selected owner'); +}); + +test('selected SDK and Broker qualify their own distinct direct Core floors in separate cases', () => { + const core = sourceArchive('liboliphaunt-native-bindings', '0.2.2'); + const sdk = sourceArchive('oliphaunt', '0.3.3', { [core.name]: '^0.2.2' }); + const helper = sourceArchive('oliphaunt-build', '0.3.4'); + const broker = sourceArchive('oliphaunt-broker', '0.3.1', { [core.name]: '^0.2.1' }); + const floors = [ + sourceArchive(core.name, '0.2.2', {}, {}, 'c'.repeat(64)), + sourceArchive(core.name, '0.2.1', {}, {}, 'd'.repeat(64)), + ]; + const cases = installedConsumerCases( + [sdk, helper, core, broker], + heldCoreLock, + ['oliphaunt-rust', 'oliphaunt-broker'], + true, + { archives: floors, owners: sourceOwners }, + ); + expect(cases.map(([name]) => name)).toEqual(['sdk', 'broker']); + expect(cases[0][1]).toEqual([sdk, floors[0]]); + expect(cases[1][1]).toEqual([broker, floors[1]]); + expect(cases[0][2]!.source).toBeUndefined(); + expect(cases[1][2]!.source).toBe(broker); +}); + +test('grouped normal and build Core requirements choose the shared exact floor in either order', () => { + const core = sourceArchive('liboliphaunt-native-bindings', '0.2.2'); + const helper = sourceArchive('oliphaunt-build', '0.3.4'); + const held = sourceArchive(core.name, '0.2.1', {}, {}, 'c'.repeat(64)); + for (const [normal, build] of [ + ['^0.2.0', '^0.2.1'], + ['^0.2.1', '^0.2.0'], + ]) { + const sdk = sourceArchive( + 'oliphaunt', + '0.3.3', + { [core.name]: normal }, + { [core.name]: build }, + ); + const cases = installedConsumerCases( + [sdk, helper, core], + heldCoreLock, + ['oliphaunt-rust'], + true, + { archives: [held], owners: sourceOwners }, + ); + expect(cases[0][1]).toEqual([sdk, held]); + expect(cases[0][2]!.floors).toEqual([{ name: core.name, version: '0.2.1' }]); + } +}); + +test('normal build and target aliases group by the original dependency package identity', () => { + const core = sourceArchive('liboliphaunt-native-bindings', '0.2.2'); + const helper = sourceArchive('oliphaunt-build', '0.3.4'); + const held = sourceArchive(core.name, '0.2.1', {}, {}, 'c'.repeat(64)); + const sdk = sourceArchive( + 'oliphaunt', + '0.3.3', + { normal_core: { package: core.name, version: '^0.2.0' } }, + { build_core: { package: core.name, version: '^0.2.1' } }, + ); + sdk.manifest.target = { + 'cfg(unix)': { dependencies: { target_core: { package: core.name, version: '~0.2.1' } } }, + }; + const cases = installedConsumerCases( + [sdk, helper, core], + heldCoreLock, + ['oliphaunt-rust'], + true, + { archives: [held], owners: sourceOwners }, + ); + expect(cases[0][1]).toEqual([sdk, held]); + expect(cases[0][2]!.floors).toEqual([{ name: core.name, version: '0.2.1' }]); +}); + +test('grouped direct exact and range requirements reject an empty intersection', () => { + const core = sourceArchive('liboliphaunt-native-bindings', '0.2.2'); + const helper = sourceArchive('oliphaunt-build', '0.3.4'); + const floors = [ + sourceArchive(core.name, '0.2.0', {}, {}, 'b'.repeat(64)), + sourceArchive(core.name, '0.2.1', {}, {}, 'c'.repeat(64)), + ]; + for (const [normal, build] of [ + ['=0.2.0', '^0.2.1'], + ['^0.2.1', '=0.2.0'], + ]) { + const sdk = sourceArchive( + 'oliphaunt', + '0.3.3', + { [core.name]: normal }, + { [core.name]: build }, + ); + expect(() => + installedConsumerCases([sdk, helper, core], heldCoreLock, ['oliphaunt-rust'], true, { + archives: floors, + owners: sourceOwners, + }), + ).toThrow(); + } +}); diff --git a/build_defs/languages/installed/context.mts b/build_defs/languages/installed/context.mts new file mode 100644 index 000000000..2c68d44fa --- /dev/null +++ b/build_defs/languages/installed/context.mts @@ -0,0 +1,94 @@ +import assert from 'node:assert/strict'; +import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; + +export interface RegistryContext { + schema: string; + cargo: string; + repository: string; + target: string; + archives: { name: string; version: string }[]; + config: Record; + indexes: { path: string; header: string; records: Record[] }[]; +} + +export function validateRegistryContext(lockText: string, context: RegistryContext) { + assert.equal(context.schema, 'oliphaunt-installed-cargo-fixture-v1'); + assert.equal(context.repository, 'index.crates.io-1949cf8c6b5b557f'); + assert.equal(context.target, 'x86_64-unknown-linux-gnu'); + const lock = Bun.TOML.parse(lockText); + const records = new Map>(); + const indexPaths = new Set(); + for (const index of context.indexes) { + assert(/^(?:1|2|3\/[a-z0-9_-]|[a-z0-9_-]{2}\/[a-z0-9_-]{2})\/[a-z0-9_-]+$/u.test(index.path)); + assert(!indexPaths.has(index.path), `duplicate sparse index: ${index.path}`); + indexPaths.add(index.path); + const header = Buffer.from(index.header, 'base64'); + assert(header.subarray(0, 5).equals(Buffer.from([3, 2, 0, 0, 0]))); + assert.equal(header.at(-1), 0); + for (const record of index.records) { + const id = `${record.name}@${record.vers}`; + assert(!records.has(id), `duplicate registry record: ${id}`); + const name = String(record.name).toLowerCase(); + const key = + name.length === 1 + ? `1/${name}` + : name.length === 2 + ? `2/${name}` + : name.length === 3 + ? `3/${name[0]}/${name}` + : `${name.slice(0, 2)}/${name.slice(2, 4)}/${name}`; + assert.equal(index.path, key); + records.set(id, record); + } + } + const archives = []; + for (const pkg of lock.package ?? []) { + if (!pkg.source) continue; + assert.equal(pkg.source, 'registry+https://github.com/rust-lang/crates.io-index'); + assert(/^[a-f0-9]{64}$/u.test(pkg.checksum)); + const id = `${pkg.name}@${pkg.version}`; + assert.equal(records.get(id)?.cksum, pkg.checksum, `locked registry identity differs: ${id}`); + records.delete(id); + archives.push({ name: pkg.name, version: pkg.version, sha256: pkg.checksum }); + } + assert.equal(records.size, 0, 'registry snapshot contains unlocked records'); + const archiveIds = new Set( + context.archives.map((archive) => `${archive.name}@${archive.version}`), + ); + assert.equal(archiveIds.size, context.archives.length, 'duplicate acquired registry identity'); + const selected = archives.filter((archive) => + archiveIds.has(`${archive.name}@${archive.version}`), + ); + assert.equal(selected.length, archiveIds.size, 'acquisition includes an unlocked archive'); + return selected; +} + +export function writeRegistryIndex(context: RegistryContext, directory: string) { + const root = path.join(directory, 'registry/index', context.repository); + mkdirSync(root, { recursive: true }); + writeFileSync(path.join(root, 'config.json'), `${JSON.stringify(context.config)}\n`); + for (const index of context.indexes) { + const file = path.join(root, '.cache', index.path); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync( + file, + Buffer.concat([ + Buffer.from(index.header, 'base64'), + ...index.records.flatMap((record) => [ + Buffer.from(`${record.vers}\0`), + Buffer.from(`${JSON.stringify(record)}\0`), + ]), + ]), + ); + } +} + +if (import.meta.main) { + const [lock, index, output] = process.argv.slice(2); + assert(lock && index && output); + const context = JSON.parse(readFileSync(index, 'utf8')) as RegistryContext; + const archives = validateRegistryContext(readFileSync(lock, 'utf8'), context); + writeRegistryIndex(context, output); + writeFileSync(path.join(output, 'archives.json'), `${JSON.stringify(archives)}\n`); +} diff --git a/build_defs/languages/installed/context.test.mts b/build_defs/languages/installed/context.test.mts new file mode 100644 index 000000000..667e42557 --- /dev/null +++ b/build_defs/languages/installed/context.test.mts @@ -0,0 +1,28 @@ +import { expect, test } from 'bun:test'; +import { readFileSync } from 'node:fs'; +import { validateRegistryContext } from './context.mts'; + +const lock = readFileSync(`${import.meta.dir}/fixture/Cargo.lock`, 'utf8'); +const context = JSON.parse(readFileSync(`${import.meta.dir}/fixture/registry-index.json`, 'utf8')); + +test('every genuine locked registry archive has its exact captured sparse record', () => { + expect(validateRegistryContext(lock, context)).toHaveLength(context.archives.length); +}); + +test('mismatched archive checksum, missing record and duplicate identity fail closed', () => { + for (const mutate of [ + (value: typeof context) => { + value.indexes[0].records[0].cksum = '0'.repeat(64); + }, + (value: typeof context) => { + value.indexes[0].records.pop(); + }, + (value: typeof context) => { + value.indexes[0].records.push(value.indexes[0].records[0]); + }, + ]) { + const changed = structuredClone(context); + mutate(changed); + expect(() => validateRegistryContext(lock, changed)).toThrow(); + } +}); diff --git a/build_defs/languages/installed/defs.bzl b/build_defs/languages/installed/defs.bzl new file mode 100644 index 000000000..24cb2bc74 --- /dev/null +++ b/build_defs/languages/installed/defs.bzl @@ -0,0 +1,164 @@ +"""Closed checkout-composition installed qualification, separate from admission.""" + +load("@rules_cc//cc:find_cc_toolchain.bzl", "use_cc_toolchain") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/languages:cargo-toolchain.bzl", "cargo_test_toolchain") +load("@oliphaunt_metadata//:metadata.bzl", "COMPLETED_SUPPLIER_ARTIFACTS", "NATIVE_CURRENT_ARTIFACTS", "PREPARED_NATIVE_SELECTED_PRODUCTS", "PRODUCTS", "PUBLICATION_CARRIERS") +load("@native_cargo_metadata//:cargo.bzl", "CARGO") + +_RUST = "@rules_rust//rust:toolchain_type" + +def _runfile(ctx, file): + return file.short_path[3:] if file.short_path.startswith("../") else ctx.workspace_name + "/" + file.short_path + +def cargo_source_owners(names): + """Owner versions of only the explicitly declared Cargo source archives.""" + result = {} + for name in names: + rows = [row for row in PUBLICATION_CARRIERS if row["ecosystem"] == "cargo" and row["name"] == name and row["target"] == None] + if len(rows) != 1: + fail("source archive needs one canonical Cargo owner: " + name) + product = rows[0]["product"] + result[name] = {"product": product, "version": PRODUCTS[product]["version"]} + return result + +def cargo_payload_sources(source_owners): + """Declared flat original crate Files, separate from source-cohort archives.""" + pools = [] + for entries, completed in [(COMPLETED_SUPPLIER_ARTIFACTS, True), (NATIVE_CURRENT_ARTIFACTS or {}, False)]: + grouped = {} + for raw in entries.values(): + if not raw["file"]["path"].endswith(".crate"): + continue + row = dict(raw) + if completed: + row["product"] = raw["publication"]["product"] + row["version"] = raw["publication"]["version"] + row.pop("publication") + target = row["file"]["path"] + if target not in grouped: + grouped[target] = [] + grouped[target].append(row) + encoded = {} + for target, rows in grouped.items(): + cargo = {(row["product"], row["version"]): True for row in rows if row["artifact"].startswith("cargo:")} + retained = [row for row in rows if not (row["artifact"].startswith("github-release:") and (row["product"], row["version"]) in cargo)] + retained = [row for row in retained if not any([row["artifact"] in ["cargo:" + name, "github-release:" + name + "-" + row["version"] + ".crate"] for name in source_owners])] + if retained: + encoded[target] = json.encode(retained) + pools.append(encoded) + return struct(completed = pools[0], current = pools[1]) + +def cargo_payload_inputs(ctx, source_owners): + """Localize authenticated metadata Files without changing their identities.""" + pools = [] + inputs = [] + for entries in [ctx.attr.payload_completed, ctx.attr.payload_current]: + rows = [] + for target, encoded in entries.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1 or files[0].is_directory or not files[0].basename.endswith(".crate"): + fail("Cargo payload needs one original regular crate File") + for raw in json.decode(encoded): + row = dict(raw) + row["file"] = dict(raw["file"], path = _runfile(ctx, files[0])) + rows.append(row) + inputs.append(files[0]) + pools.append(rows) + owners = {} + for row in PUBLICATION_CARRIERS: + if row["ecosystem"] != "cargo" or row["name"] in source_owners: + continue + owner = {"product": row["product"], "version": PRODUCTS[row["product"]]["version"]} + if row["name"] in owners and owners[row["name"]] != owner: + fail("Cargo payload has conflicting canonical owners: " + row["name"]) + owners[row["name"]] = owner + return struct(specification = {"completed": pools[0], "current": pools[1], "owners": owners}, files = inputs) + +def _installed_cargo_test_impl(ctx): + rust = ctx.toolchains[_RUST] + if not rust.cargo: + fail("installed consumer needs the declared Cargo toolchain") + cc = cargo_test_toolchain(ctx) + cargo_files = ctx.files.cargo_home + archives = ctx.files.archives + source_owners = json.decode(ctx.attr.source_identities) + payloads = cargo_payload_inputs(ctx, source_owners) + floor_archives = [] + floor_files = [] + for target, encoded in ctx.attr.floor_sources.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1 or files[0].is_directory: + fail("completed internal floor needs one actual archive File") + row = json.decode(encoded) + row["file"] = _runfile(ctx, files[0]) + floor_archives.append(row) + floor_files.append(files[0]) + specification = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(specification, json.encode({ + "archives": [_runfile(ctx, file) for file in archives], + "cargoHome": {_runfile(ctx, file): file.short_path.split("/registry/")[-1] for file in cargo_files}, + "manifest": _runfile(ctx, ctx.file.manifest), + "lock": _runfile(ctx, ctx.file.lock), + "source": _runfile(ctx, ctx.file.source), + "coreSource": _runfile(ctx, ctx.file.core_source), + "buildScript": _runfile(ctx, ctx.file.build_script), + "coreBuildScript": _runfile(ctx, ctx.file.core_build_script), + "cargo": _runfile(ctx, rust.cargo), + "rustc": _runfile(ctx, rust.rustc), + "rustdoc": _runfile(ctx, rust.rust_doc), + "compiler": _runfile(ctx, cc.configuration), + "minimum": ctx.attr.minimum, + "selectedProducts": PREPARED_NATIVE_SELECTED_PRODUCTS, + "sourceOwners": source_owners, + "payloadPool": payloads.specification, + "floorPool": {"archives": floor_archives, "owners": ctx.attr.source_owners}, + })) + files = [specification, cc.configuration, ctx.file.manifest, ctx.file.lock, ctx.file.source, ctx.file.core_source, ctx.file.build_script, ctx.file.core_build_script, ctx.file._runner] + ctx.files._helpers + cargo_files + archives + floor_files + payloads.files + rust.all_files.to_list() + cc.files + return bun_test_entrypoint(ctx, runner = ctx.file._runner, arguments = [specification], files = files, source_files = [ctx.file._runner] + ctx.files._helpers, runfiles_argument = True) + +_installed_cargo_test = rule( + implementation = _installed_cargo_test_impl, + test = True, + fragments = ["cpp"], + toolchains = [_RUST] + BUN_SOURCE_TOOLCHAINS + use_cc_toolchain(), + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "archives": attr.label_list(mandatory = True, allow_files = True), + "cargo_home": attr.label(mandatory = True), + "floor_sources": attr.label_keyed_string_dict(allow_files = True), + "source_owners": attr.string_dict(), + "source_identities": attr.string(default = "{}"), + "payload_completed": attr.label_keyed_string_dict(allow_files = True), + "payload_current": attr.label_keyed_string_dict(allow_files = True), + "manifest": attr.label(mandatory = True, allow_single_file = True), + "lock": attr.label(mandatory = True, allow_single_file = True), + "source": attr.label(mandatory = True, allow_single_file = True), + "core_source": attr.label(mandatory = True, allow_single_file = True), + "minimum": attr.bool(default = False), + "build_script": attr.label(mandatory = True, allow_single_file = True), + "core_build_script": attr.label(mandatory = True, allow_single_file = True), + "_runner": attr.label(default = "//build_defs/languages/installed:consumer.mts", allow_single_file = True), + "_helpers": attr.label_list(default = ["//build_defs/languages:cargo-environment.mts", "//build_defs/languages:cargo-metadata.mts", "//:tools/packaging/cargo-manifest.mts", "//:tools/packaging/frozen-cargo.mts", "//:tools/packaging/portable-archive.mts"], allow_files = True), + }), +) + +def installed_cargo_test(name, args = [], **kwargs): + _installed_cargo_test(name = name, args = bun_test_entrypoint_args(name) + args, **kwargs) + +def installed_cargo_tests(name, archives, **kwargs): + names = [CARGO[native.package_relative_label(target).package]["name"] for target in archives] + source_owners = cargo_source_owners(names) + owners = {name: row["product"] for name, row in source_owners.items()} + payloads = cargo_payload_sources(source_owners) + floors = {} + for row in COMPLETED_SUPPLIER_ARTIFACTS.values(): + if row["artifact"] in ["cargo:" + value for value in names]: + floors[row["file"]["path"]] = json.encode({ + "name": row["artifact"][len("cargo:"):], + "version": row["publication"]["version"], + "size": row["file"]["size"], + "sha256": row["file"]["sha256"], + }) + common = dict(kwargs, source_identities = json.encode(source_owners), payload_completed = payloads.completed, payload_current = payloads.current) + installed_cargo_test(name = name + "_test", archives = archives, **common) + installed_cargo_test(name = name + "_minimum_test", archives = archives, minimum = True, floor_sources = floors, source_owners = owners, **common) diff --git a/build_defs/languages/installed/fixture/Cargo.lock b/build_defs/languages/installed/fixture/Cargo.lock new file mode 100644 index 000000000..1e9c6bcb3 --- /dev/null +++ b/build_defs/languages/installed/fixture/Cargo.lock @@ -0,0 +1,761 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "bitflags" +version = "2.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "cc" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50a649af8a827553c29fb0cb4bd4a6f1a0dd695bd3232b9bc98bd9c8a3ffbb8b" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "filetime" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759" +dependencies = [ + "cfg-if", + "libc", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484" + +[[package]] +name = "frozen-consumer" +version = "0.0.0" +dependencies = [ + "liboliphaunt-native-linux-x64-gnu", + "oliphaunt", + "oliphaunt-build", +] + +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "indexmap" +version = "2.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jobserver" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" +dependencies = [ + "getrandom 0.4.3", + "libc", +] + +[[package]] +name = "libc" +version = "0.2.190" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "liboliphaunt-native-bindings" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b0e758a0af81e354205e9ba8e668175357c974f3c3ad3421e681ad7e07d1ed8" +dependencies = [ + "fs2", + "getrandom 0.3.4", + "libloading", + "serde", + "serde_json", + "sha2", + "tar", + "zstd", +] + +[[package]] +name = "liboliphaunt-native-linux-arm64-gnu" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a5ae2dbc88b1fc41bb453318a4ffe234bdab1e949f0fe9774bac92cc93463" +dependencies = [ + "liboliphaunt-native-linux-arm64-gnu-part-001", + "liboliphaunt-native-linux-arm64-gnu-part-002", + "liboliphaunt-native-linux-arm64-gnu-part-003", +] + +[[package]] +name = "liboliphaunt-native-linux-arm64-gnu-part-001" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d63eaee7f7a5d0bc8aa69ca8bbd0c271de8d222a90beb6c4486ae20ca1a4c77" + +[[package]] +name = "liboliphaunt-native-linux-arm64-gnu-part-002" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7d836abcef6936f150b797db616a8dd0a09cb9896feeb3354d5bf906dff8c81" + +[[package]] +name = "liboliphaunt-native-linux-arm64-gnu-part-003" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de44447a45dbf350648e408723fea1fd645822eaa48ac2a46e14b86f9fb2397" + +[[package]] +name = "liboliphaunt-native-linux-x64-gnu" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a7c2c09940e87552b9a483570e5b16d0e6ce702161b3c9ef63668fc24501801" +dependencies = [ + "liboliphaunt-native-linux-x64-gnu-part-001", + "liboliphaunt-native-linux-x64-gnu-part-002", + "liboliphaunt-native-linux-x64-gnu-part-003", +] + +[[package]] +name = "liboliphaunt-native-linux-x64-gnu-part-001" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ca82664bbf83523f8673652351e6ae44547df8f19ade7afe9f9d2413f6d42c7" + +[[package]] +name = "liboliphaunt-native-linux-x64-gnu-part-002" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6c5e1b3f3ec9bafcccb9ffc8837b819df573d9f35cbaad4d84f93b2c8bb0cbc" + +[[package]] +name = "liboliphaunt-native-linux-x64-gnu-part-003" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acc036be00ee895312635a689f084a6de692fc5e1b23bc00127f5dd775b5cdd1" + +[[package]] +name = "liboliphaunt-native-macos-arm64" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "839f8e89997162f69776c459ea635604064aefbaac17888a409b037fc7afc0a9" +dependencies = [ + "liboliphaunt-native-macos-arm64-part-001", + "liboliphaunt-native-macos-arm64-part-002", + "liboliphaunt-native-macos-arm64-part-003", +] + +[[package]] +name = "liboliphaunt-native-macos-arm64-part-001" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38600004aca0b01f6c1236b7933b48a9077d14f4773520ae3b29ab8e0d3c333f" + +[[package]] +name = "liboliphaunt-native-macos-arm64-part-002" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "741985b9a87d5b522ded00d381b394217600d0068e6c5ac11224e0f46fb0ef52" + +[[package]] +name = "liboliphaunt-native-macos-arm64-part-003" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49ca042fde617a17b49ec813e98314add7dd13a84e6bcae6dd89fc0a1d47e81a" + +[[package]] +name = "liboliphaunt-native-windows-x64-msvc" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ec4b8d474c573c7c7d31c4f32d5fcebb463b9cbfb85594f223c2dafc971bfa2" +dependencies = [ + "liboliphaunt-native-windows-x64-msvc-part-001", + "liboliphaunt-native-windows-x64-msvc-part-002", + "liboliphaunt-native-windows-x64-msvc-part-003", + "liboliphaunt-native-windows-x64-msvc-part-004", + "liboliphaunt-native-windows-x64-msvc-part-005", + "liboliphaunt-native-windows-x64-msvc-part-006", + "liboliphaunt-native-windows-x64-msvc-part-007", + "liboliphaunt-native-windows-x64-msvc-part-008", + "liboliphaunt-native-windows-x64-msvc-part-009", +] + +[[package]] +name = "liboliphaunt-native-windows-x64-msvc-part-001" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "837c7b766bd87a90107a61cc8f858883d58037a5a9bc410bac38f6ed0356aa9a" + +[[package]] +name = "liboliphaunt-native-windows-x64-msvc-part-002" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b303124aebd76a582dd671b96ee464a932c23b5da7c883143a4189a1349ebf1e" + +[[package]] +name = "liboliphaunt-native-windows-x64-msvc-part-003" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37504ef3cbc6418ee270704e412ced9b41dc4213e56fefaf6f3f7cd485c6a4b8" + +[[package]] +name = "liboliphaunt-native-windows-x64-msvc-part-004" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df97608a8dcd90e58ddc18b96ae5bc535010c91f6882dedcf8839b32064bb19" + +[[package]] +name = "liboliphaunt-native-windows-x64-msvc-part-005" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fa5b98de5e495e4b33bc726f7b3f943fd46c952d99d88c5c7eecdb7dc847388" + +[[package]] +name = "liboliphaunt-native-windows-x64-msvc-part-006" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5d38b84b2066661d3e5aceafd6c235bc686e1dba970d529a3e94ca52bf9c54b" + +[[package]] +name = "liboliphaunt-native-windows-x64-msvc-part-007" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee3f10e55ca1b32fc3131abafa5ee51f68c582526c9719fada95020ca7e0b15c" + +[[package]] +name = "liboliphaunt-native-windows-x64-msvc-part-008" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8d5e4d399a7ac9af36d04d49955ef189a182390cb826e90f1b7f892f0316d1f" + +[[package]] +name = "liboliphaunt-native-windows-x64-msvc-part-009" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "179073da938834110fcf82a7a09a1ca0446f69e9b54c12c05dc46f577c45ca4c" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "oliphaunt" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f66cc378f5512a12e58b927b0ac013510c08d8d3f803d76ecce96fa07606faa5" +dependencies = [ + "getrandom 0.3.4", + "liboliphaunt-native-bindings", + "liboliphaunt-native-linux-arm64-gnu", + "liboliphaunt-native-linux-x64-gnu", + "liboliphaunt-native-macos-arm64", + "liboliphaunt-native-windows-x64-msvc", + "oliphaunt-broker", + "oliphaunt-broker-linux-arm64-gnu", + "oliphaunt-broker-linux-x64-gnu", + "oliphaunt-broker-macos-arm64", + "oliphaunt-broker-windows-x64-msvc", + "oliphaunt-build", + "oliphaunt-query", +] + +[[package]] +name = "oliphaunt-broker" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76788356082fcb1e935fc13c16d8f3fff3d240867291229d0714a982ee2a53a9" +dependencies = [ + "getrandom 0.3.4", + "liboliphaunt-native-bindings", + "oliphaunt-query", +] + +[[package]] +name = "oliphaunt-broker-linux-arm64-gnu" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06c00cd2397ecdb8c386d635795c57b596b86c4599836749d7d29b60b96d33c2" + +[[package]] +name = "oliphaunt-broker-linux-x64-gnu" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f29d435fc06ebd24044a3ff3c4fb5247849a2957bb2e075c536f7fa0928cf8" + +[[package]] +name = "oliphaunt-broker-macos-arm64" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c233022e9fd0957cebd01b07da67502bd90d589cc8849d243ef88ad54ea78364" + +[[package]] +name = "oliphaunt-broker-windows-x64-msvc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d2fb6262d793d3cac04daf04a3f8354d91de50719bb6045f649234cfbbee0" + +[[package]] +name = "oliphaunt-build" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a2a676749df3756473b4fd0deea7ef194a5d78bbcfb6fb46f5ae1da8f058f82" +dependencies = [ + "serde", + "sha2", + "toml", +] + +[[package]] +name = "oliphaunt-query" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523a7416f6a830ef02928994a2a89e9fd9d01e4fe67b22f0480d377d5f9b235c" + +[[package]] +name = "pkg-config" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rustix" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1741ab7a6cc54a03a89b5d563ed60075c277d9e3cfa73ad0c1f23f23974703c6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7523beb55eece201a2356bee0bbca0d1ab466c14c07703b2e0ee6d42cb0c2c" +dependencies = [ + "serde_core", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "syn" +version = "3.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d62a2e0561533f2ca2561d0cf27fd9fedb640a1bf2616ff5d5c80d99017faadc" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tar" +version = "0.4.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "toml" +version = "0.9.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow 0.7.15", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.1.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baa693a8032d7e1cada7d0041e96126df243179ff061456783ac7f12bda4744c" +dependencies = [ + "winnow 1.0.4", +] + +[[package]] +name = "toml_writer" +version = "1.1.3+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06bdbd8cfc056b8d2e2e85f29b56a3bdbecb527cef81eb39e3e7b98af4652770" + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicode-ident" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" + +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d80649ab6db9d9f6f9c80a40becd948eda4714a0a5ac8c4d157a32231c7882" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.1.1+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aeec9eaf2dffbbd09201e23bd0ffcbaa33bb8e9266a10734fd7ed90a85eca078" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/build_defs/languages/installed/fixture/Cargo.toml b/build_defs/languages/installed/fixture/Cargo.toml new file mode 100644 index 000000000..60a90047c --- /dev/null +++ b/build_defs/languages/installed/fixture/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "frozen-consumer" +version = "0.0.0" +edition = "2024" +[workspace] +[dependencies] +oliphaunt = "=0.3.2" +liboliphaunt-native-linux-x64-gnu = "=0.3.2" +[build-dependencies] +oliphaunt-build = "=0.3.2" +[package.metadata.oliphaunt] +runtime = "liboliphaunt-native" +runtime-version = "0.3.2" diff --git a/build_defs/languages/installed/fixture/build.rs b/build_defs/languages/installed/fixture/build.rs new file mode 100644 index 000000000..83366e004 --- /dev/null +++ b/build_defs/languages/installed/fixture/build.rs @@ -0,0 +1,3 @@ +fn main() { + oliphaunt_build::configure(); +} diff --git a/build_defs/languages/installed/fixture/core-build.rs b/build_defs/languages/installed/fixture/core-build.rs new file mode 100644 index 000000000..a41c68a63 --- /dev/null +++ b/build_defs/languages/installed/fixture/core-build.rs @@ -0,0 +1,8 @@ +fn main() { + let embedded = oliphaunt_build::embed_resolved_artifacts() + .expect("validate and embed direct Core Cargo runtime resources"); + println!( + "cargo::rustc-env=OLIPHAUNT_EMBEDDED_RESOURCES_RS={}", + embedded.display() + ); +} diff --git a/build_defs/languages/installed/fixture/core.rs b/build_defs/languages/installed/fixture/core.rs new file mode 100644 index 000000000..240cfea2f --- /dev/null +++ b/build_defs/languages/installed/fixture/core.rs @@ -0,0 +1,28 @@ +use liboliphaunt_native_bindings::{ + EmbeddedResource, NativeConfig, NativeSession, materialize_embedded_resources, + register_packaged_resources_dir, +}; + +const RESOURCES: &[EmbeddedResource] = include!(env!("OLIPHAUNT_EMBEDDED_RESOURCES_RS")); + +fn main() -> Result<(), Box> { + register_packaged_resources_dir(materialize_embedded_resources(RESOURCES)?)?; + let storage = std::path::PathBuf::from( + std::env::var_os("OLIPHAUNT_INSTALLED_STORAGE").ok_or("storage was not declared")?, + ); + let mut database = NativeSession::open(NativeConfig::direct(storage.clone()))?; + database.exec_simple_query( + "CREATE TABLE installed_answer(value int4); INSERT INTO installed_answer VALUES (42)", + )?; + database.close()?; + let mut database = NativeSession::open(NativeConfig::direct(storage))?; + let result = database.exec_simple_query("SELECT value FROM installed_answer")?; + assert!( + result + .windows(13) + .any(|value| value == b"D\0\0\0\x0c\0\x01\0\0\0\x0242") + ); + database.close()?; + eprintln!("installed Core Cargo consumer: direct SQL and reopen passed"); + Ok(()) +} diff --git a/build_defs/languages/installed/fixture/main.rs b/build_defs/languages/installed/fixture/main.rs new file mode 100644 index 000000000..bb3df0f4f --- /dev/null +++ b/build_defs/languages/installed/fixture/main.rs @@ -0,0 +1,40 @@ +use oliphaunt::{DatabaseStorage, Oliphaunt}; + +fn main() -> Result<(), Box> { + oliphaunt::register_build_resources!()?; + let directory = std::path::PathBuf::from( + std::env::var_os("OLIPHAUNT_INSTALLED_STORAGE") + .ok_or("installed consumer storage directory was not declared")?, + ); + for broker in [false, true] { + let mode = if broker { "broker" } else { "direct" }; + let storage = directory.join(mode); + eprintln!("installed Cargo consumer: {mode} first open"); + let builder = Oliphaunt::builder().storage(DatabaseStorage::Directory(storage.clone())); + let mut db = if broker { + builder.broker().open()? + } else { + builder.direct().open()? + }; + db.exec( + "CREATE TABLE installed_answer(value int4); INSERT INTO installed_answer VALUES (42)", + )?; + db.close()?; + eprintln!("installed Cargo consumer: {mode} reopen"); + let builder = Oliphaunt::builder().storage(DatabaseStorage::Directory(storage)); + let mut db = if broker { + builder.broker().open()? + } else { + builder.direct().open()? + }; + let rows = db + .sql("SELECT value AS answer FROM installed_answer") + .query()?; + assert_eq!(rows.rows()[0].try_get::("answer")?, 42); + db.close()?; + eprintln!("installed Cargo consumer: {mode} SQL and reopen passed"); + } + // Direct close detaches a process-resident backend. The parent removes + // storage after this process's terminal PostgreSQL shutdown has completed. + Ok(()) +} diff --git a/build_defs/languages/installed/fixture/registry-index.json b/build_defs/languages/installed/fixture/registry-index.json new file mode 100644 index 000000000..119ff71b9 --- /dev/null +++ b/build_defs/languages/installed/fixture/registry-index.json @@ -0,0 +1,6052 @@ +{ + "schema": "oliphaunt-installed-cargo-fixture-v1", + "cargo": "1.93.1", + "repository": "index.crates.io-1949cf8c6b5b557f", + "target": "x86_64-unknown-linux-gnu", + "archives": [ + { + "name": "bitflags", + "version": "2.13.2" + }, + { + "name": "block-buffer", + "version": "0.10.4" + }, + { + "name": "cc", + "version": "1.7.0" + }, + { + "name": "cfg-if", + "version": "1.0.5" + }, + { + "name": "cpufeatures", + "version": "0.2.17" + }, + { + "name": "crypto-common", + "version": "0.1.7" + }, + { + "name": "digest", + "version": "0.10.7" + }, + { + "name": "equivalent", + "version": "1.0.2" + }, + { + "name": "errno", + "version": "0.3.14" + }, + { + "name": "filetime", + "version": "0.2.29" + }, + { + "name": "find-msvc-tools", + "version": "0.1.14" + }, + { + "name": "fs2", + "version": "0.4.3" + }, + { + "name": "generic-array", + "version": "0.14.7" + }, + { + "name": "getrandom", + "version": "0.3.4" + }, + { + "name": "hashbrown", + "version": "0.17.1" + }, + { + "name": "indexmap", + "version": "2.14.2" + }, + { + "name": "itoa", + "version": "1.0.18" + }, + { + "name": "jobserver", + "version": "0.1.35" + }, + { + "name": "libc", + "version": "0.2.190" + }, + { + "name": "libloading", + "version": "0.8.9" + }, + { + "name": "liboliphaunt-native-bindings", + "version": "0.2.0" + }, + { + "name": "liboliphaunt-native-linux-x64-gnu-part-001", + "version": "0.3.2" + }, + { + "name": "liboliphaunt-native-linux-x64-gnu-part-002", + "version": "0.3.2" + }, + { + "name": "liboliphaunt-native-linux-x64-gnu-part-003", + "version": "0.3.2" + }, + { + "name": "liboliphaunt-native-linux-x64-gnu", + "version": "0.3.2" + }, + { + "name": "linux-raw-sys", + "version": "0.12.1" + }, + { + "name": "memchr", + "version": "2.8.3" + }, + { + "name": "oliphaunt-broker-linux-x64-gnu", + "version": "0.3.1" + }, + { + "name": "oliphaunt-broker", + "version": "0.3.1" + }, + { + "name": "oliphaunt-build", + "version": "0.3.2" + }, + { + "name": "oliphaunt-query", + "version": "0.1.1" + }, + { + "name": "oliphaunt", + "version": "0.3.2" + }, + { + "name": "pkg-config", + "version": "0.3.34" + }, + { + "name": "proc-macro2", + "version": "1.0.107" + }, + { + "name": "quote", + "version": "1.0.47" + }, + { + "name": "rustix", + "version": "1.1.5" + }, + { + "name": "serde_core", + "version": "1.0.229" + }, + { + "name": "serde_derive", + "version": "1.0.229" + }, + { + "name": "serde_json", + "version": "1.0.152" + }, + { + "name": "serde_spanned", + "version": "1.1.2" + }, + { + "name": "serde", + "version": "1.0.229" + }, + { + "name": "sha2", + "version": "0.10.9" + }, + { + "name": "shlex", + "version": "2.0.1" + }, + { + "name": "syn", + "version": "3.0.7" + }, + { + "name": "tar", + "version": "0.4.46" + }, + { + "name": "toml_datetime", + "version": "0.7.5+spec-1.1.0" + }, + { + "name": "toml_parser", + "version": "1.1.5+spec-1.1.0" + }, + { + "name": "toml_writer", + "version": "1.1.3+spec-1.1.0" + }, + { + "name": "toml", + "version": "0.9.12+spec-1.1.0" + }, + { + "name": "typenum", + "version": "1.20.1" + }, + { + "name": "unicode-ident", + "version": "1.0.26" + }, + { + "name": "version_check", + "version": "0.9.5" + }, + { + "name": "winnow", + "version": "0.7.15" + }, + { + "name": "winnow", + "version": "1.0.4" + }, + { + "name": "xattr", + "version": "1.6.1" + }, + { + "name": "zmij", + "version": "1.0.23" + }, + { + "name": "zstd-safe", + "version": "7.3.0" + }, + { + "name": "zstd-sys", + "version": "2.1.1+zstd.1.5.7" + }, + { + "name": "zstd", + "version": "0.13.3" + } + ], + "config": { + "dl": "https://static.crates.io/crates", + "api": "https://crates.io" + }, + "indexes": [ + { + "path": "2/cc", + "header": "AwIAAABldGFnOiAiNjFjMjgxZDJhMThiZjU1Y2Y1NGU1YjdmYWEwZDMzODIiAA==", + "records": [ + { + "name": "cc", + "vers": "1.7.0", + "deps": [ + { + "name": "find-msvc-tools", + "req": "^0.1.14", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "jobserver", + "req": "^0.1.32", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.168", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "shlex", + "req": "^2.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "50a649af8a827553c29fb0cb4bd4a6f1a0dd695bd3232b9bc98bd9c8a3ffbb8b", + "features": { + "jobserver": [] + }, + "features2": { + "parallel": ["dep:jobserver", "dep:libc"] + }, + "yanked": false, + "rust_version": "1.65.0", + "pubtime": "2026-10-10T01:21:09Z", + "v": 2 + } + ] + }, + { + "path": "3/f/fs2", + "header": "AwIAAABldGFnOiAiMWU5NzQ3ZWZlMWJkYThiNDE4OWE1ZjU0MTg5OTMyYzAiAA==", + "records": [ + { + "name": "fs2", + "vers": "0.4.3", + "deps": [ + { + "name": "libc", + "req": "^0.2.30", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "tempdir", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "winapi", + "req": "^0.3", + "features": [ + "handleapi", + "processthreadsapi", + "winerror", + "fileapi", + "winbase", + "std" + ], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213", + "features": {}, + "yanked": false, + "pubtime": "2018-01-06T20:18:30Z" + } + ] + }, + { + "path": "3/s/syn", + "header": "AwIAAABldGFnOiAiZjY1MzY0YzRhMGMwZjQ0MTNjYWJmYmMwMDZhMGM4ZGYiAA==", + "records": [ + { + "name": "syn", + "vers": "3.0.7", + "deps": [ + { + "name": "anyhow", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "automod", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "flate2", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "insta", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1.0.91", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.35", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "ref-cast", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "reqwest", + "req": "^0.13", + "features": ["blocking"], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn-test-suite", + "req": "^0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tar", + "req": "^0.4.16", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "termcolor", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicode-ident", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "walkdir", + "req": "^2.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + } + ], + "cksum": "d62a2e0561533f2ca2561d0cf27fd9fedb640a1bf2616ff5d5c80d99017faadc", + "features": { + "clone-impls": [], + "derive": [], + "extra-traits": [], + "fold": [], + "full": [], + "parsing": [], + "test": ["syn-test-suite/all-features"], + "visit": [], + "visit-mut": [] + }, + "features2": { + "default": ["derive", "parsing", "printing", "clone-impls", "proc-macro"], + "printing": ["dep:quote"], + "proc-macro": ["proc-macro2/proc-macro", "quote?/proc-macro"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-10-10T02:11:18Z", + "v": 2 + } + ] + }, + { + "path": "3/t/tar", + "header": "AwIAAABldGFnOiAiMzc2ODlhYTNiMzBiNmIwY2E1NzU5Y2JhMzAwZTQ2NTAiAA==", + "records": [ + { + "name": "tar", + "vers": "0.4.46", + "deps": [ + { + "name": "astral-tokio-tar", + "req": "^0.6.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "filetime", + "req": "^0.2.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.8", + "features": ["small_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tempfile", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio", + "req": "^1", + "features": ["macros", "rt"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-stream", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "xattr", + "req": "^1.1.3", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + } + ], + "cksum": "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840", + "features": { + "default": ["xattr"] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2026-05-18T19:12:11Z" + } + ] + }, + { + "path": "bi/tf/bitflags", + "header": "AwIAAABldGFnOiAiMmYyMjc0MzNjM2E4MGJlZWM2MmQyM2MzNGJiZWQwYWUiAA==", + "records": [ + { + "name": "bitflags", + "vers": "2.13.2", + "deps": [ + { + "name": "arbitrary", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "arbitrary", + "req": "^1.0", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "bytemuck", + "req": "^1.12", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytemuck", + "req": "^1.12.2", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.228", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_lib", + "req": "^1.0.103", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "serde" + }, + { + "name": "serde_test", + "req": "^1.0.19", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "zerocopy", + "req": "^0.8", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06", + "features": { + "example_generated": [], + "serde": ["serde_core"], + "std": [] + }, + "yanked": false, + "rust_version": "1.56.0", + "pubtime": "2026-09-10T01:11:38Z" + } + ] + }, + { + "path": "bl/oc/block-buffer", + "header": "AwIAAABldGFnOiAiMGI2OGE1OWNhZDMyZGVlODdhMTUwMjM3YzQxNmU2NjAiAA==", + "records": [ + { + "name": "block-buffer", + "vers": "0.10.4", + "deps": [ + { + "name": "generic-array", + "req": "^0.14", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71", + "features": {}, + "yanked": false, + "pubtime": "2023-03-09T02:08:25Z" + } + ] + }, + { + "path": "cf/g-/cfg-if", + "header": "AwIAAABldGFnOiAiNjA4MGZiYzc2YjkwZDM1ZWViNjYwMzY1M2I2MzMwZWYiAA==", + "records": [ + { + "name": "cfg-if", + "vers": "1.0.5", + "deps": [ + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + } + ], + "cksum": "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600", + "features": { + "rustc-dep-of-std": ["core"] + }, + "yanked": false, + "rust_version": "1.32", + "pubtime": "2026-09-16T17:36:11Z" + } + ] + }, + { + "path": "cp/uf/cpufeatures", + "header": "AwIAAABldGFnOiAiNzllZTI2NTM1MTg4ZmYzMTU4ZjMzOTU2YzU2MjIwN2QiAA==", + "records": [ + { + "name": "cpufeatures", + "vers": "0.2.17", + "deps": [ + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": false, + "target": "aarch64-linux-android", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_arch = \"aarch64\", target_os = \"linux\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_arch = \"aarch64\", target_vendor = \"apple\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_arch = \"loongarch64\", target_os = \"linux\"))", + "kind": "normal" + } + ], + "cksum": "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280", + "features": {}, + "yanked": false, + "pubtime": "2025-01-25T01:35:46Z" + } + ] + }, + { + "path": "cr/yp/crypto-common", + "header": "AwIAAABldGFnOiAiMTA5NWZjMDg1YTA4YWY4ZjY5ZWUzZDlkNzI1YWEzZDEiAA==", + "records": [ + { + "name": "crypto-common", + "vers": "0.1.7", + "deps": [ + { + "name": "generic-array", + "req": "=0.14.7", + "features": ["more_lengths"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rand_core", + "req": "^0.6", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "typenum", + "req": "^1.14", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a", + "features": { + "getrandom": ["rand_core/getrandom"], + "std": [] + }, + "yanked": false, + "pubtime": "2025-11-12T14:20:00Z" + } + ] + }, + { + "path": "di/ge/digest", + "header": "AwIAAABldGFnOiAiZWU1MWVhZjc4OWExZTE4ZGE5YmQzOTEwNzA5ODVkN2QiAA==", + "records": [ + { + "name": "digest", + "vers": "0.10.7", + "deps": [ + { + "name": "blobby", + "req": "^0.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "block-buffer", + "req": "^0.10", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "const-oid", + "req": "^0.9", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "crypto-common", + "req": "^0.1.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "subtle", + "req": "^2.4", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292", + "features": { + "alloc": [], + "core-api": ["block-buffer"], + "default": ["core-api"], + "dev": ["blobby"], + "mac": ["subtle"], + "oid": ["const-oid"], + "rand_core": ["crypto-common/rand_core"], + "std": ["alloc", "crypto-common/std"] + }, + "yanked": false, + "pubtime": "2023-05-19T17:11:30Z" + } + ] + }, + { + "path": "eq/ui/equivalent", + "header": "AwIAAABldGFnOiAiNDAzYWFhMjg5ZTc2MDhkZjExMDU4MzQ1NGEwZmQ5NTYiAA==", + "records": [ + { + "name": "equivalent", + "vers": "1.0.2", + "deps": [], + "cksum": "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f", + "features": {}, + "yanked": false, + "rust_version": "1.6", + "pubtime": "2025-02-14T22:14:18Z" + } + ] + }, + { + "path": "er/rn/errno", + "header": "AwIAAABldGFnOiAiZGJmNTUxMTljNDczZjI2MzI2MTc3NTdjNTNmZThmZjYiAA==", + "records": [ + { + "name": "errno", + "vers": "0.3.14", + "deps": [ + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os=\"hermit\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os=\"wasi\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.52, <0.62", + "features": ["Win32_Foundation", "Win32_System_Diagnostics_Debug"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb", + "features": { + "default": ["std"], + "std": ["libc/std"] + }, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2025-09-09T04:35:15Z" + } + ] + }, + { + "path": "fi/le/filetime", + "header": "AwIAAABldGFnOiAiYTZjYjhlZDk3MGY1N2I0ZjQzYWNlNWYzMWFhODcwZDEiAA==", + "records": [ + { + "name": "filetime", + "vers": "0.2.29", + "deps": [ + { + "name": "cfg-if", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.27", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759", + "features": {}, + "yanked": false, + "rust_version": "1.75.0", + "pubtime": "2026-05-12T22:38:22Z" + } + ] + }, + { + "path": "fi/nd/find-msvc-tools", + "header": "AwIAAABldGFnOiAiMWE5MmMxMzUyYmQ5NzFmNzJiNjI0NTFkZGE0ZDMzN2UiAA==", + "records": [ + { + "name": "find-msvc-tools", + "vers": "0.1.14", + "deps": [], + "cksum": "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484", + "features": {}, + "yanked": false, + "rust_version": "1.65.0", + "pubtime": "2026-09-25T10:09:48Z" + } + ] + }, + { + "path": "ge/ne/generic-array", + "header": "AwIAAABldGFnOiAiOGE0ZTFiYmVmNjI4NjM0Mjc2MzI2NWZiYWUyNGU0ZjEiAA==", + "records": [ + { + "name": "generic-array", + "vers": "0.14.7", + "deps": [ + { + "name": "bincode", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "typenum", + "req": "^1.12", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "version_check", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "zeroize", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a", + "features": { + "more_lengths": [] + }, + "yanked": false, + "pubtime": "2023-03-28T00:01:29Z" + } + ] + }, + { + "path": "ge/tr/getrandom", + "header": "AwIAAABldGFnOiAiNjM1OWY3YmUyMGQ5YjdlYjUxZDIwODNmZTNmYjZlMjQiAA==", + "records": [ + { + "name": "getrandom", + "vers": "0.3.4", + "deps": [ + { + "name": "cfg-if", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "js-sys", + "req": "^0.3.77", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\"), target_feature = \"atomics\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(any(target_os = \"linux\", target_os = \"android\"), not(any(all(target_os = \"linux\", target_env = \"\"), getrandom_backend = \"custom\", getrandom_backend = \"linux_raw\", getrandom_backend = \"rdrand\", getrandom_backend = \"rndr\"))))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"hurd\", target_os = \"illumos\", target_os = \"cygwin\", all(target_os = \"horizon\", target_arch = \"arm\")))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"haiku\", target_os = \"redox\", target_os = \"nto\", target_os = \"aix\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"ios\", target_os = \"visionos\", target_os = \"watchos\", target_os = \"tvos\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"macos\", target_os = \"openbsd\", target_os = \"vita\", target_os = \"emscripten\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"netbsd\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"solaris\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"vxworks\")", + "kind": "normal" + }, + { + "name": "r-efi", + "req": "^5.1", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_os = \"uefi\", getrandom_backend = \"efi_rng\"))", + "kind": "normal" + }, + { + "name": "wasip2", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_arch = \"wasm32\", target_os = \"wasi\", target_env = \"p2\"))", + "kind": "normal" + }, + { + "name": "wasm-bindgen", + "req": "^0.2.98", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\")))", + "kind": "normal" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\")))", + "kind": "dev" + } + ], + "cksum": "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd", + "features": { + "std": [] + }, + "features2": { + "wasm_js": ["dep:wasm-bindgen", "dep:js-sys"] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2025-10-14T17:47:36Z", + "v": 2 + }, + { + "name": "getrandom", + "vers": "0.4.3", + "deps": [ + { + "name": "cfg-if", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "js-sys", + "req": "^0.3.77", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(target_family = \"wasm\", any(target_os = \"unknown\", target_os = \"none\"), target_feature = \"atomics\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(any(target_os = \"linux\", target_os = \"android\"), not(any(all(target_os = \"linux\", target_env = \"\"), getrandom_backend = \"custom\", getrandom_backend = \"linux_raw\", getrandom_backend = \"rdrand\", getrandom_backend = \"rndr\"))))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"hurd\", target_os = \"illumos\", target_os = \"cygwin\", all(target_os = \"horizon\", target_arch = \"arm\")))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"haiku\", target_os = \"redox\", target_os = \"nto\", target_os = \"aix\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"ios\", target_os = \"visionos\", target_os = \"watchos\", target_os = \"tvos\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"macos\", target_os = \"openbsd\", target_os = \"vita\", target_os = \"emscripten\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"netbsd\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"solaris\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"vxworks\")", + "kind": "normal" + }, + { + "name": "r-efi", + "req": "^6", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_os = \"uefi\", getrandom_backend = \"efi_rng\"))", + "kind": "normal" + }, + { + "name": "rand_core", + "req": "^0.10.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasm-bindgen", + "req": "^0.2.98", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(target_family = \"wasm\", any(target_os = \"unknown\", target_os = \"none\")))", + "kind": "normal" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_family = \"wasm\", any(target_os = \"unknown\", target_os = \"none\")))", + "kind": "dev" + } + ], + "cksum": "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099", + "features": { + "std": [] + }, + "features2": { + "sys_rng": ["dep:rand_core"], + "wasm_js": ["dep:wasm-bindgen", "dep:js-sys"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-06-17T18:01:59Z", + "v": 2 + } + ] + }, + { + "path": "ha/sh/hashbrown", + "header": "AwIAAABldGFnOiAiZDg0ZDljN2I3NTVmYmRkYzg4OTJlN2M4NWNlMDEwYzQiAA==", + "records": [ + { + "name": "hashbrown", + "vers": "0.17.1", + "deps": [ + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "allocator-api2", + "req": "^0.2.9", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "bumpalo", + "req": "^3.13.0", + "features": ["allocator-api2"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "criterion", + "req": "^0.7", + "features": ["html_reports"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "equivalent", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "fnv", + "req": "^1.0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "foldhash", + "req": "^0.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9.0", + "features": ["small_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "^1.9.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(any())", + "kind": "normal" + }, + { + "name": "serde_core", + "req": "^1.0.221", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_test", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a", + "features": { + "inline-more": [], + "raw-entry": [], + "rustc-internal-api": [] + }, + "features2": { + "default": [ + "default-hasher", + "inline-more", + "allocator-api2", + "equivalent", + "raw-entry" + ], + "default-hasher": ["dep:foldhash"], + "nightly": ["foldhash?/nightly", "bumpalo/allocator_api"], + "rustc-dep-of-std": ["nightly", "core", "alloc", "rustc-internal-api"], + "serde": ["dep:serde_core", "dep:serde"] + }, + "yanked": false, + "rust_version": "1.85.0", + "pubtime": "2026-05-09T04:35:04Z", + "v": 2 + } + ] + }, + { + "path": "in/de/indexmap", + "header": "AwIAAABldGFnOiAiYjA1YTBkYjBhYTUzMTAzY2NhMDI0ZWFiZGI4NDExOTAiAA==", + "records": [ + { + "name": "indexmap", + "vers": "2.14.2", + "deps": [ + { + "name": "arbitrary", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "borsh", + "req": "^1.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "equivalent", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "fastrand", + "req": "^2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "fnv", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hashbrown", + "req": "^0.17", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "itertools", + "req": "^0.14", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quickcheck", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "^1.9", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(any())", + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "sval", + "req": "^2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855", + "features": { + "default": ["std"], + "std": [], + "test_debug": [] + }, + "features2": { + "serde": ["dep:serde_core", "dep:serde"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-09-05T01:53:48Z", + "v": 2 + } + ] + }, + { + "path": "it/oa/itoa", + "header": "AwIAAABldGFnOiAiZWE4NDk0ZDU2MGYxYjgxNzQ0NDM0OTViMzcwZTI3MmYiAA==", + "records": [ + { + "name": "itoa", + "vers": "1.0.18", + "deps": [ + { + "name": "criterion", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "no-panic", + "req": "^0.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682", + "features": {}, + "yanked": false, + "rust_version": "1.68", + "pubtime": "2026-03-20T00:12:37Z" + } + ] + }, + { + "path": "jo/bs/jobserver", + "header": "AwIAAABldGFnOiAiMDEwMTQ0MWVhMzM2M2Q1NTUxNWI1MWEyYTM4ZjcwMGQiAA==", + "records": [ + { + "name": "jobserver", + "vers": "0.1.35", + "deps": [ + { + "name": "getrandom", + "req": "^0.4", + "features": ["std"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.171", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "nix", + "req": "^0.31.3", + "features": ["fs"], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "dev" + }, + { + "name": "tempfile", + "req": "^3.10.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3", + "features": {}, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-07-06T01:43:15Z" + } + ] + }, + { + "path": "li/bc/libc", + "header": "AwIAAABldGFnOiAiOGEwODRkZTJkZmRmMDE4Njg2Y2NlYThjZDAzNzlmNjAiAA==", + "records": [ + { + "name": "libc", + "vers": "0.2.190", + "deps": [ + { + "name": "rustc-std-workspace-core", + "req": "^1.0.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78", + "features": { + "align": [], + "const-extern-fn": [], + "default": ["std"], + "extra_traits": [], + "rustc-dep-of-std": ["align", "rustc-std-workspace-core"], + "std": [], + "use_std": ["std"] + }, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-10-02T19:33:19Z" + } + ] + }, + { + "path": "li/bl/libloading", + "header": "AwIAAABldGFnOiAiZTMxNzYwZjkxZjUwMmQ3NmJkNGFjMWJhMjY3MGIxOGEiAA==", + "records": [ + { + "name": "libloading", + "vers": "0.8.9", + "deps": [ + { + "name": "cfg-if", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "windows-link", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": "^0.61", + "features": ["Win32_Foundation"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "dev" + } + ], + "cksum": "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55", + "features": {}, + "yanked": false, + "rust_version": "1.71.0", + "pubtime": "2025-09-21T10:59:30Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-native-bindings", + "header": "AwIAAABldGFnOiAiYjE0YWFiOThjODgyOTM4YmNmZDEzNjIyZTIxYjc3MjYiAA==", + "records": [ + { + "name": "liboliphaunt-native-bindings", + "vers": "0.2.0", + "deps": [ + { + "name": "fs2", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "getrandom", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libloading", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tar", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "zstd", + "req": "^0.13", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "7b0e758a0af81e354205e9ba8e668175357c974f3c3ad3421e681ad7e07d1ed8", + "features": { + "internal-native-packaging": [] + }, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-10-03T01:03:02Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-native-linux-arm64-gnu", + "header": "AwIAAABldGFnOiAiZWE1NGQ1ZmE3MzNmZTgyNGIwNjM4YjEzM2FmZTgyMGMiAA==", + "records": [ + { + "name": "liboliphaunt-native-linux-arm64-gnu", + "vers": "0.3.2", + "deps": [ + { + "name": "liboliphaunt-native-linux-arm64-gnu-part-001", + "req": "=0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "liboliphaunt-native-linux-arm64-gnu-part-002", + "req": "=0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "liboliphaunt-native-linux-arm64-gnu-part-003", + "req": "=0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "361a5ae2dbc88b1fc41bb453318a4ffe234bdab1e949f0fe9774bac92cc93463", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_liboliphaunt_native_linux_arm64_gnu", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:42:05Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-native-linux-arm64-gnu-part-001", + "header": "AwIAAABldGFnOiAiMGQ4MWRmYmU2YjNhNGZmOWFiNDhiYzM2NGQ0MjQ4MDYiAA==", + "records": [ + { + "name": "liboliphaunt-native-linux-arm64-gnu-part-001", + "vers": "0.3.2", + "deps": [], + "cksum": "3d63eaee7f7a5d0bc8aa69ca8bbd0c271de8d222a90beb6c4486ae20ca1a4c77", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_part_liboliphaunt_native_linux_arm64_gnu_001", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:22Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-native-linux-arm64-gnu-part-002", + "header": "AwIAAABldGFnOiAiMzUzNDIzMzNhYTEzY2ZjNGU0NDJiMzVjYTgwZjMwOTAiAA==", + "records": [ + { + "name": "liboliphaunt-native-linux-arm64-gnu-part-002", + "vers": "0.3.2", + "deps": [], + "cksum": "c7d836abcef6936f150b797db616a8dd0a09cb9896feeb3354d5bf906dff8c81", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_part_liboliphaunt_native_linux_arm64_gnu_002", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:23Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-native-linux-arm64-gnu-part-003", + "header": "AwIAAABldGFnOiAiMGQ4M2M4ZjllZmIyNGYzNGEwM2Q2MTMwNzU1MzM3Y2YiAA==", + "records": [ + { + "name": "liboliphaunt-native-linux-arm64-gnu-part-003", + "vers": "0.3.2", + "deps": [], + "cksum": "9de44447a45dbf350648e408723fea1fd645822eaa48ac2a46e14b86f9fb2397", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_part_liboliphaunt_native_linux_arm64_gnu_003", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:24Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-native-linux-x64-gnu", + "header": "AwIAAABldGFnOiAiNmM5YmVjNTY4ZWRlYzY1YTA0ZGIxNWQwMTJiZTg0NzkiAA==", + "records": [ + { + "name": "liboliphaunt-native-linux-x64-gnu", + "vers": "0.3.2", + "deps": [ + { + "name": "liboliphaunt-native-linux-x64-gnu-part-001", + "req": "=0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "liboliphaunt-native-linux-x64-gnu-part-002", + "req": "=0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "liboliphaunt-native-linux-x64-gnu-part-003", + "req": "=0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "5a7c2c09940e87552b9a483570e5b16d0e6ce702161b3c9ef63668fc24501801", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_liboliphaunt_native_linux_x64_gnu", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:42:05Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-native-linux-x64-gnu-part-001", + "header": "AwIAAABldGFnOiAiYjE0YjVkYjA2MTZhMmY1YjE1ZDU4NWNjYjIxZDFkNmUiAA==", + "records": [ + { + "name": "liboliphaunt-native-linux-x64-gnu-part-001", + "vers": "0.3.2", + "deps": [], + "cksum": "1ca82664bbf83523f8673652351e6ae44547df8f19ade7afe9f9d2413f6d42c7", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_part_liboliphaunt_native_linux_x64_gnu_001", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:24Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-native-linux-x64-gnu-part-002", + "header": "AwIAAABldGFnOiAiN2RlMmE5ZjZiZTNkMmUxNzFmMjk5Y2MwZDc3NDU5ZTYiAA==", + "records": [ + { + "name": "liboliphaunt-native-linux-x64-gnu-part-002", + "vers": "0.3.2", + "deps": [], + "cksum": "c6c5e1b3f3ec9bafcccb9ffc8837b819df573d9f35cbaad4d84f93b2c8bb0cbc", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_part_liboliphaunt_native_linux_x64_gnu_002", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:26Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-native-linux-x64-gnu-part-003", + "header": "AwIAAABldGFnOiAiMTA1YWQyMDBkMTA0NjAyNGY0MjEwMGJkOTI4YWY4NTAiAA==", + "records": [ + { + "name": "liboliphaunt-native-linux-x64-gnu-part-003", + "vers": "0.3.2", + "deps": [], + "cksum": "acc036be00ee895312635a689f084a6de692fc5e1b23bc00127f5dd775b5cdd1", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_part_liboliphaunt_native_linux_x64_gnu_003", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:26Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-native-macos-arm64", + "header": "AwIAAABldGFnOiAiYjY3YjZkODIwOTRmNDA3YjA4Mzc4Y2M0YTQ5YjAxYWIiAA==", + "records": [ + { + "name": "liboliphaunt-native-macos-arm64", + "vers": "0.3.2", + "deps": [ + { + "name": "liboliphaunt-native-macos-arm64-part-001", + "req": "=0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "liboliphaunt-native-macos-arm64-part-002", + "req": "=0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "liboliphaunt-native-macos-arm64-part-003", + "req": "=0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "839f8e89997162f69776c459ea635604064aefbaac17888a409b037fc7afc0a9", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_liboliphaunt_native_macos_arm64", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:42:06Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-native-macos-arm64-part-001", + "header": "AwIAAABldGFnOiAiZmRjODUyODU2OGEyMTZlNGU2ODJiODI4NjRhY2E3N2IiAA==", + "records": [ + { + "name": "liboliphaunt-native-macos-arm64-part-001", + "vers": "0.3.2", + "deps": [], + "cksum": "38600004aca0b01f6c1236b7933b48a9077d14f4773520ae3b29ab8e0d3c333f", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_part_liboliphaunt_native_macos_arm64_001", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:27Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-native-macos-arm64-part-002", + "header": "AwIAAABldGFnOiAiZDU4MWQ5MGVjOTRmYTA5MTY4M2YyMzU5Mzg4MzI3NzkiAA==", + "records": [ + { + "name": "liboliphaunt-native-macos-arm64-part-002", + "vers": "0.3.2", + "deps": [], + "cksum": "741985b9a87d5b522ded00d381b394217600d0068e6c5ac11224e0f46fb0ef52", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_part_liboliphaunt_native_macos_arm64_002", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:28Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-native-macos-arm64-part-003", + "header": "AwIAAABldGFnOiAiY2M2NzJlMGRkMDI0NTc3ZmQyZjAwYWY1NmEwZWJmODMiAA==", + "records": [ + { + "name": "liboliphaunt-native-macos-arm64-part-003", + "vers": "0.3.2", + "deps": [], + "cksum": "49ca042fde617a17b49ec813e98314add7dd13a84e6bcae6dd89fc0a1d47e81a", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_part_liboliphaunt_native_macos_arm64_003", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:29Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-native-windows-x64-msvc", + "header": "AwIAAABldGFnOiAiZTZjNjZhNDA3NjM0NGU4ZTE0Y2YwMjU0ZmUxZWEwOTkiAA==", + "records": [ + { + "name": "liboliphaunt-native-windows-x64-msvc", + "vers": "0.3.2", + "deps": [ + { + "name": "liboliphaunt-native-windows-x64-msvc-part-001", + "req": "=0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "liboliphaunt-native-windows-x64-msvc-part-002", + "req": "=0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "liboliphaunt-native-windows-x64-msvc-part-003", + "req": "=0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "liboliphaunt-native-windows-x64-msvc-part-004", + "req": "=0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "liboliphaunt-native-windows-x64-msvc-part-005", + "req": "=0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "liboliphaunt-native-windows-x64-msvc-part-006", + "req": "=0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "liboliphaunt-native-windows-x64-msvc-part-007", + "req": "=0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "liboliphaunt-native-windows-x64-msvc-part-008", + "req": "=0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "liboliphaunt-native-windows-x64-msvc-part-009", + "req": "=0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "3ec4b8d474c573c7c7d31c4f32d5fcebb463b9cbfb85594f223c2dafc971bfa2", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_liboliphaunt_native_windows_x64_msvc", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:42:13Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-native-windows-x64-msvc-part-001", + "header": "AwIAAABldGFnOiAiODNmYTM2NWQ1YzY3YzBkNjQxNzE5ZTJhODVhYzk4MjEiAA==", + "records": [ + { + "name": "liboliphaunt-native-windows-x64-msvc-part-001", + "vers": "0.3.2", + "deps": [], + "cksum": "837c7b766bd87a90107a61cc8f858883d58037a5a9bc410bac38f6ed0356aa9a", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_part_liboliphaunt_native_windows_x64_msvc_001", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:29Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-native-windows-x64-msvc-part-002", + "header": "AwIAAABldGFnOiAiMDAwOWNiZTdkMjg1YTA5NTc3ZjdhNzU4ZWM4YTZjNGMiAA==", + "records": [ + { + "name": "liboliphaunt-native-windows-x64-msvc-part-002", + "vers": "0.3.2", + "deps": [], + "cksum": "b303124aebd76a582dd671b96ee464a932c23b5da7c883143a4189a1349ebf1e", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_part_liboliphaunt_native_windows_x64_msvc_002", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:30Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-native-windows-x64-msvc-part-003", + "header": "AwIAAABldGFnOiAiY2NlY2M5NzhiYWIyNzkxNWY0OGE1ZjcxMTE2ZmU3N2QiAA==", + "records": [ + { + "name": "liboliphaunt-native-windows-x64-msvc-part-003", + "vers": "0.3.2", + "deps": [], + "cksum": "37504ef3cbc6418ee270704e412ced9b41dc4213e56fefaf6f3f7cd485c6a4b8", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_part_liboliphaunt_native_windows_x64_msvc_003", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:31Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-native-windows-x64-msvc-part-004", + "header": "AwIAAABldGFnOiAiNjMyZmIwOTg2ZjllOTY1YzRlZjI0M2NkNGU0M2UxNTQiAA==", + "records": [ + { + "name": "liboliphaunt-native-windows-x64-msvc-part-004", + "vers": "0.3.2", + "deps": [], + "cksum": "8df97608a8dcd90e58ddc18b96ae5bc535010c91f6882dedcf8839b32064bb19", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_part_liboliphaunt_native_windows_x64_msvc_004", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:31Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-native-windows-x64-msvc-part-005", + "header": "AwIAAABldGFnOiAiOGUzNThmZTgzOGM2MWJkMDlhYzRkNjMxNWI3MjE1NjAiAA==", + "records": [ + { + "name": "liboliphaunt-native-windows-x64-msvc-part-005", + "vers": "0.3.2", + "deps": [], + "cksum": "8fa5b98de5e495e4b33bc726f7b3f943fd46c952d99d88c5c7eecdb7dc847388", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_part_liboliphaunt_native_windows_x64_msvc_005", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:32Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-native-windows-x64-msvc-part-006", + "header": "AwIAAABldGFnOiAiYjMyNDY5NzNhNWI3MWU0ZmE3MDliODEyYzBkNDgxMTMiAA==", + "records": [ + { + "name": "liboliphaunt-native-windows-x64-msvc-part-006", + "vers": "0.3.2", + "deps": [], + "cksum": "d5d38b84b2066661d3e5aceafd6c235bc686e1dba970d529a3e94ca52bf9c54b", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_part_liboliphaunt_native_windows_x64_msvc_006", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:33Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-native-windows-x64-msvc-part-007", + "header": "AwIAAABldGFnOiAiOWY2M2IxNjIzY2I3YTdlYjg1OWI0ZWQ4MTdlNDJjNmIiAA==", + "records": [ + { + "name": "liboliphaunt-native-windows-x64-msvc-part-007", + "vers": "0.3.2", + "deps": [], + "cksum": "ee3f10e55ca1b32fc3131abafa5ee51f68c582526c9719fada95020ca7e0b15c", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_part_liboliphaunt_native_windows_x64_msvc_007", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:34Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-native-windows-x64-msvc-part-008", + "header": "AwIAAABldGFnOiAiNzdlZTAxMjMzYjIwNzA4YjA1MGU0MTcwMzk2NmUxZDQiAA==", + "records": [ + { + "name": "liboliphaunt-native-windows-x64-msvc-part-008", + "vers": "0.3.2", + "deps": [], + "cksum": "e8d5e4d399a7ac9af36d04d49955ef189a182390cb826e90f1b7f892f0316d1f", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_part_liboliphaunt_native_windows_x64_msvc_008", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:35Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-native-windows-x64-msvc-part-009", + "header": "AwIAAABldGFnOiAiYzBhMzZmYjE0NmM5YjkxMWRhODM2OTgyZGZmZTNiM2QiAA==", + "records": [ + { + "name": "liboliphaunt-native-windows-x64-msvc-part-009", + "vers": "0.3.2", + "deps": [], + "cksum": "179073da938834110fcf82a7a09a1ca0446f69e9b54c12c05dc46f577c45ca4c", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_part_liboliphaunt_native_windows_x64_msvc_009", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:36Z" + } + ] + }, + { + "path": "li/nu/linux-raw-sys", + "header": "AwIAAABldGFnOiAiN2Q4N2ZlNTc2NGExYmU2YmQ0ZTc4NWJkOWQ0NTU2NzAiAA==", + "records": [ + { + "name": "linux-raw-sys", + "vers": "0.12.1", + "deps": [ + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "libc", + "req": "^0.2.100", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53", + "features": { + "auxvec": [], + "bootparam": [], + "btrfs": [], + "default": ["std", "general", "errno"], + "elf": [], + "elf_uapi": [], + "errno": [], + "general": [], + "if_arp": [], + "if_ether": [], + "if_packet": [], + "if_tun": [], + "image": [], + "io_uring": [], + "ioctl": [], + "landlock": [], + "loop_device": [], + "mempolicy": [], + "net": [], + "netlink": [], + "no_std": [], + "prctl": [], + "ptrace": [], + "rustc-dep-of-std": ["core", "no_std"], + "std": [], + "system": [], + "vm_sockets": [], + "xdp": [] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2025-12-23T00:00:07Z" + } + ] + }, + { + "path": "me/mc/memchr", + "header": "AwIAAABldGFnOiAiYjgwNzAzZTViODExMTA4NjlkOTQ1ZGM3ZDkxOWE5YzEiAA==", + "records": [ + { + "name": "memchr", + "vers": "2.8.3", + "deps": [ + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "log", + "req": "^0.4.20", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1.0.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + } + ], + "cksum": "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98", + "features": { + "alloc": [], + "default": ["std"], + "libc": [], + "rustc-dep-of-std": ["core"], + "std": ["alloc"], + "use_std": ["std"] + }, + "features2": { + "logging": ["dep:log"] + }, + "yanked": false, + "rust_version": "1.61", + "pubtime": "2026-07-08T00:49:54Z", + "v": 2 + } + ] + }, + { + "path": "ol/ip/oliphaunt", + "header": "AwIAAABldGFnOiAiMDdmZmMzYmQzY2ZkYTEyNTRhNTgxNTZmNzk3ZWRlNWQiAA==", + "records": [ + { + "name": "oliphaunt", + "vers": "0.3.2", + "deps": [ + { + "name": "getrandom", + "req": "^0.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "liboliphaunt-native-bindings", + "req": "^0.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "liboliphaunt-native-linux-arm64-gnu", + "req": "=0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_os = \"linux\", target_arch = \"aarch64\", target_env = \"gnu\"))", + "kind": "normal" + }, + { + "name": "liboliphaunt-native-linux-x64-gnu", + "req": "=0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_os = \"linux\", target_arch = \"x86_64\", target_env = \"gnu\"))", + "kind": "normal" + }, + { + "name": "liboliphaunt-native-macos-arm64", + "req": "=0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_os = \"macos\", target_arch = \"aarch64\"))", + "kind": "normal" + }, + { + "name": "liboliphaunt-native-windows-x64-msvc", + "req": "=0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_os = \"windows\", target_arch = \"x86_64\", target_env = \"msvc\"))", + "kind": "normal" + }, + { + "name": "oliphaunt-broker", + "req": "^0.3.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "oliphaunt-broker-linux-arm64-gnu", + "req": "=0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_os = \"linux\", target_arch = \"aarch64\", target_env = \"gnu\"))", + "kind": "normal" + }, + { + "name": "oliphaunt-broker-linux-x64-gnu", + "req": "=0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_os = \"linux\", target_arch = \"x86_64\", target_env = \"gnu\"))", + "kind": "normal" + }, + { + "name": "oliphaunt-broker-macos-arm64", + "req": "=0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_os = \"macos\", target_arch = \"aarch64\"))", + "kind": "normal" + }, + { + "name": "oliphaunt-broker-windows-x64-msvc", + "req": "=0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_os = \"windows\", target_arch = \"x86_64\", target_env = \"msvc\"))", + "kind": "normal" + }, + { + "name": "oliphaunt-build", + "req": "^0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "oliphaunt-query", + "req": "^0.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio", + "req": "^1", + "features": ["rt", "time"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "f66cc378f5512a12e58b927b0ac013510c08d8d3f803d76ecce96fa07606faa5", + "features": {}, + "features2": { + "default": ["desktop"], + "desktop": ["dep:oliphaunt-broker", "dep:getrandom"], + "mobile-bindings": ["dep:oliphaunt-broker", "dep:libc"] + }, + "yanked": false, + "links": "oliphaunt_artifact_relay", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:42:17Z", + "v": 2 + } + ] + }, + { + "path": "ol/ip/oliphaunt-broker", + "header": "AwIAAABldGFnOiAiMzNmMTA4ZDE4Mjk3ZjZmZGNlY2I5MTBmZDkwZDFkZjIiAA==", + "records": [ + { + "name": "oliphaunt-broker", + "vers": "0.3.1", + "deps": [ + { + "name": "getrandom", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "liboliphaunt-native-bindings", + "req": "^0.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "oliphaunt-query", + "req": "^0.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "76788356082fcb1e935fc13c16d8f3fff3d240867291229d0714a982ee2a53a9", + "features": {}, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:55Z" + } + ] + }, + { + "path": "ol/ip/oliphaunt-broker-linux-arm64-gnu", + "header": "AwIAAABldGFnOiAiNGRjNWM5NGZiNzYyMjE5YzI2NGEzZmRkNDZlMTQwNmYiAA==", + "records": [ + { + "name": "oliphaunt-broker-linux-arm64-gnu", + "vers": "0.3.1", + "deps": [], + "cksum": "06c00cd2397ecdb8c386d635795c57b596b86c4599836749d7d29b60b96d33c2", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_broker_linux_arm64_gnu", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:54Z" + } + ] + }, + { + "path": "ol/ip/oliphaunt-broker-linux-x64-gnu", + "header": "AwIAAABldGFnOiAiZDNhMmZkM2ExNWNjZWM5ZTFjZTM3ZTIxZTE0ZTUzN2YiAA==", + "records": [ + { + "name": "oliphaunt-broker-linux-x64-gnu", + "vers": "0.3.1", + "deps": [], + "cksum": "72f29d435fc06ebd24044a3ff3c4fb5247849a2957bb2e075c536f7fa0928cf8", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_broker_linux_x64_gnu", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:54Z" + } + ] + }, + { + "path": "ol/ip/oliphaunt-broker-macos-arm64", + "header": "AwIAAABldGFnOiAiMjc3MTZkZTVmN2EyNzU5YjYwMWVlNWY3ZDEyNjdmZTYiAA==", + "records": [ + { + "name": "oliphaunt-broker-macos-arm64", + "vers": "0.3.1", + "deps": [], + "cksum": "c233022e9fd0957cebd01b07da67502bd90d589cc8849d243ef88ad54ea78364", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_broker_macos_arm64", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:55Z" + } + ] + }, + { + "path": "ol/ip/oliphaunt-broker-windows-x64-msvc", + "header": "AwIAAABldGFnOiAiOWY1NTMzNGQwZTJjZjYwMWY2NjFkNzRhYWI2NDI0MDkiAA==", + "records": [ + { + "name": "oliphaunt-broker-windows-x64-msvc", + "vers": "0.3.1", + "deps": [], + "cksum": "136d2fb6262d793d3cac04daf04a3f8354d91de50719bb6045f649234cfbbee0", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_broker_windows_x64_msvc", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:55Z" + } + ] + }, + { + "path": "ol/ip/oliphaunt-build", + "header": "AwIAAABldGFnOiAiOTUzOGIxZTVlZjNmNzNiYmRjNWJjZDM0N2M0YjU2YzAiAA==", + "records": [ + { + "name": "oliphaunt-build", + "vers": "0.3.2", + "deps": [ + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "5a2a676749df3756473b4fd0deea7ef194a5d78bbcfb6fb46f5ae1da8f058f82", + "features": {}, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-10-07T07:42:02Z" + } + ] + }, + { + "path": "ol/ip/oliphaunt-query", + "header": "AwIAAABldGFnOiAiNDk3ZWM1ZGNjZmQyOTIyNTY1ODM2ZWQ3YTZlMDRkZTUiAA==", + "records": [ + { + "name": "oliphaunt-query", + "vers": "0.1.1", + "deps": [], + "cksum": "523a7416f6a830ef02928994a2a89e9fd9d01e4fe67b22f0480d377d5f9b235c", + "features": {}, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-10-03T01:03:22Z" + } + ] + }, + { + "path": "pk/g-/pkg-config", + "header": "AwIAAABldGFnOiAiZjJiODI5OWQ4MmIxMDhmNDNkOGQxODViYTMyNzRiNDgiAA==", + "records": [ + { + "name": "pkg-config", + "vers": "0.3.34", + "deps": [], + "cksum": "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548", + "features": {}, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2026-08-14T08:27:51Z" + } + ] + }, + { + "path": "pr/oc/proc-macro2", + "header": "AwIAAABldGFnOiAiYWJhYmI1OTE1N2M2ZTlhNzE0YTliMWNiMzAyZTg0MmUiAA==", + "records": [ + { + "name": "proc-macro2", + "vers": "1.0.107", + "deps": [ + { + "name": "flate2", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quote", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tar", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicode-ident", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9", + "features": { + "default": ["proc-macro"], + "nightly": [], + "proc-macro": [], + "span-locations": [] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-19T00:18:25Z" + } + ] + }, + { + "path": "qu/ot/quote", + "header": "AwIAAABldGFnOiAiNzI5NmI3Yzk0OGUyODExNjhiMGVhZTc0NjVmZTM5MTgiAA==", + "records": [ + { + "name": "quote", + "vers": "1.0.47", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.80", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rustversion", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.108", + "features": ["diff"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001", + "features": { + "default": ["proc-macro"], + "proc-macro": ["proc-macro2/proc-macro"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-19T00:16:57Z" + } + ] + }, + { + "path": "r-/ef/r-efi", + "header": "AwIAAABldGFnOiAiNDdiZGU4NjlmOWVjMzhmNzdkZjI2YjJlZTQxZGQ1ZTYiAA==", + "records": [ + { + "name": "r-efi", + "vers": "5.3.0", + "deps": [ + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + } + ], + "cksum": "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f", + "features": { + "efiapi": [], + "examples": ["native"], + "native": [], + "rustc-dep-of-std": ["core"] + }, + "yanked": false, + "rust_version": "1.68", + "pubtime": "2025-06-17T09:12:38Z" + }, + { + "name": "r-efi", + "vers": "6.0.0", + "deps": [ + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + } + ], + "cksum": "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf", + "features": { + "native": [], + "rustc-dep-of-std": ["core"] + }, + "yanked": false, + "rust_version": "1.68", + "pubtime": "2026-02-03T09:53:46Z" + } + ] + }, + { + "path": "ru/st/rustix", + "header": "AwIAAABldGFnOiAiMTRkZDQxMTBiMGY3MDMwNWU2MGU0ZjI2OGIxZDE3NmQiAA==", + "records": [ + { + "name": "rustix", + "vers": "1.1.5", + "deps": [ + { + "name": "bitflags", + "req": "^2.4.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "criterion", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(criterion, not(any(target_os = \"emscripten\", target_os = \"wasi\"))))", + "kind": "dev" + }, + { + "name": "flate2", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "libc", + "req": "^0.2.182", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\")))))))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.182", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(not(rustix_use_libc), not(miri), target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\"))))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.171", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "libc_errno", + "req": "^0.3.10", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\")))))))", + "kind": "normal", + "package": "errno" + }, + { + "name": "libc_errno", + "req": "^0.3.10", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(windows)", + "kind": "normal", + "package": "errno" + }, + { + "name": "libc_errno", + "req": "^0.3.10", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(not(rustix_use_libc), not(miri), target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\"))))", + "kind": "normal", + "package": "errno" + }, + { + "name": "libc_errno", + "req": "^0.3.10", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "errno" + }, + { + "name": "linux-raw-sys", + "req": "^0.12", + "features": ["general", "ioctl", "no_std"], + "optional": false, + "default_features": false, + "target": "cfg(all(any(target_os = \"linux\", target_os = \"android\"), any(rustix_use_libc, miri, not(all(target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\")))))))", + "kind": "normal" + }, + { + "name": "linux-raw-sys", + "req": "^0.12", + "features": ["auxvec", "general", "errno", "ioctl", "no_std", "elf"], + "optional": false, + "default_features": false, + "target": "cfg(all(not(rustix_use_libc), not(miri), target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\"))))", + "kind": "normal" + }, + { + "name": "memoffset", + "req": "^0.9.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "once_cell", + "req": "^1.20.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "dev" + }, + { + "name": "rustc-std-workspace-alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serial_test", + "req": "^2.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tempfile", + "req": "^3.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "windows-sys", + "req": ">=0.52, <0.62", + "features": ["Win32_Foundation", "Win32_Networking_WinSock"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d", + "features": { + "all-apis": [ + "event", + "fs", + "io_uring", + "mm", + "mount", + "net", + "param", + "pipe", + "process", + "pty", + "rand", + "runtime", + "shm", + "stdio", + "system", + "termios", + "thread", + "time" + ], + "alloc": [], + "event": [], + "fs": [], + "io_uring": ["event", "fs", "net", "thread", "linux-raw-sys/io_uring"], + "linux_4_11": [], + "linux_5_1": ["linux_4_11"], + "linux_5_11": ["linux_5_1"], + "linux_latest": ["linux_5_11"], + "mm": [], + "mount": [], + "net": [ + "linux-raw-sys/net", + "linux-raw-sys/netlink", + "linux-raw-sys/if_ether", + "linux-raw-sys/xdp" + ], + "param": [], + "pipe": [], + "process": ["linux-raw-sys/prctl"], + "pty": ["fs"], + "rand": [], + "runtime": ["linux-raw-sys/prctl"], + "rustc-dep-of-std": [ + "core", + "rustc-std-workspace-alloc", + "linux-raw-sys/rustc-dep-of-std", + "bitflags/rustc-dep-of-std" + ], + "shm": ["fs"], + "stdio": [], + "system": ["linux-raw-sys/system"], + "termios": [], + "thread": ["linux-raw-sys/prctl"], + "time": [], + "try_close": [], + "use-explicitly-provided-auxv": [], + "use-libc": ["libc_errno", "libc"], + "use-libc-auxv": [] + }, + "features2": { + "default": ["std"], + "std": ["bitflags/std", "alloc", "libc?/std", "libc_errno?/std"] + }, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-09-16T23:05:02Z", + "v": 2 + } + ] + }, + { + "path": "se/rd/serde", + "header": "AwIAAABldGFnOiAiOTcxZTFhNzFkN2Q2YWZiZmM5MGEyM2FkOTE5MzExMDMiAA==", + "records": [ + { + "name": "serde", + "vers": "1.0.229", + "deps": [ + { + "name": "serde_core", + "req": "=1.0.229", + "features": ["result"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba", + "features": { + "alloc": ["serde_core/alloc"], + "default": ["std"], + "derive": ["serde_derive"], + "rc": ["serde_core/rc"], + "std": ["serde_core/std"], + "unstable": ["serde_core/unstable"] + }, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2026-07-18T23:05:13Z" + } + ] + }, + { + "path": "se/rd/serde_core", + "header": "AwIAAABldGFnOiAiMDY3N2FlODQ2MzcwZWVmNTdkMDBkYjRhZjdhYjM5ZmMiAA==", + "records": [ + { + "name": "serde_core", + "vers": "1.0.229", + "deps": [ + { + "name": "serde", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_derive", + "req": "=1.0.229", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any())", + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48", + "features": { + "alloc": [], + "default": ["std", "result"], + "rc": [], + "result": [], + "std": [], + "unstable": [] + }, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2026-07-18T23:05:10Z" + } + ] + }, + { + "path": "se/rd/serde_derive", + "header": "AwIAAABldGFnOiAiOWM3YjkyYmFjZWE4YmNhMTdlZTI2MzBiNjQyZjA2ZTUiAA==", + "records": [ + { + "name": "serde_derive", + "vers": "1.0.229", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.74", + "features": ["proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.35", + "features": ["proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn", + "req": "^3", + "features": ["clone-impls", "derive", "parsing", "printing", "proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348", + "features": { + "default": [], + "deserialize_in_place": [] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-18T23:05:07Z" + } + ] + }, + { + "path": "se/rd/serde_json", + "header": "AwIAAABldGFnOiAiNzAxZjRjM2IyZGU3NTVmYTg2YzViM2JiZjUwZGZlNzYiAA==", + "records": [ + { + "name": "serde_json", + "vers": "1.0.152", + "deps": [ + { + "name": "automod", + "req": "^1.0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "indexmap", + "req": "^2.2.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "indoc", + "req": "^2.0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "itoa", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memchr", + "req": "^2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "ref-cast", + "req": "^1.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0.13", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any())", + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.194", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_bytes", + "req": "^0.11.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.220", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1.0.166", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_stacker", + "req": "^0.1.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.108", + "features": ["diff"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "zmij", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "1741ab7a6cc54a03a89b5d563ed60075c277d9e3cfa73ad0c1f23f23974703c6", + "features": { + "alloc": ["serde_core/alloc"], + "arbitrary_precision": [], + "default": ["std"], + "float_roundtrip": [], + "preserve_order": ["indexmap", "std"], + "raw_value": [], + "std": ["memchr/std", "serde_core/std"], + "unbounded_depth": [] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-10-10T17:04:20Z" + } + ] + }, + { + "path": "se/rd/serde_spanned", + "header": "AwIAAABldGFnOiAiY2EyZmZlMWQ1MTMxMGU2MmU3YWQ0ODdkOGJjMTgzNWEiAA==", + "records": [ + { + "name": "serde_spanned", + "vers": "1.1.2", + "deps": [ + { + "name": "serde", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde-untagged", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.228", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "4e7523beb55eece201a2356bee0bbca0d1ab466c14c07703b2e0ee6d42cb0c2c", + "features": {}, + "features2": { + "alloc": ["serde_core?/alloc"], + "default": ["std", "serde"], + "serde": ["dep:serde_core"], + "std": ["alloc", "serde_core?/std"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-10-08T00:54:02Z", + "v": 2 + } + ] + }, + { + "path": "sh/a2/sha2", + "header": "AwIAAABldGFnOiAiZWYwMzI4MTFlOTZmMThhNWEzZjQ3NTkwNDRmM2NlZmMiAA==", + "records": [ + { + "name": "sha2", + "vers": "0.10.9", + "deps": [ + { + "name": "cfg-if", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cpufeatures", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))", + "kind": "normal" + }, + { + "name": "digest", + "req": "^0.10.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "digest", + "req": "^0.10.7", + "features": ["dev"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hex-literal", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "sha2-asm", + "req": "^0.6.1", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))", + "kind": "normal" + } + ], + "cksum": "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283", + "features": { + "asm": ["sha2-asm"], + "asm-aarch64": ["asm"], + "compress": [], + "default": ["std"], + "force-soft": [], + "force-soft-compact": [], + "loongarch64_asm": [], + "oid": ["digest/oid"], + "std": ["digest/std"] + }, + "yanked": false, + "pubtime": "2025-04-30T14:38:09Z" + } + ] + }, + { + "path": "sh/le/shlex", + "header": "AwIAAABldGFnOiAiMzU1MWFhZTM0MTRhOWUyYWY2MDhkNTU1NzkzNzg0NWEiAA==", + "records": [ + { + "name": "shlex", + "vers": "2.0.1", + "deps": [], + "cksum": "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.46.0", + "pubtime": "2026-05-17T18:56:12Z" + } + ] + }, + { + "path": "to/ml/toml", + "header": "AwIAAABldGFnOiAiNTBhM2E4MTE5NGM5MDU0NmMwOTg1Y2M0YTgxNmEyYjkiAA==", + "records": [ + { + "name": "toml", + "vers": "0.9.12+spec-1.1.0", + "deps": [ + { + "name": "anstream", + "req": "^0.6.20", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anstyle", + "req": "^1.0.11", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "foldhash", + "req": "^0.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2.11.4", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "itertools", + "req": "^0.14.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.225", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde-untagged", + "req": "^0.1.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.225", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.145", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_spanned", + "req": "^1.0.4", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "snapbox", + "req": "^0.6.21", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml-test-data", + "req": "^2.3.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml-test-harness", + "req": "^1.3.3", + "features": ["snapshot"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml_datetime", + "req": "^0.7.5", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "toml_parser", + "req": "^1.0.7", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "toml_writer", + "req": "^1.0.6", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "walkdir", + "req": "^2.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "winnow", + "req": "^0.7.13", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863", + "features": { + "unbounded": [] + }, + "features2": { + "debug": ["std", "toml_parser?/debug", "dep:anstream", "dep:anstyle"], + "default": ["std", "serde", "parse", "display"], + "display": ["dep:toml_writer"], + "fast_hash": ["preserve_order", "dep:foldhash"], + "parse": ["dep:toml_parser", "dep:winnow"], + "preserve_order": ["dep:indexmap", "std"], + "serde": ["dep:serde_core", "toml_datetime/serde", "serde_spanned/serde"], + "std": [ + "indexmap?/std", + "serde_core?/std", + "toml_parser?/std", + "toml_writer?/std", + "toml_datetime/std", + "serde_spanned/std" + ] + }, + "yanked": false, + "rust_version": "1.76", + "pubtime": "2026-02-10T18:10:32Z", + "v": 2 + } + ] + }, + { + "path": "to/ml/toml_datetime", + "header": "AwIAAABldGFnOiAiMjg4ZGUzNzkwNjcwMWU0YTA1ZjAxMTM2ZGQxOWFlZjYiAA==", + "records": [ + { + "name": "toml_datetime", + "vers": "0.7.5+spec-1.1.0", + "deps": [ + { + "name": "serde_core", + "req": "^1.0.225", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "snapbox", + "req": "^0.6.21", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347", + "features": {}, + "features2": { + "alloc": ["serde_core?/alloc"], + "default": ["std"], + "serde": ["dep:serde_core"], + "std": ["alloc", "serde_core?/std"] + }, + "yanked": false, + "rust_version": "1.76", + "pubtime": "2025-12-18T13:26:19Z", + "v": 2 + } + ] + }, + { + "path": "to/ml/toml_parser", + "header": "AwIAAABldGFnOiAiOWViOWE2MWYxN2Q2YzZkMTk1NTlmNzkxZDE0YmM0NGMiAA==", + "records": [ + { + "name": "toml_parser", + "vers": "1.1.5+spec-1.1.0", + "deps": [ + { + "name": "anstream", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anstream", + "req": "^1.0.0", + "features": ["test"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "anstyle", + "req": "^1.0.14", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "snapbox", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "winnow", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "baa693a8032d7e1cada7d0041e96126df243179ff061456783ac7f12bda4744c", + "features": { + "alloc": [], + "default": ["std"], + "simd": ["winnow/simd"], + "std": ["alloc"], + "unsafe": [] + }, + "features2": { + "debug": ["std", "dep:anstream", "dep:anstyle"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-10-09T02:46:29Z", + "v": 2 + } + ] + }, + { + "path": "to/ml/toml_writer", + "header": "AwIAAABldGFnOiAiNDk0MmU4YTk4YjUxNWY2N2ZlZWFkN2NhMzc2ZjgwZjciAA==", + "records": [ + { + "name": "toml_writer", + "vers": "1.1.3+spec-1.1.0", + "deps": [ + { + "name": "proptest", + "req": "^1.10.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "snapbox", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml_old", + "req": "^0.5.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "toml" + } + ], + "cksum": "06bdbd8cfc056b8d2e2e85f29b56a3bdbecb527cef81eb39e3e7b98af4652770", + "features": { + "alloc": [], + "default": ["std"], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-10-08T00:54:04Z" + } + ] + }, + { + "path": "ty/pe/typenum", + "header": "AwIAAABldGFnOiAiZmZmMGQ5NjAyZjc2NDVmZmZmMzBhYTMzYzRmYzhmYTIiAA==", + "records": [ + { + "name": "typenum", + "vers": "1.20.1", + "deps": [ + { + "name": "scale-info", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20", + "features": { + "const-generics": [], + "i128": [], + "scale_info": ["scale-info/derive"], + "strict": [] + }, + "yanked": false, + "rust_version": "1.41.0", + "pubtime": "2026-05-29T16:00:41Z" + } + ] + }, + { + "path": "un/ic/unicode-ident", + "header": "AwIAAABldGFnOiAiYjcxNThlNzgzOGU5ZmYwZmYyNWQ5NmM3N2VmODlmNzkiAA==", + "records": [ + { + "name": "unicode-ident", + "vers": "1.0.26", + "deps": [ + { + "name": "criterion", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "fst", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "roaring", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ucd-trie", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "unicode-xid", + "req": "^0.2.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-09-17T06:18:03Z" + } + ] + }, + { + "path": "ve/rs/version_check", + "header": "AwIAAABldGFnOiAiMTdiMWIzYzA4ZjNkMjY4OTdmYTgyODg4YzU0MDljZmEiAA==", + "records": [ + { + "name": "version_check", + "vers": "0.9.5", + "deps": [], + "cksum": "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a", + "features": {}, + "yanked": false, + "pubtime": "2024-07-25T23:38:14Z" + } + ] + }, + { + "path": "wa/si/wasip2", + "header": "AwIAAABldGFnOiAiMmE1MWY4ZTc1N2NjZGE5NTU5OTVkZWMyODg5ODQ5YzciAA==", + "records": [ + { + "name": "wasip2", + "vers": "1.0.4+wasi-0.2.12", + "deps": [ + { + "name": "alloc", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "core", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "wit-bindgen", + "req": "^0.57.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487", + "features": { + "bitflags": ["wit-bindgen/bitflags"], + "default": ["std", "bitflags"], + "rustc-dep-of-std": ["core", "alloc", "wit-bindgen/rustc-dep-of-std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.87.0", + "pubtime": "2026-06-12T17:42:43Z" + } + ] + }, + { + "path": "wi/na/winapi", + "header": "AwIAAABldGFnOiAiN2IxNTA1MzFhZDhjMjc3MDUxM2UyN2QyMDk3NjJlNzYiAA==", + "records": [ + { + "name": "winapi", + "vers": "0.3.9", + "deps": [ + { + "name": "winapi-i686-pc-windows-gnu", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": "i686-pc-windows-gnu", + "kind": "normal" + }, + { + "name": "winapi-x86_64-pc-windows-gnu", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": "x86_64-pc-windows-gnu", + "kind": "normal" + } + ], + "cksum": "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419", + "features": { + "accctrl": [], + "aclapi": [], + "activation": [], + "adhoc": [], + "appmgmt": [], + "audioclient": [], + "audiosessiontypes": [], + "avrt": [], + "basetsd": [], + "bcrypt": [], + "bits": [], + "bits10_1": [], + "bits1_5": [], + "bits2_0": [], + "bits2_5": [], + "bits3_0": [], + "bits4_0": [], + "bits5_0": [], + "bitscfg": [], + "bitsmsg": [], + "bluetoothapis": [], + "bluetoothleapis": [], + "bthdef": [], + "bthioctl": [], + "bthledef": [], + "bthsdpdef": [], + "bugcodes": [], + "cderr": [], + "cfg": [], + "cfgmgr32": [], + "cguid": [], + "combaseapi": [], + "coml2api": [], + "commapi": [], + "commctrl": [], + "commdlg": [], + "commoncontrols": [], + "consoleapi": [], + "corecrt": [], + "corsym": [], + "d2d1": [], + "d2d1_1": [], + "d2d1_2": [], + "d2d1_3": [], + "d2d1effectauthor": [], + "d2d1effects": [], + "d2d1effects_1": [], + "d2d1effects_2": [], + "d2d1svg": [], + "d2dbasetypes": [], + "d3d": [], + "d3d10": [], + "d3d10_1": [], + "d3d10_1shader": [], + "d3d10effect": [], + "d3d10misc": [], + "d3d10sdklayers": [], + "d3d10shader": [], + "d3d11": [], + "d3d11_1": [], + "d3d11_2": [], + "d3d11_3": [], + "d3d11_4": [], + "d3d11on12": [], + "d3d11sdklayers": [], + "d3d11shader": [], + "d3d11tokenizedprogramformat": [], + "d3d12": [], + "d3d12sdklayers": [], + "d3d12shader": [], + "d3d9": [], + "d3d9caps": [], + "d3d9types": [], + "d3dcommon": [], + "d3dcompiler": [], + "d3dcsx": [], + "d3dkmdt": [], + "d3dkmthk": [], + "d3dukmdt": [], + "d3dx10core": [], + "d3dx10math": [], + "d3dx10mesh": [], + "datetimeapi": [], + "davclnt": [], + "dbghelp": [], + "dbt": [], + "dcommon": [], + "dcomp": [], + "dcompanimation": [], + "dcomptypes": [], + "dde": [], + "ddraw": [], + "ddrawi": [], + "ddrawint": [], + "debug": ["impl-debug"], + "debugapi": [], + "devguid": [], + "devicetopology": [], + "devpkey": [], + "devpropdef": [], + "dinput": [], + "dinputd": [], + "dispex": [], + "dmksctl": [], + "dmusicc": [], + "docobj": [], + "documenttarget": [], + "dot1x": [], + "dpa_dsa": [], + "dpapi": [], + "dsgetdc": [], + "dsound": [], + "dsrole": [], + "dvp": [], + "dwmapi": [], + "dwrite": [], + "dwrite_1": [], + "dwrite_2": [], + "dwrite_3": [], + "dxdiag": [], + "dxfile": [], + "dxgi": [], + "dxgi1_2": [], + "dxgi1_3": [], + "dxgi1_4": [], + "dxgi1_5": [], + "dxgi1_6": [], + "dxgidebug": [], + "dxgiformat": [], + "dxgitype": [], + "dxva2api": [], + "dxvahd": [], + "eaptypes": [], + "enclaveapi": [], + "endpointvolume": [], + "errhandlingapi": [], + "everything": [], + "evntcons": [], + "evntprov": [], + "evntrace": [], + "excpt": [], + "exdisp": [], + "fibersapi": [], + "fileapi": [], + "functiondiscoverykeys_devpkey": [], + "gl-gl": [], + "guiddef": [], + "handleapi": [], + "heapapi": [], + "hidclass": [], + "hidpi": [], + "hidsdi": [], + "hidusage": [], + "highlevelmonitorconfigurationapi": [], + "hstring": [], + "http": [], + "ifdef": [], + "ifmib": [], + "imm": [], + "impl-debug": [], + "impl-default": [], + "in6addr": [], + "inaddr": [], + "inspectable": [], + "interlockedapi": [], + "intsafe": [], + "ioapiset": [], + "ipexport": [], + "iphlpapi": [], + "ipifcons": [], + "ipmib": [], + "iprtrmib": [], + "iptypes": [], + "jobapi": [], + "jobapi2": [], + "knownfolders": [], + "ks": [], + "ksmedia": [], + "ktmtypes": [], + "ktmw32": [], + "l2cmn": [], + "libloaderapi": [], + "limits": [], + "lmaccess": [], + "lmalert": [], + "lmapibuf": [], + "lmat": [], + "lmcons": [], + "lmdfs": [], + "lmerrlog": [], + "lmjoin": [], + "lmmsg": [], + "lmremutl": [], + "lmrepl": [], + "lmserver": [], + "lmshare": [], + "lmstats": [], + "lmsvc": [], + "lmuse": [], + "lmwksta": [], + "lowlevelmonitorconfigurationapi": [], + "lsalookup": [], + "memoryapi": [], + "minschannel": [], + "minwinbase": [], + "minwindef": [], + "mmdeviceapi": [], + "mmeapi": [], + "mmreg": [], + "mmsystem": [], + "mprapidef": [], + "msaatext": [], + "mscat": [], + "mschapp": [], + "mssip": [], + "mstcpip": [], + "mswsock": [], + "mswsockdef": [], + "namedpipeapi": [], + "namespaceapi": [], + "nb30": [], + "ncrypt": [], + "netioapi": [], + "nldef": [], + "ntddndis": [], + "ntddscsi": [], + "ntddser": [], + "ntdef": [], + "ntlsa": [], + "ntsecapi": [], + "ntstatus": [], + "oaidl": [], + "objbase": [], + "objidl": [], + "objidlbase": [], + "ocidl": [], + "ole2": [], + "oleauto": [], + "olectl": [], + "oleidl": [], + "opmapi": [], + "pdh": [], + "perflib": [], + "physicalmonitorenumerationapi": [], + "playsoundapi": [], + "portabledevice": [], + "portabledeviceapi": [], + "portabledevicetypes": [], + "powerbase": [], + "powersetting": [], + "powrprof": [], + "processenv": [], + "processsnapshot": [], + "processthreadsapi": [], + "processtopologyapi": [], + "profileapi": [], + "propidl": [], + "propkey": [], + "propkeydef": [], + "propsys": [], + "prsht": [], + "psapi": [], + "qos": [], + "realtimeapiset": [], + "reason": [], + "restartmanager": [], + "restrictederrorinfo": [], + "rmxfguid": [], + "roapi": [], + "robuffer": [], + "roerrorapi": [], + "rpc": [], + "rpcdce": [], + "rpcndr": [], + "rtinfo": [], + "sapi": [], + "sapi51": [], + "sapi53": [], + "sapiddk": [], + "sapiddk51": [], + "schannel": [], + "sddl": [], + "securityappcontainer": [], + "securitybaseapi": [], + "servprov": [], + "setupapi": [], + "shellapi": [], + "shellscalingapi": [], + "shlobj": [], + "shobjidl": [], + "shobjidl_core": [], + "shtypes": [], + "softpub": [], + "spapidef": [], + "spellcheck": [], + "sporder": [], + "sql": [], + "sqlext": [], + "sqltypes": [], + "sqlucode": [], + "sspi": [], + "std": [], + "stralign": [], + "stringapiset": [], + "strmif": [], + "subauth": [], + "synchapi": [], + "sysinfoapi": [], + "systemtopologyapi": [], + "taskschd": [], + "tcpestats": [], + "tcpmib": [], + "textstor": [], + "threadpoolapiset": [], + "threadpoollegacyapiset": [], + "timeapi": [], + "timezoneapi": [], + "tlhelp32": [], + "transportsettingcommon": [], + "tvout": [], + "udpmib": [], + "unknwnbase": [], + "urlhist": [], + "urlmon": [], + "usb": [], + "usbioctl": [], + "usbiodef": [], + "usbscan": [], + "usbspec": [], + "userenv": [], + "usp10": [], + "utilapiset": [], + "uxtheme": [], + "vadefs": [], + "vcruntime": [], + "vsbackup": [], + "vss": [], + "vsserror": [], + "vswriter": [], + "wbemads": [], + "wbemcli": [], + "wbemdisp": [], + "wbemprov": [], + "wbemtran": [], + "wct": [], + "werapi": [], + "winbase": [], + "wincodec": [], + "wincodecsdk": [], + "wincon": [], + "wincontypes": [], + "wincred": [], + "wincrypt": [], + "windef": [], + "windot11": [], + "windowsceip": [], + "windowsx": [], + "winefs": [], + "winerror": [], + "winevt": [], + "wingdi": [], + "winhttp": [], + "wininet": [], + "winineti": [], + "winioctl": [], + "winnetwk": [], + "winnls": [], + "winnt": [], + "winreg": [], + "winsafer": [], + "winscard": [], + "winsmcrd": [], + "winsock2": [], + "winspool": [], + "winstring": [], + "winsvc": [], + "wintrust": [], + "winusb": [], + "winusbio": [], + "winuser": [], + "winver": [], + "wlanapi": [], + "wlanihv": [], + "wlanihvtypes": [], + "wlantypes": [], + "wlclient": [], + "wmistr": [], + "wnnc": [], + "wow64apiset": [], + "wpdmtpextensions": [], + "ws2bth": [], + "ws2def": [], + "ws2ipdef": [], + "ws2spi": [], + "ws2tcpip": [], + "wtsapi32": [], + "wtypes": [], + "wtypesbase": [], + "xinput": [] + }, + "yanked": false, + "pubtime": "2020-06-26T11:34:33Z" + } + ] + }, + { + "path": "wi/na/winapi-i686-pc-windows-gnu", + "header": "AwIAAABldGFnOiAiMDU5MmJiOTZmNGY2MGI2OWY4ZmVjY2IzZWQ1NzE4NTIiAA==", + "records": [ + { + "name": "winapi-i686-pc-windows-gnu", + "vers": "0.4.0", + "deps": [], + "cksum": "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6", + "features": {}, + "yanked": false, + "pubtime": "2018-01-18T00:55:38Z" + } + ] + }, + { + "path": "wi/na/winapi-x86_64-pc-windows-gnu", + "header": "AwIAAABldGFnOiAiZDE5NmU3ZTU1OTUxZWZjYWM4NDIyMjJlMzFjOGM0ODYiAA==", + "records": [ + { + "name": "winapi-x86_64-pc-windows-gnu", + "vers": "0.4.0", + "deps": [], + "cksum": "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f", + "features": {}, + "yanked": false, + "pubtime": "2018-01-18T00:55:12Z" + } + ] + }, + { + "path": "wi/nd/windows-link", + "header": "AwIAAABldGFnOiAiOGExMzljNWFiOGJmMzhhNTUxM2I0OTYxZGU4MmYwY2MiAA==", + "records": [ + { + "name": "windows-link", + "vers": "0.2.1", + "deps": [], + "cksum": "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2025-10-06T17:35:08Z" + } + ] + }, + { + "path": "wi/nd/windows-sys", + "header": "AwIAAABldGFnOiAiZjZmOGFlYTIyYzM4NmY3ZTI2YWUyNWRmNjljYWNkMzYiAA==", + "records": [ + { + "name": "windows-sys", + "vers": "0.61.2", + "deps": [ + { + "name": "windows-link", + "req": "^0.2.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc", + "features": { + "Wdk": ["Win32_Foundation"], + "Wdk_Devices": ["Wdk"], + "Wdk_Devices_Bluetooth": ["Wdk_Devices"], + "Wdk_Devices_HumanInterfaceDevice": ["Wdk_Devices"], + "Wdk_Foundation": ["Wdk"], + "Wdk_Graphics": ["Wdk"], + "Wdk_Graphics_Direct3D": ["Wdk_Graphics"], + "Wdk_NetworkManagement": ["Wdk"], + "Wdk_NetworkManagement_Ndis": ["Wdk_NetworkManagement"], + "Wdk_NetworkManagement_WindowsFilteringPlatform": ["Wdk_NetworkManagement"], + "Wdk_Storage": ["Wdk"], + "Wdk_Storage_FileSystem": ["Wdk_Storage"], + "Wdk_Storage_FileSystem_Minifilters": ["Wdk_Storage_FileSystem"], + "Wdk_System": ["Wdk"], + "Wdk_System_IO": ["Wdk_System"], + "Wdk_System_Memory": ["Wdk_System"], + "Wdk_System_OfflineRegistry": ["Wdk_System"], + "Wdk_System_Registry": ["Wdk_System"], + "Wdk_System_SystemInformation": ["Wdk_System"], + "Wdk_System_SystemServices": ["Wdk_System"], + "Wdk_System_Threading": ["Wdk_System"], + "Win32": ["Win32_Foundation"], + "Win32_Data": ["Win32"], + "Win32_Data_HtmlHelp": ["Win32_Data"], + "Win32_Data_RightsManagement": ["Win32_Data"], + "Win32_Devices": ["Win32"], + "Win32_Devices_AllJoyn": ["Win32_Devices"], + "Win32_Devices_Beep": ["Win32_Devices"], + "Win32_Devices_BiometricFramework": ["Win32_Devices"], + "Win32_Devices_Bluetooth": ["Win32_Devices"], + "Win32_Devices_Cdrom": ["Win32_Devices"], + "Win32_Devices_Communication": ["Win32_Devices"], + "Win32_Devices_DeviceAndDriverInstallation": ["Win32_Devices"], + "Win32_Devices_DeviceQuery": ["Win32_Devices"], + "Win32_Devices_Display": ["Win32_Devices"], + "Win32_Devices_Dvd": ["Win32_Devices"], + "Win32_Devices_Enumeration": ["Win32_Devices"], + "Win32_Devices_Enumeration_Pnp": ["Win32_Devices_Enumeration"], + "Win32_Devices_Fax": ["Win32_Devices"], + "Win32_Devices_HumanInterfaceDevice": ["Win32_Devices"], + "Win32_Devices_Nfc": ["Win32_Devices"], + "Win32_Devices_Nfp": ["Win32_Devices"], + "Win32_Devices_PortableDevices": ["Win32_Devices"], + "Win32_Devices_Properties": ["Win32_Devices"], + "Win32_Devices_Pwm": ["Win32_Devices"], + "Win32_Devices_Sensors": ["Win32_Devices"], + "Win32_Devices_SerialCommunication": ["Win32_Devices"], + "Win32_Devices_Tapi": ["Win32_Devices"], + "Win32_Devices_Usb": ["Win32_Devices"], + "Win32_Devices_WebServicesOnDevices": ["Win32_Devices"], + "Win32_Foundation": ["Win32"], + "Win32_Gaming": ["Win32"], + "Win32_Globalization": ["Win32"], + "Win32_Graphics": ["Win32"], + "Win32_Graphics_Dwm": ["Win32_Graphics"], + "Win32_Graphics_Gdi": ["Win32_Graphics"], + "Win32_Graphics_GdiPlus": ["Win32_Graphics"], + "Win32_Graphics_Hlsl": ["Win32_Graphics"], + "Win32_Graphics_OpenGL": ["Win32_Graphics"], + "Win32_Graphics_Printing": ["Win32_Graphics"], + "Win32_Graphics_Printing_PrintTicket": ["Win32_Graphics_Printing"], + "Win32_Management": ["Win32"], + "Win32_Management_MobileDeviceManagementRegistration": ["Win32_Management"], + "Win32_Media": ["Win32"], + "Win32_Media_Audio": ["Win32_Media"], + "Win32_Media_DxMediaObjects": ["Win32_Media"], + "Win32_Media_KernelStreaming": ["Win32_Media"], + "Win32_Media_Multimedia": ["Win32_Media"], + "Win32_Media_Streaming": ["Win32_Media"], + "Win32_Media_WindowsMediaFormat": ["Win32_Media"], + "Win32_NetworkManagement": ["Win32"], + "Win32_NetworkManagement_Dhcp": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Dns": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_InternetConnectionWizard": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_IpHelper": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Multicast": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Ndis": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetBios": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetManagement": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetShell": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetworkDiagnosticsFramework": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_P2P": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_QoS": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Rras": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Snmp": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WNet": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WebDav": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WiFi": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsConnectionManager": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsFilteringPlatform": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsFirewall": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsNetworkVirtualization": ["Win32_NetworkManagement"], + "Win32_Networking": ["Win32"], + "Win32_Networking_ActiveDirectory": ["Win32_Networking"], + "Win32_Networking_Clustering": ["Win32_Networking"], + "Win32_Networking_HttpServer": ["Win32_Networking"], + "Win32_Networking_Ldap": ["Win32_Networking"], + "Win32_Networking_WebSocket": ["Win32_Networking"], + "Win32_Networking_WinHttp": ["Win32_Networking"], + "Win32_Networking_WinInet": ["Win32_Networking"], + "Win32_Networking_WinSock": ["Win32_Networking"], + "Win32_Networking_WindowsWebServices": ["Win32_Networking"], + "Win32_Security": ["Win32"], + "Win32_Security_AppLocker": ["Win32_Security"], + "Win32_Security_Authentication": ["Win32_Security"], + "Win32_Security_Authentication_Identity": ["Win32_Security_Authentication"], + "Win32_Security_Authorization": ["Win32_Security"], + "Win32_Security_Credentials": ["Win32_Security"], + "Win32_Security_Cryptography": ["Win32_Security"], + "Win32_Security_Cryptography_Catalog": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_Certificates": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_Sip": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_UI": ["Win32_Security_Cryptography"], + "Win32_Security_DiagnosticDataQuery": ["Win32_Security"], + "Win32_Security_DirectoryServices": ["Win32_Security"], + "Win32_Security_EnterpriseData": ["Win32_Security"], + "Win32_Security_ExtensibleAuthenticationProtocol": ["Win32_Security"], + "Win32_Security_Isolation": ["Win32_Security"], + "Win32_Security_LicenseProtection": ["Win32_Security"], + "Win32_Security_NetworkAccessProtection": ["Win32_Security"], + "Win32_Security_WinTrust": ["Win32_Security"], + "Win32_Security_WinWlx": ["Win32_Security"], + "Win32_Storage": ["Win32"], + "Win32_Storage_Cabinets": ["Win32_Storage"], + "Win32_Storage_CloudFilters": ["Win32_Storage"], + "Win32_Storage_Compression": ["Win32_Storage"], + "Win32_Storage_DistributedFileSystem": ["Win32_Storage"], + "Win32_Storage_FileHistory": ["Win32_Storage"], + "Win32_Storage_FileSystem": ["Win32_Storage"], + "Win32_Storage_Imapi": ["Win32_Storage"], + "Win32_Storage_IndexServer": ["Win32_Storage"], + "Win32_Storage_InstallableFileSystems": ["Win32_Storage"], + "Win32_Storage_IscsiDisc": ["Win32_Storage"], + "Win32_Storage_Jet": ["Win32_Storage"], + "Win32_Storage_Nvme": ["Win32_Storage"], + "Win32_Storage_OfflineFiles": ["Win32_Storage"], + "Win32_Storage_OperationRecorder": ["Win32_Storage"], + "Win32_Storage_Packaging": ["Win32_Storage"], + "Win32_Storage_Packaging_Appx": ["Win32_Storage_Packaging"], + "Win32_Storage_ProjectedFileSystem": ["Win32_Storage"], + "Win32_Storage_StructuredStorage": ["Win32_Storage"], + "Win32_Storage_Vhd": ["Win32_Storage"], + "Win32_Storage_Xps": ["Win32_Storage"], + "Win32_System": ["Win32"], + "Win32_System_AddressBook": ["Win32_System"], + "Win32_System_Antimalware": ["Win32_System"], + "Win32_System_ApplicationInstallationAndServicing": ["Win32_System"], + "Win32_System_ApplicationVerifier": ["Win32_System"], + "Win32_System_ClrHosting": ["Win32_System"], + "Win32_System_Com": ["Win32_System"], + "Win32_System_Com_Marshal": ["Win32_System_Com"], + "Win32_System_Com_StructuredStorage": ["Win32_System_Com"], + "Win32_System_Com_Urlmon": ["Win32_System_Com"], + "Win32_System_ComponentServices": ["Win32_System"], + "Win32_System_Console": ["Win32_System"], + "Win32_System_CorrelationVector": ["Win32_System"], + "Win32_System_DataExchange": ["Win32_System"], + "Win32_System_DeploymentServices": ["Win32_System"], + "Win32_System_DeveloperLicensing": ["Win32_System"], + "Win32_System_Diagnostics": ["Win32_System"], + "Win32_System_Diagnostics_Ceip": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_Debug": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_Debug_Extensions": ["Win32_System_Diagnostics_Debug"], + "Win32_System_Diagnostics_Etw": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_ProcessSnapshotting": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_ToolHelp": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_TraceLogging": ["Win32_System_Diagnostics"], + "Win32_System_DistributedTransactionCoordinator": ["Win32_System"], + "Win32_System_Environment": ["Win32_System"], + "Win32_System_ErrorReporting": ["Win32_System"], + "Win32_System_EventCollector": ["Win32_System"], + "Win32_System_EventLog": ["Win32_System"], + "Win32_System_EventNotificationService": ["Win32_System"], + "Win32_System_GroupPolicy": ["Win32_System"], + "Win32_System_HostCompute": ["Win32_System"], + "Win32_System_HostComputeNetwork": ["Win32_System"], + "Win32_System_HostComputeSystem": ["Win32_System"], + "Win32_System_Hypervisor": ["Win32_System"], + "Win32_System_IO": ["Win32_System"], + "Win32_System_Iis": ["Win32_System"], + "Win32_System_Ioctl": ["Win32_System"], + "Win32_System_JobObjects": ["Win32_System"], + "Win32_System_Js": ["Win32_System"], + "Win32_System_Kernel": ["Win32_System"], + "Win32_System_LibraryLoader": ["Win32_System"], + "Win32_System_Mailslots": ["Win32_System"], + "Win32_System_Mapi": ["Win32_System"], + "Win32_System_Memory": ["Win32_System"], + "Win32_System_Memory_NonVolatile": ["Win32_System_Memory"], + "Win32_System_MessageQueuing": ["Win32_System"], + "Win32_System_MixedReality": ["Win32_System"], + "Win32_System_Ole": ["Win32_System"], + "Win32_System_PasswordManagement": ["Win32_System"], + "Win32_System_Performance": ["Win32_System"], + "Win32_System_Performance_HardwareCounterProfiling": ["Win32_System_Performance"], + "Win32_System_Pipes": ["Win32_System"], + "Win32_System_Power": ["Win32_System"], + "Win32_System_ProcessStatus": ["Win32_System"], + "Win32_System_Recovery": ["Win32_System"], + "Win32_System_Registry": ["Win32_System"], + "Win32_System_RemoteDesktop": ["Win32_System"], + "Win32_System_RemoteManagement": ["Win32_System"], + "Win32_System_RestartManager": ["Win32_System"], + "Win32_System_Restore": ["Win32_System"], + "Win32_System_Rpc": ["Win32_System"], + "Win32_System_Search": ["Win32_System"], + "Win32_System_Search_Common": ["Win32_System_Search"], + "Win32_System_SecurityCenter": ["Win32_System"], + "Win32_System_Services": ["Win32_System"], + "Win32_System_SetupAndMigration": ["Win32_System"], + "Win32_System_Shutdown": ["Win32_System"], + "Win32_System_StationsAndDesktops": ["Win32_System"], + "Win32_System_SubsystemForLinux": ["Win32_System"], + "Win32_System_SystemInformation": ["Win32_System"], + "Win32_System_SystemServices": ["Win32_System"], + "Win32_System_Threading": ["Win32_System"], + "Win32_System_Time": ["Win32_System"], + "Win32_System_TpmBaseServices": ["Win32_System"], + "Win32_System_UserAccessLogging": ["Win32_System"], + "Win32_System_Variant": ["Win32_System"], + "Win32_System_VirtualDosMachines": ["Win32_System"], + "Win32_System_WindowsProgramming": ["Win32_System"], + "Win32_System_Wmi": ["Win32_System"], + "Win32_UI": ["Win32"], + "Win32_UI_Accessibility": ["Win32_UI"], + "Win32_UI_ColorSystem": ["Win32_UI"], + "Win32_UI_Controls": ["Win32_UI"], + "Win32_UI_Controls_Dialogs": ["Win32_UI_Controls"], + "Win32_UI_HiDpi": ["Win32_UI"], + "Win32_UI_Input": ["Win32_UI"], + "Win32_UI_Input_Ime": ["Win32_UI_Input"], + "Win32_UI_Input_KeyboardAndMouse": ["Win32_UI_Input"], + "Win32_UI_Input_Pointer": ["Win32_UI_Input"], + "Win32_UI_Input_Touch": ["Win32_UI_Input"], + "Win32_UI_Input_XboxController": ["Win32_UI_Input"], + "Win32_UI_InteractionContext": ["Win32_UI"], + "Win32_UI_Magnification": ["Win32_UI"], + "Win32_UI_Shell": ["Win32_UI"], + "Win32_UI_Shell_Common": ["Win32_UI_Shell"], + "Win32_UI_Shell_PropertiesSystem": ["Win32_UI_Shell"], + "Win32_UI_TabletPC": ["Win32_UI"], + "Win32_UI_TextServices": ["Win32_UI"], + "Win32_UI_WindowsAndMessaging": ["Win32_UI"], + "Win32_Web": ["Win32"], + "Win32_Web_InternetExplorer": ["Win32_Web"], + "default": [], + "docs": [] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2025-10-06T19:18:30Z" + } + ] + }, + { + "path": "wi/nn/winnow", + "header": "AwIAAABldGFnOiAiM2JlZmY0ZTJiOWI1OGQwNjUyYmFhMGY3ZGVlY2VmYTUiAA==", + "records": [ + { + "name": "winnow", + "vers": "0.7.15", + "deps": [ + { + "name": "annotate-snippets", + "req": "^0.11.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "anstream", + "req": "^0.6.15", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anstyle", + "req": "^1.0.8", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anyhow", + "req": "^1.0.100", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "automod", + "req": "^1.0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "circular", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.5.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "is_terminal_polyfill", + "req": "^1.48.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "lexopt", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "memchr", + "req": "^2.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "proptest", + "req": "^1.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustc-hash", + "req": "^2.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "snapbox", + "req": "^0.6.21", + "features": ["examples"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "term-transcript", + "req": "^0.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "terminal_size", + "req": "^0.4.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945", + "features": { + "alloc": [], + "unstable-recover": [] + }, + "features2": { + "debug": [ + "std", + "dep:anstream", + "dep:anstyle", + "dep:is_terminal_polyfill", + "dep:terminal_size" + ], + "default": ["std"], + "simd": ["dep:memchr"], + "std": ["alloc", "memchr?/std"], + "unstable-doc": ["alloc", "std", "simd", "unstable-recover"] + }, + "yanked": false, + "rust_version": "1.65.0", + "pubtime": "2026-03-05T19:00:42Z", + "v": 2 + }, + { + "name": "winnow", + "vers": "1.0.4", + "deps": [ + { + "name": "annotate-snippets", + "req": "^0.11.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "anstream", + "req": "^0.6.15", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anstyle", + "req": "^1.0.8", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anyhow", + "req": "^1.0.100", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "automod", + "req": "^1.0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "circular", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.5.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "is_terminal_polyfill", + "req": "^1.48.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "lexopt", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "memchr", + "req": "^2.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "proptest", + "req": "^1.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustc-hash", + "req": "^2.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "snapbox", + "req": "^0.6.21", + "features": ["examples"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "term-transcript", + "req": "^0.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "terminal_size", + "req": "^0.4.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81", + "features": { + "alloc": [], + "ascii": ["parser"], + "binary": ["parser"], + "parser": [], + "unstable-recover": ["parser"] + }, + "features2": { + "debug": [ + "std", + "dep:anstream", + "dep:anstyle", + "dep:is_terminal_polyfill", + "dep:terminal_size" + ], + "default": ["std", "ascii", "binary"], + "simd": ["dep:memchr"], + "std": ["alloc", "memchr?/std"], + "unstable-doc": ["alloc", "std", "ascii", "binary", "simd", "unstable-recover"] + }, + "yanked": false, + "rust_version": "1.65.0", + "pubtime": "2026-07-13T14:31:41Z", + "v": 2 + } + ] + }, + { + "path": "wi/t-/wit-bindgen", + "header": "AwIAAABldGFnOiAiNGZiMDE4ZDEzZjBlMzY3N2Y1NGVmZDE3OTQ1OGQzNGEiAA==", + "records": [ + { + "name": "wit-bindgen", + "vers": "0.57.1", + "deps": [ + { + "name": "alloc", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "bitflags", + "req": "^2.11.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "core", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "futures", + "req": "^0.3.30", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wit-bindgen-rust-macro", + "req": "^0.57.1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e", + "features": { + "async": [], + "inter-task-wakeup": ["async"], + "realloc": [], + "std": [] + }, + "features2": { + "async-spawn": ["async", "dep:futures", "std"], + "bitflags": ["dep:bitflags"], + "default": ["macros", "realloc", "async", "std", "bitflags", "macro-string"], + "futures-stream": ["async", "dep:futures"], + "macro-string": ["wit-bindgen-rust-macro?/macro-string"], + "macros": ["dep:wit-bindgen-rust-macro"], + "rustc-dep-of-std": ["dep:core", "dep:alloc"] + }, + "yanked": false, + "rust_version": "1.85.0", + "pubtime": "2026-04-17T17:49:55Z", + "v": 2 + } + ] + }, + { + "path": "xa/tt/xattr", + "header": "AwIAAABldGFnOiAiZDFiOTMzNmU1Y2U1YTA4ZWMyOWYzOThkMTVkZjFkNzkiAA==", + "records": [ + { + "name": "xattr", + "vers": "1.6.1", + "deps": [ + { + "name": "libc", + "req": "^0.2.150", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(target_os = \"freebsd\", target_os = \"netbsd\"))", + "kind": "normal" + }, + { + "name": "rustix", + "req": "^1.0.0", + "features": ["fs", "std"], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"android\", target_os = \"linux\", target_os = \"macos\", target_os = \"hurd\"))", + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156", + "features": { + "default": ["unsupported"], + "unsupported": [] + }, + "yanked": false, + "pubtime": "2025-09-21T02:52:23Z" + } + ] + }, + { + "path": "zm/ij/zmij", + "header": "AwIAAABldGFnOiAiMGY1ODQ4NzI1ZWIwZmQyODY3OGY0YTdjNWM5M2M4MzMiAA==", + "records": [ + { + "name": "zmij", + "vers": "1.0.23", + "deps": [ + { + "name": "criterion", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "no-panic", + "req": "^0.1.36", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "num-bigint", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "num-integer", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "num_cpus", + "req": "^1.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "opt-level", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ryu", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-13T12:58:53Z" + } + ] + }, + { + "path": "zs/td/zstd", + "header": "AwIAAABldGFnOiAiZWU4ZDc2NjU1YjRlMjQxNDAzZWMyN2FlNzMxMTVkMjgiAA==", + "records": [ + { + "name": "zstd", + "vers": "0.13.3", + "deps": [ + { + "name": "clap", + "req": "^4.0", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "humansize", + "req": "^2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "partial-io", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "walkdir", + "req": "^2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "zstd-safe", + "req": "^7.1.0", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a", + "features": { + "arrays": ["zstd-safe/arrays"], + "bindgen": ["zstd-safe/bindgen"], + "debug": ["zstd-safe/debug"], + "default": ["legacy", "arrays", "zdict_builder"], + "doc-cfg": [], + "experimental": ["zstd-safe/experimental"], + "fat-lto": ["zstd-safe/fat-lto"], + "legacy": ["zstd-safe/legacy"], + "no_asm": ["zstd-safe/no_asm"], + "pkg-config": ["zstd-safe/pkg-config"], + "thin": ["zstd-safe/thin"], + "thin-lto": ["zstd-safe/thin-lto"], + "wasm": [], + "zdict_builder": ["zstd-safe/zdict_builder"], + "zstdmt": ["zstd-safe/zstdmt"] + }, + "yanked": false, + "rust_version": "1.64", + "pubtime": "2025-02-20T21:43:13Z" + } + ] + }, + { + "path": "zs/td/zstd-safe", + "header": "AwIAAABldGFnOiAiMmFiZGFlNDdjZmI4ODIxYTkwZTg4NWNmZjk0OWZjMTMiAA==", + "records": [ + { + "name": "zstd-safe", + "vers": "7.3.0", + "deps": [ + { + "name": "zstd-sys", + "req": "^2.0.15", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "64d80649ab6db9d9f6f9c80a40becd948eda4714a0a5ac8c4d157a32231c7882", + "features": { + "arrays": [], + "bindgen": ["zstd-sys/bindgen"], + "debug": ["zstd-sys/debug"], + "default": ["legacy", "arrays", "zdict_builder"], + "doc-cfg": [], + "experimental": ["zstd-sys/experimental"], + "fat-lto": ["zstd-sys/fat-lto"], + "legacy": ["zstd-sys/legacy"], + "no_asm": ["zstd-sys/no_asm"], + "pkg-config": ["zstd-sys/pkg-config"], + "seekable": ["zstd-sys/seekable"], + "std": ["zstd-sys/std"], + "thin": ["zstd-sys/thin"], + "thin-lto": ["zstd-sys/thin-lto"], + "zdict_builder": ["zstd-sys/zdict_builder"], + "zstdmt": ["zstd-sys/zstdmt"] + }, + "yanked": false, + "rust_version": "1.64", + "pubtime": "2026-09-04T14:31:21Z" + } + ] + }, + { + "path": "zs/td/zstd-sys", + "header": "AwIAAABldGFnOiAiMTg5MDU1YTAwMGI5YjQ3YzRiYjEwMjEwYTk3NWIyMDUiAA==", + "records": [ + { + "name": "zstd-sys", + "vers": "2.1.1+zstd.1.5.7", + "deps": [ + { + "name": "bindgen", + "req": "^0.73.2", + "features": ["runtime"], + "optional": true, + "default_features": false, + "target": null, + "kind": "build" + }, + { + "name": "cc", + "req": "^1.0.45", + "features": ["parallel"], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "cmake", + "req": "^0.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "pkg-config", + "req": "^0.3.28", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "aeec9eaf2dffbbd09201e23bd0ffcbaa33bb8e9266a10734fd7ed90a85eca078", + "features": { + "debug": [], + "default": ["legacy", "zdict_builder"], + "experimental": [], + "fat-lto": [], + "legacy": [], + "no_asm": [], + "no_wasm_shim": [], + "non-cargo": [], + "pkg-config": [], + "seekable": [], + "std": [], + "thin": [], + "thin-lto": [], + "vendored": [], + "zdict_builder": [], + "zstdmt": [] + }, + "features2": { + "cmake": ["dep:cmake"] + }, + "yanked": false, + "links": "zstd", + "rust_version": "1.64", + "pubtime": "2026-10-09T14:57:47Z", + "v": 2 + } + ] + } + ] +} diff --git a/build_defs/languages/installed/repositories.bzl b/build_defs/languages/installed/repositories.bzl new file mode 100644 index 000000000..1c9ffc0e0 --- /dev/null +++ b/build_defs/languages/installed/repositories.bzl @@ -0,0 +1,44 @@ +"""Immutable genuine Cargo resolution inputs for the installed-consumer test.""" + +def _installed_cargo_repository_impl(ctx): + for source in [ctx.attr.lock, ctx.attr.index, ctx.attr.converter]: + ctx.read(source) + ctx.file(".anchor", "") + result = ctx.execute([ + str(ctx.path(ctx.attr.bun)), + str(ctx.path(ctx.attr.converter)), + str(ctx.path(ctx.attr.lock)), + str(ctx.path(ctx.attr.index)), + str(ctx.path(".")), + ], environment = {}, quiet = True) + if result.return_code: + fail("installed Cargo registry snapshot is invalid: " + result.stderr) + archives = json.decode(ctx.read("archives.json")) + for start in range(0, len(archives), 8): + pending = [] + for archive in archives[start:start + 8]: + name = archive["name"] + version = archive["version"] + pending.append(ctx.download( + url = "https://static.crates.io/crates/%s/%s-%s.crate" % (name, name, version), + output = "registry/cache/index.crates.io-1949cf8c6b5b557f/%s-%s.crate" % (name, version), + sha256 = archive["sha256"], + canonical_id = "%s@%s:%s" % (name, version, archive["sha256"]), + block = False, + )) + for token in pending: + token.wait() + ctx.file("BUILD.bazel", """package(default_visibility = ["//visibility:public"]) +filegroup(name = "cargo_home", srcs = glob(["registry/**"])) +exports_files(["archives.json"]) +""") + +installed_cargo_repository = repository_rule( + implementation = _installed_cargo_repository_impl, + attrs = { + "bun": attr.label(mandatory = True, allow_single_file = True), + "lock": attr.label(default = "//build_defs/languages/installed:fixture/Cargo.lock", allow_single_file = True), + "index": attr.label(default = "//build_defs/languages/installed:fixture/registry-index.json", allow_single_file = True), + "converter": attr.label(default = "//build_defs/languages/installed:context.mts", allow_single_file = True), + }, +) diff --git a/build_defs/languages/installed/source-compile.bzl b/build_defs/languages/installed/source-compile.bzl new file mode 100644 index 000000000..cf101adbb --- /dev/null +++ b/build_defs/languages/installed/source-compile.bzl @@ -0,0 +1,179 @@ +"""Compile final Cargo source envelopes offline; no runtime/admission claim.""" + +load("@rules_cc//cc:find_cc_toolchain.bzl", "use_cc_toolchain") +load("@oliphaunt_metadata//:metadata.bzl", "COMPLETED_SUPPLIER_ARTIFACTS", "PREPARED_NATIVE_SELECTED_PRODUCTS", "PRODUCTS", "PUBLICATION_CARRIERS") +load("@wasix_tool_metadata//:targets.bzl", "WASIX_AOT_TARGETS") +load("//build_defs/languages:source.bzl", "CargoSourceInfo") +load(":defs.bzl", "cargo_payload_inputs", "cargo_payload_sources", "cargo_source_owners") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/languages:cargo-toolchain.bzl", "cargo_test_toolchain") +load("//build_defs/release:shipping.bzl", "ShippingExportInfo", "ShippingInfo") + +_RUST = "@rules_rust//rust:toolchain_type" + +def _runfile(ctx, file): + return file.short_path[3:] if file.short_path.startswith("../") else ctx.workspace_name + "/" + file.short_path + +def _runtime_payload_inputs(ctx): + if not ctx.attr.payload_export: + return struct(rows = [], files = []) + canonical = {row["name"]: row for row in PUBLICATION_CARRIERS if row["product"] == "liboliphaunt-wasix" and row["ecosystem"] == "cargo"} + rows = [] + files = [] + seen = {} + for target in ctx.attr.payload_export[ShippingExportInfo].packages: + info = target[ShippingInfo] + carrier = canonical.get(info.name) + if info.configuration != "portable" and info.configuration not in WASIX_AOT_TARGETS: + fail("current WASIX payload has no canonical configuration: " + info.configuration) + configuration = WASIX_AOT_TARGETS.get(info.configuration, info.configuration) + if carrier == None or info.name in seen or info.product != carrier["product"] or info.ecosystem != carrier["ecosystem"] or info.version != PRODUCTS[info.product]["version"] or info.version != carrier["version"] or info.role != carrier["role"] or configuration != carrier["target"]: + fail("current WASIX payload differs from its canonical configured carrier: " + info.name) + actual = info.files.to_list() + defaults = target[DefaultInfo].files.to_list() + if len(actual) != 1 or actual != defaults or actual[0].is_directory or actual[0].basename != info.name + "-" + info.version + ".crate": + fail("current WASIX payload needs its one original ShippingInfo/DefaultInfo crate File") + seen[info.name] = True + rows.append({"product": info.product, "version": info.version, "artifact": "cargo:" + info.name, "configuration": info.configuration, "file": {"path": _runfile(ctx, actual[0])}}) + files.append(actual[0]) + if sorted(seen.keys()) != sorted(canonical.keys()): + fail("current WASIX payload export differs from the complete canonical Cargo carrier set") + return struct(rows = rows, files = files) + +def _source_compile_tools(ctx): + rust = ctx.toolchains[_RUST] + if not rust.cargo: + fail("installed source compilation needs the declared Cargo toolchain") + cc = cargo_test_toolchain(ctx) + return struct( + specification = { + "cargo": _runfile(ctx, rust.cargo), + "rustc": _runfile(ctx, rust.rustc), + "rustdoc": _runfile(ctx, rust.rust_doc), + "compiler": _runfile(ctx, cc.configuration), + }, + files = [cc.configuration] + rust.all_files.to_list() + cc.files, + ) + +def _source_compile_impl(ctx): + tools = _source_compile_tools(ctx) + archives = [ctx.file.archive] + ctx.files.dependencies + source_owners = json.decode(ctx.attr.source_identities) + payloads = cargo_payload_inputs(ctx, source_owners) + runtime_payloads = _runtime_payload_inputs(ctx) + payload_pool = dict(payloads.specification, current = payloads.specification["current"] + runtime_payloads.rows) + sources = {} + source_files = [] + for target in [ctx.attr.archive] + ctx.attr.dependencies: + source = target[CargoSourceInfo] + sources[_runfile(ctx, source.archive)] = {"manifest": _runfile(ctx, source.manifest), "workspace": _runfile(ctx, source.workspace_manifest)} + source_files += [source.manifest, source.workspace_manifest] + held = [] + held_files = [] + for target, metadata in ctx.attr.held_sources.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1 or files[0].is_directory: + fail("completed source dependency needs one actual archive File") + facts = json.decode(metadata) + facts["file"] = _runfile(ctx, files[0]) + held.append(facts) + held_files.append(files[0]) + specification = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(specification, json.encode(dict({ + "archives": [_runfile(ctx, file) for file in archives], + "sources": sources, + "minimum": ctx.attr.minimum, + "held": held, + "selectedProducts": PREPARED_NATIVE_SELECTED_PRODUCTS, + "sourceOwners": source_owners, + "payloadPool": payload_pool, + "cargoHome": {_runfile(ctx, file): file.short_path.split("/registry/")[-1] for file in ctx.files.cargo_home}, + "lock": _runfile(ctx, ctx.file.lock), + "index": _runfile(ctx, ctx.file.index), + "flags": ctx.attr.cargo_args, + }, **tools.specification))) + files = [specification, ctx.file.lock, ctx.file.index, ctx.file._runner] + archives + source_files + held_files + payloads.files + runtime_payloads.files + ctx.files.cargo_home + ctx.files._helpers + tools.files + return bun_test_entrypoint(ctx, runner = ctx.file._runner, arguments = [specification], files = files, + source_files = [ctx.file._runner] + ctx.files._helpers, runfiles_argument = True) + +_source_compile_test = rule( + implementation = _source_compile_impl, + test = True, + fragments = ["cpp"], + toolchains = [_RUST] + BUN_SOURCE_TOOLCHAINS + use_cc_toolchain(), + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "archive": attr.label(mandatory = True, allow_single_file = True, providers = [CargoSourceInfo]), + "dependencies": attr.label_list(allow_files = True, providers = [CargoSourceInfo]), + "minimum": attr.bool(), + "held_sources": attr.label_keyed_string_dict(allow_files = True), + "source_identities": attr.string(default = "{}"), + "payload_completed": attr.label_keyed_string_dict(allow_files = True), + "payload_current": attr.label_keyed_string_dict(allow_files = True), + "payload_export": attr.label(providers = [ShippingExportInfo]), + "cargo_home": attr.label(mandatory = True), + "lock": attr.label(mandatory = True, allow_single_file = True), + "index": attr.label(mandatory = True, allow_single_file = True), + "cargo_args": attr.string_list(), + "_runner": attr.label(default = "//build_defs/languages/installed:source-compile.mts", allow_single_file = True), + "_helpers": attr.label_list(default = [ + "//build_defs/languages/installed:consumer.mts", + "//build_defs/languages/installed:context.mts", + "//build_defs/languages:cargo-environment.mts", + "//build_defs/languages:cargo-metadata.mts", + "//:tools/packaging/frozen-cargo.mts", + "//:tools/packaging/cargo-manifest.mts", + "//:tools/packaging/portable-archive.mts", + ], allow_files = True), + }), +) + +def _source_compile_selection_impl(ctx): + tools = _source_compile_tools(ctx) + specification = ctx.actions.declare_file(ctx.label.name + ".tools.json") + ctx.actions.write(specification, json.encode(tools.specification)) + return bun_test_entrypoint(ctx, runner = ctx.file.entry_point, arguments = [], + files = ctx.files.data + tools.files + [specification], source_files = [ctx.file.entry_point] + ctx.files.data, + environment = {"OLIPHAUNT_SOURCE_COMPILE_TEST_TOOLS": _runfile(ctx, specification)}, test_runner = True) + +_source_compile_selection_test = rule( + implementation = _source_compile_selection_impl, + test = True, + fragments = ["cpp"], + toolchains = [_RUST] + BUN_SOURCE_TOOLCHAINS + use_cc_toolchain(), + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "entry_point": attr.label(mandatory = True, allow_single_file = True), + "data": attr.label_list(allow_files = True), + }), +) + +def source_compile_selection_test(name, args = [], **kwargs): + _source_compile_selection_test(name = name, args = bun_test_entrypoint_args(name) + args, **kwargs) + +def _source_cargo_name(target): + package = native.package_relative_label(target).package + carriers = [row for row in PUBLICATION_CARRIERS if row["ecosystem"] == "cargo" and row["target"] == None and PRODUCTS[row["product"]]["path"] == package] + if len(carriers) != 1: + fail("source archive needs one canonical Cargo declaration for its package: " + package) + return carriers[0]["name"] + +def source_compile_test(name, dependencies = [], args = [], **kwargs): + source_names = [_source_cargo_name(target) for target in [kwargs["archive"]] + dependencies] + names = ["cargo:" + name for name in source_names[1:]] + source_owners = cargo_source_owners(source_names) + source_product = source_owners[source_names[0]]["product"] + minimum = bool(dependencies) and source_product in PREPARED_NATIVE_SELECTED_PRODUCTS + payloads = cargo_payload_sources(source_owners) if source_product in ["oliphaunt-wasix-rust", "oliphaunt-pgwire-server"] else struct(completed = {}, current = {}) + current_runtime = source_product in ["oliphaunt-wasix-rust", "oliphaunt-pgwire-server"] and "liboliphaunt-wasix" in PREPARED_NATIVE_SELECTED_PRODUCTS and any([owner["product"] in PREPARED_NATIVE_SELECTED_PRODUCTS for owner in source_owners.values()]) + held = {} + for row in COMPLETED_SUPPLIER_ARTIFACTS.values(): + if row["artifact"] in names: + held[row["file"]["path"]] = json.encode({ + "name": row["artifact"][len("cargo:"):], + "version": row["publication"]["version"], + "size": row["file"]["size"], + "sha256": row["file"]["sha256"], + }) + _source_compile_test(name = name, dependencies = dependencies, held_sources = held, minimum = minimum, + source_identities = json.encode(source_owners), payload_completed = payloads.completed, payload_current = payloads.current, + payload_export = "//src/wasix/runtime:cargo_shipping_export" if current_runtime else None, + args = bun_test_entrypoint_args(name) + args, **kwargs) diff --git a/build_defs/languages/installed/source-compile.mts b/build_defs/languages/installed/source-compile.mts new file mode 100644 index 000000000..8cd8b657d --- /dev/null +++ b/build_defs/languages/installed/source-compile.mts @@ -0,0 +1,742 @@ +/** Compile final extracted source packages against genuine closed Cargo inputs. */ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + copyFileSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + realpathSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { + cargoDependencyMinimum, + renderCargoToml, + resolveCargoWorkspaceInheritance, +} from '../../../tools/packaging/cargo-manifest.mts'; +import { + assertCargoSourceArtifacts, + stageCargoCarrierInputs, +} from '../../../tools/packaging/frozen-cargo.mts'; +import { type CargoLinkConfiguration, cargoLinkEnvironment } from '../cargo-environment.mts'; +import { cargoSatisfies } from '../cargo-metadata.mts'; +import { cargoCandidate, cargoPayloadInputs, cargoPayloadPool } from './consumer.mts'; +import { type RegistryContext, validateRegistryContext, writeRegistryIndex } from './context.mts'; + +type Candidate = ReturnType; + +type SourceInput = { manifest: string; workspace: string }; + +/** Original path intent must identify one of the explicitly supplied source packages. */ +export function currentPathDependencies( + sources: Record, + localNames = new Set(Object.keys(sources)), +) { + const result: Record = {}; + for (const [name, source] of Object.entries(sources)) { + const original = Bun.TOML.parse(readFileSync(source.manifest, 'utf8')); + const workspace = Bun.TOML.parse(readFileSync(source.workspace, 'utf8')).workspace ?? {}; + const manifest = resolveCargoWorkspaceInheritance(original, workspace); + assert.equal(manifest.package.name, name); + const adopted = new Set(); + for (const [target, table] of [['', manifest], ...Object.entries(manifest.target ?? {})] as [ + string, + any, + ][]) { + const authored = target ? original.target[target] : original; + for (const section of ['dependencies', 'dev-dependencies', 'build-dependencies']) { + for (const [alias, dependency] of Object.entries(table[section] ?? {}) as [string, any][]) { + if (!dependency?.path) continue; + const packageName = dependency.package ?? alias; + // Linked payload carriers remain genuine registry inputs in this worker. + if (!localNames.has(packageName)) continue; + const supplier = sources[packageName]; + assert(supplier, `Missing explicit current path archive: ${packageName}`); + const base = + authored[section]?.[alias]?.workspace === true ? source.workspace : source.manifest; + assert.equal( + realpathSync( + path.resolve(path.dirname(realpathSync(base)), dependency.path, 'Cargo.toml'), + ), + realpathSync(supplier.manifest), + `Current path does not identify the declared source archive: ${packageName}`, + ); + adopted.add(packageName); + } + } + } + result[name] = [...adopted]; + } + return result; +} + +/** Retain published requirements; explicit paths qualify current construction before versioning. */ +export function sourceCandidates( + root: Candidate, + pool: Candidate[], + lockText: string, + heldPool: Candidate[] = [], + { + minimum = false, + currentPaths = {}, + includeDev = true, + sourceOwners = {}, + selectedProducts = [], + }: { + minimum?: boolean; + currentPaths?: Record; + includeDev?: boolean; + sourceOwners?: Record; + selectedProducts?: string[]; + } = {}, +) { + const lock = Bun.TOML.parse(lockText); + assert.equal(lock.version, 4); + const locals = new Map(); + for (const row of lock.package.filter((row: any) => row.source === undefined)) { + assert(!locals.has(row.name), `Ambiguous captured local package: ${row.name}`); + assert( + !lock.package.some((other: any) => other.name === row.name && other.source), + `Captured local/registry identity overlaps: ${row.name}`, + ); + locals.set(row.name, row); + } + const available = (rows: Candidate[]) => { + const result = new Map(); + for (const row of rows) { + assert(locals.has(row.name), `Undeclared local archive: ${row.name}`); + const key = `${row.name}@${row.version}`; + const previous = result.get(key); + assert( + !previous || previous.sha256 === row.sha256, + `Conflicting actual local archive: ${key}`, + ); + result.set(key, row); + } + return result; + }; + const current = available([root, ...pool]), + completed = available(heldPool); + const selected = new Map([[root.name, root]]); + const currentOwners = new Set([root.name]); + const pending = [root]; + for (const owner of pending) { + const requirements = new Map(); + for (const table of [owner.manifest, ...Object.values(owner.manifest.target ?? {})] as any[]) { + for (const section of [ + 'dependencies', + ...(includeDev ? ['dev-dependencies'] : []), + 'build-dependencies', + ]) { + for (const [alias, declaration] of Object.entries(table[section] ?? {})) { + const dependency = + typeof declaration === 'string' ? { version: declaration } : (declaration as any); + const name = dependency.package ?? alias; + if (!locals.has(name)) continue; + assert( + typeof dependency.version === 'string' && + !dependency.path && + !dependency.git && + !dependency.workspace, + `Local requirement is not conventional: ${name}`, + ); + requirements.set(name, [...(requirements.get(name) ?? []), dependency.version]); + } + } + } + for (const [name, ranges] of requirements) { + const already = selected.get(name); + if (already) { + assert( + ranges.every((range) => cargoSatisfies(already.version, range)), + `Conflicting packaged local requirement: ${name} ${ranges.join(', ')}`, + ); + if (!minimum && currentOwners.has(owner.name) && currentPaths[owner.name]?.includes(name)) + assert(currentOwners.has(name), `Current path overlaps a held source identity: ${name}`); + continue; + } + const matching = [...current.values()].filter( + (row) => row.name === name && ranges.every((range) => cargoSatisfies(row.version, range)), + ); + let chosen: Candidate | undefined; + let fromCurrent = false; + if (minimum) { + const floor = cargoDependencyMinimum(ranges); + const key = `${name}@${floor}`; + const held = completed.get(key); + chosen = held ?? current.get(key); + const owner = sourceOwners[name]; + assert( + chosen && + (held || (owner?.version === floor && selectedProducts.includes(owner.product))), + `Missing actual local dependency minimum: ${key}`, + ); + } else if (currentOwners.has(owner.name) && currentPaths[owner.name]?.includes(name)) { + assert.equal(matching.length, 1, `Missing or ambiguous current path archive: ${name}`); + chosen = matching[0]; + fromCurrent = true; + } else { + const heldVersion = locals.get(name).version; + const retainsHeld = ranges.every((range) => cargoSatisfies(heldVersion, range)); + chosen = retainsHeld ? completed.get(`${name}@${heldVersion}`) : matching[0]; + fromCurrent = !retainsHeld; + assert(!retainsHeld || chosen, `Missing actual held local archive: ${name}@${heldVersion}`); + assert( + retainsHeld || matching.length === 1, + `Missing or ambiguous actual local archive: ${name} ${ranges.join(', ')}`, + ); + } + assert(chosen); + selected.set(name, chosen); + if (fromCurrent) currentOwners.add(name); + pending.push(chosen); + } + } + if (includeDev) + assert.equal( + selected.size, + locals.size, + 'Captured local package closure differs from actual source manifests', + ); + return [...selected.values()]; +} + +/** Retarget only authenticated local package versions; registry resolution is immutable. */ +export function sourceLock(lockText: string, candidates: Candidate[]) { + const lock = Bun.TOML.parse(lockText); + const before = structuredClone(lock); + const replacements = new Map(); + for (const candidate of candidates) { + const rows = lock.package.filter((row: any) => row.name === candidate.name); + assert.equal(rows.length, 1, `Captured local identity is ambiguous: ${candidate.name}`); + const row = rows[0]; + assert( + !row.source && !row.checksum, + `Registry package cannot be retargeted: ${candidate.name}`, + ); + if (row.version !== candidate.version) { + replacements.set(`${row.name} ${row.version}`, `${row.name} ${candidate.version}`); + row.version = candidate.version; + } + } + if (!replacements.size) return lockText; + for (const row of lock.package) { + if (!row.source && row.dependencies) + row.dependencies = row.dependencies.map( + (reference: string) => replacements.get(reference) ?? reference, + ); + } + assert.deepEqual( + lock.package.filter((row: any) => row.source), + before.package.filter((row: any) => row.source), + 'Registry resolution changed during local retarget', + ); + const rendered = renderCargoToml(lock); + assert.deepEqual(Bun.TOML.parse(rendered), lock); + return rendered; +} + +const digest = (bytes: Buffer | string) => createHash('sha256').update(bytes).digest('hex'); +export async function sourceCompile( + specification: string, + runfiles: string, + { compile = true } = {}, +) { + assert(process.env.TEST_TMPDIR, 'Installed compilation requires an isolated test directory'); + const spec = JSON.parse(readFileSync(specification, 'utf8')); + const file = (name: string) => path.join(runfiles, name); + const output = mkdtempSync(path.join(process.env.TEST_TMPDIR, 'installed-source-compile-')); + try { + const diagnostics = + process.env.TEST_UNDECLARED_OUTPUTS_DIR ?? + mkdtempSync(path.join(process.env.TEST_TMPDIR, 'installed-source-diagnostics-')); + mkdirSync(diagnostics, { recursive: true }); + const archiveDirectory = path.join(output, 'archives'); + mkdirSync(archiveDirectory); + assert(Array.isArray(spec.archives) && spec.archives.length > 0); + const archivePool = spec.archives.map((archive: string, index: number) => { + const copied = path.join(archiveDirectory, `${index}-${path.basename(archive)}`); + copyFileSync(file(archive), copied); + return cargoCandidate(copied); + }); + const heldPool = (spec.held ?? []).map((row: any, index: number) => { + const copied = path.join(archiveDirectory, `held-${index}-${path.basename(row.file)}`); + copyFileSync(file(row.file), copied); + const bytes = readFileSync(copied), + candidate = cargoCandidate(copied); + assert.equal(bytes.length, row.size, 'Completed source archive size differs'); + assert.equal(candidate.sha256, row.sha256, 'Completed source archive SHA differs'); + assert.equal(candidate.name, row.name, 'Completed source archive name differs'); + assert.equal(candidate.version, row.version, 'Completed source archive version differs'); + return candidate; + }); + const capturedLock = readFileSync(file(spec.lock), 'utf8'); + const sourceInputs = Object.fromEntries( + Object.entries(spec.sources ?? {}).map(([archive, source]: [string, any]) => { + const candidate = archivePool[spec.archives.indexOf(archive)]; + assert(candidate, 'Original source manifest is outside the explicit archive pool'); + return [ + candidate.name, + { manifest: file(source.manifest), workspace: file(source.workspace) }, + ]; + }), + ); + const currentPaths = currentPathDependencies( + sourceInputs, + new Set( + Bun.TOML.parse(capturedLock) + .package.filter((row: any) => !row.source) + .map((row: any) => row.name), + ), + ); + const sourcePool = sourceCandidates( + archivePool[0], + archivePool.slice(1), + capturedLock, + heldPool, + { currentPaths }, + ); + const payloadPool = cargoPayloadPool( + spec.payloadPool ?? { completed: [], current: [], owners: {} }, + spec.sourceOwners ?? {}, + file, + archiveDirectory, + ); + const payloadOptions = { + currentSources: archivePool, + sourceOwners: spec.sourceOwners ?? {}, + selectedProducts: spec.selectedProducts ?? [], + }; + const candidates = [ + ...sourcePool, + ...cargoPayloadInputs(sourcePool, payloadPool, payloadOptions), + ]; + const candidate = sourcePool[0]; + const config = stageCargoCarrierInputs(candidates, output); + const directory = path.join(output, 'crates', `${candidate.name}-${candidate.version}`); + const manifest = path.join(directory, 'Cargo.toml'); + const seedLockText = sourceLock(capturedLock, sourcePool); + const context = JSON.parse(readFileSync(file(spec.index), 'utf8')) as RegistryContext; + const archives = validateRegistryContext(seedLockText, context); + const cargoHome = path.join(output, 'cargo-home'); + writeRegistryIndex(context, cargoHome); + const expected = new Set(); + const registryFiles = (directory: string, relative = '') => { + for (const entry of readdirSync(directory, { withFileTypes: true })) { + const name = path.posix.join(relative, entry.name); + if (entry.isDirectory()) registryFiles(path.join(directory, entry.name), name); + else { + assert(entry.isFile()); + expected.add(name); + } + } + }; + registryFiles(path.join(cargoHome, 'registry')); + const checksums = new Map( + archives.map((archive) => [ + `cache/${context.repository}/${archive.name}-${archive.version}.crate`, + archive.sha256, + ]), + ); + for (const name of checksums.keys()) expected.add(name); + const supplied = new Set(); + for (const [input, relative] of Object.entries(spec.cargoHome) as [string, string][]) { + assert( + expected.has(relative) && !supplied.has(relative), + `Unexpected captured registry input: ${relative}`, + ); + supplied.add(relative); + const bytes = readFileSync(file(input)); + const destination = path.join(cargoHome, 'registry', relative); + if (checksums.has(relative)) { + assert.equal( + digest(bytes), + checksums.get(relative), + `Captured registry checksum differs: ${relative}`, + ); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, bytes, { flag: 'wx' }); + } else + assert.deepEqual( + bytes, + readFileSync(destination), + `Captured sparse index differs: ${relative}`, + ); + } + assert.equal(supplied.size, expected.size, 'Captured Cargo repository is incomplete'); + const lock = path.join(directory, 'Cargo.lock'); + writeFileSync(lock, seedLockText); + const env = { + ...cargoLinkEnvironment( + JSON.parse(readFileSync(file(spec.compiler), 'utf8')) as CargoLinkConfiguration, + runfiles, + ), + CARGO_HOME: cargoHome, + CARGO_TARGET_DIR: path.join(output, 'target'), + CARGO_NET_OFFLINE: 'true', + CARGO_TERM_COLOR: 'never', + RUSTC: file(spec.rustc), + RUSTDOC: file(spec.rustdoc), + PATH: path.dirname(file(spec.rustc)), + // Reuse the compiler's content-keyed cache within this private test only. + HOME: process.env.TEST_TMPDIR, + TMPDIR: output, + }; + const version = Bun.spawnSync([file(spec.cargo), '--version'], { env }); + assert.equal(version.exitCode, 0); + assert.equal( + version.stdout.toString().trim().split(' ')[1], + context.cargo, + 'Selected Cargo differs from captured resolver', + ); + const compiler = Bun.spawnSync([file(spec.rustc), '--version', '--verbose'], { env }); + assert.equal(compiler.exitCode, 0); + assert.equal( + /^host: (.+)$/mu.exec(compiler.stdout.toString())?.[1], + context.target, + 'Installed source compilation requires the captured native host', + ); + async function cargo(name: string, command: string[], cwd = directory, configuration = config) { + const stdout = path.join(diagnostics, `${name}.stdout`), + stderr = path.join(diagnostics, `${name}.stderr`); + const child = Bun.spawn([file(spec.cargo), '--config', configuration, ...command], { + cwd, + env, + stdin: 'ignore', + stdout: Bun.file(stdout), + stderr: Bun.file(stderr), + }); + let timer: ReturnType | undefined; + try { + const code = await Promise.race([ + child.exited, + new Promise((_resolve, reject) => { + timer = setTimeout(() => { + child.kill('SIGKILL'); + reject(new Error(`Installed ${candidate.name} ${name} timed out`)); + }, 1_800_000); + }), + ]); + assert.equal(code, 0, `Installed ${candidate.name} ${name} failed: ${stderr}`); + return readFileSync(stdout, 'utf8'); + } finally { + if (timer) clearTimeout(timer); + await child.exited; + } + } + await cargo('generate-lock', ['generate-lockfile', '--offline', '--manifest-path', manifest]); + const lockText = readFileSync(lock, 'utf8'); + const capturedRegistry = new Map( + Bun.TOML.parse(capturedLock) + .package.filter((row: any) => row.source) + .map((row: any) => [`${row.name}@${row.version}`, row]), + ); + const assertCapturedRegistry = (text: string) => { + for (const row of Bun.TOML.parse(text).package.filter((row: any) => row.source)) { + const original = capturedRegistry.get(`${row.name}@${row.version}`) as any; + assert( + original && original.source === row.source && original.checksum === row.checksum, + 'Cargo resolved outside the captured original registry identities: ' + + row.name + + '@' + + row.version, + ); + } + }; + assertCapturedRegistry(lockText); + const metadata = JSON.parse( + await cargo('metadata', [ + 'metadata', + '--locked', + '--offline', + '--format-version', + '1', + '--filter-platform', + context.target, + '--manifest-path', + manifest, + ...spec.flags, + ]), + ); + const selected = metadata.packages.find((pkg: any) => pkg.id === metadata.resolve?.root); + assert.equal(selected?.name, candidate.name); + assert.equal(selected?.version, candidate.version); + assert.equal(selected?.source, null); + assert.equal( + realpathSync(selected.manifest_path), + realpathSync(manifest), + 'Cargo selected a source root outside the actual envelope', + ); + for (const pkg of metadata.packages.filter((pkg: any) => pkg.source === null)) { + const declared = candidates.find( + (row) => row.name === pkg.name && row.version === pkg.version, + ); + assert(declared, `Cargo selected an undeclared local package: ${pkg.name}@${pkg.version}`); + assert.equal( + realpathSync(pkg.manifest_path), + realpathSync( + path.join(output, 'crates', `${declared.name}-${declared.version}`, 'Cargo.toml'), + ), + ); + } + if (compile) + await cargo('test-no-run', [ + 'test', + '--no-run', + '--locked', + '--offline', + '--jobs', + '2', + '--manifest-path', + manifest, + ...spec.flags, + ]); + assert.equal( + readFileSync(lock, 'utf8'), + lockText, + 'Locked offline compilation changed its genuine lock', + ); + writeFileSync( + path.join(diagnostics, 'source-compile-result.json'), + `${JSON.stringify( + { + scope: compile ? 'installed-source-compile' : 'installed-source-resolution', + status: 'passed', + level: compile ? 'locked-offline-test-compilation' : 'locked-offline-metadata', + name: candidate.name, + version: candidate.version, + target: context.target, + flags: spec.flags, + archiveSha256: candidate.sha256, + cargoLockSha256: digest(lockText), + capturedCargoLockSha256: digest(capturedLock), + registryIndexSha256: digest(readFileSync(file(spec.index))), + selectedCandidates: candidates + .filter((row) => + metadata.packages.some( + (pkg: any) => + pkg.name === row.name && pkg.version === row.version && pkg.source === null, + ), + ) + .map(({ name, version, sha256 }) => ({ name, version, sha256 })), + }, + null, + 2, + )}\n`, + ); + if (compile && spec.minimum) { + // The original package's tests can elevate normal dependencies through + // dev requirements. A dependent compiles the production source without them. + const minimumSources = sourceCandidates( + archivePool[0], + archivePool.slice(1), + capturedLock, + heldPool, + { + minimum: true, + includeDev: false, + sourceOwners: spec.sourceOwners ?? {}, + selectedProducts: spec.selectedProducts ?? [], + }, + ); + const minimumCandidates = [ + ...minimumSources, + ...cargoPayloadInputs(minimumSources, payloadPool, { + ...payloadOptions, + includeDev: false, + }), + ]; + const minimumRoot = path.join(output, 'minimum'); + const minimumConfig = stageCargoCarrierInputs(minimumCandidates, minimumRoot); + const minimumSource = path.join( + minimumRoot, + 'crates', + `${candidate.name}-${candidate.version}`, + ); + const enabledFeatures = new Set( + metadata.resolve.nodes.find((node: any) => node.id === selected.id).features, + ); + const binaries = selected.targets.filter( + (target: any) => + target.kind.includes('bin') && + (target['required-features'] ?? []).every((feature: string) => + enabledFeatures.has(feature), + ), + ); + const hasBinary = binaries.length > 0; + let minimumLockText: string | undefined; + let compiled: { name: string; version: string; manifestPath: string }[]; + const staged = minimumCandidates.map(({ name, version }) => ({ + name, + version, + manifestPath: path.join(minimumRoot, 'crates', `${name}-${version}`, 'Cargo.toml'), + })); + if (hasBinary) { + // Cargo install compiles original library and binary production targets; + // root tests and --locked would admit the root's development constraints. + compiled = assertCargoSourceArtifacts( + await cargo( + 'minimum-install', + [ + 'install', + '--path', + minimumSource, + '--root', + path.join(minimumRoot, 'installed'), + '--debug', + '--offline', + '--jobs', + '2', + '--message-format', + 'json', + ...binaries.flatMap((target: any) => ['--bin', target.name]), + ...spec.flags, + ], + minimumSource, + minimumConfig, + ), + staged, + [candidate.name], + ); + } else { + const consumer = path.join(minimumRoot, 'consumer'); + mkdirSync(path.join(consumer, 'src'), { recursive: true }); + writeFileSync(path.join(consumer, 'src/lib.rs'), 'pub fn qualification() {}\n'); + writeFileSync( + path.join(consumer, 'Cargo.toml'), + renderCargoToml({ + package: { name: 'source-floor-consumer', version: '0.0.0', edition: '2021' }, + dependencies: { + [candidate.name]: { version: `=${candidate.version}`, 'default-features': false }, + }, + features: Object.fromEntries( + Object.keys(candidate.manifest.features ?? {}).map((feature) => [ + feature, + [`${candidate.name}/${feature}`], + ]), + ), + }), + ); + const minimumLock = path.join(consumer, 'Cargo.lock'); + writeFileSync(minimumLock, sourceLock(capturedLock, minimumSources)); + await cargo('minimum-lock', ['generate-lockfile', '--offline'], consumer, minimumConfig); + const minimumMetadata = JSON.parse( + await cargo( + 'minimum-metadata', + [ + 'metadata', + '--locked', + '--offline', + '--format-version', + '1', + '--filter-platform', + context.target, + ...spec.flags, + ], + consumer, + minimumConfig, + ), + ); + for (const pkg of minimumMetadata.packages.filter( + (pkg: any) => pkg.source === null && pkg.id !== minimumMetadata.resolve.root, + )) { + const declared = minimumCandidates.find( + (row) => row.name === pkg.name && row.version === pkg.version, + ); + assert( + declared, + `Cargo selected an undeclared minimum source: ${pkg.name}@${pkg.version}`, + ); + assert.equal( + realpathSync(pkg.manifest_path), + realpathSync( + path.join( + minimumRoot, + 'crates', + `${declared.name}-${declared.version}`, + 'Cargo.toml', + ), + ), + ); + } + assert( + minimumMetadata.packages.some( + (pkg: any) => + pkg.source === null && + pkg.name === candidate.name && + pkg.version === candidate.version, + ), + 'Dependent did not compile the actual source envelope', + ); + minimumLockText = readFileSync(minimumLock, 'utf8'); + assertCapturedRegistry(minimumLockText); + compiled = assertCargoSourceArtifacts( + await cargo( + 'minimum-build', + [ + 'build', + '--locked', + '--offline', + '--jobs', + '2', + '--message-format', + 'json', + ...spec.flags, + ], + consumer, + minimumConfig, + ), + staged, + [candidate.name], + ); + assert.equal( + readFileSync(minimumLock, 'utf8'), + minimumLockText, + 'Minimum compilation changed its resolved lock', + ); + } + writeFileSync( + path.join(diagnostics, 'source-minimum-result.json'), + `${JSON.stringify( + { + scope: 'installed-source-dependent-minimum', + status: 'passed', + level: hasBinary + ? 'offline-production-install' + : 'locked-offline-dependent-compilation', + name: candidate.name, + version: candidate.version, + target: context.target, + flags: spec.flags, + archiveSha256: candidate.sha256, + ...(minimumLockText ? { cargoLockSha256: digest(minimumLockText) } : {}), + capturedCargoLockSha256: digest(capturedLock), + selectedCandidates: minimumCandidates + .filter((row) => + compiled.some((pkg: any) => pkg.name === row.name && pkg.version === row.version), + ) + .map(({ name, version, sha256 }) => ({ name, version, sha256 })), + }, + null, + 2, + )}\n`, + ); + } + } finally { + rmSync(output, { recursive: true, force: true }); + } +} +if (import.meta.main) { + const [specification, runfiles] = Bun.argv.slice(2); + if (specification === '--help') + console.log( + 'Declared compile-only qualification: SPEC RUNFILES. Genuine Cargo lock/index/cache and actual source archives required. No source rewriting or network resolution.', + ); + else { + assert(specification && runfiles && Bun.argv.length === 4); + await sourceCompile(specification, runfiles); + } +} diff --git a/build_defs/languages/installed/source-compile.test.mts b/build_defs/languages/installed/source-compile.test.mts new file mode 100644 index 000000000..236504da7 --- /dev/null +++ b/build_defs/languages/installed/source-compile.test.mts @@ -0,0 +1,892 @@ +import { afterAll, expect, test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { createDeterministicTar } from '../../../tools/packaging/archive-directory.mts'; +import { renderCargoToml } from '../../../tools/packaging/cargo-manifest.mts'; +import { stageCargoCarrierInputs } from '../../../tools/packaging/frozen-cargo.mts'; +import { canonicalGzipSync } from '../../../tools/packaging/portable-archive.mts'; +import { cargoCandidate } from './consumer.mts'; +import { writeRegistryIndex } from './context.mts'; +import { + currentPathDependencies, + sourceCandidates, + sourceCompile, + sourceLock, +} from './source-compile.mts'; + +const directory = mkdtempSync(path.join(tmpdir(), 'source-lock-selection-')); +afterAll(() => rmSync(directory, { recursive: true, force: true })); +async function archive( + name: string, + version: string, + dependencies: Record = {}, + source = '', +) { + const tree = path.join( + directory, + `${name}-${version}-${Math.random().toString(16).slice(2)}`, + `${name}-${version}`, + ); + mkdirSync(path.join(tree, 'src'), { recursive: true }); + writeFileSync( + path.join(tree, 'Cargo.toml'), + renderCargoToml({ package: { name, version, edition: '2021' }, dependencies }), + ); + writeFileSync(path.join(tree, 'src/lib.rs'), source); + const file = `${tree}.crate`; + writeFileSync(file, canonicalGzipSync(await createDeterministicTar(tree, { keepParent: true }))); + return cargoCandidate(file); +} +const child = await archive('fixture-child', '0.1.0'); +const childNext = await archive('fixture-child', '0.1.1'); +const parent = await archive('fixture-parent', '0.2.0', { 'fixture-child': '=0.1.0' }); +const parentNext = await archive('fixture-parent', '0.2.1', { 'fixture-child': '=0.1.0' }); +const parentAdopts = await archive('fixture-parent', '0.2.1', { 'fixture-child': '=0.1.1' }); +const parentRaisesFloor = await archive('fixture-parent', '0.2.1', { 'fixture-child': '^0.1.1' }); +const parentRange = await archive('fixture-parent', '0.2.1', { 'fixture-child': '^0.1.0' }); +const server = await archive('fixture-server', '0.3.0', { + 'fixture-parent': '0.2.0', + 'fixture-child': '0.1.0', +}); +const serverNext = await archive('fixture-server', '0.3.1', { + 'fixture-parent': '0.2.0', + 'fixture-child': '0.1.0', +}); +const serverAdopts = await archive('fixture-server', '0.3.1', { + 'fixture-parent': '=0.2.1', + 'fixture-child': '=0.1.1', +}); +const registry = { + name: 'fixture-registry', + version: '1.0.0', + source: 'registry+https://github.com/rust-lang/crates.io-index', + checksum: 'a'.repeat(64), +}; +const lock = (packages: (typeof child)[]) => + renderCargoToml({ + version: 4, + package: [...packages.map((row) => ({ name: row.name, version: row.version })), registry], + }); +const parentLock = lock([parent, child]); +const serverLock = lock([server, parent, child]); +const identities = (rows: (typeof child)[]) => + rows.map((row) => `${row.name}@${row.version}`).sort(); +const minimumCandidates = ( + root: typeof child, + pool: (typeof child)[], + captured: string, + held: (typeof child)[] = [], +) => sourceCandidates(root, pool, captured, held, { minimum: true, includeDev: false }); + +test('query-only own version retargets one local row and preserves registry resolution', () => { + const original = lock([child]); + const result = Bun.TOML.parse(sourceLock(original, sourceCandidates(childNext, [], original))); + expect(result.package).toEqual([{ name: child.name, version: childNext.version }, registry]); +}); +test('SDK-only bump retains exact query even when a newer candidate is present', () => { + expect(identities(sourceCandidates(parentNext, [childNext, child], parentLock, [child]))).toEqual( + ['fixture-child@0.1.0', 'fixture-parent@0.2.1'], + ); +}); +test('server-only bump retains SDK and query through conventional caret requirements', () => { + expect( + identities( + sourceCandidates(serverNext, [parentNext, childNext, parent, child], serverLock, [ + parent, + child, + ]), + ), + ).toEqual(['fixture-child@0.1.0', 'fixture-parent@0.2.0', 'fixture-server@0.3.1']); +}); +test('coordinated adoption selects new query only after packaged requirement changes', () => { + expect(identities(sourceCandidates(parentAdopts, [childNext, child], parentLock))).toEqual([ + 'fixture-child@0.1.1', + 'fixture-parent@0.2.1', + ]); + expect( + identities( + sourceCandidates(serverAdopts, [parentAdopts, childNext, parent, child], serverLock), + ), + ).toEqual(['fixture-child@0.1.1', 'fixture-parent@0.2.1', 'fixture-server@0.3.1']); +}); +test('same-version completed bytes win over unselected current source bytes', async () => { + const changed = await archive(child.name, child.version, {}, '// current unpublished source\n'); + const selected = sourceCandidates(parentNext, [changed], parentLock, [child]); + expect(selected.find((row) => row.name === child.name)?.sha256).toBe(child.sha256); +}); +test('authored current path adoption selects actual current bytes before version calculation', async () => { + const changed = await archive(child.name, child.version, {}, 'pub fn new_api() {}\n'); + const currentPaths = { [parentNext.name]: [child.name] }; + const selected = sourceCandidates(parentNext, [changed], parentLock, [child], { currentPaths }); + expect(selected.find((row) => row.name === child.name)?.sha256).toBe(changed.sha256); + expect( + minimumCandidates(parentNext, [changed], parentLock, [child]).find( + (row) => row.name === child.name, + )?.sha256, + ).toBe(child.sha256); +}); +test('current path intent verifies the original manifest and explicit dependency archive', () => { + const root = mkdtempSync(path.join(directory, 'path-intent-')); + const parentDirectory = path.join(root, 'parent'), + childDirectory = path.join(root, 'query'); + mkdirSync(parentDirectory); + mkdirSync(childDirectory); + const workspace = path.join(root, 'Cargo.toml'); + writeFileSync( + workspace, + renderCargoToml({ + workspace: { + dependencies: { query: { package: child.name, version: '^0.1.0', path: 'query' } }, + }, + }), + ); + const parentManifest = path.join(parentDirectory, 'Cargo.toml'), + childManifest = path.join(childDirectory, 'Cargo.toml'); + writeFileSync( + childManifest, + renderCargoToml({ package: { name: child.name, version: child.version } }), + ); + const sources = { + [parent.name]: { manifest: parentManifest, workspace }, + [child.name]: { manifest: childManifest, workspace }, + }; + for (const dependency of [ + { package: child.name, version: '^0.1.0', path: '../query' }, + { workspace: true }, + ]) { + writeFileSync( + parentManifest, + renderCargoToml({ + package: { name: parent.name, version: parent.version }, + dependencies: { query: dependency }, + }), + ); + expect(currentPathDependencies(sources)[parent.name]).toEqual([child.name]); + } + expect(() => + currentPathDependencies( + { [parent.name]: sources[parent.name] }, + new Set([parent.name, child.name]), + ), + ).toThrow('Missing explicit current path archive'); + writeFileSync( + parentManifest, + renderCargoToml({ + package: { name: parent.name, version: parent.version }, + dependencies: { query: { package: child.name, version: '^0.1.0', path: '.' } }, + }), + ); + expect(() => currentPathDependencies(sources)).toThrow('Current path does not identify'); +}); +test('current workspace path intent never retargets an unchanged held source dependency', async () => { + const changed = await archive(child.name, child.version, {}, 'pub fn new_api() {}\n'); + const selected = sourceCandidates(serverNext, [parent, changed], serverLock, [parent, child], { + currentPaths: { [parent.name]: [child.name] }, + }); + expect(selected.find((row) => row.name === child.name)?.sha256).toBe(child.sha256); +}); +test('missing exact held identity fails instead of adopting a compatible newer version', () => { + expect(() => sourceCandidates(serverNext, [parentNext, childNext], serverLock)).toThrow( + 'Missing actual held', + ); +}); +test('same-version current bytes never stand in for missing completed dependency bytes', () => { + expect(() => sourceCandidates(parentNext, [child], parentLock)).toThrow('Missing actual held'); + expect(() => sourceCandidates(serverNext, [parent, child], serverLock)).toThrow( + 'Missing actual held', + ); +}); +test('missing adopted candidate and conflicting identities fail closed', () => { + expect(() => sourceCandidates(parentAdopts, [child], parentLock)).toThrow('Missing or ambiguous'); + expect(() => + sourceCandidates(parentNext, [child, { ...child, sha256: '0'.repeat(64) }], parentLock), + ).toThrow('Conflicting actual'); + expect(() => + sourceCandidates(parentNext, [child, { ...child, name: 'undeclared' }], parentLock), + ).toThrow('Undeclared local'); +}); +test('newly authored floor uses the exact completed source instead of a compatible newer candidate', async () => { + const childHigher = await archive(child.name, '0.1.2'); + const selected = minimumCandidates(parentRaisesFloor, [childHigher], parentLock, [childNext]); + expect(identities(selected)).toEqual(['fixture-child@0.1.1', 'fixture-parent@0.2.1']); + expect(selected.find((row) => row.name === child.name)?.sha256).toBe(childNext.sha256); +}); +test('a compatible held identity above the declared floor does not replace the actual floor', () => { + expect( + identities( + minimumCandidates(parentRange, [childNext], lock([parent, childNext]), [child, childNext]), + ), + ).toEqual(['fixture-child@0.1.0', 'fixture-parent@0.2.1']); +}); +test('missing authored floor rejects a compatible higher source before Cargo runs', async () => { + const childHigher = await archive(child.name, '0.1.2'); + expect(() => minimumCandidates(parentRaisesFloor, [childHigher], parentLock)).toThrow( + 'Missing actual local dependency minimum: fixture-child@0.1.1', + ); +}); +test('first source floor permits only its exact prepared selected constructed producer', () => { + const options = { + minimum: true, + includeDev: false, + sourceOwners: { [child.name]: { product: 'query', version: child.version } }, + selectedProducts: ['query'], + }; + expect(identities(sourceCandidates(parentNext, [child], parentLock, [], options))).toEqual([ + 'fixture-child@0.1.0', + 'fixture-parent@0.2.1', + ]); + expect(() => + sourceCandidates(parentNext, [child], parentLock, [], { ...options, selectedProducts: [] }), + ).toThrow('Missing actual local dependency minimum'); + expect(() => + sourceCandidates(parentNext, [child], parentLock, [], { + ...options, + sourceOwners: { [child.name]: { product: 'query', version: '0.1.1' } }, + }), + ).toThrow('Missing actual local dependency minimum'); +}); +test('a stronger root floor still satisfies a compatible lower transitive requirement', async () => { + const compatibleParent = await archive(parent.name, parent.version, { [child.name]: '^0.1.0' }); + const serverConflicts = { + ...serverNext, + manifest: { + ...serverNext.manifest, + dependencies: { 'fixture-parent': '0.2.0', 'fixture-child': '0.1.1' }, + }, + }; + expect( + identities( + minimumCandidates(serverConflicts, [compatibleParent, childNext], serverLock, [ + compatibleParent, + child, + childNext, + ]), + ), + ).toEqual(['fixture-child@0.1.1', 'fixture-parent@0.2.0', 'fixture-server@0.3.1']); + expect(() => + minimumCandidates(serverConflicts, [parent, childNext], serverLock, [parent, child, childNext]), + ).toThrow('Conflicting packaged local requirement'); +}); +test('target build and development local source requirements retain their captured floor closure', () => { + for (const section of ['build-dependencies', 'dev-dependencies']) { + const manifest = { + ...parentNext.manifest, + dependencies: {}, + target: { 'cfg(unix)': { [section]: { query: { package: child.name, version: '^0.1.0' } } } }, + }; + expect( + identities(sourceCandidates({ ...parentNext, manifest }, [childNext], parentLock, [child])), + ).toEqual(['fixture-child@0.1.0', 'fixture-parent@0.2.1']); + } +}); +test('normal and build requirements on the same package use their effective floor regardless of section order', async () => { + for (const [normal, build] of [ + ['^0.1.0', '^0.1.1'], + ['^0.1.1', '^0.1.0'], + ]) { + const root = await archive(parent.name, parentNext.version, { [child.name]: normal }); + root.manifest['build-dependencies'] = { query: { package: child.name, version: build } }; + expect( + identities(minimumCandidates(root, [child], lock([parent, childNext]), [childNext])), + ).toEqual(['fixture-child@0.1.1', 'fixture-parent@0.2.1']); + } +}); +test('registry identities and missing captured local rows cannot be retargeted', () => { + expect(() => sourceLock(parentLock, [{ ...child, name: registry.name }])).toThrow( + 'Registry package cannot', + ); + expect(() => sourceLock(parentLock, [{ ...child, name: 'absent' }])).toThrow('ambiguous'); +}); +test('qualified local references follow own versions without touching registry references', () => { + const original = renderCargoToml({ + version: 4, + package: [ + { + name: parent.name, + version: parent.version, + dependencies: [`${child.name} ${child.version}`, registry.name], + }, + { name: child.name, version: child.version }, + registry, + ], + }); + const result = Bun.TOML.parse(sourceLock(original, [parentAdopts, childNext])); + expect(result.package[0].dependencies).toEqual([ + `${child.name} ${childNext.version}`, + registry.name, + ]); + expect(result.package[2]).toEqual(registry); +}); +test('unchanged candidate identities preserve the original Cargo lock bytes', () => { + expect(sourceLock(parentLock, [parent, child])).toBe(parentLock); + expect(readFileSync(child.file).length).toBeGreaterThan(0); +}); +test('failure removes only owned work and retains diagnostics outside it', async () => { + const scratch = mkdtempSync(path.join(directory, 'cleanup-')); + const specification = path.join(scratch, 'spec.json'); + writeFileSync(specification, JSON.stringify({ archives: [] })); + const previousTemporary = process.env.TEST_TMPDIR; + const previousDiagnostics = process.env.TEST_UNDECLARED_OUTPUTS_DIR; + process.env.TEST_TMPDIR = scratch; + delete process.env.TEST_UNDECLARED_OUTPUTS_DIR; + try { + await expect(sourceCompile(specification, scratch)).rejects.toThrow(); + const members = readdirSync(scratch); + expect(members.some((name) => name.startsWith('installed-source-compile-'))).toBe(false); + expect(members.some((name) => name.startsWith('installed-source-diagnostics-'))).toBe(true); + expect(readFileSync(specification, 'utf8')).toBe('{"archives":[]}'); + } finally { + if (previousTemporary === undefined) delete process.env.TEST_TMPDIR; + else process.env.TEST_TMPDIR = previousTemporary; + if (previousDiagnostics === undefined) delete process.env.TEST_UNDECLARED_OUTPUTS_DIR; + else process.env.TEST_UNDECLARED_OUTPUTS_DIR = previousDiagnostics; + } +}); + +async function qualifyOfflineCargoScenarios() { + const runfiles = process.env.RUNFILES_DIR ?? process.env.TEST_SRCDIR; + assert( + runfiles && process.env.OLIPHAUNT_SOURCE_COMPILE_TEST_TOOLS && process.env.TEST_TMPDIR, + 'Run the configured source_compile_selection_test with its declared Cargo/Rust/compiler inputs', + ); + const relative = (file: string) => path.relative(runfiles, file); + const tools = JSON.parse( + readFileSync(path.join(runfiles, process.env.OLIPHAUNT_SOURCE_COMPILE_TEST_TOOLS), 'utf8'), + ); + const tool = (name: string) => path.join(runfiles, tools[name]); + const scratch = mkdtempSync(path.join(process.env.TEST_TMPDIR, 'source-phase-cases-')); + const query = await archive('fixture-query', '0.1.1', {}, 'pub fn stable() -> u32 { 11 }\n'); + const sdk = await archive( + 'fixture-sdk', + '0.3.3', + { [query.name]: '0.1.1' }, + 'pub fn value() -> u32 { fixture_query::stable() }\n', + ); + const captured = path.join(scratch, 'captured'); + mkdirSync(captured); + const config = stageCargoCarrierInputs([sdk, query], captured); + const manifest = path.join(captured, 'crates', `${sdk.name}-${sdk.version}`, 'Cargo.toml'); + const generated = Bun.spawnSync( + [ + tool('cargo'), + '--config', + config, + 'generate-lockfile', + '--offline', + '--manifest-path', + manifest, + ], + { + env: { + PATH: path.dirname(tool('rustc')), + RUSTC: tool('rustc'), + CARGO_HOME: path.join(captured, 'cargo-home'), + HOME: captured, + CARGO_NET_OFFLINE: 'true', + }, + }, + ); + expect(generated.exitCode).toBe(0); + const cargoVersion = Bun.spawnSync([tool('cargo'), '--version']); + expect(cargoVersion.exitCode).toBe(0); + const capturedLock = path.join(captured, 'Cargo.lock'); + writeFileSync(capturedLock, readFileSync(path.join(path.dirname(manifest), 'Cargo.lock'))); + const registryConfig = { + dl: 'https://static.crates.io/crates/{crate}/{crate}-{version}.crate', + api: 'https://crates.io', + }; + const configFile = path.join(captured, 'config.json'); + writeFileSync(configFile, `${JSON.stringify(registryConfig)}\n`); + const index = path.join(captured, 'registry-index.json'); + writeFileSync( + index, + JSON.stringify({ + schema: 'oliphaunt-installed-cargo-fixture-v1', + cargo: cargoVersion.stdout.toString().trim().split(' ')[1], + repository: 'index.crates.io-1949cf8c6b5b557f', + target: 'x86_64-unknown-linux-gnu', + archives: [], + indexes: [], + config: registryConfig, + }), + ); + let count = 0; + async function qualify( + root: typeof sdk, + dependency: typeof query, + held: (typeof query)[], + minimum: boolean, + expectedSuccess: boolean, + sources: Record = {}, + payloadFixture?: { + lock: string; + index: string; + cargoHome: Record; + payloadPool: any; + sourceOwners: any; + selectedProducts: string[]; + expectedError?: RegExp; + }, + ) { + const directory = path.join(scratch, `case-${count++}`); + const started = performance.now(); + console.error( + `Offline Cargo ${path.basename(directory)}: ${root.name}@${root.version} minimum=${minimum} expectedSuccess=${expectedSuccess}`, + ); + mkdirSync(directory); + const diagnostics = path.join(directory, 'diagnostics'); + mkdirSync(diagnostics); + const spec = path.join(directory, 'spec.json'); + writeFileSync( + spec, + JSON.stringify({ + ...tools, + archives: [root.file, dependency.file].map(relative), + sources: Object.fromEntries( + Object.entries(sources).map(([archive, source]) => [ + relative(archive), + { manifest: relative(source.manifest), workspace: relative(source.workspace) }, + ]), + ), + held: held.map((row) => ({ + file: relative(row.file), + name: row.name, + version: row.version, + size: readFileSync(row.file).length, + sha256: row.sha256, + })), + lock: relative(payloadFixture?.lock ?? capturedLock), + index: relative(payloadFixture?.index ?? index), + cargoHome: payloadFixture?.cargoHome ?? { + [relative(configFile)]: 'index/index.crates.io-1949cf8c6b5b557f/config.json', + }, + ...(payloadFixture + ? { + payloadPool: payloadFixture.payloadPool, + sourceOwners: payloadFixture.sourceOwners, + selectedProducts: payloadFixture.selectedProducts, + } + : {}), + flags: [], + minimum, + }), + ); + const previous = process.env.TEST_UNDECLARED_OUTPUTS_DIR; + process.env.TEST_UNDECLARED_OUTPUTS_DIR = diagnostics; + try { + if (expectedSuccess) await sourceCompile(spec, runfiles); + else + await expect(sourceCompile(spec, runfiles)).rejects.toThrow( + payloadFixture?.expectedError ?? /minimum-(build|install) failed/, + ); + if (!expectedSuccess && payloadFixture?.expectedError) return {}; + const ordinary = JSON.parse( + readFileSync(path.join(diagnostics, 'source-compile-result.json'), 'utf8'), + ); + let floor; + if (expectedSuccess && minimum) + floor = JSON.parse( + readFileSync(path.join(diagnostics, 'source-minimum-result.json'), 'utf8'), + ); + return { ordinary, floor }; + } finally { + console.error( + `Offline Cargo ${path.basename(directory)} elapsed ${Math.round(performance.now() - started)}ms`, + ); + if (previous === undefined) delete process.env.TEST_UNDECLARED_OUTPUTS_DIR; + else process.env.TEST_UNDECLARED_OUTPUTS_DIR = previous; + } + } + const floor = await archive(query.name, '0.1.2', {}, 'pub fn stable() -> u32 { 12 }\n'); + const higher = await archive( + query.name, + '0.1.3', + {}, + 'pub fn stable() -> u32 { 13 }\npub fn new_api() -> u32 { 13 }\n', + ); + const devTree = path.join(scratch, 'dev-sdk', `${sdk.name}-0.3.4`); + mkdirSync(path.join(devTree, 'src'), { recursive: true }); + writeFileSync( + path.join(devTree, 'Cargo.toml'), + renderCargoToml({ + package: { name: sdk.name, version: '0.3.4', edition: '2021' }, + dependencies: { [query.name]: '0.1.2' }, + 'dev-dependencies': { [query.name]: '0.1.3' }, + }), + ); + writeFileSync( + path.join(devTree, 'src/lib.rs'), + 'pub fn value() -> u32 { fixture_query::new_api() }\n', + ); + const devArchive = `${devTree}.crate`; + writeFileSync( + devArchive, + canonicalGzipSync(await createDeterministicTar(devTree, { keepParent: true })), + ); + const devRoot = cargoCandidate(devArchive); + const ordinary = await qualify(devRoot, higher, [floor], false, true); + expect( + ordinary.ordinary.selectedCandidates.find((row: any) => row.name === query.name).version, + ).toBe('0.1.3'); + await qualify(devRoot, higher, [floor], true, false); + // A dependency consumer proves the library; a shipping binary must also + // compile from its original source without dev requirements raising its floor. + writeFileSync( + path.join(devTree, 'src/lib.rs'), + 'pub fn value() -> u32 { fixture_query::stable() }\n', + ); + writeFileSync( + path.join(devTree, 'src/main.rs'), + 'fn main() { println!("{}", fixture_query::new_api()); }\n', + ); + const binaryArchive = path.join(scratch, 'binary.crate'); + writeFileSync( + binaryArchive, + canonicalGzipSync(await createDeterministicTar(devTree, { keepParent: true })), + ); + await qualify(cargoCandidate(binaryArchive), higher, [floor], true, false); + writeFileSync( + path.join(devTree, 'src/main.rs'), + 'fn main() { println!("{}", fixture_query::stable()); }\n', + ); + const compatibleBinaryArchive = path.join(scratch, 'compatible-binary.crate'); + writeFileSync( + compatibleBinaryArchive, + canonicalGzipSync(await createDeterministicTar(devTree, { keepParent: true })), + ); + const binary = await qualify( + cargoCandidate(compatibleBinaryArchive), + higher, + [floor], + true, + true, + ); + expect(binary.floor.level).toBe('offline-production-install'); + expect(binary.floor.selectedCandidates.find((row: any) => row.name === query.name).version).toBe( + '0.1.2', + ); + writeFileSync( + path.join(devTree, 'Cargo.toml'), + renderCargoToml({ + package: { name: sdk.name, version: '0.3.4', edition: '2021' }, + dependencies: { [query.name]: '0.1.2' }, + 'dev-dependencies': { [query.name]: '0.1.3' }, + features: { inactive: [] }, + bin: [{ name: sdk.name, path: 'src/main.rs', 'required-features': ['inactive'] }], + }), + ); + writeFileSync( + path.join(devTree, 'src/main.rs'), + 'fn main() { println!("{}", fixture_query::new_api()); }\n', + ); + const inactiveArchive = path.join(scratch, 'inactive-binary.crate'); + writeFileSync( + inactiveArchive, + canonicalGzipSync(await createDeterministicTar(devTree, { keepParent: true })), + ); + const inactive = await qualify(cargoCandidate(inactiveArchive), higher, [floor], true, true); + expect(inactive.floor.level).toBe('locked-offline-dependent-compilation'); + const compatible = await archive( + sdk.name, + '0.3.4', + { [query.name]: '0.1.2' }, + 'pub fn value() -> u32 { fixture_query::stable() }\n', + ); + const selected = await qualify(compatible, higher, [floor], true, true); + expect( + selected.floor.selectedCandidates.find((row: any) => row.name === query.name).version, + ).toBe('0.1.2'); + const current = await archive(query.name, query.version, {}, 'pub fn new_api() -> u32 { 13 }\n'); + const coordinated = await archive( + sdk.name, + sdk.version, + { [query.name]: query.version }, + 'pub fn value() -> u32 { fixture_query::new_api() }\n', + ); + const originalDirectory = path.join(scratch, 'original'); + mkdirSync(path.join(originalDirectory, 'sdk'), { recursive: true }); + mkdirSync(path.join(originalDirectory, 'query')); + const workspace = path.join(originalDirectory, 'Cargo.toml'); + writeFileSync(workspace, '[workspace]\n'); + const originalSdk = path.join(originalDirectory, 'sdk/Cargo.toml'), + originalQuery = path.join(originalDirectory, 'query/Cargo.toml'); + writeFileSync( + originalSdk, + renderCargoToml({ + package: { name: sdk.name, version: sdk.version }, + dependencies: { [query.name]: { version: query.version, path: '../query' } }, + }), + ); + writeFileSync( + originalQuery, + renderCargoToml({ package: { name: query.name, version: query.version } }), + ); + const sources = { + [coordinated.file]: { manifest: originalSdk, workspace }, + [current.file]: { manifest: originalQuery, workspace }, + }; + const beforeVersions = await qualify(coordinated, current, [query], false, true, sources); + expect( + beforeVersions.ordinary.selectedCandidates.find((row: any) => row.name === query.name).sha256, + ).toBe(current.sha256); + await qualify(coordinated, current, [query], true, false, sources); + // These tiny archives model historical captured registry inputs and actual + // current constructor outputs. They make no publication authentication claim. + const payloadNames = [ + 'fixture-portable', + 'fixture-linux-x64', + 'fixture-linux-arm64', + 'fixture-macos', + 'fixture-windows', + 'fixture-part', + ]; + async function payloadArchive(name: string, version: string) { + if (name !== payloadNames[0]) + return archive(name, version, {}, 'pub fn stable() -> u32 { 21 }\n'); + const tree = path.join(scratch, `payload-${version}`, `${name}-${version}`); + mkdirSync(path.join(tree, 'src'), { recursive: true }); + writeFileSync( + path.join(tree, 'Cargo.toml'), + renderCargoToml({ + package: { name, version, edition: '2021' }, + 'build-dependencies': { [payloadNames[5]]: `=${version}` }, + }), + ); + writeFileSync( + path.join(tree, 'build.rs'), + 'fn main() { println!("cargo:rustc-env=VALUE={}", fixture_part::stable()); }\n', + ); + writeFileSync( + path.join(tree, 'src/lib.rs'), + 'pub fn stable() -> u32 { env!("VALUE").parse().unwrap() }\n', + ); + const file = tree + '.crate'; + writeFileSync( + file, + canonicalGzipSync(await createDeterministicTar(tree, { keepParent: true })), + ); + return cargoCandidate(file); + } + const heldPayloads = await Promise.all(payloadNames.map((name) => payloadArchive(name, '2.1.0'))); + const currentPayloads = await Promise.all( + payloadNames.map((name) => payloadArchive(name, '2.2.0')), + ); + const payloadContext = { + schema: 'oliphaunt-installed-cargo-fixture-v1', + cargo: cargoVersion.stdout.toString().trim().split(' ')[1], + repository: 'index.crates.io-1949cf8c6b5b557f', + target: 'x86_64-unknown-linux-gnu', + config: registryConfig, + archives: heldPayloads.map(({ name, version }) => ({ name, version })), + indexes: heldPayloads.map((row) => ({ + path: `${row.name.slice(0, 2)}/${row.name.slice(2, 4)}/${row.name}`, + header: Buffer.from([3, 2, 0, 0, 0, 0]).toString('base64'), + records: [ + { + name: row.name, + vers: row.version, + deps: Object.entries(row.manifest['build-dependencies'] ?? {}).map(([name, req]) => ({ + name, + req, + features: [], + optional: false, + default_features: true, + target: null, + kind: 'build', + registry: null, + })), + cksum: row.sha256, + features: {}, + yanked: false, + }, + ], + })), + }; + const payloadHome = path.join(scratch, 'historical-payload-home'); + writeRegistryIndex(payloadContext, payloadHome); + const payloadIndex = path.join(scratch, 'historical-payload-index.json'); + writeFileSync(payloadIndex, JSON.stringify(payloadContext)); + const payloadLock = path.join(scratch, 'historical-payload-lock.toml'); + writeFileSync( + payloadLock, + renderCargoToml({ + version: 4, + package: [ + { name: sdk.name, version: sdk.version }, + { name: query.name, version: query.version }, + ...heldPayloads.map((row) => ({ + name: row.name, + version: row.version, + source: 'registry+https://github.com/rust-lang/crates.io-index', + checksum: row.sha256, + })), + ], + }), + ); + const payloadCargoHome: Record = {}; + const registryDirectory = path.join(payloadHome, 'registry'); + const captureFiles = (directory: string, prefix = '') => { + for (const entry of readdirSync(directory, { withFileTypes: true })) { + const name = path.posix.join(prefix, entry.name); + if (entry.isDirectory()) captureFiles(path.join(directory, entry.name), name); + else payloadCargoHome[relative(path.join(directory, entry.name))] = name; + } + }; + captureFiles(registryDirectory); + for (const row of heldPayloads) + payloadCargoHome[relative(row.file)] = + `cache/${payloadContext.repository}/${row.name}-${row.version}.crate`; + const payloadRow = (row: typeof query) => ({ + product: 'runtime', + version: row.version, + artifact: + row.name === payloadNames[5] + ? `github-release:${row.name}-${row.version}.crate` + : `cargo:${row.name}`, + file: { path: relative(row.file), size: readFileSync(row.file).length, sha256: row.sha256 }, + }); + const payloadSdk = async (version: string) => { + const source = await archive( + sdk.name, + '0.3.5', + { [query.name]: query.version, [payloadNames[0]]: `=${version}` }, + 'pub fn value() -> u32 { fixture_portable::stable() }\n', + ); + const tree = path.join(scratch, 'payload-root-' + version, source.name + '-' + source.version); + mkdirSync(path.join(tree, 'src'), { recursive: true }); + writeFileSync( + path.join(tree, 'src/lib.rs'), + 'pub fn value() -> u32 { fixture_portable::stable() }\n', + ); + const targets = [ + 'cfg(all(target_os = "linux", target_arch = "x86_64"))', + 'cfg(all(target_os = "linux", target_arch = "aarch64"))', + 'cfg(target_os = "macos")', + 'cfg(target_os = "windows")', + ]; + writeFileSync( + path.join(tree, 'Cargo.toml'), + renderCargoToml({ + ...source.manifest, + target: Object.fromEntries( + payloadNames + .slice(1, 5) + .map((name, index) => [ + targets[index], + { dependencies: { [name]: { version: `=${version}` } } }, + ]), + ), + }), + ); + const file = tree + '.crate'; + writeFileSync( + file, + canonicalGzipSync(await createDeterministicTar(tree, { keepParent: true })), + ); + return cargoCandidate(file); + }; + const heldRoot = await payloadSdk('2.1.0'), + currentRoot = await payloadSdk('2.2.0'); + const fixture = ( + completed: (typeof query)[], + actual: (typeof query)[], + selectedProducts: string[], + ) => ({ + lock: payloadLock, + index: payloadIndex, + cargoHome: payloadCargoHome, + payloadPool: { + completed: completed.map(payloadRow), + current: actual.map(payloadRow), + owners: Object.fromEntries( + payloadNames.slice(0, 5).map((name) => [name, { product: 'runtime', version: '2.2.0' }]), + ), + }, + sourceOwners: { + [sdk.name]: { product: 'sdk', version: currentRoot.version }, + [query.name]: { product: 'query', version: query.version }, + }, + selectedProducts, + }); + const heldCase = await qualify( + heldRoot, + query, + [query], + false, + true, + {}, + fixture(heldPayloads, currentPayloads, []), + ); + expect( + heldCase.ordinary.selectedCandidates + .filter((row: any) => payloadNames.includes(row.name)) + .every((row: any) => row.version === '2.1.0'), + ).toBe(true); + const publishedCase = await qualify( + currentRoot, + query, + [query], + false, + true, + {}, + fixture(currentPayloads, [], []), + ); + expect( + publishedCase.ordinary.selectedCandidates + .filter((row: any) => payloadNames.includes(row.name)) + .map((row: any) => row.name) + .sort(), + ).toEqual([payloadNames[0], payloadNames[1], payloadNames[5]].toSorted()); + const currentCase = await qualify( + currentRoot, + query, + [query], + true, + true, + {}, + fixture([], currentPayloads, ['sdk', 'runtime']), + ); + expect( + currentCase.floor.selectedCandidates.find((row: any) => row.name === payloadNames[0]).version, + ).toBe('2.2.0'); + await qualify( + currentRoot, + query, + [query], + false, + false, + {}, + { + ...fixture( + [], + currentPayloads.filter((row) => row.name !== payloadNames[4]), + ['sdk', 'runtime'], + ), + expectedError: /Missing actual exact payload archive: fixture-windows/, + }, + ); + await qualify( + currentRoot, + query, + [query], + false, + false, + {}, + { + ...fixture( + [], + currentPayloads.filter((row) => row.name !== payloadNames[5]), + ['sdk', 'runtime'], + ), + expectedError: /generate-lock failed/, + }, + ); +} + +test( + 'real offline Cargo distinguishes current path preparation, source tests and selected production floors', + qualifyOfflineCargoScenarios, + Number(process.env.TEST_TIMEOUT ?? 180) * 1_000, +); diff --git a/build_defs/languages/installed/wasix/query/Cargo.lock b/build_defs/languages/installed/wasix/query/Cargo.lock new file mode 100644 index 000000000..3132476fa --- /dev/null +++ b/build_defs/languages/installed/wasix/query/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "oliphaunt-query" +version = "0.1.1" diff --git a/build_defs/languages/installed/wasix/query/registry-index.json b/build_defs/languages/installed/wasix/query/registry-index.json new file mode 100644 index 000000000..356de848f --- /dev/null +++ b/build_defs/languages/installed/wasix/query/registry-index.json @@ -0,0 +1,9 @@ +{ + "schema": "oliphaunt-installed-cargo-fixture-v1", + "cargo": "1.93.1", + "repository": "index.crates.io-1949cf8c6b5b557f", + "target": "x86_64-unknown-linux-gnu", + "archives": [], + "config": {}, + "indexes": [] +} diff --git a/build_defs/languages/installed/wasix/sdk/Cargo.lock b/build_defs/languages/installed/wasix/sdk/Cargo.lock new file mode 100644 index 000000000..a8daf65c7 --- /dev/null +++ b/build_defs/languages/installed/wasix/sdk/Cargo.lock @@ -0,0 +1,4530 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +dependencies = [ + "gimli 0.32.3", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" +dependencies = [ + "memchr", +] + +[[package]] +name = "ambient-authority" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9d4ee0d472d1cd2e28c97dfa124b3d8d992e10eb0a035f33f5d12e3a177ba3b" + +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "any_ascii" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70033777eb8b5124a81a1889416543dddef2de240019b674c81285a2635a7e1e" + +[[package]] +name = "anyhow" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + +[[package]] +name = "async-trait" +version = "0.1.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "backtrace" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide 0.8.9", + "object 0.37.3", + "rustc-demangle", + "windows-link", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bincode" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" +dependencies = [ + "bincode_derive", + "serde", + "unty", +] + +[[package]] +name = "bincode_derive" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" +dependencies = [ + "virtue", +] + +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags 2.13.2", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex 1.3.0", + "syn 2.0.119", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" + +[[package]] +name = "blake3" +version = "1.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d9e454fc11f76977dc803893aff6304ed33d6a26efae8696573bea74baa27ae" +dependencies = [ + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "cpufeatures 0.3.1", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "bstr" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bb31b46c14244e20ee9984b11bf5c992b91fb6939fea616e3512c8baecdbe5f" +dependencies = [ + "memchr", + "serde_core", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "bus" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b7118d0221d84fada881b657c2ddb7cd55108db79c8764c9ee212c0c259b783" +dependencies = [ + "crossbeam-channel", + "num_cpus", + "parking_lot_core", +] + +[[package]] +name = "bytecheck" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26333eeac754f0ad8a6bcd0eb0ac012156302e4e16b852b72ee399aea4f12c29" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "rancor", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46d07918caa9eeaaf06b7873925c53a61daac173539b4f7715090745e44e4e69" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" +dependencies = [ + "serde", +] + +[[package]] +name = "bytesize" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7354288c522e7e980fafd2075d63d1285794c3a6a16cdd492f189ea406e5f18b" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cap-fs-ext" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ff379b70af8e08307a8f65e7040c7301cb4a572538ade16b4984f0da77847f" +dependencies = [ + "cap-primitives", + "cap-std", + "io-lifetimes 3.0.1", + "windows-sys 0.61.2", +] + +[[package]] +name = "cap-primitives" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b5f74729fd2f44701d1a8eb47e906cdb3ccd9ec0f02baad85a744b791940b18" +dependencies = [ + "ambient-authority", + "fs-set-times", + "io-extras", + "io-lifetimes 3.0.1", + "ipnet", + "maybe-owned", + "rustix", + "rustix-linux-procfs", + "windows-sys 0.61.2", + "winx", +] + +[[package]] +name = "cap-std" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ec78e242cfa2cfe276807ac2ecc00315a6c97786977414bcd1c3963b6c91b8" +dependencies = [ + "cap-primitives", + "io-extras", + "io-lifetimes 3.0.1", + "rustix", +] + +[[package]] +name = "cc" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6651c9ed80effdc7db0ff72512157f901af5e3549e341e24b1dd4887d836d838" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex 2.0.1", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom 7.1.3", +] + +[[package]] +name = "cfg-if" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" + +[[package]] +name = "chacha20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "rand_core 0.10.1", +] + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "num-traits", +] + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clang-sys" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "157a8ba7b480713b56f4c09fd13fc3e0a22a5dfab8097ba61cbc5feef950788a" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9c751b79415d4e559e3d1fcf128e09e720eb673a06d26cf6f392d37d75b66e0" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "clap_lex" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486" + +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] + +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + +[[package]] +name = "console" +version = "0.16.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e96a4956774c13c126a8b5af4daa79384f4d826534c95a02d76afb39e2ab64e3" +dependencies = [ + "encode_unicode", + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "cooked-waker" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f" + +[[package]] +name = "corosensei" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6886a0c0f263965933c438626e7179139a62b978a33aa18281cbf0cd5a975f34" +dependencies = [ + "autocfg", + "cfg-if", + "libc", + "scopeguard", + "windows-sys 0.59.0", +] + +[[package]] +name = "cpp_demangle" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2bb79cb74d735044c972aae58ed0aaa9a837e85b01106a54c39e42e97f62253" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01a7799fd6b852db0e61728dde9a204c423b44d689dbd432522543614b490e78" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98b0cc327b5bc766e7fda9c9260cc0fa81b43a8e240440422dff70788e3f9ef1" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e8bd762f7479489c70ed6c768ddca99d7296857de437a68dcb2a94365b3fae" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "ctutils" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03bb0e1cc970d482d121d9a1744999169b69a07470b3d644a7894e53fcaf4574" +dependencies = [ + "cmov", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core 0.20.11", + "darling_macro 0.20.11", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core 0.21.3", + "darling_macro 0.21.3", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.119", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core 0.20.11", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core 0.21.3", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "dashmap" +version = "6.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "uuid", +] + +[[package]] +name = "defmt" +version = "0.3.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad" +dependencies = [ + "defmt 1.1.1", +] + +[[package]] +name = "defmt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8" +dependencies = [ + "defmt-parser", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" + +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling 0.20.11", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn 2.0.119", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.119", + "unicode-xid", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common 0.1.7", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "const-oid", + "crypto-common 0.2.2", + "ctutils", +] + +[[package]] +name = "directories" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", +] + +[[package]] +name = "displaydoc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "either" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be" + +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "enum-iterator" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4549325971814bda7a44061bf3fe7e487d447cba01e4220a4b454d630d7a016" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "enumset" +version = "1.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccc5801fd11762e24d1e420d01d2ac518f2a2ca4329d4fbb6639f2412b6204e0" +dependencies = [ + "enumset_derive", +] + +[[package]] +name = "enumset_derive" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bd536557b58c682b217b8fb199afdff47cd3eff260623f19e77074eb073d63a" +dependencies = [ + "darling 0.21.3", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "escape8259" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f0d310082fd5de539d4f41601182241147498444a7695c520288a0cdbead6" + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + +[[package]] +name = "filetime" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759" +dependencies = [ + "cfg-if", + "libc", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484" + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "flate2" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb" +dependencies = [ + "crc32fast", + "miniz_oxide 0.9.1", + "zlib-rs", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs-set-times" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94e7099f6313ecacbe1256e8ff9d617b75d1bcb16a6fddef94866d225a01a14a" +dependencies = [ + "io-lifetimes 2.0.4", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "futures" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-executor" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" + +[[package]] +name = "futures-macro" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "futures-sink" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 5.3.0", + "wasip2", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 6.0.0", + "rand_core 0.10.1", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" + +[[package]] +name = "gimli" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7f043f89559805f8c7cacc432749b2fa0d0a0a9ee46ce47164ed5ba7f126c" +dependencies = [ + "fnv", + "hashbrown 0.16.1", + "indexmap", + "stable_deref_trait", +] + +[[package]] +name = "glob" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" + +[[package]] +name = "globset" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07c34a9410465b45bd9787443bc7370f37735bad04b0f0cd57ff1a3186c98988" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "foldhash 0.2.0", +] + +[[package]] +name = "heapless" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ba4bd83f9415b58b4ed8dc5714c76e626a105be4646c02630ad730ad3b5aa4" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest 0.11.3", +] + +[[package]] +name = "http" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "hybrid-array" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17" +dependencies = [ + "typenum", +] + +[[package]] +name = "icu_collections" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" + +[[package]] +name = "icu_properties" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" + +[[package]] +name = "icu_provider" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "ignore" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b69833ed729dc5aa7d19541d96d6cf8e9137194207a04916d658e43168402f" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata", + "same-file", + "walkdir", + "winapi-util", +] + +[[package]] +name = "indexmap" +version = "2.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", + "serde", + "serde_core", +] + +[[package]] +name = "insta" +version = "1.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67d3d2e287e4b86c10b3f3b641033d1f89b74bdb39d05f34952e2b9a6fe21cd" +dependencies = [ + "console", + "once_cell", + "regex", + "serde", + "similar", + "strip-ansi-escapes", + "tempfile", +] + +[[package]] +name = "io-extras" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20fd6de4ccfcc187e38bc21cfa543cb5a302cb86a8b114eb7f0bf0dc9f8ac00f" +dependencies = [ + "io-lifetimes 3.0.1", + "windows-sys 0.60.2", +] + +[[package]] +name = "io-lifetimes" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06432fb54d3be7964ecd3649233cddf80db2832f47fec34c01f65b3d9d774983" + +[[package]] +name = "io-lifetimes" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0fb0570afe1fed943c5c3d4102d5358592d8625fda6a0007fdbe65a92fba96" + +[[package]] +name = "ipnet" +version = "2.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791930b43c0d5973160d90a8f3894509f2b273430f5c5c73b668636d0287c5c0" + +[[package]] +name = "iprange" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37209be0ad225457e63814401415e748e2453a5297f9b637338f5fb8afa4ec00" +dependencies = [ + "ipnet", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b4baf93f58d4425749ca49a51c50ebab072c5df6994d08fed93541c331481dc" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jobserver" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" +dependencies = [ + "getrandom 0.4.3", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7883d941dae510fb2d978fc3fe018c71c9e2892fd38854de3e8b92c2e5ad9cc5" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "leb128" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c83bff1d572d6b9aeef67ddfc8448e4a3737909cb28e81f97c791b9018703e52" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "lexical-sort" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c09e4591611e231daf4d4c685a66cb0410cc1e502027a20ae55f2bb9e997207a" +dependencies = [ + "any_ascii", +] + +[[package]] +name = "libc" +version = "0.2.190" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "liboliphaunt-wasix-aot-aarch64-apple-darwin" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835ede81ff81dcfb2767878209a1c372b7e3338c401595cf179aa68e1f1cc0c7" +dependencies = [ + "serde_json", + "sha2 0.10.9", +] + +[[package]] +name = "liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b15cb79e689f5f0eab69f5acd92f68f61ae57d9f3bfa4cc18658a6d1bb67ad" +dependencies = [ + "serde_json", + "sha2 0.10.9", +] + +[[package]] +name = "liboliphaunt-wasix-aot-x86_64-pc-windows-msvc" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c7a811a634a1b0d686369cbaefa8dabbfe5825fc4a03140ddda7beb3343bd30" +dependencies = [ + "serde_json", + "sha2 0.10.9", +] + +[[package]] +name = "liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e56a349c5c888ad65a623cbce954e13ae6dcead6ea846fc63202158f815976d" +dependencies = [ + "serde_json", + "sha2 0.10.9", +] + +[[package]] +name = "liboliphaunt-wasix-portable" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ebe15bd97751ed6c63ae25067c6a92a2266fa861d295d9d45844260acba30b" +dependencies = [ + "oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "oliphaunt-extension-contrib-pg18-aot-linux-x64", + "oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "oliphaunt-extension-contrib-pg18-aot-windows-x64", + "oliphaunt-extension-contrib-pg18-wasix", + "serde", + "serde_json", + "sha2 0.10.9", +] + +[[package]] +name = "libredox" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ff90caf6077a803a240f62fdbe88645a890bbca49ef8174c3cb0404362171d" +dependencies = [ + "libc", +] + +[[package]] +name = "libtest-mimic" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14e6ba06f0ade6e504aff834d7c34298e5155c6baca353cc6a4aaff2f9fd7f33" +dependencies = [ + "anstream", + "anstyle", + "clap", + "escape8259", +] + +[[package]] +name = "libunwind" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6639b70a7ce854b79c70d7e83f16b5dc0137cc914f3d7d03803b513ecc67ac" + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linked_hash_set" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "984fb35d06508d1e69fc91050cceba9c0b748f983e6739fa2c7a9237154c52c8" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" + +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" + +[[package]] +name = "lz4_flex" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef0d4ed8669f8f8826eb00dc878084aa8f253506c4fd5e8f58f5bce72ddb97e" +dependencies = [ + "twox-hash", +] + +[[package]] +name = "mach2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" +dependencies = [ + "libc", +] + +[[package]] +name = "mach2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b" + +[[package]] +name = "macho-unwind-info" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149" +dependencies = [ + "thiserror", + "zerocopy", + "zerocopy-derive", +] + +[[package]] +name = "managed" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" + +[[package]] +name = "maybe-owned" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4" + +[[package]] +name = "md-5" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98" +dependencies = [ + "cfg-if", + "digest 0.11.3", +] + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "memmap2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d28bba84adfe6646737845bc5ebbfa2c08424eb1c37e94a1fd2a82adb56a872" +dependencies = [ + "libc", +] + +[[package]] +name = "memmap2" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "miniz_oxide" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1788edb87fdc09c7e26304471e2f5be8cdefb1b6930d6e3985fc02ff53bf86ee" +dependencies = [ + "libc", + "log", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.61.2", +] + +[[package]] +name = "more-asserts" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e" + +[[package]] +name = "munge" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c" +dependencies = [ + "munge_macro", +] + +[[package]] +name = "munge_macro" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "nom" +version = "5.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b" +dependencies = [ + "memchr", + "version_check", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.13.2", +] + +[[package]] +name = "objc2-system-configuration" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7216bd11cbda54ccabcab84d523dc93b858ec75ecfb3a7d89513fa22464da396" +dependencies = [ + "objc2-core-foundation", +] + +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "object" +version = "0.39.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b" +dependencies = [ + "crc32fast", + "flate2", + "hashbrown 0.17.1", + "indexmap", + "memchr", + "ruzstd", +] + +[[package]] +name = "oliphaunt-extension-contrib-pg18-aot-linux-arm64" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6593cd36d8c9cb83d2098ef5f62005bb62861f05bcd3d7238f5bcccbc11cdfd3" +dependencies = [ + "sha2 0.10.9", +] + +[[package]] +name = "oliphaunt-extension-contrib-pg18-aot-linux-x64" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "238580b3fed00f8537e64c1c6548d74d33b544a322946879a8821eed7f4dc792" +dependencies = [ + "sha2 0.10.9", +] + +[[package]] +name = "oliphaunt-extension-contrib-pg18-aot-macos-arm64" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41bef2ac428e3b7f2149d1c342135c573a9dbd9c592eebaea3e0083f3840c64c" +dependencies = [ + "sha2 0.10.9", +] + +[[package]] +name = "oliphaunt-extension-contrib-pg18-aot-windows-x64" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "623d461eda99618bda616e1f488160d0fa6833215676f73dc0c134a29c283cbd" +dependencies = [ + "sha2 0.10.9", +] + +[[package]] +name = "oliphaunt-extension-contrib-pg18-wasix" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2cbf8c683ae8b380f11f4fa7581c41eddb370ab4d94cbba07d169c2ab7778" +dependencies = [ + "sha2 0.10.9", +] + +[[package]] +name = "oliphaunt-icu" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976fdebc00bbd4dc456e3e77dafb51886798048b648ed3f8b5f22aac8c83a587" +dependencies = [ + "sha2 0.10.9", + "tar", + "zstd", +] + +[[package]] +name = "oliphaunt-query" +version = "0.1.1" + +[[package]] +name = "oliphaunt-wasix" +version = "0.3.2" +dependencies = [ + "anyhow", + "async-trait", + "cap-fs-ext", + "cap-std", + "directories", + "dunce", + "filetime", + "flate2", + "liboliphaunt-wasix-aot-aarch64-apple-darwin", + "liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu", + "liboliphaunt-wasix-aot-x86_64-pc-windows-msvc", + "liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu", + "liboliphaunt-wasix-portable", + "oliphaunt-icu", + "oliphaunt-query", + "oliphaunt-wasix-tools", + "oliphaunt-wasix-tools-aot-aarch64-apple-darwin", + "oliphaunt-wasix-tools-aot-aarch64-unknown-linux-gnu", + "oliphaunt-wasix-tools-aot-x86_64-pc-windows-msvc", + "oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu", + "serde", + "serde_json", + "sha2 0.10.9", + "tar", + "tempfile", + "tokio", + "tokio-postgres", + "tracing", + "virtual-fs", + "virtual-mio", + "virtual-net", + "wasmer", + "wasmer-config", + "wasmer-journal", + "wasmer-package", + "wasmer-types", + "wasmer-wasix", + "wasmer-wasix-types", + "webc", + "zstd", +] + +[[package]] +name = "oliphaunt-wasix-tools" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad5adaffe18ccfb26925aee55537a958d5830e0b5c1d6b6b2431c0ae29b09740" +dependencies = [ + "sha2 0.10.9", +] + +[[package]] +name = "oliphaunt-wasix-tools-aot-aarch64-apple-darwin" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a83f654e0e336cdba6fc1b91d272bdb4c252ff2724a82bd0518ec1ba340b7caf" +dependencies = [ + "serde_json", + "sha2 0.10.9", +] + +[[package]] +name = "oliphaunt-wasix-tools-aot-aarch64-unknown-linux-gnu" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e701ccd439ec0518c48b5917cabc75eaca8bf6b47300ee2c858a5f1fb7912e0" +dependencies = [ + "serde_json", + "sha2 0.10.9", +] + +[[package]] +name = "oliphaunt-wasix-tools-aot-x86_64-pc-windows-msvc" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626152e61e5053921a70b2825e126609905f18cef80c638047c781a3485c393f" +dependencies = [ + "serde_json", + "sha2 0.10.9", +] + +[[package]] +name = "oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be53dc59e580e430294ad933e6f7551ec707211e0d4a352aedff542bbb66c61" +dependencies = [ + "serde_json", + "sha2 0.10.9", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "path-clean" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "petgraph" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" +dependencies = [ + "fixedbitset", + "hashbrown 0.15.5", + "indexmap", + "serde", +] + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_shared", + "serde", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pin-utils" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13bee6c73da26345c729282832b60b0363cf3dd9f4bfd81d8551b7a1c889a113" + +[[package]] +name = "pkg-config" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" + +[[package]] +name = "postgres-protocol" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08808e3c483c46e999108051c78334f473d5adb59d78bb80a1268c7e6aa6c514" +dependencies = [ + "base64", + "byteorder", + "bytes", + "fallible-iterator", + "hmac", + "md-5", + "memchr", + "rand 0.10.3", + "sha2 0.11.0", + "stringprep", +] + +[[package]] +name = "postgres-types" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "851ca9db4932932d69f3ea811b1abe63087a0f740a47692619dd40d4899b68be" +dependencies = [ + "bytes", + "fallible-iterator", + "postgres-protocol", +] + +[[package]] +name = "potential_utf" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a6394b9e965e73d0a289ee54f589087e2c676aedf60885baf52c76b771e4958" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.119", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "ptr_meta" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743da816b98c921cdbe8628ef7381b76f25ecf4da599fc80aca90eae7ef70cc0" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c8d9ca532f185d5d4db7a7c9d51420b452168ea1c2b913953281bd6fe1fcbd0" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "pulldown-cmark" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8" +dependencies = [ + "bitflags 1.3.2", + "memchr", + "unicase", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rancor" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b534442d0fcdb55d66f373d9cac6d33b6293a2335bc2136dbd06ce0e87d2572" +dependencies = [ + "ptr_meta", +] + +[[package]] +name = "rand" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" +dependencies = [ + "rand_chacha", + "rand_core 0.9.5", +] + +[[package]] +name = "rand" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rangemap" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a611d15b50743feb4c76b7d03edcb0e64f399c26961e4efe6975bc398be6aa3d" + +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.13.2", +] + +[[package]] +name = "redox_users" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60dc65c0ff1a7ae1294b0c67b9f14baf70b644404010370171787bfac1038fc0" +dependencies = [ + "libredox", + "thiserror", +] + +[[package]] +name = "ref-cast" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "regex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "region" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7" +dependencies = [ + "bitflags 1.3.2", + "libc", + "mach2 0.4.3", + "windows-sys 0.52.0", +] + +[[package]] +name = "rend" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "663ba70707f96e871406fe10d68128412e619b06d1d47cb91c3a4c6501176240" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "replace_with" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51743d3e274e2b18df81c4dc6caf8a5b8e15dbe799e0dca05c7617380094e884" + +[[package]] +name = "rkyv" +version = "0.8.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9776093b7ca170454ab1406954f7b7d97a57c51dc6c0642957fb2ef25c2d399" +dependencies = [ + "bytecheck", + "bytes", + "hashbrown 0.17.1", + "indexmap", + "munge", + "ptr_meta", + "rancor", + "rend", + "rkyv_derive", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.8.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c25ef604ac7dd839d44d64648952ea23c97866f124ff671b0ed2cf3ad9bb06e" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb" + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d" +dependencies = [ + "bitflags 2.13.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustix-linux-procfs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc84bf7e9aa16c4f2c758f27412dc9841341e16aa682d9c7ac308fe3ee12056" +dependencies = [ + "once_cell", + "rustix", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "rusty_pool" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ed36cdb20de66d89a17ea04b8883fc7a386f2cf877aaedca5005583ce4876ff" +dependencies = [ + "crossbeam-channel", + "futures", + "futures-channel", + "futures-executor", + "num_cpus", +] + +[[package]] +name = "ruzstd" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7c1c839d570d835527c9a5e4db7cb2198683a988cb9d7293fc8674e6bd58fc8" +dependencies = [ + "twox-hash", +] + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "saffron" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03fb9a628596fc7590eb7edbf7b0613287be78df107f5f97b118aad59fb2eea9" +dependencies = [ + "chrono", + "nom 5.1.3", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schemars" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a" +dependencies = [ + "dyn-clone", + "indexmap", + "ref-cast", + "schemars_derive", + "serde", + "serde_json", + "url", +] + +[[package]] +name = "schemars_derive" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98c67716b46af2f0b8cf752abc930f6f9aecfbf671ecfb531db8a31dbe4e2ba" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 3.0.8", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "self_cell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab42ca02749e120097e328d91d415325bdf43b1c72c4c8badf37375fe40a813" + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "serde_derive_internals" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f852137cce035d6a4df67ccce505ff6b3e9fd3a10e3e52b24dc71e650bb1a9bd" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7523beb55eece201a2356bee0bbca0d1ab466c14c07703b2e0ee6d42cb0c2c" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "digest 0.11.3", +] + +[[package]] +name = "shared-buffer" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6c99835bad52957e7aa241d3975ed17c1e5f8c92026377d117a606f36b84b16" +dependencies = [ + "bytes", + "memmap2 0.6.2", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "simd-adler32" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "similar" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" + +[[package]] +name = "siphasher" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33f4fe9184a62d842c9ef383018f3306d8ba224fd9d836f56d7288308847c256" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b3dc8af474f516a851ff4bd12db780f948b9250ad37211e4eec0bccea54e01b" + +[[package]] +name = "smoltcp" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f73d40463bba65efc9adc6370b56df76d563cc46e2482bba58351b4afb7535e" +dependencies = [ + "bitflags 1.3.2", + "byteorder", + "cfg-if", + "defmt 0.3.100", + "heapless", + "managed", +] + +[[package]] +name = "socket2" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[package]] +name = "strip-ansi-escapes" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a8f8038e7e7969abb3f1b7c2a811225e9296da208539e0f79c5251d6cac0025" +dependencies = [ + "vte", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "symbolic-common" +version = "13.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfa0014ff4e423a1bb8881453c7a29181eb14fe1dbc8e0197ebfa081903f3ed" +dependencies = [ + "debugid", + "memmap2 0.9.11", + "stable_deref_trait", + "uuid", +] + +[[package]] +name = "symbolic-demangle" +version = "13.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a213276280a1a737ff5fb89ae2a70ba51d1d4608e74736beb92f257f125f1aa" +dependencies = [ + "bitflags 2.13.2", + "cpp_demangle", + "itoa", + "rustc-demangle", + "symbolic-common", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01016da373cd8f7ef12624f796309f5c31ba8d646dd08856c02cd741d823c622" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "tar" +version = "0.4.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "target-lexicon" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.3", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "terminal_size" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" +dependencies = [ + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "termios" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b" +dependencies = [ + "libc", +] + +[[package]] +name = "thiserror" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "time" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + +[[package]] +name = "time-macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" + +[[package]] +name = "tokio" +version = "1.53.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e95f91fcc7a621e8b030f6aa23c71fe9838ae2fb4d8118b75602a328f5144044" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "tokio-postgres" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a528f7d280f6d5b9cd149635c8705b0dd049754bc67d81d31fa25169a93809d3" +dependencies = [ + "async-trait", + "byteorder", + "bytes", + "fallible-iterator", + "futures-channel", + "futures-util", + "log", + "parking_lot", + "percent-encoding", + "phf", + "pin-project-lite", + "postgres-protocol", + "postgres-types", + "rand 0.10.3", + "socket2", + "tokio", + "tokio-util", + "whoami", +] + +[[package]] +name = "tokio-stream" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d06f0b082ba57c26b79407372e57cf2a1e28124f78e9479fe80322cf53420b" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-util" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e464cf451ba96ebfc6f9b6542f17ee8b8956e33f1e40d9690624e59d7a7f8a4b" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "libc", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "1.1.8+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20489e00e4d8741d6be680764cc12e270655e375a20d1011e844a9c3379e678d" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b86d767906c6c42421dcba507eb9d203e779497710a47782a224bb871653053" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.17+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3641d5bbb5349a79e1020a242d251efbc546ad8048d133958323ce9c40a9c9c" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.1.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baa693a8032d7e1cada7d0041e96126df243179ff061456783ac7f12bda4744c" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.1.3+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06bdbd8cfc056b8d2e2e85f29b56a3bdbecb527cef81eb39e3e7b98af4652770" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "twox-hash" +version = "2.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86a801b3cea342a06d468c8710662aa29e5e05e4f5c0d62f00bbb7f2ad7941c2" + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicase" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357cc3acc6a036009fd6c973ed009037c732d60d0b4f6c673e9041497482a28f" + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-ident" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" + +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", + "serde_derive", +] + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cc1186384beb7dd8eedea376413fd654937285ea6c9cfbb928dc3043ea4b606" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "virtual-fs" +version = "0.702.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18f2136946b8a66d2bc7548fc4396c72e7a8671e8ab878342f5483e6c6dfd61f" +dependencies = [ + "anyhow", + "async-trait", + "bytes", + "dashmap", + "derive_more", + "dunce", + "futures", + "getrandom 0.4.3", + "indexmap", + "pin-project-lite", + "replace_with", + "shared-buffer", + "slab", + "thiserror", + "tokio", + "tracing", + "virtual-mio", + "wasmer-package", + "webc", +] + +[[package]] +name = "virtual-mio" +version = "0.702.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b449ceba2087fe0a7e436b9f1105dd9868addb294ff96a4a28100eadb9442b15" +dependencies = [ + "async-trait", + "bytes", + "futures", + "mio", + "parking", + "serde", + "socket2", + "thiserror", + "tracing", +] + +[[package]] +name = "virtual-net" +version = "0.702.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb377443085e3e30d0e3357a8d55925da670d070a04c9dd2284236a20cf308f1" +dependencies = [ + "anyhow", + "async-trait", + "base64", + "bincode", + "bytecheck", + "bytes", + "derive_more", + "futures-util", + "ipnet", + "iprange", + "libc", + "mio", + "pin-project-lite", + "rkyv", + "serde", + "smoltcp", + "socket2", + "thiserror", + "tokio", + "tracing", + "virtual-mio", +] + +[[package]] +name = "virtue" +version = "0.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" + +[[package]] +name = "vte" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "231fdcd7ef3037e8330d8e17e61011a2c244126acc0a982f4040ac3f9f0bc077" +dependencies = [ + "memchr", +] + +[[package]] +name = "wai-bindgen-gen-core" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa3dc41b510811122b3088197234c27e08fcad63ef936306dd8e11e2803876c" +dependencies = [ + "anyhow", + "wai-parser", +] + +[[package]] +name = "wai-bindgen-gen-rust" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19bc05e8380515c4337c40ef03b2ff233e391315b178a320de8640703d522efe" +dependencies = [ + "heck 0.3.3", + "wai-bindgen-gen-core", +] + +[[package]] +name = "wai-bindgen-gen-rust-wasm" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f35ce5e74086fac87f3a7bd50f643f00fe3559adb75c88521ecaa01c8a6199" +dependencies = [ + "heck 0.3.3", + "wai-bindgen-gen-core", + "wai-bindgen-gen-rust", +] + +[[package]] +name = "wai-bindgen-rust" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e5601c6f448c063e83a5e931b8fefcdf7e01ada424ad42372c948d2e3d67741" +dependencies = [ + "bitflags 1.3.2", + "wai-bindgen-rust-impl", +] + +[[package]] +name = "wai-bindgen-rust-impl" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdeeb5c1170246de8425a3e123e7ef260dc05ba2b522a1d369fe2315376efea4" +dependencies = [ + "proc-macro2", + "syn 1.0.109", + "wai-bindgen-gen-core", + "wai-bindgen-gen-rust-wasm", +] + +[[package]] +name = "wai-parser" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd0acb6d70885ea0c343749019ba74f015f64a9d30542e66db69b49b7e28186" +dependencies = [ + "anyhow", + "id-arena", + "pulldown-cmark", + "unicode-normalization", + "unicode-xid", +] + +[[package]] +name = "waker-fn" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasite" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fe902b4a6b8028a753d5424909b764ccf79b7a209eac9bf97e59cda9f71a42" +dependencies = [ + "wasi 0.14.7+wasi-0.2.4", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb54f33acc68fd454578d9820b0bde1a1a3d17aa17bb7b6595806d02886d409" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e29d0c35b16e224a7eeb5cd2d25e3e1968fbd65604117b44d3b789d00ee8535" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f501a8bc3719dba86ef8ae4728879c08001bea749eb1333ac5b91e040e2a6b7" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 3.0.8", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23f0c9c52aa7cd7d77769a4cfe2a9adb1b331f489a41d912ce14513d5ab995c6" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.252.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8185ae345fa5687c054626ff9a50e7089797a343d9904d1dc9820eb4c4d3196f" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasmer" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05af716b1bf3de5b8081133223f77f37916e9b4f41e0781c7fbe3e0d7b6da43a" +dependencies = [ + "bindgen", + "bytes", + "cfg-if", + "cmake", + "corosensei", + "dashmap", + "derive_more", + "futures", + "indexmap", + "itertools 0.15.0", + "js-sys", + "more-asserts", + "paste", + "rkyv", + "serde", + "serde-wasm-bindgen", + "shared-buffer", + "symbolic-demangle", + "tar", + "target-lexicon", + "thiserror", + "tracing", + "wasm-bindgen", + "wasmer-compiler", + "wasmer-derive", + "wasmer-types", + "wasmer-vm", + "windows-sys 0.61.2", +] + +[[package]] +name = "wasmer-compiler" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d984ed2ecd52a8e68ea0f4959bc342bf3b2381262105898a8cb416ecd15003" +dependencies = [ + "backtrace", + "bytes", + "cfg-if", + "crossbeam-channel", + "enum-iterator", + "enumset", + "itertools 0.15.0", + "leb128", + "libc", + "macho-unwind-info", + "memmap2 0.9.11", + "more-asserts", + "object 0.39.1", + "rangemap", + "rayon", + "region", + "rkyv", + "self_cell", + "shared-buffer", + "smallvec", + "target-lexicon", + "tempfile", + "thiserror", + "wasmer-types", + "wasmer-vm", + "wasmparser", + "which", + "windows-sys 0.61.2", +] + +[[package]] +name = "wasmer-config" +version = "0.702.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98700e4516eb825f1ad22cd5273bafd0694941722686010dc1af79b70812393f" +dependencies = [ + "anyhow", + "bytesize", + "ciborium", + "derive_builder", + "hex", + "indexmap", + "saffron", + "schemars", + "semver", + "serde", + "serde_json", + "serde_yaml", + "thiserror", + "toml", + "url", +] + +[[package]] +name = "wasmer-derive" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882cc3b1909d543b4c5cd84c21d659c9c3608225240a79b68e39554749592b79" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "wasmer-journal" +version = "0.702.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d02acd34af8c89ce772dd492da754dc999d4e3d3f30cbbf11a9c58f5e6c3a659" +dependencies = [ + "anyhow", + "async-trait", + "base64", + "bincode", + "bytecheck", + "bytes", + "derive_more", + "lz4_flex", + "num_enum", + "rkyv", + "serde", + "serde_json", + "thiserror", + "tracing", + "virtual-fs", + "virtual-net", + "wasmer", + "wasmer-config", + "wasmer-wasix-types", +] + +[[package]] +name = "wasmer-package" +version = "0.702.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54f12fd1711df6b12ade23b5db433d3f1aae4f31a7580d7db480f2cce03ccdb1" +dependencies = [ + "anyhow", + "bytes", + "cfg-if", + "ciborium", + "flate2", + "ignore", + "insta", + "libc", + "semver", + "serde", + "serde_json", + "sha2 0.11.0", + "shared-buffer", + "tar", + "tempfile", + "thiserror", + "toml", + "url", + "wasmer-config", + "wasmer-types", + "webc", +] + +[[package]] +name = "wasmer-types" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87234e5a975dc1343c08692165e01def9725a74cf527277c0e36b0eb66b8f427" +dependencies = [ + "bytecheck", + "crc32fast", + "enum-iterator", + "enumset", + "getrandom 0.4.3", + "hex", + "indexmap", + "itertools 0.15.0", + "more-asserts", + "rkyv", + "serde", + "sha2 0.11.0", + "target-lexicon", + "thiserror", + "wasmparser", +] + +[[package]] +name = "wasmer-vm" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8112dae928ca0d5341180e1ea1418d78bdb3788a78da625a4a3889fe908a91bb" +dependencies = [ + "backtrace", + "bytesize", + "cc", + "cfg-if", + "corosensei", + "crossbeam-queue", + "dashmap", + "enum-iterator", + "fnv", + "gimli 0.33.0", + "indexmap", + "itertools 0.15.0", + "libc", + "libunwind", + "mach2 0.6.0", + "memoffset", + "more-asserts", + "parking_lot", + "region", + "rustversion", + "scopeguard", + "thiserror", + "wasmer-types", + "windows-sys 0.61.2", +] + +[[package]] +name = "wasmer-wasix" +version = "0.702.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90a93bb66bc9bb1c766d53c68676f8a4f23582b0feef6135c184dfd3bf762e2e" +dependencies = [ + "anyhow", + "async-trait", + "base64", + "bincode", + "blake3", + "bus", + "bytecheck", + "bytes", + "cfg-if", + "cooked-waker", + "crossbeam-channel", + "dashmap", + "derive_more", + "flate2", + "fnv", + "fs_extra", + "futures", + "getrandom 0.3.4", + "getrandom 0.4.3", + "heapless", + "hex", + "http", + "itertools 0.15.0", + "libc", + "libtest-mimic", + "linked_hash_set", + "lz4_flex", + "num_enum", + "once_cell", + "petgraph", + "pin-project", + "pin-utils", + "rand 0.10.3", + "rkyv", + "rusty_pool", + "semver", + "serde", + "serde_derive", + "serde_json", + "serde_yaml", + "sha2 0.11.0", + "shared-buffer", + "tempfile", + "terminal_size", + "termios", + "thiserror", + "tokio", + "tokio-stream", + "toml", + "tracing", + "url", + "urlencoding", + "virtual-fs", + "virtual-mio", + "virtual-net", + "waker-fn", + "walkdir", + "wasm-encoder", + "wasmer", + "wasmer-config", + "wasmer-journal", + "wasmer-package", + "wasmer-types", + "wasmer-wasix-types", + "wasmparser", + "webc", + "weezl", + "windows-sys 0.61.2", + "xxhash-rust", + "zstd", +] + +[[package]] +name = "wasmer-wasix-types" +version = "0.702.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f982c57b8ccfcb6bc6f7d7ba420bf53a2099ea9c77135b45cdf45198a00c90db" +dependencies = [ + "anyhow", + "bitflags 2.13.2", + "byteorder", + "cfg-if", + "num_enum", + "serde", + "time", + "tracing", + "wai-bindgen-gen-core", + "wai-bindgen-gen-rust", + "wai-bindgen-gen-rust-wasm", + "wai-bindgen-rust", + "wai-parser", + "wasmer", + "wasmer-derive", + "wasmer-types", +] + +[[package]] +name = "wasmparser" +version = "0.252.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3eb099dcadcde5be9eef55e3a337128efd4e44b4c93122487e4d2e4e1c6627c" +dependencies = [ + "bitflags 2.13.2", + "indexmap", +] + +[[package]] +name = "web-sys" +version = "0.3.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88261b9deccee56594c11a3460c462c41f58d148598fe70ad77070126a68aba4" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webc" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cb48ee4bc7a902c0f1d9eb0c0656f0e78149f1190b7f78e1f28256e88279a84" +dependencies = [ + "anyhow", + "base64", + "bytes", + "cfg-if", + "ciborium", + "document-features", + "ignore", + "indexmap", + "leb128", + "lexical-sort", + "libc", + "once_cell", + "path-clean", + "rand 0.9.5", + "serde", + "serde_json", + "sha2 0.10.9", + "shared-buffer", + "thiserror", + "url", +] + +[[package]] +name = "weezl" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4ca08e5ef825b65b056d9efbd95c8750683f0a6d0466d02e96dc2e4e360f3d2" + +[[package]] +name = "which" +version = "8.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bae2f2b2b816647a1cab1acc91f5bd20812d53cb344382635ec2181940c8034f" +dependencies = [ + "libc", +] + +[[package]] +name = "whoami" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626c4bac6755d76ffc12cb01b2eac751db1996b9e0041de9aa02c8c211ddc82c" +dependencies = [ + "libc", + "libredox", + "objc2-system-configuration", + "wasite", + "web-sys", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" +dependencies = [ + "memchr", +] + +[[package]] +name = "winx" +version = "0.36.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f3fd376f71958b862e7afb20cfe5a22830e1963462f3a17f49d82a6c1d1f42d" +dependencies = [ + "bitflags 2.13.2", + "windows-sys 0.59.0", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "writeable" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" + +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + +[[package]] +name = "xxhash-rust" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "550a2b930b62486a393c52d5c3b84bff264b28aa437ed64694d31e93b1757af7" + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86502bf56ac7c77571a32e2647bb2a15894565e981fb2a48d7bde2d91c965a9d" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5457206954b06561e2608c7e19cf58b1926586d999c246eebe4502f7e2039d1a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "zlib-rs" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112" + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d80649ab6db9d9f6f9c80a40becd948eda4714a0a5ac8c4d157a32231c7882" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.1.1+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aeec9eaf2dffbbd09201e23bd0ffcbaa33bb8e9266a10734fd7ed90a85eca078" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/build_defs/languages/installed/wasix/sdk/registry-index.json b/build_defs/languages/installed/wasix/sdk/registry-index.json new file mode 100644 index 000000000..1b12dd7af --- /dev/null +++ b/build_defs/languages/installed/wasix/sdk/registry-index.json @@ -0,0 +1,39782 @@ +{ + "schema": "oliphaunt-installed-cargo-fixture-v1", + "cargo": "1.93.1", + "repository": "index.crates.io-1949cf8c6b5b557f", + "target": "x86_64-unknown-linux-gnu", + "archives": [ + { + "name": "addr2line", + "version": "0.25.1" + }, + { + "name": "adler2", + "version": "2.0.1" + }, + { + "name": "aho-corasick", + "version": "1.1.5" + }, + { + "name": "ambient-authority", + "version": "0.0.2" + }, + { + "name": "anstream", + "version": "1.0.0" + }, + { + "name": "anstyle-parse", + "version": "1.0.0" + }, + { + "name": "anstyle-query", + "version": "1.1.5" + }, + { + "name": "anstyle-wincon", + "version": "3.0.11" + }, + { + "name": "anstyle", + "version": "1.0.14" + }, + { + "name": "any_ascii", + "version": "0.1.7" + }, + { + "name": "anyhow", + "version": "1.0.104" + }, + { + "name": "arrayvec", + "version": "0.7.8" + }, + { + "name": "async-trait", + "version": "0.1.92" + }, + { + "name": "autocfg", + "version": "1.5.1" + }, + { + "name": "backtrace", + "version": "0.3.76" + }, + { + "name": "base64", + "version": "0.22.1" + }, + { + "name": "bincode_derive", + "version": "2.0.1" + }, + { + "name": "bincode", + "version": "2.0.1" + }, + { + "name": "bindgen", + "version": "0.72.1" + }, + { + "name": "bitflags", + "version": "1.3.2" + }, + { + "name": "bitflags", + "version": "2.13.2" + }, + { + "name": "blake3", + "version": "1.8.7" + }, + { + "name": "block-buffer", + "version": "0.10.4" + }, + { + "name": "block-buffer", + "version": "0.12.1" + }, + { + "name": "bstr", + "version": "1.13.1" + }, + { + "name": "bumpalo", + "version": "3.20.3" + }, + { + "name": "bus", + "version": "2.4.1" + }, + { + "name": "bytecheck_derive", + "version": "0.8.3" + }, + { + "name": "bytecheck", + "version": "0.8.3" + }, + { + "name": "byteorder", + "version": "1.5.0" + }, + { + "name": "bytes", + "version": "1.12.1" + }, + { + "name": "bytesize", + "version": "2.7.0" + }, + { + "name": "cap-fs-ext", + "version": "4.0.3" + }, + { + "name": "cap-primitives", + "version": "4.0.3" + }, + { + "name": "cap-std", + "version": "4.0.3" + }, + { + "name": "cc", + "version": "1.8.0" + }, + { + "name": "cexpr", + "version": "0.6.0" + }, + { + "name": "cfg-if", + "version": "1.0.5" + }, + { + "name": "chacha20", + "version": "0.10.2" + }, + { + "name": "chrono", + "version": "0.4.45" + }, + { + "name": "ciborium-io", + "version": "0.2.2" + }, + { + "name": "ciborium-ll", + "version": "0.2.2" + }, + { + "name": "ciborium", + "version": "0.2.2" + }, + { + "name": "clang-sys", + "version": "1.9.1" + }, + { + "name": "clap_builder", + "version": "4.6.7" + }, + { + "name": "clap_derive", + "version": "4.6.7" + }, + { + "name": "clap_lex", + "version": "1.1.1" + }, + { + "name": "clap", + "version": "4.6.7" + }, + { + "name": "cmake", + "version": "0.1.58" + }, + { + "name": "cmov", + "version": "0.5.4" + }, + { + "name": "colorchoice", + "version": "1.0.5" + }, + { + "name": "console", + "version": "0.16.6" + }, + { + "name": "const-oid", + "version": "0.10.2" + }, + { + "name": "constant_time_eq", + "version": "0.4.2" + }, + { + "name": "convert_case", + "version": "0.10.0" + }, + { + "name": "cooked-waker", + "version": "5.0.0" + }, + { + "name": "corosensei", + "version": "0.3.4" + }, + { + "name": "cpp_demangle", + "version": "0.4.5" + }, + { + "name": "cpufeatures", + "version": "0.2.17" + }, + { + "name": "cpufeatures", + "version": "0.3.1" + }, + { + "name": "crc32fast", + "version": "1.5.2" + }, + { + "name": "crossbeam-channel", + "version": "0.5.17" + }, + { + "name": "crossbeam-deque", + "version": "0.8.8" + }, + { + "name": "crossbeam-epoch", + "version": "0.9.21" + }, + { + "name": "crossbeam-queue", + "version": "0.3.14" + }, + { + "name": "crossbeam-utils", + "version": "0.8.23" + }, + { + "name": "crunchy", + "version": "0.2.4" + }, + { + "name": "crypto-common", + "version": "0.1.7" + }, + { + "name": "crypto-common", + "version": "0.2.2" + }, + { + "name": "ctutils", + "version": "0.4.3" + }, + { + "name": "darling_core", + "version": "0.20.11" + }, + { + "name": "darling_core", + "version": "0.21.3" + }, + { + "name": "darling_macro", + "version": "0.20.11" + }, + { + "name": "darling_macro", + "version": "0.21.3" + }, + { + "name": "darling", + "version": "0.20.11" + }, + { + "name": "darling", + "version": "0.21.3" + }, + { + "name": "dashmap", + "version": "6.2.1" + }, + { + "name": "debugid", + "version": "0.8.0" + }, + { + "name": "defmt-macros", + "version": "1.1.1" + }, + { + "name": "defmt-parser", + "version": "1.0.0" + }, + { + "name": "defmt", + "version": "0.3.100" + }, + { + "name": "defmt", + "version": "1.1.1" + }, + { + "name": "deranged", + "version": "0.5.8" + }, + { + "name": "derive_builder_core", + "version": "0.20.2" + }, + { + "name": "derive_builder_macro", + "version": "0.20.2" + }, + { + "name": "derive_builder", + "version": "0.20.2" + }, + { + "name": "derive_more-impl", + "version": "2.1.1" + }, + { + "name": "derive_more", + "version": "2.1.1" + }, + { + "name": "digest", + "version": "0.10.7" + }, + { + "name": "digest", + "version": "0.11.3" + }, + { + "name": "directories", + "version": "6.0.0" + }, + { + "name": "dirs-sys", + "version": "0.5.0" + }, + { + "name": "displaydoc", + "version": "0.2.7" + }, + { + "name": "document-features", + "version": "0.2.12" + }, + { + "name": "dunce", + "version": "1.0.5" + }, + { + "name": "dyn-clone", + "version": "1.0.20" + }, + { + "name": "either", + "version": "1.19.0" + }, + { + "name": "encode_unicode", + "version": "1.0.0" + }, + { + "name": "enum-iterator-derive", + "version": "1.5.0" + }, + { + "name": "enum-iterator", + "version": "2.3.0" + }, + { + "name": "enumset_derive", + "version": "0.15.0" + }, + { + "name": "enumset", + "version": "1.1.14" + }, + { + "name": "equivalent", + "version": "1.0.2" + }, + { + "name": "errno", + "version": "0.3.14" + }, + { + "name": "escape8259", + "version": "0.5.4" + }, + { + "name": "fallible-iterator", + "version": "0.2.0" + }, + { + "name": "fastrand", + "version": "2.5.0" + }, + { + "name": "filetime", + "version": "0.2.29" + }, + { + "name": "find-msvc-tools", + "version": "0.1.14" + }, + { + "name": "fixedbitset", + "version": "0.5.7" + }, + { + "name": "flate2", + "version": "1.1.10" + }, + { + "name": "fnv", + "version": "1.0.7" + }, + { + "name": "foldhash", + "version": "0.1.5" + }, + { + "name": "foldhash", + "version": "0.2.0" + }, + { + "name": "form_urlencoded", + "version": "1.2.2" + }, + { + "name": "fs_extra", + "version": "1.3.0" + }, + { + "name": "fs-set-times", + "version": "0.20.3" + }, + { + "name": "futures-channel", + "version": "0.3.34" + }, + { + "name": "futures-core", + "version": "0.3.34" + }, + { + "name": "futures-executor", + "version": "0.3.34" + }, + { + "name": "futures-io", + "version": "0.3.34" + }, + { + "name": "futures-macro", + "version": "0.3.34" + }, + { + "name": "futures-sink", + "version": "0.3.34" + }, + { + "name": "futures-task", + "version": "0.3.34" + }, + { + "name": "futures-util", + "version": "0.3.34" + }, + { + "name": "futures", + "version": "0.3.34" + }, + { + "name": "generic-array", + "version": "0.14.7" + }, + { + "name": "getrandom", + "version": "0.3.4" + }, + { + "name": "getrandom", + "version": "0.4.3" + }, + { + "name": "gimli", + "version": "0.32.3" + }, + { + "name": "gimli", + "version": "0.33.0" + }, + { + "name": "glob", + "version": "0.3.4" + }, + { + "name": "globset", + "version": "0.4.20" + }, + { + "name": "half", + "version": "2.7.1" + }, + { + "name": "hash32", + "version": "0.3.1" + }, + { + "name": "hashbrown", + "version": "0.14.5" + }, + { + "name": "hashbrown", + "version": "0.15.5" + }, + { + "name": "hashbrown", + "version": "0.16.1" + }, + { + "name": "hashbrown", + "version": "0.17.1" + }, + { + "name": "heapless", + "version": "0.9.3" + }, + { + "name": "heck", + "version": "0.3.3" + }, + { + "name": "heck", + "version": "0.5.0" + }, + { + "name": "hermit-abi", + "version": "0.5.3" + }, + { + "name": "hex", + "version": "0.4.3" + }, + { + "name": "hmac", + "version": "0.13.0" + }, + { + "name": "http", + "version": "1.5.0" + }, + { + "name": "hybrid-array", + "version": "0.4.15" + }, + { + "name": "icu_collections", + "version": "2.3.0" + }, + { + "name": "icu_locale_core", + "version": "2.3.0" + }, + { + "name": "icu_normalizer_data", + "version": "2.3.0" + }, + { + "name": "icu_normalizer", + "version": "2.3.0" + }, + { + "name": "icu_properties_data", + "version": "2.3.0" + }, + { + "name": "icu_properties", + "version": "2.3.0" + }, + { + "name": "icu_provider", + "version": "2.3.1" + }, + { + "name": "id-arena", + "version": "2.3.0" + }, + { + "name": "ident_case", + "version": "1.0.1" + }, + { + "name": "idna_adapter", + "version": "1.2.2" + }, + { + "name": "idna", + "version": "1.1.0" + }, + { + "name": "ignore", + "version": "0.4.33" + }, + { + "name": "indexmap", + "version": "2.14.2" + }, + { + "name": "insta", + "version": "1.49.0" + }, + { + "name": "io-extras", + "version": "0.19.0" + }, + { + "name": "io-lifetimes", + "version": "2.0.4" + }, + { + "name": "io-lifetimes", + "version": "3.0.1" + }, + { + "name": "ipnet", + "version": "2.12.2" + }, + { + "name": "iprange", + "version": "0.6.7" + }, + { + "name": "is_terminal_polyfill", + "version": "1.70.2" + }, + { + "name": "itertools", + "version": "0.13.0" + }, + { + "name": "itertools", + "version": "0.15.0" + }, + { + "name": "itoa", + "version": "1.0.18" + }, + { + "name": "jobserver", + "version": "0.1.35" + }, + { + "name": "js-sys", + "version": "0.3.106" + }, + { + "name": "leb128", + "version": "0.2.7" + }, + { + "name": "leb128fmt", + "version": "0.1.0" + }, + { + "name": "lexical-sort", + "version": "0.3.1" + }, + { + "name": "libc", + "version": "0.2.190" + }, + { + "name": "libloading", + "version": "0.8.9" + }, + { + "name": "liboliphaunt-wasix-aot-aarch64-apple-darwin", + "version": "0.3.2" + }, + { + "name": "liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu", + "version": "0.3.2" + }, + { + "name": "liboliphaunt-wasix-aot-x86_64-pc-windows-msvc", + "version": "0.3.2" + }, + { + "name": "liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu", + "version": "0.3.2" + }, + { + "name": "liboliphaunt-wasix-portable", + "version": "0.3.2" + }, + { + "name": "libredox", + "version": "0.1.25" + }, + { + "name": "libtest-mimic", + "version": "0.8.2" + }, + { + "name": "libunwind", + "version": "1.3.3" + }, + { + "name": "linked_hash_set", + "version": "0.1.6" + }, + { + "name": "linked-hash-map", + "version": "0.5.6" + }, + { + "name": "linux-raw-sys", + "version": "0.12.1" + }, + { + "name": "litemap", + "version": "0.8.3" + }, + { + "name": "litrs", + "version": "1.0.0" + }, + { + "name": "lock_api", + "version": "0.4.14" + }, + { + "name": "log", + "version": "0.4.34" + }, + { + "name": "lz4_flex", + "version": "0.13.1" + }, + { + "name": "mach2", + "version": "0.4.3" + }, + { + "name": "mach2", + "version": "0.6.0" + }, + { + "name": "macho-unwind-info", + "version": "0.5.0" + }, + { + "name": "managed", + "version": "0.8.0" + }, + { + "name": "maybe-owned", + "version": "0.3.4" + }, + { + "name": "md-5", + "version": "0.11.0" + }, + { + "name": "memchr", + "version": "2.8.3" + }, + { + "name": "memmap2", + "version": "0.6.2" + }, + { + "name": "memmap2", + "version": "0.9.11" + }, + { + "name": "memoffset", + "version": "0.9.1" + }, + { + "name": "minimal-lexical", + "version": "0.2.1" + }, + { + "name": "miniz_oxide", + "version": "0.8.9" + }, + { + "name": "miniz_oxide", + "version": "0.9.1" + }, + { + "name": "mio", + "version": "1.2.4" + }, + { + "name": "more-asserts", + "version": "0.3.1" + }, + { + "name": "munge_macro", + "version": "0.4.7" + }, + { + "name": "munge", + "version": "0.4.7" + }, + { + "name": "nom", + "version": "5.1.3" + }, + { + "name": "nom", + "version": "7.1.3" + }, + { + "name": "num_cpus", + "version": "1.17.0" + }, + { + "name": "num_enum_derive", + "version": "0.7.6" + }, + { + "name": "num_enum", + "version": "0.7.6" + }, + { + "name": "num-conv", + "version": "0.2.2" + }, + { + "name": "num-traits", + "version": "0.2.19" + }, + { + "name": "objc2-core-foundation", + "version": "0.3.2" + }, + { + "name": "objc2-system-configuration", + "version": "0.3.2" + }, + { + "name": "object", + "version": "0.37.3" + }, + { + "name": "object", + "version": "0.39.1" + }, + { + "name": "oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "version": "0.3.2" + }, + { + "name": "oliphaunt-extension-contrib-pg18-aot-linux-x64", + "version": "0.3.2" + }, + { + "name": "oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "version": "0.3.2" + }, + { + "name": "oliphaunt-extension-contrib-pg18-aot-windows-x64", + "version": "0.3.2" + }, + { + "name": "oliphaunt-extension-contrib-pg18-wasix", + "version": "0.3.2" + }, + { + "name": "oliphaunt-icu", + "version": "0.2.2" + }, + { + "name": "oliphaunt-wasix-tools-aot-aarch64-apple-darwin", + "version": "0.2.4" + }, + { + "name": "oliphaunt-wasix-tools-aot-aarch64-unknown-linux-gnu", + "version": "0.2.4" + }, + { + "name": "oliphaunt-wasix-tools-aot-x86_64-pc-windows-msvc", + "version": "0.2.4" + }, + { + "name": "oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu", + "version": "0.2.4" + }, + { + "name": "oliphaunt-wasix-tools", + "version": "0.2.4" + }, + { + "name": "once_cell_polyfill", + "version": "1.70.2" + }, + { + "name": "once_cell", + "version": "1.21.4" + }, + { + "name": "option-ext", + "version": "0.2.0" + }, + { + "name": "parking_lot_core", + "version": "0.9.12" + }, + { + "name": "parking_lot", + "version": "0.12.5" + }, + { + "name": "parking", + "version": "2.2.1" + }, + { + "name": "paste", + "version": "1.0.15" + }, + { + "name": "path-clean", + "version": "1.0.1" + }, + { + "name": "percent-encoding", + "version": "2.3.2" + }, + { + "name": "petgraph", + "version": "0.8.3" + }, + { + "name": "phf_shared", + "version": "0.13.1" + }, + { + "name": "phf", + "version": "0.13.1" + }, + { + "name": "pin-project-internal", + "version": "1.1.13" + }, + { + "name": "pin-project-lite", + "version": "0.2.17" + }, + { + "name": "pin-project", + "version": "1.1.13" + }, + { + "name": "pin-utils", + "version": "0.1.1" + }, + { + "name": "pkg-config", + "version": "0.3.34" + }, + { + "name": "postgres-protocol", + "version": "0.6.12" + }, + { + "name": "postgres-types", + "version": "0.2.14" + }, + { + "name": "potential_utf", + "version": "0.1.6" + }, + { + "name": "powerfmt", + "version": "0.2.1" + }, + { + "name": "ppv-lite86", + "version": "0.2.21" + }, + { + "name": "prettyplease", + "version": "0.2.37" + }, + { + "name": "proc-macro-crate", + "version": "3.5.0" + }, + { + "name": "proc-macro-error-attr2", + "version": "2.0.0" + }, + { + "name": "proc-macro-error2", + "version": "2.0.1" + }, + { + "name": "proc-macro2", + "version": "1.0.107" + }, + { + "name": "ptr_meta_derive", + "version": "0.3.2" + }, + { + "name": "ptr_meta", + "version": "0.3.2" + }, + { + "name": "pulldown-cmark", + "version": "0.8.0" + }, + { + "name": "quote", + "version": "1.0.47" + }, + { + "name": "r-efi", + "version": "5.3.0" + }, + { + "name": "r-efi", + "version": "6.0.0" + }, + { + "name": "rancor", + "version": "0.1.3" + }, + { + "name": "rand_chacha", + "version": "0.9.0" + }, + { + "name": "rand_core", + "version": "0.10.1" + }, + { + "name": "rand_core", + "version": "0.9.5" + }, + { + "name": "rand", + "version": "0.10.3" + }, + { + "name": "rand", + "version": "0.9.5" + }, + { + "name": "rangemap", + "version": "1.8.0" + }, + { + "name": "rayon-core", + "version": "1.13.0" + }, + { + "name": "rayon", + "version": "1.12.0" + }, + { + "name": "redox_syscall", + "version": "0.5.18" + }, + { + "name": "redox_users", + "version": "0.5.3" + }, + { + "name": "ref-cast-impl", + "version": "1.0.27" + }, + { + "name": "ref-cast", + "version": "1.0.27" + }, + { + "name": "regex-automata", + "version": "0.4.18" + }, + { + "name": "regex-syntax", + "version": "0.8.11" + }, + { + "name": "regex", + "version": "1.13.1" + }, + { + "name": "region", + "version": "3.0.2" + }, + { + "name": "rend", + "version": "0.5.4" + }, + { + "name": "replace_with", + "version": "0.1.8" + }, + { + "name": "rkyv_derive", + "version": "0.8.18" + }, + { + "name": "rkyv", + "version": "0.8.18" + }, + { + "name": "rustc_version", + "version": "0.4.1" + }, + { + "name": "rustc-demangle", + "version": "0.1.28" + }, + { + "name": "rustc-hash", + "version": "2.1.3" + }, + { + "name": "rustix-linux-procfs", + "version": "0.1.1" + }, + { + "name": "rustix", + "version": "1.1.5" + }, + { + "name": "rustversion", + "version": "1.0.23" + }, + { + "name": "rusty_pool", + "version": "0.7.0" + }, + { + "name": "ruzstd", + "version": "0.8.3" + }, + { + "name": "ryu", + "version": "1.0.23" + }, + { + "name": "saffron", + "version": "0.1.0" + }, + { + "name": "same-file", + "version": "1.0.6" + }, + { + "name": "schemars_derive", + "version": "1.2.2" + }, + { + "name": "schemars", + "version": "1.2.2" + }, + { + "name": "scopeguard", + "version": "1.2.0" + }, + { + "name": "self_cell", + "version": "1.3.0" + }, + { + "name": "semver", + "version": "1.0.28" + }, + { + "name": "serde_core", + "version": "1.0.229" + }, + { + "name": "serde_derive_internals", + "version": "0.30.0" + }, + { + "name": "serde_derive", + "version": "1.0.229" + }, + { + "name": "serde_json", + "version": "1.0.154" + }, + { + "name": "serde_spanned", + "version": "1.1.2" + }, + { + "name": "serde_yaml", + "version": "0.9.34+deprecated" + }, + { + "name": "serde-wasm-bindgen", + "version": "0.6.5" + }, + { + "name": "serde", + "version": "1.0.229" + }, + { + "name": "sha2", + "version": "0.10.9" + }, + { + "name": "sha2", + "version": "0.11.0" + }, + { + "name": "shared-buffer", + "version": "0.1.4" + }, + { + "name": "shlex", + "version": "1.3.0" + }, + { + "name": "shlex", + "version": "2.0.1" + }, + { + "name": "simd-adler32", + "version": "0.3.10" + }, + { + "name": "simdutf8", + "version": "0.1.5" + }, + { + "name": "similar", + "version": "2.7.0" + }, + { + "name": "siphasher", + "version": "1.0.4" + }, + { + "name": "slab", + "version": "0.4.12" + }, + { + "name": "smallvec", + "version": "1.16.3" + }, + { + "name": "smoltcp", + "version": "0.13.1" + }, + { + "name": "socket2", + "version": "0.6.5" + }, + { + "name": "stable_deref_trait", + "version": "1.2.1" + }, + { + "name": "stringprep", + "version": "0.1.5" + }, + { + "name": "strip-ansi-escapes", + "version": "0.2.1" + }, + { + "name": "strsim", + "version": "0.11.1" + }, + { + "name": "symbolic-common", + "version": "13.9.0" + }, + { + "name": "symbolic-demangle", + "version": "13.9.0" + }, + { + "name": "syn", + "version": "1.0.109" + }, + { + "name": "syn", + "version": "2.0.119" + }, + { + "name": "syn", + "version": "3.0.8" + }, + { + "name": "synstructure", + "version": "0.14.0" + }, + { + "name": "tar", + "version": "0.4.46" + }, + { + "name": "target-lexicon", + "version": "0.13.5" + }, + { + "name": "tempfile", + "version": "3.27.0" + }, + { + "name": "terminal_size", + "version": "0.4.4" + }, + { + "name": "termios", + "version": "0.3.3" + }, + { + "name": "thiserror-impl", + "version": "2.0.21" + }, + { + "name": "thiserror", + "version": "2.0.21" + }, + { + "name": "time-core", + "version": "0.1.9" + }, + { + "name": "time-macros", + "version": "0.2.32" + }, + { + "name": "time", + "version": "0.3.55" + }, + { + "name": "tinystr", + "version": "0.8.4" + }, + { + "name": "tinyvec", + "version": "1.13.3" + }, + { + "name": "tokio-macros", + "version": "2.7.2" + }, + { + "name": "tokio-postgres", + "version": "0.7.18" + }, + { + "name": "tokio-stream", + "version": "0.1.19" + }, + { + "name": "tokio-util", + "version": "0.7.20" + }, + { + "name": "tokio", + "version": "1.53.2" + }, + { + "name": "toml_datetime", + "version": "1.1.2+spec-1.1.0" + }, + { + "name": "toml_edit", + "version": "0.25.17+spec-1.1.0" + }, + { + "name": "toml_parser", + "version": "1.1.5+spec-1.1.0" + }, + { + "name": "toml_writer", + "version": "1.1.3+spec-1.1.0" + }, + { + "name": "toml", + "version": "1.1.8+spec-1.1.0" + }, + { + "name": "tracing-attributes", + "version": "0.1.31" + }, + { + "name": "tracing-core", + "version": "0.1.36" + }, + { + "name": "tracing", + "version": "0.1.44" + }, + { + "name": "twox-hash", + "version": "2.1.5" + }, + { + "name": "typenum", + "version": "1.20.1" + }, + { + "name": "unicase", + "version": "2.10.0" + }, + { + "name": "unicode-bidi", + "version": "0.3.18" + }, + { + "name": "unicode-ident", + "version": "1.0.26" + }, + { + "name": "unicode-normalization", + "version": "0.1.25" + }, + { + "name": "unicode-properties", + "version": "0.1.4" + }, + { + "name": "unicode-segmentation", + "version": "1.13.3" + }, + { + "name": "unicode-xid", + "version": "0.2.6" + }, + { + "name": "unsafe-libyaml", + "version": "0.2.11" + }, + { + "name": "unty", + "version": "0.0.4" + }, + { + "name": "url", + "version": "2.5.8" + }, + { + "name": "urlencoding", + "version": "2.1.3" + }, + { + "name": "utf8_iter", + "version": "1.0.4" + }, + { + "name": "utf8parse", + "version": "0.2.2" + }, + { + "name": "uuid", + "version": "1.28.0" + }, + { + "name": "version_check", + "version": "0.9.5" + }, + { + "name": "virtual-fs", + "version": "0.702.1" + }, + { + "name": "virtual-mio", + "version": "0.702.1" + }, + { + "name": "virtual-net", + "version": "0.702.1" + }, + { + "name": "virtue", + "version": "0.0.18" + }, + { + "name": "vte", + "version": "0.14.1" + }, + { + "name": "wai-bindgen-gen-core", + "version": "0.2.3" + }, + { + "name": "wai-bindgen-gen-rust-wasm", + "version": "0.2.3" + }, + { + "name": "wai-bindgen-gen-rust", + "version": "0.2.3" + }, + { + "name": "wai-bindgen-rust-impl", + "version": "0.2.3" + }, + { + "name": "wai-bindgen-rust", + "version": "0.2.3" + }, + { + "name": "wai-parser", + "version": "0.2.3" + }, + { + "name": "waker-fn", + "version": "1.2.0" + }, + { + "name": "walkdir", + "version": "2.5.0" + }, + { + "name": "wasi", + "version": "0.11.1+wasi-snapshot-preview1" + }, + { + "name": "wasi", + "version": "0.14.7+wasi-0.2.4" + }, + { + "name": "wasip2", + "version": "1.0.4+wasi-0.2.12" + }, + { + "name": "wasite", + "version": "1.0.2" + }, + { + "name": "wasm-bindgen-macro-support", + "version": "0.2.129" + }, + { + "name": "wasm-bindgen-macro", + "version": "0.2.129" + }, + { + "name": "wasm-bindgen-shared", + "version": "0.2.129" + }, + { + "name": "wasm-bindgen", + "version": "0.2.129" + }, + { + "name": "wasm-encoder", + "version": "0.252.0" + }, + { + "name": "wasmer-compiler", + "version": "7.2.1" + }, + { + "name": "wasmer-config", + "version": "0.702.1" + }, + { + "name": "wasmer-derive", + "version": "7.2.1" + }, + { + "name": "wasmer-journal", + "version": "0.702.1" + }, + { + "name": "wasmer-package", + "version": "0.702.1" + }, + { + "name": "wasmer-types", + "version": "7.2.1" + }, + { + "name": "wasmer-vm", + "version": "7.2.1" + }, + { + "name": "wasmer-wasix-types", + "version": "0.702.1" + }, + { + "name": "wasmer-wasix", + "version": "0.702.1" + }, + { + "name": "wasmer", + "version": "7.2.1" + }, + { + "name": "wasmparser", + "version": "0.252.0" + }, + { + "name": "web-sys", + "version": "0.3.106" + }, + { + "name": "webc", + "version": "12.0.0" + }, + { + "name": "weezl", + "version": "0.2.1" + }, + { + "name": "which", + "version": "8.0.6" + }, + { + "name": "whoami", + "version": "2.1.3" + }, + { + "name": "winapi-util", + "version": "0.1.11" + }, + { + "name": "windows_aarch64_gnullvm", + "version": "0.52.6" + }, + { + "name": "windows_aarch64_gnullvm", + "version": "0.53.1" + }, + { + "name": "windows_aarch64_msvc", + "version": "0.52.6" + }, + { + "name": "windows_aarch64_msvc", + "version": "0.53.1" + }, + { + "name": "windows_i686_gnu", + "version": "0.52.6" + }, + { + "name": "windows_i686_gnu", + "version": "0.53.1" + }, + { + "name": "windows_i686_gnullvm", + "version": "0.52.6" + }, + { + "name": "windows_i686_gnullvm", + "version": "0.53.1" + }, + { + "name": "windows_i686_msvc", + "version": "0.52.6" + }, + { + "name": "windows_i686_msvc", + "version": "0.53.1" + }, + { + "name": "windows_x86_64_gnu", + "version": "0.52.6" + }, + { + "name": "windows_x86_64_gnu", + "version": "0.53.1" + }, + { + "name": "windows_x86_64_gnullvm", + "version": "0.52.6" + }, + { + "name": "windows_x86_64_gnullvm", + "version": "0.53.1" + }, + { + "name": "windows_x86_64_msvc", + "version": "0.52.6" + }, + { + "name": "windows_x86_64_msvc", + "version": "0.53.1" + }, + { + "name": "windows-link", + "version": "0.2.1" + }, + { + "name": "windows-sys", + "version": "0.52.0" + }, + { + "name": "windows-sys", + "version": "0.59.0" + }, + { + "name": "windows-sys", + "version": "0.60.2" + }, + { + "name": "windows-sys", + "version": "0.61.2" + }, + { + "name": "windows-targets", + "version": "0.52.6" + }, + { + "name": "windows-targets", + "version": "0.53.5" + }, + { + "name": "winnow", + "version": "1.0.4" + }, + { + "name": "winx", + "version": "0.36.4" + }, + { + "name": "wit-bindgen", + "version": "0.57.1" + }, + { + "name": "writeable", + "version": "0.6.4" + }, + { + "name": "xattr", + "version": "1.6.1" + }, + { + "name": "xxhash-rust", + "version": "0.8.19" + }, + { + "name": "yoke-derive", + "version": "0.8.4" + }, + { + "name": "yoke", + "version": "0.8.3" + }, + { + "name": "zerocopy-derive", + "version": "0.8.62" + }, + { + "name": "zerocopy", + "version": "0.8.62" + }, + { + "name": "zerofrom-derive", + "version": "0.1.8" + }, + { + "name": "zerofrom", + "version": "0.1.8" + }, + { + "name": "zerotrie", + "version": "0.2.5" + }, + { + "name": "zerovec-derive", + "version": "0.11.6" + }, + { + "name": "zerovec", + "version": "0.11.8" + }, + { + "name": "zlib-rs", + "version": "0.6.8" + }, + { + "name": "zmij", + "version": "1.0.23" + }, + { + "name": "zstd-safe", + "version": "7.3.0" + }, + { + "name": "zstd-sys", + "version": "2.1.1+zstd.1.5.7" + }, + { + "name": "zstd", + "version": "0.13.3" + } + ], + "config": { + "dl": "https://static.crates.io/crates", + "api": "https://crates.io" + }, + "indexes": [ + { + "path": "2/cc", + "header": "AwIAAABldGFnOiAiYWQyNzAxODQ4NDA5NTI0MTFmMDI1MDA0ZWIxZjY5NzIiAA==", + "records": [ + { + "name": "cc", + "vers": "1.8.0", + "deps": [ + { + "name": "find-msvc-tools", + "req": "^0.1.14", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "jobserver", + "req": "^0.1.32", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.168", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "shlex", + "req": "^2.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "6651c9ed80effdc7db0ff72512157f901af5e3549e341e24b1dd4887d836d838", + "features": { + "jobserver": [] + }, + "features2": { + "parallel": ["dep:jobserver", "dep:libc"] + }, + "yanked": false, + "rust_version": "1.65.0", + "pubtime": "2026-10-11T14:17:35Z", + "v": 2 + } + ] + }, + { + "path": "3/b/bus", + "header": "AwIAAABldGFnOiAiYTY1YjVlMzQ0ZmQyNjg1YzkxZmVmMjBhNDE0NzFiMjkiAA==", + "records": [ + { + "name": "bus", + "vers": "2.4.1", + "deps": [ + { + "name": "crossbeam-channel", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "num_cpus", + "req": "^1.6.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "parking_lot_core", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "4b7118d0221d84fada881b657c2ddb7cd55108db79c8764c9ee212c0c259b783", + "features": {}, + "yanked": false, + "pubtime": "2023-08-20T12:34:40Z" + } + ] + }, + { + "path": "3/f/fnv", + "header": "AwIAAABldGFnOiAiMzJjNDYzODQ3NDEzOTA5NTQzMTJjMThjMDMwY2Y4NDQiAA==", + "records": [ + { + "name": "fnv", + "vers": "1.0.7", + "deps": [], + "cksum": "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "pubtime": "2020-05-14T16:06:29Z" + } + ] + }, + { + "path": "3/h/hex", + "header": "AwIAAABldGFnOiAiNGJlMDQ0MGIzYWU0NDU1MWVkNmQ1OTg1MWM1YzJmYzIiAA==", + "records": [ + { + "name": "hex", + "vers": "0.4.3", + "deps": [ + { + "name": "criterion", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "faster-hex", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "pretty_assertions", + "req": "^0.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustc-hex", + "req": "^2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "version-sync", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70", + "features": { + "alloc": [], + "default": ["std"], + "std": ["alloc"] + }, + "yanked": false, + "pubtime": "2021-03-03T10:48:58Z" + } + ] + }, + { + "path": "3/l/log", + "header": "AwIAAABldGFnOiAiNGE0ZGJlMjZlOWQ5MTliYTFmNjQ0MTM3NGUzODlhNTQiAA==", + "records": [ + { + "name": "log", + "vers": "0.4.34", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.63", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_test", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "sval", + "req": "^2.16", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "sval", + "req": "^2.16", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "sval_derive", + "req": "^2.16", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "sval_ref", + "req": "^2.16", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "value-bag", + "req": "^1.12", + "features": ["inline-i128"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "value-bag", + "req": "^1.12", + "features": ["test"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6", + "features": { + "alloc": [], + "kv": [], + "kv_serde": ["kv_std", "value-bag/serde", "serde"], + "kv_std": ["std", "kv", "value-bag/error"], + "kv_sval": ["kv", "value-bag/sval", "sval", "sval_ref"], + "kv_unstable": ["kv", "value-bag"], + "kv_unstable_serde": ["kv_serde", "kv_unstable_std"], + "kv_unstable_std": ["kv_std", "kv_unstable"], + "kv_unstable_sval": ["kv_sval", "kv_unstable"], + "max_level_debug": [], + "max_level_error": [], + "max_level_info": [], + "max_level_off": [], + "max_level_trace": [], + "max_level_warn": [], + "release_max_level_debug": [], + "release_max_level_error": [], + "release_max_level_info": [], + "release_max_level_off": [], + "release_max_level_trace": [], + "release_max_level_warn": [], + "serde": ["serde_core"], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.71.0", + "pubtime": "2026-08-22T11:44:27Z" + } + ] + }, + { + "path": "3/m/mio", + "header": "AwIAAABldGFnOiAiNzMyYWI4Nzk4ZTQ3NmMxZDcyZTBiNjk3NDZiOWIyZDUiAA==", + "records": [ + { + "name": "mio", + "vers": "1.2.4", + "deps": [ + { + "name": "env_logger", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "libc", + "req": "^0.2.183", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(unix, target_os = \"hermit\", target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "log", + "req": "^0.4.8", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "wasi", + "req": "^0.11.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_os = \"wasi\")", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": "^0.61", + "features": [ + "Wdk_Foundation", + "Wdk_Storage_FileSystem", + "Wdk_System_IO", + "Win32_Foundation", + "Win32_Networking_WinSock", + "Win32_Storage_FileSystem", + "Win32_Security", + "Win32_System_IO", + "Win32_System_WindowsProgramming" + ], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "1788edb87fdc09c7e26304471e2f5be8cdefb1b6930d6e3985fc02ff53bf86ee", + "features": { + "default": ["log"], + "net": [], + "os-ext": ["os-poll", "windows-sys/Win32_System_Pipes", "windows-sys/Win32_Security"], + "os-poll": [] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-10-03T16:33:10Z" + } + ] + }, + { + "path": "3/n/nom", + "header": "AwIAAABldGFnOiAiZDEwOWIwMDVlM2JhZmIzMDRkZThlODQyNjQxYjFiZmYiAA==", + "records": [ + { + "name": "nom", + "vers": "5.1.3", + "deps": [ + { + "name": "criterion", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "doc-comment", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "jemallocator", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "lazy_static", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "lexical-core", + "req": ">=0.6, <0.8", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memchr", + "req": "^2.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "regex", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "version_check", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b", + "features": { + "alloc": [], + "default": ["std", "lexical"], + "lexical": ["lexical-core"], + "regexp": ["regex"], + "regexp_macros": ["regexp", "lazy_static"], + "std": ["alloc", "memchr/use_std"] + }, + "yanked": false, + "pubtime": "2023-04-26T20:09:42Z" + }, + { + "name": "nom", + "vers": "7.1.3", + "deps": [ + { + "name": "doc-comment", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "memchr", + "req": "^2.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "minimal-lexical", + "req": "^0.2.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "proptest", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a", + "features": { + "alloc": [], + "default": ["std"], + "docsrs": [], + "std": ["alloc", "memchr/std", "minimal-lexical/std"] + }, + "yanked": false, + "rust_version": "1.48", + "pubtime": "2023-01-15T21:06:03Z" + } + ] + }, + { + "path": "3/p/phf", + "header": "AwIAAABldGFnOiAiODI0MGVlNzE2ZjZhZGVkMWZjNjllNDFkMTc2ZTViMmIiAA==", + "records": [ + { + "name": "phf", + "vers": "0.13.1", + "deps": [ + { + "name": "phf_macros", + "req": "^0.13.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "phf_shared", + "req": "^0.13.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf", + "features": { + "macros": ["phf_macros"] + }, + "features2": { + "default": ["std"], + "std": ["phf_shared/std", "serde?/std"], + "uncased": ["phf_macros?/uncased", "phf_shared/uncased"], + "unicase": ["phf_macros?/unicase", "phf_shared/unicase"] + }, + "yanked": false, + "rust_version": "1.66", + "pubtime": "2025-08-23T11:06:34Z", + "v": 2 + } + ] + }, + { + "path": "3/r/ryu", + "header": "AwIAAABldGFnOiAiYzRjNTAwNzZjNWJiZjVhYTE5ZDFmNGYyNWEwMDAyMjMiAA==", + "records": [ + { + "name": "ryu", + "vers": "1.0.23", + "deps": [ + { + "name": "criterion", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "no-panic", + "req": "^0.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "num_cpus", + "req": "^1.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand_core", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand_xorshift", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f", + "features": { + "small": [] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-02-08T20:34:03Z" + } + ] + }, + { + "path": "3/s/syn", + "header": "AwIAAABldGFnOiAiODM2YzQ4ODQ4ZTdmYWY3NjA1ZTlmZDEyNWUxMjIzZTgiAA==", + "records": [ + { + "name": "syn", + "vers": "1.0.109", + "deps": [ + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "automod", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "flate2", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "insta", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1.0.46", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ref-cast", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "regex", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "reqwest", + "req": "^0.11", + "features": ["blocking"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn-test-suite", + "req": "^0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tar", + "req": "^0.4.16", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "termcolor", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicode-ident", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "walkdir", + "req": "^2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237", + "features": { + "clone-impls": [], + "default": ["derive", "parsing", "printing", "clone-impls", "proc-macro"], + "derive": [], + "extra-traits": [], + "fold": [], + "full": [], + "parsing": [], + "printing": ["quote"], + "proc-macro": ["proc-macro2/proc-macro", "quote/proc-macro"], + "test": ["syn-test-suite/all-features"], + "visit": [], + "visit-mut": [] + }, + "yanked": false, + "rust_version": "1.31", + "pubtime": "2023-02-24T09:58:43Z" + }, + { + "name": "syn", + "vers": "2.0.119", + "deps": [ + { + "name": "anyhow", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "automod", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "flate2", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "insta", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1.0.91", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.35", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "ref-cast", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "reqwest", + "req": "^0.13", + "features": ["blocking"], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn-test-suite", + "req": "^0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tar", + "req": "^0.4.16", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "termcolor", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicode-ident", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "walkdir", + "req": "^2.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + } + ], + "cksum": "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297", + "features": { + "clone-impls": [], + "derive": [], + "extra-traits": [], + "fold": [], + "full": [], + "parsing": [], + "test": ["syn-test-suite/all-features"], + "visit": [], + "visit-mut": [] + }, + "features2": { + "default": ["derive", "parsing", "printing", "clone-impls", "proc-macro"], + "printing": ["dep:quote"], + "proc-macro": ["proc-macro2/proc-macro", "quote?/proc-macro"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-15T00:23:48Z", + "v": 2 + }, + { + "name": "syn", + "vers": "3.0.8", + "deps": [ + { + "name": "anyhow", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "automod", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "flate2", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "insta", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1.0.91", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.35", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "ref-cast", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "reqwest", + "req": "^0.13", + "features": ["blocking"], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn-test-suite", + "req": "^0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tar", + "req": "^0.4.16", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "termcolor", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicode-ident", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "walkdir", + "req": "^2.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + } + ], + "cksum": "01016da373cd8f7ef12624f796309f5c31ba8d646dd08856c02cd741d823c622", + "features": { + "clone-impls": [], + "derive": [], + "extra-traits": [], + "fold": [], + "full": [], + "parsing": [], + "test": ["syn-test-suite/all-features"], + "visit": [], + "visit-mut": [] + }, + "features2": { + "default": ["derive", "parsing", "printing", "clone-impls", "proc-macro"], + "printing": ["dep:quote"], + "proc-macro": ["proc-macro2/proc-macro", "quote?/proc-macro"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-10-11T16:12:28Z", + "v": 2 + } + ] + }, + { + "path": "3/t/tar", + "header": "AwIAAABldGFnOiAiMzc2ODlhYTNiMzBiNmIwY2E1NzU5Y2JhMzAwZTQ2NTAiAA==", + "records": [ + { + "name": "tar", + "vers": "0.4.46", + "deps": [ + { + "name": "astral-tokio-tar", + "req": "^0.6.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "filetime", + "req": "^0.2.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.8", + "features": ["small_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tempfile", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio", + "req": "^1", + "features": ["macros", "rt"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-stream", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "xattr", + "req": "^1.1.3", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + } + ], + "cksum": "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840", + "features": { + "default": ["xattr"] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2026-05-18T19:12:11Z" + } + ] + }, + { + "path": "3/u/url", + "header": "AwIAAABldGFnOiAiY2FhMmIyNjdlZWI3NmU2NzZjMjZmYTgxZmQ5MDg5OWEiAA==", + "records": [ + { + "name": "url", + "vers": "2.5.8", + "deps": [ + { + "name": "bencher", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "form_urlencoded", + "req": "^1.2.2", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "idna", + "req": "^1.1.0", + "features": ["alloc", "compiled_data"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "percent-encoding", + "req": "^2.3.2", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_derive", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"wasm32\", target_os = \"unknown\"))", + "kind": "dev" + } + ], + "cksum": "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed", + "features": { + "debugger_visualizer": [], + "expose_internals": [] + }, + "features2": { + "default": ["std"], + "serde": ["dep:serde", "dep:serde_derive"], + "std": ["idna/std", "percent-encoding/std", "form_urlencoded/std", "serde?/std"] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2026-01-05T22:14:31Z", + "v": 2 + } + ] + }, + { + "path": "3/v/vte", + "header": "AwIAAABldGFnOiAiNWE3MWNjY2JlMTFmNGNlMzE5YjI3NTA2NDQyODdiMDUiAA==", + "records": [ + { + "name": "vte", + "vers": "0.14.1", + "deps": [ + { + "name": "arrayvec", + "req": "^0.7.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "bitflags", + "req": "^2.3.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "cursor-icon", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "log", + "req": "^0.4.17", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memchr", + "req": "^2.7.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.160", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "231fdcd7ef3037e8330d8e17e61011a2c244126acc0a982f4040ac3f9f0bc077", + "features": { + "ansi": ["log", "cursor-icon", "bitflags"], + "default": ["no_std"], + "no_std": ["arrayvec"] + }, + "features2": { + "serde": ["dep:serde"] + }, + "yanked": false, + "rust_version": "1.62.1", + "pubtime": "2025-01-12T21:50:16Z", + "v": 2 + } + ] + }, + { + "path": "ad/dr/addr2line", + "header": "AwIAAABldGFnOiAiMzVmYzRkOWNhYmU1NGM4ODQ2M2VhYTZjMzRmMjJlZmQiAA==", + "records": [ + { + "name": "addr2line", + "vers": "0.25.1", + "deps": [ + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "backtrace", + "req": "^0.3.13", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "clap", + "req": "^4.3.21", + "features": ["wrap_help"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "cpp_demangle", + "req": "^0.4", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "criterion", + "req": "^0.7.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "fallible-iterator", + "req": "^0.3.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "findshlibs", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "gimli", + "req": "^0.32.0", + "features": ["read"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "libtest-mimic", + "req": "^0.8.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "memmap2", + "req": "^0.9.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "object", + "req": "^0.37.0", + "features": ["read", "compression"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rustc-demangle", + "req": "^0.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "smallvec", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "typed-arena", + "req": "^2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b", + "features": { + "cargo-all": [], + "rustc-dep-of-std": ["core", "alloc", "gimli/rustc-dep-of-std"], + "std": ["gimli/std"], + "wasm": ["object/wasm"] + }, + "features2": { + "all": ["bin", "wasm"], + "bin": [ + "loader", + "rustc-demangle", + "cpp_demangle", + "fallible-iterator", + "smallvec", + "dep:clap" + ], + "default": [ + "rustc-demangle", + "cpp_demangle", + "loader", + "fallible-iterator", + "smallvec" + ], + "loader": ["std", "dep:object", "dep:memmap2", "dep:typed-arena"] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2025-09-13T03:01:38Z", + "v": 2 + } + ] + }, + { + "path": "ad/le/adler2", + "header": "AwIAAABldGFnOiAiNmVlY2ZiMDZjMDY2NTY1YjIwODhmOTdlZTZmZWUyYmUiAA==", + "records": [ + { + "name": "adler2", + "vers": "2.0.1", + "deps": [ + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + } + ], + "cksum": "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa", + "features": { + "default": ["std"], + "rustc-dep-of-std": ["core"], + "std": [] + }, + "yanked": false, + "pubtime": "2025-06-09T22:31:53Z" + } + ] + }, + { + "path": "ah/o-/aho-corasick", + "header": "AwIAAABldGFnOiAiMjk2OTJkZGNkYzE1MmQyMDdkYTgyZDdlNzE0Yjg4ZmEiAA==", + "records": [ + { + "name": "aho-corasick", + "vers": "1.1.5", + "deps": [ + { + "name": "doc-comment", + "req": "^0.3.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "log", + "req": "^0.4.17", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memchr", + "req": "^2.4.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba", + "features": {}, + "features2": { + "default": ["std", "perf-literal"], + "logging": ["dep:log"], + "perf-literal": ["dep:memchr"], + "std": ["memchr?/std"] + }, + "yanked": false, + "rust_version": "1.60.0", + "pubtime": "2026-08-03T11:44:11Z", + "v": 2 + } + ] + }, + { + "path": "am/bi/ambient-authority", + "header": "AwIAAABldGFnOiAiYmJiOGM4NWI3ZmIwYmNmMzI1ZTg3OTI5NzU4NTY2OTEiAA==", + "records": [ + { + "name": "ambient-authority", + "vers": "0.0.2", + "deps": [], + "cksum": "e9d4ee0d472d1cd2e28c97dfa124b3d8d992e10eb0a035f33f5d12e3a177ba3b", + "features": {}, + "yanked": false, + "pubtime": "2023-04-06T23:01:28Z" + } + ] + }, + { + "path": "an/st/anstream", + "header": "AwIAAABldGFnOiAiZTQyZGU0YzM5ZmQ1YWEzYWYwYzAxYzczZTUxMDRmYjYiAA==", + "records": [ + { + "name": "anstream", + "vers": "1.0.0", + "deps": [ + { + "name": "anstyle", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anstyle-parse", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anstyle-query", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anstyle-wincon", + "req": "^3.0.5", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + }, + { + "name": "colorchoice", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "divan", + "req": "^0.1.16", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "is_terminal_polyfill", + "req": "^1.48", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "lexopt", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "owo-colors", + "req": "^4.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proptest", + "req": "^1.7.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "strip-ansi-escapes", + "req": "^0.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "utf8parse", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d", + "features": { + "test": [] + }, + "features2": { + "auto": ["dep:anstyle-query"], + "default": ["auto", "wincon"], + "wincon": ["dep:anstyle-wincon"] + }, + "yanked": false, + "rust_version": "1.66.0", + "pubtime": "2026-02-11T13:23:11Z", + "v": 2 + } + ] + }, + { + "path": "an/st/anstyle", + "header": "AwIAAABldGFnOiAiNjczODQzZDZlOTMzYzEyMjk5OTA5MzRiZDljNjU3ODciAA==", + "records": [ + { + "name": "anstyle", + "vers": "1.0.14", + "deps": [ + { + "name": "lexopt", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "snapbox", + "req": "^0.6.23", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.66.0", + "pubtime": "2026-03-13T18:59:28Z" + } + ] + }, + { + "path": "an/st/anstyle-parse", + "header": "AwIAAABldGFnOiAiYjUyMzE2ZmFhYmEzN2IzMmYxNzQ4NjA0OTY3NzkwZTYiAA==", + "records": [ + { + "name": "anstyle-parse", + "vers": "1.0.0", + "deps": [ + { + "name": "arrayvec", + "req": "^0.7.6", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "codegenrs", + "req": "^3.0.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "divan", + "req": "^0.1.16", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proptest", + "req": "^1.7.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "snapbox", + "req": "^0.6.23", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "utf8parse", + "req": "^0.2.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "vte_generate_state_changes", + "req": "^0.1.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e", + "features": {}, + "features2": { + "core": ["dep:arrayvec"], + "default": ["utf8"], + "utf8": ["dep:utf8parse"] + }, + "yanked": false, + "rust_version": "1.66.0", + "pubtime": "2026-02-11T13:23:08Z", + "v": 2 + } + ] + }, + { + "path": "an/st/anstyle-query", + "header": "AwIAAABldGFnOiAiODBmYzM5NGU3MTUwZDM5MjI2YmJiYzgwYzQzYzYxOTciAA==", + "records": [ + { + "name": "anstyle-query", + "vers": "1.1.5", + "deps": [ + { + "name": "windows-sys", + "req": ">=0.60.2, <0.62", + "features": ["Win32_System_Console", "Win32_Foundation"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc", + "features": {}, + "yanked": false, + "rust_version": "1.66.0", + "pubtime": "2025-11-13T17:30:22Z" + } + ] + }, + { + "path": "an/st/anstyle-wincon", + "header": "AwIAAABldGFnOiAiZDVjZWQ0NDYwNWM2YzU0ODI0OWYyNDE4YjllM2M0ZjAiAA==", + "records": [ + { + "name": "anstyle-wincon", + "vers": "3.0.11", + "deps": [ + { + "name": "anstyle", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "lexopt", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "once_cell_polyfill", + "req": "^1.56.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.60.2, <0.62", + "features": ["Win32_System_Console", "Win32_Foundation"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d", + "features": {}, + "yanked": false, + "rust_version": "1.66.0", + "pubtime": "2025-11-13T17:30:26Z" + } + ] + }, + { + "path": "an/y_/any_ascii", + "header": "AwIAAABldGFnOiAiMzUzMjJiNzM5YzFlYjI3ZmQ4ODQ5Njk1ZTFjMDcwNDIiAA==", + "records": [ + { + "name": "any_ascii", + "vers": "0.1.7", + "deps": [], + "cksum": "70033777eb8b5124a81a1889416543dddef2de240019b674c81285a2635a7e1e", + "features": {}, + "yanked": false, + "pubtime": "2020-10-19T14:14:51Z" + } + ] + }, + { + "path": "an/yh/anyhow", + "header": "AwIAAABldGFnOiAiZDU2MGNmMWQwZDFiOWI5ZWQ3OTZkMDU1MDU5MzhmYmMiAA==", + "records": [ + { + "name": "anyhow", + "vers": "1.0.104", + "deps": [ + { + "name": "futures", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn", + "req": "^3", + "features": ["full"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "thiserror", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.108", + "features": ["diff"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470", + "features": { + "backtrace": [], + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.68", + "pubtime": "2026-07-18T20:59:37Z" + } + ] + }, + { + "path": "ar/ra/arrayvec", + "header": "AwIAAABldGFnOiAiMTE0NmJkM2Y1YTE4YjczZDk0MTVmM2FjYWZmMmI2ZTUiAA==", + "records": [ + { + "name": "arrayvec", + "vers": "0.7.8", + "deps": [ + { + "name": "bencher", + "req": "^0.1.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "borsh", + "req": "^1.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "matches", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_test", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "zeroize", + "req": "^1.4", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.51", + "pubtime": "2026-07-02T12:44:35Z" + } + ] + }, + { + "path": "as/yn/async-trait", + "header": "AwIAAABldGFnOiAiNThlZWYzMDNmMWRjYjFjMjk4Mzg1YWVmN2FhMmZlZmEiAA==", + "records": [ + { + "name": "async-trait", + "vers": "0.1.92", + "deps": [ + { + "name": "futures", + "req": "^0.3.30", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1.0.74", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.35", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustversion", + "req": "^1.0.13", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn", + "req": "^3", + "features": ["clone-impls", "full", "parsing", "printing", "proc-macro", "visit-mut"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tracing", + "req": "^0.1.40", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tracing-attributes", + "req": "^0.1.27", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.108", + "features": ["diff"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-08-08T07:10:35Z" + } + ] + }, + { + "path": "au/to/autocfg", + "header": "AwIAAABldGFnOiAiOTY5ZGUwMWM4ZTc5NjIxYmEwMWQ4NzU0NTA5MGZjMjIiAA==", + "records": [ + { + "name": "autocfg", + "vers": "1.5.1", + "deps": [], + "cksum": "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53", + "features": {}, + "yanked": false, + "rust_version": "1.0", + "pubtime": "2026-05-22T11:03:04Z" + } + ] + }, + { + "path": "ba/ck/backtrace", + "header": "AwIAAABldGFnOiAiNTI5MjE5MThlYjZlMmQxMzc4OTAwMTE2MWQ2YzkwZDMiAA==", + "records": [ + { + "name": "backtrace", + "vers": "0.3.76", + "deps": [ + { + "name": "addr2line", + "req": "^0.25.0", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))", + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cpp_demangle", + "req": "^0.5.0", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.156", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))", + "kind": "normal" + }, + { + "name": "libloading", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "miniz_oxide", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))", + "kind": "normal" + }, + { + "name": "object", + "req": "^0.37.0", + "features": ["read_core", "elf", "macho", "pe", "xcoff", "unaligned", "archive"], + "optional": false, + "default_features": false, + "target": "cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))", + "kind": "normal" + }, + { + "name": "rustc-demangle", + "req": "^0.1.24", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ruzstd", + "req": "^0.8.1", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))", + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "windows-link", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(windows, target_os = \"cygwin\"))", + "kind": "normal" + } + ], + "cksum": "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6", + "features": { + "coresymbolication": [], + "dbghelp": [], + "default": ["std"], + "dl_iterate_phdr": [], + "dladdr": [], + "kernel32": [], + "libunwind": [], + "serialize-serde": ["serde"], + "std": [], + "unix-backtrace": [] + }, + "features2": { + "ruzstd": ["dep:ruzstd"] + }, + "yanked": false, + "rust_version": "1.82.0", + "pubtime": "2025-09-26T02:43:38Z", + "v": 2 + } + ] + }, + { + "path": "ba/se/base64", + "header": "AwIAAABldGFnOiAiMGEzMDg3N2QzZDkwZGNiNzY2ZmI5ODdjOWQxMjBhZDkiAA==", + "records": [ + { + "name": "base64", + "vers": "0.22.1", + "deps": [ + { + "name": "clap", + "req": "^3.2.25", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "once_cell", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.8.5", + "features": ["small_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rstest", + "req": "^0.13.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rstest_reuse", + "req": "^0.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "strum", + "req": "^0.25", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6", + "features": { + "alloc": [], + "default": ["std"], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.48.0", + "pubtime": "2024-04-30T23:16:40Z" + } + ] + }, + { + "path": "bi/nc/bincode", + "header": "AwIAAABldGFnOiAiM2U2ZmVhYTU3MDA5ZDYxNmYxZDU1ZmUzNTUzZDZjNzciAA==", + "records": [ + { + "name": "bincode", + "vers": "2.0.1", + "deps": [ + { + "name": "bincode_1", + "req": "^1.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "bincode" + }, + { + "name": "bincode_derive", + "req": "^2.0.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bumpalo", + "req": "^3.16.0", + "features": ["collections"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "chrono", + "req": "^0.4", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "glam", + "req": "^0.25", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ouroboros", + "req": "^0.18.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_derive", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "tempfile", + "req": "^3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unty", + "req": "^0.0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "uuid", + "req": "^1.1", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740", + "features": { + "derive": ["bincode_derive"] + }, + "features2": { + "alloc": ["serde?/alloc"], + "default": ["std", "derive"], + "std": ["alloc", "serde?/std"] + }, + "yanked": false, + "rust_version": "1.85.0", + "pubtime": "2025-03-10T18:28:08Z", + "v": 2 + } + ] + }, + { + "path": "bi/nc/bincode_derive", + "header": "AwIAAABldGFnOiAiNmUwNGJmNGVmNTEyMjAwZjY0ZDlhYzlkYjMxNWIzNDMiAA==", + "records": [ + { + "name": "bincode_derive", + "vers": "2.0.1", + "deps": [ + { + "name": "virtue", + "req": "^0.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09", + "features": {}, + "yanked": false, + "rust_version": "1.85.0", + "pubtime": "2025-03-10T18:27:58Z" + } + ] + }, + { + "path": "bi/nd/bindgen", + "header": "AwIAAABldGFnOiAiMTNkNzliODA5NGY2OTk3NWZkYTEwZTFhNjhlNWJjY2MiAA==", + "records": [ + { + "name": "bindgen", + "vers": "0.72.1", + "deps": [ + { + "name": "annotate-snippets", + "req": "^0.11.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bitflags", + "req": "^2.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cexpr", + "req": "^0.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "clang-sys", + "req": "^1", + "features": ["clang_11_0"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "clap", + "req": "^4", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "clap_complete", + "req": "^4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "itertools", + "req": ">=0.10, <0.14", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "log", + "req": "^0.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "prettyplease", + "req": "^0.2.7", + "features": ["verbatim"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1.0.80", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "regex", + "req": "^1.5.3", + "features": ["std", "unicode-perl"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rustc-hash", + "req": "^2.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "shlex", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0", + "features": ["full", "extra-traits", "visit-mut"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895", + "features": { + "__testing_only_extra_assertions": [], + "__testing_only_libclang_16": [], + "__testing_only_libclang_9": [], + "runtime": ["clang-sys/runtime"], + "static": ["clang-sys/static"] + }, + "features2": { + "__cli": ["dep:clap", "dep:clap_complete"], + "default": ["logging", "prettyplease", "runtime"], + "experimental": ["dep:annotate-snippets"], + "logging": ["dep:log"] + }, + "yanked": false, + "rust_version": "1.70.0", + "pubtime": "2025-08-31T17:50:11Z", + "v": 2 + } + ] + }, + { + "path": "bi/tf/bitflags", + "header": "AwIAAABldGFnOiAiMmYyMjc0MzNjM2E4MGJlZWM2MmQyM2MzNGJiZWQwYWUiAA==", + "records": [ + { + "name": "bitflags", + "vers": "1.3.2", + "deps": [ + { + "name": "compiler_builtins", + "req": "^0.1.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "rustversion", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_derive", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "walkdir", + "req": "^2.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a", + "features": { + "default": [], + "example_generated": [], + "rustc-dep-of-std": ["core", "compiler_builtins"] + }, + "yanked": false, + "pubtime": "2021-08-16T04:16:02Z" + }, + { + "name": "bitflags", + "vers": "2.13.2", + "deps": [ + { + "name": "arbitrary", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "arbitrary", + "req": "^1.0", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "bytemuck", + "req": "^1.12", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytemuck", + "req": "^1.12.2", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.228", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_lib", + "req": "^1.0.103", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "serde" + }, + { + "name": "serde_test", + "req": "^1.0.19", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "zerocopy", + "req": "^0.8", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06", + "features": { + "example_generated": [], + "serde": ["serde_core"], + "std": [] + }, + "yanked": false, + "rust_version": "1.56.0", + "pubtime": "2026-09-10T01:11:38Z" + } + ] + }, + { + "path": "bl/ak/blake3", + "header": "AwIAAABldGFnOiAiMjE4MzUwZjYzYTNmZGQ1ODQ5NmRkOWQyMDg4MGM5NzkiAA==", + "records": [ + { + "name": "blake3", + "vers": "1.8.7", + "deps": [ + { + "name": "arrayvec", + "req": "^0.7.4", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "cc", + "req": "^1.1.12", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "cfg-if", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "chacha20", + "req": "^0.10.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ciborium", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "constant_time_eq", + "req": "^0.4.2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "cpufeatures", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))", + "kind": "normal" + }, + { + "name": "digest", + "req": "^0.11.2", + "features": ["mac"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hex", + "req": "^0.4.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hmac", + "req": "^0.13.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "memmap2", + "req": "^0.9", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "page_size", + "req": "^0.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.10.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon-core", + "req": "^1.12.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.107", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tempfile", + "req": "^3.8.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "zeroize", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "6d9e454fc11f76977dc803893aff6304ed33d6a26efae8696573bea74baa27ae", + "features": { + "default": ["std"], + "neon": [], + "no_avx2": [], + "no_avx512": [], + "no_neon": [], + "no_sse2": [], + "no_sse41": [], + "prefer_intrinsics": [], + "pure": [], + "std": ["constant_time_eq/std"], + "wasm32_simd": [] + }, + "features2": { + "digest": ["dep:digest"], + "mmap": ["std", "dep:memmap2"], + "rayon": ["dep:rayon-core"], + "traits-preview": ["dep:digest"], + "zeroize": ["dep:zeroize", "arrayvec/zeroize"] + }, + "yanked": false, + "pubtime": "2026-08-20T09:09:56Z", + "v": 2 + } + ] + }, + { + "path": "bl/oc/block-buffer", + "header": "AwIAAABldGFnOiAiMGI2OGE1OWNhZDMyZGVlODdhMTUwMjM3YzQxNmU2NjAiAA==", + "records": [ + { + "name": "block-buffer", + "vers": "0.10.4", + "deps": [ + { + "name": "generic-array", + "req": "^0.14", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71", + "features": {}, + "yanked": false, + "pubtime": "2023-03-09T02:08:25Z" + }, + { + "name": "block-buffer", + "vers": "0.12.1", + "deps": [ + { + "name": "hex-literal", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hybrid-array", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "zeroize", + "req": "^1.8", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa", + "features": {}, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-06-11T15:40:05Z" + } + ] + }, + { + "path": "bs/tr/bstr", + "header": "AwIAAABldGFnOiAiNmY5NTM4MGM0OTcxNGZmODM0MmEzNzMxMzVmYjQwZGEiAA==", + "records": [ + { + "name": "bstr", + "vers": "1.13.1", + "deps": [ + { + "name": "memchr", + "req": "^2.7.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "regex-automata", + "req": "^0.4.1", + "features": ["dfa-search"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_core", + "req": "^1.0.85", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "ucd-parse", + "req": "^0.1.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicode-segmentation", + "req": "^1.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "6bb31b46c14244e20ee9984b11bf5c992b91fb6939fea616e3512c8baecdbe5f", + "features": {}, + "features2": { + "alloc": ["memchr/alloc", "serde_core?/alloc"], + "default": ["std", "unicode"], + "serde": ["dep:serde_core"], + "std": ["alloc", "memchr/std", "serde_core?/std"], + "unicode": ["dep:regex-automata"] + }, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-08-10T11:12:08Z", + "v": 2 + } + ] + }, + { + "path": "bu/mp/bumpalo", + "header": "AwIAAABldGFnOiAiMzFlMTk5OTI0MGIyYzhkMDU2NGMxOWZmMTVhZmYyMzQiAA==", + "records": [ + { + "name": "bumpalo", + "vers": "3.20.3", + "deps": [ + { + "name": "allocator-api2", + "req": "^0.2.8", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "blink-alloc", + "req": "=0.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.3.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quickcheck", + "req": "=1.0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.8.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "=1.10.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon-core", + "req": "=1.12.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.171", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.197", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0.115", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649", + "features": { + "allocator_api": [], + "bench_allocator_api": ["allocator_api", "blink-alloc/nightly"], + "boxed": [], + "collections": [], + "default": [], + "std": [] + }, + "features2": { + "serde": ["dep:serde"] + }, + "yanked": false, + "rust_version": "1.71.1", + "pubtime": "2026-05-22T14:59:11Z", + "v": 2 + } + ] + }, + { + "path": "by/te/bytecheck", + "header": "AwIAAABldGFnOiAiMzY5NzhlYzJkYTgxY2RiZmJmNGE1YmU4MmIzZWVlMTciAA==", + "records": [ + { + "name": "bytecheck", + "vers": "0.8.3", + "deps": [ + { + "name": "bytecheck_derive", + "req": "=0.8.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "ptr_meta", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rancor", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "simdutf8", + "req": "^0.1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "uuid-1", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "uuid" + } + ], + "cksum": "26333eeac754f0ad8a6bcd0eb0ac012156302e4e16b852b72ee399aea4f12c29", + "features": { + "default": ["simdutf8"] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-08-05T11:58:05Z" + } + ] + }, + { + "path": "by/te/bytecheck_derive", + "header": "AwIAAABldGFnOiAiYWUwMTc0Y2M4YTk5MWUyNzEzNzllNjI5MDIyYzY4ODIiAA==", + "records": [ + { + "name": "bytecheck_derive", + "vers": "0.8.3", + "deps": [ + { + "name": "proc-macro2", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3.0", + "features": ["clone-impls", "derive", "full", "parsing", "printing", "proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "46d07918caa9eeaaf06b7873925c53a61daac173539b4f7715090745e44e4e69", + "features": {}, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-08-05T11:58:04Z" + } + ] + }, + { + "path": "by/te/byteorder", + "header": "AwIAAABldGFnOiAiMTRmZTJlOTI1MGM4Zjk3M2VkNTRmYjFhNzk4NDdjMGQiAA==", + "records": [ + { + "name": "byteorder", + "vers": "1.5.0", + "deps": [ + { + "name": "quickcheck", + "req": "^0.9.2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b", + "features": { + "default": ["std"], + "i128": [], + "std": [] + }, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2023-10-06T00:45:57Z" + } + ] + }, + { + "path": "by/te/bytes", + "header": "AwIAAABldGFnOiAiNTdhYmQ4OTgxY2M3NWUwOWIyODQ2MDlhNWNkMjU2NzkiAA==", + "records": [ + { + "name": "bytes", + "vers": "1.12.1", + "deps": [ + { + "name": "extra-platforms", + "req": "^1.3", + "features": ["require-cas"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "portable-atomic" + }, + { + "name": "loom", + "req": "^0.7", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(loom)", + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.60", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_test", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.57", + "pubtime": "2026-07-08T10:01:28Z" + } + ] + }, + { + "path": "by/te/bytesize", + "header": "AwIAAABldGFnOiAiMjMxNjQwZjY1NjM1MzI4NTMyYWQ1MDRiZTA4NjVkNjciAA==", + "records": [ + { + "name": "bytesize", + "vers": "2.7.0", + "deps": [ + { + "name": "arbitrary", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "divan", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quickcheck", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml", + "req": "^1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "7354288c522e7e980fafd2075d63d1285794c3a6a16cdd492f189ea406e5f18b", + "features": { + "default": ["std"], + "std": [] + }, + "features2": { + "arbitrary": ["dep:arbitrary"], + "serde": ["dep:serde_core"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-08-02T03:27:39Z", + "v": 2 + } + ] + }, + { + "path": "ca/p-/cap-fs-ext", + "header": "AwIAAABldGFnOiAiYzkwMmY3MGJjNjE1MWU5M2NlYWQyYmFjZjg5NDRmYjYiAA==", + "records": [ + { + "name": "cap-fs-ext", + "vers": "4.0.3", + "deps": [ + { + "name": "arf-strings", + "req": "^0.7.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "camino", + "req": "^1.0.5", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cap-primitives", + "req": "^4.0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cap-std", + "req": "^4.0.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "io-lifetimes", + "req": "^3.0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.60, <0.62", + "features": ["Win32_Storage_FileSystem"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "56ff379b70af8e08307a8f65e7040c7301cb4a572538ade16b4984f0da77847f", + "features": { + "arf_strings": ["cap-std/arf_strings", "fs_utf8", "arf-strings"], + "default": ["std"], + "fs_utf8": ["cap-std/fs_utf8", "camino"], + "std": ["cap-std"] + }, + "yanked": false, + "pubtime": "2026-08-20T15:09:46Z" + } + ] + }, + { + "path": "ca/p-/cap-primitives", + "header": "AwIAAABldGFnOiAiZWE2ZGY2OWNjMzI4YmViNjRhNzY2N2FmNjc3Zjk1MDgiAA==", + "records": [ + { + "name": "cap-primitives", + "vers": "4.0.3", + "deps": [ + { + "name": "ambient-authority", + "req": "^0.0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "arbitrary", + "req": "^1.0.0", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "fs-set-times", + "req": "^0.20.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "io-extras", + "req": "^0.19.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "io-lifetimes", + "req": "^3.0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "ipnet", + "req": "^2.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "maybe-owned", + "req": "^0.3.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustix", + "req": "^1.0.0", + "features": ["fs", "process", "termios", "time"], + "optional": false, + "default_features": true, + "target": "cfg(not(windows))", + "kind": "normal" + }, + { + "name": "rustix-linux-procfs", + "req": "^0.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(target_os = \"android\", target_os = \"linux\"))", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.60, <0.62", + "features": [ + "Win32_Foundation", + "Win32_Security", + "Win32_Storage_FileSystem", + "Win32_System_Kernel", + "Win32_System_WindowsProgramming", + "Win32_System_IO", + "Wdk_Storage_FileSystem", + "Wdk_Foundation" + ], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + }, + { + "name": "winx", + "req": "^0.36.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "8b5f74729fd2f44701d1a8eb47e906cdb3ccd9ec0f02baad85a744b791940b18", + "features": {}, + "yanked": false, + "pubtime": "2026-08-20T15:09:42Z" + } + ] + }, + { + "path": "ca/p-/cap-std", + "header": "AwIAAABldGFnOiAiODI3ZDc2ZjMxZGQ4ZDFkZTc4ZjA5Y2ZkM2I5NGM2YjEiAA==", + "records": [ + { + "name": "cap-std", + "vers": "4.0.3", + "deps": [ + { + "name": "arf-strings", + "req": "^0.7.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "camino", + "req": "^1.0.5", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cap-primitives", + "req": "^4.0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "io-extras", + "req": "^0.19.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "io-lifetimes", + "req": "^3.0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rustix", + "req": "^1.0.0", + "features": ["fs"], + "optional": false, + "default_features": true, + "target": "cfg(not(windows))", + "kind": "normal" + } + ], + "cksum": "c1ec78e242cfa2cfe276807ac2ecc00315a6c97786977414bcd1c3963b6c91b8", + "features": { + "arf_strings": ["fs_utf8", "arf-strings"], + "default": [], + "fs_utf8": ["camino"] + }, + "yanked": false, + "pubtime": "2026-08-20T15:09:44Z" + } + ] + }, + { + "path": "ce/xp/cexpr", + "header": "AwIAAABldGFnOiAiMzJjOGU4YmM0NzExMDhiMDc2ZjFjY2Y2MjUwN2M0ZDAiAA==", + "records": [ + { + "name": "cexpr", + "vers": "0.6.0", + "deps": [ + { + "name": "clang-sys", + "req": ">=0.13.0, <0.29.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "nom", + "req": "^7", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766", + "features": {}, + "yanked": false, + "pubtime": "2021-10-11T09:31:52Z" + } + ] + }, + { + "path": "cf/g-/cfg-if", + "header": "AwIAAABldGFnOiAiNjA4MGZiYzc2YjkwZDM1ZWViNjYwMzY1M2I2MzMwZWYiAA==", + "records": [ + { + "name": "cfg-if", + "vers": "1.0.5", + "deps": [ + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + } + ], + "cksum": "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600", + "features": { + "rustc-dep-of-std": ["core"] + }, + "yanked": false, + "rust_version": "1.32", + "pubtime": "2026-09-16T17:36:11Z" + } + ] + }, + { + "path": "ch/ac/chacha20", + "header": "AwIAAABldGFnOiAiNWQ3MzM4YzUyYTE3N2E2ZjhhYzlmOWYwNmVlNmVlM2YiAA==", + "records": [ + { + "name": "chacha20", + "vers": "0.10.2", + "deps": [ + { + "name": "cfg-if", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cipher", + "req": "^0.5", + "features": ["stream-wrapper"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cipher", + "req": "^0.5", + "features": ["dev"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "cpufeatures", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(target_arch = \"x86_64\", target_arch = \"x86\"))", + "kind": "normal" + }, + { + "name": "hex-literal", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand_core", + "req": "^0.10", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zeroize", + "req": "^1.8.1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06", + "features": { + "default": ["cipher"], + "legacy": ["cipher"], + "xchacha": ["cipher"] + }, + "features2": { + "rng": ["dep:rand_core"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-08-27T17:51:13Z", + "v": 2 + } + ] + }, + { + "path": "ch/ro/chrono", + "header": "AwIAAABldGFnOiAiMGNlNGYyMjU2ZTJmNmVhZWU0YTI4M2VmNzQwNjRmYjYiAA==", + "records": [ + { + "name": "chrono", + "vers": "0.4.45", + "deps": [ + { + "name": "arbitrary", + "req": "^1.0.0", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bincode", + "req": "^1.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "defmt", + "req": "^1.0.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "iana-time-zone", + "req": "^0.1.45", + "features": ["fallback"], + "optional": true, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "js-sys", + "req": "^0.3", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(all(target_arch = \"wasm32\", not(any(target_os = \"emscripten\", target_os = \"wasi\"))))", + "kind": "normal" + }, + { + "name": "num-traits", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "pure-rust-locales", + "req": "^0.8.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rkyv", + "req": "^0.7.43", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.99", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "similar-asserts", + "req": "^2.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "wasm-bindgen", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(all(target_arch = \"wasm32\", not(any(target_os = \"emscripten\", target_os = \"wasi\"))))", + "kind": "normal" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"wasm32\", not(any(target_os = \"emscripten\", target_os = \"wasi\"))))", + "kind": "dev" + }, + { + "name": "windows-bindgen", + "req": "^0.66", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "windows-link", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327", + "features": { + "__internal_bench": [], + "alloc": [], + "clock": ["winapi", "iana-time-zone", "now"], + "core-error": [], + "default": ["clock", "std", "oldtime", "wasmbind"], + "libc": [], + "now": ["std"], + "oldtime": [], + "std": ["alloc"], + "unstable-locales": ["pure-rust-locales"], + "wasmbind": ["wasm-bindgen", "js-sys"], + "winapi": ["windows-link"] + }, + "features2": { + "defmt": ["dep:defmt", "pure-rust-locales?/defmt"], + "rkyv": ["dep:rkyv", "rkyv/size_32"], + "rkyv-16": ["dep:rkyv", "rkyv?/size_16"], + "rkyv-32": ["dep:rkyv", "rkyv?/size_32"], + "rkyv-64": ["dep:rkyv", "rkyv?/size_64"], + "rkyv-validation": ["rkyv?/validation"] + }, + "yanked": false, + "rust_version": "1.62.0", + "pubtime": "2026-06-04T12:16:42Z", + "v": 2 + } + ] + }, + { + "path": "ci/bo/ciborium", + "header": "AwIAAABldGFnOiAiNzZhNDU1MTk2NTA2MmQ0OTFlYzkzZmRmNjhjNTBlZTAiAA==", + "records": [ + { + "name": "ciborium", + "vers": "0.2.2", + "deps": [ + { + "name": "ciborium-io", + "req": "^0.2.2", + "features": ["alloc"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ciborium-ll", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hex", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rstest", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.100", + "features": ["alloc", "derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_bytes", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e", + "features": { + "default": ["std"], + "std": ["ciborium-io/std", "serde/std"] + }, + "yanked": false, + "rust_version": "1.58", + "pubtime": "2024-01-24T03:04:25Z" + } + ] + }, + { + "path": "ci/bo/ciborium-io", + "header": "AwIAAABldGFnOiAiMGJhZDQ2ZGUzMWI5ZTA5N2ZkNmM3OWRjMDQwNjVjMTciAA==", + "records": [ + { + "name": "ciborium-io", + "vers": "0.2.2", + "deps": [], + "cksum": "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757", + "features": { + "alloc": [], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.58", + "pubtime": "2024-01-24T03:02:36Z" + } + ] + }, + { + "path": "ci/bo/ciborium-ll", + "header": "AwIAAABldGFnOiAiMTRhMTVlOThjMWFiNDQ3MTE3NGY5MDFkZmFjZWMzN2IiAA==", + "records": [ + { + "name": "ciborium-ll", + "vers": "0.2.2", + "deps": [ + { + "name": "ciborium-io", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "half", + "req": "^2.2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "hex", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9", + "features": { + "alloc": [], + "std": ["alloc", "half/std"] + }, + "yanked": false, + "rust_version": "1.58", + "pubtime": "2024-01-24T03:03:42Z" + } + ] + }, + { + "path": "cl/an/clang-sys", + "header": "AwIAAABldGFnOiAiMmI1NmU0ZWM2ODEzMjkwZTc2OWI3MmYzYmZlZjM2NjUiAA==", + "records": [ + { + "name": "clang-sys", + "vers": "1.9.1", + "deps": [ + { + "name": "glob", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "glob", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "glob", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "lazy_static", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "libc", + "req": "^0.2.39", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "libloading", + "req": "^0.8", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": ">=3.0.0, <3.7.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "157a8ba7b480713b56f4c09fd13fc3e0a22a5dfab8097ba61cbc5feef950788a", + "features": { + "clang_10_0": ["clang_9_0"], + "clang_11_0": ["clang_10_0"], + "clang_12_0": ["clang_11_0"], + "clang_13_0": ["clang_12_0"], + "clang_14_0": ["clang_13_0"], + "clang_15_0": ["clang_14_0"], + "clang_16_0": ["clang_15_0"], + "clang_17_0": ["clang_16_0"], + "clang_18_0": ["clang_17_0"], + "clang_19_0": ["clang_18_0"], + "clang_20_0": ["clang_19_0"], + "clang_3_5": [], + "clang_3_6": ["clang_3_5"], + "clang_3_7": ["clang_3_6"], + "clang_3_8": ["clang_3_7"], + "clang_3_9": ["clang_3_8"], + "clang_4_0": ["clang_3_9"], + "clang_5_0": ["clang_4_0"], + "clang_6_0": ["clang_5_0"], + "clang_7_0": ["clang_6_0"], + "clang_8_0": ["clang_7_0"], + "clang_9_0": ["clang_8_0"], + "libcpp": [], + "runtime": ["libloading"], + "static": [] + }, + "yanked": false, + "links": "clang", + "pubtime": "2026-07-29T12:50:24Z" + } + ] + }, + { + "path": "cl/ap/clap", + "header": "AwIAAABldGFnOiAiNzJlNWQ3ZDllMDZlYWNjZGNiNTdkNzMxZGRhMTJiMzQiAA==", + "records": [ + { + "name": "clap", + "vers": "4.6.7", + "deps": [ + { + "name": "automod", + "req": "^1.0.16", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "clap-cargo", + "req": "^0.15.2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "clap_builder", + "req": "=4.6.7", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "clap_derive", + "req": "=4.6.7", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "jiff", + "req": "^0.2.23", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0.22", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "semver", + "req": "^1.0.27", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "shlex", + "req": "^2.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "snapbox", + "req": "^1.2.0", + "features": ["term-svg"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.116", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trycmd", + "req": "^1.2.0", + "features": ["color-auto", "diff", "examples"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + } + ], + "cksum": "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946", + "features": { + "cargo": ["clap_builder/cargo"], + "color": ["clap_builder/color"], + "default": ["std", "color", "help", "usage", "error-context", "suggestions"], + "env": ["clap_builder/env"], + "error-context": ["clap_builder/error-context"], + "help": ["clap_builder/help"], + "std": ["clap_builder/std"], + "string": ["clap_builder/string"], + "suggestions": ["clap_builder/suggestions"], + "unicode": ["clap_builder/unicode"], + "unstable-derive-ui-tests": [], + "unstable-ext": ["clap_builder/unstable-ext"], + "unstable-markdown": ["clap_derive/unstable-markdown"], + "unstable-styles": ["clap_builder/unstable-styles"], + "usage": ["clap_builder/usage"], + "wrap_help": ["clap_builder/wrap_help"] + }, + "features2": { + "debug": ["clap_builder/debug", "clap_derive?/debug"], + "deprecated": ["clap_builder/deprecated", "clap_derive?/deprecated"], + "derive": ["dep:clap_derive"], + "unstable-doc": ["clap_builder/unstable-doc", "derive"], + "unstable-v5": ["clap_builder/unstable-v5", "clap_derive?/unstable-v5", "deprecated"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-09-14T18:40:28Z", + "v": 2 + } + ] + }, + { + "path": "cl/ap/clap_builder", + "header": "AwIAAABldGFnOiAiYjRiYmI4MGI5ODYyNDE4NjNiZmU4ZGNjYjY5YjZmY2IiAA==", + "records": [ + { + "name": "clap_builder", + "vers": "4.6.7", + "deps": [ + { + "name": "anstream", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anstyle", + "req": "^1.0.14", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "backtrace", + "req": "^0.3.76", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "clap_lex", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "color-print", + "req": "^0.3.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "snapbox", + "req": "^1.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "strsim", + "req": "^0.11.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "terminal_size", + "req": "^0.4.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "unic-emoji-char", + "req": "^0.9.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicase", + "req": "^2.9.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "unicode-width", + "req": "^0.2.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d", + "features": { + "cargo": [], + "deprecated": [], + "env": [], + "error-context": [], + "help": [], + "std": ["anstyle/std"], + "string": [], + "unstable-ext": [], + "unstable-v5": ["deprecated"], + "usage": [] + }, + "features2": { + "color": ["dep:anstream"], + "debug": ["dep:backtrace"], + "default": ["std", "color", "help", "usage", "error-context", "suggestions"], + "suggestions": ["dep:strsim", "error-context"], + "unicode": ["dep:unicode-width", "dep:unicase"], + "unstable-doc": ["cargo", "wrap_help", "env", "unicode", "string", "unstable-ext"], + "unstable-styles": ["color"], + "wrap_help": ["help", "dep:terminal_size"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-09-14T18:40:26Z", + "v": 2 + } + ] + }, + { + "path": "cl/ap/clap_derive", + "header": "AwIAAABldGFnOiAiMDFlMzNjZjg4MzE0NDVkZjEzMGZhOWFmM2Q5OWUwMTAiAA==", + "records": [ + { + "name": "clap_derive", + "vers": "4.6.7", + "deps": [ + { + "name": "anstyle", + "req": "^1.0.14", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "heck", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1.0.106", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pulldown-cmark", + "req": "^0.13.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.45", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3.0.2", + "features": ["full"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "f9c751b79415d4e559e3d1fcf128e09e720eb673a06d26cf6f392d37d75b66e0", + "features": { + "debug": [], + "default": [], + "deprecated": [], + "raw-deprecated": ["deprecated"], + "unstable-v5": ["deprecated"] + }, + "features2": { + "unstable-markdown": ["dep:pulldown-cmark", "dep:anstyle"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-09-14T18:40:23Z", + "v": 2 + } + ] + }, + { + "path": "cl/ap/clap_lex", + "header": "AwIAAABldGFnOiAiYzUwN2IyMjM4NzA2MmM2OWMyMjBhYTgzMzYwMTZjM2IiAA==", + "records": [ + { + "name": "clap_lex", + "vers": "1.1.1", + "deps": [ + { + "name": "automod", + "req": "^1.0.16", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486", + "features": {}, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-09-14T18:40:24Z" + } + ] + }, + { + "path": "cm/ak/cmake", + "header": "AwIAAABldGFnOiAiMGIwMTc2MWUwNDdlZmU5ODNmOGViZGVlMWExNmUyZjAiAA==", + "records": [ + { + "name": "cmake", + "vers": "0.1.58", + "deps": [ + { + "name": "cc", + "req": "^1.2.46", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678", + "features": {}, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-03-26T17:58:29Z" + } + ] + }, + { + "path": "cm/ov/cmov", + "header": "AwIAAABldGFnOiAiMDU1YTdjZDBhMjk3MGEwOTRlNDg2OWJlYzQ0MjE4MjgiAA==", + "records": [ + { + "name": "cmov", + "vers": "0.5.4", + "deps": [ + { + "name": "proptest", + "req": "^1.11", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(unix, windows))", + "kind": "dev" + } + ], + "cksum": "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a", + "features": {}, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-05-28T19:07:33Z" + } + ] + }, + { + "path": "co/lo/colorchoice", + "header": "AwIAAABldGFnOiAiMjc1NzVhNjg2Njc1NTdhNTAxMTA5YjA4ZTc5YzIwZmQiAA==", + "records": [ + { + "name": "colorchoice", + "vers": "1.0.5", + "deps": [], + "cksum": "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570", + "features": {}, + "yanked": false, + "rust_version": "1.66.0", + "pubtime": "2026-03-13T18:59:29Z" + } + ] + }, + { + "path": "co/ns/console", + "header": "AwIAAABldGFnOiAiMDMyYWU0NTA3ZmI3ZTMyOGMwMjg0MzdhMjllZTAxNjQiAA==", + "records": [ + { + "name": "console", + "vers": "0.16.6", + "deps": [ + { + "name": "encode_unicode", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.99", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proptest", + "req": "^1.0.0", + "features": ["std", "bit-set", "break-dead-code"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "regex", + "req": "^1.4.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicode-width", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "windows-sys", + "req": "^0.61", + "features": [ + "Win32_Foundation", + "Win32_System_Console", + "Win32_Storage_FileSystem", + "Win32_UI_Input_KeyboardAndMouse" + ], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "e96a4956774c13c126a8b5af4daa79384f4d826534c95a02d76afb39e2ab64e3", + "features": { + "alloc": [], + "ansi-parsing": [], + "windows-console-colors": ["ansi-parsing"] + }, + "features2": { + "default": ["unicode-width", "ansi-parsing", "std"], + "std": ["dep:libc", "alloc"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-09-10T07:42:27Z", + "v": 2 + } + ] + }, + { + "path": "co/ns/const-oid", + "header": "AwIAAABldGFnOiAiNmI4NzEwMjJkNWQ2OWQyMjUzMTBkM2MzMTFhNzhhYWYiAA==", + "records": [ + { + "name": "const-oid", + "vers": "0.10.2", + "deps": [ + { + "name": "arbitrary", + "req": "^1.4", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hex-literal", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proptest", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "regex", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c", + "features": { + "db": [] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-01-07T23:11:57Z" + } + ] + }, + { + "path": "co/ns/constant_time_eq", + "header": "AwIAAABldGFnOiAiMzQxNTBmMzFjMTRkYzZkYTFmNTI1YWE4YjI4MjQyZmYiAA==", + "records": [ + { + "name": "constant_time_eq", + "vers": "0.4.2", + "deps": [ + { + "name": "count_instructions", + "req": "^0.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.5.1", + "features": ["cargo_bench_support", "html_reports"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b", + "features": { + "count_instructions_test": [], + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.85.0", + "pubtime": "2025-03-15T17:03:47Z" + } + ] + }, + { + "path": "co/nv/convert_case", + "header": "AwIAAABldGFnOiAiOWJjMDAxZjY1MjcxNWM1YjVkZmVmYWY5OWI4NmI1MWYiAA==", + "records": [ + { + "name": "convert_case", + "vers": "0.10.0", + "deps": [ + { + "name": "criterion", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicode-segmentation", + "req": "^1.9.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9", + "features": {}, + "yanked": false, + "pubtime": "2025-11-23T12:24:56Z" + } + ] + }, + { + "path": "co/ok/cooked-waker", + "header": "AwIAAABldGFnOiAiYTZkMjAxOGY1ZDM0MzJkN2RmNjlkNDk1NDdiZDUxNWMiAA==", + "records": [ + { + "name": "cooked-waker", + "vers": "5.0.0", + "deps": [], + "cksum": "147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f", + "features": {}, + "yanked": false, + "pubtime": "2020-12-23T21:47:33Z" + } + ] + }, + { + "path": "co/ro/corosensei", + "header": "AwIAAABldGFnOiAiNzIyM2JmMjExZmU0OTMyYzdhZmUwNmY5NzBjNWQ0OTQiAA==", + "records": [ + { + "name": "corosensei", + "vers": "0.3.4", + "deps": [ + { + "name": "autocfg", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "backtrace", + "req": "^0.3.69", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "cfg-if", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "criterion", + "req": "^0.5.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion-cycles-per-byte", + "req": "^0.6.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))", + "kind": "dev" + }, + { + "name": "libc", + "req": "^0.2.159", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "scopeguard", + "req": "^1.2.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "windows-sys", + "req": "^0.59.0", + "features": [ + "Win32_Foundation", + "Win32_System_Diagnostics_Debug", + "Win32_System_Kernel", + "Win32_System_Memory", + "Win32_System_Threading", + "Win32_System_SystemInformation" + ], + "optional": true, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "6886a0c0f263965933c438626e7179139a62b978a33aa18281cbf0cd5a975f34", + "features": { + "asm-unwind": ["unwind"], + "default": ["default-stack", "unwind"], + "default-stack": ["libc", "windows-sys"], + "sanitizer": [], + "unwind": [] + }, + "yanked": false, + "rust_version": "1.59.0", + "pubtime": "2026-05-24T13:32:37Z" + } + ] + }, + { + "path": "cp/p_/cpp_demangle", + "header": "AwIAAABldGFnOiAiMzIwZDIxNDUyZDI1YWY0NjI3YjgyNGNiNDVmMDNlOGEiAA==", + "records": [ + { + "name": "cpp_demangle", + "vers": "0.4.5", + "deps": [ + { + "name": "afl", + "req": "^0.15", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "clap", + "req": "^4.0", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "diff", + "req": "^0.1.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "f2bb79cb74d735044c972aae58ed0aaa9a837e85b01106a54c39e42e97f62253", + "features": { + "alloc": [], + "default": ["std"], + "fuzz": ["afl"], + "logging": ["std"], + "run_libiberty_tests": [], + "std": ["alloc"] + }, + "yanked": false, + "pubtime": "2025-09-24T01:47:04Z" + } + ] + }, + { + "path": "cp/uf/cpufeatures", + "header": "AwIAAABldGFnOiAiNzllZTI2NTM1MTg4ZmYzMTU4ZjMzOTU2YzU2MjIwN2QiAA==", + "records": [ + { + "name": "cpufeatures", + "vers": "0.2.17", + "deps": [ + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": false, + "target": "aarch64-linux-android", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_arch = \"aarch64\", target_os = \"linux\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_arch = \"aarch64\", target_vendor = \"apple\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_arch = \"loongarch64\", target_os = \"linux\"))", + "kind": "normal" + } + ], + "cksum": "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280", + "features": {}, + "yanked": false, + "pubtime": "2025-01-25T01:35:46Z" + }, + { + "name": "cpufeatures", + "vers": "0.3.1", + "deps": [ + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_arch = \"aarch64\", target_os = \"android\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_arch = \"aarch64\", target_os = \"linux\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_arch = \"aarch64\", target_vendor = \"apple\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_arch = \"loongarch64\", target_os = \"linux\"))", + "kind": "normal" + } + ], + "cksum": "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566", + "features": {}, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-08-26T18:39:59Z" + } + ] + }, + { + "path": "cr/c3/crc32fast", + "header": "AwIAAABldGFnOiAiMjcxMTZiY2EyNTA5YmQzMzY2YjcwYzdhYWM4NGE4NTgiAA==", + "records": [ + { + "name": "crc32fast", + "vers": "1.5.2", + "deps": [ + { + "name": "bencher", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "cfg-if", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "01a7799fd6b852db0e61728dde9a204c423b44d689dbd432522543614b490e78", + "features": { + "default": ["std"], + "nightly": [], + "std": [] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2026-09-12T18:41:46Z" + } + ] + }, + { + "path": "cr/os/crossbeam-channel", + "header": "AwIAAABldGFnOiAiODJiYjY1YWI3YWQ0ZDU2YzQ5YjY2ZDFhN2JhYzY5NTkiAA==", + "records": [ + { + "name": "crossbeam-channel", + "vers": "0.5.17", + "deps": [ + { + "name": "crossbeam-utils", + "req": "^0.8.18", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "num_cpus", + "req": "^1.13.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "signal-hook", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "98b0cc327b5bc766e7fda9c9260cc0fa81b43a8e240440422dff70788e3f9ef1", + "features": { + "default": ["std"], + "std": ["crossbeam-utils/std"] + }, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2026-09-05T17:47:21Z" + } + ] + }, + { + "path": "cr/os/crossbeam-deque", + "header": "AwIAAABldGFnOiAiMDg3NjUxMzQxMTM5ZWRmMzJmOGFhNmRkZmE3MzcyNTciAA==", + "records": [ + { + "name": "crossbeam-deque", + "vers": "0.8.8", + "deps": [ + { + "name": "crossbeam-epoch", + "req": "^0.9.17", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "crossbeam-utils", + "req": "^0.8.18", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a", + "features": { + "default": ["std"], + "std": ["crossbeam-epoch/std", "crossbeam-utils/std"] + }, + "yanked": false, + "rust_version": "1.61", + "pubtime": "2026-09-05T17:47:08Z" + } + ] + }, + { + "path": "cr/os/crossbeam-epoch", + "header": "AwIAAABldGFnOiAiZTQzYjVmMmQ2OGE0ZDNhMjU4YWJiYTE2OTAxYjYwMzkiAA==", + "records": [ + { + "name": "crossbeam-epoch", + "vers": "0.9.21", + "deps": [ + { + "name": "crossbeam-utils", + "req": "^0.8.18", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "loom-crate", + "req": "^0.7.1", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(crossbeam_loom)", + "kind": "normal", + "package": "loom" + }, + { + "name": "rand", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d", + "features": { + "alloc": [], + "default": ["std"], + "loom": ["loom-crate", "crossbeam-utils/loom"], + "nightly": ["crossbeam-utils/nightly"], + "std": ["alloc", "crossbeam-utils/std"] + }, + "yanked": false, + "rust_version": "1.61", + "pubtime": "2026-09-05T17:46:49Z" + } + ] + }, + { + "path": "cr/os/crossbeam-queue", + "header": "AwIAAABldGFnOiAiODhiNGQxMjY5YTBkNmNkZmE0Nzc4MTJlOGIzMDYwZWYiAA==", + "records": [ + { + "name": "crossbeam-queue", + "vers": "0.3.14", + "deps": [ + { + "name": "crossbeam-utils", + "req": "^0.8.18", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "03e8bd762f7479489c70ed6c768ddca99d7296857de437a68dcb2a94365b3fae", + "features": { + "alloc": [], + "default": ["std"], + "nightly": ["crossbeam-utils/nightly"], + "std": ["alloc", "crossbeam-utils/std"] + }, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2026-09-05T17:46:34Z" + } + ] + }, + { + "path": "cr/os/crossbeam-utils", + "header": "AwIAAABldGFnOiAiM2Q0YzEwZTIzMTQwM2JiYTVjN2E5MzExNjRmMGE3ZjEiAA==", + "records": [ + { + "name": "crossbeam-utils", + "vers": "0.8.23", + "deps": [ + { + "name": "loom", + "req": "^0.7.1", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(crossbeam_loom)", + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6", + "features": { + "default": ["std"], + "nightly": [], + "std": [] + }, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2026-09-05T17:46:14Z" + } + ] + }, + { + "path": "cr/un/crunchy", + "header": "AwIAAABldGFnOiAiNTgwZWU3NjEwYmViODVhMjdkOTQwZTIzMzdlYTRkODgiAA==", + "records": [ + { + "name": "crunchy", + "vers": "0.2.4", + "deps": [], + "cksum": "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5", + "features": { + "default": ["limit_128"], + "limit_1024": [], + "limit_128": [], + "limit_2048": [], + "limit_256": [], + "limit_512": [], + "limit_64": [], + "std": [] + }, + "yanked": false, + "pubtime": "2025-06-25T12:54:43Z" + } + ] + }, + { + "path": "cr/yp/crypto-common", + "header": "AwIAAABldGFnOiAiMTA5NWZjMDg1YTA4YWY4ZjY5ZWUzZDlkNzI1YWEzZDEiAA==", + "records": [ + { + "name": "crypto-common", + "vers": "0.1.7", + "deps": [ + { + "name": "generic-array", + "req": "=0.14.7", + "features": ["more_lengths"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rand_core", + "req": "^0.6", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "typenum", + "req": "^1.14", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a", + "features": { + "getrandom": ["rand_core/getrandom"], + "std": [] + }, + "yanked": false, + "pubtime": "2025-11-12T14:20:00Z" + }, + { + "name": "crypto-common", + "vers": "0.2.2", + "deps": [ + { + "name": "getrandom", + "req": "^0.4", + "features": ["sys_rng"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hybrid-array", + "req": "^0.4.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rand_core", + "req": "^0.10", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453", + "features": { + "zeroize": ["hybrid-array/zeroize"] + }, + "features2": { + "getrandom": ["rand_core", "dep:getrandom"], + "rand_core": ["dep:rand_core"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-05-19T16:01:22Z", + "v": 2 + } + ] + }, + { + "path": "ct/ut/ctutils", + "header": "AwIAAABldGFnOiAiZDRmNTY4YmQxNzZmNDAzNTk3MGY0ZjdkODNkYWRmMzMiAA==", + "records": [ + { + "name": "ctutils", + "vers": "0.4.3", + "deps": [ + { + "name": "cmov", + "req": "^0.5.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proptest", + "req": "^1.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "subtle", + "req": "^2.6", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "03bb0e1cc970d482d121d9a1744999169b69a07470b3d644a7894e53fcaf4574", + "features": { + "alloc": [] + }, + "features2": { + "subtle": ["dep:subtle"] + }, + "yanked": false, + "rust_version": "1.87", + "pubtime": "2026-10-05T23:29:33Z", + "v": 2 + } + ] + }, + { + "path": "da/rl/darling", + "header": "AwIAAABldGFnOiAiNDljZWM4ZmUwOTcwZDA5NmNiYmE3ZGUxNWI4NTU5MTEiAA==", + "records": [ + { + "name": "darling", + "vers": "0.20.11", + "deps": [ + { + "name": "darling_core", + "req": "=0.20.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "darling_macro", + "req": "=0.20.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1.0.86", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quote", + "req": "^1.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0.9", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(compiletests)", + "kind": "dev" + }, + { + "name": "syn", + "req": "^2.0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.89", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(compiletests)", + "kind": "dev" + } + ], + "cksum": "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee", + "features": { + "default": ["suggestions"], + "diagnostics": ["darling_core/diagnostics"], + "suggestions": ["darling_core/suggestions"] + }, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2025-03-28T20:05:16Z" + }, + { + "name": "darling", + "vers": "0.21.3", + "deps": [ + { + "name": "darling_core", + "req": "=0.21.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "darling_macro", + "req": "=0.21.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1.0.86", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quote", + "req": "^1.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0.9", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(compiletests)", + "kind": "dev" + }, + { + "name": "syn", + "req": "^2.0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.89", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(compiletests)", + "kind": "dev" + } + ], + "cksum": "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0", + "features": { + "default": ["suggestions"], + "diagnostics": ["darling_core/diagnostics"], + "serde": ["darling_core/serde"], + "suggestions": ["darling_core/suggestions"] + }, + "yanked": false, + "rust_version": "1.56.0", + "pubtime": "2025-08-22T15:40:48Z" + } + ] + }, + { + "path": "da/rl/darling_core", + "header": "AwIAAABldGFnOiAiMzA0ZGZkZTdjMzIyZGI2MTIxODA0MjA0ODA4N2RhOTciAA==", + "records": [ + { + "name": "darling_core", + "vers": "0.20.11", + "deps": [ + { + "name": "fnv", + "req": "^1.0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ident_case", + "req": "^1.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1.0.86", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "strsim", + "req": "^0.11.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0.15", + "features": ["full", "extra-traits"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e", + "features": { + "diagnostics": [], + "suggestions": ["strsim"] + }, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2025-03-28T20:05:00Z" + }, + { + "name": "darling_core", + "vers": "0.21.3", + "deps": [ + { + "name": "fnv", + "req": "^1.0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ident_case", + "req": "^1.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1.0.86", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.210", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.140", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "strsim", + "req": "^0.11.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0.15", + "features": ["full", "extra-traits"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4", + "features": { + "diagnostics": [], + "suggestions": ["strsim"] + }, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2025-08-22T15:40:32Z" + } + ] + }, + { + "path": "da/rl/darling_macro", + "header": "AwIAAABldGFnOiAiNzRlZDAxNzc5ZDg4N2Q5NGM0MGQzZDc1Y2FmOTBhZTgiAA==", + "records": [ + { + "name": "darling_macro", + "vers": "0.20.11", + "deps": [ + { + "name": "darling_core", + "req": "=0.20.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2025-03-28T20:05:07Z" + }, + { + "name": "darling_macro", + "vers": "0.21.3", + "deps": [ + { + "name": "darling_core", + "req": "=0.21.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2025-08-22T15:40:39Z" + } + ] + }, + { + "path": "da/sh/dashmap", + "header": "AwIAAABldGFnOiAiNjNiMTQ4NjFiMDE1YTA3ZGQyNzMzZTNjZTI4YmZmOTgiAA==", + "records": [ + { + "name": "dashmap", + "vers": "6.2.1", + "deps": [ + { + "name": "arbitrary", + "req": "^1.4.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "crossbeam-utils", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hashbrown", + "req": "^0.14.5", + "features": ["raw"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "lock_api", + "req": "^0.4.13", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "once_cell", + "req": "^1.21.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "parking_lot_core", + "req": "^0.9.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1.10.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.228", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "typesize", + "req": "^0.1.14", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c", + "features": { + "inline": ["hashbrown/inline-more"], + "raw-api": [] + }, + "features2": { + "typesize": ["dep:typesize"] + }, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-05-17T21:28:34Z", + "v": 2 + } + ] + }, + { + "path": "de/bu/debugid", + "header": "AwIAAABldGFnOiAiZDAxMGNkN2JmNWI1NzYwMTljN2I4YzFjZWM5NzFiYzMiAA==", + "records": [ + { + "name": "debugid", + "vers": "0.8.0", + "deps": [ + { + "name": "serde", + "req": "^1.0.85", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.37", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "uuid", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d", + "features": {}, + "yanked": false, + "pubtime": "2022-04-26T11:03:07Z" + } + ] + }, + { + "path": "de/fm/defmt", + "header": "AwIAAABldGFnOiAiNGMzNTY2NzU3MjZkMjE0NTE1NjdmN2EzNmNlMmY4NjUiAA==", + "records": [ + { + "name": "defmt", + "vers": "0.3.100", + "deps": [ + { + "name": "defmt10", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal", + "package": "defmt" + } + ], + "cksum": "f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad", + "features": { + "alloc": ["defmt10/alloc"], + "avoid-default-panic": ["defmt10/avoid-default-panic"], + "encoding-raw": ["defmt10/encoding-raw"], + "encoding-rzcobs": ["defmt10/encoding-rzcobs"], + "ip_in_core": ["defmt10/ip_in_core"], + "unstable-test": ["defmt10/unstable-test"] + }, + "yanked": false, + "pubtime": "2025-04-01T14:47:45Z" + }, + { + "name": "defmt", + "vers": "1.1.1", + "deps": [ + { + "name": "bitflags", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "defmt-macros", + "req": "=1.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustc_version", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1", + "features": { + "alloc": [], + "avoid-default-panic": [], + "encoding-raw": [], + "encoding-rzcobs": [], + "ip_in_core": [], + "unstable-test": ["defmt-macros/unstable-test"] + }, + "yanked": false, + "links": "defmt", + "pubtime": "2026-07-03T14:14:30Z" + } + ] + }, + { + "path": "de/fm/defmt-macros", + "header": "AwIAAABldGFnOiAiY2Q5ODdlMzM2ODY4YWI5NWE5ODU4YzE4MTkxODZiYjciAA==", + "records": [ + { + "name": "defmt-macros", + "vers": "1.1.1", + "deps": [ + { + "name": "defmt-parser", + "req": "=1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "maplit", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "pretty_assertions", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rstest", + "req": "^0.19", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "syn", + "req": "^2", + "features": ["full", "extra-traits"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8", + "features": { + "unstable-test": [] + }, + "yanked": false, + "pubtime": "2026-07-03T14:14:21Z" + } + ] + }, + { + "path": "de/fm/defmt-parser", + "header": "AwIAAABldGFnOiAiZDdlNjIxNjE0ZmYxOTZlNTg5MGMyYTY0N2MwZmI4NDYiAA==", + "records": [ + { + "name": "defmt-parser", + "vers": "1.0.0", + "deps": [ + { + "name": "rstest", + "req": "^0.19", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "thiserror", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e", + "features": { + "unstable": [] + }, + "yanked": false, + "pubtime": "2025-04-01T14:32:40Z" + } + ] + }, + { + "path": "de/ra/deranged", + "header": "AwIAAABldGFnOiAiMzQ4MTU1NjI5NzhmYzk5NDg4ZTJiMzMwZTIzNTA0NGQiAA==", + "records": [ + { + "name": "deranged", + "vers": "0.5.8", + "deps": [ + { + "name": "deranged-macros", + "req": "=0.3.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "num-traits", + "req": "^0.2.15", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "powerfmt", + "req": "^0.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1.0.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand010", + "req": "^0.10.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "rand" + }, + { + "name": "rand010", + "req": "^0.10.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "rand" + }, + { + "name": "rand08", + "req": "^0.8.4", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "rand" + }, + { + "name": "rand08", + "req": "^0.8.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "rand" + }, + { + "name": "rand09", + "req": "^0.9.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "rand" + }, + { + "name": "rand09", + "req": "^0.9.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "rand" + }, + { + "name": "serde_core", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.86", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c", + "features": { + "alloc": [], + "default": [] + }, + "features2": { + "macros": ["dep:deranged-macros"], + "num": ["dep:num-traits"], + "powerfmt": ["dep:powerfmt"], + "quickcheck": ["dep:quickcheck", "alloc"], + "rand": ["rand08", "rand09", "rand010"], + "rand010": ["dep:rand010"], + "rand08": ["dep:rand08"], + "rand09": ["dep:rand09"], + "serde": ["dep:serde_core"] + }, + "yanked": false, + "rust_version": "1.85.0", + "pubtime": "2026-02-21T21:37:43Z", + "v": 2 + } + ] + }, + { + "path": "de/ri/derive_builder", + "header": "AwIAAABldGFnOiAiYTQ1YzcwODJlN2Y2NzgwNjU0NzVkZTk1ODU4ZmU0YjIiAA==", + "records": [ + { + "name": "derive_builder", + "vers": "0.20.2", + "deps": [ + { + "name": "derive_builder_macro", + "req": "=0.20.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustversion", + "req": "^1.0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.38", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(compiletests)", + "kind": "dev" + } + ], + "cksum": "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947", + "features": { + "alloc": ["derive_builder_macro/alloc"], + "clippy": ["derive_builder_macro/clippy"], + "default": ["std"], + "std": ["derive_builder_macro/lib_has_std"] + }, + "yanked": false, + "pubtime": "2024-10-08T16:55:17Z" + } + ] + }, + { + "path": "de/ri/derive_builder_core", + "header": "AwIAAABldGFnOiAiYjc4MTY5NzA4NWY2MGFiOTgzMDFkYTg4MDBkY2I3YTYiAA==", + "records": [ + { + "name": "derive_builder_core", + "vers": "0.20.2", + "deps": [ + { + "name": "darling", + "req": "^0.20.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1.0.37", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.35", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0.15", + "features": ["full", "extra-traits"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8", + "features": { + "alloc": [], + "clippy": [], + "lib_has_std": [] + }, + "yanked": false, + "pubtime": "2024-10-08T16:54:04Z" + } + ] + }, + { + "path": "de/ri/derive_builder_macro", + "header": "AwIAAABldGFnOiAiMDg2ODZkMDEyOTI4NGI2YzI5MGYxZDU3YjdkYTI5NjYiAA==", + "records": [ + { + "name": "derive_builder_macro", + "vers": "0.20.2", + "deps": [ + { + "name": "derive_builder_core", + "req": "=0.20.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0.15", + "features": ["full", "extra-traits"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c", + "features": { + "alloc": ["derive_builder_core/alloc"], + "clippy": ["derive_builder_core/clippy"], + "lib_has_std": ["derive_builder_core/lib_has_std"] + }, + "yanked": false, + "pubtime": "2024-10-08T16:54:13Z" + } + ] + }, + { + "path": "de/ri/derive_more", + "header": "AwIAAABldGFnOiAiMTUwNDc2YjY1NzA0MDA1OWY5YmI4YTIxZjQ1ZjJjYzgiAA==", + "records": [ + { + "name": "derive_more", + "vers": "2.1.1", + "deps": [ + { + "name": "derive_more-impl", + "req": "=2.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustc_version", + "req": "^0.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "rustversion", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.56", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134", + "features": { + "add": ["derive_more-impl/add"], + "add_assign": ["derive_more-impl/add_assign"], + "as_ref": ["derive_more-impl/as_ref"], + "constructor": ["derive_more-impl/constructor"], + "debug": ["derive_more-impl/debug"], + "default": ["std"], + "deref": ["derive_more-impl/deref"], + "deref_mut": ["derive_more-impl/deref_mut"], + "display": ["derive_more-impl/display"], + "eq": ["derive_more-impl/eq"], + "error": ["derive_more-impl/error"], + "from": ["derive_more-impl/from"], + "from_str": ["derive_more-impl/from_str"], + "full": [ + "add", + "add_assign", + "as_ref", + "constructor", + "debug", + "deref", + "deref_mut", + "display", + "eq", + "error", + "from", + "from_str", + "index", + "index_mut", + "into", + "into_iterator", + "is_variant", + "mul", + "mul_assign", + "not", + "sum", + "try_from", + "try_into", + "try_unwrap", + "unwrap" + ], + "index": ["derive_more-impl/index"], + "index_mut": ["derive_more-impl/index_mut"], + "into": ["derive_more-impl/into"], + "into_iterator": ["derive_more-impl/into_iterator"], + "is_variant": ["derive_more-impl/is_variant"], + "mul": ["derive_more-impl/mul"], + "mul_assign": ["derive_more-impl/mul_assign"], + "not": ["derive_more-impl/not"], + "std": [], + "sum": ["derive_more-impl/sum"], + "try_from": ["derive_more-impl/try_from"], + "try_into": ["derive_more-impl/try_into"], + "try_unwrap": ["derive_more-impl/try_unwrap"], + "unwrap": ["derive_more-impl/unwrap"] + }, + "features2": { + "testing-helpers": ["derive_more-impl/testing-helpers", "dep:rustc_version"] + }, + "yanked": false, + "rust_version": "1.81.0", + "pubtime": "2025-12-22T09:13:44Z", + "v": 2 + } + ] + }, + { + "path": "de/ri/derive_more-impl", + "header": "AwIAAABldGFnOiAiMDc5ODJjZDAyOTIwZGEyZWEyMjg1M2U0ZTg0NmJkZDEiAA==", + "records": [ + { + "name": "derive_more-impl", + "vers": "2.1.1", + "deps": [ + { + "name": "convert_case", + "req": "^0.10", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "itertools", + "req": "^0.14.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustc_version", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "syn", + "req": "^2.0.45", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "unicode-xid", + "req": "^0.2.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb", + "features": { + "add": ["syn/extra-traits", "syn/visit"], + "add_assign": ["syn/extra-traits", "syn/visit"], + "as_ref": ["syn/extra-traits", "syn/visit"], + "constructor": [], + "default": [], + "deref": [], + "deref_mut": [], + "eq": ["syn/extra-traits", "syn/visit"], + "error": ["syn/extra-traits"], + "from": ["syn/extra-traits"], + "index": [], + "index_mut": [], + "into": ["syn/extra-traits", "syn/visit-mut"], + "into_iterator": [], + "mul": ["syn/extra-traits", "syn/visit"], + "mul_assign": ["syn/extra-traits", "syn/visit"], + "not": ["syn/extra-traits"], + "sum": [], + "testing-helpers": ["syn/full"], + "try_from": [], + "try_into": ["syn/extra-traits", "syn/full", "syn/visit-mut"] + }, + "features2": { + "debug": ["syn/extra-traits", "dep:unicode-xid"], + "display": ["syn/extra-traits", "dep:unicode-xid", "dep:convert_case"], + "from_str": ["syn/full", "syn/visit", "dep:convert_case"], + "full": [ + "add", + "add_assign", + "as_ref", + "constructor", + "debug", + "deref", + "deref_mut", + "display", + "eq", + "error", + "from", + "from_str", + "index", + "index_mut", + "into", + "into_iterator", + "is_variant", + "mul", + "mul_assign", + "not", + "sum", + "try_from", + "try_into", + "try_unwrap", + "unwrap" + ], + "is_variant": ["dep:convert_case"], + "try_unwrap": ["dep:convert_case"], + "unwrap": ["dep:convert_case"] + }, + "yanked": false, + "rust_version": "1.81.0", + "pubtime": "2025-12-22T09:13:41Z", + "v": 2 + } + ] + }, + { + "path": "di/ge/digest", + "header": "AwIAAABldGFnOiAiZWU1MWVhZjc4OWExZTE4ZGE5YmQzOTEwNzA5ODVkN2QiAA==", + "records": [ + { + "name": "digest", + "vers": "0.10.7", + "deps": [ + { + "name": "blobby", + "req": "^0.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "block-buffer", + "req": "^0.10", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "const-oid", + "req": "^0.9", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "crypto-common", + "req": "^0.1.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "subtle", + "req": "^2.4", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292", + "features": { + "alloc": [], + "core-api": ["block-buffer"], + "default": ["core-api"], + "dev": ["blobby"], + "mac": ["subtle"], + "oid": ["const-oid"], + "rand_core": ["crypto-common/rand_core"], + "std": ["alloc", "crypto-common/std"] + }, + "yanked": false, + "pubtime": "2023-05-19T17:11:30Z" + }, + { + "name": "digest", + "vers": "0.11.3", + "deps": [ + { + "name": "blobby", + "req": "^0.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "block-buffer", + "req": "^0.12", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "common", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal", + "package": "crypto-common" + }, + { + "name": "const-oid", + "req": "^0.10", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ctutils", + "req": "^0.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sha2", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "zeroize", + "req": "^1.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2", + "features": { + "alloc": [], + "dev": ["blobby"], + "getrandom": ["common/getrandom", "rand_core"], + "rand_core": ["common/rand_core"] + }, + "features2": { + "block-api": ["dep:block-buffer"], + "default": ["block-api"], + "mac": ["dep:ctutils"], + "oid": ["dep:const-oid"], + "zeroize": ["dep:zeroize", "block-buffer?/zeroize"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-05-03T12:54:48Z", + "v": 2 + } + ] + }, + { + "path": "di/re/directories", + "header": "AwIAAABldGFnOiAiNjFkOThkZGVmNTU5Zjk0ZWNkZjNlOWZiNDhhZjAxODYiAA==", + "records": [ + { + "name": "directories", + "vers": "6.0.0", + "deps": [ + { + "name": "bencher", + "req": "^0.1.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "dirs-sys", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d", + "features": {}, + "yanked": false, + "pubtime": "2025-01-12T17:19:05Z" + } + ] + }, + { + "path": "di/rs/dirs-sys", + "header": "AwIAAABldGFnOiAiNDAyZTNlYmNlZjVmZDk2YzNkM2M4NjQ2ZTRmNGE1Y2IiAA==", + "records": [ + { + "name": "dirs-sys", + "vers": "0.5.0", + "deps": [ + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "option-ext", + "req": "^0.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "redox_users", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"redox\")", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.59.0", + "features": [ + "Win32_UI_Shell", + "Win32_Foundation", + "Win32_Globalization", + "Win32_System_Com" + ], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab", + "features": {}, + "yanked": false, + "pubtime": "2025-01-11T22:10:02Z" + } + ] + }, + { + "path": "di/sp/displaydoc", + "header": "AwIAAABldGFnOiAiODg0YjBkNmRjMDA3NDg2ZWJkNWVhYTc3Yjc1NmY5YmMiAA==", + "records": [ + { + "name": "displaydoc", + "vers": "0.2.7", + "deps": [ + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "pretty_assertions", + "req": "^1.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustversion", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn", + "req": "^3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "thiserror", + "req": "^1.0.24", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.71.0", + "pubtime": "2026-07-28T13:58:21Z" + } + ] + }, + { + "path": "do/cu/document-features", + "header": "AwIAAABldGFnOiAiNDM3ODcwY2Q3Y2IyMzM5MjVkOGRlZTk3NmRkMDg4ZWQiAA==", + "records": [ + { + "name": "document-features", + "vers": "0.2.12", + "deps": [ + { + "name": "litrs", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61", + "features": { + "default": [], + "self-test": [] + }, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2025-10-24T09:43:31Z" + } + ] + }, + { + "path": "du/nc/dunce", + "header": "AwIAAABldGFnOiAiZjRlNzQyNDA4MzM0YjQxMDMxNzY5NjQ0ZDlmNDZjMTciAA==", + "records": [ + { + "name": "dunce", + "vers": "1.0.5", + "deps": [], + "cksum": "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813", + "features": {}, + "yanked": false, + "pubtime": "2024-08-04T01:36:46Z" + } + ] + }, + { + "path": "dy/n-/dyn-clone", + "header": "AwIAAABldGFnOiAiZTVlNWMyMjJkNzNmOGNlZGJjYjY4MzE0ODAwNWNjNDkiAA==", + "records": [ + { + "name": "dyn-clone", + "vers": "1.0.20", + "deps": [ + { + "name": "rustversion", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.66", + "features": ["diff"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555", + "features": {}, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-07-27T19:29:46Z" + } + ] + }, + { + "path": "ei/th/either", + "header": "AwIAAABldGFnOiAiNWEyMWViZDVlYWZkYThjZTZkMDZjMjVhZDM1OGFlNzAiAA==", + "records": [ + { + "name": "either", + "vers": "1.19.0", + "deps": [ + { + "name": "serde", + "req": "^1.0.95", + "features": ["alloc", "derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be", + "features": { + "default": ["std"], + "std": [], + "use_std": ["std"] + }, + "yanked": false, + "rust_version": "1.63.0", + "pubtime": "2026-10-06T18:29:04Z" + } + ] + }, + { + "path": "en/co/encode_unicode", + "header": "AwIAAABldGFnOiAiMDFhOTk1OTEzMmIxZGYxNGIwMTk5Yzg3NGQ0MTZlZTYiAA==", + "records": [ + { + "name": "encode_unicode", + "vers": "1.0.0", + "deps": [ + { + "name": "ascii", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "lazy_static", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "dev" + }, + { + "name": "minreq", + "req": "^2.6", + "features": ["https-native"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "pubtime": "2022-08-07T14:19:49Z" + } + ] + }, + { + "path": "en/um/enum-iterator", + "header": "AwIAAABldGFnOiAiZDZiNzFjNGE2N2M0NTg1NjJiZGQ1NzFiZWI1OTUwMzUiAA==", + "records": [ + { + "name": "enum-iterator", + "vers": "2.3.0", + "deps": [ + { + "name": "enum-iterator-derive", + "req": "^1.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "a4549325971814bda7a44061bf3fe7e487d447cba01e4220a4b454d630d7a016", + "features": {}, + "yanked": false, + "pubtime": "2025-09-08T15:11:01Z" + } + ] + }, + { + "path": "en/um/enum-iterator-derive", + "header": "AwIAAABldGFnOiAiZTY2ZmM0MWE0MjkzMmU0MmRhZjkwZTYwNzM5MmZiMDciAA==", + "records": [ + { + "name": "enum-iterator-derive", + "vers": "1.5.0", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.39", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0.15", + "features": ["extra-traits"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842", + "features": {}, + "yanked": false, + "pubtime": "2025-09-08T15:10:18Z" + } + ] + }, + { + "path": "en/um/enumset", + "header": "AwIAAABldGFnOiAiYjViMWI0OGQ5OGRjNmJhNjBkZjI2MGIwMzgyNjBlYjQiAA==", + "records": [ + { + "name": "enumset", + "vers": "1.1.14", + "deps": [ + { + "name": "defmt", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "enumset_derive", + "req": "^0.15.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "ccc5801fd11762e24d1e420d01d2ac518f2a2ca4329d4fbb6639f2412b6204e0", + "features": { + "alloc": [], + "proc-macro-crate": ["enumset_derive/proc-macro-crate"], + "serde2": ["enumset_derive/serde2_deprecation_warning"], + "std": [ + "alloc", + "enumset_derive/proc-macro-crate", + "enumset_derive/std_deprecation_warning" + ] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-20T14:18:57Z" + } + ] + }, + { + "path": "en/um/enumset_derive", + "header": "AwIAAABldGFnOiAiNTkyNDdjMTA0MmFiM2VkNjA0M2NhZmMyZDlhYWU2NjAiAA==", + "records": [ + { + "name": "enumset_derive", + "vers": "0.15.0", + "deps": [ + { + "name": "darling", + "req": "^0.21.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro-crate", + "req": "^3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "4bd536557b58c682b217b8fb199afdff47cd3eff260623f19e77074eb073d63a", + "features": { + "serde2_deprecation_warning": [], + "std_deprecation_warning": [] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-05-07T02:09:58Z" + } + ] + }, + { + "path": "eq/ui/equivalent", + "header": "AwIAAABldGFnOiAiNDAzYWFhMjg5ZTc2MDhkZjExMDU4MzQ1NGEwZmQ5NTYiAA==", + "records": [ + { + "name": "equivalent", + "vers": "1.0.2", + "deps": [], + "cksum": "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f", + "features": {}, + "yanked": false, + "rust_version": "1.6", + "pubtime": "2025-02-14T22:14:18Z" + } + ] + }, + { + "path": "er/rn/errno", + "header": "AwIAAABldGFnOiAiZGJmNTUxMTljNDczZjI2MzI2MTc3NTdjNTNmZThmZjYiAA==", + "records": [ + { + "name": "errno", + "vers": "0.3.14", + "deps": [ + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os=\"hermit\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os=\"wasi\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.52, <0.62", + "features": ["Win32_Foundation", "Win32_System_Diagnostics_Debug"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb", + "features": { + "default": ["std"], + "std": ["libc/std"] + }, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2025-09-09T04:35:15Z" + } + ] + }, + { + "path": "es/ca/escape8259", + "header": "AwIAAABldGFnOiAiNjRmYzdkMDdiYjllNmU4MDBmMzVkMTQxZTM4NzEzZmYiAA==", + "records": [ + { + "name": "escape8259", + "vers": "0.5.4", + "deps": [ + { + "name": "rustversion", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "9f1f0d310082fd5de539d4f41601182241147498444a7695c520288a0cdbead6", + "features": {}, + "yanked": false, + "pubtime": "2026-10-06T04:20:01Z" + } + ] + }, + { + "path": "fa/ll/fallible-iterator", + "header": "AwIAAABldGFnOiAiYTBmOTAxOTMwMTMzNDdkYjE3MWI0NmZiMDc1NzY2NTciAA==", + "records": [ + { + "name": "fallible-iterator", + "vers": "0.2.0", + "deps": [], + "cksum": "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7", + "features": { + "alloc": [], + "default": ["std"], + "std": [] + }, + "yanked": false, + "pubtime": "2019-03-10T23:23:25Z" + } + ] + }, + { + "path": "fa/st/fastrand", + "header": "AwIAAABldGFnOiAiYWQ4OTQ0ZmNhNDRjNmNlMzE0ODhiNzEyMWY3NTMwY2EiAA==", + "records": [ + { + "name": "fastrand", + "vers": "2.5.0", + "deps": [ + { + "name": "getrandom", + "req": "^0.4", + "features": ["wasm_js"], + "optional": true, + "default_features": true, + "target": "cfg(all(any(target_arch = \"wasm32\", target_arch = \"wasm64\"), target_os = \"unknown\"))", + "kind": "normal" + }, + { + "name": "getrandom", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "getrandom", + "req": "^0.4", + "features": ["wasm_js"], + "optional": false, + "default_features": true, + "target": "cfg(all(any(target_arch = \"wasm32\", target_arch = \"wasm64\"), target_os = \"unknown\"))", + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(any(target_arch = \"wasm32\", target_arch = \"wasm64\"), target_os = \"unknown\"))", + "kind": "dev" + }, + { + "name": "wyhash", + "req": "^0.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223", + "features": { + "alloc": [], + "default": ["std"], + "js": ["std", "getrandom"], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2026-07-19T12:40:53Z" + } + ] + }, + { + "path": "fi/le/filetime", + "header": "AwIAAABldGFnOiAiYTZjYjhlZDk3MGY1N2I0ZjQzYWNlNWYzMWFhODcwZDEiAA==", + "records": [ + { + "name": "filetime", + "vers": "0.2.29", + "deps": [ + { + "name": "cfg-if", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.27", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759", + "features": {}, + "yanked": false, + "rust_version": "1.75.0", + "pubtime": "2026-05-12T22:38:22Z" + } + ] + }, + { + "path": "fi/nd/find-msvc-tools", + "header": "AwIAAABldGFnOiAiMWE5MmMxMzUyYmQ5NzFmNzJiNjI0NTFkZGE0ZDMzN2UiAA==", + "records": [ + { + "name": "find-msvc-tools", + "vers": "0.1.14", + "deps": [], + "cksum": "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484", + "features": {}, + "yanked": false, + "rust_version": "1.65.0", + "pubtime": "2026-09-25T10:09:48Z" + } + ] + }, + { + "path": "fi/xe/fixedbitset", + "header": "AwIAAABldGFnOiAiZGRmYzA0MDJmZTMwMmQyZGJmMjdkNjlhM2NjMzM0ZjQiAA==", + "records": [ + { + "name": "fixedbitset", + "vers": "0.5.7", + "deps": [ + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-04-14T23:53:05Z" + } + ] + }, + { + "path": "fl/at/flate2", + "header": "AwIAAABldGFnOiAiYjY4NjJjNmRmM2JmMzE1MWY1ZDdmMDVkZjAxZDk3MmUiAA==", + "records": [ + { + "name": "flate2", + "vers": "1.1.10", + "deps": [ + { + "name": "crc32fast", + "req": "^1.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "document-features", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "libz-ng-sys", + "req": "^1.1.16", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libz-sys", + "req": "^1.1.20", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "miniz_oxide", + "req": "^0.9.0", + "features": ["simd"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "zlib-rs", + "req": "^0.6.0", + "features": ["rust-allocator"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb", + "features": { + "any_c_zlib": ["any_zlib"], + "any_impl": [], + "any_zlib": ["any_impl"] + }, + "features2": { + "cloudflare_zlib": ["zlib"], + "default": ["rust_backend", "runtime_detection"], + "miniz-sys": ["rust_backend"], + "miniz_oxide": ["any_impl", "dep:miniz_oxide", "dep:crc32fast"], + "runtime_detection": ["zlib-rs?/std", "crc32fast?/std"], + "rust_backend": ["miniz_oxide", "any_impl"], + "zlib": ["any_c_zlib", "libz-sys", "dep:crc32fast"], + "zlib-default": ["any_c_zlib", "libz-sys/default", "dep:crc32fast"], + "zlib-ng": ["any_c_zlib", "libz-ng-sys", "dep:crc32fast"], + "zlib-ng-compat": ["zlib", "libz-sys/zlib-ng", "dep:crc32fast"], + "zlib-rs": ["any_zlib", "dep:zlib-rs"] + }, + "yanked": false, + "rust_version": "1.67.0", + "pubtime": "2026-08-28T04:35:22Z", + "v": 2 + } + ] + }, + { + "path": "fo/ld/foldhash", + "header": "AwIAAABldGFnOiAiNTA1MmZiYzJmYmM4YTY0MDJhZWZjMmU0MTc3MDA2ZjIiAA==", + "records": [ + { + "name": "foldhash", + "vers": "0.1.5", + "deps": [ + { + "name": "ahash", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "chrono", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "fxhash", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hashbrown", + "req": "^0.14", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "uuid", + "req": "^1.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-03-15T20:10:19Z" + }, + { + "name": "foldhash", + "vers": "0.2.0", + "deps": [ + { + "name": "ahash", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "chrono", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "fxhash", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hashbrown", + "req": "^0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rapidhash", + "req": "^3.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "uuid", + "req": "^1.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb", + "features": { + "default": ["std"], + "nightly": [], + "std": [] + }, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-08-23T19:14:01Z" + } + ] + }, + { + "path": "fo/rm/form_urlencoded", + "header": "AwIAAABldGFnOiAiOWZmODhiOGI4ZjZjNTJiZmUxMzNhYmQ1YTg2YTcxZmUiAA==", + "records": [ + { + "name": "form_urlencoded", + "vers": "1.2.2", + "deps": [ + { + "name": "percent-encoding", + "req": "^2.3.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf", + "features": { + "alloc": ["percent-encoding/alloc"], + "default": ["std"], + "std": ["alloc", "percent-encoding/std"] + }, + "yanked": false, + "rust_version": "1.51", + "pubtime": "2025-08-21T08:47:43Z" + } + ] + }, + { + "path": "fs/_e/fs_extra", + "header": "AwIAAABldGFnOiAiZWNmNGI2OWM0OTkzYWRjZDk0OWNlMGI5ZjA4YmQzYzAiAA==", + "records": [ + { + "name": "fs_extra", + "vers": "1.3.0", + "deps": [], + "cksum": "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c", + "features": {}, + "yanked": false, + "pubtime": "2023-02-03T17:59:27Z" + } + ] + }, + { + "path": "fs/-s/fs-set-times", + "header": "AwIAAABldGFnOiAiNzAzNzNjMDM1ZjY2ZjhkMTA1NWY1YzRkY2RkNTQ1YjAiAA==", + "records": [ + { + "name": "fs-set-times", + "vers": "0.20.3", + "deps": [ + { + "name": "io-lifetimes", + "req": "^2.0.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rustix", + "req": "^1.0.0", + "features": ["fs", "time"], + "optional": false, + "default_features": true, + "target": "cfg(not(windows))", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.52, <0.60", + "features": ["Win32_Foundation", "Win32_Storage_FileSystem"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "94e7099f6313ecacbe1256e8ff9d617b75d1bcb16a6fddef94866d225a01a14a", + "features": {}, + "yanked": false, + "pubtime": "2025-03-10T15:59:24Z" + } + ] + }, + { + "path": "fu/tu/futures", + "header": "AwIAAABldGFnOiAiOTk2ZTJlNTY4NDFlZjNjMWRlZmFkMzc5Yjc3M2EyZWMiAA==", + "records": [ + { + "name": "futures", + "vers": "0.3.34", + "deps": [ + { + "name": "assert_matches", + "req": "^1.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "futures-channel", + "req": "^0.3.34", + "features": ["sink"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-core", + "req": "^0.3.34", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-executor", + "req": "^0.3.34", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-io", + "req": "^0.3.34", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-sink", + "req": "^0.3.34", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-task", + "req": "^0.3.34", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-util", + "req": "^0.3.34", + "features": ["sink"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "pin-project", + "req": "^1.0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio", + "req": "^0.1.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3", + "features": { + "alloc": [ + "futures-core/alloc", + "futures-task/alloc", + "futures-sink/alloc", + "futures-channel/alloc", + "futures-util/alloc" + ], + "async-await": ["futures-util/async-await", "futures-util/async-await-macro"], + "bilock": ["futures-util/bilock"], + "cfg-target-has-atomic": [], + "compat": ["std", "futures-util/compat"], + "default": ["std", "async-await", "executor"], + "executor": ["std", "futures-executor/std"], + "io-compat": ["compat", "futures-util/io-compat"], + "spin": ["futures-util/spin"], + "std": [ + "alloc", + "futures-core/std", + "futures-task/std", + "futures-io/std", + "futures-sink/std", + "futures-util/std", + "futures-util/io", + "futures-util/channel" + ], + "thread-pool": ["executor", "futures-executor/thread-pool"], + "unstable": [ + "futures-core/unstable", + "futures-task/unstable", + "futures-channel/unstable", + "futures-io/unstable", + "futures-util/unstable" + ], + "write-all-vectored": ["futures-util/write-all-vectored"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-08-11T12:13:28Z" + } + ] + }, + { + "path": "fu/tu/futures-channel", + "header": "AwIAAABldGFnOiAiY2FjZjM5YTc5MWQzYjZkYmFkNTEyODRmNmZhYjZlM2EiAA==", + "records": [ + { + "name": "futures-channel", + "vers": "0.3.34", + "deps": [ + { + "name": "futures-core", + "req": "^0.3.34", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-sink", + "req": "^0.3.34", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4", + "features": { + "alloc": ["futures-core/alloc"], + "cfg-target-has-atomic": [], + "default": ["std"], + "sink": ["futures-sink"], + "std": ["alloc", "futures-core/std"], + "unstable": [] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-08-11T12:13:10Z" + } + ] + }, + { + "path": "fu/tu/futures-core", + "header": "AwIAAABldGFnOiAiMTMzNzRiYmNjOGNiN2MyYmY5MzMwODMzOWZiMmE1OTYiAA==", + "records": [ + { + "name": "futures-core", + "vers": "0.3.34", + "deps": [ + { + "name": "portable-atomic", + "req": "^1.3", + "features": ["require-cas"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e", + "features": { + "alloc": [], + "cfg-target-has-atomic": [], + "default": ["std"], + "std": ["alloc"], + "unstable": [] + }, + "yanked": false, + "rust_version": "1.36", + "pubtime": "2026-08-11T12:13:01Z" + } + ] + }, + { + "path": "fu/tu/futures-executor", + "header": "AwIAAABldGFnOiAiOTI1MzA0NTU3MDI4Y2U0NjhkZmQxNzEzZjU4NjNjZWIiAA==", + "records": [ + { + "name": "futures-executor", + "vers": "0.3.34", + "deps": [ + { + "name": "futures-core", + "req": "^0.3.34", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-task", + "req": "^0.3.34", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-util", + "req": "^0.3.34", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432", + "features": { + "default": ["std"], + "std": ["futures-core/std", "futures-task/std", "futures-util/std"], + "thread-pool": ["std"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-08-11T12:13:23Z" + } + ] + }, + { + "path": "fu/tu/futures-io", + "header": "AwIAAABldGFnOiAiNjI4YzRiODVmZDIzYzk3ZGZlOWZjNmM2OGU4NjJmZWUiAA==", + "records": [ + { + "name": "futures-io", + "vers": "0.3.34", + "deps": [], + "cksum": "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed", + "features": { + "default": ["std"], + "std": [], + "unstable": [] + }, + "yanked": false, + "rust_version": "1.36", + "pubtime": "2026-08-11T12:13:03Z" + } + ] + }, + { + "path": "fu/tu/futures-macro", + "header": "AwIAAABldGFnOiAiZWU1NjVjNWJkMzgzN2NkNDgyMDYyMzYyOTZmNTFjN2UiAA==", + "records": [ + { + "name": "futures-macro", + "vers": "0.3.34", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.60", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3.0", + "features": ["full"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-08-11T12:13:14Z" + } + ] + }, + { + "path": "fu/tu/futures-sink", + "header": "AwIAAABldGFnOiAiN2FkNWMzZmE4M2Q4MTg4YTUxMTU4MThiMjhhNzI5YTQiAA==", + "records": [ + { + "name": "futures-sink", + "vers": "0.3.34", + "deps": [], + "cksum": "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d", + "features": { + "alloc": [], + "default": ["std"], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.36", + "pubtime": "2026-08-11T12:13:06Z" + } + ] + }, + { + "path": "fu/tu/futures-task", + "header": "AwIAAABldGFnOiAiY2U3ZjZkMmQwNzIzMWViMTcwZDkzOTE1ODk5MzZhODAiAA==", + "records": [ + { + "name": "futures-task", + "vers": "0.3.34", + "deps": [], + "cksum": "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd", + "features": { + "alloc": [], + "cfg-target-has-atomic": [], + "default": ["std"], + "std": ["alloc"], + "unstable": [] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-08-11T12:13:07Z" + } + ] + }, + { + "path": "fu/tu/futures-util", + "header": "AwIAAABldGFnOiAiMmYxMTVlMjMzOGQzMjExYWUzNzZlNDNlYWY3MmIwNjMiAA==", + "records": [ + { + "name": "futures-util", + "vers": "0.3.34", + "deps": [ + { + "name": "futures-channel", + "req": "^0.3.34", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-core", + "req": "^0.3.34", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-io", + "req": "^0.3.34", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-macro", + "req": "=0.3.34", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-sink", + "req": "^0.3.34", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-task", + "req": "^0.3.34", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures_01", + "req": "^0.1.25", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "futures" + }, + { + "name": "libc", + "req": "^0.2.26", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memchr", + "req": "^2.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pin-project-lite", + "req": "^0.2.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "portable-atomic-util", + "req": "^0.2.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "portable_atomic_crate", + "req": "^1.13.1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "portable-atomic" + }, + { + "name": "slab", + "req": "^0.4.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "spin", + "req": "^0.12.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^0.1.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-io", + "req": "^0.1.9", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc", + "features": { + "alloc": ["futures-core/alloc", "futures-task/alloc", "slab"], + "async-await": [], + "async-await-macro": ["async-await", "futures-macro"], + "bilock": [], + "cfg-target-has-atomic": [], + "channel": ["std", "futures-channel"], + "compat": ["std", "futures_01", "libc"], + "default": ["std", "async-await", "async-await-macro"], + "io": ["std", "futures-io", "memchr"], + "io-compat": ["io", "compat", "tokio-io", "libc"], + "portable-atomic": ["futures-core/portable-atomic", "portable_atomic_crate"], + "portable-atomic-alloc": ["portable-atomic-util/alloc", "portable-atomic"], + "sink": ["futures-sink"], + "std": ["alloc", "futures-core/std", "futures-task/std", "slab/std"], + "unstable": ["futures-core/unstable", "futures-task/unstable"], + "write-all-vectored": ["io"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-08-11T12:13:19Z" + } + ] + }, + { + "path": "ge/ne/generic-array", + "header": "AwIAAABldGFnOiAiOGE0ZTFiYmVmNjI4NjM0Mjc2MzI2NWZiYWUyNGU0ZjEiAA==", + "records": [ + { + "name": "generic-array", + "vers": "0.14.7", + "deps": [ + { + "name": "bincode", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "typenum", + "req": "^1.12", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "version_check", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "zeroize", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a", + "features": { + "more_lengths": [] + }, + "yanked": false, + "pubtime": "2023-03-28T00:01:29Z" + } + ] + }, + { + "path": "ge/tr/getrandom", + "header": "AwIAAABldGFnOiAiNjM1OWY3YmUyMGQ5YjdlYjUxZDIwODNmZTNmYjZlMjQiAA==", + "records": [ + { + "name": "getrandom", + "vers": "0.3.4", + "deps": [ + { + "name": "cfg-if", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "js-sys", + "req": "^0.3.77", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\"), target_feature = \"atomics\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(any(target_os = \"linux\", target_os = \"android\"), not(any(all(target_os = \"linux\", target_env = \"\"), getrandom_backend = \"custom\", getrandom_backend = \"linux_raw\", getrandom_backend = \"rdrand\", getrandom_backend = \"rndr\"))))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"hurd\", target_os = \"illumos\", target_os = \"cygwin\", all(target_os = \"horizon\", target_arch = \"arm\")))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"haiku\", target_os = \"redox\", target_os = \"nto\", target_os = \"aix\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"ios\", target_os = \"visionos\", target_os = \"watchos\", target_os = \"tvos\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"macos\", target_os = \"openbsd\", target_os = \"vita\", target_os = \"emscripten\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"netbsd\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"solaris\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"vxworks\")", + "kind": "normal" + }, + { + "name": "r-efi", + "req": "^5.1", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_os = \"uefi\", getrandom_backend = \"efi_rng\"))", + "kind": "normal" + }, + { + "name": "wasip2", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_arch = \"wasm32\", target_os = \"wasi\", target_env = \"p2\"))", + "kind": "normal" + }, + { + "name": "wasm-bindgen", + "req": "^0.2.98", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\")))", + "kind": "normal" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\")))", + "kind": "dev" + } + ], + "cksum": "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd", + "features": { + "std": [] + }, + "features2": { + "wasm_js": ["dep:wasm-bindgen", "dep:js-sys"] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2025-10-14T17:47:36Z", + "v": 2 + }, + { + "name": "getrandom", + "vers": "0.4.3", + "deps": [ + { + "name": "cfg-if", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "js-sys", + "req": "^0.3.77", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(target_family = \"wasm\", any(target_os = \"unknown\", target_os = \"none\"), target_feature = \"atomics\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(any(target_os = \"linux\", target_os = \"android\"), not(any(all(target_os = \"linux\", target_env = \"\"), getrandom_backend = \"custom\", getrandom_backend = \"linux_raw\", getrandom_backend = \"rdrand\", getrandom_backend = \"rndr\"))))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"hurd\", target_os = \"illumos\", target_os = \"cygwin\", all(target_os = \"horizon\", target_arch = \"arm\")))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"haiku\", target_os = \"redox\", target_os = \"nto\", target_os = \"aix\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"ios\", target_os = \"visionos\", target_os = \"watchos\", target_os = \"tvos\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"macos\", target_os = \"openbsd\", target_os = \"vita\", target_os = \"emscripten\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"netbsd\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"solaris\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"vxworks\")", + "kind": "normal" + }, + { + "name": "r-efi", + "req": "^6", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_os = \"uefi\", getrandom_backend = \"efi_rng\"))", + "kind": "normal" + }, + { + "name": "rand_core", + "req": "^0.10.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasm-bindgen", + "req": "^0.2.98", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(target_family = \"wasm\", any(target_os = \"unknown\", target_os = \"none\")))", + "kind": "normal" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_family = \"wasm\", any(target_os = \"unknown\", target_os = \"none\")))", + "kind": "dev" + } + ], + "cksum": "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099", + "features": { + "std": [] + }, + "features2": { + "sys_rng": ["dep:rand_core"], + "wasm_js": ["dep:wasm-bindgen", "dep:js-sys"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-06-17T18:01:59Z", + "v": 2 + } + ] + }, + { + "path": "gi/ml/gimli", + "header": "AwIAAABldGFnOiAiM2UwN2EwYjk5YjBlMjBhOGIwZjc5MTA0OTMyZmM2YjQiAA==", + "records": [ + { + "name": "gimli", + "vers": "0.32.3", + "deps": [ + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "fallible-iterator", + "req": "^0.3.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "stable_deref_trait", + "req": "^1.1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "test-assembler", + "req": "^0.1.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7", + "features": { + "read": ["read-core"], + "read-core": [] + }, + "features2": { + "default": ["read-all", "write"], + "endian-reader": ["read", "dep:stable_deref_trait"], + "fallible-iterator": ["dep:fallible-iterator"], + "read-all": ["read", "std", "fallible-iterator", "endian-reader"], + "rustc-dep-of-std": ["dep:core", "dep:alloc"], + "std": ["fallible-iterator?/std", "stable_deref_trait?/std"], + "write": ["dep:indexmap"] + }, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-09-13T02:44:33Z", + "v": 2 + }, + { + "name": "gimli", + "vers": "0.33.0", + "deps": [ + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "criterion", + "req": "^0.8.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "fallible-iterator", + "req": "^0.3.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "fnv", + "req": "^1.0.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "hashbrown", + "req": "^0.16.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2.0.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "stable_deref_trait", + "req": "^1.1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "test-assembler", + "req": "^0.1.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "0bf7f043f89559805f8c7cacc432749b2fa0d0a0a9ee46ce47164ed5ba7f126c", + "features": { + "read": ["read-core"], + "read-core": [] + }, + "features2": { + "default": ["read-all", "write"], + "endian-reader": ["read", "dep:stable_deref_trait"], + "fallible-iterator": ["dep:fallible-iterator"], + "read-all": ["read", "std", "endian-reader"], + "rustc-dep-of-std": ["dep:core", "dep:alloc"], + "std": ["stable_deref_trait?/std"], + "write": ["dep:fnv", "dep:hashbrown", "dep:indexmap"] + }, + "yanked": false, + "rust_version": "1.88", + "pubtime": "2026-01-24T05:33:59Z", + "v": 2 + } + ] + }, + { + "path": "gl/ob/glob", + "header": "AwIAAABldGFnOiAiYmFmZGE4MzdhNjQ5M2FkYWMwMWUzMTAyZDcxZWY0ZTkiAA==", + "records": [ + { + "name": "glob", + "vers": "0.3.4", + "deps": [ + { + "name": "doc-comment", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tempfile", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b", + "features": {}, + "yanked": false, + "rust_version": "1.63.0", + "pubtime": "2026-07-21T14:53:49Z" + } + ] + }, + { + "path": "gl/ob/globset", + "header": "AwIAAABldGFnOiAiOGI0MTgxN2VhNmI4Y2Q4YzIzYTM2Y2FjNmQ2NWQ4NzMiAA==", + "records": [ + { + "name": "globset", + "vers": "0.4.20", + "deps": [ + { + "name": "aho-corasick", + "req": "^1.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "arbitrary", + "req": "^1.3.2", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bstr", + "req": "^1.6.2", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "glob", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "log", + "req": "^0.4.20", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "regex-automata", + "req": "^0.4.18", + "features": ["std", "perf", "syntax", "meta", "nfa", "hybrid"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "regex-syntax", + "req": "^0.8.0", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.188", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.107", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "07c34a9410465b45bd9787443bc7370f37735bad04b0f0cd57ff1a3186c98988", + "features": { + "default": ["log"], + "serde1": ["serde"], + "simd-accel": [] + }, + "features2": { + "arbitrary": ["dep:arbitrary"] + }, + "yanked": false, + "rust_version": "1.88", + "pubtime": "2026-08-04T13:59:29Z", + "v": 2 + } + ] + }, + { + "path": "ha/lf/half", + "header": "AwIAAABldGFnOiAiOGE2ZTcxZTMwMzM0YTBkZThmMTE2MzE1ZWY4YmQ4ODQiAA==", + "records": [ + { + "name": "half", + "vers": "2.7.1", + "deps": [ + { + "name": "arbitrary", + "req": "^1.4.1", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytemuck", + "req": "^1.4.1", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "criterion", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "crunchy", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"spirv\")", + "kind": "normal" + }, + { + "name": "crunchy", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "num-traits", + "req": "^0.2.16", + "features": ["libm"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quickcheck_macros", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9.0", + "features": ["thread_rng"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.9.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand_distr", + "req": "^0.5.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rkyv", + "req": "^0.8.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerocopy", + "req": "^0.8.26", + "features": ["derive", "simd"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b", + "features": { + "alloc": [], + "default": ["std"], + "nightly": [], + "std": ["alloc"], + "use-intrinsics": [], + "zerocopy": [] + }, + "features2": { + "rand_distr": ["dep:rand", "dep:rand_distr"] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2025-10-14T03:59:26Z", + "v": 2 + } + ] + }, + { + "path": "ha/sh/hash32", + "header": "AwIAAABldGFnOiAiN2U1NGQ3YzYxZDNkYWM3ZjVjNTNlZjFiMDYxMDZmOTciAA==", + "records": [ + { + "name": "hash32", + "vers": "0.3.1", + "deps": [ + { + "name": "byteorder", + "req": "^1.2.2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606", + "features": {}, + "yanked": false, + "pubtime": "2022-08-09T13:44:28Z" + } + ] + }, + { + "path": "ha/sh/hashbrown", + "header": "AwIAAABldGFnOiAiZDg0ZDljN2I3NTVmYmRkYzg4OTJlN2M4NWNlMDEwYzQiAA==", + "records": [ + { + "name": "hashbrown", + "vers": "0.14.5", + "deps": [ + { + "name": "ahash", + "req": "^0.8.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "allocator-api2", + "req": "^0.2.9", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "bumpalo", + "req": "^3.13.0", + "features": ["allocator-api2"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "compiler_builtins", + "req": "^0.1.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "doc-comment", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "equivalent", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "fnv", + "req": "^1.0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "lazy_static", + "req": "^1.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.8.3", + "features": ["small_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rkyv", + "req": "^0.7.42", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rkyv", + "req": "^0.7.42", + "features": ["validation"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.25", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_test", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1", + "features": { + "default": ["ahash", "inline-more", "allocator-api2"], + "inline-more": [], + "raw": [], + "rustc-internal-api": [] + }, + "features2": { + "nightly": ["allocator-api2?/nightly", "bumpalo/allocator_api"], + "rustc-dep-of-std": [ + "nightly", + "core", + "compiler_builtins", + "alloc", + "rustc-internal-api" + ] + }, + "yanked": false, + "rust_version": "1.63.0", + "pubtime": "2024-04-28T18:32:09Z", + "v": 2 + }, + { + "name": "hashbrown", + "vers": "0.15.5", + "deps": [ + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "allocator-api2", + "req": "^0.2.9", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "bumpalo", + "req": "^3.13.0", + "features": ["allocator-api2"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "doc-comment", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "equivalent", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "fnv", + "req": "^1.0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "foldhash", + "req": "^0.1.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "lazy_static", + "req": "^1.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9.0", + "features": ["small_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "^1.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.25", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_test", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1", + "features": { + "inline-more": [], + "nightly": ["bumpalo/allocator_api"], + "raw-entry": [], + "rustc-dep-of-std": ["nightly", "core", "alloc", "rustc-internal-api"], + "rustc-internal-api": [] + }, + "features2": { + "default": [ + "default-hasher", + "inline-more", + "allocator-api2", + "equivalent", + "raw-entry" + ], + "default-hasher": ["dep:foldhash"] + }, + "yanked": false, + "rust_version": "1.65.0", + "pubtime": "2025-08-07T23:58:32Z", + "v": 2 + }, + { + "name": "hashbrown", + "vers": "0.16.1", + "deps": [ + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "allocator-api2", + "req": "^0.2.9", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "bumpalo", + "req": "^3.13.0", + "features": ["allocator-api2"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "equivalent", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "fnv", + "req": "^1.0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "foldhash", + "req": "^0.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "lazy_static", + "req": "^1.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9.0", + "features": ["small_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "^1.9.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(any())", + "kind": "normal" + }, + { + "name": "serde_core", + "req": "^1.0.221", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_test", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100", + "features": { + "inline-more": [], + "raw-entry": [], + "rustc-internal-api": [] + }, + "features2": { + "default": [ + "default-hasher", + "inline-more", + "allocator-api2", + "equivalent", + "raw-entry" + ], + "default-hasher": ["dep:foldhash"], + "nightly": ["foldhash?/nightly", "bumpalo/allocator_api"], + "rustc-dep-of-std": ["nightly", "core", "alloc", "rustc-internal-api"], + "serde": ["dep:serde_core", "dep:serde"] + }, + "yanked": false, + "rust_version": "1.65.0", + "pubtime": "2025-11-20T16:47:18Z", + "v": 2 + }, + { + "name": "hashbrown", + "vers": "0.17.1", + "deps": [ + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "allocator-api2", + "req": "^0.2.9", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "bumpalo", + "req": "^3.13.0", + "features": ["allocator-api2"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "criterion", + "req": "^0.7", + "features": ["html_reports"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "equivalent", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "fnv", + "req": "^1.0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "foldhash", + "req": "^0.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9.0", + "features": ["small_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "^1.9.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(any())", + "kind": "normal" + }, + { + "name": "serde_core", + "req": "^1.0.221", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_test", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a", + "features": { + "inline-more": [], + "raw-entry": [], + "rustc-internal-api": [] + }, + "features2": { + "default": [ + "default-hasher", + "inline-more", + "allocator-api2", + "equivalent", + "raw-entry" + ], + "default-hasher": ["dep:foldhash"], + "nightly": ["foldhash?/nightly", "bumpalo/allocator_api"], + "rustc-dep-of-std": ["nightly", "core", "alloc", "rustc-internal-api"], + "serde": ["dep:serde_core", "dep:serde"] + }, + "yanked": false, + "rust_version": "1.85.0", + "pubtime": "2026-05-09T04:35:04Z", + "v": 2 + } + ] + }, + { + "path": "he/ap/heapless", + "header": "AwIAAABldGFnOiAiNjgwMGFlOGU3YTA2MjBmZTNmZTIyMjRlYzhmODI2MzYiAA==", + "records": [ + { + "name": "heapless", + "vers": "0.9.3", + "deps": [ + { + "name": "bytes", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "critical-section", + "req": "^1.1", + "features": ["std"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "defmt", + "req": "^1.0.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "embedded-io", + "req": "^0.7", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hash32", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "portable-atomic", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_core", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "stable_deref_trait", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_arch = \"arm\", target_pointer_width = \"32\", target_pointer_width = \"64\"))", + "kind": "normal" + }, + { + "name": "static_assertions", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ufmt", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ufmt-write", + "req": "^0.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "zeroize", + "req": "^1.8", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "25ba4bd83f9415b58b4ed8dc5714c76e626a105be4646c02630ad730ad3b5aa4", + "features": { + "alloc": [], + "mpmc_large": [], + "nightly": [] + }, + "features2": { + "bytes": ["dep:bytes"], + "defmt": ["dep:defmt"], + "embedded-io-v0.7": ["dep:embedded-io"], + "portable-atomic": ["dep:portable-atomic"], + "portable-atomic-critical-section": [ + "dep:portable-atomic", + "portable-atomic", + "portable-atomic?/critical-section" + ], + "portable-atomic-unsafe-assume-single-core": [ + "dep:portable-atomic", + "portable-atomic", + "portable-atomic?/unsafe-assume-single-core" + ], + "serde": ["dep:serde_core"], + "ufmt": ["dep:ufmt", "dep:ufmt-write"], + "zeroize": ["dep:zeroize"] + }, + "yanked": false, + "rust_version": "1.87", + "pubtime": "2026-04-30T21:21:52Z", + "v": 2 + } + ] + }, + { + "path": "he/ck/heck", + "header": "AwIAAABldGFnOiAiN2UwZWRjOGEzMGNjNzYwMDhhZmM0NzkwZTQwMDE1ODkiAA==", + "records": [ + { + "name": "heck", + "vers": "0.3.3", + "deps": [ + { + "name": "unicode-segmentation", + "req": "^1.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c", + "features": {}, + "yanked": false, + "pubtime": "2021-06-02T20:40:39Z" + }, + { + "name": "heck", + "vers": "0.5.0", + "deps": [], + "cksum": "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-03-12T22:42:23Z" + } + ] + }, + { + "path": "he/rm/hermit-abi", + "header": "AwIAAABldGFnOiAiOTQ5Y2E5MWU3OTg0NTU4NmNkZDI1ZTQ3ZTdiOGMwMDUiAA==", + "records": [ + { + "name": "hermit-abi", + "vers": "0.5.3", + "deps": [ + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + } + ], + "cksum": "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284", + "features": { + "default": [], + "rustc-dep-of-std": ["core", "alloc"] + }, + "yanked": false, + "pubtime": "2026-08-31T11:45:18Z" + } + ] + }, + { + "path": "hm/ac/hmac", + "header": "AwIAAABldGFnOiAiYWIyZTAxZDljMmQ0ODUzN2NlOTEyOWQ5ODNlYTNjNDkiAA==", + "records": [ + { + "name": "hmac", + "vers": "0.13.0", + "deps": [ + { + "name": "digest", + "req": "^0.11.2", + "features": ["mac"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "digest", + "req": "^0.11.2", + "features": ["dev"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hex-literal", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "md-5", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "sha1", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "sha2", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "streebog", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + } + ], + "cksum": "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f", + "features": { + "zeroize": ["digest/zeroize"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-03-29T23:19:21Z" + } + ] + }, + { + "path": "ht/tp/http", + "header": "AwIAAABldGFnOiAiNTgzYThmZDdhOTMxZDBlMGM2Yjg5ZWNhZGFmYWFiMmEiAA==", + "records": [ + { + "name": "http", + "vers": "1.5.0", + "deps": [ + { + "name": "bytes", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "doc-comment", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "itoa", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.57.0", + "pubtime": "2026-07-29T14:57:21Z" + } + ] + }, + { + "path": "hy/br/hybrid-array", + "header": "AwIAAABldGFnOiAiNjAyM2NiMzU1MTE2MTc4YWEyMGE0NGM3MTAwYmNhZTYiAA==", + "records": [ + { + "name": "hybrid-array", + "vers": "0.4.15", + "deps": [ + { + "name": "arbitrary", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytemuck", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "ctutils", + "req": "^0.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "subtle", + "req": "^2", + "features": ["const-generics"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "typenum", + "req": "^1.20", + "features": ["const-generics"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "zerocopy", + "req": "^0.8", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "zeroize", + "req": "^1.8", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17", + "features": { + "alloc": [], + "extra-sizes": [] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-09-08T18:21:39Z" + } + ] + }, + { + "path": "ic/u_/icu_collections", + "header": "AwIAAABldGFnOiAiYmRkNjRjMDZlMThiOTlmOGE5MjcwNmM2YTBjNDBjYzIiAA==", + "records": [ + { + "name": "icu_collections", + "vers": "2.3.0", + "deps": [ + { + "name": "criterion", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "databake", + "req": "^0.2.0", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "displaydoc", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "iai", + "req": "^0.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "postcard", + "req": "^1.0.3", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "potential_utf", + "req": "^0.1.3", + "features": ["zerovec"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0.45", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml", + "req": "^0.8.0", + "features": ["parse"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "utf8_iter", + "req": "^1.0.2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "yoke", + "req": "^0.8.3", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerofrom", + "req": "^0.1.6", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerovec", + "req": "^0.11.7", + "features": ["derive", "yoke"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513", + "features": {}, + "features2": { + "alloc": ["serde?/alloc", "zerovec/alloc"], + "databake": ["dep:databake", "zerovec/databake"], + "serde": ["dep:serde", "zerovec/serde", "potential_utf/serde", "alloc"] + }, + "yanked": false, + "rust_version": "1.88", + "pubtime": "2026-08-13T23:28:40Z", + "v": 2 + } + ] + }, + { + "path": "ic/u_/icu_locale_core", + "header": "AwIAAABldGFnOiAiYjcwYjA4MTE5OGRkZjhlOWE2YTBhNTY4ODBhMWExOTciAA==", + "records": [ + { + "name": "icu_locale_core", + "vers": "2.3.0", + "deps": [ + { + "name": "criterion", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "databake", + "req": "^0.2.0", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "displaydoc", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "iai", + "req": "^0.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "litemap", + "req": "^0.8.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "litemap", + "req": "^0.8.0", + "features": ["testing"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "postcard", + "req": "^1.0.3", + "features": ["use-std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "potential_utf", + "req": "^0.1.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0.45", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tinystr", + "req": "^0.8.4", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "writeable", + "req": "^0.6.4", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerovec", + "req": "^0.11.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb", + "features": {}, + "features2": { + "alloc": ["litemap/alloc", "tinystr/alloc", "writeable/alloc", "serde?/alloc"], + "databake": ["dep:databake", "alloc"], + "serde": ["dep:serde", "tinystr/serde"], + "zerovec": ["dep:zerovec", "tinystr/zerovec"] + }, + "yanked": false, + "rust_version": "1.88", + "pubtime": "2026-08-13T23:28:12Z", + "v": 2 + } + ] + }, + { + "path": "ic/u_/icu_normalizer", + "header": "AwIAAABldGFnOiAiNWQzOTM1MjZlNDEwMDEzYTczNGNlMWE5MTRiZWRlYzYiAA==", + "records": [ + { + "name": "icu_normalizer", + "vers": "2.3.0", + "deps": [ + { + "name": "atoi", + "req": "^2.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "databake", + "req": "^0.2.0", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "detone", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "harfbuzz-traits", + "req": "^0.6.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "icu_collections", + "req": "~2.3.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "icu_normalizer_data", + "req": "~2.3.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "icu_properties", + "req": "~2.3.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "icu_provider", + "req": "^2.3.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": ["derive", "alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "smallvec", + "req": "^1.10.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "utf16_iter", + "req": "^1.0.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "utf8_iter", + "req": "^1.0.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "write16", + "req": "^1.0.0", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "write16", + "req": "^1.0.0", + "features": ["arrayvec", "smallvec"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "zerovec", + "req": "^0.11.7", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f", + "features": { + "write16": [] + }, + "features2": { + "compiled_data": [ + "dep:icu_normalizer_data", + "icu_properties?/compiled_data", + "icu_provider/baked" + ], + "datagen": [ + "serde", + "dep:databake", + "icu_properties", + "icu_collections/databake", + "zerovec/databake", + "icu_properties?/datagen", + "icu_provider/export" + ], + "default": ["compiled_data", "utf8_iter", "utf16_iter"], + "harfbuzz_traits": ["dep:harfbuzz-traits"], + "icu_properties": ["dep:icu_properties"], + "serde": [ + "dep:serde", + "icu_collections/serde", + "zerovec/serde", + "icu_properties?/serde", + "icu_provider/serde" + ], + "utf16_iter": ["dep:utf16_iter", "dep:write16"], + "utf8_iter": ["dep:utf8_iter"] + }, + "yanked": false, + "rust_version": "1.88", + "pubtime": "2026-08-13T23:28:56Z", + "v": 2 + } + ] + }, + { + "path": "ic/u_/icu_normalizer_data", + "header": "AwIAAABldGFnOiAiMDA2MjAyZDIzNDM5MDMyOGE2ZTA0YmE1N2JmZDVhZDQiAA==", + "records": [ + { + "name": "icu_normalizer_data", + "vers": "2.3.0", + "deps": [], + "cksum": "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0", + "features": {}, + "yanked": false, + "rust_version": "1.88", + "pubtime": "2026-08-13T23:28:53Z" + } + ] + }, + { + "path": "ic/u_/icu_properties", + "header": "AwIAAABldGFnOiAiOTRkMWNiYWQ1ZjcwOGI1MWI0YzNmYTZlYmI4MGQ0ZDMiAA==", + "records": [ + { + "name": "icu_properties", + "vers": "2.3.0", + "deps": [ + { + "name": "databake", + "req": "^0.2.0", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "displaydoc", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "harfbuzz-traits", + "req": "^0.6.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "icu_collections", + "req": "~2.3.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "icu_locale_core", + "req": "^2.3.0", + "features": ["zerovec"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "icu_properties_data", + "req": "~2.3.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "icu_provider", + "req": "^2.3.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "log", + "req": "^0.4.17", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "unicode-bidi", + "req": "^0.3.11", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerotrie", + "req": "^0.2.5", + "features": ["yoke", "zerofrom"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerovec", + "req": "^0.11.7", + "features": ["derive", "yoke"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148", + "features": { + "unstable": [] + }, + "features2": { + "alloc": ["zerovec/alloc", "icu_collections/alloc", "serde?/alloc"], + "compiled_data": ["dep:icu_properties_data", "icu_provider/baked"], + "datagen": [ + "serde", + "dep:databake", + "zerovec/databake", + "icu_collections/databake", + "icu_locale_core/databake", + "zerotrie/databake", + "icu_provider/export" + ], + "default": ["compiled_data"], + "harfbuzz_traits": ["dep:harfbuzz-traits"], + "log": ["dep:log"], + "serde": [ + "dep:serde", + "icu_locale_core/serde", + "zerovec/serde", + "icu_collections/serde", + "icu_provider/serde", + "zerotrie/serde" + ], + "unicode_bidi": ["dep:unicode-bidi"] + }, + "yanked": false, + "rust_version": "1.88", + "pubtime": "2026-08-13T23:28:46Z", + "v": 2 + } + ] + }, + { + "path": "ic/u_/icu_properties_data", + "header": "AwIAAABldGFnOiAiODBmYzMzYmQ1OTQwNmI1MjIzZWU3Y2E5MTQ4MDM0ZDEiAA==", + "records": [ + { + "name": "icu_properties_data", + "vers": "2.3.0", + "deps": [], + "cksum": "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa", + "features": {}, + "yanked": false, + "rust_version": "1.88", + "pubtime": "2026-08-13T23:28:42Z" + } + ] + }, + { + "path": "ic/u_/icu_provider", + "header": "AwIAAABldGFnOiAiNzNmYzhjOGQ4MTdlZDg4YzJlMDIyZTI3MGQ5NzY2MGYiAA==", + "records": [ + { + "name": "icu_provider", + "vers": "2.3.1", + "deps": [ + { + "name": "bincode", + "req": "^1.3.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "criterion", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "databake", + "req": "^0.2.0", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "displaydoc", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "erased-serde", + "req": "^0.4.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "icu_locale_core", + "req": "^2.3.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "log", + "req": "^0.4.17", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "postcard", + "req": "^1.0.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.45", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.45", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "stable_deref_trait", + "req": "^1.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "writeable", + "req": "^0.6.4", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "yoke", + "req": "^0.8.3", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerofrom", + "req": "^0.1.6", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerotrie", + "req": "^0.2.5", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerovec", + "req": "^0.11.8", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73", + "features": { + "sync": [], + "zerotrie": [] + }, + "features2": { + "alloc": [ + "icu_locale_core/alloc", + "serde?/alloc", + "yoke/alloc", + "zerofrom/alloc", + "zerovec/alloc", + "zerotrie?/alloc", + "dep:stable_deref_trait", + "dep:writeable" + ], + "baked": ["dep:zerotrie", "dep:writeable"], + "deserialize_bincode_1": ["serde", "dep:bincode", "std"], + "deserialize_json": ["serde", "dep:serde_json"], + "deserialize_postcard_1": ["serde", "dep:postcard"], + "export": [ + "serde", + "dep:erased-serde", + "dep:databake", + "std", + "sync", + "dep:postcard", + "zerovec/databake" + ], + "logging": ["dep:log"], + "serde": ["dep:serde", "yoke/serde"], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.88", + "pubtime": "2026-08-20T23:25:32Z", + "v": 2 + } + ] + }, + { + "path": "id/-a/id-arena", + "header": "AwIAAABldGFnOiAiMzlkZGQxYmZhMzNiMDI0ODljNDQ1NjFhMTgzMmI0NTIiAA==", + "records": [ + { + "name": "id-arena", + "vers": "2.3.0", + "deps": [ + { + "name": "rayon", + "req": "^1.0.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "pubtime": "2026-01-14T21:40:46Z" + } + ] + }, + { + "path": "id/en/ident_case", + "header": "AwIAAABldGFnOiAiNDQyYTkyZTMzNzExNDAwMmRmNGNjYTdiYmUwY2Y3YTUiAA==", + "records": [ + { + "name": "ident_case", + "vers": "1.0.1", + "deps": [], + "cksum": "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39", + "features": {}, + "yanked": false, + "pubtime": "2019-03-18T20:07:20Z" + } + ] + }, + { + "path": "id/na/idna", + "header": "AwIAAABldGFnOiAiNDhmY2Q5MzEwYjFmYmY4M2UyMDEwZWJmMWVmMjhmODAiAA==", + "records": [ + { + "name": "idna", + "vers": "1.1.0", + "deps": [ + { + "name": "assert_matches", + "req": "^1.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "bencher", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "idna_adapter", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "smallvec", + "req": "^1.13.1", + "features": ["const_generics"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tester", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "utf8_iter", + "req": "^1.0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de", + "features": { + "alloc": [], + "compiled_data": ["idna_adapter/compiled_data"], + "default": ["std", "compiled_data"], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.57", + "pubtime": "2025-08-21T08:48:20Z" + } + ] + }, + { + "path": "id/na/idna_adapter", + "header": "AwIAAABldGFnOiAiOTk4OGRiMjVjNGQ0ODBmMmM0ZDU2MWQ4NTJkYjhiY2UiAA==", + "records": [ + { + "name": "idna_adapter", + "vers": "1.2.2", + "deps": [ + { + "name": "icu_normalizer", + "req": "^2.2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "icu_properties", + "req": "^2.2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714", + "features": { + "compiled_data": ["icu_normalizer/compiled_data", "icu_properties/compiled_data"] + }, + "yanked": false, + "rust_version": "1.86", + "pubtime": "2026-04-27T17:45:54Z" + } + ] + }, + { + "path": "ig/no/ignore", + "header": "AwIAAABldGFnOiAiYzZkYzVlNjVmMjY1OWYyZWIxOGMzOTM5YjI4OGEzZDgiAA==", + "records": [ + { + "name": "ignore", + "vers": "0.4.33", + "deps": [ + { + "name": "bstr", + "req": "^1.6.2", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "crossbeam-channel", + "req": "^0.5.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "crossbeam-deque", + "req": "^0.8.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "globset", + "req": "^0.4.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "log", + "req": "^0.4.20", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memchr", + "req": "^2.6.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "regex-automata", + "req": "^0.4.18", + "features": ["std", "perf", "syntax", "meta", "nfa", "hybrid", "dfa-onepass"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "same-file", + "req": "^1.0.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "walkdir", + "req": "^2.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "winapi-util", + "req": "^0.1.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "00b69833ed729dc5aa7d19541d96d6cf8e9137194207a04916d658e43168402f", + "features": { + "simd-accel": [] + }, + "yanked": false, + "rust_version": "1.88", + "pubtime": "2026-08-04T13:59:40Z" + } + ] + }, + { + "path": "in/de/indexmap", + "header": "AwIAAABldGFnOiAiYjA1YTBkYjBhYTUzMTAzY2NhMDI0ZWFiZGI4NDExOTAiAA==", + "records": [ + { + "name": "indexmap", + "vers": "2.14.2", + "deps": [ + { + "name": "arbitrary", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "borsh", + "req": "^1.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "equivalent", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "fastrand", + "req": "^2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "fnv", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hashbrown", + "req": "^0.17", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "itertools", + "req": "^0.14", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quickcheck", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "^1.9", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(any())", + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "sval", + "req": "^2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855", + "features": { + "default": ["std"], + "std": [], + "test_debug": [] + }, + "features2": { + "serde": ["dep:serde_core", "dep:serde"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-09-05T01:53:48Z", + "v": 2 + } + ] + }, + { + "path": "in/st/insta", + "header": "AwIAAABldGFnOiAiZTlmZmRlMjkyN2UzOGUxZmZhNzJhZTNjYTk0NzU4OWMiAA==", + "records": [ + { + "name": "insta", + "vers": "1.49.0", + "deps": [ + { + "name": "clap", + "req": "^4.1", + "features": ["derive", "env"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "console", + "req": "^0.16", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "csv", + "req": "^1.1.6", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "globset", + "req": "^0.4.6", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "once_cell", + "req": "^1.20.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pest", + "req": "^2.1.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pest_derive", + "req": "^2.1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "regex", + "req": "^1.6.0", + "features": ["std", "unicode"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "ron", + "req": "^0.12.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustc_version", + "req": "^0.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.117", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.117", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "similar", + "req": "^2.1.0", + "features": ["inline"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "similar-asserts", + "req": "^1.4.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "strip-ansi-escapes", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "toml_edit", + "req": "^0.25.0", + "features": ["serde", "parse", "display"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "toml_writer", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "walkdir", + "req": "^2.3.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "b67d3d2e287e4b86c10b3f3b641033d1f89b74bdb39d05f34952e2b9a6fe21cd", + "features": { + "_cargo_insta_internal": ["clap"], + "colors": ["console"], + "default": ["colors"], + "filters": ["regex", "strip-ansi-escapes"], + "glob": ["walkdir", "globset"], + "json": ["serde"], + "redactions": ["pest", "pest_derive", "serde"], + "yaml": ["serde"] + }, + "features2": { + "csv": ["dep:csv", "serde"], + "ron": ["dep:ron", "serde"], + "toml": ["dep:toml_edit", "dep:toml_writer", "serde"] + }, + "yanked": false, + "rust_version": "1.66.0", + "pubtime": "2026-10-03T01:12:59Z", + "v": 2 + } + ] + }, + { + "path": "io/-e/io-extras", + "header": "AwIAAABldGFnOiAiNDgyNzk0MTEwNThjOTY3ZjM2YTE5ZTBmNmNjNzU3NDQiAA==", + "records": [ + { + "name": "io-extras", + "vers": "0.19.0", + "deps": [ + { + "name": "async-std", + "req": "^1.13.0", + "features": ["io_safety"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "io-lifetimes", + "req": "^3.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "mio", + "req": "^1.0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "os_pipe", + "req": "^1.2.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "os_pipe", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "socket2", + "req": "^0.6.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.6.0", + "features": ["io-std", "fs", "net", "process"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.52, <=0.60", + "features": ["Win32_Foundation", "Win32_Networking_WinSock", "Win32_System_Console"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "20fd6de4ccfcc187e38bc21cfa543cb5a302cb86a8b114eb7f0bf0dc9f8ac00f", + "features": { + "default": [], + "use_async_std": ["async-std"], + "use_mio_net": ["mio", "mio/net"], + "use_mio_os_ext": ["mio", "mio/os-ext"], + "use_os_pipe": ["os_pipe"], + "use_socket2": ["socket2"], + "use_tokio": ["tokio"] + }, + "yanked": false, + "rust_version": "1.70", + "pubtime": "2025-08-06T19:24:42Z" + } + ] + }, + { + "path": "io/-l/io-lifetimes", + "header": "AwIAAABldGFnOiAiMDA2NjFjYTIxMTUxY2ZlZjA1ZDBiMWE0MGE5Y2YzYTEiAA==", + "records": [ + { + "name": "io-lifetimes", + "vers": "2.0.4", + "deps": [ + { + "name": "async-std", + "req": "^1.13.0", + "features": ["io_safety"], + "optional": true, + "default_features": true, + "target": "cfg(not(target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "hermit-abi", + "req": ">=0.3, <=0.4", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(target_os = \"hermit\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.96", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(windows))", + "kind": "normal" + }, + { + "name": "mio", + "req": "^0.8.0", + "features": ["net", "os-ext"], + "optional": true, + "default_features": true, + "target": "cfg(not(target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "os_pipe", + "req": "^1.0.0", + "features": ["io_safety"], + "optional": true, + "default_features": true, + "target": "cfg(not(target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "socket2", + "req": "^0.5.0", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.6.0", + "features": ["io-std", "fs", "net", "process"], + "optional": true, + "default_features": true, + "target": "cfg(not(target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.52, <=0.59", + "features": [ + "Win32_Foundation", + "Win32_Storage_FileSystem", + "Win32_Networking_WinSock", + "Win32_Security", + "Win32_System_IO" + ], + "optional": true, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "06432fb54d3be7964ecd3649233cddf80db2832f47fec34c01f65b3d9d774983", + "features": { + "close": ["libc", "hermit-abi", "windows-sys"], + "default": [] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2024-12-04T01:31:02Z" + }, + { + "name": "io-lifetimes", + "vers": "3.0.1", + "deps": [ + { + "name": "async-std", + "req": "^1.13.0", + "features": ["io_safety"], + "optional": true, + "default_features": true, + "target": "cfg(not(target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "hermit-abi", + "req": ">=0.3, <=0.5", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(target_os = \"hermit\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.96", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(windows))", + "kind": "normal" + }, + { + "name": "mio", + "req": "^1.0.0", + "features": ["net", "os-ext"], + "optional": true, + "default_features": true, + "target": "cfg(not(target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "os_pipe", + "req": "^1.0.0", + "features": ["io_safety"], + "optional": true, + "default_features": true, + "target": "cfg(not(target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "socket2", + "req": "^0.6.0", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.6.0", + "features": ["io-std", "fs", "net", "process"], + "optional": true, + "default_features": true, + "target": "cfg(not(target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.52, <=0.60", + "features": [ + "Win32_Foundation", + "Win32_Storage_FileSystem", + "Win32_Networking_WinSock", + "Win32_Security", + "Win32_System_IO" + ], + "optional": true, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "2f0fb0570afe1fed943c5c3d4102d5358592d8625fda6a0007fdbe65a92fba96", + "features": { + "close": ["libc", "hermit-abi", "windows-sys"], + "default": [] + }, + "yanked": false, + "rust_version": "1.70", + "pubtime": "2025-08-06T19:20:58Z" + } + ] + }, + { + "path": "ip/ne/ipnet", + "header": "AwIAAABldGFnOiAiNWNhYWMwZWY1ZmE4NGY4NTZjYTllMDVmZWQ3YjVhYzAiAA==", + "records": [ + { + "name": "ipnet", + "vers": "2.12.2", + "deps": [ + { + "name": "heapless", + "req": "^0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "schemars08", + "req": "^0.8", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "schemars" + }, + { + "name": "schemars1", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "schemars" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "serde" + }, + { + "name": "serde_test", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "791930b43c0d5973160d90a8f3894509f2b273430f5c5c73b668636d0287c5c0", + "features": { + "default": ["std"], + "std": [] + }, + "features2": { + "heapless": ["dep:heapless", "serde"], + "json": ["schemars08", "serde"], + "schemars": ["schemars08"], + "schemars08": ["dep:schemars08"], + "schemars1": ["dep:schemars1"], + "ser_as_str": ["dep:heapless"], + "serde": ["dep:serde"] + }, + "yanked": false, + "pubtime": "2026-09-06T05:45:08Z", + "v": 2 + } + ] + }, + { + "path": "ip/ra/iprange", + "header": "AwIAAABldGFnOiAiODA1ODc5NmUwMTE5NmNmMzlkOWM1NGI5NzBkYWZiMjkiAA==", + "records": [ + { + "name": "iprange", + "vers": "0.6.7", + "deps": [ + { + "name": "bincode", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ipnet", + "req": "^2.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.3.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "37209be0ad225457e63814401415e748e2453a5297f9b637338f5fb8afa4ec00", + "features": {}, + "yanked": false, + "pubtime": "2022-01-17T11:54:07Z" + } + ] + }, + { + "path": "is/_t/is_terminal_polyfill", + "header": "AwIAAABldGFnOiAiMjA4NGZkNjBkMWI4YzQ4NmZkZjA3OWU2MTc1ODA2MjIiAA==", + "records": [ + { + "name": "is_terminal_polyfill", + "vers": "1.70.2", + "deps": [], + "cksum": "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695", + "features": { + "default": [] + }, + "yanked": false, + "rust_version": "1.70.0", + "pubtime": "2025-10-21T17:00:14Z" + } + ] + }, + { + "path": "it/er/itertools", + "header": "AwIAAABldGFnOiAiZmQ5N2JkOTE2Y2VlYTczYTM0OWJiOTUwM2ZkODI5OGEiAA==", + "records": [ + { + "name": "itertools", + "vers": "0.13.0", + "deps": [ + { + "name": "criterion", + "req": "^0.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "either", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "paste", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "permutohedron", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quickcheck", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186", + "features": { + "default": ["use_std"], + "use_alloc": [], + "use_std": ["use_alloc", "either/use_std"] + }, + "yanked": false, + "rust_version": "1.43.1", + "pubtime": "2024-05-16T15:37:32Z" + }, + { + "name": "itertools", + "vers": "0.15.0", + "deps": [ + { + "name": "criterion", + "req": "^0.4.0", + "features": ["html_reports"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "either", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "paste", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "permutohedron", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quickcheck", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "8b4baf93f58d4425749ca49a51c50ebab072c5df6994d08fed93541c331481dc", + "features": { + "default": ["use_std"], + "use_alloc": [], + "use_std": ["use_alloc", "either/use_std"] + }, + "yanked": false, + "rust_version": "1.63.0", + "pubtime": "2026-06-16T15:09:28Z" + } + ] + }, + { + "path": "it/oa/itoa", + "header": "AwIAAABldGFnOiAiZWE4NDk0ZDU2MGYxYjgxNzQ0NDM0OTViMzcwZTI3MmYiAA==", + "records": [ + { + "name": "itoa", + "vers": "1.0.18", + "deps": [ + { + "name": "criterion", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "no-panic", + "req": "^0.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682", + "features": {}, + "yanked": false, + "rust_version": "1.68", + "pubtime": "2026-03-20T00:12:37Z" + } + ] + }, + { + "path": "jo/bs/jobserver", + "header": "AwIAAABldGFnOiAiMDEwMTQ0MWVhMzM2M2Q1NTUxNWI1MWEyYTM4ZjcwMGQiAA==", + "records": [ + { + "name": "jobserver", + "vers": "0.1.35", + "deps": [ + { + "name": "getrandom", + "req": "^0.4", + "features": ["std"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.171", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "nix", + "req": "^0.31.3", + "features": ["fs"], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "dev" + }, + { + "name": "tempfile", + "req": "^3.10.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3", + "features": {}, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-07-06T01:43:15Z" + } + ] + }, + { + "path": "js/-s/js-sys", + "header": "AwIAAABldGFnOiAiOTM1MzY2ZDFjNDlmNmI1ZjI0NmEwZmNhMDg0YWFhMzAiAA==", + "records": [ + { + "name": "js-sys", + "vers": "0.3.106", + "deps": [ + { + "name": "cfg-if", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures-channel", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "futures-core", + "req": "^0.3.8", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-lite", + "req": "^2", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "futures-util", + "req": "^0.3.31", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "half", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "wasm-bindgen", + "req": "=0.2.129", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "7883d941dae510fb2d978fc3fe018c71c9e2892fd38854de3e8b92c2e5ad9cc5", + "features": { + "default": ["std", "unsafe-eval"], + "std": ["wasm-bindgen/std", "futures-util/std"], + "unsafe-eval": [] + }, + "features2": { + "futures-core-03-stream": ["dep:futures-util", "dep:futures-core"] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-09-25T07:13:42Z", + "v": 2 + } + ] + }, + { + "path": "le/b1/leb128", + "header": "AwIAAABldGFnOiAiYWZkNTFkZDI4OTE5NTUzMTMzODVkY2RiMDY0YzE5NWYiAA==", + "records": [ + { + "name": "leb128", + "vers": "0.2.7", + "deps": [ + { + "name": "quickcheck", + "req": "^1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "c83bff1d572d6b9aeef67ddfc8448e4a3737909cb28e81f97c791b9018703e52", + "features": { + "nightly": [] + }, + "yanked": false, + "pubtime": "2026-06-15T18:58:07Z" + } + ] + }, + { + "path": "le/b1/leb128fmt", + "header": "AwIAAABldGFnOiAiMDVmMDgxMWFiNWI2ZTQyOTA3MGZlY2M4MWUyZmQzYWUiAA==", + "records": [ + { + "name": "leb128fmt", + "vers": "0.1.0", + "deps": [], + "cksum": "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2", + "features": { + "alloc": [], + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.56.0", + "pubtime": "2023-10-02T21:31:24Z" + } + ] + }, + { + "path": "le/xi/lexical-sort", + "header": "AwIAAABldGFnOiAiZmU5YTk5MDQ1NzE5MmI5ZjE5MTRjZjNlM2JkZGZjNzQiAA==", + "records": [ + { + "name": "lexical-sort", + "vers": "0.3.1", + "deps": [ + { + "name": "alphanumeric-sort", + "req": "^1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "any_ascii", + "req": "^0.1.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "criterion", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rust_icu_ucol", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rust_icu_ustring", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "c09e4591611e231daf4d4c685a66cb0410cc1e502027a20ae55f2bb9e997207a", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "pubtime": "2020-08-29T23:40:26Z" + } + ] + }, + { + "path": "li/bc/libc", + "header": "AwIAAABldGFnOiAiOGEwODRkZTJkZmRmMDE4Njg2Y2NlYThjZDAzNzlmNjAiAA==", + "records": [ + { + "name": "libc", + "vers": "0.2.190", + "deps": [ + { + "name": "rustc-std-workspace-core", + "req": "^1.0.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78", + "features": { + "align": [], + "const-extern-fn": [], + "default": ["std"], + "extra_traits": [], + "rustc-dep-of-std": ["align", "rustc-std-workspace-core"], + "std": [], + "use_std": ["std"] + }, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-10-02T19:33:19Z" + } + ] + }, + { + "path": "li/bl/libloading", + "header": "AwIAAABldGFnOiAiZTMxNzYwZjkxZjUwMmQ3NmJkNGFjMWJhMjY3MGIxOGEiAA==", + "records": [ + { + "name": "libloading", + "vers": "0.8.9", + "deps": [ + { + "name": "cfg-if", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "windows-link", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": "^0.61", + "features": ["Win32_Foundation"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "dev" + } + ], + "cksum": "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55", + "features": {}, + "yanked": false, + "rust_version": "1.71.0", + "pubtime": "2025-09-21T10:59:30Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-wasix-aot-aarch64-apple-darwin", + "header": "AwIAAABldGFnOiAiMThjZTE2ODUzMmVmY2RmYjI1MzAwZGRjMzliMTM0ZTkiAA==", + "records": [ + { + "name": "liboliphaunt-wasix-aot-aarch64-apple-darwin", + "vers": "0.3.2", + "deps": [ + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "835ede81ff81dcfb2767878209a1c372b7e3338c401595cf179aa68e1f1cc0c7", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_liboliphaunt_wasix_aot_macos_arm64", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:47Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu", + "header": "AwIAAABldGFnOiAiYWUzMWUwN2FmMDI2OWM2ZTkzY2JlNjIxY2U5NjQyNmMiAA==", + "records": [ + { + "name": "liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu", + "vers": "0.3.2", + "deps": [ + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "14b15cb79e689f5f0eab69f5acd92f68f61ae57d9f3bfa4cc18658a6d1bb67ad", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_liboliphaunt_wasix_aot_linux_arm64_gnu", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:48Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-wasix-aot-x86_64-pc-windows-msvc", + "header": "AwIAAABldGFnOiAiYTJjYmJlZWY4NzM4Y2U1ZmNmY2Q2MTFlMTcwY2JmOWIiAA==", + "records": [ + { + "name": "liboliphaunt-wasix-aot-x86_64-pc-windows-msvc", + "vers": "0.3.2", + "deps": [ + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "6c7a811a634a1b0d686369cbaefa8dabbfe5825fc4a03140ddda7beb3343bd30", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_liboliphaunt_wasix_aot_windows_x64_msvc", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:49Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu", + "header": "AwIAAABldGFnOiAiNDc1YjlkOGZjMmMwZjA4MTU4MDU5Y2VkZmYwYzFkZGUiAA==", + "records": [ + { + "name": "liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu", + "vers": "0.3.2", + "deps": [ + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "9e56a349c5c888ad65a623cbce954e13ae6dcead6ea846fc63202158f815976d", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_liboliphaunt_wasix_aot_linux_x64_gnu", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:49Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-wasix-portable", + "header": "AwIAAABldGFnOiAiZDI5Y2FjNGJiY2UxNTEyYjFiYjNmZjM3NTc1YjQxZDIiAA==", + "records": [ + { + "name": "liboliphaunt-wasix-portable", + "vers": "0.3.2", + "deps": [ + { + "name": "oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "req": "=0.3.2", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(all(target_os = \"linux\", target_arch = \"aarch64\", target_env = \"gnu\"))", + "kind": "normal" + }, + { + "name": "oliphaunt-extension-contrib-pg18-aot-linux-x64", + "req": "=0.3.2", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(all(target_os = \"linux\", target_arch = \"x86_64\", target_env = \"gnu\"))", + "kind": "normal" + }, + { + "name": "oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "req": "=0.3.2", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(all(target_os = \"macos\", target_arch = \"aarch64\"))", + "kind": "normal" + }, + { + "name": "oliphaunt-extension-contrib-pg18-aot-windows-x64", + "req": "=0.3.2", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(all(target_os = \"windows\", target_arch = \"x86_64\", target_env = \"msvc\"))", + "kind": "normal" + }, + { + "name": "oliphaunt-extension-contrib-pg18-wasix", + "req": "=0.3.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "78ebe15bd97751ed6c63ae25067c6a92a2266fa861d295d9d45844260acba30b", + "features": { + "extension-pg-hashids": [], + "extension-pg-ivm": [], + "extension-pg-textsearch": [], + "extension-pg-uuidv7": [], + "extension-pgtap": [], + "extension-postgis": [], + "extension-vector": [] + }, + "features2": { + "extension-amcheck": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-auto-explain": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-bloom": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-btree-gin": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-btree-gist": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-citext": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-cube": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-dict-int": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-dict-xsyn": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-earthdistance": [ + "extension-cube", + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-file-fdw": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-fuzzystrmatch": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-hstore": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-intarray": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-isn": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-lo": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-ltree": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-pageinspect": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-pg-buffercache": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-pg-freespacemap": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-pg-surgery": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-pg-trgm": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-pg-visibility": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-pg-walinspect": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-pgcrypto": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-seg": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-tablefunc": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-tcn": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-tsm-system-rows": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-tsm-system-time": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-unaccent": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-uuid-ossp": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ] + }, + "yanked": false, + "links": "oliphaunt_artifact_liboliphaunt_wasix_runtime", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:42:14Z", + "v": 2 + } + ] + }, + { + "path": "li/br/libredox", + "header": "AwIAAABldGFnOiAiMTVlMzVlYmQ4ZTgxOTEwMDJhZTE3MjAwZTRmODg0ZDkiAA==", + "records": [ + { + "name": "libredox", + "vers": "0.1.25", + "deps": [ + { + "name": "bitflags", + "req": "^2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ioslice", + "req": "^0.6", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "plain", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "redox_syscall", + "req": "^0.9.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "61ff90caf6077a803a240f62fdbe88645a890bbca49ef8174c3cb0404362171d", + "features": { + "base": ["libc"], + "call": ["base"], + "default": ["base", "call", "std", "redox_syscall", "protocol", "numa"], + "mkns": ["ioslice"], + "numa": ["redox_syscall"], + "protocol": ["plain", "bitflags", "redox_syscall"], + "std": ["base"] + }, + "yanked": false, + "pubtime": "2026-09-21T13:30:01Z" + } + ] + }, + { + "path": "li/bt/libtest-mimic", + "header": "AwIAAABldGFnOiAiMjBlYzg2ODU1MTU3MThjMmUyZTJlODRmMWE2MjIwOTMiAA==", + "records": [ + { + "name": "libtest-mimic", + "vers": "0.8.2", + "deps": [ + { + "name": "anstream", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anstyle", + "req": "^1.0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "clap", + "req": "^4.0.8", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "escape8259", + "req": "^0.5.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "fastrand", + "req": "^2.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "pretty_assertions", + "req": "^1.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "14e6ba06f0ade6e504aff834d7c34298e5155c6baca353cc6a4aaff2f9fd7f33", + "features": {}, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-03-16T17:21:55Z" + } + ] + }, + { + "path": "li/bu/libunwind", + "header": "AwIAAABldGFnOiAiNmQ5N2NkMjRhZTBlOTFiNzI5NjA0YmE5MGRjMjEzYTgiAA==", + "records": [ + { + "name": "libunwind", + "vers": "1.3.3", + "deps": [], + "cksum": "0c6639b70a7ce854b79c70d7e83f16b5dc0137cc914f3d7d03803b513ecc67ac", + "features": {}, + "yanked": false, + "pubtime": "2023-10-13T13:45:37Z" + } + ] + }, + { + "path": "li/nk/linked_hash_set", + "header": "AwIAAABldGFnOiAiZTcyOTZkYzNkNTdkZTk4NDE2YWRjMGJiOTVlMjI5MDYiAA==", + "records": [ + { + "name": "linked_hash_set", + "vers": "0.1.6", + "deps": [ + { + "name": "linked-hash-map", + "req": "^0.5.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_core", + "req": "^1.0.228", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_test", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "984fb35d06508d1e69fc91050cceba9c0b748f983e6739fa2c7a9237154c52c8", + "features": {}, + "features2": { + "serde": ["dep:serde_core"] + }, + "yanked": false, + "pubtime": "2025-11-09T01:15:49Z", + "v": 2 + } + ] + }, + { + "path": "li/nk/linked-hash-map", + "header": "AwIAAABldGFnOiAiNzc5ZTFhYzM3MmJjN2Q5ZWExYjA4YzU5NDkxZjU3YjAiAA==", + "records": [ + { + "name": "linked-hash-map", + "vers": "0.5.6", + "deps": [ + { + "name": "heapsize", + "req": "^0.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_test", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f", + "features": { + "heapsize_impl": ["heapsize"], + "nightly": [], + "serde_impl": ["serde"] + }, + "yanked": false, + "pubtime": "2022-06-25T19:52:40Z" + } + ] + }, + { + "path": "li/nu/linux-raw-sys", + "header": "AwIAAABldGFnOiAiN2Q4N2ZlNTc2NGExYmU2YmQ0ZTc4NWJkOWQ0NTU2NzAiAA==", + "records": [ + { + "name": "linux-raw-sys", + "vers": "0.12.1", + "deps": [ + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "libc", + "req": "^0.2.100", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53", + "features": { + "auxvec": [], + "bootparam": [], + "btrfs": [], + "default": ["std", "general", "errno"], + "elf": [], + "elf_uapi": [], + "errno": [], + "general": [], + "if_arp": [], + "if_ether": [], + "if_packet": [], + "if_tun": [], + "image": [], + "io_uring": [], + "ioctl": [], + "landlock": [], + "loop_device": [], + "mempolicy": [], + "net": [], + "netlink": [], + "no_std": [], + "prctl": [], + "ptrace": [], + "rustc-dep-of-std": ["core", "no_std"], + "std": [], + "system": [], + "vm_sockets": [], + "xdp": [] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2025-12-23T00:00:07Z" + } + ] + }, + { + "path": "li/te/litemap", + "header": "AwIAAABldGFnOiAiZWE0MjhhMTc1MDM0NGNlNDlkOTk4ZmFmOGYzN2FkNzYiAA==", + "records": [ + { + "name": "litemap", + "vers": "0.8.3", + "deps": [ + { + "name": "bincode", + "req": "^1.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "databake", + "req": "^0.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "postcard", + "req": "^1.0.3", + "features": ["use-std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rkyv", + "req": "^0.7", + "features": ["validation"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.220", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_core", + "req": "^1.0.220", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0.45", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "yoke", + "req": "^0.8.3", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae", + "features": { + "alloc": [], + "default": ["alloc"], + "testing": ["alloc"] + }, + "features2": { + "databake": ["dep:databake"], + "serde": ["dep:serde_core", "alloc"], + "yoke": ["dep:yoke"] + }, + "yanked": false, + "rust_version": "1.82", + "pubtime": "2026-08-13T23:27:57Z", + "v": 2 + } + ] + }, + { + "path": "li/tr/litrs", + "header": "AwIAAABldGFnOiAiZTM3YTA1ZTczMzc5NDVlNzc3MzY3MjRhOGU4ZDE4NmYiAA==", + "records": [ + { + "name": "litrs", + "vers": "1.0.0", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.63", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "unicode-xid", + "req": "^0.2.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092", + "features": { + "check_suffix": ["unicode-xid"] + }, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2025-10-20T10:00:07Z" + } + ] + }, + { + "path": "lo/ck/lock_api", + "header": "AwIAAABldGFnOiAiZWM3OGI2MTNlNmNmZTkyMjJiOTQ2MzdlMTA2OTA1MWIiAA==", + "records": [ + { + "name": "lock_api", + "vers": "0.4.14", + "deps": [ + { + "name": "owning_ref", + "req": "^0.4.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "scopeguard", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.126", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965", + "features": { + "arc_lock": [], + "atomic_usize": [], + "default": ["atomic_usize"], + "nightly": [] + }, + "yanked": false, + "rust_version": "1.71.0", + "pubtime": "2025-10-03T23:33:12Z" + } + ] + }, + { + "path": "lz/4_/lz4_flex", + "header": "AwIAAABldGFnOiAiZWQ3NTY2MGQyYjUxNjJlMTE2NDhiYWQ2MjgxNWQyMmYiAA==", + "records": [ + { + "name": "lz4_flex", + "vers": "0.13.1", + "deps": [ + { + "name": "binggan", + "req": "^0.16.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "jemallocator", + "req": "^0.5.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "lz4-compress", + "req": "^0.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "lzzzz", + "req": "^2.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "more-asserts", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proptest", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0.91", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "snap", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "twox-hash", + "req": "^2.0.0", + "features": ["xxhash32"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "7ef0d4ed8669f8f8826eb00dc878084aa8f253506c4fd5e8f58f5bce72ddb97e", + "features": { + "checked-decode": [], + "nightly": [], + "safe-decode": [], + "safe-encode": [], + "std": [] + }, + "features2": { + "default": ["std", "safe-encode", "safe-decode", "frame", "checked-decode"], + "frame": ["std", "dep:twox-hash"] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-05-09T10:20:30Z", + "v": 2 + } + ] + }, + { + "path": "ma/ch/mach2", + "header": "AwIAAABldGFnOiAiNDBjZmRiZTk4MzYyZGY1Yjg0MTZiZDNjNWJlNDBkMWQiAA==", + "records": [ + { + "name": "mach2", + "vers": "0.4.3", + "deps": [ + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"macos\", target_os = \"ios\"))", + "kind": "normal" + } + ], + "cksum": "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44", + "features": { + "default": [], + "unstable": [] + }, + "yanked": false, + "pubtime": "2025-06-22T02:30:54Z" + }, + { + "name": "mach2", + "vers": "0.6.0", + "deps": [], + "cksum": "dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b", + "features": { + "default": [], + "unstable": [] + }, + "yanked": false, + "pubtime": "2025-11-16T01:16:34Z" + } + ] + }, + { + "path": "ma/ch/macho-unwind-info", + "header": "AwIAAABldGFnOiAiZDlhOGQxN2JlYmVkODYyNTE5N2Q2NDJkYTM2OGViM2IiAA==", + "records": [ + { + "name": "macho-unwind-info", + "vers": "0.5.0", + "deps": [ + { + "name": "object", + "req": "^0.36", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "thiserror", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "zerocopy", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "zerocopy-derive", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149", + "features": {}, + "yanked": false, + "pubtime": "2024-12-06T19:40:57Z" + } + ] + }, + { + "path": "ma/na/managed", + "header": "AwIAAABldGFnOiAiYjM2OTZkYTQxMjIyODRmNmI3MTQzYjk1NDk0OGM2ZDIiAA==", + "records": [ + { + "name": "managed", + "vers": "0.8.0", + "deps": [], + "cksum": "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d", + "features": { + "alloc": [], + "default": ["std"], + "map": [], + "std": [] + }, + "yanked": false, + "pubtime": "2020-07-04T01:57:33Z" + } + ] + }, + { + "path": "ma/yb/maybe-owned", + "header": "AwIAAABldGFnOiAiNTU0MWVhZTk1Yzc1NWJmZGJjNGI0YzVjYjNiMmMyNzUiAA==", + "records": [ + { + "name": "maybe-owned", + "vers": "0.3.4", + "deps": [ + { + "name": "serde", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4", + "features": {}, + "yanked": false, + "pubtime": "2020-05-23T01:30:58Z" + } + ] + }, + { + "path": "md/-5/md-5", + "header": "AwIAAABldGFnOiAiY2EwMTEyNDllNzcwMWVkODM2OWFjNmRlNzVhMjk5YjYiAA==", + "records": [ + { + "name": "md-5", + "vers": "0.11.0", + "deps": [ + { + "name": "cfg-if", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "digest", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "digest", + "req": "^0.11", + "features": ["dev"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hex-literal", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98", + "features": { + "alloc": ["digest/alloc"], + "default": ["alloc", "oid"], + "oid": ["digest/oid"], + "zeroize": ["digest/zeroize"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-03-27T14:59:39Z" + } + ] + }, + { + "path": "me/mc/memchr", + "header": "AwIAAABldGFnOiAiYjgwNzAzZTViODExMTA4NjlkOTQ1ZGM3ZDkxOWE5YzEiAA==", + "records": [ + { + "name": "memchr", + "vers": "2.8.3", + "deps": [ + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "log", + "req": "^0.4.20", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1.0.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + } + ], + "cksum": "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98", + "features": { + "alloc": [], + "default": ["std"], + "libc": [], + "rustc-dep-of-std": ["core"], + "std": ["alloc"], + "use_std": ["std"] + }, + "features2": { + "logging": ["dep:log"] + }, + "yanked": false, + "rust_version": "1.61", + "pubtime": "2026-07-08T00:49:54Z", + "v": 2 + } + ] + }, + { + "path": "me/mm/memmap2", + "header": "AwIAAABldGFnOiAiZjEyMWUwY2RlMjIyNmM5NzBiMjdhNzljOTAzYTJkNzQiAA==", + "records": [ + { + "name": "memmap2", + "vers": "0.6.2", + "deps": [ + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "owning_ref", + "req": "^0.4.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "stable_deref_trait", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "6d28bba84adfe6646737845bc5ebbfa2c08424eb1c37e94a1fd2a82adb56a872", + "features": {}, + "yanked": false, + "pubtime": "2023-05-24T13:56:15Z" + }, + { + "name": "memmap2", + "vers": "0.9.11", + "deps": [ + { + "name": "libc", + "req": "^0.2.151", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "owning_ref", + "req": "^0.4.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "stable_deref_trait", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0", + "features": {}, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-06-22T16:04:03Z" + } + ] + }, + { + "path": "me/mo/memoffset", + "header": "AwIAAABldGFnOiAiNjBmZmUyNjA1MWE4MDA0NDQ3MTk4MGI2YTczZmJiYWUiAA==", + "records": [ + { + "name": "memoffset", + "vers": "0.9.1", + "deps": [ + { + "name": "autocfg", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "doc-comment", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a", + "features": { + "default": [], + "unstable_const": [], + "unstable_offset_of": [] + }, + "yanked": false, + "pubtime": "2024-03-26T19:58:31Z" + } + ] + }, + { + "path": "mi/ni/minimal-lexical", + "header": "AwIAAABldGFnOiAiYWZmMGMzZGIzNGVmMTdlZDY0NDJhOGU2Y2M0NzY4OTYiAA==", + "records": [ + { + "name": "minimal-lexical", + "vers": "0.2.1", + "deps": [], + "cksum": "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a", + "features": { + "alloc": [], + "compact": [], + "default": ["std"], + "lint": [], + "nightly": [], + "std": [] + }, + "yanked": false, + "pubtime": "2021-10-04T10:48:13Z" + } + ] + }, + { + "path": "mi/ni/miniz_oxide", + "header": "AwIAAABldGFnOiAiNzgzNzFhMzMzMTFiNDhhZTI1MjgwZWM5MmUyOGNiYTYiAA==", + "records": [ + { + "name": "miniz_oxide", + "vers": "0.8.9", + "deps": [ + { + "name": "adler2", + "req": "^2.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "simd-adler32", + "req": "^0.3.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316", + "features": { + "block-boundary": [], + "default": ["with-alloc"], + "rustc-dep-of-std": ["core", "alloc", "adler2/rustc-dep-of-std"], + "simd": ["simd-adler32"], + "std": [], + "with-alloc": [] + }, + "yanked": false, + "pubtime": "2025-06-09T22:26:12Z" + }, + { + "name": "miniz_oxide", + "vers": "0.9.1", + "deps": [ + { + "name": "adler2", + "req": "^2.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive", "alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "simd-adler32", + "req": "^0.3.8", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c", + "features": { + "block-boundary": [], + "default": ["with-alloc"], + "rustc-dep-of-std": ["core", "alloc", "adler2/rustc-dep-of-std"], + "simd": ["simd-adler32"], + "with-alloc": [] + }, + "features2": { + "std": ["serde?/std"] + }, + "yanked": false, + "pubtime": "2026-03-13T00:19:26Z", + "v": 2 + } + ] + }, + { + "path": "mo/re/more-asserts", + "header": "AwIAAABldGFnOiAiOGNiZDUwODAxN2Y4NWRjYWYzZWUzOGFhMzJlNzgyYTciAA==", + "records": [ + { + "name": "more-asserts", + "vers": "0.3.1", + "deps": [], + "cksum": "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e", + "features": {}, + "yanked": false, + "pubtime": "2022-10-01T08:33:45Z" + } + ] + }, + { + "path": "mu/ng/munge", + "header": "AwIAAABldGFnOiAiOWE1YzljZDZkYTUxNzY2YWNiYTQ5MTdmNGM5YjZjZDIiAA==", + "records": [ + { + "name": "munge", + "vers": "0.4.7", + "deps": [ + { + "name": "munge_macro", + "req": "=0.4.7", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rustversion", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + } + ], + "cksum": "5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c", + "features": {}, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2025-09-29T14:59:31Z" + } + ] + }, + { + "path": "mu/ng/munge_macro", + "header": "AwIAAABldGFnOiAiYTM1YjRjYTFiOTFiY2E2M2Y5MjJjOGI5MjNhOGJiMzgiAA==", + "records": [ + { + "name": "munge_macro", + "vers": "0.4.7", + "deps": [ + { + "name": "proc-macro2", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2", + "features": ["clone-impls", "full", "parsing", "printing", "proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931", + "features": {}, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2025-09-29T14:59:27Z" + } + ] + }, + { + "path": "nu/m_/num_cpus", + "header": "AwIAAABldGFnOiAiMTA1NDQ3NzY1NmY2N2MwZmJiNGFlYWM0YzZmODQyMTMiAA==", + "records": [ + { + "name": "num_cpus", + "vers": "1.17.0", + "deps": [ + { + "name": "hermit-abi", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_os = \"hermit\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.26", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(windows))", + "kind": "normal" + } + ], + "cksum": "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b", + "features": {}, + "yanked": false, + "pubtime": "2025-05-30T18:59:42Z" + } + ] + }, + { + "path": "nu/m_/num_enum", + "header": "AwIAAABldGFnOiAiZWQ5NzAwNzYwMzU5NzFlZTdkZmYzOTAyMDhiNGU5NjYiAA==", + "records": [ + { + "name": "num_enum", + "vers": "0.7.6", + "deps": [ + { + "name": "anyhow", + "req": "^1.0.14", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "num_enum_derive", + "req": "=0.7.6", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "paste", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "trybuild", + "req": "^1.0.98", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "walkdir", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26", + "features": { + "complex-expressions": ["num_enum_derive/complex-expressions"], + "default": ["std"], + "external_doc": [], + "std": ["num_enum_derive/std"] + }, + "yanked": false, + "rust_version": "1.70.0", + "pubtime": "2026-03-15T21:29:40Z" + } + ] + }, + { + "path": "nu/m_/num_enum_derive", + "header": "AwIAAABldGFnOiAiMDkwZjc3Zjc1MDc4ODZiZmYwYjE0MDc2MDM1MjQxMDYiAA==", + "records": [ + { + "name": "num_enum_derive", + "vers": "0.7.6", + "deps": [ + { + "name": "proc-macro-crate", + "req": ">=1, <=3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1.0.60", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2", + "features": ["derive", "extra-traits", "parsing"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2", + "features": ["extra-traits", "parsing"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8", + "features": { + "complex-expressions": ["syn/full"], + "default": ["std"], + "external_doc": [], + "std": ["proc-macro-crate"] + }, + "yanked": false, + "rust_version": "1.70.0", + "pubtime": "2026-03-15T21:29:38Z" + } + ] + }, + { + "path": "nu/m-/num-conv", + "header": "AwIAAABldGFnOiAiZmM5MDZkOWU4YWU4ODAxNjVlYWZiYzhiZTc1MDNjM2UiAA==", + "records": [ + { + "name": "num-conv", + "vers": "0.2.2", + "deps": [], + "cksum": "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441", + "features": {}, + "yanked": false, + "rust_version": "1.57.0", + "pubtime": "2026-05-18T18:35:52Z" + } + ] + }, + { + "path": "nu/m-/num-traits", + "header": "AwIAAABldGFnOiAiNzZhMjFiYjNjOTZhOTQyMjU1ZTI0NWFhOTk3MWNiY2MiAA==", + "records": [ + { + "name": "num-traits", + "vers": "0.2.19", + "deps": [ + { + "name": "autocfg", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "libm", + "req": "^0.2.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841", + "features": { + "default": ["std"], + "i128": [], + "std": [] + }, + "features2": { + "libm": ["dep:libm"] + }, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2024-05-03T21:27:39Z", + "v": 2 + } + ] + }, + { + "path": "ob/jc/objc2-core-foundation", + "header": "AwIAAABldGFnOiAiNThlYTE2ZjM2ODVjMjM5ZWM1Nzc2NTY0NzNmOThkZmMiAA==", + "records": [ + { + "name": "objc2-core-foundation", + "vers": "0.3.2", + "deps": [ + { + "name": "bitflags", + "req": "^2.5.0", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "block2", + "req": ">=0.6.1, <0.8.0", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "dispatch2", + "req": ">=0.3.0, <0.5.0", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.80", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "objc2", + "req": ">=0.6.2, <0.8.0", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "static_assertions", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536", + "features": { + "CFArray": [], + "CFAttributedString": [], + "CFAvailability": [], + "CFBag": [], + "CFBase": [], + "CFBinaryHeap": [], + "CFBitVector": [], + "CFBundle": [], + "CFByteOrder": [], + "CFCGTypes": [], + "CFCharacterSet": [], + "CFDictionary": [], + "CFError": [], + "CFFileDescriptor": [], + "CFLocale": [], + "CFMachPort": [], + "CFMessagePort": [], + "CFNotificationCenter": [], + "CFNumber": [], + "CFPlugIn": [], + "CFPlugInCOM": [], + "CFPreferences": [], + "CFSet": [], + "CFStringEncodingExt": [], + "CFTimeZone": [], + "CFTree": [], + "CFURLAccess": [], + "CFUUID": [], + "CFUserNotification": [], + "CFUtilities": [], + "CFXMLNode": [], + "alloc": [], + "std": ["alloc"], + "unstable-coerce-pointee": [], + "unstable-darwin-objc": [] + }, + "features2": { + "CFCalendar": ["bitflags"], + "CFData": ["bitflags"], + "CFDate": ["bitflags"], + "CFDateFormatter": ["bitflags"], + "CFFileSecurity": ["bitflags"], + "CFNumberFormatter": ["bitflags"], + "CFPropertyList": ["bitflags"], + "CFRunLoop": ["bitflags"], + "CFSocket": ["bitflags"], + "CFStream": ["bitflags"], + "CFString": ["bitflags"], + "CFStringTokenizer": ["bitflags"], + "CFURL": ["bitflags"], + "CFURLEnumerator": ["bitflags"], + "CFXMLParser": ["bitflags"], + "bitflags": ["dep:bitflags"], + "block2": ["dep:block2"], + "default": [ + "std", + "CFArray", + "CFAttributedString", + "CFAvailability", + "CFBag", + "CFBinaryHeap", + "CFBitVector", + "CFBundle", + "CFByteOrder", + "CFCGTypes", + "CFCalendar", + "CFCharacterSet", + "CFData", + "CFDate", + "CFDateFormatter", + "CFDictionary", + "CFError", + "CFFileDescriptor", + "CFFileSecurity", + "CFLocale", + "CFMachPort", + "CFMessagePort", + "CFNotificationCenter", + "CFNumber", + "CFNumberFormatter", + "CFPlugIn", + "CFPlugInCOM", + "CFPreferences", + "CFPropertyList", + "CFRunLoop", + "CFSet", + "CFSocket", + "CFStream", + "CFString", + "CFStringEncodingExt", + "CFStringTokenizer", + "CFTimeZone", + "CFTree", + "CFURL", + "CFURLAccess", + "CFURLEnumerator", + "CFUUID", + "CFUserNotification", + "CFUtilities", + "CFXMLNode", + "CFXMLParser", + "bitflags", + "block2", + "dispatch2", + "libc", + "objc2" + ], + "dispatch2": ["dep:dispatch2"], + "libc": ["dep:libc"], + "objc2": ["dep:objc2", "dispatch2?/objc2"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2025-10-04T15:46:51Z", + "v": 2 + } + ] + }, + { + "path": "ob/jc/objc2-system-configuration", + "header": "AwIAAABldGFnOiAiNDkwNjMyNzljNTEwZDVkOGJiMWZjM2M1NmNiNTQ2NmYiAA==", + "records": [ + { + "name": "objc2-system-configuration", + "vers": "0.3.2", + "deps": [ + { + "name": "bitflags", + "req": "^2.5.0", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "dispatch2", + "req": ">=0.3.0, <0.5.0", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.80", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "objc2", + "req": ">=0.6.2, <0.8.0", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "objc2-core-foundation", + "req": "^0.3.2", + "features": ["CFError"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "objc2-security", + "req": "^0.3.2", + "features": ["Authorization"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "7216bd11cbda54ccabcab84d523dc93b858ec75ecfb3a7d89513fa22464da396", + "features": { + "CaptiveNetwork": [ + "objc2-core-foundation/CFArray", + "objc2-core-foundation/CFDictionary" + ], + "DHCPClientPreferences": [], + "SCDynamicStore": [ + "objc2-core-foundation/CFArray", + "objc2-core-foundation/CFDictionary", + "objc2-core-foundation/CFRunLoop" + ], + "SCDynamicStoreCopyDHCPInfo": [ + "objc2-core-foundation/CFData", + "objc2-core-foundation/CFDate", + "objc2-core-foundation/CFDictionary" + ], + "SCDynamicStoreCopySpecific": [ + "objc2-core-foundation/CFDictionary", + "objc2-core-foundation/CFString" + ], + "SCDynamicStoreKey": [], + "SCNetwork": [], + "SCNetworkConfiguration": [ + "objc2-core-foundation/CFArray", + "objc2-core-foundation/CFDictionary", + "objc2-core-foundation/CFNumber" + ], + "SCNetworkConnection": [ + "objc2-core-foundation/CFDictionary", + "objc2-core-foundation/CFRunLoop" + ], + "SCPreferencesPath": ["objc2-core-foundation/CFDictionary"], + "SCPreferencesSetSpecific": ["objc2-core-foundation/CFString"], + "SCSchemaDefinitions": [], + "alloc": [], + "std": ["alloc"], + "unstable-darwin-objc": [] + }, + "features2": { + "SCNetworkReachability": ["bitflags", "objc2-core-foundation/CFRunLoop"], + "SCPreferences": [ + "bitflags", + "objc2-core-foundation/CFArray", + "objc2-core-foundation/CFData", + "objc2-core-foundation/CFRunLoop" + ], + "bitflags": ["dep:bitflags"], + "default": [ + "std", + "CaptiveNetwork", + "DHCPClientPreferences", + "SCDynamicStore", + "SCDynamicStoreCopyDHCPInfo", + "SCDynamicStoreCopySpecific", + "SCDynamicStoreKey", + "SCNetwork", + "SCNetworkConfiguration", + "SCNetworkConnection", + "SCNetworkReachability", + "SCPreferences", + "SCPreferencesPath", + "SCPreferencesSetSpecific", + "SCSchemaDefinitions", + "bitflags", + "dispatch2", + "libc", + "objc2", + "objc2-security" + ], + "dispatch2": ["dep:dispatch2"], + "libc": ["dep:libc"], + "objc2": [ + "dep:objc2", + "dispatch2?/objc2", + "objc2-core-foundation/objc2", + "objc2-security?/objc2" + ], + "objc2-security": ["dep:objc2-security"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2025-10-04T16:34:10Z", + "v": 2 + } + ] + }, + { + "path": "ob/je/object", + "header": "AwIAAABldGFnOiAiZDRmZWNmNWVlOTZkZTliZTEyZDBiNGY4NjRjNGUwMzAiAA==", + "records": [ + { + "name": "object", + "vers": "0.37.3", + "deps": [ + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "crc32fast", + "req": "^1.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "flate2", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hashbrown", + "req": "^0.15.0", + "features": ["default-hasher"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "memchr", + "req": "^2.4.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "ruzstd", + "req": "^0.8.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasmparser", + "req": "^0.236.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe", + "features": { + "archive": [], + "cargo-all": [], + "coff": [], + "elf": [], + "macho": [], + "pe": ["coff"], + "read": ["read_core", "archive", "coff", "elf", "macho", "pe", "xcoff", "unaligned"], + "read_core": [], + "rustc-dep-of-std": ["core", "alloc", "memchr/rustc-dep-of-std"], + "std": ["memchr/std"], + "unaligned": [], + "unstable": [], + "xcoff": [] + }, + "features2": { + "all": ["read", "write", "build", "std", "compression", "wasm"], + "build": ["build_core", "write_std", "elf"], + "build_core": ["read_core", "write_core"], + "compression": ["dep:flate2", "dep:ruzstd", "std"], + "default": ["read", "compression"], + "doc": [ + "read_core", + "write_std", + "build_core", + "std", + "compression", + "archive", + "coff", + "elf", + "macho", + "pe", + "wasm", + "xcoff" + ], + "unstable-all": ["all", "unstable"], + "wasm": ["dep:wasmparser"], + "write": ["write_std", "coff", "elf", "macho", "pe", "xcoff"], + "write_core": ["dep:crc32fast", "dep:indexmap", "dep:hashbrown"], + "write_std": ["write_core", "std", "indexmap?/std", "crc32fast?/std"] + }, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2025-08-13T10:32:51Z", + "v": 2 + }, + { + "name": "object", + "vers": "0.39.1", + "deps": [ + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "crc32fast", + "req": "^1.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "flate2", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hashbrown", + "req": "^0.17.0", + "features": ["default-hasher"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2.14", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "memchr", + "req": "^2.4.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "ruzstd", + "req": "^0.8.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasmparser", + "req": "^0.247.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b", + "features": { + "archive": [], + "cargo-all": [], + "coff": [], + "elf": [], + "macho": [], + "pe": ["coff"], + "read": ["read_core", "archive", "coff", "elf", "macho", "pe", "xcoff"], + "read_core": [], + "rustc-dep-of-std": ["core", "alloc", "memchr/rustc-dep-of-std"], + "std": ["memchr/std"], + "unaligned": [], + "unstable": [], + "xcoff": [] + }, + "features2": { + "all": ["read", "write", "build", "std", "compression", "wasm"], + "build": ["build_core", "write_std", "elf"], + "build_core": ["read_core", "write_core"], + "compression": ["dep:flate2", "dep:ruzstd", "std"], + "default": ["read", "compression"], + "doc": ["all"], + "unstable-all": ["all", "unstable"], + "wasm": ["dep:wasmparser"], + "write": ["write_std", "coff", "elf", "macho", "pe", "xcoff"], + "write_core": ["dep:crc32fast", "dep:indexmap", "dep:hashbrown"], + "write_std": ["write_core", "std", "indexmap?/std", "crc32fast?/std"] + }, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-04-21T08:41:10Z", + "v": 2 + } + ] + }, + { + "path": "ol/ip/oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "header": "AwIAAABldGFnOiAiMDQ5YjAyZDI1NmJhZGJmZmNhYzk5N2FmZDEyYWRmNWIiAA==", + "records": [ + { + "name": "oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "vers": "0.3.2", + "deps": [ + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "6593cd36d8c9cb83d2098ef5f62005bb62861f05bcd3d7238f5bcccbc11cdfd3", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_extension_contrib_pg18_aot_aarch64_unknown_linux_gnu", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:50Z" + } + ] + }, + { + "path": "ol/ip/oliphaunt-extension-contrib-pg18-aot-linux-x64", + "header": "AwIAAABldGFnOiAiNTFmMDYwOTVhZTI5OTU3ZTUxYzg5NDdjZWQ3MTBiMzQiAA==", + "records": [ + { + "name": "oliphaunt-extension-contrib-pg18-aot-linux-x64", + "vers": "0.3.2", + "deps": [ + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "238580b3fed00f8537e64c1c6548d74d33b544a322946879a8821eed7f4dc792", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_extension_contrib_pg18_aot_x86_64_unknown_linux_gnu", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:51Z" + } + ] + }, + { + "path": "ol/ip/oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "header": "AwIAAABldGFnOiAiZWQxZWViMzEzNmQ1MGRiZWJmYzU0ZTdmMTYyYjliMWIiAA==", + "records": [ + { + "name": "oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "vers": "0.3.2", + "deps": [ + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "41bef2ac428e3b7f2149d1c342135c573a9dbd9c592eebaea3e0083f3840c64c", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_extension_contrib_pg18_aot_aarch64_apple_darwin", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:52Z" + } + ] + }, + { + "path": "ol/ip/oliphaunt-extension-contrib-pg18-aot-windows-x64", + "header": "AwIAAABldGFnOiAiNWI0ZDU0YjZmNjQzNmNlN2IyMjIzMDQ1YWY2YzlhZDQiAA==", + "records": [ + { + "name": "oliphaunt-extension-contrib-pg18-aot-windows-x64", + "vers": "0.3.2", + "deps": [ + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "623d461eda99618bda616e1f488160d0fa6833215676f73dc0c134a29c283cbd", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_extension_contrib_pg18_aot_x86_64_pc_windows_msvc", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:52Z" + } + ] + }, + { + "path": "ol/ip/oliphaunt-extension-contrib-pg18-wasix", + "header": "AwIAAABldGFnOiAiMDhhOGY0MGE5NjMwMWIwNGQ5MTNlMDZjY2M5NGMyM2QiAA==", + "records": [ + { + "name": "oliphaunt-extension-contrib-pg18-wasix", + "vers": "0.3.2", + "deps": [ + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "76a2cbf8c683ae8b380f11f4fa7581c41eddb370ab4d94cbba07d169c2ab7778", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_extension_contrib_pg18_wasix", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:53Z" + } + ] + }, + { + "path": "ol/ip/oliphaunt-icu", + "header": "AwIAAABldGFnOiAiZDJmZWY4MjU0YTZjZDUzZTExM2FlNDA3ZWM0YmM1YzgiAA==", + "records": [ + { + "name": "oliphaunt-icu", + "vers": "0.2.2", + "deps": [ + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "tar", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "zstd", + "req": "^0.13", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "build" + } + ], + "cksum": "976fdebc00bbd4dc456e3e77dafb51886798048b648ed3f8b5f22aac8c83a587", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_oliphaunt_icu", + "rust_version": "1.93", + "pubtime": "2026-10-02T23:55:49Z" + } + ] + }, + { + "path": "ol/ip/oliphaunt-wasix-tools", + "header": "AwIAAABldGFnOiAiYzA1YzA3ODI0YjQ0OWEzYTkyYjhjYzRiMDI0YzUyZDkiAA==", + "records": [ + { + "name": "oliphaunt-wasix-tools", + "vers": "0.2.4", + "deps": [ + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "ad5adaffe18ccfb26925aee55537a958d5830e0b5c1d6b6b2431c0ae29b09740", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_oliphaunt_wasix_tools", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:42:05Z" + } + ] + }, + { + "path": "ol/ip/oliphaunt-wasix-tools-aot-aarch64-apple-darwin", + "header": "AwIAAABldGFnOiAiYTRlYWYyMGU1NzRhN2IyYzVlZmQ5NjMyZDA0OTAwNDYiAA==", + "records": [ + { + "name": "oliphaunt-wasix-tools-aot-aarch64-apple-darwin", + "vers": "0.2.4", + "deps": [ + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "a83f654e0e336cdba6fc1b91d272bdb4c252ff2724a82bd0518ec1ba340b7caf", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_oliphaunt_wasix_tools_aot_macos_arm64", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:42:03Z" + } + ] + }, + { + "path": "ol/ip/oliphaunt-wasix-tools-aot-aarch64-unknown-linux-gnu", + "header": "AwIAAABldGFnOiAiNjQ0NDRiNTM3Yzc2YmYxZDI5Nzk5NjRkMTg2MDBmYzQiAA==", + "records": [ + { + "name": "oliphaunt-wasix-tools-aot-aarch64-unknown-linux-gnu", + "vers": "0.2.4", + "deps": [ + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "5e701ccd439ec0518c48b5917cabc75eaca8bf6b47300ee2c858a5f1fb7912e0", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_oliphaunt_wasix_tools_aot_linux_arm64_gnu", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:42:03Z" + } + ] + }, + { + "path": "ol/ip/oliphaunt-wasix-tools-aot-x86_64-pc-windows-msvc", + "header": "AwIAAABldGFnOiAiZGRmNTk3NmMyZDc0NmFlMTA1ZTEwN2M5ZDJmN2YwZjIiAA==", + "records": [ + { + "name": "oliphaunt-wasix-tools-aot-x86_64-pc-windows-msvc", + "vers": "0.2.4", + "deps": [ + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "626152e61e5053921a70b2825e126609905f18cef80c638047c781a3485c393f", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_oliphaunt_wasix_tools_aot_windows_x64_msvc", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:42:03Z" + } + ] + }, + { + "path": "ol/ip/oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu", + "header": "AwIAAABldGFnOiAiYzgwNDA2YTUyYmFlNzA3MDFiMjM2NGJhODdmNWUxODUiAA==", + "records": [ + { + "name": "oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu", + "vers": "0.2.4", + "deps": [ + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "3be53dc59e580e430294ad933e6f7551ec707211e0d4a352aedff542bbb66c61", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_oliphaunt_wasix_tools_aot_linux_x64_gnu", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:42:04Z" + } + ] + }, + { + "path": "on/ce/once_cell", + "header": "AwIAAABldGFnOiAiYWUxMGE3ZDhhYTg2YzA5ZjkxZDdlNWE0ZDkyMmZhZmYiAA==", + "records": [ + { + "name": "once_cell", + "vers": "1.21.4", + "deps": [ + { + "name": "critical-section", + "req": "^1.1.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "critical-section", + "req": "^1.1.3", + "features": ["std"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "parking_lot_core", + "req": "^0.9.10", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "portable-atomic", + "req": "^1.8", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "regex", + "req": "^1.10.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50", + "features": { + "alloc": ["race"], + "default": ["std"], + "race": [], + "std": ["alloc"], + "unstable": [] + }, + "features2": { + "atomic-polyfill": ["critical-section"], + "critical-section": ["dep:critical-section", "portable-atomic"], + "parking_lot": ["dep:parking_lot_core"], + "portable-atomic": ["dep:portable-atomic"] + }, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-03-12T10:59:52Z", + "v": 2 + } + ] + }, + { + "path": "on/ce/once_cell_polyfill", + "header": "AwIAAABldGFnOiAiNjNmZGRlZDlhZmRlZWY0ZmVmNzc0NGFmNGQ3NDFlZTkiAA==", + "records": [ + { + "name": "once_cell_polyfill", + "vers": "1.70.2", + "deps": [], + "cksum": "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe", + "features": { + "default": [] + }, + "yanked": false, + "rust_version": "1.70.0", + "pubtime": "2025-10-21T16:41:12Z" + } + ] + }, + { + "path": "op/ti/option-ext", + "header": "AwIAAABldGFnOiAiZWE4NGY0NjhjMWRiYzZkZDc5ODA3ODNkZjZjMWNkNmQiAA==", + "records": [ + { + "name": "option-ext", + "vers": "0.2.0", + "deps": [], + "cksum": "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d", + "features": {}, + "yanked": false, + "pubtime": "2023-01-11T19:28:05Z" + } + ] + }, + { + "path": "pa/rk/parking", + "header": "AwIAAABldGFnOiAiMzZmMmNjMjgwODJiODFiODIzMzExNDNkNGU4YmUwZGYiAA==", + "records": [ + { + "name": "parking", + "vers": "2.2.1", + "deps": [ + { + "name": "easy-parallel", + "req": "^3.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "loom", + "req": "^0.7", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(loom)", + "kind": "normal" + } + ], + "cksum": "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba", + "features": {}, + "yanked": false, + "rust_version": "1.51", + "pubtime": "2024-09-07T17:39:03Z" + } + ] + }, + { + "path": "pa/rk/parking_lot", + "header": "AwIAAABldGFnOiAiMGYzMzc1MGNhMWE4Y2ZlODk4ZDVjNzVjMjdlNDlmZTQiAA==", + "records": [ + { + "name": "parking_lot", + "vers": "0.12.5", + "deps": [ + { + "name": "bincode", + "req": "^1.3.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "lock_api", + "req": "^0.4.14", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "parking_lot_core", + "req": "^0.9.12", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.8.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a", + "features": { + "arc_lock": ["lock_api/arc_lock"], + "deadlock_detection": ["parking_lot_core/deadlock_detection"], + "default": [], + "hardware-lock-elision": [], + "nightly": ["parking_lot_core/nightly", "lock_api/nightly"], + "owning_ref": ["lock_api/owning_ref"], + "send_guard": [], + "serde": ["lock_api/serde"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2025-10-03T23:34:14Z" + } + ] + }, + { + "path": "pa/rk/parking_lot_core", + "header": "AwIAAABldGFnOiAiOWNjMmU1YmZmYzE2NDllODIzYjc4MTZjMzlmNzg3NmUiAA==", + "records": [ + { + "name": "parking_lot_core", + "vers": "0.9.12", + "deps": [ + { + "name": "backtrace", + "req": "^0.3.60", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.95", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "petgraph", + "req": "^0.6.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "redox_syscall", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_os = \"redox\")", + "kind": "normal" + }, + { + "name": "smallvec", + "req": "^1.6.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "windows-link", + "req": "^0.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1", + "features": { + "deadlock_detection": ["petgraph", "backtrace"], + "nightly": [] + }, + "yanked": false, + "rust_version": "1.71.0", + "pubtime": "2025-10-03T23:33:43Z" + } + ] + }, + { + "path": "pa/st/paste", + "header": "AwIAAABldGFnOiAiNGY1Y2QzZjBlODMyYzk2MGYzYzAxODA3OTM0MWU2MDIiAA==", + "records": [ + { + "name": "paste", + "vers": "1.0.15", + "deps": [ + { + "name": "paste-test-suite", + "req": "^0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.49", + "features": ["diff"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a", + "features": {}, + "yanked": false, + "rust_version": "1.31", + "pubtime": "2024-05-07T01:50:22Z" + } + ] + }, + { + "path": "pa/th/path-clean", + "header": "AwIAAABldGFnOiAiMjUyNjRkMzZjNmI0ZTY4ZWVmNDRiNzRlMzIxZGE5MjkiAA==", + "records": [ + { + "name": "path-clean", + "vers": "1.0.1", + "deps": [ + { + "name": "criterion", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef", + "features": {}, + "yanked": false, + "pubtime": "2023-02-24T03:24:24Z" + } + ] + }, + { + "path": "pe/rc/percent-encoding", + "header": "AwIAAABldGFnOiAiY2MwNDRmN2I1NDUzYWZiYTE4ZTc3YTUwMzMwOWM1YTYiAA==", + "records": [ + { + "name": "percent-encoding", + "vers": "2.3.2", + "deps": [], + "cksum": "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220", + "features": { + "alloc": [], + "default": ["std"], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.51", + "pubtime": "2025-08-21T08:46:50Z" + } + ] + }, + { + "path": "pe/tg/petgraph", + "header": "AwIAAABldGFnOiAiNWQzMzFhODE4Yjk0MmYwZTM2MWYwMDRkMmIyYmE3YWUiAA==", + "records": [ + { + "name": "petgraph", + "vers": "0.8.3", + "deps": [ + { + "name": "ahash", + "req": "^0.7.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "bincode", + "req": "^1.3.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "defmac", + "req": "^0.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "dot-parser", + "req": "^0.5.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "dot-parser-macros", + "req": "^0.5.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "fixedbitset", + "req": "^0.5.7", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "fxhash", + "req": "^0.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hashbrown", + "req": "^0.15.0", + "features": ["default-hasher", "inline-more"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2.5.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "itertools", + "req": "^0.12.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "odds", + "req": "^0.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quickcheck", + "req": "^0.8", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.5.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "^1.5.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455", + "features": { + "generate": [], + "graphmap": [], + "matrix_graph": [], + "serde-1": ["serde", "serde_derive"], + "std": ["indexmap/std"], + "unstable": ["generate"] + }, + "features2": { + "all": [ + "unstable", + "quickcheck", + "matrix_graph", + "stable_graph", + "graphmap", + "rayon", + "dot_parser" + ], + "default": ["std", "graphmap", "stable_graph", "matrix_graph"], + "dot_parser": ["std", "dep:dot-parser", "dep:dot-parser-macros"], + "quickcheck": ["std", "dep:quickcheck", "graphmap", "stable_graph"], + "rayon": ["std", "dep:rayon", "indexmap/rayon", "hashbrown/rayon"], + "stable_graph": ["serde?/alloc"] + }, + "yanked": false, + "rust_version": "1.64", + "pubtime": "2025-09-30T13:16:04Z", + "v": 2 + } + ] + }, + { + "path": "ph/f_/phf_shared", + "header": "AwIAAABldGFnOiAiMTY0YmQxZDMxNWM1MTU1MGZjMDAyNGZlOWU3NzZjZWUiAA==", + "records": [ + { + "name": "phf_shared", + "vers": "0.13.1", + "deps": [ + { + "name": "siphasher", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "uncased", + "req": "^0.9.9", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "unicase", + "req": "^2.4.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.66", + "pubtime": "2025-08-23T11:05:56Z" + } + ] + }, + { + "path": "pi/n-/pin-project", + "header": "AwIAAABldGFnOiAiYTJjMTNlZmMzOTlkNzg1ZTIzZjZhNzE2YjQ5MTViNGYiAA==", + "records": [ + { + "name": "pin-project", + "vers": "1.1.13", + "deps": [ + { + "name": "pin-project-internal", + "req": "=1.1.13", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustversion", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-05-13T18:32:09Z" + } + ] + }, + { + "path": "pi/n-/pin-project-internal", + "header": "AwIAAABldGFnOiAiYTg2YTIyZDIzZGExYjAwZTM5NjA1NjFkOTJmZmM5NmQiAA==", + "records": [ + { + "name": "pin-project-internal", + "vers": "1.1.13", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.60", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.25", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0.1", + "features": ["parsing", "printing", "clone-impls", "proc-macro", "full", "visit-mut"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-05-13T18:32:07Z" + } + ] + }, + { + "path": "pi/n-/pin-project-lite", + "header": "AwIAAABldGFnOiAiZTdmZTUwZTQwZTkzNGUyYzk5NDZlMTczOTBkNmNlZjQiAA==", + "records": [ + { + "name": "pin-project-lite", + "vers": "0.2.17", + "deps": [ + { + "name": "rustversion", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd", + "features": {}, + "yanked": false, + "rust_version": "1.37", + "pubtime": "2026-02-27T15:19:08Z" + } + ] + }, + { + "path": "pi/n-/pin-utils", + "header": "AwIAAABldGFnOiAiMTljZTgwOGMyYThhY2Y3NTFjMzc3ZTI4MzhlZGQxNGQiAA==", + "records": [ + { + "name": "pin-utils", + "vers": "0.1.1", + "deps": [], + "cksum": "13bee6c73da26345c729282832b60b0363cf3dd9f4bfd81d8551b7a1c889a113", + "features": {}, + "yanked": false, + "pubtime": "2026-10-01T07:13:59Z" + } + ] + }, + { + "path": "pk/g-/pkg-config", + "header": "AwIAAABldGFnOiAiZjJiODI5OWQ4MmIxMDhmNDNkOGQxODViYTMyNzRiNDgiAA==", + "records": [ + { + "name": "pkg-config", + "vers": "0.3.34", + "deps": [], + "cksum": "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548", + "features": {}, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2026-08-14T08:27:51Z" + } + ] + }, + { + "path": "po/st/postgres-protocol", + "header": "AwIAAABldGFnOiAiYjljYTk3NTc4NzRjODVkOTE1Y2VjZDM1ZTNmNzhiYzciAA==", + "records": [ + { + "name": "postgres-protocol", + "vers": "0.6.12", + "deps": [ + { + "name": "base64", + "req": "^0.22", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "byteorder", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytes", + "req": "^1.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "fallible-iterator", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "getrandom", + "req": "^0.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hmac", + "req": "^0.13", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "md-5", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memchr", + "req": "^2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sha2", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "stringprep", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "08808e3c483c46e999108051c78334f473d5adb59d78bb80a1268c7e6aa6c514", + "features": { + "default": [], + "js": ["getrandom/wasm_js"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-06-12T15:34:01Z" + } + ] + }, + { + "path": "po/st/postgres-types", + "header": "AwIAAABldGFnOiAiNDgwOWRmZDI4YjU0YTRkZTg4NDFmMDIzOTMzOWY1MjAiAA==", + "records": [ + { + "name": "postgres-types", + "vers": "0.2.14", + "deps": [ + { + "name": "array-init", + "req": "^2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bit-vec-06", + "req": "^0.6", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "bit-vec" + }, + { + "name": "bit-vec-07", + "req": "^0.7", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "bit-vec" + }, + { + "name": "bit-vec-08", + "req": "^0.8", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "bit-vec" + }, + { + "name": "bit-vec-09", + "req": "^0.9", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "bit-vec" + }, + { + "name": "bytes", + "req": "^1.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "chrono-04", + "req": "^0.4.33", + "features": ["clock"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "chrono" + }, + { + "name": "cidr-02", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "cidr" + }, + { + "name": "cidr-03", + "req": "^0.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "cidr" + }, + { + "name": "eui48-04", + "req": "^0.4.6", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "eui48" + }, + { + "name": "eui48-1", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "eui48" + }, + { + "name": "fallible-iterator", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "geo-types-06", + "req": "^0.6", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "geo-types" + }, + { + "name": "geo-types-0_7", + "req": "^0.7.8", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "geo-types" + }, + { + "name": "jiff-01", + "req": "^0.1", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "jiff" + }, + { + "name": "jiff-02", + "req": "^0.2", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "jiff" + }, + { + "name": "postgres-derive", + "req": "^0.4.9", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "postgres-protocol", + "req": "^0.6.12", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde-1", + "req": "^1.0.221", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "serde_core" + }, + { + "name": "serde_json-1", + "req": "^1.0.144", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "serde_json" + }, + { + "name": "smol_str-01", + "req": "^0.1.23", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "smol_str" + }, + { + "name": "time-02", + "req": "^0.2.7", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "time" + }, + { + "name": "time-03", + "req": "^0.3.5", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "time" + }, + { + "name": "uuid-08", + "req": "^0.8", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "uuid" + }, + { + "name": "uuid-1", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "uuid" + } + ], + "cksum": "851ca9db4932932d69f3ea811b1abe63087a0f740a47692619dd40d4899b68be", + "features": { + "array-impls": ["array-init"], + "derive": ["postgres-derive"], + "js": ["postgres-protocol/js"], + "with-bit-vec-0_6": ["bit-vec-06"], + "with-bit-vec-0_7": ["bit-vec-07"], + "with-bit-vec-0_8": ["bit-vec-08"], + "with-bit-vec-0_9": ["bit-vec-09"], + "with-chrono-0_4": ["chrono-04"], + "with-cidr-0_2": ["cidr-02"], + "with-cidr-0_3": ["cidr-03"], + "with-eui48-0_4": ["eui48-04"], + "with-eui48-1": ["eui48-1"], + "with-geo-types-0_6": ["geo-types-06"], + "with-geo-types-0_7": ["geo-types-0_7"], + "with-jiff-0_1": ["jiff-01"], + "with-jiff-0_2": ["jiff-02"], + "with-serde_json-1": ["serde-1", "serde_json-1"], + "with-smol_str-01": ["smol_str-01"], + "with-time-0_2": ["time-02"], + "with-time-0_3": ["time-03"], + "with-uuid-0_8": ["uuid-08"], + "with-uuid-1": ["uuid-1"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-06-12T15:37:04Z" + } + ] + }, + { + "path": "po/te/potential_utf", + "header": "AwIAAABldGFnOiAiYTg1NGQ4MWUzZTQwZGJhM2YxOGE5MjViYmI4NTY0MDYiAA==", + "records": [ + { + "name": "potential_utf", + "vers": "0.1.6", + "deps": [ + { + "name": "bincode", + "req": "^1.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "databake", + "req": "^0.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_core", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.45", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "writeable", + "req": "^0.6.4", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerovec", + "req": "^0.11.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661", + "features": {}, + "features2": { + "alloc": ["serde_core?/alloc", "writeable/alloc", "zerovec?/alloc"], + "databake": ["dep:databake"], + "default": ["alloc"], + "serde": ["dep:serde_core"], + "writeable": ["dep:writeable"], + "zerovec": ["dep:zerovec"] + }, + "yanked": false, + "rust_version": "1.82", + "pubtime": "2026-08-13T23:28:14Z", + "v": 2 + } + ] + }, + { + "path": "po/we/powerfmt", + "header": "AwIAAABldGFnOiAiMzA5NTM5NDg0YTVmNDcyMGFmMjM0MTc5ZDQ3NDI3OGMiAA==", + "records": [ + { + "name": "powerfmt", + "vers": "0.2.1", + "deps": [ + { + "name": "powerfmt-macros", + "req": "=0.1.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "4a6394b9e965e73d0a289ee54f589087e2c676aedf60885baf52c76b771e4958", + "features": { + "alloc": [], + "std": ["alloc"] + }, + "features2": { + "default": ["std", "macros"], + "macros": ["dep:powerfmt-macros"] + }, + "yanked": false, + "rust_version": "1.79.0", + "pubtime": "2026-10-05T09:01:10Z", + "v": 2 + } + ] + }, + { + "path": "pp/v-/ppv-lite86", + "header": "AwIAAABldGFnOiAiMmVjZTg1MGU4YjJjZjA0ZTRmZDNjYTdmY2VlNDcxYzAiAA==", + "records": [ + { + "name": "ppv-lite86", + "vers": "0.2.21", + "deps": [ + { + "name": "zerocopy", + "req": "^0.8.23", + "features": ["simd"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9", + "features": { + "default": ["std"], + "no_simd": [], + "simd": [], + "std": [] + }, + "yanked": false, + "rust_version": "1.61", + "pubtime": "2025-03-09T20:01:40Z" + } + ] + }, + { + "path": "pr/et/prettyplease", + "header": "AwIAAABldGFnOiAiYzQ1MzE1NjEyNGI3ODA0YmUyMTMxYTZmZDM1ODQzZTQiAA==", + "records": [ + { + "name": "prettyplease", + "vers": "0.2.37", + "deps": [ + { + "name": "indoc", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1.0.80", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1.0.80", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "quote", + "req": "^1.0.35", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "syn", + "req": "^2.0.105", + "features": ["full"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0.105", + "features": ["clone-impls", "extra-traits", "parsing", "printing", "visit-mut"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + } + ], + "cksum": "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b", + "features": { + "verbatim": ["syn/parsing"] + }, + "yanked": false, + "links": "prettyplease02", + "rust_version": "1.62", + "pubtime": "2025-08-19T00:29:26Z" + } + ] + }, + { + "path": "pr/oc/proc-macro-crate", + "header": "AwIAAABldGFnOiAiMjRjM2QwZDk2OWZkZTdmMTcxYmYyMDM5MGVhZDJkZjEiAA==", + "records": [ + { + "name": "proc-macro-crate", + "vers": "3.5.0", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.94", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quote", + "req": "^1.0.39", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn", + "req": "^2.0.99", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml_edit", + "req": "^0.25.0", + "features": ["parse"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f", + "features": {}, + "yanked": false, + "rust_version": "1.82.0", + "pubtime": "2026-03-04T11:12:33Z" + } + ] + }, + { + "path": "pr/oc/proc-macro-error-attr2", + "header": "AwIAAABldGFnOiAiYjRiZjg4MTRkZTMxOGI0NTE5YjMzZDQ1ZDZlMjdiOWYiAA==", + "records": [ + { + "name": "proc-macro-error-attr2", + "vers": "2.0.0", + "deps": [ + { + "name": "proc-macro2", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5", + "features": {}, + "yanked": false, + "rust_version": "1.61", + "pubtime": "2024-09-05T11:14:52Z" + } + ] + }, + { + "path": "pr/oc/proc-macro-error2", + "header": "AwIAAABldGFnOiAiOTlmYWEzMTA1YmNkNDM5Yzg1NDU5NWEwZGIwZjM2ZDkiAA==", + "records": [ + { + "name": "proc-macro-error2", + "vers": "2.0.1", + "deps": [ + { + "name": "proc-macro-error-attr2", + "req": "=2.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2", + "features": ["full"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.99", + "features": ["diff"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802", + "features": { + "nightly": [] + }, + "features2": { + "default": ["syn-error"], + "syn-error": ["dep:syn"] + }, + "yanked": false, + "rust_version": "1.61", + "pubtime": "2024-09-06T20:04:43Z", + "v": 2 + } + ] + }, + { + "path": "pr/oc/proc-macro2", + "header": "AwIAAABldGFnOiAiYWJhYmI1OTE1N2M2ZTlhNzE0YTliMWNiMzAyZTg0MmUiAA==", + "records": [ + { + "name": "proc-macro2", + "vers": "1.0.107", + "deps": [ + { + "name": "flate2", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quote", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tar", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicode-ident", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9", + "features": { + "default": ["proc-macro"], + "nightly": [], + "proc-macro": [], + "span-locations": [] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-19T00:18:25Z" + } + ] + }, + { + "path": "pt/r_/ptr_meta", + "header": "AwIAAABldGFnOiAiMjM3MzQ2ZjhjY2ZiMDIyZjI1MDE5OWMyNGQyZGFhMGYiAA==", + "records": [ + { + "name": "ptr_meta", + "vers": "0.3.2", + "deps": [ + { + "name": "ptr_meta_derive", + "req": "=0.3.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "743da816b98c921cdbe8628ef7381b76f25ecf4da599fc80aca90eae7ef70cc0", + "features": { + "default": ["derive", "std"], + "derive": ["ptr_meta_derive"], + "std": [] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-08-05T11:57:40Z" + } + ] + }, + { + "path": "pt/r_/ptr_meta_derive", + "header": "AwIAAABldGFnOiAiZDkyZjFlNGJlNzNlOGNkY2ZlMGJkNTYyYzNmZjYwZDkiAA==", + "records": [ + { + "name": "ptr_meta_derive", + "vers": "0.3.2", + "deps": [ + { + "name": "proc-macro2", + "req": "^1", + "features": ["proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": ["proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3.0", + "features": ["clone-impls", "derive", "full", "parsing", "printing", "proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "1c8d9ca532f185d5d4db7a7c9d51420b452168ea1c2b913953281bd6fe1fcbd0", + "features": {}, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-08-05T11:57:38Z" + } + ] + }, + { + "path": "pu/ll/pulldown-cmark", + "header": "AwIAAABldGFnOiAiMWMzMTMwZTlkZjRmNDZlMzhjNWEwODBjOTRhYWMxZDgiAA==", + "records": [ + { + "name": "pulldown-cmark", + "vers": "0.8.0", + "deps": [ + { + "name": "bitflags", + "req": "^1.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "criterion", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "getopts", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "html5ever", + "req": "^0.25", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "lazy_static", + "req": "^1.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "markup5ever_rcdom", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "memchr", + "req": "^2.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "regex", + "req": "^1.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tendril", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicase", + "req": "^2.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8", + "features": { + "default": ["getopts"], + "gen-tests": [], + "simd": [] + }, + "yanked": false, + "pubtime": "2020-09-01T15:23:43Z" + } + ] + }, + { + "path": "qu/ot/quote", + "header": "AwIAAABldGFnOiAiNzI5NmI3Yzk0OGUyODExNjhiMGVhZTc0NjVmZTM5MTgiAA==", + "records": [ + { + "name": "quote", + "vers": "1.0.47", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.80", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rustversion", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.108", + "features": ["diff"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001", + "features": { + "default": ["proc-macro"], + "proc-macro": ["proc-macro2/proc-macro"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-19T00:16:57Z" + } + ] + }, + { + "path": "r-/ef/r-efi", + "header": "AwIAAABldGFnOiAiNDdiZGU4NjlmOWVjMzhmNzdkZjI2YjJlZTQxZGQ1ZTYiAA==", + "records": [ + { + "name": "r-efi", + "vers": "5.3.0", + "deps": [ + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + } + ], + "cksum": "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f", + "features": { + "efiapi": [], + "examples": ["native"], + "native": [], + "rustc-dep-of-std": ["core"] + }, + "yanked": false, + "rust_version": "1.68", + "pubtime": "2025-06-17T09:12:38Z" + }, + { + "name": "r-efi", + "vers": "6.0.0", + "deps": [ + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + } + ], + "cksum": "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf", + "features": { + "native": [], + "rustc-dep-of-std": ["core"] + }, + "yanked": false, + "rust_version": "1.68", + "pubtime": "2026-02-03T09:53:46Z" + } + ] + }, + { + "path": "ra/nc/rancor", + "header": "AwIAAABldGFnOiAiZmE4MGU5MTYyMmYxNjVlMjFmZGI0MThkMDgxOTdlY2UiAA==", + "records": [ + { + "name": "rancor", + "vers": "0.1.3", + "deps": [ + { + "name": "ptr_meta", + "req": "^0.3", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "9b534442d0fcdb55d66f373d9cac6d33b6293a2335bc2136dbd06ce0e87d2572", + "features": { + "alloc": [], + "default": ["alloc"] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-08-05T11:46:35Z" + } + ] + }, + { + "path": "ra/nd/rand", + "header": "AwIAAABldGFnOiAiZjEyYmNmNmZjZTRhY2UwYWMwMmRmZDk4YjU4NWJkZWEiAA==", + "records": [ + { + "name": "rand", + "vers": "0.9.5", + "deps": [ + { + "name": "bincode", + "req": "^1.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand_chacha", + "req": "^0.9.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand_core", + "req": "^0.9.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand_pcg", + "req": "^0.9.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "^1.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.103", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.140", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41", + "features": { + "alloc": [], + "log": [], + "nightly": [], + "os_rng": ["rand_core/os_rng"], + "simd_support": [], + "small_rng": [], + "unbiased": [] + }, + "features2": { + "default": ["std", "std_rng", "os_rng", "small_rng", "thread_rng"], + "serde": ["dep:serde", "rand_core/serde"], + "std": ["rand_core/std", "rand_chacha?/std", "alloc"], + "std_rng": ["dep:rand_chacha"], + "thread_rng": ["std", "std_rng", "os_rng"] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2026-07-11T11:16:46Z", + "v": 2 + }, + { + "name": "rand", + "vers": "0.10.3", + "deps": [ + { + "name": "chacha20", + "req": "^0.10.0", + "features": ["rng"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "getrandom", + "req": "^0.4.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "postcard", + "req": "^1.1.3", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rand_core", + "req": "^0.10.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand_pcg", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "^1.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.103", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.140", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af", + "features": { + "alloc": [], + "log": [], + "simd_support": [], + "unbiased": [] + }, + "features2": { + "chacha": ["dep:chacha20"], + "default": ["std", "std_rng", "sys_rng", "thread_rng"], + "serde": ["dep:serde"], + "std": ["alloc", "getrandom?/std"], + "std_rng": ["dep:chacha20"], + "sys_rng": ["dep:getrandom", "getrandom/sys_rng"], + "thread_rng": ["std", "std_rng", "sys_rng"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-09-20T06:37:47Z", + "v": 2 + } + ] + }, + { + "path": "ra/nd/rand_chacha", + "header": "AwIAAABldGFnOiAiZjA0YzM0YjFjMTM5MzU4NjU5OGExMGQ4ZWI1YTkxYzkiAA==", + "records": [ + { + "name": "rand_chacha", + "vers": "0.9.0", + "deps": [ + { + "name": "ppv-lite86", + "req": "^0.2.14", + "features": ["simd"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand_core", + "req": "^0.9.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rand_core", + "req": "^0.9.0", + "features": ["os_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb", + "features": { + "default": ["std"], + "os_rng": ["rand_core/os_rng"], + "std": ["ppv-lite86/std", "rand_core/std"] + }, + "features2": { + "serde": ["dep:serde"] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2025-01-27T13:38:26Z", + "v": 2 + } + ] + }, + { + "path": "ra/nd/rand_core", + "header": "AwIAAABldGFnOiAiYjNmZWIzNDE5NGY4Y2RlODg5ZDBkN2FiY2I1YjI4MDYiAA==", + "records": [ + { + "name": "rand_core", + "vers": "0.9.5", + "deps": [ + { + "name": "getrandom", + "req": "^0.3.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c", + "features": {}, + "features2": { + "os_rng": ["dep:getrandom"], + "serde": ["dep:serde"], + "std": ["getrandom?/std"] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2026-01-13T09:22:22Z", + "v": 2 + }, + { + "name": "rand_core", + "vers": "0.10.1", + "deps": [], + "cksum": "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69", + "features": {}, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-04-13T15:26:43Z" + } + ] + }, + { + "path": "ra/ng/rangemap", + "header": "AwIAAABldGFnOiAiMDA1ODk2NGQ5Y2JiMTM2NDUyMGYzYzFhMDZjNzYyYTMiAA==", + "records": [ + { + "name": "rangemap", + "vers": "1.8.0", + "deps": [ + { + "name": "chrono", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ordered-float", + "req": "^5.3.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "ordered-float", + "req": "^5.3.0", + "features": ["proptest"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "permutator", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proptest", + "req": "^1.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quickcheck", + "req": "^1.0.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustc_version", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "test-strategy", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "a611d15b50743feb4c76b7d03edcb0e64f399c26961e4efe6975bc398be6aa3d", + "features": { + "const_fn": [], + "nightly": [] + }, + "features2": { + "ordered-float5": ["dep:ordered-float"], + "quickcheck": ["dep:quickcheck"], + "serde1": ["serde", "ordered-float?/serde"] + }, + "yanked": false, + "rust_version": "1.81.0", + "pubtime": "2026-08-14T02:30:08Z", + "v": 2 + } + ] + }, + { + "path": "ra/yo/rayon", + "header": "AwIAAABldGFnOiAiY2JiZjIyNGJjYjVjMmQyNDRhNmNlNDFlZmQ2NzU4NWYiAA==", + "records": [ + { + "name": "rayon", + "vers": "1.12.0", + "deps": [ + { + "name": "either", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand_xorshift", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon-core", + "req": "^1.13.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasm_sync", + "req": "^0.1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d", + "features": {}, + "features2": { + "web_spin_lock": ["dep:wasm_sync", "rayon-core/web_spin_lock"] + }, + "yanked": false, + "rust_version": "1.80", + "pubtime": "2026-04-14T00:56:56Z", + "v": 2 + } + ] + }, + { + "path": "ra/yo/rayon-core", + "header": "AwIAAABldGFnOiAiNDNiMGNiZWYzOTE5ZGZkZmQ5NGQ2YTY1NjQ5OGMwMzAiAA==", + "records": [ + { + "name": "rayon-core", + "vers": "1.13.0", + "deps": [ + { + "name": "crossbeam-deque", + "req": "^0.8.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "crossbeam-utils", + "req": "^0.8.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand_xorshift", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "scoped-tls", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "wasm_sync", + "req": "^0.1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91", + "features": {}, + "features2": { + "web_spin_lock": ["dep:wasm_sync"] + }, + "yanked": false, + "links": "rayon-core", + "rust_version": "1.80", + "pubtime": "2025-08-12T23:21:51Z", + "v": 2 + } + ] + }, + { + "path": "re/do/redox_syscall", + "header": "AwIAAABldGFnOiAiMTExOGMyMGZiMzQ4ZjZhMjdmZDljYWI4YmI4ZTkwNGUiAA==", + "records": [ + { + "name": "redox_syscall", + "vers": "0.5.18", + "deps": [ + { + "name": "bitflags", + "req": "^2.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "loom", + "req": "^0.7", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(loom)", + "kind": "dev" + } + ], + "cksum": "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d", + "features": { + "default": ["userspace"], + "rustc-dep-of-std": ["core", "bitflags/rustc-dep-of-std"], + "std": [], + "userspace": [] + }, + "yanked": false, + "pubtime": "2025-10-04T14:57:04Z" + } + ] + }, + { + "path": "re/do/redox_users", + "header": "AwIAAABldGFnOiAiMDM3ZjAyMGY1OTQxYzllYmRiYTRlZTg5MDM2ODMzODciAA==", + "records": [ + { + "name": "redox_users", + "vers": "0.5.3", + "deps": [ + { + "name": "getrandom", + "req": "^0.4", + "features": ["std"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libredox", + "req": "^0.1.3", + "features": ["std", "call"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rust-argon2", + "req": "^3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "thiserror", + "req": "^2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "zeroize", + "req": "^1.4", + "features": ["zeroize_derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "60dc65c0ff1a7ae1294b0c67b9f14baf70b644404010370171787bfac1038fc0", + "features": { + "auth": ["rust-argon2", "getrandom", "zeroize"], + "default": ["auth"] + }, + "yanked": false, + "pubtime": "2026-09-16T13:29:14Z" + } + ] + }, + { + "path": "re/f-/ref-cast", + "header": "AwIAAABldGFnOiAiZmJmN2RhYzA0MTE5Yjc1MGVhZTVjMWI5MmVkODBjODQiAA==", + "records": [ + { + "name": "ref-cast", + "vers": "1.0.27", + "deps": [ + { + "name": "ref-cast-impl", + "req": "=1.0.27", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ref-cast-test-suite", + "req": "^0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0.13", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.108", + "features": ["diff"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-08-19T04:27:28Z" + } + ] + }, + { + "path": "re/f-/ref-cast-impl", + "header": "AwIAAABldGFnOiAiMDI2NDk2YjU2YTUzOGExZjA1OWU1ZjQzYmZlMWZhNjMiAA==", + "records": [ + { + "name": "ref-cast-impl", + "vers": "1.0.27", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.74", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.35", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ref-cast", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-08-19T04:27:24Z" + } + ] + }, + { + "path": "re/ge/regex", + "header": "AwIAAABldGFnOiAiMDcwNTJlZDUyMmY5NWQ1YmI4Mjg5MGRhYTAwNDJlNDEiAA==", + "records": [ + { + "name": "regex", + "vers": "1.13.1", + "deps": [ + { + "name": "aho-corasick", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "anyhow", + "req": "^1.0.69", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "doc-comment", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "env_logger", + "req": "^0.9.3", + "features": ["atty", "humantime", "termcolor"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "memchr", + "req": "^2.6.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1.0.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "regex-automata", + "req": "^0.4.16", + "features": ["alloc", "syntax", "meta", "nfa-pikevm"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "regex-syntax", + "req": "^0.8.11", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "regex-test", + "req": "^0.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d", + "features": { + "pattern": [], + "perf-backtrack": ["regex-automata/nfa-backtrack"], + "perf-cache": [], + "perf-dfa": ["regex-automata/hybrid"], + "perf-dfa-full": ["regex-automata/dfa-build", "regex-automata/dfa-search"], + "perf-inline": ["regex-automata/perf-inline"], + "perf-onepass": ["regex-automata/dfa-onepass"], + "unicode": [ + "unicode-age", + "unicode-bool", + "unicode-case", + "unicode-gencat", + "unicode-perl", + "unicode-script", + "unicode-segment", + "regex-automata/unicode", + "regex-syntax/unicode" + ], + "unicode-age": ["regex-automata/unicode-age", "regex-syntax/unicode-age"], + "unicode-bool": ["regex-automata/unicode-bool", "regex-syntax/unicode-bool"], + "unicode-case": ["regex-automata/unicode-case", "regex-syntax/unicode-case"], + "unicode-gencat": ["regex-automata/unicode-gencat", "regex-syntax/unicode-gencat"], + "unicode-perl": [ + "regex-automata/unicode-perl", + "regex-automata/unicode-word-boundary", + "regex-syntax/unicode-perl" + ], + "unicode-script": ["regex-automata/unicode-script", "regex-syntax/unicode-script"], + "unicode-segment": ["regex-automata/unicode-segment", "regex-syntax/unicode-segment"], + "unstable": ["pattern"] + }, + "features2": { + "default": ["std", "perf", "unicode", "regex-syntax/default"], + "logging": ["aho-corasick?/logging", "memchr?/logging", "regex-automata/logging"], + "perf": [ + "perf-cache", + "perf-dfa", + "perf-onepass", + "perf-backtrack", + "perf-inline", + "perf-literal" + ], + "perf-literal": ["dep:aho-corasick", "dep:memchr", "regex-automata/perf-literal"], + "std": ["aho-corasick?/std", "memchr?/std", "regex-automata/std", "regex-syntax/std"], + "use_std": ["std"] + }, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-07-15T20:19:35Z", + "v": 2 + } + ] + }, + { + "path": "re/ge/regex-automata", + "header": "AwIAAABldGFnOiAiZmUzNmMyMGIxMDRmZWJhOWFlMzRhZWU4ZmRkZDMzNGMiAA==", + "records": [ + { + "name": "regex-automata", + "vers": "0.4.18", + "deps": [ + { + "name": "aho-corasick", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "anyhow", + "req": "^1.0.69", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "bstr", + "req": "^1.3.0", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "doc-comment", + "req": "^0.3.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "env_logger", + "req": "^0.9.3", + "features": ["atty", "humantime", "termcolor"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "log", + "req": "^0.4.14", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memchr", + "req": "^2.6.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1.0.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "regex-syntax", + "req": "^0.8.5", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "regex-test", + "req": "^0.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2", + "features": { + "alloc": [], + "dfa": ["dfa-build", "dfa-search", "dfa-onepass"], + "dfa-build": ["nfa-thompson", "dfa-search"], + "dfa-onepass": ["nfa-thompson"], + "dfa-search": [], + "hybrid": ["alloc", "nfa-thompson"], + "nfa": ["nfa-thompson", "nfa-pikevm", "nfa-backtrack"], + "nfa-backtrack": ["nfa-thompson"], + "nfa-pikevm": ["nfa-thompson"], + "nfa-thompson": ["alloc"], + "perf-inline": [], + "unicode-word-boundary": [] + }, + "features2": { + "default": ["std", "syntax", "perf", "unicode", "meta", "nfa", "dfa", "hybrid"], + "internal-instrument": ["internal-instrument-pikevm"], + "internal-instrument-pikevm": ["logging", "std"], + "logging": ["dep:log", "aho-corasick?/logging", "memchr?/logging"], + "meta": ["syntax", "nfa-pikevm"], + "perf": ["perf-inline", "perf-literal"], + "perf-literal": ["perf-literal-substring", "perf-literal-multisubstring"], + "perf-literal-multisubstring": ["dep:aho-corasick"], + "perf-literal-substring": ["aho-corasick?/perf-literal", "dep:memchr"], + "std": ["regex-syntax?/std", "memchr?/std", "aho-corasick?/std", "alloc"], + "syntax": ["dep:regex-syntax", "alloc"], + "unicode": [ + "unicode-age", + "unicode-bool", + "unicode-case", + "unicode-gencat", + "unicode-perl", + "unicode-script", + "unicode-segment", + "unicode-word-boundary", + "regex-syntax?/unicode" + ], + "unicode-age": ["regex-syntax?/unicode-age"], + "unicode-bool": ["regex-syntax?/unicode-bool"], + "unicode-case": ["regex-syntax?/unicode-case"], + "unicode-gencat": ["regex-syntax?/unicode-gencat"], + "unicode-perl": ["regex-syntax?/unicode-perl"], + "unicode-script": ["regex-syntax?/unicode-script"], + "unicode-segment": ["regex-syntax?/unicode-segment"] + }, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-08-04T13:10:37Z", + "v": 2 + } + ] + }, + { + "path": "re/ge/regex-syntax", + "header": "AwIAAABldGFnOiAiOGI3YWRiYzAwMDU0YmQ3ZDVkMTAxZjQzMzM1Yjg1YmEiAA==", + "records": [ + { + "name": "regex-syntax", + "vers": "0.8.11", + "deps": [ + { + "name": "arbitrary", + "req": "^1.3.0", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4", + "features": { + "default": ["std", "unicode"], + "std": [], + "unicode": [ + "unicode-age", + "unicode-bool", + "unicode-case", + "unicode-gencat", + "unicode-perl", + "unicode-script", + "unicode-segment" + ], + "unicode-age": [], + "unicode-bool": [], + "unicode-case": [], + "unicode-gencat": [], + "unicode-perl": [], + "unicode-script": [], + "unicode-segment": [] + }, + "features2": { + "arbitrary": ["dep:arbitrary"] + }, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-06-09T15:00:25Z", + "v": 2 + } + ] + }, + { + "path": "re/gi/region", + "header": "AwIAAABldGFnOiAiNTI1YjUyNGQ3YzMyM2Y2MTQwY2M5OGJlZjk2YTc3MTciAA==", + "records": [ + { + "name": "region", + "vers": "3.0.2", + "deps": [ + { + "name": "bitflags", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.153", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "mach2", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(target_os = \"macos\", target_os = \"ios\"))", + "kind": "normal" + }, + { + "name": "mmap", + "req": "^0.1.6", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "dev", + "package": "mmap-fixed" + }, + { + "name": "windows-sys", + "req": "^0.52.0", + "features": [ + "Win32_Foundation", + "Win32_System_Memory", + "Win32_System_SystemInformation", + "Win32_System_Diagnostics_Debug" + ], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7", + "features": {}, + "yanked": false, + "pubtime": "2024-03-25T08:23:23Z" + } + ] + }, + { + "path": "re/nd/rend", + "header": "AwIAAABldGFnOiAiYmMzNDE5MjRkMDVkODBhNGE5NTJjZDU2OThjODZhMGMiAA==", + "records": [ + { + "name": "rend", + "vers": "0.5.4", + "deps": [ + { + "name": "bytecheck", + "req": "^0.8", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "bytemuck-1", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "bytemuck" + }, + { + "name": "zerocopy", + "req": "^0.8", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerocopy-derive", + "req": "^0.8", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "663ba70707f96e871406fe10d68128412e619b06d1d47cb91c3a4c6501176240", + "features": { + "default": [] + }, + "features2": { + "zerocopy-0_8": ["dep:zerocopy", "dep:zerocopy-derive"] + }, + "yanked": false, + "pubtime": "2026-07-02T19:29:05Z", + "v": 2 + } + ] + }, + { + "path": "re/pl/replace_with", + "header": "AwIAAABldGFnOiAiYWFmMDdlMmMzNjFiNTY4N2FkMDE3MGM0M2U2YTE1NjkiAA==", + "records": [ + { + "name": "replace_with", + "vers": "0.1.8", + "deps": [], + "cksum": "51743d3e274e2b18df81c4dc6caf8a5b8e15dbe799e0dca05c7617380094e884", + "features": { + "default": ["std"], + "nightly": [], + "panic_abort": [], + "std": [] + }, + "yanked": false, + "pubtime": "2025-05-20T16:43:43Z" + } + ] + }, + { + "path": "rk/yv/rkyv", + "header": "AwIAAABldGFnOiAiNzYxOTI2ZWMwZDU1YTdhYjQ5NDIwMjNjZDllMGQwNmIiAA==", + "records": [ + { + "name": "rkyv", + "vers": "0.8.18", + "deps": [ + { + "name": "ahash", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "arrayvec-0_7", + "req": "^0.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "arrayvec" + }, + { + "name": "bytecheck", + "req": "^0.8", + "features": ["simdutf8"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "bytes-1", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "bytes" + }, + { + "name": "divan", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "hashbrown", + "req": "^0.17", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "hashbrown-0_14", + "req": "^0.14", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "hashbrown" + }, + { + "name": "hashbrown-0_15", + "req": "^0.15", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "hashbrown" + }, + { + "name": "hashbrown-0_16", + "req": "^0.16", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "hashbrown" + }, + { + "name": "indexmap-2", + "req": "^2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "indexmap" + }, + { + "name": "munge", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "ptr_meta", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rancor", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rend", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rkyv_derive", + "req": "=0.8.18", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rustversion", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "smallvec-1", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "smallvec" + }, + { + "name": "smol_str-0_2", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "smol_str" + }, + { + "name": "smol_str-0_3", + "req": "^0.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "smol_str" + }, + { + "name": "thin-vec-0_2", + "req": "^0.2.12", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "thin-vec" + }, + { + "name": "tinyvec-1", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "tinyvec" + }, + { + "name": "triomphe-0_1", + "req": "^0.1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "triomphe" + }, + { + "name": "trybuild", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "uuid-1", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "uuid" + } + ], + "cksum": "d9776093b7ca170454ab1406954f7b7d97a57c51dc6c0642957fb2ef25c2d399", + "features": { + "aligned": [], + "big_endian": [], + "little_endian": [], + "pointer_width_16": [], + "pointer_width_32": [], + "pointer_width_64": [], + "unaligned": [] + }, + "features2": { + "alloc": ["dep:hashbrown", "tinyvec-1?/alloc", "rancor/alloc"], + "bytecheck": ["dep:bytecheck", "rend/bytecheck", "rkyv_derive/bytecheck"], + "default": ["std", "bytecheck"], + "hashbrown-0_17": ["dep:hashbrown"], + "indexmap-2": ["dep:indexmap-2", "alloc"], + "std": ["alloc", "bytes-1?/std", "indexmap-2?/std", "ptr_meta/std", "uuid-1?/std"], + "triomphe-0_1": ["dep:triomphe-0_1", "alloc"], + "uuid-1": ["dep:uuid-1", "bytecheck?/uuid-1"] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-08-05T12:01:41Z", + "v": 2 + } + ] + }, + { + "path": "rk/yv/rkyv_derive", + "header": "AwIAAABldGFnOiAiYjUxMzQ1NTk2ZTZjYzVhNjBhMDk5YjIxMDA0MzdkMjMiAA==", + "records": [ + { + "name": "rkyv_derive", + "vers": "0.8.18", + "deps": [ + { + "name": "proc-macro2", + "req": "^1", + "features": ["proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": ["proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3.0", + "features": ["clone-impls", "derive", "parsing", "printing", "proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "1c25ef604ac7dd839d44d64648952ea23c97866f124ff671b0ed2cf3ad9bb06e", + "features": { + "bytecheck": [], + "default": [] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-08-05T12:01:39Z" + } + ] + }, + { + "path": "ru/st/rustc_version", + "header": "AwIAAABldGFnOiAiMjg2MjAxZDlkNWI0YzdkZDI4Mzc1MzhkM2FmYmIxNDAiAA==", + "records": [ + { + "name": "rustc_version", + "vers": "0.4.1", + "deps": [ + { + "name": "doc-comment", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "semver", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92", + "features": {}, + "yanked": false, + "rust_version": "1.32", + "pubtime": "2024-08-28T09:21:22Z" + } + ] + }, + { + "path": "ru/st/rustc-demangle", + "header": "AwIAAABldGFnOiAiNDc1NDhkYThlMzJkNTE0ZjJlM2E4MGI3YWUzZTU0YmIiAA==", + "records": [ + { + "name": "rustc-demangle", + "vers": "0.1.28", + "deps": [ + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + } + ], + "cksum": "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb", + "features": { + "compiler_builtins": [], + "rustc-dep-of-std": ["core"], + "std": [] + }, + "yanked": false, + "pubtime": "2026-07-08T16:08:22Z" + } + ] + }, + { + "path": "ru/st/rustc-hash", + "header": "AwIAAABldGFnOiAiOWIzNTFlY2MyNGMyYjIxNGVhMjczMzJjYjk3ZWIxNzEiAA==", + "records": [ + { + "name": "rustc-hash", + "vers": "2.1.3", + "deps": [ + { + "name": "rand", + "req": "^0.9", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d", + "features": { + "default": ["std"], + "nightly": [], + "std": [] + }, + "features2": { + "rand": ["dep:rand", "std"] + }, + "yanked": false, + "rust_version": "1.77", + "pubtime": "2026-07-02T19:13:03Z", + "v": 2 + } + ] + }, + { + "path": "ru/st/rustix", + "header": "AwIAAABldGFnOiAiMTRkZDQxMTBiMGY3MDMwNWU2MGU0ZjI2OGIxZDE3NmQiAA==", + "records": [ + { + "name": "rustix", + "vers": "1.1.5", + "deps": [ + { + "name": "bitflags", + "req": "^2.4.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "criterion", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(criterion, not(any(target_os = \"emscripten\", target_os = \"wasi\"))))", + "kind": "dev" + }, + { + "name": "flate2", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "libc", + "req": "^0.2.182", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\")))))))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.182", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(not(rustix_use_libc), not(miri), target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\"))))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.171", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "libc_errno", + "req": "^0.3.10", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\")))))))", + "kind": "normal", + "package": "errno" + }, + { + "name": "libc_errno", + "req": "^0.3.10", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(windows)", + "kind": "normal", + "package": "errno" + }, + { + "name": "libc_errno", + "req": "^0.3.10", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(not(rustix_use_libc), not(miri), target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\"))))", + "kind": "normal", + "package": "errno" + }, + { + "name": "libc_errno", + "req": "^0.3.10", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "errno" + }, + { + "name": "linux-raw-sys", + "req": "^0.12", + "features": ["general", "ioctl", "no_std"], + "optional": false, + "default_features": false, + "target": "cfg(all(any(target_os = \"linux\", target_os = \"android\"), any(rustix_use_libc, miri, not(all(target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\")))))))", + "kind": "normal" + }, + { + "name": "linux-raw-sys", + "req": "^0.12", + "features": ["auxvec", "general", "errno", "ioctl", "no_std", "elf"], + "optional": false, + "default_features": false, + "target": "cfg(all(not(rustix_use_libc), not(miri), target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\"))))", + "kind": "normal" + }, + { + "name": "memoffset", + "req": "^0.9.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "once_cell", + "req": "^1.20.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "dev" + }, + { + "name": "rustc-std-workspace-alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serial_test", + "req": "^2.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tempfile", + "req": "^3.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "windows-sys", + "req": ">=0.52, <0.62", + "features": ["Win32_Foundation", "Win32_Networking_WinSock"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d", + "features": { + "all-apis": [ + "event", + "fs", + "io_uring", + "mm", + "mount", + "net", + "param", + "pipe", + "process", + "pty", + "rand", + "runtime", + "shm", + "stdio", + "system", + "termios", + "thread", + "time" + ], + "alloc": [], + "event": [], + "fs": [], + "io_uring": ["event", "fs", "net", "thread", "linux-raw-sys/io_uring"], + "linux_4_11": [], + "linux_5_1": ["linux_4_11"], + "linux_5_11": ["linux_5_1"], + "linux_latest": ["linux_5_11"], + "mm": [], + "mount": [], + "net": [ + "linux-raw-sys/net", + "linux-raw-sys/netlink", + "linux-raw-sys/if_ether", + "linux-raw-sys/xdp" + ], + "param": [], + "pipe": [], + "process": ["linux-raw-sys/prctl"], + "pty": ["fs"], + "rand": [], + "runtime": ["linux-raw-sys/prctl"], + "rustc-dep-of-std": [ + "core", + "rustc-std-workspace-alloc", + "linux-raw-sys/rustc-dep-of-std", + "bitflags/rustc-dep-of-std" + ], + "shm": ["fs"], + "stdio": [], + "system": ["linux-raw-sys/system"], + "termios": [], + "thread": ["linux-raw-sys/prctl"], + "time": [], + "try_close": [], + "use-explicitly-provided-auxv": [], + "use-libc": ["libc_errno", "libc"], + "use-libc-auxv": [] + }, + "features2": { + "default": ["std"], + "std": ["bitflags/std", "alloc", "libc?/std", "libc_errno?/std"] + }, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-09-16T23:05:02Z", + "v": 2 + } + ] + }, + { + "path": "ru/st/rustix-linux-procfs", + "header": "AwIAAABldGFnOiAiNDY3YTc3OWM4MGZhMmY5YzE4NmNiOWRhNmYwOGJhNjYiAA==", + "records": [ + { + "name": "rustix-linux-procfs", + "vers": "0.1.1", + "deps": [ + { + "name": "once_cell", + "req": "^1.5.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustix", + "req": "^1.0.0", + "features": ["alloc", "fs"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rustix", + "req": "^1.0.0", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + } + ], + "cksum": "2fc84bf7e9aa16c4f2c758f27412dc9841341e16aa682d9c7ac308fe3ee12056", + "features": { + "default": ["std"], + "std": ["rustix/std"] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2025-04-21T21:17:44Z" + } + ] + }, + { + "path": "ru/st/rustversion", + "header": "AwIAAABldGFnOiAiZjg5Y2I5ODU1YjYxNzJkN2MyNzFiMzlmOTQ5OTZlYjAiAA==", + "records": [ + { + "name": "rustversion", + "vers": "1.0.23", + "deps": [ + { + "name": "trybuild", + "req": "^1.0.49", + "features": ["diff"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f", + "features": {}, + "yanked": false, + "rust_version": "1.31", + "pubtime": "2026-07-07T02:10:26Z" + } + ] + }, + { + "path": "ru/st/rusty_pool", + "header": "AwIAAABldGFnOiAiNjQ2NGNkNjkyMzM0NGUzNGU3ZjY4ZWJkMmJhNjQ5YTMiAA==", + "records": [ + { + "name": "rusty_pool", + "vers": "0.7.0", + "deps": [ + { + "name": "crossbeam-channel", + "req": "^0.5.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures", + "req": "^0.3.21", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures-channel", + "req": "^0.3.21", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures-executor", + "req": "^0.3.21", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "num_cpus", + "req": "^1.13.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "4ed36cdb20de66d89a17ea04b8883fc7a386f2cf877aaedca5005583ce4876ff", + "features": { + "async": ["futures"], + "default": ["async"] + }, + "yanked": false, + "pubtime": "2022-05-05T22:18:23Z" + } + ] + }, + { + "path": "ru/zs/ruzstd", + "header": "AwIAAABldGFnOiAiYjg2NjY3ZTUxZjRjYTkzNDBjZTE2MDI3ZTM4NzI1N2MiAA==", + "records": [ + { + "name": "ruzstd", + "vers": "0.8.3", + "deps": [ + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "compiler_builtins", + "req": "^0.1.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "criterion", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "fastrand", + "req": "^2.3.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.8.5", + "features": ["small_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "twox-hash", + "req": "^2.0", + "features": ["xxhash64"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zstd", + "req": "^0.13.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "a7c1c839d570d835527c9a5e4db7cb2198683a988cb9d7293fc8674e6bd58fc8", + "features": { + "fuzz_exports": [], + "std": [] + }, + "features2": { + "default": ["hash", "std"], + "dict_builder": ["std", "dep:fastrand"], + "hash": ["dep:twox-hash"], + "rustc-dep-of-std": ["dep:compiler_builtins", "dep:core", "dep:alloc"] + }, + "yanked": false, + "rust_version": "1.87", + "pubtime": "2026-05-08T12:35:05Z", + "v": 2 + } + ] + }, + { + "path": "sa/ff/saffron", + "header": "AwIAAABldGFnOiAiNWYyYWU5ZmY2N2VhZmE2ZDg2OTBjNGFlOWEwNzUyMWMiAA==", + "records": [ + { + "name": "saffron", + "vers": "0.1.0", + "deps": [ + { + "name": "chrono", + "req": "^0.4", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "criterion", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "nom", + "req": "^5.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "03fb9a628596fc7590eb7edbf7b0613287be78df107f5f97b118aad59fb2eea9", + "features": { + "default": [], + "std": [] + }, + "yanked": false, + "pubtime": "2021-02-01T21:08:52Z" + } + ] + }, + { + "path": "sa/me/same-file", + "header": "AwIAAABldGFnOiAiNTY3M2NjNjQxOGFjNmJiNTUyOWI5ZjlmNDM3OGJmMDciAA==", + "records": [ + { + "name": "same-file", + "vers": "1.0.6", + "deps": [ + { + "name": "doc-comment", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "winapi-util", + "req": "^0.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502", + "features": {}, + "yanked": false, + "pubtime": "2020-01-11T17:02:30Z" + } + ] + }, + { + "path": "sc/he/schemars", + "header": "AwIAAABldGFnOiAiOWM5M2M1MzdhNWJjZGYxMGM3YjZmZWY4MzhhOTIzZWUiAA==", + "records": [ + { + "name": "schemars", + "vers": "1.2.2", + "deps": [ + { + "name": "arrayvec07", + "req": "^0.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "arrayvec" + }, + { + "name": "arrayvec07", + "req": "^0.7", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "arrayvec" + }, + { + "name": "bigdecimal04", + "req": "^0.4", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "bigdecimal" + }, + { + "name": "bigdecimal04", + "req": "^0.4", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "bigdecimal" + }, + { + "name": "bytes1", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "bytes" + }, + { + "name": "bytes1", + "req": "^1.0", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "bytes" + }, + { + "name": "chrono04", + "req": "^0.4.39", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "chrono" + }, + { + "name": "chrono04", + "req": "^0.4", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "chrono" + }, + { + "name": "dyn-clone", + "req": "^1.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "either1", + "req": "^1.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "either" + }, + { + "name": "either1", + "req": "^1.3", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "either" + }, + { + "name": "garde", + "req": "^0.23", + "features": ["derive", "email", "regex", "url"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "indexmap2", + "req": "^2.2.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "indexmap" + }, + { + "name": "indexmap2", + "req": "^2.0", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "indexmap" + }, + { + "name": "jiff02", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "jiff" + }, + { + "name": "jiff02", + "req": "^0.2", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "jiff" + }, + { + "name": "jsonschema", + "req": "^0.30", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "pretty_assertions", + "req": "^1.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ref-cast", + "req": "^1.0.22", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "regex", + "req": "^1.10.6", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rust_decimal1", + "req": "^1.13", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "rust_decimal" + }, + { + "name": "rust_decimal1", + "req": "^1", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "rust_decimal" + }, + { + "name": "schemars_derive", + "req": "=1.2.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "semver1", + "req": "^1.0.9", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "semver" + }, + { + "name": "semver1", + "req": "^1.0.9", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "semver" + }, + { + "name": "serde", + "req": "^1.0.194", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0.127", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_repr", + "req": "^0.1.19", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "smallvec1", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "smallvec" + }, + { + "name": "smallvec1", + "req": "^1.0", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "smallvec" + }, + { + "name": "smol_str02", + "req": "^0.2.1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "smol_str" + }, + { + "name": "smol_str02", + "req": "^0.2.1", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "smol_str" + }, + { + "name": "smol_str03", + "req": "^0.3.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "smol_str" + }, + { + "name": "smol_str03", + "req": "^0.3.2", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "smol_str" + }, + { + "name": "snapbox", + "req": "^0.6.17", + "features": ["json"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "url2", + "req": "^2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "url" + }, + { + "name": "url2", + "req": "^2.0", + "features": ["serde", "std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "url" + }, + { + "name": "uuid1", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "uuid" + }, + { + "name": "uuid1", + "req": "^1.0", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "uuid" + }, + { + "name": "validator", + "req": "^0.21", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a", + "features": { + "_ui_test": [], + "default": ["derive", "std"], + "derive": ["schemars_derive"], + "preserve_order": ["serde_json/preserve_order"], + "raw_value": ["serde_json/raw_value"], + "std": [] + }, + "yanked": false, + "rust_version": "1.74", + "pubtime": "2026-07-27T14:35:28Z" + } + ] + }, + { + "path": "sc/he/schemars_derive", + "header": "AwIAAABldGFnOiAiNmY2MTQwNzM3MDc4MWNlN2ZlNzAwMWUyNjZjYjAyZTciAA==", + "records": [ + { + "name": "schemars_derive", + "vers": "1.2.2", + "deps": [ + { + "name": "pretty_assertions", + "req": "^1.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1.0.91", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.35", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive_internals", + "req": "^0.30.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3", + "features": ["extra-traits"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "d98c67716b46af2f0b8cf752abc930f6f9aecfbf671ecfb531db8a31dbe4e2ba", + "features": {}, + "yanked": false, + "rust_version": "1.74", + "pubtime": "2026-07-27T14:35:25Z" + } + ] + }, + { + "path": "sc/op/scopeguard", + "header": "AwIAAABldGFnOiAiZGFhOTM4MDg0ZjI1ZjhhNjkzYWU4ZjE0YThmYWQwZDMiAA==", + "records": [ + { + "name": "scopeguard", + "vers": "1.2.0", + "deps": [], + "cksum": "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49", + "features": { + "default": ["use_std"], + "use_std": [] + }, + "yanked": false, + "pubtime": "2023-07-17T13:47:53Z" + } + ] + }, + { + "path": "se/lf/self_cell", + "header": "AwIAAABldGFnOiAiYjUxMjJjOTU2YTQzMTU5OTc1Yjk4YmE3NGU1NzMwMzkiAA==", + "records": [ + { + "name": "self_cell", + "vers": "1.3.0", + "deps": [ + { + "name": "once_cell", + "req": "=1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": ">=1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "2ab42ca02749e120097e328d91d415325bdf43b1c72c4c8badf37375fe40a813", + "features": { + "old_rust": ["rustversion"] + }, + "yanked": false, + "pubtime": "2026-07-16T07:47:15Z" + } + ] + }, + { + "path": "se/mv/semver", + "header": "AwIAAABldGFnOiAiZmIyNTA5YTJhYWIyYjJmOGM3Nzk3YWMxZDA3M2UxMWMiAA==", + "records": [ + { + "name": "semver", + "vers": "1.0.28", + "deps": [ + { + "name": "criterion", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "serde_core" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(any())", + "kind": "normal" + } + ], + "cksum": "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd", + "features": { + "default": ["std"], + "std": [] + }, + "features2": { + "serde": ["dep:serde"] + }, + "yanked": false, + "rust_version": "1.68", + "pubtime": "2026-04-04T00:25:14Z", + "v": 2 + } + ] + }, + { + "path": "se/rd/serde", + "header": "AwIAAABldGFnOiAiOTcxZTFhNzFkN2Q2YWZiZmM5MGEyM2FkOTE5MzExMDMiAA==", + "records": [ + { + "name": "serde", + "vers": "1.0.229", + "deps": [ + { + "name": "serde_core", + "req": "=1.0.229", + "features": ["result"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba", + "features": { + "alloc": ["serde_core/alloc"], + "default": ["std"], + "derive": ["serde_derive"], + "rc": ["serde_core/rc"], + "std": ["serde_core/std"], + "unstable": ["serde_core/unstable"] + }, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2026-07-18T23:05:13Z" + } + ] + }, + { + "path": "se/rd/serde_core", + "header": "AwIAAABldGFnOiAiMDY3N2FlODQ2MzcwZWVmNTdkMDBkYjRhZjdhYjM5ZmMiAA==", + "records": [ + { + "name": "serde_core", + "vers": "1.0.229", + "deps": [ + { + "name": "serde", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_derive", + "req": "=1.0.229", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any())", + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48", + "features": { + "alloc": [], + "default": ["std", "result"], + "rc": [], + "result": [], + "std": [], + "unstable": [] + }, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2026-07-18T23:05:10Z" + } + ] + }, + { + "path": "se/rd/serde_derive", + "header": "AwIAAABldGFnOiAiOWM3YjkyYmFjZWE4YmNhMTdlZTI2MzBiNjQyZjA2ZTUiAA==", + "records": [ + { + "name": "serde_derive", + "vers": "1.0.229", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.74", + "features": ["proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.35", + "features": ["proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn", + "req": "^3", + "features": ["clone-impls", "derive", "parsing", "printing", "proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348", + "features": { + "default": [], + "deserialize_in_place": [] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-18T23:05:07Z" + } + ] + }, + { + "path": "se/rd/serde_derive_internals", + "header": "AwIAAABldGFnOiAiOWVhMDIxMDdlMWE2OTI4ZDMxMTlhZjhkYTgxZDlmNTgiAA==", + "records": [ + { + "name": "serde_derive_internals", + "vers": "0.30.0", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.74", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.35", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3", + "features": ["clone-impls", "derive", "parsing", "printing"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "f852137cce035d6a4df67ccce505ff6b3e9fd3a10e3e52b24dc71e650bb1a9bd", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-25T14:58:00Z" + } + ] + }, + { + "path": "se/rd/serde_json", + "header": "AwIAAABldGFnOiAiN2Y1OTcyOGUwYjFkMWRhZTkwYjgxZjA0ZjQwMmNhOWYiAA==", + "records": [ + { + "name": "serde_json", + "vers": "1.0.154", + "deps": [ + { + "name": "automod", + "req": "^1.0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "foldhash", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2.2.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "indoc", + "req": "^2.0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "itoa", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memchr", + "req": "^2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "ref-cast", + "req": "^1.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0.13", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any())", + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.194", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_bytes", + "req": "^0.11.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.220", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1.0.166", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_stacker", + "req": "^0.1.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.108", + "features": ["diff"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "zmij", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6", + "features": { + "alloc": ["serde_core/alloc"], + "arbitrary_precision": [], + "default": ["std"], + "float_roundtrip": [], + "raw_value": [], + "std": ["memchr/std", "serde_core/std"], + "unbounded_depth": [] + }, + "features2": { + "preserve_order": ["indexmap", "alloc", "dep:foldhash"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-10-11T15:31:46Z", + "v": 2 + } + ] + }, + { + "path": "se/rd/serde_spanned", + "header": "AwIAAABldGFnOiAiY2EyZmZlMWQ1MTMxMGU2MmU3YWQ0ODdkOGJjMTgzNWEiAA==", + "records": [ + { + "name": "serde_spanned", + "vers": "1.1.2", + "deps": [ + { + "name": "serde", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde-untagged", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.228", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "4e7523beb55eece201a2356bee0bbca0d1ab466c14c07703b2e0ee6d42cb0c2c", + "features": {}, + "features2": { + "alloc": ["serde_core?/alloc"], + "default": ["std", "serde"], + "serde": ["dep:serde_core"], + "std": ["alloc", "serde_core?/std"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-10-08T00:54:02Z", + "v": 2 + } + ] + }, + { + "path": "se/rd/serde_yaml", + "header": "AwIAAABldGFnOiAiZDUzOWZkYjQ4YjU5MmZhZmFmZDQwMDJkYmY0Yzk3ZGEiAA==", + "records": [ + { + "name": "serde_yaml", + "vers": "0.9.34+deprecated", + "deps": [ + { + "name": "anyhow", + "req": "^1.0.79", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "indexmap", + "req": "^2.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "indoc", + "req": "^2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "itoa", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ryu", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.195", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1.0.195", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unsafe-libyaml", + "req": "^0.2.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47", + "features": {}, + "yanked": false, + "rust_version": "1.64", + "pubtime": "2024-03-25T00:50:19Z" + } + ] + }, + { + "path": "se/rd/serde-wasm-bindgen", + "header": "AwIAAABldGFnOiAiZGUzODEwMDkxYmM0YWEyMjViYjI3NjUwNTVjNGQyZWQiAA==", + "records": [ + { + "name": "serde-wasm-bindgen", + "vers": "0.6.5", + "deps": [ + { + "name": "bincode", + "req": "^1.3.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "getrandom", + "req": "^0.2", + "features": ["js"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "js-sys", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "maplit", + "req": "^1.0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proptest", + "req": "^1.0", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.193", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_bytes", + "req": "^0.11.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0.39", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "wasm-bindgen", + "req": "^0.2.83", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3.24", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b", + "features": {}, + "yanked": false, + "pubtime": "2024-02-27T21:32:21Z" + } + ] + }, + { + "path": "sh/a2/sha2", + "header": "AwIAAABldGFnOiAiZWYwMzI4MTFlOTZmMThhNWEzZjQ3NTkwNDRmM2NlZmMiAA==", + "records": [ + { + "name": "sha2", + "vers": "0.10.9", + "deps": [ + { + "name": "cfg-if", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cpufeatures", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))", + "kind": "normal" + }, + { + "name": "digest", + "req": "^0.10.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "digest", + "req": "^0.10.7", + "features": ["dev"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hex-literal", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "sha2-asm", + "req": "^0.6.1", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))", + "kind": "normal" + } + ], + "cksum": "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283", + "features": { + "asm": ["sha2-asm"], + "asm-aarch64": ["asm"], + "compress": [], + "default": ["std"], + "force-soft": [], + "force-soft-compact": [], + "loongarch64_asm": [], + "oid": ["digest/oid"], + "std": ["digest/std"] + }, + "yanked": false, + "pubtime": "2025-04-30T14:38:09Z" + }, + { + "name": "sha2", + "vers": "0.11.0", + "deps": [ + { + "name": "cfg-if", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cpufeatures", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))", + "kind": "normal" + }, + { + "name": "digest", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "digest", + "req": "^0.11", + "features": ["dev"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hex-literal", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4", + "features": { + "alloc": ["digest/alloc"], + "default": ["alloc", "oid"], + "oid": ["digest/oid"], + "zeroize": ["digest/zeroize"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-03-25T15:05:27Z" + } + ] + }, + { + "path": "sh/ar/shared-buffer", + "header": "AwIAAABldGFnOiAiNTk0MTE5ZDY5ZjUyYTc5NzJjZDk5MWMxYmFkMzU5ZDciAA==", + "records": [ + { + "name": "shared-buffer", + "vers": "0.1.4", + "deps": [ + { + "name": "bytes", + "req": "^1.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memmap2", + "req": "^0.6.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "f6c99835bad52957e7aa241d3975ed17c1e5f8c92026377d117a606f36b84b16", + "features": {}, + "yanked": false, + "rust_version": "1.64.0", + "pubtime": "2023-12-14T15:44:28Z" + } + ] + }, + { + "path": "sh/le/shlex", + "header": "AwIAAABldGFnOiAiMzU1MWFhZTM0MTRhOWUyYWY2MDhkNTU1NzkzNzg0NWEiAA==", + "records": [ + { + "name": "shlex", + "vers": "1.3.0", + "deps": [], + "cksum": "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.46.0", + "pubtime": "2024-01-22T05:15:15Z" + }, + { + "name": "shlex", + "vers": "2.0.1", + "deps": [], + "cksum": "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.46.0", + "pubtime": "2026-05-17T18:56:12Z" + } + ] + }, + { + "path": "si/md/simd-adler32", + "header": "AwIAAABldGFnOiAiOTdkYjJkZDI3ZmJkNGNkMDM3ZjUyMjhkZDcwMTg2NzQiAA==", + "records": [ + { + "name": "simd-adler32", + "vers": "0.3.10", + "deps": [ + { + "name": "adler2", + "req": "^2.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "adler32", + "req": "^1.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.8", + "features": ["small_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea", + "features": { + "const-generics": [], + "default": ["std", "const-generics"], + "nightly": [], + "std": [] + }, + "yanked": false, + "pubtime": "2026-07-14T17:42:45Z" + } + ] + }, + { + "path": "si/md/simdutf8", + "header": "AwIAAABldGFnOiAiODIxMTY4ZmFlN2U2ZDI2NTU1YmI2MTJjMWI4ZTA0YmUiAA==", + "records": [ + { + "name": "simdutf8", + "vers": "0.1.5", + "deps": [], + "cksum": "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e", + "features": { + "aarch64_neon": [], + "aarch64_neon_prefetch": [], + "default": ["std"], + "hints": [], + "public_imp": [], + "std": [] + }, + "yanked": false, + "pubtime": "2024-09-22T09:18:22Z" + } + ] + }, + { + "path": "si/mi/similar", + "header": "AwIAAABldGFnOiAiYjFhMmIzZmQ1MzZkZWY3MGMyZGJkZWJkMmZlNjRhNzIiAA==", + "records": [ + { + "name": "similar", + "vers": "2.7.0", + "deps": [ + { + "name": "bstr", + "req": "^1.5.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "console", + "req": "^0.15.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "insta", + "req": "^1.10.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.130", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.68", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicode-segmentation", + "req": "^1.7.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "web-time", + "req": "^1.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa", + "features": { + "bytes": ["bstr", "text"], + "default": ["text"], + "inline": ["text"], + "text": [], + "wasm32_web_time": ["web-time"] + }, + "features2": { + "unicode": ["text", "unicode-segmentation", "bstr?/unicode", "bstr?/std"] + }, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-01-19T14:39:11Z", + "v": 2 + } + ] + }, + { + "path": "si/ph/siphasher", + "header": "AwIAAABldGFnOiAiMzJmOWJiMjMxM2EyNTI2MjgzYzFkY2M0ZjE1MDJjYTgiAA==", + "records": [ + { + "name": "siphasher", + "vers": "1.0.4", + "deps": [ + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "33f4fe9184a62d842c9ef383018f3306d8ba224fd9d836f56d7288308847c256", + "features": { + "default": ["std"], + "serde_no_std": ["serde/alloc"], + "serde_std": ["std", "serde/std"], + "std": [] + }, + "yanked": false, + "pubtime": "2026-09-25T08:51:05Z" + } + ] + }, + { + "path": "sl/ab/slab", + "header": "AwIAAABldGFnOiAiNGU0MDdhZWUyNGYwZGJhYmQyOTdmNzRmZmM5Zjk0ZDIiAA==", + "records": [ + { + "name": "slab", + "vers": "0.4.12", + "deps": [ + { + "name": "serde", + "req": "^1.0.95", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_test", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.51", + "pubtime": "2026-01-31T12:59:22Z" + } + ] + }, + { + "path": "sm/al/smallvec", + "header": "AwIAAABldGFnOiAiNmMwOGM2NWY5MjQzODI5NGI2YjQ3NjNkOTMyYjE0NDMiAA==", + "records": [ + { + "name": "smallvec", + "vers": "1.16.3", + "deps": [ + { + "name": "arbitrary", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bincode", + "req": "^2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "bincode1", + "req": "^1.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "bincode" + }, + { + "name": "malloc_size_of", + "req": "^0.1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "unty", + "req": "^0.0.4", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "5b3dc8af474f516a851ff4bd12db780f948b9250ad37211e4eec0bccea54e01b", + "features": { + "const_generics": [], + "const_new": ["const_generics"], + "drain_filter": [], + "drain_keep_rest": ["drain_filter"], + "impl_bincode": ["bincode", "unty"], + "may_dangle": [], + "specialization": [], + "union": [], + "write": [] + }, + "yanked": false, + "pubtime": "2026-10-10T02:25:27Z" + } + ] + }, + { + "path": "sm/ol/smoltcp", + "header": "AwIAAABldGFnOiAiYWI2OGFiYjk1NTUxZmVlN2QwNmFjZTI5OTU3MzgyYzciAA==", + "records": [ + { + "name": "smoltcp", + "vers": "0.13.1", + "deps": [ + { + "name": "bitflags", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "byteorder", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "defmt", + "req": "^0.3.8", + "features": ["ip_in_core"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "env_logger", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "getopts", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "heapless", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "idna", + "req": "=1.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "insta", + "req": "^1.41.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "libc", + "req": "^0.2.18", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "log", + "req": "^0.4.4", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "managed", + "req": "^0.8", + "features": ["map"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand_chacha", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rstest", + "req": "^0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "url", + "req": "^2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "5f73d40463bba65efc9adc6370b56df76d563cc46e2482bba58351b4afb7535e", + "features": { + "_netsim": [], + "_proto-fragmentation": [], + "assembler-max-segment-count-1": [], + "assembler-max-segment-count-16": [], + "assembler-max-segment-count-2": [], + "assembler-max-segment-count-3": [], + "assembler-max-segment-count-32": [], + "assembler-max-segment-count-4": [], + "assembler-max-segment-count-8": [], + "async": [], + "auto-icmp-echo-reply": [], + "dns-max-name-size-128": [], + "dns-max-name-size-255": [], + "dns-max-name-size-64": [], + "dns-max-result-count-1": [], + "dns-max-result-count-16": [], + "dns-max-result-count-2": [], + "dns-max-result-count-3": [], + "dns-max-result-count-32": [], + "dns-max-result-count-4": [], + "dns-max-result-count-8": [], + "dns-max-server-count-1": [], + "dns-max-server-count-16": [], + "dns-max-server-count-2": [], + "dns-max-server-count-3": [], + "dns-max-server-count-32": [], + "dns-max-server-count-4": [], + "dns-max-server-count-8": [], + "fragmentation-buffer-size-1024": [], + "fragmentation-buffer-size-1500": [], + "fragmentation-buffer-size-16384": [], + "fragmentation-buffer-size-2048": [], + "fragmentation-buffer-size-256": [], + "fragmentation-buffer-size-32768": [], + "fragmentation-buffer-size-4096": [], + "fragmentation-buffer-size-512": [], + "fragmentation-buffer-size-65536": [], + "fragmentation-buffer-size-8192": [], + "iface-max-addr-count-1": [], + "iface-max-addr-count-2": [], + "iface-max-addr-count-3": [], + "iface-max-addr-count-4": [], + "iface-max-addr-count-5": [], + "iface-max-addr-count-6": [], + "iface-max-addr-count-7": [], + "iface-max-addr-count-8": [], + "iface-max-multicast-group-count-1": [], + "iface-max-multicast-group-count-1024": [], + "iface-max-multicast-group-count-128": [], + "iface-max-multicast-group-count-16": [], + "iface-max-multicast-group-count-2": [], + "iface-max-multicast-group-count-256": [], + "iface-max-multicast-group-count-3": [], + "iface-max-multicast-group-count-32": [], + "iface-max-multicast-group-count-4": [], + "iface-max-multicast-group-count-5": [], + "iface-max-multicast-group-count-512": [], + "iface-max-multicast-group-count-6": [], + "iface-max-multicast-group-count-64": [], + "iface-max-multicast-group-count-7": [], + "iface-max-multicast-group-count-8": [], + "iface-max-prefix-count-1": [], + "iface-max-prefix-count-2": [], + "iface-max-prefix-count-3": [], + "iface-max-prefix-count-4": [], + "iface-max-prefix-count-5": [], + "iface-max-prefix-count-6": [], + "iface-max-prefix-count-7": [], + "iface-max-prefix-count-8": [], + "iface-max-route-count-0": [], + "iface-max-route-count-1": [], + "iface-max-route-count-1024": [], + "iface-max-route-count-128": [], + "iface-max-route-count-16": [], + "iface-max-route-count-2": [], + "iface-max-route-count-256": [], + "iface-max-route-count-3": [], + "iface-max-route-count-32": [], + "iface-max-route-count-4": [], + "iface-max-route-count-5": [], + "iface-max-route-count-512": [], + "iface-max-route-count-6": [], + "iface-max-route-count-64": [], + "iface-max-route-count-7": [], + "iface-max-route-count-8": [], + "iface-max-sixlowpan-address-context-count-1": [], + "iface-max-sixlowpan-address-context-count-1024": [], + "iface-max-sixlowpan-address-context-count-128": [], + "iface-max-sixlowpan-address-context-count-16": [], + "iface-max-sixlowpan-address-context-count-2": [], + "iface-max-sixlowpan-address-context-count-256": [], + "iface-max-sixlowpan-address-context-count-3": [], + "iface-max-sixlowpan-address-context-count-32": [], + "iface-max-sixlowpan-address-context-count-4": [], + "iface-max-sixlowpan-address-context-count-5": [], + "iface-max-sixlowpan-address-context-count-512": [], + "iface-max-sixlowpan-address-context-count-6": [], + "iface-max-sixlowpan-address-context-count-64": [], + "iface-max-sixlowpan-address-context-count-7": [], + "iface-max-sixlowpan-address-context-count-8": [], + "iface-neighbor-cache-count-1": [], + "iface-neighbor-cache-count-1024": [], + "iface-neighbor-cache-count-128": [], + "iface-neighbor-cache-count-16": [], + "iface-neighbor-cache-count-2": [], + "iface-neighbor-cache-count-256": [], + "iface-neighbor-cache-count-3": [], + "iface-neighbor-cache-count-32": [], + "iface-neighbor-cache-count-4": [], + "iface-neighbor-cache-count-5": [], + "iface-neighbor-cache-count-512": [], + "iface-neighbor-cache-count-6": [], + "iface-neighbor-cache-count-64": [], + "iface-neighbor-cache-count-7": [], + "iface-neighbor-cache-count-8": [], + "ipv6-hbh-max-options-1": [], + "ipv6-hbh-max-options-16": [], + "ipv6-hbh-max-options-2": [], + "ipv6-hbh-max-options-3": [], + "ipv6-hbh-max-options-32": [], + "ipv6-hbh-max-options-4": [], + "ipv6-hbh-max-options-8": [], + "medium-ethernet": ["socket"], + "medium-ieee802154": ["socket", "proto-sixlowpan"], + "medium-ip": ["socket"], + "multicast": [], + "packetmeta-id": [], + "proto-dhcpv4": ["proto-ipv4"], + "proto-dns": [], + "proto-ipsec": ["proto-ipsec-ah", "proto-ipsec-esp"], + "proto-ipsec-ah": [], + "proto-ipsec-esp": [], + "proto-ipv4": [], + "proto-ipv4-fragmentation": ["proto-ipv4", "_proto-fragmentation"], + "proto-ipv6": [], + "proto-ipv6-fragmentation": ["proto-ipv6", "_proto-fragmentation"], + "proto-ipv6-hbh": ["proto-ipv6"], + "proto-ipv6-routing": ["proto-ipv6"], + "proto-ipv6-slaac": ["proto-ipv6"], + "proto-rpl": ["proto-ipv6-hbh", "proto-ipv6-routing"], + "proto-sixlowpan": ["proto-ipv6"], + "proto-sixlowpan-fragmentation": ["proto-sixlowpan", "_proto-fragmentation"], + "reassembly-buffer-count-1": [], + "reassembly-buffer-count-16": [], + "reassembly-buffer-count-2": [], + "reassembly-buffer-count-3": [], + "reassembly-buffer-count-32": [], + "reassembly-buffer-count-4": [], + "reassembly-buffer-count-8": [], + "reassembly-buffer-size-1024": [], + "reassembly-buffer-size-1500": [], + "reassembly-buffer-size-16384": [], + "reassembly-buffer-size-2048": [], + "reassembly-buffer-size-256": [], + "reassembly-buffer-size-32768": [], + "reassembly-buffer-size-4096": [], + "reassembly-buffer-size-512": [], + "reassembly-buffer-size-65536": [], + "reassembly-buffer-size-8192": [], + "rpl-parents-buffer-count-16": [], + "rpl-parents-buffer-count-2": [], + "rpl-parents-buffer-count-32": [], + "rpl-parents-buffer-count-4": [], + "rpl-parents-buffer-count-8": [], + "rpl-relations-buffer-count-1": [], + "rpl-relations-buffer-count-128": [], + "rpl-relations-buffer-count-16": [], + "rpl-relations-buffer-count-2": [], + "rpl-relations-buffer-count-32": [], + "rpl-relations-buffer-count-4": [], + "rpl-relations-buffer-count-64": [], + "rpl-relations-buffer-count-8": [], + "socket": [], + "socket-dhcpv4": ["socket", "medium-ethernet", "proto-dhcpv4"], + "socket-dns": ["socket", "proto-dns"], + "socket-icmp": ["socket"], + "socket-mdns": ["socket-dns"], + "socket-raw": ["socket"], + "socket-tcp": ["socket"], + "socket-tcp-cubic": [], + "socket-tcp-pause-synack": ["socket-tcp"], + "socket-tcp-reno": [], + "socket-udp": ["socket"], + "verbose": [] + }, + "features2": { + "alloc": ["managed/alloc", "defmt?/alloc"], + "default": [ + "std", + "log", + "medium-ethernet", + "medium-ip", + "medium-ieee802154", + "phy-raw_socket", + "phy-tuntap_interface", + "proto-ipv4", + "proto-dhcpv4", + "proto-ipv6", + "proto-ipv6-slaac", + "proto-dns", + "proto-ipv4-fragmentation", + "proto-sixlowpan-fragmentation", + "socket-raw", + "socket-icmp", + "socket-udp", + "socket-tcp", + "socket-dhcpv4", + "socket-dns", + "socket-mdns", + "packetmeta-id", + "async", + "multicast", + "auto-icmp-echo-reply" + ], + "defmt": ["dep:defmt", "heapless/defmt"], + "phy-raw_socket": ["std", "libc"], + "phy-tuntap_interface": ["std", "libc"], + "std": ["managed/std", "alloc"] + }, + "yanked": false, + "rust_version": "1.91", + "pubtime": "2026-04-30T22:36:03Z", + "v": 2 + } + ] + }, + { + "path": "so/ck/socket2", + "header": "AwIAAABldGFnOiAiMGM1ZWRlYWRhNjJiZTk2N2M4YTNiMjljYWI4NzE4ZjMiAA==", + "records": [ + { + "name": "socket2", + "vers": "0.6.5", + "deps": [ + { + "name": "libc", + "req": "^0.2.172", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(unix, target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.60, <0.62", + "features": [ + "Win32_Foundation", + "Win32_Networking_WinSock", + "Win32_System_IO", + "Win32_System_Threading", + "Win32_System_WindowsProgramming" + ], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4", + "features": { + "all": [] + }, + "yanked": false, + "rust_version": "1.70", + "pubtime": "2026-07-13T19:45:58Z" + } + ] + }, + { + "path": "st/ab/stable_deref_trait", + "header": "AwIAAABldGFnOiAiY2M0NDZlNDRhYzU5OWM5Mjc0NmU5NmY3NWFlMThiODEiAA==", + "records": [ + { + "name": "stable_deref_trait", + "vers": "1.2.1", + "deps": [], + "cksum": "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596", + "features": { + "alloc": [], + "default": ["std"], + "std": ["alloc"] + }, + "yanked": false, + "pubtime": "2025-10-09T05:24:54Z" + } + ] + }, + { + "path": "st/ri/stringprep", + "header": "AwIAAABldGFnOiAiZDU3NWQwYjkwZDc5ZjRjNjhhMzg0Y2ZkMmM3NWY2OTciAA==", + "records": [ + { + "name": "stringprep", + "vers": "0.1.5", + "deps": [ + { + "name": "unicode-bidi", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "unicode-normalization", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "unicode-properties", + "req": "^0.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1", + "features": {}, + "yanked": false, + "pubtime": "2024-05-25T13:22:49Z" + } + ] + }, + { + "path": "st/ri/strip-ansi-escapes", + "header": "AwIAAABldGFnOiAiNjdlYzIzNjQyYzE5OWIxMTVlZTEyYTI5M2NmYThkNDUiAA==", + "records": [ + { + "name": "strip-ansi-escapes", + "vers": "0.2.1", + "deps": [ + { + "name": "doc-comment", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "vte", + "req": "^0.14", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "2a8f8038e7e7969abb3f1b7c2a811225e9296da208539e0f79c5251d6cac0025", + "features": {}, + "yanked": false, + "pubtime": "2025-01-14T15:47:27Z" + } + ] + }, + { + "path": "st/rs/strsim", + "header": "AwIAAABldGFnOiAiYWI2OTk0MDZjMTJkMTI4NjhmYjllY2VlOThkY2I0NmEiAA==", + "records": [ + { + "name": "strsim", + "vers": "0.11.1", + "deps": [], + "cksum": "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-04-02T22:18:09Z" + } + ] + }, + { + "path": "sy/mb/symbolic-common", + "header": "AwIAAABldGFnOiAiNjg0NTg4OGUyYjIxNjNhMTM1OGRkZWFkMTI0NWI1MzIiAA==", + "records": [ + { + "name": "symbolic-common", + "vers": "13.9.0", + "deps": [ + { + "name": "debugid", + "req": "^0.8.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memmap2", + "req": "^0.9.11", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.171", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "similar-asserts", + "req": "^1.4.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "stable_deref_trait", + "req": "^1.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "uuid", + "req": "^1.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "ddfa0014ff4e423a1bb8881453c7a29181eb14fe1dbc8e0197ebfa081903f3ed", + "features": {}, + "features2": { + "serde": ["dep:serde", "debugid/serde"] + }, + "yanked": false, + "rust_version": "1.83", + "pubtime": "2026-07-09T10:23:35Z", + "v": 2 + } + ] + }, + { + "path": "sy/mb/symbolic-demangle", + "header": "AwIAAABldGFnOiAiZjFiNDg0YzEwOWNmNDNiNzczNjQxYWM2NjllNjE2YjEiAA==", + "records": [ + { + "name": "symbolic-demangle", + "vers": "13.9.0", + "deps": [ + { + "name": "bitflags", + "req": "^2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "cc", + "req": "^1.0.79", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "cpp_demangle", + "req": "^0.4.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "itoa", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustc-demangle", + "req": "^0.1.21", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "similar-asserts", + "req": "^1.4.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "symbolic-common", + "req": "^13.9.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "2a213276280a1a737ff5fb89ae2a70ba51d1d4608e74736beb92f257f125f1aa", + "features": { + "cpp": ["cpp_demangle"], + "rust": ["rustc-demangle"], + "swift": ["cc"] + }, + "features2": { + "default": ["cpp", "msvc", "rust", "swift"], + "msvc": ["dep:bitflags", "dep:itoa"] + }, + "yanked": false, + "rust_version": "1.83", + "pubtime": "2026-07-09T10:23:42Z", + "v": 2 + } + ] + }, + { + "path": "sy/ns/synstructure", + "header": "AwIAAABldGFnOiAiZDZlNzMzYjBkMGYwZThmNjE1ZTZkY2EzOTUxYzVkOTgiAA==", + "records": [ + { + "name": "synstructure", + "vers": "0.14.0", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.60", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3", + "features": ["derive", "parsing", "printing", "clone-impls", "visit", "extra-traits"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "synstructure_test_traits", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02", + "features": { + "default": ["proc-macro"], + "proc-macro": ["proc-macro2/proc-macro", "syn/proc-macro", "quote/proc-macro"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-30T19:43:04Z" + } + ] + }, + { + "path": "ta/rg/target-lexicon", + "header": "AwIAAABldGFnOiAiODFlODhjMjkzZjAxZjZhNjhmNmVmOGQzM2FhMGVmMjciAA==", + "records": [ + { + "name": "target-lexicon", + "vers": "0.13.5", + "deps": [ + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca", + "features": { + "arch_z80": [], + "arch_zkasm": [], + "default": [], + "serde_support": ["serde", "std"], + "std": [] + }, + "yanked": false, + "pubtime": "2026-02-15T23:26:15Z" + } + ] + }, + { + "path": "te/mp/tempfile", + "header": "AwIAAABldGFnOiAiNGEwOWI0YmE2MGRhZDUxMjJiNjczZDExNjA0M2M1ODUiAA==", + "records": [ + { + "name": "tempfile", + "vers": "3.27.0", + "deps": [ + { + "name": "doc-comment", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "fastrand", + "req": "^2.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "getrandom", + "req": ">=0.3.0, <0.5", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(any(unix, windows, target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "once_cell", + "req": "^1.19.0", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rustix", + "req": "^1.1.4", + "features": ["fs"], + "optional": false, + "default_features": true, + "target": "cfg(any(unix, target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.52, <0.62", + "features": ["Win32_Storage_FileSystem", "Win32_Foundation"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd", + "features": { + "default": ["getrandom"], + "nightly": [] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2026-03-11T00:20:04Z" + } + ] + }, + { + "path": "te/rm/terminal_size", + "header": "AwIAAABldGFnOiAiNjU0MjA1NjI4ZjM1ZmJmNmU3Mzk2YTRhYWI4ZDM1NzciAA==", + "records": [ + { + "name": "terminal_size", + "vers": "0.4.4", + "deps": [ + { + "name": "rustix", + "req": "^1.0.1", + "features": ["termios"], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.59, <=0.61", + "features": ["Win32_Foundation", "Win32_System_Console"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-03-23T16:39:14Z" + } + ] + }, + { + "path": "te/rm/termios", + "header": "AwIAAABldGFnOiAiZWZlYTQ3MWMzZGViNTk5OWUzNzNlODE1MmY1MzQ4NTYiAA==", + "records": [ + { + "name": "termios", + "vers": "0.3.3", + "deps": [ + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b", + "features": {}, + "yanked": false, + "pubtime": "2020-10-13T02:04:58Z" + } + ] + }, + { + "path": "th/is/thiserror", + "header": "AwIAAABldGFnOiAiNGJmYzc5NjFmNzk1ZmE5OWJiN2QzYTk0OTBmYjJiZDYiAA==", + "records": [ + { + "name": "thiserror", + "vers": "2.0.21", + "deps": [ + { + "name": "anyhow", + "req": "^1.0.73", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ref-cast", + "req": "^1.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0.13", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "thiserror-impl", + "req": "=2.0.21", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "trybuild", + "req": "^1.0.108", + "features": ["diff"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.77", + "pubtime": "2026-09-23T20:24:07Z" + } + ] + }, + { + "path": "th/is/thiserror-impl", + "header": "AwIAAABldGFnOiAiNDgwMzQ2MjI4NzY1MGZkYmQ2MDFlODAyYjM0MGVhZTQiAA==", + "records": [ + { + "name": "thiserror-impl", + "vers": "2.0.21", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.74", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.35", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524", + "features": {}, + "yanked": false, + "rust_version": "1.77", + "pubtime": "2026-09-23T20:24:05Z" + } + ] + }, + { + "path": "ti/me/time", + "header": "AwIAAABldGFnOiAiZDg4MjI2MjU1MmNjZTJjZTY4NjYzMjBlYzQ2YjMyMzciAA==", + "records": [ + { + "name": "time", + "vers": "0.3.55", + "deps": [ + { + "name": "criterion", + "req": "^0.8.1", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(bench)", + "kind": "dev" + }, + { + "name": "deranged", + "req": "^0.5.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "js-sys", + "req": "^0.3.58", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(all(target_family = \"wasm\", not(any(target_os = \"emscripten\", target_os = \"wasi\"))))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.98", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(target_family = \"unix\")", + "kind": "normal" + }, + { + "name": "num-conv", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "num-conv", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "num_threads", + "req": "^0.1.2", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(target_family = \"unix\")", + "kind": "normal" + }, + { + "name": "powerfmt", + "req": "^0.2.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1.0.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck_macros", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand010", + "req": "^0.10.1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "rand" + }, + { + "name": "rand08", + "req": "^0.8.6", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "rand" + }, + { + "name": "rand08", + "req": "^0.8.6", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "rand" + }, + { + "name": "rand09", + "req": "^0.9.4", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "rand" + }, + { + "name": "rand09", + "req": "^0.9.4", + "features": ["small_rng"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "rand" + }, + { + "name": "rstest", + "req": "^0.26.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rstest_reuse", + "req": "^0.7.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.184", + "features": ["derive", "alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.68", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_test2", + "req": "^2.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "time-core", + "req": "=0.1.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "time-macros", + "req": "=0.2.32", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "time-macros", + "req": "=0.2.32", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.102", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(__ui_tests)", + "kind": "dev" + } + ], + "cksum": "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134", + "features": {}, + "features2": { + "alloc": ["serde_core?/alloc"], + "default": ["std"], + "formatting": ["std", "time-macros?/formatting"], + "large-dates": ["time-core/large-dates", "time-macros?/large-dates"], + "local-offset": ["std", "dep:libc", "dep:num_threads"], + "macros": ["dep:time-macros"], + "parsing": ["time-macros?/parsing"], + "quickcheck": ["dep:quickcheck", "alloc", "deranged/quickcheck"], + "rand": ["rand08", "rand09", "rand010"], + "rand010": ["dep:rand010", "deranged/rand010"], + "rand08": ["dep:rand08", "deranged/rand08"], + "rand09": ["dep:rand09", "deranged/rand09"], + "serde": ["dep:serde_core", "time-macros?/serde", "deranged/serde"], + "serde-human-readable": ["serde", "formatting", "parsing"], + "serde-well-known": ["serde", "formatting", "parsing"], + "std": ["alloc"], + "wasm-bindgen": ["dep:js-sys"] + }, + "yanked": false, + "rust_version": "1.88.0", + "pubtime": "2026-08-01T08:08:34Z", + "v": 2 + } + ] + }, + { + "path": "ti/me/time-core", + "header": "AwIAAABldGFnOiAiYzk2NmU1ZGZjNThkOTYwMTU3NjI4OWI1YmIyNDlhMmEiAA==", + "records": [ + { + "name": "time-core", + "vers": "0.1.9", + "deps": [], + "cksum": "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109", + "features": { + "large-dates": [] + }, + "yanked": false, + "rust_version": "1.88.0", + "pubtime": "2026-06-12T08:14:02Z" + } + ] + }, + { + "path": "ti/me/time-macros", + "header": "AwIAAABldGFnOiAiMWQ3YjJhMzQ5NzgyNzIzNGFlMjUyNzEzMTk3ZWE2N2YiAA==", + "records": [ + { + "name": "time-macros", + "vers": "0.2.32", + "deps": [ + { + "name": "num-conv", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "time-core", + "req": "=0.1.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85", + "features": { + "formatting": [], + "large-dates": [], + "parsing": [], + "serde": [] + }, + "yanked": false, + "rust_version": "1.88.0", + "pubtime": "2026-07-20T08:27:37Z" + } + ] + }, + { + "path": "ti/ny/tinystr", + "header": "AwIAAABldGFnOiAiODY2MDY4ZGI5MTg2Nzc5YmQzMWFkZGMxZTE3OWRkN2IiAA==", + "records": [ + { + "name": "tinystr", + "vers": "0.8.4", + "deps": [ + { + "name": "bincode", + "req": "^1.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "databake", + "req": "^0.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "displaydoc", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "postcard", + "req": "^1.0.3", + "features": ["use-std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9", + "features": ["small_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.45", + "features": ["alloc"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "zerovec", + "req": "^0.11.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643", + "features": { + "std": [] + }, + "features2": { + "alloc": ["serde_core?/alloc", "zerovec?/alloc"], + "databake": ["dep:databake"], + "default": ["alloc"], + "serde": ["dep:serde_core"], + "zerovec": ["dep:zerovec"] + }, + "yanked": false, + "rust_version": "1.82", + "pubtime": "2026-08-13T23:28:07Z", + "v": 2 + } + ] + }, + { + "path": "ti/ny/tinyvec", + "header": "AwIAAABldGFnOiAiZDc3MmFjNDU2NjIwOTk4ZjJmM2EyMTU4OTg2YmU0YTYiAA==", + "records": [ + { + "name": "tinyvec", + "vers": "1.13.3", + "deps": [ + { + "name": "arbitrary", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bin-proto", + "req": "^0.12.5", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "borsh", + "req": "^1.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "criterion", + "req": "^0.8.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "debugger_test", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "debugger_test_parser", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "defmt", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "generic-array", + "req": "^1.1.1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "schemars", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_core", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_test", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "smallvec", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee", + "features": { + "alloc": [], + "debugger_visualizer": [], + "default": [], + "experimental_write_impl": [], + "grab_spare_slice": [], + "latest_stable_rust": ["rustc_1_61"], + "nightly_slice_partition_dedup": [], + "real_blackbox": ["criterion/real_blackbox"], + "rustc_1_40": [], + "rustc_1_55": [], + "rustc_1_57": [], + "rustc_1_61": ["rustc_1_57"], + "std": ["alloc"], + "tinyvec_macros": [] + }, + "features2": { + "schemars": ["dep:schemars", "alloc"], + "serde": ["dep:serde_core"] + }, + "yanked": false, + "pubtime": "2026-09-13T23:30:12Z", + "v": 2 + } + ] + }, + { + "path": "to/ki/tokio", + "header": "AwIAAABldGFnOiAiY2JlMGZmYTdjZWNhM2QzNmU1MDVkYWYwMzI3YWUxMWMiAA==", + "records": [ + { + "name": "tokio", + "vers": "1.53.2", + "deps": [ + { + "name": "async-stream", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "backtrace", + "req": "^0.3.58", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(all(tokio_unstable, target_os = \"linux\"))", + "kind": "normal" + }, + { + "name": "backtrace", + "req": "^0.3.58", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(tokio_unstable, target_os = \"linux\"))", + "kind": "dev" + }, + { + "name": "bytes", + "req": "^1.2.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures", + "req": "^0.3.0", + "features": ["async-await"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "futures-concurrency", + "req": "^7.6.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "futures-test", + "req": "^0.3.31", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "io-uring", + "req": "^0.7.11", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(tokio_unstable, target_os = \"linux\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.168", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(all(tokio_unstable, target_os = \"linux\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.168", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(target_os = \"wasi\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.168", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.168", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "dev" + }, + { + "name": "loom", + "req": "^0.7", + "features": ["futures", "checkpoint"], + "optional": false, + "default_features": true, + "target": "cfg(loom)", + "kind": "dev" + }, + { + "name": "mio", + "req": "^1.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "mio", + "req": "^1.2.0", + "features": ["os-poll", "os-ext"], + "optional": true, + "default_features": false, + "target": "cfg(all(tokio_unstable, target_os = \"linux\"))", + "kind": "normal" + }, + { + "name": "mio-aio", + "req": "^2", + "features": ["tokio"], + "optional": false, + "default_features": true, + "target": "cfg(target_os = \"freebsd\")", + "kind": "dev" + }, + { + "name": "mockall", + "req": "^0.13.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "nix", + "req": "^0.31.0", + "features": ["aio", "fs", "socket"], + "optional": false, + "default_features": false, + "target": "cfg(unix)", + "kind": "dev" + }, + { + "name": "parking_lot", + "req": "^0.12.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pin-project-lite", + "req": "^0.2.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proptest", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_family = \"wasm\"))", + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(all(target_family = \"wasm\", target_os = \"unknown\")))", + "kind": "dev" + }, + { + "name": "signal-hook-registry", + "req": "^1.1.1", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "slab", + "req": "^0.4.9", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(all(tokio_unstable, target_os = \"linux\"))", + "kind": "normal" + }, + { + "name": "socket2", + "req": "^0.6.3", + "features": ["all"], + "optional": true, + "default_features": true, + "target": "cfg(any(not(target_family = \"wasm\"), all(target_os = \"wasi\", not(target_env = \"p1\"))))", + "kind": "normal" + }, + { + "name": "socket2", + "req": "^0.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_family = \"wasm\"))", + "kind": "dev" + }, + { + "name": "tempfile", + "req": "^3.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_family = \"wasm\"))", + "kind": "dev" + }, + { + "name": "tokio-macros", + "req": "~2.7.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio-stream", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-test", + "req": "^0.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-util", + "req": "^0.7", + "features": ["rt"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tracing", + "req": "^0.1.29", + "features": ["std"], + "optional": true, + "default_features": false, + "target": "cfg(tokio_unstable)", + "kind": "normal" + }, + { + "name": "tracing-mock", + "req": "=0.1.0-beta.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(tokio_unstable, target_has_atomic = \"64\"))", + "kind": "dev" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_family = \"wasm\", not(target_os = \"wasi\")))", + "kind": "dev" + }, + { + "name": "windows-sys", + "req": "^0.61", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": "^0.61", + "features": ["Win32_Foundation", "Win32_Security_Authorization"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "dev" + } + ], + "cksum": "e95f91fcc7a621e8b030f6aa23c71fe9838ae2fb4d8118b75602a328f5144044", + "features": { + "default": [], + "fs": [], + "full": [ + "fs", + "io-util", + "io-std", + "macros", + "net", + "parking_lot", + "process", + "rt", + "rt-multi-thread", + "signal", + "sync", + "time" + ], + "io-std": [], + "io-util": ["bytes"], + "macros": ["tokio-macros"], + "net": [ + "libc", + "mio/os-poll", + "mio/os-ext", + "mio/net", + "socket2", + "windows-sys/Win32_Foundation", + "windows-sys/Win32_Security", + "windows-sys/Win32_Storage_FileSystem", + "windows-sys/Win32_System_Pipes", + "windows-sys/Win32_System_SystemServices" + ], + "process": [ + "bytes", + "libc", + "mio/os-poll", + "mio/os-ext", + "mio/net", + "signal-hook-registry", + "windows-sys/Win32_Foundation", + "windows-sys/Win32_System_Threading", + "windows-sys/Win32_System_WindowsProgramming" + ], + "rt": [], + "rt-multi-thread": ["rt"], + "schedule-latency": [], + "signal": [ + "libc", + "mio/os-poll", + "mio/net", + "mio/os-ext", + "signal-hook-registry", + "windows-sys/Win32_Foundation", + "windows-sys/Win32_System_Console" + ], + "sync": [], + "test-util": ["rt", "sync", "time"], + "time": [] + }, + "features2": { + "io-uring": ["dep:io-uring", "libc", "mio/os-poll", "mio/os-ext", "dep:slab"], + "taskdump": ["dep:backtrace"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-10-03T11:18:32Z", + "v": 2 + } + ] + }, + { + "path": "to/ki/tokio-macros", + "header": "AwIAAABldGFnOiAiYWM3MzFjYjA0YTcxZTE1YmUwNzkwNjg1MzU4YmIwYWQiAA==", + "records": [ + { + "name": "tokio-macros", + "vers": "2.7.2", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.60", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3.0", + "features": ["full"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.0.0", + "features": ["full", "test-util"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-29T13:15:27Z" + } + ] + }, + { + "path": "to/ki/tokio-postgres", + "header": "AwIAAABldGFnOiAiNGM5ZjdhZTY1Yzg2ZGJlNGJiYzhmYjEzMzI1NTFjZWYiAA==", + "records": [ + { + "name": "tokio-postgres", + "vers": "0.7.18", + "deps": [ + { + "name": "async-trait", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bit-vec-06", + "req": "^0.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "bit-vec" + }, + { + "name": "bit-vec-07", + "req": "^0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "bit-vec" + }, + { + "name": "bit-vec-08", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "bit-vec" + }, + { + "name": "bit-vec-09", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "bit-vec" + }, + { + "name": "byteorder", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytes", + "req": "^1.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "chrono-04", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "chrono" + }, + { + "name": "criterion", + "req": "^0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "env_logger", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "eui48-1", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "eui48" + }, + { + "name": "fallible-iterator", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures-channel", + "req": "^0.3", + "features": ["sink"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures-executor", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "futures-util", + "req": "^0.3", + "features": ["sink"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-util", + "req": "^0.3", + "features": ["async-await-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "geo-types-06", + "req": "^0.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "geo-types" + }, + { + "name": "geo-types-07", + "req": "^0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "geo-types" + }, + { + "name": "jiff-01", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "jiff" + }, + { + "name": "jiff-02", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "jiff" + }, + { + "name": "log", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "parking_lot", + "req": "^0.12", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "percent-encoding", + "req": "^2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "phf", + "req": "^0.13", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pin-project-lite", + "req": "^0.2.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "postgres-protocol", + "req": "^0.6.12", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "postgres-types", + "req": "^0.2.14", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.10.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json-1", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "serde_json" + }, + { + "name": "smol_str-01", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "smol_str" + }, + { + "name": "socket2", + "req": "^0.6", + "features": ["all"], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "time-02", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "time" + }, + { + "name": "time-03", + "req": "^0.3", + "features": ["parsing"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "time" + }, + { + "name": "tokio", + "req": "^1.27", + "features": ["io-util"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.0", + "features": ["macros", "net", "rt", "rt-multi-thread", "time"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-util", + "req": "^0.7", + "features": ["codec"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "uuid-08", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "uuid" + }, + { + "name": "uuid-1", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "uuid" + }, + { + "name": "whoami", + "req": "^2.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "a528f7d280f6d5b9cd149635c8705b0dd049754bc67d81d31fa25169a93809d3", + "features": { + "array-impls": ["postgres-types/array-impls"], + "default": ["runtime"], + "js": ["postgres-protocol/js", "postgres-types/js"], + "runtime": ["tokio/net", "tokio/time"], + "with-bit-vec-0_6": ["postgres-types/with-bit-vec-0_6"], + "with-bit-vec-0_7": ["postgres-types/with-bit-vec-0_7"], + "with-bit-vec-0_8": ["postgres-types/with-bit-vec-0_8"], + "with-bit-vec-0_9": ["postgres-types/with-bit-vec-0_9"], + "with-chrono-0_4": ["postgres-types/with-chrono-0_4"], + "with-cidr-0_2": ["postgres-types/with-cidr-0_2"], + "with-cidr-0_3": ["postgres-types/with-cidr-0_3"], + "with-eui48-0_4": ["postgres-types/with-eui48-0_4"], + "with-eui48-1": ["postgres-types/with-eui48-1"], + "with-geo-types-0_6": ["postgres-types/with-geo-types-0_6"], + "with-geo-types-0_7": ["postgres-types/with-geo-types-0_7"], + "with-jiff-0_1": ["postgres-types/with-jiff-0_1"], + "with-jiff-0_2": ["postgres-types/with-jiff-0_2"], + "with-serde_json-1": ["postgres-types/with-serde_json-1"], + "with-smol_str-01": ["postgres-types/with-smol_str-01"], + "with-time-0_2": ["postgres-types/with-time-0_2"], + "with-time-0_3": ["postgres-types/with-time-0_3"], + "with-uuid-0_8": ["postgres-types/with-uuid-0_8"], + "with-uuid-1": ["postgres-types/with-uuid-1"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-06-12T15:39:21Z" + } + ] + }, + { + "path": "to/ki/tokio-stream", + "header": "AwIAAABldGFnOiAiYWYwYWE2ZTY1ZTUxZTRkOWY0MTUzYWE3ZmQ3YzkzZGEiAA==", + "records": [ + { + "name": "tokio-stream", + "vers": "0.1.19", + "deps": [ + { + "name": "async-stream", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "futures", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "futures-core", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "parking_lot", + "req": "^0.12.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "pin-project-lite", + "req": "^0.2.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.38.0", + "features": ["sync"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.38.0", + "features": ["full", "test-util"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-test", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-util", + "req": "^0.7.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "a3d06f0b082ba57c26b79407372e57cf2a1e28124f78e9479fe80322cf53420b", + "features": { + "default": ["time"], + "fs": ["tokio/fs"], + "full": ["time", "net", "io-util", "fs", "rt", "sync", "signal"], + "io-util": ["tokio/io-util"], + "net": ["tokio/net"], + "rt": ["tokio/rt"], + "signal": ["tokio/signal"], + "sync": ["tokio/sync", "tokio-util"], + "time": ["tokio/time"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-22T08:19:01Z" + } + ] + }, + { + "path": "to/ki/tokio-util", + "header": "AwIAAABldGFnOiAiMmIwYjljOTc4MmYyYzE3NTE3MDU5NGZiOGZhZDA0ZmMiAA==", + "records": [ + { + "name": "tokio-util", + "vers": "0.7.20", + "deps": [ + { + "name": "async-stream", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "bytes", + "req": "^1.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "futures-core", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures-io", + "req": "^0.3.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures-sink", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures-test", + "req": "^0.3.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "futures-util", + "req": "^0.3.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hashbrown", + "req": "^0.15.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.168", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "loom", + "req": "^0.7", + "features": ["futures", "checkpoint"], + "optional": false, + "default_features": true, + "target": "cfg(loom)", + "kind": "dev" + }, + { + "name": "parking_lot", + "req": "^0.12.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "pin-project-lite", + "req": "^0.2.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "slab", + "req": "^0.4.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio", + "req": "^1.51.0", + "features": ["sync"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.0.0", + "features": ["full"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-stream", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-test", + "req": "^0.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tracing", + "req": "^0.1.29", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "e464cf451ba96ebfc6f9b6542f17ee8b8956e33f1e40d9690624e59d7a7f8a4b", + "features": { + "__docs_rs": ["futures-util"], + "codec": ["libc"], + "compat": ["futures-io"], + "default": [], + "full": ["codec", "compat", "io-util", "time", "net", "rt", "join-map"], + "io": [], + "io-util": ["io", "tokio/rt", "tokio/io-util"], + "join-map": ["rt", "hashbrown"], + "net": ["tokio/net"], + "rt": ["tokio/rt", "tokio/sync", "futures-util"], + "time": ["tokio/time", "slab"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-10-09T11:02:11Z" + } + ] + }, + { + "path": "to/ml/toml", + "header": "AwIAAABldGFnOiAiNTBhM2E4MTE5NGM5MDU0NmMwOTg1Y2M0YTgxNmEyYjkiAA==", + "records": [ + { + "name": "toml", + "vers": "1.1.8+spec-1.1.0", + "deps": [ + { + "name": "anstream", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anstyle", + "req": "^1.0.14", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "foldhash", + "req": "^0.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2.13.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "itertools", + "req": "^0.15.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.228", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde-untagged", + "req": "^0.1.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.228", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.149", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_spanned", + "req": "^1.1.2", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "snapbox", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml-test-data", + "req": "^2.14.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml-test-harness", + "req": "^1.14.1", + "features": ["snapshot"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml_datetime", + "req": "^1.1.2", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "toml_parser", + "req": "^1.1.5", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "toml_writer", + "req": "^1.1.3", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "walkdir", + "req": "^2.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "winnow", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "20489e00e4d8741d6be680764cc12e270655e375a20d1011e844a9c3379e678d", + "features": { + "unbounded": [] + }, + "features2": { + "debug": ["std", "toml_parser?/debug", "dep:anstream", "dep:anstyle"], + "default": ["std", "serde", "parse", "display"], + "display": ["dep:toml_writer"], + "fast_hash": ["preserve_order", "dep:foldhash"], + "parse": ["dep:toml_parser", "dep:winnow"], + "preserve_order": ["dep:indexmap", "std"], + "serde": ["dep:serde_core", "toml_datetime/serde", "serde_spanned/serde"], + "std": [ + "indexmap?/std", + "serde_core?/std", + "toml_parser?/std", + "toml_writer?/std", + "toml_datetime/std", + "serde_spanned/std" + ] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-10-09T02:46:31Z", + "v": 2 + } + ] + }, + { + "path": "to/ml/toml_datetime", + "header": "AwIAAABldGFnOiAiMjg4ZGUzNzkwNjcwMWU0YTA1ZjAxMTM2ZGQxOWFlZjYiAA==", + "records": [ + { + "name": "toml_datetime", + "vers": "1.1.2+spec-1.1.0", + "deps": [ + { + "name": "serde_core", + "req": "^1.0.228", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "snapbox", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "2b86d767906c6c42421dcba507eb9d203e779497710a47782a224bb871653053", + "features": {}, + "features2": { + "alloc": ["serde_core?/alloc"], + "default": ["std"], + "serde": ["dep:serde_core"], + "std": ["alloc", "serde_core?/std"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-10-08T00:54:03Z", + "v": 2 + } + ] + }, + { + "path": "to/ml/toml_edit", + "header": "AwIAAABldGFnOiAiMWMyODRhM2I4OGY4YzIzMTlhM2VjMjY2MzYzNjZhMDYiAA==", + "records": [ + { + "name": "toml_edit", + "vers": "0.25.17+spec-1.1.0", + "deps": [ + { + "name": "anstream", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anstyle", + "req": "^1.0.14", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2.13.0", + "features": ["std"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proptest", + "req": "^1.10.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.228", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde-untagged", + "req": "^0.1.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.228", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.149", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_spanned", + "req": "^1.1.2", + "features": ["serde"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "snapbox", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml-test-data", + "req": "^2.14.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml-test-harness", + "req": "^1.14.1", + "features": ["snapshot"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml_datetime", + "req": "^1.1.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "toml_parser", + "req": "^1.1.5", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "toml_writer", + "req": "^1.1.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "walkdir", + "req": "^2.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "winnow", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "e3641d5bbb5349a79e1020a242d251efbc546ad8048d133958323ce9c40a9c9c", + "features": { + "unbounded": [] + }, + "features2": { + "debug": ["toml_parser?/debug", "dep:anstream", "dep:anstyle", "display"], + "default": ["parse", "display"], + "display": ["dep:toml_writer"], + "parse": ["dep:toml_parser", "dep:winnow"], + "serde": ["dep:serde_core", "toml_datetime/serde", "dep:serde_spanned"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-10-09T02:46:32Z", + "v": 2 + } + ] + }, + { + "path": "to/ml/toml_parser", + "header": "AwIAAABldGFnOiAiOWViOWE2MWYxN2Q2YzZkMTk1NTlmNzkxZDE0YmM0NGMiAA==", + "records": [ + { + "name": "toml_parser", + "vers": "1.1.5+spec-1.1.0", + "deps": [ + { + "name": "anstream", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anstream", + "req": "^1.0.0", + "features": ["test"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "anstyle", + "req": "^1.0.14", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "snapbox", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "winnow", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "baa693a8032d7e1cada7d0041e96126df243179ff061456783ac7f12bda4744c", + "features": { + "alloc": [], + "default": ["std"], + "simd": ["winnow/simd"], + "std": ["alloc"], + "unsafe": [] + }, + "features2": { + "debug": ["std", "dep:anstream", "dep:anstyle"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-10-09T02:46:29Z", + "v": 2 + } + ] + }, + { + "path": "to/ml/toml_writer", + "header": "AwIAAABldGFnOiAiNDk0MmU4YTk4YjUxNWY2N2ZlZWFkN2NhMzc2ZjgwZjciAA==", + "records": [ + { + "name": "toml_writer", + "vers": "1.1.3+spec-1.1.0", + "deps": [ + { + "name": "proptest", + "req": "^1.10.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "snapbox", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml_old", + "req": "^0.5.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "toml" + } + ], + "cksum": "06bdbd8cfc056b8d2e2e85f29b56a3bdbecb527cef81eb39e3e7b98af4652770", + "features": { + "alloc": [], + "default": ["std"], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-10-08T00:54:04Z" + } + ] + }, + { + "path": "tr/ac/tracing", + "header": "AwIAAABldGFnOiAiNjM0NWRiYTkxYjg3YTI3OGYwODNjMDFlODg5OGVmMjIiAA==", + "records": [ + { + "name": "tracing", + "vers": "0.1.44", + "deps": [ + { + "name": "criterion", + "req": "^0.3.6", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "futures", + "req": "^0.3.21", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "log", + "req": "^0.4.17", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "log", + "req": "^0.4.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "pin-project-lite", + "req": "^0.2.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tracing-attributes", + "req": "^0.1.31", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tracing-core", + "req": "^0.1.36", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3.38", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + } + ], + "cksum": "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100", + "features": { + "async-await": [], + "attributes": ["tracing-attributes"], + "default": ["std", "attributes"], + "log-always": ["log"], + "max_level_debug": [], + "max_level_error": [], + "max_level_info": [], + "max_level_off": [], + "max_level_trace": [], + "max_level_warn": [], + "release_max_level_debug": [], + "release_max_level_error": [], + "release_max_level_info": [], + "release_max_level_off": [], + "release_max_level_trace": [], + "release_max_level_warn": [], + "std": ["tracing-core/std"], + "valuable": ["tracing-core/valuable"] + }, + "yanked": false, + "rust_version": "1.65.0", + "pubtime": "2025-12-18T14:26:12Z" + } + ] + }, + { + "path": "tr/ac/tracing-attributes", + "header": "AwIAAABldGFnOiAiOWZjZTRiYWYyZDBiODFhMDkyMzA4NjY0OGE2OTgxNmUiAA==", + "records": [ + { + "name": "tracing-attributes", + "vers": "0.1.31", + "deps": [ + { + "name": "async-trait", + "req": "^0.1.67", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1.0.60", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.20", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustversion", + "req": "^1.0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn", + "req": "^2.0", + "features": [ + "full", + "parsing", + "printing", + "visit-mut", + "clone-impls", + "extra-traits", + "proc-macro" + ], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tokio-test", + "req": "^0.4.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tracing", + "req": "^0.1.35", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tracing-subscriber", + "req": "^0.3.0", + "features": ["env-filter"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.64", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da", + "features": { + "async-await": [] + }, + "yanked": false, + "rust_version": "1.65.0", + "pubtime": "2025-11-26T11:23:01Z" + } + ] + }, + { + "path": "tr/ac/tracing-core", + "header": "AwIAAABldGFnOiAiOTkyMTU2YTdlYjFkMTI4YzBiMTE2OGQxNWI3ODhkOTEiAA==", + "records": [ + { + "name": "tracing-core", + "vers": "0.1.36", + "deps": [ + { + "name": "once_cell", + "req": "^1.13.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "valuable", + "req": "^0.1.0", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(tracing_unstable)", + "kind": "normal" + } + ], + "cksum": "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a", + "features": { + "std": ["once_cell"] + }, + "features2": { + "default": ["std", "valuable?/std"] + }, + "yanked": false, + "rust_version": "1.65.0", + "pubtime": "2025-12-18T14:13:04Z", + "v": 2 + } + ] + }, + { + "path": "tw/ox/twox-hash", + "header": "AwIAAABldGFnOiAiZDQ2NjRkYjk0N2NjMDMyMjJiNzc4ODBlNGEwMWUzMTQiAA==", + "records": [ + { + "name": "twox-hash", + "vers": "2.1.5", + "deps": [ + { + "name": "rand", + "req": ">=0.9.0, <=0.11.0", + "features": ["thread_rng"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.0", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.117", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "86a801b3cea342a06d468c8710662aa29e5e05e4f5c0d62f00bbb7f2ad7941c2", + "features": { + "alloc": [], + "std": ["alloc"], + "xxhash32": [], + "xxhash3_128": [], + "xxhash3_64": [], + "xxhash64": [] + }, + "features2": { + "default": ["random", "xxhash32", "xxhash64", "xxhash3_64", "xxhash3_128", "std"], + "random": ["dep:rand"], + "serialize": ["dep:serde"] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-10-04T14:59:48Z", + "v": 2 + } + ] + }, + { + "path": "ty/pe/typenum", + "header": "AwIAAABldGFnOiAiZmZmMGQ5NjAyZjc2NDVmZmZmMzBhYTMzYzRmYzhmYTIiAA==", + "records": [ + { + "name": "typenum", + "vers": "1.20.1", + "deps": [ + { + "name": "scale-info", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20", + "features": { + "const-generics": [], + "i128": [], + "scale_info": ["scale-info/derive"], + "strict": [] + }, + "yanked": false, + "rust_version": "1.41.0", + "pubtime": "2026-05-29T16:00:41Z" + } + ] + }, + { + "path": "un/ic/unicase", + "header": "AwIAAABldGFnOiAiYmYwMzc1ZDlhM2U4YjcxMGE3NGJhMDc2NTVjMDY4MDQiAA==", + "records": [ + { + "name": "unicase", + "vers": "2.10.0", + "deps": [], + "cksum": "357cc3acc6a036009fd6c973ed009037c732d60d0b4f6c673e9041497482a28f", + "features": { + "nightly": [] + }, + "yanked": false, + "pubtime": "2026-10-05T13:11:23Z" + } + ] + }, + { + "path": "un/ic/unicode-bidi", + "header": "AwIAAABldGFnOiAiZmQ3MzZlZDQ5YmU3MGVmZGJkNjk2Y2MxYzk5NDdmYTUiAA==", + "records": [ + { + "name": "unicode-bidi", + "vers": "0.3.18", + "deps": [ + { + "name": "flame", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "flamer", + "req": "^0.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": ">=0.8, <2.0", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_test", + "req": ">=0.8, <2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "smallvec", + "req": ">=1.13", + "features": ["union"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5", + "features": { + "bench_it": [], + "default": ["std", "hardcoded-data"], + "flame_it": ["flame", "flamer"], + "hardcoded-data": [], + "std": [], + "unstable": [], + "with_serde": ["serde"] + }, + "yanked": false, + "rust_version": "1.47.0", + "pubtime": "2024-12-16T23:09:47Z" + } + ] + }, + { + "path": "un/ic/unicode-ident", + "header": "AwIAAABldGFnOiAiYjcxNThlNzgzOGU5ZmYwZmYyNWQ5NmM3N2VmODlmNzkiAA==", + "records": [ + { + "name": "unicode-ident", + "vers": "1.0.26", + "deps": [ + { + "name": "criterion", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "fst", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "roaring", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ucd-trie", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "unicode-xid", + "req": "^0.2.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-09-17T06:18:03Z" + } + ] + }, + { + "path": "un/ic/unicode-normalization", + "header": "AwIAAABldGFnOiAiNzdmYWU1MWExZGM4ZTZmMDc4ZjcyNzM4ZjRiYTY1YTkiAA==", + "records": [ + { + "name": "unicode-normalization", + "vers": "0.1.25", + "deps": [ + { + "name": "tinyvec", + "req": "^1", + "features": ["alloc"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.36", + "pubtime": "2025-10-30T16:06:38Z" + } + ] + }, + { + "path": "un/ic/unicode-properties", + "header": "AwIAAABldGFnOiAiYTQ5NDc5NTc4YmE0OGNhOTJhMTNhN2UzZTcwNjU4NzQiAA==", + "records": [ + { + "name": "unicode-properties", + "vers": "0.1.4", + "deps": [], + "cksum": "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d", + "features": { + "default": ["general-category", "emoji"], + "emoji": [], + "general-category": [] + }, + "yanked": false, + "pubtime": "2025-10-30T16:34:55Z" + } + ] + }, + { + "path": "un/ic/unicode-segmentation", + "header": "AwIAAABldGFnOiAiNGVjMTU1OTUxZWE0YzU0MzFiZmEyMDY1NWI1MjM2ZmEiAA==", + "records": [ + { + "name": "unicode-segmentation", + "vers": "1.13.3", + "deps": [ + { + "name": "criterion", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proptest", + "req": "^1.7.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quickcheck", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8", + "features": { + "no_std": [] + }, + "yanked": false, + "rust_version": "1.85.0", + "pubtime": "2026-06-01T15:58:43Z" + } + ] + }, + { + "path": "un/ic/unicode-xid", + "header": "AwIAAABldGFnOiAiNmNiN2JjNDA5Mjg0NThiZDI1NjZlOGU4MmQ0ZGIyZTgiAA==", + "records": [ + { + "name": "unicode-xid", + "vers": "0.2.6", + "deps": [ + { + "name": "criterion", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853", + "features": { + "bench": [], + "default": [], + "no_std": [] + }, + "yanked": false, + "rust_version": "1.17", + "pubtime": "2024-09-19T15:55:24Z" + } + ] + }, + { + "path": "un/sa/unsafe-libyaml", + "header": "AwIAAABldGFnOiAiMmQ4N2FkMDM2YmJmZDM3MTg3YTFmNDg4YjI2MmFlMTMiAA==", + "records": [ + { + "name": "unsafe-libyaml", + "vers": "0.2.11", + "deps": [ + { + "name": "pretty_assertions", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-03-17T05:44:18Z" + } + ] + }, + { + "path": "un/ty/unty", + "header": "AwIAAABldGFnOiAiZDdhYjY2NDNiMDdiODVhYTJhMmZjNTUzN2Y1ZDAzYWUiAA==", + "records": [ + { + "name": "unty", + "vers": "0.0.4", + "deps": [], + "cksum": "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae", + "features": {}, + "yanked": false, + "rust_version": "1.56.1", + "pubtime": "2025-03-07T08:06:25Z" + } + ] + }, + { + "path": "ur/le/urlencoding", + "header": "AwIAAABldGFnOiAiMGY2MWJjNWQwYTNlNmY4ZDU3Mjg2MTY1MTQ0Zjc2Y2YiAA==", + "records": [ + { + "name": "urlencoding", + "vers": "2.1.3", + "deps": [], + "cksum": "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da", + "features": {}, + "yanked": false, + "pubtime": "2023-07-21T15:12:17Z" + } + ] + }, + { + "path": "ut/f8/utf8_iter", + "header": "AwIAAABldGFnOiAiMWYwNTI1MDY2ZDMzMTllNmFkYzJiOTNhMmJlM2I5NmUiAA==", + "records": [ + { + "name": "utf8_iter", + "vers": "1.0.4", + "deps": [], + "cksum": "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be", + "features": {}, + "yanked": false, + "pubtime": "2023-12-01T17:26:51Z" + } + ] + }, + { + "path": "ut/f8/utf8parse", + "header": "AwIAAABldGFnOiAiMDliNjQ4ZmVjNWY2NjdhOWU3YzYyMjNlMjI0MTM5NzMiAA==", + "records": [ + { + "name": "utf8parse", + "vers": "0.2.2", + "deps": [], + "cksum": "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821", + "features": { + "default": [], + "nightly": [] + }, + "yanked": false, + "pubtime": "2024-06-08T07:07:41Z" + } + ] + }, + { + "path": "uu/id/uuid", + "header": "AwIAAABldGFnOiAiMDc2MDQ3MDAxOWViOTc0MjFhMTMyNmEwOGMwMGI1NmQiAA==", + "records": [ + { + "name": "uuid", + "vers": "1.28.0", + "deps": [ + { + "name": "arbitrary", + "req": "^1.1.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "atomic", + "req": "^0.6", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "borsh", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "borsh-derive", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "bytemuck", + "req": "^1.22", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "getrandom", + "req": "^0.4", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\"))))", + "kind": "normal" + }, + { + "name": "gungraun", + "req": "=0.19.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "js-sys", + "req": "^0.3", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\"), target_feature = \"atomics\"))", + "kind": "normal" + }, + { + "name": "md-5", + "req": "^0.10", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.10", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\"))))", + "kind": "normal" + }, + { + "name": "rustversion", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.221", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.221", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1.0.221", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_test", + "req": "^1.0.56", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "sha1_smol", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "slog", + "req": "^2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "trybuild", + "req": "^1.0.52", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "uuid-rng-internal-lib", + "req": "^1.28.0", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\")))", + "kind": "normal", + "package": "uuid-rng-internal" + }, + { + "name": "wasm-bindgen", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\")))", + "kind": "normal" + }, + { + "name": "wasm-bindgen", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\")))", + "kind": "dev" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\")))", + "kind": "dev" + }, + { + "name": "zerocopy", + "req": "^0.8", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "7cc1186384beb7dd8eedea376413fd654937285ea6c9cfbb928dc3043ea4b606", + "features": { + "macro-diagnostics": [], + "v8": [] + }, + "features2": { + "atomic": ["dep:atomic"], + "borsh": ["dep:borsh", "dep:borsh-derive"], + "default": ["std"], + "fast-rng": ["rng", "dep:rand"], + "js": ["dep:wasm-bindgen", "dep:js-sys"], + "md5": ["dep:md-5"], + "rng": ["dep:getrandom"], + "rng-getrandom": [ + "rng", + "dep:getrandom", + "uuid-rng-internal-lib", + "uuid-rng-internal-lib/getrandom" + ], + "rng-rand": ["rng", "dep:rand", "uuid-rng-internal-lib", "uuid-rng-internal-lib/rand"], + "serde": ["dep:serde_core"], + "sha1": ["dep:sha1_smol"], + "std": ["wasm-bindgen?/std", "js-sys?/std"], + "v1": ["atomic"], + "v3": ["md5"], + "v4": ["rng"], + "v5": ["sha1"], + "v6": ["atomic"], + "v7": ["rng"] + }, + "yanked": false, + "rust_version": "1.89.0", + "pubtime": "2026-10-10T00:02:40Z", + "v": 2 + } + ] + }, + { + "path": "ve/rs/version_check", + "header": "AwIAAABldGFnOiAiMTdiMWIzYzA4ZjNkMjY4OTdmYTgyODg4YzU0MDljZmEiAA==", + "records": [ + { + "name": "version_check", + "vers": "0.9.5", + "deps": [], + "cksum": "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a", + "features": {}, + "yanked": false, + "pubtime": "2024-07-25T23:38:14Z" + } + ] + }, + { + "path": "vi/rt/virtual-fs", + "header": "AwIAAABldGFnOiAiNDNhMGU2MjZlYzA5NjM0NWUxMTkzMDY2ZjRjNDhjZGIiAA==", + "records": [ + { + "name": "virtual-fs", + "vers": "0.702.1", + "deps": [ + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "async-trait", + "req": "^0.1.68", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytes", + "req": "^1.11.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "dashmap", + "req": "^6.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "derive_more", + "req": "^2.0.1", + "features": ["debug", "display"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "dunce", + "req": "^1.0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "filetime", + "req": "^0.2.18", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "fs_extra", + "req": "^1.3.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures", + "req": "^0.3.30", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "getrandom", + "req": "^0.4.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.178", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "pin-project-lite", + "req": "^0.2.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pretty_assertions", + "req": "^1.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "replace_with", + "req": "^0.1.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "shared-buffer", + "req": "^0.1.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "slab", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "thiserror", + "req": "^2.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.39.0", + "features": ["io-util", "sync", "macros"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.39.0", + "features": ["io-util", "rt"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "tracing", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tracing-test", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "virtual-mio", + "req": "^0.702.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-package", + "req": "^0.702.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "web-time", + "req": "^1.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "webc", + "req": "=12.0.0", + "features": ["v1"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "18f2136946b8a66d2bc7548fc4396c72e7a8671e8ab878342f5483e6c6dfd61f", + "features": { + "default": ["host-fs", "webc-fs", "static-fs"], + "enable-serde": [], + "futures": [], + "host-fs": ["libc", "fs_extra", "filetime", "tokio/fs", "tokio/io-std", "tokio/rt"], + "static-fs": ["webc", "anyhow"], + "tracking": [], + "webc-fs": ["webc", "anyhow"] + }, + "features2": { + "js": ["dep:web-time", "getrandom/wasm_js"] + }, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:05:55Z", + "v": 2 + } + ] + }, + { + "path": "vi/rt/virtual-mio", + "header": "AwIAAABldGFnOiAiOTIyMzIxNjlhYjE1YTUzYWE0ZjcxODE5NWI3ZDJjNGYiAA==", + "records": [ + { + "name": "virtual-mio", + "vers": "0.702.1", + "deps": [ + { + "name": "async-trait", + "req": "^0.1.68", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytes", + "req": "^1.11.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures", + "req": "^0.3.30", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "mio", + "req": "^1", + "features": ["os-poll"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "mio", + "req": "^1", + "features": ["os-poll", "os-ext"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "parking", + "req": "^2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "socket2", + "req": "^0.6.1", + "features": ["all"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "thiserror", + "req": "^2.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tracing", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "b449ceba2087fe0a7e436b9f1105dd9868addb294ff96a4a28100eadb9442b15", + "features": { + "js": [], + "sys": ["mio", "socket2"] + }, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:04:33Z" + } + ] + }, + { + "path": "vi/rt/virtual-net", + "header": "AwIAAABldGFnOiAiYTVlNDJkYzRiYzY5ZjJmMWU2NTEyNmJhY2YzOGZmMzgiAA==", + "records": [ + { + "name": "virtual-net", + "vers": "0.702.1", + "deps": [ + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "async-trait", + "req": "^0.1.68", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "base64", + "req": "^0.22.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bincode", + "req": "=2.0.1", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytecheck", + "req": "^0.8.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytes", + "req": "^1.11.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "derive_more", + "req": "^2.0.1", + "features": ["debug", "display"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures-util", + "req": "^0.3.31", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hyper", + "req": "^1.8.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hyper-tungstenite", + "req": "^0.19", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hyper-util", + "req": "^0.1.5", + "features": ["tokio"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ipnet", + "req": "^2.10.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "iprange", + "req": "^0.6.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.178", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "mio", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pin-project-lite", + "req": "^0.2.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rkyv", + "req": "^0.8.13", + "features": ["indexmap-2", "bytes-1"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serial_test", + "req": "^3.2.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "smoltcp", + "req": "^0.13.0", + "features": ["proto-ipv4", "std", "alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "socket2", + "req": "^0.6.1", + "features": ["all"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "thiserror", + "req": "^2.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.39.0", + "features": ["io-util"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.39.0", + "features": ["macros", "rt-multi-thread"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-serde", + "req": "^0.9", + "features": ["bincode"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio-tungstenite", + "req": "^0.28.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio-util", + "req": "^0.7.8", + "features": ["codec"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tracing", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tracing-test", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "virtual-mio", + "req": "^0.702.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "fb377443085e3e30d0e3357a8d55925da670d070a04c9dd2284236a20cf308f1", + "features": { + "cbor": ["tokio-serde/cbor"], + "host-net": [ + "libc", + "tokio/io-util", + "virtual-mio/sys", + "tokio/net", + "tokio/rt", + "socket2", + "mio" + ], + "json": ["tokio-serde/json"], + "messagepack": ["tokio-serde/messagepack"], + "remote": ["libc", "tokio/io-util", "tokio/sync", "tokio-serde", "tokio-util"], + "tokio": [] + }, + "features2": { + "default": [ + "host-net", + "remote", + "json", + "messagepack", + "cbor", + "hyper", + "tokio-tungstenite" + ], + "hyper": ["hyper-tungstenite", "hyper-util", "dep:hyper"], + "rkyv": ["dep:rkyv", "dep:bytecheck"], + "tokio-tungstenite": ["dep:tokio-tungstenite"] + }, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:05:19Z", + "v": 2 + } + ] + }, + { + "path": "vi/rt/virtue", + "header": "AwIAAABldGFnOiAiNDU2NjYzNjA5NWM1YmJlZGY1ZmQ3NDMxODkyNGYwYTgiAA==", + "records": [ + { + "name": "virtue", + "vers": "0.0.18", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1", + "features": {}, + "yanked": false, + "pubtime": "2024-11-08T14:20:44Z" + } + ] + }, + { + "path": "wa/i-/wai-bindgen-gen-core", + "header": "AwIAAABldGFnOiAiODI1MmIyOGQ4OTcwMDBiNTdmZDJmMzUzMmU1ZWJhMTYiAA==", + "records": [ + { + "name": "wai-bindgen-gen-core", + "vers": "0.2.3", + "deps": [ + { + "name": "anyhow", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wai-parser", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "1aa3dc41b510811122b3088197234c27e08fcad63ef936306dd8e11e2803876c", + "features": {}, + "yanked": false, + "rust_version": "1.64", + "pubtime": "2023-02-15T17:07:08Z" + } + ] + }, + { + "path": "wa/i-/wai-bindgen-gen-rust", + "header": "AwIAAABldGFnOiAiODZhNDI0ZTNiZjMwMGJhNGMyNGI5ODM2NjEyYTA1OWMiAA==", + "records": [ + { + "name": "wai-bindgen-gen-rust", + "vers": "0.2.3", + "deps": [ + { + "name": "heck", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wai-bindgen-gen-core", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "19bc05e8380515c4337c40ef03b2ff233e391315b178a320de8640703d522efe", + "features": {}, + "yanked": false, + "rust_version": "1.64", + "pubtime": "2023-02-15T17:11:26Z" + } + ] + }, + { + "path": "wa/i-/wai-bindgen-gen-rust-wasm", + "header": "AwIAAABldGFnOiAiMmQ2NWYzZGFmOTRhYjI0ZmMzM2NmOTA4NDc2MDAxNmUiAA==", + "records": [ + { + "name": "wai-bindgen-gen-rust-wasm", + "vers": "0.2.3", + "deps": [ + { + "name": "heck", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "structopt", + "req": "^0.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wai-bindgen-gen-core", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wai-bindgen-gen-rust", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "d6f35ce5e74086fac87f3a7bd50f643f00fe3559adb75c88521ecaa01c8a6199", + "features": {}, + "yanked": false, + "rust_version": "1.64", + "pubtime": "2023-02-15T17:13:15Z" + } + ] + }, + { + "path": "wa/i-/wai-bindgen-rust", + "header": "AwIAAABldGFnOiAiZDJkNjYwYjBjMjRjYThjY2JjNTJmMzhhOGIzMzM4NTAiAA==", + "records": [ + { + "name": "wai-bindgen-rust", + "vers": "0.2.3", + "deps": [ + { + "name": "async-trait", + "req": "^0.1.51", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bitflags", + "req": "^1.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wai-bindgen-rust-impl", + "req": "^0.2.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "4e5601c6f448c063e83a5e931b8fefcdf7e01ada424ad42372c948d2e3d67741", + "features": { + "async": ["async-trait"], + "default": ["macros", "async"], + "macros": ["wai-bindgen-rust-impl"] + }, + "yanked": false, + "rust_version": "1.64", + "pubtime": "2023-02-15T17:18:28Z" + } + ] + }, + { + "path": "wa/i-/wai-bindgen-rust-impl", + "header": "AwIAAABldGFnOiAiOTEyM2ViNDVkMTExODk3YTg2MjRkNzdiMzVhNDU3YTIiAA==", + "records": [ + { + "name": "wai-bindgen-rust-impl", + "vers": "0.2.3", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wai-bindgen-gen-core", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wai-bindgen-gen-rust-wasm", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "bdeeb5c1170246de8425a3e123e7ef260dc05ba2b522a1d369fe2315376efea4", + "features": {}, + "yanked": false, + "rust_version": "1.64", + "pubtime": "2023-02-15T17:18:03Z" + } + ] + }, + { + "path": "wa/i-/wai-parser", + "header": "AwIAAABldGFnOiAiOWEwN2YyMWEyYTcxZWI5MTRlMWYzMGE5NmZmOGUzZTMiAA==", + "records": [ + { + "name": "wai-parser", + "vers": "0.2.3", + "deps": [ + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "id-arena", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pulldown-cmark", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicode-normalization", + "req": "^0.1.19", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "unicode-xid", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wast", + "req": "^33", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "9bd0acb6d70885ea0c343749019ba74f015f64a9d30542e66db69b49b7e28186", + "features": {}, + "yanked": false, + "rust_version": "1.64", + "pubtime": "2023-02-15T17:01:46Z" + } + ] + }, + { + "path": "wa/ke/waker-fn", + "header": "AwIAAABldGFnOiAiYjIzYzJkNTE1MWNlMTgwYzUwODM0ZDE2MDVhOTMwYWYiAA==", + "records": [ + { + "name": "waker-fn", + "vers": "1.2.0", + "deps": [ + { + "name": "portable-atomic-util", + "req": "^0.2", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7", + "features": { + "portable-atomic": ["portable-atomic-util"] + }, + "yanked": false, + "rust_version": "1.51", + "pubtime": "2024-05-13T00:24:30Z" + } + ] + }, + { + "path": "wa/lk/walkdir", + "header": "AwIAAABldGFnOiAiYTI2ZWQ2NjQwMDExMTgyZjg4NzAzMThlMTM0NjYxYTEiAA==", + "records": [ + { + "name": "walkdir", + "vers": "2.5.0", + "deps": [ + { + "name": "doc-comment", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "same-file", + "req": "^1.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "winapi-util", + "req": "^0.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b", + "features": {}, + "yanked": false, + "pubtime": "2024-03-01T17:55:09Z" + } + ] + }, + { + "path": "wa/si/wasi", + "header": "AwIAAABldGFnOiAiOWVjMjhjZDI2MzIyMGM4MzNhNGIzYmQ0YThmOWU5MWQiAA==", + "records": [ + { + "name": "wasi", + "vers": "0.11.1+wasi-snapshot-preview1", + "deps": [ + { + "name": "core", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "rustc-std-workspace-alloc", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b", + "features": { + "default": ["std"], + "rustc-dep-of-std": ["core", "rustc-std-workspace-alloc"], + "std": [] + }, + "yanked": false, + "pubtime": "2025-06-10T14:23:45Z" + }, + { + "name": "wasi", + "vers": "0.14.7+wasi-0.2.4", + "deps": [ + { + "name": "wasip2", + "req": "^1.0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c", + "features": { + "bitflags": ["wasip2/bitflags"], + "default": ["wasip2/default"], + "std": ["wasip2/std"] + }, + "yanked": false, + "rust_version": "1.82.0", + "pubtime": "2025-09-15T22:01:38Z" + } + ] + }, + { + "path": "wa/si/wasip2", + "header": "AwIAAABldGFnOiAiMmE1MWY4ZTc1N2NjZGE5NTU5OTVkZWMyODg5ODQ5YzciAA==", + "records": [ + { + "name": "wasip2", + "vers": "1.0.4+wasi-0.2.12", + "deps": [ + { + "name": "alloc", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "core", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "wit-bindgen", + "req": "^0.57.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487", + "features": { + "bitflags": ["wit-bindgen/bitflags"], + "default": ["std", "bitflags"], + "rustc-dep-of-std": ["core", "alloc", "wit-bindgen/rustc-dep-of-std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.87.0", + "pubtime": "2026-06-12T17:42:43Z" + } + ] + }, + { + "path": "wa/si/wasite", + "header": "AwIAAABldGFnOiAiZjlhYzdkZjcyZWM4MjM5NTI2NjRmZGZkZDliZDZiM2IiAA==", + "records": [ + { + "name": "wasite", + "vers": "1.0.2", + "deps": [ + { + "name": "wasi", + "req": ">=0.13, <0.15", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "66fe902b4a6b8028a753d5424909b764ccf79b7a209eac9bf97e59cda9f71a42", + "features": {}, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-01-08T04:37:24Z" + } + ] + }, + { + "path": "wa/sm/wasm-bindgen", + "header": "AwIAAABldGFnOiAiNzU5OGQzMjBkOWQwNzJjMzgwMDgzZGU3MGQ5NDY2ZTMiAA==", + "records": [ + { + "name": "wasm-bindgen", + "vers": "0.2.129", + "deps": [ + { + "name": "cfg-if", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "once_cell", + "req": "^1.12", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "paste", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "paste", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm64\")", + "kind": "dev" + }, + { + "name": "rustversion-compat", + "req": "^1.0.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build", + "package": "rustversion" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "serde_derive", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm64\")", + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1", + "features": ["rt", "time", "sync"], + "optional": false, + "default_features": false, + "target": "cfg(all(target_os = \"emscripten\", wasm_bindgen_unstable_tokio))", + "kind": "dev" + }, + { + "name": "wasm-bindgen-macro", + "req": "=0.2.129", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasm-bindgen-shared", + "req": "=0.2.129", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "9bb54f33acc68fd454578d9820b0bde1a1a3d17aa17bb7b6595806d02886d409", + "features": { + "default": ["std"], + "enable-interning": ["std"], + "gg-alloc": [], + "msrv": [], + "rustversion": [], + "serde-serialize": ["serde", "serde_json", "std"], + "spans": [], + "std": [], + "strict-macro": ["wasm-bindgen-macro/strict-macro"], + "xxx_debug_only_print_generated_code": [] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-09-25T07:13:40Z" + } + ] + }, + { + "path": "wa/sm/wasm-bindgen-macro", + "header": "AwIAAABldGFnOiAiMzIwZDcwOWQyZTdmNjllODkxOGIzYzMyNjM2ZWVlOTYiAA==", + "records": [ + { + "name": "wasm-bindgen-macro", + "vers": "0.2.129", + "deps": [ + { + "name": "quote", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "trybuild", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "wasm-bindgen-macro-support", + "req": "=0.2.129", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "2e29d0c35b16e224a7eeb5cd2d25e3e1968fbd65604117b44d3b789d00ee8535", + "features": { + "strict-macro": ["wasm-bindgen-macro-support/strict-macro"] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-09-25T07:13:38Z" + } + ] + }, + { + "path": "wa/sm/wasm-bindgen-macro-support", + "header": "AwIAAABldGFnOiAiY2Y5NjRhOTdjOWZhMTAxOTVlMjhhYjk0ZTBhZmUzMTkiAA==", + "records": [ + { + "name": "wasm-bindgen-macro-support", + "vers": "0.2.129", + "deps": [ + { + "name": "bumpalo", + "req": "^3.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3.0", + "features": ["visit", "visit-mut", "full", "extra-traits"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasm-bindgen-shared", + "req": "=0.2.129", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "6f501a8bc3719dba86ef8ae4728879c08001bea749eb1333ac5b91e040e2a6b7", + "features": { + "extra-traits": ["syn/extra-traits"], + "strict-macro": [] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-09-25T07:13:36Z" + } + ] + }, + { + "path": "wa/sm/wasm-bindgen-shared", + "header": "AwIAAABldGFnOiAiMjU4ZDE1YTg1NTcyM2E3ZGI5MjcyZWYwYTQ2OWUwZGUiAA==", + "records": [ + { + "name": "wasm-bindgen-shared", + "vers": "0.2.129", + "deps": [ + { + "name": "unicode-ident", + "req": "^1.0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "23f0c9c52aa7cd7d77769a4cfe2a9adb1b331f489a41d912ce14513d5ab995c6", + "features": {}, + "yanked": false, + "links": "wasm_bindgen", + "rust_version": "1.81", + "pubtime": "2026-09-25T07:13:33Z" + } + ] + }, + { + "path": "wa/sm/wasm-encoder", + "header": "AwIAAABldGFnOiAiNjEyMGEwZTJmYmNlYzQ2MjVkNmE2Y2RlMDYxNGEyOTUiAA==", + "records": [ + { + "name": "wasm-encoder", + "vers": "0.252.0", + "deps": [ + { + "name": "anyhow", + "req": "^1.0.58", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "leb128fmt", + "req": "^0.1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "wasmparser", + "req": "^0.252.0", + "features": ["simd", "simd"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmprinter", + "req": "^0.252.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + } + ], + "cksum": "8185ae345fa5687c054626ff9a50e7089797a343d9904d1dc9820eb4c4d3196f", + "features": {}, + "features2": { + "component-model": ["wasmparser?/component-model"], + "default": ["std", "component-model"], + "std": ["wasmparser?/std"] + }, + "yanked": false, + "rust_version": "1.85.0", + "pubtime": "2026-06-12T19:22:40Z", + "v": 2 + } + ] + }, + { + "path": "wa/sm/wasmer", + "header": "AwIAAABldGFnOiAiZDMwMDJhZTA2OTM3ZThkNmVjZWQyYTE4YWU5OTEwMDciAA==", + "records": [ + { + "name": "wasmer", + "vers": "7.2.1", + "deps": [ + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "bindgen", + "req": "^0.72.1", + "features": ["logging", "prettyplease", "static"], + "optional": false, + "default_features": false, + "target": "cfg(target_env = \"musl\")", + "kind": "build" + }, + { + "name": "bindgen", + "req": "^0.72.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_env = \"musl\"))", + "kind": "build" + }, + { + "name": "bytes", + "req": "^1.11.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cmake", + "req": "^0.1.50", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "corosensei", + "req": "^0.3.0", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "crossbeam-channel", + "req": "^0.5.15", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "dashmap", + "req": "^6.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "derive_more", + "req": "^2.0.1", + "features": ["debug", "display", "from", "debug", "unwrap"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures", + "req": "^0.3.30", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "futures", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "hashbrown", + "req": "^0.17.0", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "itertools", + "req": "^0.15", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "js-sys", + "req": "^0.3.77", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "normal" + }, + { + "name": "js-sys", + "req": "^0.3.77", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "loupe", + "req": "^0.2.0", + "features": ["indexmap", "enable-indexmap"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "macro-wasmer-engine-test", + "req": "^7.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "macro-wasmer-engine-test", + "req": "^7.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "more-asserts", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "paste", + "req": "^1.0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rkyv", + "req": "^0.8.13", + "features": ["indexmap-2", "bytes-1"], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "normal" + }, + { + "name": "serde-wasm-bindgen", + "req": "^0.6.5", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "normal" + }, + { + "name": "shared-buffer", + "req": "^0.1.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "symbolic-demangle", + "req": "^13", + "features": ["rust", "cpp", "msvc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tar", + "req": "^0.4.40", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "target-lexicon", + "req": "^0.13.3", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "target-lexicon", + "req": "^0.13.3", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.6.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "tempfile", + "req": "^3.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "thiserror", + "req": "^2.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.39.0", + "features": ["full"], + "optional": false, + "default_features": false, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "tracing", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ureq", + "req": "^3.3.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "wasm-bindgen", + "req": "^0.2.120", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "normal" + }, + { + "name": "wasm-bindgen", + "req": "^0.2.120", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3.70", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "wasmer-compiler", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "normal" + }, + { + "name": "wasmer-compiler", + "req": "=7.2.1", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "wasmer-compiler-cranelift", + "req": "=7.2.1", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "wasmer-compiler-llvm", + "req": "=7.2.1", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "wasmer-compiler-singlepass", + "req": "=7.2.1", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "wasmer-derive", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "wasmer-derive", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "normal" + }, + { + "name": "wasmer-types", + "req": "=7.2.1", + "features": ["std"], + "optional": false, + "default_features": false, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "normal" + }, + { + "name": "wasmer-types", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "wasmer-vm", + "req": "=7.2.1", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "wasmparser", + "req": "^0.252.0", + "features": ["validate", "features", "simd"], + "optional": true, + "default_features": false, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "wasmparser", + "req": "^0.252.0", + "features": ["validate", "features", "simd"], + "optional": true, + "default_features": false, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "normal" + }, + { + "name": "wat", + "req": "^1.252.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wat", + "req": "^1.252.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "wat", + "req": "^1.252.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "which", + "req": "^8.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "windows-sys", + "req": "^0.61.2", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(not(target_arch = \"wasm32\"), target_os = \"windows\"))", + "kind": "normal" + }, + { + "name": "xz", + "req": "^0.1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "zip", + "req": "^8.1.0", + "features": ["deflate"], + "optional": true, + "default_features": false, + "target": null, + "kind": "build" + } + ], + "cksum": "05af716b1bf3de5b8081133223f77f37916e9b4f41e0781c7fbe3e0d7b6da43a", + "features": { + "baremetal": ["wasmer-vm/baremetal"], + "core": ["hashbrown"], + "enable-serde": [ + "wasmer-vm/enable-serde", + "wasmer-compiler/enable-serde", + "wasmer-types/enable-serde" + ], + "experimental-host-interrupt": ["wasmer-vm/experimental-host-interrupt"], + "headless": [], + "js": ["wasm-bindgen", "js-sys"], + "js-default": ["js", "std", "wasm-types-polyfill"], + "js-serializable-module": [], + "sanitizer": ["wasmer-vm/sanitizer"], + "static-artifact-create": ["wasmer-compiler/static-artifact-create"], + "static-artifact-load": ["wasmer-compiler/static-artifact-load"], + "std": [], + "wasm-c-api": ["wasm-types-polyfill"], + "wasm-types-polyfill": ["wasmparser"], + "wasmer-artifact-create": ["wasmer-compiler/wasmer-artifact-create"], + "wasmer-artifact-load": ["wasmer-compiler/wasmer-artifact-load"] + }, + "features2": { + "artifact-size": [ + "dep:loupe", + "wasmer-vm/artifact-size", + "wasmer-compiler/artifact-size" + ], + "compiler": [ + "sys", + "dep:wasmer-compiler", + "wasmer-compiler/translator", + "wasmer-compiler/compiler" + ], + "cranelift": ["compiler", "wasmer-compiler-cranelift"], + "default": ["sys-default"], + "experimental-async": ["dep:futures", "dep:corosensei"], + "llvm": ["compiler", "wasmer-compiler-llvm"], + "singlepass": ["compiler", "wasmer-compiler-singlepass"], + "sys": ["std", "dep:wasmer-vm", "dep:wasmer-compiler"], + "sys-default": ["sys", "wat", "cranelift"], + "v8": ["wasm-c-api", "std", "dep:tempfile", "dep:which", "dep:xz", "dep:ureq"], + "v8-default": ["v8", "wat"], + "wat": ["dep:wat", "wasmparser"] + }, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:07:17Z", + "v": 2 + } + ] + }, + { + "path": "wa/sm/wasmer-compiler", + "header": "AwIAAABldGFnOiAiMjEyNTZlMjgzYmNlMDgwNjFlYjNlNTgwZjMxZTQ2ZjIiAA==", + "records": [ + { + "name": "wasmer-compiler", + "vers": "7.2.1", + "deps": [ + { + "name": "backtrace", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytes", + "req": "^1.11.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "crossbeam-channel", + "req": "^0.5.15", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "enum-iterator", + "req": "^2.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "enumset", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hashbrown", + "req": "^0.17.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "itertools", + "req": "^0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "leb128", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.178", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "loupe", + "req": "^0.2.0", + "features": ["indexmap", "enable-indexmap"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "macho-unwind-info", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_os = \"macos\", target_arch = \"aarch64\"))", + "kind": "normal" + }, + { + "name": "memmap2", + "req": "^0.9.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "more-asserts", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "object", + "req": "^0.39.0", + "features": ["write"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rangemap", + "req": "^1.7.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1.7.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "region", + "req": "^3.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "rkyv", + "req": "^0.8.13", + "features": ["indexmap-2", "bytes-1"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "self_cell", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_bytes", + "req": "^0.11", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "shared-buffer", + "req": "^0.1.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "smallvec", + "req": "^1.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "target-lexicon", + "req": "^0.13.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "thiserror", + "req": "^2.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-types", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-vm", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "wasmparser", + "req": "^0.252.0", + "features": ["validate", "features", "simd"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "which", + "req": "^8.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": "^0.61.2", + "features": ["Win32_System_Diagnostics_Debug"], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"windows\")", + "kind": "normal" + } + ], + "cksum": "99d984ed2ecd52a8e68ea0f4959bc342bf3b2381262105898a8cb416ecd15003", + "features": { + "baremetal": ["wasmer-vm/baremetal"], + "compiler": ["translator"], + "core": ["hashbrown", "wasmer-types/core"], + "default": ["std"], + "enable-serde": ["serde", "serde_bytes", "wasmer-types/enable-serde"], + "static-artifact-create": ["translator", "compiler"], + "static-artifact-load": [], + "std": ["wasmer-types/std"], + "translator": ["wasmparser"], + "wasmer-artifact-create": [], + "wasmer-artifact-load": [] + }, + "features2": { + "artifact-size": ["dep:loupe"] + }, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:05:28Z", + "v": 2 + } + ] + }, + { + "path": "wa/sm/wasmer-config", + "header": "AwIAAABldGFnOiAiN2FlNDNjOTdiMjIzODY1YzY2YmQyNjg4MDNlODg2MWQiAA==", + "records": [ + { + "name": "wasmer-config", + "vers": "0.702.1", + "deps": [ + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytesize", + "req": "^2.3.1", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ciborium", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "derive_builder", + "req": "^0.20.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hex", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pretty_assertions", + "req": "^1.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "saffron", + "req": "^0.1.0", + "features": ["std"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "schemars", + "req": "^1.1.0", + "features": ["url2", "indexmap2"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "semver", + "req": "^1.0", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_yaml", + "req": "^0.9.34", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "thiserror", + "req": "^2.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "toml", + "req": "^1.1.0", + "features": ["preserve_order"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "url", + "req": "^2.5", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "98700e4516eb825f1ad22cd5273bafd0694941722686010dc1af79b70812393f", + "features": {}, + "yanked": false, + "pubtime": "2026-07-27T11:04:27Z" + } + ] + }, + { + "path": "wa/sm/wasmer-derive", + "header": "AwIAAABldGFnOiAiYjBkNTk4NjVmNGY3MDE1YzM4NzI1YmNkZWRiZGQ1MTQiAA==", + "records": [ + { + "name": "wasmer-derive", + "vers": "7.2.1", + "deps": [ + { + "name": "compiletest_rs", + "req": "^0.11.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro-error2", + "req": "^2.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.20", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2", + "features": ["full", "extra-traits", "derive", "parsing", "proc-macro", "printing"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "882cc3b1909d543b4c5cd84c21d659c9c3608225240a79b68e39554749592b79", + "features": {}, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:05:00Z" + } + ] + }, + { + "path": "wa/sm/wasmer-journal", + "header": "AwIAAABldGFnOiAiYmFjYjk0ZDc1MzJkZjVjNjY0Mzk0ODFhZTU4N2I5YWYiAA==", + "records": [ + { + "name": "wasmer-journal", + "vers": "0.702.1", + "deps": [ + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "async-trait", + "req": "^0.1.68", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "base64", + "req": "^0.22.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bincode", + "req": "=2.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytecheck", + "req": "^0.8.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytes", + "req": "^1.11.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "derive_more", + "req": "^2.0.1", + "features": ["debug", "display"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "lz4_flex", + "req": "^0.13.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "num_enum", + "req": "^0.7.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rkyv", + "req": "^0.8.13", + "features": ["indexmap-2", "bytes-1"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "shared-buffer", + "req": "^0.1.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "thiserror", + "req": "^2.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tracing", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tracing-test", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "virtual-fs", + "req": "^0.702.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "virtual-net", + "req": "^0.702.1", + "features": ["rkyv"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-config", + "req": "=0.702.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-wasix-types", + "req": "^0.702.1", + "features": ["enable-serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "d02acd34af8c89ce772dd492da754dc999d4e3d3f30cbbf11a9c58f5e6c3a659", + "features": { + "default": ["log-file", "wasmer/sys-default"], + "log-file": ["shared-buffer"] + }, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:08:34Z" + } + ] + }, + { + "path": "wa/sm/wasmer-package", + "header": "AwIAAABldGFnOiAiYmYwOTFlYTJiNDI0ZjM1MGFlNTlhNTM5ZjE2OTZmMTciAA==", + "records": [ + { + "name": "wasmer-package", + "vers": "0.702.1", + "deps": [ + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytes", + "req": "^1.11.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ciborium", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "flate2", + "req": "^1.0.34", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hexdump", + "req": "^0.1.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ignore", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "insta", + "req": "^1.45.0", + "features": ["filters", "yaml"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.178", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_family = \"wasm\", target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "pretty_assertions", + "req": "^1.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "regex", + "req": "^1.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "semver", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sha2", + "req": "^0.11.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "shared-buffer", + "req": "^0.1.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tar", + "req": "^0.4.40", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "thiserror", + "req": "^2.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "toml", + "req": "^1.1.0", + "features": ["preserve_order"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ureq", + "req": "^3.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "url", + "req": "^2.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-config", + "req": "^0.702.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-types", + "req": "^7.2.1", + "features": ["detect-wasm-features"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "webc", + "req": "=12.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "54f12fd1711df6b12ade23b5db433d3f1aae4f31a7580d7db480f2cce03ccdb1", + "features": {}, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:05:10Z" + } + ] + }, + { + "path": "wa/sm/wasmer-types", + "header": "AwIAAABldGFnOiAiZmI0ZmZhYTNjNzk3NmQxMmQyYzljYmRjYWYwN2EzYzUiAA==", + "records": [ + { + "name": "wasmer-types", + "vers": "7.2.1", + "deps": [ + { + "name": "bytecheck", + "req": "^0.8.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "crc32fast", + "req": "^1.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "criterion", + "req": "^0.8.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "enum-iterator", + "req": "^2.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "enumset", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "getrandom", + "req": "^0.4.1", + "features": ["wasm_js"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hex", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "itertools", + "req": "^0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "loupe", + "req": "^0.2.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memoffset", + "req": "^0.9.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "more-asserts", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rkyv", + "req": "^0.8.13", + "features": ["indexmap-2", "bytes-1"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive", "rc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_bytes", + "req": "^0.11", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sha2", + "req": "^0.11.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "target-lexicon", + "req": "^0.13.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "thiserror", + "req": "^2.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasmparser", + "req": "^0.252.0", + "features": ["validate", "features", "simd"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "87234e5a975dc1343c08692165e01def9725a74cf527277c0e36b0eb66b8f427", + "features": { + "core": [], + "default": ["std"], + "enable-serde": ["serde", "serde/std", "serde_bytes", "indexmap/serde"], + "std": [] + }, + "features2": { + "artifact-size": ["dep:loupe"], + "detect-wasm-features": ["dep:wasmparser"] + }, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:04:17Z", + "v": 2 + } + ] + }, + { + "path": "wa/sm/wasmer-vm", + "header": "AwIAAABldGFnOiAiMTIwYjE5OWMyN2I1MDA3MmQ1NGRkZmE4ODA5YmJlNGYiAA==", + "records": [ + { + "name": "wasmer-vm", + "vers": "7.2.1", + "deps": [ + { + "name": "backtrace", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytesize", + "req": "^2.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cc", + "req": "^1.2.47", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "cfg-if", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "corosensei", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "crossbeam-queue", + "req": "^0.3.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "dashmap", + "req": "^6.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "enum-iterator", + "req": "^2.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "fnv", + "req": "^1.0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "gimli", + "req": "^0.33.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "itertools", + "req": "^0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.178", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "libunwind", + "req": "^1.3.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(target_family = \"unix\", all(target_family = \"windows\", target_env = \"gnu\")))", + "kind": "normal" + }, + { + "name": "loupe", + "req": "^0.2.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "mach2", + "req": "^0.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_vendor = \"apple\")", + "kind": "normal" + }, + { + "name": "memoffset", + "req": "^0.9.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "more-asserts", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "parking_lot", + "req": "^0.12.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "region", + "req": "^3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustversion", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "scopeguard", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive", "rc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "thiserror", + "req": "^2.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tracing", + "req": "^0.1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-types", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "windows-sys", + "req": "^0.61.2", + "features": [ + "Win32_System_Diagnostics_Debug", + "Win32_System_Threading", + "Win32_System_Kernel", + "Win32_System_Memory" + ], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"windows\")", + "kind": "normal" + } + ], + "cksum": "8112dae928ca0d5341180e1ea1418d78bdb3788a78da625a4a3889fe908a91bb", + "features": { + "baremetal": [], + "default": [], + "enable-serde": ["serde", "indexmap/serde", "wasmer-types/enable-serde"], + "experimental-host-interrupt": [], + "sanitizer": ["corosensei/sanitizer"] + }, + "features2": { + "artifact-size": ["dep:loupe", "wasmer-types/artifact-size"] + }, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:04:54Z", + "v": 2 + } + ] + }, + { + "path": "wa/sm/wasmer-wasix", + "header": "AwIAAABldGFnOiAiYmQ4Mzg0MTYzNDU2OTE3OTY5ZDRkZmZkMTliMzYyNTAiAA==", + "records": [ + { + "name": "wasmer-wasix", + "vers": "0.702.1", + "deps": [ + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "assert-panic", + "req": "^1.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "async-trait", + "req": "^0.1.68", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "base64", + "req": "^0.22.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bincode", + "req": "=2.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "blake3", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bus", + "req": "^2.4.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytecheck", + "req": "^0.8.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytes", + "req": "^1.11.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "chrono", + "req": "^0.4.38", + "features": ["wasmbind", "std", "clock"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "ciborium", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "cooked-waker", + "req": "^5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "crossbeam-channel", + "req": "^0.5.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "dashmap", + "req": "^6.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "derive_more", + "req": "^2.0.1", + "features": ["debug", "display"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "dirs", + "req": "^6.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "env_logger", + "req": "^0.11.5", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "flate2", + "req": "^1.0.34", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "fnv", + "req": "^1.0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "fs_extra", + "req": "^1.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures", + "req": "^0.3.30", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "getrandom", + "req": "^0.4.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "getrandom03", + "req": "^0.3.4", + "features": ["wasm_js"], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "normal", + "package": "getrandom" + }, + { + "name": "heapless", + "req": "^0.9.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hex", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "http", + "req": "^1.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "http-body-util", + "req": "^0.1.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hyper", + "req": "^1.8.1", + "features": ["server"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hyper-util", + "req": "^0.1.5", + "features": ["server", "server-graceful", "tokio", "service", "client"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "itertools", + "req": "^0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "js-sys", + "req": "^0.3.77", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.178", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "libtest-mimic", + "req": "^0.8.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "linked_hash_set", + "req": "^0.1.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "log", + "req": "^0.4.22", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "lz4_flex", + "req": "^0.13.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "num_enum", + "req": "^0.7.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "once_cell", + "req": "^1.17.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "petgraph", + "req": "^0.8.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pin-project", + "req": "^1.0.12", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pin-utils", + "req": "^0.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pretty_assertions", + "req": "^1.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.10.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1.7.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "reqwest", + "req": "^0.13.0", + "features": ["native-tls", "json", "stream", "socks", "blocking"], + "optional": true, + "default_features": false, + "target": "cfg(any(target_arch = \"riscv64\", target_arch = \"loongarch64\"))", + "kind": "normal" + }, + { + "name": "reqwest", + "req": "^0.13.0", + "features": ["rustls", "json", "stream", "socks", "blocking"], + "optional": true, + "default_features": false, + "target": "cfg(not(any(target_arch = \"riscv64\", target_arch = \"loongarch64\")))", + "kind": "normal" + }, + { + "name": "rkyv", + "req": "^0.8.13", + "features": ["indexmap-2", "bytes-1"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rusty_pool", + "req": "^0.7.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "semver", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_yaml", + "req": "^0.9.34", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sha2", + "req": "^0.11.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "shared-buffer", + "req": "^0.1.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "strum", + "req": "^0.28", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tempfile", + "req": "^3.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "terminal_size", + "req": "^0.4.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "termios", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(unix, not(target_os=\"ios\")))", + "kind": "normal" + }, + { + "name": "thiserror", + "req": "^2.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.39.0", + "features": ["sync", "macros", "time", "rt"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.39.0", + "features": ["sync", "macros", "rt"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-stream", + "req": "^0.1", + "features": ["sync"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "toml", + "req": "^1.1.0", + "features": ["preserve_order"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tower", + "req": "^0.5.2", + "features": ["make", "util"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tower-http", + "req": "^0.7.0", + "features": ["trace", "util", "catch-panic", "cors"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tracing", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tracing-subscriber", + "req": "^0.3", + "features": ["env-filter", "fmt"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "tracing-test", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tracing-wasm", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "url", + "req": "^2.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "urlencoding", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "version-compare", + "req": "^0.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "virtual-fs", + "req": "^0.702.1", + "features": ["webc-fs"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "virtual-mio", + "req": "^0.702.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "virtual-net", + "req": "^0.702.1", + "features": ["rkyv"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "waker-fn", + "req": "^1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "walkdir", + "req": "^2.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasm-bindgen", + "req": "^0.2.120", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasm-bindgen-futures", + "req": "^0.4.70", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3.70", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3.70", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "wasm-encoder", + "req": "^0.252.0", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer", + "req": "=7.2.1", + "features": ["experimental-async"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer", + "req": "=7.2.1", + "features": ["wat", "js-serializable-module"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "wasmer", + "req": "=7.2.1", + "features": ["wat", "js-serializable-module", "cranelift"], + "optional": false, + "default_features": false, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "wasmer-config", + "req": "^0.702.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-journal", + "req": "^0.702.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-package", + "req": "^0.702.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-types", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-wasix-types", + "req": "^0.702.1", + "features": ["enable-serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasmparser", + "req": "^0.252.0", + "features": ["validate", "features", "simd"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wcgi", + "req": "^0.3.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wcgi-host", + "req": "^0.3.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "web-sys", + "req": "^0.3.64", + "features": [ + "Request", + "RequestInit", + "Window", + "WorkerGlobalScope", + "RequestMode", + "Response", + "Headers" + ], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "webc", + "req": "=12.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "weezl", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "windows-sys", + "req": "^0.61.2", + "features": ["Win32_System_SystemInformation"], + "optional": false, + "default_features": false, + "target": "cfg(windows)", + "kind": "normal" + }, + { + "name": "xxhash-rust", + "req": "^0.8.10", + "features": ["xxh64"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zstd", + "req": "^0.13.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + } + ], + "cksum": "90a93bb66bc9bb1c766d53c68676f8a4f23582b0feef6135c184dfd3bf762e2e", + "features": { + "compiler": [], + "ctrlc": ["tokio/signal"], + "default": ["sys-default"], + "disable-all-logging": ["tracing/release_max_level_off", "tracing/max_level_off"], + "enable-serde": ["wasmer-wasix-types/enable-serde", "wasmer/enable-serde"], + "extra-logging": [], + "host-fs": ["virtual-fs/host-fs"], + "host-reqwest": ["reqwest"], + "host-threads": [], + "host-vnet": ["virtual-net/host-net"], + "journal": ["tokio/fs", "wasmer-journal/log-file"], + "js": [ + "virtual-fs/js", + "getrandom/wasm_js", + "chrono", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wasmer/js-default", + "wasmer/wasm-types-polyfill", + "wasmer/wat", + "wasmer/js-serializable-module" + ], + "js-default": ["js"], + "llvm": ["wasmer/llvm"], + "logging": ["tracing/log"], + "remote-vnet": ["virtual-net/remote"], + "singlepass": ["wasmer/singlepass"], + "sys": [ + "webc/mmap", + "time", + "virtual-mio/sys", + "logging", + "host-fs", + "journal", + "sys-poll", + "sys-thread", + "host-vnet", + "host-threads", + "host-reqwest", + "ctrlc", + "wasmer/wat", + "wasmer/js-serializable-module", + "wasmer/sys", + "wasmer/headless" + ], + "sys-default": ["sys"], + "sys-minimal": ["wasmer/sys", "sys-thread", "tokio/fs"], + "sys-poll": [], + "sys-thread": ["tokio/rt", "tokio/time", "tokio/rt-multi-thread", "rusty_pool"], + "test-js": ["js", "wasmer/wat"], + "time": ["tokio/time"], + "v8": ["wasmer/v8"] + }, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:09:14Z" + } + ] + }, + { + "path": "wa/sm/wasmer-wasix-types", + "header": "AwIAAABldGFnOiAiYWUwYWU3N2IzYTQxMjQyMjc1MmNlMzdmNTdkM2I0NzgiAA==", + "records": [ + { + "name": "wasmer-wasix-types", + "vers": "0.702.1", + "deps": [ + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bitflags", + "req": "^2.11.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "byteorder", + "req": "^1.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "num_enum", + "req": "^0.7.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pretty_assertions", + "req": "^1.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "time", + "req": "^0.3.47", + "features": ["formatting"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tracing", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wai-bindgen-gen-core", + "req": "^0.2.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wai-bindgen-gen-rust", + "req": "^0.2.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wai-bindgen-gen-rust-wasm", + "req": "^0.2.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wai-bindgen-rust", + "req": "^0.2.1", + "features": ["macros"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wai-parser", + "req": "^0.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-derive", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-types", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "f982c57b8ccfcb6bc6f7d7ba420bf53a2099ea9c77135b45cdf45198a00c90db", + "features": { + "enable-serde": ["serde", "wasmer-types/serde"] + }, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:08:04Z" + } + ] + }, + { + "path": "wa/sm/wasmparser", + "header": "AwIAAABldGFnOiAiNWIzNGJmNGZiZDVkYjg3MWFiNDAyNjg3ZDllMDA2NzUiAA==", + "records": [ + { + "name": "wasmparser", + "vers": "0.252.0", + "deps": [ + { + "name": "anyhow", + "req": "^1.0.58", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "bitflags", + "req": "^2.4.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "criterion", + "req": "^0.7.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "env_logger", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hashbrown", + "req": "^0.17.0", + "features": ["default-hasher"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2.14.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "log", + "req": "^0.4.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "once_cell", + "req": "^1.13.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "^1.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "semver", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.166", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "d3eb099dcadcde5be9eef55e3a337128efd4e44b4c93122487e4d2e4e1c6627c", + "features": { + "features": [], + "prefer-btree-collections": [], + "simd": [], + "try-op": [], + "validate": [] + }, + "features2": { + "component-model": ["dep:semver"], + "default": [ + "std", + "validate", + "serde", + "features", + "component-model", + "hash-collections", + "simd" + ], + "hash-collections": ["dep:hashbrown", "dep:indexmap"], + "serde": ["dep:serde", "indexmap?/serde", "hashbrown?/serde"], + "std": ["indexmap?/std"] + }, + "yanked": false, + "rust_version": "1.85.0", + "pubtime": "2026-06-12T19:22:35Z", + "v": 2 + } + ] + }, + { + "path": "we/b-/web-sys", + "header": "AwIAAABldGFnOiAiOTAwZWQyZWM5ODVkMzM5MzdkNDg1YTEzZmQ5ZmNiMTciAA==", + "records": [ + { + "name": "web-sys", + "vers": "0.3.106", + "deps": [ + { + "name": "futures", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "js-sys", + "req": "=0.3.106", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasm-bindgen", + "req": "=0.2.129", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "88261b9deccee56594c11a3460c462c41f58d148598fe70ad77070126a68aba4", + "features": { + "AbortController": [], + "AbortSignal": ["EventTarget"], + "AbstractRange": [], + "AddEventListenerOptions": [], + "AesCbcParams": [], + "AesCtrParams": [], + "AesDerivedKeyParams": [], + "AesGcmParams": [], + "AesKeyAlgorithm": [], + "AesKeyGenParams": [], + "Algorithm": [], + "AlignSetting": [], + "AllowedBluetoothDevice": [], + "AllowedUsbDevice": [], + "AlphaOption": [], + "AnalyserNode": ["AudioNode", "EventTarget"], + "AnalyserOptions": [], + "AngleInstancedArrays": [], + "Animation": ["EventTarget"], + "AnimationEffect": [], + "AnimationEvent": ["Event"], + "AnimationEventInit": [], + "AnimationPlayState": [], + "AnimationPlaybackEvent": ["Event"], + "AnimationPlaybackEventInit": [], + "AnimationPropertyDetails": [], + "AnimationPropertyValueDetails": [], + "AnimationTimeline": [], + "AssignedNodesOptions": [], + "AttestationConveyancePreference": [], + "Attr": ["EventTarget", "Node"], + "AttributeNameValue": [], + "AudioBuffer": [], + "AudioBufferOptions": [], + "AudioBufferSourceNode": ["AudioNode", "AudioScheduledSourceNode", "EventTarget"], + "AudioBufferSourceOptions": [], + "AudioConfiguration": [], + "AudioContext": ["BaseAudioContext", "EventTarget"], + "AudioContextLatencyCategory": [], + "AudioContextOptions": [], + "AudioContextState": [], + "AudioData": [], + "AudioDataCopyToOptions": [], + "AudioDataInit": [], + "AudioDecoder": ["EventTarget"], + "AudioDecoderConfig": [], + "AudioDecoderInit": [], + "AudioDecoderSupport": [], + "AudioDestinationNode": ["AudioNode", "EventTarget"], + "AudioEncoder": ["EventTarget"], + "AudioEncoderConfig": [], + "AudioEncoderInit": [], + "AudioEncoderSupport": [], + "AudioListener": [], + "AudioNode": ["EventTarget"], + "AudioNodeOptions": [], + "AudioParam": [], + "AudioParamMap": [], + "AudioProcessingEvent": ["Event"], + "AudioSampleFormat": [], + "AudioScheduledSourceNode": ["AudioNode", "EventTarget"], + "AudioSinkInfo": [], + "AudioSinkOptions": [], + "AudioSinkType": [], + "AudioStreamTrack": ["EventTarget", "MediaStreamTrack"], + "AudioTrack": [], + "AudioTrackList": ["EventTarget"], + "AudioWorklet": ["Worklet"], + "AudioWorkletGlobalScope": ["WorkletGlobalScope"], + "AudioWorkletNode": ["AudioNode", "EventTarget"], + "AudioWorkletNodeOptions": [], + "AudioWorkletProcessor": [], + "AuthenticationExtensionsClientInputs": [], + "AuthenticationExtensionsClientInputsJson": [], + "AuthenticationExtensionsClientOutputs": [], + "AuthenticationExtensionsClientOutputsJson": [], + "AuthenticationExtensionsDevicePublicKeyInputs": [], + "AuthenticationExtensionsDevicePublicKeyOutputs": [], + "AuthenticationExtensionsLargeBlobInputs": [], + "AuthenticationExtensionsLargeBlobOutputs": [], + "AuthenticationExtensionsPrfInputs": [], + "AuthenticationExtensionsPrfOutputs": [], + "AuthenticationExtensionsPrfValues": [], + "AuthenticationResponseJson": [], + "AuthenticatorAssertionResponse": ["AuthenticatorResponse"], + "AuthenticatorAssertionResponseJson": [], + "AuthenticatorAttachment": [], + "AuthenticatorAttestationResponse": ["AuthenticatorResponse"], + "AuthenticatorAttestationResponseJson": [], + "AuthenticatorResponse": [], + "AuthenticatorSelectionCriteria": [], + "AuthenticatorTransport": [], + "AutoKeyword": [], + "AutocompleteInfo": [], + "BarProp": [], + "BaseAudioContext": ["EventTarget"], + "BaseComputedKeyframe": [], + "BaseKeyframe": [], + "BasePropertyIndexedKeyframe": [], + "BasicCardRequest": [], + "BasicCardResponse": [], + "BasicCardType": [], + "BatteryManager": ["EventTarget"], + "BeforeUnloadEvent": ["Event"], + "BinaryType": [], + "BiquadFilterNode": ["AudioNode", "EventTarget"], + "BiquadFilterOptions": [], + "BiquadFilterType": [], + "BitrateMode": [], + "Blob": [], + "BlobEvent": ["Event"], + "BlobEventInit": [], + "BlobPropertyBag": [], + "BlockParsingOptions": [], + "Bluetooth": ["EventTarget"], + "BluetoothAdvertisingEvent": ["Event"], + "BluetoothAdvertisingEventInit": [], + "BluetoothCharacteristicProperties": [], + "BluetoothDataFilterInit": [], + "BluetoothDevice": ["EventTarget"], + "BluetoothLeScanFilterInit": [], + "BluetoothManufacturerDataMap": [], + "BluetoothPermissionDescriptor": [], + "BluetoothPermissionResult": ["EventTarget", "PermissionStatus"], + "BluetoothPermissionStorage": [], + "BluetoothRemoteGattCharacteristic": ["EventTarget"], + "BluetoothRemoteGattDescriptor": [], + "BluetoothRemoteGattServer": [], + "BluetoothRemoteGattService": ["EventTarget"], + "BluetoothServiceDataMap": [], + "BluetoothUuid": [], + "BoxQuadOptions": [], + "BroadcastChannel": ["EventTarget"], + "BrowserElementDownloadOptions": [], + "BrowserElementExecuteScriptOptions": [], + "BrowserFeedWriter": [], + "BrowserFindCaseSensitivity": [], + "BrowserFindDirection": [], + "ByteLengthQueuingStrategy": [], + "Cache": [], + "CacheBatchOperation": [], + "CacheQueryOptions": [], + "CacheStorage": [], + "CacheStorageNamespace": [], + "CanvasCaptureMediaStream": ["EventTarget", "MediaStream"], + "CanvasCaptureMediaStreamTrack": ["EventTarget", "MediaStreamTrack"], + "CanvasGradient": [], + "CanvasPattern": [], + "CanvasRenderingContext2d": [], + "CanvasWindingRule": [], + "CaretChangedReason": [], + "CaretPosition": [], + "CaretStateChangedEventInit": [], + "CdataSection": ["CharacterData", "EventTarget", "Node", "Text"], + "ChannelCountMode": [], + "ChannelInterpretation": [], + "ChannelMergerNode": ["AudioNode", "EventTarget"], + "ChannelMergerOptions": [], + "ChannelSplitterNode": ["AudioNode", "EventTarget"], + "ChannelSplitterOptions": [], + "CharacterData": ["EventTarget", "Node"], + "CheckerboardReason": [], + "CheckerboardReport": [], + "CheckerboardReportService": [], + "ChromeFilePropertyBag": [], + "ChromeWorker": ["EventTarget", "Worker"], + "Client": [], + "ClientQueryOptions": [], + "ClientRectsAndTexts": [], + "ClientType": [], + "Clients": [], + "Clipboard": ["EventTarget"], + "ClipboardEvent": ["Event"], + "ClipboardEventInit": [], + "ClipboardItem": [], + "ClipboardItemOptions": [], + "ClipboardPermissionDescriptor": [], + "ClipboardUnsanitizedFormats": [], + "CloseEvent": ["Event"], + "CloseEventInit": [], + "CodecState": [], + "CollectedClientData": [], + "ColorSpaceConversion": [], + "CommandEvent": ["Event"], + "CommandEventInit": [], + "Comment": ["CharacterData", "EventTarget", "Node"], + "CompositeOperation": [], + "CompositionEvent": ["Event", "UiEvent"], + "CompositionEventInit": [], + "CompressionFormat": [], + "CompressionStream": [], + "ComputedEffectTiming": [], + "ConnStatusDict": [], + "ConnectionType": [], + "ConsoleCounter": [], + "ConsoleCounterError": [], + "ConsoleEvent": [], + "ConsoleInstance": [], + "ConsoleInstanceOptions": [], + "ConsoleLevel": [], + "ConsoleLogLevel": [], + "ConsoleProfileEvent": [], + "ConsoleStackEntry": [], + "ConsoleTimerError": [], + "ConsoleTimerLogOrEnd": [], + "ConsoleTimerStart": [], + "ConstantSourceNode": ["AudioNode", "AudioScheduledSourceNode", "EventTarget"], + "ConstantSourceOptions": [], + "ConstrainBooleanParameters": [], + "ConstrainDomStringParameters": [], + "ConstrainDoubleRange": [], + "ConstrainLongRange": [], + "ContextAttributes2d": [], + "ConvertCoordinateOptions": [], + "ConvolverNode": ["AudioNode", "EventTarget"], + "ConvolverOptions": [], + "CookieChangeEvent": ["Event"], + "CookieChangeEventInit": [], + "CookieInit": [], + "CookieListItem": [], + "CookieSameSite": [], + "CookieStore": ["EventTarget"], + "CookieStoreDeleteOptions": [], + "CookieStoreGetOptions": [], + "CookieStoreManager": [], + "Coordinates": [], + "CountQueuingStrategy": [], + "Credential": [], + "CredentialCreationOptions": [], + "CredentialPropertiesOutput": [], + "CredentialRequestOptions": [], + "CredentialsContainer": [], + "Crypto": [], + "CryptoKey": [], + "CryptoKeyPair": [], + "CssAnimation": ["Animation", "EventTarget"], + "CssBoxType": [], + "CssConditionRule": ["CssGroupingRule", "CssRule"], + "CssCounterStyleRule": ["CssRule"], + "CssFontFaceRule": ["CssRule"], + "CssFontFeatureValuesRule": ["CssRule"], + "CssGroupingRule": ["CssRule"], + "CssImportRule": ["CssRule"], + "CssKeyframeRule": ["CssRule"], + "CssKeyframesRule": ["CssRule"], + "CssMediaRule": ["CssConditionRule", "CssGroupingRule", "CssRule"], + "CssNamespaceRule": ["CssRule"], + "CssPageRule": ["CssRule"], + "CssPseudoElement": [], + "CssRule": [], + "CssRuleList": [], + "CssStyleDeclaration": [], + "CssStyleRule": ["CssRule"], + "CssStyleSheet": ["StyleSheet"], + "CssStyleSheetParsingMode": [], + "CssSupportsRule": ["CssConditionRule", "CssGroupingRule", "CssRule"], + "CssTransition": ["Animation", "EventTarget"], + "CssViewTransitionRule": ["CssRule"], + "CustomElementRegistry": [], + "CustomEvent": ["Event"], + "CustomEventInit": [], + "DataTransfer": [], + "DataTransferItem": [], + "DataTransferItemList": [], + "DateTimeValue": [], + "DecoderDoctorNotification": [], + "DecoderDoctorNotificationType": [], + "DecompressionStream": [], + "DedicatedWorkerGlobalScope": ["EventTarget", "WorkerGlobalScope"], + "DelayNode": ["AudioNode", "EventTarget"], + "DelayOptions": [], + "DeviceAcceleration": [], + "DeviceAccelerationInit": [], + "DeviceLightEvent": ["Event"], + "DeviceLightEventInit": [], + "DeviceMotionEvent": ["Event"], + "DeviceMotionEventInit": [], + "DeviceOrientationEvent": ["Event"], + "DeviceOrientationEventInit": [], + "DeviceProximityEvent": ["Event"], + "DeviceProximityEventInit": [], + "DeviceRotationRate": [], + "DeviceRotationRateInit": [], + "DhKeyDeriveParams": [], + "DirectionSetting": [], + "Directory": [], + "DirectoryPickerOptions": [], + "DisplayMediaStreamConstraints": [], + "DisplayNameOptions": [], + "DisplayNameResult": [], + "DistanceModelType": [], + "DnsCacheDict": [], + "DnsCacheEntry": [], + "DnsLookupDict": [], + "Document": ["EventTarget", "Node"], + "DocumentFragment": ["EventTarget", "Node"], + "DocumentTimeline": ["AnimationTimeline"], + "DocumentTimelineOptions": [], + "DocumentType": ["EventTarget", "Node"], + "DomError": [], + "DomException": [], + "DomImplementation": [], + "DomMatrix": ["DomMatrixReadOnly"], + "DomMatrix2dInit": [], + "DomMatrixInit": [], + "DomMatrixReadOnly": [], + "DomParser": [], + "DomPoint": ["DomPointReadOnly"], + "DomPointInit": [], + "DomPointReadOnly": [], + "DomQuad": [], + "DomQuadInit": [], + "DomQuadJson": [], + "DomRect": ["DomRectReadOnly"], + "DomRectInit": [], + "DomRectList": [], + "DomRectReadOnly": [], + "DomRequest": ["EventTarget"], + "DomRequestReadyState": [], + "DomStringList": [], + "DomStringMap": [], + "DomTokenList": [], + "DomWindowResizeEventDetail": [], + "DoubleRange": [], + "DragEvent": ["Event", "MouseEvent", "UiEvent"], + "DragEventInit": [], + "DynamicsCompressorNode": ["AudioNode", "EventTarget"], + "DynamicsCompressorOptions": [], + "EcKeyAlgorithm": [], + "EcKeyGenParams": [], + "EcKeyImportParams": [], + "EcdhKeyDeriveParams": [], + "EcdsaParams": [], + "EffectTiming": [], + "Element": ["EventTarget", "Node"], + "ElementCreationOptions": [], + "ElementDefinitionOptions": [], + "EncodedAudioChunk": [], + "EncodedAudioChunkInit": [], + "EncodedAudioChunkMetadata": [], + "EncodedAudioChunkType": [], + "EncodedVideoChunk": [], + "EncodedVideoChunkInit": [], + "EncodedVideoChunkMetadata": [], + "EncodedVideoChunkType": [], + "EndingTypes": [], + "ErrorCallback": [], + "ErrorEvent": ["Event"], + "ErrorEventInit": [], + "Event": [], + "EventInit": [], + "EventListener": [], + "EventListenerOptions": [], + "EventModifierInit": [], + "EventSource": ["EventTarget"], + "EventSourceInit": [], + "EventTarget": [], + "Exception": [], + "ExtBlendMinmax": [], + "ExtColorBufferFloat": [], + "ExtColorBufferHalfFloat": [], + "ExtDisjointTimerQuery": [], + "ExtFragDepth": [], + "ExtPolygonOffsetClamp": [], + "ExtSRgb": [], + "ExtShaderTextureLod": [], + "ExtTextureFilterAnisotropic": [], + "ExtTextureNorm16": [], + "ExtendableCookieChangeEvent": ["Event", "ExtendableEvent"], + "ExtendableCookieChangeEventInit": [], + "ExtendableEvent": ["Event"], + "ExtendableEventInit": [], + "ExtendableMessageEvent": ["Event", "ExtendableEvent"], + "ExtendableMessageEventInit": [], + "External": [], + "FakePluginMimeEntry": [], + "FakePluginTagInit": [], + "FetchEvent": ["Event", "ExtendableEvent"], + "FetchEventInit": [], + "FetchObserver": ["EventTarget"], + "FetchReadableStreamReadDataArray": [], + "FetchReadableStreamReadDataDone": [], + "FetchState": [], + "File": ["Blob"], + "FileCallback": [], + "FileList": [], + "FilePickerAcceptType": [], + "FilePickerOptions": [], + "FilePropertyBag": [], + "FileReader": ["EventTarget"], + "FileReaderSync": [], + "FileSystem": [], + "FileSystemCreateWritableOptions": [], + "FileSystemDirectoryEntry": ["FileSystemEntry"], + "FileSystemDirectoryHandle": ["FileSystemHandle"], + "FileSystemDirectoryReader": [], + "FileSystemEntriesCallback": [], + "FileSystemEntry": [], + "FileSystemEntryCallback": [], + "FileSystemFileEntry": ["FileSystemEntry"], + "FileSystemFileHandle": ["FileSystemHandle"], + "FileSystemFlags": [], + "FileSystemGetDirectoryOptions": [], + "FileSystemGetFileOptions": [], + "FileSystemHandle": [], + "FileSystemHandleKind": [], + "FileSystemHandlePermissionDescriptor": [], + "FileSystemPermissionDescriptor": [], + "FileSystemPermissionMode": [], + "FileSystemReadWriteOptions": [], + "FileSystemRemoveOptions": [], + "FileSystemSyncAccessHandle": [], + "FileSystemSyncAccessHandleMode": [], + "FileSystemSyncAccessHandleOptions": [], + "FileSystemWritableFileStream": ["WritableStream"], + "FillLightMode": [], + "FillMode": [], + "FlashClassification": [], + "FlowControlType": [], + "FocusEvent": ["Event", "UiEvent"], + "FocusEventInit": [], + "FocusOptions": [], + "FontData": [], + "FontFace": [], + "FontFaceDescriptors": [], + "FontFaceLoadStatus": [], + "FontFaceSet": ["EventTarget"], + "FontFaceSetIterator": [], + "FontFaceSetIteratorResult": [], + "FontFaceSetLoadEvent": ["Event"], + "FontFaceSetLoadEventInit": [], + "FontFaceSetLoadStatus": [], + "FormData": [], + "FrameType": [], + "FuzzingFunctions": [], + "GainNode": ["AudioNode", "EventTarget"], + "GainOptions": [], + "Gamepad": [], + "GamepadButton": [], + "GamepadEffectParameters": [], + "GamepadEvent": ["Event"], + "GamepadEventInit": [], + "GamepadHand": [], + "GamepadHapticActuator": [], + "GamepadHapticActuatorType": [], + "GamepadHapticEffectType": [], + "GamepadHapticsResult": [], + "GamepadMappingType": [], + "GamepadPose": [], + "GamepadTouch": [], + "Geolocation": [], + "GeolocationCoordinates": [], + "GeolocationPosition": [], + "GeolocationPositionError": [], + "GestureEvent": ["Event", "UiEvent"], + "GetAnimationsOptions": [], + "GetRootNodeOptions": [], + "GetUserMediaRequest": [], + "Gpu": [], + "GpuAdapter": [], + "GpuAdapterInfo": [], + "GpuAddressMode": [], + "GpuAutoLayoutMode": [], + "GpuBindGroup": [], + "GpuBindGroupDescriptor": [], + "GpuBindGroupEntry": [], + "GpuBindGroupLayout": [], + "GpuBindGroupLayoutDescriptor": [], + "GpuBindGroupLayoutEntry": [], + "GpuBlendComponent": [], + "GpuBlendFactor": [], + "GpuBlendOperation": [], + "GpuBlendState": [], + "GpuBuffer": [], + "GpuBufferBinding": [], + "GpuBufferBindingLayout": [], + "GpuBufferBindingType": [], + "GpuBufferDescriptor": [], + "GpuBufferMapState": [], + "GpuCanvasAlphaMode": [], + "GpuCanvasConfiguration": [], + "GpuCanvasContext": [], + "GpuCanvasToneMapping": [], + "GpuCanvasToneMappingMode": [], + "GpuColorDict": [], + "GpuColorTargetState": [], + "GpuCommandBuffer": [], + "GpuCommandBufferDescriptor": [], + "GpuCommandEncoder": [], + "GpuCommandEncoderDescriptor": [], + "GpuCompareFunction": [], + "GpuCompilationInfo": [], + "GpuCompilationMessage": [], + "GpuCompilationMessageType": [], + "GpuComputePassDescriptor": [], + "GpuComputePassEncoder": [], + "GpuComputePassTimestampWrites": [], + "GpuComputePipeline": [], + "GpuComputePipelineDescriptor": [], + "GpuCopyExternalImageDestInfo": [], + "GpuCopyExternalImageSourceInfo": [], + "GpuCullMode": [], + "GpuDepthStencilState": [], + "GpuDevice": ["EventTarget"], + "GpuDeviceDescriptor": [], + "GpuDeviceLostInfo": [], + "GpuDeviceLostReason": [], + "GpuError": [], + "GpuErrorFilter": [], + "GpuExtent3dDict": [], + "GpuExternalTexture": [], + "GpuExternalTextureBindingLayout": [], + "GpuExternalTextureDescriptor": [], + "GpuFeatureName": [], + "GpuFilterMode": [], + "GpuFragmentState": [], + "GpuFrontFace": [], + "GpuIndexFormat": [], + "GpuInternalError": ["GpuError"], + "GpuLoadOp": [], + "GpuMipmapFilterMode": [], + "GpuMultisampleState": [], + "GpuObjectDescriptorBase": [], + "GpuOrigin2dDict": [], + "GpuOrigin3dDict": [], + "GpuOutOfMemoryError": ["GpuError"], + "GpuPipelineDescriptorBase": [], + "GpuPipelineError": ["DomException"], + "GpuPipelineErrorInit": [], + "GpuPipelineErrorReason": [], + "GpuPipelineLayout": [], + "GpuPipelineLayoutDescriptor": [], + "GpuPowerPreference": [], + "GpuPrimitiveState": [], + "GpuPrimitiveTopology": [], + "GpuProgrammableStage": [], + "GpuQuerySet": [], + "GpuQuerySetDescriptor": [], + "GpuQueryType": [], + "GpuQueue": [], + "GpuQueueDescriptor": [], + "GpuRenderBundle": [], + "GpuRenderBundleDescriptor": [], + "GpuRenderBundleEncoder": [], + "GpuRenderBundleEncoderDescriptor": [], + "GpuRenderPassColorAttachment": [], + "GpuRenderPassDepthStencilAttachment": [], + "GpuRenderPassDescriptor": [], + "GpuRenderPassEncoder": [], + "GpuRenderPassLayout": [], + "GpuRenderPassTimestampWrites": [], + "GpuRenderPipeline": [], + "GpuRenderPipelineDescriptor": [], + "GpuRequestAdapterOptions": [], + "GpuSampler": [], + "GpuSamplerBindingLayout": [], + "GpuSamplerBindingType": [], + "GpuSamplerDescriptor": [], + "GpuShaderModule": [], + "GpuShaderModuleCompilationHint": [], + "GpuShaderModuleDescriptor": [], + "GpuStencilFaceState": [], + "GpuStencilOperation": [], + "GpuStorageTextureAccess": [], + "GpuStorageTextureBindingLayout": [], + "GpuStoreOp": [], + "GpuSupportedFeatures": [], + "GpuSupportedLimits": [], + "GpuTexelCopyBufferInfo": [], + "GpuTexelCopyBufferLayout": [], + "GpuTexelCopyTextureInfo": [], + "GpuTexture": [], + "GpuTextureAspect": [], + "GpuTextureBindingLayout": [], + "GpuTextureDescriptor": [], + "GpuTextureDimension": [], + "GpuTextureFormat": [], + "GpuTextureSampleType": [], + "GpuTextureView": [], + "GpuTextureViewDescriptor": [], + "GpuTextureViewDimension": [], + "GpuUncapturedErrorEvent": ["Event"], + "GpuUncapturedErrorEventInit": [], + "GpuValidationError": ["GpuError"], + "GpuVertexAttribute": [], + "GpuVertexBufferLayout": [], + "GpuVertexFormat": [], + "GpuVertexState": [], + "GpuVertexStepMode": [], + "GroupedHistoryEventInit": [], + "HalfOpenInfoDict": [], + "HardwareAcceleration": [], + "HashChangeEvent": ["Event"], + "HashChangeEventInit": [], + "Headers": [], + "HeadersGuardEnum": [], + "Hid": ["EventTarget"], + "HidCollectionInfo": [], + "HidConnectionEvent": ["Event"], + "HidConnectionEventInit": [], + "HidDevice": ["EventTarget"], + "HidDeviceFilter": [], + "HidDeviceRequestOptions": [], + "HidInputReportEvent": ["Event"], + "HidInputReportEventInit": [], + "HidReportInfo": [], + "HidReportItem": [], + "HidUnitSystem": [], + "HiddenPluginEventInit": [], + "Highlight": [], + "HighlightHitResult": [], + "HighlightRegistry": [], + "HighlightType": [], + "HighlightsFromPointOptions": [], + "History": [], + "HitRegionOptions": [], + "HkdfParams": [], + "HmacDerivedKeyParams": [], + "HmacImportParams": [], + "HmacKeyAlgorithm": [], + "HmacKeyGenParams": [], + "HtmlAllCollection": [], + "HtmlAnchorElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlAreaElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlAudioElement": [ + "Element", + "EventTarget", + "HtmlElement", + "HtmlMediaElement", + "Node" + ], + "HtmlBaseElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlBodyElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlBrElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlButtonElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlCanvasElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlCollection": [], + "HtmlDListElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlDataElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlDataListElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlDetailsElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlDialogElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlDirectoryElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlDivElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlDocument": ["Document", "EventTarget", "Node"], + "HtmlElement": ["Element", "EventTarget", "Node"], + "HtmlEmbedElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlFieldSetElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlFontElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlFormControlsCollection": ["HtmlCollection"], + "HtmlFormElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlFrameElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlFrameSetElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlHeadElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlHeadingElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlHrElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlHtmlElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlIFrameElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlImageElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlInputElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlLabelElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlLegendElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlLiElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlLinkElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlMapElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlMediaElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlMenuElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlMenuItemElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlMetaElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlMeterElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlModElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlOListElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlObjectElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlOptGroupElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlOptionElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlOptionsCollection": ["HtmlCollection"], + "HtmlOutputElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlParagraphElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlParamElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlPictureElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlPreElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlProgressElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlQuoteElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlScriptElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlSelectElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlSlotElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlSourceElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlSpanElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlStyleElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlTableCaptionElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlTableCellElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlTableColElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlTableElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlTableRowElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlTableSectionElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlTemplateElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlTextAreaElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlTimeElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlTitleElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlTrackElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlUListElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlUnknownElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlVideoElement": [ + "Element", + "EventTarget", + "HtmlElement", + "HtmlMediaElement", + "Node" + ], + "HttpConnDict": [], + "HttpConnInfo": [], + "HttpConnectionElement": [], + "IdbCursor": [], + "IdbCursorDirection": [], + "IdbCursorWithValue": ["IdbCursor"], + "IdbDatabase": ["EventTarget"], + "IdbFactory": [], + "IdbFileHandle": ["EventTarget"], + "IdbFileMetadataParameters": [], + "IdbFileRequest": ["DomRequest", "EventTarget"], + "IdbIndex": [], + "IdbIndexParameters": [], + "IdbKeyRange": [], + "IdbLocaleAwareKeyRange": ["IdbKeyRange"], + "IdbMutableFile": ["EventTarget"], + "IdbObjectStore": [], + "IdbObjectStoreParameters": [], + "IdbOpenDbOptions": [], + "IdbOpenDbRequest": ["EventTarget", "IdbRequest"], + "IdbRequest": ["EventTarget"], + "IdbRequestReadyState": [], + "IdbTransaction": ["EventTarget"], + "IdbTransactionDurability": [], + "IdbTransactionMode": [], + "IdbTransactionOptions": [], + "IdbVersionChangeEvent": ["Event"], + "IdbVersionChangeEventInit": [], + "IdleDeadline": [], + "IdleRequestOptions": [], + "IirFilterNode": ["AudioNode", "EventTarget"], + "IirFilterOptions": [], + "ImageBitmap": [], + "ImageBitmapOptions": [], + "ImageBitmapRenderingContext": [], + "ImageCapture": [], + "ImageCaptureError": [], + "ImageCaptureErrorEvent": ["Event"], + "ImageCaptureErrorEventInit": [], + "ImageData": [], + "ImageDecodeOptions": [], + "ImageDecodeResult": [], + "ImageDecoder": [], + "ImageDecoderInit": [], + "ImageEncodeOptions": [], + "ImageOrientation": [], + "ImageTrack": [], + "ImageTrackList": [], + "InputDeviceInfo": ["MediaDeviceInfo"], + "InputEvent": ["Event", "UiEvent"], + "InputEventInit": [], + "IntersectionObserver": [], + "IntersectionObserverEntry": [], + "IntersectionObserverEntryInit": [], + "IntersectionObserverInit": [], + "IntlUtils": [], + "IsInputPendingOptions": [], + "IterableKeyAndValueResult": [], + "IterableKeyOrValueResult": [], + "IterationCompositeOperation": [], + "JsonWebKey": [], + "KeyAlgorithm": [], + "KeyEvent": [], + "KeyFrameRequestEvent": ["Event"], + "KeyIdsInitData": [], + "KeyboardEvent": ["Event", "UiEvent"], + "KeyboardEventInit": [], + "KeyframeAnimationOptions": [], + "KeyframeEffect": ["AnimationEffect"], + "KeyframeEffectOptions": [], + "L10nElement": [], + "L10nValue": [], + "LargeBlobSupport": [], + "LatencyMode": [], + "LifecycleCallbacks": [], + "LineAlignSetting": [], + "ListBoxObject": [], + "LocalMediaStream": ["EventTarget", "MediaStream"], + "LocaleInfo": [], + "Location": [], + "Lock": [], + "LockInfo": [], + "LockManager": [], + "LockManagerSnapshot": [], + "LockMode": [], + "LockOptions": [], + "MathMlElement": ["Element", "EventTarget", "Node"], + "MediaCapabilities": [], + "MediaCapabilitiesInfo": [], + "MediaConfiguration": [], + "MediaDecodingConfiguration": [], + "MediaDecodingType": [], + "MediaDeviceInfo": [], + "MediaDeviceKind": [], + "MediaDevices": ["EventTarget"], + "MediaElementAudioSourceNode": ["AudioNode", "EventTarget"], + "MediaElementAudioSourceOptions": [], + "MediaEncodingConfiguration": [], + "MediaEncodingType": [], + "MediaEncryptedEvent": ["Event"], + "MediaError": [], + "MediaImage": [], + "MediaKeyError": ["Event"], + "MediaKeyMessageEvent": ["Event"], + "MediaKeyMessageEventInit": [], + "MediaKeyMessageType": [], + "MediaKeyNeededEventInit": [], + "MediaKeySession": ["EventTarget"], + "MediaKeySessionType": [], + "MediaKeyStatus": [], + "MediaKeyStatusMap": [], + "MediaKeySystemAccess": [], + "MediaKeySystemConfiguration": [], + "MediaKeySystemMediaCapability": [], + "MediaKeySystemStatus": [], + "MediaKeys": [], + "MediaKeysPolicy": [], + "MediaKeysRequirement": [], + "MediaList": [], + "MediaMetadata": [], + "MediaMetadataInit": [], + "MediaPositionState": [], + "MediaQueryList": ["EventTarget"], + "MediaQueryListEvent": ["Event"], + "MediaQueryListEventInit": [], + "MediaRecorder": ["EventTarget"], + "MediaRecorderErrorEvent": ["Event"], + "MediaRecorderErrorEventInit": [], + "MediaRecorderOptions": [], + "MediaSession": [], + "MediaSessionAction": [], + "MediaSessionActionDetails": [], + "MediaSessionPlaybackState": [], + "MediaSettingsRange": [], + "MediaSource": ["EventTarget"], + "MediaSourceEndOfStreamError": [], + "MediaSourceEnum": [], + "MediaSourceReadyState": [], + "MediaStream": ["EventTarget"], + "MediaStreamAudioDestinationNode": ["AudioNode", "EventTarget"], + "MediaStreamAudioSourceNode": ["AudioNode", "EventTarget"], + "MediaStreamAudioSourceOptions": [], + "MediaStreamConstraints": [], + "MediaStreamError": [], + "MediaStreamEvent": ["Event"], + "MediaStreamEventInit": [], + "MediaStreamTrack": ["EventTarget"], + "MediaStreamTrackEvent": ["Event"], + "MediaStreamTrackEventInit": [], + "MediaStreamTrackGenerator": ["EventTarget", "MediaStreamTrack"], + "MediaStreamTrackGeneratorInit": [], + "MediaStreamTrackProcessor": [], + "MediaStreamTrackProcessorInit": [], + "MediaStreamTrackState": [], + "MediaTrackCapabilities": [], + "MediaTrackConstraintSet": [], + "MediaTrackConstraints": [], + "MediaTrackSettings": [], + "MediaTrackSupportedConstraints": [], + "MemoryAttribution": [], + "MemoryAttributionContainer": [], + "MemoryBreakdownEntry": [], + "MemoryMeasurement": [], + "MessageChannel": [], + "MessageEvent": ["Event"], + "MessageEventInit": [], + "MessagePort": ["EventTarget"], + "MeteringMode": [], + "MidiAccess": ["EventTarget"], + "MidiConnectionEvent": ["Event"], + "MidiConnectionEventInit": [], + "MidiInput": ["EventTarget", "MidiPort"], + "MidiInputMap": [], + "MidiMessageEvent": ["Event"], + "MidiMessageEventInit": [], + "MidiOptions": [], + "MidiOutput": ["EventTarget", "MidiPort"], + "MidiOutputMap": [], + "MidiPort": ["EventTarget"], + "MidiPortConnectionState": [], + "MidiPortDeviceState": [], + "MidiPortType": [], + "MimeType": [], + "MimeTypeArray": [], + "MouseEvent": ["Event", "UiEvent"], + "MouseEventInit": [], + "MouseScrollEvent": ["Event", "MouseEvent", "UiEvent"], + "MozDebug": [], + "MutationEvent": ["Event"], + "MutationObserver": [], + "MutationObserverInit": [], + "MutationObservingInfo": [], + "MutationRecord": [], + "NamedNodeMap": [], + "NativeOsFileReadOptions": [], + "NativeOsFileWriteAtomicOptions": [], + "NavigateEvent": ["Event"], + "NavigateEventInit": [], + "Navigation": ["EventTarget"], + "NavigationActivation": [], + "NavigationApiType": [], + "NavigationCurrentEntryChangeEvent": ["Event"], + "NavigationCurrentEntryChangeEventInit": [], + "NavigationDestination": [], + "NavigationFocusReset": [], + "NavigationHistoryBehavior": [], + "NavigationHistoryEntry": ["EventTarget"], + "NavigationInterceptOptions": [], + "NavigationNavigateOptions": [], + "NavigationOptions": [], + "NavigationReloadOptions": [], + "NavigationResult": [], + "NavigationScrollBehavior": [], + "NavigationTransition": [], + "NavigationType": [], + "NavigationUpdateCurrentEntryOptions": [], + "Navigator": [], + "NavigatorAutomationInformation": [], + "NavigatorUaBrandVersion": [], + "NavigatorUaData": [], + "NetworkCommandOptions": [], + "NetworkInformation": ["EventTarget"], + "NetworkResultOptions": [], + "Node": ["EventTarget"], + "NodeFilter": [], + "NodeIterator": [], + "NodeList": [], + "Notification": ["EventTarget"], + "NotificationAction": [], + "NotificationDirection": [], + "NotificationEvent": ["Event", "ExtendableEvent"], + "NotificationEventInit": [], + "NotificationOptions": [], + "NotificationPermission": [], + "ObserverCallback": [], + "OesElementIndexUint": [], + "OesStandardDerivatives": [], + "OesTextureFloat": [], + "OesTextureFloatLinear": [], + "OesTextureHalfFloat": [], + "OesTextureHalfFloatLinear": [], + "OesVertexArrayObject": [], + "OfflineAudioCompletionEvent": ["Event"], + "OfflineAudioCompletionEventInit": [], + "OfflineAudioContext": ["BaseAudioContext", "EventTarget"], + "OfflineAudioContextOptions": [], + "OfflineResourceList": ["EventTarget"], + "OffscreenCanvas": ["EventTarget"], + "OffscreenCanvasRenderingContext2d": [], + "OpenFilePickerOptions": [], + "OpenWindowEventDetail": [], + "OptionalEffectTiming": [], + "OrientationLockType": [], + "OrientationType": [], + "OscillatorNode": ["AudioNode", "AudioScheduledSourceNode", "EventTarget"], + "OscillatorOptions": [], + "OscillatorType": [], + "OverSampleType": [], + "OvrMultiview2": [], + "PageTransitionEvent": ["Event"], + "PageTransitionEventInit": [], + "PaintRequest": [], + "PaintRequestList": [], + "PaintWorkletGlobalScope": ["WorkletGlobalScope"], + "PannerNode": ["AudioNode", "EventTarget"], + "PannerOptions": [], + "PanningModelType": [], + "ParityType": [], + "Path2d": [], + "PaymentAddress": [], + "PaymentComplete": [], + "PaymentMethodChangeEvent": ["Event", "PaymentRequestUpdateEvent"], + "PaymentMethodChangeEventInit": [], + "PaymentRequestUpdateEvent": ["Event"], + "PaymentRequestUpdateEventInit": [], + "PaymentResponse": [], + "Pbkdf2Params": [], + "PcImplIceConnectionState": [], + "PcImplIceGatheringState": [], + "PcImplSignalingState": [], + "PcObserverStateType": [], + "Performance": ["EventTarget"], + "PerformanceEntry": [], + "PerformanceEntryEventInit": [], + "PerformanceEntryFilterOptions": [], + "PerformanceMark": ["PerformanceEntry"], + "PerformanceMarkOptions": [], + "PerformanceMeasure": ["PerformanceEntry"], + "PerformanceMeasureOptions": [], + "PerformanceNavigation": [], + "PerformanceNavigationTiming": ["PerformanceEntry", "PerformanceResourceTiming"], + "PerformanceObserver": [], + "PerformanceObserverEntryList": [], + "PerformanceObserverInit": [], + "PerformanceResourceTiming": ["PerformanceEntry"], + "PerformanceServerTiming": [], + "PerformanceTiming": [], + "PeriodicWave": [], + "PeriodicWaveConstraints": [], + "PeriodicWaveOptions": [], + "PermissionDescriptor": [], + "PermissionName": [], + "PermissionState": [], + "PermissionStatus": ["EventTarget"], + "Permissions": [], + "PhotoCapabilities": [], + "PhotoSettings": [], + "PictureInPictureEvent": ["Event"], + "PictureInPictureEventInit": [], + "PictureInPictureWindow": ["EventTarget"], + "PlaneLayout": [], + "PlaybackDirection": [], + "Plugin": [], + "PluginArray": [], + "PluginCrashedEventInit": [], + "Point2d": [], + "PointerEvent": ["Event", "MouseEvent", "UiEvent"], + "PointerEventInit": [], + "PopStateEvent": ["Event"], + "PopStateEventInit": [], + "PopupBlockedEvent": ["Event"], + "PopupBlockedEventInit": [], + "Position": [], + "PositionAlignSetting": [], + "PositionError": [], + "PositionOptions": [], + "PremultiplyAlpha": [], + "Presentation": [], + "PresentationAvailability": ["EventTarget"], + "PresentationConnection": ["EventTarget"], + "PresentationConnectionAvailableEvent": ["Event"], + "PresentationConnectionAvailableEventInit": [], + "PresentationConnectionBinaryType": [], + "PresentationConnectionCloseEvent": ["Event"], + "PresentationConnectionCloseEventInit": [], + "PresentationConnectionClosedReason": [], + "PresentationConnectionList": ["EventTarget"], + "PresentationConnectionState": [], + "PresentationReceiver": [], + "PresentationRequest": ["EventTarget"], + "PresentationStyle": [], + "ProcessingInstruction": ["CharacterData", "EventTarget", "Node"], + "ProfileTimelineLayerRect": [], + "ProfileTimelineMarker": [], + "ProfileTimelineMessagePortOperationType": [], + "ProfileTimelineStackFrame": [], + "ProfileTimelineWorkerOperationType": [], + "ProgressEvent": ["Event"], + "ProgressEventInit": [], + "PromiseNativeHandler": [], + "PromiseRejectionEvent": ["Event"], + "PromiseRejectionEventInit": [], + "PublicKeyCredential": ["Credential"], + "PublicKeyCredentialCreationOptions": [], + "PublicKeyCredentialCreationOptionsJson": [], + "PublicKeyCredentialDescriptor": [], + "PublicKeyCredentialDescriptorJson": [], + "PublicKeyCredentialEntity": [], + "PublicKeyCredentialHints": [], + "PublicKeyCredentialParameters": [], + "PublicKeyCredentialRequestOptions": [], + "PublicKeyCredentialRequestOptionsJson": [], + "PublicKeyCredentialRpEntity": [], + "PublicKeyCredentialType": [], + "PublicKeyCredentialUserEntity": [], + "PublicKeyCredentialUserEntityJson": [], + "PushEncryptionKeyName": [], + "PushEvent": ["Event", "ExtendableEvent"], + "PushEventInit": [], + "PushManager": [], + "PushMessageData": [], + "PushPermissionState": [], + "PushSubscription": [], + "PushSubscriptionInit": [], + "PushSubscriptionJson": [], + "PushSubscriptionKeys": [], + "PushSubscriptionOptions": [], + "PushSubscriptionOptionsInit": [], + "QueryOptions": [], + "QueuingStrategy": [], + "QueuingStrategyInit": [], + "RadioNodeList": ["NodeList"], + "Range": ["AbstractRange"], + "RcwnPerfStats": [], + "RcwnStatus": [], + "ReadableByteStreamController": [], + "ReadableStream": [], + "ReadableStreamByobReader": [], + "ReadableStreamByobRequest": [], + "ReadableStreamDefaultController": [], + "ReadableStreamDefaultReader": [], + "ReadableStreamGetReaderOptions": [], + "ReadableStreamIteratorOptions": [], + "ReadableStreamReadResult": [], + "ReadableStreamReaderMode": [], + "ReadableStreamType": [], + "ReadableWritablePair": [], + "RecordingState": [], + "RedEyeReduction": [], + "ReferrerPolicy": [], + "RegisterRequest": [], + "RegisterResponse": [], + "RegisteredKey": [], + "RegistrationOptions": [], + "RegistrationResponseJson": [], + "Request": [], + "RequestCache": [], + "RequestCredentials": [], + "RequestDestination": [], + "RequestDeviceOptions": [], + "RequestInit": [], + "RequestMediaKeySystemAccessNotification": [], + "RequestMode": [], + "RequestRedirect": [], + "ResidentKeyRequirement": [], + "ResizeObserver": [], + "ResizeObserverBoxOptions": [], + "ResizeObserverEntry": [], + "ResizeObserverOptions": [], + "ResizeObserverSize": [], + "ResizeQuality": [], + "Response": [], + "ResponseInit": [], + "ResponseType": [], + "RsaHashedImportParams": [], + "RsaOaepParams": [], + "RsaOtherPrimesInfo": [], + "RsaPssParams": [], + "RtcAnswerOptions": [], + "RtcBundlePolicy": [], + "RtcCertificate": [], + "RtcCertificateExpiration": [], + "RtcCodecStats": [], + "RtcConfiguration": [], + "RtcDataChannel": ["EventTarget"], + "RtcDataChannelEvent": ["Event"], + "RtcDataChannelEventInit": [], + "RtcDataChannelInit": [], + "RtcDataChannelState": [], + "RtcDataChannelType": [], + "RtcDegradationPreference": [], + "RtcEncodedAudioFrame": [], + "RtcEncodedAudioFrameMetadata": [], + "RtcEncodedAudioFrameOptions": [], + "RtcEncodedVideoFrame": [], + "RtcEncodedVideoFrameMetadata": [], + "RtcEncodedVideoFrameOptions": [], + "RtcEncodedVideoFrameType": [], + "RtcFecParameters": [], + "RtcIceCandidate": [], + "RtcIceCandidateInit": [], + "RtcIceCandidatePairStats": [], + "RtcIceCandidateStats": [], + "RtcIceComponentStats": [], + "RtcIceConnectionState": [], + "RtcIceCredentialType": [], + "RtcIceGatheringState": [], + "RtcIceServer": [], + "RtcIceTransportPolicy": [], + "RtcIdentityAssertion": [], + "RtcIdentityAssertionResult": [], + "RtcIdentityProvider": [], + "RtcIdentityProviderDetails": [], + "RtcIdentityProviderOptions": [], + "RtcIdentityProviderRegistrar": [], + "RtcIdentityValidationResult": [], + "RtcInboundRtpStreamStats": [], + "RtcMediaStreamStats": [], + "RtcMediaStreamTrackStats": [], + "RtcOfferAnswerOptions": [], + "RtcOfferOptions": [], + "RtcOutboundRtpStreamStats": [], + "RtcPeerConnection": ["EventTarget"], + "RtcPeerConnectionIceErrorEvent": ["Event"], + "RtcPeerConnectionIceEvent": ["Event"], + "RtcPeerConnectionIceEventInit": [], + "RtcPeerConnectionState": [], + "RtcPriorityType": [], + "RtcRtcpParameters": [], + "RtcRtpCapabilities": [], + "RtcRtpCodecCapability": [], + "RtcRtpCodecParameters": [], + "RtcRtpContributingSource": [], + "RtcRtpEncodingParameters": [], + "RtcRtpHeaderExtensionCapability": [], + "RtcRtpHeaderExtensionParameters": [], + "RtcRtpParameters": [], + "RtcRtpReceiver": [], + "RtcRtpScriptTransform": [], + "RtcRtpScriptTransformer": ["EventTarget"], + "RtcRtpSender": [], + "RtcRtpSourceEntry": [], + "RtcRtpSourceEntryType": [], + "RtcRtpSynchronizationSource": [], + "RtcRtpTransceiver": [], + "RtcRtpTransceiverDirection": [], + "RtcRtpTransceiverInit": [], + "RtcRtxParameters": [], + "RtcSdpType": [], + "RtcSessionDescription": [], + "RtcSessionDescriptionInit": [], + "RtcSignalingState": [], + "RtcStats": [], + "RtcStatsIceCandidatePairState": [], + "RtcStatsIceCandidateType": [], + "RtcStatsReport": [], + "RtcStatsReportInternal": [], + "RtcStatsType": [], + "RtcTrackEvent": ["Event"], + "RtcTrackEventInit": [], + "RtcTransformEvent": ["Event"], + "RtcTransportStats": [], + "RtcdtmfSender": ["EventTarget"], + "RtcdtmfToneChangeEvent": ["Event"], + "RtcdtmfToneChangeEventInit": [], + "RtcrtpContributingSourceStats": [], + "RtcrtpStreamStats": [], + "SFrameTransform": ["EventTarget"], + "SFrameTransformErrorEvent": ["Event"], + "SFrameTransformErrorEventInit": [], + "SFrameTransformErrorEventType": [], + "SFrameTransformOptions": [], + "SFrameTransformRole": [], + "SaveFilePickerOptions": [], + "Scheduler": [], + "SchedulerPostTaskOptions": [], + "Scheduling": [], + "Screen": ["EventTarget"], + "ScreenColorGamut": [], + "ScreenDetailed": ["EventTarget", "Screen"], + "ScreenDetails": ["EventTarget"], + "ScreenLuminance": [], + "ScreenOrientation": ["EventTarget"], + "ScriptProcessorNode": ["AudioNode", "EventTarget"], + "ScrollAreaEvent": ["Event", "UiEvent"], + "ScrollBehavior": [], + "ScrollBoxObject": [], + "ScrollIntoViewContainer": [], + "ScrollIntoViewOptions": [], + "ScrollLogicalPosition": [], + "ScrollOptions": [], + "ScrollRestoration": [], + "ScrollSetting": [], + "ScrollState": [], + "ScrollToOptions": [], + "ScrollViewChangeEventInit": [], + "SecurityPolicyViolationEvent": ["Event"], + "SecurityPolicyViolationEventDisposition": [], + "SecurityPolicyViolationEventInit": [], + "Selection": [], + "SelectionMode": [], + "Serial": ["EventTarget"], + "SerialInputSignals": [], + "SerialOptions": [], + "SerialOutputSignals": [], + "SerialPort": ["EventTarget"], + "SerialPortFilter": [], + "SerialPortInfo": [], + "SerialPortRequestOptions": [], + "ServerSocketOptions": [], + "ServiceWorker": ["EventTarget"], + "ServiceWorkerContainer": ["EventTarget"], + "ServiceWorkerGlobalScope": ["EventTarget", "WorkerGlobalScope"], + "ServiceWorkerRegistration": ["EventTarget"], + "ServiceWorkerState": [], + "ServiceWorkerUpdateViaCache": [], + "ShadowRoot": ["DocumentFragment", "EventTarget", "Node"], + "ShadowRootInit": [], + "ShadowRootMode": [], + "ShareData": [], + "SharedWorker": ["EventTarget"], + "SharedWorkerGlobalScope": ["EventTarget", "WorkerGlobalScope"], + "ShowPopoverOptions": [], + "SignResponse": [], + "SocketElement": [], + "SocketOptions": [], + "SocketReadyState": [], + "SocketsDict": [], + "SourceBuffer": ["EventTarget"], + "SourceBufferAppendMode": [], + "SourceBufferList": ["EventTarget"], + "SpeechGrammar": [], + "SpeechGrammarList": [], + "SpeechRecognition": ["EventTarget"], + "SpeechRecognitionAlternative": [], + "SpeechRecognitionError": ["Event"], + "SpeechRecognitionErrorCode": [], + "SpeechRecognitionErrorInit": [], + "SpeechRecognitionEvent": ["Event"], + "SpeechRecognitionEventInit": [], + "SpeechRecognitionResult": [], + "SpeechRecognitionResultList": [], + "SpeechSynthesis": ["EventTarget"], + "SpeechSynthesisErrorCode": [], + "SpeechSynthesisErrorEvent": ["Event", "SpeechSynthesisEvent"], + "SpeechSynthesisErrorEventInit": [], + "SpeechSynthesisEvent": ["Event"], + "SpeechSynthesisEventInit": [], + "SpeechSynthesisUtterance": ["EventTarget"], + "SpeechSynthesisVoice": [], + "StartViewTransitionOptions": [], + "StaticRange": ["AbstractRange"], + "StaticRangeInit": [], + "StereoPannerNode": ["AudioNode", "EventTarget"], + "StereoPannerOptions": [], + "Storage": [], + "StorageEstimate": [], + "StorageEvent": ["Event"], + "StorageEventInit": [], + "StorageManager": [], + "StorageType": [], + "StreamPipeOptions": [], + "StyleRuleChangeEventInit": [], + "StyleSheet": [], + "StyleSheetApplicableStateChangeEventInit": [], + "StyleSheetChangeEventInit": [], + "StyleSheetList": [], + "SubmitEvent": ["Event"], + "SubmitEventInit": [], + "SubtleCrypto": [], + "SupportedType": [], + "SvcOutputMetadata": [], + "SvgAngle": [], + "SvgAnimateElement": [ + "Element", + "EventTarget", + "Node", + "SvgAnimationElement", + "SvgElement" + ], + "SvgAnimateMotionElement": [ + "Element", + "EventTarget", + "Node", + "SvgAnimationElement", + "SvgElement" + ], + "SvgAnimateTransformElement": [ + "Element", + "EventTarget", + "Node", + "SvgAnimationElement", + "SvgElement" + ], + "SvgAnimatedAngle": [], + "SvgAnimatedBoolean": [], + "SvgAnimatedEnumeration": [], + "SvgAnimatedInteger": [], + "SvgAnimatedLength": [], + "SvgAnimatedLengthList": [], + "SvgAnimatedNumber": [], + "SvgAnimatedNumberList": [], + "SvgAnimatedPreserveAspectRatio": [], + "SvgAnimatedRect": [], + "SvgAnimatedString": [], + "SvgAnimatedTransformList": [], + "SvgAnimationElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgBoundingBoxOptions": [], + "SvgCircleElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGeometryElement", + "SvgGraphicsElement" + ], + "SvgClipPathElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgComponentTransferFunctionElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgDefsElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGraphicsElement" + ], + "SvgDescElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgElement": ["Element", "EventTarget", "Node"], + "SvgEllipseElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGeometryElement", + "SvgGraphicsElement" + ], + "SvgFilterElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgForeignObjectElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGraphicsElement" + ], + "SvgGeometryElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGraphicsElement" + ], + "SvgGradientElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgGraphicsElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgImageElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGraphicsElement" + ], + "SvgLength": [], + "SvgLengthList": [], + "SvgLineElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGeometryElement", + "SvgGraphicsElement" + ], + "SvgLinearGradientElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGradientElement" + ], + "SvgMarkerElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgMaskElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgMatrix": [], + "SvgMetadataElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgNumber": [], + "SvgNumberList": [], + "SvgPathElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGeometryElement", + "SvgGraphicsElement" + ], + "SvgPathSeg": [], + "SvgPathSegArcAbs": ["SvgPathSeg"], + "SvgPathSegArcRel": ["SvgPathSeg"], + "SvgPathSegClosePath": ["SvgPathSeg"], + "SvgPathSegCurvetoCubicAbs": ["SvgPathSeg"], + "SvgPathSegCurvetoCubicRel": ["SvgPathSeg"], + "SvgPathSegCurvetoCubicSmoothAbs": ["SvgPathSeg"], + "SvgPathSegCurvetoCubicSmoothRel": ["SvgPathSeg"], + "SvgPathSegCurvetoQuadraticAbs": ["SvgPathSeg"], + "SvgPathSegCurvetoQuadraticRel": ["SvgPathSeg"], + "SvgPathSegCurvetoQuadraticSmoothAbs": ["SvgPathSeg"], + "SvgPathSegCurvetoQuadraticSmoothRel": ["SvgPathSeg"], + "SvgPathSegLinetoAbs": ["SvgPathSeg"], + "SvgPathSegLinetoHorizontalAbs": ["SvgPathSeg"], + "SvgPathSegLinetoHorizontalRel": ["SvgPathSeg"], + "SvgPathSegLinetoRel": ["SvgPathSeg"], + "SvgPathSegLinetoVerticalAbs": ["SvgPathSeg"], + "SvgPathSegLinetoVerticalRel": ["SvgPathSeg"], + "SvgPathSegList": [], + "SvgPathSegMovetoAbs": ["SvgPathSeg"], + "SvgPathSegMovetoRel": ["SvgPathSeg"], + "SvgPatternElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgPoint": [], + "SvgPointList": [], + "SvgPolygonElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGeometryElement", + "SvgGraphicsElement" + ], + "SvgPolylineElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGeometryElement", + "SvgGraphicsElement" + ], + "SvgPreserveAspectRatio": [], + "SvgRadialGradientElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGradientElement" + ], + "SvgRect": [], + "SvgRectElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGeometryElement", + "SvgGraphicsElement" + ], + "SvgScriptElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgSetElement": [ + "Element", + "EventTarget", + "Node", + "SvgAnimationElement", + "SvgElement" + ], + "SvgStopElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgStringList": [], + "SvgStyleElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgSwitchElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGraphicsElement" + ], + "SvgSymbolElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgTextContentElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGraphicsElement" + ], + "SvgTextElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGraphicsElement", + "SvgTextContentElement", + "SvgTextPositioningElement" + ], + "SvgTextPathElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGraphicsElement", + "SvgTextContentElement" + ], + "SvgTextPositioningElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGraphicsElement", + "SvgTextContentElement" + ], + "SvgTitleElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgTransform": [], + "SvgTransformList": [], + "SvgUnitTypes": [], + "SvgUseElement": ["Element", "EventTarget", "Node", "SvgElement", "SvgGraphicsElement"], + "SvgViewElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgZoomAndPan": [], + "SvgaElement": ["Element", "EventTarget", "Node", "SvgElement", "SvgGraphicsElement"], + "SvgfeBlendElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeColorMatrixElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeComponentTransferElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeCompositeElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeConvolveMatrixElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeDiffuseLightingElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeDisplacementMapElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeDistantLightElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeDropShadowElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeFloodElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeFuncAElement": [ + "Element", + "EventTarget", + "Node", + "SvgComponentTransferFunctionElement", + "SvgElement" + ], + "SvgfeFuncBElement": [ + "Element", + "EventTarget", + "Node", + "SvgComponentTransferFunctionElement", + "SvgElement" + ], + "SvgfeFuncGElement": [ + "Element", + "EventTarget", + "Node", + "SvgComponentTransferFunctionElement", + "SvgElement" + ], + "SvgfeFuncRElement": [ + "Element", + "EventTarget", + "Node", + "SvgComponentTransferFunctionElement", + "SvgElement" + ], + "SvgfeGaussianBlurElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeImageElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeMergeElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeMergeNodeElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeMorphologyElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeOffsetElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfePointLightElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeSpecularLightingElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeSpotLightElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeTileElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeTurbulenceElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvggElement": ["Element", "EventTarget", "Node", "SvgElement", "SvgGraphicsElement"], + "SvgmPathElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgsvgElement": ["Element", "EventTarget", "Node", "SvgElement", "SvgGraphicsElement"], + "SvgtSpanElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGraphicsElement", + "SvgTextContentElement", + "SvgTextPositioningElement" + ], + "TaskController": ["AbortController"], + "TaskControllerInit": [], + "TaskPriority": [], + "TaskPriorityChangeEvent": ["Event"], + "TaskPriorityChangeEventInit": [], + "TaskSignal": ["AbortSignal", "EventTarget"], + "TaskSignalAnyInit": [], + "TcpReadyState": [], + "TcpServerSocket": ["EventTarget"], + "TcpServerSocketEvent": ["Event"], + "TcpServerSocketEventInit": [], + "TcpSocket": ["EventTarget"], + "TcpSocketBinaryType": [], + "TcpSocketErrorEvent": ["Event"], + "TcpSocketErrorEventInit": [], + "TcpSocketEvent": ["Event"], + "TcpSocketEventInit": [], + "Text": ["CharacterData", "EventTarget", "Node"], + "TextDecodeOptions": [], + "TextDecoder": [], + "TextDecoderOptions": [], + "TextEncoder": [], + "TextMetrics": [], + "TextTrack": ["EventTarget"], + "TextTrackCue": ["EventTarget"], + "TextTrackCueList": [], + "TextTrackKind": [], + "TextTrackList": ["EventTarget"], + "TextTrackMode": [], + "TimeEvent": ["Event"], + "TimeRanges": [], + "ToggleEvent": ["Event"], + "ToggleEventInit": [], + "TogglePopoverOptions": [], + "TokenBinding": [], + "TokenBindingStatus": [], + "Touch": [], + "TouchEvent": ["Event", "UiEvent"], + "TouchEventInit": [], + "TouchInit": [], + "TouchList": [], + "TrackEvent": ["Event"], + "TrackEventInit": [], + "TransformStream": [], + "TransformStreamDefaultController": [], + "Transformer": [], + "TransitionEvent": ["Event"], + "TransitionEventInit": [], + "Transport": [], + "TreeBoxObject": [], + "TreeCellInfo": [], + "TreeView": [], + "TreeWalker": [], + "U2f": [], + "U2fClientData": [], + "ULongRange": [], + "UaDataValues": [], + "UaLowEntropyJson": [], + "UdpMessageEventInit": [], + "UdpOptions": [], + "UiEvent": ["Event"], + "UiEventInit": [], + "UnderlyingSink": [], + "UnderlyingSource": [], + "Url": [], + "UrlSearchParams": [], + "Usb": ["EventTarget"], + "UsbAlternateInterface": [], + "UsbConfiguration": [], + "UsbConnectionEvent": ["Event"], + "UsbConnectionEventInit": [], + "UsbControlTransferParameters": [], + "UsbDevice": [], + "UsbDeviceFilter": [], + "UsbDeviceRequestOptions": [], + "UsbDirection": [], + "UsbEndpoint": [], + "UsbEndpointType": [], + "UsbInTransferResult": [], + "UsbInterface": [], + "UsbIsochronousInTransferPacket": [], + "UsbIsochronousInTransferResult": [], + "UsbIsochronousOutTransferPacket": [], + "UsbIsochronousOutTransferResult": [], + "UsbOutTransferResult": [], + "UsbPermissionDescriptor": [], + "UsbPermissionResult": ["EventTarget", "PermissionStatus"], + "UsbPermissionStorage": [], + "UsbRecipient": [], + "UsbRequestType": [], + "UsbTransferStatus": [], + "UserActivation": [], + "UserProximityEvent": ["Event"], + "UserProximityEventInit": [], + "UserVerificationRequirement": [], + "ValidityState": [], + "ValueEvent": ["Event"], + "ValueEventInit": [], + "VideoColorPrimaries": [], + "VideoColorSpace": [], + "VideoColorSpaceInit": [], + "VideoConfiguration": [], + "VideoDecoder": ["EventTarget"], + "VideoDecoderConfig": [], + "VideoDecoderInit": [], + "VideoDecoderSupport": [], + "VideoEncoder": ["EventTarget"], + "VideoEncoderBitrateMode": [], + "VideoEncoderConfig": [], + "VideoEncoderEncodeOptions": [], + "VideoEncoderInit": [], + "VideoEncoderSupport": [], + "VideoFacingModeEnum": [], + "VideoFrame": [], + "VideoFrameBufferInit": [], + "VideoFrameCopyToOptions": [], + "VideoFrameInit": [], + "VideoFrameMetadata": [], + "VideoMatrixCoefficients": [], + "VideoPixelFormat": [], + "VideoPlaybackQuality": [], + "VideoStreamTrack": ["EventTarget", "MediaStreamTrack"], + "VideoTrack": [], + "VideoTrackList": ["EventTarget"], + "VideoTransferCharacteristics": [], + "ViewTransition": [], + "ViewTransitionTypeSet": [], + "VisibilityState": [], + "VisualViewport": ["EventTarget"], + "VoidCallback": [], + "VrDisplay": ["EventTarget"], + "VrDisplayCapabilities": [], + "VrEye": [], + "VrEyeParameters": [], + "VrFieldOfView": [], + "VrFrameData": [], + "VrLayer": [], + "VrMockController": [], + "VrMockDisplay": [], + "VrPose": [], + "VrServiceTest": [], + "VrStageParameters": [], + "VrSubmitFrameResult": [], + "VttCue": ["EventTarget", "TextTrackCue"], + "VttRegion": [], + "WakeLock": [], + "WakeLockSentinel": ["EventTarget"], + "WakeLockType": [], + "WatchAdvertisementsOptions": [], + "WaveShaperNode": ["AudioNode", "EventTarget"], + "WaveShaperOptions": [], + "WebGl2RenderingContext": [], + "WebGlActiveInfo": [], + "WebGlBuffer": [], + "WebGlContextAttributes": [], + "WebGlContextEvent": ["Event"], + "WebGlContextEventInit": [], + "WebGlFramebuffer": [], + "WebGlPowerPreference": [], + "WebGlProgram": [], + "WebGlQuery": [], + "WebGlRenderbuffer": [], + "WebGlRenderingContext": [], + "WebGlSampler": [], + "WebGlShader": [], + "WebGlShaderPrecisionFormat": [], + "WebGlSync": [], + "WebGlTexture": [], + "WebGlTransformFeedback": [], + "WebGlUniformLocation": [], + "WebGlVertexArrayObject": [], + "WebKitCssMatrix": ["DomMatrix", "DomMatrixReadOnly"], + "WebSocket": ["EventTarget"], + "WebSocketDict": [], + "WebSocketElement": [], + "WebTransport": [], + "WebTransportBidirectionalStream": [], + "WebTransportCloseInfo": [], + "WebTransportCongestionControl": [], + "WebTransportDatagramDuplexStream": [], + "WebTransportDatagramStats": [], + "WebTransportError": ["DomException"], + "WebTransportErrorOptions": [], + "WebTransportErrorSource": [], + "WebTransportHash": [], + "WebTransportOptions": [], + "WebTransportReceiveStream": ["ReadableStream"], + "WebTransportReceiveStreamStats": [], + "WebTransportReliabilityMode": [], + "WebTransportSendStream": ["WritableStream"], + "WebTransportSendStreamOptions": [], + "WebTransportSendStreamStats": [], + "WebTransportStats": [], + "WebglColorBufferFloat": [], + "WebglCompressedTextureAstc": [], + "WebglCompressedTextureAtc": [], + "WebglCompressedTextureEtc": [], + "WebglCompressedTextureEtc1": [], + "WebglCompressedTexturePvrtc": [], + "WebglCompressedTextureS3tc": [], + "WebglCompressedTextureS3tcSrgb": [], + "WebglDebugRendererInfo": [], + "WebglDebugShaders": [], + "WebglDepthTexture": [], + "WebglDrawBuffers": [], + "WebglLoseContext": [], + "WebglMultiDraw": [], + "WellKnownDirectory": [], + "WgslLanguageFeatures": [], + "WheelEvent": ["Event", "MouseEvent", "UiEvent"], + "WheelEventInit": [], + "WidevineCdmManifest": [], + "Window": ["EventTarget"], + "WindowClient": ["Client"], + "Worker": ["EventTarget"], + "WorkerDebuggerGlobalScope": ["EventTarget"], + "WorkerGlobalScope": ["EventTarget"], + "WorkerLocation": [], + "WorkerNavigator": [], + "WorkerOptions": [], + "WorkerType": [], + "Worklet": [], + "WorkletGlobalScope": [], + "WorkletOptions": [], + "WritableStream": [], + "WritableStreamDefaultController": [], + "WritableStreamDefaultWriter": [], + "WriteCommandType": [], + "WriteParams": [], + "XPathExpression": [], + "XPathNsResolver": [], + "XPathResult": [], + "XmlDocument": ["Document", "EventTarget", "Node"], + "XmlHttpRequest": ["EventTarget", "XmlHttpRequestEventTarget"], + "XmlHttpRequestEventTarget": ["EventTarget"], + "XmlHttpRequestResponseType": [], + "XmlHttpRequestUpload": ["EventTarget", "XmlHttpRequestEventTarget"], + "XmlSerializer": [], + "XrBoundedReferenceSpace": ["EventTarget", "XrReferenceSpace", "XrSpace"], + "XrEye": [], + "XrFrame": [], + "XrHand": [], + "XrHandJoint": [], + "XrHandedness": [], + "XrInputSource": [], + "XrInputSourceArray": [], + "XrInputSourceEvent": ["Event"], + "XrInputSourceEventInit": [], + "XrInputSourcesChangeEvent": ["Event"], + "XrInputSourcesChangeEventInit": [], + "XrJointPose": ["XrPose"], + "XrJointSpace": ["EventTarget", "XrSpace"], + "XrLayer": ["EventTarget"], + "XrPermissionDescriptor": [], + "XrPermissionStatus": ["EventTarget", "PermissionStatus"], + "XrPose": [], + "XrReferenceSpace": ["EventTarget", "XrSpace"], + "XrReferenceSpaceEvent": ["Event"], + "XrReferenceSpaceEventInit": [], + "XrReferenceSpaceType": [], + "XrRenderState": [], + "XrRenderStateInit": [], + "XrRigidTransform": [], + "XrSession": ["EventTarget"], + "XrSessionEvent": ["Event"], + "XrSessionEventInit": [], + "XrSessionInit": [], + "XrSessionMode": [], + "XrSessionSupportedPermissionDescriptor": [], + "XrSpace": ["EventTarget"], + "XrSystem": ["EventTarget"], + "XrTargetRayMode": [], + "XrView": [], + "XrViewerPose": ["XrPose"], + "XrViewport": [], + "XrVisibilityState": [], + "XrWebGlLayer": ["EventTarget", "XrLayer"], + "XrWebGlLayerInit": [], + "XsltProcessor": [], + "console": [], + "css": [], + "default": ["std"], + "gpu_buffer_usage": [], + "gpu_color_write": [], + "gpu_map_mode": [], + "gpu_shader_stage": [], + "gpu_texture_usage": [], + "std": ["wasm-bindgen/std", "js-sys/std"] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-09-25T07:13:44Z" + } + ] + }, + { + "path": "we/bc/webc", + "header": "AwIAAABldGFnOiAiNzcxOGE5NzYxMWZjZTI0ZGYxNDQ3ZmQ3ZDRjYmMyZTEiAA==", + "records": [ + { + "name": "webc", + "vers": "12.0.0", + "deps": [ + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "base64", + "req": "^0.22", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytes", + "req": "^1", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ciborium", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "document-features", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "flate2", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hexdump", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ignore", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "insta", + "req": "^1", + "features": ["filters", "yaml"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "leb128", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "lexical-sort", + "req": "^0.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "once_cell", + "req": "^1.18", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "path-clean", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pretty_assertions", + "req": "^1.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "regex", + "req": "^1.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "semver", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sequoia-openpgp", + "req": "^2.2.0-pqc.1", + "features": [ + "crypto-rust", + "allow-experimental-crypto", + "allow-variable-time-crypto" + ], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "shared-buffer", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tar", + "req": "^0.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "thiserror", + "req": "^2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "toml", + "req": "^0.9", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ureq", + "req": "^3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "url", + "req": "^2.2", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "5cb48ee4bc7a902c0f1d9eb0c0656f0e78149f1190b7f78e1f28256e88279a84", + "features": { + "mmap": [] + }, + "features2": { + "crypto": ["dep:sequoia-openpgp"], + "default": ["v1", "v2", "v3"], + "v1": ["dep:base64", "dep:leb128", "dep:lexical-sort", "dep:path-clean", "dep:rand"], + "v2": ["dep:once_cell"], + "v3": ["dep:once_cell", "dep:base64"] + }, + "yanked": false, + "rust_version": "1.90", + "pubtime": "2026-06-01T01:39:43Z", + "v": 2 + } + ] + }, + { + "path": "we/ez/weezl", + "header": "AwIAAABldGFnOiAiNDE5ZDcxY2QzMzBlOWZlOTZmYWFiZjQyMDY4Mzg2OTkiAA==", + "records": [ + { + "name": "weezl", + "vers": "0.2.1", + "deps": [ + { + "name": "criterion", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "futures", + "req": "^0.3.12", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1", + "features": ["macros", "io-util", "net", "rt", "rt-multi-thread"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-util", + "req": "^0.6.2", + "features": ["compat"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "zenbench", + "req": "^0.1.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "d4ca08e5ef825b65b056d9efbd95c8750683f0a6d0466d02e96dc2e4e360f3d2", + "features": { + "alloc": [], + "async": ["futures", "std"], + "default": ["std"], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.88.0", + "pubtime": "2026-05-15T22:35:10Z" + } + ] + }, + { + "path": "wh/ic/which", + "header": "AwIAAABldGFnOiAiODFiMTQ0NWRiODYwNTI5NTZmNzI4ZmM2YjdkMjllMGIiAA==", + "records": [ + { + "name": "which", + "vers": "8.0.6", + "deps": [ + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(any(unix, target_os = \"wasi\", target_os = \"redox\"))", + "kind": "normal" + }, + { + "name": "regex", + "req": "^1.10.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.9.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tracing", + "req": "^0.1.40", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "bae2f2b2b816647a1cab1acc91f5bd20812d53cb344382635ec2181940c8034f", + "features": {}, + "features2": { + "default": ["real-sys"], + "real-sys": ["dep:libc"], + "regex": ["dep:regex"], + "tracing": ["dep:tracing"] + }, + "yanked": false, + "rust_version": "1.70", + "pubtime": "2026-08-26T18:06:08Z", + "v": 2 + } + ] + }, + { + "path": "wh/oa/whoami", + "header": "AwIAAABldGFnOiAiMzZhZmUyMzliMTgwODJlNDRmNjg3Mzk0YTNjZWVhMzEiAA==", + "records": [ + { + "name": "whoami", + "vers": "2.1.3", + "deps": [ + { + "name": "libc", + "req": "^0.2.186", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(any(target_vendor = \"apple\", target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"netbsd\", target_os = \"openbsd\", target_os = \"illumos\", target_os = \"hurd\"), not(target_arch = \"wasm32\")))", + "kind": "normal" + }, + { + "name": "libredox", + "req": "^0.1.17", + "features": ["call"], + "optional": true, + "default_features": false, + "target": "cfg(all(target_os = \"redox\", not(target_arch = \"wasm32\")))", + "kind": "normal" + }, + { + "name": "objc2-system-configuration", + "req": "^0.3.2", + "features": ["SCDynamicStore", "SCDynamicStoreCopySpecific"], + "optional": true, + "default_features": false, + "target": "cfg(target_vendor = \"apple\")", + "kind": "normal" + }, + { + "name": "wasite", + "req": "^1.0.2", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(target_arch = \"wasm32\", target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "web-sys", + "req": "^0.3.85", + "features": ["Navigator", "Document", "Window", "Location"], + "optional": true, + "default_features": false, + "target": "cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\"), not(daku)))", + "kind": "normal" + } + ], + "cksum": "626c4bac6755d76ffc12cb01b2eac751db1996b9e0041de9aa02c8c211ddc82c", + "features": { + "force-stub": [] + }, + "features2": { + "default": ["std", "wasi-wasite", "wasm-web"], + "std": [ + "dep:libc", + "dep:libredox", + "dep:objc2-system-configuration", + "libc?/std", + "web-sys?/std" + ], + "wasi-wasite": ["dep:wasite"], + "wasm-web": ["dep:web-sys"] + }, + "yanked": false, + "rust_version": "1.75", + "pubtime": "2026-08-11T23:31:57Z", + "v": 2 + } + ] + }, + { + "path": "wi/na/winapi-util", + "header": "AwIAAABldGFnOiAiYmMxNTRlZWQ4MDJmMzllNDJkNzI1NDMzMjhiYzhkMmMiAA==", + "records": [ + { + "name": "winapi-util", + "vers": "0.1.11", + "deps": [ + { + "name": "windows-sys", + "req": ">=0.48.0, <=0.61", + "features": [ + "Win32_Foundation", + "Win32_Storage_FileSystem", + "Win32_System_Console", + "Win32_System_SystemInformation" + ], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22", + "features": {}, + "yanked": false, + "pubtime": "2025-09-07T12:24:31Z" + } + ] + }, + { + "path": "wi/nd/windows_aarch64_gnullvm", + "header": "AwIAAABldGFnOiAiYWRmZWI4NDk1MTkyYWM5ZTIxMmI2Y2Q2Yjg1NjdjNjciAA==", + "records": [ + { + "name": "windows_aarch64_gnullvm", + "vers": "0.52.6", + "deps": [], + "cksum": "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-07-03T19:43:36Z" + }, + { + "name": "windows_aarch64_gnullvm", + "vers": "0.53.1", + "deps": [], + "cksum": "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53", + "features": {}, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-10-06T17:33:29Z" + } + ] + }, + { + "path": "wi/nd/windows_aarch64_msvc", + "header": "AwIAAABldGFnOiAiMDkyODhhMjBjNjU5M2FhZGY5MWJjNjgyNzM2OWIxNDMiAA==", + "records": [ + { + "name": "windows_aarch64_msvc", + "vers": "0.52.6", + "deps": [], + "cksum": "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-07-03T19:43:40Z" + }, + { + "name": "windows_aarch64_msvc", + "vers": "0.53.1", + "deps": [], + "cksum": "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006", + "features": {}, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-10-06T17:33:33Z" + } + ] + }, + { + "path": "wi/nd/windows_i686_gnu", + "header": "AwIAAABldGFnOiAiYzBiNDZlYzM3NTNiNzBhNjllN2U4N2RkMjA2ZGM4Y2QiAA==", + "records": [ + { + "name": "windows_i686_gnu", + "vers": "0.52.6", + "deps": [], + "cksum": "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-07-03T19:43:46Z" + }, + { + "name": "windows_i686_gnu", + "vers": "0.53.1", + "deps": [], + "cksum": "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3", + "features": {}, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-10-06T17:33:40Z" + } + ] + }, + { + "path": "wi/nd/windows_i686_gnullvm", + "header": "AwIAAABldGFnOiAiNjAxZjMyMmMzOTA2NmQ1YzgxMDFkOGY5ZGQxMmQxODEiAA==", + "records": [ + { + "name": "windows_i686_gnullvm", + "vers": "0.52.6", + "deps": [], + "cksum": "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-07-03T19:43:50Z" + }, + { + "name": "windows_i686_gnullvm", + "vers": "0.53.1", + "deps": [], + "cksum": "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c", + "features": {}, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-10-06T17:33:44Z" + } + ] + }, + { + "path": "wi/nd/windows_i686_msvc", + "header": "AwIAAABldGFnOiAiZTZjZTVlMzNiYWQ4NTBkN2EzMmZmYmRlNmMzZmUyMjkiAA==", + "records": [ + { + "name": "windows_i686_msvc", + "vers": "0.52.6", + "deps": [], + "cksum": "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-07-03T19:43:54Z" + }, + { + "name": "windows_i686_msvc", + "vers": "0.53.1", + "deps": [], + "cksum": "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2", + "features": {}, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-10-06T17:33:49Z" + } + ] + }, + { + "path": "wi/nd/windows_x86_64_gnu", + "header": "AwIAAABldGFnOiAiMjJmYTljOGZmOWVhYWZkODlkOGFlNzE3MjczMTQxMjkiAA==", + "records": [ + { + "name": "windows_x86_64_gnu", + "vers": "0.52.6", + "deps": [], + "cksum": "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-07-03T19:43:58Z" + }, + { + "name": "windows_x86_64_gnu", + "vers": "0.53.1", + "deps": [], + "cksum": "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499", + "features": {}, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-10-06T17:33:55Z" + } + ] + }, + { + "path": "wi/nd/windows_x86_64_gnullvm", + "header": "AwIAAABldGFnOiAiYTg5MmZkODUyZTJhNWVmMTI1ODQ2N2JhOTA4M2IyZDUiAA==", + "records": [ + { + "name": "windows_x86_64_gnullvm", + "vers": "0.52.6", + "deps": [], + "cksum": "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-07-03T19:44:03Z" + }, + { + "name": "windows_x86_64_gnullvm", + "vers": "0.53.1", + "deps": [], + "cksum": "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1", + "features": {}, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-10-06T17:34:01Z" + } + ] + }, + { + "path": "wi/nd/windows_x86_64_msvc", + "header": "AwIAAABldGFnOiAiYjkzYjI1YzUyMjNmNzBiMTAxNzcwOTA5ODlhNjJmYjYiAA==", + "records": [ + { + "name": "windows_x86_64_msvc", + "vers": "0.52.6", + "deps": [], + "cksum": "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-07-03T19:44:07Z" + }, + { + "name": "windows_x86_64_msvc", + "vers": "0.53.1", + "deps": [], + "cksum": "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650", + "features": {}, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-10-06T17:34:07Z" + } + ] + }, + { + "path": "wi/nd/windows-link", + "header": "AwIAAABldGFnOiAiOGExMzljNWFiOGJmMzhhNTUxM2I0OTYxZGU4MmYwY2MiAA==", + "records": [ + { + "name": "windows-link", + "vers": "0.2.1", + "deps": [], + "cksum": "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2025-10-06T17:35:08Z" + } + ] + }, + { + "path": "wi/nd/windows-sys", + "header": "AwIAAABldGFnOiAiZjZmOGFlYTIyYzM4NmY3ZTI2YWUyNWRmNjljYWNkMzYiAA==", + "records": [ + { + "name": "windows-sys", + "vers": "0.52.0", + "deps": [ + { + "name": "windows-targets", + "req": "^0.52.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d", + "features": { + "Wdk": [], + "Wdk_Foundation": ["Wdk"], + "Wdk_Graphics": ["Wdk"], + "Wdk_Graphics_Direct3D": ["Wdk_Graphics"], + "Wdk_Storage": ["Wdk"], + "Wdk_Storage_FileSystem": ["Wdk_Storage"], + "Wdk_Storage_FileSystem_Minifilters": ["Wdk_Storage_FileSystem"], + "Wdk_System": ["Wdk"], + "Wdk_System_IO": ["Wdk_System"], + "Wdk_System_OfflineRegistry": ["Wdk_System"], + "Wdk_System_Registry": ["Wdk_System"], + "Wdk_System_SystemInformation": ["Wdk_System"], + "Wdk_System_SystemServices": ["Wdk_System"], + "Wdk_System_Threading": ["Wdk_System"], + "Win32": [], + "Win32_Data": ["Win32"], + "Win32_Data_HtmlHelp": ["Win32_Data"], + "Win32_Data_RightsManagement": ["Win32_Data"], + "Win32_Devices": ["Win32"], + "Win32_Devices_AllJoyn": ["Win32_Devices"], + "Win32_Devices_BiometricFramework": ["Win32_Devices"], + "Win32_Devices_Bluetooth": ["Win32_Devices"], + "Win32_Devices_Communication": ["Win32_Devices"], + "Win32_Devices_DeviceAndDriverInstallation": ["Win32_Devices"], + "Win32_Devices_DeviceQuery": ["Win32_Devices"], + "Win32_Devices_Display": ["Win32_Devices"], + "Win32_Devices_Enumeration": ["Win32_Devices"], + "Win32_Devices_Enumeration_Pnp": ["Win32_Devices_Enumeration"], + "Win32_Devices_Fax": ["Win32_Devices"], + "Win32_Devices_HumanInterfaceDevice": ["Win32_Devices"], + "Win32_Devices_PortableDevices": ["Win32_Devices"], + "Win32_Devices_Properties": ["Win32_Devices"], + "Win32_Devices_Pwm": ["Win32_Devices"], + "Win32_Devices_Sensors": ["Win32_Devices"], + "Win32_Devices_SerialCommunication": ["Win32_Devices"], + "Win32_Devices_Tapi": ["Win32_Devices"], + "Win32_Devices_Usb": ["Win32_Devices"], + "Win32_Devices_WebServicesOnDevices": ["Win32_Devices"], + "Win32_Foundation": ["Win32"], + "Win32_Gaming": ["Win32"], + "Win32_Globalization": ["Win32"], + "Win32_Graphics": ["Win32"], + "Win32_Graphics_Dwm": ["Win32_Graphics"], + "Win32_Graphics_Gdi": ["Win32_Graphics"], + "Win32_Graphics_GdiPlus": ["Win32_Graphics"], + "Win32_Graphics_Hlsl": ["Win32_Graphics"], + "Win32_Graphics_OpenGL": ["Win32_Graphics"], + "Win32_Graphics_Printing": ["Win32_Graphics"], + "Win32_Graphics_Printing_PrintTicket": ["Win32_Graphics_Printing"], + "Win32_Management": ["Win32"], + "Win32_Management_MobileDeviceManagementRegistration": ["Win32_Management"], + "Win32_Media": ["Win32"], + "Win32_Media_Audio": ["Win32_Media"], + "Win32_Media_DxMediaObjects": ["Win32_Media"], + "Win32_Media_KernelStreaming": ["Win32_Media"], + "Win32_Media_Multimedia": ["Win32_Media"], + "Win32_Media_Streaming": ["Win32_Media"], + "Win32_Media_WindowsMediaFormat": ["Win32_Media"], + "Win32_NetworkManagement": ["Win32"], + "Win32_NetworkManagement_Dhcp": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Dns": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_InternetConnectionWizard": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_IpHelper": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Multicast": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Ndis": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetBios": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetManagement": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetShell": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetworkDiagnosticsFramework": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_P2P": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_QoS": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Rras": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Snmp": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WNet": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WebDav": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WiFi": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsConnectionManager": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsFilteringPlatform": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsFirewall": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsNetworkVirtualization": ["Win32_NetworkManagement"], + "Win32_Networking": ["Win32"], + "Win32_Networking_ActiveDirectory": ["Win32_Networking"], + "Win32_Networking_Clustering": ["Win32_Networking"], + "Win32_Networking_HttpServer": ["Win32_Networking"], + "Win32_Networking_Ldap": ["Win32_Networking"], + "Win32_Networking_WebSocket": ["Win32_Networking"], + "Win32_Networking_WinHttp": ["Win32_Networking"], + "Win32_Networking_WinInet": ["Win32_Networking"], + "Win32_Networking_WinSock": ["Win32_Networking"], + "Win32_Networking_WindowsWebServices": ["Win32_Networking"], + "Win32_Security": ["Win32"], + "Win32_Security_AppLocker": ["Win32_Security"], + "Win32_Security_Authentication": ["Win32_Security"], + "Win32_Security_Authentication_Identity": ["Win32_Security_Authentication"], + "Win32_Security_Authorization": ["Win32_Security"], + "Win32_Security_Credentials": ["Win32_Security"], + "Win32_Security_Cryptography": ["Win32_Security"], + "Win32_Security_Cryptography_Catalog": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_Certificates": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_Sip": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_UI": ["Win32_Security_Cryptography"], + "Win32_Security_DiagnosticDataQuery": ["Win32_Security"], + "Win32_Security_DirectoryServices": ["Win32_Security"], + "Win32_Security_EnterpriseData": ["Win32_Security"], + "Win32_Security_ExtensibleAuthenticationProtocol": ["Win32_Security"], + "Win32_Security_Isolation": ["Win32_Security"], + "Win32_Security_LicenseProtection": ["Win32_Security"], + "Win32_Security_NetworkAccessProtection": ["Win32_Security"], + "Win32_Security_WinTrust": ["Win32_Security"], + "Win32_Security_WinWlx": ["Win32_Security"], + "Win32_Storage": ["Win32"], + "Win32_Storage_Cabinets": ["Win32_Storage"], + "Win32_Storage_CloudFilters": ["Win32_Storage"], + "Win32_Storage_Compression": ["Win32_Storage"], + "Win32_Storage_DistributedFileSystem": ["Win32_Storage"], + "Win32_Storage_FileHistory": ["Win32_Storage"], + "Win32_Storage_FileSystem": ["Win32_Storage"], + "Win32_Storage_Imapi": ["Win32_Storage"], + "Win32_Storage_IndexServer": ["Win32_Storage"], + "Win32_Storage_InstallableFileSystems": ["Win32_Storage"], + "Win32_Storage_IscsiDisc": ["Win32_Storage"], + "Win32_Storage_Jet": ["Win32_Storage"], + "Win32_Storage_Nvme": ["Win32_Storage"], + "Win32_Storage_OfflineFiles": ["Win32_Storage"], + "Win32_Storage_OperationRecorder": ["Win32_Storage"], + "Win32_Storage_Packaging": ["Win32_Storage"], + "Win32_Storage_Packaging_Appx": ["Win32_Storage_Packaging"], + "Win32_Storage_ProjectedFileSystem": ["Win32_Storage"], + "Win32_Storage_StructuredStorage": ["Win32_Storage"], + "Win32_Storage_Vhd": ["Win32_Storage"], + "Win32_Storage_Xps": ["Win32_Storage"], + "Win32_System": ["Win32"], + "Win32_System_AddressBook": ["Win32_System"], + "Win32_System_Antimalware": ["Win32_System"], + "Win32_System_ApplicationInstallationAndServicing": ["Win32_System"], + "Win32_System_ApplicationVerifier": ["Win32_System"], + "Win32_System_ClrHosting": ["Win32_System"], + "Win32_System_Com": ["Win32_System"], + "Win32_System_Com_Marshal": ["Win32_System_Com"], + "Win32_System_Com_StructuredStorage": ["Win32_System_Com"], + "Win32_System_Com_Urlmon": ["Win32_System_Com"], + "Win32_System_ComponentServices": ["Win32_System"], + "Win32_System_Console": ["Win32_System"], + "Win32_System_CorrelationVector": ["Win32_System"], + "Win32_System_DataExchange": ["Win32_System"], + "Win32_System_DeploymentServices": ["Win32_System"], + "Win32_System_DeveloperLicensing": ["Win32_System"], + "Win32_System_Diagnostics": ["Win32_System"], + "Win32_System_Diagnostics_Ceip": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_Debug": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_Debug_Extensions": ["Win32_System_Diagnostics_Debug"], + "Win32_System_Diagnostics_Etw": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_ProcessSnapshotting": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_ToolHelp": ["Win32_System_Diagnostics"], + "Win32_System_DistributedTransactionCoordinator": ["Win32_System"], + "Win32_System_Environment": ["Win32_System"], + "Win32_System_ErrorReporting": ["Win32_System"], + "Win32_System_EventCollector": ["Win32_System"], + "Win32_System_EventLog": ["Win32_System"], + "Win32_System_EventNotificationService": ["Win32_System"], + "Win32_System_GroupPolicy": ["Win32_System"], + "Win32_System_HostCompute": ["Win32_System"], + "Win32_System_HostComputeNetwork": ["Win32_System"], + "Win32_System_HostComputeSystem": ["Win32_System"], + "Win32_System_Hypervisor": ["Win32_System"], + "Win32_System_IO": ["Win32_System"], + "Win32_System_Iis": ["Win32_System"], + "Win32_System_Ioctl": ["Win32_System"], + "Win32_System_JobObjects": ["Win32_System"], + "Win32_System_Js": ["Win32_System"], + "Win32_System_Kernel": ["Win32_System"], + "Win32_System_LibraryLoader": ["Win32_System"], + "Win32_System_Mailslots": ["Win32_System"], + "Win32_System_Mapi": ["Win32_System"], + "Win32_System_Memory": ["Win32_System"], + "Win32_System_Memory_NonVolatile": ["Win32_System_Memory"], + "Win32_System_MessageQueuing": ["Win32_System"], + "Win32_System_MixedReality": ["Win32_System"], + "Win32_System_Ole": ["Win32_System"], + "Win32_System_PasswordManagement": ["Win32_System"], + "Win32_System_Performance": ["Win32_System"], + "Win32_System_Performance_HardwareCounterProfiling": ["Win32_System_Performance"], + "Win32_System_Pipes": ["Win32_System"], + "Win32_System_Power": ["Win32_System"], + "Win32_System_ProcessStatus": ["Win32_System"], + "Win32_System_Recovery": ["Win32_System"], + "Win32_System_Registry": ["Win32_System"], + "Win32_System_RemoteDesktop": ["Win32_System"], + "Win32_System_RemoteManagement": ["Win32_System"], + "Win32_System_RestartManager": ["Win32_System"], + "Win32_System_Restore": ["Win32_System"], + "Win32_System_Rpc": ["Win32_System"], + "Win32_System_Search": ["Win32_System"], + "Win32_System_Search_Common": ["Win32_System_Search"], + "Win32_System_SecurityCenter": ["Win32_System"], + "Win32_System_Services": ["Win32_System"], + "Win32_System_SetupAndMigration": ["Win32_System"], + "Win32_System_Shutdown": ["Win32_System"], + "Win32_System_StationsAndDesktops": ["Win32_System"], + "Win32_System_SubsystemForLinux": ["Win32_System"], + "Win32_System_SystemInformation": ["Win32_System"], + "Win32_System_SystemServices": ["Win32_System"], + "Win32_System_Threading": ["Win32_System"], + "Win32_System_Time": ["Win32_System"], + "Win32_System_TpmBaseServices": ["Win32_System"], + "Win32_System_UserAccessLogging": ["Win32_System"], + "Win32_System_Variant": ["Win32_System"], + "Win32_System_VirtualDosMachines": ["Win32_System"], + "Win32_System_WindowsProgramming": ["Win32_System"], + "Win32_System_Wmi": ["Win32_System"], + "Win32_UI": ["Win32"], + "Win32_UI_Accessibility": ["Win32_UI"], + "Win32_UI_ColorSystem": ["Win32_UI"], + "Win32_UI_Controls": ["Win32_UI"], + "Win32_UI_Controls_Dialogs": ["Win32_UI_Controls"], + "Win32_UI_HiDpi": ["Win32_UI"], + "Win32_UI_Input": ["Win32_UI"], + "Win32_UI_Input_Ime": ["Win32_UI_Input"], + "Win32_UI_Input_KeyboardAndMouse": ["Win32_UI_Input"], + "Win32_UI_Input_Pointer": ["Win32_UI_Input"], + "Win32_UI_Input_Touch": ["Win32_UI_Input"], + "Win32_UI_Input_XboxController": ["Win32_UI_Input"], + "Win32_UI_InteractionContext": ["Win32_UI"], + "Win32_UI_Magnification": ["Win32_UI"], + "Win32_UI_Shell": ["Win32_UI"], + "Win32_UI_Shell_PropertiesSystem": ["Win32_UI_Shell"], + "Win32_UI_TabletPC": ["Win32_UI"], + "Win32_UI_TextServices": ["Win32_UI"], + "Win32_UI_WindowsAndMessaging": ["Win32_UI"], + "Win32_Web": ["Win32"], + "Win32_Web_InternetExplorer": ["Win32_Web"], + "default": [], + "docs": [] + }, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2023-11-15T18:55:55Z" + }, + { + "name": "windows-sys", + "vers": "0.59.0", + "deps": [ + { + "name": "windows-targets", + "req": "^0.52.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b", + "features": { + "Wdk": ["Win32_Foundation"], + "Wdk_Devices": ["Wdk"], + "Wdk_Devices_Bluetooth": ["Wdk_Devices"], + "Wdk_Devices_HumanInterfaceDevice": ["Wdk_Devices"], + "Wdk_Foundation": ["Wdk"], + "Wdk_Graphics": ["Wdk"], + "Wdk_Graphics_Direct3D": ["Wdk_Graphics"], + "Wdk_NetworkManagement": ["Wdk"], + "Wdk_NetworkManagement_Ndis": ["Wdk_NetworkManagement"], + "Wdk_NetworkManagement_WindowsFilteringPlatform": ["Wdk_NetworkManagement"], + "Wdk_Storage": ["Wdk"], + "Wdk_Storage_FileSystem": ["Wdk_Storage"], + "Wdk_Storage_FileSystem_Minifilters": ["Wdk_Storage_FileSystem"], + "Wdk_System": ["Wdk"], + "Wdk_System_IO": ["Wdk_System"], + "Wdk_System_Memory": ["Wdk_System"], + "Wdk_System_OfflineRegistry": ["Wdk_System"], + "Wdk_System_Registry": ["Wdk_System"], + "Wdk_System_SystemInformation": ["Wdk_System"], + "Wdk_System_SystemServices": ["Wdk_System"], + "Wdk_System_Threading": ["Wdk_System"], + "Win32": ["Win32_Foundation"], + "Win32_Data": ["Win32"], + "Win32_Data_HtmlHelp": ["Win32_Data"], + "Win32_Data_RightsManagement": ["Win32_Data"], + "Win32_Devices": ["Win32"], + "Win32_Devices_AllJoyn": ["Win32_Devices"], + "Win32_Devices_BiometricFramework": ["Win32_Devices"], + "Win32_Devices_Bluetooth": ["Win32_Devices"], + "Win32_Devices_Communication": ["Win32_Devices"], + "Win32_Devices_DeviceAndDriverInstallation": ["Win32_Devices"], + "Win32_Devices_DeviceQuery": ["Win32_Devices"], + "Win32_Devices_Display": ["Win32_Devices"], + "Win32_Devices_Enumeration": ["Win32_Devices"], + "Win32_Devices_Enumeration_Pnp": ["Win32_Devices_Enumeration"], + "Win32_Devices_Fax": ["Win32_Devices"], + "Win32_Devices_HumanInterfaceDevice": ["Win32_Devices"], + "Win32_Devices_PortableDevices": ["Win32_Devices"], + "Win32_Devices_Properties": ["Win32_Devices"], + "Win32_Devices_Pwm": ["Win32_Devices"], + "Win32_Devices_Sensors": ["Win32_Devices"], + "Win32_Devices_SerialCommunication": ["Win32_Devices"], + "Win32_Devices_Tapi": ["Win32_Devices"], + "Win32_Devices_Usb": ["Win32_Devices"], + "Win32_Devices_WebServicesOnDevices": ["Win32_Devices"], + "Win32_Foundation": ["Win32"], + "Win32_Gaming": ["Win32"], + "Win32_Globalization": ["Win32"], + "Win32_Graphics": ["Win32"], + "Win32_Graphics_Dwm": ["Win32_Graphics"], + "Win32_Graphics_Gdi": ["Win32_Graphics"], + "Win32_Graphics_GdiPlus": ["Win32_Graphics"], + "Win32_Graphics_Hlsl": ["Win32_Graphics"], + "Win32_Graphics_OpenGL": ["Win32_Graphics"], + "Win32_Graphics_Printing": ["Win32_Graphics"], + "Win32_Graphics_Printing_PrintTicket": ["Win32_Graphics_Printing"], + "Win32_Management": ["Win32"], + "Win32_Management_MobileDeviceManagementRegistration": ["Win32_Management"], + "Win32_Media": ["Win32"], + "Win32_Media_Audio": ["Win32_Media"], + "Win32_Media_DxMediaObjects": ["Win32_Media"], + "Win32_Media_KernelStreaming": ["Win32_Media"], + "Win32_Media_Multimedia": ["Win32_Media"], + "Win32_Media_Streaming": ["Win32_Media"], + "Win32_Media_WindowsMediaFormat": ["Win32_Media"], + "Win32_NetworkManagement": ["Win32"], + "Win32_NetworkManagement_Dhcp": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Dns": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_InternetConnectionWizard": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_IpHelper": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Multicast": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Ndis": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetBios": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetManagement": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetShell": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetworkDiagnosticsFramework": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_P2P": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_QoS": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Rras": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Snmp": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WNet": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WebDav": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WiFi": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsConnectionManager": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsFilteringPlatform": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsFirewall": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsNetworkVirtualization": ["Win32_NetworkManagement"], + "Win32_Networking": ["Win32"], + "Win32_Networking_ActiveDirectory": ["Win32_Networking"], + "Win32_Networking_Clustering": ["Win32_Networking"], + "Win32_Networking_HttpServer": ["Win32_Networking"], + "Win32_Networking_Ldap": ["Win32_Networking"], + "Win32_Networking_WebSocket": ["Win32_Networking"], + "Win32_Networking_WinHttp": ["Win32_Networking"], + "Win32_Networking_WinInet": ["Win32_Networking"], + "Win32_Networking_WinSock": ["Win32_Networking"], + "Win32_Networking_WindowsWebServices": ["Win32_Networking"], + "Win32_Security": ["Win32"], + "Win32_Security_AppLocker": ["Win32_Security"], + "Win32_Security_Authentication": ["Win32_Security"], + "Win32_Security_Authentication_Identity": ["Win32_Security_Authentication"], + "Win32_Security_Authorization": ["Win32_Security"], + "Win32_Security_Credentials": ["Win32_Security"], + "Win32_Security_Cryptography": ["Win32_Security"], + "Win32_Security_Cryptography_Catalog": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_Certificates": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_Sip": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_UI": ["Win32_Security_Cryptography"], + "Win32_Security_DiagnosticDataQuery": ["Win32_Security"], + "Win32_Security_DirectoryServices": ["Win32_Security"], + "Win32_Security_EnterpriseData": ["Win32_Security"], + "Win32_Security_ExtensibleAuthenticationProtocol": ["Win32_Security"], + "Win32_Security_Isolation": ["Win32_Security"], + "Win32_Security_LicenseProtection": ["Win32_Security"], + "Win32_Security_NetworkAccessProtection": ["Win32_Security"], + "Win32_Security_WinTrust": ["Win32_Security"], + "Win32_Security_WinWlx": ["Win32_Security"], + "Win32_Storage": ["Win32"], + "Win32_Storage_Cabinets": ["Win32_Storage"], + "Win32_Storage_CloudFilters": ["Win32_Storage"], + "Win32_Storage_Compression": ["Win32_Storage"], + "Win32_Storage_DistributedFileSystem": ["Win32_Storage"], + "Win32_Storage_FileHistory": ["Win32_Storage"], + "Win32_Storage_FileSystem": ["Win32_Storage"], + "Win32_Storage_Imapi": ["Win32_Storage"], + "Win32_Storage_IndexServer": ["Win32_Storage"], + "Win32_Storage_InstallableFileSystems": ["Win32_Storage"], + "Win32_Storage_IscsiDisc": ["Win32_Storage"], + "Win32_Storage_Jet": ["Win32_Storage"], + "Win32_Storage_Nvme": ["Win32_Storage"], + "Win32_Storage_OfflineFiles": ["Win32_Storage"], + "Win32_Storage_OperationRecorder": ["Win32_Storage"], + "Win32_Storage_Packaging": ["Win32_Storage"], + "Win32_Storage_Packaging_Appx": ["Win32_Storage_Packaging"], + "Win32_Storage_ProjectedFileSystem": ["Win32_Storage"], + "Win32_Storage_StructuredStorage": ["Win32_Storage"], + "Win32_Storage_Vhd": ["Win32_Storage"], + "Win32_Storage_Xps": ["Win32_Storage"], + "Win32_System": ["Win32"], + "Win32_System_AddressBook": ["Win32_System"], + "Win32_System_Antimalware": ["Win32_System"], + "Win32_System_ApplicationInstallationAndServicing": ["Win32_System"], + "Win32_System_ApplicationVerifier": ["Win32_System"], + "Win32_System_ClrHosting": ["Win32_System"], + "Win32_System_Com": ["Win32_System"], + "Win32_System_Com_Marshal": ["Win32_System_Com"], + "Win32_System_Com_StructuredStorage": ["Win32_System_Com"], + "Win32_System_Com_Urlmon": ["Win32_System_Com"], + "Win32_System_ComponentServices": ["Win32_System"], + "Win32_System_Console": ["Win32_System"], + "Win32_System_CorrelationVector": ["Win32_System"], + "Win32_System_DataExchange": ["Win32_System"], + "Win32_System_DeploymentServices": ["Win32_System"], + "Win32_System_DeveloperLicensing": ["Win32_System"], + "Win32_System_Diagnostics": ["Win32_System"], + "Win32_System_Diagnostics_Ceip": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_Debug": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_Debug_Extensions": ["Win32_System_Diagnostics_Debug"], + "Win32_System_Diagnostics_Etw": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_ProcessSnapshotting": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_ToolHelp": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_TraceLogging": ["Win32_System_Diagnostics"], + "Win32_System_DistributedTransactionCoordinator": ["Win32_System"], + "Win32_System_Environment": ["Win32_System"], + "Win32_System_ErrorReporting": ["Win32_System"], + "Win32_System_EventCollector": ["Win32_System"], + "Win32_System_EventLog": ["Win32_System"], + "Win32_System_EventNotificationService": ["Win32_System"], + "Win32_System_GroupPolicy": ["Win32_System"], + "Win32_System_HostCompute": ["Win32_System"], + "Win32_System_HostComputeNetwork": ["Win32_System"], + "Win32_System_HostComputeSystem": ["Win32_System"], + "Win32_System_Hypervisor": ["Win32_System"], + "Win32_System_IO": ["Win32_System"], + "Win32_System_Iis": ["Win32_System"], + "Win32_System_Ioctl": ["Win32_System"], + "Win32_System_JobObjects": ["Win32_System"], + "Win32_System_Js": ["Win32_System"], + "Win32_System_Kernel": ["Win32_System"], + "Win32_System_LibraryLoader": ["Win32_System"], + "Win32_System_Mailslots": ["Win32_System"], + "Win32_System_Mapi": ["Win32_System"], + "Win32_System_Memory": ["Win32_System"], + "Win32_System_Memory_NonVolatile": ["Win32_System_Memory"], + "Win32_System_MessageQueuing": ["Win32_System"], + "Win32_System_MixedReality": ["Win32_System"], + "Win32_System_Ole": ["Win32_System"], + "Win32_System_PasswordManagement": ["Win32_System"], + "Win32_System_Performance": ["Win32_System"], + "Win32_System_Performance_HardwareCounterProfiling": ["Win32_System_Performance"], + "Win32_System_Pipes": ["Win32_System"], + "Win32_System_Power": ["Win32_System"], + "Win32_System_ProcessStatus": ["Win32_System"], + "Win32_System_Recovery": ["Win32_System"], + "Win32_System_Registry": ["Win32_System"], + "Win32_System_RemoteDesktop": ["Win32_System"], + "Win32_System_RemoteManagement": ["Win32_System"], + "Win32_System_RestartManager": ["Win32_System"], + "Win32_System_Restore": ["Win32_System"], + "Win32_System_Rpc": ["Win32_System"], + "Win32_System_Search": ["Win32_System"], + "Win32_System_Search_Common": ["Win32_System_Search"], + "Win32_System_SecurityCenter": ["Win32_System"], + "Win32_System_Services": ["Win32_System"], + "Win32_System_SetupAndMigration": ["Win32_System"], + "Win32_System_Shutdown": ["Win32_System"], + "Win32_System_StationsAndDesktops": ["Win32_System"], + "Win32_System_SubsystemForLinux": ["Win32_System"], + "Win32_System_SystemInformation": ["Win32_System"], + "Win32_System_SystemServices": ["Win32_System"], + "Win32_System_Threading": ["Win32_System"], + "Win32_System_Time": ["Win32_System"], + "Win32_System_TpmBaseServices": ["Win32_System"], + "Win32_System_UserAccessLogging": ["Win32_System"], + "Win32_System_Variant": ["Win32_System"], + "Win32_System_VirtualDosMachines": ["Win32_System"], + "Win32_System_WindowsProgramming": ["Win32_System"], + "Win32_System_Wmi": ["Win32_System"], + "Win32_UI": ["Win32"], + "Win32_UI_Accessibility": ["Win32_UI"], + "Win32_UI_ColorSystem": ["Win32_UI"], + "Win32_UI_Controls": ["Win32_UI"], + "Win32_UI_Controls_Dialogs": ["Win32_UI_Controls"], + "Win32_UI_HiDpi": ["Win32_UI"], + "Win32_UI_Input": ["Win32_UI"], + "Win32_UI_Input_Ime": ["Win32_UI_Input"], + "Win32_UI_Input_KeyboardAndMouse": ["Win32_UI_Input"], + "Win32_UI_Input_Pointer": ["Win32_UI_Input"], + "Win32_UI_Input_Touch": ["Win32_UI_Input"], + "Win32_UI_Input_XboxController": ["Win32_UI_Input"], + "Win32_UI_InteractionContext": ["Win32_UI"], + "Win32_UI_Magnification": ["Win32_UI"], + "Win32_UI_Shell": ["Win32_UI"], + "Win32_UI_Shell_Common": ["Win32_UI_Shell"], + "Win32_UI_Shell_PropertiesSystem": ["Win32_UI_Shell"], + "Win32_UI_TabletPC": ["Win32_UI"], + "Win32_UI_TextServices": ["Win32_UI"], + "Win32_UI_WindowsAndMessaging": ["Win32_UI"], + "Win32_Web": ["Win32"], + "Win32_Web_InternetExplorer": ["Win32_Web"], + "default": [], + "docs": [] + }, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2024-07-30T15:26:17Z" + }, + { + "name": "windows-sys", + "vers": "0.60.2", + "deps": [ + { + "name": "windows-targets", + "req": "^0.53.2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb", + "features": { + "Wdk": ["Win32_Foundation"], + "Wdk_Devices": ["Wdk"], + "Wdk_Devices_Bluetooth": ["Wdk_Devices"], + "Wdk_Devices_HumanInterfaceDevice": ["Wdk_Devices"], + "Wdk_Foundation": ["Wdk"], + "Wdk_Graphics": ["Wdk"], + "Wdk_Graphics_Direct3D": ["Wdk_Graphics"], + "Wdk_NetworkManagement": ["Wdk"], + "Wdk_NetworkManagement_Ndis": ["Wdk_NetworkManagement"], + "Wdk_NetworkManagement_WindowsFilteringPlatform": ["Wdk_NetworkManagement"], + "Wdk_Storage": ["Wdk"], + "Wdk_Storage_FileSystem": ["Wdk_Storage"], + "Wdk_Storage_FileSystem_Minifilters": ["Wdk_Storage_FileSystem"], + "Wdk_System": ["Wdk"], + "Wdk_System_IO": ["Wdk_System"], + "Wdk_System_Memory": ["Wdk_System"], + "Wdk_System_OfflineRegistry": ["Wdk_System"], + "Wdk_System_Registry": ["Wdk_System"], + "Wdk_System_SystemInformation": ["Wdk_System"], + "Wdk_System_SystemServices": ["Wdk_System"], + "Wdk_System_Threading": ["Wdk_System"], + "Win32": ["Win32_Foundation"], + "Win32_Data": ["Win32"], + "Win32_Data_HtmlHelp": ["Win32_Data"], + "Win32_Data_RightsManagement": ["Win32_Data"], + "Win32_Devices": ["Win32"], + "Win32_Devices_AllJoyn": ["Win32_Devices"], + "Win32_Devices_Beep": ["Win32_Devices"], + "Win32_Devices_BiometricFramework": ["Win32_Devices"], + "Win32_Devices_Bluetooth": ["Win32_Devices"], + "Win32_Devices_Cdrom": ["Win32_Devices"], + "Win32_Devices_Communication": ["Win32_Devices"], + "Win32_Devices_DeviceAndDriverInstallation": ["Win32_Devices"], + "Win32_Devices_DeviceQuery": ["Win32_Devices"], + "Win32_Devices_Display": ["Win32_Devices"], + "Win32_Devices_Dvd": ["Win32_Devices"], + "Win32_Devices_Enumeration": ["Win32_Devices"], + "Win32_Devices_Enumeration_Pnp": ["Win32_Devices_Enumeration"], + "Win32_Devices_Fax": ["Win32_Devices"], + "Win32_Devices_HumanInterfaceDevice": ["Win32_Devices"], + "Win32_Devices_Nfc": ["Win32_Devices"], + "Win32_Devices_Nfp": ["Win32_Devices"], + "Win32_Devices_PortableDevices": ["Win32_Devices"], + "Win32_Devices_Properties": ["Win32_Devices"], + "Win32_Devices_Pwm": ["Win32_Devices"], + "Win32_Devices_Sensors": ["Win32_Devices"], + "Win32_Devices_SerialCommunication": ["Win32_Devices"], + "Win32_Devices_Tapi": ["Win32_Devices"], + "Win32_Devices_Usb": ["Win32_Devices"], + "Win32_Devices_WebServicesOnDevices": ["Win32_Devices"], + "Win32_Foundation": ["Win32"], + "Win32_Gaming": ["Win32"], + "Win32_Globalization": ["Win32"], + "Win32_Graphics": ["Win32"], + "Win32_Graphics_Dwm": ["Win32_Graphics"], + "Win32_Graphics_Gdi": ["Win32_Graphics"], + "Win32_Graphics_GdiPlus": ["Win32_Graphics"], + "Win32_Graphics_Hlsl": ["Win32_Graphics"], + "Win32_Graphics_OpenGL": ["Win32_Graphics"], + "Win32_Graphics_Printing": ["Win32_Graphics"], + "Win32_Graphics_Printing_PrintTicket": ["Win32_Graphics_Printing"], + "Win32_Management": ["Win32"], + "Win32_Management_MobileDeviceManagementRegistration": ["Win32_Management"], + "Win32_Media": ["Win32"], + "Win32_Media_Audio": ["Win32_Media"], + "Win32_Media_DxMediaObjects": ["Win32_Media"], + "Win32_Media_KernelStreaming": ["Win32_Media"], + "Win32_Media_Multimedia": ["Win32_Media"], + "Win32_Media_Streaming": ["Win32_Media"], + "Win32_Media_WindowsMediaFormat": ["Win32_Media"], + "Win32_NetworkManagement": ["Win32"], + "Win32_NetworkManagement_Dhcp": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Dns": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_InternetConnectionWizard": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_IpHelper": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Multicast": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Ndis": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetBios": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetManagement": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetShell": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetworkDiagnosticsFramework": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_P2P": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_QoS": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Rras": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Snmp": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WNet": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WebDav": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WiFi": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsConnectionManager": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsFilteringPlatform": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsFirewall": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsNetworkVirtualization": ["Win32_NetworkManagement"], + "Win32_Networking": ["Win32"], + "Win32_Networking_ActiveDirectory": ["Win32_Networking"], + "Win32_Networking_Clustering": ["Win32_Networking"], + "Win32_Networking_HttpServer": ["Win32_Networking"], + "Win32_Networking_Ldap": ["Win32_Networking"], + "Win32_Networking_WebSocket": ["Win32_Networking"], + "Win32_Networking_WinHttp": ["Win32_Networking"], + "Win32_Networking_WinInet": ["Win32_Networking"], + "Win32_Networking_WinSock": ["Win32_Networking"], + "Win32_Networking_WindowsWebServices": ["Win32_Networking"], + "Win32_Security": ["Win32"], + "Win32_Security_AppLocker": ["Win32_Security"], + "Win32_Security_Authentication": ["Win32_Security"], + "Win32_Security_Authentication_Identity": ["Win32_Security_Authentication"], + "Win32_Security_Authorization": ["Win32_Security"], + "Win32_Security_Credentials": ["Win32_Security"], + "Win32_Security_Cryptography": ["Win32_Security"], + "Win32_Security_Cryptography_Catalog": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_Certificates": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_Sip": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_UI": ["Win32_Security_Cryptography"], + "Win32_Security_DiagnosticDataQuery": ["Win32_Security"], + "Win32_Security_DirectoryServices": ["Win32_Security"], + "Win32_Security_EnterpriseData": ["Win32_Security"], + "Win32_Security_ExtensibleAuthenticationProtocol": ["Win32_Security"], + "Win32_Security_Isolation": ["Win32_Security"], + "Win32_Security_LicenseProtection": ["Win32_Security"], + "Win32_Security_NetworkAccessProtection": ["Win32_Security"], + "Win32_Security_WinTrust": ["Win32_Security"], + "Win32_Security_WinWlx": ["Win32_Security"], + "Win32_Storage": ["Win32"], + "Win32_Storage_Cabinets": ["Win32_Storage"], + "Win32_Storage_CloudFilters": ["Win32_Storage"], + "Win32_Storage_Compression": ["Win32_Storage"], + "Win32_Storage_DistributedFileSystem": ["Win32_Storage"], + "Win32_Storage_FileHistory": ["Win32_Storage"], + "Win32_Storage_FileSystem": ["Win32_Storage"], + "Win32_Storage_Imapi": ["Win32_Storage"], + "Win32_Storage_IndexServer": ["Win32_Storage"], + "Win32_Storage_InstallableFileSystems": ["Win32_Storage"], + "Win32_Storage_IscsiDisc": ["Win32_Storage"], + "Win32_Storage_Jet": ["Win32_Storage"], + "Win32_Storage_Nvme": ["Win32_Storage"], + "Win32_Storage_OfflineFiles": ["Win32_Storage"], + "Win32_Storage_OperationRecorder": ["Win32_Storage"], + "Win32_Storage_Packaging": ["Win32_Storage"], + "Win32_Storage_Packaging_Appx": ["Win32_Storage_Packaging"], + "Win32_Storage_ProjectedFileSystem": ["Win32_Storage"], + "Win32_Storage_StructuredStorage": ["Win32_Storage"], + "Win32_Storage_Vhd": ["Win32_Storage"], + "Win32_Storage_Xps": ["Win32_Storage"], + "Win32_System": ["Win32"], + "Win32_System_AddressBook": ["Win32_System"], + "Win32_System_Antimalware": ["Win32_System"], + "Win32_System_ApplicationInstallationAndServicing": ["Win32_System"], + "Win32_System_ApplicationVerifier": ["Win32_System"], + "Win32_System_ClrHosting": ["Win32_System"], + "Win32_System_Com": ["Win32_System"], + "Win32_System_Com_Marshal": ["Win32_System_Com"], + "Win32_System_Com_StructuredStorage": ["Win32_System_Com"], + "Win32_System_Com_Urlmon": ["Win32_System_Com"], + "Win32_System_ComponentServices": ["Win32_System"], + "Win32_System_Console": ["Win32_System"], + "Win32_System_CorrelationVector": ["Win32_System"], + "Win32_System_DataExchange": ["Win32_System"], + "Win32_System_DeploymentServices": ["Win32_System"], + "Win32_System_DeveloperLicensing": ["Win32_System"], + "Win32_System_Diagnostics": ["Win32_System"], + "Win32_System_Diagnostics_Ceip": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_Debug": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_Debug_Extensions": ["Win32_System_Diagnostics_Debug"], + "Win32_System_Diagnostics_Etw": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_ProcessSnapshotting": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_ToolHelp": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_TraceLogging": ["Win32_System_Diagnostics"], + "Win32_System_DistributedTransactionCoordinator": ["Win32_System"], + "Win32_System_Environment": ["Win32_System"], + "Win32_System_ErrorReporting": ["Win32_System"], + "Win32_System_EventCollector": ["Win32_System"], + "Win32_System_EventLog": ["Win32_System"], + "Win32_System_EventNotificationService": ["Win32_System"], + "Win32_System_GroupPolicy": ["Win32_System"], + "Win32_System_HostCompute": ["Win32_System"], + "Win32_System_HostComputeNetwork": ["Win32_System"], + "Win32_System_HostComputeSystem": ["Win32_System"], + "Win32_System_Hypervisor": ["Win32_System"], + "Win32_System_IO": ["Win32_System"], + "Win32_System_Iis": ["Win32_System"], + "Win32_System_Ioctl": ["Win32_System"], + "Win32_System_JobObjects": ["Win32_System"], + "Win32_System_Js": ["Win32_System"], + "Win32_System_Kernel": ["Win32_System"], + "Win32_System_LibraryLoader": ["Win32_System"], + "Win32_System_Mailslots": ["Win32_System"], + "Win32_System_Mapi": ["Win32_System"], + "Win32_System_Memory": ["Win32_System"], + "Win32_System_Memory_NonVolatile": ["Win32_System_Memory"], + "Win32_System_MessageQueuing": ["Win32_System"], + "Win32_System_MixedReality": ["Win32_System"], + "Win32_System_Ole": ["Win32_System"], + "Win32_System_PasswordManagement": ["Win32_System"], + "Win32_System_Performance": ["Win32_System"], + "Win32_System_Performance_HardwareCounterProfiling": ["Win32_System_Performance"], + "Win32_System_Pipes": ["Win32_System"], + "Win32_System_Power": ["Win32_System"], + "Win32_System_ProcessStatus": ["Win32_System"], + "Win32_System_Recovery": ["Win32_System"], + "Win32_System_Registry": ["Win32_System"], + "Win32_System_RemoteDesktop": ["Win32_System"], + "Win32_System_RemoteManagement": ["Win32_System"], + "Win32_System_RestartManager": ["Win32_System"], + "Win32_System_Restore": ["Win32_System"], + "Win32_System_Rpc": ["Win32_System"], + "Win32_System_Search": ["Win32_System"], + "Win32_System_Search_Common": ["Win32_System_Search"], + "Win32_System_SecurityCenter": ["Win32_System"], + "Win32_System_Services": ["Win32_System"], + "Win32_System_SetupAndMigration": ["Win32_System"], + "Win32_System_Shutdown": ["Win32_System"], + "Win32_System_StationsAndDesktops": ["Win32_System"], + "Win32_System_SubsystemForLinux": ["Win32_System"], + "Win32_System_SystemInformation": ["Win32_System"], + "Win32_System_SystemServices": ["Win32_System"], + "Win32_System_Threading": ["Win32_System"], + "Win32_System_Time": ["Win32_System"], + "Win32_System_TpmBaseServices": ["Win32_System"], + "Win32_System_UserAccessLogging": ["Win32_System"], + "Win32_System_Variant": ["Win32_System"], + "Win32_System_VirtualDosMachines": ["Win32_System"], + "Win32_System_WindowsProgramming": ["Win32_System"], + "Win32_System_Wmi": ["Win32_System"], + "Win32_UI": ["Win32"], + "Win32_UI_Accessibility": ["Win32_UI"], + "Win32_UI_ColorSystem": ["Win32_UI"], + "Win32_UI_Controls": ["Win32_UI"], + "Win32_UI_Controls_Dialogs": ["Win32_UI_Controls"], + "Win32_UI_HiDpi": ["Win32_UI"], + "Win32_UI_Input": ["Win32_UI"], + "Win32_UI_Input_Ime": ["Win32_UI_Input"], + "Win32_UI_Input_KeyboardAndMouse": ["Win32_UI_Input"], + "Win32_UI_Input_Pointer": ["Win32_UI_Input"], + "Win32_UI_Input_Touch": ["Win32_UI_Input"], + "Win32_UI_Input_XboxController": ["Win32_UI_Input"], + "Win32_UI_InteractionContext": ["Win32_UI"], + "Win32_UI_Magnification": ["Win32_UI"], + "Win32_UI_Shell": ["Win32_UI"], + "Win32_UI_Shell_Common": ["Win32_UI_Shell"], + "Win32_UI_Shell_PropertiesSystem": ["Win32_UI_Shell"], + "Win32_UI_TabletPC": ["Win32_UI"], + "Win32_UI_TextServices": ["Win32_UI"], + "Win32_UI_WindowsAndMessaging": ["Win32_UI"], + "Win32_Web": ["Win32"], + "Win32_Web_InternetExplorer": ["Win32_Web"], + "default": [], + "docs": [] + }, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-06-12T18:59:32Z" + }, + { + "name": "windows-sys", + "vers": "0.61.2", + "deps": [ + { + "name": "windows-link", + "req": "^0.2.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc", + "features": { + "Wdk": ["Win32_Foundation"], + "Wdk_Devices": ["Wdk"], + "Wdk_Devices_Bluetooth": ["Wdk_Devices"], + "Wdk_Devices_HumanInterfaceDevice": ["Wdk_Devices"], + "Wdk_Foundation": ["Wdk"], + "Wdk_Graphics": ["Wdk"], + "Wdk_Graphics_Direct3D": ["Wdk_Graphics"], + "Wdk_NetworkManagement": ["Wdk"], + "Wdk_NetworkManagement_Ndis": ["Wdk_NetworkManagement"], + "Wdk_NetworkManagement_WindowsFilteringPlatform": ["Wdk_NetworkManagement"], + "Wdk_Storage": ["Wdk"], + "Wdk_Storage_FileSystem": ["Wdk_Storage"], + "Wdk_Storage_FileSystem_Minifilters": ["Wdk_Storage_FileSystem"], + "Wdk_System": ["Wdk"], + "Wdk_System_IO": ["Wdk_System"], + "Wdk_System_Memory": ["Wdk_System"], + "Wdk_System_OfflineRegistry": ["Wdk_System"], + "Wdk_System_Registry": ["Wdk_System"], + "Wdk_System_SystemInformation": ["Wdk_System"], + "Wdk_System_SystemServices": ["Wdk_System"], + "Wdk_System_Threading": ["Wdk_System"], + "Win32": ["Win32_Foundation"], + "Win32_Data": ["Win32"], + "Win32_Data_HtmlHelp": ["Win32_Data"], + "Win32_Data_RightsManagement": ["Win32_Data"], + "Win32_Devices": ["Win32"], + "Win32_Devices_AllJoyn": ["Win32_Devices"], + "Win32_Devices_Beep": ["Win32_Devices"], + "Win32_Devices_BiometricFramework": ["Win32_Devices"], + "Win32_Devices_Bluetooth": ["Win32_Devices"], + "Win32_Devices_Cdrom": ["Win32_Devices"], + "Win32_Devices_Communication": ["Win32_Devices"], + "Win32_Devices_DeviceAndDriverInstallation": ["Win32_Devices"], + "Win32_Devices_DeviceQuery": ["Win32_Devices"], + "Win32_Devices_Display": ["Win32_Devices"], + "Win32_Devices_Dvd": ["Win32_Devices"], + "Win32_Devices_Enumeration": ["Win32_Devices"], + "Win32_Devices_Enumeration_Pnp": ["Win32_Devices_Enumeration"], + "Win32_Devices_Fax": ["Win32_Devices"], + "Win32_Devices_HumanInterfaceDevice": ["Win32_Devices"], + "Win32_Devices_Nfc": ["Win32_Devices"], + "Win32_Devices_Nfp": ["Win32_Devices"], + "Win32_Devices_PortableDevices": ["Win32_Devices"], + "Win32_Devices_Properties": ["Win32_Devices"], + "Win32_Devices_Pwm": ["Win32_Devices"], + "Win32_Devices_Sensors": ["Win32_Devices"], + "Win32_Devices_SerialCommunication": ["Win32_Devices"], + "Win32_Devices_Tapi": ["Win32_Devices"], + "Win32_Devices_Usb": ["Win32_Devices"], + "Win32_Devices_WebServicesOnDevices": ["Win32_Devices"], + "Win32_Foundation": ["Win32"], + "Win32_Gaming": ["Win32"], + "Win32_Globalization": ["Win32"], + "Win32_Graphics": ["Win32"], + "Win32_Graphics_Dwm": ["Win32_Graphics"], + "Win32_Graphics_Gdi": ["Win32_Graphics"], + "Win32_Graphics_GdiPlus": ["Win32_Graphics"], + "Win32_Graphics_Hlsl": ["Win32_Graphics"], + "Win32_Graphics_OpenGL": ["Win32_Graphics"], + "Win32_Graphics_Printing": ["Win32_Graphics"], + "Win32_Graphics_Printing_PrintTicket": ["Win32_Graphics_Printing"], + "Win32_Management": ["Win32"], + "Win32_Management_MobileDeviceManagementRegistration": ["Win32_Management"], + "Win32_Media": ["Win32"], + "Win32_Media_Audio": ["Win32_Media"], + "Win32_Media_DxMediaObjects": ["Win32_Media"], + "Win32_Media_KernelStreaming": ["Win32_Media"], + "Win32_Media_Multimedia": ["Win32_Media"], + "Win32_Media_Streaming": ["Win32_Media"], + "Win32_Media_WindowsMediaFormat": ["Win32_Media"], + "Win32_NetworkManagement": ["Win32"], + "Win32_NetworkManagement_Dhcp": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Dns": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_InternetConnectionWizard": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_IpHelper": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Multicast": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Ndis": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetBios": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetManagement": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetShell": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetworkDiagnosticsFramework": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_P2P": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_QoS": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Rras": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Snmp": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WNet": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WebDav": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WiFi": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsConnectionManager": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsFilteringPlatform": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsFirewall": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsNetworkVirtualization": ["Win32_NetworkManagement"], + "Win32_Networking": ["Win32"], + "Win32_Networking_ActiveDirectory": ["Win32_Networking"], + "Win32_Networking_Clustering": ["Win32_Networking"], + "Win32_Networking_HttpServer": ["Win32_Networking"], + "Win32_Networking_Ldap": ["Win32_Networking"], + "Win32_Networking_WebSocket": ["Win32_Networking"], + "Win32_Networking_WinHttp": ["Win32_Networking"], + "Win32_Networking_WinInet": ["Win32_Networking"], + "Win32_Networking_WinSock": ["Win32_Networking"], + "Win32_Networking_WindowsWebServices": ["Win32_Networking"], + "Win32_Security": ["Win32"], + "Win32_Security_AppLocker": ["Win32_Security"], + "Win32_Security_Authentication": ["Win32_Security"], + "Win32_Security_Authentication_Identity": ["Win32_Security_Authentication"], + "Win32_Security_Authorization": ["Win32_Security"], + "Win32_Security_Credentials": ["Win32_Security"], + "Win32_Security_Cryptography": ["Win32_Security"], + "Win32_Security_Cryptography_Catalog": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_Certificates": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_Sip": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_UI": ["Win32_Security_Cryptography"], + "Win32_Security_DiagnosticDataQuery": ["Win32_Security"], + "Win32_Security_DirectoryServices": ["Win32_Security"], + "Win32_Security_EnterpriseData": ["Win32_Security"], + "Win32_Security_ExtensibleAuthenticationProtocol": ["Win32_Security"], + "Win32_Security_Isolation": ["Win32_Security"], + "Win32_Security_LicenseProtection": ["Win32_Security"], + "Win32_Security_NetworkAccessProtection": ["Win32_Security"], + "Win32_Security_WinTrust": ["Win32_Security"], + "Win32_Security_WinWlx": ["Win32_Security"], + "Win32_Storage": ["Win32"], + "Win32_Storage_Cabinets": ["Win32_Storage"], + "Win32_Storage_CloudFilters": ["Win32_Storage"], + "Win32_Storage_Compression": ["Win32_Storage"], + "Win32_Storage_DistributedFileSystem": ["Win32_Storage"], + "Win32_Storage_FileHistory": ["Win32_Storage"], + "Win32_Storage_FileSystem": ["Win32_Storage"], + "Win32_Storage_Imapi": ["Win32_Storage"], + "Win32_Storage_IndexServer": ["Win32_Storage"], + "Win32_Storage_InstallableFileSystems": ["Win32_Storage"], + "Win32_Storage_IscsiDisc": ["Win32_Storage"], + "Win32_Storage_Jet": ["Win32_Storage"], + "Win32_Storage_Nvme": ["Win32_Storage"], + "Win32_Storage_OfflineFiles": ["Win32_Storage"], + "Win32_Storage_OperationRecorder": ["Win32_Storage"], + "Win32_Storage_Packaging": ["Win32_Storage"], + "Win32_Storage_Packaging_Appx": ["Win32_Storage_Packaging"], + "Win32_Storage_ProjectedFileSystem": ["Win32_Storage"], + "Win32_Storage_StructuredStorage": ["Win32_Storage"], + "Win32_Storage_Vhd": ["Win32_Storage"], + "Win32_Storage_Xps": ["Win32_Storage"], + "Win32_System": ["Win32"], + "Win32_System_AddressBook": ["Win32_System"], + "Win32_System_Antimalware": ["Win32_System"], + "Win32_System_ApplicationInstallationAndServicing": ["Win32_System"], + "Win32_System_ApplicationVerifier": ["Win32_System"], + "Win32_System_ClrHosting": ["Win32_System"], + "Win32_System_Com": ["Win32_System"], + "Win32_System_Com_Marshal": ["Win32_System_Com"], + "Win32_System_Com_StructuredStorage": ["Win32_System_Com"], + "Win32_System_Com_Urlmon": ["Win32_System_Com"], + "Win32_System_ComponentServices": ["Win32_System"], + "Win32_System_Console": ["Win32_System"], + "Win32_System_CorrelationVector": ["Win32_System"], + "Win32_System_DataExchange": ["Win32_System"], + "Win32_System_DeploymentServices": ["Win32_System"], + "Win32_System_DeveloperLicensing": ["Win32_System"], + "Win32_System_Diagnostics": ["Win32_System"], + "Win32_System_Diagnostics_Ceip": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_Debug": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_Debug_Extensions": ["Win32_System_Diagnostics_Debug"], + "Win32_System_Diagnostics_Etw": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_ProcessSnapshotting": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_ToolHelp": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_TraceLogging": ["Win32_System_Diagnostics"], + "Win32_System_DistributedTransactionCoordinator": ["Win32_System"], + "Win32_System_Environment": ["Win32_System"], + "Win32_System_ErrorReporting": ["Win32_System"], + "Win32_System_EventCollector": ["Win32_System"], + "Win32_System_EventLog": ["Win32_System"], + "Win32_System_EventNotificationService": ["Win32_System"], + "Win32_System_GroupPolicy": ["Win32_System"], + "Win32_System_HostCompute": ["Win32_System"], + "Win32_System_HostComputeNetwork": ["Win32_System"], + "Win32_System_HostComputeSystem": ["Win32_System"], + "Win32_System_Hypervisor": ["Win32_System"], + "Win32_System_IO": ["Win32_System"], + "Win32_System_Iis": ["Win32_System"], + "Win32_System_Ioctl": ["Win32_System"], + "Win32_System_JobObjects": ["Win32_System"], + "Win32_System_Js": ["Win32_System"], + "Win32_System_Kernel": ["Win32_System"], + "Win32_System_LibraryLoader": ["Win32_System"], + "Win32_System_Mailslots": ["Win32_System"], + "Win32_System_Mapi": ["Win32_System"], + "Win32_System_Memory": ["Win32_System"], + "Win32_System_Memory_NonVolatile": ["Win32_System_Memory"], + "Win32_System_MessageQueuing": ["Win32_System"], + "Win32_System_MixedReality": ["Win32_System"], + "Win32_System_Ole": ["Win32_System"], + "Win32_System_PasswordManagement": ["Win32_System"], + "Win32_System_Performance": ["Win32_System"], + "Win32_System_Performance_HardwareCounterProfiling": ["Win32_System_Performance"], + "Win32_System_Pipes": ["Win32_System"], + "Win32_System_Power": ["Win32_System"], + "Win32_System_ProcessStatus": ["Win32_System"], + "Win32_System_Recovery": ["Win32_System"], + "Win32_System_Registry": ["Win32_System"], + "Win32_System_RemoteDesktop": ["Win32_System"], + "Win32_System_RemoteManagement": ["Win32_System"], + "Win32_System_RestartManager": ["Win32_System"], + "Win32_System_Restore": ["Win32_System"], + "Win32_System_Rpc": ["Win32_System"], + "Win32_System_Search": ["Win32_System"], + "Win32_System_Search_Common": ["Win32_System_Search"], + "Win32_System_SecurityCenter": ["Win32_System"], + "Win32_System_Services": ["Win32_System"], + "Win32_System_SetupAndMigration": ["Win32_System"], + "Win32_System_Shutdown": ["Win32_System"], + "Win32_System_StationsAndDesktops": ["Win32_System"], + "Win32_System_SubsystemForLinux": ["Win32_System"], + "Win32_System_SystemInformation": ["Win32_System"], + "Win32_System_SystemServices": ["Win32_System"], + "Win32_System_Threading": ["Win32_System"], + "Win32_System_Time": ["Win32_System"], + "Win32_System_TpmBaseServices": ["Win32_System"], + "Win32_System_UserAccessLogging": ["Win32_System"], + "Win32_System_Variant": ["Win32_System"], + "Win32_System_VirtualDosMachines": ["Win32_System"], + "Win32_System_WindowsProgramming": ["Win32_System"], + "Win32_System_Wmi": ["Win32_System"], + "Win32_UI": ["Win32"], + "Win32_UI_Accessibility": ["Win32_UI"], + "Win32_UI_ColorSystem": ["Win32_UI"], + "Win32_UI_Controls": ["Win32_UI"], + "Win32_UI_Controls_Dialogs": ["Win32_UI_Controls"], + "Win32_UI_HiDpi": ["Win32_UI"], + "Win32_UI_Input": ["Win32_UI"], + "Win32_UI_Input_Ime": ["Win32_UI_Input"], + "Win32_UI_Input_KeyboardAndMouse": ["Win32_UI_Input"], + "Win32_UI_Input_Pointer": ["Win32_UI_Input"], + "Win32_UI_Input_Touch": ["Win32_UI_Input"], + "Win32_UI_Input_XboxController": ["Win32_UI_Input"], + "Win32_UI_InteractionContext": ["Win32_UI"], + "Win32_UI_Magnification": ["Win32_UI"], + "Win32_UI_Shell": ["Win32_UI"], + "Win32_UI_Shell_Common": ["Win32_UI_Shell"], + "Win32_UI_Shell_PropertiesSystem": ["Win32_UI_Shell"], + "Win32_UI_TabletPC": ["Win32_UI"], + "Win32_UI_TextServices": ["Win32_UI"], + "Win32_UI_WindowsAndMessaging": ["Win32_UI"], + "Win32_Web": ["Win32"], + "Win32_Web_InternetExplorer": ["Win32_Web"], + "default": [], + "docs": [] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2025-10-06T19:18:30Z" + } + ] + }, + { + "path": "wi/nd/windows-targets", + "header": "AwIAAABldGFnOiAiMDRhNGYyMTdkYjg4MjFlNzU4YTAyMzE4YjM1ODA4ZGMiAA==", + "records": [ + { + "name": "windows-targets", + "vers": "0.52.6", + "deps": [ + { + "name": "windows_aarch64_gnullvm", + "req": "^0.52.6", + "features": [], + "optional": false, + "default_features": true, + "target": "aarch64-pc-windows-gnullvm", + "kind": "normal" + }, + { + "name": "windows_aarch64_msvc", + "req": "^0.52.6", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"aarch64\", target_env = \"msvc\", not(windows_raw_dylib)))", + "kind": "normal" + }, + { + "name": "windows_i686_gnu", + "req": "^0.52.6", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"x86\", target_env = \"gnu\", not(target_abi = \"llvm\"), not(windows_raw_dylib)))", + "kind": "normal" + }, + { + "name": "windows_i686_gnullvm", + "req": "^0.52.6", + "features": [], + "optional": false, + "default_features": true, + "target": "i686-pc-windows-gnullvm", + "kind": "normal" + }, + { + "name": "windows_i686_msvc", + "req": "^0.52.6", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"x86\", target_env = \"msvc\", not(windows_raw_dylib)))", + "kind": "normal" + }, + { + "name": "windows_x86_64_gnu", + "req": "^0.52.6", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"x86_64\", target_env = \"gnu\", not(target_abi = \"llvm\"), not(windows_raw_dylib)))", + "kind": "normal" + }, + { + "name": "windows_x86_64_gnullvm", + "req": "^0.52.6", + "features": [], + "optional": false, + "default_features": true, + "target": "x86_64-pc-windows-gnullvm", + "kind": "normal" + }, + { + "name": "windows_x86_64_msvc", + "req": "^0.52.6", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(any(target_arch = \"x86_64\", target_arch = \"arm64ec\"), target_env = \"msvc\", not(windows_raw_dylib)))", + "kind": "normal" + } + ], + "cksum": "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-07-03T19:44:18Z" + }, + { + "name": "windows-targets", + "vers": "0.53.5", + "deps": [ + { + "name": "windows-link", + "req": "^0.2.1", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(windows_raw_dylib)", + "kind": "normal" + }, + { + "name": "windows_aarch64_gnullvm", + "req": "^0.53.0", + "features": [], + "optional": false, + "default_features": true, + "target": "aarch64-pc-windows-gnullvm", + "kind": "normal" + }, + { + "name": "windows_aarch64_msvc", + "req": "^0.53.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"aarch64\", target_env = \"msvc\", not(windows_raw_dylib)))", + "kind": "normal" + }, + { + "name": "windows_i686_gnu", + "req": "^0.53.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"x86\", target_env = \"gnu\", not(target_abi = \"llvm\"), not(windows_raw_dylib)))", + "kind": "normal" + }, + { + "name": "windows_i686_gnullvm", + "req": "^0.53.0", + "features": [], + "optional": false, + "default_features": true, + "target": "i686-pc-windows-gnullvm", + "kind": "normal" + }, + { + "name": "windows_i686_msvc", + "req": "^0.53.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"x86\", target_env = \"msvc\", not(windows_raw_dylib)))", + "kind": "normal" + }, + { + "name": "windows_x86_64_gnu", + "req": "^0.53.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"x86_64\", target_env = \"gnu\", not(target_abi = \"llvm\"), not(windows_raw_dylib)))", + "kind": "normal" + }, + { + "name": "windows_x86_64_gnullvm", + "req": "^0.53.0", + "features": [], + "optional": false, + "default_features": true, + "target": "x86_64-pc-windows-gnullvm", + "kind": "normal" + }, + { + "name": "windows_x86_64_msvc", + "req": "^0.53.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(any(target_arch = \"x86_64\", target_arch = \"arm64ec\"), target_env = \"msvc\", not(windows_raw_dylib)))", + "kind": "normal" + } + ], + "cksum": "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3", + "features": {}, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-10-06T19:18:45Z" + } + ] + }, + { + "path": "wi/nn/winnow", + "header": "AwIAAABldGFnOiAiM2JlZmY0ZTJiOWI1OGQwNjUyYmFhMGY3ZGVlY2VmYTUiAA==", + "records": [ + { + "name": "winnow", + "vers": "1.0.4", + "deps": [ + { + "name": "annotate-snippets", + "req": "^0.11.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "anstream", + "req": "^0.6.15", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anstyle", + "req": "^1.0.8", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anyhow", + "req": "^1.0.100", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "automod", + "req": "^1.0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "circular", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.5.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "is_terminal_polyfill", + "req": "^1.48.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "lexopt", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "memchr", + "req": "^2.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "proptest", + "req": "^1.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustc-hash", + "req": "^2.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "snapbox", + "req": "^0.6.21", + "features": ["examples"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "term-transcript", + "req": "^0.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "terminal_size", + "req": "^0.4.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81", + "features": { + "alloc": [], + "ascii": ["parser"], + "binary": ["parser"], + "parser": [], + "unstable-recover": ["parser"] + }, + "features2": { + "debug": [ + "std", + "dep:anstream", + "dep:anstyle", + "dep:is_terminal_polyfill", + "dep:terminal_size" + ], + "default": ["std", "ascii", "binary"], + "simd": ["dep:memchr"], + "std": ["alloc", "memchr?/std"], + "unstable-doc": ["alloc", "std", "ascii", "binary", "simd", "unstable-recover"] + }, + "yanked": false, + "rust_version": "1.65.0", + "pubtime": "2026-07-13T14:31:41Z", + "v": 2 + } + ] + }, + { + "path": "wi/nx/winx", + "header": "AwIAAABldGFnOiAiOGI4ZGVkN2Y1Y2E2OWU0NzU0Y2MxOGY1N2JiZWU1ZTMiAA==", + "records": [ + { + "name": "winx", + "vers": "0.36.4", + "deps": [ + { + "name": "bitflags", + "req": "^2.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.52, <=0.59", + "features": [ + "Win32_Foundation", + "Win32_Storage_FileSystem", + "Win32_System_IO", + "Win32_System_Ioctl", + "Win32_System_LibraryLoader", + "Win32_System_Performance", + "Win32_System_SystemServices" + ], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "3f3fd376f71958b862e7afb20cfe5a22830e1963462f3a17f49d82a6c1d1f42d", + "features": {}, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2024-12-04T02:14:41Z" + } + ] + }, + { + "path": "wi/t-/wit-bindgen", + "header": "AwIAAABldGFnOiAiNGZiMDE4ZDEzZjBlMzY3N2Y1NGVmZDE3OTQ1OGQzNGEiAA==", + "records": [ + { + "name": "wit-bindgen", + "vers": "0.57.1", + "deps": [ + { + "name": "alloc", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "bitflags", + "req": "^2.11.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "core", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "futures", + "req": "^0.3.30", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wit-bindgen-rust-macro", + "req": "^0.57.1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e", + "features": { + "async": [], + "inter-task-wakeup": ["async"], + "realloc": [], + "std": [] + }, + "features2": { + "async-spawn": ["async", "dep:futures", "std"], + "bitflags": ["dep:bitflags"], + "default": ["macros", "realloc", "async", "std", "bitflags", "macro-string"], + "futures-stream": ["async", "dep:futures"], + "macro-string": ["wit-bindgen-rust-macro?/macro-string"], + "macros": ["dep:wit-bindgen-rust-macro"], + "rustc-dep-of-std": ["dep:core", "dep:alloc"] + }, + "yanked": false, + "rust_version": "1.85.0", + "pubtime": "2026-04-17T17:49:55Z", + "v": 2 + } + ] + }, + { + "path": "wr/it/writeable", + "header": "AwIAAABldGFnOiAiMzZhODU0YmFkNmI4MDJhZWZmNzUxZjY3Njg3YjI1NmMiAA==", + "records": [ + { + "name": "writeable", + "vers": "0.6.4", + "deps": [ + { + "name": "criterion", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "either", + "req": "^1.9.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.9", + "features": ["small_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc", + "features": { + "alloc": [], + "default": ["alloc"] + }, + "features2": { + "either": ["dep:either"] + }, + "yanked": false, + "rust_version": "1.82", + "pubtime": "2026-08-13T23:28:09Z", + "v": 2 + } + ] + }, + { + "path": "xa/tt/xattr", + "header": "AwIAAABldGFnOiAiZDFiOTMzNmU1Y2U1YTA4ZWMyOWYzOThkMTVkZjFkNzkiAA==", + "records": [ + { + "name": "xattr", + "vers": "1.6.1", + "deps": [ + { + "name": "libc", + "req": "^0.2.150", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(target_os = \"freebsd\", target_os = \"netbsd\"))", + "kind": "normal" + }, + { + "name": "rustix", + "req": "^1.0.0", + "features": ["fs", "std"], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"android\", target_os = \"linux\", target_os = \"macos\", target_os = \"hurd\"))", + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156", + "features": { + "default": ["unsupported"], + "unsupported": [] + }, + "yanked": false, + "pubtime": "2025-09-21T02:52:23Z" + } + ] + }, + { + "path": "xx/ha/xxhash-rust", + "header": "AwIAAABldGFnOiAiM2Q5MjkwZDQ1OTBjNDcxZjJmZThiYzYxYzI4NGYyYmEiAA==", + "records": [ + { + "name": "xxhash-rust", + "vers": "0.8.19", + "deps": [ + { + "name": "getrandom", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "xxhash-c-sys", + "req": "^0.8.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "550a2b930b62486a393c52d5c3b84bff264b28aa437ed64694d31e93b1757af7", + "features": { + "const_xxh3": [], + "const_xxh32": [], + "const_xxh64": [], + "std": [], + "xxh3": [], + "xxh32": [], + "xxh64": [] + }, + "yanked": false, + "pubtime": "2026-09-28T13:16:18Z" + } + ] + }, + { + "path": "yo/ke/yoke", + "header": "AwIAAABldGFnOiAiMWI1MjJmOWVkMDdhYjcyMGEwM2ZmYmMyMjQ1MjdmZWYiAA==", + "records": [ + { + "name": "yoke", + "vers": "0.8.3", + "deps": [ + { + "name": "bincode", + "req": "^1.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "postcard", + "req": "^1.0.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "stable_deref_trait", + "req": "^1.2.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "yoke-derive", + "req": "^0.8.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerofrom", + "req": "^0.1.6", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5", + "features": { + "alloc": ["stable_deref_trait/alloc", "zerofrom/alloc"], + "serde": [] + }, + "features2": { + "default": ["alloc", "zerofrom"], + "derive": ["dep:yoke-derive", "zerofrom/derive"], + "zerofrom": ["dep:zerofrom"] + }, + "yanked": false, + "rust_version": "1.82", + "pubtime": "2026-06-03T20:59:17Z", + "v": 2 + } + ] + }, + { + "path": "yo/ke/yoke-derive", + "header": "AwIAAABldGFnOiAiZDQwNTUwY2UzOTQ5ODFmYjgwMjQzODMzYThmODE3ZDQiAA==", + "records": [ + { + "name": "yoke-derive", + "vers": "0.8.4", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.61", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.44", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3.0", + "features": ["fold", "visit"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "synstructure", + "req": "^0.14.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71", + "features": {}, + "yanked": false, + "rust_version": "1.82", + "pubtime": "2026-09-30T13:19:39Z" + } + ] + }, + { + "path": "ze/ro/zerocopy", + "header": "AwIAAABldGFnOiAiMjM4NDVjZTgxZWViMjM0NGFhNjQ5YzljOGMzNzQ0NmYiAA==", + "records": [ + { + "name": "zerocopy", + "vers": "0.8.62", + "deps": [ + { + "name": "elain", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "itertools", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.8.7", + "features": ["small_rng"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "regex", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "zerocopy-derive", + "req": "=0.8.62", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any())", + "kind": "normal" + }, + { + "name": "zerocopy-derive", + "req": "=0.8.62", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "zerocopy-derive", + "req": "=0.8.62", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "86502bf56ac7c77571a32e2647bb2a15894565e981fb2a48d7bde2d91c965a9d", + "features": { + "__internal_use_only_features_that_work_on_stable": ["alloc", "derive", "simd", "std"], + "alloc": [], + "derive": ["zerocopy-derive"], + "float-nightly": [], + "simd": [], + "simd-nightly": ["simd"], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.56.0", + "pubtime": "2026-10-08T10:04:10Z" + } + ] + }, + { + "path": "ze/ro/zerocopy-derive", + "header": "AwIAAABldGFnOiAiZmQ5NmRkNjQ3NDFiMWFkZWMwZjY2YWE0NTBiNjU0MGIiAA==", + "records": [ + { + "name": "zerocopy-derive", + "vers": "0.8.62", + "deps": [ + { + "name": "dissimilar", + "req": "^1.0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "prettyplease", + "req": "^0.2.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.40", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustversion", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn", + "req": "^2.0.46", + "features": ["full"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0.46", + "features": ["visit"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "5457206954b06561e2608c7e19cf58b1926586d999c246eebe4502f7e2039d1a", + "features": {}, + "yanked": false, + "pubtime": "2026-10-08T10:03:02Z" + } + ] + }, + { + "path": "ze/ro/zerofrom", + "header": "AwIAAABldGFnOiAiZjRhYWY4MDhjMGE4MmRjNjFkYjEwOGQ2YzMzNTY4MmYiAA==", + "records": [ + { + "name": "zerofrom", + "vers": "0.1.8", + "deps": [ + { + "name": "zerofrom-derive", + "req": "^0.1.6", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272", + "features": { + "alloc": [], + "default": ["alloc"] + }, + "features2": { + "derive": ["dep:zerofrom-derive"] + }, + "yanked": false, + "rust_version": "1.71.1", + "pubtime": "2026-05-12T09:08:18Z", + "v": 2 + } + ] + }, + { + "path": "ze/ro/zerofrom-derive", + "header": "AwIAAABldGFnOiAiODU3NTIyYmI2NjhmNDNmMDUxNDVkNWYzNDhiMDdkOGQiAA==", + "records": [ + { + "name": "zerofrom-derive", + "vers": "0.1.8", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.61", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.44", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3.0", + "features": ["fold", "visit"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "synstructure", + "req": "^0.14.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a", + "features": {}, + "yanked": false, + "rust_version": "1.71.1", + "pubtime": "2026-09-15T21:39:20Z" + } + ] + }, + { + "path": "ze/ro/zerotrie", + "header": "AwIAAABldGFnOiAiYjBkZmFjMzY2ZWQwNTViNDZiMzljZmRkZGRiNzc0OWYiAA==", + "records": [ + { + "name": "zerotrie", + "vers": "0.2.5", + "deps": [ + { + "name": "bincode", + "req": "^1.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "databake", + "req": "^0.2.0", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "displaydoc", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "icu_locale_core", + "req": "^2.3.0", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "itertools", + "req": "^0.14.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "litemap", + "req": "^0.8.0", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "postcard", + "req": "^1.0.3", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand_pcg", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rmp-serde", + "req": "^1.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.45", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "yoke", + "req": "^0.8.3", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerofrom", + "req": "^0.1.6", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerovec", + "req": "^0.11.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f", + "features": { + "default": [] + }, + "features2": { + "alloc": ["zerovec?/alloc"], + "databake": ["dep:databake", "zerovec?/databake"], + "dense": ["dep:zerovec"], + "litemap": ["dep:litemap", "alloc"], + "serde": ["dep:serde_core", "dep:litemap", "alloc", "litemap/serde", "zerovec?/serde"], + "yoke": ["dep:yoke"], + "zerofrom": ["dep:zerofrom"], + "zerovec": ["dep:zerovec"] + }, + "yanked": false, + "rust_version": "1.82", + "pubtime": "2026-08-13T23:28:19Z", + "v": 2 + } + ] + }, + { + "path": "ze/ro/zerovec", + "header": "AwIAAABldGFnOiAiMGNmZjFjY2M1MTZjOWFjOWFmMThiNmJkOWUyMjRlZmMiAA==", + "records": [ + { + "name": "zerovec", + "vers": "0.11.8", + "deps": [ + { + "name": "bincode", + "req": "^1.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "databake", + "req": "^0.2.0", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "getrandom", + "req": "^0.3", + "features": ["wasm_js"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "iai", + "req": "^0.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "insta", + "req": "^1.43.2", + "features": ["json"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "postcard", + "req": "^1.0.3", + "features": ["use-std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand_distr", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand_pcg", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rmp-serde", + "req": "^1.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "schemars", + "req": "^1.0.4", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0.45", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "twox-hash", + "req": "^2.0.0", + "features": ["xxhash64"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "yoke", + "req": "^0.8.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "yoke", + "req": "^0.8.3", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "zerofrom", + "req": "^0.1.6", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerovec-derive", + "req": "^0.11.5", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8", + "features": { + "std": [] + }, + "features2": { + "alloc": ["serde?/alloc"], + "databake": ["dep:databake"], + "derive": ["dep:zerovec-derive"], + "hashmap": ["dep:twox-hash", "alloc"], + "schemars": ["dep:schemars", "alloc"], + "serde": ["dep:serde"], + "yoke": ["dep:yoke"] + }, + "yanked": false, + "rust_version": "1.83", + "pubtime": "2026-08-19T22:32:16Z", + "v": 2 + } + ] + }, + { + "path": "ze/ro/zerovec-derive", + "header": "AwIAAABldGFnOiAiNDJkZjljMGVjMWZjNjljNzhlMDY3ODllZWUwMzk0YWQiAA==", + "records": [ + { + "name": "zerovec-derive", + "vers": "0.11.6", + "deps": [ + { + "name": "bincode", + "req": "^1.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1.0.61", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.44", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0.45", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn", + "req": "^3.0", + "features": ["extra-traits"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da", + "features": {}, + "yanked": false, + "pubtime": "2026-08-20T23:25:28Z" + } + ] + }, + { + "path": "zl/ib/zlib-rs", + "header": "AwIAAABldGFnOiAiYTVmMWMxNDU5Nzk2ZGQxYWIzYTI5YWE0MGJmOWU4OTQiAA==", + "records": [ + { + "name": "zlib-rs", + "vers": "0.6.8", + "deps": [ + { + "name": "arbitrary", + "req": "^1.0", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "crc32fast", + "req": "^1.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "memoffset", + "req": "^0.9.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quickcheck", + "req": "^1.0.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1.0.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + } + ], + "cksum": "b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112", + "features": { + "ZLIB_DEBUG": [], + "__internal-api": [], + "__internal-fuzz": ["arbitrary"], + "__internal-fuzz-disable-checksum": [], + "__internal-test": ["quickcheck"], + "avx512": ["vpclmulqdq"], + "c-allocator": [], + "default": ["std", "c-allocator"], + "lsx": [], + "rust-allocator": [], + "std": ["rust-allocator"], + "vpclmulqdq": [] + }, + "yanked": false, + "rust_version": "1.75", + "pubtime": "2026-09-15T13:10:00Z" + } + ] + }, + { + "path": "zm/ij/zmij", + "header": "AwIAAABldGFnOiAiMGY1ODQ4NzI1ZWIwZmQyODY3OGY0YTdjNWM5M2M4MzMiAA==", + "records": [ + { + "name": "zmij", + "vers": "1.0.23", + "deps": [ + { + "name": "criterion", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "no-panic", + "req": "^0.1.36", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "num-bigint", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "num-integer", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "num_cpus", + "req": "^1.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "opt-level", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ryu", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-13T12:58:53Z" + } + ] + }, + { + "path": "zs/td/zstd", + "header": "AwIAAABldGFnOiAiZWU4ZDc2NjU1YjRlMjQxNDAzZWMyN2FlNzMxMTVkMjgiAA==", + "records": [ + { + "name": "zstd", + "vers": "0.13.3", + "deps": [ + { + "name": "clap", + "req": "^4.0", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "humansize", + "req": "^2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "partial-io", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "walkdir", + "req": "^2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "zstd-safe", + "req": "^7.1.0", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a", + "features": { + "arrays": ["zstd-safe/arrays"], + "bindgen": ["zstd-safe/bindgen"], + "debug": ["zstd-safe/debug"], + "default": ["legacy", "arrays", "zdict_builder"], + "doc-cfg": [], + "experimental": ["zstd-safe/experimental"], + "fat-lto": ["zstd-safe/fat-lto"], + "legacy": ["zstd-safe/legacy"], + "no_asm": ["zstd-safe/no_asm"], + "pkg-config": ["zstd-safe/pkg-config"], + "thin": ["zstd-safe/thin"], + "thin-lto": ["zstd-safe/thin-lto"], + "wasm": [], + "zdict_builder": ["zstd-safe/zdict_builder"], + "zstdmt": ["zstd-safe/zstdmt"] + }, + "yanked": false, + "rust_version": "1.64", + "pubtime": "2025-02-20T21:43:13Z" + } + ] + }, + { + "path": "zs/td/zstd-safe", + "header": "AwIAAABldGFnOiAiMmFiZGFlNDdjZmI4ODIxYTkwZTg4NWNmZjk0OWZjMTMiAA==", + "records": [ + { + "name": "zstd-safe", + "vers": "7.3.0", + "deps": [ + { + "name": "zstd-sys", + "req": "^2.0.15", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "64d80649ab6db9d9f6f9c80a40becd948eda4714a0a5ac8c4d157a32231c7882", + "features": { + "arrays": [], + "bindgen": ["zstd-sys/bindgen"], + "debug": ["zstd-sys/debug"], + "default": ["legacy", "arrays", "zdict_builder"], + "doc-cfg": [], + "experimental": ["zstd-sys/experimental"], + "fat-lto": ["zstd-sys/fat-lto"], + "legacy": ["zstd-sys/legacy"], + "no_asm": ["zstd-sys/no_asm"], + "pkg-config": ["zstd-sys/pkg-config"], + "seekable": ["zstd-sys/seekable"], + "std": ["zstd-sys/std"], + "thin": ["zstd-sys/thin"], + "thin-lto": ["zstd-sys/thin-lto"], + "zdict_builder": ["zstd-sys/zdict_builder"], + "zstdmt": ["zstd-sys/zstdmt"] + }, + "yanked": false, + "rust_version": "1.64", + "pubtime": "2026-09-04T14:31:21Z" + } + ] + }, + { + "path": "zs/td/zstd-sys", + "header": "AwIAAABldGFnOiAiMTg5MDU1YTAwMGI5YjQ3YzRiYjEwMjEwYTk3NWIyMDUiAA==", + "records": [ + { + "name": "zstd-sys", + "vers": "2.1.1+zstd.1.5.7", + "deps": [ + { + "name": "bindgen", + "req": "^0.73.2", + "features": ["runtime"], + "optional": true, + "default_features": false, + "target": null, + "kind": "build" + }, + { + "name": "cc", + "req": "^1.0.45", + "features": ["parallel"], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "cmake", + "req": "^0.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "pkg-config", + "req": "^0.3.28", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "aeec9eaf2dffbbd09201e23bd0ffcbaa33bb8e9266a10734fd7ed90a85eca078", + "features": { + "debug": [], + "default": ["legacy", "zdict_builder"], + "experimental": [], + "fat-lto": [], + "legacy": [], + "no_asm": [], + "no_wasm_shim": [], + "non-cargo": [], + "pkg-config": [], + "seekable": [], + "std": [], + "thin": [], + "thin-lto": [], + "vendored": [], + "zdict_builder": [], + "zstdmt": [] + }, + "features2": { + "cmake": ["dep:cmake"] + }, + "yanked": false, + "links": "zstd", + "rust_version": "1.64", + "pubtime": "2026-10-09T14:57:47Z", + "v": 2 + } + ] + } + ] +} diff --git a/build_defs/languages/installed/wasix/server/Cargo.lock b/build_defs/languages/installed/wasix/server/Cargo.lock new file mode 100644 index 000000000..7b994eb86 --- /dev/null +++ b/build_defs/languages/installed/wasix/server/Cargo.lock @@ -0,0 +1,4880 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" +dependencies = [ + "gimli 0.32.3", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "ambient-authority" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9d4ee0d472d1cd2e28c97dfa124b3d8d992e10eb0a035f33f5d12e3a177ba3b" + +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", +] + +[[package]] +name = "any_ascii" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70033777eb8b5124a81a1889416543dddef2de240019b674c81285a2635a7e1e" + +[[package]] +name = "anyhow" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + +[[package]] +name = "async-trait" +version = "0.1.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "backtrace" +version = "0.3.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide 0.8.9", + "object 0.37.3", + "rustc-demangle", + "windows-link", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bincode" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" +dependencies = [ + "bincode_derive", + "serde", + "unty", +] + +[[package]] +name = "bincode_derive" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" +dependencies = [ + "virtue", +] + +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags 2.13.2", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex 1.3.0", + "syn 2.0.119", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" + +[[package]] +name = "blake3" +version = "1.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d9e454fc11f76977dc803893aff6304ed33d6a26efae8696573bea74baa27ae" +dependencies = [ + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "cpufeatures 0.3.1", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "bstr" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bb31b46c14244e20ee9984b11bf5c992b91fb6939fea616e3512c8baecdbe5f" +dependencies = [ + "memchr", + "serde_core", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "bus" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b7118d0221d84fada881b657c2ddb7cd55108db79c8764c9ee212c0c259b783" +dependencies = [ + "crossbeam-channel", + "num_cpus", + "parking_lot_core", +] + +[[package]] +name = "bytecheck" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26333eeac754f0ad8a6bcd0eb0ac012156302e4e16b852b72ee399aea4f12c29" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "rancor", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46d07918caa9eeaaf06b7873925c53a61daac173539b4f7715090745e44e4e69" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" +dependencies = [ + "serde", +] + +[[package]] +name = "bytesize" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7354288c522e7e980fafd2075d63d1285794c3a6a16cdd492f189ea406e5f18b" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cap-fs-ext" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ff379b70af8e08307a8f65e7040c7301cb4a572538ade16b4984f0da77847f" +dependencies = [ + "cap-primitives", + "cap-std", + "io-lifetimes 3.0.1", + "windows-sys 0.61.2", +] + +[[package]] +name = "cap-primitives" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b5f74729fd2f44701d1a8eb47e906cdb3ccd9ec0f02baad85a744b791940b18" +dependencies = [ + "ambient-authority", + "fs-set-times", + "io-extras", + "io-lifetimes 3.0.1", + "ipnet", + "maybe-owned", + "rustix", + "rustix-linux-procfs", + "windows-sys 0.61.2", + "winx", +] + +[[package]] +name = "cap-std" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ec78e242cfa2cfe276807ac2ecc00315a6c97786977414bcd1c3963b6c91b8" +dependencies = [ + "cap-primitives", + "io-extras", + "io-lifetimes 3.0.1", + "rustix", +] + +[[package]] +name = "cc" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6651c9ed80effdc7db0ff72512157f901af5e3549e341e24b1dd4887d836d838" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex 2.0.1", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom 7.1.3", +] + +[[package]] +name = "cfg-if" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" + +[[package]] +name = "chacha20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "rand_core 0.10.1", +] + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "num-traits", +] + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clang-sys" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "157a8ba7b480713b56f4c09fd13fc3e0a22a5dfab8097ba61cbc5feef950788a" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9c751b79415d4e559e3d1fcf128e09e720eb673a06d26cf6f392d37d75b66e0" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "clap_lex" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486" + +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] + +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + +[[package]] +name = "console" +version = "0.16.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e96a4956774c13c126a8b5af4daa79384f4d826534c95a02d76afb39e2ab64e3" +dependencies = [ + "encode_unicode", + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + +[[package]] +name = "convert_case" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "cooked-waker" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f" + +[[package]] +name = "corosensei" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6886a0c0f263965933c438626e7179139a62b978a33aa18281cbf0cd5a975f34" +dependencies = [ + "autocfg", + "cfg-if", + "libc", + "scopeguard", + "windows-sys 0.59.0", +] + +[[package]] +name = "cpp_demangle" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2bb79cb74d735044c972aae58ed0aaa9a837e85b01106a54c39e42e97f62253" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" + +[[package]] +name = "crc32fast" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01a7799fd6b852db0e61728dde9a204c423b44d689dbd432522543614b490e78" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98b0cc327b5bc766e7fda9c9260cc0fa81b43a8e240440422dff70788e3f9ef1" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e8bd762f7479489c70ed6c768ddca99d7296857de437a68dcb2a94365b3fae" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "ctutils" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03bb0e1cc970d482d121d9a1744999169b69a07470b3d644a7894e53fcaf4574" +dependencies = [ + "cmov", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core 0.20.11", + "darling_macro 0.20.11", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core 0.21.3", + "darling_macro 0.21.3", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.119", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core 0.20.11", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core 0.21.3", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "dashmap" +version = "6.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "uuid", +] + +[[package]] +name = "defmt" +version = "0.3.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad" +dependencies = [ + "defmt 1.1.1", +] + +[[package]] +name = "defmt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8" +dependencies = [ + "defmt-parser", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" + +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling 0.20.11", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn 2.0.119", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.119", + "unicode-xid", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common 0.1.7", + "subtle", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "const-oid", + "crypto-common 0.2.2", + "ctutils", +] + +[[package]] +name = "directories" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", +] + +[[package]] +name = "displaydoc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "either" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be" +dependencies = [ + "serde", +] + +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "enum-iterator" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4549325971814bda7a44061bf3fe7e487d447cba01e4220a4b454d630d7a016" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "enumset" +version = "1.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccc5801fd11762e24d1e420d01d2ac518f2a2ca4329d4fbb6639f2412b6204e0" +dependencies = [ + "enumset_derive", +] + +[[package]] +name = "enumset_derive" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bd536557b58c682b217b8fb199afdff47cd3eff260623f19e77074eb073d63a" +dependencies = [ + "darling 0.21.3", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "escape8259" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f0d310082fd5de539d4f41601182241147498444a7695c520288a0cdbead6" + +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + +[[package]] +name = "event-listener" +version = "5.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" +dependencies = [ + "parking", + "pin-project-lite", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + +[[package]] +name = "filetime" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759" +dependencies = [ + "cfg-if", + "libc", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484" + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "flate2" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb" +dependencies = [ + "crc32fast", + "miniz_oxide 0.9.1", + "zlib-rs", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs-set-times" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94e7099f6313ecacbe1256e8ff9d617b75d1bcb16a6fddef94866d225a01a14a" +dependencies = [ + "io-lifetimes 2.0.4", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "futures" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-executor" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" + +[[package]] +name = "futures-macro" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "futures-sink" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 5.3.0", + "wasip2", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 6.0.0", + "rand_core 0.10.1", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" + +[[package]] +name = "gimli" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7f043f89559805f8c7cacc432749b2fa0d0a0a9ee46ce47164ed5ba7f126c" +dependencies = [ + "fnv", + "hashbrown 0.16.1", + "indexmap", + "stable_deref_trait", +] + +[[package]] +name = "glob" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" + +[[package]] +name = "globset" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07c34a9410465b45bd9787443bc7370f37735bad04b0f0cd57ff1a3186c98988" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "foldhash 0.2.0", +] + +[[package]] +name = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.5", +] + +[[package]] +name = "heapless" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ba4bd83f9415b58b4ed8dc5714c76e626a105be4646c02630ad730ad3b5aa4" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac 0.12.1", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "hmac" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" +dependencies = [ + "digest 0.11.3", +] + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "http" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "hybrid-array" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17" +dependencies = [ + "typenum", +] + +[[package]] +name = "icu_collections" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" + +[[package]] +name = "icu_properties" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" + +[[package]] +name = "icu_provider" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "ignore" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b69833ed729dc5aa7d19541d96d6cf8e9137194207a04916d658e43168402f" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata", + "same-file", + "walkdir", + "winapi-util", +] + +[[package]] +name = "indexmap" +version = "2.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", + "serde", + "serde_core", +] + +[[package]] +name = "insta" +version = "1.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67d3d2e287e4b86c10b3f3b641033d1f89b74bdb39d05f34952e2b9a6fe21cd" +dependencies = [ + "console", + "once_cell", + "regex", + "serde", + "similar", + "strip-ansi-escapes", + "tempfile", +] + +[[package]] +name = "io-extras" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20fd6de4ccfcc187e38bc21cfa543cb5a302cb86a8b114eb7f0bf0dc9f8ac00f" +dependencies = [ + "io-lifetimes 3.0.1", + "windows-sys 0.60.2", +] + +[[package]] +name = "io-lifetimes" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06432fb54d3be7964ecd3649233cddf80db2832f47fec34c01f65b3d9d774983" + +[[package]] +name = "io-lifetimes" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0fb0570afe1fed943c5c3d4102d5358592d8625fda6a0007fdbe65a92fba96" + +[[package]] +name = "ipnet" +version = "2.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791930b43c0d5973160d90a8f3894509f2b273430f5c5c73b668636d0287c5c0" + +[[package]] +name = "iprange" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37209be0ad225457e63814401415e748e2453a5297f9b637338f5fb8afa4ec00" +dependencies = [ + "ipnet", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b4baf93f58d4425749ca49a51c50ebab072c5df6994d08fed93541c331481dc" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jobserver" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" +dependencies = [ + "getrandom 0.4.3", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7883d941dae510fb2d978fc3fe018c71c9e2892fd38854de3e8b92c2e5ad9cc5" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "leb128" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c83bff1d572d6b9aeef67ddfc8448e4a3737909cb28e81f97c791b9018703e52" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "lexical-sort" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c09e4591611e231daf4d4c685a66cb0410cc1e502027a20ae55f2bb9e997207a" +dependencies = [ + "any_ascii", +] + +[[package]] +name = "libc" +version = "0.2.190" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "liboliphaunt-wasix-aot-aarch64-apple-darwin" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835ede81ff81dcfb2767878209a1c372b7e3338c401595cf179aa68e1f1cc0c7" +dependencies = [ + "serde_json", + "sha2 0.10.9", +] + +[[package]] +name = "liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b15cb79e689f5f0eab69f5acd92f68f61ae57d9f3bfa4cc18658a6d1bb67ad" +dependencies = [ + "serde_json", + "sha2 0.10.9", +] + +[[package]] +name = "liboliphaunt-wasix-aot-x86_64-pc-windows-msvc" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c7a811a634a1b0d686369cbaefa8dabbfe5825fc4a03140ddda7beb3343bd30" +dependencies = [ + "serde_json", + "sha2 0.10.9", +] + +[[package]] +name = "liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e56a349c5c888ad65a623cbce954e13ae6dcead6ea846fc63202158f815976d" +dependencies = [ + "serde_json", + "sha2 0.10.9", +] + +[[package]] +name = "liboliphaunt-wasix-portable" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ebe15bd97751ed6c63ae25067c6a92a2266fa861d295d9d45844260acba30b" +dependencies = [ + "oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "oliphaunt-extension-contrib-pg18-aot-linux-x64", + "oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "oliphaunt-extension-contrib-pg18-aot-windows-x64", + "oliphaunt-extension-contrib-pg18-wasix", + "serde", + "serde_json", + "sha2 0.10.9", +] + +[[package]] +name = "libredox" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ff90caf6077a803a240f62fdbe88645a890bbca49ef8174c3cb0404362171d" +dependencies = [ + "bitflags 2.13.2", + "libc", + "plain", + "redox_syscall 0.9.4", +] + +[[package]] +name = "libtest-mimic" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14e6ba06f0ade6e504aff834d7c34298e5155c6baca353cc6a4aaff2f9fd7f33" +dependencies = [ + "anstream", + "anstyle", + "clap", + "escape8259", +] + +[[package]] +name = "libunwind" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6639b70a7ce854b79c70d7e83f16b5dc0137cc914f3d7d03803b513ecc67ac" + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linked_hash_set" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "984fb35d06508d1e69fc91050cceba9c0b748f983e6739fa2c7a9237154c52c8" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" + +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" + +[[package]] +name = "lz4_flex" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef0d4ed8669f8f8826eb00dc878084aa8f253506c4fd5e8f58f5bce72ddb97e" +dependencies = [ + "twox-hash", +] + +[[package]] +name = "mach2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44" +dependencies = [ + "libc", +] + +[[package]] +name = "mach2" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b" + +[[package]] +name = "macho-unwind-info" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149" +dependencies = [ + "thiserror", + "zerocopy", + "zerocopy-derive", +] + +[[package]] +name = "managed" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" + +[[package]] +name = "maybe-owned" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4" + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest 0.10.7", +] + +[[package]] +name = "md-5" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98" +dependencies = [ + "cfg-if", + "digest 0.11.3", +] + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "memmap2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d28bba84adfe6646737845bc5ebbfa2c08424eb1c37e94a1fd2a82adb56a872" +dependencies = [ + "libc", +] + +[[package]] +name = "memmap2" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "miniz_oxide" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1788edb87fdc09c7e26304471e2f5be8cdefb1b6930d6e3985fc02ff53bf86ee" +dependencies = [ + "libc", + "log", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.61.2", +] + +[[package]] +name = "more-asserts" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e" + +[[package]] +name = "munge" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c" +dependencies = [ + "munge_macro", +] + +[[package]] +name = "munge_macro" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "nom" +version = "5.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b" +dependencies = [ + "memchr", + "version_check", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.13.2", +] + +[[package]] +name = "objc2-system-configuration" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7216bd11cbda54ccabcab84d523dc93b858ec75ecfb3a7d89513fa22464da396" +dependencies = [ + "objc2-core-foundation", +] + +[[package]] +name = "object" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +dependencies = [ + "memchr", +] + +[[package]] +name = "object" +version = "0.39.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b" +dependencies = [ + "crc32fast", + "flate2", + "hashbrown 0.17.1", + "indexmap", + "memchr", + "ruzstd", +] + +[[package]] +name = "oliphaunt-extension-contrib-pg18-aot-linux-arm64" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6593cd36d8c9cb83d2098ef5f62005bb62861f05bcd3d7238f5bcccbc11cdfd3" +dependencies = [ + "sha2 0.10.9", +] + +[[package]] +name = "oliphaunt-extension-contrib-pg18-aot-linux-x64" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "238580b3fed00f8537e64c1c6548d74d33b544a322946879a8821eed7f4dc792" +dependencies = [ + "sha2 0.10.9", +] + +[[package]] +name = "oliphaunt-extension-contrib-pg18-aot-macos-arm64" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41bef2ac428e3b7f2149d1c342135c573a9dbd9c592eebaea3e0083f3840c64c" +dependencies = [ + "sha2 0.10.9", +] + +[[package]] +name = "oliphaunt-extension-contrib-pg18-aot-windows-x64" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "623d461eda99618bda616e1f488160d0fa6833215676f73dc0c134a29c283cbd" +dependencies = [ + "sha2 0.10.9", +] + +[[package]] +name = "oliphaunt-extension-contrib-pg18-wasix" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2cbf8c683ae8b380f11f4fa7581c41eddb370ab4d94cbba07d169c2ab7778" +dependencies = [ + "sha2 0.10.9", +] + +[[package]] +name = "oliphaunt-icu" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976fdebc00bbd4dc456e3e77dafb51886798048b648ed3f8b5f22aac8c83a587" +dependencies = [ + "sha2 0.10.9", + "tar", + "zstd", +] + +[[package]] +name = "oliphaunt-pgwire-server" +version = "0.2.1" +dependencies = [ + "anyhow", + "futures-util", + "oliphaunt-query", + "oliphaunt-wasix", + "serde_json", + "sqlx", + "tempfile", + "tokio", + "tokio-postgres", + "tracing", +] + +[[package]] +name = "oliphaunt-query" +version = "0.1.1" + +[[package]] +name = "oliphaunt-wasix" +version = "0.3.2" +dependencies = [ + "anyhow", + "async-trait", + "cap-fs-ext", + "cap-std", + "directories", + "dunce", + "filetime", + "flate2", + "liboliphaunt-wasix-aot-aarch64-apple-darwin", + "liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu", + "liboliphaunt-wasix-aot-x86_64-pc-windows-msvc", + "liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu", + "liboliphaunt-wasix-portable", + "oliphaunt-icu", + "oliphaunt-query", + "serde", + "serde_json", + "sha2 0.10.9", + "tar", + "tempfile", + "tokio", + "tracing", + "virtual-fs", + "virtual-mio", + "virtual-net", + "wasmer", + "wasmer-config", + "wasmer-journal", + "wasmer-package", + "wasmer-types", + "wasmer-wasix", + "wasmer-wasix-types", + "webc", + "zstd", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.18", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "path-clean" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "petgraph" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" +dependencies = [ + "fixedbitset", + "hashbrown 0.15.5", + "indexmap", + "serde", +] + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_shared", + "serde", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pin-utils" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13bee6c73da26345c729282832b60b0363cf3dd9f4bfd81d8551b7a1c889a113" + +[[package]] +name = "pkg-config" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "postgres-protocol" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08808e3c483c46e999108051c78334f473d5adb59d78bb80a1268c7e6aa6c514" +dependencies = [ + "base64", + "byteorder", + "bytes", + "fallible-iterator", + "hmac 0.13.0", + "md-5 0.11.0", + "memchr", + "rand 0.10.3", + "sha2 0.11.0", + "stringprep", +] + +[[package]] +name = "postgres-types" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "851ca9db4932932d69f3ea811b1abe63087a0f740a47692619dd40d4899b68be" +dependencies = [ + "bytes", + "fallible-iterator", + "postgres-protocol", +] + +[[package]] +name = "potential_utf" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a6394b9e965e73d0a289ee54f589087e2c676aedf60885baf52c76b771e4958" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.119", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "ptr_meta" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743da816b98c921cdbe8628ef7381b76f25ecf4da599fc80aca90eae7ef70cc0" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c8d9ca532f185d5d4db7a7c9d51420b452168ea1c2b913953281bd6fe1fcbd0" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "pulldown-cmark" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8" +dependencies = [ + "bitflags 1.3.2", + "memchr", + "unicase", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rancor" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b534442d0fcdb55d66f373d9cac6d33b6293a2335bc2136dbd06ce0e87d2572" +dependencies = [ + "ptr_meta", +] + +[[package]] +name = "rand" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rangemap" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a611d15b50743feb4c76b7d03edcb0e64f399c26961e4efe6975bc398be6aa3d" + +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.13.2", +] + +[[package]] +name = "redox_syscall" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "737970939a87c6fa31e7acad13307bccbb017a073b695b6089a2c484f929e20e" +dependencies = [ + "bitflags 2.13.2", +] + +[[package]] +name = "redox_users" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60dc65c0ff1a7ae1294b0c67b9f14baf70b644404010370171787bfac1038fc0" +dependencies = [ + "libredox", + "thiserror", +] + +[[package]] +name = "ref-cast" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "regex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "region" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7" +dependencies = [ + "bitflags 1.3.2", + "libc", + "mach2 0.4.3", + "windows-sys 0.52.0", +] + +[[package]] +name = "rend" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "663ba70707f96e871406fe10d68128412e619b06d1d47cb91c3a4c6501176240" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "replace_with" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51743d3e274e2b18df81c4dc6caf8a5b8e15dbe799e0dca05c7617380094e884" + +[[package]] +name = "rkyv" +version = "0.8.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9776093b7ca170454ab1406954f7b7d97a57c51dc6c0642957fb2ef25c2d399" +dependencies = [ + "bytecheck", + "bytes", + "hashbrown 0.17.1", + "indexmap", + "munge", + "ptr_meta", + "rancor", + "rend", + "rkyv_derive", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.8.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c25ef604ac7dd839d44d64648952ea23c97866f124ff671b0ed2cf3ad9bb06e" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb" + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d" +dependencies = [ + "bitflags 2.13.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustix-linux-procfs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc84bf7e9aa16c4f2c758f27412dc9841341e16aa682d9c7ac308fe3ee12056" +dependencies = [ + "once_cell", + "rustix", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "rusty_pool" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ed36cdb20de66d89a17ea04b8883fc7a386f2cf877aaedca5005583ce4876ff" +dependencies = [ + "crossbeam-channel", + "futures", + "futures-channel", + "futures-executor", + "num_cpus", +] + +[[package]] +name = "ruzstd" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7c1c839d570d835527c9a5e4db7cb2198683a988cb9d7293fc8674e6bd58fc8" +dependencies = [ + "twox-hash", +] + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "saffron" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03fb9a628596fc7590eb7edbf7b0613287be78df107f5f97b118aad59fb2eea9" +dependencies = [ + "chrono", + "nom 5.1.3", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schemars" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a" +dependencies = [ + "dyn-clone", + "indexmap", + "ref-cast", + "schemars_derive", + "serde", + "serde_json", + "url", +] + +[[package]] +name = "schemars_derive" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98c67716b46af2f0b8cf752abc930f6f9aecfbf671ecfb531db8a31dbe4e2ba" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 3.0.8", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "self_cell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab42ca02749e120097e328d91d415325bdf43b1c72c4c8badf37375fe40a813" + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "serde_derive_internals" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f852137cce035d6a4df67ccce505ff6b3e9fd3a10e3e52b24dc71e650bb1a9bd" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "serde_json" +version = "1.0.154" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7523beb55eece201a2356bee0bbca0d1ab466c14c07703b2e0ee6d42cb0c2c" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "digest 0.11.3", +] + +[[package]] +name = "shared-buffer" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6c99835bad52957e7aa241d3975ed17c1e5f8c92026377d117a606f36b84b16" +dependencies = [ + "bytes", + "memmap2 0.6.2", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "simd-adler32" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "similar" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" + +[[package]] +name = "siphasher" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33f4fe9184a62d842c9ef383018f3306d8ba224fd9d836f56d7288308847c256" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b3dc8af474f516a851ff4bd12db780f948b9250ad37211e4eec0bccea54e01b" +dependencies = [ + "serde", +] + +[[package]] +name = "smoltcp" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f73d40463bba65efc9adc6370b56df76d563cc46e2482bba58351b4afb7535e" +dependencies = [ + "bitflags 1.3.2", + "byteorder", + "cfg-if", + "defmt 0.3.100", + "heapless", + "managed", +] + +[[package]] +name = "socket2" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "sqlx" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-postgres", +] + +[[package]] +name = "sqlx-core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" +dependencies = [ + "base64", + "bytes", + "crc", + "crossbeam-queue", + "either", + "event-listener", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.15.5", + "hashlink", + "indexmap", + "log", + "memchr", + "once_cell", + "percent-encoding", + "serde", + "serde_json", + "sha2 0.10.9", + "smallvec", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "url", +] + +[[package]] +name = "sqlx-macros" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 2.0.119", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" +dependencies = [ + "dotenvy", + "either", + "heck 0.5.0", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2 0.10.9", + "sqlx-core", + "sqlx-postgres", + "syn 2.0.119", + "tokio", + "url", +] + +[[package]] +name = "sqlx-postgres" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" +dependencies = [ + "atoi", + "base64", + "bitflags 2.13.2", + "byteorder", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac 0.12.1", + "home", + "itoa", + "log", + "md-5 0.10.6", + "memchr", + "once_cell", + "rand 0.8.8", + "serde", + "serde_json", + "sha2 0.10.9", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami 1.6.1", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[package]] +name = "strip-ansi-escapes" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a8f8038e7e7969abb3f1b7c2a811225e9296da208539e0f79c5251d6cac0025" +dependencies = [ + "vte", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "symbolic-common" +version = "13.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfa0014ff4e423a1bb8881453c7a29181eb14fe1dbc8e0197ebfa081903f3ed" +dependencies = [ + "debugid", + "memmap2 0.9.11", + "stable_deref_trait", + "uuid", +] + +[[package]] +name = "symbolic-demangle" +version = "13.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a213276280a1a737ff5fb89ae2a70ba51d1d4608e74736beb92f257f125f1aa" +dependencies = [ + "bitflags 2.13.2", + "cpp_demangle", + "itoa", + "rustc-demangle", + "symbolic-common", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01016da373cd8f7ef12624f796309f5c31ba8d646dd08856c02cd741d823c622" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "tar" +version = "0.4.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "target-lexicon" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.3", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "terminal_size" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874" +dependencies = [ + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "termios" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b" +dependencies = [ + "libc", +] + +[[package]] +name = "thiserror" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "time" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + +[[package]] +name = "time-macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" + +[[package]] +name = "tokio" +version = "1.53.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e95f91fcc7a621e8b030f6aa23c71fe9838ae2fb4d8118b75602a328f5144044" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "tokio-postgres" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a528f7d280f6d5b9cd149635c8705b0dd049754bc67d81d31fa25169a93809d3" +dependencies = [ + "async-trait", + "byteorder", + "bytes", + "fallible-iterator", + "futures-channel", + "futures-util", + "log", + "parking_lot", + "percent-encoding", + "phf", + "pin-project-lite", + "postgres-protocol", + "postgres-types", + "rand 0.10.3", + "socket2", + "tokio", + "tokio-util", + "whoami 2.1.3", +] + +[[package]] +name = "tokio-stream" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3d06f0b082ba57c26b79407372e57cf2a1e28124f78e9479fe80322cf53420b" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-util" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e464cf451ba96ebfc6f9b6542f17ee8b8956e33f1e40d9690624e59d7a7f8a4b" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "libc", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "1.1.8+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20489e00e4d8741d6be680764cc12e270655e375a20d1011e844a9c3379e678d" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b86d767906c6c42421dcba507eb9d203e779497710a47782a224bb871653053" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.17+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3641d5bbb5349a79e1020a242d251efbc546ad8048d133958323ce9c40a9c9c" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.1.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baa693a8032d7e1cada7d0041e96126df243179ff061456783ac7f12bda4744c" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.1.3+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06bdbd8cfc056b8d2e2e85f29b56a3bdbecb527cef81eb39e3e7b98af4652770" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "twox-hash" +version = "2.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86a801b3cea342a06d468c8710662aa29e5e05e4f5c0d62f00bbb7f2ad7941c2" + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicase" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357cc3acc6a036009fd6c973ed009037c732d60d0b4f6c673e9041497482a28f" + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-ident" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" + +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", + "serde_derive", +] + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cc1186384beb7dd8eedea376413fd654937285ea6c9cfbb928dc3043ea4b606" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "virtual-fs" +version = "0.702.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18f2136946b8a66d2bc7548fc4396c72e7a8671e8ab878342f5483e6c6dfd61f" +dependencies = [ + "anyhow", + "async-trait", + "bytes", + "dashmap", + "derive_more", + "dunce", + "futures", + "getrandom 0.4.3", + "indexmap", + "pin-project-lite", + "replace_with", + "shared-buffer", + "slab", + "thiserror", + "tokio", + "tracing", + "virtual-mio", + "wasmer-package", + "webc", +] + +[[package]] +name = "virtual-mio" +version = "0.702.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b449ceba2087fe0a7e436b9f1105dd9868addb294ff96a4a28100eadb9442b15" +dependencies = [ + "async-trait", + "bytes", + "futures", + "mio", + "parking", + "serde", + "socket2", + "thiserror", + "tracing", +] + +[[package]] +name = "virtual-net" +version = "0.702.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb377443085e3e30d0e3357a8d55925da670d070a04c9dd2284236a20cf308f1" +dependencies = [ + "anyhow", + "async-trait", + "base64", + "bincode", + "bytecheck", + "bytes", + "derive_more", + "futures-util", + "ipnet", + "iprange", + "libc", + "mio", + "pin-project-lite", + "rkyv", + "serde", + "smoltcp", + "socket2", + "thiserror", + "tokio", + "tracing", + "virtual-mio", +] + +[[package]] +name = "virtue" +version = "0.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" + +[[package]] +name = "vte" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "231fdcd7ef3037e8330d8e17e61011a2c244126acc0a982f4040ac3f9f0bc077" +dependencies = [ + "memchr", +] + +[[package]] +name = "wai-bindgen-gen-core" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa3dc41b510811122b3088197234c27e08fcad63ef936306dd8e11e2803876c" +dependencies = [ + "anyhow", + "wai-parser", +] + +[[package]] +name = "wai-bindgen-gen-rust" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19bc05e8380515c4337c40ef03b2ff233e391315b178a320de8640703d522efe" +dependencies = [ + "heck 0.3.3", + "wai-bindgen-gen-core", +] + +[[package]] +name = "wai-bindgen-gen-rust-wasm" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f35ce5e74086fac87f3a7bd50f643f00fe3559adb75c88521ecaa01c8a6199" +dependencies = [ + "heck 0.3.3", + "wai-bindgen-gen-core", + "wai-bindgen-gen-rust", +] + +[[package]] +name = "wai-bindgen-rust" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e5601c6f448c063e83a5e931b8fefcdf7e01ada424ad42372c948d2e3d67741" +dependencies = [ + "bitflags 1.3.2", + "wai-bindgen-rust-impl", +] + +[[package]] +name = "wai-bindgen-rust-impl" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdeeb5c1170246de8425a3e123e7ef260dc05ba2b522a1d369fe2315376efea4" +dependencies = [ + "proc-macro2", + "syn 1.0.109", + "wai-bindgen-gen-core", + "wai-bindgen-gen-rust-wasm", +] + +[[package]] +name = "wai-parser" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd0acb6d70885ea0c343749019ba74f015f64a9d30542e66db69b49b7e28186" +dependencies = [ + "anyhow", + "id-arena", + "pulldown-cmark", + "unicode-normalization", + "unicode-xid", +] + +[[package]] +name = "waker-fn" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasi" +version = "0.14.7+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" +dependencies = [ + "wasip2", +] + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + +[[package]] +name = "wasite" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fe902b4a6b8028a753d5424909b764ccf79b7a209eac9bf97e59cda9f71a42" +dependencies = [ + "wasi 0.14.7+wasi-0.2.4", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb54f33acc68fd454578d9820b0bde1a1a3d17aa17bb7b6595806d02886d409" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e29d0c35b16e224a7eeb5cd2d25e3e1968fbd65604117b44d3b789d00ee8535" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f501a8bc3719dba86ef8ae4728879c08001bea749eb1333ac5b91e040e2a6b7" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 3.0.8", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.129" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23f0c9c52aa7cd7d77769a4cfe2a9adb1b331f489a41d912ce14513d5ab995c6" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.252.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8185ae345fa5687c054626ff9a50e7089797a343d9904d1dc9820eb4c4d3196f" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasmer" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05af716b1bf3de5b8081133223f77f37916e9b4f41e0781c7fbe3e0d7b6da43a" +dependencies = [ + "bindgen", + "bytes", + "cfg-if", + "cmake", + "corosensei", + "dashmap", + "derive_more", + "futures", + "indexmap", + "itertools 0.15.0", + "js-sys", + "more-asserts", + "paste", + "rkyv", + "serde", + "serde-wasm-bindgen", + "shared-buffer", + "symbolic-demangle", + "tar", + "target-lexicon", + "thiserror", + "tracing", + "wasm-bindgen", + "wasmer-compiler", + "wasmer-derive", + "wasmer-types", + "wasmer-vm", + "windows-sys 0.61.2", +] + +[[package]] +name = "wasmer-compiler" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d984ed2ecd52a8e68ea0f4959bc342bf3b2381262105898a8cb416ecd15003" +dependencies = [ + "backtrace", + "bytes", + "cfg-if", + "crossbeam-channel", + "enum-iterator", + "enumset", + "itertools 0.15.0", + "leb128", + "libc", + "macho-unwind-info", + "memmap2 0.9.11", + "more-asserts", + "object 0.39.1", + "rangemap", + "rayon", + "region", + "rkyv", + "self_cell", + "shared-buffer", + "smallvec", + "target-lexicon", + "tempfile", + "thiserror", + "wasmer-types", + "wasmer-vm", + "wasmparser", + "which", + "windows-sys 0.61.2", +] + +[[package]] +name = "wasmer-config" +version = "0.702.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98700e4516eb825f1ad22cd5273bafd0694941722686010dc1af79b70812393f" +dependencies = [ + "anyhow", + "bytesize", + "ciborium", + "derive_builder", + "hex", + "indexmap", + "saffron", + "schemars", + "semver", + "serde", + "serde_json", + "serde_yaml", + "thiserror", + "toml", + "url", +] + +[[package]] +name = "wasmer-derive" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882cc3b1909d543b4c5cd84c21d659c9c3608225240a79b68e39554749592b79" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "wasmer-journal" +version = "0.702.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d02acd34af8c89ce772dd492da754dc999d4e3d3f30cbbf11a9c58f5e6c3a659" +dependencies = [ + "anyhow", + "async-trait", + "base64", + "bincode", + "bytecheck", + "bytes", + "derive_more", + "lz4_flex", + "num_enum", + "rkyv", + "serde", + "serde_json", + "thiserror", + "tracing", + "virtual-fs", + "virtual-net", + "wasmer", + "wasmer-config", + "wasmer-wasix-types", +] + +[[package]] +name = "wasmer-package" +version = "0.702.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54f12fd1711df6b12ade23b5db433d3f1aae4f31a7580d7db480f2cce03ccdb1" +dependencies = [ + "anyhow", + "bytes", + "cfg-if", + "ciborium", + "flate2", + "ignore", + "insta", + "libc", + "semver", + "serde", + "serde_json", + "sha2 0.11.0", + "shared-buffer", + "tar", + "tempfile", + "thiserror", + "toml", + "url", + "wasmer-config", + "wasmer-types", + "webc", +] + +[[package]] +name = "wasmer-types" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87234e5a975dc1343c08692165e01def9725a74cf527277c0e36b0eb66b8f427" +dependencies = [ + "bytecheck", + "crc32fast", + "enum-iterator", + "enumset", + "getrandom 0.4.3", + "hex", + "indexmap", + "itertools 0.15.0", + "more-asserts", + "rkyv", + "serde", + "sha2 0.11.0", + "target-lexicon", + "thiserror", + "wasmparser", +] + +[[package]] +name = "wasmer-vm" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8112dae928ca0d5341180e1ea1418d78bdb3788a78da625a4a3889fe908a91bb" +dependencies = [ + "backtrace", + "bytesize", + "cc", + "cfg-if", + "corosensei", + "crossbeam-queue", + "dashmap", + "enum-iterator", + "fnv", + "gimli 0.33.0", + "indexmap", + "itertools 0.15.0", + "libc", + "libunwind", + "mach2 0.6.0", + "memoffset", + "more-asserts", + "parking_lot", + "region", + "rustversion", + "scopeguard", + "thiserror", + "wasmer-types", + "windows-sys 0.61.2", +] + +[[package]] +name = "wasmer-wasix" +version = "0.702.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90a93bb66bc9bb1c766d53c68676f8a4f23582b0feef6135c184dfd3bf762e2e" +dependencies = [ + "anyhow", + "async-trait", + "base64", + "bincode", + "blake3", + "bus", + "bytecheck", + "bytes", + "cfg-if", + "cooked-waker", + "crossbeam-channel", + "dashmap", + "derive_more", + "flate2", + "fnv", + "fs_extra", + "futures", + "getrandom 0.3.4", + "getrandom 0.4.3", + "heapless", + "hex", + "http", + "itertools 0.15.0", + "libc", + "libtest-mimic", + "linked_hash_set", + "lz4_flex", + "num_enum", + "once_cell", + "petgraph", + "pin-project", + "pin-utils", + "rand 0.10.3", + "rkyv", + "rusty_pool", + "semver", + "serde", + "serde_derive", + "serde_json", + "serde_yaml", + "sha2 0.11.0", + "shared-buffer", + "tempfile", + "terminal_size", + "termios", + "thiserror", + "tokio", + "tokio-stream", + "toml", + "tracing", + "url", + "urlencoding", + "virtual-fs", + "virtual-mio", + "virtual-net", + "waker-fn", + "walkdir", + "wasm-encoder", + "wasmer", + "wasmer-config", + "wasmer-journal", + "wasmer-package", + "wasmer-types", + "wasmer-wasix-types", + "wasmparser", + "webc", + "weezl", + "windows-sys 0.61.2", + "xxhash-rust", + "zstd", +] + +[[package]] +name = "wasmer-wasix-types" +version = "0.702.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f982c57b8ccfcb6bc6f7d7ba420bf53a2099ea9c77135b45cdf45198a00c90db" +dependencies = [ + "anyhow", + "bitflags 2.13.2", + "byteorder", + "cfg-if", + "num_enum", + "serde", + "time", + "tracing", + "wai-bindgen-gen-core", + "wai-bindgen-gen-rust", + "wai-bindgen-gen-rust-wasm", + "wai-bindgen-rust", + "wai-parser", + "wasmer", + "wasmer-derive", + "wasmer-types", +] + +[[package]] +name = "wasmparser" +version = "0.252.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3eb099dcadcde5be9eef55e3a337128efd4e44b4c93122487e4d2e4e1c6627c" +dependencies = [ + "bitflags 2.13.2", + "indexmap", +] + +[[package]] +name = "web-sys" +version = "0.3.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88261b9deccee56594c11a3460c462c41f58d148598fe70ad77070126a68aba4" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webc" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cb48ee4bc7a902c0f1d9eb0c0656f0e78149f1190b7f78e1f28256e88279a84" +dependencies = [ + "anyhow", + "base64", + "bytes", + "cfg-if", + "ciborium", + "document-features", + "ignore", + "indexmap", + "leb128", + "lexical-sort", + "libc", + "once_cell", + "path-clean", + "rand 0.9.5", + "serde", + "serde_json", + "sha2 0.10.9", + "shared-buffer", + "thiserror", + "url", +] + +[[package]] +name = "weezl" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4ca08e5ef825b65b056d9efbd95c8750683f0a6d0466d02e96dc2e4e360f3d2" + +[[package]] +name = "which" +version = "8.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bae2f2b2b816647a1cab1acc91f5bd20812d53cb344382635ec2181940c8034f" +dependencies = [ + "libc", +] + +[[package]] +name = "whoami" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" +dependencies = [ + "libredox", + "wasite 0.1.0", +] + +[[package]] +name = "whoami" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626c4bac6755d76ffc12cb01b2eac751db1996b9e0041de9aa02c8c211ddc82c" +dependencies = [ + "libc", + "libredox", + "objc2-system-configuration", + "wasite 1.0.2", + "web-sys", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" +dependencies = [ + "memchr", +] + +[[package]] +name = "winx" +version = "0.36.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f3fd376f71958b862e7afb20cfe5a22830e1963462f3a17f49d82a6c1d1f42d" +dependencies = [ + "bitflags 2.13.2", + "windows-sys 0.59.0", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "writeable" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" + +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + +[[package]] +name = "xxhash-rust" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "550a2b930b62486a393c52d5c3b84bff264b28aa437ed64694d31e93b1757af7" + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", + "synstructure", +] + +[[package]] +name = "zerocopy" +version = "0.8.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86502bf56ac7c77571a32e2647bb2a15894565e981fb2a48d7bde2d91c965a9d" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5457206954b06561e2608c7e19cf58b1926586d999c246eebe4502f7e2039d1a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.8", +] + +[[package]] +name = "zlib-rs" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112" + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d80649ab6db9d9f6f9c80a40becd948eda4714a0a5ac8c4d157a32231c7882" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.1.1+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aeec9eaf2dffbbd09201e23bd0ffcbaa33bb8e9266a10734fd7ed90a85eca078" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/build_defs/languages/installed/wasix/server/registry-index.json b/build_defs/languages/installed/wasix/server/registry-index.json new file mode 100644 index 000000000..fd509a555 --- /dev/null +++ b/build_defs/languages/installed/wasix/server/registry-index.json @@ -0,0 +1,42831 @@ +{ + "schema": "oliphaunt-installed-cargo-fixture-v1", + "cargo": "1.93.1", + "repository": "index.crates.io-1949cf8c6b5b557f", + "target": "x86_64-unknown-linux-gnu", + "archives": [ + { + "name": "addr2line", + "version": "0.25.1" + }, + { + "name": "adler2", + "version": "2.0.1" + }, + { + "name": "aho-corasick", + "version": "1.1.5" + }, + { + "name": "allocator-api2", + "version": "0.2.21" + }, + { + "name": "ambient-authority", + "version": "0.0.2" + }, + { + "name": "anstream", + "version": "1.0.0" + }, + { + "name": "anstyle-parse", + "version": "1.0.0" + }, + { + "name": "anstyle-query", + "version": "1.1.5" + }, + { + "name": "anstyle-wincon", + "version": "3.0.11" + }, + { + "name": "anstyle", + "version": "1.0.14" + }, + { + "name": "any_ascii", + "version": "0.1.7" + }, + { + "name": "anyhow", + "version": "1.0.104" + }, + { + "name": "arrayvec", + "version": "0.7.8" + }, + { + "name": "async-trait", + "version": "0.1.92" + }, + { + "name": "atoi", + "version": "2.0.0" + }, + { + "name": "autocfg", + "version": "1.5.1" + }, + { + "name": "backtrace", + "version": "0.3.76" + }, + { + "name": "base64", + "version": "0.22.1" + }, + { + "name": "bincode_derive", + "version": "2.0.1" + }, + { + "name": "bincode", + "version": "2.0.1" + }, + { + "name": "bindgen", + "version": "0.72.1" + }, + { + "name": "bitflags", + "version": "1.3.2" + }, + { + "name": "bitflags", + "version": "2.13.2" + }, + { + "name": "blake3", + "version": "1.8.7" + }, + { + "name": "block-buffer", + "version": "0.10.4" + }, + { + "name": "block-buffer", + "version": "0.12.1" + }, + { + "name": "bstr", + "version": "1.13.1" + }, + { + "name": "bumpalo", + "version": "3.20.3" + }, + { + "name": "bus", + "version": "2.4.1" + }, + { + "name": "bytecheck_derive", + "version": "0.8.3" + }, + { + "name": "bytecheck", + "version": "0.8.3" + }, + { + "name": "byteorder", + "version": "1.5.0" + }, + { + "name": "bytes", + "version": "1.12.1" + }, + { + "name": "bytesize", + "version": "2.7.0" + }, + { + "name": "cap-fs-ext", + "version": "4.0.3" + }, + { + "name": "cap-primitives", + "version": "4.0.3" + }, + { + "name": "cap-std", + "version": "4.0.3" + }, + { + "name": "cc", + "version": "1.8.0" + }, + { + "name": "cexpr", + "version": "0.6.0" + }, + { + "name": "cfg-if", + "version": "1.0.5" + }, + { + "name": "chacha20", + "version": "0.10.2" + }, + { + "name": "chrono", + "version": "0.4.45" + }, + { + "name": "ciborium-io", + "version": "0.2.2" + }, + { + "name": "ciborium-ll", + "version": "0.2.2" + }, + { + "name": "ciborium", + "version": "0.2.2" + }, + { + "name": "clang-sys", + "version": "1.9.1" + }, + { + "name": "clap_builder", + "version": "4.6.7" + }, + { + "name": "clap_derive", + "version": "4.6.7" + }, + { + "name": "clap_lex", + "version": "1.1.1" + }, + { + "name": "clap", + "version": "4.6.7" + }, + { + "name": "cmake", + "version": "0.1.58" + }, + { + "name": "cmov", + "version": "0.5.4" + }, + { + "name": "colorchoice", + "version": "1.0.5" + }, + { + "name": "console", + "version": "0.16.6" + }, + { + "name": "const-oid", + "version": "0.10.2" + }, + { + "name": "constant_time_eq", + "version": "0.4.2" + }, + { + "name": "convert_case", + "version": "0.10.0" + }, + { + "name": "cooked-waker", + "version": "5.0.0" + }, + { + "name": "corosensei", + "version": "0.3.4" + }, + { + "name": "cpp_demangle", + "version": "0.4.5" + }, + { + "name": "cpufeatures", + "version": "0.2.17" + }, + { + "name": "cpufeatures", + "version": "0.3.1" + }, + { + "name": "crc-catalog", + "version": "2.5.0" + }, + { + "name": "crc", + "version": "3.4.0" + }, + { + "name": "crc32fast", + "version": "1.5.2" + }, + { + "name": "crossbeam-channel", + "version": "0.5.17" + }, + { + "name": "crossbeam-deque", + "version": "0.8.8" + }, + { + "name": "crossbeam-epoch", + "version": "0.9.21" + }, + { + "name": "crossbeam-queue", + "version": "0.3.14" + }, + { + "name": "crossbeam-utils", + "version": "0.8.23" + }, + { + "name": "crunchy", + "version": "0.2.4" + }, + { + "name": "crypto-common", + "version": "0.1.7" + }, + { + "name": "crypto-common", + "version": "0.2.2" + }, + { + "name": "ctutils", + "version": "0.4.3" + }, + { + "name": "darling_core", + "version": "0.20.11" + }, + { + "name": "darling_core", + "version": "0.21.3" + }, + { + "name": "darling_macro", + "version": "0.20.11" + }, + { + "name": "darling_macro", + "version": "0.21.3" + }, + { + "name": "darling", + "version": "0.20.11" + }, + { + "name": "darling", + "version": "0.21.3" + }, + { + "name": "dashmap", + "version": "6.2.1" + }, + { + "name": "debugid", + "version": "0.8.0" + }, + { + "name": "defmt-macros", + "version": "1.1.1" + }, + { + "name": "defmt-parser", + "version": "1.0.0" + }, + { + "name": "defmt", + "version": "0.3.100" + }, + { + "name": "defmt", + "version": "1.1.1" + }, + { + "name": "deranged", + "version": "0.5.8" + }, + { + "name": "derive_builder_core", + "version": "0.20.2" + }, + { + "name": "derive_builder_macro", + "version": "0.20.2" + }, + { + "name": "derive_builder", + "version": "0.20.2" + }, + { + "name": "derive_more-impl", + "version": "2.1.1" + }, + { + "name": "derive_more", + "version": "2.1.1" + }, + { + "name": "digest", + "version": "0.10.7" + }, + { + "name": "digest", + "version": "0.11.3" + }, + { + "name": "directories", + "version": "6.0.0" + }, + { + "name": "dirs-sys", + "version": "0.5.0" + }, + { + "name": "displaydoc", + "version": "0.2.7" + }, + { + "name": "document-features", + "version": "0.2.12" + }, + { + "name": "dotenvy", + "version": "0.15.7" + }, + { + "name": "dunce", + "version": "1.0.5" + }, + { + "name": "dyn-clone", + "version": "1.0.20" + }, + { + "name": "either", + "version": "1.19.0" + }, + { + "name": "encode_unicode", + "version": "1.0.0" + }, + { + "name": "enum-iterator-derive", + "version": "1.5.0" + }, + { + "name": "enum-iterator", + "version": "2.3.0" + }, + { + "name": "enumset_derive", + "version": "0.15.0" + }, + { + "name": "enumset", + "version": "1.1.14" + }, + { + "name": "equivalent", + "version": "1.0.2" + }, + { + "name": "errno", + "version": "0.3.14" + }, + { + "name": "escape8259", + "version": "0.5.4" + }, + { + "name": "etcetera", + "version": "0.8.0" + }, + { + "name": "event-listener", + "version": "5.4.2" + }, + { + "name": "fallible-iterator", + "version": "0.2.0" + }, + { + "name": "fastrand", + "version": "2.5.0" + }, + { + "name": "filetime", + "version": "0.2.29" + }, + { + "name": "find-msvc-tools", + "version": "0.1.14" + }, + { + "name": "fixedbitset", + "version": "0.5.7" + }, + { + "name": "flate2", + "version": "1.1.10" + }, + { + "name": "fnv", + "version": "1.0.7" + }, + { + "name": "foldhash", + "version": "0.1.5" + }, + { + "name": "foldhash", + "version": "0.2.0" + }, + { + "name": "form_urlencoded", + "version": "1.2.2" + }, + { + "name": "fs_extra", + "version": "1.3.0" + }, + { + "name": "fs-set-times", + "version": "0.20.3" + }, + { + "name": "futures-channel", + "version": "0.3.34" + }, + { + "name": "futures-core", + "version": "0.3.34" + }, + { + "name": "futures-executor", + "version": "0.3.34" + }, + { + "name": "futures-intrusive", + "version": "0.5.0" + }, + { + "name": "futures-io", + "version": "0.3.34" + }, + { + "name": "futures-macro", + "version": "0.3.34" + }, + { + "name": "futures-sink", + "version": "0.3.34" + }, + { + "name": "futures-task", + "version": "0.3.34" + }, + { + "name": "futures-util", + "version": "0.3.34" + }, + { + "name": "futures", + "version": "0.3.34" + }, + { + "name": "generic-array", + "version": "0.14.7" + }, + { + "name": "getrandom", + "version": "0.2.17" + }, + { + "name": "getrandom", + "version": "0.3.4" + }, + { + "name": "getrandom", + "version": "0.4.3" + }, + { + "name": "gimli", + "version": "0.32.3" + }, + { + "name": "gimli", + "version": "0.33.0" + }, + { + "name": "glob", + "version": "0.3.4" + }, + { + "name": "globset", + "version": "0.4.20" + }, + { + "name": "half", + "version": "2.7.1" + }, + { + "name": "hash32", + "version": "0.3.1" + }, + { + "name": "hashbrown", + "version": "0.14.5" + }, + { + "name": "hashbrown", + "version": "0.15.5" + }, + { + "name": "hashbrown", + "version": "0.16.1" + }, + { + "name": "hashbrown", + "version": "0.17.1" + }, + { + "name": "hashlink", + "version": "0.10.0" + }, + { + "name": "heapless", + "version": "0.9.3" + }, + { + "name": "heck", + "version": "0.3.3" + }, + { + "name": "heck", + "version": "0.5.0" + }, + { + "name": "hermit-abi", + "version": "0.5.3" + }, + { + "name": "hex", + "version": "0.4.3" + }, + { + "name": "hkdf", + "version": "0.12.4" + }, + { + "name": "hmac", + "version": "0.12.1" + }, + { + "name": "hmac", + "version": "0.13.0" + }, + { + "name": "home", + "version": "0.5.12" + }, + { + "name": "http", + "version": "1.5.0" + }, + { + "name": "hybrid-array", + "version": "0.4.15" + }, + { + "name": "icu_collections", + "version": "2.3.0" + }, + { + "name": "icu_locale_core", + "version": "2.3.0" + }, + { + "name": "icu_normalizer_data", + "version": "2.3.0" + }, + { + "name": "icu_normalizer", + "version": "2.3.0" + }, + { + "name": "icu_properties_data", + "version": "2.3.0" + }, + { + "name": "icu_properties", + "version": "2.3.0" + }, + { + "name": "icu_provider", + "version": "2.3.1" + }, + { + "name": "id-arena", + "version": "2.3.0" + }, + { + "name": "ident_case", + "version": "1.0.1" + }, + { + "name": "idna_adapter", + "version": "1.2.2" + }, + { + "name": "idna", + "version": "1.1.0" + }, + { + "name": "ignore", + "version": "0.4.33" + }, + { + "name": "indexmap", + "version": "2.14.2" + }, + { + "name": "insta", + "version": "1.49.0" + }, + { + "name": "io-extras", + "version": "0.19.0" + }, + { + "name": "io-lifetimes", + "version": "2.0.4" + }, + { + "name": "io-lifetimes", + "version": "3.0.1" + }, + { + "name": "ipnet", + "version": "2.12.2" + }, + { + "name": "iprange", + "version": "0.6.7" + }, + { + "name": "is_terminal_polyfill", + "version": "1.70.2" + }, + { + "name": "itertools", + "version": "0.13.0" + }, + { + "name": "itertools", + "version": "0.15.0" + }, + { + "name": "itoa", + "version": "1.0.18" + }, + { + "name": "jobserver", + "version": "0.1.35" + }, + { + "name": "js-sys", + "version": "0.3.106" + }, + { + "name": "leb128", + "version": "0.2.7" + }, + { + "name": "leb128fmt", + "version": "0.1.0" + }, + { + "name": "lexical-sort", + "version": "0.3.1" + }, + { + "name": "libc", + "version": "0.2.190" + }, + { + "name": "libloading", + "version": "0.8.9" + }, + { + "name": "liboliphaunt-wasix-aot-aarch64-apple-darwin", + "version": "0.3.2" + }, + { + "name": "liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu", + "version": "0.3.2" + }, + { + "name": "liboliphaunt-wasix-aot-x86_64-pc-windows-msvc", + "version": "0.3.2" + }, + { + "name": "liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu", + "version": "0.3.2" + }, + { + "name": "liboliphaunt-wasix-portable", + "version": "0.3.2" + }, + { + "name": "libredox", + "version": "0.1.25" + }, + { + "name": "libtest-mimic", + "version": "0.8.2" + }, + { + "name": "libunwind", + "version": "1.3.3" + }, + { + "name": "linked_hash_set", + "version": "0.1.6" + }, + { + "name": "linked-hash-map", + "version": "0.5.6" + }, + { + "name": "linux-raw-sys", + "version": "0.12.1" + }, + { + "name": "litemap", + "version": "0.8.3" + }, + { + "name": "litrs", + "version": "1.0.0" + }, + { + "name": "lock_api", + "version": "0.4.14" + }, + { + "name": "log", + "version": "0.4.34" + }, + { + "name": "lz4_flex", + "version": "0.13.1" + }, + { + "name": "mach2", + "version": "0.4.3" + }, + { + "name": "mach2", + "version": "0.6.0" + }, + { + "name": "macho-unwind-info", + "version": "0.5.0" + }, + { + "name": "managed", + "version": "0.8.0" + }, + { + "name": "maybe-owned", + "version": "0.3.4" + }, + { + "name": "md-5", + "version": "0.10.6" + }, + { + "name": "md-5", + "version": "0.11.0" + }, + { + "name": "memchr", + "version": "2.8.3" + }, + { + "name": "memmap2", + "version": "0.6.2" + }, + { + "name": "memmap2", + "version": "0.9.11" + }, + { + "name": "memoffset", + "version": "0.9.1" + }, + { + "name": "minimal-lexical", + "version": "0.2.1" + }, + { + "name": "miniz_oxide", + "version": "0.8.9" + }, + { + "name": "miniz_oxide", + "version": "0.9.1" + }, + { + "name": "mio", + "version": "1.2.4" + }, + { + "name": "more-asserts", + "version": "0.3.1" + }, + { + "name": "munge_macro", + "version": "0.4.7" + }, + { + "name": "munge", + "version": "0.4.7" + }, + { + "name": "nom", + "version": "5.1.3" + }, + { + "name": "nom", + "version": "7.1.3" + }, + { + "name": "num_cpus", + "version": "1.17.0" + }, + { + "name": "num_enum_derive", + "version": "0.7.6" + }, + { + "name": "num_enum", + "version": "0.7.6" + }, + { + "name": "num-conv", + "version": "0.2.2" + }, + { + "name": "num-traits", + "version": "0.2.19" + }, + { + "name": "objc2-core-foundation", + "version": "0.3.2" + }, + { + "name": "objc2-system-configuration", + "version": "0.3.2" + }, + { + "name": "object", + "version": "0.37.3" + }, + { + "name": "object", + "version": "0.39.1" + }, + { + "name": "oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "version": "0.3.2" + }, + { + "name": "oliphaunt-extension-contrib-pg18-aot-linux-x64", + "version": "0.3.2" + }, + { + "name": "oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "version": "0.3.2" + }, + { + "name": "oliphaunt-extension-contrib-pg18-aot-windows-x64", + "version": "0.3.2" + }, + { + "name": "oliphaunt-extension-contrib-pg18-wasix", + "version": "0.3.2" + }, + { + "name": "oliphaunt-icu", + "version": "0.2.2" + }, + { + "name": "once_cell_polyfill", + "version": "1.70.2" + }, + { + "name": "once_cell", + "version": "1.21.4" + }, + { + "name": "option-ext", + "version": "0.2.0" + }, + { + "name": "parking_lot_core", + "version": "0.9.12" + }, + { + "name": "parking_lot", + "version": "0.12.5" + }, + { + "name": "parking", + "version": "2.2.1" + }, + { + "name": "paste", + "version": "1.0.15" + }, + { + "name": "path-clean", + "version": "1.0.1" + }, + { + "name": "percent-encoding", + "version": "2.3.2" + }, + { + "name": "petgraph", + "version": "0.8.3" + }, + { + "name": "phf_shared", + "version": "0.13.1" + }, + { + "name": "phf", + "version": "0.13.1" + }, + { + "name": "pin-project-internal", + "version": "1.1.13" + }, + { + "name": "pin-project-lite", + "version": "0.2.17" + }, + { + "name": "pin-project", + "version": "1.1.13" + }, + { + "name": "pin-utils", + "version": "0.1.1" + }, + { + "name": "pkg-config", + "version": "0.3.34" + }, + { + "name": "plain", + "version": "0.2.3" + }, + { + "name": "postgres-protocol", + "version": "0.6.12" + }, + { + "name": "postgres-types", + "version": "0.2.14" + }, + { + "name": "potential_utf", + "version": "0.1.6" + }, + { + "name": "powerfmt", + "version": "0.2.1" + }, + { + "name": "ppv-lite86", + "version": "0.2.21" + }, + { + "name": "prettyplease", + "version": "0.2.37" + }, + { + "name": "proc-macro-crate", + "version": "3.5.0" + }, + { + "name": "proc-macro-error-attr2", + "version": "2.0.0" + }, + { + "name": "proc-macro-error2", + "version": "2.0.1" + }, + { + "name": "proc-macro2", + "version": "1.0.107" + }, + { + "name": "ptr_meta_derive", + "version": "0.3.2" + }, + { + "name": "ptr_meta", + "version": "0.3.2" + }, + { + "name": "pulldown-cmark", + "version": "0.8.0" + }, + { + "name": "quote", + "version": "1.0.47" + }, + { + "name": "r-efi", + "version": "5.3.0" + }, + { + "name": "r-efi", + "version": "6.0.0" + }, + { + "name": "rancor", + "version": "0.1.3" + }, + { + "name": "rand_chacha", + "version": "0.3.1" + }, + { + "name": "rand_chacha", + "version": "0.9.0" + }, + { + "name": "rand_core", + "version": "0.10.1" + }, + { + "name": "rand_core", + "version": "0.6.4" + }, + { + "name": "rand_core", + "version": "0.9.5" + }, + { + "name": "rand", + "version": "0.10.3" + }, + { + "name": "rand", + "version": "0.8.8" + }, + { + "name": "rand", + "version": "0.9.5" + }, + { + "name": "rangemap", + "version": "1.8.0" + }, + { + "name": "rayon-core", + "version": "1.13.0" + }, + { + "name": "rayon", + "version": "1.12.0" + }, + { + "name": "redox_syscall", + "version": "0.5.18" + }, + { + "name": "redox_syscall", + "version": "0.9.4" + }, + { + "name": "redox_users", + "version": "0.5.3" + }, + { + "name": "ref-cast-impl", + "version": "1.0.27" + }, + { + "name": "ref-cast", + "version": "1.0.27" + }, + { + "name": "regex-automata", + "version": "0.4.18" + }, + { + "name": "regex-syntax", + "version": "0.8.11" + }, + { + "name": "regex", + "version": "1.13.1" + }, + { + "name": "region", + "version": "3.0.2" + }, + { + "name": "rend", + "version": "0.5.4" + }, + { + "name": "replace_with", + "version": "0.1.8" + }, + { + "name": "rkyv_derive", + "version": "0.8.18" + }, + { + "name": "rkyv", + "version": "0.8.18" + }, + { + "name": "rustc_version", + "version": "0.4.1" + }, + { + "name": "rustc-demangle", + "version": "0.1.28" + }, + { + "name": "rustc-hash", + "version": "2.1.3" + }, + { + "name": "rustix-linux-procfs", + "version": "0.1.1" + }, + { + "name": "rustix", + "version": "1.1.5" + }, + { + "name": "rustversion", + "version": "1.0.23" + }, + { + "name": "rusty_pool", + "version": "0.7.0" + }, + { + "name": "ruzstd", + "version": "0.8.3" + }, + { + "name": "ryu", + "version": "1.0.23" + }, + { + "name": "saffron", + "version": "0.1.0" + }, + { + "name": "same-file", + "version": "1.0.6" + }, + { + "name": "schemars_derive", + "version": "1.2.2" + }, + { + "name": "schemars", + "version": "1.2.2" + }, + { + "name": "scopeguard", + "version": "1.2.0" + }, + { + "name": "self_cell", + "version": "1.3.0" + }, + { + "name": "semver", + "version": "1.0.28" + }, + { + "name": "serde_core", + "version": "1.0.229" + }, + { + "name": "serde_derive_internals", + "version": "0.30.0" + }, + { + "name": "serde_derive", + "version": "1.0.229" + }, + { + "name": "serde_json", + "version": "1.0.154" + }, + { + "name": "serde_spanned", + "version": "1.1.2" + }, + { + "name": "serde_yaml", + "version": "0.9.34+deprecated" + }, + { + "name": "serde-wasm-bindgen", + "version": "0.6.5" + }, + { + "name": "serde", + "version": "1.0.229" + }, + { + "name": "sha2", + "version": "0.10.9" + }, + { + "name": "sha2", + "version": "0.11.0" + }, + { + "name": "shared-buffer", + "version": "0.1.4" + }, + { + "name": "shlex", + "version": "1.3.0" + }, + { + "name": "shlex", + "version": "2.0.1" + }, + { + "name": "simd-adler32", + "version": "0.3.10" + }, + { + "name": "simdutf8", + "version": "0.1.5" + }, + { + "name": "similar", + "version": "2.7.0" + }, + { + "name": "siphasher", + "version": "1.0.4" + }, + { + "name": "slab", + "version": "0.4.12" + }, + { + "name": "smallvec", + "version": "1.16.3" + }, + { + "name": "smoltcp", + "version": "0.13.1" + }, + { + "name": "socket2", + "version": "0.6.5" + }, + { + "name": "sqlx-core", + "version": "0.8.6" + }, + { + "name": "sqlx-macros-core", + "version": "0.8.6" + }, + { + "name": "sqlx-macros", + "version": "0.8.6" + }, + { + "name": "sqlx-postgres", + "version": "0.8.6" + }, + { + "name": "sqlx", + "version": "0.8.6" + }, + { + "name": "stable_deref_trait", + "version": "1.2.1" + }, + { + "name": "stringprep", + "version": "0.1.5" + }, + { + "name": "strip-ansi-escapes", + "version": "0.2.1" + }, + { + "name": "strsim", + "version": "0.11.1" + }, + { + "name": "subtle", + "version": "2.6.1" + }, + { + "name": "symbolic-common", + "version": "13.9.0" + }, + { + "name": "symbolic-demangle", + "version": "13.9.0" + }, + { + "name": "syn", + "version": "1.0.109" + }, + { + "name": "syn", + "version": "2.0.119" + }, + { + "name": "syn", + "version": "3.0.8" + }, + { + "name": "synstructure", + "version": "0.14.0" + }, + { + "name": "tar", + "version": "0.4.46" + }, + { + "name": "target-lexicon", + "version": "0.13.5" + }, + { + "name": "tempfile", + "version": "3.27.0" + }, + { + "name": "terminal_size", + "version": "0.4.4" + }, + { + "name": "termios", + "version": "0.3.3" + }, + { + "name": "thiserror-impl", + "version": "2.0.21" + }, + { + "name": "thiserror", + "version": "2.0.21" + }, + { + "name": "time-core", + "version": "0.1.9" + }, + { + "name": "time-macros", + "version": "0.2.32" + }, + { + "name": "time", + "version": "0.3.55" + }, + { + "name": "tinystr", + "version": "0.8.4" + }, + { + "name": "tinyvec", + "version": "1.13.3" + }, + { + "name": "tokio-macros", + "version": "2.7.2" + }, + { + "name": "tokio-postgres", + "version": "0.7.18" + }, + { + "name": "tokio-stream", + "version": "0.1.19" + }, + { + "name": "tokio-util", + "version": "0.7.20" + }, + { + "name": "tokio", + "version": "1.53.2" + }, + { + "name": "toml_datetime", + "version": "1.1.2+spec-1.1.0" + }, + { + "name": "toml_edit", + "version": "0.25.17+spec-1.1.0" + }, + { + "name": "toml_parser", + "version": "1.1.5+spec-1.1.0" + }, + { + "name": "toml_writer", + "version": "1.1.3+spec-1.1.0" + }, + { + "name": "toml", + "version": "1.1.8+spec-1.1.0" + }, + { + "name": "tracing-attributes", + "version": "0.1.31" + }, + { + "name": "tracing-core", + "version": "0.1.36" + }, + { + "name": "tracing", + "version": "0.1.44" + }, + { + "name": "twox-hash", + "version": "2.1.5" + }, + { + "name": "typenum", + "version": "1.20.1" + }, + { + "name": "unicase", + "version": "2.10.0" + }, + { + "name": "unicode-bidi", + "version": "0.3.18" + }, + { + "name": "unicode-ident", + "version": "1.0.26" + }, + { + "name": "unicode-normalization", + "version": "0.1.25" + }, + { + "name": "unicode-properties", + "version": "0.1.4" + }, + { + "name": "unicode-segmentation", + "version": "1.13.3" + }, + { + "name": "unicode-xid", + "version": "0.2.6" + }, + { + "name": "unsafe-libyaml", + "version": "0.2.11" + }, + { + "name": "unty", + "version": "0.0.4" + }, + { + "name": "url", + "version": "2.5.8" + }, + { + "name": "urlencoding", + "version": "2.1.3" + }, + { + "name": "utf8_iter", + "version": "1.0.4" + }, + { + "name": "utf8parse", + "version": "0.2.2" + }, + { + "name": "uuid", + "version": "1.28.0" + }, + { + "name": "version_check", + "version": "0.9.5" + }, + { + "name": "virtual-fs", + "version": "0.702.1" + }, + { + "name": "virtual-mio", + "version": "0.702.1" + }, + { + "name": "virtual-net", + "version": "0.702.1" + }, + { + "name": "virtue", + "version": "0.0.18" + }, + { + "name": "vte", + "version": "0.14.1" + }, + { + "name": "wai-bindgen-gen-core", + "version": "0.2.3" + }, + { + "name": "wai-bindgen-gen-rust-wasm", + "version": "0.2.3" + }, + { + "name": "wai-bindgen-gen-rust", + "version": "0.2.3" + }, + { + "name": "wai-bindgen-rust-impl", + "version": "0.2.3" + }, + { + "name": "wai-bindgen-rust", + "version": "0.2.3" + }, + { + "name": "wai-parser", + "version": "0.2.3" + }, + { + "name": "waker-fn", + "version": "1.2.0" + }, + { + "name": "walkdir", + "version": "2.5.0" + }, + { + "name": "wasi", + "version": "0.11.1+wasi-snapshot-preview1" + }, + { + "name": "wasi", + "version": "0.14.7+wasi-0.2.4" + }, + { + "name": "wasip2", + "version": "1.0.4+wasi-0.2.12" + }, + { + "name": "wasite", + "version": "0.1.0" + }, + { + "name": "wasite", + "version": "1.0.2" + }, + { + "name": "wasm-bindgen-macro-support", + "version": "0.2.129" + }, + { + "name": "wasm-bindgen-macro", + "version": "0.2.129" + }, + { + "name": "wasm-bindgen-shared", + "version": "0.2.129" + }, + { + "name": "wasm-bindgen", + "version": "0.2.129" + }, + { + "name": "wasm-encoder", + "version": "0.252.0" + }, + { + "name": "wasmer-compiler", + "version": "7.2.1" + }, + { + "name": "wasmer-config", + "version": "0.702.1" + }, + { + "name": "wasmer-derive", + "version": "7.2.1" + }, + { + "name": "wasmer-journal", + "version": "0.702.1" + }, + { + "name": "wasmer-package", + "version": "0.702.1" + }, + { + "name": "wasmer-types", + "version": "7.2.1" + }, + { + "name": "wasmer-vm", + "version": "7.2.1" + }, + { + "name": "wasmer-wasix-types", + "version": "0.702.1" + }, + { + "name": "wasmer-wasix", + "version": "0.702.1" + }, + { + "name": "wasmer", + "version": "7.2.1" + }, + { + "name": "wasmparser", + "version": "0.252.0" + }, + { + "name": "web-sys", + "version": "0.3.106" + }, + { + "name": "webc", + "version": "12.0.0" + }, + { + "name": "weezl", + "version": "0.2.1" + }, + { + "name": "which", + "version": "8.0.6" + }, + { + "name": "whoami", + "version": "1.6.1" + }, + { + "name": "whoami", + "version": "2.1.3" + }, + { + "name": "winapi-util", + "version": "0.1.11" + }, + { + "name": "windows_aarch64_gnullvm", + "version": "0.48.5" + }, + { + "name": "windows_aarch64_gnullvm", + "version": "0.52.6" + }, + { + "name": "windows_aarch64_gnullvm", + "version": "0.53.1" + }, + { + "name": "windows_aarch64_msvc", + "version": "0.48.5" + }, + { + "name": "windows_aarch64_msvc", + "version": "0.52.6" + }, + { + "name": "windows_aarch64_msvc", + "version": "0.53.1" + }, + { + "name": "windows_i686_gnu", + "version": "0.48.5" + }, + { + "name": "windows_i686_gnu", + "version": "0.52.6" + }, + { + "name": "windows_i686_gnu", + "version": "0.53.1" + }, + { + "name": "windows_i686_gnullvm", + "version": "0.52.6" + }, + { + "name": "windows_i686_gnullvm", + "version": "0.53.1" + }, + { + "name": "windows_i686_msvc", + "version": "0.48.5" + }, + { + "name": "windows_i686_msvc", + "version": "0.52.6" + }, + { + "name": "windows_i686_msvc", + "version": "0.53.1" + }, + { + "name": "windows_x86_64_gnu", + "version": "0.48.5" + }, + { + "name": "windows_x86_64_gnu", + "version": "0.52.6" + }, + { + "name": "windows_x86_64_gnu", + "version": "0.53.1" + }, + { + "name": "windows_x86_64_gnullvm", + "version": "0.48.5" + }, + { + "name": "windows_x86_64_gnullvm", + "version": "0.52.6" + }, + { + "name": "windows_x86_64_gnullvm", + "version": "0.53.1" + }, + { + "name": "windows_x86_64_msvc", + "version": "0.48.5" + }, + { + "name": "windows_x86_64_msvc", + "version": "0.52.6" + }, + { + "name": "windows_x86_64_msvc", + "version": "0.53.1" + }, + { + "name": "windows-link", + "version": "0.2.1" + }, + { + "name": "windows-sys", + "version": "0.48.0" + }, + { + "name": "windows-sys", + "version": "0.52.0" + }, + { + "name": "windows-sys", + "version": "0.59.0" + }, + { + "name": "windows-sys", + "version": "0.60.2" + }, + { + "name": "windows-sys", + "version": "0.61.2" + }, + { + "name": "windows-targets", + "version": "0.48.5" + }, + { + "name": "windows-targets", + "version": "0.52.6" + }, + { + "name": "windows-targets", + "version": "0.53.5" + }, + { + "name": "winnow", + "version": "1.0.4" + }, + { + "name": "winx", + "version": "0.36.4" + }, + { + "name": "wit-bindgen", + "version": "0.57.1" + }, + { + "name": "writeable", + "version": "0.6.4" + }, + { + "name": "xattr", + "version": "1.6.1" + }, + { + "name": "xxhash-rust", + "version": "0.8.19" + }, + { + "name": "yoke-derive", + "version": "0.8.4" + }, + { + "name": "yoke", + "version": "0.8.3" + }, + { + "name": "zerocopy-derive", + "version": "0.8.62" + }, + { + "name": "zerocopy", + "version": "0.8.62" + }, + { + "name": "zerofrom-derive", + "version": "0.1.8" + }, + { + "name": "zerofrom", + "version": "0.1.8" + }, + { + "name": "zerotrie", + "version": "0.2.5" + }, + { + "name": "zerovec-derive", + "version": "0.11.6" + }, + { + "name": "zerovec", + "version": "0.11.8" + }, + { + "name": "zlib-rs", + "version": "0.6.8" + }, + { + "name": "zmij", + "version": "1.0.23" + }, + { + "name": "zstd-safe", + "version": "7.3.0" + }, + { + "name": "zstd-sys", + "version": "2.1.1+zstd.1.5.7" + }, + { + "name": "zstd", + "version": "0.13.3" + } + ], + "config": { + "dl": "https://static.crates.io/crates", + "api": "https://crates.io" + }, + "indexes": [ + { + "path": "2/cc", + "header": "AwIAAABldGFnOiAiYWQyNzAxODQ4NDA5NTI0MTFmMDI1MDA0ZWIxZjY5NzIiAA==", + "records": [ + { + "name": "cc", + "vers": "1.8.0", + "deps": [ + { + "name": "find-msvc-tools", + "req": "^0.1.14", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "jobserver", + "req": "^0.1.32", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.168", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "shlex", + "req": "^2.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "6651c9ed80effdc7db0ff72512157f901af5e3549e341e24b1dd4887d836d838", + "features": { + "jobserver": [] + }, + "features2": { + "parallel": ["dep:jobserver", "dep:libc"] + }, + "yanked": false, + "rust_version": "1.65.0", + "pubtime": "2026-10-11T14:17:35Z", + "v": 2 + } + ] + }, + { + "path": "3/b/bus", + "header": "AwIAAABldGFnOiAiYTY1YjVlMzQ0ZmQyNjg1YzkxZmVmMjBhNDE0NzFiMjkiAA==", + "records": [ + { + "name": "bus", + "vers": "2.4.1", + "deps": [ + { + "name": "crossbeam-channel", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "num_cpus", + "req": "^1.6.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "parking_lot_core", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "4b7118d0221d84fada881b657c2ddb7cd55108db79c8764c9ee212c0c259b783", + "features": {}, + "yanked": false, + "pubtime": "2023-08-20T12:34:40Z" + } + ] + }, + { + "path": "3/c/crc", + "header": "AwIAAABldGFnOiAiZDVjODJjNjY0MTAyMWVjZmJhZmJiMzRhYjkzYzU2OTkiAA==", + "records": [ + { + "name": "crc", + "vers": "3.4.0", + "deps": [ + { + "name": "crc-catalog", + "req": "^2.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d", + "features": {}, + "yanked": false, + "rust_version": "1.83", + "pubtime": "2025-11-26T17:46:02Z" + } + ] + }, + { + "path": "3/f/fnv", + "header": "AwIAAABldGFnOiAiMzJjNDYzODQ3NDEzOTA5NTQzMTJjMThjMDMwY2Y4NDQiAA==", + "records": [ + { + "name": "fnv", + "vers": "1.0.7", + "deps": [], + "cksum": "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "pubtime": "2020-05-14T16:06:29Z" + } + ] + }, + { + "path": "3/h/hex", + "header": "AwIAAABldGFnOiAiNGJlMDQ0MGIzYWU0NDU1MWVkNmQ1OTg1MWM1YzJmYzIiAA==", + "records": [ + { + "name": "hex", + "vers": "0.4.3", + "deps": [ + { + "name": "criterion", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "faster-hex", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "pretty_assertions", + "req": "^0.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustc-hex", + "req": "^2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "version-sync", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70", + "features": { + "alloc": [], + "default": ["std"], + "std": ["alloc"] + }, + "yanked": false, + "pubtime": "2021-03-03T10:48:58Z" + } + ] + }, + { + "path": "3/l/log", + "header": "AwIAAABldGFnOiAiNGE0ZGJlMjZlOWQ5MTliYTFmNjQ0MTM3NGUzODlhNTQiAA==", + "records": [ + { + "name": "log", + "vers": "0.4.34", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.63", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_test", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "sval", + "req": "^2.16", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "sval", + "req": "^2.16", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "sval_derive", + "req": "^2.16", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "sval_ref", + "req": "^2.16", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "value-bag", + "req": "^1.12", + "features": ["inline-i128"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "value-bag", + "req": "^1.12", + "features": ["test"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6", + "features": { + "alloc": [], + "kv": [], + "kv_serde": ["kv_std", "value-bag/serde", "serde"], + "kv_std": ["std", "kv", "value-bag/error"], + "kv_sval": ["kv", "value-bag/sval", "sval", "sval_ref"], + "kv_unstable": ["kv", "value-bag"], + "kv_unstable_serde": ["kv_serde", "kv_unstable_std"], + "kv_unstable_std": ["kv_std", "kv_unstable"], + "kv_unstable_sval": ["kv_sval", "kv_unstable"], + "max_level_debug": [], + "max_level_error": [], + "max_level_info": [], + "max_level_off": [], + "max_level_trace": [], + "max_level_warn": [], + "release_max_level_debug": [], + "release_max_level_error": [], + "release_max_level_info": [], + "release_max_level_off": [], + "release_max_level_trace": [], + "release_max_level_warn": [], + "serde": ["serde_core"], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.71.0", + "pubtime": "2026-08-22T11:44:27Z" + } + ] + }, + { + "path": "3/m/mio", + "header": "AwIAAABldGFnOiAiNzMyYWI4Nzk4ZTQ3NmMxZDcyZTBiNjk3NDZiOWIyZDUiAA==", + "records": [ + { + "name": "mio", + "vers": "1.2.4", + "deps": [ + { + "name": "env_logger", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "libc", + "req": "^0.2.183", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(unix, target_os = \"hermit\", target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "log", + "req": "^0.4.8", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "wasi", + "req": "^0.11.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_os = \"wasi\")", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": "^0.61", + "features": [ + "Wdk_Foundation", + "Wdk_Storage_FileSystem", + "Wdk_System_IO", + "Win32_Foundation", + "Win32_Networking_WinSock", + "Win32_Storage_FileSystem", + "Win32_Security", + "Win32_System_IO", + "Win32_System_WindowsProgramming" + ], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "1788edb87fdc09c7e26304471e2f5be8cdefb1b6930d6e3985fc02ff53bf86ee", + "features": { + "default": ["log"], + "net": [], + "os-ext": ["os-poll", "windows-sys/Win32_System_Pipes", "windows-sys/Win32_Security"], + "os-poll": [] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-10-03T16:33:10Z" + } + ] + }, + { + "path": "3/n/nom", + "header": "AwIAAABldGFnOiAiZDEwOWIwMDVlM2JhZmIzMDRkZThlODQyNjQxYjFiZmYiAA==", + "records": [ + { + "name": "nom", + "vers": "5.1.3", + "deps": [ + { + "name": "criterion", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "doc-comment", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "jemallocator", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "lazy_static", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "lexical-core", + "req": ">=0.6, <0.8", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memchr", + "req": "^2.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "regex", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "version_check", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b", + "features": { + "alloc": [], + "default": ["std", "lexical"], + "lexical": ["lexical-core"], + "regexp": ["regex"], + "regexp_macros": ["regexp", "lazy_static"], + "std": ["alloc", "memchr/use_std"] + }, + "yanked": false, + "pubtime": "2023-04-26T20:09:42Z" + }, + { + "name": "nom", + "vers": "7.1.3", + "deps": [ + { + "name": "doc-comment", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "memchr", + "req": "^2.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "minimal-lexical", + "req": "^0.2.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "proptest", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a", + "features": { + "alloc": [], + "default": ["std"], + "docsrs": [], + "std": ["alloc", "memchr/std", "minimal-lexical/std"] + }, + "yanked": false, + "rust_version": "1.48", + "pubtime": "2023-01-15T21:06:03Z" + } + ] + }, + { + "path": "3/p/phf", + "header": "AwIAAABldGFnOiAiODI0MGVlNzE2ZjZhZGVkMWZjNjllNDFkMTc2ZTViMmIiAA==", + "records": [ + { + "name": "phf", + "vers": "0.13.1", + "deps": [ + { + "name": "phf_macros", + "req": "^0.13.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "phf_shared", + "req": "^0.13.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf", + "features": { + "macros": ["phf_macros"] + }, + "features2": { + "default": ["std"], + "std": ["phf_shared/std", "serde?/std"], + "uncased": ["phf_macros?/uncased", "phf_shared/uncased"], + "unicase": ["phf_macros?/unicase", "phf_shared/unicase"] + }, + "yanked": false, + "rust_version": "1.66", + "pubtime": "2025-08-23T11:06:34Z", + "v": 2 + } + ] + }, + { + "path": "3/r/ryu", + "header": "AwIAAABldGFnOiAiYzRjNTAwNzZjNWJiZjVhYTE5ZDFmNGYyNWEwMDAyMjMiAA==", + "records": [ + { + "name": "ryu", + "vers": "1.0.23", + "deps": [ + { + "name": "criterion", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "no-panic", + "req": "^0.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "num_cpus", + "req": "^1.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand_core", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand_xorshift", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f", + "features": { + "small": [] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-02-08T20:34:03Z" + } + ] + }, + { + "path": "3/s/syn", + "header": "AwIAAABldGFnOiAiODM2YzQ4ODQ4ZTdmYWY3NjA1ZTlmZDEyNWUxMjIzZTgiAA==", + "records": [ + { + "name": "syn", + "vers": "1.0.109", + "deps": [ + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "automod", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "flate2", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "insta", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1.0.46", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ref-cast", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "regex", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "reqwest", + "req": "^0.11", + "features": ["blocking"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn-test-suite", + "req": "^0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tar", + "req": "^0.4.16", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "termcolor", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicode-ident", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "walkdir", + "req": "^2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237", + "features": { + "clone-impls": [], + "default": ["derive", "parsing", "printing", "clone-impls", "proc-macro"], + "derive": [], + "extra-traits": [], + "fold": [], + "full": [], + "parsing": [], + "printing": ["quote"], + "proc-macro": ["proc-macro2/proc-macro", "quote/proc-macro"], + "test": ["syn-test-suite/all-features"], + "visit": [], + "visit-mut": [] + }, + "yanked": false, + "rust_version": "1.31", + "pubtime": "2023-02-24T09:58:43Z" + }, + { + "name": "syn", + "vers": "2.0.119", + "deps": [ + { + "name": "anyhow", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "automod", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "flate2", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "insta", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1.0.91", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.35", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "ref-cast", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "reqwest", + "req": "^0.13", + "features": ["blocking"], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn-test-suite", + "req": "^0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tar", + "req": "^0.4.16", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "termcolor", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicode-ident", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "walkdir", + "req": "^2.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + } + ], + "cksum": "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297", + "features": { + "clone-impls": [], + "derive": [], + "extra-traits": [], + "fold": [], + "full": [], + "parsing": [], + "test": ["syn-test-suite/all-features"], + "visit": [], + "visit-mut": [] + }, + "features2": { + "default": ["derive", "parsing", "printing", "clone-impls", "proc-macro"], + "printing": ["dep:quote"], + "proc-macro": ["proc-macro2/proc-macro", "quote?/proc-macro"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-15T00:23:48Z", + "v": 2 + }, + { + "name": "syn", + "vers": "3.0.8", + "deps": [ + { + "name": "anyhow", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "automod", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "flate2", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "insta", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1.0.91", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.35", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "ref-cast", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "reqwest", + "req": "^0.13", + "features": ["blocking"], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn-test-suite", + "req": "^0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tar", + "req": "^0.4.16", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "termcolor", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicode-ident", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "walkdir", + "req": "^2.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(miri))", + "kind": "dev" + } + ], + "cksum": "01016da373cd8f7ef12624f796309f5c31ba8d646dd08856c02cd741d823c622", + "features": { + "clone-impls": [], + "derive": [], + "extra-traits": [], + "fold": [], + "full": [], + "parsing": [], + "test": ["syn-test-suite/all-features"], + "visit": [], + "visit-mut": [] + }, + "features2": { + "default": ["derive", "parsing", "printing", "clone-impls", "proc-macro"], + "printing": ["dep:quote"], + "proc-macro": ["proc-macro2/proc-macro", "quote?/proc-macro"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-10-11T16:12:28Z", + "v": 2 + } + ] + }, + { + "path": "3/t/tar", + "header": "AwIAAABldGFnOiAiMzc2ODlhYTNiMzBiNmIwY2E1NzU5Y2JhMzAwZTQ2NTAiAA==", + "records": [ + { + "name": "tar", + "vers": "0.4.46", + "deps": [ + { + "name": "astral-tokio-tar", + "req": "^0.6.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "filetime", + "req": "^0.2.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.8", + "features": ["small_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tempfile", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio", + "req": "^1", + "features": ["macros", "rt"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-stream", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "xattr", + "req": "^1.1.3", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + } + ], + "cksum": "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840", + "features": { + "default": ["xattr"] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2026-05-18T19:12:11Z" + } + ] + }, + { + "path": "3/u/url", + "header": "AwIAAABldGFnOiAiY2FhMmIyNjdlZWI3NmU2NzZjMjZmYTgxZmQ5MDg5OWEiAA==", + "records": [ + { + "name": "url", + "vers": "2.5.8", + "deps": [ + { + "name": "bencher", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "form_urlencoded", + "req": "^1.2.2", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "idna", + "req": "^1.1.0", + "features": ["alloc", "compiled_data"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "percent-encoding", + "req": "^2.3.2", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_derive", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"wasm32\", target_os = \"unknown\"))", + "kind": "dev" + } + ], + "cksum": "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed", + "features": { + "debugger_visualizer": [], + "expose_internals": [] + }, + "features2": { + "default": ["std"], + "serde": ["dep:serde", "dep:serde_derive"], + "std": ["idna/std", "percent-encoding/std", "form_urlencoded/std", "serde?/std"] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2026-01-05T22:14:31Z", + "v": 2 + } + ] + }, + { + "path": "3/v/vte", + "header": "AwIAAABldGFnOiAiNWE3MWNjY2JlMTFmNGNlMzE5YjI3NTA2NDQyODdiMDUiAA==", + "records": [ + { + "name": "vte", + "vers": "0.14.1", + "deps": [ + { + "name": "arrayvec", + "req": "^0.7.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "bitflags", + "req": "^2.3.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "cursor-icon", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "log", + "req": "^0.4.17", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memchr", + "req": "^2.7.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.160", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "231fdcd7ef3037e8330d8e17e61011a2c244126acc0a982f4040ac3f9f0bc077", + "features": { + "ansi": ["log", "cursor-icon", "bitflags"], + "default": ["no_std"], + "no_std": ["arrayvec"] + }, + "features2": { + "serde": ["dep:serde"] + }, + "yanked": false, + "rust_version": "1.62.1", + "pubtime": "2025-01-12T21:50:16Z", + "v": 2 + } + ] + }, + { + "path": "ad/dr/addr2line", + "header": "AwIAAABldGFnOiAiMzVmYzRkOWNhYmU1NGM4ODQ2M2VhYTZjMzRmMjJlZmQiAA==", + "records": [ + { + "name": "addr2line", + "vers": "0.25.1", + "deps": [ + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "backtrace", + "req": "^0.3.13", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "clap", + "req": "^4.3.21", + "features": ["wrap_help"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "cpp_demangle", + "req": "^0.4", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "criterion", + "req": "^0.7.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "fallible-iterator", + "req": "^0.3.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "findshlibs", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "gimli", + "req": "^0.32.0", + "features": ["read"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "libtest-mimic", + "req": "^0.8.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "memmap2", + "req": "^0.9.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "object", + "req": "^0.37.0", + "features": ["read", "compression"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rustc-demangle", + "req": "^0.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "smallvec", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "typed-arena", + "req": "^2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b", + "features": { + "cargo-all": [], + "rustc-dep-of-std": ["core", "alloc", "gimli/rustc-dep-of-std"], + "std": ["gimli/std"], + "wasm": ["object/wasm"] + }, + "features2": { + "all": ["bin", "wasm"], + "bin": [ + "loader", + "rustc-demangle", + "cpp_demangle", + "fallible-iterator", + "smallvec", + "dep:clap" + ], + "default": [ + "rustc-demangle", + "cpp_demangle", + "loader", + "fallible-iterator", + "smallvec" + ], + "loader": ["std", "dep:object", "dep:memmap2", "dep:typed-arena"] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2025-09-13T03:01:38Z", + "v": 2 + } + ] + }, + { + "path": "ad/le/adler2", + "header": "AwIAAABldGFnOiAiNmVlY2ZiMDZjMDY2NTY1YjIwODhmOTdlZTZmZWUyYmUiAA==", + "records": [ + { + "name": "adler2", + "vers": "2.0.1", + "deps": [ + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + } + ], + "cksum": "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa", + "features": { + "default": ["std"], + "rustc-dep-of-std": ["core"], + "std": [] + }, + "yanked": false, + "pubtime": "2025-06-09T22:31:53Z" + } + ] + }, + { + "path": "ah/o-/aho-corasick", + "header": "AwIAAABldGFnOiAiMjk2OTJkZGNkYzE1MmQyMDdkYTgyZDdlNzE0Yjg4ZmEiAA==", + "records": [ + { + "name": "aho-corasick", + "vers": "1.1.5", + "deps": [ + { + "name": "doc-comment", + "req": "^0.3.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "log", + "req": "^0.4.17", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memchr", + "req": "^2.4.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba", + "features": {}, + "features2": { + "default": ["std", "perf-literal"], + "logging": ["dep:log"], + "perf-literal": ["dep:memchr"], + "std": ["memchr?/std"] + }, + "yanked": false, + "rust_version": "1.60.0", + "pubtime": "2026-08-03T11:44:11Z", + "v": 2 + } + ] + }, + { + "path": "al/lo/allocator-api2", + "header": "AwIAAABldGFnOiAiYjBjYWY0YmZjYzc2MjNhN2M5NjVhZjJiM2ZmODcxNTQiAA==", + "records": [ + { + "name": "allocator-api2", + "vers": "0.2.21", + "deps": [ + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923", + "features": { + "alloc": [], + "default": ["std"], + "fresh-rust": [], + "nightly": [], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2024-12-01T14:49:16Z" + } + ] + }, + { + "path": "am/bi/ambient-authority", + "header": "AwIAAABldGFnOiAiYmJiOGM4NWI3ZmIwYmNmMzI1ZTg3OTI5NzU4NTY2OTEiAA==", + "records": [ + { + "name": "ambient-authority", + "vers": "0.0.2", + "deps": [], + "cksum": "e9d4ee0d472d1cd2e28c97dfa124b3d8d992e10eb0a035f33f5d12e3a177ba3b", + "features": {}, + "yanked": false, + "pubtime": "2023-04-06T23:01:28Z" + } + ] + }, + { + "path": "an/st/anstream", + "header": "AwIAAABldGFnOiAiZTQyZGU0YzM5ZmQ1YWEzYWYwYzAxYzczZTUxMDRmYjYiAA==", + "records": [ + { + "name": "anstream", + "vers": "1.0.0", + "deps": [ + { + "name": "anstyle", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anstyle-parse", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anstyle-query", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anstyle-wincon", + "req": "^3.0.5", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + }, + { + "name": "colorchoice", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "divan", + "req": "^0.1.16", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "is_terminal_polyfill", + "req": "^1.48", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "lexopt", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "owo-colors", + "req": "^4.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proptest", + "req": "^1.7.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "strip-ansi-escapes", + "req": "^0.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "utf8parse", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d", + "features": { + "test": [] + }, + "features2": { + "auto": ["dep:anstyle-query"], + "default": ["auto", "wincon"], + "wincon": ["dep:anstyle-wincon"] + }, + "yanked": false, + "rust_version": "1.66.0", + "pubtime": "2026-02-11T13:23:11Z", + "v": 2 + } + ] + }, + { + "path": "an/st/anstyle", + "header": "AwIAAABldGFnOiAiNjczODQzZDZlOTMzYzEyMjk5OTA5MzRiZDljNjU3ODciAA==", + "records": [ + { + "name": "anstyle", + "vers": "1.0.14", + "deps": [ + { + "name": "lexopt", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "snapbox", + "req": "^0.6.23", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.66.0", + "pubtime": "2026-03-13T18:59:28Z" + } + ] + }, + { + "path": "an/st/anstyle-parse", + "header": "AwIAAABldGFnOiAiYjUyMzE2ZmFhYmEzN2IzMmYxNzQ4NjA0OTY3NzkwZTYiAA==", + "records": [ + { + "name": "anstyle-parse", + "vers": "1.0.0", + "deps": [ + { + "name": "arrayvec", + "req": "^0.7.6", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "codegenrs", + "req": "^3.0.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "divan", + "req": "^0.1.16", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proptest", + "req": "^1.7.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "snapbox", + "req": "^0.6.23", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "utf8parse", + "req": "^0.2.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "vte_generate_state_changes", + "req": "^0.1.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e", + "features": {}, + "features2": { + "core": ["dep:arrayvec"], + "default": ["utf8"], + "utf8": ["dep:utf8parse"] + }, + "yanked": false, + "rust_version": "1.66.0", + "pubtime": "2026-02-11T13:23:08Z", + "v": 2 + } + ] + }, + { + "path": "an/st/anstyle-query", + "header": "AwIAAABldGFnOiAiODBmYzM5NGU3MTUwZDM5MjI2YmJiYzgwYzQzYzYxOTciAA==", + "records": [ + { + "name": "anstyle-query", + "vers": "1.1.5", + "deps": [ + { + "name": "windows-sys", + "req": ">=0.60.2, <0.62", + "features": ["Win32_System_Console", "Win32_Foundation"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc", + "features": {}, + "yanked": false, + "rust_version": "1.66.0", + "pubtime": "2025-11-13T17:30:22Z" + } + ] + }, + { + "path": "an/st/anstyle-wincon", + "header": "AwIAAABldGFnOiAiZDVjZWQ0NDYwNWM2YzU0ODI0OWYyNDE4YjllM2M0ZjAiAA==", + "records": [ + { + "name": "anstyle-wincon", + "vers": "3.0.11", + "deps": [ + { + "name": "anstyle", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "lexopt", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "once_cell_polyfill", + "req": "^1.56.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.60.2, <0.62", + "features": ["Win32_System_Console", "Win32_Foundation"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d", + "features": {}, + "yanked": false, + "rust_version": "1.66.0", + "pubtime": "2025-11-13T17:30:26Z" + } + ] + }, + { + "path": "an/y_/any_ascii", + "header": "AwIAAABldGFnOiAiMzUzMjJiNzM5YzFlYjI3ZmQ4ODQ5Njk1ZTFjMDcwNDIiAA==", + "records": [ + { + "name": "any_ascii", + "vers": "0.1.7", + "deps": [], + "cksum": "70033777eb8b5124a81a1889416543dddef2de240019b674c81285a2635a7e1e", + "features": {}, + "yanked": false, + "pubtime": "2020-10-19T14:14:51Z" + } + ] + }, + { + "path": "an/yh/anyhow", + "header": "AwIAAABldGFnOiAiZDU2MGNmMWQwZDFiOWI5ZWQ3OTZkMDU1MDU5MzhmYmMiAA==", + "records": [ + { + "name": "anyhow", + "vers": "1.0.104", + "deps": [ + { + "name": "futures", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn", + "req": "^3", + "features": ["full"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "thiserror", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.108", + "features": ["diff"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470", + "features": { + "backtrace": [], + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.68", + "pubtime": "2026-07-18T20:59:37Z" + } + ] + }, + { + "path": "ar/ra/arrayvec", + "header": "AwIAAABldGFnOiAiMTE0NmJkM2Y1YTE4YjczZDk0MTVmM2FjYWZmMmI2ZTUiAA==", + "records": [ + { + "name": "arrayvec", + "vers": "0.7.8", + "deps": [ + { + "name": "bencher", + "req": "^0.1.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "borsh", + "req": "^1.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "matches", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_test", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "zeroize", + "req": "^1.4", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.51", + "pubtime": "2026-07-02T12:44:35Z" + } + ] + }, + { + "path": "as/yn/async-trait", + "header": "AwIAAABldGFnOiAiNThlZWYzMDNmMWRjYjFjMjk4Mzg1YWVmN2FhMmZlZmEiAA==", + "records": [ + { + "name": "async-trait", + "vers": "0.1.92", + "deps": [ + { + "name": "futures", + "req": "^0.3.30", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1.0.74", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.35", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustversion", + "req": "^1.0.13", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn", + "req": "^3", + "features": ["clone-impls", "full", "parsing", "printing", "proc-macro", "visit-mut"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tracing", + "req": "^0.1.40", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tracing-attributes", + "req": "^0.1.27", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.108", + "features": ["diff"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-08-08T07:10:35Z" + } + ] + }, + { + "path": "at/oi/atoi", + "header": "AwIAAABldGFnOiAiMmNhY2U0MGJkN2RiY2MwNmU1ZTg1OTc1ZmEwODI5YjEiAA==", + "records": [ + { + "name": "atoi", + "vers": "2.0.0", + "deps": [ + { + "name": "criterion", + "req": "^0.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "num-traits", + "req": "^0.2.14", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528", + "features": { + "default": ["std"], + "std": ["num-traits/std"] + }, + "yanked": false, + "rust_version": "1.57.0", + "pubtime": "2022-10-11T17:21:42Z" + } + ] + }, + { + "path": "au/to/autocfg", + "header": "AwIAAABldGFnOiAiOTY5ZGUwMWM4ZTc5NjIxYmEwMWQ4NzU0NTA5MGZjMjIiAA==", + "records": [ + { + "name": "autocfg", + "vers": "1.5.1", + "deps": [], + "cksum": "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53", + "features": {}, + "yanked": false, + "rust_version": "1.0", + "pubtime": "2026-05-22T11:03:04Z" + } + ] + }, + { + "path": "ba/ck/backtrace", + "header": "AwIAAABldGFnOiAiNTI5MjE5MThlYjZlMmQxMzc4OTAwMTE2MWQ2YzkwZDMiAA==", + "records": [ + { + "name": "backtrace", + "vers": "0.3.76", + "deps": [ + { + "name": "addr2line", + "req": "^0.25.0", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))", + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cpp_demangle", + "req": "^0.5.0", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.156", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))", + "kind": "normal" + }, + { + "name": "libloading", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "miniz_oxide", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))", + "kind": "normal" + }, + { + "name": "object", + "req": "^0.37.0", + "features": ["read_core", "elf", "macho", "pe", "xcoff", "unaligned", "archive"], + "optional": false, + "default_features": false, + "target": "cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))", + "kind": "normal" + }, + { + "name": "rustc-demangle", + "req": "^0.1.24", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ruzstd", + "req": "^0.8.1", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(not(all(windows, target_env = \"msvc\", not(target_vendor = \"uwp\"))))", + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "windows-link", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(windows, target_os = \"cygwin\"))", + "kind": "normal" + } + ], + "cksum": "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6", + "features": { + "coresymbolication": [], + "dbghelp": [], + "default": ["std"], + "dl_iterate_phdr": [], + "dladdr": [], + "kernel32": [], + "libunwind": [], + "serialize-serde": ["serde"], + "std": [], + "unix-backtrace": [] + }, + "features2": { + "ruzstd": ["dep:ruzstd"] + }, + "yanked": false, + "rust_version": "1.82.0", + "pubtime": "2025-09-26T02:43:38Z", + "v": 2 + } + ] + }, + { + "path": "ba/se/base64", + "header": "AwIAAABldGFnOiAiMGEzMDg3N2QzZDkwZGNiNzY2ZmI5ODdjOWQxMjBhZDkiAA==", + "records": [ + { + "name": "base64", + "vers": "0.22.1", + "deps": [ + { + "name": "clap", + "req": "^3.2.25", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "once_cell", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.8.5", + "features": ["small_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rstest", + "req": "^0.13.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rstest_reuse", + "req": "^0.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "strum", + "req": "^0.25", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6", + "features": { + "alloc": [], + "default": ["std"], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.48.0", + "pubtime": "2024-04-30T23:16:40Z" + } + ] + }, + { + "path": "bi/nc/bincode", + "header": "AwIAAABldGFnOiAiM2U2ZmVhYTU3MDA5ZDYxNmYxZDU1ZmUzNTUzZDZjNzciAA==", + "records": [ + { + "name": "bincode", + "vers": "2.0.1", + "deps": [ + { + "name": "bincode_1", + "req": "^1.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "bincode" + }, + { + "name": "bincode_derive", + "req": "^2.0.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bumpalo", + "req": "^3.16.0", + "features": ["collections"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "chrono", + "req": "^0.4", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "glam", + "req": "^0.25", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ouroboros", + "req": "^0.18.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_derive", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "tempfile", + "req": "^3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unty", + "req": "^0.0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "uuid", + "req": "^1.1", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740", + "features": { + "derive": ["bincode_derive"] + }, + "features2": { + "alloc": ["serde?/alloc"], + "default": ["std", "derive"], + "std": ["alloc", "serde?/std"] + }, + "yanked": false, + "rust_version": "1.85.0", + "pubtime": "2025-03-10T18:28:08Z", + "v": 2 + } + ] + }, + { + "path": "bi/nc/bincode_derive", + "header": "AwIAAABldGFnOiAiNmUwNGJmNGVmNTEyMjAwZjY0ZDlhYzlkYjMxNWIzNDMiAA==", + "records": [ + { + "name": "bincode_derive", + "vers": "2.0.1", + "deps": [ + { + "name": "virtue", + "req": "^0.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09", + "features": {}, + "yanked": false, + "rust_version": "1.85.0", + "pubtime": "2025-03-10T18:27:58Z" + } + ] + }, + { + "path": "bi/nd/bindgen", + "header": "AwIAAABldGFnOiAiMTNkNzliODA5NGY2OTk3NWZkYTEwZTFhNjhlNWJjY2MiAA==", + "records": [ + { + "name": "bindgen", + "vers": "0.72.1", + "deps": [ + { + "name": "annotate-snippets", + "req": "^0.11.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bitflags", + "req": "^2.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cexpr", + "req": "^0.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "clang-sys", + "req": "^1", + "features": ["clang_11_0"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "clap", + "req": "^4", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "clap_complete", + "req": "^4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "itertools", + "req": ">=0.10, <0.14", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "log", + "req": "^0.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "prettyplease", + "req": "^0.2.7", + "features": ["verbatim"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1.0.80", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "regex", + "req": "^1.5.3", + "features": ["std", "unicode-perl"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rustc-hash", + "req": "^2.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "shlex", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0", + "features": ["full", "extra-traits", "visit-mut"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895", + "features": { + "__testing_only_extra_assertions": [], + "__testing_only_libclang_16": [], + "__testing_only_libclang_9": [], + "runtime": ["clang-sys/runtime"], + "static": ["clang-sys/static"] + }, + "features2": { + "__cli": ["dep:clap", "dep:clap_complete"], + "default": ["logging", "prettyplease", "runtime"], + "experimental": ["dep:annotate-snippets"], + "logging": ["dep:log"] + }, + "yanked": false, + "rust_version": "1.70.0", + "pubtime": "2025-08-31T17:50:11Z", + "v": 2 + } + ] + }, + { + "path": "bi/tf/bitflags", + "header": "AwIAAABldGFnOiAiMmYyMjc0MzNjM2E4MGJlZWM2MmQyM2MzNGJiZWQwYWUiAA==", + "records": [ + { + "name": "bitflags", + "vers": "1.3.2", + "deps": [ + { + "name": "compiler_builtins", + "req": "^0.1.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "rustversion", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_derive", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "walkdir", + "req": "^2.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a", + "features": { + "default": [], + "example_generated": [], + "rustc-dep-of-std": ["core", "compiler_builtins"] + }, + "yanked": false, + "pubtime": "2021-08-16T04:16:02Z" + }, + { + "name": "bitflags", + "vers": "2.13.2", + "deps": [ + { + "name": "arbitrary", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "arbitrary", + "req": "^1.0", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "bytemuck", + "req": "^1.12", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytemuck", + "req": "^1.12.2", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.228", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_lib", + "req": "^1.0.103", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "serde" + }, + { + "name": "serde_test", + "req": "^1.0.19", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "zerocopy", + "req": "^0.8", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06", + "features": { + "example_generated": [], + "serde": ["serde_core"], + "std": [] + }, + "yanked": false, + "rust_version": "1.56.0", + "pubtime": "2026-09-10T01:11:38Z" + } + ] + }, + { + "path": "bl/ak/blake3", + "header": "AwIAAABldGFnOiAiMjE4MzUwZjYzYTNmZGQ1ODQ5NmRkOWQyMDg4MGM5NzkiAA==", + "records": [ + { + "name": "blake3", + "vers": "1.8.7", + "deps": [ + { + "name": "arrayvec", + "req": "^0.7.4", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "cc", + "req": "^1.1.12", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "cfg-if", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "chacha20", + "req": "^0.10.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ciborium", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "constant_time_eq", + "req": "^0.4.2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "cpufeatures", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))", + "kind": "normal" + }, + { + "name": "digest", + "req": "^0.11.2", + "features": ["mac"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hex", + "req": "^0.4.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hmac", + "req": "^0.13.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "memmap2", + "req": "^0.9", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "page_size", + "req": "^0.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.10.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon-core", + "req": "^1.12.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.107", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tempfile", + "req": "^3.8.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "zeroize", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "6d9e454fc11f76977dc803893aff6304ed33d6a26efae8696573bea74baa27ae", + "features": { + "default": ["std"], + "neon": [], + "no_avx2": [], + "no_avx512": [], + "no_neon": [], + "no_sse2": [], + "no_sse41": [], + "prefer_intrinsics": [], + "pure": [], + "std": ["constant_time_eq/std"], + "wasm32_simd": [] + }, + "features2": { + "digest": ["dep:digest"], + "mmap": ["std", "dep:memmap2"], + "rayon": ["dep:rayon-core"], + "traits-preview": ["dep:digest"], + "zeroize": ["dep:zeroize", "arrayvec/zeroize"] + }, + "yanked": false, + "pubtime": "2026-08-20T09:09:56Z", + "v": 2 + } + ] + }, + { + "path": "bl/oc/block-buffer", + "header": "AwIAAABldGFnOiAiMGI2OGE1OWNhZDMyZGVlODdhMTUwMjM3YzQxNmU2NjAiAA==", + "records": [ + { + "name": "block-buffer", + "vers": "0.10.4", + "deps": [ + { + "name": "generic-array", + "req": "^0.14", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71", + "features": {}, + "yanked": false, + "pubtime": "2023-03-09T02:08:25Z" + }, + { + "name": "block-buffer", + "vers": "0.12.1", + "deps": [ + { + "name": "hex-literal", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hybrid-array", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "zeroize", + "req": "^1.8", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa", + "features": {}, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-06-11T15:40:05Z" + } + ] + }, + { + "path": "bs/tr/bstr", + "header": "AwIAAABldGFnOiAiNmY5NTM4MGM0OTcxNGZmODM0MmEzNzMxMzVmYjQwZGEiAA==", + "records": [ + { + "name": "bstr", + "vers": "1.13.1", + "deps": [ + { + "name": "memchr", + "req": "^2.7.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "regex-automata", + "req": "^0.4.1", + "features": ["dfa-search"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_core", + "req": "^1.0.85", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "ucd-parse", + "req": "^0.1.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicode-segmentation", + "req": "^1.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "6bb31b46c14244e20ee9984b11bf5c992b91fb6939fea616e3512c8baecdbe5f", + "features": {}, + "features2": { + "alloc": ["memchr/alloc", "serde_core?/alloc"], + "default": ["std", "unicode"], + "serde": ["dep:serde_core"], + "std": ["alloc", "memchr/std", "serde_core?/std"], + "unicode": ["dep:regex-automata"] + }, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-08-10T11:12:08Z", + "v": 2 + } + ] + }, + { + "path": "bu/mp/bumpalo", + "header": "AwIAAABldGFnOiAiMzFlMTk5OTI0MGIyYzhkMDU2NGMxOWZmMTVhZmYyMzQiAA==", + "records": [ + { + "name": "bumpalo", + "vers": "3.20.3", + "deps": [ + { + "name": "allocator-api2", + "req": "^0.2.8", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "blink-alloc", + "req": "=0.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.3.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quickcheck", + "req": "=1.0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.8.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "=1.10.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon-core", + "req": "=1.12.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.171", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.197", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0.115", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649", + "features": { + "allocator_api": [], + "bench_allocator_api": ["allocator_api", "blink-alloc/nightly"], + "boxed": [], + "collections": [], + "default": [], + "std": [] + }, + "features2": { + "serde": ["dep:serde"] + }, + "yanked": false, + "rust_version": "1.71.1", + "pubtime": "2026-05-22T14:59:11Z", + "v": 2 + } + ] + }, + { + "path": "by/te/bytecheck", + "header": "AwIAAABldGFnOiAiMzY5NzhlYzJkYTgxY2RiZmJmNGE1YmU4MmIzZWVlMTciAA==", + "records": [ + { + "name": "bytecheck", + "vers": "0.8.3", + "deps": [ + { + "name": "bytecheck_derive", + "req": "=0.8.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "ptr_meta", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rancor", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "simdutf8", + "req": "^0.1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "uuid-1", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "uuid" + } + ], + "cksum": "26333eeac754f0ad8a6bcd0eb0ac012156302e4e16b852b72ee399aea4f12c29", + "features": { + "default": ["simdutf8"] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-08-05T11:58:05Z" + } + ] + }, + { + "path": "by/te/bytecheck_derive", + "header": "AwIAAABldGFnOiAiYWUwMTc0Y2M4YTk5MWUyNzEzNzllNjI5MDIyYzY4ODIiAA==", + "records": [ + { + "name": "bytecheck_derive", + "vers": "0.8.3", + "deps": [ + { + "name": "proc-macro2", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3.0", + "features": ["clone-impls", "derive", "full", "parsing", "printing", "proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "46d07918caa9eeaaf06b7873925c53a61daac173539b4f7715090745e44e4e69", + "features": {}, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-08-05T11:58:04Z" + } + ] + }, + { + "path": "by/te/byteorder", + "header": "AwIAAABldGFnOiAiMTRmZTJlOTI1MGM4Zjk3M2VkNTRmYjFhNzk4NDdjMGQiAA==", + "records": [ + { + "name": "byteorder", + "vers": "1.5.0", + "deps": [ + { + "name": "quickcheck", + "req": "^0.9.2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b", + "features": { + "default": ["std"], + "i128": [], + "std": [] + }, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2023-10-06T00:45:57Z" + } + ] + }, + { + "path": "by/te/bytes", + "header": "AwIAAABldGFnOiAiNTdhYmQ4OTgxY2M3NWUwOWIyODQ2MDlhNWNkMjU2NzkiAA==", + "records": [ + { + "name": "bytes", + "vers": "1.12.1", + "deps": [ + { + "name": "extra-platforms", + "req": "^1.3", + "features": ["require-cas"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "portable-atomic" + }, + { + "name": "loom", + "req": "^0.7", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(loom)", + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.60", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_test", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.57", + "pubtime": "2026-07-08T10:01:28Z" + } + ] + }, + { + "path": "by/te/bytesize", + "header": "AwIAAABldGFnOiAiMjMxNjQwZjY1NjM1MzI4NTMyYWQ1MDRiZTA4NjVkNjciAA==", + "records": [ + { + "name": "bytesize", + "vers": "2.7.0", + "deps": [ + { + "name": "arbitrary", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "divan", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quickcheck", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml", + "req": "^1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "7354288c522e7e980fafd2075d63d1285794c3a6a16cdd492f189ea406e5f18b", + "features": { + "default": ["std"], + "std": [] + }, + "features2": { + "arbitrary": ["dep:arbitrary"], + "serde": ["dep:serde_core"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-08-02T03:27:39Z", + "v": 2 + } + ] + }, + { + "path": "ca/p-/cap-fs-ext", + "header": "AwIAAABldGFnOiAiYzkwMmY3MGJjNjE1MWU5M2NlYWQyYmFjZjg5NDRmYjYiAA==", + "records": [ + { + "name": "cap-fs-ext", + "vers": "4.0.3", + "deps": [ + { + "name": "arf-strings", + "req": "^0.7.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "camino", + "req": "^1.0.5", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cap-primitives", + "req": "^4.0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cap-std", + "req": "^4.0.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "io-lifetimes", + "req": "^3.0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.60, <0.62", + "features": ["Win32_Storage_FileSystem"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "56ff379b70af8e08307a8f65e7040c7301cb4a572538ade16b4984f0da77847f", + "features": { + "arf_strings": ["cap-std/arf_strings", "fs_utf8", "arf-strings"], + "default": ["std"], + "fs_utf8": ["cap-std/fs_utf8", "camino"], + "std": ["cap-std"] + }, + "yanked": false, + "pubtime": "2026-08-20T15:09:46Z" + } + ] + }, + { + "path": "ca/p-/cap-primitives", + "header": "AwIAAABldGFnOiAiZWE2ZGY2OWNjMzI4YmViNjRhNzY2N2FmNjc3Zjk1MDgiAA==", + "records": [ + { + "name": "cap-primitives", + "vers": "4.0.3", + "deps": [ + { + "name": "ambient-authority", + "req": "^0.0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "arbitrary", + "req": "^1.0.0", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "fs-set-times", + "req": "^0.20.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "io-extras", + "req": "^0.19.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "io-lifetimes", + "req": "^3.0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "ipnet", + "req": "^2.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "maybe-owned", + "req": "^0.3.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustix", + "req": "^1.0.0", + "features": ["fs", "process", "termios", "time"], + "optional": false, + "default_features": true, + "target": "cfg(not(windows))", + "kind": "normal" + }, + { + "name": "rustix-linux-procfs", + "req": "^0.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(target_os = \"android\", target_os = \"linux\"))", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.60, <0.62", + "features": [ + "Win32_Foundation", + "Win32_Security", + "Win32_Storage_FileSystem", + "Win32_System_Kernel", + "Win32_System_WindowsProgramming", + "Win32_System_IO", + "Wdk_Storage_FileSystem", + "Wdk_Foundation" + ], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + }, + { + "name": "winx", + "req": "^0.36.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "8b5f74729fd2f44701d1a8eb47e906cdb3ccd9ec0f02baad85a744b791940b18", + "features": {}, + "yanked": false, + "pubtime": "2026-08-20T15:09:42Z" + } + ] + }, + { + "path": "ca/p-/cap-std", + "header": "AwIAAABldGFnOiAiODI3ZDc2ZjMxZGQ4ZDFkZTc4ZjA5Y2ZkM2I5NGM2YjEiAA==", + "records": [ + { + "name": "cap-std", + "vers": "4.0.3", + "deps": [ + { + "name": "arf-strings", + "req": "^0.7.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "camino", + "req": "^1.0.5", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cap-primitives", + "req": "^4.0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "io-extras", + "req": "^0.19.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "io-lifetimes", + "req": "^3.0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rustix", + "req": "^1.0.0", + "features": ["fs"], + "optional": false, + "default_features": true, + "target": "cfg(not(windows))", + "kind": "normal" + } + ], + "cksum": "c1ec78e242cfa2cfe276807ac2ecc00315a6c97786977414bcd1c3963b6c91b8", + "features": { + "arf_strings": ["fs_utf8", "arf-strings"], + "default": [], + "fs_utf8": ["camino"] + }, + "yanked": false, + "pubtime": "2026-08-20T15:09:44Z" + } + ] + }, + { + "path": "ce/xp/cexpr", + "header": "AwIAAABldGFnOiAiMzJjOGU4YmM0NzExMDhiMDc2ZjFjY2Y2MjUwN2M0ZDAiAA==", + "records": [ + { + "name": "cexpr", + "vers": "0.6.0", + "deps": [ + { + "name": "clang-sys", + "req": ">=0.13.0, <0.29.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "nom", + "req": "^7", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766", + "features": {}, + "yanked": false, + "pubtime": "2021-10-11T09:31:52Z" + } + ] + }, + { + "path": "cf/g-/cfg-if", + "header": "AwIAAABldGFnOiAiNjA4MGZiYzc2YjkwZDM1ZWViNjYwMzY1M2I2MzMwZWYiAA==", + "records": [ + { + "name": "cfg-if", + "vers": "1.0.5", + "deps": [ + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + } + ], + "cksum": "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600", + "features": { + "rustc-dep-of-std": ["core"] + }, + "yanked": false, + "rust_version": "1.32", + "pubtime": "2026-09-16T17:36:11Z" + } + ] + }, + { + "path": "ch/ac/chacha20", + "header": "AwIAAABldGFnOiAiNWQ3MzM4YzUyYTE3N2E2ZjhhYzlmOWYwNmVlNmVlM2YiAA==", + "records": [ + { + "name": "chacha20", + "vers": "0.10.2", + "deps": [ + { + "name": "cfg-if", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cipher", + "req": "^0.5", + "features": ["stream-wrapper"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cipher", + "req": "^0.5", + "features": ["dev"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "cpufeatures", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(target_arch = \"x86_64\", target_arch = \"x86\"))", + "kind": "normal" + }, + { + "name": "hex-literal", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand_core", + "req": "^0.10", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zeroize", + "req": "^1.8.1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06", + "features": { + "default": ["cipher"], + "legacy": ["cipher"], + "xchacha": ["cipher"] + }, + "features2": { + "rng": ["dep:rand_core"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-08-27T17:51:13Z", + "v": 2 + } + ] + }, + { + "path": "ch/ro/chrono", + "header": "AwIAAABldGFnOiAiMGNlNGYyMjU2ZTJmNmVhZWU0YTI4M2VmNzQwNjRmYjYiAA==", + "records": [ + { + "name": "chrono", + "vers": "0.4.45", + "deps": [ + { + "name": "arbitrary", + "req": "^1.0.0", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bincode", + "req": "^1.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "defmt", + "req": "^1.0.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "iana-time-zone", + "req": "^0.1.45", + "features": ["fallback"], + "optional": true, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "js-sys", + "req": "^0.3", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(all(target_arch = \"wasm32\", not(any(target_os = \"emscripten\", target_os = \"wasi\"))))", + "kind": "normal" + }, + { + "name": "num-traits", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "pure-rust-locales", + "req": "^0.8.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rkyv", + "req": "^0.7.43", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.99", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "similar-asserts", + "req": "^2.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "wasm-bindgen", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(all(target_arch = \"wasm32\", not(any(target_os = \"emscripten\", target_os = \"wasi\"))))", + "kind": "normal" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"wasm32\", not(any(target_os = \"emscripten\", target_os = \"wasi\"))))", + "kind": "dev" + }, + { + "name": "windows-bindgen", + "req": "^0.66", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "windows-link", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327", + "features": { + "__internal_bench": [], + "alloc": [], + "clock": ["winapi", "iana-time-zone", "now"], + "core-error": [], + "default": ["clock", "std", "oldtime", "wasmbind"], + "libc": [], + "now": ["std"], + "oldtime": [], + "std": ["alloc"], + "unstable-locales": ["pure-rust-locales"], + "wasmbind": ["wasm-bindgen", "js-sys"], + "winapi": ["windows-link"] + }, + "features2": { + "defmt": ["dep:defmt", "pure-rust-locales?/defmt"], + "rkyv": ["dep:rkyv", "rkyv/size_32"], + "rkyv-16": ["dep:rkyv", "rkyv?/size_16"], + "rkyv-32": ["dep:rkyv", "rkyv?/size_32"], + "rkyv-64": ["dep:rkyv", "rkyv?/size_64"], + "rkyv-validation": ["rkyv?/validation"] + }, + "yanked": false, + "rust_version": "1.62.0", + "pubtime": "2026-06-04T12:16:42Z", + "v": 2 + } + ] + }, + { + "path": "ci/bo/ciborium", + "header": "AwIAAABldGFnOiAiNzZhNDU1MTk2NTA2MmQ0OTFlYzkzZmRmNjhjNTBlZTAiAA==", + "records": [ + { + "name": "ciborium", + "vers": "0.2.2", + "deps": [ + { + "name": "ciborium-io", + "req": "^0.2.2", + "features": ["alloc"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ciborium-ll", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hex", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rstest", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.100", + "features": ["alloc", "derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_bytes", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e", + "features": { + "default": ["std"], + "std": ["ciborium-io/std", "serde/std"] + }, + "yanked": false, + "rust_version": "1.58", + "pubtime": "2024-01-24T03:04:25Z" + } + ] + }, + { + "path": "ci/bo/ciborium-io", + "header": "AwIAAABldGFnOiAiMGJhZDQ2ZGUzMWI5ZTA5N2ZkNmM3OWRjMDQwNjVjMTciAA==", + "records": [ + { + "name": "ciborium-io", + "vers": "0.2.2", + "deps": [], + "cksum": "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757", + "features": { + "alloc": [], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.58", + "pubtime": "2024-01-24T03:02:36Z" + } + ] + }, + { + "path": "ci/bo/ciborium-ll", + "header": "AwIAAABldGFnOiAiMTRhMTVlOThjMWFiNDQ3MTE3NGY5MDFkZmFjZWMzN2IiAA==", + "records": [ + { + "name": "ciborium-ll", + "vers": "0.2.2", + "deps": [ + { + "name": "ciborium-io", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "half", + "req": "^2.2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "hex", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9", + "features": { + "alloc": [], + "std": ["alloc", "half/std"] + }, + "yanked": false, + "rust_version": "1.58", + "pubtime": "2024-01-24T03:03:42Z" + } + ] + }, + { + "path": "cl/an/clang-sys", + "header": "AwIAAABldGFnOiAiMmI1NmU0ZWM2ODEzMjkwZTc2OWI3MmYzYmZlZjM2NjUiAA==", + "records": [ + { + "name": "clang-sys", + "vers": "1.9.1", + "deps": [ + { + "name": "glob", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "glob", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "glob", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "lazy_static", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "libc", + "req": "^0.2.39", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "libloading", + "req": "^0.8", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": ">=3.0.0, <3.7.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "157a8ba7b480713b56f4c09fd13fc3e0a22a5dfab8097ba61cbc5feef950788a", + "features": { + "clang_10_0": ["clang_9_0"], + "clang_11_0": ["clang_10_0"], + "clang_12_0": ["clang_11_0"], + "clang_13_0": ["clang_12_0"], + "clang_14_0": ["clang_13_0"], + "clang_15_0": ["clang_14_0"], + "clang_16_0": ["clang_15_0"], + "clang_17_0": ["clang_16_0"], + "clang_18_0": ["clang_17_0"], + "clang_19_0": ["clang_18_0"], + "clang_20_0": ["clang_19_0"], + "clang_3_5": [], + "clang_3_6": ["clang_3_5"], + "clang_3_7": ["clang_3_6"], + "clang_3_8": ["clang_3_7"], + "clang_3_9": ["clang_3_8"], + "clang_4_0": ["clang_3_9"], + "clang_5_0": ["clang_4_0"], + "clang_6_0": ["clang_5_0"], + "clang_7_0": ["clang_6_0"], + "clang_8_0": ["clang_7_0"], + "clang_9_0": ["clang_8_0"], + "libcpp": [], + "runtime": ["libloading"], + "static": [] + }, + "yanked": false, + "links": "clang", + "pubtime": "2026-07-29T12:50:24Z" + } + ] + }, + { + "path": "cl/ap/clap", + "header": "AwIAAABldGFnOiAiNzJlNWQ3ZDllMDZlYWNjZGNiNTdkNzMxZGRhMTJiMzQiAA==", + "records": [ + { + "name": "clap", + "vers": "4.6.7", + "deps": [ + { + "name": "automod", + "req": "^1.0.16", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "clap-cargo", + "req": "^0.15.2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "clap_builder", + "req": "=4.6.7", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "clap_derive", + "req": "=4.6.7", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "jiff", + "req": "^0.2.23", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0.22", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "semver", + "req": "^1.0.27", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "shlex", + "req": "^2.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "snapbox", + "req": "^1.2.0", + "features": ["term-svg"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.116", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trycmd", + "req": "^1.2.0", + "features": ["color-auto", "diff", "examples"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + } + ], + "cksum": "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946", + "features": { + "cargo": ["clap_builder/cargo"], + "color": ["clap_builder/color"], + "default": ["std", "color", "help", "usage", "error-context", "suggestions"], + "env": ["clap_builder/env"], + "error-context": ["clap_builder/error-context"], + "help": ["clap_builder/help"], + "std": ["clap_builder/std"], + "string": ["clap_builder/string"], + "suggestions": ["clap_builder/suggestions"], + "unicode": ["clap_builder/unicode"], + "unstable-derive-ui-tests": [], + "unstable-ext": ["clap_builder/unstable-ext"], + "unstable-markdown": ["clap_derive/unstable-markdown"], + "unstable-styles": ["clap_builder/unstable-styles"], + "usage": ["clap_builder/usage"], + "wrap_help": ["clap_builder/wrap_help"] + }, + "features2": { + "debug": ["clap_builder/debug", "clap_derive?/debug"], + "deprecated": ["clap_builder/deprecated", "clap_derive?/deprecated"], + "derive": ["dep:clap_derive"], + "unstable-doc": ["clap_builder/unstable-doc", "derive"], + "unstable-v5": ["clap_builder/unstable-v5", "clap_derive?/unstable-v5", "deprecated"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-09-14T18:40:28Z", + "v": 2 + } + ] + }, + { + "path": "cl/ap/clap_builder", + "header": "AwIAAABldGFnOiAiYjRiYmI4MGI5ODYyNDE4NjNiZmU4ZGNjYjY5YjZmY2IiAA==", + "records": [ + { + "name": "clap_builder", + "vers": "4.6.7", + "deps": [ + { + "name": "anstream", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anstyle", + "req": "^1.0.14", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "backtrace", + "req": "^0.3.76", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "clap_lex", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "color-print", + "req": "^0.3.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "snapbox", + "req": "^1.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "strsim", + "req": "^0.11.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "terminal_size", + "req": "^0.4.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "unic-emoji-char", + "req": "^0.9.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicase", + "req": "^2.9.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "unicode-width", + "req": "^0.2.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d", + "features": { + "cargo": [], + "deprecated": [], + "env": [], + "error-context": [], + "help": [], + "std": ["anstyle/std"], + "string": [], + "unstable-ext": [], + "unstable-v5": ["deprecated"], + "usage": [] + }, + "features2": { + "color": ["dep:anstream"], + "debug": ["dep:backtrace"], + "default": ["std", "color", "help", "usage", "error-context", "suggestions"], + "suggestions": ["dep:strsim", "error-context"], + "unicode": ["dep:unicode-width", "dep:unicase"], + "unstable-doc": ["cargo", "wrap_help", "env", "unicode", "string", "unstable-ext"], + "unstable-styles": ["color"], + "wrap_help": ["help", "dep:terminal_size"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-09-14T18:40:26Z", + "v": 2 + } + ] + }, + { + "path": "cl/ap/clap_derive", + "header": "AwIAAABldGFnOiAiMDFlMzNjZjg4MzE0NDVkZjEzMGZhOWFmM2Q5OWUwMTAiAA==", + "records": [ + { + "name": "clap_derive", + "vers": "4.6.7", + "deps": [ + { + "name": "anstyle", + "req": "^1.0.14", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "heck", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1.0.106", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pulldown-cmark", + "req": "^0.13.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.45", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3.0.2", + "features": ["full"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "f9c751b79415d4e559e3d1fcf128e09e720eb673a06d26cf6f392d37d75b66e0", + "features": { + "debug": [], + "default": [], + "deprecated": [], + "raw-deprecated": ["deprecated"], + "unstable-v5": ["deprecated"] + }, + "features2": { + "unstable-markdown": ["dep:pulldown-cmark", "dep:anstyle"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-09-14T18:40:23Z", + "v": 2 + } + ] + }, + { + "path": "cl/ap/clap_lex", + "header": "AwIAAABldGFnOiAiYzUwN2IyMjM4NzA2MmM2OWMyMjBhYTgzMzYwMTZjM2IiAA==", + "records": [ + { + "name": "clap_lex", + "vers": "1.1.1", + "deps": [ + { + "name": "automod", + "req": "^1.0.16", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486", + "features": {}, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-09-14T18:40:24Z" + } + ] + }, + { + "path": "cm/ak/cmake", + "header": "AwIAAABldGFnOiAiMGIwMTc2MWUwNDdlZmU5ODNmOGViZGVlMWExNmUyZjAiAA==", + "records": [ + { + "name": "cmake", + "vers": "0.1.58", + "deps": [ + { + "name": "cc", + "req": "^1.2.46", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678", + "features": {}, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-03-26T17:58:29Z" + } + ] + }, + { + "path": "cm/ov/cmov", + "header": "AwIAAABldGFnOiAiMDU1YTdjZDBhMjk3MGEwOTRlNDg2OWJlYzQ0MjE4MjgiAA==", + "records": [ + { + "name": "cmov", + "vers": "0.5.4", + "deps": [ + { + "name": "proptest", + "req": "^1.11", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(unix, windows))", + "kind": "dev" + } + ], + "cksum": "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a", + "features": {}, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-05-28T19:07:33Z" + } + ] + }, + { + "path": "co/lo/colorchoice", + "header": "AwIAAABldGFnOiAiMjc1NzVhNjg2Njc1NTdhNTAxMTA5YjA4ZTc5YzIwZmQiAA==", + "records": [ + { + "name": "colorchoice", + "vers": "1.0.5", + "deps": [], + "cksum": "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570", + "features": {}, + "yanked": false, + "rust_version": "1.66.0", + "pubtime": "2026-03-13T18:59:29Z" + } + ] + }, + { + "path": "co/ns/console", + "header": "AwIAAABldGFnOiAiMDMyYWU0NTA3ZmI3ZTMyOGMwMjg0MzdhMjllZTAxNjQiAA==", + "records": [ + { + "name": "console", + "vers": "0.16.6", + "deps": [ + { + "name": "encode_unicode", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.99", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proptest", + "req": "^1.0.0", + "features": ["std", "bit-set", "break-dead-code"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "regex", + "req": "^1.4.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicode-width", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "windows-sys", + "req": "^0.61", + "features": [ + "Win32_Foundation", + "Win32_System_Console", + "Win32_Storage_FileSystem", + "Win32_UI_Input_KeyboardAndMouse" + ], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "e96a4956774c13c126a8b5af4daa79384f4d826534c95a02d76afb39e2ab64e3", + "features": { + "alloc": [], + "ansi-parsing": [], + "windows-console-colors": ["ansi-parsing"] + }, + "features2": { + "default": ["unicode-width", "ansi-parsing", "std"], + "std": ["dep:libc", "alloc"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-09-10T07:42:27Z", + "v": 2 + } + ] + }, + { + "path": "co/ns/const-oid", + "header": "AwIAAABldGFnOiAiNmI4NzEwMjJkNWQ2OWQyMjUzMTBkM2MzMTFhNzhhYWYiAA==", + "records": [ + { + "name": "const-oid", + "vers": "0.10.2", + "deps": [ + { + "name": "arbitrary", + "req": "^1.4", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hex-literal", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proptest", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "regex", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c", + "features": { + "db": [] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-01-07T23:11:57Z" + } + ] + }, + { + "path": "co/ns/constant_time_eq", + "header": "AwIAAABldGFnOiAiMzQxNTBmMzFjMTRkYzZkYTFmNTI1YWE4YjI4MjQyZmYiAA==", + "records": [ + { + "name": "constant_time_eq", + "vers": "0.4.2", + "deps": [ + { + "name": "count_instructions", + "req": "^0.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.5.1", + "features": ["cargo_bench_support", "html_reports"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b", + "features": { + "count_instructions_test": [], + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.85.0", + "pubtime": "2025-03-15T17:03:47Z" + } + ] + }, + { + "path": "co/nv/convert_case", + "header": "AwIAAABldGFnOiAiOWJjMDAxZjY1MjcxNWM1YjVkZmVmYWY5OWI4NmI1MWYiAA==", + "records": [ + { + "name": "convert_case", + "vers": "0.10.0", + "deps": [ + { + "name": "criterion", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicode-segmentation", + "req": "^1.9.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9", + "features": {}, + "yanked": false, + "pubtime": "2025-11-23T12:24:56Z" + } + ] + }, + { + "path": "co/ok/cooked-waker", + "header": "AwIAAABldGFnOiAiYTZkMjAxOGY1ZDM0MzJkN2RmNjlkNDk1NDdiZDUxNWMiAA==", + "records": [ + { + "name": "cooked-waker", + "vers": "5.0.0", + "deps": [], + "cksum": "147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f", + "features": {}, + "yanked": false, + "pubtime": "2020-12-23T21:47:33Z" + } + ] + }, + { + "path": "co/ro/corosensei", + "header": "AwIAAABldGFnOiAiNzIyM2JmMjExZmU0OTMyYzdhZmUwNmY5NzBjNWQ0OTQiAA==", + "records": [ + { + "name": "corosensei", + "vers": "0.3.4", + "deps": [ + { + "name": "autocfg", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "backtrace", + "req": "^0.3.69", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "cfg-if", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "criterion", + "req": "^0.5.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion-cycles-per-byte", + "req": "^0.6.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))", + "kind": "dev" + }, + { + "name": "libc", + "req": "^0.2.159", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "scopeguard", + "req": "^1.2.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "windows-sys", + "req": "^0.59.0", + "features": [ + "Win32_Foundation", + "Win32_System_Diagnostics_Debug", + "Win32_System_Kernel", + "Win32_System_Memory", + "Win32_System_Threading", + "Win32_System_SystemInformation" + ], + "optional": true, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "6886a0c0f263965933c438626e7179139a62b978a33aa18281cbf0cd5a975f34", + "features": { + "asm-unwind": ["unwind"], + "default": ["default-stack", "unwind"], + "default-stack": ["libc", "windows-sys"], + "sanitizer": [], + "unwind": [] + }, + "yanked": false, + "rust_version": "1.59.0", + "pubtime": "2026-05-24T13:32:37Z" + } + ] + }, + { + "path": "cp/p_/cpp_demangle", + "header": "AwIAAABldGFnOiAiMzIwZDIxNDUyZDI1YWY0NjI3YjgyNGNiNDVmMDNlOGEiAA==", + "records": [ + { + "name": "cpp_demangle", + "vers": "0.4.5", + "deps": [ + { + "name": "afl", + "req": "^0.15", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "clap", + "req": "^4.0", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "diff", + "req": "^0.1.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "f2bb79cb74d735044c972aae58ed0aaa9a837e85b01106a54c39e42e97f62253", + "features": { + "alloc": [], + "default": ["std"], + "fuzz": ["afl"], + "logging": ["std"], + "run_libiberty_tests": [], + "std": ["alloc"] + }, + "yanked": false, + "pubtime": "2025-09-24T01:47:04Z" + } + ] + }, + { + "path": "cp/uf/cpufeatures", + "header": "AwIAAABldGFnOiAiNzllZTI2NTM1MTg4ZmYzMTU4ZjMzOTU2YzU2MjIwN2QiAA==", + "records": [ + { + "name": "cpufeatures", + "vers": "0.2.17", + "deps": [ + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": false, + "target": "aarch64-linux-android", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_arch = \"aarch64\", target_os = \"linux\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_arch = \"aarch64\", target_vendor = \"apple\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_arch = \"loongarch64\", target_os = \"linux\"))", + "kind": "normal" + } + ], + "cksum": "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280", + "features": {}, + "yanked": false, + "pubtime": "2025-01-25T01:35:46Z" + }, + { + "name": "cpufeatures", + "vers": "0.3.1", + "deps": [ + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_arch = \"aarch64\", target_os = \"android\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_arch = \"aarch64\", target_os = \"linux\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_arch = \"aarch64\", target_vendor = \"apple\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_arch = \"loongarch64\", target_os = \"linux\"))", + "kind": "normal" + } + ], + "cksum": "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566", + "features": {}, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-08-26T18:39:59Z" + } + ] + }, + { + "path": "cr/c-/crc-catalog", + "header": "AwIAAABldGFnOiAiZGIwNTA2ZTU0NWI4NDFkYjk5ZGJiOGQzMGFjYmU2MzQiAA==", + "records": [ + { + "name": "crc-catalog", + "vers": "2.5.0", + "deps": [], + "cksum": "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853", + "features": {}, + "yanked": false, + "pubtime": "2026-04-24T18:44:55Z" + } + ] + }, + { + "path": "cr/c3/crc32fast", + "header": "AwIAAABldGFnOiAiMjcxMTZiY2EyNTA5YmQzMzY2YjcwYzdhYWM4NGE4NTgiAA==", + "records": [ + { + "name": "crc32fast", + "vers": "1.5.2", + "deps": [ + { + "name": "bencher", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "cfg-if", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "01a7799fd6b852db0e61728dde9a204c423b44d689dbd432522543614b490e78", + "features": { + "default": ["std"], + "nightly": [], + "std": [] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2026-09-12T18:41:46Z" + } + ] + }, + { + "path": "cr/os/crossbeam-channel", + "header": "AwIAAABldGFnOiAiODJiYjY1YWI3YWQ0ZDU2YzQ5YjY2ZDFhN2JhYzY5NTkiAA==", + "records": [ + { + "name": "crossbeam-channel", + "vers": "0.5.17", + "deps": [ + { + "name": "crossbeam-utils", + "req": "^0.8.18", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "num_cpus", + "req": "^1.13.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "signal-hook", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "98b0cc327b5bc766e7fda9c9260cc0fa81b43a8e240440422dff70788e3f9ef1", + "features": { + "default": ["std"], + "std": ["crossbeam-utils/std"] + }, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2026-09-05T17:47:21Z" + } + ] + }, + { + "path": "cr/os/crossbeam-deque", + "header": "AwIAAABldGFnOiAiMDg3NjUxMzQxMTM5ZWRmMzJmOGFhNmRkZmE3MzcyNTciAA==", + "records": [ + { + "name": "crossbeam-deque", + "vers": "0.8.8", + "deps": [ + { + "name": "crossbeam-epoch", + "req": "^0.9.17", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "crossbeam-utils", + "req": "^0.8.18", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a", + "features": { + "default": ["std"], + "std": ["crossbeam-epoch/std", "crossbeam-utils/std"] + }, + "yanked": false, + "rust_version": "1.61", + "pubtime": "2026-09-05T17:47:08Z" + } + ] + }, + { + "path": "cr/os/crossbeam-epoch", + "header": "AwIAAABldGFnOiAiZTQzYjVmMmQ2OGE0ZDNhMjU4YWJiYTE2OTAxYjYwMzkiAA==", + "records": [ + { + "name": "crossbeam-epoch", + "vers": "0.9.21", + "deps": [ + { + "name": "crossbeam-utils", + "req": "^0.8.18", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "loom-crate", + "req": "^0.7.1", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(crossbeam_loom)", + "kind": "normal", + "package": "loom" + }, + { + "name": "rand", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d", + "features": { + "alloc": [], + "default": ["std"], + "loom": ["loom-crate", "crossbeam-utils/loom"], + "nightly": ["crossbeam-utils/nightly"], + "std": ["alloc", "crossbeam-utils/std"] + }, + "yanked": false, + "rust_version": "1.61", + "pubtime": "2026-09-05T17:46:49Z" + } + ] + }, + { + "path": "cr/os/crossbeam-queue", + "header": "AwIAAABldGFnOiAiODhiNGQxMjY5YTBkNmNkZmE0Nzc4MTJlOGIzMDYwZWYiAA==", + "records": [ + { + "name": "crossbeam-queue", + "vers": "0.3.14", + "deps": [ + { + "name": "crossbeam-utils", + "req": "^0.8.18", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "03e8bd762f7479489c70ed6c768ddca99d7296857de437a68dcb2a94365b3fae", + "features": { + "alloc": [], + "default": ["std"], + "nightly": ["crossbeam-utils/nightly"], + "std": ["alloc", "crossbeam-utils/std"] + }, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2026-09-05T17:46:34Z" + } + ] + }, + { + "path": "cr/os/crossbeam-utils", + "header": "AwIAAABldGFnOiAiM2Q0YzEwZTIzMTQwM2JiYTVjN2E5MzExNjRmMGE3ZjEiAA==", + "records": [ + { + "name": "crossbeam-utils", + "vers": "0.8.23", + "deps": [ + { + "name": "loom", + "req": "^0.7.1", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(crossbeam_loom)", + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6", + "features": { + "default": ["std"], + "nightly": [], + "std": [] + }, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2026-09-05T17:46:14Z" + } + ] + }, + { + "path": "cr/un/crunchy", + "header": "AwIAAABldGFnOiAiNTgwZWU3NjEwYmViODVhMjdkOTQwZTIzMzdlYTRkODgiAA==", + "records": [ + { + "name": "crunchy", + "vers": "0.2.4", + "deps": [], + "cksum": "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5", + "features": { + "default": ["limit_128"], + "limit_1024": [], + "limit_128": [], + "limit_2048": [], + "limit_256": [], + "limit_512": [], + "limit_64": [], + "std": [] + }, + "yanked": false, + "pubtime": "2025-06-25T12:54:43Z" + } + ] + }, + { + "path": "cr/yp/crypto-common", + "header": "AwIAAABldGFnOiAiMTA5NWZjMDg1YTA4YWY4ZjY5ZWUzZDlkNzI1YWEzZDEiAA==", + "records": [ + { + "name": "crypto-common", + "vers": "0.1.7", + "deps": [ + { + "name": "generic-array", + "req": "=0.14.7", + "features": ["more_lengths"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rand_core", + "req": "^0.6", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "typenum", + "req": "^1.14", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a", + "features": { + "getrandom": ["rand_core/getrandom"], + "std": [] + }, + "yanked": false, + "pubtime": "2025-11-12T14:20:00Z" + }, + { + "name": "crypto-common", + "vers": "0.2.2", + "deps": [ + { + "name": "getrandom", + "req": "^0.4", + "features": ["sys_rng"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hybrid-array", + "req": "^0.4.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rand_core", + "req": "^0.10", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453", + "features": { + "zeroize": ["hybrid-array/zeroize"] + }, + "features2": { + "getrandom": ["rand_core", "dep:getrandom"], + "rand_core": ["dep:rand_core"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-05-19T16:01:22Z", + "v": 2 + } + ] + }, + { + "path": "ct/ut/ctutils", + "header": "AwIAAABldGFnOiAiZDRmNTY4YmQxNzZmNDAzNTk3MGY0ZjdkODNkYWRmMzMiAA==", + "records": [ + { + "name": "ctutils", + "vers": "0.4.3", + "deps": [ + { + "name": "cmov", + "req": "^0.5.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proptest", + "req": "^1.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "subtle", + "req": "^2.6", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "03bb0e1cc970d482d121d9a1744999169b69a07470b3d644a7894e53fcaf4574", + "features": { + "alloc": [] + }, + "features2": { + "subtle": ["dep:subtle"] + }, + "yanked": false, + "rust_version": "1.87", + "pubtime": "2026-10-05T23:29:33Z", + "v": 2 + } + ] + }, + { + "path": "da/rl/darling", + "header": "AwIAAABldGFnOiAiNDljZWM4ZmUwOTcwZDA5NmNiYmE3ZGUxNWI4NTU5MTEiAA==", + "records": [ + { + "name": "darling", + "vers": "0.20.11", + "deps": [ + { + "name": "darling_core", + "req": "=0.20.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "darling_macro", + "req": "=0.20.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1.0.86", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quote", + "req": "^1.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0.9", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(compiletests)", + "kind": "dev" + }, + { + "name": "syn", + "req": "^2.0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.89", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(compiletests)", + "kind": "dev" + } + ], + "cksum": "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee", + "features": { + "default": ["suggestions"], + "diagnostics": ["darling_core/diagnostics"], + "suggestions": ["darling_core/suggestions"] + }, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2025-03-28T20:05:16Z" + }, + { + "name": "darling", + "vers": "0.21.3", + "deps": [ + { + "name": "darling_core", + "req": "=0.21.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "darling_macro", + "req": "=0.21.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1.0.86", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quote", + "req": "^1.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0.9", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(compiletests)", + "kind": "dev" + }, + { + "name": "syn", + "req": "^2.0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.89", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(compiletests)", + "kind": "dev" + } + ], + "cksum": "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0", + "features": { + "default": ["suggestions"], + "diagnostics": ["darling_core/diagnostics"], + "serde": ["darling_core/serde"], + "suggestions": ["darling_core/suggestions"] + }, + "yanked": false, + "rust_version": "1.56.0", + "pubtime": "2025-08-22T15:40:48Z" + } + ] + }, + { + "path": "da/rl/darling_core", + "header": "AwIAAABldGFnOiAiMzA0ZGZkZTdjMzIyZGI2MTIxODA0MjA0ODA4N2RhOTciAA==", + "records": [ + { + "name": "darling_core", + "vers": "0.20.11", + "deps": [ + { + "name": "fnv", + "req": "^1.0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ident_case", + "req": "^1.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1.0.86", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "strsim", + "req": "^0.11.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0.15", + "features": ["full", "extra-traits"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e", + "features": { + "diagnostics": [], + "suggestions": ["strsim"] + }, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2025-03-28T20:05:00Z" + }, + { + "name": "darling_core", + "vers": "0.21.3", + "deps": [ + { + "name": "fnv", + "req": "^1.0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ident_case", + "req": "^1.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1.0.86", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.210", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.140", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "strsim", + "req": "^0.11.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0.15", + "features": ["full", "extra-traits"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4", + "features": { + "diagnostics": [], + "suggestions": ["strsim"] + }, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2025-08-22T15:40:32Z" + } + ] + }, + { + "path": "da/rl/darling_macro", + "header": "AwIAAABldGFnOiAiNzRlZDAxNzc5ZDg4N2Q5NGM0MGQzZDc1Y2FmOTBhZTgiAA==", + "records": [ + { + "name": "darling_macro", + "vers": "0.20.11", + "deps": [ + { + "name": "darling_core", + "req": "=0.20.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2025-03-28T20:05:07Z" + }, + { + "name": "darling_macro", + "vers": "0.21.3", + "deps": [ + { + "name": "darling_core", + "req": "=0.21.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2025-08-22T15:40:39Z" + } + ] + }, + { + "path": "da/sh/dashmap", + "header": "AwIAAABldGFnOiAiNjNiMTQ4NjFiMDE1YTA3ZGQyNzMzZTNjZTI4YmZmOTgiAA==", + "records": [ + { + "name": "dashmap", + "vers": "6.2.1", + "deps": [ + { + "name": "arbitrary", + "req": "^1.4.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "crossbeam-utils", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hashbrown", + "req": "^0.14.5", + "features": ["raw"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "lock_api", + "req": "^0.4.13", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "once_cell", + "req": "^1.21.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "parking_lot_core", + "req": "^0.9.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1.10.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.228", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "typesize", + "req": "^0.1.14", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c", + "features": { + "inline": ["hashbrown/inline-more"], + "raw-api": [] + }, + "features2": { + "typesize": ["dep:typesize"] + }, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-05-17T21:28:34Z", + "v": 2 + } + ] + }, + { + "path": "de/bu/debugid", + "header": "AwIAAABldGFnOiAiZDAxMGNkN2JmNWI1NzYwMTljN2I4YzFjZWM5NzFiYzMiAA==", + "records": [ + { + "name": "debugid", + "vers": "0.8.0", + "deps": [ + { + "name": "serde", + "req": "^1.0.85", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.37", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "uuid", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d", + "features": {}, + "yanked": false, + "pubtime": "2022-04-26T11:03:07Z" + } + ] + }, + { + "path": "de/fm/defmt", + "header": "AwIAAABldGFnOiAiNGMzNTY2NzU3MjZkMjE0NTE1NjdmN2EzNmNlMmY4NjUiAA==", + "records": [ + { + "name": "defmt", + "vers": "0.3.100", + "deps": [ + { + "name": "defmt10", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal", + "package": "defmt" + } + ], + "cksum": "f0963443817029b2024136fc4dd07a5107eb8f977eaf18fcd1fdeb11306b64ad", + "features": { + "alloc": ["defmt10/alloc"], + "avoid-default-panic": ["defmt10/avoid-default-panic"], + "encoding-raw": ["defmt10/encoding-raw"], + "encoding-rzcobs": ["defmt10/encoding-rzcobs"], + "ip_in_core": ["defmt10/ip_in_core"], + "unstable-test": ["defmt10/unstable-test"] + }, + "yanked": false, + "pubtime": "2025-04-01T14:47:45Z" + }, + { + "name": "defmt", + "vers": "1.1.1", + "deps": [ + { + "name": "bitflags", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "defmt-macros", + "req": "=1.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustc_version", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1", + "features": { + "alloc": [], + "avoid-default-panic": [], + "encoding-raw": [], + "encoding-rzcobs": [], + "ip_in_core": [], + "unstable-test": ["defmt-macros/unstable-test"] + }, + "yanked": false, + "links": "defmt", + "pubtime": "2026-07-03T14:14:30Z" + } + ] + }, + { + "path": "de/fm/defmt-macros", + "header": "AwIAAABldGFnOiAiY2Q5ODdlMzM2ODY4YWI5NWE5ODU4YzE4MTkxODZiYjciAA==", + "records": [ + { + "name": "defmt-macros", + "vers": "1.1.1", + "deps": [ + { + "name": "defmt-parser", + "req": "=1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "maplit", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "pretty_assertions", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rstest", + "req": "^0.19", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "syn", + "req": "^2", + "features": ["full", "extra-traits"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8", + "features": { + "unstable-test": [] + }, + "yanked": false, + "pubtime": "2026-07-03T14:14:21Z" + } + ] + }, + { + "path": "de/fm/defmt-parser", + "header": "AwIAAABldGFnOiAiZDdlNjIxNjE0ZmYxOTZlNTg5MGMyYTY0N2MwZmI4NDYiAA==", + "records": [ + { + "name": "defmt-parser", + "vers": "1.0.0", + "deps": [ + { + "name": "rstest", + "req": "^0.19", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "thiserror", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e", + "features": { + "unstable": [] + }, + "yanked": false, + "pubtime": "2025-04-01T14:32:40Z" + } + ] + }, + { + "path": "de/ra/deranged", + "header": "AwIAAABldGFnOiAiMzQ4MTU1NjI5NzhmYzk5NDg4ZTJiMzMwZTIzNTA0NGQiAA==", + "records": [ + { + "name": "deranged", + "vers": "0.5.8", + "deps": [ + { + "name": "deranged-macros", + "req": "=0.3.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "num-traits", + "req": "^0.2.15", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "powerfmt", + "req": "^0.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1.0.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand010", + "req": "^0.10.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "rand" + }, + { + "name": "rand010", + "req": "^0.10.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "rand" + }, + { + "name": "rand08", + "req": "^0.8.4", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "rand" + }, + { + "name": "rand08", + "req": "^0.8.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "rand" + }, + { + "name": "rand09", + "req": "^0.9.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "rand" + }, + { + "name": "rand09", + "req": "^0.9.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "rand" + }, + { + "name": "serde_core", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.86", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c", + "features": { + "alloc": [], + "default": [] + }, + "features2": { + "macros": ["dep:deranged-macros"], + "num": ["dep:num-traits"], + "powerfmt": ["dep:powerfmt"], + "quickcheck": ["dep:quickcheck", "alloc"], + "rand": ["rand08", "rand09", "rand010"], + "rand010": ["dep:rand010"], + "rand08": ["dep:rand08"], + "rand09": ["dep:rand09"], + "serde": ["dep:serde_core"] + }, + "yanked": false, + "rust_version": "1.85.0", + "pubtime": "2026-02-21T21:37:43Z", + "v": 2 + } + ] + }, + { + "path": "de/ri/derive_builder", + "header": "AwIAAABldGFnOiAiYTQ1YzcwODJlN2Y2NzgwNjU0NzVkZTk1ODU4ZmU0YjIiAA==", + "records": [ + { + "name": "derive_builder", + "vers": "0.20.2", + "deps": [ + { + "name": "derive_builder_macro", + "req": "=0.20.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustversion", + "req": "^1.0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.38", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(compiletests)", + "kind": "dev" + } + ], + "cksum": "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947", + "features": { + "alloc": ["derive_builder_macro/alloc"], + "clippy": ["derive_builder_macro/clippy"], + "default": ["std"], + "std": ["derive_builder_macro/lib_has_std"] + }, + "yanked": false, + "pubtime": "2024-10-08T16:55:17Z" + } + ] + }, + { + "path": "de/ri/derive_builder_core", + "header": "AwIAAABldGFnOiAiYjc4MTY5NzA4NWY2MGFiOTgzMDFkYTg4MDBkY2I3YTYiAA==", + "records": [ + { + "name": "derive_builder_core", + "vers": "0.20.2", + "deps": [ + { + "name": "darling", + "req": "^0.20.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1.0.37", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.35", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0.15", + "features": ["full", "extra-traits"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8", + "features": { + "alloc": [], + "clippy": [], + "lib_has_std": [] + }, + "yanked": false, + "pubtime": "2024-10-08T16:54:04Z" + } + ] + }, + { + "path": "de/ri/derive_builder_macro", + "header": "AwIAAABldGFnOiAiMDg2ODZkMDEyOTI4NGI2YzI5MGYxZDU3YjdkYTI5NjYiAA==", + "records": [ + { + "name": "derive_builder_macro", + "vers": "0.20.2", + "deps": [ + { + "name": "derive_builder_core", + "req": "=0.20.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0.15", + "features": ["full", "extra-traits"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c", + "features": { + "alloc": ["derive_builder_core/alloc"], + "clippy": ["derive_builder_core/clippy"], + "lib_has_std": ["derive_builder_core/lib_has_std"] + }, + "yanked": false, + "pubtime": "2024-10-08T16:54:13Z" + } + ] + }, + { + "path": "de/ri/derive_more", + "header": "AwIAAABldGFnOiAiMTUwNDc2YjY1NzA0MDA1OWY5YmI4YTIxZjQ1ZjJjYzgiAA==", + "records": [ + { + "name": "derive_more", + "vers": "2.1.1", + "deps": [ + { + "name": "derive_more-impl", + "req": "=2.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustc_version", + "req": "^0.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "rustversion", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.56", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134", + "features": { + "add": ["derive_more-impl/add"], + "add_assign": ["derive_more-impl/add_assign"], + "as_ref": ["derive_more-impl/as_ref"], + "constructor": ["derive_more-impl/constructor"], + "debug": ["derive_more-impl/debug"], + "default": ["std"], + "deref": ["derive_more-impl/deref"], + "deref_mut": ["derive_more-impl/deref_mut"], + "display": ["derive_more-impl/display"], + "eq": ["derive_more-impl/eq"], + "error": ["derive_more-impl/error"], + "from": ["derive_more-impl/from"], + "from_str": ["derive_more-impl/from_str"], + "full": [ + "add", + "add_assign", + "as_ref", + "constructor", + "debug", + "deref", + "deref_mut", + "display", + "eq", + "error", + "from", + "from_str", + "index", + "index_mut", + "into", + "into_iterator", + "is_variant", + "mul", + "mul_assign", + "not", + "sum", + "try_from", + "try_into", + "try_unwrap", + "unwrap" + ], + "index": ["derive_more-impl/index"], + "index_mut": ["derive_more-impl/index_mut"], + "into": ["derive_more-impl/into"], + "into_iterator": ["derive_more-impl/into_iterator"], + "is_variant": ["derive_more-impl/is_variant"], + "mul": ["derive_more-impl/mul"], + "mul_assign": ["derive_more-impl/mul_assign"], + "not": ["derive_more-impl/not"], + "std": [], + "sum": ["derive_more-impl/sum"], + "try_from": ["derive_more-impl/try_from"], + "try_into": ["derive_more-impl/try_into"], + "try_unwrap": ["derive_more-impl/try_unwrap"], + "unwrap": ["derive_more-impl/unwrap"] + }, + "features2": { + "testing-helpers": ["derive_more-impl/testing-helpers", "dep:rustc_version"] + }, + "yanked": false, + "rust_version": "1.81.0", + "pubtime": "2025-12-22T09:13:44Z", + "v": 2 + } + ] + }, + { + "path": "de/ri/derive_more-impl", + "header": "AwIAAABldGFnOiAiMDc5ODJjZDAyOTIwZGEyZWEyMjg1M2U0ZTg0NmJkZDEiAA==", + "records": [ + { + "name": "derive_more-impl", + "vers": "2.1.1", + "deps": [ + { + "name": "convert_case", + "req": "^0.10", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "itertools", + "req": "^0.14.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustc_version", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "syn", + "req": "^2.0.45", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "unicode-xid", + "req": "^0.2.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb", + "features": { + "add": ["syn/extra-traits", "syn/visit"], + "add_assign": ["syn/extra-traits", "syn/visit"], + "as_ref": ["syn/extra-traits", "syn/visit"], + "constructor": [], + "default": [], + "deref": [], + "deref_mut": [], + "eq": ["syn/extra-traits", "syn/visit"], + "error": ["syn/extra-traits"], + "from": ["syn/extra-traits"], + "index": [], + "index_mut": [], + "into": ["syn/extra-traits", "syn/visit-mut"], + "into_iterator": [], + "mul": ["syn/extra-traits", "syn/visit"], + "mul_assign": ["syn/extra-traits", "syn/visit"], + "not": ["syn/extra-traits"], + "sum": [], + "testing-helpers": ["syn/full"], + "try_from": [], + "try_into": ["syn/extra-traits", "syn/full", "syn/visit-mut"] + }, + "features2": { + "debug": ["syn/extra-traits", "dep:unicode-xid"], + "display": ["syn/extra-traits", "dep:unicode-xid", "dep:convert_case"], + "from_str": ["syn/full", "syn/visit", "dep:convert_case"], + "full": [ + "add", + "add_assign", + "as_ref", + "constructor", + "debug", + "deref", + "deref_mut", + "display", + "eq", + "error", + "from", + "from_str", + "index", + "index_mut", + "into", + "into_iterator", + "is_variant", + "mul", + "mul_assign", + "not", + "sum", + "try_from", + "try_into", + "try_unwrap", + "unwrap" + ], + "is_variant": ["dep:convert_case"], + "try_unwrap": ["dep:convert_case"], + "unwrap": ["dep:convert_case"] + }, + "yanked": false, + "rust_version": "1.81.0", + "pubtime": "2025-12-22T09:13:41Z", + "v": 2 + } + ] + }, + { + "path": "di/ge/digest", + "header": "AwIAAABldGFnOiAiZWU1MWVhZjc4OWExZTE4ZGE5YmQzOTEwNzA5ODVkN2QiAA==", + "records": [ + { + "name": "digest", + "vers": "0.10.7", + "deps": [ + { + "name": "blobby", + "req": "^0.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "block-buffer", + "req": "^0.10", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "const-oid", + "req": "^0.9", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "crypto-common", + "req": "^0.1.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "subtle", + "req": "^2.4", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292", + "features": { + "alloc": [], + "core-api": ["block-buffer"], + "default": ["core-api"], + "dev": ["blobby"], + "mac": ["subtle"], + "oid": ["const-oid"], + "rand_core": ["crypto-common/rand_core"], + "std": ["alloc", "crypto-common/std"] + }, + "yanked": false, + "pubtime": "2023-05-19T17:11:30Z" + }, + { + "name": "digest", + "vers": "0.11.3", + "deps": [ + { + "name": "blobby", + "req": "^0.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "block-buffer", + "req": "^0.12", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "common", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal", + "package": "crypto-common" + }, + { + "name": "const-oid", + "req": "^0.10", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ctutils", + "req": "^0.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sha2", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "zeroize", + "req": "^1.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2", + "features": { + "alloc": [], + "dev": ["blobby"], + "getrandom": ["common/getrandom", "rand_core"], + "rand_core": ["common/rand_core"] + }, + "features2": { + "block-api": ["dep:block-buffer"], + "default": ["block-api"], + "mac": ["dep:ctutils"], + "oid": ["dep:const-oid"], + "zeroize": ["dep:zeroize", "block-buffer?/zeroize"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-05-03T12:54:48Z", + "v": 2 + } + ] + }, + { + "path": "di/re/directories", + "header": "AwIAAABldGFnOiAiNjFkOThkZGVmNTU5Zjk0ZWNkZjNlOWZiNDhhZjAxODYiAA==", + "records": [ + { + "name": "directories", + "vers": "6.0.0", + "deps": [ + { + "name": "bencher", + "req": "^0.1.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "dirs-sys", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "16f5094c54661b38d03bd7e50df373292118db60b585c08a411c6d840017fe7d", + "features": {}, + "yanked": false, + "pubtime": "2025-01-12T17:19:05Z" + } + ] + }, + { + "path": "di/rs/dirs-sys", + "header": "AwIAAABldGFnOiAiNDAyZTNlYmNlZjVmZDk2YzNkM2M4NjQ2ZTRmNGE1Y2IiAA==", + "records": [ + { + "name": "dirs-sys", + "vers": "0.5.0", + "deps": [ + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "option-ext", + "req": "^0.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "redox_users", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"redox\")", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.59.0", + "features": [ + "Win32_UI_Shell", + "Win32_Foundation", + "Win32_Globalization", + "Win32_System_Com" + ], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab", + "features": {}, + "yanked": false, + "pubtime": "2025-01-11T22:10:02Z" + } + ] + }, + { + "path": "di/sp/displaydoc", + "header": "AwIAAABldGFnOiAiODg0YjBkNmRjMDA3NDg2ZWJkNWVhYTc3Yjc1NmY5YmMiAA==", + "records": [ + { + "name": "displaydoc", + "vers": "0.2.7", + "deps": [ + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "pretty_assertions", + "req": "^1.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustversion", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn", + "req": "^3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "thiserror", + "req": "^1.0.24", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.71.0", + "pubtime": "2026-07-28T13:58:21Z" + } + ] + }, + { + "path": "do/cu/document-features", + "header": "AwIAAABldGFnOiAiNDM3ODcwY2Q3Y2IyMzM5MjVkOGRlZTk3NmRkMDg4ZWQiAA==", + "records": [ + { + "name": "document-features", + "vers": "0.2.12", + "deps": [ + { + "name": "litrs", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61", + "features": { + "default": [], + "self-test": [] + }, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2025-10-24T09:43:31Z" + } + ] + }, + { + "path": "do/te/dotenvy", + "header": "AwIAAABldGFnOiAiOThlNjRlOThmODlmY2RlZDY1YWE4M2FlYjhhMDAwNWIiAA==", + "records": [ + { + "name": "dotenvy", + "vers": "0.15.7", + "deps": [ + { + "name": "clap", + "req": "^3.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "once_cell", + "req": "^1.16.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tempfile", + "req": "^3.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b", + "features": { + "cli": ["clap"] + }, + "yanked": false, + "rust_version": "1.56.1", + "pubtime": "2023-03-22T16:04:41Z" + } + ] + }, + { + "path": "du/nc/dunce", + "header": "AwIAAABldGFnOiAiZjRlNzQyNDA4MzM0YjQxMDMxNzY5NjQ0ZDlmNDZjMTciAA==", + "records": [ + { + "name": "dunce", + "vers": "1.0.5", + "deps": [], + "cksum": "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813", + "features": {}, + "yanked": false, + "pubtime": "2024-08-04T01:36:46Z" + } + ] + }, + { + "path": "dy/n-/dyn-clone", + "header": "AwIAAABldGFnOiAiZTVlNWMyMjJkNzNmOGNlZGJjYjY4MzE0ODAwNWNjNDkiAA==", + "records": [ + { + "name": "dyn-clone", + "vers": "1.0.20", + "deps": [ + { + "name": "rustversion", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.66", + "features": ["diff"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555", + "features": {}, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-07-27T19:29:46Z" + } + ] + }, + { + "path": "ei/th/either", + "header": "AwIAAABldGFnOiAiNWEyMWViZDVlYWZkYThjZTZkMDZjMjVhZDM1OGFlNzAiAA==", + "records": [ + { + "name": "either", + "vers": "1.19.0", + "deps": [ + { + "name": "serde", + "req": "^1.0.95", + "features": ["alloc", "derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be", + "features": { + "default": ["std"], + "std": [], + "use_std": ["std"] + }, + "yanked": false, + "rust_version": "1.63.0", + "pubtime": "2026-10-06T18:29:04Z" + } + ] + }, + { + "path": "en/co/encode_unicode", + "header": "AwIAAABldGFnOiAiMDFhOTk1OTEzMmIxZGYxNGIwMTk5Yzg3NGQ0MTZlZTYiAA==", + "records": [ + { + "name": "encode_unicode", + "vers": "1.0.0", + "deps": [ + { + "name": "ascii", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "lazy_static", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "dev" + }, + { + "name": "minreq", + "req": "^2.6", + "features": ["https-native"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "pubtime": "2022-08-07T14:19:49Z" + } + ] + }, + { + "path": "en/um/enum-iterator", + "header": "AwIAAABldGFnOiAiZDZiNzFjNGE2N2M0NTg1NjJiZGQ1NzFiZWI1OTUwMzUiAA==", + "records": [ + { + "name": "enum-iterator", + "vers": "2.3.0", + "deps": [ + { + "name": "enum-iterator-derive", + "req": "^1.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "a4549325971814bda7a44061bf3fe7e487d447cba01e4220a4b454d630d7a016", + "features": {}, + "yanked": false, + "pubtime": "2025-09-08T15:11:01Z" + } + ] + }, + { + "path": "en/um/enum-iterator-derive", + "header": "AwIAAABldGFnOiAiZTY2ZmM0MWE0MjkzMmU0MmRhZjkwZTYwNzM5MmZiMDciAA==", + "records": [ + { + "name": "enum-iterator-derive", + "vers": "1.5.0", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.39", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0.15", + "features": ["extra-traits"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842", + "features": {}, + "yanked": false, + "pubtime": "2025-09-08T15:10:18Z" + } + ] + }, + { + "path": "en/um/enumset", + "header": "AwIAAABldGFnOiAiYjViMWI0OGQ5OGRjNmJhNjBkZjI2MGIwMzgyNjBlYjQiAA==", + "records": [ + { + "name": "enumset", + "vers": "1.1.14", + "deps": [ + { + "name": "defmt", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "enumset_derive", + "req": "^0.15.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "ccc5801fd11762e24d1e420d01d2ac518f2a2ca4329d4fbb6639f2412b6204e0", + "features": { + "alloc": [], + "proc-macro-crate": ["enumset_derive/proc-macro-crate"], + "serde2": ["enumset_derive/serde2_deprecation_warning"], + "std": [ + "alloc", + "enumset_derive/proc-macro-crate", + "enumset_derive/std_deprecation_warning" + ] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-20T14:18:57Z" + } + ] + }, + { + "path": "en/um/enumset_derive", + "header": "AwIAAABldGFnOiAiNTkyNDdjMTA0MmFiM2VkNjA0M2NhZmMyZDlhYWU2NjAiAA==", + "records": [ + { + "name": "enumset_derive", + "vers": "0.15.0", + "deps": [ + { + "name": "darling", + "req": "^0.21.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro-crate", + "req": "^3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "4bd536557b58c682b217b8fb199afdff47cd3eff260623f19e77074eb073d63a", + "features": { + "serde2_deprecation_warning": [], + "std_deprecation_warning": [] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-05-07T02:09:58Z" + } + ] + }, + { + "path": "eq/ui/equivalent", + "header": "AwIAAABldGFnOiAiNDAzYWFhMjg5ZTc2MDhkZjExMDU4MzQ1NGEwZmQ5NTYiAA==", + "records": [ + { + "name": "equivalent", + "vers": "1.0.2", + "deps": [], + "cksum": "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f", + "features": {}, + "yanked": false, + "rust_version": "1.6", + "pubtime": "2025-02-14T22:14:18Z" + } + ] + }, + { + "path": "er/rn/errno", + "header": "AwIAAABldGFnOiAiZGJmNTUxMTljNDczZjI2MzI2MTc3NTdjNTNmZThmZjYiAA==", + "records": [ + { + "name": "errno", + "vers": "0.3.14", + "deps": [ + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os=\"hermit\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os=\"wasi\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.52, <0.62", + "features": ["Win32_Foundation", "Win32_System_Diagnostics_Debug"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb", + "features": { + "default": ["std"], + "std": ["libc/std"] + }, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2025-09-09T04:35:15Z" + } + ] + }, + { + "path": "es/ca/escape8259", + "header": "AwIAAABldGFnOiAiNjRmYzdkMDdiYjllNmU4MDBmMzVkMTQxZTM4NzEzZmYiAA==", + "records": [ + { + "name": "escape8259", + "vers": "0.5.4", + "deps": [ + { + "name": "rustversion", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "9f1f0d310082fd5de539d4f41601182241147498444a7695c520288a0cdbead6", + "features": {}, + "yanked": false, + "pubtime": "2026-10-06T04:20:01Z" + } + ] + }, + { + "path": "et/ce/etcetera", + "header": "AwIAAABldGFnOiAiYjhlYWIxZDgxNzY5MTA4NGU3YjM0NzQ1MGJiNzYxMzgiAA==", + "records": [ + { + "name": "etcetera", + "vers": "0.8.0", + "deps": [ + { + "name": "cfg-if", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "home", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "windows-sys", + "req": "^0.48", + "features": ["Win32_Foundation", "Win32_UI_Shell"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943", + "features": {}, + "yanked": false, + "pubtime": "2023-04-26T15:27:41Z" + } + ] + }, + { + "path": "ev/en/event-listener", + "header": "AwIAAABldGFnOiAiYjY2N2M3Y2E1NzUzODE0YzYwZjNlYTQzMWZkZTlmMWUiAA==", + "records": [ + { + "name": "event-listener", + "vers": "5.4.2", + "deps": [ + { + "name": "criterion", + "req": "^0.8", + "features": ["cargo_bench_support"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "critical-section", + "req": "^1.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "critical-section", + "req": "^1.2.0", + "features": ["std"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "futures-lite", + "req": "^2.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "loom", + "req": "^0.7", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(loom)", + "kind": "normal" + }, + { + "name": "parking", + "req": "^2.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(target_family = \"wasm\"))", + "kind": "normal" + }, + { + "name": "pin-project-lite", + "req": "^0.2.12", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "portable-atomic-util", + "req": "^0.2.0", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "portable_atomic_crate", + "req": "^1.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "portable-atomic" + }, + { + "name": "try-lock", + "req": "^0.2.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "waker-fn", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_family = \"wasm\")", + "kind": "dev" + } + ], + "cksum": "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2", + "features": { + "default": ["std"], + "portable-atomic": ["portable-atomic-util", "portable_atomic_crate"], + "std": ["parking"] + }, + "features2": { + "loom": ["parking?/loom", "dep:loom"] + }, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2026-07-27T11:31:20Z", + "v": 2 + } + ] + }, + { + "path": "fa/ll/fallible-iterator", + "header": "AwIAAABldGFnOiAiYTBmOTAxOTMwMTMzNDdkYjE3MWI0NmZiMDc1NzY2NTciAA==", + "records": [ + { + "name": "fallible-iterator", + "vers": "0.2.0", + "deps": [], + "cksum": "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7", + "features": { + "alloc": [], + "default": ["std"], + "std": [] + }, + "yanked": false, + "pubtime": "2019-03-10T23:23:25Z" + } + ] + }, + { + "path": "fa/st/fastrand", + "header": "AwIAAABldGFnOiAiYWQ4OTQ0ZmNhNDRjNmNlMzE0ODhiNzEyMWY3NTMwY2EiAA==", + "records": [ + { + "name": "fastrand", + "vers": "2.5.0", + "deps": [ + { + "name": "getrandom", + "req": "^0.4", + "features": ["wasm_js"], + "optional": true, + "default_features": true, + "target": "cfg(all(any(target_arch = \"wasm32\", target_arch = \"wasm64\"), target_os = \"unknown\"))", + "kind": "normal" + }, + { + "name": "getrandom", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "getrandom", + "req": "^0.4", + "features": ["wasm_js"], + "optional": false, + "default_features": true, + "target": "cfg(all(any(target_arch = \"wasm32\", target_arch = \"wasm64\"), target_os = \"unknown\"))", + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(any(target_arch = \"wasm32\", target_arch = \"wasm64\"), target_os = \"unknown\"))", + "kind": "dev" + }, + { + "name": "wyhash", + "req": "^0.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223", + "features": { + "alloc": [], + "default": ["std"], + "js": ["std", "getrandom"], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2026-07-19T12:40:53Z" + } + ] + }, + { + "path": "fi/le/filetime", + "header": "AwIAAABldGFnOiAiYTZjYjhlZDk3MGY1N2I0ZjQzYWNlNWYzMWFhODcwZDEiAA==", + "records": [ + { + "name": "filetime", + "vers": "0.2.29", + "deps": [ + { + "name": "cfg-if", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.27", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759", + "features": {}, + "yanked": false, + "rust_version": "1.75.0", + "pubtime": "2026-05-12T22:38:22Z" + } + ] + }, + { + "path": "fi/nd/find-msvc-tools", + "header": "AwIAAABldGFnOiAiMWE5MmMxMzUyYmQ5NzFmNzJiNjI0NTFkZGE0ZDMzN2UiAA==", + "records": [ + { + "name": "find-msvc-tools", + "vers": "0.1.14", + "deps": [], + "cksum": "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484", + "features": {}, + "yanked": false, + "rust_version": "1.65.0", + "pubtime": "2026-09-25T10:09:48Z" + } + ] + }, + { + "path": "fi/xe/fixedbitset", + "header": "AwIAAABldGFnOiAiZGRmYzA0MDJmZTMwMmQyZGJmMjdkNjlhM2NjMzM0ZjQiAA==", + "records": [ + { + "name": "fixedbitset", + "vers": "0.5.7", + "deps": [ + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-04-14T23:53:05Z" + } + ] + }, + { + "path": "fl/at/flate2", + "header": "AwIAAABldGFnOiAiYjY4NjJjNmRmM2JmMzE1MWY1ZDdmMDVkZjAxZDk3MmUiAA==", + "records": [ + { + "name": "flate2", + "vers": "1.1.10", + "deps": [ + { + "name": "crc32fast", + "req": "^1.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "document-features", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "libz-ng-sys", + "req": "^1.1.16", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libz-sys", + "req": "^1.1.20", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "miniz_oxide", + "req": "^0.9.0", + "features": ["simd"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "zlib-rs", + "req": "^0.6.0", + "features": ["rust-allocator"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb", + "features": { + "any_c_zlib": ["any_zlib"], + "any_impl": [], + "any_zlib": ["any_impl"] + }, + "features2": { + "cloudflare_zlib": ["zlib"], + "default": ["rust_backend", "runtime_detection"], + "miniz-sys": ["rust_backend"], + "miniz_oxide": ["any_impl", "dep:miniz_oxide", "dep:crc32fast"], + "runtime_detection": ["zlib-rs?/std", "crc32fast?/std"], + "rust_backend": ["miniz_oxide", "any_impl"], + "zlib": ["any_c_zlib", "libz-sys", "dep:crc32fast"], + "zlib-default": ["any_c_zlib", "libz-sys/default", "dep:crc32fast"], + "zlib-ng": ["any_c_zlib", "libz-ng-sys", "dep:crc32fast"], + "zlib-ng-compat": ["zlib", "libz-sys/zlib-ng", "dep:crc32fast"], + "zlib-rs": ["any_zlib", "dep:zlib-rs"] + }, + "yanked": false, + "rust_version": "1.67.0", + "pubtime": "2026-08-28T04:35:22Z", + "v": 2 + } + ] + }, + { + "path": "fo/ld/foldhash", + "header": "AwIAAABldGFnOiAiNTA1MmZiYzJmYmM4YTY0MDJhZWZjMmU0MTc3MDA2ZjIiAA==", + "records": [ + { + "name": "foldhash", + "vers": "0.1.5", + "deps": [ + { + "name": "ahash", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "chrono", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "fxhash", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hashbrown", + "req": "^0.14", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "uuid", + "req": "^1.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-03-15T20:10:19Z" + }, + { + "name": "foldhash", + "vers": "0.2.0", + "deps": [ + { + "name": "ahash", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "chrono", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "fxhash", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hashbrown", + "req": "^0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rapidhash", + "req": "^3.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "uuid", + "req": "^1.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb", + "features": { + "default": ["std"], + "nightly": [], + "std": [] + }, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-08-23T19:14:01Z" + } + ] + }, + { + "path": "fo/rm/form_urlencoded", + "header": "AwIAAABldGFnOiAiOWZmODhiOGI4ZjZjNTJiZmUxMzNhYmQ1YTg2YTcxZmUiAA==", + "records": [ + { + "name": "form_urlencoded", + "vers": "1.2.2", + "deps": [ + { + "name": "percent-encoding", + "req": "^2.3.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf", + "features": { + "alloc": ["percent-encoding/alloc"], + "default": ["std"], + "std": ["alloc", "percent-encoding/std"] + }, + "yanked": false, + "rust_version": "1.51", + "pubtime": "2025-08-21T08:47:43Z" + } + ] + }, + { + "path": "fs/_e/fs_extra", + "header": "AwIAAABldGFnOiAiZWNmNGI2OWM0OTkzYWRjZDk0OWNlMGI5ZjA4YmQzYzAiAA==", + "records": [ + { + "name": "fs_extra", + "vers": "1.3.0", + "deps": [], + "cksum": "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c", + "features": {}, + "yanked": false, + "pubtime": "2023-02-03T17:59:27Z" + } + ] + }, + { + "path": "fs/-s/fs-set-times", + "header": "AwIAAABldGFnOiAiNzAzNzNjMDM1ZjY2ZjhkMTA1NWY1YzRkY2RkNTQ1YjAiAA==", + "records": [ + { + "name": "fs-set-times", + "vers": "0.20.3", + "deps": [ + { + "name": "io-lifetimes", + "req": "^2.0.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rustix", + "req": "^1.0.0", + "features": ["fs", "time"], + "optional": false, + "default_features": true, + "target": "cfg(not(windows))", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.52, <0.60", + "features": ["Win32_Foundation", "Win32_Storage_FileSystem"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "94e7099f6313ecacbe1256e8ff9d617b75d1bcb16a6fddef94866d225a01a14a", + "features": {}, + "yanked": false, + "pubtime": "2025-03-10T15:59:24Z" + } + ] + }, + { + "path": "fu/tu/futures", + "header": "AwIAAABldGFnOiAiOTk2ZTJlNTY4NDFlZjNjMWRlZmFkMzc5Yjc3M2EyZWMiAA==", + "records": [ + { + "name": "futures", + "vers": "0.3.34", + "deps": [ + { + "name": "assert_matches", + "req": "^1.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "futures-channel", + "req": "^0.3.34", + "features": ["sink"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-core", + "req": "^0.3.34", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-executor", + "req": "^0.3.34", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-io", + "req": "^0.3.34", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-sink", + "req": "^0.3.34", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-task", + "req": "^0.3.34", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-util", + "req": "^0.3.34", + "features": ["sink"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "pin-project", + "req": "^1.0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio", + "req": "^0.1.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3", + "features": { + "alloc": [ + "futures-core/alloc", + "futures-task/alloc", + "futures-sink/alloc", + "futures-channel/alloc", + "futures-util/alloc" + ], + "async-await": ["futures-util/async-await", "futures-util/async-await-macro"], + "bilock": ["futures-util/bilock"], + "cfg-target-has-atomic": [], + "compat": ["std", "futures-util/compat"], + "default": ["std", "async-await", "executor"], + "executor": ["std", "futures-executor/std"], + "io-compat": ["compat", "futures-util/io-compat"], + "spin": ["futures-util/spin"], + "std": [ + "alloc", + "futures-core/std", + "futures-task/std", + "futures-io/std", + "futures-sink/std", + "futures-util/std", + "futures-util/io", + "futures-util/channel" + ], + "thread-pool": ["executor", "futures-executor/thread-pool"], + "unstable": [ + "futures-core/unstable", + "futures-task/unstable", + "futures-channel/unstable", + "futures-io/unstable", + "futures-util/unstable" + ], + "write-all-vectored": ["futures-util/write-all-vectored"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-08-11T12:13:28Z" + } + ] + }, + { + "path": "fu/tu/futures-channel", + "header": "AwIAAABldGFnOiAiY2FjZjM5YTc5MWQzYjZkYmFkNTEyODRmNmZhYjZlM2EiAA==", + "records": [ + { + "name": "futures-channel", + "vers": "0.3.34", + "deps": [ + { + "name": "futures-core", + "req": "^0.3.34", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-sink", + "req": "^0.3.34", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4", + "features": { + "alloc": ["futures-core/alloc"], + "cfg-target-has-atomic": [], + "default": ["std"], + "sink": ["futures-sink"], + "std": ["alloc", "futures-core/std"], + "unstable": [] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-08-11T12:13:10Z" + } + ] + }, + { + "path": "fu/tu/futures-core", + "header": "AwIAAABldGFnOiAiMTMzNzRiYmNjOGNiN2MyYmY5MzMwODMzOWZiMmE1OTYiAA==", + "records": [ + { + "name": "futures-core", + "vers": "0.3.34", + "deps": [ + { + "name": "portable-atomic", + "req": "^1.3", + "features": ["require-cas"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e", + "features": { + "alloc": [], + "cfg-target-has-atomic": [], + "default": ["std"], + "std": ["alloc"], + "unstable": [] + }, + "yanked": false, + "rust_version": "1.36", + "pubtime": "2026-08-11T12:13:01Z" + } + ] + }, + { + "path": "fu/tu/futures-executor", + "header": "AwIAAABldGFnOiAiOTI1MzA0NTU3MDI4Y2U0NjhkZmQxNzEzZjU4NjNjZWIiAA==", + "records": [ + { + "name": "futures-executor", + "vers": "0.3.34", + "deps": [ + { + "name": "futures-core", + "req": "^0.3.34", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-task", + "req": "^0.3.34", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-util", + "req": "^0.3.34", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432", + "features": { + "default": ["std"], + "std": ["futures-core/std", "futures-task/std", "futures-util/std"], + "thread-pool": ["std"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-08-11T12:13:23Z" + } + ] + }, + { + "path": "fu/tu/futures-intrusive", + "header": "AwIAAABldGFnOiAiZGM1NjhmYTAwZGE4YjU3MjM3N2RjZDk2YTI5ZjYwOGIiAA==", + "records": [ + { + "name": "futures-intrusive", + "vers": "0.5.0", + "deps": [ + { + "name": "async-std", + "req": "^1.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "crossbeam", + "req": "^0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "futures", + "req": "^0.3.0", + "features": ["async-await"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "futures-core", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-test", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "lazy_static", + "req": "^1.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "lock_api", + "req": "^0.4.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "parking_lot", + "req": "^0.12.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pin-utils", + "req": "^0.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "signal-hook", + "req": "^0.1.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio", + "req": "^1.14", + "features": ["full"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f", + "features": { + "alloc": ["futures-core/alloc"], + "default": ["std"], + "std": ["alloc", "parking_lot"] + }, + "yanked": false, + "pubtime": "2022-11-04T06:14:20Z" + } + ] + }, + { + "path": "fu/tu/futures-io", + "header": "AwIAAABldGFnOiAiNjI4YzRiODVmZDIzYzk3ZGZlOWZjNmM2OGU4NjJmZWUiAA==", + "records": [ + { + "name": "futures-io", + "vers": "0.3.34", + "deps": [], + "cksum": "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed", + "features": { + "default": ["std"], + "std": [], + "unstable": [] + }, + "yanked": false, + "rust_version": "1.36", + "pubtime": "2026-08-11T12:13:03Z" + } + ] + }, + { + "path": "fu/tu/futures-macro", + "header": "AwIAAABldGFnOiAiZWU1NjVjNWJkMzgzN2NkNDgyMDYyMzYyOTZmNTFjN2UiAA==", + "records": [ + { + "name": "futures-macro", + "vers": "0.3.34", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.60", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3.0", + "features": ["full"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-08-11T12:13:14Z" + } + ] + }, + { + "path": "fu/tu/futures-sink", + "header": "AwIAAABldGFnOiAiN2FkNWMzZmE4M2Q4MTg4YTUxMTU4MThiMjhhNzI5YTQiAA==", + "records": [ + { + "name": "futures-sink", + "vers": "0.3.34", + "deps": [], + "cksum": "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d", + "features": { + "alloc": [], + "default": ["std"], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.36", + "pubtime": "2026-08-11T12:13:06Z" + } + ] + }, + { + "path": "fu/tu/futures-task", + "header": "AwIAAABldGFnOiAiY2U3ZjZkMmQwNzIzMWViMTcwZDkzOTE1ODk5MzZhODAiAA==", + "records": [ + { + "name": "futures-task", + "vers": "0.3.34", + "deps": [], + "cksum": "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd", + "features": { + "alloc": [], + "cfg-target-has-atomic": [], + "default": ["std"], + "std": ["alloc"], + "unstable": [] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-08-11T12:13:07Z" + } + ] + }, + { + "path": "fu/tu/futures-util", + "header": "AwIAAABldGFnOiAiMmYxMTVlMjMzOGQzMjExYWUzNzZlNDNlYWY3MmIwNjMiAA==", + "records": [ + { + "name": "futures-util", + "vers": "0.3.34", + "deps": [ + { + "name": "futures-channel", + "req": "^0.3.34", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-core", + "req": "^0.3.34", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-io", + "req": "^0.3.34", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-macro", + "req": "=0.3.34", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-sink", + "req": "^0.3.34", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-task", + "req": "^0.3.34", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures_01", + "req": "^0.1.25", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "futures" + }, + { + "name": "libc", + "req": "^0.2.26", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memchr", + "req": "^2.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pin-project-lite", + "req": "^0.2.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "portable-atomic-util", + "req": "^0.2.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "portable_atomic_crate", + "req": "^1.13.1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "portable-atomic" + }, + { + "name": "slab", + "req": "^0.4.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "spin", + "req": "^0.12.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^0.1.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-io", + "req": "^0.1.9", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc", + "features": { + "alloc": ["futures-core/alloc", "futures-task/alloc", "slab"], + "async-await": [], + "async-await-macro": ["async-await", "futures-macro"], + "bilock": [], + "cfg-target-has-atomic": [], + "channel": ["std", "futures-channel"], + "compat": ["std", "futures_01", "libc"], + "default": ["std", "async-await", "async-await-macro"], + "io": ["std", "futures-io", "memchr"], + "io-compat": ["io", "compat", "tokio-io", "libc"], + "portable-atomic": ["futures-core/portable-atomic", "portable_atomic_crate"], + "portable-atomic-alloc": ["portable-atomic-util/alloc", "portable-atomic"], + "sink": ["futures-sink"], + "std": ["alloc", "futures-core/std", "futures-task/std", "slab/std"], + "unstable": ["futures-core/unstable", "futures-task/unstable"], + "write-all-vectored": ["io"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-08-11T12:13:19Z" + } + ] + }, + { + "path": "ge/ne/generic-array", + "header": "AwIAAABldGFnOiAiOGE0ZTFiYmVmNjI4NjM0Mjc2MzI2NWZiYWUyNGU0ZjEiAA==", + "records": [ + { + "name": "generic-array", + "vers": "0.14.7", + "deps": [ + { + "name": "bincode", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "typenum", + "req": "^1.12", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "version_check", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "zeroize", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a", + "features": { + "more_lengths": [] + }, + "yanked": false, + "pubtime": "2023-03-28T00:01:29Z" + } + ] + }, + { + "path": "ge/tr/getrandom", + "header": "AwIAAABldGFnOiAiNjM1OWY3YmUyMGQ5YjdlYjUxZDIwODNmZTNmYjZlMjQiAA==", + "records": [ + { + "name": "getrandom", + "vers": "0.2.17", + "deps": [ + { + "name": "cfg-if", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "compiler_builtins", + "req": "^0.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "core", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "js-sys", + "req": "^0.3", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(all(any(target_arch = \"wasm32\", target_arch = \"wasm64\"), target_os = \"unknown\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "wasi", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"wasi\")", + "kind": "normal" + }, + { + "name": "wasm-bindgen", + "req": "^0.2.62", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(any(target_arch = \"wasm32\", target_arch = \"wasm64\"), target_os = \"unknown\"))", + "kind": "normal" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3.18", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(any(target_arch = \"wasm32\", target_arch = \"wasm64\"), target_os = \"unknown\"))", + "kind": "dev" + } + ], + "cksum": "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0", + "features": { + "custom": [], + "js": ["wasm-bindgen", "js-sys"], + "linux_disable_fallback": [], + "rdrand": [], + "rustc-dep-of-std": [ + "compiler_builtins", + "core", + "libc/rustc-dep-of-std", + "wasi/rustc-dep-of-std" + ], + "std": [], + "test-in-browser": [] + }, + "yanked": false, + "pubtime": "2026-01-11T21:09:53Z" + }, + { + "name": "getrandom", + "vers": "0.3.4", + "deps": [ + { + "name": "cfg-if", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "js-sys", + "req": "^0.3.77", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\"), target_feature = \"atomics\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(any(target_os = \"linux\", target_os = \"android\"), not(any(all(target_os = \"linux\", target_env = \"\"), getrandom_backend = \"custom\", getrandom_backend = \"linux_raw\", getrandom_backend = \"rdrand\", getrandom_backend = \"rndr\"))))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"hurd\", target_os = \"illumos\", target_os = \"cygwin\", all(target_os = \"horizon\", target_arch = \"arm\")))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"haiku\", target_os = \"redox\", target_os = \"nto\", target_os = \"aix\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"ios\", target_os = \"visionos\", target_os = \"watchos\", target_os = \"tvos\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"macos\", target_os = \"openbsd\", target_os = \"vita\", target_os = \"emscripten\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"netbsd\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"solaris\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"vxworks\")", + "kind": "normal" + }, + { + "name": "r-efi", + "req": "^5.1", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_os = \"uefi\", getrandom_backend = \"efi_rng\"))", + "kind": "normal" + }, + { + "name": "wasip2", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_arch = \"wasm32\", target_os = \"wasi\", target_env = \"p2\"))", + "kind": "normal" + }, + { + "name": "wasm-bindgen", + "req": "^0.2.98", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\")))", + "kind": "normal" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\")))", + "kind": "dev" + } + ], + "cksum": "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd", + "features": { + "std": [] + }, + "features2": { + "wasm_js": ["dep:wasm-bindgen", "dep:js-sys"] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2025-10-14T17:47:36Z", + "v": 2 + }, + { + "name": "getrandom", + "vers": "0.4.3", + "deps": [ + { + "name": "cfg-if", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "js-sys", + "req": "^0.3.77", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(target_family = \"wasm\", any(target_os = \"unknown\", target_os = \"none\"), target_feature = \"atomics\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(any(target_os = \"linux\", target_os = \"android\"), not(any(all(target_os = \"linux\", target_env = \"\"), getrandom_backend = \"custom\", getrandom_backend = \"linux_raw\", getrandom_backend = \"rdrand\", getrandom_backend = \"rndr\"))))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"hurd\", target_os = \"illumos\", target_os = \"cygwin\", all(target_os = \"horizon\", target_arch = \"arm\")))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"haiku\", target_os = \"redox\", target_os = \"nto\", target_os = \"aix\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"ios\", target_os = \"visionos\", target_os = \"watchos\", target_os = \"tvos\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"macos\", target_os = \"openbsd\", target_os = \"vita\", target_os = \"emscripten\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"netbsd\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"solaris\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.154", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"vxworks\")", + "kind": "normal" + }, + { + "name": "r-efi", + "req": "^6", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_os = \"uefi\", getrandom_backend = \"efi_rng\"))", + "kind": "normal" + }, + { + "name": "rand_core", + "req": "^0.10.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasm-bindgen", + "req": "^0.2.98", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(target_family = \"wasm\", any(target_os = \"unknown\", target_os = \"none\")))", + "kind": "normal" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_family = \"wasm\", any(target_os = \"unknown\", target_os = \"none\")))", + "kind": "dev" + } + ], + "cksum": "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099", + "features": { + "std": [] + }, + "features2": { + "sys_rng": ["dep:rand_core"], + "wasm_js": ["dep:wasm-bindgen", "dep:js-sys"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-06-17T18:01:59Z", + "v": 2 + } + ] + }, + { + "path": "gi/ml/gimli", + "header": "AwIAAABldGFnOiAiM2UwN2EwYjk5YjBlMjBhOGIwZjc5MTA0OTMyZmM2YjQiAA==", + "records": [ + { + "name": "gimli", + "vers": "0.32.3", + "deps": [ + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "fallible-iterator", + "req": "^0.3.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "stable_deref_trait", + "req": "^1.1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "test-assembler", + "req": "^0.1.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7", + "features": { + "read": ["read-core"], + "read-core": [] + }, + "features2": { + "default": ["read-all", "write"], + "endian-reader": ["read", "dep:stable_deref_trait"], + "fallible-iterator": ["dep:fallible-iterator"], + "read-all": ["read", "std", "fallible-iterator", "endian-reader"], + "rustc-dep-of-std": ["dep:core", "dep:alloc"], + "std": ["fallible-iterator?/std", "stable_deref_trait?/std"], + "write": ["dep:indexmap"] + }, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-09-13T02:44:33Z", + "v": 2 + }, + { + "name": "gimli", + "vers": "0.33.0", + "deps": [ + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "criterion", + "req": "^0.8.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "fallible-iterator", + "req": "^0.3.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "fnv", + "req": "^1.0.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "hashbrown", + "req": "^0.16.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2.0.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "stable_deref_trait", + "req": "^1.1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "test-assembler", + "req": "^0.1.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "0bf7f043f89559805f8c7cacc432749b2fa0d0a0a9ee46ce47164ed5ba7f126c", + "features": { + "read": ["read-core"], + "read-core": [] + }, + "features2": { + "default": ["read-all", "write"], + "endian-reader": ["read", "dep:stable_deref_trait"], + "fallible-iterator": ["dep:fallible-iterator"], + "read-all": ["read", "std", "endian-reader"], + "rustc-dep-of-std": ["dep:core", "dep:alloc"], + "std": ["stable_deref_trait?/std"], + "write": ["dep:fnv", "dep:hashbrown", "dep:indexmap"] + }, + "yanked": false, + "rust_version": "1.88", + "pubtime": "2026-01-24T05:33:59Z", + "v": 2 + } + ] + }, + { + "path": "gl/ob/glob", + "header": "AwIAAABldGFnOiAiYmFmZGE4MzdhNjQ5M2FkYWMwMWUzMTAyZDcxZWY0ZTkiAA==", + "records": [ + { + "name": "glob", + "vers": "0.3.4", + "deps": [ + { + "name": "doc-comment", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tempfile", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b", + "features": {}, + "yanked": false, + "rust_version": "1.63.0", + "pubtime": "2026-07-21T14:53:49Z" + } + ] + }, + { + "path": "gl/ob/globset", + "header": "AwIAAABldGFnOiAiOGI0MTgxN2VhNmI4Y2Q4YzIzYTM2Y2FjNmQ2NWQ4NzMiAA==", + "records": [ + { + "name": "globset", + "vers": "0.4.20", + "deps": [ + { + "name": "aho-corasick", + "req": "^1.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "arbitrary", + "req": "^1.3.2", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bstr", + "req": "^1.6.2", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "glob", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "log", + "req": "^0.4.20", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "regex-automata", + "req": "^0.4.18", + "features": ["std", "perf", "syntax", "meta", "nfa", "hybrid"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "regex-syntax", + "req": "^0.8.0", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.188", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.107", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "07c34a9410465b45bd9787443bc7370f37735bad04b0f0cd57ff1a3186c98988", + "features": { + "default": ["log"], + "serde1": ["serde"], + "simd-accel": [] + }, + "features2": { + "arbitrary": ["dep:arbitrary"] + }, + "yanked": false, + "rust_version": "1.88", + "pubtime": "2026-08-04T13:59:29Z", + "v": 2 + } + ] + }, + { + "path": "ha/lf/half", + "header": "AwIAAABldGFnOiAiOGE2ZTcxZTMwMzM0YTBkZThmMTE2MzE1ZWY4YmQ4ODQiAA==", + "records": [ + { + "name": "half", + "vers": "2.7.1", + "deps": [ + { + "name": "arbitrary", + "req": "^1.4.1", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytemuck", + "req": "^1.4.1", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "criterion", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "crunchy", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"spirv\")", + "kind": "normal" + }, + { + "name": "crunchy", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "num-traits", + "req": "^0.2.16", + "features": ["libm"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quickcheck_macros", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9.0", + "features": ["thread_rng"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.9.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand_distr", + "req": "^0.5.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rkyv", + "req": "^0.8.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerocopy", + "req": "^0.8.26", + "features": ["derive", "simd"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b", + "features": { + "alloc": [], + "default": ["std"], + "nightly": [], + "std": ["alloc"], + "use-intrinsics": [], + "zerocopy": [] + }, + "features2": { + "rand_distr": ["dep:rand", "dep:rand_distr"] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2025-10-14T03:59:26Z", + "v": 2 + } + ] + }, + { + "path": "ha/sh/hash32", + "header": "AwIAAABldGFnOiAiN2U1NGQ3YzYxZDNkYWM3ZjVjNTNlZjFiMDYxMDZmOTciAA==", + "records": [ + { + "name": "hash32", + "vers": "0.3.1", + "deps": [ + { + "name": "byteorder", + "req": "^1.2.2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606", + "features": {}, + "yanked": false, + "pubtime": "2022-08-09T13:44:28Z" + } + ] + }, + { + "path": "ha/sh/hashbrown", + "header": "AwIAAABldGFnOiAiZDg0ZDljN2I3NTVmYmRkYzg4OTJlN2M4NWNlMDEwYzQiAA==", + "records": [ + { + "name": "hashbrown", + "vers": "0.14.5", + "deps": [ + { + "name": "ahash", + "req": "^0.8.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "allocator-api2", + "req": "^0.2.9", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "bumpalo", + "req": "^3.13.0", + "features": ["allocator-api2"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "compiler_builtins", + "req": "^0.1.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "doc-comment", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "equivalent", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "fnv", + "req": "^1.0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "lazy_static", + "req": "^1.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.8.3", + "features": ["small_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rkyv", + "req": "^0.7.42", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rkyv", + "req": "^0.7.42", + "features": ["validation"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.25", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_test", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1", + "features": { + "default": ["ahash", "inline-more", "allocator-api2"], + "inline-more": [], + "raw": [], + "rustc-internal-api": [] + }, + "features2": { + "nightly": ["allocator-api2?/nightly", "bumpalo/allocator_api"], + "rustc-dep-of-std": [ + "nightly", + "core", + "compiler_builtins", + "alloc", + "rustc-internal-api" + ] + }, + "yanked": false, + "rust_version": "1.63.0", + "pubtime": "2024-04-28T18:32:09Z", + "v": 2 + }, + { + "name": "hashbrown", + "vers": "0.15.5", + "deps": [ + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "allocator-api2", + "req": "^0.2.9", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "bumpalo", + "req": "^3.13.0", + "features": ["allocator-api2"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "doc-comment", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "equivalent", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "fnv", + "req": "^1.0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "foldhash", + "req": "^0.1.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "lazy_static", + "req": "^1.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9.0", + "features": ["small_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "^1.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.25", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_test", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1", + "features": { + "inline-more": [], + "nightly": ["bumpalo/allocator_api"], + "raw-entry": [], + "rustc-dep-of-std": ["nightly", "core", "alloc", "rustc-internal-api"], + "rustc-internal-api": [] + }, + "features2": { + "default": [ + "default-hasher", + "inline-more", + "allocator-api2", + "equivalent", + "raw-entry" + ], + "default-hasher": ["dep:foldhash"] + }, + "yanked": false, + "rust_version": "1.65.0", + "pubtime": "2025-08-07T23:58:32Z", + "v": 2 + }, + { + "name": "hashbrown", + "vers": "0.16.1", + "deps": [ + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "allocator-api2", + "req": "^0.2.9", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "bumpalo", + "req": "^3.13.0", + "features": ["allocator-api2"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "equivalent", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "fnv", + "req": "^1.0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "foldhash", + "req": "^0.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "lazy_static", + "req": "^1.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9.0", + "features": ["small_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "^1.9.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(any())", + "kind": "normal" + }, + { + "name": "serde_core", + "req": "^1.0.221", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_test", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100", + "features": { + "inline-more": [], + "raw-entry": [], + "rustc-internal-api": [] + }, + "features2": { + "default": [ + "default-hasher", + "inline-more", + "allocator-api2", + "equivalent", + "raw-entry" + ], + "default-hasher": ["dep:foldhash"], + "nightly": ["foldhash?/nightly", "bumpalo/allocator_api"], + "rustc-dep-of-std": ["nightly", "core", "alloc", "rustc-internal-api"], + "serde": ["dep:serde_core", "dep:serde"] + }, + "yanked": false, + "rust_version": "1.65.0", + "pubtime": "2025-11-20T16:47:18Z", + "v": 2 + }, + { + "name": "hashbrown", + "vers": "0.17.1", + "deps": [ + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "allocator-api2", + "req": "^0.2.9", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "bumpalo", + "req": "^3.13.0", + "features": ["allocator-api2"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "criterion", + "req": "^0.7", + "features": ["html_reports"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "equivalent", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "fnv", + "req": "^1.0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "foldhash", + "req": "^0.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.155", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9.0", + "features": ["small_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "^1.9.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(any())", + "kind": "normal" + }, + { + "name": "serde_core", + "req": "^1.0.221", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_test", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a", + "features": { + "inline-more": [], + "raw-entry": [], + "rustc-internal-api": [] + }, + "features2": { + "default": [ + "default-hasher", + "inline-more", + "allocator-api2", + "equivalent", + "raw-entry" + ], + "default-hasher": ["dep:foldhash"], + "nightly": ["foldhash?/nightly", "bumpalo/allocator_api"], + "rustc-dep-of-std": ["nightly", "core", "alloc", "rustc-internal-api"], + "serde": ["dep:serde_core", "dep:serde"] + }, + "yanked": false, + "rust_version": "1.85.0", + "pubtime": "2026-05-09T04:35:04Z", + "v": 2 + } + ] + }, + { + "path": "ha/sh/hashlink", + "header": "AwIAAABldGFnOiAiNzIxOWU5MGRjNzMyMzVjYmZhNmI5ZWExMjE2MGI2YjkiAA==", + "records": [ + { + "name": "hashlink", + "vers": "0.10.0", + "deps": [ + { + "name": "hashbrown", + "req": "^0.15", + "features": ["default-hasher", "inline-more"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rustc-hash", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_test", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1", + "features": { + "serde_impl": ["serde"] + }, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2024-12-09T11:48:51Z" + } + ] + }, + { + "path": "he/ap/heapless", + "header": "AwIAAABldGFnOiAiNjgwMGFlOGU3YTA2MjBmZTNmZTIyMjRlYzhmODI2MzYiAA==", + "records": [ + { + "name": "heapless", + "vers": "0.9.3", + "deps": [ + { + "name": "bytes", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "critical-section", + "req": "^1.1", + "features": ["std"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "defmt", + "req": "^1.0.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "embedded-io", + "req": "^0.7", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hash32", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "portable-atomic", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_core", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "stable_deref_trait", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_arch = \"arm\", target_pointer_width = \"32\", target_pointer_width = \"64\"))", + "kind": "normal" + }, + { + "name": "static_assertions", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ufmt", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ufmt-write", + "req": "^0.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "zeroize", + "req": "^1.8", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "25ba4bd83f9415b58b4ed8dc5714c76e626a105be4646c02630ad730ad3b5aa4", + "features": { + "alloc": [], + "mpmc_large": [], + "nightly": [] + }, + "features2": { + "bytes": ["dep:bytes"], + "defmt": ["dep:defmt"], + "embedded-io-v0.7": ["dep:embedded-io"], + "portable-atomic": ["dep:portable-atomic"], + "portable-atomic-critical-section": [ + "dep:portable-atomic", + "portable-atomic", + "portable-atomic?/critical-section" + ], + "portable-atomic-unsafe-assume-single-core": [ + "dep:portable-atomic", + "portable-atomic", + "portable-atomic?/unsafe-assume-single-core" + ], + "serde": ["dep:serde_core"], + "ufmt": ["dep:ufmt", "dep:ufmt-write"], + "zeroize": ["dep:zeroize"] + }, + "yanked": false, + "rust_version": "1.87", + "pubtime": "2026-04-30T21:21:52Z", + "v": 2 + } + ] + }, + { + "path": "he/ck/heck", + "header": "AwIAAABldGFnOiAiN2UwZWRjOGEzMGNjNzYwMDhhZmM0NzkwZTQwMDE1ODkiAA==", + "records": [ + { + "name": "heck", + "vers": "0.3.3", + "deps": [ + { + "name": "unicode-segmentation", + "req": "^1.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c", + "features": {}, + "yanked": false, + "pubtime": "2021-06-02T20:40:39Z" + }, + { + "name": "heck", + "vers": "0.5.0", + "deps": [], + "cksum": "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-03-12T22:42:23Z" + } + ] + }, + { + "path": "he/rm/hermit-abi", + "header": "AwIAAABldGFnOiAiOTQ5Y2E5MWU3OTg0NTU4NmNkZDI1ZTQ3ZTdiOGMwMDUiAA==", + "records": [ + { + "name": "hermit-abi", + "vers": "0.5.3", + "deps": [ + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + } + ], + "cksum": "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284", + "features": { + "default": [], + "rustc-dep-of-std": ["core", "alloc"] + }, + "yanked": false, + "pubtime": "2026-08-31T11:45:18Z" + } + ] + }, + { + "path": "hk/df/hkdf", + "header": "AwIAAABldGFnOiAiYjRmY2Q2YTJhNmNmMWFkMjE4ZTRiOTQ5NWRiMDcxZDQiAA==", + "records": [ + { + "name": "hkdf", + "vers": "0.12.4", + "deps": [ + { + "name": "blobby", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hex-literal", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hmac", + "req": "^0.12.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sha1", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + } + ], + "cksum": "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7", + "features": { + "std": ["hmac/std"] + }, + "yanked": false, + "pubtime": "2023-12-13T13:35:31Z" + } + ] + }, + { + "path": "hm/ac/hmac", + "header": "AwIAAABldGFnOiAiYWIyZTAxZDljMmQ0ODUzN2NlOTEyOWQ5ODNlYTNjNDkiAA==", + "records": [ + { + "name": "hmac", + "vers": "0.12.1", + "deps": [ + { + "name": "digest", + "req": "^0.10.3", + "features": ["mac"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "digest", + "req": "^0.10", + "features": ["dev"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hex-literal", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "md-5", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "sha-1", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "streebog", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + } + ], + "cksum": "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e", + "features": { + "reset": [], + "std": ["digest/std"] + }, + "yanked": false, + "pubtime": "2022-02-17T10:50:37Z" + }, + { + "name": "hmac", + "vers": "0.13.0", + "deps": [ + { + "name": "digest", + "req": "^0.11.2", + "features": ["mac"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "digest", + "req": "^0.11.2", + "features": ["dev"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hex-literal", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "md-5", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "sha1", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "sha2", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "streebog", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + } + ], + "cksum": "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f", + "features": { + "zeroize": ["digest/zeroize"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-03-29T23:19:21Z" + } + ] + }, + { + "path": "ho/me/home", + "header": "AwIAAABldGFnOiAiYjEzMjY4YWQ2MzQyODdiZjczYTM2ZDVlZjgyOWNiODEiAA==", + "records": [ + { + "name": "home", + "vers": "0.5.12", + "deps": [ + { + "name": "windows-sys", + "req": "^0.61", + "features": ["Win32_Foundation", "Win32_UI_Shell", "Win32_System_Com"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d", + "features": {}, + "yanked": false, + "rust_version": "1.88", + "pubtime": "2025-10-23T23:56:32Z" + } + ] + }, + { + "path": "ht/tp/http", + "header": "AwIAAABldGFnOiAiNTgzYThmZDdhOTMxZDBlMGM2Yjg5ZWNhZGFmYWFiMmEiAA==", + "records": [ + { + "name": "http", + "vers": "1.5.0", + "deps": [ + { + "name": "bytes", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "doc-comment", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "itoa", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.57.0", + "pubtime": "2026-07-29T14:57:21Z" + } + ] + }, + { + "path": "hy/br/hybrid-array", + "header": "AwIAAABldGFnOiAiNjAyM2NiMzU1MTE2MTc4YWEyMGE0NGM3MTAwYmNhZTYiAA==", + "records": [ + { + "name": "hybrid-array", + "vers": "0.4.15", + "deps": [ + { + "name": "arbitrary", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytemuck", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "ctutils", + "req": "^0.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "subtle", + "req": "^2", + "features": ["const-generics"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "typenum", + "req": "^1.20", + "features": ["const-generics"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "zerocopy", + "req": "^0.8", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "zeroize", + "req": "^1.8", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17", + "features": { + "alloc": [], + "extra-sizes": [] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-09-08T18:21:39Z" + } + ] + }, + { + "path": "ic/u_/icu_collections", + "header": "AwIAAABldGFnOiAiYmRkNjRjMDZlMThiOTlmOGE5MjcwNmM2YTBjNDBjYzIiAA==", + "records": [ + { + "name": "icu_collections", + "vers": "2.3.0", + "deps": [ + { + "name": "criterion", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "databake", + "req": "^0.2.0", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "displaydoc", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "iai", + "req": "^0.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "postcard", + "req": "^1.0.3", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "potential_utf", + "req": "^0.1.3", + "features": ["zerovec"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0.45", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml", + "req": "^0.8.0", + "features": ["parse"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "utf8_iter", + "req": "^1.0.2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "yoke", + "req": "^0.8.3", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerofrom", + "req": "^0.1.6", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerovec", + "req": "^0.11.7", + "features": ["derive", "yoke"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513", + "features": {}, + "features2": { + "alloc": ["serde?/alloc", "zerovec/alloc"], + "databake": ["dep:databake", "zerovec/databake"], + "serde": ["dep:serde", "zerovec/serde", "potential_utf/serde", "alloc"] + }, + "yanked": false, + "rust_version": "1.88", + "pubtime": "2026-08-13T23:28:40Z", + "v": 2 + } + ] + }, + { + "path": "ic/u_/icu_locale_core", + "header": "AwIAAABldGFnOiAiYjcwYjA4MTE5OGRkZjhlOWE2YTBhNTY4ODBhMWExOTciAA==", + "records": [ + { + "name": "icu_locale_core", + "vers": "2.3.0", + "deps": [ + { + "name": "criterion", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "databake", + "req": "^0.2.0", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "displaydoc", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "iai", + "req": "^0.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "litemap", + "req": "^0.8.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "litemap", + "req": "^0.8.0", + "features": ["testing"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "postcard", + "req": "^1.0.3", + "features": ["use-std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "potential_utf", + "req": "^0.1.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0.45", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tinystr", + "req": "^0.8.4", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "writeable", + "req": "^0.6.4", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerovec", + "req": "^0.11.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb", + "features": {}, + "features2": { + "alloc": ["litemap/alloc", "tinystr/alloc", "writeable/alloc", "serde?/alloc"], + "databake": ["dep:databake", "alloc"], + "serde": ["dep:serde", "tinystr/serde"], + "zerovec": ["dep:zerovec", "tinystr/zerovec"] + }, + "yanked": false, + "rust_version": "1.88", + "pubtime": "2026-08-13T23:28:12Z", + "v": 2 + } + ] + }, + { + "path": "ic/u_/icu_normalizer", + "header": "AwIAAABldGFnOiAiNWQzOTM1MjZlNDEwMDEzYTczNGNlMWE5MTRiZWRlYzYiAA==", + "records": [ + { + "name": "icu_normalizer", + "vers": "2.3.0", + "deps": [ + { + "name": "atoi", + "req": "^2.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "databake", + "req": "^0.2.0", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "detone", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "harfbuzz-traits", + "req": "^0.6.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "icu_collections", + "req": "~2.3.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "icu_normalizer_data", + "req": "~2.3.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "icu_properties", + "req": "~2.3.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "icu_provider", + "req": "^2.3.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": ["derive", "alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "smallvec", + "req": "^1.10.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "utf16_iter", + "req": "^1.0.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "utf8_iter", + "req": "^1.0.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "write16", + "req": "^1.0.0", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "write16", + "req": "^1.0.0", + "features": ["arrayvec", "smallvec"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "zerovec", + "req": "^0.11.7", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f", + "features": { + "write16": [] + }, + "features2": { + "compiled_data": [ + "dep:icu_normalizer_data", + "icu_properties?/compiled_data", + "icu_provider/baked" + ], + "datagen": [ + "serde", + "dep:databake", + "icu_properties", + "icu_collections/databake", + "zerovec/databake", + "icu_properties?/datagen", + "icu_provider/export" + ], + "default": ["compiled_data", "utf8_iter", "utf16_iter"], + "harfbuzz_traits": ["dep:harfbuzz-traits"], + "icu_properties": ["dep:icu_properties"], + "serde": [ + "dep:serde", + "icu_collections/serde", + "zerovec/serde", + "icu_properties?/serde", + "icu_provider/serde" + ], + "utf16_iter": ["dep:utf16_iter", "dep:write16"], + "utf8_iter": ["dep:utf8_iter"] + }, + "yanked": false, + "rust_version": "1.88", + "pubtime": "2026-08-13T23:28:56Z", + "v": 2 + } + ] + }, + { + "path": "ic/u_/icu_normalizer_data", + "header": "AwIAAABldGFnOiAiMDA2MjAyZDIzNDM5MDMyOGE2ZTA0YmE1N2JmZDVhZDQiAA==", + "records": [ + { + "name": "icu_normalizer_data", + "vers": "2.3.0", + "deps": [], + "cksum": "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0", + "features": {}, + "yanked": false, + "rust_version": "1.88", + "pubtime": "2026-08-13T23:28:53Z" + } + ] + }, + { + "path": "ic/u_/icu_properties", + "header": "AwIAAABldGFnOiAiOTRkMWNiYWQ1ZjcwOGI1MWI0YzNmYTZlYmI4MGQ0ZDMiAA==", + "records": [ + { + "name": "icu_properties", + "vers": "2.3.0", + "deps": [ + { + "name": "databake", + "req": "^0.2.0", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "displaydoc", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "harfbuzz-traits", + "req": "^0.6.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "icu_collections", + "req": "~2.3.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "icu_locale_core", + "req": "^2.3.0", + "features": ["zerovec"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "icu_properties_data", + "req": "~2.3.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "icu_provider", + "req": "^2.3.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "log", + "req": "^0.4.17", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "unicode-bidi", + "req": "^0.3.11", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerotrie", + "req": "^0.2.5", + "features": ["yoke", "zerofrom"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerovec", + "req": "^0.11.7", + "features": ["derive", "yoke"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148", + "features": { + "unstable": [] + }, + "features2": { + "alloc": ["zerovec/alloc", "icu_collections/alloc", "serde?/alloc"], + "compiled_data": ["dep:icu_properties_data", "icu_provider/baked"], + "datagen": [ + "serde", + "dep:databake", + "zerovec/databake", + "icu_collections/databake", + "icu_locale_core/databake", + "zerotrie/databake", + "icu_provider/export" + ], + "default": ["compiled_data"], + "harfbuzz_traits": ["dep:harfbuzz-traits"], + "log": ["dep:log"], + "serde": [ + "dep:serde", + "icu_locale_core/serde", + "zerovec/serde", + "icu_collections/serde", + "icu_provider/serde", + "zerotrie/serde" + ], + "unicode_bidi": ["dep:unicode-bidi"] + }, + "yanked": false, + "rust_version": "1.88", + "pubtime": "2026-08-13T23:28:46Z", + "v": 2 + } + ] + }, + { + "path": "ic/u_/icu_properties_data", + "header": "AwIAAABldGFnOiAiODBmYzMzYmQ1OTQwNmI1MjIzZWU3Y2E5MTQ4MDM0ZDEiAA==", + "records": [ + { + "name": "icu_properties_data", + "vers": "2.3.0", + "deps": [], + "cksum": "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa", + "features": {}, + "yanked": false, + "rust_version": "1.88", + "pubtime": "2026-08-13T23:28:42Z" + } + ] + }, + { + "path": "ic/u_/icu_provider", + "header": "AwIAAABldGFnOiAiNzNmYzhjOGQ4MTdlZDg4YzJlMDIyZTI3MGQ5NzY2MGYiAA==", + "records": [ + { + "name": "icu_provider", + "vers": "2.3.1", + "deps": [ + { + "name": "bincode", + "req": "^1.3.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "criterion", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "databake", + "req": "^0.2.0", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "displaydoc", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "erased-serde", + "req": "^0.4.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "icu_locale_core", + "req": "^2.3.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "log", + "req": "^0.4.17", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "postcard", + "req": "^1.0.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.45", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.45", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "stable_deref_trait", + "req": "^1.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "writeable", + "req": "^0.6.4", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "yoke", + "req": "^0.8.3", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerofrom", + "req": "^0.1.6", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerotrie", + "req": "^0.2.5", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerovec", + "req": "^0.11.8", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73", + "features": { + "sync": [], + "zerotrie": [] + }, + "features2": { + "alloc": [ + "icu_locale_core/alloc", + "serde?/alloc", + "yoke/alloc", + "zerofrom/alloc", + "zerovec/alloc", + "zerotrie?/alloc", + "dep:stable_deref_trait", + "dep:writeable" + ], + "baked": ["dep:zerotrie", "dep:writeable"], + "deserialize_bincode_1": ["serde", "dep:bincode", "std"], + "deserialize_json": ["serde", "dep:serde_json"], + "deserialize_postcard_1": ["serde", "dep:postcard"], + "export": [ + "serde", + "dep:erased-serde", + "dep:databake", + "std", + "sync", + "dep:postcard", + "zerovec/databake" + ], + "logging": ["dep:log"], + "serde": ["dep:serde", "yoke/serde"], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.88", + "pubtime": "2026-08-20T23:25:32Z", + "v": 2 + } + ] + }, + { + "path": "id/-a/id-arena", + "header": "AwIAAABldGFnOiAiMzlkZGQxYmZhMzNiMDI0ODljNDQ1NjFhMTgzMmI0NTIiAA==", + "records": [ + { + "name": "id-arena", + "vers": "2.3.0", + "deps": [ + { + "name": "rayon", + "req": "^1.0.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "pubtime": "2026-01-14T21:40:46Z" + } + ] + }, + { + "path": "id/en/ident_case", + "header": "AwIAAABldGFnOiAiNDQyYTkyZTMzNzExNDAwMmRmNGNjYTdiYmUwY2Y3YTUiAA==", + "records": [ + { + "name": "ident_case", + "vers": "1.0.1", + "deps": [], + "cksum": "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39", + "features": {}, + "yanked": false, + "pubtime": "2019-03-18T20:07:20Z" + } + ] + }, + { + "path": "id/na/idna", + "header": "AwIAAABldGFnOiAiNDhmY2Q5MzEwYjFmYmY4M2UyMDEwZWJmMWVmMjhmODAiAA==", + "records": [ + { + "name": "idna", + "vers": "1.1.0", + "deps": [ + { + "name": "assert_matches", + "req": "^1.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "bencher", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "idna_adapter", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "smallvec", + "req": "^1.13.1", + "features": ["const_generics"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tester", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "utf8_iter", + "req": "^1.0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de", + "features": { + "alloc": [], + "compiled_data": ["idna_adapter/compiled_data"], + "default": ["std", "compiled_data"], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.57", + "pubtime": "2025-08-21T08:48:20Z" + } + ] + }, + { + "path": "id/na/idna_adapter", + "header": "AwIAAABldGFnOiAiOTk4OGRiMjVjNGQ0ODBmMmM0ZDU2MWQ4NTJkYjhiY2UiAA==", + "records": [ + { + "name": "idna_adapter", + "vers": "1.2.2", + "deps": [ + { + "name": "icu_normalizer", + "req": "^2.2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "icu_properties", + "req": "^2.2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714", + "features": { + "compiled_data": ["icu_normalizer/compiled_data", "icu_properties/compiled_data"] + }, + "yanked": false, + "rust_version": "1.86", + "pubtime": "2026-04-27T17:45:54Z" + } + ] + }, + { + "path": "ig/no/ignore", + "header": "AwIAAABldGFnOiAiYzZkYzVlNjVmMjY1OWYyZWIxOGMzOTM5YjI4OGEzZDgiAA==", + "records": [ + { + "name": "ignore", + "vers": "0.4.33", + "deps": [ + { + "name": "bstr", + "req": "^1.6.2", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "crossbeam-channel", + "req": "^0.5.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "crossbeam-deque", + "req": "^0.8.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "globset", + "req": "^0.4.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "log", + "req": "^0.4.20", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memchr", + "req": "^2.6.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "regex-automata", + "req": "^0.4.18", + "features": ["std", "perf", "syntax", "meta", "nfa", "hybrid", "dfa-onepass"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "same-file", + "req": "^1.0.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "walkdir", + "req": "^2.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "winapi-util", + "req": "^0.1.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "00b69833ed729dc5aa7d19541d96d6cf8e9137194207a04916d658e43168402f", + "features": { + "simd-accel": [] + }, + "yanked": false, + "rust_version": "1.88", + "pubtime": "2026-08-04T13:59:40Z" + } + ] + }, + { + "path": "in/de/indexmap", + "header": "AwIAAABldGFnOiAiYjA1YTBkYjBhYTUzMTAzY2NhMDI0ZWFiZGI4NDExOTAiAA==", + "records": [ + { + "name": "indexmap", + "vers": "2.14.2", + "deps": [ + { + "name": "arbitrary", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "borsh", + "req": "^1.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "equivalent", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "fastrand", + "req": "^2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "fnv", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hashbrown", + "req": "^0.17", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "itertools", + "req": "^0.14", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quickcheck", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "^1.9", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(any())", + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "sval", + "req": "^2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855", + "features": { + "default": ["std"], + "std": [], + "test_debug": [] + }, + "features2": { + "serde": ["dep:serde_core", "dep:serde"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-09-05T01:53:48Z", + "v": 2 + } + ] + }, + { + "path": "in/st/insta", + "header": "AwIAAABldGFnOiAiZTlmZmRlMjkyN2UzOGUxZmZhNzJhZTNjYTk0NzU4OWMiAA==", + "records": [ + { + "name": "insta", + "vers": "1.49.0", + "deps": [ + { + "name": "clap", + "req": "^4.1", + "features": ["derive", "env"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "console", + "req": "^0.16", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "csv", + "req": "^1.1.6", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "globset", + "req": "^0.4.6", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "once_cell", + "req": "^1.20.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pest", + "req": "^2.1.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pest_derive", + "req": "^2.1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "regex", + "req": "^1.6.0", + "features": ["std", "unicode"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "ron", + "req": "^0.12.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustc_version", + "req": "^0.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.117", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.117", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "similar", + "req": "^2.1.0", + "features": ["inline"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "similar-asserts", + "req": "^1.4.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "strip-ansi-escapes", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "toml_edit", + "req": "^0.25.0", + "features": ["serde", "parse", "display"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "toml_writer", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "walkdir", + "req": "^2.3.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "b67d3d2e287e4b86c10b3f3b641033d1f89b74bdb39d05f34952e2b9a6fe21cd", + "features": { + "_cargo_insta_internal": ["clap"], + "colors": ["console"], + "default": ["colors"], + "filters": ["regex", "strip-ansi-escapes"], + "glob": ["walkdir", "globset"], + "json": ["serde"], + "redactions": ["pest", "pest_derive", "serde"], + "yaml": ["serde"] + }, + "features2": { + "csv": ["dep:csv", "serde"], + "ron": ["dep:ron", "serde"], + "toml": ["dep:toml_edit", "dep:toml_writer", "serde"] + }, + "yanked": false, + "rust_version": "1.66.0", + "pubtime": "2026-10-03T01:12:59Z", + "v": 2 + } + ] + }, + { + "path": "io/-e/io-extras", + "header": "AwIAAABldGFnOiAiNDgyNzk0MTEwNThjOTY3ZjM2YTE5ZTBmNmNjNzU3NDQiAA==", + "records": [ + { + "name": "io-extras", + "vers": "0.19.0", + "deps": [ + { + "name": "async-std", + "req": "^1.13.0", + "features": ["io_safety"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "io-lifetimes", + "req": "^3.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "mio", + "req": "^1.0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "os_pipe", + "req": "^1.2.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "os_pipe", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "socket2", + "req": "^0.6.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.6.0", + "features": ["io-std", "fs", "net", "process"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.52, <=0.60", + "features": ["Win32_Foundation", "Win32_Networking_WinSock", "Win32_System_Console"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "20fd6de4ccfcc187e38bc21cfa543cb5a302cb86a8b114eb7f0bf0dc9f8ac00f", + "features": { + "default": [], + "use_async_std": ["async-std"], + "use_mio_net": ["mio", "mio/net"], + "use_mio_os_ext": ["mio", "mio/os-ext"], + "use_os_pipe": ["os_pipe"], + "use_socket2": ["socket2"], + "use_tokio": ["tokio"] + }, + "yanked": false, + "rust_version": "1.70", + "pubtime": "2025-08-06T19:24:42Z" + } + ] + }, + { + "path": "io/-l/io-lifetimes", + "header": "AwIAAABldGFnOiAiMDA2NjFjYTIxMTUxY2ZlZjA1ZDBiMWE0MGE5Y2YzYTEiAA==", + "records": [ + { + "name": "io-lifetimes", + "vers": "2.0.4", + "deps": [ + { + "name": "async-std", + "req": "^1.13.0", + "features": ["io_safety"], + "optional": true, + "default_features": true, + "target": "cfg(not(target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "hermit-abi", + "req": ">=0.3, <=0.4", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(target_os = \"hermit\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.96", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(windows))", + "kind": "normal" + }, + { + "name": "mio", + "req": "^0.8.0", + "features": ["net", "os-ext"], + "optional": true, + "default_features": true, + "target": "cfg(not(target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "os_pipe", + "req": "^1.0.0", + "features": ["io_safety"], + "optional": true, + "default_features": true, + "target": "cfg(not(target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "socket2", + "req": "^0.5.0", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.6.0", + "features": ["io-std", "fs", "net", "process"], + "optional": true, + "default_features": true, + "target": "cfg(not(target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.52, <=0.59", + "features": [ + "Win32_Foundation", + "Win32_Storage_FileSystem", + "Win32_Networking_WinSock", + "Win32_Security", + "Win32_System_IO" + ], + "optional": true, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "06432fb54d3be7964ecd3649233cddf80db2832f47fec34c01f65b3d9d774983", + "features": { + "close": ["libc", "hermit-abi", "windows-sys"], + "default": [] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2024-12-04T01:31:02Z" + }, + { + "name": "io-lifetimes", + "vers": "3.0.1", + "deps": [ + { + "name": "async-std", + "req": "^1.13.0", + "features": ["io_safety"], + "optional": true, + "default_features": true, + "target": "cfg(not(target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "hermit-abi", + "req": ">=0.3, <=0.5", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(target_os = \"hermit\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.96", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(windows))", + "kind": "normal" + }, + { + "name": "mio", + "req": "^1.0.0", + "features": ["net", "os-ext"], + "optional": true, + "default_features": true, + "target": "cfg(not(target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "os_pipe", + "req": "^1.0.0", + "features": ["io_safety"], + "optional": true, + "default_features": true, + "target": "cfg(not(target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "socket2", + "req": "^0.6.0", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.6.0", + "features": ["io-std", "fs", "net", "process"], + "optional": true, + "default_features": true, + "target": "cfg(not(target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.52, <=0.60", + "features": [ + "Win32_Foundation", + "Win32_Storage_FileSystem", + "Win32_Networking_WinSock", + "Win32_Security", + "Win32_System_IO" + ], + "optional": true, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "2f0fb0570afe1fed943c5c3d4102d5358592d8625fda6a0007fdbe65a92fba96", + "features": { + "close": ["libc", "hermit-abi", "windows-sys"], + "default": [] + }, + "yanked": false, + "rust_version": "1.70", + "pubtime": "2025-08-06T19:20:58Z" + } + ] + }, + { + "path": "ip/ne/ipnet", + "header": "AwIAAABldGFnOiAiNWNhYWMwZWY1ZmE4NGY4NTZjYTllMDVmZWQ3YjVhYzAiAA==", + "records": [ + { + "name": "ipnet", + "vers": "2.12.2", + "deps": [ + { + "name": "heapless", + "req": "^0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "schemars08", + "req": "^0.8", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "schemars" + }, + { + "name": "schemars1", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "schemars" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "serde" + }, + { + "name": "serde_test", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "791930b43c0d5973160d90a8f3894509f2b273430f5c5c73b668636d0287c5c0", + "features": { + "default": ["std"], + "std": [] + }, + "features2": { + "heapless": ["dep:heapless", "serde"], + "json": ["schemars08", "serde"], + "schemars": ["schemars08"], + "schemars08": ["dep:schemars08"], + "schemars1": ["dep:schemars1"], + "ser_as_str": ["dep:heapless"], + "serde": ["dep:serde"] + }, + "yanked": false, + "pubtime": "2026-09-06T05:45:08Z", + "v": 2 + } + ] + }, + { + "path": "ip/ra/iprange", + "header": "AwIAAABldGFnOiAiODA1ODc5NmUwMTE5NmNmMzlkOWM1NGI5NzBkYWZiMjkiAA==", + "records": [ + { + "name": "iprange", + "vers": "0.6.7", + "deps": [ + { + "name": "bincode", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ipnet", + "req": "^2.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.3.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "37209be0ad225457e63814401415e748e2453a5297f9b637338f5fb8afa4ec00", + "features": {}, + "yanked": false, + "pubtime": "2022-01-17T11:54:07Z" + } + ] + }, + { + "path": "is/_t/is_terminal_polyfill", + "header": "AwIAAABldGFnOiAiMjA4NGZkNjBkMWI4YzQ4NmZkZjA3OWU2MTc1ODA2MjIiAA==", + "records": [ + { + "name": "is_terminal_polyfill", + "vers": "1.70.2", + "deps": [], + "cksum": "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695", + "features": { + "default": [] + }, + "yanked": false, + "rust_version": "1.70.0", + "pubtime": "2025-10-21T17:00:14Z" + } + ] + }, + { + "path": "it/er/itertools", + "header": "AwIAAABldGFnOiAiZmQ5N2JkOTE2Y2VlYTczYTM0OWJiOTUwM2ZkODI5OGEiAA==", + "records": [ + { + "name": "itertools", + "vers": "0.13.0", + "deps": [ + { + "name": "criterion", + "req": "^0.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "either", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "paste", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "permutohedron", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quickcheck", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186", + "features": { + "default": ["use_std"], + "use_alloc": [], + "use_std": ["use_alloc", "either/use_std"] + }, + "yanked": false, + "rust_version": "1.43.1", + "pubtime": "2024-05-16T15:37:32Z" + }, + { + "name": "itertools", + "vers": "0.15.0", + "deps": [ + { + "name": "criterion", + "req": "^0.4.0", + "features": ["html_reports"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "either", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "paste", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "permutohedron", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quickcheck", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "8b4baf93f58d4425749ca49a51c50ebab072c5df6994d08fed93541c331481dc", + "features": { + "default": ["use_std"], + "use_alloc": [], + "use_std": ["use_alloc", "either/use_std"] + }, + "yanked": false, + "rust_version": "1.63.0", + "pubtime": "2026-06-16T15:09:28Z" + } + ] + }, + { + "path": "it/oa/itoa", + "header": "AwIAAABldGFnOiAiZWE4NDk0ZDU2MGYxYjgxNzQ0NDM0OTViMzcwZTI3MmYiAA==", + "records": [ + { + "name": "itoa", + "vers": "1.0.18", + "deps": [ + { + "name": "criterion", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "no-panic", + "req": "^0.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682", + "features": {}, + "yanked": false, + "rust_version": "1.68", + "pubtime": "2026-03-20T00:12:37Z" + } + ] + }, + { + "path": "jo/bs/jobserver", + "header": "AwIAAABldGFnOiAiMDEwMTQ0MWVhMzM2M2Q1NTUxNWI1MWEyYTM4ZjcwMGQiAA==", + "records": [ + { + "name": "jobserver", + "vers": "0.1.35", + "deps": [ + { + "name": "getrandom", + "req": "^0.4", + "features": ["std"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.171", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "nix", + "req": "^0.31.3", + "features": ["fs"], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "dev" + }, + { + "name": "tempfile", + "req": "^3.10.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3", + "features": {}, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-07-06T01:43:15Z" + } + ] + }, + { + "path": "js/-s/js-sys", + "header": "AwIAAABldGFnOiAiOTM1MzY2ZDFjNDlmNmI1ZjI0NmEwZmNhMDg0YWFhMzAiAA==", + "records": [ + { + "name": "js-sys", + "vers": "0.3.106", + "deps": [ + { + "name": "cfg-if", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures-channel", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "futures-core", + "req": "^0.3.8", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-lite", + "req": "^2", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "futures-util", + "req": "^0.3.31", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "half", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "wasm-bindgen", + "req": "=0.2.129", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "7883d941dae510fb2d978fc3fe018c71c9e2892fd38854de3e8b92c2e5ad9cc5", + "features": { + "default": ["std", "unsafe-eval"], + "std": ["wasm-bindgen/std", "futures-util/std"], + "unsafe-eval": [] + }, + "features2": { + "futures-core-03-stream": ["dep:futures-util", "dep:futures-core"] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-09-25T07:13:42Z", + "v": 2 + } + ] + }, + { + "path": "le/b1/leb128", + "header": "AwIAAABldGFnOiAiYWZkNTFkZDI4OTE5NTUzMTMzODVkY2RiMDY0YzE5NWYiAA==", + "records": [ + { + "name": "leb128", + "vers": "0.2.7", + "deps": [ + { + "name": "quickcheck", + "req": "^1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "c83bff1d572d6b9aeef67ddfc8448e4a3737909cb28e81f97c791b9018703e52", + "features": { + "nightly": [] + }, + "yanked": false, + "pubtime": "2026-06-15T18:58:07Z" + } + ] + }, + { + "path": "le/b1/leb128fmt", + "header": "AwIAAABldGFnOiAiMDVmMDgxMWFiNWI2ZTQyOTA3MGZlY2M4MWUyZmQzYWUiAA==", + "records": [ + { + "name": "leb128fmt", + "vers": "0.1.0", + "deps": [], + "cksum": "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2", + "features": { + "alloc": [], + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.56.0", + "pubtime": "2023-10-02T21:31:24Z" + } + ] + }, + { + "path": "le/xi/lexical-sort", + "header": "AwIAAABldGFnOiAiZmU5YTk5MDQ1NzE5MmI5ZjE5MTRjZjNlM2JkZGZjNzQiAA==", + "records": [ + { + "name": "lexical-sort", + "vers": "0.3.1", + "deps": [ + { + "name": "alphanumeric-sort", + "req": "^1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "any_ascii", + "req": "^0.1.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "criterion", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rust_icu_ucol", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rust_icu_ustring", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "c09e4591611e231daf4d4c685a66cb0410cc1e502027a20ae55f2bb9e997207a", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "pubtime": "2020-08-29T23:40:26Z" + } + ] + }, + { + "path": "li/bc/libc", + "header": "AwIAAABldGFnOiAiOGEwODRkZTJkZmRmMDE4Njg2Y2NlYThjZDAzNzlmNjAiAA==", + "records": [ + { + "name": "libc", + "vers": "0.2.190", + "deps": [ + { + "name": "rustc-std-workspace-core", + "req": "^1.0.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78", + "features": { + "align": [], + "const-extern-fn": [], + "default": ["std"], + "extra_traits": [], + "rustc-dep-of-std": ["align", "rustc-std-workspace-core"], + "std": [], + "use_std": ["std"] + }, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-10-02T19:33:19Z" + } + ] + }, + { + "path": "li/bl/libloading", + "header": "AwIAAABldGFnOiAiZTMxNzYwZjkxZjUwMmQ3NmJkNGFjMWJhMjY3MGIxOGEiAA==", + "records": [ + { + "name": "libloading", + "vers": "0.8.9", + "deps": [ + { + "name": "cfg-if", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "windows-link", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": "^0.61", + "features": ["Win32_Foundation"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "dev" + } + ], + "cksum": "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55", + "features": {}, + "yanked": false, + "rust_version": "1.71.0", + "pubtime": "2025-09-21T10:59:30Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-wasix-aot-aarch64-apple-darwin", + "header": "AwIAAABldGFnOiAiMThjZTE2ODUzMmVmY2RmYjI1MzAwZGRjMzliMTM0ZTkiAA==", + "records": [ + { + "name": "liboliphaunt-wasix-aot-aarch64-apple-darwin", + "vers": "0.3.2", + "deps": [ + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "835ede81ff81dcfb2767878209a1c372b7e3338c401595cf179aa68e1f1cc0c7", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_liboliphaunt_wasix_aot_macos_arm64", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:47Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu", + "header": "AwIAAABldGFnOiAiYWUzMWUwN2FmMDI2OWM2ZTkzY2JlNjIxY2U5NjQyNmMiAA==", + "records": [ + { + "name": "liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu", + "vers": "0.3.2", + "deps": [ + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "14b15cb79e689f5f0eab69f5acd92f68f61ae57d9f3bfa4cc18658a6d1bb67ad", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_liboliphaunt_wasix_aot_linux_arm64_gnu", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:48Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-wasix-aot-x86_64-pc-windows-msvc", + "header": "AwIAAABldGFnOiAiYTJjYmJlZWY4NzM4Y2U1ZmNmY2Q2MTFlMTcwY2JmOWIiAA==", + "records": [ + { + "name": "liboliphaunt-wasix-aot-x86_64-pc-windows-msvc", + "vers": "0.3.2", + "deps": [ + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "6c7a811a634a1b0d686369cbaefa8dabbfe5825fc4a03140ddda7beb3343bd30", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_liboliphaunt_wasix_aot_windows_x64_msvc", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:49Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu", + "header": "AwIAAABldGFnOiAiNDc1YjlkOGZjMmMwZjA4MTU4MDU5Y2VkZmYwYzFkZGUiAA==", + "records": [ + { + "name": "liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu", + "vers": "0.3.2", + "deps": [ + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "9e56a349c5c888ad65a623cbce954e13ae6dcead6ea846fc63202158f815976d", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_liboliphaunt_wasix_aot_linux_x64_gnu", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:49Z" + } + ] + }, + { + "path": "li/bo/liboliphaunt-wasix-portable", + "header": "AwIAAABldGFnOiAiZDI5Y2FjNGJiY2UxNTEyYjFiYjNmZjM3NTc1YjQxZDIiAA==", + "records": [ + { + "name": "liboliphaunt-wasix-portable", + "vers": "0.3.2", + "deps": [ + { + "name": "oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "req": "=0.3.2", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(all(target_os = \"linux\", target_arch = \"aarch64\", target_env = \"gnu\"))", + "kind": "normal" + }, + { + "name": "oliphaunt-extension-contrib-pg18-aot-linux-x64", + "req": "=0.3.2", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(all(target_os = \"linux\", target_arch = \"x86_64\", target_env = \"gnu\"))", + "kind": "normal" + }, + { + "name": "oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "req": "=0.3.2", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(all(target_os = \"macos\", target_arch = \"aarch64\"))", + "kind": "normal" + }, + { + "name": "oliphaunt-extension-contrib-pg18-aot-windows-x64", + "req": "=0.3.2", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(all(target_os = \"windows\", target_arch = \"x86_64\", target_env = \"msvc\"))", + "kind": "normal" + }, + { + "name": "oliphaunt-extension-contrib-pg18-wasix", + "req": "=0.3.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "78ebe15bd97751ed6c63ae25067c6a92a2266fa861d295d9d45844260acba30b", + "features": { + "extension-pg-hashids": [], + "extension-pg-ivm": [], + "extension-pg-textsearch": [], + "extension-pg-uuidv7": [], + "extension-pgtap": [], + "extension-postgis": [], + "extension-vector": [] + }, + "features2": { + "extension-amcheck": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-auto-explain": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-bloom": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-btree-gin": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-btree-gist": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-citext": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-cube": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-dict-int": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-dict-xsyn": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-earthdistance": [ + "extension-cube", + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-file-fdw": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-fuzzystrmatch": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-hstore": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-intarray": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-isn": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-lo": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-ltree": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-pageinspect": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-pg-buffercache": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-pg-freespacemap": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-pg-surgery": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-pg-trgm": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-pg-visibility": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-pg-walinspect": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-pgcrypto": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-seg": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-tablefunc": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-tcn": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-tsm-system-rows": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-tsm-system-time": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-unaccent": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ], + "extension-uuid-ossp": [ + "dep:oliphaunt-extension-contrib-pg18-wasix", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-linux-x64", + "dep:oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "dep:oliphaunt-extension-contrib-pg18-aot-windows-x64" + ] + }, + "yanked": false, + "links": "oliphaunt_artifact_liboliphaunt_wasix_runtime", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:42:14Z", + "v": 2 + } + ] + }, + { + "path": "li/br/libredox", + "header": "AwIAAABldGFnOiAiMTVlMzVlYmQ4ZTgxOTEwMDJhZTE3MjAwZTRmODg0ZDkiAA==", + "records": [ + { + "name": "libredox", + "vers": "0.1.25", + "deps": [ + { + "name": "bitflags", + "req": "^2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ioslice", + "req": "^0.6", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "plain", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "redox_syscall", + "req": "^0.9.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "61ff90caf6077a803a240f62fdbe88645a890bbca49ef8174c3cb0404362171d", + "features": { + "base": ["libc"], + "call": ["base"], + "default": ["base", "call", "std", "redox_syscall", "protocol", "numa"], + "mkns": ["ioslice"], + "numa": ["redox_syscall"], + "protocol": ["plain", "bitflags", "redox_syscall"], + "std": ["base"] + }, + "yanked": false, + "pubtime": "2026-09-21T13:30:01Z" + } + ] + }, + { + "path": "li/bt/libtest-mimic", + "header": "AwIAAABldGFnOiAiMjBlYzg2ODU1MTU3MThjMmUyZTJlODRmMWE2MjIwOTMiAA==", + "records": [ + { + "name": "libtest-mimic", + "vers": "0.8.2", + "deps": [ + { + "name": "anstream", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anstyle", + "req": "^1.0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "clap", + "req": "^4.0.8", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "escape8259", + "req": "^0.5.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "fastrand", + "req": "^2.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "pretty_assertions", + "req": "^1.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "14e6ba06f0ade6e504aff834d7c34298e5155c6baca353cc6a4aaff2f9fd7f33", + "features": {}, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-03-16T17:21:55Z" + } + ] + }, + { + "path": "li/bu/libunwind", + "header": "AwIAAABldGFnOiAiNmQ5N2NkMjRhZTBlOTFiNzI5NjA0YmE5MGRjMjEzYTgiAA==", + "records": [ + { + "name": "libunwind", + "vers": "1.3.3", + "deps": [], + "cksum": "0c6639b70a7ce854b79c70d7e83f16b5dc0137cc914f3d7d03803b513ecc67ac", + "features": {}, + "yanked": false, + "pubtime": "2023-10-13T13:45:37Z" + } + ] + }, + { + "path": "li/nk/linked_hash_set", + "header": "AwIAAABldGFnOiAiZTcyOTZkYzNkNTdkZTk4NDE2YWRjMGJiOTVlMjI5MDYiAA==", + "records": [ + { + "name": "linked_hash_set", + "vers": "0.1.6", + "deps": [ + { + "name": "linked-hash-map", + "req": "^0.5.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_core", + "req": "^1.0.228", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_test", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "984fb35d06508d1e69fc91050cceba9c0b748f983e6739fa2c7a9237154c52c8", + "features": {}, + "features2": { + "serde": ["dep:serde_core"] + }, + "yanked": false, + "pubtime": "2025-11-09T01:15:49Z", + "v": 2 + } + ] + }, + { + "path": "li/nk/linked-hash-map", + "header": "AwIAAABldGFnOiAiNzc5ZTFhYzM3MmJjN2Q5ZWExYjA4YzU5NDkxZjU3YjAiAA==", + "records": [ + { + "name": "linked-hash-map", + "vers": "0.5.6", + "deps": [ + { + "name": "heapsize", + "req": "^0.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_test", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f", + "features": { + "heapsize_impl": ["heapsize"], + "nightly": [], + "serde_impl": ["serde"] + }, + "yanked": false, + "pubtime": "2022-06-25T19:52:40Z" + } + ] + }, + { + "path": "li/nu/linux-raw-sys", + "header": "AwIAAABldGFnOiAiN2Q4N2ZlNTc2NGExYmU2YmQ0ZTc4NWJkOWQ0NTU2NzAiAA==", + "records": [ + { + "name": "linux-raw-sys", + "vers": "0.12.1", + "deps": [ + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "libc", + "req": "^0.2.100", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53", + "features": { + "auxvec": [], + "bootparam": [], + "btrfs": [], + "default": ["std", "general", "errno"], + "elf": [], + "elf_uapi": [], + "errno": [], + "general": [], + "if_arp": [], + "if_ether": [], + "if_packet": [], + "if_tun": [], + "image": [], + "io_uring": [], + "ioctl": [], + "landlock": [], + "loop_device": [], + "mempolicy": [], + "net": [], + "netlink": [], + "no_std": [], + "prctl": [], + "ptrace": [], + "rustc-dep-of-std": ["core", "no_std"], + "std": [], + "system": [], + "vm_sockets": [], + "xdp": [] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2025-12-23T00:00:07Z" + } + ] + }, + { + "path": "li/te/litemap", + "header": "AwIAAABldGFnOiAiZWE0MjhhMTc1MDM0NGNlNDlkOTk4ZmFmOGYzN2FkNzYiAA==", + "records": [ + { + "name": "litemap", + "vers": "0.8.3", + "deps": [ + { + "name": "bincode", + "req": "^1.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "databake", + "req": "^0.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "postcard", + "req": "^1.0.3", + "features": ["use-std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rkyv", + "req": "^0.7", + "features": ["validation"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.220", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_core", + "req": "^1.0.220", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0.45", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "yoke", + "req": "^0.8.3", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae", + "features": { + "alloc": [], + "default": ["alloc"], + "testing": ["alloc"] + }, + "features2": { + "databake": ["dep:databake"], + "serde": ["dep:serde_core", "alloc"], + "yoke": ["dep:yoke"] + }, + "yanked": false, + "rust_version": "1.82", + "pubtime": "2026-08-13T23:27:57Z", + "v": 2 + } + ] + }, + { + "path": "li/tr/litrs", + "header": "AwIAAABldGFnOiAiZTM3YTA1ZTczMzc5NDVlNzc3MzY3MjRhOGU4ZDE4NmYiAA==", + "records": [ + { + "name": "litrs", + "vers": "1.0.0", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.63", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "unicode-xid", + "req": "^0.2.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092", + "features": { + "check_suffix": ["unicode-xid"] + }, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2025-10-20T10:00:07Z" + } + ] + }, + { + "path": "lo/ck/lock_api", + "header": "AwIAAABldGFnOiAiZWM3OGI2MTNlNmNmZTkyMjJiOTQ2MzdlMTA2OTA1MWIiAA==", + "records": [ + { + "name": "lock_api", + "vers": "0.4.14", + "deps": [ + { + "name": "owning_ref", + "req": "^0.4.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "scopeguard", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.126", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965", + "features": { + "arc_lock": [], + "atomic_usize": [], + "default": ["atomic_usize"], + "nightly": [] + }, + "yanked": false, + "rust_version": "1.71.0", + "pubtime": "2025-10-03T23:33:12Z" + } + ] + }, + { + "path": "lz/4_/lz4_flex", + "header": "AwIAAABldGFnOiAiZWQ3NTY2MGQyYjUxNjJlMTE2NDhiYWQ2MjgxNWQyMmYiAA==", + "records": [ + { + "name": "lz4_flex", + "vers": "0.13.1", + "deps": [ + { + "name": "binggan", + "req": "^0.16.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "jemallocator", + "req": "^0.5.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "lz4-compress", + "req": "^0.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "lzzzz", + "req": "^2.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "more-asserts", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proptest", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0.91", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "snap", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "twox-hash", + "req": "^2.0.0", + "features": ["xxhash32"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "7ef0d4ed8669f8f8826eb00dc878084aa8f253506c4fd5e8f58f5bce72ddb97e", + "features": { + "checked-decode": [], + "nightly": [], + "safe-decode": [], + "safe-encode": [], + "std": [] + }, + "features2": { + "default": ["std", "safe-encode", "safe-decode", "frame", "checked-decode"], + "frame": ["std", "dep:twox-hash"] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-05-09T10:20:30Z", + "v": 2 + } + ] + }, + { + "path": "ma/ch/mach2", + "header": "AwIAAABldGFnOiAiNDBjZmRiZTk4MzYyZGY1Yjg0MTZiZDNjNWJlNDBkMWQiAA==", + "records": [ + { + "name": "mach2", + "vers": "0.4.3", + "deps": [ + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"macos\", target_os = \"ios\"))", + "kind": "normal" + } + ], + "cksum": "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44", + "features": { + "default": [], + "unstable": [] + }, + "yanked": false, + "pubtime": "2025-06-22T02:30:54Z" + }, + { + "name": "mach2", + "vers": "0.6.0", + "deps": [], + "cksum": "dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b", + "features": { + "default": [], + "unstable": [] + }, + "yanked": false, + "pubtime": "2025-11-16T01:16:34Z" + } + ] + }, + { + "path": "ma/ch/macho-unwind-info", + "header": "AwIAAABldGFnOiAiZDlhOGQxN2JlYmVkODYyNTE5N2Q2NDJkYTM2OGViM2IiAA==", + "records": [ + { + "name": "macho-unwind-info", + "vers": "0.5.0", + "deps": [ + { + "name": "object", + "req": "^0.36", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "thiserror", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "zerocopy", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "zerocopy-derive", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "bb4bdc8b0ce69932332cf76d24af69c3a155242af95c226b2ab6c2e371ed1149", + "features": {}, + "yanked": false, + "pubtime": "2024-12-06T19:40:57Z" + } + ] + }, + { + "path": "ma/na/managed", + "header": "AwIAAABldGFnOiAiYjM2OTZkYTQxMjIyODRmNmI3MTQzYjk1NDk0OGM2ZDIiAA==", + "records": [ + { + "name": "managed", + "vers": "0.8.0", + "deps": [], + "cksum": "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d", + "features": { + "alloc": [], + "default": ["std"], + "map": [], + "std": [] + }, + "yanked": false, + "pubtime": "2020-07-04T01:57:33Z" + } + ] + }, + { + "path": "ma/yb/maybe-owned", + "header": "AwIAAABldGFnOiAiNTU0MWVhZTk1Yzc1NWJmZGJjNGI0YzVjYjNiMmMyNzUiAA==", + "records": [ + { + "name": "maybe-owned", + "vers": "0.3.4", + "deps": [ + { + "name": "serde", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4", + "features": {}, + "yanked": false, + "pubtime": "2020-05-23T01:30:58Z" + } + ] + }, + { + "path": "md/-5/md-5", + "header": "AwIAAABldGFnOiAiY2EwMTEyNDllNzcwMWVkODM2OWFjNmRlNzVhMjk5YjYiAA==", + "records": [ + { + "name": "md-5", + "vers": "0.10.6", + "deps": [ + { + "name": "cfg-if", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "digest", + "req": "^0.10.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "digest", + "req": "^0.10.7", + "features": ["dev"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hex-literal", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "md5-asm", + "req": "^0.5", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))", + "kind": "normal" + } + ], + "cksum": "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf", + "features": { + "asm": ["md5-asm"], + "default": ["std"], + "force-soft": [], + "loongarch64_asm": [], + "oid": ["digest/oid"], + "std": ["digest/std"] + }, + "yanked": false, + "pubtime": "2023-09-22T14:19:04Z" + }, + { + "name": "md-5", + "vers": "0.11.0", + "deps": [ + { + "name": "cfg-if", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "digest", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "digest", + "req": "^0.11", + "features": ["dev"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hex-literal", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98", + "features": { + "alloc": ["digest/alloc"], + "default": ["alloc", "oid"], + "oid": ["digest/oid"], + "zeroize": ["digest/zeroize"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-03-27T14:59:39Z" + } + ] + }, + { + "path": "me/mc/memchr", + "header": "AwIAAABldGFnOiAiYjgwNzAzZTViODExMTA4NjlkOTQ1ZGM3ZDkxOWE5YzEiAA==", + "records": [ + { + "name": "memchr", + "vers": "2.8.3", + "deps": [ + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "log", + "req": "^0.4.20", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1.0.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + } + ], + "cksum": "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98", + "features": { + "alloc": [], + "default": ["std"], + "libc": [], + "rustc-dep-of-std": ["core"], + "std": ["alloc"], + "use_std": ["std"] + }, + "features2": { + "logging": ["dep:log"] + }, + "yanked": false, + "rust_version": "1.61", + "pubtime": "2026-07-08T00:49:54Z", + "v": 2 + } + ] + }, + { + "path": "me/mm/memmap2", + "header": "AwIAAABldGFnOiAiZjEyMWUwY2RlMjIyNmM5NzBiMjdhNzljOTAzYTJkNzQiAA==", + "records": [ + { + "name": "memmap2", + "vers": "0.6.2", + "deps": [ + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "owning_ref", + "req": "^0.4.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "stable_deref_trait", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "6d28bba84adfe6646737845bc5ebbfa2c08424eb1c37e94a1fd2a82adb56a872", + "features": {}, + "yanked": false, + "pubtime": "2023-05-24T13:56:15Z" + }, + { + "name": "memmap2", + "vers": "0.9.11", + "deps": [ + { + "name": "libc", + "req": "^0.2.151", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "owning_ref", + "req": "^0.4.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "stable_deref_trait", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0", + "features": {}, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-06-22T16:04:03Z" + } + ] + }, + { + "path": "me/mo/memoffset", + "header": "AwIAAABldGFnOiAiNjBmZmUyNjA1MWE4MDA0NDQ3MTk4MGI2YTczZmJiYWUiAA==", + "records": [ + { + "name": "memoffset", + "vers": "0.9.1", + "deps": [ + { + "name": "autocfg", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "doc-comment", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a", + "features": { + "default": [], + "unstable_const": [], + "unstable_offset_of": [] + }, + "yanked": false, + "pubtime": "2024-03-26T19:58:31Z" + } + ] + }, + { + "path": "mi/ni/minimal-lexical", + "header": "AwIAAABldGFnOiAiYWZmMGMzZGIzNGVmMTdlZDY0NDJhOGU2Y2M0NzY4OTYiAA==", + "records": [ + { + "name": "minimal-lexical", + "vers": "0.2.1", + "deps": [], + "cksum": "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a", + "features": { + "alloc": [], + "compact": [], + "default": ["std"], + "lint": [], + "nightly": [], + "std": [] + }, + "yanked": false, + "pubtime": "2021-10-04T10:48:13Z" + } + ] + }, + { + "path": "mi/ni/miniz_oxide", + "header": "AwIAAABldGFnOiAiNzgzNzFhMzMzMTFiNDhhZTI1MjgwZWM5MmUyOGNiYTYiAA==", + "records": [ + { + "name": "miniz_oxide", + "vers": "0.8.9", + "deps": [ + { + "name": "adler2", + "req": "^2.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "simd-adler32", + "req": "^0.3.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316", + "features": { + "block-boundary": [], + "default": ["with-alloc"], + "rustc-dep-of-std": ["core", "alloc", "adler2/rustc-dep-of-std"], + "simd": ["simd-adler32"], + "std": [], + "with-alloc": [] + }, + "yanked": false, + "pubtime": "2025-06-09T22:26:12Z" + }, + { + "name": "miniz_oxide", + "vers": "0.9.1", + "deps": [ + { + "name": "adler2", + "req": "^2.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive", "alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "simd-adler32", + "req": "^0.3.8", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c", + "features": { + "block-boundary": [], + "default": ["with-alloc"], + "rustc-dep-of-std": ["core", "alloc", "adler2/rustc-dep-of-std"], + "simd": ["simd-adler32"], + "with-alloc": [] + }, + "features2": { + "std": ["serde?/std"] + }, + "yanked": false, + "pubtime": "2026-03-13T00:19:26Z", + "v": 2 + } + ] + }, + { + "path": "mo/re/more-asserts", + "header": "AwIAAABldGFnOiAiOGNiZDUwODAxN2Y4NWRjYWYzZWUzOGFhMzJlNzgyYTciAA==", + "records": [ + { + "name": "more-asserts", + "vers": "0.3.1", + "deps": [], + "cksum": "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e", + "features": {}, + "yanked": false, + "pubtime": "2022-10-01T08:33:45Z" + } + ] + }, + { + "path": "mu/ng/munge", + "header": "AwIAAABldGFnOiAiOWE1YzljZDZkYTUxNzY2YWNiYTQ5MTdmNGM5YjZjZDIiAA==", + "records": [ + { + "name": "munge", + "vers": "0.4.7", + "deps": [ + { + "name": "munge_macro", + "req": "=0.4.7", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rustversion", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + } + ], + "cksum": "5e17401f259eba956ca16491461b6e8f72913a0a114e39736ce404410f915a0c", + "features": {}, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2025-09-29T14:59:31Z" + } + ] + }, + { + "path": "mu/ng/munge_macro", + "header": "AwIAAABldGFnOiAiYTM1YjRjYTFiOTFiY2E2M2Y5MjJjOGI5MjNhOGJiMzgiAA==", + "records": [ + { + "name": "munge_macro", + "vers": "0.4.7", + "deps": [ + { + "name": "proc-macro2", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2", + "features": ["clone-impls", "full", "parsing", "printing", "proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931", + "features": {}, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2025-09-29T14:59:27Z" + } + ] + }, + { + "path": "nu/m_/num_cpus", + "header": "AwIAAABldGFnOiAiMTA1NDQ3NzY1NmY2N2MwZmJiNGFlYWM0YzZmODQyMTMiAA==", + "records": [ + { + "name": "num_cpus", + "vers": "1.17.0", + "deps": [ + { + "name": "hermit-abi", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_os = \"hermit\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.26", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(windows))", + "kind": "normal" + } + ], + "cksum": "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b", + "features": {}, + "yanked": false, + "pubtime": "2025-05-30T18:59:42Z" + } + ] + }, + { + "path": "nu/m_/num_enum", + "header": "AwIAAABldGFnOiAiZWQ5NzAwNzYwMzU5NzFlZTdkZmYzOTAyMDhiNGU5NjYiAA==", + "records": [ + { + "name": "num_enum", + "vers": "0.7.6", + "deps": [ + { + "name": "anyhow", + "req": "^1.0.14", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "num_enum_derive", + "req": "=0.7.6", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "paste", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "trybuild", + "req": "^1.0.98", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "walkdir", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26", + "features": { + "complex-expressions": ["num_enum_derive/complex-expressions"], + "default": ["std"], + "external_doc": [], + "std": ["num_enum_derive/std"] + }, + "yanked": false, + "rust_version": "1.70.0", + "pubtime": "2026-03-15T21:29:40Z" + } + ] + }, + { + "path": "nu/m_/num_enum_derive", + "header": "AwIAAABldGFnOiAiMDkwZjc3Zjc1MDc4ODZiZmYwYjE0MDc2MDM1MjQxMDYiAA==", + "records": [ + { + "name": "num_enum_derive", + "vers": "0.7.6", + "deps": [ + { + "name": "proc-macro-crate", + "req": ">=1, <=3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1.0.60", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2", + "features": ["derive", "extra-traits", "parsing"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2", + "features": ["extra-traits", "parsing"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8", + "features": { + "complex-expressions": ["syn/full"], + "default": ["std"], + "external_doc": [], + "std": ["proc-macro-crate"] + }, + "yanked": false, + "rust_version": "1.70.0", + "pubtime": "2026-03-15T21:29:38Z" + } + ] + }, + { + "path": "nu/m-/num-conv", + "header": "AwIAAABldGFnOiAiZmM5MDZkOWU4YWU4ODAxNjVlYWZiYzhiZTc1MDNjM2UiAA==", + "records": [ + { + "name": "num-conv", + "vers": "0.2.2", + "deps": [], + "cksum": "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441", + "features": {}, + "yanked": false, + "rust_version": "1.57.0", + "pubtime": "2026-05-18T18:35:52Z" + } + ] + }, + { + "path": "nu/m-/num-traits", + "header": "AwIAAABldGFnOiAiNzZhMjFiYjNjOTZhOTQyMjU1ZTI0NWFhOTk3MWNiY2MiAA==", + "records": [ + { + "name": "num-traits", + "vers": "0.2.19", + "deps": [ + { + "name": "autocfg", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "libm", + "req": "^0.2.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841", + "features": { + "default": ["std"], + "i128": [], + "std": [] + }, + "features2": { + "libm": ["dep:libm"] + }, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2024-05-03T21:27:39Z", + "v": 2 + } + ] + }, + { + "path": "ob/jc/objc2-core-foundation", + "header": "AwIAAABldGFnOiAiNThlYTE2ZjM2ODVjMjM5ZWM1Nzc2NTY0NzNmOThkZmMiAA==", + "records": [ + { + "name": "objc2-core-foundation", + "vers": "0.3.2", + "deps": [ + { + "name": "bitflags", + "req": "^2.5.0", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "block2", + "req": ">=0.6.1, <0.8.0", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "dispatch2", + "req": ">=0.3.0, <0.5.0", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.80", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "objc2", + "req": ">=0.6.2, <0.8.0", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "static_assertions", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536", + "features": { + "CFArray": [], + "CFAttributedString": [], + "CFAvailability": [], + "CFBag": [], + "CFBase": [], + "CFBinaryHeap": [], + "CFBitVector": [], + "CFBundle": [], + "CFByteOrder": [], + "CFCGTypes": [], + "CFCharacterSet": [], + "CFDictionary": [], + "CFError": [], + "CFFileDescriptor": [], + "CFLocale": [], + "CFMachPort": [], + "CFMessagePort": [], + "CFNotificationCenter": [], + "CFNumber": [], + "CFPlugIn": [], + "CFPlugInCOM": [], + "CFPreferences": [], + "CFSet": [], + "CFStringEncodingExt": [], + "CFTimeZone": [], + "CFTree": [], + "CFURLAccess": [], + "CFUUID": [], + "CFUserNotification": [], + "CFUtilities": [], + "CFXMLNode": [], + "alloc": [], + "std": ["alloc"], + "unstable-coerce-pointee": [], + "unstable-darwin-objc": [] + }, + "features2": { + "CFCalendar": ["bitflags"], + "CFData": ["bitflags"], + "CFDate": ["bitflags"], + "CFDateFormatter": ["bitflags"], + "CFFileSecurity": ["bitflags"], + "CFNumberFormatter": ["bitflags"], + "CFPropertyList": ["bitflags"], + "CFRunLoop": ["bitflags"], + "CFSocket": ["bitflags"], + "CFStream": ["bitflags"], + "CFString": ["bitflags"], + "CFStringTokenizer": ["bitflags"], + "CFURL": ["bitflags"], + "CFURLEnumerator": ["bitflags"], + "CFXMLParser": ["bitflags"], + "bitflags": ["dep:bitflags"], + "block2": ["dep:block2"], + "default": [ + "std", + "CFArray", + "CFAttributedString", + "CFAvailability", + "CFBag", + "CFBinaryHeap", + "CFBitVector", + "CFBundle", + "CFByteOrder", + "CFCGTypes", + "CFCalendar", + "CFCharacterSet", + "CFData", + "CFDate", + "CFDateFormatter", + "CFDictionary", + "CFError", + "CFFileDescriptor", + "CFFileSecurity", + "CFLocale", + "CFMachPort", + "CFMessagePort", + "CFNotificationCenter", + "CFNumber", + "CFNumberFormatter", + "CFPlugIn", + "CFPlugInCOM", + "CFPreferences", + "CFPropertyList", + "CFRunLoop", + "CFSet", + "CFSocket", + "CFStream", + "CFString", + "CFStringEncodingExt", + "CFStringTokenizer", + "CFTimeZone", + "CFTree", + "CFURL", + "CFURLAccess", + "CFURLEnumerator", + "CFUUID", + "CFUserNotification", + "CFUtilities", + "CFXMLNode", + "CFXMLParser", + "bitflags", + "block2", + "dispatch2", + "libc", + "objc2" + ], + "dispatch2": ["dep:dispatch2"], + "libc": ["dep:libc"], + "objc2": ["dep:objc2", "dispatch2?/objc2"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2025-10-04T15:46:51Z", + "v": 2 + } + ] + }, + { + "path": "ob/jc/objc2-system-configuration", + "header": "AwIAAABldGFnOiAiNDkwNjMyNzljNTEwZDVkOGJiMWZjM2M1NmNiNTQ2NmYiAA==", + "records": [ + { + "name": "objc2-system-configuration", + "vers": "0.3.2", + "deps": [ + { + "name": "bitflags", + "req": "^2.5.0", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "dispatch2", + "req": ">=0.3.0, <0.5.0", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.80", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "objc2", + "req": ">=0.6.2, <0.8.0", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "objc2-core-foundation", + "req": "^0.3.2", + "features": ["CFError"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "objc2-security", + "req": "^0.3.2", + "features": ["Authorization"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "7216bd11cbda54ccabcab84d523dc93b858ec75ecfb3a7d89513fa22464da396", + "features": { + "CaptiveNetwork": [ + "objc2-core-foundation/CFArray", + "objc2-core-foundation/CFDictionary" + ], + "DHCPClientPreferences": [], + "SCDynamicStore": [ + "objc2-core-foundation/CFArray", + "objc2-core-foundation/CFDictionary", + "objc2-core-foundation/CFRunLoop" + ], + "SCDynamicStoreCopyDHCPInfo": [ + "objc2-core-foundation/CFData", + "objc2-core-foundation/CFDate", + "objc2-core-foundation/CFDictionary" + ], + "SCDynamicStoreCopySpecific": [ + "objc2-core-foundation/CFDictionary", + "objc2-core-foundation/CFString" + ], + "SCDynamicStoreKey": [], + "SCNetwork": [], + "SCNetworkConfiguration": [ + "objc2-core-foundation/CFArray", + "objc2-core-foundation/CFDictionary", + "objc2-core-foundation/CFNumber" + ], + "SCNetworkConnection": [ + "objc2-core-foundation/CFDictionary", + "objc2-core-foundation/CFRunLoop" + ], + "SCPreferencesPath": ["objc2-core-foundation/CFDictionary"], + "SCPreferencesSetSpecific": ["objc2-core-foundation/CFString"], + "SCSchemaDefinitions": [], + "alloc": [], + "std": ["alloc"], + "unstable-darwin-objc": [] + }, + "features2": { + "SCNetworkReachability": ["bitflags", "objc2-core-foundation/CFRunLoop"], + "SCPreferences": [ + "bitflags", + "objc2-core-foundation/CFArray", + "objc2-core-foundation/CFData", + "objc2-core-foundation/CFRunLoop" + ], + "bitflags": ["dep:bitflags"], + "default": [ + "std", + "CaptiveNetwork", + "DHCPClientPreferences", + "SCDynamicStore", + "SCDynamicStoreCopyDHCPInfo", + "SCDynamicStoreCopySpecific", + "SCDynamicStoreKey", + "SCNetwork", + "SCNetworkConfiguration", + "SCNetworkConnection", + "SCNetworkReachability", + "SCPreferences", + "SCPreferencesPath", + "SCPreferencesSetSpecific", + "SCSchemaDefinitions", + "bitflags", + "dispatch2", + "libc", + "objc2", + "objc2-security" + ], + "dispatch2": ["dep:dispatch2"], + "libc": ["dep:libc"], + "objc2": [ + "dep:objc2", + "dispatch2?/objc2", + "objc2-core-foundation/objc2", + "objc2-security?/objc2" + ], + "objc2-security": ["dep:objc2-security"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2025-10-04T16:34:10Z", + "v": 2 + } + ] + }, + { + "path": "ob/je/object", + "header": "AwIAAABldGFnOiAiZDRmZWNmNWVlOTZkZTliZTEyZDBiNGY4NjRjNGUwMzAiAA==", + "records": [ + { + "name": "object", + "vers": "0.37.3", + "deps": [ + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "crc32fast", + "req": "^1.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "flate2", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hashbrown", + "req": "^0.15.0", + "features": ["default-hasher"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "memchr", + "req": "^2.4.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "ruzstd", + "req": "^0.8.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasmparser", + "req": "^0.236.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe", + "features": { + "archive": [], + "cargo-all": [], + "coff": [], + "elf": [], + "macho": [], + "pe": ["coff"], + "read": ["read_core", "archive", "coff", "elf", "macho", "pe", "xcoff", "unaligned"], + "read_core": [], + "rustc-dep-of-std": ["core", "alloc", "memchr/rustc-dep-of-std"], + "std": ["memchr/std"], + "unaligned": [], + "unstable": [], + "xcoff": [] + }, + "features2": { + "all": ["read", "write", "build", "std", "compression", "wasm"], + "build": ["build_core", "write_std", "elf"], + "build_core": ["read_core", "write_core"], + "compression": ["dep:flate2", "dep:ruzstd", "std"], + "default": ["read", "compression"], + "doc": [ + "read_core", + "write_std", + "build_core", + "std", + "compression", + "archive", + "coff", + "elf", + "macho", + "pe", + "wasm", + "xcoff" + ], + "unstable-all": ["all", "unstable"], + "wasm": ["dep:wasmparser"], + "write": ["write_std", "coff", "elf", "macho", "pe", "xcoff"], + "write_core": ["dep:crc32fast", "dep:indexmap", "dep:hashbrown"], + "write_std": ["write_core", "std", "indexmap?/std", "crc32fast?/std"] + }, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2025-08-13T10:32:51Z", + "v": 2 + }, + { + "name": "object", + "vers": "0.39.1", + "deps": [ + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "crc32fast", + "req": "^1.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "flate2", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hashbrown", + "req": "^0.17.0", + "features": ["default-hasher"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2.14", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "memchr", + "req": "^2.4.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "ruzstd", + "req": "^0.8.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasmparser", + "req": "^0.247.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b", + "features": { + "archive": [], + "cargo-all": [], + "coff": [], + "elf": [], + "macho": [], + "pe": ["coff"], + "read": ["read_core", "archive", "coff", "elf", "macho", "pe", "xcoff"], + "read_core": [], + "rustc-dep-of-std": ["core", "alloc", "memchr/rustc-dep-of-std"], + "std": ["memchr/std"], + "unaligned": [], + "unstable": [], + "xcoff": [] + }, + "features2": { + "all": ["read", "write", "build", "std", "compression", "wasm"], + "build": ["build_core", "write_std", "elf"], + "build_core": ["read_core", "write_core"], + "compression": ["dep:flate2", "dep:ruzstd", "std"], + "default": ["read", "compression"], + "doc": ["all"], + "unstable-all": ["all", "unstable"], + "wasm": ["dep:wasmparser"], + "write": ["write_std", "coff", "elf", "macho", "pe", "xcoff"], + "write_core": ["dep:crc32fast", "dep:indexmap", "dep:hashbrown"], + "write_std": ["write_core", "std", "indexmap?/std", "crc32fast?/std"] + }, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-04-21T08:41:10Z", + "v": 2 + } + ] + }, + { + "path": "ol/ip/oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "header": "AwIAAABldGFnOiAiMDQ5YjAyZDI1NmJhZGJmZmNhYzk5N2FmZDEyYWRmNWIiAA==", + "records": [ + { + "name": "oliphaunt-extension-contrib-pg18-aot-linux-arm64", + "vers": "0.3.2", + "deps": [ + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "6593cd36d8c9cb83d2098ef5f62005bb62861f05bcd3d7238f5bcccbc11cdfd3", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_extension_contrib_pg18_aot_aarch64_unknown_linux_gnu", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:50Z" + } + ] + }, + { + "path": "ol/ip/oliphaunt-extension-contrib-pg18-aot-linux-x64", + "header": "AwIAAABldGFnOiAiNTFmMDYwOTVhZTI5OTU3ZTUxYzg5NDdjZWQ3MTBiMzQiAA==", + "records": [ + { + "name": "oliphaunt-extension-contrib-pg18-aot-linux-x64", + "vers": "0.3.2", + "deps": [ + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "238580b3fed00f8537e64c1c6548d74d33b544a322946879a8821eed7f4dc792", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_extension_contrib_pg18_aot_x86_64_unknown_linux_gnu", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:51Z" + } + ] + }, + { + "path": "ol/ip/oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "header": "AwIAAABldGFnOiAiZWQxZWViMzEzNmQ1MGRiZWJmYzU0ZTdmMTYyYjliMWIiAA==", + "records": [ + { + "name": "oliphaunt-extension-contrib-pg18-aot-macos-arm64", + "vers": "0.3.2", + "deps": [ + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "41bef2ac428e3b7f2149d1c342135c573a9dbd9c592eebaea3e0083f3840c64c", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_extension_contrib_pg18_aot_aarch64_apple_darwin", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:52Z" + } + ] + }, + { + "path": "ol/ip/oliphaunt-extension-contrib-pg18-aot-windows-x64", + "header": "AwIAAABldGFnOiAiNWI0ZDU0YjZmNjQzNmNlN2IyMjIzMDQ1YWY2YzlhZDQiAA==", + "records": [ + { + "name": "oliphaunt-extension-contrib-pg18-aot-windows-x64", + "vers": "0.3.2", + "deps": [ + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "623d461eda99618bda616e1f488160d0fa6833215676f73dc0c134a29c283cbd", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_extension_contrib_pg18_aot_x86_64_pc_windows_msvc", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:52Z" + } + ] + }, + { + "path": "ol/ip/oliphaunt-extension-contrib-pg18-wasix", + "header": "AwIAAABldGFnOiAiMDhhOGY0MGE5NjMwMWIwNGQ5MTNlMDZjY2M5NGMyM2QiAA==", + "records": [ + { + "name": "oliphaunt-extension-contrib-pg18-wasix", + "vers": "0.3.2", + "deps": [ + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "76a2cbf8c683ae8b380f11f4fa7581c41eddb370ab4d94cbba07d169c2ab7778", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_extension_contrib_pg18_wasix", + "rust_version": "1.93", + "pubtime": "2026-10-07T07:40:53Z" + } + ] + }, + { + "path": "ol/ip/oliphaunt-icu", + "header": "AwIAAABldGFnOiAiZDJmZWY4MjU0YTZjZDUzZTExM2FlNDA3ZWM0YmM1YzgiAA==", + "records": [ + { + "name": "oliphaunt-icu", + "vers": "0.2.2", + "deps": [ + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "tar", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "zstd", + "req": "^0.13", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "build" + } + ], + "cksum": "976fdebc00bbd4dc456e3e77dafb51886798048b648ed3f8b5f22aac8c83a587", + "features": {}, + "yanked": false, + "links": "oliphaunt_artifact_oliphaunt_icu", + "rust_version": "1.93", + "pubtime": "2026-10-02T23:55:49Z" + } + ] + }, + { + "path": "on/ce/once_cell", + "header": "AwIAAABldGFnOiAiYWUxMGE3ZDhhYTg2YzA5ZjkxZDdlNWE0ZDkyMmZhZmYiAA==", + "records": [ + { + "name": "once_cell", + "vers": "1.21.4", + "deps": [ + { + "name": "critical-section", + "req": "^1.1.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "critical-section", + "req": "^1.1.3", + "features": ["std"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "parking_lot_core", + "req": "^0.9.10", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "portable-atomic", + "req": "^1.8", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "regex", + "req": "^1.10.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50", + "features": { + "alloc": ["race"], + "default": ["std"], + "race": [], + "std": ["alloc"], + "unstable": [] + }, + "features2": { + "atomic-polyfill": ["critical-section"], + "critical-section": ["dep:critical-section", "portable-atomic"], + "parking_lot": ["dep:parking_lot_core"], + "portable-atomic": ["dep:portable-atomic"] + }, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-03-12T10:59:52Z", + "v": 2 + } + ] + }, + { + "path": "on/ce/once_cell_polyfill", + "header": "AwIAAABldGFnOiAiNjNmZGRlZDlhZmRlZWY0ZmVmNzc0NGFmNGQ3NDFlZTkiAA==", + "records": [ + { + "name": "once_cell_polyfill", + "vers": "1.70.2", + "deps": [], + "cksum": "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe", + "features": { + "default": [] + }, + "yanked": false, + "rust_version": "1.70.0", + "pubtime": "2025-10-21T16:41:12Z" + } + ] + }, + { + "path": "op/ti/option-ext", + "header": "AwIAAABldGFnOiAiZWE4NGY0NjhjMWRiYzZkZDc5ODA3ODNkZjZjMWNkNmQiAA==", + "records": [ + { + "name": "option-ext", + "vers": "0.2.0", + "deps": [], + "cksum": "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d", + "features": {}, + "yanked": false, + "pubtime": "2023-01-11T19:28:05Z" + } + ] + }, + { + "path": "pa/rk/parking", + "header": "AwIAAABldGFnOiAiMzZmMmNjMjgwODJiODFiODIzMzExNDNkNGU4YmUwZGYiAA==", + "records": [ + { + "name": "parking", + "vers": "2.2.1", + "deps": [ + { + "name": "easy-parallel", + "req": "^3.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "loom", + "req": "^0.7", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(loom)", + "kind": "normal" + } + ], + "cksum": "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba", + "features": {}, + "yanked": false, + "rust_version": "1.51", + "pubtime": "2024-09-07T17:39:03Z" + } + ] + }, + { + "path": "pa/rk/parking_lot", + "header": "AwIAAABldGFnOiAiMGYzMzc1MGNhMWE4Y2ZlODk4ZDVjNzVjMjdlNDlmZTQiAA==", + "records": [ + { + "name": "parking_lot", + "vers": "0.12.5", + "deps": [ + { + "name": "bincode", + "req": "^1.3.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "lock_api", + "req": "^0.4.14", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "parking_lot_core", + "req": "^0.9.12", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.8.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a", + "features": { + "arc_lock": ["lock_api/arc_lock"], + "deadlock_detection": ["parking_lot_core/deadlock_detection"], + "default": [], + "hardware-lock-elision": [], + "nightly": ["parking_lot_core/nightly", "lock_api/nightly"], + "owning_ref": ["lock_api/owning_ref"], + "send_guard": [], + "serde": ["lock_api/serde"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2025-10-03T23:34:14Z" + } + ] + }, + { + "path": "pa/rk/parking_lot_core", + "header": "AwIAAABldGFnOiAiOWNjMmU1YmZmYzE2NDllODIzYjc4MTZjMzlmNzg3NmUiAA==", + "records": [ + { + "name": "parking_lot_core", + "vers": "0.9.12", + "deps": [ + { + "name": "backtrace", + "req": "^0.3.60", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.95", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "petgraph", + "req": "^0.6.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "redox_syscall", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_os = \"redox\")", + "kind": "normal" + }, + { + "name": "smallvec", + "req": "^1.6.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "windows-link", + "req": "^0.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1", + "features": { + "deadlock_detection": ["petgraph", "backtrace"], + "nightly": [] + }, + "yanked": false, + "rust_version": "1.71.0", + "pubtime": "2025-10-03T23:33:43Z" + } + ] + }, + { + "path": "pa/st/paste", + "header": "AwIAAABldGFnOiAiNGY1Y2QzZjBlODMyYzk2MGYzYzAxODA3OTM0MWU2MDIiAA==", + "records": [ + { + "name": "paste", + "vers": "1.0.15", + "deps": [ + { + "name": "paste-test-suite", + "req": "^0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.49", + "features": ["diff"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a", + "features": {}, + "yanked": false, + "rust_version": "1.31", + "pubtime": "2024-05-07T01:50:22Z" + } + ] + }, + { + "path": "pa/th/path-clean", + "header": "AwIAAABldGFnOiAiMjUyNjRkMzZjNmI0ZTY4ZWVmNDRiNzRlMzIxZGE5MjkiAA==", + "records": [ + { + "name": "path-clean", + "vers": "1.0.1", + "deps": [ + { + "name": "criterion", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef", + "features": {}, + "yanked": false, + "pubtime": "2023-02-24T03:24:24Z" + } + ] + }, + { + "path": "pe/rc/percent-encoding", + "header": "AwIAAABldGFnOiAiY2MwNDRmN2I1NDUzYWZiYTE4ZTc3YTUwMzMwOWM1YTYiAA==", + "records": [ + { + "name": "percent-encoding", + "vers": "2.3.2", + "deps": [], + "cksum": "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220", + "features": { + "alloc": [], + "default": ["std"], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.51", + "pubtime": "2025-08-21T08:46:50Z" + } + ] + }, + { + "path": "pe/tg/petgraph", + "header": "AwIAAABldGFnOiAiNWQzMzFhODE4Yjk0MmYwZTM2MWYwMDRkMmIyYmE3YWUiAA==", + "records": [ + { + "name": "petgraph", + "vers": "0.8.3", + "deps": [ + { + "name": "ahash", + "req": "^0.7.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "bincode", + "req": "^1.3.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "defmac", + "req": "^0.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "dot-parser", + "req": "^0.5.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "dot-parser-macros", + "req": "^0.5.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "fixedbitset", + "req": "^0.5.7", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "fxhash", + "req": "^0.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hashbrown", + "req": "^0.15.0", + "features": ["default-hasher", "inline-more"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2.5.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "itertools", + "req": "^0.12.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "odds", + "req": "^0.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quickcheck", + "req": "^0.8", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.5.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "^1.5.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455", + "features": { + "generate": [], + "graphmap": [], + "matrix_graph": [], + "serde-1": ["serde", "serde_derive"], + "std": ["indexmap/std"], + "unstable": ["generate"] + }, + "features2": { + "all": [ + "unstable", + "quickcheck", + "matrix_graph", + "stable_graph", + "graphmap", + "rayon", + "dot_parser" + ], + "default": ["std", "graphmap", "stable_graph", "matrix_graph"], + "dot_parser": ["std", "dep:dot-parser", "dep:dot-parser-macros"], + "quickcheck": ["std", "dep:quickcheck", "graphmap", "stable_graph"], + "rayon": ["std", "dep:rayon", "indexmap/rayon", "hashbrown/rayon"], + "stable_graph": ["serde?/alloc"] + }, + "yanked": false, + "rust_version": "1.64", + "pubtime": "2025-09-30T13:16:04Z", + "v": 2 + } + ] + }, + { + "path": "ph/f_/phf_shared", + "header": "AwIAAABldGFnOiAiMTY0YmQxZDMxNWM1MTU1MGZjMDAyNGZlOWU3NzZjZWUiAA==", + "records": [ + { + "name": "phf_shared", + "vers": "0.13.1", + "deps": [ + { + "name": "siphasher", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "uncased", + "req": "^0.9.9", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "unicase", + "req": "^2.4.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.66", + "pubtime": "2025-08-23T11:05:56Z" + } + ] + }, + { + "path": "pi/n-/pin-project", + "header": "AwIAAABldGFnOiAiYTJjMTNlZmMzOTlkNzg1ZTIzZjZhNzE2YjQ5MTViNGYiAA==", + "records": [ + { + "name": "pin-project", + "vers": "1.1.13", + "deps": [ + { + "name": "pin-project-internal", + "req": "=1.1.13", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustversion", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "2466b2336ed02bcdca6b294417127b90ec92038d1d5c4fbeac971a922e0e0924", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-05-13T18:32:09Z" + } + ] + }, + { + "path": "pi/n-/pin-project-internal", + "header": "AwIAAABldGFnOiAiYTg2YTIyZDIzZGExYjAwZTM5NjA1NjFkOTJmZmM5NmQiAA==", + "records": [ + { + "name": "pin-project-internal", + "vers": "1.1.13", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.60", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.25", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0.1", + "features": ["parsing", "printing", "clone-impls", "proc-macro", "full", "visit-mut"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-05-13T18:32:07Z" + } + ] + }, + { + "path": "pi/n-/pin-project-lite", + "header": "AwIAAABldGFnOiAiZTdmZTUwZTQwZTkzNGUyYzk5NDZlMTczOTBkNmNlZjQiAA==", + "records": [ + { + "name": "pin-project-lite", + "vers": "0.2.17", + "deps": [ + { + "name": "rustversion", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd", + "features": {}, + "yanked": false, + "rust_version": "1.37", + "pubtime": "2026-02-27T15:19:08Z" + } + ] + }, + { + "path": "pi/n-/pin-utils", + "header": "AwIAAABldGFnOiAiMTljZTgwOGMyYThhY2Y3NTFjMzc3ZTI4MzhlZGQxNGQiAA==", + "records": [ + { + "name": "pin-utils", + "vers": "0.1.1", + "deps": [], + "cksum": "13bee6c73da26345c729282832b60b0363cf3dd9f4bfd81d8551b7a1c889a113", + "features": {}, + "yanked": false, + "pubtime": "2026-10-01T07:13:59Z" + } + ] + }, + { + "path": "pk/g-/pkg-config", + "header": "AwIAAABldGFnOiAiZjJiODI5OWQ4MmIxMDhmNDNkOGQxODViYTMyNzRiNDgiAA==", + "records": [ + { + "name": "pkg-config", + "vers": "0.3.34", + "deps": [], + "cksum": "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548", + "features": {}, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2026-08-14T08:27:51Z" + } + ] + }, + { + "path": "pl/ai/plain", + "header": "AwIAAABldGFnOiAiMzk5ZTc4MjY1NjJlMTA5MGM3YzZjMTJiZjcxMjNmMzEiAA==", + "records": [ + { + "name": "plain", + "vers": "0.2.3", + "deps": [], + "cksum": "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6", + "features": {}, + "yanked": false, + "pubtime": "2017-11-24T15:28:33Z" + } + ] + }, + { + "path": "po/st/postgres-protocol", + "header": "AwIAAABldGFnOiAiYjljYTk3NTc4NzRjODVkOTE1Y2VjZDM1ZTNmNzhiYzciAA==", + "records": [ + { + "name": "postgres-protocol", + "vers": "0.6.12", + "deps": [ + { + "name": "base64", + "req": "^0.22", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "byteorder", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytes", + "req": "^1.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "fallible-iterator", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "getrandom", + "req": "^0.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hmac", + "req": "^0.13", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "md-5", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memchr", + "req": "^2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sha2", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "stringprep", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "08808e3c483c46e999108051c78334f473d5adb59d78bb80a1268c7e6aa6c514", + "features": { + "default": [], + "js": ["getrandom/wasm_js"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-06-12T15:34:01Z" + } + ] + }, + { + "path": "po/st/postgres-types", + "header": "AwIAAABldGFnOiAiNDgwOWRmZDI4YjU0YTRkZTg4NDFmMDIzOTMzOWY1MjAiAA==", + "records": [ + { + "name": "postgres-types", + "vers": "0.2.14", + "deps": [ + { + "name": "array-init", + "req": "^2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bit-vec-06", + "req": "^0.6", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "bit-vec" + }, + { + "name": "bit-vec-07", + "req": "^0.7", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "bit-vec" + }, + { + "name": "bit-vec-08", + "req": "^0.8", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "bit-vec" + }, + { + "name": "bit-vec-09", + "req": "^0.9", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "bit-vec" + }, + { + "name": "bytes", + "req": "^1.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "chrono-04", + "req": "^0.4.33", + "features": ["clock"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "chrono" + }, + { + "name": "cidr-02", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "cidr" + }, + { + "name": "cidr-03", + "req": "^0.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "cidr" + }, + { + "name": "eui48-04", + "req": "^0.4.6", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "eui48" + }, + { + "name": "eui48-1", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "eui48" + }, + { + "name": "fallible-iterator", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "geo-types-06", + "req": "^0.6", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "geo-types" + }, + { + "name": "geo-types-0_7", + "req": "^0.7.8", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "geo-types" + }, + { + "name": "jiff-01", + "req": "^0.1", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "jiff" + }, + { + "name": "jiff-02", + "req": "^0.2", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "jiff" + }, + { + "name": "postgres-derive", + "req": "^0.4.9", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "postgres-protocol", + "req": "^0.6.12", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde-1", + "req": "^1.0.221", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "serde_core" + }, + { + "name": "serde_json-1", + "req": "^1.0.144", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "serde_json" + }, + { + "name": "smol_str-01", + "req": "^0.1.23", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "smol_str" + }, + { + "name": "time-02", + "req": "^0.2.7", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "time" + }, + { + "name": "time-03", + "req": "^0.3.5", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "time" + }, + { + "name": "uuid-08", + "req": "^0.8", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "uuid" + }, + { + "name": "uuid-1", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "uuid" + } + ], + "cksum": "851ca9db4932932d69f3ea811b1abe63087a0f740a47692619dd40d4899b68be", + "features": { + "array-impls": ["array-init"], + "derive": ["postgres-derive"], + "js": ["postgres-protocol/js"], + "with-bit-vec-0_6": ["bit-vec-06"], + "with-bit-vec-0_7": ["bit-vec-07"], + "with-bit-vec-0_8": ["bit-vec-08"], + "with-bit-vec-0_9": ["bit-vec-09"], + "with-chrono-0_4": ["chrono-04"], + "with-cidr-0_2": ["cidr-02"], + "with-cidr-0_3": ["cidr-03"], + "with-eui48-0_4": ["eui48-04"], + "with-eui48-1": ["eui48-1"], + "with-geo-types-0_6": ["geo-types-06"], + "with-geo-types-0_7": ["geo-types-0_7"], + "with-jiff-0_1": ["jiff-01"], + "with-jiff-0_2": ["jiff-02"], + "with-serde_json-1": ["serde-1", "serde_json-1"], + "with-smol_str-01": ["smol_str-01"], + "with-time-0_2": ["time-02"], + "with-time-0_3": ["time-03"], + "with-uuid-0_8": ["uuid-08"], + "with-uuid-1": ["uuid-1"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-06-12T15:37:04Z" + } + ] + }, + { + "path": "po/te/potential_utf", + "header": "AwIAAABldGFnOiAiYTg1NGQ4MWUzZTQwZGJhM2YxOGE5MjViYmI4NTY0MDYiAA==", + "records": [ + { + "name": "potential_utf", + "vers": "0.1.6", + "deps": [ + { + "name": "bincode", + "req": "^1.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "databake", + "req": "^0.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_core", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.45", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "writeable", + "req": "^0.6.4", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerovec", + "req": "^0.11.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661", + "features": {}, + "features2": { + "alloc": ["serde_core?/alloc", "writeable/alloc", "zerovec?/alloc"], + "databake": ["dep:databake"], + "default": ["alloc"], + "serde": ["dep:serde_core"], + "writeable": ["dep:writeable"], + "zerovec": ["dep:zerovec"] + }, + "yanked": false, + "rust_version": "1.82", + "pubtime": "2026-08-13T23:28:14Z", + "v": 2 + } + ] + }, + { + "path": "po/we/powerfmt", + "header": "AwIAAABldGFnOiAiMzA5NTM5NDg0YTVmNDcyMGFmMjM0MTc5ZDQ3NDI3OGMiAA==", + "records": [ + { + "name": "powerfmt", + "vers": "0.2.1", + "deps": [ + { + "name": "powerfmt-macros", + "req": "=0.1.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "4a6394b9e965e73d0a289ee54f589087e2c676aedf60885baf52c76b771e4958", + "features": { + "alloc": [], + "std": ["alloc"] + }, + "features2": { + "default": ["std", "macros"], + "macros": ["dep:powerfmt-macros"] + }, + "yanked": false, + "rust_version": "1.79.0", + "pubtime": "2026-10-05T09:01:10Z", + "v": 2 + } + ] + }, + { + "path": "pp/v-/ppv-lite86", + "header": "AwIAAABldGFnOiAiMmVjZTg1MGU4YjJjZjA0ZTRmZDNjYTdmY2VlNDcxYzAiAA==", + "records": [ + { + "name": "ppv-lite86", + "vers": "0.2.21", + "deps": [ + { + "name": "zerocopy", + "req": "^0.8.23", + "features": ["simd"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9", + "features": { + "default": ["std"], + "no_simd": [], + "simd": [], + "std": [] + }, + "yanked": false, + "rust_version": "1.61", + "pubtime": "2025-03-09T20:01:40Z" + } + ] + }, + { + "path": "pr/et/prettyplease", + "header": "AwIAAABldGFnOiAiYzQ1MzE1NjEyNGI3ODA0YmUyMTMxYTZmZDM1ODQzZTQiAA==", + "records": [ + { + "name": "prettyplease", + "vers": "0.2.37", + "deps": [ + { + "name": "indoc", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1.0.80", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1.0.80", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "quote", + "req": "^1.0.35", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "syn", + "req": "^2.0.105", + "features": ["full"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0.105", + "features": ["clone-impls", "extra-traits", "parsing", "printing", "visit-mut"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + } + ], + "cksum": "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b", + "features": { + "verbatim": ["syn/parsing"] + }, + "yanked": false, + "links": "prettyplease02", + "rust_version": "1.62", + "pubtime": "2025-08-19T00:29:26Z" + } + ] + }, + { + "path": "pr/oc/proc-macro-crate", + "header": "AwIAAABldGFnOiAiMjRjM2QwZDk2OWZkZTdmMTcxYmYyMDM5MGVhZDJkZjEiAA==", + "records": [ + { + "name": "proc-macro-crate", + "vers": "3.5.0", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.94", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quote", + "req": "^1.0.39", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn", + "req": "^2.0.99", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml_edit", + "req": "^0.25.0", + "features": ["parse"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f", + "features": {}, + "yanked": false, + "rust_version": "1.82.0", + "pubtime": "2026-03-04T11:12:33Z" + } + ] + }, + { + "path": "pr/oc/proc-macro-error-attr2", + "header": "AwIAAABldGFnOiAiYjRiZjg4MTRkZTMxOGI0NTE5YjMzZDQ1ZDZlMjdiOWYiAA==", + "records": [ + { + "name": "proc-macro-error-attr2", + "vers": "2.0.0", + "deps": [ + { + "name": "proc-macro2", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5", + "features": {}, + "yanked": false, + "rust_version": "1.61", + "pubtime": "2024-09-05T11:14:52Z" + } + ] + }, + { + "path": "pr/oc/proc-macro-error2", + "header": "AwIAAABldGFnOiAiOTlmYWEzMTA1YmNkNDM5Yzg1NDU5NWEwZGIwZjM2ZDkiAA==", + "records": [ + { + "name": "proc-macro-error2", + "vers": "2.0.1", + "deps": [ + { + "name": "proc-macro-error-attr2", + "req": "=2.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2", + "features": ["full"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.99", + "features": ["diff"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802", + "features": { + "nightly": [] + }, + "features2": { + "default": ["syn-error"], + "syn-error": ["dep:syn"] + }, + "yanked": false, + "rust_version": "1.61", + "pubtime": "2024-09-06T20:04:43Z", + "v": 2 + } + ] + }, + { + "path": "pr/oc/proc-macro2", + "header": "AwIAAABldGFnOiAiYWJhYmI1OTE1N2M2ZTlhNzE0YTliMWNiMzAyZTg0MmUiAA==", + "records": [ + { + "name": "proc-macro2", + "vers": "1.0.107", + "deps": [ + { + "name": "flate2", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quote", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tar", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicode-ident", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9", + "features": { + "default": ["proc-macro"], + "nightly": [], + "proc-macro": [], + "span-locations": [] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-19T00:18:25Z" + } + ] + }, + { + "path": "pt/r_/ptr_meta", + "header": "AwIAAABldGFnOiAiMjM3MzQ2ZjhjY2ZiMDIyZjI1MDE5OWMyNGQyZGFhMGYiAA==", + "records": [ + { + "name": "ptr_meta", + "vers": "0.3.2", + "deps": [ + { + "name": "ptr_meta_derive", + "req": "=0.3.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "743da816b98c921cdbe8628ef7381b76f25ecf4da599fc80aca90eae7ef70cc0", + "features": { + "default": ["derive", "std"], + "derive": ["ptr_meta_derive"], + "std": [] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-08-05T11:57:40Z" + } + ] + }, + { + "path": "pt/r_/ptr_meta_derive", + "header": "AwIAAABldGFnOiAiZDkyZjFlNGJlNzNlOGNkY2ZlMGJkNTYyYzNmZjYwZDkiAA==", + "records": [ + { + "name": "ptr_meta_derive", + "vers": "0.3.2", + "deps": [ + { + "name": "proc-macro2", + "req": "^1", + "features": ["proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": ["proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3.0", + "features": ["clone-impls", "derive", "full", "parsing", "printing", "proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "1c8d9ca532f185d5d4db7a7c9d51420b452168ea1c2b913953281bd6fe1fcbd0", + "features": {}, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-08-05T11:57:38Z" + } + ] + }, + { + "path": "pu/ll/pulldown-cmark", + "header": "AwIAAABldGFnOiAiMWMzMTMwZTlkZjRmNDZlMzhjNWEwODBjOTRhYWMxZDgiAA==", + "records": [ + { + "name": "pulldown-cmark", + "vers": "0.8.0", + "deps": [ + { + "name": "bitflags", + "req": "^1.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "criterion", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "getopts", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "html5ever", + "req": "^0.25", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "lazy_static", + "req": "^1.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "markup5ever_rcdom", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "memchr", + "req": "^2.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "regex", + "req": "^1.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tendril", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicase", + "req": "^2.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8", + "features": { + "default": ["getopts"], + "gen-tests": [], + "simd": [] + }, + "yanked": false, + "pubtime": "2020-09-01T15:23:43Z" + } + ] + }, + { + "path": "qu/ot/quote", + "header": "AwIAAABldGFnOiAiNzI5NmI3Yzk0OGUyODExNjhiMGVhZTc0NjVmZTM5MTgiAA==", + "records": [ + { + "name": "quote", + "vers": "1.0.47", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.80", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rustversion", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.108", + "features": ["diff"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001", + "features": { + "default": ["proc-macro"], + "proc-macro": ["proc-macro2/proc-macro"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-19T00:16:57Z" + } + ] + }, + { + "path": "r-/ef/r-efi", + "header": "AwIAAABldGFnOiAiNDdiZGU4NjlmOWVjMzhmNzdkZjI2YjJlZTQxZGQ1ZTYiAA==", + "records": [ + { + "name": "r-efi", + "vers": "5.3.0", + "deps": [ + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + } + ], + "cksum": "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f", + "features": { + "efiapi": [], + "examples": ["native"], + "native": [], + "rustc-dep-of-std": ["core"] + }, + "yanked": false, + "rust_version": "1.68", + "pubtime": "2025-06-17T09:12:38Z" + }, + { + "name": "r-efi", + "vers": "6.0.0", + "deps": [ + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + } + ], + "cksum": "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf", + "features": { + "native": [], + "rustc-dep-of-std": ["core"] + }, + "yanked": false, + "rust_version": "1.68", + "pubtime": "2026-02-03T09:53:46Z" + } + ] + }, + { + "path": "ra/nc/rancor", + "header": "AwIAAABldGFnOiAiZmE4MGU5MTYyMmYxNjVlMjFmZGI0MThkMDgxOTdlY2UiAA==", + "records": [ + { + "name": "rancor", + "vers": "0.1.3", + "deps": [ + { + "name": "ptr_meta", + "req": "^0.3", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "9b534442d0fcdb55d66f373d9cac6d33b6293a2335bc2136dbd06ce0e87d2572", + "features": { + "alloc": [], + "default": ["alloc"] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-08-05T11:46:35Z" + } + ] + }, + { + "path": "ra/nd/rand", + "header": "AwIAAABldGFnOiAiZjEyYmNmNmZjZTRhY2UwYWMwMmRmZDk4YjU4NWJkZWEiAA==", + "records": [ + { + "name": "rand", + "vers": "0.8.8", + "deps": [ + { + "name": "bincode", + "req": "^1.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "libc", + "req": "^0.2.22", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "rand_chacha", + "req": "^0.3.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand_core", + "req": "^0.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rand_pcg", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.103", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.99", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c", + "features": { + "alloc": ["rand_core/alloc"], + "default": ["std", "std_rng"], + "getrandom": ["rand_core/getrandom"], + "log": [], + "min_const_gen": [], + "nightly": [], + "serde1": ["serde", "rand_core/serde1"], + "small_rng": [], + "std": ["rand_core/std", "rand_chacha/std", "alloc", "getrandom", "libc"], + "std_rng": ["rand_chacha"] + }, + "yanked": false, + "pubtime": "2026-08-25T07:45:50Z" + }, + { + "name": "rand", + "vers": "0.9.5", + "deps": [ + { + "name": "bincode", + "req": "^1.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand_chacha", + "req": "^0.9.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand_core", + "req": "^0.9.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand_pcg", + "req": "^0.9.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "^1.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.103", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.140", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41", + "features": { + "alloc": [], + "log": [], + "nightly": [], + "os_rng": ["rand_core/os_rng"], + "simd_support": [], + "small_rng": [], + "unbiased": [] + }, + "features2": { + "default": ["std", "std_rng", "os_rng", "small_rng", "thread_rng"], + "serde": ["dep:serde", "rand_core/serde"], + "std": ["rand_core/std", "rand_chacha?/std", "alloc"], + "std_rng": ["dep:rand_chacha"], + "thread_rng": ["std", "std_rng", "os_rng"] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2026-07-11T11:16:46Z", + "v": 2 + }, + { + "name": "rand", + "vers": "0.10.3", + "deps": [ + { + "name": "chacha20", + "req": "^0.10.0", + "features": ["rng"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "getrandom", + "req": "^0.4.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "postcard", + "req": "^1.1.3", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rand_core", + "req": "^0.10.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand_pcg", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "^1.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.103", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.140", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af", + "features": { + "alloc": [], + "log": [], + "simd_support": [], + "unbiased": [] + }, + "features2": { + "chacha": ["dep:chacha20"], + "default": ["std", "std_rng", "sys_rng", "thread_rng"], + "serde": ["dep:serde"], + "std": ["alloc", "getrandom?/std"], + "std_rng": ["dep:chacha20"], + "sys_rng": ["dep:getrandom", "getrandom/sys_rng"], + "thread_rng": ["std", "std_rng", "sys_rng"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-09-20T06:37:47Z", + "v": 2 + } + ] + }, + { + "path": "ra/nd/rand_chacha", + "header": "AwIAAABldGFnOiAiZjA0YzM0YjFjMTM5MzU4NjU5OGExMGQ4ZWI1YTkxYzkiAA==", + "records": [ + { + "name": "rand_chacha", + "vers": "0.3.1", + "deps": [ + { + "name": "ppv-lite86", + "req": "^0.2.8", + "features": ["simd"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand_core", + "req": "^0.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88", + "features": { + "default": ["std"], + "serde1": ["serde"], + "simd": [], + "std": ["ppv-lite86/std"] + }, + "yanked": false, + "pubtime": "2021-06-09T19:46:38Z" + }, + { + "name": "rand_chacha", + "vers": "0.9.0", + "deps": [ + { + "name": "ppv-lite86", + "req": "^0.2.14", + "features": ["simd"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand_core", + "req": "^0.9.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rand_core", + "req": "^0.9.0", + "features": ["os_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb", + "features": { + "default": ["std"], + "os_rng": ["rand_core/os_rng"], + "std": ["ppv-lite86/std", "rand_core/std"] + }, + "features2": { + "serde": ["dep:serde"] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2025-01-27T13:38:26Z", + "v": 2 + } + ] + }, + { + "path": "ra/nd/rand_core", + "header": "AwIAAABldGFnOiAiYjNmZWIzNDE5NGY4Y2RlODg5ZDBkN2FiY2I1YjI4MDYiAA==", + "records": [ + { + "name": "rand_core", + "vers": "0.6.4", + "deps": [ + { + "name": "getrandom", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c", + "features": { + "alloc": [], + "serde1": ["serde"], + "std": ["alloc", "getrandom", "getrandom/std"] + }, + "yanked": false, + "pubtime": "2022-09-15T13:23:44Z" + }, + { + "name": "rand_core", + "vers": "0.9.5", + "deps": [ + { + "name": "getrandom", + "req": "^0.3.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c", + "features": {}, + "features2": { + "os_rng": ["dep:getrandom"], + "serde": ["dep:serde"], + "std": ["getrandom?/std"] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2026-01-13T09:22:22Z", + "v": 2 + }, + { + "name": "rand_core", + "vers": "0.10.1", + "deps": [], + "cksum": "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69", + "features": {}, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-04-13T15:26:43Z" + } + ] + }, + { + "path": "ra/ng/rangemap", + "header": "AwIAAABldGFnOiAiMDA1ODk2NGQ5Y2JiMTM2NDUyMGYzYzFhMDZjNzYyYTMiAA==", + "records": [ + { + "name": "rangemap", + "vers": "1.8.0", + "deps": [ + { + "name": "chrono", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ordered-float", + "req": "^5.3.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "ordered-float", + "req": "^5.3.0", + "features": ["proptest"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "permutator", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proptest", + "req": "^1.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quickcheck", + "req": "^1.0.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustc_version", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "test-strategy", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "a611d15b50743feb4c76b7d03edcb0e64f399c26961e4efe6975bc398be6aa3d", + "features": { + "const_fn": [], + "nightly": [] + }, + "features2": { + "ordered-float5": ["dep:ordered-float"], + "quickcheck": ["dep:quickcheck"], + "serde1": ["serde", "ordered-float?/serde"] + }, + "yanked": false, + "rust_version": "1.81.0", + "pubtime": "2026-08-14T02:30:08Z", + "v": 2 + } + ] + }, + { + "path": "ra/yo/rayon", + "header": "AwIAAABldGFnOiAiY2JiZjIyNGJjYjVjMmQyNDRhNmNlNDFlZmQ2NzU4NWYiAA==", + "records": [ + { + "name": "rayon", + "vers": "1.12.0", + "deps": [ + { + "name": "either", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand_xorshift", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon-core", + "req": "^1.13.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasm_sync", + "req": "^0.1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d", + "features": {}, + "features2": { + "web_spin_lock": ["dep:wasm_sync", "rayon-core/web_spin_lock"] + }, + "yanked": false, + "rust_version": "1.80", + "pubtime": "2026-04-14T00:56:56Z", + "v": 2 + } + ] + }, + { + "path": "ra/yo/rayon-core", + "header": "AwIAAABldGFnOiAiNDNiMGNiZWYzOTE5ZGZkZmQ5NGQ2YTY1NjQ5OGMwMzAiAA==", + "records": [ + { + "name": "rayon-core", + "vers": "1.13.0", + "deps": [ + { + "name": "crossbeam-deque", + "req": "^0.8.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "crossbeam-utils", + "req": "^0.8.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand_xorshift", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "scoped-tls", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "wasm_sync", + "req": "^0.1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91", + "features": {}, + "features2": { + "web_spin_lock": ["dep:wasm_sync"] + }, + "yanked": false, + "links": "rayon-core", + "rust_version": "1.80", + "pubtime": "2025-08-12T23:21:51Z", + "v": 2 + } + ] + }, + { + "path": "re/do/redox_syscall", + "header": "AwIAAABldGFnOiAiMTExOGMyMGZiMzQ4ZjZhMjdmZDljYWI4YmI4ZTkwNGUiAA==", + "records": [ + { + "name": "redox_syscall", + "vers": "0.5.18", + "deps": [ + { + "name": "bitflags", + "req": "^2.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "loom", + "req": "^0.7", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(loom)", + "kind": "dev" + } + ], + "cksum": "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d", + "features": { + "default": ["userspace"], + "rustc-dep-of-std": ["core", "bitflags/rustc-dep-of-std"], + "std": [], + "userspace": [] + }, + "yanked": false, + "pubtime": "2025-10-04T14:57:04Z" + }, + { + "name": "redox_syscall", + "vers": "0.9.4", + "deps": [ + { + "name": "bitflags", + "req": "^2.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "loom", + "req": "^0.7", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(loom)", + "kind": "dev" + } + ], + "cksum": "737970939a87c6fa31e7acad13307bccbb017a073b695b6089a2c484f929e20e", + "features": { + "default": ["userspace"], + "rustc-dep-of-std": ["core", "bitflags/rustc-dep-of-std"], + "std": [], + "userspace": [] + }, + "yanked": false, + "pubtime": "2026-09-05T08:52:15Z" + } + ] + }, + { + "path": "re/do/redox_users", + "header": "AwIAAABldGFnOiAiMDM3ZjAyMGY1OTQxYzllYmRiYTRlZTg5MDM2ODMzODciAA==", + "records": [ + { + "name": "redox_users", + "vers": "0.5.3", + "deps": [ + { + "name": "getrandom", + "req": "^0.4", + "features": ["std"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libredox", + "req": "^0.1.3", + "features": ["std", "call"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rust-argon2", + "req": "^3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "thiserror", + "req": "^2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "zeroize", + "req": "^1.4", + "features": ["zeroize_derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "60dc65c0ff1a7ae1294b0c67b9f14baf70b644404010370171787bfac1038fc0", + "features": { + "auth": ["rust-argon2", "getrandom", "zeroize"], + "default": ["auth"] + }, + "yanked": false, + "pubtime": "2026-09-16T13:29:14Z" + } + ] + }, + { + "path": "re/f-/ref-cast", + "header": "AwIAAABldGFnOiAiZmJmN2RhYzA0MTE5Yjc1MGVhZTVjMWI5MmVkODBjODQiAA==", + "records": [ + { + "name": "ref-cast", + "vers": "1.0.27", + "deps": [ + { + "name": "ref-cast-impl", + "req": "=1.0.27", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ref-cast-test-suite", + "req": "^0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0.13", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.108", + "features": ["diff"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-08-19T04:27:28Z" + } + ] + }, + { + "path": "re/f-/ref-cast-impl", + "header": "AwIAAABldGFnOiAiMDI2NDk2YjU2YTUzOGExZjA1OWU1ZjQzYmZlMWZhNjMiAA==", + "records": [ + { + "name": "ref-cast-impl", + "vers": "1.0.27", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.74", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.35", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ref-cast", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-08-19T04:27:24Z" + } + ] + }, + { + "path": "re/ge/regex", + "header": "AwIAAABldGFnOiAiMDcwNTJlZDUyMmY5NWQ1YmI4Mjg5MGRhYTAwNDJlNDEiAA==", + "records": [ + { + "name": "regex", + "vers": "1.13.1", + "deps": [ + { + "name": "aho-corasick", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "anyhow", + "req": "^1.0.69", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "doc-comment", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "env_logger", + "req": "^0.9.3", + "features": ["atty", "humantime", "termcolor"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "memchr", + "req": "^2.6.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1.0.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "regex-automata", + "req": "^0.4.16", + "features": ["alloc", "syntax", "meta", "nfa-pikevm"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "regex-syntax", + "req": "^0.8.11", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "regex-test", + "req": "^0.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d", + "features": { + "pattern": [], + "perf-backtrack": ["regex-automata/nfa-backtrack"], + "perf-cache": [], + "perf-dfa": ["regex-automata/hybrid"], + "perf-dfa-full": ["regex-automata/dfa-build", "regex-automata/dfa-search"], + "perf-inline": ["regex-automata/perf-inline"], + "perf-onepass": ["regex-automata/dfa-onepass"], + "unicode": [ + "unicode-age", + "unicode-bool", + "unicode-case", + "unicode-gencat", + "unicode-perl", + "unicode-script", + "unicode-segment", + "regex-automata/unicode", + "regex-syntax/unicode" + ], + "unicode-age": ["regex-automata/unicode-age", "regex-syntax/unicode-age"], + "unicode-bool": ["regex-automata/unicode-bool", "regex-syntax/unicode-bool"], + "unicode-case": ["regex-automata/unicode-case", "regex-syntax/unicode-case"], + "unicode-gencat": ["regex-automata/unicode-gencat", "regex-syntax/unicode-gencat"], + "unicode-perl": [ + "regex-automata/unicode-perl", + "regex-automata/unicode-word-boundary", + "regex-syntax/unicode-perl" + ], + "unicode-script": ["regex-automata/unicode-script", "regex-syntax/unicode-script"], + "unicode-segment": ["regex-automata/unicode-segment", "regex-syntax/unicode-segment"], + "unstable": ["pattern"] + }, + "features2": { + "default": ["std", "perf", "unicode", "regex-syntax/default"], + "logging": ["aho-corasick?/logging", "memchr?/logging", "regex-automata/logging"], + "perf": [ + "perf-cache", + "perf-dfa", + "perf-onepass", + "perf-backtrack", + "perf-inline", + "perf-literal" + ], + "perf-literal": ["dep:aho-corasick", "dep:memchr", "regex-automata/perf-literal"], + "std": ["aho-corasick?/std", "memchr?/std", "regex-automata/std", "regex-syntax/std"], + "use_std": ["std"] + }, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-07-15T20:19:35Z", + "v": 2 + } + ] + }, + { + "path": "re/ge/regex-automata", + "header": "AwIAAABldGFnOiAiZmUzNmMyMGIxMDRmZWJhOWFlMzRhZWU4ZmRkZDMzNGMiAA==", + "records": [ + { + "name": "regex-automata", + "vers": "0.4.18", + "deps": [ + { + "name": "aho-corasick", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "anyhow", + "req": "^1.0.69", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "bstr", + "req": "^1.3.0", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "doc-comment", + "req": "^0.3.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "env_logger", + "req": "^0.9.3", + "features": ["atty", "humantime", "termcolor"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "log", + "req": "^0.4.14", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memchr", + "req": "^2.6.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1.0.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "regex-syntax", + "req": "^0.8.5", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "regex-test", + "req": "^0.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2", + "features": { + "alloc": [], + "dfa": ["dfa-build", "dfa-search", "dfa-onepass"], + "dfa-build": ["nfa-thompson", "dfa-search"], + "dfa-onepass": ["nfa-thompson"], + "dfa-search": [], + "hybrid": ["alloc", "nfa-thompson"], + "nfa": ["nfa-thompson", "nfa-pikevm", "nfa-backtrack"], + "nfa-backtrack": ["nfa-thompson"], + "nfa-pikevm": ["nfa-thompson"], + "nfa-thompson": ["alloc"], + "perf-inline": [], + "unicode-word-boundary": [] + }, + "features2": { + "default": ["std", "syntax", "perf", "unicode", "meta", "nfa", "dfa", "hybrid"], + "internal-instrument": ["internal-instrument-pikevm"], + "internal-instrument-pikevm": ["logging", "std"], + "logging": ["dep:log", "aho-corasick?/logging", "memchr?/logging"], + "meta": ["syntax", "nfa-pikevm"], + "perf": ["perf-inline", "perf-literal"], + "perf-literal": ["perf-literal-substring", "perf-literal-multisubstring"], + "perf-literal-multisubstring": ["dep:aho-corasick"], + "perf-literal-substring": ["aho-corasick?/perf-literal", "dep:memchr"], + "std": ["regex-syntax?/std", "memchr?/std", "aho-corasick?/std", "alloc"], + "syntax": ["dep:regex-syntax", "alloc"], + "unicode": [ + "unicode-age", + "unicode-bool", + "unicode-case", + "unicode-gencat", + "unicode-perl", + "unicode-script", + "unicode-segment", + "unicode-word-boundary", + "regex-syntax?/unicode" + ], + "unicode-age": ["regex-syntax?/unicode-age"], + "unicode-bool": ["regex-syntax?/unicode-bool"], + "unicode-case": ["regex-syntax?/unicode-case"], + "unicode-gencat": ["regex-syntax?/unicode-gencat"], + "unicode-perl": ["regex-syntax?/unicode-perl"], + "unicode-script": ["regex-syntax?/unicode-script"], + "unicode-segment": ["regex-syntax?/unicode-segment"] + }, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-08-04T13:10:37Z", + "v": 2 + } + ] + }, + { + "path": "re/ge/regex-syntax", + "header": "AwIAAABldGFnOiAiOGI3YWRiYzAwMDU0YmQ3ZDVkMTAxZjQzMzM1Yjg1YmEiAA==", + "records": [ + { + "name": "regex-syntax", + "vers": "0.8.11", + "deps": [ + { + "name": "arbitrary", + "req": "^1.3.0", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4", + "features": { + "default": ["std", "unicode"], + "std": [], + "unicode": [ + "unicode-age", + "unicode-bool", + "unicode-case", + "unicode-gencat", + "unicode-perl", + "unicode-script", + "unicode-segment" + ], + "unicode-age": [], + "unicode-bool": [], + "unicode-case": [], + "unicode-gencat": [], + "unicode-perl": [], + "unicode-script": [], + "unicode-segment": [] + }, + "features2": { + "arbitrary": ["dep:arbitrary"] + }, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-06-09T15:00:25Z", + "v": 2 + } + ] + }, + { + "path": "re/gi/region", + "header": "AwIAAABldGFnOiAiNTI1YjUyNGQ3YzMyM2Y2MTQwY2M5OGJlZjk2YTc3MTciAA==", + "records": [ + { + "name": "region", + "vers": "3.0.2", + "deps": [ + { + "name": "bitflags", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.153", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "mach2", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(target_os = \"macos\", target_os = \"ios\"))", + "kind": "normal" + }, + { + "name": "mmap", + "req": "^0.1.6", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "dev", + "package": "mmap-fixed" + }, + { + "name": "windows-sys", + "req": "^0.52.0", + "features": [ + "Win32_Foundation", + "Win32_System_Memory", + "Win32_System_SystemInformation", + "Win32_System_Diagnostics_Debug" + ], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7", + "features": {}, + "yanked": false, + "pubtime": "2024-03-25T08:23:23Z" + } + ] + }, + { + "path": "re/nd/rend", + "header": "AwIAAABldGFnOiAiYmMzNDE5MjRkMDVkODBhNGE5NTJjZDU2OThjODZhMGMiAA==", + "records": [ + { + "name": "rend", + "vers": "0.5.4", + "deps": [ + { + "name": "bytecheck", + "req": "^0.8", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "bytemuck-1", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "bytemuck" + }, + { + "name": "zerocopy", + "req": "^0.8", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerocopy-derive", + "req": "^0.8", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "663ba70707f96e871406fe10d68128412e619b06d1d47cb91c3a4c6501176240", + "features": { + "default": [] + }, + "features2": { + "zerocopy-0_8": ["dep:zerocopy", "dep:zerocopy-derive"] + }, + "yanked": false, + "pubtime": "2026-07-02T19:29:05Z", + "v": 2 + } + ] + }, + { + "path": "re/pl/replace_with", + "header": "AwIAAABldGFnOiAiYWFmMDdlMmMzNjFiNTY4N2FkMDE3MGM0M2U2YTE1NjkiAA==", + "records": [ + { + "name": "replace_with", + "vers": "0.1.8", + "deps": [], + "cksum": "51743d3e274e2b18df81c4dc6caf8a5b8e15dbe799e0dca05c7617380094e884", + "features": { + "default": ["std"], + "nightly": [], + "panic_abort": [], + "std": [] + }, + "yanked": false, + "pubtime": "2025-05-20T16:43:43Z" + } + ] + }, + { + "path": "rk/yv/rkyv", + "header": "AwIAAABldGFnOiAiNzYxOTI2ZWMwZDU1YTdhYjQ5NDIwMjNjZDllMGQwNmIiAA==", + "records": [ + { + "name": "rkyv", + "vers": "0.8.18", + "deps": [ + { + "name": "ahash", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "arrayvec-0_7", + "req": "^0.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "arrayvec" + }, + { + "name": "bytecheck", + "req": "^0.8", + "features": ["simdutf8"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "bytes-1", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "bytes" + }, + { + "name": "divan", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "hashbrown", + "req": "^0.17", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "hashbrown-0_14", + "req": "^0.14", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "hashbrown" + }, + { + "name": "hashbrown-0_15", + "req": "^0.15", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "hashbrown" + }, + { + "name": "hashbrown-0_16", + "req": "^0.16", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "hashbrown" + }, + { + "name": "indexmap-2", + "req": "^2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "indexmap" + }, + { + "name": "munge", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "ptr_meta", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rancor", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rend", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rkyv_derive", + "req": "=0.8.18", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rustversion", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "smallvec-1", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "smallvec" + }, + { + "name": "smol_str-0_2", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "smol_str" + }, + { + "name": "smol_str-0_3", + "req": "^0.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "smol_str" + }, + { + "name": "thin-vec-0_2", + "req": "^0.2.12", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "thin-vec" + }, + { + "name": "tinyvec-1", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "tinyvec" + }, + { + "name": "triomphe-0_1", + "req": "^0.1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "triomphe" + }, + { + "name": "trybuild", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "uuid-1", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "uuid" + } + ], + "cksum": "d9776093b7ca170454ab1406954f7b7d97a57c51dc6c0642957fb2ef25c2d399", + "features": { + "aligned": [], + "big_endian": [], + "little_endian": [], + "pointer_width_16": [], + "pointer_width_32": [], + "pointer_width_64": [], + "unaligned": [] + }, + "features2": { + "alloc": ["dep:hashbrown", "tinyvec-1?/alloc", "rancor/alloc"], + "bytecheck": ["dep:bytecheck", "rend/bytecheck", "rkyv_derive/bytecheck"], + "default": ["std", "bytecheck"], + "hashbrown-0_17": ["dep:hashbrown"], + "indexmap-2": ["dep:indexmap-2", "alloc"], + "std": ["alloc", "bytes-1?/std", "indexmap-2?/std", "ptr_meta/std", "uuid-1?/std"], + "triomphe-0_1": ["dep:triomphe-0_1", "alloc"], + "uuid-1": ["dep:uuid-1", "bytecheck?/uuid-1"] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-08-05T12:01:41Z", + "v": 2 + } + ] + }, + { + "path": "rk/yv/rkyv_derive", + "header": "AwIAAABldGFnOiAiYjUxMzQ1NTk2ZTZjYzVhNjBhMDk5YjIxMDA0MzdkMjMiAA==", + "records": [ + { + "name": "rkyv_derive", + "vers": "0.8.18", + "deps": [ + { + "name": "proc-macro2", + "req": "^1", + "features": ["proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": ["proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3.0", + "features": ["clone-impls", "derive", "parsing", "printing", "proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "1c25ef604ac7dd839d44d64648952ea23c97866f124ff671b0ed2cf3ad9bb06e", + "features": { + "bytecheck": [], + "default": [] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-08-05T12:01:39Z" + } + ] + }, + { + "path": "ru/st/rustc_version", + "header": "AwIAAABldGFnOiAiMjg2MjAxZDlkNWI0YzdkZDI4Mzc1MzhkM2FmYmIxNDAiAA==", + "records": [ + { + "name": "rustc_version", + "vers": "0.4.1", + "deps": [ + { + "name": "doc-comment", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "semver", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92", + "features": {}, + "yanked": false, + "rust_version": "1.32", + "pubtime": "2024-08-28T09:21:22Z" + } + ] + }, + { + "path": "ru/st/rustc-demangle", + "header": "AwIAAABldGFnOiAiNDc1NDhkYThlMzJkNTE0ZjJlM2E4MGI3YWUzZTU0YmIiAA==", + "records": [ + { + "name": "rustc-demangle", + "vers": "0.1.28", + "deps": [ + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + } + ], + "cksum": "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb", + "features": { + "compiler_builtins": [], + "rustc-dep-of-std": ["core"], + "std": [] + }, + "yanked": false, + "pubtime": "2026-07-08T16:08:22Z" + } + ] + }, + { + "path": "ru/st/rustc-hash", + "header": "AwIAAABldGFnOiAiOWIzNTFlY2MyNGMyYjIxNGVhMjczMzJjYjk3ZWIxNzEiAA==", + "records": [ + { + "name": "rustc-hash", + "vers": "2.1.3", + "deps": [ + { + "name": "rand", + "req": "^0.9", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d", + "features": { + "default": ["std"], + "nightly": [], + "std": [] + }, + "features2": { + "rand": ["dep:rand", "std"] + }, + "yanked": false, + "rust_version": "1.77", + "pubtime": "2026-07-02T19:13:03Z", + "v": 2 + } + ] + }, + { + "path": "ru/st/rustix", + "header": "AwIAAABldGFnOiAiMTRkZDQxMTBiMGY3MDMwNWU2MGU0ZjI2OGIxZDE3NmQiAA==", + "records": [ + { + "name": "rustix", + "vers": "1.1.5", + "deps": [ + { + "name": "bitflags", + "req": "^2.4.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "criterion", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(criterion, not(any(target_os = \"emscripten\", target_os = \"wasi\"))))", + "kind": "dev" + }, + { + "name": "flate2", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "libc", + "req": "^0.2.182", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\")))))))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.182", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(not(rustix_use_libc), not(miri), target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\"))))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.171", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "libc_errno", + "req": "^0.3.10", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(not(windows), any(rustix_use_libc, miri, not(all(target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\")))))))", + "kind": "normal", + "package": "errno" + }, + { + "name": "libc_errno", + "req": "^0.3.10", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(windows)", + "kind": "normal", + "package": "errno" + }, + { + "name": "libc_errno", + "req": "^0.3.10", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(not(rustix_use_libc), not(miri), target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\"))))", + "kind": "normal", + "package": "errno" + }, + { + "name": "libc_errno", + "req": "^0.3.10", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "errno" + }, + { + "name": "linux-raw-sys", + "req": "^0.12", + "features": ["general", "ioctl", "no_std"], + "optional": false, + "default_features": false, + "target": "cfg(all(any(target_os = \"linux\", target_os = \"android\"), any(rustix_use_libc, miri, not(all(target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\")))))))", + "kind": "normal" + }, + { + "name": "linux-raw-sys", + "req": "^0.12", + "features": ["auxvec", "general", "errno", "ioctl", "no_std", "elf"], + "optional": false, + "default_features": false, + "target": "cfg(all(not(rustix_use_libc), not(miri), target_os = \"linux\", any(target_endian = \"little\", any(target_arch = \"s390x\", target_arch = \"powerpc\")), any(target_arch = \"arm\", all(target_arch = \"aarch64\", target_pointer_width = \"64\"), target_arch = \"riscv64\", all(rustix_use_experimental_asm, target_arch = \"powerpc\"), all(rustix_use_experimental_asm, target_arch = \"powerpc64\"), all(rustix_use_experimental_asm, target_arch = \"s390x\"), all(rustix_use_experimental_asm, target_arch = \"mips\"), all(rustix_use_experimental_asm, target_arch = \"mips32r6\"), all(rustix_use_experimental_asm, target_arch = \"mips64\"), all(rustix_use_experimental_asm, target_arch = \"mips64r6\"), target_arch = \"x86\", all(target_arch = \"x86_64\", target_pointer_width = \"64\"))))", + "kind": "normal" + }, + { + "name": "memoffset", + "req": "^0.9.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "once_cell", + "req": "^1.20.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "dev" + }, + { + "name": "rustc-std-workspace-alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serial_test", + "req": "^2.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tempfile", + "req": "^3.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "windows-sys", + "req": ">=0.52, <0.62", + "features": ["Win32_Foundation", "Win32_Networking_WinSock"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d", + "features": { + "all-apis": [ + "event", + "fs", + "io_uring", + "mm", + "mount", + "net", + "param", + "pipe", + "process", + "pty", + "rand", + "runtime", + "shm", + "stdio", + "system", + "termios", + "thread", + "time" + ], + "alloc": [], + "event": [], + "fs": [], + "io_uring": ["event", "fs", "net", "thread", "linux-raw-sys/io_uring"], + "linux_4_11": [], + "linux_5_1": ["linux_4_11"], + "linux_5_11": ["linux_5_1"], + "linux_latest": ["linux_5_11"], + "mm": [], + "mount": [], + "net": [ + "linux-raw-sys/net", + "linux-raw-sys/netlink", + "linux-raw-sys/if_ether", + "linux-raw-sys/xdp" + ], + "param": [], + "pipe": [], + "process": ["linux-raw-sys/prctl"], + "pty": ["fs"], + "rand": [], + "runtime": ["linux-raw-sys/prctl"], + "rustc-dep-of-std": [ + "core", + "rustc-std-workspace-alloc", + "linux-raw-sys/rustc-dep-of-std", + "bitflags/rustc-dep-of-std" + ], + "shm": ["fs"], + "stdio": [], + "system": ["linux-raw-sys/system"], + "termios": [], + "thread": ["linux-raw-sys/prctl"], + "time": [], + "try_close": [], + "use-explicitly-provided-auxv": [], + "use-libc": ["libc_errno", "libc"], + "use-libc-auxv": [] + }, + "features2": { + "default": ["std"], + "std": ["bitflags/std", "alloc", "libc?/std", "libc_errno?/std"] + }, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-09-16T23:05:02Z", + "v": 2 + } + ] + }, + { + "path": "ru/st/rustix-linux-procfs", + "header": "AwIAAABldGFnOiAiNDY3YTc3OWM4MGZhMmY5YzE4NmNiOWRhNmYwOGJhNjYiAA==", + "records": [ + { + "name": "rustix-linux-procfs", + "vers": "0.1.1", + "deps": [ + { + "name": "once_cell", + "req": "^1.5.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustix", + "req": "^1.0.0", + "features": ["alloc", "fs"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rustix", + "req": "^1.0.0", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + } + ], + "cksum": "2fc84bf7e9aa16c4f2c758f27412dc9841341e16aa682d9c7ac308fe3ee12056", + "features": { + "default": ["std"], + "std": ["rustix/std"] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2025-04-21T21:17:44Z" + } + ] + }, + { + "path": "ru/st/rustversion", + "header": "AwIAAABldGFnOiAiZjg5Y2I5ODU1YjYxNzJkN2MyNzFiMzlmOTQ5OTZlYjAiAA==", + "records": [ + { + "name": "rustversion", + "vers": "1.0.23", + "deps": [ + { + "name": "trybuild", + "req": "^1.0.49", + "features": ["diff"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f", + "features": {}, + "yanked": false, + "rust_version": "1.31", + "pubtime": "2026-07-07T02:10:26Z" + } + ] + }, + { + "path": "ru/st/rusty_pool", + "header": "AwIAAABldGFnOiAiNjQ2NGNkNjkyMzM0NGUzNGU3ZjY4ZWJkMmJhNjQ5YTMiAA==", + "records": [ + { + "name": "rusty_pool", + "vers": "0.7.0", + "deps": [ + { + "name": "crossbeam-channel", + "req": "^0.5.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures", + "req": "^0.3.21", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures-channel", + "req": "^0.3.21", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures-executor", + "req": "^0.3.21", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "num_cpus", + "req": "^1.13.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "4ed36cdb20de66d89a17ea04b8883fc7a386f2cf877aaedca5005583ce4876ff", + "features": { + "async": ["futures"], + "default": ["async"] + }, + "yanked": false, + "pubtime": "2022-05-05T22:18:23Z" + } + ] + }, + { + "path": "ru/zs/ruzstd", + "header": "AwIAAABldGFnOiAiYjg2NjY3ZTUxZjRjYTkzNDBjZTE2MDI3ZTM4NzI1N2MiAA==", + "records": [ + { + "name": "ruzstd", + "vers": "0.8.3", + "deps": [ + { + "name": "alloc", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "compiler_builtins", + "req": "^0.1.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "core", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "criterion", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "fastrand", + "req": "^2.3.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.8.5", + "features": ["small_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "twox-hash", + "req": "^2.0", + "features": ["xxhash64"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zstd", + "req": "^0.13.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "a7c1c839d570d835527c9a5e4db7cb2198683a988cb9d7293fc8674e6bd58fc8", + "features": { + "fuzz_exports": [], + "std": [] + }, + "features2": { + "default": ["hash", "std"], + "dict_builder": ["std", "dep:fastrand"], + "hash": ["dep:twox-hash"], + "rustc-dep-of-std": ["dep:compiler_builtins", "dep:core", "dep:alloc"] + }, + "yanked": false, + "rust_version": "1.87", + "pubtime": "2026-05-08T12:35:05Z", + "v": 2 + } + ] + }, + { + "path": "sa/ff/saffron", + "header": "AwIAAABldGFnOiAiNWYyYWU5ZmY2N2VhZmE2ZDg2OTBjNGFlOWEwNzUyMWMiAA==", + "records": [ + { + "name": "saffron", + "vers": "0.1.0", + "deps": [ + { + "name": "chrono", + "req": "^0.4", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "criterion", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "nom", + "req": "^5.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "03fb9a628596fc7590eb7edbf7b0613287be78df107f5f97b118aad59fb2eea9", + "features": { + "default": [], + "std": [] + }, + "yanked": false, + "pubtime": "2021-02-01T21:08:52Z" + } + ] + }, + { + "path": "sa/me/same-file", + "header": "AwIAAABldGFnOiAiNTY3M2NjNjQxOGFjNmJiNTUyOWI5ZjlmNDM3OGJmMDciAA==", + "records": [ + { + "name": "same-file", + "vers": "1.0.6", + "deps": [ + { + "name": "doc-comment", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "winapi-util", + "req": "^0.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502", + "features": {}, + "yanked": false, + "pubtime": "2020-01-11T17:02:30Z" + } + ] + }, + { + "path": "sc/he/schemars", + "header": "AwIAAABldGFnOiAiOWM5M2M1MzdhNWJjZGYxMGM3YjZmZWY4MzhhOTIzZWUiAA==", + "records": [ + { + "name": "schemars", + "vers": "1.2.2", + "deps": [ + { + "name": "arrayvec07", + "req": "^0.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "arrayvec" + }, + { + "name": "arrayvec07", + "req": "^0.7", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "arrayvec" + }, + { + "name": "bigdecimal04", + "req": "^0.4", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "bigdecimal" + }, + { + "name": "bigdecimal04", + "req": "^0.4", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "bigdecimal" + }, + { + "name": "bytes1", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "bytes" + }, + { + "name": "bytes1", + "req": "^1.0", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "bytes" + }, + { + "name": "chrono04", + "req": "^0.4.39", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "chrono" + }, + { + "name": "chrono04", + "req": "^0.4", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "chrono" + }, + { + "name": "dyn-clone", + "req": "^1.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "either1", + "req": "^1.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "either" + }, + { + "name": "either1", + "req": "^1.3", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "either" + }, + { + "name": "garde", + "req": "^0.23", + "features": ["derive", "email", "regex", "url"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "indexmap2", + "req": "^2.2.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "indexmap" + }, + { + "name": "indexmap2", + "req": "^2.0", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "indexmap" + }, + { + "name": "jiff02", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "jiff" + }, + { + "name": "jiff02", + "req": "^0.2", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "jiff" + }, + { + "name": "jsonschema", + "req": "^0.30", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "pretty_assertions", + "req": "^1.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ref-cast", + "req": "^1.0.22", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "regex", + "req": "^1.10.6", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rust_decimal1", + "req": "^1.13", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "rust_decimal" + }, + { + "name": "rust_decimal1", + "req": "^1", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "rust_decimal" + }, + { + "name": "schemars_derive", + "req": "=1.2.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "semver1", + "req": "^1.0.9", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "semver" + }, + { + "name": "semver1", + "req": "^1.0.9", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "semver" + }, + { + "name": "serde", + "req": "^1.0.194", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0.127", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_repr", + "req": "^0.1.19", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "smallvec1", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "smallvec" + }, + { + "name": "smallvec1", + "req": "^1.0", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "smallvec" + }, + { + "name": "smol_str02", + "req": "^0.2.1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "smol_str" + }, + { + "name": "smol_str02", + "req": "^0.2.1", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "smol_str" + }, + { + "name": "smol_str03", + "req": "^0.3.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "smol_str" + }, + { + "name": "smol_str03", + "req": "^0.3.2", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "smol_str" + }, + { + "name": "snapbox", + "req": "^0.6.17", + "features": ["json"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "url2", + "req": "^2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "url" + }, + { + "name": "url2", + "req": "^2.0", + "features": ["serde", "std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "url" + }, + { + "name": "uuid1", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "uuid" + }, + { + "name": "uuid1", + "req": "^1.0", + "features": ["serde"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "uuid" + }, + { + "name": "validator", + "req": "^0.21", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a", + "features": { + "_ui_test": [], + "default": ["derive", "std"], + "derive": ["schemars_derive"], + "preserve_order": ["serde_json/preserve_order"], + "raw_value": ["serde_json/raw_value"], + "std": [] + }, + "yanked": false, + "rust_version": "1.74", + "pubtime": "2026-07-27T14:35:28Z" + } + ] + }, + { + "path": "sc/he/schemars_derive", + "header": "AwIAAABldGFnOiAiNmY2MTQwNzM3MDc4MWNlN2ZlNzAwMWUyNjZjYjAyZTciAA==", + "records": [ + { + "name": "schemars_derive", + "vers": "1.2.2", + "deps": [ + { + "name": "pretty_assertions", + "req": "^1.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1.0.91", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.35", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive_internals", + "req": "^0.30.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3", + "features": ["extra-traits"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "d98c67716b46af2f0b8cf752abc930f6f9aecfbf671ecfb531db8a31dbe4e2ba", + "features": {}, + "yanked": false, + "rust_version": "1.74", + "pubtime": "2026-07-27T14:35:25Z" + } + ] + }, + { + "path": "sc/op/scopeguard", + "header": "AwIAAABldGFnOiAiZGFhOTM4MDg0ZjI1ZjhhNjkzYWU4ZjE0YThmYWQwZDMiAA==", + "records": [ + { + "name": "scopeguard", + "vers": "1.2.0", + "deps": [], + "cksum": "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49", + "features": { + "default": ["use_std"], + "use_std": [] + }, + "yanked": false, + "pubtime": "2023-07-17T13:47:53Z" + } + ] + }, + { + "path": "se/lf/self_cell", + "header": "AwIAAABldGFnOiAiYjUxMjJjOTU2YTQzMTU5OTc1Yjk4YmE3NGU1NzMwMzkiAA==", + "records": [ + { + "name": "self_cell", + "vers": "1.3.0", + "deps": [ + { + "name": "once_cell", + "req": "=1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": ">=1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "2ab42ca02749e120097e328d91d415325bdf43b1c72c4c8badf37375fe40a813", + "features": { + "old_rust": ["rustversion"] + }, + "yanked": false, + "pubtime": "2026-07-16T07:47:15Z" + } + ] + }, + { + "path": "se/mv/semver", + "header": "AwIAAABldGFnOiAiZmIyNTA5YTJhYWIyYjJmOGM3Nzk3YWMxZDA3M2UxMWMiAA==", + "records": [ + { + "name": "semver", + "vers": "1.0.28", + "deps": [ + { + "name": "criterion", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "serde_core" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(any())", + "kind": "normal" + } + ], + "cksum": "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd", + "features": { + "default": ["std"], + "std": [] + }, + "features2": { + "serde": ["dep:serde"] + }, + "yanked": false, + "rust_version": "1.68", + "pubtime": "2026-04-04T00:25:14Z", + "v": 2 + } + ] + }, + { + "path": "se/rd/serde", + "header": "AwIAAABldGFnOiAiOTcxZTFhNzFkN2Q2YWZiZmM5MGEyM2FkOTE5MzExMDMiAA==", + "records": [ + { + "name": "serde", + "vers": "1.0.229", + "deps": [ + { + "name": "serde_core", + "req": "=1.0.229", + "features": ["result"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba", + "features": { + "alloc": ["serde_core/alloc"], + "default": ["std"], + "derive": ["serde_derive"], + "rc": ["serde_core/rc"], + "std": ["serde_core/std"], + "unstable": ["serde_core/unstable"] + }, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2026-07-18T23:05:13Z" + } + ] + }, + { + "path": "se/rd/serde_core", + "header": "AwIAAABldGFnOiAiMDY3N2FlODQ2MzcwZWVmNTdkMDBkYjRhZjdhYjM5ZmMiAA==", + "records": [ + { + "name": "serde_core", + "vers": "1.0.229", + "deps": [ + { + "name": "serde", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_derive", + "req": "=1.0.229", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any())", + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48", + "features": { + "alloc": [], + "default": ["std", "result"], + "rc": [], + "result": [], + "std": [], + "unstable": [] + }, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2026-07-18T23:05:10Z" + } + ] + }, + { + "path": "se/rd/serde_derive", + "header": "AwIAAABldGFnOiAiOWM3YjkyYmFjZWE4YmNhMTdlZTI2MzBiNjQyZjA2ZTUiAA==", + "records": [ + { + "name": "serde_derive", + "vers": "1.0.229", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.74", + "features": ["proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.35", + "features": ["proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn", + "req": "^3", + "features": ["clone-impls", "derive", "parsing", "printing", "proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348", + "features": { + "default": [], + "deserialize_in_place": [] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-18T23:05:07Z" + } + ] + }, + { + "path": "se/rd/serde_derive_internals", + "header": "AwIAAABldGFnOiAiOWVhMDIxMDdlMWE2OTI4ZDMxMTlhZjhkYTgxZDlmNTgiAA==", + "records": [ + { + "name": "serde_derive_internals", + "vers": "0.30.0", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.74", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.35", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3", + "features": ["clone-impls", "derive", "parsing", "printing"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "f852137cce035d6a4df67ccce505ff6b3e9fd3a10e3e52b24dc71e650bb1a9bd", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-25T14:58:00Z" + } + ] + }, + { + "path": "se/rd/serde_json", + "header": "AwIAAABldGFnOiAiN2Y1OTcyOGUwYjFkMWRhZTkwYjgxZjA0ZjQwMmNhOWYiAA==", + "records": [ + { + "name": "serde_json", + "vers": "1.0.154", + "deps": [ + { + "name": "automod", + "req": "^1.0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "foldhash", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2.2.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "indoc", + "req": "^2.0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "itoa", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memchr", + "req": "^2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "ref-cast", + "req": "^1.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0.13", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(any())", + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.194", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_bytes", + "req": "^0.11.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.220", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1.0.166", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_stacker", + "req": "^0.1.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.108", + "features": ["diff"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "zmij", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6", + "features": { + "alloc": ["serde_core/alloc"], + "arbitrary_precision": [], + "default": ["std"], + "float_roundtrip": [], + "raw_value": [], + "std": ["memchr/std", "serde_core/std"], + "unbounded_depth": [] + }, + "features2": { + "preserve_order": ["indexmap", "alloc", "dep:foldhash"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-10-11T15:31:46Z", + "v": 2 + } + ] + }, + { + "path": "se/rd/serde_spanned", + "header": "AwIAAABldGFnOiAiY2EyZmZlMWQ1MTMxMGU2MmU3YWQ0ODdkOGJjMTgzNWEiAA==", + "records": [ + { + "name": "serde_spanned", + "vers": "1.1.2", + "deps": [ + { + "name": "serde", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde-untagged", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.228", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "4e7523beb55eece201a2356bee0bbca0d1ab466c14c07703b2e0ee6d42cb0c2c", + "features": {}, + "features2": { + "alloc": ["serde_core?/alloc"], + "default": ["std", "serde"], + "serde": ["dep:serde_core"], + "std": ["alloc", "serde_core?/std"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-10-08T00:54:02Z", + "v": 2 + } + ] + }, + { + "path": "se/rd/serde_yaml", + "header": "AwIAAABldGFnOiAiZDUzOWZkYjQ4YjU5MmZhZmFmZDQwMDJkYmY0Yzk3ZGEiAA==", + "records": [ + { + "name": "serde_yaml", + "vers": "0.9.34+deprecated", + "deps": [ + { + "name": "anyhow", + "req": "^1.0.79", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "indexmap", + "req": "^2.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "indoc", + "req": "^2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "itoa", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ryu", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.195", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1.0.195", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unsafe-libyaml", + "req": "^0.2.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47", + "features": {}, + "yanked": false, + "rust_version": "1.64", + "pubtime": "2024-03-25T00:50:19Z" + } + ] + }, + { + "path": "se/rd/serde-wasm-bindgen", + "header": "AwIAAABldGFnOiAiZGUzODEwMDkxYmM0YWEyMjViYjI3NjUwNTVjNGQyZWQiAA==", + "records": [ + { + "name": "serde-wasm-bindgen", + "vers": "0.6.5", + "deps": [ + { + "name": "bincode", + "req": "^1.3.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "getrandom", + "req": "^0.2", + "features": ["js"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "js-sys", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "maplit", + "req": "^1.0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proptest", + "req": "^1.0", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.193", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_bytes", + "req": "^0.11.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0.39", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "wasm-bindgen", + "req": "^0.2.83", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3.24", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b", + "features": {}, + "yanked": false, + "pubtime": "2024-02-27T21:32:21Z" + } + ] + }, + { + "path": "sh/a2/sha2", + "header": "AwIAAABldGFnOiAiZWYwMzI4MTFlOTZmMThhNWEzZjQ3NTkwNDRmM2NlZmMiAA==", + "records": [ + { + "name": "sha2", + "vers": "0.10.9", + "deps": [ + { + "name": "cfg-if", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cpufeatures", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))", + "kind": "normal" + }, + { + "name": "digest", + "req": "^0.10.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "digest", + "req": "^0.10.7", + "features": ["dev"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hex-literal", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "sha2-asm", + "req": "^0.6.1", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))", + "kind": "normal" + } + ], + "cksum": "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283", + "features": { + "asm": ["sha2-asm"], + "asm-aarch64": ["asm"], + "compress": [], + "default": ["std"], + "force-soft": [], + "force-soft-compact": [], + "loongarch64_asm": [], + "oid": ["digest/oid"], + "std": ["digest/std"] + }, + "yanked": false, + "pubtime": "2025-04-30T14:38:09Z" + }, + { + "name": "sha2", + "vers": "0.11.0", + "deps": [ + { + "name": "cfg-if", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cpufeatures", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(target_arch = \"aarch64\", target_arch = \"x86_64\", target_arch = \"x86\"))", + "kind": "normal" + }, + { + "name": "digest", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "digest", + "req": "^0.11", + "features": ["dev"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hex-literal", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4", + "features": { + "alloc": ["digest/alloc"], + "default": ["alloc", "oid"], + "oid": ["digest/oid"], + "zeroize": ["digest/zeroize"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-03-25T15:05:27Z" + } + ] + }, + { + "path": "sh/ar/shared-buffer", + "header": "AwIAAABldGFnOiAiNTk0MTE5ZDY5ZjUyYTc5NzJjZDk5MWMxYmFkMzU5ZDciAA==", + "records": [ + { + "name": "shared-buffer", + "vers": "0.1.4", + "deps": [ + { + "name": "bytes", + "req": "^1.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memmap2", + "req": "^0.6.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "f6c99835bad52957e7aa241d3975ed17c1e5f8c92026377d117a606f36b84b16", + "features": {}, + "yanked": false, + "rust_version": "1.64.0", + "pubtime": "2023-12-14T15:44:28Z" + } + ] + }, + { + "path": "sh/le/shlex", + "header": "AwIAAABldGFnOiAiMzU1MWFhZTM0MTRhOWUyYWY2MDhkNTU1NzkzNzg0NWEiAA==", + "records": [ + { + "name": "shlex", + "vers": "1.3.0", + "deps": [], + "cksum": "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.46.0", + "pubtime": "2024-01-22T05:15:15Z" + }, + { + "name": "shlex", + "vers": "2.0.1", + "deps": [], + "cksum": "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.46.0", + "pubtime": "2026-05-17T18:56:12Z" + } + ] + }, + { + "path": "si/md/simd-adler32", + "header": "AwIAAABldGFnOiAiOTdkYjJkZDI3ZmJkNGNkMDM3ZjUyMjhkZDcwMTg2NzQiAA==", + "records": [ + { + "name": "simd-adler32", + "vers": "0.3.10", + "deps": [ + { + "name": "adler2", + "req": "^2.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "adler32", + "req": "^1.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.8", + "features": ["small_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea", + "features": { + "const-generics": [], + "default": ["std", "const-generics"], + "nightly": [], + "std": [] + }, + "yanked": false, + "pubtime": "2026-07-14T17:42:45Z" + } + ] + }, + { + "path": "si/md/simdutf8", + "header": "AwIAAABldGFnOiAiODIxMTY4ZmFlN2U2ZDI2NTU1YmI2MTJjMWI4ZTA0YmUiAA==", + "records": [ + { + "name": "simdutf8", + "vers": "0.1.5", + "deps": [], + "cksum": "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e", + "features": { + "aarch64_neon": [], + "aarch64_neon_prefetch": [], + "default": ["std"], + "hints": [], + "public_imp": [], + "std": [] + }, + "yanked": false, + "pubtime": "2024-09-22T09:18:22Z" + } + ] + }, + { + "path": "si/mi/similar", + "header": "AwIAAABldGFnOiAiYjFhMmIzZmQ1MzZkZWY3MGMyZGJkZWJkMmZlNjRhNzIiAA==", + "records": [ + { + "name": "similar", + "vers": "2.7.0", + "deps": [ + { + "name": "bstr", + "req": "^1.5.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "console", + "req": "^0.15.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "insta", + "req": "^1.10.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.130", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.68", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicode-segmentation", + "req": "^1.7.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "web-time", + "req": "^1.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa", + "features": { + "bytes": ["bstr", "text"], + "default": ["text"], + "inline": ["text"], + "text": [], + "wasm32_web_time": ["web-time"] + }, + "features2": { + "unicode": ["text", "unicode-segmentation", "bstr?/unicode", "bstr?/std"] + }, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-01-19T14:39:11Z", + "v": 2 + } + ] + }, + { + "path": "si/ph/siphasher", + "header": "AwIAAABldGFnOiAiMzJmOWJiMjMxM2EyNTI2MjgzYzFkY2M0ZjE1MDJjYTgiAA==", + "records": [ + { + "name": "siphasher", + "vers": "1.0.4", + "deps": [ + { + "name": "serde", + "req": "^1.0", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "33f4fe9184a62d842c9ef383018f3306d8ba224fd9d836f56d7288308847c256", + "features": { + "default": ["std"], + "serde_no_std": ["serde/alloc"], + "serde_std": ["std", "serde/std"], + "std": [] + }, + "yanked": false, + "pubtime": "2026-09-25T08:51:05Z" + } + ] + }, + { + "path": "sl/ab/slab", + "header": "AwIAAABldGFnOiAiNGU0MDdhZWUyNGYwZGJhYmQyOTdmNzRmZmM5Zjk0ZDIiAA==", + "records": [ + { + "name": "slab", + "vers": "0.4.12", + "deps": [ + { + "name": "serde", + "req": "^1.0.95", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_test", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.51", + "pubtime": "2026-01-31T12:59:22Z" + } + ] + }, + { + "path": "sm/al/smallvec", + "header": "AwIAAABldGFnOiAiNmMwOGM2NWY5MjQzODI5NGI2YjQ3NjNkOTMyYjE0NDMiAA==", + "records": [ + { + "name": "smallvec", + "vers": "1.16.3", + "deps": [ + { + "name": "arbitrary", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bincode", + "req": "^2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "bincode1", + "req": "^1.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "bincode" + }, + { + "name": "malloc_size_of", + "req": "^0.1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "unty", + "req": "^0.0.4", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "5b3dc8af474f516a851ff4bd12db780f948b9250ad37211e4eec0bccea54e01b", + "features": { + "const_generics": [], + "const_new": ["const_generics"], + "drain_filter": [], + "drain_keep_rest": ["drain_filter"], + "impl_bincode": ["bincode", "unty"], + "may_dangle": [], + "specialization": [], + "union": [], + "write": [] + }, + "yanked": false, + "pubtime": "2026-10-10T02:25:27Z" + } + ] + }, + { + "path": "sm/ol/smoltcp", + "header": "AwIAAABldGFnOiAiYWI2OGFiYjk1NTUxZmVlN2QwNmFjZTI5OTU3MzgyYzciAA==", + "records": [ + { + "name": "smoltcp", + "vers": "0.13.1", + "deps": [ + { + "name": "bitflags", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "byteorder", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "defmt", + "req": "^0.3.8", + "features": ["ip_in_core"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "env_logger", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "getopts", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "heapless", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "idna", + "req": "=1.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "insta", + "req": "^1.41.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "libc", + "req": "^0.2.18", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "log", + "req": "^0.4.4", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "managed", + "req": "^0.8", + "features": ["map"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand_chacha", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rstest", + "req": "^0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "url", + "req": "^2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "5f73d40463bba65efc9adc6370b56df76d563cc46e2482bba58351b4afb7535e", + "features": { + "_netsim": [], + "_proto-fragmentation": [], + "assembler-max-segment-count-1": [], + "assembler-max-segment-count-16": [], + "assembler-max-segment-count-2": [], + "assembler-max-segment-count-3": [], + "assembler-max-segment-count-32": [], + "assembler-max-segment-count-4": [], + "assembler-max-segment-count-8": [], + "async": [], + "auto-icmp-echo-reply": [], + "dns-max-name-size-128": [], + "dns-max-name-size-255": [], + "dns-max-name-size-64": [], + "dns-max-result-count-1": [], + "dns-max-result-count-16": [], + "dns-max-result-count-2": [], + "dns-max-result-count-3": [], + "dns-max-result-count-32": [], + "dns-max-result-count-4": [], + "dns-max-result-count-8": [], + "dns-max-server-count-1": [], + "dns-max-server-count-16": [], + "dns-max-server-count-2": [], + "dns-max-server-count-3": [], + "dns-max-server-count-32": [], + "dns-max-server-count-4": [], + "dns-max-server-count-8": [], + "fragmentation-buffer-size-1024": [], + "fragmentation-buffer-size-1500": [], + "fragmentation-buffer-size-16384": [], + "fragmentation-buffer-size-2048": [], + "fragmentation-buffer-size-256": [], + "fragmentation-buffer-size-32768": [], + "fragmentation-buffer-size-4096": [], + "fragmentation-buffer-size-512": [], + "fragmentation-buffer-size-65536": [], + "fragmentation-buffer-size-8192": [], + "iface-max-addr-count-1": [], + "iface-max-addr-count-2": [], + "iface-max-addr-count-3": [], + "iface-max-addr-count-4": [], + "iface-max-addr-count-5": [], + "iface-max-addr-count-6": [], + "iface-max-addr-count-7": [], + "iface-max-addr-count-8": [], + "iface-max-multicast-group-count-1": [], + "iface-max-multicast-group-count-1024": [], + "iface-max-multicast-group-count-128": [], + "iface-max-multicast-group-count-16": [], + "iface-max-multicast-group-count-2": [], + "iface-max-multicast-group-count-256": [], + "iface-max-multicast-group-count-3": [], + "iface-max-multicast-group-count-32": [], + "iface-max-multicast-group-count-4": [], + "iface-max-multicast-group-count-5": [], + "iface-max-multicast-group-count-512": [], + "iface-max-multicast-group-count-6": [], + "iface-max-multicast-group-count-64": [], + "iface-max-multicast-group-count-7": [], + "iface-max-multicast-group-count-8": [], + "iface-max-prefix-count-1": [], + "iface-max-prefix-count-2": [], + "iface-max-prefix-count-3": [], + "iface-max-prefix-count-4": [], + "iface-max-prefix-count-5": [], + "iface-max-prefix-count-6": [], + "iface-max-prefix-count-7": [], + "iface-max-prefix-count-8": [], + "iface-max-route-count-0": [], + "iface-max-route-count-1": [], + "iface-max-route-count-1024": [], + "iface-max-route-count-128": [], + "iface-max-route-count-16": [], + "iface-max-route-count-2": [], + "iface-max-route-count-256": [], + "iface-max-route-count-3": [], + "iface-max-route-count-32": [], + "iface-max-route-count-4": [], + "iface-max-route-count-5": [], + "iface-max-route-count-512": [], + "iface-max-route-count-6": [], + "iface-max-route-count-64": [], + "iface-max-route-count-7": [], + "iface-max-route-count-8": [], + "iface-max-sixlowpan-address-context-count-1": [], + "iface-max-sixlowpan-address-context-count-1024": [], + "iface-max-sixlowpan-address-context-count-128": [], + "iface-max-sixlowpan-address-context-count-16": [], + "iface-max-sixlowpan-address-context-count-2": [], + "iface-max-sixlowpan-address-context-count-256": [], + "iface-max-sixlowpan-address-context-count-3": [], + "iface-max-sixlowpan-address-context-count-32": [], + "iface-max-sixlowpan-address-context-count-4": [], + "iface-max-sixlowpan-address-context-count-5": [], + "iface-max-sixlowpan-address-context-count-512": [], + "iface-max-sixlowpan-address-context-count-6": [], + "iface-max-sixlowpan-address-context-count-64": [], + "iface-max-sixlowpan-address-context-count-7": [], + "iface-max-sixlowpan-address-context-count-8": [], + "iface-neighbor-cache-count-1": [], + "iface-neighbor-cache-count-1024": [], + "iface-neighbor-cache-count-128": [], + "iface-neighbor-cache-count-16": [], + "iface-neighbor-cache-count-2": [], + "iface-neighbor-cache-count-256": [], + "iface-neighbor-cache-count-3": [], + "iface-neighbor-cache-count-32": [], + "iface-neighbor-cache-count-4": [], + "iface-neighbor-cache-count-5": [], + "iface-neighbor-cache-count-512": [], + "iface-neighbor-cache-count-6": [], + "iface-neighbor-cache-count-64": [], + "iface-neighbor-cache-count-7": [], + "iface-neighbor-cache-count-8": [], + "ipv6-hbh-max-options-1": [], + "ipv6-hbh-max-options-16": [], + "ipv6-hbh-max-options-2": [], + "ipv6-hbh-max-options-3": [], + "ipv6-hbh-max-options-32": [], + "ipv6-hbh-max-options-4": [], + "ipv6-hbh-max-options-8": [], + "medium-ethernet": ["socket"], + "medium-ieee802154": ["socket", "proto-sixlowpan"], + "medium-ip": ["socket"], + "multicast": [], + "packetmeta-id": [], + "proto-dhcpv4": ["proto-ipv4"], + "proto-dns": [], + "proto-ipsec": ["proto-ipsec-ah", "proto-ipsec-esp"], + "proto-ipsec-ah": [], + "proto-ipsec-esp": [], + "proto-ipv4": [], + "proto-ipv4-fragmentation": ["proto-ipv4", "_proto-fragmentation"], + "proto-ipv6": [], + "proto-ipv6-fragmentation": ["proto-ipv6", "_proto-fragmentation"], + "proto-ipv6-hbh": ["proto-ipv6"], + "proto-ipv6-routing": ["proto-ipv6"], + "proto-ipv6-slaac": ["proto-ipv6"], + "proto-rpl": ["proto-ipv6-hbh", "proto-ipv6-routing"], + "proto-sixlowpan": ["proto-ipv6"], + "proto-sixlowpan-fragmentation": ["proto-sixlowpan", "_proto-fragmentation"], + "reassembly-buffer-count-1": [], + "reassembly-buffer-count-16": [], + "reassembly-buffer-count-2": [], + "reassembly-buffer-count-3": [], + "reassembly-buffer-count-32": [], + "reassembly-buffer-count-4": [], + "reassembly-buffer-count-8": [], + "reassembly-buffer-size-1024": [], + "reassembly-buffer-size-1500": [], + "reassembly-buffer-size-16384": [], + "reassembly-buffer-size-2048": [], + "reassembly-buffer-size-256": [], + "reassembly-buffer-size-32768": [], + "reassembly-buffer-size-4096": [], + "reassembly-buffer-size-512": [], + "reassembly-buffer-size-65536": [], + "reassembly-buffer-size-8192": [], + "rpl-parents-buffer-count-16": [], + "rpl-parents-buffer-count-2": [], + "rpl-parents-buffer-count-32": [], + "rpl-parents-buffer-count-4": [], + "rpl-parents-buffer-count-8": [], + "rpl-relations-buffer-count-1": [], + "rpl-relations-buffer-count-128": [], + "rpl-relations-buffer-count-16": [], + "rpl-relations-buffer-count-2": [], + "rpl-relations-buffer-count-32": [], + "rpl-relations-buffer-count-4": [], + "rpl-relations-buffer-count-64": [], + "rpl-relations-buffer-count-8": [], + "socket": [], + "socket-dhcpv4": ["socket", "medium-ethernet", "proto-dhcpv4"], + "socket-dns": ["socket", "proto-dns"], + "socket-icmp": ["socket"], + "socket-mdns": ["socket-dns"], + "socket-raw": ["socket"], + "socket-tcp": ["socket"], + "socket-tcp-cubic": [], + "socket-tcp-pause-synack": ["socket-tcp"], + "socket-tcp-reno": [], + "socket-udp": ["socket"], + "verbose": [] + }, + "features2": { + "alloc": ["managed/alloc", "defmt?/alloc"], + "default": [ + "std", + "log", + "medium-ethernet", + "medium-ip", + "medium-ieee802154", + "phy-raw_socket", + "phy-tuntap_interface", + "proto-ipv4", + "proto-dhcpv4", + "proto-ipv6", + "proto-ipv6-slaac", + "proto-dns", + "proto-ipv4-fragmentation", + "proto-sixlowpan-fragmentation", + "socket-raw", + "socket-icmp", + "socket-udp", + "socket-tcp", + "socket-dhcpv4", + "socket-dns", + "socket-mdns", + "packetmeta-id", + "async", + "multicast", + "auto-icmp-echo-reply" + ], + "defmt": ["dep:defmt", "heapless/defmt"], + "phy-raw_socket": ["std", "libc"], + "phy-tuntap_interface": ["std", "libc"], + "std": ["managed/std", "alloc"] + }, + "yanked": false, + "rust_version": "1.91", + "pubtime": "2026-04-30T22:36:03Z", + "v": 2 + } + ] + }, + { + "path": "so/ck/socket2", + "header": "AwIAAABldGFnOiAiMGM1ZWRlYWRhNjJiZTk2N2M4YTNiMjljYWI4NzE4ZjMiAA==", + "records": [ + { + "name": "socket2", + "vers": "0.6.5", + "deps": [ + { + "name": "libc", + "req": "^0.2.172", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(unix, target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.60, <0.62", + "features": [ + "Win32_Foundation", + "Win32_Networking_WinSock", + "Win32_System_IO", + "Win32_System_Threading", + "Win32_System_WindowsProgramming" + ], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4", + "features": { + "all": [] + }, + "yanked": false, + "rust_version": "1.70", + "pubtime": "2026-07-13T19:45:58Z" + } + ] + }, + { + "path": "sq/lx/sqlx", + "header": "AwIAAABldGFnOiAiNDdmMzIxOGE3YzRlMGM2ODNmZGM3ZTlhYTZkZDg2ZTkiAA==", + "records": [ + { + "name": "sqlx", + "vers": "0.8.6", + "deps": [ + { + "name": "anyhow", + "req": "^1.0.52", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "async-std", + "req": "^1.12", + "features": ["attributes"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.5.1", + "features": ["async_tokio"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "dotenvy", + "req": "^0.15.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "env_logger", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "futures", + "req": "^0.3.19", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hex", + "req": "^0.4.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "libsqlite3-sys", + "req": "^0.30.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "libsqlite3-sys", + "req": "^0.30.1", + "features": ["bundled-sqlcipher"], + "optional": false, + "default_features": true, + "target": "cfg(sqlite_test_sqlcipher)", + "kind": "dev" + }, + { + "name": "paste", + "req": "^1.0.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.8.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand_xoshiro", + "req": "^0.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.132", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0.73", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "sqlx-core", + "req": "=0.8.6", + "features": ["offline", "migrate"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sqlx-macros", + "req": "=0.8.6", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sqlx-mysql", + "req": "=0.8.6", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sqlx-postgres", + "req": "=0.8.6", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sqlx-sqlite", + "req": "=0.8.6", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.10.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "time_", + "req": "^0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "time" + }, + { + "name": "tokio", + "req": "^1.15.0", + "features": ["full"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.53", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "url", + "req": "^2.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc", + "features": { + "_rt-async-std": [], + "_rt-tokio": [], + "_sqlite": [], + "bstr": ["sqlx-core/bstr"], + "derive": ["sqlx-macros/derive"], + "macros": ["derive", "sqlx-macros/macros"], + "sqlite-preupdate-hook": ["sqlx-sqlite/preupdate-hook"], + "tls-none": [] + }, + "features2": { + "_unstable-all-types": [ + "bigdecimal", + "rust_decimal", + "json", + "time", + "chrono", + "ipnet", + "ipnetwork", + "mac_address", + "uuid", + "bit-vec", + "bstr" + ], + "all-databases": ["mysql", "sqlite", "postgres", "any"], + "any": ["sqlx-core/any", "sqlx-mysql?/any", "sqlx-postgres?/any", "sqlx-sqlite?/any"], + "bigdecimal": [ + "sqlx-core/bigdecimal", + "sqlx-macros?/bigdecimal", + "sqlx-mysql?/bigdecimal", + "sqlx-postgres?/bigdecimal" + ], + "bit-vec": ["sqlx-core/bit-vec", "sqlx-macros?/bit-vec", "sqlx-postgres?/bit-vec"], + "chrono": [ + "sqlx-core/chrono", + "sqlx-macros?/chrono", + "sqlx-mysql?/chrono", + "sqlx-postgres?/chrono", + "sqlx-sqlite?/chrono" + ], + "default": ["any", "macros", "migrate", "json"], + "ipnet": ["sqlx-core/ipnet", "sqlx-macros?/ipnet", "sqlx-postgres?/ipnet"], + "ipnetwork": [ + "sqlx-core/ipnetwork", + "sqlx-macros?/ipnetwork", + "sqlx-postgres?/ipnetwork" + ], + "json": [ + "sqlx-core/json", + "sqlx-macros?/json", + "sqlx-mysql?/json", + "sqlx-postgres?/json", + "sqlx-sqlite?/json" + ], + "mac_address": [ + "sqlx-core/mac_address", + "sqlx-macros?/mac_address", + "sqlx-postgres?/mac_address" + ], + "migrate": [ + "sqlx-core/migrate", + "sqlx-macros?/migrate", + "sqlx-mysql?/migrate", + "sqlx-postgres?/migrate", + "sqlx-sqlite?/migrate" + ], + "mysql": ["sqlx-mysql", "sqlx-macros?/mysql"], + "postgres": ["sqlx-postgres", "sqlx-macros?/postgres"], + "regexp": ["sqlx-sqlite?/regexp"], + "runtime-async-std": [ + "_rt-async-std", + "sqlx-core/_rt-async-std", + "sqlx-macros?/_rt-async-std" + ], + "runtime-async-std-native-tls": ["runtime-async-std", "tls-native-tls"], + "runtime-async-std-rustls": ["runtime-async-std", "tls-rustls-ring"], + "runtime-tokio": ["_rt-tokio", "sqlx-core/_rt-tokio", "sqlx-macros?/_rt-tokio"], + "runtime-tokio-native-tls": ["runtime-tokio", "tls-native-tls"], + "runtime-tokio-rustls": ["runtime-tokio", "tls-rustls-ring"], + "rust_decimal": [ + "sqlx-core/rust_decimal", + "sqlx-macros?/rust_decimal", + "sqlx-mysql?/rust_decimal", + "sqlx-postgres?/rust_decimal" + ], + "sqlite": ["_sqlite", "sqlx-sqlite/bundled", "sqlx-macros?/sqlite"], + "sqlite-unbundled": [ + "_sqlite", + "sqlx-sqlite/unbundled", + "sqlx-macros?/sqlite-unbundled" + ], + "time": [ + "sqlx-core/time", + "sqlx-macros?/time", + "sqlx-mysql?/time", + "sqlx-postgres?/time", + "sqlx-sqlite?/time" + ], + "tls-native-tls": ["sqlx-core/_tls-native-tls", "sqlx-macros?/_tls-native-tls"], + "tls-rustls": ["tls-rustls-ring"], + "tls-rustls-aws-lc-rs": [ + "sqlx-core/_tls-rustls-aws-lc-rs", + "sqlx-macros?/_tls-rustls-aws-lc-rs" + ], + "tls-rustls-ring": ["tls-rustls-ring-webpki"], + "tls-rustls-ring-native-roots": [ + "sqlx-core/_tls-rustls-ring-native-roots", + "sqlx-macros?/_tls-rustls-ring-native-roots" + ], + "tls-rustls-ring-webpki": [ + "sqlx-core/_tls-rustls-ring-webpki", + "sqlx-macros?/_tls-rustls-ring-webpki" + ], + "uuid": [ + "sqlx-core/uuid", + "sqlx-macros?/uuid", + "sqlx-mysql?/uuid", + "sqlx-postgres?/uuid", + "sqlx-sqlite?/uuid" + ] + }, + "yanked": false, + "pubtime": "2025-05-19T23:24:26Z", + "v": 2 + } + ] + }, + { + "path": "sq/lx/sqlx-core", + "header": "AwIAAABldGFnOiAiZWU3ZWYwZDg3YjFmMjRjNzA0NDkzMmJkMjRkYTdmYzYiAA==", + "records": [ + { + "name": "sqlx-core", + "vers": "0.8.6", + "deps": [ + { + "name": "async-io", + "req": "^1.9.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "async-std", + "req": "^1.12", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "base64", + "req": "^0.22.0", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "bigdecimal", + "req": "^0.4.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bit-vec", + "req": "^0.6.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bstr", + "req": "^1.0", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "bytes", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "chrono", + "req": "^0.4.34", + "features": ["clock"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "crc", + "req": "^3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "crossbeam-queue", + "req": "^0.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "either", + "req": "^1.6.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "event-listener", + "req": "^5.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures-core", + "req": "^0.3.19", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-intrusive", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures-io", + "req": "^0.3.24", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures-util", + "req": "^0.3.19", + "features": ["alloc", "sink", "io"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "hashbrown", + "req": "^0.15.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hashlink", + "req": "^0.10.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ipnet", + "req": "^2.3.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ipnetwork", + "req": "^0.20.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "log", + "req": "^0.4.18", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "mac_address", + "req": "^1.1.5", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memchr", + "req": "^2.4.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "native-tls", + "req": "^0.2.10", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "once_cell", + "req": "^1.9.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "percent-encoding", + "req": "^2.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "regex", + "req": "^1.5.5", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rust_decimal", + "req": "^1.26.1", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rustls", + "req": "^0.23.15", + "features": ["std", "tls12"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rustls-native-certs", + "req": "^0.8.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.132", + "features": ["derive", "rc"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.73", + "features": ["raw_value"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sha2", + "req": "^0.10.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "smallvec", + "req": "^1.7.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sqlx", + "req": "=0.8.6", + "features": ["postgres", "sqlite", "mysql", "migrate", "macros", "time", "uuid"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "thiserror", + "req": "^2.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "time", + "req": "^0.3.36", + "features": ["formatting", "parsing", "macros"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1", + "features": ["time", "net", "sync", "fs", "io-util", "rt"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1", + "features": ["rt"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-stream", + "req": "^0.1.8", + "features": ["fs"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tracing", + "req": "^0.1.37", + "features": ["log"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "url", + "req": "^2.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "uuid", + "req": "^1.1.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "webpki-roots", + "req": "^0.26", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6", + "features": { + "_rt-async-std": ["async-std", "async-io"], + "_rt-tokio": ["tokio", "tokio-stream"], + "_tls-native-tls": ["native-tls"], + "_tls-none": [], + "_tls-rustls": ["rustls"], + "_tls-rustls-aws-lc-rs": ["_tls-rustls", "rustls/aws-lc-rs", "webpki-roots"], + "_tls-rustls-ring-native-roots": ["_tls-rustls", "rustls/ring", "rustls-native-certs"], + "_tls-rustls-ring-webpki": ["_tls-rustls", "rustls/ring", "webpki-roots"], + "any": [], + "default": [], + "json": ["serde", "serde_json"], + "migrate": ["sha2", "crc"], + "offline": ["serde", "either/serde"] + }, + "yanked": false, + "pubtime": "2025-05-19T23:23:07Z" + } + ] + }, + { + "path": "sq/lx/sqlx-macros", + "header": "AwIAAABldGFnOiAiNGVmYmMxNjlmMjgxM2I1MGU2N2ZhZjliZDhhMTk0ZGQiAA==", + "records": [ + { + "name": "sqlx-macros", + "vers": "0.8.6", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.36", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.26", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "sqlx-core", + "req": "=0.8.6", + "features": ["any"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sqlx-macros-core", + "req": "=0.8.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0.52", + "features": ["parsing", "proc-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d", + "features": { + "_rt-async-std": ["sqlx-macros-core/_rt-async-std"], + "_rt-tokio": ["sqlx-macros-core/_rt-tokio"], + "_tls-native-tls": ["sqlx-macros-core/_tls-native-tls"], + "_tls-rustls-aws-lc-rs": ["sqlx-macros-core/_tls-rustls-aws-lc-rs"], + "_tls-rustls-ring-native-roots": ["sqlx-macros-core/_tls-rustls-ring-native-roots"], + "_tls-rustls-ring-webpki": ["sqlx-macros-core/_tls-rustls-ring-webpki"], + "bigdecimal": ["sqlx-macros-core/bigdecimal"], + "bit-vec": ["sqlx-macros-core/bit-vec"], + "chrono": ["sqlx-macros-core/chrono"], + "default": [], + "derive": ["sqlx-macros-core/derive"], + "ipnet": ["sqlx-macros-core/ipnet"], + "ipnetwork": ["sqlx-macros-core/ipnetwork"], + "json": ["sqlx-macros-core/json"], + "mac_address": ["sqlx-macros-core/mac_address"], + "macros": ["sqlx-macros-core/macros"], + "migrate": ["sqlx-macros-core/migrate"], + "mysql": ["sqlx-macros-core/mysql"], + "postgres": ["sqlx-macros-core/postgres"], + "rust_decimal": ["sqlx-macros-core/rust_decimal"], + "sqlite": ["sqlx-macros-core/sqlite"], + "sqlite-unbundled": ["sqlx-macros-core/sqlite-unbundled"], + "time": ["sqlx-macros-core/time"], + "uuid": ["sqlx-macros-core/uuid"] + }, + "yanked": false, + "pubtime": "2025-05-19T23:23:58Z" + } + ] + }, + { + "path": "sq/lx/sqlx-macros-core", + "header": "AwIAAABldGFnOiAiZWY5MzdlNGY2YzkzZTBhZjNkYThkNjJkM2Q2NGQwNTIiAA==", + "records": [ + { + "name": "sqlx-macros-core", + "vers": "0.8.6", + "deps": [ + { + "name": "async-std", + "req": "^1.12", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "dotenvy", + "req": "^0.15.7", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "either", + "req": "^1.6.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "heck", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hex", + "req": "^0.4.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "once_cell", + "req": "^1.9.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1.0.79", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.26", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.132", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.73", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sha2", + "req": "^0.10.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sqlx-core", + "req": "=0.8.6", + "features": ["offline"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sqlx-mysql", + "req": "=0.8.6", + "features": ["offline", "migrate"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sqlx-postgres", + "req": "=0.8.6", + "features": ["offline", "migrate"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sqlx-sqlite", + "req": "=0.8.6", + "features": ["offline", "migrate"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0.52", + "features": ["full", "derive", "parsing", "printing", "clone-impls"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1", + "features": ["time", "net", "sync", "fs", "io-util", "rt"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "url", + "req": "^2.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b", + "features": { + "_rt-async-std": ["async-std", "sqlx-core/_rt-async-std"], + "_rt-tokio": ["tokio", "sqlx-core/_rt-tokio"], + "_sqlite": [], + "_tls-native-tls": ["sqlx-core/_tls-native-tls"], + "_tls-rustls-aws-lc-rs": ["sqlx-core/_tls-rustls-aws-lc-rs"], + "_tls-rustls-ring-native-roots": ["sqlx-core/_tls-rustls-ring-native-roots"], + "_tls-rustls-ring-webpki": ["sqlx-core/_tls-rustls-ring-webpki"], + "default": [], + "derive": [], + "macros": [], + "migrate": ["sqlx-core/migrate"], + "mysql": ["sqlx-mysql"], + "postgres": ["sqlx-postgres"], + "sqlite": ["_sqlite", "sqlx-sqlite/bundled"], + "sqlite-unbundled": ["_sqlite", "sqlx-sqlite/unbundled"] + }, + "features2": { + "bigdecimal": [ + "sqlx-core/bigdecimal", + "sqlx-mysql?/bigdecimal", + "sqlx-postgres?/bigdecimal" + ], + "bit-vec": ["sqlx-core/bit-vec", "sqlx-postgres?/bit-vec"], + "chrono": [ + "sqlx-core/chrono", + "sqlx-mysql?/chrono", + "sqlx-postgres?/chrono", + "sqlx-sqlite?/chrono" + ], + "ipnet": ["sqlx-core/ipnet", "sqlx-postgres?/ipnet"], + "ipnetwork": ["sqlx-core/ipnetwork", "sqlx-postgres?/ipnetwork"], + "json": [ + "sqlx-core/json", + "sqlx-mysql?/json", + "sqlx-postgres?/json", + "sqlx-sqlite?/json" + ], + "mac_address": ["sqlx-core/mac_address", "sqlx-postgres?/mac_address"], + "rust_decimal": [ + "sqlx-core/rust_decimal", + "sqlx-mysql?/rust_decimal", + "sqlx-postgres?/rust_decimal" + ], + "time": [ + "sqlx-core/time", + "sqlx-mysql?/time", + "sqlx-postgres?/time", + "sqlx-sqlite?/time" + ], + "uuid": [ + "sqlx-core/uuid", + "sqlx-mysql?/uuid", + "sqlx-postgres?/uuid", + "sqlx-sqlite?/uuid" + ] + }, + "yanked": false, + "pubtime": "2025-05-19T23:23:50Z", + "v": 2 + } + ] + }, + { + "path": "sq/lx/sqlx-postgres", + "header": "AwIAAABldGFnOiAiZmM1NmQ3ZDY1ZDAxNDBiMTI4ZTFkMWM4ZTY5M2VjNjYiAA==", + "records": [ + { + "name": "sqlx-postgres", + "vers": "0.8.6", + "deps": [ + { + "name": "atoi", + "req": "^2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "base64", + "req": "^0.22.0", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "bigdecimal", + "req": "^0.4.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bit-vec", + "req": "^0.6.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bitflags", + "req": "^2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "byteorder", + "req": "^1.4.3", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "chrono", + "req": "^0.4.34", + "features": ["std", "clock"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "crc", + "req": "^3.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "dotenvy", + "req": "^0.15.7", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "etcetera", + "req": "^0.8.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_os = \"windows\")", + "kind": "normal" + }, + { + "name": "futures-channel", + "req": "^0.3.19", + "features": ["sink", "alloc", "std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-core", + "req": "^0.3.19", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-util", + "req": "^0.3.19", + "features": ["alloc", "sink", "io"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "hex", + "req": "^0.4.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hkdf", + "req": "^0.12.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hmac", + "req": "^0.12.0", + "features": ["reset"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "home", + "req": "^0.5.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ipnet", + "req": "^2.3.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ipnetwork", + "req": "^0.20.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "itoa", + "req": "^1.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "log", + "req": "^0.4.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "mac_address", + "req": "^1.1.5", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "md-5", + "req": "^0.10.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "memchr", + "req": "^2.4.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "num-bigint", + "req": "^0.4.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "once_cell", + "req": "^1.9.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.8.4", + "features": ["std", "std_rng"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rust_decimal", + "req": "^1.26.1", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.144", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.85", + "features": ["raw_value"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sha2", + "req": "^0.10.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "smallvec", + "req": "^1.7.0", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sqlx", + "req": "=0.8.6", + "features": ["postgres", "derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "sqlx-core", + "req": "=0.8.6", + "features": ["json"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "stringprep", + "req": "^0.1.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "thiserror", + "req": "^2.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "time", + "req": "^0.3.36", + "features": ["formatting", "parsing", "macros"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tracing", + "req": "^0.1.37", + "features": ["log"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "uuid", + "req": "^1.1.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "whoami", + "req": "^1.2.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46", + "features": { + "any": ["sqlx-core/any"], + "json": ["sqlx-core/json"], + "migrate": ["sqlx-core/migrate"], + "offline": ["sqlx-core/offline"] + }, + "features2": { + "bigdecimal": ["dep:bigdecimal", "dep:num-bigint", "sqlx-core/bigdecimal"], + "bit-vec": ["dep:bit-vec", "sqlx-core/bit-vec"], + "chrono": ["dep:chrono", "sqlx-core/chrono"], + "ipnet": ["dep:ipnet", "sqlx-core/ipnet"], + "ipnetwork": ["dep:ipnetwork", "sqlx-core/ipnetwork"], + "mac_address": ["dep:mac_address", "sqlx-core/mac_address"], + "rust_decimal": ["dep:rust_decimal", "rust_decimal/maths", "sqlx-core/rust_decimal"], + "time": ["dep:time", "sqlx-core/time"], + "uuid": ["dep:uuid", "sqlx-core/uuid"] + }, + "yanked": false, + "pubtime": "2025-05-19T23:23:25Z", + "v": 2 + } + ] + }, + { + "path": "st/ab/stable_deref_trait", + "header": "AwIAAABldGFnOiAiY2M0NDZlNDRhYzU5OWM5Mjc0NmU5NmY3NWFlMThiODEiAA==", + "records": [ + { + "name": "stable_deref_trait", + "vers": "1.2.1", + "deps": [], + "cksum": "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596", + "features": { + "alloc": [], + "default": ["std"], + "std": ["alloc"] + }, + "yanked": false, + "pubtime": "2025-10-09T05:24:54Z" + } + ] + }, + { + "path": "st/ri/stringprep", + "header": "AwIAAABldGFnOiAiZDU3NWQwYjkwZDc5ZjRjNjhhMzg0Y2ZkMmM3NWY2OTciAA==", + "records": [ + { + "name": "stringprep", + "vers": "0.1.5", + "deps": [ + { + "name": "unicode-bidi", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "unicode-normalization", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "unicode-properties", + "req": "^0.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1", + "features": {}, + "yanked": false, + "pubtime": "2024-05-25T13:22:49Z" + } + ] + }, + { + "path": "st/ri/strip-ansi-escapes", + "header": "AwIAAABldGFnOiAiNjdlYzIzNjQyYzE5OWIxMTVlZTEyYTI5M2NmYThkNDUiAA==", + "records": [ + { + "name": "strip-ansi-escapes", + "vers": "0.2.1", + "deps": [ + { + "name": "doc-comment", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "vte", + "req": "^0.14", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "2a8f8038e7e7969abb3f1b7c2a811225e9296da208539e0f79c5251d6cac0025", + "features": {}, + "yanked": false, + "pubtime": "2025-01-14T15:47:27Z" + } + ] + }, + { + "path": "st/rs/strsim", + "header": "AwIAAABldGFnOiAiYWI2OTk0MDZjMTJkMTI4NjhmYjllY2VlOThkY2I0NmEiAA==", + "records": [ + { + "name": "strsim", + "vers": "0.11.1", + "deps": [], + "cksum": "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-04-02T22:18:09Z" + } + ] + }, + { + "path": "su/bt/subtle", + "header": "AwIAAABldGFnOiAiODljOGU4Y2E0NWJkOTMzOTUxMzAxNDU0MTlhNjQ3MTAiAA==", + "records": [ + { + "name": "subtle", + "vers": "2.6.1", + "deps": [ + { + "name": "rand", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292", + "features": { + "const-generics": [], + "core_hint_black_box": [], + "default": ["std", "i128"], + "i128": [], + "nightly": [], + "std": [] + }, + "yanked": false, + "pubtime": "2024-06-24T17:25:24Z" + } + ] + }, + { + "path": "sy/mb/symbolic-common", + "header": "AwIAAABldGFnOiAiNjg0NTg4OGUyYjIxNjNhMTM1OGRkZWFkMTI0NWI1MzIiAA==", + "records": [ + { + "name": "symbolic-common", + "vers": "13.9.0", + "deps": [ + { + "name": "debugid", + "req": "^0.8.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memmap2", + "req": "^0.9.11", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.171", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "similar-asserts", + "req": "^1.4.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "stable_deref_trait", + "req": "^1.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "uuid", + "req": "^1.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "ddfa0014ff4e423a1bb8881453c7a29181eb14fe1dbc8e0197ebfa081903f3ed", + "features": {}, + "features2": { + "serde": ["dep:serde", "debugid/serde"] + }, + "yanked": false, + "rust_version": "1.83", + "pubtime": "2026-07-09T10:23:35Z", + "v": 2 + } + ] + }, + { + "path": "sy/mb/symbolic-demangle", + "header": "AwIAAABldGFnOiAiZjFiNDg0YzEwOWNmNDNiNzczNjQxYWM2NjllNjE2YjEiAA==", + "records": [ + { + "name": "symbolic-demangle", + "vers": "13.9.0", + "deps": [ + { + "name": "bitflags", + "req": "^2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "cc", + "req": "^1.0.79", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "cpp_demangle", + "req": "^0.4.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "itoa", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustc-demangle", + "req": "^0.1.21", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "similar-asserts", + "req": "^1.4.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "symbolic-common", + "req": "^13.9.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "2a213276280a1a737ff5fb89ae2a70ba51d1d4608e74736beb92f257f125f1aa", + "features": { + "cpp": ["cpp_demangle"], + "rust": ["rustc-demangle"], + "swift": ["cc"] + }, + "features2": { + "default": ["cpp", "msvc", "rust", "swift"], + "msvc": ["dep:bitflags", "dep:itoa"] + }, + "yanked": false, + "rust_version": "1.83", + "pubtime": "2026-07-09T10:23:42Z", + "v": 2 + } + ] + }, + { + "path": "sy/ns/synstructure", + "header": "AwIAAABldGFnOiAiZDZlNzMzYjBkMGYwZThmNjE1ZTZkY2EzOTUxYzVkOTgiAA==", + "records": [ + { + "name": "synstructure", + "vers": "0.14.0", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.60", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3", + "features": ["derive", "parsing", "printing", "clone-impls", "visit", "extra-traits"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "synstructure_test_traits", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02", + "features": { + "default": ["proc-macro"], + "proc-macro": ["proc-macro2/proc-macro", "syn/proc-macro", "quote/proc-macro"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-30T19:43:04Z" + } + ] + }, + { + "path": "ta/rg/target-lexicon", + "header": "AwIAAABldGFnOiAiODFlODhjMjkzZjAxZjZhNjhmNmVmOGQzM2FhMGVmMjciAA==", + "records": [ + { + "name": "target-lexicon", + "vers": "0.13.5", + "deps": [ + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca", + "features": { + "arch_z80": [], + "arch_zkasm": [], + "default": [], + "serde_support": ["serde", "std"], + "std": [] + }, + "yanked": false, + "pubtime": "2026-02-15T23:26:15Z" + } + ] + }, + { + "path": "te/mp/tempfile", + "header": "AwIAAABldGFnOiAiNGEwOWI0YmE2MGRhZDUxMjJiNjczZDExNjA0M2M1ODUiAA==", + "records": [ + { + "name": "tempfile", + "vers": "3.27.0", + "deps": [ + { + "name": "doc-comment", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "fastrand", + "req": "^2.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "getrandom", + "req": ">=0.3.0, <0.5", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(any(unix, windows, target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "once_cell", + "req": "^1.19.0", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rustix", + "req": "^1.1.4", + "features": ["fs"], + "optional": false, + "default_features": true, + "target": "cfg(any(unix, target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.52, <0.62", + "features": ["Win32_Storage_FileSystem", "Win32_Foundation"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd", + "features": { + "default": ["getrandom"], + "nightly": [] + }, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2026-03-11T00:20:04Z" + } + ] + }, + { + "path": "te/rm/terminal_size", + "header": "AwIAAABldGFnOiAiNjU0MjA1NjI4ZjM1ZmJmNmU3Mzk2YTRhYWI4ZDM1NzciAA==", + "records": [ + { + "name": "terminal_size", + "vers": "0.4.4", + "deps": [ + { + "name": "rustix", + "req": "^1.0.1", + "features": ["termios"], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.59, <=0.61", + "features": ["Win32_Foundation", "Win32_System_Console"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "230a1b821ccbd75b185820a1f1ff7b14d21da1e442e22c0863ea5f08771a8874", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-03-23T16:39:14Z" + } + ] + }, + { + "path": "te/rm/termios", + "header": "AwIAAABldGFnOiAiZWZlYTQ3MWMzZGViNTk5OWUzNzNlODE1MmY1MzQ4NTYiAA==", + "records": [ + { + "name": "termios", + "vers": "0.3.3", + "deps": [ + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "411c5bf740737c7918b8b1fe232dca4dc9f8e754b8ad5e20966814001ed0ac6b", + "features": {}, + "yanked": false, + "pubtime": "2020-10-13T02:04:58Z" + } + ] + }, + { + "path": "th/is/thiserror", + "header": "AwIAAABldGFnOiAiNGJmYzc5NjFmNzk1ZmE5OWJiN2QzYTk0OTBmYjJiZDYiAA==", + "records": [ + { + "name": "thiserror", + "vers": "2.0.21", + "deps": [ + { + "name": "anyhow", + "req": "^1.0.73", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ref-cast", + "req": "^1.0.18", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0.13", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "thiserror-impl", + "req": "=2.0.21", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "trybuild", + "req": "^1.0.108", + "features": ["diff"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.77", + "pubtime": "2026-09-23T20:24:07Z" + } + ] + }, + { + "path": "th/is/thiserror-impl", + "header": "AwIAAABldGFnOiAiNDgwMzQ2MjI4NzY1MGZkYmQ2MDFlODAyYjM0MGVhZTQiAA==", + "records": [ + { + "name": "thiserror-impl", + "vers": "2.0.21", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.74", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.35", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524", + "features": {}, + "yanked": false, + "rust_version": "1.77", + "pubtime": "2026-09-23T20:24:05Z" + } + ] + }, + { + "path": "ti/me/time", + "header": "AwIAAABldGFnOiAiZDg4MjI2MjU1MmNjZTJjZTY4NjYzMjBlYzQ2YjMyMzciAA==", + "records": [ + { + "name": "time", + "vers": "0.3.55", + "deps": [ + { + "name": "criterion", + "req": "^0.8.1", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(bench)", + "kind": "dev" + }, + { + "name": "deranged", + "req": "^0.5.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "js-sys", + "req": "^0.3.58", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(all(target_family = \"wasm\", not(any(target_os = \"emscripten\", target_os = \"wasi\"))))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.98", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(target_family = \"unix\")", + "kind": "normal" + }, + { + "name": "num-conv", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "num-conv", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "num_threads", + "req": "^0.1.2", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(target_family = \"unix\")", + "kind": "normal" + }, + { + "name": "powerfmt", + "req": "^0.2.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1.0.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck_macros", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand010", + "req": "^0.10.1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "rand" + }, + { + "name": "rand08", + "req": "^0.8.6", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "rand" + }, + { + "name": "rand08", + "req": "^0.8.6", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "rand" + }, + { + "name": "rand09", + "req": "^0.9.4", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal", + "package": "rand" + }, + { + "name": "rand09", + "req": "^0.9.4", + "features": ["small_rng"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "rand" + }, + { + "name": "rstest", + "req": "^0.26.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rstest_reuse", + "req": "^0.7.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.184", + "features": ["derive", "alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.68", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_test2", + "req": "^2.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "time-core", + "req": "=0.1.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "time-macros", + "req": "=0.2.32", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "time-macros", + "req": "=0.2.32", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.102", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(__ui_tests)", + "kind": "dev" + } + ], + "cksum": "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134", + "features": {}, + "features2": { + "alloc": ["serde_core?/alloc"], + "default": ["std"], + "formatting": ["std", "time-macros?/formatting"], + "large-dates": ["time-core/large-dates", "time-macros?/large-dates"], + "local-offset": ["std", "dep:libc", "dep:num_threads"], + "macros": ["dep:time-macros"], + "parsing": ["time-macros?/parsing"], + "quickcheck": ["dep:quickcheck", "alloc", "deranged/quickcheck"], + "rand": ["rand08", "rand09", "rand010"], + "rand010": ["dep:rand010", "deranged/rand010"], + "rand08": ["dep:rand08", "deranged/rand08"], + "rand09": ["dep:rand09", "deranged/rand09"], + "serde": ["dep:serde_core", "time-macros?/serde", "deranged/serde"], + "serde-human-readable": ["serde", "formatting", "parsing"], + "serde-well-known": ["serde", "formatting", "parsing"], + "std": ["alloc"], + "wasm-bindgen": ["dep:js-sys"] + }, + "yanked": false, + "rust_version": "1.88.0", + "pubtime": "2026-08-01T08:08:34Z", + "v": 2 + } + ] + }, + { + "path": "ti/me/time-core", + "header": "AwIAAABldGFnOiAiYzk2NmU1ZGZjNThkOTYwMTU3NjI4OWI1YmIyNDlhMmEiAA==", + "records": [ + { + "name": "time-core", + "vers": "0.1.9", + "deps": [], + "cksum": "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109", + "features": { + "large-dates": [] + }, + "yanked": false, + "rust_version": "1.88.0", + "pubtime": "2026-06-12T08:14:02Z" + } + ] + }, + { + "path": "ti/me/time-macros", + "header": "AwIAAABldGFnOiAiMWQ3YjJhMzQ5NzgyNzIzNGFlMjUyNzEzMTk3ZWE2N2YiAA==", + "records": [ + { + "name": "time-macros", + "vers": "0.2.32", + "deps": [ + { + "name": "num-conv", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "time-core", + "req": "=0.1.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85", + "features": { + "formatting": [], + "large-dates": [], + "parsing": [], + "serde": [] + }, + "yanked": false, + "rust_version": "1.88.0", + "pubtime": "2026-07-20T08:27:37Z" + } + ] + }, + { + "path": "ti/ny/tinystr", + "header": "AwIAAABldGFnOiAiODY2MDY4ZGI5MTg2Nzc5YmQzMWFkZGMxZTE3OWRkN2IiAA==", + "records": [ + { + "name": "tinystr", + "vers": "0.8.4", + "deps": [ + { + "name": "bincode", + "req": "^1.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "databake", + "req": "^0.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "displaydoc", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "postcard", + "req": "^1.0.3", + "features": ["use-std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9", + "features": ["small_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.45", + "features": ["alloc"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "zerovec", + "req": "^0.11.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643", + "features": { + "std": [] + }, + "features2": { + "alloc": ["serde_core?/alloc", "zerovec?/alloc"], + "databake": ["dep:databake"], + "default": ["alloc"], + "serde": ["dep:serde_core"], + "zerovec": ["dep:zerovec"] + }, + "yanked": false, + "rust_version": "1.82", + "pubtime": "2026-08-13T23:28:07Z", + "v": 2 + } + ] + }, + { + "path": "ti/ny/tinyvec", + "header": "AwIAAABldGFnOiAiZDc3MmFjNDU2NjIwOTk4ZjJmM2EyMTU4OTg2YmU0YTYiAA==", + "records": [ + { + "name": "tinyvec", + "vers": "1.13.3", + "deps": [ + { + "name": "arbitrary", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bin-proto", + "req": "^0.12.5", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "borsh", + "req": "^1.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "criterion", + "req": "^0.8.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "debugger_test", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "debugger_test_parser", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "defmt", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "generic-array", + "req": "^1.1.1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "schemars", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_core", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_test", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "smallvec", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee", + "features": { + "alloc": [], + "debugger_visualizer": [], + "default": [], + "experimental_write_impl": [], + "grab_spare_slice": [], + "latest_stable_rust": ["rustc_1_61"], + "nightly_slice_partition_dedup": [], + "real_blackbox": ["criterion/real_blackbox"], + "rustc_1_40": [], + "rustc_1_55": [], + "rustc_1_57": [], + "rustc_1_61": ["rustc_1_57"], + "std": ["alloc"], + "tinyvec_macros": [] + }, + "features2": { + "schemars": ["dep:schemars", "alloc"], + "serde": ["dep:serde_core"] + }, + "yanked": false, + "pubtime": "2026-09-13T23:30:12Z", + "v": 2 + } + ] + }, + { + "path": "to/ki/tokio", + "header": "AwIAAABldGFnOiAiY2JlMGZmYTdjZWNhM2QzNmU1MDVkYWYwMzI3YWUxMWMiAA==", + "records": [ + { + "name": "tokio", + "vers": "1.53.2", + "deps": [ + { + "name": "async-stream", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "backtrace", + "req": "^0.3.58", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(all(tokio_unstable, target_os = \"linux\"))", + "kind": "normal" + }, + { + "name": "backtrace", + "req": "^0.3.58", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(tokio_unstable, target_os = \"linux\"))", + "kind": "dev" + }, + { + "name": "bytes", + "req": "^1.2.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures", + "req": "^0.3.0", + "features": ["async-await"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "futures-concurrency", + "req": "^7.6.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "futures-test", + "req": "^0.3.31", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "io-uring", + "req": "^0.7.11", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(tokio_unstable, target_os = \"linux\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.168", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(all(tokio_unstable, target_os = \"linux\"))", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.168", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(target_os = \"wasi\")", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.168", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.168", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(unix)", + "kind": "dev" + }, + { + "name": "loom", + "req": "^0.7", + "features": ["futures", "checkpoint"], + "optional": false, + "default_features": true, + "target": "cfg(loom)", + "kind": "dev" + }, + { + "name": "mio", + "req": "^1.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "mio", + "req": "^1.2.0", + "features": ["os-poll", "os-ext"], + "optional": true, + "default_features": false, + "target": "cfg(all(tokio_unstable, target_os = \"linux\"))", + "kind": "normal" + }, + { + "name": "mio-aio", + "req": "^2", + "features": ["tokio"], + "optional": false, + "default_features": true, + "target": "cfg(target_os = \"freebsd\")", + "kind": "dev" + }, + { + "name": "mockall", + "req": "^0.13.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "nix", + "req": "^0.31.0", + "features": ["aio", "fs", "socket"], + "optional": false, + "default_features": false, + "target": "cfg(unix)", + "kind": "dev" + }, + { + "name": "parking_lot", + "req": "^0.12.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pin-project-lite", + "req": "^0.2.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proptest", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_family = \"wasm\"))", + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(all(target_family = \"wasm\", target_os = \"unknown\")))", + "kind": "dev" + }, + { + "name": "signal-hook-registry", + "req": "^1.1.1", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "slab", + "req": "^0.4.9", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(all(tokio_unstable, target_os = \"linux\"))", + "kind": "normal" + }, + { + "name": "socket2", + "req": "^0.6.3", + "features": ["all"], + "optional": true, + "default_features": true, + "target": "cfg(any(not(target_family = \"wasm\"), all(target_os = \"wasi\", not(target_env = \"p1\"))))", + "kind": "normal" + }, + { + "name": "socket2", + "req": "^0.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_family = \"wasm\"))", + "kind": "dev" + }, + { + "name": "tempfile", + "req": "^3.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_family = \"wasm\"))", + "kind": "dev" + }, + { + "name": "tokio-macros", + "req": "~2.7.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio-stream", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-test", + "req": "^0.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-util", + "req": "^0.7", + "features": ["rt"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tracing", + "req": "^0.1.29", + "features": ["std"], + "optional": true, + "default_features": false, + "target": "cfg(tokio_unstable)", + "kind": "normal" + }, + { + "name": "tracing-mock", + "req": "=0.1.0-beta.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(tokio_unstable, target_has_atomic = \"64\"))", + "kind": "dev" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_family = \"wasm\", not(target_os = \"wasi\")))", + "kind": "dev" + }, + { + "name": "windows-sys", + "req": "^0.61", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": "^0.61", + "features": ["Win32_Foundation", "Win32_Security_Authorization"], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "dev" + } + ], + "cksum": "e95f91fcc7a621e8b030f6aa23c71fe9838ae2fb4d8118b75602a328f5144044", + "features": { + "default": [], + "fs": [], + "full": [ + "fs", + "io-util", + "io-std", + "macros", + "net", + "parking_lot", + "process", + "rt", + "rt-multi-thread", + "signal", + "sync", + "time" + ], + "io-std": [], + "io-util": ["bytes"], + "macros": ["tokio-macros"], + "net": [ + "libc", + "mio/os-poll", + "mio/os-ext", + "mio/net", + "socket2", + "windows-sys/Win32_Foundation", + "windows-sys/Win32_Security", + "windows-sys/Win32_Storage_FileSystem", + "windows-sys/Win32_System_Pipes", + "windows-sys/Win32_System_SystemServices" + ], + "process": [ + "bytes", + "libc", + "mio/os-poll", + "mio/os-ext", + "mio/net", + "signal-hook-registry", + "windows-sys/Win32_Foundation", + "windows-sys/Win32_System_Threading", + "windows-sys/Win32_System_WindowsProgramming" + ], + "rt": [], + "rt-multi-thread": ["rt"], + "schedule-latency": [], + "signal": [ + "libc", + "mio/os-poll", + "mio/net", + "mio/os-ext", + "signal-hook-registry", + "windows-sys/Win32_Foundation", + "windows-sys/Win32_System_Console" + ], + "sync": [], + "test-util": ["rt", "sync", "time"], + "time": [] + }, + "features2": { + "io-uring": ["dep:io-uring", "libc", "mio/os-poll", "mio/os-ext", "dep:slab"], + "taskdump": ["dep:backtrace"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-10-03T11:18:32Z", + "v": 2 + } + ] + }, + { + "path": "to/ki/tokio-macros", + "header": "AwIAAABldGFnOiAiYWM3MzFjYjA0YTcxZTE1YmUwNzkwNjg1MzU4YmIwYWQiAA==", + "records": [ + { + "name": "tokio-macros", + "vers": "2.7.2", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.60", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3.0", + "features": ["full"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.0.0", + "features": ["full", "test-util"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-29T13:15:27Z" + } + ] + }, + { + "path": "to/ki/tokio-postgres", + "header": "AwIAAABldGFnOiAiNGM5ZjdhZTY1Yzg2ZGJlNGJiYzhmYjEzMzI1NTFjZWYiAA==", + "records": [ + { + "name": "tokio-postgres", + "vers": "0.7.18", + "deps": [ + { + "name": "async-trait", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bit-vec-06", + "req": "^0.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "bit-vec" + }, + { + "name": "bit-vec-07", + "req": "^0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "bit-vec" + }, + { + "name": "bit-vec-08", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "bit-vec" + }, + { + "name": "bit-vec-09", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "bit-vec" + }, + { + "name": "byteorder", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytes", + "req": "^1.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "chrono-04", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "chrono" + }, + { + "name": "criterion", + "req": "^0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "env_logger", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "eui48-1", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev", + "package": "eui48" + }, + { + "name": "fallible-iterator", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures-channel", + "req": "^0.3", + "features": ["sink"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures-executor", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "futures-util", + "req": "^0.3", + "features": ["sink"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "futures-util", + "req": "^0.3", + "features": ["async-await-macro"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "geo-types-06", + "req": "^0.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "geo-types" + }, + { + "name": "geo-types-07", + "req": "^0.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "geo-types" + }, + { + "name": "jiff-01", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "jiff" + }, + { + "name": "jiff-02", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "jiff" + }, + { + "name": "log", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "parking_lot", + "req": "^0.12", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "percent-encoding", + "req": "^2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "phf", + "req": "^0.13", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pin-project-lite", + "req": "^0.2.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "postgres-protocol", + "req": "^0.6.12", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "postgres-types", + "req": "^0.2.14", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.10.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json-1", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "serde_json" + }, + { + "name": "smol_str-01", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "smol_str" + }, + { + "name": "socket2", + "req": "^0.6", + "features": ["all"], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "time-02", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "time" + }, + { + "name": "time-03", + "req": "^0.3", + "features": ["parsing"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "time" + }, + { + "name": "tokio", + "req": "^1.27", + "features": ["io-util"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.0", + "features": ["macros", "net", "rt", "rt-multi-thread", "time"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-util", + "req": "^0.7", + "features": ["codec"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "uuid-08", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "uuid" + }, + { + "name": "uuid-1", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "uuid" + }, + { + "name": "whoami", + "req": "^2.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "a528f7d280f6d5b9cd149635c8705b0dd049754bc67d81d31fa25169a93809d3", + "features": { + "array-impls": ["postgres-types/array-impls"], + "default": ["runtime"], + "js": ["postgres-protocol/js", "postgres-types/js"], + "runtime": ["tokio/net", "tokio/time"], + "with-bit-vec-0_6": ["postgres-types/with-bit-vec-0_6"], + "with-bit-vec-0_7": ["postgres-types/with-bit-vec-0_7"], + "with-bit-vec-0_8": ["postgres-types/with-bit-vec-0_8"], + "with-bit-vec-0_9": ["postgres-types/with-bit-vec-0_9"], + "with-chrono-0_4": ["postgres-types/with-chrono-0_4"], + "with-cidr-0_2": ["postgres-types/with-cidr-0_2"], + "with-cidr-0_3": ["postgres-types/with-cidr-0_3"], + "with-eui48-0_4": ["postgres-types/with-eui48-0_4"], + "with-eui48-1": ["postgres-types/with-eui48-1"], + "with-geo-types-0_6": ["postgres-types/with-geo-types-0_6"], + "with-geo-types-0_7": ["postgres-types/with-geo-types-0_7"], + "with-jiff-0_1": ["postgres-types/with-jiff-0_1"], + "with-jiff-0_2": ["postgres-types/with-jiff-0_2"], + "with-serde_json-1": ["postgres-types/with-serde_json-1"], + "with-smol_str-01": ["postgres-types/with-smol_str-01"], + "with-time-0_2": ["postgres-types/with-time-0_2"], + "with-time-0_3": ["postgres-types/with-time-0_3"], + "with-uuid-0_8": ["postgres-types/with-uuid-0_8"], + "with-uuid-1": ["postgres-types/with-uuid-1"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-06-12T15:39:21Z" + } + ] + }, + { + "path": "to/ki/tokio-stream", + "header": "AwIAAABldGFnOiAiYWYwYWE2ZTY1ZTUxZTRkOWY0MTUzYWE3ZmQ3YzkzZGEiAA==", + "records": [ + { + "name": "tokio-stream", + "vers": "0.1.19", + "deps": [ + { + "name": "async-stream", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "futures", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "futures-core", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "parking_lot", + "req": "^0.12.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "pin-project-lite", + "req": "^0.2.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.38.0", + "features": ["sync"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.38.0", + "features": ["full", "test-util"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-test", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-util", + "req": "^0.7.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "a3d06f0b082ba57c26b79407372e57cf2a1e28124f78e9479fe80322cf53420b", + "features": { + "default": ["time"], + "fs": ["tokio/fs"], + "full": ["time", "net", "io-util", "fs", "rt", "sync", "signal"], + "io-util": ["tokio/io-util"], + "net": ["tokio/net"], + "rt": ["tokio/rt"], + "signal": ["tokio/signal"], + "sync": ["tokio/sync", "tokio-util"], + "time": ["tokio/time"] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-22T08:19:01Z" + } + ] + }, + { + "path": "to/ki/tokio-util", + "header": "AwIAAABldGFnOiAiMmIwYjljOTc4MmYyYzE3NTE3MDU5NGZiOGZhZDA0ZmMiAA==", + "records": [ + { + "name": "tokio-util", + "vers": "0.7.20", + "deps": [ + { + "name": "async-stream", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "bytes", + "req": "^1.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "futures-core", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures-io", + "req": "^0.3.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures-sink", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures-test", + "req": "^0.3.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "futures-util", + "req": "^0.3.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hashbrown", + "req": "^0.15.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.168", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "loom", + "req": "^0.7", + "features": ["futures", "checkpoint"], + "optional": false, + "default_features": true, + "target": "cfg(loom)", + "kind": "dev" + }, + { + "name": "parking_lot", + "req": "^0.12.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "pin-project-lite", + "req": "^0.2.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "slab", + "req": "^0.4.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio", + "req": "^1.51.0", + "features": ["sync"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.0.0", + "features": ["full"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-stream", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-test", + "req": "^0.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tracing", + "req": "^0.1.29", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "e464cf451ba96ebfc6f9b6542f17ee8b8956e33f1e40d9690624e59d7a7f8a4b", + "features": { + "__docs_rs": ["futures-util"], + "codec": ["libc"], + "compat": ["futures-io"], + "default": [], + "full": ["codec", "compat", "io-util", "time", "net", "rt", "join-map"], + "io": [], + "io-util": ["io", "tokio/rt", "tokio/io-util"], + "join-map": ["rt", "hashbrown"], + "net": ["tokio/net"], + "rt": ["tokio/rt", "tokio/sync", "futures-util"], + "time": ["tokio/time", "slab"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-10-09T11:02:11Z" + } + ] + }, + { + "path": "to/ml/toml", + "header": "AwIAAABldGFnOiAiNTBhM2E4MTE5NGM5MDU0NmMwOTg1Y2M0YTgxNmEyYjkiAA==", + "records": [ + { + "name": "toml", + "vers": "1.1.8+spec-1.1.0", + "deps": [ + { + "name": "anstream", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anstyle", + "req": "^1.0.14", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "foldhash", + "req": "^0.2.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2.13.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "itertools", + "req": "^0.15.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.228", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde-untagged", + "req": "^0.1.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.228", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.149", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_spanned", + "req": "^1.1.2", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "snapbox", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml-test-data", + "req": "^2.14.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml-test-harness", + "req": "^1.14.1", + "features": ["snapshot"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml_datetime", + "req": "^1.1.2", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "toml_parser", + "req": "^1.1.5", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "toml_writer", + "req": "^1.1.3", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "walkdir", + "req": "^2.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "winnow", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "20489e00e4d8741d6be680764cc12e270655e375a20d1011e844a9c3379e678d", + "features": { + "unbounded": [] + }, + "features2": { + "debug": ["std", "toml_parser?/debug", "dep:anstream", "dep:anstyle"], + "default": ["std", "serde", "parse", "display"], + "display": ["dep:toml_writer"], + "fast_hash": ["preserve_order", "dep:foldhash"], + "parse": ["dep:toml_parser", "dep:winnow"], + "preserve_order": ["dep:indexmap", "std"], + "serde": ["dep:serde_core", "toml_datetime/serde", "serde_spanned/serde"], + "std": [ + "indexmap?/std", + "serde_core?/std", + "toml_parser?/std", + "toml_writer?/std", + "toml_datetime/std", + "serde_spanned/std" + ] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-10-09T02:46:31Z", + "v": 2 + } + ] + }, + { + "path": "to/ml/toml_datetime", + "header": "AwIAAABldGFnOiAiMjg4ZGUzNzkwNjcwMWU0YTA1ZjAxMTM2ZGQxOWFlZjYiAA==", + "records": [ + { + "name": "toml_datetime", + "vers": "1.1.2+spec-1.1.0", + "deps": [ + { + "name": "serde_core", + "req": "^1.0.228", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "snapbox", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "2b86d767906c6c42421dcba507eb9d203e779497710a47782a224bb871653053", + "features": {}, + "features2": { + "alloc": ["serde_core?/alloc"], + "default": ["std"], + "serde": ["dep:serde_core"], + "std": ["alloc", "serde_core?/std"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-10-08T00:54:03Z", + "v": 2 + } + ] + }, + { + "path": "to/ml/toml_edit", + "header": "AwIAAABldGFnOiAiMWMyODRhM2I4OGY4YzIzMTlhM2VjMjY2MzYzNjZhMDYiAA==", + "records": [ + { + "name": "toml_edit", + "vers": "0.25.17+spec-1.1.0", + "deps": [ + { + "name": "anstream", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anstyle", + "req": "^1.0.14", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2.13.0", + "features": ["std"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proptest", + "req": "^1.10.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.228", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde-untagged", + "req": "^0.1.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.228", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.149", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_spanned", + "req": "^1.1.2", + "features": ["serde"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "snapbox", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml-test-data", + "req": "^2.14.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml-test-harness", + "req": "^1.14.1", + "features": ["snapshot"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml_datetime", + "req": "^1.1.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "toml_parser", + "req": "^1.1.5", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "toml_writer", + "req": "^1.1.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "walkdir", + "req": "^2.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "winnow", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "e3641d5bbb5349a79e1020a242d251efbc546ad8048d133958323ce9c40a9c9c", + "features": { + "unbounded": [] + }, + "features2": { + "debug": ["toml_parser?/debug", "dep:anstream", "dep:anstyle", "display"], + "default": ["parse", "display"], + "display": ["dep:toml_writer"], + "parse": ["dep:toml_parser", "dep:winnow"], + "serde": ["dep:serde_core", "toml_datetime/serde", "dep:serde_spanned"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-10-09T02:46:32Z", + "v": 2 + } + ] + }, + { + "path": "to/ml/toml_parser", + "header": "AwIAAABldGFnOiAiOWViOWE2MWYxN2Q2YzZkMTk1NTlmNzkxZDE0YmM0NGMiAA==", + "records": [ + { + "name": "toml_parser", + "vers": "1.1.5+spec-1.1.0", + "deps": [ + { + "name": "anstream", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anstream", + "req": "^1.0.0", + "features": ["test"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "anstyle", + "req": "^1.0.14", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "snapbox", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "winnow", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "baa693a8032d7e1cada7d0041e96126df243179ff061456783ac7f12bda4744c", + "features": { + "alloc": [], + "default": ["std"], + "simd": ["winnow/simd"], + "std": ["alloc"], + "unsafe": [] + }, + "features2": { + "debug": ["std", "dep:anstream", "dep:anstyle"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-10-09T02:46:29Z", + "v": 2 + } + ] + }, + { + "path": "to/ml/toml_writer", + "header": "AwIAAABldGFnOiAiNDk0MmU4YTk4YjUxNWY2N2ZlZWFkN2NhMzc2ZjgwZjciAA==", + "records": [ + { + "name": "toml_writer", + "vers": "1.1.3+spec-1.1.0", + "deps": [ + { + "name": "proptest", + "req": "^1.10.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "snapbox", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "toml_old", + "req": "^0.5.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev", + "package": "toml" + } + ], + "cksum": "06bdbd8cfc056b8d2e2e85f29b56a3bdbecb527cef81eb39e3e7b98af4652770", + "features": { + "alloc": [], + "default": ["std"], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.85", + "pubtime": "2026-10-08T00:54:04Z" + } + ] + }, + { + "path": "tr/ac/tracing", + "header": "AwIAAABldGFnOiAiNjM0NWRiYTkxYjg3YTI3OGYwODNjMDFlODg5OGVmMjIiAA==", + "records": [ + { + "name": "tracing", + "vers": "0.1.44", + "deps": [ + { + "name": "criterion", + "req": "^0.3.6", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "futures", + "req": "^0.3.21", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "log", + "req": "^0.4.17", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "log", + "req": "^0.4.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "pin-project-lite", + "req": "^0.2.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tracing-attributes", + "req": "^0.1.31", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tracing-core", + "req": "^0.1.36", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3.38", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + } + ], + "cksum": "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100", + "features": { + "async-await": [], + "attributes": ["tracing-attributes"], + "default": ["std", "attributes"], + "log-always": ["log"], + "max_level_debug": [], + "max_level_error": [], + "max_level_info": [], + "max_level_off": [], + "max_level_trace": [], + "max_level_warn": [], + "release_max_level_debug": [], + "release_max_level_error": [], + "release_max_level_info": [], + "release_max_level_off": [], + "release_max_level_trace": [], + "release_max_level_warn": [], + "std": ["tracing-core/std"], + "valuable": ["tracing-core/valuable"] + }, + "yanked": false, + "rust_version": "1.65.0", + "pubtime": "2025-12-18T14:26:12Z" + } + ] + }, + { + "path": "tr/ac/tracing-attributes", + "header": "AwIAAABldGFnOiAiOWZjZTRiYWYyZDBiODFhMDkyMzA4NjY0OGE2OTgxNmUiAA==", + "records": [ + { + "name": "tracing-attributes", + "vers": "0.1.31", + "deps": [ + { + "name": "async-trait", + "req": "^0.1.67", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1.0.60", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.20", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustversion", + "req": "^1.0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn", + "req": "^2.0", + "features": [ + "full", + "parsing", + "printing", + "visit-mut", + "clone-impls", + "extra-traits", + "proc-macro" + ], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tokio-test", + "req": "^0.4.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tracing", + "req": "^0.1.35", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tracing-subscriber", + "req": "^0.3.0", + "features": ["env-filter"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "trybuild", + "req": "^1.0.64", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da", + "features": { + "async-await": [] + }, + "yanked": false, + "rust_version": "1.65.0", + "pubtime": "2025-11-26T11:23:01Z" + } + ] + }, + { + "path": "tr/ac/tracing-core", + "header": "AwIAAABldGFnOiAiOTkyMTU2YTdlYjFkMTI4YzBiMTE2OGQxNWI3ODhkOTEiAA==", + "records": [ + { + "name": "tracing-core", + "vers": "0.1.36", + "deps": [ + { + "name": "once_cell", + "req": "^1.13.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "valuable", + "req": "^0.1.0", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(tracing_unstable)", + "kind": "normal" + } + ], + "cksum": "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a", + "features": { + "std": ["once_cell"] + }, + "features2": { + "default": ["std", "valuable?/std"] + }, + "yanked": false, + "rust_version": "1.65.0", + "pubtime": "2025-12-18T14:13:04Z", + "v": 2 + } + ] + }, + { + "path": "tw/ox/twox-hash", + "header": "AwIAAABldGFnOiAiZDQ2NjRkYjk0N2NjMDMyMjJiNzc4ODBlNGEwMWUzMTQiAA==", + "records": [ + { + "name": "twox-hash", + "vers": "2.1.5", + "deps": [ + { + "name": "rand", + "req": ">=0.9.0, <=0.11.0", + "features": ["thread_rng"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.0", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.117", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "86a801b3cea342a06d468c8710662aa29e5e05e4f5c0d62f00bbb7f2ad7941c2", + "features": { + "alloc": [], + "std": ["alloc"], + "xxhash32": [], + "xxhash3_128": [], + "xxhash3_64": [], + "xxhash64": [] + }, + "features2": { + "default": ["random", "xxhash32", "xxhash64", "xxhash3_64", "xxhash3_128", "std"], + "random": ["dep:rand"], + "serialize": ["dep:serde"] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-10-04T14:59:48Z", + "v": 2 + } + ] + }, + { + "path": "ty/pe/typenum", + "header": "AwIAAABldGFnOiAiZmZmMGQ5NjAyZjc2NDVmZmZmMzBhYTMzYzRmYzhmYTIiAA==", + "records": [ + { + "name": "typenum", + "vers": "1.20.1", + "deps": [ + { + "name": "scale-info", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20", + "features": { + "const-generics": [], + "i128": [], + "scale_info": ["scale-info/derive"], + "strict": [] + }, + "yanked": false, + "rust_version": "1.41.0", + "pubtime": "2026-05-29T16:00:41Z" + } + ] + }, + { + "path": "un/ic/unicase", + "header": "AwIAAABldGFnOiAiYmYwMzc1ZDlhM2U4YjcxMGE3NGJhMDc2NTVjMDY4MDQiAA==", + "records": [ + { + "name": "unicase", + "vers": "2.10.0", + "deps": [], + "cksum": "357cc3acc6a036009fd6c973ed009037c732d60d0b4f6c673e9041497482a28f", + "features": { + "nightly": [] + }, + "yanked": false, + "pubtime": "2026-10-05T13:11:23Z" + } + ] + }, + { + "path": "un/ic/unicode-bidi", + "header": "AwIAAABldGFnOiAiZmQ3MzZlZDQ5YmU3MGVmZGJkNjk2Y2MxYzk5NDdmYTUiAA==", + "records": [ + { + "name": "unicode-bidi", + "vers": "0.3.18", + "deps": [ + { + "name": "flame", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "flamer", + "req": "^0.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": ">=0.8, <2.0", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_test", + "req": ">=0.8, <2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "smallvec", + "req": ">=1.13", + "features": ["union"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5", + "features": { + "bench_it": [], + "default": ["std", "hardcoded-data"], + "flame_it": ["flame", "flamer"], + "hardcoded-data": [], + "std": [], + "unstable": [], + "with_serde": ["serde"] + }, + "yanked": false, + "rust_version": "1.47.0", + "pubtime": "2024-12-16T23:09:47Z" + } + ] + }, + { + "path": "un/ic/unicode-ident", + "header": "AwIAAABldGFnOiAiYjcxNThlNzgzOGU5ZmYwZmYyNWQ5NmM3N2VmODlmNzkiAA==", + "records": [ + { + "name": "unicode-ident", + "vers": "1.0.26", + "deps": [ + { + "name": "criterion", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "fst", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "roaring", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ucd-trie", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "unicode-xid", + "req": "^0.2.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-09-17T06:18:03Z" + } + ] + }, + { + "path": "un/ic/unicode-normalization", + "header": "AwIAAABldGFnOiAiNzdmYWU1MWExZGM4ZTZmMDc4ZjcyNzM4ZjRiYTY1YTkiAA==", + "records": [ + { + "name": "unicode-normalization", + "vers": "0.1.25", + "deps": [ + { + "name": "tinyvec", + "req": "^1", + "features": ["alloc"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8", + "features": { + "default": ["std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.36", + "pubtime": "2025-10-30T16:06:38Z" + } + ] + }, + { + "path": "un/ic/unicode-properties", + "header": "AwIAAABldGFnOiAiYTQ5NDc5NTc4YmE0OGNhOTJhMTNhN2UzZTcwNjU4NzQiAA==", + "records": [ + { + "name": "unicode-properties", + "vers": "0.1.4", + "deps": [], + "cksum": "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d", + "features": { + "default": ["general-category", "emoji"], + "emoji": [], + "general-category": [] + }, + "yanked": false, + "pubtime": "2025-10-30T16:34:55Z" + } + ] + }, + { + "path": "un/ic/unicode-segmentation", + "header": "AwIAAABldGFnOiAiNGVjMTU1OTUxZWE0YzU0MzFiZmEyMDY1NWI1MjM2ZmEiAA==", + "records": [ + { + "name": "unicode-segmentation", + "vers": "1.13.3", + "deps": [ + { + "name": "criterion", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proptest", + "req": "^1.7.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quickcheck", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8", + "features": { + "no_std": [] + }, + "yanked": false, + "rust_version": "1.85.0", + "pubtime": "2026-06-01T15:58:43Z" + } + ] + }, + { + "path": "un/ic/unicode-xid", + "header": "AwIAAABldGFnOiAiNmNiN2JjNDA5Mjg0NThiZDI1NjZlOGU4MmQ0ZGIyZTgiAA==", + "records": [ + { + "name": "unicode-xid", + "vers": "0.2.6", + "deps": [ + { + "name": "criterion", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853", + "features": { + "bench": [], + "default": [], + "no_std": [] + }, + "yanked": false, + "rust_version": "1.17", + "pubtime": "2024-09-19T15:55:24Z" + } + ] + }, + { + "path": "un/sa/unsafe-libyaml", + "header": "AwIAAABldGFnOiAiMmQ4N2FkMDM2YmJmZDM3MTg3YTFmNDg4YjI2MmFlMTMiAA==", + "records": [ + { + "name": "unsafe-libyaml", + "vers": "0.2.11", + "deps": [ + { + "name": "pretty_assertions", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-03-17T05:44:18Z" + } + ] + }, + { + "path": "un/ty/unty", + "header": "AwIAAABldGFnOiAiZDdhYjY2NDNiMDdiODVhYTJhMmZjNTUzN2Y1ZDAzYWUiAA==", + "records": [ + { + "name": "unty", + "vers": "0.0.4", + "deps": [], + "cksum": "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae", + "features": {}, + "yanked": false, + "rust_version": "1.56.1", + "pubtime": "2025-03-07T08:06:25Z" + } + ] + }, + { + "path": "ur/le/urlencoding", + "header": "AwIAAABldGFnOiAiMGY2MWJjNWQwYTNlNmY4ZDU3Mjg2MTY1MTQ0Zjc2Y2YiAA==", + "records": [ + { + "name": "urlencoding", + "vers": "2.1.3", + "deps": [], + "cksum": "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da", + "features": {}, + "yanked": false, + "pubtime": "2023-07-21T15:12:17Z" + } + ] + }, + { + "path": "ut/f8/utf8_iter", + "header": "AwIAAABldGFnOiAiMWYwNTI1MDY2ZDMzMTllNmFkYzJiOTNhMmJlM2I5NmUiAA==", + "records": [ + { + "name": "utf8_iter", + "vers": "1.0.4", + "deps": [], + "cksum": "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be", + "features": {}, + "yanked": false, + "pubtime": "2023-12-01T17:26:51Z" + } + ] + }, + { + "path": "ut/f8/utf8parse", + "header": "AwIAAABldGFnOiAiMDliNjQ4ZmVjNWY2NjdhOWU3YzYyMjNlMjI0MTM5NzMiAA==", + "records": [ + { + "name": "utf8parse", + "vers": "0.2.2", + "deps": [], + "cksum": "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821", + "features": { + "default": [], + "nightly": [] + }, + "yanked": false, + "pubtime": "2024-06-08T07:07:41Z" + } + ] + }, + { + "path": "uu/id/uuid", + "header": "AwIAAABldGFnOiAiMDc2MDQ3MDAxOWViOTc0MjFhMTMyNmEwOGMwMGI1NmQiAA==", + "records": [ + { + "name": "uuid", + "vers": "1.28.0", + "deps": [ + { + "name": "arbitrary", + "req": "^1.1.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "atomic", + "req": "^0.6", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "borsh", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "borsh-derive", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "bytemuck", + "req": "^1.22", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "getrandom", + "req": "^0.4", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\"))))", + "kind": "normal" + }, + { + "name": "gungraun", + "req": "=0.19.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "js-sys", + "req": "^0.3", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\"), target_feature = \"atomics\"))", + "kind": "normal" + }, + { + "name": "md-5", + "req": "^0.10", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.10", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\"))))", + "kind": "normal" + }, + { + "name": "rustversion", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.221", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.221", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1.0.221", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_test", + "req": "^1.0.56", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "sha1_smol", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "slog", + "req": "^2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "trybuild", + "req": "^1.0.52", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "uuid-rng-internal-lib", + "req": "^1.28.0", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\")))", + "kind": "normal", + "package": "uuid-rng-internal" + }, + { + "name": "wasm-bindgen", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\")))", + "kind": "normal" + }, + { + "name": "wasm-bindgen", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\")))", + "kind": "dev" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"wasm32\", any(target_os = \"unknown\", target_os = \"none\")))", + "kind": "dev" + }, + { + "name": "zerocopy", + "req": "^0.8", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "7cc1186384beb7dd8eedea376413fd654937285ea6c9cfbb928dc3043ea4b606", + "features": { + "macro-diagnostics": [], + "v8": [] + }, + "features2": { + "atomic": ["dep:atomic"], + "borsh": ["dep:borsh", "dep:borsh-derive"], + "default": ["std"], + "fast-rng": ["rng", "dep:rand"], + "js": ["dep:wasm-bindgen", "dep:js-sys"], + "md5": ["dep:md-5"], + "rng": ["dep:getrandom"], + "rng-getrandom": [ + "rng", + "dep:getrandom", + "uuid-rng-internal-lib", + "uuid-rng-internal-lib/getrandom" + ], + "rng-rand": ["rng", "dep:rand", "uuid-rng-internal-lib", "uuid-rng-internal-lib/rand"], + "serde": ["dep:serde_core"], + "sha1": ["dep:sha1_smol"], + "std": ["wasm-bindgen?/std", "js-sys?/std"], + "v1": ["atomic"], + "v3": ["md5"], + "v4": ["rng"], + "v5": ["sha1"], + "v6": ["atomic"], + "v7": ["rng"] + }, + "yanked": false, + "rust_version": "1.89.0", + "pubtime": "2026-10-10T00:02:40Z", + "v": 2 + } + ] + }, + { + "path": "ve/rs/version_check", + "header": "AwIAAABldGFnOiAiMTdiMWIzYzA4ZjNkMjY4OTdmYTgyODg4YzU0MDljZmEiAA==", + "records": [ + { + "name": "version_check", + "vers": "0.9.5", + "deps": [], + "cksum": "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a", + "features": {}, + "yanked": false, + "pubtime": "2024-07-25T23:38:14Z" + } + ] + }, + { + "path": "vi/rt/virtual-fs", + "header": "AwIAAABldGFnOiAiNDNhMGU2MjZlYzA5NjM0NWUxMTkzMDY2ZjRjNDhjZGIiAA==", + "records": [ + { + "name": "virtual-fs", + "vers": "0.702.1", + "deps": [ + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "async-trait", + "req": "^0.1.68", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytes", + "req": "^1.11.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "dashmap", + "req": "^6.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "derive_more", + "req": "^2.0.1", + "features": ["debug", "display"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "dunce", + "req": "^1.0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "filetime", + "req": "^0.2.18", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "fs_extra", + "req": "^1.3.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures", + "req": "^0.3.30", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "getrandom", + "req": "^0.4.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.178", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "pin-project-lite", + "req": "^0.2.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pretty_assertions", + "req": "^1.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "replace_with", + "req": "^0.1.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "shared-buffer", + "req": "^0.1.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "slab", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "thiserror", + "req": "^2.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.39.0", + "features": ["io-util", "sync", "macros"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.39.0", + "features": ["io-util", "rt"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "tracing", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tracing-test", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "virtual-mio", + "req": "^0.702.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-package", + "req": "^0.702.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "web-time", + "req": "^1.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "webc", + "req": "=12.0.0", + "features": ["v1"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "18f2136946b8a66d2bc7548fc4396c72e7a8671e8ab878342f5483e6c6dfd61f", + "features": { + "default": ["host-fs", "webc-fs", "static-fs"], + "enable-serde": [], + "futures": [], + "host-fs": ["libc", "fs_extra", "filetime", "tokio/fs", "tokio/io-std", "tokio/rt"], + "static-fs": ["webc", "anyhow"], + "tracking": [], + "webc-fs": ["webc", "anyhow"] + }, + "features2": { + "js": ["dep:web-time", "getrandom/wasm_js"] + }, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:05:55Z", + "v": 2 + } + ] + }, + { + "path": "vi/rt/virtual-mio", + "header": "AwIAAABldGFnOiAiOTIyMzIxNjlhYjE1YTUzYWE0ZjcxODE5NWI3ZDJjNGYiAA==", + "records": [ + { + "name": "virtual-mio", + "vers": "0.702.1", + "deps": [ + { + "name": "async-trait", + "req": "^0.1.68", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytes", + "req": "^1.11.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures", + "req": "^0.3.30", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "mio", + "req": "^1", + "features": ["os-poll"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "mio", + "req": "^1", + "features": ["os-poll", "os-ext"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "parking", + "req": "^2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "socket2", + "req": "^0.6.1", + "features": ["all"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "thiserror", + "req": "^2.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tracing", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "b449ceba2087fe0a7e436b9f1105dd9868addb294ff96a4a28100eadb9442b15", + "features": { + "js": [], + "sys": ["mio", "socket2"] + }, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:04:33Z" + } + ] + }, + { + "path": "vi/rt/virtual-net", + "header": "AwIAAABldGFnOiAiYTVlNDJkYzRiYzY5ZjJmMWU2NTEyNmJhY2YzOGZmMzgiAA==", + "records": [ + { + "name": "virtual-net", + "vers": "0.702.1", + "deps": [ + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "async-trait", + "req": "^0.1.68", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "base64", + "req": "^0.22.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bincode", + "req": "=2.0.1", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytecheck", + "req": "^0.8.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytes", + "req": "^1.11.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "derive_more", + "req": "^2.0.1", + "features": ["debug", "display"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures-util", + "req": "^0.3.31", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hyper", + "req": "^1.8.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hyper-tungstenite", + "req": "^0.19", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hyper-util", + "req": "^0.1.5", + "features": ["tokio"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ipnet", + "req": "^2.10.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "iprange", + "req": "^0.6.7", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.178", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "mio", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pin-project-lite", + "req": "^0.2.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rkyv", + "req": "^0.8.13", + "features": ["indexmap-2", "bytes-1"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serial_test", + "req": "^3.2.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "smoltcp", + "req": "^0.13.0", + "features": ["proto-ipv4", "std", "alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "socket2", + "req": "^0.6.1", + "features": ["all"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "thiserror", + "req": "^2.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.39.0", + "features": ["io-util"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.39.0", + "features": ["macros", "rt-multi-thread"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-serde", + "req": "^0.9", + "features": ["bincode"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio-tungstenite", + "req": "^0.28.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio-util", + "req": "^0.7.8", + "features": ["codec"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tracing", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tracing-test", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "virtual-mio", + "req": "^0.702.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "fb377443085e3e30d0e3357a8d55925da670d070a04c9dd2284236a20cf308f1", + "features": { + "cbor": ["tokio-serde/cbor"], + "host-net": [ + "libc", + "tokio/io-util", + "virtual-mio/sys", + "tokio/net", + "tokio/rt", + "socket2", + "mio" + ], + "json": ["tokio-serde/json"], + "messagepack": ["tokio-serde/messagepack"], + "remote": ["libc", "tokio/io-util", "tokio/sync", "tokio-serde", "tokio-util"], + "tokio": [] + }, + "features2": { + "default": [ + "host-net", + "remote", + "json", + "messagepack", + "cbor", + "hyper", + "tokio-tungstenite" + ], + "hyper": ["hyper-tungstenite", "hyper-util", "dep:hyper"], + "rkyv": ["dep:rkyv", "dep:bytecheck"], + "tokio-tungstenite": ["dep:tokio-tungstenite"] + }, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:05:19Z", + "v": 2 + } + ] + }, + { + "path": "vi/rt/virtue", + "header": "AwIAAABldGFnOiAiNDU2NjYzNjA5NWM1YmJlZGY1ZmQ3NDMxODkyNGYwYTgiAA==", + "records": [ + { + "name": "virtue", + "vers": "0.0.18", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1", + "features": {}, + "yanked": false, + "pubtime": "2024-11-08T14:20:44Z" + } + ] + }, + { + "path": "wa/i-/wai-bindgen-gen-core", + "header": "AwIAAABldGFnOiAiODI1MmIyOGQ4OTcwMDBiNTdmZDJmMzUzMmU1ZWJhMTYiAA==", + "records": [ + { + "name": "wai-bindgen-gen-core", + "vers": "0.2.3", + "deps": [ + { + "name": "anyhow", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wai-parser", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "1aa3dc41b510811122b3088197234c27e08fcad63ef936306dd8e11e2803876c", + "features": {}, + "yanked": false, + "rust_version": "1.64", + "pubtime": "2023-02-15T17:07:08Z" + } + ] + }, + { + "path": "wa/i-/wai-bindgen-gen-rust", + "header": "AwIAAABldGFnOiAiODZhNDI0ZTNiZjMwMGJhNGMyNGI5ODM2NjEyYTA1OWMiAA==", + "records": [ + { + "name": "wai-bindgen-gen-rust", + "vers": "0.2.3", + "deps": [ + { + "name": "heck", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wai-bindgen-gen-core", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "19bc05e8380515c4337c40ef03b2ff233e391315b178a320de8640703d522efe", + "features": {}, + "yanked": false, + "rust_version": "1.64", + "pubtime": "2023-02-15T17:11:26Z" + } + ] + }, + { + "path": "wa/i-/wai-bindgen-gen-rust-wasm", + "header": "AwIAAABldGFnOiAiMmQ2NWYzZGFmOTRhYjI0ZmMzM2NmOTA4NDc2MDAxNmUiAA==", + "records": [ + { + "name": "wai-bindgen-gen-rust-wasm", + "vers": "0.2.3", + "deps": [ + { + "name": "heck", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "structopt", + "req": "^0.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wai-bindgen-gen-core", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wai-bindgen-gen-rust", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "d6f35ce5e74086fac87f3a7bd50f643f00fe3559adb75c88521ecaa01c8a6199", + "features": {}, + "yanked": false, + "rust_version": "1.64", + "pubtime": "2023-02-15T17:13:15Z" + } + ] + }, + { + "path": "wa/i-/wai-bindgen-rust", + "header": "AwIAAABldGFnOiAiZDJkNjYwYjBjMjRjYThjY2JjNTJmMzhhOGIzMzM4NTAiAA==", + "records": [ + { + "name": "wai-bindgen-rust", + "vers": "0.2.3", + "deps": [ + { + "name": "async-trait", + "req": "^0.1.51", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bitflags", + "req": "^1.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wai-bindgen-rust-impl", + "req": "^0.2.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "4e5601c6f448c063e83a5e931b8fefcdf7e01ada424ad42372c948d2e3d67741", + "features": { + "async": ["async-trait"], + "default": ["macros", "async"], + "macros": ["wai-bindgen-rust-impl"] + }, + "yanked": false, + "rust_version": "1.64", + "pubtime": "2023-02-15T17:18:28Z" + } + ] + }, + { + "path": "wa/i-/wai-bindgen-rust-impl", + "header": "AwIAAABldGFnOiAiOTEyM2ViNDVkMTExODk3YTg2MjRkNzdiMzVhNDU3YTIiAA==", + "records": [ + { + "name": "wai-bindgen-rust-impl", + "vers": "0.2.3", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wai-bindgen-gen-core", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wai-bindgen-gen-rust-wasm", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "bdeeb5c1170246de8425a3e123e7ef260dc05ba2b522a1d369fe2315376efea4", + "features": {}, + "yanked": false, + "rust_version": "1.64", + "pubtime": "2023-02-15T17:18:03Z" + } + ] + }, + { + "path": "wa/i-/wai-parser", + "header": "AwIAAABldGFnOiAiOWEwN2YyMWEyYTcxZWI5MTRlMWYzMGE5NmZmOGUzZTMiAA==", + "records": [ + { + "name": "wai-parser", + "vers": "0.2.3", + "deps": [ + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "id-arena", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pulldown-cmark", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "unicode-normalization", + "req": "^0.1.19", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "unicode-xid", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wast", + "req": "^33", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "9bd0acb6d70885ea0c343749019ba74f015f64a9d30542e66db69b49b7e28186", + "features": {}, + "yanked": false, + "rust_version": "1.64", + "pubtime": "2023-02-15T17:01:46Z" + } + ] + }, + { + "path": "wa/ke/waker-fn", + "header": "AwIAAABldGFnOiAiYjIzYzJkNTE1MWNlMTgwYzUwODM0ZDE2MDVhOTMwYWYiAA==", + "records": [ + { + "name": "waker-fn", + "vers": "1.2.0", + "deps": [ + { + "name": "portable-atomic-util", + "req": "^0.2", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7", + "features": { + "portable-atomic": ["portable-atomic-util"] + }, + "yanked": false, + "rust_version": "1.51", + "pubtime": "2024-05-13T00:24:30Z" + } + ] + }, + { + "path": "wa/lk/walkdir", + "header": "AwIAAABldGFnOiAiYTI2ZWQ2NjQwMDExMTgyZjg4NzAzMThlMTM0NjYxYTEiAA==", + "records": [ + { + "name": "walkdir", + "vers": "2.5.0", + "deps": [ + { + "name": "doc-comment", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "same-file", + "req": "^1.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "winapi-util", + "req": "^0.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b", + "features": {}, + "yanked": false, + "pubtime": "2024-03-01T17:55:09Z" + } + ] + }, + { + "path": "wa/si/wasi", + "header": "AwIAAABldGFnOiAiOWVjMjhjZDI2MzIyMGM4MzNhNGIzYmQ0YThmOWU5MWQiAA==", + "records": [ + { + "name": "wasi", + "vers": "0.11.1+wasi-snapshot-preview1", + "deps": [ + { + "name": "core", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "rustc-std-workspace-alloc", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b", + "features": { + "default": ["std"], + "rustc-dep-of-std": ["core", "rustc-std-workspace-alloc"], + "std": [] + }, + "yanked": false, + "pubtime": "2025-06-10T14:23:45Z" + }, + { + "name": "wasi", + "vers": "0.14.7+wasi-0.2.4", + "deps": [ + { + "name": "wasip2", + "req": "^1.0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c", + "features": { + "bitflags": ["wasip2/bitflags"], + "default": ["wasip2/default"], + "std": ["wasip2/std"] + }, + "yanked": false, + "rust_version": "1.82.0", + "pubtime": "2025-09-15T22:01:38Z" + } + ] + }, + { + "path": "wa/si/wasip2", + "header": "AwIAAABldGFnOiAiMmE1MWY4ZTc1N2NjZGE5NTU5OTVkZWMyODg5ODQ5YzciAA==", + "records": [ + { + "name": "wasip2", + "vers": "1.0.4+wasi-0.2.12", + "deps": [ + { + "name": "alloc", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "core", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "wit-bindgen", + "req": "^0.57.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487", + "features": { + "bitflags": ["wit-bindgen/bitflags"], + "default": ["std", "bitflags"], + "rustc-dep-of-std": ["core", "alloc", "wit-bindgen/rustc-dep-of-std"], + "std": [] + }, + "yanked": false, + "rust_version": "1.87.0", + "pubtime": "2026-06-12T17:42:43Z" + } + ] + }, + { + "path": "wa/si/wasite", + "header": "AwIAAABldGFnOiAiZjlhYzdkZjcyZWM4MjM5NTI2NjRmZGZkZDliZDZiM2IiAA==", + "records": [ + { + "name": "wasite", + "vers": "0.1.0", + "deps": [], + "cksum": "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b", + "features": {}, + "yanked": false, + "pubtime": "2022-12-04T20:03:04Z" + }, + { + "name": "wasite", + "vers": "1.0.2", + "deps": [ + { + "name": "wasi", + "req": ">=0.13, <0.15", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "66fe902b4a6b8028a753d5424909b764ccf79b7a209eac9bf97e59cda9f71a42", + "features": {}, + "yanked": false, + "rust_version": "1.65", + "pubtime": "2026-01-08T04:37:24Z" + } + ] + }, + { + "path": "wa/sm/wasm-bindgen", + "header": "AwIAAABldGFnOiAiNzU5OGQzMjBkOWQwNzJjMzgwMDgzZGU3MGQ5NDY2ZTMiAA==", + "records": [ + { + "name": "wasm-bindgen", + "vers": "0.2.129", + "deps": [ + { + "name": "cfg-if", + "req": "^1.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "once_cell", + "req": "^1.12", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "paste", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "paste", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm64\")", + "kind": "dev" + }, + { + "name": "rustversion-compat", + "req": "^1.0.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build", + "package": "rustversion" + }, + { + "name": "serde", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "serde_derive", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm64\")", + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1", + "features": ["rt", "time", "sync"], + "optional": false, + "default_features": false, + "target": "cfg(all(target_os = \"emscripten\", wasm_bindgen_unstable_tokio))", + "kind": "dev" + }, + { + "name": "wasm-bindgen-macro", + "req": "=0.2.129", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasm-bindgen-shared", + "req": "=0.2.129", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "9bb54f33acc68fd454578d9820b0bde1a1a3d17aa17bb7b6595806d02886d409", + "features": { + "default": ["std"], + "enable-interning": ["std"], + "gg-alloc": [], + "msrv": [], + "rustversion": [], + "serde-serialize": ["serde", "serde_json", "std"], + "spans": [], + "std": [], + "strict-macro": ["wasm-bindgen-macro/strict-macro"], + "xxx_debug_only_print_generated_code": [] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-09-25T07:13:40Z" + } + ] + }, + { + "path": "wa/sm/wasm-bindgen-macro", + "header": "AwIAAABldGFnOiAiMzIwZDcwOWQyZTdmNjllODkxOGIzYzMyNjM2ZWVlOTYiAA==", + "records": [ + { + "name": "wasm-bindgen-macro", + "vers": "0.2.129", + "deps": [ + { + "name": "quote", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "trybuild", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "wasm-bindgen-macro-support", + "req": "=0.2.129", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "2e29d0c35b16e224a7eeb5cd2d25e3e1968fbd65604117b44d3b789d00ee8535", + "features": { + "strict-macro": ["wasm-bindgen-macro-support/strict-macro"] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-09-25T07:13:38Z" + } + ] + }, + { + "path": "wa/sm/wasm-bindgen-macro-support", + "header": "AwIAAABldGFnOiAiY2Y5NjRhOTdjOWZhMTAxOTVlMjhhYjk0ZTBhZmUzMTkiAA==", + "records": [ + { + "name": "wasm-bindgen-macro-support", + "vers": "0.2.129", + "deps": [ + { + "name": "bumpalo", + "req": "^3.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3.0", + "features": ["visit", "visit-mut", "full", "extra-traits"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasm-bindgen-shared", + "req": "=0.2.129", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "6f501a8bc3719dba86ef8ae4728879c08001bea749eb1333ac5b91e040e2a6b7", + "features": { + "extra-traits": ["syn/extra-traits"], + "strict-macro": [] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-09-25T07:13:36Z" + } + ] + }, + { + "path": "wa/sm/wasm-bindgen-shared", + "header": "AwIAAABldGFnOiAiMjU4ZDE1YTg1NTcyM2E3ZGI5MjcyZWYwYTQ2OWUwZGUiAA==", + "records": [ + { + "name": "wasm-bindgen-shared", + "vers": "0.2.129", + "deps": [ + { + "name": "unicode-ident", + "req": "^1.0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "23f0c9c52aa7cd7d77769a4cfe2a9adb1b331f489a41d912ce14513d5ab995c6", + "features": {}, + "yanked": false, + "links": "wasm_bindgen", + "rust_version": "1.81", + "pubtime": "2026-09-25T07:13:33Z" + } + ] + }, + { + "path": "wa/sm/wasm-encoder", + "header": "AwIAAABldGFnOiAiNjEyMGEwZTJmYmNlYzQ2MjVkNmE2Y2RlMDYxNGEyOTUiAA==", + "records": [ + { + "name": "wasm-encoder", + "vers": "0.252.0", + "deps": [ + { + "name": "anyhow", + "req": "^1.0.58", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "leb128fmt", + "req": "^0.1.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "wasmparser", + "req": "^0.252.0", + "features": ["simd", "simd"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmprinter", + "req": "^0.252.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + } + ], + "cksum": "8185ae345fa5687c054626ff9a50e7089797a343d9904d1dc9820eb4c4d3196f", + "features": {}, + "features2": { + "component-model": ["wasmparser?/component-model"], + "default": ["std", "component-model"], + "std": ["wasmparser?/std"] + }, + "yanked": false, + "rust_version": "1.85.0", + "pubtime": "2026-06-12T19:22:40Z", + "v": 2 + } + ] + }, + { + "path": "wa/sm/wasmer", + "header": "AwIAAABldGFnOiAiZDMwMDJhZTA2OTM3ZThkNmVjZWQyYTE4YWU5OTEwMDciAA==", + "records": [ + { + "name": "wasmer", + "vers": "7.2.1", + "deps": [ + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "bindgen", + "req": "^0.72.1", + "features": ["logging", "prettyplease", "static"], + "optional": false, + "default_features": false, + "target": "cfg(target_env = \"musl\")", + "kind": "build" + }, + { + "name": "bindgen", + "req": "^0.72.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_env = \"musl\"))", + "kind": "build" + }, + { + "name": "bytes", + "req": "^1.11.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cmake", + "req": "^0.1.50", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "corosensei", + "req": "^0.3.0", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "crossbeam-channel", + "req": "^0.5.15", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "dashmap", + "req": "^6.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "derive_more", + "req": "^2.0.1", + "features": ["debug", "display", "from", "debug", "unwrap"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures", + "req": "^0.3.30", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "futures", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "hashbrown", + "req": "^0.17.0", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "itertools", + "req": "^0.15", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "js-sys", + "req": "^0.3.77", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "normal" + }, + { + "name": "js-sys", + "req": "^0.3.77", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "loupe", + "req": "^0.2.0", + "features": ["indexmap", "enable-indexmap"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "macro-wasmer-engine-test", + "req": "^7.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "macro-wasmer-engine-test", + "req": "^7.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "more-asserts", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "paste", + "req": "^1.0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rkyv", + "req": "^0.8.13", + "features": ["indexmap-2", "bytes-1"], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "normal" + }, + { + "name": "serde-wasm-bindgen", + "req": "^0.6.5", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "normal" + }, + { + "name": "shared-buffer", + "req": "^0.1.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "symbolic-demangle", + "req": "^13", + "features": ["rust", "cpp", "msvc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tar", + "req": "^0.4.40", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "target-lexicon", + "req": "^0.13.3", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "target-lexicon", + "req": "^0.13.3", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.6.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "tempfile", + "req": "^3.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "thiserror", + "req": "^2.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.39.0", + "features": ["full"], + "optional": false, + "default_features": false, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "tracing", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ureq", + "req": "^3.3.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "wasm-bindgen", + "req": "^0.2.120", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "normal" + }, + { + "name": "wasm-bindgen", + "req": "^0.2.120", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3.70", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "wasmer-compiler", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "normal" + }, + { + "name": "wasmer-compiler", + "req": "=7.2.1", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "wasmer-compiler-cranelift", + "req": "=7.2.1", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "wasmer-compiler-llvm", + "req": "=7.2.1", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "wasmer-compiler-singlepass", + "req": "=7.2.1", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "wasmer-derive", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "wasmer-derive", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "normal" + }, + { + "name": "wasmer-types", + "req": "=7.2.1", + "features": ["std"], + "optional": false, + "default_features": false, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "normal" + }, + { + "name": "wasmer-types", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "wasmer-vm", + "req": "=7.2.1", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "wasmparser", + "req": "^0.252.0", + "features": ["validate", "features", "simd"], + "optional": true, + "default_features": false, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "wasmparser", + "req": "^0.252.0", + "features": ["validate", "features", "simd"], + "optional": true, + "default_features": false, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "normal" + }, + { + "name": "wat", + "req": "^1.252.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wat", + "req": "^1.252.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "wat", + "req": "^1.252.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "which", + "req": "^8.0.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "windows-sys", + "req": "^0.61.2", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(not(target_arch = \"wasm32\"), target_os = \"windows\"))", + "kind": "normal" + }, + { + "name": "xz", + "req": "^0.1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "zip", + "req": "^8.1.0", + "features": ["deflate"], + "optional": true, + "default_features": false, + "target": null, + "kind": "build" + } + ], + "cksum": "05af716b1bf3de5b8081133223f77f37916e9b4f41e0781c7fbe3e0d7b6da43a", + "features": { + "baremetal": ["wasmer-vm/baremetal"], + "core": ["hashbrown"], + "enable-serde": [ + "wasmer-vm/enable-serde", + "wasmer-compiler/enable-serde", + "wasmer-types/enable-serde" + ], + "experimental-host-interrupt": ["wasmer-vm/experimental-host-interrupt"], + "headless": [], + "js": ["wasm-bindgen", "js-sys"], + "js-default": ["js", "std", "wasm-types-polyfill"], + "js-serializable-module": [], + "sanitizer": ["wasmer-vm/sanitizer"], + "static-artifact-create": ["wasmer-compiler/static-artifact-create"], + "static-artifact-load": ["wasmer-compiler/static-artifact-load"], + "std": [], + "wasm-c-api": ["wasm-types-polyfill"], + "wasm-types-polyfill": ["wasmparser"], + "wasmer-artifact-create": ["wasmer-compiler/wasmer-artifact-create"], + "wasmer-artifact-load": ["wasmer-compiler/wasmer-artifact-load"] + }, + "features2": { + "artifact-size": [ + "dep:loupe", + "wasmer-vm/artifact-size", + "wasmer-compiler/artifact-size" + ], + "compiler": [ + "sys", + "dep:wasmer-compiler", + "wasmer-compiler/translator", + "wasmer-compiler/compiler" + ], + "cranelift": ["compiler", "wasmer-compiler-cranelift"], + "default": ["sys-default"], + "experimental-async": ["dep:futures", "dep:corosensei"], + "llvm": ["compiler", "wasmer-compiler-llvm"], + "singlepass": ["compiler", "wasmer-compiler-singlepass"], + "sys": ["std", "dep:wasmer-vm", "dep:wasmer-compiler"], + "sys-default": ["sys", "wat", "cranelift"], + "v8": ["wasm-c-api", "std", "dep:tempfile", "dep:which", "dep:xz", "dep:ureq"], + "v8-default": ["v8", "wat"], + "wat": ["dep:wat", "wasmparser"] + }, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:07:17Z", + "v": 2 + } + ] + }, + { + "path": "wa/sm/wasmer-compiler", + "header": "AwIAAABldGFnOiAiMjEyNTZlMjgzYmNlMDgwNjFlYjNlNTgwZjMxZTQ2ZjIiAA==", + "records": [ + { + "name": "wasmer-compiler", + "vers": "7.2.1", + "deps": [ + { + "name": "backtrace", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytes", + "req": "^1.11.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "crossbeam-channel", + "req": "^0.5.15", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "enum-iterator", + "req": "^2.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "enumset", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hashbrown", + "req": "^0.17.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "itertools", + "req": "^0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "leb128", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.178", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "loupe", + "req": "^0.2.0", + "features": ["indexmap", "enable-indexmap"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "macho-unwind-info", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_os = \"macos\", target_arch = \"aarch64\"))", + "kind": "normal" + }, + { + "name": "memmap2", + "req": "^0.9.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "more-asserts", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "object", + "req": "^0.39.0", + "features": ["write"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rangemap", + "req": "^1.7.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1.7.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "region", + "req": "^3.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "rkyv", + "req": "^0.8.13", + "features": ["indexmap-2", "bytes-1"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "self_cell", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_bytes", + "req": "^0.11", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "shared-buffer", + "req": "^0.1.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "smallvec", + "req": "^1.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "target-lexicon", + "req": "^0.13.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "thiserror", + "req": "^2.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-types", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-vm", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "wasmparser", + "req": "^0.252.0", + "features": ["validate", "features", "simd"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "which", + "req": "^8.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "windows-sys", + "req": "^0.61.2", + "features": ["Win32_System_Diagnostics_Debug"], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"windows\")", + "kind": "normal" + } + ], + "cksum": "99d984ed2ecd52a8e68ea0f4959bc342bf3b2381262105898a8cb416ecd15003", + "features": { + "baremetal": ["wasmer-vm/baremetal"], + "compiler": ["translator"], + "core": ["hashbrown", "wasmer-types/core"], + "default": ["std"], + "enable-serde": ["serde", "serde_bytes", "wasmer-types/enable-serde"], + "static-artifact-create": ["translator", "compiler"], + "static-artifact-load": [], + "std": ["wasmer-types/std"], + "translator": ["wasmparser"], + "wasmer-artifact-create": [], + "wasmer-artifact-load": [] + }, + "features2": { + "artifact-size": ["dep:loupe"] + }, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:05:28Z", + "v": 2 + } + ] + }, + { + "path": "wa/sm/wasmer-config", + "header": "AwIAAABldGFnOiAiN2FlNDNjOTdiMjIzODY1YzY2YmQyNjg4MDNlODg2MWQiAA==", + "records": [ + { + "name": "wasmer-config", + "vers": "0.702.1", + "deps": [ + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytesize", + "req": "^2.3.1", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ciborium", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "derive_builder", + "req": "^0.20.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hex", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pretty_assertions", + "req": "^1.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "saffron", + "req": "^0.1.0", + "features": ["std"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "schemars", + "req": "^1.1.0", + "features": ["url2", "indexmap2"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "semver", + "req": "^1.0", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde_yaml", + "req": "^0.9.34", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "thiserror", + "req": "^2.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "toml", + "req": "^1.1.0", + "features": ["preserve_order"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "url", + "req": "^2.5", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "98700e4516eb825f1ad22cd5273bafd0694941722686010dc1af79b70812393f", + "features": {}, + "yanked": false, + "pubtime": "2026-07-27T11:04:27Z" + } + ] + }, + { + "path": "wa/sm/wasmer-derive", + "header": "AwIAAABldGFnOiAiYjBkNTk4NjVmNGY3MDE1YzM4NzI1YmNkZWRiZGQ1MTQiAA==", + "records": [ + { + "name": "wasmer-derive", + "vers": "7.2.1", + "deps": [ + { + "name": "compiletest_rs", + "req": "^0.11.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro-error2", + "req": "^2.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "proc-macro2", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.20", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2", + "features": ["full", "extra-traits", "derive", "parsing", "proc-macro", "printing"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "882cc3b1909d543b4c5cd84c21d659c9c3608225240a79b68e39554749592b79", + "features": {}, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:05:00Z" + } + ] + }, + { + "path": "wa/sm/wasmer-journal", + "header": "AwIAAABldGFnOiAiYmFjYjk0ZDc1MzJkZjVjNjY0Mzk0ODFhZTU4N2I5YWYiAA==", + "records": [ + { + "name": "wasmer-journal", + "vers": "0.702.1", + "deps": [ + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "async-trait", + "req": "^0.1.68", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "base64", + "req": "^0.22.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bincode", + "req": "=2.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytecheck", + "req": "^0.8.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytes", + "req": "^1.11.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "derive_more", + "req": "^2.0.1", + "features": ["debug", "display"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "lz4_flex", + "req": "^0.13.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "num_enum", + "req": "^0.7.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rkyv", + "req": "^0.8.13", + "features": ["indexmap-2", "bytes-1"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "shared-buffer", + "req": "^0.1.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "thiserror", + "req": "^2.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tracing", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tracing-test", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "virtual-fs", + "req": "^0.702.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "virtual-net", + "req": "^0.702.1", + "features": ["rkyv"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-config", + "req": "=0.702.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-wasix-types", + "req": "^0.702.1", + "features": ["enable-serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "d02acd34af8c89ce772dd492da754dc999d4e3d3f30cbbf11a9c58f5e6c3a659", + "features": { + "default": ["log-file", "wasmer/sys-default"], + "log-file": ["shared-buffer"] + }, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:08:34Z" + } + ] + }, + { + "path": "wa/sm/wasmer-package", + "header": "AwIAAABldGFnOiAiYmYwOTFlYTJiNDI0ZjM1MGFlNTlhNTM5ZjE2OTZmMTciAA==", + "records": [ + { + "name": "wasmer-package", + "vers": "0.702.1", + "deps": [ + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytes", + "req": "^1.11.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ciborium", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "flate2", + "req": "^1.0.34", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hexdump", + "req": "^0.1.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ignore", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "insta", + "req": "^1.45.0", + "features": ["filters", "yaml"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.178", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(all(target_family = \"wasm\", target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "pretty_assertions", + "req": "^1.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "regex", + "req": "^1.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "semver", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sha2", + "req": "^0.11.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "shared-buffer", + "req": "^0.1.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tar", + "req": "^0.4.40", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "thiserror", + "req": "^2.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "toml", + "req": "^1.1.0", + "features": ["preserve_order"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ureq", + "req": "^3.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "url", + "req": "^2.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-config", + "req": "^0.702.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-types", + "req": "^7.2.1", + "features": ["detect-wasm-features"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "webc", + "req": "=12.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "54f12fd1711df6b12ade23b5db433d3f1aae4f31a7580d7db480f2cce03ccdb1", + "features": {}, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:05:10Z" + } + ] + }, + { + "path": "wa/sm/wasmer-types", + "header": "AwIAAABldGFnOiAiZmI0ZmZhYTNjNzk3NmQxMmQyYzljYmRjYWYwN2EzYzUiAA==", + "records": [ + { + "name": "wasmer-types", + "vers": "7.2.1", + "deps": [ + { + "name": "bytecheck", + "req": "^0.8.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "crc32fast", + "req": "^1.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "criterion", + "req": "^0.8.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "enum-iterator", + "req": "^2.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "enumset", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "getrandom", + "req": "^0.4.1", + "features": ["wasm_js"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hex", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "itertools", + "req": "^0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "loupe", + "req": "^0.2.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "memoffset", + "req": "^0.9.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "more-asserts", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rkyv", + "req": "^0.8.13", + "features": ["indexmap-2", "bytes-1"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive", "rc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_bytes", + "req": "^0.11", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sha2", + "req": "^0.11.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "target-lexicon", + "req": "^0.13.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "thiserror", + "req": "^2.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasmparser", + "req": "^0.252.0", + "features": ["validate", "features", "simd"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "87234e5a975dc1343c08692165e01def9725a74cf527277c0e36b0eb66b8f427", + "features": { + "core": [], + "default": ["std"], + "enable-serde": ["serde", "serde/std", "serde_bytes", "indexmap/serde"], + "std": [] + }, + "features2": { + "artifact-size": ["dep:loupe"], + "detect-wasm-features": ["dep:wasmparser"] + }, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:04:17Z", + "v": 2 + } + ] + }, + { + "path": "wa/sm/wasmer-vm", + "header": "AwIAAABldGFnOiAiMTIwYjE5OWMyN2I1MDA3MmQ1NGRkZmE4ODA5YmJlNGYiAA==", + "records": [ + { + "name": "wasmer-vm", + "vers": "7.2.1", + "deps": [ + { + "name": "backtrace", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytesize", + "req": "^2.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cc", + "req": "^1.2.47", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "cfg-if", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "corosensei", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "crossbeam-queue", + "req": "^0.3.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "dashmap", + "req": "^6.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "enum-iterator", + "req": "^2.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "fnv", + "req": "^1.0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "gimli", + "req": "^0.33.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "itertools", + "req": "^0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.178", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "libunwind", + "req": "^1.3.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(target_family = \"unix\", all(target_family = \"windows\", target_env = \"gnu\")))", + "kind": "normal" + }, + { + "name": "loupe", + "req": "^0.2.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "mach2", + "req": "^0.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_vendor = \"apple\")", + "kind": "normal" + }, + { + "name": "memoffset", + "req": "^0.9.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "more-asserts", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "parking_lot", + "req": "^0.12.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "region", + "req": "^3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustversion", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "scopeguard", + "req": "^1.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive", "rc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "thiserror", + "req": "^2.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tracing", + "req": "^0.1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-types", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "windows-sys", + "req": "^0.61.2", + "features": [ + "Win32_System_Diagnostics_Debug", + "Win32_System_Threading", + "Win32_System_Kernel", + "Win32_System_Memory" + ], + "optional": false, + "default_features": false, + "target": "cfg(target_os = \"windows\")", + "kind": "normal" + } + ], + "cksum": "8112dae928ca0d5341180e1ea1418d78bdb3788a78da625a4a3889fe908a91bb", + "features": { + "baremetal": [], + "default": [], + "enable-serde": ["serde", "indexmap/serde", "wasmer-types/enable-serde"], + "experimental-host-interrupt": [], + "sanitizer": ["corosensei/sanitizer"] + }, + "features2": { + "artifact-size": ["dep:loupe", "wasmer-types/artifact-size"] + }, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:04:54Z", + "v": 2 + } + ] + }, + { + "path": "wa/sm/wasmer-wasix", + "header": "AwIAAABldGFnOiAiYmQ4Mzg0MTYzNDU2OTE3OTY5ZDRkZmZkMTliMzYyNTAiAA==", + "records": [ + { + "name": "wasmer-wasix", + "vers": "0.702.1", + "deps": [ + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "assert-panic", + "req": "^1.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "async-trait", + "req": "^0.1.68", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "base64", + "req": "^0.22.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bincode", + "req": "=2.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "blake3", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bus", + "req": "^2.4.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytecheck", + "req": "^0.8.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytes", + "req": "^1.11.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "chrono", + "req": "^0.4.38", + "features": ["wasmbind", "std", "clock"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "ciborium", + "req": "^0.2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "cooked-waker", + "req": "^5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "crossbeam-channel", + "req": "^0.5.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "dashmap", + "req": "^6.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "derive_more", + "req": "^2.0.1", + "features": ["debug", "display"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "dirs", + "req": "^6.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "env_logger", + "req": "^0.11.5", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "flate2", + "req": "^1.0.34", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "fnv", + "req": "^1.0.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "fs_extra", + "req": "^1.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "futures", + "req": "^0.3.30", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "getrandom", + "req": "^0.4.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "getrandom03", + "req": "^0.3.4", + "features": ["wasm_js"], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "normal", + "package": "getrandom" + }, + { + "name": "heapless", + "req": "^0.9.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hex", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "http", + "req": "^1.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "http-body-util", + "req": "^0.1.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hyper", + "req": "^1.8.1", + "features": ["server"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hyper-util", + "req": "^0.1.5", + "features": ["server", "server-graceful", "tokio", "service", "client"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "itertools", + "req": "^0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "js-sys", + "req": "^0.3.77", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2.178", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(unix)", + "kind": "normal" + }, + { + "name": "libtest-mimic", + "req": "^0.8.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "linked_hash_set", + "req": "^0.1.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "log", + "req": "^0.4.22", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "lz4_flex", + "req": "^0.13.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "num_enum", + "req": "^0.7.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "once_cell", + "req": "^1.17.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "petgraph", + "req": "^0.8.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pin-project", + "req": "^1.0.12", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pin-utils", + "req": "^0.1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pretty_assertions", + "req": "^1.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.10.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rayon", + "req": "^1.7.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "reqwest", + "req": "^0.13.0", + "features": ["native-tls", "json", "stream", "socks", "blocking"], + "optional": true, + "default_features": false, + "target": "cfg(any(target_arch = \"riscv64\", target_arch = \"loongarch64\"))", + "kind": "normal" + }, + { + "name": "reqwest", + "req": "^0.13.0", + "features": ["rustls", "json", "stream", "socks", "blocking"], + "optional": true, + "default_features": false, + "target": "cfg(not(any(target_arch = \"riscv64\", target_arch = \"loongarch64\")))", + "kind": "normal" + }, + { + "name": "rkyv", + "req": "^0.8.13", + "features": ["indexmap-2", "bytes-1"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rusty_pool", + "req": "^0.7.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "semver", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_derive", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_yaml", + "req": "^0.9.34", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sha2", + "req": "^0.11.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "shared-buffer", + "req": "^0.1.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "strum", + "req": "^0.28", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tempfile", + "req": "^3.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "terminal_size", + "req": "^0.4.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + }, + { + "name": "termios", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(unix, not(target_os=\"ios\")))", + "kind": "normal" + }, + { + "name": "thiserror", + "req": "^2.0.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.39.0", + "features": ["sync", "macros", "time", "rt"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1.39.0", + "features": ["sync", "macros", "rt"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-stream", + "req": "^0.1", + "features": ["sync"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "toml", + "req": "^1.1.0", + "features": ["preserve_order"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tower", + "req": "^0.5.2", + "features": ["make", "util"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tower-http", + "req": "^0.7.0", + "features": ["trace", "util", "catch-panic", "cors"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tracing", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tracing-subscriber", + "req": "^0.3", + "features": ["env-filter", "fmt"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "tracing-test", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tracing-wasm", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "url", + "req": "^2.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "urlencoding", + "req": "^2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "version-compare", + "req": "^0.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "virtual-fs", + "req": "^0.702.1", + "features": ["webc-fs"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "virtual-mio", + "req": "^0.702.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "virtual-net", + "req": "^0.702.1", + "features": ["rkyv"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "waker-fn", + "req": "^1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "walkdir", + "req": "^2.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasm-bindgen", + "req": "^0.2.120", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasm-bindgen-futures", + "req": "^0.4.70", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3.70", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "wasm-bindgen-test", + "req": "^0.3.70", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "wasm-encoder", + "req": "^0.252.0", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer", + "req": "=7.2.1", + "features": ["experimental-async"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer", + "req": "=7.2.1", + "features": ["wat", "js-serializable-module"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "wasmer", + "req": "=7.2.1", + "features": ["wat", "js-serializable-module", "cranelift"], + "optional": false, + "default_features": false, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "wasmer-config", + "req": "^0.702.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-journal", + "req": "^0.702.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-package", + "req": "^0.702.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-types", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-wasix-types", + "req": "^0.702.1", + "features": ["enable-serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasmparser", + "req": "^0.252.0", + "features": ["validate", "features", "simd"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wcgi", + "req": "^0.3.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wcgi-host", + "req": "^0.3.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "web-sys", + "req": "^0.3.64", + "features": [ + "Request", + "RequestInit", + "Window", + "WorkerGlobalScope", + "RequestMode", + "Response", + "Headers" + ], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "webc", + "req": "=12.0.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "weezl", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "windows-sys", + "req": "^0.61.2", + "features": ["Win32_System_SystemInformation"], + "optional": false, + "default_features": false, + "target": "cfg(windows)", + "kind": "normal" + }, + { + "name": "xxhash-rust", + "req": "^0.8.10", + "features": ["xxh64"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zstd", + "req": "^0.13.2", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "normal" + } + ], + "cksum": "90a93bb66bc9bb1c766d53c68676f8a4f23582b0feef6135c184dfd3bf762e2e", + "features": { + "compiler": [], + "ctrlc": ["tokio/signal"], + "default": ["sys-default"], + "disable-all-logging": ["tracing/release_max_level_off", "tracing/max_level_off"], + "enable-serde": ["wasmer-wasix-types/enable-serde", "wasmer/enable-serde"], + "extra-logging": [], + "host-fs": ["virtual-fs/host-fs"], + "host-reqwest": ["reqwest"], + "host-threads": [], + "host-vnet": ["virtual-net/host-net"], + "journal": ["tokio/fs", "wasmer-journal/log-file"], + "js": [ + "virtual-fs/js", + "getrandom/wasm_js", + "chrono", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wasmer/js-default", + "wasmer/wasm-types-polyfill", + "wasmer/wat", + "wasmer/js-serializable-module" + ], + "js-default": ["js"], + "llvm": ["wasmer/llvm"], + "logging": ["tracing/log"], + "remote-vnet": ["virtual-net/remote"], + "singlepass": ["wasmer/singlepass"], + "sys": [ + "webc/mmap", + "time", + "virtual-mio/sys", + "logging", + "host-fs", + "journal", + "sys-poll", + "sys-thread", + "host-vnet", + "host-threads", + "host-reqwest", + "ctrlc", + "wasmer/wat", + "wasmer/js-serializable-module", + "wasmer/sys", + "wasmer/headless" + ], + "sys-default": ["sys"], + "sys-minimal": ["wasmer/sys", "sys-thread", "tokio/fs"], + "sys-poll": [], + "sys-thread": ["tokio/rt", "tokio/time", "tokio/rt-multi-thread", "rusty_pool"], + "test-js": ["js", "wasmer/wat"], + "time": ["tokio/time"], + "v8": ["wasmer/v8"] + }, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:09:14Z" + } + ] + }, + { + "path": "wa/sm/wasmer-wasix-types", + "header": "AwIAAABldGFnOiAiYWUwYWU3N2IzYTQxMjQyMjc1MmNlMzdmNTdkM2I0NzgiAA==", + "records": [ + { + "name": "wasmer-wasix-types", + "vers": "0.702.1", + "deps": [ + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bitflags", + "req": "^2.11.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "byteorder", + "req": "^1.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "num_enum", + "req": "^0.7.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pretty_assertions", + "req": "^1.4.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "time", + "req": "^0.3.47", + "features": ["formatting"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tracing", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wai-bindgen-gen-core", + "req": "^0.2.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wai-bindgen-gen-rust", + "req": "^0.2.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wai-bindgen-gen-rust-wasm", + "req": "^0.2.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wai-bindgen-rust", + "req": "^0.2.1", + "features": ["macros"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wai-parser", + "req": "^0.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-derive", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wasmer-types", + "req": "=7.2.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "f982c57b8ccfcb6bc6f7d7ba420bf53a2099ea9c77135b45cdf45198a00c90db", + "features": { + "enable-serde": ["serde", "wasmer-types/serde"] + }, + "yanked": false, + "rust_version": "1.93", + "pubtime": "2026-07-27T11:08:04Z" + } + ] + }, + { + "path": "wa/sm/wasmparser", + "header": "AwIAAABldGFnOiAiNWIzNGJmNGZiZDVkYjg3MWFiNDAyNjg3ZDllMDA2NzUiAA==", + "records": [ + { + "name": "wasmparser", + "vers": "0.252.0", + "deps": [ + { + "name": "anyhow", + "req": "^1.0.58", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "bitflags", + "req": "^2.4.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "criterion", + "req": "^0.7.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "env_logger", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "hashbrown", + "req": "^0.17.0", + "features": ["default-hasher"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2.14.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "log", + "req": "^0.4.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "once_cell", + "req": "^1.13.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rayon", + "req": "^1.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "semver", + "req": "^1.0.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.166", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "d3eb099dcadcde5be9eef55e3a337128efd4e44b4c93122487e4d2e4e1c6627c", + "features": { + "features": [], + "prefer-btree-collections": [], + "simd": [], + "try-op": [], + "validate": [] + }, + "features2": { + "component-model": ["dep:semver"], + "default": [ + "std", + "validate", + "serde", + "features", + "component-model", + "hash-collections", + "simd" + ], + "hash-collections": ["dep:hashbrown", "dep:indexmap"], + "serde": ["dep:serde", "indexmap?/serde", "hashbrown?/serde"], + "std": ["indexmap?/std"] + }, + "yanked": false, + "rust_version": "1.85.0", + "pubtime": "2026-06-12T19:22:35Z", + "v": 2 + } + ] + }, + { + "path": "we/b-/web-sys", + "header": "AwIAAABldGFnOiAiOTAwZWQyZWM5ODVkMzM5MzdkNDg1YTEzZmQ5ZmNiMTciAA==", + "records": [ + { + "name": "web-sys", + "vers": "0.3.106", + "deps": [ + { + "name": "futures", + "req": "^0.3", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(target_arch = \"wasm32\")", + "kind": "dev" + }, + { + "name": "js-sys", + "req": "=0.3.106", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "wasm-bindgen", + "req": "=0.2.129", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "88261b9deccee56594c11a3460c462c41f58d148598fe70ad77070126a68aba4", + "features": { + "AbortController": [], + "AbortSignal": ["EventTarget"], + "AbstractRange": [], + "AddEventListenerOptions": [], + "AesCbcParams": [], + "AesCtrParams": [], + "AesDerivedKeyParams": [], + "AesGcmParams": [], + "AesKeyAlgorithm": [], + "AesKeyGenParams": [], + "Algorithm": [], + "AlignSetting": [], + "AllowedBluetoothDevice": [], + "AllowedUsbDevice": [], + "AlphaOption": [], + "AnalyserNode": ["AudioNode", "EventTarget"], + "AnalyserOptions": [], + "AngleInstancedArrays": [], + "Animation": ["EventTarget"], + "AnimationEffect": [], + "AnimationEvent": ["Event"], + "AnimationEventInit": [], + "AnimationPlayState": [], + "AnimationPlaybackEvent": ["Event"], + "AnimationPlaybackEventInit": [], + "AnimationPropertyDetails": [], + "AnimationPropertyValueDetails": [], + "AnimationTimeline": [], + "AssignedNodesOptions": [], + "AttestationConveyancePreference": [], + "Attr": ["EventTarget", "Node"], + "AttributeNameValue": [], + "AudioBuffer": [], + "AudioBufferOptions": [], + "AudioBufferSourceNode": ["AudioNode", "AudioScheduledSourceNode", "EventTarget"], + "AudioBufferSourceOptions": [], + "AudioConfiguration": [], + "AudioContext": ["BaseAudioContext", "EventTarget"], + "AudioContextLatencyCategory": [], + "AudioContextOptions": [], + "AudioContextState": [], + "AudioData": [], + "AudioDataCopyToOptions": [], + "AudioDataInit": [], + "AudioDecoder": ["EventTarget"], + "AudioDecoderConfig": [], + "AudioDecoderInit": [], + "AudioDecoderSupport": [], + "AudioDestinationNode": ["AudioNode", "EventTarget"], + "AudioEncoder": ["EventTarget"], + "AudioEncoderConfig": [], + "AudioEncoderInit": [], + "AudioEncoderSupport": [], + "AudioListener": [], + "AudioNode": ["EventTarget"], + "AudioNodeOptions": [], + "AudioParam": [], + "AudioParamMap": [], + "AudioProcessingEvent": ["Event"], + "AudioSampleFormat": [], + "AudioScheduledSourceNode": ["AudioNode", "EventTarget"], + "AudioSinkInfo": [], + "AudioSinkOptions": [], + "AudioSinkType": [], + "AudioStreamTrack": ["EventTarget", "MediaStreamTrack"], + "AudioTrack": [], + "AudioTrackList": ["EventTarget"], + "AudioWorklet": ["Worklet"], + "AudioWorkletGlobalScope": ["WorkletGlobalScope"], + "AudioWorkletNode": ["AudioNode", "EventTarget"], + "AudioWorkletNodeOptions": [], + "AudioWorkletProcessor": [], + "AuthenticationExtensionsClientInputs": [], + "AuthenticationExtensionsClientInputsJson": [], + "AuthenticationExtensionsClientOutputs": [], + "AuthenticationExtensionsClientOutputsJson": [], + "AuthenticationExtensionsDevicePublicKeyInputs": [], + "AuthenticationExtensionsDevicePublicKeyOutputs": [], + "AuthenticationExtensionsLargeBlobInputs": [], + "AuthenticationExtensionsLargeBlobOutputs": [], + "AuthenticationExtensionsPrfInputs": [], + "AuthenticationExtensionsPrfOutputs": [], + "AuthenticationExtensionsPrfValues": [], + "AuthenticationResponseJson": [], + "AuthenticatorAssertionResponse": ["AuthenticatorResponse"], + "AuthenticatorAssertionResponseJson": [], + "AuthenticatorAttachment": [], + "AuthenticatorAttestationResponse": ["AuthenticatorResponse"], + "AuthenticatorAttestationResponseJson": [], + "AuthenticatorResponse": [], + "AuthenticatorSelectionCriteria": [], + "AuthenticatorTransport": [], + "AutoKeyword": [], + "AutocompleteInfo": [], + "BarProp": [], + "BaseAudioContext": ["EventTarget"], + "BaseComputedKeyframe": [], + "BaseKeyframe": [], + "BasePropertyIndexedKeyframe": [], + "BasicCardRequest": [], + "BasicCardResponse": [], + "BasicCardType": [], + "BatteryManager": ["EventTarget"], + "BeforeUnloadEvent": ["Event"], + "BinaryType": [], + "BiquadFilterNode": ["AudioNode", "EventTarget"], + "BiquadFilterOptions": [], + "BiquadFilterType": [], + "BitrateMode": [], + "Blob": [], + "BlobEvent": ["Event"], + "BlobEventInit": [], + "BlobPropertyBag": [], + "BlockParsingOptions": [], + "Bluetooth": ["EventTarget"], + "BluetoothAdvertisingEvent": ["Event"], + "BluetoothAdvertisingEventInit": [], + "BluetoothCharacteristicProperties": [], + "BluetoothDataFilterInit": [], + "BluetoothDevice": ["EventTarget"], + "BluetoothLeScanFilterInit": [], + "BluetoothManufacturerDataMap": [], + "BluetoothPermissionDescriptor": [], + "BluetoothPermissionResult": ["EventTarget", "PermissionStatus"], + "BluetoothPermissionStorage": [], + "BluetoothRemoteGattCharacteristic": ["EventTarget"], + "BluetoothRemoteGattDescriptor": [], + "BluetoothRemoteGattServer": [], + "BluetoothRemoteGattService": ["EventTarget"], + "BluetoothServiceDataMap": [], + "BluetoothUuid": [], + "BoxQuadOptions": [], + "BroadcastChannel": ["EventTarget"], + "BrowserElementDownloadOptions": [], + "BrowserElementExecuteScriptOptions": [], + "BrowserFeedWriter": [], + "BrowserFindCaseSensitivity": [], + "BrowserFindDirection": [], + "ByteLengthQueuingStrategy": [], + "Cache": [], + "CacheBatchOperation": [], + "CacheQueryOptions": [], + "CacheStorage": [], + "CacheStorageNamespace": [], + "CanvasCaptureMediaStream": ["EventTarget", "MediaStream"], + "CanvasCaptureMediaStreamTrack": ["EventTarget", "MediaStreamTrack"], + "CanvasGradient": [], + "CanvasPattern": [], + "CanvasRenderingContext2d": [], + "CanvasWindingRule": [], + "CaretChangedReason": [], + "CaretPosition": [], + "CaretStateChangedEventInit": [], + "CdataSection": ["CharacterData", "EventTarget", "Node", "Text"], + "ChannelCountMode": [], + "ChannelInterpretation": [], + "ChannelMergerNode": ["AudioNode", "EventTarget"], + "ChannelMergerOptions": [], + "ChannelSplitterNode": ["AudioNode", "EventTarget"], + "ChannelSplitterOptions": [], + "CharacterData": ["EventTarget", "Node"], + "CheckerboardReason": [], + "CheckerboardReport": [], + "CheckerboardReportService": [], + "ChromeFilePropertyBag": [], + "ChromeWorker": ["EventTarget", "Worker"], + "Client": [], + "ClientQueryOptions": [], + "ClientRectsAndTexts": [], + "ClientType": [], + "Clients": [], + "Clipboard": ["EventTarget"], + "ClipboardEvent": ["Event"], + "ClipboardEventInit": [], + "ClipboardItem": [], + "ClipboardItemOptions": [], + "ClipboardPermissionDescriptor": [], + "ClipboardUnsanitizedFormats": [], + "CloseEvent": ["Event"], + "CloseEventInit": [], + "CodecState": [], + "CollectedClientData": [], + "ColorSpaceConversion": [], + "CommandEvent": ["Event"], + "CommandEventInit": [], + "Comment": ["CharacterData", "EventTarget", "Node"], + "CompositeOperation": [], + "CompositionEvent": ["Event", "UiEvent"], + "CompositionEventInit": [], + "CompressionFormat": [], + "CompressionStream": [], + "ComputedEffectTiming": [], + "ConnStatusDict": [], + "ConnectionType": [], + "ConsoleCounter": [], + "ConsoleCounterError": [], + "ConsoleEvent": [], + "ConsoleInstance": [], + "ConsoleInstanceOptions": [], + "ConsoleLevel": [], + "ConsoleLogLevel": [], + "ConsoleProfileEvent": [], + "ConsoleStackEntry": [], + "ConsoleTimerError": [], + "ConsoleTimerLogOrEnd": [], + "ConsoleTimerStart": [], + "ConstantSourceNode": ["AudioNode", "AudioScheduledSourceNode", "EventTarget"], + "ConstantSourceOptions": [], + "ConstrainBooleanParameters": [], + "ConstrainDomStringParameters": [], + "ConstrainDoubleRange": [], + "ConstrainLongRange": [], + "ContextAttributes2d": [], + "ConvertCoordinateOptions": [], + "ConvolverNode": ["AudioNode", "EventTarget"], + "ConvolverOptions": [], + "CookieChangeEvent": ["Event"], + "CookieChangeEventInit": [], + "CookieInit": [], + "CookieListItem": [], + "CookieSameSite": [], + "CookieStore": ["EventTarget"], + "CookieStoreDeleteOptions": [], + "CookieStoreGetOptions": [], + "CookieStoreManager": [], + "Coordinates": [], + "CountQueuingStrategy": [], + "Credential": [], + "CredentialCreationOptions": [], + "CredentialPropertiesOutput": [], + "CredentialRequestOptions": [], + "CredentialsContainer": [], + "Crypto": [], + "CryptoKey": [], + "CryptoKeyPair": [], + "CssAnimation": ["Animation", "EventTarget"], + "CssBoxType": [], + "CssConditionRule": ["CssGroupingRule", "CssRule"], + "CssCounterStyleRule": ["CssRule"], + "CssFontFaceRule": ["CssRule"], + "CssFontFeatureValuesRule": ["CssRule"], + "CssGroupingRule": ["CssRule"], + "CssImportRule": ["CssRule"], + "CssKeyframeRule": ["CssRule"], + "CssKeyframesRule": ["CssRule"], + "CssMediaRule": ["CssConditionRule", "CssGroupingRule", "CssRule"], + "CssNamespaceRule": ["CssRule"], + "CssPageRule": ["CssRule"], + "CssPseudoElement": [], + "CssRule": [], + "CssRuleList": [], + "CssStyleDeclaration": [], + "CssStyleRule": ["CssRule"], + "CssStyleSheet": ["StyleSheet"], + "CssStyleSheetParsingMode": [], + "CssSupportsRule": ["CssConditionRule", "CssGroupingRule", "CssRule"], + "CssTransition": ["Animation", "EventTarget"], + "CssViewTransitionRule": ["CssRule"], + "CustomElementRegistry": [], + "CustomEvent": ["Event"], + "CustomEventInit": [], + "DataTransfer": [], + "DataTransferItem": [], + "DataTransferItemList": [], + "DateTimeValue": [], + "DecoderDoctorNotification": [], + "DecoderDoctorNotificationType": [], + "DecompressionStream": [], + "DedicatedWorkerGlobalScope": ["EventTarget", "WorkerGlobalScope"], + "DelayNode": ["AudioNode", "EventTarget"], + "DelayOptions": [], + "DeviceAcceleration": [], + "DeviceAccelerationInit": [], + "DeviceLightEvent": ["Event"], + "DeviceLightEventInit": [], + "DeviceMotionEvent": ["Event"], + "DeviceMotionEventInit": [], + "DeviceOrientationEvent": ["Event"], + "DeviceOrientationEventInit": [], + "DeviceProximityEvent": ["Event"], + "DeviceProximityEventInit": [], + "DeviceRotationRate": [], + "DeviceRotationRateInit": [], + "DhKeyDeriveParams": [], + "DirectionSetting": [], + "Directory": [], + "DirectoryPickerOptions": [], + "DisplayMediaStreamConstraints": [], + "DisplayNameOptions": [], + "DisplayNameResult": [], + "DistanceModelType": [], + "DnsCacheDict": [], + "DnsCacheEntry": [], + "DnsLookupDict": [], + "Document": ["EventTarget", "Node"], + "DocumentFragment": ["EventTarget", "Node"], + "DocumentTimeline": ["AnimationTimeline"], + "DocumentTimelineOptions": [], + "DocumentType": ["EventTarget", "Node"], + "DomError": [], + "DomException": [], + "DomImplementation": [], + "DomMatrix": ["DomMatrixReadOnly"], + "DomMatrix2dInit": [], + "DomMatrixInit": [], + "DomMatrixReadOnly": [], + "DomParser": [], + "DomPoint": ["DomPointReadOnly"], + "DomPointInit": [], + "DomPointReadOnly": [], + "DomQuad": [], + "DomQuadInit": [], + "DomQuadJson": [], + "DomRect": ["DomRectReadOnly"], + "DomRectInit": [], + "DomRectList": [], + "DomRectReadOnly": [], + "DomRequest": ["EventTarget"], + "DomRequestReadyState": [], + "DomStringList": [], + "DomStringMap": [], + "DomTokenList": [], + "DomWindowResizeEventDetail": [], + "DoubleRange": [], + "DragEvent": ["Event", "MouseEvent", "UiEvent"], + "DragEventInit": [], + "DynamicsCompressorNode": ["AudioNode", "EventTarget"], + "DynamicsCompressorOptions": [], + "EcKeyAlgorithm": [], + "EcKeyGenParams": [], + "EcKeyImportParams": [], + "EcdhKeyDeriveParams": [], + "EcdsaParams": [], + "EffectTiming": [], + "Element": ["EventTarget", "Node"], + "ElementCreationOptions": [], + "ElementDefinitionOptions": [], + "EncodedAudioChunk": [], + "EncodedAudioChunkInit": [], + "EncodedAudioChunkMetadata": [], + "EncodedAudioChunkType": [], + "EncodedVideoChunk": [], + "EncodedVideoChunkInit": [], + "EncodedVideoChunkMetadata": [], + "EncodedVideoChunkType": [], + "EndingTypes": [], + "ErrorCallback": [], + "ErrorEvent": ["Event"], + "ErrorEventInit": [], + "Event": [], + "EventInit": [], + "EventListener": [], + "EventListenerOptions": [], + "EventModifierInit": [], + "EventSource": ["EventTarget"], + "EventSourceInit": [], + "EventTarget": [], + "Exception": [], + "ExtBlendMinmax": [], + "ExtColorBufferFloat": [], + "ExtColorBufferHalfFloat": [], + "ExtDisjointTimerQuery": [], + "ExtFragDepth": [], + "ExtPolygonOffsetClamp": [], + "ExtSRgb": [], + "ExtShaderTextureLod": [], + "ExtTextureFilterAnisotropic": [], + "ExtTextureNorm16": [], + "ExtendableCookieChangeEvent": ["Event", "ExtendableEvent"], + "ExtendableCookieChangeEventInit": [], + "ExtendableEvent": ["Event"], + "ExtendableEventInit": [], + "ExtendableMessageEvent": ["Event", "ExtendableEvent"], + "ExtendableMessageEventInit": [], + "External": [], + "FakePluginMimeEntry": [], + "FakePluginTagInit": [], + "FetchEvent": ["Event", "ExtendableEvent"], + "FetchEventInit": [], + "FetchObserver": ["EventTarget"], + "FetchReadableStreamReadDataArray": [], + "FetchReadableStreamReadDataDone": [], + "FetchState": [], + "File": ["Blob"], + "FileCallback": [], + "FileList": [], + "FilePickerAcceptType": [], + "FilePickerOptions": [], + "FilePropertyBag": [], + "FileReader": ["EventTarget"], + "FileReaderSync": [], + "FileSystem": [], + "FileSystemCreateWritableOptions": [], + "FileSystemDirectoryEntry": ["FileSystemEntry"], + "FileSystemDirectoryHandle": ["FileSystemHandle"], + "FileSystemDirectoryReader": [], + "FileSystemEntriesCallback": [], + "FileSystemEntry": [], + "FileSystemEntryCallback": [], + "FileSystemFileEntry": ["FileSystemEntry"], + "FileSystemFileHandle": ["FileSystemHandle"], + "FileSystemFlags": [], + "FileSystemGetDirectoryOptions": [], + "FileSystemGetFileOptions": [], + "FileSystemHandle": [], + "FileSystemHandleKind": [], + "FileSystemHandlePermissionDescriptor": [], + "FileSystemPermissionDescriptor": [], + "FileSystemPermissionMode": [], + "FileSystemReadWriteOptions": [], + "FileSystemRemoveOptions": [], + "FileSystemSyncAccessHandle": [], + "FileSystemSyncAccessHandleMode": [], + "FileSystemSyncAccessHandleOptions": [], + "FileSystemWritableFileStream": ["WritableStream"], + "FillLightMode": [], + "FillMode": [], + "FlashClassification": [], + "FlowControlType": [], + "FocusEvent": ["Event", "UiEvent"], + "FocusEventInit": [], + "FocusOptions": [], + "FontData": [], + "FontFace": [], + "FontFaceDescriptors": [], + "FontFaceLoadStatus": [], + "FontFaceSet": ["EventTarget"], + "FontFaceSetIterator": [], + "FontFaceSetIteratorResult": [], + "FontFaceSetLoadEvent": ["Event"], + "FontFaceSetLoadEventInit": [], + "FontFaceSetLoadStatus": [], + "FormData": [], + "FrameType": [], + "FuzzingFunctions": [], + "GainNode": ["AudioNode", "EventTarget"], + "GainOptions": [], + "Gamepad": [], + "GamepadButton": [], + "GamepadEffectParameters": [], + "GamepadEvent": ["Event"], + "GamepadEventInit": [], + "GamepadHand": [], + "GamepadHapticActuator": [], + "GamepadHapticActuatorType": [], + "GamepadHapticEffectType": [], + "GamepadHapticsResult": [], + "GamepadMappingType": [], + "GamepadPose": [], + "GamepadTouch": [], + "Geolocation": [], + "GeolocationCoordinates": [], + "GeolocationPosition": [], + "GeolocationPositionError": [], + "GestureEvent": ["Event", "UiEvent"], + "GetAnimationsOptions": [], + "GetRootNodeOptions": [], + "GetUserMediaRequest": [], + "Gpu": [], + "GpuAdapter": [], + "GpuAdapterInfo": [], + "GpuAddressMode": [], + "GpuAutoLayoutMode": [], + "GpuBindGroup": [], + "GpuBindGroupDescriptor": [], + "GpuBindGroupEntry": [], + "GpuBindGroupLayout": [], + "GpuBindGroupLayoutDescriptor": [], + "GpuBindGroupLayoutEntry": [], + "GpuBlendComponent": [], + "GpuBlendFactor": [], + "GpuBlendOperation": [], + "GpuBlendState": [], + "GpuBuffer": [], + "GpuBufferBinding": [], + "GpuBufferBindingLayout": [], + "GpuBufferBindingType": [], + "GpuBufferDescriptor": [], + "GpuBufferMapState": [], + "GpuCanvasAlphaMode": [], + "GpuCanvasConfiguration": [], + "GpuCanvasContext": [], + "GpuCanvasToneMapping": [], + "GpuCanvasToneMappingMode": [], + "GpuColorDict": [], + "GpuColorTargetState": [], + "GpuCommandBuffer": [], + "GpuCommandBufferDescriptor": [], + "GpuCommandEncoder": [], + "GpuCommandEncoderDescriptor": [], + "GpuCompareFunction": [], + "GpuCompilationInfo": [], + "GpuCompilationMessage": [], + "GpuCompilationMessageType": [], + "GpuComputePassDescriptor": [], + "GpuComputePassEncoder": [], + "GpuComputePassTimestampWrites": [], + "GpuComputePipeline": [], + "GpuComputePipelineDescriptor": [], + "GpuCopyExternalImageDestInfo": [], + "GpuCopyExternalImageSourceInfo": [], + "GpuCullMode": [], + "GpuDepthStencilState": [], + "GpuDevice": ["EventTarget"], + "GpuDeviceDescriptor": [], + "GpuDeviceLostInfo": [], + "GpuDeviceLostReason": [], + "GpuError": [], + "GpuErrorFilter": [], + "GpuExtent3dDict": [], + "GpuExternalTexture": [], + "GpuExternalTextureBindingLayout": [], + "GpuExternalTextureDescriptor": [], + "GpuFeatureName": [], + "GpuFilterMode": [], + "GpuFragmentState": [], + "GpuFrontFace": [], + "GpuIndexFormat": [], + "GpuInternalError": ["GpuError"], + "GpuLoadOp": [], + "GpuMipmapFilterMode": [], + "GpuMultisampleState": [], + "GpuObjectDescriptorBase": [], + "GpuOrigin2dDict": [], + "GpuOrigin3dDict": [], + "GpuOutOfMemoryError": ["GpuError"], + "GpuPipelineDescriptorBase": [], + "GpuPipelineError": ["DomException"], + "GpuPipelineErrorInit": [], + "GpuPipelineErrorReason": [], + "GpuPipelineLayout": [], + "GpuPipelineLayoutDescriptor": [], + "GpuPowerPreference": [], + "GpuPrimitiveState": [], + "GpuPrimitiveTopology": [], + "GpuProgrammableStage": [], + "GpuQuerySet": [], + "GpuQuerySetDescriptor": [], + "GpuQueryType": [], + "GpuQueue": [], + "GpuQueueDescriptor": [], + "GpuRenderBundle": [], + "GpuRenderBundleDescriptor": [], + "GpuRenderBundleEncoder": [], + "GpuRenderBundleEncoderDescriptor": [], + "GpuRenderPassColorAttachment": [], + "GpuRenderPassDepthStencilAttachment": [], + "GpuRenderPassDescriptor": [], + "GpuRenderPassEncoder": [], + "GpuRenderPassLayout": [], + "GpuRenderPassTimestampWrites": [], + "GpuRenderPipeline": [], + "GpuRenderPipelineDescriptor": [], + "GpuRequestAdapterOptions": [], + "GpuSampler": [], + "GpuSamplerBindingLayout": [], + "GpuSamplerBindingType": [], + "GpuSamplerDescriptor": [], + "GpuShaderModule": [], + "GpuShaderModuleCompilationHint": [], + "GpuShaderModuleDescriptor": [], + "GpuStencilFaceState": [], + "GpuStencilOperation": [], + "GpuStorageTextureAccess": [], + "GpuStorageTextureBindingLayout": [], + "GpuStoreOp": [], + "GpuSupportedFeatures": [], + "GpuSupportedLimits": [], + "GpuTexelCopyBufferInfo": [], + "GpuTexelCopyBufferLayout": [], + "GpuTexelCopyTextureInfo": [], + "GpuTexture": [], + "GpuTextureAspect": [], + "GpuTextureBindingLayout": [], + "GpuTextureDescriptor": [], + "GpuTextureDimension": [], + "GpuTextureFormat": [], + "GpuTextureSampleType": [], + "GpuTextureView": [], + "GpuTextureViewDescriptor": [], + "GpuTextureViewDimension": [], + "GpuUncapturedErrorEvent": ["Event"], + "GpuUncapturedErrorEventInit": [], + "GpuValidationError": ["GpuError"], + "GpuVertexAttribute": [], + "GpuVertexBufferLayout": [], + "GpuVertexFormat": [], + "GpuVertexState": [], + "GpuVertexStepMode": [], + "GroupedHistoryEventInit": [], + "HalfOpenInfoDict": [], + "HardwareAcceleration": [], + "HashChangeEvent": ["Event"], + "HashChangeEventInit": [], + "Headers": [], + "HeadersGuardEnum": [], + "Hid": ["EventTarget"], + "HidCollectionInfo": [], + "HidConnectionEvent": ["Event"], + "HidConnectionEventInit": [], + "HidDevice": ["EventTarget"], + "HidDeviceFilter": [], + "HidDeviceRequestOptions": [], + "HidInputReportEvent": ["Event"], + "HidInputReportEventInit": [], + "HidReportInfo": [], + "HidReportItem": [], + "HidUnitSystem": [], + "HiddenPluginEventInit": [], + "Highlight": [], + "HighlightHitResult": [], + "HighlightRegistry": [], + "HighlightType": [], + "HighlightsFromPointOptions": [], + "History": [], + "HitRegionOptions": [], + "HkdfParams": [], + "HmacDerivedKeyParams": [], + "HmacImportParams": [], + "HmacKeyAlgorithm": [], + "HmacKeyGenParams": [], + "HtmlAllCollection": [], + "HtmlAnchorElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlAreaElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlAudioElement": [ + "Element", + "EventTarget", + "HtmlElement", + "HtmlMediaElement", + "Node" + ], + "HtmlBaseElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlBodyElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlBrElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlButtonElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlCanvasElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlCollection": [], + "HtmlDListElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlDataElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlDataListElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlDetailsElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlDialogElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlDirectoryElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlDivElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlDocument": ["Document", "EventTarget", "Node"], + "HtmlElement": ["Element", "EventTarget", "Node"], + "HtmlEmbedElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlFieldSetElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlFontElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlFormControlsCollection": ["HtmlCollection"], + "HtmlFormElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlFrameElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlFrameSetElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlHeadElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlHeadingElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlHrElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlHtmlElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlIFrameElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlImageElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlInputElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlLabelElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlLegendElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlLiElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlLinkElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlMapElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlMediaElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlMenuElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlMenuItemElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlMetaElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlMeterElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlModElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlOListElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlObjectElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlOptGroupElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlOptionElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlOptionsCollection": ["HtmlCollection"], + "HtmlOutputElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlParagraphElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlParamElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlPictureElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlPreElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlProgressElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlQuoteElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlScriptElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlSelectElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlSlotElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlSourceElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlSpanElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlStyleElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlTableCaptionElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlTableCellElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlTableColElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlTableElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlTableRowElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlTableSectionElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlTemplateElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlTextAreaElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlTimeElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlTitleElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlTrackElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlUListElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlUnknownElement": ["Element", "EventTarget", "HtmlElement", "Node"], + "HtmlVideoElement": [ + "Element", + "EventTarget", + "HtmlElement", + "HtmlMediaElement", + "Node" + ], + "HttpConnDict": [], + "HttpConnInfo": [], + "HttpConnectionElement": [], + "IdbCursor": [], + "IdbCursorDirection": [], + "IdbCursorWithValue": ["IdbCursor"], + "IdbDatabase": ["EventTarget"], + "IdbFactory": [], + "IdbFileHandle": ["EventTarget"], + "IdbFileMetadataParameters": [], + "IdbFileRequest": ["DomRequest", "EventTarget"], + "IdbIndex": [], + "IdbIndexParameters": [], + "IdbKeyRange": [], + "IdbLocaleAwareKeyRange": ["IdbKeyRange"], + "IdbMutableFile": ["EventTarget"], + "IdbObjectStore": [], + "IdbObjectStoreParameters": [], + "IdbOpenDbOptions": [], + "IdbOpenDbRequest": ["EventTarget", "IdbRequest"], + "IdbRequest": ["EventTarget"], + "IdbRequestReadyState": [], + "IdbTransaction": ["EventTarget"], + "IdbTransactionDurability": [], + "IdbTransactionMode": [], + "IdbTransactionOptions": [], + "IdbVersionChangeEvent": ["Event"], + "IdbVersionChangeEventInit": [], + "IdleDeadline": [], + "IdleRequestOptions": [], + "IirFilterNode": ["AudioNode", "EventTarget"], + "IirFilterOptions": [], + "ImageBitmap": [], + "ImageBitmapOptions": [], + "ImageBitmapRenderingContext": [], + "ImageCapture": [], + "ImageCaptureError": [], + "ImageCaptureErrorEvent": ["Event"], + "ImageCaptureErrorEventInit": [], + "ImageData": [], + "ImageDecodeOptions": [], + "ImageDecodeResult": [], + "ImageDecoder": [], + "ImageDecoderInit": [], + "ImageEncodeOptions": [], + "ImageOrientation": [], + "ImageTrack": [], + "ImageTrackList": [], + "InputDeviceInfo": ["MediaDeviceInfo"], + "InputEvent": ["Event", "UiEvent"], + "InputEventInit": [], + "IntersectionObserver": [], + "IntersectionObserverEntry": [], + "IntersectionObserverEntryInit": [], + "IntersectionObserverInit": [], + "IntlUtils": [], + "IsInputPendingOptions": [], + "IterableKeyAndValueResult": [], + "IterableKeyOrValueResult": [], + "IterationCompositeOperation": [], + "JsonWebKey": [], + "KeyAlgorithm": [], + "KeyEvent": [], + "KeyFrameRequestEvent": ["Event"], + "KeyIdsInitData": [], + "KeyboardEvent": ["Event", "UiEvent"], + "KeyboardEventInit": [], + "KeyframeAnimationOptions": [], + "KeyframeEffect": ["AnimationEffect"], + "KeyframeEffectOptions": [], + "L10nElement": [], + "L10nValue": [], + "LargeBlobSupport": [], + "LatencyMode": [], + "LifecycleCallbacks": [], + "LineAlignSetting": [], + "ListBoxObject": [], + "LocalMediaStream": ["EventTarget", "MediaStream"], + "LocaleInfo": [], + "Location": [], + "Lock": [], + "LockInfo": [], + "LockManager": [], + "LockManagerSnapshot": [], + "LockMode": [], + "LockOptions": [], + "MathMlElement": ["Element", "EventTarget", "Node"], + "MediaCapabilities": [], + "MediaCapabilitiesInfo": [], + "MediaConfiguration": [], + "MediaDecodingConfiguration": [], + "MediaDecodingType": [], + "MediaDeviceInfo": [], + "MediaDeviceKind": [], + "MediaDevices": ["EventTarget"], + "MediaElementAudioSourceNode": ["AudioNode", "EventTarget"], + "MediaElementAudioSourceOptions": [], + "MediaEncodingConfiguration": [], + "MediaEncodingType": [], + "MediaEncryptedEvent": ["Event"], + "MediaError": [], + "MediaImage": [], + "MediaKeyError": ["Event"], + "MediaKeyMessageEvent": ["Event"], + "MediaKeyMessageEventInit": [], + "MediaKeyMessageType": [], + "MediaKeyNeededEventInit": [], + "MediaKeySession": ["EventTarget"], + "MediaKeySessionType": [], + "MediaKeyStatus": [], + "MediaKeyStatusMap": [], + "MediaKeySystemAccess": [], + "MediaKeySystemConfiguration": [], + "MediaKeySystemMediaCapability": [], + "MediaKeySystemStatus": [], + "MediaKeys": [], + "MediaKeysPolicy": [], + "MediaKeysRequirement": [], + "MediaList": [], + "MediaMetadata": [], + "MediaMetadataInit": [], + "MediaPositionState": [], + "MediaQueryList": ["EventTarget"], + "MediaQueryListEvent": ["Event"], + "MediaQueryListEventInit": [], + "MediaRecorder": ["EventTarget"], + "MediaRecorderErrorEvent": ["Event"], + "MediaRecorderErrorEventInit": [], + "MediaRecorderOptions": [], + "MediaSession": [], + "MediaSessionAction": [], + "MediaSessionActionDetails": [], + "MediaSessionPlaybackState": [], + "MediaSettingsRange": [], + "MediaSource": ["EventTarget"], + "MediaSourceEndOfStreamError": [], + "MediaSourceEnum": [], + "MediaSourceReadyState": [], + "MediaStream": ["EventTarget"], + "MediaStreamAudioDestinationNode": ["AudioNode", "EventTarget"], + "MediaStreamAudioSourceNode": ["AudioNode", "EventTarget"], + "MediaStreamAudioSourceOptions": [], + "MediaStreamConstraints": [], + "MediaStreamError": [], + "MediaStreamEvent": ["Event"], + "MediaStreamEventInit": [], + "MediaStreamTrack": ["EventTarget"], + "MediaStreamTrackEvent": ["Event"], + "MediaStreamTrackEventInit": [], + "MediaStreamTrackGenerator": ["EventTarget", "MediaStreamTrack"], + "MediaStreamTrackGeneratorInit": [], + "MediaStreamTrackProcessor": [], + "MediaStreamTrackProcessorInit": [], + "MediaStreamTrackState": [], + "MediaTrackCapabilities": [], + "MediaTrackConstraintSet": [], + "MediaTrackConstraints": [], + "MediaTrackSettings": [], + "MediaTrackSupportedConstraints": [], + "MemoryAttribution": [], + "MemoryAttributionContainer": [], + "MemoryBreakdownEntry": [], + "MemoryMeasurement": [], + "MessageChannel": [], + "MessageEvent": ["Event"], + "MessageEventInit": [], + "MessagePort": ["EventTarget"], + "MeteringMode": [], + "MidiAccess": ["EventTarget"], + "MidiConnectionEvent": ["Event"], + "MidiConnectionEventInit": [], + "MidiInput": ["EventTarget", "MidiPort"], + "MidiInputMap": [], + "MidiMessageEvent": ["Event"], + "MidiMessageEventInit": [], + "MidiOptions": [], + "MidiOutput": ["EventTarget", "MidiPort"], + "MidiOutputMap": [], + "MidiPort": ["EventTarget"], + "MidiPortConnectionState": [], + "MidiPortDeviceState": [], + "MidiPortType": [], + "MimeType": [], + "MimeTypeArray": [], + "MouseEvent": ["Event", "UiEvent"], + "MouseEventInit": [], + "MouseScrollEvent": ["Event", "MouseEvent", "UiEvent"], + "MozDebug": [], + "MutationEvent": ["Event"], + "MutationObserver": [], + "MutationObserverInit": [], + "MutationObservingInfo": [], + "MutationRecord": [], + "NamedNodeMap": [], + "NativeOsFileReadOptions": [], + "NativeOsFileWriteAtomicOptions": [], + "NavigateEvent": ["Event"], + "NavigateEventInit": [], + "Navigation": ["EventTarget"], + "NavigationActivation": [], + "NavigationApiType": [], + "NavigationCurrentEntryChangeEvent": ["Event"], + "NavigationCurrentEntryChangeEventInit": [], + "NavigationDestination": [], + "NavigationFocusReset": [], + "NavigationHistoryBehavior": [], + "NavigationHistoryEntry": ["EventTarget"], + "NavigationInterceptOptions": [], + "NavigationNavigateOptions": [], + "NavigationOptions": [], + "NavigationReloadOptions": [], + "NavigationResult": [], + "NavigationScrollBehavior": [], + "NavigationTransition": [], + "NavigationType": [], + "NavigationUpdateCurrentEntryOptions": [], + "Navigator": [], + "NavigatorAutomationInformation": [], + "NavigatorUaBrandVersion": [], + "NavigatorUaData": [], + "NetworkCommandOptions": [], + "NetworkInformation": ["EventTarget"], + "NetworkResultOptions": [], + "Node": ["EventTarget"], + "NodeFilter": [], + "NodeIterator": [], + "NodeList": [], + "Notification": ["EventTarget"], + "NotificationAction": [], + "NotificationDirection": [], + "NotificationEvent": ["Event", "ExtendableEvent"], + "NotificationEventInit": [], + "NotificationOptions": [], + "NotificationPermission": [], + "ObserverCallback": [], + "OesElementIndexUint": [], + "OesStandardDerivatives": [], + "OesTextureFloat": [], + "OesTextureFloatLinear": [], + "OesTextureHalfFloat": [], + "OesTextureHalfFloatLinear": [], + "OesVertexArrayObject": [], + "OfflineAudioCompletionEvent": ["Event"], + "OfflineAudioCompletionEventInit": [], + "OfflineAudioContext": ["BaseAudioContext", "EventTarget"], + "OfflineAudioContextOptions": [], + "OfflineResourceList": ["EventTarget"], + "OffscreenCanvas": ["EventTarget"], + "OffscreenCanvasRenderingContext2d": [], + "OpenFilePickerOptions": [], + "OpenWindowEventDetail": [], + "OptionalEffectTiming": [], + "OrientationLockType": [], + "OrientationType": [], + "OscillatorNode": ["AudioNode", "AudioScheduledSourceNode", "EventTarget"], + "OscillatorOptions": [], + "OscillatorType": [], + "OverSampleType": [], + "OvrMultiview2": [], + "PageTransitionEvent": ["Event"], + "PageTransitionEventInit": [], + "PaintRequest": [], + "PaintRequestList": [], + "PaintWorkletGlobalScope": ["WorkletGlobalScope"], + "PannerNode": ["AudioNode", "EventTarget"], + "PannerOptions": [], + "PanningModelType": [], + "ParityType": [], + "Path2d": [], + "PaymentAddress": [], + "PaymentComplete": [], + "PaymentMethodChangeEvent": ["Event", "PaymentRequestUpdateEvent"], + "PaymentMethodChangeEventInit": [], + "PaymentRequestUpdateEvent": ["Event"], + "PaymentRequestUpdateEventInit": [], + "PaymentResponse": [], + "Pbkdf2Params": [], + "PcImplIceConnectionState": [], + "PcImplIceGatheringState": [], + "PcImplSignalingState": [], + "PcObserverStateType": [], + "Performance": ["EventTarget"], + "PerformanceEntry": [], + "PerformanceEntryEventInit": [], + "PerformanceEntryFilterOptions": [], + "PerformanceMark": ["PerformanceEntry"], + "PerformanceMarkOptions": [], + "PerformanceMeasure": ["PerformanceEntry"], + "PerformanceMeasureOptions": [], + "PerformanceNavigation": [], + "PerformanceNavigationTiming": ["PerformanceEntry", "PerformanceResourceTiming"], + "PerformanceObserver": [], + "PerformanceObserverEntryList": [], + "PerformanceObserverInit": [], + "PerformanceResourceTiming": ["PerformanceEntry"], + "PerformanceServerTiming": [], + "PerformanceTiming": [], + "PeriodicWave": [], + "PeriodicWaveConstraints": [], + "PeriodicWaveOptions": [], + "PermissionDescriptor": [], + "PermissionName": [], + "PermissionState": [], + "PermissionStatus": ["EventTarget"], + "Permissions": [], + "PhotoCapabilities": [], + "PhotoSettings": [], + "PictureInPictureEvent": ["Event"], + "PictureInPictureEventInit": [], + "PictureInPictureWindow": ["EventTarget"], + "PlaneLayout": [], + "PlaybackDirection": [], + "Plugin": [], + "PluginArray": [], + "PluginCrashedEventInit": [], + "Point2d": [], + "PointerEvent": ["Event", "MouseEvent", "UiEvent"], + "PointerEventInit": [], + "PopStateEvent": ["Event"], + "PopStateEventInit": [], + "PopupBlockedEvent": ["Event"], + "PopupBlockedEventInit": [], + "Position": [], + "PositionAlignSetting": [], + "PositionError": [], + "PositionOptions": [], + "PremultiplyAlpha": [], + "Presentation": [], + "PresentationAvailability": ["EventTarget"], + "PresentationConnection": ["EventTarget"], + "PresentationConnectionAvailableEvent": ["Event"], + "PresentationConnectionAvailableEventInit": [], + "PresentationConnectionBinaryType": [], + "PresentationConnectionCloseEvent": ["Event"], + "PresentationConnectionCloseEventInit": [], + "PresentationConnectionClosedReason": [], + "PresentationConnectionList": ["EventTarget"], + "PresentationConnectionState": [], + "PresentationReceiver": [], + "PresentationRequest": ["EventTarget"], + "PresentationStyle": [], + "ProcessingInstruction": ["CharacterData", "EventTarget", "Node"], + "ProfileTimelineLayerRect": [], + "ProfileTimelineMarker": [], + "ProfileTimelineMessagePortOperationType": [], + "ProfileTimelineStackFrame": [], + "ProfileTimelineWorkerOperationType": [], + "ProgressEvent": ["Event"], + "ProgressEventInit": [], + "PromiseNativeHandler": [], + "PromiseRejectionEvent": ["Event"], + "PromiseRejectionEventInit": [], + "PublicKeyCredential": ["Credential"], + "PublicKeyCredentialCreationOptions": [], + "PublicKeyCredentialCreationOptionsJson": [], + "PublicKeyCredentialDescriptor": [], + "PublicKeyCredentialDescriptorJson": [], + "PublicKeyCredentialEntity": [], + "PublicKeyCredentialHints": [], + "PublicKeyCredentialParameters": [], + "PublicKeyCredentialRequestOptions": [], + "PublicKeyCredentialRequestOptionsJson": [], + "PublicKeyCredentialRpEntity": [], + "PublicKeyCredentialType": [], + "PublicKeyCredentialUserEntity": [], + "PublicKeyCredentialUserEntityJson": [], + "PushEncryptionKeyName": [], + "PushEvent": ["Event", "ExtendableEvent"], + "PushEventInit": [], + "PushManager": [], + "PushMessageData": [], + "PushPermissionState": [], + "PushSubscription": [], + "PushSubscriptionInit": [], + "PushSubscriptionJson": [], + "PushSubscriptionKeys": [], + "PushSubscriptionOptions": [], + "PushSubscriptionOptionsInit": [], + "QueryOptions": [], + "QueuingStrategy": [], + "QueuingStrategyInit": [], + "RadioNodeList": ["NodeList"], + "Range": ["AbstractRange"], + "RcwnPerfStats": [], + "RcwnStatus": [], + "ReadableByteStreamController": [], + "ReadableStream": [], + "ReadableStreamByobReader": [], + "ReadableStreamByobRequest": [], + "ReadableStreamDefaultController": [], + "ReadableStreamDefaultReader": [], + "ReadableStreamGetReaderOptions": [], + "ReadableStreamIteratorOptions": [], + "ReadableStreamReadResult": [], + "ReadableStreamReaderMode": [], + "ReadableStreamType": [], + "ReadableWritablePair": [], + "RecordingState": [], + "RedEyeReduction": [], + "ReferrerPolicy": [], + "RegisterRequest": [], + "RegisterResponse": [], + "RegisteredKey": [], + "RegistrationOptions": [], + "RegistrationResponseJson": [], + "Request": [], + "RequestCache": [], + "RequestCredentials": [], + "RequestDestination": [], + "RequestDeviceOptions": [], + "RequestInit": [], + "RequestMediaKeySystemAccessNotification": [], + "RequestMode": [], + "RequestRedirect": [], + "ResidentKeyRequirement": [], + "ResizeObserver": [], + "ResizeObserverBoxOptions": [], + "ResizeObserverEntry": [], + "ResizeObserverOptions": [], + "ResizeObserverSize": [], + "ResizeQuality": [], + "Response": [], + "ResponseInit": [], + "ResponseType": [], + "RsaHashedImportParams": [], + "RsaOaepParams": [], + "RsaOtherPrimesInfo": [], + "RsaPssParams": [], + "RtcAnswerOptions": [], + "RtcBundlePolicy": [], + "RtcCertificate": [], + "RtcCertificateExpiration": [], + "RtcCodecStats": [], + "RtcConfiguration": [], + "RtcDataChannel": ["EventTarget"], + "RtcDataChannelEvent": ["Event"], + "RtcDataChannelEventInit": [], + "RtcDataChannelInit": [], + "RtcDataChannelState": [], + "RtcDataChannelType": [], + "RtcDegradationPreference": [], + "RtcEncodedAudioFrame": [], + "RtcEncodedAudioFrameMetadata": [], + "RtcEncodedAudioFrameOptions": [], + "RtcEncodedVideoFrame": [], + "RtcEncodedVideoFrameMetadata": [], + "RtcEncodedVideoFrameOptions": [], + "RtcEncodedVideoFrameType": [], + "RtcFecParameters": [], + "RtcIceCandidate": [], + "RtcIceCandidateInit": [], + "RtcIceCandidatePairStats": [], + "RtcIceCandidateStats": [], + "RtcIceComponentStats": [], + "RtcIceConnectionState": [], + "RtcIceCredentialType": [], + "RtcIceGatheringState": [], + "RtcIceServer": [], + "RtcIceTransportPolicy": [], + "RtcIdentityAssertion": [], + "RtcIdentityAssertionResult": [], + "RtcIdentityProvider": [], + "RtcIdentityProviderDetails": [], + "RtcIdentityProviderOptions": [], + "RtcIdentityProviderRegistrar": [], + "RtcIdentityValidationResult": [], + "RtcInboundRtpStreamStats": [], + "RtcMediaStreamStats": [], + "RtcMediaStreamTrackStats": [], + "RtcOfferAnswerOptions": [], + "RtcOfferOptions": [], + "RtcOutboundRtpStreamStats": [], + "RtcPeerConnection": ["EventTarget"], + "RtcPeerConnectionIceErrorEvent": ["Event"], + "RtcPeerConnectionIceEvent": ["Event"], + "RtcPeerConnectionIceEventInit": [], + "RtcPeerConnectionState": [], + "RtcPriorityType": [], + "RtcRtcpParameters": [], + "RtcRtpCapabilities": [], + "RtcRtpCodecCapability": [], + "RtcRtpCodecParameters": [], + "RtcRtpContributingSource": [], + "RtcRtpEncodingParameters": [], + "RtcRtpHeaderExtensionCapability": [], + "RtcRtpHeaderExtensionParameters": [], + "RtcRtpParameters": [], + "RtcRtpReceiver": [], + "RtcRtpScriptTransform": [], + "RtcRtpScriptTransformer": ["EventTarget"], + "RtcRtpSender": [], + "RtcRtpSourceEntry": [], + "RtcRtpSourceEntryType": [], + "RtcRtpSynchronizationSource": [], + "RtcRtpTransceiver": [], + "RtcRtpTransceiverDirection": [], + "RtcRtpTransceiverInit": [], + "RtcRtxParameters": [], + "RtcSdpType": [], + "RtcSessionDescription": [], + "RtcSessionDescriptionInit": [], + "RtcSignalingState": [], + "RtcStats": [], + "RtcStatsIceCandidatePairState": [], + "RtcStatsIceCandidateType": [], + "RtcStatsReport": [], + "RtcStatsReportInternal": [], + "RtcStatsType": [], + "RtcTrackEvent": ["Event"], + "RtcTrackEventInit": [], + "RtcTransformEvent": ["Event"], + "RtcTransportStats": [], + "RtcdtmfSender": ["EventTarget"], + "RtcdtmfToneChangeEvent": ["Event"], + "RtcdtmfToneChangeEventInit": [], + "RtcrtpContributingSourceStats": [], + "RtcrtpStreamStats": [], + "SFrameTransform": ["EventTarget"], + "SFrameTransformErrorEvent": ["Event"], + "SFrameTransformErrorEventInit": [], + "SFrameTransformErrorEventType": [], + "SFrameTransformOptions": [], + "SFrameTransformRole": [], + "SaveFilePickerOptions": [], + "Scheduler": [], + "SchedulerPostTaskOptions": [], + "Scheduling": [], + "Screen": ["EventTarget"], + "ScreenColorGamut": [], + "ScreenDetailed": ["EventTarget", "Screen"], + "ScreenDetails": ["EventTarget"], + "ScreenLuminance": [], + "ScreenOrientation": ["EventTarget"], + "ScriptProcessorNode": ["AudioNode", "EventTarget"], + "ScrollAreaEvent": ["Event", "UiEvent"], + "ScrollBehavior": [], + "ScrollBoxObject": [], + "ScrollIntoViewContainer": [], + "ScrollIntoViewOptions": [], + "ScrollLogicalPosition": [], + "ScrollOptions": [], + "ScrollRestoration": [], + "ScrollSetting": [], + "ScrollState": [], + "ScrollToOptions": [], + "ScrollViewChangeEventInit": [], + "SecurityPolicyViolationEvent": ["Event"], + "SecurityPolicyViolationEventDisposition": [], + "SecurityPolicyViolationEventInit": [], + "Selection": [], + "SelectionMode": [], + "Serial": ["EventTarget"], + "SerialInputSignals": [], + "SerialOptions": [], + "SerialOutputSignals": [], + "SerialPort": ["EventTarget"], + "SerialPortFilter": [], + "SerialPortInfo": [], + "SerialPortRequestOptions": [], + "ServerSocketOptions": [], + "ServiceWorker": ["EventTarget"], + "ServiceWorkerContainer": ["EventTarget"], + "ServiceWorkerGlobalScope": ["EventTarget", "WorkerGlobalScope"], + "ServiceWorkerRegistration": ["EventTarget"], + "ServiceWorkerState": [], + "ServiceWorkerUpdateViaCache": [], + "ShadowRoot": ["DocumentFragment", "EventTarget", "Node"], + "ShadowRootInit": [], + "ShadowRootMode": [], + "ShareData": [], + "SharedWorker": ["EventTarget"], + "SharedWorkerGlobalScope": ["EventTarget", "WorkerGlobalScope"], + "ShowPopoverOptions": [], + "SignResponse": [], + "SocketElement": [], + "SocketOptions": [], + "SocketReadyState": [], + "SocketsDict": [], + "SourceBuffer": ["EventTarget"], + "SourceBufferAppendMode": [], + "SourceBufferList": ["EventTarget"], + "SpeechGrammar": [], + "SpeechGrammarList": [], + "SpeechRecognition": ["EventTarget"], + "SpeechRecognitionAlternative": [], + "SpeechRecognitionError": ["Event"], + "SpeechRecognitionErrorCode": [], + "SpeechRecognitionErrorInit": [], + "SpeechRecognitionEvent": ["Event"], + "SpeechRecognitionEventInit": [], + "SpeechRecognitionResult": [], + "SpeechRecognitionResultList": [], + "SpeechSynthesis": ["EventTarget"], + "SpeechSynthesisErrorCode": [], + "SpeechSynthesisErrorEvent": ["Event", "SpeechSynthesisEvent"], + "SpeechSynthesisErrorEventInit": [], + "SpeechSynthesisEvent": ["Event"], + "SpeechSynthesisEventInit": [], + "SpeechSynthesisUtterance": ["EventTarget"], + "SpeechSynthesisVoice": [], + "StartViewTransitionOptions": [], + "StaticRange": ["AbstractRange"], + "StaticRangeInit": [], + "StereoPannerNode": ["AudioNode", "EventTarget"], + "StereoPannerOptions": [], + "Storage": [], + "StorageEstimate": [], + "StorageEvent": ["Event"], + "StorageEventInit": [], + "StorageManager": [], + "StorageType": [], + "StreamPipeOptions": [], + "StyleRuleChangeEventInit": [], + "StyleSheet": [], + "StyleSheetApplicableStateChangeEventInit": [], + "StyleSheetChangeEventInit": [], + "StyleSheetList": [], + "SubmitEvent": ["Event"], + "SubmitEventInit": [], + "SubtleCrypto": [], + "SupportedType": [], + "SvcOutputMetadata": [], + "SvgAngle": [], + "SvgAnimateElement": [ + "Element", + "EventTarget", + "Node", + "SvgAnimationElement", + "SvgElement" + ], + "SvgAnimateMotionElement": [ + "Element", + "EventTarget", + "Node", + "SvgAnimationElement", + "SvgElement" + ], + "SvgAnimateTransformElement": [ + "Element", + "EventTarget", + "Node", + "SvgAnimationElement", + "SvgElement" + ], + "SvgAnimatedAngle": [], + "SvgAnimatedBoolean": [], + "SvgAnimatedEnumeration": [], + "SvgAnimatedInteger": [], + "SvgAnimatedLength": [], + "SvgAnimatedLengthList": [], + "SvgAnimatedNumber": [], + "SvgAnimatedNumberList": [], + "SvgAnimatedPreserveAspectRatio": [], + "SvgAnimatedRect": [], + "SvgAnimatedString": [], + "SvgAnimatedTransformList": [], + "SvgAnimationElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgBoundingBoxOptions": [], + "SvgCircleElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGeometryElement", + "SvgGraphicsElement" + ], + "SvgClipPathElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgComponentTransferFunctionElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgDefsElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGraphicsElement" + ], + "SvgDescElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgElement": ["Element", "EventTarget", "Node"], + "SvgEllipseElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGeometryElement", + "SvgGraphicsElement" + ], + "SvgFilterElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgForeignObjectElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGraphicsElement" + ], + "SvgGeometryElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGraphicsElement" + ], + "SvgGradientElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgGraphicsElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgImageElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGraphicsElement" + ], + "SvgLength": [], + "SvgLengthList": [], + "SvgLineElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGeometryElement", + "SvgGraphicsElement" + ], + "SvgLinearGradientElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGradientElement" + ], + "SvgMarkerElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgMaskElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgMatrix": [], + "SvgMetadataElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgNumber": [], + "SvgNumberList": [], + "SvgPathElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGeometryElement", + "SvgGraphicsElement" + ], + "SvgPathSeg": [], + "SvgPathSegArcAbs": ["SvgPathSeg"], + "SvgPathSegArcRel": ["SvgPathSeg"], + "SvgPathSegClosePath": ["SvgPathSeg"], + "SvgPathSegCurvetoCubicAbs": ["SvgPathSeg"], + "SvgPathSegCurvetoCubicRel": ["SvgPathSeg"], + "SvgPathSegCurvetoCubicSmoothAbs": ["SvgPathSeg"], + "SvgPathSegCurvetoCubicSmoothRel": ["SvgPathSeg"], + "SvgPathSegCurvetoQuadraticAbs": ["SvgPathSeg"], + "SvgPathSegCurvetoQuadraticRel": ["SvgPathSeg"], + "SvgPathSegCurvetoQuadraticSmoothAbs": ["SvgPathSeg"], + "SvgPathSegCurvetoQuadraticSmoothRel": ["SvgPathSeg"], + "SvgPathSegLinetoAbs": ["SvgPathSeg"], + "SvgPathSegLinetoHorizontalAbs": ["SvgPathSeg"], + "SvgPathSegLinetoHorizontalRel": ["SvgPathSeg"], + "SvgPathSegLinetoRel": ["SvgPathSeg"], + "SvgPathSegLinetoVerticalAbs": ["SvgPathSeg"], + "SvgPathSegLinetoVerticalRel": ["SvgPathSeg"], + "SvgPathSegList": [], + "SvgPathSegMovetoAbs": ["SvgPathSeg"], + "SvgPathSegMovetoRel": ["SvgPathSeg"], + "SvgPatternElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgPoint": [], + "SvgPointList": [], + "SvgPolygonElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGeometryElement", + "SvgGraphicsElement" + ], + "SvgPolylineElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGeometryElement", + "SvgGraphicsElement" + ], + "SvgPreserveAspectRatio": [], + "SvgRadialGradientElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGradientElement" + ], + "SvgRect": [], + "SvgRectElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGeometryElement", + "SvgGraphicsElement" + ], + "SvgScriptElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgSetElement": [ + "Element", + "EventTarget", + "Node", + "SvgAnimationElement", + "SvgElement" + ], + "SvgStopElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgStringList": [], + "SvgStyleElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgSwitchElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGraphicsElement" + ], + "SvgSymbolElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgTextContentElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGraphicsElement" + ], + "SvgTextElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGraphicsElement", + "SvgTextContentElement", + "SvgTextPositioningElement" + ], + "SvgTextPathElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGraphicsElement", + "SvgTextContentElement" + ], + "SvgTextPositioningElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGraphicsElement", + "SvgTextContentElement" + ], + "SvgTitleElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgTransform": [], + "SvgTransformList": [], + "SvgUnitTypes": [], + "SvgUseElement": ["Element", "EventTarget", "Node", "SvgElement", "SvgGraphicsElement"], + "SvgViewElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgZoomAndPan": [], + "SvgaElement": ["Element", "EventTarget", "Node", "SvgElement", "SvgGraphicsElement"], + "SvgfeBlendElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeColorMatrixElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeComponentTransferElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeCompositeElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeConvolveMatrixElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeDiffuseLightingElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeDisplacementMapElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeDistantLightElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeDropShadowElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeFloodElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeFuncAElement": [ + "Element", + "EventTarget", + "Node", + "SvgComponentTransferFunctionElement", + "SvgElement" + ], + "SvgfeFuncBElement": [ + "Element", + "EventTarget", + "Node", + "SvgComponentTransferFunctionElement", + "SvgElement" + ], + "SvgfeFuncGElement": [ + "Element", + "EventTarget", + "Node", + "SvgComponentTransferFunctionElement", + "SvgElement" + ], + "SvgfeFuncRElement": [ + "Element", + "EventTarget", + "Node", + "SvgComponentTransferFunctionElement", + "SvgElement" + ], + "SvgfeGaussianBlurElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeImageElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeMergeElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeMergeNodeElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeMorphologyElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeOffsetElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfePointLightElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeSpecularLightingElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeSpotLightElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeTileElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgfeTurbulenceElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvggElement": ["Element", "EventTarget", "Node", "SvgElement", "SvgGraphicsElement"], + "SvgmPathElement": ["Element", "EventTarget", "Node", "SvgElement"], + "SvgsvgElement": ["Element", "EventTarget", "Node", "SvgElement", "SvgGraphicsElement"], + "SvgtSpanElement": [ + "Element", + "EventTarget", + "Node", + "SvgElement", + "SvgGraphicsElement", + "SvgTextContentElement", + "SvgTextPositioningElement" + ], + "TaskController": ["AbortController"], + "TaskControllerInit": [], + "TaskPriority": [], + "TaskPriorityChangeEvent": ["Event"], + "TaskPriorityChangeEventInit": [], + "TaskSignal": ["AbortSignal", "EventTarget"], + "TaskSignalAnyInit": [], + "TcpReadyState": [], + "TcpServerSocket": ["EventTarget"], + "TcpServerSocketEvent": ["Event"], + "TcpServerSocketEventInit": [], + "TcpSocket": ["EventTarget"], + "TcpSocketBinaryType": [], + "TcpSocketErrorEvent": ["Event"], + "TcpSocketErrorEventInit": [], + "TcpSocketEvent": ["Event"], + "TcpSocketEventInit": [], + "Text": ["CharacterData", "EventTarget", "Node"], + "TextDecodeOptions": [], + "TextDecoder": [], + "TextDecoderOptions": [], + "TextEncoder": [], + "TextMetrics": [], + "TextTrack": ["EventTarget"], + "TextTrackCue": ["EventTarget"], + "TextTrackCueList": [], + "TextTrackKind": [], + "TextTrackList": ["EventTarget"], + "TextTrackMode": [], + "TimeEvent": ["Event"], + "TimeRanges": [], + "ToggleEvent": ["Event"], + "ToggleEventInit": [], + "TogglePopoverOptions": [], + "TokenBinding": [], + "TokenBindingStatus": [], + "Touch": [], + "TouchEvent": ["Event", "UiEvent"], + "TouchEventInit": [], + "TouchInit": [], + "TouchList": [], + "TrackEvent": ["Event"], + "TrackEventInit": [], + "TransformStream": [], + "TransformStreamDefaultController": [], + "Transformer": [], + "TransitionEvent": ["Event"], + "TransitionEventInit": [], + "Transport": [], + "TreeBoxObject": [], + "TreeCellInfo": [], + "TreeView": [], + "TreeWalker": [], + "U2f": [], + "U2fClientData": [], + "ULongRange": [], + "UaDataValues": [], + "UaLowEntropyJson": [], + "UdpMessageEventInit": [], + "UdpOptions": [], + "UiEvent": ["Event"], + "UiEventInit": [], + "UnderlyingSink": [], + "UnderlyingSource": [], + "Url": [], + "UrlSearchParams": [], + "Usb": ["EventTarget"], + "UsbAlternateInterface": [], + "UsbConfiguration": [], + "UsbConnectionEvent": ["Event"], + "UsbConnectionEventInit": [], + "UsbControlTransferParameters": [], + "UsbDevice": [], + "UsbDeviceFilter": [], + "UsbDeviceRequestOptions": [], + "UsbDirection": [], + "UsbEndpoint": [], + "UsbEndpointType": [], + "UsbInTransferResult": [], + "UsbInterface": [], + "UsbIsochronousInTransferPacket": [], + "UsbIsochronousInTransferResult": [], + "UsbIsochronousOutTransferPacket": [], + "UsbIsochronousOutTransferResult": [], + "UsbOutTransferResult": [], + "UsbPermissionDescriptor": [], + "UsbPermissionResult": ["EventTarget", "PermissionStatus"], + "UsbPermissionStorage": [], + "UsbRecipient": [], + "UsbRequestType": [], + "UsbTransferStatus": [], + "UserActivation": [], + "UserProximityEvent": ["Event"], + "UserProximityEventInit": [], + "UserVerificationRequirement": [], + "ValidityState": [], + "ValueEvent": ["Event"], + "ValueEventInit": [], + "VideoColorPrimaries": [], + "VideoColorSpace": [], + "VideoColorSpaceInit": [], + "VideoConfiguration": [], + "VideoDecoder": ["EventTarget"], + "VideoDecoderConfig": [], + "VideoDecoderInit": [], + "VideoDecoderSupport": [], + "VideoEncoder": ["EventTarget"], + "VideoEncoderBitrateMode": [], + "VideoEncoderConfig": [], + "VideoEncoderEncodeOptions": [], + "VideoEncoderInit": [], + "VideoEncoderSupport": [], + "VideoFacingModeEnum": [], + "VideoFrame": [], + "VideoFrameBufferInit": [], + "VideoFrameCopyToOptions": [], + "VideoFrameInit": [], + "VideoFrameMetadata": [], + "VideoMatrixCoefficients": [], + "VideoPixelFormat": [], + "VideoPlaybackQuality": [], + "VideoStreamTrack": ["EventTarget", "MediaStreamTrack"], + "VideoTrack": [], + "VideoTrackList": ["EventTarget"], + "VideoTransferCharacteristics": [], + "ViewTransition": [], + "ViewTransitionTypeSet": [], + "VisibilityState": [], + "VisualViewport": ["EventTarget"], + "VoidCallback": [], + "VrDisplay": ["EventTarget"], + "VrDisplayCapabilities": [], + "VrEye": [], + "VrEyeParameters": [], + "VrFieldOfView": [], + "VrFrameData": [], + "VrLayer": [], + "VrMockController": [], + "VrMockDisplay": [], + "VrPose": [], + "VrServiceTest": [], + "VrStageParameters": [], + "VrSubmitFrameResult": [], + "VttCue": ["EventTarget", "TextTrackCue"], + "VttRegion": [], + "WakeLock": [], + "WakeLockSentinel": ["EventTarget"], + "WakeLockType": [], + "WatchAdvertisementsOptions": [], + "WaveShaperNode": ["AudioNode", "EventTarget"], + "WaveShaperOptions": [], + "WebGl2RenderingContext": [], + "WebGlActiveInfo": [], + "WebGlBuffer": [], + "WebGlContextAttributes": [], + "WebGlContextEvent": ["Event"], + "WebGlContextEventInit": [], + "WebGlFramebuffer": [], + "WebGlPowerPreference": [], + "WebGlProgram": [], + "WebGlQuery": [], + "WebGlRenderbuffer": [], + "WebGlRenderingContext": [], + "WebGlSampler": [], + "WebGlShader": [], + "WebGlShaderPrecisionFormat": [], + "WebGlSync": [], + "WebGlTexture": [], + "WebGlTransformFeedback": [], + "WebGlUniformLocation": [], + "WebGlVertexArrayObject": [], + "WebKitCssMatrix": ["DomMatrix", "DomMatrixReadOnly"], + "WebSocket": ["EventTarget"], + "WebSocketDict": [], + "WebSocketElement": [], + "WebTransport": [], + "WebTransportBidirectionalStream": [], + "WebTransportCloseInfo": [], + "WebTransportCongestionControl": [], + "WebTransportDatagramDuplexStream": [], + "WebTransportDatagramStats": [], + "WebTransportError": ["DomException"], + "WebTransportErrorOptions": [], + "WebTransportErrorSource": [], + "WebTransportHash": [], + "WebTransportOptions": [], + "WebTransportReceiveStream": ["ReadableStream"], + "WebTransportReceiveStreamStats": [], + "WebTransportReliabilityMode": [], + "WebTransportSendStream": ["WritableStream"], + "WebTransportSendStreamOptions": [], + "WebTransportSendStreamStats": [], + "WebTransportStats": [], + "WebglColorBufferFloat": [], + "WebglCompressedTextureAstc": [], + "WebglCompressedTextureAtc": [], + "WebglCompressedTextureEtc": [], + "WebglCompressedTextureEtc1": [], + "WebglCompressedTexturePvrtc": [], + "WebglCompressedTextureS3tc": [], + "WebglCompressedTextureS3tcSrgb": [], + "WebglDebugRendererInfo": [], + "WebglDebugShaders": [], + "WebglDepthTexture": [], + "WebglDrawBuffers": [], + "WebglLoseContext": [], + "WebglMultiDraw": [], + "WellKnownDirectory": [], + "WgslLanguageFeatures": [], + "WheelEvent": ["Event", "MouseEvent", "UiEvent"], + "WheelEventInit": [], + "WidevineCdmManifest": [], + "Window": ["EventTarget"], + "WindowClient": ["Client"], + "Worker": ["EventTarget"], + "WorkerDebuggerGlobalScope": ["EventTarget"], + "WorkerGlobalScope": ["EventTarget"], + "WorkerLocation": [], + "WorkerNavigator": [], + "WorkerOptions": [], + "WorkerType": [], + "Worklet": [], + "WorkletGlobalScope": [], + "WorkletOptions": [], + "WritableStream": [], + "WritableStreamDefaultController": [], + "WritableStreamDefaultWriter": [], + "WriteCommandType": [], + "WriteParams": [], + "XPathExpression": [], + "XPathNsResolver": [], + "XPathResult": [], + "XmlDocument": ["Document", "EventTarget", "Node"], + "XmlHttpRequest": ["EventTarget", "XmlHttpRequestEventTarget"], + "XmlHttpRequestEventTarget": ["EventTarget"], + "XmlHttpRequestResponseType": [], + "XmlHttpRequestUpload": ["EventTarget", "XmlHttpRequestEventTarget"], + "XmlSerializer": [], + "XrBoundedReferenceSpace": ["EventTarget", "XrReferenceSpace", "XrSpace"], + "XrEye": [], + "XrFrame": [], + "XrHand": [], + "XrHandJoint": [], + "XrHandedness": [], + "XrInputSource": [], + "XrInputSourceArray": [], + "XrInputSourceEvent": ["Event"], + "XrInputSourceEventInit": [], + "XrInputSourcesChangeEvent": ["Event"], + "XrInputSourcesChangeEventInit": [], + "XrJointPose": ["XrPose"], + "XrJointSpace": ["EventTarget", "XrSpace"], + "XrLayer": ["EventTarget"], + "XrPermissionDescriptor": [], + "XrPermissionStatus": ["EventTarget", "PermissionStatus"], + "XrPose": [], + "XrReferenceSpace": ["EventTarget", "XrSpace"], + "XrReferenceSpaceEvent": ["Event"], + "XrReferenceSpaceEventInit": [], + "XrReferenceSpaceType": [], + "XrRenderState": [], + "XrRenderStateInit": [], + "XrRigidTransform": [], + "XrSession": ["EventTarget"], + "XrSessionEvent": ["Event"], + "XrSessionEventInit": [], + "XrSessionInit": [], + "XrSessionMode": [], + "XrSessionSupportedPermissionDescriptor": [], + "XrSpace": ["EventTarget"], + "XrSystem": ["EventTarget"], + "XrTargetRayMode": [], + "XrView": [], + "XrViewerPose": ["XrPose"], + "XrViewport": [], + "XrVisibilityState": [], + "XrWebGlLayer": ["EventTarget", "XrLayer"], + "XrWebGlLayerInit": [], + "XsltProcessor": [], + "console": [], + "css": [], + "default": ["std"], + "gpu_buffer_usage": [], + "gpu_color_write": [], + "gpu_map_mode": [], + "gpu_shader_stage": [], + "gpu_texture_usage": [], + "std": ["wasm-bindgen/std", "js-sys/std"] + }, + "yanked": false, + "rust_version": "1.81", + "pubtime": "2026-09-25T07:13:44Z" + } + ] + }, + { + "path": "we/bc/webc", + "header": "AwIAAABldGFnOiAiNzcxOGE5NzYxMWZjZTI0ZGYxNDQ3ZmQ3ZDRjYmMyZTEiAA==", + "records": [ + { + "name": "webc", + "vers": "12.0.0", + "deps": [ + { + "name": "anyhow", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "base64", + "req": "^0.22", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "bytes", + "req": "^1", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "cfg-if", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ciborium", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "document-features", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "flate2", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "hexdump", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ignore", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "indexmap", + "req": "^2", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "insta", + "req": "^1", + "features": ["filters", "yaml"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "leb128", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "lexical-sort", + "req": "^0.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "once_cell", + "req": "^1.18", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "path-clean", + "req": "^1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "pretty_assertions", + "req": "^1.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "regex", + "req": "^1.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "semver", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sequoia-openpgp", + "req": "^2.2.0-pqc.1", + "features": [ + "crypto-rust", + "allow-experimental-crypto", + "allow-variable-time-crypto" + ], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "sha2", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "shared-buffer", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tar", + "req": "^0.4", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "thiserror", + "req": "^2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "toml", + "req": "^0.9", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "ureq", + "req": "^3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "url", + "req": "^2.2", + "features": ["serde"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "5cb48ee4bc7a902c0f1d9eb0c0656f0e78149f1190b7f78e1f28256e88279a84", + "features": { + "mmap": [] + }, + "features2": { + "crypto": ["dep:sequoia-openpgp"], + "default": ["v1", "v2", "v3"], + "v1": ["dep:base64", "dep:leb128", "dep:lexical-sort", "dep:path-clean", "dep:rand"], + "v2": ["dep:once_cell"], + "v3": ["dep:once_cell", "dep:base64"] + }, + "yanked": false, + "rust_version": "1.90", + "pubtime": "2026-06-01T01:39:43Z", + "v": 2 + } + ] + }, + { + "path": "we/ez/weezl", + "header": "AwIAAABldGFnOiAiNDE5ZDcxY2QzMzBlOWZlOTZmYWFiZjQyMDY4Mzg2OTkiAA==", + "records": [ + { + "name": "weezl", + "vers": "0.2.1", + "deps": [ + { + "name": "criterion", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "futures", + "req": "^0.3.12", + "features": ["std"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "tokio", + "req": "^1", + "features": ["macros", "io-util", "net", "rt", "rt-multi-thread"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "tokio-util", + "req": "^0.6.2", + "features": ["compat"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "zenbench", + "req": "^0.1.3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "d4ca08e5ef825b65b056d9efbd95c8750683f0a6d0466d02e96dc2e4e360f3d2", + "features": { + "alloc": [], + "async": ["futures", "std"], + "default": ["std"], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.88.0", + "pubtime": "2026-05-15T22:35:10Z" + } + ] + }, + { + "path": "wh/ic/which", + "header": "AwIAAABldGFnOiAiODFiMTQ0NWRiODYwNTI5NTZmNzI4ZmM2YjdkMjllMGIiAA==", + "records": [ + { + "name": "which", + "vers": "8.0.6", + "deps": [ + { + "name": "libc", + "req": "^0.2", + "features": [], + "optional": true, + "default_features": true, + "target": "cfg(any(unix, target_os = \"wasi\", target_os = \"redox\"))", + "kind": "normal" + }, + { + "name": "regex", + "req": "^1.10.2", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3.9.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "tracing", + "req": "^0.1.40", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "bae2f2b2b816647a1cab1acc91f5bd20812d53cb344382635ec2181940c8034f", + "features": {}, + "features2": { + "default": ["real-sys"], + "real-sys": ["dep:libc"], + "regex": ["dep:regex"], + "tracing": ["dep:tracing"] + }, + "yanked": false, + "rust_version": "1.70", + "pubtime": "2026-08-26T18:06:08Z", + "v": 2 + } + ] + }, + { + "path": "wh/oa/whoami", + "header": "AwIAAABldGFnOiAiMzZhZmUyMzliMTgwODJlNDRmNjg3Mzk0YTNjZWVhMzEiAA==", + "records": [ + { + "name": "whoami", + "vers": "1.6.1", + "deps": [ + { + "name": "libredox", + "req": "^0.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_os = \"redox\", not(target_arch = \"wasm32\")))", + "kind": "normal" + }, + { + "name": "wasite", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"wasm32\", target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "web-sys", + "req": "^0.3", + "features": ["Navigator", "Document", "Window", "Location"], + "optional": true, + "default_features": true, + "target": "cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\"), not(daku)))", + "kind": "normal" + } + ], + "cksum": "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d", + "features": { + "default": ["web"], + "web": ["web-sys"] + }, + "yanked": false, + "rust_version": "1.40", + "pubtime": "2025-08-11T05:10:01Z" + }, + { + "name": "whoami", + "vers": "2.1.3", + "deps": [ + { + "name": "libc", + "req": "^0.2.186", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(any(target_vendor = \"apple\", target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"netbsd\", target_os = \"openbsd\", target_os = \"illumos\", target_os = \"hurd\"), not(target_arch = \"wasm32\")))", + "kind": "normal" + }, + { + "name": "libredox", + "req": "^0.1.17", + "features": ["call"], + "optional": true, + "default_features": false, + "target": "cfg(all(target_os = \"redox\", not(target_arch = \"wasm32\")))", + "kind": "normal" + }, + { + "name": "objc2-system-configuration", + "req": "^0.3.2", + "features": ["SCDynamicStore", "SCDynamicStoreCopySpecific"], + "optional": true, + "default_features": false, + "target": "cfg(target_vendor = \"apple\")", + "kind": "normal" + }, + { + "name": "wasite", + "req": "^1.0.2", + "features": [], + "optional": true, + "default_features": false, + "target": "cfg(all(target_arch = \"wasm32\", target_os = \"wasi\"))", + "kind": "normal" + }, + { + "name": "web-sys", + "req": "^0.3.85", + "features": ["Navigator", "Document", "Window", "Location"], + "optional": true, + "default_features": false, + "target": "cfg(all(target_arch = \"wasm32\", not(target_os = \"wasi\"), not(daku)))", + "kind": "normal" + } + ], + "cksum": "626c4bac6755d76ffc12cb01b2eac751db1996b9e0041de9aa02c8c211ddc82c", + "features": { + "force-stub": [] + }, + "features2": { + "default": ["std", "wasi-wasite", "wasm-web"], + "std": [ + "dep:libc", + "dep:libredox", + "dep:objc2-system-configuration", + "libc?/std", + "web-sys?/std" + ], + "wasi-wasite": ["dep:wasite"], + "wasm-web": ["dep:web-sys"] + }, + "yanked": false, + "rust_version": "1.75", + "pubtime": "2026-08-11T23:31:57Z", + "v": 2 + } + ] + }, + { + "path": "wi/na/winapi-util", + "header": "AwIAAABldGFnOiAiYmMxNTRlZWQ4MDJmMzllNDJkNzI1NDMzMjhiYzhkMmMiAA==", + "records": [ + { + "name": "winapi-util", + "vers": "0.1.11", + "deps": [ + { + "name": "windows-sys", + "req": ">=0.48.0, <=0.61", + "features": [ + "Win32_Foundation", + "Win32_Storage_FileSystem", + "Win32_System_Console", + "Win32_System_SystemInformation" + ], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22", + "features": {}, + "yanked": false, + "pubtime": "2025-09-07T12:24:31Z" + } + ] + }, + { + "path": "wi/nd/windows_aarch64_gnullvm", + "header": "AwIAAABldGFnOiAiYWRmZWI4NDk1MTkyYWM5ZTIxMmI2Y2Q2Yjg1NjdjNjciAA==", + "records": [ + { + "name": "windows_aarch64_gnullvm", + "vers": "0.48.5", + "deps": [], + "cksum": "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8", + "features": {}, + "yanked": false, + "pubtime": "2023-08-18T17:46:06Z" + }, + { + "name": "windows_aarch64_gnullvm", + "vers": "0.52.6", + "deps": [], + "cksum": "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-07-03T19:43:36Z" + }, + { + "name": "windows_aarch64_gnullvm", + "vers": "0.53.1", + "deps": [], + "cksum": "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53", + "features": {}, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-10-06T17:33:29Z" + } + ] + }, + { + "path": "wi/nd/windows_aarch64_msvc", + "header": "AwIAAABldGFnOiAiMDkyODhhMjBjNjU5M2FhZGY5MWJjNjgyNzM2OWIxNDMiAA==", + "records": [ + { + "name": "windows_aarch64_msvc", + "vers": "0.48.5", + "deps": [], + "cksum": "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc", + "features": {}, + "yanked": false, + "pubtime": "2023-08-18T17:46:33Z" + }, + { + "name": "windows_aarch64_msvc", + "vers": "0.52.6", + "deps": [], + "cksum": "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-07-03T19:43:40Z" + }, + { + "name": "windows_aarch64_msvc", + "vers": "0.53.1", + "deps": [], + "cksum": "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006", + "features": {}, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-10-06T17:33:33Z" + } + ] + }, + { + "path": "wi/nd/windows_i686_gnu", + "header": "AwIAAABldGFnOiAiYzBiNDZlYzM3NTNiNzBhNjllN2U4N2RkMjA2ZGM4Y2QiAA==", + "records": [ + { + "name": "windows_i686_gnu", + "vers": "0.48.5", + "deps": [], + "cksum": "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e", + "features": {}, + "yanked": false, + "pubtime": "2023-08-18T17:46:48Z" + }, + { + "name": "windows_i686_gnu", + "vers": "0.52.6", + "deps": [], + "cksum": "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-07-03T19:43:46Z" + }, + { + "name": "windows_i686_gnu", + "vers": "0.53.1", + "deps": [], + "cksum": "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3", + "features": {}, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-10-06T17:33:40Z" + } + ] + }, + { + "path": "wi/nd/windows_i686_gnullvm", + "header": "AwIAAABldGFnOiAiNjAxZjMyMmMzOTA2NmQ1YzgxMDFkOGY5ZGQxMmQxODEiAA==", + "records": [ + { + "name": "windows_i686_gnullvm", + "vers": "0.52.6", + "deps": [], + "cksum": "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-07-03T19:43:50Z" + }, + { + "name": "windows_i686_gnullvm", + "vers": "0.53.1", + "deps": [], + "cksum": "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c", + "features": {}, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-10-06T17:33:44Z" + } + ] + }, + { + "path": "wi/nd/windows_i686_msvc", + "header": "AwIAAABldGFnOiAiZTZjZTVlMzNiYWQ4NTBkN2EzMmZmYmRlNmMzZmUyMjkiAA==", + "records": [ + { + "name": "windows_i686_msvc", + "vers": "0.48.5", + "deps": [], + "cksum": "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406", + "features": {}, + "yanked": false, + "pubtime": "2023-08-18T17:47:01Z" + }, + { + "name": "windows_i686_msvc", + "vers": "0.52.6", + "deps": [], + "cksum": "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-07-03T19:43:54Z" + }, + { + "name": "windows_i686_msvc", + "vers": "0.53.1", + "deps": [], + "cksum": "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2", + "features": {}, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-10-06T17:33:49Z" + } + ] + }, + { + "path": "wi/nd/windows_x86_64_gnu", + "header": "AwIAAABldGFnOiAiMjJmYTljOGZmOWVhYWZkODlkOGFlNzE3MjczMTQxMjkiAA==", + "records": [ + { + "name": "windows_x86_64_gnu", + "vers": "0.48.5", + "deps": [], + "cksum": "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e", + "features": {}, + "yanked": false, + "pubtime": "2023-08-18T17:47:19Z" + }, + { + "name": "windows_x86_64_gnu", + "vers": "0.52.6", + "deps": [], + "cksum": "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-07-03T19:43:58Z" + }, + { + "name": "windows_x86_64_gnu", + "vers": "0.53.1", + "deps": [], + "cksum": "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499", + "features": {}, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-10-06T17:33:55Z" + } + ] + }, + { + "path": "wi/nd/windows_x86_64_gnullvm", + "header": "AwIAAABldGFnOiAiYTg5MmZkODUyZTJhNWVmMTI1ODQ2N2JhOTA4M2IyZDUiAA==", + "records": [ + { + "name": "windows_x86_64_gnullvm", + "vers": "0.48.5", + "deps": [], + "cksum": "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc", + "features": {}, + "yanked": false, + "pubtime": "2023-08-18T17:47:45Z" + }, + { + "name": "windows_x86_64_gnullvm", + "vers": "0.52.6", + "deps": [], + "cksum": "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-07-03T19:44:03Z" + }, + { + "name": "windows_x86_64_gnullvm", + "vers": "0.53.1", + "deps": [], + "cksum": "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1", + "features": {}, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-10-06T17:34:01Z" + } + ] + }, + { + "path": "wi/nd/windows_x86_64_msvc", + "header": "AwIAAABldGFnOiAiYjkzYjI1YzUyMjNmNzBiMTAxNzcwOTA5ODlhNjJmYjYiAA==", + "records": [ + { + "name": "windows_x86_64_msvc", + "vers": "0.48.5", + "deps": [], + "cksum": "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538", + "features": {}, + "yanked": false, + "pubtime": "2023-08-18T17:47:56Z" + }, + { + "name": "windows_x86_64_msvc", + "vers": "0.52.6", + "deps": [], + "cksum": "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-07-03T19:44:07Z" + }, + { + "name": "windows_x86_64_msvc", + "vers": "0.53.1", + "deps": [], + "cksum": "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650", + "features": {}, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-10-06T17:34:07Z" + } + ] + }, + { + "path": "wi/nd/windows-link", + "header": "AwIAAABldGFnOiAiOGExMzljNWFiOGJmMzhhNTUxM2I0OTYxZGU4MmYwY2MiAA==", + "records": [ + { + "name": "windows-link", + "vers": "0.2.1", + "deps": [], + "cksum": "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2025-10-06T17:35:08Z" + } + ] + }, + { + "path": "wi/nd/windows-sys", + "header": "AwIAAABldGFnOiAiZjZmOGFlYTIyYzM4NmY3ZTI2YWUyNWRmNjljYWNkMzYiAA==", + "records": [ + { + "name": "windows-sys", + "vers": "0.48.0", + "deps": [ + { + "name": "windows-targets", + "req": "^0.48.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9", + "features": { + "Wdk": [], + "Wdk_System": ["Wdk"], + "Wdk_System_OfflineRegistry": ["Wdk_System"], + "Win32": [], + "Win32_Data": ["Win32"], + "Win32_Data_HtmlHelp": ["Win32_Data"], + "Win32_Data_RightsManagement": ["Win32_Data"], + "Win32_Data_Xml": ["Win32_Data"], + "Win32_Data_Xml_MsXml": ["Win32_Data_Xml"], + "Win32_Data_Xml_XmlLite": ["Win32_Data_Xml"], + "Win32_Devices": ["Win32"], + "Win32_Devices_AllJoyn": ["Win32_Devices"], + "Win32_Devices_BiometricFramework": ["Win32_Devices"], + "Win32_Devices_Bluetooth": ["Win32_Devices"], + "Win32_Devices_Communication": ["Win32_Devices"], + "Win32_Devices_DeviceAccess": ["Win32_Devices"], + "Win32_Devices_DeviceAndDriverInstallation": ["Win32_Devices"], + "Win32_Devices_DeviceQuery": ["Win32_Devices"], + "Win32_Devices_Display": ["Win32_Devices"], + "Win32_Devices_Enumeration": ["Win32_Devices"], + "Win32_Devices_Enumeration_Pnp": ["Win32_Devices_Enumeration"], + "Win32_Devices_Fax": ["Win32_Devices"], + "Win32_Devices_FunctionDiscovery": ["Win32_Devices"], + "Win32_Devices_Geolocation": ["Win32_Devices"], + "Win32_Devices_HumanInterfaceDevice": ["Win32_Devices"], + "Win32_Devices_ImageAcquisition": ["Win32_Devices"], + "Win32_Devices_PortableDevices": ["Win32_Devices"], + "Win32_Devices_Properties": ["Win32_Devices"], + "Win32_Devices_Pwm": ["Win32_Devices"], + "Win32_Devices_Sensors": ["Win32_Devices"], + "Win32_Devices_SerialCommunication": ["Win32_Devices"], + "Win32_Devices_Tapi": ["Win32_Devices"], + "Win32_Devices_Usb": ["Win32_Devices"], + "Win32_Devices_WebServicesOnDevices": ["Win32_Devices"], + "Win32_Foundation": ["Win32"], + "Win32_Gaming": ["Win32"], + "Win32_Globalization": ["Win32"], + "Win32_Graphics": ["Win32"], + "Win32_Graphics_Dwm": ["Win32_Graphics"], + "Win32_Graphics_Gdi": ["Win32_Graphics"], + "Win32_Graphics_Hlsl": ["Win32_Graphics"], + "Win32_Graphics_OpenGL": ["Win32_Graphics"], + "Win32_Graphics_Printing": ["Win32_Graphics"], + "Win32_Graphics_Printing_PrintTicket": ["Win32_Graphics_Printing"], + "Win32_Management": ["Win32"], + "Win32_Management_MobileDeviceManagementRegistration": ["Win32_Management"], + "Win32_Media": ["Win32"], + "Win32_Media_Audio": ["Win32_Media"], + "Win32_Media_Audio_Apo": ["Win32_Media_Audio"], + "Win32_Media_Audio_DirectMusic": ["Win32_Media_Audio"], + "Win32_Media_Audio_Endpoints": ["Win32_Media_Audio"], + "Win32_Media_Audio_XAudio2": ["Win32_Media_Audio"], + "Win32_Media_DeviceManager": ["Win32_Media"], + "Win32_Media_DxMediaObjects": ["Win32_Media"], + "Win32_Media_KernelStreaming": ["Win32_Media"], + "Win32_Media_LibrarySharingServices": ["Win32_Media"], + "Win32_Media_MediaPlayer": ["Win32_Media"], + "Win32_Media_Multimedia": ["Win32_Media"], + "Win32_Media_Speech": ["Win32_Media"], + "Win32_Media_Streaming": ["Win32_Media"], + "Win32_Media_WindowsMediaFormat": ["Win32_Media"], + "Win32_NetworkManagement": ["Win32"], + "Win32_NetworkManagement_Dhcp": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Dns": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_InternetConnectionWizard": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_IpHelper": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_MobileBroadband": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Multicast": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Ndis": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetBios": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetManagement": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetShell": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetworkDiagnosticsFramework": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetworkPolicyServer": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_P2P": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_QoS": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Rras": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Snmp": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WNet": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WebDav": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WiFi": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsConnectNow": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsConnectionManager": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsFilteringPlatform": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsFirewall": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsNetworkVirtualization": ["Win32_NetworkManagement"], + "Win32_Networking": ["Win32"], + "Win32_Networking_ActiveDirectory": ["Win32_Networking"], + "Win32_Networking_BackgroundIntelligentTransferService": ["Win32_Networking"], + "Win32_Networking_Clustering": ["Win32_Networking"], + "Win32_Networking_HttpServer": ["Win32_Networking"], + "Win32_Networking_Ldap": ["Win32_Networking"], + "Win32_Networking_NetworkListManager": ["Win32_Networking"], + "Win32_Networking_RemoteDifferentialCompression": ["Win32_Networking"], + "Win32_Networking_WebSocket": ["Win32_Networking"], + "Win32_Networking_WinHttp": ["Win32_Networking"], + "Win32_Networking_WinInet": ["Win32_Networking"], + "Win32_Networking_WinSock": ["Win32_Networking"], + "Win32_Networking_WindowsWebServices": ["Win32_Networking"], + "Win32_Security": ["Win32"], + "Win32_Security_AppLocker": ["Win32_Security"], + "Win32_Security_Authentication": ["Win32_Security"], + "Win32_Security_Authentication_Identity": ["Win32_Security_Authentication"], + "Win32_Security_Authentication_Identity_Provider": [ + "Win32_Security_Authentication_Identity" + ], + "Win32_Security_Authorization": ["Win32_Security"], + "Win32_Security_Authorization_UI": ["Win32_Security_Authorization"], + "Win32_Security_ConfigurationSnapin": ["Win32_Security"], + "Win32_Security_Credentials": ["Win32_Security"], + "Win32_Security_Cryptography": ["Win32_Security"], + "Win32_Security_Cryptography_Catalog": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_Certificates": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_Sip": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_UI": ["Win32_Security_Cryptography"], + "Win32_Security_DiagnosticDataQuery": ["Win32_Security"], + "Win32_Security_DirectoryServices": ["Win32_Security"], + "Win32_Security_EnterpriseData": ["Win32_Security"], + "Win32_Security_ExtensibleAuthenticationProtocol": ["Win32_Security"], + "Win32_Security_Isolation": ["Win32_Security"], + "Win32_Security_LicenseProtection": ["Win32_Security"], + "Win32_Security_NetworkAccessProtection": ["Win32_Security"], + "Win32_Security_Tpm": ["Win32_Security"], + "Win32_Security_WinTrust": ["Win32_Security"], + "Win32_Security_WinWlx": ["Win32_Security"], + "Win32_Storage": ["Win32"], + "Win32_Storage_Cabinets": ["Win32_Storage"], + "Win32_Storage_CloudFilters": ["Win32_Storage"], + "Win32_Storage_Compression": ["Win32_Storage"], + "Win32_Storage_DataDeduplication": ["Win32_Storage"], + "Win32_Storage_DistributedFileSystem": ["Win32_Storage"], + "Win32_Storage_EnhancedStorage": ["Win32_Storage"], + "Win32_Storage_FileHistory": ["Win32_Storage"], + "Win32_Storage_FileServerResourceManager": ["Win32_Storage"], + "Win32_Storage_FileSystem": ["Win32_Storage"], + "Win32_Storage_Imapi": ["Win32_Storage"], + "Win32_Storage_IndexServer": ["Win32_Storage"], + "Win32_Storage_InstallableFileSystems": ["Win32_Storage"], + "Win32_Storage_IscsiDisc": ["Win32_Storage"], + "Win32_Storage_Jet": ["Win32_Storage"], + "Win32_Storage_OfflineFiles": ["Win32_Storage"], + "Win32_Storage_OperationRecorder": ["Win32_Storage"], + "Win32_Storage_Packaging": ["Win32_Storage"], + "Win32_Storage_Packaging_Appx": ["Win32_Storage_Packaging"], + "Win32_Storage_Packaging_Opc": ["Win32_Storage_Packaging"], + "Win32_Storage_ProjectedFileSystem": ["Win32_Storage"], + "Win32_Storage_StructuredStorage": ["Win32_Storage"], + "Win32_Storage_Vhd": ["Win32_Storage"], + "Win32_Storage_VirtualDiskService": ["Win32_Storage"], + "Win32_Storage_Vss": ["Win32_Storage"], + "Win32_Storage_Xps": ["Win32_Storage"], + "Win32_Storage_Xps_Printing": ["Win32_Storage_Xps"], + "Win32_System": ["Win32"], + "Win32_System_AddressBook": ["Win32_System"], + "Win32_System_Antimalware": ["Win32_System"], + "Win32_System_ApplicationInstallationAndServicing": ["Win32_System"], + "Win32_System_ApplicationVerifier": ["Win32_System"], + "Win32_System_AssessmentTool": ["Win32_System"], + "Win32_System_ClrHosting": ["Win32_System"], + "Win32_System_Com": ["Win32_System"], + "Win32_System_Com_CallObj": ["Win32_System_Com"], + "Win32_System_Com_ChannelCredentials": ["Win32_System_Com"], + "Win32_System_Com_Events": ["Win32_System_Com"], + "Win32_System_Com_Marshal": ["Win32_System_Com"], + "Win32_System_Com_StructuredStorage": ["Win32_System_Com"], + "Win32_System_Com_UI": ["Win32_System_Com"], + "Win32_System_Com_Urlmon": ["Win32_System_Com"], + "Win32_System_ComponentServices": ["Win32_System"], + "Win32_System_Console": ["Win32_System"], + "Win32_System_Contacts": ["Win32_System"], + "Win32_System_CorrelationVector": ["Win32_System"], + "Win32_System_DataExchange": ["Win32_System"], + "Win32_System_DeploymentServices": ["Win32_System"], + "Win32_System_DesktopSharing": ["Win32_System"], + "Win32_System_DeveloperLicensing": ["Win32_System"], + "Win32_System_Diagnostics": ["Win32_System"], + "Win32_System_Diagnostics_Ceip": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_ClrProfiling": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_Debug": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_Debug_ActiveScript": ["Win32_System_Diagnostics_Debug"], + "Win32_System_Diagnostics_Debug_Extensions": ["Win32_System_Diagnostics_Debug"], + "Win32_System_Diagnostics_Etw": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_ProcessSnapshotting": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_ToolHelp": ["Win32_System_Diagnostics"], + "Win32_System_DistributedTransactionCoordinator": ["Win32_System"], + "Win32_System_Environment": ["Win32_System"], + "Win32_System_ErrorReporting": ["Win32_System"], + "Win32_System_EventCollector": ["Win32_System"], + "Win32_System_EventLog": ["Win32_System"], + "Win32_System_EventNotificationService": ["Win32_System"], + "Win32_System_GroupPolicy": ["Win32_System"], + "Win32_System_HostCompute": ["Win32_System"], + "Win32_System_HostComputeNetwork": ["Win32_System"], + "Win32_System_HostComputeSystem": ["Win32_System"], + "Win32_System_Hypervisor": ["Win32_System"], + "Win32_System_IO": ["Win32_System"], + "Win32_System_Iis": ["Win32_System"], + "Win32_System_Ioctl": ["Win32_System"], + "Win32_System_JobObjects": ["Win32_System"], + "Win32_System_Js": ["Win32_System"], + "Win32_System_Kernel": ["Win32_System"], + "Win32_System_LibraryLoader": ["Win32_System"], + "Win32_System_Mailslots": ["Win32_System"], + "Win32_System_Mapi": ["Win32_System"], + "Win32_System_Memory": ["Win32_System"], + "Win32_System_Memory_NonVolatile": ["Win32_System_Memory"], + "Win32_System_MessageQueuing": ["Win32_System"], + "Win32_System_MixedReality": ["Win32_System"], + "Win32_System_Mmc": ["Win32_System"], + "Win32_System_Ole": ["Win32_System"], + "Win32_System_ParentalControls": ["Win32_System"], + "Win32_System_PasswordManagement": ["Win32_System"], + "Win32_System_Performance": ["Win32_System"], + "Win32_System_Performance_HardwareCounterProfiling": ["Win32_System_Performance"], + "Win32_System_Pipes": ["Win32_System"], + "Win32_System_Power": ["Win32_System"], + "Win32_System_ProcessStatus": ["Win32_System"], + "Win32_System_RealTimeCommunications": ["Win32_System"], + "Win32_System_Recovery": ["Win32_System"], + "Win32_System_Registry": ["Win32_System"], + "Win32_System_RemoteAssistance": ["Win32_System"], + "Win32_System_RemoteDesktop": ["Win32_System"], + "Win32_System_RemoteManagement": ["Win32_System"], + "Win32_System_RestartManager": ["Win32_System"], + "Win32_System_Restore": ["Win32_System"], + "Win32_System_Rpc": ["Win32_System"], + "Win32_System_Search": ["Win32_System"], + "Win32_System_Search_Common": ["Win32_System_Search"], + "Win32_System_SecurityCenter": ["Win32_System"], + "Win32_System_ServerBackup": ["Win32_System"], + "Win32_System_Services": ["Win32_System"], + "Win32_System_SettingsManagementInfrastructure": ["Win32_System"], + "Win32_System_SetupAndMigration": ["Win32_System"], + "Win32_System_Shutdown": ["Win32_System"], + "Win32_System_StationsAndDesktops": ["Win32_System"], + "Win32_System_SubsystemForLinux": ["Win32_System"], + "Win32_System_SystemInformation": ["Win32_System"], + "Win32_System_SystemServices": ["Win32_System"], + "Win32_System_TaskScheduler": ["Win32_System"], + "Win32_System_Threading": ["Win32_System"], + "Win32_System_Time": ["Win32_System"], + "Win32_System_TpmBaseServices": ["Win32_System"], + "Win32_System_UpdateAgent": ["Win32_System"], + "Win32_System_UpdateAssessment": ["Win32_System"], + "Win32_System_UserAccessLogging": ["Win32_System"], + "Win32_System_VirtualDosMachines": ["Win32_System"], + "Win32_System_WindowsProgramming": ["Win32_System"], + "Win32_System_WindowsSync": ["Win32_System"], + "Win32_System_Wmi": ["Win32_System"], + "Win32_UI": ["Win32"], + "Win32_UI_Accessibility": ["Win32_UI"], + "Win32_UI_Animation": ["Win32_UI"], + "Win32_UI_ColorSystem": ["Win32_UI"], + "Win32_UI_Controls": ["Win32_UI"], + "Win32_UI_Controls_Dialogs": ["Win32_UI_Controls"], + "Win32_UI_Controls_RichEdit": ["Win32_UI_Controls"], + "Win32_UI_HiDpi": ["Win32_UI"], + "Win32_UI_Input": ["Win32_UI"], + "Win32_UI_Input_Ime": ["Win32_UI_Input"], + "Win32_UI_Input_Ink": ["Win32_UI_Input"], + "Win32_UI_Input_KeyboardAndMouse": ["Win32_UI_Input"], + "Win32_UI_Input_Pointer": ["Win32_UI_Input"], + "Win32_UI_Input_Radial": ["Win32_UI_Input"], + "Win32_UI_Input_Touch": ["Win32_UI_Input"], + "Win32_UI_Input_XboxController": ["Win32_UI_Input"], + "Win32_UI_InteractionContext": ["Win32_UI"], + "Win32_UI_LegacyWindowsEnvironmentFeatures": ["Win32_UI"], + "Win32_UI_Magnification": ["Win32_UI"], + "Win32_UI_Notifications": ["Win32_UI"], + "Win32_UI_Ribbon": ["Win32_UI"], + "Win32_UI_Shell": ["Win32_UI"], + "Win32_UI_Shell_Common": ["Win32_UI_Shell"], + "Win32_UI_Shell_PropertiesSystem": ["Win32_UI_Shell"], + "Win32_UI_TabletPC": ["Win32_UI"], + "Win32_UI_TextServices": ["Win32_UI"], + "Win32_UI_WindowsAndMessaging": ["Win32_UI"], + "Win32_UI_Wpf": ["Win32_UI"], + "Win32_Web": ["Win32"], + "Win32_Web_InternetExplorer": ["Win32_Web"], + "default": [] + }, + "yanked": false, + "rust_version": "1.48", + "pubtime": "2023-03-31T12:59:46Z" + }, + { + "name": "windows-sys", + "vers": "0.52.0", + "deps": [ + { + "name": "windows-targets", + "req": "^0.52.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d", + "features": { + "Wdk": [], + "Wdk_Foundation": ["Wdk"], + "Wdk_Graphics": ["Wdk"], + "Wdk_Graphics_Direct3D": ["Wdk_Graphics"], + "Wdk_Storage": ["Wdk"], + "Wdk_Storage_FileSystem": ["Wdk_Storage"], + "Wdk_Storage_FileSystem_Minifilters": ["Wdk_Storage_FileSystem"], + "Wdk_System": ["Wdk"], + "Wdk_System_IO": ["Wdk_System"], + "Wdk_System_OfflineRegistry": ["Wdk_System"], + "Wdk_System_Registry": ["Wdk_System"], + "Wdk_System_SystemInformation": ["Wdk_System"], + "Wdk_System_SystemServices": ["Wdk_System"], + "Wdk_System_Threading": ["Wdk_System"], + "Win32": [], + "Win32_Data": ["Win32"], + "Win32_Data_HtmlHelp": ["Win32_Data"], + "Win32_Data_RightsManagement": ["Win32_Data"], + "Win32_Devices": ["Win32"], + "Win32_Devices_AllJoyn": ["Win32_Devices"], + "Win32_Devices_BiometricFramework": ["Win32_Devices"], + "Win32_Devices_Bluetooth": ["Win32_Devices"], + "Win32_Devices_Communication": ["Win32_Devices"], + "Win32_Devices_DeviceAndDriverInstallation": ["Win32_Devices"], + "Win32_Devices_DeviceQuery": ["Win32_Devices"], + "Win32_Devices_Display": ["Win32_Devices"], + "Win32_Devices_Enumeration": ["Win32_Devices"], + "Win32_Devices_Enumeration_Pnp": ["Win32_Devices_Enumeration"], + "Win32_Devices_Fax": ["Win32_Devices"], + "Win32_Devices_HumanInterfaceDevice": ["Win32_Devices"], + "Win32_Devices_PortableDevices": ["Win32_Devices"], + "Win32_Devices_Properties": ["Win32_Devices"], + "Win32_Devices_Pwm": ["Win32_Devices"], + "Win32_Devices_Sensors": ["Win32_Devices"], + "Win32_Devices_SerialCommunication": ["Win32_Devices"], + "Win32_Devices_Tapi": ["Win32_Devices"], + "Win32_Devices_Usb": ["Win32_Devices"], + "Win32_Devices_WebServicesOnDevices": ["Win32_Devices"], + "Win32_Foundation": ["Win32"], + "Win32_Gaming": ["Win32"], + "Win32_Globalization": ["Win32"], + "Win32_Graphics": ["Win32"], + "Win32_Graphics_Dwm": ["Win32_Graphics"], + "Win32_Graphics_Gdi": ["Win32_Graphics"], + "Win32_Graphics_GdiPlus": ["Win32_Graphics"], + "Win32_Graphics_Hlsl": ["Win32_Graphics"], + "Win32_Graphics_OpenGL": ["Win32_Graphics"], + "Win32_Graphics_Printing": ["Win32_Graphics"], + "Win32_Graphics_Printing_PrintTicket": ["Win32_Graphics_Printing"], + "Win32_Management": ["Win32"], + "Win32_Management_MobileDeviceManagementRegistration": ["Win32_Management"], + "Win32_Media": ["Win32"], + "Win32_Media_Audio": ["Win32_Media"], + "Win32_Media_DxMediaObjects": ["Win32_Media"], + "Win32_Media_KernelStreaming": ["Win32_Media"], + "Win32_Media_Multimedia": ["Win32_Media"], + "Win32_Media_Streaming": ["Win32_Media"], + "Win32_Media_WindowsMediaFormat": ["Win32_Media"], + "Win32_NetworkManagement": ["Win32"], + "Win32_NetworkManagement_Dhcp": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Dns": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_InternetConnectionWizard": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_IpHelper": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Multicast": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Ndis": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetBios": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetManagement": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetShell": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetworkDiagnosticsFramework": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_P2P": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_QoS": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Rras": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Snmp": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WNet": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WebDav": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WiFi": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsConnectionManager": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsFilteringPlatform": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsFirewall": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsNetworkVirtualization": ["Win32_NetworkManagement"], + "Win32_Networking": ["Win32"], + "Win32_Networking_ActiveDirectory": ["Win32_Networking"], + "Win32_Networking_Clustering": ["Win32_Networking"], + "Win32_Networking_HttpServer": ["Win32_Networking"], + "Win32_Networking_Ldap": ["Win32_Networking"], + "Win32_Networking_WebSocket": ["Win32_Networking"], + "Win32_Networking_WinHttp": ["Win32_Networking"], + "Win32_Networking_WinInet": ["Win32_Networking"], + "Win32_Networking_WinSock": ["Win32_Networking"], + "Win32_Networking_WindowsWebServices": ["Win32_Networking"], + "Win32_Security": ["Win32"], + "Win32_Security_AppLocker": ["Win32_Security"], + "Win32_Security_Authentication": ["Win32_Security"], + "Win32_Security_Authentication_Identity": ["Win32_Security_Authentication"], + "Win32_Security_Authorization": ["Win32_Security"], + "Win32_Security_Credentials": ["Win32_Security"], + "Win32_Security_Cryptography": ["Win32_Security"], + "Win32_Security_Cryptography_Catalog": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_Certificates": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_Sip": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_UI": ["Win32_Security_Cryptography"], + "Win32_Security_DiagnosticDataQuery": ["Win32_Security"], + "Win32_Security_DirectoryServices": ["Win32_Security"], + "Win32_Security_EnterpriseData": ["Win32_Security"], + "Win32_Security_ExtensibleAuthenticationProtocol": ["Win32_Security"], + "Win32_Security_Isolation": ["Win32_Security"], + "Win32_Security_LicenseProtection": ["Win32_Security"], + "Win32_Security_NetworkAccessProtection": ["Win32_Security"], + "Win32_Security_WinTrust": ["Win32_Security"], + "Win32_Security_WinWlx": ["Win32_Security"], + "Win32_Storage": ["Win32"], + "Win32_Storage_Cabinets": ["Win32_Storage"], + "Win32_Storage_CloudFilters": ["Win32_Storage"], + "Win32_Storage_Compression": ["Win32_Storage"], + "Win32_Storage_DistributedFileSystem": ["Win32_Storage"], + "Win32_Storage_FileHistory": ["Win32_Storage"], + "Win32_Storage_FileSystem": ["Win32_Storage"], + "Win32_Storage_Imapi": ["Win32_Storage"], + "Win32_Storage_IndexServer": ["Win32_Storage"], + "Win32_Storage_InstallableFileSystems": ["Win32_Storage"], + "Win32_Storage_IscsiDisc": ["Win32_Storage"], + "Win32_Storage_Jet": ["Win32_Storage"], + "Win32_Storage_Nvme": ["Win32_Storage"], + "Win32_Storage_OfflineFiles": ["Win32_Storage"], + "Win32_Storage_OperationRecorder": ["Win32_Storage"], + "Win32_Storage_Packaging": ["Win32_Storage"], + "Win32_Storage_Packaging_Appx": ["Win32_Storage_Packaging"], + "Win32_Storage_ProjectedFileSystem": ["Win32_Storage"], + "Win32_Storage_StructuredStorage": ["Win32_Storage"], + "Win32_Storage_Vhd": ["Win32_Storage"], + "Win32_Storage_Xps": ["Win32_Storage"], + "Win32_System": ["Win32"], + "Win32_System_AddressBook": ["Win32_System"], + "Win32_System_Antimalware": ["Win32_System"], + "Win32_System_ApplicationInstallationAndServicing": ["Win32_System"], + "Win32_System_ApplicationVerifier": ["Win32_System"], + "Win32_System_ClrHosting": ["Win32_System"], + "Win32_System_Com": ["Win32_System"], + "Win32_System_Com_Marshal": ["Win32_System_Com"], + "Win32_System_Com_StructuredStorage": ["Win32_System_Com"], + "Win32_System_Com_Urlmon": ["Win32_System_Com"], + "Win32_System_ComponentServices": ["Win32_System"], + "Win32_System_Console": ["Win32_System"], + "Win32_System_CorrelationVector": ["Win32_System"], + "Win32_System_DataExchange": ["Win32_System"], + "Win32_System_DeploymentServices": ["Win32_System"], + "Win32_System_DeveloperLicensing": ["Win32_System"], + "Win32_System_Diagnostics": ["Win32_System"], + "Win32_System_Diagnostics_Ceip": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_Debug": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_Debug_Extensions": ["Win32_System_Diagnostics_Debug"], + "Win32_System_Diagnostics_Etw": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_ProcessSnapshotting": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_ToolHelp": ["Win32_System_Diagnostics"], + "Win32_System_DistributedTransactionCoordinator": ["Win32_System"], + "Win32_System_Environment": ["Win32_System"], + "Win32_System_ErrorReporting": ["Win32_System"], + "Win32_System_EventCollector": ["Win32_System"], + "Win32_System_EventLog": ["Win32_System"], + "Win32_System_EventNotificationService": ["Win32_System"], + "Win32_System_GroupPolicy": ["Win32_System"], + "Win32_System_HostCompute": ["Win32_System"], + "Win32_System_HostComputeNetwork": ["Win32_System"], + "Win32_System_HostComputeSystem": ["Win32_System"], + "Win32_System_Hypervisor": ["Win32_System"], + "Win32_System_IO": ["Win32_System"], + "Win32_System_Iis": ["Win32_System"], + "Win32_System_Ioctl": ["Win32_System"], + "Win32_System_JobObjects": ["Win32_System"], + "Win32_System_Js": ["Win32_System"], + "Win32_System_Kernel": ["Win32_System"], + "Win32_System_LibraryLoader": ["Win32_System"], + "Win32_System_Mailslots": ["Win32_System"], + "Win32_System_Mapi": ["Win32_System"], + "Win32_System_Memory": ["Win32_System"], + "Win32_System_Memory_NonVolatile": ["Win32_System_Memory"], + "Win32_System_MessageQueuing": ["Win32_System"], + "Win32_System_MixedReality": ["Win32_System"], + "Win32_System_Ole": ["Win32_System"], + "Win32_System_PasswordManagement": ["Win32_System"], + "Win32_System_Performance": ["Win32_System"], + "Win32_System_Performance_HardwareCounterProfiling": ["Win32_System_Performance"], + "Win32_System_Pipes": ["Win32_System"], + "Win32_System_Power": ["Win32_System"], + "Win32_System_ProcessStatus": ["Win32_System"], + "Win32_System_Recovery": ["Win32_System"], + "Win32_System_Registry": ["Win32_System"], + "Win32_System_RemoteDesktop": ["Win32_System"], + "Win32_System_RemoteManagement": ["Win32_System"], + "Win32_System_RestartManager": ["Win32_System"], + "Win32_System_Restore": ["Win32_System"], + "Win32_System_Rpc": ["Win32_System"], + "Win32_System_Search": ["Win32_System"], + "Win32_System_Search_Common": ["Win32_System_Search"], + "Win32_System_SecurityCenter": ["Win32_System"], + "Win32_System_Services": ["Win32_System"], + "Win32_System_SetupAndMigration": ["Win32_System"], + "Win32_System_Shutdown": ["Win32_System"], + "Win32_System_StationsAndDesktops": ["Win32_System"], + "Win32_System_SubsystemForLinux": ["Win32_System"], + "Win32_System_SystemInformation": ["Win32_System"], + "Win32_System_SystemServices": ["Win32_System"], + "Win32_System_Threading": ["Win32_System"], + "Win32_System_Time": ["Win32_System"], + "Win32_System_TpmBaseServices": ["Win32_System"], + "Win32_System_UserAccessLogging": ["Win32_System"], + "Win32_System_Variant": ["Win32_System"], + "Win32_System_VirtualDosMachines": ["Win32_System"], + "Win32_System_WindowsProgramming": ["Win32_System"], + "Win32_System_Wmi": ["Win32_System"], + "Win32_UI": ["Win32"], + "Win32_UI_Accessibility": ["Win32_UI"], + "Win32_UI_ColorSystem": ["Win32_UI"], + "Win32_UI_Controls": ["Win32_UI"], + "Win32_UI_Controls_Dialogs": ["Win32_UI_Controls"], + "Win32_UI_HiDpi": ["Win32_UI"], + "Win32_UI_Input": ["Win32_UI"], + "Win32_UI_Input_Ime": ["Win32_UI_Input"], + "Win32_UI_Input_KeyboardAndMouse": ["Win32_UI_Input"], + "Win32_UI_Input_Pointer": ["Win32_UI_Input"], + "Win32_UI_Input_Touch": ["Win32_UI_Input"], + "Win32_UI_Input_XboxController": ["Win32_UI_Input"], + "Win32_UI_InteractionContext": ["Win32_UI"], + "Win32_UI_Magnification": ["Win32_UI"], + "Win32_UI_Shell": ["Win32_UI"], + "Win32_UI_Shell_PropertiesSystem": ["Win32_UI_Shell"], + "Win32_UI_TabletPC": ["Win32_UI"], + "Win32_UI_TextServices": ["Win32_UI"], + "Win32_UI_WindowsAndMessaging": ["Win32_UI"], + "Win32_Web": ["Win32"], + "Win32_Web_InternetExplorer": ["Win32_Web"], + "default": [], + "docs": [] + }, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2023-11-15T18:55:55Z" + }, + { + "name": "windows-sys", + "vers": "0.59.0", + "deps": [ + { + "name": "windows-targets", + "req": "^0.52.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b", + "features": { + "Wdk": ["Win32_Foundation"], + "Wdk_Devices": ["Wdk"], + "Wdk_Devices_Bluetooth": ["Wdk_Devices"], + "Wdk_Devices_HumanInterfaceDevice": ["Wdk_Devices"], + "Wdk_Foundation": ["Wdk"], + "Wdk_Graphics": ["Wdk"], + "Wdk_Graphics_Direct3D": ["Wdk_Graphics"], + "Wdk_NetworkManagement": ["Wdk"], + "Wdk_NetworkManagement_Ndis": ["Wdk_NetworkManagement"], + "Wdk_NetworkManagement_WindowsFilteringPlatform": ["Wdk_NetworkManagement"], + "Wdk_Storage": ["Wdk"], + "Wdk_Storage_FileSystem": ["Wdk_Storage"], + "Wdk_Storage_FileSystem_Minifilters": ["Wdk_Storage_FileSystem"], + "Wdk_System": ["Wdk"], + "Wdk_System_IO": ["Wdk_System"], + "Wdk_System_Memory": ["Wdk_System"], + "Wdk_System_OfflineRegistry": ["Wdk_System"], + "Wdk_System_Registry": ["Wdk_System"], + "Wdk_System_SystemInformation": ["Wdk_System"], + "Wdk_System_SystemServices": ["Wdk_System"], + "Wdk_System_Threading": ["Wdk_System"], + "Win32": ["Win32_Foundation"], + "Win32_Data": ["Win32"], + "Win32_Data_HtmlHelp": ["Win32_Data"], + "Win32_Data_RightsManagement": ["Win32_Data"], + "Win32_Devices": ["Win32"], + "Win32_Devices_AllJoyn": ["Win32_Devices"], + "Win32_Devices_BiometricFramework": ["Win32_Devices"], + "Win32_Devices_Bluetooth": ["Win32_Devices"], + "Win32_Devices_Communication": ["Win32_Devices"], + "Win32_Devices_DeviceAndDriverInstallation": ["Win32_Devices"], + "Win32_Devices_DeviceQuery": ["Win32_Devices"], + "Win32_Devices_Display": ["Win32_Devices"], + "Win32_Devices_Enumeration": ["Win32_Devices"], + "Win32_Devices_Enumeration_Pnp": ["Win32_Devices_Enumeration"], + "Win32_Devices_Fax": ["Win32_Devices"], + "Win32_Devices_HumanInterfaceDevice": ["Win32_Devices"], + "Win32_Devices_PortableDevices": ["Win32_Devices"], + "Win32_Devices_Properties": ["Win32_Devices"], + "Win32_Devices_Pwm": ["Win32_Devices"], + "Win32_Devices_Sensors": ["Win32_Devices"], + "Win32_Devices_SerialCommunication": ["Win32_Devices"], + "Win32_Devices_Tapi": ["Win32_Devices"], + "Win32_Devices_Usb": ["Win32_Devices"], + "Win32_Devices_WebServicesOnDevices": ["Win32_Devices"], + "Win32_Foundation": ["Win32"], + "Win32_Gaming": ["Win32"], + "Win32_Globalization": ["Win32"], + "Win32_Graphics": ["Win32"], + "Win32_Graphics_Dwm": ["Win32_Graphics"], + "Win32_Graphics_Gdi": ["Win32_Graphics"], + "Win32_Graphics_GdiPlus": ["Win32_Graphics"], + "Win32_Graphics_Hlsl": ["Win32_Graphics"], + "Win32_Graphics_OpenGL": ["Win32_Graphics"], + "Win32_Graphics_Printing": ["Win32_Graphics"], + "Win32_Graphics_Printing_PrintTicket": ["Win32_Graphics_Printing"], + "Win32_Management": ["Win32"], + "Win32_Management_MobileDeviceManagementRegistration": ["Win32_Management"], + "Win32_Media": ["Win32"], + "Win32_Media_Audio": ["Win32_Media"], + "Win32_Media_DxMediaObjects": ["Win32_Media"], + "Win32_Media_KernelStreaming": ["Win32_Media"], + "Win32_Media_Multimedia": ["Win32_Media"], + "Win32_Media_Streaming": ["Win32_Media"], + "Win32_Media_WindowsMediaFormat": ["Win32_Media"], + "Win32_NetworkManagement": ["Win32"], + "Win32_NetworkManagement_Dhcp": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Dns": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_InternetConnectionWizard": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_IpHelper": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Multicast": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Ndis": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetBios": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetManagement": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetShell": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetworkDiagnosticsFramework": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_P2P": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_QoS": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Rras": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Snmp": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WNet": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WebDav": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WiFi": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsConnectionManager": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsFilteringPlatform": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsFirewall": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsNetworkVirtualization": ["Win32_NetworkManagement"], + "Win32_Networking": ["Win32"], + "Win32_Networking_ActiveDirectory": ["Win32_Networking"], + "Win32_Networking_Clustering": ["Win32_Networking"], + "Win32_Networking_HttpServer": ["Win32_Networking"], + "Win32_Networking_Ldap": ["Win32_Networking"], + "Win32_Networking_WebSocket": ["Win32_Networking"], + "Win32_Networking_WinHttp": ["Win32_Networking"], + "Win32_Networking_WinInet": ["Win32_Networking"], + "Win32_Networking_WinSock": ["Win32_Networking"], + "Win32_Networking_WindowsWebServices": ["Win32_Networking"], + "Win32_Security": ["Win32"], + "Win32_Security_AppLocker": ["Win32_Security"], + "Win32_Security_Authentication": ["Win32_Security"], + "Win32_Security_Authentication_Identity": ["Win32_Security_Authentication"], + "Win32_Security_Authorization": ["Win32_Security"], + "Win32_Security_Credentials": ["Win32_Security"], + "Win32_Security_Cryptography": ["Win32_Security"], + "Win32_Security_Cryptography_Catalog": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_Certificates": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_Sip": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_UI": ["Win32_Security_Cryptography"], + "Win32_Security_DiagnosticDataQuery": ["Win32_Security"], + "Win32_Security_DirectoryServices": ["Win32_Security"], + "Win32_Security_EnterpriseData": ["Win32_Security"], + "Win32_Security_ExtensibleAuthenticationProtocol": ["Win32_Security"], + "Win32_Security_Isolation": ["Win32_Security"], + "Win32_Security_LicenseProtection": ["Win32_Security"], + "Win32_Security_NetworkAccessProtection": ["Win32_Security"], + "Win32_Security_WinTrust": ["Win32_Security"], + "Win32_Security_WinWlx": ["Win32_Security"], + "Win32_Storage": ["Win32"], + "Win32_Storage_Cabinets": ["Win32_Storage"], + "Win32_Storage_CloudFilters": ["Win32_Storage"], + "Win32_Storage_Compression": ["Win32_Storage"], + "Win32_Storage_DistributedFileSystem": ["Win32_Storage"], + "Win32_Storage_FileHistory": ["Win32_Storage"], + "Win32_Storage_FileSystem": ["Win32_Storage"], + "Win32_Storage_Imapi": ["Win32_Storage"], + "Win32_Storage_IndexServer": ["Win32_Storage"], + "Win32_Storage_InstallableFileSystems": ["Win32_Storage"], + "Win32_Storage_IscsiDisc": ["Win32_Storage"], + "Win32_Storage_Jet": ["Win32_Storage"], + "Win32_Storage_Nvme": ["Win32_Storage"], + "Win32_Storage_OfflineFiles": ["Win32_Storage"], + "Win32_Storage_OperationRecorder": ["Win32_Storage"], + "Win32_Storage_Packaging": ["Win32_Storage"], + "Win32_Storage_Packaging_Appx": ["Win32_Storage_Packaging"], + "Win32_Storage_ProjectedFileSystem": ["Win32_Storage"], + "Win32_Storage_StructuredStorage": ["Win32_Storage"], + "Win32_Storage_Vhd": ["Win32_Storage"], + "Win32_Storage_Xps": ["Win32_Storage"], + "Win32_System": ["Win32"], + "Win32_System_AddressBook": ["Win32_System"], + "Win32_System_Antimalware": ["Win32_System"], + "Win32_System_ApplicationInstallationAndServicing": ["Win32_System"], + "Win32_System_ApplicationVerifier": ["Win32_System"], + "Win32_System_ClrHosting": ["Win32_System"], + "Win32_System_Com": ["Win32_System"], + "Win32_System_Com_Marshal": ["Win32_System_Com"], + "Win32_System_Com_StructuredStorage": ["Win32_System_Com"], + "Win32_System_Com_Urlmon": ["Win32_System_Com"], + "Win32_System_ComponentServices": ["Win32_System"], + "Win32_System_Console": ["Win32_System"], + "Win32_System_CorrelationVector": ["Win32_System"], + "Win32_System_DataExchange": ["Win32_System"], + "Win32_System_DeploymentServices": ["Win32_System"], + "Win32_System_DeveloperLicensing": ["Win32_System"], + "Win32_System_Diagnostics": ["Win32_System"], + "Win32_System_Diagnostics_Ceip": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_Debug": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_Debug_Extensions": ["Win32_System_Diagnostics_Debug"], + "Win32_System_Diagnostics_Etw": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_ProcessSnapshotting": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_ToolHelp": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_TraceLogging": ["Win32_System_Diagnostics"], + "Win32_System_DistributedTransactionCoordinator": ["Win32_System"], + "Win32_System_Environment": ["Win32_System"], + "Win32_System_ErrorReporting": ["Win32_System"], + "Win32_System_EventCollector": ["Win32_System"], + "Win32_System_EventLog": ["Win32_System"], + "Win32_System_EventNotificationService": ["Win32_System"], + "Win32_System_GroupPolicy": ["Win32_System"], + "Win32_System_HostCompute": ["Win32_System"], + "Win32_System_HostComputeNetwork": ["Win32_System"], + "Win32_System_HostComputeSystem": ["Win32_System"], + "Win32_System_Hypervisor": ["Win32_System"], + "Win32_System_IO": ["Win32_System"], + "Win32_System_Iis": ["Win32_System"], + "Win32_System_Ioctl": ["Win32_System"], + "Win32_System_JobObjects": ["Win32_System"], + "Win32_System_Js": ["Win32_System"], + "Win32_System_Kernel": ["Win32_System"], + "Win32_System_LibraryLoader": ["Win32_System"], + "Win32_System_Mailslots": ["Win32_System"], + "Win32_System_Mapi": ["Win32_System"], + "Win32_System_Memory": ["Win32_System"], + "Win32_System_Memory_NonVolatile": ["Win32_System_Memory"], + "Win32_System_MessageQueuing": ["Win32_System"], + "Win32_System_MixedReality": ["Win32_System"], + "Win32_System_Ole": ["Win32_System"], + "Win32_System_PasswordManagement": ["Win32_System"], + "Win32_System_Performance": ["Win32_System"], + "Win32_System_Performance_HardwareCounterProfiling": ["Win32_System_Performance"], + "Win32_System_Pipes": ["Win32_System"], + "Win32_System_Power": ["Win32_System"], + "Win32_System_ProcessStatus": ["Win32_System"], + "Win32_System_Recovery": ["Win32_System"], + "Win32_System_Registry": ["Win32_System"], + "Win32_System_RemoteDesktop": ["Win32_System"], + "Win32_System_RemoteManagement": ["Win32_System"], + "Win32_System_RestartManager": ["Win32_System"], + "Win32_System_Restore": ["Win32_System"], + "Win32_System_Rpc": ["Win32_System"], + "Win32_System_Search": ["Win32_System"], + "Win32_System_Search_Common": ["Win32_System_Search"], + "Win32_System_SecurityCenter": ["Win32_System"], + "Win32_System_Services": ["Win32_System"], + "Win32_System_SetupAndMigration": ["Win32_System"], + "Win32_System_Shutdown": ["Win32_System"], + "Win32_System_StationsAndDesktops": ["Win32_System"], + "Win32_System_SubsystemForLinux": ["Win32_System"], + "Win32_System_SystemInformation": ["Win32_System"], + "Win32_System_SystemServices": ["Win32_System"], + "Win32_System_Threading": ["Win32_System"], + "Win32_System_Time": ["Win32_System"], + "Win32_System_TpmBaseServices": ["Win32_System"], + "Win32_System_UserAccessLogging": ["Win32_System"], + "Win32_System_Variant": ["Win32_System"], + "Win32_System_VirtualDosMachines": ["Win32_System"], + "Win32_System_WindowsProgramming": ["Win32_System"], + "Win32_System_Wmi": ["Win32_System"], + "Win32_UI": ["Win32"], + "Win32_UI_Accessibility": ["Win32_UI"], + "Win32_UI_ColorSystem": ["Win32_UI"], + "Win32_UI_Controls": ["Win32_UI"], + "Win32_UI_Controls_Dialogs": ["Win32_UI_Controls"], + "Win32_UI_HiDpi": ["Win32_UI"], + "Win32_UI_Input": ["Win32_UI"], + "Win32_UI_Input_Ime": ["Win32_UI_Input"], + "Win32_UI_Input_KeyboardAndMouse": ["Win32_UI_Input"], + "Win32_UI_Input_Pointer": ["Win32_UI_Input"], + "Win32_UI_Input_Touch": ["Win32_UI_Input"], + "Win32_UI_Input_XboxController": ["Win32_UI_Input"], + "Win32_UI_InteractionContext": ["Win32_UI"], + "Win32_UI_Magnification": ["Win32_UI"], + "Win32_UI_Shell": ["Win32_UI"], + "Win32_UI_Shell_Common": ["Win32_UI_Shell"], + "Win32_UI_Shell_PropertiesSystem": ["Win32_UI_Shell"], + "Win32_UI_TabletPC": ["Win32_UI"], + "Win32_UI_TextServices": ["Win32_UI"], + "Win32_UI_WindowsAndMessaging": ["Win32_UI"], + "Win32_Web": ["Win32"], + "Win32_Web_InternetExplorer": ["Win32_Web"], + "default": [], + "docs": [] + }, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2024-07-30T15:26:17Z" + }, + { + "name": "windows-sys", + "vers": "0.60.2", + "deps": [ + { + "name": "windows-targets", + "req": "^0.53.2", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb", + "features": { + "Wdk": ["Win32_Foundation"], + "Wdk_Devices": ["Wdk"], + "Wdk_Devices_Bluetooth": ["Wdk_Devices"], + "Wdk_Devices_HumanInterfaceDevice": ["Wdk_Devices"], + "Wdk_Foundation": ["Wdk"], + "Wdk_Graphics": ["Wdk"], + "Wdk_Graphics_Direct3D": ["Wdk_Graphics"], + "Wdk_NetworkManagement": ["Wdk"], + "Wdk_NetworkManagement_Ndis": ["Wdk_NetworkManagement"], + "Wdk_NetworkManagement_WindowsFilteringPlatform": ["Wdk_NetworkManagement"], + "Wdk_Storage": ["Wdk"], + "Wdk_Storage_FileSystem": ["Wdk_Storage"], + "Wdk_Storage_FileSystem_Minifilters": ["Wdk_Storage_FileSystem"], + "Wdk_System": ["Wdk"], + "Wdk_System_IO": ["Wdk_System"], + "Wdk_System_Memory": ["Wdk_System"], + "Wdk_System_OfflineRegistry": ["Wdk_System"], + "Wdk_System_Registry": ["Wdk_System"], + "Wdk_System_SystemInformation": ["Wdk_System"], + "Wdk_System_SystemServices": ["Wdk_System"], + "Wdk_System_Threading": ["Wdk_System"], + "Win32": ["Win32_Foundation"], + "Win32_Data": ["Win32"], + "Win32_Data_HtmlHelp": ["Win32_Data"], + "Win32_Data_RightsManagement": ["Win32_Data"], + "Win32_Devices": ["Win32"], + "Win32_Devices_AllJoyn": ["Win32_Devices"], + "Win32_Devices_Beep": ["Win32_Devices"], + "Win32_Devices_BiometricFramework": ["Win32_Devices"], + "Win32_Devices_Bluetooth": ["Win32_Devices"], + "Win32_Devices_Cdrom": ["Win32_Devices"], + "Win32_Devices_Communication": ["Win32_Devices"], + "Win32_Devices_DeviceAndDriverInstallation": ["Win32_Devices"], + "Win32_Devices_DeviceQuery": ["Win32_Devices"], + "Win32_Devices_Display": ["Win32_Devices"], + "Win32_Devices_Dvd": ["Win32_Devices"], + "Win32_Devices_Enumeration": ["Win32_Devices"], + "Win32_Devices_Enumeration_Pnp": ["Win32_Devices_Enumeration"], + "Win32_Devices_Fax": ["Win32_Devices"], + "Win32_Devices_HumanInterfaceDevice": ["Win32_Devices"], + "Win32_Devices_Nfc": ["Win32_Devices"], + "Win32_Devices_Nfp": ["Win32_Devices"], + "Win32_Devices_PortableDevices": ["Win32_Devices"], + "Win32_Devices_Properties": ["Win32_Devices"], + "Win32_Devices_Pwm": ["Win32_Devices"], + "Win32_Devices_Sensors": ["Win32_Devices"], + "Win32_Devices_SerialCommunication": ["Win32_Devices"], + "Win32_Devices_Tapi": ["Win32_Devices"], + "Win32_Devices_Usb": ["Win32_Devices"], + "Win32_Devices_WebServicesOnDevices": ["Win32_Devices"], + "Win32_Foundation": ["Win32"], + "Win32_Gaming": ["Win32"], + "Win32_Globalization": ["Win32"], + "Win32_Graphics": ["Win32"], + "Win32_Graphics_Dwm": ["Win32_Graphics"], + "Win32_Graphics_Gdi": ["Win32_Graphics"], + "Win32_Graphics_GdiPlus": ["Win32_Graphics"], + "Win32_Graphics_Hlsl": ["Win32_Graphics"], + "Win32_Graphics_OpenGL": ["Win32_Graphics"], + "Win32_Graphics_Printing": ["Win32_Graphics"], + "Win32_Graphics_Printing_PrintTicket": ["Win32_Graphics_Printing"], + "Win32_Management": ["Win32"], + "Win32_Management_MobileDeviceManagementRegistration": ["Win32_Management"], + "Win32_Media": ["Win32"], + "Win32_Media_Audio": ["Win32_Media"], + "Win32_Media_DxMediaObjects": ["Win32_Media"], + "Win32_Media_KernelStreaming": ["Win32_Media"], + "Win32_Media_Multimedia": ["Win32_Media"], + "Win32_Media_Streaming": ["Win32_Media"], + "Win32_Media_WindowsMediaFormat": ["Win32_Media"], + "Win32_NetworkManagement": ["Win32"], + "Win32_NetworkManagement_Dhcp": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Dns": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_InternetConnectionWizard": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_IpHelper": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Multicast": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Ndis": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetBios": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetManagement": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetShell": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetworkDiagnosticsFramework": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_P2P": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_QoS": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Rras": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Snmp": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WNet": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WebDav": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WiFi": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsConnectionManager": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsFilteringPlatform": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsFirewall": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsNetworkVirtualization": ["Win32_NetworkManagement"], + "Win32_Networking": ["Win32"], + "Win32_Networking_ActiveDirectory": ["Win32_Networking"], + "Win32_Networking_Clustering": ["Win32_Networking"], + "Win32_Networking_HttpServer": ["Win32_Networking"], + "Win32_Networking_Ldap": ["Win32_Networking"], + "Win32_Networking_WebSocket": ["Win32_Networking"], + "Win32_Networking_WinHttp": ["Win32_Networking"], + "Win32_Networking_WinInet": ["Win32_Networking"], + "Win32_Networking_WinSock": ["Win32_Networking"], + "Win32_Networking_WindowsWebServices": ["Win32_Networking"], + "Win32_Security": ["Win32"], + "Win32_Security_AppLocker": ["Win32_Security"], + "Win32_Security_Authentication": ["Win32_Security"], + "Win32_Security_Authentication_Identity": ["Win32_Security_Authentication"], + "Win32_Security_Authorization": ["Win32_Security"], + "Win32_Security_Credentials": ["Win32_Security"], + "Win32_Security_Cryptography": ["Win32_Security"], + "Win32_Security_Cryptography_Catalog": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_Certificates": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_Sip": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_UI": ["Win32_Security_Cryptography"], + "Win32_Security_DiagnosticDataQuery": ["Win32_Security"], + "Win32_Security_DirectoryServices": ["Win32_Security"], + "Win32_Security_EnterpriseData": ["Win32_Security"], + "Win32_Security_ExtensibleAuthenticationProtocol": ["Win32_Security"], + "Win32_Security_Isolation": ["Win32_Security"], + "Win32_Security_LicenseProtection": ["Win32_Security"], + "Win32_Security_NetworkAccessProtection": ["Win32_Security"], + "Win32_Security_WinTrust": ["Win32_Security"], + "Win32_Security_WinWlx": ["Win32_Security"], + "Win32_Storage": ["Win32"], + "Win32_Storage_Cabinets": ["Win32_Storage"], + "Win32_Storage_CloudFilters": ["Win32_Storage"], + "Win32_Storage_Compression": ["Win32_Storage"], + "Win32_Storage_DistributedFileSystem": ["Win32_Storage"], + "Win32_Storage_FileHistory": ["Win32_Storage"], + "Win32_Storage_FileSystem": ["Win32_Storage"], + "Win32_Storage_Imapi": ["Win32_Storage"], + "Win32_Storage_IndexServer": ["Win32_Storage"], + "Win32_Storage_InstallableFileSystems": ["Win32_Storage"], + "Win32_Storage_IscsiDisc": ["Win32_Storage"], + "Win32_Storage_Jet": ["Win32_Storage"], + "Win32_Storage_Nvme": ["Win32_Storage"], + "Win32_Storage_OfflineFiles": ["Win32_Storage"], + "Win32_Storage_OperationRecorder": ["Win32_Storage"], + "Win32_Storage_Packaging": ["Win32_Storage"], + "Win32_Storage_Packaging_Appx": ["Win32_Storage_Packaging"], + "Win32_Storage_ProjectedFileSystem": ["Win32_Storage"], + "Win32_Storage_StructuredStorage": ["Win32_Storage"], + "Win32_Storage_Vhd": ["Win32_Storage"], + "Win32_Storage_Xps": ["Win32_Storage"], + "Win32_System": ["Win32"], + "Win32_System_AddressBook": ["Win32_System"], + "Win32_System_Antimalware": ["Win32_System"], + "Win32_System_ApplicationInstallationAndServicing": ["Win32_System"], + "Win32_System_ApplicationVerifier": ["Win32_System"], + "Win32_System_ClrHosting": ["Win32_System"], + "Win32_System_Com": ["Win32_System"], + "Win32_System_Com_Marshal": ["Win32_System_Com"], + "Win32_System_Com_StructuredStorage": ["Win32_System_Com"], + "Win32_System_Com_Urlmon": ["Win32_System_Com"], + "Win32_System_ComponentServices": ["Win32_System"], + "Win32_System_Console": ["Win32_System"], + "Win32_System_CorrelationVector": ["Win32_System"], + "Win32_System_DataExchange": ["Win32_System"], + "Win32_System_DeploymentServices": ["Win32_System"], + "Win32_System_DeveloperLicensing": ["Win32_System"], + "Win32_System_Diagnostics": ["Win32_System"], + "Win32_System_Diagnostics_Ceip": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_Debug": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_Debug_Extensions": ["Win32_System_Diagnostics_Debug"], + "Win32_System_Diagnostics_Etw": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_ProcessSnapshotting": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_ToolHelp": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_TraceLogging": ["Win32_System_Diagnostics"], + "Win32_System_DistributedTransactionCoordinator": ["Win32_System"], + "Win32_System_Environment": ["Win32_System"], + "Win32_System_ErrorReporting": ["Win32_System"], + "Win32_System_EventCollector": ["Win32_System"], + "Win32_System_EventLog": ["Win32_System"], + "Win32_System_EventNotificationService": ["Win32_System"], + "Win32_System_GroupPolicy": ["Win32_System"], + "Win32_System_HostCompute": ["Win32_System"], + "Win32_System_HostComputeNetwork": ["Win32_System"], + "Win32_System_HostComputeSystem": ["Win32_System"], + "Win32_System_Hypervisor": ["Win32_System"], + "Win32_System_IO": ["Win32_System"], + "Win32_System_Iis": ["Win32_System"], + "Win32_System_Ioctl": ["Win32_System"], + "Win32_System_JobObjects": ["Win32_System"], + "Win32_System_Js": ["Win32_System"], + "Win32_System_Kernel": ["Win32_System"], + "Win32_System_LibraryLoader": ["Win32_System"], + "Win32_System_Mailslots": ["Win32_System"], + "Win32_System_Mapi": ["Win32_System"], + "Win32_System_Memory": ["Win32_System"], + "Win32_System_Memory_NonVolatile": ["Win32_System_Memory"], + "Win32_System_MessageQueuing": ["Win32_System"], + "Win32_System_MixedReality": ["Win32_System"], + "Win32_System_Ole": ["Win32_System"], + "Win32_System_PasswordManagement": ["Win32_System"], + "Win32_System_Performance": ["Win32_System"], + "Win32_System_Performance_HardwareCounterProfiling": ["Win32_System_Performance"], + "Win32_System_Pipes": ["Win32_System"], + "Win32_System_Power": ["Win32_System"], + "Win32_System_ProcessStatus": ["Win32_System"], + "Win32_System_Recovery": ["Win32_System"], + "Win32_System_Registry": ["Win32_System"], + "Win32_System_RemoteDesktop": ["Win32_System"], + "Win32_System_RemoteManagement": ["Win32_System"], + "Win32_System_RestartManager": ["Win32_System"], + "Win32_System_Restore": ["Win32_System"], + "Win32_System_Rpc": ["Win32_System"], + "Win32_System_Search": ["Win32_System"], + "Win32_System_Search_Common": ["Win32_System_Search"], + "Win32_System_SecurityCenter": ["Win32_System"], + "Win32_System_Services": ["Win32_System"], + "Win32_System_SetupAndMigration": ["Win32_System"], + "Win32_System_Shutdown": ["Win32_System"], + "Win32_System_StationsAndDesktops": ["Win32_System"], + "Win32_System_SubsystemForLinux": ["Win32_System"], + "Win32_System_SystemInformation": ["Win32_System"], + "Win32_System_SystemServices": ["Win32_System"], + "Win32_System_Threading": ["Win32_System"], + "Win32_System_Time": ["Win32_System"], + "Win32_System_TpmBaseServices": ["Win32_System"], + "Win32_System_UserAccessLogging": ["Win32_System"], + "Win32_System_Variant": ["Win32_System"], + "Win32_System_VirtualDosMachines": ["Win32_System"], + "Win32_System_WindowsProgramming": ["Win32_System"], + "Win32_System_Wmi": ["Win32_System"], + "Win32_UI": ["Win32"], + "Win32_UI_Accessibility": ["Win32_UI"], + "Win32_UI_ColorSystem": ["Win32_UI"], + "Win32_UI_Controls": ["Win32_UI"], + "Win32_UI_Controls_Dialogs": ["Win32_UI_Controls"], + "Win32_UI_HiDpi": ["Win32_UI"], + "Win32_UI_Input": ["Win32_UI"], + "Win32_UI_Input_Ime": ["Win32_UI_Input"], + "Win32_UI_Input_KeyboardAndMouse": ["Win32_UI_Input"], + "Win32_UI_Input_Pointer": ["Win32_UI_Input"], + "Win32_UI_Input_Touch": ["Win32_UI_Input"], + "Win32_UI_Input_XboxController": ["Win32_UI_Input"], + "Win32_UI_InteractionContext": ["Win32_UI"], + "Win32_UI_Magnification": ["Win32_UI"], + "Win32_UI_Shell": ["Win32_UI"], + "Win32_UI_Shell_Common": ["Win32_UI_Shell"], + "Win32_UI_Shell_PropertiesSystem": ["Win32_UI_Shell"], + "Win32_UI_TabletPC": ["Win32_UI"], + "Win32_UI_TextServices": ["Win32_UI"], + "Win32_UI_WindowsAndMessaging": ["Win32_UI"], + "Win32_Web": ["Win32"], + "Win32_Web_InternetExplorer": ["Win32_Web"], + "default": [], + "docs": [] + }, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-06-12T18:59:32Z" + }, + { + "name": "windows-sys", + "vers": "0.61.2", + "deps": [ + { + "name": "windows-link", + "req": "^0.2.1", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc", + "features": { + "Wdk": ["Win32_Foundation"], + "Wdk_Devices": ["Wdk"], + "Wdk_Devices_Bluetooth": ["Wdk_Devices"], + "Wdk_Devices_HumanInterfaceDevice": ["Wdk_Devices"], + "Wdk_Foundation": ["Wdk"], + "Wdk_Graphics": ["Wdk"], + "Wdk_Graphics_Direct3D": ["Wdk_Graphics"], + "Wdk_NetworkManagement": ["Wdk"], + "Wdk_NetworkManagement_Ndis": ["Wdk_NetworkManagement"], + "Wdk_NetworkManagement_WindowsFilteringPlatform": ["Wdk_NetworkManagement"], + "Wdk_Storage": ["Wdk"], + "Wdk_Storage_FileSystem": ["Wdk_Storage"], + "Wdk_Storage_FileSystem_Minifilters": ["Wdk_Storage_FileSystem"], + "Wdk_System": ["Wdk"], + "Wdk_System_IO": ["Wdk_System"], + "Wdk_System_Memory": ["Wdk_System"], + "Wdk_System_OfflineRegistry": ["Wdk_System"], + "Wdk_System_Registry": ["Wdk_System"], + "Wdk_System_SystemInformation": ["Wdk_System"], + "Wdk_System_SystemServices": ["Wdk_System"], + "Wdk_System_Threading": ["Wdk_System"], + "Win32": ["Win32_Foundation"], + "Win32_Data": ["Win32"], + "Win32_Data_HtmlHelp": ["Win32_Data"], + "Win32_Data_RightsManagement": ["Win32_Data"], + "Win32_Devices": ["Win32"], + "Win32_Devices_AllJoyn": ["Win32_Devices"], + "Win32_Devices_Beep": ["Win32_Devices"], + "Win32_Devices_BiometricFramework": ["Win32_Devices"], + "Win32_Devices_Bluetooth": ["Win32_Devices"], + "Win32_Devices_Cdrom": ["Win32_Devices"], + "Win32_Devices_Communication": ["Win32_Devices"], + "Win32_Devices_DeviceAndDriverInstallation": ["Win32_Devices"], + "Win32_Devices_DeviceQuery": ["Win32_Devices"], + "Win32_Devices_Display": ["Win32_Devices"], + "Win32_Devices_Dvd": ["Win32_Devices"], + "Win32_Devices_Enumeration": ["Win32_Devices"], + "Win32_Devices_Enumeration_Pnp": ["Win32_Devices_Enumeration"], + "Win32_Devices_Fax": ["Win32_Devices"], + "Win32_Devices_HumanInterfaceDevice": ["Win32_Devices"], + "Win32_Devices_Nfc": ["Win32_Devices"], + "Win32_Devices_Nfp": ["Win32_Devices"], + "Win32_Devices_PortableDevices": ["Win32_Devices"], + "Win32_Devices_Properties": ["Win32_Devices"], + "Win32_Devices_Pwm": ["Win32_Devices"], + "Win32_Devices_Sensors": ["Win32_Devices"], + "Win32_Devices_SerialCommunication": ["Win32_Devices"], + "Win32_Devices_Tapi": ["Win32_Devices"], + "Win32_Devices_Usb": ["Win32_Devices"], + "Win32_Devices_WebServicesOnDevices": ["Win32_Devices"], + "Win32_Foundation": ["Win32"], + "Win32_Gaming": ["Win32"], + "Win32_Globalization": ["Win32"], + "Win32_Graphics": ["Win32"], + "Win32_Graphics_Dwm": ["Win32_Graphics"], + "Win32_Graphics_Gdi": ["Win32_Graphics"], + "Win32_Graphics_GdiPlus": ["Win32_Graphics"], + "Win32_Graphics_Hlsl": ["Win32_Graphics"], + "Win32_Graphics_OpenGL": ["Win32_Graphics"], + "Win32_Graphics_Printing": ["Win32_Graphics"], + "Win32_Graphics_Printing_PrintTicket": ["Win32_Graphics_Printing"], + "Win32_Management": ["Win32"], + "Win32_Management_MobileDeviceManagementRegistration": ["Win32_Management"], + "Win32_Media": ["Win32"], + "Win32_Media_Audio": ["Win32_Media"], + "Win32_Media_DxMediaObjects": ["Win32_Media"], + "Win32_Media_KernelStreaming": ["Win32_Media"], + "Win32_Media_Multimedia": ["Win32_Media"], + "Win32_Media_Streaming": ["Win32_Media"], + "Win32_Media_WindowsMediaFormat": ["Win32_Media"], + "Win32_NetworkManagement": ["Win32"], + "Win32_NetworkManagement_Dhcp": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Dns": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_InternetConnectionWizard": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_IpHelper": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Multicast": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Ndis": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetBios": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetManagement": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetShell": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_NetworkDiagnosticsFramework": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_P2P": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_QoS": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Rras": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_Snmp": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WNet": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WebDav": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WiFi": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsConnectionManager": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsFilteringPlatform": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsFirewall": ["Win32_NetworkManagement"], + "Win32_NetworkManagement_WindowsNetworkVirtualization": ["Win32_NetworkManagement"], + "Win32_Networking": ["Win32"], + "Win32_Networking_ActiveDirectory": ["Win32_Networking"], + "Win32_Networking_Clustering": ["Win32_Networking"], + "Win32_Networking_HttpServer": ["Win32_Networking"], + "Win32_Networking_Ldap": ["Win32_Networking"], + "Win32_Networking_WebSocket": ["Win32_Networking"], + "Win32_Networking_WinHttp": ["Win32_Networking"], + "Win32_Networking_WinInet": ["Win32_Networking"], + "Win32_Networking_WinSock": ["Win32_Networking"], + "Win32_Networking_WindowsWebServices": ["Win32_Networking"], + "Win32_Security": ["Win32"], + "Win32_Security_AppLocker": ["Win32_Security"], + "Win32_Security_Authentication": ["Win32_Security"], + "Win32_Security_Authentication_Identity": ["Win32_Security_Authentication"], + "Win32_Security_Authorization": ["Win32_Security"], + "Win32_Security_Credentials": ["Win32_Security"], + "Win32_Security_Cryptography": ["Win32_Security"], + "Win32_Security_Cryptography_Catalog": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_Certificates": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_Sip": ["Win32_Security_Cryptography"], + "Win32_Security_Cryptography_UI": ["Win32_Security_Cryptography"], + "Win32_Security_DiagnosticDataQuery": ["Win32_Security"], + "Win32_Security_DirectoryServices": ["Win32_Security"], + "Win32_Security_EnterpriseData": ["Win32_Security"], + "Win32_Security_ExtensibleAuthenticationProtocol": ["Win32_Security"], + "Win32_Security_Isolation": ["Win32_Security"], + "Win32_Security_LicenseProtection": ["Win32_Security"], + "Win32_Security_NetworkAccessProtection": ["Win32_Security"], + "Win32_Security_WinTrust": ["Win32_Security"], + "Win32_Security_WinWlx": ["Win32_Security"], + "Win32_Storage": ["Win32"], + "Win32_Storage_Cabinets": ["Win32_Storage"], + "Win32_Storage_CloudFilters": ["Win32_Storage"], + "Win32_Storage_Compression": ["Win32_Storage"], + "Win32_Storage_DistributedFileSystem": ["Win32_Storage"], + "Win32_Storage_FileHistory": ["Win32_Storage"], + "Win32_Storage_FileSystem": ["Win32_Storage"], + "Win32_Storage_Imapi": ["Win32_Storage"], + "Win32_Storage_IndexServer": ["Win32_Storage"], + "Win32_Storage_InstallableFileSystems": ["Win32_Storage"], + "Win32_Storage_IscsiDisc": ["Win32_Storage"], + "Win32_Storage_Jet": ["Win32_Storage"], + "Win32_Storage_Nvme": ["Win32_Storage"], + "Win32_Storage_OfflineFiles": ["Win32_Storage"], + "Win32_Storage_OperationRecorder": ["Win32_Storage"], + "Win32_Storage_Packaging": ["Win32_Storage"], + "Win32_Storage_Packaging_Appx": ["Win32_Storage_Packaging"], + "Win32_Storage_ProjectedFileSystem": ["Win32_Storage"], + "Win32_Storage_StructuredStorage": ["Win32_Storage"], + "Win32_Storage_Vhd": ["Win32_Storage"], + "Win32_Storage_Xps": ["Win32_Storage"], + "Win32_System": ["Win32"], + "Win32_System_AddressBook": ["Win32_System"], + "Win32_System_Antimalware": ["Win32_System"], + "Win32_System_ApplicationInstallationAndServicing": ["Win32_System"], + "Win32_System_ApplicationVerifier": ["Win32_System"], + "Win32_System_ClrHosting": ["Win32_System"], + "Win32_System_Com": ["Win32_System"], + "Win32_System_Com_Marshal": ["Win32_System_Com"], + "Win32_System_Com_StructuredStorage": ["Win32_System_Com"], + "Win32_System_Com_Urlmon": ["Win32_System_Com"], + "Win32_System_ComponentServices": ["Win32_System"], + "Win32_System_Console": ["Win32_System"], + "Win32_System_CorrelationVector": ["Win32_System"], + "Win32_System_DataExchange": ["Win32_System"], + "Win32_System_DeploymentServices": ["Win32_System"], + "Win32_System_DeveloperLicensing": ["Win32_System"], + "Win32_System_Diagnostics": ["Win32_System"], + "Win32_System_Diagnostics_Ceip": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_Debug": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_Debug_Extensions": ["Win32_System_Diagnostics_Debug"], + "Win32_System_Diagnostics_Etw": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_ProcessSnapshotting": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_ToolHelp": ["Win32_System_Diagnostics"], + "Win32_System_Diagnostics_TraceLogging": ["Win32_System_Diagnostics"], + "Win32_System_DistributedTransactionCoordinator": ["Win32_System"], + "Win32_System_Environment": ["Win32_System"], + "Win32_System_ErrorReporting": ["Win32_System"], + "Win32_System_EventCollector": ["Win32_System"], + "Win32_System_EventLog": ["Win32_System"], + "Win32_System_EventNotificationService": ["Win32_System"], + "Win32_System_GroupPolicy": ["Win32_System"], + "Win32_System_HostCompute": ["Win32_System"], + "Win32_System_HostComputeNetwork": ["Win32_System"], + "Win32_System_HostComputeSystem": ["Win32_System"], + "Win32_System_Hypervisor": ["Win32_System"], + "Win32_System_IO": ["Win32_System"], + "Win32_System_Iis": ["Win32_System"], + "Win32_System_Ioctl": ["Win32_System"], + "Win32_System_JobObjects": ["Win32_System"], + "Win32_System_Js": ["Win32_System"], + "Win32_System_Kernel": ["Win32_System"], + "Win32_System_LibraryLoader": ["Win32_System"], + "Win32_System_Mailslots": ["Win32_System"], + "Win32_System_Mapi": ["Win32_System"], + "Win32_System_Memory": ["Win32_System"], + "Win32_System_Memory_NonVolatile": ["Win32_System_Memory"], + "Win32_System_MessageQueuing": ["Win32_System"], + "Win32_System_MixedReality": ["Win32_System"], + "Win32_System_Ole": ["Win32_System"], + "Win32_System_PasswordManagement": ["Win32_System"], + "Win32_System_Performance": ["Win32_System"], + "Win32_System_Performance_HardwareCounterProfiling": ["Win32_System_Performance"], + "Win32_System_Pipes": ["Win32_System"], + "Win32_System_Power": ["Win32_System"], + "Win32_System_ProcessStatus": ["Win32_System"], + "Win32_System_Recovery": ["Win32_System"], + "Win32_System_Registry": ["Win32_System"], + "Win32_System_RemoteDesktop": ["Win32_System"], + "Win32_System_RemoteManagement": ["Win32_System"], + "Win32_System_RestartManager": ["Win32_System"], + "Win32_System_Restore": ["Win32_System"], + "Win32_System_Rpc": ["Win32_System"], + "Win32_System_Search": ["Win32_System"], + "Win32_System_Search_Common": ["Win32_System_Search"], + "Win32_System_SecurityCenter": ["Win32_System"], + "Win32_System_Services": ["Win32_System"], + "Win32_System_SetupAndMigration": ["Win32_System"], + "Win32_System_Shutdown": ["Win32_System"], + "Win32_System_StationsAndDesktops": ["Win32_System"], + "Win32_System_SubsystemForLinux": ["Win32_System"], + "Win32_System_SystemInformation": ["Win32_System"], + "Win32_System_SystemServices": ["Win32_System"], + "Win32_System_Threading": ["Win32_System"], + "Win32_System_Time": ["Win32_System"], + "Win32_System_TpmBaseServices": ["Win32_System"], + "Win32_System_UserAccessLogging": ["Win32_System"], + "Win32_System_Variant": ["Win32_System"], + "Win32_System_VirtualDosMachines": ["Win32_System"], + "Win32_System_WindowsProgramming": ["Win32_System"], + "Win32_System_Wmi": ["Win32_System"], + "Win32_UI": ["Win32"], + "Win32_UI_Accessibility": ["Win32_UI"], + "Win32_UI_ColorSystem": ["Win32_UI"], + "Win32_UI_Controls": ["Win32_UI"], + "Win32_UI_Controls_Dialogs": ["Win32_UI_Controls"], + "Win32_UI_HiDpi": ["Win32_UI"], + "Win32_UI_Input": ["Win32_UI"], + "Win32_UI_Input_Ime": ["Win32_UI_Input"], + "Win32_UI_Input_KeyboardAndMouse": ["Win32_UI_Input"], + "Win32_UI_Input_Pointer": ["Win32_UI_Input"], + "Win32_UI_Input_Touch": ["Win32_UI_Input"], + "Win32_UI_Input_XboxController": ["Win32_UI_Input"], + "Win32_UI_InteractionContext": ["Win32_UI"], + "Win32_UI_Magnification": ["Win32_UI"], + "Win32_UI_Shell": ["Win32_UI"], + "Win32_UI_Shell_Common": ["Win32_UI_Shell"], + "Win32_UI_Shell_PropertiesSystem": ["Win32_UI_Shell"], + "Win32_UI_TabletPC": ["Win32_UI"], + "Win32_UI_TextServices": ["Win32_UI"], + "Win32_UI_WindowsAndMessaging": ["Win32_UI"], + "Win32_Web": ["Win32"], + "Win32_Web_InternetExplorer": ["Win32_Web"], + "default": [], + "docs": [] + }, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2025-10-06T19:18:30Z" + } + ] + }, + { + "path": "wi/nd/windows-targets", + "header": "AwIAAABldGFnOiAiMDRhNGYyMTdkYjg4MjFlNzU4YTAyMzE4YjM1ODA4ZGMiAA==", + "records": [ + { + "name": "windows-targets", + "vers": "0.48.5", + "deps": [ + { + "name": "windows_aarch64_gnullvm", + "req": "^0.48.5", + "features": [], + "optional": false, + "default_features": true, + "target": "aarch64-pc-windows-gnullvm", + "kind": "normal" + }, + { + "name": "windows_aarch64_msvc", + "req": "^0.48.5", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"aarch64\", target_env = \"msvc\", not(windows_raw_dylib)))", + "kind": "normal" + }, + { + "name": "windows_i686_gnu", + "req": "^0.48.5", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"x86\", target_env = \"gnu\", not(windows_raw_dylib)))", + "kind": "normal" + }, + { + "name": "windows_i686_msvc", + "req": "^0.48.5", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"x86\", target_env = \"msvc\", not(windows_raw_dylib)))", + "kind": "normal" + }, + { + "name": "windows_x86_64_gnu", + "req": "^0.48.5", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"x86_64\", target_env = \"gnu\", not(target_abi = \"llvm\"), not(windows_raw_dylib)))", + "kind": "normal" + }, + { + "name": "windows_x86_64_gnullvm", + "req": "^0.48.5", + "features": [], + "optional": false, + "default_features": true, + "target": "x86_64-pc-windows-gnullvm", + "kind": "normal" + }, + { + "name": "windows_x86_64_msvc", + "req": "^0.48.5", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"x86_64\", target_env = \"msvc\", not(windows_raw_dylib)))", + "kind": "normal" + } + ], + "cksum": "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c", + "features": {}, + "yanked": false, + "pubtime": "2023-08-18T17:48:34Z" + }, + { + "name": "windows-targets", + "vers": "0.52.6", + "deps": [ + { + "name": "windows_aarch64_gnullvm", + "req": "^0.52.6", + "features": [], + "optional": false, + "default_features": true, + "target": "aarch64-pc-windows-gnullvm", + "kind": "normal" + }, + { + "name": "windows_aarch64_msvc", + "req": "^0.52.6", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"aarch64\", target_env = \"msvc\", not(windows_raw_dylib)))", + "kind": "normal" + }, + { + "name": "windows_i686_gnu", + "req": "^0.52.6", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"x86\", target_env = \"gnu\", not(target_abi = \"llvm\"), not(windows_raw_dylib)))", + "kind": "normal" + }, + { + "name": "windows_i686_gnullvm", + "req": "^0.52.6", + "features": [], + "optional": false, + "default_features": true, + "target": "i686-pc-windows-gnullvm", + "kind": "normal" + }, + { + "name": "windows_i686_msvc", + "req": "^0.52.6", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"x86\", target_env = \"msvc\", not(windows_raw_dylib)))", + "kind": "normal" + }, + { + "name": "windows_x86_64_gnu", + "req": "^0.52.6", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"x86_64\", target_env = \"gnu\", not(target_abi = \"llvm\"), not(windows_raw_dylib)))", + "kind": "normal" + }, + { + "name": "windows_x86_64_gnullvm", + "req": "^0.52.6", + "features": [], + "optional": false, + "default_features": true, + "target": "x86_64-pc-windows-gnullvm", + "kind": "normal" + }, + { + "name": "windows_x86_64_msvc", + "req": "^0.52.6", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(any(target_arch = \"x86_64\", target_arch = \"arm64ec\"), target_env = \"msvc\", not(windows_raw_dylib)))", + "kind": "normal" + } + ], + "cksum": "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973", + "features": {}, + "yanked": false, + "rust_version": "1.56", + "pubtime": "2024-07-03T19:44:18Z" + }, + { + "name": "windows-targets", + "vers": "0.53.5", + "deps": [ + { + "name": "windows-link", + "req": "^0.2.1", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(windows_raw_dylib)", + "kind": "normal" + }, + { + "name": "windows_aarch64_gnullvm", + "req": "^0.53.0", + "features": [], + "optional": false, + "default_features": true, + "target": "aarch64-pc-windows-gnullvm", + "kind": "normal" + }, + { + "name": "windows_aarch64_msvc", + "req": "^0.53.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"aarch64\", target_env = \"msvc\", not(windows_raw_dylib)))", + "kind": "normal" + }, + { + "name": "windows_i686_gnu", + "req": "^0.53.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"x86\", target_env = \"gnu\", not(target_abi = \"llvm\"), not(windows_raw_dylib)))", + "kind": "normal" + }, + { + "name": "windows_i686_gnullvm", + "req": "^0.53.0", + "features": [], + "optional": false, + "default_features": true, + "target": "i686-pc-windows-gnullvm", + "kind": "normal" + }, + { + "name": "windows_i686_msvc", + "req": "^0.53.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"x86\", target_env = \"msvc\", not(windows_raw_dylib)))", + "kind": "normal" + }, + { + "name": "windows_x86_64_gnu", + "req": "^0.53.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(target_arch = \"x86_64\", target_env = \"gnu\", not(target_abi = \"llvm\"), not(windows_raw_dylib)))", + "kind": "normal" + }, + { + "name": "windows_x86_64_gnullvm", + "req": "^0.53.0", + "features": [], + "optional": false, + "default_features": true, + "target": "x86_64-pc-windows-gnullvm", + "kind": "normal" + }, + { + "name": "windows_x86_64_msvc", + "req": "^0.53.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(all(any(target_arch = \"x86_64\", target_arch = \"arm64ec\"), target_env = \"msvc\", not(windows_raw_dylib)))", + "kind": "normal" + } + ], + "cksum": "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3", + "features": {}, + "yanked": false, + "rust_version": "1.60", + "pubtime": "2025-10-06T19:18:45Z" + } + ] + }, + { + "path": "wi/nn/winnow", + "header": "AwIAAABldGFnOiAiM2JlZmY0ZTJiOWI1OGQwNjUyYmFhMGY3ZGVlY2VmYTUiAA==", + "records": [ + { + "name": "winnow", + "vers": "1.0.4", + "deps": [ + { + "name": "annotate-snippets", + "req": "^0.11.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "anstream", + "req": "^0.6.15", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anstyle", + "req": "^1.0.8", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "anyhow", + "req": "^1.0.100", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "automod", + "req": "^1.0.15", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "circular", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.5.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "is_terminal_polyfill", + "req": "^1.48.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "lexopt", + "req": "^0.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "memchr", + "req": "^2.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "proptest", + "req": "^1.6.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustc-hash", + "req": "^2.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "snapbox", + "req": "^0.6.21", + "features": ["examples"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "term-transcript", + "req": "^0.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "terminal_size", + "req": "^0.4.3", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81", + "features": { + "alloc": [], + "ascii": ["parser"], + "binary": ["parser"], + "parser": [], + "unstable-recover": ["parser"] + }, + "features2": { + "debug": [ + "std", + "dep:anstream", + "dep:anstyle", + "dep:is_terminal_polyfill", + "dep:terminal_size" + ], + "default": ["std", "ascii", "binary"], + "simd": ["dep:memchr"], + "std": ["alloc", "memchr?/std"], + "unstable-doc": ["alloc", "std", "ascii", "binary", "simd", "unstable-recover"] + }, + "yanked": false, + "rust_version": "1.65.0", + "pubtime": "2026-07-13T14:31:41Z", + "v": 2 + } + ] + }, + { + "path": "wi/nx/winx", + "header": "AwIAAABldGFnOiAiOGI4ZGVkN2Y1Y2E2OWU0NzU0Y2MxOGY1N2JiZWU1ZTMiAA==", + "records": [ + { + "name": "winx", + "vers": "0.36.4", + "deps": [ + { + "name": "bitflags", + "req": "^2.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "windows-sys", + "req": ">=0.52, <=0.59", + "features": [ + "Win32_Foundation", + "Win32_Storage_FileSystem", + "Win32_System_IO", + "Win32_System_Ioctl", + "Win32_System_LibraryLoader", + "Win32_System_Performance", + "Win32_System_SystemServices" + ], + "optional": false, + "default_features": true, + "target": "cfg(windows)", + "kind": "normal" + } + ], + "cksum": "3f3fd376f71958b862e7afb20cfe5a22830e1963462f3a17f49d82a6c1d1f42d", + "features": {}, + "yanked": false, + "rust_version": "1.63", + "pubtime": "2024-12-04T02:14:41Z" + } + ] + }, + { + "path": "wi/t-/wit-bindgen", + "header": "AwIAAABldGFnOiAiNGZiMDE4ZDEzZjBlMzY3N2Y1NGVmZDE3OTQ1OGQzNGEiAA==", + "records": [ + { + "name": "wit-bindgen", + "vers": "0.57.1", + "deps": [ + { + "name": "alloc", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-alloc" + }, + { + "name": "bitflags", + "req": "^2.11.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "core", + "req": "^1.0", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal", + "package": "rustc-std-workspace-core" + }, + { + "name": "futures", + "req": "^0.3.30", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "wit-bindgen-rust-macro", + "req": "^0.57.1", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e", + "features": { + "async": [], + "inter-task-wakeup": ["async"], + "realloc": [], + "std": [] + }, + "features2": { + "async-spawn": ["async", "dep:futures", "std"], + "bitflags": ["dep:bitflags"], + "default": ["macros", "realloc", "async", "std", "bitflags", "macro-string"], + "futures-stream": ["async", "dep:futures"], + "macro-string": ["wit-bindgen-rust-macro?/macro-string"], + "macros": ["dep:wit-bindgen-rust-macro"], + "rustc-dep-of-std": ["dep:core", "dep:alloc"] + }, + "yanked": false, + "rust_version": "1.85.0", + "pubtime": "2026-04-17T17:49:55Z", + "v": 2 + } + ] + }, + { + "path": "wr/it/writeable", + "header": "AwIAAABldGFnOiAiMzZhODU0YmFkNmI4MDJhZWZmNzUxZjY3Njg3YjI1NmMiAA==", + "records": [ + { + "name": "writeable", + "vers": "0.6.4", + "deps": [ + { + "name": "criterion", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "either", + "req": "^1.9.0", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "rand", + "req": "^0.9", + "features": ["small_rng"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc", + "features": { + "alloc": [], + "default": ["alloc"] + }, + "features2": { + "either": ["dep:either"] + }, + "yanked": false, + "rust_version": "1.82", + "pubtime": "2026-08-13T23:28:09Z", + "v": 2 + } + ] + }, + { + "path": "xa/tt/xattr", + "header": "AwIAAABldGFnOiAiZDFiOTMzNmU1Y2U1YTA4ZWMyOWYzOThkMTVkZjFkNzkiAA==", + "records": [ + { + "name": "xattr", + "vers": "1.6.1", + "deps": [ + { + "name": "libc", + "req": "^0.2.150", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any(target_os = \"freebsd\", target_os = \"netbsd\"))", + "kind": "normal" + }, + { + "name": "rustix", + "req": "^1.0.0", + "features": ["fs", "std"], + "optional": false, + "default_features": false, + "target": "cfg(any(target_os = \"android\", target_os = \"linux\", target_os = \"macos\", target_os = \"hurd\"))", + "kind": "normal" + }, + { + "name": "tempfile", + "req": "^3", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156", + "features": { + "default": ["unsupported"], + "unsupported": [] + }, + "yanked": false, + "pubtime": "2025-09-21T02:52:23Z" + } + ] + }, + { + "path": "xx/ha/xxhash-rust", + "header": "AwIAAABldGFnOiAiM2Q5MjkwZDQ1OTBjNDcxZjJmZThiYzYxYzI4NGYyYmEiAA==", + "records": [ + { + "name": "xxhash-rust", + "vers": "0.8.19", + "deps": [ + { + "name": "getrandom", + "req": "^0.4", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "xxhash-c-sys", + "req": "^0.8.6", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "550a2b930b62486a393c52d5c3b84bff264b28aa437ed64694d31e93b1757af7", + "features": { + "const_xxh3": [], + "const_xxh32": [], + "const_xxh64": [], + "std": [], + "xxh3": [], + "xxh32": [], + "xxh64": [] + }, + "yanked": false, + "pubtime": "2026-09-28T13:16:18Z" + } + ] + }, + { + "path": "yo/ke/yoke", + "header": "AwIAAABldGFnOiAiMWI1MjJmOWVkMDdhYjcyMGEwM2ZmYmMyMjQ1MjdmZWYiAA==", + "records": [ + { + "name": "yoke", + "vers": "0.8.3", + "deps": [ + { + "name": "bincode", + "req": "^1.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "postcard", + "req": "^1.0.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "stable_deref_trait", + "req": "^1.2.0", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "yoke-derive", + "req": "^0.8.2", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerofrom", + "req": "^0.1.6", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5", + "features": { + "alloc": ["stable_deref_trait/alloc", "zerofrom/alloc"], + "serde": [] + }, + "features2": { + "default": ["alloc", "zerofrom"], + "derive": ["dep:yoke-derive", "zerofrom/derive"], + "zerofrom": ["dep:zerofrom"] + }, + "yanked": false, + "rust_version": "1.82", + "pubtime": "2026-06-03T20:59:17Z", + "v": 2 + } + ] + }, + { + "path": "yo/ke/yoke-derive", + "header": "AwIAAABldGFnOiAiZDQwNTUwY2UzOTQ5ODFmYjgwMjQzODMzYThmODE3ZDQiAA==", + "records": [ + { + "name": "yoke-derive", + "vers": "0.8.4", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.61", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.44", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3.0", + "features": ["fold", "visit"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "synstructure", + "req": "^0.14.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71", + "features": {}, + "yanked": false, + "rust_version": "1.82", + "pubtime": "2026-09-30T13:19:39Z" + } + ] + }, + { + "path": "ze/ro/zerocopy", + "header": "AwIAAABldGFnOiAiMjM4NDVjZTgxZWViMjM0NGFhNjQ5YzljOGMzNzQ0NmYiAA==", + "records": [ + { + "name": "zerocopy", + "vers": "0.8.62", + "deps": [ + { + "name": "elain", + "req": "^0.3.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "itertools", + "req": "^0.11", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.8.7", + "features": ["small_rng"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "regex", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rustversion", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "zerocopy-derive", + "req": "=0.8.62", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(any())", + "kind": "normal" + }, + { + "name": "zerocopy-derive", + "req": "=0.8.62", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "zerocopy-derive", + "req": "=0.8.62", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "86502bf56ac7c77571a32e2647bb2a15894565e981fb2a48d7bde2d91c965a9d", + "features": { + "__internal_use_only_features_that_work_on_stable": ["alloc", "derive", "simd", "std"], + "alloc": [], + "derive": ["zerocopy-derive"], + "float-nightly": [], + "simd": [], + "simd-nightly": ["simd"], + "std": ["alloc"] + }, + "yanked": false, + "rust_version": "1.56.0", + "pubtime": "2026-10-08T10:04:10Z" + } + ] + }, + { + "path": "ze/ro/zerocopy-derive", + "header": "AwIAAABldGFnOiAiZmQ5NmRkNjQ3NDFiMWFkZWMwZjY2YWE0NTBiNjU0MGIiAA==", + "records": [ + { + "name": "zerocopy-derive", + "vers": "0.8.62", + "deps": [ + { + "name": "dissimilar", + "req": "^1.0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "prettyplease", + "req": "^0.2.17", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1.0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.40", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "rustversion", + "req": "^1.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "static_assertions", + "req": "^1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn", + "req": "^2.0.46", + "features": ["full"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^2.0.46", + "features": ["visit"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "5457206954b06561e2608c7e19cf58b1926586d999c246eebe4502f7e2039d1a", + "features": {}, + "yanked": false, + "pubtime": "2026-10-08T10:03:02Z" + } + ] + }, + { + "path": "ze/ro/zerofrom", + "header": "AwIAAABldGFnOiAiZjRhYWY4MDhjMGE4MmRjNjFkYjEwOGQ2YzMzNTY4MmYiAA==", + "records": [ + { + "name": "zerofrom", + "vers": "0.1.8", + "deps": [ + { + "name": "zerofrom-derive", + "req": "^0.1.6", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272", + "features": { + "alloc": [], + "default": ["alloc"] + }, + "features2": { + "derive": ["dep:zerofrom-derive"] + }, + "yanked": false, + "rust_version": "1.71.1", + "pubtime": "2026-05-12T09:08:18Z", + "v": 2 + } + ] + }, + { + "path": "ze/ro/zerofrom-derive", + "header": "AwIAAABldGFnOiAiODU3NTIyYmI2NjhmNDNmMDUxNDVkNWYzNDhiMDdkOGQiAA==", + "records": [ + { + "name": "zerofrom-derive", + "vers": "0.1.8", + "deps": [ + { + "name": "proc-macro2", + "req": "^1.0.61", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.44", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "syn", + "req": "^3.0", + "features": ["fold", "visit"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "synstructure", + "req": "^0.14.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a", + "features": {}, + "yanked": false, + "rust_version": "1.71.1", + "pubtime": "2026-09-15T21:39:20Z" + } + ] + }, + { + "path": "ze/ro/zerotrie", + "header": "AwIAAABldGFnOiAiYjBkZmFjMzY2ZWQwNTViNDZiMzljZmRkZGRiNzc0OWYiAA==", + "records": [ + { + "name": "zerotrie", + "vers": "0.2.5", + "deps": [ + { + "name": "bincode", + "req": "^1.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "databake", + "req": "^0.2.0", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "displaydoc", + "req": "^0.2.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "icu_locale_core", + "req": "^2.3.0", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "itertools", + "req": "^0.14.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "litemap", + "req": "^0.8.0", + "features": ["alloc"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "postcard", + "req": "^1.0.3", + "features": ["alloc"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand_pcg", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rmp-serde", + "req": "^1.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde_core", + "req": "^1.0.220", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde_json", + "req": "^1.0.45", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "yoke", + "req": "^0.8.3", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerofrom", + "req": "^0.1.6", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerovec", + "req": "^0.11.7", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f", + "features": { + "default": [] + }, + "features2": { + "alloc": ["zerovec?/alloc"], + "databake": ["dep:databake", "zerovec?/databake"], + "dense": ["dep:zerovec"], + "litemap": ["dep:litemap", "alloc"], + "serde": ["dep:serde_core", "dep:litemap", "alloc", "litemap/serde", "zerovec?/serde"], + "yoke": ["dep:yoke"], + "zerofrom": ["dep:zerofrom"], + "zerovec": ["dep:zerovec"] + }, + "yanked": false, + "rust_version": "1.82", + "pubtime": "2026-08-13T23:28:19Z", + "v": 2 + } + ] + }, + { + "path": "ze/ro/zerovec", + "header": "AwIAAABldGFnOiAiMGNmZjFjY2M1MTZjOWFjOWFmMThiNmJkOWUyMjRlZmMiAA==", + "records": [ + { + "name": "zerovec", + "vers": "0.11.8", + "deps": [ + { + "name": "bincode", + "req": "^1.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "criterion", + "req": "^0.5.0", + "features": [], + "optional": false, + "default_features": true, + "target": "cfg(not(target_arch = \"wasm32\"))", + "kind": "dev" + }, + { + "name": "databake", + "req": "^0.2.0", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "getrandom", + "req": "^0.3", + "features": ["wasm_js"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "iai", + "req": "^0.1.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "insta", + "req": "^1.43.2", + "features": ["json"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "postcard", + "req": "^1.0.3", + "features": ["use-std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand_distr", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand_pcg", + "req": "^0.9", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rmp-serde", + "req": "^1.2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "schemars", + "req": "^1.0.4", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": ["derive"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0.45", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "twox-hash", + "req": "^2.0.0", + "features": ["xxhash64"], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "yoke", + "req": "^0.8.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "yoke", + "req": "^0.8.3", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "zerofrom", + "req": "^0.1.6", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "zerovec-derive", + "req": "^0.11.5", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8", + "features": { + "std": [] + }, + "features2": { + "alloc": ["serde?/alloc"], + "databake": ["dep:databake"], + "derive": ["dep:zerovec-derive"], + "hashmap": ["dep:twox-hash", "alloc"], + "schemars": ["dep:schemars", "alloc"], + "serde": ["dep:serde"], + "yoke": ["dep:yoke"] + }, + "yanked": false, + "rust_version": "1.83", + "pubtime": "2026-08-19T22:32:16Z", + "v": 2 + } + ] + }, + { + "path": "ze/ro/zerovec-derive", + "header": "AwIAAABldGFnOiAiNDJkZjljMGVjMWZjNjljNzhlMDY3ODllZWUwMzk0YWQiAA==", + "records": [ + { + "name": "zerovec-derive", + "vers": "0.11.6", + "deps": [ + { + "name": "bincode", + "req": "^1.3.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "proc-macro2", + "req": "^1.0.61", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "quote", + "req": "^1.0.44", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "serde", + "req": "^1.0.220", + "features": ["derive"], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + }, + { + "name": "serde_json", + "req": "^1.0.45", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "syn", + "req": "^3.0", + "features": ["extra-traits"], + "optional": false, + "default_features": true, + "target": null, + "kind": "normal" + } + ], + "cksum": "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da", + "features": {}, + "yanked": false, + "pubtime": "2026-08-20T23:25:28Z" + } + ] + }, + { + "path": "zl/ib/zlib-rs", + "header": "AwIAAABldGFnOiAiYTVmMWMxNDU5Nzk2ZGQxYWIzYTI5YWE0MGJmOWU4OTQiAA==", + "records": [ + { + "name": "zlib-rs", + "vers": "0.6.8", + "deps": [ + { + "name": "arbitrary", + "req": "^1.0", + "features": ["derive"], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "crc32fast", + "req": "^1.3.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "memoffset", + "req": "^0.9.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "quickcheck", + "req": "^1.0.3", + "features": [], + "optional": true, + "default_features": false, + "target": null, + "kind": "normal" + }, + { + "name": "quickcheck", + "req": "^1.0.3", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "dev" + } + ], + "cksum": "b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112", + "features": { + "ZLIB_DEBUG": [], + "__internal-api": [], + "__internal-fuzz": ["arbitrary"], + "__internal-fuzz-disable-checksum": [], + "__internal-test": ["quickcheck"], + "avx512": ["vpclmulqdq"], + "c-allocator": [], + "default": ["std", "c-allocator"], + "lsx": [], + "rust-allocator": [], + "std": ["rust-allocator"], + "vpclmulqdq": [] + }, + "yanked": false, + "rust_version": "1.75", + "pubtime": "2026-09-15T13:10:00Z" + } + ] + }, + { + "path": "zm/ij/zmij", + "header": "AwIAAABldGFnOiAiMGY1ODQ4NzI1ZWIwZmQyODY3OGY0YTdjNWM5M2M4MzMiAA==", + "records": [ + { + "name": "zmij", + "vers": "1.0.23", + "deps": [ + { + "name": "criterion", + "req": "^0.8", + "features": [], + "optional": false, + "default_features": false, + "target": "cfg(not(miri))", + "kind": "dev" + }, + { + "name": "no-panic", + "req": "^0.1.36", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "normal" + }, + { + "name": "num-bigint", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "num-integer", + "req": "^0.1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "num_cpus", + "req": "^1.8", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "opt-level", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "rand", + "req": "^0.10", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "ryu", + "req": "^1", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + } + ], + "cksum": "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b", + "features": {}, + "yanked": false, + "rust_version": "1.71", + "pubtime": "2026-07-13T12:58:53Z" + } + ] + }, + { + "path": "zs/td/zstd", + "header": "AwIAAABldGFnOiAiZWU4ZDc2NjU1YjRlMjQxNDAzZWMyN2FlNzMxMTVkMjgiAA==", + "records": [ + { + "name": "zstd", + "vers": "0.13.3", + "deps": [ + { + "name": "clap", + "req": "^4.0", + "features": ["derive"], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "humansize", + "req": "^2.0", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "partial-io", + "req": "^0.5", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "walkdir", + "req": "^2.2", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "dev" + }, + { + "name": "zstd-safe", + "req": "^7.1.0", + "features": ["std"], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a", + "features": { + "arrays": ["zstd-safe/arrays"], + "bindgen": ["zstd-safe/bindgen"], + "debug": ["zstd-safe/debug"], + "default": ["legacy", "arrays", "zdict_builder"], + "doc-cfg": [], + "experimental": ["zstd-safe/experimental"], + "fat-lto": ["zstd-safe/fat-lto"], + "legacy": ["zstd-safe/legacy"], + "no_asm": ["zstd-safe/no_asm"], + "pkg-config": ["zstd-safe/pkg-config"], + "thin": ["zstd-safe/thin"], + "thin-lto": ["zstd-safe/thin-lto"], + "wasm": [], + "zdict_builder": ["zstd-safe/zdict_builder"], + "zstdmt": ["zstd-safe/zstdmt"] + }, + "yanked": false, + "rust_version": "1.64", + "pubtime": "2025-02-20T21:43:13Z" + } + ] + }, + { + "path": "zs/td/zstd-safe", + "header": "AwIAAABldGFnOiAiMmFiZGFlNDdjZmI4ODIxYTkwZTg4NWNmZjk0OWZjMTMiAA==", + "records": [ + { + "name": "zstd-safe", + "vers": "7.3.0", + "deps": [ + { + "name": "zstd-sys", + "req": "^2.0.15", + "features": [], + "optional": false, + "default_features": false, + "target": null, + "kind": "normal" + } + ], + "cksum": "64d80649ab6db9d9f6f9c80a40becd948eda4714a0a5ac8c4d157a32231c7882", + "features": { + "arrays": [], + "bindgen": ["zstd-sys/bindgen"], + "debug": ["zstd-sys/debug"], + "default": ["legacy", "arrays", "zdict_builder"], + "doc-cfg": [], + "experimental": ["zstd-sys/experimental"], + "fat-lto": ["zstd-sys/fat-lto"], + "legacy": ["zstd-sys/legacy"], + "no_asm": ["zstd-sys/no_asm"], + "pkg-config": ["zstd-sys/pkg-config"], + "seekable": ["zstd-sys/seekable"], + "std": ["zstd-sys/std"], + "thin": ["zstd-sys/thin"], + "thin-lto": ["zstd-sys/thin-lto"], + "zdict_builder": ["zstd-sys/zdict_builder"], + "zstdmt": ["zstd-sys/zstdmt"] + }, + "yanked": false, + "rust_version": "1.64", + "pubtime": "2026-09-04T14:31:21Z" + } + ] + }, + { + "path": "zs/td/zstd-sys", + "header": "AwIAAABldGFnOiAiMTg5MDU1YTAwMGI5YjQ3YzRiYjEwMjEwYTk3NWIyMDUiAA==", + "records": [ + { + "name": "zstd-sys", + "vers": "2.1.1+zstd.1.5.7", + "deps": [ + { + "name": "bindgen", + "req": "^0.73.2", + "features": ["runtime"], + "optional": true, + "default_features": false, + "target": null, + "kind": "build" + }, + { + "name": "cc", + "req": "^1.0.45", + "features": ["parallel"], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "cmake", + "req": "^0.1", + "features": [], + "optional": true, + "default_features": true, + "target": null, + "kind": "build" + }, + { + "name": "pkg-config", + "req": "^0.3.28", + "features": [], + "optional": false, + "default_features": true, + "target": null, + "kind": "build" + } + ], + "cksum": "aeec9eaf2dffbbd09201e23bd0ffcbaa33bb8e9266a10734fd7ed90a85eca078", + "features": { + "debug": [], + "default": ["legacy", "zdict_builder"], + "experimental": [], + "fat-lto": [], + "legacy": [], + "no_asm": [], + "no_wasm_shim": [], + "non-cargo": [], + "pkg-config": [], + "seekable": [], + "std": [], + "thin": [], + "thin-lto": [], + "vendored": [], + "zdict_builder": [], + "zstdmt": [] + }, + "features2": { + "cmake": ["dep:cmake"] + }, + "yanked": false, + "links": "zstd", + "rust_version": "1.64", + "pubtime": "2026-10-09T14:57:47Z", + "v": 2 + } + ] + } + ] +} diff --git a/build_defs/languages/isolated-cache-test.mts b/build_defs/languages/isolated-cache-test.mts new file mode 100644 index 000000000..20a895e9f --- /dev/null +++ b/build_defs/languages/isolated-cache-test.mts @@ -0,0 +1,15 @@ +import assert from 'node:assert/strict'; +import path from 'node:path'; + +const [binary, ...args] = process.argv.slice(2); +assert(binary && process.env.TEST_TMPDIR, 'isolated Rust test needs its binary and test directory'); +const result = Bun.spawnSync([binary, ...args], { + env: { + ...process.env, + OLIPHAUNT_RUNTIME_CACHE_DIR: path.join(process.env.TEST_TMPDIR, 'native-cache'), + }, + stdin: 'inherit', + stdout: 'inherit', + stderr: 'inherit', +}); +process.exit(result.exitCode); diff --git a/build_defs/languages/jvm/BUILD.bazel b/build_defs/languages/jvm/BUILD.bazel new file mode 100644 index 000000000..9351e6bf7 --- /dev/null +++ b/build_defs/languages/jvm/BUILD.bazel @@ -0,0 +1,104 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/foundation:bun.bzl", "bun_binary", "bun_test") +load("//build_defs/native/carriers:defs.bzl", "native_carrier_helpers") +load(":kotlin.bzl", "kotlin_sdk_toolchain") +load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") +load("@rules_kotlin//kotlin:android.bzl", "kt_android_library") +load(":android-lint.bzl", "kotlin_android_lint_test") + +package(default_visibility = ["//visibility:public"]) + +exports_files(glob(["*.bzl", "*.mts"])) + +exports_files(["aar-import-android-bootclasspath.patch"]) +exports_files(["lint_maven_install.json"]) + +kotlin_sdk_toolchain(name = "sdk_toolchain") + +kt_jvm_library( + name = "lint_model", + testonly = True, + srcs = ["LintModel.kt"], + deps = [ + "@oliphaunt_android_lint_maven//:com_android_tools_lint_lint_model", + "@oliphaunt_android_lint_maven//:com_android_tools_sdk_common", + "@oliphaunt_android_lint_maven//:com_android_tools_sdklib", + "@oliphaunt_android_lint_maven//:com_android_tools_common", + "@oliphaunt_android_lint_maven//:com_google_code_gson_gson", + ], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) + +# This independent compiled fixture must produce a real API-level source error. +# It detects a model which ignores its sources or loses Android/Gradle identity. +kt_android_library( + name = "lint_api_canary_classes", + testonly = True, + srcs = ["testdata/lint/NewApi.kt"], + manifest = "testdata/lint/AndroidManifest.xml", + custom_package = "dev.oliphaunt", + deps = ["@oliphaunt_kotlin_maven//:org_jetbrains_kotlin_kotlin_stdlib"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) + +kotlin_android_lint_test( + name = "android_lint_api_canary_test", + library = ":lint_api_canary_classes", + srcs = ["testdata/lint/NewApi.kt"], + manifest = "testdata/lint/AndroidManifest.xml", + min_sdk = 24, + expect_issue = "NewApi", + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + size = "small", +) + +bun_test(name = "android_lint_runner_test", entry_point = "android-lint.test.mts", data = ["android-lint.mts"], size = "small") + +bun_binary(name = "plugin_descriptor", entry_point = "plugin-descriptor.mts") + +bun_test(name = "ktlint_runner_test", entry_point = "ktlint.test.mts", data = ["ktlint.mts"], size = "small") + +bun_test(name = "android_sdk_metadata_test", entry_point = "android-sdk-metadata.test.mts", data = ["android-sdk-metadata.mts", "//tools/dev:android-sdk.toml"], size = "small") + +bun_test( + name = "kotlin_sdk_metadata_test", + entry_point = "kotlin-sdk-metadata.test.mts", + data = [ + "kotlin-sdk-metadata.mts", "maven-pom.mts", + "//:tools/packaging/maven-central-contract.mts", "//tools/dev:android-sdk.toml", + "//src/native/sdks/kotlin:VERSION", "//src/native/sdks/kotlin:gradle.properties", + "//src/native/sdks/kotlin:oliphaunt/build.gradle.kts", "//src/native/sdks/kotlin:gradle/libs.versions.toml", + "//src/native/sdks/kotlin/oliphaunt-android-gradle-plugin:build.gradle.kts", + ], + size = "small", +) + +bun_test( + name = "maven_package_test", + entry_point = "maven-package.test.mts", + data = [ + "maven-package.mts", "maven-pom.mts", "kotlin-sdk-metadata.mts", "//build_defs/languages:mobile-legal.mts", + "//src/native/sdks/kotlin:VERSION", "//src/native/sdks/kotlin:gradle.properties", "//src/native/sdks/kotlin:gradle/libs.versions.toml", + "//src/native/sdks/kotlin:oliphaunt/build.gradle.kts", "//src/native/sdks/kotlin:tools/kotlin-maven-staging.mts", + "//src/native/sdks/kotlin/oliphaunt-android-gradle-plugin:build.gradle.kts", + "//tools/dev:android-sdk.toml", "//:Cargo.lock", "//:LICENSE", "//:THIRD_PARTY_NOTICES.md", "//src/native/mobile-bindings:license_inputs", + "//:tools/packaging/archive-directory.mts", "//:tools/packaging/portable-archive.mts", "//:tools/packaging/testdata/release-fixture-utils.mts", "//:tools/packaging/testdata/zip-fixture.mts", + "//:tools/packaging/maven-central-contract.mts", "//:tools/packaging/platform-binary-contract.mts", "//:tools/packaging/windows-vc-runtime-closure.mts", + "//:tools/packaging/windows-vc-runtime-policy.json", + "//:tools/packaging/release-notices.mts", "//:tools/packaging/release-directory-safety.mts", "//:tools/packaging/rust-dependency-license-contract.mts", "//tools/release:platform-compatibility-policy.mts", + ], + size = "small", +) + +bun_test( + name = "installed_maven_contract_test", + entry_point = "installed-maven-contract.test.mts", + data = [ + "installed-maven.test.mts", "//src/native/sdks/kotlin:tools/check-package.mts", "//src/native/sdks/kotlin:tools/kotlin-maven-staging.mts", + "//build_defs/languages:mobile-legal.mts", + "//:tools/packaging/testdata/zip-fixture.mts", "//:tools/packaging/maven-central-contract.mts", + ] + native_carrier_helpers(), + size = "small", +) + +source_quality_files() diff --git a/build_defs/languages/jvm/LintModel.kt b/build_defs/languages/jvm/LintModel.kt new file mode 100644 index 000000000..91ba6684a --- /dev/null +++ b/build_defs/languages/jvm/LintModel.kt @@ -0,0 +1,148 @@ +package dev.oliphaunt.build + +import com.android.ide.common.repository.AgpVersion +import com.android.sdklib.AndroidVersion +import com.android.tools.lint.model.* +import com.google.gson.Gson +import java.io.File + +/** Adapt actual Bazel library facts through the pinned official serializer. */ +object LintModel { + data class Library( + val coordinate: String, + val jars: List, + val dependencies: List, + ) + + data class Configuration( + val root: String, + val destination: String, + val agpVersion: String, + val namespace: String, + val jvmTarget: String, + val compileSdk: Int, + val minSdk: Int, + val targetSdk: Int, + val bootClasspath: List, + val classes: List, + val manifest: String, + val mergedManifest: String, + val sources: List, + val generatedSources: List, + val consumerProguard: List, + val libraries: List, + val dependencies: List, + ) + + @JvmStatic + fun main(arguments: Array) { + require(arguments.size == 1) { "Lint model requires its declared native facts" } + val config = Gson().fromJson(File(arguments[0]).readText(), Configuration::class.java) + require(config.classes.isNotEmpty() && config.sources.isNotEmpty()) + val libraries = config.libraries.associate { library -> + library.coordinate to DefaultLintModelJavaLibrary( + identifier = library.coordinate, + jarFiles = library.jars.map(::File), + resolvedCoordinates = requireNotNull(LintModelMavenName.parse(library.coordinate)), + provided = false, + ) + } + require(libraries.size == config.libraries.size) { "Duplicate native Maven coordinates" } + val resolver = DefaultLintModelLibraryResolver(libraries) + val descriptors = config.libraries.associateBy { it.coordinate } + val memo = mutableMapOf() + val visiting = mutableSetOf() + fun dependency(coordinate: String): LintModelDependency { + memo[coordinate]?.let { return it } + require(visiting.add(coordinate)) { "Native Maven dependency cycle at $coordinate" } + val library = requireNotNull(descriptors[coordinate]) { "Missing native Maven library $coordinate" } + val artifact = requireNotNull(LintModelMavenName.parse(coordinate)) + val result = DefaultLintModelDependency( + identifier = coordinate, + artifactName = "${artifact.groupId}:${artifact.artifactId}", + requestedCoordinates = coordinate, + dependencies = library.dependencies.map(::dependency), + libraryResolver = resolver, + ) + visiting.remove(coordinate) + return result.also { memo[coordinate] = it } + } + val graph = DefaultLintModelDependencyGraph(config.dependencies.map(::dependency), resolver) + val dependencies = DefaultLintModelDependencies(graph, graph, resolver) + val variants = mutableListOf() + val root = File(config.root) + val module = DefaultLintModelModule( + loader = LintModelSerialization, + dir = root, + modulePath = ":oliphaunt", + type = LintModelModuleType.LIBRARY, + mavenName = null, + agpVersion = requireNotNull(AgpVersion.tryParse(config.agpVersion)), + buildFolder = root.resolve("build"), + lintOptions = DefaultLintModelLintOptions(), + lintRuleJars = emptyList(), + resourcePrefix = null, + dynamicFeatures = emptyList(), + bootClassPath = config.bootClasspath.map(::File), + javaSourceLevel = config.jvmTarget, + compileTarget = "android-${config.compileSdk}", + variants = variants, + neverShrinking = true, + ) + variants.add( + DefaultLintModelVariant( + module = module, + name = "debug", + useSupportLibraryVectorDrawables = false, + mainArtifactOrNull = DefaultLintModelAndroidArtifact( + applicationId = config.namespace, + generatedResourceFolders = emptyList(), + generatedSourceFolders = config.generatedSources.map(::File), + desugaredMethodsFiles = emptyList(), + dependencies = dependencies, + classOutputs = config.classes.map(::File), + type = LintModelArtifactType.MAIN, + ), + testArtifact = null, + androidTestArtifact = null, + testFixturesArtifact = null, + mergedManifest = File(config.mergedManifest), + manifestMergeReport = null, + `package` = config.namespace, + minSdkVersion = AndroidVersion(config.minSdk), + targetSdkVersion = AndroidVersion(config.targetSdk), + resValues = emptyMap(), + manifestPlaceholders = emptyMap(), + resourceConfigurations = emptyList(), + proguardFiles = emptyList(), + consumerProguardFiles = config.consumerProguard.map(::File), + sourceProviders = listOf( + DefaultLintModelSourceProvider( + manifestFiles = listOf(File(config.manifest)), + javaDirectories = config.sources.map(::File), + resDirectories = emptyList(), + assetsDirectories = emptyList(), + debugOnly = false, + unitTestOnly = false, + instrumentationTestOnly = false, + testFixture = false, + ), + ), + testSourceProviders = emptyList(), + testFixturesSourceProviders = emptyList(), + debuggable = true, + shrinkable = false, + buildFeatures = DefaultLintModelBuildFeatures( + viewBinding = false, + coreLibraryDesugaringEnabled = false, + namespacingMode = LintModelNamespacingMode.DISABLED, + ), + libraryResolver = resolver, + partialResultsDir = null, + desugaredMethodsFiles = emptyList(), + ), + ) + File(config.destination).mkdirs() + LintModelSerialization.writeModule(module, File(config.destination)) + } +} diff --git a/build_defs/languages/jvm/aar-import-android-bootclasspath.patch b/build_defs/languages/jvm/aar-import-android-bootclasspath.patch new file mode 100644 index 000000000..d2628699d --- /dev/null +++ b/build_defs/languages/jvm/aar-import-android-bootclasspath.patch @@ -0,0 +1,12 @@ +--- a/rules/aar_import/impl.bzl ++++ b/rules/aar_import/impl.bzl +@@ -326,8 +326,8 @@ + + if enable_desugar_java8: + bootclasspath = depset(transitive = [ +- desugar_java8_extra_bootclasspath, + bootclasspath, ++ desugar_java8_extra_bootclasspath, + ]) + + merged_java_info = java_common.merge(java_infos + r_java_info) diff --git a/build_defs/languages/jvm/android-lint.bzl b/build_defs/languages/jvm/android-lint.bzl new file mode 100644 index 000000000..49917cd12 --- /dev/null +++ b/build_defs/languages/jvm/android-lint.bzl @@ -0,0 +1,111 @@ +"""Android debug Lint over the actual native library and pinned official model.""" + +load("@oliphaunt_kotlin_manifest//:metadata.bzl", "KOTLIN", "KOTLIN_QUALITY") +load("@rules_android//providers:providers.bzl", "AndroidIdeInfo") +load("@rules_java//java/common:java_info.bzl", "JavaInfo") +load("@rules_jvm_external//:providers.bzl", "MavenInfo") +load("@rules_jvm_external//private/rules:has_maven_deps.bzl", "calculate_artifact_jars", "has_maven_deps") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") + +_JAVA_RUNTIME = "@bazel_tools//tools/jdk:runtime_toolchain_type" + +def _android_lint_test_impl(ctx): + runtime = ctx.toolchains[_JAVA_RUNTIME].java_runtime + java = [file for file in runtime.files.to_list() if file.path == runtime.java_executable_exec_path] + if len(java) != 1: + fail("Android Lint requires the declared Java runtime executable") + metadata = { + "agpVersion": KOTLIN_QUALITY["lint"]["agpVersion"], + "namespace": KOTLIN["namespace"], + "jvmTarget": KOTLIN["jvmTarget"], + "languageVersion": KOTLIN["languageVersion"], + "compileSdk": KOTLIN["compileSdk"], + "minSdk": ctx.attr.min_sdk if ctx.attr.min_sdk else KOTLIN["minSdk"], + "expectIssue": ctx.attr.expect_issue, + } + arguments = [java[0], json.encode(metadata)] + # The Kotlin compiler's implicit runtime must not contaminate Lint's + # isolated upstream Kotlin/UAST dependencies. Only helper classes join it. + tools = ctx.attr._model[JavaInfo].runtime_output_jars + ctx.attr._lint[JavaInfo].transitive_runtime_jars.to_list() + for jar in tools: + arguments += ["tool", jar] + classes = depset(transitive = [depset(target[JavaInfo].runtime_output_jars) for target in [ctx.attr.library] + ctx.attr.additional_classes]).to_list() + if not classes: + fail("Android Lint requires the actual native compiled library") + for jar in classes: + arguments += ["class", jar] + info = ctx.attr.library[MavenInfo] + libraries = {} + jars = [] + for dependency in info.all_infos.to_list(): + if dependency.coordinates == None: + continue + if dependency.coordinates == "STOPPED": + fail("Android Lint cannot omit a declared Maven dependency") + physical = calculate_artifact_jars(dependency) + record = struct(jars = physical, dependencies = dependency.maven_deps.to_list()) + previous = libraries.get(dependency.coordinates) + if previous != None and previous != record: + fail("Android Lint has conflicting actual Maven facts for " + dependency.coordinates) + libraries[dependency.coordinates] = record + for coordinate in sorted(libraries): + record = libraries[coordinate] + if not record.jars: + fail("Android Lint Maven dependency has no declared runtime JAR: " + coordinate) + arguments += ["library", coordinate, json.encode(record.dependencies), str(len(record.jars))] + record.jars + jars.extend(record.jars) + for coordinate in info.maven_deps.to_list(): + arguments += ["dependency", coordinate] + merged_manifest = ctx.attr.library[AndroidIdeInfo].generated_manifest or ctx.file.manifest + arguments += ["manifest", ctx.file.manifest, "merged-manifest", merged_manifest] + for file in ctx.files.proguard: + arguments += ["proguard", file] + files = [] + for kind, declared in [("source", ctx.files.srcs), ("generated", ctx.files.generated_srcs), ("conventional", ctx.files.conventional_files)]: + for file in declared: + if kind == "generated": + member = file.short_path.replace("../", "external/") + elif file.short_path.startswith(ctx.label.package + "/"): + member = file.short_path[len(ctx.label.package) + 1:] + else: + fail("Android Lint authored sources must belong to their declared owner") + arguments += [kind, member, file] + files.append(file) + for file in ctx.files._sdk: + arguments += ["sdk", file.short_path.split("/", 2)[2], file] + files.append(file) + inputs = files + classes + jars + tools + runtime.files.to_list() + [ctx.file.manifest, merged_manifest] + ctx.files.proguard + # A complete SDK platform exceeds operating-system argv limits. Keep the + # same declared facts in a response file instead of expanding them in argv. + specification = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(specification, json.encode([ + {"file": argument.short_path[3:] if argument.short_path.startswith("../") else ctx.workspace_name + "/" + argument.short_path} + if type(argument) == "File" else {"literal": argument} + for argument in arguments + ]) + "\n") + return bun_test_entrypoint(ctx, ctx.file._runner, [specification], inputs + [specification], + runfiles_argument = True, source_files = [ctx.file._runner]) + +_android_lint_test = rule( + implementation = _android_lint_test_impl, + test = True, + toolchains = BUN_SOURCE_TOOLCHAINS + [_JAVA_RUNTIME], + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "library": attr.label(mandatory = True, providers = [JavaInfo, AndroidIdeInfo], aspects = [has_maven_deps]), + "additional_classes": attr.label_list(providers = [JavaInfo]), + "srcs": attr.label_list(allow_files = [".kt", ".java", ".aidl"], mandatory = True), + "generated_srcs": attr.label_list(allow_files = [".kt", ".java"]), + "conventional_files": attr.label_list(allow_files = True), + "manifest": attr.label(mandatory = True, allow_single_file = [".xml"]), + "proguard": attr.label_list(allow_files = True), + "min_sdk": attr.int(), + "expect_issue": attr.string(), + "_sdk": attr.label(default = "@oliphaunt_android_sdk_archive//:lint_inputs"), + "_lint": attr.label(default = "@oliphaunt_android_lint_maven//:com_android_tools_lint_lint_gradle", providers = [JavaInfo]), + "_model": attr.label(default = "//build_defs/languages/jvm:lint_model", providers = [JavaInfo], cfg = "exec"), + "_runner": attr.label(default = "//build_defs/languages/jvm:android-lint.mts", allow_single_file = True), + }), +) + +def kotlin_android_lint_test(name, **kwargs): + _android_lint_test(name = name, args = bun_test_entrypoint_args(name), **kwargs) diff --git a/build_defs/languages/jvm/android-lint.mts b/build_defs/languages/jvm/android-lint.mts new file mode 100644 index 000000000..914f6fd3a --- /dev/null +++ b/build_defs/languages/jvm/android-lint.mts @@ -0,0 +1,262 @@ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { copyFileSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; + +type Source = { + kind: 'source' | 'generated' | 'conventional' | 'sdk'; + member: string; + file: string; +}; +type Library = { coordinate: string; jars: string[]; dependencies: string[] }; +type Metadata = { + agpVersion: string; + namespace: string; + jvmTarget: string; + languageVersion: string; + compileSdk: number; + minSdk: number; + expectIssue: string; +}; + +/** Resolve response-file facts only within their declared runfiles root. */ +export function declaredAndroidLintArguments(specification: string, runfiles: string): string[] { + assert(path.isAbsolute(runfiles), 'Android Lint requires an absolute declared runfiles root'); + const arguments_ = JSON.parse(specification); + assert(Array.isArray(arguments_), 'Android Lint requires declared argument records'); + return arguments_.map((argument) => { + assert(argument && typeof argument === 'object' && Object.keys(argument).length === 1); + if (Object.hasOwn(argument, 'literal')) { + assert.equal(typeof argument.literal, 'string'); + return argument.literal; + } + const file = argument.file; + assert( + typeof file === 'string' && + file && + !path.posix.isAbsolute(file) && + !/^[A-Za-z]:/u.test(file) && + !/[\\\u0000-\u001f]/u.test(file) && + file.split('/').every((part) => part && part !== '.' && part !== '..'), + 'Android Lint requires a safe declared runfile', + ); + return path.join(runfiles, file); + }); +} + +/** Stage exactly declared files so Lint cannot discover an ambient SDK or project. */ +export function stageAndroidLintSources(root: string, sources: Source[]) { + const seen = new Set(); + const authored: string[] = []; + const generated: string[] = []; + for (const { kind, member, file } of sources) { + assert( + member && + !/^[A-Za-z]:/u.test(member) && + !/[\\\u0000-\u001f]/u.test(member) && + !path.posix.isAbsolute(member) && + member.split('/').every((part) => part && part !== '.' && part !== '..'), + 'Android Lint requires safe explicit file members', + ); + const directory = + kind === 'sdk' + ? 'sdk' + : kind === 'conventional' + ? 'project' + : `project/oliphaunt/${kind === 'generated' ? 'generated' : 'authored'}`; + const relative = `${directory}/${member}`; + assert(!seen.has(relative), `Duplicate Android Lint file ${relative}`); + seen.add(relative); + const destination = path.join(root, relative); + mkdirSync(path.dirname(destination), { recursive: true }); + copyFileSync(file, destination); + if (kind === 'source') authored.push(destination); + if (kind === 'generated') generated.push(destination); + } + assert(authored.length, 'Android Lint requires actual authored production sources'); + assert( + sources.some(({ kind, member }) => kind === 'sdk' && member.endsWith('/android.jar')), + 'Android Lint requires the declared compiler SDK platform', + ); + return { authored, generated }; +} + +if (import.meta.main) { + const [specification, runfiles] = process.argv.slice(2); + assert(specification && runfiles && process.argv.length === 4); + const [java, metadataText, ...arguments_] = declaredAndroidLintArguments( + readFileSync(specification, 'utf8'), + runfiles, + ); + assert(java && metadataText, 'Android Lint requires declared Java and conventional metadata'); + const metadata: Metadata = JSON.parse(metadataText); + const tools: string[] = []; + const classes: string[] = []; + const proguard: string[] = []; + const sources: Source[] = []; + const libraries: Library[] = []; + const dependencies: string[] = []; + let manifest: string | undefined; + let mergedManifest: string | undefined; + for (let index = 0; index < arguments_.length; ) { + const kind = arguments_[index++]; + if ( + kind === 'tool' || + kind === 'class' || + kind === 'proguard' || + kind === 'dependency' || + kind === 'manifest' || + kind === 'merged-manifest' + ) { + const file = arguments_[index++]; + assert(file, `Incomplete Android Lint ${kind} declaration`); + if (kind === 'tool') tools.push(file); + if (kind === 'class') classes.push(file); + if (kind === 'proguard') proguard.push(file); + if (kind === 'dependency') dependencies.push(file); + if (kind === 'manifest') { + assert(!manifest, 'Android Lint requires exactly one native manifest'); + manifest = file; + } + if (kind === 'merged-manifest') { + assert(!mergedManifest, 'Android Lint requires exactly one native merged manifest'); + mergedManifest = file; + } + } else if (kind === 'library') { + const [coordinate, dependencyText, countText] = arguments_.slice(index, index + 3); + const count = Number(countText); + assert(coordinate && dependencyText && Number.isSafeInteger(count) && count > 0); + index += 3; + const jars = arguments_.slice(index, index + count); + assert.equal(jars.length, count); + index += count; + libraries.push({ coordinate, dependencies: JSON.parse(dependencyText), jars }); + } else { + assert( + ['source', 'generated', 'conventional', 'sdk'].includes(kind), + 'Unknown Android Lint input', + ); + const [member, file] = arguments_.slice(index, index + 2); + assert(member && file, 'Incomplete Android Lint source declaration'); + index += 2; + sources.push({ kind: kind as Source['kind'], member, file }); + } + } + assert( + tools.length && classes.length && manifest && mergedManifest, + 'Android Lint requires actual CLI, compiled classes and native manifests', + ); + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-android-lint-')); + try { + stageAndroidLintSources(root, sources); + const moduleRoot = path.join(root, 'project', 'oliphaunt'); + const nativeManifest = path.join(moduleRoot, 'AndroidManifest.xml'); + copyFileSync(manifest, nativeManifest); + const compiledManifest = path.join(moduleRoot, 'AndroidManifest.merged.xml'); + copyFileSync(mergedManifest, compiledManifest); + const destination = path.join(root, 'model'); + const sdk = path.join(root, 'sdk'); + const spec = path.join(root, 'model.json'); + writeFileSync( + spec, + JSON.stringify({ + root: moduleRoot, + destination, + agpVersion: metadata.agpVersion, + namespace: metadata.namespace, + jvmTarget: metadata.jvmTarget, + compileSdk: metadata.compileSdk, + minSdk: metadata.minSdk, + targetSdk: metadata.compileSdk, + bootClasspath: [ + path.join(sdk, 'platforms', `android-${metadata.compileSdk}`, 'android.jar'), + ], + classes, + manifest: nativeManifest, + mergedManifest: compiledManifest, + sources: [path.join(moduleRoot, 'authored')], + generatedSources: sources.some(({ kind }) => kind === 'generated') + ? [path.join(moduleRoot, 'generated')] + : [], + consumerProguard: proguard, + libraries, + dependencies, + }), + ); + const environment = { ...process.env }; + for (const key of [ + 'ANDROID_HOME', + 'ANDROID_SDK_ROOT', + 'LINT_JARS', + 'JAVA_TOOL_OPTIONS', + '_JAVA_OPTIONS', + 'JDK_JAVA_OPTIONS', + ]) + delete environment[key]; + const prefix = [ + '-Xmx768m', + '-XX:ActiveProcessorCount=2', + `-Duser.home=${root}`, + '-Dfile.encoding=UTF-8', + '-cp', + tools.join(path.delimiter), + ]; + const options = { + cwd: path.join(root, 'project'), + env: environment, + encoding: 'utf8' as const, + maxBuffer: 16 * 1024 * 1024, + }; + const model = spawnSync(java, [...prefix, 'dev.oliphaunt.build.LintModel', spec], options); + if (model.error) throw model.error; + assert.equal( + model.status, + 0, + `Official Android Lint model serialization failed:\n${model.stdout}${model.stderr}`, + ); + const result = spawnSync( + java, + [ + ...prefix, + 'com.android.tools.lint.Main', + '--lint-model', + destination, + '--variant', + 'debug', + '--sdk-home', + sdk, + '--jdk-home', + path.dirname(path.dirname(java)), + '--cache-dir', + path.join(root, 'cache'), + '--java-language-level', + metadata.jvmTarget, + '--kotlin-language-level', + metadata.languageVersion, + '--offline', + '--exitcode', + ], + options, + ); + if (result.error) throw result.error; + const output = `${result.stdout}${result.stderr}`; + process.stdout.write(output); + if (metadata.expectIssue) { + assert.equal( + result.status, + 1, + 'Android Lint API canary must fail with a genuine source error', + ); + assert( + output.includes(`[${metadata.expectIssue}]`), + `Android Lint missed its ${metadata.expectIssue} API canary`, + ); + assert(!output.includes('[LintError]'), 'Android Lint API canary has an analysis failure'); + } else { + assert.equal(result.status, 0, 'Conventional Android debug source analysis failed'); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +} diff --git a/build_defs/languages/jvm/android-lint.test.mts b/build_defs/languages/jvm/android-lint.test.mts new file mode 100644 index 000000000..52aca44af --- /dev/null +++ b/build_defs/languages/jvm/android-lint.test.mts @@ -0,0 +1,79 @@ +import { expect, test } from 'bun:test'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { declaredAndroidLintArguments, stageAndroidLintSources } from './android-lint.mts'; + +test('complete SDK response exceeds argv capacity without expanding the launch arguments', () => { + const root = path.join(os.tmpdir(), 'declared lint runfiles'); + const literal = JSON.stringify({ namespace: 'dev.oliphaunt', value: 'quoted " metadata' }); + const files = Array.from({ length: 12_000 }, (_, index) => ({ + file: `_main/sdk/platforms/android-36/data/res/${'declared-platform-member-'.repeat(7)}${index}.xml`, + })); + const response = JSON.stringify([{ literal }, ...files]); + expect(response.length).toBeGreaterThan(2 * 1024 * 1024); + const actual = declaredAndroidLintArguments(response, root); + expect(actual).toHaveLength(files.length + 1); + expect(actual[0]).toBe(literal); + expect(actual.at(-1)).toBe(path.join(root, files.at(-1).file)); +}); + +test('declared response paths and record kinds reject traversal and ambiguity', () => { + const root = path.join(os.tmpdir(), 'declared-lint-runfiles'); + for (const file of [ + '../outside.jar', + '/absolute.jar', + 'C:/absolute.jar', + '_main/../outside', + '_main/a\\b', + '_main//empty', + ]) { + expect(() => declaredAndroidLintArguments(JSON.stringify([{ file }]), root)).toThrow( + /safe declared/u, + ); + } + for (const record of [ + { file: '_main/a', literal: 'ambiguous' }, + {}, + { literal: 4 }, + { unknown: 'kind' }, + ]) { + expect(() => declaredAndroidLintArguments(JSON.stringify([record]), root)).toThrow(); + } + expect(() => declaredAndroidLintArguments('[]', 'relative')).toThrow(/absolute/u); +}); + +test('stages only declared authored, generated, Gradle and SDK inputs in isolated roots', () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-lint-staging-')); + try { + const input = path.join(root, 'input'); + writeFileSync(input, 'declared'); + const stage = path.join(root, 'stage'); + mkdirSync(stage); + const sources = [ + { kind: 'source' as const, member: 'src/Api.kt', file: input }, + { kind: 'generated' as const, member: 'bindings/Generated.kt', file: input }, + { kind: 'conventional' as const, member: 'oliphaunt/build.gradle.kts', file: input }, + { kind: 'sdk' as const, member: 'platforms/android-36/android.jar', file: input }, + ]; + const result = stageAndroidLintSources(stage, sources); + expect(result.authored).toEqual([path.join(stage, 'project/oliphaunt/authored/src/Api.kt')]); + expect(result.generated).toEqual([ + path.join(stage, 'project/oliphaunt/generated/bindings/Generated.kt'), + ]); + expect(readFileSync(path.join(stage, 'project/oliphaunt/build.gradle.kts'), 'utf8')).toBe( + 'declared', + ); + expect(readFileSync(path.join(stage, 'sdk/platforms/android-36/android.jar'), 'utf8')).toBe( + 'declared', + ); + expect(() => stageAndroidLintSources(stage, [...sources, sources[0]])).toThrow(/Duplicate/u); + expect(() => + stageAndroidLintSources(stage, [{ ...sources[0], member: '../escape.kt' }]), + ).toThrow(/safe explicit/u); + expect(() => stageAndroidLintSources(stage, [sources[3]])).toThrow(/authored/u); + expect(() => stageAndroidLintSources(stage, [sources[0]])).toThrow(/compiler SDK/u); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/build_defs/languages/jvm/android-sdk-metadata.mts b/build_defs/languages/jvm/android-sdk-metadata.mts new file mode 100644 index 000000000..ca039d798 --- /dev/null +++ b/build_defs/languages/jvm/android-sdk-metadata.mts @@ -0,0 +1,219 @@ +import { readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; + +function properties(file) { + return Object.fromEntries( + readFileSync(file, 'utf8') + .split('\n') + .filter((line) => line.includes('=') && !line.startsWith('#')) + .map((line) => { + const index = line.indexOf('='); + return [line.slice(0, index).trim(), line.slice(index + 1).trim()]; + }), + ); +} + +export function androidSdkMetadata(manifest, { os = process.platform, arch = process.arch } = {}) { + if (os !== 'linux' || arch !== 'x64') + throw new Error('native Android SDK construction requires Linux x86_64 execution'); + const packages = manifest.packages; + const api = Number(packages?.compile_sdk); + if ( + !Number.isSafeInteger(api) || + api <= 0 || + !/^\d+[.]\d+[.]\d+$/u.test(packages?.build_tools) || + !/^\d+[.]\d+[.]\d+$/u.test(packages?.platform_tools) + ) + throw new Error('Android SDK acquisition requires exact conventional SDK package versions'); + const archives = [ + { ...manifest.platform, directory: `platforms/android-${api}`, role: 'platform' }, + { + ...manifest.build_tools?.linux, + directory: `build-tools/${packages.build_tools}`, + role: 'build-tools', + }, + { ...manifest.platform_tools?.linux, directory: 'platform-tools', role: 'platform-tools' }, + ]; + for (const archive of archives) { + if ( + typeof archive.url !== 'string' || + !/^https:\/\/dl[.]google[.]com\/android\/repository\/[A-Za-z0-9_.-]+[.]zip$/u.test( + archive.url, + ) || + !/^[a-f0-9]{64}$/u.test(archive.sha256) || + !/^[A-Za-z0-9_.-]+$/u.test(archive.strip_prefix) + ) + throw new Error( + `Android SDK ${archive.role} requires an immutable Google archive and SHA-256`, + ); + } + if ( + manifest.platform.strip_prefix !== `android-${api}` || + !/^[1-9]\d*$/u.test(manifest.platform.revision) + ) + throw new Error( + 'Android SDK platform archive must match the conventional compile SDK and revision', + ); + return { + api, + buildTools: packages.build_tools, + platformTools: packages.platform_tools, + archives, + }; +} + +export function verifyAndroidSdk(directory, metadata) { + const platform = properties( + path.join(directory, `platforms/android-${metadata.api}/source.properties`), + ); + const buildTools = properties( + path.join(directory, `build-tools/${metadata.buildTools}/source.properties`), + ); + const platformTools = properties(path.join(directory, 'platform-tools/source.properties')); + if ( + Number(platform['AndroidVersion.ApiLevel']) !== metadata.api || + platform['Pkg.Revision'] !== metadata.archives[0].revision || + buildTools['Pkg.Revision'] !== metadata.buildTools || + platformTools['Pkg.Revision'] !== metadata.platformTools + ) + throw new Error('Android SDK archive package identities differ from the conventional pins'); +} + +export function androidEmulatorMetadata( + manifest, + { os = process.platform, arch = process.arch } = {}, +) { + if (os !== 'linux' || arch !== 'x64') + throw new Error('installed Android qualification requires Linux x86_64 execution'); + const version = manifest.packages?.emulator; + const image = manifest.system_image?.linux_x86_64; + if ( + !/^\d+[.]\d+[.]\d+$/u.test(version) || + !image || + image.api !== '35' || + image.tag !== 'google_atd' || + image.abi !== 'x86_64' || + !/^[1-9]\d*$/u.test(image.revision) + ) + throw new Error( + 'installed Android qualification requires exact emulator and API35 google_atd/x86_64 pins', + ); + const imagePath = `system-images/android-${image.api}/${image.tag}/${image.abi}`; + const archives = [ + { ...manifest.emulator?.linux, directory: 'emulator', role: 'emulator' }, + { ...image, directory: imagePath, role: 'system-image' }, + { + ...manifest.command_line_tools?.linux, + directory: 'cmdline-tools/latest', + role: 'command-line-tools', + strip_prefix: 'cmdline-tools', + }, + ]; + for (const archive of archives) { + const allowed = + archive.role === 'emulator' + ? /^https:\/\/dl[.]google[.]com\/android\/repository\/emulator-linux_x64-\d+[.]zip$/u + : archive.role === 'system-image' + ? /^https:\/\/dl[.]google[.]com\/android\/repository\/sys-img\/google_atd\/x86_64-35_r\d+[.]zip$/u + : /^https:\/\/dl[.]google[.]com\/android\/repository\/commandlinetools-linux-\d+_latest[.]zip$/u; + if ( + !allowed.test(archive.url) || + !/^[a-f0-9]{64}$/u.test(archive.sha256) || + !/^[A-Za-z0-9_.-]+$/u.test(archive.strip_prefix) || + !Number.isSafeInteger(Number(archive.bytes)) || + Number(archive.bytes) <= 0 + ) + throw new Error( + `installed Android ${archive.role} requires an immutable official archive, size and SHA-256`, + ); + } + if (archives[0].strip_prefix !== 'emulator' || archives[1].strip_prefix !== image.abi) + throw new Error('installed Android archive prefixes differ from their package identities'); + if ( + archives[2].url !== + `https://dl.google.com/android/repository/commandlinetools-linux-${manifest.packages.command_line_tools_build}_latest.zip` || + !/^\d+[.]\d+$/u.test(manifest.packages.command_line_tools_revision) + ) + throw new Error( + 'Installed Android AVD tools differ from the conventional command-line tools pin', + ); + return { + version, + api: Number(image.api), + tag: image.tag, + abi: image.abi, + commandLineToolsRevision: manifest.packages.command_line_tools_revision, + imageRevision: image.revision, + imagePath, + archives, + }; +} + +export function verifyAndroidEmulator(directory, metadata) { + const emulator = properties(path.join(directory, 'emulator/source.properties')); + const image = properties(path.join(directory, metadata.imagePath, 'source.properties')); + const tools = properties(path.join(directory, 'cmdline-tools/latest/source.properties')); + if ( + emulator['Pkg.Revision'] !== metadata.version || + image['Pkg.Revision'] !== metadata.imageRevision || + Number(image['AndroidVersion.ApiLevel']) !== metadata.api || + image['SystemImage.TagId'] !== metadata.tag || + image['SystemImage.Abi'] !== metadata.abi || + tools['Pkg.Revision'] !== metadata.commandLineToolsRevision + ) + throw new Error('Android emulator/image package identities differ from the conventional pins'); + const minimum = /^emulator#(\d+[.]\d+[.]\d+)$/u.exec(image['Pkg.Dependencies']); + if (!minimum || !Bun.semver.satisfies(metadata.version, '>=' + minimum[1])) + throw new Error('Pinned emulator does not satisfy the original system-image requirement'); +} + +export function androidLocalPackageDocuments(directory, metadata) { + verifyAndroidEmulator(directory, metadata); + const image = properties(path.join(directory, metadata.imagePath, 'source.properties')); + const xml = (text) => + String(text) + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"'); + if ( + !/^\d+$/u.test(image['AndroidVersion.ExtensionLevel']) || + !['true', 'false'].includes(image['AndroidVersion.IsBaseSdk']) || + image['Addon.VendorId'] !== 'google' + ) + throw new Error('Original Android system image lacks its standard SDK type metadata'); + const document = (id, type, revision, description) => + `\n\n${type}${revision}${xml(description)}\n\n`; + const [major, minor, micro] = metadata.version.split('.'); + return { + 'emulator/package.xml': document( + 'emulator', + '', + `${major}${minor}${micro}`, + 'Android Emulator', + ), + [metadata.imagePath + '/package.xml']: document( + metadata.imagePath.replaceAll('/', ';'), + `${metadata.api}${image['AndroidVersion.ExtensionLevel']}${image['AndroidVersion.IsBaseSdk']}${xml(metadata.tag)}${xml(image['SystemImage.TagDisplay'])}${xml(image['Addon.VendorId'])}${xml(image['Addon.VendorDisplay'])}${xml(metadata.abi)}${xml(metadata.abi)}`, + `${metadata.imageRevision}`, + image['Pkg.Desc'], + ), + }; +} + +if (import.meta.main) { + const [manifestFile, outputFile, ...rest] = process.argv.slice(2); + const installed = rest[0] === '--emulator'; + const directory = rest[installed ? 1 : 0]; + if (!manifestFile || !outputFile || rest.length > (installed ? 2 : 1)) + throw new Error('usage: android-sdk-metadata.mts MANIFEST OUTPUT [--emulator] [SDK_DIRECTORY]'); + const manifest = Bun.TOML.parse(readFileSync(manifestFile, 'utf8')); + const metadata = installed ? androidEmulatorMetadata(manifest) : androidSdkMetadata(manifest); + if (directory) (installed ? verifyAndroidEmulator : verifyAndroidSdk)(directory, metadata); + if (installed && directory) + for (const [relative, text] of Object.entries( + androidLocalPackageDocuments(directory, metadata), + )) + writeFileSync(path.join(directory, relative), text); + writeFileSync(outputFile, JSON.stringify(metadata)); +} diff --git a/build_defs/languages/jvm/android-sdk-metadata.test.mts b/build_defs/languages/jvm/android-sdk-metadata.test.mts new file mode 100644 index 000000000..ff0e5505b --- /dev/null +++ b/build_defs/languages/jvm/android-sdk-metadata.test.mts @@ -0,0 +1,154 @@ +import { expect, test } from 'bun:test'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { + androidEmulatorMetadata, + androidLocalPackageDocuments, + androidSdkMetadata, + verifyAndroidEmulator, + verifyAndroidSdk, +} from './android-sdk-metadata.mts'; + +const manifest = Bun.TOML.parse( + readFileSync(new URL('../../../tools/dev/android-sdk.toml', import.meta.url), 'utf8'), +); + +test('acquisition derives exact versions and checked archives from the conventional SDK manifest', () => { + const metadata = androidSdkMetadata(manifest); + expect(metadata.api).toBe(Number(manifest.packages.compile_sdk)); + expect(metadata.buildTools).toBe(manifest.packages.build_tools); + expect(metadata.platformTools).toBe(manifest.packages.platform_tools); + expect(metadata.archives.map(({ directory }) => directory)).toEqual([ + 'platforms/android-36', + 'build-tools/36.0.0', + 'platform-tools', + ]); + for (const update of [ + (value) => { + value.platform.sha256 = ''; + }, + (value) => { + value.platform.url = 'https://example.com/sdk.zip'; + }, + (value) => { + value.packages.compile_sdk = '37'; + }, + (value) => { + value.build_tools.linux.strip_prefix = '../outside'; + }, + ]) { + const value = structuredClone(manifest); + update(value); + expect(() => androidSdkMetadata(value)).toThrow(); + } + expect(() => androidSdkMetadata(manifest, { os: 'darwin', arch: 'arm64' })).toThrow( + 'Linux x86_64', + ); +}); + +test('installed emulator pins are lazy and remain independent of the compiler SDK archives', () => { + const metadata = androidEmulatorMetadata(manifest); + expect(metadata.api).toBe(35); + expect(metadata.abi).toBe('x86_64'); + expect(metadata.tag).toBe('google_atd'); + expect(metadata.version).toBe(manifest.packages.emulator); + expect(metadata.archives.map((row) => row.role)).toEqual([ + 'emulator', + 'system-image', + 'command-line-tools', + ]); + const compiler = androidSdkMetadata(manifest); + const value = structuredClone(manifest); + value.emulator.linux.sha256 = ''; + expect(() => androidEmulatorMetadata(value)).toThrow('immutable'); + expect(androidSdkMetadata(value)).toEqual(compiler); + for (const update of [ + (value) => { + value.system_image.linux_x86_64.api = '36'; + }, + (value) => { + value.system_image.linux_x86_64.abi = 'arm64-v8a'; + }, + (value) => { + value.emulator.linux.url = 'https://example.com/emulator.zip'; + }, + (value) => { + value.system_image.linux_x86_64.strip_prefix = '../outside'; + }, + (value) => { + value.packages.command_line_tools_build = '0'; + }, + ]) { + const value = structuredClone(manifest); + update(value); + expect(() => androidEmulatorMetadata(value)).toThrow(); + } +}); + +test('offline AVD package documents derive from verified original properties and do not rewrite test inputs', () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-emulator-properties-')); + const metadata = androidEmulatorMetadata(manifest); + const input = { + 'emulator/source.properties': `Pkg.Revision=${metadata.version}\n`, + 'cmdline-tools/latest/source.properties': `Pkg.Revision=${metadata.commandLineToolsRevision}\n`, + [metadata.imagePath + '/source.properties']: + `Pkg.Revision=${metadata.imageRevision}\nAndroidVersion.ApiLevel=${metadata.api}\nAndroidVersion.ExtensionLevel=13\nAndroidVersion.IsBaseSdk=true\nSystemImage.TagId=${metadata.tag}\nSystemImage.TagDisplay=Google APIs ATD\nSystemImage.Abi=${metadata.abi}\nAddon.VendorId=google\nAddon.VendorDisplay=Google Inc.\nPkg.Desc=Original API35 image\nPkg.Dependencies=emulator#32.1.8\n`, + }; + try { + for (const [relative, text] of Object.entries(input)) { + mkdirSync(path.dirname(path.join(root, relative)), { recursive: true }); + writeFileSync(path.join(root, relative), text); + } + expect(() => verifyAndroidEmulator(root, metadata)).not.toThrow(); + const docs = androidLocalPackageDocuments(root, metadata); + expect(docs['emulator/package.xml']).toContain( + `${metadata.version.split('.')[0]}`, + ); + expect(docs[metadata.imagePath + '/package.xml']).toContain( + `${metadata.api}`, + ); + expect(docs[metadata.imagePath + '/package.xml']).toContain( + '13', + ); + for (const [relative, text] of Object.entries(input)) + expect(readFileSync(path.join(root, relative), 'utf8')).toBe(text); + const image = path.join(root, metadata.imagePath, 'source.properties'); + for (const [from, to] of [ + [`AndroidVersion.ApiLevel=${metadata.api}`, 'AndroidVersion.ApiLevel=36'], + ['SystemImage.Abi=x86_64', 'SystemImage.Abi=arm64-v8a'], + ['emulator#32.1.8', 'emulator#99.0.0'], + ]) { + writeFileSync(image, input[metadata.imagePath + '/source.properties'].replace(from, to)); + expect(() => verifyAndroidEmulator(root, metadata)).toThrow(); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('downloaded SDK package properties must exactly match the pinned acquisition contract', () => { + const directory = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-sdk-properties-')); + const metadata = androidSdkMetadata(manifest); + const files = [ + ['platforms/android-36/source.properties', 'AndroidVersion.ApiLevel=36\nPkg.Revision=2\n'], + ['build-tools/36.0.0/source.properties', 'Pkg.Revision=36.0.0\n'], + ['platform-tools/source.properties', 'Pkg.Revision=37.0.0\n'], + ]; + try { + for (const [relative, text] of files) { + const file = path.join(directory, relative); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, text); + } + expect(() => verifyAndroidSdk(directory, metadata)).not.toThrow(); + for (const [relative, text] of files) { + const file = path.join(directory, relative); + writeFileSync(file, 'Pkg.Revision=0\n'); + expect(() => verifyAndroidSdk(directory, metadata)).toThrow('package identities'); + writeFileSync(file, text); + } + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); diff --git a/build_defs/languages/jvm/android-sdk-repository.bzl b/build_defs/languages/jvm/android-sdk-repository.bzl new file mode 100644 index 000000000..c880118b0 --- /dev/null +++ b/build_defs/languages/jvm/android-sdk-repository.bzl @@ -0,0 +1,141 @@ +"""Lazy SDK registrations and pinned archives using maintained Android rules.""" + +def _supported_host(ctx): + return ctx.os.name == "linux" and ctx.os.arch in ["amd64", "x86_64"] + +def _sdk_metadata(ctx): + ctx.read(ctx.attr.manifest) + ctx.read(ctx.attr.converter) + ctx.watch(ctx.path(ctx.attr.bun)) + command = [str(ctx.path(ctx.attr.bun)), str(ctx.path(ctx.attr.converter)), str(ctx.path(ctx.attr.manifest)), str(ctx.path("sdk.json"))] + checked = ctx.execute(command, timeout = 60) + if checked.return_code: + fail("Android SDK acquisition metadata is invalid:\n" + checked.stdout + checked.stderr) + return json.decode(ctx.read("sdk.json")), command + +def _android_sdk_hub_impl(ctx): + if not _supported_host(ctx): + ctx.template("BUILD.bazel", ctx.attr.empty_template) + return ctx.repo_metadata(reproducible = True) + metadata, _ = _sdk_metadata(ctx) + archive = "@%s//:" % ctx.attr.archive + api = metadata["api"] + # Upstream globally registers @androidsdk//:all. The registration package + # must contain no archive-backed toolchain types, settings or loaded .bzl + # files. Implementation labels and ordinary aliases remain lazy. + lines = [ + 'load("@rules_android//rules/android_sdk_repository:helper.bzl", "int_flag")', + 'package(default_visibility = ["//visibility:public"])', + 'toolchain_type(name = "sdk_toolchain_type")', + 'config_feature_flag(name = "true", allowed_values = ["true", "false"], default_value = "true")', + 'config_setting(name = "always_true", flag_values = {":true": "true"})', + 'config_setting(name = "always_false", flag_values = {":true": "false"})', + 'alias(name = "has_androidsdk", actual = ":always_true")', + 'int_flag(name = "api_level", build_setting_default = %d, values = [%d])' % (api, api), + 'config_setting(name = "api_%d_enabled", flag_values = {":api_level": "%d"})' % (api, api), + 'toolchain(name = "sdk-toolchain", toolchain_type = ":sdk_toolchain_type", toolchain = "%ssdk-%d", exec_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], target_settings = [":api_%d_enabled"])' % (archive, api, api), + 'alias(name = "sdk-%d-toolchain", actual = ":sdk-toolchain")' % api, + ] + # Keep the aliases used by the maintained Android/Kotlin rules and the SDK + # platform jars. Actual tools and their runfiles stay in the archive repo, + # rendered by upstream's unchanged template/helper. + aliases = [ + "sdk", "sdk-%d" % api, "files", "aapt2", "fail", + "platform-tools/adb", "adb", "platform_tools_files", "dexdump", "build_tools_libs", + "core-for-system-modules-jar", "d8_jar_import", + "org_apache_http_legacy", "org_apache_http_legacy-%d" % api, + ] + if api >= 28: + aliases.append("legacy_test-%d" % api) + for name in aliases: + lines.append('alias(name = "%s", actual = "%s%s")' % (name, archive, name)) + ctx.file("BUILD.bazel", "\n".join(lines) + "\n") + return ctx.repo_metadata(reproducible = True) + +def _android_sdk_archive_impl(ctx): + if not _supported_host(ctx): + # Non-Android source clients need no Linux binary SDK acquisition. + ctx.template("BUILD.bazel", ctx.attr.empty_template) + return ctx.repo_metadata(reproducible = True) + metadata, command = _sdk_metadata(ctx) + for archive in metadata["archives"]: + ctx.download_and_extract(url = archive["url"], sha256 = archive["sha256"], output = archive["directory"], strip_prefix = archive["strip_prefix"]) + checked = ctx.execute(command + [str(ctx.path("."))], timeout = 60) + if checked.return_code: + fail("Android SDK archive identity is invalid:\n" + checked.stdout + checked.stderr) + ctx.symlink(ctx.attr.helper, "helper.bzl") + ctx.template("BUILD.bazel", ctx.attr.template, substitutions = { + "__repository_name__": ctx.name, + "__build_tools_version__": metadata["buildTools"], + "__build_tools_directory__": metadata["buildTools"], + "__api_levels__": str(metadata["api"]), + "__default_api_level__": str(metadata["api"]), + "__system_image_dirs__": "", + }) + platform = "platforms/android-%d/" % metadata["api"] + ctx.file("BUILD.bazel", ctx.read("BUILD.bazel") + '\nfilegroup(name = "lint_inputs", srcs = glob(%s), visibility = ["//visibility:public"])\n' % repr([ + platform + "android.jar", + platform + "framework.aidl", + platform + "source.properties", + platform + "sdk.properties", + platform + "build.prop", + platform + "data/**", + ])) + ctx.file("BUILD.bazel", ctx.read("BUILD.bazel") + '\nfilegroup(name = "platform_tools_files", srcs = glob(["platform-tools/**"]), visibility = ["//visibility:public"])\n') + return ctx.repo_metadata(reproducible = True) + +def _android_emulator_impl(ctx): + if not _supported_host(ctx): + ctx.template("BUILD.bazel", ctx.attr.empty_template) + return ctx.repo_metadata(reproducible = True) + ctx.read(ctx.attr.manifest) + ctx.read(ctx.attr.converter) + ctx.watch(ctx.path(ctx.attr.bun)) + command = [str(ctx.path(ctx.attr.bun)), str(ctx.path(ctx.attr.converter)), str(ctx.path(ctx.attr.manifest)), str(ctx.path("emulator.json")), "--emulator"] + result = ctx.execute(command, timeout = 60) + if result.return_code: + fail("Android emulator acquisition metadata is invalid:\n" + result.stdout + result.stderr) + metadata = json.decode(ctx.read("emulator.json")) + for archive in metadata["archives"]: + ctx.download_and_extract(url = archive["url"], sha256 = archive["sha256"], output = archive["directory"], strip_prefix = archive["strip_prefix"]) + result = ctx.execute(command + [str(ctx.path("."))], timeout = 60) + if result.return_code: + fail("Android emulator archive identity is invalid:\n" + result.stdout + result.stderr) + ctx.file("BUILD.bazel", '\n'.join([ + 'package(default_visibility = ["//visibility:public"])', + 'exports_files(["emulator.json"])', + 'filegroup(name = "files", srcs = glob(["emulator/**", "system-images/**", "cmdline-tools/**"]))', + ]) + '\n') + return ctx.repo_metadata(reproducible = True) + +def _metadata_attrs(): + return { + "manifest": attr.label(default = Label("//tools/dev:android-sdk.toml"), allow_single_file = True), + "bun": attr.label(default = Label("@bun_runtime//:bun"), allow_single_file = True), + "converter": attr.label(default = Label("//build_defs/languages/jvm:android-sdk-metadata.mts"), allow_single_file = True), + "empty_template": attr.label(default = Label("@rules_android//rules/android_sdk_repository:empty.template.bzl"), allow_single_file = True), + } + +_hub_attrs = _metadata_attrs() +_hub_attrs["archive"] = attr.string(mandatory = True) + +android_sdk_hub_repository = repository_rule( + implementation = _android_sdk_hub_impl, + attrs = _hub_attrs, +) + +_archive_attrs = _metadata_attrs() +_archive_attrs.update({ + "template": attr.label(default = Label("@rules_android//rules/android_sdk_repository:template.bzl"), allow_single_file = True), + "helper": attr.label(default = Label("@rules_android//rules/android_sdk_repository:helper.bzl"), allow_single_file = True), +}) + +android_sdk_archive_repository = repository_rule( + implementation = _android_sdk_archive_impl, + attrs = _archive_attrs, +) + +android_emulator_repository = repository_rule( + implementation = _android_emulator_impl, + attrs = _metadata_attrs(), +) diff --git a/build_defs/languages/jvm/bindings.bzl b/build_defs/languages/jvm/bindings.bzl new file mode 100644 index 000000000..f52eeb1e9 --- /dev/null +++ b/build_defs/languages/jvm/bindings.bzl @@ -0,0 +1,31 @@ +"""Kotlin bindings from the same declared Unix mobile metadata and UniFFI CLI.""" + +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") + +def _uniffi_kotlin_impl(ctx): + library = ctx.file.library + output = ctx.actions.declare_file(ctx.label.name + "/dev/oliphaunt/bindings/oliphaunt_mobile_bindings.kt") + bun_file_action( + ctx, + entry_point = ctx.file.driver, + source_files = [ctx.file.driver, ctx.file.helper], + arguments = [ctx.executable.generator.path, library.path, ctx.file.configuration.path, output.dirname.removesuffix("/dev/oliphaunt/bindings")], + inputs = [ctx.file.driver, ctx.file.helper, library, ctx.file.configuration], + tools = [ctx.attr.generator[DefaultInfo].files_to_run], + outputs = [output], + mnemonic = "OliphauntUniFfiKotlin", + use_default_shell_env = False, + ) + return [DefaultInfo(files = depset([output]))] + +uniffi_kotlin = rule( + implementation = _uniffi_kotlin_impl, + attrs = { + "library": attr.label(mandatory = True, allow_single_file = [".so", ".dylib", ".rlib"], cfg = "exec"), + "generator": attr.label(mandatory = True, executable = True, cfg = "exec"), + "configuration": attr.label(mandatory = True, allow_single_file = [".toml"]), + "driver": attr.label(default = Label("//build_defs/languages/jvm:generate-kotlin.mts"), allow_single_file = True), + "helper": attr.label(default = Label("//build_defs/languages:uniffi.mts"), allow_single_file = True), + }, + toolchains = BUN_SOURCE_TOOLCHAINS, +) diff --git a/build_defs/languages/jvm/compiled-inputs-test.bzl b/build_defs/languages/jvm/compiled-inputs-test.bzl new file mode 100644 index 000000000..327a46a6c --- /dev/null +++ b/build_defs/languages/jvm/compiled-inputs-test.bzl @@ -0,0 +1,69 @@ +"""Bind Kotlin supplier coverage to its original Android and generator Rust Files.""" + +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") +load("//build_defs/languages:mobile-compiled-inputs.bzl", "MOBILE_BINDINGS_COMPILE_OWNERS", "mobile_bindings_compile_group") +load("//build_defs/release:shipping.bzl", "ShippingExportInfo", "ShippingInfo") +load("//build_defs/release:supplier.bzl", "ShippingSupplierInfo") +load(":maven.bzl", "KOTLIN_BINDINGS_COMPILE_SLOTS") + +def _compiled_inputs_test_impl(ctx): + env = analysistest.begin(ctx) + packages = analysistest.target_under_test(env)[ShippingExportInfo].packages + inputs = ctx.attr.maven[ShippingSupplierInfo] + asserts.true(env, inputs.suppliers != None, "Kotlin compiler inputs require authenticated completed Query source facts") + if inputs.suppliers == None: + return analysistest.end(env) + count = len(MOBILE_BINDINGS_COMPILE_OWNERS) * len(KOTLIN_BINDINGS_COMPILE_SLOTS) + held = [row for row in inputs.suppliers if row["product"] == "oliphaunt-query"] + asserts.equals(env, 1, len(held)) + if len(held) != 1: + return analysistest.end(env) + asserts.equals(env, "compiled-input", held[0]["binding"]) + asserts.equals(env, "completed-publication", held[0]["origin"]["kind"]) + asserts.equals(env, "cargo:oliphaunt-query", held[0]["origin"]["artifact"]) + asserts.equals(env, count + 1, len(inputs.suppliers)) + asserts.equals(env, count, len(packages)) + asserts.equals(env, count, len({str(package.label): True for package in packages})) + asserts.equals(env, 4, len(ctx.attr.maven[DefaultInfo].files.to_list())) + paths = [] + for owner, product in MOBILE_BINDINGS_COMPILE_OWNERS.items(): + producer = {"core": Label("//src/native/rust-bindings:lib"), "sdk": Label("//src/native/sdks/rust:mobile_lib"), "broker": Label("//src/native/broker:lib")}[owner] + for slot in KOTLIN_BINDINGS_COMPILE_SLOTS: + group = mobile_bindings_compile_group(owner, slot) + files = getattr(ctx.attr.maven[OutputGroupInfo], group).to_list() + asserts.equals(env, 1, len(files)) + file = files[0] + asserts.false(env, file.is_source) + asserts.false(env, file.is_directory) + asserts.equals(env, producer, file.owner) + paths.append(file.path) + rows = [row for row in inputs.suppliers if row["product"] == product and row["configuration"] == slot] + asserts.equals(env, 1, len(rows)) + asserts.equals(env, "compiled-input", rows[0]["binding"]) + asserts.equals(env, {"kind": "current-source"}, rows[0]["origin"]) + asserts.equals(env, [{"path": file.path}], rows[0]["files"]) + roots = [package[ShippingInfo] for package in packages if package[ShippingInfo].product == product and package[ShippingInfo].configuration == slot] + asserts.equals(env, 1, len(roots)) + asserts.equals(env, "internal", roots[0].ecosystem) + asserts.equals(env, product + "-kotlin-bindings", roots[0].name) + asserts.equals(env, "compiled-source", roots[0].role) + asserts.equals(env, rows[0]["version"], roots[0].version) + asserts.equals(env, [file.path], [value.path for value in roots[0].files.to_list()]) + products = [MOBILE_BINDINGS_COMPILE_OWNERS["core"]] + ([MOBILE_BINDINGS_COMPILE_OWNERS["broker"]] if owner == "sdk" else []) + expected = [] if owner == "core" else [row for row in inputs.suppliers if row["product"] in products and row["configuration"] == slot] + held + asserts.equals(env, sorted([json.encode(row) for row in expected]), sorted([json.encode(row) for row in roots[0].supplier_inputs])) + asserts.equals(env, count, len({file: True for file in paths})) + plugin = ctx.attr.plugin[ShippingInfo].supplier_inputs + asserts.equals(env, 1, len(plugin)) + asserts.equals(env, "liboliphaunt-native", plugin[0]["product"]) + asserts.equals(env, "abi-contract", plugin[0]["binding"]) + asserts.equals(env, {"kind": "current-source"}, plugin[0]["origin"]) + asserts.equals(env, ["src/native/runtime/bin/android-cxx-runtime.map", "src/native/runtime/include/oliphaunt.h"], sorted([file["path"] for file in plugin[0]["files"]])) + asserts.equals(env, [], ctx.attr.marker[ShippingInfo].supplier_inputs) + return analysistest.end(env) + +kotlin_compiled_inputs_test = analysistest.make(_compiled_inputs_test_impl, attrs = { + "maven": attr.label(mandatory = True, providers = [ShippingSupplierInfo, OutputGroupInfo]), + "plugin": attr.label(mandatory = True, providers = [ShippingInfo]), + "marker": attr.label(mandatory = True, providers = [ShippingInfo]), +}) diff --git a/build_defs/languages/jvm/generate-kotlin.mts b/build_defs/languages/jvm/generate-kotlin.mts new file mode 100644 index 000000000..c8eb7d1ac --- /dev/null +++ b/build_defs/languages/jvm/generate-kotlin.mts @@ -0,0 +1,41 @@ +import assert from 'node:assert/strict'; +import { readdirSync, readFileSync } from 'node:fs'; +import path from 'node:path'; +import { generateUniffi } from '../uniffi.mts'; + +export function validateKotlinConfiguration(configuration: unknown) { + const values = configuration as { + crates?: { oliphaunt_mobile_bindings?: { bindings?: { kotlin?: Record } } }; + }; + const kotlin = values.crates?.oliphaunt_mobile_bindings?.bindings?.kotlin; + assert.equal(kotlin?.package_name, 'dev.oliphaunt.bindings'); + assert.equal(kotlin?.cdylib_name, 'oliphaunt_mobile_bindings'); + assert.equal(kotlin?.disable_java_cleaner, true, 'Android API24 uses the configured JNA cleaner'); +} + +export function validateGeneratedKotlin(directory: string) { + const children = readdirSync(directory, { recursive: true }).sort(); + assert.deepEqual(children, [ + 'dev', + 'dev/oliphaunt', + 'dev/oliphaunt/bindings', + 'dev/oliphaunt/bindings/oliphaunt_mobile_bindings.kt', + ]); + const text = readFileSync( + path.join(directory, 'dev/oliphaunt/bindings/oliphaunt_mobile_bindings.kt'), + 'utf8', + ); + assert.match(text, /^package dev\.oliphaunt\.bindings$/mu); + assert.ok( + text.includes('oliphaunt_mobile_bindings'), + 'Generated bindings must load the conventional mobile cdylib', + ); +} + +if (import.meta.main) { + const [generator, library, configuration, directory] = process.argv.slice(2); + assert.equal(process.argv.length, 6, 'Expected generator, metadata library, config and output'); + validateKotlinConfiguration(Bun.TOML.parse(readFileSync(configuration, 'utf8'))); + generateUniffi({ generator, library, configuration, directory, language: 'kotlin' }); + validateGeneratedKotlin(directory); +} diff --git a/build_defs/languages/jvm/installed-maven-contract.test.mts b/build_defs/languages/jvm/installed-maven-contract.test.mts new file mode 100644 index 000000000..2a01c3436 --- /dev/null +++ b/build_defs/languages/jvm/installed-maven-contract.test.mts @@ -0,0 +1,48 @@ +import { expect, test } from 'bun:test'; +import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { zipArchive } from '../../../tools/packaging/testdata/zip-fixture.mts'; +import { + checkInstalledKotlinMaven, + requirePublicConsumerClasses, +} from './installed-maven.test.mts'; + +test('the installed Android proof requires both compiled Kotlin and Java public API consumers', () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-kotlin-consumer-')); + try { + const kotlin = path.join(root, 'kotlin.jar'); + const java = path.join(root, 'java.jar'); + writeFileSync( + kotlin, + zipArchive([{ name: 'dev/oliphaunt/consumer/PublicApiConsumerKt.class' }]), + ); + writeFileSync( + java, + zipArchive([{ name: 'dev/oliphaunt/consumer/JavaPublicApiConsumer.class' }]), + ); + expect(() => requirePublicConsumerClasses([kotlin, java])).not.toThrow(); + expect(() => requirePublicConsumerClasses([kotlin])).toThrow('JavaPublicApiConsumer.class'); + expect(() => requirePublicConsumerClasses([])).toThrow('declared JARs'); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +for (const member of [ + '../outside.pom', + '/outside.pom', + 'group/../outside.pom', + 'group\\outside.pom', +]) + test(`the installed Maven proof rejects unsafe declared member ${member}`, async () => { + await expect( + checkInstalledKotlinMaven('0.0.1', ['maven', member, 'unread-file']), + ).rejects.toThrow('safe repository relative file'); + }); + +test('the installed Maven proof rejects an incomplete final companion closure', async () => { + await expect(checkInstalledKotlinMaven('0.0.1', [])).rejects.toThrow( + 'exact 10-file Maven Central companion closure', + ); +}); diff --git a/build_defs/languages/jvm/installed-maven.test.mts b/build_defs/languages/jvm/installed-maven.test.mts new file mode 100644 index 000000000..134de8214 --- /dev/null +++ b/build_defs/languages/jvm/installed-maven.test.mts @@ -0,0 +1,87 @@ +import assert from 'node:assert/strict'; +import { copyFileSync, mkdirSync, mkdtempSync, rmSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { checkKotlinPackage } from '../../../src/native/sdks/kotlin/tools/check-package.mts'; +import { validateKotlinMavenStagingClosure } from '../../../src/native/sdks/kotlin/tools/kotlin-maven-staging.mts'; +import { readJavaArchiveEntries } from '../../../tools/packaging/portable-archive.mts'; +import { stageMobileLegalSources } from '../mobile-legal.mts'; + +const PUBLIC_CONSUMER_CLASSES = [ + 'dev/oliphaunt/consumer/PublicApiConsumerKt.class', + 'dev/oliphaunt/consumer/JavaPublicApiConsumer.class', +]; + +export function requirePublicConsumerClasses(files: string[]) { + assert(files.length, 'Installed Android public API consumer must compile to declared JARs'); + const members = new Set(files.flatMap((file) => [...readJavaArchiveEntries(file).keys()])); + for (const member of PUBLIC_CONSUMER_CLASSES) + assert(members.has(member), `Installed Android public API consumer is missing ${member}`); +} + +export async function checkInstalledKotlinMaven(version: string, arguments_: string[]) { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-installed-kotlin-')); + try { + const packageRoot = path.join(root, 'package'); + const maven = path.join(packageRoot, 'maven'); + mkdirSync(maven, { recursive: true }); + const copied = new Set(); + const consumers: string[] = []; + const legalSources: Record = {}; + for (let index = 0; index < arguments_.length; ) { + const kind = arguments_[index++]; + if (kind === 'consumer') { + const file = arguments_[index++]; + assert(file, 'Compiled public API consumer requires its declared JAR'); + const destination = path.join(root, `consumer-${consumers.length}.jar`); + copyFileSync(file, destination); + consumers.push(destination); + continue; + } + if (kind === 'legal') { + const member = arguments_[index++]; + const source = arguments_[index++]; + assert(member && source, 'Installed Kotlin test requires declared legal source files'); + assert(!Object.hasOwn(legalSources, member), `Duplicate declared legal source ${member}`); + legalSources[member] = source; + continue; + } + assert.equal( + kind, + 'maven', + 'Installed Kotlin test accepts only declared Maven files and consumer JARs', + ); + const relative = arguments_[index++]; + const source = arguments_[index++]; + assert( + relative && + source && + !relative.includes('\\') && + !path.posix.isAbsolute(relative) && + relative.split('/').every((part) => part && part !== '.' && part !== '..'), + 'Declared Maven member must be a safe repository relative file', + ); + assert(!copied.has(relative), `Duplicate declared Maven file ${relative}`); + copied.add(relative); + const destination = path.join(maven, relative); + mkdirSync(path.dirname(destination), { recursive: true }); + copyFileSync(source, destination); + } + validateKotlinMavenStagingClosure(maven, version, { allowLocalMetadata: false }); + const sourceRoot = path.join(root, 'legal-sources'); + stageMobileLegalSources(legalSources, sourceRoot); + assert( + await checkKotlinPackage(packageRoot, { sourceRoot }), + 'Final Kotlin Maven repository must contain checked packages', + ); + requirePublicConsumerClasses(consumers); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + const [version, ...arguments_] = process.argv.slice(2); + assert(version, 'Installed Kotlin test requires its canonical owner version'); + await checkInstalledKotlinMaven(version, arguments_); +} diff --git a/build_defs/languages/jvm/javadoc.mts b/build_defs/languages/jvm/javadoc.mts new file mode 100644 index 000000000..ecec7f110 --- /dev/null +++ b/build_defs/languages/jvm/javadoc.mts @@ -0,0 +1,47 @@ +import assert from 'node:assert/strict'; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { spawnSync } from 'node:child_process'; +import { createDeterministicZip } from '../../../tools/packaging/archive-directory.mts'; + +const [output, specification] = process.argv.slice(2); +assert.equal(process.argv.length, 4, 'Expected output archive and declared Java tool/source JSON'); +const values = JSON.parse(readFileSync(specification, 'utf8')); +assert.ok(Array.isArray(values.sources) && values.sources.length > 0); +assert.ok(Array.isArray(values.classpath) && /^\d+$/u.test(values.release)); +assert.ok( + !path.isAbsolute(values.javaHome), + 'Javadoc requires the acquired execution JDK, not an ambient local JDK', +); +const directory = mkdtempSync(path.join(path.dirname(output), '.javadoc-')); +try { + const result = spawnSync( + path.join(values.javaHome, 'bin/javadoc'), + [ + '--release', + values.release, + '-quiet', + '-Xdoclint:none', + '-notimestamp', + '-encoding', + 'UTF-8', + '-charset', + 'UTF-8', + '-docencoding', + 'UTF-8', + '-classpath', + values.classpath.join(path.delimiter), + '-d', + directory, + ...values.sources, + ], + { env: {}, encoding: 'utf8' }, + ); + assert.equal(result.error, undefined, `Javadoc could not start: ${result.error?.message}`); + assert.equal(result.status, 0, `Javadoc failed:\n${result.stdout}${result.stderr}`); + // Validate the actual producer tree before handing it across Bazel's sandbox + // boundary, where declared tree inputs are represented by symlinks. + writeFileSync(output, await createDeterministicZip(directory)); +} finally { + rmSync(directory, { recursive: true, force: true }); +} diff --git a/build_defs/languages/jvm/kotlin-sdk-metadata.mts b/build_defs/languages/jvm/kotlin-sdk-metadata.mts new file mode 100644 index 000000000..1d743ad4e --- /dev/null +++ b/build_defs/languages/jvm/kotlin-sdk-metadata.mts @@ -0,0 +1,184 @@ +import { readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { conventionalPomMetadata } from './maven-pom.mts'; + +export function kotlinSdkMetadata({ + catalog, + gradle, + pluginGradle, + properties, + version, + androidSdk, +}) { + const single = (pattern, label) => { + const matches = [...gradle.matchAll(pattern)]; + if (matches.length !== 1) + throw new Error(`Kotlin SDK requires one conventional ${label} declaration`); + return matches[0][1]; + }; + const compileSdk = Number(single(/\bcompileSdk\s*=\s*(\d+)/gu, 'compileSdk')); + const minSdk = Number(single(/\bminSdk\s*=\s*(\d+)/gu, 'minSdk')); + const namespace = single(/\bnamespace\s*=\s*"([^"]+)"/gu, 'Android namespace'); + const jvmTarget = single( + /gradleProperty\("oliphauntJvmToolchain"\)\s*[.]orElse\("(\d+)"\)/gu, + 'JVM target', + ); + const props = Object.fromEntries( + properties + .split('\n') + .filter((line) => /^[A-Z_]+=/.test(line)) + .map((line) => line.split('=', 2)), + ); + if ( + compileSdk !== Number(androidSdk.packages.compile_sdk) || + !Number.isSafeInteger(minSdk) || + minSdk < 1 || + minSdk > compileSdk || + namespace !== 'dev.oliphaunt' || + props.VERSION_NAME !== version || + props.GROUP !== 'dev.oliphaunt' + ) + throw new Error( + 'Kotlin SDK compiler/publication defaults differ from the conventional Android and product manifests', + ); + if (!/^\d+[.]\d+[.]\d+$/u.test(catalog.versions.kotlin) || !/^\d+$/u.test(jvmTarget)) + throw new Error('Kotlin SDK requires exact compiler and JVM target versions'); + function library(alias) { + const raw = catalog.libraries[alias]; + const version = + typeof raw?.version === 'string' ? raw.version : catalog.versions[raw?.version?.ref]; + if ( + !raw || + !/^[A-Za-z0-9_.-]+:[A-Za-z0-9_.-]+$/u.test(raw.module) || + typeof version !== 'string' || + version.length === 0 + ) + throw new Error( + `Kotlin SDK catalog library ${alias} must have one exact conventional coordinate`, + ); + return { module: raw.module, version }; + } + const libraries = Object.fromEntries( + ['kotlin-stdlib', 'jna', 'kotlinx-coroutines-core'].map((alias) => [alias, library(alias)]), + ); + if (libraries['kotlin-stdlib'].version !== catalog.versions.kotlin) + throw new Error('Kotlin stdlib must retain the compiler version owner'); + return { + compilerVersion: catalog.versions.kotlin, + languageVersion: catalog.versions.kotlin.split('.').slice(0, 2).join('.'), + jvmTarget, + compileSdk, + minSdk, + namespace, + libraries, + sdkPom: conventionalPomMetadata(gradle, version), + pluginPom: conventionalPomMetadata(pluginGradle, version), + }; +} + +/** Import source formatter scope without adding tooling to production metadata. */ +export function kotlinQualityMetadata({ catalog, gradle }) { + const library = catalog.libraries['ktlint-cli']; + const version = catalog.versions[library?.version?.ref]; + if ( + library?.module !== 'com.pinterest.ktlint:ktlint-cli' || + library?.version?.ref !== 'ktlint' || + typeof version !== 'string' || + !/^\d+[.]\d+[.]\d+$/u.test(version) + ) + throw new Error('Kotlin formatter requires its exact conventional ktlint-cli catalog pin'); + const blocks = [...gradle.matchAll(/^spotless\s*\{\n([\s\S]*?)^\}/gmu)]; + if (blocks.length !== 1) + throw new Error('Kotlin formatter requires one conventional Spotless block'); + let remainder = blocks[0][1]; + const formats = [ + ...remainder.matchAll(/^ {4}(kotlin|kotlinGradle)\s*\{\n([\s\S]*?)^ {4}\}/gmu), + ].map(([block, name, content]) => { + remainder = remainder.replace(block, ''); + const declaration = content.match( + /^\s*target\(([\s\S]*?)\)\s*ktlint\(\s*libs[.]versions[.]ktlint[.]get\(\)\s*,?\s*\)\s*(?:[.]editorConfigOverride\(\s*mapOf\(([\s\S]*?)\)\s*,?\s*\))?\s*$/u, + ); + if (!declaration) + throw new Error( + `Kotlin formatter requires literal targets and canonical ktlint pin for ${name}`, + ); + function literals(value: string, pattern: RegExp) { + const matches = [...value.matchAll(pattern)]; + if (!matches.length || value.replace(pattern, '').replaceAll(',', '').trim()) + throw new Error('Kotlin formatter requires literal conventional scope/configuration'); + return matches; + } + const targets = literals(declaration[1], /"([^"\n]+)"/gu).map(([, target]) => { + const relative = path.posix.normalize(`oliphaunt/${target}`); + if ( + /[$\\\u0000-\u001f]/u.test(target) || + target.startsWith('/') || + relative === '..' || + relative.startsWith('../') || + !relative.endsWith(name === 'kotlin' ? '.kt' : '.gradle.kts') + ) + throw new Error('Kotlin formatter targets must stay in the conventional SDK source tree'); + return relative; + }); + const editorConfig = declaration[2] + ? Object.fromEntries( + literals(declaration[2], /"([A-Za-z0-9_.-]+)"\s+to\s+"([A-Za-z0-9_.-]+)"/gu).map( + ([, key, value]) => [key, value], + ), + ) + : {}; + return { name, targets, editorConfig }; + }); + if ( + remainder.trim() || + formats + .map(({ name }) => name) + .sort() + .join(',') !== 'kotlin,kotlinGradle' + ) + throw new Error('Kotlin formatter requires exactly the conventional Kotlin and Gradle scopes'); + const lintVersion = catalog.versions['android-lint']; + const agp = catalog.plugins['android-library']; + const agpVersion = catalog.versions[agp?.version?.ref]; + if ( + typeof lintVersion !== 'string' || + !/^\d+[.]\d+[.]\d+$/u.test(lintVersion) || + agp?.id !== 'com.android.library' || + typeof agpVersion !== 'string' || + !/^\d+[.]\d+[.]\d+$/u.test(agpVersion) + ) + throw new Error('Android Lint requires exact conventional Lint and Android plugin pins'); + return { + ktlint: { module: library.module, version, formats }, + // lint-gradle declares the Groovy runtime used by GradleDetector. The + // plain lint POM omits that official CLI detector dependency closure. + lint: { module: 'com.android.tools.lint:lint-gradle', version: lintVersion, agpVersion }, + }; +} + +/** Keep the standalone Lint dependency resolver separate from SDK/formatter libraries. */ +export function kotlinLintCatalog(inputs: Parameters[0]) { + const { lint } = kotlinQualityMetadata(inputs); + return `[versions]\nandroid-lint = "${lint.version}"\n\n[libraries]\nandroid-lint = { module = "${lint.module}", version.ref = "android-lint" }\n`; +} + +if (import.meta.main) { + const [catalog, gradle, pluginGradle, properties, version, sdk, output] = process.argv.slice(2); + if (!output || process.argv.length !== 9) + throw new Error( + 'usage: kotlin-sdk-metadata.mts CATALOG GRADLE PLUGIN_GRADLE PROPERTIES VERSION ANDROID_SDK OUTPUT', + ); + const inputs = { + catalog: Bun.TOML.parse(readFileSync(catalog, 'utf8')), + gradle: readFileSync(gradle, 'utf8'), + pluginGradle: readFileSync(pluginGradle, 'utf8'), + properties: readFileSync(properties, 'utf8'), + version: readFileSync(version, 'utf8').trim(), + androidSdk: Bun.TOML.parse(readFileSync(sdk, 'utf8')), + }; + writeFileSync( + output, + `KOTLIN = ${JSON.stringify(kotlinSdkMetadata(inputs), null, 2)}\nKOTLIN_QUALITY = ${JSON.stringify(kotlinQualityMetadata(inputs), null, 2)}\n`, + ); + writeFileSync(path.join(path.dirname(output), 'lint.versions.toml'), kotlinLintCatalog(inputs)); +} diff --git a/build_defs/languages/jvm/kotlin-sdk-metadata.test.mts b/build_defs/languages/jvm/kotlin-sdk-metadata.test.mts new file mode 100644 index 000000000..7b233fecf --- /dev/null +++ b/build_defs/languages/jvm/kotlin-sdk-metadata.test.mts @@ -0,0 +1,182 @@ +import { expect, test } from 'bun:test'; +import { readFileSync } from 'node:fs'; +import { validateMavenCentralPublication } from '../../../tools/packaging/maven-central-contract.mts'; +import { + kotlinLintCatalog, + kotlinQualityMetadata, + kotlinSdkMetadata, +} from './kotlin-sdk-metadata.mts'; +import { mavenPom } from './maven-pom.mts'; + +const read = (member: string) => + readFileSync(new URL(`../../../${member}`, import.meta.url), 'utf8'); +function inputs() { + return { + catalog: Bun.TOML.parse(read('src/native/sdks/kotlin/gradle/libs.versions.toml')), + gradle: read('src/native/sdks/kotlin/oliphaunt/build.gradle.kts'), + pluginGradle: read('src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/build.gradle.kts'), + properties: read('src/native/sdks/kotlin/gradle.properties'), + version: read('src/native/sdks/kotlin/VERSION').trim(), + androidSdk: Bun.TOML.parse(read('tools/dev/android-sdk.toml')), + }; +} +test('imports compiler, Android and POM facts from the conventional manifests', () => { + const source = inputs(); + const metadata = kotlinSdkMetadata(source); + expect(metadata.compilerVersion).toBe(source.catalog.versions.kotlin); + expect(metadata.jvmTarget).toBe('17'); + expect(metadata.languageVersion).toBe('2.2'); + expect(metadata.compileSdk).toBe(Number(source.androidSdk.packages.compile_sdk)); + expect(metadata.minSdk).toBe(24); + expect(metadata.libraries.jna.version).toBe(source.catalog.versions.jna); + expect(metadata.sdkPom.license.url).toContain(`oliphaunt-kotlin-v${source.version}/LICENSE`); + expect(metadata.pluginPom.scm.developerConnection).toContain('github.com:f0rr0'); + const coordinate = { + groupId: 'dev.oliphaunt', + artifactId: 'oliphaunt-android', + version: source.version, + packaging: 'aar', + }; + const validated = validateMavenCentralPublication({ + pomText: mavenPom({ coordinate, metadata: metadata.sdkPom }), + files: [`.aar`, '.pom', '-sources.jar', '-javadoc.jar'].map((suffix) => ({ + name: `${coordinate.artifactId}-${source.version}${suffix}`, + size: 1, + })), + }); + expect(validated.artifactId).toBe(coordinate.artifactId); +}); + +test('imports the existing Spotless formatter pin and scopes separately from production facts', () => { + const source = inputs(); + const before = kotlinSdkMetadata(source); + const metadata = kotlinQualityMetadata(source).ktlint; + expect(metadata.version).toBe('1.8.0'); + expect(metadata.formats).toEqual([ + { + name: 'kotlin', + targets: ['oliphaunt/src/**/*.kt', 'tests/public-api-consumer/src/**/*.kt'], + editorConfig: { + 'ktlint_standard_property-naming': 'disabled', + ktlint_code_style: 'intellij_idea', + }, + }, + { + name: 'kotlinGradle', + targets: ['oliphaunt/*.gradle.kts', '*.gradle.kts', 'tests/public-api-consumer/*.gradle.kts'], + editorConfig: {}, + }, + ]); + source.catalog.versions.ktlint = '99.0.0'; + expect(kotlinSdkMetadata(source)).toEqual(before); + expect(kotlinQualityMetadata(source).ktlint.version).toBe('99.0.0'); + expect(Object.keys(before.libraries)).toEqual([ + 'kotlin-stdlib', + 'jna', + 'kotlinx-coroutines-core', + ]); +}); + +test('preserves literal formatter facts across conventional multiline formatting', () => { + const source = inputs(); + const expected = kotlinQualityMetadata(source); + source.gradle = source.gradle + .replace( + 'ktlint(libs.versions.ktlint.get())', + 'ktlint(\n libs.versions.ktlint.get(),\n )', + ) + .replace( + 'target("src/**/*.kt", "../tests/public-api-consumer/src/**/*.kt")', + 'target(\n "src/**/*.kt",\n "../tests/public-api-consumer/src/**/*.kt",\n )', + ); + expect(kotlinQualityMetadata(source)).toEqual(expected); + expect(expected.ktlint.formats.find(({ name }) => name === 'kotlinGradle').editorConfig).toEqual( + {}, + ); +}); + +test('isolates the conventional Android Lint tool pin from production and formatter resolution', () => { + const source = inputs(); + const production = kotlinSdkMetadata(source); + const formatter = kotlinQualityMetadata(source).ktlint; + const aliases = Object.keys(source.catalog.libraries); + const quality = kotlinQualityMetadata(source); + expect(quality.lint).toEqual({ + module: 'com.android.tools.lint:lint-gradle', + version: '31.11.1', + agpVersion: source.catalog.versions['android-gradle-plugin'], + }); + expect(Bun.TOML.parse(kotlinLintCatalog(source))).toEqual({ + versions: { 'android-lint': '31.11.1' }, + libraries: { + 'android-lint': { + module: quality.lint.module, + version: { ref: 'android-lint' }, + }, + }, + }); + source.catalog.versions['android-lint'] = '99.0.0'; + expect(kotlinSdkMetadata(source)).toEqual(production); + expect(kotlinQualityMetadata(source).ktlint).toEqual(formatter); + expect(Object.keys(source.catalog.libraries)).toEqual(aliases); + expect(kotlinQualityMetadata(source).lint.version).toBe('99.0.0'); + source.catalog.versions['android-lint'] = 'latest.release'; + expect(() => kotlinLintCatalog(source)).toThrow(/exact conventional/u); +}); + +test('rejects unsupported or escaping formatter declarations instead of silently losing scope', () => { + for (const change of [ + (source) => { + source.gradle = source.gradle.replace('ktlint(libs.versions.ktlint.get())', 'ktlint()'); + }, + (source) => { + source.gradle = source.gradle.replace('"src/**/*.kt"', '"../../outside/**/*.kt"'); + }, + (source) => { + source.gradle = source.gradle.replace('target("src/**/*.kt",', 'target(computedTargets,'); + }, + (source) => { + source.gradle = source.gradle.replace('kotlinGradle {', 'unknownFormat {'); + }, + (source) => { + source.catalog.libraries['ktlint-cli'].version.ref = 'spotless'; + }, + ]) { + const source = inputs(); + change(source); + expect(() => kotlinQualityMetadata(source)).toThrow(); + } +}); +test('rejects ambiguous or contradictory imported construction/publication facts', () => { + const changes = [ + (value) => { + value.androidSdk.packages.compile_sdk = '37'; + }, + (value) => { + value.version = '999.0.0'; + }, + (value) => { + value.catalog.libraries['kotlin-stdlib'].version = '1.0.0'; + }, + (value) => { + value.gradle += '\ncompileSdk = 36\n'; + }, + (value) => { + value.gradle = value.gradle.replace('minSdk = 24', 'minSdk = 99'); + }, + (value) => { + value.pluginGradle = value.pluginGradle.replace( + 'name.set("MIT License")', + 'name.set("${computedLicense}")', + ); + }, + (value) => { + value.catalog.libraries.jna.version.ref = 'not-declared'; + }, + ]; + for (const change of changes) { + const source = inputs(); + change(source); + expect(() => kotlinSdkMetadata(source)).toThrow(); + } +}); diff --git a/build_defs/languages/jvm/kotlin-sdk-repository.bzl b/build_defs/languages/jvm/kotlin-sdk-repository.bzl new file mode 100644 index 000000000..be9070d17 --- /dev/null +++ b/build_defs/languages/jvm/kotlin-sdk-repository.bzl @@ -0,0 +1,28 @@ +"""Bounded import of existing conventional Kotlin construction defaults.""" + +def _kotlin_sdk_metadata_impl(ctx): + sources = [ctx.attr.catalog, ctx.attr.gradle, ctx.attr.plugin_gradle, ctx.attr.properties, ctx.attr.version, ctx.attr.android_sdk] + for source in sources + [ctx.attr.converter, ctx.attr.pom_helper]: + ctx.read(source) + ctx.watch(ctx.path(ctx.attr.bun)) + command = [str(ctx.path(ctx.attr.bun)), str(ctx.path(ctx.attr.converter))] + [str(ctx.path(source)) for source in sources] + [str(ctx.path("metadata.bzl"))] + result = ctx.execute(command, timeout = 60) + if result.return_code: + fail("Kotlin SDK conventional import failed:\n" + result.stdout + result.stderr) + ctx.file("BUILD.bazel", "exports_files([\"metadata.bzl\", \"lint.versions.toml\"], visibility=[\"//visibility:public\"])\n") + return ctx.repo_metadata(reproducible = True) + +kotlin_sdk_metadata_repository = repository_rule( + implementation = _kotlin_sdk_metadata_impl, + attrs = { + "bun": attr.label(default = Label("@bun_runtime//:bun"), allow_single_file = True), + "converter": attr.label(default = Label("//build_defs/languages/jvm:kotlin-sdk-metadata.mts"), allow_single_file = True), + "pom_helper": attr.label(default = Label("//build_defs/languages/jvm:maven-pom.mts"), allow_single_file = True), + "catalog": attr.label(default = Label("//src/native/sdks/kotlin:gradle/libs.versions.toml"), allow_single_file = True), + "gradle": attr.label(default = Label("//src/native/sdks/kotlin:oliphaunt/build.gradle.kts"), allow_single_file = True), + "plugin_gradle": attr.label(default = Label("//src/native/sdks/kotlin/oliphaunt-android-gradle-plugin:build.gradle.kts"), allow_single_file = True), + "properties": attr.label(default = Label("//src/native/sdks/kotlin:gradle.properties"), allow_single_file = True), + "version": attr.label(default = Label("//src/native/sdks/kotlin:VERSION"), allow_single_file = True), + "android_sdk": attr.label(default = Label("//tools/dev:android-sdk.toml"), allow_single_file = True), + }, +) diff --git a/build_defs/languages/jvm/kotlin.bzl b/build_defs/languages/jvm/kotlin.bzl new file mode 100644 index 000000000..e43e3f850 --- /dev/null +++ b/build_defs/languages/jvm/kotlin.bzl @@ -0,0 +1,17 @@ +"""Maintained Kotlin compiler options from the conventional SDK version catalog.""" + +load("@oliphaunt_kotlin_manifest//:metadata.bzl", "KOTLIN") +load("@rules_kotlin//kotlin:core.bzl", "define_kt_toolchain", "kt_javac_options") +load("@rules_kotlin//src/main/starlark/core/repositories:versions.bzl", "versions") + +def kotlin_sdk_toolchain(name): + if versions.KOTLIN_CURRENT_COMPILER_RELEASE.version != KOTLIN["compilerVersion"]: + fail("Maintained Kotlin compiler must match the conventional libs.versions.toml pin") + kt_javac_options(name = name + "_javac", release = KOTLIN["jvmTarget"]) + define_kt_toolchain( + name = name, + language_version = KOTLIN["languageVersion"], + api_version = KOTLIN["languageVersion"], + jvm_target = KOTLIN["jvmTarget"], + javac_options = ":" + name + "_javac", + ) diff --git a/build_defs/languages/jvm/ktlint.mts b/build_defs/languages/jvm/ktlint.mts new file mode 100644 index 000000000..022c1f05c --- /dev/null +++ b/build_defs/languages/jvm/ktlint.mts @@ -0,0 +1,97 @@ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { copyFileSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; + +type Format = { name: 'kotlin' | 'kotlinGradle'; editorConfig: Record }; +type Source = { format: string; member: string; file: string }; + +export function stageKotlinFormatSources(root: string, formats: Format[], sources: Source[]) { + assert(sources.length, 'Kotlin formatter must check declared authored sources'); + assert.equal( + formats + .map(({ name }) => name) + .sort() + .join(','), + 'kotlin,kotlinGradle', + 'Kotlin formatter requires its two conventional source scopes', + ); + const config = ['root = true']; + for (const format of formats) { + config.push('', format.name === 'kotlin' ? '[*.kt]' : '[*.kts]'); + for (const [key, value] of Object.entries(format.editorConfig)) { + assert(/^[A-Za-z0-9_.-]+$/u.test(key) && /^[A-Za-z0-9_.-]+$/u.test(value)); + config.push(`${key} = ${value}`); + } + } + // A private root prevents ambient home/ancestor .editorconfig from changing the check. + writeFileSync(path.join(root, '.editorconfig'), `${config.join('\n')}\n`); + const seen = new Set(); + for (const source of sources) { + assert( + formats.some(({ name }) => name === source.format), + 'Unknown Kotlin formatter scope', + ); + assert( + source.member && + !/^[A-Za-z]:/u.test(source.member) && + !/[\\\u0000-\u001f*?{}[\]!]/u.test(source.member) && + !path.posix.isAbsolute(source.member) && + source.member.split('/').every((part) => part && part !== '.' && part !== '..') && + source.member.endsWith(source.format === 'kotlin' ? '.kt' : '.gradle.kts'), + 'Kotlin formatter requires safe explicit source members', + ); + assert(!seen.has(source.member), `Duplicate Kotlin formatter source ${source.member}`); + seen.add(source.member); + const destination = path.join(root, source.member); + mkdirSync(path.dirname(destination), { recursive: true }); + copyFileSync(source.file, destination); + } + return [...seen]; +} + +if (import.meta.main) { + const [java, config, ...arguments_] = process.argv.slice(2); + assert(java && config, 'Kotlin formatter requires declared Java and conventional configuration'); + const jars: string[] = []; + const sources: Source[] = []; + for (let index = 0; index < arguments_.length; ) { + const kind = arguments_[index++]; + if (kind === 'jar') { + const file = arguments_[index++]; + assert(file, 'Kotlin formatter requires declared CLI JARs'); + jars.push(file); + } else { + assert.equal(kind, 'source', 'Kotlin formatter accepts declared JARs and source files'); + const [format, member, file] = arguments_.slice(index, index + 3); + assert(format && member && file, 'Incomplete Kotlin formatter source declaration'); + index += 3; + sources.push({ format, member, file }); + } + } + assert(jars.length, 'Kotlin formatter requires its declared CLI classpath'); + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-ktlint-')); + try { + const members = stageKotlinFormatSources(root, JSON.parse(config), sources); + const result = spawnSync( + java, + [ + '-Xmx512m', + '-XX:ActiveProcessorCount=2', + `-Duser.home=${root}`, + '-Dfile.encoding=UTF-8', + '-cp', + jars.join(path.delimiter), + 'com.pinterest.ktlint.Main', + '--relative', + ...members, + ], + { cwd: root, stdio: 'inherit' }, + ); + if (result.error) throw result.error; + assert.equal(result.status, 0, 'Conventional Kotlin source formatting failed'); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} diff --git a/build_defs/languages/jvm/ktlint.test.mts b/build_defs/languages/jvm/ktlint.test.mts new file mode 100644 index 000000000..3891a7598 --- /dev/null +++ b/build_defs/languages/jvm/ktlint.test.mts @@ -0,0 +1,41 @@ +import { expect, test } from 'bun:test'; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { stageKotlinFormatSources } from './ktlint.mts'; + +const formats = [ + { name: 'kotlin' as const, editorConfig: { 'ktlint_standard_property-naming': 'disabled' } }, + { name: 'kotlinGradle' as const, editorConfig: {} }, +]; + +test('stages only declared sources and preserves the Kotlin-only Spotless editorconfig override', () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-ktlint-test-')); + try { + const file = path.join(root, 'input.kt'); + writeFileSync(file, 'val fixture = 1\n'); + expect( + stageKotlinFormatSources(root, formats, [ + { format: 'kotlin', member: 'src/Fixture.kt', file }, + { format: 'kotlinGradle', member: 'build.gradle.kts', file }, + ]), + ).toEqual(['src/Fixture.kt', 'build.gradle.kts']); + expect(readFileSync(path.join(root, 'src/Fixture.kt'), 'utf8')).toBe('val fixture = 1\n'); + expect(readFileSync(path.join(root, '.editorconfig'), 'utf8')).toBe( + 'root = true\n\n[*.kt]\nktlint_standard_property-naming = disabled\n\n[*.kts]\n', + ); + for (const member of ['../outside.kt', '/outside.kt', 'src\\Outside.kt', 'src/*.kt']) + expect(() => + stageKotlinFormatSources(root, formats, [{ format: 'kotlin', member, file }]), + ).toThrow('safe explicit source'); + expect(() => stageKotlinFormatSources(root, formats, [])).toThrow('declared authored sources'); + expect(() => + stageKotlinFormatSources(root, formats, [ + { format: 'kotlin', member: 'Fixture.kt', file }, + { format: 'kotlin', member: 'Fixture.kt', file }, + ]), + ).toThrow('Duplicate'); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/build_defs/languages/jvm/lint_maven_install.json b/build_defs/languages/jvm/lint_maven_install.json new file mode 100644 index 000000000..cc376b0c1 --- /dev/null +++ b/build_defs/languages/jvm/lint_maven_install.json @@ -0,0 +1,3652 @@ +{ + "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL", + "__INPUT_ARTIFACTS_HASH": { + "com.android.tools.lint:lint-gradle": -1104953427, + "repositories": 752543690 + }, + "__RESOLVED_ARTIFACTS_HASH": { + "com.android.tools.analytics-library:protos": -2078783876, + "com.android.tools.analytics-library:shared": 481891594, + "com.android.tools.analytics-library:tracker": 353292039, + "com.android.tools.build:aapt2-proto": -1284214028, + "com.android.tools.build:builder-model": -748788292, + "com.android.tools.build:manifest-merger": -462556092, + "com.android.tools.ddms:ddmlib": -2103638176, + "com.android.tools.external.com-intellij:intellij-core": 2140720964, + "com.android.tools.external.com-intellij:kotlin-compiler": 1097967862, + "com.android.tools.external.org-jetbrains:uast": 1664334624, + "com.android.tools.layoutlib:layoutlib-api": -470291451, + "com.android.tools.lint:lint": -233952471, + "com.android.tools.lint:lint-api": 2028650264, + "com.android.tools.lint:lint-checks": 1802329701, + "com.android.tools.lint:lint-gradle": 2067726837, + "com.android.tools.lint:lint-model": 1862620855, + "com.android.tools.lint:lint-typedef-remover": 2048093975, + "com.android.tools:annotations": 907750985, + "com.android.tools:common": 1897244822, + "com.android.tools:dvlib": -1233726827, + "com.android.tools:play-sdk-proto": -1817558107, + "com.android.tools:repository": -2008709692, + "com.android.tools:sdk-common": 283574033, + "com.android.tools:sdklib": 1468315970, + "com.google.code.findbugs:jsr305": -713370090, + "com.google.code.gson:gson": 840167180, + "com.google.errorprone:error_prone_annotations": 287874225, + "com.google.guava:failureaccess": -1298943386, + "com.google.guava:guava": 1328149913, + "com.google.guava:listenablefuture": 1217152504, + "com.google.j2objc:j2objc-annotations": 1534135524, + "com.google.jimfs:jimfs": -952452444, + "com.google.protobuf:protobuf-java": -657294294, + "com.sun.activation:javax.activation": 552692369, + "com.sun.istack:istack-commons-runtime": 1416570933, + "com.sun.xml.fastinfoset:FastInfoset": -487074561, + "commons-codec:commons-codec": -1682714639, + "commons-io:commons-io": -1998585292, + "commons-logging:commons-logging": 1716392336, + "jakarta.activation:jakarta.activation-api": -937702517, + "jakarta.xml.bind:jakarta.xml.bind-api": -1934422838, + "javax.inject:javax.inject": -1077928230, + "net.java.dev.jna:jna": 1795159127, + "net.java.dev.jna:jna-platform": 386378207, + "net.sf.kxml:kxml2": 1479229475, + "org.apache.commons:commons-compress": 720316149, + "org.apache.httpcomponents:httpclient": -150445942, + "org.apache.httpcomponents:httpcore": 1398853054, + "org.apache.httpcomponents:httpmime": -915852415, + "org.bouncycastle:bcpkix-jdk18on": 345605474, + "org.bouncycastle:bcprov-jdk18on": -2091979459, + "org.bouncycastle:bcutil-jdk18on": 1704079400, + "org.checkerframework:checker-qual": -1038930962, + "org.codehaus.groovy:groovy": -369266001, + "org.glassfish.jaxb:jaxb-runtime": 327974660, + "org.glassfish.jaxb:txw2": 627537583, + "org.jetbrains.kotlin:kotlin-reflect": -1162860086, + "org.jetbrains.kotlin:kotlin-stdlib": 1382915809, + "org.jetbrains.kotlin:kotlin-stdlib-jdk7": -1975903762, + "org.jetbrains.kotlin:kotlin-stdlib-jdk8": -1294430934, + "org.jetbrains:annotations": 1212182747, + "org.jvnet.staxex:stax-ex": -524827021, + "org.ow2.asm:asm": 385487560, + "org.ow2.asm:asm-analysis": 308870873, + "org.ow2.asm:asm-commons": -1895044571, + "org.ow2.asm:asm-tree": -2004866378 + }, + "artifacts": { + "com.android.tools.analytics-library:protos": { + "shasums": { + "jar": "2e7c74d3a54257e4e12c39b8779cc7ae30dbe748a9c12c364835c5892f92a7fc" + }, + "version": "31.11.1" + }, + "com.android.tools.analytics-library:shared": { + "shasums": { + "jar": "306355bafa0727ab1bffcab94ba4b607f8ce7b953c9ba20d58d72b325c1a8ce7" + }, + "version": "31.11.1" + }, + "com.android.tools.analytics-library:tracker": { + "shasums": { + "jar": "a0e2fa1bcd6825bc1c3954e0a206d88083f46bb161c650fe7c8980eb13afc082" + }, + "version": "31.11.1" + }, + "com.android.tools.build:aapt2-proto": { + "shasums": { + "jar": "9fcf2e5ac206f630449184498814246d82af61bda39c484799cccb6761cf29e0" + }, + "version": "8.11.1-12782657" + }, + "com.android.tools.build:builder-model": { + "shasums": { + "jar": "2dac329a5c2ca619984c27bc0a18b16f556ffd5b10ac5b5095e86ce28a245807" + }, + "version": "8.11.1" + }, + "com.android.tools.build:manifest-merger": { + "shasums": { + "jar": "129abb829aa931c23d8906b590c54d8dc8c046148bc3afb651917d69b7113fc8" + }, + "version": "31.11.1" + }, + "com.android.tools.ddms:ddmlib": { + "shasums": { + "jar": "839957f961100713ea0eed628a8684cc39aa479631c36249793e6df7e0cd63d8" + }, + "version": "31.11.1" + }, + "com.android.tools.external.com-intellij:intellij-core": { + "shasums": { + "jar": "36815dd436cb9c02cb255e43e9c971422d10c33e6fd9c4fe1e48c71e92b180c6" + }, + "version": "31.11.1" + }, + "com.android.tools.external.com-intellij:kotlin-compiler": { + "shasums": { + "jar": "b24d171f6ccaeaba526d7de6d9f94149ee12bad9a48098c558d1f47dfd3e0bb5" + }, + "version": "31.11.1" + }, + "com.android.tools.external.org-jetbrains:uast": { + "shasums": { + "jar": "97ba20c9eaf66f5dd00c787b817b39992838155f96065e6629d08e18633ff55f" + }, + "version": "31.11.1" + }, + "com.android.tools.layoutlib:layoutlib-api": { + "shasums": { + "jar": "d06bc650247632a4a4e6596b87312019f45e900267c5476c47a5bfa6e3fd3132" + }, + "version": "31.11.1" + }, + "com.android.tools.lint:lint": { + "shasums": { + "jar": "5453d4519d7cb1fe729fe353b11ca9c14b4573baac4b5a191708f8721e7e303b" + }, + "version": "31.11.1" + }, + "com.android.tools.lint:lint-api": { + "shasums": { + "jar": "bce7f154e8dc63d23684e997148350d4ee260bb0f55f2d17842a618ff813b19a" + }, + "version": "31.11.1" + }, + "com.android.tools.lint:lint-checks": { + "shasums": { + "jar": "268dfa6f53da439480f18f79bf881b9183ea2ea8a062819076d138210ddfa953" + }, + "version": "31.11.1" + }, + "com.android.tools.lint:lint-gradle": { + "shasums": { + "jar": "a42b6a41c436d90ca31a13d67afba1157b157efc892a7496f67432bf8a831cbd" + }, + "version": "31.11.1" + }, + "com.android.tools.lint:lint-model": { + "shasums": { + "jar": "84364a9bf0f234541d668d42318221516fd3a7273425bee2ee1bb3674c8e7723" + }, + "version": "31.11.1" + }, + "com.android.tools.lint:lint-typedef-remover": { + "shasums": { + "jar": "4a3ba3babfd79e6fc67bcef647fb4ecfeaf59b481b108f7c2eba4d1c5c6dea8e" + }, + "version": "31.11.1" + }, + "com.android.tools:annotations": { + "shasums": { + "jar": "3b4bb9620c17d19e5bd91ac1988080553573b4c3b739fdd92416f42f2daf3e78" + }, + "version": "31.11.1" + }, + "com.android.tools:common": { + "shasums": { + "jar": "2f2b7f1a122b63ac3e04576c90043a81eb6d263cc6bad46e2c32c2ddca6b5bd3" + }, + "version": "31.11.1" + }, + "com.android.tools:dvlib": { + "shasums": { + "jar": "e3cf3fdc947788dee8d5baa76cb72a66571174bc4741edf0e3bab97a7ca90e1b" + }, + "version": "31.11.1" + }, + "com.android.tools:play-sdk-proto": { + "shasums": { + "jar": "c6fc15a5c203064cfd2c8a176fdeac72ae0a2d743ec47a2e66a0238d8d870b6b" + }, + "version": "31.11.1" + }, + "com.android.tools:repository": { + "shasums": { + "jar": "095becb618937d1d2a4d77a921d70563ec9ffda05d62ec1aff6a9bae701d39da" + }, + "version": "31.11.1" + }, + "com.android.tools:sdk-common": { + "shasums": { + "jar": "46f4645222d393c1131be1e66fdc0be0da4d7f2ab3c68a728308367f99f3bdf2" + }, + "version": "31.11.1" + }, + "com.android.tools:sdklib": { + "shasums": { + "jar": "b9b62adb6f6369800b07815b41ca5f4532c20d2e07e407167f9522d6acbc8cfb" + }, + "version": "31.11.1" + }, + "com.google.code.findbugs:jsr305": { + "shasums": { + "jar": "766ad2a0783f2687962c8ad74ceecc38a28b9f72a2d085ee438b7813e928d0c7" + }, + "version": "3.0.2" + }, + "com.google.code.gson:gson": { + "shasums": { + "jar": "57928d6e5a6edeb2abd3770a8f95ba44dce45f3b23b7a9dc2b309c581552a78b" + }, + "version": "2.11.0" + }, + "com.google.errorprone:error_prone_annotations": { + "shasums": { + "jar": "f3fc8a3a0a4020706a373b00e7f57c2512dd26d1f83d28c7d38768f8682b231e" + }, + "version": "2.28.0" + }, + "com.google.guava:failureaccess": { + "shasums": { + "jar": "8a8f81cf9b359e3f6dfa691a1e776985c061ef2f223c9b2c80753e1b458e8064" + }, + "version": "1.0.2" + }, + "com.google.guava:guava": { + "shasums": { + "jar": "4bf0e2c5af8e4525c96e8fde17a4f7307f97f8478f11c4c8e35a0e3298ae4e90" + }, + "version": "33.3.1-jre" + }, + "com.google.guava:listenablefuture": { + "shasums": { + "jar": "b372a037d4230aa57fbeffdef30fd6123f9c0c2db85d0aced00c91b974f33f99" + }, + "version": "9999.0-empty-to-avoid-conflict-with-guava" + }, + "com.google.j2objc:j2objc-annotations": { + "shasums": { + "jar": "88241573467ddca44ffd4d74aa04c2bbfd11bf7c17e0c342c94c9de7a70a7c64" + }, + "version": "3.0.0" + }, + "com.google.jimfs:jimfs": { + "shasums": { + "jar": "c4828e28d7c0a930af9387510b3bada7daa5c04d7c25a75c7b8b081f1c257ddd" + }, + "version": "1.1" + }, + "com.google.protobuf:protobuf-java": { + "shasums": { + "jar": "8540247fad9e06baefa8fb45eb313802d019f485f14300e0f9d6b556ed88e753" + }, + "version": "3.25.5" + }, + "com.sun.activation:javax.activation": { + "shasums": { + "jar": "993302b16cd7056f21e779cc577d175a810bb4900ef73cd8fbf2b50f928ba9ce" + }, + "version": "1.2.0" + }, + "com.sun.istack:istack-commons-runtime": { + "shasums": { + "jar": "4ffabb06be454a05e4398e20c77fa2b6308d4b88dfbef7ca30a76b5b7d5505ef" + }, + "version": "3.0.8" + }, + "com.sun.xml.fastinfoset:FastInfoset": { + "shasums": { + "jar": "056f3a1e144409f21ed16afc26805f58e9a21f3fce1543c42d400719d250c511" + }, + "version": "1.2.16" + }, + "commons-codec:commons-codec": { + "shasums": { + "jar": "4241dfa94e711d435f29a4604a3e2de5c4aa3c165e23bd066be6fc1fc4309569" + }, + "version": "1.10" + }, + "commons-io:commons-io": { + "shasums": { + "jar": "f41f7baacd716896447ace9758621f62c1c6b0a91d89acee488da26fc477c84f" + }, + "version": "2.16.1" + }, + "commons-logging:commons-logging": { + "shasums": { + "jar": "daddea1ea0be0f56978ab3006b8ac92834afeefbd9b7e4e6316fca57df0fa636" + }, + "version": "1.2" + }, + "jakarta.activation:jakarta.activation-api": { + "shasums": { + "jar": "8b0a0f52fa8b05c5431921a063ed866efaa41dadf2e3a7ee3e1961f2b0d9645b" + }, + "version": "1.2.1" + }, + "jakarta.xml.bind:jakarta.xml.bind-api": { + "shasums": { + "jar": "69156304079bdeed9fc0ae3b39389f19b3cc4ba4443bc80508995394ead742ea" + }, + "version": "2.3.2" + }, + "javax.inject:javax.inject": { + "shasums": { + "jar": "91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff" + }, + "version": "1" + }, + "net.java.dev.jna:jna": { + "shasums": { + "jar": "5557e235a8aa2f9766d5dc609d67948f2a8832c2d796cea9ef1d6cbe0b3b7eaf" + }, + "version": "5.6.0" + }, + "net.java.dev.jna:jna-platform": { + "shasums": { + "jar": "9ecea8bf2b1b39963939d18b70464eef60c508fed8820f9dcaba0c35518eabf7" + }, + "version": "5.6.0" + }, + "net.sf.kxml:kxml2": { + "shasums": { + "jar": "f264dd9f79a1fde10ce5ecc53221eff24be4c9331c830b7d52f2f08a7b633de2" + }, + "version": "2.3.0" + }, + "org.apache.commons:commons-compress": { + "shasums": { + "jar": "6aecfd5459728a595601cfa07258d131972ffc39b492eb48bdd596577a2f244a" + }, + "version": "1.21" + }, + "org.apache.httpcomponents:httpclient": { + "shasums": { + "jar": "c03f813195e7a80e3608d0ddd8da80b21696a4c92a6a2298865bf149071551c7" + }, + "version": "4.5.6" + }, + "org.apache.httpcomponents:httpcore": { + "shasums": { + "jar": "6c9b3dd142a09dc468e23ad39aad6f75a0f2b85125104469f026e52a474e464f" + }, + "version": "4.4.16" + }, + "org.apache.httpcomponents:httpmime": { + "shasums": { + "jar": "0b2b1102c18d3c7e05a77214b9b7501a6f6056174ae5604e0e256776eda7553e" + }, + "version": "4.5.6" + }, + "org.bouncycastle:bcpkix-jdk18on": { + "shasums": { + "jar": "3639a24ddf9ba4b7eba0659b44770e91eba816421888e571f285aadefe532cd6" + }, + "version": "1.79" + }, + "org.bouncycastle:bcprov-jdk18on": { + "shasums": { + "jar": "0d81ecc3124536b539bce9aa3fe9621b7f84c9cee371b635a5b31c78b79ab1da" + }, + "version": "1.79" + }, + "org.bouncycastle:bcutil-jdk18on": { + "shasums": { + "jar": "c70b88ada58938cbc2f005d40329054078bcfa1149e6ffc03e9242eb6ab21836" + }, + "version": "1.79" + }, + "org.checkerframework:checker-qual": { + "shasums": { + "jar": "3fbc2e98f05854c3df16df9abaa955b91b15b3ecac33623208ed6424640ef0f6" + }, + "version": "3.43.0" + }, + "org.codehaus.groovy:groovy": { + "shasums": { + "jar": "c92c92c4b9b183f9981ba7399f36592e5e3ad6f4cdac7101b5a22cc17998d13f" + }, + "version": "3.0.22" + }, + "org.glassfish.jaxb:jaxb-runtime": { + "shasums": { + "jar": "e6e0a1e89fb6ff786279e6a0082d5cef52dc2ebe67053d041800737652b4fd1b" + }, + "version": "2.3.2" + }, + "org.glassfish.jaxb:txw2": { + "shasums": { + "jar": "4a6a9f483388d461b81aa9a28c685b8b74c0597993bf1884b04eddbca95f48fe" + }, + "version": "2.3.2" + }, + "org.jetbrains.kotlin:kotlin-reflect": { + "shasums": { + "jar": "419778f2b7a826bad6ee2ca1e4bdebe639ab306d2904fa3ef2a308ecfaab3811" + }, + "version": "2.1.20" + }, + "org.jetbrains.kotlin:kotlin-stdlib": { + "shasums": { + "jar": "1bcc74e8ce84e2c25eaafde10f1248349cce3062b6e36978cbeec610db1e930a" + }, + "version": "2.1.20" + }, + "org.jetbrains.kotlin:kotlin-stdlib-jdk7": { + "shasums": { + "jar": "5343bf795783932e5fa538b0bca05af810bb07213edb9baa770c784068f57867" + }, + "version": "2.1.20" + }, + "org.jetbrains.kotlin:kotlin-stdlib-jdk8": { + "shasums": { + "jar": "ed22217b5dc0940a068d8be9440bbe2f7f9f51c466cdd1185e2385cdec19f238" + }, + "version": "2.1.20" + }, + "org.jetbrains:annotations": { + "shasums": { + "jar": "7b0f19724082cbfcbc66e5abea2b9bc92cf08a1ea11e191933ed43801eb3cd05" + }, + "version": "23.0.0" + }, + "org.jvnet.staxex:stax-ex": { + "shasums": { + "jar": "20522549056e9e50aa35ef0b445a2e47a53d06be0b0a9467d704e2483ffb049a" + }, + "version": "1.8.1" + }, + "org.ow2.asm:asm": { + "shasums": { + "jar": "8cadd43ac5eb6d09de05faecca38b917a040bb9139c7edeb4cc81c740b713281" + }, + "version": "9.7.1" + }, + "org.ow2.asm:asm-analysis": { + "shasums": { + "jar": "85b29371884ba31bb76edf22323c2c24e172c3267a67152eba3d1ccc2e041ef2" + }, + "version": "9.7.1" + }, + "org.ow2.asm:asm-commons": { + "shasums": { + "jar": "9a579b54d292ad9be171d4313fd4739c635592c2b5ac3a459bbd1049cddec6a0" + }, + "version": "9.7.1" + }, + "org.ow2.asm:asm-tree": { + "shasums": { + "jar": "9929881f59eb6b840e86d54570c77b59ce721d104e6dfd7a40978991c2d3b41f" + }, + "version": "9.7.1" + } + }, + "dependencies": { + "com.android.tools.analytics-library:protos": [ + "com.google.protobuf:protobuf-java" + ], + "com.android.tools.analytics-library:shared": [ + "com.android.tools.analytics-library:protos", + "com.android.tools:annotations", + "com.android.tools:common", + "com.google.code.gson:gson", + "com.google.guava:guava", + "net.java.dev.jna:jna-platform", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "com.android.tools.analytics-library:tracker": [ + "com.android.tools.analytics-library:protos", + "com.android.tools.analytics-library:shared", + "com.android.tools:annotations", + "com.android.tools:common", + "com.google.guava:guava", + "com.google.protobuf:protobuf-java", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "com.android.tools.build:aapt2-proto": [ + "com.google.protobuf:protobuf-java" + ], + "com.android.tools.build:builder-model": [ + "com.android.tools:annotations", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.android.tools.build:manifest-merger": [ + "com.android.tools:common", + "com.android.tools:sdk-common", + "com.android.tools:sdklib", + "com.google.code.gson:gson", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.android.tools.ddms:ddmlib": [ + "com.android.tools:common", + "com.google.protobuf:protobuf-java", + "net.sf.kxml:kxml2", + "org.jetbrains:annotations" + ], + "com.android.tools.layoutlib:layoutlib-api": [ + "com.android.tools:annotations", + "com.android.tools:common", + "net.sf.kxml:kxml2", + "org.jetbrains:annotations" + ], + "com.android.tools.lint:lint": [ + "com.android.tools.analytics-library:protos", + "com.android.tools.analytics-library:shared", + "com.android.tools.analytics-library:tracker", + "com.android.tools.build:manifest-merger", + "com.android.tools.external.com-intellij:intellij-core", + "com.android.tools.external.com-intellij:kotlin-compiler", + "com.android.tools.external.org-jetbrains:uast", + "com.android.tools.layoutlib:layoutlib-api", + "com.android.tools.lint:lint-api", + "com.android.tools.lint:lint-checks", + "com.android.tools:common", + "com.android.tools:sdk-common", + "com.android.tools:sdklib", + "com.google.guava:guava", + "org.jetbrains.kotlin:kotlin-reflect", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "com.android.tools.lint:lint-api": [ + "com.android.tools.build:builder-model", + "com.android.tools.build:manifest-merger", + "com.android.tools.external.com-intellij:intellij-core", + "com.android.tools.external.com-intellij:kotlin-compiler", + "com.android.tools.external.org-jetbrains:uast", + "com.android.tools.layoutlib:layoutlib-api", + "com.android.tools.lint:lint-model", + "com.android.tools:common", + "com.android.tools:sdk-common", + "com.android.tools:sdklib", + "com.google.guava:guava", + "commons-io:commons-io", + "net.sf.kxml:kxml2", + "org.jetbrains.kotlin:kotlin-reflect", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8", + "org.ow2.asm:asm", + "org.ow2.asm:asm-commons", + "org.ow2.asm:asm-tree" + ], + "com.android.tools.lint:lint-checks": [ + "com.android.tools.external.com-intellij:intellij-core", + "com.android.tools.external.com-intellij:kotlin-compiler", + "com.android.tools.external.org-jetbrains:uast", + "com.android.tools.layoutlib:layoutlib-api", + "com.android.tools.lint:lint-api", + "com.android.tools:common", + "com.android.tools:play-sdk-proto", + "com.android.tools:sdk-common", + "com.android.tools:sdklib", + "com.google.code.gson:gson", + "com.google.guava:guava", + "com.google.protobuf:protobuf-java", + "net.sf.kxml:kxml2", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8", + "org.ow2.asm:asm-analysis" + ], + "com.android.tools.lint:lint-gradle": [ + "com.android.tools.external.com-intellij:intellij-core", + "com.android.tools.external.com-intellij:kotlin-compiler", + "com.android.tools.external.org-jetbrains:uast", + "com.android.tools.lint:lint", + "com.android.tools.lint:lint-typedef-remover", + "com.android.tools:common", + "org.codehaus.groovy:groovy" + ], + "com.android.tools.lint:lint-model": [ + "com.android.tools.build:builder-model", + "com.android.tools:common", + "com.android.tools:repository", + "com.android.tools:sdk-common", + "com.android.tools:sdklib", + "net.sf.kxml:kxml2", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "com.android.tools.lint:lint-typedef-remover": [ + "com.android.tools:annotations", + "com.google.guava:guava", + "org.ow2.asm:asm" + ], + "com.android.tools:common": [ + "com.android.tools:annotations", + "com.google.guava:guava", + "net.java.dev.jna:jna-platform", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "com.android.tools:dvlib": [ + "com.android.tools:common" + ], + "com.android.tools:play-sdk-proto": [ + "com.google.protobuf:protobuf-java" + ], + "com.android.tools:repository": [ + "com.android.tools.analytics-library:shared", + "com.android.tools:common", + "com.google.jimfs:jimfs", + "com.sun.activation:javax.activation", + "org.apache.commons:commons-compress", + "org.glassfish.jaxb:jaxb-runtime", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "com.android.tools:sdk-common": [ + "com.android.tools.analytics-library:shared", + "com.android.tools.build:aapt2-proto", + "com.android.tools.ddms:ddmlib", + "com.android.tools.layoutlib:layoutlib-api", + "com.android.tools:common", + "com.android.tools:sdklib", + "com.google.code.gson:gson", + "com.google.guava:guava", + "com.google.protobuf:protobuf-java", + "javax.inject:javax.inject", + "net.sf.kxml:kxml2", + "org.apache.commons:commons-compress", + "org.bouncycastle:bcpkix-jdk18on", + "org.bouncycastle:bcprov-jdk18on", + "org.glassfish.jaxb:jaxb-runtime", + "org.jetbrains.kotlin:kotlin-reflect", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + ], + "com.android.tools:sdklib": [ + "com.android.tools.layoutlib:layoutlib-api", + "com.android.tools:common", + "com.android.tools:dvlib", + "com.android.tools:repository", + "com.google.code.gson:gson", + "org.apache.commons:commons-compress", + "org.apache.httpcomponents:httpcore", + "org.apache.httpcomponents:httpmime", + "org.glassfish.jaxb:jaxb-runtime" + ], + "com.google.code.gson:gson": [ + "com.google.errorprone:error_prone_annotations" + ], + "com.google.guava:guava": [ + "com.google.code.findbugs:jsr305", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:failureaccess", + "com.google.guava:listenablefuture", + "com.google.j2objc:j2objc-annotations", + "org.checkerframework:checker-qual" + ], + "com.google.jimfs:jimfs": [ + "com.google.guava:guava" + ], + "com.sun.istack:istack-commons-runtime": [ + "jakarta.activation:jakarta.activation-api" + ], + "jakarta.xml.bind:jakarta.xml.bind-api": [ + "jakarta.activation:jakarta.activation-api" + ], + "net.java.dev.jna:jna-platform": [ + "net.java.dev.jna:jna" + ], + "org.apache.httpcomponents:httpclient": [ + "commons-codec:commons-codec", + "commons-logging:commons-logging", + "org.apache.httpcomponents:httpcore" + ], + "org.apache.httpcomponents:httpmime": [ + "org.apache.httpcomponents:httpclient" + ], + "org.bouncycastle:bcpkix-jdk18on": [ + "org.bouncycastle:bcprov-jdk18on", + "org.bouncycastle:bcutil-jdk18on" + ], + "org.bouncycastle:bcutil-jdk18on": [ + "org.bouncycastle:bcprov-jdk18on" + ], + "org.glassfish.jaxb:jaxb-runtime": [ + "com.sun.istack:istack-commons-runtime", + "com.sun.xml.fastinfoset:FastInfoset", + "jakarta.activation:jakarta.activation-api", + "jakarta.xml.bind:jakarta.xml.bind-api", + "org.glassfish.jaxb:txw2", + "org.jvnet.staxex:stax-ex" + ], + "org.jetbrains.kotlin:kotlin-reflect": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "org.jetbrains.kotlin:kotlin-stdlib": [ + "org.jetbrains:annotations" + ], + "org.jetbrains.kotlin:kotlin-stdlib-jdk7": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "org.jetbrains.kotlin:kotlin-stdlib-jdk8": [ + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlin:kotlin-stdlib-jdk7" + ], + "org.jvnet.staxex:stax-ex": [ + "jakarta.activation:jakarta.activation-api", + "jakarta.xml.bind:jakarta.xml.bind-api" + ], + "org.ow2.asm:asm-analysis": [ + "org.ow2.asm:asm-tree" + ], + "org.ow2.asm:asm-commons": [ + "org.ow2.asm:asm", + "org.ow2.asm:asm-tree" + ], + "org.ow2.asm:asm-tree": [ + "org.ow2.asm:asm" + ] + }, + "packages": { + "com.android.tools.analytics-library:protos": [ + "com.android.tools.build.gradle.internal.profile", + "com.google.wireless.android.play.playlog.proto", + "com.google.wireless.android.sdk.stats" + ], + "com.android.tools.analytics-library:shared": [ + "com.android.tools.analytics" + ], + "com.android.tools.analytics-library:tracker": [ + "com.android.tools.analytics" + ], + "com.android.tools.build:aapt2-proto": [ + "android.aapt.pb.internal", + "com.android.aapt" + ], + "com.android.tools.build:builder-model": [ + "com.android.build", + "com.android.builder.model", + "com.android.builder.model.level2", + "com.android.builder.model.v2", + "com.android.builder.model.v2.dsl", + "com.android.builder.model.v2.ide", + "com.android.builder.model.v2.models", + "com.android.builder.model.v2.models.ndk" + ], + "com.android.tools.build:manifest-merger": [ + "com.android.manifmerger" + ], + "com.android.tools.ddms:ddmlib": [ + "com.android.commands.am", + "com.android.ddmlib", + "com.android.ddmlib.clientmanager", + "com.android.ddmlib.idevicemanager", + "com.android.ddmlib.internal", + "com.android.ddmlib.internal.commands", + "com.android.ddmlib.internal.jdwp", + "com.android.ddmlib.internal.jdwp.chunkhandler", + "com.android.ddmlib.internal.jdwp.interceptor", + "com.android.ddmlib.jdwp", + "com.android.ddmlib.jdwp.packets", + "com.android.ddmlib.log", + "com.android.ddmlib.logcat", + "com.android.ddmlib.testrunner", + "com.android.ddmlib.utils", + "com.android.incfs.install", + "com.android.incfs.install.adb.ddmlib", + "com.android.server.adb.protos" + ], + "com.android.tools.external.com-intellij:intellij-core": [ + "_COROUTINE", + "com.esotericsoftware.kryo.kryo5", + "com.esotericsoftware.kryo.kryo5.asm", + "com.esotericsoftware.kryo.kryo5.io", + "com.esotericsoftware.kryo.kryo5.minlog", + "com.esotericsoftware.kryo.kryo5.objenesis", + "com.esotericsoftware.kryo.kryo5.objenesis.instantiator", + "com.esotericsoftware.kryo.kryo5.objenesis.instantiator.android", + "com.esotericsoftware.kryo.kryo5.objenesis.instantiator.annotations", + "com.esotericsoftware.kryo.kryo5.objenesis.instantiator.basic", + "com.esotericsoftware.kryo.kryo5.objenesis.instantiator.gcj", + "com.esotericsoftware.kryo.kryo5.objenesis.instantiator.perc", + "com.esotericsoftware.kryo.kryo5.objenesis.instantiator.sun", + "com.esotericsoftware.kryo.kryo5.objenesis.instantiator.util", + "com.esotericsoftware.kryo.kryo5.objenesis.strategy", + "com.esotericsoftware.kryo.kryo5.reflectasm", + "com.esotericsoftware.kryo.kryo5.serializers", + "com.esotericsoftware.kryo.kryo5.unsafe", + "com.esotericsoftware.kryo.kryo5.util", + "com.fasterxml.aalto", + "com.fasterxml.aalto.async", + "com.fasterxml.aalto.dom", + "com.fasterxml.aalto.evt", + "com.fasterxml.aalto.impl", + "com.fasterxml.aalto.in", + "com.fasterxml.aalto.io", + "com.fasterxml.aalto.out", + "com.fasterxml.aalto.sax", + "com.fasterxml.aalto.stax", + "com.fasterxml.aalto.util", + "com.github.benmanes.caffeine.cache", + "com.github.benmanes.caffeine.cache.stats", + "com.intellij", + "com.intellij.analysis", + "com.intellij.application", + "com.intellij.application.options.colors", + "com.intellij.codeHighlighting", + "com.intellij.codeInsight", + "com.intellij.codeInsight.codeFragment", + "com.intellij.codeInsight.completion", + "com.intellij.codeInsight.completion.command", + "com.intellij.codeInsight.completion.impl", + "com.intellij.codeInsight.completion.ml", + "com.intellij.codeInsight.completion.proc", + "com.intellij.codeInsight.completion.scope", + "com.intellij.codeInsight.completion.util", + "com.intellij.codeInsight.controlflow", + "com.intellij.codeInsight.controlflow.impl", + "com.intellij.codeInsight.daemon", + "com.intellij.codeInsight.daemon.impl", + "com.intellij.codeInsight.daemon.impl.actions", + "com.intellij.codeInsight.daemon.impl.analysis", + "com.intellij.codeInsight.daemon.impl.quickfix", + "com.intellij.codeInsight.dataflow", + "com.intellij.codeInsight.dataflow.map", + "com.intellij.codeInsight.documentation", + "com.intellij.codeInsight.editorActions", + "com.intellij.codeInsight.folding", + "com.intellij.codeInsight.folding.impl", + "com.intellij.codeInsight.generation", + "com.intellij.codeInsight.highlighting", + "com.intellij.codeInsight.hint", + "com.intellij.codeInsight.intention", + "com.intellij.codeInsight.intention.choice", + "com.intellij.codeInsight.intention.impl", + "com.intellij.codeInsight.intention.impl.config", + "com.intellij.codeInsight.intention.preview", + "com.intellij.codeInsight.javadoc", + "com.intellij.codeInsight.lookup", + "com.intellij.codeInsight.lookup.impl", + "com.intellij.codeInsight.multiverse", + "com.intellij.codeInsight.navigation.action", + "com.intellij.codeInsight.navigation.actions", + "com.intellij.codeInsight.parameterInfo", + "com.intellij.codeInsight.problems", + "com.intellij.codeInsight.quickfix", + "com.intellij.codeInsight.runner", + "com.intellij.codeInsight.template", + "com.intellij.codeInsight.template.impl", + "com.intellij.codeInsight.template.macro", + "com.intellij.codeInsight.util", + "com.intellij.codeInspection", + "com.intellij.codeInspection.actions", + "com.intellij.codeInspection.dataFlow", + "com.intellij.codeInspection.dataFlow.interpreter", + "com.intellij.codeInspection.dataFlow.lang", + "com.intellij.codeInspection.dataFlow.lang.ir", + "com.intellij.codeInspection.dataFlow.memory", + "com.intellij.codeInspection.dataFlow.rangeSet", + "com.intellij.codeInspection.dataFlow.types", + "com.intellij.codeInspection.dataFlow.value", + "com.intellij.codeInspection.ex", + "com.intellij.codeInspection.lang", + "com.intellij.codeInspection.options", + "com.intellij.codeInspection.reference", + "com.intellij.codeInspection.ui", + "com.intellij.codeInspection.ui.util", + "com.intellij.codeInspection.util", + "com.intellij.codeInspection.visibility", + "com.intellij.codeWithMe", + "com.intellij.concurrency", + "com.intellij.concurrency.client", + "com.intellij.configurationStore", + "com.intellij.core", + "com.intellij.diagnostic", + "com.intellij.diff.comparison", + "com.intellij.diff.comparison.iterables", + "com.intellij.diff.fragments", + "com.intellij.diff.tools.util.text", + "com.intellij.diff.util", + "com.intellij.execution", + "com.intellij.execution.configurations", + "com.intellij.execution.filters", + "com.intellij.execution.process", + "com.intellij.execution.rmi", + "com.intellij.execution.rmi.ssl", + "com.intellij.execution.wsl", + "com.intellij.extapi.psi", + "com.intellij.featureStatistics", + "com.intellij.filename", + "com.intellij.find", + "com.intellij.find.findUsages", + "com.intellij.find.impl", + "com.intellij.formatting", + "com.intellij.ide", + "com.intellij.ide.bootstrap", + "com.intellij.ide.debug", + "com.intellij.ide.fileTemplates", + "com.intellij.ide.highlighter", + "com.intellij.ide.highlighter.custom", + "com.intellij.ide.highlighter.custom.tokens", + "com.intellij.ide.lightEdit", + "com.intellij.ide.plugins", + "com.intellij.ide.plugins.cl", + "com.intellij.ide.presentation", + "com.intellij.ide.scratch", + "com.intellij.ide.util", + "com.intellij.idea", + "com.intellij.indentation", + "com.intellij.injected.editor", + "com.intellij.inlinePrompt", + "com.intellij.java.frontback.psi.impl", + "com.intellij.java.workspace.entities", + "com.intellij.java.workspace.entities.impl", + "com.intellij.jna", + "com.intellij.l10n", + "com.intellij.lang", + "com.intellij.lang.annotation", + "com.intellij.lang.documentation", + "com.intellij.lang.folding", + "com.intellij.lang.impl", + "com.intellij.lang.impl.modcommand", + "com.intellij.lang.injection", + "com.intellij.lang.injection.general", + "com.intellij.lang.java", + "com.intellij.lang.java.beans", + "com.intellij.lang.java.lexer", + "com.intellij.lang.java.parser", + "com.intellij.lang.java.source", + "com.intellij.lang.jvm", + "com.intellij.lang.jvm.annotation", + "com.intellij.lang.jvm.facade", + "com.intellij.lang.jvm.source", + "com.intellij.lang.jvm.types", + "com.intellij.lang.jvm.util", + "com.intellij.lang.parameterInfo", + "com.intellij.lang.parser", + "com.intellij.lang.refactoring", + "com.intellij.lang.spi", + "com.intellij.lang.tree.util", + "com.intellij.lexer", + "com.intellij.mock", + "com.intellij.modcommand", + "com.intellij.model", + "com.intellij.model.presentation", + "com.intellij.model.psi", + "com.intellij.model.psi.impl", + "com.intellij.model.search", + "com.intellij.navigation", + "com.intellij.notebook.editor", + "com.intellij.openapi", + "com.intellij.openapi.actionSystem", + "com.intellij.openapi.application", + "com.intellij.openapi.application.ex", + "com.intellij.openapi.application.impl", + "com.intellij.openapi.client", + "com.intellij.openapi.command", + "com.intellij.openapi.command.impl", + "com.intellij.openapi.command.undo", + "com.intellij.openapi.components", + "com.intellij.openapi.concurrency", + "com.intellij.openapi.diagnostic", + "com.intellij.openapi.editor", + "com.intellij.openapi.editor.actionSystem", + "com.intellij.openapi.editor.colors", + "com.intellij.openapi.editor.event", + "com.intellij.openapi.editor.ex", + "com.intellij.openapi.editor.ex.util", + "com.intellij.openapi.editor.impl", + "com.intellij.openapi.editor.impl.event", + "com.intellij.openapi.editor.markup", + "com.intellij.openapi.extensions", + "com.intellij.openapi.extensions.impl", + "com.intellij.openapi.fileEditor", + "com.intellij.openapi.fileEditor.ex", + "com.intellij.openapi.fileEditor.impl", + "com.intellij.openapi.fileTypes", + "com.intellij.openapi.fileTypes.ex", + "com.intellij.openapi.fileTypes.impl", + "com.intellij.openapi.module", + "com.intellij.openapi.module.impl", + "com.intellij.openapi.module.impl.scopes", + "com.intellij.openapi.options", + "com.intellij.openapi.paths", + "com.intellij.openapi.progress", + "com.intellij.openapi.progress.impl", + "com.intellij.openapi.progress.util", + "com.intellij.openapi.project", + "com.intellij.openapi.projectRoots", + "com.intellij.openapi.roots", + "com.intellij.openapi.roots.ex", + "com.intellij.openapi.roots.impl", + "com.intellij.openapi.roots.impl.libraries", + "com.intellij.openapi.roots.libraries", + "com.intellij.openapi.startup", + "com.intellij.openapi.ui", + "com.intellij.openapi.util", + "com.intellij.openapi.util.io", + "com.intellij.openapi.util.objectTree", + "com.intellij.openapi.util.registry", + "com.intellij.openapi.util.text", + "com.intellij.openapi.vfs", + "com.intellij.openapi.vfs.encoding", + "com.intellij.openapi.vfs.ex.dummy", + "com.intellij.openapi.vfs.ex.http", + "com.intellij.openapi.vfs.impl", + "com.intellij.openapi.vfs.impl.http", + "com.intellij.openapi.vfs.impl.jar", + "com.intellij.openapi.vfs.limits", + "com.intellij.openapi.vfs.local", + "com.intellij.openapi.vfs.newvfs", + "com.intellij.openapi.vfs.newvfs.events", + "com.intellij.openapi.vfs.newvfs.persistent", + "com.intellij.openapi.vfs.pointers", + "com.intellij.openapi.vfs.transformer", + "com.intellij.openapi.wm.ex", + "com.intellij.packageDependencies", + "com.intellij.patterns", + "com.intellij.patterns.compiler", + "com.intellij.platform.backend.navigation", + "com.intellij.platform.backend.presentation", + "com.intellij.platform.backend.workspace", + "com.intellij.platform.backend.workspace.impl", + "com.intellij.platform.diagnostic.telemetry", + "com.intellij.platform.diagnostic.telemetry.helpers", + "com.intellij.platform.jps.model.impl.resolver", + "com.intellij.platform.jps.model.resolver", + "com.intellij.platform.jps.model.serialization.resolver", + "com.intellij.platform.util", + "com.intellij.platform.util.coroutines", + "com.intellij.platform.util.coroutines.channel", + "com.intellij.platform.util.coroutines.compute", + "com.intellij.platform.util.coroutines.flow", + "com.intellij.platform.util.coroutines.internal", + "com.intellij.platform.util.coroutines.sync", + "com.intellij.platform.util.progress", + "com.intellij.platform.util.progress.impl", + "com.intellij.platform.workspace.jps", + "com.intellij.platform.workspace.jps.bridge", + "com.intellij.platform.workspace.jps.bridge.impl", + "com.intellij.platform.workspace.jps.bridge.impl.java", + "com.intellij.platform.workspace.jps.bridge.impl.library", + "com.intellij.platform.workspace.jps.bridge.impl.library.sdk", + "com.intellij.platform.workspace.jps.bridge.impl.module", + "com.intellij.platform.workspace.jps.bridge.impl.serialization", + "com.intellij.platform.workspace.jps.entities", + "com.intellij.platform.workspace.jps.entities.impl", + "com.intellij.platform.workspace.jps.impl", + "com.intellij.platform.workspace.jps.serialization", + "com.intellij.platform.workspace.jps.serialization.impl", + "com.intellij.platform.workspace.storage", + "com.intellij.platform.workspace.storage.annotations", + "com.intellij.platform.workspace.storage.impl", + "com.intellij.platform.workspace.storage.impl.cache", + "com.intellij.platform.workspace.storage.impl.containers", + "com.intellij.platform.workspace.storage.impl.exceptions", + "com.intellij.platform.workspace.storage.impl.external", + "com.intellij.platform.workspace.storage.impl.indices", + "com.intellij.platform.workspace.storage.impl.query", + "com.intellij.platform.workspace.storage.impl.references", + "com.intellij.platform.workspace.storage.impl.serialization", + "com.intellij.platform.workspace.storage.impl.serialization.registration", + "com.intellij.platform.workspace.storage.impl.serialization.serializer", + "com.intellij.platform.workspace.storage.impl.trace", + "com.intellij.platform.workspace.storage.impl.url", + "com.intellij.platform.workspace.storage.instrumentation", + "com.intellij.platform.workspace.storage.metadata", + "com.intellij.platform.workspace.storage.metadata.diff", + "com.intellij.platform.workspace.storage.metadata.exceptions", + "com.intellij.platform.workspace.storage.metadata.extensions", + "com.intellij.platform.workspace.storage.metadata.impl", + "com.intellij.platform.workspace.storage.metadata.model", + "com.intellij.platform.workspace.storage.metadata.resolver", + "com.intellij.platform.workspace.storage.metadata.utils", + "com.intellij.platform.workspace.storage.query", + "com.intellij.platform.workspace.storage.trace", + "com.intellij.platform.workspace.storage.url", + "com.intellij.pom", + "com.intellij.pom.core.impl", + "com.intellij.pom.event", + "com.intellij.pom.impl", + "com.intellij.pom.java", + "com.intellij.pom.references", + "com.intellij.pom.tree", + "com.intellij.pom.tree.events", + "com.intellij.pom.tree.events.impl", + "com.intellij.pom.wrappers", + "com.intellij.problems", + "com.intellij.profile", + "com.intellij.profile.codeInspection", + "com.intellij.projectModel", + "com.intellij.psi", + "com.intellij.psi.augment", + "com.intellij.psi.codeStyle", + "com.intellij.psi.compiled", + "com.intellij.psi.controlFlow", + "com.intellij.psi.css", + "com.intellij.psi.file", + "com.intellij.psi.filters", + "com.intellij.psi.filters.classes", + "com.intellij.psi.filters.element", + "com.intellij.psi.filters.position", + "com.intellij.psi.impl", + "com.intellij.psi.impl.cache", + "com.intellij.psi.impl.compiled", + "com.intellij.psi.impl.file", + "com.intellij.psi.impl.file.impl", + "com.intellij.psi.impl.java.stubs", + "com.intellij.psi.impl.java.stubs.impl", + "com.intellij.psi.impl.java.stubs.index", + "com.intellij.psi.impl.light", + "com.intellij.psi.impl.meta", + "com.intellij.psi.impl.search", + "com.intellij.psi.impl.smartPointers", + "com.intellij.psi.impl.source", + "com.intellij.psi.impl.source.codeStyle", + "com.intellij.psi.impl.source.javadoc", + "com.intellij.psi.impl.source.resolve", + "com.intellij.psi.impl.source.resolve.graphInference", + "com.intellij.psi.impl.source.resolve.graphInference.constraints", + "com.intellij.psi.impl.source.resolve.reference", + "com.intellij.psi.impl.source.resolve.reference.impl", + "com.intellij.psi.impl.source.resolve.reference.impl.manipulators", + "com.intellij.psi.impl.source.resolve.reference.impl.providers", + "com.intellij.psi.impl.source.tree", + "com.intellij.psi.impl.source.tree.injected", + "com.intellij.psi.impl.source.tree.java", + "com.intellij.psi.infos", + "com.intellij.psi.injection", + "com.intellij.psi.javadoc", + "com.intellij.psi.meta", + "com.intellij.psi.presentation.java", + "com.intellij.psi.scope", + "com.intellij.psi.scope.conflictResolvers", + "com.intellij.psi.scope.processor", + "com.intellij.psi.scope.util", + "com.intellij.psi.search", + "com.intellij.psi.search.impl", + "com.intellij.psi.search.scope", + "com.intellij.psi.search.scope.impl", + "com.intellij.psi.search.scope.packageSet", + "com.intellij.psi.search.searches", + "com.intellij.psi.statistics", + "com.intellij.psi.stub", + "com.intellij.psi.stubs", + "com.intellij.psi.targets", + "com.intellij.psi.templateLanguages", + "com.intellij.psi.text", + "com.intellij.psi.tree", + "com.intellij.psi.tree.java", + "com.intellij.psi.util", + "com.intellij.refactoring.listeners", + "com.intellij.refactoring.rename", + "com.intellij.refactoring.util", + "com.intellij.reference", + "com.intellij.security", + "com.intellij.serialization", + "com.intellij.serviceContainer", + "com.intellij.smRunner", + "com.intellij.testFramework", + "com.intellij.testIntegration", + "com.intellij.ui", + "com.intellij.ui.classFilter", + "com.intellij.ui.icons", + "com.intellij.usageView", + "com.intellij.util", + "com.intellij.util.cls", + "com.intellij.util.codeInsight", + "com.intellij.util.concurrency", + "com.intellij.util.concurrency.annotations", + "com.intellij.util.containers", + "com.intellij.util.containers.hash", + "com.intellij.util.containers.prefixTree", + "com.intellij.util.containers.prefixTree.map", + "com.intellij.util.containers.prefixTree.set", + "com.intellij.util.diff", + "com.intellij.util.download", + "com.intellij.util.download.impl", + "com.intellij.util.execution", + "com.intellij.util.fmap", + "com.intellij.util.graph", + "com.intellij.util.graph.impl", + "com.intellij.util.indexing", + "com.intellij.util.indexing.containers", + "com.intellij.util.indexing.flavor", + "com.intellij.util.indexing.impl", + "com.intellij.util.indexing.impl.diagnostics", + "com.intellij.util.indexing.impl.forward", + "com.intellij.util.io", + "com.intellij.util.io.blobstorage", + "com.intellij.util.io.externalizer", + "com.intellij.util.io.keyStorage", + "com.intellij.util.io.pagecache", + "com.intellij.util.io.pagecache.impl", + "com.intellij.util.io.stats", + "com.intellij.util.io.storage", + "com.intellij.util.io.storage.lf", + "com.intellij.util.io.zip", + "com.intellij.util.keyFMap", + "com.intellij.util.lang", + "com.intellij.util.messages", + "com.intellij.util.messages.impl", + "com.intellij.util.pico", + "com.intellij.util.profiling", + "com.intellij.util.progress", + "com.intellij.util.ref", + "com.intellij.util.system", + "com.intellij.util.text", + "com.intellij.util.text.minimatch", + "com.intellij.util.ui", + "com.intellij.util.ui.classpath", + "com.intellij.util.xml.dom", + "com.intellij.util.xmlb", + "com.intellij.util.xmlb.annotations", + "com.intellij.webcore.packaging", + "com.intellij.workspaceModel.ide", + "com.intellij.workspaceModel.ide.legacyBridge", + "com.intellij.workspaceModel.ide.legacyBridge.sdk", + "com.intellij.xml", + "com.intellij.xml.util", + "com.sun.jna", + "com.sun.jna.internal", + "com.sun.jna.platform", + "com.sun.jna.platform.bsd", + "com.sun.jna.platform.dnd", + "com.sun.jna.platform.linux", + "com.sun.jna.platform.mac", + "com.sun.jna.platform.unix", + "com.sun.jna.platform.unix.aix", + "com.sun.jna.platform.unix.solaris", + "com.sun.jna.platform.win32", + "com.sun.jna.platform.win32.COM", + "com.sun.jna.platform.win32.COM.tlb", + "com.sun.jna.platform.win32.COM.tlb.imp", + "com.sun.jna.platform.win32.COM.util", + "com.sun.jna.platform.win32.COM.util.annotation", + "com.sun.jna.platform.wince", + "com.sun.jna.ptr", + "com.sun.jna.win32", + "io.opentelemetry.api", + "io.opentelemetry.api.baggage", + "io.opentelemetry.api.baggage.propagation", + "io.opentelemetry.api.common", + "io.opentelemetry.api.internal", + "io.opentelemetry.api.logs", + "io.opentelemetry.api.metrics", + "io.opentelemetry.api.trace", + "io.opentelemetry.api.trace.propagation", + "io.opentelemetry.api.trace.propagation.internal", + "io.opentelemetry.context", + "io.opentelemetry.context.internal.shaded", + "io.opentelemetry.context.propagation", + "io.opentelemetry.context.propagation.internal", + "io.opentelemetry.internal.shaded.jctools.counters", + "io.opentelemetry.internal.shaded.jctools.maps", + "io.opentelemetry.internal.shaded.jctools.queues", + "io.opentelemetry.internal.shaded.jctools.queues.atomic", + "io.opentelemetry.internal.shaded.jctools.queues.atomic.unpadded", + "io.opentelemetry.internal.shaded.jctools.queues.unpadded", + "io.opentelemetry.internal.shaded.jctools.util", + "io.opentelemetry.sdk", + "io.opentelemetry.sdk.common", + "io.opentelemetry.sdk.common.export", + "io.opentelemetry.sdk.common.internal", + "io.opentelemetry.sdk.internal", + "io.opentelemetry.sdk.logs", + "io.opentelemetry.sdk.logs.data", + "io.opentelemetry.sdk.logs.data.internal", + "io.opentelemetry.sdk.logs.export", + "io.opentelemetry.sdk.logs.internal", + "io.opentelemetry.sdk.metrics", + "io.opentelemetry.sdk.metrics.data", + "io.opentelemetry.sdk.metrics.export", + "io.opentelemetry.sdk.metrics.internal", + "io.opentelemetry.sdk.metrics.internal.aggregator", + "io.opentelemetry.sdk.metrics.internal.concurrent", + "io.opentelemetry.sdk.metrics.internal.data", + "io.opentelemetry.sdk.metrics.internal.debug", + "io.opentelemetry.sdk.metrics.internal.descriptor", + "io.opentelemetry.sdk.metrics.internal.exemplar", + "io.opentelemetry.sdk.metrics.internal.export", + "io.opentelemetry.sdk.metrics.internal.state", + "io.opentelemetry.sdk.metrics.internal.view", + "io.opentelemetry.sdk.resources", + "io.opentelemetry.sdk.trace", + "io.opentelemetry.sdk.trace.data", + "io.opentelemetry.sdk.trace.export", + "io.opentelemetry.sdk.trace.internal", + "io.opentelemetry.sdk.trace.samplers", + "io.opentelemetry.semconv", + "it.unimi.dsi.fastutil", + "it.unimi.dsi.fastutil.booleans", + "it.unimi.dsi.fastutil.bytes", + "it.unimi.dsi.fastutil.chars", + "it.unimi.dsi.fastutil.doubles", + "it.unimi.dsi.fastutil.floats", + "it.unimi.dsi.fastutil.ints", + "it.unimi.dsi.fastutil.longs", + "it.unimi.dsi.fastutil.objects", + "it.unimi.dsi.fastutil.shorts", + "kotlinx.collections.immutable", + "kotlinx.collections.immutable.adapters", + "kotlinx.collections.immutable.implementations.immutableList", + "kotlinx.collections.immutable.implementations.immutableMap", + "kotlinx.collections.immutable.implementations.immutableSet", + "kotlinx.collections.immutable.implementations.persistentOrderedMap", + "kotlinx.collections.immutable.implementations.persistentOrderedSet", + "kotlinx.collections.immutable.internal", + "kotlinx.coroutines", + "kotlinx.coroutines.channels", + "kotlinx.coroutines.debug", + "kotlinx.coroutines.debug.internal", + "kotlinx.coroutines.debug.junit4", + "kotlinx.coroutines.debug.junit5", + "kotlinx.coroutines.flow", + "kotlinx.coroutines.flow.internal", + "kotlinx.coroutines.future", + "kotlinx.coroutines.internal", + "kotlinx.coroutines.internal.intellij", + "kotlinx.coroutines.intrinsics", + "kotlinx.coroutines.repackaged.net.bytebuddy", + "kotlinx.coroutines.repackaged.net.bytebuddy.agent", + "kotlinx.coroutines.repackaged.net.bytebuddy.agent.builder", + "kotlinx.coroutines.repackaged.net.bytebuddy.asm", + "kotlinx.coroutines.repackaged.net.bytebuddy.build", + "kotlinx.coroutines.repackaged.net.bytebuddy.description", + "kotlinx.coroutines.repackaged.net.bytebuddy.description.annotation", + "kotlinx.coroutines.repackaged.net.bytebuddy.description.enumeration", + "kotlinx.coroutines.repackaged.net.bytebuddy.description.field", + "kotlinx.coroutines.repackaged.net.bytebuddy.description.method", + "kotlinx.coroutines.repackaged.net.bytebuddy.description.modifier", + "kotlinx.coroutines.repackaged.net.bytebuddy.description.type", + "kotlinx.coroutines.repackaged.net.bytebuddy.dynamic", + "kotlinx.coroutines.repackaged.net.bytebuddy.dynamic.loading", + "kotlinx.coroutines.repackaged.net.bytebuddy.dynamic.scaffold", + "kotlinx.coroutines.repackaged.net.bytebuddy.dynamic.scaffold.inline", + "kotlinx.coroutines.repackaged.net.bytebuddy.dynamic.scaffold.subclass", + "kotlinx.coroutines.repackaged.net.bytebuddy.implementation", + "kotlinx.coroutines.repackaged.net.bytebuddy.implementation.attribute", + "kotlinx.coroutines.repackaged.net.bytebuddy.implementation.auxiliary", + "kotlinx.coroutines.repackaged.net.bytebuddy.implementation.bind", + "kotlinx.coroutines.repackaged.net.bytebuddy.implementation.bind.annotation", + "kotlinx.coroutines.repackaged.net.bytebuddy.implementation.bytecode", + "kotlinx.coroutines.repackaged.net.bytebuddy.implementation.bytecode.assign", + "kotlinx.coroutines.repackaged.net.bytebuddy.implementation.bytecode.assign.primitive", + "kotlinx.coroutines.repackaged.net.bytebuddy.implementation.bytecode.assign.reference", + "kotlinx.coroutines.repackaged.net.bytebuddy.implementation.bytecode.collection", + "kotlinx.coroutines.repackaged.net.bytebuddy.implementation.bytecode.constant", + "kotlinx.coroutines.repackaged.net.bytebuddy.implementation.bytecode.member", + "kotlinx.coroutines.repackaged.net.bytebuddy.jar.asm", + "kotlinx.coroutines.repackaged.net.bytebuddy.jar.asm.commons", + "kotlinx.coroutines.repackaged.net.bytebuddy.jar.asm.signature", + "kotlinx.coroutines.repackaged.net.bytebuddy.matcher", + "kotlinx.coroutines.repackaged.net.bytebuddy.pool", + "kotlinx.coroutines.repackaged.net.bytebuddy.utility", + "kotlinx.coroutines.repackaged.net.bytebuddy.utility.privilege", + "kotlinx.coroutines.repackaged.net.bytebuddy.utility.visitor", + "kotlinx.coroutines.scheduling", + "kotlinx.coroutines.selects", + "kotlinx.coroutines.stream", + "kotlinx.coroutines.sync", + "kotlinx.coroutines.time", + "kotlinx.serialization", + "kotlinx.serialization.builtins", + "kotlinx.serialization.descriptors", + "kotlinx.serialization.encoding", + "kotlinx.serialization.internal", + "kotlinx.serialization.json", + "kotlinx.serialization.json.internal", + "kotlinx.serialization.modules", + "net.jpountz.lz4", + "net.jpountz.util", + "net.jpountz.xxhash", + "one.util.streamex", + "org.apache.commons.codec", + "org.apache.commons.codec.binary", + "org.apache.commons.codec.cli", + "org.apache.commons.codec.digest", + "org.apache.commons.codec.language", + "org.apache.commons.codec.language.bm", + "org.apache.commons.codec.net", + "org.apache.commons.compress", + "org.apache.commons.compress.archivers", + "org.apache.commons.compress.archivers.ar", + "org.apache.commons.compress.archivers.arj", + "org.apache.commons.compress.archivers.cpio", + "org.apache.commons.compress.archivers.dump", + "org.apache.commons.compress.archivers.examples", + "org.apache.commons.compress.archivers.jar", + "org.apache.commons.compress.archivers.sevenz", + "org.apache.commons.compress.archivers.tar", + "org.apache.commons.compress.archivers.zip", + "org.apache.commons.compress.changes", + "org.apache.commons.compress.compressors", + "org.apache.commons.compress.compressors.brotli", + "org.apache.commons.compress.compressors.bzip2", + "org.apache.commons.compress.compressors.deflate", + "org.apache.commons.compress.compressors.deflate64", + "org.apache.commons.compress.compressors.gzip", + "org.apache.commons.compress.compressors.lz4", + "org.apache.commons.compress.compressors.lz77support", + "org.apache.commons.compress.compressors.lzma", + "org.apache.commons.compress.compressors.lzw", + "org.apache.commons.compress.compressors.pack200", + "org.apache.commons.compress.compressors.snappy", + "org.apache.commons.compress.compressors.xz", + "org.apache.commons.compress.compressors.z", + "org.apache.commons.compress.compressors.zstandard", + "org.apache.commons.compress.harmony", + "org.apache.commons.compress.harmony.archive.internal.nls", + "org.apache.commons.compress.harmony.pack200", + "org.apache.commons.compress.harmony.unpack200", + "org.apache.commons.compress.harmony.unpack200.bytecode", + "org.apache.commons.compress.harmony.unpack200.bytecode.forms", + "org.apache.commons.compress.java.util.jar", + "org.apache.commons.compress.parallel", + "org.apache.commons.compress.utils", + "org.apache.commons.io", + "org.apache.commons.io.build", + "org.apache.commons.io.channels", + "org.apache.commons.io.charset", + "org.apache.commons.io.comparator", + "org.apache.commons.io.file", + "org.apache.commons.io.file.attribute", + "org.apache.commons.io.file.spi", + "org.apache.commons.io.filefilter", + "org.apache.commons.io.function", + "org.apache.commons.io.input", + "org.apache.commons.io.input.buffer", + "org.apache.commons.io.monitor", + "org.apache.commons.io.output", + "org.apache.commons.io.serialization", + "org.apache.log4j", + "org.apache.log4j.helpers", + "org.apache.log4j.spi", + "org.apache.log4j.xml", + "org.apache.oro.io", + "org.apache.oro.text", + "org.apache.oro.text.awk", + "org.apache.oro.text.perl", + "org.apache.oro.text.regex", + "org.apache.oro.util", + "org.codehaus.stax2", + "org.codehaus.stax2.evt", + "org.codehaus.stax2.io", + "org.codehaus.stax2.osgi", + "org.codehaus.stax2.ri", + "org.codehaus.stax2.ri.dom", + "org.codehaus.stax2.ri.evt", + "org.codehaus.stax2.ri.typed", + "org.codehaus.stax2.typed", + "org.codehaus.stax2.util", + "org.codehaus.stax2.validation", + "org.intellij.lang.annotations", + "org.jaxen", + "org.jaxen.dom", + "org.jaxen.dom4j", + "org.jaxen.expr", + "org.jaxen.expr.iter", + "org.jaxen.function", + "org.jaxen.function.ext", + "org.jaxen.function.xslt", + "org.jaxen.javabean", + "org.jaxen.jdom", + "org.jaxen.pattern", + "org.jaxen.saxpath", + "org.jaxen.saxpath.base", + "org.jaxen.saxpath.helpers", + "org.jaxen.util", + "org.jaxen.xom", + "org.jdom", + "org.jdom.filter", + "org.jdom.filter2", + "org.jdom.input", + "org.jdom.input.sax", + "org.jdom.output", + "org.jdom.util", + "org.jdom.xpath", + "org.jdom.xpath.jaxen", + "org.jdom.xpath.util", + "org.jetbrains.annotations", + "org.jetbrains.concurrency", + "org.jetbrains.ide", + "org.jetbrains.jps.model", + "org.jetbrains.jps.model.artifact", + "org.jetbrains.jps.model.artifact.elements", + "org.jetbrains.jps.model.artifact.elements.ex", + "org.jetbrains.jps.model.artifact.impl", + "org.jetbrains.jps.model.artifact.impl.elements", + "org.jetbrains.jps.model.ex", + "org.jetbrains.jps.model.fileTypes", + "org.jetbrains.jps.model.fileTypes.impl", + "org.jetbrains.jps.model.impl", + "org.jetbrains.jps.model.impl.runConfiguration", + "org.jetbrains.jps.model.jarRepository", + "org.jetbrains.jps.model.jarRepository.impl", + "org.jetbrains.jps.model.java", + "org.jetbrains.jps.model.java.compiler", + "org.jetbrains.jps.model.java.impl", + "org.jetbrains.jps.model.java.impl.compiler", + "org.jetbrains.jps.model.java.impl.runConfiguration", + "org.jetbrains.jps.model.java.runConfiguration", + "org.jetbrains.jps.model.library", + "org.jetbrains.jps.model.library.impl", + "org.jetbrains.jps.model.library.impl.sdk", + "org.jetbrains.jps.model.library.sdk", + "org.jetbrains.jps.model.module", + "org.jetbrains.jps.model.module.impl", + "org.jetbrains.jps.model.runConfiguration", + "org.jetbrains.jps.model.serialization", + "org.jetbrains.jps.model.serialization.artifact", + "org.jetbrains.jps.model.serialization.facet", + "org.jetbrains.jps.model.serialization.impl", + "org.jetbrains.jps.model.serialization.jarRepository", + "org.jetbrains.jps.model.serialization.java", + "org.jetbrains.jps.model.serialization.java.compiler", + "org.jetbrains.jps.model.serialization.library", + "org.jetbrains.jps.model.serialization.module", + "org.jetbrains.jps.model.serialization.runConfigurations", + "org.jetbrains.jps.plugin", + "org.jetbrains.jps.service", + "org.jetbrains.jps.service.impl", + "org.jetbrains.jps.util", + "org.jetbrains.org.objectweb.asm", + "org.jetbrains.org.objectweb.asm.commons", + "org.jetbrains.org.objectweb.asm.signature", + "org.jetbrains.org.objectweb.asm.tree", + "org.jetbrains.org.objectweb.asm.tree.analysis", + "org.jetbrains.org.objectweb.asm.util", + "org.picocontainer" + ], + "com.android.tools.external.com-intellij:kotlin-compiler": [ + "com.google.gwt.dev.js", + "com.google.gwt.dev.js.parserExceptions", + "com.google.gwt.dev.js.rhino", + "com.intellij.openapi.util", + "com.intellij.openapi.vfs", + "com.intellij.util.io", + "com.intellij.util.lang", + "io.vavr", + "io.vavr.collection", + "io.vavr.concurrent", + "io.vavr.control", + "io.vavr.match.annotation", + "kotlin.script.dependencies", + "kotlin.script.experimental.annotations", + "kotlin.script.experimental.api", + "kotlin.script.experimental.dependencies", + "kotlin.script.experimental.host", + "kotlin.script.experimental.impl", + "kotlin.script.experimental.jvm", + "kotlin.script.experimental.jvm.compat", + "kotlin.script.experimental.jvm.impl", + "kotlin.script.experimental.jvm.util", + "kotlin.script.experimental.location", + "kotlin.script.experimental.util", + "kotlin.script.extensions", + "kotlin.script.templates", + "kotlin.script.templates.standard", + "kotlinx.collections.immutable", + "kotlinx.collections.immutable.adapters", + "kotlinx.collections.immutable.implementations.immutableList", + "kotlinx.collections.immutable.implementations.immutableMap", + "kotlinx.collections.immutable.implementations.immutableSet", + "kotlinx.collections.immutable.implementations.persistentOrderedMap", + "kotlinx.collections.immutable.implementations.persistentOrderedSet", + "kotlinx.collections.immutable.internal", + "org.jetbrains.annotations", + "org.jetbrains.kotlin", + "org.jetbrains.kotlin.analysis.api", + "org.jetbrains.kotlin.analysis.api.annotations", + "org.jetbrains.kotlin.analysis.api.base", + "org.jetbrains.kotlin.analysis.api.compile", + "org.jetbrains.kotlin.analysis.api.components", + "org.jetbrains.kotlin.analysis.api.contracts.description", + "org.jetbrains.kotlin.analysis.api.contracts.description.booleans", + "org.jetbrains.kotlin.analysis.api.descriptors", + "org.jetbrains.kotlin.analysis.api.descriptors.annotations", + "org.jetbrains.kotlin.analysis.api.descriptors.components", + "org.jetbrains.kotlin.analysis.api.descriptors.components.base", + "org.jetbrains.kotlin.analysis.api.descriptors.contracts", + "org.jetbrains.kotlin.analysis.api.descriptors.modification", + "org.jetbrains.kotlin.analysis.api.descriptors.references", + "org.jetbrains.kotlin.analysis.api.descriptors.scopes", + "org.jetbrains.kotlin.analysis.api.descriptors.signatures", + "org.jetbrains.kotlin.analysis.api.descriptors.symbols", + "org.jetbrains.kotlin.analysis.api.descriptors.symbols.base", + "org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased", + "org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base", + "org.jetbrains.kotlin.analysis.api.descriptors.symbols.pointers", + "org.jetbrains.kotlin.analysis.api.descriptors.symbols.psiBased", + "org.jetbrains.kotlin.analysis.api.descriptors.symbols.psiBased.base", + "org.jetbrains.kotlin.analysis.api.descriptors.types", + "org.jetbrains.kotlin.analysis.api.descriptors.types.base", + "org.jetbrains.kotlin.analysis.api.descriptors.utils", + "org.jetbrains.kotlin.analysis.api.diagnostics", + "org.jetbrains.kotlin.analysis.api.fir", + "org.jetbrains.kotlin.analysis.api.fir.annotations", + "org.jetbrains.kotlin.analysis.api.fir.components", + "org.jetbrains.kotlin.analysis.api.fir.contracts", + "org.jetbrains.kotlin.analysis.api.fir.diagnostics", + "org.jetbrains.kotlin.analysis.api.fir.evaluate", + "org.jetbrains.kotlin.analysis.api.fir.modification", + "org.jetbrains.kotlin.analysis.api.fir.references", + "org.jetbrains.kotlin.analysis.api.fir.scopes", + "org.jetbrains.kotlin.analysis.api.fir.signatures", + "org.jetbrains.kotlin.analysis.api.fir.statistics", + "org.jetbrains.kotlin.analysis.api.fir.symbols", + "org.jetbrains.kotlin.analysis.api.fir.symbols.pointers", + "org.jetbrains.kotlin.analysis.api.fir.types", + "org.jetbrains.kotlin.analysis.api.fir.types.qualifiers", + "org.jetbrains.kotlin.analysis.api.fir.utils", + "org.jetbrains.kotlin.analysis.api.impl.base", + "org.jetbrains.kotlin.analysis.api.impl.base.annotations", + "org.jetbrains.kotlin.analysis.api.impl.base.components", + "org.jetbrains.kotlin.analysis.api.impl.base.contracts.description", + "org.jetbrains.kotlin.analysis.api.impl.base.contracts.description.booleans", + "org.jetbrains.kotlin.analysis.api.impl.base.imports", + "org.jetbrains.kotlin.analysis.api.impl.base.java", + "org.jetbrains.kotlin.analysis.api.impl.base.java.source", + "org.jetbrains.kotlin.analysis.api.impl.base.lifetime", + "org.jetbrains.kotlin.analysis.api.impl.base.permissions", + "org.jetbrains.kotlin.analysis.api.impl.base.projectStructure", + "org.jetbrains.kotlin.analysis.api.impl.base.references", + "org.jetbrains.kotlin.analysis.api.impl.base.resolution", + "org.jetbrains.kotlin.analysis.api.impl.base.restrictedAnalysis", + "org.jetbrains.kotlin.analysis.api.impl.base.scopes", + "org.jetbrains.kotlin.analysis.api.impl.base.sessions", + "org.jetbrains.kotlin.analysis.api.impl.base.signatures", + "org.jetbrains.kotlin.analysis.api.impl.base.symbols", + "org.jetbrains.kotlin.analysis.api.impl.base.symbols.pointers", + "org.jetbrains.kotlin.analysis.api.impl.base.types", + "org.jetbrains.kotlin.analysis.api.impl.base.util", + "org.jetbrains.kotlin.analysis.api.imports", + "org.jetbrains.kotlin.analysis.api.lifetime", + "org.jetbrains.kotlin.analysis.api.permissions", + "org.jetbrains.kotlin.analysis.api.platform", + "org.jetbrains.kotlin.analysis.api.platform.caches", + "org.jetbrains.kotlin.analysis.api.platform.declarations", + "org.jetbrains.kotlin.analysis.api.platform.java", + "org.jetbrains.kotlin.analysis.api.platform.lifetime", + "org.jetbrains.kotlin.analysis.api.platform.modification", + "org.jetbrains.kotlin.analysis.api.platform.packages", + "org.jetbrains.kotlin.analysis.api.platform.permissions", + "org.jetbrains.kotlin.analysis.api.platform.projectStructure", + "org.jetbrains.kotlin.analysis.api.platform.resolution", + "org.jetbrains.kotlin.analysis.api.platform.restrictedAnalysis", + "org.jetbrains.kotlin.analysis.api.platform.statistics", + "org.jetbrains.kotlin.analysis.api.platform.utils", + "org.jetbrains.kotlin.analysis.api.projectStructure", + "org.jetbrains.kotlin.analysis.api.renderer.base", + "org.jetbrains.kotlin.analysis.api.renderer.base.annotations", + "org.jetbrains.kotlin.analysis.api.renderer.base.annotations.renderers", + "org.jetbrains.kotlin.analysis.api.renderer.base.contextReceivers", + "org.jetbrains.kotlin.analysis.api.renderer.base.contextReceivers.renderers", + "org.jetbrains.kotlin.analysis.api.renderer.declarations", + "org.jetbrains.kotlin.analysis.api.renderer.declarations.bodies", + "org.jetbrains.kotlin.analysis.api.renderer.declarations.impl", + "org.jetbrains.kotlin.analysis.api.renderer.declarations.modifiers", + "org.jetbrains.kotlin.analysis.api.renderer.declarations.modifiers.impl", + "org.jetbrains.kotlin.analysis.api.renderer.declarations.modifiers.renderers", + "org.jetbrains.kotlin.analysis.api.renderer.declarations.renderers", + "org.jetbrains.kotlin.analysis.api.renderer.declarations.renderers.callables", + "org.jetbrains.kotlin.analysis.api.renderer.declarations.renderers.classifiers", + "org.jetbrains.kotlin.analysis.api.renderer.declarations.superTypes", + "org.jetbrains.kotlin.analysis.api.renderer.types", + "org.jetbrains.kotlin.analysis.api.renderer.types.impl", + "org.jetbrains.kotlin.analysis.api.renderer.types.renderers", + "org.jetbrains.kotlin.analysis.api.resolution", + "org.jetbrains.kotlin.analysis.api.resolve.extensions", + "org.jetbrains.kotlin.analysis.api.scopes", + "org.jetbrains.kotlin.analysis.api.session", + "org.jetbrains.kotlin.analysis.api.signatures", + "org.jetbrains.kotlin.analysis.api.standalone", + "org.jetbrains.kotlin.analysis.api.standalone.base", + "org.jetbrains.kotlin.analysis.api.standalone.base.declarations", + "org.jetbrains.kotlin.analysis.api.standalone.base.java", + "org.jetbrains.kotlin.analysis.api.standalone.base.modification", + "org.jetbrains.kotlin.analysis.api.standalone.base.packages", + "org.jetbrains.kotlin.analysis.api.standalone.base.permissions", + "org.jetbrains.kotlin.analysis.api.standalone.base.projectStructure", + "org.jetbrains.kotlin.analysis.api.standalone.base.services", + "org.jetbrains.kotlin.analysis.api.symbols", + "org.jetbrains.kotlin.analysis.api.symbols.markers", + "org.jetbrains.kotlin.analysis.api.symbols.pointers", + "org.jetbrains.kotlin.analysis.api.types", + "org.jetbrains.kotlin.analysis.api.utils", + "org.jetbrains.kotlin.analysis.api.utils.errors", + "org.jetbrains.kotlin.analysis.decompiled.light.classes", + "org.jetbrains.kotlin.analysis.decompiled.light.classes.origin", + "org.jetbrains.kotlin.analysis.decompiler.js", + "org.jetbrains.kotlin.analysis.decompiler.konan", + "org.jetbrains.kotlin.analysis.decompiler.psi", + "org.jetbrains.kotlin.analysis.decompiler.psi.file", + "org.jetbrains.kotlin.analysis.decompiler.psi.text", + "org.jetbrains.kotlin.analysis.decompiler.stub", + "org.jetbrains.kotlin.analysis.decompiler.stub.file", + "org.jetbrains.kotlin.analysis.decompiler.stub.flags", + "org.jetbrains.kotlin.analysis.low.level.api.fir", + "org.jetbrains.kotlin.analysis.low.level.api.fir.api", + "org.jetbrains.kotlin.analysis.low.level.api.fir.api.services", + "org.jetbrains.kotlin.analysis.low.level.api.fir.api.targets", + "org.jetbrains.kotlin.analysis.low.level.api.fir.caches", + "org.jetbrains.kotlin.analysis.low.level.api.fir.caches.cleanable", + "org.jetbrains.kotlin.analysis.low.level.api.fir.compile", + "org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics", + "org.jetbrains.kotlin.analysis.low.level.api.fir.diagnostics.fir", + "org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder", + "org.jetbrains.kotlin.analysis.low.level.api.fir.file.builder", + "org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure", + "org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve", + "org.jetbrains.kotlin.analysis.low.level.api.fir.projectStructure", + "org.jetbrains.kotlin.analysis.low.level.api.fir.providers", + "org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions", + "org.jetbrains.kotlin.analysis.low.level.api.fir.resolver", + "org.jetbrains.kotlin.analysis.low.level.api.fir.services", + "org.jetbrains.kotlin.analysis.low.level.api.fir.sessions", + "org.jetbrains.kotlin.analysis.low.level.api.fir.state", + "org.jetbrains.kotlin.analysis.low.level.api.fir.statistics", + "org.jetbrains.kotlin.analysis.low.level.api.fir.statistics.domains", + "org.jetbrains.kotlin.analysis.low.level.api.fir.stubBased.deserialization", + "org.jetbrains.kotlin.analysis.low.level.api.fir.symbolProviders", + "org.jetbrains.kotlin.analysis.low.level.api.fir.symbolProviders.combined", + "org.jetbrains.kotlin.analysis.low.level.api.fir.symbolProviders.factories", + "org.jetbrains.kotlin.analysis.low.level.api.fir.transformers", + "org.jetbrains.kotlin.analysis.low.level.api.fir.util", + "org.jetbrains.kotlin.analysis.project.structure.builder", + "org.jetbrains.kotlin.analysis.project.structure.impl", + "org.jetbrains.kotlin.analysis.utils", + "org.jetbrains.kotlin.analysis.utils.caches", + "org.jetbrains.kotlin.analysis.utils.collections", + "org.jetbrains.kotlin.analysis.utils.errors", + "org.jetbrains.kotlin.analysis.utils.printer", + "org.jetbrains.kotlin.analysis.utils.relfection", + "org.jetbrains.kotlin.analyzer", + "org.jetbrains.kotlin.analyzer.common", + "org.jetbrains.kotlin.arguments", + "org.jetbrains.kotlin.asJava", + "org.jetbrains.kotlin.asJava.builder", + "org.jetbrains.kotlin.asJava.classes", + "org.jetbrains.kotlin.asJava.elements", + "org.jetbrains.kotlin.asJava.finder", + "org.jetbrains.kotlin.backend.common", + "org.jetbrains.kotlin.backend.common.actualizer", + "org.jetbrains.kotlin.backend.common.actualizer.checker", + "org.jetbrains.kotlin.backend.common.bridges", + "org.jetbrains.kotlin.backend.common.checkers", + "org.jetbrains.kotlin.backend.common.diagnostics", + "org.jetbrains.kotlin.backend.common.linkage", + "org.jetbrains.kotlin.backend.common.linkage.issues", + "org.jetbrains.kotlin.backend.common.linkage.partial", + "org.jetbrains.kotlin.backend.common.output", + "org.jetbrains.kotlin.backend.common.overrides", + "org.jetbrains.kotlin.backend.common.serialization", + "org.jetbrains.kotlin.backend.common.serialization.encodings", + "org.jetbrains.kotlin.backend.common.serialization.mangle", + "org.jetbrains.kotlin.backend.common.serialization.mangle.descriptor", + "org.jetbrains.kotlin.backend.common.serialization.mangle.ir", + "org.jetbrains.kotlin.backend.common.serialization.metadata", + "org.jetbrains.kotlin.backend.common.serialization.proto", + "org.jetbrains.kotlin.backend.common.serialization.signature", + "org.jetbrains.kotlin.backend.js", + "org.jetbrains.kotlin.backend.jvm", + "org.jetbrains.kotlin.backend.jvm.caches", + "org.jetbrains.kotlin.backend.jvm.codegen", + "org.jetbrains.kotlin.backend.jvm.extensions", + "org.jetbrains.kotlin.backend.jvm.intrinsics", + "org.jetbrains.kotlin.backend.jvm.ir", + "org.jetbrains.kotlin.backend.jvm.lower", + "org.jetbrains.kotlin.backend.jvm.lower.indy", + "org.jetbrains.kotlin.backend.jvm.mapping", + "org.jetbrains.kotlin.backend.jvm.metadata", + "org.jetbrains.kotlin.backend.jvm.overrides", + "org.jetbrains.kotlin.backend.konan", + "org.jetbrains.kotlin.backend.konan.descriptors", + "org.jetbrains.kotlin.backend.konan.ir", + "org.jetbrains.kotlin.backend.konan.lower", + "org.jetbrains.kotlin.build", + "org.jetbrains.kotlin.build.report", + "org.jetbrains.kotlin.build.report.metrics", + "org.jetbrains.kotlin.build.report.statistics", + "org.jetbrains.kotlin.build.report.statistics.file", + "org.jetbrains.kotlin.buildtools.api", + "org.jetbrains.kotlin.buildtools.api.internal", + "org.jetbrains.kotlin.buildtools.api.internal.wrappers", + "org.jetbrains.kotlin.buildtools.api.jvm", + "org.jetbrains.kotlin.buildtools.internal", + "org.jetbrains.kotlin.builtins", + "org.jetbrains.kotlin.builtins.functions", + "org.jetbrains.kotlin.builtins.jvm", + "org.jetbrains.kotlin.builtins.konan", + "org.jetbrains.kotlin.cfg", + "org.jetbrains.kotlin.cfg.pseudocode", + "org.jetbrains.kotlin.cfg.pseudocode.instructions", + "org.jetbrains.kotlin.cfg.pseudocode.instructions.eval", + "org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps", + "org.jetbrains.kotlin.cfg.pseudocode.instructions.special", + "org.jetbrains.kotlin.cfg.pseudocodeTraverser", + "org.jetbrains.kotlin.cfg.variable", + "org.jetbrains.kotlin.checkers", + "org.jetbrains.kotlin.checkers.diagnostics", + "org.jetbrains.kotlin.checkers.diagnostics.factories", + "org.jetbrains.kotlin.checkers.utils", + "org.jetbrains.kotlin.cli.common", + "org.jetbrains.kotlin.cli.common.arguments", + "org.jetbrains.kotlin.cli.common.config", + "org.jetbrains.kotlin.cli.common.environment", + "org.jetbrains.kotlin.cli.common.extensions", + "org.jetbrains.kotlin.cli.common.fir", + "org.jetbrains.kotlin.cli.common.localfs", + "org.jetbrains.kotlin.cli.common.messages", + "org.jetbrains.kotlin.cli.common.modules", + "org.jetbrains.kotlin.cli.common.output", + "org.jetbrains.kotlin.cli.common.profiling", + "org.jetbrains.kotlin.cli.common.repl", + "org.jetbrains.kotlin.cli.js", + "org.jetbrains.kotlin.cli.js.klib", + "org.jetbrains.kotlin.cli.jvm", + "org.jetbrains.kotlin.cli.jvm.compiler", + "org.jetbrains.kotlin.cli.jvm.compiler.jarfs", + "org.jetbrains.kotlin.cli.jvm.compiler.legacy.pipeline", + "org.jetbrains.kotlin.cli.jvm.config", + "org.jetbrains.kotlin.cli.jvm.index", + "org.jetbrains.kotlin.cli.jvm.javac", + "org.jetbrains.kotlin.cli.jvm.modules", + "org.jetbrains.kotlin.cli.jvm.plugins", + "org.jetbrains.kotlin.cli.metadata", + "org.jetbrains.kotlin.cli.pipeline", + "org.jetbrains.kotlin.cli.pipeline.jvm", + "org.jetbrains.kotlin.cli.pipeline.metadata", + "org.jetbrains.kotlin.cli.pipeline.web", + "org.jetbrains.kotlin.cli.pipeline.web.js", + "org.jetbrains.kotlin.cli.pipeline.web.wasm", + "org.jetbrains.kotlin.cli.plugins", + "org.jetbrains.kotlin.codegen", + "org.jetbrains.kotlin.codegen.coroutines", + "org.jetbrains.kotlin.codegen.extensions", + "org.jetbrains.kotlin.codegen.inline", + "org.jetbrains.kotlin.codegen.inline.coroutines", + "org.jetbrains.kotlin.codegen.intrinsics", + "org.jetbrains.kotlin.codegen.optimization", + "org.jetbrains.kotlin.codegen.optimization.boxing", + "org.jetbrains.kotlin.codegen.optimization.common", + "org.jetbrains.kotlin.codegen.optimization.fixStack", + "org.jetbrains.kotlin.codegen.optimization.nullCheck", + "org.jetbrains.kotlin.codegen.optimization.temporaryVals", + "org.jetbrains.kotlin.codegen.optimization.transformer", + "org.jetbrains.kotlin.codegen.pseudoInsns", + "org.jetbrains.kotlin.codegen.serialization", + "org.jetbrains.kotlin.codegen.signature", + "org.jetbrains.kotlin.codegen.state", + "org.jetbrains.kotlin.codegen.when", + "org.jetbrains.kotlin.compiler.plugin", + "org.jetbrains.kotlin.compilerRunner", + "org.jetbrains.kotlin.config", + "org.jetbrains.kotlin.config.phaser", + "org.jetbrains.kotlin.constant", + "org.jetbrains.kotlin.container", + "org.jetbrains.kotlin.context", + "org.jetbrains.kotlin.contracts", + "org.jetbrains.kotlin.contracts.description", + "org.jetbrains.kotlin.contracts.description.expressions", + "org.jetbrains.kotlin.contracts.interpretation", + "org.jetbrains.kotlin.contracts.model", + "org.jetbrains.kotlin.contracts.model.functors", + "org.jetbrains.kotlin.contracts.model.structure", + "org.jetbrains.kotlin.contracts.model.visitors", + "org.jetbrains.kotlin.contracts.parsing", + "org.jetbrains.kotlin.contracts.parsing.effects", + "org.jetbrains.kotlin.coroutines", + "org.jetbrains.kotlin.daemon.client", + "org.jetbrains.kotlin.daemon.common", + "org.jetbrains.kotlin.descriptors", + "org.jetbrains.kotlin.descriptors.annotations", + "org.jetbrains.kotlin.descriptors.deserialization", + "org.jetbrains.kotlin.descriptors.impl", + "org.jetbrains.kotlin.descriptors.java", + "org.jetbrains.kotlin.descriptors.konan", + "org.jetbrains.kotlin.descriptors.runtime.components", + "org.jetbrains.kotlin.descriptors.runtime.structure", + "org.jetbrains.kotlin.descriptors.synthetic", + "org.jetbrains.kotlin.diagnostics", + "org.jetbrains.kotlin.diagnostics.impl", + "org.jetbrains.kotlin.diagnostics.rendering", + "org.jetbrains.kotlin.extensions", + "org.jetbrains.kotlin.extensions.internal", + "org.jetbrains.kotlin.fileClasses", + "org.jetbrains.kotlin.fir", + "org.jetbrains.kotlin.fir.analysis", + "org.jetbrains.kotlin.fir.analysis.cfa", + "org.jetbrains.kotlin.fir.analysis.cfa.util", + "org.jetbrains.kotlin.fir.analysis.checkers", + "org.jetbrains.kotlin.fir.analysis.checkers.cfa", + "org.jetbrains.kotlin.fir.analysis.checkers.config", + "org.jetbrains.kotlin.fir.analysis.checkers.context", + "org.jetbrains.kotlin.fir.analysis.checkers.declaration", + "org.jetbrains.kotlin.fir.analysis.checkers.experimental", + "org.jetbrains.kotlin.fir.analysis.checkers.expression", + "org.jetbrains.kotlin.fir.analysis.checkers.extra", + "org.jetbrains.kotlin.fir.analysis.checkers.syntax", + "org.jetbrains.kotlin.fir.analysis.checkers.type", + "org.jetbrains.kotlin.fir.analysis.collectors", + "org.jetbrains.kotlin.fir.analysis.collectors.components", + "org.jetbrains.kotlin.fir.analysis.diagnostics", + "org.jetbrains.kotlin.fir.analysis.diagnostics.js", + "org.jetbrains.kotlin.fir.analysis.diagnostics.jvm", + "org.jetbrains.kotlin.fir.analysis.diagnostics.native", + "org.jetbrains.kotlin.fir.analysis.diagnostics.wasm", + "org.jetbrains.kotlin.fir.analysis.diagnostics.web.common", + "org.jetbrains.kotlin.fir.analysis.extensions", + "org.jetbrains.kotlin.fir.analysis.js.checkers", + "org.jetbrains.kotlin.fir.analysis.js.checkers.declaration", + "org.jetbrains.kotlin.fir.analysis.js.checkers.expression", + "org.jetbrains.kotlin.fir.analysis.jvm", + "org.jetbrains.kotlin.fir.analysis.jvm.checkers", + "org.jetbrains.kotlin.fir.analysis.jvm.checkers.declaration", + "org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression", + "org.jetbrains.kotlin.fir.analysis.jvm.checkers.type", + "org.jetbrains.kotlin.fir.analysis.native.checkers", + "org.jetbrains.kotlin.fir.analysis.wasm.checkers", + "org.jetbrains.kotlin.fir.analysis.wasm.checkers.declaration", + "org.jetbrains.kotlin.fir.analysis.wasm.checkers.expression", + "org.jetbrains.kotlin.fir.analysis.web.common.checkers", + "org.jetbrains.kotlin.fir.analysis.web.common.checkers.declaration", + "org.jetbrains.kotlin.fir.analysis.web.common.checkers.expression", + "org.jetbrains.kotlin.fir.backend", + "org.jetbrains.kotlin.fir.backend.generators", + "org.jetbrains.kotlin.fir.backend.jvm", + "org.jetbrains.kotlin.fir.backend.native", + "org.jetbrains.kotlin.fir.backend.native.interop", + "org.jetbrains.kotlin.fir.backend.utils", + "org.jetbrains.kotlin.fir.builder", + "org.jetbrains.kotlin.fir.caches", + "org.jetbrains.kotlin.fir.checkers", + "org.jetbrains.kotlin.fir.contracts", + "org.jetbrains.kotlin.fir.contracts.builder", + "org.jetbrains.kotlin.fir.contracts.description", + "org.jetbrains.kotlin.fir.contracts.impl", + "org.jetbrains.kotlin.fir.declarations", + "org.jetbrains.kotlin.fir.declarations.builder", + "org.jetbrains.kotlin.fir.declarations.comparators", + "org.jetbrains.kotlin.fir.declarations.impl", + "org.jetbrains.kotlin.fir.declarations.synthetic", + "org.jetbrains.kotlin.fir.declarations.utils", + "org.jetbrains.kotlin.fir.descriptors", + "org.jetbrains.kotlin.fir.deserialization", + "org.jetbrains.kotlin.fir.diagnostics", + "org.jetbrains.kotlin.fir.expressions", + "org.jetbrains.kotlin.fir.expressions.builder", + "org.jetbrains.kotlin.fir.expressions.impl", + "org.jetbrains.kotlin.fir.extensions", + "org.jetbrains.kotlin.fir.extensions.predicate", + "org.jetbrains.kotlin.fir.extensions.utils", + "org.jetbrains.kotlin.fir.impl", + "org.jetbrains.kotlin.fir.java", + "org.jetbrains.kotlin.fir.java.declarations", + "org.jetbrains.kotlin.fir.java.deserialization", + "org.jetbrains.kotlin.fir.java.enhancement", + "org.jetbrains.kotlin.fir.java.scopes", + "org.jetbrains.kotlin.fir.java.symbols", + "org.jetbrains.kotlin.fir.lazy", + "org.jetbrains.kotlin.fir.modules", + "org.jetbrains.kotlin.fir.pipeline", + "org.jetbrains.kotlin.fir.plugin", + "org.jetbrains.kotlin.fir.references", + "org.jetbrains.kotlin.fir.references.builder", + "org.jetbrains.kotlin.fir.references.impl", + "org.jetbrains.kotlin.fir.renderer", + "org.jetbrains.kotlin.fir.resolve", + "org.jetbrains.kotlin.fir.resolve.calls", + "org.jetbrains.kotlin.fir.resolve.calls.candidate", + "org.jetbrains.kotlin.fir.resolve.calls.js", + "org.jetbrains.kotlin.fir.resolve.calls.jvm", + "org.jetbrains.kotlin.fir.resolve.calls.overloads", + "org.jetbrains.kotlin.fir.resolve.calls.stages", + "org.jetbrains.kotlin.fir.resolve.calls.tower", + "org.jetbrains.kotlin.fir.resolve.dfa", + "org.jetbrains.kotlin.fir.resolve.dfa.cfg", + "org.jetbrains.kotlin.fir.resolve.diagnostics", + "org.jetbrains.kotlin.fir.resolve.inference", + "org.jetbrains.kotlin.fir.resolve.inference.model", + "org.jetbrains.kotlin.fir.resolve.providers", + "org.jetbrains.kotlin.fir.resolve.providers.impl", + "org.jetbrains.kotlin.fir.resolve.scopes", + "org.jetbrains.kotlin.fir.resolve.substitution", + "org.jetbrains.kotlin.fir.resolve.transformers", + "org.jetbrains.kotlin.fir.resolve.transformers.body.resolve", + "org.jetbrains.kotlin.fir.resolve.transformers.contracts", + "org.jetbrains.kotlin.fir.resolve.transformers.mpp", + "org.jetbrains.kotlin.fir.resolve.transformers.plugin", + "org.jetbrains.kotlin.fir.scopes", + "org.jetbrains.kotlin.fir.scopes.impl", + "org.jetbrains.kotlin.fir.scopes.jvm", + "org.jetbrains.kotlin.fir.serialization", + "org.jetbrains.kotlin.fir.serialization.constant", + "org.jetbrains.kotlin.fir.session", + "org.jetbrains.kotlin.fir.session.environment", + "org.jetbrains.kotlin.fir.symbols", + "org.jetbrains.kotlin.fir.symbols.impl", + "org.jetbrains.kotlin.fir.types", + "org.jetbrains.kotlin.fir.types.builder", + "org.jetbrains.kotlin.fir.types.impl", + "org.jetbrains.kotlin.fir.types.jvm", + "org.jetbrains.kotlin.fir.util", + "org.jetbrains.kotlin.fir.utils.exceptions", + "org.jetbrains.kotlin.fir.visitors", + "org.jetbrains.kotlin.frontend.di", + "org.jetbrains.kotlin.frontend.java.di", + "org.jetbrains.kotlin.frontend.js.di", + "org.jetbrains.kotlin.idea", + "org.jetbrains.kotlin.idea.references", + "org.jetbrains.kotlin.incremental", + "org.jetbrains.kotlin.incremental.components", + "org.jetbrains.kotlin.incremental.impl", + "org.jetbrains.kotlin.incremental.js", + "org.jetbrains.kotlin.incremental.storage", + "org.jetbrains.kotlin.inline", + "org.jetbrains.kotlin.ir", + "org.jetbrains.kotlin.ir.backend.js", + "org.jetbrains.kotlin.ir.builders", + "org.jetbrains.kotlin.ir.builders.declarations", + "org.jetbrains.kotlin.ir.declarations", + "org.jetbrains.kotlin.ir.declarations.impl", + "org.jetbrains.kotlin.ir.declarations.lazy", + "org.jetbrains.kotlin.ir.descriptors", + "org.jetbrains.kotlin.ir.expressions", + "org.jetbrains.kotlin.ir.expressions.impl", + "org.jetbrains.kotlin.ir.inline", + "org.jetbrains.kotlin.ir.inline.konan", + "org.jetbrains.kotlin.ir.objcinterop", + "org.jetbrains.kotlin.ir.overrides", + "org.jetbrains.kotlin.ir.symbols", + "org.jetbrains.kotlin.ir.symbols.impl", + "org.jetbrains.kotlin.ir.types", + "org.jetbrains.kotlin.ir.types.impl", + "org.jetbrains.kotlin.ir.util", + "org.jetbrains.kotlin.ir.visitors", + "org.jetbrains.kotlin.js", + "org.jetbrains.kotlin.js.analyze", + "org.jetbrains.kotlin.js.analyzer", + "org.jetbrains.kotlin.js.backend", + "org.jetbrains.kotlin.js.backend.ast", + "org.jetbrains.kotlin.js.backend.ast.metadata", + "org.jetbrains.kotlin.js.common", + "org.jetbrains.kotlin.js.config", + "org.jetbrains.kotlin.js.descriptorUtils", + "org.jetbrains.kotlin.js.inline.clean", + "org.jetbrains.kotlin.js.inline.util", + "org.jetbrains.kotlin.js.inline.util.collectors", + "org.jetbrains.kotlin.js.naming", + "org.jetbrains.kotlin.js.parser", + "org.jetbrains.kotlin.js.parser.sourcemaps", + "org.jetbrains.kotlin.js.patterns", + "org.jetbrains.kotlin.js.resolve", + "org.jetbrains.kotlin.js.resolve.diagnostics", + "org.jetbrains.kotlin.js.sourceMap", + "org.jetbrains.kotlin.js.translate.context", + "org.jetbrains.kotlin.js.translate.utils", + "org.jetbrains.kotlin.js.util", + "org.jetbrains.kotlin.kapt3.diagnostic", + "org.jetbrains.kotlin.kdoc.lexer", + "org.jetbrains.kotlin.kdoc.parser", + "org.jetbrains.kotlin.kdoc.psi.api", + "org.jetbrains.kotlin.kdoc.psi.impl", + "org.jetbrains.kotlin.konan", + "org.jetbrains.kotlin.konan.exec", + "org.jetbrains.kotlin.konan.file", + "org.jetbrains.kotlin.konan.library", + "org.jetbrains.kotlin.konan.library.impl", + "org.jetbrains.kotlin.konan.properties", + "org.jetbrains.kotlin.konan.target", + "org.jetbrains.kotlin.konan.util", + "org.jetbrains.kotlin.lexer", + "org.jetbrains.kotlin.library", + "org.jetbrains.kotlin.library.abi", + "org.jetbrains.kotlin.library.abi.impl", + "org.jetbrains.kotlin.library.encodings", + "org.jetbrains.kotlin.library.impl", + "org.jetbrains.kotlin.library.metadata", + "org.jetbrains.kotlin.library.metadata.impl", + "org.jetbrains.kotlin.library.metadata.resolver", + "org.jetbrains.kotlin.library.metadata.resolver.impl", + "org.jetbrains.kotlin.light.classes.symbol", + "org.jetbrains.kotlin.light.classes.symbol.annotations", + "org.jetbrains.kotlin.light.classes.symbol.classes", + "org.jetbrains.kotlin.light.classes.symbol.codeReferences", + "org.jetbrains.kotlin.light.classes.symbol.fields", + "org.jetbrains.kotlin.light.classes.symbol.methods", + "org.jetbrains.kotlin.light.classes.symbol.modifierLists", + "org.jetbrains.kotlin.light.classes.symbol.parameters", + "org.jetbrains.kotlin.load.java", + "org.jetbrains.kotlin.load.java.components", + "org.jetbrains.kotlin.load.java.descriptors", + "org.jetbrains.kotlin.load.java.lazy", + "org.jetbrains.kotlin.load.java.lazy.descriptors", + "org.jetbrains.kotlin.load.java.lazy.types", + "org.jetbrains.kotlin.load.java.sam", + "org.jetbrains.kotlin.load.java.sources", + "org.jetbrains.kotlin.load.java.structure", + "org.jetbrains.kotlin.load.java.structure.impl", + "org.jetbrains.kotlin.load.java.structure.impl.classFiles", + "org.jetbrains.kotlin.load.java.structure.impl.source", + "org.jetbrains.kotlin.load.java.typeEnhancement", + "org.jetbrains.kotlin.load.kotlin", + "org.jetbrains.kotlin.load.kotlin.header", + "org.jetbrains.kotlin.load.kotlin.incremental", + "org.jetbrains.kotlin.load.kotlin.incremental.components", + "org.jetbrains.kotlin.metadata", + "org.jetbrains.kotlin.metadata.builtins", + "org.jetbrains.kotlin.metadata.deserialization", + "org.jetbrains.kotlin.metadata.java", + "org.jetbrains.kotlin.metadata.js", + "org.jetbrains.kotlin.metadata.jvm", + "org.jetbrains.kotlin.metadata.jvm.deserialization", + "org.jetbrains.kotlin.metadata.jvm.serialization", + "org.jetbrains.kotlin.metadata.serialization", + "org.jetbrains.kotlin.modules", + "org.jetbrains.kotlin.mpp", + "org.jetbrains.kotlin.name", + "org.jetbrains.kotlin.native.interop", + "org.jetbrains.kotlin.parsing", + "org.jetbrains.kotlin.platform", + "org.jetbrains.kotlin.platform.compat", + "org.jetbrains.kotlin.platform.impl", + "org.jetbrains.kotlin.platform.js", + "org.jetbrains.kotlin.platform.jvm", + "org.jetbrains.kotlin.platform.konan", + "org.jetbrains.kotlin.platform.wasm", + "org.jetbrains.kotlin.plugin.references", + "org.jetbrains.kotlin.preloading", + "org.jetbrains.kotlin.preloading.instrumentation", + "org.jetbrains.kotlin.preloading.instrumentation.annotations", + "org.jetbrains.kotlin.progress", + "org.jetbrains.kotlin.protobuf", + "org.jetbrains.kotlin.psi", + "org.jetbrains.kotlin.psi.addRemoveModifier", + "org.jetbrains.kotlin.psi.codeFragmentUtil", + "org.jetbrains.kotlin.psi.debugText", + "org.jetbrains.kotlin.psi.findDocComment", + "org.jetbrains.kotlin.psi.psiUtil", + "org.jetbrains.kotlin.psi.stubs", + "org.jetbrains.kotlin.psi.stubs.elements", + "org.jetbrains.kotlin.psi.stubs.impl", + "org.jetbrains.kotlin.psi.synthetics", + "org.jetbrains.kotlin.psi.typeRefHelpers", + "org.jetbrains.kotlin.psi2ir", + "org.jetbrains.kotlin.psi2ir.descriptors", + "org.jetbrains.kotlin.psi2ir.generators", + "org.jetbrains.kotlin.psi2ir.generators.fragments", + "org.jetbrains.kotlin.psi2ir.intermediate", + "org.jetbrains.kotlin.psi2ir.lazy", + "org.jetbrains.kotlin.psi2ir.preprocessing", + "org.jetbrains.kotlin.psi2ir.transformations", + "org.jetbrains.kotlin.references.fe10", + "org.jetbrains.kotlin.references.fe10.base", + "org.jetbrains.kotlin.references.fe10.util", + "org.jetbrains.kotlin.renderer", + "org.jetbrains.kotlin.resolve", + "org.jetbrains.kotlin.resolve.annotation", + "org.jetbrains.kotlin.resolve.annotations", + "org.jetbrains.kotlin.resolve.bindingContextUtil", + "org.jetbrains.kotlin.resolve.calls", + "org.jetbrains.kotlin.resolve.calls.callUtil", + "org.jetbrains.kotlin.resolve.calls.checkers", + "org.jetbrains.kotlin.resolve.calls.components", + "org.jetbrains.kotlin.resolve.calls.components.candidate", + "org.jetbrains.kotlin.resolve.calls.context", + "org.jetbrains.kotlin.resolve.calls.inference", + "org.jetbrains.kotlin.resolve.calls.inference.components", + "org.jetbrains.kotlin.resolve.calls.inference.constraintPosition", + "org.jetbrains.kotlin.resolve.calls.inference.model", + "org.jetbrains.kotlin.resolve.calls.model", + "org.jetbrains.kotlin.resolve.calls.mpp", + "org.jetbrains.kotlin.resolve.calls.results", + "org.jetbrains.kotlin.resolve.calls.smartcasts", + "org.jetbrains.kotlin.resolve.calls.tasks", + "org.jetbrains.kotlin.resolve.calls.tower", + "org.jetbrains.kotlin.resolve.calls.util", + "org.jetbrains.kotlin.resolve.checkers", + "org.jetbrains.kotlin.resolve.constants", + "org.jetbrains.kotlin.resolve.constants.evaluate", + "org.jetbrains.kotlin.resolve.deprecation", + "org.jetbrains.kotlin.resolve.descriptorUtil", + "org.jetbrains.kotlin.resolve.diagnostics", + "org.jetbrains.kotlin.resolve.extensions", + "org.jetbrains.kotlin.resolve.inline", + "org.jetbrains.kotlin.resolve.jvm", + "org.jetbrains.kotlin.resolve.jvm.annotations", + "org.jetbrains.kotlin.resolve.jvm.checkers", + "org.jetbrains.kotlin.resolve.jvm.diagnostics", + "org.jetbrains.kotlin.resolve.jvm.extensions", + "org.jetbrains.kotlin.resolve.jvm.jvmSignature", + "org.jetbrains.kotlin.resolve.jvm.kotlinSignature", + "org.jetbrains.kotlin.resolve.jvm.modules", + "org.jetbrains.kotlin.resolve.jvm.multiplatform", + "org.jetbrains.kotlin.resolve.jvm.platform", + "org.jetbrains.kotlin.resolve.konan.diagnostics", + "org.jetbrains.kotlin.resolve.konan.platform", + "org.jetbrains.kotlin.resolve.lazy", + "org.jetbrains.kotlin.resolve.lazy.data", + "org.jetbrains.kotlin.resolve.lazy.declarations", + "org.jetbrains.kotlin.resolve.lazy.descriptors", + "org.jetbrains.kotlin.resolve.multiplatform", + "org.jetbrains.kotlin.resolve.references", + "org.jetbrains.kotlin.resolve.repl", + "org.jetbrains.kotlin.resolve.sam", + "org.jetbrains.kotlin.resolve.scopes", + "org.jetbrains.kotlin.resolve.scopes.optimization", + "org.jetbrains.kotlin.resolve.scopes.receivers", + "org.jetbrains.kotlin.resolve.scopes.synthetic", + "org.jetbrains.kotlin.resolve.scopes.utils", + "org.jetbrains.kotlin.resolve.source", + "org.jetbrains.kotlin.resolve.typeApproximation", + "org.jetbrains.kotlin.resolve.typeBinding", + "org.jetbrains.kotlin.scripting", + "org.jetbrains.kotlin.scripting.compiler.plugin", + "org.jetbrains.kotlin.scripting.compiler.plugin.definitions", + "org.jetbrains.kotlin.scripting.compiler.plugin.dependencies", + "org.jetbrains.kotlin.scripting.compiler.plugin.extensions", + "org.jetbrains.kotlin.scripting.compiler.plugin.impl", + "org.jetbrains.kotlin.scripting.compiler.plugin.irLowerings", + "org.jetbrains.kotlin.scripting.compiler.plugin.repl", + "org.jetbrains.kotlin.scripting.compiler.plugin.repl.configuration", + "org.jetbrains.kotlin.scripting.compiler.plugin.repl.messages", + "org.jetbrains.kotlin.scripting.compiler.plugin.repl.reader", + "org.jetbrains.kotlin.scripting.compiler.plugin.repl.writer", + "org.jetbrains.kotlin.scripting.compiler.plugin.services", + "org.jetbrains.kotlin.scripting.configuration", + "org.jetbrains.kotlin.scripting.definitions", + "org.jetbrains.kotlin.scripting.extensions", + "org.jetbrains.kotlin.scripting.resolve", + "org.jetbrains.kotlin.serialization", + "org.jetbrains.kotlin.serialization.deserialization", + "org.jetbrains.kotlin.serialization.deserialization.builtins", + "org.jetbrains.kotlin.serialization.deserialization.descriptors", + "org.jetbrains.kotlin.serialization.js", + "org.jetbrains.kotlin.serialization.js.ast", + "org.jetbrains.kotlin.storage", + "org.jetbrains.kotlin.synthetic", + "org.jetbrains.kotlin.type", + "org.jetbrains.kotlin.types", + "org.jetbrains.kotlin.types.checker", + "org.jetbrains.kotlin.types.error", + "org.jetbrains.kotlin.types.expressions", + "org.jetbrains.kotlin.types.expressions.typeInfoFactory", + "org.jetbrains.kotlin.types.expressions.unqualifiedSuper", + "org.jetbrains.kotlin.types.extensions", + "org.jetbrains.kotlin.types.model", + "org.jetbrains.kotlin.types.typeUtil", + "org.jetbrains.kotlin.types.typesApproximation", + "org.jetbrains.kotlin.util", + "org.jetbrains.kotlin.util.capitalizeDecapitalize", + "org.jetbrains.kotlin.util.collectionUtils", + "org.jetbrains.kotlin.util.slicedMap", + "org.jetbrains.kotlin.util.vavr", + "org.jetbrains.kotlin.utils", + "org.jetbrains.kotlin.utils.addToStdlib", + "org.jetbrains.kotlin.utils.concurrent.block", + "org.jetbrains.kotlin.utils.exceptions", + "org.jetbrains.kotlin.utils.fileUtils", + "org.jetbrains.kotlin.utils.kapt", + "org.jetbrains.kotlin.utils.repl", + "org.jetbrains.kotlin.utils.strings", + "org.jetbrains.kotlin.wasm.analyze", + "org.jetbrains.kotlin.wasm.config", + "org.jetbrains.kotlin.wasm.resolve", + "org.jetbrains.kotlin.wasm.resolve.diagnostics", + "org.jetbrains.kotlin.wasm.util", + "org.jline.builtins", + "org.jline.builtins.ssh", + "org.jline.builtins.telnet", + "org.jline.console", + "org.jline.console.impl", + "org.jline.keymap", + "org.jline.nativ", + "org.jline.reader", + "org.jline.reader.impl", + "org.jline.reader.impl.completer", + "org.jline.reader.impl.history", + "org.jline.style", + "org.jline.terminal", + "org.jline.terminal.impl", + "org.jline.terminal.impl.exec", + "org.jline.terminal.impl.jansi", + "org.jline.terminal.impl.jansi.freebsd", + "org.jline.terminal.impl.jansi.linux", + "org.jline.terminal.impl.jansi.osx", + "org.jline.terminal.impl.jansi.solaris", + "org.jline.terminal.impl.jansi.win", + "org.jline.terminal.impl.jna", + "org.jline.terminal.impl.jna.freebsd", + "org.jline.terminal.impl.jna.linux", + "org.jline.terminal.impl.jna.osx", + "org.jline.terminal.impl.jna.solaris", + "org.jline.terminal.impl.jna.win", + "org.jline.terminal.impl.jni", + "org.jline.terminal.impl.jni.freebsd", + "org.jline.terminal.impl.jni.linux", + "org.jline.terminal.impl.jni.osx", + "org.jline.terminal.impl.jni.solaris", + "org.jline.terminal.impl.jni.win", + "org.jline.terminal.spi", + "org.jline.utils", + "org.jline.widget" + ], + "com.android.tools.external.org-jetbrains:uast": [ + "org.jetbrains.uast", + "org.jetbrains.uast.analysis", + "org.jetbrains.uast.evaluation", + "org.jetbrains.uast.expressions", + "org.jetbrains.uast.internal", + "org.jetbrains.uast.java", + "org.jetbrains.uast.java.declarations", + "org.jetbrains.uast.java.expressions", + "org.jetbrains.uast.java.internal", + "org.jetbrains.uast.java.kinds", + "org.jetbrains.uast.kotlin", + "org.jetbrains.uast.kotlin.evaluation", + "org.jetbrains.uast.kotlin.internal", + "org.jetbrains.uast.kotlin.kinds", + "org.jetbrains.uast.kotlin.psi", + "org.jetbrains.uast.psi", + "org.jetbrains.uast.util", + "org.jetbrains.uast.values", + "org.jetbrains.uast.visitor" + ], + "com.android.tools.layoutlib:layoutlib-api": [ + "com.android.ide.common.rendering.api", + "com.android.resources" + ], + "com.android.tools.lint:lint": [ + "com.android.tools.idea.gradle.dcl.lang", + "com.android.tools.idea.gradle.dcl.lang.lexer", + "com.android.tools.idea.gradle.dcl.lang.parser", + "com.android.tools.idea.gradle.dcl.lang.psi", + "com.android.tools.idea.gradle.dcl.lang.psi.impl", + "com.android.tools.lint", + "com.android.tools.lint.gradle", + "com.android.tools.lint.uast" + ], + "com.android.tools.lint:lint-api": [ + "com.android.tools.lint.client.api", + "com.android.tools.lint.detector.api", + "com.android.tools.lint.detector.api.interprocedural", + "com.android.tools.lint.helpers" + ], + "com.android.tools.lint:lint-checks": [ + "com.android.tools.lint.checks", + "com.android.tools.lint.checks.fx.utils", + "com.android.tools.lint.checks.optional", + "com.android.tools.lint.checks.plurals" + ], + "com.android.tools.lint:lint-gradle": [ + "com.android.tools.lint.annotations" + ], + "com.android.tools.lint:lint-model": [ + "com.android.tools.lint.model" + ], + "com.android.tools.lint:lint-typedef-remover": [ + "com.android.tools.lint.typedefs" + ], + "com.android.tools:annotations": [ + "com.android.annotations", + "com.android.annotations.concurrency" + ], + "com.android.tools:common": [ + "com.android", + "com.android.ide.common.blame", + "com.android.io", + "com.android.prefs", + "com.android.resources", + "com.android.sdklib", + "com.android.support", + "com.android.testing.utils", + "com.android.tools.proguard", + "com.android.utils", + "com.android.utils.cache", + "com.android.utils.concurrency", + "com.android.utils.cxx", + "com.android.utils.cxx.collections", + "com.android.utils.cxx.io", + "com.android.utils.cxx.ninja", + "com.android.utils.cxx.os", + "com.android.utils.cxx.process", + "com.android.utils.function", + "com.android.utils.reflection", + "com.android.utils.sleep", + "com.android.utils.text", + "com.android.xml", + "com.android.xml.sax" + ], + "com.android.tools:dvlib": [ + "com.android.dvlib" + ], + "com.android.tools:play-sdk-proto": [ + "com.android.tools.lint.checks" + ], + "com.android.tools:repository": [ + "com.android.repository", + "com.android.repository.api", + "com.android.repository.impl.downloader", + "com.android.repository.impl.generated.generic.v1", + "com.android.repository.impl.generated.generic.v2", + "com.android.repository.impl.generated.v1", + "com.android.repository.impl.generated.v2", + "com.android.repository.impl.installer", + "com.android.repository.impl.manager", + "com.android.repository.impl.meta", + "com.android.repository.impl.sources", + "com.android.repository.impl.sources.generated.v1", + "com.android.repository.io", + "com.android.repository.util" + ], + "com.android.tools:sdk-common": [ + "com.android.ide.common.blame", + "com.android.ide.common.blame.parser", + "com.android.ide.common.blame.parser.aapt", + "com.android.ide.common.blame.parser.util", + "com.android.ide.common.build", + "com.android.ide.common.caching", + "com.android.ide.common.fonts", + "com.android.ide.common.gradle", + "com.android.ide.common.internal", + "com.android.ide.common.pagealign", + "com.android.ide.common.process", + "com.android.ide.common.rendering", + "com.android.ide.common.repository", + "com.android.ide.common.resources", + "com.android.ide.common.resources.configuration", + "com.android.ide.common.resources.escape.string", + "com.android.ide.common.resources.escape.xml", + "com.android.ide.common.resources.sampledata", + "com.android.ide.common.resources.usage", + "com.android.ide.common.sdk", + "com.android.ide.common.signing", + "com.android.ide.common.symbols", + "com.android.ide.common.util", + "com.android.ide.common.vectordrawable", + "com.android.ide.common.workers", + "com.android.ide.common.xml", + "com.android.instantapp.provision", + "com.android.instantapp.run", + "com.android.instantapp.sdk", + "com.android.instantapp.utils", + "com.android.projectmodel", + "wireless.android.instantapps.sdk" + ], + "com.android.tools:sdklib": [ + "com.android.sdklib", + "com.android.sdklib.devices", + "com.android.sdklib.internal.avd", + "com.android.sdklib.internal.build", + "com.android.sdklib.internal.project", + "com.android.sdklib.repository", + "com.android.sdklib.repository.generated.addon.v1", + "com.android.sdklib.repository.generated.addon.v2", + "com.android.sdklib.repository.generated.addon.v3", + "com.android.sdklib.repository.generated.common.v1", + "com.android.sdklib.repository.generated.common.v2", + "com.android.sdklib.repository.generated.common.v3", + "com.android.sdklib.repository.generated.repository.v1", + "com.android.sdklib.repository.generated.repository.v2", + "com.android.sdklib.repository.generated.repository.v3", + "com.android.sdklib.repository.generated.sysimg.v1", + "com.android.sdklib.repository.generated.sysimg.v2", + "com.android.sdklib.repository.generated.sysimg.v3", + "com.android.sdklib.repository.generated.sysimg.v4", + "com.android.sdklib.repository.installer", + "com.android.sdklib.repository.legacy", + "com.android.sdklib.repository.legacy.descriptors", + "com.android.sdklib.repository.legacy.io", + "com.android.sdklib.repository.legacy.local", + "com.android.sdklib.repository.legacy.remote", + "com.android.sdklib.repository.legacy.remote.internal", + "com.android.sdklib.repository.legacy.remote.internal.archives", + "com.android.sdklib.repository.legacy.remote.internal.packages", + "com.android.sdklib.repository.legacy.remote.internal.sources", + "com.android.sdklib.repository.meta", + "com.android.sdklib.repository.sources", + "com.android.sdklib.repository.sources.generated.v1", + "com.android.sdklib.repository.sources.generated.v2", + "com.android.sdklib.repository.sources.generated.v3", + "com.android.sdklib.repository.sources.generated.v4", + "com.android.sdklib.repository.sources.generated.v5", + "com.android.sdklib.repository.sources.generated.v6", + "com.android.sdklib.repository.targets", + "com.android.sdklib.tool", + "com.android.sdklib.tool.sdkmanager", + "com.android.sdklib.util" + ], + "com.google.code.findbugs:jsr305": [ + "javax.annotation", + "javax.annotation.concurrent", + "javax.annotation.meta" + ], + "com.google.code.gson:gson": [ + "com.google.gson", + "com.google.gson.annotations", + "com.google.gson.internal", + "com.google.gson.internal.bind", + "com.google.gson.internal.bind.util", + "com.google.gson.internal.reflect", + "com.google.gson.internal.sql", + "com.google.gson.reflect", + "com.google.gson.stream" + ], + "com.google.errorprone:error_prone_annotations": [ + "com.google.errorprone.annotations", + "com.google.errorprone.annotations.concurrent" + ], + "com.google.guava:failureaccess": [ + "com.google.common.util.concurrent.internal" + ], + "com.google.guava:guava": [ + "com.google.common.annotations", + "com.google.common.base", + "com.google.common.base.internal", + "com.google.common.cache", + "com.google.common.collect", + "com.google.common.escape", + "com.google.common.eventbus", + "com.google.common.graph", + "com.google.common.hash", + "com.google.common.html", + "com.google.common.io", + "com.google.common.math", + "com.google.common.net", + "com.google.common.primitives", + "com.google.common.reflect", + "com.google.common.util.concurrent", + "com.google.common.xml", + "com.google.thirdparty.publicsuffix" + ], + "com.google.j2objc:j2objc-annotations": [ + "com.google.j2objc.annotations" + ], + "com.google.jimfs:jimfs": [ + "com.google.common.jimfs" + ], + "com.google.protobuf:protobuf-java": [ + "com.google.protobuf", + "com.google.protobuf.compiler" + ], + "com.sun.activation:javax.activation": [ + "com.sun.activation.registries", + "com.sun.activation.viewers", + "javax.activation" + ], + "com.sun.istack:istack-commons-runtime": [ + "com.sun.istack", + "com.sun.istack.localization", + "com.sun.istack.logging" + ], + "com.sun.xml.fastinfoset:FastInfoset": [ + "com.sun.xml.fastinfoset", + "com.sun.xml.fastinfoset.algorithm", + "com.sun.xml.fastinfoset.alphabet", + "com.sun.xml.fastinfoset.dom", + "com.sun.xml.fastinfoset.org.apache.xerces.util", + "com.sun.xml.fastinfoset.sax", + "com.sun.xml.fastinfoset.stax", + "com.sun.xml.fastinfoset.stax.events", + "com.sun.xml.fastinfoset.stax.factory", + "com.sun.xml.fastinfoset.stax.util", + "com.sun.xml.fastinfoset.tools", + "com.sun.xml.fastinfoset.util", + "com.sun.xml.fastinfoset.vocab", + "org.jvnet.fastinfoset", + "org.jvnet.fastinfoset.sax", + "org.jvnet.fastinfoset.sax.helpers", + "org.jvnet.fastinfoset.stax" + ], + "commons-codec:commons-codec": [ + "org.apache.commons.codec", + "org.apache.commons.codec.binary", + "org.apache.commons.codec.digest", + "org.apache.commons.codec.language", + "org.apache.commons.codec.language.bm", + "org.apache.commons.codec.net" + ], + "commons-io:commons-io": [ + "org.apache.commons.io", + "org.apache.commons.io.build", + "org.apache.commons.io.channels", + "org.apache.commons.io.charset", + "org.apache.commons.io.comparator", + "org.apache.commons.io.file", + "org.apache.commons.io.file.attribute", + "org.apache.commons.io.file.spi", + "org.apache.commons.io.filefilter", + "org.apache.commons.io.function", + "org.apache.commons.io.input", + "org.apache.commons.io.input.buffer", + "org.apache.commons.io.monitor", + "org.apache.commons.io.output", + "org.apache.commons.io.serialization" + ], + "commons-logging:commons-logging": [ + "org.apache.commons.logging", + "org.apache.commons.logging.impl" + ], + "jakarta.activation:jakarta.activation-api": [ + "javax.activation" + ], + "jakarta.xml.bind:jakarta.xml.bind-api": [ + "javax.xml.bind", + "javax.xml.bind.annotation", + "javax.xml.bind.annotation.adapters", + "javax.xml.bind.attachment", + "javax.xml.bind.helpers", + "javax.xml.bind.util" + ], + "javax.inject:javax.inject": [ + "javax.inject" + ], + "net.java.dev.jna:jna": [ + "com.sun.jna", + "com.sun.jna.internal", + "com.sun.jna.ptr", + "com.sun.jna.win32" + ], + "net.java.dev.jna:jna-platform": [ + "com.sun.jna.platform", + "com.sun.jna.platform.dnd", + "com.sun.jna.platform.linux", + "com.sun.jna.platform.mac", + "com.sun.jna.platform.unix", + "com.sun.jna.platform.unix.solaris", + "com.sun.jna.platform.win32", + "com.sun.jna.platform.win32.COM", + "com.sun.jna.platform.win32.COM.tlb", + "com.sun.jna.platform.win32.COM.tlb.imp", + "com.sun.jna.platform.win32.COM.util", + "com.sun.jna.platform.win32.COM.util.annotation", + "com.sun.jna.platform.wince" + ], + "net.sf.kxml:kxml2": [ + "org.kxml2.io", + "org.kxml2.kdom", + "org.kxml2.wap", + "org.kxml2.wap.syncml", + "org.kxml2.wap.wml", + "org.kxml2.wap.wv", + "org.xmlpull.v1" + ], + "org.apache.commons:commons-compress": [ + "org.apache.commons.compress", + "org.apache.commons.compress.archivers", + "org.apache.commons.compress.archivers.ar", + "org.apache.commons.compress.archivers.arj", + "org.apache.commons.compress.archivers.cpio", + "org.apache.commons.compress.archivers.dump", + "org.apache.commons.compress.archivers.examples", + "org.apache.commons.compress.archivers.jar", + "org.apache.commons.compress.archivers.sevenz", + "org.apache.commons.compress.archivers.tar", + "org.apache.commons.compress.archivers.zip", + "org.apache.commons.compress.changes", + "org.apache.commons.compress.compressors", + "org.apache.commons.compress.compressors.brotli", + "org.apache.commons.compress.compressors.bzip2", + "org.apache.commons.compress.compressors.deflate", + "org.apache.commons.compress.compressors.deflate64", + "org.apache.commons.compress.compressors.gzip", + "org.apache.commons.compress.compressors.lz4", + "org.apache.commons.compress.compressors.lz77support", + "org.apache.commons.compress.compressors.lzma", + "org.apache.commons.compress.compressors.lzw", + "org.apache.commons.compress.compressors.pack200", + "org.apache.commons.compress.compressors.snappy", + "org.apache.commons.compress.compressors.xz", + "org.apache.commons.compress.compressors.z", + "org.apache.commons.compress.compressors.zstandard", + "org.apache.commons.compress.harmony.archive.internal.nls", + "org.apache.commons.compress.harmony.pack200", + "org.apache.commons.compress.harmony.unpack200", + "org.apache.commons.compress.harmony.unpack200.bytecode", + "org.apache.commons.compress.harmony.unpack200.bytecode.forms", + "org.apache.commons.compress.java.util.jar", + "org.apache.commons.compress.parallel", + "org.apache.commons.compress.utils" + ], + "org.apache.httpcomponents:httpclient": [ + "org.apache.http.auth", + "org.apache.http.auth.params", + "org.apache.http.client", + "org.apache.http.client.config", + "org.apache.http.client.entity", + "org.apache.http.client.methods", + "org.apache.http.client.params", + "org.apache.http.client.protocol", + "org.apache.http.client.utils", + "org.apache.http.conn", + "org.apache.http.conn.params", + "org.apache.http.conn.routing", + "org.apache.http.conn.scheme", + "org.apache.http.conn.socket", + "org.apache.http.conn.ssl", + "org.apache.http.conn.util", + "org.apache.http.cookie", + "org.apache.http.cookie.params", + "org.apache.http.impl.auth", + "org.apache.http.impl.client", + "org.apache.http.impl.conn", + "org.apache.http.impl.conn.tsccm", + "org.apache.http.impl.cookie", + "org.apache.http.impl.execchain" + ], + "org.apache.httpcomponents:httpcore": [ + "org.apache.http", + "org.apache.http.annotation", + "org.apache.http.concurrent", + "org.apache.http.config", + "org.apache.http.entity", + "org.apache.http.impl", + "org.apache.http.impl.bootstrap", + "org.apache.http.impl.entity", + "org.apache.http.impl.io", + "org.apache.http.impl.pool", + "org.apache.http.io", + "org.apache.http.message", + "org.apache.http.params", + "org.apache.http.pool", + "org.apache.http.protocol", + "org.apache.http.ssl", + "org.apache.http.util" + ], + "org.apache.httpcomponents:httpmime": [ + "org.apache.http.entity.mime", + "org.apache.http.entity.mime.content" + ], + "org.bouncycastle:bcpkix-jdk18on": [ + "org.bouncycastle.cert", + "org.bouncycastle.cert.bc", + "org.bouncycastle.cert.cmp", + "org.bouncycastle.cert.crmf", + "org.bouncycastle.cert.crmf.bc", + "org.bouncycastle.cert.crmf.jcajce", + "org.bouncycastle.cert.dane", + "org.bouncycastle.cert.dane.fetcher", + "org.bouncycastle.cert.jcajce", + "org.bouncycastle.cert.ocsp", + "org.bouncycastle.cert.ocsp.jcajce", + "org.bouncycastle.cert.path", + "org.bouncycastle.cert.path.validations", + "org.bouncycastle.cert.selector", + "org.bouncycastle.cert.selector.jcajce", + "org.bouncycastle.cmc", + "org.bouncycastle.cms", + "org.bouncycastle.cms.bc", + "org.bouncycastle.cms.jcajce", + "org.bouncycastle.dvcs", + "org.bouncycastle.eac", + "org.bouncycastle.eac.jcajce", + "org.bouncycastle.eac.operator", + "org.bouncycastle.eac.operator.jcajce", + "org.bouncycastle.est", + "org.bouncycastle.est.jcajce", + "org.bouncycastle.its", + "org.bouncycastle.its.bc", + "org.bouncycastle.its.jcajce", + "org.bouncycastle.its.operator", + "org.bouncycastle.mime", + "org.bouncycastle.mime.encoding", + "org.bouncycastle.mime.smime", + "org.bouncycastle.mozilla", + "org.bouncycastle.mozilla.jcajce", + "org.bouncycastle.openssl", + "org.bouncycastle.openssl.bc", + "org.bouncycastle.openssl.jcajce", + "org.bouncycastle.operator", + "org.bouncycastle.operator.bc", + "org.bouncycastle.operator.jcajce", + "org.bouncycastle.pkcs", + "org.bouncycastle.pkcs.bc", + "org.bouncycastle.pkcs.jcajce", + "org.bouncycastle.pkix", + "org.bouncycastle.pkix.jcajce", + "org.bouncycastle.pkix.util", + "org.bouncycastle.pkix.util.filter", + "org.bouncycastle.tsp", + "org.bouncycastle.tsp.cms", + "org.bouncycastle.tsp.ers", + "org.bouncycastle.voms" + ], + "org.bouncycastle:bcprov-jdk18on": [ + "org.bouncycastle", + "org.bouncycastle.asn1", + "org.bouncycastle.asn1.anssi", + "org.bouncycastle.asn1.bc", + "org.bouncycastle.asn1.cryptopro", + "org.bouncycastle.asn1.gm", + "org.bouncycastle.asn1.nist", + "org.bouncycastle.asn1.ocsp", + "org.bouncycastle.asn1.pkcs", + "org.bouncycastle.asn1.sec", + "org.bouncycastle.asn1.teletrust", + "org.bouncycastle.asn1.ua", + "org.bouncycastle.asn1.util", + "org.bouncycastle.asn1.x500", + "org.bouncycastle.asn1.x500.style", + "org.bouncycastle.asn1.x509", + "org.bouncycastle.asn1.x509.qualified", + "org.bouncycastle.asn1.x509.sigi", + "org.bouncycastle.asn1.x9", + "org.bouncycastle.crypto", + "org.bouncycastle.crypto.agreement", + "org.bouncycastle.crypto.agreement.jpake", + "org.bouncycastle.crypto.agreement.kdf", + "org.bouncycastle.crypto.agreement.srp", + "org.bouncycastle.crypto.commitments", + "org.bouncycastle.crypto.constraints", + "org.bouncycastle.crypto.digests", + "org.bouncycastle.crypto.ec", + "org.bouncycastle.crypto.encodings", + "org.bouncycastle.crypto.engines", + "org.bouncycastle.crypto.examples", + "org.bouncycastle.crypto.fpe", + "org.bouncycastle.crypto.generators", + "org.bouncycastle.crypto.hpke", + "org.bouncycastle.crypto.io", + "org.bouncycastle.crypto.kems", + "org.bouncycastle.crypto.macs", + "org.bouncycastle.crypto.modes", + "org.bouncycastle.crypto.modes.gcm", + "org.bouncycastle.crypto.modes.kgcm", + "org.bouncycastle.crypto.paddings", + "org.bouncycastle.crypto.params", + "org.bouncycastle.crypto.parsers", + "org.bouncycastle.crypto.prng", + "org.bouncycastle.crypto.prng.drbg", + "org.bouncycastle.crypto.signers", + "org.bouncycastle.crypto.tls", + "org.bouncycastle.crypto.util", + "org.bouncycastle.i18n", + "org.bouncycastle.i18n.filter", + "org.bouncycastle.iana", + "org.bouncycastle.internal.asn1.bsi", + "org.bouncycastle.internal.asn1.cms", + "org.bouncycastle.internal.asn1.cryptlib", + "org.bouncycastle.internal.asn1.eac", + "org.bouncycastle.internal.asn1.edec", + "org.bouncycastle.internal.asn1.gnu", + "org.bouncycastle.internal.asn1.iana", + "org.bouncycastle.internal.asn1.isara", + "org.bouncycastle.internal.asn1.isismtt", + "org.bouncycastle.internal.asn1.iso", + "org.bouncycastle.internal.asn1.kisa", + "org.bouncycastle.internal.asn1.microsoft", + "org.bouncycastle.internal.asn1.misc", + "org.bouncycastle.internal.asn1.nsri", + "org.bouncycastle.internal.asn1.ntt", + "org.bouncycastle.internal.asn1.oiw", + "org.bouncycastle.internal.asn1.rosstandart", + "org.bouncycastle.jcajce", + "org.bouncycastle.jcajce.interfaces", + "org.bouncycastle.jcajce.io", + "org.bouncycastle.jcajce.provider.asymmetric", + "org.bouncycastle.jcajce.provider.asymmetric.compositesignatures", + "org.bouncycastle.jcajce.provider.asymmetric.dh", + "org.bouncycastle.jcajce.provider.asymmetric.dsa", + "org.bouncycastle.jcajce.provider.asymmetric.dstu", + "org.bouncycastle.jcajce.provider.asymmetric.ec", + "org.bouncycastle.jcajce.provider.asymmetric.ecgost", + "org.bouncycastle.jcajce.provider.asymmetric.ecgost12", + "org.bouncycastle.jcajce.provider.asymmetric.edec", + "org.bouncycastle.jcajce.provider.asymmetric.elgamal", + "org.bouncycastle.jcajce.provider.asymmetric.gost", + "org.bouncycastle.jcajce.provider.asymmetric.ies", + "org.bouncycastle.jcajce.provider.asymmetric.mldsa", + "org.bouncycastle.jcajce.provider.asymmetric.mlkem", + "org.bouncycastle.jcajce.provider.asymmetric.rsa", + "org.bouncycastle.jcajce.provider.asymmetric.slhdsa", + "org.bouncycastle.jcajce.provider.asymmetric.util", + "org.bouncycastle.jcajce.provider.asymmetric.x509", + "org.bouncycastle.jcajce.provider.config", + "org.bouncycastle.jcajce.provider.digest", + "org.bouncycastle.jcajce.provider.drbg", + "org.bouncycastle.jcajce.provider.keystore", + "org.bouncycastle.jcajce.provider.keystore.bc", + "org.bouncycastle.jcajce.provider.keystore.bcfks", + "org.bouncycastle.jcajce.provider.keystore.pkcs12", + "org.bouncycastle.jcajce.provider.keystore.util", + "org.bouncycastle.jcajce.provider.symmetric", + "org.bouncycastle.jcajce.provider.symmetric.util", + "org.bouncycastle.jcajce.provider.util", + "org.bouncycastle.jcajce.spec", + "org.bouncycastle.jcajce.util", + "org.bouncycastle.jce", + "org.bouncycastle.jce.exception", + "org.bouncycastle.jce.interfaces", + "org.bouncycastle.jce.netscape", + "org.bouncycastle.jce.provider", + "org.bouncycastle.jce.spec", + "org.bouncycastle.math", + "org.bouncycastle.math.ec", + "org.bouncycastle.math.ec.custom.djb", + "org.bouncycastle.math.ec.custom.gm", + "org.bouncycastle.math.ec.custom.sec", + "org.bouncycastle.math.ec.endo", + "org.bouncycastle.math.ec.rfc7748", + "org.bouncycastle.math.ec.rfc8032", + "org.bouncycastle.math.ec.tools", + "org.bouncycastle.math.field", + "org.bouncycastle.math.raw", + "org.bouncycastle.pqc.asn1", + "org.bouncycastle.pqc.crypto", + "org.bouncycastle.pqc.crypto.bike", + "org.bouncycastle.pqc.crypto.cmce", + "org.bouncycastle.pqc.crypto.crystals.dilithium", + "org.bouncycastle.pqc.crypto.falcon", + "org.bouncycastle.pqc.crypto.frodo", + "org.bouncycastle.pqc.crypto.gemss", + "org.bouncycastle.pqc.crypto.hqc", + "org.bouncycastle.pqc.crypto.lms", + "org.bouncycastle.pqc.crypto.mldsa", + "org.bouncycastle.pqc.crypto.mlkem", + "org.bouncycastle.pqc.crypto.newhope", + "org.bouncycastle.pqc.crypto.ntru", + "org.bouncycastle.pqc.crypto.ntruprime", + "org.bouncycastle.pqc.crypto.picnic", + "org.bouncycastle.pqc.crypto.rainbow", + "org.bouncycastle.pqc.crypto.saber", + "org.bouncycastle.pqc.crypto.slhdsa", + "org.bouncycastle.pqc.crypto.sphincs", + "org.bouncycastle.pqc.crypto.sphincsplus", + "org.bouncycastle.pqc.crypto.util", + "org.bouncycastle.pqc.crypto.xmss", + "org.bouncycastle.pqc.crypto.xwing", + "org.bouncycastle.pqc.jcajce.interfaces", + "org.bouncycastle.pqc.jcajce.provider", + "org.bouncycastle.pqc.jcajce.provider.bike", + "org.bouncycastle.pqc.jcajce.provider.cmce", + "org.bouncycastle.pqc.jcajce.provider.dilithium", + "org.bouncycastle.pqc.jcajce.provider.falcon", + "org.bouncycastle.pqc.jcajce.provider.frodo", + "org.bouncycastle.pqc.jcajce.provider.gmss", + "org.bouncycastle.pqc.jcajce.provider.hqc", + "org.bouncycastle.pqc.jcajce.provider.kyber", + "org.bouncycastle.pqc.jcajce.provider.lms", + "org.bouncycastle.pqc.jcajce.provider.mceliece", + "org.bouncycastle.pqc.jcajce.provider.newhope", + "org.bouncycastle.pqc.jcajce.provider.ntru", + "org.bouncycastle.pqc.jcajce.provider.ntruprime", + "org.bouncycastle.pqc.jcajce.provider.picnic", + "org.bouncycastle.pqc.jcajce.provider.rainbow", + "org.bouncycastle.pqc.jcajce.provider.saber", + "org.bouncycastle.pqc.jcajce.provider.sphincs", + "org.bouncycastle.pqc.jcajce.provider.sphincsplus", + "org.bouncycastle.pqc.jcajce.provider.util", + "org.bouncycastle.pqc.jcajce.provider.xmss", + "org.bouncycastle.pqc.jcajce.spec", + "org.bouncycastle.pqc.legacy.crypto.gmss", + "org.bouncycastle.pqc.legacy.crypto.gmss.util", + "org.bouncycastle.pqc.legacy.crypto.mceliece", + "org.bouncycastle.pqc.legacy.crypto.ntru", + "org.bouncycastle.pqc.legacy.crypto.qtesla", + "org.bouncycastle.pqc.legacy.crypto.rainbow", + "org.bouncycastle.pqc.legacy.crypto.rainbow.util", + "org.bouncycastle.pqc.legacy.math.linearalgebra", + "org.bouncycastle.pqc.legacy.math.ntru.euclid", + "org.bouncycastle.pqc.legacy.math.ntru.polynomial", + "org.bouncycastle.pqc.legacy.math.ntru.util", + "org.bouncycastle.pqc.math.ntru", + "org.bouncycastle.pqc.math.ntru.parameters", + "org.bouncycastle.util", + "org.bouncycastle.util.encoders", + "org.bouncycastle.util.io", + "org.bouncycastle.util.io.pem", + "org.bouncycastle.util.test", + "org.bouncycastle.x509", + "org.bouncycastle.x509.extension", + "org.bouncycastle.x509.util" + ], + "org.bouncycastle:bcutil-jdk18on": [ + "org.bouncycastle.asn1.bsi", + "org.bouncycastle.asn1.cmc", + "org.bouncycastle.asn1.cmp", + "org.bouncycastle.asn1.cms", + "org.bouncycastle.asn1.cms.ecc", + "org.bouncycastle.asn1.crmf", + "org.bouncycastle.asn1.cryptlib", + "org.bouncycastle.asn1.dvcs", + "org.bouncycastle.asn1.eac", + "org.bouncycastle.asn1.edec", + "org.bouncycastle.asn1.esf", + "org.bouncycastle.asn1.ess", + "org.bouncycastle.asn1.est", + "org.bouncycastle.asn1.gnu", + "org.bouncycastle.asn1.iana", + "org.bouncycastle.asn1.icao", + "org.bouncycastle.asn1.isara", + "org.bouncycastle.asn1.isismtt", + "org.bouncycastle.asn1.isismtt.ocsp", + "org.bouncycastle.asn1.isismtt.x509", + "org.bouncycastle.asn1.iso", + "org.bouncycastle.asn1.kisa", + "org.bouncycastle.asn1.microsoft", + "org.bouncycastle.asn1.misc", + "org.bouncycastle.asn1.mozilla", + "org.bouncycastle.asn1.nsri", + "org.bouncycastle.asn1.ntt", + "org.bouncycastle.asn1.oiw", + "org.bouncycastle.asn1.rosstandart", + "org.bouncycastle.asn1.smime", + "org.bouncycastle.asn1.tsp", + "org.bouncycastle.oer", + "org.bouncycastle.oer.its", + "org.bouncycastle.oer.its.etsi102941", + "org.bouncycastle.oer.its.etsi102941.basetypes", + "org.bouncycastle.oer.its.etsi103097", + "org.bouncycastle.oer.its.etsi103097.extension", + "org.bouncycastle.oer.its.ieee1609dot2", + "org.bouncycastle.oer.its.ieee1609dot2.basetypes", + "org.bouncycastle.oer.its.ieee1609dot2dot1", + "org.bouncycastle.oer.its.template.etsi102941", + "org.bouncycastle.oer.its.template.etsi102941.basetypes", + "org.bouncycastle.oer.its.template.etsi103097", + "org.bouncycastle.oer.its.template.etsi103097.extension", + "org.bouncycastle.oer.its.template.ieee1609dot2", + "org.bouncycastle.oer.its.template.ieee1609dot2.basetypes", + "org.bouncycastle.oer.its.template.ieee1609dot2dot1" + ], + "org.checkerframework:checker-qual": [ + "org.checkerframework.checker.builder.qual", + "org.checkerframework.checker.calledmethods.qual", + "org.checkerframework.checker.compilermsgs.qual", + "org.checkerframework.checker.fenum.qual", + "org.checkerframework.checker.formatter.qual", + "org.checkerframework.checker.guieffect.qual", + "org.checkerframework.checker.i18n.qual", + "org.checkerframework.checker.i18nformatter.qual", + "org.checkerframework.checker.index.qual", + "org.checkerframework.checker.initialization.qual", + "org.checkerframework.checker.interning.qual", + "org.checkerframework.checker.lock.qual", + "org.checkerframework.checker.mustcall.qual", + "org.checkerframework.checker.nullness.qual", + "org.checkerframework.checker.optional.qual", + "org.checkerframework.checker.propkey.qual", + "org.checkerframework.checker.regex.qual", + "org.checkerframework.checker.signature.qual", + "org.checkerframework.checker.signedness.qual", + "org.checkerframework.checker.tainting.qual", + "org.checkerframework.checker.units.qual", + "org.checkerframework.common.aliasing.qual", + "org.checkerframework.common.initializedfields.qual", + "org.checkerframework.common.reflection.qual", + "org.checkerframework.common.returnsreceiver.qual", + "org.checkerframework.common.subtyping.qual", + "org.checkerframework.common.util.count.report.qual", + "org.checkerframework.common.value.qual", + "org.checkerframework.dataflow.qual", + "org.checkerframework.framework.qual" + ], + "org.codehaus.groovy:groovy": [ + "groovy.beans", + "groovy.cli", + "groovy.cli.internal", + "groovy.grape", + "groovy.inspect", + "groovy.io", + "groovy.lang", + "groovy.lang.groovydoc", + "groovy.namespace", + "groovy.security", + "groovy.time", + "groovy.transform", + "groovy.transform.builder", + "groovy.transform.options", + "groovy.transform.stc", + "groovy.ui", + "groovy.util", + "groovy.util.logging", + "groovy.xml", + "groovyjarjarantlr", + "groovyjarjarantlr.ASdebug", + "groovyjarjarantlr.actions.cpp", + "groovyjarjarantlr.actions.csharp", + "groovyjarjarantlr.actions.java", + "groovyjarjarantlr.actions.python", + "groovyjarjarantlr.build", + "groovyjarjarantlr.collections", + "groovyjarjarantlr.collections.impl", + "groovyjarjarantlr.debug", + "groovyjarjarantlr.debug.misc", + "groovyjarjarantlr.preprocessor", + "groovyjarjarantlr4.runtime", + "groovyjarjarantlr4.runtime.debug", + "groovyjarjarantlr4.runtime.misc", + "groovyjarjarantlr4.runtime.tree", + "groovyjarjarantlr4.v4", + "groovyjarjarantlr4.v4.analysis", + "groovyjarjarantlr4.v4.automata", + "groovyjarjarantlr4.v4.codegen", + "groovyjarjarantlr4.v4.codegen.model", + "groovyjarjarantlr4.v4.codegen.model.chunk", + "groovyjarjarantlr4.v4.codegen.model.decl", + "groovyjarjarantlr4.v4.codegen.target", + "groovyjarjarantlr4.v4.gui", + "groovyjarjarantlr4.v4.misc", + "groovyjarjarantlr4.v4.parse", + "groovyjarjarantlr4.v4.runtime", + "groovyjarjarantlr4.v4.runtime.atn", + "groovyjarjarantlr4.v4.runtime.dfa", + "groovyjarjarantlr4.v4.runtime.misc", + "groovyjarjarantlr4.v4.runtime.tree", + "groovyjarjarantlr4.v4.runtime.tree.pattern", + "groovyjarjarantlr4.v4.runtime.tree.xpath", + "groovyjarjarantlr4.v4.semantics", + "groovyjarjarantlr4.v4.tool", + "groovyjarjarantlr4.v4.tool.ast", + "groovyjarjarantlr4.v4.unicode", + "groovyjarjarasm.asm", + "groovyjarjarasm.asm.commons", + "groovyjarjarasm.asm.signature", + "groovyjarjarasm.asm.tree", + "groovyjarjarasm.asm.util", + "groovyjarjarpicocli", + "org.apache.groovy.antlr", + "org.apache.groovy.ast.tools", + "org.apache.groovy.internal.metaclass", + "org.apache.groovy.internal.util", + "org.apache.groovy.io", + "org.apache.groovy.lang.annotation", + "org.apache.groovy.metaclass", + "org.apache.groovy.parser.antlr4", + "org.apache.groovy.parser.antlr4.internal", + "org.apache.groovy.parser.antlr4.internal.atnmanager", + "org.apache.groovy.parser.antlr4.util", + "org.apache.groovy.plugin", + "org.apache.groovy.util", + "org.apache.groovy.util.concurrent", + "org.apache.groovy.util.concurrent.concurrentlinkedhashmap", + "org.codehaus.groovy", + "org.codehaus.groovy.antlr", + "org.codehaus.groovy.antlr.java", + "org.codehaus.groovy.antlr.parser", + "org.codehaus.groovy.antlr.treewalker", + "org.codehaus.groovy.ast", + "org.codehaus.groovy.ast.builder", + "org.codehaus.groovy.ast.decompiled", + "org.codehaus.groovy.ast.expr", + "org.codehaus.groovy.ast.stmt", + "org.codehaus.groovy.ast.tools", + "org.codehaus.groovy.classgen", + "org.codehaus.groovy.classgen.asm", + "org.codehaus.groovy.classgen.asm.indy", + "org.codehaus.groovy.classgen.asm.indy.sc", + "org.codehaus.groovy.classgen.asm.sc", + "org.codehaus.groovy.classgen.asm.util", + "org.codehaus.groovy.control", + "org.codehaus.groovy.control.customizers", + "org.codehaus.groovy.control.customizers.builder", + "org.codehaus.groovy.control.io", + "org.codehaus.groovy.control.messages", + "org.codehaus.groovy.plugin", + "org.codehaus.groovy.reflection", + "org.codehaus.groovy.reflection.android", + "org.codehaus.groovy.reflection.stdclasses", + "org.codehaus.groovy.reflection.v7", + "org.codehaus.groovy.runtime", + "org.codehaus.groovy.runtime.callsite", + "org.codehaus.groovy.runtime.dgmimpl", + "org.codehaus.groovy.runtime.dgmimpl.arrays", + "org.codehaus.groovy.runtime.m12n", + "org.codehaus.groovy.runtime.memoize", + "org.codehaus.groovy.runtime.metaclass", + "org.codehaus.groovy.runtime.powerassert", + "org.codehaus.groovy.runtime.typehandling", + "org.codehaus.groovy.runtime.wrappers", + "org.codehaus.groovy.syntax", + "org.codehaus.groovy.tools", + "org.codehaus.groovy.tools.ast", + "org.codehaus.groovy.tools.gse", + "org.codehaus.groovy.tools.javac", + "org.codehaus.groovy.tools.shell", + "org.codehaus.groovy.tools.shell.util", + "org.codehaus.groovy.transform", + "org.codehaus.groovy.transform.sc", + "org.codehaus.groovy.transform.sc.transformers", + "org.codehaus.groovy.transform.stc", + "org.codehaus.groovy.transform.tailrec", + "org.codehaus.groovy.transform.trait", + "org.codehaus.groovy.util", + "org.codehaus.groovy.vmplugin", + "org.codehaus.groovy.vmplugin.v5", + "org.codehaus.groovy.vmplugin.v6", + "org.codehaus.groovy.vmplugin.v7", + "org.codehaus.groovy.vmplugin.v8", + "org.codehaus.groovy.vmplugin.v9" + ], + "org.glassfish.jaxb:jaxb-runtime": [ + "com.sun.xml.bind", + "com.sun.xml.bind.annotation", + "com.sun.xml.bind.api", + "com.sun.xml.bind.api.impl", + "com.sun.xml.bind.marshaller", + "com.sun.xml.bind.unmarshaller", + "com.sun.xml.bind.util", + "com.sun.xml.bind.v2", + "com.sun.xml.bind.v2.bytecode", + "com.sun.xml.bind.v2.model.annotation", + "com.sun.xml.bind.v2.model.core", + "com.sun.xml.bind.v2.model.impl", + "com.sun.xml.bind.v2.model.nav", + "com.sun.xml.bind.v2.model.runtime", + "com.sun.xml.bind.v2.model.util", + "com.sun.xml.bind.v2.runtime", + "com.sun.xml.bind.v2.runtime.output", + "com.sun.xml.bind.v2.runtime.property", + "com.sun.xml.bind.v2.runtime.reflect", + "com.sun.xml.bind.v2.runtime.reflect.opt", + "com.sun.xml.bind.v2.runtime.unmarshaller", + "com.sun.xml.bind.v2.schemagen", + "com.sun.xml.bind.v2.schemagen.episode", + "com.sun.xml.bind.v2.schemagen.xmlschema", + "com.sun.xml.bind.v2.util" + ], + "org.glassfish.jaxb:txw2": [ + "com.sun.xml.txw2", + "com.sun.xml.txw2.annotation", + "com.sun.xml.txw2.output" + ], + "org.jetbrains.kotlin:kotlin-reflect": [ + "kotlin.reflect.full", + "kotlin.reflect.jvm", + "kotlin.reflect.jvm.internal", + "kotlin.reflect.jvm.internal.calls", + "kotlin.reflect.jvm.internal.impl", + "kotlin.reflect.jvm.internal.impl.builtins", + "kotlin.reflect.jvm.internal.impl.builtins.functions", + "kotlin.reflect.jvm.internal.impl.builtins.jvm", + "kotlin.reflect.jvm.internal.impl.descriptors", + "kotlin.reflect.jvm.internal.impl.descriptors.annotations", + "kotlin.reflect.jvm.internal.impl.descriptors.deserialization", + "kotlin.reflect.jvm.internal.impl.descriptors.impl", + "kotlin.reflect.jvm.internal.impl.descriptors.java", + "kotlin.reflect.jvm.internal.impl.descriptors.runtime.components", + "kotlin.reflect.jvm.internal.impl.descriptors.runtime.structure", + "kotlin.reflect.jvm.internal.impl.incremental", + "kotlin.reflect.jvm.internal.impl.incremental.components", + "kotlin.reflect.jvm.internal.impl.load.java", + "kotlin.reflect.jvm.internal.impl.load.java.components", + "kotlin.reflect.jvm.internal.impl.load.java.descriptors", + "kotlin.reflect.jvm.internal.impl.load.java.lazy", + "kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors", + "kotlin.reflect.jvm.internal.impl.load.java.lazy.types", + "kotlin.reflect.jvm.internal.impl.load.java.sources", + "kotlin.reflect.jvm.internal.impl.load.java.structure", + "kotlin.reflect.jvm.internal.impl.load.java.typeEnhancement", + "kotlin.reflect.jvm.internal.impl.load.kotlin", + "kotlin.reflect.jvm.internal.impl.load.kotlin.header", + "kotlin.reflect.jvm.internal.impl.metadata", + "kotlin.reflect.jvm.internal.impl.metadata.builtins", + "kotlin.reflect.jvm.internal.impl.metadata.deserialization", + "kotlin.reflect.jvm.internal.impl.metadata.jvm", + "kotlin.reflect.jvm.internal.impl.metadata.jvm.deserialization", + "kotlin.reflect.jvm.internal.impl.name", + "kotlin.reflect.jvm.internal.impl.platform", + "kotlin.reflect.jvm.internal.impl.protobuf", + "kotlin.reflect.jvm.internal.impl.renderer", + "kotlin.reflect.jvm.internal.impl.resolve", + "kotlin.reflect.jvm.internal.impl.resolve.calls.inference", + "kotlin.reflect.jvm.internal.impl.resolve.constants", + "kotlin.reflect.jvm.internal.impl.resolve.deprecation", + "kotlin.reflect.jvm.internal.impl.resolve.descriptorUtil", + "kotlin.reflect.jvm.internal.impl.resolve.jvm", + "kotlin.reflect.jvm.internal.impl.resolve.sam", + "kotlin.reflect.jvm.internal.impl.resolve.scopes", + "kotlin.reflect.jvm.internal.impl.resolve.scopes.receivers", + "kotlin.reflect.jvm.internal.impl.serialization", + "kotlin.reflect.jvm.internal.impl.serialization.deserialization", + "kotlin.reflect.jvm.internal.impl.serialization.deserialization.builtins", + "kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors", + "kotlin.reflect.jvm.internal.impl.storage", + "kotlin.reflect.jvm.internal.impl.types", + "kotlin.reflect.jvm.internal.impl.types.checker", + "kotlin.reflect.jvm.internal.impl.types.error", + "kotlin.reflect.jvm.internal.impl.types.extensions", + "kotlin.reflect.jvm.internal.impl.types.model", + "kotlin.reflect.jvm.internal.impl.types.typeUtil", + "kotlin.reflect.jvm.internal.impl.types.typesApproximation", + "kotlin.reflect.jvm.internal.impl.util", + "kotlin.reflect.jvm.internal.impl.util.capitalizeDecapitalize", + "kotlin.reflect.jvm.internal.impl.util.collectionUtils", + "kotlin.reflect.jvm.internal.impl.utils", + "kotlin.reflect.jvm.internal.impl.utils.addToStdlib" + ], + "org.jetbrains.kotlin:kotlin-stdlib": [ + "kotlin", + "kotlin.annotation", + "kotlin.collections", + "kotlin.collections.builders", + "kotlin.collections.jdk8", + "kotlin.collections.unsigned", + "kotlin.comparisons", + "kotlin.concurrent", + "kotlin.concurrent.atomics", + "kotlin.concurrent.internal", + "kotlin.contracts", + "kotlin.coroutines", + "kotlin.coroutines.cancellation", + "kotlin.coroutines.intrinsics", + "kotlin.coroutines.jvm.internal", + "kotlin.enums", + "kotlin.experimental", + "kotlin.internal", + "kotlin.internal.jdk7", + "kotlin.internal.jdk8", + "kotlin.io", + "kotlin.io.encoding", + "kotlin.io.path", + "kotlin.jdk7", + "kotlin.js", + "kotlin.jvm", + "kotlin.jvm.functions", + "kotlin.jvm.internal", + "kotlin.jvm.internal.markers", + "kotlin.jvm.internal.unsafe", + "kotlin.jvm.jdk8", + "kotlin.jvm.optionals", + "kotlin.math", + "kotlin.properties", + "kotlin.random", + "kotlin.random.jdk8", + "kotlin.ranges", + "kotlin.reflect", + "kotlin.sequences", + "kotlin.streams.jdk8", + "kotlin.system", + "kotlin.text", + "kotlin.text.jdk8", + "kotlin.time", + "kotlin.time.jdk8", + "kotlin.uuid" + ], + "org.jetbrains:annotations": [ + "org.intellij.lang.annotations", + "org.jetbrains.annotations" + ], + "org.jvnet.staxex:stax-ex": [ + "org.jvnet.staxex", + "org.jvnet.staxex.util" + ], + "org.ow2.asm:asm": [ + "org.objectweb.asm", + "org.objectweb.asm.signature" + ], + "org.ow2.asm:asm-analysis": [ + "org.objectweb.asm.tree.analysis" + ], + "org.ow2.asm:asm-commons": [ + "org.objectweb.asm.commons" + ], + "org.ow2.asm:asm-tree": [ + "org.objectweb.asm.tree" + ] + }, + "repositories": { + "https://repo.maven.apache.org/maven2/": [ + "com.android.tools.analytics-library:protos", + "com.android.tools.analytics-library:shared", + "com.android.tools.analytics-library:tracker", + "com.android.tools.build:aapt2-proto", + "com.android.tools.build:builder-model", + "com.android.tools.build:manifest-merger", + "com.android.tools.ddms:ddmlib", + "com.android.tools.external.com-intellij:intellij-core", + "com.android.tools.external.com-intellij:kotlin-compiler", + "com.android.tools.external.org-jetbrains:uast", + "com.android.tools.layoutlib:layoutlib-api", + "com.android.tools.lint:lint", + "com.android.tools.lint:lint-api", + "com.android.tools.lint:lint-checks", + "com.android.tools.lint:lint-gradle", + "com.android.tools.lint:lint-model", + "com.android.tools.lint:lint-typedef-remover", + "com.android.tools:annotations", + "com.android.tools:common", + "com.android.tools:dvlib", + "com.android.tools:play-sdk-proto", + "com.android.tools:repository", + "com.android.tools:sdk-common", + "com.android.tools:sdklib", + "com.google.code.findbugs:jsr305", + "com.google.code.gson:gson", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:failureaccess", + "com.google.guava:guava", + "com.google.guava:listenablefuture", + "com.google.j2objc:j2objc-annotations", + "com.google.jimfs:jimfs", + "com.google.protobuf:protobuf-java", + "com.sun.activation:javax.activation", + "com.sun.istack:istack-commons-runtime", + "com.sun.xml.fastinfoset:FastInfoset", + "commons-codec:commons-codec", + "commons-io:commons-io", + "commons-logging:commons-logging", + "jakarta.activation:jakarta.activation-api", + "jakarta.xml.bind:jakarta.xml.bind-api", + "javax.inject:javax.inject", + "net.java.dev.jna:jna", + "net.java.dev.jna:jna-platform", + "net.sf.kxml:kxml2", + "org.apache.commons:commons-compress", + "org.apache.httpcomponents:httpclient", + "org.apache.httpcomponents:httpcore", + "org.apache.httpcomponents:httpmime", + "org.bouncycastle:bcpkix-jdk18on", + "org.bouncycastle:bcprov-jdk18on", + "org.bouncycastle:bcutil-jdk18on", + "org.checkerframework:checker-qual", + "org.codehaus.groovy:groovy", + "org.glassfish.jaxb:jaxb-runtime", + "org.glassfish.jaxb:txw2", + "org.jetbrains.kotlin:kotlin-reflect", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlin:kotlin-stdlib-jdk7", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8", + "org.jetbrains:annotations", + "org.jvnet.staxex:stax-ex", + "org.ow2.asm:asm", + "org.ow2.asm:asm-analysis", + "org.ow2.asm:asm-commons", + "org.ow2.asm:asm-tree" + ], + "https://dl.google.com/dl/android/maven2/": [ + "com.android.tools.analytics-library:protos", + "com.android.tools.analytics-library:shared", + "com.android.tools.analytics-library:tracker", + "com.android.tools.build:aapt2-proto", + "com.android.tools.build:builder-model", + "com.android.tools.build:manifest-merger", + "com.android.tools.ddms:ddmlib", + "com.android.tools.external.com-intellij:intellij-core", + "com.android.tools.external.com-intellij:kotlin-compiler", + "com.android.tools.external.org-jetbrains:uast", + "com.android.tools.layoutlib:layoutlib-api", + "com.android.tools.lint:lint", + "com.android.tools.lint:lint-api", + "com.android.tools.lint:lint-checks", + "com.android.tools.lint:lint-gradle", + "com.android.tools.lint:lint-model", + "com.android.tools.lint:lint-typedef-remover", + "com.android.tools:annotations", + "com.android.tools:common", + "com.android.tools:dvlib", + "com.android.tools:play-sdk-proto", + "com.android.tools:repository", + "com.android.tools:sdk-common", + "com.android.tools:sdklib", + "com.google.code.findbugs:jsr305", + "com.google.code.gson:gson", + "com.google.errorprone:error_prone_annotations", + "com.google.guava:failureaccess", + "com.google.guava:guava", + "com.google.guava:listenablefuture", + "com.google.j2objc:j2objc-annotations", + "com.google.jimfs:jimfs", + "com.google.protobuf:protobuf-java", + "com.sun.activation:javax.activation", + "com.sun.istack:istack-commons-runtime", + "com.sun.xml.fastinfoset:FastInfoset", + "commons-codec:commons-codec", + "commons-io:commons-io", + "commons-logging:commons-logging", + "jakarta.activation:jakarta.activation-api", + "jakarta.xml.bind:jakarta.xml.bind-api", + "javax.inject:javax.inject", + "net.java.dev.jna:jna", + "net.java.dev.jna:jna-platform", + "net.sf.kxml:kxml2", + "org.apache.commons:commons-compress", + "org.apache.httpcomponents:httpclient", + "org.apache.httpcomponents:httpcore", + "org.apache.httpcomponents:httpmime", + "org.bouncycastle:bcpkix-jdk18on", + "org.bouncycastle:bcprov-jdk18on", + "org.bouncycastle:bcutil-jdk18on", + "org.checkerframework:checker-qual", + "org.codehaus.groovy:groovy", + "org.glassfish.jaxb:jaxb-runtime", + "org.glassfish.jaxb:txw2", + "org.jetbrains.kotlin:kotlin-reflect", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlin:kotlin-stdlib-jdk7", + "org.jetbrains.kotlin:kotlin-stdlib-jdk8", + "org.jetbrains:annotations", + "org.jvnet.staxex:stax-ex", + "org.ow2.asm:asm", + "org.ow2.asm:asm-analysis", + "org.ow2.asm:asm-commons", + "org.ow2.asm:asm-tree" + ] + }, + "services": { + "com.android.tools.external.com-intellij:intellij-core": { + "com.intellij.platform.jps.model.resolver.JpsDependencyResolverConfigurationService": [ + "com.intellij.platform.jps.model.impl.resolver.JpsDependencyResolverConfigurationServiceImpl" + ], + "com.intellij.platform.workspace.jps.bridge.JpsModuleExtensionBridge": [ + "com.intellij.platform.workspace.jps.bridge.impl.serialization.DefaultFacetAsModuleExtensionBridge" + ], + "javax.xml.stream.XMLEventFactory": [ + "com.fasterxml.aalto.stax.EventFactoryImpl" + ], + "javax.xml.stream.XMLInputFactory": [ + "com.fasterxml.aalto.stax.InputFactoryImpl" + ], + "javax.xml.stream.XMLOutputFactory": [ + "com.fasterxml.aalto.stax.OutputFactoryImpl" + ], + "org.jetbrains.jps.model.JpsElementFactory": [ + "org.jetbrains.jps.model.impl.JpsElementFactoryImpl" + ], + "org.jetbrains.jps.model.JpsEncodingConfigurationService": [ + "org.jetbrains.jps.model.impl.JpsEncodingConfigurationServiceImpl" + ], + "org.jetbrains.jps.model.artifact.JpsArtifactService": [ + "org.jetbrains.jps.model.artifact.impl.JpsArtifactServiceImpl" + ], + "org.jetbrains.jps.model.artifact.elements.JpsPackagingElementFactory": [ + "org.jetbrains.jps.model.artifact.impl.elements.JpsPackagingElementFactoryImpl" + ], + "org.jetbrains.jps.model.ex.JpsExElementFactory": [ + "org.jetbrains.jps.model.impl.JpsExElementFactoryImpl" + ], + "org.jetbrains.jps.model.ex.JpsReferenceCustomFactory": [ + "com.intellij.platform.workspace.jps.bridge.impl.JpsReferenceCustomFactoryImpl" + ], + "org.jetbrains.jps.model.fileTypes.FileNameMatcherFactory": [ + "org.jetbrains.jps.model.fileTypes.impl.FileNameMatcherFactoryImpl" + ], + "org.jetbrains.jps.model.jarRepository.JpsRemoteRepositoryService": [ + "org.jetbrains.jps.model.jarRepository.impl.JpsRemoteRepositoryServiceImpl" + ], + "org.jetbrains.jps.model.java.JdkVersionDetector": [ + "org.jetbrains.jps.model.java.impl.JdkVersionDetectorImpl" + ], + "org.jetbrains.jps.model.java.JpsJavaExtensionService": [ + "org.jetbrains.jps.model.java.impl.JpsJavaExtensionServiceImpl" + ], + "org.jetbrains.jps.model.serialization.JpsModelSerializerExtension": [ + "com.intellij.platform.jps.model.serialization.resolver.JpsDependencyResolverConfigurationSerializerExtension", + "org.jetbrains.jps.model.serialization.JpsEncodingModelSerializerExtension", + "org.jetbrains.jps.model.serialization.jarRepository.JpsRemoteRepositoriesModelSerializerExtension", + "org.jetbrains.jps.model.serialization.java.JpsJavaModelSerializerExtension" + ], + "org.jetbrains.jps.model.serialization.JpsPathMacroContributor": [ + "org.jetbrains.jps.model.serialization.java.JpsMavenHomePathMacroContributor" + ], + "org.jetbrains.jps.model.serialization.JpsSerializationManager": [ + "org.jetbrains.jps.model.serialization.impl.JpsSerializationManagerImpl" + ], + "org.jetbrains.jps.model.serialization.impl.JpsSerializationViaWorkspaceModel": [ + "com.intellij.platform.workspace.jps.bridge.impl.serialization.JpsSerializationViaWorkspaceModelImpl" + ], + "org.jetbrains.jps.service.JpsServiceManager": [ + "org.jetbrains.jps.service.impl.JpsServiceManagerImpl" + ], + "org.jetbrains.jps.service.SharedThreadPool": [ + "org.jetbrains.jps.service.impl.SharedThreadPoolImpl" + ], + "reactor.blockhound.integration.BlockHoundIntegration": [ + "kotlinx.coroutines.debug.CoroutinesBlockHoundIntegration" + ] + }, + "com.android.tools.external.com-intellij:kotlin-compiler": { + "org.jetbrains.kotlin.builtins.BuiltInsLoader": [ + "org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInsLoaderImpl" + ], + "org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor": [ + "org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCommandLineProcessor" + ], + "org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar": [ + "org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingK2CompilerPluginRegistrar" + ], + "org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar": [ + "org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationComponentRegistrar" + ], + "org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition": [ + "org.jetbrains.kotlin.load.java.ErasedOverridabilityCondition", + "org.jetbrains.kotlin.load.java.FieldOverridabilityCondition", + "org.jetbrains.kotlin.load.java.JavaIncompatibilityRulesOverridabilityCondition" + ], + "org.jetbrains.kotlin.resolve.jvm.jvmSignature.KotlinToJvmSignatureMapper": [ + "org.jetbrains.kotlin.codegen.signature.KotlinToJvmSignatureMapperImpl" + ], + "org.jetbrains.kotlin.util.ModuleVisibilityHelper": [ + "org.jetbrains.kotlin.cli.common.ModuleVisibilityHelperImpl" + ], + "org/": [], + "org/jline/": [], + "org/jline/terminal/": [], + "org/jline/terminal/provider/": [], + "org/jline/terminal/provider/exec": [ + "class=org.jline.terminal.impl.exec.ExecTerminalProvider" + ], + "org/jline/terminal/provider/jansi": [ + "class=org.jline.terminal.impl.jansi.JansiTerminalProvider" + ], + "org/jline/terminal/provider/jna": [ + "class=org.jline.terminal.impl.jna.JnaTerminalProvider" + ], + "org/jline/terminal/provider/jni": [ + "class=org.jline.terminal.impl.jni.JniTerminalProvider" + ] + }, + "com.google.jimfs:jimfs": { + "java.nio.file.spi.FileSystemProvider": [ + "com.google.common.jimfs.SystemJimfsFileSystemProvider" + ] + }, + "net.sf.kxml:kxml2": { + "org.xmlpull.v1.XmlPullParserFactory": [ + "org.kxml2.io.KXmlParser,org.kxml2.io.KXmlSerializer" + ] + }, + "org.bouncycastle:bcprov-jdk18on": { + "java.security.Provider": [ + "org.bouncycastle.jce.provider.BouncyCastleProvider", + "org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider" + ] + }, + "org.codehaus.groovy:groovy": { + "org.codehaus.groovy.transform.ASTTransformation": [ + "groovy.grape.GrabAnnotationTransformation" + ] + }, + "org.glassfish.jaxb:jaxb-runtime": { + "javax.xml.bind.JAXBContext": [ + "com.sun.xml.bind.v2.ContextFactory" + ] + }, + "org.jetbrains.kotlin:kotlin-reflect": { + "kotlin.reflect.jvm.internal.impl.builtins.BuiltInsLoader": [ + "kotlin.reflect.jvm.internal.impl.serialization.deserialization.builtins.BuiltInsLoaderImpl" + ], + "kotlin.reflect.jvm.internal.impl.resolve.ExternalOverridabilityCondition": [ + "kotlin.reflect.jvm.internal.impl.load.java.ErasedOverridabilityCondition", + "kotlin.reflect.jvm.internal.impl.load.java.FieldOverridabilityCondition", + "kotlin.reflect.jvm.internal.impl.load.java.JavaIncompatibilityRulesOverridabilityCondition" + ] + } + }, + "version": "3" +} diff --git a/build_defs/languages/jvm/maven-package.mts b/build_defs/languages/jvm/maven-package.mts new file mode 100644 index 000000000..2af32cbc6 --- /dev/null +++ b/build_defs/languages/jvm/maven-package.mts @@ -0,0 +1,302 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { kotlinMavenCentralCoordinates } from '../../../src/native/sdks/kotlin/tools/kotlin-maven-staging.mts'; +import { createDeterministicZip } from '../../../tools/packaging/archive-directory.mts'; +import { validateMavenCentralPublication } from '../../../tools/packaging/maven-central-contract.mts'; +import { inspectPlatformBinaryBuffer } from '../../../tools/packaging/platform-binary-contract.mts'; +import { + readJavaArchiveEntries, + readPortableArchiveEntries, +} from '../../../tools/packaging/portable-archive.mts'; +import { stageReleaseNotices } from '../../../tools/packaging/release-notices.mts'; +import { stageMobileLegalSources } from '../mobile-legal.mts'; +import { mavenPom } from './maven-pom.mts'; + +const ANDROID_TARGETS = { 'arm64-v8a': 'android-arm64', x86_64: 'android-x86_64' }; +function put(root: string, member: string, bytes: Uint8Array | string) { + assert.ok( + member && + !member.startsWith('/') && + !member.includes('\\') && + member.split('/').every((part) => part && part !== '.' && part !== '..'), + `Unsafe package member ${member}`, + ); + const file = path.join(root, member); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, bytes, { mode: 0o644 }); +} +function archiveFiles(file: string, { javaArchive = false } = {}) { + const entries = javaArchive + ? readJavaArchiveEntries(realpathSync(file)) + : readPortableArchiveEntries(realpathSync(file), { format: 'zip' }); + return new Map( + [...entries] + .filter(([, entry]) => entry.isFile) + .map(([name, entry]) => [name, Buffer.from(entry.data())]), + ); +} +async function mergeClasses(inputs: string[], directory: string, output: string) { + const seen = new Map(); + for (const input of inputs) + for (const [name, bytes] of archiveFiles(input, { javaArchive: true })) { + if (name === 'META-INF/MANIFEST.MF') continue; + const previous = seen.get(name); + assert.ok(!previous || previous.equals(bytes), `Conflicting compiled class/resource ${name}`); + seen.set(name, bytes); + } + assert.ok( + [...seen.keys()].some((name) => name.endsWith('.class')), + 'Publication must contain compiled classes', + ); + put(directory, 'META-INF/MANIFEST.MF', 'Manifest-Version: 1.0\r\n\r\n'); + for (const [name, bytes] of seen) put(directory, name, bytes); + writeFileSync(output, await createDeterministicZip(directory)); +} +function sourceMember(member: string, bytes: Buffer) { + if (member.startsWith('generated/')) { + const packageName = bytes.toString('utf8').match(/^package ([A-Za-z0-9_.]+)\s*;?$/mu)?.[1]; + assert.ok(packageName, `Generated source ${member} must declare its package`); + return `${packageName.replaceAll('.', '/')}/${path.posix.basename(member)}`; + } + return member; +} +function validateAndroidManifest(manifest: string, kotlin) { + const root = manifest.match(/]*>/u); + assert.ok(root, 'Compiler manifest must declare its manifest root'); + const namespaces = [...root[0].matchAll(/\sxmlns:android\s*=\s*(["'])([^"']*)\1/gu)]; + assert.deepEqual( + namespaces.map((match) => match[2]), + ['http://schemas.android.com/apk/res/android'], + 'Compiler manifest must bind the canonical Android namespace', + ); + const sdkTags = [...manifest.matchAll(/<\/?uses-sdk\b[^>]*>/gu)]; + assert.equal(sdkTags.length, 1, 'Compiler manifest must declare exactly one uses-sdk'); + const sdk = sdkTags[0][0].match(/^$/u); + assert.ok(sdk, 'Compiler uses-sdk must be self-closing'); + assert.match( + sdk[1], + /^(?:\s+[A-Za-z_:][\w:.-]*\s*=\s*(?:"[^"]*"|'[^']*'))*\s*$/u, + 'Compiler uses-sdk must contain canonical Android SDK attributes', + ); + const attributes = [...sdk[1].matchAll(/([A-Za-z_:][\w:.-]*)\s*=\s*(["'])([^"']*)\2/gu)] + .map((match) => [match[1], match[3]]) + .sort(([left], [right]) => left.localeCompare(right)); + assert.deepEqual( + attributes, + [ + ['android:minSdkVersion', String(kotlin.minSdk)], + ['android:targetSdkVersion', String(kotlin.compileSdk)], + ], + 'Compiler uses-sdk must contain canonical Android SDK attributes', + ); +} +function sdkDependencies(specification) { + const libraries = specification.kotlin.libraries; + const coroutines = libraries['kotlinx-coroutines-core']; + const [group, artifact] = coroutines.module.split(':'); + // MavenInfo identifies the locked JVM variant; maintained Java processing + // may change its declared JAR filename without changing that identity. + assert.equal( + specification.coroutinesCoordinates, + `${group}:${artifact}-jvm:${coroutines.version}`, + 'Resolved coroutine dependency must have the canonical JVM Maven coordinates', + ); + assert.ok( + archiveFiles(specification.coroutinesJvm, { javaArchive: true }).has( + 'kotlinx/coroutines/Job.class', + ), + 'Resolved coroutine dependency must be the actual JVM library', + ); + return [ + { ...libraries['kotlin-stdlib'], scope: 'compile' }, + { + ...libraries.jna, + type: 'aar', + scope: 'runtime', + exclusions: [{ groupId: '*', artifactId: '*' }], + }, + { + module: `${group}:${artifact}-jvm`, + version: coroutines.version, + scope: 'runtime', + exclusions: [ + 'kotlin-stdlib-common', + 'kotlin-test-common', + 'kotlin-test-annotations-common', + ].map((artifactId) => ({ groupId: 'org.jetbrains.kotlin', artifactId })), + }, + ]; +} +export async function packageKotlinMaven(output: string, specification) { + output = path.resolve(output); + mkdirSync(output, { recursive: true }); + const coordinate = kotlinMavenCentralCoordinates(specification.version).find( + (value) => `${value.groupId}:${value.artifactId}` === specification.coordinate, + ); + assert.ok( + coordinate && specification.registryPackages.includes(`maven:${specification.coordinate}`), + 'Publication coordinate must belong to the canonical Kotlin owner', + ); + const scratch = mkdtempSync(path.join(output, '.maven-package-')); + try { + const isSdk = coordinate.packaging === 'aar'; + const isMarker = coordinate.packaging === 'pom'; + const metadata = isSdk ? specification.kotlin.sdkPom : specification.kotlin.pluginPom; + const prefix = `${coordinate.artifactId}-${coordinate.version}`; + const directory = path.join(output, coordinate.directory); + mkdirSync(directory, { recursive: true }); + if (!isMarker) { + const sourceRoot = path.join(scratch, 'sources'); + let contract; + if (isSdk) contract = stageMobileLegalSources(specification.legalSources, sourceRoot); + else + for (const member of ['LICENSE', 'THIRD_PARTY_NOTICES.md']) { + assert.equal(typeof specification.legalSources[member], 'string', `Missing ${member}`); + put(sourceRoot, member, readFileSync(realpathSync(specification.legalSources[member]))); + } + if (isSdk) { + assert.deepEqual( + Object.keys(specification.nativeLibraries).sort(), + Object.keys(ANDROID_TARGETS).sort(), + 'AAR must consume both exact declared Android ABI outputs', + ); + const aar = path.join(scratch, 'aar'); + // Android's compiler creates a Java ZIP container; final publication + // bytes below still pass the strict portable archive reader. + for (const [member, bytes] of archiveFiles(specification.androidAar, { javaArchive: true })) + if (member !== 'classes.jar') { + assert.ok( + !member.startsWith('jni/') && !member.startsWith('assets/oliphaunt'), + 'Compiler AAR may not smuggle native runtime payloads', + ); + put(aar, member, bytes); + } + const manifest = readFileSync(path.join(aar, 'AndroidManifest.xml'), 'utf8'); + validateAndroidManifest(manifest, specification.kotlin); + await mergeClasses( + specification.classJars, + path.join(scratch, 'classes'), + path.join(aar, 'classes.jar'), + ); + for (const [abi, target] of Object.entries(ANDROID_TARGETS)) { + const bytes = readFileSync(realpathSync(specification.nativeLibraries[abi])); + inspectPlatformBinaryBuffer(bytes, { + target: `android-${abi}`, + label: `Kotlin ${abi} mobile bindings`, + }); + put(aar, `jni/${abi}/liboliphaunt_mobile_bindings.so`, bytes); + const legal = path.join(aar, 'assets/oliphaunt-native-bindings', target); + stageReleaseNotices(legal, { profile: 'source-sdk', sourceRoot }); + contract.stageRustDependencyLicenses(legal, target); + contract.assertRustDependencyLicensesInDirectory(legal, { target }); + } + stageReleaseNotices(aar, { profile: 'source-sdk', sourceRoot }); + const archive = path.join(directory, `${prefix}.aar`); + writeFileSync(archive, await createDeterministicZip(aar)); + const entries = readPortableArchiveEntries(archive, { format: 'zip' }); + for (const target of Object.values(ANDROID_TARGETS)) + contract.assertRustDependencyLicensesInEntries(entries, { + target, + prefix: `assets/oliphaunt-native-bindings/${target}`, + }); + } else { + const jar = path.join(scratch, 'plugin'); + await mergeClasses(specification.classJars, jar, path.join(scratch, 'compiled.jar')); + stageReleaseNotices(path.join(jar, 'META-INF'), { profile: 'source-sdk', sourceRoot }); + const descriptor = readFileSync( + path.join(jar, 'META-INF/gradle-plugins/dev.oliphaunt.android.properties'), + 'utf8', + ); + assert.equal( + descriptor, + 'implementation-class=dev.oliphaunt.android.OliphauntAndroidPlugin\n', + ); + assert.ok( + archiveFiles(specification.classJars[0], { javaArchive: true }).has( + 'dev/oliphaunt/android/OliphauntAndroidPlugin.class', + ), + 'Actual plugin implementation must be compiled', + ); + writeFileSync(path.join(directory, `${prefix}.jar`), await createDeterministicZip(jar)); + } + const sources = path.join(scratch, 'published-sources'); + for (const [member, file] of Object.entries(specification.sources) as [string, string][]) { + const bytes = readFileSync(realpathSync(file)); + put(sources, sourceMember(member, bytes), bytes); + } + assert.ok( + Object.keys(specification.sources).length > 0, + 'Source companion must contain actual publication sources', + ); + stageReleaseNotices(path.join(sources, 'META-INF'), { profile: 'source-sdk', sourceRoot }); + writeFileSync( + path.join(directory, `${prefix}-sources.jar`), + await createDeterministicZip(sources), + ); + const docs = path.join(scratch, 'published-docs'); + const javadoc = specification.javadocArchive + ? archiveFiles(specification.javadocArchive) + : new Map( + Object.entries(specification.javadoc ?? {}).map(([member, file]) => [ + member, + readFileSync(realpathSync(file as string)), + ]), + ); + if (!isSdk) + assert.ok( + [...javadoc.keys()].some((name) => name.endsWith('.html')), + 'Plugin documentation companion requires real Javadoc output', + ); + for (const [member, bytes] of javadoc) put(docs, member, bytes); + stageReleaseNotices(path.join(docs, 'META-INF'), { profile: 'source-sdk', sourceRoot }); + // The existing Android publication has a legal-only javadoc companion. + writeFileSync( + path.join(directory, `${prefix}-javadoc.jar`), + await createDeterministicZip(docs), + ); + if (!isSdk) { + const file = path.join(directory, `${prefix}.jar`); + const bytes = readFileSync(file); + const artifact = { + name: path.basename(file), + url: path.basename(file), + size: bytes.length, + sha512: createHash('sha512').update(bytes).digest('hex'), + sha256: createHash('sha256').update(bytes).digest('hex'), + sha1: createHash('sha1').update(bytes).digest('hex'), + md5: createHash('md5').update(bytes).digest('hex'), + }; + writeFileSync( + path.join(directory, `${prefix}.module`), + `${JSON.stringify({ formatVersion: '1.1', component: { group: coordinate.groupId, module: coordinate.artifactId, version: coordinate.version, attributes: { 'org.gradle.status': 'release' } }, variants: ['java-api', 'java-runtime'].map((usage) => ({ name: usage === 'java-api' ? 'apiElements' : 'runtimeElements', attributes: { 'org.gradle.category': 'library', 'org.gradle.dependency.bundling': 'external', 'org.gradle.jvm.version': Number(specification.kotlin.jvmTarget), 'org.gradle.libraryelements': 'jar', 'org.gradle.usage': usage }, files: [artifact] })) }, null, 2)}\n`, + ); + } + } + const dependencies = isSdk + ? sdkDependencies(specification) + : isMarker + ? [{ module: 'dev.oliphaunt:oliphaunt-android-gradle-plugin', version: coordinate.version }] + : []; + const pom = mavenPom({ coordinate, metadata, dependencies }); + writeFileSync(path.join(directory, `${prefix}.pom`), pom); + const files = coordinate.files.map((relative) => ({ + name: path.basename(relative), + size: readFileSync(path.join(output, relative)).length, + })); + validateMavenCentralPublication({ pomText: pom, files, context: specification.coordinate }); + return coordinate.files; + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +} +if (import.meta.main) { + const [output, specification] = process.argv.slice(2); + assert.equal( + process.argv.length, + 4, + 'Expected output directory and explicit publication input JSON', + ); + await packageKotlinMaven(output, JSON.parse(readFileSync(specification, 'utf8'))); +} diff --git a/build_defs/languages/jvm/maven-package.test.mts b/build_defs/languages/jvm/maven-package.test.mts new file mode 100644 index 000000000..4f15ef066 --- /dev/null +++ b/build_defs/languages/jvm/maven-package.test.mts @@ -0,0 +1,315 @@ +import { expect, test } from 'bun:test'; +import { + chmodSync, + copyFileSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { validateKotlinMavenStagingClosure } from '../../../src/native/sdks/kotlin/tools/kotlin-maven-staging.mts'; +import { createDeterministicZip } from '../../../tools/packaging/archive-directory.mts'; +import { readPortableArchiveEntries } from '../../../tools/packaging/portable-archive.mts'; +import { elfFixture } from '../../../tools/packaging/testdata/release-fixture-utils.mts'; +import { zipArchive } from '../../../tools/packaging/testdata/zip-fixture.mts'; +import { kotlinSdkMetadata } from './kotlin-sdk-metadata.mts'; +import { packageKotlinMaven } from './maven-package.mts'; + +const ROOT = path.resolve(import.meta.dir, '../../..'); +const read = (member: string) => readFileSync(path.join(ROOT, member), 'utf8'); +const OWNER = 'src/native/mobile-bindings'; +const REGISTRY = [ + 'dev.oliphaunt:oliphaunt-android', + 'dev.oliphaunt:oliphaunt-android-gradle-plugin', + 'dev.oliphaunt.android:dev.oliphaunt.android.gradle.plugin', +]; +async function fixture(scratch: string) { + const kotlin = kotlinSdkMetadata({ + catalog: Bun.TOML.parse(read('src/native/sdks/kotlin/gradle/libs.versions.toml')), + gradle: read('src/native/sdks/kotlin/oliphaunt/build.gradle.kts'), + pluginGradle: read('src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/build.gradle.kts'), + properties: read('src/native/sdks/kotlin/gradle.properties'), + version: read('src/native/sdks/kotlin/VERSION').trim(), + androidSdk: Bun.TOML.parse(read('tools/dev/android-sdk.toml')), + }); + async function zip(name: string, entries: Record) { + const tree = path.join(scratch, `${name}-tree`); + for (const [member, bytes] of Object.entries(entries)) { + const file = path.join(tree, member); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, bytes); + } + const archive = path.join(scratch, name); + writeFileSync(archive, await createDeterministicZip(tree)); + return archive; + } + const compiled = await zip('sdk.jar', { 'dev/oliphaunt/Oliphaunt.class': 'compiled fixture' }); + const plugin = await zip('plugin.jar', { + 'dev/oliphaunt/android/OliphauntAndroidPlugin.class': 'compiled fixture', + 'META-INF/gradle-plugins/dev.oliphaunt.android.properties': + 'implementation-class=dev.oliphaunt.android.OliphauntAndroidPlugin\n', + }); + const androidAar = path.join(scratch, 'base.aar'); + const androidManifest = `\n\n \n \n\n`; + // Maintained Android construction emits FAT attributes=0, deflated entries + // with signed data descriptors, including an empty res/ directory. + writeFileSync( + androidAar, + zipArchive( + [ + { + name: 'AndroidManifest.xml', + data: androidManifest, + }, + { name: 'classes.jar', data: readFileSync(compiled) }, + { name: 'res/', data: '' }, + { name: 'R.txt', data: '' }, + { name: 'proguard.txt', data: '-keep class dev.oliphaunt.** { *; }\n' }, + ].map((entry) => ({ + ...entry, + versionMadeBy: 0x0014, + externalAttributes: 0, + method: 8, + descriptor: 'signed', + })), + ), + ); + const coroutinesJvm = await zip( + `processed_kotlinx-coroutines-core-jvm-${kotlin.libraries['kotlinx-coroutines-core'].version}.jar`, + { 'kotlinx/coroutines/Job.class': 'dependency fixture' }, + ); + const nativeLibraries = {}; + for (const [abi, machine] of [ + ['arm64-v8a', 183], + ['x86_64', 62], + ] as const) { + const file = path.join(scratch, `${abi}.so`); + writeFileSync(file, elfFixture({ machine, androidApi: 24 })); + nativeLibraries[abi] = file; + } + const source = path.join(scratch, 'Source.kt'); + writeFileSync(source, 'package dev.oliphaunt\nclass Source\n'); + const html = path.join(scratch, 'index.html'); + writeFileSync(html, 'Fixture generated documentation'); + const members = [ + 'LICENSE', + 'THIRD_PARTY_NOTICES.md', + 'Cargo.lock', + `${OWNER}/dependency-licenses.json`, + ...readdirSync(path.join(ROOT, OWNER, 'dependency-license-blobs')).map( + (name) => `${OWNER}/dependency-license-blobs/${name}`, + ), + ]; + const legalSources = Object.fromEntries( + members.map((member) => { + const destination = path.join(scratch, 'legal-inputs', member); + mkdirSync(path.dirname(destination), { recursive: true }); + copyFileSync(path.join(ROOT, member), destination); + chmodSync(destination, 0o644); + return [member, destination]; + }), + ); + return { + version: read('src/native/sdks/kotlin/VERSION').trim(), + registryPackages: REGISTRY.map((coordinate) => `maven:${coordinate}`), + kotlin, + classJars: [compiled], + plugin, + nativeLibraries, + androidAar, + androidManifest, + coroutinesJvm, + coroutinesCoordinates: `${kotlin.libraries['kotlinx-coroutines-core'].module}-jvm:${kotlin.libraries['kotlinx-coroutines-core'].version}`, + sources: { 'generated/Source.kt': source }, + javadoc: { 'index.html': html }, + legalSources, + }; +} +test('three native envelopes preserve the exact existing ten-file Maven closure', async () => { + const scratch = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-native-maven-')); + try { + const values = await fixture(scratch); + expect(() => readPortableArchiveEntries(values.androidAar, { format: 'zip' })).toThrow( + 'inconsistent FAT directory metadata', + ); + const output = path.join(scratch, 'maven'); + for (const coordinate of REGISTRY) + await packageKotlinMaven(output, { + ...values, + coordinate, + classJars: [coordinate === REGISTRY[1] ? values.plugin : values.classJars[0]], + }); + const publication = validateKotlinMavenStagingClosure(output, values.version, { + allowLocalMetadata: false, + }); + expect(publication.publicationFiles).toHaveLength(10); + const aar = path.join( + output, + publication.publicationFiles.find((name) => name.endsWith('.aar'))!, + ); + const entries = readPortableArchiveEntries(aar, { format: 'zip' }); + expect(entries.get('AndroidManifest.xml')?.data().toString()).toBe(values.androidManifest); + expect(entries.get('R.txt')?.data()).toHaveLength(0); + expect(entries.get('proguard.txt')?.data().toString()).toBe( + '-keep class dev.oliphaunt.** { *; }\n', + ); + expect(entries.has('jni/arm64-v8a/liboliphaunt_mobile_bindings.so')).toBeTrue(); + expect(entries.has('jni/x86_64/liboliphaunt_mobile_bindings.so')).toBeTrue(); + expect( + entries.has( + 'assets/oliphaunt-native-bindings/android-arm64/THIRD_PARTY_LICENSES/rust/DEPENDENCIES.json', + ), + ).toBeTrue(); + const before = readFileSync(aar); + await packageKotlinMaven(output, { ...values, coordinate: REGISTRY[0] }); + expect(readFileSync(aar).equals(before)).toBeTrue(); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +}); +test('compiler AAR input keeps directory, link and native payload checks', async () => { + const scratch = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-native-maven-aar-bad-')); + try { + const values = await fixture(scratch); + for (const [entry, message] of [ + [ + { name: 'res/', data: 'payload', versionMadeBy: 0x0014, externalAttributes: 0 }, + 'non-empty ZIP directory', + ], + [ + { name: 'res/link', data: '../escape', externalAttributes: 0o120777 << 16 }, + 'link or special', + ], + [{ name: 'jni/arm64-v8a/undeclared.so', data: 'payload' }, 'smuggle native runtime'], + ] as const) { + writeFileSync(values.androidAar, zipArchive([entry])); + await expect( + packageKotlinMaven(path.join(scratch, 'maven'), { + ...values, + coordinate: REGISTRY[0], + }), + ).rejects.toThrow(message); + } + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +}); +test('requires one self-closing uses-sdk with exactly the canonical Android attributes', async () => { + const scratch = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-native-maven-manifest-bad-')); + try { + const values = await fixture(scratch); + const sdk = values.androidManifest.match(/]*>/u)?.[0]; + if (!sdk) throw new Error('Fixture must declare uses-sdk'); + for (const [manifest, message] of [ + [values.androidManifest.replace(sdk, ''), 'exactly one uses-sdk'], + [values.androidManifest.replace(sdk, `${sdk}\n${sdk}`), 'exactly one uses-sdk'], + [values.androidManifest.replace(sdk, sdk.replace('/>', '>')), 'self-closing'], + [ + values.androidManifest.replace('android:minSdkVersion="24"', 'android:minSdkVersion="23"'), + 'canonical Android SDK attributes', + ], + [ + values.androidManifest.replace( + 'android:targetSdkVersion="36"', + 'android:targetSdkVersion="35"', + ), + 'canonical Android SDK attributes', + ], + [ + values.androidManifest.replace(sdk, sdk.replace('/>', 'android:maxSdkVersion="36" />')), + 'canonical Android SDK attributes', + ], + [ + values.androidManifest.replace(sdk, sdk.replace('android:minSdkVersion', 'minSdkVersion')), + 'canonical Android SDK attributes', + ], + [ + values.androidManifest.replace(sdk, sdk.replace('/>', 'android:minSdkVersion="24" />')), + 'canonical Android SDK attributes', + ], + [ + values.androidManifest.replace( + 'http://schemas.android.com/apk/res/android', + 'https://example.com', + ), + 'canonical Android namespace', + ], + ]) { + writeFileSync( + values.androidAar, + zipArchive([{ name: 'AndroidManifest.xml', data: manifest }]), + ); + await expect( + packageKotlinMaven(path.join(scratch, 'maven'), { + ...values, + coordinate: REGISTRY[0], + }), + ).rejects.toThrow(message); + } + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +}); +test('rejects unowned coordinates, incomplete ABI inputs, wrong resolved dependencies and malformed native bytes', async () => { + const scratch = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-native-maven-bad-')); + try { + const values = await fixture(scratch); + const output = path.join(scratch, 'maven'); + await expect( + packageKotlinMaven(output, { ...values, coordinate: 'org.example:other' }), + ).rejects.toThrow('canonical Kotlin owner'); + await expect( + packageKotlinMaven(output, { + ...values, + coordinate: REGISTRY[0], + nativeLibraries: { 'arm64-v8a': values.nativeLibraries['arm64-v8a'] }, + }), + ).rejects.toThrow('both exact declared'); + const bad = readFileSync(values.nativeLibraries['arm64-v8a']); + bad.writeBigUInt64LE(4096n, 112); + writeFileSync(values.nativeLibraries['arm64-v8a'], bad); + await expect( + packageKotlinMaven(output, { ...values, coordinate: REGISTRY[0] }), + ).rejects.toThrow('alignment'); + writeFileSync( + values.nativeLibraries['arm64-v8a'], + elfFixture({ machine: 183, androidApi: 24 }), + ); + await expect( + packageKotlinMaven(output, { + ...values, + coordinate: REGISTRY[0], + coroutinesJvm: values.classJars[0], + }), + ).rejects.toThrow('actual JVM library'); + for (const coroutinesCoordinates of [ + values.coroutinesCoordinates.replace( + 'kotlinx-coroutines-core-jvm', + 'kotlinx-coroutines-core', + ), + values.coroutinesCoordinates.replace(/:[^:]+$/u, ':0.0.0'), + undefined, + ]) + await expect( + packageKotlinMaven(output, { + ...values, + coordinate: REGISTRY[0], + coroutinesCoordinates, + }), + ).rejects.toThrow('canonical JVM Maven coordinates'); + await expect( + packageKotlinMaven(output, { + ...values, + coordinate: REGISTRY[1], + classJars: [values.plugin], + javadoc: {}, + }), + ).rejects.toThrow('real Javadoc'); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +}); diff --git a/build_defs/languages/jvm/maven-pom.mts b/build_defs/languages/jvm/maven-pom.mts new file mode 100644 index 000000000..379335280 --- /dev/null +++ b/build_defs/languages/jvm/maven-pom.mts @@ -0,0 +1,62 @@ +import assert from 'node:assert/strict'; + +/** Import the literal publication metadata already authored in the Gradle build. */ +export function conventionalPomMetadata(gradle: string, version: string) { + const start = gradle.indexOf('\n pom {'); + assert.ok( + start >= 0 && gradle.indexOf('\n pom {', start + 1) < 0, + 'Expected one conventional Maven pom block', + ); + const source = gradle.slice(start); + function field(name: string, occurrences = 1) { + const matches = [ + ...source.matchAll(new RegExp(`^\\s*${name}[.]set\\("([^"\\n]+)"\\)\\s*$`, 'gm')), + ]; + assert.equal(matches.length, occurrences, `Expected ${occurrences} literal POM ${name} values`); + return matches.map((match) => match[1]!.replaceAll('${project.version}', version)); + } + const names = field('name', 3); + const urls = field('url', 4); + for (const value of [ + ...names, + ...urls, + ...field('description'), + ...field('connection'), + ...field('developerConnection'), + ]) + assert.ok(!value.includes('${'), 'Unsupported dynamic conventional Maven metadata'); + return { + name: names[0]!, + description: field('description')[0]!, + inceptionYear: field('inceptionYear')[0]!, + url: urls[0]!, + license: { name: names[1]!, url: urls[1]!, distribution: field('distribution')[0]! }, + developer: { id: field('id')[0]!, name: names[2]!, url: urls[2]! }, + scm: { + url: urls[3]!, + connection: field('connection')[0]!, + developerConnection: field('developerConnection')[0]!, + }, + }; +} + +const xml = (value: string) => + String(value) + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll("'", '''); +const tag = (name: string, value: string) => `<${name}>${xml(value)}`; + +export function mavenPom({ coordinate, metadata, dependencies = [] }) { + const { groupId, artifactId, version, packaging } = coordinate; + const dependencyXml = dependencies + .map(({ module, version: dependencyVersion, scope, type, exclusions = [] }) => { + const [group, artifact] = module.split(':'); + assert.ok(group && artifact && dependencyVersion); + return `${tag('groupId', group)}${tag('artifactId', artifact)}${tag('version', dependencyVersion)}${scope ? tag('scope', scope) : ''}${type ? tag('type', type) : ''}${exclusions.length ? `${exclusions.map(({ groupId: excludedGroup, artifactId: excludedArtifact }) => `${tag('groupId', excludedGroup)}${tag('artifactId', excludedArtifact)}`).join('')}` : ''}`; + }) + .join(''); + return `\n${tag('modelVersion', '4.0.0')}${tag('groupId', groupId)}${tag('artifactId', artifactId)}${tag('version', version)}${tag('packaging', packaging)}${tag('name', metadata.name)}${tag('description', metadata.description)}${tag('inceptionYear', metadata.inceptionYear)}${tag('url', metadata.url)}${tag('name', metadata.license.name)}${tag('url', metadata.license.url)}${tag('distribution', metadata.license.distribution)}${tag('id', metadata.developer.id)}${tag('name', metadata.developer.name)}${tag('url', metadata.developer.url)}${tag('url', metadata.scm.url)}${tag('connection', metadata.scm.connection)}${tag('developerConnection', metadata.scm.developerConnection)}${dependencyXml ? `${dependencyXml}` : ''}\n`; +} diff --git a/build_defs/languages/jvm/maven.bzl b/build_defs/languages/jvm/maven.bzl new file mode 100644 index 000000000..7e7684bcf --- /dev/null +++ b/build_defs/languages/jvm/maven.bzl @@ -0,0 +1,227 @@ +"""Maven envelopes over real maintained Java/Kotlin/Android construction outputs.""" + +load("@oliphaunt_metadata//:metadata.bzl", "PRODUCTS", "PUBLICATION_CARRIERS") +load("@oliphaunt_kotlin_manifest//:metadata.bzl", "KOTLIN") +load("@rules_java//java/common:java_info.bzl", "JavaInfo") +load("@rules_jvm_external//:providers.bzl", "MavenInfo") +load("@rules_jvm_external//private/rules:has_maven_deps.bzl", "has_maven_deps") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_file_action", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/languages:mobile-compiled-inputs.bzl", "MOBILE_BINDINGS_COMPILE_OWNERS", "MOBILE_BINDINGS_COMPILE_QUALIFICATION", "MobileCompiledInputsInfo", "merge_mobile_compiled_inputs", "mobile_bindings_compile_group", "mobile_bindings_compiled_supplier", "mobile_compiled_inputs") +load("//build_defs/native/carriers:defs.bzl", "native_carrier_helpers") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") +load("//build_defs/release:supplier.bzl", "ShippingSupplierInfo", "merge_shipping_suppliers") + +_JAVA_RUNTIME = "@bazel_tools//tools/jdk:runtime_toolchain_type" +KOTLIN_BINDINGS_COMPILE_SLOTS = ["android-arm64-v8a", "android-x86_64", "host-generator"] + +def _javadoc_impl(ctx): + runtime = ctx.toolchains[_JAVA_RUNTIME].java_runtime + classpath = depset(transitive = [dep[JavaInfo].transitive_compile_time_jars for dep in ctx.attr.deps]) + spec = ctx.actions.declare_file(ctx.label.name + ".json") + ctx.actions.write(spec, json.encode({"sources": [file.path for file in ctx.files.srcs], "classpath": [file.path for file in classpath.to_list()], "javaHome": runtime.java_home, "release": KOTLIN["jvmTarget"]})) + output = ctx.actions.declare_file(ctx.label.name + ".zip") + bun_file_action( + ctx, + entry_point = ctx.file._driver, + source_files = [ctx.file._driver] + ctx.files._helpers, + arguments = [output.path, spec.path], + inputs = depset(ctx.files.srcs + [spec, ctx.file._driver] + ctx.files._helpers, transitive = [classpath, runtime.files]), + outputs = [output], + mnemonic = "OliphauntPluginJavadoc", + use_default_shell_env = False, + ) + return [DefaultInfo(files = depset([output]))] + +java_javadoc = rule( + implementation = _javadoc_impl, + toolchains = BUN_SOURCE_TOOLCHAINS + [_JAVA_RUNTIME], + attrs = { + "srcs": attr.label_list(allow_files = [".java"], mandatory = True), + "deps": attr.label_list(providers = [JavaInfo]), + "_driver": attr.label(default = Label("//build_defs/languages/jvm:javadoc.mts"), allow_single_file = True), + "_helpers": attr.label_list(default = [Label("//:tools/packaging/archive-directory.mts"), Label("//:tools/packaging/portable-archive.mts")], allow_files = True), + }, +) + +def _maven_package_impl(ctx): + owner = PRODUCTS["oliphaunt-kotlin"] + group, artifact = ctx.attr.coordinate.split(":") + version = owner["version"] + packaging = ctx.attr.packaging + suffixes = [".pom"] if packaging == "pom" else ["." + packaging, ".pom", "-sources.jar", "-javadoc.jar"] + ([".module"] if packaging == "jar" else []) + relative = group.replace(".", "/") + "/" + artifact + "/" + version + "/" + artifact + "-" + version + files = [ctx.actions.declare_file(ctx.label.name + "/maven/" + relative + suffix) for suffix in suffixes] + root = files[0].path.removesuffix(relative + suffixes[0]) + sources = {} + for file in ctx.files.sources: + member = file.short_path + authored = False + for prefix in [ctx.label.package + "/src/main/java/", ctx.label.package + "/oliphaunt/src/commonMain/kotlin/", ctx.label.package + "/oliphaunt/src/androidMain/kotlin/", ctx.label.package + "/oliphaunt/src/androidMain/aidl/"]: + if member.startswith(prefix): + member = member[len(prefix):] + authored = True + break + if not authored: + member = "generated/" + file.basename + if member in sources: + fail("Duplicate Maven source member " + member) + sources[member] = file.path + legal = {file.short_path: file.path for file in ctx.files.legal_sources} + class_jars = depset(transitive = [depset(dep[JavaInfo].runtime_output_jars) for dep in ctx.attr.classes]).to_list() + inputs = ctx.files.sources + ctx.files.legal_sources + class_jars + [ctx.file._packager] + ctx.files._helpers + native = {} + if ctx.file.android_aar: + inputs.append(ctx.file.android_aar) + for target, abi in ctx.attr.native_libraries.items(): + physical = target[DefaultInfo].files.to_list() + if len(physical) != 1 or abi in native: + fail("Each unique Android ABI must bind one declared mobile library") + native[abi] = physical[0].path + inputs.extend(physical) + coroutines_jar = None + coroutines_coordinates = None + if ctx.attr.coroutines_jvm: + coroutines = ctx.attr.coroutines_jvm + library = KOTLIN["libraries"]["kotlinx-coroutines-core"] + coroutines_coordinates = coroutines[MavenInfo].coordinates + if coroutines_coordinates != library["module"] + "-jvm:" + library["version"]: + fail("Declared JVM coroutine dependency differs from canonical Kotlin coordinates") + jars = coroutines[JavaInfo].runtime_output_jars + if len(jars) != 1: + fail("Declared JVM coroutine dependency must provide exactly one runtime JAR") + coroutines_jar = jars[0] + inputs.append(coroutines_jar) + if ctx.file.javadoc: + inputs.append(ctx.file.javadoc) + spec = ctx.actions.declare_file(ctx.label.name + ".json") + ctx.actions.write(spec, json.encode({ + "version": version, "registryPackages": owner["registry_packages"], "coordinate": ctx.attr.coordinate, + "kotlin": KOTLIN, "sources": sources, "legalSources": legal, + "classJars": [file.path for file in class_jars], "nativeLibraries": native, + "androidAar": ctx.file.android_aar.path if ctx.file.android_aar else None, + "coroutinesJvm": coroutines_jar.path if coroutines_jar else None, + "coroutinesCoordinates": coroutines_coordinates, + "javadocArchive": ctx.file.javadoc.path if ctx.file.javadoc else None, + })) + bun_file_action( + ctx, + entry_point = ctx.file._packager, + source_files = [ctx.file._packager] + ctx.files._helpers, + arguments = [root, spec.path], + inputs = depset(inputs + [spec]), + outputs = files, + mnemonic = "OliphauntMavenEnvelope", + use_default_shell_env = False, + ) + observed = [] + for target in ctx.attr.sources: + if MobileCompiledInputsInfo in target: + observed.append(target[MobileCompiledInputsInfo]) + else: + source_files = target[DefaultInfo].files.to_list() + if len(source_files) != 1 or not source_files[0].is_source or source_files[0].owner != target.label: + fail("Maven source rule lacks its original compiler input observation: " + str(target.label)) + compiled = merge_mobile_compiled_inputs(observed + [target[MobileCompiledInputsInfo] for target in ctx.attr.native_libraries]) + if packaging == "aar": + expected = [mobile_bindings_compile_group(owner, slot) for owner in MOBILE_BINDINGS_COMPILE_OWNERS for slot in KOTLIN_BINDINGS_COMPILE_SLOTS] + if sorted(compiled.files) != sorted(expected) or sorted(compiled.upstream) != sorted(expected): + fail("Kotlin AAR must retain its complete original Rust compiler File inventory") + suppliers = merge_shipping_suppliers([ctx.attr.suppliers[ShippingSupplierInfo], compiled.current, compiled.registry]) + return [DefaultInfo(files = depset(files)), compiled, suppliers, + OutputGroupInfo(archive = depset([files[0]]) if packaging != "pom" else depset(), **{name: depset([file]) for name, file in compiled.files.items()})] + +_maven_package = rule( + implementation = _maven_package_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = { + "coordinate": attr.string(mandatory = True), + "packaging": attr.string(mandatory = True, values = ["aar", "jar", "pom"]), + "sources": attr.label_list(allow_files = True, aspects = [mobile_compiled_inputs]), + "legal_sources": attr.label_list(allow_files = True), + "classes": attr.label_list(providers = [JavaInfo]), + "android_aar": attr.label(allow_single_file = [".aar"]), + "native_libraries": attr.label_keyed_string_dict(allow_files = True, aspects = [mobile_compiled_inputs]), + "suppliers": attr.label(default = "//build_defs/release:no_suppliers", providers = [ShippingSupplierInfo]), + "coroutines_jvm": attr.label(providers = [JavaInfo], aspects = [has_maven_deps]), + "javadoc": attr.label(allow_single_file = True), + "_packager": attr.label(default = Label("//build_defs/languages/jvm:maven-package.mts"), allow_single_file = True), + "_helpers": attr.label_list(default = [ + Label("//build_defs/languages/jvm:maven-pom.mts"), Label("//build_defs/languages:mobile-legal.mts"), + Label("//src/native/sdks/kotlin:tools/kotlin-maven-staging.mts"), Label("//src/native/mobile-bindings:tools/dependency-license-contract.mts"), + Label("//:tools/packaging/maven-central-contract.mts"), Label("//:tools/packaging/archive-directory.mts"), Label("//:tools/packaging/portable-archive.mts"), + Label("//:tools/packaging/platform-binary-contract.mts"), Label("//:tools/packaging/windows-vc-runtime-closure.mts"), Label("//tools/release:platform-compatibility-policy.mts"), + Label("//:tools/packaging/windows-vc-runtime-policy.json"), + Label("//:tools/packaging/release-notices.mts"), Label("//:tools/packaging/release-directory-safety.mts"), Label("//:tools/packaging/rust-dependency-license-contract.mts"), + ], allow_files = True), + }, +) + +def kotlin_maven_package(name, coordinate, packaging, **kwargs): + carriers = [row for row in PUBLICATION_CARRIERS if row["product"] == "oliphaunt-kotlin" and row["ecosystem"] == "maven" and row["name"] == coordinate and row["target"] == None] + if len(carriers) != 1: + fail("Canonical Maven package identity is not unique: " + coordinate) + _maven_package(name = name, coordinate = coordinate, packaging = packaging, **kwargs) + if packaging != "pom": + native.filegroup(name = name + "_archive", srcs = [":" + name], output_group = "archive") + shipping_package( + name = name + "_shipping", + owner = "@oliphaunt_metadata//:product_oliphaunt-kotlin", + artifacts = [":" + name], ecosystem = "maven", package_name = coordinate, configuration = "portable", role = carriers[0]["role"], + suppliers = ":" + name, + ) + if packaging == "aar": + exports = [] + for owner, product in MOBILE_BINDINGS_COMPILE_OWNERS.items(): + packages = [] + for slot in KOTLIN_BINDINGS_COMPILE_SLOTS: + group = mobile_bindings_compile_group(owner, slot) + native.filegroup(name = name + "_" + group, srcs = [":" + name], output_group = group) + supplier = name + "_" + group + "_suppliers" + mobile_bindings_compiled_supplier(name = supplier, inputs = ":" + name, owner = owner, configuration = slot) + package = name + "_" + group + "_shipping" + shipping_package(name = package, owner = "@oliphaunt_metadata//:product_" + product, artifacts = [":" + name + "_" + group], + ecosystem = "internal", package_name = product + "-kotlin-bindings", configuration = slot, role = "compiled-source", suppliers = ":" + supplier) + packages.append(":" + package) + export = name + "_" + owner + "_compiled_shipping_export" + shipping_export(name = export, packages = packages, qualification = MOBILE_BINDINGS_COMPILE_QUALIFICATION[owner], testonly = True) + exports.append(":" + export) + shipping_export(name = name + "_compiled_shipping_export", exports = exports, testonly = True) + +def _installed_maven_test_impl(ctx): + arguments = [PRODUCTS["oliphaunt-kotlin"]["version"]] + artifacts = ctx.files.packages + for file in artifacts: + parts = file.short_path.split("/maven/", 1) + if len(parts) != 2: + fail("Installed Kotlin package must provide declared Maven repository files: " + file.short_path) + arguments += ["maven", parts[1], file] + consumer = ctx.attr.consumer[JavaInfo].runtime_output_jars + if not consumer: + fail("Installed Kotlin public API consumer must provide compiled JARs") + for file in consumer: + arguments += ["consumer", file] + for file in ctx.files._legal: + arguments += ["legal", file.short_path, file] + return bun_test_entrypoint(ctx, ctx.file._runner, arguments, artifacts + consumer + ctx.files._helpers + ctx.files._legal, + source_files = [ctx.file._runner] + ctx.files._helpers) + +_kotlin_installed_maven_test = rule( + implementation = _installed_maven_test_impl, + test = True, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "packages": attr.label_list(mandatory = True), + "consumer": attr.label(mandatory = True, providers = [JavaInfo]), + "_runner": attr.label(default = "//build_defs/languages/jvm:installed-maven.test.mts", allow_single_file = True), + "_helpers": attr.label_list(default = native_carrier_helpers() + [ + "//build_defs/languages:mobile-legal.mts", + "//src/native/sdks/kotlin:tools/check-package.mts", "//src/native/sdks/kotlin:tools/kotlin-maven-staging.mts", + "//:tools/packaging/maven-central-contract.mts", + ], allow_files = True), + "_legal": attr.label_list(default = ["//:LICENSE", "//:THIRD_PARTY_NOTICES.md", "//:Cargo.lock", "//src/native/mobile-bindings:license_inputs"], allow_files = True), + }), +) + +def kotlin_installed_maven_test(name, **kwargs): + """Final Maven contract plus compilation of the imported public Android AAR.""" + _kotlin_installed_maven_test(name = name, args = bun_test_entrypoint_args(name), **kwargs) diff --git a/build_defs/languages/jvm/plugin-descriptor.mts b/build_defs/languages/jvm/plugin-descriptor.mts new file mode 100644 index 000000000..2f5c50c42 --- /dev/null +++ b/build_defs/languages/jvm/plugin-descriptor.mts @@ -0,0 +1,14 @@ +import { readFile, writeFile } from 'node:fs/promises'; + +const [manifest, output] = process.argv.slice(2); +if (!manifest || !output) + throw new Error('Expected the conventional Gradle plugin manifest and output path'); +const source = await readFile(manifest, 'utf8'); +const value = (field: string) => { + const matches = [...source.matchAll(new RegExp(`^\\s*${field} = "([A-Za-z0-9_.]+)"\\s*$`, 'gm'))]; + if (matches.length !== 1) throw new Error(`Expected exactly one literal Gradle plugin ${field}`); + return matches[0]![1]!; +}; +if (value('id') !== 'dev.oliphaunt.android') + throw new Error('Unexpected public Gradle plugin identity'); +await writeFile(output, `implementation-class=${value('implementationClass')}\n`); diff --git a/build_defs/languages/jvm/quality.bzl b/build_defs/languages/jvm/quality.bzl new file mode 100644 index 000000000..a4396d50f --- /dev/null +++ b/build_defs/languages/jvm/quality.bzl @@ -0,0 +1,45 @@ +"""Source-only Kotlin formatting with the conventional Spotless tool and scope.""" + +load("@oliphaunt_kotlin_manifest//:metadata.bzl", "KOTLIN_QUALITY") +load("@rules_java//java/common:java_info.bzl", "JavaInfo") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") + +_JAVA_RUNTIME = "@bazel_tools//tools/jdk:runtime_toolchain_type" + +def _ktlint_test_impl(ctx): + runtime = ctx.toolchains[_JAVA_RUNTIME].java_runtime + java = [file for file in runtime.files.to_list() if file.path == runtime.java_executable_exec_path] + if len(java) != 1: + fail("Kotlin formatter requires the declared Java runtime executable") + jars = ctx.attr._ktlint[JavaInfo].transitive_runtime_jars.to_list() + arguments = [java[0], json.encode(KOTLIN_QUALITY["ktlint"]["formats"])] + for jar in jars: + arguments += ["jar", jar] + files = [] + for target, format_name in ctx.attr.srcs.items(): + for file in target[DefaultInfo].files.to_list(): + if not file.short_path.startswith(ctx.label.package + "/"): + fail("Kotlin formatter source must belong to its declared SDK package") + arguments += ["source", format_name, file.short_path[len(ctx.label.package) + 1:], file] + files.append(file) + return bun_test_entrypoint(ctx, ctx.file._runner, arguments, files + jars + runtime.files.to_list(), source_files = [ctx.file._runner]) + +_ktlint_test = rule( + implementation = _ktlint_test_impl, + test = True, + toolchains = BUN_SOURCE_TOOLCHAINS + [_JAVA_RUNTIME], + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "srcs": attr.label_keyed_string_dict(allow_files = [".kt", ".kts"]), + "_ktlint": attr.label(default = "@oliphaunt_kotlin_maven//:com_pinterest_ktlint_ktlint_cli", providers = [JavaInfo]), + "_runner": attr.label(default = "//build_defs/languages/jvm:ktlint.mts", allow_single_file = True), + }), +) + +def kotlin_format_test(name, **kwargs): + sources = {} + for format in KOTLIN_QUALITY["ktlint"]["formats"]: + for source in native.glob(format["targets"], allow_empty = False): + if source in sources: + fail("Conventional Kotlin formatter scopes overlap: " + source) + sources[source] = format["name"] + _ktlint_test(name = name, srcs = sources, args = bun_test_entrypoint_args(name), **kwargs) diff --git a/build_defs/languages/jvm/repositories.bzl b/build_defs/languages/jvm/repositories.bzl new file mode 100644 index 000000000..24140a703 --- /dev/null +++ b/build_defs/languages/jvm/repositories.bzl @@ -0,0 +1,29 @@ +"""Import compiler APIs from the existing, checksummed Gradle wrapper contract.""" + +def _gradle_api_impl(ctx): + properties = {} + for line in ctx.read(ctx.attr.wrapper).splitlines(): + if "=" in line and not line.startswith("#"): + key, value = line.split("=", 1) + properties[key] = value.replace("\\:", ":") + url = properties.get("distributionUrl", "") + digest = properties.get("distributionSha256Sum", "") + if not url.startswith("https://services.gradle.org/distributions/gradle-") or not url.endswith("-bin.zip"): + fail("Gradle API acquisition requires the canonical HTTPS binary wrapper distribution") + if len(digest) != 64 or any([char not in "0123456789abcdef" for char in digest.elems()]): + fail("Gradle API acquisition requires the wrapper's exact SHA-256") + version = url.split("/")[-1].removeprefix("gradle-").removesuffix("-bin.zip") + ctx.download_and_extract(url = url, sha256 = digest, strip_prefix = "gradle-" + version) + ctx.file("BUILD.bazel", """load("@rules_java//java:defs.bzl", "java_import") +package(default_visibility = ["//visibility:public"]) +# Gradle is a compile/runtime dependency of its consumer plugin. It is never +# invoked to construct a repository product. +java_import(name = "api", jars = glob(["lib/*.jar", "lib/plugins/*.jar"]), neverlink = True) +java_import(name = "test_runtime", jars = glob(["lib/*.jar", "lib/plugins/*.jar"])) +""") + return ctx.repo_metadata(reproducible = True) + +gradle_api_repository = repository_rule( + implementation = _gradle_api_impl, + attrs = {"wrapper": attr.label(default = Label("//src/native/sdks/kotlin:gradle/wrapper/gradle-wrapper.properties"), allow_single_file = True)}, +) diff --git a/build_defs/languages/jvm/robolectric.bzl b/build_defs/languages/jvm/robolectric.bzl new file mode 100644 index 000000000..234db9fdf --- /dev/null +++ b/build_defs/languages/jvm/robolectric.bzl @@ -0,0 +1,14 @@ +"""Declare one offline Robolectric SDK without acquiring unused Android APIs.""" + +def _robolectric_sdk_impl(ctx): + jar = ctx.file.jar + version = jar.basename.removeprefix("android-all-instrumented-").removesuffix(".jar") + properties = ctx.actions.declare_file(ctx.label.name + ".properties") + relative = "../" * len(ctx.label.package.split("/")) + jar.short_path + ctx.actions.write(properties, "org.robolectric\\:android-all-instrumented\\:%s=%s\n" % (version, relative)) + return [DefaultInfo(files = depset([properties]), runfiles = ctx.runfiles(files = [properties, jar]))] + +robolectric_sdk = rule( + implementation = _robolectric_sdk_impl, + attrs = {"jar": attr.label(mandatory = True, allow_single_file = [".jar"])}, +) diff --git a/build_defs/languages/jvm/testdata/lint/AndroidManifest.xml b/build_defs/languages/jvm/testdata/lint/AndroidManifest.xml new file mode 100644 index 000000000..5ba8e8ff9 --- /dev/null +++ b/build_defs/languages/jvm/testdata/lint/AndroidManifest.xml @@ -0,0 +1,3 @@ + + + diff --git a/build_defs/languages/jvm/testdata/lint/NewApi.kt b/build_defs/languages/jvm/testdata/lint/NewApi.kt new file mode 100644 index 000000000..2e6d929d4 --- /dev/null +++ b/build_defs/languages/jvm/testdata/lint/NewApi.kt @@ -0,0 +1,6 @@ +package dev.oliphaunt.lintfixture + +import android.graphics.Color + +/** API 26 cannot be called unguarded by this fixture's API 24 contract. */ +fun unsupportedApi(): Color = Color.valueOf(0) diff --git a/build_defs/languages/jvm/verify-aar-import-bootclasspath.mts b/build_defs/languages/jvm/verify-aar-import-bootclasspath.mts new file mode 100644 index 000000000..31e093044 --- /dev/null +++ b/build_defs/languages/jvm/verify-aar-import-bootclasspath.mts @@ -0,0 +1,77 @@ +/** Diagnose the pinned Android import bootclasspath using actual cached JARs. */ +import assert from 'node:assert/strict'; +import { realpathSync } from 'node:fs'; +import { dirname, isAbsolute, join } from 'node:path'; +import { pathToFileURL } from 'node:url'; + +const [sdk, extras, merged, javap] = Bun.argv.slice(2); +assert.equal( + Bun.argv.length, + 6, + 'Expected android.jar java_base_extras.jar merged_interface.jar absolute-javap', +); +assert(isAbsolute(javap), 'Use the actual declared JDK javap'); +const files = [sdk, extras, merged].map(realpathSync); +// These are compiler/platform JAR diagnostics, not publication archive admission. +// Read them with the same pinned JDK whose javap inspects the actual class bytes. +const run = (executable: string, arguments_: string[]) => { + const result = Bun.spawnSync([executable, ...arguments_], { + env: { ...process.env, PATH: '', JAVA_TOOL_OPTIONS: '', JDK_JAVA_OPTIONS: '' }, + }); + assert.equal(result.exitCode, 0, result.stderr.toString()); + return result.stdout.toString(); +}; +const archives = files.map( + (file) => new Set(run(join(dirname(javap), 'jar'), ['tf', file]).split('\n')), +); +const methodType = 'java/lang/invoke/MethodType.class'; +const helper = 'java/lang/invoke/LambdaMetafactory.class'; +const constable = 'java/lang/constant/Constable.class'; +const classIdentity = (index: number, member: string) => { + assert(archives[index].has(member), `Missing actual class ${files[index]}!/${member}`); + const location = `jar:${pathToFileURL(files[index]).href}!/${member}`; + const output = run(javap, ['-verbose', location]); + assert( + output.startsWith(`Classfile ${location}\n`), + 'javap must inspect that actual archive member', + ); + const sha256 = output.match(/SHA-256 checksum ([a-f0-9]{64})/u)?.[1]; + assert(sha256, 'Actual class must report its SHA256'); + const declaration = output.split('\n').find((line) => line.startsWith('public ')); + assert(declaration, `Missing actual class declaration ${member}`); + return { sha256, declaration }; +}; +const sdkMethod = classIdentity(0, methodType); +const extrasMethod = classIdentity(1, methodType); +const mergedMethod = classIdentity(2, methodType); +assert(!sdkMethod.declaration.includes('java.lang.constant.Constable')); +assert(extrasMethod.declaration.includes('java.lang.constant.Constable')); +assert.equal(mergedMethod.declaration, sdkMethod.declaration); +assert( + archives.every((archive) => !archive.has(constable)), + 'Current Android closure lacks Constable', +); +const resolve = (order: number[], member: string) => + order.find((index) => archives[index].has(member)); +assert.equal(resolve([1, 2], methodType), 1, 'Old ordering selects the incompatible extras class'); +assert.equal( + resolve([2, 1], methodType), + 2, + 'Proposed ordering selects the actual SDK-derived class', +); +assert(!archives[0].has(helper), 'The Java bootstrap helper is absent from Android public stubs'); +const extrasHelper = classIdentity(1, helper); +const mergedHelper = classIdentity(2, helper); +assert.equal(mergedHelper.declaration, extrasHelper.declaration); +assert.notEqual( + resolve([2, 1], helper), + undefined, + 'Extras-only bootstrap helper must remain available', +); +console.log(`SDK MethodType: ${sdkMethod.sha256}\n${sdkMethod.declaration}`); +console.log(`Extras MethodType: ${extrasMethod.sha256}\n${extrasMethod.declaration}`); +console.log(`Selected SDK-derived MethodType: ${mergedMethod.sha256}`); +console.log(`Retained extras-only LambdaMetafactory: ${mergedHelper.sha256}`); +console.log( + 'Actual cached class identities prove SDK-first precedence; installed consumer execution remains required.', +); diff --git a/build_defs/languages/mobile-compiled-inputs.bzl b/build_defs/languages/mobile-compiled-inputs.bzl new file mode 100644 index 000000000..412530ba3 --- /dev/null +++ b/build_defs/languages/mobile-compiled-inputs.bzl @@ -0,0 +1,166 @@ +"""Original configured Rust suppliers shared by the Apple and Android FFI envelopes.""" + +load("@oliphaunt_metadata//:metadata.bzl", "COMPLETED_SUPPLIER_PUBLICATIONS", "PRODUCTS", "PUBLICATION_CARRIERS") +load("@native_cargo_metadata//:cargo.bzl", "CARGO") +load("@rules_rust//rust:defs.bzl", "rust_common") +load("//build_defs/release:identity.bzl", "ReleaseIdentityInfo") +load("//build_defs/release:supplier.bzl", "current_rust_shipping_supplier", "held_rust_shipping_supplier", "merge_shipping_suppliers") + +MOBILE_BINDINGS_COMPILE_OWNERS = {"core": "liboliphaunt-native-bindings", "sdk": "oliphaunt-rust", "broker": "oliphaunt-broker"} +MOBILE_BINDINGS_COMPILE_QUALIFICATION = { + "core": ["//src/native/rust-bindings:unit_test"], + "sdk": ["//src/native/sdks/rust:mobile_unit_test", "//src/native/mobile-bindings:unit_test"], + "broker": ["//src/native/broker:unit_test"], +} +MobileCompiledInputsInfo = provider(fields = ["current", "registry", "files", "upstream"]) + +def mobile_bindings_compile_group(owner, configuration): + return "compiled_" + owner + "_" + configuration.replace("-", "_") + +def _compiled_slot(ctx, target): + if target.label == Label("//src/native/mobile-bindings:lib"): + return "host-generator" + if ctx.target_platform_has_constraint(ctx.attr._android[platform_common.ConstraintValueInfo]): + if ctx.target_platform_has_constraint(ctx.attr._arm64[platform_common.ConstraintValueInfo]): + return "android-arm64-v8a" + if ctx.target_platform_has_constraint(ctx.attr._x64[platform_common.ConstraintValueInfo]): + return "android-x86_64" + fail("Mobile FFI compiler source requires an actual supported Android ABI") + if not ctx.target_platform_has_constraint(ctx.attr._arm64[platform_common.ConstraintValueInfo]): + fail("Mobile FFI compiler source requires its actual arm64 Apple slice") + if ctx.target_platform_has_constraint(ctx.attr._macos[platform_common.ConstraintValueInfo]): + return "macos-arm64" + if ctx.target_platform_has_constraint(ctx.attr._ios[platform_common.ConstraintValueInfo]): + for name, slot in [("_device", "ios-device"), ("_simulator", "ios-simulator")]: + if ctx.target_platform_has_constraint(getattr(ctx.attr, name)[platform_common.ConstraintValueInfo]): + return slot + fail("Mobile FFI compiler source has no declared Apple slice") + +def _current_compiled_supplier(crate, producers, configuration): + name, owner = producers[crate.owner] + source = PRODUCTS[owner.id]["path"] + if owner.id != MOBILE_BINDINGS_COMPILE_OWNERS[name] or source not in CARGO or CARGO[source]["version"] != owner.version or CARGO[source]["crate_name"] != crate.name or crate.type != "rlib": + fail("Mobile FFI dependency differs from its actual conventional Rust owner") + return current_rust_shipping_supplier(crate, crate.owner, owner, source, configuration) + +def _compiled_upstream(ctx, crate, producers, configuration): + current = [] + registry = [] + for dependency in crate.deps.to_list(): + value = dependency.crate_info + if not value: + continue + if value.owner in producers: + current.append(_current_compiled_supplier(value, producers, configuration)) + continue + carriers = [row for row in PUBLICATION_CARRIERS if row["ecosystem"] == "cargo" and row["name"].replace("-", "_") == value.name] + if not carriers: + continue + owner = ctx.attr._query_owner[ReleaseIdentityInfo] + if len(carriers) != 1 or carriers[0]["product"] != owner.id: + fail("Mobile FFI compiler contains an undeclared conventional Rust supplier: " + value.name) + name = carriers[0]["name"] + declaration = CARGO[crate.owner.package]["dependencies"].get(name) + if not declaration or (type(declaration) == "dict" and "path" in declaration): + fail("Mobile FFI query supplier must retain its actual declared registry source") + version = declaration if type(declaration) == "string" else declaration["version"] + key = owner.id + "@" + version.removeprefix("=") + origin = {"kind": "completed-publication", "publication": COMPLETED_SUPPLIER_PUBLICATIONS[key], "artifact": "cargo:" + name} if key in COMPLETED_SUPPLIER_PUBLICATIONS else None + registry.append(held_rust_shipping_supplier(value, owner, origin)) + return struct(current = merge_shipping_suppliers(current), registry = merge_shipping_suppliers(registry)) + +def merge_mobile_compiled_inputs(infos): + """Keep original configured Files and their upstream coverage together.""" + files = {} + upstream = {} + for observed in infos: + for group, file in observed.files.items(): + if group in files and files[group].path != file.path: + fail("Mobile FFI compiler slot mixes original configured Files") + files[group] = file + upstream[group] = merge_shipping_suppliers([upstream[group], observed.upstream[group]]) if group in upstream else observed.upstream[group] + return MobileCompiledInputsInfo( + current = merge_shipping_suppliers([observed.current for observed in infos]), + registry = merge_shipping_suppliers([observed.registry for observed in infos]), + files = files, + upstream = upstream, + ) + +def _compiled_inputs_impl(target, ctx): + infos = [] + registry = [] + files = {} + upstream = {} + if ctx.rule == None: + return [MobileCompiledInputsInfo(current = merge_shipping_suppliers([]), registry = merge_shipping_suppliers([]), files = files, upstream = upstream)] + if target.label in [Label("//src/native/mobile-bindings:static"), Label("//src/native/mobile-bindings:lib"), Label("//src/native/mobile-bindings:shared")]: + crate = target[rust_common.test_crate_info].crate if rust_common.test_crate_info in target else target[rust_common.crate_info] + if crate.owner != target.label or crate.type != {"static": "staticlib", "lib": "rlib", "shared": "cdylib"}[target.label.name]: + fail("Mobile FFI inputs must belong to the actual declared mobile compiler target") + configuration = _compiled_slot(ctx, target) + producers = { + Label("//src/native/rust-bindings:lib"): ("core", ctx.attr._core_owner[ReleaseIdentityInfo]), + Label("//src/native/sdks/rust:mobile_lib"): ("sdk", ctx.attr._sdk_owner[ReleaseIdentityInfo]), + Label("//src/native/broker:lib"): ("broker", ctx.attr._broker_owner[ReleaseIdentityInfo]), + } + registry.append(_compiled_upstream(ctx, crate, producers, configuration).registry) + for value in target[rust_common.dep_info].transitive_crates.to_list(): + if value.owner not in producers: + if value.name != "oliphaunt_query" and any([row["ecosystem"] == "cargo" and row["name"].replace("-", "_") == value.name for row in PUBLICATION_CARRIERS]): + fail("Mobile FFI compiler contains an undeclared conventional Rust supplier: " + value.name) + continue + name, _owner = producers[value.owner] + group = mobile_bindings_compile_group(name, configuration) + if group in files: + fail("Mobile FFI compiler repeats an original Rust dependency") + infos.append(_current_compiled_supplier(value, producers, configuration)) + files[group] = value.output + dependencies = _compiled_upstream(ctx, value, producers, configuration) + upstream[group] = merge_shipping_suppliers([dependencies.current, dependencies.registry]) + registry.append(dependencies.registry) + if len(files) != len(producers): + fail("Mobile FFI compiler must expose every actual local Rust dependency") + observations = [MobileCompiledInputsInfo(current = merge_shipping_suppliers(infos), registry = merge_shipping_suppliers(registry), files = files, upstream = upstream)] + for name in ["deps", "public_hdrs", "umbrella_header", "bindings", "library", "artifact"]: + dependencies = getattr(ctx.rule.attr, name, []) + if type(dependencies) != "list": + dependencies = [dependencies] + for dependency in dependencies: + if dependency and MobileCompiledInputsInfo in dependency: + observations.append(dependency[MobileCompiledInputsInfo]) + return [merge_mobile_compiled_inputs(observations)] + +mobile_compiled_inputs = aspect( + implementation = _compiled_inputs_impl, + attr_aspects = ["deps", "public_hdrs", "umbrella_header", "bindings", "library", "artifact"], + attrs = { + "_core_owner": attr.label(default = Label("@oliphaunt_metadata//:product_liboliphaunt-native-bindings")), + "_sdk_owner": attr.label(default = Label("@oliphaunt_metadata//:product_oliphaunt-rust")), + "_broker_owner": attr.label(default = Label("@oliphaunt_metadata//:product_oliphaunt-broker")), + "_query_owner": attr.label(default = Label("@oliphaunt_metadata//:product_oliphaunt-query")), + "_arm64": attr.label(default = Label("@platforms//cpu:aarch64")), + "_x64": attr.label(default = Label("@platforms//cpu:x86_64")), + "_android": attr.label(default = Label("@platforms//os:android")), + "_macos": attr.label(default = Label("@platforms//os:macos")), + "_ios": attr.label(default = Label("@platforms//os:ios")), + "_device": attr.label(default = Label("@apple_support//constraints:device")), + "_simulator": attr.label(default = Label("@apple_support//constraints:simulator")), + }, +) + +def _compiled_supplier_impl(ctx): + compiled = ctx.attr.inputs[MobileCompiledInputsInfo] + group = mobile_bindings_compile_group(ctx.attr.owner, ctx.attr.configuration) + if group not in compiled.upstream: + fail("Mobile FFI compiler root needs its exact original configured dependency coverage") + selected = compiled.upstream[group] + return [DefaultInfo(files = selected.files), selected] + +mobile_bindings_compiled_supplier = rule( + implementation = _compiled_supplier_impl, + attrs = { + "inputs": attr.label(mandatory = True, providers = [MobileCompiledInputsInfo]), + "owner": attr.string(mandatory = True, values = MOBILE_BINDINGS_COMPILE_OWNERS.keys()), + "configuration": attr.string(mandatory = True), + }, +) diff --git a/build_defs/languages/mobile-legal.mts b/build_defs/languages/mobile-legal.mts new file mode 100644 index 000000000..6464b98e0 --- /dev/null +++ b/build_defs/languages/mobile-legal.mts @@ -0,0 +1,43 @@ +import assert from 'node:assert/strict'; +import { chmodSync, copyFileSync, mkdirSync, realpathSync, statSync } from 'node:fs'; +import path from 'node:path'; +import { createMobileDependencyLicenseContract } from '../../src/native/mobile-bindings/tools/dependency-license-contract.mts'; + +const OWNER = 'src/native/mobile-bindings'; +const REQUIRED = [ + 'LICENSE', + 'THIRD_PARTY_NOTICES.md', + 'Cargo.lock', + `${OWNER}/dependency-licenses.json`, +]; +const LEGAL_INPUT = new RegExp(`^${OWNER}/dependency-license-blobs/[a-f0-9]{64}\\.base64$`); + +/** Stage only the explicit, canonical legal inputs shared by both mobile SDKs. */ +export function stageMobileLegalSources(sources: Record, sourceRoot: string) { + assert.ok(path.isAbsolute(sourceRoot), 'Mobile legal source root must be absolute'); + assert.ok(sources && typeof sources === 'object' && !Array.isArray(sources)); + for (const member of REQUIRED) + assert.equal(typeof sources[member], 'string', `Missing ${member}`); + const contract = createMobileDependencyLicenseContract(sourceRoot); + for (const [member, file] of Object.entries(sources)) { + assert.ok( + REQUIRED.includes(member) || + LEGAL_INPUT.test(member) || + member === `${OWNER}/tools/dependency-license-contract.mts`, + `Unexpected legal source ${member}`, + ); + assert.equal(typeof file, 'string'); + const physical = realpathSync(file); + const stat = statSync(physical); + assert.ok( + stat.isFile() && contract.hasSafeRustSourceFilesystemMode(stat.mode), + `Unsafe legal source ${member}`, + ); + const destination = path.join(sourceRoot, member); + mkdirSync(path.dirname(destination), { recursive: true }); + copyFileSync(physical, destination); + chmodSync(destination, 0o644); + } + contract.loadRustDependencyLicenseContract({ auditLock: true }); + return contract; +} diff --git a/build_defs/languages/mobile.bzl b/build_defs/languages/mobile.bzl new file mode 100644 index 000000000..46d98892f --- /dev/null +++ b/build_defs/languages/mobile.bzl @@ -0,0 +1,26 @@ +"""Host UniFFI generator from the conventional mobile bindgen target.""" + +load("@mobile_bindgen_crates//:defs.bzl", "crate_deps") +load("@native_cargo_metadata//:cargo.bzl", "CARGO") +load("@rules_rust//rust:defs.bzl", "rust_binary") +load(":rust.bzl", "cargo_features") + +def mobile_bindgen(name = "bindgen"): + facts = CARGO[native.package_name()] + binaries = [target for target in facts["binaries"] if target.get("required-features") == ["bindgen"]] + if len(binaries) != 1 or facts["features"].get("bindgen") != ["uniffi/cli"]: + fail("Mobile generator must retain its conventional UniFFI CLI target contract") + target = binaries[0] + # This target's source calls only UniFFI's CLI. The mobile runtime library + # is the generator's data input, not an executable dependency of its CLI. + rust_binary( + name = name, + srcs = [target["path"]], + crate_root = target["path"], + crate_name = target["name"].replace("-", "_"), + crate_features = cargo_features(facts, ["bindgen"], False), + edition = facts["edition"], + version = facts["version"], + rustc_env_files = [":cargo_env"], + deps = crate_deps(["uniffi"], package_name = native.package_name()), + ) diff --git a/build_defs/languages/napi-artifact-test.bzl b/build_defs/languages/napi-artifact-test.bzl new file mode 100644 index 000000000..0bcc7c855 --- /dev/null +++ b/build_defs/languages/napi-artifact-test.bzl @@ -0,0 +1,178 @@ +"""Node-API projections select the Rust cdylib even when import libraries coexist.""" + +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") +load("@rules_rust//rust:defs.bzl", "rust_common") +load(":rust.bzl", "napi_artifact") +load("//build_defs/wasix:napi.bzl", "WasixNapiInputsInfo", "WasixNapiReleaseInfo", "wasix_napi_release") +load("//build_defs/release:supplier.bzl", "ShippingSupplierInfo") +load("@oliphaunt_metadata//:metadata.bzl", "NATIVE_CURRENT_ARTIFACTS", "PRODUCTS", "WASIX_ARTIFACTS") + +def _library_impl(ctx): + library = ctx.actions.declare_file(ctx.label.name + ".dll") + import_library = ctx.actions.declare_file(ctx.label.name + ".dll.lib") + ctx.actions.write(library, "dynamic library fixture") + ctx.actions.write(import_library, "import library fixture") + return [ + DefaultInfo(files = depset([library, import_library])), + rust_common.test_crate_info(crate = rust_common.crate_info(type = ctx.attr.kind, output = library)), + ] + +_library = rule(implementation = _library_impl, attrs = {"kind": attr.string()}) + +def _release_inputs_impl(ctx): + tree = ctx.actions.declare_directory(ctx.label.name) + evidence = ctx.actions.declare_file(ctx.label.name + ".evidence") + ctx.actions.run_shell(outputs = [tree], command = "mkdir -p \"$1\"", arguments = [tree.path]) + ctx.actions.write(evidence, "analysis-only supplier fixture") + return [ + DefaultInfo(files = depset([tree])), + WasixNapiInputsInfo(tree = tree, target = "windows-x64-msvc", triple = "x86_64-pc-windows-msvc", sql_names = ["fixture"], sdk_version = "fixture-sdk"), + ShippingSupplierInfo(suppliers = [{"product": "declared-supplier-fixture"}], files = depset([evidence])), + ] + +_release_inputs = rule(implementation = _release_inputs_impl) + +def _projection_impl(ctx): + env = analysistest.begin(ctx) + actions = analysistest.target_actions(env) + asserts.equals(env, 1, len(actions)) + asserts.equals(env, ["napi_projection_library.dll"], [file.basename for file in actions[0].inputs.to_list()]) + asserts.equals(env, ["fixture.node"], [file.basename for file in analysistest.target_under_test(env)[DefaultInfo].files.to_list()]) + release = ctx.attr.release + asserts.equals(env, "napi_projection_library.dll", release[WasixNapiReleaseInfo].binary.basename) + asserts.equals(env, ["napi_projection_library.dll"], [file.basename for file in release[DefaultInfo].files.to_list()]) + asserts.equals(env, "fixture-sdk", release[WasixNapiReleaseInfo].inputs.sdk_version) + suppliers = release[ShippingSupplierInfo].suppliers + asserts.equals(env, {"product": "declared-supplier-fixture"}, suppliers[0]) + compiled = [] + for index, product, package, group in [ + (1, "oliphaunt-wasix-rust", "src/wasix/sdks/rust", "sdk_compiled"), + (2, "oliphaunt-pgwire-server", "src/wasix/pgwire-server", "server_compiled"), + ]: + supplier = suppliers[index] + asserts.equals(env, product, supplier["product"]) + asserts.equals(env, "windows-x64-msvc", supplier["configuration"]) + asserts.equals(env, "compiled-input", supplier["binding"]) + asserts.equals(env, {"kind": "current-source"}, supplier["origin"]) + files = getattr(release[OutputGroupInfo], group).to_list() + asserts.equals(env, 1, len(files)) + asserts.equals(env, Label("//" + package + ":shipping_supplier_fixture"), files[0].owner) + asserts.equals(env, [{"path": files[0].path}], supplier["files"]) + compiled.extend(files) + asserts.equals(env, sorted([file.path for file in compiled]), sorted([file.path for file in release[ShippingSupplierInfo].files.to_list() if file.basename != "napi_release_inputs.evidence"])) + return analysistest.end(env) + +_projection_test = analysistest.make(_projection_impl, attrs = {"release": attr.label(mandatory = True, providers = [WasixNapiReleaseInfo])}) + +def _rejected_impl(ctx): + env = analysistest.begin(ctx) + asserts.expect_failure(env, "Node-API artifacts require a Rust cdylib") + return analysistest.end(env) + +_rejected_test = analysistest.make(_rejected_impl, expect_failure = True) + +_NapiFeaturesInfo = provider(fields = ["features", "testonly"]) + +def _napi_features_impl(target, ctx): + return [_NapiFeaturesInfo(features = ctx.rule.attr.crate_features, testonly = ctx.rule.attr.testonly)] + +_napi_features = aspect(implementation = _napi_features_impl, required_providers = [rust_common.crate_info]) + +_SdkAotPayloadInfo = provider(fields = ["files"]) + +def _sdk_aot_payload_impl(target, ctx): + files = [] + if NATIVE_CURRENT_ARTIFACTS == None: + sdk = ctx.rule.attr.sdk[0][rust_common.crate_info] + for dependency in sdk.deps.to_list(): + crate = dependency.crate_info + if crate and crate.name.startswith("liboliphaunt_wasix_aot_"): + files.extend([file for file in crate.compile_data.to_list() if file.is_directory]) + return [_SdkAotPayloadInfo(files = files)] + +_sdk_aot_payload = aspect(implementation = _sdk_aot_payload_impl) + +def _payload_profile_impl(ctx): + env = analysistest.begin(ctx) + producer = analysistest.target_under_test(env) + expected = {} + for target in ctx.attr.public_archives: + for file in target[DefaultInfo].files.to_list(): + if file.basename in ctx.attr.archive_names: + asserts.false(env, file.basename in expected, "ambiguous original Cargo archive") + expected[file.basename] = file.path + asserts.equals(env, sorted(ctx.attr.archive_names), sorted(expected)) + actual = [file["path"] for supplier in producer[ShippingSupplierInfo].suppliers + if supplier["product"] == "liboliphaunt-wasix" for file in supplier["files"]] + asserts.equals(env, sorted(expected.values()), sorted(actual)) + for product, package, group in [ + ("oliphaunt-wasix-rust", "src/wasix/sdks/rust", "sdk_compiled"), + ("oliphaunt-pgwire-server", "src/wasix/pgwire-server", "server_compiled"), + ]: + files = getattr(producer[OutputGroupInfo], group).to_list() + asserts.equals(env, 1, len(files)) + asserts.equals(env, Label("//" + package + ":napi_release_lib"), files[0].owner) + suppliers = [supplier for supplier in producer[ShippingSupplierInfo].suppliers if supplier["product"] == product] + asserts.equals(env, 1, len(suppliers)) + asserts.equals(env, "compiled-input", suppliers[0]["binding"]) + asserts.equals(env, {"kind": "current-source"}, suppliers[0]["origin"]) + asserts.equals(env, [{"path": files[0].path}], suppliers[0]["files"]) + public_napi, unit_napi = ctx.attr.public_napi, ctx.attr.unit_napi + public_features = public_napi[_NapiFeaturesInfo].features + asserts.false(env, "noop" in public_features) + asserts.equals(env, sorted(public_features + ["noop"]), sorted(unit_napi[_NapiFeaturesInfo].features)) + asserts.true(env, unit_napi[_NapiFeaturesInfo].testonly) + asserts.equals(env, public_napi[rust_common.crate_info].root, unit_napi[rust_common.crate_info].root) + unit_dependencies = unit_napi[rust_common.crate_info].deps.to_list() + asserts.equals(env, 1, len(unit_dependencies)) + if len(unit_dependencies) == 1: + asserts.equals(env, public_napi[rust_common.crate_info].deps.to_list(), unit_dependencies[0].crate_group_info.dep_variant_infos.to_list()) + if ctx.attr.public_aot_payload: + expected_payload = ctx.attr.public_aot_payload[DefaultInfo].files.to_list() + actual_payload = producer[_SdkAotPayloadInfo].files + asserts.equals(env, 1, len(expected_payload)) + asserts.equals(env, expected_payload, actual_payload, + "SDK AOT payload paths: expected %s, got %s" % ([file.path for file in expected_payload], [file.path for file in actual_payload])) + return analysistest.end(env) + +_payload_profile_test = analysistest.make(_payload_profile_impl, attrs = { + "public_archives": attr.label_list(allow_files = True), + "archive_names": attr.string_list(), + "public_napi": attr.label(default = "@cargo_crates//:napi", aspects = [_napi_features], providers = [rust_common.crate_info]), + "unit_napi": attr.label(default = "@cargo_crates//:napi_noop", aspects = [_napi_features], providers = [rust_common.crate_info]), + "public_aot_payload": attr.label(), +}, extra_target_under_test_aspects = [_sdk_aot_payload]) + +def napi_artifact_tests(): + _release_inputs(name = "napi_release_inputs", tags = ["manual"]) + _library(name = "napi_projection_library", kind = "cdylib", tags = ["manual"]) + napi_artifact(name = "napi_projection", library = ":napi_projection_library", out = "fixture.node", tags = ["manual"]) + wasix_napi_release(name = "napi_release_projection", library = ":napi_projection_library", inputs = ":napi_release_inputs", sdk = "//src/wasix/sdks/rust:shipping_supplier_fixture", server = "//src/wasix/pgwire-server:shipping_supplier_fixture", testonly = True, tags = ["manual"]) + _projection_test(name = "napi_artifact_projection_test", target_under_test = ":napi_projection", release = ":napi_release_projection") + _library(name = "napi_rejected_library", kind = "staticlib", tags = ["manual"]) + napi_artifact(name = "napi_rejected", library = ":napi_rejected_library", out = "rejected.node", tags = ["manual"]) + _rejected_test(name = "napi_artifact_kind_test", target_under_test = ":napi_rejected") + wasix_napi_release(name = "napi_release_rejected", library = ":napi_rejected_library", inputs = ":napi_release_inputs", sdk = "//src/wasix/sdks/rust:shipping_supplier_fixture", server = "//src/wasix/pgwire-server:shipping_supplier_fixture", testonly = True, tags = ["manual"]) + _rejected_test(name = "wasix_napi_release_kind_test", target_under_test = ":napi_release_rejected") + archives, names, aot_payloads = {}, {}, {} + version = PRODUCTS["liboliphaunt-wasix"]["version"] + for row in WASIX_ARTIFACTS: + if row["product"] != "oliphaunt-wasix-napi" or row["kind"] != "wasix-napi-addon": + continue + condition = "@rules_rust//rust/platform:" + row["triple"] + packages = ["liboliphaunt-wasix-portable", "liboliphaunt-wasix-aot-" + row["triple"], + "oliphaunt-extension-contrib-pg18-wasix", "oliphaunt-extension-contrib-pg18-aot-" + row["target"].removesuffix("-gnu").removesuffix("-msvc")] + archives[condition] = [ + original["file"]["path"] + for package in packages + for original in [NATIVE_CURRENT_ARTIFACTS.get("liboliphaunt-wasix/" + version + "/cargo:" + package)] + if original + ] if NATIVE_CURRENT_ARTIFACTS != None else [ + "//src/wasix/runtime/crates/assets:crate", "//src/wasix/runtime/crates/aot/" + row["triple"] + ":crate", "//build_defs/extensions/wasix:contrib", + ] + names[condition] = [package + "-" + version + ".crate" for package in packages] + if NATIVE_CURRENT_ARTIFACTS == None: + aot_payloads[condition] = "//src/wasix/runtime:aot_" + row["target"].replace("-", "_") + "_payload" + _payload_profile_test(name = "napi_payload_profile_test", target_under_test = "//src/wasix/node-addon:release_addon", + public_archives = select(archives), archive_names = select(names), + public_aot_payload = select(aot_payloads) if NATIVE_CURRENT_ARTIFACTS == None else None) diff --git a/build_defs/languages/napi-noop.bzl b/build_defs/languages/napi-noop.bzl new file mode 100644 index 000000000..1b489e706 --- /dev/null +++ b/build_defs/languages/napi-noop.bzl @@ -0,0 +1,35 @@ +"""Keep napi's conventional noop feature confined to Rust unit tests.""" + +load("@cargo_crates//:defs.bzl", "crate_deps") +load("@rules_rust//rust:defs.bzl", "rust_common", "rust_library") + +def _napi_dependencies_impl(ctx): + return [rust_common.crate_group_info(dep_variant_infos = ctx.attr.library[rust_common.crate_info].deps)] + +_napi_dependencies = rule( + implementation = _napi_dependencies_impl, + attrs = {"library": attr.label(mandatory = True, providers = [rust_common.crate_info])}, +) + +def napi_noop_library(): + # crate_universe appends this call after its generated public library. + _napi_dependencies(name = "napi_noop_dependencies", library = ":napi", testonly = True) + attributes = dict(native.existing_rule("napi")) + attributes.pop("kind") + # The original library forwards stock platform compatibility through the group. + # Copying its selector would lose the foreign @platforms root-package label. + attributes.pop("target_compatible_with", None) + if not attributes.get("restricted_to"): + attributes.pop("restricted_to", None) + attributes["name"] = "napi_noop" + attributes["crate_name"] = "napi" + attributes["crate_features"] = list(attributes["crate_features"]) + ["noop"] + attributes["testonly"] = True + attributes["visibility"] = ["//visibility:public"] + # existing_rule loses foreign repositories for labels in the root package. + # Forward the selected typed dependencies instead of its converted strings. + attributes["deps"] = [":napi_noop_dependencies"] + rust_library(**attributes) + +def napi_unit_crate_deps(deps, package_name = None): + return [Label("@cargo_crates//:napi_noop") if name == "napi" else crate_deps([name], package_name = package_name)[0] for name in deps] diff --git a/build_defs/languages/repositories.bzl b/build_defs/languages/repositories.bzl new file mode 100644 index 000000000..c2c424135 --- /dev/null +++ b/build_defs/languages/repositories.bzl @@ -0,0 +1,40 @@ +"""One-way Cargo dependency and compile-fact projections from conventional inputs.""" + +def _cargo_metadata_impl(ctx): + ctx.read(ctx.attr.workspace) + ctx.read(ctx.attr.lockfile) + ctx.read(ctx.attr.converter) + ctx.read(ctx.attr.manifest_helper) + ctx.watch(ctx.path(ctx.attr.bun)) + result = ctx.execute([ + ctx.path(ctx.attr.bun), + ctx.path(ctx.attr.converter), + ctx.path(ctx.attr.workspace), + ctx.path(ctx.attr.lockfile), + ctx.path("."), + ] + ctx.attr.roots + (["--workspace-prefix", ctx.attr.workspace_prefix] if ctx.attr.workspace_prefix else []) + ["--activate", json.encode(ctx.attr.activations)], quiet = True) + if result.return_code: + fail("Cannot import conventional Cargo inputs: " + result.stderr) + data = json.decode(result.stdout) + workspace_root = ctx.path(ctx.attr.workspace).dirname + for _ in ctx.attr.workspace_prefix.split("/") if ctx.attr.workspace_prefix else []: + workspace_root = workspace_root.dirname + for relative in data["manifests"] + data["watched"]: + ctx.watch(workspace_root.get_child(relative)) + ctx.file("cargo.bzl", "CARGO = " + repr(data["facts"]) + "\n") + ctx.file("BUILD.bazel", "exports_files(" + repr(["Cargo.toml", "Cargo.lock", "cargo.bzl"] + data["manifests"]) + ', visibility = ["//visibility:public"])\n') + return ctx.repo_metadata(reproducible = True) + +cargo_metadata_repository = repository_rule( + implementation = _cargo_metadata_impl, + attrs = { + "workspace": attr.label(default = Label("//:Cargo.toml"), allow_single_file = True), + "lockfile": attr.label(default = Label("//:Cargo.lock"), allow_single_file = True), + "converter": attr.label(default = Label("//build_defs/languages:cargo-metadata.mts"), allow_single_file = True), + "manifest_helper": attr.label(default = Label("//:tools/packaging/cargo-manifest.mts"), allow_single_file = True), + "workspace_prefix": attr.string(), + "bun": attr.label(default = Label("@bun_runtime//:bun"), allow_single_file = True), + "roots": attr.string_list(), + "activations": attr.string_list_dict(), + }, +) diff --git a/build_defs/languages/rust.bzl b/build_defs/languages/rust.bzl new file mode 100644 index 000000000..99066a6d1 --- /dev/null +++ b/build_defs/languages/rust.bzl @@ -0,0 +1,330 @@ +"""Native rules_rust construction using conventional Cargo compile facts.""" + +load("@cargo_crates//:defs.bzl", "all_crate_deps", "crate_deps") +load("@native_cargo_metadata//:cargo.bzl", "CARGO") +load("@rules_rust//cargo:defs.bzl", "cargo_build_script", "cargo_toml_env_vars") +load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_common", "rust_doc_test", "rust_library", "rust_shared_library", "rust_static_library", "rust_test") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") + +# These are the canonical first-party Cargo conditions currently in the workspace. +# Unknown conditions fail instead of silently dropping a dependency. The labels +# are the same exact triple conditions used by crate_universe for external deps. +_TARGET_CONDITIONS = { + 'cfg(all(target_os = "macos", target_arch = "aarch64"))': ["aarch64-apple-darwin"], + 'cfg(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu"))': ["x86_64-unknown-linux-gnu"], + 'cfg(all(target_os = "linux", target_arch = "aarch64", target_env = "gnu"))': ["aarch64-unknown-linux-gnu"], + 'cfg(all(target_os = "windows", target_arch = "x86_64", target_env = "msvc"))': ["x86_64-pc-windows-msvc"], + "cfg(unix)": ["x86_64-unknown-linux-gnu", "aarch64-unknown-linux-gnu", "aarch64-apple-darwin", "aarch64-apple-ios", "aarch64-apple-ios-sim", "aarch64-linux-android", "x86_64-linux-android"], +} + +def cargo_features(facts, features = [], default_features = True): + """Expand source feature names, preserving optional dependency activation.""" + enabled = {feature: True for feature in features} + if default_features and "default" in facts["features"]: + enabled["default"] = True + for _ in range(len(facts["features"]) + 1): + added = False + for feature in enabled.keys(): + if feature not in facts["features"]: + declaration = facts["dependencies"].get(feature) + if type(declaration) != "dict" or not declaration.get("optional", False): + fail("Unknown conventional Cargo feature " + feature) + for item in facts["features"].get(feature, []): + if "/" not in item and not item.startswith("dep:") and item not in enabled: + enabled[item] = True + added = True + if not added: + break + return enabled.keys() + +def _active(declaration, name, facts, features): + if type(declaration) == "string" or not declaration.get("optional", False): + return True + if name in features: + return True + for feature in features: + for item in facts["features"].get(feature, []): + if item == "dep:" + name or item.startswith(name + "/"): + return True + return False + +def _package_name(package_name): + return package_name or native.package_name() + +def _source_prefix(package_name): + package_name = _package_name(package_name) + if package_name == native.package_name(): + return "" + prefix = native.package_name() + "/" if native.package_name() else "" + if not package_name.startswith(prefix): + fail("Cargo source package must be inside its Bazel owner: " + package_name) + return package_name.removeprefix(prefix) + "/" + +def _table_dependencies(table, facts, features, path_dependencies, proc_macro_names, crate_dependencies, package_name): + normal = [] + macros = [] + for name, declaration in table.items(): + if not _active(declaration, name, facts, features): + continue + if type(declaration) == "dict" and "path" in declaration: + if name not in path_dependencies: + fail("Missing native Cargo path dependency " + name + " for " + native.package_name()) + normal.append(path_dependencies[name]) + elif name in proc_macro_names: + macros.extend(crate_dependencies([name], package_name = package_name)) + else: + normal.extend(crate_dependencies([name], package_name = package_name)) + return normal, macros + +def _dependencies(facts, features, section, path_dependencies, proc_macro_names, crate_dependencies = crate_deps, include_dev = False, package_name = None): + table = facts[section] | facts["dev_dependencies"] if include_dev else facts[section] + package_name = _package_name(package_name) + normal, macros = _table_dependencies(table, facts, features, path_dependencies, proc_macro_names, crate_dependencies, package_name) + cargo_section = section.replace("_", "-") + for condition, table in facts["target_dependencies"].items(): + dependencies = table.get(cargo_section, {}) + if include_dev: + dependencies = dependencies | table.get("dev-dependencies", {}) + if not dependencies: + continue + if condition not in _TARGET_CONDITIONS: + fail("Unrepresented Cargo target condition " + condition + " for " + native.package_name()) + target_normal, target_macros = _table_dependencies(dependencies, facts, features, path_dependencies, proc_macro_names, crate_dependencies, package_name) + normal = normal + select({"@rules_rust//rust/platform:" + triple: target_normal for triple in _TARGET_CONDITIONS[condition]} | {"//conditions:default": []}) + macros = macros + select({"@rules_rust//rust/platform:" + triple: target_macros for triple in _TARGET_CONDITIONS[condition]} | {"//conditions:default": []}) + return normal, macros + +def _readme(facts, source_prefix = ""): + return [source_prefix + facts["readme"]] if facts["readme"] else [] + +def _release_flags(facts): + strip = facts.get("release_strip") + if strip == None: + return [] + if strip != "symbols": + fail("Unrepresented conventional Cargo release strip setting: " + str(strip)) + return select({"//build_defs/languages:release": ["-Cstrip=" + strip], "//conditions:default": []}) + +def cargo_package_env(name = "cargo_env", workspace_manifest = "//:Cargo.toml", package_name = None): + cargo_toml_env_vars( + name = name, + src = _source_prefix(package_name) + "Cargo.toml", + workspace = workspace_manifest, + ) + +def cargo_generator(name = "build_script", path_dependencies = {}, srcs = [], data = [], tools = [], build_script_env = {}, features = [], default_features = True, proc_macro_names = [], cargo_facts = CARGO, crate_dependencies = crate_deps, package_name = None, cargo_env = ":cargo_env"): + package_name = _package_name(package_name) + prefix = _source_prefix(package_name) + facts = cargo_facts[package_name] + if not facts["build"]: + fail("Cargo manifest has no build script for " + native.package_name()) + enabled = cargo_features(facts, features, default_features) + deps, macros = _dependencies(facts, enabled, "build_dependencies", path_dependencies, proc_macro_names, crate_dependencies, package_name = package_name) + link_deps, _ = _dependencies(facts, enabled, "dependencies", path_dependencies, proc_macro_names, crate_dependencies, package_name = package_name) + cargo_build_script( + name = name, + srcs = [prefix + facts["build"]] + srcs, + crate_root = prefix + facts["build"], + # Cargo's private build-script name also bounds Windows object paths. + crate_name = "build_script_build", + rustc_env = {"CARGO_CRATE_NAME": "build_script_build"}, + pkg_name = facts["name"], + edition = facts["edition"], + version = facts["version"], + crate_features = enabled, + deps = deps, + link_deps = link_deps, + proc_macro_deps = macros, + rustc_env_files = [cargo_env], + data = [prefix + "Cargo.toml"] + data, + tools = tools, + build_script_env = ({"CARGO_MANIFEST_DIR": package_name} if prefix else {}) | build_script_env, + use_default_shell_env = False, + links = facts["links"], + ) + +def cargo_generator_test(name = "generator_test", path_dependencies = {}, srcs = [], features = [], default_features = True, proc_macro_names = [], **kwargs): + facts = CARGO[native.package_name()] + if not facts["build"]: + fail("Cargo manifest has no build script for " + native.package_name()) + enabled = cargo_features(facts, features, default_features) + deps, macros = _dependencies(facts, enabled, "build_dependencies", path_dependencies, proc_macro_names) + rust_test( + name = name, + srcs = [facts["build"]] + srcs, + crate_root = facts["build"], + edition = facts["edition"], + version = facts["version"], + crate_features = enabled, + deps = deps, + proc_macro_deps = macros, + rustc_env_files = [":cargo_env"], + **kwargs + ) + +def cargo_library(name = "lib", kind = "rlib", path_dependencies = {}, proc_macro_names = [], features = [], default_features = True, build_script = None, compile_data = [], rustc_env = {}, rustc_flags = [], cargo_facts = CARGO, crate_dependencies = crate_deps, package_name = None, cargo_env = ":cargo_env", **kwargs): + package_name = _package_name(package_name) + prefix = _source_prefix(package_name) + facts = cargo_facts[package_name] + if not facts["library"]: + fail("Cargo manifest has no library for " + native.package_name()) + if bool(facts["build"]) != bool(build_script): + fail("Native Cargo build script must match the conventional manifest for " + native.package_name()) + enabled = cargo_features(facts, features, default_features) + deps, macros = _dependencies(facts, enabled, "dependencies", path_dependencies, proc_macro_names, crate_dependencies, package_name = package_name) + constructor = {"rlib": rust_library, "cdylib": rust_shared_library, "staticlib": rust_static_library}.get(kind) + if not constructor: + fail("Unsupported native Cargo library kind " + kind) + constructor( + name = name, + srcs = native.glob([prefix + "src/**/*.rs"], exclude = [prefix + "src/main.rs", prefix + "src/bin/**/*.rs"]), + crate_root = prefix + facts["library"], + crate_name = facts["crate_name"], + edition = facts["edition"], + version = facts["version"], + crate_features = enabled, + deps = deps + ([build_script] if build_script else []), + proc_macro_deps = macros, + rustc_env_files = [cargo_env], + rustc_env = ({"CARGO_MANIFEST_DIR": package_name} if prefix else {}) | rustc_env, + rustc_flags = rustc_flags + _release_flags(facts), + compile_data = _readme(facts, prefix) + native.glob([prefix + "src/**/*"], exclude = [prefix + "src/**/*.rs"], allow_empty = True) + compile_data, + **kwargs + ) + +def cargo_napi_library(name, rustc_flags = [], **kwargs): + """Preserve napi-build's macOS cdylib linker policy, ignored by rules_rust.""" + cargo_library( + name = name, + kind = "cdylib", + rustc_flags = rustc_flags + select({ + "@platforms//os:macos": [ + "-Clink-arg=-Wl", + "-Clink-arg=-undefined", + "-Clink-arg=dynamic_lookup", + ], + "//conditions:default": [], + }), + **kwargs + ) + +def _isolated_cache_test_impl(ctx): + binary = ctx.attr.binary[DefaultInfo].files_to_run.executable + return bun_test_entrypoint(ctx, runner = ctx.file._runner, arguments = [binary], files = [binary], source_files = [ctx.file._runner], additional_runfiles = ctx.attr.binary[DefaultInfo].default_runfiles) + [ctx.attr.binary[RunEnvironmentInfo]] + +_isolated_cache_test = rule( + implementation = _isolated_cache_test_impl, + test = True, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "binary": attr.label(mandatory = True, executable = True, cfg = "target"), + "_runner": attr.label(default = "//build_defs/languages:isolated-cache-test.mts", allow_single_file = True), + }), + toolchains = BUN_SOURCE_TOOLCHAINS, +) + +def cargo_library_test(name = "unit_test", crate = ":lib", data = [], tags = [], isolated_cache = False, cargo_facts = CARGO, all_dependencies = all_crate_deps, package_name = None, cargo_env = ":cargo_env", path_dependencies = {}, rustc_env = {}, features = [], default_features = True, crate_dependencies = crate_deps, proc_macro_names = [], build_script = None, **kwargs): + package_name = _package_name(package_name) + facts = cargo_facts[package_name] + enabled = cargo_features(facts, features, default_features) + if crate == None: + deps, macros = _dependencies(facts, enabled, "dependencies", path_dependencies, proc_macro_names, crate_dependencies, include_dev = True, package_name = package_name) + else: + deps = all_dependencies(normal_dev = True, package_name = package_name) + path_dependencies.values() + macros = all_dependencies(proc_macro_dev = True, package_name = package_name) + rust_test( + name = name + "_binary" if isolated_cache else name, + crate = crate, + edition = facts["edition"], + version = facts["version"], + crate_features = enabled, + deps = deps + ([build_script] if build_script else []), + proc_macro_deps = macros, + rustc_env_files = [cargo_env], + rustc_env = rustc_env | {"CARGO_MANIFEST_DIR": package_name}, + data = data + [_source_prefix(package_name) + "Cargo.toml"], + tags = tags + (["manual"] if isolated_cache else []), + **kwargs + ) + if isolated_cache: + _isolated_cache_test(name = name, binary = ":" + name + "_binary", args = bun_test_entrypoint_args(name), size = kwargs.get("size", "small")) + +def cargo_integration_test(name, source, crate = ":lib", srcs = [], data = [], rustc_env = {}, features = [], default_features = True, path_dependencies = {}, proc_macro_names = [], cargo_facts = CARGO, crate_dependencies = crate_deps, package_name = None, cargo_env = ":cargo_env", **kwargs): + """Compile a conventional external integration root against its actual library.""" + package_name = _package_name(package_name) + facts = cargo_facts[package_name] + enabled = cargo_features(facts, features, default_features) + normal, macros = _dependencies(facts, enabled, "dependencies", path_dependencies, proc_macro_names, crate_dependencies, include_dev = True, package_name = package_name) + rust_test( + name = name, + srcs = [source] + srcs, + crate_root = source, + edition = facts["edition"], + version = facts["version"], + crate_features = enabled, + deps = [crate] + normal, + proc_macro_deps = macros, + rustc_env_files = [cargo_env], + rustc_env = {"CARGO_MANIFEST_DIR": package_name} | rustc_env, + data = data + [_source_prefix(package_name) + "Cargo.toml"], + **kwargs + ) + +def cargo_doc_test(name = "doc_test", crate = ":lib", features = [], default_features = True, cargo_facts = CARGO, **kwargs): + """Run maintained rustdoc tests with the conventional Cargo feature closure.""" + rust_doc_test( + name = name, + crate = crate, + crate_features = cargo_features(cargo_facts[native.package_name()], features, default_features), + **kwargs + ) + +def cargo_binary(name, source, path_dependencies = {}, features = [], default_features = True, build_script = None, proc_macro_names = [], library = None, crate_dependencies = crate_deps, rustc_env = {}, rustc_flags = [], compile_data = [], cargo_facts = CARGO, package_name = None, cargo_env = ":cargo_env", **kwargs): + package_name = _package_name(package_name) + prefix = _source_prefix(package_name) + facts = cargo_facts[package_name] + enabled = cargo_features(facts, features, default_features) + binaries = [target for target in facts["binaries"] if prefix + target["path"] == source] + if not binaries and source == prefix + "src/main.rs": + binaries = [{"name": facts["name"]}] + if len(binaries) != 1: + fail("Native binary must match a conventional Cargo target: " + source) + for required in binaries[0].get("required-features", []): + if required not in enabled: + fail("Native binary requires conventional Cargo feature " + required) + deps, macros = _dependencies(facts, enabled, "dependencies", path_dependencies, proc_macro_names, crate_dependencies, package_name = package_name) + rust_binary( + name = name, + srcs = native.glob([prefix + "src/**/*.rs"]), + crate_root = source, + crate_name = binaries[0]["name"].replace("-", "_"), + edition = facts["edition"], + version = facts["version"], + crate_features = enabled, + deps = deps + ([build_script] if build_script else []) + ([library] if library else []), + proc_macro_deps = macros, + rustc_env_files = [cargo_env], + rustc_env = ({"CARGO_MANIFEST_DIR": package_name} if prefix else {}) | rustc_env, + rustc_flags = rustc_flags + _release_flags(facts), + compile_data = _readme(facts, prefix) + compile_data, + **kwargs + ) + +def rust_cdylib_output(library): + """Select the typed Rust binary when platform auxiliary files coexist.""" + crate = library[rust_common.test_crate_info].crate + if crate.type != "cdylib": + fail("Node-API artifacts require a Rust cdylib") + return crate.output + +def _napi_artifact_impl(ctx): + output = ctx.actions.declare_file(ctx.attr.out) + ctx.actions.symlink(output = output, target_file = rust_cdylib_output(ctx.attr.library)) + return [DefaultInfo(files = depset([output]))] + +napi_artifact = rule( + implementation = _napi_artifact_impl, + attrs = { + "library": attr.label(providers = [rust_common.test_crate_info], mandatory = True), + "out": attr.string(mandatory = True), + }, +) diff --git a/build_defs/languages/source-contract.mts b/build_defs/languages/source-contract.mts new file mode 100644 index 000000000..77fc7a284 --- /dev/null +++ b/build_defs/languages/source-contract.mts @@ -0,0 +1,177 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { mkdirSync, readFileSync, realpathSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { assertPackagedCargoDependencies } from '../../tools/packaging/cargo-dependencies.mts'; +import { + extractPortableArchiveTree, + readPortableArchiveEntries, +} from '../../tools/packaging/portable-archive.mts'; +import { + renderUnsupportedNativeTargetGuard, + rustNativeTargetCfg, +} from '../../tools/packaging/rust-native-targets.mts'; +import { type SourceMetadata, sourceManifest } from './source-package.mts'; + +export type CargoSourceContract = { + archive: string; + manifest: string; + workspace: string; + metadata: SourceMetadata; + entries: Record; +}; + +/** Check actual public source bytes against declared checkout files and requirements. */ +export function verifyCargoSourceContract(spec: CargoSourceContract) { + const original = readFileSync(spec.manifest, 'utf8'); + const expected = sourceManifest(original, readFileSync(spec.workspace, 'utf8'), spec.metadata); + const root = `${expected.package.name}-${expected.package.version}`; + const entries = readPortableArchiveEntries(realpathSync(spec.archive)); + const bytes = (member: string) => { + const entry = entries.get(`${root}/${member}`); + assert(entry?.isFile, `Cargo source archive omitted ${member}`); + return Buffer.from(entry.data()); + }; + const packed = Bun.TOML.parse(bytes('Cargo.toml').toString('utf8')); + assert.deepEqual(packed.package, expected.package, 'public Cargo package metadata changed'); + assert.deepEqual(packed.features ?? {}, expected.features ?? {}, 'public Cargo features changed'); + assertPackagedCargoDependencies(packed, expected, 'public Cargo source archive'); + assert.deepEqual(packed.workspace, {}, 'source package must isolate its consumer workspace'); + assert.equal( + bytes('Cargo.toml.orig').toString('utf8'), + original, + 'original manifest bytes changed', + ); + for (const [name, entry] of entries) { + assert( + (name === root && entry.isDirectory) || name.startsWith(`${root}/`), + `Cargo source member is outside declared package: ${name}`, + ); + assert( + (entry.isFile && entry.mode === 0o644) || (entry.isDirectory && entry.mode === 0o755), + `Cargo source member has invalid type or mode: ${name}`, + ); + if (entry.isDirectory) continue; + const member = name.slice(root.length + 1); + if (member === 'Cargo.toml' || member === 'Cargo.toml.orig') continue; + const source = spec.entries[member]; + assert(source, `Cargo source archive contains undeclared member ${member}`); + const authored = readFileSync(source); + const actual = Buffer.from(entry.data()); + if (member === 'src/lib.rs' && spec.metadata.nativeArtifacts) { + const targets = spec.metadata.nativeArtifacts.map((row) => row.target); + const guard = renderUnsupportedNativeTargetGuard({ + product: packed.package.name, + nativeTargets: targets, + nativeCfgs: targets.map(rustNativeTargetCfg), + guidance: 'use the separately versioned oliphaunt-wasix crate for WASIX environments.', + }); + assert.equal( + actual.toString('utf8'), + `${authored.toString('utf8')}\n${guard}\n`, + 'native SDK source archive changed its library or target guard', + ); + } else assert(actual.equals(authored), `Cargo source bytes changed: ${member}`); + } + // Both SDKs promise their complete library tree and fixture payloads. Cargo + // owns checkout-only tests/tools selection; those are not rebuilt here. + for (const member of Object.keys(spec.entries)) + if ( + ['LICENSE', 'THIRD_PARTY_NOTICES.md', 'README.md', 'build.rs'].includes(member) || + member.startsWith('src/') || + member.startsWith('testdata/') + ) + bytes(member); + return { root, manifest: packed, members: entries.size }; +} + +async function main(specification: string, runfiles: string) { + assert(process.env.TEST_TMPDIR, 'source qualification requires Bazel TEST_TMPDIR'); + const spec = JSON.parse(readFileSync(specification, 'utf8')); + const file = (name: string) => path.join(runfiles, name); + const receipts = []; + for (const [index, source] of spec.packages.entries()) { + const input: CargoSourceContract = { + archive: file(source.archive), + manifest: file(source.manifest), + workspace: file(source.workspace), + metadata: JSON.parse(readFileSync(file(source.metadata), 'utf8')), + entries: Object.fromEntries( + Object.entries(source.entries).map(([name, value]) => [name, file(value as string)]), + ), + }; + const contract = verifyCargoSourceContract(input); + const directory = path.join(process.env.TEST_TMPDIR, String(index)); + const sourceRoot = path.join(directory, 'source'); + const home = path.join(directory, 'cargo-home'); + mkdirSync(home, { recursive: true }); + extractPortableArchiveTree(realpathSync(input.archive), sourceRoot, contract.root); + const result = Bun.spawnSync( + [ + file(spec.cargo), + 'metadata', + '--offline', + '--no-deps', + '--format-version', + '1', + '--manifest-path', + path.join(sourceRoot, 'Cargo.toml'), + ], + { + env: { + HOME: home, + CARGO_HOME: home, + CARGO_NET_OFFLINE: 'true', + RUSTC: file(spec.rustc), + PATH: path.dirname(file(spec.rustc)), + }, + }, + ); + assert.equal( + result.exitCode, + 0, + `installed Cargo source metadata failed: ${result.stderr.toString()}`, + ); + const packages = JSON.parse(result.stdout.toString()).packages; + assert.equal(packages.length, 1, 'source package must expose one conventional Cargo identity'); + const [compiled] = packages; + assert.equal(compiled.name, contract.manifest.package.name); + assert.equal(compiled.version, contract.manifest.package.version); + assert.deepEqual(compiled.features, contract.manifest.features ?? {}); + assert(compiled.targets.length > 0, 'public source manifest omitted its compiler targets'); + for (const target of compiled.targets) { + const member = path.relative(sourceRoot, target.src_path).split(path.sep).join('/'); + assert( + member && !member.startsWith('../') && !path.isAbsolute(member), + 'Cargo target escapes its source package', + ); + assert(input.entries[member], `Cargo target has undeclared source ${member}`); + readFileSync(target.src_path); + } + receipts.push({ + name: compiled.name, + version: compiled.version, + members: contract.members, + sha256: createHash('sha256').update(readFileSync(input.archive)).digest('hex'), + targets: compiled.targets.map((target: { name: string; kind: string[] }) => ({ + name: target.name, + kind: target.kind, + })), + }); + } + const output = process.env.TEST_UNDECLARED_OUTPUTS_DIR ?? process.env.TEST_TMPDIR; + mkdirSync(output, { recursive: true }); + writeFileSync( + path.join(output, 'cargo-source-contract.json'), + `${JSON.stringify({ schema: 'oliphaunt-cargo-source-contract-v1', packages: receipts }, null, 2)}\n`, + ); +} + +if (import.meta.main) { + const [specification, runfiles] = process.argv.slice(2); + assert( + specification && runfiles && process.argv.length === 4, + 'expected source specification and runfiles root', + ); + await main(specification, runfiles); +} diff --git a/build_defs/languages/source-contract.test.mts b/build_defs/languages/source-contract.test.mts new file mode 100644 index 000000000..3411c36ca --- /dev/null +++ b/build_defs/languages/source-contract.test.mts @@ -0,0 +1,139 @@ +import { expect, test } from 'bun:test'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { renderCargoToml } from '../../tools/packaging/cargo-manifest.mts'; +import { readPortableArchiveEntries } from '../../tools/packaging/portable-archive.mts'; +import { archive } from '../query/package.mts'; +import { type CargoSourceContract, verifyCargoSourceContract } from './source-contract.mts'; +import { sourceEnvelope } from './source-package.mts'; + +async function fixture(root: string, version = '0.3.2'): Promise { + mkdirSync(path.join(root, 'src'), { recursive: true }); + const entries: Record = {}; + for (const [member, bytes] of Object.entries({ + 'Cargo.toml': `[package]\nname="sdk"\nversion="${version}"\nedition="2024"\n[features]\ndefault=["desktop"]\ndesktop=["dep:query"]\n[dependencies]\nquery={path="../query",version="0.1.1",optional=true,default-features=false,features=["std"]}\n`, + 'src/lib.rs': 'pub fn source() -> u8 { 42 }\n', + LICENSE: 'MIT\n', + 'THIRD_PARTY_NOTICES.md': 'Source SDK notice\n', + 'README.md': 'SDK\n', + })) { + entries[member] = path.join(root, member); + writeFileSync(entries[member], bytes); + } + const workspace = path.join(root, 'workspace.toml'); + writeFileSync(workspace, '[workspace]\n'); + const metadata = { + product: 'sdk', + version, + compatibility: { runtime: '0.3.2', broker: '0.3.1' }, + dependencyOwners: {}, + nativeArtifacts: [ + { sourceProduct: 'runtime', target: 'linux-x64-gnu', packageName: 'runtime-linux-x64-gnu' }, + ], + brokerArtifacts: [ + { sourceProduct: 'broker', target: 'linux-x64-gnu', packageName: 'broker-linux-x64-gnu' }, + ], + }; + const file = path.join(root, 'sdk.crate'); + writeFileSync(file, await sourceEnvelope(entries['Cargo.toml'], workspace, entries, metadata)); + return { archive: file, manifest: entries['Cargo.toml'], workspace, metadata, entries }; +} + +test('actual source archives preserve defaults and independent installed pins across SDK increments', async () => { + const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-source-contract-')); + try { + for (const version of ['0.3.2', '0.3.3', '0.4.0']) { + const input = await fixture(path.join(root, version), version); + const contract = verifyCargoSourceContract(input); + expect(contract.manifest.features.default).toEqual(['desktop']); + expect(contract.manifest.dependencies.query).toEqual({ + version: '0.1.1', + optional: true, + 'default-features': false, + features: ['std'], + }); + const deps = + contract.manifest.target[ + 'cfg(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu"))' + ].dependencies; + expect(deps['runtime-linux-x64-gnu'].version).toBe('=0.3.2'); + expect(deps['broker-linux-x64-gnu'].version).toBe('=0.3.1'); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('actual package reader rejects missing/extra source, stripped defaults and retargeted dependencies', async () => { + const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-source-contract-faults-')); + try { + const input = await fixture(root); + const files = Object.fromEntries( + [...readPortableArchiveEntries(input.archive)] + .filter(([, entry]) => entry.isFile) + .map(([name, entry]) => [name, Buffer.from(entry.data())]), + ); + const prefix = 'sdk-0.3.2/'; + const faults: [string, (entries: Record) => void, string][] = [ + [ + 'manifest', + (entries) => { + delete entries[`${prefix}Cargo.toml`]; + }, + 'omitted Cargo.toml', + ], + [ + 'library', + (entries) => { + delete entries[`${prefix}src/lib.rs`]; + }, + 'omitted src/lib.rs', + ], + [ + 'extra', + (entries) => { + entries[`${prefix}src/ambient.rs`] = Buffer.from('ambient'); + }, + 'undeclared member', + ], + [ + 'changed-source', + (entries) => { + entries[`${prefix}src/lib.rs`] = Buffer.from('changed'); + }, + 'library or target guard', + ], + [ + 'defaults', + (entries) => { + const manifest = Bun.TOML.parse(entries[`${prefix}Cargo.toml`].toString()); + manifest.features.default = []; + entries[`${prefix}Cargo.toml`] = Buffer.from(renderCargoToml(manifest)); + }, + 'features changed', + ], + [ + 'retarget', + (entries) => { + const manifest = Bun.TOML.parse(entries[`${prefix}Cargo.toml`].toString()); + manifest.target[ + 'cfg(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu"))' + ].dependencies['runtime-linux-x64-gnu'].version = '=0.4.0'; + entries[`${prefix}Cargo.toml`] = Buffer.from(renderCargoToml(manifest)); + }, + 'differs from', + ], + ]; + for (const [name, change, message] of faults) { + const changed = { ...files }; + change(changed); + const file = path.join(root, `${name}.crate`); + writeFileSync(file, archive(changed)); + expect(() => verifyCargoSourceContract({ ...input, archive: file })).toThrow(message); + } + expect(readFileSync(input.archive).length).toBeGreaterThan(0); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/build_defs/languages/source-package.mts b/build_defs/languages/source-package.mts new file mode 100644 index 000000000..277fc8513 --- /dev/null +++ b/build_defs/languages/source-package.mts @@ -0,0 +1,208 @@ +import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { dirname, join, resolve } from 'node:path'; +import { + renderCargoToml as renderToml, + resolveCargoWorkspaceInheritance, +} from '../../tools/packaging/cargo-manifest.mts'; +import { + cargoPackageRelativePathParts, + packageGeneratedCargoSource, +} from '../../tools/packaging/cargo-source-package.mts'; +import { + assertSameNativeTargetSet, + renderUnsupportedNativeTargetGuard, + rustNativeTargetCfg, +} from '../../tools/packaging/rust-native-targets.mts'; + +type Table = Record; +export type SourceMetadata = { + product: string; + version: string; + compatibility: Record; + dependencyOwners: Record; + nativeArtifacts?: { sourceProduct: string; target: string; packageName: string }[]; + brokerArtifacts?: { sourceProduct: string; target: string; packageName: string }[]; +}; + +const CARGO_VIRTUAL_FILES = new Set(['Cargo.lock', 'Cargo.toml.orig', '.cargo_vcs_info.json']); + +export function selectedSourceEntries(listing: string, entries: Record) { + const selected: Record = {}; + const names = listing.trim().replaceAll('\\', '/').split(/\r?\n/); + for (const name of names) { + if (CARGO_VIRTUAL_FILES.has(name)) continue; + if (!Object.hasOwn(entries, name)) + throw new Error(`Cargo listed undeclared public source input ${name}`); + if (Object.hasOwn(selected, name)) + throw new Error(`Cargo repeated public source input ${name}`); + selected[name] = entries[name]; + } + if (!selected['Cargo.toml']) throw new Error('Cargo source inventory omitted its manifest'); + return selected; +} + +async function conventionalSourceEntries(cargo: string, entries: Record) { + const directory = await mkdtemp(join(tmpdir(), 'oliphaunt-cargo-inventory-')); + try { + const source = join(directory, 'source'); + for (const [name, bytes] of Object.entries(entries)) { + const destination = join(source, name); + await mkdir(dirname(destination), { recursive: true }); + await writeFile(destination, bytes); + } + const home = join(directory, 'home'); + await mkdir(home); + const child = Bun.spawn( + [ + resolve(cargo), + 'package', + '--offline', + '--no-verify', + '--list', + '--manifest-path', + join(source, 'Cargo.toml'), + ], + { + env: { PATH: '', HOME: home, CARGO_HOME: home, CARGO_NET_OFFLINE: 'true' }, + stdout: 'pipe', + stderr: 'pipe', + }, + ); + const [status, stdout, stderr] = await Promise.all([ + child.exited, + new Response(child.stdout).text(), + new Response(child.stderr).text(), + ]); + if (status !== 0) throw new Error(`Conventional Cargo source inventory failed: ${stderr}`); + return selectedSourceEntries(stdout, entries); + } finally { + await rm(directory, { recursive: true, force: true }); + } +} + +export function sourceManifest( + original: string, + workspaceText: string, + metadata: SourceMetadata, +): Table { + const manifest: Table = resolveCargoWorkspaceInheritance( + Bun.TOML.parse(original), + Bun.TOML.parse(workspaceText).workspace ?? {}, + ); + if (!manifest.package || manifest.package.version !== metadata.version) + throw new Error(`Source package version disagrees with ${metadata.product} owner`); + for (const table of [manifest, ...Object.values(manifest.target ?? {})] as Table[]) { + for (const section of ['dependencies', 'dev-dependencies', 'build-dependencies']) { + if (!table[section]) continue; + for (const [name, dependency] of Object.entries(table[section]) as [ + string, + Table | string, + ][]) { + if (typeof dependency === 'string' || !dependency.path) continue; + delete dependency.path; + if (typeof dependency.version !== 'string') + throw new Error(`Unversioned public Cargo dependency ${name}`); + if (dependency.version === '*') { + const owner = metadata.dependencyOwners[dependency.package ?? name]; + const version = metadata.compatibility[owner]; + if (!version) throw new Error(`Missing installed compatibility pin for ${name}`); + dependency.version = `=${version}`; + } + } + } + } + // Isolate the conventional consumer from a surrounding checkout workspace. + delete manifest.package.workspace; + manifest.workspace = {}; + if (metadata.nativeArtifacts || metadata.brokerArtifacts) { + const native = metadata.nativeArtifacts ?? []; + const broker = metadata.brokerArtifacts ?? []; + assertSameNativeTargetSet( + 'Rust SDK native runtime/broker', + native.map((row) => row.target), + broker.map((row) => row.target), + ); + manifest.target ??= {}; + for (const row of [...native, ...broker]) { + const version = metadata.compatibility[row.sourceProduct]; + if (!version) throw new Error(`Missing installed compatibility pin for ${row.sourceProduct}`); + const condition = `cfg(${rustNativeTargetCfg(row.target)})`; + manifest.target[condition] ??= {}; + manifest.target[condition].dependencies ??= {}; + if (manifest.target[condition].dependencies[row.packageName]) + throw new Error(`Duplicate generated Cargo dependency ${row.packageName}`); + manifest.target[condition].dependencies[row.packageName] = { version: `=${version}` }; + } + } + return manifest; +} + +export async function sourceEnvelope( + manifestPath: string, + workspacePath: string, + mapping: Record, + metadata: SourceMetadata, + cargo?: string, +): Promise { + const original = await readFile(manifestPath, 'utf8'); + const manifest = sourceManifest(original, await readFile(workspacePath, 'utf8'), metadata); + const prefix = `${manifest.package.name}-${manifest.package.version}`; + if (!/^[\w.-]+$/.test(prefix)) throw new Error('Invalid Cargo source package identity'); + let sources: Record = {}; + for (const [destination, source] of Object.entries(mapping)) { + try { + cargoPackageRelativePathParts(destination); + } catch { + throw new Error(`Unsafe Cargo source entry ${destination}`); + } + sources[destination] = await readFile(source); + } + if (!sources['Cargo.toml']) throw new Error('Missing public Cargo source entry Cargo.toml'); + sources['Cargo.toml'] = Buffer.from(renderToml(manifest)); + if (cargo) sources = await conventionalSourceEntries(cargo, sources); + for (const required of ['Cargo.toml', 'LICENSE', 'THIRD_PARTY_NOTICES.md', 'README.md']) + if (!sources[required]) throw new Error(`Missing public Cargo source entry ${required}`); + sources['Cargo.toml.orig'] = Buffer.from(original); + if (metadata.nativeArtifacts) { + if (!sources['src/lib.rs']) throw new Error('Rust SDK source package is missing its library'); + sources['src/lib.rs'] = Buffer.from( + `${Buffer.from(sources['src/lib.rs']).toString('utf8')}\n${renderUnsupportedNativeTargetGuard({ product: manifest.package.name, nativeTargets: metadata.nativeArtifacts.map((row) => row.target), nativeCfgs: metadata.nativeArtifacts.map((row) => rustNativeTargetCfg(row.target)), guidance: 'use the separately versioned oliphaunt-wasix crate for WASIX environments.' })}\n`, + ); + } + const directory = await mkdtemp(join(tmpdir(), 'oliphaunt-source-envelope-')); + try { + const source = join(directory, 'source'); + for (const [member, bytes] of Object.entries(sources)) { + const destination = join(source, member); + await mkdir(dirname(destination), { recursive: true }); + await writeFile(destination, bytes, { mode: 0o644 }); + } + const crate = packageGeneratedCargoSource(join(source, 'Cargo.toml'), directory, { + noticeProfile: 'source-sdk', + noticeSourceRoot: source, + fixedFileMode: 0o644, + }); + return await readFile(crate); + } finally { + await rm(directory, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + const [output, manifest, workspace, specification, metadataFile, cargo] = process.argv.slice(2); + if (!output || !manifest || !workspace || !specification || !metadataFile || !cargo) + throw new Error( + 'Expected source archive, manifest, workspace, entry mapping, metadata and pinned Cargo', + ); + await writeFile( + output, + await sourceEnvelope( + manifest, + workspace, + JSON.parse(await readFile(specification, 'utf8')), + JSON.parse(await readFile(metadataFile, 'utf8')), + cargo, + ), + ); +} diff --git a/build_defs/languages/source-package.test.mts b/build_defs/languages/source-package.test.mts new file mode 100644 index 000000000..086759694 --- /dev/null +++ b/build_defs/languages/source-package.test.mts @@ -0,0 +1,203 @@ +import { expect, test } from 'bun:test'; +import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { + type SourceMetadata, + selectedSourceEntries, + sourceEnvelope, + sourceManifest, +} from './source-package.mts'; + +const original = + '[package]\nname="sdk"\nversion="0.3.2"\nedition.workspace=true\nlicense.workspace=true\n[dependencies]\nquery={path="../query",version="0.1.1"}\nserde={workspace=true,features=["rc"]}\n'; +const workspace = + '[workspace.package]\nedition="2024"\nlicense="MIT"\n[workspace.dependencies]\nserde={version="1",features=["derive"]}\n'; +const metadata: SourceMetadata = { + product: 'sdk', + version: '0.3.2', + compatibility: { runtime: '0.3.2', broker: '0.3.1' }, + dependencyOwners: {}, +}; + +test('public source manifests preserve dependency ranges/features and resolve workspace values', () => { + const manifest = sourceManifest(original, workspace, metadata); + expect(manifest.package).toEqual({ + name: 'sdk', + version: '0.3.2', + edition: '2024', + license: 'MIT', + }); + expect(manifest.dependencies.query).toEqual({ version: '0.1.1' }); + expect(manifest.dependencies.serde).toEqual({ version: '1', features: ['derive', 'rc'] }); + expect(manifest.workspace).toEqual({}); + expect(() => sourceManifest(original, workspace, { ...metadata, version: '0.3.3' })).toThrow( + 'owner', + ); + expect(() => + sourceManifest(original.replace(',version="0.1.1"', ''), workspace, metadata), + ).toThrow('Unversioned'); +}); + +test('SDK carriers retain installed pins even when another workspace release version is newer', () => { + const delivery = { + ...metadata, + nativeArtifacts: [ + { sourceProduct: 'runtime', target: 'linux-x64-gnu', packageName: 'runtime-linux-x64-gnu' }, + ], + brokerArtifacts: [ + { sourceProduct: 'broker', target: 'linux-x64-gnu', packageName: 'broker-linux-x64-gnu' }, + ], + }; + const manifest = sourceManifest(original, workspace, delivery); + const dependencies = + manifest.target['cfg(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu"))'] + .dependencies; + expect(dependencies).toEqual({ + 'runtime-linux-x64-gnu': { version: '=0.3.2' }, + 'broker-linux-x64-gnu': { version: '=0.3.1' }, + }); + expect(() => + sourceManifest(original, workspace, { + ...delivery, + brokerArtifacts: [{ ...delivery.brokerArtifacts[0], target: 'macos-arm64' }], + }), + ).toThrow('mismatch'); + expect(() => sourceManifest(original, workspace, { ...delivery, compatibility: {} })).toThrow( + 'Missing installed', + ); +}); + +test('wildcard path carriers resolve to their consumer compatibility contract', () => { + const source = original.replace('version="0.1.1"', 'version="*"'); + expect( + sourceManifest(source, workspace, { ...metadata, dependencyOwners: { query: 'runtime' } }) + .dependencies.query.version, + ).toBe('=0.3.2'); + expect(() => sourceManifest(source, workspace, metadata)).toThrow('Missing installed'); +}); + +test('inherited string requirements keep optionality and target feature additions', () => { + const manifest = sourceManifest( + '[package]\nname="sdk"\nversion="0.3.2"\nworkspace="../adapters"\n[dependencies]\nquery={workspace=true,optional=true}\n[target.\'cfg(unix)\'.build-dependencies]\nquery={workspace=true,features=["std"]}\n', + '[workspace.dependencies]\nquery="=0.1.1"\n', + metadata, + ); + expect(manifest.dependencies.query).toEqual({ version: '=0.1.1', optional: true }); + expect(manifest.target['cfg(unix)']['build-dependencies'].query).toEqual({ + version: '=0.1.1', + features: ['std'], + }); + expect(manifest.package.workspace).toBeUndefined(); + expect(manifest.workspace).toEqual({}); + expect(() => + sourceManifest( + '[package]\nname="sdk"\nversion="0.3.2"\n[dependencies]\nquery.workspace=true\n', + '[workspace]\n', + metadata, + ), + ).toThrow('Missing inherited'); +}); + +test('admits exactly Cargo-listed declared bytes and rejects undeclared source or duplicate entries', () => { + const entries = { + 'Cargo.toml': Buffer.from('manifest'), + 'src/lib.rs': Buffer.from('pub fn api() {}'), + 'tests/private.rs': Buffer.from('private checkout test'), + }; + for (const listing of [ + 'Cargo.lock\nCargo.toml\nCargo.toml.orig\nsrc/lib.rs\n', + 'Cargo.lock\r\nCargo.toml\r\nCargo.toml.orig\r\n.cargo_vcs_info.json\r\nsrc\\lib.rs\r\n', + ]) { + expect(selectedSourceEntries(listing, entries)).toEqual({ + 'Cargo.toml': entries['Cargo.toml'], + 'src/lib.rs': entries['src/lib.rs'], + }); + } + expect(() => selectedSourceEntries('Cargo.toml\n../ambient.rs\n', entries)).toThrow('undeclared'); + expect(() => selectedSourceEntries('Cargo.toml\n..\\ambient.rs\n', entries)).toThrow( + 'undeclared', + ); + expect(() => selectedSourceEntries('Cargo.toml\nC:\\ambient.rs\n', entries)).toThrow( + 'undeclared', + ); + expect(() => selectedSourceEntries('Cargo.toml\nCargo.toml\n', entries)).toThrow('repeated'); + expect(() => selectedSourceEntries('Cargo.toml\nsrc/lib.rs\nsrc\\lib.rs\n', entries)).toThrow( + 'repeated', + ); + expect(() => selectedSourceEntries('src/lib.rs\n', entries)).toThrow('omitted'); +}); + +test('native source envelopes are deterministic, retain manifests and reject undeclared/unsafe entries', async () => { + const directory = await mkdtemp(join(tmpdir(), 'cargo-source-')); + try { + const manifest = join(directory, 'Cargo.toml'); + const root = join(directory, 'workspace.toml'); + const readme = join(directory, 'README.md'); + const license = join(directory, 'LICENSE'); + const notices = join(directory, 'THIRD_PARTY_NOTICES.md'); + await writeFile(manifest, original); + await writeFile(root, workspace); + await writeFile(readme, 'SDK'); + await writeFile(license, 'MIT'); + await writeFile(notices, 'source notices'); + const entries = { + 'Cargo.toml': manifest, + 'README.md': readme, + LICENSE: license, + 'THIRD_PARTY_NOTICES.md': notices, + }; + const first = await sourceEnvelope(manifest, root, entries, metadata); + expect(await sourceEnvelope(manifest, root, entries, metadata)).toEqual(first); + const files = await new Bun.Archive(first).files(); + expect(await files.get('sdk-0.3.2/Cargo.toml.orig')?.text()).toBe( + await readFile(manifest, 'utf8'), + ); + expect( + Bun.TOML.parse((await files.get('sdk-0.3.2/Cargo.toml')?.text()) ?? '').dependencies.query + .path, + ).toBeUndefined(); + await expect( + sourceEnvelope(manifest, root, { ...entries, '../unsafe': readme }, metadata), + ).rejects.toThrow('Unsafe'); + await expect( + sourceEnvelope(manifest, root, { 'Cargo.toml': manifest }, metadata), + ).rejects.toThrow('Missing public'); + await expect(sourceEnvelope(manifest, root, { LICENSE: license }, metadata)).rejects.toThrow( + 'Cargo.toml', + ); + } finally { + await rm(directory, { recursive: true, force: true }); + } +}); + +test('adding explicit workspace source composition leaves public dependency bytes and installed pins held', () => { + const source = + '[package]\nname="sdk"\nversion="0.3.2"\n[dependencies]\nbindings.workspace=true\n'; + const held = + '[workspace.dependencies]\nbindings={version="0.2.0",features=["resource-loading"]}\n'; + const composed = held.replace('version="0.2.0"', 'path="bindings",version="0.2.0"'); + const delivery = { + ...metadata, + nativeArtifacts: [ + { sourceProduct: 'runtime', target: 'linux-x64-gnu', packageName: 'runtime-linux-x64-gnu' }, + ], + brokerArtifacts: [ + { sourceProduct: 'broker', target: 'linux-x64-gnu', packageName: 'broker-linux-x64-gnu' }, + ], + }; + expect(sourceManifest(source, composed, delivery)).toEqual( + sourceManifest(source, held, delivery), + ); + const direct = source.replace( + 'bindings.workspace=true', + 'bindings={path="../bindings",version="0.2.0",features=["resource-loading"]}', + ); + expect(sourceManifest(direct, composed, delivery)).toEqual( + sourceManifest(source, held, delivery), + ); + expect(sourceManifest(source, composed, delivery).dependencies.bindings).toEqual({ + version: '0.2.0', + features: ['resource-loading'], + }); +}); diff --git a/build_defs/languages/source.bzl b/build_defs/languages/source.bzl new file mode 100644 index 000000000..29edc2e05 --- /dev/null +++ b/build_defs/languages/source.bzl @@ -0,0 +1,150 @@ +"""Deterministic public source crates from authored manifests and native files.""" + +load("@native_cargo_metadata//:cargo.bzl", "CARGO") +load("@oliphaunt_metadata//:metadata.bzl", "PREPARED_NATIVE_SELECTED_PRODUCTS", "PRODUCTS", "PUBLICATION_CARRIERS") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_file_action", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") +load("//build_defs/release:supplier.bzl", "shipping_suppliers") + +_RUST_TOOLCHAIN = "@rules_rust//rust:toolchain" +CargoSourceInfo = provider(fields = ["archive", "manifest", "workspace_manifest", "entries", "metadata"]) +_SOURCE_HELPERS = [Label("//:tools/packaging/cargo-manifest.mts"), Label("//:tools/packaging/cargo-source-package.mts"), Label("//:tools/packaging/package-archive.mts"), Label("//:tools/packaging/archive-directory.mts"), Label("//:tools/packaging/portable-archive.mts"), Label("//:tools/packaging/release-notices.mts"), Label("//:tools/packaging/release-directory-safety.mts"), Label("//:tools/packaging/rust-native-targets.mts")] + +def _runfile(ctx, file): + return file.short_path[3:] if file.short_path.startswith("../") else ctx.workspace_name + "/" + file.short_path + +def _source_impl(ctx): + inputs = [ctx.file.manifest, ctx.file.workspace_manifest, ctx.file._packager] + ctx.files._helpers + entries = {} + entry_files = {} + for target, destination in ctx.attr.entries.items(): + for file in target[DefaultInfo].files.to_list(): + entry = destination + if destination.endswith("/"): + prefix = target.label.package + "/" + if not file.short_path.startswith(prefix): + fail("source archive file is outside its declared package: " + file.short_path) + entry += file.short_path[len(prefix):] + if entry in entries: + fail("duplicate source archive entry " + entry) + entries[entry] = file.path + entry_files[entry] = file + inputs.append(file) + specification = ctx.actions.declare_file(ctx.label.name + ".entries.json") + metadata = ctx.actions.declare_file(ctx.label.name + ".metadata.json") + ctx.actions.write(specification, json.encode(entries)) + ctx.actions.write(metadata, ctx.attr.metadata) + output = ctx.actions.declare_file(ctx.attr.out) + cargo = ctx.toolchains[_RUST_TOOLCHAIN].cargo + if not cargo: + fail("Conventional Cargo source inventory requires the pinned Cargo toolchain") + args = ctx.actions.args() + args.add_all([output, ctx.file.manifest, ctx.file.workspace_manifest, specification, metadata, cargo]) + # Enumeration needs only Cargo itself, not a compiled target sysroot. It is + # offline metadata; all archive construction remains this bounded action. + bun_file_action(ctx, entry_point = ctx.file._packager, arguments = [args], inputs = depset(inputs + [specification, metadata, cargo]), source_files = [ctx.file._packager] + ctx.files._helpers, outputs = [output], mnemonic = "CargoSourceEnvelope") + return [DefaultInfo(files = depset([output])), CargoSourceInfo(archive = output, manifest = ctx.file.manifest, workspace_manifest = ctx.file.workspace_manifest, entries = entry_files, metadata = metadata)] + +def _source_contract_impl(ctx): + rust = ctx.toolchains[_RUST_TOOLCHAIN] + if not rust.cargo: + fail("Source consumer metadata requires the pinned Cargo toolchain") + packages = [] + files = rust.all_files.to_list() + [ctx.file._runner] + ctx.files._helpers + for target in ctx.attr.packages: + source = target[CargoSourceInfo] + packages.append({ + "archive": _runfile(ctx, source.archive), + "manifest": _runfile(ctx, source.manifest), + "workspace": _runfile(ctx, source.workspace_manifest), + "metadata": _runfile(ctx, source.metadata), + "entries": {name: _runfile(ctx, file) for name, file in source.entries.items()}, + }) + files += [source.archive, source.manifest, source.workspace_manifest, source.metadata] + source.entries.values() + specification = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(specification, json.encode({"packages": packages, "cargo": _runfile(ctx, rust.cargo), "rustc": _runfile(ctx, rust.rustc)})) + return bun_test_entrypoint(ctx, ctx.file._runner, [specification], files + [specification], source_files = [ctx.file._runner] + ctx.files._helpers, runfiles_argument = True) + +_cargo_source_contract_test = rule( + implementation = _source_contract_impl, + test = True, + toolchains = BUN_SOURCE_TOOLCHAINS + [_RUST_TOOLCHAIN], + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "packages": attr.label_list(providers = [CargoSourceInfo], mandatory = True), + "_runner": attr.label(default = Label("//build_defs/languages:source-contract.mts"), allow_single_file = True), + "_helpers": attr.label_list(default = _SOURCE_HELPERS + [Label("//build_defs/languages:source-package.mts"), Label("//:tools/packaging/cargo-dependencies.mts")], allow_files = True), + }), +) + +def cargo_source_contract_test(name, **kwargs): + _cargo_source_contract_test(name = name, args = bun_test_entrypoint_args(name), **kwargs) + +_cargo_source = rule( + implementation = _source_impl, + toolchains = BUN_SOURCE_TOOLCHAINS + [_RUST_TOOLCHAIN], + attrs = { + "entries": attr.label_keyed_string_dict(allow_files = True), + "manifest": attr.label(allow_single_file = True, mandatory = True), + "workspace_manifest": attr.label(default = Label("//:Cargo.toml"), allow_single_file = True), + "metadata": attr.string(mandatory = True), + "out": attr.string(mandatory = True), + "_packager": attr.label(default = Label("//build_defs/languages:source-package.mts"), allow_single_file = True), + "_helpers": attr.label_list(default = _SOURCE_HELPERS, allow_files = True), + }, +) + +def cargo_source_package(product, fixtures = "", native_sdk = False, cargo_facts = CARGO, workspace_manifest = "//:Cargo.toml", qualification = []): + facts = cargo_facts[native.package_name()] + descriptor = PRODUCTS[product] + if "crates:" + facts["name"] not in descriptor.get("registry_packages", []): + fail("Cargo source package is not declared by its release owner: " + facts["name"]) + carriers = [row for row in PUBLICATION_CARRIERS if row["product"] == product and row["ecosystem"] == "cargo" and row["name"] == facts["name"] and row["target"] == None] + if len(carriers) != 1: + fail("Canonical Cargo source package identity is not unique: " + facts["name"]) + dependencies = dict(facts["dependencies"]) + dependencies.update(facts["build_dependencies"]) + dependencies.update(facts["dev_dependencies"]) + for table in facts["target_dependencies"].values(): + dependencies.update(table.get("dependencies", {})) + dependency_owners = {} + for name, declaration in dependencies.items(): + package_name = declaration.get("package", name) if type(declaration) == "dict" else name + for owner, candidate in PRODUCTS.items(): + if "crates:" + package_name in candidate.get("registry_packages", []): + dependency_owners[package_name] = owner + metadata = {"product": product, "version": descriptor["version"], "compatibility": descriptor["compatibility_versions"], "dependencyOwners": dependency_owners} + if native_sdk: + metadata["nativeArtifacts"] = PRODUCTS["liboliphaunt-native"]["cargo_artifacts"] + metadata["brokerArtifacts"] = PRODUCTS["oliphaunt-broker"]["cargo_artifacts"] + # Cargo owns public include/exclude semantics. Stage the complete declared + # package tree so newly added source directories cannot disappear silently. + # Nested Bazel/Cargo packages have their own construction boundary. + # Source checkout fixture symlinks and staged package fixture copies occupy + # the same paths. The canonical fixture target supplies those bytes once. + sources = native.glob(["**"], exclude = [fixtures + "**"] if fixtures else [], allow_empty = True) + entries = {file: file for file in sources} + for name in ["LICENSE", "THIRD_PARTY_NOTICES.md"]: + # Source SDKs carry the repository's source notice. A package-local + # runtime notice belongs to compiled carriers, not this source crate. + entries.pop(name, None) + entries["//:" + name] = name + if fixtures: + entries["//src/test-fixtures:rust_fixtures"] = fixtures + _cargo_source(name = "crate", manifest = "Cargo.toml", workspace_manifest = workspace_manifest, entries = entries, metadata = json.encode(metadata), out = facts["name"] + ".crate") + # This envelope contains authored source and conventional requirements. + # Its compile/test dependencies are not incorporated compiled carrier Files. + shipping_suppliers(name = "source_suppliers", inputs = []) + shipping_package(name = "shipping_package", owner = "@oliphaunt_metadata//:product_" + product, artifacts = [":crate"], ecosystem = "cargo", package_name = facts["name"], configuration = "source", role = carriers[0]["role"], suppliers = ":source_suppliers") + common_consumer = "//build_defs/languages/installed:consumer_test" + minimum_dependencies = dict(facts["dependencies"]) + minimum_dependencies.update(facts["build_dependencies"]) + for table in facts["target_dependencies"].values(): + minimum_dependencies.update(table.get("dependencies", {})) + minimum_dependencies.update(table.get("build-dependencies", {})) + internal_minimum = any([ + (declaration.get("package", name) if type(declaration) == "dict" else name) in dependency_owners + for name, declaration in minimum_dependencies.items() + ]) + if product in ["oliphaunt-rust", "oliphaunt-broker"] and product in PREPARED_NATIVE_SELECTED_PRODUCTS and common_consumer in qualification and internal_minimum: + qualification = qualification + ["//build_defs/languages/installed:consumer_minimum_test"] + shipping_export(name = "shipping_export", packages = [":shipping_package"], qualification = qualification, testonly = True) diff --git a/build_defs/languages/swift/BUILD.bazel b/build_defs/languages/swift/BUILD.bazel new file mode 100644 index 000000000..032bd8404 --- /dev/null +++ b/build_defs/languages/swift/BUILD.bazel @@ -0,0 +1,60 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/foundation:bun.bzl", "bun_test") +load("//build_defs/native/carriers:defs.bzl", "native_payload_helpers") +load(":extension-fixture.bzl", "selected_swift_extension_fixture") +load(":xcframework.bzl", "BINDINGS_ENVELOPE_HELPERS") + +package(default_visibility = ["//visibility:public"]) +exports_files(glob(["*.bzl", "*.mts"])) +selected_swift_extension_fixture() +bun_test(name = "generate_test", entry_point = "generate.test.mts", data = ["generate.mts", "//build_defs/languages:uniffi.mts"], size = "small") +bun_test( + name = "xcframework_envelope_test", + entry_point = "xcframework-envelope.test.mts", + data = [ + "xcframework-envelope.mts", + "//src/native/mobile-bindings:license_inputs", + "//:Cargo.lock", + "//:LICENSE", + "//:THIRD_PARTY_NOTICES.md", + ] + BINDINGS_ENVELOPE_HELPERS, + source_files = ["xcframework-envelope.mts"] + BINDINGS_ENVELOPE_HELPERS, + size = "small", +) +bun_test( + name = "source_package_test", + entry_point = "source-package.test.mts", + data = [ + "source-package.fixture.mts", + "consumer-test.mts", + "//src/native/sdks/swift:Tests/OliphauntTests/AsyncStringSignal.swift", + "//src/native/sdks/swift:tools/prepare-swift-release-consumer.mts", + "//build_defs/native/apple:swift-candidate-contract.mts", + "source-package.mts", + "source-delivery-contract.mts", + "//build_defs/native/carriers:payload.mts", + "//tools/release:native-file-identity.mts", + "//build_defs/release:testdata/swift-0.8.2-carrier.json", + "//src/native/sdks/swift:tools/swift-native-carrier-contract.mts", + "//src/native/sdks/swift:tools/swift-release-manifest.mts", + "//src/native/sdks/swift:tools/swift-source-fixture-contract.mts", + "//src/native/sdks/swift:tools/swift-xcframework-contract.mts", + "//src/native/sdks/swift:generator_sources", + "//src/extensions/generated/sdk:metadata", + "//src/native/runtime:include/oliphaunt.h", + "//:LICENSE", + "//:THIRD_PARTY_NOTICES.md", + "//:tools/packaging/archive-directory.mts", + "//:tools/packaging/sdk-runtime-payload.mts", + "//:tools/packaging/testdata/zip-fixture.mts", + "//:tools/packaging/emit-javascript.mts", + ] + native_payload_helpers(), + size = "small", +) + +source_quality_files() + +# Source-only inputs for the existing SDK package policy tests. +exports_files([ + "source-delivery-contract.mts", +], visibility = ["//visibility:public"]) diff --git a/build_defs/languages/swift/bindings.bzl b/build_defs/languages/swift/bindings.bzl new file mode 100644 index 000000000..5ad415d0a --- /dev/null +++ b/build_defs/languages/swift/bindings.bzl @@ -0,0 +1,47 @@ +"""Declared UniFFI generation from the native mobile library's metadata.""" + +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") + +def _uniffi_swift_impl(ctx): + library = ctx.file.library + swift = ctx.actions.declare_file(ctx.label.name + "/OliphauntNativeBindings.swift") + header = ctx.actions.declare_file(ctx.label.name + "/OliphauntNativeBindingsFFI.h") + modulemap = ctx.actions.declare_file(ctx.label.name + "/OliphauntNativeBindingsFFI.modulemap") + bun_file_action( + ctx, + entry_point = ctx.file.driver, + source_files = [ctx.file.driver, ctx.file._invocation], + arguments = [ctx.executable.generator.path, library.path, ctx.file.configuration.path, swift.dirname], + inputs = [ctx.file.driver, ctx.file._invocation, library, ctx.file.configuration], + tools = [ctx.attr.generator[DefaultInfo].files_to_run], + outputs = [swift, header, modulemap], + mnemonic = "OliphauntUniFfiSwift", + use_default_shell_env = False, + ) + return [DefaultInfo(files = depset([swift, header, modulemap])), OutputGroupInfo(swift = depset([swift]), header = depset([header]), modulemap = depset([modulemap]))] + +uniffi_swift = rule( + implementation = _uniffi_swift_impl, + attrs = { + "library": attr.label(mandatory = True, allow_single_file = [".so", ".dylib", ".rlib"], cfg = "exec"), + "generator": attr.label(mandatory = True, executable = True, cfg = "exec"), + "configuration": attr.label(mandatory = True, allow_single_file = [".toml"]), + "driver": attr.label(default = Label("//build_defs/languages/swift:generate.mts"), allow_single_file = True), + "_invocation": attr.label(default = Label("//build_defs/languages:uniffi.mts"), allow_single_file = True), + }, + toolchains = BUN_SOURCE_TOOLCHAINS, +) + +def _uniffi_output_impl(ctx): + return [DefaultInfo(files = getattr(ctx.attr.bindings[OutputGroupInfo], ctx.attr.group))] + +# Generation uses one host metadata variant for every target slice. Keeping +# this edge in the execution configuration avoids three identical generators +# when Apple's XCFramework rule splits its header dependency by platform. +uniffi_output = rule( + implementation = _uniffi_output_impl, + attrs = { + "bindings": attr.label(mandatory = True, providers = [OutputGroupInfo], cfg = "exec"), + "group": attr.string(mandatory = True, values = ["swift", "header", "modulemap"]), + }, +) diff --git a/build_defs/languages/swift/compiled-inputs-test.bzl b/build_defs/languages/swift/compiled-inputs-test.bzl new file mode 100644 index 000000000..4b5c9a69a --- /dev/null +++ b/build_defs/languages/swift/compiled-inputs-test.bzl @@ -0,0 +1,60 @@ +"""Bind the forwarded records to actual stock Apple compiler outputs and owning roots.""" + +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") +load("//build_defs/release:shipping.bzl", "ShippingExportInfo", "ShippingInfo") +load("//build_defs/release:supplier.bzl", "ShippingSupplierInfo") +load(":xcframework.bzl", "SWIFT_BINDINGS_COMPILE_OWNERS", "SWIFT_BINDINGS_COMPILE_SLOTS", "swift_bindings_compile_group") + +def _compiled_inputs_test_impl(ctx): + env = analysistest.begin(ctx) + target = analysistest.target_under_test(env) + inputs = ctx.attr.bindings[ShippingSupplierInfo] + packages = target[ShippingExportInfo].packages + asserts.true(env, inputs.suppliers != None, "Swift compiler inputs require authenticated completed Query source facts") + if inputs.suppliers == None: + return analysistest.end(env) + count = len(SWIFT_BINDINGS_COMPILE_OWNERS) * len(SWIFT_BINDINGS_COMPILE_SLOTS) + held = [row for row in inputs.suppliers if row["product"] == "oliphaunt-query"] + asserts.equals(env, 1, len(held)) + if len(held) != 1: + return analysistest.end(env) + asserts.equals(env, "compiled-input", held[0]["binding"]) + asserts.equals(env, "completed-publication", held[0]["origin"]["kind"]) + asserts.equals(env, "cargo:oliphaunt-query", held[0]["origin"]["artifact"]) + asserts.equals(env, count + len(held), len(inputs.suppliers)) + asserts.equals(env, count, len(packages)) + asserts.equals(env, count, len({str(package.label): True for package in packages})) + asserts.equals(env, 2, len(ctx.attr.bindings[DefaultInfo].files.to_list())) + paths = [] + for owner, product in SWIFT_BINDINGS_COMPILE_OWNERS.items(): + producer = {"core": Label("//src/native/rust-bindings:lib"), "sdk": Label("//src/native/sdks/rust:mobile_lib"), "broker": Label("//src/native/broker:lib")}[owner] + for slot in SWIFT_BINDINGS_COMPILE_SLOTS: + group = swift_bindings_compile_group(owner, slot) + files = getattr(ctx.attr.bindings[OutputGroupInfo], group).to_list() + asserts.equals(env, 1, len(files)) + file = files[0] + asserts.false(env, file.is_source) + asserts.false(env, file.is_directory) + asserts.equals(env, producer, file.owner) + paths.append(file.path) + rows = [row for row in inputs.suppliers if row["product"] == product and row["configuration"] == slot] + asserts.equals(env, 1, len(rows)) + asserts.equals(env, "compiled-input", rows[0]["binding"]) + asserts.equals(env, {"kind": "current-source"}, rows[0]["origin"]) + asserts.equals(env, [{"path": file.path}], rows[0]["files"]) + roots = [package[ShippingInfo] for package in packages if package[ShippingInfo].product == product and package[ShippingInfo].configuration == slot] + asserts.equals(env, 1, len(roots)) + asserts.equals(env, "internal", roots[0].ecosystem) + asserts.equals(env, product + "-swift-bindings", roots[0].name) + asserts.equals(env, "compiled-source", roots[0].role) + asserts.equals(env, rows[0]["version"], roots[0].version) + asserts.equals(env, [file.path], [value.path for value in roots[0].files.to_list()]) + products = [SWIFT_BINDINGS_COMPILE_OWNERS["core"]] + ([SWIFT_BINDINGS_COMPILE_OWNERS["broker"]] if owner == "sdk" else []) + expected = [] if owner == "core" else [row for row in inputs.suppliers if row["product"] in products and row["configuration"] == slot] + held + asserts.equals(env, sorted([json.encode(row) for row in expected]), sorted([json.encode(row) for row in roots[0].supplier_inputs])) + asserts.equals(env, count, len({file: True for file in paths})) + return analysistest.end(env) + +swift_compiled_inputs_test = analysistest.make(_compiled_inputs_test_impl, attrs = { + "bindings": attr.label(mandatory = True, providers = [ShippingSupplierInfo, OutputGroupInfo]), +}) diff --git a/build_defs/languages/swift/consumer-test.mts b/build_defs/languages/swift/consumer-test.mts new file mode 100644 index 000000000..5e69bc6e8 --- /dev/null +++ b/build_defs/languages/swift/consumer-test.mts @@ -0,0 +1,215 @@ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { copyFileSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { localizeSwiftReleaseManifest } from '../../../src/native/sdks/swift/tools/prepare-swift-release-consumer.mts'; +import { extractPortableArchiveTree } from '../../../tools/packaging/portable-archive.mts'; +import { composeSwiftCandidateManifest } from '../../native/apple/swift-candidate-contract.mts'; +import { copyDeclaredTree } from '../../native/carriers/payload.mts'; +import { + assertSwiftSourceDeliveryParity, + readSwiftSourceTagMembers, +} from './source-delivery-contract.mts'; + +assert.equal(process.platform, 'darwin', 'Installed Swift runtime qualification requires macOS'); +assert.equal(process.arch, 'arm64', 'Installed Swift runtime qualification requires Apple arm64'); +const [ + source, + base, + bindings, + consumer, + swift, + swiftc, + clang, + clangxx, + sdkFile, + receipt, + triple, + sourceTree, + sourceTreePath, +] = process.argv.slice(2); +assert.equal( + process.argv.length, + 15, + 'Expected exact Swift package, native assets, consumer and declared toolchain', +); +const root = process.env.TEST_TMPDIR; +assert.ok(root && path.isAbsolute(root), 'Bazel must supply a private TEST_TMPDIR'); +const sdkMarker = `${path.sep}sdk_macosx${path.sep}`; +assert.ok(sdkFile.includes(sdkMarker), 'Expected a file from the declared macOS SDK'); +const sdk = `${sdkFile.slice(0, sdkFile.indexOf(sdkMarker))}${path.sep}sdk_macosx`; +const home = path.join(root, 'home'); +mkdirSync(home); +const packageRoot = path.join(root, 'package'); +extractPortableArchiveTree(realpathSync(source), packageRoot, 'package'); +const checksum = (file: string) => createHash('sha256').update(readFileSync(file)).digest('hex'); +const stagedSource = path.join(root, 'source-tag'); +copyDeclaredTree(sourceTree, stagedSource, [], sourceTreePath); +assertSwiftSourceDeliveryParity( + realpathSync(source), + readSwiftSourceTagMembers(stagedSource), + readFileSync(path.join(stagedSource, 'Package.swift')), +); +const manifestFile = path.join(packageRoot, 'Package.swift'); +const { manifest, ...composition } = composeSwiftCandidateManifest( + readFileSync(manifestFile, 'utf8'), + readFileSync(path.join(packageRoot, 'LIBOLIPHAUNT_VERSION'), 'utf8'), + path.basename(base), + checksum(base), +); +writeFileSync(manifestFile, manifest); +localizeSwiftReleaseManifest({ + manifestFile, + assetFile: realpathSync(base), + bindingsAssetFile: realpathSync(bindings), + outputFile: manifestFile, +}); +extractPortableArchiveTree( + realpathSync(base), + path.join(packageRoot, 'Artifacts/liboliphaunt.xcframework'), + 'liboliphaunt.xcframework', +); +extractPortableArchiveTree( + realpathSync(bindings), + path.join(packageRoot, 'Artifacts/OliphauntNativeBindingsFFI.xcframework'), + 'OliphauntNativeBindingsFFI.xcframework', +); +const consumerRoot = path.join(root, 'consumer'); +mkdirSync(path.join(consumerRoot, 'Sources/InstalledConsumer'), { recursive: true }); +writeFileSync( + path.join(consumerRoot, 'Sources/InstalledConsumer/main.swift'), + readFileSync(consumer), +); +const nativeTests = path.join(consumerRoot, 'Tests/NativeRuntimeTests'); +mkdirSync(nativeTests, { recursive: true }); +for (const file of ['NativeRuntimeTests.swift', 'AsyncStringSignal.swift']) + copyFileSync(path.join(packageRoot, 'Tests/OliphauntTests', file), path.join(nativeTests, file)); +const facts = JSON.parse(readFileSync(receipt, 'utf8')); +assert.equal( + triple, + `arm64-apple-macosx${facts.deploymentTargets.package_macos}`, + 'Swift package profile disagrees with the declared host SDK', +); +writeFileSync( + path.join(consumerRoot, 'Package.swift'), + `// swift-tools-version: 6.0 +import PackageDescription +let package = Package(name: "InstalledConsumer", platforms: [.macOS("${facts.deploymentTargets.package_macos}")], dependencies: [.package(name: "OliphauntSDK", path: "../package")], targets: [.executableTarget(name: "InstalledConsumer", dependencies: [${['COliphaunt', 'Oliphaunt', 'OliphauntCore', 'OliphauntBroker', 'OliphauntBrokerExtension', 'OliphauntExtensionSupport'].map((product) => `.product(name: "${product}", package: "OliphauntSDK")`).join(', ')}]), .testTarget(name: "NativeRuntimeTests", dependencies: [.product(name: "Oliphaunt", package: "OliphauntSDK"), .product(name: "OliphauntCore", package: "OliphauntSDK")])]) +`, +); +const signingTools = path.join(path.dirname(receipt), 'tools'); +const environment = { + HOME: home, + CFFIXED_USER_HOME: home, + TMPDIR: root, + PATH: [path.dirname(swift), signingTools].join(path.delimiter), + CODESIGN_ALLOCATE: path.join(signingTools, 'codesign_allocate'), + SWIFTPM_CUSTOM_BIN_DIR: path.dirname(swift), + DEVELOPER_DIR: facts.developerDirectory, + SDKROOT: sdk, + SWIFT_EXEC: swiftc, + CC: clang, + CXX: clangxx, +}; +const build = path.join(root, 'build'); +const testing = path.resolve(path.dirname(swift), '../lib/swift/macosx/testing'); +const swiftOptions = [ + '--package-path', + consumerRoot, + '--scratch-path', + build, + '--cache-path', + path.join(root, 'cache'), + '--config-path', + path.join(root, 'configuration'), + '--security-path', + path.join(root, 'security'), + '--sdk', + sdk, + '--triple', + triple, + '--jobs', + '2', + '--disable-sandbox', + '-Xswiftc', + '-disable-sandbox', + '-Xswiftc', + '-enable-testing', + '-Xswiftc', + '-resource-dir', + '-Xswiftc', + path.resolve(path.dirname(swift), '../lib/swift'), + ...['plugins', 'plugins/testing'].flatMap((directory) => [ + '-Xswiftc', + '-external-plugin-path', + '-Xswiftc', + `${path.resolve(path.dirname(swift), '../lib/swift/host', directory)}#${path.join(path.dirname(swift), 'swift-plugin-server')}`, + ]), + ...['-I', '-L'].flatMap((flag) => ['-Xswiftc', flag, '-Xswiftc', testing]), + '-Xlinker', + '-rpath', + '-Xlinker', + testing, + '-Xcc', + '-isysroot', + '-Xcc', + sdk, +]; +const result = spawnSync(swift, ['build', ...swiftOptions], { env: environment, stdio: 'inherit' }); +assert.equal(result.error, undefined, String(result.error)); +assert.equal(result.status, 0, 'Installed Swift source ZIP failed to compile/link'); +const executable = path.join(build, 'debug/InstalledConsumer'); +for (const phase of ['create', 'reopen']) { + const run = spawnSync(executable, [phase, path.join(root, 'database')], { + env: environment, + encoding: 'utf8', + }); + assert.equal(run.error, undefined, String(run.error)); + assert.equal(run.status, 0, `Installed Swift ${phase} failed: ${run.stderr}`); + assert.equal(run.stdout.trim(), `installed-swift-${phase}-42`); +} +// Swift Testing can host tests outside the installed executable's bundle directory. +const installedRuntime = realpathSync( + path.join(path.dirname(executable), 'liboliphaunt.framework/Resources/oliphaunt/runtime/files'), +); +const native = spawnSync( + swift, + ['test', ...swiftOptions, '--disable-xctest', '--filter', 'NativeRuntimeTests'], + { + env: { + ...environment, + OLIPHAUNT_SWIFT_REQUIRE_NATIVE: '1', + OLIPHAUNT_INSTALL_DIR: installedRuntime, + }, + encoding: 'utf8', + maxBuffer: 32 * 1024 * 1024, + }, +); +assert.equal(native.error, undefined, String(native.error)); +const nativeOutput = `${native.stdout}\n${native.stderr}`; +assert.equal(native.status, 0, `Installed Swift native suite failed:\n${nativeOutput}`); +assert.match(nativeOutput, /Test run with [1-9][0-9]* tests? .*passed/u); +console.log(nativeOutput); +const output = process.env.TEST_UNDECLARED_OUTPUTS_DIR ?? root; +mkdirSync(output, { recursive: true }); +writeFileSync( + path.join(output, 'swift-consumer-receipt.json'), + `${JSON.stringify( + { + schema: 'oliphaunt-installed-swift-consumer-v1', + mode: 'bundled-candidate', + composition, + inputs: Object.fromEntries( + Object.entries({ source, base, bindings, consumer, hostSdk: receipt }).map( + ([name, file]) => [name, { name: path.basename(file), sha256: checksum(file) }], + ), + ), + triple, + resourceResolution: 'framework-bundle', + cases: ['create-query-42', 'reopen-query-42', 'native-runtime-suite'], + }, + null, + 2, + )}\n`, +); diff --git a/build_defs/languages/swift/consumer.bzl b/build_defs/languages/swift/consumer.bzl new file mode 100644 index 000000000..d9c4ca243 --- /dev/null +++ b/build_defs/languages/swift/consumer.bzl @@ -0,0 +1,56 @@ +"""Installed SwiftPM consumer on the licensed, declared native Xcode profile.""" + +load("@oliphaunt_toolchain_metadata//:apple-platforms.bzl", "APPLE_DEPLOYMENT_TARGETS") +load("//build_defs/extensions:final_leaf.bzl", "NativeAppleBaseInfo") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/native/carriers:defs.bzl", "native_payload_helpers") + +_SWIFT_TOOLCHAIN = "@rules_swift//toolchains:toolchain_type" + +def _consumer_impl(ctx): + base = ctx.attr.native_base[NativeAppleBaseInfo] + framework = [file for file in base.archive_files if file.path == base.archives["base-xcframework"]["path"]][0] + info = ctx.toolchains[_SWIFT_TOOLCHAIN].swift_toolchain + tools = depset(transitive = [depset(config.additional_tools) for config in info.tool_configs.values()]).to_list() + selected = [] + for mode in ["swift", "swiftc", "clang", "clang++"]: + files = [file for file in tools if file.short_path.endswith("/toolchain/bin/" + mode)] + if len(files) != 1: + fail("Installed Swift consumer requires exactly one declared Xcode " + mode) + selected.append(files[0]) + sdk_files = [file for file in tools if "/sdk_macosx/" in file.short_path] + if not sdk_files: + fail("Installed Swift consumer requires a declared macOS SDK") + receipts = [file for file in tools if file.basename == "receipt.json"] + if len(receipts) != 1: + fail("Installed Swift consumer requires one exact host SDK receipt") + inputs = [ctx.file.archive, framework, ctx.file.bindings, ctx.file.consumer] + arguments = inputs + selected + [sdk_files[0], receipts[0], "arm64-apple-macosx%s" % APPLE_DEPLOYMENT_TARGETS["package_macos"], ctx.file.source_tree, ctx.file.source_tree.path] + inputs.extend([ctx.file.source_tree, ctx.file._codesign, ctx.file._codesign_allocate]) + return bun_test_entrypoint(ctx, ctx.file._runner, arguments, tools + inputs + ctx.files._helpers, source_files = [ctx.file._runner] + ctx.files._helpers) + +_swift_package_consumer_test = rule( + implementation = _consumer_impl, + test = True, + toolchains = [_SWIFT_TOOLCHAIN] + BUN_SOURCE_TOOLCHAINS, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "archive": attr.label(mandatory = True, allow_single_file = [".zip"]), + "source_tree": attr.label(mandatory = True, allow_single_file = True), + "native_base": attr.label(default = Label("//src/native/sdks/swift:source_package_native_requirement"), providers = [NativeAppleBaseInfo]), + "bindings": attr.label(mandatory = True, allow_single_file = [".zip"]), + "consumer": attr.label(mandatory = True, allow_single_file = [".swift"]), + "_codesign": attr.label(default = Label("@native_apple_sdk//:tools/codesign"), allow_single_file = True), + "_codesign_allocate": attr.label(default = Label("@native_apple_sdk//:tools/codesign_allocate"), allow_single_file = True), + "_runner": attr.label(default = Label("//build_defs/languages/swift:consumer-test.mts"), allow_single_file = True), + "_helpers": attr.label_list(default = [Label(value) for value in [ + "//src/native/sdks/swift:tools/prepare-swift-release-consumer.mts", + "//build_defs/native/apple:swift-candidate-contract.mts", + "//build_defs/native/carriers:payload.mts", + "//build_defs/languages/swift:source-delivery-contract.mts", + "//tools/release:native-file-identity.mts", + ] + native_payload_helpers()], allow_files = True), + }), +) + +def swift_package_consumer_test(name, args = [], **kwargs): + _swift_package_consumer_test(name = name, args = bun_test_entrypoint_args(name) + args, **kwargs) diff --git a/build_defs/languages/swift/extension-fixture.bzl b/build_defs/languages/swift/extension-fixture.bzl new file mode 100644 index 000000000..b8231a838 --- /dev/null +++ b/build_defs/languages/swift/extension-fixture.bzl @@ -0,0 +1,122 @@ +"""Selected Swift consumer Files over the original source and final carriers.""" + +load("@oliphaunt_metadata//:metadata.bzl", "COMPLETED_SUPPLIER_ARTIFACTS", "EXTENSION_FINAL_INPUTS", "EXTENSION_RELEASE_METADATA", "NATIVE_RUNTIME_ARTIFACTS", "NATIVE_SWIFT_SOURCE_INPUT", "PREPARED_NATIVE_SELECTED_PRODUCTS", "PRODUCTS") +load("//build_defs/extensions:owner_carriers.bzl", "native_owner_carrier_helpers", "native_owner_carrier_metadata") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") +load("//build_defs/release:supplier.bzl", "ShippingSupplierInfo") + +def swift_extension_fixture_helpers(): + return native_owner_carrier_helpers() + [ + "//src/native/sdks/swift:generator_sources", + "//src/native/sdks/swift:tools/swift-extension-release-consumer-inputs.mts", + "//src/native/sdks/swift:tools/swift-source-carrier-contract.mts", + "//src/native/sdks/swift:tools/prepare-swift-release-consumer.mts", + ] + +def _requested_products(): + selected = PREPARED_NATIVE_SELECTED_PRODUCTS + if "oliphaunt-swift" not in selected: + return [] + source = NATIVE_SWIFT_SOURCE_INPUT + if not source: + fail("selected Swift requires its original qualified source ZIP/carrier/catalog Files") + if source["version"] != PRODUCTS["oliphaunt-swift"]["version"]: + fail("selected Swift original source package version differs from its conventional manifest") + requested = [] + for product in sorted({row["artifactProduct"]: True for row in EXTENSION_RELEASE_METADATA}): + spec = native_owner_carrier_metadata(product) + if spec["owner"] in selected and spec["runtimeVersion"] == source["nativeVersion"]: + requested.append(product) + return requested + +def selected_swift_extension_fixture_exports(): + return ["//build_defs/languages/swift:selected_extension_fixture_shipping_export"] if _requested_products() else [] + +def _impl(ctx): + original = json.decode(ctx.attr.original) + aliases = {} + for target, alias in ctx.attr.original_files.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1 or files[0].is_directory: + fail("Swift fixture original inputs require retained regular Files") + aliases[alias] = files[0] + source = {key: dict(original[key], path = aliases[original[key]["path"]].path) for key in ["archive", "carrier", "ownerCatalog"]} + controls = [] + inputs = list(aliases.values()) + for target, product in ctx.attr.controls.items(): + files = getattr(target[OutputGroupInfo], "control_swift-extension-carrier").to_list() + if len(files) != 1 or files[0].is_directory: + fail("Swift fixture requires exactly one source-owned final carrier control") + spec = native_owner_carrier_metadata(product) + controls.append({"product": spec["owner"], "version": spec["version"], "file": {"path": files[0].path}}) + inputs.append(files[0]) + archives = json.decode(ctx.attr.assets) + base_archives = json.decode(ctx.attr.base_archives) + for row in archives: + row["path"] = aliases[row["path"]].path + for row in base_archives.values(): + row["path"] = aliases[row["path"]].path + output = ctx.actions.declare_directory(ctx.label.name + "/release/swiftpm-extension-consumer-fixture") + action = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(action, json.encode({"version": original["version"], "selectedProducts": PREPARED_NATIVE_SELECTED_PRODUCTS, + "sourceArchive": source["archive"], "sourceCarrier": source["carrier"], "ownerCatalog": source["ownerCatalog"], + "carriers": controls, "assets": archives, "baseArchives": base_archives if base_archives else None})) + bun_file_action(ctx, ctx.file._runner, arguments = [output.path, action.path], inputs = inputs + [action], + source_files = [ctx.file._runner] + ctx.files._helpers, outputs = [output], mnemonic = "SwiftExtensionConsumerFixture") + suppliers = json.decode(ctx.attr.suppliers) + for supplier in suppliers: + for file in supplier["files"]: + file["path"] = aliases[file["path"]].path + return [DefaultInfo(files = depset([output])), ShippingSupplierInfo(suppliers = suppliers, files = depset(inputs))] + +_fixture = rule(implementation = _impl, toolchains = BUN_SOURCE_TOOLCHAINS, attrs = { + "original": attr.string(mandatory = True), "assets": attr.string(mandatory = True), "base_archives": attr.string(mandatory = True), + "suppliers": attr.string(mandatory = True), "controls": attr.label_keyed_string_dict(), + "original_files": attr.label_keyed_string_dict(allow_files = True), + "_runner": attr.label(default = ":extension-fixture.mts", allow_single_file = True), + "_helpers": attr.label_list(default = swift_extension_fixture_helpers(), allow_files = True), +}) + +def selected_swift_extension_fixture(): + requested = _requested_products() + if not requested: + return + source = NATIVE_SWIFT_SOURCE_INPUT + files = [source[key] for key in ["archive", "carrier", "ownerCatalog"]] + assets, suppliers, controls, base_archives = [], [], {}, {} + for product in requested: + spec = native_owner_carrier_metadata(product) + family = "contrib_native_family" if spec["releaseMetadata"]["class"] == "contrib" else spec["members"][0]["sqlName"] + "_family" + controls["//build_defs/extensions:" + family] = product + record = EXTENSION_FINAL_INPUTS.get(product + "/native/ios-xcframework") + if not record: + fail("selected Swift fixture is missing its original final Apple carrier File: " + product) + assets.extend(record["github"]) + files.extend(record["github"]) + for file in record["github"]: + suppliers.append({"product": record["owner"], "version": record["version"], "configuration": record["target"], "binding": "abi-contract", + "origin": {"kind": "current-source", "producer": dict(file["producer"], **({"member": file["member"]} if "member" in file else {}))}, "files": [{"path": file["path"]}]}) + for key in ["archive", "carrier", "ownerCatalog"]: + file = source[key] + suppliers.append({"product": source["owner"], "version": source["version"], "configuration": "portable", "binding": "abi-contract", + "origin": {"kind": "current-source", "producer": dict(file["producer"], **({"member": file["member"]} if "member" in file else {}))}, "files": [{"path": file["path"]}]}) + for role, kind, target in [("base-xcframework", "apple-swiftpm-binary", "apple-spm-xcframework"), ("runtime-resources", "runtime-resources", "ios-datum64")]: + rows = [row for row in NATIVE_RUNTIME_ARTIFACTS if row["kind"] == kind and row["target"] == target] + if len(rows) != 1: + fail("Swift fixture requires one canonical native base archive role") + artifact = "github-release:" + rows[0]["asset"].replace("{version}", source["nativeVersion"]) + capture = COMPLETED_SUPPLIER_ARTIFACTS.get("liboliphaunt-native/" + source["nativeVersion"] + "/" + artifact) + if capture: + base_archives[role] = capture["file"] + files.append(capture["file"]) + suppliers.append({"product": "liboliphaunt-native", "version": source["nativeVersion"], "configuration": target, "binding": "abi-contract", + "origin": {"kind": "completed-publication", "publication": capture["publication"], "artifact": artifact}, "files": [{"path": capture["file"]["path"]}]}) + if base_archives and len(base_archives) != 2: + fail("selected Swift fixture original base archive tuple is incomplete") + _fixture(name = "selected_extension_fixture", original = json.encode(source), assets = json.encode(assets), + base_archives = json.encode(base_archives), original_files = {file["path"]: file["path"] for file in files}, controls = controls, suppliers = json.encode(suppliers)) + shipping_package(name = "selected_extension_fixture_shipping", owner = "@oliphaunt_metadata//:product_oliphaunt-swift", + artifacts = [":selected_extension_fixture"], ecosystem = "github", package_name = "swiftpm-extension-consumer-fixture", + configuration = "portable", role = "release-input", suppliers = ":selected_extension_fixture") + shipping_export(name = "selected_extension_fixture_shipping_export", packages = [":selected_extension_fixture_shipping"]) diff --git a/build_defs/languages/swift/extension-fixture.mts b/build_defs/languages/swift/extension-fixture.mts new file mode 100644 index 000000000..09115259a --- /dev/null +++ b/build_defs/languages/swift/extension-fixture.mts @@ -0,0 +1,164 @@ +/** The selected consumer fixture uses original source/carrier Files, offline. */ +import assert from 'node:assert/strict'; +import { mkdtempSync, readFileSync, realpathSync, rmSync } from 'node:fs'; +import { mkdir } from 'node:fs/promises'; +import path from 'node:path'; +import { renderExtensionProducts } from '../../../src/native/sdks/swift/tools/render-extension-products.mts'; +import { extractVerifiedZipArchive } from '../../../src/native/sdks/swift/tools/swift-carrier-resolver.mts'; +import { extensionReleaseConsumerInputs } from '../../../src/native/sdks/swift/tools/swift-extension-release-consumer-inputs.mts'; +import { fileIdentity } from '../../../tools/release/native-file-identity.mts'; + +type Input = { path: string; size: number; sha256: string }; +export type SwiftExtensionFixtureSpec = { + version: string; + selectedProducts: string[]; + sourceArchive: Input; + sourceCarrier: Input; + ownerCatalog: Input; + carriers: { product: string; version: string; file: Input }[]; + assets: Input[]; + baseArchives?: Record; +}; + +const physical = (input: Input) => { + const file = realpathSync(path.resolve(input.path)); + const observed = fileIdentity(file); + assert.deepEqual( + { size: observed.size, sha256: observed.sha256 }, + { size: input.size, sha256: input.sha256 }, + 'declared Swift fixture input bytes differ', + ); + return file; +}; + +export async function buildSwiftExtensionFixture(output: string, spec: SwiftExtensionFixtureSpec) { + assert.ok( + spec.selectedProducts.includes('oliphaunt-swift'), + 'Swift fixture requires the selected source product', + ); + assert.ok(spec.carriers.length > 0, 'Swift fixture requires selected independent Apple carriers'); + assert.equal( + new Set(spec.selectedProducts).size, + spec.selectedProducts.length, + 'Swift fixture selection repeats', + ); + assert.equal( + new Set(spec.carriers.map(({ product }) => product)).size, + spec.carriers.length, + 'Swift fixture carrier owner repeats', + ); + const files = [ + spec.sourceArchive, + spec.sourceCarrier, + spec.ownerCatalog, + ...spec.carriers.map(({ file }) => file), + ...spec.assets, + ...Object.values(spec.baseArchives ?? {}), + ]; + const sourceArchive = physical(spec.sourceArchive); + const sourceCarrier = physical(spec.sourceCarrier); + const ownerCatalog = physical(spec.ownerCatalog); + const carriers = spec.carriers.map(({ product, version, file }) => { + assert.ok( + spec.selectedProducts.includes(product), + 'Swift fixture cannot include an unselected carrier owner', + ); + const carrier = physical(file); + const document = JSON.parse(readFileSync(carrier, 'utf8')); + assert.equal(document.release?.product, product, 'Swift fixture carrier owner differs'); + assert.equal(document.release?.version, version, 'Swift fixture carrier version differs'); + return carrier; + }); + const destination = path.resolve(output); + await mkdir(path.dirname(destination), { recursive: true }); + const scratch = mkdtempSync(path.join(path.dirname(destination), '.swift-extension-fixture-')); + try { + const source = path.join(scratch, 'source'); + await extractVerifiedZipArchive({ archive: sourceArchive, destination: source }); + const sdk = path.join(source, 'package'); + assert.equal( + readFileSync(path.join(sdk, 'VERSION'), 'utf8').trim(), + spec.version, + 'Swift fixture cannot restamp another source package version', + ); + const base = JSON.parse(readFileSync(sourceCarrier, 'utf8')).base; + assert.equal( + readFileSync(path.join(sdk, 'LIBOLIPHAUNT_VERSION'), 'utf8').trim(), + base.version, + 'Swift fixture must preserve the source package native compatibility pin', + ); + const plan = extensionReleaseConsumerInputs({ + sourceCarrierFile: sourceCarrier, + extensionCarrierFiles: carriers, + nativeBaseArchiveInputs: spec.baseArchives, + }); + const cache = path.join(scratch, 'cache'); + await mkdir(path.join(cache, 'objects'), { recursive: true }); + const envelopes = new Map(); + for (const carrier of carriers) + for (const envelope of JSON.parse(readFileSync(carrier, 'utf8')).carriers) { + const previous = envelopes.get(envelope.name); + if (previous) + assert.deepEqual(previous, envelope, 'Swift fixture carrier envelope conflicts'); + else envelopes.set(envelope.name, envelope); + } + for (const envelope of envelopes.values()) { + const matches = spec.assets.filter( + (input) => + path.basename(input.path) === envelope.name && + input.sha256 === envelope.sha256 && + input.size === envelope.bytes, + ); + assert.equal( + matches.length, + 1, + 'Swift fixture requires the exact declared public carrier archive', + ); + fileIdentity( + physical(matches[0]), + path.join(cache, 'objects', `${envelope.sha256}-${envelope.name}`), + ); + } + await renderExtensionProducts([ + '--carrier', + sourceCarrier, + ...carriers.flatMap((carrier) => ['--extension-carrier', carrier]), + '--extensions', + plan.extensionsCsv, + '--base-package-version', + spec.version, + '--owner-catalog', + ownerCatalog, + '--cache-dir', + cache, + '--offline', + '--local-binary-targets', + '--output-dir', + destination, + ]); + const generated = JSON.parse( + readFileSync(path.join(destination, 'extension-products.json'), 'utf8'), + ); + assert.deepEqual( + generated.selected.map(({ sqlName }) => sqlName).sort(), + plan.extensions, + 'Swift fixture generated a different extension selection', + ); + for (const input of files) physical(input); + return generated; + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + assert.equal(process.argv.length, 4, 'Swift fixture needs declared output and input spec'); + const spec = JSON.parse(readFileSync(process.argv[3], 'utf8')); + // Newly constructed control Files have a declared Bazel producer rather + // than prior archive digests; capture their identities at this action edge. + spec.carriers = spec.carriers.map((row) => { + const file = fileIdentity(realpathSync(row.file.path)); + return { ...row, file: { path: row.file.path, size: file.size, sha256: file.sha256 } }; + }); + await buildSwiftExtensionFixture(process.argv[2], spec); +} diff --git a/build_defs/languages/swift/generate.mts b/build_defs/languages/swift/generate.mts new file mode 100644 index 000000000..5443cec59 --- /dev/null +++ b/build_defs/languages/swift/generate.mts @@ -0,0 +1,28 @@ +import assert from 'node:assert/strict'; +import { readdirSync, readFileSync } from 'node:fs'; +import { generateUniffi } from '../uniffi.mts'; + +export function validateSwiftConfiguration(configuration: unknown) { + const values = configuration as { + crates?: { oliphaunt_mobile_bindings?: { bindings?: { swift?: Record } } }; + }; + const swift = values.crates?.oliphaunt_mobile_bindings?.bindings?.swift; + assert.equal(swift?.module_name, 'OliphauntNativeBindings'); + assert.equal(swift?.ffi_module_name, 'OliphauntNativeBindingsFFI'); +} + +export function validateGeneratedSwift(directory: string) { + assert.deepEqual(readdirSync(directory).sort(), [ + 'OliphauntNativeBindings.swift', + 'OliphauntNativeBindingsFFI.h', + 'OliphauntNativeBindingsFFI.modulemap', + ]); +} + +if (import.meta.main) { + const [generator, library, configuration, directory] = process.argv.slice(2); + assert.equal(process.argv.length, 6, 'Expected generator, metadata library, config and output'); + validateSwiftConfiguration(Bun.TOML.parse(readFileSync(configuration, 'utf8'))); + generateUniffi({ generator, library, configuration, directory, language: 'swift' }); + validateGeneratedSwift(directory); +} diff --git a/build_defs/languages/swift/generate.test.mts b/build_defs/languages/swift/generate.test.mts new file mode 100644 index 000000000..3d0f376e9 --- /dev/null +++ b/build_defs/languages/swift/generate.test.mts @@ -0,0 +1,41 @@ +import { expect, test } from 'bun:test'; +import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { validateGeneratedSwift, validateSwiftConfiguration } from './generate.mts'; + +test('conventional UniFFI module identity is required by the existing Swift consumers', () => { + const swift = { + module_name: 'OliphauntNativeBindings', + ffi_module_name: 'OliphauntNativeBindingsFFI', + }; + const config = (value: unknown) => ({ + crates: { oliphaunt_mobile_bindings: { bindings: { swift: value } } }, + }); + validateSwiftConfiguration(config(swift)); + for (const value of [ + null, + {}, + { ...swift, module_name: 'Renamed' }, + { ...swift, ffi_module_name: undefined }, + ]) + expect(() => validateSwiftConfiguration(config(value))).toThrow(); +}); + +test('generated shape rejects missing outputs and undeclared outputs', () => { + const directory = mkdtempSync(path.join(tmpdir(), 'oliphaunt-uniffi-swift-')); + try { + for (const name of ['OliphauntNativeBindingsFFI.h', 'OliphauntNativeBindingsFFI.modulemap']) + writeFileSync(path.join(directory, name), 'fixture\n'); + expect(() => validateGeneratedSwift(directory)).toThrow(); + writeFileSync( + path.join(directory, 'OliphauntNativeBindings.swift'), + 'func backupToFd(fd: Int32) {}\n', + ); + validateGeneratedSwift(directory); + writeFileSync(path.join(directory, 'extra.swift'), 'extra\n'); + expect(() => validateGeneratedSwift(directory)).toThrow(); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); diff --git a/build_defs/languages/swift/ios-compile-test.mts b/build_defs/languages/swift/ios-compile-test.mts new file mode 100644 index 000000000..1fb514c0f --- /dev/null +++ b/build_defs/languages/swift/ios-compile-test.mts @@ -0,0 +1,149 @@ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { + copyFileSync, + mkdirSync, + readFileSync, + realpathSync, + statSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; + +assert.equal(process.platform, 'darwin', 'iOS compile qualification requires declared Xcode'); +assert.equal(process.arch, 'arm64', 'iOS compile qualification requires Apple arm64'); +const [specification, compiler, sdkFile, receipt] = process.argv.slice(2); +assert.equal(process.argv.length, 6, 'Expected exact compiler inputs and declared host SDK'); +const runfiles = process.env.OLIPHAUNT_BAZEL_RUNFILES; +const work = process.env.TEST_TMPDIR; +assert(runfiles && work && path.isAbsolute(runfiles) && path.isAbsolute(work)); +const inputs = JSON.parse(readFileSync(specification, 'utf8')); +const declared = (name: string) => { + assert(name && !path.isAbsolute(name) && !name.split('/').includes('..')); + return path.join(runfiles, name); +}; +const marker = `${path.sep}sdk_iphoneos${path.sep}`; +assert(sdkFile.includes(marker), 'Expected an actual declared iPhoneOS SDK File'); +const sdkRoot = sdkFile.slice(0, sdkFile.indexOf(marker)); +const sdk = path.join(sdkRoot, 'sdk_iphoneos'); +const facts = JSON.parse(readFileSync(receipt, 'utf8')); +assert.equal(facts.family, 'apple'); +assert( + Number.parseInt(facts.observations.iphoneos_version, 10) >= 26, + 'Broker requires iOS 26 SDK', +); +assert.equal(facts.tools.swiftc, 'tools/swiftc'); +const home = path.join(work, 'home'); +const stage = path.join(work, 'modules'); +const cache = path.join(work, 'module-cache'); +for (const directory of [ + home, + stage, + cache, + path.join(stage, 'ffi'), + path.join(stage, 'COliphaunt'), +]) + mkdirSync(directory, { recursive: true }); +for (const [key, destination] of [ + ['ffiHeader', 'ffi/OliphauntNativeBindingsFFI.h'], + ['ffiModulemap', 'ffi/module.modulemap'], + ['publicHeader', 'COliphaunt/oliphaunt.h'], + ['cHeader', 'COliphaunt/COliphaunt.h'], + ['cModulemap', 'COliphaunt/module.modulemap'], +]) + copyFileSync(declared(inputs[key]), path.join(stage, destination)); +const flags = [ + // Match rules_swift: Swift's macro sandbox cannot nest inside Bazel's sandbox. + '-disable-sandbox', + '-sdk', + sdk, + '-resource-dir', + path.join(sdkRoot, 'toolchain/lib/swift'), + '-external-plugin-path', + `${path.join(sdkRoot, 'toolchain/lib/swift/host/plugins')}#${path.join(sdkRoot, 'toolchain/bin/swift-plugin-server')}`, + '-swift-version', + '6', + '-package-name', + 'Oliphaunt', + '-parse-as-library', + '-module-cache-path', + cache, + '-Xcc', + `-fmodules-cache-path=${cache}`, + '-I', + stage, + '-I', + path.join(stage, 'ffi'), +]; +const environment = { + HOME: home, + TMPDIR: work, + PATH: path.join(sdkRoot, 'toolchain/bin'), + DEVELOPER_DIR: facts.developerDirectory, + SDKROOT: sdk, +}; +function compile(label: string, arguments_: string[]): void { + const result = spawnSync(realpathSync(compiler), [...flags, ...arguments_], { + cwd: work, + env: environment, + encoding: 'utf8', + maxBuffer: 32 * 1024 * 1024, + }); + assert.ifError(result.error); + assert.equal(result.status, 0, `${label}\n${result.stdout}\n${result.stderr}`); + console.log(`iOS compiler qualified ${label}`); +} +for (const [module, sources] of [ + ['OliphauntNativeBindings', [inputs.generatedSwift]], + ...['OliphauntCore', 'Oliphaunt', 'OliphauntBroker', 'OliphauntBrokerExtension'].map((module) => [ + module, + inputs.modules[module], + ]), +] as [string, string[]][]) { + const output = path.join(stage, `${module}.swiftmodule`); + compile(module, [ + '-target', + `arm64-apple-ios${module.startsWith('OliphauntBroker') ? '26.0' : '17.0'}`, + '-emit-module', + '-module-name', + module, + '-emit-module-path', + output, + ...sources.map(declared), + ]); + assert( + statSync(output).isFile() && statSync(output).size > 0, + `${module} emitted no actual module`, + ); +} +const extension = path.join(stage, 'DatabaseExtension.swift'); +writeFileSync( + extension, + readFileSync(declared(inputs.extensionTemplate), 'utf8').replaceAll( + '__HOST_BUNDLE_IDENTIFIER__', + 'dev.oliphaunt.BrokerCompile', + ), +); +const host = path.join(stage, 'Host.swift'); +copyFileSync(declared(inputs.hostTemplate), host); +compile('broker host template', ['-target', 'arm64-apple-ios26.0', '-typecheck', host]); +compile('broker application extension template', [ + '-target', + 'arm64-apple-ios26.0', + '-application-extension', + '-typecheck', + extension, +]); +for (const [execution, target, definitions] of [ + ['nativeDirect', 'arm64-apple-ios17.0', []], + ['broker', 'arm64-apple-ios26.0', ['-D', 'OLIPHAUNT_BROKER']], +] as [string, string, string[]][]) + compile(`React Native adapter ${execution}`, [ + '-target', + target, + ...definitions, + '-import-objc-header', + declared(inputs.adapterHeader), + '-typecheck', + declared(inputs.adapter), + ]); diff --git a/build_defs/languages/swift/ios-compile.bzl b/build_defs/languages/swift/ios-compile.bzl new file mode 100644 index 000000000..9264d4afa --- /dev/null +++ b/build_defs/languages/swift/ios-compile.bzl @@ -0,0 +1,65 @@ +"""The conventional broker and React Native iOS compiler qualification.""" + +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") + +def _runfile(ctx, file): + return file.short_path[3:] if file.short_path.startswith("../") else ctx.workspace_name + "/" + file.short_path + +def _ios_compile_impl(ctx): + modules = {} + for module in ["OliphauntCore", "Oliphaunt", "OliphauntBroker", "OliphauntBrokerExtension"]: + files = [file for file in ctx.files.sources if "/Sources/" + module + "/" in file.short_path] + if not files: + fail("iOS compiler qualification requires the original " + module + " sources") + modules[module] = [_runfile(ctx, file) for file in files] + files = [ctx.file.generated_swift, ctx.file.ffi_header, ctx.file.ffi_modulemap, ctx.file.public_header, + ctx.file.c_header, ctx.file.c_modulemap, ctx.file.extension_template, ctx.file.host_template, + ctx.file.adapter, ctx.file.adapter_header] + specification = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(specification, json.encode({ + "modules": modules, + "generatedSwift": _runfile(ctx, ctx.file.generated_swift), + "ffiHeader": _runfile(ctx, ctx.file.ffi_header), + "ffiModulemap": _runfile(ctx, ctx.file.ffi_modulemap), + "publicHeader": _runfile(ctx, ctx.file.public_header), + "cHeader": _runfile(ctx, ctx.file.c_header), + "cModulemap": _runfile(ctx, ctx.file.c_modulemap), + "extensionTemplate": _runfile(ctx, ctx.file.extension_template), + "hostTemplate": _runfile(ctx, ctx.file.host_template), + "adapter": _runfile(ctx, ctx.file.adapter), + "adapterHeader": _runfile(ctx, ctx.file.adapter_header), + })) + if not ctx.files._sdk: + fail("iOS compiler qualification requires the declared iPhoneOS SDK") + return bun_test_entrypoint(ctx, ctx.file._runner, + [specification, ctx.file._compiler, ctx.files._sdk[0], ctx.file._receipt], + files + ctx.files.sources + ctx.files._sdk + ctx.files._toolchain + ctx.files._platform + [ctx.file._compiler, ctx.file._receipt, specification], + source_files = [ctx.file._runner], runfiles_environment = ["OLIPHAUNT_BAZEL_RUNFILES"]) + +_swift_ios_compile_test = rule( + implementation = _ios_compile_impl, + test = True, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "sources": attr.label_list(mandatory = True, allow_files = [".swift"]), + "generated_swift": attr.label(mandatory = True, allow_single_file = [".swift"]), + "ffi_header": attr.label(mandatory = True, allow_single_file = [".h"]), + "ffi_modulemap": attr.label(mandatory = True, allow_single_file = True), + "public_header": attr.label(default = Label("//src/native/runtime:include/oliphaunt.h"), allow_single_file = True), + "c_header": attr.label(mandatory = True, allow_single_file = True), + "c_modulemap": attr.label(mandatory = True, allow_single_file = True), + "extension_template": attr.label(mandatory = True, allow_single_file = True), + "host_template": attr.label(mandatory = True, allow_single_file = True), + "adapter": attr.label(default = Label("//src/native/sdks/react-native:ios/OliphauntAdapter.swift"), allow_single_file = True), + "adapter_header": attr.label(default = Label("//src/native/sdks/react-native:ios/OliphauntAdapter.h"), allow_single_file = True), + "_runner": attr.label(default = Label("//build_defs/languages/swift:ios-compile-test.mts"), allow_single_file = True), + "_compiler": attr.label(default = Label("@native_apple_sdk//:tools/swiftc_files"), allow_single_file = True), + "_receipt": attr.label(default = Label("@native_apple_sdk//:receipt.json"), allow_single_file = True), + "_sdk": attr.label(default = Label("@native_apple_sdk//:sdk_iphoneos_files")), + "_toolchain": attr.label(default = Label("@native_apple_sdk//:toolchain_files")), + "_platform": attr.label_list(default = [Label("@native_apple_sdk//:platform_iphoneos/Library_files"), Label("@native_apple_sdk//:platform_iphoneos/usr/lib_files")]), + }), +) + +def swift_ios_compile_test(name, args = [], **kwargs): + _swift_ios_compile_test(name = name, args = bun_test_entrypoint_args(name) + args, **kwargs) diff --git a/build_defs/languages/swift/source-delivery-contract.mts b/build_defs/languages/swift/source-delivery-contract.mts new file mode 100644 index 000000000..3f41deab3 --- /dev/null +++ b/build_defs/languages/swift/source-delivery-contract.mts @@ -0,0 +1,93 @@ +/** The source ZIP's installed compile also covers the source tag's shared members. */ +import { deepStrictEqual } from 'node:assert'; +import { createHash } from 'node:crypto'; +import { lstatSync, readdirSync, realpathSync } from 'node:fs'; +import path from 'node:path'; +import { readPortableArchiveEntries } from '../../../tools/packaging/portable-archive.mts'; +import { fileIdentity } from '../../../tools/release/native-file-identity.mts'; + +type Member = + | { path: string; type: 'directory'; mode: number } + | { path: string; type: 'file'; mode: number; size: number; sha256: string }; + +const sha256 = (data: Uint8Array) => createHash('sha256').update(data).digest('hex'); +const common = (name: string) => + /^(Sources|Templates)(\/|$)/u.test(name) || + ['VERSION', 'LIBOLIPHAUNT_VERSION', 'LICENSE', 'THIRD_PARTY_NOTICES.md'].includes(name); + +/** A declared runfiles tree may have a root link; nested links remain prohibited. */ +export function readSwiftSourceTagMembers(tree: string): Member[] { + const root = realpathSync(tree); + const rows: Member[] = []; + const visit = (name: string) => { + const absolute = path.join(root, name); + const stat = lstatSync(absolute); + if (stat.isDirectory()) { + rows.push({ path: name, type: 'directory', mode: stat.mode & 0o777 }); + for (const child of readdirSync(absolute).sort()) visit(name ? `${name}/${child}` : child); + } else if (stat.isFile()) rows.push({ path: name, ...fileIdentity(absolute) }); + else throw new Error(`Swift source tag requires regular members: ${name}`); + }; + if (!lstatSync(root).isDirectory()) throw new Error('Swift source tag must be a directory'); + visit(''); + return rows; +} + +/** Carriers are source-tag-only; ZIP tests/docs are intentionally outside its manifest. */ +export function assertSwiftSourceDeliveryParity( + archive: string, + tree: readonly Member[], + manifest: Uint8Array, +) { + const entries = readPortableArchiveEntries(archive); + const archiveRows = []; + for (const [name, entry] of entries) { + const member = name.startsWith('package/') ? name.slice('package/'.length) : ''; + if (!common(member)) continue; + archiveRows.push( + entry.isDirectory + ? { path: member, type: 'directory' } + : { + path: member, + type: 'file', + mode: entry.mode & 0o777, + size: entry.size, + sha256: sha256(entry.data()), + }, + ); + } + const treeRows = []; + for (const row of tree) { + const member = row.path.startsWith('src/sdks/swift/') + ? row.path.slice('src/sdks/swift/'.length) + : row.path; + if (!common(member)) continue; + // Git source tags do not record directory modes. File modes stay exact. + const { mode: _directoryMode, ...directory } = row; + treeRows.push( + row.type === 'directory' ? { ...directory, path: member } : { ...row, path: member }, + ); + } + for (const required of ['VERSION', 'LIBOLIPHAUNT_VERSION', 'LICENSE', 'THIRD_PARTY_NOTICES.md']) + if (!archiveRows.some(({ path, type }) => path === required && type === 'file')) + throw new Error(`Swift source ZIP lacks required shared member ${required}`); + const ordered = (rows) => rows.sort((left, right) => left.path.localeCompare(right.path)); + deepStrictEqual( + ordered(treeRows), + ordered(archiveRows), + 'Swift source tag shared delivered members differ from the installed source ZIP', + ); + const packageManifest = entries.get('package/Package.swift'); + if (!packageManifest?.isFile) throw new Error('Swift source ZIP lacks Package.swift'); + const sourceManifest = tree.find(({ path }) => path === 'Package.swift'); + if (sourceManifest?.type !== 'file' || sourceManifest.mode !== (packageManifest.mode & 0o777)) + throw new Error('Swift source tag manifest mode differs from the installed source ZIP'); + const canonical = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }) + .decode(manifest) + .replaceAll('"src/sdks/swift/Sources/', '"Sources/'); + deepStrictEqual( + Buffer.from(packageManifest.data()), + Buffer.from(canonical), + 'Swift source ZIP manifest differs beyond the canonical source path rewrite', + ); +} diff --git a/build_defs/languages/swift/source-package.fixture.mts b/build_defs/languages/swift/source-package.fixture.mts new file mode 100644 index 000000000..d8829595a --- /dev/null +++ b/build_defs/languages/swift/source-package.fixture.mts @@ -0,0 +1,129 @@ +/** Shared real source-envelope inputs for source packaging and physical transport fixtures. */ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { mkdirSync, readFileSync, realpathSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { + createDeterministicTar, + createDeterministicZip, +} from '../../../tools/packaging/archive-directory.mts'; +import { + canonicalGzipSync, + readPortableArchiveEntries, +} from '../../../tools/packaging/portable-archive.mts'; +import type { SwiftSourceSpecification } from './source-package.mts'; + +function digest(bytes: Uint8Array): string { + return createHash('sha256').update(bytes).digest('hex'); +} + +export async function fixture( + scratch: string, + legalMode = 0o644, +): Promise { + const carrier = JSON.parse( + readFileSync('build_defs/release/testdata/swift-0.8.2-carrier.json', 'utf8'), + ); + const files: Record = {}; + for (const asset of carrier.base.assets) { + const root = path.join(scratch, asset.role); + const group = carrier.legal.base.find( + (row: { assetRole: string }) => row.assetRole === asset.role, + ); + mkdirSync(path.join(root, asset.member), { recursive: true }); + for (const legal of group.files) { + const bytes = Buffer.from(`frozen fixture ${legal.member}\n`); + const destination = path.join(root, legal.member); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, bytes, { mode: legalMode }); + legal.bytes = bytes.length; + legal.sha256 = digest(bytes); + } + if (asset.role === 'base-xcframework') { + const framework = path.join(root, asset.member); + const slices = [ + ['macos-arm64', 'macos', ''], + ['ios-arm64', 'ios', ''], + ['ios-arm64-simulator', 'ios', 'simulator'], + ] as const; + writeFileSync( + path.join(framework, 'Info.plist'), + `AvailableLibraries${slices.map(([identifier, platform, variant]) => `LibraryIdentifier${identifier}LibraryPathfixture.aSupportedArchitecturesarm64SupportedPlatform${platform}${variant ? `SupportedPlatformVariant${variant}` : ''}`).join('')}`, + ); + for (const [identifier] of slices) { + mkdirSync(path.join(framework, identifier)); + writeFileSync(path.join(framework, identifier, 'fixture.a'), 'construction fixture\n'); + mkdirSync(path.join(framework, identifier, 'Headers')); + writeFileSync( + path.join(framework, identifier, 'Headers', 'oliphaunt.h'), + '// genuine held native fixture header\n', + ); + } + } + const archive = path.join(scratch, asset.name); + const modes = Object.fromEntries(group.files.map((legal) => [legal.member, legalMode])); + const bytes = + asset.format === 'zip' + ? await createDeterministicZip(path.join(root, asset.member), { keepParent: true, modes }) + : canonicalGzipSync(await createDeterministicTar(root, { modes })); + writeFileSync(archive, bytes); + asset.bytes = bytes.length; + asset.sha256 = digest(bytes); + files[asset.role] = archive; + } + const carrierFile = path.join(scratch, 'carrier.json'); + writeFileSync(carrierFile, `${JSON.stringify(carrier, null, 2)}\n`); + const source = path.join(scratch, 'source-inputs'); + mkdirSync(source); + const sourceFiles: Record = {}; + for (const [member, bytes] of Object.entries({ + VERSION: '9.8.7\n', + LIBOLIPHAUNT_VERSION: '0.3.3\n', + 'Package.swift': '// development package\n', + 'README.md': 'Swift SDK\n', + 'Sources/Oliphaunt/Oliphaunt.swift': '// source fixture\n', + 'Templates/OliphauntBroker/Info.plist': 'fixture\n', + 'Tests/test.swift': '// test fixture\n', + 'Tests/Fixtures/swiftpm-extension-resources/runtime/files/share/postgresql/extension/fixture.control': + 'declared test fixture\n', + })) { + const file = path.join(source, member); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, bytes); + sourceFiles[member] = file; + } + for (const member of ['LICENSE', 'THIRD_PARTY_NOTICES.md']) + sourceFiles[member] = path.resolve(member); + const generatedSwift = path.join(scratch, 'OliphauntNativeBindings.swift'); + writeFileSync(generatedSwift, '// generated fixture\n'); + const bindingsArchive = path.join(scratch, 'oliphaunt-swift-9.8.7-bindings.xcframework.zip'); + const xcframework = files['base-xcframework']; + const runtimeResources = files['runtime-resources']; + assert.ok(xcframework && runtimeResources); + const original = readPortableArchiveEntries(xcframework); + const ffi = path.join(scratch, 'OliphauntNativeBindingsFFI.xcframework'); + mkdirSync(ffi); + for (const [member, entry] of original) { + if (!entry.isFile) continue; + const destination = path.join(ffi, member.slice('liboliphaunt.xcframework/'.length)); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, entry.data()); + } + writeFileSync(bindingsArchive, await createDeterministicZip(ffi, { keepParent: true })); + return { + version: '9.8.7', + nativeVersion: '0.3.3', + sources: sourceFiles, + generatedSwift, + bindingsArchive, + carrier: carrierFile, + xcframework, + runtimeResources, + generators: Object.fromEntries( + ['extension-resource-inventory', 'render-extension-products', 'swift-carrier-resolver'].map( + (name) => [`${name}.mjs`, realpathSync(`src/native/sdks/swift/tools/${name}.mts`)], + ), + ), + ownerCatalog: path.resolve('src/extensions/generated/sdk/extensions.json'), + }; +} diff --git a/build_defs/languages/swift/source-package.mts b/build_defs/languages/swift/source-package.mts new file mode 100644 index 000000000..4ab4a5958 --- /dev/null +++ b/build_defs/languages/swift/source-package.mts @@ -0,0 +1,264 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + copyFileSync, + mkdirSync, + mkdtempSync, + readFileSync, + realpathSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { validateFrozenNativeCarrierIdentity } from '../../../src/native/sdks/swift/tools/swift-native-carrier-contract.mts'; +import { renderSwiftReleaseManifest } from '../../../src/native/sdks/swift/tools/swift-release-manifest.mts'; +import { + SWIFT_SOURCE_FIXTURE_PREFIX, + validateSwiftSourceFixtureEntries, +} from '../../../src/native/sdks/swift/tools/swift-source-fixture-contract.mts'; +import { + readNativeAppleHeader, + validateAppleXcframeworkAsset, +} from '../../../src/native/sdks/swift/tools/swift-xcframework-contract.mts'; +import { createDeterministicZip } from '../../../tools/packaging/archive-directory.mts'; +import { bundleJavaScript, emitJavaScript } from '../../../tools/packaging/emit-javascript.mts'; +import { readPortableArchiveEntries } from '../../../tools/packaging/portable-archive.mts'; +import { + assertReleaseNoticesInDirectory, + stageReleaseNotices, +} from '../../../tools/packaging/release-notices.mts'; +import { findSdkRuntimePayloadViolation } from '../../../tools/packaging/sdk-runtime-payload.mts'; + +const REPOSITORY = 'https://github.com/f0rr0/oliphaunt'; +const SEMVER = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u; +const CARRIER = 'oliphaunt-react-native-ios-carriers.json'; + +export type SwiftSourceSpecification = { + version: string; + nativeVersion: string; + sources: Record; + generatedSwift: string; + bindingsArchive: string; + carrier: string; + xcframework: string; + runtimeResources: string; + generators: Record; + ownerCatalog: string; +}; + +function sha256(bytes: Uint8Array): string { + return createHash('sha256').update(bytes).digest('hex'); +} + +function copy(source: string, destination: string): void { + mkdirSync(path.dirname(destination), { recursive: true }); + copyFileSync(realpathSync(source), destination); + chmodSync(destination, 0o644); +} + +export function verifyFrozenNativeArchives( + spec: Pick< + SwiftSourceSpecification, + 'carrier' | 'nativeVersion' | 'xcframework' | 'runtimeResources' + >, +) { + const carrier = validateFrozenNativeCarrierIdentity({ + carrier: JSON.parse(readFileSync(spec.carrier, 'utf8')), + expectedNativeVersion: spec.nativeVersion, + }); + for (const asset of carrier.base.assets) { + const file = realpathSync( + asset.role === 'base-xcframework' ? spec.xcframework : spec.runtimeResources, + ); + const bytes = readFileSync(file); + assert.equal(bytes.length, asset.bytes, `${asset.name} size differs from frozen carrier`); + assert.equal(sha256(bytes), asset.sha256, `${asset.name} SHA-256 differs from frozen carrier`); + const entries = readPortableArchiveEntries(file, { format: asset.format }); + assert.ok( + [...entries.keys()].some( + (member) => member === asset.member || member.startsWith(`${asset.member}/`), + ), + `${asset.name} lacks declared member ${asset.member}`, + ); + const group = carrier.legal.base.find((row) => row.assetRole === asset.role); + assert.ok(group, `${asset.name} lacks frozen legal metadata`); + for (const legal of group.files) { + const entry = entries.get(legal.member); + assert.ok(entry?.isFile, `${asset.name} lacks legal file ${legal.member}`); + assert.equal(entry.mode & 0o777, 0o644, `${legal.member} must have mode 0644`); + const content = entry.data(); + assert.equal(content.length, legal.bytes, `${legal.member} size differs from frozen carrier`); + assert.equal( + sha256(content), + legal.sha256, + `${legal.member} SHA-256 differs from frozen carrier`, + ); + } + } + return carrier; +} + +export async function packageSwiftSource( + outputRoot: string, + spec: SwiftSourceSpecification, +): Promise { + outputRoot = path.resolve(outputRoot); + assert.match(spec.version, SEMVER, 'Swift owner version must be stable SemVer'); + assert.match(spec.nativeVersion, SEMVER, 'Swift compatibility version must be stable SemVer'); + for (const member of [ + 'Package.swift', + 'VERSION', + 'LIBOLIPHAUNT_VERSION', + 'LICENSE', + 'THIRD_PARTY_NOTICES.md', + 'README.md', + ]) + assert(Object.hasOwn(spec.sources, member), `Swift source inputs omitted ${member}`); + const carrier = verifyFrozenNativeArchives(spec); + await validateAppleXcframeworkAsset(realpathSync(spec.xcframework)); + await validateAppleXcframeworkAsset( + realpathSync(spec.bindingsArchive), + 'OliphauntNativeBindingsFFI', + ); + const base = carrier.base.assets.find((asset) => asset.role === 'base-xcframework'); + const bindingsName = `oliphaunt-swift-${spec.version}-bindings.xcframework.zip`; + assert.equal( + path.basename(spec.bindingsArchive), + bindingsName, + 'Swift FFI asset must match release owner version', + ); + const manifest = renderSwiftReleaseManifest( + `${REPOSITORY}/releases/download/${carrier.base.tag}`, + spec.nativeVersion, + base.sha256, + `${REPOSITORY}/releases/download/oliphaunt-swift-v${spec.version}/${bindingsName}`, + sha256(readFileSync(spec.bindingsArchive)), + ); + mkdirSync(outputRoot, { recursive: true }); + const scratch = mkdtempSync(path.join(outputRoot, '.swift-source-')); + try { + const sourceRoot = path.join(scratch, 'sources'); + const sourcePackage = path.join(scratch, 'package'); + const tree = path.join(outputRoot, 'release-tree'); + for (const [member, source] of Object.entries(spec.sources)) { + assert.ok( + member && + !member.includes('\\') && + !member.startsWith('/') && + !/^[A-Za-z]:/u.test(member) && + !/[\u0000-\u001f\u007f]/u.test(member) && + member.split('/').every((part) => part && part !== '.' && part !== '..'), + `Unsafe Swift source entry ${member}`, + ); + assert.ok( + member === 'LICENSE' || + member === 'THIRD_PARTY_NOTICES.md' || + /^(Sources|Templates|Tests)\//u.test(member) || + [ + 'README.md', + 'CHANGELOG.md', + 'VERSION', + 'LIBOLIPHAUNT_VERSION', + 'Package.swift', + ].includes(member), + `Unexpected Swift source entry ${member}`, + ); + copy(source, path.join(sourcePackage, member)); + if (member === 'LICENSE' || member === 'THIRD_PARTY_NOTICES.md') + copy(source, path.join(sourceRoot, member)); + if ( + /^(Sources|Templates)\//u.test(member) || + ['VERSION', 'LIBOLIPHAUNT_VERSION'].includes(member) + ) + copy(source, path.join(tree, 'src/sdks/swift', member)); + } + assert.equal( + readFileSync(path.join(sourcePackage, 'VERSION'), 'utf8').trim(), + spec.version, + 'Swift conventional version disagrees with owner', + ); + assert.equal( + readFileSync(path.join(sourcePackage, 'LIBOLIPHAUNT_VERSION'), 'utf8').trim(), + spec.nativeVersion, + 'Swift conventional compatibility pin disagrees with owner', + ); + for (const root of [tree, sourcePackage]) { + stageReleaseNotices(root, { profile: 'source-sdk', sourceRoot }); + assertReleaseNoticesInDirectory(root, { profile: 'source-sdk', sourceRoot }); + } + const bindingsDestination = 'Sources/OliphauntNativeBindings/OliphauntNativeBindings.swift'; + copy(spec.generatedSwift, path.join(sourcePackage, bindingsDestination)); + copy(spec.generatedSwift, path.join(tree, 'src/sdks/swift', bindingsDestination)); + // Header bytes come from this package's actual native requirement, even + // while the workspace native source advances independently. + const publicHeader = 'Sources/COliphaunt/include/oliphaunt.h'; + const header = readNativeAppleHeader(realpathSync(spec.xcframework)); + for (const destination of [ + path.join(sourcePackage, publicHeader), + path.join(tree, 'src/sdks/swift', publicHeader), + ]) { + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, header, { mode: 0o644 }); + } + writeFileSync(path.join(outputRoot, 'Package.swift.release'), manifest, { mode: 0o644 }); + // The declared tree is a complete source tag. The separately named + // manifest stays available to the existing frozen publication adapter. + writeFileSync(path.join(tree, 'Package.swift'), manifest, { mode: 0o644 }); + writeFileSync( + path.join(sourcePackage, 'Package.swift'), + manifest.replaceAll('"src/sdks/swift/Sources/', '"Sources/'), + { mode: 0o644 }, + ); + const carrierFile = path.join(tree, 'src/sdks/swift/Carriers', CARRIER); + mkdirSync(path.dirname(carrierFile), { recursive: true }); + // Preserve the immutable public carrier bytes, rather than rebinding its + // held dependency to current workspace versions or legal source files. + copy(spec.carrier, carrierFile); + const generatorRoot = path.join(outputRoot, 'extension-generator'); + mkdirSync(generatorRoot, { recursive: true }); + assert.deepEqual(Object.keys(spec.generators).sort(), [ + 'extension-resource-inventory.mjs', + 'render-extension-products.mjs', + 'swift-carrier-resolver.mjs', + ]); + for (const [name, source] of Object.entries(spec.generators)) { + const destination = path.join(generatorRoot, name); + if (name === 'swift-carrier-resolver.mjs') + writeFileSync(destination, await bundleJavaScript(source), { mode: 0o644 }); + else emitJavaScript(source, destination); + } + copy(spec.ownerCatalog, path.join(generatorRoot, 'extension-owner-catalog.json')); + writeFileSync( + path.join(outputRoot, 'Oliphaunt-source.zip'), + await createDeterministicZip(sourcePackage, { keepParent: true }), + { mode: 0o644 }, + ); + const archive = path.join(outputRoot, 'Oliphaunt-source.zip'); + const entries = readPortableArchiveEntries(archive); + const fixtures = new Map( + Object.entries(spec.sources) + .filter(([member]) => `package/${member}`.startsWith(SWIFT_SOURCE_FIXTURE_PREFIX)) + .map(([member, source]) => [`package/${member}`, readFileSync(source)]), + ); + const allowed = validateSwiftSourceFixtureEntries(archive, entries, fixtures); + const violation = findSdkRuntimePayloadViolation( + 'oliphaunt-swift', + [...entries].filter(([, entry]) => entry.isFile).map(([name]) => name), + allowed, + ); + assert.equal( + violation, + null, + `Swift source ZIP must not include runtime/extension payload ${violation}`, + ); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + const [outputRoot, specification] = process.argv.slice(2); + assert.equal(process.argv.length, 4, 'Expected output root and declared Swift specification'); + await packageSwiftSource(outputRoot, JSON.parse(readFileSync(specification, 'utf8'))); +} diff --git a/build_defs/languages/swift/source-package.test.mts b/build_defs/languages/swift/source-package.test.mts new file mode 100644 index 000000000..9b9d829e1 --- /dev/null +++ b/build_defs/languages/swift/source-package.test.mts @@ -0,0 +1,502 @@ +import { expect, test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { + chmodSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + SWIFT_SOURCE_FIXTURE_PREFIX, + validateSwiftSourceFixtureEntries, +} from '../../../src/native/sdks/swift/tools/swift-source-fixture-contract.mts'; +import { readNativeAppleHeader } from '../../../src/native/sdks/swift/tools/swift-xcframework-contract.mts'; +import { readPortableArchiveEntries } from '../../../tools/packaging/portable-archive.mts'; +import { zipArchive } from '../../../tools/packaging/testdata/zip-fixture.mts'; +import { copyDeclaredTree } from '../../native/carriers/payload.mts'; +import { + assertSwiftSourceDeliveryParity, + readSwiftSourceTagMembers, +} from './source-delivery-contract.mts'; +import { fixture } from './source-package.fixture.mts'; +import { packageSwiftSource, verifyFrozenNativeArchives } from './source-package.mts'; + +test('a held native header cannot be replaced by another slice or an incomplete framework', () => { + const root = mkdtempSync(path.join(tmpdir(), 'selected-native-header-')); + try { + const file = path.join(root, 'native.zip'); + const rows = ['macos-arm64', 'ios-arm64', 'ios-arm64-simulator'].map((slice) => ({ + name: `liboliphaunt.xcframework/${slice}/liboliphaunt.framework/Headers/oliphaunt.h`, + data: Buffer.from('original selected ABI header'), + })); + writeFileSync(file, zipArchive(rows)); + expect(readNativeAppleHeader(file)).toEqual(rows[0].data); + writeFileSync(file, zipArchive(rows.slice(1))); + expect(() => readNativeAppleHeader(file)).toThrow(/all public C headers/); + writeFileSync( + file, + zipArchive([...rows.slice(0, 2), { ...rows[2], data: Buffer.from('another ABI header') }]), + ); + expect(() => readNativeAppleHeader(file)).toThrow(/different public C headers/); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('final source envelope preserves held native version, exact source-tag paths and portable package paths', async () => { + const scratch = mkdtempSync(path.join(tmpdir(), 'oliphaunt-swift-source-')); + try { + const spec = await fixture(scratch); + const first = path.join(scratch, 'first'); + const second = path.join(scratch, 'second'); + await packageSwiftSource(path.relative(process.cwd(), first), spec); + await packageSwiftSource(second, spec); + expect( + readFileSync(path.join(first, 'Oliphaunt-source.zip')).equals( + readFileSync(path.join(second, 'Oliphaunt-source.zip')), + ), + ).toBeTrue(); + const manifest = readFileSync(path.join(first, 'Package.swift.release'), 'utf8'); + expect(manifest).toContain('liboliphaunt-native-v0.3.3'); + expect(manifest).toContain('oliphaunt-swift-v9.8.7'); + expect(readFileSync(path.join(first, 'release-tree/Package.swift'), 'utf8')).toBe(manifest); + expect( + readFileSync(path.join(first, 'release-tree/src/sdks/swift/VERSION'), 'utf8').trim(), + ).toBe(spec.version); + expect( + readFileSync( + path.join(first, 'release-tree/src/sdks/swift/LIBOLIPHAUNT_VERSION'), + 'utf8', + ).trim(), + ).toBe(spec.nativeVersion); + expect( + readFileSync( + path.join( + first, + 'release-tree/src/sdks/swift/Carriers/oliphaunt-react-native-ios-carriers.json', + ), + ).equals(readFileSync(spec.carrier)), + ).toBeTrue(); + const entries = readPortableArchiveEntries(path.join(first, 'Oliphaunt-source.zip')); + const fixtures = new Map( + Object.entries(spec.sources) + .filter(([member]) => `package/${member}`.startsWith(SWIFT_SOURCE_FIXTURE_PREFIX)) + .map(([member, file]) => [`package/${member}`, readFileSync(file)]), + ); + const [fixtureName] = fixtures.keys(); + assert(fixtureName); + const fixtureEntry = entries.get(fixtureName); + assert(fixtureEntry?.isFile); + for (const [fault, message] of [ + ['missing', 'file set must exactly match'], + ['extra', 'file set must exactly match'], + ['tampered', 'must byte-for-byte match'], + ]) { + const changed = new Map(entries); + if (fault === 'missing') changed.delete(fixtureName); + else + changed.set( + fault === 'extra' ? `${SWIFT_SOURCE_FIXTURE_PREFIX}extra.control` : fixtureName, + { + ...fixtureEntry, + data: () => Buffer.from('changed fixture'), + }, + ); + expect(() => validateSwiftSourceFixtureEntries('changed.zip', changed, fixtures)).toThrow( + message, + ); + } + const tree = path.join(first, 'release-tree'); + const treeManifest = readFileSync(path.join(tree, 'Package.swift')); + // This is the publisher's Git100644 fixture, not a claim about NTFS + // permission bits. Exact physical-tree modes are checked separately below. + const declaredTagMembers = readSwiftSourceTagMembers(tree).map((row) => + row.type === 'file' ? { ...row, mode: 0o644 } : row, + ); + const archiveParity = (archive: string) => + assertSwiftSourceDeliveryParity(archive, declaredTagMembers, treeManifest); + archiveParity(path.join(first, 'Oliphaunt-source.zip')); + const zipRows = [...entries].map(([name, entry]) => { + expect(entry.mode & 0o777).toBe(entry.isDirectory ? 0o755 : 0o644); + return { + name: entry.isDirectory ? `${name}/` : name, + data: entry.isFile ? Buffer.from(entry.data()) : Buffer.alloc(0), + externalAttributes: + ((entry.isDirectory ? 0o40755 : 0o100644) << 16) | (entry.isDirectory ? 0x10 : 0), + }; + }); + const corruptArchive = path.join(scratch, 'source-fault.zip'); + writeFileSync(corruptArchive, zipArchive(zipRows)); + archiveParity(corruptArchive); + const sharedMember = 'package/Sources/Oliphaunt/Oliphaunt.swift'; + for (const [rows, message] of [ + [zipRows.filter(({ name }) => name !== sharedMember), 'shared delivered members differ'], + [ + zipRows.map((row) => + row.name === sharedMember + ? { ...row, data: Buffer.from('// ZIP-only source edit\n') } + : row, + ), + 'shared delivered members differ', + ], + [ + [ + ...zipRows, + { + name: 'package/Sources/Oliphaunt/extra.swift', + data: Buffer.from('// ZIP-only extra source\n'), + externalAttributes: 0o100644 << 16, + }, + ], + 'shared delivered members differ', + ], + [ + zipRows.map((row) => + row.name === 'package/Package.swift' + ? { + ...row, + data: Buffer.concat([row.data, Buffer.from('// ZIP-only manifest edit\n')]), + } + : row, + ), + 'manifest differs beyond the canonical source path rewrite', + ], + ] as const) { + writeFileSync(corruptArchive, zipArchive(rows)); + expect(() => archiveParity(corruptArchive)).toThrow(message); + } + for (const member of [sharedMember, 'package/Package.swift']) { + writeFileSync( + corruptArchive, + zipArchive( + zipRows.map((row) => + row.name === member ? { ...row, externalAttributes: 0o100755 << 16 } : row, + ), + ), + ); + expect(() => archiveParity(corruptArchive)).toThrow( + member.endsWith('/Package.swift') + ? 'manifest mode differs' + : 'shared delivered members differ', + ); + } + for (const [name, message] of [ + ['package/../escape', 'unsafe archive member'], + ['/escape', 'unsafe archive member'], + ['C:/escape', 'unsafe archive member'], + ['package\\escape', 'unsafe archive member'], + ['package/Sources/CON.swift', 'non-portable archive member'], + ['package/Sources/file.swift:stream', 'non-portable archive member'], + ]) { + writeFileSync(corruptArchive, zipArchive([...zipRows, { name, data: 'unsafe member' }])); + expect(() => archiveParity(corruptArchive)).toThrow(message); + } + for (const mode of [0o120777, 0o10644]) { + writeFileSync( + corruptArchive, + zipArchive( + zipRows.map((row) => + row.name === sharedMember + ? { ...row, data: Buffer.from('../outside'), externalAttributes: mode << 16 } + : row, + ), + ), + ); + expect(() => archiveParity(corruptArchive)).toThrow('link or special ZIP entry'); + } + // Windows chmod/stat cannot establish a POSIX source-tree mode contract, + // and file symlink creation may require privileges. Encoded ZIP faults + // above cover both contracts portably without weakening the public reader. + if (process.platform !== 'win32') { + const declaredTree = 'first/release-tree'; + const runfilesTree = path.join(scratch, 'runfiles/_main', declaredTree); + for (const row of readSwiftSourceTagMembers(tree)) { + const destination = path.join(runfilesTree, row.path); + if (row.type === 'directory') mkdirSync(destination, { recursive: true }); + else { + mkdirSync(path.dirname(destination), { recursive: true }); + chmodSync(path.join(tree, row.path), 0o555); + symlinkSync(path.join(tree, row.path), destination); + } + } + expect(() => readSwiftSourceTagMembers(runfilesTree)).toThrow('regular members'); + const stagedTree = path.join(scratch, 'staged-source-tag'); + copyDeclaredTree(runfilesTree, stagedTree, [], declaredTree); + assertSwiftSourceDeliveryParity( + path.join(first, 'Oliphaunt-source.zip'), + readSwiftSourceTagMembers(stagedTree), + readFileSync(path.join(stagedTree, 'Package.swift')), + ); + for (const row of readSwiftSourceTagMembers(stagedTree)) + if (row.type === 'file') chmodSync(path.join(tree, row.path), 0o644); + const parity = () => + assertSwiftSourceDeliveryParity( + path.join(first, 'Oliphaunt-source.zip'), + readSwiftSourceTagMembers(tree), + readFileSync(path.join(tree, 'Package.swift')), + ); + parity(); + const member = path.join(tree, 'src/sdks/swift/Sources/Oliphaunt/Oliphaunt.swift'); + const original = readFileSync(member); + for (const fault of ['removed', 'changed', 'extra', 'mode', 'symlink']) { + const extra = path.join(tree, 'src/sdks/swift/Sources/Oliphaunt/extra.swift'); + if (fault === 'removed') rmSync(member); + if (fault === 'changed') writeFileSync(member, '// only source tag changed\n'); + if (fault === 'extra') writeFileSync(extra, '// extra source tag member\n'); + if (fault === 'mode') chmodSync(member, 0o755); + if (fault === 'symlink') { + rmSync(member); + symlinkSync(spec.generatedSwift, member); + } + expect(parity).toThrow(); + rmSync(extra, { force: true }); + rmSync(member, { force: true }); + writeFileSync(member, original, { mode: 0o644 }); + } + parity(); + const tagManifest = path.join(tree, 'Package.swift'); + const manifestBytes = readFileSync(tagManifest); + writeFileSync( + tagManifest, + Buffer.concat([manifestBytes, Buffer.from('// tree-only edit\n')]), + ); + expect(parity).toThrow('manifest differs beyond the canonical source path rewrite'); + writeFileSync(tagManifest, manifestBytes); + chmodSync(tagManifest, 0o755); + expect(parity).toThrow('manifest mode differs'); + chmodSync(tagManifest, 0o644); + parity(); + } + const content = (member: string) => { + const entry = entries.get(member); + assert.ok(entry?.isFile, `Missing ${member}`); + return Buffer.from(entry.data()); + }; + expect(content('package/Package.swift').toString()).toContain('path: "Sources/Oliphaunt"'); + expect( + content('package/Sources/OliphauntNativeBindings/OliphauntNativeBindings.swift').toString(), + ).toBe('// generated fixture\n'); + expect(entries.has('package/Tests/test.swift')).toBeTrue(); + expect( + entries.has( + 'package/Tests/Fixtures/swiftpm-extension-resources/runtime/files/share/postgresql/extension/fixture.control', + ), + ).toBeTrue(); + expect(entries.has('package/Templates/OliphauntBroker/Info.plist')).toBeTrue(); + expect(content('package/Sources/COliphaunt/include/oliphaunt.h').toString()).toBe( + '// genuine held native fixture header\n', + ); + expect( + content('package/Sources/COliphaunt/include/oliphaunt.h').equals( + readFileSync('src/native/runtime/include/oliphaunt.h'), + ), + ).toBeFalse(); + for (const name of [ + 'extension-resource-inventory.mjs', + 'render-extension-products.mjs', + 'swift-carrier-resolver.mjs', + 'extension-owner-catalog.json', + ]) + expect(readFileSync(path.join(first, 'extension-generator', name)).length).toBeGreaterThan(0); + expect(() => verifyFrozenNativeArchives({ ...spec, nativeVersion: '0.3.4' })).toThrow( + 'must match', + ); + await expect( + packageSwiftSource(path.join(scratch, 'mismatch'), { ...spec, version: '9.8.8' }), + ).rejects.toThrow('owner version'); + await expect( + packageSwiftSource(path.join(scratch, 'escape'), { + ...spec, + sources: { ...spec.sources, '../escape': spec.generatedSwift }, + }), + ).rejects.toThrow('Unsafe Swift source'); + await expect( + packageSwiftSource(path.join(scratch, 'runtime-payload'), { + ...spec, + sources: { + ...spec.sources, + 'Sources/Oliphaunt/Resources/runtime/files/share/postgresql/extension/pgtap.control': + spec.generatedSwift, + }, + }), + ).rejects.toThrow('must not include runtime/extension payload'); + for (const member of [ + 'Package.swift', + 'VERSION', + 'LIBOLIPHAUNT_VERSION', + 'LICENSE', + 'THIRD_PARTY_NOTICES.md', + 'README.md', + ]) { + const sources = { ...spec.sources }; + delete sources[member]; + await expect( + packageSwiftSource(path.join(scratch, `missing-${member}`), { ...spec, sources }), + ).rejects.toThrow(`omitted ${member}`); + } + const corrupted = path.join(scratch, 'corrupt.zip'); + writeFileSync(corrupted, 'corrupt\n'); + expect(() => verifyFrozenNativeArchives({ ...spec, xcframework: corrupted })).toThrow( + 'size differs', + ); + const executableLegal = await fixture(path.join(scratch, 'executable-legal'), 0o755); + expect(() => verifyFrozenNativeArchives(executableLegal)).toThrow('must have mode 0644'); + // Even an updated envelope hash cannot hide a changed frozen legal locator. + const changed = JSON.parse(readFileSync(spec.carrier, 'utf8')); + changed.legal.base[0].files[0].sha256 = '0'.repeat(64); + writeFileSync(spec.carrier, JSON.stringify(changed)); + expect(() => verifyFrozenNativeArchives(spec)).toThrow('SHA-256 differs'); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +}); + +test.skipIf(process.platform === 'win32')( + 'installed Swift consumer isolates its home and supplies the native suite its installed runtime', + async () => { + const scratch = mkdtempSync(path.join(tmpdir(), 'swift-consumer-signing-')); + try { + const spec = await fixture(path.join(scratch, 'inputs')); + const nativeTests = path.join(scratch, 'NativeRuntimeTests.swift'); + writeFileSync(nativeTests, 'import Testing\n'); + spec.sources['Tests/OliphauntTests/NativeRuntimeTests.swift'] = nativeTests; + const signalHelper = path.resolve( + 'src/native/sdks/swift/Tests/OliphauntTests/AsyncStringSignal.swift', + ); + spec.sources['Tests/OliphauntTests/AsyncStringSignal.swift'] = signalHelper; + const packaged = path.join(scratch, 'packaged'); + await packageSwiftSource(packaged, spec); + const sdk = path.join(scratch, 'declared-sdk'); + const bin = path.join(sdk, 'toolchain/bin'); + const tools = path.join(sdk, 'tools'); + mkdirSync(bin, { recursive: true }); + mkdirSync(tools); + for (const name of ['codesign', 'codesign_allocate']) + symlinkSync(process.execPath, path.join(tools, name)); + const sdkFile = path.join(sdk, 'sdk_macosx/usr/include/fixture.h'); + mkdirSync(path.dirname(sdkFile), { recursive: true }); + writeFileSync(sdkFile, '// declared SDK fixture\n'); + const receipt = path.join(sdk, 'receipt.json'); + writeFileSync( + receipt, + JSON.stringify({ + developerDirectory: '/declared/developer', + deploymentTargets: { package_macos: '13.0' }, + }), + ); + const trace = path.join(scratch, 'swiftpm-phases'); + const runRoot = path.join(scratch, 'test-root'); + const physicalRunRoot = path.join(scratch, 'physical-test-root'); + mkdirSync(physicalRunRoot); + // Exercise canonical paths on Linux too, like macOS's /var -> /private/var. + symlinkSync(physicalRunRoot, runRoot, 'dir'); + const installedRuntime = path.join( + runRoot, + 'build/debug/liboliphaunt.framework/Resources/oliphaunt/runtime/files', + ); + const checkHome = `assert.equal(process.env.HOME, ${JSON.stringify(path.join(runRoot, 'home'))}); +assert.equal(process.env.CFFIXED_USER_HOME, process.env.HOME, 'Foundation must use the private test home');`; + const checkDefaultRuntime = `assert.equal(process.env.OLIPHAUNT_INSTALL_DIR, undefined, 'default resource discovery must remain under test'); +assert.equal(process.env.OLIPHAUNT_RUNTIME_DIR, undefined); +assert.equal(process.env.OLIPHAUNT_INITDB, undefined);`; + const installedConsumer = `#!${process.execPath} +import assert from 'node:assert/strict'; +import { appendFileSync } from 'node:fs'; +${checkHome} +${checkDefaultRuntime} +appendFileSync(${JSON.stringify(trace)}, process.argv[2] + '\\n'); +console.log('installed-swift-' + process.argv[2] + '-42'); +`; + const executable = path.join(bin, 'swift'); + // These tool fixtures exercise the real consumer runner and child PATH; + // they are not Swift compilation or macOS signing evidence. + writeFileSync( + executable, + '#!' + + process.execPath + + '\n' + + ` +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { appendFileSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +${checkHome} +const args = process.argv.slice(2); +const signing = spawnSync('codesign', ['--version'], { env: process.env, encoding: 'utf8' }); +assert.equal(signing.error, undefined, 'captured codesign must resolve from the consumer PATH'); +assert.equal(signing.status, 0); +assert.equal(process.env.CODESIGN_ALLOCATE, ${JSON.stringify(path.join(tools, 'codesign_allocate'))}); +assert.equal(spawnSync(process.env.CODESIGN_ALLOCATE, ['--version'], { env: process.env }).status, 0); +assert.equal(process.env.SWIFTPM_CUSTOM_BIN_DIR, ${JSON.stringify(bin)}); +appendFileSync(${JSON.stringify(trace)}, args[0] + '\\n'); +if (args[0] === 'build') { + ${checkDefaultRuntime} + const build = args[args.indexOf('--scratch-path') + 1]; + mkdirSync(path.join(build, 'debug'), { recursive: true }); + writeFileSync(path.join(build, 'debug/InstalledConsumer'), ${JSON.stringify(installedConsumer)}, { mode: 0o755 }); + mkdirSync(${JSON.stringify(installedRuntime)}, { recursive: true }); + writeFileSync(path.join(${JSON.stringify(installedRuntime)}, '../manifest.properties'), 'installed framework runtime fixture'); +} else { + assert.equal(args[0], 'test'); + assert(args.includes('--disable-xctest')); + assert.equal(args[args.indexOf('--filter') + 1], 'NativeRuntimeTests'); + assert.equal(process.env.OLIPHAUNT_SWIFT_REQUIRE_NATIVE, '1'); + assert.equal(process.env.OLIPHAUNT_INSTALL_DIR, realpathSync(${JSON.stringify(installedRuntime)}), 'the native suite must use its installed framework runtime'); + assert.equal(readFileSync(path.join(process.env.OLIPHAUNT_INSTALL_DIR, '../manifest.properties'), 'utf8'), 'installed framework runtime fixture'); + console.log('Test run with 1 test passed'); +} +`, + { mode: 0o755 }, + ); + const preload = path.join(scratch, 'darwin-fixture.mts'); + writeFileSync( + preload, + "Object.defineProperty(process, 'platform', { value: 'darwin' });\nObject.defineProperty(process, 'arch', { value: 'arm64' });\n", + ); + const sourceTree = path.join(packaged, 'release-tree'); + const result = spawnSync( + process.execPath, + [ + '--no-install', + '--no-env-file', + '--preload', + preload, + path.join(import.meta.dir, 'consumer-test.mts'), + path.join(packaged, 'Oliphaunt-source.zip'), + spec.xcframework, + spec.bindingsArchive, + nativeTests, + executable, + path.join(bin, 'swiftc'), + path.join(bin, 'clang'), + path.join(bin, 'clang++'), + sdkFile, + receipt, + 'arm64-apple-macosx13.0', + sourceTree, + sourceTree, + ], + { env: { TEST_TMPDIR: runRoot }, encoding: 'utf8', maxBuffer: 4 * 1024 * 1024 }, + ); + expect(result.status, result.stderr).toBe(0); + expect( + readFileSync( + path.join(runRoot, 'consumer/Tests/NativeRuntimeTests/AsyncStringSignal.swift'), + ), + ).toEqual(readFileSync(signalHelper)); + expect(readFileSync(trace, 'utf8')).toBe('build\ncreate\nreopen\ntest\n'); + const proof = JSON.parse( + readFileSync(path.join(runRoot, 'swift-consumer-receipt.json'), 'utf8'), + ); + expect(proof.cases).toEqual(['create-query-42', 'reopen-query-42', 'native-runtime-suite']); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } + }, +); diff --git a/build_defs/languages/swift/source.bzl b/build_defs/languages/swift/source.bzl new file mode 100644 index 000000000..836254e99 --- /dev/null +++ b/build_defs/languages/swift/source.bzl @@ -0,0 +1,176 @@ +"""The final SwiftPM source carrier, using its declared frozen native pin.""" + +load("@oliphaunt_metadata//:metadata.bzl", "PRODUCTS") +load("//build_defs/apple:slices.bzl", "apple_slice_filegroup", "apple_slice_groups") +load("//build_defs/extensions:declared_final_inputs.bzl", "native_declared_apple_base") +load("//build_defs/extensions:final_leaf.bzl", "NativeAppleBaseInfo") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") +load("//build_defs/foundation:bun-sources.bzl", "bun_source_path", "bun_source_tree") +load("//build_defs/languages:mobile-compiled-inputs.bzl", "MOBILE_BINDINGS_COMPILE_QUALIFICATION") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") +load("//build_defs/release:supplier.bzl", "shipping_suppliers") +load(":xcframework.bzl", "SWIFT_BINDINGS_COMPILE_OWNERS", "SWIFT_BINDINGS_COMPILE_SLOTS", "swift_bindings_compile_group", "swift_bindings_compiled_supplier") + +def _swift_source_impl(ctx): + base = ctx.attr.native_base[NativeAppleBaseInfo] + if base.version != ctx.attr.native_version or len(base.archive_files) != 2: + fail("Swift source must consume its exact conventional native requirement") + archives = base.archives + framework = [file for file in base.archive_files if file.path == archives["base-xcframework"]["path"]][0] + resources = [file for file in base.archive_files if file.path == archives["runtime-resources"]["path"]][0] + sources = {} + inputs = ctx.files.sources + [ctx.file.generated_swift, ctx.file.bindings_archive, base.file, framework, resources, ctx.file.owner_catalog, ctx.file._packager] + ctx.files._helpers + prefix = ctx.label.package + "/" + for file in ctx.files.sources: + member = file.short_path[len(prefix):] if file.short_path.startswith(prefix) else file.short_path + if member in sources: + fail("duplicate Swift source member " + member) + sources[member] = file.path + generators = {} + code = bun_source_tree(ctx, ctx.label.name + ".sources", [ctx.file._packager] + ctx.files._helpers + ctx.files.generators) + for file in ctx.files.generators: + generators[file.basename.removesuffix(".mts") + ".mjs"] = bun_source_path(ctx, code, file) + inputs.append(file) + specification = ctx.actions.declare_file(ctx.label.name + ".sources.json") + ctx.actions.write(specification, json.encode({ + "version": ctx.attr.version, + "nativeVersion": ctx.attr.native_version, + "sources": sources, + "generatedSwift": ctx.file.generated_swift.path, + "bindingsArchive": ctx.file.bindings_archive.path, + "carrier": base.file.path, + "xcframework": framework.path, + "runtimeResources": resources.path, + "generators": generators, + "ownerCatalog": ctx.file.owner_catalog.path, + })) + archive = ctx.actions.declare_file(ctx.label.name + "/Oliphaunt-source.zip") + manifest = ctx.actions.declare_file(ctx.label.name + "/Package.swift.release") + tree = ctx.actions.declare_directory(ctx.label.name + "/release-tree") + generator_files = [ctx.actions.declare_file(ctx.label.name + "/extension-generator/" + name) for name in ["extension-resource-inventory.mjs", "render-extension-products.mjs", "swift-carrier-resolver.mjs", "extension-owner-catalog.json"]] + outputs = [archive, manifest, tree] + generator_files + bun_file_action( + ctx, + entry_point = ctx.file._packager, + sources = code, + arguments = [archive.dirname, specification.path], + inputs = depset(inputs + [specification]), + outputs = outputs, + mnemonic = "OliphauntSwiftSourceEnvelope", + use_default_shell_env = False, + ) + return [DefaultInfo(files = depset(outputs)), OutputGroupInfo( + source_archive = depset([archive]), + manifest = depset([manifest]), + tree = depset([tree]), + resource_inventory = depset([generator_files[0]]), + extension_generator = depset([generator_files[1]]), + carrier_resolver = depset([generator_files[2]]), + owner_catalog = depset([generator_files[3]]), + **apple_slice_groups([ctx.attr.bindings_archive, ctx.attr.native_base]) + )] + +_swift_source = rule( + implementation = _swift_source_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = { + "version": attr.string(mandatory = True), + "native_version": attr.string(mandatory = True), + "sources": attr.label_list(allow_files = True, mandatory = True), + "generated_swift": attr.label(allow_single_file = [".swift"], mandatory = True), + "bindings_archive": attr.label(allow_single_file = [".zip"], mandatory = True), + "native_base": attr.label(providers = [NativeAppleBaseInfo], mandatory = True), + "owner_catalog": attr.label(allow_single_file = [".json"], mandatory = True), + "generators": attr.label_list(allow_files = [".mts"], mandatory = True), + "_packager": attr.label(default = Label("//build_defs/languages/swift:source-package.mts"), allow_single_file = True), + "_helpers": attr.label_list(default = [ + Label("//src/native/sdks/swift:tools/swift-native-carrier-contract.mts"), + Label("//src/native/sdks/swift:tools/swift-release-manifest.mts"), + Label("//src/native/sdks/swift:tools/swift-source-fixture-contract.mts"), + Label("//src/native/sdks/swift:tools/swift-xcframework-contract.mts"), + Label("//:tools/packaging/archive-directory.mts"), + Label("//:tools/packaging/portable-archive.mts"), + Label("//:tools/packaging/sdk-runtime-payload.mts"), + Label("//:tools/packaging/release-notices.mts"), + Label("//:tools/packaging/release-directory-safety.mts"), + Label("//:tools/packaging/emit-javascript.mts"), + ], allow_files = True), + }, +) + +def swift_source_package(name, sources, bindings_archive, bindings_release_assets, generated_swift): + product = "oliphaunt-swift" + descriptor = PRODUCTS[product] + native_requirement = name + "_native_requirement" + native_declared_apple_base(name = native_requirement, version = descriptor["compatibility_versions"]["liboliphaunt-native"], local_current = True) + source_suppliers = name + "_suppliers" + shipping_suppliers(name = source_suppliers, inputs = [":" + native_requirement, bindings_release_assets]) + _swift_source( + name = name, + version = descriptor["version"], + native_version = descriptor["compatibility_versions"]["liboliphaunt-native"], + sources = sources, + generated_swift = generated_swift, + bindings_archive = bindings_archive, + native_base = ":" + native_requirement, + owner_catalog = "//src/extensions/generated/sdk:extensions.json", + generators = ["tools/extension-resource-inventory.mts", "tools/render-extension-products.mts", "tools/swift-carrier-resolver.mts"], + target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:aarch64"], + ) + packages = [] + for group, artifact_name in [ + ("source_archive", "Oliphaunt-source.zip"), + ("manifest", "Package.swift.release"), + ("tree", "release-tree"), + ("tree", "oliphaunt-react-native-ios-carriers.json"), + ("resource_inventory", "extension-resource-inventory.mjs"), + ("extension_generator", "render-extension-products.mjs"), + ("carrier_resolver", "swift-carrier-resolver.mjs"), + ("owner_catalog", "extension-owner-catalog.json"), + ]: + suffix = artifact_name.replace(".", "_") + apple_slice_filegroup(name = "release_input_" + suffix, src = ":" + name, output_group = group) + package = "shipping_" + suffix + shipping_package(name = package, owner = "@oliphaunt_metadata//:product_" + product, artifacts = [":release_input_" + suffix], ecosystem = "github", package_name = artifact_name, configuration = "portable", role = "release-input", suppliers = ":" + source_suppliers) + packages.append(":" + package) + for group, suffix, artifact_name, configuration in [ + ("archive", "bindings", "oliphaunt-swift-" + descriptor["version"] + "-bindings.xcframework.zip", "apple-xcframework"), + ("checksums", "checksums", "oliphaunt-swift-" + descriptor["version"] + "-release-assets.sha256", "portable"), + ]: + apple_slice_filegroup(name = "release_asset_" + suffix, src = bindings_release_assets, output_group = group) + package = "shipping_" + suffix + shipping_package(name = package, owner = "@oliphaunt_metadata//:product_" + product, artifacts = [":release_asset_" + suffix], ecosystem = "github", package_name = artifact_name, configuration = configuration, role = "github-release-asset", suppliers = bindings_release_assets) + packages.append(":" + package) + compiled_exports = [] + for owner, producer in SWIFT_BINDINGS_COMPILE_OWNERS.items(): + compiled = [] + for slot in SWIFT_BINDINGS_COMPILE_SLOTS: + group = swift_bindings_compile_group(owner, slot) + native.filegroup(name = name + "_" + group, srcs = [bindings_release_assets], output_group = group) + supplier = name + "_" + owner + "_suppliers_" + slot.replace("-", "_") + swift_bindings_compiled_supplier(name = supplier, inputs = bindings_release_assets, owner = owner, configuration = slot) + package = "shipping_" + group + shipping_package(name = package, owner = "@oliphaunt_metadata//:product_" + producer, artifacts = [":" + name + "_" + group], + ecosystem = "internal", package_name = producer + "-swift-bindings", configuration = slot, role = "compiled-source", suppliers = ":" + supplier) + compiled.append(":" + package) + export = name + "_" + owner + "_compiled_shipping_export" + shipping_export(name = export, packages = compiled, + qualification = MOBILE_BINDINGS_COMPILE_QUALIFICATION[owner], + testonly = True) + compiled_exports.append(":" + export) + shipping_export(name = name + "_compiled_shipping_export", exports = compiled_exports, testonly = True) + source_checks = ["//src/native/sdks/swift:unit_test", "//src/native/sdks/swift:public_api_consumer_test", "//src/native/sdks/swift:ios_compile_test", "//src/native/sdks/swift:compiled_supplier_analysis_test"] + shipping_export( + name = "preparation_shipping_export", + packages = packages, + exports = [":" + name + "_compiled_shipping_export"], + qualification = source_checks, + testonly = True, + ) + shipping_export( + name = "shipping_export", + packages = packages, + exports = [":" + name + "_compiled_shipping_export"], + qualification = source_checks + ["//src/native/sdks/swift:installed_consumer_test"], + testonly = True, + ) diff --git a/build_defs/languages/swift/xcframework-envelope.mts b/build_defs/languages/swift/xcframework-envelope.mts new file mode 100644 index 000000000..a3fce0f3b --- /dev/null +++ b/build_defs/languages/swift/xcframework-envelope.mts @@ -0,0 +1,61 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { validateAppleXcframeworkAsset } from '../../../src/native/sdks/swift/tools/swift-xcframework-contract.mts'; +import { createDeterministicZip } from '../../../tools/packaging/archive-directory.mts'; +import { + extractPortableArchiveTree, + readPortableArchiveEntries, +} from '../../../tools/packaging/portable-archive.mts'; +import { stageReleaseNotices } from '../../../tools/packaging/release-notices.mts'; +import { stageMobileLegalSources } from '../mobile-legal.mts'; + +const FRAMEWORK = 'OliphauntNativeBindingsFFI.xcframework'; +const TARGETS = ['ios-arm64', 'ios-simulator-arm64', 'macos-arm64']; + +export async function packageBindingsXcframework( + input: string, + output: string, + sources: Record, +): Promise { + output = path.resolve(output); + mkdirSync(path.dirname(output), { recursive: true }); + const scratch = mkdtempSync(path.join(path.dirname(output), '.swift-bindings-')); + try { + const sourceRoot = path.join(scratch, 'sources'); + const contract = stageMobileLegalSources(sources, sourceRoot); + await validateAppleXcframeworkAsset(realpathSync(input), 'OliphauntNativeBindingsFFI'); + const framework = path.join(scratch, FRAMEWORK); + extractPortableArchiveTree(realpathSync(input), framework, FRAMEWORK); + for (const target of TARGETS) { + const directory = path.join(framework, 'licenses', target); + stageReleaseNotices(directory, { profile: 'source-sdk', sourceRoot }); + contract.stageRustDependencyLicenses(directory, target); + contract.assertRustDependencyLicensesInDirectory(directory, { target }); + } + const bytes = await createDeterministicZip(framework, { keepParent: true }); + writeFileSync(output, bytes, { mode: 0o644 }); + const entries = readPortableArchiveEntries(output, { format: 'zip' }); + for (const target of TARGETS) + contract.assertRustDependencyLicensesInEntries(entries, { + target, + prefix: `${FRAMEWORK}/licenses/${target}`, + label: output, + }); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + const [input, output, sources, checksums] = process.argv.slice(2); + assert.equal( + process.argv.length, + 6, + 'Expected intermediate archive, output, sources and checksum manifest', + ); + await packageBindingsXcframework(input, output, JSON.parse(readFileSync(sources, 'utf8'))); + const sha = createHash('sha256').update(readFileSync(output)).digest('hex'); + writeFileSync(checksums, `${sha} ./${path.basename(output)}\n`, { mode: 0o644 }); +} diff --git a/build_defs/languages/swift/xcframework-envelope.test.mts b/build_defs/languages/swift/xcframework-envelope.test.mts new file mode 100644 index 000000000..ac4017b4a --- /dev/null +++ b/build_defs/languages/swift/xcframework-envelope.test.mts @@ -0,0 +1,99 @@ +import { expect, test } from 'bun:test'; +import { + chmodSync, + copyFileSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + realpathSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { createMobileDependencyLicenseContract } from '../../../src/native/mobile-bindings/tools/dependency-license-contract.mts'; +import { createDeterministicZip } from '../../../tools/packaging/archive-directory.mts'; +import { readPortableArchiveEntries } from '../../../tools/packaging/portable-archive.mts'; +import { packageBindingsXcframework } from './xcframework-envelope.mts'; + +const OWNER = 'src/native/mobile-bindings'; +const inputRoot = process.env.TEST_SRCDIR + ? path.join(process.env.TEST_SRCDIR, process.env.TEST_WORKSPACE ?? '_main') + : process.cwd(); +function legalSources(root: string): Record { + const members = [ + 'LICENSE', + 'THIRD_PARTY_NOTICES.md', + 'Cargo.lock', + `${OWNER}/dependency-licenses.json`, + ]; + for (const name of readdirSync(path.join(inputRoot, OWNER, 'dependency-license-blobs'))) + members.push(`${OWNER}/dependency-license-blobs/${name}`); + return Object.fromEntries( + members.map((member) => { + const destination = path.join(root, member); + mkdirSync(path.dirname(destination), { recursive: true }); + copyFileSync(realpathSync(path.join(inputRoot, member)), destination); + chmodSync(destination, 0o644); + return [member, destination]; + }), + ); +} + +test('canonical FFI envelope reuses strict target license bytes and deterministic archives', async () => { + const scratch = mkdtempSync(path.join(tmpdir(), 'oliphaunt-swift-envelope-')); + try { + const legal = legalSources(path.join(scratch, 'legal-inputs')); + const framework = path.join(scratch, 'OliphauntNativeBindingsFFI.xcframework'); + mkdirSync(framework); + const slices = [ + ['macos-arm64', 'macos', ''], + ['ios-arm64', 'ios', ''], + ['ios-arm64-simulator', 'ios', 'simulator'], + ] as const; + writeFileSync( + path.join(framework, 'Info.plist'), + `AvailableLibraries${slices.map(([identifier, platform, variant]) => `LibraryIdentifier${identifier}LibraryPathfixture.aSupportedArchitecturesarm64SupportedPlatform${platform}${variant ? `SupportedPlatformVariant${variant}` : ''}`).join('')}`, + ); + for (const [identifier] of slices) { + mkdirSync(path.join(framework, identifier)); + writeFileSync(path.join(framework, identifier, 'fixture.a'), 'fixture construction only\n'); + } + const intermediate = path.join(scratch, 'intermediate.zip'); + writeFileSync(intermediate, await createDeterministicZip(framework, { keepParent: true })); + const first = path.join(scratch, 'first.zip'); + const second = path.join(scratch, 'second.zip'); + await packageBindingsXcframework(intermediate, path.relative(process.cwd(), first), legal); + await packageBindingsXcframework(intermediate, second, legal); + expect(readFileSync(first).equals(readFileSync(second))).toBeTrue(); + const entries = readPortableArchiveEntries(first, { format: 'zip' }); + // Runfiles inputs may be links; independent contract verification uses a + // physical source tree just as the declared packaging action does. + const sourceRoot = path.join(scratch, 'expected-sources'); + for (const [member, source] of Object.entries(legal)) { + const destination = path.join(sourceRoot, member); + mkdirSync(path.dirname(destination), { recursive: true }); + copyFileSync(realpathSync(source), destination); + } + const contract = createMobileDependencyLicenseContract(sourceRoot); + for (const target of ['ios-arm64', 'ios-simulator-arm64', 'macos-arm64']) + expect( + contract.assertRustDependencyLicensesInEntries(entries, { + target, + prefix: `OliphauntNativeBindingsFFI.xcframework/licenses/${target}`, + }).length, + ).toBeGreaterThan(0); + const unexpected = { ...legal, '../outside': legal.LICENSE }; + await expect( + packageBindingsXcframework(intermediate, path.join(scratch, 'bad.zip'), unexpected), + ).rejects.toThrow('Unexpected legal source'); + const missing = { ...legal }; + delete missing[`${OWNER}/dependency-licenses.json`]; + await expect( + packageBindingsXcframework(intermediate, path.join(scratch, 'missing.zip'), missing), + ).rejects.toThrow('Missing'); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +}); diff --git a/build_defs/languages/swift/xcframework.bzl b/build_defs/languages/swift/xcframework.bzl new file mode 100644 index 000000000..bd5c52186 --- /dev/null +++ b/build_defs/languages/swift/xcframework.bzl @@ -0,0 +1,126 @@ +"""Standard Apple XCFramework construction using the declared product profiles.""" + +load("@oliphaunt_toolchain_metadata//:apple-platforms.bzl", "APPLE_DEPLOYMENT_TARGETS") +load("@rules_apple//apple:apple.bzl", "apple_static_xcframework") +load("@oliphaunt_metadata//:metadata.bzl", "PRODUCTS") +load("//build_defs/apple:slices.bzl", "apple_slice_groups") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") +load("//build_defs/release:supplier.bzl", "ShippingSupplierInfo", "merge_shipping_suppliers") +load( + "//build_defs/languages:mobile-compiled-inputs.bzl", + _MOBILE_BINDINGS_COMPILE_OWNERS = "MOBILE_BINDINGS_COMPILE_OWNERS", + _SwiftCompiledInputsInfo = "MobileCompiledInputsInfo", + _compiled_inputs = "mobile_compiled_inputs", + _mobile_bindings_compile_group = "mobile_bindings_compile_group", + _mobile_bindings_compiled_supplier = "mobile_bindings_compiled_supplier", +) + +_MACOS_PROFILE = "@apple_support//platforms:macos_arm64_platform" + +BINDINGS_ENVELOPE_HELPERS = [ + Label("//build_defs/languages:mobile-legal.mts"), + Label("//src/native/mobile-bindings:tools/dependency-license-contract.mts"), + Label("//:tools/packaging/archive-directory.mts"), + Label("//:tools/packaging/portable-archive.mts"), + Label("//:tools/packaging/release-notices.mts"), + Label("//:tools/packaging/release-directory-safety.mts"), + Label("//:tools/packaging/rust-dependency-license-contract.mts"), + Label("//src/native/sdks/swift:tools/swift-xcframework-contract.mts"), +] + +def _package_platform_impl(settings, attr): + # Standard Apple split transitions consult this supported label setting. + # Preserve the SDK package's Mac deployment profile through that split. + return {_MACOS_PROFILE: str(Label("//build_defs/host:apple_package_macos_arm64"))} + +_package_platform = transition(implementation = _package_platform_impl, inputs = [], outputs = [_MACOS_PROFILE]) + +SWIFT_BINDINGS_COMPILE_SLOTS = ["macos-arm64", "ios-device", "ios-simulator", "host-generator"] +SWIFT_BINDINGS_COMPILE_OWNERS = _MOBILE_BINDINGS_COMPILE_OWNERS +swift_bindings_compile_group = _mobile_bindings_compile_group +swift_bindings_compiled_supplier = _mobile_bindings_compiled_supplier + +def _archive_impl(ctx): + archive = ctx.attr.archive[0] + compiled = archive[_SwiftCompiledInputsInfo] + expected = [swift_bindings_compile_group(owner, slot) for owner in SWIFT_BINDINGS_COMPILE_OWNERS for slot in SWIFT_BINDINGS_COMPILE_SLOTS] + if sorted(compiled.files) != sorted(expected) or sorted(compiled.upstream) != sorted(expected): + fail("Swift XCFramework must retain its complete original Rust compiler File inventory") + return [archive[DefaultInfo], compiled, merge_shipping_suppliers([compiled.current, compiled.registry]), OutputGroupInfo(**(apple_slice_groups([archive]) | {name: depset([file]) for name, file in compiled.files.items()}))] + +_product_archive = rule( + implementation = _archive_impl, + attrs = { + "archive": attr.label(mandatory = True, cfg = _package_platform, aspects = [_compiled_inputs]), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), + }, +) + +def bindings_xcframework(name, library, header): + """Build the canonical three Rust FFI slices; legal envelope is separate.""" + apple_static_xcframework( + name = name + "_archive", + bundle_name = "OliphauntNativeBindingsFFI", + deps = [library], + public_hdrs = [header], + umbrella_header = header, + ios = {"device": ["arm64"], "simulator": ["arm64"]}, + macos = ["arm64"], + minimum_os_versions = {"macos": APPLE_DEPLOYMENT_TARGETS["package_macos"], "ios": APPLE_DEPLOYMENT_TARGETS["ios"]}, + tags = ["no-remote"], + target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:aarch64"], + visibility = ["//visibility:private"], + ) + _product_archive(name = name, archive = ":" + name + "_archive", target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:aarch64"]) + +def _bindings_envelope_impl(ctx): + files = ctx.files.sources + source_paths = {} + for file in files: + if file.short_path in source_paths: + fail("duplicate FFI legal source: " + file.short_path) + source_paths[file.short_path] = file.path + specification = ctx.actions.declare_file(ctx.label.name + ".sources.json") + ctx.actions.write(specification, json.encode(source_paths)) + archive = ctx.actions.declare_file(ctx.attr.archive_name) + checksums = ctx.actions.declare_file(ctx.attr.checksum_name) + bun_file_action( + ctx, + entry_point = ctx.file._packager, + source_files = [ctx.file._packager] + ctx.files._helpers, + arguments = [ctx.file.intermediate.path, archive.path, specification.path, checksums.path], + inputs = depset([ctx.file.intermediate, ctx.file._packager, specification] + files + ctx.files._helpers), + outputs = [archive, checksums], + mnemonic = "OliphauntSwiftBindingsEnvelope", + use_default_shell_env = False, + ) + groups = apple_slice_groups([ctx.attr.intermediate]) | {"archive": depset([archive]), "checksums": depset([checksums])} + for owner in SWIFT_BINDINGS_COMPILE_OWNERS: + for slot in SWIFT_BINDINGS_COMPILE_SLOTS: + group = swift_bindings_compile_group(owner, slot) + groups[group] = getattr(ctx.attr.intermediate[OutputGroupInfo], group) + return [DefaultInfo(files = depset([archive, checksums])), OutputGroupInfo(**groups), ctx.attr.intermediate[ShippingSupplierInfo], ctx.attr.intermediate[_SwiftCompiledInputsInfo]] + +_bindings_envelope = rule( + implementation = _bindings_envelope_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = { + "intermediate": attr.label(mandatory = True, allow_single_file = [".zip"], providers = [ShippingSupplierInfo, OutputGroupInfo, _SwiftCompiledInputsInfo]), + "sources": attr.label_list(allow_files = True, mandatory = True), + "archive_name": attr.string(mandatory = True), + "checksum_name": attr.string(mandatory = True), + "_packager": attr.label(default = Label("//build_defs/languages/swift:xcframework-envelope.mts"), allow_single_file = True), + "_helpers": attr.label_list(default = BINDINGS_ENVELOPE_HELPERS, allow_files = True), + }, +) + +def bindings_envelope(name, intermediate): + version = PRODUCTS["oliphaunt-swift"]["version"] + _bindings_envelope( + name = name, + intermediate = intermediate, + sources = ["//src/native/mobile-bindings:license_inputs", "//:Cargo.lock", "//:LICENSE", "//:THIRD_PARTY_NOTICES.md"], + archive_name = "oliphaunt-swift-" + version + "-bindings.xcframework.zip", + checksum_name = "oliphaunt-swift-" + version + "-release-assets.sha256", + target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:aarch64"], + ) diff --git a/build_defs/languages/ts/BUILD.bazel b/build_defs/languages/ts/BUILD.bazel new file mode 100644 index 000000000..acbfeb401 --- /dev/null +++ b/build_defs/languages/ts/BUILD.bazel @@ -0,0 +1,27 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/foundation:bun.bzl", "bun_test") +load("@aspect_rules_js//npm:defs.bzl", "npm_link_package") +load("@javascript_consumer_packages//:roots.bzl", "CONSUMER_TOOLS") + +package(default_visibility = ["//visibility:public"]) + +# Extract the original integrity-checked archive through the public package API. +# The final regular modules live in tools/release, outside this package's link. +_PROTOBUFJS = CONSUMER_TOOLS["@oliphaunt/release-tools"]["protobufjs"] +npm_link_package( + name = "protobufjs_native_aquery_package", + src = "@javascript_consumer_packages//:" + _PROTOBUFJS, +) + +exports_files(["metadata.mts", "repositories.bzl", "defs.bzl", "publish-manifest.mts", "consumer-test.mts", "unit-tests.mts", "unit-tests.bzl"]) + +exports_files(["compiler-inputs.json"]) + +bun_test( + name = "metadata_test", + entry_point = "metadata.test.mts", + data = ["metadata.mts", "//:tools/packaging/portable-archive.mts", "testdata/ts-query-0.1.1.tgz", "//src/wasix/postgres-tools/ts/tests/installed:package.json", "//src/wasix/postgres-tools/ts/tests/installed:bun.lock"], + size = "small", +) + +source_quality_files() diff --git a/build_defs/languages/ts/compiler-inputs.json b/build_defs/languages/ts/compiler-inputs.json new file mode 100644 index 000000000..7a0a80fd8 --- /dev/null +++ b/build_defs/languages/ts/compiler-inputs.json @@ -0,0 +1,13 @@ +{ + "workspaces": { + "oliphaunt-example-browser-wasix": ["vite", "@electric-sql/pglite"], + "@oliphaunt/ts": ["@types/pg"], + "@oliphaunt/react-native": [ + "@react-native/typescript-config", + "react-native", + "react", + "@react-native/codegen" + ] + }, + "overrideTools": ["esbuild"] +} diff --git a/build_defs/languages/ts/consumer-test.mts b/build_defs/languages/ts/consumer-test.mts new file mode 100644 index 000000000..4ce9ad502 --- /dev/null +++ b/build_defs/languages/ts/consumer-test.mts @@ -0,0 +1,114 @@ +import assert from 'node:assert/strict'; +import { cp, mkdir, readFile, symlink, writeFile } from 'node:fs/promises'; +import { dirname, join } from 'node:path'; + +const [archive, query, consumerSource, node, compiler, acquisitionFile, typesFile] = + Bun.argv.slice(2); +assert(archive && query && consumerSource && node && compiler && acquisitionFile && typesFile); +assert(process.env.TEST_TMPDIR && process.env.OLIPHAUNT_BAZEL_RUNFILES); +const directory = join(process.env.TEST_TMPDIR, 'native-sdk-consumer'); + +async function extract(file: string, destination: string, publicEnvelope = true) { + const entries = await new Bun.Archive(await readFile(file)).files(); + assert(entries.size > 0); + const prefix = publicEnvelope ? 'package/' : `${entries.keys().next().value?.split('/')[0]}/`; + for (const [name, content] of entries) { + assert( + name.startsWith(prefix) && !name.split('/').some((part) => part === '..' || part === '.'), + ); + const target = join(destination, name.slice(prefix.length)); + await mkdir(dirname(target), { recursive: true }); + await writeFile(target, await content.bytes()); + } +} + +await extract(archive, join(directory, 'node_modules/@oliphaunt/ts')); +await extract(query, join(directory, 'node_modules/@oliphaunt/ts-query')); +const manifest = JSON.parse( + await readFile(join(directory, 'node_modules/@oliphaunt/ts/package.json'), 'utf8'), +); +assert.equal(manifest.type, 'module'); +assert.equal(manifest.scripts, undefined); +assert.equal(manifest.devDependencies, undefined); +assert( + Object.values(manifest.optionalDependencies).every((version) => + /^\d+\.\d+\.\d+$/.test(String(version)), + ), +); + +const packages = JSON.parse(await readFile(acquisitionFile, 'utf8')); +const specification: { packages: Record; types: Record } = + JSON.parse(await readFile(typesFile, 'utf8')); +const stores: Record = {}; +for (const [id, source] of Object.entries(specification.packages)) { + assert(packages[id], `undeclared type package ${id}`); + const destination = join(directory, '.types', id, 'node_modules', packages[id].package); + stores[id] = destination; + const input = join(process.env.OLIPHAUNT_BAZEL_RUNFILES, source); + if (input.endsWith('.tgz')) await extract(input, destination, false); + else { + await mkdir(dirname(destination), { recursive: true }); + await cp(input, destination, { recursive: true }); + } +} +for (const [id, row] of Object.entries(packages) as [ + string, + { package: string; dependencies: Record }, +][]) { + assert(stores[id], `missing type package ${id}`); + for (const [name, target] of Object.entries(row.dependencies)) { + const link = join(stores[id], 'node_modules', name); + await mkdir(dirname(link), { recursive: true }); + await symlink(stores[target], link, 'dir'); + } +} +for (const [name, id] of Object.entries(specification.types)) { + assert(stores[id], `missing direct SDK type package ${name}`); + const link = join(directory, 'node_modules', name); + await mkdir(dirname(link), { recursive: true }); + await symlink(stores[id], link, 'dir'); +} + +const consumer = join(directory, 'consumer.mts'); +const original = await readFile(consumerSource, 'utf8'); +await writeFile(consumer, original); +const environment = { ...process.env, NODE_PATH: '', NODE_OPTIONS: '' }; +const types = Bun.spawnSync( + [ + node, + join(compiler, 'bin/tsc'), + '--module', + 'NodeNext', + '--moduleResolution', + 'NodeNext', + '--target', + 'ES2022', + '--lib', + 'ES2023,DOM', + '--types', + 'node,bun', + '--strict', + '--skipLibCheck', + '--noEmit', + consumer, + ], + { + cwd: directory, + env: environment, + stdout: 'inherit', + stderr: 'inherit', + }, +); +assert.equal(types.exitCode, 0, 'packed SDK public type consumer failed'); +const executable = join(directory, 'consumer.mjs'); +await writeFile( + executable, + new Bun.Transpiler({ loader: 'ts', target: 'node' }).transformSync(original), +); +const runtime = Bun.spawnSync([node, executable], { + cwd: directory, + env: environment, + stdout: 'inherit', + stderr: 'inherit', +}); +assert.equal(runtime.exitCode, 0, 'packed SDK Node consumer failed'); diff --git a/build_defs/languages/ts/defs.bzl b/build_defs/languages/ts/defs.bzl new file mode 100644 index 000000000..cbd66aa1e --- /dev/null +++ b/build_defs/languages/ts/defs.bzl @@ -0,0 +1,224 @@ +"""Native SDK manifest projection and consumers of actual npm envelopes.""" + +load("@aspect_rules_js//npm:providers.bzl", "NpmPackageInfo") +load("@aspect_rules_js//npm:defs.bzl", "npm_link_package") +load("//build_defs/release:shipping.bzl", "ShippingInfo") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_file_action", "bun_test_entrypoint", "bun_test_entrypoint_args") + +_NODE_TOOLCHAIN = "@rules_nodejs//nodejs:toolchain_type" + +def _publish_files_impl(ctx): + outputs = [ctx.actions.declare_file(ctx.label.name + "/" + name) for name in ["package.json", "LICENSE", "THIRD_PARTY_NOTICES.md"]] + bun_file_action( + ctx, + entry_point = ctx.file._writer, + arguments = [ctx.attr.profile, ctx.file.manifest.path, outputs[0].dirname], + inputs = [ctx.file.manifest, ctx.file._writer, ctx.file.profile_helper] + ctx.files._helpers, + source_files = [ctx.file._writer, ctx.file.profile_helper] + ctx.files._helpers, + outputs = outputs, + mnemonic = "SourceSdkManifest", + ) + return [DefaultInfo(files = depset(outputs)), OutputGroupInfo(manifest = depset([outputs[0]]), license = depset([outputs[1]]), notices = depset([outputs[2]]))] + +_source_sdk_publish_files = rule( + implementation = _publish_files_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = { + "manifest": attr.label(mandatory = True, allow_single_file = [".json"]), + "profile": attr.string(default = "js", values = ["js", "wasix-ts", "wasix-tools"]), + "_writer": attr.label(default = "//build_defs/languages/ts:publish-manifest.mts", allow_single_file = True), + "profile_helper": attr.label(mandatory = True, allow_single_file = True), + "_helpers": attr.label_list(default = [ + "//:LICENSE", + "//:THIRD_PARTY_NOTICES.md", + "//:tools/packaging/release-notices.mts", + "//:tools/packaging/release-directory-safety.mts", + "//:tools/packaging/portable-archive.mts", + ], allow_files = True), + }, +) + +def source_sdk_publish_files(name, manifest, profile = "js", **kwargs): + _source_sdk_publish_files( + name = name, + manifest = manifest, + profile = profile, + profile_helper = { + "js": "//:tools/packaging/source-only-sdk-package.mts", + "wasix-ts": "//src/wasix/sdks/ts:tools/package.mts", + "wasix-tools": "//src/wasix/postgres-tools/ts:tools/package.mts", + }[profile], + **kwargs + ) + +def _archive_package_impl(ctx): + return [ + DefaultInfo(files = depset([ctx.file.archive])), + NpmPackageInfo(package = ctx.attr.package_name, version = ctx.attr.version, src = ctx.file.archive, npm_package_store_infos = depset()), + ] + +npm_archive_package = rule( + implementation = _archive_package_impl, + attrs = { + "archive": attr.label(mandatory = True, allow_single_file = [".tgz"]), + "package_name": attr.string(mandatory = True), + "version": attr.string(mandatory = True), + }, +) + +def _dependency_package_impl(ctx): + if ctx.attr.source == "unverified": + fail("Final npm dependency %s is unresolved: %s" % (ctx.attr.package_name, ctx.attr.reason)) + if ctx.attr.current: + identity = ctx.attr.current[ShippingInfo] + if identity.ecosystem != "npm" or identity.name != ctx.attr.package_name or identity.version != ctx.attr.version or (ctx.attr.owner and identity.product != ctx.attr.owner): + fail("Current npm dependency differs from its declared source owner/name/version") + files = identity.files.to_list() + if len(files) != 1 or files[0].is_directory or not files[0].basename.endswith(".tgz"): + fail("Current npm dependency needs one actual shipping archive File") + archive = files[0] + elif ctx.attr.registry: + identity = ctx.attr.registry[NpmPackageInfo] + if identity.package != ctx.attr.package_name or identity.version != ctx.attr.version: + fail("Registry npm dependency name/version differs") + archive = identity.src + else: + archive = ctx.file.archive + if not archive: + fail("Final npm dependency needs its actual captured archive File") + output = ctx.actions.declare_file(ctx.label.name + "/dependency.tgz") + arguments = ["--verify-dependency", archive.path, output.path, ctx.attr.package_name, ctx.attr.version, str(ctx.attr.size), ctx.attr.sha256] + sources = [ctx.file._validator, ctx.file._archive_reader] + bun_file_action(ctx, entry_point = ctx.file._validator, arguments = arguments, inputs = [archive] + sources, source_files = sources, outputs = [output], mnemonic = "VerifyNpmDependency") + return [DefaultInfo(files = depset([output])), NpmPackageInfo(package = ctx.attr.package_name, version = ctx.attr.version, src = output, npm_package_store_infos = depset())] + +_dependency_package = rule( + implementation = _dependency_package_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = { + "source": attr.string(mandatory = True), + "package_name": attr.string(mandatory = True), + "version": attr.string(default = ""), + "owner": attr.string(default = ""), + "reason": attr.string(default = ""), + "size": attr.int(default = -1), + "sha256": attr.string(default = ""), + "archive": attr.label(allow_single_file = [".tgz"]), + "registry": attr.label(providers = [NpmPackageInfo]), + "current": attr.label(providers = [ShippingInfo]), + "_validator": attr.label(default = "//build_defs/languages/ts:metadata.mts", allow_single_file = True), + "_archive_reader": attr.label(default = "//:tools/packaging/portable-archive.mts", allow_single_file = True), + }, +) + +def workspace_dependency_package(name, workspace, dependency, current, **kwargs): + """Use the declared completed/selected source choice for compiler and installed consumers.""" + choice = workspace["dependencyInputs"][dependency] + _dependency_package( + name = name, + source = choice["source"], + package_name = dependency, + version = choice.get("version", ""), + owner = choice.get("owner", ""), + reason = choice.get("reason", ""), + size = choice.get("size", -1), + sha256 = choice.get("sha256", ""), + archive = choice.get("archive"), + registry = "@javascript_packages//:" + choice["package"] if choice["source"] == "registry" else None, + current = current if choice["source"] == "workspace" else None, + **kwargs + ) + +def workspace_dependency_link(name, package, workspace, dependency, **kwargs): + choice = workspace["dependencyInputs"][dependency] + npm_link_package(name = name, src = package, deps = {":_javascript_" + key: child for child, key in choice.get("packages", {}).items()}, **kwargs) + +def _runfile(ctx, file): + return file.short_path[3:] if file.short_path.startswith("../") else ctx.workspace_name + "/" + file.short_path + +def _consumer_impl(ctx): + node = ctx.toolchains[_NODE_TOOLCHAIN].nodeinfo.node + if not node: + fail("SDK consumers require the pinned Node toolchain") + type_files = [] + packages = {} + for key, target in ctx.attr.type_packages.items(): + source = key[NpmPackageInfo].src + type_files.append(source) + packages[target] = _runfile(ctx, source) + specification = ctx.actions.declare_file(ctx.label.name + ".types.json") + ctx.actions.write(specification, json.encode({"packages": packages, "types": ctx.attr.types})) + files = [ctx.file.archive, ctx.file.query, ctx.file.consumer, ctx.file._runner, ctx.file.acquisition, ctx.file.typescript, specification, node] + type_files + arguments = [ctx.file.archive, ctx.file.query, ctx.file.consumer, node, ctx.file.typescript, ctx.file.acquisition, specification] + return bun_test_entrypoint(ctx, ctx.file._runner, arguments, files, source_files = [ctx.file._runner], runfiles_environment = ["OLIPHAUNT_BAZEL_RUNFILES"]) + +_source_sdk_consumer_test = rule( + implementation = _consumer_impl, + test = True, + toolchains = BUN_SOURCE_TOOLCHAINS + [_NODE_TOOLCHAIN], + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "archive": attr.label(mandatory = True, allow_single_file = [".tgz"]), + "query": attr.label(mandatory = True, allow_single_file = [".tgz"]), + "consumer": attr.label(mandatory = True, allow_single_file = True), + "typescript": attr.label(default = "@npm_typescript//:node_modules/typescript/dir", allow_single_file = True), + "acquisition": attr.label(default = "@javascript_packages//:acquisition.json", allow_single_file = True), + "type_packages": attr.label_keyed_string_dict(providers = [NpmPackageInfo]), + "types": attr.string_dict(mandatory = True), + "_runner": attr.label(default = "//build_defs/languages/ts:consumer-test.mts", allow_single_file = True), + }), +) + +def source_sdk_consumer_test(name, args = [], **kwargs): + _source_sdk_consumer_test(name = name, args = bun_test_entrypoint_args(name) + args, **kwargs) + +def _installed_npm_consumer_impl(ctx): + node = ctx.toolchains[_NODE_TOOLCHAIN].nodeinfo.node + if not node: + fail("Installed npm consumers require the pinned Node toolchain") + packages = {} + package_files = [] + for target, identity in ctx.attr.packages.items(): + source = target[NpmPackageInfo].src + packages[identity] = _runfile(ctx, source) + package_files.append(source) + archives = {} + for target, name in ctx.attr.archives.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1: + fail("Installed npm archive must have exactly one producer file: " + str(target.label)) + archives[name] = _runfile(ctx, files[0]) + package_files += files + specification = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(specification, json.encode({"packages": packages, "archives": archives, "roots": ctx.attr.roots, "consumer": _runfile(ctx, ctx.file.consumer), "helpers": [_runfile(ctx, file) for file in ctx.files.helpers], "acquisitions": [_runfile(ctx, file) for file in ctx.files.acquisitions]})) + files = package_files + [specification, node, ctx.file.typescript, ctx.file.runner, ctx.file.consumer] + ctx.files.helpers + ctx.files.acquisitions + return bun_test_entrypoint(ctx, ctx.file.runner, [specification, node, ctx.file.typescript], files, source_files = [ctx.file.runner, ctx.file.consumer] + ctx.files.helpers, runfiles_environment = ["OLIPHAUNT_BAZEL_RUNFILES"]) + +_installed_npm_consumer_test = rule( + implementation = _installed_npm_consumer_impl, + test = True, + toolchains = BUN_SOURCE_TOOLCHAINS + [_NODE_TOOLCHAIN], + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "packages": attr.label_keyed_string_dict(providers = [NpmPackageInfo]), + "archives": attr.label_keyed_string_dict(allow_files = True), + "roots": attr.string_dict(mandatory = True), + "acquisitions": attr.label_list(allow_files = [".json"], mandatory = True), + "runner": attr.label(allow_single_file = True, mandatory = True), + "consumer": attr.label(allow_single_file = True, mandatory = True), + "helpers": attr.label_list(allow_files = True), + "typescript": attr.label(default = "@npm_typescript//:node_modules/typescript/dir", allow_single_file = True), + }), +) + +def installed_npm_consumer_test(name, args = [], **kwargs): + _installed_npm_consumer_test(name = name, args = bun_test_entrypoint_args(name) + args, **kwargs) + +def npm_dependency_closure(packages, roots): + selected = {identity: True for identity in roots} + for _ in range(len(packages) + 1): + previous = len(selected) + for identity in selected.keys(): + for dependency in packages[identity]["dependencies"].values(): + selected[dependency] = True + if len(selected) == previous: + return selected.keys() + fail("npm dependency closure exceeds its declared packages") diff --git a/build_defs/languages/ts/metadata.mts b/build_defs/languages/ts/metadata.mts new file mode 100644 index 000000000..93adf82ff --- /dev/null +++ b/build_defs/languages/ts/metadata.mts @@ -0,0 +1,722 @@ +import { createHash } from 'node:crypto'; +import { copyFileSync, existsSync, readFileSync, realpathSync, statSync } from 'node:fs'; +import { readPortableArchiveEntries } from '../../../tools/packaging/portable-archive.mts'; +import { dirname, relative } from 'node:path'; +import { isDeepStrictEqual } from 'node:util'; + +type Manifest = { + name: string; + version: string; + type?: string; + dependencies?: Record; + devDependencies?: Record; + optionalDependencies?: Record; + peerDependencies?: Record; +}; +type Lock = { + lockfileVersion: number; + configVersion: number; + catalog?: Record; + overrides?: Record; + workspaces: Record; + packages: Record< + string, + [ + string, + string, + { + dependencies?: Record; + optionalDependencies?: Record; + peerDependencies?: Record; + optionalPeers?: string[]; + bin?: string | Record; + os?: string; + cpu?: string; + }, + string, + ] + >; +}; +type SupplierArchive = { + publication: { product: string; version: string; [key: string]: unknown }; + artifact: string; + file: { path: string; size: number; sha256: string }; + /** Generated repository alias for this same captured File. */ + archive: string; +}; + +/** Check the actual npm File; completion/origin authentication remains the controller's job. */ +export function validateJavascriptDependencyArchive( + file: string, + name: string, + version: string, + identity?: { size: number; sha256: string }, +) { + const source = realpathSync(file); + const before = statSync(source); + if (!before.isFile() || (identity && before.size !== identity.size)) + throw new Error(`JavaScript dependency ${name} File size differs`); + if (before.size > 512 * 1024 * 1024) + throw new Error('JavaScript dependency archive exceeds 512 MiB'); + if ( + identity && + createHash('sha256').update(readFileSync(source)).digest('hex') !== identity.sha256 + ) + throw new Error(`JavaScript dependency ${name} File digest differs`); + const packed = readPortableArchiveEntries(source).get('package/package.json'); + if (!packed?.isFile || packed.isSymbolicLink) + throw new Error(`JavaScript dependency ${name} has no packed manifest`); + const manifest = JSON.parse(packed.data().toString('utf8')); + if (manifest.name !== name || manifest.version !== version) + throw new Error(`JavaScript dependency ${name} packed identity differs`); + const after = statSync(source); + if ( + before.ino !== after.ino || + before.size !== after.size || + before.mtimeMs !== after.mtimeMs || + before.ctimeMs !== after.ctimeMs + ) + throw new Error(`JavaScript dependency ${name} File changed during capture`); + return manifest as Manifest; +} + +type CompilerInputs = { + workspaces?: Record; + overrideTools?: string[]; +}; + +/** Import exact compiler, type, and external runtime closures from the conventional lock. */ +export function importJavascriptMetadata( + root: { workspaces: { catalog?: Record }; overrides?: Record }, + lock: Lock, + manifests: Record, + consumerTools: Record = {}, + compilerInputs: CompilerInputs = {}, + dependencyManifests: Record = {}, + executionWorkspaces: string[] = [], + graphWorkspaces: string[] = [], + { + supplierArchives = [], + selectedProducts = [], + sourceOwners = {}, + }: { + supplierArchives?: SupplierArchive[]; + selectedProducts?: string[]; + sourceOwners?: Record; + } = {}, +) { + if (lock.lockfileVersion !== 2 || lock.configVersion !== 1) + throw new Error('Unsupported Bun lockfile schema'); + const packages: Record< + string, + { + package: string; + version: string; + integrity: string; + dependencies: Record; + } + > = {}; + const consumerPackages: typeof packages = {}; + const compilerPackages: typeof packages & Record = {}; + const consumerRoots: Record> = {}; + const consumerBins: Record>> = {}; + const compilerRoots: typeof consumerRoots = {}; + const compilerToolRoots: Record = {}; + const ids = new Map(); + const visiting = new Set(); + const resolutionKey = (name: string, parent: string) => { + for ( + let context = parent; + context; + context = context.replace(/(?:^|\/)(?:@[^/]+\/)?[^/]+$/u, '') + ) + if (Object.hasOwn(lock.packages, `${context}/${name}`)) return `${context}/${name}`; + return name; + }; + const selectedManifests = { ...manifests, ...dependencyManifests }; + const lockedPackage = ( + name: string, + parent: string, + requirement: string, + allowOverride = false, + ) => { + const override = root.overrides?.[name]; + if (override) { + if (!allowOverride) throw new Error(`Unsupported JavaScript override for ${name}`); + if (lock.overrides?.[name] !== override || !/^\d+\.\d+\.\d+$/.test(override)) + throw new Error(`bun.lock has a stale or unsupported JavaScript override for ${name}`); + requirement = override; + } + const key = resolutionKey(name, parent); + const entry = lock.packages[key]; + if ( + !entry?.[0].startsWith(`${name}@`) || + entry[1] !== '' || + !/^sha512-[A-Za-z0-9+/]+=*$/.test(entry[3] ?? '') + ) + throw new Error(`Missing integrity-bearing lock entry for ${key}`); + const version = entry[0].slice(name.length + 1); + if (!Bun.semver.satisfies(version, requirement)) + throw new Error(`Locked ${key}@${version} does not satisfy ${requirement}`); + return { key, entry, version }; + }; + const consumerSelection = { ...consumerTools }; + const execution = new Set(executionWorkspaces); + const graphs = new Set(graphWorkspaces); + if ( + graphs.size !== graphWorkspaces.length || + graphWorkspaces.some((workspace) => !execution.has(workspace)) + ) + throw new Error('Consumer graph workspace requires one selected execution workspace'); + if (execution.size !== executionWorkspaces.length) + throw new Error('Duplicate execution workspace selection'); + const catalogRequirement = (name: string, requirement: string) => { + if (requirement !== 'catalog:') return requirement; + const range = root.workspaces.catalog?.[name]; + if (!range || lock.catalog?.[name] !== range) + throw new Error(`bun.lock has a stale catalog declaration for ${name}`); + return range; + }; + for (const workspace of executionWorkspaces) { + const member = Object.entries(selectedManifests).find( + ([, manifest]) => manifest.name === workspace, + ); + if (!member || Object.hasOwn(consumerSelection, workspace)) + throw new Error( + `Execution workspace requires one independent conventional selection ${workspace}`, + ); + consumerSelection[workspace] = Object.keys({ + ...member[1].dependencies, + ...member[1].devDependencies, + }) + .filter( + (name) => + !graphs.has(workspace) || + !Object.values(lock.workspaces).some((source) => source.name === name) || + /^sha512-[A-Za-z0-9+/]+=*$/.test( + lock.packages[resolutionKey(name, workspace)]?.[3] ?? '', + ), + ) + .sort(); + } + const onConsumerPlatform = (entry: Lock['packages'][string] | undefined) => + Boolean( + entry?.[2] && + (!entry[2].os || entry[2].os === 'linux') && + (!entry[2].cpu || entry[2].cpu === 'x64'), + ); + const consumerProvided = new Map>(); + for (const workspace of Object.keys(consumerSelection)) { + const member = Object.entries(selectedManifests).find( + ([, manifest]) => manifest.name === workspace, + ); + if (!member) throw new Error(`Missing conventional consumer workspace ${workspace}`); + const [path, manifest] = member; + const provided = new Set(); + const visit = (name: string, parent: string, range: string, optional = false) => { + const key = resolutionKey(name, parent); + const entry = lock.packages[key]; + if (!entry?.[2] || !onConsumerPlatform(entry)) { + if (optional) return; + throw new Error(`Missing Linux x64 consumer tool dependency ${parent} -> ${name}`); + } + lockedPackage(name, parent, range, true); + if (provided.has(key)) return; + provided.add(key); + for (const [dependency, requirement] of Object.entries({ + ...entry[2].dependencies, + ...entry[2].optionalDependencies, + ...Object.fromEntries( + Object.entries(entry[2].peerDependencies ?? {}).filter( + ([name]) => !entry[2].optionalPeers?.includes(name), + ), + ), + })) + visit( + dependency, + key, + requirement, + Object.hasOwn(entry[2].optionalDependencies ?? {}, dependency), + ); + }; + // Optional peers are supplied by this workspace, not unrelated global lock entries. + for (const field of ['dependencies', 'devDependencies'] as const) + for (const name of Object.keys({ ...manifest[field], ...lock.workspaces[path]?.[field] })) { + const requirement = manifest[field]?.[name]; + if (!requirement || lock.workspaces[path]?.[field]?.[name] !== requirement) + throw new Error( + `bun.lock has a stale consumer ${consumerSelection[workspace].includes(name) ? 'tool' : 'provider'} declaration ${workspace}/${name}`, + ); + const range = catalogRequirement(name, requirement); + const source = Object.values(lock.workspaces).find((row) => row.name === name); + if ( + source && + !/^sha512-[A-Za-z0-9+/]+=*$/.test( + lock.packages[resolutionKey(name, workspace)]?.[3] ?? '', + ) + ) + continue; + visit(name, workspace, range); + } + consumerProvided.set(workspace, provided); + } + const record = ( + name: string, + parent: string, + requirement: string, + consumer = false, + compiler = false, + consumerWorkspace = '', + ): string => { + const { key, entry, version } = lockedPackage(name, parent, requirement, consumer || compiler); + if (consumer && !onConsumerPlatform(entry)) + throw new Error(`Consumer tool ${key} does not support Linux x64`); + const identity = `${consumer ? `consumer:${consumerWorkspace}:` : compiler ? 'compiler:' : ''}${key}`; + const result = consumer ? consumerPackages : compiler ? compilerPackages : packages; + const existing = ids.get(identity); + if (existing) return existing; + if (visiting.has(identity)) throw new Error(`Cycle in JavaScript type dependencies at ${key}`); + const context = consumer && graphs.has(consumerWorkspace) ? `/${consumerWorkspace}/${key}` : ''; + const id = `p_${createHash('sha256').update(`${name}@${version}${context}`).digest('hex').slice(0, 16)}`; + if (compiler || (consumer && graphs.has(consumerWorkspace))) ids.set(identity, id); + visiting.add(identity); + const dependencies: Record = {}; + const requirements = consumer + ? { + ...entry[2].peerDependencies, + ...entry[2].dependencies, + ...entry[2].optionalDependencies, + } + : compiler + ? { + ...entry[2].dependencies, + ...entry[2].optionalDependencies, + ...Object.fromEntries( + Object.entries(entry[2].peerDependencies ?? {}).filter(([name]) => + name.startsWith('@types/'), + ), + ), + } + : (entry[2].dependencies ?? {}); + for (const [dependency, range] of Object.entries(requirements)) { + if (consumer) { + const optionalPeer = + entry[2].optionalPeers?.includes(dependency) && + !Object.hasOwn(entry[2].dependencies ?? {}, dependency) && + !Object.hasOwn(entry[2].optionalDependencies ?? {}, dependency); + const optional = + Object.hasOwn(entry[2].optionalDependencies ?? {}, dependency) || optionalPeer; + const child = lock.packages[resolutionKey(dependency, key)]; + if ( + optionalPeer && + (!consumerProvided.get(consumerWorkspace)?.has(resolutionKey(dependency, key)) || + !child || + !Bun.semver.satisfies( + child[0].slice(dependency.length + 1), + root.overrides?.[dependency] ?? range, + )) + ) + continue; + if (!onConsumerPlatform(child)) { + if (optional) continue; + throw new Error(`Missing Linux x64 consumer tool dependency ${key} -> ${dependency}`); + } + } + dependencies[dependency] = record( + dependency, + key, + range, + consumer, + compiler, + consumerWorkspace, + ); + } + const resolved = { + package: name, + version, + integrity: entry[3], + dependencies, + ...(compiler && entry[2].os ? { os: entry[2].os } : {}), + ...(compiler && entry[2].cpu ? { cpu: entry[2].cpu } : {}), + }; + if (result[id] && !isDeepStrictEqual(result[id], resolved)) + throw new Error(`Conflicting acquisition closure for ${name}@${version}`); + result[id] = resolved; + ids.set(identity, id); + visiting.delete(identity); + return id; + }; + const workspaces: Record< + string, + { + name: string; + version: string; + type: string; + dependencies: Record; + types: Record; + packages?: Record; + dependencyInputs?: Record>; + } + > = {}; + for (const path of Object.keys(dependencyManifests)) + if (Object.hasOwn(manifests, path)) + throw new Error( + `JavaScript workspace ${path} is selected as both compiler and dependency input`, + ); + let typescript: { package: string; version: string; integrity: string } | undefined; + for (const [path, manifest] of Object.entries(selectedManifests).sort(([a], [b]) => + a.localeCompare(b), + )) { + const workspace = lock.workspaces[path]; + if (workspace?.name !== manifest.name || workspace.version !== manifest.version) + throw new Error(`bun.lock has a stale workspace identity for ${path}`); + const types: Record = {}; + for (const name of Object.hasOwn(manifests, path) + ? [ + 'typescript', + ...Object.keys(manifest.devDependencies ?? {}).filter((name) => + name.startsWith('@types/'), + ), + ] + : []) { + let requirement = manifest.devDependencies?.[name]; + if (workspace.devDependencies?.[name] !== requirement || !requirement) + throw new Error(`bun.lock has a stale workspace declaration for ${path}/${name}`); + requirement = catalogRequirement(name, requirement); + // Test-only types are not compiler inputs unless selected by tsconfig's types contract. + if (!['typescript', '@types/node', '@types/bun'].includes(name)) continue; + const id = record(name, manifest.name, requirement); + if (name === 'typescript') { + const { package: packageName, version, integrity } = packages[id]; + const compiler = { package: packageName, version, integrity }; + if (typescript && JSON.stringify(typescript) !== JSON.stringify(compiler)) + throw new Error('Selected JavaScript workspaces require different TypeScript compilers'); + typescript = compiler; + } else types[name] = id; + } + const dependencies = manifest.dependencies ?? {}; + const runtimePackages: Record = {}; + const dependencyInputs: Record> = {}; + for (const [name, requirement] of Object.hasOwn(manifests, path) + ? Object.entries(dependencies) + : []) { + if (workspace.dependencies?.[name] !== requirement) + throw new Error(`bun.lock has a stale workspace dependency for ${path}/${name}`); + const target = Object.entries(selectedManifests).find(([, row]) => row.name === name); + const range = requirement.startsWith('workspace:') + ? requirement.slice('workspace:'.length) + : requirement; + const current = + target && Bun.semver.satisfies(target[1].version, ['^', '~'].includes(range) ? '*' : range); + const owner = target && sourceOwners[target[0]]; + const owns = Boolean(owner?.registry_packages.includes(`npm:${name}`)); + const selected = Boolean(owns && selectedProducts.includes(owner!.id)); + if (current && (requirement.startsWith('workspace:') || selected)) { + dependencyInputs[name] = { + source: 'workspace', + workspace: target[0], + version: target[1].version, + ...(owns ? { owner: owner!.id } : {}), + }; + } else if (requirement.startsWith('workspace:')) { + throw new Error( + `Native JavaScript dependency ${name} must match its conventional workspace version`, + ); + } else { + const captured = supplierArchives.filter( + (row) => + row.artifact === `npm:${name}` && + Bun.semver.satisfies(row.publication.version, range) && + (!owns || row.publication.product === owner!.id), + ); + if (captured.length > 1) + throw new Error(`Ambiguous completed JavaScript dependency ${name}`); + if (captured.length) { + const row = captured[0]; + if (!/^@[A-Za-z0-9_.+-]+\/\/:/.test(row.archive)) + throw new Error( + `Completed JavaScript dependency ${name} needs its captured File alias`, + ); + const packageManifest = validateJavascriptDependencyArchive( + row.file.path, + name, + row.publication.version, + row.file, + ); + if ( + Object.keys(packageManifest.optionalDependencies ?? {}).length || + Object.keys(packageManifest.peerDependencies ?? {}).length + ) + throw new Error( + `Completed JavaScript dependency ${name} requires an explicit optional/peer closure`, + ); + const children: Record = {}; + for (const [child, childRequirement] of Object.entries( + packageManifest.dependencies ?? {}, + )) + children[child] = record( + child, + resolutionKey(name, manifest.name), + childRequirement as string, + ); + dependencyInputs[name] = { + source: 'completed', + archive: row.archive, + version: packageManifest.version, + publication: row.publication, + artifact: row.artifact, + size: row.file.size, + sha256: row.file.sha256, + packages: children, + }; + } else { + const key = resolutionKey(name, manifest.name); + const entry = lock.packages[key]; + if ( + entry?.[0].startsWith(`${name}@`) && + entry[1] === '' && + /^sha512-[A-Za-z0-9+/]+=*$/.test(entry[3] ?? '') + ) { + const id = record(name, manifest.name, requirement); + if (!target) runtimePackages[name] = id; + dependencyInputs[name] = { + source: 'registry', + package: id, + version: packages[id].version, + packages: packages[id].dependencies, + }; + } else if (target || Object.values(lock.workspaces).some((row) => row.name === name)) { + dependencyInputs[name] = { + source: 'unverified', + requirement, + reason: 'missing completed archive or selected source owner', + }; + } else { + const id = record(name, manifest.name, requirement); + if (!target) runtimePackages[name] = id; + dependencyInputs[name] = { + source: 'registry', + package: id, + version: packages[id].version, + packages: packages[id].dependencies, + }; + } + } + } + } + if (workspaces[manifest.name]) + throw new Error(`Duplicate JavaScript workspace ${manifest.name}`); + workspaces[manifest.name] = { + name: manifest.name, + version: manifest.version, + type: manifest.type ?? 'commonjs', + dependencies, + types, + ...(Object.keys(dependencyInputs).length ? { dependencyInputs } : {}), + }; + if (Object.keys(runtimePackages).length) workspaces[manifest.name].packages = runtimePackages; + } + if (!typescript) throw new Error('Selected workspaces have no TypeScript compiler'); + // The compiler is acquired by aspect_rules_ts from the same lock-derived facts. + for (const id of Object.keys(packages)) + if (packages[id].package === 'typescript') delete packages[id]; + for (const [workspace, tools] of Object.entries(consumerSelection)) { + const member = Object.entries(selectedManifests).find( + ([, manifest]) => manifest.name === workspace, + ); + if (!member || !tools.length || new Set(tools).size !== tools.length) + throw new Error(`Consumer tools require one selected conventional workspace ${workspace}`); + const [path, manifest] = member; + consumerRoots[workspace] = {}; + consumerBins[workspace] = {}; + for (const name of tools) { + const field = manifest.devDependencies?.[name] ? 'devDependencies' : 'dependencies'; + let requirement = manifest[field]?.[name]; + if (!requirement || lock.workspaces[path][field]?.[name] !== requirement) + throw new Error(`bun.lock has a stale consumer tool declaration ${workspace}/${name}`); + requirement = catalogRequirement(name, requirement); + consumerRoots[workspace][name] = record(name, workspace, requirement, true, false, workspace); + const bin = lock.packages[resolutionKey(name, workspace)][2].bin; + if (bin) { + const bins = + typeof bin === 'string' ? { [name.slice(name.lastIndexOf('/') + 1)]: bin } : bin; + consumerBins[workspace][name] = {}; + for (const [command, path] of Object.entries(bins)) { + if ( + !command || + command === '.' || + command === '..' || + /[/\\:\u0000-\u001f\u007f]/u.test(command) || + typeof path !== 'string' || + /[\\:\u0000-\u001f\u007f]/u.test(path) + ) + throw new Error(`Invalid consumer CLI declaration ${name}/${command}`); + const relative = path.replace(/^\.\//u, ''); + if (relative.split('/').some((part) => !part || part === '.' || part === '..')) + throw new Error(`Consumer CLI path must stay inside ${name}`); + consumerBins[workspace][name][command] = relative; + } + } + } + } + for (const [workspace, inputs] of Object.entries(compilerInputs.workspaces ?? {})) { + const member = Object.entries(manifests).find(([, manifest]) => manifest.name === workspace); + if (!member || !inputs.length || new Set(inputs).size !== inputs.length) + throw new Error(`Compiler inputs require one selected conventional workspace ${workspace}`); + const [path, manifest] = member; + compilerRoots[workspace] = {}; + for (const name of inputs) { + let requirement = manifest.devDependencies?.[name]; + if (!requirement || lock.workspaces[path].devDependencies?.[name] !== requirement) + throw new Error(`bun.lock has a stale compiler input declaration ${workspace}/${name}`); + requirement = catalogRequirement(name, requirement); + compilerRoots[workspace][name] = record(name, workspace, requirement, false, true); + } + } + for (const name of compilerInputs.overrideTools ?? []) { + if ( + compilerToolRoots[name] || + !/^\d+\.\d+\.\d+$/.test(root.overrides?.[name] ?? '') || + lock.overrides?.[name] !== root.overrides?.[name] + ) + throw new Error(`Compiler override tool ${name} requires an exact canonical lock override`); + compilerToolRoots[name] = record(name, '', root.overrides![name], false, true); + } + const compilerClosures: Record = {}; + const closure = (records: typeof packages, roots: string[]) => { + const ids = new Set(); + const pending = [...roots]; + for (let current = pending.pop(); current; current = pending.pop()) { + if (ids.has(current)) continue; + ids.add(current); + pending.push(...Object.values(records[current].dependencies)); + } + return [...ids].sort(); + }; + const sharedCompilerPackages = Object.keys(compilerPackages) + .filter((id) => Object.hasOwn(packages, id)) + .sort(); + for (const id of sharedCompilerPackages) + if (!isDeepStrictEqual(compilerPackages[id], packages[id])) + throw new Error(`Conflicting compiler/type acquisition context for ${packages[id].package}`); + for (const id of Object.keys(compilerPackages)) + compilerClosures[id] = closure(compilerPackages, [id]); + return { + workspaces, + packages, + typescript, + ...(Object.keys(compilerRoots).length || Object.keys(compilerToolRoots).length + ? { + compilerInputs: { + roots: compilerRoots, + tools: compilerToolRoots, + packages: compilerPackages, + closures: compilerClosures, + shared: sharedCompilerPackages, + }, + } + : {}), + ...(Object.keys(consumerRoots).length + ? { + consumerTools: { + roots: consumerRoots, + bins: consumerBins, + closures: Object.fromEntries( + Object.entries(consumerRoots).map(([workspace, roots]) => [ + workspace, + closure(consumerPackages, Object.values(roots)), + ]), + ), + packages: consumerPackages, + platform: { os: 'linux', cpu: 'x64' }, + }, + } + : {}), + }; +} + +if (import.meta.main && Bun.argv[2] === '--verify-dependency') { + const [, , , file, output, name, version, size, sha256] = Bun.argv; + if (!file || !output || !name || !version) + throw new Error('Expected dependency File, output, name and version'); + const identity = sha256 ? { size: Number(size), sha256 } : undefined; + validateJavascriptDependencyArchive(file, name, version, identity); + copyFileSync(file, output); + validateJavascriptDependencyArchive(output, name, version, identity); +} else if (import.meta.main) { + const [rootFile, lockFile, ...parameters] = Bun.argv.slice(2); + const dependencyOptions = parameters.filter((value) => value.startsWith('--dependency-inputs=')); + if (dependencyOptions.length > 1) + throw new Error('Expected at most one dependency input projection'); + const dependencyInputs = dependencyOptions.length + ? JSON.parse(readFileSync(dependencyOptions[0].slice('--dependency-inputs='.length), 'utf8')) + : {}; + const options = parameters.filter((value) => value.startsWith('--consumer-tools=')); + const executionOptions = parameters.filter((value) => value.startsWith('--consumer-workspace=')); + const graphOptions = parameters.filter((value) => + value.startsWith('--consumer-graph-workspace='), + ); + const compilerOptions = parameters.filter((value) => value.startsWith('--compiler-inputs=')); + const dependencyFiles = parameters + .filter((value) => value.startsWith('--dependency-manifest=')) + .map((value) => value.slice('--dependency-manifest='.length)); + if (options.length > 1) throw new Error('Expected at most one consumer tool selection'); + if (compilerOptions.length > 1) throw new Error('Expected at most one compiler input selection'); + const manifestFiles = parameters.filter( + (value) => + !value.startsWith('--consumer-tools=') && + !value.startsWith('--consumer-workspace=') && + !value.startsWith('--consumer-graph-workspace=') && + !value.startsWith('--compiler-inputs=') && + !value.startsWith('--dependency-manifest=') && + !value.startsWith('--dependency-inputs='), + ); + const consumerTools = options.length + ? JSON.parse(readFileSync(options[0].slice('--consumer-tools='.length), 'utf8')) + : {}; + const compilerInputs = compilerOptions.length + ? JSON.parse(readFileSync(compilerOptions[0].slice('--compiler-inputs='.length), 'utf8')) + : {}; + if (!rootFile || !lockFile || !manifestFiles.length) + throw new Error( + 'Expected root package.json, bun.lock, and conventional workspace package.json files', + ); + const root = dirname(rootFile); + const readManifests = (files: string[]) => + Object.fromEntries( + files.map((file) => [ + relative(root, dirname(file)).split('\\').join('/'), + JSON.parse(readFileSync(file, 'utf8')), + ]), + ); + console.log( + JSON.stringify( + importJavascriptMetadata( + JSON.parse(readFileSync(rootFile, 'utf8')), + Bun.JSONC.parse(readFileSync(lockFile, 'utf8')), + readManifests(manifestFiles), + consumerTools, + compilerInputs, + readManifests(dependencyFiles), + executionOptions.map((value) => value.slice('--consumer-workspace='.length)), + graphOptions.map((value) => value.slice('--consumer-graph-workspace='.length)), + { + ...dependencyInputs, + sourceOwners: Object.fromEntries( + [...manifestFiles, ...dependencyFiles].flatMap((file) => { + const descriptor = `${dirname(file)}/release.toml`; + return existsSync(descriptor) + ? [ + [ + relative(root, dirname(file)).split('\\').join('/'), + Bun.TOML.parse(readFileSync(descriptor, 'utf8')), + ], + ] + : []; + }), + ), + }, + ), + ), + ); +} diff --git a/build_defs/languages/ts/metadata.test.mts b/build_defs/languages/ts/metadata.test.mts new file mode 100644 index 000000000..cd5545e0e --- /dev/null +++ b/build_defs/languages/ts/metadata.test.mts @@ -0,0 +1,892 @@ +import { expect, test } from 'bun:test'; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { createHash } from 'node:crypto'; +import { gzipSync, gunzipSync } from 'node:zlib'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { importJavascriptMetadata, validateJavascriptDependencyArchive } from './metadata.mts'; + +test('installed tools fixture acquires the public held SDK closure and rejects stale pins', () => { + const fixture = new URL('../../../src/wasix/postgres-tools/ts/tests/installed/', import.meta.url); + const manifest = JSON.parse(readFileSync(new URL('package.json', fixture), 'utf8')); + const lock = Bun.JSONC.parse(readFileSync(new URL('bun.lock', fixture), 'utf8')); + const project = (selectedManifest = manifest, selectedLock = lock) => + importJavascriptMetadata( + { workspaces: {} }, + selectedLock, + { '': selectedManifest }, + { [manifest.name]: ['@oliphaunt/wasix-ts'] }, + ); + const acquisition = project().consumerTools; + expect( + Object.values(acquisition.packages) + .map((row) => row.package) + .sort(), + ).toEqual([ + '@oliphaunt/liboliphaunt-wasix', + '@oliphaunt/ts-query', + '@oliphaunt/wasix-napi-linux-x64-gnu', + '@oliphaunt/wasix-ts', + 'fzstd', + ]); + expect( + acquisition.packages[acquisition.roots[manifest.name]['@oliphaunt/wasix-ts']].version, + ).toBe(manifest.devDependencies['@oliphaunt/wasix-ts']); + const stale = structuredClone(manifest); + stale.devDependencies['@oliphaunt/wasix-ts'] = '99.0.0'; + expect(() => project(stale)).toThrow(/stale consumer tool declaration/u); + const missing = structuredClone(lock); + delete missing.packages['@oliphaunt/liboliphaunt-wasix']; + expect(() => project(manifest, missing)).toThrow(/Missing Linux x64 consumer tool dependency/u); +}); + +function fixture() { + const manifest = { + name: '@oliphaunt/sdk', + version: '1.2.3', + type: 'module', + devDependencies: { typescript: 'catalog:', '@types/node': '^24.0.0', '@types/bun': 'catalog:' }, + dependencies: { '@oliphaunt/query': '1.0.0' }, + }; + const query = { + name: '@oliphaunt/query', + version: '1.0.0', + devDependencies: { typescript: 'catalog:', '@types/node': '^24.0.0' }, + }; + const node = [ + '@types/node@24.1.0', + '', + { dependencies: { 'undici-types': '7.1.0' } }, + 'sha512-bm9kZQ==', + ]; + const typescript = ['typescript@6.0.3', '', {}, 'sha512-dHNj']; + return { + root: { workspaces: { catalog: { typescript: '^6.0.3', '@types/bun': '1.4.2' } } }, + manifests: { 'src/sdk': manifest, 'src/query': query }, + lock: { + lockfileVersion: 2, + configVersion: 1, + catalog: { typescript: '^6.0.3', '@types/bun': '1.4.2' }, + workspaces: { 'src/sdk': manifest, 'src/query': query }, + packages: { + typescript, + '@types/node': ['@types/node@22.1.0', '', {}, 'sha512-b2xk'], + '@oliphaunt/sdk/@types/node': node, + '@oliphaunt/query/@types/node': node, + '@oliphaunt/sdk/@types/node/undici-types': [ + 'undici-types@7.1.0', + '', + {}, + 'sha512-aHR0cA==', + ], + '@oliphaunt/query/@types/node/undici-types': [ + 'undici-types@7.1.0', + '', + {}, + 'sha512-aHR0cA==', + ], + '@types/bun': [ + '@types/bun@1.4.2', + '', + { dependencies: { 'bun-types': '1.4.2' } }, + 'sha512-YnVu', + ], + 'bun-types': [ + 'bun-types@1.4.2', + '', + { dependencies: { '@types/node': '*' } }, + 'sha512-dHlwZXM=', + ], + }, + }, + } as any; +} + +test('imports nested exact Bun resolutions, preserving a dependency’s different Node types', () => { + const { root, lock, manifests } = fixture(); + const imported = importJavascriptMetadata(root, lock, manifests); + const sdkNode = imported.workspaces['@oliphaunt/sdk'].types['@types/node']; + expect(imported.packages[sdkNode].version).toBe('24.1.0'); + expect(imported.workspaces['@oliphaunt/query'].types['@types/node']).toBe(sdkNode); + const bun = imported.packages[imported.workspaces['@oliphaunt/sdk'].types['@types/bun']]; + const bunTypes = imported.packages[bun.dependencies['bun-types']]; + expect(imported.packages[bunTypes.dependencies['@types/node']].version).toBe('22.1.0'); + expect(Object.values(imported.packages).some((pkg) => pkg.package === 'typescript')).toBe(false); +}); + +test('external runtime acquisition stays locked and workspace names can resolve genuine registry entries', () => { + const value = fixture(); + value.manifests['src/sdk'].dependencies.fzstd = '0.1.1'; + value.lock.packages.fzstd = ['fzstd@0.1.1', '', {}, 'sha512-ZnpzdGQ=']; + const imported = importJavascriptMetadata(value.root, value.lock, value.manifests); + const id = imported.workspaces['@oliphaunt/sdk'].packages?.fzstd; + if (!id) throw new Error('Locked runtime package missing'); + expect(imported.packages[id]).toEqual({ + package: 'fzstd', + version: '0.1.1', + integrity: 'sha512-ZnpzdGQ=', + dependencies: {}, + }); + expect(imported.workspaces['@oliphaunt/query'].packages).toBeUndefined(); + value.lock.packages.fzstd[3] = ''; + expect(() => importJavascriptMetadata(value.root, value.lock, value.manifests)).toThrow( + 'integrity-bearing', + ); + const workspace = fixture(); + workspace.lock.packages['@oliphaunt/query'] = [ + '@oliphaunt/query@1.0.0', + '', + {}, + 'sha512-cXVlcnk=', + ]; + delete workspace.manifests['src/query']; + const locked = importJavascriptMetadata(workspace.root, workspace.lock, workspace.manifests); + expect(locked.workspaces['@oliphaunt/sdk'].dependencyInputs?.['@oliphaunt/query'].source).toBe( + 'registry', + ); +}); + +test('asset workspace dependency identities remain conventional without becoming compiler inputs', () => { + const value = fixture(); + const asset = { name: '@oliphaunt/assets', version: '0.2.4', type: 'module' }; + value.manifests['src/sdk'].dependencies[asset.name] = 'workspace:*'; + value.lock.workspaces['src/assets'] = { ...asset }; + const dependencies = { 'src/assets': asset }; + const before = importJavascriptMetadata( + value.root, + value.lock, + value.manifests, + {}, + {}, + dependencies, + ); + expect(before.workspaces[asset.name]).toEqual({ ...asset, dependencies: {}, types: {} }); + expect(Object.values(before.packages).some((row) => row.package === asset.name)).toBe(false); + asset.version = '0.2.5'; + expect(() => + importJavascriptMetadata(value.root, value.lock, value.manifests, {}, {}, dependencies), + ).toThrow('stale workspace identity'); + asset.version = '0.2.4'; + value.manifests['src/sdk'].dependencies[asset.name] = '0.2.5'; + expect( + importJavascriptMetadata(value.root, value.lock, value.manifests, {}, {}, dependencies) + .workspaces['@oliphaunt/sdk'].dependencyInputs?.[asset.name].source, + ).toBe('unverified'); + expect(() => + importJavascriptMetadata(value.root, value.lock, value.manifests, {}, {}, value.manifests), + ).toThrow('both compiler and dependency'); +}); + +test('consumer tools use an isolated exact lock closure with canonical overrides and host optional packages', () => { + const value = fixture(); + value.root.overrides = { esbuild: '0.28.1' }; + value.lock.overrides = { ...value.root.overrides }; + value.manifests['src/sdk'].devDependencies.vite = '^6.0.3'; + Object.assign(value.lock.packages, { + vite: [ + 'vite@6.4.2', + '', + { dependencies: { esbuild: '^0.21.0' }, optionalDependencies: { absent: '*' } }, + 'sha512-dml0ZQ==', + ], + esbuild: [ + 'esbuild@0.28.1', + '', + { optionalDependencies: { linux: '0.28.1', darwin: '0.28.1' } }, + 'sha512-ZXNi', + ], + linux: ['linux@0.28.1', '', { os: 'linux', cpu: 'x64' }, 'sha512-bGludXg='], + darwin: ['darwin@0.28.1', '', { os: 'darwin', cpu: 'arm64' }, 'sha512-ZGFyd2lu'], + }); + const before = importJavascriptMetadata(value.root, value.lock, value.manifests); + const { consumerTools, ...production } = importJavascriptMetadata( + value.root, + value.lock, + value.manifests, + { '@oliphaunt/sdk': ['vite'] }, + ); + expect(production).toEqual(before); + expect( + Object.values(consumerTools?.packages ?? {}) + .map((row) => row.package) + .sort(), + ).toEqual(['esbuild', 'linux', 'vite']); + expect(consumerTools?.platform).toEqual({ os: 'linux', cpu: 'x64' }); + for (const mutate of [ + (fixture: any) => { + fixture.lock.overrides.esbuild = '0.21.0'; + }, + (fixture: any) => { + delete fixture.lock.packages.esbuild; + }, + (fixture: any) => { + fixture.lock.packages.linux[3] = ''; + }, + (fixture: any) => { + fixture.lock.packages.esbuild[2].os = 'darwin'; + }, + ]) { + const invalid = structuredClone(value); + mutate(invalid); + expect(() => + importJavascriptMetadata(invalid.root, invalid.lock, invalid.manifests, { + '@oliphaunt/sdk': ['vite'], + }), + ).toThrow(); + } +}); + +test('rejects stale declarations and missing integrity without selecting unavailable workspace versions', () => { + for (const mutate of [ + (value: any) => { + value.lock.workspaces['src/sdk'] = { ...value.lock.workspaces['src/sdk'], version: '1.2.2' }; + }, + (value: any) => { + value.lock.catalog.typescript = '^5.9.0'; + }, + (value: any) => { + value.lock.packages['@oliphaunt/sdk/@types/node'][3] = ''; + }, + (value: any) => { + value.root.overrides = { '@types/node': '24.1.0' }; + }, + ]) { + const value = fixture(); + mutate(value); + expect(() => importJavascriptMetadata(value.root, value.lock, value.manifests)).toThrow(); + } +}); + +test('compiler/type sharing admits exact lock context and rejects conflicting bytes or dependencies', () => { + const value = fixture(); + value.manifests['src/sdk'].devDependencies.framework = '^2.0.0'; + Object.assign(value.lock.packages, { + framework: [ + 'framework@2.1.0', + '', + { dependencies: { '@types/node': '^24.0.0' } }, + 'sha512-ZnJhbWU=', + ], + 'framework/@types/node': structuredClone(value.lock.packages['@oliphaunt/sdk/@types/node']), + 'framework/@types/node/undici-types': structuredClone( + value.lock.packages['@oliphaunt/sdk/@types/node/undici-types'], + ), + }); + const selection = { workspaces: { '@oliphaunt/sdk': ['framework'] } }; + const before = importJavascriptMetadata(value.root, value.lock, value.manifests); + const { compilerInputs, ...unchanged } = importJavascriptMetadata( + value.root, + value.lock, + value.manifests, + {}, + selection, + ); + expect(unchanged).toEqual(before); + const nodeId = before.workspaces['@oliphaunt/sdk'].types['@types/node']; + const undiciId = before.packages[nodeId].dependencies['undici-types']; + expect(compilerInputs?.shared).toEqual([nodeId, undiciId].sort()); + expect(compilerInputs?.packages[nodeId]).toEqual(before.packages[nodeId]); + for (const mutate of [ + (invalid: any) => { + invalid.lock.packages['framework/@types/node'][3] = 'sha512-Y29uZmxpY3Q='; + }, + (invalid: any) => { + invalid.lock.packages['framework/@types/node'][2].dependencies['undici-types'] = '^7.1.0'; + invalid.lock.packages['framework/@types/node/undici-types'] = [ + 'undici-types@7.2.0', + '', + {}, + 'sha512-Y29uZmxpY3Q=', + ]; + }, + ]) { + const invalid = structuredClone(value); + mutate(invalid); + expect(() => + importJavascriptMetadata(invalid.root, invalid.lock, invalid.manifests, {}, selection), + ).toThrow('Conflicting compiler/type acquisition context'); + } +}); + +test('compiler roots import declared type peers and every immutable tool platform without changing existing views', () => { + const value = fixture(); + value.manifests['src/sdk'].devDependencies.framework = '^2.0.0'; + value.root.overrides = { esbuild: '0.28.1' }; + value.lock.overrides = { ...value.root.overrides }; + Object.assign(value.lock.packages, { + framework: [ + 'framework@2.1.0', + '', + { peerDependencies: { '@types/render': '^19.0.0' }, optionalPeers: ['@types/render'] }, + 'sha512-ZnJhbWU=', + ], + '@types/render': ['@types/render@19.2.0', '', {}, 'sha512-cmVuZGVy'], + esbuild: [ + 'esbuild@0.28.1', + '', + { optionalDependencies: { linux: '0.28.1', darwin: '0.28.1' } }, + 'sha512-ZXNi', + ], + linux: ['linux@0.28.1', '', { os: 'linux', cpu: 'x64' }, 'sha512-bGludXg='], + darwin: ['darwin@0.28.1', '', { os: 'darwin', cpu: 'arm64' }, 'sha512-ZGFyd2lu'], + }); + const selection = { workspaces: { '@oliphaunt/sdk': ['framework'] }, overrideTools: ['esbuild'] }; + const before = importJavascriptMetadata(value.root, value.lock, value.manifests); + const { compilerInputs, ...unchanged } = importJavascriptMetadata( + value.root, + value.lock, + value.manifests, + {}, + selection, + ); + expect(unchanged).toEqual(before); + const compiled = compilerInputs!; + const framework = compiled.packages[compiled.roots['@oliphaunt/sdk'].framework]; + expect(compiled.packages[framework.dependencies['@types/render']].version).toBe('19.2.0'); + const tool = compiled.packages[compiled.tools.esbuild]; + expect( + Object.values(tool.dependencies) + .map((id) => compiled.packages[id].os) + .sort(), + ).toEqual(['darwin', 'linux']); + const cyclic = structuredClone(value); + cyclic.lock.packages.framework[2].dependencies = { helper: '2.1.0' }; + cyclic.lock.packages.helper = [ + 'helper@2.1.0', + '', + { dependencies: { framework: '^2.0.0' } }, + 'sha512-aGVscGVy', + ]; + const withCycle = importJavascriptMetadata( + cyclic.root, + cyclic.lock, + cyclic.manifests, + {}, + selection, + ).compilerInputs!; + const frameworkId = withCycle.roots['@oliphaunt/sdk'].framework; + const helperId = withCycle.packages[frameworkId].dependencies.helper; + expect(withCycle.packages[helperId].dependencies.framework).toBe(frameworkId); + expect(withCycle.closures[frameworkId]).toContain(helperId); + for (const mutate of [ + (invalid: any) => { + invalid.lock.workspaces['src/sdk'] = { + ...invalid.lock.workspaces['src/sdk'], + devDependencies: { + ...invalid.lock.workspaces['src/sdk'].devDependencies, + framework: '^1.0.0', + }, + }; + }, + (invalid: any) => { + delete invalid.lock.packages['@types/render']; + }, + (invalid: any) => { + invalid.lock.packages['@types/render'][0] = '@types/render@18.0.0'; + }, + (invalid: any) => { + invalid.lock.overrides.esbuild = '0.21.0'; + }, + (invalid: any) => { + delete invalid.lock.packages.darwin; + }, + (invalid: any) => { + invalid.lock.packages.linux[0] = 'linux@1.0.0'; + }, + ]) { + const invalid = structuredClone(value); + mutate(invalid); + expect(() => + importJavascriptMetadata(invalid.root, invalid.lock, invalid.manifests, {}, selection), + ).toThrow(); + } +}); + +test('detects cyclic type acquisitions and conflicting immutable package closures', () => { + const cyclic = fixture(); + cyclic.lock.packages['bun-types'][2].dependencies['@types/bun'] = '1.4.2'; + expect(() => importJavascriptMetadata(cyclic.root, cyclic.lock, cyclic.manifests)).toThrow( + 'Cycle', + ); + const conflicting = fixture(); + conflicting.lock.packages['@oliphaunt/query/@types/node'] = [ + '@types/node@24.1.0', + '', + {}, + 'sha512-bm9kZQ==', + ]; + expect(() => + importJavascriptMetadata(conflicting.root, conflicting.lock, conflicting.manifests), + ).toThrow('Conflicting'); +}); + +test('nested compiler dependencies inherit the nearest locked resolution context', () => { + const value = fixture(); + value.manifests['src/sdk'].devDependencies.framework = '^2.0.0'; + Object.assign(value.lock.packages, { + framework: [ + 'framework@2.1.0', + '', + { dependencies: { transformer: '2.1.0' } }, + 'sha512-ZnJhbWU=', + ], + transformer: ['transformer@2.1.0', '', {}, 'sha512-dHJhbnM='], + 'framework/transformer': [ + 'transformer@2.1.0', + '', + { dependencies: { parser: '^3.5.0' } }, + 'sha512-dHJhbnM=', + ], + 'framework/parser': ['parser@3.5.0', '', {}, 'sha512-bmVhcg=='], + parser: ['parser@3.3.0', '', {}, 'sha512-Z2xvYmFs'], + }); + const compiled = importJavascriptMetadata( + value.root, + value.lock, + value.manifests, + {}, + { + workspaces: { '@oliphaunt/sdk': ['framework'] }, + }, + ).compilerInputs!; + const framework = compiled.packages[compiled.roots['@oliphaunt/sdk'].framework]; + const transformer = compiled.packages[framework.dependencies.transformer]; + expect(compiled.packages[transformer.dependencies.parser].version).toBe('3.5.0'); +}); + +function executionFixture() { + const value = fixture(); + value.root.overrides = { esbuild: '0.28.1' }; + value.lock.overrides = { ...value.root.overrides }; + const manifest = { + name: '@oliphaunt/docs', + version: '0.0.0', + dependencies: { framework: '^16.0.0', render: '^19.0.0' }, + devDependencies: { css: '^4.0.0', typescript: '^5.9.3' }, + }; + value.dependencies = { 'src/docs': manifest }; + value.lock.workspaces['src/docs'] = structuredClone(manifest); + Object.assign(value.lock.packages, { + framework: [ + 'framework@16.2.7', + '', + { + dependencies: { esbuild: '^0.21.0' }, + peerDependencies: { render: '^19.0.0', optional: '^1.0.0', unrelated: '^7.0.0' }, + optionalPeers: ['optional', 'unrelated'], + bin: { build: './dist/cli.js' }, + }, + 'sha512-ZnJhbWU=', + ], + render: ['render@19.2.7', '', {}, 'sha512-cmVuZGVy'], + css: ['css@4.3.0', '', { dependencies: { optional: '^1.0.0' } }, 'sha512-Y3Nz'], + optional: ['optional@1.0.0', '', {}, 'sha512-cGVlcg=='], + unrelated: ['unrelated@6.4.2', '', {}, 'sha512-dml0ZQ=='], + '@oliphaunt/docs/typescript': [ + 'typescript@5.9.3', + '', + { bin: { tsc: './bin/tsc' } }, + 'sha512-dHM=', + ], + esbuild: [ + 'esbuild@0.28.1', + '', + { optionalDependencies: { linux: '0.28.1', darwin: '0.28.1' } }, + 'sha512-ZXNi', + ], + linux: ['linux@0.28.1', '', { os: 'linux', cpu: 'x64' }, 'sha512-bGludXg='], + darwin: ['darwin@0.28.1', '', { os: 'darwin', cpu: 'arm64' }, 'sha512-ZGFyd2lu'], + }); + return value; +} + +const executionProjection = (value = executionFixture()) => + importJavascriptMetadata(value.root, value.lock, value.manifests, {}, {}, value.dependencies, [ + '@oliphaunt/docs', + ]); + +test('explicit tools select conventional runtime or development libraries with exact field bindings', () => { + const value = fixture(); + const workspace = '@oliphaunt/release-tools'; + const manifest = { + name: workspace, + type: 'module', + dependencies: { protobufjs: '8.8.1', 'release-please': '17.3.0' }, + }; + const dependencies = { 'tools/release': manifest } as any; + value.lock.workspaces['tools/release'] = structuredClone(manifest); + Object.assign(value.lock.packages, { + protobufjs: ['protobufjs@8.8.1', '', { dependencies: { long: '^5.3.2' } }, 'sha512-cHJvdG8='], + long: ['long@5.3.2', '', {}, 'sha512-bG9uZw=='], + 'release-please': ['release-please@17.3.0', '', {}, 'sha512-cmVsZWFzZQ=='], + }); + const project = (tools = {}, execution: string[] = []) => + importJavascriptMetadata( + value.root, + value.lock, + value.manifests, + tools, + {}, + dependencies, + execution, + ); + expect(() => project({ [workspace]: ['protobufjs'] }, [workspace])).toThrow( + 'independent conventional selection', + ); + const selected = { [workspace]: ['protobufjs'] }; + const acquired = project(selected).consumerTools!; + expect(Object.keys(acquired.roots[workspace])).toEqual(['protobufjs']); + const library = acquired.packages[acquired.roots[workspace].protobufjs]; + expect(library.version).toBe('8.8.1'); + expect(Object.keys(library.dependencies)).toEqual(['long']); + expect(acquired.packages[library.dependencies.long].version).toBe('5.3.2'); + expect( + Object.values(acquired.packages) + .map((row) => row.package) + .sort(), + ).toEqual(['long', 'protobufjs']); + value.lock.workspaces['tools/release'].dependencies.protobufjs = '8.8.0'; + expect(() => project(selected)).toThrow('stale consumer tool declaration'); + value.lock.workspaces['tools/release'] = structuredClone(manifest); + const runtime = structuredClone(acquired); + (manifest as any).devDependencies = { protobufjs: manifest.dependencies.protobufjs }; + delete (manifest.dependencies as any).protobufjs; + expect(() => project(selected)).toThrow('stale consumer tool declaration'); + value.lock.workspaces['tools/release'] = structuredClone(manifest); + expect(project(selected).consumerTools).toEqual(runtime); +}); + +test('execution workspaces acquire every conventional root with their own compiler and lock-projected CLI paths', () => { + const value = executionFixture(); + const before = importJavascriptMetadata( + value.root, + value.lock, + value.manifests, + {}, + {}, + value.dependencies, + ); + const { consumerTools, ...unchanged } = executionProjection(value); + expect(unchanged).toEqual(before); + const acquired = consumerTools!; + expect(Object.keys(acquired.roots['@oliphaunt/docs'])).toEqual([ + 'css', + 'framework', + 'render', + 'typescript', + ]); + expect(acquired.packages[acquired.roots['@oliphaunt/docs'].typescript].version).toBe('5.9.3'); + expect(before.typescript.version).toBe('6.0.3'); + const framework = acquired.packages[acquired.roots['@oliphaunt/docs'].framework]; + expect(Object.keys(framework.dependencies).sort()).toEqual(['esbuild', 'optional', 'render']); + const esbuild = acquired.packages[framework.dependencies.esbuild]; + expect(esbuild.version).toBe('0.28.1'); + expect(Object.keys(esbuild.dependencies)).toEqual(['linux']); + expect(acquired.bins['@oliphaunt/docs']).toEqual({ + framework: { build: 'dist/cli.js' }, + typescript: { tsc: 'bin/tsc' }, + }); + expect(acquired.closures['@oliphaunt/docs']).toEqual(Object.keys(acquired.packages).sort()); + value.manifests['src/sdk'].devDependencies.tool = '1.0.0'; + value.lock.packages.tool = [ + 'tool@1.0.0', + '', + { dependencies: { esbuild: '^0.21.0' } }, + 'sha512-dG9vbA==', + ]; + const isolated = importJavascriptMetadata( + value.root, + value.lock, + value.manifests, + { '@oliphaunt/sdk': ['tool'] }, + {}, + value.dependencies, + ['@oliphaunt/docs'], + ).consumerTools!; + expect( + isolated.closures['@oliphaunt/sdk'].map((id) => isolated.packages[id].package).sort(), + ).toEqual(['esbuild', 'linux', 'tool']); + expect(isolated.closures['@oliphaunt/docs']).not.toContain(isolated.roots['@oliphaunt/sdk'].tool); + const scalar = executionFixture(); + scalar.lock.packages.framework[2].bin = './dist/cli.js'; + expect(executionProjection(scalar).consumerTools!.bins['@oliphaunt/docs'].framework).toEqual({ + framework: 'dist/cli.js', + }); +}); + +test('optional peers require a compatible provider in the selected workspace context', () => { + for (const provided of [false, true]) { + const value = executionFixture(); + delete value.lock.packages.css[2].dependencies.optional; + if (provided) { + value.dependencies['src/docs'].devDependencies.unrelated = '^6.0.0'; + value.lock.workspaces['src/docs'].devDependencies.unrelated = '^6.0.0'; + } + const acquired = executionProjection(value).consumerTools!; + const framework = acquired.packages[acquired.roots['@oliphaunt/docs'].framework]; + expect(Object.keys(framework.dependencies).sort()).toEqual(['esbuild', 'render']); + } + const value = executionFixture(); + value.manifests['src/sdk'].devDependencies.framework = '^16.0.0'; + value.manifests['src/sdk'].devDependencies.css = '^4.0.0'; + value.lock.workspaces['src/sdk'] = structuredClone(value.manifests['src/sdk']); + value.lock.workspaces['src/sdk'].devDependencies.css = '^3.0.0'; + expect(() => + importJavascriptMetadata(value.root, value.lock, value.manifests, { + '@oliphaunt/sdk': ['framework'], + }), + ).toThrow('stale consumer provider declaration'); + const incompatible = executionFixture(); + incompatible.lock.packages.css[2].dependencies.optional = '^2.0.0'; + expect(() => executionProjection(incompatible)).toThrow('does not satisfy'); + const required = executionFixture(); + required.lock.packages.framework[2].dependencies.optional = '^1.0.0'; + required.lock.packages.framework[2].peerDependencies.optional = '^2.0.0'; + expect(executionProjection(required).consumerTools?.packages).toBeDefined(); +}); + +test('execution acquisition rejects stale declarations, wrong platforms, missing peers, integrity and overrides', () => { + for (const mutate of [ + (value: any) => { + value.lock.workspaces['src/docs'].dependencies.framework = '^15.0.0'; + }, + (value: any) => { + value.lock.workspaces['src/docs'].dependencies.removed = '1.0.0'; + }, + (value: any) => { + value.lock.packages.framework[2].os = 'darwin'; + }, + (value: any) => { + delete value.lock.packages.render; + }, + (value: any) => { + value.lock.packages.render[0] = 'render@18.0.0'; + }, + (value: any) => { + value.lock.packages.framework[3] = ''; + }, + (value: any) => { + value.lock.overrides.esbuild = '0.21.0'; + }, + (value: any) => { + value.lock.packages.framework[2].dependencies.framework = '^16.0.0'; + }, + ]) { + const value = executionFixture(); + mutate(value); + expect(() => executionProjection(value)).toThrow(); + } + const value = executionFixture(); + expect(() => + importJavascriptMetadata(value.root, value.lock, value.manifests, {}, {}, value.dependencies, [ + '@oliphaunt/docs', + '@oliphaunt/docs', + ]), + ).toThrow('Duplicate execution workspace'); +}); + +test('consumer CLI paths stay inside the declared package', () => { + for (const path of [ + '', + '../cli.js', + './dist/../../cli.js', + '/cli.js', + 'C:/cli.js', + 'dist\\cli.js', + 'dist/\ncli.js', + ]) { + const value = executionFixture(); + value.lock.packages.framework[2].bin.build = path; + expect(() => executionProjection(value)).toThrow(); + } + for (const command of ['', '../build', 'build:run', 'build\nrun']) { + const value = executionFixture(); + value.lock.packages.framework[2].bin = { [command]: 'dist/cli.js' }; + expect(() => executionProjection(value)).toThrow(); + } +}); + +test('distinct optional peer contexts cannot silently share one installation identity', () => { + const value = executionFixture(); + value.manifests['src/sdk'].devDependencies.framework = '^16.0.0'; + expect(() => + importJavascriptMetadata( + value.root, + value.lock, + value.manifests, + { '@oliphaunt/sdk': ['framework'] }, + {}, + value.dependencies, + ['@oliphaunt/docs'], + ), + ).toThrow('Conflicting acquisition closure'); + value.manifests['src/sdk'].devDependencies.css = '^4.0.0'; + const same = structuredClone(value.lock.packages.framework); + same[2].peerDependencies = Object.fromEntries(Object.entries(same[2].peerDependencies).reverse()); + value.lock.packages['@oliphaunt/sdk/framework'] = same; + expect(() => + importJavascriptMetadata( + value.root, + value.lock, + value.manifests, + { '@oliphaunt/sdk': ['framework'] }, + {}, + value.dependencies, + ['@oliphaunt/docs'], + ), + ).not.toThrow(); +}); + +function heldQueryFixture() { + const value = fixture(); + const original = value.manifests['src/query']; + original.name = '@oliphaunt/ts-query'; + original.version = '0.1.1'; + value.manifests['src/sdk'].dependencies = { [original.name]: '0.1.1' }; + value.lock.packages[`${original.name}/@types/node`] = + value.lock.packages['@oliphaunt/query/@types/node']; + value.lock.packages[`${original.name}/@types/node/undici-types`] = + value.lock.packages['@oliphaunt/query/@types/node/undici-types']; + const file = fileURLToPath(new URL('./testdata/ts-query-0.1.1.tgz', import.meta.url)); + const bytes = readFileSync(file); + const row = { + publication: { + product: 'oliphaunt-query-ts', + version: '0.1.1', + tagName: 'oliphaunt-query-ts-v0.1.1', + publicationSha: 'c51052fe8b8ffc7e992266c5ab3d7a63b47441e7', + publicationTree: '59791800860832994b48b8009bb48c5a74a7764e', + releaseSha: '7b192697ff522f71f9c694593d352aa30469cea1', + }, + artifact: `npm:${original.name}`, + archive: '@oliphaunt_metadata//:supplier-artifacts/query.tgz', + file: { + path: file, + size: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + }, + }; + const owners = { + 'src/query': { id: row.publication.product, registry_packages: [row.artifact] }, + }; + const project = (options = {}) => + importJavascriptMetadata(value.root, value.lock, value.manifests, {}, {}, {}, [], [], { + supplierArchives: [row], + sourceOwners: owners, + ...options, + }); + return { value, row, owners, project }; +} + +test('ordinary held query survives a current major version and uses the exact retained published File', () => { + const { value, row, project } = heldQueryFixture(); + value.manifests['src/query'].version = '1.0.0'; + const choice = project().workspaces['@oliphaunt/sdk'].dependencyInputs!['@oliphaunt/ts-query']; + expect(choice).toMatchObject({ + source: 'completed', + version: '0.1.1', + archive: row.archive, + sha256: 'f0f690ed68891aef72f49dab3f4b79206cda428e55ace54cef8ff8de58557c60', + packages: {}, + }); + expect(project().workspaces['@oliphaunt/sdk'].dependencies['@oliphaunt/ts-query']).toBe('0.1.1'); +}); + +test('same-version workspace bytes do not imply adoption; prepared source selection and owner must both match', () => { + const { row, project } = heldQueryFixture(); + expect( + project().workspaces['@oliphaunt/sdk'].dependencyInputs!['@oliphaunt/ts-query'].source, + ).toBe('completed'); + const selected = project({ selectedProducts: ['oliphaunt-query-ts'] }).workspaces[ + '@oliphaunt/sdk' + ].dependencyInputs!['@oliphaunt/ts-query']; + expect(selected).toEqual({ + source: 'workspace', + workspace: 'src/query', + version: '0.1.1', + owner: 'oliphaunt-query-ts', + }); + expect( + project({ selectedProducts: ['oliphaunt-react-native'] }).workspaces['@oliphaunt/sdk'] + .dependencyInputs!['@oliphaunt/ts-query'].source, + ).toBe('completed'); + expect( + project({ + selectedProducts: ['oliphaunt-query-ts'], + sourceOwners: { 'src/query': { id: 'other', registry_packages: [row.artifact] } }, + }).workspaces['@oliphaunt/sdk'].dependencyInputs!['@oliphaunt/ts-query'].source, + ).toBe('unverified'); +}); + +test('explicit workspace source remains conventional and missing pool does not prevent metadata/tool loading', () => { + const { value, project } = heldQueryFixture(); + const missing = project({ supplierArchives: [] }); + expect(missing.typescript.version).toBe('6.0.3'); + expect( + missing.workspaces['@oliphaunt/sdk'].dependencyInputs!['@oliphaunt/ts-query'], + ).toMatchObject({ source: 'unverified' }); + value.manifests['src/sdk'].dependencies['@oliphaunt/ts-query'] = 'workspace:*'; + expect( + project({ supplierArchives: [] }).workspaces['@oliphaunt/sdk'].dependencyInputs![ + '@oliphaunt/ts-query' + ].source, + ).toBe('workspace'); + value.manifests['src/sdk'].dependencies['@oliphaunt/ts-query'] = 'workspace:2.0.0'; + expect(() => project()).toThrow('conventional workspace version'); +}); + +test('held File digest and packed identity reject same-version byte substitution and wrong archive identities', () => { + const { row, project } = heldQueryFixture(); + const directory = mkdtempSync(path.join(tmpdir(), 'ts-held-query-')); + try { + const file = path.join(directory, 'query.tgz'); + const bytes = gzipSync(gunzipSync(readFileSync(row.file.path)), { level: 1 }); + writeFileSync(file, bytes); + expect(validateJavascriptDependencyArchive(file, '@oliphaunt/ts-query', '0.1.1').version).toBe( + '0.1.1', + ); + expect(() => + project({ + supplierArchives: [{ ...row, file: { ...row.file, path: file, size: bytes.length } }], + }), + ).toThrow('digest differs'); + expect(() => + validateJavascriptDependencyArchive(row.file.path, '@oliphaunt/ts-query', '1.0.0', row.file), + ).toThrow('packed identity differs'); + expect(() => + validateJavascriptDependencyArchive(row.file.path, 'wrong', '0.1.1', row.file), + ).toThrow('packed identity differs'); + expect(() => project({ supplierArchives: [row, row] })).toThrow('Ambiguous'); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('declared dependency worker preserves retained archive bytes and rejects post-projection tampering', () => { + const { row } = heldQueryFixture(); + const directory = mkdtempSync(path.join(tmpdir(), 'ts-dependency-worker-')); + try { + const output = path.join(directory, 'checked.tgz'); + const run = (file = row.file.path) => + Bun.spawnSync([ + process.execPath, + fileURLToPath(new URL('./metadata.mts', import.meta.url)), + '--verify-dependency', + file, + output, + '@oliphaunt/ts-query', + '0.1.1', + String(row.file.size), + row.file.sha256, + ]); + expect(run().exitCode).toBe(0); + expect(readFileSync(output)).toEqual(readFileSync(row.file.path)); + const substitute = path.join(directory, 'substitute.tgz'); + writeFileSync(substitute, gzipSync(gunzipSync(readFileSync(row.file.path)), { level: 1 })); + expect(run(substitute).exitCode).not.toBe(0); + expect(readFileSync(output)).toEqual(readFileSync(row.file.path)); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); diff --git a/build_defs/languages/ts/publish-manifest.mts b/build_defs/languages/ts/publish-manifest.mts new file mode 100644 index 000000000..48a048266 --- /dev/null +++ b/build_defs/languages/ts/publish-manifest.mts @@ -0,0 +1,56 @@ +import { copyFile, mkdir, mkdtemp, rm } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { pathToFileURL } from 'node:url'; + +const [profile, source, directory] = Bun.argv.slice(2); +if (!['js', 'wasix-ts', 'wasix-tools'].includes(profile) || !source || !directory) + throw new Error('Expected SDK profile, source manifest and output directory'); +const inputs = process.cwd(); +const staging = await mkdtemp(join(tmpdir(), 'oliphaunt-sdk-manifest-')); +try { + // Release notice validation requires real files. Materialize only declared + // inputs rather than weakening that boundary for Bazel's sandbox symlinks. + const helpers = join(staging, 'tools/packaging'); + await mkdir(helpers, { recursive: true }); + for (const name of [ + 'release-notices.mts', + 'release-directory-safety.mts', + 'portable-archive.mts', + ]) + await copyFile(join(inputs, 'tools/packaging', name), join(helpers, name)); + for (const name of ['LICENSE', 'THIRD_PARTY_NOTICES.md']) + await copyFile(join(inputs, name), join(staging, name)); + const packageDirectory = join(staging, 'package'); + await mkdir(packageDirectory); + await copyFile(source, join(packageDirectory, 'package.json')); + if (profile === 'js') { + await copyFile( + join(inputs, 'tools/packaging/source-only-sdk-package.mts'), + join(helpers, 'source-only-sdk-package.mts'), + ); + const { prepareSourceOnlyNpmPackage, SOURCE_ONLY_NPM_PROFILES } = await import( + pathToFileURL(join(helpers, 'source-only-sdk-package.mts')).href + ); + prepareSourceOnlyNpmPackage(packageDirectory, SOURCE_ONLY_NPM_PROFILES.js); + } else { + const canonical = + profile === 'wasix-ts' + ? 'src/wasix/sdks/ts/tools/package.mts' + : 'src/wasix/postgres-tools/ts/tools/package.mts'; + const projected = join(staging, canonical); + await mkdir(join(projected, '..'), { recursive: true }); + await copyFile(join(inputs, canonical), projected); + const canonicalWriter = await import(pathToFileURL(projected).href); + const prepare = + profile === 'wasix-ts' + ? canonicalWriter.prepareWasixTypescriptPackage + : canonicalWriter.prepareWasixToolsTypescriptPackage; + prepare(packageDirectory); + } + await mkdir(directory, { recursive: true }); + for (const name of ['package.json', 'LICENSE', 'THIRD_PARTY_NOTICES.md']) + await copyFile(join(packageDirectory, name), join(directory, name)); +} finally { + await rm(staging, { recursive: true, force: true }); +} diff --git a/build_defs/languages/ts/repositories.bzl b/build_defs/languages/ts/repositories.bzl new file mode 100644 index 000000000..e721520a8 --- /dev/null +++ b/build_defs/languages/ts/repositories.bzl @@ -0,0 +1,224 @@ +"""One-way JavaScript acquisition from the conventional Bun workspace lock.""" + +load("@aspect_rules_js//npm:repositories.bzl", "npm_import") + +def _metadata_impl(ctx): + inputs = [ctx.attr.package, ctx.attr.lockfile, ctx.attr.converter] + ctx.attr.manifests + ctx.attr.dependency_manifests + for source in inputs: + ctx.read(source) + ctx.read(ctx.attr.archive_reader) + for source in ctx.attr.manifests + ctx.attr.dependency_manifests: + descriptor = ctx.path(source).dirname.get_child("release.toml") + if descriptor.exists: + ctx.read(descriptor) + supplier_archives = [] + for row in json.decode(ctx.read(ctx.attr.supplier_artifacts)).values(): + if not row["artifact"].startswith("npm:"): + continue + alias = row["file"]["path"] + file = ctx.path(Label(alias)) + ctx.watch(file) + supplier_archives.append(dict(row, archive = alias, file = dict(row["file"], path = str(file)))) + selected = json.decode(ctx.read(ctx.attr.selected_products)) + ctx.file("dependency-inputs.json", json.encode({"supplierArchives": supplier_archives, "selectedProducts": selected})) + ctx.watch(ctx.path(ctx.attr.bun)) + ctx.file("consumer-selection.json", json.encode(ctx.attr.consumer_tools)) + compiler_arguments = [] + if ctx.attr.compiler_inputs: + ctx.read(ctx.attr.compiler_inputs) + compiler_arguments = ["--compiler-inputs=" + str(ctx.path(ctx.attr.compiler_inputs))] + result = ctx.execute([ + ctx.path(ctx.attr.bun), + ctx.path(ctx.attr.converter), + ctx.path(ctx.attr.package), + ctx.path(ctx.attr.lockfile), + "--consumer-tools=" + str(ctx.path("consumer-selection.json")), + "--dependency-inputs=" + str(ctx.path("dependency-inputs.json")), + ] + compiler_arguments + ["--consumer-workspace=" + workspace for workspace in ctx.attr.consumer_workspaces] + ["--consumer-graph-workspace=" + workspace for workspace in ctx.attr.consumer_graph_workspaces] + ["--dependency-manifest=" + str(ctx.path(source)) for source in ctx.attr.dependency_manifests] + [ctx.path(source) for source in ctx.attr.manifests], quiet = True) + if result.return_code: + fail("Cannot import canonical JavaScript workspace inputs: " + result.stderr) + data = json.decode(result.stdout) + ctx.file("metadata.bzl", "JAVASCRIPT = " + repr(data["workspaces"]) + "\n") + ctx.file("acquisition.json", json.encode(data["packages"])) + ctx.file("typescript.json", json.encode(data["typescript"])) + ctx.file("consumer-tools.json", json.encode(data.get("consumerTools", {"roots": {}, "packages": {}, "platform": {"os": "linux", "cpu": "x64"}}))) + ctx.file("compiler-inputs.json", json.encode(data.get("compilerInputs", {"roots": {}, "tools": {}, "packages": {}, "closures": {}}))) + ctx.file("BUILD.bazel", 'exports_files(["metadata.bzl", "acquisition.json", "typescript.json", "consumer-tools.json", "compiler-inputs.json"], visibility = ["//visibility:public"])\n') + return ctx.repo_metadata(reproducible = True) + +javascript_metadata_repository = repository_rule( + implementation = _metadata_impl, + attrs = { + "selected_products": attr.label(default = Label("@oliphaunt_metadata//:prepared-selected-products.json"), allow_single_file = True), + "supplier_artifacts": attr.label(default = Label("@oliphaunt_metadata//:completed-supplier-artifacts.json"), allow_single_file = True), + "archive_reader": attr.label(default = Label("//:tools/packaging/portable-archive.mts"), allow_single_file = True), + "package": attr.label(default = Label("//:package.json"), allow_single_file = True), + "lockfile": attr.label(default = Label("//:bun.lock"), allow_single_file = True), + "converter": attr.label(default = Label("//build_defs/languages/ts:metadata.mts"), allow_single_file = True), + "bun": attr.label(default = Label("@bun_runtime//:bun"), allow_single_file = True), + "manifests": attr.label_list(allow_files = True, mandatory = True), + "dependency_manifests": attr.label_list(allow_files = True, default = []), + "consumer_tools": attr.string_list_dict(default = {}), + "consumer_workspaces": attr.string_list(default = []), + "consumer_graph_workspaces": attr.string_list(default = []), + "compiler_inputs": attr.label(allow_single_file = [".json"]), + }, +) + +def _hub_impl(ctx): + metadata = json.decode(ctx.read(ctx.attr.metadata)) + data = metadata["packages"] if ctx.attr.consumer or ctx.attr.compiler else metadata + link_macro = "compiler_input_links" if ctx.attr.compiler else "javascript_type_links" + lines = [ + 'load("@aspect_rules_js//npm/private:npm_package_store.bzl", "npm_package_store")', + 'load("@aspect_rules_js//npm/private:npm_link_package_store.bzl", "npm_link_package_store")', + "PACKAGES = {", + ] + if ctx.attr.compiler: + lines.insert(1, 'load("@aspect_rules_js//npm/private:npm_package_store_internal.bzl", "npm_package_store_internal")') + for key in sorted(data): + row = data[key] + source_prefix = "javascript_" if key in ctx.attr.shared else ctx.attr.prefix + if ctx.attr.compiler: + lines.append(" %s: {\"src\": Label(%s), \"dependencies\": %s, \"package\": %s, \"version\": %s}," % (repr(key), repr("@" + source_prefix + key + "//:pkg"), repr(row["dependencies"]), repr(row["package"]), repr(row["version"]))) + else: + lines.append(" %s: {\"src\": Label(%s), \"dependencies\": %s}," % (repr(key), repr("@" + ctx.attr.prefix + key + "//:pkg"), repr(row["dependencies"]))) + lines.extend([ + "}", + "", + "def %s(types):" % link_macro, + ]) + if ctx.attr.compiler: + lines.extend([ + " for key, row in PACKAGES.items():", + " if key in SHARED:", + ' if not native.existing_rule("_javascript_" + key):', + ' fail("Compiler/type shared packages require javascript_type_links in the same package")', + ' native.alias(name = "_compiler_" + key + "_ref", actual = ":_javascript_" + key)', + ' native.alias(name = "_compiler_" + key + "_pkg", actual = ":_javascript_" + key)', + " else:", + ' npm_package_store_internal(name = "_compiler_" + key + "_ref", key = key, src = None, package = row["package"], version = row["version"], deps = {})', + ' npm_package_store_internal(name = "_compiler_" + key + "_pkg", key = key, package = row["package"], version = row["version"], src = row["src"], deps = {":_compiler_" + dependency + "_ref": name for name, dependency in row["dependencies"].items()})', + " for key, row in PACKAGES.items():", + " if key in SHARED:", + ' native.alias(name = "_compiler_" + key, actual = ":_javascript_" + key)', + " else:", + ' npm_package_store_internal(name = "_compiler_" + key, key = key, src = None, package = row["package"], version = row["version"], deps = {":_compiler_" + dependency + "_pkg": PACKAGES[dependency]["package"] for dependency in CLOSURES[key]})', + ]) + else: + lines.extend([ + " for key in sorted(PACKAGES):", + " row = PACKAGES[key]", + " npm_package_store(name = \"_javascript_\" + key, src = row[\"src\"], deps = {\":_javascript_\" + dependency: name for name, dependency in row[\"dependencies\"].items()})", + ]) + lines.extend([ + " for name, key in types.items():", + ' npm_link_package_store(name = "node_modules/" + name, src = ":_compiler_" + key)' if ctx.attr.compiler else ' npm_link_package_store(name = "node_modules/" + name, src = ":_javascript_" + key)', + ]) + if ctx.attr.compiler: + lines.append("CLOSURES = " + repr(metadata.get("closures", {}))) + lines.append("SHARED = " + repr(ctx.attr.shared)) + ctx.file("defs.bzl", "\n".join(lines) + "\n") + ctx.file("acquisition.json", json.encode(data) if ctx.attr.consumer or ctx.attr.compiler else ctx.read(ctx.attr.metadata)) + consumer_files = [] + if ctx.attr.consumer: + acquisitions = ["CONSUMER_ACQUISITIONS = {"] + for workspace, keys in sorted(metadata.get("closures", {}).items()): + path = "workspaces/" + workspace + ".json" + ctx.file(path, json.encode({key: data[key] for key in keys})) + consumer_files.append(path) + acquisitions.append(" %s: Label(%s)," % (repr(workspace), repr("//:" + path))) + acquisitions.append("}") + ctx.file("roots.bzl", "CONSUMER_TOOLS = " + repr(metadata["roots"]) + "\nCONSUMER_BINS = " + repr(metadata.get("bins", {})) + "\nCONSUMER_PACKAGES = " + repr(data) + "\nCONSUMER_CLOSURES = " + repr(metadata.get("closures", {})) + "\n" + "\n".join(acquisitions) + "\n") + if ctx.attr.compiler: + ctx.file("roots.bzl", "COMPILER_INPUTS = " + repr(metadata["roots"]) + "\nCOMPILER_TOOLS = " + repr(metadata["tools"]) + "\nCOMPILER_PACKAGES = " + repr(data) + "\nCOMPILER_CLOSURES = " + repr(metadata["closures"]) + "\n") + build = ['package(default_visibility = ["//visibility:public"])', 'exports_files(["defs.bzl", "acquisition.json"])'] + if ctx.attr.consumer or ctx.attr.compiler: + build.append('exports_files(["roots.bzl"])') + if consumer_files: + build.append("exports_files(%s)" % repr(consumer_files)) + for key in sorted(data): + source_prefix = "javascript_" if key in ctx.attr.shared else ctx.attr.prefix + build.append("alias(name = %s, actual = %s)" % (repr(key), repr("@" + source_prefix + key + "//:pkg"))) + ctx.file("BUILD.bazel", "\n".join(build) + "\n") + return ctx.repo_metadata(reproducible = True) + +_javascript_hub = repository_rule( + implementation = _hub_impl, + attrs = { + "metadata": attr.label(mandatory = True), + "prefix": attr.string(default = "javascript_"), + "consumer": attr.bool(default = False), + "compiler": attr.bool(default = False), + "shared": attr.string_list(), + }, +) + +def _packages_impl(ctx): + tags = [tag for module in ctx.modules for tag in module.tags.configure] + if len(tags) != 1: + fail("Exactly one canonical JavaScript acquisition projection is required") + for module in ctx.modules: + if module.tags.configure and not module.is_root: + fail("Only the root module may configure JavaScript acquisition") + metadata = tags[0].metadata + packages = json.decode(ctx.read(metadata)) + for key, package in packages.items(): + npm_import( + name = "javascript_" + key, + package = package["package"], + version = package["version"], + integrity = package["integrity"], + lifecycle_hooks = [], + ) + _javascript_hub(name = "javascript_packages", metadata = metadata) + repos = ["javascript_packages"] + for context, metadata in [("consumer", tags[0].consumer_metadata), ("installed", tags[0].installed_metadata), ("android_app", tags[0].android_app_metadata)]: + if not metadata: + continue + consumer = json.decode(ctx.read(metadata)) + if consumer["platform"] != {"os": "linux", "cpu": "x64"}: + fail("The %s consumer closure requires Linux x64" % context) + for key, package in consumer["packages"].items(): + npm_import( + name = "javascript_" + context + "_" + key, + package = package["package"], + version = package["version"], + integrity = package["integrity"], + lifecycle_hooks = [], + ) + name = "javascript_" + context + "_packages" + _javascript_hub(name = name, metadata = metadata, prefix = "javascript_" + context + "_", consumer = True) + repos.append(name) + if tags[0].compiler_metadata: + compiler = json.decode(ctx.read(tags[0].compiler_metadata)) + shared = sorted([key for key in compiler["packages"] if key in packages]) + if shared != compiler.get("shared", []): + fail("Compiler/type shared package projection differs from conventional acquisition") + for key in shared: + if compiler["packages"][key] != packages[key]: + fail("Conflicting compiler/type identity, integrity, or dependency context: " + key) + for key, package in compiler["packages"].items(): + if key in shared: + continue + npm_import( + name = "javascript_compiler_" + key, + package = package["package"], + version = package["version"], + integrity = package["integrity"], + lifecycle_hooks = [], + ) + _javascript_hub(name = "javascript_compiler_packages", metadata = tags[0].compiler_metadata, prefix = "javascript_compiler_", compiler = True, shared = shared) + repos.append("javascript_compiler_packages") + return ctx.extension_metadata(root_module_direct_deps = repos, root_module_direct_dev_deps = [], reproducible = True) + +javascript_packages = module_extension( + implementation = _packages_impl, + tag_classes = {"configure": tag_class(attrs = { + "metadata": attr.label(mandatory = True), + "consumer_metadata": attr.label(), + "android_app_metadata": attr.label(), + "installed_metadata": attr.label(), + "compiler_metadata": attr.label(), + })}, +) diff --git a/build_defs/languages/ts/testdata/ts-query-0.1.1.tgz b/build_defs/languages/ts/testdata/ts-query-0.1.1.tgz new file mode 100644 index 000000000..f1521746f Binary files /dev/null and b/build_defs/languages/ts/testdata/ts-query-0.1.1.tgz differ diff --git a/build_defs/languages/ts/unit-tests.bzl b/build_defs/languages/ts/unit-tests.bzl new file mode 100644 index 000000000..3ab660bfa --- /dev/null +++ b/build_defs/languages/ts/unit-tests.bzl @@ -0,0 +1,55 @@ +"""Execute the source-owned SDK unit suites without native runtime construction.""" + +load("@aspect_rules_js//npm:providers.bzl", "NpmPackageInfo") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") + +def _runfile(ctx, file): + return file.short_path[3:] if file.short_path.startswith("../") else ctx.workspace_name + "/" + file.short_path + +def _sdk_unit_test_impl(ctx): + sources = {} + for file in ctx.files.sources + ctx.files.fixtures + ctx.files.tests + ctx.files.package_manifests + [ctx.file.manifest] + ([ctx.file.configuration] if ctx.file.configuration else []): + if file.is_directory or file.short_path.startswith("../"): + fail("SDK source units require individual repository source Files") + if file.short_path in sources and sources[file.short_path] != file: + fail("SDK source units have conflicting declared source paths: " + file.short_path) + sources[file.short_path] = file + packages = [] + package_files = [] + for target, name in ctx.attr.packages.items(): + package = target[NpmPackageInfo] + if package.package != name or package.src.is_directory: + fail("SDK source units require the declared npm archive identity for " + name) + packages.append({"name": name, "version": package.version, "archive": _runfile(ctx, package.src)}) + package_files.append(package.src) + specification = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(specification, json.encode({ + "sdk": ctx.file.manifest.short_path.removesuffix("/package.json"), + "sources": {relative: _runfile(ctx, file) for relative, file in sources.items()}, + "configuration": ctx.file.configuration.short_path if ctx.file.configuration else None, + "packageManifests": [file.short_path for file in ctx.files.package_manifests], + "tests": sorted([file.short_path for file in ctx.files.tests]) if ctx.files.tests else sorted([relative for relative in sources if relative.startswith(ctx.file.manifest.short_path.removesuffix("package.json") + "src/__tests__/") and relative.endswith(".test.ts")]), + "packages": packages, + })) + return bun_test_entrypoint(ctx, ctx.file._runner, [specification], + [specification] + sources.values() + package_files + [ctx.file._runner], + source_files = [ctx.file._runner], runfiles_environment = ["OLIPHAUNT_BAZEL_RUNFILES"]) + +_sdk_unit_test = rule( + implementation = _sdk_unit_test_impl, + test = True, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "manifest": attr.label(mandatory = True, allow_single_file = [".json"]), + "sources": attr.label_list(allow_files = True, mandatory = True), + "tests": attr.label_list(allow_files = [".test.ts", ".test.mts"], doc = "Optional existing SDK-owned operational test roots; source suites use their conventional src/__tests__ tree."), + "fixtures": attr.label_list(allow_files = True), + "configuration": attr.label(allow_single_file = [".toml"]), + "package_manifests": attr.label_list(allow_files = [".json"], doc = "Authored metadata for existing unit-owned carrier fixtures; no native payload construction."), + "packages": attr.label_keyed_string_dict(providers = [NpmPackageInfo]), + "_runner": attr.label(default = "//build_defs/languages/ts:unit-tests.mts", allow_single_file = True), + }), +) + +def sdk_unit_test(name, **kwargs): + _sdk_unit_test(name = name, args = bun_test_entrypoint_args(name), **kwargs) diff --git a/build_defs/languages/ts/unit-tests.mts b/build_defs/languages/ts/unit-tests.mts new file mode 100644 index 000000000..fa45d1324 --- /dev/null +++ b/build_defs/languages/ts/unit-tests.mts @@ -0,0 +1,109 @@ +import assert from 'node:assert/strict'; +import { copyFileSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; + +const [file] = process.argv.slice(2); +assert(file && process.env.TEST_TMPDIR && process.env.OLIPHAUNT_BAZEL_RUNFILES); +const inputs = JSON.parse(readFileSync(file, 'utf8')) as { + sdk: string; + configuration: string | null; + sources: Record; + packageManifests: string[]; + tests: string[]; + packages: Array<{ name: string; version: string; archive: string }>; +}; +const root = path.join(process.env.TEST_TMPDIR, 'sdk-unit-source'); +const runfiles = process.env.OLIPHAUNT_BAZEL_RUNFILES; +function relative(value: string): string { + assert( + value && + !path.isAbsolute(value) && + !value.includes('\\') && + !value.split('/').some((part) => !part || part === '.' || part === '..'), + ); + return value; +} +for (const [destination, source] of Object.entries(inputs.sources)) { + const output = path.join(root, relative(destination)); + mkdirSync(path.dirname(output), { recursive: true }); + // Each File becomes a regular module; Bun must not import undeclared siblings through a source symlink. + copyFileSync(path.join(runfiles, relative(source)), output); +} +const sdk = path.join(root, relative(inputs.sdk)); +for (const source of inputs.packageManifests) { + const manifest = JSON.parse(readFileSync(path.join(root, relative(source)), 'utf8')); + const destination = path.join(sdk, 'node_modules', relative(manifest.name), 'package.json'); + mkdirSync(path.dirname(destination), { recursive: true }); + // Existing resolver units create their own dummy payloads from this authored metadata. + // This is neither an installed native carrier nor a publication qualification. + copyFileSync(path.join(root, source), destination); +} +for (const dependency of inputs.packages) { + const directory = path.join(sdk, 'node_modules', relative(dependency.name)); + const entries = await new Bun.Archive( + readFileSync(path.join(runfiles, relative(dependency.archive))), + ).files(); + assert(entries.size, `empty declared package ${dependency.name}`); + for (const [name, content] of entries) { + assert( + name.startsWith('package/'), + `package ${dependency.name} lacks its conventional npm prefix`, + ); + const target = path.join(directory, relative(name.slice('package/'.length))); + mkdirSync(path.dirname(target), { recursive: true }); + writeFileSync(target, await content.bytes()); + } + const manifest = JSON.parse(readFileSync(path.join(directory, 'package.json'), 'utf8')); + assert.equal(manifest.name, dependency.name); + assert.equal(manifest.version, dependency.version); +} +const configuration = inputs.configuration + ? path.join(root, relative(inputs.configuration)) + : path.join(sdk, 'unit-bunfig.toml'); +if (!inputs.configuration) writeFileSync(configuration, ''); +assert(inputs.tests.length > 0, 'SDK unit root must include source-owned behavioral tests'); +const tests = inputs.tests.map((test) => { + assert( + (test.startsWith(`${inputs.sdk}/src/__tests__/`) || test.startsWith(`${inputs.sdk}/tools/`)) && + /\.test\.(?:ts|mts)$/u.test(test), + ); + assert(Object.hasOwn(inputs.sources, test)); + return path.join(root, relative(test)); +}); +const result = Bun.spawnSync( + [ + process.execPath, + 'test', + '--no-install', + '--no-env-file', + `--config=${configuration}`, + '--isolate', + '--timeout=30000', + ...tests, + ], + { + cwd: sdk, + env: { + ...process.env, + NODE_PATH: '', + NODE_OPTIONS: '', + XDG_CACHE_HOME: path.join(process.env.TEST_TMPDIR, 'cache'), + TMPDIR: process.env.TEST_TMPDIR, + }, + stdout: 'pipe', + stderr: 'pipe', + }, +); +process.stdout.write(result.stdout); +process.stderr.write(result.stderr); +assert.equal(result.exitCode, 0, 'source-owned SDK unit suite failed'); +const summary = `${result.stdout.toString()}\n${result.stderr.toString()}`.match( + /Ran (\d+) tests? across (\d+) files?/u, +); +assert( + summary && Number(summary[1]) > 0 && Number(summary[2]) === inputs.tests.length, + 'every declared SDK unit file must execute', +); +console.log( + `Source SDK units: ${summary[1]} cases across all ${summary[2]} declared files; no runtime producer inputs`, +); diff --git a/build_defs/languages/uniffi.mts b/build_defs/languages/uniffi.mts new file mode 100644 index 000000000..77c241ae4 --- /dev/null +++ b/build_defs/languages/uniffi.mts @@ -0,0 +1,40 @@ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; + +export function generateUniffi({ + generator, + library, + configuration, + language, + directory, +}: { + generator: string; + library: string; + configuration: string; + language: 'swift' | 'kotlin'; + directory: string; +}) { + // Unix metadata retains the fd-based mobile API; Windows metadata omits it. + assert.ok( + process.platform === 'darwin' || process.platform === 'linux', + 'Mobile binding metadata requires a Unix execution host', + ); + const result = spawnSync( + generator, + [ + 'generate', + '--library', + library, + '--config', + configuration, + '--language', + language, + '--no-format', + '--out-dir', + directory, + ], + { stdio: 'inherit', env: {} }, + ); + assert.equal(result.error, undefined, String(result.error)); + assert.equal(result.status, 0, 'Declared UniFFI generator failed'); +} diff --git a/build_defs/languages/wasix.bzl b/build_defs/languages/wasix.bzl new file mode 100644 index 000000000..88b1572ee --- /dev/null +++ b/build_defs/languages/wasix.bzl @@ -0,0 +1,42 @@ +"""WASIX Cargo carriers consume declared payload construction outputs.""" + +load(":rust.bzl", "cargo_generator", "cargo_library", "cargo_library_test", "cargo_package_env") +load("@rules_rust//rust:defs.bzl", "rust_clippy_test") +load("//build_defs/wasix:platform.bzl", "WASIX_PAYLOAD_PROFILE") + +def _cargo_payload_impl(ctx): + return [ctx.attr.payload[0][DefaultInfo]] + +_cargo_payload = rule( + implementation = _cargo_payload_impl, + attrs = { + "payload": attr.label(mandatory = True, cfg = WASIX_PAYLOAD_PROFILE), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), + }, +) + +def wasix_runtime_carrier(payload, portable = False): + cargo_package_env() + _cargo_payload(name = "cargo_payload", payload = payload) + payload = ":cargo_payload" + environment = { + "OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD": "1", + # Native packaging consumes declared File providers. Conventional + # Cargo's mutable target-directory descriptor is not a native output. + "OLIPHAUNT_ARTIFACT_CRATE_EMIT_CARGO_MANIFEST": "0", + "OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR" if portable else "OLIPHAUNT_WASM_GENERATED_AOT_DIR": "$(execpath " + payload + ")", + } + cargo_generator(srcs = ["build-support.rs"], data = [payload], build_script_env = environment) + cargo_library(build_script = ":build_script", compile_data = [payload]) + cargo_library_test() + + # Cargo permits absent payloads for source checks; shipping remains strict. + cargo_generator(name = "quality_build_script", srcs = ["build-support.rs"]) + cargo_library(name = "quality_lib", build_script = ":quality_build_script") + cargo_library_test(name = "quality_unit_test", crate = ":quality_lib") + rust_clippy_test( + name = "clippy_test", + targets = [":quality_lib", ":quality_unit_test", ":quality_build_script_"], + transitive = False, + size = "small", + ) diff --git a/build_defs/native/BUILD.bazel b/build_defs/native/BUILD.bazel new file mode 100644 index 000000000..11759699b --- /dev/null +++ b/build_defs/native/BUILD.bazel @@ -0,0 +1,133 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_test") +load("//build_defs/android:toolchain.bzl", "android_artifact") +load("//build_defs/foundation:bun.bzl", "bun_script_test", "bun_test") +load(":platform_config.bzl", "NATIVE_COMPATIBLE", "NATIVE_WINDOWS_COMPATIBLE") +load(":compiler_probes.bzl", "native_compiler_probe_targets") +load(":mobile-profile-test.bzl", "native_mobile_profile_tests") +load(":probe-tools-test.bzl", "compiler_probe_tool_inputs_test") + +package(default_visibility = ["//visibility:public"]) + +exports_files(glob(["*.bzl", "*.bazel", "*.sh", "*.mts", "*.c", "*.cc", "patches/*.patch"])) + +config_setting(name = "linux_x86_64", constraint_values = ["@platforms//os:linux", "@platforms//cpu:x86_64"]) +config_setting(name = "linux_aarch64", constraint_values = ["@platforms//os:linux", "@platforms//cpu:aarch64"]) +config_setting(name = "linux_x86_64_gnu_2_28", constraint_values = ["@platforms//os:linux", "@platforms//cpu:x86_64", "@zig_sdk//libc:gnu.2.28"]) +config_setting(name = "linux_aarch64_gnu_2_28", constraint_values = ["@platforms//os:linux", "@platforms//cpu:aarch64", "@zig_sdk//libc:gnu.2.28"]) +config_setting(name = "linux_opt", constraint_values = ["@platforms//os:linux"], values = {"compilation_mode": "opt"}) +config_setting(name = "android_arm64", constraint_values = ["@platforms//os:android", "@platforms//cpu:aarch64", "//build_defs/android:ndk_runtime"]) +config_setting(name = "android_x86_64", constraint_values = ["@platforms//os:android", "@platforms//cpu:x86_64", "//build_defs/android:ndk_runtime"]) +config_setting(name = "android", constraint_values = ["@platforms//os:android", "//build_defs/android:ndk_runtime"]) +config_setting(name = "macos_arm64", constraint_values = ["@platforms//os:macos", "@platforms//cpu:aarch64"]) +config_setting(name = "windows_x64", constraint_values = ["@platforms//os:windows", "@platforms//cpu:x86_64"]) +config_setting(name = "ios_arm64", constraint_values = ["@platforms//os:ios", "@platforms//cpu:aarch64", "@apple_support//constraints:apple", "@apple_support//constraints:device"]) +config_setting(name = "ios_arm64_simulator", constraint_values = ["@platforms//os:ios", "@platforms//cpu:aarch64", "@apple_support//constraints:apple", "@apple_support//constraints:simulator"]) +config_setting(name = "ios", constraint_values = ["@platforms//os:ios", "@platforms//cpu:aarch64", "@apple_support//constraints:apple"]) + +platform(name = "linux_x86_64_glibc_2_28", constraint_values = ["@platforms//os:linux", "@platforms//cpu:x86_64", "@zig_sdk//libc:gnu.2.28"]) +platform(name = "linux_aarch64_glibc_2_28", constraint_values = ["@platforms//os:linux", "@platforms//cpu:aarch64", "@zig_sdk//libc:gnu.2.28"]) + +native_compiler_probe_targets(name = "compiler_probe") +native_mobile_profile_tests() +compiler_probe_tool_inputs_test() + +# A frontend utility must not share a link with the embedded C API runtime. +cc_binary( + name = "windows_restricted_process", + srcs = ["windows-restricted-process.c"], + deps = ["@postgres//:server_headers", "@postgres//:common_frontend", "@postgres//:port_frontend"], + defines = ["FRONTEND"], + copts = ["/std:c11"], + testonly = True, + target_compatible_with = NATIVE_WINDOWS_COMPATIBLE, +) + +bun_script_test( + name = "windows_restricted_process_test", + entry_point = "windows-restricted-process.test.mts", + args = ["$(location :windows_restricted_process)"], + data = [":windows_restricted_process"], + target_compatible_with = NATIVE_WINDOWS_COMPATIBLE, + size = "small", +) + +cc_test( + name = "probe_process_test", + srcs = ["probe-process.test.cc"], + copts = select({"@platforms//os:windows": ["/std:c++17"], "//conditions:default": ["-std=c++17"]}), + deps = ["@rules_cc_autoconf//autoconf/private/checker:native_process"], + size = "small", +) + +bun_test( + name = "windows_exports_test", + entry_point = "windows-exports.test.mts", + data = ["windows-exports.mts"], + size = "small", +) + +bun_script_test( + name = "postgres_probe_header_test", + entry_point = "postgres-probe-header.test.mts", + args = ["$(location @postgres//:src/include/utils/probes.h)", "$(location @postgres//:src/backend/utils/probes.d)"], + data = ["@postgres//:src/include/utils/probes.h", "@postgres//:src/backend/utils/probes.d"], + size = "small", +) + +bun_script_test( + name = "host_config_policy_test", + entry_point = "host-config-policy.test.mts", + args = ["$(location :compiler_probe_tool_inputs_subject)"], + data = ["host_config.bzl", ":compiler_probe_tool_inputs_subject"], + size = "small", +) + +bun_script_test( + name = "host_runtime_test_helpers_test", + entry_point = "host-runtime-test-helpers.test.mts", + data = ["host-runtime-test-helpers.mts", "//:tools/packaging/portable-archive.mts"], + size = "small", +) + +bun_script_test( + name = "icu_data_object_test", + entry_point = "icu-data-object.test.mts", + args = ["$(location @icu_data//:data)", "$(location @icu//:common/unicode/uvernum.h)", "$(location @icu//:common/unicode/utypes.h)"], + data = ["icu-data-object.mts", "@icu_data//:data", "@icu//:common/unicode/uvernum.h", "@icu//:common/unicode/utypes.h"], + size = "small", +) + +cc_test( + name = "crypto_smoke_test", + srcs = ["crypto_smoke.c"], + deps = ["@openssl//:crypto"], + env = {"OPENSSL_MODULES": "/nonexistent-oliphaunt-provider", "OPENSSL_CONF": "/nonexistent-oliphaunt-config"}, + target_compatible_with = NATIVE_COMPATIBLE, +) + +[android_artifact( + name = "android_runtime_" + name, + artifact = "//src/native/runtime:liboliphaunt.so", + platform = "//build_defs/android:android_" + name, + output = "android-" + name + "-liboliphaunt.so", +) for name in ["arm64", "x86_64"]] + +bun_script_test( + name = "android_runtime_abi_test", + entry_point = "android-runtime-abi.test.mts", + args = ["$(location :android_runtime_arm64)", "$(location :android_runtime_x86_64)", "$(location @android_ndk//:nm)", "$(location //src/native/runtime:include/oliphaunt.h)"], + data = [":android_runtime_arm64", ":android_runtime_x86_64", "@android_ndk//:nm", "//src/native/runtime:include/oliphaunt.h", "//:tools/packaging/platform-binary-contract.mts", "//:tools/packaging/windows-vc-runtime-closure.mts", "//:tools/packaging/windows-vc-runtime-policy.json", "//tools/release:platform-compatibility-policy.mts"], + size = "medium", + tags = ["manual"], +) + +bun_test( + name = "rust_runtime_runner_test", + entry_point = "rust-runtime-test.test.mts", + data = ["rust-runtime-test.mts", "host-runtime-test-helpers.mts", "//:tools/packaging/portable-archive.mts", "//:tools/packaging/release-directory-safety.mts"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + size = "small", +) + +source_quality_files() diff --git a/build_defs/native/android-runtime-abi.test.mts b/build_defs/native/android-runtime-abi.test.mts new file mode 100644 index 000000000..d72824d36 --- /dev/null +++ b/build_defs/native/android-runtime-abi.test.mts @@ -0,0 +1,106 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { inspectPlatformBinaryBuffer } from '../../tools/packaging/platform-binary-contract.mts'; + +const [arm64, x64, nm, header] = process.argv.slice(2); +assert( + arm64 && x64 && nm && header, + 'expected two actual Android runtimes, declared nm and public C header', +); +const publicFunctions = [ + ...readFileSync(header, 'utf8').matchAll(/^OLIPHAUNT_API\s+[^;]+?\b(oliphaunt_\w+)\s*\(/gmu), +].map((match) => match[1]!); +assert(publicFunctions.length > 0, 'public header has no exported ABI functions'); + +function symbols(library: string, options: string[]) { + const result = Bun.spawnSync([nm!, ...options, library], { + env: { PATH: '/nonexistent', LANG: 'C' }, + stdout: 'pipe', + stderr: 'pipe', + }); + assert.equal( + result.exitCode, + 0, + `${library}: declared llvm-nm failed: ${result.stderr.toString()}`, + ); + return result.stdout.toString(); +} + +for (const [library, target] of [ + [arm64, 'android-arm64-v8a'], + [x64, 'android-x86_64'], +] as const) { + const bytes = readFileSync(library!); + inspectPlatformBinaryBuffer(bytes, { target, label: library }); + + // A malformed copy of an actual runtime verifies the publication validator + // against the native producer, rather than only against synthetic ELF data. + const offset = Number(bytes.readBigUInt64LE(32)); + const entrySize = bytes.readUInt16LE(54); + const count = bytes.readUInt16LE(56); + const malformed = Buffer.from(bytes); + let altered = false; + for (let index = 0; index < count; index++) { + const entry = offset + entrySize * index; + if (bytes.readUInt32LE(entry) !== 1) continue; + malformed.writeBigUInt64LE(4096n, entry + 48); + altered = true; + break; + } + assert(altered, `${target}: no loadable ELF segment`); + assert.throws( + () => inspectPlatformBinaryBuffer(malformed, { target, label: library }), + /PT_LOAD alignment/u, + ); + + const exports = new Set( + symbols(library!, ['--dynamic', '--defined-only']) + .split('\n') + .map((line) => line.trim().split(/\s+/u).at(-1)), + ); + for (const name of publicFunctions) + assert(exports.has(name), `${target}: missing public C ABI ${name}`); + for (const name of [ + 'oliphaunt_builtin_dict_snowball_Pg_magic_func', + 'dsnowball_init', + 'pg_finfo_dsnowball_init', + 'dsnowball_lexize', + 'pg_finfo_dsnowball_lexize', + ]) { + assert(exports.has(name), `${target}: missing builtin Snowball ${name}`); + } + assert( + [...exports].some((name) => /^ucol_open(?:_\d+)?$/u.test(name ?? '')), + `${target}: missing actual linked ICU collation implementation`, + ); + assert( + !exports.has('pg_register_static_icu_data'), + `${target}: embeds an alternate ICU data registration implementation`, + ); + + const defined = symbols(library!, ['--defined-only', '--print-size']); + for (const line of defined.split('\n')) { + const match = line.match(/^\s*[a-f0-9]+\s+([a-f0-9]+)\s+\w\s+(icudt\d+[a-z]*_dat)$/iu); + if (match) + assert( + Number.parseInt(match[1]!, 16) <= 4096, + `${target}: ${match[2]} embeds ICU data rather than the declared external resource`, + ); + } + const imports = symbols(library!, ['--dynamic', '--undefined-only']) + .split('\n') + .map((line) => line.trim().split(/\s+/u).at(-1)?.split('@')[0]); + const forbidden = imports.find((name) => + /^(?:shm(?:get|ctl|dt|at)|shm_open|sem(?:get|ctl|op|open|close|unlink|wait|post|trywait|timedwait|init|destroy))$/u.test( + name ?? '', + ), + ); + assert.equal( + forbidden, + undefined, + `${target}: imports mobile-forbidden process-global IPC ${forbidden}`, + ); + console.log( + `${target}: actual C ABI, ICU, builtin Snowball, Bionic/static-C++/16-KiB ELF and process-local IPC contract pass`, + ); +} diff --git a/build_defs/native/android/BUILD.bazel b/build_defs/native/android/BUILD.bazel new file mode 100644 index 000000000..79cdc070f --- /dev/null +++ b/build_defs/native/android/BUILD.bazel @@ -0,0 +1,22 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/foundation:bun.bzl", "bun_binary") +load("//build_defs/native/carriers:defs.bzl", "native_carrier_helpers", "native_payload_helpers") + +package(default_visibility = ["//visibility:public"]) +exports_files(glob(["*.bzl", "*.mts"])) + +filegroup(name = "runtime_helpers", srcs = {label: True for label in native_carrier_helpers() + native_payload_helpers() + [ + "//build_defs/native/carriers:payload.mts", "//build_defs/resources:shared.mts", + "//build_defs/native:host-runtime-test-helpers.mts", + "//src/native/runtime:tools/native-mobile-abi-contract.mts", + "//src/native/runtime:tools/finalize-native-runtime-carrier.mts", + "//src/native/runtime:tools/native-runtime-carrier-contract.mts", + "//src/database-resources:contracts/native-manifest.mts", "//src/database-resources:contracts/contract.json", + "//src/extensions/tools:extension-upstream-licenses.mts", + "//:tools/packaging/build-maven-artifact-manifest.mts", "//:tools/packaging/maven-artifact-manifest.mts", + "//:tools/packaging/maven-artifact-staging.mts", "//:tools/packaging/maven-central-contract.mts", + "//:tools/packaging/atomic-directory.mts", "//tools/release:compatibility-version-policy.mts", "//tools/release:product-version.mts", +]}.keys()) +bun_binary(name = "runtime_envelope", entry_point = "runtime-envelope.mts", data = [":runtime_helpers"]) + +source_quality_files() diff --git a/build_defs/native/android/runtime-assets.test.mts b/build_defs/native/android/runtime-assets.test.mts new file mode 100644 index 000000000..3ae1adf4e --- /dev/null +++ b/build_defs/native/android/runtime-assets.test.mts @@ -0,0 +1,94 @@ +import assert from 'node:assert/strict'; +import { copyFileSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { + compareNativeMobileAbiReceipts, + NATIVE_MOBILE_ABI_TARGETS_BY_DOMAIN, +} from '../../../src/native/runtime/tools/native-mobile-abi-contract.mts'; +import { bindNativeRuntimeResourceManifest } from '../../../src/native/runtime/tools/native-runtime-carrier-contract.mts'; +import { validateMavenCentralPublication } from '../../../tools/packaging/maven-central-contract.mts'; +import { readPortableArchiveEntries } from '../../../tools/packaging/portable-archive.mts'; +import { copyDeclaredTree } from '../carriers/payload.mts'; + +/** Consume final GH and Maven bytes, without claiming Android execution. */ +export function checkAndroidRuntimeAssets( + metadata, + artifacts: Map, + maven: Map, +) { + assert.deepEqual( + [...artifacts.keys()].sort(), + metadata.artifacts.map((row) => row.target).sort(), + ); + assert.deepEqual([...maven.keys()].sort(), metadata.carriers.map((row) => row.name).sort()); + const runtime = readPortableArchiveEntries(artifacts.get('android-datum64'), { + format: 'tar.gz', + }); + const manifest = runtime.get('oliphaunt/runtime/manifest.properties'); + assert(manifest?.isFile, 'Final Android runtime resources must contain their installed manifest'); + assert( + manifest.data().equals(bindNativeRuntimeResourceManifest(manifest.data(), 'android-datum64')), + ); + compareNativeMobileAbiReceipts( + 'android-datum64', + NATIVE_MOBILE_ABI_TARGETS_BY_DOMAIN['android-datum64'].map((target) => { + const receipt = runtime.get(`oliphaunt/provenance/native-mobile-abi/${target}.properties`); + assert(receipt?.isFile, `Final Android runtime resources lost the actual ${target} receipt`); + return { label: target, text: receipt.data().toString('utf8') }; + }), + ); + for (const carrier of metadata.carriers) { + const [group, artifact] = carrier.name.split(':'); + const directory = path.join( + maven.get(carrier.name), + ...group.split('.'), + artifact, + metadata.version, + ); + const prefix = `${artifact}-${metadata.version}`; + const names = readdirSync(directory).sort(); + const publication = validateMavenCentralPublication({ + context: `${carrier.name}:${metadata.version}`, + files: names.map((name) => ({ name, size: statSync(path.join(directory, name)).size })), + pomText: readFileSync(path.join(directory, `${prefix}.pom`), 'utf8'), + }); + assert.equal( + `${publication.groupId}:${publication.artifactId}:${publication.version}`, + `${carrier.name}:${metadata.version}`, + ); + const target = carrier.target ?? 'android-datum64'; + const github = artifacts.get(target); + assert(github, 'Final Maven runtime must correspond to an actual canonical GH artifact'); + assert( + readFileSync(path.join(directory, `${prefix}.tar.gz`)).equals(readFileSync(github)), + `${carrier.name} Maven and GH runtime bytes diverged`, + ); + } +} + +if (import.meta.main) { + const [metadataText, ...arguments_] = process.argv.slice(2); + const metadata = JSON.parse(metadataText); + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-installed-android-runtime-')); + try { + const artifacts = new Map(); + const maven = new Map(); + for (let index = 0; index < arguments_.length; index += 4) { + const [kind, identity, source, declaredPath] = arguments_.slice(index, index + 4); + assert( + identity && source && declaredPath, + 'Android runtime test requires complete declared final inputs', + ); + const target = kind === 'asset' ? artifacts : maven; + assert(['asset', 'maven'].includes(kind) && !target.has(identity)); + const destination = path.join(root, `input-${index}`); + if (kind === 'asset') copyFileSync(source, destination); + else copyDeclaredTree(source, destination, undefined, declaredPath); + target.set(identity, destination); + } + checkAndroidRuntimeAssets(metadata, artifacts, maven); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} diff --git a/build_defs/native/android/runtime-envelope.mts b/build_defs/native/android/runtime-envelope.mts new file mode 100644 index 000000000..5dea1e97f --- /dev/null +++ b/build_defs/native/android/runtime-envelope.mts @@ -0,0 +1,166 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + copyFileSync, + mkdirSync, + readFileSync, + realpathSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { finalizeNativeRuntimeCarrier } from '../../../src/native/runtime/tools/finalize-native-runtime-carrier.mts'; +import { + compareNativeMobileAbiReceipts, + parseNativeMobileAbiReceipt, +} from '../../../src/native/runtime/tools/native-mobile-abi-contract.mts'; +import { + requiredRuntimeMemberPaths, + validatePayload, +} from '../../../src/native/runtime/tools/native-runtime-payload.mts'; +import { createDeterministicTar } from '../../../tools/packaging/archive-directory.mts'; +import { buildMavenArtifactManifest } from '../../../tools/packaging/build-maven-artifact-manifest.mts'; +import { stageMavenArtifactManifest } from '../../../tools/packaging/maven-artifact-staging.mts'; +import { inspectPlatformBinaryTree } from '../../../tools/packaging/platform-binary-contract.mts'; +import { canonicalGzipSync } from '../../../tools/packaging/portable-archive.mts'; +import { stageReleaseNotices } from '../../../tools/packaging/release-notices.mts'; +import { materializeInputs, privateWork, readSpecification, run } from '../../resources/shared.mts'; +import { copyDeclaredTree } from '../carriers/payload.mts'; + +/** Envelope declared compiled Files; never invoke a build or discover a checkout. */ +export async function packageAndroidRuntime(specification) { + assert.equal( + process.platform, + 'linux', + 'Android runtime resources use their admitted Linux producer', + ); + assert.equal( + process.arch, + 'x64', + 'Android runtime resources use their admitted Linux x64 producer', + ); + const work = privateWork(path.resolve(specification.resources)); + try { + const legal = materializeInputs(specification.notices, path.join(work, 'legal')); + const payload = path.join(work, 'payload'); + copyDeclaredTree( + specification.payload, + payload, + requiredRuntimeMemberPaths('linux-x64-gnu', 'runtime/bin'), + ); + const receipts = Object.entries(specification.receipts).map(([target, file]) => { + const text = readFileSync(file as string, 'utf8'); + assert.equal( + parseNativeMobileAbiReceipt(text, target).get('target'), + target, + 'Android runtime receipt must bind its actual producer', + ); + return { label: target, text }; + }); + compareNativeMobileAbiReceipts('android-datum64', receipts); + const assets = path.join(work, 'assets'); + mkdirSync(assets); + const hash = createHash('sha256').update('oliphaunt-android-runtime-resources-v1\n'); + hash.update(await createDeterministicTar(payload)); + for (const receipt of receipts.sort((a, b) => a.label.localeCompare(b.label))) + hash.update(receipt.text); + const resourceStage = path.join(work, 'resources'); + run( + realpathSync(specification.formatter), + [ + '--output', + resourceStage, + '--liboliphaunt-native-version', + specification.version, + '--extension-target', + 'android-datum64', + '--runtime-cache-identity', + `android-runtime-${hash.digest('hex')}`, + ], + { + HOME: work, + TMPDIR: work, + LC_ALL: 'C', + LANG: 'C', + OLIPHAUNT_INSTALL_DIR: path.join(payload, 'runtime'), + OLIPHAUNT_EMBEDDED_MODULE_DIR: path.join(payload, 'lib/modules'), + OLIPHAUNT_RUNTIME_CACHE_DIR: path.join(work, 'cache'), + }, + work, + ); + const closure = path.join(resourceStage, 'oliphaunt'); + const provenance = path.join(closure, 'provenance/native-mobile-abi'); + mkdirSync(provenance, { recursive: true }); + for (const receipt of receipts) + writeFileSync(path.join(provenance, `${receipt.label}.properties`), receipt.text, { + mode: 0o644, + }); + finalizeNativeRuntimeCarrier(closure, 'android-datum64'); + stageReleaseNotices(resourceStage, { profile: 'native-runtime-resources', sourceRoot: legal }); + const resourceAsset = path.join(assets, path.basename(specification.resources)); + writeFileSync(resourceAsset, canonicalGzipSync(await createDeterministicTar(resourceStage)), { + mode: 0o644, + }); + copyFileSync(resourceAsset, specification.resources); + for (const artifact of specification.artifacts.filter((row) => row.kind === 'native-runtime')) { + const binary = specification.libraries[artifact.target]; + assert( + binary && artifact.library_relative_path, + 'Android runtime needs its actual canonical library', + ); + const name = artifact.asset.replaceAll('{version}', specification.version); + const stage = path.join(work, name.slice(0, -'.tar.gz'.length)); + const destination = path.join(stage, artifact.library_relative_path); + mkdirSync(path.dirname(destination), { recursive: true }); + copyFileSync(binary, destination); + chmodSync(destination, 0o755); + materializeInputs(specification.headers, path.join(stage, 'include')); + // NDK llvm-strip is a multicall llvm-objcopy alias; retain its argv[0]. + run( + path.resolve(specification.strip), + ['--strip-debug', destination], + { HOME: work, TMPDIR: work, LC_ALL: 'C', LANG: 'C' }, + work, + ); + stageReleaseNotices(stage, { profile: 'native-runtime', sourceRoot: legal }); + validatePayload(stage, artifact.target, { requireRuntime: false, toolSet: 'runtime' }); + await inspectPlatformBinaryTree(stage, { target: artifact.target }); + const asset = path.join(assets, name); + writeFileSync(asset, canonicalGzipSync(await createDeterministicTar(stage)), { mode: 0o644 }); + copyFileSync(asset, specification.outputs[artifact.target]); + } + const manifest = await buildMavenArtifactManifest(path.join(work, 'maven.tsv'), { + runtime: true, + runtimeAssetRoot: assets, + context: { + version: specification.version, + artifactTargets: specification.artifacts, + registryPackages: specification.carriers.map((row) => row.name), + noticeSourceRoot: legal, + }, + }); + const mavenRoot = path.join(work, 'maven'); + const publications = await stageMavenArtifactManifest(manifest, mavenRoot, { + noticeSourceRoot: legal, + }); + assert.equal( + publications.length, + specification.carriers.length, + 'Android Maven construction must have exactly the canonical coordinates', + ); + for (const carrier of specification.carriers) { + const [group, artifact] = carrier.name.split(':'); + assert(group && artifact, 'Android runtime requires a canonical Maven coordinate'); + const relative = path.join(...group.split('.'), artifact, specification.version); + copyDeclaredTree( + path.join(mavenRoot, relative), + path.join(specification.mavenOutputs[carrier.name], relative), + ); + } + } finally { + rmSync(work, { recursive: true, force: true }); + } +} + +if (import.meta.main) await packageAndroidRuntime(readSpecification()); diff --git a/build_defs/native/android/runtime.bzl b/build_defs/native/android/runtime.bzl new file mode 100644 index 000000000..de1d7a223 --- /dev/null +++ b/build_defs/native/android/runtime.bzl @@ -0,0 +1,125 @@ +"""Final Android runtime carriers over the existing configured native producers.""" + +load("@oliphaunt_metadata//:metadata.bzl", "NATIVE_RUNTIME_ARTIFACTS", "PRODUCTS", "PUBLICATION_CARRIERS") +load("//build_defs/android:toolchain.bzl", "android_artifact") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "BunScriptInfo", "bun_action", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/native/carriers:defs.bzl", "native_carrier_legal_inputs") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") + +_LINUX = ["@platforms//os:linux", "@platforms//cpu:x86_64"] +_TARGETS = {"android-arm64-v8a": "arm64", "android-x86_64": "x86_64"} +_AndroidRuntimeAssetsInfo = provider(fields = ["metadata", "assets", "maven"]) + +def _sources(entries, inputs): + result = {} + for target, member in entries.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1 or member in result: + fail("Android runtime carrier input needs one unique declared File: " + str(target.label)) + result[member] = files[0].path + inputs += files + return result + +def _runtime_impl(ctx): + inputs = ctx.files.payload + ctx.files._strip + if len(ctx.files.payload) != 1 or not ctx.files.payload[0].is_directory: + fail("Android runtime resources require the actual declared Linux native payload tree") + strip = [file for file in ctx.files._strip if file.basename == "llvm-strip"] + if len(strip) != 1: + fail("Android runtime envelopes require the actual NDK strip tool and its closure") + metadata = json.decode(ctx.attr.metadata) + outputs = {row["target"]: ctx.actions.declare_file(row["asset"].replace("{version}", metadata["version"])) for row in metadata["artifacts"]} + maven = {row["name"]: ctx.actions.declare_directory(ctx.label.name + "/maven/" + row["name"].replace(":", "/")) for row in metadata["carriers"]} + specification = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(specification, json.encode(metadata | { + "payload": ctx.files.payload[0].path, + "libraries": _sources(ctx.attr.libraries, inputs), + "receipts": _sources(ctx.attr.receipts, inputs), + "headers": _sources(ctx.attr.headers, inputs), + "notices": _sources(ctx.attr.notices, inputs), + "resources": outputs["android-datum64"].path, + "outputs": {target: file.path for target, file in outputs.items()}, + "mavenOutputs": {coordinate: file.path for coordinate, file in maven.items()}, + "formatter": ctx.executable._formatter.path, + "strip": strip[0].path, + }) + "\n") + bun_action(ctx, ctx.attr._tool, arguments = [specification.path], + inputs = inputs + [specification], tools = [ctx.attr._formatter[DefaultInfo].files_to_run], + outputs = outputs.values() + maven.values(), mnemonic = "NativeAndroidRuntimeEnvelope") + groups = {target.replace("-", "_"): depset([file]) for target, file in outputs.items()} + for coordinate, file in maven.items(): + groups["maven_" + coordinate.split(":")[1].replace("-", "_")] = depset([file]) + return [DefaultInfo(files = depset(outputs.values() + maven.values())), OutputGroupInfo(**groups), + _AndroidRuntimeAssetsInfo(metadata = ctx.attr.metadata, assets = outputs, maven = maven)] + +_runtime_envelopes = rule(implementation = _runtime_impl, attrs = { + "metadata": attr.string(mandatory = True), + "payload": attr.label(default = "//src/native/runtime:public_payload"), + "libraries": attr.label_keyed_string_dict(allow_files = True, mandatory = True), + "receipts": attr.label_keyed_string_dict(allow_files = True, mandatory = True), + "headers": attr.label_keyed_string_dict(allow_files = True, mandatory = True), + "notices": attr.label_keyed_string_dict(allow_files = True, mandatory = True), + "_formatter": attr.label(default = "//src/native/runtime/packaging:resources", executable = True, cfg = "exec"), + "_strip": attr.label(default = "@android_ndk//:strip_files", allow_files = True, cfg = "exec"), + "_tool": attr.label(default = "//build_defs/native/android:runtime_envelope", providers = [BunScriptInfo], cfg = "exec"), +}) + +def _assets_test_impl(ctx): + info = ctx.attr.assets[_AndroidRuntimeAssetsInfo] + arguments = [info.metadata] + for target, file in info.assets.items(): + arguments += ["asset", target, file, file.path] + for coordinate, file in info.maven.items(): + arguments += ["maven", coordinate, file, file.path] + return bun_test_entrypoint(ctx, ctx.file._runner, arguments, + info.assets.values() + info.maven.values() + ctx.files._helpers, + source_files = [ctx.file._runner] + ctx.files._helpers) + +_assets_test = rule(implementation = _assets_test_impl, test = True, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "assets": attr.label(mandatory = True, providers = [_AndroidRuntimeAssetsInfo]), + "_runner": attr.label(default = "//build_defs/native/android:runtime-assets.test.mts", allow_single_file = True), + "_helpers": attr.label(default = "//build_defs/native/android:runtime_helpers"), + })) + +def native_android_runtime_targets(): + """Construction follows the canonical runtime artifacts and Maven identities.""" + product = "liboliphaunt-native" + rows = [row for row in NATIVE_RUNTIME_ARTIFACTS if row["product"] == product and (row["kind"] == "native-runtime" and row["target"] in _TARGETS or row["kind"] == "runtime-resources" and row["target"] == "android-datum64")] + if len(rows) != len(_TARGETS) + 1: + fail("Android runtime requires exactly its canonical ABI and physical-domain artifacts") + runtime_maven = [name[len("maven:"):] for name in PRODUCTS[product]["registry_packages"] if name.startswith("maven:")] + carriers = [row for row in PUBLICATION_CARRIERS if row["product"] == product and row["ecosystem"] == "maven" and row["name"] in runtime_maven] + if len(carriers) != len(rows): + fail("Android runtime must retain one canonical Maven identity per final artifact") + libraries = {} + for target, platform in _TARGETS.items(): + name = "android_runtime_" + platform + android_artifact(name = name, artifact = ":runtime_shared", platform = "//build_defs/android:android_" + platform, target_compatible_with = _LINUX) + libraries[":" + name] = target + _runtime_envelopes(name = "android_release_assets", metadata = json.encode({"version": PRODUCTS[product]["version"], "artifacts": rows, "carriers": carriers}), + libraries = libraries, receipts = { + "//src/database-resources:android_arm64_abi": "android-arm64-v8a", + "//src/database-resources:android_x86_64_abi": "android-x86_64", + "//src/database-resources:native_target_abi": "linux-x64-gnu", + }, headers = {file: file[len("include/"):] for file in native.glob(["include/*.h"])}, + notices = native_carrier_legal_inputs(), target_compatible_with = _LINUX) + packages = [] + for row in rows: + name = "android_" + row["target"].replace("android-", "").replace("-", "_") + native.filegroup(name = name + "_archive", srcs = [":android_release_assets"], output_group = row["target"].replace("-", "_"), target_compatible_with = _LINUX) + shipping_package(name = name + "_github_shipping", owner = "@oliphaunt_metadata//:product_" + product, artifacts = [":" + name + "_archive"], + ecosystem = "github", package_name = row["asset"].replace("{version}", PRODUCTS[product]["version"]), configuration = row["target"], role = "github-release-asset", suppliers = "//build_defs/release:no_suppliers") + packages.append(":" + name + "_github_shipping") + for row in carriers: + artifact = row["name"].split(":")[1] + name = "android_maven_" + artifact.replace("-", "_") + native.filegroup(name = name, srcs = [":android_release_assets"], output_group = "maven_" + artifact.replace("-", "_"), target_compatible_with = _LINUX) + configuration = row["target"] if row["target"] != None else "android-datum64" + shipping_package(name = name + "_shipping", owner = "@oliphaunt_metadata//:product_" + product, artifacts = [":" + name], + ecosystem = "maven", package_name = row["name"], configuration = configuration, role = row["role"], suppliers = "//build_defs/release:no_suppliers") + packages.append(":" + name + "_shipping") + _assets_test(name = "android_runtime_assets_test", assets = ":android_release_assets", args = bun_test_entrypoint_args("android_runtime_assets_test"), + target_compatible_with = _LINUX, size = "small") + shipping_export(name = "android_shipping_export", packages = packages, qualification = [":android_runtime_assets_test", "//src/examples/native/react-native-expo:android_installed_test"], testonly = True, target_compatible_with = _LINUX) diff --git a/build_defs/native/android_lp64_config.bzl b/build_defs/native/android_lp64_config.bzl new file mode 100644 index 000000000..ccc87b34a --- /dev/null +++ b/build_defs/native/android_lp64_config.bzl @@ -0,0 +1,126 @@ +"""PostgreSQL 18.4 Bionic LP64 facts verified with the declared NDK/API profile. + +Both arm64 and x86_64 API24 compiler/configuration oracles agree on these +non-ISA facts. Use portable CRC, as in the Linux native slice. The registered +Android toolchain rejects NDK/API drift until this bounded profile is reviewed. +Version strings are derived from the canonical PG source pin. +""" + +ANDROID_LP64_CONFIG = { + "ALIGNOF_DOUBLE": "8", + "ALIGNOF_INT": "4", + "ALIGNOF_INT64_T": "8", + "ALIGNOF_LONG": "8", + "ALIGNOF_PG_INT128_TYPE": "16", + "ALIGNOF_SHORT": "2", + "BLCKSZ": "8192", + "CONFIGURE_ARGS": "\"Bazel Android Bionic ICU embedded profile\"", + "DEF_PGPORT": "5432", + "DEF_PGPORT_STR": "\"5432\"", + "DLSUFFIX": "\".so\"", + "HAVE_COMPUTED_GOTO": "1", + "HAVE_DECL_FDATASYNC": "1", + "HAVE_DECL_F_FULLFSYNC": "0", + "HAVE_DECL_MEMSET_S": "0", + "HAVE_DECL_POSIX_FADVISE": "1", + "HAVE_DECL_PREADV": "1", + "HAVE_DECL_PWRITEV": "1", + "HAVE_DECL_STRCHRNUL": "1", + "HAVE_DECL_STRLCAT": "1", + "HAVE_DECL_STRLCPY": "1", + "HAVE_DECL_STRNLEN": "1", + "HAVE_DECL_STRSEP": "1", + "HAVE_DECL_TIMINGSAFE_BCMP": "0", + "HAVE_EXECINFO_H": "1", + "HAVE_FSEEKO": "1", + "HAVE_GCC__ATOMIC_INT32_CAS": "1", + "HAVE_GCC__ATOMIC_INT64_CAS": "1", + "HAVE_GCC__SYNC_CHAR_TAS": "1", + "HAVE_GCC__SYNC_INT32_CAS": "1", + "HAVE_GCC__SYNC_INT32_TAS": "1", + "HAVE_GCC__SYNC_INT64_CAS": "1", + "HAVE_GETAUXVAL": "1", + "HAVE_GETIFADDRS": "1", + "HAVE_GETOPT": "1", + "HAVE_GETOPT_H": "1", + "HAVE_GETOPT_LONG": "1", + "HAVE_IFADDRS_H": "1", + "HAVE_INET_ATON": "1", + "HAVE_INET_PTON": "1", + "HAVE_INTTYPES_H": "1", + "HAVE_INT_OPTERR": "1", + "HAVE_INT_OPTRESET": "1", + "HAVE_INT_TIMEZONE": "1", + "HAVE_LIBM": "1", + "HAVE_MEMORY_H": "1", + "HAVE_MKDTEMP": "1", + "HAVE_POSIX_FADVISE": "1", + "HAVE_POSIX_FALLOCATE": "1", + "HAVE_PPOLL": "1", + "HAVE_PTHREAD": "1", + "HAVE_PTHREAD_BARRIER_WAIT": "1", + "HAVE_PTHREAD_PRIO_INHERIT": "1", + "HAVE_SOCKLEN_T": "1", + "HAVE_STDINT_H": "1", + "HAVE_STDLIB_H": "1", + "HAVE_STRERROR_R": "1", + "HAVE_STRINGS_H": "1", + "HAVE_STRING_H": "1", + "HAVE_STRLCAT": "1", + "HAVE_STRLCPY": "1", + "HAVE_STRNLEN": "1", + "HAVE_STRSEP": "1", + "HAVE_STRSIGNAL": "1", + "HAVE_STRUCT_OPTION": "1", + "HAVE_STRUCT_TM_TM_ZONE": "1", + "HAVE_SYSLOG": "1", + "HAVE_SYS_EPOLL_H": "1", + "HAVE_SYS_PERSONALITY_H": "1", + "HAVE_SYS_PRCTL_H": "1", + "HAVE_SYS_SIGNALFD_H": "1", + "HAVE_SYS_STAT_H": "1", + "HAVE_SYS_TYPES_H": "1", + "HAVE_TERMIOS_H": "1", + "HAVE_TYPEOF": "1", + "HAVE_UNION_SEMUN": "1", + "HAVE_UNISTD_H": "1", + "HAVE_USELOCALE": "1", + "HAVE_VISIBILITY_ATTRIBUTE": "1", + "HAVE_XLOCALE_H": "1", + "HAVE__BUILTIN_BSWAP16": "1", + "HAVE__BUILTIN_BSWAP32": "1", + "HAVE__BUILTIN_BSWAP64": "1", + "HAVE__BUILTIN_CLZ": "1", + "HAVE__BUILTIN_CONSTANT_P": "1", + "HAVE__BUILTIN_CTZ": "1", + "HAVE__BUILTIN_FRAME_ADDRESS": "1", + "HAVE__BUILTIN_OP_OVERFLOW": "1", + "HAVE__BUILTIN_POPCOUNT": "1", + "HAVE__BUILTIN_TYPES_COMPATIBLE_P": "1", + "HAVE__BUILTIN_UNREACHABLE": "1", + "HAVE__STATIC_ASSERT": "1", + "MAXIMUM_ALIGNOF": "8", + "MEMSET_LOOP_LIMIT": "1024", + "PACKAGE_BUGREPORT": "\"pgsql-bugs@lists.postgresql.org\"", + "PACKAGE_NAME": "\"PostgreSQL\"", + "PACKAGE_TARNAME": "\"postgresql\"", + "PACKAGE_URL": "\"https://www.postgresql.org/\"", + "PG_CXX_PRINTF_ATTRIBUTE": "printf", + "PG_C_PRINTF_ATTRIBUTE": "printf", + "PG_INT128_TYPE": "__int128", + "PG_KRB_SRVNAM": "\"postgres\"", + "RELSEG_SIZE": "131072", + "SIZEOF_LONG": "8", + "SIZEOF_LONG_LONG": "8", + "SIZEOF_OFF_T": "8", + "SIZEOF_SIZE_T": "8", + "SIZEOF_VOID_P": "8", + "STDC_HEADERS": "1", + "USE_ICU": "1", + "USE_SLICING_BY_8_CRC32C": "1", + "USE_SYSV_SHARED_MEMORY": "1", + "USE_UNNAMED_POSIX_SEMAPHORES": "1", + "XLOG_BLCKSZ": "8192", + "pg_restrict": "__restrict", + "restrict": "__restrict", +} diff --git a/build_defs/native/apple/BUILD.bazel b/build_defs/native/apple/BUILD.bazel new file mode 100644 index 000000000..e77431431 --- /dev/null +++ b/build_defs/native/apple/BUILD.bazel @@ -0,0 +1,53 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/foundation:bun.bzl", "bun_binary", "bun_test") +load("//build_defs/native/carriers:defs.bzl", "native_carrier_legal_inputs", "native_payload_helpers") + +package(default_visibility = ["//visibility:public"]) + +exports_files(glob(["*.mts"])) +exports_files(["bundled-consumer.swift"]) +exports_files(["static-carrier-consumer.bzl"]) + +filegroup(name = "framework_helpers", srcs = native_payload_helpers() + [ + "//build_defs/native/carriers:payload.mts", + "//build_defs/resources:shared.mts", + "//build_defs/native:host-runtime-test-helpers.mts", + "//src/native/runtime:tools/native-mobile-abi-contract.mts", + "//src/native/runtime:tools/finalize-native-runtime-carrier.mts", + "//src/native/runtime:tools/native-runtime-carrier-contract.mts", + "//src/native/sdks/swift:tools/swift-xcframework-contract.mts", + "//src/native/sdks/swift:tools/ios-carrier-manifest.mts", + "//src/native/sdks/swift:tools/native-legal-source-basis.mts", + "//src/native/sdks/swift:tools/swift-native-carrier-contract.mts", + "//src/database-resources:seeds/carrier-identities.mts", + "//:src/extensions/artifacts/packages/tools/contrib-carriers.mts", + "//:src/extensions/artifacts/packages/tools/extension-registry-packages.mts", + "//src/extensions/contracts:extension-target-profiles.mts", + "//src/extensions/tools:extension-upstream-licenses.mts", + "//src/native/mobile-bindings:tools/dependency-license-contract.mts", + "//src/wasix/runtime:tools/wasix-cargo-artifact-contract.mts", + "//:tools/packaging/rust-dependency-license-contract.mts", + "//tools/release:compatibility-version-parser.mts", + "//tools/release:extension-release-metadata.mts", + "//tools/release:release-artifact-targets.mts", + "//tools/release:release-graph.mts", + "//tools/release:release-history.mts", + "//src/database-resources:contracts/native-manifest.mts", + "//src/database-resources:contracts/contract.json", + "//:tools/packaging/archive-directory.mts", +]) + +bun_binary(name = "framework_envelope", entry_point = "framework-envelope.mts", data = [":framework_helpers"]) +bun_binary(name = "seed_envelope", entry_point = "seed-envelope.mts", data = ["//build_defs/resources:helpers"]) + +bun_test(name = "framework_contract_test", entry_point = "framework-envelope.test.mts", data = ["framework-envelope.mts", ":framework_helpers"], size = "small") +bun_test(name = "swift_candidate_contract_test", entry_point = "swift-candidate-contract.test.mts", data = ["swift-candidate-contract.mts", "//src/native/sdks/swift:tools/prepare-swift-release-consumer.mts"], size = "small") +bun_test(name = "static_carrier_consumer_contract_test", entry_point = "static-carrier-consumer.test.mts", data = ["static-carrier-consumer.mts", ":framework_helpers", "//src/native/sdks/swift:generator_sources"], size = "small") +bun_test( + name = "mobile_seed_contract_test", + entry_point = "//src/database-resources:seeds/package-mobile-carriers.test.mts", + data = ["//build_defs/resources:helpers"] + native_carrier_legal_inputs().keys(), + size = "small", +) + +source_quality_files() diff --git a/build_defs/native/apple/bundled-consumer.swift b/build_defs/native/apple/bundled-consumer.swift new file mode 100644 index 000000000..8c850def2 --- /dev/null +++ b/build_defs/native/apple/bundled-consumer.swift @@ -0,0 +1,36 @@ +import Foundation +import Oliphaunt + +@main +enum BundledRuntimeConsumer { + static func main() async throws { + guard ProcessInfo.processInfo.environment["OLIPHAUNT_RUNTIME_DIR"] == nil, + CommandLine.arguments.count == 3, + ["create", "reopen"].contains(CommandLine.arguments[1]) else { + fatalError("Expected bundled resources and create|reopen plus database directory") + } + guard let framework = Bundle(identifier: "dev.oliphaunt.liboliphaunt"), + let resources = framework.resourceURL, + FileManager.default.fileExists( + atPath: resources.appendingPathComponent("oliphaunt/runtime/manifest.properties").path + ) else { + fatalError("Installed dynamic framework did not deliver its bundled runtime resources") + } + let configuration = OliphauntConfiguration( + storage: .directory(URL(fileURLWithPath: CommandLine.arguments[2], isDirectory: true)), + username: "postgres", database: "postgres" + ) + let database = try await OliphauntDatabase.open(configuration: configuration) + if CommandLine.arguments[1] == "create" { + _ = try await database.execute("CREATE TABLE persisted(value int4 NOT NULL)") + _ = try await database.execute("INSERT INTO persisted VALUES ($1)", parameters: [.int32(42)]) + } + let result = try await database.query("SELECT value AS answer FROM persisted") + guard result.rows.count == 1, + try result.rows[0].value(named: "answer", as: Int32.self) == 42 else { + fatalError("Bundled Swift candidate failed the persisted query") + } + try await database.close() + print("installed-swift-\(CommandLine.arguments[1])-42") + } +} diff --git a/build_defs/native/apple/framework-envelope.mts b/build_defs/native/apple/framework-envelope.mts new file mode 100644 index 000000000..27736044e --- /dev/null +++ b/build_defs/native/apple/framework-envelope.mts @@ -0,0 +1,380 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + copyFileSync, + lstatSync, + mkdirSync, + readFileSync, + realpathSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { finalizeNativeRuntimeCarrier } from '../../../src/native/runtime/tools/finalize-native-runtime-carrier.mts'; +import { + compareNativeMobileAbiReceipts, + nativeMobileAbiReceipt, +} from '../../../src/native/runtime/tools/native-mobile-abi-contract.mts'; +import { requiredRuntimeMemberPaths } from '../../../src/native/runtime/tools/native-runtime-payload.mts'; +import { writeIosCarrierManifest } from '../../../src/native/sdks/swift/tools/ios-carrier-manifest.mts'; +import { currentNativeLegalSourceBasis } from '../../../src/native/sdks/swift/tools/native-legal-source-basis.mts'; +import { validateAppleXcframeworkAsset } from '../../../src/native/sdks/swift/tools/swift-xcframework-contract.mts'; +import { + createDeterministicTar, + createDeterministicZip, +} from '../../../tools/packaging/archive-directory.mts'; +import { + inspectPlatformBinaryBuffer, + inspectPlatformBinaryTree, +} from '../../../tools/packaging/platform-binary-contract.mts'; +import { + canonicalGzipSync, + extractPortableArchiveTree, +} from '../../../tools/packaging/portable-archive.mts'; +import { + assertReleaseNoticesInDirectory, + stageReleaseNotices, +} from '../../../tools/packaging/release-notices.mts'; +import { APPLE_PLATFORM_COMPATIBILITY } from '../../../tools/release/platform-compatibility-policy.mts'; +import { materializeInputs, privateWork, readSpecification, run } from '../../resources/shared.mts'; +import { copyDeclaredTree } from '../carriers/payload.mts'; + +const FRAMEWORK = 'liboliphaunt.xcframework'; +const INSTALL_NAME = '@rpath/liboliphaunt.framework/liboliphaunt'; +const SLICES = [ + { + target: 'macos-arm64', + identifier: 'macos-arm64', + platform: APPLE_PLATFORM_COMPATIBILITY.macos, + }, + { target: 'ios-arm64', identifier: 'ios-arm64', platform: APPLE_PLATFORM_COMPATIBILITY.ios }, + { + target: 'ios-arm64-simulator', + identifier: 'ios-arm64-simulator', + platform: APPLE_PLATFORM_COMPATIBILITY.iosSimulator, + }, +]; + +/** Admission uses the shared Mach-O parser, then requires a real dynamic library. */ +export function inspectDynamicFrameworkBinary(bytes: Buffer, target: string) { + const expected = SLICES.find((slice) => slice.target === target); + assert(expected, `unsupported Apple framework slice ${target}`); + const inspected = inspectPlatformBinaryBuffer(bytes, { + target: 'ios-xcframework', + label: target, + }); + assert.equal(inspected.format, 'macho', 'framework binary must be Mach-O'); + assert.equal(bytes.readUInt32LE(0), 0xfeedfacf, 'framework must be a thin arm64 Mach-O'); + assert.equal(bytes.readUInt32LE(12), 6, 'public base framework must be MH_DYLIB'); + assert.equal(inspected.slices.length, 1, 'framework must contain exactly one arm64 slice'); + assert.equal( + inspected.slices[0].platform, + expected.platform.id, + 'framework binary platform disagrees with its slice', + ); + return inspected; +} + +/** Public relative paths and content, never the workspace or sandbox location. */ +export function runtimeContentIdentity( + entries: Record, + context: unknown, +): string { + const hash = createHash('sha256'); + const field = (bytes: Uint8Array) => { + const size = Buffer.alloc(8); + size.writeBigUInt64BE(BigInt(bytes.byteLength)); + hash.update(size).update(bytes); + }; + field(Buffer.from('oliphaunt-native-apple-runtime-v1')); + field(Buffer.from(JSON.stringify(context))); + for (const name of Object.keys(entries).sort()) { + assert( + name && + !path.isAbsolute(name) && + !name.includes('\\') && + !name.split('/').some((part) => ['', '.', '..'].includes(part)), + 'identity requires stable public relative paths', + ); + field(Buffer.from(name)); + field(entries[name]); + } + return `apple-runtime-${hash.digest('hex')}`; +} + +function tool(specification, name: string, args: string[], work: string): string { + // Tool Files and their runtime closure are declared by the Mac SDK repository. + return run( + realpathSync(specification.tools[name]), + args, + { HOME: work, TMPDIR: work, LC_ALL: 'C', LANG: 'C' }, + work, + ); +} + +function checkPublicAbi(specification, binary: string, target: string, work: string): void { + inspectDynamicFrameworkBinary(readFileSync(binary), target); + const symbols = new Set( + tool(specification, 'nm', ['-gU', binary], work) + .split(/\r?\n/u) + .map((line) => line.trim().split(/\s+/u).at(-1)), + ); + const header = readFileSync(specification.publicHeader, 'utf8'); + const publicFunctions = [ + ...header.matchAll(/^OLIPHAUNT_API\s+[^;]+?\b(oliphaunt_\w+)\s*\(/gmu), + ].map((match) => match[1]); + assert(publicFunctions.length > 0, 'canonical public header has no API functions'); + for (const name of publicFunctions) + assert(symbols.has(`_${name}`), `${target}: missing canonical public API ${name}`); + if (target.startsWith('ios-')) { + const imports = tool(specification, 'nm', ['-u', binary], work) + .split(/\r?\n/u) + .map((line) => line.trim().split(/\s+/u).at(-1)); + assert( + !imports.some((name) => + /^_(?:shmget|shmat|shmdt|shmctl|shm_open|shm_unlink|semget|semop|semctl|sem_open|sem_close|sem_unlink|sem_wait|sem_post|sem_trywait|sem_init|sem_destroy)$/u.test( + name ?? '', + ), + ), + `${target}: mobile framework imports process-global IPC`, + ); + for (const name of [ + 'dsnowball_init', + 'dsnowball_lexize', + 'pg_finfo_dsnowball_init', + 'pg_finfo_dsnowball_lexize', + 'oliphaunt_builtin_dict_snowball_Pg_magic_func', + ]) + assert(symbols.has(`_${name}`), `${target}: missing builtin Snowball ${name}`); + } + const installNames = tool(specification, 'otool', ['-D', binary], work) + .split(/\r?\n/u) + .slice(1) + .filter(Boolean) + .map((line) => line.trim()); + assert.deepEqual(installNames, [INSTALL_NAME], `${target}: unexpected framework install name`); +} + +function fixEmbeddedModules(specification, directory: string, work: string): void { + for (const name of ['dict_snowball', 'plpgsql']) { + const binary = path.join(directory, `${name}.dylib`); + assert(lstatSync(binary).isFile(), `missing actual embedded module ${name}`); + tool( + specification, + 'install_name_tool', + ['-change', '@rpath/liboliphaunt.dylib', INSTALL_NAME, binary], + work, + ); + const commands = tool(specification, 'otool', ['-l', binary], work); + for (const match of commands.matchAll( + /\bcmd LC_RPATH\s+cmdsize \d+\s+path (.*?) \(offset \d+\)/gu, + )) { + if (path.isAbsolute(match[1])) + tool(specification, 'install_name_tool', ['-delete_rpath', match[1], binary], work); + } + tool(specification, 'strip', ['-S', binary], work); + const dependencies = tool(specification, 'otool', ['-L', binary], work); + assert( + dependencies.includes(INSTALL_NAME), + `${name}: embedded module does not link the public framework`, + ); + assert( + !dependencies.includes('@rpath/liboliphaunt.dylib '), + `${name}: stale standalone runtime install name`, + ); + inspectPlatformBinaryBuffer(readFileSync(binary), { target: 'ios-xcframework', label: name }); + } +} + +export async function packageAppleRuntime(specification): Promise { + assert.equal( + process.platform, + 'darwin', + 'Apple framework finalization requires the declared Mac SDK executor', + ); + const work = privateWork(path.resolve(specification.swiftpm)); + try { + const payload = path.join(work, 'payload'); + copyDeclaredTree( + specification.payload, + payload, + requiredRuntimeMemberPaths('macos-arm64', 'runtime/bin'), + ); + const legal = materializeInputs(specification.notices, path.join(work, 'legal')); + const framework = path.join(work, FRAMEWORK); + extractPortableArchiveTree(realpathSync(specification.intermediate), framework, FRAMEWORK); + tool(specification, 'plutil', ['-convert', 'xml1', path.join(framework, 'Info.plist')], work); + const receipts = new Map(); + const identityInputs: Record = { + 'runtime-payload.tar': await createDeterministicTar(payload), + 'legal-sources.tar': await createDeterministicTar(legal), + }; + for (const slice of SLICES) { + const directory = path.join(framework, slice.identifier, 'liboliphaunt.framework'); + const binary = path.join(directory, 'liboliphaunt'); + tool(specification, 'strip', ['-S', binary], work); + checkPublicAbi(specification, binary, slice.target, work); + identityInputs[`${slice.identifier}/liboliphaunt.framework/liboliphaunt`] = + readFileSync(binary); + identityInputs[`${slice.identifier}/liboliphaunt.framework/Headers.tar`] = + await createDeterministicTar(path.join(directory, 'Headers')); + const headers = materializeInputs( + specification.headers[slice.target], + path.join(work, 'headers', slice.target), + ); + const receipt = Buffer.from(nativeMobileAbiReceipt(headers, slice.target)); + receipts.set(slice.target, receipt); + identityInputs[`provenance/native-mobile-abi/${slice.target}.properties`] = receipt; + mkdirSync(path.dirname(specification.receipts[slice.target]), { recursive: true }); + writeFileSync(specification.receipts[slice.target], receipt, { mode: 0o644 }); + } + compareNativeMobileAbiReceipts( + 'ios-datum64', + [...receipts].map(([target, bytes]) => ({ label: target, text: bytes.toString('utf8') })), + ); + + const macosModules = path.join(work, 'framework-modules'); + copyDeclaredTree(path.join(payload, 'lib/modules'), macosModules); + fixEmbeddedModules(specification, macosModules, work); + identityInputs['macos-arm64/runtime/files/lib/modules.tar'] = + await createDeterministicTar(macosModules); + + const resources = new Map(); + for (const domain of ['macos-arm64', 'ios-datum64']) { + const output = path.join(work, domain); + const identity = runtimeContentIdentity(identityInputs, { + version: specification.version, + domain, + artifact: 'native-direct', + registry: 'not-required', + }); + run( + realpathSync(specification.formatter), + [ + '--output', + output, + '--liboliphaunt-native-version', + specification.version, + '--extension-target', + domain, + '--runtime-cache-identity', + identity, + ], + { + HOME: work, + TMPDIR: work, + LC_ALL: 'C', + LANG: 'C', + OLIPHAUNT_INSTALL_DIR: path.join(payload, 'runtime'), + OLIPHAUNT_EMBEDDED_MODULE_DIR: + domain === 'macos-arm64' ? macosModules : path.join(payload, 'lib/modules'), + OLIPHAUNT_RUNTIME_CACHE_DIR: path.join(work, 'cache', domain), + }, + work, + ); + const root = path.join(output, 'oliphaunt'); + if (domain === 'macos-arm64') { + copyDeclaredTree(macosModules, path.join(root, 'runtime/files/lib/modules')); + // The embedded engine and subprocess server have distinct core modules. + // Preserve the ordinary PostgreSQL modules alongside the framework ones. + for (const name of ['dict_snowball', 'plpgsql']) + copyFileSync( + path.join(payload, 'runtime/lib/postgresql', `${name}.dylib`), + path.join(root, 'runtime/files/lib/postgresql', `${name}.dylib`), + ); + } else { + const provenance = path.join(root, 'provenance/native-mobile-abi'); + mkdirSync(provenance, { recursive: true }); + for (const [target, receipt] of receipts) + writeFileSync(path.join(provenance, `${target}.properties`), receipt, { mode: 0o644 }); + } + finalizeNativeRuntimeCarrier(root, domain); + resources.set(domain, root); + } + for (const slice of SLICES) { + const destination = path.join( + framework, + slice.identifier, + 'liboliphaunt.framework/Resources/oliphaunt', + ); + assert( + !lstatExists(destination), + 'maintained framework must not contain a competing runtime resource tree', + ); + const source = resources.get(slice.target === 'macos-arm64' ? 'macos-arm64' : 'ios-datum64'); + assert(source, 'missing formatted runtime resource domain'); + copyDeclaredTree(source, destination); + } + stageReleaseNotices(framework, { profile: 'native-runtime', sourceRoot: legal }); + assertReleaseNoticesInDirectory(framework, { profile: 'native-runtime', sourceRoot: legal }); + await inspectPlatformBinaryTree(framework, { target: 'ios-xcframework' }); + writeFileSync( + specification.swiftpm, + await createDeterministicZip(framework, { keepParent: true }), + { mode: 0o644 }, + ); + await validateAppleXcframeworkAsset(specification.swiftpm); + const archiveRoot = path.join(work, `liboliphaunt-${specification.version}-ios-xcframework`); + mkdirSync(archiveRoot); + copyDeclaredTree(framework, path.join(archiveRoot, FRAMEWORK)); + stageReleaseNotices(archiveRoot, { profile: 'native-runtime', sourceRoot: legal }); + writeFileSync( + specification.archive, + canonicalGzipSync(await createDeterministicTar(archiveRoot)), + { mode: 0o644 }, + ); + for (const [name, domain] of [ + ['resources', 'ios-datum64'], + ['macos_resources', 'macos-arm64'], + ]) { + // The macOS projection is an internal candidate-consumer input, drawn + // from the same formatter result already embedded in its framework. + const resourceRoot = path.join(work, `resource-archive-${domain}`); + mkdirSync(resourceRoot); + const source = resources.get(domain); + assert(source, `missing formatted ${domain} runtime resources`); + copyDeclaredTree(source, path.join(resourceRoot, 'oliphaunt')); + stageReleaseNotices(resourceRoot, { profile: 'native-runtime-resources', sourceRoot: legal }); + writeFileSync( + specification[name], + canonicalGzipSync(await createDeterministicTar(resourceRoot)), + { mode: 0o644 }, + ); + } + for (const name of ['swiftpm', 'archive', 'resources', 'macos_resources']) + chmodSync(specification[name], 0o644); + writeIosCarrierManifest(specification.ios_manifest, { + baseAssetDir: path.dirname(specification.swiftpm), + baseRuntimeVersion: specification.version, + baseTag: `liboliphaunt-native-v${specification.version}`, + baseSourceBasis: currentNativeLegalSourceBasis, + baseLegalSourceRoot: legal, + }); + writeFileSync( + specification.checksums, + `${['swiftpm', 'archive', 'resources'] + .map( + (name) => + `${createHash('sha256').update(readFileSync(specification[name])).digest('hex')} ./${path.basename(specification[name])}`, + ) + .sort() + .join('\n')}\n`, + { mode: 0o644 }, + ); + } finally { + rmSync(work, { recursive: true, force: true }); + } +} + +function lstatExists(file: string): boolean { + try { + lstatSync(file); + return true; + } catch (error) { + if (error.code === 'ENOENT') return false; + throw error; + } +} + +if (import.meta.main) await packageAppleRuntime(readSpecification()); diff --git a/build_defs/native/apple/framework-envelope.test.mts b/build_defs/native/apple/framework-envelope.test.mts new file mode 100644 index 000000000..967f55bfb --- /dev/null +++ b/build_defs/native/apple/framework-envelope.test.mts @@ -0,0 +1,72 @@ +import { expect, test } from 'bun:test'; +import { inspectDynamicFrameworkBinary, runtimeContentIdentity } from './framework-envelope.mts'; + +// Independent minimal physical Mach-O fixture; no filename/header inference. +function image(platform: number, minimum: number, type = 6): Buffer { + const bytes = Buffer.alloc(56); + bytes.writeUInt32LE(0xfeedfacf, 0); + bytes.writeUInt32LE(0x0100000c, 4); + bytes.writeUInt32LE(type, 12); + bytes.writeUInt32LE(1, 16); + bytes.writeUInt32LE(24, 20); + bytes.writeUInt32LE(0x32, 32); + bytes.writeUInt32LE(24, 36); + bytes.writeUInt32LE(platform, 40); + bytes.writeUInt32LE(minimum << 16, 44); + bytes.writeUInt32LE(minimum << 16, 48); + return bytes; +} + +test('the public framework admits actual dynamic binaries for all three Apple slices', () => { + for (const [target, platform, minimum] of [ + ['macos-arm64', 1, 14], + ['ios-arm64', 2, 17], + ['ios-arm64-simulator', 7, 17], + ] as const) + expect(inspectDynamicFrameworkBinary(image(platform, minimum), target).slices).toHaveLength(1); +}); + +test('a static object, swapped device/simulator image or incompatible OS floor cannot replace the public framework', () => { + expect(() => inspectDynamicFrameworkBinary(image(2, 17, 1), 'ios-arm64')).toThrow(/MH_DYLIB/u); + expect(() => inspectDynamicFrameworkBinary(image(7, 17), 'ios-arm64')).toThrow( + /platform disagrees/u, + ); + expect(() => inspectDynamicFrameworkBinary(image(2, 18), 'ios-arm64')).toThrow(/minimum/u); + expect(() => inspectDynamicFrameworkBinary(Buffer.from('!\n'), 'ios-arm64')).toThrow(); +}); + +test('runtime identity commits content and public names, independent of source location and entry order', () => { + const header = Buffer.from('public ABI'); + const runtime = Buffer.from('dynamic runtime'); + const first = runtimeContentIdentity( + { 'Headers/oliphaunt.h': header, 'runtime/liboliphaunt': runtime }, + { domain: 'ios-datum64' }, + ); + expect(first).toBe( + runtimeContentIdentity( + { 'runtime/liboliphaunt': runtime, 'Headers/oliphaunt.h': header }, + { domain: 'ios-datum64' }, + ), + ); + expect(first).toMatch(/^apple-runtime-[0-9a-f]{64}$/u); + expect(first).not.toBe( + runtimeContentIdentity( + { 'Headers/oliphaunt.h': header, 'runtime/liboliphaunt': Buffer.from('changed runtime') }, + { domain: 'ios-datum64' }, + ), + ); + expect(first).not.toBe( + runtimeContentIdentity( + { 'Headers/oliphaunt.h': header, 'runtime/liboliphaunt': runtime }, + { domain: 'macos-arm64' }, + ), + ); + expect(first).not.toBe( + runtimeContentIdentity( + { 'Headers/other.h': header, 'runtime/liboliphaunt': runtime }, + { domain: 'ios-datum64' }, + ), + ); + for (const name of ['/sandbox/runtime', '../runtime', 'runtime\\file', 'runtime/./file']) + expect(() => runtimeContentIdentity({ [name]: runtime }, {})).toThrow(/public relative paths/u); +}); diff --git a/build_defs/native/apple/runtime-final.test.mts b/build_defs/native/apple/runtime-final.test.mts new file mode 100644 index 000000000..c1527dbbb --- /dev/null +++ b/build_defs/native/apple/runtime-final.test.mts @@ -0,0 +1,109 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { readFileSync, realpathSync } from 'node:fs'; +import { + compareNativeMobileAbiReceipts, + parseNativeMobileAbiReceipt, +} from '../../../src/native/runtime/tools/native-mobile-abi-contract.mts'; +import { bindNativeRuntimeResourceManifest } from '../../../src/native/runtime/tools/native-runtime-carrier-contract.mts'; +import { validateAppleXcframeworkAsset } from '../../../src/native/sdks/swift/tools/swift-xcframework-contract.mts'; +import { readPortableArchiveEntries } from '../../../tools/packaging/portable-archive.mts'; +import { assertMatchingArchiveTrees } from '../../resources/mobile_resource_contract.mts'; +import { inspectDynamicFrameworkBinary } from './framework-envelope.mts'; + +const [archive, swiftpm, resources, checksums, header, iosManifest, ...receipts] = + process.argv.slice(2); +assert.equal(receipts.length, 3, 'final Apple resources require all three actual ABI receipts'); +const [physicalArchive, physicalSwiftpm, physicalResources] = [archive, swiftpm, resources].map( + (file) => realpathSync(file), +); +await validateAppleXcframeworkAsset(physicalSwiftpm); +const framework = readPortableArchiveEntries(physicalSwiftpm); +const github = readPortableArchiveEntries(physicalArchive); +const runtimeResources = readPortableArchiveEntries(physicalResources); +const manifest = JSON.parse(readFileSync(iosManifest, 'utf8')); +assert.equal(manifest.base.product, 'liboliphaunt-native'); +assert.equal(manifest.base.tag, `liboliphaunt-native-v${manifest.base.version}`); +assert.deepEqual(manifest.extensions, []); +assert.deepEqual(manifest.carriers, []); +assert.deepEqual(manifest.legal.extensions, []); +for (const [role, file, entries] of [ + ['base-xcframework', swiftpm, framework], + ['runtime-resources', resources, runtimeResources], +]) { + const bytes = readFileSync(file); + const asset = manifest.base.assets.find((row) => row.role === role); + assert(asset, `missing actual ${role} base asset`); + assert.equal(asset.name, file.split('/').at(-1)); + assert.equal(asset.bytes, bytes.byteLength); + assert.equal(asset.sha256, createHash('sha256').update(bytes).digest('hex')); + const legal = manifest.legal.base.find((row) => row.assetRole === role); + assert(legal, `missing actual ${role} legal contract`); + for (const row of legal.files) { + const entry = entries.get(row.member); + assert(entry?.isFile && !entry.isSymbolicLink, `missing base legal member ${row.member}`); + const actual = entry.data(); + assert.equal(actual.byteLength, row.bytes); + assert.equal(createHash('sha256').update(actual).digest('hex'), row.sha256); + } +} +const prefix = 'liboliphaunt.xcframework/'; +assertMatchingArchiveTrees(github, prefix, framework, prefix); +const regular = (entries: typeof framework, name: string) => { + const entry = entries.get(name); + assert(entry?.isFile && !entry.isSymbolicLink, `missing regular Apple carrier member ${name}`); + return entry.data(); +}; +const runtimeManifest = regular(runtimeResources, 'oliphaunt/runtime/manifest.properties'); +assert(runtimeManifest.equals(bindNativeRuntimeResourceManifest(runtimeManifest, 'ios-datum64'))); +const abi = receipts.map((file) => ({ text: readFileSync(file, 'utf8'), label: file })); +compareNativeMobileAbiReceipts('ios-datum64', abi); +for (const [identifier, target] of [ + ['ios-arm64', 'ios-arm64'], + ['ios-arm64-simulator', 'ios-arm64-simulator'], + ['macos-arm64', 'macos-arm64'], +]) { + const slice = `${prefix}${identifier}/liboliphaunt.framework/`; + inspectDynamicFrameworkBinary(regular(framework, `${slice}liboliphaunt`), target); + assert(regular(framework, `${slice}Headers/oliphaunt.h`).equals(readFileSync(header))); + if (target.startsWith('ios-')) + assertMatchingArchiveTrees( + framework, + `${slice}Resources/oliphaunt/`, + runtimeResources, + 'oliphaunt/', + ); + const carrier = `${slice}Resources/oliphaunt/`; + for (const { text, label } of abi) { + const abiTarget = parseNativeMobileAbiReceipt(text, label).get('target'); + // The iOS resource contract preserves all genuine domain receipts in each slice. + if (target.startsWith('ios-')) + assert( + regular(framework, `${carrier}provenance/native-mobile-abi/${abiTarget}.properties`).equals( + Buffer.from(text), + ), + ); + } +} +const actualChecksums = new Map( + readFileSync(checksums, 'utf8') + .trim() + .split('\n') + .map((line) => { + const match = /^([a-f0-9]{64}) {2}\.\/([^/]+)$/u.exec(line); + assert(match, 'Apple checksum rows require canonical public names'); + return [match[2], match[1]]; + }), +); +assert.equal(actualChecksums.size, 3); +for (const file of [archive, swiftpm, resources]) { + const name = file.split('/').at(-1); + assert(name, 'Apple checksum input requires its actual asset name'); + assert.equal( + actualChecksums.get(name), + createHash('sha256').update(readFileSync(file)).digest('hex'), + ); +} +console.log( + 'Final Apple GitHub framework and iOS resources agree with the qualified native SwiftPM candidate', +); diff --git a/build_defs/native/apple/seed-envelope.mts b/build_defs/native/apple/seed-envelope.mts new file mode 100644 index 000000000..176345d87 --- /dev/null +++ b/build_defs/native/apple/seed-envelope.mts @@ -0,0 +1,51 @@ +import assert from 'node:assert/strict'; +import { chmodSync, copyFileSync, mkdirSync, rmSync } from 'node:fs'; +import path from 'node:path'; +import { packageMobileSeedCarriers } from '../../../src/database-resources/seeds/package-mobile-carriers.mts'; +import { materializeInputs, privateWork, readSpecification } from '../../resources/shared.mts'; + +export async function packageSwiftSeedEnvelope(specification) { + const version = specification.version; + const expected = [`database-resources-${version}-icu-data.tar.gz`]; + for (const profile of ['standard', 'icu']) { + const stem = `database-resources-${version}-seed-native-ios-datum64-${profile}`; + expected.push(`${stem}.tar.zst`, `${stem}.json`); + } + assert.deepEqual( + specification.assets.map((input) => path.basename(input)).sort(), + expected.sort(), + 'Swift resources require exactly the canonical standard seed, ICU seed and ICU archive', + ); + const output = path.resolve(specification.output); + const work = privateWork(output); + try { + const legalRoot = materializeInputs(specification.notices, path.join(work, 'legal')); + const assets = path.join(work, 'assets'); + mkdirSync(assets); + for (const input of specification.assets) { + const destination = path.join(assets, path.basename(input)); + copyFileSync(input, destination); + chmodSync(destination, 0o644); + } + const results = await packageMobileSeedCarriers({ + targets: ['ios-datum64'], + profiles: ['standard', 'icu'], + assetDir: assets, + workDir: path.join(work, 'mobile'), + version, + contract: specification.contract, + noticeSourceRoot: legalRoot, + }); + const archive = path.join(assets, `database-resources-${version}-swift.zip`); + assert.deepEqual( + results, + [archive], + 'the existing formatter must emit one canonical Swift ZIP', + ); + copyFileSync(archive, output); + } finally { + rmSync(work, { recursive: true, force: true }); + } +} + +if (import.meta.main) await packageSwiftSeedEnvelope(readSpecification()); diff --git a/build_defs/native/apple/static-carrier-consumer.bzl b/build_defs/native/apple/static-carrier-consumer.bzl new file mode 100644 index 000000000..ad8b259b4 --- /dev/null +++ b/build_defs/native/apple/static-carrier-consumer.bzl @@ -0,0 +1,72 @@ +"""Installed current-core C ABI and generated static-extension registration.""" + +load("@oliphaunt_metadata//:metadata.bzl", "PRODUCTS") +load("@oliphaunt_toolchain_metadata//:apple-platforms.bzl", "APPLE_DEPLOYMENT_TARGETS") +load("//build_defs/extensions:contrib_carriers.bzl", "native_contrib_carrier_legal") +load("//build_defs/extensions:final_leaf.bzl", "ExtensionFinalLeafInfo") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") + +_SWIFT_TOOLCHAIN = "@rules_swift//toolchains:toolchain_type" + +def _runfile(ctx, file): + return file.short_path[3:] if file.short_path.startswith("../") else ctx.workspace_name + "/" + file.short_path + +def _consumer_impl(ctx): + info = ctx.toolchains[_SWIFT_TOOLCHAIN].swift_toolchain + tools = depset(transitive = [depset(config.additional_tools) for config in info.tool_configs.values()]).to_list() + selected = {} + for mode in ["clang", "clang++"]: + files = [file for file in tools if file.short_path.endswith("/toolchain/bin/" + mode)] + if len(files) != 1: + fail("Packaged Apple C consumer requires exactly one declared Xcode " + mode) + selected[mode] = files[0] + sdk_files = [file for file in tools if "/sdk_macosx/" in file.short_path] + receipts = [file for file in tools if file.basename == "receipt.json"] + if not sdk_files or len(receipts) != 1: + fail("Packaged Apple C consumer requires one declared macOS SDK and receipt") + + version = PRODUCTS["liboliphaunt-native"]["version"] + inputs = [ctx.file.base, ctx.file.ios_resources, ctx.file.macos_resources, ctx.file.base_manifest, ctx.file.owner_catalog] + leaves = [] + if len(ctx.attr.leaves) != 1 or not ctx.attr.extensions: + fail("Current-core registration qualification requires one contrib carrier and nonempty selected members") + for target in ctx.attr.leaves: + leaf = target[ExtensionFinalLeafInfo] + if leaf.product != "oliphaunt-extension-contrib-pg18" or leaf.family != "native" or leaf.target != "ios-xcframework" or leaf.metadata["runtimeVersion"] != version: + fail("Packaged Apple registration requires actual iOS final leaves with the selected current core version") + inputs += leaf.github + [leaf.frozen] + leaves.append({"product": leaf.product, "owner": leaf.owner, "version": leaf.version, + "runtimeVersion": leaf.metadata["runtimeVersion"], "sqlNames": sorted([member["sqlName"] for member in leaf.metadata["members"]]), + "github": [_runfile(ctx, file) for file in leaf.github], "frozen": _runfile(ctx, leaf.frozen)}) + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode({ + "version": version, "basePackageVersion": PRODUCTS["oliphaunt-swift"]["version"], + "base": _runfile(ctx, ctx.file.base), "iosResources": _runfile(ctx, ctx.file.ios_resources), + "macosResources": _runfile(ctx, ctx.file.macos_resources), "baseManifest": _runfile(ctx, ctx.file.base_manifest), + "ownerCatalog": _runfile(ctx, ctx.file.owner_catalog), "leaves": leaves, "extensions": ctx.attr.extensions, + "clang": _runfile(ctx, selected["clang"]), "clangxx": _runfile(ctx, selected["clang++"]), + "sdkFile": _runfile(ctx, sdk_files[0]), "receipt": _runfile(ctx, receipts[0]), + "triple": "arm64-apple-macosx" + APPLE_DEPLOYMENT_TARGETS["package_macos"], + }) + "\n") + return bun_test_entrypoint(ctx, ctx.file._runner, [spec], tools + inputs + [spec] + ctx.files._helpers, + source_files = [ctx.file._runner] + ctx.files._helpers, runfiles_argument = True) + +_consumer_test = rule( + implementation = _consumer_impl, + test = True, + toolchains = [_SWIFT_TOOLCHAIN] + BUN_SOURCE_TOOLCHAINS, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "base": attr.label(mandatory = True, allow_single_file = [".zip"]), + "ios_resources": attr.label(mandatory = True, allow_single_file = [".tar.gz"]), + "macos_resources": attr.label(mandatory = True, allow_single_file = [".tar.gz"]), + "base_manifest": attr.label(mandatory = True, allow_single_file = [".json"]), + "leaves": attr.label_list(mandatory = True, providers = [ExtensionFinalLeafInfo]), + "extensions": attr.string_list(mandatory = True), + "owner_catalog": attr.label(default = "//src/extensions/generated/sdk:extensions.json", allow_single_file = [".json"]), + "_runner": attr.label(default = "//build_defs/native/apple:static-carrier-consumer.mts", allow_single_file = True), + "_helpers": attr.label_list(default = ["//build_defs/native/apple:framework_helpers", "//src/native/sdks/swift:generator_sources"] + native_contrib_carrier_legal(), allow_files = True), + }), +) + +def apple_static_carrier_consumer_test(name, args = [], **kwargs): + _consumer_test(name = name, args = bun_test_entrypoint_args(name) + args, **kwargs) diff --git a/build_defs/native/apple/static-carrier-consumer.mts b/build_defs/native/apple/static-carrier-consumer.mts new file mode 100644 index 000000000..2dc722382 --- /dev/null +++ b/build_defs/native/apple/static-carrier-consumer.mts @@ -0,0 +1,382 @@ +/** Packaged current native core and actual Apple static carriers; no Swift SDK construction. */ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { + copyFileSync, + mkdirSync, + readdirSync, + readFileSync, + realpathSync, + renameSync, + statSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { buildIosCarrierManifest } from '../../../src/native/sdks/swift/tools/ios-carrier-manifest.mts'; +import { renderExtensionProducts } from '../../../src/native/sdks/swift/tools/render-extension-products.mts'; +import { + archiveLogicalTreeRows, + extractPortableArchiveTree, + readPortableArchiveEntries, +} from '../../../tools/packaging/portable-archive.mts'; + +const sha256 = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +const json = (file: string) => JSON.parse(readFileSync(file, 'utf8')); +const relativeFile = (value: string) => { + assert.equal(typeof value, 'string'); + assert.ok(value && !value.includes('\\') && !path.posix.isAbsolute(value)); + assert.ok(value.split('/').every((part) => part && part !== '.' && part !== '..')); + return value; +}; + +function filesAt(input: string): string[] { + const source = realpathSync(input); + if (statSync(source).isFile()) return [source]; + assert.ok(statSync(source).isDirectory(), 'carrier input must be a declared file or tree'); + return readdirSync(source, { withFileTypes: true }).flatMap((entry) => { + const file = path.join(source, entry.name); + assert.ok( + entry.isFile() || entry.isDirectory() || (entry.isSymbolicLink() && statSync(file).isFile()), + ); + return filesAt(file); + }); +} + +/** Relocate exact original archives; all frozen identity fields remain unchanged. */ +export function stageNativeStaticLeaf( + leaf: any, + root: string, + runtimeVersion: string, + expectedTarget = 'ios-xcframework', +) { + assert( + ['ios-xcframework', 'android-arm64-v8a', 'android-x86_64'].includes(expectedTarget), + 'Unsupported static carrier target', + ); + if (leaf.target !== undefined) + assert.equal(leaf.target, expectedTarget, 'Static leaf target differs'); + assert.equal(leaf.runtimeVersion, runtimeVersion, 'static carrier holds a different native core'); + const frozen = json(leaf.frozen); + assert.equal(frozen.product, leaf.product); + assert.equal(frozen.version, leaf.version); + assert.equal(frozen.releaseProduct ?? frozen.product, leaf.owner); + assert.equal(frozen.compatibility.nativeRuntimeVersion, runtimeVersion); + const members = frozen.extensions ?? [frozen]; + assert.deepEqual(members.map((member: any) => member.sqlName).sort(), [...leaf.sqlNames].sort()); + const actualFiles = leaf.github.flatMap(filesAt); + const physical = new Map( + actualFiles.map((file: string) => [path.basename(file), file]), + ); + assert.equal(physical.size, actualFiles.length, 'carrier archive basenames must be unique'); + mkdirSync(root, { recursive: true }); + const stageBytes = (row: any, bytes: Uint8Array, destination: string) => { + assert.equal(path.basename(relativeFile(row.name)), row.name); + assert.equal(bytes.length, row.bytes, `${row.name} frozen size differs`); + assert.equal(sha256(bytes), row.sha256, `${row.name} frozen SHA-256 differs`); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, bytes); + return { ...row, path: destination }; + }; + const direct = new Map(); + for (const row of frozen.carrierAssets ?? members[0].assets) { + assert.equal(row.family, 'native'); + assert.equal(row.target, expectedTarget); + const file = physical.get(row.name); + assert.ok(file, `missing actual packaged carrier ${row.name}`); + assert.ok(!direct.has(row.name), 'frozen carrier archive basenames must be unique'); + direct.set( + row.name, + stageBytes(row, readFileSync(file), path.join(root, 'archives', row.name)), + ); + } + assert.equal(direct.size, physical.size, 'actual carrier files must match frozen direct assets'); + const bundles = new Map>(); + const staged = members.map((member: any) => ({ + ...member, + assets: member.assets.map((row: any) => { + if (row.carrierAsset === undefined) { + const archive = direct.get(row.name); + assert.ok(archive, `missing direct member archive ${row.name}`); + return { ...row, path: archive.path }; + } + const outer = direct.get(row.carrierAsset); + assert.ok(outer, 'member archive lacks its original aggregate carrier'); + if (!bundles.has(outer.path)) bundles.set(outer.path, readPortableArchiveEntries(outer.path)); + const name = `${relativeFile(row.carrierRoot)}/${relativeFile(row.memberPath)}`; + const entry = bundles.get(outer.path)?.get(name); + assert.ok(entry?.isFile, `missing original nested member ${name}`); + return stageBytes( + row, + entry.data(), + path.join(root, 'members', relativeFile(member.sqlName), row.name), + ); + }), + })); + const document = frozen.extensions + ? { ...frozen, carrierAssets: [...direct.values()], extensions: staged } + : staged[0]; + const output = path.join(root, 'extension-artifacts.json'); + writeFileSync(output, `${JSON.stringify(document, null, 2)}\n`); + return { output, archives: [...direct.values()] }; +} + +export const stageAppleStaticLeaf = stageNativeStaticLeaf; + +/** Maintained Apple static XCFrameworks store ar bytes inside a .framework binary. */ +export function macosStaticArchive(framework: string): string { + const files = filesAt(path.join(framework, 'macos-arm64')); + const archives = files.filter((file) => + readFileSync(file).subarray(0, 8).equals(Buffer.from('!\n')), + ); + assert.equal( + archives.length, + 1, + 'packaged macOS static framework must contain exactly one ar library', + ); + const archive = archives[0]; + assert.ok(archive); + return archive; +} + +export async function runAppleStaticCarrierConsumer(spec: any, root: string) { + assert.equal(process.platform, 'darwin', 'packaged Apple execution requires genuine macOS'); + assert.equal(process.arch, 'arm64', 'packaged Apple execution requires Apple arm64'); + assert.ok(root && path.isAbsolute(root), 'Bazel must supply a private TEST_TMPDIR'); + const facts = json(spec.receipt); + assert.equal(spec.triple, `arm64-apple-macosx${facts.deploymentTargets.package_macos}`); + const sdkMarker = `${path.sep}sdk_macosx${path.sep}`; + assert.ok(spec.sdkFile.includes(sdkMarker)); + const sdk = spec.sdkFile.slice(0, spec.sdkFile.indexOf(sdkMarker)) + sdkMarker.slice(0, -1); + const products = Object.fromEntries( + spec.leaves.map((leaf: any) => [ + leaf.product, + { + product: leaf.product, + releaseProduct: leaf.owner, + version: leaf.version, + sqlNames: [...leaf.sqlNames].sort(), + tag: `${leaf.owner}-v${leaf.version}`, + }, + ]), + ); + assert.equal(Object.keys(products).length, spec.leaves.length, 'repeated static carrier owner'); + const staged = spec.leaves.map((leaf: any, index: number) => + stageAppleStaticLeaf(leaf, path.join(root, `leaf-${index}`), spec.version), + ); + const archiveInput = (file: string) => ({ + path: realpathSync(file), + size: statSync(file).size, + sha256: sha256(readFileSync(file)), + }); + const carrier = buildIosCarrierManifest({ + baseRuntimeVersion: spec.version, + baseTag: `liboliphaunt-native-v${spec.version}`, + baseCarrierManifest: realpathSync(spec.baseManifest), + baseArchiveInputs: { + 'base-xcframework': archiveInput(spec.base), + 'runtime-resources': archiveInput(spec.iosResources), + }, + declaredProducts: products, + extensionManifests: staged.map((leaf: any) => leaf.output), + }); + const cache = path.join(root, 'cache'); + mkdirSync(path.join(cache, 'objects'), { recursive: true }); + for (const row of staged.flatMap((leaf: any) => leaf.archives)) + copyFileSync(row.path, path.join(cache, 'objects', `${row.sha256}-${row.name}`)); + const carrierFile = path.join(root, 'ios.json'); + writeFileSync(carrierFile, JSON.stringify(carrier)); + const generated = path.join(root, 'generated'); + await renderExtensionProducts([ + '--carrier', + carrierFile, + '--extensions', + spec.extensions.join(','), + '--output-dir', + generated, + '--cache-dir', + cache, + '--offline', + '--local-binary-targets', + '--owner-catalog', + spec.ownerCatalog, + '--base-package-version', + spec.basePackageVersion, + ]); + const rows = (archive: string, prefix: string) => + archiveLogicalTreeRows(readPortableArchiveEntries(realpathSync(archive)), archive, prefix).sort( + (left, right) => left.path.localeCompare(right.path), + ); + assert.deepEqual( + rows( + spec.base, + 'liboliphaunt.xcframework/macos-arm64/liboliphaunt.framework/Resources/oliphaunt/', + ), + rows(spec.macosResources, 'oliphaunt/'), + 'packaged macOS resource archive differs from bundled framework resources', + ); + const framework = path.join(root, 'liboliphaunt.xcframework'); + extractPortableArchiveTree(realpathSync(spec.base), framework, 'liboliphaunt.xcframework'); + const macos = path.join(framework, 'macos-arm64'); + const include = path.join(root, 'include'); + mkdirSync(include); + writeFileSync(path.join(include, 'COliphaunt.h'), '#include \n'); + const selection = json(path.join(generated, 'extension-products.json')); + assert.deepEqual( + selection.selected.map((row: any) => row.sqlName).sort(), + [...spec.extensions].sort(), + 'selected registration cohort differs', + ); + const registrations = selection.targets.filter( + (target: any) => target.kind === 'target' && target.name.startsWith('COliphauntExtension'), + ); + assert.equal( + registrations.length, + spec.extensions.length, + 'consumer requires actual compiled static extensions', + ); + const environment = { + HOME: path.join(root, 'home'), + TMPDIR: root, + PATH: path.dirname(spec.clang), + DEVELOPER_DIR: facts.developerDirectory, + SDKROOT: sdk, + DYLD_LIBRARY_PATH: '', + DYLD_FRAMEWORK_PATH: '', + DYLD_FALLBACK_LIBRARY_PATH: '', + DYLD_FALLBACK_FRAMEWORK_PATH: '', + }; + mkdirSync(environment.HOME); + const run = (binary: string, args: string[]) => { + const result = spawnSync(binary, args, { + cwd: root, + env: environment, + encoding: 'utf8', + timeout: 120_000, + }); + assert.equal(result.error, undefined); + assert.equal(result.status, 0, `${binary}: ${result.stdout}\n${result.stderr}`); + return result.stdout; + }; + const flags = ['-target', spec.triple, '-isysroot', sdk, '-F', macos, '-I', include]; + const objects: string[] = []; + const functions: string[] = []; + const headers: string[] = []; + for (const target of registrations) { + const directory = path.join(generated, target.path); + const header = path.join(directory, 'include', `${target.name}.h`); + const declarations = [ + ...readFileSync(header, 'utf8').matchAll( + /const OliphauntStaticExtension \*([A-Za-z_][A-Za-z0-9_]*)\(void\);/gu, + ), + ]; + assert.equal( + declarations.length, + 1, + 'registration header must expose exactly one renderer-owned descriptor', + ); + const descriptor = declarations[0]?.[1]; + assert.ok(descriptor); + functions.push(descriptor); + headers.push(header); + const object = path.join(root, `${target.name}.o`); + run(spec.clang, [ + ...flags, + '-std=gnu11', + '-I', + path.dirname(header), + '-c', + path.join(directory, 'registration.c'), + '-o', + object, + ]); + objects.push(object); + } + const main = path.join(root, 'consumer.c'); + writeFileSync( + main, + `${headers.map((header) => `#include ${JSON.stringify(header)}`).join('\n')}\n#include \n#include \nint main(void) {\nif (strcmp(oliphaunt_version(), ${JSON.stringify(spec.version)}) != 0) return 1;\nOliphauntStaticExtension extensions[] = { ${functions.map((name) => `*${name}()`).join(', ')} };\nif (oliphaunt_register_static_extensions(extensions, sizeof(extensions)/sizeof(extensions[0])) != 0) return 2;\nprintf("%s\\n", oliphaunt_version());\nreturn 0;\n}\n`, + ); + const mainObject = path.join(root, 'consumer.o'); + run(spec.clang, [...flags, '-std=gnu11', '-c', main, '-o', mainObject]); + const archives = selection.targets + .filter((target: any) => target.kind === 'binaryTarget') + .map((target: any) => macosStaticArchive(path.join(generated, target.path))); + assert.ok( + archives.length >= registrations.length, + 'generated registration lacks packaged static archives', + ); + const executable = path.join(root, 'consumer'); + run(spec.clangxx, [ + ...flags, + mainObject, + ...objects, + ...archives, + '-framework', + 'liboliphaunt', + `-Wl,-rpath,${macos}`, + '-o', + executable, + ]); + assert.equal( + run(executable, []).trim(), + spec.version, + 'actual packaged native API returned another version', + ); + const binary = path.join(macos, 'liboliphaunt.framework', 'liboliphaunt'); + renameSync(binary, `${binary}.disabled`); + try { + const missing = spawnSync(executable, [], { + cwd: root, + env: environment, + encoding: 'utf8', + timeout: 30_000, + }); + assert.equal(missing.error, undefined); + assert.notEqual(missing.status, 0, 'consumer resolved an alternate native core'); + assert.match(missing.stderr, /liboliphaunt/iu); + assert.match(missing.stderr, /Library not loaded|image not found|library not found/iu); + } finally { + renameSync(`${binary}.disabled`, binary); + } + console.log( + JSON.stringify({ + runtimeVersion: spec.version, + coreSha256: sha256(readFileSync(spec.base)), + registeredExtensions: spec.extensions, + construction: 'actual-packaged-core-static-final-link-and-process-registration', + sqlExecuted: false, + }), + ); +} + +if (import.meta.main) { + const [specFile, runfiles] = process.argv.slice(2); + assert.equal( + process.argv.length, + 4, + 'expected declared consumer specification and runfiles root', + ); + assert.ok(runfiles && path.isAbsolute(runfiles)); + assert.ok(specFile); + const spec = json(specFile); + for (const key of [ + 'base', + 'iosResources', + 'macosResources', + 'baseManifest', + 'ownerCatalog', + 'clang', + 'clangxx', + 'sdkFile', + 'receipt', + ]) + spec[key] = path.join(runfiles, relativeFile(spec[key])); + for (const leaf of spec.leaves) { + leaf.frozen = path.join(runfiles, relativeFile(leaf.frozen)); + leaf.github = leaf.github.map((file: string) => path.join(runfiles, relativeFile(file))); + } + const root = process.env.TEST_TMPDIR; + assert.ok(root); + await runAppleStaticCarrierConsumer(spec, root); +} diff --git a/build_defs/native/apple/static-carrier-consumer.test.mts b/build_defs/native/apple/static-carrier-consumer.test.mts new file mode 100644 index 000000000..3cb8baef3 --- /dev/null +++ b/build_defs/native/apple/static-carrier-consumer.test.mts @@ -0,0 +1,164 @@ +import { test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { createDeterministicTar } from '../../../tools/packaging/archive-directory.mts'; +import { canonicalGzipSync } from '../../../tools/packaging/portable-archive.mts'; +import { macosStaticArchive, stageAppleStaticLeaf } from './static-carrier-consumer.mts'; + +// Fixtures qualify relocation/admission only; their bytes are not native binaries. +function fixture(root: string, bundle = false) { + const bytes = Buffer.from('original packaged fixture bytes'); + const row = { + name: 'fixture.zip', + path: 'old/constructor/fixture.zip', + family: 'native', + target: 'ios-xcframework', + sha256: createHash('sha256').update(bytes).digest('hex'), + bytes: bytes.length, + }; + const frozen = { + schema: 'oliphaunt-extension-ci-artifacts-v1', + product: 'fixture-product', + releaseProduct: 'fixture-owner', + version: '1.2.3', + compatibility: { nativeRuntimeVersion: '4.5.6' }, + sqlName: 'fixture', + assets: [row], + }; + mkdirSync(path.join(root, 'github'), { recursive: true }); + writeFileSync(path.join(root, 'github', row.name), bytes); + const leaf = { + product: frozen.product, + owner: frozen.releaseProduct, + version: frozen.version, + runtimeVersion: '4.5.6', + sqlNames: ['fixture'], + github: [path.join(root, 'github')], + frozen: path.join(root, 'frozen.json'), + }; + const write = (value: any = frozen) => writeFileSync(leaf.frozen, JSON.stringify(value)); + if (!bundle) write(); + return { bytes, row, frozen, leaf, write }; +} + +test('singleton relocates exact original archive bytes without rewriting held identity fields', () => { + const root = mkdtempSync(path.join(tmpdir(), 'apple-static-single-')); + try { + const input = fixture(root); + const staged = stageAppleStaticLeaf(input.leaf, path.join(root, 'staged'), '4.5.6'); + const output = JSON.parse(readFileSync(staged.output, 'utf8')); + assert.deepEqual({ ...output, assets: input.frozen.assets }, input.frozen); + assert.deepEqual(readFileSync(output.assets[0].path), input.bytes); + writeFileSync(path.join(root, 'github', input.row.name), 'corrupt'); + assert.throws( + () => stageAppleStaticLeaf(input.leaf, path.join(root, 'corrupt'), '4.5.6'), + /frozen size differs/, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('independently held core, changed cohort and unexpected physical archive fail closed', () => { + const root = mkdtempSync(path.join(tmpdir(), 'apple-static-admission-')); + try { + const input = fixture(root); + assert.throws( + () => stageAppleStaticLeaf(input.leaf, path.join(root, 'wrong-core'), '4.5.7'), + /different native core/, + ); + input.write({ ...input.frozen, compatibility: { nativeRuntimeVersion: '4.5.5' } }); + assert.throws(() => + stageAppleStaticLeaf(input.leaf, path.join(root, 'wrong-frozen-core'), '4.5.6'), + ); + input.write(); + assert.throws(() => + stageAppleStaticLeaf( + { ...input.leaf, sqlNames: ['another'] }, + path.join(root, 'wrong-cohort'), + '4.5.6', + ), + ); + writeFileSync(path.join(root, 'github', 'undeclared.zip'), 'extra'); + assert.throws( + () => stageAppleStaticLeaf(input.leaf, path.join(root, 'extra'), '4.5.6'), + /must match frozen direct assets/, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('bundle relocation preserves original nested bytes and rejects a falsified nested digest', async () => { + const root = mkdtempSync(path.join(tmpdir(), 'apple-static-bundle-')); + try { + const input = fixture(root, true); + const nested = path.join(root, 'bundle', 'extensions', 'fixture', input.row.name); + mkdirSync(path.dirname(nested), { recursive: true }); + writeFileSync(nested, input.bytes); + const outer = canonicalGzipSync( + await createDeterministicTar(path.join(root, 'bundle'), { keepParent: true }), + ); + rmSync(path.join(root, 'github', input.row.name)); + writeFileSync(path.join(root, 'github', 'bundle.tar.gz'), outer); + const direct = { + ...input.row, + name: 'bundle.tar.gz', + path: 'old/bundle.tar.gz', + bytes: outer.length, + sha256: createHash('sha256').update(outer).digest('hex'), + }; + const member = { + ...input.frozen, + assets: [ + { + ...input.row, + carrierAsset: direct.name, + carrierRoot: 'bundle', + memberPath: `extensions/fixture/${input.row.name}`, + }, + ], + }; + const frozen = { + ...input.frozen, + schema: 'oliphaunt-extension-ci-artifacts-v2', + extensions: [member], + carrierAssets: [direct], + }; + input.write(frozen); + const staged = stageAppleStaticLeaf(input.leaf, path.join(root, 'staged'), '4.5.6'); + const output = JSON.parse(readFileSync(staged.output, 'utf8')); + assert.deepEqual(readFileSync(output.extensions[0].assets[0].path), input.bytes); + assert.equal(output.extensions[0].assets[0].carrierAsset, direct.name); + const asset = member.assets[0]; + assert.ok(asset); + asset.sha256 = '0'.repeat(64); + input.write(frozen); + assert.throws( + () => stageAppleStaticLeaf(input.leaf, path.join(root, 'bad-digest'), '4.5.6'), + /frozen SHA-256 differs/, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('macOS archive selection accepts framework-wrapped ar bytes and rejects absent or duplicate libraries', () => { + const root = mkdtempSync(path.join(tmpdir(), 'apple-static-library-')); + try { + const macos = path.join(root, 'macos-arm64', 'fixture.framework'); + mkdirSync(path.join(macos, 'Headers'), { recursive: true }); + writeFileSync(path.join(macos, 'Headers', 'fixture.h'), 'header fixture'); + assert.throws(() => macosStaticArchive(root), /exactly one ar library/); + const archive = path.join(macos, 'fixture'); + writeFileSync(archive, '!\nfixture'); + assert.equal(macosStaticArchive(root), archive); + writeFileSync(path.join(macos, 'duplicate.a'), '!\nother'); + assert.throws(() => macosStaticArchive(root), /exactly one ar library/); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/build_defs/native/apple/swift-candidate-contract.mts b/build_defs/native/apple/swift-candidate-contract.mts new file mode 100644 index 000000000..ab8e11ae0 --- /dev/null +++ b/build_defs/native/apple/swift-candidate-contract.mts @@ -0,0 +1,39 @@ +import assert from 'node:assert/strict'; +import path from 'node:path'; +import { parseSwiftReleaseBinaryTarget } from '../../../src/native/sdks/swift/tools/prepare-swift-release-consumer.mts'; + +/** Compose a temporary candidate test without retargeting the SDK's held native pin. */ +export function composeSwiftCandidateManifest( + manifest: string, + authoredNativeVersion: string, + candidateName: string, + candidateChecksum: string, +) { + const version = authoredNativeVersion.trim(); + assert.match(version, /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/u); + assert.equal(candidateName, path.basename(candidateName), 'candidate asset must be a basename'); + assert.equal( + candidateName, + `liboliphaunt-${version}-apple-spm-xcframework.zip`, + 'candidate cannot change the authored Swift native requirement', + ); + assert.match(candidateChecksum, /^[0-9a-f]{64}$/u); + const target = parseSwiftReleaseBinaryTarget(manifest); + assert.equal( + target.url, + `https://github.com/f0rr0/oliphaunt/releases/download/liboliphaunt-native-v${version}/${candidateName}`, + 'candidate must retain the authored canonical native release URL', + ); + return { + manifest: + manifest.slice(0, target.index) + + manifest + .slice(target.index, target.end) + .replace(`"${target.checksum}"`, `"${candidateChecksum}"`) + + manifest.slice(target.end), + nativeVersion: version, + heldChecksum: target.checksum, + candidateChecksum, + publicUrl: target.url, + }; +} diff --git a/build_defs/native/apple/swift-candidate-contract.test.mts b/build_defs/native/apple/swift-candidate-contract.test.mts new file mode 100644 index 000000000..516dee174 --- /dev/null +++ b/build_defs/native/apple/swift-candidate-contract.test.mts @@ -0,0 +1,43 @@ +import { expect, test } from 'bun:test'; +import { composeSwiftCandidateManifest } from './swift-candidate-contract.mts'; + +const heldChecksum = '1'.repeat(64); +const candidateChecksum = '2'.repeat(64); +const version = '1.2.3'; +const name = `liboliphaunt-${version}-apple-spm-xcframework.zip`; +const target = `.binaryTarget(name: "liboliphaunt", url: "https://github.com/f0rr0/oliphaunt/releases/download/liboliphaunt-native-v${version}/${name}", checksum: "${heldChecksum}")`; + +test('candidate composition changes only the native checksum and records the held requirement', () => { + const manifest = `// checksum elsewhere: ${heldChecksum}\n${target}\n// retained source\n`; + const result = composeSwiftCandidateManifest(manifest, `${version}\n`, name, candidateChecksum); + expect(result.manifest).toBe( + manifest.replace(target, target.replace(heldChecksum, candidateChecksum)), + ); + expect(result.heldChecksum).toBe(heldChecksum); + expect(result.candidateChecksum).toBe(candidateChecksum); + expect(result.nativeVersion).toBe(version); + expect(composeSwiftCandidateManifest(manifest, version, name, heldChecksum).manifest).toBe( + manifest, + ); +}); + +test('candidate composition cannot substitute a newer runtime, noncanonical origin or ambiguous target', () => { + expect(() => composeSwiftCandidateManifest(target, '1.2.4', name, candidateChecksum)).toThrow( + /authored Swift native requirement/u, + ); + expect(() => + composeSwiftCandidateManifest(target, version, `../${name}`, candidateChecksum), + ).toThrow(/basename/u); + expect(() => + composeSwiftCandidateManifest( + target.replace('github.com', 'example.com'), + version, + name, + candidateChecksum, + ), + ).toThrow(/canonical native release URL/u); + expect(() => + composeSwiftCandidateManifest(`${target}\n${target}`, version, name, candidateChecksum), + ).toThrow(/exactly one/u); + expect(() => composeSwiftCandidateManifest(target, version, name, 'invalid')).toThrow(); +}); diff --git a/build_defs/native/carriers/BUILD.bazel b/build_defs/native/carriers/BUILD.bazel new file mode 100644 index 000000000..1e7d7ec19 --- /dev/null +++ b/build_defs/native/carriers/BUILD.bazel @@ -0,0 +1,20 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/foundation:bun.bzl", "bun_binary", "bun_script_test", "bun_test") +load(":defs.bzl", "native_carrier_helpers", "native_carrier_legal_inputs", "native_carrier_unit_inputs", "native_payload_helpers") + +package(default_visibility = ["//visibility:public"]) +exports_files(glob(["*.bzl", "*.mts"])) + +_HELPERS = native_carrier_helpers() +_LEGAL = list(native_carrier_legal_inputs().keys()) + +bun_binary(name = "payload_tool", entry_point = "payload.mts", data = native_payload_helpers()) +bun_binary(name = "envelope_tool", entry_point = "envelopes.mts", data = ["payload.mts"] + _HELPERS + _LEGAL) +bun_binary(name = "facade_tool", entry_point = "facades.mts", data = ["payload.mts", "//src/native/postgres-tools:tools/package-cargo-artifacts.mts", "//:tools/packaging/emit-javascript.mts"] + _HELPERS + _LEGAL) +bun_binary(name = "checksum_tool", entry_point = "checksums.mts") +bun_test(name = "release_family_test", entry_point = "release-family.unit.test.mts", data = ["release-family.test.mts", "checksums.mts", "//tools/release:checksum-manifest.mts"], size = "small") + +native_carrier_unit_inputs(name = "unit_inputs") +bun_script_test(name = "package_test", entry_point = "package.test.mts", args = ["$(location :unit_inputs)"], data = [":unit_inputs", "//:tools/packaging/testdata/release-fixture-utils.mts", "payload.mts", "envelopes.mts", "facades.mts", "checksums.mts", "//src/native/postgres-tools:tools/package-cargo-artifacts.mts", "//:tools/packaging/emit-javascript.mts"] + _HELPERS + _LEGAL, size = "small") + +source_quality_files() diff --git a/build_defs/native/carriers/cargo-consumer.test.mts b/build_defs/native/carriers/cargo-consumer.test.mts new file mode 100644 index 000000000..7be74b956 --- /dev/null +++ b/build_defs/native/carriers/cargo-consumer.test.mts @@ -0,0 +1,178 @@ +/** Offline conventional Cargo reconstruction of the actual emitted payload crates. */ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + copyFileSync, + mkdirSync, + mkdtempSync, + readFileSync, + realpathSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { + extractPortableArchiveTree, + readPortableArchiveEntries, +} from '../../../tools/packaging/portable-archive.mts'; +import { + type CargoLinkConfiguration, + cargoLinkEnvironment, +} from '../../languages/cargo-environment.mts'; + +const [packagesDirectory, githubArchive, cargo, rustc, rustdoc, configurationFile, runfiles] = + process.argv.slice(2); +assert( + packagesDirectory && + githubArchive && + cargo && + rustc && + rustdoc && + configurationFile && + runfiles && + process.env.TEST_TMPDIR, +); +const root = mkdtempSync(path.join(process.env.TEST_TMPDIR, 'installed-native-cargo-')); +const digest = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +try { + const privateGithub = path.join(root, path.basename(githubArchive)); + copyFileSync(githubArchive, privateGithub); + const packages = JSON.parse(readFileSync(path.join(packagesDirectory, 'packages.json'), 'utf8')); + assert.equal(packages.schema, 'oliphaunt-liboliphaunt-cargo-artifacts-v1'); + assert( + packages.packages.length > 1, + 'actual native Cargo tree must contain aggregator and payload parts', + ); + const records: { + name: string; + version: string; + manifest: Record; + directory: string; + role: string; + }[] = []; + for (const row of packages.packages) { + // The tree owns the physical crates. The operational index may retain + // execroot-relative locators; they must name precisely those actual files. + const archive = path.join(packagesDirectory, path.basename(row.cratePath)); + const privateArchive = path.join(root, path.basename(archive)); + copyFileSync(realpathSync(archive), privateArchive); + const entries = readPortableArchiveEntries(privateArchive); + const manifests = [...entries.values()].filter( + (entry) => entry.isFile && /^[^/]+\/Cargo\.toml$/u.test(entry.name), + ); + assert.equal( + manifests.length, + 1, + 'each emitted crate must contain exactly one package manifest', + ); + const manifest = Bun.TOML.parse(manifests[0].data().toString()) as Record; + assert.equal(manifest.package.name, row.name); + assert.equal(path.basename(archive), `${row.name}-${manifest.package.version}.crate`); + const directory = path.join(root, 'crates', row.name); + extractPortableArchiveTree( + privateArchive, + directory, + `${row.name}-${manifest.package.version}`, + ); + records.push({ + name: row.name, + version: manifest.package.version, + manifest, + directory, + role: row.role, + }); + } + const aggregators = records.filter(({ role }) => role === 'aggregator'); + assert.equal(aggregators.length, 1); + const aggregator = aggregators[0]; + const parts = records.filter(({ role }) => role === 'part'); + assert(parts.length > 0); + assert.deepEqual( + Object.keys(aggregator.manifest['build-dependencies']).sort(), + parts.map(({ name }) => name).sort(), + ); + for (const part of parts) { + assert.deepEqual(aggregator.manifest['build-dependencies'][part.name], { + version: `=${part.version}`, + }); + assert.equal(part.version, aggregator.version); + } + const consumer = path.join(root, 'consumer'); + mkdirSync(path.join(consumer, 'src'), { recursive: true }); + const quote = (value: string) => JSON.stringify(value.replaceAll('\\', '/')); + writeFileSync( + path.join(consumer, 'Cargo.toml'), + `[package]\nname = "installed-native-payload-consumer"\nversion = "0.0.0"\nedition = "2024"\nbuild = "build.rs"\n\n[dependencies]\nartifact = { package = ${quote(aggregator.name)}, version = ${quote(`=${aggregator.version}`)}, path = ${quote(aggregator.directory)} }\n\n[patch.crates-io]\n${parts.map(({ name, directory }) => `${quote(name)} = { path = ${quote(directory)} }`).join('\n')}\n\n[workspace]\n`, + ); + const metadataKey = `DEP_${aggregator.manifest.package.links.toUpperCase().replaceAll('-', '_')}_MANIFEST`; + writeFileSync( + path.join(consumer, 'build.rs'), + `fn main() {\n let manifest = std::env::var(${JSON.stringify(metadataKey)}).expect("actual aggregator must supply reconstructed manifest");\n println!("cargo::rustc-env=RECONSTRUCTED_MANIFEST={manifest}");\n}\n`, + ); + writeFileSync( + path.join(consumer, 'src/main.rs'), + 'fn main() { println!("{}", env!("RECONSTRUCTED_MANIFEST")); }\n', + ); + const env = { ...process.env }; + for (const key of Object.keys(env)) + if (/^(?:CARGO_|RUST|DEP_|OLIPHAUNT_|LIBOLIPHAUNT_)/u.test(key)) delete env[key]; + Object.assign( + env, + cargoLinkEnvironment( + JSON.parse(readFileSync(configurationFile, 'utf8')) as CargoLinkConfiguration, + runfiles, + ), + { + CARGO_HOME: path.join(root, 'cargo-home'), + CARGO_TARGET_DIR: path.join(root, 'target'), + CARGO_NET_OFFLINE: 'true', + RUSTC: rustc, + RUSTDOC: rustdoc, + OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD: '1', + }, + ); + const result = Bun.spawnSync( + [cargo, 'run', '--offline', '--manifest-path', path.join(consumer, 'Cargo.toml')], + { cwd: consumer, env, stdout: 'pipe', stderr: 'pipe' }, + ); + assert.equal( + result.exitCode, + 0, + `installed Cargo reconstruction failed:\n${result.stderr.toString()}`, + ); + const manifest = Bun.TOML.parse(readFileSync(result.stdout.toString().trim(), 'utf8')) as Record< + string, + any + >; + assert.equal(manifest.schema, 'oliphaunt-artifact-manifest-v1'); + assert.equal(manifest.version, aggregator.version); + assert.equal( + manifest.product, + packages.packages.find(({ role }) => role === 'aggregator').product, + ); + const actual = manifest.files + .map((file) => { + const bytes = readFileSync(file.source); + assert.equal(digest(bytes), file.sha256, `reconstructed bytes differ for ${file.relative}`); + return { relative: file.relative, sha256: file.sha256, executable: file.executable }; + }) + .sort((a, b) => a.relative.localeCompare(b.relative, 'en')); + const expected = [...readPortableArchiveEntries(privateGithub).values()] + .filter((entry) => entry.isFile) + .map((entry) => ({ + relative: entry.name, + sha256: digest(entry.data()), + executable: Boolean(entry.mode & 0o100), + })) + .sort((a, b) => a.relative.localeCompare(b.relative, 'en')); + assert.deepEqual( + actual, + expected, + 'offline reconstructed Cargo payload must equal the final GitHub payload', + ); + console.log( + `Installed native Cargo: ${parts.length} actual payload parts reconstructed ${actual.length} final public files exactly, offline.`, + ); +} finally { + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/native/carriers/checksums.mts b/build_defs/native/carriers/checksums.mts new file mode 100644 index 000000000..cc29de634 --- /dev/null +++ b/build_defs/native/carriers/checksums.mts @@ -0,0 +1,97 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + copyFileSync, + mkdirSync, + readFileSync, + realpathSync, + statSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; + +/** Product-wide assembly requires exactly the canonical assets supplied by its caller. */ +export function writeNativeChecksums({ + expected, + files, + output, +}: { + expected: string[]; + files: string[]; + output: string; +}): void { + assert( + expected.length && new Set(expected).size === expected.length, + 'checksum asset names must be unique', + ); + const observed = files + .map((file) => ({ name: path.basename(file), file })) + .sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0)); + assert.deepEqual( + observed.map(({ name }) => name), + [...expected].sort(), + 'product checksum assembly is missing or repeats canonical assets', + ); + mkdirSync(path.dirname(output), { recursive: true }); + writeFileSync( + output, + observed + .map( + ({ name, file }) => + `${createHash('sha256').update(readFileSync(file)).digest('hex')} ./${name}\n`, + ) + .join(''), + ); +} + +/** Join independently constructed archives into the canonical product directory. */ +export function assembleNativeReleaseAssets(spec: { + expected: string[]; + files: string[]; + copies: string[]; + output: string; +}): void { + const destinations = spec.copies.map((file) => path.basename(file)).sort(); + assert.deepEqual(destinations, [...spec.expected].sort(), 'release asset destinations differ'); + assert.equal( + new Set([...spec.copies, spec.output].map((file) => path.resolve(path.dirname(file)))).size, + 1, + 'release assets and checksum must share one directory', + ); + assert.equal(path.basename(path.dirname(spec.output)), 'release-assets'); + const sources = new Map(spec.files.map((file) => [path.basename(file), file])); + assert.equal(sources.size, spec.files.length, 'release assets repeat a source name'); + assert.deepEqual( + [...sources.keys()].sort(), + destinations, + 'release asset source inventory differs', + ); + assert(!sources.has(path.basename(spec.output)), 'checksum must not include itself'); + const copies = spec.copies.map((destination) => { + const declared = sources.get(path.basename(destination)); + assert(declared, 'release asset source is missing'); + // Bazel projects declared input Files as sandbox links. Resolve only the + // supplied leaf; assembled public outputs are regular copied files. + const source = realpathSync(declared); + assert(statSync(source).isFile(), 'release asset input must resolve to a regular file'); + assert.notEqual( + path.resolve(source), + path.resolve(destination), + 'release asset source is its destination', + ); + return { source, destination }; + }); + mkdirSync(path.dirname(spec.output), { recursive: true }); + for (const { source, destination } of copies) { + copyFileSync(source, destination); + chmodSync(destination, 0o644); + } + writeNativeChecksums({ expected: spec.expected, files: spec.copies, output: spec.output }); +} +if (import.meta.main) { + assert.equal(process.argv.length, 3, 'usage: checksums.mts '); + const spec = JSON.parse(readFileSync(process.argv[2], 'utf8')); + if (spec.copies !== undefined) assembleNativeReleaseAssets(spec); + else writeNativeChecksums(spec); +} diff --git a/build_defs/native/carriers/defs.bzl b/build_defs/native/carriers/defs.bzl new file mode 100644 index 000000000..063dd7cc3 --- /dev/null +++ b/build_defs/native/carriers/defs.bzl @@ -0,0 +1,301 @@ +"""Desktop runtime/tools envelopes from typed native construction mappings.""" + +load("@oliphaunt_metadata//:metadata.bzl", "NATIVE_RUNTIME_ARTIFACTS", "PRODUCTS", "PUBLICATION_CARRIERS") +load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain", "use_cc_toolchain") +load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES") +load("@rules_cc//cc/common:cc_common.bzl", "cc_common") +load("@rules_pkg//pkg:providers.bzl", "PackageFilesInfo", "PackageFilegroupInfo") +load("//build_defs/foundation:bun.bzl", "BunScriptInfo", "bun_action") +load("//build_defs/host:desktop-profile.bzl", "desktop_profile") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") + +_CONFIGURATIONS = { + "linux-x64-gnu": "//build_defs/native:linux_x86_64", + "linux-arm64-gnu": "//build_defs/native:linux_aarch64_gnu_2_28", + "macos-arm64": "//build_defs/native:macos_arm64", + "windows-x64-msvc": "//build_defs/native:windows_x64", +} + +def native_carrier_legal_inputs(profile = "native-runtime"): + # Keep this declared source map aligned with releaseNoticeRows(profile), + # including the source.toml pins validated by that existing renderer. + if profile not in ["native-runtime", "native-tools"]: + fail("unsupported native carrier legal profile: " + profile) + result = {"//:" + name: name for name in [ + "LICENSE", "THIRD_PARTY_NOTICES.md", + ]} + result["//src/native/runtime:THIRD_PARTY_NOTICES.md"] = "src/native/runtime/THIRD_PARTY_NOTICES.md" + components = [("postgres", ["COPYRIGHT", "source.toml"])] + if profile == "native-runtime": + components.append(("icu", ["LICENSE", "source.toml"])) + for package, names in components: + for name in names: + result["//src/third-party/" + package + ":" + name] = "src/third-party/" + package + "/" + name + return result + +def native_carrier_helpers(): + return [ + "//:tools/packaging/archive-directory.mts", "//:tools/packaging/cargo-source-package.mts", "//:tools/packaging/cargo-manifest.mts", + "//:tools/packaging/native-cargo-payload.mts", "//:tools/packaging/npm-package.mts", + "//:tools/packaging/npm-trusted-publishing.mts", "//:tools/packaging/package-archive.mts", + "//:tools/packaging/platform-binary-contract.mts", "//:tools/packaging/portable-archive.mts", + "//:tools/packaging/release-carrier.mts", "//:tools/packaging/release-directory-safety.mts", + "//:tools/packaging/sdk-runtime-payload.mts", + "//:tools/packaging/release-notices.mts", "//:tools/packaging/rust-native-targets.mts", + "//:tools/packaging/rust-dependency-license-contract.mts", + "//:tools/packaging/windows-vc-runtime-closure.mts", "//:tools/packaging/windows-vc-runtime-policy.json", + "//tools/release:release-artifact-targets.mts", "//tools/release:release-graph.mts", + "//tools/release:release-history.mts", "//tools/release:compatibility-version-parser.mts", + "//tools/release:extension-release-metadata.mts", "//tools/release:platform-compatibility-policy.mts", + "//:src/extensions/artifacts/packages/tools/contrib-carriers.mts", + "//:src/extensions/artifacts/packages/tools/extension-registry-packages.mts", + "//src/extensions/contracts:extension-target-profiles.mts", + "//src/database-resources:seeds/carrier-identities.mts", + "//src/native/mobile-bindings:tools/dependency-license-contract.mts", + "//src/wasix/runtime:tools/wasix-cargo-artifact-contract.mts", + "//src/wasix/runtime:tools/wasix-runtime-npm-contract.mts", + "//src/native/runtime:tools/native-runtime-payload.mts", + "//src/native/runtime:tools/native-runtime-payload-policy.json", + ] + +def native_payload_helpers(): + """The payload renderer's module closure and eagerly read policy files. + + Envelope/registry rendering is a later action with its own inputs. Keep + those modules out of the payload tool so they cannot invalidate its output. + Legal source bytes are supplied separately by the payload rule. + """ + return [ + "//src/native/runtime:tools/native-runtime-payload.mts", + "//src/native/runtime:tools/native-runtime-payload-policy.json", + "//:tools/packaging/platform-binary-contract.mts", + "//tools/release:platform-compatibility-policy.mts", + "//:tools/packaging/release-notices.mts", + "//:tools/packaging/portable-archive.mts", + "//:tools/packaging/release-directory-safety.mts", + "//:tools/packaging/windows-vc-runtime-closure.mts", + "//:tools/packaging/windows-vc-runtime-policy.json", + ] + +def _sources(entries, inputs): + result = {} + for target, destination in entries.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1: + fail("carrier source must be exactly one declared File: " + str(target.label)) + if destination in result: + fail("duplicate carrier source destination " + destination) + result[destination] = files[0].path + inputs.append(files[0]) + return result + +def _mapping_rows(targets, prefix, inputs): + rows = [] + for target in targets: + if PackageFilesInfo in target: + mappings = [target[PackageFilesInfo]] + elif PackageFilegroupInfo in target: + group = target[PackageFilegroupInfo] + if group.pkg_dirs or group.pkg_symlinks: + fail("native public payload does not support authored directories or symlinks") + mappings = [provider for provider, _origin in group.pkg_files] + else: + fail("native payload requires typed rules_pkg mappings: " + str(target.label)) + for mapping in mappings: + for destination, source in mapping.dest_src_map.items(): + # These two upstream build recipes are not installed timezone data. + if destination.endswith("timezonesets/Makefile") or destination.endswith("timezonesets/meson.build"): + continue + rows.append({"source": source.path, "destination": prefix + destination, "tree": source.is_directory, "mode": mapping.attributes.get("mode", "0644")}) + inputs.append(source) + return rows + +def _stripped_impl(ctx): + original = ctx.attr.mapping[PackageFilesInfo] + result = {} + if ctx.attr.enabled: + cc = find_cc_toolchain(ctx) + configuration = cc_common.configure_features(ctx = ctx, cc_toolchain = cc, requested_features = ctx.features, unsupported_features = ctx.disabled_features) + strip = cc_common.get_tool_for_action(feature_configuration = configuration, action_name = ACTION_NAMES.strip) + for index, (destination, source) in enumerate(original.dest_src_map.items()): + if ctx.attr.enabled: + if source.is_directory: + fail("native binary stripping requires scalar Files") + output = ctx.actions.declare_file(ctx.label.name + "/" + str(index) + "/" + source.basename) + ctx.actions.run(executable = strip, arguments = ctx.attr.strip_flags + ["-o", output.path, source.path], inputs = [source], tools = cc.all_files, outputs = [output], mnemonic = "NativeCarrierStrip") + result[destination] = output + else: + result[destination] = source + return [DefaultInfo(files = depset(result.values())), PackageFilesInfo(dest_src_map = result, attributes = original.attributes)] + +_stripped_mapping = rule( + implementation = _stripped_impl, + attrs = {"mapping": attr.label(providers = [PackageFilesInfo], mandatory = True), "enabled": attr.bool(default = True), "strip_flags": attr.string_list(default = ["--strip-debug"])}, + fragments = ["cpp"], toolchains = use_cc_toolchain(), +) + +def _payload_impl(ctx): + inputs = [] + rows = _mapping_rows(ctx.attr.root_mappings, "", inputs) + _mapping_rows(ctx.attr.runtime_mappings, "runtime/", inputs) + output = ctx.actions.declare_directory(ctx.label.name) + spec = json.decode(ctx.attr.metadata) + spec.update({"mappings": rows, "legal": _sources(ctx.attr.legal, inputs), "windowsRuntime": {file.basename: file.path for file in ctx.files.windows_runtime}, "output": output.path}) + inputs += ctx.files.windows_runtime + manifest = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(manifest, json.encode(spec)) + bun_action(ctx, ctx.attr.tool, arguments = [manifest.path], inputs = inputs + [manifest], outputs = [output], mnemonic = "NativePublicPayload") + return [DefaultInfo(files = depset([output]))] + +native_public_payload = rule( + implementation = _payload_impl, + cfg = desktop_profile, + attrs = { + "root_mappings": attr.label_list(mandatory = True), "runtime_mappings": attr.label_list(mandatory = True), + "metadata": attr.string(mandatory = True), "legal": attr.label_keyed_string_dict(allow_files = True), + "windows_runtime": attr.label_list(allow_files = True), + "tool": attr.label(default = Label("//build_defs/native/carriers:payload_tool"), providers = [BunScriptInfo], cfg = "exec"), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), + }, +) + +def _envelope_impl(ctx): + inputs = [ctx.file.payload] + output = ctx.actions.declare_directory(ctx.attr.out) if ctx.attr.phase == "cargo" else ctx.actions.declare_file(ctx.attr.out) + spec = json.decode(ctx.attr.metadata) + spec.update({"phase": ctx.attr.phase, "payload": ctx.file.payload.path, "sources": _sources(ctx.attr.sources, inputs), "legal": _sources(ctx.attr.legal, inputs), "output": output.path}) + manifest = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(manifest, json.encode(spec)) + bun_action(ctx, ctx.attr.tool, arguments = [manifest.path], inputs = inputs + [manifest], outputs = [output], mnemonic = {"github": "NativeGithubEnvelope", "npm": "NativeNpmEnvelope", "cargo": "NativeCargoEnvelope"}[ctx.attr.phase]) + return [DefaultInfo(files = depset([output]))] + +_native_envelope = rule( + implementation = _envelope_impl, + attrs = {"payload": attr.label(allow_single_file = True, mandatory = True), "phase": attr.string(values = ["github", "npm", "cargo"], mandatory = True), "out": attr.string(mandatory = True), "metadata": attr.string(mandatory = True), "sources": attr.label_keyed_string_dict(allow_files = True), "legal": attr.label_keyed_string_dict(allow_files = True), "tool": attr.label(default = Label("//build_defs/native/carriers:envelope_tool"), providers = [BunScriptInfo], cfg = "exec")}, +) + +def native_desktop_carriers(product, root_mappings, runtime_mappings, binary_mappings, qualification): + descriptor = PRODUCTS[product] + rows = [row for row in NATIVE_RUNTIME_ARTIFACTS if row["product"] == product and row["kind"] in ["native-runtime", "native-tools"] and row["target"] in _CONFIGURATIONS] + carriers = [row for row in PUBLICATION_CARRIERS if row["product"] == product] + metadata, payload_metadata, payload_legal, github, npm, npm_names, npm_roles, cargo_names, cargo_roles, physical, compatible, sources = {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} + for artifact in rows: + target = artifact["target"] + configuration = _CONFIGURATIONS[target] + metadata[configuration] = json.encode({"artifact": artifact, "version": descriptor["version"], "carriers": carriers}) + # The public payload consumes only its binary/layout contract. Own + # release versions and registry identities belong to later envelopes. + # Compiler inputs (including the runtime's public version API) stay in + # the actual typed mappings and their native construction closure. + payload_metadata[configuration] = json.encode({"artifact": {"kind": artifact["kind"], "target": target}}) + payload_legal[configuration] = native_carrier_legal_inputs(artifact["kind"]) + github[configuration] = "release-assets/" + artifact["asset"].replace("{version}", descriptor["version"]) + leaf = [row for row in carriers if row["ecosystem"] == "npm" and row["name"] == artifact["npm_package"]] + # Base runtime and contrib share a release owner. Select the exact + # conventional native payload aggregator, not every owner/target row. + package_base = "liboliphaunt-native" if product == "liboliphaunt-native" else "oliphaunt-tools" + cargo = [row for row in carriers if row["ecosystem"] == "cargo" and row["target"] == target and row["name"] == package_base + "-" + target] + if len(leaf) != 1 or len(cargo) != 1: + fail("canonical native registry leaf must be unique for " + target) + leaf, cargo = leaf[0], cargo[0] + npm[configuration] = leaf["name"].replace("@", "").replace("/", "-") + "-" + leaf["version"] + ".tgz" + npm_names[configuration], npm_roles[configuration] = leaf["name"], leaf["role"] + cargo_names[configuration], cargo_roles[configuration] = cargo["name"], cargo["role"] + physical[configuration], compatible[configuration] = target, [] + directory = ("packages/" if product == "liboliphaunt-native" else "npm-platforms/") + leaf["target"] + sources[configuration] = {directory + "/package.json": "package.json", directory + "/README.md": "README.md"} + compatibility = select(compatible | {"//conditions:default": ["@platforms//:incompatible"]}) + replacements = {} + for index, mapping in enumerate(binary_mappings): + name = "public_binary_mapping_" + str(index) + _stripped_mapping(name = name, mapping = mapping, enabled = select({"//build_defs/native:macos_arm64": True, "//conditions:default": False}), strip_flags = ["-S"], target_compatible_with = compatibility) + replacements[mapping] = ":" + name + native_public_payload(name = "public_payload", root_mappings = [replacements.get(label, label) for label in root_mappings], runtime_mappings = [replacements.get(label, label) for label in runtime_mappings], metadata = select(payload_metadata), legal = select(payload_legal), windows_runtime = select({"//build_defs/native:windows_x64": ["@native_msvc_sdk//:runtime_dlls"], "//conditions:default": []}), target_compatible_with = compatibility) + for phase, out in [("github", select(github)), ("npm", select(npm)), ("cargo", "cargo-packages")]: + _native_envelope(name = "github_archive" if phase == "github" else "cargo_packages" if phase == "cargo" else "npm", phase = phase, payload = ":public_payload", metadata = select(metadata), sources = select(sources) if phase == "npm" else {}, legal = native_carrier_legal_inputs() if phase != "github" else {}, out = out, target_compatible_with = compatibility) + shipping_package(name = "native_github_shipping", owner = "@oliphaunt_metadata//:product_" + product, artifacts = [":github_archive"], ecosystem = "github", package_name = select({key: value[len("release-assets/"):] for key, value in github.items()}), configuration = select(physical), role = "github-release-asset", suppliers = "//build_defs/release:no_suppliers") + shipping_package(name = "native_npm_shipping", owner = "@oliphaunt_metadata//:product_" + product, artifacts = [":npm"], ecosystem = "npm", package_name = select(npm_names), configuration = select(physical), role = select(npm_roles), suppliers = "//build_defs/release:no_suppliers") + shipping_package(name = "native_cargo_shipping", owner = "@oliphaunt_metadata//:product_" + product, artifacts = [":cargo_packages"], ecosystem = "cargo", package_name = select(cargo_names), configuration = select(physical), role = select(cargo_roles), suppliers = "//build_defs/release:no_suppliers") + shipping_package(name = "native_payload_shipping", owner = "@oliphaunt_metadata//:product_" + product, artifacts = [":public_payload"], ecosystem = "internal", package_name = product + "-public-payload", configuration = select(physical), role = "construction", suppliers = "//build_defs/release:no_suppliers") + shipping_export(name = "native_shipping_export", packages = [":native_github_shipping", ":native_npm_shipping", ":native_cargo_shipping", ":native_payload_shipping"], qualification = qualification, testonly = True) + +def _facade_impl(ctx): + inputs = [] + output = ctx.actions.declare_file(ctx.attr.out) + spec = json.decode(ctx.attr.metadata) + spec.update({"phase": ctx.attr.phase, "sources": _sources(ctx.attr.sources, inputs), "legal": _sources(ctx.attr.legal, inputs), "output": output.path}) + manifest = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(manifest, json.encode(spec)) + bun_action(ctx, ctx.attr.tool, arguments = [manifest.path], inputs = inputs + [manifest], outputs = [output], mnemonic = "NativeToolsFacade") + return [DefaultInfo(files = depset([output]))] + +_native_facade = rule(implementation = _facade_impl, attrs = {"phase": attr.string(values = ["npm", "cargo"], mandatory = True), "out": attr.string(mandatory = True), "metadata": attr.string(mandatory = True), "sources": attr.label_keyed_string_dict(allow_files = True), "legal": attr.label_keyed_string_dict(allow_files = True), "tool": attr.label(default = Label("//build_defs/native/carriers:facade_tool"), providers = [BunScriptInfo], cfg = "exec")}) + +def native_tools_facades(qualification): + product = "postgres-tools-native" + descriptor = PRODUCTS[product] + carriers = [row for row in PUBLICATION_CARRIERS if row["product"] == product] + metadata = json.encode({"version": descriptor["version"], "targets": [row for row in NATIVE_RUNTIME_ARTIFACTS if row["product"] == product and row["kind"] == "native-tools"], "carriers": carriers}) + for ecosystem in ["npm", "cargo"]: + rows = [row for row in carriers if row["ecosystem"] == ecosystem and row["target"] == None] + if len(rows) != 1: + fail("tools source facade must have one canonical identity") + row = rows[0] + if ecosystem == "npm": + sources = {"npm/" + file: file for file in ["package.json", "README.md", "index.mts", "index.d.ts"]} + output = row["name"].replace("@", "").replace("/", "-") + "-" + row["version"] + ".tgz" + else: + sources = {file: file[len("crates/tools/"):] for file in native.glob(["crates/tools/**"], exclude = ["crates/tools/tests/**", "**/target/**"])} + sources["//src/test-fixtures:postgres/logical-tools.json"] = "testdata/logical-tools.json" + output = row["name"] + "-" + row["version"] + ".crate" + name = ecosystem + "_facade" + _native_facade(name = name, phase = ecosystem, out = output, metadata = metadata, sources = sources, legal = native_carrier_legal_inputs()) + shipping_package(name = name + "_shipping", owner = "@oliphaunt_metadata//:product_" + product, artifacts = [":" + name], ecosystem = ecosystem, package_name = row["name"], configuration = "portable", role = row["role"], suppliers = "//build_defs/release:no_suppliers") + shipping_export(name = "facade_shipping_export", packages = [":npm_facade_shipping", ":cargo_facade_shipping"], qualification = qualification, testonly = True) + +def _unit_inputs_impl(ctx): + inputs = [] + output = ctx.actions.declare_file(ctx.label.name + ".json") + metadata = json.decode(ctx.attr.metadata) + metadata.update({"sources": _sources(ctx.attr.sources, inputs), "legal": _sources(ctx.attr.legal, inputs)}) + metadata["payloadModules"] = {file.short_path: file.path for file in ctx.files.payload_modules} + metadata["payloadLegalInputs"] = {profile: native_carrier_legal_inputs(profile).values() for profile in ["native-tools", "native-runtime"]} + inputs += ctx.files.payload_modules + ctx.actions.write(output, json.encode(metadata)) + return [DefaultInfo(files = depset([output]), runfiles = ctx.runfiles(files = inputs + [output]))] + +_native_unit_inputs = rule(implementation = _unit_inputs_impl, attrs = {"metadata": attr.string(mandatory = True), "sources": attr.label_keyed_string_dict(allow_files = True), "legal": attr.label_keyed_string_dict(allow_files = True), "payload_modules": attr.label_list(allow_files = True)}) + +def native_carrier_unit_inputs(name): + product = "postgres-tools-native" + rows = [row for row in NATIVE_RUNTIME_ARTIFACTS if row["product"] == product and row["kind"] == "native-tools"] + sources = {} + for file in ["package.json", "README.md", "index.mts", "index.d.ts"]: + sources["//src/native/postgres-tools:npm/" + file] = "npm/" + file + for file in ["Cargo.toml", "README.md", "build.rs", "build_support.rs", "src/arguments.rs", "src/lib.rs"]: + sources["//src/native/postgres-tools:crates/tools/" + file] = "cargo/" + file + sources["//src/test-fixtures:postgres/logical-tools.json"] = "cargo/testdata/logical-tools.json" + _native_unit_inputs(name = name, metadata = json.encode({"version": PRODUCTS[product]["version"], "targets": rows, "carriers": [row for row in PUBLICATION_CARRIERS if row["product"] == product]}), sources = sources, legal = native_carrier_legal_inputs(), payload_modules = [":payload.mts"] + native_payload_helpers()) + +def _checksums_impl(ctx): + files = ctx.files.archives + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + output = ctx.actions.declare_file(ctx.attr.output_directory + "/" + ctx.attr.out) + copies = [ctx.actions.declare_file(ctx.attr.output_directory + "/" + name) for name in ctx.attr.expected] if ctx.attr.assemble else [] + data = {"expected": ctx.attr.expected, "files": [file.path for file in files], "output": output.path} + if ctx.attr.assemble: + data["copies"] = [file.path for file in copies] + ctx.actions.write(spec, json.encode(data)) + bun_action(ctx, ctx.attr.tool, arguments = [spec.path], inputs = files + [spec], outputs = [output] + copies, mnemonic = "NativeProductReleaseAssets" if ctx.attr.assemble else "NativeProductChecksums") + groups = {file.basename: depset([file]) for file in copies} + groups["checksums"] = depset([output]) + return [DefaultInfo(files = depset([output] + copies)), OutputGroupInfo(**groups)] + +_native_checksums = rule(implementation = _checksums_impl, attrs = {"archives": attr.label_list(allow_files = True, mandatory = True), "expected": attr.string_list(mandatory = True), "out": attr.string(mandatory = True), "output_directory": attr.string(default = "release-assets"), "assemble": attr.bool(default = False), "tool": attr.label(default = Label("//build_defs/native/carriers:checksum_tool"), providers = [BunScriptInfo], cfg = "exec")}) + +def native_checksum_manifest(name, product, archives, artifact_rows = NATIVE_RUNTIME_ARTIFACTS, assemble = False, output_directory = "release-assets"): + descriptor = PRODUCTS[product] + rows = [row for row in artifact_rows if row["product"] == product and "github-release" in row["surfaces"]] + checksums = [row for row in rows if row["kind"] == "checksums"] + if len(checksums) != 1: + fail("product checksum descriptor must be unique") + _native_checksums(name = name, archives = archives, expected = [row["asset"].replace("{version}", descriptor["version"]) for row in rows if row["kind"] != "checksums"], out = checksums[0]["asset"].replace("{version}", descriptor["version"]), assemble = assemble, output_directory = output_directory) diff --git a/build_defs/native/carriers/envelopes.mts b/build_defs/native/carriers/envelopes.mts new file mode 100644 index 000000000..1ca6fe843 --- /dev/null +++ b/build_defs/native/carriers/envelopes.mts @@ -0,0 +1,188 @@ +/** Existing public envelope writers over one previously validated native payload. */ +import assert from 'node:assert/strict'; +import { copyFileSync, cpSync, mkdirSync, mkdtempSync, readFileSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + requiredCoreRuntimePaths, + requiredRuntimeMemberPaths, + requiredToolsMemberPaths, +} from '../../../src/native/runtime/tools/native-runtime-payload.mts'; +import { archiveDirectory } from '../../../tools/packaging/archive-directory.mts'; +import { + packagePayload, + writePackagesManifest, +} from '../../../tools/packaging/native-cargo-payload.mts'; +import { packGeneratedNpmCarrier } from '../../../tools/packaging/npm-package.mts'; +import { + stageNpmPackageDescriptor, + validatePackedNpmPackage, +} from '../../../tools/packaging/release-carrier.mts'; +import { + assertReleaseNoticesInArchive, + releaseNoticeRows, + stageReleaseNotices, +} from '../../../tools/packaging/release-notices.mts'; +import { type Artifact, copyDeclaredTree, member, stageLegalSources } from './payload.mts'; + +interface Carrier { + product: string; + ecosystem: string; + name: string; + version: string; + target: string | null; + role: string; +} +export interface EnvelopeSpec { + phase: 'github' | 'npm' | 'cargo'; + artifact: Artifact; + version: string; + carriers: Carrier[]; + payload: string; + sources: Record; + legal: Record; + output: string; + partBytes?: number; +} + +export function validateNpmIdentity(manifest: Record, spec: EnvelopeSpec): Carrier { + const candidates = spec.carriers.filter( + (row) => row.ecosystem === 'npm' && row.name === spec.artifact.npm_package, + ); + assert.equal(candidates.length, 1, 'canonical native npm carrier must be unique'); + const row = candidates[0]; + assert.equal(row.product, spec.artifact.product); + assert.equal(row.version, spec.version); + assert.equal(manifest.name, row.name); + assert.equal(manifest.version, row.version); + assert.equal(manifest.oliphaunt?.target, spec.artifact.target); + assert.deepEqual(manifest.os, [spec.artifact.npm_os]); + assert.deepEqual(manifest.cpu, [spec.artifact.npm_cpu]); + assert.deepEqual(manifest.libc, spec.artifact.npm_libc ? [spec.artifact.npm_libc] : undefined); + assert.equal(manifest.exports?.['./package.json'], './package.json'); + if (spec.artifact.kind === 'native-runtime') + assert.equal(manifest.oliphaunt?.libraryRelativePath, spec.artifact.library_relative_path); + assert.equal(manifest.oliphaunt?.runtimeRelativePath, 'runtime'); + return row; +} + +export async function packageEnvelope(spec: EnvelopeSpec): Promise { + const output = path.resolve(spec.output); + mkdirSync(path.dirname(output), { recursive: true }); + const root = mkdtempSync(path.join(tmpdir(), 'native-envelope-')); + try { + const payload = path.join(root, 'payload'); + const executables = + spec.artifact.kind === 'native-tools' + ? requiredToolsMemberPaths(spec.artifact.target, 'runtime/bin') + : requiredRuntimeMemberPaths(spec.artifact.target, 'runtime/bin'); + copyDeclaredTree(spec.payload, payload, executables); + if (spec.phase === 'github') { + assert.equal( + path.basename(output), + spec.artifact.asset.replaceAll('{version}', spec.version), + ); + await archiveDirectory(payload, output, { + modes: Object.fromEntries(executables.map((name) => [name, 0o755])), + }); + return; + } + const sourceRoot = path.join(root, 'legal'); + stageLegalSources(spec.legal, sourceRoot); + const notices = { profile: spec.artifact.kind, sourceRoot }; + if (spec.phase === 'npm') { + const descriptors = path.join(root, 'descriptors'); + stageLegalSources(spec.sources, descriptors); + const manifest = JSON.parse(readFileSync(path.join(descriptors, 'package.json'), 'utf8')); + const row = validateNpmIdentity(manifest, spec); + const stage = stageNpmPackageDescriptor(row.name, descriptors, spec.version, { + target: spec.artifact.target, + stageDir: path.join(root, 'package'), + }); + cpSync(path.join(payload, 'runtime'), path.join(stage, 'runtime'), { recursive: true }); + const executableMembers = executables.map((name) => `package/${name}`); + const required = [...executableMembers]; + if (spec.artifact.kind === 'native-runtime') { + const library = spec.artifact.library_relative_path; + assert(library, 'native runtime omitted its canonical library path'); + mkdirSync(path.dirname(member(stage, library)), { recursive: true }); + copyFileSync(member(payload, library), member(stage, library)); + cpSync(path.join(payload, 'lib/modules'), path.join(stage, 'lib/modules'), { + recursive: true, + }); + required.push( + `package/${library}`, + ...requiredCoreRuntimePaths(spec.artifact.target).map( + (name) => `package/runtime/${name}`, + ), + ); + if (spec.artifact.target === 'windows-x64-msvc') { + // The wrapper uses the root bin directory; carry the same explicit DLL/receipt closure. + cpSync(path.join(payload, 'bin'), path.join(stage, 'bin'), { recursive: true }); + } + } + stageReleaseNotices(stage, notices); + required.push(...releaseNoticeRows(notices).map(({ member }) => `package/${member}`)); + const tarball = packGeneratedNpmCarrier(stage, path.join(root, 'tarballs')); + validatePackedNpmPackage({ + packageName: row.name, + version: spec.version, + tarball, + requiredMembers: required, + executableMembers, + }); + assertReleaseNoticesInArchive(tarball, { ...notices, prefix: 'package' }); + copyFileSync(tarball, output); + } else { + assert.equal(spec.phase, 'cargo'); + mkdirSync(output, { recursive: true }); + const packageBase = + spec.artifact.kind === 'native-tools' ? 'oliphaunt-tools' : 'liboliphaunt-native'; + const packages = packagePayload( + payload, + path.join(root, 'sources'), + output, + path.join(root, 'cargo'), + { + target: { ...spec.artifact, libraryRelativePath: spec.artifact.library_relative_path }, + version: spec.version, + partBytes: spec.partBytes ?? 64 * 1024 * 1024, + packageBase, + artifactProduct: packageBase, + artifactKind: spec.artifact.kind, + artifactLabel: + spec.artifact.kind === 'native-tools' + ? 'Oliphaunt native tools' + : 'Oliphaunt native runtime', + noticeProfile: spec.artifact.kind, + noticeSourceRoot: sourceRoot, + executableFiles: executables, + }, + ); + const carrier = spec.carriers.filter( + (row) => + row.ecosystem === 'cargo' && + row.target === spec.artifact.target && + row.name === packages.find(({ role }) => role === 'aggregator')?.name, + ); + assert.equal(carrier.length, 1, 'canonical Cargo aggregator must be unique'); + assert.equal(packages.find(({ role }) => role === 'aggregator')?.name, carrier[0].name); + // packages.json retains actual conventional manifests, never private /tmp paths. + for (const pkg of packages) { + const manifest = path.join(output, 'manifests', pkg.name, 'Cargo.toml'); + mkdirSync(path.dirname(manifest), { recursive: true }); + copyFileSync(pkg.manifestPath, manifest); + pkg.manifestPath = path.join(spec.output, 'manifests', pkg.name, 'Cargo.toml'); + pkg.cratePath = path.join(spec.output, path.basename(pkg.cratePath)); + } + writePackagesManifest(packages, output, spec.artifact.product); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + assert.equal(process.argv.length, 3, 'usage: envelopes.mts '); + await packageEnvelope(JSON.parse(readFileSync(process.argv[2], 'utf8'))); +} diff --git a/build_defs/native/carriers/facades.mts b/build_defs/native/carriers/facades.mts new file mode 100644 index 000000000..00692b7ac --- /dev/null +++ b/build_defs/native/carriers/facades.mts @@ -0,0 +1,131 @@ +/** Tools source facades always describe every canonical platform, independent of payload selection. */ +import assert from 'node:assert/strict'; +import { copyFileSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { writeToolsFacadeCrate } from '../../../src/native/postgres-tools/tools/package-cargo-artifacts.mts'; +import { emitJavaScript } from '../../../tools/packaging/emit-javascript.mts'; +import { freezeSourceCrate } from '../../../tools/packaging/native-cargo-payload.mts'; +import { packGeneratedNpmCarrier } from '../../../tools/packaging/npm-package.mts'; +import { + stageNpmPackageDescriptor, + validatePackedNpmPackage, +} from '../../../tools/packaging/release-carrier.mts'; +import { + assertReleaseNoticesInArchive, + releaseNoticeRows, + stageReleaseNotices, +} from '../../../tools/packaging/release-notices.mts'; +import { type Artifact, member, stageLegalSources } from './payload.mts'; + +export interface FacadeSpec { + phase: 'npm' | 'cargo'; + version: string; + targets: Artifact[]; + carriers: { + ecosystem: string; + name: string; + version: string; + role: string; + target: string | null; + }[]; + sources: Record; + legal: Record; + output: string; +} + +export function toolsFacadeTargets(spec: FacadeSpec): Artifact[] { + const targets = spec.targets.filter( + (row) => row.product === 'postgres-tools-native' && row.kind === 'native-tools', + ); + assert( + targets.length > 0 && new Set(targets.map(({ target }) => target)).size === targets.length, + 'canonical tools target list must be unique and complete', + ); + const leaves = spec.carriers.filter((row) => row.ecosystem === 'npm' && row.target !== null); + assert.deepEqual( + targets.map(({ npm_package }) => npm_package).sort(), + leaves.map(({ name }) => name).sort(), + 'tools facade must describe all declared platform leaves', + ); + assert( + leaves.every(({ version }) => version === spec.version), + 'tools platform leaf version disagrees with product', + ); + return targets; +} + +export function packageToolsFacade(spec: FacadeSpec): void { + const targets = toolsFacadeTargets(spec); + const root = mkdtempSync(path.join(tmpdir(), 'native-tools-facade-')); + try { + const sourceRoot = path.join(root, 'legal'); + const sources = path.join(root, 'sources'); + stageLegalSources(spec.legal, sourceRoot); + stageLegalSources(spec.sources, sources); + mkdirSync(path.dirname(spec.output), { recursive: true }); + if (spec.phase === 'npm') { + const rows = spec.carriers.filter((row) => row.ecosystem === 'npm' && row.target === null); + assert.equal(rows.length, 1, 'canonical tools npm facade must be unique'); + const row = rows[0]; + const stage = stageNpmPackageDescriptor(row.name, sources, spec.version, { + stageDir: path.join(root, 'package'), + }); + const manifestFile = path.join(stage, 'package.json'); + const manifest = JSON.parse(readFileSync(manifestFile, 'utf8')); + assert.deepEqual( + Object.keys(manifest.optionalDependencies).sort(), + targets.map(({ npm_package }) => npm_package).sort(), + 'authored tools optional dependencies disagree with canonical leaves', + ); + delete manifest.scripts; + manifest.optionalDependencies = Object.fromEntries( + Object.keys(manifest.optionalDependencies) + .sort() + .map((name) => [name, spec.version]), + ); + writeFileSync(manifestFile, `${JSON.stringify(manifest, null, 2)}\n`); + emitJavaScript(path.join(sources, 'index.mts'), path.join(stage, 'index.js')); + copyFileSync(path.join(sources, 'index.d.ts'), path.join(stage, 'index.d.ts')); + const notices = { profile: 'source-sdk', sourceRoot }; + stageReleaseNotices(stage, notices); + const tarball = packGeneratedNpmCarrier(stage, path.join(root, 'tarballs')); + validatePackedNpmPackage({ + packageName: row.name, + version: spec.version, + tarball, + requiredMembers: [ + 'package/index.js', + 'package/index.d.ts', + ...releaseNoticeRows(notices).map(({ member }) => `package/${member}`), + ], + }); + assertReleaseNoticesInArchive(tarball, { ...notices, prefix: 'package' }); + copyFileSync(tarball, spec.output); + } else { + assert.equal(spec.phase, 'cargo'); + const pkg = writeToolsFacadeCrate(path.join(root, 'generated'), { + version: spec.version, + toolsTargets: targets, + templateRoot: sources, + fixture: member(sources, 'testdata/logical-tools.json'), + noticeSourceRoot: sourceRoot, + }); + const rows = spec.carriers.filter((row) => row.ecosystem === 'cargo' && row.target === null); + assert.equal(rows.length, 1); + assert.equal(pkg.name, rows[0].name); + mkdirSync(path.join(root, 'out'), { recursive: true }); + const frozen = freezeSourceCrate(pkg, path.join(root, 'out'), path.join(root, 'cargo'), { + noticeSourceRoot: sourceRoot, + }); + copyFileSync(frozen.cratePath, spec.output); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + assert.equal(process.argv.length, 3, 'usage: facades.mts '); + packageToolsFacade(JSON.parse(readFileSync(process.argv[2], 'utf8'))); +} diff --git a/build_defs/native/carriers/installed.test.mts b/build_defs/native/carriers/installed.test.mts new file mode 100644 index 000000000..2552be33f --- /dev/null +++ b/build_defs/native/carriers/installed.test.mts @@ -0,0 +1,312 @@ +/** Qualify relocation of the finished public GitHub and npm carriers. */ +import assert from 'node:assert/strict'; +import { + chmodSync, + copyFileSync, + mkdirSync, + mkdtempSync, + readFileSync, + renameSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { createServer } from 'node:net'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + extractPortableArchiveTree, + readPortableArchiveEntries, +} from '../../../tools/packaging/portable-archive.mts'; +import { + assertMissingHostRuntime, + hostRuntimeEnvironment, + runHostBinary, +} from '../host-runtime-test-helpers.mts'; +import { expectedLogicalValue, VERIFY_SQL } from './tools-consumer.mts'; + +const [ + runtimeArchive, + runtimeNpmArchive, + toolsArchive, + facadeArchive, + leafArchive, + profileConsumer, + npmConsumer, + fixture, + node, +] = process.argv.slice(2).map((file) => path.resolve(file)); +assert( + runtimeArchive && + runtimeNpmArchive && + toolsArchive && + facadeArchive && + leafArchive && + profileConsumer && + npmConsumer && + fixture && + node, +); +const root = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'installed-native-')); +const windows = process.platform === 'win32'; +const suffix = windows ? '.exe' : ''; +const native = path.join(root, 'installed-runtime'); +const runtime = path.join(native, 'runtime'); +const tools = path.join(root, 'installed-tools/runtime'); +const consumer = path.join(root, `consumer${suffix}`); +const database = path.join(root, 'server-database'); +const restored = path.join(root, 'server-backup'); +// Socket filenames have a small independent OS limit, even when TEST_TMPDIR is long. +const socket = windows ? undefined : mkdtempSync('/tmp/oliphaunt-carrier-socket-'); +let running: string | undefined; +const library = windows + ? 'bin/oliphaunt.dll' + : process.platform === 'darwin' + ? 'lib/liboliphaunt.dylib' + : 'lib/liboliphaunt.so'; +function runtimeEnvironment(installed: string): NodeJS.ProcessEnv { + const installedRuntime = path.join(installed, 'runtime'); + const env = hostRuntimeEnvironment(installedRuntime, root); + delete env.ICU_DATA; + if (windows) env.PATH = [path.join(installed, 'bin'), env.PATH].join(';'); + else + env[process.platform === 'darwin' ? 'DYLD_LIBRARY_PATH' : 'LD_LIBRARY_PATH'] = [ + path.join(installed, 'lib'), + path.join(installedRuntime, 'lib'), + ].join(':'); + return env; +} + +function installNpmLeaf(archive: string, modules: string) { + // Read the selected package identity from the actual final archive, not a host-name map. + const entry = readPortableArchiveEntries(archive).get('package/package.json'); + assert(entry?.isFile); + const manifest = JSON.parse(entry.data().toString()); + assert.match(manifest.name, /^@oliphaunt\/[a-z0-9][a-z0-9._-]*$/u); + assert.equal(manifest.oliphaunt?.runtimeRelativePath, 'runtime'); + const installed = path.join(modules, ...manifest.name.split('/')); + extractPortableArchiveTree(archive, installed, 'package'); + return { manifest, installed }; +} + +const env = runtimeEnvironment(native); +const run = (binary: string, args: string[], overrides: NodeJS.ProcessEnv = {}) => + runHostBinary(binary, args, { ...env, ...overrides }, root); +// Raw ICU and prepared cluster seeds have separate public products. Bootstrap +// this libc smoke through the existing minimal native-initdb contract. +const bootstrap = { + OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY: '1', + OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY: '1', +}; +const control = path.join(runtime, `bin/pg_ctl${suffix}`); +async function freeTcpPort(): Promise { + const server = createServer(); + await new Promise((accept, reject) => { + server.once('error', reject); + server.listen(0, '127.0.0.1', accept); + }); + const address = server.address(); + assert(address && typeof address !== 'string'); + await new Promise((accept, reject) => + server.close((error) => (error ? reject(error) : accept())), + ); + return String(address.port); +} + +try { + // Bazel input aliases are resolved at this boundary; archive validation still + // requires regular private files and never follows links inside an archive. + const archives = [ + runtimeArchive, + runtimeNpmArchive, + toolsArchive, + facadeArchive, + leafArchive, + ].map((source, index) => { + const destination = path.join(root, `input-${index}-${path.basename(source)}`); + copyFileSync(source, destination); + return destination; + }); + const [privateRuntime, privateRuntimeNpm, privateTools, privateFacade, privateLeaf] = archives; + const privateNpmConsumer = path.join(root, 'npm-consumer.mts'); + copyFileSync(npmConsumer, privateNpmConsumer); + extractPortableArchiveTree(privateRuntime, native); + extractPortableArchiveTree(privateTools, path.dirname(tools)); + copyFileSync(profileConsumer, consumer); + chmodSync(consumer, 0o755); + const modules = path.join(root, 'node_modules'); + const runtimeLeaf = installNpmLeaf(privateRuntimeNpm, modules); + assert.equal(runtimeLeaf.manifest.oliphaunt?.libraryRelativePath, library); + for (const [origin, installed] of [ + ['github', native], + ['npm', runtimeLeaf.installed], + ]) { + const installedRuntime = path.join(installed, 'runtime'); + const installedEnv = runtimeEnvironment(installed); + const runInstalled = (binary: string, args: string[], overrides: NodeJS.ProcessEnv = {}) => + runHostBinary(binary, args, { ...installedEnv, ...overrides }, root); + const embeddedRoot = path.join(root, `${origin}-embedded-database`); + const embedded = path.join(embeddedRoot, 'pgdata'); + mkdirSync(embeddedRoot); + runInstalled( + path.join(installedRuntime, `bin/initdb${suffix}`), + [ + '-D', + embedded, + '-U', + 'postgres', + '--locale-provider=libc', + '--locale=C', + '--encoding=UTF8', + '--auth=trust', + '--no-sync', + ], + bootstrap, + ); + writeFileSync( + path.join(embeddedRoot, '.oliphaunt.json'), + `${JSON.stringify({ + schema: 'oliphaunt-database-root-v1', + engineFamily: 'native', + pgdata: 'pgdata', + postgresMajor: 18, + physicalFormat: 'native-pg18-v1', + })}\n`, + ); + runInstalled(consumer, [ + embedded, + installedRuntime, + 'CREATE TABLE persisted(value integer); INSERT INTO persisted VALUES (42); SELECT 42', + '42', + ]); + runInstalled(consumer, [embedded, installedRuntime, 'SELECT value FROM persisted', '42']); + runInstalled(consumer, [ + embedded, + installedRuntime, + "DO $$ BEGIN PERFORM 42; END $$; SELECT to_tsvector('english', 'running')", + 'run', + ]); + const held = path.join(installed, library); + renameSync(held, `${held}.removed`); + try { + const missing = Bun.spawnSync([consumer, embedded, installedRuntime, 'SELECT 42', '42'], { + env: installedEnv, + cwd: root, + stdout: 'pipe', + stderr: 'pipe', + }); + assertMissingHostRuntime(missing, path.basename(library)); + } finally { + renameSync(`${held}.removed`, held); + } + } + + const facade = path.join(modules, '@oliphaunt/tools'); + extractPortableArchiveTree(privateFacade, facade, 'package'); + const { manifest: leafManifest, installed: leaf } = installNpmLeaf(privateLeaf, modules); + const packedFacade = JSON.parse(readFileSync(path.join(facade, 'package.json'), 'utf8')); + assert.equal(packedFacade.optionalDependencies[leafManifest.name], leafManifest.version); + env.PGUSER = 'oliphaunt_carrier_test'; + env.PGDATABASE = 'postgres'; + env.PGPORT = await freeTcpPort(); + env.PGHOST = windows ? '127.0.0.1' : socket; + const connectionEnvironment = { + PGUSER: env.PGUSER, + PGDATABASE: env.PGDATABASE, + PGPORT: env.PGPORT, + PGHOST: env.PGHOST, + }; + const toolsEnv = { ...hostRuntimeEnvironment(tools, root), ...connectionEnvironment }; + const runTools = (binary: string, args: string[]) => runHostBinary(binary, args, toolsEnv, root); + mkdirSync(database); + run( + path.join(runtime, `bin/initdb${suffix}`), + [ + '-D', + database, + '-U', + env.PGUSER, + '--locale=C', + '--encoding=UTF8', + '--auth=trust', + '--no-sync', + ], + bootstrap, + ); + const options = windows ? `-h 127.0.0.1 -p ${env.PGPORT}` : `-k ${socket} -h '' -p ${env.PGPORT}`; + const start = (directory: string) => { + running = directory; + runHostBinary( + control, + [ + '-D', + directory, + '-l', + path.join(root, `${path.basename(directory)}.log`), + '-o', + options, + '-w', + 'start', + ], + env, + root, + 'inherit', + ); + }; + start(database); + const connection = `host=${env.PGHOST} port=${env.PGPORT} user=${env.PGUSER} dbname=postgres`; + runHostBinary( + node, + [privateNpmConsumer, path.join(facade, 'index.js'), connection, fixture], + { + ...hostRuntimeEnvironment(path.join(leaf, 'runtime'), root), + ...connectionEnvironment, + NODE_PATH: '', + NODE_OPTIONS: '', + }, + root, + ); + runTools(path.join(tools, `bin/pg_basebackup${suffix}`), [ + '-D', + restored, + '--format=plain', + '--wal-method=stream', + '--checkpoint=fast', + '--no-sync', + ]); + assert( + readFileSync(path.join(restored, 'backup_manifest'), 'utf8').includes( + 'PostgreSQL-Backup-Manifest-Version', + ), + ); + run(control, ['-D', database, '-m', 'fast', '-w', 'stop']); + running = undefined; + start(restored); + const logicalFixture = JSON.parse(readFileSync(fixture, 'utf8')); + assert.equal( + runTools(path.join(tools, `bin/psql${suffix}`), [ + '-X', + '-A', + '-t', + '-v', + 'ON_ERROR_STOP=1', + '-c', + VERIFY_SQL, + ]).trim(), + expectedLogicalValue(logicalFixture), + ); + run(control, ['-D', restored, '-m', 'fast', '-w', 'stop']); + running = undefined; + console.log( + 'Installed native carriers: GitHub and npm libc-profile relocated C query/reopen/modules and missing-library guards; isolated npm facade dump/restore and GitHub tools backup/reopen passed.', + ); +} finally { + if (running) + Bun.spawnSync([control, '-D', running, '-m', 'immediate', '-w', 'stop'], { + env, + cwd: root, + stdout: 'pipe', + stderr: 'pipe', + }); + if (socket) rmSync(socket, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/native/carriers/package.test.mts b/build_defs/native/carriers/package.test.mts new file mode 100644 index 000000000..831e82f83 --- /dev/null +++ b/build_defs/native/carriers/package.test.mts @@ -0,0 +1,549 @@ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { randomBytes } from 'node:crypto'; +import { + chmodSync, + copyFileSync, + existsSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + rmSync, + statSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { + requiredCoreRuntimePaths, + requiredRuntimeTools, + requiredToolsPackageTools, +} from '../../../src/native/runtime/tools/native-runtime-payload.mts'; +import { readPortableArchiveEntries } from '../../../tools/packaging/portable-archive.mts'; +import { + releaseNoticeRows, + stageReleaseNotices, +} from '../../../tools/packaging/release-notices.mts'; +import { + windowsImportLibraryFixture, + windowsPeFixture, +} from '../../../tools/packaging/testdata/release-fixture-utils.mts'; +import { + WINDOWS_VC_RUNTIME_DLLS, + WINDOWS_VC_RUNTIME_RECEIPT, +} from '../../../tools/packaging/windows-vc-runtime-closure.mts'; +import { writeNativeChecksums } from './checksums.mts'; +import { type EnvelopeSpec, packageEnvelope, validateNpmIdentity } from './envelopes.mts'; +import { type FacadeSpec, packageToolsFacade, toolsFacadeTargets } from './facades.mts'; +import { + copyDeclaredTree, + materializeMappings, + packageNativePayload, + stageLegalSources, +} from './payload.mts'; + +const [inputs] = process.argv.slice(2); +assert(inputs, 'expected canonical carrier test inputs'); +const specification = JSON.parse(readFileSync(inputs, 'utf8')); +const root = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'native-carrier-tests-')); +function requiredMember( + entries: ReturnType, + name: string, +): Buffer { + const entry = entries.get(name); + assert(entry?.isFile, `missing regular archive member ${name}`); + return Buffer.from(entry.data()); +} +function assertCargoDataModes(entries: ReturnType): void { + for (const [name, entry] of entries) + assert.equal(entry.mode, entry.isDirectory ? 0o755 : 0o644, name); +} +let scenarios = 0; +try { + // Exercise the exact declared payload tool tree, without the envelope tool's + // much larger module set or the checkout as an import fallback. + const modules = path.join(root, 'payload-modules'); + for (const [relative, file] of Object.entries(specification.payloadModules)) { + assert(!relative.startsWith('../') && !path.isAbsolute(relative)); + const destination = path.join(modules, relative); + mkdirSync(path.dirname(destination), { recursive: true }); + copyFileSync(file as string, destination); + } + const importedPayload = path.join(modules, 'build_defs/native/carriers/payload.mts'); + const probePayload = () => + spawnSync( + process.execPath, + [ + '--no-env-file', + '--no-install', + '--eval', + `await import(${JSON.stringify(pathToFileURL(importedPayload).href)})`, + ], + { cwd: modules, env: {}, encoding: 'utf8' }, + ); + assert.equal(probePayload().status, 0, 'declared payload module closure must execute'); + assert(!existsSync(path.join(modules, 'build_defs/native/carriers/envelopes.mts'))); + const unused = path.join(modules, 'tools/packaging/npm-package.mts'); + writeFileSync(unused, 'deliberately invalid unused envelope code'); + assert.equal(probePayload().status, 0, 'envelope code must not enter the payload import closure'); + const policy = path.join(modules, 'src/native/runtime/tools/native-runtime-payload-policy.json'); + const policyBytes = readFileSync(policy); + writeFileSync(policy, 'invalid consumed payload policy'); + assert.notEqual( + probePayload().status, + 0, + 'consumed payload policy must remain an actual module input', + ); + writeFileSync(policy, policyBytes); + const binaryHelper = path.join(modules, 'tools/packaging/platform-binary-contract.mts'); + const helperBytes = readFileSync(binaryHelper); + writeFileSync(binaryHelper, 'deliberately invalid consumed binary validator'); + assert.notEqual( + probePayload().status, + 0, + 'consumed binary validator must remain an actual module input', + ); + writeFileSync(binaryHelper, helperBytes); + assert.equal(probePayload().status, 0); + scenarios++; + + const scalar = path.join(root, 'scalar'); + writeFileSync(scalar, 'actual producer bytes'); + const tree = path.join(root, 'tree'); + mkdirSync(path.join(tree, 'nested'), { recursive: true }); + writeFileSync(path.join(tree, 'nested/data'), 'timezone bytes'); + const output = path.join(root, 'mapped'); + const mappings = [ + { source: scalar, destination: 'runtime/bin/postgres', tree: false, mode: '0755' }, + { source: tree, destination: 'runtime/share/postgresql/timezone', tree: true, mode: '0644' }, + ]; + materializeMappings(mappings, output); + assert.equal( + readFileSync(path.join(output, 'runtime/bin/postgres'), 'utf8'), + 'actual producer bytes', + ); + assert.equal(statSync(path.join(output, 'runtime/bin/postgres')).mode & 0o777, 0o755); + assert.equal( + readFileSync(path.join(output, 'runtime/share/postgresql/timezone/nested/data'), 'utf8'), + 'timezone bytes', + ); + assert.throws( + () => materializeMappings([...mappings, mappings[0]], path.join(root, 'duplicate')), + /duplicate/, + ); + assert.throws( + () => + materializeMappings( + [{ ...mappings[0], destination: '../escape' }], + path.join(root, 'escape'), + ), + /unsafe/, + ); + assert.throws( + () => materializeMappings([{ ...mappings[0], mode: '0777' }], path.join(root, 'bad-mode')), + /mode/, + ); + symlinkSync(scalar, path.join(tree, 'escape')); + assert.throws( + () => materializeMappings([mappings[1]], path.join(root, 'linked')), + /symbolic link/, + ); + rmSync(path.join(tree, 'escape')); + scenarios++; + + const generated = path.join(root, 'producer/declared/tree'); + const sandbox = path.join(root, 'sandbox'); + const projected = path.join(sandbox, 'declared/tree'); + mkdirSync(path.join(generated, 'nested'), { recursive: true }); + mkdirSync(path.join(projected, 'nested'), { recursive: true }); + writeFileSync(path.join(generated, 'nested/data'), 'declared tree bytes'); + symlinkSync(path.join(generated, 'nested/data'), path.join(projected, 'nested/data')); + const sourceCwd = process.cwd(); + try { + process.chdir(sandbox); + copyDeclaredTree('declared/tree', path.join(root, 'physical-tree')); + assert.equal( + readFileSync(path.join(root, 'physical-tree/nested/data'), 'utf8'), + 'declared tree bytes', + ); + const runfiles = path.join(root, 'runfiles/maven'); + mkdirSync(path.dirname(runfiles), { recursive: true }); + symlinkSync(projected, runfiles); + copyDeclaredTree(runfiles, path.join(root, 'runfiles-tree'), undefined, 'declared/tree'); + assert.equal( + readFileSync(path.join(root, 'runfiles-tree/nested/data'), 'utf8'), + 'declared tree bytes', + ); + assert.throws( + () => copyDeclaredTree(runfiles, path.join(root, 'undeclared-runfiles-tree')), + /execroot-relative/, + ); + assert.throws( + () => + copyDeclaredTree(runfiles, path.join(root, 'wrong-runfiles-tree'), undefined, 'other/tree'), + /escapes/, + ); + const otherRoot = path.join(root, 'other-producer/declared/tree'); + mkdirSync(otherRoot, { recursive: true }); + writeFileSync(path.join(otherRoot, 'second'), 'other producer bytes'); + symlinkSync(path.join(otherRoot, 'second'), path.join(projected, 'second')); + assert.throws( + () => copyDeclaredTree(runfiles, path.join(root, 'mixed-roots'), undefined, 'declared/tree'), + /mixed physical roots/, + ); + rmSync(path.join(projected, 'second')); + chmodSync(path.join(generated, 'nested/data'), 0o755); + copyDeclaredTree('declared/tree', path.join(root, 'normalized-tree'), []); + assert.equal(statSync(path.join(root, 'normalized-tree/nested/data')).mode & 0o777, 0o644); + assert.throws( + () => copyDeclaredTree('declared/tree', path.join(root, 'missing-executable'), ['missing']), + /omitted executable/, + ); + symlinkSync(scalar, path.join(projected, 'outside')); + assert.throws( + () => copyDeclaredTree('declared/tree', path.join(root, 'outside-tree')), + /escapes/, + ); + rmSync(path.join(projected, 'outside')); + rmSync(path.join(generated, 'nested/data')); + symlinkSync(scalar, path.join(generated, 'nested/data')); + assert.throws( + () => copyDeclaredTree('declared/tree', path.join(root, 'authored-link-tree')), + /non-regular original/, + ); + } finally { + process.chdir(sourceCwd); + } + scenarios++; + + const artifact = specification.targets.find(({ target }) => target === 'linux-x64-gnu'); + const leaf = specification.carriers.find( + ({ ecosystem, name }) => ecosystem === 'npm' && name === artifact.npm_package, + ); + const manifest = { + name: leaf.name, + version: specification.version, + os: [artifact.npm_os], + cpu: [artifact.npm_cpu], + libc: [artifact.npm_libc], + exports: { './package.json': './package.json' }, + oliphaunt: { target: artifact.target, runtimeRelativePath: 'runtime' }, + }; + const envelope: EnvelopeSpec = { + phase: 'npm', + artifact, + version: specification.version, + carriers: specification.carriers, + payload: output, + sources: {}, + legal: specification.legal, + output: path.join(root, 'leaf.tgz'), + }; + assert.equal(validateNpmIdentity(manifest, envelope).name, leaf.name); + assert.throws(() => validateNpmIdentity({ ...manifest, version: '999.0.0' }, envelope)); + assert.throws(() => validateNpmIdentity({ ...manifest, cpu: ['arm64'] }, envelope)); + scenarios++; + + const facade: FacadeSpec = { + phase: 'npm', + version: specification.version, + targets: specification.targets, + carriers: specification.carriers, + sources: Object.fromEntries( + Object.entries(specification.sources) + .filter(([name]) => name.startsWith('npm/')) + .map(([name, file]) => [name.slice(4), file]), + ) as Record, + legal: specification.legal, + output: path.join(root, 'tools.tgz'), + }; + assert.equal(toolsFacadeTargets(facade).length, specification.targets.length); + assert.throws( + () => toolsFacadeTargets({ ...facade, targets: facade.targets.slice(1) }), + /all declared/, + ); + packageToolsFacade(facade); + const npm = readPortableArchiveEntries(facade.output); + const packed = JSON.parse(requiredMember(npm, 'package/package.json').toString()); + assert.deepEqual( + packed.optionalDependencies, + Object.fromEntries( + specification.targets.map(({ npm_package }) => [npm_package, specification.version]), + ), + ); + assert.equal(packed.scripts, undefined); + assert(requiredMember(npm, 'package/index.js').toString().includes('resolveRuntime')); + const repeat = path.join(root, 'tools-repeat.tgz'); + packageToolsFacade({ ...facade, output: repeat }); + assert.deepEqual(readFileSync(repeat), readFileSync(facade.output)); + scenarios++; + + const cargoFacade = { + ...facade, + phase: 'cargo' as const, + sources: Object.fromEntries( + Object.entries(specification.sources) + .filter(([name]) => name.startsWith('cargo/')) + .map(([name, file]) => [name.slice(6), file]), + ) as Record, + output: path.join(root, 'tools.crate'), + }; + packageToolsFacade(cargoFacade); + const cargo = readPortableArchiveEntries(cargoFacade.output); + assertCargoDataModes(cargo); + const text = requiredMember( + cargo, + `oliphaunt-tools-${specification.version}/Cargo.toml`, + ).toString(); + const cargoManifest = Bun.TOML.parse(text); + const dependencies = Object.values(cargoManifest.target).flatMap((table) => + Object.entries(table.dependencies), + ); + assert.deepEqual( + dependencies.map(([name]) => name).sort(), + specification.targets.map(({ target }) => `oliphaunt-tools-${target}`).sort(), + ); + for (const [, dependency] of dependencies) + assert.deepEqual(dependency, { version: `=${specification.version}` }); + assert(cargo.has(`oliphaunt-tools-${specification.version}/testdata/logical-tools.json`)); + scenarios++; + + const payload = path.join(root, 'cargo-payload'); + mkdirSync(path.join(payload, 'runtime/bin'), { recursive: true }); + writeFileSync(path.join(payload, 'runtime/bin/psql'), randomBytes(1024)); + chmodSync(path.join(payload, 'runtime/bin/psql'), 0o755); + for (const name of ['pg_dump', 'pg_basebackup']) + writeFileSync(path.join(payload, 'runtime/bin', name), 'archive executable'); + chmodSync(path.join(payload, 'runtime/bin/pg_dump'), 0o444); + chmodSync(path.join(payload, 'runtime/bin/pg_basebackup'), 0o666); + writeFileSync(path.join(payload, 'runtime/bin/provider.dll'), 'provider library'); + writeFileSync(path.join(payload, 'runtime/bin/provider-receipt.json'), '{}'); + // Reproduce Bazel's generated-tree permissions, rather than assuming those + // permissions retain the package mapping's distinction between files/programs. + chmodSync(path.join(payload, 'runtime/bin/provider.dll'), 0o755); + chmodSync(path.join(payload, 'runtime/bin/provider-receipt.json'), 0o755); + const legal = path.join(root, 'legal'); + stageLegalSources(specification.legal, legal); + for (const profile of ['native-tools', 'native-runtime']) { + const declared = specification.payloadLegalInputs[profile]; + const required = releaseNoticeRows({ profile, sourceRoot: legal }).flatMap((row) => + [row.source, row.sourceManifest] + .filter((file) => file !== undefined) + .map((file) => path.relative(legal, file)), + ); + assert.deepEqual([...declared].sort(), required.sort(), `${profile} legal source closure`); + } + const toolsLegal = path.join(root, 'tools-legal'); + stageLegalSources( + Object.fromEntries( + specification.payloadLegalInputs['native-tools'].map((name) => [ + name, + specification.legal[name], + ]), + ), + toolsLegal, + ); + assert(!existsSync(path.join(toolsLegal, 'src/third-party/icu'))); + const originalNotices = path.join(root, 'original-tools-notices'); + const narrowedNotices = path.join(root, 'narrowed-tools-notices'); + stageReleaseNotices(originalNotices, { profile: 'native-tools', sourceRoot: legal }); + stageReleaseNotices(narrowedNotices, { profile: 'native-tools', sourceRoot: toolsLegal }); + const compareNotices = (relative = '') => { + const names = readdirSync(path.join(originalNotices, relative)).sort(); + assert.deepEqual(readdirSync(path.join(narrowedNotices, relative)).sort(), names); + for (const name of names) { + const member = path.join(relative, name); + const original = path.join(originalNotices, member); + const narrowed = path.join(narrowedNotices, member); + if (statSync(original).isDirectory()) compareNotices(member); + else assert.deepEqual(readFileSync(narrowed), readFileSync(original), member); + } + }; + compareNotices(); + scenarios++; + + const windowsTarget = 'windows-x64-msvc'; + const windowsSource = path.join(root, 'windows-inputs'); + mkdirSync(windowsSource); + const windowsRuntime = Object.fromEntries( + WINDOWS_VC_RUNTIME_DLLS.map((name) => { + const file = path.join(windowsSource, name); + writeFileSync(file, windowsPeFixture()); + return [name, file]; + }), + ); + const cProgram = path.join(windowsSource, 'c-program.exe'); + writeFileSync(cProgram, windowsPeFixture({ imports: ['vcruntime140.dll'] })); + const data = path.join(windowsSource, 'data'); + writeFileSync(data, 'runtime data fixture'); + const importLibrary = path.join(windowsSource, 'oliphaunt.lib'); + writeFileSync(importLibrary, windowsImportLibraryFixture()); + for (const kind of ['native-tools', 'native-runtime']) { + const runtime = kind === 'native-runtime'; + const programs = runtime + ? requiredRuntimeTools(windowsTarget) + : requiredToolsPackageTools(windowsTarget); + const mappings = programs.map((name) => ({ + source: cProgram, + destination: 'runtime/bin/' + name, + tree: false, + mode: '0755', + })); + if (runtime) { + for (const destination of requiredCoreRuntimePaths(windowsTarget)) + mappings.push({ + source: destination.endsWith('.dll') ? cProgram : data, + destination: 'runtime/' + destination, + tree: false, + mode: '0644', + }); + mappings.push( + { source: cProgram, destination: 'bin/oliphaunt.dll', tree: false, mode: '0644' }, + { source: importLibrary, destination: 'lib/oliphaunt.lib', tree: false, mode: '0644' }, + ); + } + const output = path.join(root, kind); + await packageNativePayload({ + artifact: { kind, target: windowsTarget }, + mappings, + legal: Object.fromEntries( + specification.payloadLegalInputs[kind].map((name) => [name, specification.legal[name]]), + ), + windowsRuntime, + output, + }); + const expected = runtime ? WINDOWS_VC_RUNTIME_DLLS : ['vcruntime140.dll']; + for (const directory of runtime ? ['runtime/bin', 'bin'] : ['runtime/bin']) { + const bin = path.join(output, directory); + assert.deepEqual( + readdirSync(bin) + .filter((name) => WINDOWS_VC_RUNTIME_DLLS.includes(name)) + .sort(), + [...expected].sort(), + kind + ' ' + directory + ' exact VC closure', + ); + assert.deepEqual( + readFileSync(path.join(bin, WINDOWS_VC_RUNTIME_RECEIPT), 'utf8') + .trim() + .split('\n') + .map((line) => line.split(' ')[1]), + [...expected].sort(), + kind + ' ' + directory + ' exact VC receipt', + ); + for (const name of expected) + assert.deepEqual(readFileSync(path.join(bin, name)), readFileSync(windowsRuntime[name])); + } + scenarios++; + } + const cargoOutput = path.join(root, 'cargo-packages'); + await packageEnvelope({ + ...envelope, + phase: 'cargo', + payload, + output: cargoOutput, + partBytes: 256, + }); + const index = JSON.parse(readFileSync(path.join(cargoOutput, 'packages.json'), 'utf8')); + assert.equal(index.schema, 'oliphaunt-liboliphaunt-cargo-artifacts-v1'); + assert(index.packages.filter(({ role }) => role === 'part').length > 4); + assert.equal(index.packages.filter(({ role }) => role === 'aggregator').length, 1); + const cargoEntries = new Map>(); + for (const pkg of index.packages) { + assert(!pkg.manifestPath.includes('native-envelope-')); + assert(statSync(pkg.cratePath).size <= 10 * 1024 * 1024); + const entries = readPortableArchiveEntries(pkg.cratePath); + assertCargoDataModes(entries); + cargoEntries.set(pkg.cratePath, entries); + } + const chunks = index.packages + .filter(({ role }) => role === 'part') + .flatMap(({ cratePath }) => + [...cargoEntries.get(cratePath)!.values()] + .filter((entry) => entry.isFile && /\/psql\.part\d{3}$/u.test(entry.name)) + .map((entry) => Buffer.from(entry.data())), + ); + assert.equal(chunks.length, 4); + assert.deepEqual(Buffer.concat(chunks), readFileSync(path.join(payload, 'runtime/bin/psql'))); + const aggregator = index.packages.find(({ role }) => role === 'aggregator'); + const build = requiredMember( + cargoEntries.get(aggregator.cratePath)!, + `${aggregator.name}-${specification.version}/build.rs`, + ).toString(); + for (const executable of ['pg_dump', 'pg_basebackup', 'psql']) + assert.match(build, new RegExp(`\\("runtime/bin/${executable}", "[0-9a-f]{64}", true\\)`)); + for (const regular of ['provider.dll', 'provider-receipt.json']) + assert.match( + build, + new RegExp(`\\("runtime/bin/${regular.replaceAll('.', '\\.')}", "[0-9a-f]{64}", false\\)`), + ); + const cwd = process.cwd(); + const absoluteLegal = Object.fromEntries( + Object.entries(envelope.legal).map(([name, file]) => [name, path.resolve(file)]), + ); + try { + process.chdir(root); + await packageEnvelope({ + ...envelope, + phase: 'cargo', + payload, + output: 'logical-cargo', + partBytes: 256, + legal: absoluteLegal, + }); + const relative = JSON.parse(readFileSync('logical-cargo/packages.json', 'utf8')); + assert( + relative.packages.every( + ({ cratePath, manifestPath }) => + cratePath.startsWith('logical-cargo/') && + manifestPath.startsWith('logical-cargo/manifests/'), + ), + ); + } finally { + process.chdir(cwd); + } + scenarios++; + + const github = path.join(root, artifact.asset.replaceAll('{version}', specification.version)); + await packageEnvelope({ ...envelope, phase: 'github', payload, output: github }); + const githubEntries = readPortableArchiveEntries(github); + for (const regular of ['provider.dll', 'provider-receipt.json']) + assert.equal(githubEntries.get(`runtime/bin/${regular}`)?.mode, 0o644); + for (const executable of ['pg_dump', 'pg_basebackup', 'psql']) + assert.equal(githubEntries.get(`runtime/bin/${executable}`)?.mode, 0o755); + const copy = path.join(root, 'repeat', path.basename(github)); + await packageEnvelope({ ...envelope, phase: 'github', payload, output: copy }); + assert.deepEqual(readFileSync(github), readFileSync(copy)); + const checksum = path.join(root, 'checksums'); + writeNativeChecksums({ expected: [path.basename(github)], files: [github], output: checksum }); + assert.match( + readFileSync(checksum, 'utf8'), + new RegExp(`^[0-9a-f]{64} \\.\\/${path.basename(github).replaceAll('.', '\\.')}\\n$`), + ); + assert.throws( + () => + writeNativeChecksums({ + expected: [path.basename(github), 'missing'], + files: [github], + output: checksum, + }), + /missing/, + ); + assert.throws( + () => + writeNativeChecksums({ + expected: [path.basename(github)], + files: [github, copy], + output: checksum, + }), + /repeats/, + ); + scenarios++; + console.log( + `Native runtime/tools carriers: ${scenarios} mapping, identity, facade, split-payload and checksum scenarios passed.`, + ); +} finally { + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/native/carriers/payload.mts b/build_defs/native/carriers/payload.mts new file mode 100644 index 000000000..29de3725b --- /dev/null +++ b/build_defs/native/carriers/payload.mts @@ -0,0 +1,233 @@ +/** Materialize only typed rules_pkg Files and TreeArtifacts into the public layout. */ +import assert from 'node:assert/strict'; +import { + chmodSync, + copyFileSync, + lstatSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + readlinkSync, + realpathSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { validatePayload } from '../../../src/native/runtime/tools/native-runtime-payload.mts'; +import { inspectPlatformBinaryTree } from '../../../tools/packaging/platform-binary-contract.mts'; +import { + assertReleaseNoticesInDirectory, + stageReleaseNotices, +} from '../../../tools/packaging/release-notices.mts'; +import { + renderWindowsVcRuntimeSourceReceipt, + stageWindowsVcRuntime, + WINDOWS_VC_RUNTIME_RECEIPT, +} from '../../../tools/packaging/windows-vc-runtime-closure.mts'; + +export interface Mapping { + source: string; + destination: string; + tree: boolean; + mode: string; +} +export interface Artifact { + product: string; + kind: string; + target: string; + triple: string; + asset: string; + library_relative_path?: string; + npm_package?: string; + npm_os?: string; + npm_cpu?: string; + npm_libc?: string; +} +export interface PayloadSpec { + artifact: Pick; + mappings: Mapping[]; + legal: Record; + windowsRuntime: Record; + output: string; +} + +export function member(root: string, relative: string): string { + assert( + typeof relative === 'string' && + relative && + !relative.startsWith('/') && + !relative.includes('\\') && + !/[\u0000-\u001f\u007f]/u.test(relative) && + relative.split('/').every((part) => part && part !== '.' && part !== '..'), + `unsafe payload destination ${JSON.stringify(relative)}`, + ); + return path.join(root, ...relative.split('/')); +} + +function copy(source: string, destination: string, mode: number): void { + assert(lstatSync(source).isFile(), `expected regular declared file ${source}`); + mkdirSync(path.dirname(destination), { recursive: true }); + copyFileSync(source, destination); + chmodSync(destination, mode); +} + +/** Source Files may be runfiles/sandbox aliases; children inside a declared tree may not. */ +export function materializeMappings(mappings: Mapping[], output: string): void { + const destinations = new Set(); + const visit = (source: string, relative: string, tree: boolean, mode: number) => { + const destination = member(output, relative); + assert(!destinations.has(relative), `duplicate native payload destination ${relative}`); + destinations.add(relative); + const stat = lstatSync(source); + assert(!stat.isSymbolicLink(), `declared payload tree contains a symbolic link: ${source}`); + if (tree) { + assert(stat.isDirectory(), `expected declared payload tree ${source}`); + mkdirSync(destination, { recursive: true }); + chmodSync(destination, 0o755); + for (const name of readdirSync(source).sort()) { + const child = path.join(source, name); + visit(child, `${relative}/${name}`, lstatSync(child).isDirectory(), mode); + } + } else copy(source, destination, mode); + }; + mkdirSync(output, { recursive: true }); + for (const mapping of mappings) { + assert(/^[0-7]{3,4}$/u.test(mapping.mode), `unsupported native payload mode ${mapping.mode}`); + const mode = Number.parseInt(mapping.mode, 8); + assert(mode === 0o644 || mode === 0o755, `unsupported native payload mode ${mapping.mode}`); + visit(realpathSync(mapping.source), mapping.destination, mapping.tree, mode); + } +} + +export function stageLegalSources(sources: Record, output: string): void { + for (const [relative, source] of Object.entries(sources)) + copy(realpathSync(source), member(output, relative), 0o644); +} + +/** Materialize one declared TreeArtifact's one-hop sandbox file aliases. + * Original tree files must be regular, belong to the same logical tree, and + * share one physical root. Authored symlinks and directory links stay invalid. + * declaredPath retains File.path identity for absolute runfiles inputs. + */ +export function copyDeclaredTree( + source: string, + output: string, + executableFiles?: readonly string[], + declaredPath = source, +): void { + const root = realpathSync(source); + let physicalRoot: string | undefined; + const rows: Mapping[] = []; + const visit = (directory: string, relative = '') => { + assert(lstatSync(directory).isDirectory(), `expected declared tree directory ${directory}`); + mkdirSync(relative ? member(output, relative) : output, { recursive: true }); + for (const name of readdirSync(directory).sort()) { + const child = path.join(directory, name); + const destination = relative ? `${relative}/${name}` : name; + const metadata = lstatSync(child); + if (metadata.isDirectory()) { + visit(child, destination); + continue; + } + let original = child; + let owner = root; + if (metadata.isSymbolicLink()) { + assert( + !path.isAbsolute(declaredPath) && !declaredPath.split('/').includes('..'), + 'sandbox tree aliases require the declared execroot-relative TreeArtifact path', + ); + original = path.resolve(path.dirname(child), readlinkSync(child)); + owner = path.resolve(original, ...destination.split('/').map(() => '..')); + assert( + owner.endsWith(path.sep + path.normalize(declaredPath)), + `sandbox file alias escapes the declared tree: ${child}`, + ); + } + const originalMetadata = lstatSync(original); + assert(originalMetadata.isFile(), `declared tree has a non-regular original file: ${child}`); + physicalRoot ??= owner; + assert.equal(owner, physicalRoot, 'declared tree file aliases have mixed physical roots'); + rows.push({ + source: original, + destination, + tree: false, + mode: originalMetadata.mode & 0o100 ? '0755' : '0644', + }); + } + }; + visit(root); + if (executableFiles !== undefined) { + const executables = new Set(executableFiles); + assert.equal(executables.size, executableFiles.length, 'duplicate executable tree member'); + const members = new Set(rows.map(({ destination }) => destination)); + for (const name of executables) { + member(output, name); + assert(members.has(name), `declared tree omitted executable member ${name}`); + } + // Bazel can make every generated tree member executable. Public modes + // therefore come from the declared payload contract at this boundary. + for (const row of rows) row.mode = executables.has(row.destination) ? '0755' : '0644'; + } + materializeMappings(rows, output); +} + +export async function packageNativePayload(spec: PayloadSpec): Promise { + assert( + ['native-runtime', 'native-tools'].includes(spec.artifact.kind), + 'unsupported native payload kind', + ); + const output = path.resolve(spec.output); + const windowsVcRuntimeProfile = spec.artifact.kind === 'native-runtime' ? 'provider' : undefined; + const temporary = mkdtempSync(path.join(tmpdir(), 'native-public-payload-')); + try { + const mappings = spec.mappings.map((mapping, index) => { + if (!mapping.tree) return mapping; + const source = path.join(temporary, `tree-${index}`); + copyDeclaredTree(mapping.source, source); + return { ...mapping, source }; + }); + materializeMappings(mappings, output); + const sourceRoot = path.join(temporary, 'legal-sources'); + stageLegalSources(spec.legal, sourceRoot); + const notices = { profile: spec.artifact.kind, sourceRoot }; + stageReleaseNotices(output, notices); + if (spec.artifact.target === 'windows-x64-msvc') { + const source = path.join(temporary, 'vc-runtime'); + mkdirSync(source); + for (const [name, file] of Object.entries(spec.windowsRuntime)) + copy(realpathSync(file), member(source, name), 0o644); + writeFileSync( + path.join(source, WINDOWS_VC_RUNTIME_RECEIPT), + renderWindowsVcRuntimeSourceReceipt({ sourceDirectory: source, profile: 'provider' }), + ); + const destinations = [path.join(output, 'runtime/bin')]; + if (spec.artifact.kind === 'native-runtime') destinations.push(path.join(output, 'bin')); + stageWindowsVcRuntime({ + root: output, + sourceDirectory: source, + destinations, + profile: windowsVcRuntimeProfile, + }); + } else + assert.equal(Object.keys(spec.windowsRuntime).length, 0, 'foreign Windows runtime inputs'); + validatePayload(output, spec.artifact.target, { + toolSet: spec.artifact.kind === 'native-tools' ? 'tools' : 'runtime', + }); + assertReleaseNoticesInDirectory(output, notices); + await inspectPlatformBinaryTree(output, { + target: spec.artifact.target, + windowsVcRuntimeProfile: windowsVcRuntimeProfile ?? 'direct', + requireWindowsRuntimeImportLibrary: + spec.artifact.kind === 'native-runtime' && spec.artifact.target === 'windows-x64-msvc', + }); + } finally { + rmSync(temporary, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + assert.equal(process.argv.length, 3, 'usage: payload.mts '); + await packageNativePayload(JSON.parse(readFileSync(process.argv[2], 'utf8'))); +} diff --git a/build_defs/native/carriers/release-family.bzl b/build_defs/native/carriers/release-family.bzl new file mode 100644 index 000000000..12d481e80 --- /dev/null +++ b/build_defs/native/carriers/release-family.bzl @@ -0,0 +1,90 @@ +"""Checksum-only publication roots from authenticated final public archive Files.""" + +load("@oliphaunt_metadata//:metadata.bzl", "NATIVE_CURRENT_ARTIFACTS", "NATIVE_HELPER_ARTIFACTS", "NATIVE_RUNTIME_ARTIFACTS", "PRODUCTS", "WASIX_ARTIFACTS") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") +load("//build_defs/release:supplier.bzl", "shipping_suppliers") +load(":defs.bzl", "native_checksum_manifest") + +_LINUX_X64 = ["@platforms//os:linux", "@platforms//cpu:x86_64"] + +def _canonical_archives_impl(ctx): + selected = {} + for file in ctx.files.archives: + if file.basename not in ctx.attr.expected: + continue + if file.is_directory or file.basename in selected: + fail("release family requires one actual public File per canonical archive") + selected[file.basename] = file + if sorted(selected.keys()) != sorted(ctx.attr.expected): + fail("release family is missing canonical public archive Files") + return [DefaultInfo(files = depset(selected.values()))] + +_canonical_archives = rule( + implementation = _canonical_archives_impl, + attrs = { + "archives": attr.label_list(allow_files = True, mandatory = True), + "expected": attr.string_list(mandatory = True), + }, +) + +def _checksum_test_impl(ctx): + files = ctx.attr.family[DefaultInfo].files.to_list() + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode({ + "product": ctx.attr.product, + "checksum": ctx.attr.checksum, + "archives": ctx.attr.expected, + })) + return bun_test_entrypoint(ctx, runner = ctx.file._runner, + arguments = [spec] + files, + files = [spec] + files, + source_files = [ctx.file._runner, ctx.file._validator]) + +_checksum_test = rule( + implementation = _checksum_test_impl, + test = True, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "family": attr.label(mandatory = True), + "product": attr.string(mandatory = True), + "checksum": attr.string(mandatory = True), + "expected": attr.string_list(mandatory = True), + "_runner": attr.label(default = Label(":release-family.test.mts"), allow_single_file = True), + "_validator": attr.label(default = Label("//tools/release:checksum-manifest.mts"), allow_single_file = True), + }), +) + +def native_release_checksum_family(product, artifact_rows = None, export_name = "checksum_shipping_export"): + """Each host keeps its archive root; this once-only owner exports its checksum.""" + version = PRODUCTS[product]["version"] + if artifact_rows == None: + artifact_rows = NATIVE_RUNTIME_ARTIFACTS + NATIVE_HELPER_ARTIFACTS + WASIX_ARTIFACTS + rows = [row for row in artifact_rows if row["product"] == product and "github-release" in row["surfaces"]] + checksums = [row for row in rows if row["kind"] == "checksums"] + if len(checksums) != 1: + fail("release family requires its unique canonical checksum descriptor") + checksum = checksums[0] + expected = [row["asset"].replace("{version}", version) for row in rows if row["kind"] != "checksums"] + current = NATIVE_CURRENT_ARTIFACTS or {} + archives = [row["file"]["path"] for name in expected + for row in [current.get(product + "/" + version + "/github-release:" + name)] if row] + _canonical_archives(name = "release_family_archives", archives = archives, + expected = expected, target_compatible_with = _LINUX_X64) + native_checksum_manifest(name = "release_assets", product = product, artifact_rows = artifact_rows, + archives = [":release_family_archives"], assemble = True, + output_directory = "release_family/release-assets") + native.filegroup(name = "release_checksums", srcs = [":release_assets"], output_group = "checksums") + shipping_suppliers(name = "release_checksum_suppliers", inputs = []) + shipping_package(name = "release_checksums_shipping", owner = "@oliphaunt_metadata//:product_" + product, + artifacts = [":release_checksums"], ecosystem = "github", + package_name = checksum["asset"].replace("{version}", version), + configuration = checksum.get("target", "") or "portable", role = "github-release-asset", + suppliers = ":release_checksum_suppliers") + _checksum_test(name = "release_checksums_test", family = ":release_assets", product = product, + checksum = checksum["asset"].replace("{version}", version), expected = expected, + args = bun_test_entrypoint_args("release_checksums_test"), size = "small", + target_compatible_with = _LINUX_X64) + shipping_export(name = export_name, packages = [":release_checksums_shipping"], + qualification = [":release_checksums_test"], testonly = True, + target_compatible_with = _LINUX_X64) diff --git a/build_defs/native/carriers/release-family.test.mts b/build_defs/native/carriers/release-family.test.mts new file mode 100644 index 000000000..69168515e --- /dev/null +++ b/build_defs/native/carriers/release-family.test.mts @@ -0,0 +1,32 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import { validateChecksumManifest } from '../../../tools/release/checksum-manifest.mts'; + +/** Qualify the actual assembled family using the publication reader's checksum contract. */ +export function checkReleaseChecksumFamily( + expected: { product: string; checksum: string; archives: string[] }, + files: string[], +) { + assert(expected.archives.length, 'release family requires canonical public archives'); + assert.equal(new Set(expected.archives).size, expected.archives.length); + assert(!expected.archives.includes(expected.checksum), 'checksum cannot include itself'); + assert.deepEqual( + files.map((file) => path.basename(file)).sort(), + [...expected.archives, expected.checksum].sort(), + `${expected.product} release family must contain exactly its canonical public Files`, + ); + const checksum = files.find((file) => path.basename(file) === expected.checksum); + assert(checksum); + validateChecksumManifest( + checksum, + files.filter((file) => file !== checksum), + `${expected.product}/${expected.checksum}`, + ); +} + +if (import.meta.main) { + const [specification, ...files] = process.argv.slice(2); + assert(specification, 'release checksum test requires its declared family specification'); + checkReleaseChecksumFamily(JSON.parse(readFileSync(specification, 'utf8')), files); +} diff --git a/build_defs/native/carriers/release-family.unit.test.mts b/build_defs/native/carriers/release-family.unit.test.mts new file mode 100644 index 000000000..cdbd3b65b --- /dev/null +++ b/build_defs/native/carriers/release-family.unit.test.mts @@ -0,0 +1,79 @@ +import { expect, test } from 'bun:test'; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { assembleNativeReleaseAssets } from './checksums.mts'; +import { checkReleaseChecksumFamily } from './release-family.test.mts'; + +function fixture() { + const root = mkdtempSync(path.join(tmpdir(), 'release-checksum-family-')); + const expected = { + product: 'fixture', + checksum: 'fixture-release-assets.sha256', + archives: ['fixture-linux.tar.gz', 'fixture-macos.zip'], + }; + const inputs = expected.archives.map((name, index) => { + const file = path.join(root, name); + writeFileSync(file, `actual archive bytes ${index}\n`); + return file; + }); + const directory = path.join(root, 'family', 'release-assets'); + const copies = expected.archives.map((name) => path.join(directory, name)); + const checksum = path.join(directory, expected.checksum); + assembleNativeReleaseAssets({ + expected: expected.archives, + files: inputs, + copies, + output: checksum, + }); + return { root, expected, checksum, files: [...copies, checksum] }; +} + +test('qualifies the writer actual complete Files and rejects changed public bytes', () => { + const value = fixture(); + try { + checkReleaseChecksumFamily(value.expected, value.files); + writeFileSync(value.files[0], 'changed archive bytes'); + expect(() => checkReleaseChecksumFamily(value.expected, value.files)).toThrow( + 'does not match its frozen bytes', + ); + } finally { + rmSync(value.root, { recursive: true, force: true }); + } +}); + +test('rejects missing, extra, repeated, and wrongly named final Files', () => { + const value = fixture(); + try { + for (const files of [ + value.files.slice(1), + [...value.files, value.files[0]], + [...value.files, path.join(value.root, 'extra.tar.gz')], + ]) + expect(() => checkReleaseChecksumFamily(value.expected, files)).toThrow( + 'exactly its canonical public Files', + ); + expect(() => + checkReleaseChecksumFamily({ ...value.expected, checksum: 'other.sha256' }, value.files), + ).toThrow('exactly its canonical public Files'); + } finally { + rmSync(value.root, { recursive: true, force: true }); + } +}); + +test('retains the publication reader strict syntax, uniqueness, and complete coverage', () => { + const value = fixture(); + try { + const original = readFileSync(value.checksum, 'utf8'); + for (const content of [ + original.replaceAll(' ./', ' '), + `${original}${original.split('\n')[0]}\n`, + `${original.split('\n')[0]}\n`, + ]) { + writeFileSync(value.checksum, content); + expect(() => checkReleaseChecksumFamily(value.expected, value.files)).toThrow(); + } + } finally { + rmSync(value.root, { recursive: true, force: true }); + } +}); diff --git a/build_defs/native/carriers/tests.bzl b/build_defs/native/carriers/tests.bzl new file mode 100644 index 000000000..65aa992bd --- /dev/null +++ b/build_defs/native/carriers/tests.bzl @@ -0,0 +1,62 @@ +"""Installed carrier consumers using conventional Cargo and declared toolchains.""" + +load("@rules_cc//cc:find_cc_toolchain.bzl", "use_cc_toolchain") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/languages:cargo-toolchain.bzl", "cargo_test_toolchain") + +_RUST_TOOLCHAIN = "@rules_rust//rust:toolchain_type" +_NODE_TOOLCHAIN = "@rules_nodejs//nodejs:toolchain_type" + +def _installed_impl(ctx): + node = ctx.toolchains[_NODE_TOOLCHAIN].nodeinfo.node + if not node: + fail("installed npm tools require the declared Node toolchain") + arguments = [] + for target in ctx.attr.inputs: + files = target[DefaultInfo].files.to_list() + if len(files) != 1: + fail("installed carrier argument must be one declared file: " + str(target.label)) + arguments.append(files[0]) + arguments.append(node) + sources = [ctx.file._runner] + ctx.files._helpers + return bun_test_entrypoint(ctx, ctx.file._runner, arguments, arguments + sources, source_files = sources) + +_native_installed_carrier_test = rule( + implementation = _installed_impl, + test = True, + toolchains = [_NODE_TOOLCHAIN] + BUN_SOURCE_TOOLCHAINS, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "inputs": attr.label_list(mandatory = True, allow_files = True), + "_runner": attr.label(default = "//build_defs/native/carriers:installed.test.mts", allow_single_file = True), + "_helpers": attr.label_list(default = ["//build_defs/native/carriers:tools-consumer.mts", "//build_defs/native:host-runtime-test-helpers.mts", "//:tools/packaging/portable-archive.mts"], allow_files = True), + }), +) + +def native_installed_carrier_test(name, args = [], **kwargs): + _native_installed_carrier_test(name = name, args = bun_test_entrypoint_args(name) + args, **kwargs) + +def _cargo_impl(ctx): + rust = ctx.toolchains[_RUST_TOOLCHAIN] + if not rust.cargo: + fail("installed native consumers require Cargo from the declared Rust toolchain") + cc = cargo_test_toolchain(ctx) + arguments = [ctx.file.packages, ctx.file.archive, rust.cargo, rust.rustc, rust.rust_doc, cc.configuration] + files = [ctx.file.packages, ctx.file.archive, ctx.file._runner, ctx.file._archive_helper, ctx.file._cargo_environment, cc.configuration] + rust.all_files.to_list() + cc.files + return bun_test_entrypoint(ctx, ctx.file._runner, arguments, files, runfiles_argument = True, source_files = [ctx.file._runner, ctx.file._archive_helper, ctx.file._cargo_environment]) + +_native_cargo_consumer_test = rule( + implementation = _cargo_impl, + test = True, + toolchains = [_RUST_TOOLCHAIN] + BUN_SOURCE_TOOLCHAINS + use_cc_toolchain(), + fragments = ["cpp"], + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "packages": attr.label(mandatory = True, allow_single_file = True), + "archive": attr.label(mandatory = True, allow_single_file = True), + "_runner": attr.label(default = "//build_defs/native/carriers:cargo-consumer.test.mts", allow_single_file = True), + "_archive_helper": attr.label(default = "//:tools/packaging/portable-archive.mts", allow_single_file = True), + "_cargo_environment": attr.label(default = "//build_defs/languages:cargo-environment.mts", allow_single_file = True), + }), +) + +def native_cargo_consumer_test(name, args = [], **kwargs): + _native_cargo_consumer_test(name = name, args = bun_test_entrypoint_args(name) + args, **kwargs) diff --git a/build_defs/native/carriers/tools-consumer.mts b/build_defs/native/carriers/tools-consumer.mts new file mode 100644 index 000000000..0f670bdbe --- /dev/null +++ b/build_defs/native/carriers/tools-consumer.mts @@ -0,0 +1,30 @@ +/** Execute the actual installed public facade against the isolated test server. */ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { pathToFileURL } from 'node:url'; + +export const VERIFY_SQL = 'SELECT count(*), sum(id) FROM logical_items'; +export function expectedLogicalValue(fixture: { expected: { rows: number; sum: number } }): string { + return `${fixture.expected.rows}|${fixture.expected.sum}`; +} + +if (import.meta.main) { + const [entry, connection, fixtureFile] = process.argv.slice(2); + assert(entry && connection && fixtureFile); + const tools = await import(pathToFileURL(entry).href); + const query = await tools.psql(connection, { command: 'SELECT 42', args: ['-A', '-t'] }); + assert.equal(query.trim(), '42'); + const fixture = JSON.parse(readFileSync(fixtureFile, 'utf8')); + // The published base runtime excludes the separately packaged pgTAP extension. + // Preserve the shared logical fixture's row/sum oracle using ordinary tables. + await tools.psql(connection, { + script: + "CREATE TABLE logical_items(id integer PRIMARY KEY, value text); INSERT INTO logical_items VALUES (40, 'alpha'), (41, 'beta'), (42, 'gamma')", + }); + const logical = await tools.pgDump(connection, { args: ['--no-owner', '--no-privileges'] }); + assert(logical.includes('COPY public.logical_items')); + await tools.psql(connection, { command: 'DROP TABLE logical_items' }); + await tools.psql(connection, { script: logical }); + const restored = await tools.psql(connection, { command: VERIFY_SQL, args: ['-A', '-t'] }); + assert.equal(restored.trim(), expectedLogicalValue(fixture)); +} diff --git a/build_defs/native/compiler-probe-contract.c b/build_defs/native/compiler-probe-contract.c new file mode 100644 index 000000000..4e0166542 --- /dev/null +++ b/build_defs/native/compiler-probe-contract.c @@ -0,0 +1,32 @@ +#include +#include + +#define OLIPHAUNT_STRINGIFY_INNER(value) #value +#define OLIPHAUNT_STRINGIFY(value) OLIPHAUNT_STRINGIFY_INNER(value) +#include OLIPHAUNT_STRINGIFY(OLIPHAUNT_COMPILER_PROBE_HEADER) + +#if !defined(HAVE_STDIO_H) || !defined(HAVE_STDINT_H) || !defined(HAVE_STDLIB_H) +#error "native compiler probe failed mandatory standard headers" +#endif +#if defined(HAVE_OLIPHAUNT_NATIVE_PROBE_MISSING_HEADER_H) || defined(HAVE_OLIPHAUNT_MISSING_TYPE) +#error "native compiler probe falsely accepts a missing header or type" +#endif + +/* Compile-time expressions work with MSVC and cross compilers too. No target + * execution or copied host LP64 assumption establishes these ABI facts. */ +#define SAME_SIZE(macro, type) typedef char verify_##macro[(macro) == sizeof(type) ? 1 : -1] +#define SAME_ALIGNMENT(macro, type) \ + struct align_##macro { char lead; type value; }; \ + typedef char verify_##macro[(macro) == offsetof(struct align_##macro, value) ? 1 : -1] + +SAME_SIZE(SIZEOF_LONG, long); +SAME_SIZE(SIZEOF_LONG_LONG, long long); +SAME_SIZE(SIZEOF_SIZE_T, size_t); +SAME_SIZE(SIZEOF_VOID_P, void *); +SAME_ALIGNMENT(ALIGNOF_DOUBLE, double); +SAME_ALIGNMENT(ALIGNOF_INT, int); +SAME_ALIGNMENT(ALIGNOF_INT64_T, int64_t); +SAME_ALIGNMENT(ALIGNOF_LONG, long); +SAME_ALIGNMENT(ALIGNOF_SHORT, short); + +int main(void) { return 0; } diff --git a/build_defs/native/compiler_probes.bzl b/build_defs/native/compiler_probes.bzl new file mode 100644 index 000000000..192b1ec5a --- /dev/null +++ b/build_defs/native/compiler_probes.bzl @@ -0,0 +1,84 @@ +"""Compiler-derived native facts, qualified separately before PG config cutover. + +The maintained checker compiles/links probes with the actual target CC toolchain; +it never executes a target program to establish type size or alignment. +""" + +load("@bazel_skylib//rules:write_file.bzl", "write_file") +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") +load("@rules_cc_autoconf//autoconf:autoconf.bzl", "autoconf") +load("@rules_cc_autoconf//autoconf:autoconf_hdr.bzl", "autoconf_hdr") +load("@rules_cc_autoconf//autoconf:checks.bzl", "checks", "macros") +load(":postgres_sources.bzl", "POSTGRES_PORT_REPLACEMENT_SOURCES") + +def native_compiler_probe_targets(name): + """Expose a real positive link, negative probes and target ABI facts.""" + # This is a platform preflight, not a replacement pg_config.h. Backend + # features, source roles and platform libraries need separate PG evidence. + probe_checks = macros.AC_CHECK_HEADERS([ + "stdio.h", "stdint.h", "stdlib.h", "strings.h", "string.h", + "unistd.h", "sys/types.h", "sys/epoll.h", "sys/event.h", + "oliphaunt-native-probe-missing-header.h", + ]) + macros.AC_CHECK_FUNCS([ + macro[len("HAVE_"):].lower() + for macro in POSTGRES_PORT_REPLACEMENT_SOURCES.keys() + ]) + [ + checks.AC_CHECK_SIZEOF("long", define = "SIZEOF_LONG"), + checks.AC_CHECK_SIZEOF("long long", define = "SIZEOF_LONG_LONG"), + checks.AC_CHECK_SIZEOF("size_t", define = "SIZEOF_SIZE_T"), + checks.AC_CHECK_SIZEOF("void *", define = "SIZEOF_VOID_P"), + checks.AC_CHECK_ALIGNOF("double", define = "ALIGNOF_DOUBLE"), + checks.AC_CHECK_ALIGNOF("int", define = "ALIGNOF_INT"), + checks.AC_CHECK_ALIGNOF("int64_t", define = "ALIGNOF_INT64_T", includes = ["#include "]), + checks.AC_CHECK_ALIGNOF("long", define = "ALIGNOF_LONG"), + checks.AC_CHECK_ALIGNOF("short", define = "ALIGNOF_SHORT"), + checks.AC_CHECK_TYPE("oliphaunt_native_probe_missing_type", define = "HAVE_OLIPHAUNT_MISSING_TYPE"), + ] + probe_checks = [checks.AC_DEFINE("_GNU_SOURCE", "1")] + [ + json.encode(json.decode(probe) | {"compile_defines": ["_GNU_SOURCE"]}) + for probe in probe_checks + ] + autoconf( + name = name + "_facts", + checks = probe_checks, + ) + write_file( + name = name + "_template", + out = name + ".h.in", + content = ["#undef " + json.decode(probe)["define"] for probe in probe_checks], + ) + autoconf_hdr( + name = name + "_header", + out = name + ".h", + template = ":" + name + "_template", + deps = [":" + name + "_facts"], + defaults = False, + ) + cc_library( + name = name + "_headers", + hdrs = [":" + name + "_header"], + includes = ["."], + ) + # A broken compiler/sysroot may return the same status as an absent optional + # feature. Require one genuine standard-library compile/link per target + # configuration, rather than repeating a sanity compile inside every probe. + cc_binary(name = name + "_sanity", srcs = ["probe-sanity.c"]) + cc_library( + name = name + "_contract", + srcs = ["compiler-probe-contract.c"], + deps = [":" + name + "_headers"], + local_defines = ["OLIPHAUNT_COMPILER_PROBE_HEADER=" + name + ".h"], + ) + native.filegroup( + name = name + "_configuration", + srcs = [":" + name + "_header", ":" + name + "_sanity", ":" + name + "_contract"], + ) + cc_test( + name = name + "_test", + deps = [":" + name + "_contract"], + data = [":" + name + "_sanity"], + # The contract is a compile-only assertion plus trivial main, not a + # shared-library ABI consumer. Avoid constructing an unused probe DSO. + linkstatic = True, + size = "small", + ) diff --git a/build_defs/native/config.bzl b/build_defs/native/config.bzl new file mode 100644 index 000000000..01b04c425 --- /dev/null +++ b/build_defs/native/config.bzl @@ -0,0 +1,76 @@ +"""Declared PostgreSQL configuration and filesystem layout headers.""" + +_DIRECTORIES = { + "PGBINDIR": "bin", + "PGSHAREDIR": "share/postgresql", + "SYSCONFDIR": "etc", + "INCLUDEDIR": "include", + "PKGINCLUDEDIR": "include/postgresql", + "INCLUDEDIRSERVER": "include/postgresql/server", + "LIBDIR": "lib", + "PKGLIBDIR": "lib/postgresql", + "LOCALEDIR": "share/locale", + "DOCDIR": "share/doc", + "HTMLDIR": "share/doc/html", + "MANDIR": "share/man", +} + +def _layout(ctx, output_directory): + os_header = ctx.actions.declare_file(output_directory + "/pg_config_os.h") + ctx.actions.symlink(output = os_header, target_file = ctx.file.os_header) + paths = ctx.actions.declare_file(output_directory + "/pg_config_paths.h") + prefix = ctx.attr.prefix.rstrip("/") + ctx.actions.write(paths, "".join(['#define ' + key + ' "' + prefix + '/' + value + '"\n' for key, value in _DIRECTORIES.items()])) + return [os_header, paths] + +def postgres_configuration_values(version, values, profile): + """Combine explicit product policy and conventional PostgreSQL version fields.""" + parts = version.split(".") + major = int(parts[0]) + minor = int(parts[1]) + values = dict(values) + values.update({ + "PACKAGE_STRING": '"PostgreSQL ' + version + '"', + "PACKAGE_VERSION": '"' + version + '"', + "PG_MAJORVERSION": '"' + parts[0] + '"', + "PG_MAJORVERSION_NUM": str(major), + "PG_MINORVERSION_NUM": str(minor), + "PG_VERSION": '"' + version + '"', + "PG_VERSION_NUM": str(major * 10000 + minor), + "PG_VERSION_STR": '"PostgreSQL ' + version + ' ' + profile + ', ' + str(int(values["SIZEOF_VOID_P"]) * 8) + '-bit"', + }) + return values + +def _pg_config_impl(ctx): + values = postgres_configuration_values(ctx.attr.version, ctx.attr.values, ctx.attr.profile) + config = ctx.actions.declare_file("src/include/pg_config.h") + ctx.actions.expand_template( + template = ctx.file.template, + output = config, + substitutions = {"#undef " + key + "\n": "#define " + key + " " + value + "\n" for key, value in values.items()}, + ) + return [DefaultInfo(files = depset([config] + _layout(ctx, "src/include")))] + +pg_config = rule( + implementation = _pg_config_impl, + attrs = { + "template": attr.label(allow_single_file = True, mandatory = True), + "os_header": attr.label(allow_single_file = True, mandatory = True), + "version": attr.string(mandatory = True), + "values": attr.string_dict(mandatory = True), + "profile": attr.string(mandatory = True), + "prefix": attr.string(default = "/oliphaunt/runtime"), + }, +) + +def _pg_config_layout_impl(ctx): + return [DefaultInfo(files = depset(_layout(ctx, ctx.attr.output_directory)))] + +pg_config_layout = rule( + implementation = _pg_config_layout_impl, + attrs = { + "os_header": attr.label(allow_single_file = True, mandatory = True), + "output_directory": attr.string(default = "host_config/src/include"), + "prefix": attr.string(default = "/oliphaunt/runtime"), + }, +) diff --git a/build_defs/native/crypto_smoke.c b/build_defs/native/crypto_smoke.c new file mode 100644 index 000000000..21fa8ef9a --- /dev/null +++ b/build_defs/native/crypto_smoke.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include +#include + +static int digest(const char *name, const char *provider, const unsigned char *expected, size_t expected_size) +{ + unsigned char output[EVP_MAX_MD_SIZE]; + unsigned int size = 0; + EVP_MD *algorithm = EVP_MD_fetch(NULL, name, provider); + int success = algorithm && EVP_Digest("abc", 3, output, &size, algorithm, NULL) + && size == expected_size && memcmp(output, expected, size) == 0; + EVP_MD_free(algorithm); + return success; +} + +int main(void) +{ + static const unsigned char sha256[] = { + 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, + 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, + 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, + 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad, + }; + static const unsigned char md4[] = { + 0xa4, 0x48, 0x01, 0x7a, 0xaf, 0x21, 0xd8, 0x52, + 0x5f, 0xc1, 0x0a, 0xe8, 0x7a, 0xa6, 0x72, 0x9d, + }; + if (OpenSSL_version_num() != OPENSSL_VERSION_NUMBER) { + fputs("OpenSSL headers and compiled source disagree\n", stderr); + return 1; + } + OSSL_PROVIDER *default_provider = OSSL_PROVIDER_load(NULL, "default"); + OSSL_PROVIDER *legacy_provider = OSSL_PROVIDER_load(NULL, "legacy"); + int success = default_provider && legacy_provider + && digest("SHA256", "provider=default", sha256, sizeof(sha256)) + && digest("MD4", "provider=legacy", md4, sizeof(md4)); + OSSL_PROVIDER_unload(legacy_provider); + OSSL_PROVIDER_unload(default_provider); + if (!success) { + fputs("OpenSSL builtin default/legacy provider digest failed\n", stderr); + return 1; + } + puts(OpenSSL_version(OPENSSL_VERSION)); + return 0; +} diff --git a/build_defs/native/frontend_sources.bzl b/build_defs/native/frontend_sources.bzl new file mode 100644 index 000000000..2291b0da4 --- /dev/null +++ b/build_defs/native/frontend_sources.bzl @@ -0,0 +1,53 @@ +"""PostgreSQL 18.4 source roles for the three published native tools. + +Inventories follow src/bin/{pg_dump,pg_basebackup,psql}/meson.build. Other +upstream frontends are intentionally absent from the product construction roots. +""" + +POSTGRES_DUMP_COMMON_SOURCES = [ + "src/bin/pg_dump/compress_gzip.c", + "src/bin/pg_dump/compress_io.c", + "src/bin/pg_dump/compress_lz4.c", + "src/bin/pg_dump/compress_none.c", + "src/bin/pg_dump/compress_zstd.c", + "src/bin/pg_dump/connectdb.c", + "src/bin/pg_dump/dumputils.c", + "src/bin/pg_dump/filter.c", + "src/bin/pg_dump/parallel.c", + "src/bin/pg_dump/pg_backup_archiver.c", + "src/bin/pg_dump/pg_backup_custom.c", + "src/bin/pg_dump/pg_backup_db.c", + "src/bin/pg_dump/pg_backup_directory.c", + "src/bin/pg_dump/pg_backup_null.c", + "src/bin/pg_dump/pg_backup_tar.c", + "src/bin/pg_dump/pg_backup_utils.c", +] + +POSTGRES_DUMP_SOURCES = [ + "src/bin/pg_dump/common.c", + "src/bin/pg_dump/pg_dump.c", + "src/bin/pg_dump/pg_dump_sort.c", +] + +POSTGRES_BASEBACKUP_COMMON_SOURCES = [ + "src/bin/pg_basebackup/astreamer_inject.c", + "src/bin/pg_basebackup/receivelog.c", + "src/bin/pg_basebackup/streamutil.c", + "src/bin/pg_basebackup/walmethods.c", +] + +POSTGRES_PSQL_SOURCES = [ + "src/bin/psql/command.c", + "src/bin/psql/common.c", + "src/bin/psql/copy.c", + "src/bin/psql/crosstabview.c", + "src/bin/psql/describe.c", + "src/bin/psql/help.c", + "src/bin/psql/input.c", + "src/bin/psql/large_obj.c", + "src/bin/psql/mainloop.c", + "src/bin/psql/prompt.c", + "src/bin/psql/startup.c", + "src/bin/psql/stringutils.c", + "src/bin/psql/variables.c", +] diff --git a/build_defs/native/generators.bzl b/build_defs/native/generators.bzl new file mode 100644 index 000000000..24cceb3e7 --- /dev/null +++ b/build_defs/native/generators.bzl @@ -0,0 +1,118 @@ +"""Bounded PostgreSQL source generators using declared execution toolchains.""" + +PERL_CAPTURE_STDOUT = "open(STDOUT, q(>), shift @ARGV) or die $!; system {$ARGV[0]} @ARGV; die qq(Perl generator failed: status $?) if $? != 0;" + +_PERL = "@rules_perl//perl:exec_toolchain_type" +_BISON = "@rules_bison//bison:toolchain_type" +_FLEX = "@rules_flex//flex:toolchain_type" +_M4 = "@rules_m4//m4:toolchain_type" + +def _expand(ctx, value): + targets = ctx.attr.srcs + [ctx.attr.script] + for target in targets: + files = target[DefaultInfo].files.to_list() + if len(files) == 1: + value = value.replace("$(dirname " + target.label.name + ")", files[0].dirname) + rule_dir = ctx.bin_dir.path + "/" + ctx.label.workspace_root + if ctx.label.package: + rule_dir += "/" + ctx.label.package + value = value.replace("$(RULEDIR)", rule_dir).replace("$@", ctx.outputs.outs[0].path) + return ctx.expand_location(value, targets = targets) + +def _perl_generator_impl(ctx): + perl = ctx.toolchains[_PERL].perl_runtime + arguments = perl.perlopt + [_expand(ctx, value) for value in ctx.attr.options] + arguments += [ctx.file.script.path] + [_expand(ctx, value) for value in ctx.attr.arguments] + if ctx.attr.capture_stdout: + # Wait for the generator: Windows exec exits the launcher before its + # child completes, so Bazel would terminate the child and capture no output. + arguments = perl.perlopt + [ + "-e", + PERL_CAPTURE_STDOUT, + ctx.outputs.outs[0].path, + perl.interpreter.path, + ] + arguments + ctx.actions.run( + executable = perl.interpreter, + arguments = arguments, + inputs = depset(ctx.files.srcs + [ctx.file.script], transitive = [perl.runtime]), + outputs = ctx.outputs.outs, + env = {"PERL5LIB": "", "PERL5OPT": ""}, + mnemonic = "PostgresPerl", + progress_message = "Generate PostgreSQL sources %{label}", + ) + return [DefaultInfo(files = depset(ctx.outputs.outs))] + +postgres_perl = rule( + implementation = _perl_generator_impl, + attrs = { + "script": attr.label(mandatory = True, allow_single_file = True), + "srcs": attr.label_list(allow_files = True), + "outs": attr.output_list(mandatory = True), + "arguments": attr.string_list(), + "options": attr.string_list(), + "capture_stdout": attr.bool(), + }, + toolchains = [_PERL], +) + +def _parser_action(ctx, scanner): + if scanner: + selected = ctx.toolchains[_FLEX] + toolchain = selected.flex_toolchain + tool = toolchain.flex_tool + environment = dict(toolchain.flex_env) + else: + selected = ctx.toolchains[_BISON] + toolchain = selected.bison_toolchain + tool = toolchain.bison_tool + environment = dict(toolchain.bison_env) + inputs = [toolchain.all_files] + tools = [tool] + # The canonical Windows ports call their linked M4 implementation, which + # disables shell execution. Other maintained providers use declared M4. + if not getattr(selected, "embedded_m4", False): + m4 = ctx.toolchains[_M4].m4_toolchain + environment.update({ + "M4": m4.m4_tool.executable.path, + "M4_SYSCMD_SHELL": ctx.executable._deny_shell.path, + }) + inputs.append(m4.all_files) + tools.extend([m4.m4_tool, ctx.executable._deny_shell]) + ctx.actions.run( + executable = tool, + arguments = ctx.attr.options + ["-o", ctx.outputs.outs[0].path, ctx.file.src.path], + inputs = depset([ctx.file.src], transitive = inputs), + tools = tools, + outputs = ctx.outputs.outs, + env = environment, + mnemonic = "PostgresFlex" if scanner else "PostgresBison", + progress_message = "Generate PostgreSQL parser %{label}", + ) + return [DefaultInfo(files = depset(ctx.outputs.outs))] + +def _bison_impl(ctx): + return _parser_action(ctx, False) + +def _flex_impl(ctx): + return _parser_action(ctx, True) + +def _parser_attrs(deny_shell): + return { + "src": attr.label(mandatory = True, allow_single_file = True), + "outs": attr.output_list(mandatory = True), + "options": attr.string_list(), + "_deny_shell": attr.label(default = deny_shell, executable = True, cfg = "exec"), + } + +postgres_bison = rule( + implementation = _bison_impl, + attrs = _parser_attrs("@rules_bison//bison/internal:m4_deny_shell"), + toolchains = [_BISON, _M4], +) + +postgres_flex = rule( + implementation = _flex_impl, + attrs = _parser_attrs("@rules_flex//flex/internal:m4_deny_shell"), + toolchains = [_FLEX, _M4], +) diff --git a/build_defs/native/host-config-contract.c b/build_defs/native/host-config-contract.c new file mode 100644 index 000000000..0a52d661c --- /dev/null +++ b/build_defs/native/host-config-contract.c @@ -0,0 +1,45 @@ +/* Reject absent/incorrect target ABI probes before admitting PostgreSQL. */ +#include +#include +#include +#include "pg_config.h" + +#if !defined(SIZEOF_LONG) || !defined(SIZEOF_LONG_LONG) || \ + !defined(SIZEOF_OFF_T) || !defined(SIZEOF_SIZE_T) || \ + !defined(SIZEOF_VOID_P) || !defined(ALIGNOF_DOUBLE) || \ + !defined(ALIGNOF_INT) || !defined(ALIGNOF_INT64_T) || \ + !defined(ALIGNOF_LONG) || !defined(ALIGNOF_SHORT) +#error "Host ABI facts are missing: inspect the native compiler probe diagnostics" +#else + +struct oliphaunt_double_alignment { char byte; double value; }; +struct oliphaunt_int_alignment { char byte; int value; }; +struct oliphaunt_int64_t_alignment { char byte; int64_t value; }; +struct oliphaunt_long_alignment { char byte; long value; }; +struct oliphaunt_short_alignment { char byte; short value; }; +#define ALIGNOF(type) offsetof(struct oliphaunt_##type##_alignment, value) +#define ASSERT(name, condition) typedef char name[(condition) ? 1 : -1] +ASSERT(long_size, SIZEOF_LONG == sizeof(long)); +ASSERT(long_long_size, SIZEOF_LONG_LONG == sizeof(long long)); +ASSERT(off_t_size, SIZEOF_OFF_T == sizeof(off_t)); +ASSERT(size_t_size, SIZEOF_SIZE_T == sizeof(size_t)); +ASSERT(pointer_size, SIZEOF_VOID_P == sizeof(void *)); +ASSERT(double_align, ALIGNOF_DOUBLE == ALIGNOF(double)); +ASSERT(int_align, ALIGNOF_INT == ALIGNOF(int)); +ASSERT(int64_align, ALIGNOF_INT64_T == ALIGNOF(int64_t)); +ASSERT(long_align, ALIGNOF_LONG == ALIGNOF(long)); +ASSERT(short_align, ALIGNOF_SHORT == ALIGNOF(short)); +ASSERT(pg_alignment, MAXIMUM_ALIGNOF >= ALIGNOF(int64_t)); +ASSERT(profile_pointer_size, SIZEOF_VOID_P == 8); +/* PG uses this fact in StaticAssertExpr for memory-context names. */ +#ifdef HAVE__BUILTIN_CONSTANT_P +ASSERT(constant_memory_context_name, __builtin_constant_p("memory context")); +#endif +#ifdef _WIN32 +ASSERT(windows_llp64, SIZEOF_LONG == 4 && SIZEOF_OFF_T == 4); +/* Match PG18 Windows policy and the backend executable /STACK reserve. */ +ASSERT(windows_stack_rlimit, WIN32_STACK_RLIMIT == 4194304); +#else +ASSERT(apple_lp64, SIZEOF_LONG == 8 && SIZEOF_OFF_T == 8); +#endif +#endif diff --git a/build_defs/native/host-config-policy.test.mts b/build_defs/native/host-config-policy.test.mts new file mode 100644 index 000000000..511a770de --- /dev/null +++ b/build_defs/native/host-config-policy.test.mts @@ -0,0 +1,112 @@ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; + +// Preserve the numeric feature switches consumed by the maintained checker. +const source = readFileSync(new URL('./host_config.bzl', import.meta.url), 'utf8'); +function featureSwitchValue(policy: string): unknown { + const value = /checks\.AC_DEFINE\(d,\s*([^\n)]+)\)\s+for d in definitions\s*\+/u.exec( + policy, + )?.[1]; + if (!value) throw new Error('host feature-switch AC_DEFINE declaration is missing'); + return JSON.parse(value); +} +assert.equal(featureSwitchValue(source), 1); +assert.notEqual( + featureSwitchValue(source.replace(/checks\.AC_DEFINE\(d,\s*1\)/u, 'checks.AC_DEFINE(d, "1")')), + 1, +); + +const [checker] = process.argv.slice(2); +assert(checker, 'Expected the declared maintained checker executable'); +const root = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'autoconf-diagnostics-')); +try { + const compiler = path.join(root, 'controlled compiler.mts'); + const diagnostic = 'controlled compiler diagnostic'; + writeFileSync( + compiler, + `import {appendFileSync,existsSync,readFileSync} from 'node:fs'; +const [mode,calls,...args]=Bun.argv.slice(2); +const previous=existsSync(calls)?readFileSync(calls,'utf8').trim().split('\\n').filter(Boolean):[]; +appendFileSync(calls,JSON.stringify(readFileSync(args[args.indexOf('-c')+1],'utf8'))+'\\n'); +console.log('controlled compiler stdout'); +console.error('${diagnostic}'); +process.exit(mode==='pass'||(mode==='late-pass'&&previous.length===4)?0:1); +`, + ); + const template = + '#include \n{$EILSEQ}\ntypedef char result[({lhs} < {rhs}) ? 1 : -1];\n'; + for (const [name, type, mode, status, success, invocations, visible] of [ + ['positive', 'compile', 'pass', 0, true, 1, false], + ['optional-negative', 'compile', 'fail', 0, false, 1, false], + ['optional-sizeof', 'sizeof', 'fail', 0, false, 4, false], + ['fatal', 'compute_int', 'fail', 1, undefined, 5, true], + ['fatal-retry-passes', 'compute_int', 'late-pass', 1, undefined, 5, true], + ] as const) { + const directory = path.join(root, name); + mkdirSync(directory); + const calls = path.join(directory, 'calls.jsonl'); + const configuration = path.join(directory, 'config.json'); + const check = path.join(directory, 'check.json'); + const resultFile = path.join(directory, 'result.json'); + const flags = ['--no-env-file', compiler, mode, calls]; + writeFileSync( + configuration, + JSON.stringify({ + c_compiler: process.execPath, + cpp_compiler: process.execPath, + c_flags: flags, + cpp_flags: flags, + c_link_flags: [], + cpp_link_flags: [], + linker: process.execPath, + compiler_type: 'clang', + }), + ); + writeFileSync( + check, + JSON.stringify({ + name: 'controlled_probe', + type, + code: type === 'compile' ? 'int main(void) { return 0; }' : template, + }), + ); + const result = spawnSync( + path.resolve(checker), + ['--config', configuration, '--check', check, '--results', resultFile], + { + encoding: 'utf8', + maxBuffer: 1024 * 1024, + env: { ...process.env, RULES_CC_AUTOCONF_DEBUG: undefined }, + }, + ); + assert.equal(result.status, status, `${name}: ${result.stderr}`); + assert.equal(result.stdout, ''); + assert.equal(result.stderr.split(diagnostic).length - 1, visible ? 1 : 0, name); + const probes = readFileSync(calls, 'utf8') + .trim() + .split('\n') + .map((line) => JSON.parse(line)); + assert.equal(probes.length, invocations, name); + if (visible) { + assert.equal( + probes[4], + probes[2], + 'the diagnostic must replay the exact previously failed comparison', + ); + assert.match(result.stderr, /EILSEQ.*can't be evaluated/u); + assert.equal( + existsSync(resultFile), + false, + 'diagnostic replay must never admit the failed check', + ); + } else { + assert.equal(result.stderr, ''); + assert.equal(JSON.parse(readFileSync(resultFile, 'utf8')).success, success); + } + } +} finally { + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/native/host-runtime-sql.test.mts b/build_defs/native/host-runtime-sql.test.mts new file mode 100644 index 000000000..aa2dc66d2 --- /dev/null +++ b/build_defs/native/host-runtime-sql.test.mts @@ -0,0 +1,161 @@ +import assert from 'node:assert/strict'; +import { + chmodSync, + copyFileSync, + mkdirSync, + mkdtempSync, + readdirSync, + renameSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join, resolve } from 'node:path'; +import { + assertMissingHostRuntime, + extractNativePayload, + hostRuntimeEnvironment, + runHostBinary, +} from './host-runtime-test-helpers.mts'; + +assert.equal( + process.argv.length, + 6, + 'expected runtime payload, full C consumer, archive fixture and ICU profile consumer', +); +const [payload, sourceSmoke, sourceFixture, sourceProfile] = process.argv + .slice(2) + .map((file) => resolve(file)); +const root = mkdtempSync(join(process.env.TEST_TMPDIR ?? tmpdir(), 'host-runtime-')); +const runtime = join(root, 'runtime'); +const consumer = join(root, 'consumer'); +const bin = join(consumer, 'bin'); +const windows = process.platform === 'win32'; +const suffix = windows ? '.exe' : ''; +const libraryName = windows + ? 'oliphaunt.dll' + : process.platform === 'darwin' + ? 'liboliphaunt.dylib' + : 'liboliphaunt.so'; +const library = join(runtime, windows ? 'bin' : 'lib', libraryName); +const env = hostRuntimeEnvironment(runtime, root); +env.OLIPHAUNT_STREAM_QUEUE_MAX_BYTES = '4096'; +const run = (binary: string, args: string[], overrides: NodeJS.ProcessEnv = {}) => + runHostBinary(binary, args, { ...env, ...overrides }, consumer); + +function descriptor(database: string): void { + writeFileSync( + join(database, '.oliphaunt.json'), + JSON.stringify({ + schema: 'oliphaunt-database-root-v1', + engineFamily: 'native', + pgdata: 'pgdata', + postgresMajor: 18, + physicalFormat: 'native-pg18-v1', + }) + '\n', + ); +} + +try { + await extractNativePayload(payload!, runtime); + mkdirSync(bin, { recursive: true }); + const smoke = join(bin, 'runtime_smoke' + suffix); + const profile = join(bin, 'profile_smoke' + suffix); + for (const [source, destination] of [ + [sourceSmoke!, smoke], + [sourceProfile!, profile], + ]) { + copyFileSync(source, destination); + if (!windows) chmodSync(destination, 0o755); + } + const fixture = join(consumer, 'physical-archive-native-v1.properties'); + copyFileSync(sourceFixture!, fixture); + // The full C suite also reads this shared fixture relative to its cwd. + const sharedFixture = 'src/test-fixtures/storage/physical-backup-wal-range-v1.properties'; + mkdirSync(dirname(join(consumer, sharedFixture)), { recursive: true }); + copyFileSync(resolve(sharedFixture), join(consumer, sharedFixture)); + + const baseline = Bun.spawnSync([profile], { env, cwd: consumer, stdout: 'pipe', stderr: 'pipe' }); + assert.equal( + baseline.exitCode, + 2, + `profile consumer did not load before candidate removal: ${baseline.stderr.toString()}`, + ); + renameSync(library, library + '.disabled'); + try { + const missing = Bun.spawnSync([profile], { + env, + cwd: consumer, + stdout: 'pipe', + stderr: 'pipe', + }); + assertMissingHostRuntime(missing, libraryName); + } finally { + renameSync(library + '.disabled', library); + } + + const initdb = join(runtime, 'bin', 'initdb' + suffix); + const database = join(root, 'database'); + mkdirSync(database); + run( + initdb, + [ + '-D', + join(database, 'pgdata'), + '-U', + 'postgres', + '--auth=trust', + '--no-sync', + '--locale-provider=libc', + '--locale=C', + '--encoding=UTF8', + ], + { + OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY: '1', + OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY: '1', + }, + ); + descriptor(database); + for (let attempt = 0; attempt < 2; attempt++) { + // Windows reopens the same database with mixed separators on the second pass. + const pgdata = attempt === 0 ? join(database, 'pgdata') : `${database}/pgdata`; + run(smoke, [pgdata, runtime, fixture]); + } + + assert( + readdirSync(join(runtime, 'share', 'icu')).some((name) => /^icudt\d+l\.dat$/u.test(name)), + 'runtime payload must retain the managed raw ICU data contract', + ); + const icuDatabase = join(root, 'icu-database'); + mkdirSync(icuDatabase); + run( + initdb, + [ + '-D', + join(icuDatabase, 'pgdata'), + '-U', + 'postgres', + '--auth=trust', + '--no-sync', + '--locale-provider=icu', + '--icu-locale=en-US', + '--encoding=UTF8', + ], + { + OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY: '1', + ICU_DATA: windows ? '/ambient/unverified-icu' : env.ICU_DATA, + }, + ); + descriptor(icuDatabase); + const sql = + "WITH ordered AS (SELECT item FROM (VALUES ('z'), ('a'), (chr(228))) AS input(item) ORDER BY item) SELECT CASE WHEN datlocprovider = 'i' AND datlocale = 'en-US' AND (SELECT string_agg(item, ',') FROM ordered) = 'a,' || chr(228) || ',z' THEN 'BAZEL_ICU_OK' ELSE 'BAZEL_ICU_MISMATCH' END FROM pg_database WHERE datname = current_database()"; + for (let attempt = 0; attempt < 2; attempt++) + run(profile, [join(icuDatabase, 'pgdata'), runtime, sql, 'BAZEL_ICU_OK'], { + ICU_DATA: '/ambient/unverified-icu', + }); + console.log( + 'Relocated candidate loader boundary, complete C runtime persistence and ICU profile reopen: PASS', + ); +} finally { + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/native/host-runtime-test-helpers.mts b/build_defs/native/host-runtime-test-helpers.mts new file mode 100644 index 000000000..bede9092a --- /dev/null +++ b/build_defs/native/host-runtime-test-helpers.mts @@ -0,0 +1,120 @@ +import assert from 'node:assert/strict'; +import { + chmodSync, + createReadStream, + mkdirSync, + mkdtempSync, + renameSync, + rmSync, + statSync, +} from 'node:fs'; +import { dirname, join, posix, win32 } from 'node:path'; +import { + DEFAULT_PORTABLE_ARCHIVE_LIMITS, + readPortableTarStream, +} from '../../tools/packaging/portable-archive.mts'; + +export async function extractNativePayload(archive: string, destination: string): Promise { + const file = statSync(archive); + assert( + file.isFile() && file.size > 0 && file.size <= DEFAULT_PORTABLE_ARCHIVE_LIMITS.maxArchiveBytes, + 'expected a bounded regular native payload archive', + ); + mkdirSync(dirname(destination), { recursive: true }); + const staging = mkdtempSync(join(dirname(destination), '.native-payload-')); + const input = createReadStream(archive); + try { + // Payloads are already plain tar. Keep the existing bounded reader without + // recompressing or retaining an additional copy of the runtime in memory. + const entries = await readPortableTarStream(input, archive, {}, { root: staging }); + for (const entry of [...entries.values()].reverse()) + if (entry.isDirectory) chmodSync(join(staging, entry.name), entry.mode); + chmodSync(staging, 0o755); + rmSync(destination, { recursive: true, force: true }); + renameSync(staging, destination); + } finally { + input.destroy(); + rmSync(staging, { recursive: true, force: true }); + } +} + +export function hostRuntimeEnvironment( + runtime: string, + root: string, + platform: NodeJS.Platform = process.platform, + source: NodeJS.ProcessEnv = process.env, +): NodeJS.ProcessEnv { + assert( + ['linux', 'darwin', 'win32'].includes(platform), + `unsupported native smoke host ${platform}`, + ); + const env = { ...source }; + for (const key of Object.keys(env)) + if ( + /^(?:LD_|DYLD_|PG|OLIPHAUNT_|LIBOLIPHAUNT_)/iu.test(key) || + /^(?:PATH|INCLUDE|LIB|LIBPATH|RUNFILES_DIR|RUNFILES_MANIFEST_FILE|TEST_SRCDIR)$/iu.test(key) + ) + delete env[key]; + const paths = platform === 'win32' ? win32 : posix; + if (platform === 'win32') { + const systemRoot = Object.entries(source).find( + ([key]) => key.toLowerCase() === 'systemroot', + )?.[1]; + assert(systemRoot && win32.isAbsolute(systemRoot), 'Windows smoke requires the OS SystemRoot'); + env.PATH = [win32.join(runtime, 'bin'), win32.join(systemRoot, 'System32'), systemRoot].join( + ';', + ); + } else { + env.PATH = '/usr/bin:/bin:/usr/sbin:/sbin'; + env[platform === 'darwin' ? 'DYLD_LIBRARY_PATH' : 'LD_LIBRARY_PATH'] = posix.join( + runtime, + 'lib', + ); + if (platform === 'darwin') env.DYLD_FALLBACK_LIBRARY_PATH = ''; + } + env.ICU_DATA = paths.join(runtime, 'share', 'icu'); + env.PGSERVICEFILE = paths.join(root, 'no-service'); + env.PGPASSFILE = paths.join(root, 'no-password'); + return env; +} + +export function runHostBinary( + binary: string, + args: string[], + env: NodeJS.ProcessEnv, + cwd: string, + output: 'pipe' | 'inherit' = 'pipe', +): string { + const result = Bun.spawnSync([binary, ...args], { env, cwd, stdout: output, stderr: output }); + assert.equal( + result.exitCode, + 0, + `${binary}: ${result.stderr?.toString() ?? ''}\n${result.stdout?.toString() ?? ''}`, + ); + return result.stdout?.toString() ?? ''; +} + +export function assertMissingHostRuntime( + result: { exitCode: number; stderr: Uint8Array }, + library: string, + platform: NodeJS.Platform = process.platform, +): void { + const diagnostic = Buffer.from(result.stderr).toString(); + if (platform === 'win32') { + // Bun exposes the low byte of Windows STATUS_DLL_NOT_FOUND (0xc0000135). + assert.equal(result.exitCode, 0x35, 'consumer resolved the removed candidate DLL'); + } else if (platform === 'darwin') { + assert.notEqual(result.exitCode, 0, 'consumer resolved the removed candidate dylib'); + assert( + diagnostic.includes(library) && + /Library not loaded|library not found|image not found/iu.test(diagnostic), + `expected the dyld missing-candidate diagnostic: ${diagnostic}`, + ); + } else { + assert.equal(result.exitCode, 127, 'consumer resolved the removed candidate shared library'); + assert( + diagnostic.includes(library), + `expected the missing-candidate loader diagnostic: ${diagnostic}`, + ); + } +} diff --git a/build_defs/native/host-runtime-test-helpers.test.mts b/build_defs/native/host-runtime-test-helpers.test.mts new file mode 100644 index 000000000..c84216421 --- /dev/null +++ b/build_defs/native/host-runtime-test-helpers.test.mts @@ -0,0 +1,227 @@ +import assert from 'node:assert/strict'; +import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { + assertMissingHostRuntime, + extractNativePayload, + hostRuntimeEnvironment, + runHostBinary, +} from './host-runtime-test-helpers.mts'; + +const ambient = { + PATH: '/bazel/native-sdk/bin', + Path: 'C:\\native-sdk\\bin', + SystemRoot: 'C:\\Windows', + LD_LIBRARY_PATH: '/producer/lib', + LD_PRELOAD: '/producer/inject.so', + DYLD_LIBRARY_PATH: '/producer/lib', + DYLD_FALLBACK_LIBRARY_PATH: '/producer/lib', + DYLD_INSERT_LIBRARIES: '/producer/inject.dylib', + INCLUDE: '/compiler/include', + LIB: '/compiler/lib', + PGHOST: 'ambient-host', + PGDATA: '/ambient/data', + OLIPHAUNT_POSTGRES: '/producer/postgres', + OLIPHAUNT_ICU_DATA_DIR: '/ambient/icu', + LIBOLIPHAUNT_PATH: '/producer/liboliphaunt', + RUNFILES_DIR: '/bazel/runfiles', + TEST_SRCDIR: '/bazel/runfiles', + KEEP: 'unchanged', +}; +for (const platform of ['linux', 'darwin', 'win32'] as const) { + const env = hostRuntimeEnvironment( + platform === 'win32' ? 'C:\\candidate' : '/candidate', + platform === 'win32' ? 'C:\\test' : '/test', + platform, + ambient, + ); + assert.equal(env.KEEP, 'unchanged'); + for (const key of [ + 'Path', + 'LD_PRELOAD', + 'DYLD_INSERT_LIBRARIES', + 'INCLUDE', + 'LIB', + 'PGHOST', + 'PGDATA', + 'OLIPHAUNT_POSTGRES', + 'OLIPHAUNT_ICU_DATA_DIR', + 'LIBOLIPHAUNT_PATH', + 'RUNFILES_DIR', + 'TEST_SRCDIR', + ]) + assert.equal(env[key], undefined, `${platform} retained ${key}`); + if (platform === 'win32') { + assert.equal(env.PATH, 'C:\\candidate\\bin;C:\\Windows\\System32;C:\\Windows'); + assert.equal(env.LD_LIBRARY_PATH, undefined); + assert.equal(env.DYLD_LIBRARY_PATH, undefined); + assert.equal(env.ICU_DATA, 'C:\\candidate\\share\\icu'); + } else { + assert.equal(env.PATH, '/usr/bin:/bin:/usr/sbin:/sbin'); + assert.equal( + env[platform === 'darwin' ? 'DYLD_LIBRARY_PATH' : 'LD_LIBRARY_PATH'], + '/candidate/lib', + ); + assert.equal(env[platform === 'darwin' ? 'LD_LIBRARY_PATH' : 'DYLD_LIBRARY_PATH'], undefined); + assert.equal(env.ICU_DATA, '/candidate/share/icu'); + if (platform === 'darwin') assert.equal(env.DYLD_FALLBACK_LIBRARY_PATH, ''); + } +} +assert.throws( + () => hostRuntimeEnvironment('C:\\candidate', 'C:\\test', 'win32', {}), + /SystemRoot/u, +); +assert.throws( + () => hostRuntimeEnvironment('/candidate', '/test', 'freebsd', ambient), + /unsupported/u, +); +const result = (exitCode: number, stderr = '') => ({ exitCode, stderr: Buffer.from(stderr) }); +assertMissingHostRuntime( + result(127, 'liboliphaunt.so: cannot open shared object file'), + 'liboliphaunt.so', + 'linux', +); +assertMissingHostRuntime( + result(134, 'dyld: Library not loaded: @rpath/liboliphaunt.dylib'), + 'liboliphaunt.dylib', + 'darwin', +); +assertMissingHostRuntime(result(0x35), 'oliphaunt.dll', 'win32'); +for (const status of [0x34, 0x36]) + assert.throws(() => assertMissingHostRuntime(result(status), 'oliphaunt.dll', 'win32')); +for (const platform of ['linux', 'darwin', 'win32'] as const) { + assert.throws(() => assertMissingHostRuntime(result(0), 'liboliphaunt', platform)); + assert.throws(() => + assertMissingHostRuntime(result(2, 'usage: profile_smoke'), 'liboliphaunt', platform), + ); +} +assert.throws(() => + assertMissingHostRuntime(result(127, 'different.so: missing'), 'liboliphaunt.so', 'linux'), +); +assert.throws(() => + assertMissingHostRuntime( + result(134, 'unrelated crash in liboliphaunt.dylib'), + 'liboliphaunt.dylib', + 'darwin', + ), +); + +function tar(names: string[]): Buffer { + const members: Buffer[] = []; + for (const name of names) { + const body = Buffer.from('candidate'); + const header = Buffer.alloc(512); + header.write(name, 0, 'ascii'); + for (const offset of [100, 108, 116]) header.write('0000755\0', offset, 'ascii'); + header.write(body.length.toString(8).padStart(11, '0') + '\0', 124, 'ascii'); + header.write('00000000000\0', 136, 'ascii'); + header.fill(0x20, 148, 156); + header[156] = 0x30; + header.write('ustar\0', 257, 'ascii'); + header.write('00', 263, 'ascii'); + const sum = header.reduce((total, byte) => total + byte, 0); + header.write(sum.toString(8).padStart(6, '0') + '\0 ', 148, 'ascii'); + members.push(header, body, Buffer.alloc(512 - body.length)); + } + return Buffer.concat([...members, Buffer.alloc(1024)]); +} + +const root = mkdtempSync(join(tmpdir(), 'host-payload-helper-')); +try { + assert.equal( + runHostBinary( + process.execPath, + ['--no-env-file', '-e', 'console.log("captured stdout")'], + process.env, + root, + ), + 'captured stdout\n', + ); + assert.throws( + () => + runHostBinary( + process.execPath, + [ + '--no-env-file', + '-e', + 'console.log("captured stdout"); console.error("captured stderr"); process.exit(7)', + ], + process.env, + root, + ), + /captured stderr\s+captured stdout/u, + ); + const controller = join(root, 'controller.mts'); + writeFileSync( + controller, + ` +import { spawn } from 'node:child_process'; +import { existsSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +const [mode, release, done, pidFile, exitCode] = process.argv.slice(2); +if (mode === 'descendant') { + const finish = (reason) => { writeFileSync(done, reason); process.exit(0); }; + setTimeout(() => finish('deadline'), 10_000); + setInterval(() => { if (existsSync(release)) finish('released'); }, 10); +} else { + const descendant = spawn(process.execPath, + ['--no-env-file', import.meta.path, 'descendant', release, done, pidFile], + { cwd: tmpdir(), detached: true, stdio: ['ignore', 'inherit', 'inherit'] }); + descendant.unref(); + writeFileSync(pidFile, String(descendant.pid)); + process.exit(Number(exitCode)); +} +`, + ); + for (const exitCode of [0, 7]) { + const release = join(root, `release-${exitCode}`); + const done = join(root, `done-${exitCode}`); + const pidFile = join(root, `pid-${exitCode}`); + const runController = () => + runHostBinary( + process.execPath, + ['--no-env-file', controller, 'controller', release, done, pidFile, String(exitCode)], + process.env, + root, + 'inherit', + ); + try { + if (exitCode === 0) assert.equal(runController(), ''); + else + assert.throws( + runController, + (error) => error instanceof assert.AssertionError && error.actual === exitCode, + ); + const pid = Number(readFileSync(pidFile, 'utf8')); + assert(Number.isSafeInteger(pid) && pid > 0); + assert.doesNotThrow(() => process.kill(pid, 0), 'descendant must outlive its controller'); + assert(!existsSync(done), 'controller return must not wait for descendant output EOF'); + } finally { + writeFileSync(release, 'release'); + const deadline = Date.now() + 10_000; + while (!existsSync(done) && Date.now() < deadline) await Bun.sleep(10); + assert(existsSync(done), 'detached descendant did not finish cleanup'); + } + assert.equal(readFileSync(done, 'utf8'), 'released'); + } + const archive = join(root, 'payload.tar'); + const destination = join(root, 'runtime'); + writeFileSync(archive, tar(['bin/probe'])); + await extractNativePayload(archive, destination); + assert.equal(readFileSync(join(destination, 'bin', 'probe'), 'utf8'), 'candidate'); + writeFileSync(archive, tar(['bin/probe', '../escape'])); + await assert.rejects(extractNativePayload(archive, destination), /unsafe archive member/u); + assert.equal( + readFileSync(join(destination, 'bin', 'probe'), 'utf8'), + 'candidate', + 'invalid tar must not replace an existing tree', + ); + assert(!existsSync(join(root, 'escape'))); + writeFileSync(archive, tar(['bin/probe']).subarray(0, 700)); + await assert.rejects(extractNativePayload(archive, destination), /truncated/u); + await assert.rejects(extractNativePayload(root, destination), /bounded regular/u); + console.log('Host payload extraction, loader isolation and missing-candidate oracles: PASS'); +} finally { + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/native/host_config.bzl b/build_defs/native/host_config.bzl new file mode 100644 index 000000000..76f8d76e2 --- /dev/null +++ b/build_defs/native/host_config.bzl @@ -0,0 +1,190 @@ +"""PostgreSQL target facts established by the selected Apple/MSVC compiler. + +Linux and Android retain their already qualified bounded profiles. These host +profiles use upstream PG18.4 capability tests through the maintained native +checker, with no execution of a target binary and no configure process. +""" + +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library") +load("@rules_cc_autoconf//autoconf:autoconf.bzl", "autoconf") +load("@rules_cc_autoconf//autoconf:autoconf_hdr.bzl", "autoconf_hdr") +load("@rules_cc_autoconf//autoconf:autoconf_srcs.bzl", "autoconf_srcs") +load("@rules_cc_autoconf//autoconf:checks.bzl", "checks", "macros") +load(":config.bzl", "pg_config_layout") +load(":postgres_sources.bzl", "POSTGRES_PORT_REPLACEMENT_SOURCES") +load(":windows_config.bzl", "WINDOWS_CONFIG", "WINDOWS_COPTS", "WINDOWS_DEFINES") +load(":windows_sources.bzl", "WINDOWS_PORT_REPLACEMENT_SOURCES", "WINDOWS_FORCED_PORT_REPLACEMENTS") + +_PROFILES = [ + ("macos", False, "@oliphaunt//build_defs/native:macos_arm64", None), + ("windows", True, "@oliphaunt//build_defs/native:windows_x64", None), + ("ios", False, "@oliphaunt//build_defs/native:ios_arm64", 0), + ("ios_simulator", False, "@oliphaunt//build_defs/native:ios_arm64_simulator", 1), +] + +_HEADERS = [ + "atomic.h", "copyfile.h", "crtdefs.h", "execinfo.h", "getopt.h", + "ifaddrs.h", "inttypes.h", "mbarrier.h", "memory.h", "stdint.h", + "stdlib.h", "strings.h", "string.h", "sys/epoll.h", "sys/event.h", + "sys/personality.h", "sys/prctl.h", "sys/procctl.h", "sys/signalfd.h", + "sys/stat.h", "sys/types.h", "sys/ucred.h", "termios.h", "ucred.h", + "unistd.h", "xlocale.h", +] + +_FUNCTIONS = [ + "backtrace_symbols", "copyfile", "copy_file_range", "elf_aux_info", + "explicit_bzero", "fseeko", "getauxval", "getifaddrs", "getopt", + "getopt_long", "getpeereid", "getpeerucred", "inet_aton", "inet_pton", + "kqueue", "localeconv_l", "mbstowcs_l", "mkdtemp", "posix_fadvise", + "posix_fallocate", "ppoll", "pthread_barrier_wait", "pthread_is_threaded_np", + "setproctitle", "setproctitle_fast", "strerror_r", "strlcat", "strlcpy", + "strnlen", "strsep", "strsignal", "sync_file_range", "syncfs", "syslog", + "timingsafe_bcmp", "uselocale", "wcstombs_l", +] + +_DECLARATIONS = { + "fdatasync": "unistd.h", + "F_FULLFSYNC": "fcntl.h", + "memset_s": "string.h", + "posix_fadvise": "fcntl.h", + "preadv": "sys/uio.h", + "pwritev": "sys/uio.h", + "strchrnul": "string.h", + "strlcat": "string.h", + "strlcpy": "string.h", + "strnlen": "string.h", + "strsep": "string.h", + "timingsafe_bcmp": "string.h", +} + +# These are PG's compiler features, not guesses based on a compiler name. The +# probes keep the exact expressions which the corresponding PG code requires. +# See PostgreSQL config/c-compiler.m4 and config/c-library.m4: constant +# expressions need static bounds; referenced external variables need linking. +_COMPILE_FEATURES = { + "HAVE_COMPUTED_GOTO": "int main(void) { void *p = &&label; goto *p; label: return 0; }", + "HAVE_TYPEOF": "int main(void) { int x; typeof(x) y = 0; return y; }", + "HAVE__STATIC_ASSERT": "int main(void) { return ({ _Static_assert(1, \"ok\"); 0; }); }", + "HAVE__BUILTIN_CONSTANT_P": "static int x; static int y[__builtin_constant_p(x) ? x : 1]; static int z[__builtin_constant_p(\"string literal\") ? 1 : x];", + "HAVE__BUILTIN_TYPES_COMPATIBLE_P": "int main(void) { int x; static int y[__builtin_types_compatible_p(__typeof__(x), int)]; return 0; }", + "HAVE_VISIBILITY_ATTRIBUTE": "__attribute__((visibility(\"hidden\"))) int f(void) { return 0; }", + "HAVE_PTHREAD_PRIO_INHERIT": "#include \nint main(void) { return PTHREAD_PRIO_INHERIT; }", + "STRERROR_R_INT": "#include \nint main(void) { char b[100]; switch (strerror_r(1, b, sizeof(b))) { case 0: break; default: break; } return 0; }", + "HAVE_UNION_SEMUN": "#include \n#include \n#include \nint main(void) { union semun u; return sizeof(u); }", + "HAVE__CPUID": "#include \nint main(void) { int x[4]; __cpuid(x, 0); return x[0]; }", + "HAVE__CPUIDEX": "#include \nint main(void) { int x[4]; __cpuidex(x, 0, 0); return x[0]; }", +} + +_LINK_FEATURES = { + "HAVE_INT_OPTERR": "#include \nint main(void) { extern int opterr; opterr = 1; return 0; }", + "HAVE_INT_OPTRESET": "#include \nint main(void) { extern int optreset; optreset = 1; return 0; }", + "HAVE_INT_TIMEZONE": "#include \nint res; int main(void) { res = timezone / 60; return 0; }", + "HAVE__BUILTIN_BSWAP16": "int main(void) { return __builtin_bswap16(1); }", + "HAVE__BUILTIN_BSWAP32": "int main(void) { return __builtin_bswap32(1); }", + "HAVE__BUILTIN_BSWAP64": "int main(void) { return __builtin_bswap64(1); }", + "HAVE__BUILTIN_CLZ": "int main(void) { return __builtin_clz(1); }", + "HAVE__BUILTIN_CTZ": "int main(void) { return __builtin_ctz(1); }", + "HAVE__BUILTIN_FRAME_ADDRESS": "int main(void) { return __builtin_frame_address(0) == 0; }", + "HAVE__BUILTIN_OP_OVERFLOW": "#include \nint64_t a = 1, b = 1, result; int oflo; int main(void) { oflo = __builtin_mul_overflow(a, b, &result); return 0; }", + "HAVE__BUILTIN_POPCOUNT": "int main(void) { return __builtin_popcount(1); }", + "HAVE__BUILTIN_UNREACHABLE": "int main(void) { __builtin_unreachable(); }", + "HAVE_GCC__SYNC_CHAR_TAS": "int main(void) { char x = 0; return __sync_lock_test_and_set(&x, 1); }", + "HAVE_GCC__SYNC_INT32_TAS": "#include \nint main(void) { int32_t x = 0; return __sync_lock_test_and_set(&x, 1); }", + "HAVE_GCC__SYNC_INT32_CAS": "#include \nint main(void) { int32_t x = 0; return __sync_val_compare_and_swap(&x, 0, 1); }", + "HAVE_GCC__SYNC_INT64_CAS": "#include \nint main(void) { int64_t x = 0; return __sync_val_compare_and_swap(&x, 0, 1); }", + "HAVE_GCC__ATOMIC_INT32_CAS": "#include \nint main(void) { int32_t x = 0, y = 0; return __atomic_compare_exchange_n(&x, &y, 1, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }", + "HAVE_GCC__ATOMIC_INT64_CAS": "#include \nint main(void) { int64_t x = 0, y = 0; return __atomic_compare_exchange_n(&x, &y, 1, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); }", + # Volatile reads retain upstream's runtime-helper check under optimization. + "HAVE_PG_INT128": "volatile __int128 a = 48828125, b = 97656250; int main(void) { __int128 c, d; a = (a << 12) + 1; b = (b << 12) + 5; c = a * b; d = (c + b) / b; if (d != a + 1) return 1; return 0; }", + "HAVE_PTHREAD": "#include \nstatic void *f(void *p) { return p; } int main(void) { pthread_t t; return pthread_create(&t, 0, f, 0); }", +} + +def _policy(version, windows, ios = False): + major, minor = [int(part) for part in version.split(".")] + policy = WINDOWS_CONFIG if windows else { + "BLCKSZ": "8192", "CONFIGURE_ARGS": '"Bazel macOS arm64 ICU profile"', + "DEF_PGPORT": "5432", "DEF_PGPORT_STR": '"5432"', "DLSUFFIX": '".dylib"', + "MEMSET_LOOP_LIMIT": "1024", "PACKAGE_BUGREPORT": '"pgsql-bugs@lists.postgresql.org"', + "PACKAGE_NAME": '"PostgreSQL"', "PACKAGE_TARNAME": '"postgresql"', + "PACKAGE_URL": '"https://www.postgresql.org/"', "PG_KRB_SRVNAM": '"postgres"', + "RELSEG_SIZE": "131072", "USE_ICU": "1", "USE_SYSV_SEMAPHORES": "1", + "USE_SYSV_SHARED_MEMORY": "1", "USE_SLICING_BY_8_CRC32C": "1", + "XLOG_BLCKSZ": "8192", "pg_restrict": "__restrict", + "PG_C_PRINTF_ATTRIBUTE": "printf", "PG_CXX_PRINTF_ATTRIBUTE": "printf", + } + if ios: + policy = policy | {"CONFIGURE_ARGS": '"Bazel iOS arm64 ICU profile"'} + return policy | { + "PACKAGE_STRING": '"PostgreSQL ' + version + '"', + "PACKAGE_VERSION": '"' + version + '"', + "PG_MAJORVERSION": '"' + str(major) + '"', + "PG_MAJORVERSION_NUM": str(major), "PG_MINORVERSION_NUM": str(minor), + "PG_VERSION": '"' + version + '"', "PG_VERSION_NUM": str(major * 10000 + minor), + "PG_VERSION_STR": '"PostgreSQL ' + version + ' Bazel ' + ("MSVC" if windows else "Apple Clang") + ', 64-bit"', + # Upstream derives this from double's compiler-established alignment. + "MAXIMUM_ALIGNOF": "ALIGNOF_DOUBLE", + "STDC_HEADERS": "1", + } + +def postgres_capability_checks(copts, definitions, abi = True, excluded = [], windows = False): + """Use one maintained upstream check set for target compiler/libc facts.""" + # PG's Windows sys/socket.h shim includes these SDK headers. Probe that + # same native interface without depending on the PG compatibility headers. + socket_includes = ["#include ", "#include "] if windows else ["#include ", "#include "] + tests = macros.AC_CHECK_HEADERS(_HEADERS) + macros.AC_CHECK_FUNCS(_FUNCTIONS) + tests += [checks.AC_CHECK_DECL(symbol, includes = ["#include <" + header + ">"], define = "HAVE_DECL_" + symbol.upper(), if_false = "0") for symbol, header in _DECLARATIONS.items()] + if abi: + tests += [checks.AC_CHECK_SIZEOF(t, includes = ["#include ", "#include "], define = d) for t, d in [ + ("long", "SIZEOF_LONG"), ("long long", "SIZEOF_LONG_LONG"), ("off_t", "SIZEOF_OFF_T"), ("size_t", "SIZEOF_SIZE_T"), ("void *", "SIZEOF_VOID_P"), + ]] + tests += [checks.AC_CHECK_ALIGNOF(t, includes = ["#include "], define = d) for t, d in [ + ("double", "ALIGNOF_DOUBLE"), ("int", "ALIGNOF_INT"), ("int64_t", "ALIGNOF_INT64_T"), ("long", "ALIGNOF_LONG"), ("short", "ALIGNOF_SHORT"), + ]] + tests += [checks.AC_CHECK_TYPE("struct option", includes = ["#include "], define = "HAVE_STRUCT_OPTION"), + checks.AC_CHECK_TYPE("socklen_t", includes = socket_includes, define = "HAVE_SOCKLEN_T"), + checks.AC_CHECK_MEMBER("struct sockaddr.sa_len", includes = socket_includes, define = "HAVE_STRUCT_SOCKADDR_SA_LEN"), + checks.AC_CHECK_MEMBER("struct tm.tm_zone", includes = ["#include "], define = "HAVE_STRUCT_TM_TM_ZONE")] + tests += [checks.AC_TRY_COMPILE(code = code, define = define) for define, code in _COMPILE_FEATURES.items()] + tests += [checks.AC_TRY_LINK(code = code, define = define, if_false = None) for define, code in _LINK_FEATURES.items()] + tests += [checks.AC_DEFINE("PG_INT128_TYPE", condition = "HAVE_PG_INT128", if_true = "__int128", if_false = None), + checks.AC_CHECK_ALIGNOF("__int128", define = "ALIGNOF_PG_INT128_TYPE", requires = ["HAVE_PG_INT128"])] + # Compilation flags and SDK feature visibility must match production. + tests = [test for test in tests if json.decode(test).get("define") not in excluded] + return [json.encode(json.decode(test) | {"copts": copts, "compile_defines": definitions + ["__STDC_WANT_LIB_EXT1__"]}) for test in tests] + +def postgres_host_configuration_targets(version): + """Declare facts, header, positive admission and conditional port units.""" + for suffix, windows, setting, simulator in _PROFILES: + name = "host_" + suffix + compatible = select({setting: [], "//conditions:default": ["@platforms//:incompatible"]}) + opts = WINDOWS_COPTS + ["/WX"] if windows else ["-std=gnu11", "-Werror=unguarded-availability-new", "-Werror=incompatible-pointer-types", "-Werror=implicit-function-declaration"] + definitions = WINDOWS_DEFINES if windows else ["_DARWIN_C_SOURCE"] + policy = _policy(version, windows, ios = simulator != None) + tests = postgres_capability_checks(opts, definitions, windows = windows) + # AC_DEFINE preserves the value's JSON type in probe preambles. Feature + # switches must be integers: "1" would emit a C string literal, which + # conflicts with MSVC's /D_CRT_SECURE_NO_DEPRECATE=1 under /WX. + autoconf(name = name + "_facts", checks = [checks.AC_DEFINE(d, 1) for d in definitions + ["__STDC_WANT_LIB_EXT1__"]] + tests + [checks.AC_DEFINE(key, value) for key, value in policy.items()], target_compatible_with = compatible) + # PG Meson emits WIN32_STACK_RLIMIT, but the Autoconf template has no + # placeholder: its Makefile.win32 supplies the value through CPPFLAGS. + # Resolve this Windows-only placeholder from the existing policy fact. + autoconf_hdr(name = name + "_config", out = name + "/src/include/pg_config.h", template = "src/include/pg_config.h.in", deps = [":" + name + "_facts"], defaults = False, + substitutions = {"#undef BLCKSZ": "#undef BLCKSZ\n#undef WIN32_STACK_RLIMIT"} if windows else {}, target_compatible_with = compatible) + pg_config_layout(name = name + "_layout", os_header = "src/include/port/" + ("win32.h" if windows else "darwin.h"), output_directory = name + "/src/include", target_compatible_with = compatible) + cc_binary(name = name + "_sanity", srcs = ["@oliphaunt//build_defs/native:probe-sanity.c"], copts = opts, target_compatible_with = compatible) + abi_sources = ["@oliphaunt//build_defs/native:host-config-contract.c"] + abi_defines = [] + if simulator != None: + abi_sources.append("@oliphaunt//build_defs/native:ios-config-contract.c") + abi_defines.append("OLIPHAUNT_EXPECT_IOS_SIMULATOR=" + str(simulator)) + cc_library(name = name + "_abi", srcs = abi_sources, local_defines = abi_defines, hdrs = [":" + name + "_config"], includes = [name + "/src/include"], copts = opts, target_compatible_with = compatible) + native.filegroup(name = name + "_configuration", srcs = [":" + name + "_config", ":" + name + "_layout"], target_compatible_with = compatible) + # This dependency is built once for the profile; a dead compiler cannot + # be interpreted as a platform where every optional feature is absent. + cc_library(name = name + "_admission", deps = [":" + name + "_abi"], data = [":" + name + "_sanity"], target_compatible_with = compatible) + replacements = WINDOWS_PORT_REPLACEMENT_SOURCES if windows else POSTGRES_PORT_REPLACEMENT_SOURCES + # PG always compiles its MSVC getopt replacements. Only conditions + # depending on actual compiler facts need generated autoconf sources. + forced = WINDOWS_FORCED_PORT_REPLACEMENTS if windows else [] + autoconf_srcs(name = name + "_conditional_replacements", srcs = {source: "!ac_cv_func_" + macro[len("HAVE_"):].lower() for macro, source in replacements.items() if macro not in forced}, deps = [":" + name + "_facts"], defaults = False, target_compatible_with = compatible) + native.filegroup(name = name + "_replacements", srcs = [source for macro, source in replacements.items() if macro in forced] + [":" + name + "_conditional_replacements"], target_compatible_with = compatible) diff --git a/build_defs/native/icu-data-object.mts b/build_defs/native/icu-data-object.mts new file mode 100644 index 000000000..018a20a0d --- /dev/null +++ b/build_defs/native/icu-data-object.mts @@ -0,0 +1,120 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +export function icuDataIdentity(versionHeader: string, typesHeader: string) { + const major = versionHeader.match(/^\s*#\s*define\s+U_ICU_VERSION_MAJOR_NUM\s+(\d+)\s*$/mu)?.[1]; + const short = versionHeader.match(/^\s*#\s*define\s+U_ICU_VERSION_SHORT\s+"(\d+)"\s*$/mu)?.[1]; + const entryMacro = typesHeader.match(/^\s*#\s*define\s+U_ICUDATA_ENTRY_POINT\s+(.+)$/mu)?.[1]; + const body = typesHeader.match( + /^\s*#\s*define\s+U_DEF_ICUDATA_ENTRY_POINT\(major,\s*suff\)\s+(.+)$/mu, + )?.[1]; + if ( + !major || + short !== major || + entryMacro?.replace(/\s+/gu, '') !== + 'U_DEF2_ICUDATA_ENTRY_POINT(U_ICU_VERSION_MAJOR_NUM,U_LIB_SUFFIX_C_NAME)' || + body?.replace(/\s+/gu, '') !== 'icudt##major##_dat' + ) { + throw new Error('Unsupported ICU source data entry-point/version macros'); + } + // Expand the unsuffixed upstream token-paste definition. Neither the version + // nor the concrete symbol is maintained separately from the source headers. + const symbol = body.replace(/\bmajor\b/gu, major).replace(/\s|##/gu, ''); + return { symbol, packageName: `icudt${short}l` }; +} + +function checkCommonData(data: Buffer, packageName: string) { + if ( + data.length < 28 || + data[2] !== 0xda || + data[3] !== 0x27 || + data[8] !== 0 || + data[9] !== 0 || + data[10] !== 2 || + data.toString('ascii', 12, 16) !== 'CmnD' || + data[16] !== 1 + ) { + throw new Error('Expected ICU little-endian ASCII common data (CmnD v1)'); + } + const headerSize = data.readUInt16LE(0); + if (headerSize < 24 || headerSize + 4 > data.length) + throw new Error('Truncated ICU common-data header'); + const count = data.readUInt32LE(headerSize); + const tableEnd = 4 + count * 8; + if (!count || headerSize + tableEnd > data.length) + throw new Error('Empty or truncated ICU common-data table'); + for (let index = 0; index < count; index++) { + const entry = headerSize + 4 + index * 8; + const nameOffset = data.readUInt32LE(entry); + const itemOffset = data.readUInt32LE(entry + 4); + const nameEnd = data.indexOf(0, headerSize + nameOffset); + if ( + nameOffset < tableEnd || + itemOffset <= nameOffset || + headerSize + itemOffset >= data.length || + itemOffset % 16 !== 0 || + nameEnd < 0 || + nameEnd >= headerSize + itemOffset + ) { + throw new Error('Invalid ICU common-data item offsets'); + } + const name = data.toString('ascii', headerSize + nameOffset, nameEnd); + if (!name.startsWith(`${packageName}/`)) + throw new Error(`ICU data package ${name} does not match source ${packageName}`); + } +} + +export function icuDataObject( + data: Buffer, + versionHeader: string, + typesHeader: string, + machine: string, +) { + if (machine !== 'amd64') throw new Error(`Unsupported ICU COFF machine: ${machine}`); + const { symbol, packageName } = icuDataIdentity(versionHeader, typesHeader); + checkCommonData(data, packageName); + + // Same bounded COFF layout as ICU tools/toolutil/pkg_genc.cpp writeObjectCode: + // linker directives, 16-aligned read-only data, one external DATA symbol, and + // its long-name string table. A zero timestamp makes the output reproducible. + const directive = Buffer.from(`-export:${symbol},data `, 'ascii'); + const names = Buffer.from(`${symbol}\0`, 'ascii'); + const headerSize = 20 + 2 * 40; + const dataOffset = headerSize + directive.length; + const symbolsOffset = dataOffset + data.length; + if (symbolsOffset + 18 + 4 + names.length > 0xffffffff) + throw new Error('ICU data exceeds the supported COFF object size'); + const header = Buffer.alloc(headerSize); + header.writeUInt16LE(0x8664, 0); // IMAGE_FILE_MACHINE_AMD64 + header.writeUInt16LE(2, 2); + header.writeUInt32LE(symbolsOffset, 8); + header.writeUInt32LE(1, 12); + header.write('.drectve', 20, 'ascii'); + header.writeUInt32LE(directive.length, 36); + header.writeUInt32LE(headerSize, 40); + header.writeUInt32LE(0x00100a00, 56); // INFO | REMOVE | ALIGN_1BYTES + header.write('.rdata', 60, 'ascii'); + header.writeUInt32LE(data.length, 76); + header.writeUInt32LE(dataOffset, 80); + header.writeUInt32LE(0x40500040, 96); // INITIALIZED_DATA | ALIGN_16BYTES | READ + const symbols = Buffer.alloc(18 + 4); + symbols.writeUInt32LE(4, 4); // long symbol name at string-table offset 4 + symbols.writeInt16LE(2, 12); // section 2, offset 0 + symbols[16] = 2; // IMAGE_SYM_CLASS_EXTERNAL + symbols.writeUInt32LE(4 + names.length, 18); + return Buffer.concat([header, directive, data, symbols, names]); +} + +if (import.meta.main) { + const [dataPath, versionPath, typesPath, machine, output] = process.argv.slice(2); + if (!dataPath || !versionPath || !typesPath || !machine || !output) + throw new Error('Expected data, uvernum.h, utypes.h, machine, output.obj'); + writeFileSync( + output, + icuDataObject( + readFileSync(dataPath), + readFileSync(versionPath, 'utf8'), + readFileSync(typesPath, 'utf8'), + machine, + ), + ); +} diff --git a/build_defs/native/icu-data-object.test.mts b/build_defs/native/icu-data-object.test.mts new file mode 100644 index 000000000..c86e7a89c --- /dev/null +++ b/build_defs/native/icu-data-object.test.mts @@ -0,0 +1,129 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { icuDataIdentity, icuDataObject } from './icu-data-object.mts'; + +const version = '#define U_ICU_VERSION_MAJOR_NUM 91\n#define U_ICU_VERSION_SHORT "91"\n'; +const types = + '#define U_ICUDATA_ENTRY_POINT U_DEF2_ICUDATA_ENTRY_POINT(U_ICU_VERSION_MAJOR_NUM,U_LIB_SUFFIX_C_NAME)\n' + + '#define U_DEF_ICUDATA_ENTRY_POINT(major, suff) icudt##major##_dat\n'; + +function commonData(packageName: string) { + const data = Buffer.alloc(128); + data.writeUInt16LE(32, 0); + data[2] = 0xda; + data[3] = 0x27; + data[10] = 2; + data.write('CmnD', 12, 'ascii'); + data[16] = 1; + data.writeUInt32LE(1, 32); + data.writeUInt32LE(12, 36); + data.writeUInt32LE(64, 40); + data.write(`${packageName}/test.res\0`, 44, 'ascii'); + for (let index = 96; index < data.length; index++) data[index] = index; + return data; +} + +function checkObject(data: Buffer, versionHeader: string, typesHeader: string) { + const object = icuDataObject(data, versionHeader, typesHeader, 'amd64'); + const { symbol } = icuDataIdentity(versionHeader, typesHeader); + assert.equal(object.readUInt16LE(0), 0x8664); + assert.equal(object.readUInt16LE(2), 2); + assert.equal(object.readUInt32LE(4), 0, 'timestamp must be reproducible'); + assert.equal(object.readUInt32LE(12), 1); + assert.equal(object.subarray(20, 28).toString('ascii'), '.drectve'); + assert.equal(object.subarray(60, 66).toString('ascii'), '.rdata'); + assert.equal(object.readUInt32LE(56), 0x00100a00); + assert.equal(object.readUInt32LE(96), 0x40500040, 'read-only data needs 16-byte alignment'); + const directiveStart = object.readUInt32LE(40); + const directiveEnd = directiveStart + object.readUInt32LE(36); + assert.equal( + object.subarray(directiveStart, directiveEnd).toString('ascii'), + `-export:${symbol},data `, + ); + const rawStart = object.readUInt32LE(80); + const rawEnd = rawStart + object.readUInt32LE(76); + assert.deepEqual(object.subarray(rawStart, rawEnd), data, 'full data bytes must be unchanged'); + const symbolsStart = object.readUInt32LE(8); + assert.equal(symbolsStart, rawEnd); + assert.equal(object.readUInt32LE(symbolsStart), 0); + assert.equal(object.readUInt32LE(symbolsStart + 4), 4); + assert.equal(object.readUInt32LE(symbolsStart + 8), 0); + assert.equal(object.readInt16LE(symbolsStart + 12), 2); + assert.equal(object[symbolsStart + 16], 2); + assert.equal(object[symbolsStart + 17], 0); + assert.equal(object.subarray(symbolsStart + 22, -1).toString('ascii'), symbol); + assert.equal(object.readUInt32LE(symbolsStart + 18), symbol.length + 5); + assert.deepEqual(icuDataObject(data, versionHeader, typesHeader, 'amd64'), object); +} + +const data = commonData('icudt91l'); +assert.deepEqual(icuDataIdentity(version, types), { + symbol: 'icudt91_dat', + packageName: 'icudt91l', +}); +checkObject(data, version, types); +assert.throws(() => icuDataObject(data, version, types, 'arm64'), /Unsupported ICU COFF machine/u); +assert.throws(() => icuDataObject(data, version, types, 'i386'), /Unsupported ICU COFF machine/u); +assert.throws(() => icuDataObject(data.subarray(0, 12), version, types, 'amd64'), /Expected ICU/u); +assert.throws( + () => icuDataObject(commonData('icudt90l'), version, types, 'amd64'), + /does not match source/u, +); +assert.throws( + () => icuDataObject(data, version.replace('"91"', '"90"'), types, 'amd64'), + /macros/u, +); +assert.throws( + () => + icuDataObject( + data, + version, + types.replace('icudt##major##_dat', 'other##major##_dat'), + 'amd64', + ), + /macros/u, +); +for (const mutate of [ + (bytes: Buffer) => { + bytes[8] = 1; + }, + (bytes: Buffer) => { + bytes.writeUInt16LE(0xffff, 0); + }, + (bytes: Buffer) => { + bytes.writeUInt32LE(0, 32); + }, + (bytes: Buffer) => { + bytes.writeUInt32LE(0xffffffff, 32); + }, + (bytes: Buffer) => { + bytes.writeUInt32LE(0, 36); + }, + (bytes: Buffer) => { + bytes.writeUInt32LE(63, 40); + }, + (bytes: Buffer) => { + bytes.writeUInt32LE(128, 40); + }, + (bytes: Buffer) => { + bytes.fill(0xff, 44); + }, +]) { + const invalid = Buffer.from(data); + mutate(invalid); + assert.throws(() => icuDataObject(invalid, version, types, 'amd64'), /ICU/u); +} + +const [dataPath, versionPath, typesPath] = process.argv.slice(2); +if (dataPath || versionPath || typesPath) { + assert( + dataPath && versionPath && typesPath, + 'expected canonical data and both actual source headers', + ); + checkObject( + readFileSync(dataPath), + readFileSync(versionPath, 'utf8'), + readFileSync(typesPath, 'utf8'), + ); +} +console.log('ICU COFF data layout, source identity, raw bytes and malformed inputs: PASS'); diff --git a/build_defs/native/icu-windows-smoke.cc b/build_defs/native/icu-windows-smoke.cc new file mode 100644 index 000000000..fd558a5f7 --- /dev/null +++ b/build_defs/native/icu-windows-smoke.cc @@ -0,0 +1,41 @@ +#include +#include + +#include "unicode/uclean.h" +#include "unicode/ucol.h" +#include "unicode/uloc.h" +#include "unicode/unorm2.h" +#include "unicode/uversion.h" + +extern "C" const unsigned char U_DATA_API U_ICUDATA_ENTRY_POINT[]; + +int main() { + // The exported symbol must be the real, aligned common-data header. This + // also makes the test link directly through the generated data import lib. + if (reinterpret_cast(U_ICUDATA_ENTRY_POINT) % 16 != 0 || + U_ICUDATA_ENTRY_POINT[2] != 0xda || U_ICUDATA_ENTRY_POINT[3] != 0x27 || + U_ICUDATA_ENTRY_POINT[12] != 'C' || U_ICUDATA_ENTRY_POINT[13] != 'm') + return 1; + UVersionInfo version; + u_getVersion(version); + if (version[0] != U_ICU_VERSION_MAJOR_NUM) return 2; + UErrorCode error = U_ZERO_ERROR; + u_init(&error); + if (U_FAILURE(error) || uloc_countAvailable() < 100) return 3; + const UNormalizer2 *nfc = unorm2_getNFCInstance(&error); + if (U_FAILURE(error) || !nfc) return 4; + const UChar decomposed[] = {0x65, 0x301}; + UChar composed[8]; + const int32_t length = unorm2_normalize(nfc, decomposed, 2, composed, 8, &error); + if (U_FAILURE(error) || length != 1 || composed[0] != 0xe9) return 4; + UCollator *collator = ucol_open("de", &error); + if (U_FAILURE(error) || !collator) return 5; + const UChar a_umlaut[] = {0xe4}; + const UChar z[] = {0x7a}; + const bool ordered = ucol_strcoll(collator, a_umlaut, 1, z, 1) == UCOL_LESS; + ucol_close(collator); + u_cleanup(); + if (!ordered) return 6; + std::puts("Actual ICU shared data, normalization and collation: PASS"); + return 0; +} diff --git a/build_defs/native/icu.BUILD.bazel b/build_defs/native/icu.BUILD.bazel new file mode 100644 index 000000000..f3128a571 --- /dev/null +++ b/build_defs/native/icu.BUILD.bazel @@ -0,0 +1,82 @@ +load("@rules_cc//cc:cc_library.bzl", "cc_library") +load("@oliphaunt//build_defs/native:platform_config.bzl", "NATIVE_C_COMPATIBLE", "NATIVE_LINKOPTS") +load("@oliphaunt//build_defs/native:icu_windows.bzl", "icu_windows_targets") +load( + ":icu_sources.bzl", + "ICU_COMMON_HEADERS", + "ICU_COMMON_SOURCES", + "ICU_I18N_HEADERS", + "ICU_I18N_SOURCES", + "ICU_STUBDATA_HEADERS", + "ICU_STUBDATA_SOURCES", +) + +package(default_visibility = ["//visibility:public"]) + +exports_files(["common/unicode/uvernum.h", "common/unicode/utypes.h"]) + +# ICU's source platform/uconfig headers select the target defaults; there is no +# configure-generated header or legacy build-system action. Each ABI profile +# still requires its actual linked/runtime qualification. +_COMPATIBLE = NATIVE_C_COMPATIBLE + +_CXXFLAGS = [ + "-std=c++17", + "-fPIC", + "-pthread", +] + +# The header boundary keeps the stub data library independent of common's +# implementation. Windows consumers use the actual shared DLL ABI. +cc_library( + name = "common_headers", + hdrs = ICU_COMMON_HEADERS, + defines = select({"@platforms//os:windows": [], "//conditions:default": ["U_STATIC_IMPLEMENTATION"]}), + includes = ["common"], + target_compatible_with = _COMPATIBLE, +) + +# ICU's checked-in empty TOC preserves the normal versioned icudt76_dat +# entrypoint. It does not embed or generate the managed icudt76l.dat resource. +cc_library( + name = "data_stub", + srcs = ICU_STUBDATA_SOURCES, + hdrs = ICU_STUBDATA_HEADERS, + copts = _CXXFLAGS, + linkstatic = True, + target_compatible_with = _COMPATIBLE + select({"@platforms//os:windows": ["@platforms//:incompatible"], "//conditions:default": []}), + deps = [":common_headers"], +) + +cc_library( + name = "common", + srcs = select({"@platforms//os:windows": [], "//conditions:default": ICU_COMMON_SOURCES}), + copts = select({"@platforms//os:windows": [], "//conditions:default": _CXXFLAGS}), + linkopts = NATIVE_LINKOPTS, + linkstatic = True, + local_defines = select({"@platforms//os:windows": [], "//conditions:default": ["U_COMMON_IMPLEMENTATION"]}), + target_compatible_with = _COMPATIBLE, + deps = [ + ":common_headers", + ] + select({"@platforms//os:windows": [":icuuc76.dll_import"], "//conditions:default": [":data_stub"]}), +) + +cc_library( + name = "i18n_headers", + hdrs = ICU_I18N_HEADERS, + includes = ["i18n"], + deps = [":common_headers"], + target_compatible_with = _COMPATIBLE, +) + +cc_library( + name = "i18n", + srcs = select({"@platforms//os:windows": [], "//conditions:default": ICU_I18N_SOURCES}), + copts = select({"@platforms//os:windows": [], "//conditions:default": _CXXFLAGS}), + linkstatic = True, + local_defines = select({"@platforms//os:windows": [], "//conditions:default": ["U_I18N_IMPLEMENTATION"]}), + target_compatible_with = _COMPATIBLE, + deps = [":common", ":i18n_headers"] + select({"@platforms//os:windows": [":icuin76.dll_import"], "//conditions:default": []}), +) + +icu_windows_targets(common_sources = ICU_COMMON_SOURCES, i18n_sources = ICU_I18N_SOURCES) diff --git a/build_defs/native/icu_data.bzl b/build_defs/native/icu_data.bzl new file mode 100644 index 000000000..f0aef1535 --- /dev/null +++ b/build_defs/native/icu_data.bzl @@ -0,0 +1,58 @@ +"""Pinned ICU 76 little-endian data as an explicit runtime resource.""" + +def _manifest_strings(text): + values = {} + for line in text.splitlines(): + line = line.strip() + if not line or line.startswith("#"): + continue + key, separator, value = line.partition("=") + key = key.strip() + value = value.strip() + if not separator or not value.startswith("\"") or not value.endswith("\""): + fail("ICU data source metadata must contain quoted strings: " + line) + if key in values: + fail("duplicate ICU data source metadata key: " + key) + values[key] = value[1:-1] + return values + +def _icu_data_repository_impl(ctx): + source = _manifest_strings(ctx.read(ctx.attr.source_manifest)) + for key in ["url", "sha256"]: + if not source.get(key): + fail("ICU data source metadata is missing " + key) + if source.get("kind") != "archive": + fail("ICU data source must be a checksum-pinned archive") + prefix = source.get("strip_prefix", "") + ctx.download_and_extract( + url = source["url"], + sha256 = source["sha256"], + type = "zip", + stripPrefix = "" if prefix == "." else prefix, + ) + + # This filename is the ICU 76 little-endian ABI resource consumed by the + # existing portable packages and managed-runtime data directory. + data = "icudt76l.dat" + if not ctx.path(data).exists: + fail("pinned ICU data archive is missing " + data) + notices = [ + filename + for filename in ["LICENSE", "icu4c-76_1-data-bin-l-README.md"] + if ctx.path(filename).exists + ] + ctx.file("BUILD.bazel", """package(default_visibility = ["//visibility:public"]) +exports_files({files}) +filegroup(name = "data", srcs = {data}) +filegroup(name = "notices", srcs = {notices}) +""".format(files = repr([data] + notices), data = repr([data]), notices = repr(notices))) + +icu_data_repository = repository_rule( + implementation = _icu_data_repository_impl, + attrs = { + "source_manifest": attr.label( + default = Label("//src/database-resources/icu:source.toml"), + allow_single_file = True, + ), + }, +) diff --git a/build_defs/native/icu_sources.bzl b/build_defs/native/icu_sources.bzl new file mode 100644 index 000000000..8279bc47d --- /dev/null +++ b/build_defs/native/icu_sources.bzl @@ -0,0 +1,987 @@ +"""ICU 76.1 compilation inputs from the canonical pinned source checkout. + +The source lists preserve upstream common/i18n/stubdata sources.txt order. +Platform-specific units remain in those lists: upstream guards their bodies. +Headers and Unicode tables are checked-in inputs, not generated build outputs. +The data stub supplies the empty icudt76_dat table; full Unicode data remains +an explicit runtime resource supplied by the managed ICU data package. +""" + +ICU_COMMON_SOURCES = [ + "common/appendable.cpp", + "common/bmpset.cpp", + "common/brkeng.cpp", + "common/brkiter.cpp", + "common/bytesinkutil.cpp", + "common/bytestream.cpp", + "common/bytestrie.cpp", + "common/bytestriebuilder.cpp", + "common/bytestrieiterator.cpp", + "common/caniter.cpp", + "common/characterproperties.cpp", + "common/chariter.cpp", + "common/charstr.cpp", + "common/cmemory.cpp", + "common/cstr.cpp", + "common/cstring.cpp", + "common/cwchar.cpp", + "common/dictbe.cpp", + "common/dictionarydata.cpp", + "common/dtintrv.cpp", + "common/edits.cpp", + "common/emojiprops.cpp", + "common/errorcode.cpp", + "common/filteredbrk.cpp", + "common/filterednormalizer2.cpp", + "common/icudataver.cpp", + "common/icuplug.cpp", + "common/loadednormalizer2impl.cpp", + "common/localebuilder.cpp", + "common/localematcher.cpp", + "common/localeprioritylist.cpp", + "common/locavailable.cpp", + "common/locbased.cpp", + "common/locdispnames.cpp", + "common/locdistance.cpp", + "common/locdspnm.cpp", + "common/locid.cpp", + "common/loclikely.cpp", + "common/loclikelysubtags.cpp", + "common/locmap.cpp", + "common/locresdata.cpp", + "common/locutil.cpp", + "common/lsr.cpp", + "common/lstmbe.cpp", + "common/messagepattern.cpp", + "common/mlbe.cpp", + "common/normalizer2.cpp", + "common/normalizer2impl.cpp", + "common/normlzr.cpp", + "common/parsepos.cpp", + "common/patternprops.cpp", + "common/pluralmap.cpp", + "common/propname.cpp", + "common/propsvec.cpp", + "common/punycode.cpp", + "common/putil.cpp", + "common/rbbi.cpp", + "common/rbbi_cache.cpp", + "common/rbbidata.cpp", + "common/rbbinode.cpp", + "common/rbbirb.cpp", + "common/rbbiscan.cpp", + "common/rbbisetb.cpp", + "common/rbbistbl.cpp", + "common/rbbitblb.cpp", + "common/resbund.cpp", + "common/resbund_cnv.cpp", + "common/resource.cpp", + "common/restrace.cpp", + "common/ruleiter.cpp", + "common/schriter.cpp", + "common/serv.cpp", + "common/servlk.cpp", + "common/servlkf.cpp", + "common/servls.cpp", + "common/servnotf.cpp", + "common/servrbf.cpp", + "common/servslkf.cpp", + "common/sharedobject.cpp", + "common/simpleformatter.cpp", + "common/static_unicode_sets.cpp", + "common/stringpiece.cpp", + "common/stringtriebuilder.cpp", + "common/uarrsort.cpp", + "common/ubidi.cpp", + "common/ubidi_props.cpp", + "common/ubidiln.cpp", + "common/ubiditransform.cpp", + "common/ubidiwrt.cpp", + "common/ubrk.cpp", + "common/ucase.cpp", + "common/ucasemap.cpp", + "common/ucasemap_titlecase_brkiter.cpp", + "common/ucat.cpp", + "common/uchar.cpp", + "common/ucharstrie.cpp", + "common/ucharstriebuilder.cpp", + "common/ucharstrieiterator.cpp", + "common/uchriter.cpp", + "common/ucln_cmn.cpp", + "common/ucmndata.cpp", + "common/ucnv.cpp", + "common/ucnv2022.cpp", + "common/ucnv_bld.cpp", + "common/ucnv_cb.cpp", + "common/ucnv_cnv.cpp", + "common/ucnv_ct.cpp", + "common/ucnv_err.cpp", + "common/ucnv_ext.cpp", + "common/ucnv_io.cpp", + "common/ucnv_lmb.cpp", + "common/ucnv_set.cpp", + "common/ucnv_u16.cpp", + "common/ucnv_u32.cpp", + "common/ucnv_u7.cpp", + "common/ucnv_u8.cpp", + "common/ucnvbocu.cpp", + "common/ucnvdisp.cpp", + "common/ucnvhz.cpp", + "common/ucnvisci.cpp", + "common/ucnvlat1.cpp", + "common/ucnvmbcs.cpp", + "common/ucnvscsu.cpp", + "common/ucnvsel.cpp", + "common/ucol_swp.cpp", + "common/ucptrie.cpp", + "common/ucurr.cpp", + "common/udata.cpp", + "common/udatamem.cpp", + "common/udataswp.cpp", + "common/uenum.cpp", + "common/uhash.cpp", + "common/uhash_us.cpp", + "common/uidna.cpp", + "common/uinit.cpp", + "common/uinvchar.cpp", + "common/uiter.cpp", + "common/ulist.cpp", + "common/uloc.cpp", + "common/uloc_keytype.cpp", + "common/uloc_tag.cpp", + "common/ulocale.cpp", + "common/ulocbuilder.cpp", + "common/umapfile.cpp", + "common/umath.cpp", + "common/umutablecptrie.cpp", + "common/umutex.cpp", + "common/unames.cpp", + "common/unifiedcache.cpp", + "common/unifilt.cpp", + "common/unifunct.cpp", + "common/uniset.cpp", + "common/uniset_closure.cpp", + "common/uniset_props.cpp", + "common/unisetspan.cpp", + "common/unistr.cpp", + "common/unistr_case.cpp", + "common/unistr_case_locale.cpp", + "common/unistr_cnv.cpp", + "common/unistr_props.cpp", + "common/unistr_titlecase_brkiter.cpp", + "common/unorm.cpp", + "common/unormcmp.cpp", + "common/uobject.cpp", + "common/uprops.cpp", + "common/ures_cnv.cpp", + "common/uresbund.cpp", + "common/uresdata.cpp", + "common/usc_impl.cpp", + "common/uscript.cpp", + "common/uscript_props.cpp", + "common/uset.cpp", + "common/uset_props.cpp", + "common/usetiter.cpp", + "common/ushape.cpp", + "common/usprep.cpp", + "common/ustack.cpp", + "common/ustr_cnv.cpp", + "common/ustr_titlecase_brkiter.cpp", + "common/ustr_wcs.cpp", + "common/ustrcase.cpp", + "common/ustrcase_locale.cpp", + "common/ustrenum.cpp", + "common/ustrfmt.cpp", + "common/ustring.cpp", + "common/ustrtrns.cpp", + "common/utext.cpp", + "common/utf_impl.cpp", + "common/util.cpp", + "common/util_props.cpp", + "common/utrace.cpp", + "common/utrie.cpp", + "common/utrie2.cpp", + "common/utrie2_builder.cpp", + "common/utrie_swap.cpp", + "common/uts46.cpp", + "common/utypes.cpp", + "common/uvector.cpp", + "common/uvectr32.cpp", + "common/uvectr64.cpp", + "common/wintz.cpp", +] + +ICU_COMMON_HEADERS = [ + "common/bmpset.h", + "common/brkeng.h", + "common/bytesinkutil.h", + "common/capi_helper.h", + "common/charstr.h", + "common/charstrmap.h", + "common/cmemory.h", + "common/cpputils.h", + "common/cstr.h", + "common/cstring.h", + "common/cwchar.h", + "common/dictbe.h", + "common/dictionarydata.h", + "common/emojiprops.h", + "common/hash.h", + "common/icuplugimp.h", + "common/localefallback_data.h", + "common/localeprioritylist.h", + "common/localsvc.h", + "common/locbased.h", + "common/locdistance.h", + "common/loclikelysubtags.h", + "common/locmap.h", + "common/locutil.h", + "common/lsr.h", + "common/lstmbe.h", + "common/messageimpl.h", + "common/mlbe.h", + "common/msvcres.h", + "common/mutex.h", + "common/norm2_nfc_data.h", + "common/norm2allmodes.h", + "common/normalizer2impl.h", + "common/patternprops.h", + "common/pluralmap.h", + "common/propname.h", + "common/propname_data.h", + "common/propsvec.h", + "common/punycode.h", + "common/putilimp.h", + "common/rbbi_cache.h", + "common/rbbidata.h", + "common/rbbinode.h", + "common/rbbirb.h", + "common/rbbirpt.h", + "common/rbbiscan.h", + "common/rbbisetb.h", + "common/rbbitblb.h", + "common/resource.h", + "common/restrace.h", + "common/ruleiter.h", + "common/serv.h", + "common/servloc.h", + "common/servnotf.h", + "common/sharedobject.h", + "common/sprpimpl.h", + "common/static_unicode_sets.h", + "common/uarrsort.h", + "common/uassert.h", + "common/ubidi_props.h", + "common/ubidi_props_data.h", + "common/ubidiimp.h", + "common/ubrkimpl.h", + "common/ucase.h", + "common/ucase_props_data.h", + "common/ucasemap_imp.h", + "common/uchar_props_data.h", + "common/ucln.h", + "common/ucln_cmn.h", + "common/ucln_imp.h", + "common/ucmndata.h", + "common/ucnv_bld.h", + "common/ucnv_cnv.h", + "common/ucnv_ext.h", + "common/ucnv_imp.h", + "common/ucnv_io.h", + "common/ucnvmbcs.h", + "common/ucol_data.h", + "common/ucol_swp.h", + "common/ucptrie_impl.h", + "common/ucurrimp.h", + "common/udatamem.h", + "common/udataswp.h", + "common/uelement.h", + "common/uenumimp.h", + "common/uhash.h", + "common/uinvchar.h", + "common/ulayout_props.h", + "common/ulist.h", + "common/ulocimp.h", + "common/umapfile.h", + "common/umutex.h", + "common/unicode/appendable.h", + "common/unicode/brkiter.h", + "common/unicode/bytestream.h", + "common/unicode/bytestrie.h", + "common/unicode/bytestriebuilder.h", + "common/unicode/caniter.h", + "common/unicode/casemap.h", + "common/unicode/char16ptr.h", + "common/unicode/chariter.h", + "common/unicode/dbbi.h", + "common/unicode/docmain.h", + "common/unicode/dtintrv.h", + "common/unicode/edits.h", + "common/unicode/enumset.h", + "common/unicode/errorcode.h", + "common/unicode/filteredbrk.h", + "common/unicode/icudataver.h", + "common/unicode/icuplug.h", + "common/unicode/idna.h", + "common/unicode/localebuilder.h", + "common/unicode/localematcher.h", + "common/unicode/localpointer.h", + "common/unicode/locdspnm.h", + "common/unicode/locid.h", + "common/unicode/messagepattern.h", + "common/unicode/normalizer2.h", + "common/unicode/normlzr.h", + "common/unicode/parseerr.h", + "common/unicode/parsepos.h", + "common/unicode/platform.h", + "common/unicode/ptypes.h", + "common/unicode/putil.h", + "common/unicode/rbbi.h", + "common/unicode/rep.h", + "common/unicode/resbund.h", + "common/unicode/schriter.h", + "common/unicode/simpleformatter.h", + "common/unicode/std_string.h", + "common/unicode/strenum.h", + "common/unicode/stringoptions.h", + "common/unicode/stringpiece.h", + "common/unicode/stringtriebuilder.h", + "common/unicode/symtable.h", + "common/unicode/ubidi.h", + "common/unicode/ubiditransform.h", + "common/unicode/ubrk.h", + "common/unicode/ucasemap.h", + "common/unicode/ucat.h", + "common/unicode/uchar.h", + "common/unicode/ucharstrie.h", + "common/unicode/ucharstriebuilder.h", + "common/unicode/uchriter.h", + "common/unicode/uclean.h", + "common/unicode/ucnv.h", + "common/unicode/ucnv_cb.h", + "common/unicode/ucnv_err.h", + "common/unicode/ucnvsel.h", + "common/unicode/uconfig.h", + "common/unicode/ucpmap.h", + "common/unicode/ucptrie.h", + "common/unicode/ucurr.h", + "common/unicode/udata.h", + "common/unicode/udisplaycontext.h", + "common/unicode/uenum.h", + "common/unicode/uidna.h", + "common/unicode/uiter.h", + "common/unicode/uldnames.h", + "common/unicode/uloc.h", + "common/unicode/ulocale.h", + "common/unicode/ulocbuilder.h", + "common/unicode/umachine.h", + "common/unicode/umisc.h", + "common/unicode/umutablecptrie.h", + "common/unicode/unifilt.h", + "common/unicode/unifunct.h", + "common/unicode/unimatch.h", + "common/unicode/uniset.h", + "common/unicode/unistr.h", + "common/unicode/unorm.h", + "common/unicode/unorm2.h", + "common/unicode/uobject.h", + "common/unicode/urename.h", + "common/unicode/urep.h", + "common/unicode/ures.h", + "common/unicode/uscript.h", + "common/unicode/uset.h", + "common/unicode/usetiter.h", + "common/unicode/ushape.h", + "common/unicode/usprep.h", + "common/unicode/ustring.h", + "common/unicode/ustringtrie.h", + "common/unicode/utext.h", + "common/unicode/utf.h", + "common/unicode/utf16.h", + "common/unicode/utf32.h", + "common/unicode/utf8.h", + "common/unicode/utf_old.h", + "common/unicode/utrace.h", + "common/unicode/utypes.h", + "common/unicode/uvernum.h", + "common/unicode/uversion.h", + "common/unifiedcache.h", + "common/uniquecharstr.h", + "common/unisetspan.h", + "common/unistrappender.h", + "common/unormimp.h", + "common/uposixdefs.h", + "common/uprops.h", + "common/uresdata.h", + "common/uresimp.h", + "common/ureslocs.h", + "common/usc_impl.h", + "common/uset_imp.h", + "common/ustr_cnv.h", + "common/ustr_imp.h", + "common/ustrenum.h", + "common/ustrfmt.h", + "common/util.h", + "common/utracimp.h", + "common/utrie.h", + "common/utrie2.h", + "common/utrie2_impl.h", + "common/utypeinfo.h", + "common/uvector.h", + "common/uvectr32.h", + "common/uvectr64.h", + "common/wintz.h", +] + +ICU_I18N_SOURCES = [ + "i18n/alphaindex.cpp", + "i18n/anytrans.cpp", + "i18n/astro.cpp", + "i18n/basictz.cpp", + "i18n/bocsu.cpp", + "i18n/brktrans.cpp", + "i18n/buddhcal.cpp", + "i18n/calendar.cpp", + "i18n/casetrn.cpp", + "i18n/cecal.cpp", + "i18n/chnsecal.cpp", + "i18n/choicfmt.cpp", + "i18n/coleitr.cpp", + "i18n/coll.cpp", + "i18n/collation.cpp", + "i18n/collationbuilder.cpp", + "i18n/collationcompare.cpp", + "i18n/collationdata.cpp", + "i18n/collationdatabuilder.cpp", + "i18n/collationdatareader.cpp", + "i18n/collationdatawriter.cpp", + "i18n/collationfastlatin.cpp", + "i18n/collationfastlatinbuilder.cpp", + "i18n/collationfcd.cpp", + "i18n/collationiterator.cpp", + "i18n/collationkeys.cpp", + "i18n/collationroot.cpp", + "i18n/collationrootelements.cpp", + "i18n/collationruleparser.cpp", + "i18n/collationsets.cpp", + "i18n/collationsettings.cpp", + "i18n/collationtailoring.cpp", + "i18n/collationweights.cpp", + "i18n/compactdecimalformat.cpp", + "i18n/coptccal.cpp", + "i18n/cpdtrans.cpp", + "i18n/csdetect.cpp", + "i18n/csmatch.cpp", + "i18n/csr2022.cpp", + "i18n/csrecog.cpp", + "i18n/csrmbcs.cpp", + "i18n/csrsbcs.cpp", + "i18n/csrucode.cpp", + "i18n/csrutf8.cpp", + "i18n/curramt.cpp", + "i18n/currfmt.cpp", + "i18n/currpinf.cpp", + "i18n/currunit.cpp", + "i18n/dangical.cpp", + "i18n/datefmt.cpp", + "i18n/dayperiodrules.cpp", + "i18n/dcfmtsym.cpp", + "i18n/decContext.cpp", + "i18n/decNumber.cpp", + "i18n/decimfmt.cpp", + "i18n/displayoptions.cpp", + "i18n/double-conversion-bignum-dtoa.cpp", + "i18n/double-conversion-bignum.cpp", + "i18n/double-conversion-cached-powers.cpp", + "i18n/double-conversion-double-to-string.cpp", + "i18n/double-conversion-fast-dtoa.cpp", + "i18n/double-conversion-string-to-double.cpp", + "i18n/double-conversion-strtod.cpp", + "i18n/dtfmtsym.cpp", + "i18n/dtitvfmt.cpp", + "i18n/dtitvinf.cpp", + "i18n/dtptngen.cpp", + "i18n/dtrule.cpp", + "i18n/erarules.cpp", + "i18n/esctrn.cpp", + "i18n/ethpccal.cpp", + "i18n/fmtable.cpp", + "i18n/fmtable_cnv.cpp", + "i18n/format.cpp", + "i18n/formatted_string_builder.cpp", + "i18n/formattedval_iterimpl.cpp", + "i18n/formattedval_sbimpl.cpp", + "i18n/formattedvalue.cpp", + "i18n/fphdlimp.cpp", + "i18n/fpositer.cpp", + "i18n/funcrepl.cpp", + "i18n/gender.cpp", + "i18n/gregocal.cpp", + "i18n/gregoimp.cpp", + "i18n/hebrwcal.cpp", + "i18n/indiancal.cpp", + "i18n/inputext.cpp", + "i18n/islamcal.cpp", + "i18n/iso8601cal.cpp", + "i18n/japancal.cpp", + "i18n/listformatter.cpp", + "i18n/measfmt.cpp", + "i18n/measunit.cpp", + "i18n/measunit_extra.cpp", + "i18n/measure.cpp", + "i18n/msgfmt.cpp", + "i18n/messageformat2.cpp", + "i18n/messageformat2_arguments.cpp", + "i18n/messageformat2_checker.cpp", + "i18n/messageformat2_data_model.cpp", + "i18n/messageformat2_errors.cpp", + "i18n/messageformat2_evaluation.cpp", + "i18n/messageformat2_formatter.cpp", + "i18n/messageformat2_formattable.cpp", + "i18n/messageformat2_function_registry.cpp", + "i18n/messageformat2_parser.cpp", + "i18n/messageformat2_serializer.cpp", + "i18n/name2uni.cpp", + "i18n/nfrs.cpp", + "i18n/nfrule.cpp", + "i18n/nfsubs.cpp", + "i18n/nortrans.cpp", + "i18n/nultrans.cpp", + "i18n/number_affixutils.cpp", + "i18n/number_asformat.cpp", + "i18n/number_capi.cpp", + "i18n/number_compact.cpp", + "i18n/number_currencysymbols.cpp", + "i18n/number_decimalquantity.cpp", + "i18n/number_decimfmtprops.cpp", + "i18n/number_fluent.cpp", + "i18n/number_formatimpl.cpp", + "i18n/number_grouping.cpp", + "i18n/number_integerwidth.cpp", + "i18n/number_longnames.cpp", + "i18n/number_mapper.cpp", + "i18n/number_modifiers.cpp", + "i18n/number_multiplier.cpp", + "i18n/number_notation.cpp", + "i18n/number_output.cpp", + "i18n/number_padding.cpp", + "i18n/number_patternmodifier.cpp", + "i18n/number_patternstring.cpp", + "i18n/number_rounding.cpp", + "i18n/number_scientific.cpp", + "i18n/number_simple.cpp", + "i18n/number_skeletons.cpp", + "i18n/number_symbolswrapper.cpp", + "i18n/number_usageprefs.cpp", + "i18n/number_utils.cpp", + "i18n/numfmt.cpp", + "i18n/numparse_affixes.cpp", + "i18n/numparse_compositions.cpp", + "i18n/numparse_currency.cpp", + "i18n/numparse_decimal.cpp", + "i18n/numparse_impl.cpp", + "i18n/numparse_parsednumber.cpp", + "i18n/numparse_scientific.cpp", + "i18n/numparse_symbols.cpp", + "i18n/numparse_validators.cpp", + "i18n/numrange_capi.cpp", + "i18n/numrange_fluent.cpp", + "i18n/numrange_impl.cpp", + "i18n/numsys.cpp", + "i18n/olsontz.cpp", + "i18n/persncal.cpp", + "i18n/pluralranges.cpp", + "i18n/plurfmt.cpp", + "i18n/plurrule.cpp", + "i18n/quant.cpp", + "i18n/quantityformatter.cpp", + "i18n/rbnf.cpp", + "i18n/rbt.cpp", + "i18n/rbt_data.cpp", + "i18n/rbt_pars.cpp", + "i18n/rbt_rule.cpp", + "i18n/rbt_set.cpp", + "i18n/rbtz.cpp", + "i18n/regexcmp.cpp", + "i18n/regeximp.cpp", + "i18n/regexst.cpp", + "i18n/regextxt.cpp", + "i18n/region.cpp", + "i18n/reldatefmt.cpp", + "i18n/reldtfmt.cpp", + "i18n/rematch.cpp", + "i18n/remtrans.cpp", + "i18n/repattrn.cpp", + "i18n/rulebasedcollator.cpp", + "i18n/scientificnumberformatter.cpp", + "i18n/scriptset.cpp", + "i18n/search.cpp", + "i18n/selfmt.cpp", + "i18n/sharedbreakiterator.cpp", + "i18n/simpletz.cpp", + "i18n/smpdtfmt.cpp", + "i18n/smpdtfst.cpp", + "i18n/sortkey.cpp", + "i18n/standardplural.cpp", + "i18n/string_segment.cpp", + "i18n/strmatch.cpp", + "i18n/strrepl.cpp", + "i18n/stsearch.cpp", + "i18n/taiwncal.cpp", + "i18n/timezone.cpp", + "i18n/titletrn.cpp", + "i18n/tmunit.cpp", + "i18n/tmutamt.cpp", + "i18n/tmutfmt.cpp", + "i18n/tolowtrn.cpp", + "i18n/toupptrn.cpp", + "i18n/translit.cpp", + "i18n/transreg.cpp", + "i18n/tridpars.cpp", + "i18n/tzfmt.cpp", + "i18n/tzgnames.cpp", + "i18n/tznames.cpp", + "i18n/tznames_impl.cpp", + "i18n/tzrule.cpp", + "i18n/tztrans.cpp", + "i18n/ucal.cpp", + "i18n/ucln_in.cpp", + "i18n/ucol.cpp", + "i18n/ucol_res.cpp", + "i18n/ucol_sit.cpp", + "i18n/ucoleitr.cpp", + "i18n/ucsdet.cpp", + "i18n/udat.cpp", + "i18n/udateintervalformat.cpp", + "i18n/udatpg.cpp", + "i18n/ufieldpositer.cpp", + "i18n/uitercollationiterator.cpp", + "i18n/ulistformatter.cpp", + "i18n/ulocdata.cpp", + "i18n/umsg.cpp", + "i18n/unesctrn.cpp", + "i18n/uni2name.cpp", + "i18n/units_data.cpp", + "i18n/units_complexconverter.cpp", + "i18n/units_converter.cpp", + "i18n/units_router.cpp", + "i18n/unum.cpp", + "i18n/unumsys.cpp", + "i18n/upluralrules.cpp", + "i18n/uregex.cpp", + "i18n/uregexc.cpp", + "i18n/uregion.cpp", + "i18n/usearch.cpp", + "i18n/uspoof.cpp", + "i18n/uspoof_build.cpp", + "i18n/uspoof_conf.cpp", + "i18n/uspoof_impl.cpp", + "i18n/utf16collationiterator.cpp", + "i18n/utf8collationiterator.cpp", + "i18n/utmscale.cpp", + "i18n/utrans.cpp", + "i18n/vtzone.cpp", + "i18n/vzone.cpp", + "i18n/windtfmt.cpp", + "i18n/winnmfmt.cpp", + "i18n/wintzimpl.cpp", + "i18n/zonemeta.cpp", + "i18n/zrule.cpp", + "i18n/ztrans.cpp", +] + +ICU_I18N_HEADERS = [ + "i18n/anytrans.h", + "i18n/astro.h", + "i18n/bocsu.h", + "i18n/brktrans.h", + "i18n/buddhcal.h", + "i18n/casetrn.h", + "i18n/cecal.h", + "i18n/chnsecal.h", + "i18n/collation.h", + "i18n/collationbuilder.h", + "i18n/collationcompare.h", + "i18n/collationdata.h", + "i18n/collationdatabuilder.h", + "i18n/collationdatareader.h", + "i18n/collationdatawriter.h", + "i18n/collationfastlatin.h", + "i18n/collationfastlatinbuilder.h", + "i18n/collationfcd.h", + "i18n/collationiterator.h", + "i18n/collationkeys.h", + "i18n/collationroot.h", + "i18n/collationrootelements.h", + "i18n/collationruleparser.h", + "i18n/collationsets.h", + "i18n/collationsettings.h", + "i18n/collationtailoring.h", + "i18n/collationweights.h", + "i18n/collunsafe.h", + "i18n/coptccal.h", + "i18n/cpdtrans.h", + "i18n/csdetect.h", + "i18n/csmatch.h", + "i18n/csr2022.h", + "i18n/csrecog.h", + "i18n/csrmbcs.h", + "i18n/csrsbcs.h", + "i18n/csrucode.h", + "i18n/csrutf8.h", + "i18n/currfmt.h", + "i18n/dangical.h", + "i18n/dayperiodrules.h", + "i18n/decContext.h", + "i18n/decNumber.h", + "i18n/decNumberLocal.h", + "i18n/double-conversion-bignum-dtoa.h", + "i18n/double-conversion-bignum.h", + "i18n/double-conversion-cached-powers.h", + "i18n/double-conversion-diy-fp.h", + "i18n/double-conversion-double-to-string.h", + "i18n/double-conversion-fast-dtoa.h", + "i18n/double-conversion-ieee.h", + "i18n/double-conversion-string-to-double.h", + "i18n/double-conversion-strtod.h", + "i18n/double-conversion-utils.h", + "i18n/double-conversion.h", + "i18n/dt_impl.h", + "i18n/dtitv_impl.h", + "i18n/dtptngen_impl.h", + "i18n/erarules.h", + "i18n/esctrn.h", + "i18n/ethpccal.h", + "i18n/fmtableimp.h", + "i18n/formatted_string_builder.h", + "i18n/formattedval_impl.h", + "i18n/fphdlimp.h", + "i18n/funcrepl.h", + "i18n/gregoimp.h", + "i18n/hebrwcal.h", + "i18n/indiancal.h", + "i18n/inputext.h", + "i18n/islamcal.h", + "i18n/iso8601cal.h", + "i18n/japancal.h", + "i18n/measunit_impl.h", + "i18n/messageformat2_allocation.h", + "i18n/messageformat2_checker.h", + "i18n/messageformat2_errors.h", + "i18n/messageformat2_evaluation.h", + "i18n/messageformat2_function_registry_internal.h", + "i18n/messageformat2_macros.h", + "i18n/messageformat2_parser.h", + "i18n/messageformat2_serializer.h", + "i18n/msgfmt_impl.h", + "i18n/name2uni.h", + "i18n/nfrlist.h", + "i18n/nfrs.h", + "i18n/nfrule.h", + "i18n/nfsubs.h", + "i18n/nortrans.h", + "i18n/nultrans.h", + "i18n/number_affixutils.h", + "i18n/number_asformat.h", + "i18n/number_compact.h", + "i18n/number_currencysymbols.h", + "i18n/number_decimalquantity.h", + "i18n/number_decimfmtprops.h", + "i18n/number_decnum.h", + "i18n/number_formatimpl.h", + "i18n/number_longnames.h", + "i18n/number_mapper.h", + "i18n/number_microprops.h", + "i18n/number_modifiers.h", + "i18n/number_multiplier.h", + "i18n/number_patternmodifier.h", + "i18n/number_patternstring.h", + "i18n/number_roundingutils.h", + "i18n/number_scientific.h", + "i18n/number_skeletons.h", + "i18n/number_types.h", + "i18n/number_usageprefs.h", + "i18n/number_utils.h", + "i18n/number_utypes.h", + "i18n/numparse_affixes.h", + "i18n/numparse_compositions.h", + "i18n/numparse_currency.h", + "i18n/numparse_decimal.h", + "i18n/numparse_impl.h", + "i18n/numparse_scientific.h", + "i18n/numparse_symbols.h", + "i18n/numparse_types.h", + "i18n/numparse_utils.h", + "i18n/numparse_validators.h", + "i18n/numrange_impl.h", + "i18n/numsys_impl.h", + "i18n/olsontz.h", + "i18n/persncal.h", + "i18n/pluralranges.h", + "i18n/plurrule_impl.h", + "i18n/quant.h", + "i18n/quantityformatter.h", + "i18n/rbt.h", + "i18n/rbt_data.h", + "i18n/rbt_pars.h", + "i18n/rbt_rule.h", + "i18n/rbt_set.h", + "i18n/regexcmp.h", + "i18n/regexcst.h", + "i18n/regeximp.h", + "i18n/regexst.h", + "i18n/regextxt.h", + "i18n/region_impl.h", + "i18n/reldtfmt.h", + "i18n/remtrans.h", + "i18n/scriptset.h", + "i18n/selfmtimpl.h", + "i18n/sharedbreakiterator.h", + "i18n/sharedcalendar.h", + "i18n/shareddateformatsymbols.h", + "i18n/sharednumberformat.h", + "i18n/sharedpluralrules.h", + "i18n/smpdtfst.h", + "i18n/standardplural.h", + "i18n/string_segment.h", + "i18n/strmatch.h", + "i18n/strrepl.h", + "i18n/taiwncal.h", + "i18n/titletrn.h", + "i18n/tolowtrn.h", + "i18n/toupptrn.h", + "i18n/transreg.h", + "i18n/tridpars.h", + "i18n/tzgnames.h", + "i18n/tznames_impl.h", + "i18n/ucln_in.h", + "i18n/ucol_imp.h", + "i18n/uitercollationiterator.h", + "i18n/umsg_imp.h", + "i18n/unesctrn.h", + "i18n/uni2name.h", + "i18n/unicode/alphaindex.h", + "i18n/unicode/basictz.h", + "i18n/unicode/calendar.h", + "i18n/unicode/choicfmt.h", + "i18n/unicode/coleitr.h", + "i18n/unicode/coll.h", + "i18n/unicode/compactdecimalformat.h", + "i18n/unicode/curramt.h", + "i18n/unicode/currpinf.h", + "i18n/unicode/currunit.h", + "i18n/unicode/datefmt.h", + "i18n/unicode/dcfmtsym.h", + "i18n/unicode/decimfmt.h", + "i18n/unicode/displayoptions.h", + "i18n/unicode/dtfmtsym.h", + "i18n/unicode/dtitvfmt.h", + "i18n/unicode/dtitvinf.h", + "i18n/unicode/dtptngen.h", + "i18n/unicode/dtrule.h", + "i18n/unicode/fieldpos.h", + "i18n/unicode/fmtable.h", + "i18n/unicode/format.h", + "i18n/unicode/formattednumber.h", + "i18n/unicode/formattedvalue.h", + "i18n/unicode/fpositer.h", + "i18n/unicode/gender.h", + "i18n/unicode/gregocal.h", + "i18n/unicode/listformatter.h", + "i18n/unicode/measfmt.h", + "i18n/unicode/measunit.h", + "i18n/unicode/measure.h", + "i18n/unicode/messageformat2.h", + "i18n/unicode/messageformat2_arguments.h", + "i18n/unicode/messageformat2_data_model.h", + "i18n/unicode/messageformat2_data_model_names.h", + "i18n/unicode/messageformat2_formattable.h", + "i18n/unicode/messageformat2_function_registry.h", + "i18n/unicode/msgfmt.h", + "i18n/unicode/nounit.h", + "i18n/unicode/numberformatter.h", + "i18n/unicode/numberrangeformatter.h", + "i18n/unicode/numfmt.h", + "i18n/unicode/numsys.h", + "i18n/unicode/plurfmt.h", + "i18n/unicode/plurrule.h", + "i18n/unicode/rbnf.h", + "i18n/unicode/rbtz.h", + "i18n/unicode/regex.h", + "i18n/unicode/region.h", + "i18n/unicode/reldatefmt.h", + "i18n/unicode/scientificnumberformatter.h", + "i18n/unicode/search.h", + "i18n/unicode/selfmt.h", + "i18n/unicode/simplenumberformatter.h", + "i18n/unicode/simpletz.h", + "i18n/unicode/smpdtfmt.h", + "i18n/unicode/sortkey.h", + "i18n/unicode/stsearch.h", + "i18n/unicode/tblcoll.h", + "i18n/unicode/timezone.h", + "i18n/unicode/tmunit.h", + "i18n/unicode/tmutamt.h", + "i18n/unicode/tmutfmt.h", + "i18n/unicode/translit.h", + "i18n/unicode/tzfmt.h", + "i18n/unicode/tznames.h", + "i18n/unicode/tzrule.h", + "i18n/unicode/tztrans.h", + "i18n/unicode/ucal.h", + "i18n/unicode/ucol.h", + "i18n/unicode/ucoleitr.h", + "i18n/unicode/ucsdet.h", + "i18n/unicode/udat.h", + "i18n/unicode/udateintervalformat.h", + "i18n/unicode/udatpg.h", + "i18n/unicode/udisplayoptions.h", + "i18n/unicode/ufieldpositer.h", + "i18n/unicode/uformattable.h", + "i18n/unicode/uformattednumber.h", + "i18n/unicode/uformattedvalue.h", + "i18n/unicode/ugender.h", + "i18n/unicode/ulistformatter.h", + "i18n/unicode/ulocdata.h", + "i18n/unicode/umsg.h", + "i18n/unicode/unirepl.h", + "i18n/unicode/unum.h", + "i18n/unicode/unumberformatter.h", + "i18n/unicode/unumberoptions.h", + "i18n/unicode/unumberrangeformatter.h", + "i18n/unicode/unumsys.h", + "i18n/unicode/upluralrules.h", + "i18n/unicode/uregex.h", + "i18n/unicode/uregion.h", + "i18n/unicode/ureldatefmt.h", + "i18n/unicode/usearch.h", + "i18n/unicode/usimplenumberformatter.h", + "i18n/unicode/uspoof.h", + "i18n/unicode/utmscale.h", + "i18n/unicode/utrans.h", + "i18n/unicode/vtzone.h", + "i18n/units_complexconverter.h", + "i18n/units_converter.h", + "i18n/units_data.h", + "i18n/units_router.h", + "i18n/uspoof_conf.h", + "i18n/uspoof_impl.h", + "i18n/usrchimp.h", + "i18n/utf16collationiterator.h", + "i18n/utf8collationiterator.h", + "i18n/vzone.h", + "i18n/windtfmt.h", + "i18n/winnmfmt.h", + "i18n/wintzimpl.h", + "i18n/zonemeta.h", + "i18n/zrule.h", + "i18n/ztrans.h", +] + +ICU_STUBDATA_SOURCES = [ + "stubdata/stubdata.cpp", +] + +ICU_STUBDATA_HEADERS = [ + "stubdata/stubdata.h", +] diff --git a/build_defs/native/icu_windows.bzl b/build_defs/native/icu_windows.bzl new file mode 100644 index 000000000..2e3c771e5 --- /dev/null +++ b/build_defs/native/icu_windows.bzl @@ -0,0 +1,99 @@ +"""Direct Windows ICU shared construction with the canonical full data object.""" + +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_import", "cc_library", "cc_test") +load("@oliphaunt//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") + +_WINDOWS = ["@platforms//os:windows", "@platforms//cpu:x86_64"] +_COPTS = ["/std:c++17", "/utf-8"] +_DEFINES = ["_CRT_SECURE_NO_DEPRECATE", "_HAS_EXCEPTIONS=0", "U_ATTRIBUTE_DEPRECATED="] + +def _data_object_impl(ctx): + output = ctx.actions.declare_file(ctx.label.name + ".obj") + bun_file_action( + ctx, + entry_point = ctx.file._generator, + source_files = [ctx.file._generator], + arguments = [ctx.file.data.path, ctx.file.version.path, ctx.file.types.path, "amd64", output.path], + inputs = [ctx.file._generator, ctx.file.data, ctx.file.version, ctx.file.types], + outputs = [output], + mnemonic = "IcuDataObject", + progress_message = "Embed canonical ICU data %{label}", + ) + return [DefaultInfo(files = depset([output]))] + +_data_object = rule( + implementation = _data_object_impl, + attrs = { + "data": attr.label(default = "@icu_data//:data", allow_single_file = True), + "version": attr.label(mandatory = True, allow_single_file = True), + "types": attr.label(mandatory = True, allow_single_file = True), + "_generator": attr.label(default = Label("@oliphaunt//build_defs/native:icu-data-object.mts"), allow_single_file = True), + }, + toolchains = BUN_SOURCE_TOOLCHAINS, +) + +def _shared(name, srcs = [], deps = [], import_deps = [], linkopts = [], features = []): + cc_binary( + name = name, + srcs = srcs, + deps = deps, + copts = _COPTS, + linkopts = ["/INCREMENTAL:NO"] + linkopts, + linkshared = True, + linkstatic = True, + # ICU's public declarations and the data object's directive explicitly + # export the ABI; avoid an unrelated export-all symbol scan. + features = ["no_windows_export_all_symbols"] + features, + target_compatible_with = _WINDOWS, + ) + interface = name + "_interface" + native.filegroup(name = interface, srcs = [":" + name], output_group = "interface_library", target_compatible_with = _WINDOWS) + cc_import( + name = name + "_import", + shared_library = ":" + name, + interface_library = ":" + interface, + # Forward runtime/import dependencies, never implementation archives. + deps = import_deps, + target_compatible_with = _WINDOWS, + ) + +def icu_windows_targets(common_sources, i18n_sources): + """Declare ICU76.1's established Windows carrier DLL names, fenced by pin.""" + _data_object(name = "windows_data_object", version = "common/unicode/uvernum.h", types = "common/unicode/utypes.h", target_compatible_with = _WINDOWS) + # Upstream pkgdata uses /NOENTRY for its data-only DLL: no CRT initializer + # or bootstrap stub is part of the Unicode resource carrier. + # Its raw COFF data object is independent of C++ compilation/debug modes. + # Those mode features imply generate_pdb_file; disable the owning modes + # together with the PDB feature for this resource-only link. + _shared(name = "icudt76.dll", srcs = [":windows_data_object"], linkopts = ["/NOENTRY", "/MANIFEST:NO"], features = ["-fastbuild", "-dbg", "-generate_pdb_file"]) + + for role, sources, headers, dependencies, definitions, linkopts in [ + ("common", common_sources, ":common_headers", [":icudt76.dll_import"], ["U_COMMON_IMPLEMENTATION", "U_PLATFORM_USES_ONLY_WIN32_API=1"], ["kernel32.lib", "advapi32.lib"]), + ("i18n", i18n_sources, ":i18n_headers", [":icuuc76.dll_import"], ["U_I18N_IMPLEMENTATION"], ["kernel32.lib"]), + ]: + cc_library( + name = "windows_" + role + "_objects", + srcs = sources, + deps = [headers] + dependencies, + local_defines = _DEFINES + definitions, + copts = _COPTS, + alwayslink = True, + linkstatic = True, + target_compatible_with = _WINDOWS, + ) + _shared( + name = "icuuc76.dll" if role == "common" else "icuin76.dll", + deps = [":windows_" + role + "_objects"] + dependencies, + import_deps = dependencies, + linkopts = linkopts, + ) + native.filegroup(name = "windows_runtime_dlls", srcs = [":icudt76.dll", ":icuuc76.dll", ":icuin76.dll"], target_compatible_with = _WINDOWS) + cc_test( + name = "windows_icu_smoke_test", + srcs = [Label("@oliphaunt//build_defs/native:icu-windows-smoke.cc")], + deps = [":i18n"], + copts = _COPTS, + env = {"ICU_DATA": "/nonexistent-oliphaunt-icu-data"}, + target_compatible_with = _WINDOWS, + size = "small", + ) diff --git a/build_defs/native/ios-config-contract.c b/build_defs/native/ios-config-contract.c new file mode 100644 index 000000000..dd44cb94f --- /dev/null +++ b/build_defs/native/ios-config-contract.c @@ -0,0 +1,19 @@ +/* Reject a mismatched device/simulator SDK before admitting mobile PG objects. */ +#include +#include "pg_config.h" + +#if !TARGET_OS_IOS || !TARGET_CPU_ARM64 || TARGET_OS_MACCATALYST +#error "The native iOS profile requires an arm64 iOS SDK" +#endif + +#ifndef OLIPHAUNT_EXPECT_IOS_SIMULATOR +#error "The iOS configuration must declare its device/simulator role" +#endif + +#if TARGET_OS_SIMULATOR != OLIPHAUNT_EXPECT_IOS_SIMULATOR +#error "The native iOS profile selected the wrong device/simulator SDK" +#endif + +#if !defined(USE_ICU) || USE_ICU != 1 +#error "The native iOS PostgreSQL configuration requires ICU" +#endif diff --git a/build_defs/native/linux_x86_64_config.bzl b/build_defs/native/linux_x86_64_config.bzl new file mode 100644 index 000000000..b97293f9f --- /dev/null +++ b/build_defs/native/linux_x86_64_config.bzl @@ -0,0 +1,132 @@ +"""Explicit PG configuration for the Linux x86_64 ICU-enabled port probe. + +This is a development profile, not release parity: OpenSSL/compression and +production compiler/sysroot qualification are separate cutover gates. Constants +are from PostgreSQL18.4 Linux LP64 ABI; use portable CRC to avoid ambient CPU +features. Version fields are derived from the canonical source pin. +""" + +LINUX_X86_64_CONFIG = { + "USE_ICU": "1", + 'ALIGNOF_DOUBLE': '8', + 'ALIGNOF_INT': '4', + 'ALIGNOF_INT64_T': '8', + 'ALIGNOF_LONG': '8', + 'ALIGNOF_PG_INT128_TYPE': '16', + 'ALIGNOF_SHORT': '2', + 'BLCKSZ': '8192', + 'CONFIGURE_ARGS': '"Bazel linux-x86_64 ICU-enabled development slice"', + 'DEF_PGPORT': '5432', + 'DEF_PGPORT_STR': '"5432"', + 'DLSUFFIX': '".so"', + 'HAVE_BACKTRACE_SYMBOLS': '1', + 'HAVE_COMPUTED_GOTO': '1', + 'HAVE_COPY_FILE_RANGE': '1', + 'HAVE_DECL_FDATASYNC': '1', + 'HAVE_DECL_F_FULLFSYNC': '0', + 'HAVE_DECL_MEMSET_S': '0', + 'HAVE_DECL_POSIX_FADVISE': '1', + 'HAVE_DECL_PREADV': '1', + 'HAVE_DECL_PWRITEV': '1', + 'HAVE_DECL_STRCHRNUL': '1', + 'HAVE_DECL_STRLCAT': '1', + 'HAVE_DECL_STRLCPY': '1', + 'HAVE_DECL_STRNLEN': '1', + 'HAVE_DECL_STRSEP': '1', + 'HAVE_DECL_TIMINGSAFE_BCMP': '0', + 'HAVE_EXECINFO_H': '1', + 'HAVE_EXPLICIT_BZERO': '1', + 'HAVE_FSEEKO': '1', + 'HAVE_GCC__ATOMIC_INT32_CAS': '1', + 'HAVE_GCC__ATOMIC_INT64_CAS': '1', + 'HAVE_GCC__SYNC_CHAR_TAS': '1', + 'HAVE_GCC__SYNC_INT32_CAS': '1', + 'HAVE_GCC__SYNC_INT32_TAS': '1', + 'HAVE_GCC__SYNC_INT64_CAS': '1', + 'HAVE_GETAUXVAL': '1', + 'HAVE_GETIFADDRS': '1', + 'HAVE_GETOPT': '1', + 'HAVE_GETOPT_H': '1', + 'HAVE_GETOPT_LONG': '1', + 'HAVE_IFADDRS_H': '1', + 'HAVE_INET_ATON': '1', + 'HAVE_INET_PTON': '1', + 'HAVE_INTTYPES_H': '1', + 'HAVE_INT_OPTERR': '1', + 'HAVE_INT_TIMEZONE': '1', + 'HAVE_LIBM': '1', + 'HAVE_MEMORY_H': '1', + 'HAVE_MKDTEMP': '1', + 'HAVE_POSIX_FADVISE': '1', + 'HAVE_POSIX_FALLOCATE': '1', + 'HAVE_PPOLL': '1', + 'HAVE_PTHREAD': '1', + 'HAVE_PTHREAD_BARRIER_WAIT': '1', + 'HAVE_PTHREAD_PRIO_INHERIT': '1', + 'HAVE_SOCKLEN_T': '1', + 'HAVE_STDINT_H': '1', + 'HAVE_STDLIB_H': '1', + 'HAVE_STRERROR_R': '1', + 'HAVE_STRINGS_H': '1', + 'HAVE_STRING_H': '1', + 'HAVE_STRLCAT': '1', + 'HAVE_STRLCPY': '1', + 'HAVE_STRNLEN': '1', + 'HAVE_STRSEP': '1', + 'HAVE_STRSIGNAL': '1', + 'HAVE_STRUCT_OPTION': '1', + 'HAVE_STRUCT_TM_TM_ZONE': '1', + 'HAVE_SYNCFS': '1', + 'HAVE_SYNC_FILE_RANGE': '1', + 'HAVE_SYSLOG': '1', + 'HAVE_SYS_EPOLL_H': '1', + 'HAVE_SYS_PERSONALITY_H': '1', + 'HAVE_SYS_PRCTL_H': '1', + 'HAVE_SYS_SIGNALFD_H': '1', + 'HAVE_SYS_STAT_H': '1', + 'HAVE_SYS_TYPES_H': '1', + 'HAVE_TERMIOS_H': '1', + 'HAVE_TYPEOF': '1', + 'HAVE_UNISTD_H': '1', + 'HAVE_USELOCALE': '1', + 'HAVE_VISIBILITY_ATTRIBUTE': '1', + 'HAVE_X86_64_POPCNTQ': '1', + 'HAVE_XSAVE_INTRINSICS': '1', + 'HAVE__BUILTIN_BSWAP16': '1', + 'HAVE__BUILTIN_BSWAP32': '1', + 'HAVE__BUILTIN_BSWAP64': '1', + 'HAVE__BUILTIN_CLZ': '1', + 'HAVE__BUILTIN_CONSTANT_P': '1', + 'HAVE__BUILTIN_CTZ': '1', + 'HAVE__BUILTIN_FRAME_ADDRESS': '1', + 'HAVE__BUILTIN_OP_OVERFLOW': '1', + 'HAVE__BUILTIN_POPCOUNT': '1', + 'HAVE__BUILTIN_TYPES_COMPATIBLE_P': '1', + 'HAVE__BUILTIN_UNREACHABLE': '1', + 'HAVE__GET_CPUID': '1', + 'HAVE__GET_CPUID_COUNT': '1', + 'HAVE__STATIC_ASSERT': '1', + 'MAXIMUM_ALIGNOF': '8', + 'MEMSET_LOOP_LIMIT': '1024', + 'PACKAGE_BUGREPORT': '"pgsql-bugs@lists.postgresql.org"', + 'PACKAGE_NAME': '"PostgreSQL"', + 'PACKAGE_TARNAME': '"postgresql"', + 'PACKAGE_URL': '"https://www.postgresql.org/"', + 'PG_CXX_PRINTF_ATTRIBUTE': 'gnu_printf', + 'PG_C_PRINTF_ATTRIBUTE': 'gnu_printf', + 'PG_INT128_TYPE': '__int128', + 'PG_KRB_SRVNAM': '"postgres"', + 'RELSEG_SIZE': '131072', + 'SIZEOF_LONG': '8', + 'SIZEOF_LONG_LONG': '8', + 'SIZEOF_OFF_T': '8', + 'SIZEOF_SIZE_T': '8', + 'SIZEOF_VOID_P': '8', + 'STDC_HEADERS': '1', + 'USE_SLICING_BY_8_CRC32C': '1', + 'USE_SYSV_SHARED_MEMORY': '1', + 'USE_UNNAMED_POSIX_SEMAPHORES': '1', + 'XLOG_BLCKSZ': '8192', + 'pg_restrict': '__restrict', + 'restrict': '__restrict', +} diff --git a/build_defs/native/mobile-profile-test.bzl b/build_defs/native/mobile-profile-test.bzl new file mode 100644 index 000000000..c1426ede6 --- /dev/null +++ b/build_defs/native/mobile-profile-test.bzl @@ -0,0 +1,85 @@ +"""Configured selector and builtin link regressions; these do not execute binaries.""" + +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") +load(":platform_config.bzl", "NATIVE_BACKEND_PORT_SOURCES", "NATIVE_BUILTIN_SNOWBALL", "NATIVE_C_COMPATIBLE", "NATIVE_COMPATIBLE", "NATIVE_CONFIGURATION", "NATIVE_CONFIGURATION_ADMISSION", "NATIVE_ELF_C_COMPATIBLE", "NATIVE_EMBEDDED_DEFINES", "NATIVE_HEADER_DEFINES", "NATIVE_INCLUDE_DIRECTORIES", "NATIVE_LINKOPTS") + +_VALUES = { + "ports": NATIVE_BACKEND_PORT_SOURCES, + "snowball": NATIVE_BUILTIN_SNOWBALL, + "c_compatible": NATIVE_C_COMPATIBLE, + "desktop_compatible": NATIVE_COMPATIBLE, + "configuration": NATIVE_CONFIGURATION, + "admission": NATIVE_CONFIGURATION_ADMISSION, + "elf_compatible": NATIVE_ELF_C_COMPATIBLE, + "embedded_defines": NATIVE_EMBEDDED_DEFINES, + "header_defines": NATIVE_HEADER_DEFINES, + "includes": NATIVE_INCLUDE_DIRECTORIES, + "linkopts": NATIVE_LINKOPTS, +} +_ProfileInfo = provider(fields = ["values"]) + +def _profile_impl(ctx): + return [_ProfileInfo(values = {name: getattr(ctx.attr, name) for name in _VALUES})] + +_profile = rule(implementation = _profile_impl, attrs = {name: attr.string_list() for name in _VALUES}) + +def _ios_profile_test(ctx): + env = analysistest.begin(ctx) + values = analysistest.target_under_test(env)[_ProfileInfo].values + asserts.equals(env, [], values["c_compatible"]) + asserts.equals(env, ["@platforms//:incompatible"], values["desktop_compatible"]) + asserts.equals(env, ["@platforms//:incompatible"], values["elf_compatible"]) + asserts.equals(env, ["src/backend/port/oliphaunt_embedded_sema.c", "src/backend/port/oliphaunt_embedded_shmem.c"], values["ports"]) + asserts.equals(env, ["OLIPHAUNT_EMBEDDED_MOBILE_SHMEM"], values["embedded_defines"]) + asserts.equals(env, ["OLIPHAUNT_BUILTIN_DICT_SNOWBALL"], values["snowball"]) + asserts.equals(env, ["_DARWIN_C_SOURCE"], values["header_defines"]) + asserts.equals(env, [], values["linkopts"]) + asserts.equals(env, [":host_" + ctx.attr.profile + "_configuration"], values["configuration"]) + asserts.equals(env, [":host_" + ctx.attr.profile + "_admission"], values["admission"]) + asserts.equals(env, ["host_" + ctx.attr.profile + "/src/include"], values["includes"]) + return analysistest.end(env) + +_device_test = analysistest.make(_ios_profile_test, attrs = {"profile": attr.string(default = "ios")}, config_settings = {"//command_line_option:platforms": str(Label("//build_defs/host:ios_device_arm64"))}) +_simulator_test = analysistest.make(_ios_profile_test, attrs = {"profile": attr.string(default = "ios_simulator")}, config_settings = {"//command_line_option:platforms": str(Label("//build_defs/host:ios_simulator_arm64"))}) + +def _builtin_link_test_impl(ctx): + env = analysistest.begin(ctx) + wrapper = analysistest.target_under_test(env) + compilation = wrapper[CcInfo].compilation_context + defines = compilation.defines.to_list() + asserts.true(env, "OLIPHAUNT_BUILTIN_PLPGSQL" in defines) + asserts.equals(env, ctx.attr.snowball, "OLIPHAUNT_BUILTIN_DICT_SNOWBALL" in defines) + expected = { + Label("@postgres//:plpgsql_embedded"): not ctx.attr.windows, + Label("@postgres//:plpgsql_builtin_windows"): ctx.attr.windows, + Label("@postgres//:snowball_builtin"): ctx.attr.snowball, + } + inputs = wrapper[CcInfo].linking_context.linker_inputs.to_list() + for owner, needed in expected.items(): + libraries = [library for entry in inputs if entry.owner == owner for library in entry.libraries] + asserts.equals(env, needed, len(libraries) > 0, "builtin define and library must agree: " + str(owner)) + for library in libraries: + asserts.true(env, library.alwayslink, "builtin registration must survive linking: " + str(owner)) + asserts.true(env, library.static_library != None or library.pic_static_library != None, "builtin must contribute its actual archive: " + str(owner)) + asserts.false(env, any([file.basename == "pg_config.h" for file in compilation.headers.to_list()]), "private builtin headers must not escape through the public wrapper") + return analysistest.end(env) + +_BUILTIN_ATTRS = {"windows": attr.bool(default = False), "snowball": attr.bool(default = False)} +_builtin_link_test = analysistest.make(_builtin_link_test_impl, attrs = _BUILTIN_ATTRS) +_device_builtin_link_test = analysistest.make(_builtin_link_test_impl, attrs = _BUILTIN_ATTRS, config_settings = {"//command_line_option:platforms": str(Label("//build_defs/host:ios_device_arm64"))}) +_simulator_builtin_link_test = analysistest.make(_builtin_link_test_impl, attrs = _BUILTIN_ATTRS, config_settings = {"//command_line_option:platforms": str(Label("//build_defs/host:ios_simulator_arm64"))}) + +def native_mobile_profile_tests(): + _profile(name = "mobile_profile_subject", **_VALUES) + _device_test(name = "ios_device_profile_test", target_under_test = ":mobile_profile_subject") + _simulator_test(name = "ios_simulator_profile_test", target_under_test = ":mobile_profile_subject") + _builtin_link_test( + name = "runtime_builtin_link_test", + target_under_test = "//src/native/runtime:wrapper", + windows = select({":windows_x64": True, "//conditions:default": False}), + snowball = select({":android": True, ":ios": True, "//conditions:default": False}), + size = "small", + ) + for test, name in [(_device_builtin_link_test, "ios_device_builtin_link_test"), (_simulator_builtin_link_test, "ios_simulator_builtin_link_test")]: + test(name = name, target_under_test = "//src/native/runtime:wrapper", snowball = True, target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:aarch64"], size = "small") diff --git a/build_defs/native/mobile.bzl b/build_defs/native/mobile.bzl new file mode 100644 index 000000000..e3e719c26 --- /dev/null +++ b/build_defs/native/mobile.bzl @@ -0,0 +1,238 @@ +"""Native iOS archives and the public dynamic Apple framework construction.""" + +load("@oliphaunt_metadata//:metadata.bzl", "NATIVE_RUNTIME_ARTIFACTS", "PRODUCTS") +load("@oliphaunt_toolchain_metadata//:apple-platforms.bzl", "APPLE_DEPLOYMENT_TARGETS") +load("@rules_apple//apple:apple.bzl", "apple_xcframework") +load("@rules_cc//cc:cc_static_library.bzl", "cc_static_library") +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_import", "cc_library") +load("//build_defs/apple:slices.bzl", "apple_slice_filegroup", "apple_slice_groups") +load("//build_defs/foundation:bun.bzl", "BunScriptInfo", "bun_action", "bun_script_test") +load("//build_defs/native:platform_config.bzl", "NATIVE_LINKOPTS") +load("//build_defs/native/carriers:defs.bzl", "native_carrier_legal_inputs") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") +load("//build_defs/release:supplier.bzl", "shipping_suppliers") + +_MAC = ["@platforms//os:macos", "@platforms//cpu:aarch64"] +_MACOS_PROFILE = "@apple_support//platforms:macos_arm64_platform" + +def _package_platform_impl(settings, attr): + return {_MACOS_PROFILE: str(Label("//build_defs/host:apple_package_macos_arm64"))} + +_package_platform = transition(implementation = _package_platform_impl, inputs = [], outputs = [_MACOS_PROFILE]) + +def _macos_impl(settings, attr): + return {"//command_line_option:platforms": [str(Label("//build_defs/host:apple_package_macos_arm64"))]} + +def _device_impl(settings, attr): + return {"//command_line_option:platforms": [str(Label("//build_defs/host:ios_device_arm64"))]} + +def _simulator_impl(settings, attr): + return {"//command_line_option:platforms": [str(Label("//build_defs/host:ios_simulator_arm64"))]} + +_macos = transition(implementation = _macos_impl, inputs = [], outputs = ["//command_line_option:platforms"]) +_device = transition(implementation = _device_impl, inputs = [], outputs = ["//command_line_option:platforms"]) +_simulator = transition(implementation = _simulator_impl, inputs = [], outputs = ["//command_line_option:platforms"]) + +def _infoplist_impl(ctx): + output = ctx.actions.declare_file(ctx.label.name + ".plist") + ctx.actions.write(output, """ + + +CFBundleShortVersionString%s +CFBundleVersion1 + +""" % PRODUCTS["liboliphaunt-native"]["version"]) + return [DefaultInfo(files = depset([output]))] + +_infoplist = rule(implementation = _infoplist_impl) + +def _archive_impl(ctx): + archive = ctx.attr.archive[0] + return [archive[DefaultInfo], OutputGroupInfo(**apple_slice_groups([archive]))] + +_framework_archive = rule(implementation = _archive_impl, attrs = { + "archive": attr.label(mandatory = True, cfg = _package_platform), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), +}) + +def _source_map(targets, inputs): + result = {} + for target, relative in targets.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1: + fail("Apple carrier source must resolve to one declared File: " + str(target.label)) + result[relative] = files[0].path + inputs.append(files[0]) + return result + +def _release_assets_impl(ctx): + inputs = [ctx.file.intermediate, ctx.file.public_header] + payload = ctx.attr.payload[0][DefaultInfo].files.to_list() + if len(payload) != 1 or not payload[0].is_directory: + fail("Apple resources require one declared native public payload tree") + inputs += payload + headers, receipt_paths, receipt_outputs = {}, {}, {} + common = _source_map(ctx.attr.abi_headers, inputs) + for target, attribute in [ + ("macos-arm64", "macos_configuration"), + ("ios-arm64", "device_configuration"), + ("ios-arm64-simulator", "simulator_configuration"), + ]: + configuration = getattr(ctx.files, attribute) + configs = [file for file in configuration if file.basename == "pg_config.h"] + if len(configs) != 1: + fail("Apple ABI admission requires the actual single configured pg_config.h for " + target) + headers[target] = common | {"src/include/pg_config.h": configs[0].path} + inputs += configuration + receipt = ctx.actions.declare_file(ctx.label.name + "/" + target + ".properties") + receipt_paths[target] = receipt.path + receipt_outputs[target] = receipt + outputs = {name: ctx.actions.declare_file(ctx.attr.asset_names[name]) for name in ["archive", "swiftpm", "resources", "macos_resources", "checksums"]} + outputs["ios_manifest"] = ctx.actions.declare_file(ctx.label.name + "/ios.json") + tools = {"nm": ctx.file._nm.path, "otool": ctx.file._otool.path, "strip": ctx.file._strip.path, + "install_name_tool": ctx.file._install_name_tool.path, "plutil": ctx.file._plutil.path} + inputs += ctx.files._sdk_runtime + [ctx.file._nm, ctx.file._otool, ctx.file._strip, ctx.file._install_name_tool, ctx.file._plutil] + specification = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(specification, json.encode({ + "version": PRODUCTS["liboliphaunt-native"]["version"], + "intermediate": ctx.file.intermediate.path, + "payload": payload[0].path, + "publicHeader": ctx.file.public_header.path, + "headers": headers, + "receipts": receipt_paths, + "tools": tools, + "formatter": ctx.executable._formatter.path, + "notices": _source_map(ctx.attr.notices, inputs), + } | {name: file.path for name, file in outputs.items()}) + "\n") + bun_action(ctx, ctx.attr._tool, arguments = [specification.path], + inputs = inputs + [specification], tools = [ctx.attr._formatter[DefaultInfo].files_to_run], + outputs = outputs.values() + receipt_outputs.values(), execution_requirements = {"no-remote": "1"}, mnemonic = "NativeAppleRuntimeEnvelope") + groups = apple_slice_groups([ctx.attr.intermediate]) | {name: depset([file]) for name, file in outputs.items()} + for name, target in [("macos_abi", "macos-arm64"), ("ios_device_abi", "ios-arm64"), ("ios_simulator_abi", "ios-arm64-simulator")]: + groups[name] = depset([receipt_outputs[target]]) + return [DefaultInfo(files = depset(outputs.values())), OutputGroupInfo(**groups)] + +_release_assets = rule(implementation = _release_assets_impl, attrs = { + "intermediate": attr.label(mandatory = True, allow_single_file = [".zip"]), + "payload": attr.label(default = "//src/native/runtime:public_payload", cfg = _macos), + "public_header": attr.label(default = "//src/native/runtime:include/oliphaunt.h", allow_single_file = True), + "macos_configuration": attr.label(default = "@postgres//:configuration", cfg = _macos, allow_files = True), + "device_configuration": attr.label(default = "@postgres//:configuration", cfg = _device, allow_files = True), + "simulator_configuration": attr.label(default = "@postgres//:configuration", cfg = _simulator, allow_files = True), + "abi_headers": attr.label_keyed_string_dict(default = { + Label("@postgres//:src/include/pg_config_manual.h"): "src/include/pg_config_manual.h", + Label("@postgres//:src/include/catalog/catversion.h"): "src/include/catalog/catversion.h", + Label("@postgres//:src/include/catalog/pg_control.h"): "src/include/catalog/pg_control.h", + }, allow_files = True), + "notices": attr.label_keyed_string_dict(allow_files = True), + "asset_names": attr.string_dict(mandatory = True), + "_formatter": attr.label(default = "//src/native/runtime/packaging:resources", executable = True, cfg = "exec"), + "_tool": attr.label(default = "//build_defs/native/apple:framework_envelope", providers = [BunScriptInfo], cfg = "exec"), + "_nm": attr.label(default = "@native_apple_sdk//:tools/nm_files", allow_single_file = True, cfg = "exec"), + "_strip": attr.label(default = "@native_apple_sdk//:tools/strip_files", allow_single_file = True, cfg = "exec"), + "_otool": attr.label(default = "@native_apple_sdk//:tools/otool", allow_single_file = True, cfg = "exec"), + "_plutil": attr.label(default = "@native_apple_sdk//:tools/plutil", allow_single_file = True, cfg = "exec"), + "_install_name_tool": attr.label(default = "@native_apple_sdk//:tools/install_name_tool", allow_single_file = True, cfg = "exec"), + "_sdk_runtime": attr.label(default = "@native_apple_sdk//:toolchain_files", cfg = "exec"), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), +}) + +def native_apple_runtime_targets(qualification): + """Build the same dynamic device, simulator and macOS public framework.""" + _infoplist(name = "apple_framework_info") + apple_xcframework( + name = "apple_xcframework_raw", + bundle_name = "liboliphaunt", + bundle_id = "dev.oliphaunt.liboliphaunt", + deps = [":wrapper", "@postgres//:backend_embedded", "@postgres//:main_embedded"], + linkopts = NATIVE_LINKOPTS, + public_hdrs = native.glob(["include/*.h"]), + umbrella_header = "include/oliphaunt.h", + infoplists = [":apple_framework_info"], + ios = {"device": ["arm64"], "simulator": ["arm64"]}, + macos = ["arm64"], + families_required = {"ios": ["iphone"]}, + minimum_os_versions = {"macos": APPLE_DEPLOYMENT_TARGETS["package_macos"], "ios": APPLE_DEPLOYMENT_TARGETS["ios"]}, + tags = ["no-remote"], + target_compatible_with = _MAC, + visibility = ["//visibility:private"], + ) + _framework_archive(name = "apple_xcframework_intermediate", archive = ":apple_xcframework_raw", target_compatible_with = _MAC) + version = PRODUCTS["liboliphaunt-native"]["version"] + selected = {} + for name, kind, target in [ + ("archive", "native-runtime", "ios-xcframework"), + ("swiftpm", "apple-swiftpm-binary", "apple-spm-xcframework"), + ("resources", "runtime-resources", "ios-datum64"), + ]: + rows = [row for row in NATIVE_RUNTIME_ARTIFACTS if row["product"] == "liboliphaunt-native" and row["kind"] == kind and row["target"] == target] + if len(rows) != 1: + fail("Apple native carrier must have one canonical artifact: " + kind + "/" + target) + selected[name] = rows[0] + _release_assets(name = "apple_release_assets", intermediate = ":apple_xcframework_intermediate", + asset_names = {name: row["asset"].replace("{version}", version) for name, row in selected.items()} | { + "checksums": "apple-release-assets.sha256", + "macos_resources": "apple-macos-runtime-resources.tar.gz", + }, + notices = native_carrier_legal_inputs(), target_compatible_with = _MAC) + shipping_suppliers(name = "apple_suppliers", inputs = []) + packages = [] + for name, row in selected.items(): + apple_slice_filegroup(name = "apple_" + name, src = ":apple_release_assets", output_group = name, target_compatible_with = _MAC) + shipping_package(name = "apple_" + name + "_shipping", owner = "@oliphaunt_metadata//:product_liboliphaunt-native", artifacts = [":apple_" + name], + ecosystem = "github", package_name = row["asset"].replace("{version}", version), configuration = row["target"], role = "github-release-asset", suppliers = ":apple_suppliers") + packages.append(":apple_" + name + "_shipping") + for name in ["ios_device_abi", "ios_simulator_abi", "macos_abi", "macos_resources", "checksums", "ios_manifest"]: + apple_slice_filegroup(name = "apple_" + name, src = ":apple_release_assets", output_group = name, target_compatible_with = _MAC) + shipping_package(name = "apple_ios_manifest_shipping", owner = "@oliphaunt_metadata//:product_liboliphaunt-native", artifacts = [":apple_ios_manifest"], + ecosystem = "internal", package_name = "ios.json", configuration = "ios-xcframework", role = "apple-base-ios-manifest-input", suppliers = ":apple_suppliers") + packages.append(":apple_ios_manifest_shipping") + bun_script_test( + name = "apple_final_contract_test", + entry_point = "//build_defs/native/apple:runtime-final.test.mts", + args = ["$(location :apple_archive)", "$(location :apple_swiftpm)", "$(location :apple_resources)", + "$(location :apple_checksums)", "$(location include/oliphaunt.h)", + "$(location :apple_ios_manifest)", "$(location :apple_ios_device_abi)", "$(location :apple_ios_simulator_abi)", "$(location :apple_macos_abi)"], + data = [":apple_archive", ":apple_swiftpm", ":apple_resources", ":apple_checksums", "include/oliphaunt.h", + ":apple_ios_manifest", ":apple_ios_device_abi", ":apple_ios_simulator_abi", ":apple_macos_abi", + "//build_defs/native/apple:framework-envelope.mts", "//build_defs/native/apple:framework_helpers", + "//build_defs/resources:mobile_resource_contract.mts", "//build_defs/resources:helpers"], + target_compatible_with = _MAC + ["//build_defs/host:apple_package"], + size = "medium", + ) + shipping_export(name = "apple_shipping_export", packages = packages, qualification = qualification, testonly = True, target_compatible_with = _MAC) + +def native_ios_runtime_targets(): + """Declare one real archive and its conventional public CcInfo consumer.""" + compatible = ["@platforms//os:ios", "@platforms//cpu:aarch64", "@apple_support//constraints:apple"] + cc_static_library( + name = "mobile_static_archive", + deps = [ + ":wrapper", + "@postgres//:backend_embedded", + "@postgres//:main_embedded", + ], + target_compatible_with = compatible, + ) + cc_import( + name = "mobile_static_import", + static_library = ":mobile_static_archive", + alwayslink = True, + target_compatible_with = compatible, + ) + cc_library( + name = "mobile_static", + deps = [":mobile_static_import"], + hdrs = ["include/oliphaunt.h"], + includes = ["include"], + target_compatible_with = compatible, + ) + # Compile and link every imported object against the selected SDK. This is + # deliberately a binary target: it must never run on the macOS executor. + cc_binary( + name = "mobile_static_abi_consumer", + srcs = ["smoke/liboliphaunt_abi_conformance.c"], + deps = [":mobile_static"], + copts = ["-std=c11", "-Wall", "-Wextra", "-Werror"], + target_compatible_with = compatible, + ) diff --git a/build_defs/native/native-tools-sql.test.mts b/build_defs/native/native-tools-sql.test.mts new file mode 100644 index 000000000..8dc35bca2 --- /dev/null +++ b/build_defs/native/native-tools-sql.test.mts @@ -0,0 +1,143 @@ +import assert from 'node:assert/strict'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync } from 'node:fs'; +import { createServer } from 'node:net'; +import { tmpdir } from 'node:os'; +import { basename, join, resolve } from 'node:path'; +import { + extractNativePayload, + hostRuntimeEnvironment, + runHostBinary, +} from './host-runtime-test-helpers.mts'; + +const [runtimeArchive, toolsArchive] = process.argv.slice(2).map((file) => resolve(file)); +assert(runtimeArchive && toolsArchive, 'expected actual runtime and tools archives'); +const root = mkdtempSync(join(process.env.TEST_TMPDIR ?? tmpdir(), 'native-tools-')); +const windows = process.platform === 'win32'; +const suffix = windows ? '.exe' : ''; +// Unix socket names have a small OS limit; Bazel test temporary paths can exceed it. +const socket = windows ? undefined : mkdtempSync('/tmp/oliphaunt-pg-socket-'); +const runtime = join(root, 'runtime'); +const tools = join(root, 'tools'); +const database = join(root, 'database'); +const env: NodeJS.ProcessEnv = { + ...hostRuntimeEnvironment(runtime, root), + PGHOST: windows ? '127.0.0.1' : socket, + PGPORT: '5432', + PGUSER: 'oliphaunt_native_test', + PGDATABASE: 'postgres', +}; + +function run(binary: string, args: string[], output: 'pipe' | 'inherit' = 'pipe'): string { + console.log(`Native tools: ${basename(binary)} begin`); + const result = runHostBinary(binary, args, env, root, output); + console.log(`Native tools: ${basename(binary)} done`); + return result; +} + +async function freeTcpPort(): Promise { + const server = createServer(); + await new Promise((accept, reject) => { + server.once('error', reject); + server.listen(0, '127.0.0.1', accept); + }); + const address = server.address(); + assert(address && typeof address !== 'string'); + await new Promise((accept, reject) => + server.close((error) => (error ? reject(error) : accept())), + ); + return String(address.port); +} + +let running = false; +try { + console.log('Native tools: runtime extraction begin'); + await extractNativePayload(runtimeArchive, runtime); + console.log('Native tools: runtime extraction done; tools extraction begin'); + await extractNativePayload(toolsArchive, tools); + console.log('Native tools: tools extraction done'); + mkdirSync(database); + const initdb = join(runtime, 'bin', 'initdb' + suffix); + const control = join(runtime, 'bin', 'pg_ctl' + suffix); + const psql = join(tools, 'bin', 'psql' + suffix); + const dump = join(tools, 'bin', 'pg_dump' + suffix); + const backup = join(tools, 'bin', 'pg_basebackup' + suffix); + run(initdb, [ + '-D', + database, + '-U', + env.PGUSER!, + '--locale=C', + '--encoding=UTF8', + '--auth=trust', + '--no-sync', + ]); + if (windows) env.PGPORT = await freeTcpPort(); + const serverOptions = windows + ? `-h 127.0.0.1 -p ${env.PGPORT}` + : `-k ${socket} -h '' -p ${env.PGPORT}`; + running = true; + // Windows pg_ctl's CMD child keeps inherited handles until the server exits. + run( + control, + ['-D', database, '-l', join(root, 'postgres.log'), '-o', serverOptions, '-w', 'start'], + 'inherit', + ); + const sql = (statement: string) => + run(psql, ['-X', '-A', '-t', '-v', 'ON_ERROR_STOP=1', '-c', statement]).trim(); + assert.equal(sql('SELECT 42'), '42'); + sql( + "CREATE TABLE native_tools_probe(id integer PRIMARY KEY, payload text); INSERT INTO native_tools_probe VALUES (7, 'round trip')", + ); + const logical = run(dump, ['--no-owner', '--no-privileges']); + assert.match(logical, /COPY public\.native_tools_probe/u); + assert.match(logical, /7\tround trip/u); + sql('DROP TABLE native_tools_probe'); + console.log('Native tools: psql restore begin'); + const restore = Bun.spawnSync([psql, '-X', '-v', 'ON_ERROR_STOP=1'], { + env, + cwd: root, + stdin: Buffer.from(logical), + stdout: 'pipe', + stderr: 'pipe', + }); + assert.equal(restore.exitCode, 0, restore.stderr.toString()); + console.log('Native tools: psql restore done'); + assert.equal(sql('SELECT payload FROM native_tools_probe WHERE id=7'), 'round trip'); + const physical = join(root, 'physical-backup'); + run(backup, [ + '-D', + physical, + '--format=plain', + '--wal-method=stream', + '--checkpoint=fast', + '--no-sync', + ]); + assert.match( + readFileSync(join(physical, 'backup_manifest'), 'utf8'), + /PostgreSQL-Backup-Manifest-Version/u, + ); + run(control, ['-D', database, '-m', 'fast', '-w', 'stop']); + running = false; + running = true; + run( + control, + ['-D', physical, '-l', join(root, 'backup-postgres.log'), '-o', serverOptions, '-w', 'start'], + 'inherit', + ); + assert.equal(sql('SELECT payload FROM native_tools_probe WHERE id=7'), 'round trip'); + run(control, ['-D', physical, '-m', 'fast', '-w', 'stop']); + running = false; + console.log( + 'Native tools: extracted pg_ctl lifecycle, psql, logical dump/restore, streaming backup and recovered SQL passed.', + ); +} finally { + if (running) { + for (const directory of [database, join(root, 'physical-backup')]) + Bun.spawnSync( + [join(runtime, 'bin', 'pg_ctl' + suffix), '-D', directory, '-m', 'immediate', '-w', 'stop'], + { env, cwd: root, stdout: 'pipe', stderr: 'pipe' }, + ); + } + if (socket) rmSync(socket, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/native/openssl_repository.bzl b/build_defs/native/openssl_repository.bzl new file mode 100644 index 000000000..8ee4f85f2 --- /dev/null +++ b/build_defs/native/openssl_repository.bzl @@ -0,0 +1,109 @@ +"""Canonical OpenSSL source with a pinned maintained native Bazel recipe. + +The BCR overlay is build code only. Templates and assembly are generated from +the canonical source; its separately distributed pregenerated bytes are never +imported. The source and profile still require consumer qualification. +""" + +load(":repositories.bzl", "source_string_values") + +_RECIPE_BASE = "https://raw.githubusercontent.com/bazelbuild/bazel-central-registry/95c1934a010a2a7b072e42f0d833f73174a14c55/modules/openssl/3.5.5.bcr.4/" +_LEGACY_SOURCES = [ + "providers/legacyprov.c", + "providers/implementations/ciphers/cipher_blowfish.c", + "providers/implementations/ciphers/cipher_blowfish_hw.c", + "providers/implementations/ciphers/cipher_cast5.c", + "providers/implementations/ciphers/cipher_cast5_hw.c", + "providers/implementations/ciphers/cipher_des.c", + "providers/implementations/ciphers/cipher_des_hw.c", + "providers/implementations/ciphers/cipher_desx.c", + "providers/implementations/ciphers/cipher_desx_hw.c", + "providers/implementations/ciphers/cipher_idea.c", + "providers/implementations/ciphers/cipher_idea_hw.c", + "providers/implementations/ciphers/cipher_rc2.c", + "providers/implementations/ciphers/cipher_rc2_hw.c", + "providers/implementations/ciphers/cipher_rc4.c", + "providers/implementations/ciphers/cipher_rc4_hmac_md5.c", + "providers/implementations/ciphers/cipher_rc4_hmac_md5_hw.c", + "providers/implementations/ciphers/cipher_rc4_hw.c", + "providers/implementations/ciphers/cipher_seed.c", + "providers/implementations/ciphers/cipher_seed_hw.c", + "providers/implementations/digests/md4_prov.c", + "providers/implementations/digests/mdc2_prov.c", + "providers/implementations/digests/wp_prov.c", + "providers/implementations/kdfs/pbkdf1.c", + "providers/implementations/kdfs/pvkkdf.c", +] + +def _replace_once(text, before, after): + if text.count(before) != 1: + fail("pinned OpenSSL recipe shape changed: " + before) + return text.replace(before, after) + +def _openssl_repository_impl(ctx): + source = source_string_values(ctx.read(ctx.attr.source_manifest)) + if source.get("url") != "https://github.com/openssl/openssl.git" or source.get("commit") != "286ddeaac037533bbdce65b3c689e3f7ffebf0f6": + fail("OpenSSL native recipe inventory is bounded to the canonical 3.5.6 source; review inventory and configuration before updating it") + ctx.download_and_extract( + url = "https://codeload.github.com/openssl/openssl/tar.gz/" + source["commit"], + sha256 = "135c4c043db5d480d7dd4d3c0e96f0cb3cbee574e48c3cc505c540e65ffa1746", + type = "tar.gz", + stripPrefix = "openssl-" + source["commit"], + ) + ctx.download( + url = _RECIPE_BASE + "source.json", + sha256 = "662d68be9227e60ef65fed83c6820564bda4af0efe6a40dc62dd9aee288fe9cf", + output = "BAZEL_RECIPE_SOURCE.json", + ) + recipe = json.decode(ctx.read("BAZEL_RECIPE_SOURCE.json")) + downloads = [] + for path, integrity in recipe["overlay"].items(): + if path.startswith("/") or ".." in path.split("/"): + fail("invalid pinned OpenSSL overlay path: " + path) + if path in ["MODULE.bazel", "presubmit.yml"]: + continue + downloads.append(ctx.download(url = _RECIPE_BASE + "overlay/" + path, integrity = integrity, output = path, block = False)) + for download in downloads: + download.wait() + for path in recipe["overlay"]: + if path.startswith("configdata/") and path.endswith("/configdata.pm"): + configuration = ctx.read(path) + configuration = _replace_once(configuration, "our %disabled = ();", "our %disabled = (module => q(option), engine => q(option), q(dynamic-engine) => q(option), shared => q(option));") + ctx.file(path, configuration) + build = ctx.read("BUILD.bazel") + build = _replace_once(build, 'load("//bazel:pregen.bzl", "pregen_overlay_targets")\n', "") + build = _replace_once(build, 'name = "use-pregenerated",\n build_setting_default = True,', 'name = "use-pregenerated",\n build_setting_default = False,') + build = _replace_once(build, "pregen_overlay_targets()", "\n".join([ + 'alias(name = "pregen_hdrs", actual = ":perl_generated_hdrs")', + 'alias(name = "pregen_srcs", actual = ":perl_generated_srcs")', + 'alias(name = "pregen_app_hdrs", actual = ":perl_generated_app_hdrs")', + 'alias(name = "pregen_app_srcs", actual = ":perl_generated_app_srcs")', + ])) + for flavor in ["linux64", "elf", "ios64", "macosx"]: + build = build.replace('"@openssl_pregen//:asm_' + flavor + '"', '":perlasm_genfiles"') + if "@openssl_pregen" in build: + fail("unhandled pregenerated OpenSSL dependency in the pinned recipe") + # Canonical VC-noCE-common EX_LIBS belong to libcrypto's consumers, + # including shared libraries which retain its complete static archive. + build = _replace_once( + build, + ' "@platforms//os:windows": [],\n "//conditions:default": [\n "-lc",\n "-pthread",', + ' "@platforms//os:windows": ["ws2_32.lib", "gdi32.lib", "advapi32.lib", "crypt32.lib", "user32.lib"],\n "//conditions:default": [\n "-lc",\n "-pthread",', + ) + # This runtime carries its legacy provider in libcrypto, matching the + # existing mobile no-module construction instead of finding a host module. + crypto_sources = '[source for source in COMMON_CRYPTO_SRCS if not source.startswith("crypto/engine/") and not source.startswith("engines/")]' + build = _replace_once(build, "srcs = COMMON_CRYPTO_SRCS + select({", "srcs = " + crypto_sources + " + " + repr(_LEGACY_SOURCES) + " + select({") + build = _replace_once(build, "COMMON_DEFINES = select({", 'COMMON_DEFINES = ["STATIC_LEGACY", "OPENSSL_NO_MODULE", "OPENSSL_NO_ENGINE"] + select({') + ctx.file("configdata/wasix/configdata.pm", ctx.read(Label("//build_defs/wasix/dependencies:openssl-configdata.pm"))) + ctx.file("util/wasix_batch_dofile.pl", ctx.read("bazel/batch_dofile.pl")) + build += '\nload("@oliphaunt//build_defs/wasix/dependencies:openssl.bzl", "wasix_openssl")\nwasix_openssl(name = "wasix_crypto")\n' + ctx.file("BUILD.bazel", build) + ctx.file("BAZEL_RECIPE_ORIGIN", _RECIPE_BASE + "\n") + +openssl_repository = repository_rule( + implementation = _openssl_repository_impl, + attrs = { + "source_manifest": attr.label(default = "//src/third-party/openssl:source.toml", allow_single_file = True), + }, +) diff --git a/build_defs/native/patches/rules-cc-autoconf-fatal-diagnostics.patch b/build_defs/native/patches/rules-cc-autoconf-fatal-diagnostics.patch new file mode 100644 index 000000000..2b71674ce --- /dev/null +++ b/build_defs/native/patches/rules-cc-autoconf-fatal-diagnostics.patch @@ -0,0 +1,110 @@ +diff --git a/autoconf/private/checker/check_runner.cc b/autoconf/private/checker/check_runner.cc +index 782e81023..b70ccd7c3 100644 +--- a/autoconf/private/checker/check_runner.cc ++++ b/autoconf/private/checker/check_runner.cc +@@ -516,7 +516,7 @@ CheckResult CheckRunner::check_compute_int(const Check& check) { + } + std::optional value = find_compile_time_int_bisect( + *check.code(), check.language(), /*search_begin=*/-1024, +- /*search_end=*/1024, extra_copts); ++ /*search_end=*/1024, extra_copts, /*diagnose_failure=*/true); + + if (value.has_value()) { + return CheckResult(id, std::to_string(*value), true, +@@ -815,7 +815,7 @@ static std::pair split_code_expr( + std::optional CheckRunner::find_compile_time_int_bisect( + const std::string& base_code_template, const std::string& language, + const int search_begin, const int search_end, +- const std::vector& extra_copts) { ++ const std::vector& extra_copts, bool diagnose_failure) { + const std::pair code_expr = + split_code_expr(base_code_template); + // int type for target might not be same as host +@@ -846,6 +846,14 @@ std::optional CheckRunner::find_compile_time_int_bisect( + language, extra_copts)) { + // at least search_begin < constant or constant < search_end should + // compile if none compile, means expr can't evaluate at compile time ++ if (diagnose_failure) { ++ // Replay one failed comparison with compiler diagnostics. A ++ // successful retry must not change the already-failed result. ++ try_compile(gen_less_compare(code_expr.first, ++ std::to_string(search_begin), ++ code_expr.second), ++ language, extra_copts, /*diagnostics=*/true); ++ } + throw std::runtime_error( + "'" + code_expr.second + + "' can't be evaluated (non-exist constant, invalid expression, or " +diff --git a/autoconf/private/checker/check_runner.h b/autoconf/private/checker/check_runner.h +index 759b5ee53..4bb6f56f5 100644 +--- a/autoconf/private/checker/check_runner.h ++++ b/autoconf/private/checker/check_runner.h +@@ -136,7 +136,8 @@ class CheckRunner { + * @return true if compilation succeeded, false otherwise. + */ + bool try_compile(const std::string& code, const std::string& language = "c", +- const std::vector& extra_copts = {}); ++ const std::vector& extra_copts = {}, ++ bool diagnostics = false); + + /** + * @brief Try to link an object file into an executable. +@@ -303,7 +304,8 @@ class CheckRunner { + std::optional find_compile_time_int_bisect( + const std::string& base_code_template, const std::string& language, + const int search_begin = -1024, const int search_end = 1024, +- const std::vector& extra_copts = {}); ++ const std::vector& extra_copts = {}, ++ bool diagnose_failure = false); + + /** + * @brief Resolve compile_defines from check and build #define +diff --git a/autoconf/private/checker/compilation.cc b/autoconf/private/checker/compilation.cc +index 46ad1c7d0..342712939 100644 +--- a/autoconf/private/checker/compilation.cc ++++ b/autoconf/private/checker/compilation.cc +@@ -23,6 +23,11 @@ namespace rules_cc_autoconf { + + constexpr const char* kCoptsMarker = "{rules_cc_autoconf:copts}"; + constexpr const char* kLinkoptsMarker = "{rules_cc_autoconf:linkopts}"; ++#ifdef _WIN32 ++constexpr const char* kNullOutput = "NUL"; ++#else ++constexpr const char* kNullOutput = "/dev/null"; ++#endif + + namespace { + +@@ -69,9 +74,11 @@ bool is_msvc_output_flag(std::string_view arg) { + }); + } + +-int run_command(const std::string& label, const std::vector& cmd) { ++int run_command(const std::string& label, const std::vector& cmd, ++ bool diagnostics = false) { + DebugLogger::debug("Executing declared native " + label + " tool: " + cmd.front()); +- return run_native_process(cmd, !DebugLogger::is_verbose_debug_enabled()); ++ return run_native_process(cmd, !diagnostics && !DebugLogger::is_verbose_debug_enabled(), ++ diagnostics ? kNullOutput : ""); + } + + /** +@@ -240,7 +247,8 @@ std::string CheckRunner::get_file_extension(const std::string& language) { + + bool CheckRunner::try_compile(const std::string& code, + const std::string& language, +- const std::vector& extra_copts) { ++ const std::vector& extra_copts, ++ bool diagnostics) { + BuildDir tmp(source_id_, source_dir_); + std::optional source_file = + tmp.write_source(code, get_file_extension(language)); +@@ -261,7 +269,7 @@ bool CheckRunner::try_compile(const std::string& code, + cmd.push_back(tmp.object_path(false).string()); + } + +- return run_command("compile", cmd) == 0; ++ return run_command("compile", cmd, diagnostics) == 0; + } + + bool CheckRunner::try_link(const std::filesystem::path& object_file, diff --git a/build_defs/native/patches/rules-cc-autoconf-native-process.patch b/build_defs/native/patches/rules-cc-autoconf-native-process.patch new file mode 100644 index 000000000..5faf9f2dc --- /dev/null +++ b/build_defs/native/patches/rules-cc-autoconf-native-process.patch @@ -0,0 +1,473 @@ +diff -ruN oliphaunt-rules-cc-autoconf-0.24.0/autoconf/autoconf_hdr.bzl oliphaunt-rules-cc-autoconf-0.24.0-native/autoconf/autoconf_hdr.bzl +--- oliphaunt-rules-cc-autoconf-0.24.0/autoconf/autoconf_hdr.bzl 2026-09-10 17:29:48.000000000 +0000 ++++ oliphaunt-rules-cc-autoconf-0.24.0-native/autoconf/autoconf_hdr.bzl 2026-10-11 03:34:59.833011431 +0000 +@@ -128,7 +128,7 @@ + inputs = inputs, + outputs = [ctx.outputs.out], + mnemonic = "CcAutoconfHdr", +- env = ctx.configuration.default_shell_env, ++ env = {"LC_ALL": "C"}, + # TODO: https://github.com/periareon/rules_cc_autoconf/issues/148 + execution_requirements = {"supports-path-mapping": ""} if bazel_features.rules.write_action_has_execution_requirements else {}, + ) +diff -ruN oliphaunt-rules-cc-autoconf-0.24.0/autoconf/macros/AC_C_RESTRICT/restrict.bzl oliphaunt-rules-cc-autoconf-0.24.0-native/autoconf/macros/AC_C_RESTRICT/restrict.bzl +--- oliphaunt-rules-cc-autoconf-0.24.0/autoconf/macros/AC_C_RESTRICT/restrict.bzl 2026-09-10 17:29:48.000000000 +0000 ++++ oliphaunt-rules-cc-autoconf-0.24.0-native/autoconf/macros/AC_C_RESTRICT/restrict.bzl 2026-10-11 03:34:59.832011434 +0000 +@@ -102,7 +102,7 @@ + outputs = [result_file], + mnemonic = "CcAutoconfCheck", + progress_message = "CcAutoconfCheck %{label} - " + cache_name, +- env = env | ctx.configuration.default_shell_env, ++ env = {"LC_ALL": "C"} | env, +- tools = toolchain_info.cc_toolchain.all_files, ++ tools = [toolchain_info.cc_toolchain.all_files], + # TODO: https://github.com/periareon/rules_cc_autoconf/issues/148 + execution_requirements = {"supports-path-mapping": ""} if bazel_features.rules.write_action_has_execution_requirements else {}, +diff -ruN oliphaunt-rules-cc-autoconf-0.24.0/autoconf/private/autoconf_library.bzl oliphaunt-rules-cc-autoconf-0.24.0-native/autoconf/private/autoconf_library.bzl +--- oliphaunt-rules-cc-autoconf-0.24.0/autoconf/private/autoconf_library.bzl 2026-09-10 17:29:48.000000000 +0000 ++++ oliphaunt-rules-cc-autoconf-0.24.0-native/autoconf/private/autoconf_library.bzl 2026-10-11 03:34:59.832011434 +0000 +@@ -461,7 +461,7 @@ + outputs = [check_result_file], + mnemonic = "CcAutoconfCheck", + progress_message = "CcAutoconfCheck %{label} - " + check_name, +- env = env | ctx.configuration.default_shell_env, ++ env = {"LC_ALL": "C"} | env, +- tools = toolchain_info.cc_toolchain.all_files, ++ tools = [toolchain_info.cc_toolchain.all_files], + # TODO: https://github.com/periareon/rules_cc_autoconf/issues/148 + execution_requirements = {"supports-path-mapping": ""} if bazel_features.rules.write_action_has_execution_requirements else {}, +diff -ruN oliphaunt-rules-cc-autoconf-0.24.0/autoconf/private/checker/BUILD.bazel oliphaunt-rules-cc-autoconf-0.24.0-native/autoconf/private/checker/BUILD.bazel +--- oliphaunt-rules-cc-autoconf-0.24.0/autoconf/private/checker/BUILD.bazel 2026-09-10 17:29:48.000000000 +0000 ++++ oliphaunt-rules-cc-autoconf-0.24.0-native/autoconf/private/checker/BUILD.bazel 2026-10-11 03:35:45.275880222 +0000 +@@ -51,6 +51,7 @@ + ], + hdrs = [ + "check_runner.h", ++ "native_process.h", + "system_header.h", + ], + cxxopts = cxxopts(), +@@ -124,3 +125,9 @@ + "//tools/json", + ], + ) ++ ++cc_library( ++ name = "native_process", ++ hdrs = ["native_process.h"], ++ visibility = ["//visibility:public"], ++) +diff -ruN oliphaunt-rules-cc-autoconf-0.24.0/autoconf/private/checker/compilation.cc oliphaunt-rules-cc-autoconf-0.24.0-native/autoconf/private/checker/compilation.cc +--- oliphaunt-rules-cc-autoconf-0.24.0/autoconf/private/checker/compilation.cc 2026-09-10 17:29:48.000000000 +0000 ++++ oliphaunt-rules-cc-autoconf-0.24.0-native/autoconf/private/checker/compilation.cc 2026-10-11 03:42:48.925623923 +0000 +@@ -16,6 +16,7 @@ + + #include "autoconf/private/checker/check_runner.h" + #include "autoconf/private/checker/debug_logger.h" ++#include "autoconf/private/checker/native_process.h" + #include "autoconf/private/common/file_util.h" + + namespace rules_cc_autoconf { +@@ -25,70 +26,6 @@ + + namespace { + +-#ifdef _WIN32 +-/** +- * @brief Convert a long path to Windows 8.3 short path format (no spaces). +- * +- * This function is used to avoid issues with cmd.exe when paths contain spaces. +- * If conversion fails, returns the original path wrapped in quotes. +- * +- * @param long_path The long path to convert. +- * @return The short path (8.3 format) or quoted original path if conversion +- * fails. +- */ +-std::string get_short_path(const std::string& long_path) { +- // Get the required buffer size +- DWORD length = GetShortPathNameA(long_path.c_str(), nullptr, 0); +- if (length == 0) { +- // If conversion fails, return original path quoted +- return "\"" + long_path + "\""; +- } +- +- // Get the short path +- std::vector buffer(length); +- DWORD result = GetShortPathNameA(long_path.c_str(), buffer.data(), length); +- if (result == 0 || result >= length) { +- // If conversion fails, return original path quoted +- return "\"" + long_path + "\""; +- } +- +- return std::string(buffer.data()); +-} +-#endif +- +-/** +- * @brief Quote an argument if it contains spaces. +- * +- * On Windows, uses double quotes. On Unix, uses single quotes. +- * This prevents command-line parsing issues when paths or arguments contain +- * spaces. +- * +- * @param arg The argument string to potentially quote. +- * @return The quoted argument if it contains spaces, otherwise the original +- * argument. +- */ +-std::string quote_if_needed(const std::string& arg) { +-#ifdef _WIN32 +- if (arg.find_first_of(" \t()&|<>^") != std::string::npos) { +- return "\"" + arg + "\""; +- } +-#else +- if (arg.find_first_of(" \t()|&;<>$`*?[]{}!#~'\"\\") != std::string::npos) { +- std::string quoted = "'"; +- for (char c : arg) { +- if (c == '\'') { +- quoted += "'\\''"; +- } else { +- quoted += c; +- } +- } +- quoted += "'"; +- return quoted; +- } +-#endif +- return arg; +-} +- + /** + * @brief Sanitize a define name for use in filenames. + * +@@ -132,61 +69,9 @@ + }); + } + +-/** +- * @brief Build a shell command string from a vector of arguments. +- * +- * On Windows, the first argument (compiler/linker path) is converted to +- * 8.3 short path format. All arguments with spaces are quoted. +- * +- * @param cmd Vector of command parts (program + arguments). +- * @return The assembled shell command string. +- */ +-std::string build_command_string(const std::vector& cmd) { +- std::stringstream cmd_str; +- for (size_t i = 0; i < cmd.size(); ++i) { +- if (i > 0) cmd_str << " "; +- if (i == 0) { +-#ifdef _WIN32 +- cmd_str << get_short_path(cmd[i]); +-#else +- cmd_str << quote_if_needed(cmd[i]); +-#endif +- } else { +- cmd_str << quote_if_needed(cmd[i]); +- } +- } +- return cmd_str.str(); +-} +- +-/** +- * @brief Execute a shell command, optionally suppressing output. +- * +- * If verbose debug is not enabled, stdout and stderr are redirected to +- * /dev/null (or NUL on Windows). +- * +- * @param label A label for debug logging (e.g., "compile", "link"). +- * @param cmd Vector of command parts. +- * @return The process exit code (already WEXITSTATUS-unwrapped on Unix). +- */ + int run_command(const std::string& label, const std::vector& cmd) { +- std::string full_cmd = build_command_string(cmd); +- +- if (!DebugLogger::is_verbose_debug_enabled()) { +-#ifdef _WIN32 +- full_cmd += " >NUL 2>&1"; +-#else +- full_cmd += " >/dev/null 2>&1"; +-#endif +- } +- +- DebugLogger::debug("Executing " + label + " command: " + full_cmd); +- +- int result = std::system(full_cmd.c_str()); +-#ifdef _WIN32 +- return result; +-#else +- return WEXITSTATUS(result); +-#endif ++ DebugLogger::debug("Executing declared native " + label + " tool: " + cmd.front()); ++ return run_native_process(cmd, !DebugLogger::is_verbose_debug_enabled()); + } + + /** +@@ -236,10 +121,11 @@ + std::ofstream source = open_ofstream(source_file); + if (!source.is_open()) { + DebugLogger::warn("Failed to create source file"); +- return std::nullopt; ++ throw NativeProcessError("cannot create native probe source: " + source_file.string()); + } + source << code; + source.close(); ++ if (!source) throw NativeProcessError("cannot write native probe source: " + source_file.string()); + return source_file; + } + +diff -ruN oliphaunt-rules-cc-autoconf-0.24.0/autoconf/private/checker/native_process.h oliphaunt-rules-cc-autoconf-0.24.0-native/autoconf/private/checker/native_process.h +--- oliphaunt-rules-cc-autoconf-0.24.0/autoconf/private/checker/native_process.h 1970-01-01 00:00:00.000000000 +0000 ++++ oliphaunt-rules-cc-autoconf-0.24.0-native/autoconf/private/checker/native_process.h 2026-10-11 03:42:48.925623923 +0000 +@@ -0,0 +1,160 @@ ++#ifndef RULES_CC_AUTOCONF_NATIVE_PROCESS_H ++#define RULES_CC_AUTOCONF_NATIVE_PROCESS_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef _WIN32 ++#include ++#else ++#include ++#include ++#include ++#include ++extern char** environ; ++#endif ++ ++namespace rules_cc_autoconf { ++ ++// The maintained numeric probes catch runtime_error for an unknown expression. ++// Infrastructure failures must bypass that legitimate optional-result handler. ++class NativeProcessError : public std::logic_error { ++ public: ++ using std::logic_error::logic_error; ++}; ++ ++inline NativeProcessError native_process_error(const std::string& context, int code) { ++ return NativeProcessError(context + ": " + ++ std::error_code(code, std::generic_category()).message()); ++} ++ ++// A compiler's ordinary nonzero exit is a negative feature result. A failed ++// process launch, signal, broken output path or wrapper failure is a broken ++// construction environment and must fail the action instead. ++inline int run_native_process(const std::vector& args, ++ bool quiet = true, ++ const std::string& stdout_path = "") { ++ if (args.empty() || args.front().empty()) { ++ throw NativeProcessError("native probe has no declared executable"); ++ } ++#ifdef _WIN32 ++ // CreateProcess uses the CRT command-line convention, not cmd.exe syntax. ++ auto quote = [](const std::string& value) { ++ std::string result = "\""; ++ size_t slashes = 0; ++ for (char c : value) { ++ if (c == '\\') { ++ ++slashes; ++ } else { ++ result.append(slashes * (c == '"' ? 2 : 1), '\\'); ++ slashes = 0; ++ if (c == '"') result += '\\'; ++ result += c; ++ } ++ } ++ result.append(slashes * 2, '\\'); ++ return result + '"'; ++ }; ++ std::string command; ++ for (const auto& arg : args) { ++ if (!command.empty()) command += ' '; ++ command += quote(arg); ++ } ++ SECURITY_ATTRIBUTES security{sizeof(security), nullptr, TRUE}; ++ HANDLE null_output = INVALID_HANDLE_VALUE; ++ HANDLE file_output = INVALID_HANDLE_VALUE; ++ if (quiet) { ++ null_output = CreateFileA("NUL", GENERIC_WRITE, FILE_SHARE_WRITE, ++ &security, OPEN_EXISTING, 0, nullptr); ++ if (null_output == INVALID_HANDLE_VALUE) { ++ throw NativeProcessError("cannot open native probe diagnostic sink"); ++ } ++ } ++ if (!stdout_path.empty()) { ++ file_output = CreateFileA(stdout_path.c_str(), GENERIC_WRITE, ++ FILE_SHARE_READ, &security, CREATE_ALWAYS, ++ FILE_ATTRIBUTE_NORMAL, nullptr); ++ if (file_output == INVALID_HANDLE_VALUE) { ++ if (quiet) CloseHandle(null_output); ++ throw NativeProcessError("cannot create native probe output: " + stdout_path); ++ } ++ } ++ STARTUPINFOA startup{}; ++ startup.cb = sizeof(startup); ++ startup.dwFlags = STARTF_USESTDHANDLES; ++ startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE); ++ startup.hStdOutput = file_output != INVALID_HANDLE_VALUE ? file_output : ++ (quiet ? null_output : GetStdHandle(STD_OUTPUT_HANDLE)); ++ startup.hStdError = quiet ? null_output : GetStdHandle(STD_ERROR_HANDLE); ++ PROCESS_INFORMATION process{}; ++ auto application = std::filesystem::path(args.front()).make_preferred().string(); ++ BOOL launched = CreateProcessA(application.c_str(), command.data(), nullptr, ++ nullptr, TRUE, 0, nullptr, nullptr, ++ &startup, &process); ++ DWORD launch_error = GetLastError(); ++ if (file_output != INVALID_HANDLE_VALUE) CloseHandle(file_output); ++ if (quiet) CloseHandle(null_output); ++ if (!launched) { ++ throw NativeProcessError("cannot launch declared native probe tool " + ++ args.front() + ": Windows error " + ++ std::to_string(launch_error)); ++ } ++ DWORD waited = WaitForSingleObject(process.hProcess, INFINITE); ++ DWORD code = 0; ++ BOOL obtained = GetExitCodeProcess(process.hProcess, &code); ++ CloseHandle(process.hThread); ++ CloseHandle(process.hProcess); ++ if (waited != WAIT_OBJECT_0 || !obtained || code >= 0xC0000000UL) { ++ throw NativeProcessError("declared native probe tool crashed: " + args.front()); ++ } ++ return static_cast(code); ++#else ++ posix_spawn_file_actions_t actions; ++ int error = posix_spawn_file_actions_init(&actions); ++ if (error) throw native_process_error("probe spawn setup", error); ++ auto redirect = [&](int descriptor, const std::string& path) { ++ int result = posix_spawn_file_actions_addopen( ++ &actions, descriptor, path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0600); ++ if (result) { ++ posix_spawn_file_actions_destroy(&actions); ++ throw native_process_error("probe output setup", result); ++ } ++ }; ++ if (!stdout_path.empty()) redirect(STDOUT_FILENO, stdout_path); ++ else if (quiet) redirect(STDOUT_FILENO, "/dev/null"); ++ if (quiet) redirect(STDERR_FILENO, "/dev/null"); ++ std::vector argv; ++ for (const auto& arg : args) argv.push_back(const_cast(arg.c_str())); ++ argv.push_back(nullptr); ++ pid_t pid = 0; ++ // No PATH lookup and no shell: args[0] is the declared toolchain path. ++ error = posix_spawn(&pid, args.front().c_str(), &actions, nullptr, ++ argv.data(), environ); ++ posix_spawn_file_actions_destroy(&actions); ++ if (error) { ++ throw native_process_error("cannot launch declared native probe tool " + args.front(), error); ++ } ++ int status = 0; ++ pid_t waited; ++ do { waited = waitpid(pid, &status, 0); } while (waited == -1 && errno == EINTR); ++ if (waited == -1) { ++ throw native_process_error("probe wait", errno); ++ } ++ if (!WIFEXITED(status)) { ++ throw NativeProcessError("declared native probe tool was signalled: " + args.front()); ++ } ++ int code = WEXITSTATUS(status); ++ if (code == 126 || code == 127) { ++ throw NativeProcessError("declared native probe wrapper failed: " + args.front()); ++ } ++ return code; ++#endif ++} ++ ++} // namespace rules_cc_autoconf ++ ++#endif +diff -ruN oliphaunt-rules-cc-autoconf-0.24.0/autoconf/private/checker/system_header.cc oliphaunt-rules-cc-autoconf-0.24.0-native/autoconf/private/checker/system_header.cc +--- oliphaunt-rules-cc-autoconf-0.24.0/autoconf/private/checker/system_header.cc 2026-09-10 17:29:48.000000000 +0000 ++++ oliphaunt-rules-cc-autoconf-0.24.0-native/autoconf/private/checker/system_header.cc 2026-10-11 03:42:48.925623923 +0000 +@@ -13,34 +13,13 @@ + + #include "autoconf/private/checker/config.h" + #include "autoconf/private/checker/debug_logger.h" ++#include "autoconf/private/checker/native_process.h" + #include "autoconf/private/common/file_util.h" + + namespace rules_cc_autoconf { + + namespace { + +-#ifdef _WIN32 +-std::string get_short_path_sys(const std::string& long_path) { +- DWORD length = GetShortPathNameA(long_path.c_str(), nullptr, 0); +- if (length == 0) return "\"" + long_path + "\""; +- std::vector buffer(length); +- DWORD result = GetShortPathNameA(long_path.c_str(), buffer.data(), length); +- if (result == 0 || result >= length) return "\"" + long_path + "\""; +- return std::string(buffer.data()); +-} +-#endif +- +-std::string quote_arg(const std::string& arg) { +- if (arg.find(' ') != std::string::npos) { +-#ifdef _WIN32 +- return "\"" + arg + "\""; +-#else +- return "'" + arg + "'"; +-#endif +- } +- return arg; +-} +- + bool ends_with(const std::string& str, const std::string& suffix) { + if (suffix.size() > str.size()) return false; + return str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; +@@ -119,39 +98,25 @@ + if (!src.is_open()) { + DebugLogger::warn("GL_NEXT_HEADER: failed to write source for " + + header); +- return std::nullopt; ++ throw NativeProcessError("cannot create native preprocessor source: " + src_path.string()); + } + src << src_code; ++ src.close(); ++ if (!src) throw NativeProcessError("cannot write native preprocessor source: " + src_path.string()); + } + +- // Build the preprocessor command +- std::ostringstream cmd; +-#ifdef _WIN32 +- cmd << get_short_path_sys(compiler); +-#else +- cmd << quote_arg(compiler); +-#endif +- +- for (const std::string& f : flags) { +- cmd << " " << quote_arg(f); +- } +- ++ std::vector command{compiler}; ++ command.insert(command.end(), flags.begin(), flags.end()); + if (msvc) { +- // MSVC: /E writes preprocessed output to stdout, /EP suppresses #line +- // markers so we use /E to keep them +- cmd << " /E " << quote_arg(src_path.string()); +- cmd << " > " << quote_arg(pp_out.string()) << " 2>NUL"; ++ command.push_back("/E"); ++ command.push_back(src_path.string()); + } else { +- cmd << " -E " << quote_arg(src_path.string()); +- cmd << " -o " << quote_arg(pp_out.string()) << " 2>/dev/null"; ++ command.push_back("-E"); ++ command.push_back(src_path.string()); ++ command.push_back("-o"); ++ command.push_back(pp_out.string()); + } +- +- DebugLogger::debug("GL_NEXT_HEADER: running preprocessor: " + cmd.str()); +- +- int rc = std::system(cmd.str().c_str()); +-#ifndef _WIN32 +- rc = WEXITSTATUS(rc); +-#endif ++ int rc = run_native_process(command, true, msvc ? pp_out.string() : ""); + + // Clean up source file + std::error_code ec; diff --git a/build_defs/native/platform_config.bzl b/build_defs/native/platform_config.bzl new file mode 100644 index 000000000..595554ade --- /dev/null +++ b/build_defs/native/platform_config.bzl @@ -0,0 +1,177 @@ +"""Bounded native PG configuration selected by the target ABI and libc.""" + +load(":android_lp64_config.bzl", "ANDROID_LP64_CONFIG") +load(":linux_x86_64_config.bzl", "LINUX_X86_64_CONFIG") +load(":postgres_sources.bzl", "POSTGRES_BACKEND_LINUX_SOURCES", "POSTGRES_PORT_REPLACEMENT_SOURCES", "POSTGRES_PORT_CRC_GENERIC_SOURCES") +load(":windows_config.bzl", "WINDOWS_COPTS", "WINDOWS_DEFINES", "WINDOWS_BACKEND_DEFINES", "WINDOWS_WRAPPER_DEFINES", "WINDOWS_INCLUDE_DIRECTORIES", "WINDOWS_LINKOPTS") +load(":windows_sources.bzl", "WINDOWS_BACKEND_PORT_SOURCES", "WINDOWS_PORT_SOURCES", "WINDOWS_PORT_CRC_SOURCES", "WINDOWS_LIBPQ_SOURCES") + +_X64 = "@oliphaunt//build_defs/native:linux_x86_64" +_X64_GNU_228 = "@oliphaunt//build_defs/native:linux_x86_64_gnu_2_28" +_ARM64_GNU_228 = "@oliphaunt//build_defs/native:linux_aarch64_gnu_2_28" +_ANDROID_ARM64 = "@oliphaunt//build_defs/native:android_arm64" +_ANDROID_X64 = "@oliphaunt//build_defs/native:android_x86_64" +_ANDROID = "@oliphaunt//build_defs/native:android" +_MACOS = "@oliphaunt//build_defs/native:macos_arm64" +_WINDOWS = "@oliphaunt//build_defs/native:windows_x64" +_IOS = "@oliphaunt//build_defs/native:ios" +_IOS_DEVICE = "@oliphaunt//build_defs/native:ios_arm64" +_IOS_SIMULATOR = "@oliphaunt//build_defs/native:ios_arm64_simulator" + +# __FILE__ diagnostics must not contain Bazel's incidental repository counter. +_POSTGRES_SOURCE_MAP = "-ffile-prefix-map=" + Label("@postgres//:src/include/pg_config.h.in").workspace_root + "/=postgres/" + +# glibc introduced strlcpy/strlcat in 2.38; lower ABI profiles must compile PG's +# replacements. This is a toolchain-dependent fact, not a host configure probe. +_GNU_228 = {key: value for key, value in LINUX_X86_64_CONFIG.items() if key not in ["HAVE_STRLCPY", "HAVE_STRLCAT"]} | { + "HAVE_DECL_STRLCPY": "0", + "HAVE_DECL_STRLCAT": "0", + "CONFIGURE_ARGS": '"Bazel Linux glibc 2.28 ICU profile"', + # Clang implements the printf checker, but rejects GCC's gnu_printf spelling. + "PG_C_PRINTF_ATTRIBUTE": "printf", + "PG_CXX_PRINTF_ATTRIBUTE": "printf", +} + +_ARM64_228 = {key: value for key, value in _GNU_228.items() if key not in ["HAVE_X86_64_POPCNTQ", "HAVE_XSAVE_INTRINSICS", "HAVE__GET_CPUID", "HAVE__GET_CPUID_COUNT"]} +_ANDROID_X64_CONFIG = ANDROID_LP64_CONFIG | {key: "1" for key in ["HAVE_X86_64_POPCNTQ", "HAVE_XSAVE_INTRINSICS", "HAVE__GET_CPUID", "HAVE__GET_CPUID_COUNT"]} + +NATIVE_CONFIG = select({ + _X64_GNU_228: _GNU_228, + _ARM64_GNU_228: _ARM64_228, + _X64: LINUX_X86_64_CONFIG, + _ANDROID_ARM64: ANDROID_LP64_CONFIG, + _ANDROID_X64: _ANDROID_X64_CONFIG, +}, no_match_error = "No PostgreSQL native configuration for this target ABI/libc. Select a declared Linux or bounded Android native platform; Apple and MSVC profiles require their own qualification.") + +NATIVE_PROFILE = select({ + _X64_GNU_228: "Linux x86_64 glibc 2.28 Bazel", + _ARM64_GNU_228: "Linux aarch64 glibc 2.28 Bazel", + _X64: "Linux x86_64 Bazel development slice", + _ANDROID_ARM64: "Android aarch64 Bionic Bazel", + _ANDROID_X64: "Android x86_64 Bionic Bazel", +}) + +NATIVE_COMPATIBLE = select({ + _X64: [], + _ARM64_GNU_228: [], + _MACOS: [], + _WINDOWS: [], + "//conditions:default": ["@platforms//:incompatible"], +}) + +# C construction capability is broader than the desktop module/server carrier. +# Android and iOS embed process-local IPC and builtin modules; they cannot claim the +# desktop postmaster or installed dynamic-extension SQL consumer semantics. +NATIVE_C_COMPATIBLE = select({ + _X64: [], + _ARM64_GNU_228: [], + _ANDROID: [], + _IOS_DEVICE: [], + _IOS_SIMULATOR: [], + _MACOS: [], + _WINDOWS: [], + "//conditions:default": ["@platforms//:incompatible"], +}) + +NATIVE_ELF_C_COMPATIBLE = select({_X64: [], _ARM64_GNU_228: [], _ANDROID: [], "//conditions:default": ["@platforms//:incompatible"]}) +NATIVE_UNIX_COMPATIBLE = select({_X64: [], _ARM64_GNU_228: [], _MACOS: [], "//conditions:default": ["@platforms//:incompatible"]}) +NATIVE_MACOS_COMPATIBLE = select({_MACOS: [], "//conditions:default": ["@platforms//:incompatible"]}) +NATIVE_WINDOWS_COMPATIBLE = select({_WINDOWS: [], "//conditions:default": ["@platforms//:incompatible"]}) +NATIVE_HOST_COMPATIBLE = select({_MACOS: [], _WINDOWS: [], "//conditions:default": ["@platforms//:incompatible"]}) +NATIVE_LINUX_COMPATIBLE = select({_X64: [], _ARM64_GNU_228: [], "//conditions:default": ["@platforms//:incompatible"]}) + +def _port_replacements(configuration): + return [source for macro, source in POSTGRES_PORT_REPLACEMENT_SOURCES.items() if macro not in configuration] + +NATIVE_PORT_REPLACEMENTS = select({ + _X64_GNU_228: _port_replacements(_GNU_228), + _ARM64_GNU_228: _port_replacements(_ARM64_228), + _X64: _port_replacements(LINUX_X86_64_CONFIG), + _ANDROID: _port_replacements(ANDROID_LP64_CONFIG), + _MACOS: [":host_macos_replacements"], + _WINDOWS: [":host_windows_replacements"], + _IOS_DEVICE: [":host_ios_replacements"], + _IOS_SIMULATOR: [":host_ios_simulator_replacements"], +}) + +# The fixed profiles remain selected only on their qualified configurations. +# Host profiles establish HAVE_* facts with the actual target compiler/SDK. +NATIVE_CONFIGURATION = select({ + _MACOS: [":host_macos_configuration"], + _WINDOWS: [":host_windows_configuration"], + _IOS_DEVICE: [":host_ios_configuration"], + _IOS_SIMULATOR: [":host_ios_simulator_configuration"], + "//conditions:default": [":static_configuration"], +}) +NATIVE_CONFIGURATION_ADMISSION = select({ + _MACOS: [":host_macos_admission"], + _WINDOWS: [":host_windows_admission"], + _IOS_DEVICE: [":host_ios_admission"], + _IOS_SIMULATOR: [":host_ios_simulator_admission"], + "//conditions:default": [], +}) +NATIVE_INCLUDE_DIRECTORIES = select({ + _MACOS: ["host_macos/src/include"], + _WINDOWS: ["host_windows/src/include"] + WINDOWS_INCLUDE_DIRECTORIES, + _IOS_DEVICE: ["host_ios/src/include"], + _IOS_SIMULATOR: ["host_ios_simulator/src/include"], + "//conditions:default": [], +}) +NATIVE_HEADER_DEFINES = select({ + _MACOS: ["_DARWIN_C_SOURCE"], + _WINDOWS: WINDOWS_DEFINES, + _IOS: ["_DARWIN_C_SOURCE"], + "//conditions:default": ["_GNU_SOURCE"], +}) +NATIVE_COPTS = select({ + _WINDOWS: WINDOWS_COPTS, + "//conditions:default": ["-std=gnu11", "-fno-strict-aliasing", "-fwrapv", "-fexcess-precision=standard", _POSTGRES_SOURCE_MAP], +}) +NATIVE_BACKEND_DEFINES = select({_WINDOWS: WINDOWS_BACKEND_DEFINES, "//conditions:default": []}) +NATIVE_WRAPPER_DEFINES = select({_WINDOWS: WINDOWS_WRAPPER_DEFINES, "//conditions:default": []}) +NATIVE_WRAPPER_COPTS = select({_WINDOWS: WINDOWS_COPTS, "//conditions:default": ["-std=gnu11", "-fno-strict-aliasing", "-fwrapv", _POSTGRES_SOURCE_MAP]}) +NATIVE_BUILTIN_PLPGSQL_DEPS = select({_WINDOWS: ["@postgres//:plpgsql_builtin_windows"], "//conditions:default": ["@postgres//:plpgsql_embedded"]}) +NATIVE_PORT_ADDITIONAL_SOURCES = select({_WINDOWS: WINDOWS_PORT_SOURCES, "//conditions:default": []}) +NATIVE_PORT_CRC_SOURCES = select({_WINDOWS: WINDOWS_PORT_CRC_SOURCES, "//conditions:default": POSTGRES_PORT_CRC_GENERIC_SOURCES}) +NATIVE_LIBPQ_ADDITIONAL_SOURCES = select({_WINDOWS: WINDOWS_LIBPQ_SOURCES, "//conditions:default": []}) + +NATIVE_OS_HEADER = "src/include/port/linux.h" +NATIVE_BACKEND_PORT_SOURCES = select({ + _ANDROID: ["src/backend/port/oliphaunt_embedded_sema.c", "src/backend/port/oliphaunt_embedded_shmem.c"], + _IOS: ["src/backend/port/oliphaunt_embedded_sema.c", "src/backend/port/oliphaunt_embedded_shmem.c"], + _MACOS: ["src/backend/port/sysv_sema.c", "src/backend/port/sysv_shmem.c"], + _WINDOWS: WINDOWS_BACKEND_PORT_SOURCES, + "//conditions:default": POSTGRES_BACKEND_LINUX_SOURCES, +}) +NATIVE_LINKOPTS = select({ + _ANDROID: ["-lm", "-ldl"], + _MACOS: [], + _IOS: [], + _WINDOWS: WINDOWS_LINKOPTS, + "//conditions:default": ["-lm", "-ldl", "-lpthread"], +}) +# The pinned Zig toolchain intentionally has no post-link strip tool. Its +# declared linker supports debug stripping without removing dynamic exports. +# Keep development/debug outputs intact; apply only at final native links. +NATIVE_RELEASE_LINKOPTS = select({"@oliphaunt//build_defs/native:linux_opt": ["-Wl,-S"], "//conditions:default": []}) +NATIVE_FRONTEND_LINKOPTS = select({_MACOS: ["-Wl,-rpath,@loader_path/../lib"], _WINDOWS: [], "//conditions:default": ["-Wl,-rpath,$ORIGIN/../lib"]}) +NATIVE_SERVER_LINKOPTS = select({_MACOS: [], _WINDOWS: [], "//conditions:default": ["-Wl,--export-dynamic"]}) +NATIVE_MODULE_LINKOPTS = select({_MACOS: ["-Wl,-undefined,dynamic_lookup"], _WINDOWS: [], "//conditions:default": []}) +NATIVE_EMBEDDED_MODULE_LINKOPTS = select({_MACOS: ["-Wl,-rpath,@loader_path/.."], _WINDOWS: [], "//conditions:default": ["-Wl,-z,defs"]}) +NATIVE_LIBPQ_LINKOPTS = select({_MACOS: ["-Wl,-install_name,@rpath/libpq.5.dylib"], _WINDOWS: [], "//conditions:default": ["-Wl,-soname,libpq.so.5", "-Wl,-z,defs"]}) +NATIVE_RUNTIME_LINKOPTS = select({_MACOS: ["-Wl,-install_name,@rpath/liboliphaunt.dylib"], _WINDOWS: [], "//conditions:default": ["-Wl,-soname,liboliphaunt.so", "-Wl,-z,defs"]}) +NATIVE_EMBEDDED_DEFINES = select({ + _ANDROID: ["OLIPHAUNT_EMBEDDED_MOBILE_SHMEM"], + _IOS: ["OLIPHAUNT_EMBEDDED_MOBILE_SHMEM"], + "//conditions:default": [], +}) +NATIVE_BUILTIN_SNOWBALL = select({ + _ANDROID: ["OLIPHAUNT_BUILTIN_DICT_SNOWBALL"], + _IOS: ["OLIPHAUNT_BUILTIN_DICT_SNOWBALL"], + "//conditions:default": [], +}) +NATIVE_BUILTIN_SNOWBALL_DEPS = select({ + _ANDROID: ["@postgres//:snowball_builtin"], + _IOS: ["@postgres//:snowball_builtin"], + "//conditions:default": [], +}) diff --git a/build_defs/native/postgres-probe-header.test.mts b/build_defs/native/postgres-probe-header.test.mts new file mode 100644 index 000000000..f0a009b76 --- /dev/null +++ b/build_defs/native/postgres-probe-header.test.mts @@ -0,0 +1,20 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; + +const [headerPath, declarationsPath] = process.argv.slice(2); +assert(headerPath && declarationsPath, 'expected generated probes.h and upstream probes.d'); +const header = readFileSync(headerPath, 'utf8').replaceAll('\r\n', '\n'); +const declarations = readFileSync(declarationsPath, 'utf8'); +const probes = [...declarations.matchAll(/^\s*probe\s+([A-Za-z_][A-Za-z0-9_]*)\([^;]*\);/gm)]; +assert(probes.length > 0, 'upstream probes.d must declare probes'); +const macros = new Map( + [...header.matchAll(/^#define (TRACE_POSTGRESQL_[A-Z0-9_]+)\([^)]*\) ([^\n]*)$/gm)].map( + ([, name, body]) => [name, body], + ), +); + +for (const [, probe] of probes) { + const name = `TRACE_POSTGRESQL_${probe.replaceAll('__', '_').toUpperCase()}`; + assert.equal(macros.get(name), 'do {} while (0)', `${name} must be a generated no-op`); + assert.equal(macros.get(`${name}_ENABLED`), '(0)', `${name}_ENABLED must return zero`); +} diff --git a/build_defs/native/postgres.BUILD.bazel b/build_defs/native/postgres.BUILD.bazel new file mode 100644 index 000000000..31c8670d0 --- /dev/null +++ b/build_defs/native/postgres.BUILD.bazel @@ -0,0 +1,8 @@ +load("@oliphaunt//build_defs/native:postgres.bzl", "postgres_native_targets") +load(":version.bzl", "POSTGRES_VERSION") + +package(default_visibility = ["//visibility:public"]) + +exports_files(glob(["contrib/**", "src/include/**/*.h", "src/backend/catalog/*.sql", "src/bin/pg_dump/*.c"])) + +postgres_native_targets(version = POSTGRES_VERSION) diff --git a/build_defs/native/postgres.bzl b/build_defs/native/postgres.bzl new file mode 100644 index 000000000..aaf419fb6 --- /dev/null +++ b/build_defs/native/postgres.bzl @@ -0,0 +1,290 @@ +"""Direct PostgreSQL generator/C targets for the initial Linux x86_64 slice. + +No upstream Make/Meson/Configure producer is run by these targets. Optional +release-parity features remain separate gates; the local development profile +does not claim to be a publishable replacement for every native product. +""" + +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_import", "cc_library") +load(":config.bzl", "pg_config") +load(":generators.bzl", "postgres_bison", "postgres_flex", "postgres_perl") +load(":host_config.bzl", "postgres_host_configuration_targets") +load(":windows_link.bzl", "postgres_windows_exports", "postgres_windows_resource", "postgres_windows_server") +load(":platform_config.bzl", "NATIVE_CONFIG", "NATIVE_PROFILE", "NATIVE_C_COMPATIBLE", "NATIVE_PORT_REPLACEMENTS", "NATIVE_OS_HEADER", "NATIVE_BACKEND_PORT_SOURCES", "NATIVE_LINKOPTS", "NATIVE_RELEASE_LINKOPTS", "NATIVE_EMBEDDED_DEFINES", "NATIVE_CONFIGURATION", "NATIVE_CONFIGURATION_ADMISSION", "NATIVE_INCLUDE_DIRECTORIES", "NATIVE_HEADER_DEFINES", "NATIVE_COPTS", "NATIVE_BACKEND_DEFINES", "NATIVE_PORT_ADDITIONAL_SOURCES", "NATIVE_PORT_CRC_SOURCES", "NATIVE_LIBPQ_ADDITIONAL_SOURCES", "NATIVE_FRONTEND_LINKOPTS", "NATIVE_SERVER_LINKOPTS", "NATIVE_MODULE_LINKOPTS", "NATIVE_LIBPQ_LINKOPTS", "NATIVE_UNIX_COMPATIBLE", "NATIVE_ELF_C_COMPATIBLE", "NATIVE_MACOS_COMPATIBLE", "NATIVE_WINDOWS_COMPATIBLE") +load(":resources.bzl", "timezone_database") +load(":frontend_sources.bzl", "POSTGRES_DUMP_COMMON_SOURCES", "POSTGRES_DUMP_SOURCES", "POSTGRES_BASEBACKUP_COMMON_SOURCES", "POSTGRES_PSQL_SOURCES") +load(":postgres_sources.bzl", + "POSTGRES_BACKEND_SOURCES", + "POSTGRES_MAIN_SOURCES", + "POSTGRES_BACKEND_GENERATED_SOURCES", + "POSTGRES_BACKEND_FLEX_INPUTS", + "POSTGRES_BACKEND_BISON_INPUTS", + "POSTGRES_FLEX_OPTIONS", + "POSTGRES_BACKEND_TEXTUAL_SOURCES", + "POSTGRES_COMMON_SOURCES", + "POSTGRES_COMMON_RYU_SOURCES", + "POSTGRES_COMMON_CONFIG_INFO_SOURCES", + "POSTGRES_COMMON_BUILTIN_CRYPTO_SOURCES", + "POSTGRES_COMMON_FRONTEND_SHARED_ADDITIONAL_SOURCES", + "POSTGRES_COMMON_FRONTEND_STATIC_ADDITIONAL_SOURCES", + "POSTGRES_PORT_SOURCES", + "POSTGRES_PORT_CRC_GENERIC_SOURCES", + "POSTGRES_TIMEZONE_SOURCES", + "POSTGRES_ZIC_SOURCES", + "POSTGRES_SNOWBALL_SOURCES", + "POSTGRES_SNOWBALL_STOPWORDS", + "POSTGRES_SNOWBALL_SQL_INPUTS", + "POSTGRES_PLPGSQL_SOURCES", + "POSTGRES_PLPGSQL_GENERATED_SOURCES", + "POSTGRES_PLPGSQL_GENERATED_HEADERS", + "POSTGRES_LIBPQ_SOURCES", + "POSTGRES_INITDB_SOURCES", + "POSTGRES_PG_CONFIG_SOURCES", + "POSTGRES_FRONTEND_UTIL_SOURCES", + "POSTGRES_CATALOG_HEADERS", + "POSTGRES_CATALOG_DATA", + "POSTGRES_CATALOG_GENERATOR_EXTRA_INPUTS", + "POSTGRES_CATALOG_GENERATED_HEADERS", + "POSTGRES_NODE_GENERATOR_INPUTS", + "POSTGRES_NODE_GENERATED_TEXTUAL_SOURCES", + "POSTGRES_WAIT_EVENT_GENERATED_TEXTUAL_SOURCES", + "POSTGRES_BACKEND_GENERATED_HEADERS", + "POSTGRES_COMMON_GENERATED_HEADERS", + "POSTGRES_BACKEND_INCLUDE_DIRECTORIES", +) + +_COMPATIBLE = NATIVE_C_COMPATIBLE +_COPTS = NATIVE_COPTS +_LINKOPTS = NATIVE_LINKOPTS +_FRONTEND_LINKOPTS = NATIVE_FRONTEND_LINKOPTS + +def _locations(paths): + return ["$(location " + name + ")" for name in paths] + +def _perl(name, script, inputs, outputs, arguments, capture = False, options = []): + postgres_perl( + name = name, + script = script, + srcs = inputs, + outs = outputs, + arguments = arguments, + options = options, + capture_stdout = capture, + ) + +def _parser(name, source, output, scanner = False, options_override = None): + options = options_override.split(" ") if options_override != None else (POSTGRES_FLEX_OPTIONS.get(output, []) if scanner else ["-d"]) + outputs = [output] if scanner else [output, output[:-2] + ".h"] + generator = postgres_flex if scanner else postgres_bison + generator( + name = name, + src = source, + outs = outputs, + options = options, + ) + +def postgres_generated_targets(version): + """Generate upstream PG sources in the caller's patched source repository.""" + include_path = "$(dirname src/include/catalog/pg_proc.h)/.." + catalog_outputs = POSTGRES_CATALOG_GENERATED_HEADERS + ["src/include/catalog/postgres.bki", "src/include/catalog/system_constraints.sql"] + _perl("catalog", "src/backend/catalog/genbki.pl", POSTGRES_CATALOG_HEADERS + POSTGRES_CATALOG_DATA + POSTGRES_CATALOG_GENERATOR_EXTRA_INPUTS, catalog_outputs, + ["--include-path=" + include_path, "--set-version=" + version.split(".")[0], "--output=$(RULEDIR)/src/include/catalog"] + _locations(POSTGRES_CATALOG_HEADERS)) + _perl("nodes", "src/backend/nodes/gen_node_support.pl", POSTGRES_NODE_GENERATOR_INPUTS + ["src/backend/catalog/Catalog.pm"], POSTGRES_NODE_GENERATED_TEXTUAL_SOURCES, + ["-o", "$(RULEDIR)/src/include/nodes"] + _locations(POSTGRES_NODE_GENERATOR_INPUTS)) + _perl("wait_events", "src/backend/utils/activity/generate-wait_event_types.pl", ["src/backend/utils/activity/wait_event_names.txt"], POSTGRES_WAIT_EVENT_GENERATED_TEXTUAL_SOURCES, + ["--outdir", "$(RULEDIR)/src/include/utils", "--code", "$(location src/backend/utils/activity/wait_event_names.txt)"]) + _perl("errcodes", "src/backend/utils/generate-errcodes.pl", ["src/backend/utils/errcodes.txt"], ["src/include/utils/errcodes.h"], + ["--outfile", "$@", "$(location src/backend/utils/errcodes.txt)"]) + _perl("dummy_probes", "src/backend/utils/Gen_dummy_probes.pl", ["src/backend/utils/probes.d"], ["src/include/utils/probes.h"], + ["$(location src/backend/utils/probes.d)"], capture = True, options = ["-n"]) + _perl("fmgrtab", "src/backend/utils/Gen_fmgrtab.pl", ["src/include/catalog/pg_proc.h", "src/include/catalog/pg_proc.dat", "src/backend/catalog/Catalog.pm"], + ["src/include/utils/fmgroids.h", "src/include/utils/fmgrprotos.h", "src/include/utils/fmgrtab.c"], + ["--include-path=" + include_path, "--output=$(RULEDIR)/src/include/utils", "$(location src/include/catalog/pg_proc.dat)"], + options = ["-I", "$(dirname src/backend/catalog/Catalog.pm)"]) + _perl("lwlocks", "src/backend/storage/lmgr/generate-lwlocknames.pl", ["src/include/storage/lwlocklist.h", "src/backend/utils/activity/wait_event_names.txt"], ["src/include/storage/lwlocknames.h"], + ["-o", "$(RULEDIR)/src/include/storage", "$(location src/include/storage/lwlocklist.h)", "$(location src/backend/utils/activity/wait_event_names.txt)"]) + _perl("keywords", "src/tools/gen_keywordlist.pl", ["src/tools/PerfectHash.pm", "src/include/parser/kwlist.h"], POSTGRES_COMMON_GENERATED_HEADERS, + ["--output", "$(RULEDIR)/src/common", "--extern", "$(location src/include/parser/kwlist.h)"]) + for output, source in POSTGRES_BACKEND_BISON_INPUTS.items(): + _parser("bison_" + output.rsplit("/", 1)[1][:-2], source, output) + for output, source in POSTGRES_BACKEND_FLEX_INPUTS.items(): + _parser("flex_" + output.rsplit("/", 1)[1][:-2].replace("-", "_"), source, output, scanner = True) + _parser("plpgsql_grammar", "src/pl/plpgsql/src/pl_gram.y", "src/pl/plpgsql/src/pl_gram.c") + _perl("plpgsql_errcodes", "src/pl/plpgsql/src/generate-plerrcodes.pl", ["src/backend/utils/errcodes.txt"], ["src/pl/plpgsql/src/plerrcodes.h"], + ["$(location src/backend/utils/errcodes.txt)"], capture = True) + for kind, variable in [("reserved", "ReservedPLKeywords"), ("unreserved", "UnreservedPLKeywords")]: + source = "src/pl/plpgsql/src/pl_" + kind + "_kwlist.h" + _perl("plpgsql_" + kind, "src/tools/gen_keywordlist.pl", ["src/tools/PerfectHash.pm", source], [source[:-2] + "_d.h"], + ["--output", "$(RULEDIR)/src/pl/plpgsql/src", "--varname", variable, "$(location " + source + ")"]) + _perl("snowball_sql", "src/backend/snowball/snowball_create.pl", POSTGRES_SNOWBALL_SQL_INPUTS, + ["src/backend/snowball/snowball_create.sql"], + ["--input", "$(dirname src/backend/snowball/snowball.sql.in)", "--outdir", "$(RULEDIR)/src/backend/snowball"]) + +def postgres_frontend_generated_targets(): + """Generate frontend scanners/completion/help in the caller's PG source.""" + _parser("frontend_scan", "src/fe_utils/psqlscan.l", "src/fe_utils/psqlscan.c", scanner = True) + _parser("psql_slash_scan", "src/bin/psql/psqlscanslash.l", "src/bin/psql/psqlscanslash.c", scanner = True, options_override = "-Cfe -p -p") + _perl("psql_completion", "src/bin/psql/gen_tabcomplete.pl", ["src/bin/psql/tab-complete.in.c"], ["src/bin/psql/tab-complete.c"], + ["$(location src/bin/psql/tab-complete.in.c)", "--outfile", "$@"]) + help_inputs = native.glob(["doc/src/sgml/ref/*.sgml"]) + _perl("psql_help", "src/bin/psql/create_help.pl", help_inputs, ["src/bin/psql/sql_help.c", "src/bin/psql/sql_help.h"], + ["--docdir", "$(dirname " + help_inputs[0] + ")", "--outdir", "$(RULEDIR)/src/bin/psql", "--basename", "sql_help"]) + +def postgres_native_targets(version): + """Declare explicit sources and generated outputs, separately by ABI role.""" + pg_config(name = "static_configuration", template = "src/include/pg_config.h.in", os_header = NATIVE_OS_HEADER, version = version, + values = NATIVE_CONFIG, profile = NATIVE_PROFILE) + postgres_host_configuration_targets(version) + native.filegroup(name = "configuration", srcs = NATIVE_CONFIGURATION) + postgres_generated_targets(version) + postgres_frontend_generated_targets() + generated_headers = POSTGRES_CATALOG_GENERATED_HEADERS + POSTGRES_NODE_GENERATED_TEXTUAL_SOURCES + POSTGRES_WAIT_EVENT_GENERATED_TEXTUAL_SOURCES + POSTGRES_BACKEND_GENERATED_HEADERS + POSTGRES_COMMON_GENERATED_HEADERS + POSTGRES_PLPGSQL_GENERATED_HEADERS + cc_library( + name = "server_headers", + hdrs = native.glob(["src/include/**/*.h", "src/backend/**/*.h", "src/common/**/*.h", "src/pl/plpgsql/src/*.h", "src/interfaces/libpq/*.h", "src/timezone/*.h"]) + generated_headers + [":configuration"], + textual_hdrs = POSTGRES_BACKEND_TEXTUAL_SOURCES, + deps = ["@icu//:i18n_headers"] + NATIVE_CONFIGURATION_ADMISSION, + includes = NATIVE_INCLUDE_DIRECTORIES + POSTGRES_BACKEND_INCLUDE_DIRECTORIES + ["src/common", "src/pl/plpgsql/src", "src/interfaces/libpq", "src/include/snowball", "src/timezone"], + defines = NATIVE_HEADER_DEFINES, + target_compatible_with = _COMPATIBLE, + ) + cc_library(name = "embedded_headers", deps = [":server_headers"], defines = ["OLIPHAUNT_EMBEDDED"] + NATIVE_EMBEDDED_DEFINES, target_compatible_with = _COMPATIBLE) + common_sources = POSTGRES_COMMON_SOURCES + POSTGRES_COMMON_RYU_SOURCES + POSTGRES_COMMON_CONFIG_INFO_SOURCES + POSTGRES_COMMON_BUILTIN_CRYPTO_SOURCES + port_sources = POSTGRES_PORT_SOURCES + NATIVE_PORT_CRC_SOURCES + NATIVE_PORT_ADDITIONAL_SOURCES + NATIVE_PORT_REPLACEMENTS + for role, headers, definitions, additions in [ + ("server", ":server_headers", [], []), + ("embedded", ":embedded_headers", [], []), + ("frontend", ":server_headers", ["FRONTEND", "USE_PRIVATE_ENCODING_FUNCS"], POSTGRES_COMMON_FRONTEND_SHARED_ADDITIONAL_SOURCES + POSTGRES_COMMON_FRONTEND_STATIC_ADDITIONAL_SOURCES), + ]: + core_definitions = NATIVE_BACKEND_DEFINES if role != "frontend" else [] + cc_library(name = "common_" + role, srcs = common_sources + additions, deps = [headers], local_defines = definitions + core_definitions, copts = _COPTS, linkopts = _LINKOPTS, target_compatible_with = _COMPATIBLE) + cc_library(name = "port_" + role, srcs = port_sources, deps = [headers], local_defines = definitions + core_definitions, copts = _COPTS, target_compatible_with = _COMPATIBLE) + if role != "frontend": + cc_library(name = "timezone_" + role, srcs = POSTGRES_TIMEZONE_SOURCES, deps = [headers], local_defines = core_definitions, copts = _COPTS, target_compatible_with = _COMPATIBLE) + cc_library(name = "backend_" + role, srcs = POSTGRES_BACKEND_SOURCES + NATIVE_BACKEND_PORT_SOURCES + POSTGRES_BACKEND_GENERATED_SOURCES, + deps = [headers, ":common_" + role, ":port_" + role, ":timezone_" + role, "@icu//:i18n"], + local_defines = core_definitions, copts = _COPTS, alwayslink = True, target_compatible_with = _COMPATIBLE) + cc_library(name = "plpgsql_" + role, srcs = POSTGRES_PLPGSQL_SOURCES + POSTGRES_PLPGSQL_GENERATED_SOURCES, + deps = [headers], copts = _COPTS, alwayslink = True, target_compatible_with = _COMPATIBLE) + cc_library(name = "snowball_" + role, srcs = POSTGRES_SNOWBALL_SOURCES, deps = [headers], copts = _COPTS, alwayslink = True, target_compatible_with = _COMPATIBLE) + cc_library(name = "snowball_builtin", srcs = POSTGRES_SNOWBALL_SOURCES, deps = [":embedded_headers"], + local_defines = ["Pg_magic_func=oliphaunt_builtin_dict_snowball_Pg_magic_func"], + copts = _COPTS, alwayslink = True, target_compatible_with = _COMPATIBLE) + # MSVC builtin objects produce engine DATA; module objects import it. + cc_library(name = "plpgsql_builtin_windows", srcs = POSTGRES_PLPGSQL_SOURCES + POSTGRES_PLPGSQL_GENERATED_SOURCES, + deps = [":embedded_headers"], local_defines = NATIVE_BACKEND_DEFINES, copts = _COPTS, alwayslink = True, target_compatible_with = NATIVE_WINDOWS_COMPATIBLE) + # libpq exports public encoding functions and must not pull frontend logging + # or exit-on-OOM implementations. Keep upstream's shared/frontend role split. + cc_library(name = "common_frontend_shlib", srcs = common_sources + POSTGRES_COMMON_FRONTEND_SHARED_ADDITIONAL_SOURCES, + deps = [":server_headers"], local_defines = ["FRONTEND", "JSONAPI_USE_PQEXPBUFFER"], + copts = _COPTS, linkopts = _LINKOPTS, target_compatible_with = _COMPATIBLE) + cc_library(name = "libpq_objects", srcs = POSTGRES_LIBPQ_SOURCES + NATIVE_LIBPQ_ADDITIONAL_SOURCES, deps = [":server_headers", ":common_frontend_shlib", ":port_frontend"], local_defines = ["FRONTEND", "SO_MAJOR_VERSION=5"], copts = _COPTS, alwayslink = True, target_compatible_with = _COMPATIBLE) + cc_binary(name = "libpq.so", deps = [":libpq_objects"], linkshared = True, + features = ["-soname"], linkopts = NATIVE_LIBPQ_LINKOPTS + _LINKOPTS + NATIVE_RELEASE_LINKOPTS, target_compatible_with = NATIVE_ELF_C_COMPATIBLE) + cc_binary(name = "libpq.dylib", deps = [":libpq_objects"], linkshared = True, linkopts = NATIVE_LIBPQ_LINKOPTS + _LINKOPTS, target_compatible_with = NATIVE_MACOS_COMPATIBLE) + _postgres_windows_targets() + native.alias(name = "libpq_shared", actual = select({"@oliphaunt//build_defs/native:macos_arm64": ":libpq.dylib", "@oliphaunt//build_defs/native:windows_x64": ":libpq.dll", "//conditions:default": ":libpq.so"})) + cc_import(name = "libpq", shared_library = ":libpq_shared", interface_library = select({"@oliphaunt//build_defs/native:windows_x64": ":libpq_windows_interface", "//conditions:default": None}), target_compatible_with = _COMPATIBLE) + # Match upstream fe_utils Windows Winsock capacity without exporting it to other targets. + cc_library(name = "frontend_utils", srcs = POSTGRES_FRONTEND_UTIL_SOURCES + ["src/fe_utils/psqlscan.c"], + deps = [":server_headers", ":common_frontend", ":port_frontend", ":libpq"], + defines = ["FRONTEND"], + local_defines = select({"@oliphaunt//build_defs/native:windows_x64": ["FD_SETSIZE=1024"], "//conditions:default": []}), + copts = _COPTS, target_compatible_with = _COMPATIBLE) + cc_library(name = "tools_headers", hdrs = native.glob(["src/bin/pg_dump/*.h", "src/bin/pg_basebackup/*.h", "src/bin/psql/*.h"]) + ["src/bin/psql/sql_help.h"], + deps = [":server_headers"], includes = ["src/bin/pg_dump", "src/bin/pg_basebackup", "src/bin/psql"], target_compatible_with = _COMPATIBLE) + frontend_deps = [":server_headers", ":common_frontend", ":port_frontend", ":libpq", ":frontend_utils"] + cc_binary(name = "pg_ctl", srcs = ["src/bin/pg_ctl/pg_ctl.c"], deps = [":server_headers", ":common_frontend", ":port_frontend"] + select({"@oliphaunt//build_defs/native:windows_x64": [":libpq"], "//conditions:default": []}), + defines = ["FRONTEND"], copts = _COPTS, linkopts = NATIVE_RELEASE_LINKOPTS, target_compatible_with = _COMPATIBLE) + cc_binary(name = "pg_config", srcs = POSTGRES_PG_CONFIG_SOURCES, deps = [":server_headers", ":common_frontend", ":port_frontend"], + defines = ["FRONTEND"], copts = _COPTS, target_compatible_with = _COMPATIBLE) + cc_library(name = "dump_common", srcs = POSTGRES_DUMP_COMMON_SOURCES, deps = frontend_deps + [":tools_headers"], + defines = ["FRONTEND"], copts = _COPTS, target_compatible_with = _COMPATIBLE) + cc_binary(name = "pg_dump", srcs = POSTGRES_DUMP_SOURCES, deps = frontend_deps + [":tools_headers", ":dump_common"], + defines = ["FRONTEND"], copts = _COPTS, linkopts = _FRONTEND_LINKOPTS + NATIVE_RELEASE_LINKOPTS, target_compatible_with = _COMPATIBLE) + cc_library(name = "basebackup_common", srcs = POSTGRES_BASEBACKUP_COMMON_SOURCES, deps = frontend_deps + [":tools_headers"], + defines = ["FRONTEND"], copts = _COPTS, target_compatible_with = _COMPATIBLE) + cc_binary(name = "pg_basebackup", srcs = ["src/bin/pg_basebackup/pg_basebackup.c"], deps = frontend_deps + [":tools_headers", ":basebackup_common"], + defines = ["FRONTEND"], copts = _COPTS, linkopts = _FRONTEND_LINKOPTS + NATIVE_RELEASE_LINKOPTS, target_compatible_with = _COMPATIBLE) + cc_binary(name = "psql", srcs = POSTGRES_PSQL_SOURCES + ["src/bin/psql/psqlscanslash.c", "src/bin/psql/tab-complete.c", "src/bin/psql/sql_help.c"], + deps = frontend_deps + [":tools_headers"], defines = ["FRONTEND"], copts = _COPTS, linkopts = _FRONTEND_LINKOPTS + NATIVE_RELEASE_LINKOPTS, target_compatible_with = _COMPATIBLE) + # Original PostgreSQL regression driver, constructed only by test consumers. + cc_binary( + name = "pg_regress", + srcs = ["src/test/regress/pg_regress.c", "src/test/regress/pg_regress_main.c", "src/test/regress/pg_regress.h"], + deps = [":server_headers", ":common_frontend", ":port_frontend", ":libpq"], + defines = ["FRONTEND"], + copts = _COPTS + ["-DSHELLPROG=\\\"/bin/sh\\\""] + select({ + "@oliphaunt//build_defs/native:linux_aarch64_gnu_2_28": ["-DHOST_TUPLE=\\\"aarch64-unknown-linux-gnu\\\""], + "//conditions:default": ["-DHOST_TUPLE=\\\"x86_64-pc-linux-gnu\\\""], + }), + linkopts = _FRONTEND_LINKOPTS + NATIVE_RELEASE_LINKOPTS, + target_compatible_with = select({ + "@oliphaunt//build_defs/native:linux_x86_64": [], + "@oliphaunt//build_defs/native:linux_aarch64_gnu_2_28": [], + "//conditions:default": ["@platforms//:incompatible"], + }), + testonly = True, + ) + cc_library(name = "initdb_frontend_utils", srcs = ["src/fe_utils/option_utils.c", "src/fe_utils/string_utils.c"], + deps = [":server_headers", ":common_frontend", ":port_frontend", ":libpq"], defines = ["FRONTEND"], copts = _COPTS, target_compatible_with = _COMPATIBLE) + cc_binary(name = "postgres", srcs = POSTGRES_MAIN_SOURCES, deps = [":backend_server"], copts = _COPTS, + linkopts = NATIVE_SERVER_LINKOPTS + _LINKOPTS + NATIVE_RELEASE_LINKOPTS, target_compatible_with = NATIVE_UNIX_COMPATIBLE) + native.alias(name = "server_executable", actual = select({"@oliphaunt//build_defs/native:windows_x64": ":postgres_windows", "//conditions:default": ":postgres"})) + cc_library(name = "main_embedded", srcs = POSTGRES_MAIN_SOURCES, deps = [":embedded_headers"], + local_defines = ["main=oliphaunt_postgres_main"] + NATIVE_BACKEND_DEFINES, copts = _COPTS, target_compatible_with = _COMPATIBLE) + cc_binary(name = "initdb", srcs = POSTGRES_INITDB_SOURCES, deps = [":server_headers", ":common_frontend", ":port_frontend", ":libpq", ":initdb_frontend_utils", "@icu//:i18n"], + defines = ["FRONTEND", "USE_PRIVATE_ENCODING_FUNCS"], copts = _COPTS, linkopts = _LINKOPTS + _FRONTEND_LINKOPTS + NATIVE_RELEASE_LINKOPTS, target_compatible_with = _COMPATIBLE) + cc_library(name = "zic_headers", hdrs = [ + "src/include/c.h", "src/include/pg_config_manual.h", "src/include/postgres_ext.h", "src/include/port.h", + "src/include/postgres_fe.h", "src/include/common/fe_memutils.h", "src/include/pg_getopt.h", "src/include/pgtime.h", "src/include/lib/sort_template.h", + "src/timezone/private.h", "src/timezone/tzfile.h", ":configuration", + ] + select({"@oliphaunt//build_defs/native:windows_x64": native.glob(["src/include/port/win32/**/*.h", "src/include/port/win32_msvc/**/*.h"]), "//conditions:default": []}), + includes = NATIVE_INCLUDE_DIRECTORIES + ["src/include", "src/timezone"], defines = NATIVE_HEADER_DEFINES, deps = NATIVE_CONFIGURATION_ADMISSION, target_compatible_with = _COMPATIBLE) + cc_library(name = "zic_port", srcs = ["src/port/qsort.c", "src/port/snprintf.c", "src/port/strerror.c"], deps = [":zic_headers"], + defines = ["FRONTEND"], copts = _COPTS, linkopts = select({"@oliphaunt//build_defs/native:windows_x64": [], "//conditions:default": ["-lm"]}), target_compatible_with = NATIVE_UNIX_COMPATIBLE) + cc_binary(name = "zic", srcs = POSTGRES_ZIC_SOURCES, deps = [":zic_headers"] + select({"@oliphaunt//build_defs/native:windows_x64": [":common_frontend", ":port_frontend"], "//conditions:default": [":zic_port"]}), + defines = ["FRONTEND"], copts = _COPTS, target_compatible_with = _COMPATIBLE) + timezone_database(name = "timezone", source = "src/timezone/data/tzdata.zi", zic = ":zic") + for name, dependency in [("plpgsql", ":plpgsql_server"), ("dict_snowball", ":snowball_server")]: + cc_binary(name = name + ".so", deps = [dependency], linkshared = True, linkopts = NATIVE_RELEASE_LINKOPTS, target_compatible_with = NATIVE_ELF_C_COMPATIBLE) + cc_binary(name = name + ".dylib", deps = [dependency], linkshared = True, linkopts = NATIVE_MODULE_LINKOPTS, target_compatible_with = NATIVE_MACOS_COMPATIBLE) + cc_binary(name = name + ".dll", deps = [dependency, ":server_import_library"], linkshared = True, target_compatible_with = NATIVE_WINDOWS_COMPATIBLE) + native.alias(name = name + "_module", actual = select({"@oliphaunt//build_defs/native:macos_arm64": ":" + name + ".dylib", "@oliphaunt//build_defs/native:windows_x64": ":" + name + ".dll", "//conditions:default": ":" + name + ".so"})) + postgres_resource_targets() + +def _postgres_windows_targets(): + _perl("libpq_windows_exports", "src/tools/gen_export.pl", ["src/interfaces/libpq/exports.txt"], ["libpq.def"], + ["--format", "win", "--libname", "libpq", "--input", "$(location src/interfaces/libpq/exports.txt)", "--output", "$@"]) + cc_binary(name = "libpq.dll", deps = [":libpq_objects"], linkshared = True, win_def_file = "libpq.def", features = ["no_windows_export_all_symbols"], + linkopts = _LINKOPTS, target_compatible_with = NATIVE_WINDOWS_COMPATIBLE) + native.filegroup(name = "libpq_windows_interface", srcs = [":libpq.dll"], output_group = "interface_library", target_compatible_with = NATIVE_WINDOWS_COMPATIBLE) + cc_library(name = "main_server_windows", srcs = POSTGRES_MAIN_SOURCES, deps = [":server_headers"], local_defines = NATIVE_BACKEND_DEFINES, copts = _COPTS, target_compatible_with = NATIVE_WINDOWS_COMPATIBLE) + postgres_windows_exports(name = "server_windows_exports", roots = [":backend_server", ":main_server_windows"], target_compatible_with = NATIVE_WINDOWS_COMPATIBLE) + postgres_windows_resource(name = "server_windows_resource", template = "src/port/win32ver.rc", configuration = ":configuration", filename = "postgres.exe", description = "PostgreSQL Server", icon = "src/port/win32.ico", target_compatible_with = NATIVE_WINDOWS_COMPATIBLE) + postgres_windows_server(name = "postgres_windows", deps = [":backend_server", ":main_server_windows"], exports = ":server_windows_exports", resources = [":server_windows_resource"], linkopts = _LINKOPTS, target_compatible_with = NATIVE_WINDOWS_COMPATIBLE) + native.filegroup(name = "server_windows_interface", srcs = [":postgres_windows"], output_group = "interface_library", target_compatible_with = NATIVE_WINDOWS_COMPATIBLE) + cc_import(name = "server_import_library", interface_library = ":server_windows_interface", system_provided = True, target_compatible_with = NATIVE_WINDOWS_COMPATIBLE) + +def postgres_resource_targets(): + """Declare resources in the caller's actual patched/generated PG context.""" + native.filegroup(name = "catalog_runtime_data", srcs = [ + "src/include/catalog/postgres.bki", + "src/include/catalog/system_constraints.sql", + "src/backend/snowball/snowball_create.sql", + "src/backend/catalog/information_schema.sql", + "src/backend/catalog/system_functions.sql", + "src/backend/catalog/system_views.sql", + "src/backend/catalog/sql_features.txt", + "src/backend/utils/misc/postgresql.conf.sample", + "src/backend/libpq/pg_hba.conf.sample", + "src/backend/libpq/pg_ident.conf.sample", + ]) + native.filegroup(name = "stopwords", srcs = POSTGRES_SNOWBALL_STOPWORDS) + native.filegroup(name = "timezone_abbreviations", srcs = native.glob(["src/timezone/tznames/*"], exclude = ["src/timezone/tznames/README"])) + native.filegroup(name = "license", srcs = ["COPYRIGHT"]) + native.filegroup(name = "builtin_extension_data", srcs = native.glob(["src/pl/plpgsql/src/plpgsql.control", "src/pl/plpgsql/src/plpgsql--*.sql"])) + directories = {control.rsplit("/", 1)[0]: True for control in native.glob(["contrib/*/*.control"])} + for directory in directories: + name = directory.split("/")[-1].replace("-", "_") + native.filegroup(name = "contrib_" + name + "_resources", srcs = native.glob([directory + "/*.control", directory + "/*--*.sql", directory + "/*.rules"], allow_empty = True)) diff --git a/build_defs/native/postgres_sources.bzl b/build_defs/native/postgres_sources.bzl new file mode 100644 index 000000000..9b82b4fbf --- /dev/null +++ b/build_defs/native/postgres_sources.bzl @@ -0,0 +1,1475 @@ +"""Explicit PostgreSQL 18.4 source inventories for native compilation. + +Paths are relative to the pinned @postgres repository root. These lists were +checked against the release's recursive backend Meson lists and Make OBJS; +no upstream build system is invoked to discover or compile sources. + +The Linux variant uses POSIX semaphores and SysV shared memory. Optional TLS, +GSSAPI, CPU CRC implementations and libc replacements are separate so that +source selection agrees with the generated pg_config.h. Server and frontend +support libraries compile separately: FRONTEND changes their implementation. +Generated C fragments in *_TEXTUAL_SOURCES are included by translation units +and must be declared as headers, never compiled as independent sources. +""" +# All ordinary backend units, including the non-LLVM JIT dispatcher. +POSTGRES_BACKEND_SOURCES = [ + "src/backend/access/brin/brin.c", + "src/backend/access/brin/brin_bloom.c", + "src/backend/access/brin/brin_inclusion.c", + "src/backend/access/brin/brin_minmax.c", + "src/backend/access/brin/brin_minmax_multi.c", + "src/backend/access/brin/brin_pageops.c", + "src/backend/access/brin/brin_revmap.c", + "src/backend/access/brin/brin_tuple.c", + "src/backend/access/brin/brin_validate.c", + "src/backend/access/brin/brin_xlog.c", + "src/backend/access/common/attmap.c", + "src/backend/access/common/bufmask.c", + "src/backend/access/common/detoast.c", + "src/backend/access/common/heaptuple.c", + "src/backend/access/common/indextuple.c", + "src/backend/access/common/printsimple.c", + "src/backend/access/common/printtup.c", + "src/backend/access/common/relation.c", + "src/backend/access/common/reloptions.c", + "src/backend/access/common/scankey.c", + "src/backend/access/common/session.c", + "src/backend/access/common/syncscan.c", + "src/backend/access/common/tidstore.c", + "src/backend/access/common/toast_compression.c", + "src/backend/access/common/toast_internals.c", + "src/backend/access/common/tupconvert.c", + "src/backend/access/common/tupdesc.c", + "src/backend/access/gin/ginarrayproc.c", + "src/backend/access/gin/ginbtree.c", + "src/backend/access/gin/ginbulk.c", + "src/backend/access/gin/gindatapage.c", + "src/backend/access/gin/ginentrypage.c", + "src/backend/access/gin/ginfast.c", + "src/backend/access/gin/ginget.c", + "src/backend/access/gin/gininsert.c", + "src/backend/access/gin/ginlogic.c", + "src/backend/access/gin/ginpostinglist.c", + "src/backend/access/gin/ginscan.c", + "src/backend/access/gin/ginutil.c", + "src/backend/access/gin/ginvacuum.c", + "src/backend/access/gin/ginvalidate.c", + "src/backend/access/gin/ginxlog.c", + "src/backend/access/gist/gist.c", + "src/backend/access/gist/gistbuild.c", + "src/backend/access/gist/gistbuildbuffers.c", + "src/backend/access/gist/gistget.c", + "src/backend/access/gist/gistproc.c", + "src/backend/access/gist/gistscan.c", + "src/backend/access/gist/gistsplit.c", + "src/backend/access/gist/gistutil.c", + "src/backend/access/gist/gistvacuum.c", + "src/backend/access/gist/gistvalidate.c", + "src/backend/access/gist/gistxlog.c", + "src/backend/access/hash/hash.c", + "src/backend/access/hash/hash_xlog.c", + "src/backend/access/hash/hashfunc.c", + "src/backend/access/hash/hashinsert.c", + "src/backend/access/hash/hashovfl.c", + "src/backend/access/hash/hashpage.c", + "src/backend/access/hash/hashsearch.c", + "src/backend/access/hash/hashsort.c", + "src/backend/access/hash/hashutil.c", + "src/backend/access/hash/hashvalidate.c", + "src/backend/access/heap/heapam.c", + "src/backend/access/heap/heapam_handler.c", + "src/backend/access/heap/heapam_visibility.c", + "src/backend/access/heap/heapam_xlog.c", + "src/backend/access/heap/heaptoast.c", + "src/backend/access/heap/hio.c", + "src/backend/access/heap/pruneheap.c", + "src/backend/access/heap/rewriteheap.c", + "src/backend/access/heap/vacuumlazy.c", + "src/backend/access/heap/visibilitymap.c", + "src/backend/access/index/amapi.c", + "src/backend/access/index/amvalidate.c", + "src/backend/access/index/genam.c", + "src/backend/access/index/indexam.c", + "src/backend/access/nbtree/nbtcompare.c", + "src/backend/access/nbtree/nbtdedup.c", + "src/backend/access/nbtree/nbtinsert.c", + "src/backend/access/nbtree/nbtpage.c", + "src/backend/access/nbtree/nbtpreprocesskeys.c", + "src/backend/access/nbtree/nbtree.c", + "src/backend/access/nbtree/nbtsearch.c", + "src/backend/access/nbtree/nbtsort.c", + "src/backend/access/nbtree/nbtsplitloc.c", + "src/backend/access/nbtree/nbtutils.c", + "src/backend/access/nbtree/nbtvalidate.c", + "src/backend/access/nbtree/nbtxlog.c", + "src/backend/access/rmgrdesc/brindesc.c", + "src/backend/access/rmgrdesc/clogdesc.c", + "src/backend/access/rmgrdesc/committsdesc.c", + "src/backend/access/rmgrdesc/dbasedesc.c", + "src/backend/access/rmgrdesc/genericdesc.c", + "src/backend/access/rmgrdesc/gindesc.c", + "src/backend/access/rmgrdesc/gistdesc.c", + "src/backend/access/rmgrdesc/hashdesc.c", + "src/backend/access/rmgrdesc/heapdesc.c", + "src/backend/access/rmgrdesc/logicalmsgdesc.c", + "src/backend/access/rmgrdesc/mxactdesc.c", + "src/backend/access/rmgrdesc/nbtdesc.c", + "src/backend/access/rmgrdesc/relmapdesc.c", + "src/backend/access/rmgrdesc/replorigindesc.c", + "src/backend/access/rmgrdesc/rmgrdesc_utils.c", + "src/backend/access/rmgrdesc/seqdesc.c", + "src/backend/access/rmgrdesc/smgrdesc.c", + "src/backend/access/rmgrdesc/spgdesc.c", + "src/backend/access/rmgrdesc/standbydesc.c", + "src/backend/access/rmgrdesc/tblspcdesc.c", + "src/backend/access/rmgrdesc/xactdesc.c", + "src/backend/access/rmgrdesc/xlogdesc.c", + "src/backend/access/sequence/sequence.c", + "src/backend/access/spgist/spgdoinsert.c", + "src/backend/access/spgist/spginsert.c", + "src/backend/access/spgist/spgkdtreeproc.c", + "src/backend/access/spgist/spgproc.c", + "src/backend/access/spgist/spgquadtreeproc.c", + "src/backend/access/spgist/spgscan.c", + "src/backend/access/spgist/spgtextproc.c", + "src/backend/access/spgist/spgutils.c", + "src/backend/access/spgist/spgvacuum.c", + "src/backend/access/spgist/spgvalidate.c", + "src/backend/access/spgist/spgxlog.c", + "src/backend/access/table/table.c", + "src/backend/access/table/tableam.c", + "src/backend/access/table/tableamapi.c", + "src/backend/access/table/toast_helper.c", + "src/backend/access/tablesample/bernoulli.c", + "src/backend/access/tablesample/system.c", + "src/backend/access/tablesample/tablesample.c", + "src/backend/access/transam/clog.c", + "src/backend/access/transam/commit_ts.c", + "src/backend/access/transam/generic_xlog.c", + "src/backend/access/transam/multixact.c", + "src/backend/access/transam/parallel.c", + "src/backend/access/transam/rmgr.c", + "src/backend/access/transam/slru.c", + "src/backend/access/transam/subtrans.c", + "src/backend/access/transam/timeline.c", + "src/backend/access/transam/transam.c", + "src/backend/access/transam/twophase.c", + "src/backend/access/transam/twophase_rmgr.c", + "src/backend/access/transam/varsup.c", + "src/backend/access/transam/xact.c", + "src/backend/access/transam/xlog.c", + "src/backend/access/transam/xlogarchive.c", + "src/backend/access/transam/xlogbackup.c", + "src/backend/access/transam/xlogfuncs.c", + "src/backend/access/transam/xloginsert.c", + "src/backend/access/transam/xlogprefetcher.c", + "src/backend/access/transam/xlogreader.c", + "src/backend/access/transam/xlogrecovery.c", + "src/backend/access/transam/xlogstats.c", + "src/backend/access/transam/xlogutils.c", + "src/backend/archive/shell_archive.c", + "src/backend/backup/backup_manifest.c", + "src/backend/backup/basebackup.c", + "src/backend/backup/basebackup_copy.c", + "src/backend/backup/basebackup_gzip.c", + "src/backend/backup/basebackup_incremental.c", + "src/backend/backup/basebackup_lz4.c", + "src/backend/backup/basebackup_progress.c", + "src/backend/backup/basebackup_server.c", + "src/backend/backup/basebackup_sink.c", + "src/backend/backup/basebackup_target.c", + "src/backend/backup/basebackup_throttle.c", + "src/backend/backup/basebackup_zstd.c", + "src/backend/backup/walsummary.c", + "src/backend/backup/walsummaryfuncs.c", + "src/backend/bootstrap/bootstrap.c", + "src/backend/catalog/aclchk.c", + "src/backend/catalog/catalog.c", + "src/backend/catalog/dependency.c", + "src/backend/catalog/heap.c", + "src/backend/catalog/index.c", + "src/backend/catalog/indexing.c", + "src/backend/catalog/namespace.c", + "src/backend/catalog/objectaccess.c", + "src/backend/catalog/objectaddress.c", + "src/backend/catalog/partition.c", + "src/backend/catalog/pg_aggregate.c", + "src/backend/catalog/pg_attrdef.c", + "src/backend/catalog/pg_cast.c", + "src/backend/catalog/pg_class.c", + "src/backend/catalog/pg_collation.c", + "src/backend/catalog/pg_constraint.c", + "src/backend/catalog/pg_conversion.c", + "src/backend/catalog/pg_db_role_setting.c", + "src/backend/catalog/pg_depend.c", + "src/backend/catalog/pg_enum.c", + "src/backend/catalog/pg_inherits.c", + "src/backend/catalog/pg_largeobject.c", + "src/backend/catalog/pg_namespace.c", + "src/backend/catalog/pg_operator.c", + "src/backend/catalog/pg_parameter_acl.c", + "src/backend/catalog/pg_proc.c", + "src/backend/catalog/pg_publication.c", + "src/backend/catalog/pg_range.c", + "src/backend/catalog/pg_shdepend.c", + "src/backend/catalog/pg_subscription.c", + "src/backend/catalog/pg_type.c", + "src/backend/catalog/storage.c", + "src/backend/catalog/toasting.c", + "src/backend/commands/aggregatecmds.c", + "src/backend/commands/alter.c", + "src/backend/commands/amcmds.c", + "src/backend/commands/analyze.c", + "src/backend/commands/async.c", + "src/backend/commands/cluster.c", + "src/backend/commands/collationcmds.c", + "src/backend/commands/comment.c", + "src/backend/commands/constraint.c", + "src/backend/commands/conversioncmds.c", + "src/backend/commands/copy.c", + "src/backend/commands/copyfrom.c", + "src/backend/commands/copyfromparse.c", + "src/backend/commands/copyto.c", + "src/backend/commands/createas.c", + "src/backend/commands/dbcommands.c", + "src/backend/commands/define.c", + "src/backend/commands/discard.c", + "src/backend/commands/dropcmds.c", + "src/backend/commands/event_trigger.c", + "src/backend/commands/explain.c", + "src/backend/commands/explain_dr.c", + "src/backend/commands/explain_format.c", + "src/backend/commands/explain_state.c", + "src/backend/commands/extension.c", + "src/backend/commands/foreigncmds.c", + "src/backend/commands/functioncmds.c", + "src/backend/commands/indexcmds.c", + "src/backend/commands/lockcmds.c", + "src/backend/commands/matview.c", + "src/backend/commands/opclasscmds.c", + "src/backend/commands/operatorcmds.c", + "src/backend/commands/policy.c", + "src/backend/commands/portalcmds.c", + "src/backend/commands/prepare.c", + "src/backend/commands/proclang.c", + "src/backend/commands/publicationcmds.c", + "src/backend/commands/schemacmds.c", + "src/backend/commands/seclabel.c", + "src/backend/commands/sequence.c", + "src/backend/commands/statscmds.c", + "src/backend/commands/subscriptioncmds.c", + "src/backend/commands/tablecmds.c", + "src/backend/commands/tablespace.c", + "src/backend/commands/trigger.c", + "src/backend/commands/tsearchcmds.c", + "src/backend/commands/typecmds.c", + "src/backend/commands/user.c", + "src/backend/commands/vacuum.c", + "src/backend/commands/vacuumparallel.c", + "src/backend/commands/variable.c", + "src/backend/commands/view.c", + "src/backend/executor/execAmi.c", + "src/backend/executor/execAsync.c", + "src/backend/executor/execCurrent.c", + "src/backend/executor/execExpr.c", + "src/backend/executor/execExprInterp.c", + "src/backend/executor/execGrouping.c", + "src/backend/executor/execIndexing.c", + "src/backend/executor/execJunk.c", + "src/backend/executor/execMain.c", + "src/backend/executor/execParallel.c", + "src/backend/executor/execPartition.c", + "src/backend/executor/execProcnode.c", + "src/backend/executor/execReplication.c", + "src/backend/executor/execSRF.c", + "src/backend/executor/execScan.c", + "src/backend/executor/execTuples.c", + "src/backend/executor/execUtils.c", + "src/backend/executor/functions.c", + "src/backend/executor/instrument.c", + "src/backend/executor/nodeAgg.c", + "src/backend/executor/nodeAppend.c", + "src/backend/executor/nodeBitmapAnd.c", + "src/backend/executor/nodeBitmapHeapscan.c", + "src/backend/executor/nodeBitmapIndexscan.c", + "src/backend/executor/nodeBitmapOr.c", + "src/backend/executor/nodeCtescan.c", + "src/backend/executor/nodeCustom.c", + "src/backend/executor/nodeForeignscan.c", + "src/backend/executor/nodeFunctionscan.c", + "src/backend/executor/nodeGather.c", + "src/backend/executor/nodeGatherMerge.c", + "src/backend/executor/nodeGroup.c", + "src/backend/executor/nodeHash.c", + "src/backend/executor/nodeHashjoin.c", + "src/backend/executor/nodeIncrementalSort.c", + "src/backend/executor/nodeIndexonlyscan.c", + "src/backend/executor/nodeIndexscan.c", + "src/backend/executor/nodeLimit.c", + "src/backend/executor/nodeLockRows.c", + "src/backend/executor/nodeMaterial.c", + "src/backend/executor/nodeMemoize.c", + "src/backend/executor/nodeMergeAppend.c", + "src/backend/executor/nodeMergejoin.c", + "src/backend/executor/nodeModifyTable.c", + "src/backend/executor/nodeNamedtuplestorescan.c", + "src/backend/executor/nodeNestloop.c", + "src/backend/executor/nodeProjectSet.c", + "src/backend/executor/nodeRecursiveunion.c", + "src/backend/executor/nodeResult.c", + "src/backend/executor/nodeSamplescan.c", + "src/backend/executor/nodeSeqscan.c", + "src/backend/executor/nodeSetOp.c", + "src/backend/executor/nodeSort.c", + "src/backend/executor/nodeSubplan.c", + "src/backend/executor/nodeSubqueryscan.c", + "src/backend/executor/nodeTableFuncscan.c", + "src/backend/executor/nodeTidrangescan.c", + "src/backend/executor/nodeTidscan.c", + "src/backend/executor/nodeUnique.c", + "src/backend/executor/nodeValuesscan.c", + "src/backend/executor/nodeWindowAgg.c", + "src/backend/executor/nodeWorktablescan.c", + "src/backend/executor/spi.c", + "src/backend/executor/tqueue.c", + "src/backend/executor/tstoreReceiver.c", + "src/backend/foreign/foreign.c", + "src/backend/jit/jit.c", + "src/backend/lib/bipartite_match.c", + "src/backend/lib/bloomfilter.c", + "src/backend/lib/dshash.c", + "src/backend/lib/hyperloglog.c", + "src/backend/lib/ilist.c", + "src/backend/lib/integerset.c", + "src/backend/lib/knapsack.c", + "src/backend/lib/pairingheap.c", + "src/backend/lib/rbtree.c", + "src/backend/libpq/auth-oauth.c", + "src/backend/libpq/auth-sasl.c", + "src/backend/libpq/auth-scram.c", + "src/backend/libpq/auth.c", + "src/backend/libpq/be-fsstubs.c", + "src/backend/libpq/be-secure-common.c", + "src/backend/libpq/be-secure.c", + "src/backend/libpq/crypt.c", + "src/backend/libpq/hba.c", + "src/backend/libpq/ifaddr.c", + "src/backend/libpq/pqcomm.c", + "src/backend/libpq/pqformat.c", + "src/backend/libpq/pqmq.c", + "src/backend/libpq/pqsignal.c", + "src/backend/nodes/bitmapset.c", + "src/backend/nodes/copyfuncs.c", + "src/backend/nodes/equalfuncs.c", + "src/backend/nodes/extensible.c", + "src/backend/nodes/list.c", + "src/backend/nodes/makefuncs.c", + "src/backend/nodes/multibitmapset.c", + "src/backend/nodes/nodeFuncs.c", + "src/backend/nodes/outfuncs.c", + "src/backend/nodes/params.c", + "src/backend/nodes/print.c", + "src/backend/nodes/queryjumblefuncs.c", + "src/backend/nodes/read.c", + "src/backend/nodes/readfuncs.c", + "src/backend/nodes/tidbitmap.c", + "src/backend/nodes/value.c", + "src/backend/optimizer/geqo/geqo_copy.c", + "src/backend/optimizer/geqo/geqo_cx.c", + "src/backend/optimizer/geqo/geqo_erx.c", + "src/backend/optimizer/geqo/geqo_eval.c", + "src/backend/optimizer/geqo/geqo_main.c", + "src/backend/optimizer/geqo/geqo_misc.c", + "src/backend/optimizer/geqo/geqo_mutation.c", + "src/backend/optimizer/geqo/geqo_ox1.c", + "src/backend/optimizer/geqo/geqo_ox2.c", + "src/backend/optimizer/geqo/geqo_pmx.c", + "src/backend/optimizer/geqo/geqo_pool.c", + "src/backend/optimizer/geqo/geqo_px.c", + "src/backend/optimizer/geqo/geqo_random.c", + "src/backend/optimizer/geqo/geqo_recombination.c", + "src/backend/optimizer/geqo/geqo_selection.c", + "src/backend/optimizer/path/allpaths.c", + "src/backend/optimizer/path/clausesel.c", + "src/backend/optimizer/path/costsize.c", + "src/backend/optimizer/path/equivclass.c", + "src/backend/optimizer/path/indxpath.c", + "src/backend/optimizer/path/joinpath.c", + "src/backend/optimizer/path/joinrels.c", + "src/backend/optimizer/path/pathkeys.c", + "src/backend/optimizer/path/tidpath.c", + "src/backend/optimizer/plan/analyzejoins.c", + "src/backend/optimizer/plan/createplan.c", + "src/backend/optimizer/plan/initsplan.c", + "src/backend/optimizer/plan/planagg.c", + "src/backend/optimizer/plan/planmain.c", + "src/backend/optimizer/plan/planner.c", + "src/backend/optimizer/plan/setrefs.c", + "src/backend/optimizer/plan/subselect.c", + "src/backend/optimizer/prep/prepagg.c", + "src/backend/optimizer/prep/prepjointree.c", + "src/backend/optimizer/prep/prepqual.c", + "src/backend/optimizer/prep/preptlist.c", + "src/backend/optimizer/prep/prepunion.c", + "src/backend/optimizer/util/appendinfo.c", + "src/backend/optimizer/util/clauses.c", + "src/backend/optimizer/util/inherit.c", + "src/backend/optimizer/util/joininfo.c", + "src/backend/optimizer/util/orclauses.c", + "src/backend/optimizer/util/paramassign.c", + "src/backend/optimizer/util/pathnode.c", + "src/backend/optimizer/util/placeholder.c", + "src/backend/optimizer/util/plancat.c", + "src/backend/optimizer/util/predtest.c", + "src/backend/optimizer/util/relnode.c", + "src/backend/optimizer/util/restrictinfo.c", + "src/backend/optimizer/util/tlist.c", + "src/backend/optimizer/util/var.c", + "src/backend/parser/analyze.c", + "src/backend/parser/parse_agg.c", + "src/backend/parser/parse_clause.c", + "src/backend/parser/parse_coerce.c", + "src/backend/parser/parse_collate.c", + "src/backend/parser/parse_cte.c", + "src/backend/parser/parse_enr.c", + "src/backend/parser/parse_expr.c", + "src/backend/parser/parse_func.c", + "src/backend/parser/parse_jsontable.c", + "src/backend/parser/parse_merge.c", + "src/backend/parser/parse_node.c", + "src/backend/parser/parse_oper.c", + "src/backend/parser/parse_param.c", + "src/backend/parser/parse_relation.c", + "src/backend/parser/parse_target.c", + "src/backend/parser/parse_type.c", + "src/backend/parser/parse_utilcmd.c", + "src/backend/parser/parser.c", + "src/backend/parser/scansup.c", + "src/backend/partitioning/partbounds.c", + "src/backend/partitioning/partdesc.c", + "src/backend/partitioning/partprune.c", + "src/backend/port/atomics.c", + "src/backend/postmaster/autovacuum.c", + "src/backend/postmaster/auxprocess.c", + "src/backend/postmaster/bgworker.c", + "src/backend/postmaster/bgwriter.c", + "src/backend/postmaster/checkpointer.c", + "src/backend/postmaster/fork_process.c", + "src/backend/postmaster/interrupt.c", + "src/backend/postmaster/launch_backend.c", + "src/backend/postmaster/pgarch.c", + "src/backend/postmaster/pmchild.c", + "src/backend/postmaster/postmaster.c", + "src/backend/postmaster/startup.c", + "src/backend/postmaster/syslogger.c", + "src/backend/postmaster/walsummarizer.c", + "src/backend/postmaster/walwriter.c", + "src/backend/regex/regcomp.c", + "src/backend/regex/regerror.c", + "src/backend/regex/regexec.c", + "src/backend/regex/regexport.c", + "src/backend/regex/regfree.c", + "src/backend/regex/regprefix.c", + "src/backend/replication/logical/applyparallelworker.c", + "src/backend/replication/logical/conflict.c", + "src/backend/replication/logical/decode.c", + "src/backend/replication/logical/launcher.c", + "src/backend/replication/logical/logical.c", + "src/backend/replication/logical/logicalfuncs.c", + "src/backend/replication/logical/message.c", + "src/backend/replication/logical/origin.c", + "src/backend/replication/logical/proto.c", + "src/backend/replication/logical/relation.c", + "src/backend/replication/logical/reorderbuffer.c", + "src/backend/replication/logical/slotsync.c", + "src/backend/replication/logical/snapbuild.c", + "src/backend/replication/logical/tablesync.c", + "src/backend/replication/logical/worker.c", + "src/backend/replication/slot.c", + "src/backend/replication/slotfuncs.c", + "src/backend/replication/syncrep.c", + "src/backend/replication/walreceiver.c", + "src/backend/replication/walreceiverfuncs.c", + "src/backend/replication/walsender.c", + "src/backend/rewrite/rewriteDefine.c", + "src/backend/rewrite/rewriteHandler.c", + "src/backend/rewrite/rewriteManip.c", + "src/backend/rewrite/rewriteRemove.c", + "src/backend/rewrite/rewriteSearchCycle.c", + "src/backend/rewrite/rewriteSupport.c", + "src/backend/rewrite/rowsecurity.c", + "src/backend/statistics/attribute_stats.c", + "src/backend/statistics/dependencies.c", + "src/backend/statistics/extended_stats.c", + "src/backend/statistics/mcv.c", + "src/backend/statistics/mvdistinct.c", + "src/backend/statistics/relation_stats.c", + "src/backend/statistics/stat_utils.c", + "src/backend/storage/aio/aio.c", + "src/backend/storage/aio/aio_callback.c", + "src/backend/storage/aio/aio_funcs.c", + "src/backend/storage/aio/aio_init.c", + "src/backend/storage/aio/aio_io.c", + "src/backend/storage/aio/aio_target.c", + "src/backend/storage/aio/method_io_uring.c", + "src/backend/storage/aio/method_sync.c", + "src/backend/storage/aio/method_worker.c", + "src/backend/storage/aio/read_stream.c", + "src/backend/storage/buffer/buf_init.c", + "src/backend/storage/buffer/buf_table.c", + "src/backend/storage/buffer/bufmgr.c", + "src/backend/storage/buffer/freelist.c", + "src/backend/storage/buffer/localbuf.c", + "src/backend/storage/file/buffile.c", + "src/backend/storage/file/copydir.c", + "src/backend/storage/file/fd.c", + "src/backend/storage/file/fileset.c", + "src/backend/storage/file/reinit.c", + "src/backend/storage/file/sharedfileset.c", + "src/backend/storage/freespace/freespace.c", + "src/backend/storage/freespace/fsmpage.c", + "src/backend/storage/freespace/indexfsm.c", + "src/backend/storage/ipc/barrier.c", + "src/backend/storage/ipc/dsm.c", + "src/backend/storage/ipc/dsm_impl.c", + "src/backend/storage/ipc/dsm_registry.c", + "src/backend/storage/ipc/ipc.c", + "src/backend/storage/ipc/ipci.c", + "src/backend/storage/ipc/latch.c", + "src/backend/storage/ipc/pmsignal.c", + "src/backend/storage/ipc/procarray.c", + "src/backend/storage/ipc/procsignal.c", + "src/backend/storage/ipc/shm_mq.c", + "src/backend/storage/ipc/shm_toc.c", + "src/backend/storage/ipc/shmem.c", + "src/backend/storage/ipc/signalfuncs.c", + "src/backend/storage/ipc/sinval.c", + "src/backend/storage/ipc/sinvaladt.c", + "src/backend/storage/ipc/standby.c", + "src/backend/storage/ipc/waiteventset.c", + "src/backend/storage/large_object/inv_api.c", + "src/backend/storage/lmgr/condition_variable.c", + "src/backend/storage/lmgr/deadlock.c", + "src/backend/storage/lmgr/lmgr.c", + "src/backend/storage/lmgr/lock.c", + "src/backend/storage/lmgr/lwlock.c", + "src/backend/storage/lmgr/predicate.c", + "src/backend/storage/lmgr/proc.c", + "src/backend/storage/lmgr/s_lock.c", + "src/backend/storage/page/bufpage.c", + "src/backend/storage/page/checksum.c", + "src/backend/storage/page/itemptr.c", + "src/backend/storage/smgr/bulk_write.c", + "src/backend/storage/smgr/md.c", + "src/backend/storage/smgr/smgr.c", + "src/backend/storage/sync/sync.c", + "src/backend/tcop/backend_startup.c", + "src/backend/tcop/cmdtag.c", + "src/backend/tcop/dest.c", + "src/backend/tcop/fastpath.c", + "src/backend/tcop/postgres.c", + "src/backend/tcop/pquery.c", + "src/backend/tcop/utility.c", + "src/backend/tsearch/dict.c", + "src/backend/tsearch/dict_ispell.c", + "src/backend/tsearch/dict_simple.c", + "src/backend/tsearch/dict_synonym.c", + "src/backend/tsearch/dict_thesaurus.c", + "src/backend/tsearch/regis.c", + "src/backend/tsearch/spell.c", + "src/backend/tsearch/to_tsany.c", + "src/backend/tsearch/ts_locale.c", + "src/backend/tsearch/ts_parse.c", + "src/backend/tsearch/ts_selfuncs.c", + "src/backend/tsearch/ts_typanalyze.c", + "src/backend/tsearch/ts_utils.c", + "src/backend/tsearch/wparser.c", + "src/backend/tsearch/wparser_def.c", + "src/backend/utils/activity/backend_progress.c", + "src/backend/utils/activity/backend_status.c", + "src/backend/utils/activity/pgstat.c", + "src/backend/utils/activity/pgstat_archiver.c", + "src/backend/utils/activity/pgstat_backend.c", + "src/backend/utils/activity/pgstat_bgwriter.c", + "src/backend/utils/activity/pgstat_checkpointer.c", + "src/backend/utils/activity/pgstat_database.c", + "src/backend/utils/activity/pgstat_function.c", + "src/backend/utils/activity/pgstat_io.c", + "src/backend/utils/activity/pgstat_relation.c", + "src/backend/utils/activity/pgstat_replslot.c", + "src/backend/utils/activity/pgstat_shmem.c", + "src/backend/utils/activity/pgstat_slru.c", + "src/backend/utils/activity/pgstat_subscription.c", + "src/backend/utils/activity/pgstat_wal.c", + "src/backend/utils/activity/pgstat_xact.c", + "src/backend/utils/activity/wait_event.c", + "src/backend/utils/activity/wait_event_funcs.c", + "src/backend/utils/adt/acl.c", + "src/backend/utils/adt/amutils.c", + "src/backend/utils/adt/array_expanded.c", + "src/backend/utils/adt/array_selfuncs.c", + "src/backend/utils/adt/array_typanalyze.c", + "src/backend/utils/adt/array_userfuncs.c", + "src/backend/utils/adt/arrayfuncs.c", + "src/backend/utils/adt/arraysubs.c", + "src/backend/utils/adt/arrayutils.c", + "src/backend/utils/adt/ascii.c", + "src/backend/utils/adt/bool.c", + "src/backend/utils/adt/cash.c", + "src/backend/utils/adt/char.c", + "src/backend/utils/adt/cryptohashfuncs.c", + "src/backend/utils/adt/date.c", + "src/backend/utils/adt/datetime.c", + "src/backend/utils/adt/datum.c", + "src/backend/utils/adt/dbsize.c", + "src/backend/utils/adt/domains.c", + "src/backend/utils/adt/encode.c", + "src/backend/utils/adt/enum.c", + "src/backend/utils/adt/expandeddatum.c", + "src/backend/utils/adt/expandedrecord.c", + "src/backend/utils/adt/float.c", + "src/backend/utils/adt/format_type.c", + "src/backend/utils/adt/formatting.c", + "src/backend/utils/adt/genfile.c", + "src/backend/utils/adt/geo_ops.c", + "src/backend/utils/adt/geo_selfuncs.c", + "src/backend/utils/adt/geo_spgist.c", + "src/backend/utils/adt/hbafuncs.c", + "src/backend/utils/adt/inet_cidr_ntop.c", + "src/backend/utils/adt/inet_net_pton.c", + "src/backend/utils/adt/int.c", + "src/backend/utils/adt/int8.c", + "src/backend/utils/adt/json.c", + "src/backend/utils/adt/jsonb.c", + "src/backend/utils/adt/jsonb_gin.c", + "src/backend/utils/adt/jsonb_op.c", + "src/backend/utils/adt/jsonb_util.c", + "src/backend/utils/adt/jsonbsubs.c", + "src/backend/utils/adt/jsonfuncs.c", + "src/backend/utils/adt/jsonpath.c", + "src/backend/utils/adt/jsonpath_exec.c", + "src/backend/utils/adt/like.c", + "src/backend/utils/adt/like_support.c", + "src/backend/utils/adt/lockfuncs.c", + "src/backend/utils/adt/mac.c", + "src/backend/utils/adt/mac8.c", + "src/backend/utils/adt/mcxtfuncs.c", + "src/backend/utils/adt/misc.c", + "src/backend/utils/adt/multirangetypes.c", + "src/backend/utils/adt/multirangetypes_selfuncs.c", + "src/backend/utils/adt/name.c", + "src/backend/utils/adt/network.c", + "src/backend/utils/adt/network_gist.c", + "src/backend/utils/adt/network_selfuncs.c", + "src/backend/utils/adt/network_spgist.c", + "src/backend/utils/adt/numeric.c", + "src/backend/utils/adt/numutils.c", + "src/backend/utils/adt/oid.c", + "src/backend/utils/adt/oracle_compat.c", + "src/backend/utils/adt/orderedsetaggs.c", + "src/backend/utils/adt/partitionfuncs.c", + "src/backend/utils/adt/pg_locale.c", + "src/backend/utils/adt/pg_locale_builtin.c", + "src/backend/utils/adt/pg_locale_icu.c", + "src/backend/utils/adt/pg_locale_libc.c", + "src/backend/utils/adt/pg_lsn.c", + "src/backend/utils/adt/pg_upgrade_support.c", + "src/backend/utils/adt/pgstatfuncs.c", + "src/backend/utils/adt/pseudorandomfuncs.c", + "src/backend/utils/adt/pseudotypes.c", + "src/backend/utils/adt/quote.c", + "src/backend/utils/adt/rangetypes.c", + "src/backend/utils/adt/rangetypes_gist.c", + "src/backend/utils/adt/rangetypes_selfuncs.c", + "src/backend/utils/adt/rangetypes_spgist.c", + "src/backend/utils/adt/rangetypes_typanalyze.c", + "src/backend/utils/adt/regexp.c", + "src/backend/utils/adt/regproc.c", + "src/backend/utils/adt/ri_triggers.c", + "src/backend/utils/adt/rowtypes.c", + "src/backend/utils/adt/ruleutils.c", + "src/backend/utils/adt/selfuncs.c", + "src/backend/utils/adt/skipsupport.c", + "src/backend/utils/adt/tid.c", + "src/backend/utils/adt/timestamp.c", + "src/backend/utils/adt/trigfuncs.c", + "src/backend/utils/adt/tsginidx.c", + "src/backend/utils/adt/tsgistidx.c", + "src/backend/utils/adt/tsquery.c", + "src/backend/utils/adt/tsquery_cleanup.c", + "src/backend/utils/adt/tsquery_gist.c", + "src/backend/utils/adt/tsquery_op.c", + "src/backend/utils/adt/tsquery_rewrite.c", + "src/backend/utils/adt/tsquery_util.c", + "src/backend/utils/adt/tsrank.c", + "src/backend/utils/adt/tsvector.c", + "src/backend/utils/adt/tsvector_op.c", + "src/backend/utils/adt/tsvector_parser.c", + "src/backend/utils/adt/uuid.c", + "src/backend/utils/adt/varbit.c", + "src/backend/utils/adt/varchar.c", + "src/backend/utils/adt/varlena.c", + "src/backend/utils/adt/version.c", + "src/backend/utils/adt/waitfuncs.c", + "src/backend/utils/adt/windowfuncs.c", + "src/backend/utils/adt/xid.c", + "src/backend/utils/adt/xid8funcs.c", + "src/backend/utils/adt/xml.c", + "src/backend/utils/cache/attoptcache.c", + "src/backend/utils/cache/catcache.c", + "src/backend/utils/cache/evtcache.c", + "src/backend/utils/cache/funccache.c", + "src/backend/utils/cache/inval.c", + "src/backend/utils/cache/lsyscache.c", + "src/backend/utils/cache/partcache.c", + "src/backend/utils/cache/plancache.c", + "src/backend/utils/cache/relcache.c", + "src/backend/utils/cache/relfilenumbermap.c", + "src/backend/utils/cache/relmapper.c", + "src/backend/utils/cache/spccache.c", + "src/backend/utils/cache/syscache.c", + "src/backend/utils/cache/ts_cache.c", + "src/backend/utils/cache/typcache.c", + "src/backend/utils/error/assert.c", + "src/backend/utils/error/csvlog.c", + "src/backend/utils/error/elog.c", + "src/backend/utils/error/jsonlog.c", + "src/backend/utils/fmgr/dfmgr.c", + "src/backend/utils/fmgr/fmgr.c", + "src/backend/utils/fmgr/funcapi.c", + "src/backend/utils/hash/dynahash.c", + "src/backend/utils/hash/pg_crc.c", + "src/backend/utils/init/globals.c", + "src/backend/utils/init/miscinit.c", + "src/backend/utils/init/postinit.c", + "src/backend/utils/init/usercontext.c", + "src/backend/utils/mb/conv.c", + "src/backend/utils/mb/mbutils.c", + "src/backend/utils/mb/stringinfo_mb.c", + "src/backend/utils/mb/wstrcmp.c", + "src/backend/utils/mb/wstrncmp.c", + "src/backend/utils/misc/conffiles.c", + "src/backend/utils/misc/guc.c", + "src/backend/utils/misc/guc_funcs.c", + "src/backend/utils/misc/guc_tables.c", + "src/backend/utils/misc/help_config.c", + "src/backend/utils/misc/injection_point.c", + "src/backend/utils/misc/pg_config.c", + "src/backend/utils/misc/pg_controldata.c", + "src/backend/utils/misc/pg_rusage.c", + "src/backend/utils/misc/ps_status.c", + "src/backend/utils/misc/queryenvironment.c", + "src/backend/utils/misc/rls.c", + "src/backend/utils/misc/sampling.c", + "src/backend/utils/misc/stack_depth.c", + "src/backend/utils/misc/superuser.c", + "src/backend/utils/misc/timeout.c", + "src/backend/utils/misc/tzparser.c", + "src/backend/utils/mmgr/alignedalloc.c", + "src/backend/utils/mmgr/aset.c", + "src/backend/utils/mmgr/bump.c", + "src/backend/utils/mmgr/dsa.c", + "src/backend/utils/mmgr/freepage.c", + "src/backend/utils/mmgr/generation.c", + "src/backend/utils/mmgr/mcxt.c", + "src/backend/utils/mmgr/memdebug.c", + "src/backend/utils/mmgr/portalmem.c", + "src/backend/utils/mmgr/slab.c", + "src/backend/utils/resowner/resowner.c", + "src/backend/utils/sort/logtape.c", + "src/backend/utils/sort/qsort_interruptible.c", + "src/backend/utils/sort/sharedtuplestore.c", + "src/backend/utils/sort/sortsupport.c", + "src/backend/utils/sort/tuplesort.c", + "src/backend/utils/sort/tuplesortvariants.c", + "src/backend/utils/sort/tuplestore.c", + "src/backend/utils/time/combocid.c", + "src/backend/utils/time/snapmgr.c", +] + +# Add only when linking the postgres executable; embedded entry is in tcop/postgres.c. +POSTGRES_MAIN_SOURCES = [ + "src/backend/main/main.c", +] + +# Matches USE_UNNAMED_POSIX_SEMAPHORES and USE_SYSV_SHARED_MEMORY. +POSTGRES_BACKEND_LINUX_SOURCES = [ + "src/backend/port/posix_sema.c", + "src/backend/port/sysv_shmem.c", +] + +POSTGRES_BACKEND_OPENSSL_SOURCES = [ + "src/backend/libpq/be-secure-openssl.c", +] + +POSTGRES_BACKEND_GSSAPI_SOURCES = [ + "src/backend/libpq/be-gssapi-common.c", + "src/backend/libpq/be-secure-gssapi.c", +] + +# Standalone generated C; fmgrtab uses the Meson include-tree output layout. +POSTGRES_BACKEND_GENERATED_SOURCES = [ + "src/backend/bootstrap/bootparse.c", + "src/backend/bootstrap/bootscanner.c", + "src/backend/parser/gram.c", + "src/backend/parser/scan.c", + "src/backend/replication/repl_gram.c", + "src/backend/replication/repl_scanner.c", + "src/backend/replication/syncrep_gram.c", + "src/backend/replication/syncrep_scanner.c", + "src/backend/utils/adt/jsonpath_gram.c", + "src/backend/utils/adt/jsonpath_scan.c", + "src/backend/utils/misc/guc-file.c", + "src/include/utils/fmgrtab.c", +] + +# Bison emits the matching .h beside each .c (bison -d -o OUTPUT INPUT). +POSTGRES_BACKEND_FLEX_INPUTS = { + "src/backend/bootstrap/bootscanner.c": "src/backend/bootstrap/bootscanner.l", + "src/backend/parser/scan.c": "src/backend/parser/scan.l", + "src/backend/replication/repl_scanner.c": "src/backend/replication/repl_scanner.l", + "src/backend/replication/syncrep_scanner.c": "src/backend/replication/syncrep_scanner.l", + "src/backend/utils/adt/jsonpath_scan.c": "src/backend/utils/adt/jsonpath_scan.l", + "src/backend/utils/misc/guc-file.c": "src/backend/utils/misc/guc-file.l", +} + +POSTGRES_BACKEND_BISON_INPUTS = { + "src/backend/bootstrap/bootparse.c": "src/backend/bootstrap/bootparse.y", + "src/backend/parser/gram.c": "src/backend/parser/gram.y", + "src/backend/replication/repl_gram.c": "src/backend/replication/repl_gram.y", + "src/backend/replication/syncrep_gram.c": "src/backend/replication/syncrep_gram.y", + "src/backend/utils/adt/jsonpath_gram.c": "src/backend/utils/adt/jsonpath_gram.y", +} + +# The remaining scanners take their options from the .l file. +POSTGRES_FLEX_OPTIONS = { + "src/backend/parser/scan.c": ["-b", "-CF", "-p", "-p"], + "src/backend/utils/adt/jsonpath_scan.c": ["-b", "-CF", "-p", "-p"], + "src/fe_utils/psqlscan.c": ["-b", "-Cfe", "-p", "-p"], +} + +# Regular included C fragments needed as header inputs. +POSTGRES_BACKEND_TEXTUAL_SOURCES = [ + "src/backend/regex/regc_color.c", + "src/backend/regex/regc_cvec.c", + "src/backend/regex/regc_lex.c", + "src/backend/regex/regc_locale.c", + "src/backend/regex/regc_nfa.c", + "src/backend/regex/regc_pg_locale.c", + "src/backend/regex/rege_dfa.c", + "src/backend/utils/adt/levenshtein.c", + "src/backend/utils/adt/like_match.c", +] + +POSTGRES_COMMON_SOURCES = [ + "src/common/archive.c", + "src/common/base64.c", + "src/common/binaryheap.c", + "src/common/blkreftable.c", + "src/common/checksum_helper.c", + "src/common/compression.c", + "src/common/controldata_utils.c", + "src/common/encnames.c", + "src/common/exec.c", + "src/common/file_perm.c", + "src/common/file_utils.c", + "src/common/hashfn.c", + "src/common/ip.c", + "src/common/jsonapi.c", + "src/common/keywords.c", + "src/common/kwlookup.c", + "src/common/link-canary.c", + "src/common/md5_common.c", + "src/common/parse_manifest.c", + "src/common/percentrepl.c", + "src/common/pg_get_line.c", + "src/common/pg_lzcompress.c", + "src/common/pg_prng.c", + "src/common/pgfnames.c", + "src/common/psprintf.c", + "src/common/relpath.c", + "src/common/rmtree.c", + "src/common/saslprep.c", + "src/common/scram-common.c", + "src/common/string.c", + "src/common/stringinfo.c", + "src/common/unicode_case.c", + "src/common/unicode_category.c", + "src/common/unicode_norm.c", + "src/common/username.c", + "src/common/wait_error.c", + "src/common/wchar.c", +] + +# Ryu declaration-after-statement warning exception is scoped to these units. +POSTGRES_COMMON_RYU_SOURCES = [ + "src/common/d2s.c", + "src/common/f2s.c", +] + +# Compile config_info.c with the eight VAL_* configuration strings. +POSTGRES_COMMON_CONFIG_INFO_SOURCES = [ + "src/common/config_info.c", +] + +# Use when USE_OPENSSL is unset. +POSTGRES_COMMON_BUILTIN_CRYPTO_SOURCES = [ + "src/common/cryptohash.c", + "src/common/hmac.c", + "src/common/md5.c", + "src/common/sha1.c", + "src/common/sha2.c", +] + +# Use when USE_OPENSSL is set; do not also compile builtin crypto. +POSTGRES_COMMON_OPENSSL_SOURCES = [ + "src/common/cryptohash_openssl.c", + "src/common/hmac_openssl.c", +] + +# FRONTEND; shared jsonapi also needs JSONAPI_USE_PQEXPBUFFER and libpq includes. +POSTGRES_COMMON_FRONTEND_SHARED_ADDITIONAL_SOURCES = [ + "src/common/restricted_token.c", + "src/common/sprompt.c", +] + +# Static frontend also includes shared additions and USE_PRIVATE_ENCODING_FUNCS. +POSTGRES_COMMON_FRONTEND_STATIC_ADDITIONAL_SOURCES = [ + "src/common/fe_memutils.c", + "src/common/logging.c", +] + +POSTGRES_PORT_SOURCES = [ + "src/port/bsearch_arg.c", + "src/port/chklocale.c", + "src/port/inet_net_ntop.c", + "src/port/noblock.c", + "src/port/path.c", + "src/port/pg_bitutils.c", + "src/port/pg_localeconv_r.c", + "src/port/pg_numa.c", + "src/port/pg_popcount_aarch64.c", + "src/port/pg_popcount_avx512.c", + "src/port/pg_strong_random.c", + "src/port/pgcheckdir.c", + "src/port/pgmkdirp.c", + "src/port/pgsleep.c", + "src/port/pgstrcasecmp.c", + "src/port/pgstrsignal.c", + "src/port/pqsignal.c", + "src/port/qsort.c", + "src/port/qsort_arg.c", + "src/port/quotes.c", + "src/port/snprintf.c", + "src/port/strerror.c", + "src/port/tar.c", +] + +# Add a replacement only if its matching pg_config.h HAVE_* is undefined. +# These are configuration choices, not an assumed libc feature inventory. +POSTGRES_PORT_REPLACEMENT_SOURCES = { + "HAVE_EXPLICIT_BZERO": "src/port/explicit_bzero.c", + "HAVE_GETOPT": "src/port/getopt.c", + "HAVE_GETOPT_LONG": "src/port/getopt_long.c", + "HAVE_GETPEEREID": "src/port/getpeereid.c", + "HAVE_INET_ATON": "src/port/inet_aton.c", + "HAVE_MKDTEMP": "src/port/mkdtemp.c", + "HAVE_STRLCAT": "src/port/strlcat.c", + "HAVE_STRLCPY": "src/port/strlcpy.c", + "HAVE_STRNLEN": "src/port/strnlen.c", + "HAVE_STRSEP": "src/port/strsep.c", + "HAVE_TIMINGSAFE_BCMP": "src/port/timingsafe_bcmp.c", + "HAVE_PTHREAD_BARRIER_WAIT": "src/port/pthread_barrier_wait.c", +} + +# Matches USE_SLICING_BY_8_CRC32C; portable baseline without target ISA flags. +POSTGRES_PORT_CRC_GENERIC_SOURCES = [ + "src/port/pg_crc32c_sb8.c", +] + +# Matches USE_SSE42_CRC32C_WITH_RUNTIME_CHECK; specialized source needs its ISA feature. +POSTGRES_PORT_CRC_X86_RUNTIME_SOURCES = [ + "src/port/pg_crc32c_sse42.c", + "src/port/pg_crc32c_sse42_choose.c", + "src/port/pg_crc32c_sb8.c", +] + +POSTGRES_TIMEZONE_SOURCES = [ + "src/timezone/localtime.c", + "src/timezone/pgtz.c", + "src/timezone/strftime.c", +] + +# Build for the execution platform to generate target timezone data. +POSTGRES_ZIC_SOURCES = [ + "src/timezone/zic.c", +] + +# The release ships libstemmer C; only snowball_create.sql is generated. +POSTGRES_SNOWBALL_SOURCES = [ + "src/backend/snowball/libstemmer/api.c", + "src/backend/snowball/libstemmer/utilities.c", + "src/backend/snowball/dict_snowball.c", + "src/backend/snowball/libstemmer/stem_ISO_8859_1_basque.c", + "src/backend/snowball/libstemmer/stem_ISO_8859_1_catalan.c", + "src/backend/snowball/libstemmer/stem_ISO_8859_1_danish.c", + "src/backend/snowball/libstemmer/stem_ISO_8859_1_dutch.c", + "src/backend/snowball/libstemmer/stem_ISO_8859_1_english.c", + "src/backend/snowball/libstemmer/stem_ISO_8859_1_finnish.c", + "src/backend/snowball/libstemmer/stem_ISO_8859_1_french.c", + "src/backend/snowball/libstemmer/stem_ISO_8859_1_german.c", + "src/backend/snowball/libstemmer/stem_ISO_8859_1_indonesian.c", + "src/backend/snowball/libstemmer/stem_ISO_8859_1_irish.c", + "src/backend/snowball/libstemmer/stem_ISO_8859_1_italian.c", + "src/backend/snowball/libstemmer/stem_ISO_8859_1_norwegian.c", + "src/backend/snowball/libstemmer/stem_ISO_8859_1_porter.c", + "src/backend/snowball/libstemmer/stem_ISO_8859_1_portuguese.c", + "src/backend/snowball/libstemmer/stem_ISO_8859_1_spanish.c", + "src/backend/snowball/libstemmer/stem_ISO_8859_1_swedish.c", + "src/backend/snowball/libstemmer/stem_ISO_8859_2_hungarian.c", + "src/backend/snowball/libstemmer/stem_KOI8_R_russian.c", + "src/backend/snowball/libstemmer/stem_UTF_8_arabic.c", + "src/backend/snowball/libstemmer/stem_UTF_8_armenian.c", + "src/backend/snowball/libstemmer/stem_UTF_8_basque.c", + "src/backend/snowball/libstemmer/stem_UTF_8_catalan.c", + "src/backend/snowball/libstemmer/stem_UTF_8_danish.c", + "src/backend/snowball/libstemmer/stem_UTF_8_dutch.c", + "src/backend/snowball/libstemmer/stem_UTF_8_english.c", + "src/backend/snowball/libstemmer/stem_UTF_8_estonian.c", + "src/backend/snowball/libstemmer/stem_UTF_8_finnish.c", + "src/backend/snowball/libstemmer/stem_UTF_8_french.c", + "src/backend/snowball/libstemmer/stem_UTF_8_german.c", + "src/backend/snowball/libstemmer/stem_UTF_8_greek.c", + "src/backend/snowball/libstemmer/stem_UTF_8_hindi.c", + "src/backend/snowball/libstemmer/stem_UTF_8_hungarian.c", + "src/backend/snowball/libstemmer/stem_UTF_8_indonesian.c", + "src/backend/snowball/libstemmer/stem_UTF_8_irish.c", + "src/backend/snowball/libstemmer/stem_UTF_8_italian.c", + "src/backend/snowball/libstemmer/stem_UTF_8_lithuanian.c", + "src/backend/snowball/libstemmer/stem_UTF_8_nepali.c", + "src/backend/snowball/libstemmer/stem_UTF_8_norwegian.c", + "src/backend/snowball/libstemmer/stem_UTF_8_porter.c", + "src/backend/snowball/libstemmer/stem_UTF_8_portuguese.c", + "src/backend/snowball/libstemmer/stem_UTF_8_romanian.c", + "src/backend/snowball/libstemmer/stem_UTF_8_russian.c", + "src/backend/snowball/libstemmer/stem_UTF_8_serbian.c", + "src/backend/snowball/libstemmer/stem_UTF_8_spanish.c", + "src/backend/snowball/libstemmer/stem_UTF_8_swedish.c", + "src/backend/snowball/libstemmer/stem_UTF_8_tamil.c", + "src/backend/snowball/libstemmer/stem_UTF_8_turkish.c", + "src/backend/snowball/libstemmer/stem_UTF_8_yiddish.c", +] + +POSTGRES_SNOWBALL_STOPWORDS = [ + "src/backend/snowball/stopwords/danish.stop", + "src/backend/snowball/stopwords/dutch.stop", + "src/backend/snowball/stopwords/english.stop", + "src/backend/snowball/stopwords/finnish.stop", + "src/backend/snowball/stopwords/french.stop", + "src/backend/snowball/stopwords/german.stop", + "src/backend/snowball/stopwords/hungarian.stop", + "src/backend/snowball/stopwords/italian.stop", + "src/backend/snowball/stopwords/nepali.stop", + "src/backend/snowball/stopwords/norwegian.stop", + "src/backend/snowball/stopwords/portuguese.stop", + "src/backend/snowball/stopwords/russian.stop", + "src/backend/snowball/stopwords/spanish.stop", + "src/backend/snowball/stopwords/swedish.stop", + "src/backend/snowball/stopwords/turkish.stop", +] + +# snowball_create.pl also tests the existence/content size of each stopword file. +POSTGRES_SNOWBALL_SQL_INPUTS = [ + "src/backend/snowball/snowball.sql.in", + "src/backend/snowball/snowball_func.sql.in", + "src/backend/snowball/stopwords/danish.stop", + "src/backend/snowball/stopwords/dutch.stop", + "src/backend/snowball/stopwords/english.stop", + "src/backend/snowball/stopwords/finnish.stop", + "src/backend/snowball/stopwords/french.stop", + "src/backend/snowball/stopwords/german.stop", + "src/backend/snowball/stopwords/hungarian.stop", + "src/backend/snowball/stopwords/italian.stop", + "src/backend/snowball/stopwords/nepali.stop", + "src/backend/snowball/stopwords/norwegian.stop", + "src/backend/snowball/stopwords/portuguese.stop", + "src/backend/snowball/stopwords/russian.stop", + "src/backend/snowball/stopwords/spanish.stop", + "src/backend/snowball/stopwords/swedish.stop", + "src/backend/snowball/stopwords/turkish.stop", +] + +POSTGRES_PLPGSQL_SOURCES = [ + "src/pl/plpgsql/src/pl_comp.c", + "src/pl/plpgsql/src/pl_exec.c", + "src/pl/plpgsql/src/pl_funcs.c", + "src/pl/plpgsql/src/pl_handler.c", + "src/pl/plpgsql/src/pl_scanner.c", +] + +# pl_gram.y requires Bison; pl_scanner.c is handwritten, not a Flex source. +POSTGRES_PLPGSQL_GENERATED_SOURCES = [ + "src/pl/plpgsql/src/pl_gram.c", +] + +# generate-plerrcodes.pl and gen_keywordlist.pl supply the non-grammar headers. +POSTGRES_PLPGSQL_GENERATED_HEADERS = [ + "src/pl/plpgsql/src/pl_gram.h", + "src/pl/plpgsql/src/plerrcodes.h", + "src/pl/plpgsql/src/pl_reserved_kwlist_d.h", + "src/pl/plpgsql/src/pl_unreserved_kwlist_d.h", +] + +# Compile FRONTEND and SO_MAJOR_VERSION=5; shared libpq also USE_DYNAMIC_OAUTH. +POSTGRES_LIBPQ_SOURCES = [ + "src/interfaces/libpq/fe-auth-oauth.c", + "src/interfaces/libpq/fe-auth-scram.c", + "src/interfaces/libpq/fe-auth.c", + "src/interfaces/libpq/fe-cancel.c", + "src/interfaces/libpq/fe-connect.c", + "src/interfaces/libpq/fe-exec.c", + "src/interfaces/libpq/fe-lobj.c", + "src/interfaces/libpq/fe-misc.c", + "src/interfaces/libpq/fe-print.c", + "src/interfaces/libpq/fe-protocol3.c", + "src/interfaces/libpq/fe-secure.c", + "src/interfaces/libpq/fe-trace.c", + "src/interfaces/libpq/legacy-pqsignal.c", + "src/interfaces/libpq/libpq-events.c", + "src/interfaces/libpq/pqexpbuffer.c", +] + +POSTGRES_LIBPQ_OPENSSL_SOURCES = [ + "src/interfaces/libpq/fe-secure-common.c", + "src/interfaces/libpq/fe-secure-openssl.c", +] + +POSTGRES_LIBPQ_GSSAPI_SOURCES = [ + "src/interfaces/libpq/fe-gssapi-common.c", + "src/interfaces/libpq/fe-secure-gssapi.c", +] + +# FRONTEND and USE_PRIVATE_ENCODING_FUNCS; link frontend support plus libpq. +POSTGRES_INITDB_SOURCES = [ + "src/bin/initdb/findtimezone.c", + "src/bin/initdb/initdb.c", + "src/timezone/localtime.c", +] + +POSTGRES_PG_CONFIG_SOURCES = [ + "src/bin/pg_config/pg_config.c", +] + +POSTGRES_FRONTEND_UTIL_SOURCES = [ + "src/fe_utils/archive.c", + "src/fe_utils/astreamer_file.c", + "src/fe_utils/astreamer_gzip.c", + "src/fe_utils/astreamer_lz4.c", + "src/fe_utils/astreamer_tar.c", + "src/fe_utils/astreamer_zstd.c", + "src/fe_utils/cancel.c", + "src/fe_utils/conditional.c", + "src/fe_utils/connect_utils.c", + "src/fe_utils/mbprint.c", + "src/fe_utils/option_utils.c", + "src/fe_utils/parallel_slot.c", + "src/fe_utils/print.c", + "src/fe_utils/query_utils.c", + "src/fe_utils/recovery_gen.c", + "src/fe_utils/simple_list.c", + "src/fe_utils/string_utils.c", +] + +# Only needed by frontend utilities that use libpgfeutils. +POSTGRES_FRONTEND_UTIL_GENERATED_SOURCES = [ + "src/fe_utils/psqlscan.c", +] + +# genbki.pl argument order is semantically significant; do not sort this list. +POSTGRES_CATALOG_HEADERS = [ + "src/include/catalog/pg_proc.h", + "src/include/catalog/pg_type.h", + "src/include/catalog/pg_attribute.h", + "src/include/catalog/pg_class.h", + "src/include/catalog/pg_attrdef.h", + "src/include/catalog/pg_constraint.h", + "src/include/catalog/pg_inherits.h", + "src/include/catalog/pg_index.h", + "src/include/catalog/pg_operator.h", + "src/include/catalog/pg_opfamily.h", + "src/include/catalog/pg_opclass.h", + "src/include/catalog/pg_am.h", + "src/include/catalog/pg_amop.h", + "src/include/catalog/pg_amproc.h", + "src/include/catalog/pg_language.h", + "src/include/catalog/pg_largeobject_metadata.h", + "src/include/catalog/pg_largeobject.h", + "src/include/catalog/pg_aggregate.h", + "src/include/catalog/pg_statistic.h", + "src/include/catalog/pg_statistic_ext.h", + "src/include/catalog/pg_statistic_ext_data.h", + "src/include/catalog/pg_rewrite.h", + "src/include/catalog/pg_trigger.h", + "src/include/catalog/pg_event_trigger.h", + "src/include/catalog/pg_description.h", + "src/include/catalog/pg_cast.h", + "src/include/catalog/pg_enum.h", + "src/include/catalog/pg_namespace.h", + "src/include/catalog/pg_conversion.h", + "src/include/catalog/pg_depend.h", + "src/include/catalog/pg_database.h", + "src/include/catalog/pg_db_role_setting.h", + "src/include/catalog/pg_tablespace.h", + "src/include/catalog/pg_authid.h", + "src/include/catalog/pg_auth_members.h", + "src/include/catalog/pg_shdepend.h", + "src/include/catalog/pg_shdescription.h", + "src/include/catalog/pg_ts_config.h", + "src/include/catalog/pg_ts_config_map.h", + "src/include/catalog/pg_ts_dict.h", + "src/include/catalog/pg_ts_parser.h", + "src/include/catalog/pg_ts_template.h", + "src/include/catalog/pg_extension.h", + "src/include/catalog/pg_foreign_data_wrapper.h", + "src/include/catalog/pg_foreign_server.h", + "src/include/catalog/pg_user_mapping.h", + "src/include/catalog/pg_foreign_table.h", + "src/include/catalog/pg_policy.h", + "src/include/catalog/pg_replication_origin.h", + "src/include/catalog/pg_default_acl.h", + "src/include/catalog/pg_init_privs.h", + "src/include/catalog/pg_seclabel.h", + "src/include/catalog/pg_shseclabel.h", + "src/include/catalog/pg_collation.h", + "src/include/catalog/pg_parameter_acl.h", + "src/include/catalog/pg_partitioned_table.h", + "src/include/catalog/pg_range.h", + "src/include/catalog/pg_transform.h", + "src/include/catalog/pg_sequence.h", + "src/include/catalog/pg_publication.h", + "src/include/catalog/pg_publication_namespace.h", + "src/include/catalog/pg_publication_rel.h", + "src/include/catalog/pg_subscription.h", + "src/include/catalog/pg_subscription_rel.h", +] + +POSTGRES_CATALOG_DATA = [ + "src/include/catalog/pg_aggregate.dat", + "src/include/catalog/pg_am.dat", + "src/include/catalog/pg_amop.dat", + "src/include/catalog/pg_amproc.dat", + "src/include/catalog/pg_authid.dat", + "src/include/catalog/pg_cast.dat", + "src/include/catalog/pg_class.dat", + "src/include/catalog/pg_collation.dat", + "src/include/catalog/pg_conversion.dat", + "src/include/catalog/pg_database.dat", + "src/include/catalog/pg_language.dat", + "src/include/catalog/pg_namespace.dat", + "src/include/catalog/pg_opclass.dat", + "src/include/catalog/pg_operator.dat", + "src/include/catalog/pg_opfamily.dat", + "src/include/catalog/pg_proc.dat", + "src/include/catalog/pg_range.dat", + "src/include/catalog/pg_tablespace.dat", + "src/include/catalog/pg_ts_config.dat", + "src/include/catalog/pg_ts_config_map.dat", + "src/include/catalog/pg_ts_dict.dat", + "src/include/catalog/pg_ts_parser.dat", + "src/include/catalog/pg_ts_template.dat", + "src/include/catalog/pg_type.dat", +] + +# Additional files read by genbki.pl outside its command-line catalog headers. +POSTGRES_CATALOG_GENERATOR_EXTRA_INPUTS = [ + "src/backend/catalog/Catalog.pm", + "src/include/access/transam.h", + "src/include/mb/pg_wchar.h", +] + +# genbki also emits postgres.bki and system_constraints.sql as runtime resources. +POSTGRES_CATALOG_GENERATED_HEADERS = [ + "src/include/catalog/schemapg.h", + "src/include/catalog/syscache_ids.h", + "src/include/catalog/syscache_info.h", + "src/include/catalog/system_fk_info.h", + "src/include/catalog/pg_proc_d.h", + "src/include/catalog/pg_type_d.h", + "src/include/catalog/pg_attribute_d.h", + "src/include/catalog/pg_class_d.h", + "src/include/catalog/pg_attrdef_d.h", + "src/include/catalog/pg_constraint_d.h", + "src/include/catalog/pg_inherits_d.h", + "src/include/catalog/pg_index_d.h", + "src/include/catalog/pg_operator_d.h", + "src/include/catalog/pg_opfamily_d.h", + "src/include/catalog/pg_opclass_d.h", + "src/include/catalog/pg_am_d.h", + "src/include/catalog/pg_amop_d.h", + "src/include/catalog/pg_amproc_d.h", + "src/include/catalog/pg_language_d.h", + "src/include/catalog/pg_largeobject_metadata_d.h", + "src/include/catalog/pg_largeobject_d.h", + "src/include/catalog/pg_aggregate_d.h", + "src/include/catalog/pg_statistic_d.h", + "src/include/catalog/pg_statistic_ext_d.h", + "src/include/catalog/pg_statistic_ext_data_d.h", + "src/include/catalog/pg_rewrite_d.h", + "src/include/catalog/pg_trigger_d.h", + "src/include/catalog/pg_event_trigger_d.h", + "src/include/catalog/pg_description_d.h", + "src/include/catalog/pg_cast_d.h", + "src/include/catalog/pg_enum_d.h", + "src/include/catalog/pg_namespace_d.h", + "src/include/catalog/pg_conversion_d.h", + "src/include/catalog/pg_depend_d.h", + "src/include/catalog/pg_database_d.h", + "src/include/catalog/pg_db_role_setting_d.h", + "src/include/catalog/pg_tablespace_d.h", + "src/include/catalog/pg_authid_d.h", + "src/include/catalog/pg_auth_members_d.h", + "src/include/catalog/pg_shdepend_d.h", + "src/include/catalog/pg_shdescription_d.h", + "src/include/catalog/pg_ts_config_d.h", + "src/include/catalog/pg_ts_config_map_d.h", + "src/include/catalog/pg_ts_dict_d.h", + "src/include/catalog/pg_ts_parser_d.h", + "src/include/catalog/pg_ts_template_d.h", + "src/include/catalog/pg_extension_d.h", + "src/include/catalog/pg_foreign_data_wrapper_d.h", + "src/include/catalog/pg_foreign_server_d.h", + "src/include/catalog/pg_user_mapping_d.h", + "src/include/catalog/pg_foreign_table_d.h", + "src/include/catalog/pg_policy_d.h", + "src/include/catalog/pg_replication_origin_d.h", + "src/include/catalog/pg_default_acl_d.h", + "src/include/catalog/pg_init_privs_d.h", + "src/include/catalog/pg_seclabel_d.h", + "src/include/catalog/pg_shseclabel_d.h", + "src/include/catalog/pg_collation_d.h", + "src/include/catalog/pg_parameter_acl_d.h", + "src/include/catalog/pg_partitioned_table_d.h", + "src/include/catalog/pg_range_d.h", + "src/include/catalog/pg_transform_d.h", + "src/include/catalog/pg_sequence_d.h", + "src/include/catalog/pg_publication_d.h", + "src/include/catalog/pg_publication_namespace_d.h", + "src/include/catalog/pg_publication_rel_d.h", + "src/include/catalog/pg_subscription_d.h", + "src/include/catalog/pg_subscription_rel_d.h", +] + +# gen_node_support.pl additionally loads Catalog.pm. +POSTGRES_NODE_GENERATOR_INPUTS = [ + "src/include/nodes/nodes.h", + "src/include/nodes/primnodes.h", + "src/include/nodes/parsenodes.h", + "src/include/nodes/pathnodes.h", + "src/include/nodes/plannodes.h", + "src/include/nodes/execnodes.h", + "src/include/access/amapi.h", + "src/include/access/cmptype.h", + "src/include/access/sdir.h", + "src/include/access/tableam.h", + "src/include/access/tsmapi.h", + "src/include/commands/event_trigger.h", + "src/include/commands/trigger.h", + "src/include/executor/tuptable.h", + "src/include/foreign/fdwapi.h", + "src/include/nodes/bitmapset.h", + "src/include/nodes/extensible.h", + "src/include/nodes/lockoptions.h", + "src/include/nodes/miscnodes.h", + "src/include/nodes/replnodes.h", + "src/include/nodes/supportnodes.h", + "src/include/nodes/value.h", + "src/include/utils/rel.h", +] + +# nodetags.h plus ten included .c fragments, not standalone C outputs. +POSTGRES_NODE_GENERATED_TEXTUAL_SOURCES = [ + "src/include/nodes/nodetags.h", + "src/include/nodes/outfuncs.funcs.c", + "src/include/nodes/outfuncs.switch.c", + "src/include/nodes/readfuncs.funcs.c", + "src/include/nodes/readfuncs.switch.c", + "src/include/nodes/copyfuncs.funcs.c", + "src/include/nodes/copyfuncs.switch.c", + "src/include/nodes/equalfuncs.funcs.c", + "src/include/nodes/equalfuncs.switch.c", + "src/include/nodes/queryjumblefuncs.funcs.c", + "src/include/nodes/queryjumblefuncs.switch.c", +] + +# Generated by generate-wait_event_types.pl --code from wait_event_names.txt. +POSTGRES_WAIT_EVENT_GENERATED_TEXTUAL_SOURCES = [ + "src/include/utils/wait_event_types.h", + "src/include/utils/pgstat_wait_event.c", + "src/include/utils/wait_event_funcs_data.c", +] + +# Other backend generated headers; catalog/node/wait-event sets are separate. +POSTGRES_BACKEND_GENERATED_HEADERS = [ + "src/include/utils/errcodes.h", + "src/include/utils/probes.h", + "src/include/utils/fmgroids.h", + "src/include/utils/fmgrprotos.h", + "src/include/storage/lwlocknames.h", + "src/backend/bootstrap/bootparse.h", + "src/backend/parser/gram.h", + "src/backend/replication/repl_gram.h", + "src/backend/replication/syncrep_gram.h", + "src/backend/utils/adt/jsonpath_gram.h", +] + +# gen_keywordlist.pl --extern; declares PerfectHash.pm and parser/kwlist.h. +POSTGRES_COMMON_GENERATED_HEADERS = [ + "src/common/kwlist_d.h", +] + +POSTGRES_BACKEND_INCLUDE_DIRECTORIES = [ + "src/include", + "src/include/nodes", + "src/backend", + "src/backend/bootstrap", + "src/backend/parser", + "src/backend/replication", + "src/backend/utils/adt", + "src/backend/utils/misc", +] + +# Resource output paths follow the same generated tree as compile inputs. +POSTGRES_CATALOG_GENERATED_RESOURCES = [ + "src/include/catalog/postgres.bki", + "src/include/catalog/system_constraints.sql", +] + +POSTGRES_SNOWBALL_GENERATED_RESOURCES = [ + "src/backend/snowball/snowball_create.sql", +] + +POSTGRES_TIMEZONE_DATA_INPUTS = [ + "src/timezone/data/tzdata.zi", +] + +POSTGRES_CODEGEN_SCRIPTS = [ + "src/backend/catalog/Catalog.pm", + "src/backend/catalog/genbki.pl", + "src/backend/nodes/gen_node_support.pl", + "src/backend/snowball/snowball_create.pl", + "src/backend/storage/lmgr/generate-lwlocknames.pl", + "src/backend/utils/Gen_dummy_probes.pl", + "src/backend/utils/Gen_fmgrtab.pl", + "src/backend/utils/activity/generate-wait_event_types.pl", + "src/backend/utils/generate-errcodes.pl", + "src/pl/plpgsql/src/generate-plerrcodes.pl", + "src/tools/PerfectHash.pm", + "src/tools/gen_keywordlist.pl", + "src/tools/pgflex", +] + +POSTGRES_CONFIG_HEADERS = [ + "src/include/pg_config.h", + "src/include/pg_config_os.h", + "src/include/pg_config_paths.h", +] diff --git a/build_defs/native/probe-process.test.cc b/build_defs/native/probe-process.test.cc new file mode 100644 index 000000000..45b0ccf31 --- /dev/null +++ b/build_defs/native/probe-process.test.cc @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "autoconf/private/checker/native_process.h" + +#define CHECK(expression) do { if (!(expression)) { \ + std::cerr << "failed: " << #expression << '\n'; return 2; \ +} } while (false) + +int main(int argc, char** argv) { + if (argc > 1) { + std::string mode = argv[1]; + if (mode == "exit") return std::stoi(argv[2]); + if (mode == "echo") { + for (int index = 2; index < argc; ++index) std::cout << argv[index] << '\n'; + return 0; + } +#ifndef _WIN32 + if (mode == "signal") std::raise(SIGTERM); +#endif + return 3; + } + using rules_cc_autoconf::run_native_process; + auto executable = std::filesystem::absolute(argv[0]).string(); + CHECK(run_native_process({executable, "exit", "0"}) == 0); + CHECK(run_native_process({executable, "exit", "1"}) == 1); + + auto rejects = [&](const std::vector& arguments) { + bool failed = false; + try { run_native_process(arguments); } + catch (const std::exception&) { failed = true; } + return failed; + }; + CHECK(rejects({})); + CHECK(rejects({executable + "-missing"})); + bool bypassed_optional_result = false; + try { run_native_process({executable + "-missing"}); } + catch (const std::runtime_error&) { return 2; } + catch (const std::exception&) { bypassed_optional_result = true; } + CHECK(bypassed_optional_result); +#ifndef _WIN32 + CHECK(rejects({executable, "signal"})); + CHECK(rejects({executable, "exit", "126"})); + CHECK(rejects({executable, "exit", "127"})); +#endif + + auto temporary = std::getenv("TEST_TMPDIR"); + CHECK(temporary); + auto output = (std::filesystem::path(temporary) / "literal args output.txt").string(); + std::vector literals = {"", "a b", "x\\", "a\"b", "'$();&<>%", "trailing \\"}; + std::vector command = {executable, "echo"}; + command.insert(command.end(), literals.begin(), literals.end()); + CHECK(run_native_process(command, true, output) == 0); + std::ifstream input(output); + std::string actual((std::istreambuf_iterator(input)), {}); + std::string expected; + for (const auto& value : literals) expected += value + '\n'; + CHECK(actual == expected); + bool unwritable_failed = false; + try { run_native_process(command, true, output + "/missing/out.txt"); } + catch (const std::exception&) { unwritable_failed = true; } + CHECK(unwritable_failed); + return 0; +} diff --git a/build_defs/native/probe-sanity.c b/build_defs/native/probe-sanity.c new file mode 100644 index 000000000..0b86f1c48 --- /dev/null +++ b/build_defs/native/probe-sanity.c @@ -0,0 +1,11 @@ +#include +#include +#include + +int main(void) { + void *allocation = malloc(sizeof(uint64_t)); + if (!allocation) return 1; + puts("declared native compiler and standard-library link are usable"); + free(allocation); + return 0; +} diff --git a/build_defs/native/probe-tools-test.bzl b/build_defs/native/probe-tools-test.bzl new file mode 100644 index 000000000..9d3cb42f4 --- /dev/null +++ b/build_defs/native/probe-tools-test.bzl @@ -0,0 +1,61 @@ +"""Analysis-only proof that shared probe tools preserve the selected SDK inputs.""" + +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") +load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain", "use_cc_toolchain") + +_ProbeToolsInfo = provider(fields = ["files"]) + +def _probe_tools_impl(ctx): + files = find_cc_toolchain(ctx).all_files + # Neither action executes; the analysis test compares their declarations. + for name, tools in [("flat", files), ("shared", [files])]: + ctx.actions.run( + executable = ctx.executable.checker, + arguments = ["--help"], + inputs = [ctx.file.source], + outputs = [ctx.actions.declare_file(name + ".probe")], + tools = tools, + mnemonic = "ProbeToolInputs", + ) + return [ + _ProbeToolsInfo(files = files), + DefaultInfo(files = depset([ctx.executable.checker]), runfiles = ctx.attr.checker[DefaultInfo].default_runfiles), + ] + +_probe_tools = rule( + implementation = _probe_tools_impl, + attrs = { + "source": attr.label(allow_single_file = True), + "checker": attr.label(executable = True, cfg = "exec"), + }, + toolchains = use_cc_toolchain(), +) + +def _probe_tools_test_impl(ctx): + env = analysistest.begin(ctx) + actions = analysistest.target_actions(env) + asserts.equals(env, 2, len(actions)) + expected = {file.path: True for file in analysistest.target_under_test(env)[_ProbeToolsInfo].files.to_list()} + asserts.true(env, len(expected) > 0) + for action in actions: + inputs = {file.path: True for file in action.inputs.to_list()} + asserts.equals(env, expected, {path: True for path in inputs if path in expected}) + asserts.equals(env, sorted([file.path for file in actions[0].inputs.to_list()]), sorted([file.path for file in actions[1].inputs.to_list()])) + asserts.equals(env, actions[0].argv, actions[1].argv) + asserts.equals(env, actions[0].env, actions[1].env) + return analysistest.end(env) + +_probe_tools_test = analysistest.make(_probe_tools_test_impl) + +def compiler_probe_tool_inputs_test(): + _probe_tools( + name = "compiler_probe_tool_inputs_subject", + source = ":probe-sanity.c", + checker = "@rules_cc_autoconf//autoconf/private/checker:checker_bin", + tags = ["manual"], + testonly = True, + ) + _probe_tools_test( + name = "compiler_probe_tool_inputs_test", + target_under_test = ":compiler_probe_tool_inputs_subject", + ) diff --git a/build_defs/native/repositories.bzl b/build_defs/native/repositories.bzl new file mode 100644 index 000000000..14dc7e85c --- /dev/null +++ b/build_defs/native/repositories.bzl @@ -0,0 +1,156 @@ +"""Pinned PostgreSQL source and explicit local generator tools for the native port. + +The local tools repository is a development capability, not a hermetic release +toolchain. Its binaries and data files are declared action inputs; the host +loader/sysroot still needs the separately qualified production toolchain. +""" + +def source_string_values(text): + values = {} + for line in text.splitlines(): + line = line.strip() + if not line or line.startswith("#") or line.startswith("["): + continue + key, separator, value = line.partition("=") + value = value.strip() + if not separator or not value.startswith("\"") or not value.endswith("\""): + fail("source metadata must contain quoted string values: " + line) + values[key.strip()] = value[1:-1] + return values + +def postgres_overlay_paths(overlays): + """Validate declared regular-text overlays before acquiring PG sources.""" + destinations = {} + for label, relative in overlays.items(): + components = relative.split("/") + if not relative.startswith("src/") or any([part in ["", ".", ".."] for part in components]) or any([character not in "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._-/" for character in relative.elems()]): + fail("invalid PostgreSQL overlay destination: " + relative) + if relative in destinations: + fail("duplicate PostgreSQL overlay destination: " + relative) + destinations[relative] = label + return {relative: destinations[relative] for relative in sorted(destinations)} + +def _postgres_repository_impl(ctx): + overlays = postgres_overlay_paths(ctx.attr.overlays) + source = source_string_values(ctx.read(ctx.attr.source_manifest)) + for name in ["version", "url", "sha256"]: + if name not in source: + fail("PostgreSQL source manifest is missing " + name) + # The explicit unit inventory and LP64 configuration have only been proven + # against this source. A pin update needs a reviewed inventory/profile port. + if source["version"] != "18.4" or source["sha256"] != "81a81ec695fb0c7901407defaa1d2f7973617154cf27ba74e3a7ab8e64436094": + fail("native PostgreSQL inventory/configuration is proven only for the canonical 18.4 source; review the source inventory, configuration and runtime parity before updating this profile") + ctx.download_and_extract( + url = source["url"], + sha256 = source["sha256"], + stripPrefix = "postgresql-" + source["version"], + ) + # The authored postmaster recipe installs its six Git-100644 source blobs + # before the ordered series. Empty defaults preserve existing source trees. + for relative, label in overlays.items(): + ctx.file(relative, ctx.read(label), executable = False) + if overlays: + ctx.read(ctx.attr.overlay_modes_tool) + ctx.watch(ctx.path(ctx.attr.overlay_bun)) + result = ctx.execute([ctx.path(ctx.attr.overlay_bun), "--no-install", "--no-env-file", ctx.path(ctx.attr.overlay_modes_tool), "overlay", ctx.path("."), json.encode(overlays.keys())], quiet = True) + if result.return_code: + fail("Cannot apply declared PostgreSQL overlay modes: " + result.stderr) + patches = [] + for line in ctx.read(ctx.attr.patch_series).splitlines(): + patch = line.strip() + if not patch or patch.startswith("#"): + continue + if not patch.startswith("src/") or ".." in patch.split("/"): + fail("invalid repository-relative PostgreSQL patch: " + patch) + if patch.startswith("src/native/runtime/"): + label = Label("//src/native/runtime:" + patch[len("src/native/runtime/"):]) + elif patch.startswith("src/wasix/runtime/"): + label = Label("//src/wasix/runtime:" + patch[len("src/wasix/runtime/"):]) + elif patch.startswith("src/wasix/postmaster/"): + label = Label("//src/wasix/postmaster:" + patch[len("src/wasix/postmaster/"):]) + elif patch.startswith("src/third-party/postgres/"): + label = Label("//src/third-party/postgres:" + patch[len("src/third-party/postgres/"):]) + else: + fail("unknown PostgreSQL patch owner: " + patch) + ctx.patch(ctx.path(label), strip = 1) + patches.append(patch) + ctx.file("SOURCE_VERSION", source["version"] + "\n") + ctx.file("version.bzl", "POSTGRES_VERSION = " + repr(source["version"]) + "\n") + ctx.file("patches.bzl", "POSTGRES_PATCHES = " + repr(patches) + "\n") + ctx.symlink(ctx.attr.build_file, "BUILD.bazel") + +postgres_repository = repository_rule( + implementation = _postgres_repository_impl, + attrs = { + "source_manifest": attr.label(default = "//src/third-party/postgres:source.toml", allow_single_file = True), + "patch_series": attr.label(default = "//src/native/runtime:postgres/series", allow_single_file = True), + "build_file": attr.label(default = "//build_defs/native:postgres.BUILD.bazel", allow_single_file = True), + "overlays": attr.label_keyed_string_dict(allow_files = True), + "overlay_modes_tool": attr.label(default = Label("//build_defs/wasix/postmaster:source-modes.mts"), allow_single_file = True), + "overlay_bun": attr.label(default = Label("@bun_runtime//:bun"), allow_single_file = True), + }, +) + +def _icu_repository_impl(ctx): + source = source_string_values(ctx.read(ctx.attr.source_manifest)) + if source.get("url") != "https://github.com/unicode-org/icu.git": + fail("ICU canonical origin changed; review archive acquisition before updating this import") + commit = source.get("commit") + if commit != "8eca245c7484ac6cc179e3e5f7c1ea7680810f39": + fail("ICU source pin changed; update the verified archive checksum and native inventory together") + ctx.download_and_extract( + url = "https://codeload.github.com/unicode-org/icu/tar.gz/" + commit, + type = "tar.gz", + # SHA-256 of the immutable commit archive, verified during this port. + sha256 = "6fb1db5c6eaeece80b1edc91696823de873bb79ab31360102bf9d6978441b1af", + stripPrefix = "icu-" + commit + "/icu4c/source", + ) + # Upstream's partial Bazel packages use the original archive-root paths. + for directory in ["common", "i18n", "stubdata"]: + ctx.delete(directory + "/BUILD.bazel") + ctx.symlink(ctx.attr.build_file, "BUILD.bazel") + ctx.symlink(ctx.attr.inventory, "icu_sources.bzl") + +icu_repository = repository_rule( + implementation = _icu_repository_impl, + attrs = { + "source_manifest": attr.label(default = "//src/third-party/icu:source.toml", allow_single_file = True), + "build_file": attr.label(default = "//build_defs/native:icu.BUILD.bazel", allow_single_file = True), + "inventory": attr.label(default = "//build_defs/native:icu_sources.bzl", allow_single_file = True), + }, +) + +def _native_exec_tools_impl(ctx): + versions = [] + for name in ["perl", "bison", "flex", "m4", "patch"]: + binary = ctx.which(name) + if not binary: + fail("native generator tool is unavailable: " + name) + ctx.symlink(binary, name) + result = ctx.execute([binary, "--version"]) + if result.return_code: + fail("cannot identify generator tool: " + name) + versions.append(name + "=" + result.stdout.strip()) + bison_data = ctx.execute([ctx.path("bison"), "--print-datadir"]) + if bison_data.return_code: + fail("cannot locate bison skeletons") + ctx.symlink(bison_data.stdout.strip(), "bison_data") + perl_libs = ctx.execute([ctx.path("perl"), "-e", "print join(qq(\\n), grep { -d $_ && $_ ne q(.) } @INC)"]) + if perl_libs.return_code: + fail("cannot locate Perl standard library") + count = 0 + for directory in perl_libs.stdout.splitlines(): + ctx.symlink(directory, "perl_lib_" + str(count)) + count += 1 + ctx.file("VERSIONS", "\n".join(versions) + "\n") + ctx.file("BUILD.bazel", """package(default_visibility = [\"//visibility:public\"]) +exports_files([\"perl\", \"bison\", \"flex\", \"m4\", \"patch\", \"VERSIONS\"]) +filegroup(name = \"data\", srcs = glob([\"bison_data/**\", \"perl_lib_*/**\"], allow_empty = False)) +filegroup(name = \"perl_data\", srcs = glob([\"perl_lib_*/**\"], allow_empty = False)) +""") + +native_exec_tools_repository = repository_rule( + implementation = _native_exec_tools_impl, + local = True, + configure = True, +) diff --git a/build_defs/native/resources.bzl b/build_defs/native/resources.bzl new file mode 100644 index 000000000..c347ed995 --- /dev/null +++ b/build_defs/native/resources.bzl @@ -0,0 +1,21 @@ +"""Native PostgreSQL resource generators with explicit inputs and exec tools.""" + +def _timezone_database_impl(ctx): + output = ctx.actions.declare_directory(ctx.attr.name) + ctx.actions.run( + executable = ctx.executable.zic, + arguments = ["-d", output.path] + (["-p", ctx.attr.posixrules] if ctx.attr.posixrules else []) + [ctx.file.source.path], + inputs = [ctx.file.source], + outputs = [output], + mnemonic = "PostgresTimezone", + ) + return [DefaultInfo(files = depset([output]))] + +timezone_database = rule( + implementation = _timezone_database_impl, + attrs = { + "source": attr.label(allow_single_file = True, mandatory = True), + "zic": attr.label(executable = True, cfg = "exec", mandatory = True), + "posixrules": attr.string(default = "US/Eastern"), + }, +) diff --git a/build_defs/native/runtime_sql_test.sh b/build_defs/native/runtime_sql_test.sh new file mode 100755 index 000000000..a201d63f7 --- /dev/null +++ b/build_defs/native/runtime_sql_test.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail + +payload="$PWD/$1" +fixture="$PWD/$3" +runtime="$TEST_TMPDIR/runtime" +database="$TEST_TMPDIR/database" +consumer_bin="$TEST_TMPDIR/consumer/bin" +mkdir -p "$runtime" "$database" "$consumer_bin" +tar -xf "$payload" -C "$runtime" +# Relocation removes the compiled consumers' Bazel runfiles loader fallback. +cp "$PWD/$2" "$consumer_bin/runtime_smoke" +cp "$PWD/$4" "$consumer_bin/profile_smoke" +smoke="$consumer_bin/runtime_smoke" +profile_smoke="$consumer_bin/profile_smoke" +export LD_LIBRARY_PATH="$runtime/lib" +mv "$runtime/lib/liboliphaunt.so" "$runtime/lib/liboliphaunt.so.disabled" +missing_runtime_status=0 +"$profile_smoke" > "$TEST_TMPDIR/missing-runtime.log" 2>&1 || missing_runtime_status=$? +mv "$runtime/lib/liboliphaunt.so.disabled" "$runtime/lib/liboliphaunt.so" +if [ "$missing_runtime_status" -ne 127 ]; then + cat "$TEST_TMPDIR/missing-runtime.log" >&2 + echo 'consumer resolved liboliphaunt outside the candidate payload' >&2 + exit 1 +fi +export OLIPHAUNT_STREAM_QUEUE_MAX_BYTES=4096 +OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY=1 OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY=1 \ + "$runtime/bin/initdb" -D "$database/pgdata" -U postgres --auth=trust --no-sync --locale-provider=libc --locale=C --encoding=UTF8 +printf '%s\n' '{"schema":"oliphaunt-database-root-v1","engineFamily":"native","pgdata":"pgdata","postgresMajor":18,"physicalFormat":"native-pg18-v1"}' > "$database/.oliphaunt.json" +# Each process opens the same files: the second execution proves persistence. +"$smoke" "$database/pgdata" "$runtime" "$fixture" +"$smoke" "$database/pgdata" "$runtime" "$fixture" + +icu_database="$TEST_TMPDIR/icu-database" +mkdir "$icu_database" +ICU_DATA="$runtime/share/icu" OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY=1 \ + "$runtime/bin/initdb" -D "$icu_database/pgdata" -U postgres --auth=trust --no-sync --locale-provider=icu --icu-locale=en-US --encoding=UTF8 +printf '%s\n' '{"schema":"oliphaunt-database-root-v1","engineFamily":"native","pgdata":"pgdata","postgresMajor":18,"physicalFormat":"native-pg18-v1"}' > "$icu_database/.oliphaunt.json" +for attempt in 1 2; do + ICU_DATA=/ambient/unverified-icu "$profile_smoke" "$icu_database/pgdata" "$runtime" \ + "WITH ordered AS (SELECT item FROM (VALUES ('z'), ('a'), (chr(228))) AS input(item) ORDER BY item) SELECT CASE WHEN datlocprovider = 'i' AND datlocale = 'en-US' AND (SELECT string_agg(item, ',') FROM ordered) = 'a,' || chr(228) || ',z' THEN 'BAZEL_ICU_OK' ELSE 'BAZEL_ICU_MISMATCH' END FROM pg_database WHERE datname = current_database()" BAZEL_ICU_OK +done diff --git a/build_defs/native/rust-runtime-test.bzl b/build_defs/native/rust-runtime-test.bzl new file mode 100644 index 000000000..c7f45ac20 --- /dev/null +++ b/build_defs/native/rust-runtime-test.bzl @@ -0,0 +1,59 @@ +"""Run stock Rust test binaries against the exact final native carrier Files.""" + +load("//build_defs/extensions:extensions.bzl", "ExtensionMemberInfo") +load("@oliphaunt_metadata//:metadata.bzl", "NATIVE_CURRENT_ARTIFACTS", "NATIVE_HELPER_ARTIFACTS", "NATIVE_RUNTIME_ARTIFACTS", "PRODUCTS") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") + +def _impl(ctx): + if not ctx.file.runtime or not ctx.file.tools or not ctx.file.broker: + fail("Rust runtime qualification is missing original current Native, tools or Broker archive Files") + binary = ctx.attr.binary[DefaultInfo].files_to_run.executable + members = [target[ExtensionMemberInfo] for target in ctx.attr.extensions] + names = [member.sql_name for member in members] + if len({name: True for name in names}) != len(names) or names != sorted(names): + fail("Rust extension lifecycle requires unique, sorted canonical members") + if any([member.configuration != "linux-x64-gnu" for member in members]): + fail("Rust extension lifecycle requires actual Linux x64 member Files") + archives = [member.archive for member in members] + arguments = [binary, ctx.file.runtime, ctx.file.tools, ctx.file.broker, json.encode(ctx.attr.test_args), json.encode(names), ctx.workspace_name] + archives + sources = [ctx.file._runner] + ctx.files._helpers + result = bun_test_entrypoint(ctx, ctx.file._runner, arguments, arguments[:4] + archives + sources, source_files = sources, runfiles_argument = True, additional_runfiles = ctx.attr.binary[DefaultInfo].default_runfiles) + if RunEnvironmentInfo in ctx.attr.binary: + result.append(ctx.attr.binary[RunEnvironmentInfo]) + return result + +_native_rust_runtime_test = rule( + implementation = _impl, + test = True, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "binary": attr.label(mandatory = True, executable = True, cfg = "target"), + "runtime": attr.label(allow_single_file = True), + "tools": attr.label(allow_single_file = True), + "broker": attr.label(allow_single_file = True), + "test_args": attr.string_list(default = ["--test-threads=1", "--nocapture"]), + "extensions": attr.label_list(providers = [ExtensionMemberInfo]), + "_runner": attr.label(default = Label("//build_defs/native:rust-runtime-test.mts"), allow_single_file = True), + "_helpers": attr.label_list(default = [Label("//build_defs/native:host-runtime-test-helpers.mts"), Label("//:tools/packaging/portable-archive.mts"), Label("//:tools/packaging/release-directory-safety.mts")], allow_files = True), + }), + toolchains = BUN_SOURCE_TOOLCHAINS, +) + +def native_rust_runtime_test(name, **kwargs): + for attribute, product, kind, local in [ + ("runtime", "liboliphaunt-native", "native-runtime", "//src/native/runtime:github_archive"), + ("tools", "postgres-tools-native", "native-tools", "//src/native/postgres-tools:github_archive"), + ("broker", "oliphaunt-broker", "broker-helper", "//src/native/broker:github_archive"), + ]: + if NATIVE_CURRENT_ARTIFACTS == None: + if attribute not in kwargs: + kwargs[attribute] = local + continue + version = PRODUCTS[product]["version"] + artifacts = [row for row in NATIVE_RUNTIME_ARTIFACTS + NATIVE_HELPER_ARTIFACTS if row["product"] == product and row["kind"] == kind and row["target"] == "linux-x64-gnu"] + if len(artifacts) != 1: + fail("Rust runtime qualification requires its canonical " + product + " archive") + artifact = "github-release:" + artifacts[0]["asset"].replace("{version}", version) + row = NATIVE_CURRENT_ARTIFACTS.get(product + "/" + version + "/" + artifact) + # A present transport never requests local producers for a missing File. + kwargs[attribute] = row["file"]["path"] if row else None + _native_rust_runtime_test(name = name, args = bun_test_entrypoint_args(name), **kwargs) diff --git a/build_defs/native/rust-runtime-test.mts b/build_defs/native/rust-runtime-test.mts new file mode 100644 index 000000000..9d6f45a64 --- /dev/null +++ b/build_defs/native/rust-runtime-test.mts @@ -0,0 +1,174 @@ +import assert from 'node:assert/strict'; +import { copyFileSync, lstatSync, mkdirSync, mkdtempSync, readFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { extractPortableArchiveTree } from '../../tools/packaging/portable-archive.mts'; +import { removeOwnedDirectory } from '../../tools/packaging/release-directory-safety.mts'; +import { hostRuntimeEnvironment } from './host-runtime-test-helpers.mts'; + +export function assertExecutedRustTests(output: string): void { + const summaries = [...output.matchAll(/^test result: ok[.] (\d+) passed; 0 failed;/gmu)]; + assert(summaries.length > 0, 'Rust harness did not report a successful test result'); + assert(Number(summaries.at(-1)![1]) > 0, 'Rust runtime qualification executed zero tests'); +} + +export function nativeRustTestEnvironment( + native: string, + tools: string, + broker: string, + root: string, +): NodeJS.ProcessEnv { + assert.equal(process.platform, 'linux', 'Native Rust lifecycle qualification runs on Linux'); + const installed = path.join(native, 'runtime'); + const env = hostRuntimeEnvironment(installed, root); + delete env.ICU_DATA; + Object.assign(env, { + LIBOLIPHAUNT_PATH: path.join(native, 'lib/liboliphaunt.so'), + OLIPHAUNT_INSTALL_DIR: installed, + OLIPHAUNT_INITDB: path.join(installed, 'bin/initdb'), + OLIPHAUNT_POSTGRES: path.join(installed, 'bin/postgres'), + OLIPHAUNT_EMBEDDED_MODULE_DIR: path.join(native, 'lib/modules'), + OLIPHAUNT_TOOLS_DIR: path.join(tools, 'runtime'), + OLIPHAUNT_BROKER: path.join(broker, 'bin/oliphaunt-broker'), + OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY: '1', + OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY: '1', + OLIPHAUNT_RUNTIME_CACHE_DIR: path.join(root, 'native-cache'), + LD_LIBRARY_PATH: [ + path.join(native, 'lib'), + path.join(installed, 'lib'), + path.join(tools, 'runtime/lib'), + ].join(':'), + TMPDIR: path.join(root, 'tmp'), + TMP: path.join(root, 'tmp'), + TEMP: path.join(root, 'tmp'), + }); + for (const file of [ + env.LIBOLIPHAUNT_PATH, + env.OLIPHAUNT_INITDB, + env.OLIPHAUNT_POSTGRES, + env.OLIPHAUNT_BROKER, + path.join(tools, 'runtime/bin/psql'), + path.join(tools, 'runtime/bin/pg_basebackup'), + ]) { + assert( + file && lstatSync(file).isFile(), + 'Native Rust qualification needs its exact installed carrier Files', + ); + } + mkdirSync(env.TMPDIR!, { recursive: true }); + return env; +} + +/** Let the production SDK select and materialize original extension sidecars. */ +export function stageNativeRustExtensions( + root: string, + names: readonly string[], + archives: readonly string[], +): string | undefined { + assert.equal( + names.length, + archives.length, + 'Every extension needs its original declared archive', + ); + assert.equal(new Set(names).size, names.length, 'Extension Files cannot repeat a SQL member'); + assert.deepEqual( + names, + [...names].sort(), + 'Extension Files must follow canonical SQL-name order', + ); + for (const name of names) + assert(/^[a-z][a-z0-9_-]*$/u.test(name), 'Extension sidecar needs a canonical SQL name'); + if (names.length === 0) return undefined; + const resources = path.join(root, 'resources'); + for (const [index, source] of archives.entries()) { + const archive = path.join(root, `extension-${index}.tar.gz`); + // The outer Bazel File alias is transport; archive members remain strictly validated. + copyFileSync(source, archive); + const destination = path.join(resources, 'extension', names[index]); + extractPortableArchiveTree(archive, destination); + const descriptor = JSON.parse(readFileSync(path.join(destination, 'extension.json'), 'utf8')); + assert.equal(descriptor.schema, 'oliphaunt-extension-member-payload-v1'); + assert.equal( + descriptor.sql_name, + names[index], + 'Extension archive differs from its configured member', + ); + assert.equal(descriptor.family, 'native'); + assert.equal(descriptor.configuration, 'linux-x64-gnu'); + } + return resources; +} + +if (import.meta.main) { + const [ + binary, + runtimeArchive, + toolsArchive, + brokerArchive, + argsJson, + namesJson, + workspace, + ...trailingArguments + ] = Bun.argv.slice(2); + assert( + workspace && workspace === path.basename(workspace) && workspace !== '.' && workspace !== '..', + 'Expected declared runfiles workspace', + ); + assert( + binary && runtimeArchive && toolsArchive && brokerArchive && argsJson && namesJson, + 'Expected Rust executable and exact final native carrier Files', + ); + const args = JSON.parse(argsJson) as unknown; + const names = JSON.parse(namesJson) as unknown; + assert( + Array.isArray(names) && names.every((name) => typeof name === 'string'), + 'Expected configured extension SQL names', + ); + const extensionArchives = trailingArguments.slice(0, names.length); + const runfilesRoot = trailingArguments[names.length]; + assert( + runfilesRoot && path.isAbsolute(runfilesRoot), + 'Expected original directory runfiles root', + ); + assert( + Array.isArray(args) && args.every((value) => typeof value === 'string'), + 'Expected Rust harness arguments', + ); + const root = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'native-rust-')); + try { + const destinations = ['native', 'tools', 'broker'].map((name) => path.join(root, name)); + for (const [index, source] of [runtimeArchive, toolsArchive, brokerArchive].entries()) { + const archive = path.join(root, 'input-' + index + '.tar.gz'); + // Resolve only the outer declared File alias before strict archive validation. + copyFileSync(source, archive); + extractPortableArchiveTree(archive, destinations[index]); + } + const env = nativeRustTestEnvironment(destinations[0], destinations[1], destinations[2], root); + // Preserve the original test data namespace when native code changes cwd. + env.TEST_SRCDIR = runfilesRoot; + env.TEST_WORKSPACE = workspace; + const resources = stageNativeRustExtensions(root, names, extensionArchives); + if (resources) { + env.OLIPHAUNT_RESOURCES_DIR = resources; + env.OLIPHAUNT_NATIVE_EXTENSION_PROOF_SQL_NAMES = names.join(','); + env.OLIPHAUNT_EXTENSION_MATRIX = '1'; + } + const result = Bun.spawnSync( + [path.resolve(binary), ...args, ...trailingArguments.slice(names.length + 1)], + { + cwd: path.join(runfilesRoot, workspace), + env, + stdin: 'inherit', + stdout: 'pipe', + stderr: 'pipe', + timeout: 600_000, + }, + ); + process.stdout.write(result.stdout); + process.stderr.write(result.stderr); + assert.equal(result.exitCode, 0, 'Native Rust test binary failed'); + assertExecutedRustTests(result.stdout.toString() + '\n' + result.stderr.toString()); + } finally { + removeOwnedDirectory(root); + } +} diff --git a/build_defs/native/rust-runtime-test.test.mts b/build_defs/native/rust-runtime-test.test.mts new file mode 100644 index 000000000..41bd805d2 --- /dev/null +++ b/build_defs/native/rust-runtime-test.test.mts @@ -0,0 +1,149 @@ +import assert from 'node:assert/strict'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { gzipSync } from 'node:zlib'; +import { test } from 'node:test'; +import { + assertExecutedRustTests, + nativeRustTestEnvironment, + stageNativeRustExtensions, +} from './rust-runtime-test.mts'; + +test('runtime proof requires a successful harness with executed tests', () => { + assertExecutedRustTests( + 'running 3 tests\ntest result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.03s', + ); + for (const output of [ + 'running 0 tests\ntest result: ok. 0 passed; 0 failed;', + 'test result: FAILED. 1 passed; 1 failed;', + '', + ]) + assert.throws(() => assertExecutedRustTests(output)); + assert.throws(() => + assertExecutedRustTests( + 'test result: ok. 1 passed; 0 failed;\ntest result: ok. 0 passed; 0 failed;', + ), + ); +}); + +test('native carrier bindings cannot fall back to an installed host runtime', () => { + const root = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'native-rust-env-')); + try { + const native = path.join(root, 'native'); + const tools = path.join(root, 'tools'); + const broker = path.join(root, 'broker'); + const files = [ + path.join(native, 'lib/liboliphaunt.so'), + path.join(native, 'runtime/bin/initdb'), + path.join(native, 'runtime/bin/postgres'), + path.join(tools, 'runtime/bin/psql'), + path.join(tools, 'runtime/bin/pg_basebackup'), + path.join(broker, 'bin/oliphaunt-broker'), + ]; + for (const file of files) { + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, 'candidate'); + } + const env = nativeRustTestEnvironment(native, tools, broker, root); + assert.equal(env.LIBOLIPHAUNT_PATH, files[0]); + assert.equal(env.OLIPHAUNT_BROKER, files.at(-1)); + assert.equal(env.OLIPHAUNT_INSTALL_DIR, path.join(native, 'runtime')); + assert.equal(env.OLIPHAUNT_TOOLS_DIR, path.join(tools, 'runtime')); + assert.equal(env.ICU_DATA, undefined); + assert.equal(env.OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY, '1'); + assert(!env.LD_LIBRARY_PATH?.includes('/usr/lib')); + assert.equal(readFileSync(files[0], 'utf8'), 'candidate'); + rmSync(files[0]); + assert.throws(() => nativeRustTestEnvironment(native, tools, broker, root)); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('original extension sidecars retain both ABI profiles and auxiliary data through File aliases', async () => { + const root = mkdtempSync( + path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'native-extension-stage-'), + ); + try { + const files = { + 'extension.json': JSON.stringify({ + schema: 'oliphaunt-extension-member-payload-v1', + sql_name: 'vector', + family: 'native', + configuration: 'linux-x64-gnu', + }), + 'lib/modules/vector.so': 'embedded ABI', + 'lib/postgresql/vector.so': 'server ABI', + 'share/postgresql/extension/vector.control': "default_version = '0.8.2'", + 'share/postgresql/extension/vector--0.8.2.sql': 'CREATE EXTENSION fixture;', + 'share/postgresql/tsearch_data/fixture.rules': 'auxiliary data', + }; + const archive = path.join(root, 'original.tar.gz'); + const bytes = gzipSync(await new Bun.Archive(files).bytes()); + writeFileSync(archive, bytes); + const alias = path.join(root, 'declared-file-alias.tar.gz'); + symlinkSync(archive, alias); + const resources = stageNativeRustExtensions(root, ['vector'], [alias]); + assert(resources); + assert.equal(resources, path.join(root, 'resources')); + for (const [name, value] of Object.entries(files)) + assert.equal(readFileSync(path.join(resources, 'extension/vector', name), 'utf8'), value); + assert.deepEqual( + readFileSync(archive), + bytes, + 'the original declared producer File is unchanged', + ); + assert.equal(stageNativeRustExtensions(root, [], []), undefined); + assert.throws( + () => stageNativeRustExtensions(root, ['vector'], []), + /original declared archive/u, + ); + assert.throws( + () => stageNativeRustExtensions(root, ['vector', 'vector'], [archive, archive]), + /repeat/u, + ); + assert.throws( + () => stageNativeRustExtensions(root, ['../../outside'], [archive]), + /canonical SQL name/u, + ); + assert.throws( + () => stageNativeRustExtensions(root, ['hstore'], [archive]), + /configured member/u, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('extension sidecars reject another target or family instead of substituting host resources', async () => { + const root = mkdtempSync( + path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'native-extension-profile-'), + ); + try { + for (const override of [ + { configuration: 'linux-arm64-gnu' }, + { family: 'wasix' }, + { schema: 'unknown' }, + ]) { + const archive = path.join(root, 'wrong-profile.tar.gz'); + writeFileSync( + archive, + gzipSync( + await new Bun.Archive({ + 'extension.json': JSON.stringify({ + schema: 'oliphaunt-extension-member-payload-v1', + sql_name: 'vector', + family: 'native', + configuration: 'linux-x64-gnu', + ...override, + }), + }).bytes(), + ), + ); + assert.throws(() => stageNativeRustExtensions(root, ['vector'], [archive])); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/build_defs/native/windows-abi-conformance.test.mts b/build_defs/native/windows-abi-conformance.test.mts new file mode 100644 index 000000000..cba6d8a99 --- /dev/null +++ b/build_defs/native/windows-abi-conformance.test.mts @@ -0,0 +1,63 @@ +import assert from 'node:assert/strict'; +import { + copyFileSync, + mkdirSync, + mkdtempSync, + readFileSync, + readdirSync, + renameSync, + rmSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import { basename, join, resolve } from 'node:path'; +import { windowsVcRuntimeProfileNames } from '../../tools/packaging/windows-vc-runtime-closure.mts'; +import { + assertMissingHostRuntime, + extractNativePayload, + hostRuntimeEnvironment, + runHostBinary, +} from './host-runtime-test-helpers.mts'; + +assert.equal(process.platform, 'win32', 'installed Windows ABI proof requires Windows execution'); +const [payloadArgument, binaryArgument, ...crtArguments] = process.argv.slice(2); +const payload = payloadArgument && resolve(payloadArgument); +const sourceBinary = binaryArgument && resolve(binaryArgument); +// Bazel's $(locations) supplies one space-separated list of normalized runfile +// paths; this repository exports the CRT files under simple crt/ labels. +const crtSources = crtArguments + .flatMap((argument) => argument.split(/\s+/u)) + .map((file) => resolve(file)); +assert(payload && sourceBinary, 'expected runtime payload, ABI executable and declared CRT files'); +assert.deepEqual( + crtSources.map((file) => basename(file).toLowerCase()).sort(), + windowsVcRuntimeProfileNames('provider'), + 'ABI consumer requires the exact selected provider CRT closure', +); +const root = mkdtempSync(join(process.env.TEST_TMPDIR ?? tmpdir(), 'windows-abi-')); +try { + const runtime = join(root, 'runtime'); + const consumer = join(root, 'consumer'); + const bin = join(consumer, 'bin'); + await extractNativePayload(payload, runtime); + mkdirSync(bin, { recursive: true }); + const binary = join(bin, 'abi_conformance.exe'); + copyFileSync(sourceBinary, binary); + for (const name of readdirSync(join(runtime, 'bin')).filter((name) => + name.toLowerCase().endsWith('.dll'), + )) + copyFileSync(join(runtime, 'bin', name), join(bin, name)); + for (const source of crtSources) + assert( + readFileSync(join(bin, basename(source))).equals(readFileSync(source)), + `installed ${basename(source)} differs from the selected compiler CRT`, + ); + const env = hostRuntimeEnvironment(consumer, root); + runHostBinary(binary, [], env, consumer); + const library = join(bin, 'oliphaunt.dll'); + renameSync(library, library + '.disabled'); + const missing = Bun.spawnSync([binary], { env, cwd: consumer, stdout: 'pipe', stderr: 'pipe' }); + assertMissingHostRuntime(missing, 'oliphaunt.dll'); + console.log('Installed Windows C ABI with declared runtime, ICU and exact CRT DLLs: PASS'); +} finally { + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/native/windows-exports.mts b/build_defs/native/windows-exports.mts new file mode 100644 index 000000000..5917b9c92 --- /dev/null +++ b/build_defs/native/windows-exports.mts @@ -0,0 +1,42 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +/** PostgreSQL18.4 msvc_gendef.pl's x64 symbol selection, without shell/stamps. */ +export function postgresExports(symbols: string): string { + const exports = new Map(); + for (const line of symbols.split(/\r?\n/)) { + const fields = line + .replace(/notype \(\)/g, 'func') + .replace(/notype/g, 'data') + .trim() + .split(/\s+/); + if (!/^[A-F0-9]{3,}$/.test(fields[0] ?? '') || fields.length < 7) continue; + const [, , section, type, visibility, , name] = fields; + if (section === 'UNDEF' || visibility !== 'External' || !name) continue; + if ( + /^(?:@|\(|__real|__xmm|__imp|__IMPORT_DESCRIPTOR|__NULL_IMPORT|\?\?_C)/.test(name) || + /NULL_THUNK_DATA$/.test(name) + ) + continue; + if (type !== 'data' && type !== 'func') + throw new Error(`Unsupported MSVC symbol type for ${name}: ${type}`); + const previous = exports.get(name); + if (previous && previous !== type) + throw new Error(`MSVC symbol changes kind between core archives: ${name}`); + exports.set(name, type); + } + if (!exports.size) throw new Error('MSVC produced no defined external core symbols'); + return ( + 'EXPORTS\n' + + [...exports] + .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)) + .map(([name, type]) => ` ${name}${type === 'data' ? ' DATA' : ''}\n`) + .join('') + ); +} + +if (import.meta.main) { + const [input, output, ...extra] = process.argv.slice(2); + if (!input || !output || extra.length) + throw new Error('usage: windows-exports.mts SYMBOLS OUTPUT.def'); + writeFileSync(output, postgresExports(readFileSync(input, 'utf8'))); +} diff --git a/build_defs/native/windows-exports.test.mts b/build_defs/native/windows-exports.test.mts new file mode 100644 index 000000000..c79452c99 --- /dev/null +++ b/build_defs/native/windows-exports.test.mts @@ -0,0 +1,32 @@ +import { describe, expect, test } from 'bun:test'; +import { postgresExports } from './windows-exports.mts'; + +describe('MSVC backend exports', () => { + test('preserves upstream defined external DATA and function semantics', () => { + const symbols = [ + '02E 00000130 SECTA notype External | standbyState', + '064 00000020 SECTC notype () External | XLogCheckBuffer', + '02F 00000009 SECT9 notype Static | LocalRecoveryInProgress', + '065 00000000 UNDEF notype () External | BufferGetTag', + '066 00000000 SECT2 notype External | __imp_malloc', + '067 00000000 SECT2 notype External | __real@00000000', + '068 00000000 SECT2 notype External | ??_C@_01@literal', + '069 00000000 SECT2 notype External | __NULL_IMPORT_DESCRIPTOR', + '070 00000000 SECT2 notype External | foo_NULL_THUNK_DATA', + '071 00000000 SECT2 notype External | @compiler', + ].join('\n'); + expect(postgresExports(symbols)).toBe('EXPORTS\n XLogCheckBuffer\n standbyState DATA\n'); + }); + test('merges duplicate definitions without ordinals or 32-bit decoration changes', () => { + const symbol = '001 00000000 SECT1 notype () External | _x64Name'; + expect(postgresExports(`${symbol}\r\n${symbol}`)).toBe('EXPORTS\n _x64Name\n'); + }); + test('rejects empty output and contradictory ABI symbol kinds', () => { + expect(() => postgresExports('MSVC banner')).toThrow('no defined'); + expect(() => + postgresExports( + '001 00000000 SECT1 notype External | symbol\n002 00000000 SECT1 notype () External | symbol', + ), + ).toThrow('changes kind'); + }); +}); diff --git a/build_defs/native/windows-generators.bzl b/build_defs/native/windows-generators.bzl new file mode 100644 index 000000000..1700982cb --- /dev/null +++ b/build_defs/native/windows-generators.bzl @@ -0,0 +1,65 @@ +"""Canonical native Windows Flex/Bison execution toolchains.""" + +load("@rules_bison//bison:providers.bzl", "BisonToolchainInfo") +load("@rules_flex//flex:providers.bzl", "FlexToolchainInfo") +load(":repositories.bzl", "source_string_values") + +def _executable_impl(ctx): + executable = ctx.actions.declare_file(ctx.label.name + ".exe") + ctx.actions.symlink(output = executable, target_file = ctx.file.binary, is_executable = True) + return [DefaultInfo( + files = depset([executable]), + executable = executable, + runfiles = ctx.runfiles(files = [ctx.file.binary] + ctx.files.data), + )] + +windows_generator_executable = rule( + implementation = _executable_impl, + executable = True, + attrs = { + "binary": attr.label(mandatory = True, allow_single_file = [".exe"]), + "data": attr.label_list(allow_files = True), + }, +) + +def _toolchain_impl(ctx): + tool = ctx.attr.tool[DefaultInfo].files_to_run + files = depset([tool.executable], transitive = [ctx.attr.tool[DefaultInfo].default_runfiles.files]) + if ctx.attr.kind == "flex": + info = FlexToolchainInfo(all_files = files, flex_tool = tool, flex_env = {}, flex_lexer_h = ctx.file.data_anchor) + return [platform_common.ToolchainInfo(flex_toolchain = info, embedded_m4 = True)] + info = BisonToolchainInfo(all_files = files, bison_tool = tool, bison_env = {"BISON_PKGDATADIR": ctx.file.data_anchor.dirname}) + return [platform_common.ToolchainInfo(bison_toolchain = info, embedded_m4 = True)] + +windows_generator_toolchain = rule( + implementation = _toolchain_impl, + attrs = { + "tool": attr.label(mandatory = True, executable = True, cfg = "exec"), + "kind": attr.string(mandatory = True, values = ["flex", "bison"]), + "data_anchor": attr.label(mandatory = True, allow_single_file = True), + }, +) + +def _repository_impl(ctx): + source = source_string_values(ctx.read(ctx.attr.manifest)) + # Use the same reviewed native Windows payload as development/CI setup. + ctx.download_and_extract(url = source["url"], sha256 = source["sha256"]) + ctx.file("BUILD.bazel", """load(%s, "windows_generator_executable", "windows_generator_toolchain") +package(default_visibility = ["//visibility:public"]) +exports_files(["FlexLexer.h", "data/README.md"]) +windows_generator_executable(name = "flex", binary = %s, data = ["FlexLexer.h"]) +windows_generator_executable(name = "bison", binary = %s, data = glob(["data/**"], allow_empty = False)) +windows_generator_toolchain(name = "flex_info", kind = "flex", tool = ":flex", data_anchor = "FlexLexer.h") +windows_generator_toolchain(name = "bison_info", kind = "bison", tool = ":bison", data_anchor = "data/README.md") +toolchain(name = "flex_toolchain", toolchain = ":flex_info", toolchain_type = "@rules_flex//flex:toolchain_type", exec_compatible_with = ["@platforms//os:windows", "@platforms//cpu:x86_64"]) +toolchain(name = "bison_toolchain", toolchain = ":bison_info", toolchain_type = "@rules_bison//bison:toolchain_type", exec_compatible_with = ["@platforms//os:windows", "@platforms//cpu:x86_64"]) +""" % (repr(str(ctx.attr.definition)), repr(source["flex_path"]), repr(source["bison_path"]))) + return ctx.repo_metadata(reproducible = True) + +windows_generators_repository = repository_rule( + implementation = _repository_impl, + attrs = { + "manifest": attr.label(default = Label("//tools/dev:winflexbison.toml"), allow_single_file = True), + "definition": attr.label(default = Label(":windows-generators.bzl"), allow_single_file = True), + }, +) diff --git a/build_defs/native/windows-restricted-process.c b/build_defs/native/windows-restricted-process.c new file mode 100644 index 000000000..04fea905d --- /dev/null +++ b/build_defs/native/windows-restricted-process.c @@ -0,0 +1,58 @@ +#include "postgres_fe.h" +#include "common/logging.h" +#include + +int main(int argc, char **argv) { + if (argc < 2) return 2; + pg_logging_init(argv[0]); + const wchar_t *source = GetCommandLineW(); + wchar_t *line = pg_malloc((wcslen(source) + 1) * sizeof(wchar_t)); + wcscpy(line, source); + wchar_t *command = line; + // Keep the caller's child argument quoting after our executable. + int quoted = 0; + while (*command && (quoted || (*command != L' ' && *command != L'\t'))) { + if (*command == L'"') quoted = !quoted; + command++; + } + while (*command == L' ' || *command == L'\t') command++; + HANDLE original = NULL, restricted = NULL; + SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_AUTHORITY; + SID_AND_ATTRIBUTES denied[2] = {{0}}; + STARTUPINFOW startup = {0}; + PROCESS_INFORMATION child = {0}; + DWORD status = 1; + // Match PostgreSQL's restricted token; its common launcher cannot pass pipe handles. + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &original) || + !AllocateAndInitializeSid(&authority, 2, SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &denied[0].Sid) || + !AllocateAndInitializeSid(&authority, 2, SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_POWER_USERS, 0, 0, 0, 0, 0, 0, &denied[1].Sid) || + !CreateRestrictedToken(original, DISABLE_MAX_PRIVILEGE, 2, denied, + 0, NULL, 0, NULL, &restricted) || + !AddUserToTokenDacl(restricted)) goto failed; + startup.cb = sizeof(startup); + startup.dwFlags = STARTF_USESTDHANDLES; + startup.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + startup.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); + startup.hStdError = GetStdHandle(STD_ERROR_HANDLE); + if (!SetHandleInformation(startup.hStdInput, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) || + !SetHandleInformation(startup.hStdOutput, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) || + !SetHandleInformation(startup.hStdError, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) || + !CreateProcessAsUserW(restricted, NULL, command, NULL, NULL, TRUE, + 0, NULL, NULL, &startup, &child)) goto failed; + if (WaitForSingleObject(child.hProcess, INFINITE) != WAIT_OBJECT_0 || + !GetExitCodeProcess(child.hProcess, &status)) goto failed; + goto cleanup; +failed: + fprintf(stderr, "restricted process launch failed: Windows error %lu\n", (unsigned long)GetLastError()); + status = 1; +cleanup: + if (child.hThread) CloseHandle(child.hThread); + if (child.hProcess) CloseHandle(child.hProcess); + if (restricted) CloseHandle(restricted); + if (original) CloseHandle(original); + for (int i = 0; i < 2; i++) if (denied[i].Sid) FreeSid(denied[i].Sid); + free(line); + return (int)status; +} diff --git a/build_defs/native/windows-restricted-process.test.mts b/build_defs/native/windows-restricted-process.test.mts new file mode 100644 index 000000000..7008f7165 --- /dev/null +++ b/build_defs/native/windows-restricted-process.test.mts @@ -0,0 +1,86 @@ +import assert from 'node:assert/strict'; +import { copyFileSync, mkdirSync, mkdtempSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join, win32 } from 'node:path'; + +const text = (bytes: Uint8Array) => Buffer.from(bytes).toString('utf8'); + +if (process.argv[2] === '--child') { + const input = await Bun.stdin.text(); + await Bun.write(Bun.stdout, JSON.stringify({ input, args: process.argv.slice(3) })); + await Bun.write(Bun.stderr, 'restricted child stderr\n'); + process.exit(7); +} + +assert.equal(process.platform, 'win32'); +const [source] = process.argv.slice(2); +assert(source); +const root = mkdtempSync(join(process.env.TEST_TMPDIR ?? tmpdir(), 'restricted-process-')); +try { + const directory = join(root, 'launcher with spaces'); + mkdirSync(directory); + const launcher = join(directory, 'restricted process.exe'); + const child = join(root, 'child script with spaces.mts'); + copyFileSync(source, launcher); + copyFileSync(import.meta.path, child); + const systemRoot = Object.entries(process.env).find( + ([name]) => name.toLowerCase() === 'systemroot', + )?.[1]; + assert(systemRoot && win32.isAbsolute(systemRoot)); + const env = { + SystemRoot: systemRoot, + PATH: [win32.join(systemRoot, 'System32'), systemRoot].join(';'), + TEMP: root, + TMP: root, + }; + const args = [ + 'argument with spaces', + 'quote "inside"', + 'backslash before quote \\"', + 'trailing backslash \\', + 'Unicode Ω-é-雪', + ]; + const input = 'restricted pipe input Ω-é-雪\n'; + for (const stdin of [Buffer.from(input), 'ignore'] as const) { + const result = Bun.spawnSync( + [launcher, process.execPath, '--no-install', '--no-env-file', child, '--child', ...args], + { + cwd: root, + env, + stdin, + stdout: 'pipe', + stderr: 'pipe', + timeout: 15_000, + }, + ); + assert.equal(result.exitCode, 7, text(result.stderr)); + assert.deepEqual(JSON.parse(text(result.stdout)), { + input: stdin === 'ignore' ? '' : input, + args, + }); + assert.equal(text(result.stderr), 'restricted child stderr\n'); + } + const empty = Bun.spawnSync([launcher], { + cwd: root, + env, + stdin: 'ignore', + stdout: 'pipe', + stderr: 'pipe', + }); + assert.equal(empty.exitCode, 2); + const missing = Bun.spawnSync([launcher, join(root, 'missing program.exe')], { + cwd: root, + env, + stdin: 'ignore', + stdout: 'pipe', + stderr: 'pipe', + timeout: 15_000, + }); + assert.equal(missing.exitCode, 1); + assert.match(text(missing.stderr), /restricted process launch failed: Windows error \d+/u); + console.log( + 'Restricted process: pipe and ignored stdin, stdout, stderr, Unicode/quoted argv, exit status and missing program PASS', + ); +} finally { + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/native/windows_config.bzl b/build_defs/native/windows_config.bzl new file mode 100644 index 000000000..2879345b7 --- /dev/null +++ b/build_defs/native/windows_config.bzl @@ -0,0 +1,93 @@ +"""Declared PostgreSQL product policy for the MSVC x64 Windows profile. + +No HAVE_* capability is asserted here. The selected compiler/SDK must establish +those facts. ABI expectations are separate from generated configuration values. +""" + +WINDOWS_CONFIG = { + "BLCKSZ": "8192", + "CONFIGURE_ARGS": '"Bazel Windows x64 MSVC ICU profile"', + "DEF_PGPORT": "5432", + "DEF_PGPORT_STR": '"5432"', + "DLSUFFIX": '".dll"', + "MEMSET_LOOP_LIMIT": "1024", + "PACKAGE_BUGREPORT": '"pgsql-bugs@lists.postgresql.org"', + "PACKAGE_NAME": '"PostgreSQL"', + "PACKAGE_TARNAME": '"postgresql"', + "PACKAGE_URL": '"https://www.postgresql.org/"', + "PG_KRB_SRVNAM": '"postgres"', + "RELSEG_SIZE": "131072", + "USE_ICU": "1", + # Upstream meson.build selects these by Windows/MSVC x64 domain. + "USE_SSE42_CRC32C_WITH_RUNTIME_CHECK": "1", + "USE_WIN32_SEMAPHORES": "1", + "USE_WIN32_SHARED_MEMORY": "1", + "WIN32_STACK_RLIMIT": "4194304", + "XLOG_BLCKSZ": "8192", + # PG uses a separate spelling to avoid colliding with __declspec(restrict). + "pg_restrict": "__restrict", +} + +# Contract expectations, not a substitute for target compiler sizeof/alignof +# checks. UCRT off_t is 32-bit; PG's win32_port.h supplies a 64-bit pgoff_t and +# fseeko/ftello wrappers rather than pretending that off_t is 64-bit. +WINDOWS_X64_ABI = { + "ALIGNOF_DOUBLE": "8", + "ALIGNOF_INT": "4", + "ALIGNOF_INT64_T": "8", + "ALIGNOF_LONG": "4", + "ALIGNOF_SHORT": "2", + "MAXIMUM_ALIGNOF": "8", + "SIZEOF_LONG": "4", + "SIZEOF_LONG_LONG": "8", + "SIZEOF_OFF_T": "4", + "SIZEOF_SIZE_T": "8", + "SIZEOF_VOID_P": "8", +} + +WINDOWS_OS_HEADER = "src/include/port/win32.h" +WINDOWS_INCLUDE_DIRECTORIES = [ + "src/include/port/win32", + "src/include/port/win32_msvc", + # libpq-int.h includes pthread-win32.h from src/port. + "src/port", +] + +WINDOWS_DEFINES = [ + "WIN32", + "WINDOWS", + "__WINDOWS__", + "__WIN32__", + "_CRT_SECURE_NO_DEPRECATE", + "_CRT_NONSTDC_NO_DEPRECATE", +] + +# Apply to producing backend/common/port/main objects, never exported header +# dependencies: extension modules must compile with PGDLLIMPORT = dllimport. +WINDOWS_BACKEND_DEFINES = ["BUILDING_DLL"] +WINDOWS_WRAPPER_DEFINES = ["OLIPHAUNT_BUILDING_DLL", "_CRT_SECURE_NO_WARNINGS"] + +WINDOWS_COPTS = [ + "/std:c11", + "/wd4018", + "/wd4244", + "/wd4273", + "/wd4101", + "/wd4102", + "/wd4090", + "/wd4267", +] + +# /MD is owned by the standard MSVC toolchain's dynamic_link_msvcrt feature. +# These are the explicit SDK import libraries used by the canonical embedded +# Windows construction recipe, including its wrapper and PostgreSQL closure. +WINDOWS_LINKOPTS = [ + "/INCREMENTAL:NO", + "/STACK:4194304", + "ws2_32.lib", + "secur32.lib", + "advapi32.lib", + "shell32.lib", + "user32.lib", + "bcrypt.lib", +] diff --git a/build_defs/native/windows_link.bzl b/build_defs/native/windows_link.bzl new file mode 100644 index 000000000..28a82831f --- /dev/null +++ b/build_defs/native/windows_link.bzl @@ -0,0 +1,115 @@ +"""Bounded native MSVC export/resource/executable link actions for PostgreSQL.""" + +load("@rules_cc//cc/common:cc_common.bzl", "cc_common") +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") +load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain", "use_cc_toolchain") +load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") + + +def _cc(ctx): + toolchain = find_cc_toolchain(ctx) + features = cc_common.configure_features(ctx = ctx, cc_toolchain = toolchain, requested_features = ctx.features, unsupported_features = ctx.disabled_features) + variables = cc_common.create_compile_variables(feature_configuration = features, cc_toolchain = toolchain) + environment = cc_common.get_environment_variables(feature_configuration = features, action_name = ACTION_NAMES.c_compile, variables = variables) + return toolchain, features, environment + +def _exports_impl(ctx): + toolchain, _, environment = _cc(ctx) + archives = {} + for dep in ctx.attr.roots: + for linker_input in dep[CcInfo].linking_context.linker_inputs.to_list(): + for library in linker_input.libraries: + # Shared dependencies expose interface libraries; never export + # their imported symbols as though they belonged to the engine. + archive = library.static_library or library.pic_static_library + if archive: + archives[archive.path] = archive + if not archives: + fail("PostgreSQL Windows exports require actual producing core archives") + symbols = ctx.actions.declare_file(ctx.label.name + ".symbols") + ctx.actions.run(executable = ctx.file._dumpbin, arguments = ["/nologo", "/symbols", "/out:" + symbols.path] + sorted(archives), + inputs = depset(archives.values(), transitive = [toolchain.all_files]), outputs = [symbols], env = environment, mnemonic = "PostgresMsvcSymbols") + output = ctx.actions.declare_file(ctx.label.name + ".def") + bun_file_action(ctx, entry_point = ctx.file._parser, source_files = [ctx.file._parser], arguments = [symbols.path, output.path], + inputs = [ctx.file._parser, symbols], outputs = [output], mnemonic = "PostgresMsvcExports") + return [DefaultInfo(files = depset([output]))] + +postgres_windows_exports = rule( + implementation = _exports_impl, + attrs = { + "roots": attr.label_list(mandatory = True, providers = [CcInfo]), + "_dumpbin": attr.label(default = Label("@native_msvc_sdk//:compiler_bin/dumpbin.exe"), allow_single_file = True, cfg = "exec"), + "_parser": attr.label(default = Label("//build_defs/native:windows-exports.mts"), allow_single_file = True), + }, + fragments = ["cpp"], + toolchains = use_cc_toolchain() + BUN_SOURCE_TOOLCHAINS, +) + +def _resource_impl(ctx): + toolchain, _, environment = _cc(ctx) + headers = [file for file in ctx.files.configuration if file.basename == "pg_config.h"] + if len(headers) != 1: + fail("MSVC version resources require the selected single pg_config.h") + template = ctx.actions.declare_file(ctx.label.name + ".rc") + icon = 'IDI_ICON ICON "' + ctx.file.icon.path.replace("\\", "/") + '"' if ctx.file.icon else "" + ctx.actions.expand_template(template = ctx.file.template, output = template, substitutions = { + "FILEDESC": '"' + ctx.attr.description + '"', + "_INTERNAL_NAME_": '"' + ctx.attr.filename + '"', + "_ORIGINAL_NAME_": '"' + ctx.attr.filename + '"', + "_ICO_": icon, + }) + output = ctx.actions.declare_file(ctx.label.name + ".res") + ctx.actions.run(executable = ctx.file._rc, arguments = ["/nologo", "/i", headers[0].dirname, "/fo", output.path, template.path], + inputs = depset([template] + ctx.files.configuration + ([ctx.file.icon] if ctx.file.icon else []), transitive = [toolchain.all_files]), + outputs = [output], env = environment, mnemonic = "PostgresMsvcResource") + return [DefaultInfo(files = depset([output]))] + +postgres_windows_resource = rule( + implementation = _resource_impl, + attrs = { + "template": attr.label(mandatory = True, allow_single_file = True), + "configuration": attr.label(mandatory = True, allow_files = True), + "filename": attr.string(mandatory = True), + "description": attr.string(mandatory = True), + "icon": attr.label(allow_single_file = True), + "_rc": attr.label(default = Label("@native_msvc_sdk//:sdk_bin/rc.exe"), allow_single_file = True, cfg = "exec"), + }, + fragments = ["cpp"], + toolchains = use_cc_toolchain(), +) + +def _server_impl(ctx): + toolchain, features, _ = _cc(ctx) + # The ordinary server is an executable, but its extensions import backend + # functions AND DATA from a postgres.exe import library. cc_binary's DLL + # export helper only covers linkshared outputs, so declare this real output + # directly through the same native C++ linker API. + import_library = ctx.actions.declare_file("postgres.lib") + output = cc_common.link( + actions = ctx.actions, + feature_configuration = features, + cc_toolchain = toolchain, + linking_contexts = [dep[CcInfo].linking_context for dep in ctx.attr.deps], + user_link_flags = ctx.attr.linkopts + [file.path for file in ctx.files.resources] + ["/DEF:" + ctx.file.exports.path, "/IMPLIB:" + import_library.path], + additional_inputs = [ctx.file.exports] + ctx.files.resources, + additional_outputs = [import_library], + name = "postgres", + output_type = "executable", + link_deps_statically = True, + stamp = 0, + ) + return [DefaultInfo(files = depset([output.executable]), executable = output.executable), OutputGroupInfo(interface_library = depset([import_library]))] + +postgres_windows_server = rule( + implementation = _server_impl, + attrs = { + "deps": attr.label_list(mandatory = True, providers = [CcInfo]), + "exports": attr.label(mandatory = True, allow_single_file = True), + "resources": attr.label_list(allow_files = True), + "linkopts": attr.string_list(), + }, + fragments = ["cpp"], + toolchains = use_cc_toolchain(), + executable = True, +) diff --git a/build_defs/native/windows_sources.bzl b/build_defs/native/windows_sources.bzl new file mode 100644 index 000000000..1964659a8 --- /dev/null +++ b/build_defs/native/windows_sources.bzl @@ -0,0 +1,69 @@ +"""PostgreSQL 18.4 Windows/MSVC sources in addition to the shared inventories. + +Membership follows src/port/meson.build, src/backend/port/meson.build, +src/backend/port/win32/meson.build and src/interfaces/libpq/meson.build. +""" + +load(":postgres_sources.bzl", "POSTGRES_PORT_CRC_X86_RUNTIME_SOURCES", "POSTGRES_PORT_REPLACEMENT_SOURCES") + +# These units are compiled independently for backend and frontend roles. +WINDOWS_PORT_SOURCES = [ + "src/port/dirmod.c", + "src/port/kill.c", + "src/port/open.c", + "src/port/system.c", + "src/port/win32common.c", + "src/port/win32dlopen.c", + "src/port/win32env.c", + "src/port/win32error.c", + "src/port/win32fdatasync.c", + "src/port/win32fseek.c", + "src/port/win32gai_strerror.c", + "src/port/win32getrusage.c", + "src/port/win32link.c", + "src/port/win32ntdll.c", + "src/port/win32pread.c", + "src/port/win32pwrite.c", + "src/port/win32security.c", + "src/port/win32setlocale.c", + "src/port/win32stat.c", + # Upstream adds these two for MSVC, separately from the OS selection. + "src/port/dirent.c", + "src/port/win32gettimeofday.c", +] + +WINDOWS_BACKEND_PORT_SOURCES = [ + "src/backend/port/win32_sema.c", + "src/backend/port/win32_shmem.c", + "src/backend/port/win32/crashdump.c", + "src/backend/port/win32/signal.c", + "src/backend/port/win32/socket.c", + "src/backend/port/win32/timer.c", +] + +WINDOWS_LIBPQ_SOURCES = [ + "src/interfaces/libpq/pthread-win32.c", + "src/interfaces/libpq/win32.c", +] + +# Upstream unconditionally selects SSE4.2 with a runtime CPU check for MSVC +# x86/x64. The fallback is part of this inventory, not a second CRC selection. +WINDOWS_PORT_CRC_SOURCES = POSTGRES_PORT_CRC_X86_RUNTIME_SOURCES + +# Absence of a POSIX barrier on Windows does not select its pthread replacement: +# upstream explicitly omits that candidate on Windows. The two getopt functions +# are always replaced, even when a Windows environment supplies them. +WINDOWS_PORT_REPLACEMENT_SOURCES = { + macro: source + for macro, source in POSTGRES_PORT_REPLACEMENT_SOURCES.items() + if macro != "HAVE_PTHREAD_BARRIER_WAIT" +} +WINDOWS_FORCED_PORT_REPLACEMENTS = ["HAVE_GETOPT", "HAVE_GETOPT_LONG"] + +def windows_port_replacements(configuration): + """Select replacements from established facts, retaining upstream policy.""" + return [ + source + for macro, source in WINDOWS_PORT_REPLACEMENT_SOURCES.items() + if macro in WINDOWS_FORCED_PORT_REPLACEMENTS or configuration.get(macro, "0") != "1" + ] diff --git a/build_defs/quality/BUILD.bazel b/build_defs/quality/BUILD.bazel new file mode 100644 index 000000000..4c9dbdb6c --- /dev/null +++ b/build_defs/quality/BUILD.bazel @@ -0,0 +1,79 @@ +load("//build_defs/foundation:bun.bzl", "bun_test") +load("@bazel_lib//lib:copy_file.bzl", "copy_file") +load(":biome.bzl", "biome_runner_test", "biome_test") +load(":rustfmt.bzl", "rustfmt_runner_test") +load(":sources.bzl", "source_quality_files") + +package(default_visibility = ["//visibility:public"]) + +exports_files(glob(["*.bzl", "*.mts"])) + +source_quality_files() + +test_suite( + name = "rust_clippy_test", + tests = [ + "//:extension_proof_clippy_test", + "//:perf_clippy_test", + "//src/database-resources/icu:clippy_test", + "//src/native/broker:clippy_test", + "//src/native/mobile-bindings:clippy_test", + "//src/native/node-addon:clippy_test", + "//src/native/postgres-tools:clippy_test", + "//src/native/runtime/packaging:clippy_test", + "//src/native/rust-bindings:clippy_test", + "//src/native/sdks/rust:clippy_test", + "//src/native/sdks/rust/crates/oliphaunt-build:clippy_test", + "//src/query/rust:clippy_test", + "//src/wasix/postgres-tools:clippy_test", + "//src/wasix/runtime/crates/aot/aarch64-apple-darwin:clippy_test", + "//src/wasix/runtime/crates/aot/aarch64-unknown-linux-gnu:clippy_test", + "//src/wasix/runtime/crates/aot/x86_64-pc-windows-msvc:clippy_test", + "//src/wasix/runtime/crates/aot/x86_64-unknown-linux-gnu:clippy_test", + "//src/wasix/runtime/crates/assets:clippy_test", + "//src/wasix/runtime/tools/xtask:clippy_test", + "//src/wasix/sdks/rust:clippy_test", + ], +) + +test_suite( + name = "rust_doctest_suite", + tests = [ + "//src/native/sdks/rust:doc_test", + "//src/native/sdks/rust/crates/oliphaunt-build:doc_test", + "//src/wasix/sdks/rust:doc_test", + "//src/wasix/sdks/rust:tools_doc_test", + ], +) + +biome_runner_test( + name = "biome_runner_test", + size = "small", + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) + +rustfmt_runner_test(name = "rustfmt_runner_test", size = "small") + +# A generated output is not an authored formatting input. If the adapter +# requests this deliberately invalid output, its format check must fail. +copy_file( + name = "generated_biome_fixture", + src = "fixtures/invalid-biome.ts", + out = "unrequested-generated.ts", + testonly = True, +) + +biome_test( + name = "authored_sources_only_test", + mode = "format", + sources = ["fixture-good.ts", ":generated_biome_fixture"], + size = "small", + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) + +bun_test( + name = "metadata_test", + entry_point = "metadata.test.mts", + data = ["metadata.mts", "//:package.json", "//:bun.lock", "//tools/dev:maintainer-tools.toml"], + size = "small", +) diff --git a/build_defs/quality/biome.bzl b/build_defs/quality/biome.bzl new file mode 100644 index 000000000..254691523 --- /dev/null +++ b/build_defs/quality/biome.bzl @@ -0,0 +1,64 @@ +"""Biome source checks with declared repository paths and conventional policy.""" + +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") + +def _biome_impl(ctx): + files = [source for source in ctx.files.sources if source.is_source] + [ctx.file.config, ctx.file.gitignore] + by_path = {} + for source in files: + if source.short_path.startswith("../"): + fail("Biome source checks accept authored main-repository sources only") + if source.short_path in by_path and by_path[source.short_path] != source: + fail("Conflicting declared Biome source: " + source.short_path) + by_path[source.short_path] = source + arguments = [ctx.file.biome, ctx.attr.mode] + for path in sorted(by_path): + arguments.extend([path, by_path[path]]) + return bun_test_entrypoint(ctx, ctx.file._runner, arguments, files + [ctx.file.biome], source_files = [ctx.file._runner]) + +_biome_test = rule( + implementation = _biome_impl, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "sources": attr.label_list(allow_files = True), + "mode": attr.string(values = ["format", "lint"], mandatory = True), + "biome": attr.label(default = Label("@biome_linux_x64//:biome"), allow_single_file = True, cfg = "exec"), + "config": attr.label(default = Label("//:biome.json"), allow_single_file = True), + "gitignore": attr.label(default = Label("//:.gitignore"), allow_single_file = True), + "_runner": attr.label(default = Label("//build_defs/quality:biome.mts"), allow_single_file = True), + }), + toolchains = BUN_SOURCE_TOOLCHAINS, + test = True, +) + +def biome_test(name, mode, sources, **kwargs): + _biome_test(name = name, mode = mode, sources = sources, args = bun_test_entrypoint_args(name), **kwargs) + +def _runner_test_impl(ctx): + binary = ctx.file.biome + runfile = binary.short_path[3:] if binary.short_path.startswith("../") else ctx.workspace_name + "/" + binary.short_path + sources = [ctx.file._runner, ctx.file._implementation, ctx.file.config] + return bun_test_entrypoint( + ctx, + ctx.file._runner, + [], + sources + [binary], + source_files = sources, + environment = {"OLIPHAUNT_BIOME_RUNFILE": runfile}, + runfiles_environment = ["OLIPHAUNT_QUALITY_RUNFILES"], + test_runner = True, + ) + +_biome_runner_test = rule( + implementation = _runner_test_impl, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "biome": attr.label(default = Label("@biome_linux_x64//:biome"), allow_single_file = True, cfg = "exec"), + "config": attr.label(default = Label("//:biome.json"), allow_single_file = True), + "_runner": attr.label(default = Label("//build_defs/quality:biome.test.mts"), allow_single_file = True), + "_implementation": attr.label(default = Label("//build_defs/quality:biome.mts"), allow_single_file = True), + }), + toolchains = BUN_SOURCE_TOOLCHAINS, + test = True, +) + +def biome_runner_test(name, **kwargs): + _biome_runner_test(name = name, args = bun_test_entrypoint_args(name), **kwargs) diff --git a/build_defs/quality/biome.mts b/build_defs/quality/biome.mts new file mode 100644 index 000000000..9f43aa729 --- /dev/null +++ b/build_defs/quality/biome.mts @@ -0,0 +1,69 @@ +import { spawnSync } from 'node:child_process'; +import { copyFileSync, mkdirSync, mkdtempSync, realpathSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join, resolve } from 'node:path'; + +export type QualitySource = { path: string; source: string }; + +/** Preserve repository paths so the conventional Biome and Git exclusions apply. */ +export function runBiome( + binary: string, + mode: 'format' | 'lint', + sources: QualitySource[], + options: { capture?: boolean } = {}, +) { + if (mode !== 'format' && mode !== 'lint') throw new Error('Expected Biome format or lint'); + // Biome's scanner rejects .cache ancestors, including Bazel's default TEST_TMPDIR. + const root = realpathSync(mkdtempSync(join(tmpdir(), 'oliphaunt-biome-'))); + try { + const paths = new Set(); + for (const file of sources) { + if ( + !file.path || + file.path.includes('\\') || + file.path.startsWith('/') || + file.path.split('/').some((part) => !part || part === '.' || part === '..') || + paths.has(file.path) + ) + throw new Error(`Invalid or duplicate declared quality source: ${file.path}`); + paths.add(file.path); + const target = join(root, file.path); + mkdirSync(dirname(target), { recursive: true }); + copyFileSync(file.source, target); + } + if (!paths.has('biome.json') || !paths.has('.gitignore')) + throw new Error('Biome source checks require conventional biome.json and .gitignore'); + const result = spawnSync( + resolve(binary), + [ + mode, + ...(mode === 'lint' ? ['--diagnostic-level=error'] : []), + '--no-errors-on-unmatched', + `--config-path=${root}`, + `--vcs-root=${root}`, + '.', + ], + { cwd: root, stdio: options.capture ? 'pipe' : 'inherit', encoding: 'utf8' }, + ); + if (result.error) throw result.error; + if (result.signal || result.status === null) + throw new Error(`Biome ${mode} terminated without an exit status`); + return { status: result.status, stdout: result.stdout ?? '', stderr: result.stderr ?? '' }; + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + const [binary, mode, ...files] = Bun.argv.slice(2); + if (!binary || (mode !== 'format' && mode !== 'lint') || files.length % 2) + throw new Error('Expected Biome binary, mode, and declared path/File pairs'); + process.exitCode = runBiome( + binary, + mode, + Array.from({ length: files.length / 2 }, (_, index) => ({ + path: files[index * 2], + source: files[index * 2 + 1], + })), + ).status; +} diff --git a/build_defs/quality/biome.test.mts b/build_defs/quality/biome.test.mts new file mode 100644 index 000000000..b9d53d15d --- /dev/null +++ b/build_defs/quality/biome.test.mts @@ -0,0 +1,197 @@ +import { expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join } from 'node:path'; +import { runBiome } from './biome.mts'; + +const binary = + process.env.OLIPHAUNT_BIOME_BINARY ?? + (process.env.OLIPHAUNT_QUALITY_RUNFILES && process.env.OLIPHAUNT_BIOME_RUNFILE + ? join(process.env.OLIPHAUNT_QUALITY_RUNFILES, process.env.OLIPHAUNT_BIOME_RUNFILE) + : undefined); +if (!binary) throw new Error('Biome regressions require the declared formatter binary'); +const config = readFileSync(new URL('../../biome.json', import.meta.url), 'utf8'); + +function fixture(files: Record, check: (root: string) => void) { + const root = mkdtempSync(join(process.env.TEST_TMPDIR ?? tmpdir(), 'oliphaunt-biome-fixture-')); + try { + for (const [path, content] of Object.entries({ + 'biome.json': config, + '.gitignore': '', + ...files, + })) { + const file = join(root, path); + mkdirSync(dirname(file), { recursive: true }); + writeFileSync(file, content); + chmodSync(file, 0o444); + } + check(root); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +function check(root: string, mode: 'format' | 'lint', paths: string[]) { + return runBiome( + binary!, + mode, + ['biome.json', '.gitignore', ...paths].map((path) => ({ path, source: join(root, path) })), + { capture: true }, + ); +} + +test('checks declared bytes and preserves read-only sources', () => { + fixture({ 'src/bad.ts': 'export const value=1;\n' }, (root) => { + const before = readFileSync(join(root, 'src/bad.ts')); + expect(check(root, 'format', ['src/bad.ts']).status).toBe(1); + expect(readFileSync(join(root, 'src/bad.ts'))).toEqual(before); + const lint = check(root, 'lint', ['src/bad.ts']); + expect(lint.status).toBe(0); + }); +}); + +test('applies conventional Biome directory exclusions and root/nested Git ignores', () => { + fixture( + { + '.gitignore': '/root-ignored.ts\n', + 'src/.gitignore': 'local-ignored.ts\n', + 'src/good.ts': 'export const value = 1;\n', + 'root-ignored.ts': 'syntax error \\\n', + 'src/local-ignored.ts': 'syntax error \\\n', + 'src/generated/bad.ts': 'syntax error \\\n', + 'src/fixtures/bad.ts': 'syntax error \\\n', + }, + (root) => { + const paths = [ + 'src/.gitignore', + 'src/good.ts', + 'root-ignored.ts', + 'src/local-ignored.ts', + 'src/generated/bad.ts', + 'src/fixtures/bad.ts', + ]; + const format = check(root, 'format', paths); + if (format.status !== 0) { + console.error( + 'Biome declared policy diagnostic', + JSON.stringify({ + ambientConfigPresent: process.env.BIOME_CONFIG_PATH !== undefined, + binarySha256: createHash('sha256').update(readFileSync(binary!)).digest('hex'), + configSha256: createHash('sha256').update(config).digest('hex'), + }), + ); + } + expect(format).toMatchObject({ status: 0 }); + expect(check(root, 'lint', paths)).toMatchObject({ status: 0 }); + }, + ); +}); + +test('applies root Git ignores through a symlinked test temporary directory', () => { + const scratch = mkdtempSync( + join(process.env.TEST_TMPDIR ?? tmpdir(), 'oliphaunt-biome-aliased-'), + ); + const previous = process.env.TEST_TMPDIR; + try { + const physical = join(scratch, 'physical'); + const logical = join(scratch, 'logical'); + mkdirSync(physical); + symlinkSync(physical, logical, 'dir'); + process.env.TEST_TMPDIR = logical; + fixture( + { + '.gitignore': '/ignored.ts\n', + 'ignored.ts': 'syntax error \\\n', + 'good.ts': 'export const value = 1;\n', + }, + (root) => { + expect(check(root, 'format', ['ignored.ts', 'good.ts'])).toMatchObject({ status: 0 }); + expect(check(root, 'lint', ['ignored.ts', 'good.ts'])).toMatchObject({ status: 0 }); + }, + ); + } finally { + if (previous === undefined) delete process.env.TEST_TMPDIR; + else process.env.TEST_TMPDIR = previous; + rmSync(scratch, { recursive: true, force: true }); + } +}); + +test('preserves nested Git ignores when Bazel temporary inputs are under .cache', () => { + const scratch = mkdtempSync( + join(process.env.TEST_TMPDIR ?? tmpdir(), 'oliphaunt-biome-cache-parent-'), + ); + const previous = process.env.TEST_TMPDIR; + try { + const cached = join(scratch, '.cache', 'bazel-tests'); + mkdirSync(cached, { recursive: true }); + process.env.TEST_TMPDIR = cached; + fixture( + { + '.gitignore': '/root-ignored.ts\n', + 'src/.gitignore': 'local-ignored.ts\n', + 'src/good.ts': 'export const value = 1;\n', + 'root-ignored.ts': 'syntax error \\\n', + 'src/local-ignored.ts': 'syntax error \\\n', + 'src/format-bad.ts': 'export const value=1;\n', + 'src/lint-bad.ts': 'export const value = undeclaredIdentifier;\n', + }, + (root) => { + const paths = ['src/.gitignore', 'src/good.ts', 'root-ignored.ts', 'src/local-ignored.ts']; + expect(check(root, 'format', paths)).toMatchObject({ status: 0 }); + expect(check(root, 'lint', paths)).toMatchObject({ status: 0 }); + expect(check(root, 'format', [...paths, 'src/format-bad.ts']).status).toBe(1); + expect(check(root, 'lint', [...paths, 'src/lint-bad.ts']).status).toBe(1); + }, + ); + } finally { + if (previous === undefined) delete process.env.TEST_TMPDIR; + else process.env.TEST_TMPDIR = previous; + rmSync(scratch, { recursive: true, force: true }); + } +}); + +test('detects actual lint errors and refuses path escape or duplicate members', () => { + fixture({ 'src/bad.ts': 'export const value = undeclaredIdentifier;\n' }, (root) => { + expect(check(root, 'lint', ['src/bad.ts']).status).toBe(1); + expect(() => check(root, 'format', ['../outside.ts'])).toThrow('Invalid or duplicate'); + expect(() => check(root, 'format', ['src/bad.ts', 'src/bad.ts'])).toThrow( + 'Invalid or duplicate', + ); + }); +}); + +test('uses declared configuration when BIOME_CONFIG_PATH points elsewhere', () => { + const external = mkdtempSync( + join(process.env.TEST_TMPDIR ?? tmpdir(), 'oliphaunt-biome-external-config-'), + ); + const previous = process.env.BIOME_CONFIG_PATH; + try { + writeFileSync(join(external, 'biome.json'), config); + process.env.BIOME_CONFIG_PATH = external; + fixture( + { + 'src/.gitignore': 'ignored.ts\n', + 'src/ignored.ts': 'syntax error \\\n', + 'src/good.ts': 'export const value = 1;\n', + }, + (root) => { + const paths = ['src/.gitignore', 'src/ignored.ts', 'src/good.ts']; + expect(check(root, 'format', paths)).toMatchObject({ status: 0 }); + expect(check(root, 'lint', paths)).toMatchObject({ status: 0 }); + }, + ); + } finally { + if (previous === undefined) delete process.env.BIOME_CONFIG_PATH; + else process.env.BIOME_CONFIG_PATH = previous; + rmSync(external, { recursive: true, force: true }); + } +}); diff --git a/build_defs/quality/fixture-good.ts b/build_defs/quality/fixture-good.ts new file mode 100644 index 000000000..efeee5db1 --- /dev/null +++ b/build_defs/quality/fixture-good.ts @@ -0,0 +1 @@ +export const value = 1; diff --git a/build_defs/quality/fixtures/invalid-biome.ts b/build_defs/quality/fixtures/invalid-biome.ts new file mode 100644 index 000000000..6d3d1da70 --- /dev/null +++ b/build_defs/quality/fixtures/invalid-biome.ts @@ -0,0 +1 @@ +const invalid = ; diff --git a/build_defs/quality/metadata.mts b/build_defs/quality/metadata.mts new file mode 100644 index 000000000..b4d6aac01 --- /dev/null +++ b/build_defs/quality/metadata.mts @@ -0,0 +1,115 @@ +import { readFileSync } from 'node:fs'; + +type PackageManifest = { name: string; devDependencies?: Record }; +type LockedPackage = [ + string, + string, + { optionalDependencies?: Record; os?: string; cpu?: string }, + string, +]; +type BunLock = { + lockfileVersion: number; + configVersion: number; + workspaces: Record; + packages: Record; +}; + +/** Select the native formatter from the same root declaration and Bun lock as Moon. */ +export function importBiomeMetadata(root: PackageManifest, lock: BunLock) { + if (lock.lockfileVersion !== 2 || lock.configVersion !== 1) + throw new Error('Unsupported Bun lockfile schema'); + const packageName = '@biomejs/biome'; + const requirement = root.devDependencies?.[packageName]; + if ( + !requirement || + lock.workspaces['']?.name !== root.name || + lock.workspaces[''].devDependencies?.[packageName] !== requirement + ) + throw new Error('bun.lock has a stale root Biome declaration'); + const record = (name: string, range: string) => { + const entry = lock.packages[name]; + if ( + !entry?.[0].startsWith(`${name}@`) || + entry[1] !== '' || + !/^sha512-[A-Za-z0-9+/]+=*$/.test(entry[3] ?? '') + ) + throw new Error(`Missing integrity-bearing Biome lock entry for ${name}`); + const version = entry[0].slice(name.length + 1); + if (!Bun.semver.satisfies(version, range)) + throw new Error(`Locked ${name}@${version} does not satisfy ${range}`); + return { package: name, version, integrity: entry[3] }; + }; + const wrapper = record(packageName, requirement); + const platformName = '@biomejs/cli-linux-x64'; + const platformRequirement = lock.packages[packageName][2].optionalDependencies?.[platformName]; + if (platformRequirement !== wrapper.version) + throw new Error('Biome native binary is not bound to the declared formatter version'); + const platform = record(platformName, platformRequirement); + if ( + lock.packages[platformName][2].os !== 'linux' || + lock.packages[platformName][2].cpu !== 'x64' || + platform.version !== wrapper.version + ) + throw new Error('Biome source checks require the locked Linux x64 binary'); + return { ...platform, wrapper, platform: { os: 'linux', cpu: 'x64' } }; +} + +type WorkflowToolPin = { + version: string; + repository: string; + assets: { 'linux-amd64': { url: string; sha256: string; binary_path: string } }; +}; + +export function importWorkflowMetadata(manifest: Record) { + return Object.fromEntries( + ['actionlint', 'zizmor', 'shellcheck'].map((name) => { + const pin = manifest[name]; + const asset = pin?.assets?.['linux-amd64']; + if ( + !pin || + !/^\d+[.]\d+[.]\d+$/u.test(pin.version) || + !/^[A-Za-z0-9_-]+\/[A-Za-z0-9_.-]+$/u.test(pin.repository) || + !asset || + !asset.url.startsWith( + 'https://github.com/' + pin.repository + '/releases/download/v' + pin.version + '/', + ) || + !/^[0-9a-f]{64}$/u.test(asset.sha256) || + !asset.binary_path || + asset.binary_path.split('/').some((part) => !part || part === '.' || part === '..') || + asset.binary_path.includes('\\') + ) + throw new Error('Expected an exact conventional Linux x64 workflow tool pin: ' + name); + const parts = asset.binary_path.split('/'); + const binary = parts.pop(); + if (binary !== name) + throw new Error('Workflow tool binary must match its declared identity: ' + name); + return [ + name, + { + version: pin.version, + url: asset.url, + sha256: asset.sha256, + stripPrefix: parts.join('/'), + binary, + }, + ]; + }), + ); +} + +if (import.meta.main) { + const [manifest, lockfile, tools] = Bun.argv.slice(2); + if (!manifest || !lockfile || !tools) + throw new Error('Expected root package.json, bun.lock and maintainer-tools.toml'); + console.log( + JSON.stringify({ + biome: importBiomeMetadata( + JSON.parse(readFileSync(manifest, 'utf8')), + Bun.JSONC.parse(readFileSync(lockfile, 'utf8')), + ), + workflow: importWorkflowMetadata( + Bun.TOML.parse(readFileSync(tools, 'utf8')) as Record, + ), + }), + ); +} diff --git a/build_defs/quality/metadata.test.mts b/build_defs/quality/metadata.test.mts new file mode 100644 index 000000000..c8986c708 --- /dev/null +++ b/build_defs/quality/metadata.test.mts @@ -0,0 +1,74 @@ +import { expect, test } from 'bun:test'; +import { readFileSync } from 'node:fs'; +import { importBiomeMetadata, importWorkflowMetadata } from './metadata.mts'; + +const root = JSON.parse(readFileSync(new URL('../../package.json', import.meta.url), 'utf8')); +const lock = Bun.JSONC.parse(readFileSync(new URL('../../bun.lock', import.meta.url), 'utf8')); +const copy = () => structuredClone(lock); + +test('uses the same declared formatter and integrity-locked Linux binary', () => { + const result = importBiomeMetadata(root, lock); + expect(result.version).toBe(root.devDependencies['@biomejs/biome']); + expect(result.integrity).toBe(lock.packages['@biomejs/cli-linux-x64'][3]); + expect(result.wrapper.integrity).toBe(lock.packages['@biomejs/biome'][3]); + expect(result.platform).toEqual({ os: 'linux', cpu: 'x64' }); +}); + +test('rejects a stale declaration and unsupported lock format', () => { + const stale = copy(); + stale.workspaces[''].devDependencies['@biomejs/biome'] = '1.0.0'; + expect(() => importBiomeMetadata(root, stale)).toThrow('stale root Biome'); + const unsupported = copy(); + unsupported.lockfileVersion = 1; + expect(() => importBiomeMetadata(root, unsupported)).toThrow('Unsupported Bun lockfile'); +}); + +test('rejects substituted, unbound, or non-integrity-bearing native binaries', () => { + const platform = '@biomejs/cli-linux-x64'; + const wrongVersion = copy(); + wrongVersion.packages[platform][0] = `${platform}@1.0.0`; + expect(() => importBiomeMetadata(root, wrongVersion)).toThrow('does not satisfy'); + const missingBinding = copy(); + delete missingBinding.packages['@biomejs/biome'][2].optionalDependencies[platform]; + expect(() => importBiomeMetadata(root, missingBinding)).toThrow('not bound'); + const wrongHost = copy(); + wrongHost.packages[platform][2].cpu = 'arm64'; + expect(() => importBiomeMetadata(root, wrongHost)).toThrow('Linux x64'); + const unsigned = copy(); + unsigned.packages[platform][3] = ''; + expect(() => importBiomeMetadata(root, unsigned)).toThrow('integrity-bearing'); +}); + +const workflowPins = Bun.TOML.parse( + readFileSync(new URL('../../tools/dev/maintainer-tools.toml', import.meta.url), 'utf8'), +) as any; +test('workflow tools use the same conventional version pins and checksum-bearing archives', () => { + const metadata = importWorkflowMetadata(workflowPins); + expect(Object.keys(metadata)).toEqual(['actionlint', 'zizmor', 'shellcheck']); + for (const [name, tool] of Object.entries(metadata)) { + expect(tool.version).toBe(workflowPins[name].version); + expect(tool.sha256).toBe(workflowPins[name].assets['linux-amd64'].sha256); + expect(tool.binary).toBe(name); + } + for (const mutate of [ + (pin: any) => { + pin.version = 'latest'; + }, + (pin: any) => { + pin.assets['linux-amd64'].sha256 = ''; + }, + (pin: any) => { + pin.assets['linux-amd64'].url = 'https://example.com/tool.tgz'; + }, + (pin: any) => { + pin.assets['linux-amd64'].binary_path = '../actionlint'; + }, + (pin: any) => { + pin.assets['linux-amd64'].binary_path = 'other'; + }, + ]) { + const invalid = structuredClone(workflowPins); + mutate(invalid.actionlint); + expect(() => importWorkflowMetadata(invalid)).toThrow(); + } +}); diff --git a/build_defs/quality/repositories.bzl b/build_defs/quality/repositories.bzl new file mode 100644 index 000000000..50d5213b5 --- /dev/null +++ b/build_defs/quality/repositories.bzl @@ -0,0 +1,59 @@ +"""Source-quality tool acquisition from conventional package declarations.""" + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +def _metadata_impl(ctx): + for source in [ctx.attr.package, ctx.attr.lockfile, ctx.attr.maintainer_tools, ctx.attr.converter]: + ctx.read(source) + ctx.watch(ctx.path(ctx.attr.bun)) + result = ctx.execute([ctx.path(ctx.attr.bun), ctx.path(ctx.attr.converter), ctx.path(ctx.attr.package), ctx.path(ctx.attr.lockfile), ctx.path(ctx.attr.maintainer_tools)], quiet = True) + if result.return_code: + fail("Cannot import conventional source-quality acquisition: " + result.stderr) + data = json.decode(result.stdout) + ctx.file("quality.json", json.encode(data)) + ctx.file("BUILD.bazel", 'exports_files(["quality.json"], visibility = ["//visibility:public"])\n') + return ctx.repo_metadata(reproducible = True) + +quality_metadata_repository = repository_rule( + implementation = _metadata_impl, + attrs = { + "package": attr.label(default = Label("//:package.json"), allow_single_file = True), + "lockfile": attr.label(default = Label("//:bun.lock"), allow_single_file = True), + "maintainer_tools": attr.label(default = Label("//tools/dev:maintainer-tools.toml"), allow_single_file = True), + "converter": attr.label(default = Label("//build_defs/quality:metadata.mts"), allow_single_file = True), + "bun": attr.label(default = Label("@bun_runtime//:bun"), allow_single_file = True), + }, +) + +def _tools_impl(ctx): + tags = [tag for module in ctx.modules for tag in module.tags.configure] + if len(tags) != 1: + fail("Exactly one conventional source-quality acquisition is required") + for module in ctx.modules: + if module.tags.configure and not module.is_root: + fail("Only the root module may configure source-quality acquisition") + metadata = json.decode(ctx.read(tags[0].metadata)) + data = metadata["biome"] + if data["package"] != "@biomejs/cli-linux-x64" or data["platform"] != {"os": "linux", "cpu": "x64"}: + fail("Source-quality acquisition requires the conventional Linux x64 Biome binary") + http_archive( + name = "biome_linux_x64", + urls = ["https://registry.npmjs.org/%s/-/cli-linux-x64-%s.tgz" % (data["package"], data["version"])], + integrity = data["integrity"], + strip_prefix = "package", + build_file_content = 'exports_files(["biome"], visibility = ["//visibility:public"])\n', + ) + for name, tool in metadata["workflow"].items(): + http_archive( + name = name + "_linux_x64", + urls = [tool["url"]], + sha256 = tool["sha256"], + strip_prefix = tool["stripPrefix"], + build_file_content = 'exports_files(["%s"], visibility = ["//visibility:public"])\n' % tool["binary"], + ) + return ctx.extension_metadata(reproducible = True) + +quality_tools = module_extension( + implementation = _tools_impl, + tag_classes = {"configure": tag_class(attrs = {"metadata": attr.label(mandatory = True)})}, +) diff --git a/build_defs/quality/rust.bzl b/build_defs/quality/rust.bzl new file mode 100644 index 000000000..b8bc462e6 --- /dev/null +++ b/build_defs/quality/rust.bzl @@ -0,0 +1,34 @@ +"""Source quality for conventional Cargo packages owned by the root package.""" + +load("//build_defs/languages:rust.bzl", "cargo_binary", "cargo_library_test", "cargo_package_env") +load("@rules_rust//rust:defs.bzl", "rust_clippy_test") + +def root_cargo_quality(): + """Declare actual benchmark/proof compile roots without new package boundaries.""" + for name, package_name in { + "perf": "src/benchmarks/perf/runner", + "extension_proof": "src/extensions/tests/native", + }.items(): + cargo_package_env(name = name + "_cargo_env", package_name = package_name) + cargo_binary( + name = name + "_cargo_binary", + source = package_name + "/src/main.rs", + package_name = package_name, + cargo_env = ":" + name + "_cargo_env", + path_dependencies = {"oliphaunt": "//src/native/sdks/rust:lib"}, + compile_data = ["//src/native/sdks/rust:integration_sources"] if name == "extension_proof" else [], + tags = ["manual"], + ) + cargo_library_test( + name = name + "_cargo_unit_test", + crate = ":" + name + "_cargo_binary", + package_name = package_name, + cargo_env = ":" + name + "_cargo_env", + tags = ["manual"], + ) + rust_clippy_test( + name = name + "_clippy_test", + targets = [":" + name + "_cargo_binary", ":" + name + "_cargo_unit_test"], + transitive = False, + size = "small", + ) diff --git a/build_defs/quality/rustfmt.bzl b/build_defs/quality/rustfmt.bzl new file mode 100644 index 000000000..e1d3e5da1 --- /dev/null +++ b/build_defs/quality/rustfmt.bzl @@ -0,0 +1,60 @@ +"""Check authored Rust files with the declared formatter without compiling crates.""" + +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") + +_RUSTFMT_TOOLCHAIN = "@rules_rust//rust/rustfmt:toolchain_type" + +def _rustfmt_impl(ctx): + toolchain = ctx.toolchains[_RUSTFMT_TOOLCHAIN] + for source in ctx.files.source_files: + if not source.is_source or source.short_path.startswith("../"): + fail("Rust formatting requires authored workspace sources: " + source.short_path) + return bun_test_entrypoint( + ctx, + runner = ctx.file._runner, + arguments = [toolchain.rustfmt, ctx.file.config] + ctx.files.source_files, + files = [ctx.file.config] + ctx.files.source_files + toolchain.all_files.to_list(), + source_files = [ctx.file._runner], + ) + +_rustfmt_test = rule( + implementation = _rustfmt_impl, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "source_files": attr.label_list(allow_files = [".rs"], mandatory = True, allow_empty = False), + "config": attr.label(default = Label("//:rustfmt.toml"), allow_single_file = True), + "_runner": attr.label(default = Label("//build_defs/quality:rustfmt.mts"), allow_single_file = True), + }), + toolchains = BUN_SOURCE_TOOLCHAINS + [_RUSTFMT_TOOLCHAIN], + test = True, +) + +def rustfmt_test(name, args = [], **kwargs): + _rustfmt_test(name = name, args = bun_test_entrypoint_args(name) + args, **kwargs) + +def _runner_test_impl(ctx): + toolchain = ctx.toolchains[_RUSTFMT_TOOLCHAIN] + formatter = toolchain.rustfmt + runfile = formatter.short_path[3:] if formatter.short_path.startswith("../") else ctx.workspace_name + "/" + formatter.short_path + return bun_test_entrypoint( + ctx, + runner = ctx.file._runner, + arguments = [], + files = toolchain.all_files.to_list(), + source_files = [ctx.file._runner, ctx.file._implementation], + environment = {"OLIPHAUNT_RUSTFMT_RUNFILE": runfile}, + runfiles_environment = ["OLIPHAUNT_BAZEL_RUNFILES"], + test_runner = True, + ) + +_rustfmt_runner_test = rule( + implementation = _runner_test_impl, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "_runner": attr.label(default = Label("//build_defs/quality:rustfmt.test.mts"), allow_single_file = True), + "_implementation": attr.label(default = Label("//build_defs/quality:rustfmt.mts"), allow_single_file = True), + }), + toolchains = BUN_SOURCE_TOOLCHAINS + [_RUSTFMT_TOOLCHAIN], + test = True, +) + +def rustfmt_runner_test(name, args = [], **kwargs): + _rustfmt_runner_test(name = name, args = bun_test_entrypoint_args(name) + args, **kwargs) diff --git a/build_defs/quality/rustfmt.mts b/build_defs/quality/rustfmt.mts new file mode 100644 index 000000000..d8950ba4f --- /dev/null +++ b/build_defs/quality/rustfmt.mts @@ -0,0 +1,28 @@ +import { spawnSync } from 'node:child_process'; + +/** Each path retains its declared runfiles hierarchy; formatter traversal adds no sources. */ +export function runRustfmtCheck(rustfmt: string, config: string, sources: string[]) { + if (!rustfmt || !config || !sources.length || new Set(sources).size !== sources.length) + throw new Error('Rust formatting requires one formatter, config and nonempty unique sources'); + const result = spawnSync( + rustfmt, + ['--check', '--config-path', config, '--config', 'skip_children=true', '--', ...sources], + { encoding: 'utf8', maxBuffer: 8 * 1024 * 1024 }, + ); + if (result.error) throw result.error; + if (result.status === null) throw new Error(`Rust formatter terminated by ${result.signal}`); + return { status: result.status, stdout: result.stdout, stderr: result.stderr }; +} + +if (import.meta.main) { + try { + const [rustfmt, config, ...sources] = process.argv.slice(2); + const result = runRustfmtCheck(rustfmt, config, sources); + process.stdout.write(result.stdout); + process.stderr.write(result.stderr); + process.exitCode = result.status; + } catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exitCode = 1; + } +} diff --git a/build_defs/quality/rustfmt.test.mts b/build_defs/quality/rustfmt.test.mts new file mode 100644 index 000000000..a58fe87d3 --- /dev/null +++ b/build_defs/quality/rustfmt.test.mts @@ -0,0 +1,86 @@ +import { expect, test } from 'bun:test'; +import { + chmodSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + statSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { runRustfmtCheck } from './rustfmt.mts'; + +const rustfmt = + process.env.OLIPHAUNT_RUSTFMT ?? + (process.env.OLIPHAUNT_BAZEL_RUNFILES && process.env.OLIPHAUNT_RUSTFMT_RUNFILE + ? path.join(process.env.OLIPHAUNT_BAZEL_RUNFILES, process.env.OLIPHAUNT_RUSTFMT_RUNFILE) + : undefined); +if (!rustfmt) throw new Error('Rust formatter tests require the declared formatter'); + +function fixture(run: (root: string, file: (name: string, bytes: string) => string) => void) { + const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-rustfmt-')); + const file = (name: string, bytes: string) => { + const target = path.join(root, name); + mkdirSync(path.dirname(target), { recursive: true }); + writeFileSync(target, bytes, { flag: 'wx', mode: 0o644 }); + return target; + }; + try { + run(root, file); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +test('the declared edition and formatter check readonly sources without altering bytes or modes', () => { + fixture((_root, file) => { + const config = file('rustfmt.toml', 'edition = "2024"\nmax_width = 100\n'); + const source = file('crate/src/lib.rs', 'pub async fn probe() {}\n'); + chmodSync(source, 0o444); + expect(runRustfmtCheck(rustfmt, config, [source]).status).toBe(0); + expect(readFileSync(source, 'utf8')).toBe('pub async fn probe() {}\n'); + expect(statSync(source).mode & 0o777).toBe(0o444); + }); +}); + +test('formatting faults retain the logical path when distinct crates share a source basename', () => { + fixture((_root, file) => { + const config = file('rustfmt.toml', 'edition = "2024"\n'); + const first = file('first/src/lib.rs', 'pub fn first() {}\n'); + const bytes = 'pub fn second(){let value=1;}\n'; + const second = file('second/src/lib.rs', bytes); + chmodSync(second, 0o444); + const result = runRustfmtCheck(rustfmt, config, [first, second]); + expect(result.status).toBe(1); + expect(result.stdout).toContain(second); + expect(readFileSync(second, 'utf8')).toBe(bytes); + expect(statSync(second).mode & 0o777).toBe(0o444); + }); +}); + +test('the explicit config controls formatting rather than an adjacent source config', () => { + fixture((_root, file) => { + const selected = file('policy/rustfmt.toml', 'edition = "2024"\nmax_width = 100\n'); + const adjacent = file('crate/rustfmt.toml', 'edition = "2024"\nmax_width = 40\n'); + const source = file( + 'crate/src/lib.rs', + 'pub fn width(first: u32, second: u32, third: u32) -> u32 {\n first + second + third\n}\n', + ); + expect(runRustfmtCheck(rustfmt, selected, [source]).status).toBe(0); + expect(runRustfmtCheck(rustfmt, adjacent, [source]).status).toBe(1); + }); +}); + +test('child modules enter the check only as explicit source files', () => { + fixture((_root, file) => { + const config = file('rustfmt.toml', 'edition = "2024"\n'); + const root = file('crate/src/lib.rs', 'mod child;\n'); + const child = file('crate/src/child.rs', 'pub fn child(){let value=1;}\n'); + expect(runRustfmtCheck(rustfmt, config, [root]).status).toBe(0); + expect(runRustfmtCheck(rustfmt, config, [root, child]).status).toBe(1); + expect(() => runRustfmtCheck(rustfmt, config, [])).toThrow('nonempty'); + expect(() => runRustfmtCheck(rustfmt, config, [root, root])).toThrow('unique'); + }); +}); diff --git a/build_defs/quality/sources.bzl b/build_defs/quality/sources.bzl new file mode 100644 index 000000000..8c93fcbaf --- /dev/null +++ b/build_defs/quality/sources.bzl @@ -0,0 +1,17 @@ +"""Source-only quality ownership; the formatter applies conventional exclusions.""" + +def source_quality_files(name = "quality_sources", exclude = []): + # Bazel output aliases are root entries; nested bazel-* names can be authored sources. + output_excludes = ["bazel-*/**"] if native.package_name() == "" else [] + native.filegroup( + name = name, + srcs = native.glob(["**/*.js", "**/*.mjs", "**/*.cjs", "**/*.ts", "**/*.mts", "**/*.cts", "**/*.tsx", "**/*.json", "**/*.jsonc", "**/*.css", "**/.gitignore"], exclude = ["**/node_modules/**", "**/target/**", "**/.git/**"] + output_excludes + exclude, allow_empty = True), + visibility = ["//visibility:public"], + ) + +def rust_quality_files(name = "rustfmt_sources"): + native.filegroup( + name = name, + srcs = native.glob(["**/*.rs"], exclude = ["**/target/**", "**/vendor/**", "**/generated/**", "**/fixtures/**"], allow_empty = True), + visibility = ["//visibility:public"], + ) diff --git a/build_defs/query/BUILD.bazel b/build_defs/query/BUILD.bazel new file mode 100644 index 000000000..656e5f8e6 --- /dev/null +++ b/build_defs/query/BUILD.bazel @@ -0,0 +1,95 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("@aspect_rules_ts//ts:defs.bzl", "ts_project") +load("//build_defs/foundation:bun.bzl", "bun_test") +load(":defs.bzl", "npm_consumer_test", "query_envelope") + +package(default_visibility = ["//visibility:public"]) + +_MODULE_OUT_DIR = "dist" + +exports_files([ + "defs.bzl", + "package.mts", + "consumer-test.mts", + "cargo-consumer-test.mts", + "consumer/Cargo.toml", + "consumer/main.rs", +]) + +bun_test( + name = "cargo_link_environment_test", + size = "small", + entry_point = "cargo-consumer-test.test.mts", + data = ["cargo-consumer-test.mts", "package.mts", "//build_defs/languages:cargo-environment.mts", "//:tools/packaging/archive-directory.mts", "//:tools/packaging/package-archive.mts", "//:tools/packaging/portable-archive.mts"], +) + +bun_test( + name = "package_test", + size = "small", + entry_point = "package.test.mts", + data = [ + "package.mts", + "//:tools/packaging/archive-directory.mts", + "//:tools/packaging/portable-archive.mts", + ], +) + +# Exercise the archive boundary with real nested JavaScript and declarations. +# Both public formats must remain usable after installation outside the checkout. +NESTED_SRCS = glob(["test-fixtures/src/**/*.ts"]) + +ts_project( + name = "nested_module", + srcs = NESTED_SRCS, + tsconfig = {"compilerOptions": { + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": True, + "target": "ES2022", + "types": [], + }}, + declaration = True, + out_dir = _MODULE_OUT_DIR + "/module", + root_dir = "test-fixtures/src", + transpiler = "tsc", + supports_workers = 0, +) + +ts_project( + name = "nested_commonjs", + srcs = NESTED_SRCS, + tsconfig = {"compilerOptions": { + "module": "Node16", + "moduleResolution": "Node16", + "strict": True, + "target": "ES2022", + "types": [], + }}, + declaration = True, + out_dir = _MODULE_OUT_DIR + "/commonjs", + root_dir = "test-fixtures/src", + transpiler = "tsc", + supports_workers = 0, +) + +query_envelope( + name = "nested_npm", + format = "npm", + manifest = "test-fixtures/npm-package.json", + entries = { + ":nested_module": "dist/module/", + ":nested_commonjs": "dist/commonjs/", + "test-fixtures/npm-package.json": "package.json", + "test-fixtures/module.package.json": "dist/module/package.json", + }, + out = "nested-query.tgz", +) + +npm_consumer_test( + name = "nested_envelope_test", + size = "small", + archive = ":nested_npm", + consumer = "test-fixtures/consumer.mts", +) + +source_quality_files(exclude = [_MODULE_OUT_DIR + "/**"]) diff --git a/build_defs/query/cargo-consumer-test.mts b/build_defs/query/cargo-consumer-test.mts new file mode 100644 index 000000000..4874f3b56 --- /dev/null +++ b/build_defs/query/cargo-consumer-test.mts @@ -0,0 +1,92 @@ +import assert from 'node:assert/strict'; +import { copyFile, mkdir, readFile, realpath } from 'node:fs/promises'; +import { join } from 'node:path'; +import { + extractPortableArchiveTree, + readPortableArchiveEntries, +} from '../../tools/packaging/portable-archive.mts'; +import { + type CargoLinkConfiguration, + cargoLinkEnvironment, +} from '../languages/cargo-environment.mts'; + +export { + type CargoLinkConfiguration, + cargoLinkEnvironment, +} from '../languages/cargo-environment.mts'; + +export function sourceCrateRoot(archive: string): string { + const entries = readPortableArchiveEntries(archive); + for (const entry of entries.values()) + assert( + entry.isDirectory ? entry.mode === 0o755 : entry.isFile && entry.mode === 0o644, + 'source crate must contain regular mode 0644 files and mode 0755 directories', + ); + const manifests = [...entries.values()].filter( + (entry) => entry.isFile && entry.name.endsWith('/Cargo.toml'), + ); + assert.equal(manifests.length, 1, 'source crate must contain one Cargo manifest'); + const [manifest] = manifests; + assert(manifest); + const prefix = manifest.name.slice(0, -'/Cargo.toml'.length); + assert( + [...entries.values()].every( + (entry) => + entry.name.startsWith(`${prefix}/`) || (entry.isDirectory && entry.name === prefix), + ), + 'source crate members must stay inside their package root', + ); + return prefix; +} + +async function installedConsumerTest(args: string[]) { + const [archive, manifest, source, cargo, rustc, rustdoc, linkConfiguration, runfiles] = args; + assert( + archive && + manifest && + source && + cargo && + rustc && + rustdoc && + linkConfiguration && + runfiles && + process.env.TEST_TMPDIR, + ); + const directory = join(process.env.TEST_TMPDIR, 'query-cargo-consumer'); + await mkdir(directory, { recursive: true }); + const sourceArchive = await realpath(archive); + const prefix = sourceCrateRoot(sourceArchive); + extractPortableArchiveTree(sourceArchive, join(directory, 'installed'), prefix); + const consumer = join(directory, 'consumer'); + await mkdir(join(consumer, 'src'), { recursive: true }); + await copyFile(manifest, join(consumer, 'Cargo.toml')); + await copyFile(source, join(consumer, 'src/main.rs')); + + const env = { ...process.env }; + for (const key of Object.keys(env)) { + if (key.startsWith('CARGO_') || key.startsWith('RUST')) delete env[key]; + } + Object.assign(env, { + ...cargoLinkEnvironment( + JSON.parse(await readFile(linkConfiguration, 'utf8')) as CargoLinkConfiguration, + runfiles, + ), + CARGO_HOME: join(directory, 'cargo-home'), + CARGO_TARGET_DIR: join(directory, 'target'), + CARGO_NET_OFFLINE: 'true', + RUSTC: rustc, + RUSTDOC: rustdoc, + }); + const result = Bun.spawnSync( + [cargo, 'run', '--offline', '--manifest-path', join(consumer, 'Cargo.toml')], + { + cwd: consumer, + env, + stdout: 'inherit', + stderr: 'inherit', + }, + ); + assert.equal(result.exitCode, 0, 'installed source crate consumer failed'); +} + +if (import.meta.main) await installedConsumerTest(process.argv.slice(2)); diff --git a/build_defs/query/cargo-consumer-test.test.mts b/build_defs/query/cargo-consumer-test.test.mts new file mode 100644 index 000000000..35a95f786 --- /dev/null +++ b/build_defs/query/cargo-consumer-test.test.mts @@ -0,0 +1,95 @@ +import { expect, test } from 'bun:test'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { createDeterministicTar } from '../../tools/packaging/package-archive.mts'; +import { + canonicalGzipSync, + extractPortableArchiveTree, + readFileOnlyTarGzipEntries, +} from '../../tools/packaging/portable-archive.mts'; +import { cargoLinkEnvironment, sourceCrateRoot } from './cargo-consumer-test.mts'; +import { archive as packageEnvelope } from './package.mts'; + +test('installed Cargo source accepts canonical directory entries and rejects malformed source envelopes', () => { + const scratch = mkdtempSync(join(tmpdir(), 'oliphaunt-query-cargo-contract-')); + try { + const stage = join(scratch, 'stage'); + mkdirSync(join(stage, 'src'), { recursive: true }); + writeFileSync(join(stage, 'Cargo.toml'), '[package]\nname="fixture"\nversion="1.2.3"\n'); + writeFileSync(join(stage, 'src/lib.rs'), 'pub fn proof() {}\n'); + const archive = join(scratch, 'fixture.crate'); + const packageArchive = (mode = 0o644) => + writeFileSync( + archive, + canonicalGzipSync(createDeterministicTar(stage, 'fixture-1.2.3', { fixedFileMode: mode })), + ); + packageArchive(); + expect(() => readFileOnlyTarGzipEntries(archive)).toThrow('must be a regular mode=644 file'); + expect(sourceCrateRoot(archive)).toBe('fixture-1.2.3'); + const installed = join(scratch, 'installed'); + extractPortableArchiveTree(archive, installed, sourceCrateRoot(archive)); + expect(readFileSync(join(installed, 'src/lib.rs'), 'utf8')).toBe('pub fn proof() {}\n'); + packageArchive(0o755); + expect(() => sourceCrateRoot(archive)).toThrow('regular mode 0644 files'); + writeFileSync(join(stage, 'src/Cargo.toml'), '[package]\nname="extra"\nversion="1.2.3"\n'); + packageArchive(); + expect(() => sourceCrateRoot(archive)).toThrow('one Cargo manifest'); + writeFileSync( + archive, + packageEnvelope({ + 'fixture-1.2.3/Cargo.toml': Buffer.from('[package]\nname="fixture"\nversion="1.2.3"\n'), + 'other/src/lib.rs': Buffer.from('pub fn unowned() {}\n'), + }), + ); + expect(() => sourceCrateRoot(archive)).toThrow('inside their package root'); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +}); + +test('installed Cargo proof retains registered Apple SDK link flags with declared runfiles paths', () => { + const environment = cargoLinkEnvironment( + { + linker: 'external/compiler/bin/clang', + args: ['-isysroot', 'external/sdk/MacOSX.sdk', '-Wl,-no_uuid'], + env: { SDKROOT: 'external/sdk/MacOSX.sdk', DEVELOPER_DIR: 'external/sdk' }, + roots: { 'external/compiler': 'compiler', 'external/sdk': 'sdk' }, + }, + '/runfiles', + ); + const sdk = join('/runfiles', 'sdk'); + const compiler = join('/runfiles', 'compiler'); + expect(environment.SDKROOT).toBe(`${sdk}/MacOSX.sdk`); + expect(environment.DEVELOPER_DIR).toBe(sdk); + expect(environment.CARGO_ENCODED_RUSTFLAGS.split('\x1f')).toEqual([ + `-Clinker=${compiler}/bin/clang`, + '-Clink-arg=-isysroot', + `-Clink-arg=${sdk}/MacOSX.sdk`, + '-Clink-arg=-Wl,-no_uuid', + ]); +}); + +test('installed Cargo proof retains Windows LIB/INCLUDE and arguments containing spaces', () => { + const environment = cargoLinkEnvironment( + { + linker: 'external/compiler/bin/link.exe', + args: ['/LIBPATH:external/sdk/lib/um x64', '/NOLOGO'], + env: { + LIB: 'external/sdk/lib/ucrt;external/sdk/lib/um x64', + INCLUDE: 'external/sdk/include', + }, + roots: { 'external/compiler': 'compiler', 'external/sdk': 'sdk' }, + }, + '/runfiles', + ); + const sdk = join('/runfiles', 'sdk'); + const compiler = join('/runfiles', 'compiler'); + expect(environment.LIB).toBe(`${sdk}/lib/ucrt;${sdk}/lib/um x64`); + expect(environment.INCLUDE).toBe(`${sdk}/include`); + expect(environment.CARGO_ENCODED_RUSTFLAGS.split('\x1f')).toEqual([ + `-Clinker=${compiler}/bin/link.exe`, + `-Clink-arg=/LIBPATH:${sdk}/lib/um x64`, + '-Clink-arg=/NOLOGO', + ]); +}); diff --git a/build_defs/query/consumer-test.mts b/build_defs/query/consumer-test.mts new file mode 100644 index 000000000..2fc33fa37 --- /dev/null +++ b/build_defs/query/consumer-test.mts @@ -0,0 +1,27 @@ +import assert from 'node:assert/strict'; +import { mkdir, readFile, writeFile } from 'node:fs/promises'; +import { join } from 'node:path'; + +const [archivePath, consumerPath, node] = process.argv.slice(2); +assert(archivePath && consumerPath && node && process.env.TEST_TMPDIR); +const directory = join(process.env.TEST_TMPDIR, 'query-consumer'); +const packageDirectory = join(directory, 'node_modules', '@oliphaunt', 'ts-query'); +const files = await new Bun.Archive(await readFile(archivePath)).files(); +for (const [path, content] of files) { + assert(path.startsWith('package/') && !path.split('/').includes('..')); + const destination = join(packageDirectory, path.slice('package/'.length)); + await mkdir(join(destination, '..'), { recursive: true }); + await writeFile(destination, await content.bytes()); +} +const consumer = join(directory, 'consumer.mjs'); +const source = new Bun.Transpiler({ loader: 'ts', target: 'node' }).transformSync( + await readFile(consumerPath, 'utf8'), +); +await writeFile(consumer, source); +const result = Bun.spawnSync([node, consumer], { + cwd: directory, + stdout: 'inherit', + stderr: 'inherit', + env: { ...process.env, NODE_PATH: '', NODE_OPTIONS: '' }, +}); +assert.equal(result.exitCode, 0, 'packed query consumer failed'); diff --git a/build_defs/query/consumer/Cargo.toml b/build_defs/query/consumer/Cargo.toml new file mode 100644 index 000000000..5a9959479 --- /dev/null +++ b/build_defs/query/consumer/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "query-envelope-consumer" +version = "0.0.0" +edition = "2024" + +[dependencies] +oliphaunt-query = { path = "../installed" } + +[workspace] diff --git a/build_defs/query/consumer/main.rs b/build_defs/query/consumer/main.rs new file mode 100644 index 000000000..4fb6d8f54 --- /dev/null +++ b/build_defs/query/consumer/main.rs @@ -0,0 +1,5 @@ +fn main() { + let frame = oliphaunt_query::simple_query("SELECT 42").unwrap(); + assert_eq!(frame[0], b'Q'); + assert_eq!(&frame[5..frame.len() - 1], b"SELECT 42"); +} diff --git a/build_defs/query/defs.bzl b/build_defs/query/defs.bzl new file mode 100644 index 000000000..85b1dcf34 --- /dev/null +++ b/build_defs/query/defs.bzl @@ -0,0 +1,118 @@ +"""Bounded query packaging and tests; compilation belongs to language rules.""" + +load("@aspect_rules_js//js:providers.bzl", "JsInfo") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_file_action", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("@rules_cc//cc:find_cc_toolchain.bzl", "use_cc_toolchain") +load("//build_defs/languages:cargo-toolchain.bzl", "cargo_test_toolchain") + +_NODE_TOOLCHAIN = "@rules_nodejs//nodejs:toolchain_type" +_RUST_TOOLCHAIN = "@rules_rust//rust:toolchain_type" + +def require_commonjs_package(package_type): + """Validate Node16's sandbox default against the manifest's semantic projection.""" + if package_type != "commonjs": + fail("query's CommonJS output requires package.json type commonjs (or absent), got " + repr(package_type)) + +def _envelope_impl(ctx): + inputs = [ctx.file.manifest] + mapping = {} + for target, destination in ctx.attr.entries.items(): + files = target[DefaultInfo].files.to_list() + if JsInfo in target: + files += target[JsInfo].types.to_list() + for file in depset(files).to_list(): + entry = destination + if destination.endswith("/"): + output_prefix = target.label.package + "/" + destination + if not file.short_path.startswith(output_prefix): + fail("compiled query output %s is outside declared package output prefix %s" % (file.short_path, output_prefix)) + entry += file.short_path[len(output_prefix):] + if entry in mapping: + fail("duplicate package entry: " + entry) + mapping[entry] = file.path + inputs.append(file) + specification = ctx.actions.declare_file(ctx.label.name + ".entries.json") + ctx.actions.write(specification, json.encode(mapping)) + output = ctx.actions.declare_file(ctx.attr.out) + args = ctx.actions.args() + args.add(ctx.attr.format) + args.add(output) + args.add(ctx.file.manifest) + args.add(specification) + if ctx.file.workspace_manifest: + args.add(ctx.file.workspace_manifest) + inputs.append(ctx.file.workspace_manifest) + bun_file_action( + ctx, + entry_point = ctx.file._packager, + arguments = [args], + inputs = depset(inputs + [specification, ctx.file._packager] + ctx.files._archive_helpers), + source_files = [ctx.file._packager] + ctx.files._archive_helpers, + outputs = [output], + mnemonic = "QueryEnvelope", + progress_message = "Packaging query %s %s" % (ctx.attr.format, ctx.label), + ) + return [DefaultInfo(files = depset([output]))] + +query_envelope = rule( + implementation = _envelope_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = { + "entries": attr.label_keyed_string_dict(allow_files = True), + "format": attr.string(mandatory = True, values = ["npm", "crate"]), + "manifest": attr.label(mandatory = True, allow_single_file = True), + "workspace_manifest": attr.label(allow_single_file = True), + "out": attr.string(mandatory = True), + "_packager": attr.label(default = "//build_defs/query:package.mts", allow_single_file = True), + "_archive_helpers": attr.label_list(default = ["//:tools/packaging/archive-directory.mts", "//:tools/packaging/portable-archive.mts"], allow_files = True), + }, +) + +def _npm_consumer_test_impl(ctx): + node = ctx.toolchains[_NODE_TOOLCHAIN].nodeinfo.node + if not node: + fail("query consumer tests require the pinned Node toolchain") + files = [ctx.file.archive, ctx.file.consumer, ctx.file._runner, node] + return bun_test_entrypoint(ctx, ctx.file._runner, [ctx.file.archive, ctx.file.consumer, node], files, source_files = [ctx.file._runner]) + +_npm_consumer_test = rule( + implementation = _npm_consumer_test_impl, + test = True, + toolchains = BUN_SOURCE_TOOLCHAINS + [_NODE_TOOLCHAIN], + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "archive": attr.label(mandatory = True, allow_single_file = True), + "consumer": attr.label(mandatory = True, allow_single_file = True), + "_runner": attr.label(default = "//build_defs/query:consumer-test.mts", allow_single_file = True), + }), +) + +def npm_consumer_test(name, args = [], **kwargs): + _npm_consumer_test(name = name, args = bun_test_entrypoint_args(name) + args, **kwargs) + +def _cargo_consumer_test_impl(ctx): + rust = ctx.toolchains[_RUST_TOOLCHAIN] + if not rust.cargo: + fail("installed query consumer tests require Cargo from the pinned Rust toolchain") + cc = cargo_test_toolchain(ctx) + link_configuration = cc.configuration + arguments = [ctx.file.archive, ctx.file.manifest, ctx.file.source, rust.cargo, rust.rustc, rust.rust_doc, link_configuration] + files = [ctx.file.archive, ctx.file.manifest, ctx.file.source, ctx.file._runner, ctx.file._archive_helper, ctx.file._cargo_environment, link_configuration] + rust.all_files.to_list() + cc.files + return bun_test_entrypoint(ctx, ctx.file._runner, arguments, files, source_files = [ctx.file._runner, ctx.file._archive_helper, ctx.file._cargo_environment], runfiles_argument = True) + +_cargo_consumer_test = rule( + implementation = _cargo_consumer_test_impl, + test = True, + toolchains = BUN_SOURCE_TOOLCHAINS + [_RUST_TOOLCHAIN] + use_cc_toolchain(), + fragments = ["cpp"], + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "archive": attr.label(mandatory = True, allow_single_file = True), + "manifest": attr.label(mandatory = True, allow_single_file = [".toml"]), + "source": attr.label(mandatory = True, allow_single_file = [".rs"]), + "_runner": attr.label(default = "//build_defs/query:cargo-consumer-test.mts", allow_single_file = True), + "_archive_helper": attr.label(default = "//:tools/packaging/portable-archive.mts", allow_single_file = True), + "_cargo_environment": attr.label(default = "//build_defs/languages:cargo-environment.mts", allow_single_file = True), + }), +) + +def cargo_consumer_test(name, args = [], **kwargs): + _cargo_consumer_test(name = name, args = bun_test_entrypoint_args(name) + args, **kwargs) diff --git a/build_defs/query/package.mts b/build_defs/query/package.mts new file mode 100644 index 000000000..4800f1b99 --- /dev/null +++ b/build_defs/query/package.mts @@ -0,0 +1,118 @@ +import { readFile, writeFile } from 'node:fs/promises'; +import { tarHeader } from '../../tools/packaging/archive-directory.mts'; +import { canonicalGzipSync } from '../../tools/packaging/portable-archive.mts'; + +type Entries = Record; + +function archivePath(path: string): void { + const fitsUstar = + Buffer.byteLength(path) <= 100 || + path.split('/').some((_, index, parts) => { + if (!index) return false; + return ( + Buffer.byteLength(parts.slice(0, index).join('/')) <= 155 && + Buffer.byteLength(parts.slice(index).join('/')) <= 100 + ); + }); + if ( + !path || + !fitsUstar || + path.startsWith('/') || + path.includes('\\') || + path.split('/').some((part) => !part || part === '.' || part === '..') + ) { + throw new Error(`Unsupported archive path: ${path}`); + } +} + +/** Fixed ustar headers and gzip metadata make identical inputs produce identical bytes. */ +export function archive(entries: Entries): Buffer { + const chunks: Buffer[] = []; + for (const [path, bytes] of Object.entries(entries).sort(([left], [right]) => + left < right ? -1 : 1, + )) { + archivePath(path); + const content = Buffer.from(bytes); + const header = tarHeader({ name: path, isDirectory: false }, content.length, 0o644); + chunks.push(header, content, Buffer.alloc((512 - (content.length % 512)) % 512)); + } + chunks.push(Buffer.alloc(1024)); + return canonicalGzipSync(Buffer.concat(chunks)); +} + +export function crateManifest(original: string, workspace: string): string { + if (Object.keys(Bun.TOML.parse(original)).some((key) => key !== 'package')) { + throw new Error('Query source crate supports only its dependency-free package section'); + } + const values = Bun.TOML.parse(workspace).workspace?.package; + const normalized = original.replace(/^([\w-]+)\.workspace\s*=\s*true\s*$/gm, (_, key: string) => { + const value = values?.[key]; + if (typeof value !== 'string') { + throw new Error(`Missing string workspace.package.${key}`); + } + return `${key} = ${JSON.stringify(value)}`; + }); + for (const [key, value] of Object.entries(Bun.TOML.parse(normalized).package)) { + if (value && typeof value === 'object' && 'workspace' in value) { + throw new Error(`Unsupported workspace inheritance syntax for package.${key}`); + } + } + return normalized; +} + +function exportPaths(value: unknown): string[] { + if (typeof value === 'string') return [value]; + if (!value || typeof value !== 'object') return []; + return Object.values(value).flatMap(exportPaths); +} + +export async function packageEnvelope( + format: 'npm' | 'crate', + manifestPath: string, + mapping: Record, + workspacePath?: string, +): Promise { + const original = await readFile(manifestPath, 'utf8'); + const manifest = format === 'npm' ? JSON.parse(original) : Bun.TOML.parse(original).package; + if (!manifest || typeof manifest.name !== 'string' || !/^[\w@/.-]+$/.test(manifest.name)) { + throw new Error('Missing or invalid package name'); + } + if ( + typeof manifest.version !== 'string' || + !/^\d+\.\d+\.\d+(?:[-+][\w.-]+)?$/.test(manifest.version) + ) { + throw new Error('Missing or invalid package version'); + } + const prefix = format === 'npm' ? 'package' : `${manifest.name}-${manifest.version}`; + const entries: Entries = {}; + for (const [destination, source] of Object.entries(mapping)) { + archivePath(destination); + entries[`${prefix}/${destination}`] = await readFile(source); + } + const manifestName = format === 'npm' ? 'package.json' : 'Cargo.toml'; + if (!entries[`${prefix}/${manifestName}`]) + throw new Error(`Missing ${manifestName} package entry`); + if (format === 'crate') { + if (!workspacePath) throw new Error('Source crate requires its workspace manifest'); + entries[`${prefix}/Cargo.toml.orig`] = Buffer.from(original); + entries[`${prefix}/Cargo.toml`] = Buffer.from( + crateManifest(original, await readFile(workspacePath, 'utf8')), + ); + } else { + for (const path of exportPaths(manifest.exports)) { + if (!path.startsWith('./') || !entries[`${prefix}/${path.slice(2)}`]) { + throw new Error(`Missing exported npm entry: ${path}`); + } + } + } + return archive(entries); +} + +if (import.meta.main) { + const [format, output, manifest, specification, workspace] = process.argv.slice(2); + if ((format !== 'npm' && format !== 'crate') || !output || !manifest || !specification) { + throw new Error('Usage: package.mts npm|crate OUTPUT MANIFEST ENTRIES.json [WORKSPACE]'); + } + const mapping = JSON.parse(await readFile(specification, 'utf8')) as Record; + await writeFile(output, await packageEnvelope(format, manifest, mapping, workspace)); +} diff --git a/build_defs/query/package.test.mts b/build_defs/query/package.test.mts new file mode 100644 index 000000000..508899a94 --- /dev/null +++ b/build_defs/query/package.test.mts @@ -0,0 +1,103 @@ +import { expect, test } from 'bun:test'; +import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { readFileOnlyTarGzipEntries } from '../../tools/packaging/portable-archive.mts'; +import { archive, crateManifest, packageEnvelope } from './package.mts'; + +test('archive has deterministic bytes, sorted entries and fixed file metadata', async () => { + const entries = { 'package/z': Buffer.from('last'), 'package/a': Buffer.from('first') }; + const first = archive(entries); + expect([...first.subarray(0, 10)]).toEqual([0x1f, 0x8b, 8, 0, 0, 0, 0, 0, 0, 3]); + expect(archive({ 'package/a': entries['package/a'], 'package/z': entries['package/z'] })).toEqual( + first, + ); + const files = await new Bun.Archive(first).files(); + expect([...files.keys()]).toEqual(['package/a', 'package/z']); + expect(await files.get('package/a')?.text()).toBe('first'); + expect(files.get('package/a')?.lastModified).toBe(0); + for (const path of ['/absolute', '../outside', 'a/../outside', 'a\\b', 'x'.repeat(101)]) { + expect(() => archive({ [path]: Buffer.from('bad') })).toThrow('Unsupported archive path'); + } + const nested = `${'prefix'.repeat(20)}/file.txt`; + const nestedFiles = await new Bun.Archive(archive({ [nested]: Buffer.from('nested') })).files(); + expect(await nestedFiles.get(nested)?.text()).toBe('nested'); + const directory = await mkdtemp(join(tmpdir(), 'query-archive-')); + try { + const path = join(directory, 'package.tgz'); + await writeFile(path, first); + expect([...readFileOnlyTarGzipEntries(path).keys()]).toEqual(['package/a', 'package/z']); + } finally { + await rm(directory, { recursive: true, force: true }); + } +}); + +test('source crate resolves authored workspace values and preserves the original manifest', async () => { + const original = + '[package]\nname = "oliphaunt-query"\nversion = "0.1.1"\nedition.workspace = true\nlicense.workspace = true\n'; + const workspace = '[workspace.package]\nedition = "2024"\nlicense = "MIT"\n'; + expect(Bun.TOML.parse(crateManifest(original, workspace)).package).toEqual({ + name: 'oliphaunt-query', + version: '0.1.1', + edition: '2024', + license: 'MIT', + }); + expect(() => crateManifest(original, '[workspace.package]\nedition = "2024"\n')).toThrow( + 'workspace.package.license', + ); + expect(() => + crateManifest(`${original}[dependencies]\nserde.workspace = true\n`, workspace), + ).toThrow('dependency-free package section'); + expect(() => + crateManifest( + original.replace('edition.workspace = true', 'edition.workspace = true # inherited'), + workspace, + ), + ).toThrow('Unsupported workspace inheritance syntax'); + const directory = await mkdtemp(join(tmpdir(), 'query-crate-')); + try { + const manifest = join(directory, 'Cargo.toml'); + const workspacePath = join(directory, 'workspace.toml'); + await writeFile(manifest, original); + await writeFile(workspacePath, workspace); + const bytes = await packageEnvelope( + 'crate', + manifest, + { 'Cargo.toml': manifest }, + workspacePath, + ); + const files = await new Bun.Archive(bytes).files(); + expect(await files.get('oliphaunt-query-0.1.1/Cargo.toml.orig')?.text()).toBe(original); + expect( + Bun.TOML.parse((await files.get('oliphaunt-query-0.1.1/Cargo.toml')?.text()) ?? '').package + .edition, + ).toBe('2024'); + } finally { + await rm(directory, { recursive: true, force: true }); + } +}); + +test('npm envelope rejects missing compiled exports and preserves its full manifest', async () => { + const directory = await mkdtemp(join(tmpdir(), 'query-npm-')); + try { + const manifest = join(directory, 'package.json'); + const source = join(directory, 'query.js'); + const original = JSON.stringify({ + name: '@oliphaunt/ts-query', + version: '0.1.1', + exports: { './query': './dist/query.js' }, + publishConfig: { access: 'public' }, + }); + await writeFile(manifest, original); + await writeFile(source, 'export const value = 42;'); + await expect(packageEnvelope('npm', manifest, { 'package.json': manifest })).rejects.toThrow( + 'Missing exported npm entry', + ); + const files = await new Bun.Archive( + await packageEnvelope('npm', manifest, { 'package.json': manifest, 'dist/query.js': source }), + ).files(); + expect(await files.get('package/package.json')?.text()).toBe(await readFile(manifest, 'utf8')); + } finally { + await rm(directory, { recursive: true, force: true }); + } +}); diff --git a/build_defs/query/test-fixtures/consumer.mts b/build_defs/query/test-fixtures/consumer.mts new file mode 100644 index 000000000..cc6317f1d --- /dev/null +++ b/build_defs/query/test-fixtures/consumer.mts @@ -0,0 +1,15 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { createRequire } from 'node:module'; +import { nestedValue } from '@oliphaunt/ts-query/protocol'; + +const require = createRequire(import.meta.url); +assert.equal(nestedValue, 42); +assert.equal(require('@oliphaunt/ts-query/protocol').nestedValue, 42); +for (const format of ['module', 'commonjs']) { + const declaration = new URL( + `./node_modules/@oliphaunt/ts-query/dist/${format}/nested/value.d.ts`, + import.meta.url, + ); + assert.match(readFileSync(declaration, 'utf8'), /export declare const nestedValue: number;/); +} diff --git a/build_defs/query/test-fixtures/module.package.json b/build_defs/query/test-fixtures/module.package.json new file mode 100644 index 000000000..5ffd9800b --- /dev/null +++ b/build_defs/query/test-fixtures/module.package.json @@ -0,0 +1 @@ +{ "type": "module" } diff --git a/build_defs/query/test-fixtures/npm-package.json b/build_defs/query/test-fixtures/npm-package.json new file mode 100644 index 000000000..a87537e60 --- /dev/null +++ b/build_defs/query/test-fixtures/npm-package.json @@ -0,0 +1,16 @@ +{ + "name": "@oliphaunt/ts-query", + "version": "0.0.0", + "exports": { + "./protocol": { + "import": { + "types": "./dist/module/protocol.d.ts", + "default": "./dist/module/protocol.js" + }, + "require": { + "types": "./dist/commonjs/protocol.d.ts", + "default": "./dist/commonjs/protocol.js" + } + } + } +} diff --git a/build_defs/query/test-fixtures/src/nested/value.ts b/build_defs/query/test-fixtures/src/nested/value.ts new file mode 100644 index 000000000..3388f41f1 --- /dev/null +++ b/build_defs/query/test-fixtures/src/nested/value.ts @@ -0,0 +1 @@ +export const nestedValue: number = 42; diff --git a/build_defs/query/test-fixtures/src/protocol.ts b/build_defs/query/test-fixtures/src/protocol.ts new file mode 100644 index 000000000..482262fc5 --- /dev/null +++ b/build_defs/query/test-fixtures/src/protocol.ts @@ -0,0 +1 @@ +export { nestedValue } from './nested/value.js'; diff --git a/build_defs/release/BUILD.bazel b/build_defs/release/BUILD.bazel new file mode 100644 index 000000000..f132d232e --- /dev/null +++ b/build_defs/release/BUILD.bazel @@ -0,0 +1,48 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/foundation:bun.bzl", "bun_test") +load("//build_defs/extensions:platforms.bzl", "NATIVE_EXTENSION_COMPATIBLE", "NATIVE_EXTENSION_CONFIGURATION") +load(":supplier.bzl", "cc_shipping_supplier", "shipping_suppliers") + +package(default_visibility = ["//visibility:public"]) + +NATIVE_BINARY_HELPERS = ["//:tools/packaging/platform-binary-contract.mts", "//:tools/packaging/windows-vc-runtime-closure.mts", "//:tools/packaging/windows-vc-runtime-policy.json", "//tools/release:platform-compatibility-policy.mts"] + +exports_files(glob(["*.bzl", "*.mts", "*-source.json", "*-releases.json", "*-completed-publication.json", "*-npm-*.json", "testdata/*.json"])) + +shipping_suppliers(name = "no_suppliers", inputs = []) + +cc_shipping_supplier( + name = "current_native_core_supplier", + producer = "//src/native/runtime:runtime_shared_library", + owner = "@oliphaunt_metadata//:product_liboliphaunt-native", + configuration = NATIVE_EXTENSION_CONFIGURATION, + target_compatible_with = NATIVE_EXTENSION_COMPATIBLE, +) + +bun_test( + name = "frozen_native_carrier_test", + entry_point = "frozen-native-carrier.test.mts", + data = ["frozen-native-carrier.mts", "//src/native/sdks/swift:tools/swift-native-carrier-contract.mts", "//src/native/sdks/swift:tools/native-legal-source-basis.mts"] + glob(["*-source.json", "*-releases.json", "*-completed-publication.json", "testdata/*.json"]), + size = "small", +) + +bun_test( + name = "frozen_native_runtime_test", + entry_point = "frozen-native-runtime.test.mts", + data = ["frozen-native-runtime.mts", "native-0.3.2-releases.json", "native-0.3.2-completed-publication.json", "native-0.3.3-releases.json", "native-0.3.3-completed-publication.json", + "//src/native/sdks/rust:release.toml", "//src/native/sdks/rust:Cargo.toml", "//tools/release:compatibility-version-parser.mts", + "//src/native/sdks/kotlin:release.toml", "//src/native/sdks/kotlin/oliphaunt-android-gradle-plugin:src/main/resources/dev/oliphaunt/android/liboliphaunt.version", + "//:tools/packaging/portable-archive.mts", "//:tools/packaging/archive-directory.mts"] + NATIVE_BINARY_HELPERS, + size = "small", +) + +bun_test( + name = "frozen_native_npm_test", + entry_point = "frozen-native-npm.test.mts", + data = ["frozen-native-npm.mts", "frozen-native-runtime.mts", "native-0.3.2-releases.json", "native-0.3.2-completed-publication.json", + "//src/native/sdks/ts:release.toml", "//src/native/sdks/ts:package.json", "//src/native/runtime:release.toml", "//tools/release:compatibility-version-parser.mts", + "//:tools/packaging/portable-archive.mts", "//:tools/packaging/archive-directory.mts", "//:tools/packaging/testdata/release-fixture-utils.mts"] + glob(["*-npm-*.json"]) + NATIVE_BINARY_HELPERS, + size = "small", +) + +source_quality_files() diff --git a/build_defs/release/capture-native-npm.mts b/build_defs/release/capture-native-npm.mts new file mode 100644 index 000000000..42a50ecb1 --- /dev/null +++ b/build_defs/release/capture-native-npm.mts @@ -0,0 +1,198 @@ +// Explicit read-only capture, outside Bazel/repository actions. Version comes +// from the consumer's conventional compatibility declaration, never latest. + +import { spawnSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { readPortableArchiveEntries } from '../../tools/packaging/portable-archive.mts'; +import { compatibilityVersionFromText } from '../../tools/release/compatibility-version-parser.mts'; +import { createCompletedPublicationChecker } from '../../tools/release/completed-release-publication.mts'; +import { + requestGithubPages, + requestGithubRepositoryJson, +} from '../../tools/release/github-read.mts'; +import { frozenNativeNpmInput, verifyFrozenNativeNpm } from './frozen-native-npm.mts'; +import { frozenNativeRuntimeInputs } from './frozen-native-runtime.mts'; + +async function json(url) { + const response = await fetch(url); + if (!response.ok) throw new Error(`capture GET ${url} failed: ${response.status}`); + return response.json(); +} + +if (import.meta.main) { + const [descriptorFile, compatibilityPath, name, target, destination] = process.argv.slice(2); + if (!destination || process.argv.length !== 7) + throw new Error( + 'usage: capture-native-npm.mts CONSUMER_RELEASE_TOML COMPATIBILITY_PATH NPM_PACKAGE TARGET NEW_OUTPUT_DIRECTORY', + ); + const descriptor = Bun.TOML.parse(readFileSync(descriptorFile, 'utf8')); + const compatibilityText = readFileSync(compatibilityPath, 'utf8'); + const matches = Object.entries(descriptor.compatibility_versions ?? {}).filter( + ([, entry]) => + entry.source_product === 'liboliphaunt-native' && entry.path === compatibilityPath, + ); + if (matches.length !== 1) + throw new Error('capture requires one authored native compatibility pin'); + const [id, entry] = matches[0]; + const version = compatibilityVersionFromText({ id, ...entry }, compatibilityText); + if (!/^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u.test(version)) + throw new Error('capture requires a stable exact native compatibility version'); + const tagName = `liboliphaunt-native-v${version}`; + const release = await requestGithubRepositoryJson( + `repos/f0rr0/oliphaunt/releases/tags/${tagName}`, + ); + const completion = await createCompletedPublicationChecker({ repository: 'f0rr0/oliphaunt' })({ + product: 'liboliphaunt-native', + version, + publicationSha: release.target_commitish, + tagName, + }); + const assets = await requestGithubPages(`repos/f0rr0/oliphaunt/releases/${release.id}/assets`); + const releases = [ + { + product: 'liboliphaunt-native', + version, + tag: tagName, + releaseId: release.id, + releaseName: release.name, + targetCommitish: release.target_commitish, + draft: release.draft, + prerelease: release.prerelease, + assets: assets.map((asset) => { + if (!/^sha256:[0-9a-f]{64}$/u.test(asset.digest ?? '')) + throw new Error(`capture requires GitHub's immutable digest for ${asset.name}`); + return { + assetId: asset.id, + name: asset.name, + sha256: asset.digest.slice(7), + size: asset.size, + }; + }), + }, + ]; + const metadata = await json(`https://registry.npmjs.org/${encodeURIComponent(name)}/${version}`); + if (metadata.name !== name) + throw new Error('registry returned a different requested package identity'); + const attestationUrl = `https://registry.npmjs.org/-/npm/v1/attestations/${name.replace('/', '%2f')}@${version}`; + if (metadata.dist?.attestations?.url !== attestationUrl) + throw new Error('capture requires the exact canonical npm attestation endpoint'); + const rawAttestations = await json(attestationUrl); + // Preserve standard signed bundles, omitting ephemeral signedAccessSignatureUrl. + const attestations = { + attestations: rawAttestations.attestations.map(({ predicateType, bundle }) => ({ + predicateType, + bundle, + })), + }; + const ownerDescriptor = Bun.TOML.parse(readFileSync('src/native/runtime/release.toml', 'utf8')); + const request = { + metadata, + attestations, + releases, + completion, + descriptor, + compatibilityText, + compatibilityPath, + ownerDescriptor, + target, + }; + const input = frozenNativeNpmInput(request); + const [native] = frozenNativeRuntimeInputs({ ...request, selectedTargets: [target] }); + const scratch = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-native-npm-capture-')); + try { + // npm verifies registry signatures and Sigstore attestations with its + // maintained verifier. Offline import only binds these verified captures. + writeFileSync( + path.join(scratch, 'package.json'), + JSON.stringify({ private: true, optionalDependencies: { [name]: version } }), + ); + const npm = (args) => { + const result = spawnSync( + 'npm', + [ + ...args, + '--registry=https://registry.npmjs.org', + '--userconfig=/dev/null', + `--cache=${path.join(scratch, 'cache')}`, + ], + { cwd: scratch, encoding: 'utf8' }, + ); + if (result.error || result.status !== 0) + throw new Error(`npm signature capture failed: ${result.error?.message ?? result.stderr}`); + process.stdout.write(result.stdout); + }; + // Capture foreign packages without executing them or disabling npm checks. + if (metadata.os?.length !== 1 || metadata.cpu?.length !== 1) + throw new Error('capture requires one declared npm OS and CPU'); + npm([ + 'install', + '--ignore-scripts', + '--no-audit', + '--no-fund', + `--os=${metadata.os[0]}`, + `--cpu=${metadata.cpu[0]}`, + ]); + const lock = JSON.parse(readFileSync(path.join(scratch, 'package-lock.json'), 'utf8')); + const installed = lock.packages?.[`node_modules/${name}`]; + if ( + installed?.version !== version || + installed.integrity !== input.integrity || + installed.resolved !== input.url + ) + throw new Error('npm authenticated a different archive from the captured metadata'); + npm(['audit', 'signatures']); + const archive = path.join(scratch, input.filename); + const response = await fetch(input.url); + if (!response.ok) throw new Error(`npm archive download failed: ${response.status}`); + const bytes = Buffer.from(await response.arrayBuffer()); + writeFileSync(archive, bytes); + verifyFrozenNativeNpm(input, archive); + // The public GitHub archive supplies the independently completed native + // payload. npm intentionally omits its source header; every runtime/legal + // file must have identical bytes, rather than a renamed current build. + const nativeArchive = path.join(scratch, native.name); + const nativeResponse = await fetch(native.url); + if (!nativeResponse.ok) + throw new Error(`completed runtime download failed: ${nativeResponse.status}`); + const nativeBytes = Buffer.from(await nativeResponse.arrayBuffer()); + if ( + nativeBytes.length !== native.size || + createHash('sha256').update(nativeBytes).digest('hex') !== native.sha256 + ) + throw new Error('completed GitHub runtime bytes differ from captured release'); + writeFileSync(nativeArchive, nativeBytes); + const npmEntries = readPortableArchiveEntries(archive); + for (const [member, file] of readPortableArchiveEntries(nativeArchive)) { + if (!file.isFile || member.startsWith('include/') || member === native.interfaceLibrary) + continue; + // npm retains dependent ICU DLLs in runtime/bin; its root bin contains + // the provider DLL and the explicit VC closure selected by the packager. + const published = + npmEntries.get(`package/${member}`) ?? + (target === 'windows-x64-msvc' && member.startsWith('bin/') && member.endsWith('.dll') + ? npmEntries.get(`package/runtime/${member}`) + : undefined); + const data = (entry) => (typeof entry.data === 'function' ? entry.data() : entry.data); + if (!published?.isFile || !data(file).equals(data(published))) + throw new Error(`npm runtime differs from completed native publication member ${member}`); + } + mkdirSync(destination); // Fail rather than overwrite an existing capture. + const write = (suffix, value) => + writeFileSync( + path.join(destination, `native-${version}-${suffix}.json`), + `${JSON.stringify(value, null, 2)}\n`, + ); + write('releases', releases); + write('completed-publication', completion); + write(`npm-${target}`, metadata); + write(`npm-${target}-attestations`, attestations); + console.log( + `Captured ${name}@${version}, completed source ${input.publicationSha}, sha256 ${createHash('sha256').update(bytes).digest('hex')}`, + ); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +} diff --git a/build_defs/release/frozen-native-carrier.bzl b/build_defs/release/frozen-native-carrier.bzl new file mode 100644 index 000000000..481b96396 --- /dev/null +++ b/build_defs/release/frozen-native-carrier.bzl @@ -0,0 +1,53 @@ +"""Acquire the actual native files frozen in a published Swift source carrier.""" + +def _frozen_native_carrier_impl(ctx): + facts = json.decode(ctx.read(ctx.attr.source)) + for source in [ctx.attr.converter, ctx.attr.parser, ctx.attr.basis, ctx.attr.compatibility, ctx.attr.bun, ctx.attr.native_releases, ctx.attr.native_completion, ctx.attr.source_publication]: + ctx.watch(ctx.path(source)) + source_command = [str(ctx.path(ctx.attr.bun)), str(ctx.path(ctx.attr.converter)), str(ctx.path(ctx.attr.source))] + checked = ctx.execute(source_command, timeout = 60) + if checked.return_code: + fail("published native source facts are invalid:\n" + checked.stdout + checked.stderr) + # The URL binds the member to an immutable source commit; its original Git + # blob and SHA-256 are checked by the shared parser before assets are used. + ctx.download(url = checked.stdout.strip(), output = "carrier.json", sha256 = facts["sha256"]) + command = [str(ctx.path(ctx.attr.bun)), str(ctx.path(ctx.attr.converter)), str(ctx.path(ctx.attr.source)), str(ctx.path("carrier.json")), str(ctx.path(ctx.attr.compatibility)), str(ctx.path("assets.json")), str(ctx.path(ctx.attr.native_releases)), str(ctx.path(ctx.attr.native_completion)), str(ctx.path(ctx.attr.source_publication))] + checked = ctx.execute(command, timeout = 60) + if checked.return_code: + fail("published native carrier import failed:\n" + checked.stdout + checked.stderr) + assets = json.decode(ctx.read("assets.json")) + for asset in assets: + ctx.download(url = asset["url"], output = asset["name"], sha256 = asset["sha256"]) + checked = ctx.execute(command + [str(ctx.path("."))], timeout = 60) + if checked.return_code: + fail("published native asset verification failed:\n" + checked.stdout + checked.stderr) + publication = json.decode(ctx.read(ctx.attr.native_completion)) + origins = [{"kind": "completed-publication", "publication": publication, "artifact": "github-release:" + asset["name"]} for asset in assets] + ctx.file("BUILD.bazel", """load("@oliphaunt//build_defs/release:identity.bzl", "release_identity") +load("@oliphaunt//build_defs/release:supplier.bzl", "file_shipping_supplier", "shipping_suppliers") +package(default_visibility = ["//visibility:public"]) +exports_files(["carrier.json", "assets.json"]) +filegroup(name = "carrier", srcs = ["carrier.json"]) +filegroup(name = "xcframework_archive", srcs = [%s]) +filegroup(name = "runtime_resources_archive", srcs = [%s]) +release_identity(name = "native_owner", product_id = %s, version = %s) +file_shipping_supplier(name = "xcframework_supplier", inputs = {":xcframework_archive": ""}, owner = ":native_owner", configuration = "apple-spm-xcframework", binding = "abi-contract", origin = %s) +file_shipping_supplier(name = "runtime_resources_supplier", inputs = {":runtime_resources_archive": ""}, owner = ":native_owner", configuration = "ios-datum64", binding = "abi-contract", origin = %s) +shipping_suppliers(name = "suppliers", inputs = [":xcframework_supplier", ":runtime_resources_supplier"]) +""" % (repr(assets[0]["name"]), repr(assets[1]["name"]), repr(publication["product"]), repr(publication["version"]), repr(json.encode(origins[0])), repr(json.encode(origins[1])))) + return ctx.repo_metadata(reproducible = True) + +frozen_native_carrier_repository = repository_rule( + implementation = _frozen_native_carrier_impl, + attrs = { + "source": attr.label(allow_single_file = True, mandatory = True), + "compatibility": attr.label(allow_single_file = True, mandatory = True), + "native_releases": attr.label(allow_single_file = True, mandatory = True), + "native_completion": attr.label(allow_single_file = True, mandatory = True), + "source_publication": attr.label(allow_single_file = True, mandatory = True), + "bun": attr.label(default = Label("@bun_runtime//:bun"), allow_single_file = True), + "converter": attr.label(default = Label("//build_defs/release:frozen-native-carrier.mts"), allow_single_file = True), + "parser": attr.label(default = Label("//src/native/sdks/swift:tools/swift-native-carrier-contract.mts"), allow_single_file = True), + "basis": attr.label(default = Label("//src/native/sdks/swift:tools/native-legal-source-basis.mts"), allow_single_file = True), + }, +) diff --git a/build_defs/release/frozen-native-carrier.mts b/build_defs/release/frozen-native-carrier.mts new file mode 100644 index 000000000..3b34f7d89 --- /dev/null +++ b/build_defs/release/frozen-native-carrier.mts @@ -0,0 +1,174 @@ +import { createHash } from 'node:crypto'; +import { readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { + createCapturedPublishedNativeLegalSourceBasis, + nativeBaseLegalForSource, +} from '../../src/native/sdks/swift/tools/native-legal-source-basis.mts'; +import { validateFrozenNativeCarrierIdentity } from '../../src/native/sdks/swift/tools/swift-native-carrier-contract.mts'; + +const member = 'src/sdks/swift/Carriers/oliphaunt-react-native-ios-carriers.json'; +const fullSha = /^[a-f0-9]{40}$/u; +const stableVersion = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u; +const digest = (bytes) => createHash('sha256').update(bytes).digest('hex'); + +export function frozenNativeCarrierSource(source) { + const keys = [ + 'repository', + 'source_tag', + 'source_commit', + 'source_tree', + 'source_member', + 'source_blob', + 'sha256', + 'bytes', + ]; + if ( + !source || + JSON.stringify(Object.keys(source).sort()) !== JSON.stringify(keys.sort()) || + source.repository !== 'f0rr0/oliphaunt' || + !stableVersion.test(source.source_tag) || + ![source.source_commit, source.source_tree, source.source_blob].every((sha) => + fullSha.test(sha), + ) || + source.source_member !== member || + !/^[a-f0-9]{64}$/u.test(source.sha256) || + !Number.isSafeInteger(source.bytes) || + source.bytes <= 0 || + source.bytes > 1024 * 1024 + ) + throw new Error('frozen native carrier requires exact immutable published source facts'); + return `https://raw.githubusercontent.com/${source.repository}/${source.source_commit}/${source.source_member}`; +} + +export function readFrozenNativeCarrier({ + source, + carrierBytes, + expectedVersion, + assetDirectory, + publicationContext, +}) { + frozenNativeCarrierSource(source); + const blob = createHash('sha1') + .update(`blob ${carrierBytes.byteLength}\0`) + .update(carrierBytes) + .digest('hex'); + if ( + carrierBytes.byteLength !== source.bytes || + digest(carrierBytes) !== source.sha256 || + blob !== source.source_blob + ) + throw new Error('frozen native carrier bytes differ from the immutable source member'); + if (!stableVersion.test(expectedVersion)) + throw new Error('native compatibility input must contain one stable version'); + // These are externally checked acquisition inputs, not receipts minted by + // this converter. Bind the downloaded member to the captured source parent, + // blob and native release inventory before deriving its historical policy. + const { nativeCompletion, nativeReleases, swiftSource } = publicationContext ?? {}; + if ( + !Array.isArray(nativeReleases) || + nativeReleases.length !== 1 || + nativeCompletion?.version !== expectedVersion || + nativeReleases[0].product !== nativeCompletion.product || + nativeReleases[0].version !== nativeCompletion.version || + !Array.isArray(nativeReleases[0].assets) || + swiftSource?.publication?.version !== source.source_tag || + swiftSource.reference?.object?.sha !== source.source_commit || + swiftSource.commit?.sha !== source.source_commit || + swiftSource.commit?.tree?.sha !== source.source_tree || + swiftSource.member?.path !== source.source_member || + swiftSource.member?.sha !== source.source_blob + ) + throw new Error('frozen native carrier requires matching authenticated publication context'); + const release = nativeReleases[0]; + const sourceBasis = createCapturedPublishedNativeLegalSourceBasis({ + publication: nativeCompletion, + nativeRelease: { + id: release.releaseId, + tag_name: release.tag, + target_commitish: release.targetCommitish, + draft: release.draft, + prerelease: release.prerelease, + }, + sourcePublication: swiftSource.publication, + sourceReference: swiftSource.reference, + sourceCommit: swiftSource.commit, + carrierContents: { + path: swiftSource.member.path, + type: 'file', + encoding: 'base64', + sha: swiftSource.member.sha, + content: carrierBytes.toString('base64'), + }, + nativeAssets: release.assets.map((asset) => ({ + id: asset.assetId, + name: asset.name, + browser_download_url: `https://github.com/f0rr0/oliphaunt/releases/download/${release.tag}/${asset.name}`, + digest: `sha256:${asset.sha256}`, + size: asset.size, + })), + }); + const document = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(carrierBytes)); + const carrier = validateFrozenNativeCarrierIdentity({ + carrier: document, + expectedNativeVersion: expectedVersion, + expectedBaseLegal: nativeBaseLegalForSource({ + base: document.base, + sourceBasis, + currentLegal: () => { + throw new Error('held native acquisition cannot consult current legal policy'); + }, + }), + }); + if (assetDirectory) + for (const asset of carrier.base.assets) { + const bytes = readFileSync(path.join(assetDirectory, asset.name)); + if (bytes.byteLength !== asset.bytes || digest(bytes) !== asset.sha256) + throw new Error( + `published native asset bytes differ from the frozen carrier: ${asset.name}`, + ); + } + return carrier; +} + +if (import.meta.main) { + const [ + sourceFile, + carrierFile, + versionFile, + outputFile, + nativeReleasesFile, + nativeCompletionFile, + sourcePublicationFile, + assetDirectory, + ] = process.argv.slice(2); + if (sourceFile && !carrierFile) { + console.log(frozenNativeCarrierSource(JSON.parse(readFileSync(sourceFile, 'utf8')))); + process.exit(0); + } + if ( + !sourceFile || + !carrierFile || + !versionFile || + !outputFile || + !nativeReleasesFile || + !nativeCompletionFile || + !sourcePublicationFile || + process.argv.length > 10 + ) + throw new Error( + 'usage: frozen-native-carrier.mts SOURCE CARRIER COMPATIBILITY_VERSION OUTPUT NATIVE_RELEASES NATIVE_COMPLETION SOURCE_PUBLICATION [ASSET_DIRECTORY]', + ); + const carrier = readFrozenNativeCarrier({ + source: JSON.parse(readFileSync(sourceFile, 'utf8')), + carrierBytes: readFileSync(carrierFile), + expectedVersion: readFileSync(versionFile, 'utf8').trim(), + publicationContext: { + nativeReleases: JSON.parse(readFileSync(nativeReleasesFile, 'utf8')), + nativeCompletion: JSON.parse(readFileSync(nativeCompletionFile, 'utf8')), + swiftSource: JSON.parse(readFileSync(sourcePublicationFile, 'utf8')), + }, + assetDirectory, + }); + writeFileSync(outputFile, JSON.stringify(carrier.base.assets)); +} diff --git a/build_defs/release/frozen-native-carrier.test.mts b/build_defs/release/frozen-native-carrier.test.mts new file mode 100644 index 000000000..a6d86655f --- /dev/null +++ b/build_defs/release/frozen-native-carrier.test.mts @@ -0,0 +1,190 @@ +import { expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { frozenNativeCarrierSource, readFrozenNativeCarrier } from './frozen-native-carrier.mts'; + +const root = import.meta.dir; +function fixture(tag = '0.8.1') { + const expectedVersion = tag === '0.8.1' ? '0.3.2' : '0.3.3'; + return { + source: JSON.parse(readFileSync(path.join(root, `swift-${tag}-source.json`), 'utf8')), + carrierBytes: readFileSync(path.join(root, `testdata/swift-${tag}-carrier.json`)), + expectedVersion, + publicationContext: { + nativeCompletion: JSON.parse( + readFileSync( + path.join(root, `native-${expectedVersion}-completed-publication.json`), + 'utf8', + ), + ), + nativeReleases: JSON.parse( + readFileSync(path.join(root, `native-${expectedVersion}-releases.json`), 'utf8'), + ), + swiftSource: JSON.parse( + readFileSync(path.join(root, `swift-${tag}-publication-source.json`), 'utf8'), + ), + }, + }; +} +function changed(update) { + const value = fixture(); + const document = JSON.parse(value.carrierBytes.toString()); + update(document); + value.carrierBytes = Buffer.from(JSON.stringify(document)); + value.source = { + ...value.source, + bytes: value.carrierBytes.length, + sha256: createHash('sha256').update(value.carrierBytes).digest('hex'), + source_blob: createHash('sha1') + .update(`blob ${value.carrierBytes.length}\0`) + .update(value.carrierBytes) + .digest('hex'), + }; + // Model a different externally captured publication, rather than asking the + // incoming document to supply its own expected blob or asset declarations. + value.publicationContext.swiftSource.member.sha = value.source.source_blob; + for (const asset of document.base.assets) { + const row = value.publicationContext.nativeReleases[0].assets.find( + ({ name }) => name === asset.name, + ); + row.sha256 = asset.sha256; + row.size = asset.bytes; + } + return value; +} + +test('reads exact published source members for the independently held and current runtime pins', () => { + for (const tag of ['0.8.1', '0.8.2']) { + const value = fixture(tag); + const carrier = readFrozenNativeCarrier(value); + expect(carrier.base.version).toBe(value.expectedVersion); + expect(frozenNativeCarrierSource(value.source)).toContain( + `/${value.source.source_commit}/${value.source.source_member}`, + ); + expect(carrier.base.assets).toHaveLength(2); + } + expect(() => readFrozenNativeCarrier({ ...fixture(), expectedVersion: '0.3.3' })).toThrow( + 'matching authenticated publication context', + ); +}); + +test('declared publication inputs independently bind the source blob, parent and native assets', () => { + const value = fixture(); + expect(() => readFrozenNativeCarrier({ ...value, publicationContext: undefined })).toThrow( + 'matching authenticated publication context', + ); + for (const update of [ + (context) => { + context.swiftSource.member.sha = 'f'.repeat(40); + }, + (context) => { + context.swiftSource.commit.parents[0].sha = 'f'.repeat(40); + }, + (context) => { + context.swiftSource.publication.publicationSha = 'f'.repeat(40); + }, + (context) => { + context.nativeCompletion.publicationSha = 'f'.repeat(40); + }, + (context) => { + context.nativeReleases[0].assets.find(({ name }) => + name.endsWith('apple-spm-xcframework.zip'), + ).sha256 = 'f'.repeat(64); + }, + ]) { + const publicationContext = structuredClone(value.publicationContext); + update(publicationContext); + expect(() => readFrozenNativeCarrier({ ...value, publicationContext })).toThrow(); + } + const incoming = changed((carrier) => { + carrier.legal.base[0].files[0].sha256 = 'f'.repeat(64); + }); + expect(() => + readFrozenNativeCarrier({ ...incoming, publicationContext: value.publicationContext }), + ).toThrow('matching authenticated publication context'); +}); + +test('source membership and bytes are immutable', () => { + const value = fixture(); + for (const field of [ + 'repository', + 'source_tag', + 'source_commit', + 'source_tree', + 'source_member', + 'source_blob', + 'sha256', + 'bytes', + ]) + expect(() => frozenNativeCarrierSource({ ...value.source, [field]: '' })).toThrow( + 'exact immutable published source facts', + ); + for (const field of ['sha256', 'source_blob']) + expect(() => + readFrozenNativeCarrier({ + ...value, + source: { ...value.source, [field]: 'f'.repeat(field === 'sha256' ? 64 : 40) }, + }), + ).toThrow('immutable source member'); + expect(() => + readFrozenNativeCarrier({ + ...value, + carrierBytes: Buffer.concat([value.carrierBytes, Buffer.from(' ')]), + }), + ).toThrow('immutable source member'); +}); + +test('frozen legal digests may differ from current source but retain strict legal locators', () => { + const value = changed((carrier) => { + carrier.legal.base[0].files[0].sha256 = 'f'.repeat(64); + }); + expect(readFrozenNativeCarrier(value).legal.base[0].files[0].sha256).toBe('f'.repeat(64)); + for (const update of [ + (carrier) => { + carrier.legal.base[0].files[0].member = 'elsewhere/LICENSE'; + }, + (carrier) => { + carrier.legal.base[1].files[0].member = '../LICENSE'; + }, + (carrier) => { + carrier.legal.base[0].files[0].kind = 'payload'; + }, + (carrier) => { + carrier.legal.base[0].files[0].bytes = 0; + }, + (carrier) => { + carrier.legal.base[0].files[0].sha256 = 'missing'; + }, + (carrier) => { + carrier.legal.base[0].assetRole = 'runtime-resources'; + }, + (carrier) => { + carrier.legal.base[1].files.push({ ...carrier.legal.base[1].files[0] }); + }, + ]) + expect(() => readFrozenNativeCarrier(changed(update))).toThrow(); +}); + +test('every materialized asset must match the exact frozen bytes and size', () => { + const directory = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-published-assets-')); + try { + const value = changed((carrier) => { + for (const asset of carrier.base.assets) { + const bytes = Buffer.from(asset.role); + asset.bytes = bytes.length; + asset.sha256 = createHash('sha256').update(bytes).digest('hex'); + writeFileSync(path.join(directory, asset.name), bytes); + } + }); + expect( + readFrozenNativeCarrier({ ...value, assetDirectory: directory }).base.assets, + ).toHaveLength(2); + const name = readFrozenNativeCarrier(value).base.assets[1].name; + writeFileSync(path.join(directory, name), 'changed runtime resources'); + expect(() => readFrozenNativeCarrier({ ...value, assetDirectory: directory })).toThrow(name); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); diff --git a/build_defs/release/frozen-native-npm.bzl b/build_defs/release/frozen-native-npm.bzl new file mode 100644 index 000000000..6fa7762fd --- /dev/null +++ b/build_defs/release/frozen-native-npm.bzl @@ -0,0 +1,44 @@ +"""A declared held npm runtime archive bound to the consumer's conventional pin.""" + +def _frozen_native_npm_impl(ctx): + authored = ctx.attr.compatibility.package + "/" + ctx.attr.compatibility.name + if authored != ctx.attr.compatibility_path: + fail("Frozen npm compatibility label must name the exact authored descriptor source") + sources = [ctx.attr.metadata, ctx.attr.attestations, ctx.attr.releases, ctx.attr.completion, ctx.attr.descriptor, ctx.attr.compatibility, ctx.attr.owner_descriptor] + for source in sources + [ctx.attr.converter] + ctx.attr.helpers: + ctx.read(source) + ctx.watch(ctx.path(ctx.attr.bun)) + command = [str(ctx.path(ctx.attr.bun)), str(ctx.path(ctx.attr.converter))] + [str(ctx.path(source)) for source in sources[:6]] + [ctx.attr.compatibility_path, str(ctx.path(ctx.attr.owner_descriptor)), ctx.attr.target, str(ctx.path("inputs.json"))] + checked = ctx.execute(command, timeout = 60) + if checked.return_code: + fail("Frozen npm input facts are invalid:\n" + checked.stdout + checked.stderr) + artifact = json.decode(ctx.read("inputs.json")) + ctx.download(url = artifact["url"], output = artifact["filename"], integrity = artifact["integrity"]) + checked = ctx.execute(command + [str(ctx.path(artifact["filename"]))], timeout = 120) + if checked.return_code: + fail("Frozen npm bytes are invalid:\n" + checked.stdout + checked.stderr) + name = artifact["target"].replace("-", "_") + ctx.file("BUILD.bazel", 'package(default_visibility = ["//visibility:public"])\nexports_files(["inputs.json"])\nfilegroup(name = "archive", srcs = [%s])\nfilegroup(name = "npm_%s", srcs = [":archive"])\n' % (repr(artifact["filename"]), name)) + return ctx.repo_metadata(reproducible = True) + +frozen_native_npm_repository = repository_rule( + implementation = _frozen_native_npm_impl, + attrs = { + "metadata": attr.label(allow_single_file = True, mandatory = True), + "attestations": attr.label(allow_single_file = True, mandatory = True), + "releases": attr.label(allow_single_file = True, mandatory = True), + "completion": attr.label(allow_single_file = True, mandatory = True), + "descriptor": attr.label(allow_single_file = True, mandatory = True), + "compatibility": attr.label(allow_single_file = True, mandatory = True), + "compatibility_path": attr.string(mandatory = True), + "target": attr.string(mandatory = True), + "owner_descriptor": attr.label(default = Label("//src/native/runtime:release.toml"), allow_single_file = True), + "bun": attr.label(default = Label("@bun_runtime//:bun"), allow_single_file = True), + "converter": attr.label(default = Label("//build_defs/release:frozen-native-npm.mts"), allow_single_file = True), + "helpers": attr.label_list(default = [ + Label("//build_defs/release:frozen-native-runtime.mts"), Label("//tools/release:compatibility-version-parser.mts"), Label("//:tools/packaging/portable-archive.mts"), + Label("//:tools/packaging/platform-binary-contract.mts"), Label("//:tools/packaging/windows-vc-runtime-closure.mts"), + Label("//:tools/packaging/windows-vc-runtime-policy.json"), Label("//tools/release:platform-compatibility-policy.mts"), + ], allow_files = True), + }, +) diff --git a/build_defs/release/frozen-native-npm.mts b/build_defs/release/frozen-native-npm.mts new file mode 100644 index 000000000..d771928d6 --- /dev/null +++ b/build_defs/release/frozen-native-npm.mts @@ -0,0 +1,213 @@ +import { createHash } from 'node:crypto'; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { frozenNativeRuntimeInputs } from './frozen-native-runtime.mts'; +import { + extractPortableArchiveTree, + readPortableArchiveEntries, +} from '../../tools/packaging/portable-archive.mts'; +import { inspectPlatformBinaryEntries } from '../../tools/packaging/platform-binary-contract.mts'; +import { verifyWindowsVcRuntimeClosure } from '../../tools/packaging/windows-vc-runtime-closure.mts'; + +const provenance = 'https://slsa.dev/provenance/v1'; +const publish = 'https://github.com/npm/attestation/tree/main/specs/publish/v0.1'; +const repository = 'https://github.com/f0rr0/oliphaunt'; +const platforms = new Map([ + ['linux-x64-gnu', { suffix: 'linux-x64-gnu', os: 'linux', cpu: 'x64', libc: ['glibc'] }], + ['linux-arm64-gnu', { suffix: 'linux-arm64-gnu', os: 'linux', cpu: 'arm64', libc: ['glibc'] }], + ['macos-arm64', { suffix: 'darwin-arm64', os: 'darwin', cpu: 'arm64' }], + ['windows-x64-msvc', { suffix: 'win32-x64-msvc', os: 'win32', cpu: 'x64' }], +]); + +function matchesPlatform(manifest, target) { + const platform = platforms.get(target); + return ( + platform && + manifest.name === `@oliphaunt/liboliphaunt-${platform.suffix}` && + JSON.stringify(manifest.os) === JSON.stringify([platform.os]) && + JSON.stringify(manifest.cpu) === JSON.stringify([platform.cpu]) && + JSON.stringify(manifest.libc) === JSON.stringify(platform.libc) && + manifest.optional === true + ); +} + +/** Consume independently signature-verified registry captures; this is not a new authentication authority. */ +export function frozenNativeNpmInput({ + metadata, + attestations, + ownerDescriptor, + target, + ...runtime +}) { + const [native] = frozenNativeRuntimeInputs({ ...runtime, selectedTargets: [target] }); + const name = metadata.name; + const version = native.version; + if ( + ownerDescriptor.id !== 'liboliphaunt-native' || + !ownerDescriptor.registry_packages?.includes(`npm:${name}`) || + !matchesPlatform(metadata, target) || + metadata.version !== version || + metadata.oliphaunt?.target !== target || + metadata.oliphaunt.libraryRelativePath !== native.library || + metadata.oliphaunt.runtimeRelativePath !== 'runtime' + ) + throw new Error( + 'frozen native npm identity differs from its declared owner or compatibility pin', + ); + const filename = `${name.split('/').at(-1)}-${version}.tgz`; + const url = `https://registry.npmjs.org/${name}/-/${filename}`; + const integrity = metadata.dist?.integrity; + if ( + metadata.dist?.tarball !== url || + !/^sha512-[A-Za-z0-9+/]{86}==$/u.test(integrity ?? '') || + !/^[0-9a-f]{40}$/u.test(metadata.dist?.shasum ?? '') + ) + throw new Error( + 'frozen native npm requires canonical registry URL and immutable SHA-512 integrity', + ); + const sha512 = Buffer.from(integrity.slice(7), 'base64').toString('hex'); + const subject = `pkg:npm/${name.replace('@', '%40')}@${version}`; + for (const kind of [provenance, publish]) { + const rows = attestations?.attestations?.filter((row) => row.predicateType === kind) ?? []; + if (rows.length !== 1) + throw new Error( + 'frozen native npm requires unique captured provenance and publish attestations', + ); + const envelope = rows[0].bundle?.dsseEnvelope; + if (envelope?.payloadType !== 'application/vnd.in-toto+json' || !envelope.signatures?.length) + throw new Error('frozen native npm attestation is missing its signed statement'); + const statement = JSON.parse(Buffer.from(envelope.payload, 'base64').toString('utf8')); + if ( + statement.predicateType !== kind || + statement.subject?.length !== 1 || + statement.subject[0].name !== subject || + statement.subject[0].digest?.sha512 !== sha512 + ) + throw new Error('frozen native npm attestation does not bind the exact registry archive'); + if (kind === provenance) { + const definition = statement.predicate?.buildDefinition; + const workflow = definition?.externalParameters?.workflow; + const sources = definition?.resolvedDependencies ?? []; + if ( + definition?.buildType !== + 'https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1' || + workflow?.repository !== repository || + workflow.ref !== 'refs/heads/main' || + workflow.path !== '.github/workflows/release.yml' || + sources.length !== 1 || + sources[0].uri !== `git+${repository}@refs/heads/main` || + sources[0].digest?.gitCommit !== native.publicationSha + ) + throw new Error( + 'frozen native npm provenance differs from the completed native publication source', + ); + } else if ( + statement.predicate?.name !== name || + statement.predicate.version !== version || + statement.predicate.registry !== 'https://registry.npmjs.org' + ) + throw new Error('frozen native npm publish attestation differs from its registry identity'); + } + return { + name, + version, + target, + filename, + url, + integrity, + shasum: metadata.dist.shasum, + library: native.library, + publicationSha: native.publicationSha, + publicationTree: native.publicationTree, + }; +} + +export function verifyFrozenNativeNpm(input, archive) { + const bytes = readFileSync(archive); + if ( + `sha512-${createHash('sha512').update(bytes).digest('base64')}` !== input.integrity || + createHash('sha1').update(bytes).digest('hex') !== input.shasum + ) + throw new Error('frozen native npm archive differs from captured registry integrity'); + const entries = readPortableArchiveEntries(archive); + if ([...entries.keys()].some((name) => name !== 'package' && !name.startsWith('package/'))) + throw new Error('frozen native npm archive must contain only its package tree'); + const member = entries.get('package/package.json'); + if (!member?.isFile) + throw new Error('frozen native npm archive is missing its regular package manifest'); + const manifest = JSON.parse( + (typeof member.data === 'function' ? member.data() : member.data).toString('utf8'), + ); + if ( + manifest.name !== input.name || + manifest.version !== input.version || + !matchesPlatform(manifest, input.target) || + manifest.oliphaunt?.target !== input.target || + manifest.oliphaunt.libraryRelativePath !== input.library || + manifest.oliphaunt.runtimeRelativePath !== 'runtime' + ) + throw new Error('frozen native npm physical manifest differs from declared registry identity'); + for (const file of [ + input.library, + `runtime/bin/initdb${input.target === 'windows-x64-msvc' ? '.exe' : ''}`, + 'runtime/share/postgresql/postgres.bki', + 'LICENSE', + 'THIRD_PARTY_NOTICES.md', + 'THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT', + 'THIRD_PARTY_LICENSES/ICU-LICENSE', + ]) + if (!entries.get(`package/${file}`)?.isFile || entries.get(`package/${file}`).size <= 0) + throw new Error(`frozen native npm archive is missing regular runtime/legal member ${file}`); + if (input.target === 'windows-x64-msvc') { + inspectPlatformBinaryEntries( + [...entries].map(([name, entry]) => ({ ...entry, name: name.replace(/^package\//u, '') })), + { target: input.target, rootLabel: input.filename, windowsVcRuntimeProfile: 'provider' }, + ); + const root = mkdtempSync(path.join(tmpdir(), 'frozen-native-npm-')); + try { + extractPortableArchiveTree(archive, root, 'package'); + verifyWindowsVcRuntimeClosure({ + root, + searchRoots: [path.join(root, 'bin'), path.join(root, 'runtime/bin')], + profile: 'provider', + }); + } finally { + rmSync(root, { recursive: true, force: true }); + } + } +} + +if (import.meta.main) { + const [ + metadata, + attestations, + releases, + completion, + descriptor, + compatibility, + compatibilityPath, + owner, + target, + output, + archive, + ] = process.argv.slice(2); + if (!output || process.argv.length > 13) + throw new Error( + 'usage: frozen-native-npm.mts METADATA ATTESTATIONS RELEASES COMPLETION DESCRIPTOR COMPATIBILITY PATH OWNER TARGET OUTPUT [ARCHIVE]', + ); + const json = (file) => JSON.parse(readFileSync(file, 'utf8')); + const input = frozenNativeNpmInput({ + metadata: json(metadata), + attestations: json(attestations), + releases: json(releases), + completion: json(completion), + descriptor: Bun.TOML.parse(readFileSync(descriptor, 'utf8')), + compatibilityText: readFileSync(compatibility, 'utf8'), + compatibilityPath, + ownerDescriptor: Bun.TOML.parse(readFileSync(owner, 'utf8')), + target, + }); + if (archive) verifyFrozenNativeNpm(input, archive); + writeFileSync(output, JSON.stringify(input)); +} diff --git a/build_defs/release/frozen-native-npm.test.mts b/build_defs/release/frozen-native-npm.test.mts new file mode 100644 index 000000000..befe2451c --- /dev/null +++ b/build_defs/release/frozen-native-npm.test.mts @@ -0,0 +1,231 @@ +import { expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { archiveDirectory } from '../../tools/packaging/archive-directory.mts'; +import { windowsPeFixture } from '../../tools/packaging/testdata/release-fixture-utils.mts'; +import { frozenNativeNpmInput, verifyFrozenNativeNpm } from './frozen-native-npm.mts'; + +const root = path.resolve(import.meta.dir, '../..'); +const request = (target = 'linux-x64-gnu') => { + const json = (file) => JSON.parse(readFileSync(path.join(import.meta.dir, file), 'utf8')); + const text = (file) => readFileSync(path.join(root, file), 'utf8'); + return { + metadata: json(`native-0.3.2-npm-${target}.json`), + attestations: json(`native-0.3.2-npm-${target}-attestations.json`), + releases: json('native-0.3.2-releases.json'), + completion: json('native-0.3.2-completed-publication.json'), + descriptor: Bun.TOML.parse(text('src/native/sdks/ts/release.toml')), + compatibilityText: text('src/native/sdks/ts/package.json'), + compatibilityPath: 'src/native/sdks/ts/package.json', + target, + ownerDescriptor: Bun.TOML.parse(text('src/native/runtime/release.toml')), + }; +}; + +test('held npm uses the conventional SDK pin, registry integrity and exact completed source', () => { + for (const target of ['linux-x64-gnu', 'linux-arm64-gnu', 'macos-arm64', 'windows-x64-msvc']) { + const captured = request(target); + const input = frozenNativeNpmInput(captured); + expect(input.version).toBe('0.3.2'); + expect(input.target).toBe(target); + expect(input.name).toBe(captured.metadata.name); + expect(input.publicationSha).toBe('31b5803d80ce3884a1fc2d3e9ab869dd733b461c'); + expect(input.integrity).toBe(captured.metadata.dist.integrity); + } +}); + +test('held npm rejects pin, owner, registry, provenance and physical target substitutions', () => { + const bad = (mutate) => { + const value = request(); + mutate(value); + expect(() => frozenNativeNpmInput(value)).toThrow(); + }; + bad((value) => { + value.compatibilityText = value.compatibilityText.replace( + '"liboliphauntVersion": "0.3.2"', + '"liboliphauntVersion": "0.3.3"', + ); + }); + bad((value) => { + value.ownerDescriptor.registry_packages = []; + }); + bad((value) => { + value.metadata.version = '0.3.3'; + }); + bad((value) => { + value.metadata.oliphaunt.target = 'linux-arm64-gnu'; + }); + bad((value) => { + value.metadata.oliphaunt.libraryRelativePath = '../lib.so'; + }); + bad((value) => { + value.metadata.name = '@oliphaunt/liboliphaunt-linux-arm64-gnu'; + }); + for (const [key, replacement] of [ + ['os', ['win32']], + ['cpu', ['arm64']], + ['libc', ['musl']], + ['optional', false], + ]) + bad((value) => { + value.metadata[key] = replacement; + }); + bad((value) => { + value.metadata.dist.tarball = 'https://example.com/archive.tgz'; + }); + bad((value) => { + value.metadata.dist.integrity = 'sha256-abc'; + }); + bad((value) => { + value.attestations.attestations = []; + }); + bad((value) => { + value.attestations.attestations.push(value.attestations.attestations[0]); + }); + bad((value) => { + const row = value.attestations.attestations.find( + (row) => row.predicateType === 'https://slsa.dev/provenance/v1', + ); + const statement = JSON.parse(Buffer.from(row.bundle.dsseEnvelope.payload, 'base64').toString()); + statement.predicate.buildDefinition.resolvedDependencies[0].digest.gitCommit = '0'.repeat(40); + row.bundle.dsseEnvelope.payload = Buffer.from(JSON.stringify(statement)).toString('base64'); + }); + bad((value) => { + const row = value.attestations.attestations[0]; + const statement = JSON.parse(Buffer.from(row.bundle.dsseEnvelope.payload, 'base64').toString()); + statement.subject[0].digest.sha512 = '0'.repeat(128); + row.bundle.dsseEnvelope.payload = Buffer.from(JSON.stringify(statement)).toString('base64'); + }); +}); + +test('Windows held npm requires initdb.exe, x64 PE bytes and both complete CRT receipts', async () => { + const temp = mkdtempSync(path.join(os.tmpdir(), 'held-native-npm-windows-')); + try { + const source = path.join(temp, 'package'); + const input = { + ...frozenNativeNpmInput(request()), + name: '@oliphaunt/liboliphaunt-win32-x64-msvc', + target: 'windows-x64-msvc', + library: 'bin/oliphaunt.dll', + }; + const manifest = { + ...request().metadata, + name: input.name, + os: ['win32'], + cpu: ['x64'], + oliphaunt: { + target: input.target, + libraryRelativePath: input.library, + runtimeRelativePath: 'runtime', + }, + }; + delete manifest.libc; + const write = (file, bytes) => { + mkdirSync(path.dirname(path.join(source, file)), { recursive: true }); + writeFileSync(path.join(source, file), bytes); + }; + write('package.json', JSON.stringify(manifest)); + for (const file of [ + 'runtime/share/postgresql/postgres.bki', + 'LICENSE', + 'THIRD_PARTY_NOTICES.md', + 'THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT', + 'THIRD_PARTY_LICENSES/ICU-LICENSE', + ]) + write(file, `fixture ${file}`); + write(input.library, windowsPeFixture({ imports: ['VCRUNTIME140.dll'] })); + write('runtime/bin/initdb.exe', windowsPeFixture()); + const crt = windowsPeFixture({ imports: ['KERNEL32.dll'] }); + const names = ['msvcp140.dll', 'vcruntime140.dll', 'vcruntime140_1.dll']; + const receipt = names + .map((name) => `${createHash('sha256').update(crt).digest('hex')} ${name}\n`) + .join(''); + for (const directory of ['bin', 'runtime/bin']) { + for (const name of names) write(`${directory}/${name}`, crt); + write(`${directory}/windows-vc-runtime.sha256`, receipt); + } + const archive = path.join(temp, 'fixture.tar.gz'); + const pack = async () => { + await archiveDirectory(source, archive, { keepParent: true }); + const bytes = readFileSync(archive); + return { + ...input, + integrity: `sha512-${createHash('sha512').update(bytes).digest('base64')}`, + shasum: createHash('sha1').update(bytes).digest('hex'), + }; + }; + verifyFrozenNativeNpm(await pack(), archive); + rmSync(path.join(source, 'runtime/bin/initdb.exe')); + write('runtime/bin/initdb', windowsPeFixture()); + const unixInitdb = await pack(); + expect(() => verifyFrozenNativeNpm(unixInitdb, archive)).toThrow('initdb.exe'); + rmSync(path.join(source, 'runtime/bin/initdb')); + write('runtime/bin/initdb.exe', windowsPeFixture()); + write(input.library, windowsPeFixture({ machine: 0x14c })); + const wrongMachine = await pack(); + expect(() => verifyFrozenNativeNpm(wrongMachine, archive)).toThrow('not x64'); + write(input.library, windowsPeFixture({ imports: ['VCRUNTIME140.dll'] })); + write( + 'runtime/bin/windows-vc-runtime.sha256', + receipt.replace(/^[a-f0-9]{64}/u, '0'.repeat(64)), + ); + const badReceipt = await pack(); + expect(() => verifyFrozenNativeNpm(badReceipt, archive)).toThrow('does not match'); + write('runtime/bin/windows-vc-runtime.sha256', receipt); + rmSync(path.join(source, 'runtime/bin/vcruntime140.dll')); + const missingCrt = await pack(); + expect(() => verifyFrozenNativeNpm(missingCrt, archive)).toThrow('closure mismatch'); + } finally { + rmSync(temp, { recursive: true, force: true }); + } +}); + +test('physical held npm checks integrity, manifest identity and real runtime/legal members', async () => { + const temp = mkdtempSync(path.join(os.tmpdir(), 'held-native-npm-')); + try { + const input = frozenNativeNpmInput(request()); + const source = path.join(temp, 'package'); + const manifest = request().metadata; + const members = [ + input.library, + 'runtime/bin/initdb', + 'runtime/share/postgresql/postgres.bki', + 'LICENSE', + 'THIRD_PARTY_NOTICES.md', + 'THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT', + 'THIRD_PARTY_LICENSES/ICU-LICENSE', + ]; + const write = (file, text) => { + mkdirSync(path.dirname(path.join(source, file)), { recursive: true }); + writeFileSync(path.join(source, file), text); + }; + for (const member of members) write(member, `fixture ${member}`); + write('package.json', JSON.stringify(manifest)); + const archive = path.join(temp, 'fixture.tar.gz'); + const pack = async () => { + await archiveDirectory(source, archive, { keepParent: true }); + const bytes = readFileSync(archive); + return { + ...input, + integrity: `sha512-${createHash('sha512').update(bytes).digest('base64')}`, + shasum: createHash('sha1').update(bytes).digest('hex'), + }; + }; + const physical = await pack(); + verifyFrozenNativeNpm(physical, archive); + expect(() => verifyFrozenNativeNpm(input, archive)).toThrow('integrity'); + manifest.version = '0.3.3'; + write('package.json', JSON.stringify(manifest)); + const changed = await pack(); + expect(() => verifyFrozenNativeNpm(changed, archive)).toThrow('manifest'); + manifest.version = input.version; + write('package.json', JSON.stringify(manifest)); + rmSync(path.join(source, 'THIRD_PARTY_LICENSES/ICU-LICENSE')); + const incomplete = await pack(); + expect(() => verifyFrozenNativeNpm(incomplete, archive)).toThrow('ICU-LICENSE'); + } finally { + rmSync(temp, { recursive: true, force: true }); + } +}); diff --git a/build_defs/release/frozen-native-runtime.bzl b/build_defs/release/frozen-native-runtime.bzl new file mode 100644 index 000000000..10c99625f --- /dev/null +++ b/build_defs/release/frozen-native-runtime.bzl @@ -0,0 +1,56 @@ +"""Declared immutable published native inputs; construction acquisition, not admission.""" + +def _frozen_native_runtime_impl(ctx): + authored_path = ctx.attr.compatibility.package + "/" + ctx.attr.compatibility.name + if authored_path != ctx.attr.compatibility_path: + fail("Frozen native compatibility label must name the descriptor's exact authored source path") + for source in [ctx.attr.releases, ctx.attr.completion, ctx.attr.descriptor, ctx.attr.compatibility, ctx.attr.converter] + ctx.attr.helpers: + ctx.read(source) + ctx.watch(ctx.path(ctx.attr.bun)) + command = [str(ctx.path(ctx.attr.bun)), str(ctx.path(ctx.attr.converter)), str(ctx.path(ctx.attr.releases)), str(ctx.path(ctx.attr.completion)), str(ctx.path(ctx.attr.descriptor)), str(ctx.path(ctx.attr.compatibility)), ctx.attr.compatibility_path, json.encode(ctx.attr.targets), str(ctx.path("inputs.json"))] + checked = ctx.execute(command, timeout = 60) + if checked.return_code: + fail("Frozen native publication inputs are invalid:\n" + checked.stdout + checked.stderr) + inputs = json.decode(ctx.read("inputs.json")) + for artifact in inputs: + ctx.download(url = artifact["url"], output = artifact["name"], sha256 = artifact["sha256"]) + checked = ctx.execute(command + [str(ctx.path("."))], timeout = 120) + if checked.return_code: + fail("Frozen native archive verification failed:\n" + checked.stdout + checked.stderr) + lines = ['load("@rules_cc//cc:cc_import.bzl", "cc_import")', 'load("@rules_cc//cc:cc_library.bzl", "cc_library")', 'package(default_visibility = ["//visibility:public"])', 'exports_files(["inputs.json"])'] + for artifact in inputs: + target = artifact["target"] + name = target.replace("-", "_") + os = "android" if target.startswith("android-") else "osx" if target.startswith("macos-") else "windows" if target.startswith("windows-") else "linux" + cpu = "aarch64" if "arm64" in target else "x86_64" + lines.extend([ + 'filegroup(name = "archive_%s", srcs = [%s])' % (name, repr(artifact["name"])), + 'filegroup(name = "runtime_%s", srcs = glob(["%s/**"], exclude_directories = 1))' % (name, target), + 'filegroup(name = "library_%s", srcs = ["%s/%s"])' % (name, target, artifact["library"]), + 'filegroup(name = "headers_%s", srcs = ["%s/include/oliphaunt.h"])' % (name, target), + 'cc_import(name = "_cc_%s", shared_library = "%s/%s"%s, visibility = ["//visibility:private"], target_compatible_with = ["@platforms//os:%s", "@platforms//cpu:%s"])' % (name, target, artifact["library"], ', interface_library = "%s/%s"' % (target, artifact["interfaceLibrary"]) if artifact.get("interfaceLibrary") else "", os, cpu), + 'cc_library(name = "cc_%s", hdrs = ["%s/include/oliphaunt.h"], strip_include_prefix = "%s/include", deps = [":_cc_%s"], target_compatible_with = ["@platforms//os:%s", "@platforms//cpu:%s"])' % (name, target, target, name, os, cpu), + ]) + if artifact.get("interfaceLibrary"): + lines.append('filegroup(name = "interface_library_%s", srcs = ["%s/%s"])' % (name, target, artifact["interfaceLibrary"])) + ctx.file("BUILD.bazel", "\n".join(lines) + "\n") + return ctx.repo_metadata(reproducible = True) + +frozen_native_runtime_repository = repository_rule( + implementation = _frozen_native_runtime_impl, + attrs = { + "releases": attr.label(allow_single_file = True, mandatory = True), + "completion": attr.label(allow_single_file = True, mandatory = True), + "descriptor": attr.label(allow_single_file = True, mandatory = True), + "compatibility": attr.label(allow_single_file = True, mandatory = True), + "compatibility_path": attr.string(mandatory = True), + "targets": attr.string_list(mandatory = True), + "bun": attr.label(default = Label("@bun_runtime//:bun"), allow_single_file = True), + "converter": attr.label(default = Label("//build_defs/release:frozen-native-runtime.mts"), allow_single_file = True), + "helpers": attr.label_list(default = [ + Label("//tools/release:compatibility-version-parser.mts"), Label("//:tools/packaging/portable-archive.mts"), + Label("//:tools/packaging/platform-binary-contract.mts"), Label("//:tools/packaging/windows-vc-runtime-closure.mts"), + Label("//:tools/packaging/windows-vc-runtime-policy.json"), Label("//tools/release:platform-compatibility-policy.mts"), + ], allow_files = True), + }, +) diff --git a/build_defs/release/frozen-native-runtime.mts b/build_defs/release/frozen-native-runtime.mts new file mode 100644 index 000000000..9ac43b692 --- /dev/null +++ b/build_defs/release/frozen-native-runtime.mts @@ -0,0 +1,212 @@ +import { createHash } from 'node:crypto'; +import { readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { inspectPlatformBinaryEntries } from '../../tools/packaging/platform-binary-contract.mts'; +import { + extractPortableArchiveTree, + readPortableArchiveEntries, +} from '../../tools/packaging/portable-archive.mts'; +import { verifyWindowsVcRuntimeClosure } from '../../tools/packaging/windows-vc-runtime-closure.mts'; +import { compatibilityVersionFromText } from '../../tools/release/compatibility-version-parser.mts'; + +const product = 'liboliphaunt-native'; +const fullSha = /^[a-f0-9]{40}$/u; +const digest = /^[a-f0-9]{64}$/u; +const stableVersion = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u; +const targets = new Map([ + ['linux-x64-gnu', 'lib/liboliphaunt.so'], + ['linux-arm64-gnu', 'lib/liboliphaunt.so'], + ['macos-arm64', 'lib/liboliphaunt.dylib'], + ['android-arm64-v8a', 'lib/liboliphaunt.so'], + ['android-x86_64', 'lib/liboliphaunt.so'], + ['windows-x64-msvc', 'bin/oliphaunt.dll'], +]); + +function exactKeys(value, keys, context) { + if ( + !value || + typeof value !== 'object' || + Array.isArray(value) || + JSON.stringify(Object.keys(value).sort()) !== JSON.stringify([...keys].sort()) + ) + throw new Error(`${context} requires exact immutable fact fields`); +} + +/** Import existing captured GitHub/completion facts, bound to the consumer's authored pin. */ +export function frozenNativeRuntimeInputs({ + releases, + completion, + descriptor, + compatibilityText, + compatibilityPath, + selectedTargets, +}) { + const matches = Object.entries(descriptor.compatibility_versions ?? {}).filter( + ([, entry]) => entry.source_product === product && entry.path === compatibilityPath, + ); + if (matches.length !== 1) + throw new Error('native runtime acquisition requires one declared compatibility owner/source'); + const [id, entry] = matches[0]; + const version = compatibilityVersionFromText({ id, ...entry }, compatibilityText); + if (!stableVersion.test(version)) + throw new Error('native runtime requires one stable compatibility pin'); + exactKeys( + completion, + ['product', 'version', 'tagName', 'publicationSha', 'publicationTree', 'releaseSha'], + 'completed publication', + ); + if ( + completion.product !== product || + completion.version !== version || + completion.tagName !== `${product}-v${version}` || + ![completion.publicationSha, completion.publicationTree, completion.releaseSha].every((sha) => + fullSha.test(sha), + ) + ) + throw new Error('completed publication does not match the declared native compatibility pin'); + if (!Array.isArray(releases) || releases.length !== 1) + throw new Error('native acquisition requires one captured published release'); + const release = releases[0]; + exactKeys( + release, + [ + 'product', + 'version', + 'tag', + 'releaseId', + 'releaseName', + 'targetCommitish', + 'draft', + 'prerelease', + 'assets', + ], + 'GitHub release snapshot', + ); + if ( + release.product !== product || + release.version !== version || + release.tag !== completion.tagName || + release.releaseName !== `${product} v${version}` || + release.targetCommitish !== completion.publicationSha || + release.draft !== false || + release.prerelease !== false || + !Number.isSafeInteger(release.releaseId) || + release.releaseId <= 0 || + !Array.isArray(release.assets) || + release.assets.length === 0 + ) + throw new Error('GitHub release snapshot differs from the completed native publication'); + const names = new Set(); + const ids = new Set(); + for (const asset of release.assets) { + exactKeys(asset, ['assetId', 'name', 'sha256', 'size'], 'GitHub release asset'); + if ( + !Number.isSafeInteger(asset.assetId) || + asset.assetId <= 0 || + ids.has(asset.assetId) || + !/^[A-Za-z0-9][A-Za-z0-9._-]*$/u.test(asset.name) || + names.has(asset.name) || + !digest.test(asset.sha256) || + !Number.isSafeInteger(asset.size) || + asset.size <= 0 + ) + throw new Error('GitHub release snapshot has an invalid or duplicate immutable asset'); + names.add(asset.name); + ids.add(asset.assetId); + } + if ( + !Array.isArray(selectedTargets) || + selectedTargets.length === 0 || + new Set(selectedTargets).size !== selectedTargets.length + ) + throw new Error('native acquisition requires a unique nonempty target set'); + return selectedTargets.map((target) => { + const library = targets.get(target); + if (!library) throw new Error(`unsupported frozen native runtime target: ${target}`); + const windows = target === 'windows-x64-msvc'; + const name = `liboliphaunt-${version}-${target}.${windows ? 'zip' : 'tar.gz'}`; + const asset = release.assets.find((row) => row.name === name); + if (!asset) throw new Error(`completed native publication is missing ${name}`); + return { + ...asset, + target, + library, + ...(windows ? { interfaceLibrary: 'lib/oliphaunt.lib' } : {}), + version, + publicationSha: completion.publicationSha, + publicationTree: completion.publicationTree, + url: `https://github.com/f0rr0/oliphaunt/releases/download/${release.tag}/${name}`, + }; + }); +} + +/** Check physical immutable bytes and extract through the retained safe archive reader. */ +export function extractFrozenNativeRuntime(input, archive, destination) { + const bytes = readFileSync(archive); + if ( + bytes.length !== input.size || + createHash('sha256').update(bytes).digest('hex') !== input.sha256 + ) + throw new Error( + `frozen native runtime archive differs from captured publication: ${input.name}`, + ); + const entries = readPortableArchiveEntries(archive); + for (const member of [ + input.library, + ...(input.interfaceLibrary ? [input.interfaceLibrary] : []), + 'include/oliphaunt.h', + 'LICENSE', + 'THIRD_PARTY_NOTICES.md', + 'THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT', + 'THIRD_PARTY_LICENSES/ICU-LICENSE', + ]) + if (!entries.get(member)?.isFile) + throw new Error(`frozen native runtime is missing regular member ${member}`); + if (input.target === 'windows-x64-msvc') + inspectPlatformBinaryEntries(entries.values(), { + target: input.target, + rootLabel: input.name, + requireWindowsRuntimeImportLibrary: true, + windowsVcRuntimeProfile: 'provider', + }); + extractPortableArchiveTree(archive, destination); + if (input.target === 'windows-x64-msvc') + verifyWindowsVcRuntimeClosure({ + root: destination, + searchRoots: [path.join(destination, 'bin'), path.join(destination, 'runtime/bin')], + profile: 'provider', + }); +} + +if (import.meta.main) { + const [ + releasesFile, + completionFile, + descriptorFile, + compatibilityFile, + compatibilityPath, + targetsJson, + output, + archiveDirectory, + ] = process.argv.slice(2); + if (!output || process.argv.length > 10) + throw new Error( + 'usage: frozen-native-runtime.mts RELEASES COMPLETION DESCRIPTOR COMPATIBILITY PATH TARGETS_JSON OUTPUT [ARCHIVE_DIRECTORY]', + ); + const inputs = frozenNativeRuntimeInputs({ + releases: JSON.parse(readFileSync(releasesFile, 'utf8')), + completion: JSON.parse(readFileSync(completionFile, 'utf8')), + descriptor: Bun.TOML.parse(readFileSync(descriptorFile, 'utf8')), + compatibilityText: readFileSync(compatibilityFile, 'utf8'), + compatibilityPath, + selectedTargets: JSON.parse(targetsJson), + }); + if (archiveDirectory) + for (const input of inputs) + extractFrozenNativeRuntime( + input, + path.join(archiveDirectory, input.name), + path.join(archiveDirectory, input.target), + ); + writeFileSync(output, JSON.stringify(inputs)); +} diff --git a/build_defs/release/frozen-native-runtime.test.mts b/build_defs/release/frozen-native-runtime.test.mts new file mode 100644 index 000000000..f7b065c95 --- /dev/null +++ b/build_defs/release/frozen-native-runtime.test.mts @@ -0,0 +1,238 @@ +import { describe, expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { archiveDirectory } from '../../tools/packaging/archive-directory.mts'; +import { extractFrozenNativeRuntime, frozenNativeRuntimeInputs } from './frozen-native-runtime.mts'; + +const directory = path.dirname(import.meta.path); +const request = () => ({ + releases: JSON.parse(readFileSync(path.join(directory, 'native-0.3.2-releases.json'), 'utf8')), + completion: JSON.parse( + readFileSync(path.join(directory, 'native-0.3.2-completed-publication.json'), 'utf8'), + ), + descriptor: Bun.TOML.parse( + readFileSync(path.join(directory, '../../src/native/sdks/rust/release.toml'), 'utf8'), + ), + compatibilityText: readFileSync( + path.join(directory, '../../src/native/sdks/rust/Cargo.toml'), + 'utf8', + ), + compatibilityPath: 'src/native/sdks/rust/Cargo.toml', + selectedTargets: ['linux-x64-gnu'], +}); + +const kotlinRequest = () => { + const read = (member) => readFileSync(path.join(directory, member), 'utf8'); + const compatibilityPath = + 'src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/liboliphaunt.version'; + return { + releases: JSON.parse(read('native-0.3.3-releases.json')), + completion: JSON.parse(read('native-0.3.3-completed-publication.json')), + descriptor: Bun.TOML.parse(read('../../src/native/sdks/kotlin/release.toml')), + compatibilityText: read(`../../${compatibilityPath}`), + compatibilityPath, + selectedTargets: ['linux-x64-gnu'], + }; +}; + +describe('captured completed native publication acquisition', () => { + test('uses the authored pin and exact captured source, tag and asset bytes', () => { + const [input] = frozenNativeRuntimeInputs(request()); + expect(input.version).toBe('0.3.2'); + expect(input.publicationSha).toBe('31b5803d80ce3884a1fc2d3e9ab869dd733b461c'); + expect(input.publicationTree).toBe('7355d3958334202a31d02aa3291b480fdd1f02f4'); + expect(input.sha256).toBe('cb7aecb19398198c4c3ae48b95b0c7ce3ee4c90e5e7e783608f29ae2b84d55aa'); + expect(input.size).toBe(14152293); + expect(input.url).toBe( + 'https://github.com/f0rr0/oliphaunt/releases/download/liboliphaunt-native-v0.3.2/liboliphaunt-0.3.2-linux-x64-gnu.tar.gz', + ); + }); + + test('binds Kotlin to its own published 0.3.3 pin rather than the Rust held version', () => { + const [input] = frozenNativeRuntimeInputs(kotlinRequest()); + expect(input.version).toBe('0.3.3'); + expect(input.publicationSha).toBe('cd68c6c9655f53c50a3a98d4db36cfc256d26a3c'); + expect(input.sha256).toBe('17daee827bcbd0a1777e60c23e713079e10a20cf321749d9b9700b6e87599071'); + }); + + test('selects genuine desktop archives and the Windows held import library', () => { + const inputs = frozenNativeRuntimeInputs({ + ...kotlinRequest(), + selectedTargets: ['linux-x64-gnu', 'macos-arm64', 'windows-x64-msvc'], + }); + expect( + inputs.map((input) => [input.target, input.name, input.library, input.interfaceLibrary]), + ).toEqual([ + [ + 'linux-x64-gnu', + 'liboliphaunt-0.3.3-linux-x64-gnu.tar.gz', + 'lib/liboliphaunt.so', + undefined, + ], + ['macos-arm64', 'liboliphaunt-0.3.3-macos-arm64.tar.gz', 'lib/liboliphaunt.dylib', undefined], + [ + 'windows-x64-msvc', + 'liboliphaunt-0.3.3-windows-x64-msvc.zip', + 'bin/oliphaunt.dll', + 'lib/oliphaunt.lib', + ], + ]); + expect(inputs[2].sha256).toBe( + '910415985a5e676156a72f2ea5eb778980b46682dd89a1bbc5f487520001a902', + ); + expect(inputs[2].size).toBe(41445869); + expect(new Set(inputs.map((input) => input.publicationSha)).size).toBe(1); + const missing = kotlinRequest(); + missing.selectedTargets = ['windows-x64-msvc']; + missing.releases[0].assets = missing.releases[0].assets.filter( + (asset) => !asset.name.endsWith('.zip'), + ); + expect(() => frozenNativeRuntimeInputs(missing)).toThrow( + 'missing liboliphaunt-0.3.3-windows-x64-msvc.zip', + ); + }); + + test('rejects source/pin drift and incomplete, duplicate or mutable publication facts', () => { + const bad = (mutate) => { + const value = request(); + mutate(value); + expect(() => frozenNativeRuntimeInputs(value)).toThrow(); + }; + bad((value) => { + value.compatibilityText = value.compatibilityText.replace( + 'native-version = "0.3.2"', + 'native-version = "0.3.3"', + ); + }); + bad((value) => { + value.compatibilityPath = 'ambient/Cargo.toml'; + }); + bad((value) => { + value.completion.publicationTree = 'main'; + }); + bad((value) => { + value.releases[0].targetCommitish = 'main'; + }); + bad((value) => { + value.releases[0].draft = true; + }); + bad((value) => { + value.releases[0].assets.push(value.releases[0].assets[0]); + }); + bad((value) => { + value.releases[0].assets = []; + }); + bad((value) => { + value.releases[0].assets = value.releases[0].assets.filter( + (asset) => !asset.name.endsWith('linux-x64-gnu.tar.gz'), + ); + }); + bad((value) => { + value.selectedTargets = ['linux-x64-gnu', 'linux-x64-gnu']; + }); + bad((value) => { + value.selectedTargets = ['unknown']; + }); + }); + + test('requires exact physical bytes and retained regular runtime/legal members', async () => { + const temp = mkdtempSync(path.join(os.tmpdir(), 'held-native-runtime-')); + try { + const fs = await import('node:fs/promises'); + const source = path.join(temp, 'source'); + const members = [ + 'lib/liboliphaunt.so', + 'include/oliphaunt.h', + 'LICENSE', + 'THIRD_PARTY_NOTICES.md', + 'THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT', + 'THIRD_PARTY_LICENSES/ICU-LICENSE', + ]; + for (const member of members) { + await fs.mkdir(path.dirname(path.join(source, member)), { + recursive: true, + }); + await fs.writeFile(path.join(source, member), `fixture ${member}\n`); + } + const archive = path.join(temp, 'fixture.tar.gz'); + await archiveDirectory(source, archive); + const bytes = readFileSync(archive); + const input = { + ...frozenNativeRuntimeInputs(request())[0], + size: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + }; + const output = path.join(temp, 'output'); + extractFrozenNativeRuntime(input, archive, output); + expect(readFileSync(path.join(output, 'include/oliphaunt.h'), 'utf8')).toBe( + 'fixture include/oliphaunt.h\n', + ); + expect(() => + extractFrozenNativeRuntime({ ...input, size: input.size + 1 }, archive, output), + ).toThrow('differs from captured publication'); + writeFileSync(path.join(source, 'include/oliphaunt.h'), 'changed'); + await fs.unlink(path.join(source, 'THIRD_PARTY_LICENSES/ICU-LICENSE')); + await archiveDirectory(source, archive); + const incomplete = readFileSync(archive); + expect(() => + extractFrozenNativeRuntime( + { + ...input, + size: incomplete.length, + sha256: createHash('sha256').update(incomplete).digest('hex'), + }, + archive, + output, + ), + ).toThrow('missing regular member THIRD_PARTY_LICENSES/ICU-LICENSE'); + } finally { + rmSync(temp, { recursive: true, force: true }); + } + }); + + test('Windows physical import requires its interface library and retained native binary contract', async () => { + const temp = mkdtempSync(path.join(os.tmpdir(), 'held-windows-runtime-')); + try { + const fs = await import('node:fs/promises'); + const source = path.join(temp, 'source'); + for (const member of [ + 'bin/oliphaunt.dll', + 'include/oliphaunt.h', + 'LICENSE', + 'THIRD_PARTY_NOTICES.md', + 'THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT', + 'THIRD_PARTY_LICENSES/ICU-LICENSE', + ]) { + await fs.mkdir(path.dirname(path.join(source, member)), { recursive: true }); + await fs.writeFile(path.join(source, member), `fixture ${member}\n`); + } + const archive = path.join(temp, 'physical-fixture.tar.gz'); + const input = frozenNativeRuntimeInputs({ + ...kotlinRequest(), + selectedTargets: ['windows-x64-msvc'], + })[0]; + const extract = async () => { + await archiveDirectory(source, archive); + const bytes = readFileSync(archive); + return () => + extractFrozenNativeRuntime( + { + ...input, + size: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + }, + archive, + path.join(temp, 'output'), + ); + }; + expect(await extract()).toThrow('missing regular member lib/oliphaunt.lib'); + await fs.mkdir(path.join(source, 'lib')); + await fs.writeFile(path.join(source, 'lib/oliphaunt.lib'), 'not an import library'); + expect(await extract()).toThrow(/malformed|truncated/u); + } finally { + rmSync(temp, { recursive: true, force: true }); + } + }); +}); diff --git a/build_defs/release/identity.bzl b/build_defs/release/identity.bzl new file mode 100644 index 000000000..97c2d5473 --- /dev/null +++ b/build_defs/release/identity.bzl @@ -0,0 +1,16 @@ +"""Release identity data, independent of all payload construction.""" + +ReleaseIdentityInfo = provider(fields = ["id", "version"]) + +def _release_identity_impl(ctx): + if not ctx.attr.product_id or not ctx.attr.version: + fail("release identity requires a product id and selected version") + return [ReleaseIdentityInfo(id = ctx.attr.product_id, version = ctx.attr.version)] + +release_identity = rule( + implementation = _release_identity_impl, + attrs = { + "product_id": attr.string(mandatory = True), + "version": attr.string(mandatory = True), + }, +) diff --git a/build_defs/release/native-0.3.2-completed-publication.json b/build_defs/release/native-0.3.2-completed-publication.json new file mode 100644 index 000000000..93e101816 --- /dev/null +++ b/build_defs/release/native-0.3.2-completed-publication.json @@ -0,0 +1,8 @@ +{ + "product": "liboliphaunt-native", + "version": "0.3.2", + "tagName": "liboliphaunt-native-v0.3.2", + "publicationSha": "31b5803d80ce3884a1fc2d3e9ab869dd733b461c", + "publicationTree": "7355d3958334202a31d02aa3291b480fdd1f02f4", + "releaseSha": "31b5803d80ce3884a1fc2d3e9ab869dd733b461c" +} diff --git a/build_defs/release/native-0.3.2-npm-linux-arm64-gnu-attestations.json b/build_defs/release/native-0.3.2-npm-linux-arm64-gnu-attestations.json new file mode 100644 index 000000000..c1a058db1 --- /dev/null +++ b/build_defs/release/native-0.3.2-npm-linux-arm64-gnu-attestations.json @@ -0,0 +1,139 @@ +{ + "attestations": [ + { + "predicateType": "https://github.com/npm/attestation/tree/main/specs/publish/v0.1", + "bundle": { + "mediaType": "application/vnd.dev.sigstore.bundle+json;version=0.2", + "verificationMaterial": { + "publicKey": { + "hint": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + }, + "tlogEntries": [ + { + "logIndex": "3126898912", + "logId": { + "keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0=" + }, + "kindVersion": { + "kind": "dsse", + "version": "0.0.1" + }, + "integratedTime": "1791360128", + "inclusionPromise": { + "signedEntryTimestamp": "MEQCIEUOPJTGYqTmtZ0wgWYeZVW9BwaaXBhbPcM0nTkZ/btTAiAF2hRMU20s9t1++oQuH+ZyInHqopWbiAaIn3NInOU1xA==" + }, + "inclusionProof": { + "logIndex": "3004994650", + "rootHash": "BDuhN8AWM0qYhiDothj/2SEUUkSRRVNa/xuT5rc7bh8=", + "treeSize": "3004994680", + "hashes": [ + "fu1urr3zDwMJMfyYxW2MFSceiohjIP4JjFlynlN0ec4=", + "FZCX8IWpgG414tusoNgGfzHCIE2Bb+/VU9NA0VERPFE=", + "Fm1g4OxsgPsrGWNMirolt9EM6c0U3Gm8qDa1SNc0A6A=", + "m7lwjJsyCykVpoSv8cGh0oTs2rLcLz7rwqPMIhCRdik=", + "WkrM3gT/lebXhX30LcdzkZYdKNHKicl8hRXTwSJHM9A=", + "EQ+fZhpR52ZPW8/NjjssMg1S0v75XFcJBTmGTgSrx3o=", + "ySuD2IeJE4D7FHdp6tgdp7KA7tdCVzxjLDPwrzY1ZrQ=", + "b7DdV9UYsuqkeC4bYpnQqfEXaG5RDJmh8r5aIHE81M0=", + "bkuVcv0HwGbhqkpY5vnC6AVYWm9bkI2cKmOdhfzsvFw=", + "QMw1k5no3cfipRksAFnA9i95ZICFDiDw0yqS9k67LKA=", + "elLDQ6wVHMFzMoA8Zyuxzk//O77opXchK8l8wrwAEPE=", + "AITQYGvsxlpdAjbZL+ujvmbDH51sR+4T6G8OCFJbtVA=", + "WymSSAFdY3L1BjserJgGo6PUJWiKIc5OHBM+Xxw2adk=", + "3fRFZuDepJD9y0NjNA9nqInlZuCxNImKQJJfr//qImA=", + "x9rXqkSu8+Vm4yqD2XeAwn305JZ4ZykdOwcD90FjP8o=", + "NlOclldmKPA1tMKIskqHAwuQDYHp31YwpK+OOMrMccc=", + "qxzHanAzz57SDdmJe0B7bJK72NTIBbwEMGBBKvDOROw=", + "xH/DCseLHr9eKoYT8qsORZK7zVdEGYWHuVtsVrD95wY=" + ], + "checkpoint": { + "envelope": "rekor.sigstore.dev - 1193050959916656506\n3004994680\nBDuhN8AWM0qYhiDothj/2SEUUkSRRVNa/xuT5rc7bh8=\n\n— rekor.sigstore.dev wNI9ajBFAiEAyGeACAp/OW8doGMXDoD763D7p5lBSpatjSlvmUrSTPkCIBmYtBrbUB76BGcqQuhFVKuMPESdEvYrSjMqZawgh+E0\n" + } + }, + "canonicalizedBody": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiZHNzZSIsInNwZWMiOnsiZW52ZWxvcGVIYXNoIjp7ImFsZ29yaXRobSI6InNoYTI1NiIsInZhbHVlIjoiMzgxZTI2ZGNkYmRhNTRmM2Q4YmM1NzA2MjAyOWNjMDU1MzQ0Mjc1MWMxNTRkNjQ1NjBmMTlhODY1YzU2YjExZSJ9LCJwYXlsb2FkSGFzaCI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6IjNkZTVhNTg0OTk4ZjEwNDM1NjAwM2Q1ODJmMzViNDgwNTc3ZWEzZDY4YzQwNzVlOTFmODExMzQ5MThmNzIwMTAifSwic2lnbmF0dXJlcyI6W3sic2lnbmF0dXJlIjoiTUVVQ0lBUG5ON3AwTjE3b3dNekl4OFhvMkU1WGZNWWJYUUppekd2MUxUNUx2a2R2QWlFQTFaSmc0VmFIWE8xOFBPMVZ0YkpTOEtFOGVIeThqWGpyM3NaYmU3cmV5VjQ9IiwidmVyaWZpZXIiOiJMUzB0TFMxQ1JVZEpUaUJRVlVKTVNVTWdTMFZaTFMwdExTMEtUVVpyZDBWM1dVaExiMXBKZW1vd1EwRlJXVWxMYjFwSmVtb3dSRUZSWTBSUlowRkZXVFpaWVRkWEt5czNZVlZRZW5aTlZISmxla2cyV1dONE0yTXJTQXBQUzFsRFkwNUhlV0pLV2xORFNuRXZabVEzVVdFNGRYVkJTM1JrU1d0VlVYUlJhVVZMUlZKb1FXMUZOV3hOVFVwb1VEaFBhMFJQWVRKblBUMEtMUzB0TFMxRlRrUWdVRlZDVEVsRElFdEZXUzB0TFMwdENnPT0ifV19fQ==" + } + ], + "timestampVerificationData": { + "rfc3161Timestamps": [] + } + }, + "dsseEnvelope": { + "payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInN1YmplY3QiOlt7Im5hbWUiOiJwa2c6bnBtLyU0MG9saXBoYXVudC9saWJvbGlwaGF1bnQtbGludXgtYXJtNjQtZ251QDAuMy4yIiwiZGlnZXN0Ijp7InNoYTUxMiI6IjE4ZjU0MTY3NmEyODQwNmI4NmViY2M3YWNjNDMxYzc2YWI3ZjRkOWYzYTg0NmQ0Njg2YTI1ZTk0MTFiOTk0ZTIyZTZjZGMzMzA3NzAzNmJhYjE5Zjc1N2QzNDNiYmVmODRjYjQ2NTE3YTVmNjQ1Mzg3YWRhN2NjZjlmMGNlNTU1In19XSwicHJlZGljYXRlVHlwZSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9ucG0vYXR0ZXN0YXRpb24vdHJlZS9tYWluL3NwZWNzL3B1Ymxpc2gvdjAuMSIsInByZWRpY2F0ZSI6eyJuYW1lIjoiQG9saXBoYXVudC9saWJvbGlwaGF1bnQtbGludXgtYXJtNjQtZ251IiwidmVyc2lvbiI6IjAuMy4yIiwicmVnaXN0cnkiOiJodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZyJ9fQ==", + "payloadType": "application/vnd.in-toto+json", + "signatures": [ + { + "sig": "MEUCIAPnN7p0N17owMzIx8Xo2E5XfMYbXQJizGv1LT5LvkdvAiEA1ZJg4VaHXO18PO1VtbJS8KE8eHy8jXjr3sZbe7reyV4=", + "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + } + ] + } + } + }, + { + "predicateType": "https://slsa.dev/provenance/v1", + "bundle": { + "mediaType": "application/vnd.dev.sigstore.bundle.v0.3+json", + "verificationMaterial": { + "certificate": { + "rawBytes": "MIIG8zCCBnmgAwIBAgIUQ3TeCx0skbiV5FAqwmMnimT+uNUwCgYIKoZIzj0EAwMwNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwHhcNMjYxMDA3MDc1OTIyWhcNMjYxMDA3MDgwOTIyWjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFz2eHkxugb+Y2+/GGc1c7eNRPwQeLlv0PZruVZ3jqryFigPnSZrqfKHbvjef/ewdiUqpjaGLfl5xRCwU3r5ijqOCBZgwggWUMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAfBgNVHSMEGDAWgBTf0+nPViQRlvmo2OkoVaLGLhhkPzBeBgNVHREBAf8EVDBShlBodHRwczovL2dpdGh1Yi5jb20vZjBycjAvb2xpcGhhdW50Ly5naXRodWIvd29ya2Zsb3dzL3JlbGVhc2UueW1sQHJlZnMvaGVhZHMvbWFpbjA5BgorBgEEAYO/MAEBBCtodHRwczovL3Rva2VuLmFjdGlvbnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tMB8GCisGAQQBg78wAQIEEXdvcmtmbG93X2Rpc3BhdGNoMDYGCisGAQQBg78wAQMEKDMxYjU4MDNkODBjZTM4ODRhMWZjMmQzZTlhYjg2OWRkNzMzYjQ2MWMwFQYKKwYBBAGDvzABBAQHUmVsZWFzZTAdBgorBgEEAYO/MAEFBA9mMHJyMC9vbGlwaGF1bnQwHQYKKwYBBAGDvzABBgQPcmVmcy9oZWFkcy9tYWluMDsGCisGAQQBg78wAQgELQwraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1YnVzZXJjb250ZW50LmNvbTBgBgorBgEEAYO/MAEJBFIMUGh0dHBzOi8vZ2l0aHViLmNvbS9mMHJyMC9vbGlwaGF1bnQvLmdpdGh1Yi93b3JrZmxvd3MvcmVsZWFzZS55bWxAcmVmcy9oZWFkcy9tYWluMDgGCisGAQQBg78wAQoEKgwoMzFiNTgwM2Q4MGNlMzg4NGExZmMyZDNlOWFiODY5ZGQ3MzNiNDYxYzAdBgorBgEEAYO/MAELBA8MDWdpdGh1Yi1ob3N0ZWQwMgYKKwYBBAGDvzABDAQkDCJodHRwczovL2dpdGh1Yi5jb20vZjBycjAvb2xpcGhhdW50MDgGCisGAQQBg78wAQ0EKgwoMzFiNTgwM2Q4MGNlMzg4NGExZmMyZDNlOWFiODY5ZGQ3MzNiNDYxYzAfBgorBgEEAYO/MAEOBBEMD3JlZnMvaGVhZHMvbWFpbjAaBgorBgEEAYO/MAEPBAwMCjEwNjUwNTkxMTQwKAYKKwYBBAGDvzABEAQaDBhodHRwczovL2dpdGh1Yi5jb20vZjBycjAwFwYKKwYBBAGDvzABEQQJDAc4NTc0MjE5MGAGCisGAQQBg78wARIEUgxQaHR0cHM6Ly9naXRodWIuY29tL2YwcnIwL29saXBoYXVudC8uZ2l0aHViL3dvcmtmbG93cy9yZWxlYXNlLnltbEByZWZzL2hlYWRzL21haW4wOAYKKwYBBAGDvzABEwQqDCgzMWI1ODAzZDgwY2UzODg0YTFmYzJkM2U5YWI4NjlkZDczM2I0NjFjMCEGCisGAQQBg78wARQEEwwRd29ya2Zsb3dfZGlzcGF0Y2gwVgYKKwYBBAGDvzABFQRIDEZodHRwczovL2dpdGh1Yi5jb20vZjBycjAvb2xpcGhhdW50L2FjdGlvbnMvcnVucy8zNzU4MzU2OTM0OC9hdHRlbXB0cy8xMBYGCisGAQQBg78wARYECAwGcHVibGljMB8GCisGAQQBg78wARcEEQwPcmVsZWFzZS1wdWJsaXNoMEAGCisGAQQBg78wARgEMgwwcmVwbzpmMHJyMC9vbGlwaGF1bnQ6ZW52aXJvbm1lbnQ6cmVsZWFzZS1wdWJsaXNoMIGKBgorBgEEAdZ5AgQCBHwEegB4AHYA3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4AAAGhFV/OOAAABAMARzBFAiBy8vYPFSmXtfauHPYNxGVT8q2w37FV2e4T+qjD4hfFKgIhAKd9Le53Ci3X6KdWzHlGRS2Dw9V4i0zzutwK55hYoEzeMAoGCCqGSM49BAMDA2gAMGUCMDCvO5C3UcNRuS5SmyXiMvw7j31SxNp822ullYQOoZGtbrmmjqvZFZoXCKf7/FQU8AIxAMnlgyf5MInWOpTa8vDOgsjwXqhChE//zEck3NfvZMiL09dFjj0JUYTuUKF+m7eP0w==" + }, + "tlogEntries": [ + { + "logIndex": "3126861219", + "logId": { + "keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0=" + }, + "kindVersion": { + "kind": "dsse", + "version": "0.0.1" + }, + "integratedTime": "1791359963", + "inclusionPromise": { + "signedEntryTimestamp": "MEUCIQDvowvYwCgbdD1XyvQ/dveMfLjuybV7dr4CXoc80KMP4wIgJGBXySoK+BVPuFaxBc+R1mQthub7Y1zJaGP6U9sKGiA=" + }, + "inclusionProof": { + "logIndex": "3004956957", + "rootHash": "og2N7XfMSBsoBxwLk7S1zrLybt9os7F9Q6wc4+0g8a8=", + "treeSize": "3004956977", + "hashes": [ + "q2aCcOjgi6ry9CNEE/7lsqzGCoxfKTIyVmlDmkGIPg8=", + "FVyiJIzsMD9zRK65ONw2Bh31ru/2vfPkMcV2CDk+VQU=", + "Ur8chUCym/STqYqQh+2TTecgStCjOWpDC8ODRxu4514=", + "S73wr1+nMBj+W4iUK65Hig71K6BoLiGq9e1C3bhGnLk=", + "2ic6jm2n4xwGOTVUoa+eLBMfy7LOfd4qu/XI5UoaEAI=", + "pTCrYbTudBE2OqyLg5aci1zyjiIF9QZlz+dkHTn++nQ=", + "w6s6g3NPZ4q+CSc3XED24f/mSnx1PwUY/j7CMwq7k50=", + "elLDQ6wVHMFzMoA8Zyuxzk//O77opXchK8l8wrwAEPE=", + "AITQYGvsxlpdAjbZL+ujvmbDH51sR+4T6G8OCFJbtVA=", + "WymSSAFdY3L1BjserJgGo6PUJWiKIc5OHBM+Xxw2adk=", + "3fRFZuDepJD9y0NjNA9nqInlZuCxNImKQJJfr//qImA=", + "x9rXqkSu8+Vm4yqD2XeAwn305JZ4ZykdOwcD90FjP8o=", + "NlOclldmKPA1tMKIskqHAwuQDYHp31YwpK+OOMrMccc=", + "qxzHanAzz57SDdmJe0B7bJK72NTIBbwEMGBBKvDOROw=", + "xH/DCseLHr9eKoYT8qsORZK7zVdEGYWHuVtsVrD95wY=" + ], + "checkpoint": { + "envelope": "rekor.sigstore.dev - 1193050959916656506\n3004956977\nog2N7XfMSBsoBxwLk7S1zrLybt9os7F9Q6wc4+0g8a8=\n\n— rekor.sigstore.dev wNI9ajBEAiAQN1KiU3YxCbD3qnO6s8n8u+MJ2p4o+JnIxtK9+dNSaQIgI68IU5T3UWQicQBt+f769r0PuvkkAG47zrAYACVnGxU=\n" + } + }, + "canonicalizedBody": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiZHNzZSIsInNwZWMiOnsiZW52ZWxvcGVIYXNoIjp7ImFsZ29yaXRobSI6InNoYTI1NiIsInZhbHVlIjoiMjQ4MDM1ZjM0YjdiZWUyZWEwY2IwOTM4Yjc3NzIxNzJiOWU4ZDVjZjljNjIyNTY0MDk0NWNmMTAyNjdlNjdmYiJ9LCJwYXlsb2FkSGFzaCI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6Ijk5YzUyOWY5YzY0OTI4MDYwNDZhM2FlYzViYTZkNzdmM2Q5MGEwYTU0ZDVlZTc2NGFiYjdlNDRlMTliMWE4YTQifSwic2lnbmF0dXJlcyI6W3sic2lnbmF0dXJlIjoiTUVZQ0lRRDFBRXBMSWRIZ1NrZ0JvT2o0Ykg3TmkrVUlQNnFQS1dmMzRwWVhXRUFJQ2dJaEFPVkFPcE4yR0Y2ZTRPUFVNbkY3QTMxY2crMHo4K2toZjYyVTdOOFpjYUk4IiwidmVyaWZpZXIiOiJMUzB0TFMxQ1JVZEpUaUJEUlZKVVNVWkpRMEZVUlMwdExTMHRDazFKU1VjNGVrTkRRbTV0WjBGM1NVSkJaMGxWVVROVVpVTjRNSE5yWW1sV05VWkJjWGR0VFc1cGJWUXJkVTVWZDBObldVbExiMXBKZW1vd1JVRjNUWGNLVG5wRlZrMUNUVWRCTVZWRlEyaE5UV015Ykc1ak0xSjJZMjFWZFZwSFZqSk5ValIzU0VGWlJGWlJVVVJGZUZaNllWZGtlbVJIT1hsYVV6RndZbTVTYkFwamJURnNXa2RzYUdSSFZYZElhR05PVFdwWmVFMUVRVE5OUkdNeFQxUkplVmRvWTA1TmFsbDRUVVJCTTAxRVozZFBWRWw1VjJwQlFVMUdhM2RGZDFsSUNrdHZXa2w2YWpCRFFWRlpTVXR2V2tsNmFqQkVRVkZqUkZGblFVVkdlakpsU0d0NGRXZGlLMWt5S3k5SFIyTXhZemRsVGxKUWQxRmxUR3gyTUZCYWNuVUtWbG96YW5GeWVVWnBaMUJ1VTFweWNXWkxTR0oyYW1WbUwyVjNaR2xWY1hCcVlVZE1abXcxZUZKRGQxVXpjalZwYW5GUFEwSmFaM2RuWjFkVlRVRTBSd3BCTVZWa1JIZEZRaTkzVVVWQmQwbElaMFJCVkVKblRsWklVMVZGUkVSQlMwSm5aM0pDWjBWR1FsRmpSRUY2UVdaQ1owNVdTRk5OUlVkRVFWZG5RbFJtQ2pBcmJsQldhVkZTYkhadGJ6SlBhMjlXWVV4SFRHaG9hMUI2UW1WQ1owNVdTRkpGUWtGbU9FVldSRUpUYUd4Q2IyUklVbmRqZW05MlRESmtjR1JIYURFS1dXazFhbUl5TUhaYWFrSjVZMnBCZG1JeWVIQmpSMmhvWkZjMU1FeDVOVzVoV0ZKdlpGZEpkbVF5T1hsaE1scHpZak5rZWt3elNteGlSMVpvWXpKVmRRcGxWekZ6VVVoS2JGcHVUWFpoUjFab1draE5kbUpYUm5CaWFrRTFRbWR2Y2tKblJVVkJXVTh2VFVGRlFrSkRkRzlrU0ZKM1kzcHZka3d6VW5aaE1sWjFDa3h0Um1wa1IyeDJZbTVOZFZveWJEQmhTRlpwWkZoT2JHTnRUblppYmxKc1ltNVJkVmt5T1hSTlFqaEhRMmx6UjBGUlVVSm5OemgzUVZGSlJVVllaSFlLWTIxMGJXSkhPVE5ZTWxKd1l6TkNhR1JIVG05TlJGbEhRMmx6UjBGUlVVSm5OemgzUVZGTlJVdEVUWGhaYWxVMFRVUk9hMDlFUW1wYVZFMDBUMFJTYUFwTlYxcHFUVzFSZWxwVWJHaFphbWN5VDFkU2EwNTZUWHBaYWxFeVRWZE5kMFpSV1V0TGQxbENRa0ZIUkhaNlFVSkNRVkZJVlcxV2MxcFhSbnBhVkVGa0NrSm5iM0pDWjBWRlFWbFBMMDFCUlVaQ1FUbHRUVWhLZVUxRE9YWmlSMngzWVVkR01XSnVVWGRJVVZsTFMzZFpRa0pCUjBSMmVrRkNRbWRSVUdOdFZtMEtZM2s1YjFwWFJtdGplVGwwV1Zkc2RVMUVjMGREYVhOSFFWRlJRbWMzT0hkQlVXZEZURkYzY21GSVVqQmpTRTAyVEhrNU1HSXlkR3hpYVRWb1dUTlNjQXBpTWpWNlRHMWtjR1JIYURGWmJsWjZXbGhLYW1JeU5UQmFWelV3VEcxT2RtSlVRbWRDWjI5eVFtZEZSVUZaVHk5TlFVVktRa1pKVFZWSGFEQmtTRUo2Q2s5cE9IWmFNbXd3WVVoV2FVeHRUblppVXpsdFRVaEtlVTFET1haaVIyeDNZVWRHTVdKdVVYWk1iV1J3WkVkb01WbHBPVE5pTTBweVdtMTRkbVF6VFhZS1kyMVdjMXBYUm5wYVV6VTFZbGQ0UVdOdFZtMWplVGx2V2xkR2EyTjVPWFJaVjJ4MVRVUm5SME5wYzBkQlVWRkNaemM0ZDBGUmIwVkxaM2R2VFhwR2FRcE9WR2QzVFRKUk5FMUhUbXhOZW1jMFRrZEZlRnB0VFhsYVJFNXNUMWRHYVU5RVdUVmFSMUV6VFhwT2FVNUVXWGhaZWtGa1FtZHZja0puUlVWQldVOHZDazFCUlV4Q1FUaE5SRmRrY0dSSGFERlphVEZ2WWpOT01GcFhVWGROWjFsTFMzZFpRa0pCUjBSMmVrRkNSRUZSYTBSRFNtOWtTRkozWTNwdmRrd3laSEFLWkVkb01WbHBOV3BpTWpCMldtcENlV05xUVhaaU1uaHdZMGRvYUdSWE5UQk5SR2RIUTJselIwRlJVVUpuTnpoM1FWRXdSVXRuZDI5TmVrWnBUbFJuZHdwTk1sRTBUVWRPYkUxNlp6Uk9SMFY0V20xTmVWcEVUbXhQVjBacFQwUlpOVnBIVVROTmVrNXBUa1JaZUZsNlFXWkNaMjl5UW1kRlJVRlpUeTlOUVVWUENrSkNSVTFFTTBwc1dtNU5kbUZIVm1oYVNFMTJZbGRHY0dKcVFXRkNaMjl5UW1kRlJVRlpUeTlOUVVWUVFrRjNUVU5xUlhkT2FsVjNUbFJyZUUxVVVYY0tTMEZaUzB0M1dVSkNRVWRFZG5wQlFrVkJVV0ZFUW1odlpFaFNkMk42YjNaTU1tUndaRWRvTVZscE5XcGlNakIyV21wQ2VXTnFRWGRHZDFsTFMzZFpRZ3BDUVVkRWRucEJRa1ZSVVVwRVFXTTBUbFJqTUUxcVJUVk5SMEZIUTJselIwRlJVVUpuTnpoM1FWSkpSVlZuZUZGaFNGSXdZMGhOTmt4NU9XNWhXRkp2Q21SWFNYVlpNamwwVERKWmQyTnVTWGRNTWpsellWaENiMWxZVm5Wa1F6aDFXakpzTUdGSVZtbE1NMlIyWTIxMGJXSkhPVE5qZVRsNVdsZDRiRmxZVG13S1RHNXNkR0pGUW5sYVYxcDZUREpvYkZsWFVucE1NakZvWVZjMGQwOUJXVXRMZDFsQ1FrRkhSSFo2UVVKRmQxRnhSRU5uZWsxWFNURlBSRUY2V2tSbmR3cFpNbFY2VDBSbk1GbFVSbTFaZWtwclRUSlZOVmxYU1RST2FteHJXa1JqZWsweVNUQk9ha1pxVFVORlIwTnBjMGRCVVZGQ1p6YzRkMEZTVVVWRmQzZFNDbVF5T1hsaE1scHpZak5rWmxwSGJIcGpSMFl3V1RKbmQxWm5XVXRMZDFsQ1FrRkhSSFo2UVVKR1VWSkpSRVZhYjJSSVVuZGplbTkyVERKa2NHUkhhREVLV1drMWFtSXlNSFphYWtKNVkycEJkbUl5ZUhCalIyaG9aRmMxTUV3eVJtcGtSMngyWW01TmRtTnVWblZqZVRoNlRucFZORTE2VlRKUFZFMHdUME01YUFwa1NGSnNZbGhDTUdONU9IaE5RbGxIUTJselIwRlJVVUpuTnpoM1FWSlpSVU5CZDBkalNGWnBZa2RzYWsxQ09FZERhWE5IUVZGUlFtYzNPSGRCVW1ORkNrVlJkMUJqYlZaeldsZEdlbHBUTVhka1YwcHpZVmhPYjAxRlFVZERhWE5IUVZGUlFtYzNPSGRCVW1kRlRXZDNkMk50Vm5kaWVuQnRUVWhLZVUxRE9YWUtZa2RzZDJGSFJqRmlibEUyV2xjMU1tRllTblppYlRGc1ltNVJObU50Vm5OYVYwWjZXbE14ZDJSWFNuTmhXRTV2VFVsSFMwSm5iM0pDWjBWRlFXUmFOUXBCWjFGRFFraDNSV1ZuUWpSQlNGbEJNMVF3ZDJGellraEZWRXBxUjFJMFkyMVhZek5CY1VwTFdISnFaVkJMTXk5b05IQjVaME00Y0Rkdk5FRkJRVWRvQ2taV0wwOVBRVUZCUWtGTlFWSjZRa1pCYVVKNU9IWlpVRVpUYlZoMFptRjFTRkJaVG5oSFZsUTRjVEozTXpkR1ZqSmxORlFyY1dwRU5HaG1Sa3RuU1dnS1FVdGtPVXhsTlRORGFUTllOa3RrVjNwSWJFZFNVekpFZHpsV05Ha3dlbnAxZEhkTE5UVm9XVzlGZW1WTlFXOUhRME54UjFOTk5EbENRVTFFUVRKblFRcE5SMVZEVFVSRGRrODFRek5WWTA1U2RWTTFVMjE1V0dsTmRuYzNhak14VTNoT2NEZ3lNblZzYkZsUlQyOWFSM1JpY20xdGFuRjJXa1phYjFoRFMyWTNDaTlHVVZVNFFVbDRRVTF1YkdkNVpqVk5TVzVYVDNCVVlUaDJSRTluYzJwM1dIRm9RMmhGTHk5NlJXTnJNMDVtZGxwTmFVd3dPV1JHYW1vd1NsVlpWSFVLVlV0R0syMDNaVkF3ZHowOUNpMHRMUzB0UlU1RUlFTkZVbFJKUmtsRFFWUkZMUzB0TFMwSyJ9XX19" + } + ], + "timestampVerificationData": { + "rfc3161Timestamps": [] + } + }, + "dsseEnvelope": { + "payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoicGtnOm5wbS8lNDBvbGlwaGF1bnQvbGlib2xpcGhhdW50LWxpbnV4LWFybTY0LWdudUAwLjMuMiIsImRpZ2VzdCI6eyJzaGE1MTIiOiIxOGY1NDE2NzZhMjg0MDZiODZlYmNjN2FjYzQzMWM3NmFiN2Y0ZDlmM2E4NDZkNDY4NmEyNWU5NDExYjk5NGUyMmU2Y2RjMzMwNzcwMzZiYWIxOWY3NTdkMzQzYmJlZjg0Y2I0NjUxN2E1ZjY0NTM4N2FkYTdjY2Y5ZjBjZTU1NSJ9fV0sInByZWRpY2F0ZVR5cGUiOiJodHRwczovL3Nsc2EuZGV2L3Byb3ZlbmFuY2UvdjEiLCJwcmVkaWNhdGUiOnsiYnVpbGREZWZpbml0aW9uIjp7ImJ1aWxkVHlwZSI6Imh0dHBzOi8vc2xzYS1mcmFtZXdvcmsuZ2l0aHViLmlvL2dpdGh1Yi1hY3Rpb25zLWJ1aWxkdHlwZXMvd29ya2Zsb3cvdjEiLCJleHRlcm5hbFBhcmFtZXRlcnMiOnsid29ya2Zsb3ciOnsicmVmIjoicmVmcy9oZWFkcy9tYWluIiwicmVwb3NpdG9yeSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9mMHJyMC9vbGlwaGF1bnQiLCJwYXRoIjoiLmdpdGh1Yi93b3JrZmxvd3MvcmVsZWFzZS55bWwifX0sImludGVybmFsUGFyYW1ldGVycyI6eyJnaXRodWIiOnsiZXZlbnRfbmFtZSI6IndvcmtmbG93X2Rpc3BhdGNoIiwicmVwb3NpdG9yeV9pZCI6IjEwNjUwNTkxMTQiLCJyZXBvc2l0b3J5X293bmVyX2lkIjoiODU3NDIxOSJ9fSwicmVzb2x2ZWREZXBlbmRlbmNpZXMiOlt7InVyaSI6ImdpdCtodHRwczovL2dpdGh1Yi5jb20vZjBycjAvb2xpcGhhdW50QHJlZnMvaGVhZHMvbWFpbiIsImRpZ2VzdCI6eyJnaXRDb21taXQiOiIzMWI1ODAzZDgwY2UzODg0YTFmYzJkM2U5YWI4NjlkZDczM2I0NjFjIn19XX0sInJ1bkRldGFpbHMiOnsiYnVpbGRlciI6eyJpZCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL3J1bm5lci9naXRodWItaG9zdGVkIn0sIm1ldGFkYXRhIjp7Imludm9jYXRpb25JZCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9mMHJyMC9vbGlwaGF1bnQvYWN0aW9ucy9ydW5zLzM3NTgzNTY5MzQ4L2F0dGVtcHRzLzEifX19fQ==", + "payloadType": "application/vnd.in-toto+json", + "signatures": [ + { + "sig": "MEYCIQD1AEpLIdHgSkgBoOj4bH7Ni+UIP6qPKWf34pYXWEAICgIhAOVAOpN2GF6e4OPUMnF7A31cg+0z8+khf62U7N8ZcaI8", + "keyid": "" + } + ] + } + } + } + ] +} diff --git a/build_defs/release/native-0.3.2-npm-linux-arm64-gnu.json b/build_defs/release/native-0.3.2-npm-linux-arm64-gnu.json new file mode 100644 index 000000000..1d1b07bc5 --- /dev/null +++ b/build_defs/release/native-0.3.2-npm-linux-arm64-gnu.json @@ -0,0 +1,92 @@ +{ + "os": [ + "linux" + ], + "cpu": [ + "arm64" + ], + "bugs": { + "url": "https://github.com/f0rr0/oliphaunt/issues" + }, + "dist": { + "shasum": "8c22c16e615f7cfc09710c3dbb94348a2560fa4d", + "tarball": "https://registry.npmjs.org/@oliphaunt/liboliphaunt-linux-arm64-gnu/-/liboliphaunt-linux-arm64-gnu-0.3.2.tgz", + "fileCount": 737, + "integrity": "sha512-GPVBZ2ooQGuG68x6zEMcdqt/TZ86hG1GhqJelBG5lOIubNwzB3A2urGfdX00O774TLRlF6X2RTh62nzPnwzlVQ==", + "signatures": [ + { + "sig": "MEUCIHyLF5v5TZOMhrLslUMkMyJy17i8bKGTz5Ym/y4FpHG+AiEA24a+pNOe0oSBB/uA59WH6naayWdqE2twF+ECwkc5KRI=", + "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + }, + { + "sig": "MEQCIBhVoj9hdmDjd8xn16Q/IfNmRVY11ZU8psMpWalOoVAlAiBqe0FkSIgRJ3yQDnnvgCbeetd6A/Y41MT+QDYOh3+mcw==", + "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + } + ], + "attestations": { + "url": "https://registry.npmjs.org/-/npm/v1/attestations/@oliphaunt%2fliboliphaunt-linux-arm64-gnu@0.3.2", + "provenance": { + "predicateType": "https://slsa.dev/provenance/v1" + } + }, + "unpackedSize": 35627262 + }, + "libc": [ + "glibc" + ], + "name": "@oliphaunt/liboliphaunt-linux-arm64-gnu", + "type": "module", + "_from": "file:/home/runner/work/oliphaunt/oliphaunt/target/release/npm-packages/oliphaunt-liboliphaunt-linux-arm64-gnu/oliphaunt-liboliphaunt-linux-arm64-gnu-0.3.2.tgz", + "exports": { + "./package.json": "./package.json" + }, + "license": "MIT AND PostgreSQL AND Unicode-3.0", + "_npmUser": { + "name": "GitHub Actions", + "email": "npm-oidc-no-reply@github.com", + "trustedPublisher": { + "id": "github", + "oidcConfigId": "c2d7cdab-29ec-4775-83a4-4aac086164c4" + } + }, + "homepage": "https://github.com/f0rr0/oliphaunt#readme", + "optional": true, + "_resolved": "/home/runner/work/oliphaunt/oliphaunt/target/release/npm-packages/oliphaunt-liboliphaunt-linux-arm64-gnu/oliphaunt-liboliphaunt-linux-arm64-gnu-0.3.2.tgz", + "oliphaunt": { + "target": "linux-arm64-gnu", + "libraryRelativePath": "lib/liboliphaunt.so", + "runtimeRelativePath": "runtime" + }, + "_integrity": "sha512-GPVBZ2ooQGuG68x6zEMcdqt/TZ86hG1GhqJelBG5lOIubNwzB3A2urGfdX00O774TLRlF6X2RTh62nzPnwzlVQ==", + "repository": { + "url": "git+https://github.com/f0rr0/oliphaunt.git", + "type": "git", + "directory": "src/native/runtime/packages/linux-arm64-gnu" + }, + "_npmVersion": "11.18.0", + "description": "Linux arm64 glibc liboliphaunt native library for Oliphaunt.", + "directories": {}, + "maintainers": [ + { + "name": "oliphaunt", + "email": "sids.outlook.email@gmail.com" + } + ], + "_nodeVersion": "22.22.3", + "publishConfig": { + "access": "public", + "provenance": true, + "executableFiles": [ + "./runtime/bin/initdb", + "./runtime/bin/pg_ctl", + "./runtime/bin/postgres" + ] + }, + "_hasShrinkwrap": false, + "_npmOperationalInternal": { + "tmp": "tmp/liboliphaunt-linux-arm64-gnu_0.3.2_1791360126498_0.23137709262715256", + "host": "s3://npm-registry-packages-npm-production" + }, + "_id": "@oliphaunt/liboliphaunt-linux-arm64-gnu@0.3.2", + "version": "0.3.2" +} diff --git a/build_defs/release/native-0.3.2-npm-linux-x64-gnu-attestations.json b/build_defs/release/native-0.3.2-npm-linux-x64-gnu-attestations.json new file mode 100644 index 000000000..fb1a46062 --- /dev/null +++ b/build_defs/release/native-0.3.2-npm-linux-x64-gnu-attestations.json @@ -0,0 +1,145 @@ +{ + "attestations": [ + { + "predicateType": "https://github.com/npm/attestation/tree/main/specs/publish/v0.1", + "bundle": { + "mediaType": "application/vnd.dev.sigstore.bundle+json;version=0.2", + "verificationMaterial": { + "publicKey": { + "hint": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + }, + "tlogEntries": [ + { + "logIndex": "3126953490", + "logId": { + "keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0=" + }, + "kindVersion": { + "kind": "dsse", + "version": "0.0.1" + }, + "integratedTime": "1791360398", + "inclusionPromise": { + "signedEntryTimestamp": "MEUCIQDSYt4I+KeFw8UtB3wjfzbaGewb6TFVBGH0uqv5H798TwIgSssc34DAgw7z2PST4E59eHpWWRt7j2Or/C1ghwHQOLo=" + }, + "inclusionProof": { + "logIndex": "3005049228", + "rootHash": "ZNZa1gd+i1ThwDvgp/4jjPiR8trdU5I3BGV85NKVNlY=", + "treeSize": "3005049242", + "hashes": [ + "p0hcXR4yYCtAB/rEy862txHHQridteBE6QGT3+VHkaE=", + "H2iPAoSWawrPLjMnmYJ09HXqYnozUP4kURXYtUGdaIw=", + "Mohj0gCh+dDvaLlTJZ85gnfpSgV4OqFfinBYK6mdvjQ=", + "chWxglgVEgZjZVHkghjN7CfcIRbwuFijE9OGS+JgdDM=", + "0nJB4Dbnq5Xi/a/Cv+vXj52B2xzuet3wJSM0yCwIij4=", + "+g+GHywpwVuoYYotVzMn/LvLVL5EF71ImiSuoJTFu9g=", + "rvM95NakRutNspaj8HxAER/0OwwZStAV3uOgPYOuUV8=", + "Zg08aq832NjpZAp9mS2oNNOM8687dWxsKvGM6d5F0L4=", + "KHdd8M7bgCVGHfT4D14C+HfLDXHgvqpLfO4cVzNkTmE=", + "3MNgc+JUINhpQJAbwAoxYccj2ouSmbLMjmGe3DWdbHM=", + "FKI1jW8r0x7ZbsMu5lfC/wN3oR0zNs11XCe2J3wt4eM=", + "elLDQ6wVHMFzMoA8Zyuxzk//O77opXchK8l8wrwAEPE=", + "AITQYGvsxlpdAjbZL+ujvmbDH51sR+4T6G8OCFJbtVA=", + "WymSSAFdY3L1BjserJgGo6PUJWiKIc5OHBM+Xxw2adk=", + "3fRFZuDepJD9y0NjNA9nqInlZuCxNImKQJJfr//qImA=", + "x9rXqkSu8+Vm4yqD2XeAwn305JZ4ZykdOwcD90FjP8o=", + "NlOclldmKPA1tMKIskqHAwuQDYHp31YwpK+OOMrMccc=", + "qxzHanAzz57SDdmJe0B7bJK72NTIBbwEMGBBKvDOROw=", + "xH/DCseLHr9eKoYT8qsORZK7zVdEGYWHuVtsVrD95wY=" + ], + "checkpoint": { + "envelope": "rekor.sigstore.dev - 1193050959916656506\n3005049242\nZNZa1gd+i1ThwDvgp/4jjPiR8trdU5I3BGV85NKVNlY=\n\n— rekor.sigstore.dev wNI9ajBFAiA8Z11ynupVvVQZWw3wcSz/KYo2D5GlyF+fOdI8l6liUwIhAP55BOIZpJCQ7XyfIToRa/QOm1pM76U00nUWk78AF3T7\n" + } + }, + "canonicalizedBody": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiZHNzZSIsInNwZWMiOnsiZW52ZWxvcGVIYXNoIjp7ImFsZ29yaXRobSI6InNoYTI1NiIsInZhbHVlIjoiNzMzMzk2ZGU3N2E4NWEyYjc2OGFjMWRlMDgyZWMxMzdlOWU2NTIwYmY3ZjFiMDRlOGFiZjA0MWE4YWFhMTFhMSJ9LCJwYXlsb2FkSGFzaCI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6IjFlNDY0NzMxYTY5MzY5MzcyYmEzMDRkY2YxNGNkNDEyNTY3MWU5NmI5NTRmNDhlMmExOGQzMTBlYTE2NjMwMTUifSwic2lnbmF0dXJlcyI6W3sic2lnbmF0dXJlIjoiTUVZQ0lRRHBsUXFJUWFOb0xSMjcxbDNFd2kzSEt2QnBQQjBUa25RbWZ2SWZTVlRqZlFJaEFNUHg2a2REVDV4SGVDVi9vcjJwWThCUC93UWdNWkR1OXFYY0tIMmJ3bjNtIiwidmVyaWZpZXIiOiJMUzB0TFMxQ1JVZEpUaUJRVlVKTVNVTWdTMFZaTFMwdExTMEtUVVpyZDBWM1dVaExiMXBKZW1vd1EwRlJXVWxMYjFwSmVtb3dSRUZSWTBSUlowRkZXVFpaWVRkWEt5czNZVlZRZW5aTlZISmxla2cyV1dONE0yTXJTQXBQUzFsRFkwNUhlV0pLV2xORFNuRXZabVEzVVdFNGRYVkJTM1JrU1d0VlVYUlJhVVZMUlZKb1FXMUZOV3hOVFVwb1VEaFBhMFJQWVRKblBUMEtMUzB0TFMxRlRrUWdVRlZDVEVsRElFdEZXUzB0TFMwdENnPT0ifV19fQ==" + } + ], + "timestampVerificationData": { + "rfc3161Timestamps": [] + } + }, + "dsseEnvelope": { + "payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInN1YmplY3QiOlt7Im5hbWUiOiJwa2c6bnBtLyU0MG9saXBoYXVudC9saWJvbGlwaGF1bnQtbGludXgteDY0LWdudUAwLjMuMiIsImRpZ2VzdCI6eyJzaGE1MTIiOiI0YTBiZmFkZDRmMzMwODg0ODUwODI2MTY2MWI1YTY0YTQ0MDUzNzI0Mjk1YWY4YzkzZDIwZTAxOTc3ZWU3MGJiMmFiOWVlMTgyZGU5ZTM1ZWJlM2Q5Yzg4YzBlNjI0OTc5OTdkZmZiMGZiNTFjM2VhNGZlNDgwNjBkMWM1MzNhZiJ9fV0sInByZWRpY2F0ZVR5cGUiOiJodHRwczovL2dpdGh1Yi5jb20vbnBtL2F0dGVzdGF0aW9uL3RyZWUvbWFpbi9zcGVjcy9wdWJsaXNoL3YwLjEiLCJwcmVkaWNhdGUiOnsibmFtZSI6IkBvbGlwaGF1bnQvbGlib2xpcGhhdW50LWxpbnV4LXg2NC1nbnUiLCJ2ZXJzaW9uIjoiMC4zLjIiLCJyZWdpc3RyeSI6Imh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnIn19", + "payloadType": "application/vnd.in-toto+json", + "signatures": [ + { + "sig": "MEYCIQDplQqIQaNoLR271l3Ewi3HKvBpPB0TknQmfvIfSVTjfQIhAMPx6kdDT5xHeCV/or2pY8BP/wQgMZDu9qXcKH2bwn3m", + "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + } + ] + } + } + }, + { + "predicateType": "https://slsa.dev/provenance/v1", + "bundle": { + "mediaType": "application/vnd.dev.sigstore.bundle.v0.3+json", + "verificationMaterial": { + "certificate": { + "rawBytes": "MIIG9DCCBnqgAwIBAgIUITLg4iYWVRqP/b4fQX8RHXrHuDowCgYIKoZIzj0EAwMwNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwHhcNMjYxMDA3MDgwMjE1WhcNMjYxMDA3MDgxMjE1WjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEg4H3mNjY6aY2C1ECNDYN4naQzmUaLFRSiaygXihNlQEUzkVgx1x/I0qR9LT++hCMNMgqeBJiYkoSLIXIv9zPpqOCBZkwggWVMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAfBgNVHSMEGDAWgBTf0+nPViQRlvmo2OkoVaLGLhhkPzBeBgNVHREBAf8EVDBShlBodHRwczovL2dpdGh1Yi5jb20vZjBycjAvb2xpcGhhdW50Ly5naXRodWIvd29ya2Zsb3dzL3JlbGVhc2UueW1sQHJlZnMvaGVhZHMvbWFpbjA5BgorBgEEAYO/MAEBBCtodHRwczovL3Rva2VuLmFjdGlvbnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tMB8GCisGAQQBg78wAQIEEXdvcmtmbG93X2Rpc3BhdGNoMDYGCisGAQQBg78wAQMEKDMxYjU4MDNkODBjZTM4ODRhMWZjMmQzZTlhYjg2OWRkNzMzYjQ2MWMwFQYKKwYBBAGDvzABBAQHUmVsZWFzZTAdBgorBgEEAYO/MAEFBA9mMHJyMC9vbGlwaGF1bnQwHQYKKwYBBAGDvzABBgQPcmVmcy9oZWFkcy9tYWluMDsGCisGAQQBg78wAQgELQwraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1YnVzZXJjb250ZW50LmNvbTBgBgorBgEEAYO/MAEJBFIMUGh0dHBzOi8vZ2l0aHViLmNvbS9mMHJyMC9vbGlwaGF1bnQvLmdpdGh1Yi93b3JrZmxvd3MvcmVsZWFzZS55bWxAcmVmcy9oZWFkcy9tYWluMDgGCisGAQQBg78wAQoEKgwoMzFiNTgwM2Q4MGNlMzg4NGExZmMyZDNlOWFiODY5ZGQ3MzNiNDYxYzAdBgorBgEEAYO/MAELBA8MDWdpdGh1Yi1ob3N0ZWQwMgYKKwYBBAGDvzABDAQkDCJodHRwczovL2dpdGh1Yi5jb20vZjBycjAvb2xpcGhhdW50MDgGCisGAQQBg78wAQ0EKgwoMzFiNTgwM2Q4MGNlMzg4NGExZmMyZDNlOWFiODY5ZGQ3MzNiNDYxYzAfBgorBgEEAYO/MAEOBBEMD3JlZnMvaGVhZHMvbWFpbjAaBgorBgEEAYO/MAEPBAwMCjEwNjUwNTkxMTQwKAYKKwYBBAGDvzABEAQaDBhodHRwczovL2dpdGh1Yi5jb20vZjBycjAwFwYKKwYBBAGDvzABEQQJDAc4NTc0MjE5MGAGCisGAQQBg78wARIEUgxQaHR0cHM6Ly9naXRodWIuY29tL2YwcnIwL29saXBoYXVudC8uZ2l0aHViL3dvcmtmbG93cy9yZWxlYXNlLnltbEByZWZzL2hlYWRzL21haW4wOAYKKwYBBAGDvzABEwQqDCgzMWI1ODAzZDgwY2UzODg0YTFmYzJkM2U5YWI4NjlkZDczM2I0NjFjMCEGCisGAQQBg78wARQEEwwRd29ya2Zsb3dfZGlzcGF0Y2gwVgYKKwYBBAGDvzABFQRIDEZodHRwczovL2dpdGh1Yi5jb20vZjBycjAvb2xpcGhhdW50L2FjdGlvbnMvcnVucy8zNzU4MzU2OTM0OC9hdHRlbXB0cy8xMBYGCisGAQQBg78wARYECAwGcHVibGljMB8GCisGAQQBg78wARcEEQwPcmVsZWFzZS1wdWJsaXNoMEAGCisGAQQBg78wARgEMgwwcmVwbzpmMHJyMC9vbGlwaGF1bnQ6ZW52aXJvbm1lbnQ6cmVsZWFzZS1wdWJsaXNoMIGLBgorBgEEAdZ5AgQCBH0EewB5AHcA3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4AAAGhFWJx6gAABAMASDBGAiEA5qYFO8LC5Zmda6T4HI5LnY8vbrQeT2ySO0G7dgRcfhwCIQCn4L3D2EOwtZxALTkIpAM1prm4wsZz+QidTvJwxr2ZejAKBggqhkjOPQQDAwNoADBlAjB/YD/c1YPNkzdi8mXWGBVxMxh9H/fZbgXSFGxNJCKKdlj9cdok4JF17SvlwhsB61ACMQDdeM41XXBeB9FtLWWQlIJFVNLIePk66IOwfzs+ou0ZFuqt6g6xfzpTlxhg8SLVTf4=" + }, + "tlogEntries": [ + { + "logIndex": "3126900206", + "logId": { + "keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0=" + }, + "kindVersion": { + "kind": "dsse", + "version": "0.0.1" + }, + "integratedTime": "1791360136", + "inclusionPromise": { + "signedEntryTimestamp": "MEYCIQC7A28bbY3jK2iNdms7fbd+oPY/Xe32hmWZI3j//KGJ7wIhAILvmHS6xz/HQA0yIWQYvOZEtBkBOVSwemUGbeJmdyC6" + }, + "inclusionProof": { + "logIndex": "3004995944", + "rootHash": "xrG1hGmwaQm2eV8r5B1IoEbWMS6wpx0qsIEwyPiP+DU=", + "treeSize": "3004995969", + "hashes": [ + "LMwqHZ1wpaTUQmw1voh2/tXdgEGo9l0QCmCws12u4es=", + "wV+SGS0ujDnaHdJVZ6cROnkKeQij99Bkm4XYy2tmvhs=", + "BXXvmv/5mAWRTE/paq+pDvEi3T/f4Tir+bbC0sneQPY=", + "x8qJp3imnWMpdd/G7i0OZCGu15LmttFgQ/0GXT0vPi8=", + "iRUOi/Gf8sn7GLt/X5syQfwIiCgK2mMXvVVrAuRuz4M=", + "pCa7U/RDove7dVbCrhGV2E7TzF9wlifAHRgtauTPVv4=", + "tvRiGNTbfM9Qt2ce1xExU9kD3BJNslfrb7Gf0jHlWHQ=", + "IdB9bE9vO67EKzJDAUIDrf4hBfl6NTmn78jPaMGYdig=", + "WbDw8fc1Yka9+Pzhj9LO253e8+Hs8RHfNniWJ/ccvcU=", + "98tDgcPyTK/Oe/w2dy1M25R6CQMmwbtJRQUtALvbJ3w=", + "bkuVcv0HwGbhqkpY5vnC6AVYWm9bkI2cKmOdhfzsvFw=", + "QMw1k5no3cfipRksAFnA9i95ZICFDiDw0yqS9k67LKA=", + "elLDQ6wVHMFzMoA8Zyuxzk//O77opXchK8l8wrwAEPE=", + "AITQYGvsxlpdAjbZL+ujvmbDH51sR+4T6G8OCFJbtVA=", + "WymSSAFdY3L1BjserJgGo6PUJWiKIc5OHBM+Xxw2adk=", + "3fRFZuDepJD9y0NjNA9nqInlZuCxNImKQJJfr//qImA=", + "x9rXqkSu8+Vm4yqD2XeAwn305JZ4ZykdOwcD90FjP8o=", + "NlOclldmKPA1tMKIskqHAwuQDYHp31YwpK+OOMrMccc=", + "qxzHanAzz57SDdmJe0B7bJK72NTIBbwEMGBBKvDOROw=", + "xH/DCseLHr9eKoYT8qsORZK7zVdEGYWHuVtsVrD95wY=" + ], + "checkpoint": { + "envelope": "rekor.sigstore.dev - 1193050959916656506\n3004995969\nxrG1hGmwaQm2eV8r5B1IoEbWMS6wpx0qsIEwyPiP+DU=\n\n— rekor.sigstore.dev wNI9ajBEAiAt9844HqvHdJPQc9KEn9h7OW0ww0HQFQv1sl+InDfqlwIgIHaGDUw8IBwlwBkEq2wpF4F5QoUU4FpRZoKLJXDFfog=\n" + } + }, + "canonicalizedBody": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiZHNzZSIsInNwZWMiOnsiZW52ZWxvcGVIYXNoIjp7ImFsZ29yaXRobSI6InNoYTI1NiIsInZhbHVlIjoiNTI5N2M5MzE4YjE2YWRlZjczOTdiYTdmY2RiOTM4ZWYxM2ViMDNlMWIxNGE2OWZlYWQ0Y2Y5ZWNlNGQ3NDg5MSJ9LCJwYXlsb2FkSGFzaCI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6IjlhMmFlNzhmZGNhY2IxMjk3NmY0OTJjODcwNzI3OTIyMjEzMzRjMTg1NzI5YWIxYmU5MWE3ZGI4NmMwMzRhYjgifSwic2lnbmF0dXJlcyI6W3sic2lnbmF0dXJlIjoiTUVVQ0lFWGdTc2Z3VHk5OEd2SjhrVm85OXVvRXYxcFBmVTgzN0JtSmkvSW1JeGNNQWlFQXNsZWZyVDRuci8wbWQvZCswS0hLMzRxb1RWYW5JTGh5TVFhTHQ1VjFDVm89IiwidmVyaWZpZXIiOiJMUzB0TFMxQ1JVZEpUaUJEUlZKVVNVWkpRMEZVUlMwdExTMHRDazFKU1VjNVJFTkRRbTV4WjBGM1NVSkJaMGxWU1ZSTVp6UnBXVmRXVW5GUUwySTBabEZZT0ZKSVdISklkVVJ2ZDBObldVbExiMXBKZW1vd1JVRjNUWGNLVG5wRlZrMUNUVWRCTVZWRlEyaE5UV015Ykc1ak0xSjJZMjFWZFZwSFZqSk5ValIzU0VGWlJGWlJVVVJGZUZaNllWZGtlbVJIT1hsYVV6RndZbTVTYkFwamJURnNXa2RzYUdSSFZYZElhR05PVFdwWmVFMUVRVE5OUkdkM1RXcEZNVmRvWTA1TmFsbDRUVVJCTTAxRVozaE5ha1V4VjJwQlFVMUdhM2RGZDFsSUNrdHZXa2w2YWpCRFFWRlpTVXR2V2tsNmFqQkVRVkZqUkZGblFVVm5ORWd6YlU1cVdUWmhXVEpETVVWRFRrUlpUalJ1WVZGNmJWVmhURVpTVTJsaGVXY0tXR2xvVG14UlJWVjZhMVpuZURGNEwwa3djVkk1VEZRcksyaERUVTVOWjNGbFFrcHBXV3R2VTB4SldFbDJPWHBRY0hGUFEwSmFhM2RuWjFkV1RVRTBSd3BCTVZWa1JIZEZRaTkzVVVWQmQwbElaMFJCVkVKblRsWklVMVZGUkVSQlMwSm5aM0pDWjBWR1FsRmpSRUY2UVdaQ1owNVdTRk5OUlVkRVFWZG5RbFJtQ2pBcmJsQldhVkZTYkhadGJ6SlBhMjlXWVV4SFRHaG9hMUI2UW1WQ1owNVdTRkpGUWtGbU9FVldSRUpUYUd4Q2IyUklVbmRqZW05MlRESmtjR1JIYURFS1dXazFhbUl5TUhaYWFrSjVZMnBCZG1JeWVIQmpSMmhvWkZjMU1FeDVOVzVoV0ZKdlpGZEpkbVF5T1hsaE1scHpZak5rZWt3elNteGlSMVpvWXpKVmRRcGxWekZ6VVVoS2JGcHVUWFpoUjFab1draE5kbUpYUm5CaWFrRTFRbWR2Y2tKblJVVkJXVTh2VFVGRlFrSkRkRzlrU0ZKM1kzcHZka3d6VW5aaE1sWjFDa3h0Um1wa1IyeDJZbTVOZFZveWJEQmhTRlpwWkZoT2JHTnRUblppYmxKc1ltNVJkVmt5T1hSTlFqaEhRMmx6UjBGUlVVSm5OemgzUVZGSlJVVllaSFlLWTIxMGJXSkhPVE5ZTWxKd1l6TkNhR1JIVG05TlJGbEhRMmx6UjBGUlVVSm5OemgzUVZGTlJVdEVUWGhaYWxVMFRVUk9hMDlFUW1wYVZFMDBUMFJTYUFwTlYxcHFUVzFSZWxwVWJHaFphbWN5VDFkU2EwNTZUWHBaYWxFeVRWZE5kMFpSV1V0TGQxbENRa0ZIUkhaNlFVSkNRVkZJVlcxV2MxcFhSbnBhVkVGa0NrSm5iM0pDWjBWRlFWbFBMMDFCUlVaQ1FUbHRUVWhLZVUxRE9YWmlSMngzWVVkR01XSnVVWGRJVVZsTFMzZFpRa0pCUjBSMmVrRkNRbWRSVUdOdFZtMEtZM2s1YjFwWFJtdGplVGwwV1Zkc2RVMUVjMGREYVhOSFFWRlJRbWMzT0hkQlVXZEZURkYzY21GSVVqQmpTRTAyVEhrNU1HSXlkR3hpYVRWb1dUTlNjQXBpTWpWNlRHMWtjR1JIYURGWmJsWjZXbGhLYW1JeU5UQmFWelV3VEcxT2RtSlVRbWRDWjI5eVFtZEZSVUZaVHk5TlFVVktRa1pKVFZWSGFEQmtTRUo2Q2s5cE9IWmFNbXd3WVVoV2FVeHRUblppVXpsdFRVaEtlVTFET1haaVIyeDNZVWRHTVdKdVVYWk1iV1J3WkVkb01WbHBPVE5pTTBweVdtMTRkbVF6VFhZS1kyMVdjMXBYUm5wYVV6VTFZbGQ0UVdOdFZtMWplVGx2V2xkR2EyTjVPWFJaVjJ4MVRVUm5SME5wYzBkQlVWRkNaemM0ZDBGUmIwVkxaM2R2VFhwR2FRcE9WR2QzVFRKUk5FMUhUbXhOZW1jMFRrZEZlRnB0VFhsYVJFNXNUMWRHYVU5RVdUVmFSMUV6VFhwT2FVNUVXWGhaZWtGa1FtZHZja0puUlVWQldVOHZDazFCUlV4Q1FUaE5SRmRrY0dSSGFERlphVEZ2WWpOT01GcFhVWGROWjFsTFMzZFpRa0pCUjBSMmVrRkNSRUZSYTBSRFNtOWtTRkozWTNwdmRrd3laSEFLWkVkb01WbHBOV3BpTWpCMldtcENlV05xUVhaaU1uaHdZMGRvYUdSWE5UQk5SR2RIUTJselIwRlJVVUpuTnpoM1FWRXdSVXRuZDI5TmVrWnBUbFJuZHdwTk1sRTBUVWRPYkUxNlp6Uk9SMFY0V20xTmVWcEVUbXhQVjBacFQwUlpOVnBIVVROTmVrNXBUa1JaZUZsNlFXWkNaMjl5UW1kRlJVRlpUeTlOUVVWUENrSkNSVTFFTTBwc1dtNU5kbUZIVm1oYVNFMTJZbGRHY0dKcVFXRkNaMjl5UW1kRlJVRlpUeTlOUVVWUVFrRjNUVU5xUlhkT2FsVjNUbFJyZUUxVVVYY0tTMEZaUzB0M1dVSkNRVWRFZG5wQlFrVkJVV0ZFUW1odlpFaFNkMk42YjNaTU1tUndaRWRvTVZscE5XcGlNakIyV21wQ2VXTnFRWGRHZDFsTFMzZFpRZ3BDUVVkRWRucEJRa1ZSVVVwRVFXTTBUbFJqTUUxcVJUVk5SMEZIUTJselIwRlJVVUpuTnpoM1FWSkpSVlZuZUZGaFNGSXdZMGhOTmt4NU9XNWhXRkp2Q21SWFNYVlpNamwwVERKWmQyTnVTWGRNTWpsellWaENiMWxZVm5Wa1F6aDFXakpzTUdGSVZtbE1NMlIyWTIxMGJXSkhPVE5qZVRsNVdsZDRiRmxZVG13S1RHNXNkR0pGUW5sYVYxcDZUREpvYkZsWFVucE1NakZvWVZjMGQwOUJXVXRMZDFsQ1FrRkhSSFo2UVVKRmQxRnhSRU5uZWsxWFNURlBSRUY2V2tSbmR3cFpNbFY2VDBSbk1GbFVSbTFaZWtwclRUSlZOVmxYU1RST2FteHJXa1JqZWsweVNUQk9ha1pxVFVORlIwTnBjMGRCVVZGQ1p6YzRkMEZTVVVWRmQzZFNDbVF5T1hsaE1scHpZak5rWmxwSGJIcGpSMFl3V1RKbmQxWm5XVXRMZDFsQ1FrRkhSSFo2UVVKR1VWSkpSRVZhYjJSSVVuZGplbTkyVERKa2NHUkhhREVLV1drMWFtSXlNSFphYWtKNVkycEJkbUl5ZUhCalIyaG9aRmMxTUV3eVJtcGtSMngyWW01TmRtTnVWblZqZVRoNlRucFZORTE2VlRKUFZFMHdUME01YUFwa1NGSnNZbGhDTUdONU9IaE5RbGxIUTJselIwRlJVVUpuTnpoM1FWSlpSVU5CZDBkalNGWnBZa2RzYWsxQ09FZERhWE5IUVZGUlFtYzNPSGRCVW1ORkNrVlJkMUJqYlZaeldsZEdlbHBUTVhka1YwcHpZVmhPYjAxRlFVZERhWE5IUVZGUlFtYzNPSGRCVW1kRlRXZDNkMk50Vm5kaWVuQnRUVWhLZVUxRE9YWUtZa2RzZDJGSFJqRmlibEUyV2xjMU1tRllTblppYlRGc1ltNVJObU50Vm5OYVYwWjZXbE14ZDJSWFNuTmhXRTV2VFVsSFRFSm5iM0pDWjBWRlFXUmFOUXBCWjFGRFFrZ3dSV1YzUWpWQlNHTkJNMVF3ZDJGellraEZWRXBxUjFJMFkyMVhZek5CY1VwTFdISnFaVkJMTXk5b05IQjVaME00Y0Rkdk5FRkJRVWRvQ2taWFNuZzJaMEZCUWtGTlFWTkVRa2RCYVVWQk5YRlpSazg0VEVNMVdtMWtZVFpVTkVoSk5VeHVXVGgyWW5KUlpWUXllVk5QTUVjM1pHZFNZMlpvZDBNS1NWRkRialJNTTBReVJVOTNkRnA0UVV4VWEwbHdRVTB4Y0hKdE5IZHpXbm9yVVdsa1ZIWktkM2h5TWxwbGFrRkxRbWRuY1docmFrOVFVVkZFUVhkT2J3cEJSRUpzUVdwQ0wxbEVMMk14V1ZCT2EzcGthVGh0V0ZkSFFsWjRUWGhvT1VndlpscGlaMWhUUmtkNFRrcERTMHRrYkdvNVkyUnZhelJLUmpFM1UzWnNDbmRvYzBJMk1VRkRUVkZFWkdWTk5ERllXRUpsUWpsR2RFeFhWMUZzU1VwR1ZrNU1TV1ZRYXpZMlNVOTNabnB6SzI5MU1GcEdkWEYwTm1jMmVHWjZjRlFLYkhob1p6aFRURlpVWmpROUNpMHRMUzB0UlU1RUlFTkZVbFJKUmtsRFFWUkZMUzB0TFMwSyJ9XX19" + } + ], + "timestampVerificationData": { + "rfc3161Timestamps": [] + } + }, + "dsseEnvelope": { + "payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoicGtnOm5wbS8lNDBvbGlwaGF1bnQvbGlib2xpcGhhdW50LWxpbnV4LXg2NC1nbnVAMC4zLjIiLCJkaWdlc3QiOnsic2hhNTEyIjoiNGEwYmZhZGQ0ZjMzMDg4NDg1MDgyNjE2NjFiNWE2NGE0NDA1MzcyNDI5NWFmOGM5M2QyMGUwMTk3N2VlNzBiYjJhYjllZTE4MmRlOWUzNWViZTNkOWM4OGMwZTYyNDk3OTk3ZGZmYjBmYjUxYzNlYTRmZTQ4MDYwZDFjNTMzYWYifX1dLCJwcmVkaWNhdGVUeXBlIjoiaHR0cHM6Ly9zbHNhLmRldi9wcm92ZW5hbmNlL3YxIiwicHJlZGljYXRlIjp7ImJ1aWxkRGVmaW5pdGlvbiI6eyJidWlsZFR5cGUiOiJodHRwczovL3Nsc2EtZnJhbWV3b3JrLmdpdGh1Yi5pby9naXRodWItYWN0aW9ucy1idWlsZHR5cGVzL3dvcmtmbG93L3YxIiwiZXh0ZXJuYWxQYXJhbWV0ZXJzIjp7IndvcmtmbG93Ijp7InJlZiI6InJlZnMvaGVhZHMvbWFpbiIsInJlcG9zaXRvcnkiOiJodHRwczovL2dpdGh1Yi5jb20vZjBycjAvb2xpcGhhdW50IiwicGF0aCI6Ii5naXRodWIvd29ya2Zsb3dzL3JlbGVhc2UueW1sIn19LCJpbnRlcm5hbFBhcmFtZXRlcnMiOnsiZ2l0aHViIjp7ImV2ZW50X25hbWUiOiJ3b3JrZmxvd19kaXNwYXRjaCIsInJlcG9zaXRvcnlfaWQiOiIxMDY1MDU5MTE0IiwicmVwb3NpdG9yeV9vd25lcl9pZCI6Ijg1NzQyMTkifX0sInJlc29sdmVkRGVwZW5kZW5jaWVzIjpbeyJ1cmkiOiJnaXQraHR0cHM6Ly9naXRodWIuY29tL2YwcnIwL29saXBoYXVudEByZWZzL2hlYWRzL21haW4iLCJkaWdlc3QiOnsiZ2l0Q29tbWl0IjoiMzFiNTgwM2Q4MGNlMzg4NGExZmMyZDNlOWFiODY5ZGQ3MzNiNDYxYyJ9fV19LCJydW5EZXRhaWxzIjp7ImJ1aWxkZXIiOnsiaWQiOiJodHRwczovL2dpdGh1Yi5jb20vYWN0aW9ucy9ydW5uZXIvZ2l0aHViLWhvc3RlZCJ9LCJtZXRhZGF0YSI6eyJpbnZvY2F0aW9uSWQiOiJodHRwczovL2dpdGh1Yi5jb20vZjBycjAvb2xpcGhhdW50L2FjdGlvbnMvcnVucy8zNzU4MzU2OTM0OC9hdHRlbXB0cy8xIn19fX0=", + "payloadType": "application/vnd.in-toto+json", + "signatures": [ + { + "sig": "MEUCIEXgSsfwTy98GvJ8kVo99uoEv1pPfU837BmJi/ImIxcMAiEAslefrT4nr/0md/d+0KHK34qoTVanILhyMQaLt5V1CVo=", + "keyid": "" + } + ] + } + } + } + ] +} diff --git a/build_defs/release/native-0.3.2-npm-linux-x64-gnu.json b/build_defs/release/native-0.3.2-npm-linux-x64-gnu.json new file mode 100644 index 000000000..656277f56 --- /dev/null +++ b/build_defs/release/native-0.3.2-npm-linux-x64-gnu.json @@ -0,0 +1,92 @@ +{ + "os": [ + "linux" + ], + "cpu": [ + "x64" + ], + "bugs": { + "url": "https://github.com/f0rr0/oliphaunt/issues" + }, + "dist": { + "shasum": "4442cbd22105697113e2de471582911eaf4c09c5", + "tarball": "https://registry.npmjs.org/@oliphaunt/liboliphaunt-linux-x64-gnu/-/liboliphaunt-linux-x64-gnu-0.3.2.tgz", + "fileCount": 737, + "integrity": "sha512-Sgv63U8zCISFCCYWYbWmSkQFNyQpWvjJPSDgGXfucLsque4YLenjXr49nIjA5iSXmX3/sPtRw+pP5IBg0cUzrw==", + "signatures": [ + { + "sig": "MEUCIQCPRGWAvVPfJ16wOEFX1PYdlXwHivG/QsRyZtQ3s0R4VQIgE62ayjN3oP19EurZ5EVKlONHHpiputs9ldChSJSXjyY=", + "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + }, + { + "sig": "MEQCICcrUt4D8XdXW/X/Yzm3XVfnQu5iTxW8PpJo9fC0ljkGAiArKUox/tJWtUcSeoGYB68fu9iri8GYtUdonPMEgFrUjg==", + "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + } + ], + "attestations": { + "url": "https://registry.npmjs.org/-/npm/v1/attestations/@oliphaunt%2fliboliphaunt-linux-x64-gnu@0.3.2", + "provenance": { + "predicateType": "https://slsa.dev/provenance/v1" + } + }, + "unpackedSize": 34420240 + }, + "libc": [ + "glibc" + ], + "name": "@oliphaunt/liboliphaunt-linux-x64-gnu", + "type": "module", + "_from": "file:/home/runner/work/oliphaunt/oliphaunt/target/release/npm-packages/oliphaunt-liboliphaunt-linux-x64-gnu/oliphaunt-liboliphaunt-linux-x64-gnu-0.3.2.tgz", + "exports": { + "./package.json": "./package.json" + }, + "license": "MIT AND PostgreSQL AND Unicode-3.0", + "_npmUser": { + "name": "GitHub Actions", + "email": "npm-oidc-no-reply@github.com", + "trustedPublisher": { + "id": "github", + "oidcConfigId": "b375dfe0-1c31-45d8-8c3a-508778e50c59" + } + }, + "homepage": "https://github.com/f0rr0/oliphaunt#readme", + "optional": true, + "_resolved": "/home/runner/work/oliphaunt/oliphaunt/target/release/npm-packages/oliphaunt-liboliphaunt-linux-x64-gnu/oliphaunt-liboliphaunt-linux-x64-gnu-0.3.2.tgz", + "oliphaunt": { + "target": "linux-x64-gnu", + "libraryRelativePath": "lib/liboliphaunt.so", + "runtimeRelativePath": "runtime" + }, + "_integrity": "sha512-Sgv63U8zCISFCCYWYbWmSkQFNyQpWvjJPSDgGXfucLsque4YLenjXr49nIjA5iSXmX3/sPtRw+pP5IBg0cUzrw==", + "repository": { + "url": "git+https://github.com/f0rr0/oliphaunt.git", + "type": "git", + "directory": "src/native/runtime/packages/linux-x64-gnu" + }, + "_npmVersion": "11.18.0", + "description": "Linux x64 glibc liboliphaunt native library for Oliphaunt.", + "directories": {}, + "maintainers": [ + { + "name": "oliphaunt", + "email": "sids.outlook.email@gmail.com" + } + ], + "_nodeVersion": "22.22.3", + "publishConfig": { + "access": "public", + "provenance": true, + "executableFiles": [ + "./runtime/bin/initdb", + "./runtime/bin/pg_ctl", + "./runtime/bin/postgres" + ] + }, + "_hasShrinkwrap": false, + "_npmOperationalInternal": { + "tmp": "tmp/liboliphaunt-linux-x64-gnu_0.3.2_1791360394182_0.7911558616524945", + "host": "s3://npm-registry-packages-npm-production" + }, + "_id": "@oliphaunt/liboliphaunt-linux-x64-gnu@0.3.2", + "version": "0.3.2" +} diff --git a/build_defs/release/native-0.3.2-npm-macos-arm64-attestations.json b/build_defs/release/native-0.3.2-npm-macos-arm64-attestations.json new file mode 100644 index 000000000..79c366dc2 --- /dev/null +++ b/build_defs/release/native-0.3.2-npm-macos-arm64-attestations.json @@ -0,0 +1,144 @@ +{ + "attestations": [ + { + "predicateType": "https://github.com/npm/attestation/tree/main/specs/publish/v0.1", + "bundle": { + "mediaType": "application/vnd.dev.sigstore.bundle+json;version=0.2", + "verificationMaterial": { + "publicKey": { + "hint": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + }, + "tlogEntries": [ + { + "logIndex": "3126858912", + "logId": { + "keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0=" + }, + "kindVersion": { + "kind": "dsse", + "version": "0.0.1" + }, + "integratedTime": "1791359952", + "inclusionPromise": { + "signedEntryTimestamp": "MEUCIBf+TaCcnAfrYMusNt0dAbXBI3ZCHtTqCMqFCLImG9iqAiEAw9o/ucDvH55FBKUD6pw3bjJaytFrI5GROgMfh2YM2+4=" + }, + "inclusionProof": { + "logIndex": "3004954650", + "rootHash": "vby0iXwJLR9MFFjKYeO3d9yeZZX3O5m/DGXjhut1lnw=", + "treeSize": "3004954662", + "hashes": [ + "+1DPXDHlSVkCzFinnX8Zor+GY9F3c8Hz8RdZ2wA5vos=", + "8VlWOfKNSzM2I8zqSFCJYfw5/ouiITVHmBZzD7YJ1cg=", + "uZZJShJ2VCVgF+3AnDS5uTxR1iFdJakUhEZUnPCTkvU=", + "NJVGp/U9G+WCPJ8iJuJw+QvIjFmt4j5zC0NtuYY/gRE=", + "TmaZkKBFclrRS7QwwNC/LnZcPb6NCX99hgtp+Rl86tM=", + "y0wWREWMRoZ5cgTZ5xF3tb4S2bvu/e+k1MvDlh21Pg4=", + "2iqFuoeiuZMlQ3AnRhOJScVI3sOudIjHyLKWbrEBTA8=", + "fv9SS2o8G24NpC0L9IcWOu/YkfcwVbKRaIRygvkiEgY=", + "3OmDmbEbb5oBLKo+7JYJ4qVsCedw+RciS+MMxgtFqaw=", + "tgZv0cB+1xdIHQC9YRamQ/wxB5PotDLoyl4mGL1Ais0=", + "gsGQtOvQseSbXJrbgUNClXHAKIzFJK1FxZdxAxzJ4X0=", + "DC/u+yi+DgAxrH8AWHGRYYGM83MLUtzV7h84BZl8Gl0=", + "vv8cN7kbrEk8irImb+2f4QhRNNDgvMiVIIXIPcNegMQ=", + "AITQYGvsxlpdAjbZL+ujvmbDH51sR+4T6G8OCFJbtVA=", + "WymSSAFdY3L1BjserJgGo6PUJWiKIc5OHBM+Xxw2adk=", + "3fRFZuDepJD9y0NjNA9nqInlZuCxNImKQJJfr//qImA=", + "x9rXqkSu8+Vm4yqD2XeAwn305JZ4ZykdOwcD90FjP8o=", + "NlOclldmKPA1tMKIskqHAwuQDYHp31YwpK+OOMrMccc=", + "qxzHanAzz57SDdmJe0B7bJK72NTIBbwEMGBBKvDOROw=", + "xH/DCseLHr9eKoYT8qsORZK7zVdEGYWHuVtsVrD95wY=" + ], + "checkpoint": { + "envelope": "rekor.sigstore.dev - 1193050959916656506\n3004954662\nvby0iXwJLR9MFFjKYeO3d9yeZZX3O5m/DGXjhut1lnw=\n\n— rekor.sigstore.dev wNI9ajBFAiEAyCiyW9gLo0QE5Lgjzf6iTCy0a1NZ2m5a7VY6X8yYT+YCID2RDRzurHkqgR+Xmo37+J0scVwQ95M//AK1nPDU7lPG\n" + } + }, + "canonicalizedBody": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiZHNzZSIsInNwZWMiOnsiZW52ZWxvcGVIYXNoIjp7ImFsZ29yaXRobSI6InNoYTI1NiIsInZhbHVlIjoiNjNhM2M4MzViNDA5MTg3NzJmZWE1MGY0NDRlZTA4ZjAzN2M5ODRmOTQ3ZTVjM2ZjNmM1N2Y5OTg5MTU4ZDljOCJ9LCJwYXlsb2FkSGFzaCI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6IjY5NzIwODA3OGVjNzU5N2VlODhkMDAxZTdlODZjMjljZDliYmIxOGVlYTdjYThhZDk1ZjkxZWUzYTI2ODdmZmMifSwic2lnbmF0dXJlcyI6W3sic2lnbmF0dXJlIjoiTUVRQ0lFblFxcnEzSFloZUJ1M0pPU2ZTRUIxZG5FbU54YkZxaEw2SmtyTjdJMmJSQWlBR2dLRklNWXFOSTFjbVJqUGhremIvMG9VVUs3U0dlRzFua3hLTGMwNnl4Zz09IiwidmVyaWZpZXIiOiJMUzB0TFMxQ1JVZEpUaUJRVlVKTVNVTWdTMFZaTFMwdExTMEtUVVpyZDBWM1dVaExiMXBKZW1vd1EwRlJXVWxMYjFwSmVtb3dSRUZSWTBSUlowRkZXVFpaWVRkWEt5czNZVlZRZW5aTlZISmxla2cyV1dONE0yTXJTQXBQUzFsRFkwNUhlV0pLV2xORFNuRXZabVEzVVdFNGRYVkJTM1JrU1d0VlVYUlJhVVZMUlZKb1FXMUZOV3hOVFVwb1VEaFBhMFJQWVRKblBUMEtMUzB0TFMxRlRrUWdVRlZDVEVsRElFdEZXUzB0TFMwdENnPT0ifV19fQ==" + } + ], + "timestampVerificationData": { + "rfc3161Timestamps": [] + } + }, + "dsseEnvelope": { + "payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInN1YmplY3QiOlt7Im5hbWUiOiJwa2c6bnBtLyU0MG9saXBoYXVudC9saWJvbGlwaGF1bnQtZGFyd2luLWFybTY0QDAuMy4yIiwiZGlnZXN0Ijp7InNoYTUxMiI6IjAzN2EzZTBlMWE1NDkxYjAzMjM3OTZiZmYyMzc3MzJjZjcxZWU4ZGIwYWU0YWViNzRmMmYzZjE4ODUwMDEyNzMyNjQ0NWNjMzk3NDEzNjY5NmZjNGViYmJhMmIzY2IyZmRhODM1OGY4NTY1MmRkYWI0ODFmZTg2YmM3NjYzMmExIn19XSwicHJlZGljYXRlVHlwZSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9ucG0vYXR0ZXN0YXRpb24vdHJlZS9tYWluL3NwZWNzL3B1Ymxpc2gvdjAuMSIsInByZWRpY2F0ZSI6eyJuYW1lIjoiQG9saXBoYXVudC9saWJvbGlwaGF1bnQtZGFyd2luLWFybTY0IiwidmVyc2lvbiI6IjAuMy4yIiwicmVnaXN0cnkiOiJodHRwczovL3JlZ2lzdHJ5Lm5wbWpzLm9yZyJ9fQ==", + "payloadType": "application/vnd.in-toto+json", + "signatures": [ + { + "sig": "MEQCIEnQqrq3HYheBu3JOSfSEB1dnEmNxbFqhL6JkrN7I2bRAiAGgKFIMYqNI1cmRjPhkzb/0oUUK7SGeG1nkxKLc06yxg==", + "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + } + ] + } + } + }, + { + "predicateType": "https://slsa.dev/provenance/v1", + "bundle": { + "mediaType": "application/vnd.dev.sigstore.bundle.v0.3+json", + "verificationMaterial": { + "certificate": { + "rawBytes": "MIIG8jCCBnmgAwIBAgIUMnQ4E8yrSl4Lp9Kqqhkh+h1XGGwwCgYIKoZIzj0EAwMwNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwHhcNMjYxMDA3MDc1MTU0WhcNMjYxMDA3MDgwMTU0WjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEwpiS4FJUihGb4Wl4QnpN7Z0ddsmW78e5OEdsp1qlMKf7ZL34dA47TJJgYuoLhuWdJnQhvcONvZXQW8iS4E+VZaOCBZgwggWUMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAfBgNVHSMEGDAWgBTf0+nPViQRlvmo2OkoVaLGLhhkPzBeBgNVHREBAf8EVDBShlBodHRwczovL2dpdGh1Yi5jb20vZjBycjAvb2xpcGhhdW50Ly5naXRodWIvd29ya2Zsb3dzL3JlbGVhc2UueW1sQHJlZnMvaGVhZHMvbWFpbjA5BgorBgEEAYO/MAEBBCtodHRwczovL3Rva2VuLmFjdGlvbnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tMB8GCisGAQQBg78wAQIEEXdvcmtmbG93X2Rpc3BhdGNoMDYGCisGAQQBg78wAQMEKDMxYjU4MDNkODBjZTM4ODRhMWZjMmQzZTlhYjg2OWRkNzMzYjQ2MWMwFQYKKwYBBAGDvzABBAQHUmVsZWFzZTAdBgorBgEEAYO/MAEFBA9mMHJyMC9vbGlwaGF1bnQwHQYKKwYBBAGDvzABBgQPcmVmcy9oZWFkcy9tYWluMDsGCisGAQQBg78wAQgELQwraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1YnVzZXJjb250ZW50LmNvbTBgBgorBgEEAYO/MAEJBFIMUGh0dHBzOi8vZ2l0aHViLmNvbS9mMHJyMC9vbGlwaGF1bnQvLmdpdGh1Yi93b3JrZmxvd3MvcmVsZWFzZS55bWxAcmVmcy9oZWFkcy9tYWluMDgGCisGAQQBg78wAQoEKgwoMzFiNTgwM2Q4MGNlMzg4NGExZmMyZDNlOWFiODY5ZGQ3MzNiNDYxYzAdBgorBgEEAYO/MAELBA8MDWdpdGh1Yi1ob3N0ZWQwMgYKKwYBBAGDvzABDAQkDCJodHRwczovL2dpdGh1Yi5jb20vZjBycjAvb2xpcGhhdW50MDgGCisGAQQBg78wAQ0EKgwoMzFiNTgwM2Q4MGNlMzg4NGExZmMyZDNlOWFiODY5ZGQ3MzNiNDYxYzAfBgorBgEEAYO/MAEOBBEMD3JlZnMvaGVhZHMvbWFpbjAaBgorBgEEAYO/MAEPBAwMCjEwNjUwNTkxMTQwKAYKKwYBBAGDvzABEAQaDBhodHRwczovL2dpdGh1Yi5jb20vZjBycjAwFwYKKwYBBAGDvzABEQQJDAc4NTc0MjE5MGAGCisGAQQBg78wARIEUgxQaHR0cHM6Ly9naXRodWIuY29tL2YwcnIwL29saXBoYXVudC8uZ2l0aHViL3dvcmtmbG93cy9yZWxlYXNlLnltbEByZWZzL2hlYWRzL21haW4wOAYKKwYBBAGDvzABEwQqDCgzMWI1ODAzZDgwY2UzODg0YTFmYzJkM2U5YWI4NjlkZDczM2I0NjFjMCEGCisGAQQBg78wARQEEwwRd29ya2Zsb3dfZGlzcGF0Y2gwVgYKKwYBBAGDvzABFQRIDEZodHRwczovL2dpdGh1Yi5jb20vZjBycjAvb2xpcGhhdW50L2FjdGlvbnMvcnVucy8zNzU4MzU2OTM0OC9hdHRlbXB0cy8xMBYGCisGAQQBg78wARYECAwGcHVibGljMB8GCisGAQQBg78wARcEEQwPcmVsZWFzZS1wdWJsaXNoMEAGCisGAQQBg78wARgEMgwwcmVwbzpmMHJyMC9vbGlwaGF1bnQ6ZW52aXJvbm1lbnQ6cmVsZWFzZS1wdWJsaXNoMIGKBgorBgEEAdZ5AgQCBHwEegB4AHYA3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4AAAGhFVj2xgAABAMARzBFAiEAipocst06UautGDsVlbpSXE6XpoXM5803Sz8hsaDOwvMCIB2Kue+T0/J+aazQvHGZ94E9T+XA09IxvRi7Cw4QeVfYMAoGCCqGSM49BAMDA2cAMGQCMGG36dd4LMZ12S6wPW7fo/boqgeJPq44kCVrzqXblb+NLkVUmLFs7zNaHPMRRc8PRQIwEG3WkgaTd+mJNJiQJ1Q5meL9zgnKyxcU5oXdLrmiw5BtINnEclvI4mreMGHtvN3D" + }, + "tlogEntries": [ + { + "logIndex": "3126783499", + "logId": { + "keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0=" + }, + "kindVersion": { + "kind": "dsse", + "version": "0.0.1" + }, + "integratedTime": "1791359514", + "inclusionPromise": { + "signedEntryTimestamp": "MEQCIGTVotXAa5fHPf+uZ9lXs6bDKgH2EQrMFnl/ehvr0G23AiB0k70gd2tRAyFPgHwViENzp0L+GPIxNAcBxvGt8jRQpQ==" + }, + "inclusionProof": { + "logIndex": "3004879237", + "rootHash": "4/R4jHmIXdrn4wj+RYVQavp1rJu5kShbenv4jUnV38s=", + "treeSize": "3004879253", + "hashes": [ + "Edjpe8585DaSL9CM/yprXSNqKtQKv7qCFl4SR7tk9qo=", + "0qsQbnjuSMtOgW9bzuC/0udJmV4tb9htxidVodqd0LE=", + "auxat5p/se2YUAUtkfFkV2U42BE1e6wwIF+b4SR/cdo=", + "nk6J4Af4R4rFjZZlsCFRPVw66KNATUFehKGnkaxXfdc=", + "NHjwGxqMiOpAjQ3kN1Akd+kriU2aRAOzklzx1N0zML0=", + "zKh8cHFYPqrJ7g4YWhvcBBB/7qUCoXvLqN4HFuA+/PQ=", + "Br7x+4u/g20zjxb5iq7mw+iPboWZWZsPd1xFXm3Dbew=", + "0LFPabIUP+GzrBO2uWmD3vyOz/rM1QrfStVCWUGJyJg=", + "u6lGFXejBUaq6JcZANGtwdRvnGZ4IIxfN4tpD6Ngf3g=", + "yIu/a0V1xOMbndjxTwvOifXIeTCKaVbAtYGEONuPA+g=", + "vv8cN7kbrEk8irImb+2f4QhRNNDgvMiVIIXIPcNegMQ=", + "AITQYGvsxlpdAjbZL+ujvmbDH51sR+4T6G8OCFJbtVA=", + "WymSSAFdY3L1BjserJgGo6PUJWiKIc5OHBM+Xxw2adk=", + "3fRFZuDepJD9y0NjNA9nqInlZuCxNImKQJJfr//qImA=", + "x9rXqkSu8+Vm4yqD2XeAwn305JZ4ZykdOwcD90FjP8o=", + "NlOclldmKPA1tMKIskqHAwuQDYHp31YwpK+OOMrMccc=", + "qxzHanAzz57SDdmJe0B7bJK72NTIBbwEMGBBKvDOROw=", + "xH/DCseLHr9eKoYT8qsORZK7zVdEGYWHuVtsVrD95wY=" + ], + "checkpoint": { + "envelope": "rekor.sigstore.dev - 1193050959916656506\n3004879253\n4/R4jHmIXdrn4wj+RYVQavp1rJu5kShbenv4jUnV38s=\n\n— rekor.sigstore.dev wNI9ajBFAiB/usDrl6nXIXX1oLW4VEzLBAY3fPdh1BY+kgATZrQdQgIhAPEMYbNhhYe56H0EK6PUfoQswKF3bQG/5hCIrr10dE33\n" + } + }, + "canonicalizedBody": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiZHNzZSIsInNwZWMiOnsiZW52ZWxvcGVIYXNoIjp7ImFsZ29yaXRobSI6InNoYTI1NiIsInZhbHVlIjoiN2ViYjZhYjk1Mzk2MmQ3NGViYmMwOThkN2RlOGFiZmIwYjIyNzk1MWUyZWZmOGY2NTE4MWM4MjkwZTBlYmMzNCJ9LCJwYXlsb2FkSGFzaCI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6ImY2Y2ZhZTY2ZTM2ZTZlOGIwMTQzOGZlY2FhYzA1ZjljYTdmNWUwMzhjZmUwZWI4OWNhNDM2OTlmOGIwNWM2N2EifSwic2lnbmF0dXJlcyI6W3sic2lnbmF0dXJlIjoiTUVZQ0lRRHlFNWZ5U2doWkZjMUx1NEE0RGJCL1VrNFlYWmxUN09NVzZIRXl6d041akFJaEFNK2hsdU10QUIrSmZ5M2Z3QXZONW11cHl2MnVGdG5HWmpGMTAxMnI0VXd1IiwidmVyaWZpZXIiOiJMUzB0TFMxQ1JVZEpUaUJEUlZKVVNVWkpRMEZVUlMwdExTMHRDazFKU1VjNGFrTkRRbTV0WjBGM1NVSkJaMGxWVFc1Uk5FVTRlWEpUYkRSTWNEbExjWEZvYTJncmFERllSMGQzZDBObldVbExiMXBKZW1vd1JVRjNUWGNLVG5wRlZrMUNUVWRCTVZWRlEyaE5UV015Ykc1ak0xSjJZMjFWZFZwSFZqSk5ValIzU0VGWlJGWlJVVVJGZUZaNllWZGtlbVJIT1hsYVV6RndZbTVTYkFwamJURnNXa2RzYUdSSFZYZElhR05PVFdwWmVFMUVRVE5OUkdNeFRWUlZNRmRvWTA1TmFsbDRUVVJCTTAxRVozZE5WRlV3VjJwQlFVMUdhM2RGZDFsSUNrdHZXa2w2YWpCRFFWRlpTVXR2V2tsNmFqQkVRVkZqUkZGblFVVjNjR2xUTkVaS1ZXbG9SMkkwVjJ3MFVXNXdUamRhTUdSa2MyMVhOemhsTlU5RlpITUtjREZ4YkUxTFpqZGFURE0wWkVFME4xUktTbWRaZFc5TWFIVlhaRXB1VVdoMlkwOU9kbHBZVVZjNGFWTTBSU3RXV21GUFEwSmFaM2RuWjFkVlRVRTBSd3BCTVZWa1JIZEZRaTkzVVVWQmQwbElaMFJCVkVKblRsWklVMVZGUkVSQlMwSm5aM0pDWjBWR1FsRmpSRUY2UVdaQ1owNVdTRk5OUlVkRVFWZG5RbFJtQ2pBcmJsQldhVkZTYkhadGJ6SlBhMjlXWVV4SFRHaG9hMUI2UW1WQ1owNVdTRkpGUWtGbU9FVldSRUpUYUd4Q2IyUklVbmRqZW05MlRESmtjR1JIYURFS1dXazFhbUl5TUhaYWFrSjVZMnBCZG1JeWVIQmpSMmhvWkZjMU1FeDVOVzVoV0ZKdlpGZEpkbVF5T1hsaE1scHpZak5rZWt3elNteGlSMVpvWXpKVmRRcGxWekZ6VVVoS2JGcHVUWFpoUjFab1draE5kbUpYUm5CaWFrRTFRbWR2Y2tKblJVVkJXVTh2VFVGRlFrSkRkRzlrU0ZKM1kzcHZka3d6VW5aaE1sWjFDa3h0Um1wa1IyeDJZbTVOZFZveWJEQmhTRlpwWkZoT2JHTnRUblppYmxKc1ltNVJkVmt5T1hSTlFqaEhRMmx6UjBGUlVVSm5OemgzUVZGSlJVVllaSFlLWTIxMGJXSkhPVE5ZTWxKd1l6TkNhR1JIVG05TlJGbEhRMmx6UjBGUlVVSm5OemgzUVZGTlJVdEVUWGhaYWxVMFRVUk9hMDlFUW1wYVZFMDBUMFJTYUFwTlYxcHFUVzFSZWxwVWJHaFphbWN5VDFkU2EwNTZUWHBaYWxFeVRWZE5kMFpSV1V0TGQxbENRa0ZIUkhaNlFVSkNRVkZJVlcxV2MxcFhSbnBhVkVGa0NrSm5iM0pDWjBWRlFWbFBMMDFCUlVaQ1FUbHRUVWhLZVUxRE9YWmlSMngzWVVkR01XSnVVWGRJVVZsTFMzZFpRa0pCUjBSMmVrRkNRbWRSVUdOdFZtMEtZM2s1YjFwWFJtdGplVGwwV1Zkc2RVMUVjMGREYVhOSFFWRlJRbWMzT0hkQlVXZEZURkYzY21GSVVqQmpTRTAyVEhrNU1HSXlkR3hpYVRWb1dUTlNjQXBpTWpWNlRHMWtjR1JIYURGWmJsWjZXbGhLYW1JeU5UQmFWelV3VEcxT2RtSlVRbWRDWjI5eVFtZEZSVUZaVHk5TlFVVktRa1pKVFZWSGFEQmtTRUo2Q2s5cE9IWmFNbXd3WVVoV2FVeHRUblppVXpsdFRVaEtlVTFET1haaVIyeDNZVWRHTVdKdVVYWk1iV1J3WkVkb01WbHBPVE5pTTBweVdtMTRkbVF6VFhZS1kyMVdjMXBYUm5wYVV6VTFZbGQ0UVdOdFZtMWplVGx2V2xkR2EyTjVPWFJaVjJ4MVRVUm5SME5wYzBkQlVWRkNaemM0ZDBGUmIwVkxaM2R2VFhwR2FRcE9WR2QzVFRKUk5FMUhUbXhOZW1jMFRrZEZlRnB0VFhsYVJFNXNUMWRHYVU5RVdUVmFSMUV6VFhwT2FVNUVXWGhaZWtGa1FtZHZja0puUlVWQldVOHZDazFCUlV4Q1FUaE5SRmRrY0dSSGFERlphVEZ2WWpOT01GcFhVWGROWjFsTFMzZFpRa0pCUjBSMmVrRkNSRUZSYTBSRFNtOWtTRkozWTNwdmRrd3laSEFLWkVkb01WbHBOV3BpTWpCMldtcENlV05xUVhaaU1uaHdZMGRvYUdSWE5UQk5SR2RIUTJselIwRlJVVUpuTnpoM1FWRXdSVXRuZDI5TmVrWnBUbFJuZHdwTk1sRTBUVWRPYkUxNlp6Uk9SMFY0V20xTmVWcEVUbXhQVjBacFQwUlpOVnBIVVROTmVrNXBUa1JaZUZsNlFXWkNaMjl5UW1kRlJVRlpUeTlOUVVWUENrSkNSVTFFTTBwc1dtNU5kbUZIVm1oYVNFMTJZbGRHY0dKcVFXRkNaMjl5UW1kRlJVRlpUeTlOUVVWUVFrRjNUVU5xUlhkT2FsVjNUbFJyZUUxVVVYY0tTMEZaUzB0M1dVSkNRVWRFZG5wQlFrVkJVV0ZFUW1odlpFaFNkMk42YjNaTU1tUndaRWRvTVZscE5XcGlNakIyV21wQ2VXTnFRWGRHZDFsTFMzZFpRZ3BDUVVkRWRucEJRa1ZSVVVwRVFXTTBUbFJqTUUxcVJUVk5SMEZIUTJselIwRlJVVUpuTnpoM1FWSkpSVlZuZUZGaFNGSXdZMGhOTmt4NU9XNWhXRkp2Q21SWFNYVlpNamwwVERKWmQyTnVTWGRNTWpsellWaENiMWxZVm5Wa1F6aDFXakpzTUdGSVZtbE1NMlIyWTIxMGJXSkhPVE5qZVRsNVdsZDRiRmxZVG13S1RHNXNkR0pGUW5sYVYxcDZUREpvYkZsWFVucE1NakZvWVZjMGQwOUJXVXRMZDFsQ1FrRkhSSFo2UVVKRmQxRnhSRU5uZWsxWFNURlBSRUY2V2tSbmR3cFpNbFY2VDBSbk1GbFVSbTFaZWtwclRUSlZOVmxYU1RST2FteHJXa1JqZWsweVNUQk9ha1pxVFVORlIwTnBjMGRCVVZGQ1p6YzRkMEZTVVVWRmQzZFNDbVF5T1hsaE1scHpZak5rWmxwSGJIcGpSMFl3V1RKbmQxWm5XVXRMZDFsQ1FrRkhSSFo2UVVKR1VWSkpSRVZhYjJSSVVuZGplbTkyVERKa2NHUkhhREVLV1drMWFtSXlNSFphYWtKNVkycEJkbUl5ZUhCalIyaG9aRmMxTUV3eVJtcGtSMngyWW01TmRtTnVWblZqZVRoNlRucFZORTE2VlRKUFZFMHdUME01YUFwa1NGSnNZbGhDTUdONU9IaE5RbGxIUTJselIwRlJVVUpuTnpoM1FWSlpSVU5CZDBkalNGWnBZa2RzYWsxQ09FZERhWE5IUVZGUlFtYzNPSGRCVW1ORkNrVlJkMUJqYlZaeldsZEdlbHBUTVhka1YwcHpZVmhPYjAxRlFVZERhWE5IUVZGUlFtYzNPSGRCVW1kRlRXZDNkMk50Vm5kaWVuQnRUVWhLZVUxRE9YWUtZa2RzZDJGSFJqRmlibEUyV2xjMU1tRllTblppYlRGc1ltNVJObU50Vm5OYVYwWjZXbE14ZDJSWFNuTmhXRTV2VFVsSFMwSm5iM0pDWjBWRlFXUmFOUXBCWjFGRFFraDNSV1ZuUWpSQlNGbEJNMVF3ZDJGellraEZWRXBxUjFJMFkyMVhZek5CY1VwTFdISnFaVkJMTXk5b05IQjVaME00Y0Rkdk5FRkJRVWRvQ2taV2FqSjRaMEZCUWtGTlFWSjZRa1pCYVVWQmFYQnZZM04wTURaVllYVjBSMFJ6Vm14aWNGTllSVFpZY0c5WVRUVTRNRE5UZWpob2MyRkVUM2QyVFVNS1NVSXlTM1ZsSzFRd0wwb3JZV0Y2VVhaSVIxbzVORVU1VkN0WVFUQTVTWGgyVW1rM1EzYzBVV1ZXWmxsTlFXOUhRME54UjFOTk5EbENRVTFFUVRKalFRcE5SMUZEVFVkSE16WmtaRFJNVFZveE1sTTJkMUJYTjJadkwySnZjV2RsU2xCeE5EUnJRMVp5ZW5GWVlteGlLMDVNYTFaVmJVeEdjemQ2VG1GSVVFMVNDbEpqT0ZCU1VVbDNSVWN6VjJ0bllWUmtLMjFLVGtwcFVVb3hVVFZ0WlV3NWVtZHVTM2w0WTFVMWIxaGtUSEp0YVhjMVFuUkpUbTVGWTJ4MlNUUnRjbVVLVFVkSWRIWk9NMFFLTFMwdExTMUZUa1FnUTBWU1ZFbEdTVU5CVkVVdExTMHRMUW89In1dfX0=" + } + ], + "timestampVerificationData": { + "rfc3161Timestamps": [] + } + }, + "dsseEnvelope": { + "payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoicGtnOm5wbS8lNDBvbGlwaGF1bnQvbGlib2xpcGhhdW50LWRhcndpbi1hcm02NEAwLjMuMiIsImRpZ2VzdCI6eyJzaGE1MTIiOiIwMzdhM2UwZTFhNTQ5MWIwMzIzNzk2YmZmMjM3NzMyY2Y3MWVlOGRiMGFlNGFlYjc0ZjJmM2YxODg1MDAxMjczMjY0NDVjYzM5NzQxMzY2OTZmYzRlYmJiYTJiM2NiMmZkYTgzNThmODU2NTJkZGFiNDgxZmU4NmJjNzY2MzJhMSJ9fV0sInByZWRpY2F0ZVR5cGUiOiJodHRwczovL3Nsc2EuZGV2L3Byb3ZlbmFuY2UvdjEiLCJwcmVkaWNhdGUiOnsiYnVpbGREZWZpbml0aW9uIjp7ImJ1aWxkVHlwZSI6Imh0dHBzOi8vc2xzYS1mcmFtZXdvcmsuZ2l0aHViLmlvL2dpdGh1Yi1hY3Rpb25zLWJ1aWxkdHlwZXMvd29ya2Zsb3cvdjEiLCJleHRlcm5hbFBhcmFtZXRlcnMiOnsid29ya2Zsb3ciOnsicmVmIjoicmVmcy9oZWFkcy9tYWluIiwicmVwb3NpdG9yeSI6Imh0dHBzOi8vZ2l0aHViLmNvbS9mMHJyMC9vbGlwaGF1bnQiLCJwYXRoIjoiLmdpdGh1Yi93b3JrZmxvd3MvcmVsZWFzZS55bWwifX0sImludGVybmFsUGFyYW1ldGVycyI6eyJnaXRodWIiOnsiZXZlbnRfbmFtZSI6IndvcmtmbG93X2Rpc3BhdGNoIiwicmVwb3NpdG9yeV9pZCI6IjEwNjUwNTkxMTQiLCJyZXBvc2l0b3J5X293bmVyX2lkIjoiODU3NDIxOSJ9fSwicmVzb2x2ZWREZXBlbmRlbmNpZXMiOlt7InVyaSI6ImdpdCtodHRwczovL2dpdGh1Yi5jb20vZjBycjAvb2xpcGhhdW50QHJlZnMvaGVhZHMvbWFpbiIsImRpZ2VzdCI6eyJnaXRDb21taXQiOiIzMWI1ODAzZDgwY2UzODg0YTFmYzJkM2U5YWI4NjlkZDczM2I0NjFjIn19XX0sInJ1bkRldGFpbHMiOnsiYnVpbGRlciI6eyJpZCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9hY3Rpb25zL3J1bm5lci9naXRodWItaG9zdGVkIn0sIm1ldGFkYXRhIjp7Imludm9jYXRpb25JZCI6Imh0dHBzOi8vZ2l0aHViLmNvbS9mMHJyMC9vbGlwaGF1bnQvYWN0aW9ucy9ydW5zLzM3NTgzNTY5MzQ4L2F0dGVtcHRzLzEifX19fQ==", + "payloadType": "application/vnd.in-toto+json", + "signatures": [ + { + "sig": "MEYCIQDyE5fySghZFc1Lu4A4DbB/Uk4YXZlT7OMW6HEyzwN5jAIhAM+hluMtAB+Jfy3fwAvN5mupyv2uFtnGZjF1012r4Uwu", + "keyid": "" + } + ] + } + } + } + ] +} diff --git a/build_defs/release/native-0.3.2-npm-macos-arm64.json b/build_defs/release/native-0.3.2-npm-macos-arm64.json new file mode 100644 index 000000000..f3c9decf8 --- /dev/null +++ b/build_defs/release/native-0.3.2-npm-macos-arm64.json @@ -0,0 +1,89 @@ +{ + "os": [ + "darwin" + ], + "cpu": [ + "arm64" + ], + "bugs": { + "url": "https://github.com/f0rr0/oliphaunt/issues" + }, + "dist": { + "shasum": "9cb6f46cb35004b5234b3da595de5b5c4300d7a0", + "tarball": "https://registry.npmjs.org/@oliphaunt/liboliphaunt-darwin-arm64/-/liboliphaunt-darwin-arm64-0.3.2.tgz", + "fileCount": 733, + "integrity": "sha512-A3o+DhpUkbAyN5a/8jdzLPce6NsK5K63Ty8/GIUAEnMmRFzDl0E2aW/E67uis8sv2oNY+FZS3atIH+hrx2YyoQ==", + "signatures": [ + { + "sig": "MEQCIDSmb2GqQovIM8bT7oTH410YA9Pbj132S0+TrhIMITvnAiAGu27RgzyPqY6PICVvi5zD8eG1BnQgTEIlw0HSypC2qg==", + "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + }, + { + "sig": "MEUCIQDJC/qWp6aLtNSFnYaEed5a6U8Hwf7zK6S+/EO4YuWncwIgBhciZI+5XvYKeiqRoFnc/OcyhgJwBc8YmZJjhYNuQRM=", + "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + } + ], + "attestations": { + "url": "https://registry.npmjs.org/-/npm/v1/attestations/@oliphaunt%2fliboliphaunt-darwin-arm64@0.3.2", + "provenance": { + "predicateType": "https://slsa.dev/provenance/v1" + } + }, + "unpackedSize": 32395953 + }, + "name": "@oliphaunt/liboliphaunt-darwin-arm64", + "type": "module", + "_from": "file:/home/runner/work/oliphaunt/oliphaunt/target/release/npm-packages/oliphaunt-liboliphaunt-darwin-arm64/oliphaunt-liboliphaunt-darwin-arm64-0.3.2.tgz", + "exports": { + "./package.json": "./package.json" + }, + "license": "MIT AND PostgreSQL AND Unicode-3.0", + "_npmUser": { + "name": "GitHub Actions", + "email": "npm-oidc-no-reply@github.com", + "trustedPublisher": { + "id": "github", + "oidcConfigId": "b0df802e-6cd6-482e-ba73-2c28a4c19fe4" + } + }, + "homepage": "https://github.com/f0rr0/oliphaunt#readme", + "optional": true, + "_resolved": "/home/runner/work/oliphaunt/oliphaunt/target/release/npm-packages/oliphaunt-liboliphaunt-darwin-arm64/oliphaunt-liboliphaunt-darwin-arm64-0.3.2.tgz", + "oliphaunt": { + "target": "macos-arm64", + "libraryRelativePath": "lib/liboliphaunt.dylib", + "runtimeRelativePath": "runtime" + }, + "_integrity": "sha512-A3o+DhpUkbAyN5a/8jdzLPce6NsK5K63Ty8/GIUAEnMmRFzDl0E2aW/E67uis8sv2oNY+FZS3atIH+hrx2YyoQ==", + "repository": { + "url": "git+https://github.com/f0rr0/oliphaunt.git", + "type": "git", + "directory": "src/native/runtime/packages/darwin-arm64" + }, + "_npmVersion": "11.18.0", + "description": "macOS arm64 liboliphaunt native library for Oliphaunt.", + "directories": {}, + "maintainers": [ + { + "name": "oliphaunt", + "email": "sids.outlook.email@gmail.com" + } + ], + "_nodeVersion": "22.22.3", + "publishConfig": { + "access": "public", + "provenance": true, + "executableFiles": [ + "./runtime/bin/initdb", + "./runtime/bin/pg_ctl", + "./runtime/bin/postgres" + ] + }, + "_hasShrinkwrap": false, + "_npmOperationalInternal": { + "tmp": "tmp/liboliphaunt-darwin-arm64_0.3.2_1791359951177_0.8751834618586141", + "host": "s3://npm-registry-packages-npm-production" + }, + "_id": "@oliphaunt/liboliphaunt-darwin-arm64@0.3.2", + "version": "0.3.2" +} diff --git a/build_defs/release/native-0.3.2-npm-windows-x64-msvc-attestations.json b/build_defs/release/native-0.3.2-npm-windows-x64-msvc-attestations.json new file mode 100644 index 000000000..6694ff4a4 --- /dev/null +++ b/build_defs/release/native-0.3.2-npm-windows-x64-msvc-attestations.json @@ -0,0 +1,149 @@ +{ + "attestations": [ + { + "predicateType": "https://github.com/npm/attestation/tree/main/specs/publish/v0.1", + "bundle": { + "mediaType": "application/vnd.dev.sigstore.bundle+json;version=0.2", + "verificationMaterial": { + "publicKey": { + "hint": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + }, + "tlogEntries": [ + { + "logIndex": "3126986377", + "logId": { + "keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0=" + }, + "kindVersion": { + "kind": "dsse", + "version": "0.0.1" + }, + "integratedTime": "1791360540", + "inclusionPromise": { + "signedEntryTimestamp": "MEYCIQDSrE9TdtdHGGaNhHQHO+doZomOyRh79PS5qiL6X8WpOwIhAKQeHZAz3KVAeI3Ajmkky5xDbcbE2v1qn66IcZ7ZrcO8" + }, + "inclusionProof": { + "logIndex": "3005082115", + "rootHash": "BOPH/Dfvjc+4FW/tW4r6qBYzxDUeFhDjJfGW7Ndbcwc=", + "treeSize": "3005082242", + "hashes": [ + "08W6o6k9G0ldoZm+30U44h5BOoLZwIt4nZudjnXD3tI=", + "tyUwQ1Yy8fKpR+VwNRtTzrHl5jf7EV4Rlxrf40XKGYs=", + "XmxakZ7V4erL4shA09gEVnL5S20xqIemagrQPWXbb4Y=", + "o3hRo8x4r6kE7eNEa3eDBDpo8ORyZ5axSS4JbBMk5m4=", + "S1B4+zXPirOSlgKEETCBRNOgLUjqXrXNVsQ/nKuGaJQ=", + "s7NtPa7eTMNogCdhRdDVEJdy5EQ//rZ1m4afyWtA4g0=", + "GWQqFtiwEOInNdqO3ktak6imjg3dZGAyThQWa4mllV8=", + "k/VoMY810w2tFwPJcu3x+QYQ/i2NdMeLg/OAFaXC0m0=", + "O04t/nUOYtjO851e7/iBsxgwHlSJiAExt1kavhFSDPA=", + "dpMUPtBVPWdXKBkBgoOF3gPvQieS7Gs5kWCMGXrg9B8=", + "jezOWf/uQBvZV3FOLzqE2dZwEKW2KnxLv2KpSylQ5fw=", + "jI+EhBE03dGH6P2TPdAbDfkq+OcFavn8VgkzL+ZvqsA=", + "JCiUfwQIRvpzkqfyyw03J2Ivsk77G/rL4+eSugbkyPo=", + "FKI1jW8r0x7ZbsMu5lfC/wN3oR0zNs11XCe2J3wt4eM=", + "elLDQ6wVHMFzMoA8Zyuxzk//O77opXchK8l8wrwAEPE=", + "AITQYGvsxlpdAjbZL+ujvmbDH51sR+4T6G8OCFJbtVA=", + "WymSSAFdY3L1BjserJgGo6PUJWiKIc5OHBM+Xxw2adk=", + "3fRFZuDepJD9y0NjNA9nqInlZuCxNImKQJJfr//qImA=", + "x9rXqkSu8+Vm4yqD2XeAwn305JZ4ZykdOwcD90FjP8o=", + "NlOclldmKPA1tMKIskqHAwuQDYHp31YwpK+OOMrMccc=", + "qxzHanAzz57SDdmJe0B7bJK72NTIBbwEMGBBKvDOROw=", + "xH/DCseLHr9eKoYT8qsORZK7zVdEGYWHuVtsVrD95wY=" + ], + "checkpoint": { + "envelope": "rekor.sigstore.dev - 1193050959916656506\n3005082242\nBOPH/Dfvjc+4FW/tW4r6qBYzxDUeFhDjJfGW7Ndbcwc=\n\n— rekor.sigstore.dev wNI9ajBEAiBSNYnTFrCflQm/NKJoGZfos+9V1PA8oJV5+RCldzTDSAIgSrM0XKwSign6K1JDyCoQXQTs7gmb32az8/6qWvx2coE=\n" + } + }, + "canonicalizedBody": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiZHNzZSIsInNwZWMiOnsiZW52ZWxvcGVIYXNoIjp7ImFsZ29yaXRobSI6InNoYTI1NiIsInZhbHVlIjoiMWEwY2FkOTNmNmJkNzg5MGQ3YjdkY2FhYTllZmViMjQ0ZmY0MDY3MDBmNjY2ODEyM2ZlMDliNzYxMjVmZDNiMiJ9LCJwYXlsb2FkSGFzaCI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6ImQ2OWQyZGRmYjBkYmZkZGNlZTYwYTg5OTk0ZTZiNWVjODg5Zjk1MzI5MmJjOTVlNGQ4MTc1MzJhNjZlY2IxN2YifSwic2lnbmF0dXJlcyI6W3sic2lnbmF0dXJlIjoiTUVVQ0lRREtxcDNGS1M2S2Erd25rK3NMMk02bG1EK1J6cys5RXlOejVtWXpHazVFZ3dJZ2RPNmhrNFUya2JiR1dKN0VIeWcxN2dYeUtidEhTZUNodTdOcFR1d0lENkE9IiwidmVyaWZpZXIiOiJMUzB0TFMxQ1JVZEpUaUJRVlVKTVNVTWdTMFZaTFMwdExTMEtUVVpyZDBWM1dVaExiMXBKZW1vd1EwRlJXVWxMYjFwSmVtb3dSRUZSWTBSUlowRkZXVFpaWVRkWEt5czNZVlZRZW5aTlZISmxla2cyV1dONE0yTXJTQXBQUzFsRFkwNUhlV0pLV2xORFNuRXZabVEzVVdFNGRYVkJTM1JrU1d0VlVYUlJhVVZMUlZKb1FXMUZOV3hOVFVwb1VEaFBhMFJQWVRKblBUMEtMUzB0TFMxRlRrUWdVRlZDVEVsRElFdEZXUzB0TFMwdENnPT0ifV19fQ==" + } + ], + "timestampVerificationData": { + "rfc3161Timestamps": [] + } + }, + "dsseEnvelope": { + "payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInN1YmplY3QiOlt7Im5hbWUiOiJwa2c6bnBtLyU0MG9saXBoYXVudC9saWJvbGlwaGF1bnQtd2luMzIteDY0LW1zdmNAMC4zLjIiLCJkaWdlc3QiOnsic2hhNTEyIjoiMTJlZGUzNjhiYmU4OTUwMTJiOGRkMzdhNjc3NzVkNmExMGQ4MDZjYmE0OWE5YzYzMDE3OGRmYzU4MGYxMTQ4ZTM2NDFlYmQzZDY5MmU4MTJkZDk0OTJlNWQ4NzM0Y2M5NDUwMzc1M2Y2YTcxODQ3ZmE5MDViN2I0MTgzZDc5NTgifX1dLCJwcmVkaWNhdGVUeXBlIjoiaHR0cHM6Ly9naXRodWIuY29tL25wbS9hdHRlc3RhdGlvbi90cmVlL21haW4vc3BlY3MvcHVibGlzaC92MC4xIiwicHJlZGljYXRlIjp7Im5hbWUiOiJAb2xpcGhhdW50L2xpYm9saXBoYXVudC13aW4zMi14NjQtbXN2YyIsInZlcnNpb24iOiIwLjMuMiIsInJlZ2lzdHJ5IjoiaHR0cHM6Ly9yZWdpc3RyeS5ucG1qcy5vcmcifX0=", + "payloadType": "application/vnd.in-toto+json", + "signatures": [ + { + "sig": "MEUCIQDKqp3FKS6Ka+wnk+sL2M6lmD+Rzs+9EyNz5mYzGk5EgwIgdO6hk4U2kbbGWJ7EHyg17gXyKbtHSeChu7NpTuwID6A=", + "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + } + ] + } + } + }, + { + "predicateType": "https://slsa.dev/provenance/v1", + "bundle": { + "mediaType": "application/vnd.dev.sigstore.bundle.v0.3+json", + "verificationMaterial": { + "certificate": { + "rawBytes": "MIIG9DCCBnmgAwIBAgIUPgsOR3Z5ZDq5KWjsir7jpQUz9rswCgYIKoZIzj0EAwMwNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwHhcNMjYxMDA3MDgwNjQwWhcNMjYxMDA3MDgxNjQwWjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE+P0XPz5wHAhMv/zTuoRXUonjjgwKQL3wLXlSlgGRemWYoVZXIrzPEHdNrBBoYxxJ7Me85WyFRc2MC0G2ARiYG6OCBZgwggWUMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAfBgNVHSMEGDAWgBTf0+nPViQRlvmo2OkoVaLGLhhkPzBeBgNVHREBAf8EVDBShlBodHRwczovL2dpdGh1Yi5jb20vZjBycjAvb2xpcGhhdW50Ly5naXRodWIvd29ya2Zsb3dzL3JlbGVhc2UueW1sQHJlZnMvaGVhZHMvbWFpbjA5BgorBgEEAYO/MAEBBCtodHRwczovL3Rva2VuLmFjdGlvbnMuZ2l0aHVidXNlcmNvbnRlbnQuY29tMB8GCisGAQQBg78wAQIEEXdvcmtmbG93X2Rpc3BhdGNoMDYGCisGAQQBg78wAQMEKDMxYjU4MDNkODBjZTM4ODRhMWZjMmQzZTlhYjg2OWRkNzMzYjQ2MWMwFQYKKwYBBAGDvzABBAQHUmVsZWFzZTAdBgorBgEEAYO/MAEFBA9mMHJyMC9vbGlwaGF1bnQwHQYKKwYBBAGDvzABBgQPcmVmcy9oZWFkcy9tYWluMDsGCisGAQQBg78wAQgELQwraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1YnVzZXJjb250ZW50LmNvbTBgBgorBgEEAYO/MAEJBFIMUGh0dHBzOi8vZ2l0aHViLmNvbS9mMHJyMC9vbGlwaGF1bnQvLmdpdGh1Yi93b3JrZmxvd3MvcmVsZWFzZS55bWxAcmVmcy9oZWFkcy9tYWluMDgGCisGAQQBg78wAQoEKgwoMzFiNTgwM2Q4MGNlMzg4NGExZmMyZDNlOWFiODY5ZGQ3MzNiNDYxYzAdBgorBgEEAYO/MAELBA8MDWdpdGh1Yi1ob3N0ZWQwMgYKKwYBBAGDvzABDAQkDCJodHRwczovL2dpdGh1Yi5jb20vZjBycjAvb2xpcGhhdW50MDgGCisGAQQBg78wAQ0EKgwoMzFiNTgwM2Q4MGNlMzg4NGExZmMyZDNlOWFiODY5ZGQ3MzNiNDYxYzAfBgorBgEEAYO/MAEOBBEMD3JlZnMvaGVhZHMvbWFpbjAaBgorBgEEAYO/MAEPBAwMCjEwNjUwNTkxMTQwKAYKKwYBBAGDvzABEAQaDBhodHRwczovL2dpdGh1Yi5jb20vZjBycjAwFwYKKwYBBAGDvzABEQQJDAc4NTc0MjE5MGAGCisGAQQBg78wARIEUgxQaHR0cHM6Ly9naXRodWIuY29tL2YwcnIwL29saXBoYXVudC8uZ2l0aHViL3dvcmtmbG93cy9yZWxlYXNlLnltbEByZWZzL2hlYWRzL21haW4wOAYKKwYBBAGDvzABEwQqDCgzMWI1ODAzZDgwY2UzODg0YTFmYzJkM2U5YWI4NjlkZDczM2I0NjFjMCEGCisGAQQBg78wARQEEwwRd29ya2Zsb3dfZGlzcGF0Y2gwVgYKKwYBBAGDvzABFQRIDEZodHRwczovL2dpdGh1Yi5jb20vZjBycjAvb2xpcGhhdW50L2FjdGlvbnMvcnVucy8zNzU4MzU2OTM0OC9hdHRlbXB0cy8xMBYGCisGAQQBg78wARYECAwGcHVibGljMB8GCisGAQQBg78wARcEEQwPcmVsZWFzZS1wdWJsaXNoMEAGCisGAQQBg78wARgEMgwwcmVwbzpmMHJyMC9vbGlwaGF1bnQ6ZW52aXJvbm1lbnQ6cmVsZWFzZS1wdWJsaXNoMIGKBgorBgEEAdZ5AgQCBHwEegB4AHYA3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4AAAGhFWZ+YwAABAMARzBFAiEAq4bp5BO+DknkenUajf8X6xK7faw9ngIKSTd5kkn/uKYCIGf5bJwzXYfvjEwzsb5LvvJoBE0uxhcximE8ZacTcFYWMAoGCCqGSM49BAMDA2kAMGYCMQCI6GoYigcCmbGU1QBTsMYYVlSOctt1ye/R/G0oOc9VdZgVz85Av4ER/oSCysiuTxoCMQCHRlnKqhY8B+mYxwzVghfdr2Gda0ar2aQvUr3Rp6AkcHRymAiAxoBCTUcmbKDnreU=" + }, + "tlogEntries": [ + { + "logIndex": "3126953854", + "logId": { + "keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0=" + }, + "kindVersion": { + "kind": "dsse", + "version": "0.0.1" + }, + "integratedTime": "1791360401", + "inclusionPromise": { + "signedEntryTimestamp": "MEUCIB7zdzIHzp151J4l3mF8Vwi8eFWRtCMwcEYSZtNztgzaAiEAnBbZp3AU/qWcAuRMhDtybmRX/LGMVXvis2ZXCGmv4y8=" + }, + "inclusionProof": { + "logIndex": "3005049592", + "rootHash": "fZRLOtD6RmQsxHngM5XzeHTWfS1HEVQI9juyBwzbJO8=", + "treeSize": "3005049597", + "hashes": [ + "h70TemEGTUOgy8zyO5H5D9MAVkX9VEaD//kACOiGgzA=", + "ty6NnLGAKWGgri63TnxJXBAFrbJ1fq8Jp5NR3shux1I=", + "jHiLNoQkAudK5+S1qGm8T4EvTf8cTCtUMoZtvG41AN4=", + "XZDkCqw0EMGn7/5lFaVMRUuqyB6Wl7TOLSgUN518nFo=", + "alfF6UwtH1Uxa8nZZ4z+gzsWqGMYk1+C+UmGF+sU01Y=", + "JP4c8NriYq+Jm+Nk1/uuqbp3foSnQD7505u4oifIOT4=", + "v9W+qEbctSM3YsOpwNf9K+1yTEA1jr+ijM7lq0+ILeA=", + "3tp5tBA3cYmOvJjoxq5xUegFChOWvC0AH+ZLLKyuG4o=", + "8VxDfmV7wdqzhLGum+faBFfWbogh6FgXy1NoJQKrovM=", + "Zg08aq832NjpZAp9mS2oNNOM8687dWxsKvGM6d5F0L4=", + "KHdd8M7bgCVGHfT4D14C+HfLDXHgvqpLfO4cVzNkTmE=", + "3MNgc+JUINhpQJAbwAoxYccj2ouSmbLMjmGe3DWdbHM=", + "FKI1jW8r0x7ZbsMu5lfC/wN3oR0zNs11XCe2J3wt4eM=", + "elLDQ6wVHMFzMoA8Zyuxzk//O77opXchK8l8wrwAEPE=", + "AITQYGvsxlpdAjbZL+ujvmbDH51sR+4T6G8OCFJbtVA=", + "WymSSAFdY3L1BjserJgGo6PUJWiKIc5OHBM+Xxw2adk=", + "3fRFZuDepJD9y0NjNA9nqInlZuCxNImKQJJfr//qImA=", + "x9rXqkSu8+Vm4yqD2XeAwn305JZ4ZykdOwcD90FjP8o=", + "NlOclldmKPA1tMKIskqHAwuQDYHp31YwpK+OOMrMccc=", + "qxzHanAzz57SDdmJe0B7bJK72NTIBbwEMGBBKvDOROw=", + "xH/DCseLHr9eKoYT8qsORZK7zVdEGYWHuVtsVrD95wY=" + ], + "checkpoint": { + "envelope": "rekor.sigstore.dev - 1193050959916656506\n3005049597\nfZRLOtD6RmQsxHngM5XzeHTWfS1HEVQI9juyBwzbJO8=\n\n— rekor.sigstore.dev wNI9ajBGAiEApiujR/7TyTKBkNS7uyq4jW5CXqGSC7Jnh6hKHN17vKECIQDA9gAUW6keQuQ8ays5MhyrKWKLdct1aKIg3G1r4C53Iw==\n" + } + }, + "canonicalizedBody": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiZHNzZSIsInNwZWMiOnsiZW52ZWxvcGVIYXNoIjp7ImFsZ29yaXRobSI6InNoYTI1NiIsInZhbHVlIjoiZGU4Mjc3ZDA4MTZkZWRhNDYyYzk4OTAzYzFhZjZiMjliYzE1ZGE2OGMxNmQ2NWY1MDM3MjNkNDA4Yjg0MTFiMCJ9LCJwYXlsb2FkSGFzaCI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6ImU5ZDI4NTllNjA2NzE2YTAxYmRhYTFiYmQwZDk4NDE0ZGQzNTBjMjIyZDZkMDkwYWRlNTkzODUyNWE3ZDU2ZmEifSwic2lnbmF0dXJlcyI6W3sic2lnbmF0dXJlIjoiTUVRQ0lGaFNvMGsvMC94UlhxUEVYUWl2T2RxNUpyQW5JZ25rS3RNL0xJT3NlalFFQWlCZlo1S201OUcveVJGRUF3Wk04UDJvNmJvN1RRbklaSlJGQkw1dHd5N2o1UT09IiwidmVyaWZpZXIiOiJMUzB0TFMxQ1JVZEpUaUJEUlZKVVNVWkpRMEZVUlMwdExTMHRDazFKU1VjNVJFTkRRbTV0WjBGM1NVSkJaMGxWVUdkelQxSXpXalZhUkhFMVMxZHFjMmx5TjJwd1VWVjZPWEp6ZDBObldVbExiMXBKZW1vd1JVRjNUWGNLVG5wRlZrMUNUVWRCTVZWRlEyaE5UV015Ykc1ak0xSjJZMjFWZFZwSFZqSk5ValIzU0VGWlJGWlJVVVJGZUZaNllWZGtlbVJIT1hsYVV6RndZbTVTYkFwamJURnNXa2RzYUdSSFZYZElhR05PVFdwWmVFMUVRVE5OUkdkM1RtcFJkMWRvWTA1TmFsbDRUVVJCTTAxRVozaE9hbEYzVjJwQlFVMUdhM2RGZDFsSUNrdHZXa2w2YWpCRFFWRlpTVXR2V2tsNmFqQkVRVkZqUkZGblFVVXJVREJZVUhvMWQwaEJhRTEyTDNwVWRXOVNXRlZ2Ym1wcVozZExVVXd6ZDB4WWJGTUtiR2RIVW1WdFYxbHZWbHBZU1hKNlVFVklaRTV5UWtKdldYaDRTamROWlRnMVYzbEdVbU15VFVNd1J6SkJVbWxaUnpaUFEwSmFaM2RuWjFkVlRVRTBSd3BCTVZWa1JIZEZRaTkzVVVWQmQwbElaMFJCVkVKblRsWklVMVZGUkVSQlMwSm5aM0pDWjBWR1FsRmpSRUY2UVdaQ1owNVdTRk5OUlVkRVFWZG5RbFJtQ2pBcmJsQldhVkZTYkhadGJ6SlBhMjlXWVV4SFRHaG9hMUI2UW1WQ1owNVdTRkpGUWtGbU9FVldSRUpUYUd4Q2IyUklVbmRqZW05MlRESmtjR1JIYURFS1dXazFhbUl5TUhaYWFrSjVZMnBCZG1JeWVIQmpSMmhvWkZjMU1FeDVOVzVoV0ZKdlpGZEpkbVF5T1hsaE1scHpZak5rZWt3elNteGlSMVpvWXpKVmRRcGxWekZ6VVVoS2JGcHVUWFpoUjFab1draE5kbUpYUm5CaWFrRTFRbWR2Y2tKblJVVkJXVTh2VFVGRlFrSkRkRzlrU0ZKM1kzcHZka3d6VW5aaE1sWjFDa3h0Um1wa1IyeDJZbTVOZFZveWJEQmhTRlpwWkZoT2JHTnRUblppYmxKc1ltNVJkVmt5T1hSTlFqaEhRMmx6UjBGUlVVSm5OemgzUVZGSlJVVllaSFlLWTIxMGJXSkhPVE5ZTWxKd1l6TkNhR1JIVG05TlJGbEhRMmx6UjBGUlVVSm5OemgzUVZGTlJVdEVUWGhaYWxVMFRVUk9hMDlFUW1wYVZFMDBUMFJTYUFwTlYxcHFUVzFSZWxwVWJHaFphbWN5VDFkU2EwNTZUWHBaYWxFeVRWZE5kMFpSV1V0TGQxbENRa0ZIUkhaNlFVSkNRVkZJVlcxV2MxcFhSbnBhVkVGa0NrSm5iM0pDWjBWRlFWbFBMMDFCUlVaQ1FUbHRUVWhLZVUxRE9YWmlSMngzWVVkR01XSnVVWGRJVVZsTFMzZFpRa0pCUjBSMmVrRkNRbWRSVUdOdFZtMEtZM2s1YjFwWFJtdGplVGwwV1Zkc2RVMUVjMGREYVhOSFFWRlJRbWMzT0hkQlVXZEZURkYzY21GSVVqQmpTRTAyVEhrNU1HSXlkR3hpYVRWb1dUTlNjQXBpTWpWNlRHMWtjR1JIYURGWmJsWjZXbGhLYW1JeU5UQmFWelV3VEcxT2RtSlVRbWRDWjI5eVFtZEZSVUZaVHk5TlFVVktRa1pKVFZWSGFEQmtTRUo2Q2s5cE9IWmFNbXd3WVVoV2FVeHRUblppVXpsdFRVaEtlVTFET1haaVIyeDNZVWRHTVdKdVVYWk1iV1J3WkVkb01WbHBPVE5pTTBweVdtMTRkbVF6VFhZS1kyMVdjMXBYUm5wYVV6VTFZbGQ0UVdOdFZtMWplVGx2V2xkR2EyTjVPWFJaVjJ4MVRVUm5SME5wYzBkQlVWRkNaemM0ZDBGUmIwVkxaM2R2VFhwR2FRcE9WR2QzVFRKUk5FMUhUbXhOZW1jMFRrZEZlRnB0VFhsYVJFNXNUMWRHYVU5RVdUVmFSMUV6VFhwT2FVNUVXWGhaZWtGa1FtZHZja0puUlVWQldVOHZDazFCUlV4Q1FUaE5SRmRrY0dSSGFERlphVEZ2WWpOT01GcFhVWGROWjFsTFMzZFpRa0pCUjBSMmVrRkNSRUZSYTBSRFNtOWtTRkozWTNwdmRrd3laSEFLWkVkb01WbHBOV3BpTWpCMldtcENlV05xUVhaaU1uaHdZMGRvYUdSWE5UQk5SR2RIUTJselIwRlJVVUpuTnpoM1FWRXdSVXRuZDI5TmVrWnBUbFJuZHdwTk1sRTBUVWRPYkUxNlp6Uk9SMFY0V20xTmVWcEVUbXhQVjBacFQwUlpOVnBIVVROTmVrNXBUa1JaZUZsNlFXWkNaMjl5UW1kRlJVRlpUeTlOUVVWUENrSkNSVTFFTTBwc1dtNU5kbUZIVm1oYVNFMTJZbGRHY0dKcVFXRkNaMjl5UW1kRlJVRlpUeTlOUVVWUVFrRjNUVU5xUlhkT2FsVjNUbFJyZUUxVVVYY0tTMEZaUzB0M1dVSkNRVWRFZG5wQlFrVkJVV0ZFUW1odlpFaFNkMk42YjNaTU1tUndaRWRvTVZscE5XcGlNakIyV21wQ2VXTnFRWGRHZDFsTFMzZFpRZ3BDUVVkRWRucEJRa1ZSVVVwRVFXTTBUbFJqTUUxcVJUVk5SMEZIUTJselIwRlJVVUpuTnpoM1FWSkpSVlZuZUZGaFNGSXdZMGhOTmt4NU9XNWhXRkp2Q21SWFNYVlpNamwwVERKWmQyTnVTWGRNTWpsellWaENiMWxZVm5Wa1F6aDFXakpzTUdGSVZtbE1NMlIyWTIxMGJXSkhPVE5qZVRsNVdsZDRiRmxZVG13S1RHNXNkR0pGUW5sYVYxcDZUREpvYkZsWFVucE1NakZvWVZjMGQwOUJXVXRMZDFsQ1FrRkhSSFo2UVVKRmQxRnhSRU5uZWsxWFNURlBSRUY2V2tSbmR3cFpNbFY2VDBSbk1GbFVSbTFaZWtwclRUSlZOVmxYU1RST2FteHJXa1JqZWsweVNUQk9ha1pxVFVORlIwTnBjMGRCVVZGQ1p6YzRkMEZTVVVWRmQzZFNDbVF5T1hsaE1scHpZak5rWmxwSGJIcGpSMFl3V1RKbmQxWm5XVXRMZDFsQ1FrRkhSSFo2UVVKR1VWSkpSRVZhYjJSSVVuZGplbTkyVERKa2NHUkhhREVLV1drMWFtSXlNSFphYWtKNVkycEJkbUl5ZUhCalIyaG9aRmMxTUV3eVJtcGtSMngyWW01TmRtTnVWblZqZVRoNlRucFZORTE2VlRKUFZFMHdUME01YUFwa1NGSnNZbGhDTUdONU9IaE5RbGxIUTJselIwRlJVVUpuTnpoM1FWSlpSVU5CZDBkalNGWnBZa2RzYWsxQ09FZERhWE5IUVZGUlFtYzNPSGRCVW1ORkNrVlJkMUJqYlZaeldsZEdlbHBUTVhka1YwcHpZVmhPYjAxRlFVZERhWE5IUVZGUlFtYzNPSGRCVW1kRlRXZDNkMk50Vm5kaWVuQnRUVWhLZVUxRE9YWUtZa2RzZDJGSFJqRmlibEUyV2xjMU1tRllTblppYlRGc1ltNVJObU50Vm5OYVYwWjZXbE14ZDJSWFNuTmhXRTV2VFVsSFMwSm5iM0pDWjBWRlFXUmFOUXBCWjFGRFFraDNSV1ZuUWpSQlNGbEJNMVF3ZDJGellraEZWRXBxUjFJMFkyMVhZek5CY1VwTFdISnFaVkJMTXk5b05IQjVaME00Y0Rkdk5FRkJRVWRvQ2taWFdpdFpkMEZCUWtGTlFWSjZRa1pCYVVWQmNUUmljRFZDVHl0RWEyNXJaVzVWWVdwbU9GZzJlRXMzWm1GM09XNW5TVXRUVkdRMWEydHVMM1ZMV1VNS1NVZG1OV0pLZDNwWVdXWjJha1YzZW5OaU5VeDJka3B2UWtVd2RYaG9ZM2hwYlVVNFdtRmpWR05HV1ZkTlFXOUhRME54UjFOTk5EbENRVTFFUVRKclFRcE5SMWxEVFZGRFNUWkhiMWxwWjJORGJXSkhWVEZSUWxSelRWbFpWbXhUVDJOMGRERjVaUzlTTDBjd2IwOWpPVlprV21kV2VqZzFRWFkwUlZJdmIxTkRDbmx6YVhWVWVHOURUVkZEU0ZKc2JrdHhhRms0UWl0dFdYaDNlbFpuYUdaa2NqSkhaR0V3WVhJeVlWRjJWWEl6VW5BMlFXdGpTRko1YlVGcFFYaHZRa01LVkZWamJXSkxSRzV5WlZVOUNpMHRMUzB0UlU1RUlFTkZVbFJKUmtsRFFWUkZMUzB0TFMwSyJ9XX19" + } + ], + "timestampVerificationData": { + "rfc3161Timestamps": [] + } + }, + "dsseEnvelope": { + "payload": "eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjEiLCJzdWJqZWN0IjpbeyJuYW1lIjoicGtnOm5wbS8lNDBvbGlwaGF1bnQvbGlib2xpcGhhdW50LXdpbjMyLXg2NC1tc3ZjQDAuMy4yIiwiZGlnZXN0Ijp7InNoYTUxMiI6IjEyZWRlMzY4YmJlODk1MDEyYjhkZDM3YTY3Nzc1ZDZhMTBkODA2Y2JhNDlhOWM2MzAxNzhkZmM1ODBmMTE0OGUzNjQxZWJkM2Q2OTJlODEyZGQ5NDkyZTVkODczNGNjOTQ1MDM3NTNmNmE3MTg0N2ZhOTA1YjdiNDE4M2Q3OTU4In19XSwicHJlZGljYXRlVHlwZSI6Imh0dHBzOi8vc2xzYS5kZXYvcHJvdmVuYW5jZS92MSIsInByZWRpY2F0ZSI6eyJidWlsZERlZmluaXRpb24iOnsiYnVpbGRUeXBlIjoiaHR0cHM6Ly9zbHNhLWZyYW1ld29yay5naXRodWIuaW8vZ2l0aHViLWFjdGlvbnMtYnVpbGR0eXBlcy93b3JrZmxvdy92MSIsImV4dGVybmFsUGFyYW1ldGVycyI6eyJ3b3JrZmxvdyI6eyJyZWYiOiJyZWZzL2hlYWRzL21haW4iLCJyZXBvc2l0b3J5IjoiaHR0cHM6Ly9naXRodWIuY29tL2YwcnIwL29saXBoYXVudCIsInBhdGgiOiIuZ2l0aHViL3dvcmtmbG93cy9yZWxlYXNlLnltbCJ9fSwiaW50ZXJuYWxQYXJhbWV0ZXJzIjp7ImdpdGh1YiI6eyJldmVudF9uYW1lIjoid29ya2Zsb3dfZGlzcGF0Y2giLCJyZXBvc2l0b3J5X2lkIjoiMTA2NTA1OTExNCIsInJlcG9zaXRvcnlfb3duZXJfaWQiOiI4NTc0MjE5In19LCJyZXNvbHZlZERlcGVuZGVuY2llcyI6W3sidXJpIjoiZ2l0K2h0dHBzOi8vZ2l0aHViLmNvbS9mMHJyMC9vbGlwaGF1bnRAcmVmcy9oZWFkcy9tYWluIiwiZGlnZXN0Ijp7ImdpdENvbW1pdCI6IjMxYjU4MDNkODBjZTM4ODRhMWZjMmQzZTlhYjg2OWRkNzMzYjQ2MWMifX1dfSwicnVuRGV0YWlscyI6eyJidWlsZGVyIjp7ImlkIjoiaHR0cHM6Ly9naXRodWIuY29tL2FjdGlvbnMvcnVubmVyL2dpdGh1Yi1ob3N0ZWQifSwibWV0YWRhdGEiOnsiaW52b2NhdGlvbklkIjoiaHR0cHM6Ly9naXRodWIuY29tL2YwcnIwL29saXBoYXVudC9hY3Rpb25zL3J1bnMvMzc1ODM1NjkzNDgvYXR0ZW1wdHMvMSJ9fX19", + "payloadType": "application/vnd.in-toto+json", + "signatures": [ + { + "sig": "MEQCIFhSo0k/0/xRXqPEXQivOdq5JrAnIgnkKtM/LIOsejQEAiBfZ5Km59G/yRFEAwZM8P2o6bo7TQnIZJRFBL5twy7j5Q==", + "keyid": "" + } + ] + } + } + } + ] +} diff --git a/build_defs/release/native-0.3.2-npm-windows-x64-msvc.json b/build_defs/release/native-0.3.2-npm-windows-x64-msvc.json new file mode 100644 index 000000000..378f00667 --- /dev/null +++ b/build_defs/release/native-0.3.2-npm-windows-x64-msvc.json @@ -0,0 +1,89 @@ +{ + "os": [ + "win32" + ], + "cpu": [ + "x64" + ], + "bugs": { + "url": "https://github.com/f0rr0/oliphaunt/issues" + }, + "dist": { + "shasum": "ffb866b389c2eecf6b07270e5572e9cbd2312a65", + "tarball": "https://registry.npmjs.org/@oliphaunt/liboliphaunt-win32-x64-msvc/-/liboliphaunt-win32-x64-msvc-0.3.2.tgz", + "fileCount": 816, + "integrity": "sha512-Eu3jaLvolQErjdN6Z3ddahDYBsukmpxjAXjfxYDxFI42QevT1pLoEt2UkuXYc0zJRQN1P2pxhH+pBbe0GD15WA==", + "signatures": [ + { + "sig": "MEQCIGniIvM+XMvJuliphkPFFWFZUBsUSrBwxEa54GdEjdrfAiBMVAiXAmsz6cSczVw5zqmUbM+roxKAcu8kmtYEPPa17A==", + "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + }, + { + "sig": "MEUCICvRhgv8gR8w7JxyeQdR6U8yDBmywW7rtVylAYPVAadTAiEAgCAbX+TNcdfsz3HiCasGBq2w0IrZVdcdyT+ECInbabU=", + "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + } + ], + "attestations": { + "url": "https://registry.npmjs.org/-/npm/v1/attestations/@oliphaunt%2fliboliphaunt-win32-x64-msvc@0.3.2", + "provenance": { + "predicateType": "https://slsa.dev/provenance/v1" + } + }, + "unpackedSize": 64615340 + }, + "name": "@oliphaunt/liboliphaunt-win32-x64-msvc", + "type": "module", + "_from": "file:/home/runner/work/oliphaunt/oliphaunt/target/release/npm-packages/oliphaunt-liboliphaunt-win32-x64-msvc/oliphaunt-liboliphaunt-win32-x64-msvc-0.3.2.tgz", + "exports": { + "./package.json": "./package.json" + }, + "license": "MIT AND PostgreSQL AND Unicode-3.0", + "_npmUser": { + "name": "GitHub Actions", + "email": "npm-oidc-no-reply@github.com", + "trustedPublisher": { + "id": "github", + "oidcConfigId": "5bf3b6d1-57a9-4a1e-8d22-a82682714810" + } + }, + "homepage": "https://github.com/f0rr0/oliphaunt#readme", + "optional": true, + "_resolved": "/home/runner/work/oliphaunt/oliphaunt/target/release/npm-packages/oliphaunt-liboliphaunt-win32-x64-msvc/oliphaunt-liboliphaunt-win32-x64-msvc-0.3.2.tgz", + "oliphaunt": { + "target": "windows-x64-msvc", + "libraryRelativePath": "bin/oliphaunt.dll", + "runtimeRelativePath": "runtime" + }, + "_integrity": "sha512-Eu3jaLvolQErjdN6Z3ddahDYBsukmpxjAXjfxYDxFI42QevT1pLoEt2UkuXYc0zJRQN1P2pxhH+pBbe0GD15WA==", + "repository": { + "url": "git+https://github.com/f0rr0/oliphaunt.git", + "type": "git", + "directory": "src/native/runtime/packages/win32-x64-msvc" + }, + "_npmVersion": "11.18.0", + "description": "Windows x64 MSVC liboliphaunt native library for Oliphaunt.", + "directories": {}, + "maintainers": [ + { + "name": "oliphaunt", + "email": "sids.outlook.email@gmail.com" + } + ], + "_nodeVersion": "22.22.3", + "publishConfig": { + "access": "public", + "provenance": true, + "executableFiles": [ + "./runtime/bin/initdb.exe", + "./runtime/bin/pg_ctl.exe", + "./runtime/bin/postgres.exe" + ] + }, + "_hasShrinkwrap": false, + "_npmOperationalInternal": { + "tmp": "tmp/liboliphaunt-win32-x64-msvc_0.3.2_1791360538939_0.29245279241943734", + "host": "s3://npm-registry-packages-npm-production" + }, + "_id": "@oliphaunt/liboliphaunt-win32-x64-msvc@0.3.2", + "version": "0.3.2" +} diff --git a/build_defs/release/native-0.3.2-releases.json b/build_defs/release/native-0.3.2-releases.json new file mode 100644 index 000000000..7abc2671c --- /dev/null +++ b/build_defs/release/native-0.3.2-releases.json @@ -0,0 +1,146 @@ +[ + { + "product": "liboliphaunt-native", + "version": "0.3.2", + "tag": "liboliphaunt-native-v0.3.2", + "releaseId": 405480667, + "releaseName": "liboliphaunt-native v0.3.2", + "targetCommitish": "31b5803d80ce3884a1fc2d3e9ab869dd733b461c", + "draft": false, + "prerelease": false, + "assets": [ + { + "assetId": 617903857, + "name": "liboliphaunt-0.3.2-android-arm64-v8a.tar.gz", + "sha256": "64febb7c599ba66074918dee4cdc4af91683d109bcd1df4e05a9a2d54b9e348c", + "size": 5386097 + }, + { + "assetId": 617906008, + "name": "liboliphaunt-0.3.2-android-x86_64.tar.gz", + "sha256": "89f8aa3057155b396b06d708cf38beecc57186a42caff0b48d9af4704b948a09", + "size": 5594884 + }, + { + "assetId": 617908152, + "name": "liboliphaunt-0.3.2-apple-spm-xcframework.zip", + "sha256": "915ea189f2ad74ac31fc4402dc31f00d4f42c4dcfe73e360db7cd0f36419dec8", + "size": 37968414 + }, + { + "assetId": 617910342, + "name": "liboliphaunt-0.3.2-ios-xcframework.tar.gz", + "sha256": "cd1e89e1b79acc6b69ecc15cfec9f487722049b92706a2f0d79c834a808d0514", + "size": 38770258 + }, + { + "assetId": 617912324, + "name": "liboliphaunt-0.3.2-linux-arm64-gnu.tar.gz", + "sha256": "65a37b4658cec4dcbe2390652c90d15dff64e447757258a96629f58bf1fd8c3b", + "size": 13778606 + }, + { + "assetId": 617913936, + "name": "liboliphaunt-0.3.2-linux-x64-gnu.tar.gz", + "sha256": "cb7aecb19398198c4c3ae48b95b0c7ce3ee4c90e5e7e783608f29ae2b84d55aa", + "size": 14152293 + }, + { + "assetId": 617915743, + "name": "liboliphaunt-0.3.2-macos-arm64.tar.gz", + "sha256": "95533e3beecae8c3e235efc7821d7057a8960b7eade5402b217f32221b3b4852", + "size": 12407735 + }, + { + "assetId": 617918335, + "name": "liboliphaunt-0.3.2-release-assets.sha256", + "sha256": "6a0b45068d50e5b02378b205e052561cb855ae636223d96ec91f4e8dac0da5a2", + "size": 1128 + }, + { + "assetId": 617920849, + "name": "liboliphaunt-0.3.2-runtime-resources-android-datum64.tar.gz", + "sha256": "5525d1c9a8f1b1325a17c27acbf3e9e58d7eae87d201eba3587866427fb655d7", + "size": 9601301 + }, + { + "assetId": 617923340, + "name": "liboliphaunt-0.3.2-runtime-resources-ios-datum64.tar.gz", + "sha256": "44409f9a63382d2ffb51e380df69df4323078b2ce6e806de6e9adcc3729bd20e", + "size": 7901759 + }, + { + "assetId": 617925129, + "name": "liboliphaunt-0.3.2-windows-x64-msvc.zip", + "sha256": "6df6d8fae057a554f15abf63ba05aad80846ecf9f11eb61475accafc58fa45a9", + "size": 41445885 + }, + { + "assetId": 617926860, + "name": "oliphaunt-extension-contrib-pg18-0.3.2-manifest.json", + "sha256": "5b347c0e9ec91c800572603fd323cc34295fa06b0247129e06ad43894c1da756", + "size": 399825 + }, + { + "assetId": 617928974, + "name": "oliphaunt-extension-contrib-pg18-0.3.2-manifest.properties", + "sha256": "c9daa3d344c7abd11ecf627a90effd90ef860878e5ad176d0bffa10cf0ade21e", + "size": 86679 + }, + { + "assetId": 617930789, + "name": "oliphaunt-extension-contrib-pg18-0.3.2-native-android-arm64-v8a-bundle.tar.gz", + "sha256": "468f850c41a4a0a0c8dbb39b03e92c3b18fe6260a006681c9fff6e3146e8d0ed", + "size": 4388780 + }, + { + "assetId": 617931403, + "name": "oliphaunt-extension-contrib-pg18-0.3.2-native-android-x86_64-bundle.tar.gz", + "sha256": "66967105d32255854f38e4d2c6bd31556209baca0ecc07fab66b0f3111d463b9", + "size": 3952020 + }, + { + "assetId": 617932218, + "name": "oliphaunt-extension-contrib-pg18-0.3.2-native-ios-xcframework-bundle.tar.gz", + "sha256": "dffa89d464984179a042c1ccca56f58af3f5581a51f29d05a0fd56e1b484f443", + "size": 20950350 + }, + { + "assetId": 617932966, + "name": "oliphaunt-extension-contrib-pg18-0.3.2-native-linux-arm64-gnu-bundle.tar.gz", + "sha256": "899841df7028960db7ce08b17e44dd7f7a3eac65b1d6abc5ffe4e44b9280c764", + "size": 1029686 + }, + { + "assetId": 617933583, + "name": "oliphaunt-extension-contrib-pg18-0.3.2-native-linux-x64-gnu-bundle.tar.gz", + "sha256": "f89c58a89c1f895ec793ff02d8d153693931b66685258c92fe70915db946e5ca", + "size": 978418 + }, + { + "assetId": 617934260, + "name": "oliphaunt-extension-contrib-pg18-0.3.2-native-macos-arm64-bundle.tar.gz", + "sha256": "7ed91c9697934afad480769981c70f38509197afd22945a67e785b68a000aa60", + "size": 5250439 + }, + { + "assetId": 617934997, + "name": "oliphaunt-extension-contrib-pg18-0.3.2-native-windows-x64-msvc-bundle.tar.gz", + "sha256": "a852b14d7097640d790e72bcbc2f0fc7d4a38744ed9843ecc03a2bf29de58c8b", + "size": 3527908 + }, + { + "assetId": 617935392, + "name": "oliphaunt-extension-contrib-pg18-0.3.2-release-assets.sha256", + "sha256": "6f7059584e645b8cb2f84eb974299f317ef4c22e92867c0981f9bccf877c16b3", + "size": 1388 + }, + { + "assetId": 617935753, + "name": "oliphaunt-extension-contrib-pg18-0.3.2-swift-extension-carrier.json", + "sha256": "79a20d7e0f59c0e5bc05acabbac963647835b3815c8e2d01824af317712caa64", + "size": 275977 + } + ] + } +] diff --git a/build_defs/release/native-0.3.3-completed-publication.json b/build_defs/release/native-0.3.3-completed-publication.json new file mode 100644 index 000000000..e27886549 --- /dev/null +++ b/build_defs/release/native-0.3.3-completed-publication.json @@ -0,0 +1,8 @@ +{ + "product": "liboliphaunt-native", + "version": "0.3.3", + "tagName": "liboliphaunt-native-v0.3.3", + "publicationSha": "cd68c6c9655f53c50a3a98d4db36cfc256d26a3c", + "publicationTree": "f15802598bf4570742a6e420de722af0ef6be457", + "releaseSha": "126bc0264f2ca21f3c79f3d532ce8a1ca6674211" +} diff --git a/build_defs/release/native-0.3.3-releases.json b/build_defs/release/native-0.3.3-releases.json new file mode 100644 index 000000000..65c9262fb --- /dev/null +++ b/build_defs/release/native-0.3.3-releases.json @@ -0,0 +1,146 @@ +[ + { + "product": "liboliphaunt-native", + "version": "0.3.3", + "tag": "liboliphaunt-native-v0.3.3", + "releaseId": 407873993, + "releaseName": "liboliphaunt-native v0.3.3", + "targetCommitish": "cd68c6c9655f53c50a3a98d4db36cfc256d26a3c", + "draft": false, + "prerelease": false, + "assets": [ + { + "assetId": 624861117, + "name": "liboliphaunt-0.3.3-android-arm64-v8a.tar.gz", + "sha256": "4c4fb476b18b43a5c00abd7892e5ebbfb4eaa13ea9f0cc9625c73d8e890b87ae", + "size": 5386195 + }, + { + "assetId": 624862824, + "name": "liboliphaunt-0.3.3-android-x86_64.tar.gz", + "sha256": "6d7cfb542e169129e4b52698721e44fad21f8d48f7246b02555d5c7e0a4c95ed", + "size": 5595121 + }, + { + "assetId": 624864874, + "name": "liboliphaunt-0.3.3-apple-spm-xcframework.zip", + "sha256": "e6311658046cb2714bc0c1a7c5610f6ce36cda2156c8092aea21500cce7f2ba1", + "size": 38239524 + }, + { + "assetId": 624866796, + "name": "liboliphaunt-0.3.3-ios-xcframework.tar.gz", + "sha256": "35069d6456f85997f15473e1524440b36e14dc725c03e197eb99c36178c7d969", + "size": 39046682 + }, + { + "assetId": 624869136, + "name": "liboliphaunt-0.3.3-linux-arm64-gnu.tar.gz", + "sha256": "b6d268b16a00cf62db187a9c7a382eb071664899437d4c3edce3778248f7e61b", + "size": 13778609 + }, + { + "assetId": 624871411, + "name": "liboliphaunt-0.3.3-linux-x64-gnu.tar.gz", + "sha256": "17daee827bcbd0a1777e60c23e713079e10a20cf321749d9b9700b6e87599071", + "size": 14152276 + }, + { + "assetId": 624873188, + "name": "liboliphaunt-0.3.3-macos-arm64.tar.gz", + "sha256": "76b628beb3837a43976f54ec04f4490fa7ff1acc6bb7188640d64e7ba35868d7", + "size": 12407735 + }, + { + "assetId": 624874975, + "name": "liboliphaunt-0.3.3-release-assets.sha256", + "sha256": "fdd35fcf7bc681fa82deb7a69f41c94a0c12e059c371fd2dbfa344c6c5bd4dfa", + "size": 1128 + }, + { + "assetId": 624876955, + "name": "liboliphaunt-0.3.3-runtime-resources-android-datum64.tar.gz", + "sha256": "5525d1c9a8f1b1325a17c27acbf3e9e58d7eae87d201eba3587866427fb655d7", + "size": 9601301 + }, + { + "assetId": 624878825, + "name": "liboliphaunt-0.3.3-runtime-resources-ios-datum64.tar.gz", + "sha256": "7084b5f68d9d95be4857bd1809845e7d3688978c2e18fff87afd58b1e483a223", + "size": 7901816 + }, + { + "assetId": 624880783, + "name": "liboliphaunt-0.3.3-windows-x64-msvc.zip", + "sha256": "910415985a5e676156a72f2ea5eb778980b46682dd89a1bbc5f487520001a902", + "size": 41445869 + }, + { + "assetId": 624882644, + "name": "oliphaunt-extension-contrib-pg18-0.3.3-manifest.json", + "sha256": "203759c76f4418661a34a73cf3b0b5b1892233e42b6c4e3b8ffb921075827c1b", + "size": 399825 + }, + { + "assetId": 624884290, + "name": "oliphaunt-extension-contrib-pg18-0.3.3-manifest.properties", + "sha256": "21788b4b3a29bcb1d7dd5a7d358d235f066c417f7a1ef88a7b94a8f566260266", + "size": 86679 + }, + { + "assetId": 624886163, + "name": "oliphaunt-extension-contrib-pg18-0.3.3-native-android-arm64-v8a-bundle.tar.gz", + "sha256": "0b16664a89582c638c2fe5407bc708eec981582016cd3fac6995ae3bbbec7cdc", + "size": 4388805 + }, + { + "assetId": 624886911, + "name": "oliphaunt-extension-contrib-pg18-0.3.3-native-android-x86_64-bundle.tar.gz", + "sha256": "ac30c17050bbe4c59f0feba0793b941d76d94dda3cd7e6fe57acd6ebb3d8a41a", + "size": 3952051 + }, + { + "assetId": 624887802, + "name": "oliphaunt-extension-contrib-pg18-0.3.3-native-ios-xcframework-bundle.tar.gz", + "sha256": "33ad7f5da42e5528233fd38e76ff7e44e78a0668d3b039939e22499c94160292", + "size": 20954767 + }, + { + "assetId": 624888517, + "name": "oliphaunt-extension-contrib-pg18-0.3.3-native-linux-arm64-gnu-bundle.tar.gz", + "sha256": "7ed93d234e97892396269b95af9abfb1347230e5150c4d77e135a93bad73c534", + "size": 1029680 + }, + { + "assetId": 624889188, + "name": "oliphaunt-extension-contrib-pg18-0.3.3-native-linux-x64-gnu-bundle.tar.gz", + "sha256": "b44f93702d70c82659a21f66dc9573a4e8b153bd4e1e6b6656feaa642ef4284c", + "size": 978396 + }, + { + "assetId": 624889874, + "name": "oliphaunt-extension-contrib-pg18-0.3.3-native-macos-arm64-bundle.tar.gz", + "sha256": "b83a9cc1c5a1fba6d859802f8eea3eed9b9166db67d22d5f8d4ca9a7a0885132", + "size": 5249713 + }, + { + "assetId": 624890613, + "name": "oliphaunt-extension-contrib-pg18-0.3.3-native-windows-x64-msvc-bundle.tar.gz", + "sha256": "6d7d949cd043a6615ac3d69fb8959474e5735b0b632823b36b088c0772a06d51", + "size": 3527858 + }, + { + "assetId": 624891007, + "name": "oliphaunt-extension-contrib-pg18-0.3.3-release-assets.sha256", + "sha256": "8cbccaf147cdf23b313417bd44b642096633cf14ca14c756c2f8bab1bebafec4", + "size": 1388 + }, + { + "assetId": 624891325, + "name": "oliphaunt-extension-contrib-pg18-0.3.3-swift-extension-carrier.json", + "sha256": "ea8d7ecfbf6d7c68e85cd19cbb45a73e0aac8b80907d221253289e027c6da501", + "size": 275977 + } + ] + } +] diff --git a/build_defs/release/repositories.bzl b/build_defs/release/repositories.bzl new file mode 100644 index 000000000..ce8c8b3e9 --- /dev/null +++ b/build_defs/release/repositories.bzl @@ -0,0 +1,71 @@ +"""One-way tracked import of existing product/extension policy before analysis.""" + +_PUBLICATION_INPUTS_ENV = "OLIPHAUNT_NATIVE_PUBLICATION_INPUTS" + +def _domain_metadata_impl(ctx): + root = ctx.path(ctx.attr.config).dirname + converter = ctx.path(ctx.attr.converter) + # Repository reads track source changes. The converter's receipt covers its + # discovered descriptors, including new products and external source pins. + ctx.read(converter) + ctx.read(ctx.path(ctx.attr.config)) + ctx.watch(ctx.path(ctx.attr.bun)) + command = [ + str(ctx.path(ctx.attr.bun)), + str(converter), + "--root", + str(root), + "--output-dir", + str(ctx.path(".")), + "--identity-rule", + str(ctx.attr.identity_rule), + ] + publication_inputs = ctx.os.environ.get(_PUBLICATION_INPUTS_ENV, "") + snapshot_path = ctx.path(publication_inputs) if publication_inputs else None + snapshot = None + if snapshot_path: + if not snapshot_path.exists: + fail(_PUBLICATION_INPUTS_ENV + " must name the immutable controller input snapshot") + ctx.watch(snapshot_path) + snapshot = ctx.read(snapshot_path) + command.extend(["--native-publication-inputs", str(snapshot_path)]) + result = ctx.execute(command, timeout = 120) + if result.return_code: + fail("release metadata import failed:\n" + result.stdout + result.stderr) + receipt = json.decode(ctx.read(".metadata-inputs.json")) + inputs = receipt["sourceInputs"] + for relative, observed in inputs.items(): + source = root.get_child(relative) + ctx.watch(source) + current = ctx.read(source) if source.exists else None + if current != observed: + fail("release metadata changed during import: " + relative) + for file in receipt["nativePublicationFiles"]: + source = ctx.path(file["source"]) + ctx.watch(source) + ctx.symlink(source, file["path"]) + if snapshot_path and ctx.read(snapshot_path) != snapshot: + fail("controller publication inputs changed during import") + directories = json.decode(ctx.read(".metadata-directories.json")) + for relative, observed in directories.items(): + source = root.get_child(relative) + ctx.watch(source) + # The authored metadata owner remains when its optional dependency + # directory is removed. Watching the removable directory's listing or + # tree in Bazel 8 can retain an input rooted at a now-missing directory. + ctx.watch_tree(source.dirname) + current = sorted([entry.basename for entry in source.readdir(watch = "no")]) if source.exists else None + if current != observed: + fail("release metadata directory changed during import: " + relative) + +domain_metadata = repository_rule( + implementation = _domain_metadata_impl, + environ = [_PUBLICATION_INPUTS_ENV], + configure = True, + attrs = { + "bun": attr.label(allow_single_file = True, mandatory = True), + "config": attr.label(allow_single_file = True, default = Label("//:release-please-config.json")), + "converter": attr.label(allow_single_file = True, default = Label("//tools/release:bazel-release-metadata.mts")), + "identity_rule": attr.label(allow_single_file = True, default = Label("//build_defs/release:identity.bzl")), + }, +) diff --git a/build_defs/release/shipping.bzl b/build_defs/release/shipping.bzl new file mode 100644 index 000000000..830c1ae00 --- /dev/null +++ b/build_defs/release/shipping.bzl @@ -0,0 +1,134 @@ +"""Construction outputs and declared ownership, not publication admission evidence.""" + +load("//build_defs/apple:slices.bzl", "apple_slice_groups") +load(":identity.bzl", "ReleaseIdentityInfo") +load(":supplier.bzl", "ShippingSupplierInfo") + +ShippingInfo = provider(fields = ["product", "version", "ecosystem", "name", "configuration", "role", "files", "supplier_inputs"]) +ShippingExportInfo = provider(fields = ["packages", "qualification", "policies"]) + +def _package(info): + return { + "product": info.product, + "version": info.version, + "ecosystem": info.ecosystem, + "name": info.name, + "configuration": info.configuration, + "role": info.role, + "supplierInputs": info.supplier_inputs, + "outputs": [{"path": file.path, "owner": str(file.owner)} for file in info.files.to_list()], + } + +def _shipping_package_impl(ctx): + owner = ctx.attr.owner[ReleaseIdentityInfo] + suppliers = ctx.attr.suppliers[ShippingSupplierInfo] + if suppliers.suppliers == None: + fail("shipping package requires explicit known supplier coverage") + files = depset(transitive = [artifact[DefaultInfo].files for artifact in ctx.attr.artifacts]) + if not files.to_list(): + fail("shipping package must contain actual output files") + info = ShippingInfo( + product = owner.id, + version = owner.version, + ecosystem = ctx.attr.ecosystem, + name = ctx.attr.package_name, + configuration = ctx.attr.configuration, + role = ctx.attr.role, + files = files, + supplier_inputs = suppliers.suppliers, + ) + manifest = ctx.actions.declare_file(ctx.label.name + ".shipping.json") + ctx.actions.write(manifest, json.encode({"label": str(ctx.label), "package": _package(info)}) + "\n") + observation_inputs = depset( + ctx.files.observation_inputs, + transitive = [suppliers.files] + [ + target[OutputGroupInfo].observation_inputs + for target in ctx.attr.observation_inputs + if OutputGroupInfo in target and hasattr(target[OutputGroupInfo], "observation_inputs") + ], + ) + return [ + DefaultInfo(files = files), + info, + OutputGroupInfo(shipping_manifest = depset([manifest]), observation_inputs = observation_inputs, **apple_slice_groups(ctx.attr.artifacts)), + ] + +shipping_package = rule( + implementation = _shipping_package_impl, + attrs = { + "owner": attr.label(providers = [ReleaseIdentityInfo], mandatory = True), + "artifacts": attr.label_list(allow_files = True, mandatory = True), + "ecosystem": attr.string(values = ["cargo", "npm", "maven", "github", "swift", "internal"], mandatory = True), + "package_name": attr.string(mandatory = True), + "configuration": attr.string(mandatory = True), + "role": attr.string(mandatory = True), + "suppliers": attr.label(providers = [ShippingSupplierInfo], mandatory = True, doc = "Actual configured supplier Files; use //build_defs/release:no_suppliers to explicitly declare none. Unknown coverage is not a complete shipping package."), + "observation_inputs": attr.label_list(allow_files = True, doc = "Original constructor values required by evidence capture, materialized in this same invocation."), + }, +) + +def _shipping_export_impl(ctx): + targets = list(ctx.attr.packages) + tests = {str(target.label): target for target in ctx.attr.qualification} + policies = [] + if targets: + policies.append({ + "owner": str(ctx.label), + "roots": [str(target.label) for target in targets], + "qualification": [str(target.label) for target in ctx.attr.qualification], + }) + for child in ctx.attr.exports: + export = child[ShippingExportInfo] + targets.extend(export.packages) + policies.extend(export.policies) + for target in export.qualification: + tests[str(target.label)] = target + if not targets: + fail("shipping export must contain actual shipping packages") + if ctx.attr.qualification and not ctx.attr.packages: + fail("composed shipping qualification belongs to the source owner of its packages") + packages = [] + identities = {} + versions = {} + for target in targets: + info = target[ShippingInfo] + key = info.ecosystem + ":" + info.name + if info.ecosystem == "github": + # Assets and candidate inputs belong to a component release; + # registry carrier names remain global within their ecosystem. + key = info.product + ":" + key + if info.ecosystem == "internal": + key += ":" + info.configuration + if key in identities: + fail("duplicate shipping identity " + key + " from " + identities[key] + " and " + str(target.label)) + identities[key] = str(target.label) + if info.product in versions and versions[info.product] != info.version: + fail("inconsistent shipping version for " + info.product) + versions[info.product] = info.version + packages.append(_package(info)) + output = ctx.actions.declare_file(ctx.label.name + ".json") + ctx.actions.write(output, json.encode({ + "schema": "oliphaunt-bazel-shipping-v1", + "scope": "construction", + "owner": str(ctx.label), + "roots": [str(target.label) for target in targets], + "packages": packages, + "qualification": sorted(tests.keys()), + "policies": policies, + }) + "\n") + return [ + DefaultInfo(files = depset([output])), + OutputGroupInfo(shipping_policy = depset([output]), **apple_slice_groups(targets)), + ShippingExportInfo(packages = targets, qualification = tests.values(), policies = policies), + ] + +shipping_export = rule( + implementation = _shipping_export_impl, + attrs = { + "packages": attr.label_list(providers = [ShippingInfo]), + "exports": attr.label_list(providers = [ShippingExportInfo], doc = "Source-owned exports; each child's own root-to-test policy is retained."), + "qualification": attr.label_list( + doc = "Mandatory configured actual tests, including final installed consumers; set testonly = True on the export. Source/host unit tests retain that scope and do not replace installed runtime proof. Declare actual tests, including manual tests, rather than test_suite targets. Incompatible mandatory tests make the export incompatible; use select() only when the owner explicitly has no policy for that configuration.", + ), + }, +) diff --git a/build_defs/release/supplier.bzl b/build_defs/release/supplier.bzl new file mode 100644 index 000000000..bed92bd0a --- /dev/null +++ b/build_defs/release/supplier.bzl @@ -0,0 +1,203 @@ +"""Actual configured supplier Files; construction data, never admission.""" + +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") +load("@rules_rust//rust:defs.bzl", "rust_common") +load(":identity.bzl", "ReleaseIdentityInfo") + +ShippingSupplierInfo = provider(fields = ["suppliers", "files"]) + +def current_rust_shipping_supplier(crate, producer, owner, source_package, configuration): + """Observe the existing configured crate output; callers validate its conventional owner.""" + if producer.package != source_package or not crate.root.short_path.startswith(source_package + "/"): + fail("current Rust supplier differs from its conventional source package") + file = crate.output + if file.is_source or file.is_directory or not file.path.startswith("bazel-out/") or file.owner != producer: + fail("current Rust supplier requires the actual generated library owned by its producer") + return ShippingSupplierInfo( + suppliers = [{"product": owner.id, "version": owner.version, "configuration": configuration, + "binding": "compiled-input", "origin": {"kind": "current-source"}, "files": [{"path": file.path}]}], + files = depset([file]), + ) + +def held_rust_shipping_supplier(crate, owner, origin = None): + """Keep registry source incorporation bound to its genuine completed origin, or unknown.""" + # Registry source incorporation is separate from the core loaded at runtime. + files = {file.path: file for file in crate.srcs.to_list()} + manifests = [file for file in crate.compile_data.to_list() if file.basename == "Cargo.toml" and file.dirname == crate.root.dirname.removesuffix("/src")] + if len(manifests) != 1: + fail("registry Rust supplier requires its actual source Cargo.toml") + files[manifests[0].path] = manifests[0] + declarations = [] + for file in files.values(): + if file.is_directory or not file.short_path.startswith("../"): + fail("held Rust supplier requires actual external source Files") + declarations.append({"path": file.path, "member": "/".join(file.short_path.split("/")[2:])}) + suppliers = None + if origin: + publication = origin.get("publication", {}) + if origin.get("kind") != "completed-publication" or publication.get("product") != owner.id: + fail("held Rust supplier requires its exact completed release owner") + suppliers = [{"product": owner.id, "version": publication["version"], "configuration": "portable", + "binding": "compiled-input", "origin": origin, "files": declarations}] + return ShippingSupplierInfo(suppliers = suppliers, files = depset(files.values())) + +def _rust_supplier_impl(ctx): + crate = ctx.attr.producer[rust_common.crate_info] + if ctx.attr.current_source: + if ctx.attr.origin or not ctx.attr.source_package: + fail("current Rust supplier needs its declared source package and cannot claim a completed origin") + info = current_rust_shipping_supplier(crate, ctx.attr.producer.label, ctx.attr.owner[ReleaseIdentityInfo], ctx.attr.source_package, ctx.attr.configuration) + return [DefaultInfo(files = info.files), info] + if ctx.attr.source_package: + fail("a held Rust supplier cannot declare current source ownership") + info = held_rust_shipping_supplier(crate, ctx.attr.owner[ReleaseIdentityInfo], json.decode(ctx.attr.origin) if ctx.attr.origin else None) + return [DefaultInfo(files = info.files), info] + +rust_shipping_supplier = rule( + implementation = _rust_supplier_impl, + attrs = { + "producer": attr.label(providers = [rust_common.crate_info], mandatory = True), + "owner": attr.label(providers = [ReleaseIdentityInfo], mandatory = True), + "origin": attr.string(doc = "Completed registry carrier facts from the authenticated per-run snapshot; omission stays unknown."), + "current_source": attr.bool(doc = "Observe the same locally compiled library File used by the consumer; never substitutes a dependency."), + "source_package": attr.string(doc = "Conventional Cargo source package, validated against the release owner by the carrier macro."), + "configuration": attr.string(default = "portable"), + }, +) + +def _cc_supplier_impl(ctx): + producer = ctx.attr.producer + files = {} + for linker_input in producer[CcInfo].linking_context.linker_inputs.to_list(): + # Only this producer's library, not its transitive tool/dependency Files. + if linker_input.owner != producer.label: + continue + for library in linker_input.libraries: + dynamic = library.resolved_symlink_interface_library or library.interface_library or library.resolved_symlink_dynamic_library or library.dynamic_library + static = library.pic_static_library or library.static_library + if dynamic and static: + fail("supplier requires an unambiguous dynamic or static library File: " + str(producer.label)) + file = dynamic or static + if file: + # An archive in CcInfo may merely forward transitive libraries. + # Its final embedding action must prove incorporation separately. + files[file.path] = struct(file = file, binding = "abi-contract" if dynamic else None) + if len(files) != 1: + fail("supplier requires one actual library File owned by its CcInfo producer: " + str(producer.label)) + selected = files.values()[0] + file = selected.file + if file.is_directory: + fail("supplier must be a regular library File") + owner = ctx.attr.owner[ReleaseIdentityInfo] + origin = {"kind": "current-source"} + declaration = {"path": file.path} + if ctx.attr.completed_publication: + publication = ctx.attr.completed_publication + if sorted(publication) != sorted(["product", "version", "tagName", "publicationSha", "publicationTree", "releaseSha"]): + fail("held supplier requires exact existing completed publication fields") + if publication["product"] != owner.id or publication["version"] != owner.version or publication["tagName"] != owner.id + "-v" + owner.version: + fail("held supplier differs from its release identity") + if not ctx.attr.artifact or not ctx.attr.member: + fail("held supplier requires its canonical archive and exact member") + origin = {"kind": "completed-publication", "publication": publication, "artifact": ctx.attr.artifact} + declaration["member"] = ctx.attr.member + elif ctx.attr.artifact or ctx.attr.member: + fail("current supplier cannot assert a published archive member") + info = ShippingSupplierInfo( + suppliers = [{"product": owner.id, "version": owner.version, "configuration": ctx.attr.configuration, "binding": selected.binding, "origin": origin, "files": [declaration]}] if selected.binding else None, + files = depset([file]), + ) + # Consumers can use this target as the actual C dependency. No copying, + # compilation, identity stamping, or replacement linking context is added. + return [DefaultInfo(files = info.files), producer[CcInfo], info] + +cc_shipping_supplier = rule( + implementation = _cc_supplier_impl, + attrs = { + "producer": attr.label(providers = [CcInfo], mandatory = True), + "owner": attr.label(providers = [ReleaseIdentityInfo], mandatory = True), + "configuration": attr.string(mandatory = True), + "completed_publication": attr.string_dict(), + "artifact": attr.string(), + "member": attr.string(), + }, +) + +def merge_shipping_suppliers(inputs): + """Union exact File declarations for each supplier binding; unknown stays unknown.""" + files = depset(transitive = [info.files for info in inputs]) + if any([info.suppliers == None for info in inputs]): + return ShippingSupplierInfo(suppliers = None, files = files) + suppliers = {} + for info in inputs: + for supplier in info.suppliers: + key = json.encode({name: supplier[name] for name in ["product", "binding", "configuration", "origin"]}) + if key not in suppliers: + suppliers[key] = dict(supplier, files = {}) + merged = suppliers[key] + if merged["version"] != supplier["version"]: + fail("conflicting versions for native supplier binding: " + key) + for declaration in supplier["files"]: + path = declaration["path"] + if path in merged["files"] and merged["files"][path] != declaration: + fail("conflicting native supplier File declaration: " + path) + merged["files"][path] = declaration + return ShippingSupplierInfo( + suppliers = [dict(suppliers[key], files = [suppliers[key]["files"][path] for path in sorted(suppliers[key]["files"])]) for key in sorted(suppliers)], + files = files, + ) + +def _suppliers_impl(ctx): + info = merge_shipping_suppliers([target[ShippingSupplierInfo] for target in ctx.attr.inputs]) + return [ + DefaultInfo(files = info.files), + info, + ] + +shipping_suppliers = rule( + implementation = _suppliers_impl, + attrs = {"inputs": attr.label_list(providers = [ShippingSupplierInfo])}, +) + +def _file_supplier_impl(ctx): + files = [] + declarations = [] + for target, member in ctx.attr.inputs.items(): + selected = target[DefaultInfo].files.to_list() + if len(selected) != 1 or selected[0].is_directory: + fail("supplier requires its exact declared regular File") + file = selected[0] + files.append(file) + declaration = {"path": file.path} + if member: + declaration["member"] = member + declarations.append(declaration) + if not files: + fail("supplier requires nonempty actual File inputs") + suppliers = None + if ctx.attr.origin: + owner = ctx.attr.owner[ReleaseIdentityInfo] + origin = json.decode(ctx.attr.origin) + version = owner.version + if origin.get("kind") == "completed-publication": + publication = origin.get("publication", {}) + if publication.get("product") != owner.id: + fail("held supplier differs from its release owner") + version = publication.get("version") + suppliers = [{"product": owner.id, "version": version, + "configuration": ctx.attr.configuration, "binding": ctx.attr.binding, + "origin": origin, "files": declarations}] + info = ShippingSupplierInfo(suppliers = suppliers, files = depset(files)) + return [DefaultInfo(files = info.files, runfiles = ctx.runfiles(files = files)), info] + +file_shipping_supplier = rule( + implementation = _file_supplier_impl, + attrs = { + "inputs": attr.label_keyed_string_dict(allow_files = True, mandatory = True, + doc = "Actual single File targets mapped to original archive member paths; empty member means the whole authenticated archive."), + "owner": attr.label(providers = [ReleaseIdentityInfo], mandatory = True), + "configuration": attr.string(mandatory = True), + "binding": attr.string(values = ["compiled-input", "abi-contract"], mandatory = True), + "origin": attr.string(doc = "Typed original producer/completed publication facts; omission retains unknown supplier coverage."), + }, +) diff --git a/build_defs/release/swift-0.8.1-publication-source.json b/build_defs/release/swift-0.8.1-publication-source.json new file mode 100644 index 000000000..bb13155a3 --- /dev/null +++ b/build_defs/release/swift-0.8.1-publication-source.json @@ -0,0 +1,32 @@ +{ + "publication": { + "product": "oliphaunt-swift", + "version": "0.8.1", + "tagName": "oliphaunt-swift-v0.8.1", + "publicationSha": "31b5803d80ce3884a1fc2d3e9ab869dd733b461c", + "publicationTree": "7355d3958334202a31d02aa3291b480fdd1f02f4", + "releaseSha": "31b5803d80ce3884a1fc2d3e9ab869dd733b461c" + }, + "reference": { + "ref": "refs/tags/0.8.1", + "object": { + "type": "commit", + "sha": "eaccd5ddbad7af683983758d4c3aeaf4d9cff47a" + } + }, + "commit": { + "sha": "eaccd5ddbad7af683983758d4c3aeaf4d9cff47a", + "tree": { + "sha": "f2b3553e8a31a7cbf50d95165d73b3e889526328" + }, + "parents": [ + { + "sha": "31b5803d80ce3884a1fc2d3e9ab869dd733b461c" + } + ] + }, + "member": { + "path": "src/sdks/swift/Carriers/oliphaunt-react-native-ios-carriers.json", + "sha": "2334b31ba62ad840243e61ab2bf84e54203f835d" + } +} diff --git a/build_defs/release/swift-0.8.1-source.json b/build_defs/release/swift-0.8.1-source.json new file mode 100644 index 000000000..29c5c2a32 --- /dev/null +++ b/build_defs/release/swift-0.8.1-source.json @@ -0,0 +1,10 @@ +{ + "repository": "f0rr0/oliphaunt", + "source_tag": "0.8.1", + "source_commit": "eaccd5ddbad7af683983758d4c3aeaf4d9cff47a", + "source_tree": "f2b3553e8a31a7cbf50d95165d73b3e889526328", + "source_member": "src/sdks/swift/Carriers/oliphaunt-react-native-ios-carriers.json", + "source_blob": "2334b31ba62ad840243e61ab2bf84e54203f835d", + "sha256": "30fc3649384e60af7ebb15dafddbd5b69f22a8ab2bcbf526575b0fed99584de2", + "bytes": 3697 +} diff --git a/build_defs/release/swift-0.8.2-publication-source.json b/build_defs/release/swift-0.8.2-publication-source.json new file mode 100644 index 000000000..2771af86c --- /dev/null +++ b/build_defs/release/swift-0.8.2-publication-source.json @@ -0,0 +1,32 @@ +{ + "publication": { + "product": "oliphaunt-swift", + "version": "0.8.2", + "tagName": "oliphaunt-swift-v0.8.2", + "publicationSha": "cd68c6c9655f53c50a3a98d4db36cfc256d26a3c", + "publicationTree": "f15802598bf4570742a6e420de722af0ef6be457", + "releaseSha": "126bc0264f2ca21f3c79f3d532ce8a1ca6674211" + }, + "reference": { + "ref": "refs/tags/0.8.2", + "object": { + "type": "commit", + "sha": "1c9f3420da157854bbb9786c54e822ed983ad4eb" + } + }, + "commit": { + "sha": "1c9f3420da157854bbb9786c54e822ed983ad4eb", + "tree": { + "sha": "4780a4b5fbff58287842e49622c25e8fe0c1cce6" + }, + "parents": [ + { + "sha": "cd68c6c9655f53c50a3a98d4db36cfc256d26a3c" + } + ] + }, + "member": { + "path": "src/sdks/swift/Carriers/oliphaunt-react-native-ios-carriers.json", + "sha": "328255dbe362b6b1228126d96115e2ae44cad3b1" + } +} diff --git a/build_defs/release/swift-0.8.2-source.json b/build_defs/release/swift-0.8.2-source.json new file mode 100644 index 000000000..6c54f2215 --- /dev/null +++ b/build_defs/release/swift-0.8.2-source.json @@ -0,0 +1,10 @@ +{ + "repository": "f0rr0/oliphaunt", + "source_tag": "0.8.2", + "source_commit": "1c9f3420da157854bbb9786c54e822ed983ad4eb", + "source_tree": "4780a4b5fbff58287842e49622c25e8fe0c1cce6", + "source_member": "src/sdks/swift/Carriers/oliphaunt-react-native-ios-carriers.json", + "source_blob": "328255dbe362b6b1228126d96115e2ae44cad3b1", + "sha256": "2fd76493f03036d3f27228baf64ca8d24286e3da4ef21ae4ecbc492b2accedfd", + "bytes": 3697 +} diff --git a/build_defs/release/testdata/swift-0.8.1-carrier.json b/build_defs/release/testdata/swift-0.8.1-carrier.json new file mode 100644 index 000000000..2334b31ba --- /dev/null +++ b/build_defs/release/testdata/swift-0.8.1-carrier.json @@ -0,0 +1,103 @@ +{ + "base": { + "assets": [ + { + "bytes": 37968414, + "format": "zip", + "member": "liboliphaunt.xcframework", + "name": "liboliphaunt-0.3.2-apple-spm-xcframework.zip", + "role": "base-xcframework", + "sha256": "915ea189f2ad74ac31fc4402dc31f00d4f42c4dcfe73e360db7cd0f36419dec8", + "url": "https://github.com/f0rr0/oliphaunt/releases/download/liboliphaunt-native-v0.3.2/liboliphaunt-0.3.2-apple-spm-xcframework.zip" + }, + { + "bytes": 7901759, + "format": "tar.gz", + "member": "oliphaunt", + "name": "liboliphaunt-0.3.2-runtime-resources-ios-datum64.tar.gz", + "role": "runtime-resources", + "sha256": "44409f9a63382d2ffb51e380df69df4323078b2ce6e806de6e9adcc3729bd20e", + "url": "https://github.com/f0rr0/oliphaunt/releases/download/liboliphaunt-native-v0.3.2/liboliphaunt-0.3.2-runtime-resources-ios-datum64.tar.gz" + } + ], + "product": "liboliphaunt-native", + "tag": "liboliphaunt-native-v0.3.2", + "version": "0.3.2" + }, + "carriers": [], + "extensions": [], + "legal": { + "base": [ + { + "assetRole": "base-xcframework", + "files": [ + { + "bytes": 1085, + "kind": "license", + "member": "liboliphaunt.xcframework/LICENSE", + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10" + }, + { + "bytes": 26487, + "kind": "license", + "member": "liboliphaunt.xcframework/THIRD_PARTY_LICENSES/ICU-LICENSE", + "sha256": "01edac20612b1e590c1c1cfb02b7218c6adc7b0a944eda7a1e03aeee10725aed" + }, + { + "bytes": 1198, + "kind": "license", + "member": "liboliphaunt.xcframework/THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", + "sha256": "3d6af92ff8a4c2cdf69afb1cf44edea727922f5cd0cf8b5f72b11cdecac8fdfd" + }, + { + "bytes": 1123, + "kind": "notice", + "member": "liboliphaunt.xcframework/THIRD_PARTY_NOTICES.liboliphaunt-native.md", + "sha256": "31bcaad933b6ffa8a9b7f1e2bdafc05e056cb71130da3caf808dd8ca4149a243" + }, + { + "bytes": 821, + "kind": "notice", + "member": "liboliphaunt.xcframework/THIRD_PARTY_NOTICES.md", + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830" + } + ], + "profile": "native-runtime", + "spdx": "MIT AND PostgreSQL AND Unicode-3.0" + }, + { + "assetRole": "runtime-resources", + "files": [ + { + "bytes": 1085, + "kind": "license", + "member": "LICENSE", + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10" + }, + { + "bytes": 1198, + "kind": "license", + "member": "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", + "sha256": "3d6af92ff8a4c2cdf69afb1cf44edea727922f5cd0cf8b5f72b11cdecac8fdfd" + }, + { + "bytes": 1123, + "kind": "notice", + "member": "THIRD_PARTY_NOTICES.liboliphaunt-native.md", + "sha256": "31bcaad933b6ffa8a9b7f1e2bdafc05e056cb71130da3caf808dd8ca4149a243" + }, + { + "bytes": 821, + "kind": "notice", + "member": "THIRD_PARTY_NOTICES.md", + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830" + } + ], + "profile": "native-runtime-resources", + "spdx": "MIT AND PostgreSQL" + } + ], + "extensions": [] + }, + "schema": "oliphaunt-react-native-ios-carrier-v1" +} diff --git a/build_defs/release/testdata/swift-0.8.2-carrier.json b/build_defs/release/testdata/swift-0.8.2-carrier.json new file mode 100644 index 000000000..328255dbe --- /dev/null +++ b/build_defs/release/testdata/swift-0.8.2-carrier.json @@ -0,0 +1,103 @@ +{ + "base": { + "assets": [ + { + "bytes": 38239524, + "format": "zip", + "member": "liboliphaunt.xcframework", + "name": "liboliphaunt-0.3.3-apple-spm-xcframework.zip", + "role": "base-xcframework", + "sha256": "e6311658046cb2714bc0c1a7c5610f6ce36cda2156c8092aea21500cce7f2ba1", + "url": "https://github.com/f0rr0/oliphaunt/releases/download/liboliphaunt-native-v0.3.3/liboliphaunt-0.3.3-apple-spm-xcframework.zip" + }, + { + "bytes": 7901816, + "format": "tar.gz", + "member": "oliphaunt", + "name": "liboliphaunt-0.3.3-runtime-resources-ios-datum64.tar.gz", + "role": "runtime-resources", + "sha256": "7084b5f68d9d95be4857bd1809845e7d3688978c2e18fff87afd58b1e483a223", + "url": "https://github.com/f0rr0/oliphaunt/releases/download/liboliphaunt-native-v0.3.3/liboliphaunt-0.3.3-runtime-resources-ios-datum64.tar.gz" + } + ], + "product": "liboliphaunt-native", + "tag": "liboliphaunt-native-v0.3.3", + "version": "0.3.3" + }, + "carriers": [], + "extensions": [], + "legal": { + "base": [ + { + "assetRole": "base-xcframework", + "files": [ + { + "bytes": 1085, + "kind": "license", + "member": "liboliphaunt.xcframework/LICENSE", + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10" + }, + { + "bytes": 26487, + "kind": "license", + "member": "liboliphaunt.xcframework/THIRD_PARTY_LICENSES/ICU-LICENSE", + "sha256": "01edac20612b1e590c1c1cfb02b7218c6adc7b0a944eda7a1e03aeee10725aed" + }, + { + "bytes": 1198, + "kind": "license", + "member": "liboliphaunt.xcframework/THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", + "sha256": "3d6af92ff8a4c2cdf69afb1cf44edea727922f5cd0cf8b5f72b11cdecac8fdfd" + }, + { + "bytes": 1123, + "kind": "notice", + "member": "liboliphaunt.xcframework/THIRD_PARTY_NOTICES.liboliphaunt-native.md", + "sha256": "31bcaad933b6ffa8a9b7f1e2bdafc05e056cb71130da3caf808dd8ca4149a243" + }, + { + "bytes": 821, + "kind": "notice", + "member": "liboliphaunt.xcframework/THIRD_PARTY_NOTICES.md", + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830" + } + ], + "profile": "native-runtime", + "spdx": "MIT AND PostgreSQL AND Unicode-3.0" + }, + { + "assetRole": "runtime-resources", + "files": [ + { + "bytes": 1085, + "kind": "license", + "member": "LICENSE", + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10" + }, + { + "bytes": 1198, + "kind": "license", + "member": "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT", + "sha256": "3d6af92ff8a4c2cdf69afb1cf44edea727922f5cd0cf8b5f72b11cdecac8fdfd" + }, + { + "bytes": 1123, + "kind": "notice", + "member": "THIRD_PARTY_NOTICES.liboliphaunt-native.md", + "sha256": "31bcaad933b6ffa8a9b7f1e2bdafc05e056cb71130da3caf808dd8ca4149a243" + }, + { + "bytes": 821, + "kind": "notice", + "member": "THIRD_PARTY_NOTICES.md", + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830" + } + ], + "profile": "native-runtime-resources", + "spdx": "MIT AND PostgreSQL" + } + ], + "extensions": [] + }, + "schema": "oliphaunt-react-native-ios-carrier-v1" +} diff --git a/build_defs/resources/BUILD.bazel b/build_defs/resources/BUILD.bazel new file mode 100644 index 000000000..b4bb1502f --- /dev/null +++ b/build_defs/resources/BUILD.bazel @@ -0,0 +1,129 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/foundation:bun.bzl", "bun_binary", "bun_test") +load("@rules_cc//cc:defs.bzl", "cc_binary") +load("//build_defs/native:platform_config.bzl", "NATIVE_COMPATIBLE") +load("//build_defs/native/carriers:defs.bzl", "native_carrier_legal_inputs") +load(":desktop-profile-test.bzl", "desktop_profile_tests") +load(":carrier-inputs-test.bzl", "seed_carrier_inputs_tests") + +package(default_visibility = ["//visibility:public"]) + +desktop_profile_tests() +seed_carrier_inputs_tests() + +exports_files(glob(["*.bzl", "*.mts"])) + +filegroup(name = "helpers", srcs = [ + "shared.mts", + "seed_construction.mts", + "wasix_inputs.mts", + "//build_defs/native:host-runtime-test-helpers.mts", + "//src/database-resources:contracts/contract.json", + "//src/database-resources:contracts/icu-data.mts", + "//src/database-resources:contracts/native-manifest.mts", + "//src/database-resources:seeds/carrier-identities.mts", + "//src/database-resources:seeds/native/tools/stage-native-cluster-seed.mts", + "//src/database-resources:seeds/package-carriers.mts", + "//src/database-resources:seeds/package-mobile-carriers.mts", + "//src/database-resources:seeds/package.mts", + "//src/database-resources/icu:tools/icu-npm-carrier-contract.mts", + "//src/database-resources/icu:tools/package-cargo.mts", + "//src/database-resources/icu:tools/package-npm.mts", + "//src/database-resources/icu:tools/write-icu-package-size-report.mts", + "//:src/extensions/artifacts/packages/tools/contrib-carriers.mts", + "//:src/extensions/artifacts/packages/tools/extension-registry-packages.mts", + "//src/extensions/contracts:extension-target-profiles.mts", + "//src/extensions/tools:extension-upstream-licenses.mts", + "//src/native/mobile-bindings:tools/dependency-license-contract.mts", + "//src/native/runtime:tools/native-mobile-abi-contract.mts", + "//src/wasix/runtime:tools/wasix-cargo-artifact-contract.mts", + "//src/wasix/runtime:tools/wasix-runtime-npm-contract.mts", + "//src/wasix/runtime:tools/wasix-runtime-npm-descriptor.mts", + "//src/wasix/runtime:tools/wasix-runtime-npm-payload.mts", + "//:tools/packaging/archive-directory.mts", + "//:tools/packaging/platform-binary-contract.mts", + "//:tools/packaging/atomic-directory.mts", + "//:tools/packaging/build-maven-artifact-manifest.mts", + "//:tools/packaging/cargo-source-package.mts", + "//:tools/packaging/cargo-manifest.mts", + "//:tools/packaging/maven-artifact-manifest.mts", + "//:tools/packaging/maven-artifact-staging.mts", + "//:tools/packaging/maven-central-contract.mts", + "//:tools/packaging/npm-package.mts", + "//:tools/packaging/npm-trusted-publishing.mts", + "//:tools/packaging/package-archive.mts", + "//:tools/packaging/portable-archive.mts", + "//:tools/packaging/release-carrier.mts", + "//:tools/packaging/sdk-runtime-payload.mts", + "//:tools/packaging/release-directory-safety.mts", + "//:tools/packaging/release-notices.mts", + "//:tools/packaging/rust-dependency-license-contract.mts", + "//:tools/packaging/wasix-cargo-payload.mts", + "//:tools/packaging/windows-vc-runtime-closure.mts", + "//:tools/packaging/windows-vc-runtime-policy.json", + "//tools/release:compatibility-version-parser.mts", + "//tools/release:compatibility-version-policy.mts", + "//tools/release:extension-release-metadata.mts", + "//tools/release:platform-compatibility-policy.mts", + "//tools/release:product-version.mts", + "//tools/release:native-file-identity.mts", + "//tools/release:release-artifact-targets.mts", + "//tools/release:release-graph.mts", + "//tools/release:release-history.mts", +]) + +BOOTSTRAP_HELPERS = [ + "shared.mts", "seed_construction.mts", "//build_defs/native:host-runtime-test-helpers.mts", + "//tools/release:native-file-identity.mts", "//:tools/packaging/release-directory-safety.mts", + "//:tools/packaging/portable-archive.mts", + "//:tools/packaging/archive-directory.mts", + "//:tools/packaging/platform-binary-contract.mts", + "//:tools/packaging/windows-vc-runtime-closure.mts", + "//:tools/packaging/windows-vc-runtime-policy.json", + "//tools/release:platform-compatibility-policy.mts", + "//src/native/runtime:tools/native-mobile-abi-contract.mts", + "//src/database-resources:seeds/native/tools/stage-native-cluster-seed.mts", + "//src/database-resources:contracts/native-manifest.mts", + "//src/database-resources:contracts/icu-data.mts", + "//src/database-resources:contracts/contract.json", +] + +bun_binary(name = "native_seed", entry_point = "native_seed.mts", data = BOOTSTRAP_HELPERS) +bun_binary(name = "wasix_seed", entry_point = "wasix_seed.mts", data = [":helpers"]) +bun_binary(name = "seed_domain", entry_point = "seed_domain.mts", data = BOOTSTRAP_HELPERS) +bun_binary(name = "abi_receipt", entry_point = "abi_receipt.mts", data = [ + "shared.mts", "//build_defs/native:host-runtime-test-helpers.mts", + "//:tools/packaging/portable-archive.mts", + "//src/native/runtime:tools/native-mobile-abi-contract.mts", + "//:tools/packaging/platform-binary-contract.mts", "//:tools/packaging/windows-vc-runtime-closure.mts", + "//:tools/packaging/windows-vc-runtime-policy.json", "//tools/release:platform-compatibility-policy.mts", +]) +[bun_binary(name = name, entry_point = name + ".mts", data = [":helpers"]) + for name in ["icu_payload", "seed_assets", "carriers"]] + +cc_binary( + name = "seed_consumer", + srcs = ["seed_consumer.c"], + deps = ["//src/native/runtime:liboliphaunt", "@postgres//:server_headers", "@postgres//:port_frontend"], + copts = select({"//build_defs/native:windows_x64": ["/std:c11", "/W4", "/WX"], "//conditions:default": ["-std=c11", "-Wall", "-Wextra", "-Werror"]}), + target_compatible_with = NATIVE_COMPATIBLE, +) + +bun_test(name = "resource_contract_test", entry_point = "resource_contract.test.mts", data = [ + ":helpers", "seed_domain.mts", "seed_assets.mts", "seed-construction-fixture.mts", "//src/database-resources:cluster_seed_contract_fixtures", + "//:LICENSE", "//src/third-party/icu:LICENSE", "//src/third-party/icu:source.toml", +], size = "small") + +bun_test(name = "seed_construction_test", entry_point = "seed_construction.test.mts", data = [":helpers", "seed-construction-fixture.mts"], size = "small") +bun_test(name = "seed_domain_test", entry_point = "seed_domain.test.mts", data = [":helpers", "seed_domain.mts"], size = "small") + +bun_test(name = "mobile_resource_contract_test", entry_point = "mobile_resource_contract.test.mts", data = [ + ":helpers", "carriers.mts", "mobile_resource_contract.mts", "//:tools/packaging/testdata/tar-fixture.mts", +] + native_carrier_legal_inputs().keys(), size = "small") + +source_quality_files() + +# Source-only inputs for the existing SDK package policy tests. +exports_files([ + "seed_construction.mts", +], visibility = ["//visibility:public"]) diff --git a/build_defs/resources/README.md b/build_defs/resources/README.md new file mode 100644 index 000000000..407747482 --- /dev/null +++ b/build_defs/resources/README.md @@ -0,0 +1,27 @@ +# Database resource construction + +The desktop slice declares the pinned ICU data archive and its npm, Cargo and Maven carriers, plus standard and ICU PostgreSQL seeds for Linux x64 and ARM, Mac ARM and Windows x64. `//src/database-resources:native_shipping_export` exposes the shared ICU carriers and the selected host's seed carriers through the existing shipping provider. Each configured cohort has 12 roots; it constructs one host's seeds. The original Linux shipping and test labels remain available. This is partial coverage of the database-resources product; it does not satisfy complete product admission. + +Bootstrap consumes the selected native runtime, actual PostgreSQL configuration headers and the canonical seed contract. The ABI receipt comes from those headers, including resolved integer aliases. The ICU profile additionally consumes the actual pinned data archive. Consumer requirements record the runtime version passed to the packaging action, and the manifests identify the consumed PostgreSQL and initdb binaries. + +The executor must match the selected runtime artifact's canonical OS and CPU. Before initdb, construction checks the actual PostgreSQL, initdb and runtime-library architecture and platform baseline. The same resource test selects the canonical target's manifests and registry identities. Windows uses its native memory and DLL loader settings; Mac uses its dylib loader settings. Bootstrap inherits only the required OS loader root and receives its selected ICU data explicitly. Linux construction and formatter checks remain locally reproducible; actual Mac, Windows and ARM execution requires those CI hosts. + +PostgreSQL bootstrap intentionally consumes clock, PID and random state. A new bootstrap can produce different physical bytes for identical declared source inputs. Release affectedness must use the consumed source inputs and completed publication history; a fresh PGDATA hash cannot select a release. Publication freezes the original admitted archive bytes through the existing candidate mechanism. Validation opens disposable copies, and does not normalize control or WAL contents. + +The bootstrap output is a plain tar File containing every required empty directory, the original PGDATA files, its producer manifest and its actual ABI receipt. Bazel TreeArtifacts omit empty directories when transferred between actions, so they cannot be the seed transport. Archive adapters copy declared Bazel file aliases into private regular files before invoking the existing strict archive readers. + +`//src/database-resources:native_resource_test` checks the packed resource bytes, exact PostgreSQL directory membership and archive modes, canonical npm/Cargo identities and versions, producer hashes, header receipt, ICU profile behavior, SQL persistence across reopen and failure when the extracted runtime library is removed. Its scratch database roots use the SDK's production descriptor publisher. POSIX consumers receive the separate ICU data carrier and reject its removal. Windows loads the canonical data from `icudt76.dll`; its negative probe removes that DLL. Carrier identity and byte validation remain required on every host. The test also rejects a PostgreSQL error containing the expected result text. The original `:linux_resource_test` runs this same consumer with Linux compatibility constraints. Linux execution does not establish the remaining foreign host or mobile ABI domains. + +The qualified Linux x64 target and execution profile pass both resource tests. An unchanged warm invocation executes no bootstrap, packaging or consumer actions, and the 19 physical outputs behind the 12 shipping roots retain their SHA-256 and size. This establishes reuse of frozen bytes, rather than reproducibility of a fresh bootstrap. + +The Android construction slice also passes locally. `native_target_abi` reads the selected PostgreSQL headers and inspects the compiled runtime for its actual platform; the Android transitions produce separate arm64 and x86_64 receipts. Domain binding compares both receipts with the original Linux bootstrap receipt, checks the canonical Datum64 fields, and preserves PGDATA bytes and empty directories. It reuses the same GitHub, npm, Cargo and Maven writers. + +Build `//src/database-resources:android_datum64_standard_carriers` and `:android_datum64_icu_carriers` to construct all 16 final envelope files behind the ten new Android shipping roots. Shipping exports write the construction index; they do not force indexed artifact actions. Independent inspection checks the archive, npm/Cargo/Maven identities, runtime pin and exact original seed bytes. The warm request reruns no bootstrap, receipt, domain-binding or envelope producer, and retains identical SHA-256 and size for all 20 inspected outputs, including the four original/domain frozen tar files. + +The WASIX construction slice also passes locally. `//src/database-resources:wasix_resource_test` consumes the actual portable runtime, the standard Cargo seed-runner target with its authored feature, and the separate ICU data archive. Both profiles run the existing WASIX initdb constructor, freeze the authentic PGDATA bytes and preserve its empty directories. The manifests record the exact consumed runtime version and PostgreSQL/initdb module hashes; WASIX retains its distinct Datum32 physical format. + +The test checks exact archive/npm/Cargo contents and canonical identities, exercises the SDK's actual resource-parser sources with the pinned fzstd package, and rejects wrong runtime versions, module hashes, physical format, compatibility key, archive bytes and ICU tree hashes. The independent Rust verifier opens private packaged-seed copies with actual PostgreSQL, checks both profile probes, writes rows and reads them in a later process. Missing ICU data and `pg_control` fail. Six Rust unit tests also run through the declared execution configuration, covering error capture, required empty directories and rejection of work directories inside inputs before filesystem mutation. + +Build `//src/database-resources:wasix_standard_carriers` and `:wasix_icu_carriers` for the two profiles' final npm/Cargo envelopes and archive/manifest inputs; `:wasix_shipping_export` indexes their eight canonical shipping roots. The unchanged warm request passes in 0.568 seconds with zero executed producers or tests, and all ten inspected carrier/archive/manifest/frozen files retain their SHA-256 and size. This proves reuse of the admitted frozen bytes. The portable PostgreSQL module's export policy consumes actual extension side-module imports, so constructing that exact consumer module also requires their compile closure. + +The earlier qualified construction covers 17 of 33 registry carriers and 13 of 31 GitHub identities. Mac, Windows and ARM seed execution, Android execution, iOS seed admission, combined Swift packaging and the complete checksum aggregate still require qualification. The iOS domain requires genuine device, simulator and Mac producer receipts; it cannot be admitted from Mac headers alone. diff --git a/build_defs/resources/abi_receipt.mts b/build_defs/resources/abi_receipt.mts new file mode 100644 index 000000000..9949784e9 --- /dev/null +++ b/build_defs/resources/abi_receipt.mts @@ -0,0 +1,19 @@ +import { readFileSync, rmSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { nativeMobileAbiReceipt } from '../../src/native/runtime/tools/native-mobile-abi-contract.mts'; +import { inspectPlatformBinaryBuffer } from '../../tools/packaging/platform-binary-contract.mts'; +import { materializeInputs, privateWork, readSpecification } from './shared.mts'; + +const specification = readSpecification(); +const work = privateWork(path.resolve(specification.output)); +try { + // The producing runtime and headers come from the same target configuration. + inspectPlatformBinaryBuffer(readFileSync(specification.runtime), { + target: specification.target, + label: specification.runtime, + }); + const headers = materializeInputs(specification.headers, path.join(work, 'headers')); + writeFileSync(specification.output, nativeMobileAbiReceipt(headers, specification.target)); +} finally { + rmSync(work, { recursive: true, force: true }); +} diff --git a/build_defs/resources/carrier-inputs-test.bzl b/build_defs/resources/carrier-inputs-test.bzl new file mode 100644 index 000000000..5a149d905 --- /dev/null +++ b/build_defs/resources/carrier-inputs-test.bzl @@ -0,0 +1,105 @@ +"""Check actual seed envelope inputs without constructing platform runtimes.""" + +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") +load("@oliphaunt_metadata//:metadata.bzl", "NATIVE_RUNTIME_ARTIFACTS") +load("//build_defs/release:shipping.bzl", "ShippingInfo") +load("//build_defs/release:supplier.bzl", "ShippingSupplierInfo", "merge_shipping_suppliers") +load(":mobile.bzl", "native_seed_domain") +load(":resources.bzl", "NATIVE_SEED_ABI_CONFIGURATION", "NativeSeedInfo", "WasixSeedInfo", "native_seed_abi_shipping", "native_seed_abi_suppliers", "seed_envelopes") + +def _fixture_impl(ctx): + file = ctx.actions.declare_file(ctx.label.name + ".fixture") + ctx.actions.write(file, "analysis fixture; not a PostgreSQL seed") + runtime = file + if ctx.attr.separate_runtime: + runtime = ctx.actions.declare_file(ctx.label.name + ".runtime") + ctx.actions.write(runtime, "analysis fixture; original runtime, not its ABI receipt") + fields = {"frozen": file, "runtime": runtime, "profile": ctx.attr.profile, "target": ctx.attr.target, "construction": file} + seed = NativeSeedInfo(abi = file, **fields) if ctx.attr.family == "native" else WasixSeedInfo(**fields) + suppliers = native_seed_abi_suppliers([runtime]) if ctx.attr.family == "native" else ShippingSupplierInfo(suppliers = [], files = depset()) + return [DefaultInfo(files = depset([file])), seed, suppliers, OutputGroupInfo(supplier_inputs = suppliers.files, observation_inputs = depset([file]))] + +_fixture = rule(implementation = _fixture_impl, attrs = { + "family": attr.string(default = "native"), + "target": attr.string(default = "portable"), + "profile": attr.string(default = "icu"), + "separate_runtime": attr.bool(), +}) + +def _inputs_test_impl(ctx): + env = analysistest.begin(ctx) + actions = [action for action in analysistest.target_actions(env) if action.mnemonic == "ResourceCarriers"] + asserts.equals(env, 1, len(actions)) + if actions: + inputs = actions[0].inputs.to_list() + asserts.equals(env, ctx.attr.needs_icu, ctx.file.icu in inputs, "the actual carrier action must declare exactly the ICU payload it reads") + if ctx.attr.producer: + suppliers = ctx.attr.seed[ShippingSupplierInfo] + producer = ctx.attr.producer[ShippingInfo] + consumer = ctx.attr.shipping[ShippingInfo] + asserts.equals(env, suppliers.suppliers, consumer.supplier_inputs) + asserts.equals(env, "liboliphaunt-native", producer.product) + asserts.equals(env, "abi-contract", producer.role) + asserts.equals(env, NATIVE_SEED_ABI_CONFIGURATION, producer.configuration) + asserts.false(env, producer.configuration in [row["target"] for row in NATIVE_RUNTIME_ARTIFACTS], "seed provenance must not become a public runtime delivery slot") + expected_paths = sorted([source[NativeSeedInfo].runtime.path for source in ctx.attr.supplier_sources]) + asserts.equals(env, expected_paths, sorted([file.path for file in producer.files.to_list()])) + asserts.equals(env, expected_paths, sorted([file.path for file in suppliers.files.to_list()])) + asserts.equals(env, 1, len(suppliers.suppliers), "the real domain must merge creator and target ABI Files into one supplier binding") + source_suppliers = [source[ShippingSupplierInfo] for source in ctx.attr.supplier_sources] + for sources in [source_suppliers[::-1], source_suppliers + source_suppliers]: + asserts.equals(env, suppliers.suppliers, merge_shipping_suppliers(sources).suppliers) + unknown = ShippingSupplierInfo(suppliers = None, files = depset([ctx.file.icu])) + for sources in [[unknown] + source_suppliers, source_suppliers + [unknown]]: + merged = merge_shipping_suppliers(sources) + asserts.equals(env, None, merged.suppliers) + asserts.equals(env, sorted(expected_paths + [ctx.file.icu.path]), sorted([file.path for file in merged.files.to_list()])) + asserts.equals(env, [], producer.supplier_inputs) + for supplier in suppliers.suppliers: + asserts.equals(env, "abi-contract", supplier["binding"], "creator provenance must not imply compiled version coupling") + asserts.equals(env, producer.product, supplier["product"]) + asserts.equals(env, producer.configuration, supplier["configuration"]) + asserts.equals(env, [{"path": path} for path in expected_paths], supplier["files"]) + return analysistest.end(env) + +_inputs_test = analysistest.make(_inputs_test_impl, attrs = { + "icu": attr.label(allow_single_file = True, mandatory = True), + "needs_icu": attr.bool(), + "seed": attr.label(providers = [ShippingSupplierInfo], mandatory = True), + "shipping": attr.label(providers = [ShippingInfo], mandatory = True), + "producer": attr.label(providers = [ShippingInfo]), + "supplier_sources": attr.label_list(providers = [NativeSeedInfo]), +}) + +def seed_carrier_inputs_tests(): + fixture_kwargs = {"testonly": True, "tags": ["manual"]} + _fixture(name = "seed_carrier_icu_fixture", **fixture_kwargs) + for family, target, profiles in [ + ("native", "ios-datum64", ["standard", "icu"]), + ("native", "android-datum64", ["standard", "icu"]), + ("native", "linux-x64-gnu", ["icu"]), + ("wasix", "portable", ["icu"]), + ]: + for profile in profiles: + prefix = "seed_carrier_" + target.replace("-", "_") + "_" + profile + if target in ["ios-datum64", "android-datum64"]: + host = "macos-arm64" if target == "ios-datum64" else "linux-x64-gnu" + _fixture(name = prefix + "_creator", target = host, profile = profile, **fixture_kwargs) + receipts = [] + for abi in ["device", "simulator"] if target == "ios-datum64" else ["arm64", "x64"]: + name = prefix + "_" + abi + "_abi" + _fixture(name = name, profile = profile, separate_runtime = target == "android-datum64", **fixture_kwargs) + receipts.append(":" + name) + supplier_sources = [":" + prefix + "_creator"] + receipts + native_seed_domain(name = prefix + "_seed", producer = supplier_sources[0], receipts = receipts, suppliers = receipts, + domain = target, icu = ":seed_carrier_icu_fixture" if profile == "icu" else None, **fixture_kwargs) + else: + _fixture(name = prefix + "_seed", family = family, target = target, profile = profile, **fixture_kwargs) + supplier_sources = [":" + prefix + "_seed"] if family == "native" else [] + seed_envelopes(prefix, family, target, profile, ":" + prefix + "_seed", icu = ":seed_carrier_icu_fixture" if profile == "icu" else None, + consumer_runtime = ":seed_carrier_icu_fixture" if family == "wasix" else None, suppliers = ":" + prefix + "_seed", **fixture_kwargs) + producer = native_seed_abi_shipping(prefix, ":" + prefix + "_seed", **fixture_kwargs) if family == "native" else None + _inputs_test(name = prefix + "_inputs_test", target_under_test = ":" + prefix + "_carriers", + icu = ":seed_carrier_icu_fixture", needs_icu = profile == "icu" and target in ["ios-datum64", "android-datum64"], + seed = ":" + prefix + "_seed", shipping = ":" + prefix + "_github_archive", producer = producer, + supplier_sources = supplier_sources, size = "small") diff --git a/build_defs/resources/carriers.mts b/build_defs/resources/carriers.mts new file mode 100644 index 000000000..3b22a0ee3 --- /dev/null +++ b/build_defs/resources/carriers.mts @@ -0,0 +1,134 @@ +import assert from 'node:assert/strict'; +import { chmodSync, copyFileSync, mkdirSync, readdirSync, rmSync } from 'node:fs'; +import path from 'node:path'; +import { packageIcuCargo } from '../../src/database-resources/icu/tools/package-cargo.mts'; +import { resourceNpmTarballs } from '../../src/database-resources/icu/tools/package-npm.mts'; +import { packageSeedCarriers } from '../../src/database-resources/seeds/package-carriers.mts'; +import { packageMobileSeedCarriers } from '../../src/database-resources/seeds/package-mobile-carriers.mts'; +import { buildMavenArtifactManifest } from '../../tools/packaging/build-maven-artifact-manifest.mts'; +import { stageMavenArtifactManifest } from '../../tools/packaging/maven-artifact-staging.mts'; +import { materializeInputs, privateWork, readSpecification } from './shared.mts'; + +const specification = readSpecification(); +const work = privateWork(path.resolve(specification.npmOutput)); +try { + const legalRoot = materializeInputs(specification.notices, path.join(work, 'legal')); + const assets = path.join(work, 'assets'); + mkdirSync(assets); + for (const input of specification.assets) { + const destination = path.join(assets, path.basename(input)); + copyFileSync(input, destination); + // The conventional formatter rewrites its private manifest copies. + chmodSync(destination, 0o644); + } + const output = path.join(work, 'packages'); + mkdirSync(output); + let npm: string; + let cargo: string; + if (specification.kind === 'icu') { + const sourceArchive = path.join(assets, path.basename(specification.assets[0])); + const templateRoot = materializeInputs(specification.templates, path.join(work, 'templates')); + npm = resourceNpmTarballs(specification.version, { + sourceArchive, + packageRoot: path.join(templateRoot, 'npm'), + stageDir: path.join(work, 'npm-stage'), + outputDir: path.join(output, 'npm'), + noticeSourceRoot: legalRoot, + })[0][1]; + cargo = packageIcuCargo( + [ + '--asset', + sourceArchive, + '--output-dir', + path.join(output, 'cargo'), + '--work-dir', + path.join(work, 'cargo'), + ], + { + version: specification.version, + root: work, + templateDir: path.join(templateRoot, 'cargo'), + noticeSourceRoot: legalRoot, + }, + ).cratePath; + const registryPackages = specification.carriers + .filter((row) => row.ecosystem === 'maven') + .map((row) => row.name); + const manifest = await buildMavenArtifactManifest(path.join(work, 'maven.tsv'), { + artifactProduct: 'database-resources', + artifactIds: ['oliphaunt-icu'], + runtimeAssetRoot: assets, + context: { + version: specification.version, + artifactTargets: specification.artifactRows, + registryPackages, + noticeSourceRoot: legalRoot, + }, + }); + await stageMavenArtifactManifest(manifest, specification.mavenOutput, { + noticeSourceRoot: legalRoot, + }); + } else { + assert.equal(specification.kind, 'seed'); + const [result] = packageSeedCarriers( + [ + '--family', + specification.family, + '--target', + specification.target, + '--profile', + specification.profile, + ], + { + version: specification.version, + assetDir: assets, + outputDir: output, + sourceDir: path.join(work, 'seed-sources'), + contract: specification.contract, + noticeSourceRoot: legalRoot, + }, + ); + assert.equal(result.npm, specification.carriers.find((row) => row.ecosystem === 'npm').name); + assert.equal( + result.cargo, + specification.carriers.find((row) => row.ecosystem === 'cargo').name, + ); + npm = result.npmArchive; + cargo = result.crate; + if (specification.mavenOutput) { + assert.equal(specification.target, 'android-datum64'); + const canonical = specification.carriers.find((row) => row.ecosystem === 'maven'); + assert.ok(canonical, 'the Android resource has one canonical Maven carrier'); + await packageMobileSeedCarriers({ + targets: [specification.target], + profiles: [specification.profile], + assetDir: assets, + workDir: path.join(work, 'mobile'), + mavenDir: specification.mavenOutput, + version: specification.version, + noticeSourceRoot: legalRoot, + contract: specification.contract, + }); + const [group, artifact] = canonical.name.split(':'); + assert.ok(group && artifact); + assert.deepEqual( + readdirSync( + path.join( + specification.mavenOutput, + ...group.split('.'), + artifact, + specification.version, + ), + ).sort(), + ['-javadoc.jar', '-sources.jar', '.pom', '.tar.gz'] + .map((suffix) => `${artifact}-${specification.version}${suffix}`) + .sort(), + 'the existing Maven writer must emit the exact canonical carrier', + ); + } + } + copyFileSync(npm, specification.npmOutput); + copyFileSync(cargo, specification.cargoOutput); +} finally { + rmSync(work, { recursive: true, force: true }); +} diff --git a/build_defs/resources/desktop-profile-test.bzl b/build_defs/resources/desktop-profile-test.bzl new file mode 100644 index 000000000..17560cf98 --- /dev/null +++ b/build_defs/resources/desktop-profile-test.bzl @@ -0,0 +1,58 @@ +"""Analyze the real desktop constructors beneath package and target profiles.""" + +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") +load("@rules_pkg//pkg:providers.bzl", "PackageFilesInfo") +load("//build_defs/foundation:bun.bzl", "bun_test_entrypoint_args") +load("//build_defs/native/carriers:defs.bzl", "native_public_payload") +load(":resources.bzl", "native_seed", "native_seed_consumer_test") + +def _fixture_impl(ctx): + profile = [name for name in ["macos", "linux", "windows", "ios", "android"] if ctx.target_platform_has_constraint(ctx.attr._oses[name][platform_common.ConstraintValueInfo])][0] + if ctx.target_platform_has_constraint(ctx.attr._package[platform_common.ConstraintValueInfo]): + profile += "-package" + output = ctx.actions.declare_file(ctx.label.name + "/profile-fixture/" + profile + "/" + ctx.attr.filename) + ctx.actions.write(output, profile) + return [DefaultInfo(files = depset([output]), runfiles = ctx.runfiles(files = [output])), + PackageFilesInfo(dest_src_map = {ctx.attr.filename: output}, attributes = {"mode": "0644"})] + +_fixture = rule(implementation = _fixture_impl, attrs = { + "filename": attr.string(mandatory = True), + "_package": attr.label(default = "//build_defs/host:apple_package"), + "_oses": attr.string_keyed_label_dict(default = {name: "@platforms//os:" + name for name in ["macos", "linux", "windows", "ios", "android"]}), +}) + +def _profile_test_impl(ctx): + env = analysistest.begin(ctx) + target = analysistest.target_under_test(env) + if ctx.attr.consumer: + files = target[DefaultInfo].default_runfiles.files.to_list() + else: + actions = [action for action in analysistest.target_actions(env) if action.mnemonic == ctx.attr.mnemonic] + asserts.equals(env, 1, len(actions)) + files = actions[0].inputs.to_list() if actions else [] + fixtures = [file.path for file in files if "/profile-fixture/" in file.path] + asserts.true(env, len(fixtures) >= ctx.attr.minimum_files, "must inspect the actual constructor inputs/runfiles") + for file in fixtures: + asserts.true(env, "/profile-fixture/" + ctx.attr.expected + "/" in file, file) + return analysistest.end(env) + +_ATTRS = {"mnemonic": attr.string(default = "NativePublicPayload"), "expected": attr.string(default = "macos"), "consumer": attr.bool(), "minimum_files": attr.int(default = 1)} +_package_test = analysistest.make(_profile_test_impl, attrs = _ATTRS, config_settings = {"//command_line_option:platforms": str(Label("//build_defs/host:apple_package_macos_arm64"))}) +_linux_test = analysistest.make(_profile_test_impl, attrs = _ATTRS, config_settings = {"//command_line_option:platforms": str(Label("//build_defs/native:linux_x86_64_glibc_2_28"))}) +_windows_test = analysistest.make(_profile_test_impl, attrs = _ATTRS, config_settings = {"//command_line_option:platforms": str(Label("//build_defs/host:native_windows_x64"))}) +_ios_test = analysistest.make(_profile_test_impl, attrs = _ATTRS, config_settings = {"//command_line_option:platforms": str(Label("//build_defs/host:ios_device_arm64"))}) +_android_test = analysistest.make(_profile_test_impl, attrs = _ATTRS, config_settings = {"//command_line_option:platforms": str(Label("//build_defs/android:android_arm64"))}) + +def desktop_profile_tests(): + for name, filename in [("runtime", "runtime.tar"), ("configuration", "pg_config.h"), ("header", "pg_control.h")]: + _fixture(name = "desktop_profile_" + name, filename = filename, testonly = True, tags = ["manual"]) + native_public_payload(name = "desktop_profile_payload", root_mappings = [":desktop_profile_runtime"], runtime_mappings = [], metadata = "{}", testonly = True, tags = ["manual"]) + native_seed(name = "desktop_profile_seed", runtime = ":desktop_profile_runtime", configuration = ":desktop_profile_configuration", + headers = {":desktop_profile_header": "src/include/catalog/pg_control.h"}, profile = "standard", target = "macos-arm64", testonly = True, tags = ["manual"]) + name = "desktop_profile_consumer_subject_test" + native_seed_consumer_test(name = name, runtime = ":desktop_profile_runtime", consumer = ":desktop_profile_header", + specification = ":desktop_profile_configuration", args = bun_test_entrypoint_args(name), tags = ["manual"]) + _package_test(name = "desktop_seed_profile_test", target_under_test = ":desktop_profile_seed", mnemonic = "PostgresClusterSeed", minimum_files = 3, size = "small") + _package_test(name = "desktop_seed_consumer_profile_test", target_under_test = ":" + name, consumer = True, minimum_files = 3, size = "small") + for test, profile in [(_package_test, "macos"), (_linux_test, "linux"), (_windows_test, "windows"), (_ios_test, "ios"), (_android_test, "android")]: + test(name = "desktop_payload_" + profile + "_profile_test", target_under_test = ":desktop_profile_payload", expected = profile, size = "small") diff --git a/build_defs/resources/icu_payload.mts b/build_defs/resources/icu_payload.mts new file mode 100644 index 000000000..115ccc9fe --- /dev/null +++ b/build_defs/resources/icu_payload.mts @@ -0,0 +1,39 @@ +import assert from 'node:assert/strict'; +import { copyFileSync, mkdirSync, rmSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { archiveDirectory } from '../../tools/packaging/archive-directory.mts'; +import { + stageReleaseNotices, + assertReleaseNoticesInArchive, +} from '../../tools/packaging/release-notices.mts'; +import { + nativeIcuDataManifest, + validateNativeIcuDataManifest, +} from '../../src/database-resources/contracts/icu-data.mts'; +import { icuPackageSizeReport } from '../../src/database-resources/icu/tools/write-icu-package-size-report.mts'; +import { materializeInputs, privateWork, readSpecification } from './shared.mts'; + +const specification = readSpecification(); +const output = path.resolve(specification.output); +const work = privateWork(output); +try { + const legalRoot = materializeInputs(specification.notices, path.join(work, 'legal')); + const payload = path.join(work, 'payload'); + const data = path.join(payload, 'share/icu'); + mkdirSync(data, { recursive: true }); + assert.equal( + path.basename(specification.data), + 'icudt76l.dat', + 'expected pinned ICU76 little-endian data', + ); + copyFileSync(specification.data, path.join(data, 'icudt76l.dat')); + const manifest = nativeIcuDataManifest(data); + validateNativeIcuDataManifest(manifest, data); + writeFileSync(path.join(payload, 'manifest.properties'), manifest); + writeFileSync(path.join(payload, 'package-size.tsv'), icuPackageSizeReport(data)); + stageReleaseNotices(payload, { profile: 'native-icu-data', sourceRoot: legalRoot }); + await archiveDirectory(payload, output); + assertReleaseNoticesInArchive(output, { profile: 'native-icu-data', sourceRoot: legalRoot }); +} finally { + rmSync(work, { recursive: true, force: true }); +} diff --git a/build_defs/resources/mobile.bzl b/build_defs/resources/mobile.bzl new file mode 100644 index 000000000..9523ef4db --- /dev/null +++ b/build_defs/resources/mobile.bzl @@ -0,0 +1,247 @@ +"""Genuine target ABI receipts for separately admitted native seed domains.""" + +load("//build_defs/foundation:bun.bzl", "BunScriptInfo", "bun_action", "bun_script_test") +load("//build_defs/resources:resources.bzl", "NATIVE_SEED_ABI_CONFIGURATION", "NativeSeedInfo", "SEED_REUSE_ATTRS", "native_seed_abi_suppliers", "native_seed_envelopes", "seed_constructor_inputs", "seed_constructor_tree_members", "seed_promotion", "seed_reuse") +load("//build_defs/release:shipping.bzl", "shipping_export") +load("//build_defs/release:supplier.bzl", "ShippingSupplierInfo", "file_shipping_supplier", "merge_shipping_suppliers") +load("@oliphaunt_metadata//:metadata.bzl", "DATABASE_RESOURCE_ARTIFACTS", "DATABASE_RESOURCE_CONTRACT", "PRODUCTS", "SEED_REUSE_CONTROLS") +load("//build_defs/native/carriers:defs.bzl", "native_carrier_legal_inputs") +load("//build_defs/release:shipping.bzl", "shipping_package") + +NativeAbiReceiptInfo = provider(fields = ["receipt", "runtime", "target"]) + +def _constraint(ctx, name): + return ctx.target_platform_has_constraint(getattr(ctx.attr, name)[platform_common.ConstraintValueInfo]) + +def _target(ctx): + arm64 = _constraint(ctx, "_arm64") + x64 = _constraint(ctx, "_x64") + if _constraint(ctx, "_ios") and arm64: + device = _constraint(ctx, "_apple_device") + simulator = _constraint(ctx, "_apple_simulator") + if device == simulator: + fail("iOS seed ABI requires exactly one actual device/simulator compiler configuration") + return "ios-arm64" if device else "ios-arm64-simulator" + if _constraint(ctx, "_android"): + if arm64: + return "android-arm64-v8a" + if x64: + return "android-x86_64" + if _constraint(ctx, "_linux"): + if arm64: + return "linux-arm64-gnu" + if x64: + return "linux-x64-gnu" + if _constraint(ctx, "_macos") and arm64: + return "macos-arm64" + if _constraint(ctx, "_windows") and x64: + return "windows-x64-msvc" + fail("No admitted PostgreSQL target configuration supplies this native seed ABI receipt") + +def _native_abi_receipt_impl(ctx): + target = _target(ctx) + configurations = [file for file in ctx.files.configuration if file.basename == "pg_config.h"] + if len(configurations) != 1: + fail("Native seed ABI receipt needs one actual configured PostgreSQL header") + headers = {"src/include/pg_config.h": configurations[0].path} + for dependency, relative in ctx.attr.headers.items(): + files = dependency[DefaultInfo].files.to_list() + if len(files) != 1: + fail("Native seed ABI receipt header must name one actual source file") + headers[relative] = files[0].path + runtime = ctx.file.runtime + receipt = ctx.actions.declare_file(ctx.label.name + ".properties") + specification = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(specification, json.encode({"target": target, "runtime": runtime.path, "headers": headers, "output": receipt.path}) + "\n") + arguments = ctx.actions.args() + arguments.add(specification) + bun_action(ctx, ctx.attr._tool, arguments = [arguments], + inputs = [specification, runtime] + ctx.files.configuration + ctx.files.headers, + outputs = [receipt], mnemonic = "NativeSeedTargetAbi") + suppliers = native_seed_abi_suppliers([runtime]) + return [DefaultInfo(files = depset([receipt])), suppliers, + NativeAbiReceiptInfo(receipt = receipt, runtime = runtime, target = target), + OutputGroupInfo(supplier_inputs = suppliers.files)] + +native_abi_receipt = rule( + implementation = _native_abi_receipt_impl, + attrs = { + "runtime": attr.label(default = "//src/native/runtime:runtime_abi_binary", allow_single_file = True), + "configuration": attr.label(default = "@postgres//:configuration", allow_files = True), + "headers": attr.label_keyed_string_dict(default = { + Label("@postgres//:src/include/pg_config_manual.h"): "src/include/pg_config_manual.h", + Label("@postgres//:src/include/catalog/catversion.h"): "src/include/catalog/catversion.h", + Label("@postgres//:src/include/catalog/pg_control.h"): "src/include/catalog/pg_control.h", + }, allow_files = True), + "_tool": attr.label(default = "//build_defs/resources:abi_receipt", providers = [BunScriptInfo], cfg = "exec"), + "_android": attr.label(default = "@platforms//os:android"), + "_ios": attr.label(default = "@platforms//os:ios"), + "_apple_device": attr.label(default = "@apple_support//constraints:device"), + "_apple_simulator": attr.label(default = "@apple_support//constraints:simulator"), + "_linux": attr.label(default = "@platforms//os:linux"), + "_macos": attr.label(default = "@platforms//os:macos"), + "_windows": attr.label(default = "@platforms//os:windows"), + "_arm64": attr.label(default = "@platforms//cpu:aarch64"), + "_x64": attr.label(default = "@platforms//cpu:x86_64"), + }, +) + +def _native_seed_domain_impl(ctx): + producer = ctx.attr.producer[NativeSeedInfo] + frozen = ctx.actions.declare_file(ctx.label.name + ".tar") + construction = ctx.actions.declare_file(ctx.label.name + ".seed-construction.json") + specification = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + receipts = ctx.files.receipts + [producer.abi] + constructor_inputs = [producer.frozen] + receipts + ([ctx.file.icu] if ctx.file.icu else []) + logical_roles = {} + for dependency in ctx.attr.receipts: + for file in dependency[DefaultInfo].files.to_list(): + name = "abi/" + dependency.label.package + "/" + dependency.label.name + "/" + file.basename + if file.path in logical_roles and logical_roles[file.path] != name: + fail("Native domain ABI input has ambiguous dependency roles") + logical_roles[file.path] = name + reuse, reuse_inputs = seed_reuse(ctx) + promotion, promotion_inputs = seed_promotion(ctx) + ctx.actions.write(specification, json.encode({ + "seed": producer.frozen.path, + "producerConstruction": producer.construction.path, + "producerTarget": producer.target, + "profile": producer.profile, + "domain": ctx.attr.domain, + "receipts": [file.path for file in receipts], + "icu": ctx.file.icu.path if ctx.file.icu else None, + "contract": DATABASE_RESOURCE_CONTRACT, + "constructionInputs": seed_constructor_inputs(ctx, constructor_inputs, logical_roles), + "constructionTreeMembers": seed_constructor_tree_members(ctx), + "constructionOutput": construction.path, + "reuse": reuse, + "promotion": promotion, + "output": frozen.path, + }) + "\n") + arguments = ctx.actions.args() + arguments.add(specification) + bun_action(ctx, ctx.attr._tool, arguments = [arguments], + inputs = [specification, producer.construction] + constructor_inputs + reuse_inputs + promotion_inputs, + outputs = [frozen, construction], mnemonic = "NativeSeedDomainAdmission") + observation_inputs = depset( + [frozen, construction], + transitive = [ctx.attr.producer[OutputGroupInfo].observation_inputs], + ) + suppliers = merge_shipping_suppliers([ctx.attr.producer[ShippingSupplierInfo]] + [supplier[ShippingSupplierInfo] for supplier in ctx.attr.suppliers]) + return [DefaultInfo(files = depset([frozen, producer.abi, construction])), suppliers, + NativeSeedInfo(frozen = frozen, abi = producer.abi, runtime = producer.runtime, + profile = producer.profile, target = ctx.attr.domain, construction = construction), + OutputGroupInfo(frozen = depset([frozen]), abi = depset([producer.abi]), construction = depset([construction]), observation_inputs = observation_inputs, supplier_inputs = suppliers.files)] + +native_seed_domain = rule( + implementation = _native_seed_domain_impl, + attrs = dict(SEED_REUSE_ATTRS, **{ + "producer": attr.label(providers = [NativeSeedInfo, ShippingSupplierInfo], mandatory = True), + "receipts": attr.label_list(allow_files = True, mandatory = True), + "suppliers": attr.label_list(providers = [ShippingSupplierInfo], mandatory = True), + "domain": attr.string(values = ["android-datum64", "ios-datum64"], mandatory = True), + "icu": attr.label(allow_single_file = True), + "_tool": attr.label(default = "//build_defs/resources:seed_domain", providers = [BunScriptInfo], cfg = "exec"), + }), +) + +def android_resource_slice(name, qualification): + """Admit the actual Linux bootstrap against both actual Android producers.""" + compatible = ["@platforms//os:linux", "@platforms//cpu:x86_64"] + packages = [] + receipts = [":android_arm64_abi", ":android_x86_64_abi"] + for profile in DATABASE_RESOURCE_CONTRACT["profiles"]: + prefix = "android_datum64_" + profile + icu = ":icu_payload" if profile == "icu" else None + native_seed_domain(name = prefix + "_seed", producer = ":linux_x64_" + profile + "_seed", receipts = receipts, suppliers = receipts, + domain = "android-datum64", icu = icu, target_compatible_with = compatible, + **SEED_REUSE_CONTROLS.get("native/android-datum64/" + profile, {})) + native.filegroup(name = prefix + "_frozen", srcs = [":" + prefix + "_seed"], output_group = "frozen") + native.filegroup(name = prefix + "_construction", srcs = [":" + prefix + "_seed"], output_group = "construction") + packages.extend(native_seed_envelopes(prefix, "android-datum64", profile, ":" + prefix + "_seed", icu = icu, compatible = compatible)) + shipping_export(name = name, packages = packages, qualification = qualification, testonly = True, target_compatible_with = compatible) + +def _swift_seed_envelope_impl(ctx): + output = ctx.actions.declare_file(ctx.attr.out) + notices = {} + inputs = list(ctx.files.assets) + for target, relative in ctx.attr.notices.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1: + fail("Swift seed notice must resolve to one declared source") + notices[relative] = files[0].path + inputs += files + specification = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(specification, json.encode({ + "version": PRODUCTS["database-resources"]["version"], + "contract": DATABASE_RESOURCE_CONTRACT, + "assets": [file.path for file in ctx.files.assets], + "notices": notices, + "output": output.path, + }) + "\n") + bun_action(ctx, ctx.attr._tool, arguments = [specification.path], inputs = inputs + [specification], outputs = [output], mnemonic = "SwiftSeedEnvelope") + return [DefaultInfo(files = depset([output])), merge_shipping_suppliers([seed[ShippingSupplierInfo] for seed in ctx.attr.seeds])] + +_swift_seed_envelope = rule(implementation = _swift_seed_envelope_impl, attrs = { + "assets": attr.label_list(allow_files = True, mandatory = True), + "seeds": attr.label_list(providers = [ShippingSupplierInfo], mandatory = True), + "notices": attr.label_keyed_string_dict(allow_files = True), + "out": attr.string(mandatory = True), + "_tool": attr.label(default = "//build_defs/native/apple:seed_envelope", providers = [BunScriptInfo], cfg = "exec"), +}) + +def ios_resource_slice(name, qualification): + """Admit the real Mac bootstrap against both actual dynamic iOS producers.""" + compatible = ["@platforms//os:macos", "@platforms//cpu:aarch64"] + packages, assets, seeds = [], [":icu_payload"], [] + suppliers = [] + for target in ["device", "simulator"]: + supplier_name = "ios_seed_" + target + "_abi_supplier" + file_shipping_supplier(name = supplier_name, inputs = {"//src/native/runtime:apple_ios_" + target + "_abi": ""}, + owner = "@oliphaunt_metadata//:product_liboliphaunt-native", configuration = NATIVE_SEED_ABI_CONFIGURATION, + binding = "abi-contract", origin = json.encode({"kind": "current-source"}), target_compatible_with = compatible) + suppliers.append(":" + supplier_name) + for profile in DATABASE_RESOURCE_CONTRACT["profiles"]: + prefix = "ios_datum64_" + profile + icu = ":icu_payload" if profile == "icu" else None + native_seed_domain(name = prefix + "_seed", producer = ":macos_arm64_" + profile + "_seed", + receipts = ["//src/native/runtime:apple_ios_device_abi", "//src/native/runtime:apple_ios_simulator_abi"], suppliers = suppliers, + domain = "ios-datum64", icu = icu, target_compatible_with = compatible, + **SEED_REUSE_CONTROLS.get("native/ios-datum64/" + profile, {})) + native.filegroup(name = prefix + "_frozen", srcs = [":" + prefix + "_seed"], output_group = "frozen") + native.filegroup(name = prefix + "_construction", srcs = [":" + prefix + "_seed"], output_group = "construction") + packages.extend(native_seed_envelopes(prefix, "ios-datum64", profile, ":" + prefix + "_seed", icu = icu, compatible = compatible)) + assets.append(":" + prefix + "_assets") + seeds.append(":" + prefix + "_seed") + rows = [row for row in DATABASE_RESOURCE_ARTIFACTS if row["kind"] == "swift-source"] + if len(rows) != 1: + fail("Swift seed envelope requires exactly one canonical artifact") + asset = rows[0]["asset"].replace("{version}", PRODUCTS["database-resources"]["version"]) + _swift_seed_envelope(name = "swift_seed_archive", assets = assets, seeds = seeds, notices = native_carrier_legal_inputs(), out = asset, target_compatible_with = compatible) + shipping_package(name = "swift_seed_shipping", owner = "@oliphaunt_metadata//:product_database-resources", artifacts = [":swift_seed_archive"], + ecosystem = "github", package_name = asset, configuration = rows[0]["target"], role = "github-release-asset", suppliers = ":swift_seed_archive", observation_inputs = seeds) + shipping_export(name = name, packages = packages + [":swift_seed_shipping"], qualification = qualification, testonly = True, target_compatible_with = compatible) + +def mobile_resource_test(name, target): + """Compare every actual final carrier to its admitted frozen mobile seed.""" + if target not in ["android-datum64", "ios-datum64"]: + fail("mobile resource qualification requires its native domain") + android = target == "android-datum64" + compatible = ["@platforms//os:linux", "@platforms//cpu:x86_64"] if android else ["@platforms//os:macos", "@platforms//cpu:aarch64"] + files = [":icu_payload"] + ([] if android else [":swift_seed_archive"]) + seed_files = [] + for profile in sorted(DATABASE_RESOURCE_CONTRACT["profiles"]): + prefix = target.replace("-", "_") + "_" + profile + seed_files.extend([":" + prefix + "_" + suffix for suffix in ["frozen", "archive", "manifest", "carriers_npm_files", "carriers_cargo_files", "construction"]]) + if android: + seed_files.append(":" + prefix + "_carriers_maven_files") + bun_script_test( + name = name, + entry_point = "//build_defs/resources:mobile_resource_contract.mts", + args = [target, PRODUCTS["database-resources"]["version"], PRODUCTS["liboliphaunt-native"]["version"], + "$(location :icu_payload)", "-" if android else "$(location :swift_seed_archive)"] + + ["$(location " + file + ")" for file in seed_files], + data = files + seed_files + ["//build_defs/resources:helpers"], + target_compatible_with = compatible, + size = "medium", + ) diff --git a/build_defs/resources/mobile_resource_contract.mts b/build_defs/resources/mobile_resource_contract.mts new file mode 100644 index 000000000..af2d8a40e --- /dev/null +++ b/build_defs/resources/mobile_resource_contract.mts @@ -0,0 +1,302 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + createReadStream, + mkdirSync, + readdirSync, + readFileSync, + realpathSync, + statSync, +} from 'node:fs'; +import path from 'node:path'; +import { validateNativeIcuDataManifest } from '../../src/database-resources/contracts/icu-data.mts'; +import { + emptyDirectoryPaths, + logicalTreeSha256, + parseProperties, + validateNativeClusterSeedDirectory, +} from '../../src/database-resources/contracts/native-manifest.mts'; +import { seedCarrierIdentities } from '../../src/database-resources/seeds/carrier-identities.mts'; +import { stageMobileSeed } from '../../src/database-resources/seeds/package-mobile-carriers.mts'; +import { + compareNativeMobileAbiReceipts, + NATIVE_MOBILE_ABI_TARGETS_BY_DOMAIN, +} from '../../src/native/runtime/tools/native-mobile-abi-contract.mts'; +import { validateMavenCentralPublication } from '../../tools/packaging/maven-central-contract.mts'; +import { + archiveLogicalTreeRows, + extractPortableArchiveTree, + readPortableArchiveEntries, + readPortableTarStream, +} from '../../tools/packaging/portable-archive.mts'; +import { seedProducerIdentity, validateSeedConstructionReceipt } from './seed_construction.mts'; + +type Entries = ReturnType; + +function regular(entries: Entries, name: string): Buffer { + const entry = entries.get(name); + assert(entry?.isFile && !entry.isSymbolicLink, `missing regular archive member ${name}`); + return entry.data(); +} + +/** Compare physical files, directories and modes across the final package formats. */ +export function assertMatchingArchiveTrees( + left: Entries, + leftPrefix: string, + right: Entries, + rightPrefix: string, +): void { + const tree = (entries: Entries, prefix: string) => + [...entries] + .filter(([name]) => name.startsWith(prefix) && name !== prefix.replace(/\/$/u, '')) + .map(([name, entry]) => { + assert(entry.isDirectory || (entry.isFile && !entry.isSymbolicLink), name); + return { + path: name.slice(prefix.length), + mode: entry.mode & 0o7777, + directory: entry.isDirectory, + sha256: entry.isDirectory + ? null + : createHash('sha256').update(entry.data()).digest('hex'), + }; + }) + .sort((a, b) => a.path.localeCompare(b.path)); + const expected = tree(right, rightPrefix); + assert( + expected.some((row) => !row.directory), + 'comparison requires actual resource files', + ); + assert.deepEqual( + tree(left, leftPrefix), + expected, + 'final package changed its frozen resource tree', + ); +} + +type SeedFiles = { + profile: 'standard' | 'icu'; + frozen: string; + archive: string; + manifest: string; + npm: string; + cargo: string; + construction: string; + maven?: string; +}; + +/** Actual package-byte proof; target device execution belongs to its separate installed lane. */ +export async function verifyMobileResourceFiles({ + target, + version, + runtimeVersion, + icu, + swift, + seeds, + root, +}: { + target: 'android-datum64' | 'ios-datum64'; + version: string; + runtimeVersion: string; + icu: string; + swift?: string; + seeds: SeedFiles[]; + root: string; +}): Promise { + assert(['android-datum64', 'ios-datum64'].includes(target)); + assert.match(runtimeVersion, /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u); + assert.deepEqual(seeds.map(({ profile }) => profile).sort(), ['icu', 'standard']); + assert.equal(Boolean(swift), target === 'ios-datum64'); + // Bazel's declared outer Files may be runfiles aliases. Archive members retain + // the strict parser's regular-file, path, mode and complete-tree checks. + icu = realpathSync(icu); + swift = swift ? realpathSync(swift) : undefined; + seeds = seeds.map((seed) => ({ + ...seed, + frozen: realpathSync(seed.frozen), + archive: realpathSync(seed.archive), + manifest: realpathSync(seed.manifest), + npm: realpathSync(seed.npm), + cargo: realpathSync(seed.cargo), + construction: realpathSync(seed.construction), + ...(seed.maven ? { maven: realpathSync(seed.maven) } : {}), + })); + const icuRoot = path.join(root, 'icu'); + extractPortableArchiveTree(icu, icuRoot); + const icuData = path.join(icuRoot, 'share/icu'); + validateNativeIcuDataManifest(readFileSync(path.join(icuRoot, 'manifest.properties')), icuData); + const swiftEntries = swift ? readPortableArchiveEntries(swift) : undefined; + if (swiftEntries) + assertMatchingArchiveTrees( + swiftEntries, + 'Sources/OliphauntICU/share/icu/', + readPortableArchiveEntries(icu), + 'share/icu/', + ); + const identities = seedCarrierIdentities(); + for (const seed of seeds) { + assert.equal(Boolean(seed.maven), target === 'android-datum64'); + const construction = validateSeedConstructionReceipt( + JSON.parse(readFileSync(seed.construction, 'utf8')), + ); + assert.equal(construction.intent.family, 'native'); + assert.equal(construction.intent.target, target); + assert.equal(construction.intent.profile, seed.profile); + const frozenBytes = readFileSync(seed.frozen); + assert.deepEqual(construction.frozen, { + size: frozenBytes.length, + sha256: createHash('sha256').update(frozenBytes).digest('hex'), + }); + const frozenRoot = path.join(root, seed.profile, 'frozen'); + mkdirSync(frozenRoot, { recursive: true }); + const stream = createReadStream(seed.frozen); + let inventory; + try { + inventory = await readPortableTarStream(stream, seed.frozen, {}, { root: frozenRoot }); + } finally { + stream.destroy(); + } + const frozenEntries = new Map( + [...inventory].map(([name, entry]) => [ + name, + { + ...entry, + data: () => readFileSync(path.join(frozenRoot, name)), + }, + ]), + ); + const receipts = NATIVE_MOBILE_ABI_TARGETS_BY_DOMAIN[target].map((abiTarget) => ({ + text: regular(frozenEntries, `abi-receipts/${abiTarget}.properties`).toString(), + label: seed.frozen, + })); + compareNativeMobileAbiReceipts(target, receipts); + validateNativeClusterSeedDirectory(frozenRoot, seed.profile, { + target, + icuData: seed.profile === 'icu' ? icuData : undefined, + }); + const archiveEntries = readPortableArchiveEntries(seed.archive); + assertMatchingArchiveTrees(archiveEntries, '', frozenEntries, 'files/'); + const stage = path.join(root, seed.profile, 'canonical-mobile'); + const manifest = stageMobileSeed({ + archive: seed.archive, + manifest: seed.manifest, + destination: stage, + target, + profile: seed.profile, + icuData: seed.profile === 'icu' ? icuData : undefined, + }); + assert.equal(manifest.runtime.product, 'liboliphaunt-native'); + assert.match(manifest.runtime.version, /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u); + if (construction.sourceManifest) { + const original = JSON.parse(construction.sourceManifest.contents); + assert.deepEqual(manifest.runtime, original.runtime, 'retain the admitted seed runtime'); + assert.deepEqual(manifest.source, original.source, 'retain the admitted seed source'); + } else assert.equal(manifest.runtime.version, runtimeVersion); + assert.deepEqual( + { + postgresSha256: manifest.source?.postgresSha256, + initdbSha256: manifest.source?.initdbSha256, + }, + seedProducerIdentity(construction), + 'mobile seed hashes must identify its original constructor', + ); + assert.equal( + construction.pgdata.treeSha256, + logicalTreeSha256(archiveLogicalTreeRows(archiveEntries, seed.archive, '')), + ); + assert.deepEqual( + construction.pgdata.emptyDirectories, + emptyDirectoryPaths(path.join(stage, 'files')), + ); + const identity = identities.find( + (row) => row.family === 'native' && row.target === target && row.profile === seed.profile, + ); + assert(identity, 'mobile resource requires one canonical carrier identity'); + const npm = readPortableArchiveEntries(seed.npm); + const packageJson = JSON.parse(regular(npm, 'package/package.json').toString()); + assert.equal(packageJson.name, identity.npm); + assert.equal(packageJson.version, version); + assert.deepEqual( + packageJson.dependencies ?? {}, + seed.profile === 'icu' ? { '@oliphaunt/icu': version } : {}, + ); + const npmManifest = JSON.parse(regular(npm, 'package/manifest.json').toString()); + const { directory, ...npmSeedManifest } = npmManifest; + assert.deepEqual(npmSeedManifest, manifest, 'npm must preserve the canonical seed manifest'); + assert.equal( + directory.treeSha256, + logicalTreeSha256(archiveLogicalTreeRows(archiveEntries, seed.archive, '')), + ); + assert.deepEqual(directory.emptyDirectories, emptyDirectoryPaths(path.join(stage, 'files'))); + assertMatchingArchiveTrees(npm, `package/${directory.path}/`, archiveEntries, ''); + assert(!npm.has('package/seed.tar.zst'), 'native npm seed must expose installed PGDATA'); + const cargo = readPortableArchiveEntries(seed.cargo); + const crateRoot = `${identity.cargo}-${version}`; + const cargoManifest = Bun.TOML.parse(regular(cargo, `${crateRoot}/Cargo.toml`).toString()); + assert.equal(cargoManifest.package.name, identity.cargo); + assert.equal(cargoManifest.package.version, version); + assert.deepEqual( + cargoManifest.dependencies ?? {}, + seed.profile === 'icu' ? { 'oliphaunt-icu': `=${version}` } : {}, + ); + assert(regular(cargo, `${crateRoot}/seed.tar.zst`).equals(readFileSync(seed.archive))); + assert.deepEqual(JSON.parse(regular(cargo, `${crateRoot}/manifest.json`).toString()), manifest); + assert(statSync(seed.cargo).size <= 10 * 1024 * 1024); + const resource = seed.profile === 'icu' ? 'cluster-seed-icu' : 'cluster-seed'; + const validateMobile = (entries: Entries, prefix: string) => { + assertMatchingArchiveTrees(entries, `${prefix}/files/`, archiveEntries, ''); + const actual = regular(entries, `${prefix}/manifest.properties`); + assert(actual.equals(readFileSync(path.join(stage, 'manifest.properties')))); + const fields = parseProperties(actual, prefix); + assert.equal(fields.get('target'), target); + }; + if (seed.maven) { + const coordinate = path.join(seed.maven, 'dev/oliphaunt/runtime', identity.cargo, version); + validateMavenCentralPublication({ + context: 'actual Android seed carrier', + files: readdirSync(coordinate).map((name) => ({ + name, + size: statSync(path.join(coordinate, name)).size, + })), + pomText: readFileSync(path.join(coordinate, `${identity.cargo}-${version}.pom`), 'utf8'), + }); + validateMobile( + readPortableArchiveEntries( + realpathSync(path.join(coordinate, `${identity.cargo}-${version}.tar.gz`)), + ), + resource, + ); + } else { + assert(swiftEntries, 'iOS resource proof requires its final Swift source carrier'); + const module = `OliphauntSeedNativeIOS${seed.profile === 'icu' ? 'ICU' : 'Standard'}`; + validateMobile(npm, `package/${module}.bundle/${resource}`); + validateMobile(swiftEntries, `Sources/${module}/${resource}`); + regular(swiftEntries, `Sources/${module}/Resources.swift`); + } + } +} + +if (import.meta.main) { + const [target, version, runtimeVersion, icu, swift, ...inputs] = process.argv.slice(2); + assert(process.env.TEST_TMPDIR, 'test requires a private Bazel scratch directory'); + const stride = target === 'android-datum64' ? 7 : 6; + assert.equal(inputs.length, stride * 2, 'test requires both complete actual seed packages'); + const seeds = (['icu', 'standard'] as const).map((profile, index) => { + const [frozen, archive, manifest, npm, cargo, construction, maven] = inputs.slice( + index * stride, + (index + 1) * stride, + ); + return { profile, frozen, archive, manifest, npm, cargo, construction, maven }; + }); + await verifyMobileResourceFiles({ + target: target as 'android-datum64' | 'ios-datum64', + version, + runtimeVersion, + icu, + swift: swift === '-' ? undefined : swift, + seeds, + root: process.env.TEST_TMPDIR, + }); + console.log( + `${target} final GitHub/npm/Cargo/mobile resources preserve the admitted seed bytes and ABI`, + ); +} diff --git a/build_defs/resources/mobile_resource_contract.test.mts b/build_defs/resources/mobile_resource_contract.test.mts new file mode 100644 index 000000000..f76f3074a --- /dev/null +++ b/build_defs/resources/mobile_resource_contract.test.mts @@ -0,0 +1,429 @@ +import { expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { + existsSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + nativeIcuDataManifest, + parseNativeIcuDataIdentity, +} from '../../src/database-resources/contracts/icu-data.mts'; +import { NATIVE_PGDATA_DIRECTORIES } from '../../src/database-resources/contracts/native-manifest.mts'; +import { seedCarrierIdentities } from '../../src/database-resources/seeds/carrier-identities.mts'; +import { + packageMobileSeedCarriers, + stageMobileSeed, +} from '../../src/database-resources/seeds/package-mobile-carriers.mts'; +import { NATIVE_MOBILE_ABI_TARGETS_BY_DOMAIN } from '../../src/native/runtime/tools/native-mobile-abi-contract.mts'; +import { createDeterministicTar } from '../../tools/packaging/archive-directory.mts'; +import { + canonicalGzipSync, + readPortableArchiveEntries, + releaseZstdCompressSync, +} from '../../tools/packaging/portable-archive.mts'; +import { tarArchive } from '../../tools/packaging/testdata/tar-fixture.mts'; +import { releaseNoticeRows } from '../../tools/packaging/release-notices.mts'; +import { + assertMatchingArchiveTrees, + verifyMobileResourceFiles, +} from './mobile_resource_contract.mts'; +import { + captureSeedConstructionIntent, + writeSeedConstructionReceipt, +} from './seed_construction.mts'; + +test('final resource comparison binds PostgreSQL bytes, empty directories, modes and regular files', () => { + const root = mkdtempSync(path.join(tmpdir(), 'mobile-resource-proof-')); + try { + const original = [ + { name: 'PG_VERSION', data: '18\n' }, + { name: 'global/', type: '5', mode: 0o755 }, + { name: 'global/pg_control', data: 'physical seed bytes' }, + { name: 'pg_twophase/', type: '5', mode: 0o755 }, + ]; + const archive = (name: string, rows) => { + const file = path.join(root, name); + writeFileSync(file, tarArchive(rows)); + return readPortableArchiveEntries(file); + }; + const frozen = archive( + 'frozen.tar.gz', + original.map((row) => ({ ...row, name: `files/${row.name}` })), + ); + const equivalent = archive('equivalent.tar.gz', [...original].reverse()); + assertMatchingArchiveTrees(equivalent, '', frozen, 'files/'); + for (const [name, rows] of [ + [ + 'changed', + original.map((row) => + row.name === 'global/pg_control' ? { ...row, data: 'changed bytes' } : row, + ), + ], + ['missing-empty', original.filter((row) => row.name !== 'pg_twophase/')], + ['mode', original.map((row) => (row.name === 'PG_VERSION' ? { ...row, mode: 0o755 } : row))], + [ + 'symlink', + original.map((row) => + row.name === 'global/pg_control' + ? { ...row, data: '', type: '2', linkTarget: 'other' } + : row, + ), + ], + ]) + expect(() => + assertMatchingArchiveTrees(archive(`${name}.tar.gz`, rows), '', frozen, 'files/'), + ).toThrow(); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('the final mobile verifier consumes conventional Android and iOS package writers through declared input aliases', async () => { + const root = mkdtempSync(path.join(tmpdir(), 'mobile-carrier-formatters-')); + try { + const version = '7.8.9'; + const runtimeVersion = '1.2.3'; + const contract = JSON.parse( + readFileSync( + new URL('../../src/database-resources/contracts/contract.json', import.meta.url), + 'utf8', + ), + ); + const icuRoot = path.join(root, 'icu'); + const data = path.join(icuRoot, 'share/icu'); + mkdirSync(data, { recursive: true }); + writeFileSync(path.join(data, 'icudt76l.dat'), 'formatter fixture ICU bytes'); + const icuManifest = nativeIcuDataManifest(data); + writeFileSync(path.join(icuRoot, 'manifest.properties'), icuManifest); + const assets = path.join(root, 'assets'); + mkdirSync(assets); + const icu = path.join(assets, `database-resources-${version}-icu-data.tar.gz`); + writeFileSync(icu, canonicalGzipSync(await createDeterministicTar(icuRoot))); + const identity = parseNativeIcuDataIdentity(icuManifest); + const pgdata = path.join(root, 'pgdata'); + for (const directory of NATIVE_PGDATA_DIRECTORIES) + mkdirSync(path.join(pgdata, directory), { recursive: true }); + writeFileSync(path.join(pgdata, 'PG_VERSION'), '18\n'); + writeFileSync( + path.join(pgdata, 'global/pg_control'), + 'formatter fixture, not runtime evidence', + ); + const seedBytes = releaseZstdCompressSync(await createDeterministicTar(pgdata)); + const values = { + schema: 'oliphaunt-native-mobile-abi-v1', + byteOrder: 'little', + datumBytes: '8', + maximumAlignof: '8', + float8ByVal: '1', + blockSize: '8192', + walBlockSize: '8192', + relationSegmentSize: '131072', + nameDataLength: '64', + indexMaxKeys: '32', + catalogVersion: '202506291', + pgControlVersion: '1800', + }; + const sourceRoot = path.resolve(import.meta.dir, '../..'); + const notices = Object.fromEntries( + releaseNoticeRows({ profile: 'native-runtime-resources' }).flatMap((row) => + [row.source, row.sourceManifest] + .filter((file): file is string => typeof file === 'string') + .map((file) => [path.relative(sourceRoot, file), file]), + ), + ); + for (const target of ['android-datum64', 'ios-datum64'] as const) { + const seeds = []; + const producer = { postgresSha256: 'a'.repeat(64), initdbSha256: 'b'.repeat(64) }; + const constructions = []; + for (const profile of ['icu', 'standard'] as const) { + const stem = `database-resources-${version}-seed-native-${target}-${profile}`; + const archive = path.join(assets, `${stem}.tar.zst`); + const manifest = path.join(assets, `${stem}.json`); + writeFileSync(archive, seedBytes); + writeFileSync( + manifest, + JSON.stringify({ + schema: contract.manifests.wasix.schema, + catalogProfile: profile, + artifactRole: contract.profiles[profile].artifactRole, + runtime: { + product: 'liboliphaunt-native', + engineFamily: 'native', + target, + version: runtimeVersion, + postgresMajor: 18, + physicalFormat: contract.physicalFormats.native, + compatibilityKey: contract.compatibilityKeys.native[target], + }, + source: { producer: 'native-initdb', ...producer }, + archive: { + sha256: createHash('sha256').update(seedBytes).digest('hex'), + compressedBytes: seedBytes.length, + }, + icu: profile === 'icu' ? identity : null, + }), + ); + const frozenRoot = path.join(root, `${target}-${profile}-frozen`); + stageMobileSeed({ + archive, + manifest, + destination: frozenRoot, + target, + profile, + icuData: profile === 'icu' ? data : undefined, + }); + mkdirSync(path.join(frozenRoot, 'abi-receipts')); + for (const abiTarget of NATIVE_MOBILE_ABI_TARGETS_BY_DOMAIN[target]) + writeFileSync( + path.join(frozenRoot, 'abi-receipts', `${abiTarget}.properties`), + `${Object.entries({ ...values, target: abiTarget }) + .map(([key, value]) => `${key}=${value}`) + .join('\n')}\n`, + ); + const frozen = path.join(root, `${target}-${profile}-frozen.tar`); + writeFileSync(frozen, await createDeterministicTar(frozenRoot)); + const construction = path.join(root, `${target}-${profile}.seed-construction.json`); + const intent = captureSeedConstructionIntent( + { family: 'native', target, profile }, + { producer }, + { manifest }, + ); + writeSeedConstructionReceipt(construction, intent, frozen, path.join(frozenRoot, 'files')); + constructions.push({ construction, intent, frozen, frozenRoot, archive, manifest }); + const carrierIdentity = seedCarrierIdentities().find( + (row) => row.family === 'native' && row.target === target && row.profile === profile, + ); + if (!carrierIdentity) throw new Error('missing canonical seed carrier'); + const npmOutput = path.join(root, `${target}-${profile}.tgz`); + const cargoOutput = path.join(root, `${target}-${profile}.crate`); + const specification = path.join(root, `${target}-${profile}-inputs.json`); + const invoke = (inputs: string[]) => { + writeFileSync( + specification, + JSON.stringify({ + kind: 'seed', + family: 'native', + target, + profile, + version, + contract, + notices, + assets: inputs, + npmOutput, + cargoOutput, + carriers: [ + { ecosystem: 'npm', name: carrierIdentity.npm }, + { ecosystem: 'cargo', name: carrierIdentity.cargo }, + ], + }), + ); + return Bun.spawnSync( + [ + process.execPath, + '--no-install', + '--no-env-file', + path.join(import.meta.dir, 'carriers.mts'), + specification, + ], + { stdout: 'pipe', stderr: 'pipe' }, + ); + }; + if (target === 'ios-datum64' && profile === 'icu') { + const missing = invoke([archive, manifest]); + expect(missing.exitCode).not.toBe(0); + expect(missing.stderr.toString()).toContain( + `database-resources-${version}-icu-data.tar.gz cannot be inspected`, + ); + expect(existsSync(npmOutput)).toBe(false); + expect(existsSync(cargoOutput)).toBe(false); + } + const complete = invoke([archive, manifest, ...(profile === 'icu' ? [icu] : [])]); + expect(complete.exitCode, complete.stderr.toString()).toBe(0); + for (const [name, entry] of readPortableArchiveEntries(cargoOutput)) + expect(entry.mode, name).toBe(entry.isDirectory ? 0o755 : 0o644); + seeds.push({ + profile, + frozen, + archive, + manifest, + npm: npmOutput, + cargo: cargoOutput, + construction, + maven: target === 'android-datum64' ? path.join(root, 'maven') : undefined, + }); + } + const outputs = await packageMobileSeedCarriers({ + targets: [target], + profiles: ['standard', 'icu'], + assetDir: assets, + version, + contract, + workDir: path.join(root, `${target}-mobile`), + mavenDir: path.join(root, 'maven'), + }); + const aliases = path.join(root, `${target}-input-aliases`); + mkdirSync(aliases); + const alias = (file: string) => { + const input = path.join(aliases, path.basename(file)); + symlinkSync(file, input); + return input; + }; + const aliasedIcu = alias(icu); + const swift = target === 'ios-datum64' ? alias(outputs[0]) : undefined; + let aliasedMaven: string | undefined; + if (target === 'android-datum64') { + const mavenRunfiles = path.join(root, 'maven-runfiles'); + for (const seed of seeds) { + const identity = seedCarrierIdentities().find( + (row) => + row.family === 'native' && row.target === target && row.profile === seed.profile, + ); + if (!identity) throw new Error('missing canonical seed carrier'); + const coordinate = path.join('dev/oliphaunt/runtime', identity.cargo, version); + const source = path.join(root, 'maven', coordinate); + const destination = path.join(mavenRunfiles, coordinate); + mkdirSync(destination, { recursive: true }); + for (const name of readdirSync(source)) + symlinkSync(path.join(source, name), path.join(destination, name)); + } + aliasedMaven = alias(mavenRunfiles); + } + const aliasedSeeds = seeds.map((seed) => ({ + ...seed, + frozen: alias(seed.frozen), + archive: alias(seed.archive), + manifest: alias(seed.manifest), + npm: alias(seed.npm), + cargo: alias(seed.cargo), + construction: alias(seed.construction), + maven: aliasedMaven, + })); + await verifyMobileResourceFiles({ + target, + version, + runtimeVersion, + icu: aliasedIcu, + swift, + seeds: aliasedSeeds, + root: path.join(root, `${target}-proof`), + }); + await expect( + verifyMobileResourceFiles({ + target, + version, + runtimeVersion: '1.2.4', + icu: aliasedIcu, + swift, + seeds: aliasedSeeds, + root: path.join(root, `${target}-fresh-runtime-mismatch`), + }), + ).rejects.toThrow(); + const publication = { + product: 'database-resources', + version: '0.2.2', + tagName: 'database-resources-v0.2.2', + publicationSha: 'a'.repeat(40), + publicationTree: 'b'.repeat(40), + releaseSha: 'c'.repeat(40), + }; + for (const row of constructions) { + const contents = readFileSync(row.manifest, 'utf8'); + const manifestIdentity = { + size: Buffer.byteLength(contents), + sha256: createHash('sha256').update(contents).digest('hex'), + }; + writeSeedConstructionReceipt( + row.construction, + row.intent, + row.frozen, + path.join(row.frozenRoot, 'files'), + { + kind: 'completed-publication', + operation: 'adopted', + publication, + archive: { + size: seedBytes.length, + sha256: createHash('sha256').update(seedBytes).digest('hex'), + }, + manifest: manifestIdentity, + }, + undefined, + { ...manifestIdentity, contents, publication }, + ); + } + await verifyMobileResourceFiles({ + target, + version, + runtimeVersion: '1.2.4', + icu: aliasedIcu, + swift, + seeds: aliasedSeeds, + root: path.join(root, `${target}-admitted-original-runtime`), + }); + await expect( + verifyMobileResourceFiles({ + target, + version, + runtimeVersion: 'latest', + icu: aliasedIcu, + swift, + seeds: aliasedSeeds, + root: path.join(root, `${target}-invalid-runtime-version`), + }), + ).rejects.toThrow(); + const original = readFileSync(seeds[0].manifest, 'utf8'); + for (const mutation of [ + { runtime: { ...JSON.parse(original).runtime, version: '1.2.4' } }, + { runtime: { ...JSON.parse(original).runtime, product: 'liboliphaunt-wasix' } }, + { source: { ...JSON.parse(original).source, postgresSha256: 'c'.repeat(64) } }, + { archive: { ...JSON.parse(original).archive, sha256: 'c'.repeat(64) } }, + ]) { + writeFileSync(seeds[0].manifest, JSON.stringify({ ...JSON.parse(original), ...mutation })); + await expect( + verifyMobileResourceFiles({ + target, + version, + runtimeVersion: '1.2.4', + icu: aliasedIcu, + swift, + seeds: aliasedSeeds, + root: path.join(root, `${target}-changed-original-provenance`), + }), + ).rejects.toThrow(); + } + writeFileSync(seeds[0].manifest, original); + await expect( + verifyMobileResourceFiles({ + target, + version: '7.8.8', + runtimeVersion, + icu: aliasedIcu, + swift, + seeds: aliasedSeeds, + root: path.join(root, `${target}-wrong-version`), + }), + ).rejects.toThrow(); + await expect( + verifyMobileResourceFiles({ + target, + version, + runtimeVersion, + icu: alias(icuRoot), + swift, + seeds: aliasedSeeds, + root: path.join(root, `${target}-directory-substitution`), + }), + ).rejects.toThrow(); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/build_defs/resources/native_seed.mts b/build_defs/resources/native_seed.mts new file mode 100644 index 000000000..99957aeec --- /dev/null +++ b/build_defs/resources/native_seed.mts @@ -0,0 +1,257 @@ +import assert from 'node:assert/strict'; +import { copyFileSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { validateNativeIcuDataManifest } from '../../src/database-resources/contracts/icu-data.mts'; +import { + emptyDirectoryPaths, + filesystemTreeRows, + logicalTreeSha256, + validateNativeClusterSeedDirectory, +} from '../../src/database-resources/contracts/native-manifest.mts'; +import { installNativeClusterSeed } from '../../src/database-resources/seeds/native/tools/stage-native-cluster-seed.mts'; +import { + nativeMobileAbiReceipt, + parseNativeMobileAbiReceipt, +} from '../../src/native/runtime/tools/native-mobile-abi-contract.mts'; +import { createDeterministicTar } from '../../tools/packaging/archive-directory.mts'; +import { inspectPlatformBinaryBuffer } from '../../tools/packaging/platform-binary-contract.mts'; +import { extractPortableArchiveTree } from '../../tools/packaging/portable-archive.mts'; +import { extractNativePayload } from '../native/host-runtime-test-helpers.mts'; +import { + captureSeedConstructionIntent, + captureSeedContentIntent, + captureSeedProducerIdentity, + seedConstructionFileBinding, + seedConstructionInvocation, + selectCompletedSeed, + selectQualifiedSeed, + writePromotedSeedReceipt, + writeSeedConstructionReceipt, +} from './seed_construction.mts'; +import { + materializeArchive, + materializeInputs, + nativeSeedHost, + privateWork, + readSpecification, + run, + seedEnvironment, +} from './shared.mts'; + +const specification = readSpecification(); +const host = nativeSeedHost(specification.runtimeArtifact); +assert.equal(specification.target, host.target); +const output = path.resolve(specification.output); +const work = privateWork(output); +try { + const runtime = path.join(work, 'runtime'); + await extractNativePayload(specification.runtime, runtime); + for (const binary of [ + `bin/postgres${host.executableSuffix}`, + `bin/initdb${host.executableSuffix}`, + host.libraryRelativePath, + ]) { + inspectPlatformBinaryBuffer(readFileSync(path.join(runtime, binary)), { + target: specification.target, + label: binary, + }); + } + const abiRoot = materializeInputs(specification.headers, path.join(work, 'headers')); + const abi = nativeMobileAbiReceipt(abiRoot, specification.target); + parseNativeMobileAbiReceipt(abi); + let icuData: string | undefined; + if (specification.icu) { + const icuRoot = path.join(work, 'icu'); + extractPortableArchiveTree( + materializeArchive(specification.icu, path.join(work, 'inputs')), + icuRoot, + ); + icuData = path.join(icuRoot, 'share/icu'); + validateNativeIcuDataManifest(readFileSync(path.join(icuRoot, 'manifest.properties')), icuData); + } + assert.equal(specification.profile === 'icu', Boolean(icuData)); + const prepared = path.join(work, 'prepared'); + const frozen = path.join(work, 'frozen'); + mkdirSync(prepared); + const command = path.join(runtime, `bin/initdb${host.executableSuffix}`); + const arguments_ = [ + '-D', + path.join(prepared, 'files'), + '-U', + 'postgres', + '--auth=trust', + '--locale-provider=libc', + '--locale=C', + '--encoding=UTF8', + '-L', + path.join(runtime, 'share/postgresql'), + '-c', + `shared_memory_type=${host.memoryType}`, + '-c', + `dynamic_shared_memory_type=${host.memoryType}`, + '-c', + 'max_connections=100', + '-c', + 'autovacuum_worker_slots=16', + '-c', + 'shared_buffers=128MB', + ]; + const environment = seedEnvironment(runtime, work, icuData); + const intent = specification.constructionInputs + ? captureSeedConstructionIntent( + { family: 'native', target: specification.target, profile: specification.profile }, + { + toolFlags: process.execArgv, + producer: captureSeedProducerIdentity(runtime, specification.target), + invocation: seedConstructionInvocation(command, arguments_, environment, { + runtime, + work, + ...(icuData ? { icuData } : {}), + }), + contract: specification.contract, + runtimeArtifact: specification.runtimeArtifact, + abi, + bindings: { + runtime: seedConstructionFileBinding( + specification.constructionInputs, + specification.runtime, + ), + headers: Object.fromEntries( + Object.entries(specification.headers).map(([role, file]) => [ + role, + seedConstructionFileBinding(specification.constructionInputs, file as string), + ]), + ), + icu: specification.icu + ? seedConstructionFileBinding(specification.constructionInputs, specification.icu) + : null, + }, + }, + specification.constructionInputs, + specification.constructionTreeMembers, + ) + : undefined; + const contentIntent = intent + ? captureSeedContentIntent( + { family: 'native', target: specification.target, profile: specification.profile }, + { + contract: specification.contract, + abi, + invocation: seedConstructionInvocation( + command, + arguments_, + { + LANG: environment.LANG, + LC_ALL: environment.LC_ALL, + TZ: environment.TZ, + PGTZ: environment.PGTZ, + OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY: + environment.OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY, + OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY: + environment.OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY, + OLIPHAUNT_INTERNAL_ICU_READY: environment.OLIPHAUNT_INTERNAL_ICU_READY, + }, + { runtime, work, ...(icuData ? { icuData } : {}) }, + ), + }, + path.join(runtime, 'share/postgresql'), + icuData, + ) + : undefined; + assert.ok(!specification.reuse || intent, 'seed reuse requires declared constructor inputs'); + assert.ok( + !specification.promotion || intent, + 'seed promotion requires declared constructor inputs', + ); + assert.ok( + !(specification.reuse && specification.promotion), + 'seed has more than one physical origin', + ); + const promoted = intent + ? selectQualifiedSeed(intent, specification.promotion, contentIntent) + : undefined; + if (promoted) { + copyFileSync(promoted.frozen, output); + await extractNativePayload(output, frozen); + validateNativeClusterSeedDirectory(frozen, specification.profile, { + target: specification.target, + icuData, + }); + assert.equal( + readFileSync(path.join(frozen, 'abi.properties'), 'utf8'), + abi, + 'promoted seed must retain the current physical ABI contract', + ); + writeFileSync(specification.abiOutput, abi); + assert.ok(specification.constructionOutput, 'declared seed promotion requires receipt output'); + writePromotedSeedReceipt( + specification.constructionOutput, + promoted, + output, + path.join(frozen, 'files'), + ); + } else { + const completed = intent + ? selectCompletedSeed(intent, specification.reuse, contentIntent) + : undefined; + if (completed) { + extractPortableArchiveTree( + materializeArchive(completed.archive, path.join(work, 'completed')), + path.join(prepared, 'files'), + ); + } else { + // PostgreSQL intentionally uses clock/PID/CSPRNG; freeze this one construction intact. + run(command, arguments_, environment, work); + } + const retained = completed + ? { + tree: logicalTreeSha256(filesystemTreeRows(path.join(prepared, 'files'))), + emptyDirectories: emptyDirectoryPaths(path.join(prepared, 'files')), + } + : undefined; + installNativeClusterSeed( + prepared, + { + runtime, + destination: frozen, + target: specification.target, + profile: specification.profile, + icuData, + }, + specification.contract, + ); + writeFileSync(path.join(frozen, 'abi.properties'), abi); + if (retained) { + assert.equal( + logicalTreeSha256(filesystemTreeRows(path.join(frozen, 'files'))), + retained.tree, + 'seed reuse must preserve all PGDATA bytes', + ); + assert.deepEqual( + emptyDirectoryPaths(path.join(frozen, 'files')), + retained.emptyDirectories, + 'seed reuse must preserve empty PGDATA directories', + ); + } + // A File archive preserves required empty directories across Bazel action transport. + writeFileSync(output, await createDeterministicTar(frozen)); + writeFileSync(specification.abiOutput, abi); + if (intent) { + assert.ok( + specification.constructionOutput, + 'declared seed intent requires its receipt output', + ); + writeSeedConstructionReceipt( + specification.constructionOutput, + intent, + output, + path.join(frozen, 'files'), + completed?.origin, + contentIntent, + completed?.sourceManifest, + ); + } + } +} finally { + rmSync(work, { recursive: true, force: true }); +} diff --git a/build_defs/resources/resource_contract.test.mts b/build_defs/resources/resource_contract.test.mts new file mode 100644 index 000000000..62e1f6949 --- /dev/null +++ b/build_defs/resources/resource_contract.test.mts @@ -0,0 +1,554 @@ +import { expect, test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + copyFileSync, + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + emptyDirectoryPaths, + filesystemTreeRows, + logicalTreeSha256, + parseProperties, +} from '../../src/database-resources/contracts/native-manifest.mts'; +import { packageClusterSeed } from '../../src/database-resources/seeds/package.mts'; +import { WASIX_PORTABLE_RELEASE_MEMBERS } from '../../src/wasix/runtime/tools/wasix-runtime-npm-contract.mts'; +import { createDeterministicTar } from '../../tools/packaging/archive-directory.mts'; +import { buildMavenArtifactManifest } from '../../tools/packaging/build-maven-artifact-manifest.mts'; +import { + canonicalGzipSync, + readPortableArchiveEntries, + releaseZstdCompressSync, +} from '../../tools/packaging/portable-archive.mts'; +import { releaseProfilePackageLicense } from '../../tools/packaging/release-notices.mts'; +import { + assertSeedPublicData, + selectCompletedSeed, + writeSeedConstructionReceipt, +} from './seed_construction.mts'; +import { bindSeedDomain } from './seed_domain.mts'; +import { fixture, identity, publication } from './seed-construction-fixture.mts'; +import { materializeInputs, nativeSeedHost, seedEnvironment } from './shared.mts'; +import { wasixRuntimeInputs } from './wasix_inputs.mts'; + +test('private WASIX assets admit current module bytes while preserving the held seed and creator', async () => { + // Opaque PGDATA and module bytes exercise the actual formatter, not PostgreSQL execution. + const f = await fixture('wasix'); + try { + const publicManifest = readFileSync(f.assets.manifest); + const held = JSON.parse(publicManifest.toString('utf8')); + const selected = selectCompletedSeed( + f.intent, + { + operation: 'adopt', + publication, + archive: identity(f.assets.archive), + manifest: identity(f.assets.manifest), + }, + f.intent, + ); + assert.ok(selected); + writeSeedConstructionReceipt( + f.receiptPath, + f.intent, + f.frozen, + f.pgdata, + selected.origin, + f.intent, + selected.sourceManifest, + ); + const receiptBytes = readFileSync(f.receiptPath); + const frozen = readFileSync(f.frozen); + const currentModule = Buffer.from('current consuming module bytes'); + const current = path.join(f.root, 'current', 'oliphaunt', 'bin'); + mkdirSync(current, { recursive: true }); + writeFileSync(path.join(current, 'postgres'), currentModule); + copyFileSync(f.inputs.initdb, path.join(current, 'initdb')); + const runtimeBytes = releaseZstdCompressSync( + await createDeterministicTar(path.join(f.root, 'current')), + ); + const sha = (bytes: Buffer) => createHash('sha256').update(bytes).digest('hex'); + const runtime = path.join(f.root, 'portable'); + mkdirSync(runtime); + writeFileSync(path.join(runtime, 'oliphaunt.wasix.tar.zst'), runtimeBytes); + writeFileSync( + path.join(runtime, 'manifest.json'), + JSON.stringify({ + 'format-version': 2, + 'source-fingerprint': 'controlled current module fixture', + runtime: { + archive: 'oliphaunt.wasix.tar.zst', + sha256: sha(runtimeBytes), + size: runtimeBytes.length, + 'module-sha256': sha(currentModule), + 'postgres-version': '18.4', + link: { exports: [] }, + }, + 'runtime-support': [], + extensions: [], + }), + ); + const privateArchive = path.join(f.root, 'private', path.basename(f.assets.archive)); + const privateManifest = path.join(f.root, 'private', path.basename(f.assets.manifest)); + const specification = path.join(f.root, 'private-inputs.json'); + writeFileSync( + specification, + JSON.stringify({ + family: 'wasix', + seed: f.frozen, + construction: f.receiptPath, + runtime, + profile: 'standard', + target: 'portable', + icu: null, + version: publication.version, + runtimeVersion: '0.3.3', + contract: f.invocation.contract, + archive: privateArchive, + manifest: privateManifest, + }), + ); + const result = Bun.spawnSync( + [ + process.execPath, + '--no-install', + '--no-env-file', + path.join(import.meta.dir, 'seed_assets.mts'), + specification, + ], + { stdout: 'pipe', stderr: 'pipe' }, + ); + expect(result.exitCode, result.stderr.toString()).toBe(0); + const admitted = JSON.parse(readFileSync(privateManifest, 'utf8')); + expect(held.runtime.consumerSha256).not.toBe(sha(currentModule)); + expect(admitted.runtime.consumerSha256).toBe(sha(currentModule)); + expect(admitted.runtime.version).toBe('0.3.3'); + expect(admitted.runtime.producerSha256).toBe(held.runtime.producerSha256); + expect(admitted.runtime.initdbSha256).toBe(held.runtime.initdbSha256); + expect(readFileSync(privateArchive)).toEqual(readFileSync(f.assets.archive)); + expect(readFileSync(f.assets.manifest)).toEqual(publicManifest); + expect(readFileSync(f.receiptPath)).toEqual(receiptBytes); + expect(readFileSync(f.frozen)).toEqual(frozen); + assertSeedPublicData(privateArchive, JSON.parse(receiptBytes.toString('utf8'))); + } finally { + rmSync(f.root, { recursive: true, force: true }); + } +}); + +test('WASIX resource archive aliases preserve declared bytes and reject non-file members', async () => { + const root = mkdtempSync(path.join(tmpdir(), 'wasix-resource-archive-alias-')); + try { + const tree = path.join(root, 'release'); + const bytes: Record = { + runtimeArchive: Buffer.from('declared runtime archive bytes'), + manifest: Buffer.from('{"declared":"manifest bytes"}'), + }; + for (const [name, member] of Object.entries(WASIX_PORTABLE_RELEASE_MEMBERS)) { + mkdirSync(path.dirname(path.join(tree, member)), { recursive: true }); + writeFileSync(path.join(tree, member), bytes[name]); + } + const archive = path.join(root, 'runtime.tar.gz'); + writeFileSync(archive, canonicalGzipSync(await createDeterministicTar(tree))); + const alias = path.join(root, 'generated/runtimeFile'); + mkdirSync(path.dirname(alias), { recursive: true }); + symlinkSync(archive, alias, 'file'); + const admitted = wasixRuntimeInputs(alias, path.join(root, 'archive-work')); + expect(readFileSync(path.join(admitted, 'oliphaunt.wasix.tar.zst'))).toEqual( + bytes.runtimeArchive, + ); + expect(readFileSync(path.join(admitted, 'manifest.json'))).toEqual(bytes.manifest); + + const directoryAlias = path.join(root, 'runtimeTree'); + symlinkSync(admitted, directoryAlias, 'dir'); + const directoryWork = path.join(root, 'directory-work'); + expect(wasixRuntimeInputs(directoryAlias, directoryWork)).toBe(directoryAlias); + expect(existsSync(directoryWork)).toBe(false); + + const manifest = path.join(tree, WASIX_PORTABLE_RELEASE_MEMBERS.manifest); + rmSync(manifest); + mkdirSync(manifest); + const invalidArchive = path.join(root, 'wrong-kind.tar.gz'); + writeFileSync(invalidArchive, canonicalGzipSync(await createDeterministicTar(tree))); + const invalidAlias = path.join(root, 'generated/wrongRuntimeFile'); + symlinkSync(invalidArchive, invalidAlias, 'file'); + expect(() => wasixRuntimeInputs(invalidAlias, path.join(root, 'invalid-work'))).toThrow( + `admitted WASIX runtime needs regular ${WASIX_PORTABLE_RELEASE_MEMBERS.manifest}`, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('resource Maven formatter loads from declared helpers and rejects missing carrier mappings before output', async () => { + const root = mkdtempSync(path.join(tmpdir(), 'resource-maven-contract-')); + const manifest = path.join(root, 'maven.tsv'); + try { + await expect( + buildMavenArtifactManifest(manifest, { + artifactProduct: 'database-resources', + artifactIds: ['unknown-carrier'], + runtimeAssetRoot: root, + context: { version: '1.0.0', artifactTargets: [], registryPackages: [] }, + }), + ).rejects.toThrow('database-resources artifact targets did not produce any Maven artifacts'); + expect(existsSync(manifest)).toBe(false); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('native bootstrap rejects a runtime for a different executor before filesystem mutation', () => { + const artifact = { + target: 'windows-x64-msvc', + npm_os: 'win32', + npm_cpu: 'x64', + library_relative_path: 'bin/oliphaunt.dll', + }; + expect(nativeSeedHost(artifact, 'win32', 'x64')).toEqual({ + target: artifact.target, + executableSuffix: '.exe', + memoryType: 'windows', + libraryRelativePath: 'bin/oliphaunt.dll', + }); + expect(() => nativeSeedHost(artifact, 'linux', 'x64')).toThrow('executor OS'); + expect(() => nativeSeedHost(artifact, 'win32', 'arm64')).toThrow('executor CPU'); + expect(() => nativeSeedHost(artifact, 'freebsd', 'x64')).toThrow('unsupported'); + expect(() => + nativeSeedHost({ ...artifact, library_relative_path: '../ambient.dll' }, 'win32', 'x64'), + ).toThrow('canonical'); + const mac = { + ...artifact, + target: 'macos-arm64', + npm_os: 'darwin', + npm_cpu: 'arm64', + library_relative_path: 'lib/liboliphaunt.dylib', + }; + expect(nativeSeedHost(mac, 'darwin', 'arm64').memoryType).toBe('mmap'); + expect(nativeSeedHost(mac, 'darwin', 'arm64').executableSuffix).toBe(''); +}); + +test('seed loader environments consume only candidate libraries and the selected separate ICU data', () => { + const ambient = { + PATH: '/ambient/bin', + LD_LIBRARY_PATH: '/ambient/lib', + DYLD_LIBRARY_PATH: '/ambient/lib', + ICU_DATA: '/ambient/icu', + PGDATA: '/ambient/database', + secret: 'must-not-be-inherited', + SystemRoot: 'C:\\Windows', + }; + for (const platform of ['linux', 'darwin', 'win32'] as const) { + const runtime = platform === 'win32' ? 'C:\\candidate' : '/candidate'; + const root = platform === 'win32' ? 'C:\\private' : '/private'; + const standard = seedEnvironment(runtime, root, undefined, platform, ambient); + expect(standard.PGDATA).toBeUndefined(); + expect(standard.secret).toBeUndefined(); + expect(standard.ICU_DATA).toBeUndefined(); + expect(standard.OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY).toBe('1'); + expect(standard.PATH).not.toContain('/ambient'); + expect(standard.HOME).toBe(root); + expect(standard.TEMP).toBe(root); + if (platform === 'win32') { + expect(standard.PATH).toBe('C:\\candidate\\bin;C:\\Windows\\System32;C:\\Windows'); + expect(standard.SystemRoot).toBe('C:\\Windows'); + expect(standard.LD_LIBRARY_PATH).toBeUndefined(); + } else { + expect(standard[platform === 'darwin' ? 'DYLD_LIBRARY_PATH' : 'LD_LIBRARY_PATH']).toBe( + '/candidate/lib', + ); + expect(standard.SystemRoot).toBeUndefined(); + } + const icu = seedEnvironment(runtime, root, '/selected/icu', platform, ambient); + expect(icu.ICU_DATA).toBe('/selected/icu'); + expect(icu.OLIPHAUNT_INTERNAL_ICU_READY).toBe('1'); + expect(icu.OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY).toBeUndefined(); + } + expect(() => seedEnvironment('C:\\candidate', 'C:\\private', undefined, 'win32', {})).toThrow( + 'SystemRoot', + ); +}); + +test('declared input staging rejects paths that escape its private root', () => { + const root = mkdtempSync(path.join(tmpdir(), 'resource-contract-')); + try { + const input = path.join(root, 'input'); + writeFileSync(input, 'declared input'); + materializeInputs({ 'nested/file': input }, path.join(root, 'stage')); + expect(readFileSync(path.join(root, 'stage/nested/file'), 'utf8')).toBe('declared input'); + expect(() => materializeInputs({ '../escape': input }, path.join(root, 'stage'))).toThrow( + 'unsafe', + ); + expect(() => + materializeInputs({ 'nested/../escape': input }, path.join(root, 'stage')), + ).toThrow('unsafe'); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('seed envelopes preserve explicit historical runtime requirements and empty directories', async () => { + const root = mkdtempSync(path.join(tmpdir(), 'resource-contract-')); + try { + const contract = JSON.parse( + readFileSync( + new URL('../../src/database-resources/contracts/contract.json', import.meta.url), + 'utf8', + ), + ); + const pgdata = path.join(root, 'fixture'); + for (const directory of contract.pgdataDirectories) + mkdirSync(path.join(pgdata, directory), { recursive: true }); + writeFileSync(path.join(pgdata, 'PG_VERSION'), '18\n'); + // This tests the formatter boundary; only the installed consumer qualifies real PGDATA. + writeFileSync(path.join(pgdata, 'global/pg_control'), 'formatter fixture\n'); + const runtime = path.join(root, 'runtime'); + mkdirSync(path.join(runtime, 'bin'), { recursive: true }); + writeFileSync(path.join(runtime, 'bin/postgres'), 'declared postgres fixture'); + writeFileSync(path.join(runtime, 'bin/initdb'), 'declared initdb fixture'); + const options = { + family: 'native', + profile: 'standard', + target: 'linux-x64-gnu', + pgdata, + runtime, + contract, + version: '0.2.2', + runtimeVersion: '0.3.2', + outputDir: path.join(root, 'assets'), + }; + const result = await packageClusterSeed(options); + const manifest = JSON.parse(readFileSync(result.manifest, 'utf8')); + expect(manifest.runtime.version).toBe('0.3.2'); + expect(manifest.runtime.compatibilityKey).toBe( + contract.compatibilityKeys.native['linux-x64-gnu'], + ); + const entries = readPortableArchiveEntries(result.archive); + expect(entries.get('pg_twophase')?.isDirectory).toBe(true); + expect(entries.get('pg_twophase')?.mode).toBe(0o755); + expect(entries.get('global/pg_control')?.mode).toBe(0o644); + const heldOptions = { + ...options, + runtime: undefined, + producer: manifest.source, + nativeSourceManifest: JSON.stringify(manifest), + }; + const beforeCoreBump = await packageClusterSeed({ + ...heldOptions, + runtimeVersion: '0.3.3', + outputDir: path.join(root, 'before-core'), + }); + const afterCoreBump = await packageClusterSeed({ + ...heldOptions, + runtimeVersion: '0.3.4', + outputDir: path.join(root, 'after-core'), + }); + expect(readFileSync(afterCoreBump.manifest)).toEqual(readFileSync(beforeCoreBump.manifest)); + expect(readFileSync(afterCoreBump.archive)).toEqual(readFileSync(beforeCoreBump.archive)); + const heldDescriptor = JSON.parse(readFileSync(afterCoreBump.manifest, 'utf8')); + expect(heldDescriptor.runtime).toEqual(manifest.runtime); + expect(heldDescriptor.source).toEqual(manifest.source); + await expect( + packageClusterSeed({ + ...heldOptions, + producer: { ...manifest.source, postgresSha256: '0'.repeat(64) }, + }), + ).rejects.toThrow('producer/profile'); + const incompatibleOriginal = structuredClone(manifest); + incompatibleOriginal.runtime.target = 'ios-datum64'; + await expect( + packageClusterSeed({ + ...heldOptions, + nativeSourceManifest: JSON.stringify(incompatibleOriginal), + }), + ).rejects.toThrow('physical identity'); + const before = readFileSync(path.join(pgdata, 'global/pg_control')); + await packageClusterSeed({ ...options, version: '0.2.3' }); + expect(readFileSync(path.join(pgdata, 'global/pg_control')).equals(before)).toBe(true); + await expect(packageClusterSeed({ ...options, runtimeVersion: undefined })).rejects.toThrow( + 'exact', + ); + await expect(packageClusterSeed({ ...options, icuData: root })).rejects.toThrow('only ICU'); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('WASIX manifest retains exact consumed module hashes and the distinct Datum32 contract', async () => { + const root = mkdtempSync(path.join(tmpdir(), 'resource-wasix-contract-')); + try { + const contract = JSON.parse( + readFileSync( + new URL('../../src/database-resources/contracts/contract.json', import.meta.url), + 'utf8', + ), + ); + const pgdata = path.join(root, 'formatter-fixture'); + for (const directory of contract.pgdataDirectories) + mkdirSync(path.join(pgdata, directory), { recursive: true }); + writeFileSync(path.join(pgdata, 'PG_VERSION'), '18\n'); + writeFileSync(path.join(pgdata, 'global/pg_control'), 'formatter fixture only'); + const runtime = path.join(root, 'runtime'); + mkdirSync(path.join(runtime, 'bin'), { recursive: true }); + const postgres = Buffer.from('explicit WASIX postgres fixture'); + const initdb = Buffer.from('explicit WASIX initdb fixture'); + writeFileSync(path.join(runtime, 'bin/postgres'), postgres); + writeFileSync(path.join(runtime, 'bin/initdb'), initdb); + const result = await packageClusterSeed({ + family: 'wasix', + profile: 'standard', + target: 'portable', + pgdata, + runtime, + contract, + version: '0.2.2', + runtimeVersion: '0.3.2', + outputDir: path.join(root, 'assets'), + }); + const manifest = JSON.parse(readFileSync(result.manifest, 'utf8')); + const sha256 = (bytes: Buffer) => createHash('sha256').update(bytes).digest('hex'); + expect(manifest.runtime.version).toBe('0.3.2'); + expect(manifest.runtime.engineFamily).toBe('wasix'); + expect(manifest.runtime.target).toBe('portable'); + expect(manifest.runtime.physicalFormat).toBe(contract.physicalFormats.wasix); + expect(manifest.runtime.compatibilityKey).toBe(contract.compatibilityKeys.wasixDatum32); + expect(manifest.runtime.consumerSha256).toBe(sha256(postgres)); + expect(manifest.runtime.producerSha256).toBe(sha256(postgres)); + expect(manifest.runtime.initdbSha256).toBe(sha256(initdb)); + expect(manifest.source.producer).toBe('wasix-initdb'); + expect(readPortableArchiveEntries(result.archive).get('pg_twophase')?.isDirectory).toBe(true); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('license metadata uses the declared source tree and rejects altered or absent pinned licenses', () => { + const root = mkdtempSync(path.join(tmpdir(), 'resource-license-')); + try { + const source = path.resolve(import.meta.dir, '../..'); + materializeInputs( + Object.fromEntries( + ['LICENSE', 'src/third-party/icu/LICENSE', 'src/third-party/icu/source.toml'].map( + (relative) => [relative, path.join(source, relative)], + ), + ), + root, + ); + const license = releaseProfilePackageLicense('native-icu-data', { sourceRoot: root }); + expect(license.spdx).toBe('MIT AND Unicode-3.0'); + expect(license.entries.map((entry) => entry.source)).toEqual([ + path.join(root, 'LICENSE'), + path.join(root, 'src/third-party/icu/LICENSE'), + ]); + const icuLicense = path.join(root, 'src/third-party/icu/LICENSE'); + chmodSync(icuLicense, 0o644); + writeFileSync(icuLicense, 'altered pinned ICU license'); + expect(() => releaseProfilePackageLicense('native-icu-data', { sourceRoot: root })).toThrow( + /sha256|bytes|license/, + ); + rmSync(icuLicense); + expect(() => releaseProfilePackageLicense('native-icu-data', { sourceRoot: root })).toThrow(); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('domain binding requires every target receipt and preserves PostgreSQL bytes and empty directories', () => { + const root = mkdtempSync(path.join(tmpdir(), 'resource-domain-')); + try { + const source = path.resolve(import.meta.dir, '../..'); + const contract = JSON.parse( + readFileSync(path.join(source, 'src/database-resources/contracts/contract.json'), 'utf8'), + ); + const seed = path.join(root, 'seed'); + const pgdata = path.join(seed, 'files'); + for (const directory of contract.pgdataDirectories) + mkdirSync(path.join(pgdata, directory), { recursive: true }); + // Formatter fixtures exercise binding; real target construction qualifies the receipts. + writeFileSync(path.join(pgdata, 'PG_VERSION'), '18\n'); + writeFileSync(path.join(pgdata, 'global/pg_control'), 'domain fixture preserves this nonce'); + writeFileSync( + path.join(seed, 'manifest.properties'), + readFileSync( + path.join( + source, + 'src/database-resources/contracts/fixtures/native-standard.valid.properties', + ), + ), + ); + const values = { + schema: 'oliphaunt-native-mobile-abi-v1', + byteOrder: 'little', + datumBytes: '8', + maximumAlignof: '8', + float8ByVal: '1', + blockSize: '8192', + walBlockSize: '8192', + relationSegmentSize: '131072', + nameDataLength: '64', + indexMaxKeys: '32', + catalogVersion: '202506291', + pgControlVersion: '1800', + }; + const receipts = ['android-arm64-v8a', 'android-x86_64', 'linux-x64-gnu'].map((target) => ({ + text: `${Object.entries({ ...values, target }) + .map(([key, value]) => `${key}=${value}`) + .join('\n')}\n`, + label: target, + })); + writeFileSync(path.join(seed, 'abi.properties'), receipts[2].text); + const options = { + seed, + producerTarget: 'linux-x64-gnu', + domain: 'android-datum64', + profile: 'standard', + receipts, + }; + const before = logicalTreeSha256(filesystemTreeRows(pgdata)); + const empty = emptyDirectoryPaths(pgdata); + expect(() => bindSeedDomain({ ...options, receipts: receipts.slice(1) })).toThrow( + 'requires receipts', + ); + expect(() => bindSeedDomain({ ...options, producerTarget: 'macos-arm64' })).toThrow( + 'actual host producer', + ); + expect(() => + bindSeedDomain({ + ...options, + receipts: [ + receipts[0], + { + ...receipts[1], + text: receipts[1].text.replace('maximumAlignof=8', 'maximumAlignof=16'), + }, + receipts[2], + ], + }), + ).toThrow('ABI mismatch'); + expect(logicalTreeSha256(filesystemTreeRows(pgdata))).toBe(before); + bindSeedDomain(options); + const manifest = parseProperties( + readFileSync(path.join(seed, 'manifest.properties')), + 'domain fixture', + ); + expect(manifest.get('target')).toBe('android-datum64'); + expect(manifest.get('compatibilityKey')).toBe( + contract.compatibilityKeys.native['android-datum64'], + ); + expect(logicalTreeSha256(filesystemTreeRows(pgdata))).toBe(before); + expect(emptyDirectoryPaths(pgdata)).toEqual(empty); + expect(readFileSync(path.join(seed, 'abi-receipts/android-x86_64.properties'), 'utf8')).toBe( + receipts[1].text, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/build_defs/resources/resource_slice.test.mts b/build_defs/resources/resource_slice.test.mts new file mode 100644 index 000000000..c8d98a16f --- /dev/null +++ b/build_defs/resources/resource_slice.test.mts @@ -0,0 +1,434 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + copyFileSync, + cpSync, + mkdirSync, + readdirSync, + readFileSync, + renameSync, + rmSync, + statSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { validateNativeIcuDataManifest } from '../../src/database-resources/contracts/icu-data.mts'; +import { + emptyDirectoryPaths, + filesystemTreeRows, + logicalTreeSha256, + validateNativeClusterSeedDirectory, + validatePgdataDirectories, +} from '../../src/database-resources/contracts/native-manifest.mts'; +import { seedCarrierIdentities } from '../../src/database-resources/seeds/carrier-identities.mts'; +import { parseNativeMobileAbiReceipt } from '../../src/native/runtime/tools/native-mobile-abi-contract.mts'; +import { validateSelectedNativeSeed } from '../../src/native/sdks/ts/src/native/cluster-seed.ts'; +import { publishNativeDescriptor } from '../../src/native/sdks/ts/src/root-descriptor.ts'; +import { validateMavenCentralPublication } from '../../tools/packaging/maven-central-contract.mts'; +import { + archiveLogicalTreeRows, + extractPortableArchiveTree, + readPortableArchiveEntries, + readPortableTarZstdBufferEntries, +} from '../../tools/packaging/portable-archive.mts'; +import { + assertMissingHostRuntime, + extractNativePayload, +} from '../native/host-runtime-test-helpers.mts'; +import { seedProducerIdentity, validateSeedConstructionReceipt } from './seed_construction.mts'; +import { materializeArchive, nativeSeedHost, run, seedEnvironment } from './shared.mts'; + +const [ + runtimeArchive, + consumerInput, + runtimeVersion, + version, + seedSpecification, + icuArchive, + icuNpm, + icuCargo, + mavenRoot, + ...seedInputs +] = process.argv + .slice(2) + .map((value, index) => ([2, 3].includes(index) ? value : path.resolve(value))); +const runtimeArtifact = JSON.parse(readFileSync(seedSpecification, 'utf8')).runtimeArtifact; +const host = nativeSeedHost(runtimeArtifact); +const target = host.target; +assert.equal(seedInputs.length, 14); +assert(process.env.TEST_TMPDIR, 'test requires a private Bazel scratch directory'); +const root = path.resolve(process.env.TEST_TMPDIR); +const copyArchive = (source: string) => materializeArchive(source, path.join(root, 'inputs')); +function member(entries: ReturnType, name: string) { + const entry = entries.get(name); + assert(entry?.isFile && !entry.isSymbolicLink, `missing regular archive member ${name}`); + return entry; +} +const runtime = path.join(root, 'runtime'); +await extractNativePayload(runtimeArchive, runtime); +// POSIX uses the separate ICU data carrier; Windows loads its canonical data DLL. +rmSync(path.join(runtime, 'share/icu'), { recursive: true, force: true }); +const consumer = path.join(root, `consumer/bin/seed-consumer${host.executableSuffix}`); +mkdirSync(path.dirname(consumer), { recursive: true }); +copyFileSync(consumerInput, consumer); +if (process.platform !== 'win32') chmodSync(consumer, 0o755); +assert.equal( + run(consumer, ['--version'], seedEnvironment(runtime, root), root).trim(), + runtimeVersion, +); +const library = path.join(runtime, host.libraryRelativePath); +renameSync(library, `${library}.removed`); +try { + assertMissingHostRuntime( + Bun.spawnSync([consumer, '--version'], { + env: seedEnvironment(runtime, root), + cwd: root, + stdout: 'pipe', + stderr: 'pipe', + }), + path.basename(library), + ); +} finally { + renameSync(`${library}.removed`, library); +} + +const icu = path.join(root, 'icu'); +extractPortableArchiveTree(copyArchive(icuArchive), icu); +const icuData = path.join(icu, 'share/icu'); +const icuIdentity = validateNativeIcuDataManifest( + readFileSync(path.join(icu, 'manifest.properties')), + icuData, +); +const icuEntries = readPortableArchiveEntries(copyArchive(icuNpm)); +const icuPackage = JSON.parse(member(icuEntries, 'package/package.json').data().toString()); +assert.equal(icuPackage.name, '@oliphaunt/icu'); +assert.equal(icuPackage.version, version); +assert.equal(icuPackage.oliphaunt.icuDataTreeSha256, icuIdentity.icuDataTreeSha256); +assert( + member(icuEntries, 'package/OliphauntICU.bundle/share/icu/icudt76l.dat') + .data() + .equals(readFileSync(path.join(icuData, 'icudt76l.dat'))), +); +const icuCrate = readPortableArchiveEntries(copyArchive(icuCargo)); +const cargoIcuTree = readPortableTarZstdBufferEntries( + member(icuCrate, `oliphaunt-icu-${version}/payload/icu-data.tar.zst`).data(), +); +assert.equal( + logicalTreeSha256(archiveLogicalTreeRows(cargoIcuTree, icuCargo, 'share/icu/')), + icuIdentity.icuDataTreeSha256, +); +assert(statSync(icuCargo).size <= 10 * 1024 * 1024); +const coordinate = path.join(mavenRoot, 'dev/oliphaunt/runtime/oliphaunt-icu', version); +validateMavenCentralPublication({ + context: 'actual ICU carrier', + files: readdirSync(coordinate).map((name) => ({ + name, + size: statSync(path.join(coordinate, name)).size, + })), + pomText: readFileSync(path.join(coordinate, `oliphaunt-icu-${version}.pom`), 'utf8'), +}); +assert( + readFileSync(path.join(coordinate, `oliphaunt-icu-${version}.tar.gz`)).equals( + readFileSync(icuArchive), + ), +); +const profileContract = JSON.parse( + readFileSync( + new URL('../../src/database-resources/contracts/profile-probe.json', import.meta.url), + 'utf8', + ), +); +const seedProfiles = Object.keys( + JSON.parse( + readFileSync( + new URL('../../src/database-resources/contracts/contract.json', import.meta.url), + 'utf8', + ), + ).profiles, +).sort(); +const identities = seedCarrierIdentities(); +for (const [index, profile] of seedProfiles.entries()) { + let [archive, manifestFile, frozen, abiFile, npm, cargo, constructionFile] = seedInputs.slice( + index * 7, + (index + 1) * 7, + ); + archive = copyArchive(archive); + npm = copyArchive(npm); + cargo = copyArchive(cargo); + const tree = path.join(root, profile, 'frozen'); + await extractNativePayload(frozen, tree); + const manifest = JSON.parse(readFileSync(manifestFile, 'utf8')); + const construction = validateSeedConstructionReceipt( + JSON.parse(readFileSync(constructionFile, 'utf8')), + ); + assert.equal(construction.intent.family, 'native'); + assert.equal(construction.intent.target, target); + assert.equal(construction.intent.profile, profile); + const frozenBytes = readFileSync(frozen); + assert.deepEqual(construction.frozen, { + size: frozenBytes.length, + sha256: createHash('sha256').update(frozenBytes).digest('hex'), + }); + if (construction.sourceManifest) { + const original = JSON.parse(construction.sourceManifest.contents); + assert.deepEqual( + manifest.runtime, + original.runtime, + 'qualification must retain the original admitted native runtime', + ); + assert.deepEqual( + manifest.source, + original.source, + 'qualification must retain the original seed source', + ); + } + assert.equal(manifest.runtime.target, target); + assert.equal( + manifest.archive.sha256, + createHash('sha256').update(readFileSync(archive)).digest('hex'), + ); + assert.deepEqual( + { + postgresSha256: manifest.source.postgresSha256, + initdbSha256: manifest.source.initdbSha256, + }, + seedProducerIdentity(construction), + 'seed producer hashes must identify the original constructor', + ); + const abi = parseNativeMobileAbiReceipt(readFileSync(abiFile, 'utf8')); + assert.equal(abi.get('target'), target); + validateNativeClusterSeedDirectory(tree, profile, { + target, + icuData: profile === 'icu' ? icuData : undefined, + }); + const originalHash = logicalTreeSha256(filesystemTreeRows(path.join(tree, 'files'))); + const selectedManifestFile = path.join(root, profile, 'selected-seed.json'); + writeFileSync( + selectedManifestFile, + JSON.stringify({ + ...manifest, + directory: { + path: 'frozen/files', + treeSha256: originalHash, + emptyDirectories: emptyDirectoryPaths(path.join(tree, 'files')), + }, + }), + ); + await validateSelectedNativeSeed( + { manifestPath: selectedManifestFile, directory: path.join(tree, 'files') }, + target, + runtimeVersion, + profile === 'icu' ? icuIdentity.icuDataTreeSha256 : undefined, + ); + assert.equal(construction.pgdata.treeSha256, originalHash); + const seedEntries = readPortableArchiveEntries(archive); + assert.equal(logicalTreeSha256(archiveLogicalTreeRows(seedEntries, archive, '')), originalHash); + const directories = readdirSync(path.join(tree, 'files'), { + recursive: true, + withFileTypes: true, + }) + .filter((entry) => entry.isDirectory()) + .map((entry) => + path + .relative(path.join(tree, 'files'), path.join(entry.parentPath, entry.name)) + .split(path.sep) + .join('/'), + ) + .sort(); + assert.deepEqual( + [...seedEntries] + .filter(([, entry]) => entry.isDirectory) + .map(([name]) => name) + .sort(), + directories, + 'the final archive must preserve exactly the original PostgreSQL directories', + ); + for (const [name, entry] of seedEntries) { + assert( + entry.isDirectory || (entry.isFile && !entry.isSymbolicLink), + `unexpected seed member ${name}`, + ); + assert.equal( + entry.mode, + entry.isDirectory ? 0o755 : 0o644, + `unexpected seed member mode ${name}`, + ); + } + const pgdata = path.join(root, profile, 'consumer/pgdata'); + extractPortableArchiveTree(archive, pgdata); + validatePgdataDirectories(pgdata); + assert.equal(logicalTreeSha256(filesystemTreeRows(pgdata)), originalHash); + chmodSync(pgdata, 0o700); + await publishNativeDescriptor(path.dirname(pgdata)); + const env = seedEnvironment(runtime, root, profile === 'icu' ? icuData : undefined); + const probe = profileContract.profiles[profile]; + // Each negative starts from the immutable original, before a successful open + // can checkpoint or otherwise change PGDATA. PostgreSQL's CRC routines + // preserve a valid checksum so PostgreSQL must reject the physical version. + for (const field of ['control', 'catalog']) { + const incompatible = path.join(root, profile, `incompatible-${field}`, 'pgdata'); + mkdirSync(path.dirname(incompatible), { recursive: true }); + cpSync(pgdata, incompatible, { recursive: true }); + await publishNativeDescriptor(path.dirname(incompatible)); + const controlFile = path.join(incompatible, 'global/pg_control'); + const before = readFileSync(controlFile); + const mutation = run(consumer, [`--corrupt-${field}`, controlFile], env, root); + assert.match( + mutation, + new RegExp( + `corrupted ${field === 'control' ? 'PG_CONTROL_VERSION' : 'CATALOG_VERSION_NO'} with valid CRC32C`, + 'u', + ), + ); + const changed = readFileSync(controlFile); + assert.equal(changed.length, before.length); + assert.ok(!changed.equals(before), 'test must change the physical control file'); + const rejected = Bun.spawnSync([consumer, incompatible, runtime, probe.sql, probe.expected], { + env, + cwd: root, + stdout: 'pipe', + stderr: 'pipe', + }); + assert.notEqual(rejected.exitCode, 0, `runtime accepted incompatible ${field} version`); + const diagnostic = rejected.stderr.toString(); + assert.match(diagnostic, /database files are incompatible with server/u); + assert.doesNotMatch(diagnostic, /incorrect checksum in control file/u); + } + run(consumer, [pgdata, runtime, probe.sql, probe.expected], env, root); + if (profile === 'icu') { + const data = + process.platform === 'win32' + ? path.join(runtime, 'bin', 'icudt76.dll') + : path.join(icuData, 'icudt76l.dat'); + renameSync(data, `${data}.removed`); + try { + const missingData = Bun.spawnSync([consumer, pgdata, runtime, probe.sql, probe.expected], { + env, + cwd: root, + stdout: 'pipe', + stderr: 'pipe', + }); + if (process.platform === 'win32') assertMissingHostRuntime(missingData, path.basename(data)); + else + assert.notEqual(missingData.exitCode, 0, 'consumer resolved the removed ICU carrier data'); + } finally { + renameSync(`${data}.removed`, data); + } + } + const errorResponse = Bun.spawnSync( + [ + consumer, + pgdata, + runtime, + "DO $$ BEGIN RAISE EXCEPTION 'resource-error-sentinel'; END $$", + 'resource-error-sentinel', + ], + { env, cwd: root, stdout: 'pipe', stderr: 'pipe' }, + ); + assert.notEqual( + errorResponse.exitCode, + 0, + 'consumer accepted an error message as its expected result', + ); + run( + consumer, + [ + pgdata, + runtime, + "CREATE TABLE resource_probe (value text); INSERT INTO resource_probe VALUES ('resource-reopen-ok'); SELECT value FROM resource_probe", + 'resource-reopen-ok', + ], + env, + root, + ); + run( + consumer, + [pgdata, runtime, 'SELECT value FROM resource_probe', 'resource-reopen-ok'], + env, + root, + ); + assert.equal( + logicalTreeSha256(filesystemTreeRows(path.join(tree, 'files'))), + originalHash, + 'consumer changed the frozen seed', + ); + const packedNpm = readPortableArchiveEntries(npm); + const packageJson = JSON.parse(member(packedNpm, 'package/package.json').data().toString()); + const identity = identities.find( + (row) => row.family === 'native' && row.target === target && row.profile === profile, + ); + assert(identity, 'the installed seed must have one canonical carrier identity'); + assert.equal(packageJson.name, identity.npm); + assert.equal(packageJson.version, version); + assert.deepEqual( + packageJson.dependencies ?? {}, + profile === 'icu' ? { '@oliphaunt/icu': version } : {}, + ); + assert(!packedNpm.has('package/seed.tar.zst')); + const npmManifest = JSON.parse(member(packedNpm, 'package/manifest.json').data().toString()); + assert.deepEqual(npmManifest.runtime, manifest.runtime); + assert.deepEqual(npmManifest.source, manifest.source); + assert.equal(npmManifest.directory.treeSha256, originalHash); + assert.equal( + logicalTreeSha256( + archiveLogicalTreeRows(packedNpm, npm, `package/${npmManifest.directory.path}/`), + ), + originalHash, + ); + for (const [name, entry] of packedNpm) { + if (!name.startsWith(`package/${npmManifest.directory.path}/`)) continue; + assert.equal( + entry.mode, + entry.isDirectory ? 0o755 : 0o644, + `unexpected installed seed mode ${name}`, + ); + } + assert(npmManifest.directory.emptyDirectories.includes('pg_twophase')); + const crateEntries = readPortableArchiveEntries(cargo); + for (const [name, entry] of crateEntries) + assert.equal(entry.mode, entry.isDirectory ? 0o755 : 0o644, name); + const crateRoot = `${identity.cargo}-${version}`; + const cargoManifest = Bun.TOML.parse( + member(crateEntries, `${crateRoot}/Cargo.toml`).data().toString(), + ); + const cargoPackage = cargoManifest.package as { name: string; version: string }; + assert.equal(cargoPackage.name, identity.cargo); + assert.equal(cargoPackage.version, version); + assert(member(crateEntries, `${crateRoot}/seed.tar.zst`).data().equals(readFileSync(archive))); + const crateManifest = JSON.parse( + member(crateEntries, `${crateRoot}/manifest.json`).data().toString(), + ); + assert.deepEqual(crateManifest.runtime, manifest.runtime); + assert.deepEqual(crateManifest.source, manifest.source); + assert(statSync(cargo).size <= 10 * 1024 * 1024); + const corrupted = path.join(root, profile, 'corrupted'); + cpSync(tree, corrupted, { recursive: true }); + writeFileSync( + path.join(corrupted, 'manifest.properties'), + readFileSync(path.join(corrupted, 'manifest.properties'), 'utf8').replace( + `target=${target}`, + `target=${target === 'linux-x64-gnu' ? 'macos-arm64' : 'linux-x64-gnu'}`, + ), + ); + assert.throws( + () => + validateNativeClusterSeedDirectory(corrupted, profile, { + target, + icuData: profile === 'icu' ? icuData : undefined, + }), + /target/, + ); + writeFileSync(path.join(corrupted, 'files/PG_VERSION'), '17\n'); + assert.throws( + () => + validateNativeClusterSeedDirectory(corrupted, profile, { + target, + icuData: profile === 'icu' ? icuData : undefined, + }), + /PostgreSQL.*expected 18/, + ); +} +console.log( + `ICU npm/Cargo/Maven and both ${target} native seed carriers passed actual runtime, reopen, ABI, integrity and missing-library checks`, +); diff --git a/build_defs/resources/resources.bzl b/build_defs/resources/resources.bzl new file mode 100644 index 000000000..4d01c1335 --- /dev/null +++ b/build_defs/resources/resources.bzl @@ -0,0 +1,619 @@ +"""Declared resource construction; PostgreSQL seed bytes are intentionally unique.""" + +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "BunScriptInfo", "bun_action", "bun_script_test", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/host:desktop-profile.bzl", "desktop_profile") +load("@oliphaunt_metadata//:metadata.bzl", "DATABASE_RESOURCE_ARTIFACTS", "DATABASE_RESOURCE_CONTRACT", "DATABASE_WASIX_SEED_CONSUMER", "DATABASE_SEED_CARRIERS", "NATIVE_CURRENT_ARTIFACTS", "NATIVE_RUNTIME_ARTIFACTS", "PRODUCTS", "PUBLICATION_CARRIERS", "SEED_REUSE_CONTROLS", "COMPLETED_SUPPLIER_ARTIFACTS", "WASIX_ARTIFACTS") +load("@oliphaunt_javascript_metadata//:metadata.bzl", "JAVASCRIPT") +load("@aspect_rules_js//npm:providers.bzl", "NpmPackageInfo") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") +load("//build_defs/release:supplier.bzl", "ShippingSupplierInfo", "file_shipping_supplier") +load("//build_defs/native:platform_config.bzl", "NATIVE_COMPATIBLE") + +NativeSeedInfo = provider(fields = ["frozen", "abi", "runtime", "profile", "target", "construction"]) +WasixSeedInfo = provider(fields = ["frozen", "runtime", "profile", "target", "construction"]) +SeedAssetsInfo = provider(fields = ["archive", "manifest"]) + +_LINUX_X64 = ["@platforms//os:linux", "@platforms//cpu:x86_64"] +_DESKTOP_PROFILES = { + "linux_x64": ("linux-x64-gnu", _LINUX_X64, "//build_defs/native:linux_x86_64"), + "linux_arm64": ("linux-arm64-gnu", ["@platforms//os:linux", "@platforms//cpu:aarch64"], "//build_defs/native:linux_aarch64"), + "macos_arm64": ("macos-arm64", ["@platforms//os:macos", "@platforms//cpu:aarch64"], "//build_defs/native:macos_arm64"), + "windows_x64": ("windows-x64-msvc", ["@platforms//os:windows", "@platforms//cpu:x86_64"], "//build_defs/native:windows_x64"), +} +_VERSION = PRODUCTS["database-resources"]["version"] +NATIVE_SEED_ABI_CONFIGURATION = "seed-abi" + +def native_seed_abi_suppliers(files): + """The actual creator/ABI Files bind seed format, not compiled version coupling.""" + if not files or any([file.is_source or file.is_directory for file in files]): + fail("Native seed ABI provenance requires actual generated regular Files") + return ShippingSupplierInfo( + suppliers = [{"product": "liboliphaunt-native", "version": PRODUCTS["liboliphaunt-native"]["version"], + "configuration": NATIVE_SEED_ABI_CONFIGURATION, "binding": "abi-contract", + "origin": {"kind": "current-source"}, "files": [{"path": file.path} for file in files]}], + files = depset(files), + ) + +def _wasix_consumer_version(): + return PRODUCTS["database-resources"]["compatibility_versions"]["liboliphaunt-wasix"] + +def _wasix_consumer(): + version = _wasix_consumer_version() + rows = [row for row in WASIX_ARTIFACTS if row["product"] == "liboliphaunt-wasix" and row["kind"] == "wasix-runtime" and row["target"] == "portable"] + if len(rows) != 1: + fail("WASIX seed consumer requires one canonical portable archive") + artifact = "github-release:" + rows[0]["asset"].replace("{version}", version) + key = "liboliphaunt-wasix/" + version + "/" + artifact + return COMPLETED_SUPPLIER_ARTIFACTS.get(key) + + +def _runtime_artifact(target): + rows = [row for row in NATIVE_RUNTIME_ARTIFACTS + if row["product"] == "liboliphaunt-native" and row["kind"] == "native-runtime" and row["target"] == target] + if len(rows) != 1: + fail("native seed must consume exactly one canonical runtime artifact for " + target) + return {key: rows[0][key] for key in ["target", "npm_os", "npm_cpu", "library_relative_path"]} + +def _resource_compile_data_impl(ctx): + output = ctx.actions.declare_file(ctx.attr.out) + ctx.actions.symlink(output = output, target_file = ctx.file.src) + return [DefaultInfo(files = depset([output]))] + +resource_compile_data = rule(implementation = _resource_compile_data_impl, attrs = { + "src": attr.label(mandatory = True, allow_single_file = True), + "out": attr.string(mandatory = True), +}) + +_NOTICES = [ + "//:LICENSE", "//:THIRD_PARTY_NOTICES.md", + "//src/native/runtime:THIRD_PARTY_NOTICES.md", + "//src/wasix/sdks/rust:THIRD_PARTY_NOTICES.md", + "//src/third-party/postgres:COPYRIGHT", "//src/third-party/postgres:source.toml", + "//src/third-party/icu:LICENSE", "//src/third-party/icu:source.toml", +] + +def _input_map(files): + return {file.short_path: file.path for file in files} + +def _action(ctx, specification, inputs, outputs, mnemonic, tree_inputs = None, **kwargs): + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode(specification) + "\n") + arguments = ctx.actions.args() + arguments.add(spec) + action_arguments = [arguments] + if tree_inputs != None: + tree_arguments = ctx.actions.args() + tree_arguments.add_all(depset(tree_inputs), expand_directories = True) + tree_arguments.use_param_file("--construction-tree-files=%s", use_always = True) + tree_arguments.set_param_file_format("multiline") + action_arguments.append(tree_arguments) + bun_action(ctx, ctx.attr._tool, arguments = action_arguments, inputs = inputs + [spec], outputs = outputs, mnemonic = mnemonic, **kwargs) + return spec + +def _tool(label): + return attr.label(default = Label(label), providers = [BunScriptInfo], cfg = "exec") + +def seed_constructor_inputs(ctx, inputs, logical_roles = {}): + script = ctx.attr._tool[BunScriptInfo] + files = inputs + script.files.to_list() + [script.bun] + paths = {} + for file in files: + name = logical_roles.get(file.path) or ("external/" + file.short_path[3:] if file.short_path.startswith("../") else file.short_path) + if name in paths and paths[name] != file.path: + fail("Seed construction inputs share a logical File name: " + name) + paths[name] = file.path + return paths + +def seed_constructor_tree_members(ctx): + """The Bun provider owns the exact regular Files copied into its code trees.""" + sources = ctx.attr._tool[BunScriptInfo].sources + return { + ("external/" + tree.short_path[3:] if tree.short_path.startswith("../") else tree.short_path): { + name.removeprefix(repository + "/"): file.path + for name, file in sources.members.items() + if name.startswith(repository + "/") + } + for repository, tree in sources.trees.items() + } + +SEED_REUSE_ATTRS = { + "completed_archive": attr.label(allow_single_file = True), + "completed_manifest": attr.label(allow_single_file = True), + "completed_metadata": attr.label(allow_single_file = True), + "completed_anchor": attr.label(allow_single_file = True), + "reuse_control": attr.string(), + "qualified_frozen": attr.label(allow_single_file = True), + "qualified_receipt": attr.label(allow_single_file = True), + "promotion_control": attr.string(), +} + +def seed_reuse(ctx): + inputs = [file for file in [ctx.file.completed_archive, ctx.file.completed_manifest, ctx.file.completed_metadata, ctx.file.completed_anchor] if file] + if not ctx.attr.reuse_control: + if inputs: + fail("Completed seed Files require their exact typed origin control") + return None, [] + if not ctx.file.completed_archive or not ctx.file.completed_manifest: + fail("Seed reuse requires both actual completed archive and descriptor Files") + control = json.decode(ctx.attr.reuse_control) + control["archive"]["path"] = ctx.file.completed_archive.path + control["manifest"]["path"] = ctx.file.completed_manifest.path + if ctx.file.completed_metadata: + control["metadata"]["path"] = ctx.file.completed_metadata.path + elif control.get("metadata"): + fail("Seed metadata origin must name its actual declared File") + if ctx.file.completed_anchor: + control["anchor"]["path"] = ctx.file.completed_anchor.path + elif control.get("anchor"): + fail("Seed migration anchor must name its actual declared File") + return control, inputs + +def seed_promotion(ctx): + inputs = [file for file in [ctx.file.qualified_frozen, ctx.file.qualified_receipt] if file] + if not ctx.attr.promotion_control: + if inputs: + fail("Qualified seed Files require their exact original producer and transition") + return None, [] + if ctx.attr.reuse_control or not ctx.file.qualified_frozen or not ctx.file.qualified_receipt: + fail("Seed promotion requires exactly its original frozen TAR and receipt Files") + control = json.decode(ctx.attr.promotion_control) + control["frozen"]["path"] = ctx.file.qualified_frozen.path + control["receipt"]["path"] = ctx.file.qualified_receipt.path + return control, inputs + +def _icu_payload_impl(ctx): + _action(ctx, { + "data": ctx.file.data.path, + "output": ctx.outputs.out.path, + "notices": _input_map(ctx.files.notices), + }, [ctx.file.data] + ctx.files.notices, [ctx.outputs.out], "IcuResourceArchive") + return [DefaultInfo(files = depset([ctx.outputs.out]))] + +icu_payload = rule(implementation = _icu_payload_impl, attrs = { + "data": attr.label(default = "@icu_data//:icudt76l.dat", allow_single_file = True), + "notices": attr.label_list(default = _NOTICES, allow_files = True), + "out": attr.output(mandatory = True), + "_tool": _tool("//build_defs/resources:icu_payload"), +}) + +def _native_seed_impl(ctx): + frozen = ctx.actions.declare_file(ctx.label.name + ".tar") + abi = ctx.actions.declare_file(ctx.label.name + ".abi.properties") + construction = ctx.actions.declare_file(ctx.label.name + ".seed-construction.json") + config = [file for file in ctx.files.configuration if file.basename == "pg_config.h"] + if len(config) != 1: + fail("seed ABI requires exactly one actual configured pg_config.h") + headers = {"src/include/pg_config.h": config[0].path} + for target, relative in ctx.attr.headers.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1: + fail("seed ABI header must have exactly one declared file") + headers[relative] = files[0].path + constructor_inputs = [ctx.file.runtime] + ctx.files.configuration + ctx.files.headers + ([ctx.file.icu] if ctx.file.icu else []) + reuse, reuse_inputs = seed_reuse(ctx) + promotion, promotion_inputs = seed_promotion(ctx) + specification = _action(ctx, { + "runtime": ctx.file.runtime.path, + "profile": ctx.attr.profile, + "target": ctx.attr.target, + "runtimeArtifact": _runtime_artifact(ctx.attr.target), + "contract": DATABASE_RESOURCE_CONTRACT, + "headers": headers, + "icu": ctx.file.icu.path if ctx.file.icu else None, + "output": frozen.path, + "abiOutput": abi.path, + "constructionInputs": seed_constructor_inputs(ctx, constructor_inputs), + "constructionTreeMembers": seed_constructor_tree_members(ctx), + "constructionOutput": construction.path, + "reuse": reuse, + "promotion": promotion, + }, constructor_inputs + reuse_inputs + promotion_inputs, [frozen, abi, construction], "PostgresClusterSeed") + suppliers = native_seed_abi_suppliers([ctx.file.runtime]) + return [DefaultInfo(files = depset([frozen, abi, construction])), suppliers, + NativeSeedInfo(frozen = frozen, abi = abi, runtime = ctx.file.runtime, profile = ctx.attr.profile, target = ctx.attr.target, construction = construction), + OutputGroupInfo(frozen = depset([frozen]), abi = depset([abi]), specification = depset([specification]), construction = depset([construction]), observation_inputs = depset([frozen, construction]), supplier_inputs = suppliers.files)] + +native_seed = rule(implementation = _native_seed_impl, cfg = desktop_profile, attrs = dict(SEED_REUSE_ATTRS, **{ + "runtime": attr.label(default = "//src/native/runtime:runtime_payload", allow_single_file = True), + "configuration": attr.label(default = "@postgres//:configuration", allow_files = True), + "headers": attr.label_keyed_string_dict(default = { + Label("@postgres//:src/include/pg_config_manual.h"): "src/include/pg_config_manual.h", + Label("@postgres//:src/include/catalog/catversion.h"): "src/include/catalog/catversion.h", + Label("@postgres//:src/include/catalog/pg_control.h"): "src/include/catalog/pg_control.h", + }, allow_files = True), + "profile": attr.string(values = ["standard", "icu"], mandatory = True), + "target": attr.string(default = "linux-x64-gnu"), + "icu": attr.label(allow_single_file = True), + "_tool": _tool("//build_defs/resources:native_seed"), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), +})) + +def _wasix_resources(_os, _input_count): + return {"cpu": 2, "memory": 8192} + +def _wasix_seed_impl(ctx): + frozen = ctx.actions.declare_file(ctx.label.name + ".tar") + construction = ctx.actions.declare_file(ctx.label.name + ".seed-construction.json") + constructor_inputs = [ctx.file.runtime] + ([ctx.file.icu] if ctx.file.icu else []) + ctx.attr._runner[DefaultInfo].files.to_list() + ctx.attr._runner[DefaultInfo].default_runfiles.files.to_list() + constructor_trees = [file for file in constructor_inputs if file.is_directory] + reuse, reuse_inputs = seed_reuse(ctx) + promotion, promotion_inputs = seed_promotion(ctx) + _action(ctx, { + "runtime": ctx.file.runtime.path, + "runner": ctx.executable._runner.path, + "profile": ctx.attr.profile, + "target": "portable", + "icu": ctx.file.icu.path if ctx.file.icu else None, + "output": frozen.path, + "contract": DATABASE_RESOURCE_CONTRACT, + "constructionInputs": seed_constructor_inputs(ctx, constructor_inputs), + "constructionTreeMembers": seed_constructor_tree_members(ctx), + "constructionTrees": [file.path for file in depset(constructor_trees).to_list()], + "constructionOutput": construction.path, + "reuse": reuse, + "promotion": promotion, + }, constructor_inputs + reuse_inputs + promotion_inputs, [frozen, construction], "WasixClusterSeed", + tree_inputs = constructor_trees, + tools = [ctx.attr._runner[DefaultInfo].files_to_run], resource_set = _wasix_resources, + env = {"LC_ALL": "C", "RAYON_NUM_THREADS": "2"}) + return [DefaultInfo(files = depset([frozen, construction])), + WasixSeedInfo(frozen = frozen, runtime = ctx.file.runtime, profile = ctx.attr.profile, target = "portable", construction = construction), + OutputGroupInfo(frozen = depset([frozen]), construction = depset([construction]), observation_inputs = depset([frozen, construction]))] + +wasix_seed = rule(implementation = _wasix_seed_impl, attrs = dict(SEED_REUSE_ATTRS, **{ + "runtime": attr.label(default = "//src/wasix/runtime:portable_payload", allow_single_file = True), + "profile": attr.string(values = ["standard", "icu"], mandatory = True), + "icu": attr.label(allow_single_file = True), + "_tool": _tool("//build_defs/resources:wasix_seed"), + "_runner": attr.label(default = "//src/database-resources/seeds/wasix:seed_runner", executable = True, cfg = "exec"), +})) + +def _seed_assets_impl(ctx): + family = "native" if NativeSeedInfo in ctx.attr.seed else "wasix" + seed = ctx.attr.seed[NativeSeedInfo] if family == "native" else ctx.attr.seed[WasixSeedInfo] + if ctx.attr.consumer_version and (family != "wasix" or not ctx.attr.testonly): + fail("an explicit seed consumer version requires private WASIX qualification") + _action(ctx, { + "family": family, + "seed": seed.frozen.path, + "construction": seed.construction.path, + "runtime": ctx.file.consumer_runtime.path if family == "wasix" else None, + "profile": seed.profile, + "target": seed.target, + "icu": ctx.file.icu.path if ctx.file.icu else None, + "version": _VERSION, + "runtimeVersion": (ctx.attr.consumer_version or _wasix_consumer_version()) if family == "wasix" else PRODUCTS["liboliphaunt-native"]["version"], + "contract": DATABASE_RESOURCE_CONTRACT, + "archive": ctx.outputs.archive.path, + "manifest": ctx.outputs.manifest.path, + }, [seed.frozen, seed.construction] + ([ctx.file.consumer_runtime] if family == "wasix" else []) + ([seed.abi] if family == "native" else []) + ([ctx.file.icu] if ctx.file.icu else []), [ctx.outputs.archive, ctx.outputs.manifest], "ClusterSeedArchive") + return [DefaultInfo(files = depset([ctx.outputs.archive, ctx.outputs.manifest])), + SeedAssetsInfo(archive = ctx.outputs.archive, manifest = ctx.outputs.manifest), + OutputGroupInfo(archive = depset([ctx.outputs.archive]), manifest = depset([ctx.outputs.manifest]))] + +seed_assets = rule(implementation = _seed_assets_impl, attrs = { + "seed": attr.label(providers = [[NativeSeedInfo], [WasixSeedInfo]], mandatory = True), + "consumer_runtime": attr.label(allow_single_file = True), + "consumer_version": attr.string(doc = "Explicit WASIX consuming runtime version; omission retains public resource admission."), + "icu": attr.label(allow_single_file = True), + "archive": attr.output(mandatory = True), + "manifest": attr.output(mandatory = True), + "_tool": _tool("//build_defs/resources:seed_assets"), +}) + +def _resource_carriers_impl(ctx): + npm = ctx.actions.declare_file(ctx.label.name + ".tgz") + cargo = ctx.actions.declare_file(ctx.label.name + ".crate") + maven = ctx.actions.declare_directory(ctx.label.name + "/maven") if ctx.attr.kind == "icu" or ctx.attr.target == "android-datum64" else None + templates = {} + for target, relative in ctx.attr.templates.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1: + fail("resource template must name one authored file") + templates[relative] = files[0].path + _action(ctx, { + "kind": ctx.attr.kind, + "family": ctx.attr.family, + "target": ctx.attr.target, + "profile": ctx.attr.profile, + "version": _VERSION, + "contract": DATABASE_RESOURCE_CONTRACT, + "carriers": json.decode(ctx.attr.carriers), + "artifactRows": DATABASE_RESOURCE_ARTIFACTS, + "assets": [file.path for file in ctx.files.assets], + "templates": templates, + "notices": _input_map(ctx.files.notices), + "npmOutput": npm.path, + "cargoOutput": cargo.path, + "mavenOutput": maven.path if maven else None, + }, ctx.files.assets + ctx.files.templates + ctx.files.notices, [npm, cargo] + ([maven] if maven else []), "ResourceCarriers") + return [DefaultInfo(files = depset([npm, cargo] + ([maven] if maven else []))), + OutputGroupInfo(npm = depset([npm]), cargo = depset([cargo]), maven = depset([maven] if maven else []))] + +resource_carriers = rule(implementation = _resource_carriers_impl, attrs = { + "assets": attr.label_list(allow_files = True, mandatory = True), + "templates": attr.label_keyed_string_dict(allow_files = True), + "notices": attr.label_list(default = _NOTICES, allow_files = True), + "kind": attr.string(values = ["icu", "seed"], mandatory = True), + "family": attr.string(default = "native", values = ["native", "wasix"]), + "target": attr.string(default = "portable"), + "profile": attr.string(), + "carriers": attr.string(mandatory = True), + "_tool": _tool("//build_defs/resources:carriers"), +}) + +def _rows(names): + rows = [row for row in PUBLICATION_CARRIERS if row["product"] == "database-resources" and row["name"] in names] + if len(rows) != len(names): + fail("resource carriers must exactly match the canonical publication catalog") + return rows + +def _shipping(name, rows, suppliers, observation_inputs = [], **kwargs): + packages = [] + for row in rows: + label = name + "_" + row["ecosystem"] + native.filegroup(name = label + "_files", srcs = [":" + name], output_group = row["ecosystem"], **kwargs) + shipping_package(name = label, owner = "@oliphaunt_metadata//:product_database-resources", artifacts = [":" + label + "_files"], + ecosystem = row["ecosystem"], package_name = row["name"], configuration = row["target"] or "portable", role = row["role"], suppliers = suppliers, observation_inputs = observation_inputs, **kwargs) + packages.append(":" + label) + return packages + +def _seed_artifact_rows(family, target, profile): + rows = [row for row in DATABASE_RESOURCE_ARTIFACTS if row["kind"] == family + "-seeds" and row["target"] == target and ("." + profile + ".") in row["id"]] + archives = [row for row in rows if row["asset"].endswith(".tar.zst")] + manifests = [row for row in rows if row["asset"].endswith(".json")] + if len(archives) != 1 or len(manifests) != 1: + fail("seed envelopes require exactly the canonical archive and manifest") + return archives[0], manifests[0] + +def _declared_seed_assets_impl(ctx): + files = ctx.files.assets + if any([file.is_directory for file in files]) or sorted([file.basename for file in files]) != sorted(ctx.attr.expected) or len(ctx.attr.configurations) != len(ctx.attr.expected) or any([configuration != ctx.attr.target for configuration in ctx.attr.configurations]): + fail("installed native seed requires its exact original current archive and manifest Files for " + ctx.attr.target) + return [DefaultInfo(files = depset(files))] + +_declared_seed_assets = rule(implementation = _declared_seed_assets_impl, attrs = { + "assets": attr.label_list(allow_files = True), "expected": attr.string_list(mandatory = True), + "configurations": attr.string_list(), "target": attr.string(mandatory = True), +}) + +def ios_declared_standard_seed_npm(name): + """Format an installed consumer's seed from its original qualified assets.""" + target = "ios-datum64" + rows = _seed_artifact_rows("native", target, "standard") + names = [row["asset"].replace("{version}", _VERSION) for row in rows] + current = NATIVE_CURRENT_ARTIFACTS or {} + captures = [current.get("database-resources/" + _VERSION + "/github-release:" + asset) for asset in names] + _declared_seed_assets(name = name + "_assets", expected = names, target = target, + assets = [row["file"]["path"] for row in captures if row], configurations = [row["configuration"] for row in captures if row]) + identities = [row for row in DATABASE_SEED_CARRIERS if row["family"] == "native" and row["target"] == target and row["profile"] == "standard"] + if len(identities) != 1: + fail("installed seed requires one canonical registry identity") + identity = identities[0] + resource_carriers(name = name + "_carriers", kind = "seed", family = "native", target = target, profile = "standard", + assets = [":" + name + "_assets"], carriers = json.encode(_rows([identity["npm"], identity["cargo"]]))) + native.filegroup(name = name, srcs = [":" + name + "_carriers"], output_group = "npm") + +def wasix_current_seed_assets(name, profile = "standard"): + """Private current-module admission preserves the original seed and creator.""" + archive, manifest = _seed_artifact_rows("wasix", "portable", profile) + seed_assets(name = name, seed = "//src/database-resources:wasix_" + profile + "_seed", + icu = "//src/database-resources:icu_payload" if profile == "icu" else None, + consumer_runtime = "//src/wasix/runtime:portable_payload", consumer_version = PRODUCTS["liboliphaunt-wasix"]["version"], + archive = name + "/" + archive["asset"].replace("{version}", _VERSION), manifest = name + "/" + manifest["asset"].replace("{version}", _VERSION), + target_compatible_with = _LINUX_X64, testonly = True) + for group in ["archive", "manifest"]: + native.filegroup(name = name + "_" + group, srcs = [":" + name], output_group = group, testonly = True) + +def seed_envelopes(prefix, family, target, profile, seed, suppliers, icu = None, compatible = [], consumer_runtime = None, **kwargs): + """Use the one canonical row expansion and existing writers for one seed.""" + archive, manifest = _seed_artifact_rows(family, target, profile) + seed_assets(name = prefix + "_assets", seed = seed, icu = icu, consumer_runtime = consumer_runtime, + archive = archive["asset"].replace("{version}", _VERSION), manifest = manifest["asset"].replace("{version}", _VERSION), target_compatible_with = compatible, **kwargs) + packages = [] + for group, row in [("archive", archive), ("manifest", manifest)]: + native.filegroup(name = prefix + "_" + group, srcs = [":" + prefix + "_assets"], output_group = group, **kwargs) + shipping_package(name = prefix + "_github_" + group, owner = "@oliphaunt_metadata//:product_database-resources", artifacts = [":" + prefix + "_" + group], + ecosystem = "github", package_name = row["asset"].replace("{version}", _VERSION), configuration = row["target"], role = "github-release-asset", suppliers = suppliers, observation_inputs = [seed], **kwargs) + packages.append(":" + prefix + "_github_" + group) + identities = [row for row in DATABASE_SEED_CARRIERS if row["family"] == family and row["target"] == target and row["profile"] == profile] + if len(identities) != 1: + fail("seed envelopes require one canonical registry identity") + identity = identities[0] + names = [identity["npm"], identity["cargo"]] + if target == "android-datum64": + maven = [row for row in PUBLICATION_CARRIERS if row["product"] == "database-resources" and row["ecosystem"] == "maven" and row["name"].split(":")[-1] == identity["cargo"]] + if len(maven) != 1: + fail("Android seed requires exactly its declared canonical Maven carrier") + names.append(maven[0]["name"]) + carriers = _rows(names) + resource_carriers(name = prefix + "_carriers", kind = "seed", family = family, target = target, profile = profile, assets = [":" + prefix + "_assets"] + ([icu] if target in ["android-datum64", "ios-datum64"] and profile == "icu" else []), carriers = json.encode(carriers), target_compatible_with = compatible, **kwargs) + packages.extend(_shipping(prefix + "_carriers", carriers, suppliers = suppliers, observation_inputs = [seed], **kwargs)) + return packages + +def native_seed_abi_shipping(prefix, seed, **kwargs): + native.filegroup(name = prefix + "_seed_abi_files", srcs = [seed], output_group = "supplier_inputs", **kwargs) + name = prefix + "_seed_abi_shipping" + shipping_package(name = name, owner = "@oliphaunt_metadata//:product_liboliphaunt-native", artifacts = [":" + prefix + "_seed_abi_files"], + ecosystem = "internal", package_name = prefix + "-seed-abi", configuration = NATIVE_SEED_ABI_CONFIGURATION, + role = "abi-contract", suppliers = "//build_defs/release:no_suppliers", **kwargs) + return ":" + name + +def native_seed_envelopes(prefix, target, profile, seed, icu = None, compatible = []): + packages = seed_envelopes(prefix, "native", target, profile, seed, suppliers = seed, icu = icu, compatible = compatible) + return packages + [native_seed_abi_shipping(prefix, seed, target_compatible_with = compatible)] + +def wasix_resource_slice(name, qualification): + consumer = _wasix_consumer() if DATABASE_WASIX_SEED_CONSUMER["source"] == "completed" else None + file_shipping_supplier(name = "wasix_consumer_supplier", inputs = {"//src/wasix/runtime:release_archive_portable": ""} if DATABASE_WASIX_SEED_CONSUMER["source"] == "current" else ({consumer["file"]["path"]: ""} if consumer else {}), + owner = "@oliphaunt_metadata//:product_liboliphaunt-wasix", configuration = "portable", binding = "abi-contract", + origin = json.encode({"kind": "current-source"}) if DATABASE_WASIX_SEED_CONSUMER["source"] == "current" else (json.encode({"kind": "completed-publication", "publication": consumer["publication"], "artifact": consumer["artifact"]}) if consumer else "")) + packages = [] + for profile in DATABASE_RESOURCE_CONTRACT["profiles"]: + prefix = "wasix_" + profile + icu = ":icu_payload" if profile == "icu" else None + wasix_seed(name = prefix + "_seed", profile = profile, icu = icu, + target_compatible_with = _LINUX_X64, + exec_compatible_with = _LINUX_X64 + ["@zig_sdk//libc:gnu.2.34"], + **SEED_REUSE_CONTROLS.get("wasix/portable/" + profile, {})) + native.filegroup(name = prefix + "_frozen", srcs = [":" + prefix + "_seed"], output_group = "frozen") + native.filegroup(name = prefix + "_construction", srcs = [":" + prefix + "_seed"], output_group = "construction") + packages.extend(seed_envelopes(prefix, "wasix", "portable", profile, ":" + prefix + "_seed", icu = icu, compatible = _LINUX_X64, consumer_runtime = ":wasix_consumer_supplier", suppliers = ":wasix_consumer_supplier")) + shipping_export(name = name, packages = packages, qualification = qualification, testonly = True) + +def _wasix_resource_test_impl(ctx): + arguments = [ctx.executable._unit_test, ctx.executable._runner, ctx.file.runtime, ctx.file.icu, _VERSION, _wasix_consumer_version()] + files = [ctx.executable._unit_test, ctx.executable._runner, ctx.file.runtime, ctx.file.icu] + for profile in ["standard", "icu"]: + frozen = getattr(ctx.file, profile + "_frozen") + assets = getattr(ctx.files, profile + "_assets") + carriers = getattr(ctx.files, profile + "_carriers") + archives = [file for file in assets if file.basename.endswith(".tar.zst")] + manifests = [file for file in assets if file.basename.endswith(".json")] + npm = [file for file in carriers if file.basename.endswith(".tgz")] + cargo = [file for file in carriers if file.basename.endswith(".crate")] + if [len(archives), len(manifests), len(npm), len(cargo)] != [1, 1, 1, 1]: + fail("WASIX resource test requires one actual archive/manifest/npm/Cargo for each profile") + selected = [frozen, archives[0], manifests[0], npm[0], cargo[0], getattr(ctx.file, profile + "_construction")] + arguments.extend(selected) + files.extend(selected) + fzstd = ctx.attr._fzstd[NpmPackageInfo].src + arguments.append(fzstd) + files.append(fzstd) + for label, relative in ctx.attr._sdk_helpers.items(): + sources = label[DefaultInfo].files.to_list() + if len(sources) != 1: + fail("SDK resource consumer helper must be exactly one authored File") + arguments.extend([relative, sources[0]]) + files.extend(sources) + identities = [row for row in DATABASE_SEED_CARRIERS if row["family"] == "wasix"] + arguments.append(json.encode(identities)) + return bun_test_entrypoint(ctx, ctx.file._script, arguments, files + ctx.files._helpers, + source_files = [ctx.file._script] + ctx.files._helpers, + additional_runfiles = ctx.attr._runner[DefaultInfo].default_runfiles.merge(ctx.attr._unit_test[DefaultInfo].default_runfiles)) + +_wasix_resource_test = rule(implementation = _wasix_resource_test_impl, test = True, toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "runtime": attr.label(mandatory = True, allow_single_file = True), + "icu": attr.label(default = "//src/database-resources:icu_payload", allow_single_file = True), + "standard_frozen": attr.label(default = "//src/database-resources:wasix_standard_frozen", allow_single_file = True), + "standard_construction": attr.label(default = "//src/database-resources:wasix_standard_construction", allow_single_file = True), + "icu_construction": attr.label(default = "//src/database-resources:wasix_icu_construction", allow_single_file = True), + "standard_assets": attr.label(default = "//src/database-resources:wasix_standard_assets"), + "standard_carriers": attr.label(default = "//src/database-resources:wasix_standard_carriers"), + "icu_frozen": attr.label(default = "//src/database-resources:wasix_icu_frozen", allow_single_file = True), + "icu_assets": attr.label(default = "//src/database-resources:wasix_icu_assets"), + "icu_carriers": attr.label(default = "//src/database-resources:wasix_icu_carriers"), + "_runner": attr.label(default = "//src/database-resources/seeds/wasix:seed_runner", executable = True, cfg = "exec"), + "_unit_test": attr.label(default = "//src/database-resources/seeds/wasix:unit_test", executable = True, cfg = "exec"), + "_script": attr.label(default = "//build_defs/resources:wasix_resource.test.mts", allow_single_file = True), + "_fzstd": attr.label(default = Label("@javascript_packages//:" + JAVASCRIPT["@oliphaunt/wasix-ts"]["packages"]["fzstd"]), providers = [NpmPackageInfo]), + "_sdk_helpers": attr.label_keyed_string_dict(default = { + Label("//src/wasix/sdks/ts:src/resources/extensions.ts"): "resources/extensions.ts", + Label("//src/wasix/sdks/ts:src/resources/archive.ts"): "resources/archive.ts", + Label("//src/wasix/sdks/ts:src/resources/asset-source.ts"): "resources/asset-source.ts", + Label("//src/wasix/sdks/ts:src/resources/zstd.ts"): "resources/zstd.ts", + Label("//src/wasix/sdks/ts:src/storage/database-root.ts"): "storage/database-root.ts", + }, allow_files = True), + "_helpers": attr.label_list(default = ["//build_defs/resources:helpers"], allow_files = True), +})) + +def wasix_resource_test(name): + _wasix_resource_test(name = name, runtime = "//src/database-resources:wasix_consumer_supplier", args = bun_test_entrypoint_args(name), size = "large", timeout = "long", + target_compatible_with = _LINUX_X64, + exec_compatible_with = _LINUX_X64 + ["@zig_sdk//libc:gnu.2.34"]) + +def wasix_sdk_resource_test(name): + """Qualify SDK seed consumption independently of public resource admission.""" + labels = [ + "//src/wasix/sdks/rust:quality_resources_test", + "//src/wasix/runtime:portable_payload", + "//src/database-resources:icu_payload", + ] + seeds = ["//src/database-resources:wasix_" + profile + "_" + group for profile in ["standard", "icu"] for group in ["frozen", "construction"]] + bun_script_test(name = name, entry_point = "//build_defs/resources:wasix_sdk_resource.test.mts", + args = ["$(location " + label + ")" for label in labels] + [_VERSION, PRODUCTS["liboliphaunt-wasix"]["version"]] + ["$(location " + label + ")" for label in seeds], + data = labels + seeds + ["//build_defs/resources:helpers"], + source_files = ["//build_defs/resources:helpers"], + size = "large", timeout = "long", target_compatible_with = _LINUX_X64, + exec_compatible_with = _LINUX_X64 + ["@zig_sdk//libc:gnu.2.34"]) + +def native_resource_slice(name, templates, qualification): + icu_row = [row for row in DATABASE_RESOURCE_ARTIFACTS if row["kind"] == "icu-data"][0] + icu_payload(name = "icu_payload", out = icu_row["asset"].replace("{version}", _VERSION)) + icu_rows = _rows(["@oliphaunt/icu", "oliphaunt-icu", "dev.oliphaunt.runtime:oliphaunt-icu"]) + resource_carriers(name = "icu_carriers", kind = "icu", assets = [":icu_payload"], templates = templates, carriers = json.encode(icu_rows)) + packages = _shipping("icu_carriers", icu_rows, suppliers = "//build_defs/release:no_suppliers") + shipping_package(name = "icu_github", owner = "@oliphaunt_metadata//:product_database-resources", artifacts = [":icu_payload"], ecosystem = "github", + package_name = icu_row["asset"].replace("{version}", _VERSION), configuration = "portable", role = "github-release-asset", suppliers = "//build_defs/release:no_suppliers") + packages.append(":icu_github") + platform_packages = {} + for architecture, (target, compatible, condition) in _DESKTOP_PROFILES.items(): + selected = [] + for profile in DATABASE_RESOURCE_CONTRACT["profiles"]: + prefix = architecture + "_" + profile + icu = ":icu_payload" if profile == "icu" else None + native_seed(name = prefix + "_seed", target = target, profile = profile, icu = icu, + target_compatible_with = compatible, exec_compatible_with = compatible, + **SEED_REUSE_CONTROLS.get("native/" + target + "/" + profile, {})) + native.filegroup(name = prefix + "_frozen", srcs = [":" + prefix + "_seed"], output_group = "frozen") + native.filegroup(name = prefix + "_abi", srcs = [":" + prefix + "_seed"], output_group = "abi") + native.filegroup(name = prefix + "_construction", srcs = [":" + prefix + "_seed"], output_group = "construction") + native.filegroup(name = prefix + "_specification", srcs = [":" + prefix + "_seed"], output_group = "specification") + selected.extend(native_seed_envelopes(prefix, target, profile, ":" + prefix + "_seed", icu = icu, compatible = compatible)) + platform_packages[condition] = selected + shipping_export(name = "icu_shipping_export", packages = packages, qualification = qualification + ["//src/database-resources/icu:icu_cargo_unit_test"], testonly = True) + shipping_export(name = "native_target_shipping_export", packages = select(platform_packages), qualification = qualification, testonly = True, target_compatible_with = NATIVE_COMPATIBLE) + shipping_export(name = name, packages = packages + select(platform_packages), qualification = qualification, testonly = True, target_compatible_with = NATIVE_COMPATIBLE) + +def linux_resource_slice(name, templates, qualification): + """Retain the original Linux entry point while sharing desktop construction.""" + native_resource_slice(name = "native_shipping_export", templates = templates, qualification = qualification) + native.alias(name = name, actual = ":native_shipping_export", testonly = True, target_compatible_with = ["@platforms//os:linux"]) + +def _native_seed_consumer_test_impl(ctx): + arguments = [ctx.file.runtime, ctx.file.consumer, PRODUCTS["liboliphaunt-native"]["version"], _VERSION, ctx.file.specification] + ctx.files.icu_files + ctx.files.seed_files + files = [ctx.file.runtime, ctx.file.consumer, ctx.file.specification] + ctx.files.icu_files + ctx.files.seed_files + return bun_test_entrypoint(ctx, ctx.file._script, arguments, files + ctx.files._helpers, + source_files = [ctx.file._script] + ctx.files._helpers, + additional_runfiles = ctx.attr.consumer[DefaultInfo].default_runfiles) + +native_seed_consumer_test = rule(implementation = _native_seed_consumer_test_impl, cfg = desktop_profile, test = True, toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "runtime": attr.label(default = "//src/native/runtime:runtime_payload", allow_single_file = True), + "consumer": attr.label(default = "//build_defs/resources:seed_consumer", allow_single_file = True), + "specification": attr.label(mandatory = True, allow_single_file = True), + "icu_files": attr.label_list(allow_files = True), + "seed_files": attr.label_list(allow_files = True), + "_script": attr.label(default = "//build_defs/resources:resource_slice.test.mts", allow_single_file = True), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), + "_helpers": attr.label_list(default = [ + "//build_defs/resources:helpers", "//build_defs/resources:shared.mts", + "//src/native/sdks/ts:src/root-descriptor.ts", "//src/native/sdks/ts:src/native/filesystem-durability.ts", + "//src/native/sdks/ts:src/native/cluster-seed.ts", + "//src/database-resources:contracts/profile-probe.json", + ], allow_files = True), +})) + +def native_resource_test(name, compatible = NATIVE_COMPATIBLE): + """Qualify the selected host using actual frozen seeds and final carriers.""" + seed_files = {} + targets = {} + for architecture, (target, _compatible, condition) in _DESKTOP_PROFILES.items(): + seed_files[condition] = [":" + architecture + "_" + profile + "_" + group + for profile in sorted(DATABASE_RESOURCE_CONTRACT["profiles"]) + for group in ["archive", "manifest", "frozen", "abi", "carriers_npm_files", "carriers_cargo_files", "construction"]] + targets[condition] = ":" + architecture + "_standard_specification" + icu = [":icu_payload", ":icu_carriers_npm_files", ":icu_carriers_cargo_files", ":icu_carriers_maven_files"] + native_seed_consumer_test( + name = name, + args = bun_test_entrypoint_args(name), + specification = select(targets), + icu_files = icu, + seed_files = select(seed_files), + target_compatible_with = compatible, + size = "medium", + ) + +def linux_resource_test(name): + native_resource_test(name, compatible = ["@platforms//os:linux"]) diff --git a/build_defs/resources/seed-construction-fixture.mts b/build_defs/resources/seed-construction-fixture.mts new file mode 100644 index 000000000..b64653406 --- /dev/null +++ b/build_defs/resources/seed-construction-fixture.mts @@ -0,0 +1,144 @@ +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { packageClusterSeed } from '../../src/database-resources/seeds/package.mts'; +import { createDeterministicTar } from '../../tools/packaging/archive-directory.mts'; +import { + captureSeedConstructionIntent, + writeSeedConstructionReceipt, +} from './seed_construction.mts'; + +export const publication = { + product: 'database-resources', + version: '0.2.2', + tagName: 'database-resources-v0.2.2', + publicationSha: 'a'.repeat(40), + publicationTree: 'b'.repeat(40), + releaseSha: 'c'.repeat(40), +}; + +export const identity = (file: string) => { + const bytes = readFileSync(file); + return { + path: file, + size: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + }; +}; + +export async function fixture( + family: 'native' | 'wasix', + profile: 'standard' | 'icu' = 'standard', +) { + const root = mkdtempSync(path.join(tmpdir(), 'seed-construction-test-')); + const contract = JSON.parse( + readFileSync( + new URL('../../src/database-resources/contracts/contract.json', import.meta.url), + 'utf8', + ), + ); + const target = family === 'native' ? 'linux-x64-gnu' : 'portable'; + const pgdata = path.join(root, 'pgdata'); + for (const directory of contract.pgdataDirectories) + mkdirSync(path.join(pgdata, directory), { recursive: true }); + writeFileSync(path.join(pgdata, 'PG_VERSION'), '18\n'); + // Opaque formatter fixtures: installed resource tests supply actual PostgreSQL execution. + writeFileSync(path.join(pgdata, 'global/pg_control'), 'unchanged opaque control bytes\n'); + writeFileSync( + path.join(pgdata, 'pg_wal/000000010000000000000001'), + 'unchanged opaque WAL bytes\n', + ); + const runtime = path.join(root, 'runtime'); + mkdirSync(path.join(runtime, 'bin'), { recursive: true }); + const postgres = path.join(runtime, 'bin/postgres'); + const initdb = path.join(runtime, 'bin/initdb'); + const tool = path.join(root, 'constructor.mts'); + writeFileSync(postgres, 'actual declared postgres bytes fixture'); + writeFileSync(initdb, 'actual declared initdb bytes fixture'); + writeFileSync(tool, 'actual constructor source fixture'); + const inputs = { postgres, initdb, tool }; + const invocation = { + contract, + command: 'initdb', + arguments: ['--encoding=UTF8'], + environment: { TZ: 'UTC' }, + }; + const intent = captureSeedConstructionIntent({ family, target, profile }, invocation, inputs); + const frozen = path.join(root, 'frozen.tar'); + writeFileSync(frozen, await createDeterministicTar(pgdata)); + const receiptPath = path.join(root, 'receipt.json'); + const receipt = writeSeedConstructionReceipt(receiptPath, intent, frozen, pgdata); + const icuData = profile === 'icu' ? path.join(root, 'icu') : undefined; + if (icuData) { + mkdirSync(icuData); + writeFileSync(path.join(icuData, 'icudt76l.dat'), 'fixture data'); + } + const assets = await packageClusterSeed({ + family, + target, + profile, + pgdata, + runtime, + icuData, + contract, + version: publication.version, + runtimeVersion: '0.3.2', + outputDir: path.join(root, 'assets'), + }); + const metadata = path.join(root, 'metadata.json'); + const updateMetadata = (currentReceipt = receipt) => + writeFileSync( + metadata, + JSON.stringify({ + source: { commit: publication.publicationSha, tree: publication.publicationTree }, + product: { id: publication.product, version: publication.version }, + construction: [ + { seedConstructions: [{ path: receiptPath, contents: JSON.stringify(currentReceipt) }] }, + ], + }), + ); + updateMetadata(); + const control = () => ({ + operation: 'reuse' as const, + publication, + archive: identity(assets.archive), + manifest: identity(assets.manifest), + metadata: identity(metadata), + }); + return { + root, + intent, + inputs, + invocation, + pgdata, + receipt, + receiptPath, + frozen, + assets, + metadata, + updateMetadata, + control, + }; +} + +export function bootstrapFiles(root: string) { + const share = path.join(root, 'share'); + mkdirSync(path.join(share, 'extension'), { recursive: true }); + for (const name of [ + 'postgres.bki', + 'pg_hba.conf.sample', + 'pg_ident.conf.sample', + 'postgresql.conf.sample', + 'snowball_create.sql', + 'information_schema.sql', + 'sql_features.txt', + 'system_constraints.sql', + 'system_functions.sql', + 'system_views.sql', + ]) + writeFileSync(path.join(share, name), `actual ${name} bytes\n`); + writeFileSync(path.join(share, 'extension/plpgsql.control'), "default_version = '1.0'\n"); + writeFileSync(path.join(share, 'extension/plpgsql--1.0.sql'), 'actual language bootstrap SQL\n'); + return share; +} diff --git a/build_defs/resources/seed_assets.mts b/build_defs/resources/seed_assets.mts new file mode 100644 index 000000000..b71653b86 --- /dev/null +++ b/build_defs/resources/seed_assets.mts @@ -0,0 +1,67 @@ +import assert from 'node:assert/strict'; +import { copyFileSync, readFileSync, realpathSync, rmSync } from 'node:fs'; +import path from 'node:path'; +import { validateNativeClusterSeedDirectory } from '../../src/database-resources/contracts/native-manifest.mts'; +import { packageClusterSeed } from '../../src/database-resources/seeds/package.mts'; +import { extractPortableArchiveTree } from '../../tools/packaging/portable-archive.mts'; +import { fileIdentity } from '../../tools/release/native-file-identity.mts'; +import { extractNativePayload } from '../native/host-runtime-test-helpers.mts'; +import { seedProducerIdentity, validateSeedConstructionReceipt } from './seed_construction.mts'; +import { materializeArchive, privateWork, readSpecification } from './shared.mts'; +import { extractWasixRuntime } from './wasix_inputs.mts'; + +const specification = readSpecification(); +const work = privateWork(path.resolve(specification.archive)); +try { + const family = specification.family; + assert.ok(['native', 'wasix'].includes(family)); + const runtime = family === 'wasix' ? extractWasixRuntime(specification.runtime, work) : undefined; + const receipt = validateSeedConstructionReceipt( + JSON.parse(readFileSync(specification.construction, 'utf8')), + ); + const actualFrozen = fileIdentity(realpathSync(specification.seed)); + assert.deepEqual( + receipt.frozen, + { size: actualFrozen.size, sha256: actualFrozen.sha256 }, + 'seed archive must bind its original frozen constructor', + ); + assert.equal(receipt.intent.family, family); + assert.equal(receipt.intent.target, specification.target); + assert.equal(receipt.intent.profile, specification.profile); + const seed = path.join(work, 'seed'); + await extractNativePayload(specification.seed, seed); + let icuData: string | undefined; + if (specification.icu) { + const icuRoot = path.join(work, 'icu'); + extractPortableArchiveTree( + materializeArchive(specification.icu, path.join(work, 'inputs')), + icuRoot, + ); + icuData = path.join(icuRoot, 'share/icu'); + } + if (family === 'native') + validateNativeClusterSeedDirectory(seed, specification.profile, { + target: specification.target, + icuData, + }); + const result = await packageClusterSeed({ + family, + target: specification.target, + profile: specification.profile, + pgdata: family === 'native' ? path.join(seed, 'files') : seed, + runtime, + icuData, + version: specification.version, + runtimeVersion: specification.runtimeVersion, + producer: seedProducerIdentity(receipt), + nativeSourceManifest: family === 'native' ? receipt.sourceManifest?.contents : undefined, + contract: specification.contract, + outputDir: path.join(work, 'assets'), + }); + assert.equal(path.basename(result.archive), path.basename(specification.archive)); + assert.equal(path.basename(result.manifest), path.basename(specification.manifest)); + copyFileSync(result.archive, specification.archive); + copyFileSync(result.manifest, specification.manifest); +} finally { + rmSync(work, { recursive: true, force: true }); +} diff --git a/build_defs/resources/seed_construction.mts b/build_defs/resources/seed_construction.mts new file mode 100644 index 000000000..910cd7c60 --- /dev/null +++ b/build_defs/resources/seed_construction.mts @@ -0,0 +1,918 @@ +/** A seed is immutable data; reuse requires the same concrete construction intent. */ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { lstatSync, readdirSync, readFileSync, realpathSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { + emptyDirectoryPaths, + filesystemTreeRows, + logicalTreeSha256, + validatePgdataDirectories, +} from '../../src/database-resources/contracts/native-manifest.mts'; +import { readPortableArchiveEntries } from '../../tools/packaging/portable-archive.mts'; +import type { CompletedPublication } from '../../tools/release/completed-release-publication.mts'; +import { fileIdentity } from '../../tools/release/native-file-identity.mts'; + +export const SEED_CONSTRUCTION_SCHEMA = 'oliphaunt-seed-construction-v1'; +export const SEED_CONSTRUCTION_RECEIPT_SUFFIX = '.seed-construction.json'; +type FileIdentity = { size: number; sha256: string }; +type DeclaredFile = FileIdentity & { path: string }; +type Slot = { family: 'native' | 'wasix'; target: string; profile: 'standard' | 'icu' }; +export type SeedConstructionIntent = Slot & { + invocation: unknown; + inputs: { name: string; members: unknown[] }[]; +}; + +/** Bind semantic roles to the actual declared File, independent of its cache location. */ +export function seedConstructionFileBinding(inputs: Record, file: string) { + const names = Object.entries(inputs) + .filter(([, declared]) => path.resolve(declared) === path.resolve(file)) + .map(([name]) => name); + assert.equal(names.length, 1, 'constructor role must name exactly one declared logical File'); + return names[0]; +} + +/** Only explicitly named execution locations are replaced, never input contents. */ +export function seedConstructionInvocation( + command: string, + arguments_: string[], + environment: NodeJS.ProcessEnv, + locations: Record, +) { + const mappings = Object.entries(locations).sort( + ([, left], [, right]) => right.length - left.length, + ); + const transport = (value: string) => { + for (const [name, location] of mappings) { + assert.ok(location, 'constructor execution location is required'); + value = value.replaceAll(location, `<${name}>`); + } + return value; + }; + return { + command: transport(command), + arguments: arguments_.map(transport), + environment: Object.fromEntries( + Object.entries(environment) + .filter((entry): entry is [string, string] => entry[1] !== undefined) + .map(([name, value]) => [name, transport(value)]), + ), + }; +} +export type SeedReuseControl = { + operation: 'reuse' | 'adopt'; + publication: CompletedPublication; + archive: DeclaredFile; + manifest: DeclaredFile; + metadata?: DeclaredFile; + /** Reviewed, immutable migration contract, distinct from old release metadata. */ + anchor?: DeclaredFile; +}; +type Source = { commit: string; tree: string }; +export type QualifiedSeedControl = { + source: Source; + evidenceDigest: string; + invocationId: string; + frozen: DeclaredFile; + receipt: DeclaredFile; + transition: { source: Source; updatesSha256: string }; +}; +export type SeedProducerIdentity = { postgresSha256: string; initdbSha256: string }; +type SeedSourceManifest = FileIdentity & { contents: string; publication: CompletedPublication }; +export type SeedConstructionReceipt = { + schema: typeof SEED_CONSTRUCTION_SCHEMA; + intent: SeedConstructionIntent; + intentSha256: string; + frozen: FileIdentity; + pgdata: { treeSha256: string; emptyDirectories: string[] }; + /** A promoted seed retains its original constructor, qualified by the current runtime. */ + qualificationIntent?: SeedConstructionIntent; + /** Desired seed contents; executable/tool provenance remains in intent. */ + contentIntent?: SeedConstructionIntent; + contentIntentSha256?: string; + qualificationContentIntent?: SeedConstructionIntent; + /** The exact completed descriptor preserves creator facts for copied PGDATA. */ + sourceManifest?: SeedSourceManifest; + origin: + | { kind: 'constructed' } + | { + kind: 'completed-publication'; + operation: 'reused' | 'adopted'; + publication: CompletedPublication; + archive: FileIdentity; + manifest: FileIdentity; + metadata?: FileIdentity; + anchor?: FileIdentity & { source: Source; receiptSha256: string }; + } + | { + kind: 'qualified-construction'; + source: Source; + evidenceDigest: string; + invocationId: string; + frozen: FileIdentity; + receipt: FileIdentity; + transition: QualifiedSeedControl['transition']; + }; +}; + +export const SEED_CONSTRUCTION_ANCHOR_SCHEMA = 'oliphaunt-seed-construction-anchor-v1'; +export type SeedConstructionAnchor = { + schema: typeof SEED_CONSTRUCTION_ANCHOR_SCHEMA; + source: Source; + publication: CompletedPublication; + seeds: (Slot & { + archive: FileIdentity; + manifest: FileIdentity; + receipt: FileIdentity & { contents: string }; + producer: { + evidenceDigest: string; + invocationId: string; + root: string; + configuration: string; + output: string; + }; + })[]; +}; + +const sha256 = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +const canonical = (value: unknown): string => + Array.isArray(value) + ? `[${value.map(canonical).join(',')}]` + : value && typeof value === 'object' + ? `{${Object.entries(value) + .sort(([left], [right]) => left.localeCompare(right)) + .map(([key, child]) => `${JSON.stringify(key)}:${canonical(child)}`) + .join(',')}}` + : JSON.stringify(value); +const digest = (value: unknown) => sha256(Buffer.from(canonical(value))); +export const seedConstructionIntentSha256 = (intent: SeedConstructionIntent) => digest(intent); +const equal = (left: unknown, right: unknown) => canonical(left) === canonical(right); +const physicalFile = (file: string) => fileIdentity(realpathSync(file)); +const identity = ({ size, sha256 }: FileIdentity): FileIdentity => ({ size, sha256 }); +const assertIdentity = (value: FileIdentity) => { + assert.ok(Number.isSafeInteger(value?.size) && value.size > 0, 'seed identity needs size'); + assert.match(value.sha256, /^[a-f0-9]{64}$/u, 'seed identity needs SHA-256'); +}; +const safeName = (name: string) => { + assert.ok( + name && + !path.isAbsolute(name) && + !/[\\\u0000-\u001f\u007f]/u.test(name) && + !name.split('/').some((part) => !part || part === '.' || part === '..'), + 'seed constructor input requires a safe logical name', + ); +}; + +/** Bind Bazel's expanded TreeArtifact leaves to their original regular Files. + * This is an execution inventory, never a recursive discovery of link targets. + */ +export function expandSeedConstructionTrees( + inputs: Record, + trees: string[], + files: string[], + knownMembers: Record> = {}, +) { + assert.ok( + Array.isArray(trees) && Array.isArray(files), + 'declared constructor Trees require a leaf inventory', + ); + const expanded: Record = Object.assign(Object.create(null), inputs); + const treeMembers: Record> = Object.assign( + Object.create(null), + knownMembers, + ); + const seenTrees = new Set(); + const roots = trees.map((file) => { + assert.ok(typeof file === 'string' && file, 'constructor Tree requires a declared File path'); + const resolved = path.resolve(file); + assert.ok(!seenTrees.has(resolved), 'constructor Tree is declared more than once'); + seenTrees.add(resolved); + const name = seedConstructionFileBinding(inputs, file); + safeName(name); + assert.ok( + !Object.hasOwn(treeMembers, name), + 'constructor Tree already has a declared member inventory', + ); + const physical = realpathSync(file); + assert.ok(lstatSync(physical).isDirectory(), 'constructor Tree must be a directory'); + const members: Record = Object.create(null); + treeMembers[name] = members; + return { name, resolved, physical, members }; + }); + for (const root of roots) + for (const other of roots) + if (root !== other) { + const relative = path.relative(root.resolved, other.resolved); + assert.ok( + relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative), + 'constructor Tree roots must not overlap', + ); + } + const seenFiles = new Set(); + for (const file of files) { + assert.ok( + typeof file === 'string' && + file && + !/[\u0000-\u001f\u007f]/u.test(file) && + !file.split(path.sep).some((part) => part === '.' || part === '..'), + 'constructor Tree leaf requires a safe File path', + ); + const resolved = path.resolve(file); + assert.ok(!seenFiles.has(resolved), 'constructor Tree leaf is declared more than once'); + seenFiles.add(resolved); + const owners = roots.filter((root) => { + const relative = path.relative(root.resolved, resolved); + return ( + relative && + relative !== '..' && + !relative.startsWith(`..${path.sep}`) && + !path.isAbsolute(relative) + ); + }); + assert.equal(owners.length, 1, 'constructor Tree leaf requires one exact declared input root'); + const root = owners[0]; + const member = path.relative(root.resolved, resolved).split(path.sep).join('/'); + safeName(member); + let directory = root.physical; + for (const part of member.split('/').slice(0, -1)) { + directory = path.join(directory, part); + const stat = lstatSync(directory); + assert.ok( + stat.isDirectory() && !stat.isSymbolicLink(), + 'constructor Tree leaf has an aliased parent directory', + ); + } + const primary = realpathSync(path.join(root.physical, member)); + assert.ok( + lstatSync(primary).isFile(), + 'constructor Tree leaf requires an actual regular primary File', + ); + const logical = `${root.name}/${member}`; + assert.ok( + !Object.hasOwn(expanded, logical), + 'constructor Tree leaf collides with a declared File name', + ); + expanded[logical] = primary; + root.members[member] = primary; + } + for (const root of roots) + assert.ok(Object.keys(root.members).length > 0, 'constructor Tree has no declared leaf Files'); + return { inputs: expanded, treeMembers }; +} + +/** Physical names are transport locations; logical File names and all bytes remain exact. */ +export function captureSeedConstructionIntent( + slot: Slot, + invocation: unknown, + inputs: Record, + toolTreeMembers: Record> = {}, +): SeedConstructionIntent { + assert.ok(['native', 'wasix'].includes(slot.family), 'seed family is required'); + assert.ok(['standard', 'icu'].includes(slot.profile), 'seed profile is required'); + safeName(slot.target); + assert.ok(Object.keys(inputs).length > 0, 'seed construction must declare actual inputs'); + for (const [name, declared] of Object.entries(toolTreeMembers)) { + assert.ok(Object.hasOwn(inputs, name), 'constructor tool tree must be a declared input'); + assert.ok(Object.keys(declared).length, 'constructor tool tree requires declared members'); + for (const [member, source] of Object.entries(declared)) { + safeName(member); + assert.ok( + Object.values(inputs).includes(source), + 'constructor tool member must be a declared File', + ); + } + } + const records = Object.entries(inputs) + .sort(([left], [right]) => left.localeCompare(right)) + .map(([name, file]) => { + safeName(name); + const logicalName = name; + const physical = realpathSync(file); + const members: Record[] = []; + const expected = Object.hasOwn(toolTreeMembers, name) ? toolTreeMembers[name] : undefined; + const directories = new Set(['']); + const observed = new Set(); + if (expected) + for (const member of Object.keys(expected)) { + const parts = member.split('/'); + for (let count = 1; count < parts.length; count++) + directories.add(parts.slice(0, count).join('/')); + } + const visit = (file: string, name: string) => { + const stat = lstatSync(file); + assert.ok( + expected || !stat.isSymbolicLink(), + `constructor input tree must contain actual Files: ${logicalName}/${name || '.'}`, + ); + let actual: FileIdentity | undefined; + if (expected) { + if (stat.isDirectory()) + assert.ok(directories.has(name), 'constructor tool tree has an undeclared directory'); + else { + assert.ok( + Object.hasOwn(expected, name), + 'constructor tool tree has an undeclared member', + ); + actual = identity(physicalFile(file)); + assert.deepEqual( + actual, + identity(physicalFile(expected[name])), + 'constructor tool tree member differs from its declared File', + ); + observed.add(name); + } + } + if (stat.isDirectory()) { + members.push({ path: name, type: 'directory' }); + for (const child of readdirSync(file).sort()) + visit(path.join(file, child), name ? `${name}/${child}` : child); + } else { + members.push({ path: name, type: 'file', ...(actual ?? identity(fileIdentity(file))) }); + } + }; + // Cache read-only modes and checkout write bits do not describe seed intent. + if (expected) + assert.ok(lstatSync(physical).isDirectory(), 'constructor tool tree must be a directory'); + visit(physical, ''); + if (expected) + assert.deepEqual( + [...observed].sort(), + Object.keys(expected).sort(), + 'constructor tool tree is missing a declared File', + ); + members.sort((left, right) => String(left.path).localeCompare(String(right.path))); + assert.ok(members.length, 'constructor input must contain actual bytes'); + return { name, members }; + }); + return structuredClone({ ...slot, invocation, inputs: records }); +} + +/** Actual initdb bootstrap data, separate from runtime/tool implementation and version envelopes. */ +export function captureSeedContentIntent( + slot: Slot, + invocation: unknown, + share: string, + icuData?: string, +) { + const names = [ + 'postgres.bki', + 'pg_hba.conf.sample', + 'pg_ident.conf.sample', + 'postgresql.conf.sample', + 'snowball_create.sql', + 'information_schema.sql', + 'sql_features.txt', + 'system_constraints.sql', + 'system_functions.sql', + 'system_views.sql', + ]; + const control = path.join(share, 'extension/plpgsql.control'); + const versions = [ + ...readFileSync(control, 'utf8').matchAll( + /^\s*default_version\s*=\s*'([A-Za-z0-9._-]+)'\s*(?:#.*)?$/gmu, + ), + ]; + assert.equal(versions.length, 1, 'initdb requires one declared plpgsql bootstrap version'); + const inputs = Object.fromEntries( + names.map((name) => [`bootstrap/${name}`, path.join(share, name)]), + ); + inputs['bootstrap/plpgsql.control'] = control; + inputs['bootstrap/plpgsql.sql'] = path.join(share, `extension/plpgsql--${versions[0][1]}.sql`); + if (icuData) inputs['icu/data'] = icuData; + return captureSeedConstructionIntent(slot, invocation, inputs); +} + +export function captureSeedProducerIdentity(runtime: string, target: string): SeedProducerIdentity { + const suffix = target.startsWith('windows-') ? '.exe' : ''; + return { + postgresSha256: physicalFile(path.join(runtime, 'bin', 'postgres' + suffix)).sha256, + initdbSha256: physicalFile(path.join(runtime, 'bin', 'initdb' + suffix)).sha256, + }; +} + +/** Current qualification never rewrites the identity of the data's creator. */ +export function seedProducerIdentity(receipt: SeedConstructionReceipt): SeedProducerIdentity { + let producer: SeedProducerIdentity; + if (receipt.sourceManifest) { + const manifest = JSON.parse(receipt.sourceManifest.contents); + producer = { + postgresSha256: + receipt.intent.family === 'native' + ? manifest.source?.postgresSha256 + : manifest.runtime?.producerSha256, + initdbSha256: + receipt.intent.family === 'native' + ? manifest.source?.initdbSha256 + : manifest.runtime?.initdbSha256, + }; + } else { + assert.ok( + receipt.origin.kind !== 'completed-publication', + 'copied seed lacks its original completed descriptor', + ); + producer = (receipt.intent.invocation as any)?.producer; + } + assert.ok(producer, 'seed constructor lacks its original producer identity'); + for (const value of [producer.postgresSha256, producer.initdbSha256]) + assert.match(value, /^[a-f0-9]{64}$/u, 'seed original producer needs exact hashes'); + return { postgresSha256: producer.postgresSha256, initdbSha256: producer.initdbSha256 }; +} + +export function validateSeedConstructionReceipt(value: unknown): SeedConstructionReceipt { + const receipt = value as SeedConstructionReceipt; + assert.equal(receipt?.schema, SEED_CONSTRUCTION_SCHEMA, 'unsupported seed constructor receipt'); + assert.ok( + receipt.intent && Array.isArray(receipt.intent.inputs), + 'missing seed constructor intent', + ); + assert.ok(receipt.intent.inputs.length, 'empty seed constructor intent'); + assert.equal( + receipt.intentSha256, + digest(receipt.intent), + 'seed constructor intent digest differs', + ); + assert.equal( + Boolean(receipt.contentIntent), + Boolean(receipt.contentIntentSha256), + 'seed content intent/digest must be paired', + ); + if (receipt.contentIntent) { + assert.ok(receipt.contentIntent.inputs.length, 'seed content intent requires actual inputs'); + assert.equal( + receipt.contentIntentSha256, + digest(receipt.contentIntent), + 'seed content intent digest differs', + ); + assert.ok( + ['family', 'target', 'profile'].every( + (key) => receipt.contentIntent?.[key] === receipt.intent[key], + ), + 'seed content intent slot differs', + ); + } + if (receipt.qualificationContentIntent) { + assert.ok( + receipt.origin.kind === 'qualified-construction' && receipt.contentIntent, + 'qualified seed content requires original content intent', + ); + assert.ok( + ['family', 'target', 'profile'].every( + (key) => receipt.qualificationContentIntent?.[key] === receipt.intent[key], + ), + 'qualified seed content slot differs', + ); + } + if (receipt.sourceManifest) { + const original = receipt.sourceManifest; + assert.deepEqual(Object.keys(original).sort(), ['contents', 'publication', 'sha256', 'size']); + assertCompletedIdentity(original.publication); + const contents = Buffer.from(original.contents); + assert.deepEqual( + identity(original), + { size: contents.length, sha256: sha256(contents) }, + 'seed original descriptor bytes differ', + ); + const manifest = JSON.parse(original.contents); + assert.equal(manifest.catalogProfile, receipt.intent.profile); + assert.equal(manifest.runtime?.engineFamily, receipt.intent.family); + assert.equal(manifest.runtime?.target, receipt.intent.target); + assert.equal(manifest.runtime?.postgresMajor, 18); + assert.ok( + receipt.origin.kind !== 'constructed', + 'fresh seed cannot claim a completed descriptor', + ); + if (receipt.origin.kind === 'completed-publication') { + assert.deepEqual(original.publication, receipt.origin.publication); + assert.deepEqual(identity(original), receipt.origin.manifest); + assert.equal( + manifest.archive?.sha256, + receipt.origin.archive.sha256, + 'original descriptor archive digest differs', + ); + assert.equal( + manifest.archive?.compressedBytes, + receipt.origin.archive.size, + 'original descriptor archive size differs', + ); + } + seedProducerIdentity(receipt); + } + assertIdentity(receipt.frozen); + assert.match(receipt.pgdata?.treeSha256, /^[a-f0-9]{64}$/u, 'missing exact PGDATA digest'); + assert.ok(Array.isArray(receipt.pgdata.emptyDirectories), 'missing empty PGDATA directories'); + for (const name of receipt.pgdata.emptyDirectories) safeName(name); + assert.deepEqual( + receipt.pgdata.emptyDirectories, + [...new Set(receipt.pgdata.emptyDirectories)].sort(), + 'seed empty directory identity is not canonical', + ); + if (receipt.origin?.kind === 'qualified-construction') { + validateQualifiedSeedOrigin(receipt.origin); + assert.ok(receipt.qualificationIntent, 'promoted seed requires the observed current intent'); + assert.ok( + ['family', 'target', 'profile'].every( + (key) => receipt.intent[key] === receipt.qualificationIntent?.[key], + ), + 'promoted seed must keep the same seed slot', + ); + } else if (receipt.origin?.kind === 'completed-publication') { + assert.ok( + ['reused', 'adopted'].includes(receipt.origin.operation), + 'unknown seed reuse operation', + ); + assertCompletedIdentity(receipt.origin.publication); + assertIdentity(receipt.origin.archive); + assertIdentity(receipt.origin.manifest); + if (receipt.origin.metadata) assertIdentity(receipt.origin.metadata); + if (receipt.origin.anchor) { + assertIdentity(receipt.origin.anchor); + for (const value of Object.values(receipt.origin.anchor.source)) + assert.match(value, /^[a-f0-9]{40}$/u); + assert.match(receipt.origin.anchor.receiptSha256, /^[a-f0-9]{64}$/u); + assert.ok(receipt.contentIntent, 'anchored seed reuse requires observed content intent'); + } + if (receipt.origin.operation === 'reused') + assert.ok( + receipt.origin.metadata || receipt.origin.anchor, + 'reused seed requires its authentic constructor metadata or declared migration anchor', + ); + } else assert.equal(receipt.origin?.kind, 'constructed', 'unknown seed construction origin'); + return structuredClone(receipt); +} + +/** Structural validation cannot authenticate an anchor; the controller binds reviewed source. */ +export function validateSeedConstructionAnchor(value: unknown): SeedConstructionAnchor { + const anchor = value as SeedConstructionAnchor; + assert.equal( + anchor?.schema, + SEED_CONSTRUCTION_ANCHOR_SCHEMA, + 'unsupported seed construction anchor', + ); + assert.deepEqual( + Object.keys(anchor).sort(), + ['schema', 'source', 'publication', 'seeds'].sort(), + 'seed anchor fields differ', + ); + assert.deepEqual(Object.keys(anchor.source).sort(), ['commit', 'tree']); + for (const value of Object.values(anchor.source)) assert.match(value, /^[a-f0-9]{40}$/u); + assertCompletedIdentity(anchor.publication); + assert.ok( + Array.isArray(anchor.seeds) && anchor.seeds.length, + 'seed anchor requires original observations', + ); + const keys = anchor.seeds.map((seed) => { + assert.deepEqual( + Object.keys(seed).sort(), + ['family', 'target', 'profile', 'archive', 'manifest', 'receipt', 'producer'].sort(), + 'seed anchor slot fields differ', + ); + assertIdentity(seed.archive); + assertIdentity(seed.manifest); + assertIdentity(seed.receipt); + assert.equal( + seed.receipt.size, + Buffer.byteLength(seed.receipt.contents), + 'seed anchor receipt size differs', + ); + assert.equal( + seed.receipt.sha256, + sha256(Buffer.from(seed.receipt.contents)), + 'seed anchor receipt bytes differ', + ); + assert.deepEqual( + Object.keys(seed.producer).sort(), + ['evidenceDigest', 'invocationId', 'root', 'configuration', 'output'].sort(), + 'seed anchor producer fields differ', + ); + assert.match(seed.producer.evidenceDigest, /^sha256:[a-f0-9]{64}$/u); + for (const field of ['invocationId', 'root', 'configuration', 'output']) + assert.ok(typeof seed.producer[field] === 'string' && seed.producer[field]); + const receipt = validateSeedConstructionReceipt(JSON.parse(seed.receipt.contents)); + assert.ok(receipt.contentIntent, 'seed anchor requires original observed desired contents'); + assert.ok( + ['family', 'target', 'profile'].every((key) => receipt.intent[key] === seed[key]), + 'seed anchor slot differs from original receipt', + ); + assert.equal( + receipt.origin.kind, + 'completed-publication', + 'seed anchor must record explicit adoption', + ); + assert.equal( + receipt.origin.operation, + 'adopted', + 'seed anchor cannot reinterpret a constructed seed', + ); + assert.deepEqual( + receipt.origin.publication, + anchor.publication, + 'seed anchor publication differs', + ); + assert.deepEqual(receipt.origin.archive, seed.archive, 'seed anchor archive differs'); + assert.deepEqual(receipt.origin.manifest, seed.manifest, 'seed anchor manifest differs'); + return `${seed.family}/${seed.target}/${seed.profile}`; + }); + assert.deepEqual(keys, [...new Set(keys)].sort(), 'seed anchor slots must be unique and sorted'); + return structuredClone(anchor); +} + +function validateQualifiedSeedOrigin( + control: Omit & { + frozen: FileIdentity; + receipt: FileIdentity; + }, +) { + for (const source of [control.source, control.transition?.source]) + for (const value of [source?.commit, source?.tree]) + assert.match(value, /^[a-f0-9]{40}$/u, 'qualified seed source must be exact'); + assert.match( + control.evidenceDigest, + /^sha256:[a-f0-9]{64}$/u, + 'qualified seed requires its authenticated evidence digest', + ); + assert.ok( + typeof control.invocationId === 'string' && control.invocationId.length > 0, + 'qualified seed requires its original invocation', + ); + assert.match( + control.transition.updatesSha256, + /^[a-f0-9]{64}$/u, + 'seed promotion requires exact generated version updates', + ); + assertIdentity(control.frozen); + assertIdentity(control.receipt); +} + +/** Only the controller authenticates producer/transition; this action binds exact declared Files. */ +export function selectQualifiedSeed( + intent: SeedConstructionIntent, + control?: QualifiedSeedControl, + contentIntent?: SeedConstructionIntent, +) { + if (!control) return undefined; + validateQualifiedSeedOrigin(control); + for (const file of [control.frozen, control.receipt]) + assert.deepEqual( + identity(physicalFile(file.path)), + identity(file), + 'qualified seed input bytes differ', + ); + const receipt = validateSeedConstructionReceipt( + JSON.parse(readFileSync(control.receipt.path, 'utf8')), + ); + assert.deepEqual( + receipt.frozen, + identity(control.frozen), + 'qualified seed receipt/TAR binding differs', + ); + assert.ok( + ['family', 'target', 'profile'].every((key) => receipt.intent[key] === intent[key]), + 'qualified seed promotion cannot change seed slot', + ); + if (contentIntent) { + const originalContent = receipt.qualificationContentIntent ?? receipt.contentIntent; + assert.ok( + originalContent && equal(originalContent, contentIntent), + 'version promotion changed declared seed contents', + ); + } + const origin: SeedConstructionReceipt['origin'] = { + kind: 'qualified-construction', + source: structuredClone(control.source), + evidenceDigest: control.evidenceDigest, + invocationId: control.invocationId, + frozen: identity(control.frozen), + receipt: identity(control.receipt), + transition: structuredClone(control.transition), + }; + return { + frozen: control.frozen.path, + receipt, + qualificationIntent: structuredClone(intent), + ...(contentIntent ? { qualificationContentIntent: structuredClone(contentIntent) } : {}), + origin, + }; +} + +export function writePromotedSeedReceipt( + file: string, + promoted: NonNullable>, + frozen: string, + pgdata: string, +) { + assert.deepEqual( + identity(physicalFile(frozen)), + promoted.receipt.frozen, + 'promotion must preserve exact frozen TAR bytes', + ); + assert.equal( + logicalTreeSha256(filesystemTreeRows(pgdata)), + promoted.receipt.pgdata.treeSha256, + 'promotion must preserve every PGDATA byte', + ); + assert.deepEqual( + emptyDirectoryPaths(pgdata), + promoted.receipt.pgdata.emptyDirectories, + 'promotion must preserve empty PGDATA directories', + ); + const receipt = validateSeedConstructionReceipt({ + ...promoted.receipt, + qualificationIntent: promoted.qualificationIntent, + ...(promoted.qualificationContentIntent + ? { qualificationContentIntent: promoted.qualificationContentIntent } + : {}), + origin: promoted.origin, + }); + writeFileSync(file, `${JSON.stringify(receipt)}\n`); + return receipt; +} + +function assertCompletedIdentity(publication: CompletedPublication) { + assert.equal(publication?.product, 'database-resources', 'seed owner is database-resources'); + assert.equal(publication.tagName, `${publication.product}-v${publication.version}`); + for (const value of [ + publication.publicationSha, + publication.publicationTree, + publication.releaseSha, + ]) + assert.match(value, /^[a-f0-9]{40}$/u, 'seed reuse needs an exact completed publication'); +} + +/** Validate supplied acquisition bytes even when their recipe will not be reused. */ +export function selectCompletedSeed( + intent: SeedConstructionIntent, + control?: SeedReuseControl, + contentIntent?: SeedConstructionIntent, +) { + if (!control) return undefined; + assertCompletedIdentity(control.publication); + assert.ok( + ['reuse', 'adopt'].includes(control.operation), + 'explicit seed reuse operation is required', + ); + for (const file of [ + control.archive, + control.manifest, + ...(control.metadata ? [control.metadata] : []), + ...(control.anchor ? [control.anchor] : []), + ]) { + assertIdentity(file); + assert.deepEqual( + identity(physicalFile(file.path)), + identity(file), + 'completed seed input bytes differ', + ); + } + const manifest = JSON.parse(readFileSync(control.manifest.path, 'utf8')); + assert.equal(manifest.catalogProfile, intent.profile, 'completed seed profile differs'); + assert.equal(manifest.runtime?.engineFamily, intent.family, 'completed seed family differs'); + assert.equal(manifest.runtime?.target, intent.target, 'completed seed target differs'); + assert.equal(manifest.runtime?.postgresMajor, 18, 'completed seed PostgreSQL contract differs'); + assert.equal( + manifest.archive?.path, + path.basename(control.archive.path), + 'completed archive name differs', + ); + assert.equal( + manifest.archive?.sha256, + control.archive.sha256, + 'completed descriptor digest differs', + ); + assert.equal( + manifest.archive?.compressedBytes, + control.archive.size, + 'completed descriptor size differs', + ); + const origin = { + kind: 'completed-publication' as const, + operation: control.operation === 'adopt' ? ('adopted' as const) : ('reused' as const), + publication: structuredClone(control.publication), + archive: identity(control.archive), + manifest: identity(control.manifest), + ...(control.metadata ? { metadata: identity(control.metadata) } : {}), + }; + assert.ok(!(control.metadata && control.anchor), 'seed constructor baseline is ambiguous'); + const sourceManifest = { + ...identity(control.manifest), + contents: readFileSync(control.manifest.path, 'utf8'), + publication: structuredClone(control.publication), + }; + if (control.operation === 'adopt') + return { archive: control.archive.path, origin, sourceManifest }; + let receipt: SeedConstructionReceipt; + if (control.anchor) { + assert.ok(contentIntent, 'anchor reuse requires observed desired contents'); + const anchor = validateSeedConstructionAnchor( + JSON.parse(readFileSync(control.anchor.path, 'utf8')), + ); + assert.deepEqual( + anchor.publication, + control.publication, + 'seed anchor completed origin differs', + ); + const seed = anchor.seeds.find((seed) => + ['family', 'target', 'profile'].every((key) => seed[key] === intent[key]), + ); + assert.ok(seed, 'seed anchor slot is absent'); + assert.deepEqual(seed.archive, identity(control.archive), 'seed anchor public archive differs'); + assert.deepEqual( + seed.manifest, + identity(control.manifest), + 'seed anchor public descriptor differs', + ); + receipt = validateSeedConstructionReceipt(JSON.parse(seed.receipt.contents)); + if (!equal(receipt.contentIntent, contentIntent)) return undefined; + Object.assign(origin, { + anchor: { + ...identity(control.anchor), + source: anchor.source, + receiptSha256: seed.receipt.sha256, + }, + }); + } else { + if (!control.metadata) return undefined; + const metadata = JSON.parse(readFileSync(control.metadata.path, 'utf8')); + assert.deepEqual( + metadata.source, + { + commit: control.publication.publicationSha, + tree: control.publication.publicationTree, + }, + 'seed metadata source differs from completed publication', + ); + assert.equal(metadata.product?.id, control.publication.product); + assert.equal(metadata.product?.version, control.publication.version); + const receipts = (metadata.construction ?? []) + .flatMap((construction) => construction.seedConstructions ?? []) + .map(({ contents }) => validateSeedConstructionReceipt(JSON.parse(contents))) + .filter((receipt) => + ['family', 'profile', 'target'].every((key) => receipt.intent[key] === intent[key]), + ); + if (!receipts.length) return undefined; // Legacy public origins contain no constructor history. + assert.equal(receipts.length, 1, 'completed seed constructor slot is ambiguous'); + receipt = receipts[0]; + const completedContent = receipt.qualificationContentIntent ?? receipt.contentIntent; + if (contentIntent && completedContent) { + if (!equal(completedContent, contentIntent)) return undefined; + } else if (!equal(receipt.qualificationIntent ?? receipt.intent, intent)) return undefined; + } + assertSeedPublicData(control.archive.path, receipt); + return { archive: control.archive.path, origin, sourceManifest }; +} + +/** The public seed must contain every original PGDATA byte and empty directory. */ +export function assertSeedPublicData(archive: string, receipt: SeedConstructionReceipt) { + const entries = readPortableArchiveEntries(realpathSync(archive)); + const actualTree = logicalTreeSha256( + [...entries.values()] + .filter((entry) => entry.isFile) + .map((entry) => ({ path: entry.name, bytes: entry.data() })), + ); + assert.equal( + actualTree, + receipt.pgdata.treeSha256, + 'completed PGDATA differs from constructor receipt', + ); + const directories = [...entries.values()] + .filter((entry) => entry.isDirectory) + .map((entry) => entry.name.replace(/\/$/u, '')); + const names = [...entries.keys()]; + const emptyDirectories = directories + .filter( + (directory) => + !names.some((name) => name !== `${directory}/` && name.startsWith(`${directory}/`)), + ) + .sort(); + assert.deepEqual( + emptyDirectories, + receipt.pgdata.emptyDirectories, + 'completed PGDATA empty directories differ', + ); +} + +export function writeSeedConstructionReceipt( + file: string, + intent: SeedConstructionIntent, + frozen: string, + pgdata: string, + origin: SeedConstructionReceipt['origin'] = { kind: 'constructed' }, + contentIntent?: SeedConstructionIntent, + sourceManifest?: SeedSourceManifest, +) { + validatePgdataDirectories(pgdata); + const receipt = validateSeedConstructionReceipt({ + schema: SEED_CONSTRUCTION_SCHEMA, + intent, + intentSha256: digest(intent), + ...(contentIntent ? { contentIntent, contentIntentSha256: digest(contentIntent) } : {}), + frozen: identity(physicalFile(frozen)), + pgdata: { + treeSha256: logicalTreeSha256(filesystemTreeRows(pgdata)), + emptyDirectories: emptyDirectoryPaths(pgdata), + }, + origin, + ...(sourceManifest ? { sourceManifest } : {}), + }); + writeFileSync(file, `${JSON.stringify(receipt)}\n`); + return receipt; +} diff --git a/build_defs/resources/seed_construction.test.mts b/build_defs/resources/seed_construction.test.mts new file mode 100644 index 000000000..39acd252d --- /dev/null +++ b/build_defs/resources/seed_construction.test.mts @@ -0,0 +1,904 @@ +import { expect, test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + copyFileSync, + mkdirSync, + mkdtempSync, + readFileSync, + realpathSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { packageClusterSeed } from '../../src/database-resources/seeds/package.mts'; +import { createDeterministicTar } from '../../tools/packaging/archive-directory.mts'; +import { extractPortableArchiveTree } from '../../tools/packaging/portable-archive.mts'; +import { + captureSeedConstructionIntent, + captureSeedContentIntent, + captureSeedProducerIdentity, + expandSeedConstructionTrees, + SEED_CONSTRUCTION_ANCHOR_SCHEMA, + seedConstructionFileBinding, + seedConstructionInvocation, + seedProducerIdentity, + selectCompletedSeed, + selectQualifiedSeed, + validateSeedConstructionAnchor, + validateSeedConstructionReceipt, + writePromotedSeedReceipt, + writeSeedConstructionReceipt, +} from './seed_construction.mts'; +import { bootstrapFiles, fixture, identity, publication } from './seed-construction-fixture.mts'; +import { parseWasixBootstrapRecipe } from './wasix_inputs.mts'; + +test('semantic File roles must bind exact declared inputs and invalidate reassigned headers', () => { + const inputs = { manual: '/cache/manual.h', control: '/cache/control.h' }; + expect(seedConstructionFileBinding(inputs, '/cache/manual.h')).toBe('manual'); + expect(() => seedConstructionFileBinding(inputs, '/ambient/header.h')).toThrow( + 'declared logical File', + ); + expect(() => + seedConstructionFileBinding({ ...inputs, alias: '/cache/manual.h' }, '/cache/manual.h'), + ).toThrow('exactly one'); + const bindings = (headers: Record) => + Object.fromEntries( + Object.entries(headers).map(([role, file]) => [ + role, + seedConstructionFileBinding(inputs, file), + ]), + ); + expect(bindings({ manual: inputs.manual, control: inputs.control })).not.toEqual( + bindings({ manual: inputs.control, control: inputs.manual }), + ); +}); + +test('semantic File names do not inherit undeclared tool trees from Object.prototype', async () => { + const f = await fixture('native'); + try { + const inputs = { constructor: f.inputs.tool, toString: f.inputs.postgres }; + const implicit = captureSeedConstructionIntent( + { family: 'native', target: 'linux-x64-gnu', profile: 'standard' }, + f.invocation, + inputs, + ); + const explicit = captureSeedConstructionIntent( + { family: 'native', target: 'linux-x64-gnu', profile: 'standard' }, + f.invocation, + inputs, + Object.create(null), + ); + expect(implicit).toEqual(explicit); + } finally { + rmSync(f.root, { recursive: true, force: true }); + } +}); + +for (const family of ['native', 'wasix'] as const) { + for (const profile of ['standard', 'icu'] as const) { + test(`${family}/${profile} reuses every immutable PGDATA and empty directory only with matching concrete intent`, async () => { + const f = await fixture(family, profile); + try { + const selected = selectCompletedSeed(f.intent, f.control()); + expect(selected?.origin.operation).toBe('reused'); + expect(selected?.origin.metadata).toBeDefined(); + const destination = path.join(f.root, 'copy'); + extractPortableArchiveTree(f.assets.archive, destination); + expect(readFileSync(path.join(destination, 'global/pg_control'))).toEqual( + readFileSync(path.join(f.pgdata, 'global/pg_control')), + ); + expect(readFileSync(path.join(destination, 'pg_wal/000000010000000000000001'))).toEqual( + readFileSync(path.join(f.pgdata, 'pg_wal/000000010000000000000001')), + ); + expect( + selectCompletedSeed(f.intent, { ...f.control(), metadata: undefined }), + ).toBeUndefined(); + expect(selectCompletedSeed(f.intent)).toBeUndefined(); + const adoption = selectCompletedSeed(f.intent, { + ...f.control(), + operation: 'adopt', + metadata: undefined, + }); + expect(adoption?.origin.operation).toBe('adopted'); + expect(adoption?.origin.metadata).toBeUndefined(); + const adoptedReceipt = writeSeedConstructionReceipt( + f.receiptPath, + f.intent, + f.frozen, + f.pgdata, + adoption?.origin, + ); + expect(adoptedReceipt.origin.kind).toBe('completed-publication'); + expect(adoptedReceipt).not.toHaveProperty('qualified'); + f.updateMetadata(adoptedReceipt); + expect(selectCompletedSeed(f.intent, f.control())?.origin.operation).toBe('reused'); + } finally { + rmSync(f.root, { recursive: true, force: true }); + } + }); + } +} + +test('completed seed reuse reads the declared archive alias and rejects a directory target', async () => { + const f = await fixture('wasix'); + try { + const captured = f.control(); + const sandbox = path.join(f.root, 'sandbox'); + mkdirSync(sandbox); + const alias = path.join(sandbox, path.basename(captured.archive.path)); + symlinkSync(captured.archive.path, alias, 'file'); + const control = { ...captured, archive: { ...captured.archive, path: alias } }; + const selected = selectCompletedSeed(f.intent, control); + expect(selected?.origin.operation).toBe('reused'); + expect(selected?.archive).toBe(alias); + expect(selected?.origin.archive).toEqual({ + size: captured.archive.size, + sha256: captured.archive.sha256, + }); + rmSync(alias); + symlinkSync(f.pgdata, alias, 'dir'); + expect(() => selectCompletedSeed(f.intent, control)).toThrow('regular file'); + } finally { + rmSync(f.root, { recursive: true, force: true }); + } +}); + +test('legacy and changed recipe proof constructs afresh; corrupt declared completion bytes fail closed', async () => { + const f = await fixture('native'); + try { + writeFileSync( + f.metadata, + JSON.stringify({ + source: { commit: publication.publicationSha, tree: publication.publicationTree }, + product: { id: publication.product, version: publication.version }, + construction: [{}], + }), + ); + expect(selectCompletedSeed(f.intent, f.control())).toBeUndefined(); + f.updateMetadata(); + const changed = structuredClone(f.intent); + changed.invocation = { ...f.invocation, arguments: ['--encoding=LATIN1'] }; + expect(selectCompletedSeed(changed, f.control())).toBeUndefined(); + const captured = f.control(); + writeFileSync(f.assets.archive, 'corrupt bytes'); + expect(() => selectCompletedSeed(f.intent, captured)).toThrow('input bytes differ'); + } finally { + rmSync(f.root, { recursive: true, force: true }); + } +}); + +test('fresh control/WAL entropy never proves the old seed came from an unchanged constructor', async () => { + const f = await fixture('wasix'); + try { + writeFileSync(path.join(f.pgdata, 'global/pg_control'), 'fresh control clock/PID/random'); + writeFileSync(path.join(f.pgdata, 'pg_wal/000000010000000000000001'), 'fresh WAL entropy'); + writeFileSync(f.frozen, await createDeterministicTar(f.pgdata)); + const fresh = writeSeedConstructionReceipt(f.receiptPath, f.intent, f.frozen, f.pgdata); + expect(fresh.intentSha256).toBe(f.receipt.intentSha256); + expect(fresh.pgdata.treeSha256).not.toBe(f.receipt.pgdata.treeSha256); + f.updateMetadata(fresh); + expect(() => selectCompletedSeed(f.intent, f.control())).toThrow('PGDATA differs'); + } finally { + rmSync(f.root, { recursive: true, force: true }); + } +}); + +test('deterministic random actual-input mutations always invalidate reuse and restore coherently', async () => { + const f = await fixture('native'); + try { + let random = 0x5eed; + const before = Object.fromEntries( + Object.entries(f.inputs).map(([name, file]) => [name, readFileSync(file)]), + ); + for (let scenario = 0; scenario < 64; scenario++) { + random = (Math.imul(random, 1664525) + 1013904223) >>> 0; + const selected = Object.keys(f.inputs).filter((_, index) => (random & (1 << index)) !== 0); + for (const name of selected) + writeFileSync(f.inputs[name], Buffer.concat([before[name], Buffer.from(` ${scenario}`)])); + const current = captureSeedConstructionIntent(f.intent, f.invocation, f.inputs); + expect(selectCompletedSeed(current, f.control()) !== undefined).toBe(selected.length === 0); + for (const name of selected) writeFileSync(f.inputs[name], before[name]); + expect( + selectCompletedSeed( + captureSeedConstructionIntent(f.intent, f.invocation, f.inputs), + f.control(), + )?.origin.operation, + ).toBe('reused'); + } + } finally { + rmSync(f.root, { recursive: true, force: true }); + } +}); + +test('source transport modes preserve intent; actual empty directories, command and environment belong to intent', async () => { + const f = await fixture('native'); + try { + const changedEnvironment = captureSeedConstructionIntent( + f.intent, + { ...f.invocation, environment: { TZ: 'Pacific/Honolulu' } }, + f.inputs, + ); + expect(selectCompletedSeed(changedEnvironment, f.control())).toBeUndefined(); + if (process.platform !== 'win32') { + chmodSync(f.inputs.tool, 0o444); + expect( + selectCompletedSeed( + captureSeedConstructionIntent(f.intent, f.invocation, f.inputs), + f.control(), + )?.origin.operation, + ).toBe('reused'); + chmodSync(f.inputs.tool, 0o755); + expect( + selectCompletedSeed( + captureSeedConstructionIntent(f.intent, f.invocation, f.inputs), + f.control(), + )?.origin.operation, + ).toBe('reused'); + } + const inputTree = path.join(f.root, 'input-tree'); + mkdirSync(path.join(inputTree, 'empty'), { recursive: true }); + writeFileSync(path.join(inputTree, 'tool.mts'), 'declared tool'); + const initial = captureSeedConstructionIntent(f.intent, f.invocation, { inputTree }); + rmSync(path.join(inputTree, 'empty'), { recursive: true }); + expect(captureSeedConstructionIntent(f.intent, f.invocation, { inputTree })).not.toEqual( + initial, + ); + expect(() => + captureSeedConstructionIntent(f.intent, f.invocation, { '../escape': inputTree }), + ).toThrow('safe logical name'); + const bad = structuredClone(f.receipt); + bad.intent.invocation = 'forged'; + expect(() => validateSeedConstructionReceipt(bad)).toThrow('intent digest differs'); + } finally { + rmSync(f.root, { recursive: true, force: true }); + } +}); + +test('transport locations do not hide any actual command, environment or input data', () => { + const invocation = (root: string) => + seedConstructionInvocation( + `${root}/runtime/bin/initdb`, + ['-D', `${root}/work/pgdata`, '--encoding=UTF8'], + { HOME: `${root}/work`, TZ: 'UTC' }, + { runtime: `${root}/runtime`, work: `${root}/work` }, + ); + expect(invocation('/first')).toEqual(invocation('/second')); + expect(invocation('/first').arguments).toContain('--encoding=UTF8'); + expect(invocation('/first').environment.TZ).toBe('UTC'); +}); + +test('version promotion keeps one frozen seed and original constructor while observing final runtime intent', async () => { + const f = await fixture('wasix'); + try { + writeFileSync(f.inputs.postgres, 'actual final versioned runtime bytes'); + const current = captureSeedConstructionIntent(f.intent, f.invocation, f.inputs); + expect(selectCompletedSeed(current, f.control())).toBeUndefined(); + const control = { + source: { commit: 'd'.repeat(40), tree: 'e'.repeat(40) }, + evidenceDigest: `sha256:${'f'.repeat(64)}`, + invocationId: 'original-qualified-invocation', + frozen: identity(f.frozen), + receipt: identity(f.receiptPath), + transition: { + source: { commit: '1'.repeat(40), tree: '2'.repeat(40) }, + updatesSha256: '3'.repeat(64), + }, + }; + const promotion = selectQualifiedSeed(current, control); + assert.ok(promotion); + const frozen = path.join(f.root, 'promoted.tar'); + copyFileSync(promotion.frozen, frozen); + const promotedReceipt = writePromotedSeedReceipt( + path.join(f.root, 'promoted.json'), + promotion, + frozen, + f.pgdata, + ); + expect(promotedReceipt.frozen).toEqual(f.receipt.frozen); + expect(promotedReceipt.pgdata).toEqual(f.receipt.pgdata); + expect(promotedReceipt.intentSha256).toBe(f.receipt.intentSha256); + expect(promotedReceipt.intent).toEqual(f.receipt.intent); + expect(promotedReceipt.qualificationIntent).toEqual(current); + expect(promotedReceipt.origin.kind).toBe('qualified-construction'); + expect(promotedReceipt).not.toHaveProperty('qualified'); + f.updateMetadata(promotedReceipt); + expect(selectCompletedSeed(current, f.control())?.origin.operation).toBe('reused'); + expect(selectCompletedSeed(f.intent, f.control())).toBeUndefined(); + expect(() => selectQualifiedSeed({ ...current, profile: 'icu' }, control)).toThrow( + 'cannot change seed slot', + ); + expect(() => + selectQualifiedSeed(current, { ...control, evidenceDigest: 'unverified' }), + ).toThrow('authenticated evidence digest'); + writeFileSync(f.frozen, 'changed frozen constructor bytes'); + expect(() => selectQualifiedSeed(current, control)).toThrow( + 'qualified seed input bytes differ', + ); + } finally { + rmSync(f.root, { recursive: true, force: true }); + } +}); + +test('WASIX guest recipe changes invalidate completed reuse and promotion while tool bytes stay provenance', async () => { + const f = await fixture('wasix'); + try { + const share = bootstrapFiles(f.root); + const recipe = parseWasixBootstrapRecipe( + JSON.stringify({ + schema: 'oliphaunt-wasix-bootstrap-recipe-v1', + profile: 'standard', + command: 'initdb', + workingDirectory: '/', + arguments: ['--encoding=UTF8'], + environment: [['TZ', 'UTC']], + }), + 'standard', + ); + expect( + parseWasixBootstrapRecipe(JSON.stringify({ ...recipe, profile: 'icu' }), 'icu').profile, + ).toBe('icu'); + const content = captureSeedContentIntent(f.intent, { recipe }, share); + const receipt = writeSeedConstructionReceipt( + f.receiptPath, + f.intent, + f.frozen, + f.pgdata, + undefined, + content, + ); + f.updateMetadata(receipt); + const promotion = { + source: { commit: 'd'.repeat(40), tree: 'e'.repeat(40) }, + evidenceDigest: `sha256:${'f'.repeat(64)}`, + invocationId: 'actual-original-qualification', + frozen: identity(f.frozen), + receipt: identity(f.receiptPath), + transition: { + source: { commit: '1'.repeat(40), tree: '2'.repeat(40) }, + updatesSha256: '3'.repeat(64), + }, + }; + writeFileSync(f.inputs.tool, '// changed tool comments\n'); + const current = captureSeedConstructionIntent(f.intent, f.invocation, f.inputs); + expect(current).not.toEqual(f.intent); + expect(selectCompletedSeed(current, f.control(), content)?.origin.operation).toBe('reused'); + expect(selectQualifiedSeed(current, promotion, content)?.receipt.intent).toEqual(f.intent); + for (const changed of [ + { ...recipe, arguments: ['--encoding=LATIN1'] }, + { ...recipe, environment: [['TZ', 'Pacific/Honolulu']] }, + { ...recipe, workingDirectory: '/base' }, + { ...recipe, command: 'different-initdb' }, + ]) { + const actual = parseWasixBootstrapRecipe(JSON.stringify(changed), 'standard'); + const changedContent = captureSeedContentIntent(f.intent, { recipe: actual }, share); + expect(changedContent).not.toEqual(content); + expect(selectCompletedSeed(current, f.control(), changedContent)).toBeUndefined(); + expect(() => selectQualifiedSeed(current, promotion, changedContent)).toThrow( + 'changed declared seed contents', + ); + } + for (const malformed of [ + null, + {}, + { ...recipe, schema: 'unrecognized' }, + { ...recipe, profile: 'icu' }, + { ...recipe, arguments: [null] }, + { ...recipe, workingDirectory: '../base' }, + { + ...recipe, + environment: [ + ['TZ', 'UTC'], + ['TZ', 'different'], + ], + }, + { ...recipe, environment: [['TZ']] }, + { ...recipe, extra: 'undeclared' }, + ]) + expect(() => parseWasixBootstrapRecipe(JSON.stringify(malformed), 'standard')).toThrow(); + expect(() => parseWasixBootstrapRecipe('{', 'standard')).toThrow(); + expect(() => parseWasixBootstrapRecipe(' '.repeat(64 * 1024 + 1), 'standard')).toThrow( + 'not bounded', + ); + } finally { + rmSync(f.root, { recursive: true, force: true }); + } +}); + +test('desired content binds actual bootstrap/ABI/invocation/ICU, independent of tool comments and version envelopes', async () => { + const f = await fixture('native'); + try { + const share = bootstrapFiles(f.root); + const invocation = { + arguments: ['--encoding=UTF8'], + abi: 'real catalog/control ABI', + contract: 'PG18', + }; + const content = () => captureSeedContentIntent(f.intent, invocation, share); + const original = content(); + writeFileSync(f.inputs.tool, '// constructor comment changed\n'); + writeFileSync(f.inputs.postgres, 'same valid runtime with different version envelope\n'); + expect(content()).toEqual(original); + expect(captureSeedConstructionIntent(f.intent, f.invocation, f.inputs)).not.toEqual(f.intent); + writeFileSync(path.join(share, 'postgres.bki'), 'actual changed desired catalog\n'); + expect(content()).not.toEqual(original); + expect( + captureSeedContentIntent(f.intent, { ...invocation, abi: 'changed ABI' }, share), + ).not.toEqual(content()); + expect( + captureSeedContentIntent( + f.intent, + { ...invocation, arguments: ['--encoding=LATIN1'] }, + share, + ), + ).not.toEqual(content()); + const icu = path.join(f.root, 'actual-icu'); + mkdirSync(icu); + writeFileSync(path.join(icu, 'data.dat'), 'ICU one'); + const icuContent = captureSeedContentIntent( + { ...f.intent, profile: 'icu' }, + invocation, + share, + icu, + ); + writeFileSync(path.join(icu, 'data.dat'), 'ICU two'); + expect( + captureSeedContentIntent({ ...f.intent, profile: 'icu' }, invocation, share, icu), + ).not.toEqual(icuContent); + writeFileSync( + path.join(share, 'extension/plpgsql.control'), + "default_version = '1.0'\ndefault_version = '2.0'\n", + ); + expect(() => content()).toThrow('one declared'); + } finally { + rmSync(f.root, { recursive: true, force: true }); + } +}); + +for (const family of ['native', 'wasix'] as const) { + test(`${family} fixed legacy adoption retains exact public data through comments/versions and changes only on desired input`, async () => { + const f = await fixture(family); + try { + const share = bootstrapFiles(f.root); + const content = captureSeedContentIntent( + f.intent, + { contract: 'actual desired contract' }, + share, + ); + const adoption = selectCompletedSeed( + f.intent, + { ...f.control(), operation: 'adopt', metadata: undefined }, + content, + ); + const receipt = writeSeedConstructionReceipt( + f.receiptPath, + f.intent, + f.frozen, + f.pgdata, + adoption?.origin, + content, + ); + const contents = readFileSync(f.receiptPath, 'utf8'); + const anchor = { + schema: SEED_CONSTRUCTION_ANCHOR_SCHEMA, + source: { commit: 'd'.repeat(40), tree: 'e'.repeat(40) }, + publication, + seeds: [ + { + family, + target: f.intent.target, + profile: f.intent.profile, + archive: identity(f.assets.archive), + manifest: identity(f.assets.manifest), + receipt: { ...identity(f.receiptPath), contents }, + producer: { + evidenceDigest: `sha256:${'f'.repeat(64)}`, + invocationId: 'original-PR-construction', + root: '//source:resource', + configuration: 'actual-root-config', + output: 'actual-resource.tar', + }, + }, + ], + }; + // Transport paths are not part of the immutable source contract. + for (const seed of anchor.seeds) + for (const field of ['archive', 'manifest', 'receipt']) delete seed[field].path; + const anchorPath = path.join(f.root, 'construction-anchor.json'); + writeFileSync(anchorPath, JSON.stringify(validateSeedConstructionAnchor(anchor))); + const control = { ...f.control(), metadata: undefined, anchor: identity(anchorPath) }; + writeFileSync(f.inputs.postgres, 'current valid version wrapper'); + writeFileSync(f.inputs.tool, '// current worker comments'); + const current = captureSeedConstructionIntent(f.intent, f.invocation, f.inputs); + const selected = selectCompletedSeed(current, control, content); + expect(selected?.origin.operation).toBe('reused'); + expect(selected?.origin.anchor.source).toEqual(anchor.source); + expect(selected?.origin).not.toHaveProperty('metadata'); + expect(selected?.archive).toBe(f.assets.archive); + const reusedReceipt = writeSeedConstructionReceipt( + f.receiptPath, + current, + f.frozen, + f.pgdata, + selected?.origin, + content, + ); + expect(reusedReceipt.pgdata).toEqual(receipt.pgdata); + f.updateMetadata(reusedReceipt); + expect(selectCompletedSeed(current, f.control(), content)?.origin.operation).toBe('reused'); + writeFileSync(path.join(share, 'postgres.bki'), 'genuinely changed catalog content'); + const changed = captureSeedContentIntent( + f.intent, + { contract: 'actual desired contract' }, + share, + ); + expect(selectCompletedSeed(current, control, changed)).toBeUndefined(); + expect(() => selectCompletedSeed(current, control)).toThrow('observed desired'); + expect(() => + selectCompletedSeed( + current, + { ...control, publication: { ...publication, publicationTree: '1'.repeat(40) } }, + content, + ), + ).toThrow('completed origin differs'); + const edited = structuredClone(anchor); + edited.seeds[0].receipt.contents += ' '; + expect(() => validateSeedConstructionAnchor(edited)).toThrow('receipt size differs'); + const fabricated = structuredClone(anchor); + const raw = JSON.parse(fabricated.seeds[0].receipt.contents); + raw.origin = { kind: 'constructed' }; + fabricated.seeds[0].receipt.contents = JSON.stringify(raw); + fabricated.seeds[0].receipt.size = Buffer.byteLength(fabricated.seeds[0].receipt.contents); + fabricated.seeds[0].receipt.sha256 = createHash('sha256') + .update(fabricated.seeds[0].receipt.contents) + .digest('hex'); + expect(() => validateSeedConstructionAnchor(fabricated)).toThrow('explicit adoption'); + } finally { + rmSync(f.root, { recursive: true, force: true }); + } + }); +} + +test('copied seed creator facts survive version promotion while WASIX consumer binds actual final bytes', async () => { + const root = mkdtempSync(path.join(tmpdir(), 'seed-producer-identity-')); + const contract = JSON.parse( + readFileSync( + new URL('../../src/database-resources/contracts/contract.json', import.meta.url), + 'utf8', + ), + ); + const publication = { + product: 'database-resources', + version: '0.2.2', + tagName: 'database-resources-v0.2.2', + publicationSha: 'a'.repeat(40), + publicationTree: 'b'.repeat(40), + releaseSha: 'c'.repeat(40), + }; + const id = (file: string) => { + return identity(file); + }; + try { + for (const family of ['native', 'wasix'] as const) { + const base = path.join(root, family); + const pgdata = path.join(base, 'pgdata'); + for (const dir of contract.pgdataDirectories) + mkdirSync(path.join(pgdata, dir), { recursive: true }); + writeFileSync(path.join(pgdata, 'PG_VERSION'), '18\n'); + writeFileSync(path.join(pgdata, 'global/pg_control'), 'opaque original control'); + writeFileSync(path.join(pgdata, 'pg_wal/000000010000000000000001'), 'opaque original WAL'); + const runtime = path.join(base, 'runtime'); + mkdirSync(path.join(runtime, 'bin'), { recursive: true }); + writeFileSync(path.join(runtime, 'bin/postgres'), 'original actual postgres bytes'); + writeFileSync(path.join(runtime, 'bin/initdb'), 'original actual initdb bytes'); + const target = family === 'native' ? 'linux-x64-gnu' : 'portable'; + const slot = { family, target, profile: 'standard' as const }; + const originalProducer = captureSeedProducerIdentity(runtime, target); + const bootstrap = path.join(base, 'bootstrap.sql'); + writeFileSync(bootstrap, 'declared same bootstrap content'); + const content = captureSeedConstructionIntent(slot, { contract }, { bootstrap }); + const frozen = path.join(base, 'frozen.tar'); + writeFileSync(frozen, await createDeterministicTar(pgdata)); + const assets = await packageClusterSeed({ + family, + target, + profile: 'standard', + pgdata, + runtime, + contract, + version: '0.2.2', + runtimeVersion: '0.3.2', + outputDir: path.join(base, 'public'), + }); + writeFileSync(path.join(runtime, 'bin/postgres'), 'preversion current actual postgres'); + writeFileSync(path.join(runtime, 'bin/initdb'), 'preversion current actual initdb'); + const beforeIntent = captureSeedConstructionIntent( + slot, + { contract, producer: captureSeedProducerIdentity(runtime, target) }, + { runtime }, + ); + const fresh = writeSeedConstructionReceipt( + path.join(base, 'fresh.seed-construction.json'), + beforeIntent, + frozen, + pgdata, + ); + expect(seedProducerIdentity(fresh)).toEqual(captureSeedProducerIdentity(runtime, target)); + expect( + seedProducerIdentity({ + ...fresh, + intent: { + ...fresh.intent, + invocation: { producer: { ...originalProducer, extra: 'never copied into source' } }, + }, + }), + ).toEqual(originalProducer); + const completed = selectCompletedSeed( + beforeIntent, + { + operation: 'adopt', + publication, + archive: id(assets.archive), + manifest: id(assets.manifest), + }, + content, + )!; + const receiptFile = path.join(base, 'adopted.seed-construction.json'); + const adopted = writeSeedConstructionReceipt( + receiptFile, + beforeIntent, + frozen, + pgdata, + completed.origin, + content, + completed.sourceManifest, + ); + expect(seedProducerIdentity(adopted)).toEqual(originalProducer); + expect(() => seedProducerIdentity({ ...adopted, sourceManifest: undefined })).toThrow( + 'original completed descriptor', + ); + expect(() => + validateSeedConstructionReceipt({ + ...adopted, + sourceManifest: { + ...adopted.sourceManifest, + contents: adopted.sourceManifest!.contents + ' ', + }, + }), + ).toThrow('descriptor bytes differ'); + writeFileSync(path.join(runtime, 'bin/postgres'), 'final compiled bumped runtime bytes'); + writeFileSync(path.join(runtime, 'bin/initdb'), 'final compiled bumped initdb bytes'); + const finalIntent = captureSeedConstructionIntent( + slot, + { contract, producer: captureSeedProducerIdentity(runtime, target) }, + { runtime }, + ); + const promotion = { + source: { commit: 'd'.repeat(40), tree: 'e'.repeat(40) }, + evidenceDigest: `sha256:${'f'.repeat(64)}`, + invocationId: 'original-qualified-construction', + frozen: id(frozen), + receipt: id(receiptFile), + transition: { + source: { commit: '1'.repeat(40), tree: '2'.repeat(40) }, + updatesSha256: '3'.repeat(64), + }, + }; + const selected = selectQualifiedSeed(finalIntent, promotion, content)!; + const promoted = writePromotedSeedReceipt( + path.join(base, 'promoted.seed-construction.json'), + selected, + frozen, + pgdata, + ); + expect(promoted.intent).toEqual(adopted.intent); + expect(promoted.sourceManifest).toEqual(adopted.sourceManifest); + expect(promoted.pgdata).toEqual(adopted.pgdata); + expect(seedProducerIdentity(promoted)).toEqual(originalProducer); + const final = await packageClusterSeed({ + family, + target, + profile: 'standard', + pgdata, + runtime, + contract, + version: '0.2.3', + runtimeVersion: '0.3.3', + outputDir: path.join(base, 'final'), + producer: seedProducerIdentity(promoted), + nativeSourceManifest: family === 'native' ? promoted.sourceManifest?.contents : undefined, + }); + const descriptor = JSON.parse(readFileSync(final.manifest, 'utf8')); + expect(descriptor.runtime.version).toBe( + family === 'native' + ? JSON.parse(promoted.sourceManifest?.contents ?? '{}').runtime?.version + : '0.3.3', + ); + if (family === 'native') + expect({ + postgresSha256: descriptor.source.postgresSha256, + initdbSha256: descriptor.source.initdbSha256, + }).toEqual(originalProducer); + else { + expect(descriptor.runtime.consumerSha256).toBe( + captureSeedProducerIdentity(runtime, target).postgresSha256, + ); + expect(descriptor.runtime.producerSha256).toBe(originalProducer.postgresSha256); + expect(descriptor.runtime.initdbSha256).toBe(originalProducer.initdbSha256); + expect(descriptor.runtime.consumerSha256).not.toBe(descriptor.runtime.producerSha256); + } + writeFileSync(bootstrap, 'changed desired bootstrap content'); + const changed = captureSeedConstructionIntent(slot, { contract }, { bootstrap }); + expect(() => selectQualifiedSeed(finalIntent, promotion, changed)).toThrow( + 'declared seed contents', + ); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test.skipIf(process.platform === 'win32')( + 'declared Bun module trees bind sandbox leaf links to exact logical members and source bytes', + () => { + const root = mkdtempSync(path.join(tmpdir(), 'seed-module-transport-')); + try { + const originals = path.join(root, 'declared'); + const output = path.join(root, 'producer-tree'); + const sandbox = path.join(root, 'sandbox-tree'); + for (const directory of [originals, output, sandbox]) + mkdirSync(path.join(directory, 'tools'), { recursive: true }); + const source = path.join(originals, 'tools/seed.mts'); + const copied = path.join(output, 'tools/seed.mts'); + const linked = path.join(sandbox, 'tools/seed.mts'); + writeFileSync(source, 'exact source-owned constructor bytes\n'); + copyFileSync(source, copied); + symlinkSync(copied, linked); // Ordinary sandbox absolute links leave the sandbox root. + const slot = { + family: 'native' as const, + profile: 'standard' as const, + target: 'linux-arm64-gnu', + }; + const inputs = (tree: string) => ({ 'tools/source': source, 'tools/copied': tree }); + const declared = { 'tools/copied': { 'tools/seed.mts': source } }; + const intent = () => + captureSeedConstructionIntent(slot, { command: 'initdb' }, inputs(sandbox), declared); + expect(intent()).toEqual( + captureSeedConstructionIntent(slot, { command: 'initdb' }, inputs(output), declared), + ); + expect(() => captureSeedConstructionIntent(slot, {}, inputs(sandbox))).toThrow( + 'actual Files: tools/copied/tools/seed.mts', + ); + writeFileSync(path.join(sandbox, 'extra.mts'), 'undeclared source'); + expect(intent).toThrow('undeclared member'); + rmSync(path.join(sandbox, 'extra.mts')); + rmSync(linked); + expect(intent).toThrow('missing a declared File'); + symlinkSync(copied, linked); + writeFileSync(copied, 'substituted producer output'); + expect(intent).toThrow('differs from its declared File'); + writeFileSync(copied, readFileSync(source)); + mkdirSync(path.join(sandbox, 'extra-directory')); + expect(intent).toThrow('undeclared directory'); + rmSync(path.join(sandbox, 'extra-directory'), { recursive: true }); + rmSync(path.join(sandbox, 'tools'), { recursive: true }); + symlinkSync(path.join(output, 'tools'), path.join(sandbox, 'tools'), 'dir'); + expect(intent).toThrow('undeclared member'); + expect(() => + captureSeedConstructionIntent(slot, {}, inputs(output), { + unknown: declared['tools/copied'], + }), + ).toThrow('declared input'); + expect(() => + captureSeedConstructionIntent(slot, {}, inputs(output), { + 'tools/copied': { '../escape': source }, + }), + ).toThrow('safe logical name'); + expect(() => + captureSeedConstructionIntent(slot, {}, inputs(output), { + 'tools/copied': { 'tools/seed.mts': copied }, + }), + ).toThrow('declared File'); + expect(() => + captureSeedConstructionIntent(slot, {}, inputs(output), { 'tools/copied': {} }), + ).toThrow('declared members'); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }, +); + +test.skipIf(process.platform === 'win32')( + 'Bazel expanded runtime leaves preserve constructor intent and reject missing, unknown and substituted Files', + () => { + const root = realpathSync(mkdtempSync(path.join(tmpdir(), 'seed-runtime-tree-'))); + try { + const producer = path.join(root, 'producer'); + const sandbox = path.join(root, 'sandbox'); + const members = ['bin/postgres', 'share/postgresql/postgres.bki']; + for (const member of members) { + for (const base of [producer, sandbox]) + mkdirSync(path.dirname(path.join(base, member)), { recursive: true }); + writeFileSync(path.join(producer, member), `declared runtime ${member}`); + symlinkSync(path.join(producer, member), path.join(sandbox, member)); + } + const logical = 'src/wasix/runtime/portable_payload_files'; + const inputs = (directory: string) => ({ [logical]: directory }); + const leaves = (directory: string) => members.map((member) => path.join(directory, member)); + const expanded = (directory: string, files = leaves(directory)) => + expandSeedConstructionTrees(inputs(directory), [directory], files); + const capture = (profile: 'standard' | 'icu', declared: ReturnType) => + captureSeedConstructionIntent( + { family: 'wasix', target: 'portable', profile }, + {}, + declared.inputs, + declared.treeMembers, + ); + const declared = expanded(sandbox); + expect(declared.inputs[`${logical}/bin/postgres`]).toBe(path.join(producer, 'bin/postgres')); + for (const profile of ['standard', 'icu'] as const) { + expect(capture(profile, declared)).toEqual(capture(profile, expanded(producer))); + expect(capture(profile, expanded(sandbox, leaves(sandbox).reverse()))).toEqual( + capture(profile, declared), + ); + } + expect(() => + captureSeedConstructionIntent( + { family: 'wasix', target: 'portable', profile: 'standard' }, + {}, + inputs(sandbox), + ), + ).toThrow('actual Files'); + expect(() => capture('standard', expanded(sandbox, leaves(sandbox).slice(0, 1)))).toThrow( + 'undeclared directory', + ); + expect(() => + expandSeedConstructionTrees( + inputs(sandbox), + [sandbox], + [...leaves(sandbox), leaves(sandbox)[0]], + ), + ).toThrow('more than once'); + expect(() => expanded(sandbox, leaves(producer))).toThrow('exact declared input root'); + expect(() => expanded(sandbox, [path.join(sandbox, 'share/postgresql')])).toThrow( + 'actual regular primary File', + ); + expect(() => + expandSeedConstructionTrees(inputs(sandbox), [producer], leaves(producer)), + ).toThrow('declared logical File'); + expect(() => expandSeedConstructionTrees(inputs(sandbox), [sandbox], [])).toThrow( + 'no declared leaf Files', + ); + expect(() => + expandSeedConstructionTrees(inputs(sandbox), [sandbox], leaves(sandbox), { + [logical]: { [members[0]]: path.join(producer, members[0]) }, + }), + ).toThrow('already has a declared member inventory'); + expect(() => + expandSeedConstructionTrees( + { ...inputs(sandbox), nested: path.join(sandbox, 'bin') }, + [sandbox, path.join(sandbox, 'bin')], + leaves(sandbox), + ), + ).toThrow('must not overlap'); + writeFileSync(path.join(sandbox, 'extra'), 'unlisted runtime'); + expect(() => capture('standard', declared)).toThrow('undeclared member'); + rmSync(path.join(sandbox, 'extra')); + const alias = path.join(sandbox, members[0]); + rmSync(alias); + expect(() => capture('standard', declared)).toThrow('missing a declared File'); + const wrong = path.join(root, 'wrong'); + writeFileSync(wrong, 'substituted runtime'); + symlinkSync(wrong, alias); + expect(() => capture('standard', declared)).toThrow('differs from its declared File'); + rmSync(path.join(sandbox, 'bin'), { recursive: true }); + symlinkSync(path.join(producer, 'bin'), path.join(sandbox, 'bin'), 'dir'); + expect(() => expanded(sandbox)).toThrow('aliased parent directory'); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }, +); diff --git a/build_defs/resources/seed_consumer.c b/build_defs/resources/seed_consumer.c new file mode 100644 index 000000000..f660c29b2 --- /dev/null +++ b/build_defs/resources/seed_consumer.c @@ -0,0 +1,100 @@ +#include "postgres_fe.h" +#include "catalog/catversion.h" +#include "catalog/pg_control.h" +#include "oliphaunt.h" +#include +#include +#include +#include + +static uint32_t read_u32(const uint8_t *data) { + return ((uint32_t)data[0] << 24) | ((uint32_t)data[1] << 16) | + ((uint32_t)data[2] << 8) | (uint32_t)data[3]; +} + +/* Test-only negative fixtures retain the canonical ControlFileData CRC. */ +static int corrupt_control_file(const char *path, int catalog) { + unsigned char bytes[PG_CONTROL_FILE_SIZE]; + ControlFileData control; + pg_crc32c crc; + FILE *file = fopen(path, "r+b"); + if (file == NULL) return 2; + if (fread(bytes, 1, sizeof(bytes), file) != sizeof(bytes) || + fgetc(file) != EOF || ferror(file)) { + fclose(file); + return 2; + } + memcpy(&control, bytes, sizeof(control)); + INIT_CRC32C(crc); + COMP_CRC32C(crc, bytes, offsetof(ControlFileData, crc)); + FIN_CRC32C(crc); + if (!EQ_CRC32C(crc, control.crc) || + control.pg_control_version != PG_CONTROL_VERSION || + control.catalog_version_no != CATALOG_VERSION_NO) { + fclose(file); + fputs("fixture requires an original compatible control file with a valid CRC32C\n", stderr); + return 2; + } + if (catalog) control.catalog_version_no ^= 1U; + else control.pg_control_version ^= 1U; + memcpy(bytes, &control, sizeof(control)); + INIT_CRC32C(crc); + COMP_CRC32C(crc, bytes, offsetof(ControlFileData, crc)); + FIN_CRC32C(crc); + memcpy(bytes + offsetof(ControlFileData, crc), &crc, sizeof(control.crc)); + if (fseek(file, 0, SEEK_SET) != 0 || + fwrite(bytes, 1, sizeof(bytes), file) != sizeof(bytes) || fflush(file) != 0) { + fclose(file); + return 2; + } + if (fclose(file) != 0) return 2; + printf("corrupted %s with valid CRC32C\n", catalog ? "CATALOG_VERSION_NO" : "PG_CONTROL_VERSION"); + return 0; +} + +int main(int argc, char **argv) { + if (argc == 2 && strcmp(argv[1], "--version") == 0) { + puts(oliphaunt_version()); + return 0; + } + if (argc == 3 && strcmp(argv[1], "--corrupt-control") == 0) + return corrupt_control_file(argv[2], 0); + if (argc == 3 && strcmp(argv[1], "--corrupt-catalog") == 0) + return corrupt_control_file(argv[2], 1); + if (argc != 5) return 2; + OliphauntConfig config = { + .abi_version = OLIPHAUNT_ABI_VERSION, .pgdata = argv[1], .runtime_dir = argv[2], + .username = "postgres", .database = "postgres", .icu_data_dir = getenv("ICU_DATA"), + }; + OliphauntHandle *database = NULL; + OliphauntErrorCapture error = {0}; + if (oliphaunt_init_with_error(&config, &database, &error) != 0 || database == NULL) { + fprintf(stderr, "seed open failed: %s\n", error.message); + return 1; + } + OliphauntResponse response = {0}; + int failed = oliphaunt_exec_simple_query_with_error(database, argv[3], strlen(argv[3]), &response, &error) != 0; + size_t expected = strlen(argv[4]); + int found = 0, complete = 0, ready = 0; + size_t cursor = 0; + while (!failed && cursor < response.len) { + if (response.len - cursor < 5) { failed = 1; break; } + const uint8_t *message = response.data + cursor; + uint32_t length = read_u32(message + 1); + if (length < 4 || (size_t)length + 1 > response.len - cursor) { failed = 1; break; } + if (message[0] == 'E') failed = 1; + if (message[0] == 'C') complete = 1; + if (message[0] == 'Z') ready = 1; + if (message[0] == 'D' && length >= 10 && message[5] == 0 && message[6] == 1) { + uint32_t value_length = read_u32(message + 7); + if ((size_t)value_length == expected && value_length == length - 10 && + memcmp(message + 11, argv[4], expected) == 0) found = 1; + } + cursor += (size_t)length + 1; + } + if (failed || !found || !complete || !ready) + fprintf(stderr, "seed query did not return expected PostgreSQL row: %s: %s\n", argv[3], error.message); + oliphaunt_free_response(&response); + if (oliphaunt_close(database) != 0) return 1; + return !failed && found && complete && ready ? 0 : 1; +} diff --git a/build_defs/resources/seed_domain.mts b/build_defs/resources/seed_domain.mts new file mode 100644 index 000000000..242f18b46 --- /dev/null +++ b/build_defs/resources/seed_domain.mts @@ -0,0 +1,269 @@ +import assert from 'node:assert/strict'; +import { + copyFileSync, + mkdirSync, + readFileSync, + realpathSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { + bindNativeClusterSeedManifest, + emptyDirectoryPaths, + filesystemTreeRows, + logicalTreeSha256, + parseProperties, + validateNativeClusterSeedDirectory, +} from '../../src/database-resources/contracts/native-manifest.mts'; +import { + compareNativeMobileAbiReceipts, + NATIVE_MOBILE_ABI_TARGETS_BY_DOMAIN, + parseNativeMobileAbiReceipt, +} from '../../src/native/runtime/tools/native-mobile-abi-contract.mts'; +import { createDeterministicTar } from '../../tools/packaging/archive-directory.mts'; +import { extractPortableArchiveTree } from '../../tools/packaging/portable-archive.mts'; +import { fileIdentity } from '../../tools/release/native-file-identity.mts'; +import { extractNativePayload } from '../native/host-runtime-test-helpers.mts'; +import { + captureSeedConstructionIntent, + seedConstructionFileBinding, + seedProducerIdentity, + selectCompletedSeed, + selectQualifiedSeed, + validateSeedConstructionReceipt, + writePromotedSeedReceipt, + writeSeedConstructionReceipt, +} from './seed_construction.mts'; +import { materializeArchive, privateWork, readSpecification } from './shared.mts'; + +/** Bind a physically unchanged host seed only after every real target ABI agrees. */ +export function bindSeedDomain({ seed, producerTarget, domain, profile, receipts, icuData }) { + const targets = NATIVE_MOBILE_ABI_TARGETS_BY_DOMAIN[domain]; + assert.ok(targets, 'the native seed domain must be declared'); + assert.equal(producerTarget, targets.at(-1), 'the declared domain uses its actual host producer'); + compareNativeMobileAbiReceipts(domain, receipts); + const producerReceipt = receipts.find( + ({ text, label }) => parseNativeMobileAbiReceipt(text, label).get('target') === producerTarget, + ); + assert.equal( + readFileSync(path.join(seed, 'abi.properties'), 'utf8'), + producerReceipt.text, + 'domain admission must consume the original bootstrap ABI receipt', + ); + validateNativeClusterSeedDirectory(seed, profile, { target: producerTarget, icuData }); + const pgdata = path.join(seed, 'files'); + const digest = logicalTreeSha256(filesystemTreeRows(pgdata)); + const emptyDirectories = emptyDirectoryPaths(pgdata); + const values = parseProperties( + readFileSync(path.join(seed, 'manifest.properties')), + 'native seed host manifest', + ); + values.delete('target'); + values.delete('compatibilityKey'); + const unbound = Buffer.from( + `${[...values].map(([key, value]) => `${key}=${value}`).join('\n')}\n`, + ); + writeFileSync( + path.join(seed, 'manifest.properties'), + bindNativeClusterSeedManifest(unbound, domain, profile), + ); + // Preserve exact genuine receipts for inspection; these do not modify PostgreSQL files. + const evidence = path.join(seed, 'abi-receipts'); + mkdirSync(evidence); + for (const { text, label } of receipts) { + const target = parseNativeMobileAbiReceipt(text, label).get('target'); + writeFileSync(path.join(evidence, `${target}.properties`), text); + } + validateNativeClusterSeedDirectory(seed, profile, { target: domain, icuData }); + assert.equal(logicalTreeSha256(filesystemTreeRows(pgdata)), digest); + assert.deepEqual(emptyDirectoryPaths(pgdata), emptyDirectories); +} + +/** A domain owns its immutable seed, while every real target still supplies its ABI. */ +export async function constructSeedDomain(specification) { + const work = privateWork(path.resolve(specification.output)); + try { + let icuData: string | undefined; + if (specification.icu) { + const icu = path.join(work, 'icu'); + extractPortableArchiveTree( + materializeArchive(specification.icu, path.join(work, 'inputs')), + icu, + ); + icuData = path.join(icu, 'share/icu'); + } + const receipts = specification.receipts.map((file) => ({ + text: readFileSync(file, 'utf8'), + label: file, + })); + compareNativeMobileAbiReceipts(specification.domain, receipts); + const producer = receipts.find( + ({ text, label }) => + parseNativeMobileAbiReceipt(text, label).get('target') === specification.producerTarget, + ); + assert.ok(producer, 'domain requires its actual host ABI receipt'); + const host = path.join(work, 'host'); + await extractNativePayload(specification.seed, host); + validateNativeClusterSeedDirectory(host, specification.profile, { + target: specification.producerTarget, + icuData, + }); + assert.equal(readFileSync(path.join(host, 'abi.properties'), 'utf8'), producer.text); + let producerReceipt; + if (specification.producerConstruction) { + const receipt = validateSeedConstructionReceipt( + JSON.parse(readFileSync(specification.producerConstruction, 'utf8')), + ); + assert.equal(receipt.intent.family, 'native'); + assert.equal(receipt.intent.target, specification.producerTarget); + assert.equal(receipt.intent.profile, specification.profile); + const frozen = fileIdentity(realpathSync(specification.seed)); + assert.deepEqual( + receipt.frozen, + { size: frozen.size, sha256: frozen.sha256 }, + 'domain host receipt must bind its genuine frozen TAR', + ); + producerReceipt = receipt; + } + assert.ok( + !specification.constructionInputs || producerReceipt, + 'domain intent requires its actual bound host constructor receipt', + ); + const intent = specification.constructionInputs + ? captureSeedConstructionIntent( + { family: 'native', target: specification.domain, profile: specification.profile }, + { + toolFlags: process.execArgv, + producerTarget: specification.producerTarget, + producer: seedProducerIdentity(producerReceipt), + contract: specification.contract, + bindings: { + seed: seedConstructionFileBinding( + specification.constructionInputs, + specification.seed, + ), + receipts: Object.fromEntries( + receipts.map(({ text, label }) => [ + parseNativeMobileAbiReceipt(text, label).get('target'), + seedConstructionFileBinding(specification.constructionInputs, label), + ]), + ), + icu: specification.icu + ? seedConstructionFileBinding(specification.constructionInputs, specification.icu) + : null, + }, + }, + specification.constructionInputs, + specification.constructionTreeMembers, + ) + : undefined; + const producerContent = + producerReceipt?.qualificationContentIntent ?? producerReceipt?.contentIntent; + assert.ok( + !intent || producerContent, + 'domain content must bind the actual producer content receipt', + ); + const contentIntent = intent + ? captureSeedConstructionIntent( + { family: 'native', target: specification.domain, profile: specification.profile }, + { contract: specification.contract, producerContent, producerAbi: producer.text }, + { + ...Object.fromEntries( + receipts.map(({ text, label }) => [ + `abi/${parseNativeMobileAbiReceipt(text, label).get('target')}`, + label, + ]), + ), + ...(icuData ? { 'icu/data': icuData } : {}), + }, + ) + : undefined; + assert.ok(!specification.reuse || intent, 'domain reuse requires declared constructor inputs'); + assert.ok( + !specification.promotion || intent, + 'domain promotion requires declared constructor inputs', + ); + assert.ok( + !(specification.reuse && specification.promotion), + 'domain has more than one physical origin', + ); + const promoted = intent + ? selectQualifiedSeed(intent, specification.promotion, contentIntent) + : undefined; + if (promoted) { + const seed = path.join(work, 'promoted'); + copyFileSync(promoted.frozen, specification.output); + await extractNativePayload(specification.output, seed); + validateNativeClusterSeedDirectory(seed, specification.profile, { + target: specification.domain, + icuData, + }); + assert.equal(readFileSync(path.join(seed, 'abi.properties'), 'utf8'), producer.text); + for (const { text, label } of receipts) { + const target = parseNativeMobileAbiReceipt(text, label).get('target'); + assert.equal( + readFileSync(path.join(seed, 'abi-receipts', `${target}.properties`), 'utf8'), + text, + ); + } + assert.ok(specification.constructionOutput, 'domain promotion requires its receipt output'); + writePromotedSeedReceipt( + specification.constructionOutput, + promoted, + specification.output, + path.join(seed, 'files'), + ); + } else { + const completed = intent + ? selectCompletedSeed(intent, specification.reuse, contentIntent) + : undefined; + let seed = host; + if (completed) { + seed = path.join(work, 'completed'); + const pgdata = path.join(seed, 'files'); + extractPortableArchiveTree( + materializeArchive(completed.archive, path.join(work, 'inputs')), + pgdata, + ); + // Reuse the current host envelope with the domain's exact public PGDATA. + // The admission action never invokes initdb or rewrites PostgreSQL files. + const manifest = parseProperties( + readFileSync(path.join(host, 'manifest.properties')), + 'domain host manifest', + ); + manifest.set('cacheKey', logicalTreeSha256(filesystemTreeRows(pgdata))); + writeFileSync( + path.join(seed, 'manifest.properties'), + `${[...manifest].map(([key, value]) => `${key}=${value}`).join('\n')}\n`, + ); + writeFileSync(path.join(seed, 'abi.properties'), producer.text); + } + bindSeedDomain({ + seed, + producerTarget: specification.producerTarget, + domain: specification.domain, + profile: specification.profile, + receipts, + icuData, + }); + writeFileSync(specification.output, await createDeterministicTar(seed)); + if (intent) { + assert.ok(specification.constructionOutput, 'domain intent requires its receipt output'); + writeSeedConstructionReceipt( + specification.constructionOutput, + intent, + specification.output, + path.join(seed, 'files'), + completed?.origin, + contentIntent, + completed?.sourceManifest, + ); + } + } + } finally { + rmSync(work, { recursive: true, force: true }); + } +} + +if (import.meta.main) await constructSeedDomain(readSpecification()); diff --git a/build_defs/resources/seed_domain.test.mts b/build_defs/resources/seed_domain.test.mts new file mode 100644 index 000000000..255098201 --- /dev/null +++ b/build_defs/resources/seed_domain.test.mts @@ -0,0 +1,228 @@ +import { expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + bindNativeClusterSeedManifest, + filesystemTreeRows, + logicalTreeSha256, +} from '../../src/database-resources/contracts/native-manifest.mts'; +import { packageClusterSeed } from '../../src/database-resources/seeds/package.mts'; +import { createDeterministicTar } from '../../tools/packaging/archive-directory.mts'; +import { + captureSeedConstructionIntent, + captureSeedProducerIdentity, + seedProducerIdentity, + writeSeedConstructionReceipt, +} from './seed_construction.mts'; +import { constructSeedDomain } from './seed_domain.mts'; + +const identity = (file: string) => ({ + path: file, + size: readFileSync(file).length, + sha256: createHash('sha256').update(readFileSync(file)).digest('hex'), +}); + +test('domain keeps its own public PGDATA, binds real ABI inputs, and promotes one exact frozen seed', async () => { + const root = mkdtempSync(path.join(tmpdir(), 'seed-domain-construction-')); + try { + const contract = JSON.parse( + readFileSync( + new URL('../../src/database-resources/contracts/contract.json', import.meta.url), + 'utf8', + ), + ); + const host = path.join(root, 'host'); + const pgdata = path.join(host, 'files'); + for (const directory of contract.pgdataDirectories) + mkdirSync(path.join(pgdata, directory), { recursive: true }); + writeFileSync(path.join(pgdata, 'PG_VERSION'), '18\n'); + writeFileSync(path.join(pgdata, 'global/pg_control'), 'opaque host nonce'); + writeFileSync(path.join(pgdata, 'pg_wal/000000010000000000000001'), 'opaque host WAL'); + const fields = { + schema: 'oliphaunt-native-mobile-abi-v1', + byteOrder: 'little', + datumBytes: '8', + maximumAlignof: '8', + float8ByVal: '1', + blockSize: '8192', + walBlockSize: '8192', + relationSegmentSize: '131072', + nameDataLength: '64', + indexMaxKeys: '32', + catalogVersion: '202506291', + pgControlVersion: '1800', + }; + const receipts = ['android-arm64-v8a', 'android-x86_64', 'linux-x64-gnu'].map((target) => { + const file = path.join(root, `${target}.properties`); + writeFileSync( + file, + `${Object.entries({ ...fields, target }) + .map(([key, value]) => `${key}=${value}`) + .join('\n')}\n`, + ); + return file; + }); + writeFileSync(path.join(host, 'abi.properties'), readFileSync(receipts[2])); + const values = { + schema: contract.manifests.native.schema, + layout: contract.manifests.native.layout, + artifactRole: contract.profiles.standard.artifactRole, + catalogProfile: 'standard', + postgresMajor: '18', + physicalFormat: contract.physicalFormats.native, + initialSuperuser: 'postgres', + icuDataVersion: '', + icuDataForm: '', + icuDataTreeSha256: '', + runtimeFeatures: contract.profiles.standard.requiredRuntimeFeatures.join(','), + cacheKey: logicalTreeSha256(filesystemTreeRows(pgdata)), + }; + writeFileSync( + path.join(host, 'manifest.properties'), + bindNativeClusterSeedManifest( + Buffer.from( + `${Object.entries(values) + .map(([key, value]) => `${key}=${value}`) + .join('\n')}\n`, + ), + 'linux-x64-gnu', + 'standard', + ), + ); + const frozen = path.join(root, 'host.tar'); + writeFileSync(frozen, await createDeterministicTar(host)); + const recipe = path.join(root, 'recipe.mts'); + writeFileSync(recipe, 'declared actual domain recipe fixture'); + const runtime = path.join(root, 'runtime'); + mkdirSync(path.join(runtime, 'bin'), { recursive: true }); + writeFileSync(path.join(runtime, 'bin/postgres'), 'formatter-only runtime'); + writeFileSync(path.join(runtime, 'bin/initdb'), 'formatter-only runtime'); + const producerConstruction = path.join(root, 'host.seed-construction.json'); + const producerIntent = captureSeedConstructionIntent( + { family: 'native', target: 'linux-x64-gnu', profile: 'standard' }, + { contract, producer: captureSeedProducerIdentity(runtime, 'linux-x64-gnu') }, + { + recipe, + postgres: path.join(runtime, 'bin/postgres'), + initdb: path.join(runtime, 'bin/initdb'), + }, + ); + writeSeedConstructionReceipt( + producerConstruction, + producerIntent, + frozen, + pgdata, + undefined, + producerIntent, + ); + const inputs = { + seed: frozen, + recipe, + ...Object.fromEntries(receipts.map((file, index) => [`abi-${index}`, file])), + }; + const spec = { + seed: frozen, + producerConstruction, + producerTarget: 'linux-x64-gnu', + domain: 'android-datum64', + profile: 'standard', + receipts, + icu: null, + contract, + constructionInputs: inputs, + output: path.join(root, 'constructed.tar'), + constructionOutput: path.join(root, 'constructed.seed-construction.json'), + }; + await constructSeedDomain(spec); + const constructed = JSON.parse(readFileSync(spec.constructionOutput, 'utf8')); + expect(constructed.intent.target).toBe('android-datum64'); + expect(constructed.origin.kind).toBe('constructed'); + expect(seedProducerIdentity(constructed)).toEqual( + captureSeedProducerIdentity(runtime, 'linux-x64-gnu'), + ); + const publicPgdata = path.join(root, 'public-pgdata'); + mkdirSync(publicPgdata); + // Formatter fixtures isolate immutable-data selection; actual installed tests qualify execution. + for (const directory of contract.pgdataDirectories) + mkdirSync(path.join(publicPgdata, directory), { recursive: true }); + writeFileSync(path.join(publicPgdata, 'PG_VERSION'), '18\n'); + writeFileSync( + path.join(publicPgdata, 'global/pg_control'), + 'different authentic-domain nonce fixture', + ); + writeFileSync( + path.join(publicPgdata, 'pg_wal/000000010000000000000001'), + 'different domain WAL fixture', + ); + + const assets = await packageClusterSeed({ + family: 'native', + target: 'android-datum64', + profile: 'standard', + pgdata: publicPgdata, + runtime, + contract, + version: '0.2.2', + runtimeVersion: '0.3.2', + outputDir: path.join(root, 'assets'), + }); + const reuse = { + operation: 'adopt', + publication: { + product: 'database-resources', + version: '0.2.2', + tagName: 'database-resources-v0.2.2', + publicationSha: 'a'.repeat(40), + publicationTree: 'b'.repeat(40), + releaseSha: 'c'.repeat(40), + }, + archive: identity(assets.archive), + manifest: identity(assets.manifest), + }; + const adoptedSpec = { + ...spec, + reuse, + output: path.join(root, 'adopted.tar'), + constructionOutput: path.join(root, 'adopted.seed-construction.json'), + }; + await constructSeedDomain(adoptedSpec); + const adopted = JSON.parse(readFileSync(adoptedSpec.constructionOutput, 'utf8')); + expect(adopted.origin.operation).toBe('adopted'); + expect(adopted.pgdata.treeSha256).toBe(logicalTreeSha256(filesystemTreeRows(publicPgdata))); + expect(adopted.pgdata.treeSha256).not.toBe(constructed.pgdata.treeSha256); + const promotion = { + source: { commit: 'd'.repeat(40), tree: 'e'.repeat(40) }, + evidenceDigest: `sha256:${'f'.repeat(64)}`, + invocationId: 'original-diagnostic-construction', + frozen: identity(adoptedSpec.output), + receipt: identity(adoptedSpec.constructionOutput), + transition: { + source: { commit: '1'.repeat(40), tree: '2'.repeat(40) }, + updatesSha256: '3'.repeat(64), + }, + }; + writeFileSync(recipe, 'changed qualification recipe fixture'); + const promotedSpec = { + ...spec, + promotion, + output: path.join(root, 'promoted.tar'), + constructionOutput: path.join(root, 'promoted.seed-construction.json'), + }; + await constructSeedDomain(promotedSpec); + const promoted = JSON.parse(readFileSync(promotedSpec.constructionOutput, 'utf8')); + expect(identity(promotedSpec.output).sha256).toBe(identity(adoptedSpec.output).sha256); + expect(promoted.intent).toEqual(adopted.intent); + expect(promoted.qualificationIntent).not.toEqual(adopted.intent); + writeFileSync( + receipts[0], + readFileSync(receipts[0], 'utf8').replace('maximumAlignof=8', 'maximumAlignof=16'), + ); + const rejected = { ...spec, reuse, output: path.join(root, 'rejected.tar') }; + await expect(constructSeedDomain(rejected)).rejects.toThrow('ABI mismatch'); + expect(existsSync(rejected.output)).toBe(false); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/build_defs/resources/shared.mts b/build_defs/resources/shared.mts new file mode 100644 index 000000000..ea8825336 --- /dev/null +++ b/build_defs/resources/shared.mts @@ -0,0 +1,106 @@ +import assert from 'node:assert/strict'; +import { copyFileSync, mkdirSync, mkdtempSync, readFileSync } from 'node:fs'; +import path from 'node:path'; +import { hostRuntimeEnvironment } from '../native/host-runtime-test-helpers.mts'; + +/** Match the concrete executor to the canonical native runtime artifact. */ +export function nativeSeedHost( + artifact: { target: string; npm_os: string; npm_cpu: string; library_relative_path: string }, + platform: NodeJS.Platform = process.platform, + architecture: string = process.arch, +) { + assert(['linux', 'darwin', 'win32'].includes(platform), 'unsupported native seed executor'); + assert.equal(artifact.npm_os, platform, 'seed runtime must match the executor OS'); + assert.equal(artifact.npm_cpu, architecture, 'seed runtime must match the executor CPU'); + assert( + /^(?:bin|lib)\/[A-Za-z0-9_.-]+$/u.test(artifact.library_relative_path), + 'native seed requires the canonical desktop runtime library path', + ); + return { + target: artifact.target, + executableSuffix: platform === 'win32' ? '.exe' : '', + memoryType: platform === 'win32' ? 'windows' : 'mmap', + libraryRelativePath: artifact.library_relative_path, + }; +} + +export function readSpecification(extraArguments = 0) { + assert.equal( + process.argv.length, + 3 + extraArguments, + extraArguments + ? 'expected declared action arguments' + : 'expected one declared action specification', + ); + return JSON.parse(readFileSync(process.argv[2], 'utf8')); +} + +export function privateWork(output: string): string { + mkdirSync(path.dirname(output), { recursive: true }); + return mkdtempSync(path.join(path.dirname(output), '.resource-')); +} + +export function materializeInputs(inputs: Record, root: string): string { + for (const [relative, source] of Object.entries(inputs)) { + assert( + relative && + !path.isAbsolute(relative) && + !relative.split('/').some((part) => ['', '.', '..'].includes(part)), + 'unsafe declared resource input path', + ); + const destination = path.join(root, relative); + mkdirSync(path.dirname(destination), { recursive: true }); + copyFileSync(source, destination); + } + return root; +} + +export function materializeArchive(source: string, root: string): string { + const name = path.basename(source); + materializeInputs({ [name]: source }, root); + return path.join(root, name); +} + +export function seedEnvironment( + runtime: string, + root: string, + icuData?: string, + platform: NodeJS.Platform = process.platform, + source: NodeJS.ProcessEnv = process.env, +): NodeJS.ProcessEnv { + // Keep only the Windows OS loader root; ambient build/locale variables must + // not affect a distributed cluster's bootstrap or satisfy a missing carrier. + const systemRoot = Object.entries(source).find(([key]) => key.toLowerCase() === 'systemroot'); + const osEnvironment = platform === 'win32' && systemRoot ? { SystemRoot: systemRoot[1] } : {}; + const env = hostRuntimeEnvironment(runtime, root, platform, osEnvironment); + delete env.ICU_DATA; + return { + ...env, + HOME: root, + TEMP: root, + TMP: root, + LANG: 'C', + LC_ALL: 'C', + TZ: 'UTC', + PGTZ: 'UTC', + PGSERVICEFILE: path.join(root, 'no-service'), + PGPASSFILE: path.join(root, 'no-password'), + OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY: '1', + ...(icuData === undefined + ? { OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY: '1' } + : { + ICU_DATA: icuData, + OLIPHAUNT_INTERNAL_ICU_READY: '1', + }), + }; +} + +export function run(binary: string, args: string[], env: NodeJS.ProcessEnv, cwd: string): string { + const result = Bun.spawnSync([binary, ...args], { env, cwd, stdout: 'pipe', stderr: 'pipe' }); + assert.equal( + result.exitCode, + 0, + `${binary}: ${result.stderr.toString()}\n${result.stdout.toString()}`, + ); + return result.stdout.toString(); +} diff --git a/build_defs/resources/wasix_inputs.mts b/build_defs/resources/wasix_inputs.mts new file mode 100644 index 000000000..8b31a631e --- /dev/null +++ b/build_defs/resources/wasix_inputs.mts @@ -0,0 +1,102 @@ +import assert from 'node:assert/strict'; +import { mkdirSync, readFileSync, realpathSync, statSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { WASIX_PORTABLE_RELEASE_MEMBERS } from '../../src/wasix/runtime/tools/wasix-runtime-npm-contract.mts'; +import { wasixRuntimeNpmPayloadInputs } from '../../src/wasix/runtime/tools/wasix-runtime-npm-payload.mts'; +import { + extractPortableArchiveTree, + readPortableArchiveEntries, +} from '../../tools/packaging/portable-archive.mts'; +import { materializeArchive } from './shared.mts'; + +export type WasixBootstrapRecipe = { + schema: 'oliphaunt-wasix-bootstrap-recipe-v1'; + profile: 'standard' | 'icu'; + command: string; + workingDirectory: string; + arguments: string[]; + environment: [string, string][]; +}; + +/** The declared runner describes the same guest recipe it actually executes. */ +export function parseWasixBootstrapRecipe(text: string, profile: 'standard' | 'icu') { + assert.ok(Buffer.byteLength(text) <= 64 * 1024, 'WASIX bootstrap recipe is not bounded'); + const recipe = JSON.parse(text); + assert.ok( + recipe && typeof recipe === 'object' && !Array.isArray(recipe), + 'invalid WASIX bootstrap recipe', + ); + assert.deepEqual( + Object.keys(recipe).sort(), + ['schema', 'profile', 'command', 'workingDirectory', 'arguments', 'environment'].sort(), + 'WASIX bootstrap recipe fields differ', + ); + assert.equal( + recipe.schema, + 'oliphaunt-wasix-bootstrap-recipe-v1', + 'unsupported WASIX bootstrap recipe', + ); + assert.equal(recipe.profile, profile, 'WASIX bootstrap recipe profile differs'); + const string = (value: unknown): value is string => + typeof value === 'string' && !/[\u0000-\u001f\u007f]/u.test(value); + assert.ok(string(recipe.command) && recipe.command, 'WASIX bootstrap recipe needs its command'); + assert.ok( + string(recipe.workingDirectory) && + recipe.workingDirectory.startsWith('/') && + !recipe.workingDirectory.split('/').some((part: string) => part === '.' || part === '..'), + 'WASIX bootstrap recipe needs its guest working directory', + ); + assert.ok( + Array.isArray(recipe.arguments) && recipe.arguments.length && recipe.arguments.every(string), + 'invalid WASIX bootstrap arguments', + ); + assert.ok( + Array.isArray(recipe.environment) && recipe.environment.length, + 'invalid WASIX bootstrap environment', + ); + const names = new Set(); + for (const row of recipe.environment) { + assert.ok( + Array.isArray(row) && + row.length === 2 && + string(row[0]) && + /^[A-Za-z_][A-Za-z_0-9]*$/u.test(row[0]) && + string(row[1]), + 'invalid WASIX bootstrap environment entry', + ); + assert.ok(!names.has(row[0]), 'duplicate WASIX bootstrap environment entry'); + names.add(row[0]); + } + return recipe as WasixBootstrapRecipe; +} + +/** Project the actual completed archive; current payload directories remain unchanged. */ +export function wasixRuntimeInputs(source: string, work: string): string { + if (!statSync(source).isFile()) return source; + const entries = readPortableArchiveEntries(realpathSync(source)); + const output = path.join(work, 'admitted-runtime'); + mkdirSync(output, { recursive: true }); + for (const [name, member] of Object.entries(WASIX_PORTABLE_RELEASE_MEMBERS)) { + const file = entries.get(member); + assert.ok(file?.isFile, `admitted WASIX runtime needs regular ${member}`); + writeFileSync( + path.join(output, name === 'manifest' ? 'manifest.json' : 'oliphaunt.wasix.tar.zst'), + file.data(), + ); + } + return output; +} + +/** Consume the existing canonical core archive/manifest, never walk its tree aliases. */ +export function extractWasixRuntime(source: string, work: string): string { + source = wasixRuntimeInputs(source, work); + const archive = path.join(source, 'oliphaunt.wasix.tar.zst'); + wasixRuntimeNpmPayloadInputs({ + manifestBytes: readFileSync(path.join(source, 'manifest.json')), + runtimeBytes: readFileSync(archive), + label: 'declared WASIX seed runtime', + }); + const destination = path.join(work, 'runtime'); + extractPortableArchiveTree(materializeArchive(archive, path.join(work, 'inputs')), destination); + return path.join(destination, 'oliphaunt'); +} diff --git a/build_defs/resources/wasix_resource.test.mts b/build_defs/resources/wasix_resource.test.mts new file mode 100644 index 000000000..565c62aec --- /dev/null +++ b/build_defs/resources/wasix_resource.test.mts @@ -0,0 +1,249 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + emptyDirectoryPaths, + filesystemTreeRows, + logicalTreeSha256, + validatePgdataDirectories, +} from '../../src/database-resources/contracts/native-manifest.mts'; +import { + renderWasixRuntimeDescriptorModule, + wasixRuntimeNpmPayloadInputs, +} from '../../src/wasix/runtime/tools/wasix-runtime-npm-payload.mts'; +import { + extractPortableArchiveTree, + readPortableArchiveEntries, +} from '../../tools/packaging/portable-archive.mts'; +import { extractNativePayload } from '../native/host-runtime-test-helpers.mts'; +import { materializeArchive, materializeInputs } from './shared.mts'; +import { extractWasixRuntime, wasixRuntimeInputs } from './wasix_inputs.mts'; +import { seedProducerIdentity, validateSeedConstructionReceipt } from './seed_construction.mts'; + +const [unitTest, runner, portable, icu, version, runtimeVersion, ...files] = process.argv.slice(2); +assert.equal(files.length, 24); +const identityJson = files.pop(); +assert.ok(identityJson); +const identities = JSON.parse(identityJson); +const seedFiles = files.splice(0, 12); +const fzstd = files.shift(); +assert.ok(fzstd); +const sdkSources: Record = {}; +for (let index = 0; index < files.length; index += 2) sdkSources[files[index]] = files[index + 1]; +const root = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'wasix-resource-')); +const digest = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +const copyArchive = (source: string) => + materializeArchive(source, mkdtempSync(path.join(root, 'archive-'))); +const member = (entries: ReturnType, name: string) => { + const entry = entries.get(name); + assert.ok(entry?.isFile, `carrier must contain regular ${name}`); + return entry.data(); +}; +const environment = { LC_ALL: 'C', LANG: 'C', TZ: 'UTC', RAYON_NUM_THREADS: '2' }; +const invoke = (args: string[]) => + Bun.spawnSync([runner, ...args], { cwd: root, env: environment, stdout: 'pipe', stderr: 'pipe' }); +try { + const units = Bun.spawnSync([unitTest], { + cwd: root, + env: { ...environment, TEST_TMPDIR: root }, + stdout: 'pipe', + stderr: 'pipe', + }); + assert.equal(units.exitCode, 0, `${units.stderr.toString()}\n${units.stdout.toString()}`); + console.log(units.stdout.toString()); + const admitted = wasixRuntimeInputs(portable, root); + const runtime = extractWasixRuntime(admitted, root); + const icuRoot = path.join(root, 'icu-resource'); + extractPortableArchiveTree(copyArchive(icu), icuRoot); + const icuData = path.join(icuRoot, 'share/icu'); + // This exercises the real SDK metadata consumer from its declared source + // closure. The independent Rust verifier below executes PostgreSQL. + const sdk = materializeInputs(sdkSources, path.join(root, 'sdk')); + extractPortableArchiveTree(copyArchive(fzstd), path.join(sdk, 'node_modules/.fzstd')); + renameSync(path.join(sdk, 'node_modules/.fzstd/package'), path.join(sdk, 'node_modules/fzstd')); + const runtimeBytes = readFileSync(path.join(admitted, 'oliphaunt.wasix.tar.zst')); + const coreBytes = readFileSync(path.join(admitted, 'manifest.json')); + const coreInputs = wasixRuntimeNpmPayloadInputs({ + manifestBytes: coreBytes, + runtimeBytes, + label: 'resource SDK consumer', + }); + const runtimePackage = path.join(sdk, 'node_modules/@oliphaunt/liboliphaunt-wasix'); + mkdirSync(runtimePackage, { recursive: true }); + writeFileSync( + path.join(runtimePackage, 'index.mjs'), + renderWasixRuntimeDescriptorModule({ version: runtimeVersion, ...coreInputs }), + ); + // This private fixture declares only module resolution; the descriptor's + // actual identity and implementation come from the canonical formatter. + writeFileSync( + path.join(runtimePackage, 'package.json'), + JSON.stringify({ type: 'module', exports: './index.mjs' }), + ); + const { prepareWasixRuntime } = await import(path.join(sdk, 'resources/extensions.ts')); + const { descriptor } = await import(path.join(runtimePackage, 'index.mjs')); + const runtimeDescriptor = { + ...descriptor, + runtimeArchive: { ...descriptor.runtimeArchive, source: runtimeBytes }, + manifest: { ...descriptor.manifest, source: coreBytes }, + }; + const optionsFor = (profile: string, archive: Buffer, manifest: Buffer) => ({ + runtime: runtimeDescriptor, + extensions: [], + extensionCarriers: {}, + startupGUCs: {}, + seed: { archive, manifest }, + ...(profile === 'icu' + ? { + icu: { + data: readFileSync(path.join(icuData, 'icudt76l.dat')), + manifest: readFileSync(path.join(icuRoot, 'manifest.properties')), + }, + } + : {}), + }); + const load = async (options: ReturnType) => { + const prepared = await prepareWasixRuntime(options); + assert.ok(prepared.loadClusterSeed); + return prepared.loadClusterSeed(); + }; + for (const [index, profile] of ['standard', 'icu'].entries()) { + const [frozen, archive, manifestPath, npm, cargo, construction] = seedFiles.slice( + index * 6, + index * 6 + 6, + ); + const receipt = validateSeedConstructionReceipt(JSON.parse(readFileSync(construction, 'utf8'))); + const producer = seedProducerIdentity(receipt); + assert.deepEqual(receipt.frozen, { + size: readFileSync(frozen).length, + sha256: digest(readFileSync(frozen)), + }); + const seed = path.join(root, profile); + extractPortableArchiveTree(copyArchive(archive), seed); + validatePgdataDirectories(seed); + const original = path.join(root, `${profile}-frozen`); + await extractNativePayload(frozen, original); + const before = logicalTreeSha256(filesystemTreeRows(original)); + assert.equal(logicalTreeSha256(filesystemTreeRows(seed)), before); + assert.deepEqual(emptyDirectoryPaths(seed), emptyDirectoryPaths(original)); + const manifestBytes = readFileSync(manifestPath); + const manifest = JSON.parse(manifestBytes.toString('utf8')); + assert.equal(manifest.runtime.version, runtimeVersion); + assert.equal(manifest.runtime.engineFamily, 'wasix'); + assert.equal( + manifest.runtime.consumerSha256, + digest(readFileSync(path.join(runtime, 'bin/postgres'))), + ); + assert.equal(manifest.runtime.producerSha256, producer.postgresSha256); + assert.equal(manifest.runtime.initdbSha256, producer.initdbSha256); + assert.equal(manifest.archive.sha256, digest(readFileSync(archive))); + assert.equal(manifest.catalogProfile, profile); + const options = optionsFor(profile, readFileSync(archive), manifestBytes); + const mount = await load(options); + assert.equal(Buffer.from(mount.files.PG_VERSION).toString('utf8').trim(), '18'); + assert.equal( + digest(mount.files['global/pg_control']), + digest(readFileSync(path.join(seed, 'global/pg_control'))), + ); + for (const [field, value] of [ + ['version', '999.0.0'], + ['consumerSha256', '0'.repeat(64)], + ['physicalFormat', 'native-pg18-v1'], + ['compatibilityKey', 'native-pg18-linux-x64-gnu-v1'], + ]) { + const changed = structuredClone(manifest); + changed.runtime[field] = value; + await assert.rejects( + load({ + ...options, + seed: { ...options.seed, manifest: Buffer.from(JSON.stringify(changed)) }, + }), + ); + } + await assert.rejects( + load({ ...options, seed: { ...options.seed, archive: Buffer.from('changed seed archive') } }), + ); + if (profile === 'icu') { + const changed = structuredClone(manifest); + changed.icu.dataTreeSha256 = '0'.repeat(64); + await assert.rejects( + load({ + ...options, + seed: { ...options.seed, manifest: Buffer.from(JSON.stringify(changed)) }, + }), + ); + } + const identity = identities.find((row) => row.profile === profile); + const npmEntries = readPortableArchiveEntries(copyArchive(npm)); + const npmManifest = JSON.parse(member(npmEntries, 'package/package.json').toString('utf8')); + assert.equal(npmManifest.name, identity.npm); + assert.equal(npmManifest.version, version); + assert.equal(member(npmEntries, 'package/seed.tar.zst').equals(readFileSync(archive)), true); + assert.equal(member(npmEntries, 'package/manifest.json').equals(manifestBytes), true); + const cargoEntries = readPortableArchiveEntries(copyArchive(cargo)); + const cratePrefix = `${identity.cargo}-${version}`; + const cargoManifest = Bun.TOML.parse( + member(cargoEntries, `${cratePrefix}/Cargo.toml`).toString('utf8'), + ); + assert.equal(cargoManifest.package.name, identity.cargo); + assert.equal(cargoManifest.package.version, version); + assert.equal( + member(cargoEntries, `${cratePrefix}/seed.tar.zst`).equals(readFileSync(archive)), + true, + ); + assert.equal(member(cargoEntries, `${cratePrefix}/manifest.json`).equals(manifestBytes), true); + if (profile === 'icu') { + assert.equal(npmManifest.dependencies['@oliphaunt/icu'], version); + assert.equal(cargoManifest.dependencies['oliphaunt-icu'], `=${version}`); + } else { + assert.equal(npmManifest.dependencies, undefined); + assert.equal(cargoManifest.dependencies, undefined); + } + // Independent CLI mode opens the packaged archive on a private copy, checks + // both profile probes, writes rows, and reads them from a later PG process. + const result = invoke([ + 'verify', + runtime, + path.join(root, `${profile}-consumer`), + profile, + seed, + ...(profile === 'icu' ? [icuData] : []), + ]); + assert.equal(result.exitCode, 0, `${result.stderr.toString()}\n${result.stdout.toString()}`); + assert.equal(logicalTreeSha256(filesystemTreeRows(original)), before); + assert.equal(logicalTreeSha256(filesystemTreeRows(seed)), before); + if (profile === 'icu') { + const missing = invoke(['verify', runtime, path.join(root, 'missing-icu'), profile, seed]); + assert.notEqual(missing.exitCode, 0, 'ICU PGDATA consumer must reject absent ICU resource'); + } + const broken = path.join(root, `${profile}-broken`); + extractPortableArchiveTree(copyArchive(archive), broken); + rmSync(path.join(broken, 'global/pg_control')); + const rejected = invoke([ + 'verify', + runtime, + path.join(root, `${profile}-rejected`), + profile, + broken, + ...(profile === 'icu' ? [icuData] : []), + ]); + assert.notEqual(rejected.exitCode, 0, 'consumer must reject missing pg_control'); + } + // Core admission must fail before constructing any seed if declared module + // or archive bytes disagree with their canonical runtime manifest. + const wrong = path.join(root, 'wrong-runtime'); + mkdirSync(wrong); + writeFileSync( + path.join(wrong, 'manifest.json'), + readFileSync(path.join(admitted, 'manifest.json')), + ); + writeFileSync(path.join(wrong, 'oliphaunt.wasix.tar.zst'), 'altered actual archive'); + assert.throws(() => extractWasixRuntime(wrong, path.join(root, 'wrong-input')), /sha256|archive/); + console.log( + 'WASIX standard/ICU archive +npm/Cargo exact bytes, actual profile/reopen/persistence, missing resource/control and runtime digest rejection passed', + ); +} finally { + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/resources/wasix_sdk_resource.test.mts b/build_defs/resources/wasix_sdk_resource.test.mts new file mode 100644 index 000000000..3d255fb8e --- /dev/null +++ b/build_defs/resources/wasix_sdk_resource.test.mts @@ -0,0 +1,64 @@ +import assert from 'node:assert/strict'; +import { mkdtempSync, readFileSync, realpathSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { packageClusterSeed } from '../../src/database-resources/seeds/package.mts'; +import { fileIdentity } from '../../tools/release/native-file-identity.mts'; +import { extractPortableArchiveTree } from '../../tools/packaging/portable-archive.mts'; +import { extractNativePayload } from '../native/host-runtime-test-helpers.mts'; +import { materializeArchive } from './shared.mts'; +import { seedProducerIdentity, validateSeedConstructionReceipt } from './seed_construction.mts'; +import { extractWasixRuntime } from './wasix_inputs.mts'; + +const [sdkTest, portable, icu, version, runtimeVersion, ...seeds] = process.argv.slice(2); +assert.equal(seeds.length, 4); +const root = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'wasix-sdk-seeds-')); +try { + const runtime = extractWasixRuntime(portable, root); + const icuRoot = path.join(root, 'icu-data'); + extractPortableArchiveTree(materializeArchive(icu, path.join(root, 'inputs')), icuRoot); + const outputs: string[] = []; + for (const [index, profile] of ['standard', 'icu'].entries()) { + const [frozen, receiptFile] = seeds.slice(index * 2, index * 2 + 2); + const receipt = validateSeedConstructionReceipt(JSON.parse(readFileSync(receiptFile, 'utf8'))); + const frozenFile = fileIdentity(realpathSync(frozen)); + assert.deepEqual(receipt.frozen, { size: frozenFile.size, sha256: frozenFile.sha256 }); + const pgdata = path.join(root, profile); + await extractNativePayload(frozen, pgdata); + // This private compatibility overlay belongs to the SDK test; it never replaces a public descriptor. + const packaged = await packageClusterSeed({ + family: 'wasix', + target: 'portable', + profile, + pgdata, + runtime, + version, + runtimeVersion, + producer: seedProducerIdentity(receipt), + icuData: profile === 'icu' ? path.join(icuRoot, 'share/icu') : undefined, + outputDir: path.join(root, 'assets'), + }); + outputs.push(packaged.archive); + } + const result = Bun.spawnSync([realpathSync(sdkTest), '--include-ignored', '--test-threads=1'], { + cwd: root, + env: { + LC_ALL: 'C', + LANG: 'C', + TZ: 'UTC', + RAYON_NUM_THREADS: '2', + TEST_TMPDIR: root, + XDG_CACHE_HOME: path.join(root, 'cache'), + OLIPHAUNT_TEST_STANDARD_SEED: outputs[0], + OLIPHAUNT_TEST_ICU_SEED: outputs[1], + OLIPHAUNT_TEST_ICU_ROOT: icuRoot, + }, + stdout: 'pipe', + stderr: 'pipe', + }); + assert.equal(result.exitCode, 0, `${result.stderr.toString()}\n${result.stdout.toString()}`); + assert.match(result.stdout.toString(), /test result: ok\. 2 passed; 0 failed; 0 ignored;/u); + console.log(result.stdout.toString()); +} finally { + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/resources/wasix_seed.mts b/build_defs/resources/wasix_seed.mts new file mode 100644 index 000000000..bb6d47440 --- /dev/null +++ b/build_defs/resources/wasix_seed.mts @@ -0,0 +1,173 @@ +import assert from 'node:assert/strict'; +import { copyFileSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { validateNativeIcuDataManifest } from '../../src/database-resources/contracts/icu-data.mts'; +import { createDeterministicTar } from '../../tools/packaging/archive-directory.mts'; +import { extractPortableArchiveTree } from '../../tools/packaging/portable-archive.mts'; +import { extractNativePayload } from '../native/host-runtime-test-helpers.mts'; +import { + captureSeedConstructionIntent, + captureSeedContentIntent, + captureSeedProducerIdentity, + expandSeedConstructionTrees, + seedConstructionFileBinding, + seedConstructionInvocation, + selectCompletedSeed, + selectQualifiedSeed, + writePromotedSeedReceipt, + writeSeedConstructionReceipt, +} from './seed_construction.mts'; +import { materializeArchive, privateWork, readSpecification, run } from './shared.mts'; +import { extractWasixRuntime, parseWasixBootstrapRecipe } from './wasix_inputs.mts'; + +const specification = readSpecification(process.argv.length === 4 ? 1 : 0); +if (Object.hasOwn(specification, 'constructionTrees')) { + const flag = '--construction-tree-files='; + assert.ok( + process.argv[3]?.startsWith(flag), + 'seed constructor requires its declared Tree leaf inventory', + ); + const leaves = readFileSync(process.argv[3].slice(flag.length), 'utf8') + .split(/\r?\n/u) + .filter(Boolean); + const declared = expandSeedConstructionTrees( + specification.constructionInputs, + specification.constructionTrees, + leaves, + specification.constructionTreeMembers, + ); + specification.constructionInputs = declared.inputs; + specification.constructionTreeMembers = declared.treeMembers; +} else + assert.equal(process.argv.length, 3, 'seed constructor has an undeclared Tree leaf argument'); +assert.equal(specification.target, 'portable'); +const work = privateWork(path.resolve(specification.output)); +try { + const runtime = extractWasixRuntime(specification.runtime, work); + let icuData: string | undefined; + if (specification.icu) { + const icuRoot = path.join(work, 'icu'); + extractPortableArchiveTree( + materializeArchive(specification.icu, path.join(work, 'inputs')), + icuRoot, + ); + icuData = path.join(icuRoot, 'share/icu'); + validateNativeIcuDataManifest(readFileSync(path.join(icuRoot, 'manifest.properties')), icuData); + } + assert.equal(specification.profile === 'icu', Boolean(icuData)); + const prepared = path.join(work, 'prepared'); + const command = path.resolve(specification.runner); + const arguments_ = [runtime, prepared, specification.profile, ...(icuData ? [icuData] : [])]; + const environment = { LC_ALL: 'C', LANG: 'C', TZ: 'UTC', RAYON_NUM_THREADS: '2' }; + const recipe = parseWasixBootstrapRecipe( + run(command, ['recipe', specification.profile], environment, work), + specification.profile, + ); + const intent = specification.constructionInputs + ? captureSeedConstructionIntent( + { family: 'wasix', target: 'portable', profile: specification.profile }, + { + toolFlags: process.execArgv, + producer: captureSeedProducerIdentity(runtime, specification.target), + invocation: seedConstructionInvocation(command, arguments_, environment, { + runtime, + work, + runner: command, + ...(icuData ? { icuData } : {}), + }), + contract: specification.contract, + bindings: { + runtime: seedConstructionFileBinding( + specification.constructionInputs, + specification.runtime, + ), + runner: seedConstructionFileBinding( + specification.constructionInputs, + specification.runner, + ), + icu: specification.icu + ? seedConstructionFileBinding(specification.constructionInputs, specification.icu) + : null, + }, + }, + specification.constructionInputs, + specification.constructionTreeMembers, + ) + : undefined; + const contentIntent = intent + ? captureSeedContentIntent( + { family: 'wasix', target: 'portable', profile: specification.profile }, + { + contract: specification.contract, + recipe, + invocation: seedConstructionInvocation(command, arguments_, environment, { + runtime, + work, + runner: command, + ...(icuData ? { icuData } : {}), + }), + }, + path.join(runtime, 'share/postgresql'), + icuData, + ) + : undefined; + assert.ok(!specification.reuse || intent, 'seed reuse requires declared constructor inputs'); + assert.ok( + !specification.promotion || intent, + 'seed promotion requires declared constructor inputs', + ); + assert.ok( + !(specification.reuse && specification.promotion), + 'seed has more than one physical origin', + ); + const promoted = intent + ? selectQualifiedSeed(intent, specification.promotion, contentIntent) + : undefined; + if (promoted) { + copyFileSync(promoted.frozen, specification.output); + const pgdata = path.join(prepared, 'pgdata'); + await extractNativePayload(specification.output, pgdata); + assert.ok(specification.constructionOutput, 'declared seed promotion requires receipt output'); + writePromotedSeedReceipt( + specification.constructionOutput, + promoted, + specification.output, + pgdata, + ); + } else { + const completed = intent + ? selectCompletedSeed(intent, specification.reuse, contentIntent) + : undefined; + if (completed) { + extractPortableArchiveTree( + materializeArchive(completed.archive, path.join(work, 'completed')), + path.join(prepared, 'pgdata'), + ); + } else { + run(command, arguments_, environment, work); + } + // The genuine WASIX initdb constructor verifies both profile and reopen. + // Freeze its unique PGDATA intact; do not normalize clock/PID/random fields. + writeFileSync( + specification.output, + await createDeterministicTar(path.join(prepared, 'pgdata')), + ); + if (intent) { + assert.ok( + specification.constructionOutput, + 'declared seed intent requires its receipt output', + ); + writeSeedConstructionReceipt( + specification.constructionOutput, + intent, + specification.output, + path.join(prepared, 'pgdata'), + completed?.origin, + contentIntent, + completed?.sourceManifest, + ); + } + } +} finally { + rmSync(work, { recursive: true, force: true }); +} diff --git a/build_defs/wasix/BUILD.bazel b/build_defs/wasix/BUILD.bazel new file mode 100644 index 000000000..72683e103 --- /dev/null +++ b/build_defs/wasix/BUILD.bazel @@ -0,0 +1,251 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("@rules_cc//cc:defs.bzl", "cc_import", "cc_library", "cc_test") +load("//build_defs/foundation:bun.bzl", "bun_test") +load(":llvm.bzl", "exec_files", "llvm_helper_runtime", "llvm_libxml2_arm64") +load(":npm.bzl", "RUNTIME_NPM_HELPERS", "RUNTIME_NPM_NOTICES") +load(":cargo.bzl", "RUNTIME_CARGO_HELPERS") +load(":tools-carriers.bzl", "TOOLS_CARRIER_HELPERS") +load(":aot-repeatability.bzl", "wasix_aot_repeatability_test") +load(":napi.bzl", "NAPI_HELPERS", "NAPI_NOTICES") +load(":host-aot-smoke.bzl", "wasix_host_aot_smoke_test") +load(":host-aot-smoke-test.bzl", "wasix_host_aot_smoke_argument_tests") + +package(default_visibility = ["//visibility:public"]) + +exports_files(glob(["*.bzl", "*.bazel", "*.mts", "*.patch"])) +exports_files(["config_probe.c"], visibility = ["@postgres_wasix//:__pkg__"]) + +bun_test( + name = "napi_inputs_test", + entry_point = "napi-inputs.test.mts", + data = ["napi-inputs.mts", "napi.mts", "held-wasix-relocatable-includes.patch", "//src/wasix/node-addon:Cargo.toml", "//src/wasix/node-addon:package.json", "//:src/extensions/generated/extensions.catalog.json", "//:tools/packaging/testdata/release-fixture-utils.mts"] + NAPI_HELPERS + NAPI_NOTICES.keys() + [ + "//src/wasix/node-addon:packages/" + target + "/" + file for target in ["linux-x64-gnu", "linux-arm64-gnu", "darwin-arm64", "win32-x64-msvc"] for file in ["package.json", "README.md"] + ], + size = "small", +) + +bun_test( + name = "napi_envelopes_test", + entry_point = "//src/wasix/node-addon:tools/package-platform.test.mts", + data = ["//:tools/packaging/testdata/release-fixture-utils.mts", "//src/wasix/node-addon:tools/workspace-runtime-contract.test.mts"] + NAPI_HELPERS + NAPI_NOTICES.keys() + [ + "//src/wasix/node-addon:packages/" + target + "/" + file for target in ["linux-x64-gnu", "linux-arm64-gnu", "darwin-arm64", "win32-x64-msvc"] for file in ["package.json", "README.md"] + ], + size = "small", +) + +wasix_aot_repeatability_test( + name = "macos_aot_repeatability_test", + module = "//src/wasix/runtime:plpgsql", + size = "small", + tags = ["manual"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + exec_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64", "@zig_sdk//libc:gnu.2.34"], +) + + +bun_test( + name = "package_test", + entry_point = "package.test.mts", + data = [ + "package.mts", + "//:tools/packaging/archive-directory.mts", + "//:tools/packaging/portable-archive.mts", + ], + size = "small", +) + +bun_test( + name = "runtime_npm_test", + entry_point = "npm.test.mts", + data = ["npm.mts"] + RUNTIME_NPM_HELPERS + RUNTIME_NPM_NOTICES.keys(), + size = "small", +) + +bun_test( + name = "runtime_cargo_test", + entry_point = "cargo.test.mts", + data = ["cargo.mts", "//src/wasix/runtime:toolchain.toml"] + RUNTIME_CARGO_HELPERS + RUNTIME_NPM_NOTICES.keys() + [ + "//src/wasix/runtime/crates/assets:package_sources", + "//src/wasix/runtime/crates/aot/x86_64-unknown-linux-gnu:package_sources", + "//src/wasix/runtime/crates/aot/aarch64-unknown-linux-gnu:package_sources", + "//src/wasix/runtime/crates/aot/aarch64-apple-darwin:package_sources", + "//src/wasix/runtime/crates/aot/x86_64-pc-windows-msvc:package_sources", + ], + size = "small", +) + +bun_test( + name = "tools_carriers_test", + entry_point = "tools-carriers.test.mts", + data = [ + "tools-carriers.mts", + "//src/wasix/runtime:toolchain.toml", + "//src/wasix/runtime:postgres/series", + "//src/wasix/postgres-tools:npm/native.mts", + "//src/wasix/postgres-tools:carrier_source_patches", + ] + ["//src/wasix/postgres-tools:" + target + "_package_sources" for target in [ + "portable", "linux_arm64_gnu", "linux_x64_gnu", "macos_arm64", "windows_x64_msvc", + ]] + TOOLS_CARRIER_HELPERS + RUNTIME_NPM_NOTICES.keys(), + size = "small", +) + +bun_test( + name = "cargo_inputs_test", + entry_point = "cargo-inputs.test.mts", + data = [ + "cargo-inputs.mts", + "cargo.mts", + "//build_defs/languages:cargo-metadata.mts", + "//:tools/packaging/frozen-cargo.mts", + "//:Cargo.lock", + "//src/wasix/runtime:release.toml", + "//src/wasix/runtime:toolchain.toml", + "//src/wasix/postgres-tools:crates/tools/Cargo.toml", + "//src/wasix/runtime/crates/assets:package_sources", + "//src/wasix/runtime/crates/aot/x86_64-unknown-linux-gnu:package_sources", + "//src/wasix/runtime/crates/aot/aarch64-unknown-linux-gnu:package_sources", + "//src/wasix/runtime/crates/aot/aarch64-apple-darwin:package_sources", + "//src/wasix/runtime/crates/aot/x86_64-pc-windows-msvc:package_sources", + ] + RUNTIME_CARGO_HELPERS + RUNTIME_NPM_NOTICES.keys(), + size = "small", +) + +wasix_host_aot_smoke_test( + name = "host_aot_smoke_test", + target_triple = select({ + ":llvm_linux_x64": "x86_64-unknown-linux-gnu", + ":llvm_linux_arm64": "aarch64-unknown-linux-gnu", + ":llvm_macos_arm64": "aarch64-apple-darwin", + ":llvm_windows_x64": "x86_64-pc-windows-msvc", + }), + size = "large", + timeout = "long", + tags = ["manual", "installed-consumer"], +) + +wasix_host_aot_smoke_argument_tests() + +bun_test( + name = "host_aot_smoke_inputs_test", + entry_point = "host-aot-smoke.test.mts", + data = ["host-aot-smoke.mts", "cargo-inputs.mts", "cargo.mts", "//build_defs/languages:cargo-metadata.mts", "//:tools/packaging/frozen-cargo.mts", "//src/wasix/postgres-tools:tools/package-assets.mts", "//src/wasix/runtime:tools/package-release-assets.mts", "//src/wasix/runtime:toolchain.toml"] + RUNTIME_CARGO_HELPERS + RUNTIME_NPM_NOTICES.keys(), + size = "small", +) + +platform( + name = "portable", + constraint_values = ["@platforms//cpu:wasm32", "@platforms//os:wasi"], +) + +# Canonical LLVM22's helper and archives require glibc 2.34 for construction. +# This internal execution profile does not set the native product ABI floor. +platform( + name = "llvm_serializer_linux_x86_64", + constraint_values = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + "@zig_sdk//libc:gnu.2.34", + ], +) + +# These source selectors avoid acquiring foreign LLVM archives during a native +# serializer build. The forwarding rules select in execution configuration. +config_setting(name = "llvm_linux_x64", constraint_values = ["@platforms//os:linux", "@platforms//cpu:x86_64"]) +config_setting(name = "llvm_linux_arm64", constraint_values = ["@platforms//os:linux", "@platforms//cpu:aarch64"]) +config_setting(name = "llvm_macos_arm64", constraint_values = ["@platforms//os:macos", "@platforms//cpu:aarch64"]) +config_setting(name = "llvm_windows_x64", constraint_values = ["@platforms//os:windows", "@platforms//cpu:x86_64"]) + +filegroup( + name = "llvm_files_for_host", + srcs = select({ + ":llvm_linux_x64": ["@wasmer_llvm_linux_x64//:files"], + ":llvm_linux_arm64": ["@wasmer_llvm_linux_arm64//:files"], + ":llvm_macos_arm64": ["@wasmer_llvm_macos_arm64//:files"], + ":llvm_windows_x64": ["@wasmer_llvm_windows_x64//:files"], + }), +) + +filegroup( + name = "llvm_env_for_host", + srcs = select({ + ":llvm_linux_x64": ["@wasmer_llvm_linux_x64//:llvm.env"], + ":llvm_linux_arm64": ["@wasmer_llvm_linux_arm64//:llvm.env"], + ":llvm_macos_arm64": ["@wasmer_llvm_macos_arm64//:llvm.env"], + ":llvm_windows_x64": ["@wasmer_llvm_windows_x64//:llvm.env"], + }), +) + +exec_files(name = "wasmer_llvm_files", srcs = [":llvm_files_for_host"]) +exec_files(name = "wasmer_llvm_env", srcs = [":llvm_env_for_host"]) + +llvm_libxml2_arm64(name = "llvm_libxml2_arm64", target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:aarch64"]) + +# LLVM22's GNU C++ ABI and its llvm-config helper use this maintained runtime. +# Import the ELF SONAME file, rather than libgcc_s.so's linker script. +cc_import( + name = "wasmer_gnu_unwind", + shared_library = "@llvm_gnu_runtime//:lib64/libgcc_s.so.1", + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) + +cc_library( + name = "wasmer_llvm_gnu_link", + deps = ["@llvm_gnu_runtime//:libstdcxx", ":wasmer_gnu_unwind"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) + +llvm_helper_runtime( + name = "wasmer_llvm_gnu_env", + libraries = [ + "@llvm_gnu_runtime//:lib64/libstdc++.so.6", + "@llvm_gnu_runtime//:lib64/libstdc++.so.6.0.30", + "@llvm_gnu_runtime//:lib64/libgcc_s.so.1", + ], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) + +filegroup( + name = "wasmer_llvm_gnu_files", + srcs = [":wasmer_llvm_gnu_env"], + output_group = "runtime_files", +) + +# Resolution reads only these constraints; acquire the compiler payload only +# when a configured wasm32/WASI target selects its implementation. +toolchain( + name = "cc_toolchain", + toolchain = "@wasix_toolchain//:compiler", + toolchain_type = "@rules_cc//cc:toolchain_type", + exec_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + target_compatible_with = ["@platforms//os:wasi", "@platforms//cpu:wasm32"], +) + +alias( + name = "config_probe", + actual = "@postgres_wasix//:configuration_contract", + target_compatible_with = ["@platforms//cpu:wasm32", "@platforms//os:wasi"], +) + +cc_test( + name = "bridge_abi_test", + size = "small", + srcs = [ + "//src/wasix/runtime:assets/build/wasix_shim/oliphaunt_wasix_bridge.c", + "//src/wasix/runtime:assets/build/wasix_shim/oliphaunt_wasix_bridge_abi_test.c", + ], + copts = ["-std=c11", "-Wall", "-Wextra"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) + +cc_test( + name = "initdb_shim_abi_test", + size = "small", + srcs = [ + "//src/wasix/runtime:assets/build/wasix_shim/oliphaunt_wasix_initdb_shim.c", + "//src/wasix/runtime:assets/build/wasix_shim/oliphaunt_wasix_initdb_shim_abi_test.c", + ], + copts = ["-std=c11", "-Wall", "-Wextra"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) + +source_quality_files() diff --git a/build_defs/wasix/aot-repeatability.bzl b/build_defs/wasix/aot-repeatability.bzl new file mode 100644 index 000000000..69ff8bf43 --- /dev/null +++ b/build_defs/wasix/aot-repeatability.bzl @@ -0,0 +1,33 @@ +"""Exercise the actual Mach-O serializer in independently seeded processes.""" + +load("@wasix_tool_metadata//:targets.bzl", "WASIX_AOT_TARGETS") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") +load(":platform.bzl", "WASIX_PORTABLE_TRANSITION") +load(":wasm.bzl", "WasmModuleInfo") + +def _repeatability_impl(ctx): + module = ctx.attr.module[0][WasmModuleInfo].module + serializer = ctx.executable._serializer + return bun_test_entrypoint( + ctx, + ctx.file._runner, + [serializer, module, WASIX_AOT_TARGETS["macos-arm64"]], + [serializer, module, ctx.file._runner], + source_files = [ctx.file._runner], + additional_runfiles = ctx.attr._serializer[DefaultInfo].default_runfiles, + ) + +_wasix_aot_repeatability_test = rule( + implementation = _repeatability_impl, + test = True, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "module": attr.label(mandatory = True, providers = [WasmModuleInfo], cfg = WASIX_PORTABLE_TRANSITION), + "_serializer": attr.label(default = "//src/wasix/runtime/tools/xtask:aot_serializer", executable = True, cfg = "exec"), + "_runner": attr.label(default = "//build_defs/wasix:aot-repeatability.mts", allow_single_file = True), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), + }), +) + +def wasix_aot_repeatability_test(name, **kwargs): + _wasix_aot_repeatability_test(name = name, args = bun_test_entrypoint_args(name), **kwargs) diff --git a/build_defs/wasix/aot-repeatability.mts b/build_defs/wasix/aot-repeatability.mts new file mode 100644 index 000000000..a7f658530 --- /dev/null +++ b/build_defs/wasix/aot-repeatability.mts @@ -0,0 +1,65 @@ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { mkdtempSync, readFileSync, rmSync } from 'node:fs'; +import path from 'node:path'; + +const [serializer, module, target] = process.argv.slice(2); +assert(serializer && module && target && process.argv.length === 5 && process.env.TEST_TMPDIR); +const sha256 = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +const source = readFileSync(module); +assert(source.subarray(0, 8).equals(Buffer.from([0, 97, 115, 109, 1, 0, 0, 0]))); +const root = mkdtempSync(path.join(process.env.TEST_TMPDIR, 'aot-repeatability-')); +try { + const results = [0, 1].map((index) => { + const output = path.join(root, String(index), 'plpgsql.bin.zst'); + const result = spawnSync( + serializer, + [ + 'aot-serializer', + 'serialize', + '--input', + module, + '--output', + output, + '--target', + target, + '--threads', + '2', + ], + { cwd: root, env: { LC_ALL: 'C' }, timeout: 300_000, maxBuffer: 4 * 1024 * 1024 }, + ); + assert.ifError(result.error); + assert.equal(result.status, 0, `fresh serializer failed:\n${result.stderr.toString()}`); + const compressed = readFileSync(output); + const raw = Buffer.from(Bun.zstdDecompressSync(compressed)); + assert(raw.length > 0 && compressed.length > 0); + return { compressed, raw }; + }); + assert( + results[0].raw.equals(results[1].raw), + `fresh serialized bytes differ: ${results.map(({ raw }) => sha256(raw)).join(', ')}`, + ); + assert( + results[0].compressed.equals(results[1].compressed), + `fresh compressed bytes differ: ${results.map(({ compressed }) => sha256(compressed)).join(', ')}`, + ); + assert( + readFileSync(module).equals(source), + 'serialization changed its actual shipping WASM input', + ); + console.log( + JSON.stringify({ + target, + serializerSha256: sha256(readFileSync(serializer)), + wasmSha256: sha256(source), + rawSha256: sha256(results[0].raw), + compressedSha256: sha256(results[0].compressed), + rawBytes: results[0].raw.length, + compressedBytes: results[0].compressed.length, + freshProcesses: results.length, + }), + ); +} finally { + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/wasix/aot.bzl b/build_defs/wasix/aot.bzl new file mode 100644 index 000000000..9afbeba8d --- /dev/null +++ b/build_defs/wasix/aot.bzl @@ -0,0 +1,149 @@ +"""Native, Linux-first Wasmer LLVM serialization for canonical target triples. + +Cross-target construction remains distinct from the required target-host +deserialize, query and reopen consumer proofs. +""" + +load("@wasix_tool_metadata//:targets.bzl", "WASIX_AOT_TARGETS") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") +load(":wasm.bzl", "WasmModuleInfo") +load(":platform.bzl", "WASIX_PORTABLE_TRANSITION") + +WasixAotInfo = provider(fields = { + "image": "Zstandard-compressed Wasmer serialized module.", + "module": "The original portable module.", + "target": "The exact canonical target triple.", +}) + +def _resources(_os, _input_count): + return {"cpu": 2, "memory": 8192} + +def _aot_impl(ctx): + if ctx.attr.target_id not in WASIX_AOT_TARGETS: + fail("WASIX AOT requires an admitted canonical target: " + ctx.attr.target_id) + target = WASIX_AOT_TARGETS[ctx.attr.target_id] + module = ctx.attr.module[0][WasmModuleInfo].module + output = ctx.actions.declare_file(ctx.label.name + "/" + ctx.attr.output_name) + arguments = ctx.actions.args() + arguments.add_all(["aot-serializer", "serialize"]) + arguments.add("--input", module) + arguments.add("--output", output) + arguments.add("--target", target) + arguments.add_all(["--threads", "2"]) + ctx.actions.run( + executable = ctx.attr._serializer[DefaultInfo].files_to_run, + arguments = [arguments], + inputs = [module], + outputs = [output], + env = {"LC_ALL": "C"}, + mnemonic = "WasixAotSerialize", + progress_message = "Serialize WASIX AOT " + ctx.attr.target_id + " %{label}", + resource_set = _resources, + ) + return [ + DefaultInfo(files = depset([output])), + WasixAotInfo(image = output, module = module, target = target), + ] + +wasix_aot = rule( + implementation = _aot_impl, + attrs = { + "module": attr.label(providers = [WasmModuleInfo], mandatory = True, cfg = WASIX_PORTABLE_TRANSITION), + "target_id": attr.string(mandatory = True), + "output_name": attr.string(mandatory = True), + "_serializer": attr.label(default = "//src/wasix/runtime/tools/xtask:aot_serializer", executable = True, cfg = "exec"), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), + }, +) + +def _aot_payload_impl(ctx): + if ctx.attr.target_id not in WASIX_AOT_TARGETS: + fail("WASIX AOT requires an admitted canonical target: " + ctx.attr.target_id) + target = WASIX_AOT_TARGETS[ctx.attr.target_id] + portable = ctx.attr.portable[DefaultInfo].files.to_list() + if len(portable) != 1 or not portable[0].is_directory: + fail("AOT requires the declared portable runtime directory") + inputs = portable + [ctx.file.toolchain] + artifacts = [] + for label, name in ctx.attr.artifacts.items(): + artifact = label[WasixAotInfo] + if artifact.target != target: + fail("AOT payload cannot mix serializer target triples") + inputs += [artifact.image, artifact.module] + artifacts.append({"name": name, "path": artifact.image.basename, "image": artifact.image.path, "module": artifact.module.path}) + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode({ + "portable_manifest": portable[0].path + "/manifest.json", + "toolchain": ctx.file.toolchain.path, + "target_triple": target, + "artifacts": artifacts, + })) + output = ctx.actions.declare_directory(ctx.label.name + "/" + target) + args = ctx.actions.args() + args.add("--spec", spec) + args.add("--output", output.path) + args.add("--manifest-tool", ctx.executable._manifest_tool) + bun_file_action( + ctx, + ctx.file._packager, + arguments = [args], + inputs = depset(inputs + [spec]), + source_files = [], + tools = [ctx.attr._manifest_tool[DefaultInfo].files_to_run], + outputs = [output], + env = {"LC_ALL": "C"}, + mnemonic = "WasixAotEnvelope", + progress_message = "Package declared WASIX AOT " + ctx.attr.target_id + " %{label}", + ) + return [DefaultInfo(files = depset([output]))] + +wasix_aot_payload = rule( + implementation = _aot_payload_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = { + "target_id": attr.string(mandatory = True), + "portable": attr.label(mandatory = True), + "artifacts": attr.label_keyed_string_dict(providers = [WasixAotInfo], mandatory = True), + "toolchain": attr.label(default = "//src/wasix/runtime:toolchain.toml", allow_single_file = True), + "_packager": attr.label(default = "//build_defs/wasix:package-aot.mts", allow_single_file = True), + "_manifest_tool": attr.label(default = "//src/wasix/runtime/tools/xtask:xtask", executable = True, cfg = "exec"), + }, +) + +def _wasix_aot_targets(images): + for target_id in WASIX_AOT_TARGETS: + prefix = "aot_" + target_id.replace("-", "_") + "_" + for module, (image, _identity) in images.items(): + wasix_aot( + name = prefix + module, + module = ":" + module, + target_id = target_id, + output_name = image, + tags = ["manual"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + exec_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64", "@zig_sdk//libc:gnu.2.34"], + ) + wasix_aot_payload( + name = prefix + "payload", + target_id = target_id, + portable = ":portable_payload", + artifacts = {":" + prefix + module: identity for module, (_image, identity) in images.items()}, + tags = ["manual"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + ) + +def wasix_runtime_aot_targets(): + """Declare the four frozen runtime images for each canonical AOT target.""" + _wasix_aot_targets({ + "postgres": ("oliphaunt-llvm-opta.bin.zst", "runtime:oliphaunt"), + "initdb": ("initdb-llvm-opta.bin.zst", "tool:initdb"), + "plpgsql": ("plpgsql-llvm-opta.bin.zst", "runtime-support:plpgsql"), + "dict_snowball": ("dict_snowball-llvm-opta.bin.zst", "runtime-support:dict_snowball"), + }) + +def wasix_tools_aot_targets(): + """Serialize only pg_dump and psql; no core runtime construction edge.""" + _wasix_aot_targets({ + "pg_dump": ("pg_dump-llvm-opta.bin.zst", "tool:pg_dump"), + "psql": ("psql-llvm-opta.bin.zst", "tool:psql"), + }) diff --git a/build_defs/wasix/browser/BUILD.bazel b/build_defs/wasix/browser/BUILD.bazel new file mode 100644 index 000000000..a2821030e --- /dev/null +++ b/build_defs/wasix/browser/BUILD.bazel @@ -0,0 +1,53 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/foundation:bun.bzl", "bun_script_test", "bun_test") +load("@javascript_consumer_packages//:roots.bzl", "CONSUMER_ACQUISITIONS", "CONSUMER_CLOSURES", "CONSUMER_TOOLS") +load(":defs.bzl", "browser_consumer_tools_test") + +package(default_visibility = ["//visibility:public"]) +exports_files(["metadata.mts", "repositories.bzl", "defs.bzl", "compile.mts", "bundle.mts", "npm-archives.mts", "rollup-compile.mts", "provenance.mts", "package-host.mts", "check-host-abi.mts", "copy-host-assets.mts", "consumer.mts", "consumer-tools-driver.mts", "chrome-receipt.mts", "crate-source-metadata.patch", "cargo-extension.bzl"]) + +browser_consumer_tools_test( + name = "consumer_tools_test", + size = "small", + packages = {"@javascript_consumer_packages//:" + key: key for key in CONSUMER_CLOSURES["@oliphaunt/wasix-ts"]}, + acquisition = CONSUMER_ACQUISITIONS["@oliphaunt/wasix-ts"], + roots = CONSUMER_TOOLS["@oliphaunt/wasix-ts"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) + +bun_test( + name = "metadata_test", + entry_point = "metadata.test.mts", + data = ["metadata.mts"], + size = "small", +) + +bun_test( + name = "compile_test", + entry_point = "compile.test.mts", + data = ["npm-archives.mts"], + size = "small", +) + +bun_test( + name = "chrome_receipt_test", + entry_point = "chrome-receipt.test.mts", + data = ["chrome-receipt.mts"], + size = "small", +) + +bun_script_test( + name = "cargo_source_projection_test", + entry_point = "cargo-source-projection-test.mts", + data = ["metadata.mts", "@browser_sources//:cargo-sources.json", "@browser_cargo//:cargo-bazel.json", "@browser_cargo//:crates.bzl", "//src/wasix/browser-host:source.toml"], + size = "small", +) + +bun_test( + name = "provenance_test", + entry_point = "provenance.test.mts", + data = ["provenance.mts", "metadata.mts"], + size = "small", +) + +source_quality_files() diff --git a/build_defs/wasix/browser/bundle.mts b/build_defs/wasix/browser/bundle.mts new file mode 100644 index 000000000..859d1e37f --- /dev/null +++ b/build_defs/wasix/browser/bundle.mts @@ -0,0 +1,28 @@ +import assert from 'node:assert/strict'; +import { copyFile, cp, mkdir, mkdtemp, readFile } from 'node:fs/promises'; +import { dirname, join, resolve } from 'node:path'; +import { materializeCompilerPackages } from './npm-archives.mts'; + +const [input, output, compiler, context, specificationFile, driver] = Bun.argv.slice(2); +assert(input && output && compiler && context && specificationFile && driver); +const outputPath = resolve(output); +const metadata = JSON.parse(await readFile(context, 'utf8')); +const specification: { sources: Record; packages: Record } = + JSON.parse(await readFile(specificationFile, 'utf8')); +const workspace = await mkdtemp(join(dirname(outputPath), '.browser-rollup-')); +for (const [name, file] of Object.entries(specification.sources)) { + assert(!name.startsWith('/') && !name.split('/').some((part) => part === '..' || part === '.')); + const destination = join(workspace, name); + await mkdir(dirname(destination), { recursive: true }); + await copyFile(file, destination); +} +await cp(input, join(workspace, 'pkg'), { recursive: true, dereference: true }); +await materializeCompilerPackages(metadata.acquisition, specification.packages, workspace); +const result = Bun.spawnSync([resolve(compiler), resolve(driver), workspace], { + cwd: workspace, + env: { ...process.env, PATH: '', NODE_PATH: '', NODE_OPTIONS: '' }, + stdout: 'inherit', + stderr: 'inherit', +}); +assert.equal(result.exitCode, 0, 'Pinned Rollup compiler failed'); +await cp(join(workspace, 'dist'), outputPath, { recursive: true, dereference: true }); diff --git a/build_defs/wasix/browser/cargo-extension.bzl b/build_defs/wasix/browser/cargo-extension.bzl new file mode 100644 index 000000000..4a34b9be8 --- /dev/null +++ b/build_defs/wasix/browser/cargo-extension.bzl @@ -0,0 +1,3 @@ +load("@rules_rust//crate_universe:extensions.bzl", _crate = "crate") + +crate = _crate diff --git a/build_defs/wasix/browser/cargo-source-projection-test.mts b/build_defs/wasix/browser/cargo-source-projection-test.mts new file mode 100644 index 000000000..952179d18 --- /dev/null +++ b/build_defs/wasix/browser/cargo-source-projection-test.mts @@ -0,0 +1,76 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { browserCargoSources } from './metadata.mts'; + +const runfiles = process.env.RUNFILES_DIR; +assert(runfiles, 'This regression consumes the actual Bazel crate_universe output'); +const mapping = readFileSync(join(runfiles, '_repo_mapping'), 'utf8') + .trim() + .split('\n') + .map((line) => line.split(',')); +function external(repository: string, path: string) { + const roots = new Set(mapping.filter((row) => row[1] === repository).map((row) => row[2])); + assert.equal(roots.size, 1, `Expected one declared ${repository} repository`); + return join(runfiles, [...roots][0], path); +} +const sources = JSON.parse(readFileSync(external('browser_sources', 'cargo-sources.json'), 'utf8')); +const context = JSON.parse(readFileSync(external('browser_cargo', 'cargo-bazel.json'), 'utf8')); +const acquisitionMacro = readFileSync(external('browser_cargo', 'crates.bzl'), 'utf8'); +const source = Bun.TOML.parse( + readFileSync(join(runfiles, '_main/src/wasix/browser-host/source.toml'), 'utf8'), +); +const canonical = browserCargoSources(source); +assert.deepEqual(Object.keys(sources).sort(), Object.keys(canonical).sort()); +for (const [id, expected] of Object.entries(canonical)) { + const row = sources[id]; + const actual = context.crates[id].repository; + assert.deepEqual(Object.keys(actual), ['Http'], `${id} must use immutable HTTP acquisition`); + assert.equal(actual.Http.url, expected.url); + assert.equal(actual.Http.sha256, expected.sha256); + assert.equal(row.strip_prefix, expected.strip_prefix); + assert.deepEqual(actual.Http.patch_args, ['-p1']); + assert.deepEqual(actual.Http.patches, row.patches); + let previous = -1; + for (const patch of row.patches) { + const offset = acquisitionMacro.indexOf(JSON.stringify(patch)); + assert(offset > previous, `${id} acquisition macro changed canonical patch order`); + previous = offset; + } + assert.deepEqual( + row.patches.map((label: string) => label.split(':').at(-1)), + expected.patches, + ); +} +for (const [id, row] of Object.entries(context.crates) as [string, any][]) + assert(!row.repository?.Path, `${id} unexpectedly acquired an ambient path source`); +assert.deepEqual(Object.keys(context.workspace_members), ['wasmer-js 0.0.0']); + +function crate(name: string) { + const matches = Object.entries(context.crates).filter(([id]) => id.split(' ')[0] === name); + assert.equal(matches.length, 1, `Expected one resolved ${name} crate`); + return matches[0][1] as any; +} +function dependencyTriples(parent: string, dependency: string) { + const deps = crate(parent).common_attrs.deps ?? []; + const common = Array.isArray(deps) ? deps : (deps.common ?? []); + const matches = (rows: any[]) => rows.some((row) => row.id.split(' ')[0] === dependency); + const triples = new Set(); + if (matches(common)) + for (const triple of ['wasm32-unknown-unknown', 'x86_64-unknown-linux-gnu']) + triples.add(triple); + for (const [condition, rows] of Object.entries(deps.selects ?? {}) as [string, any[]][]) + if (matches(rows)) { + assert(context.conditions[condition], `Missing generated condition ${condition}`); + for (const triple of context.conditions[condition]) triples.add(triple); + } + return [...triples].sort(); +} +// The exact pinned nightly's Cargo tree selects this edge only with WASM +// atomics; the three optional web-time edges remain disabled. +assert.deepEqual(dependencyTriples('wasm-bindgen-futures', 'web-sys'), ['wasm32-unknown-unknown']); +for (const dependency of ['futures-channel', 'futures-util', 'web-sys']) + assert.deepEqual(dependencyTriples('web-time', dependency), []); +console.log( + `Verified four pinned browser sources and configured atomics dependencies across ${Object.keys(context.crates).length} resolved crates`, +); diff --git a/build_defs/wasix/browser/check-host-abi.mts b/build_defs/wasix/browser/check-host-abi.mts new file mode 100644 index 000000000..9cbfbef5f --- /dev/null +++ b/build_defs/wasix/browser/check-host-abi.mts @@ -0,0 +1,48 @@ +import assert from 'node:assert/strict'; +import { writeFileSync } from 'node:fs'; +import { createRequire } from 'node:module'; +import { join, resolve } from 'node:path'; + +const workspace = resolve(process.argv[2]); +const ts = createRequire(join(workspace, 'package.json'))('typescript'); +const file = join(workspace, 'consumer.mts'); +const text = [ + 'import * as generated from "./generated/index.mjs";', + 'import * as curated from "./curated/index.mjs";', + 'const compatible: typeof curated = generated;', + 'void compatible;', + '// @ts-expect-error Instance handles are created by runWasix.', + 'new curated.Instance();', + '// @ts-expect-error Direct handles are created by instantiateOliphauntDirect.', + 'new curated.OliphauntDirectInstance();', +].join('\n'); +writeFileSync(file, text); +const options = { + noEmit: true, + strict: true, + skipLibCheck: true, + target: ts.ScriptTarget.ES2022, + module: ts.ModuleKind.NodeNext, + moduleResolution: ts.ModuleResolutionKind.NodeNext, + lib: ['lib.es2023.d.ts', 'lib.dom.d.ts', 'lib.dom.iterable.d.ts', 'lib.webworker.d.ts'], + types: [], +}; +const program = ts.createProgram([file], options); +const diagnostics = ts.getPreEmitDiagnostics(program); +if (diagnostics.length) + throw new Error( + ts.formatDiagnosticsWithColorAndContext(diagnostics, { + getCanonicalFileName: (path: string) => path, + getCurrentDirectory: () => workspace, + getNewLine: () => '\n', + }), + ); +assert.equal(diagnostics.length, 0); +writeFileSync( + join(workspace, 'abi-check.json'), + JSON.stringify({ + compatible: true, + typescriptVersion: ts.version, + nodeVersion: process.versions.node, + }), +); diff --git a/build_defs/wasix/browser/chrome-receipt.mts b/build_defs/wasix/browser/chrome-receipt.mts new file mode 100644 index 000000000..7ab3a6fc2 --- /dev/null +++ b/build_defs/wasix/browser/chrome-receipt.mts @@ -0,0 +1,99 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { readFile, realpath, writeFile } from 'node:fs/promises'; +import { arch, platform, release } from 'node:os'; +import { dirname, join, resolve } from 'node:path'; + +const sha256 = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +const isElf = (bytes: Buffer) => bytes.subarray(0, 4).equals(Buffer.from([0x7f, 0x45, 0x4c, 0x46])); + +async function hostRuntime() { + return { + platform: platform(), + arch: arch(), + kernel: release(), + osReleaseSha256: sha256(await readFile('/etc/os-release')), + }; +} + +async function version(executable: string) { + const result = Bun.spawnSync([executable, '--version'], { + env: { ...process.env, PATH: '', NODE_PATH: '', NODE_OPTIONS: '' }, + }); + assert.equal(result.exitCode, 0, 'Chrome did not report its actual version'); + return result.stdout.toString().trim(); +} + +async function findChrome(selected?: string) { + // Use the existing browser smoke candidate order, then identify its real ELF. + for (const candidate of [ + selected ?? process.env.CHROME_BIN, + '/usr/bin/google-chrome', + '/usr/bin/chromium', + '/usr/bin/chromium-browser', + ]) { + if (!candidate) continue; + try { + const executable = await realpath(candidate); + if (isElf(await readFile(executable))) return executable; + for (const binary of [join(dirname(executable), 'chrome'), '/usr/lib/chromium/chromium']) { + try { + const actual = await realpath(binary); + if (isElf(await readFile(actual))) return actual; + } catch (cause) { + if ((cause as NodeJS.ErrnoException).code !== 'ENOENT') throw cause; + } + } + assert(!selected, 'Selected Chrome must identify its actual Linux ELF executable'); + } catch (cause) { + if (selected || (cause as NodeJS.ErrnoException).code !== 'ENOENT') throw cause; + } + } + throw new Error('Browser qualification requires an installed Chrome/Chromium executable'); +} + +export async function captureChromeReceipt( + output: string, + hostImage: string, + imageVersion: string, + selected?: string, +) { + assert(hostImage?.trim() && imageVersion?.trim(), 'Expected explicit hostImage and ImageVersion'); + const executable = await findChrome(selected); + const receipt = { + executable, + sha256: sha256(await readFile(executable)), + version: await version(executable), + hostImage, + imageVersion, + hostRuntime: await hostRuntime(), + }; + await writeFile(output, `${JSON.stringify(receipt, null, 2)}\n`); + return receipt; +} + +export async function assertChromeReceipt(chromePath: string, file: string) { + assert(resolve(chromePath) === chromePath, 'Chrome executable must be an absolute path'); + const executable = await realpath(chromePath); + const bytes = await readFile(executable); + assert(isElf(bytes), 'Chrome must identify the actual Linux ELF executable'); + const receipt = JSON.parse(await readFile(file, 'utf8')); + assert.equal(receipt.executable, executable); + assert.equal(receipt.sha256, sha256(bytes)); + assert( + receipt.hostImage?.trim() && receipt.imageVersion?.trim(), + 'Chrome requires explicit hostImage and ImageVersion', + ); + assert.deepEqual(receipt.hostRuntime, await hostRuntime()); + assert.equal(receipt.version, await version(executable)); + return receipt; +} + +if (import.meta.main) { + const [output, hostImage, imageVersion, selected] = Bun.argv.slice(2); + assert( + output && hostImage && imageVersion, + 'Expected receipt.json hostImage ImageVersion [Chrome executable]', + ); + console.log((await captureChromeReceipt(output, hostImage, imageVersion, selected)).executable); +} diff --git a/build_defs/wasix/browser/chrome-receipt.test.mts b/build_defs/wasix/browser/chrome-receipt.test.mts new file mode 100644 index 000000000..cc774e0ec --- /dev/null +++ b/build_defs/wasix/browser/chrome-receipt.test.mts @@ -0,0 +1,21 @@ +import { expect, test } from 'bun:test'; +import { mkdtemp, rm, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { assertChromeReceipt, captureChromeReceipt } from './chrome-receipt.mts'; + +test('Chrome operational receipt requires explicit image identity and binds the executable before launch', async () => { + await expect(captureChromeReceipt('/unused', '', 'image-version')).rejects.toThrow('hostImage'); + await expect(captureChromeReceipt('/unused', 'host-image', '')).rejects.toThrow('ImageVersion'); + const directory = await mkdtemp(join(tmpdir(), 'oliphaunt-chrome-receipt-test-')); + try { + const executable = join(directory, 'chrome'); + const receipt = join(directory, 'receipt.json'); + await writeFile(executable, Buffer.from([0x7f, 0x45, 0x4c, 0x46])); + await writeFile(receipt, JSON.stringify({ executable, sha256: '0'.repeat(64) })); + await expect(assertChromeReceipt(executable, receipt)).rejects.toThrow(); + await expect(assertChromeReceipt('relative/chrome', receipt)).rejects.toThrow('absolute'); + } finally { + await rm(directory, { recursive: true, force: true }); + } +}); diff --git a/build_defs/wasix/browser/compile.mts b/build_defs/wasix/browser/compile.mts new file mode 100644 index 000000000..a5d42f304 --- /dev/null +++ b/build_defs/wasix/browser/compile.mts @@ -0,0 +1,40 @@ +import assert from 'node:assert/strict'; +import { chmod, cp, mkdir, readFile } from 'node:fs/promises'; +import { join, resolve } from 'node:path'; + +function run(binary: string, arguments_: string[], cwd?: string) { + const result = Bun.spawnSync([resolve(binary), ...arguments_], { + cwd, + env: { ...process.env, PATH: '', NODE_PATH: '', NODE_OPTIONS: '', BINARYEN_CORES: '1' }, + stdout: 'inherit', + stderr: 'inherit', + }); + assert.equal(result.exitCode, 0, `${binary} compiler failed`); +} + +if (import.meta.main) { + const [mode, input, output, compiler, context] = Bun.argv.slice(2); + assert(mode && input && output && compiler); + const outputPath = resolve(output); + if (mode === 'bindgen') { + const metadata = JSON.parse(await readFile(context, 'utf8')); + const profile = metadata.bindgen.profile; + const flags = ['--target', 'web', '--weak-refs', '--typescript', '--out-name', 'wasmer_js']; + if (profile['debug-js-glue']) flags.push('--debug'); + if (!profile['demangle-name-section']) flags.push('--no-demangle'); + if (profile['dwarf-debug-info']) flags.push('--keep-debug'); + await mkdir(outputPath, { recursive: true }); + run(compiler, [resolve(input), '--out-dir', outputPath, ...flags]); + } else if (mode === 'optimize') { + const metadata = JSON.parse(await readFile(context, 'utf8')); + await cp(input, outputPath, { recursive: true, dereference: true }); + await chmod(outputPath, 0o755); + await chmod(join(outputPath, 'wasmer_js_bg.wasm'), 0o644); + run(compiler, [ + join(resolve(input), 'wasmer_js_bg.wasm'), + ...metadata.wasmOpt, + '-o', + join(outputPath, 'wasmer_js_bg.wasm'), + ]); + } else throw new Error(`Unknown browser compiler action ${mode}`); +} diff --git a/build_defs/wasix/browser/compile.test.mts b/build_defs/wasix/browser/compile.test.mts new file mode 100644 index 000000000..0ea18102c --- /dev/null +++ b/build_defs/wasix/browser/compile.test.mts @@ -0,0 +1,35 @@ +import { expect, test } from 'bun:test'; +import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { extractNpmPackage } from './npm-archives.mts'; + +test('locked npm dot paths extract while traversal and aliases fail closed', async () => { + const root = await mkdtemp(join(tmpdir(), 'browser-npm-paths-')); + try { + const archive = join(root, 'canonical.tgz'); + await writeFile( + archive, + await new Bun.Archive({ + 'package/./dist/cjs/index.js': 'export {};', + 'package/dist/cjs/index.js': 'export {};', + }).bytes(), + ); + await expect(extractNpmPackage(archive, join(root, 'shipping'))).rejects.toThrow( + 'Duplicate shipping', + ); + await extractNpmPackage(archive, join(root, 'valid'), { allowIdenticalAliases: true }); + expect(await readFile(join(root, 'valid/dist/cjs/index.js'), 'utf8')).toBe('export {};'); + for (const entries of [ + { 'package/../escape.js': 'escape' }, + { 'package/dist/index.js': 'first', 'package/./dist/index.js': 'alias' }, + ]) { + await writeFile(archive, await new Bun.Archive(entries).bytes()); + await expect( + extractNpmPackage(archive, join(root, 'invalid'), { allowIdenticalAliases: true }), + ).rejects.toThrow(); + } + } finally { + await rm(root, { recursive: true, force: true }); + } +}); diff --git a/build_defs/wasix/browser/consumer-tools-driver.mts b/build_defs/wasix/browser/consumer-tools-driver.mts new file mode 100644 index 000000000..d063b4613 --- /dev/null +++ b/build_defs/wasix/browser/consumer-tools-driver.mts @@ -0,0 +1,17 @@ +import assert from 'node:assert/strict'; +import { createServer, transformWithEsbuild } from 'vite'; + +const transformed = await transformWithEsbuild('export const answer: number = 42;', 'probe.ts'); +assert(transformed.code.includes('answer = 42')); +assert(!transformed.code.includes(': number')); +const server = await createServer({ + configFile: false, + server: { middlewareMode: true }, + optimizeDeps: { noDiscovery: true, include: [] }, +}); +try { + assert(server.middlewares); +} finally { + await server.close(); +} +console.log('Locked Vite closure loaded and actual native esbuild transformed TypeScript'); diff --git a/build_defs/wasix/browser/consumer.mts b/build_defs/wasix/browser/consumer.mts new file mode 100644 index 000000000..298620498 --- /dev/null +++ b/build_defs/wasix/browser/consumer.mts @@ -0,0 +1,195 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { chmod, copyFile, mkdir, mkdtemp, readFile, symlink, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { dirname, join, resolve } from 'node:path'; +import { assertChromeReceipt } from './chrome-receipt.mts'; +import { extractNpmPackage } from './npm-archives.mts'; +import { assertNativeBrowserHostProvenance, HOST_FILES } from './provenance.mts'; + +const [mode, specificationFile, acquisitionFile, node, driver, ...arguments_] = Bun.argv.slice(2); +assert( + ['tools', 'package', 'archives'].includes(mode) && + specificationFile && + acquisitionFile && + node && + driver, +); +const directory = await mkdtemp( + join(process.env.TEST_TMPDIR ?? tmpdir(), 'oliphaunt-browser-consumer-'), +); +const specification = JSON.parse(await readFile(specificationFile, 'utf8')); +const acquisition = JSON.parse(await readFile(acquisitionFile, 'utf8')); +const runfiles = process.env.OLIPHAUNT_BAZEL_RUNFILES; +assert(runfiles); +if (specification.runtimeAcquisition) { + const runtime = JSON.parse( + await readFile(join(runfiles, specification.runtimeAcquisition), 'utf8'), + ); + for (const [id, row] of Object.entries(runtime)) { + if (acquisition[id]) assert.deepEqual(acquisition[id], row); + else acquisition[id] = row; + } +} +const stores: Record = {}; +assert.deepEqual(Object.keys(specification.packages).sort(), Object.keys(acquisition).sort()); +for (const [id, source] of Object.entries(specification.packages) as [string, string][]) { + const row = acquisition[id]; + const destination = join(directory, '.compiler', id, 'node_modules', row.package); + await extractNpmPackage(join(runfiles, source), destination, { allowIdenticalAliases: true }); + const manifest = JSON.parse(await readFile(join(destination, 'package.json'), 'utf8')); + assert.equal(manifest.name, row.package); + assert.equal(manifest.version, row.version); + if (row.package === '@esbuild/linux-x64') await chmod(join(destination, 'bin/esbuild'), 0o755); + stores[id] = destination; +} +for (const [id, row] of Object.entries(acquisition) as [ + string, + { dependencies: Record }, +][]) { + for (const [name, dependency] of Object.entries(row.dependencies)) { + assert(stores[dependency], `missing consumer compiler dependency ${name}`); + const destination = join(stores[id], 'node_modules', name); + await mkdir(dirname(destination), { recursive: true }); + await symlink(stores[dependency], destination, 'dir'); + } +} +for (const [name, id] of Object.entries(specification.roots) as [string, string][]) { + assert(stores[id], `missing consumer compiler ${name}`); + const destination = join(directory, 'node_modules', name); + await mkdir(dirname(destination), { recursive: true }); + await symlink(stores[id], destination, 'dir'); +} + +function run(script: string, parameters: string[], environment = {}) { + const result = Bun.spawnSync([node, script, ...parameters], { + cwd: directory, + env: { ...process.env, PATH: '', NODE_PATH: '', NODE_OPTIONS: '', ...environment }, + stdout: 'inherit', + stderr: 'inherit', + }); + assert.equal(result.exitCode, 0, 'actual browser consumer failed'); +} + +if (mode === 'tools') { + const destination = join(directory, 'tool-smoke.mts'); + await copyFile(driver, destination); + run(destination, []); +} else { + const [frozenConsumer, cdp, extensions, ...suppliedArchives] = + mode === 'archives' + ? arguments_ + : [...arguments_.slice(3, 6), ...arguments_.slice(0, 3), ...arguments_.slice(6)]; + const [sdk, query, runtime, suppliedChromePath, suppliedReceiptFile] = + mode === 'archives' + ? [ + suppliedArchives[0], + suppliedArchives[2], + suppliedArchives[4], + ...suppliedArchives.slice(6), + ] + : suppliedArchives; + const chromePath = suppliedChromePath ?? process.env.OLIPHAUNT_BROWSER_CHROME; + const receiptFile = suppliedReceiptFile ?? process.env.OLIPHAUNT_BROWSER_CHROME_RECEIPT; + assert( + sdk && query && runtime && frozenConsumer && cdp && extensions && chromePath && receiptFile, + 'Expected actual SDK/query/runtime archives, existing browser fixture, explicit Chrome executable and host receipt', + ); + const receipt = await assertChromeReceipt(chromePath, receiptFile); + await writeFile( + join(directory, 'chrome-host-receipt.json'), + `${JSON.stringify(receipt, null, 2)}\n`, + ); + + const archives: Record = {}; + for (const [index, name, archive] of [ + [0, '@oliphaunt/wasix-ts', sdk], + [1, '@oliphaunt/ts-query', query], + [2, '@oliphaunt/liboliphaunt-wasix', runtime], + ] as const) { + const actual = createHash('sha256') + .update(await readFile(archive)) + .digest('hex'); + if (mode === 'archives') { + assert.equal( + resolve(archive), + archive, + `Expected absolute producer archive path for ${name}`, + ); + const expected = suppliedArchives[index * 2 + 1]; + assert.match(expected, /^[a-f0-9]{64}$/u, `Expected producer SHA256 for ${name}`); + assert.equal(actual, expected, `Actual producer archive changed: ${name}`); + } + archives[name] = { path: archive, sha256: actual }; + } + + for (const [name, archive] of [ + ['@oliphaunt/wasix-ts', sdk], + ['@oliphaunt/ts-query', query], + ['@oliphaunt/liboliphaunt-wasix', runtime], + ]) + await extractNpmPackage(archive, join(directory, 'node_modules', name)); + const manifest = JSON.parse( + await readFile(join(directory, 'node_modules/@oliphaunt/wasix-ts/package.json'), 'utf8'), + ); + assert.deepEqual( + manifest, + JSON.parse(await readFile(join(runfiles, specification.manifest), 'utf8')), + 'Actual SDK archive manifest differs from its canonical formatter output', + ); + assert.equal(manifest.name, '@oliphaunt/wasix-ts'); + const host = join(directory, 'node_modules/@oliphaunt/wasix-ts/lib/host'); + assertNativeBrowserHostProvenance( + JSON.parse(await readFile(join(host, 'provenance.json'), 'utf8')), + { + files: Object.fromEntries( + await Promise.all(HOST_FILES.map(async (name) => [name, await readFile(join(host, name))])), + ), + }, + ); + for (const name of ['@oliphaunt/ts-query', '@oliphaunt/liboliphaunt-wasix']) { + const dependency = JSON.parse( + await readFile(join(directory, 'node_modules', name, 'package.json'), 'utf8'), + ); + assert.equal(dependency.name, name); + assert.equal(dependency.version, manifest.dependencies[name]); + } + for (const [name, id] of Object.entries(specification.runtime) as [string, string][]) { + const source = acquisition[id]; + assert.equal(source.package, name); + assert.equal(source.version, manifest.dependencies[name]); + const destination = join(directory, 'node_modules', name); + await mkdir(dirname(destination), { recursive: true }); + await symlink(stores[id], destination, 'dir'); + } + await copyFile(frozenConsumer, join(directory, 'consume.mts')); + await copyFile(cdp, join(directory, 'browser-cdp.mts')); + await copyFile(extensions, join(directory, 'extensions.mts')); + for (const [name, source] of Object.entries(specification.storageFixtures) as [ + string, + string, + ][]) { + await copyFile(join(runfiles, source), join(directory, name)); + } + await mkdir(join(directory, 'public/wasix-assets'), { recursive: true }); + await copyFile( + join(runfiles, specification.seedArchive), + join(directory, 'public/wasix-assets/cluster-seed-standard'), + ); + await copyFile( + join(runfiles, specification.seedManifest), + join(directory, 'public/wasix-assets/cluster-seed-standard-manifest'), + ); + run(join(directory, 'consume.mts'), [directory, '[]', '--opfs'], { + OLIPHAUNT_BROWSER_CHROME: receipt.executable, + }); + const proof = join(directory, 'browser-consumer-receipt.json'); + await writeFile( + proof, + `${JSON.stringify({ archives, chrome: receipt, exports: ['default', 'worker'], sql: 'SELECT 42::int AS answer', answers: ['42', '42'], opfs: { answers: '1,2,3', transport: 'synchronous-access', crashAnswer: '73', crashRelations: '48' } }, null, 2)}\n`, + ); + console.log( + `Browser default and worker SQL qualified with ${receipt.version} on ${receipt.hostImage}`, + ); + console.log(proof); +} diff --git a/build_defs/wasix/browser/copy-host-assets.mts b/build_defs/wasix/browser/copy-host-assets.mts new file mode 100644 index 000000000..32c4c1243 --- /dev/null +++ b/build_defs/wasix/browser/copy-host-assets.mts @@ -0,0 +1,16 @@ +import assert from 'node:assert/strict'; +import { copyFile, mkdir, readdir } from 'node:fs/promises'; +import { basename, dirname, join } from 'node:path'; +import { HOST_FILES } from './provenance.mts'; + +const [source, ...outputs] = Bun.argv.slice(2); +const names = [...HOST_FILES, 'provenance.json']; +assert.deepEqual( + outputs.map((file) => basename(file)), + names, +); +assert.deepEqual((await readdir(source)).sort(), [...names].sort()); +for (const output of outputs) { + await mkdir(dirname(output), { recursive: true }); + await copyFile(join(source, basename(output)), output); +} diff --git a/build_defs/wasix/browser/crate-source-metadata.patch b/build_defs/wasix/browser/crate-source-metadata.patch new file mode 100644 index 000000000..aeafe3621 --- /dev/null +++ b/build_defs/wasix/browser/crate-source-metadata.patch @@ -0,0 +1,164 @@ +--- a/crate_universe/extensions.bzl ++++ b/crate_universe/extensions.bzl +@@ -529,6 +529,53 @@ + + return config + ++def _project_configured_target_features(metadata, supported_platform_triples): ++ # cargo tree already resolved configured target features; translate only ++ # predicates the platform-only generator cannot evaluate. ++ packages = {package["id"]: package for package in metadata["packages"]} ++ tree = metadata["metadata"]["cargo-bazel"]["tree_metadata"] ++ for node in metadata["resolve"]["nodes"]: ++ parent = packages[node["id"]] ++ dependencies = [] ++ for dependency in node["deps"]: ++ unsupported = [ ++ kind ++ for kind in dependency["dep_kinds"] ++ if kind["target"] and "target_feature" in kind["target"] ++ ] ++ if not unsupported: ++ dependencies.append(dependency) ++ continue ++ declarations = [ ++ declared ++ for declared in parent["dependencies"] ++ if (declared["rename"] or declared["name"]).replace("-", "_") == dependency["name"] and ++ declared["kind"] == unsupported[0]["kind"] and ++ declared["target"] == unsupported[0]["target"] ++ ] ++ if len(unsupported) != 1 or len(declarations) != 1: ++ fail("Ambiguous configured target-feature dependency in " + parent["id"]) ++ # The maintained generator already uses cargo tree for optional deps. ++ if declarations[0]["optional"]: ++ dependencies.append(dependency) ++ continue ++ if len(dependency["dep_kinds"]) != 1 or unsupported[0]["kind"] != None: ++ fail("Configured target-feature projection requires one normal dependency kind in " + parent["id"]) ++ child = packages[dependency["pkg"]] ++ child_id = child["name"] + " " + child["version"] ++ resolved = tree.get(parent["name"] + " " + parent["version"]) ++ if resolved == None: ++ fail("Missing standard Cargo tree for configured target-feature dependency in " + parent["id"]) ++ common = (resolved["common"] or {}).get("deps", []) ++ selected = [ ++ triple ++ for triple in supported_platform_triples ++ if child_id in common or child_id in resolved["selects"].get(triple, {}).get("deps", []) ++ ] ++ if selected: ++ dependencies.append(dict(dependency, dep_kinds = [{"kind": None, "target": triple} for triple in selected])) ++ node["deps"] = dependencies ++ + def _generate_hub_and_spokes( + *, + module_ctx, +@@ -575,6 +622,34 @@ + + tag_path = module_ctx.path(cfg.name) + ++ source_metadata = {} ++ if cfg.source_metadata: ++ # Source metadata is a one-way acquisition projection, never a second ++ # dependency lock. The standard splicer and generator still resolve all ++ # dependency edges and features from the conventional Cargo inputs. ++ if lockfile: ++ fail("source_metadata requires generation from the conventional Cargo lock") ++ source_metadata = json.decode(module_ctx.read(cfg.source_metadata)) ++ annotations = dict(annotations) ++ for crate_id, source in source_metadata.items(): ++ parts = crate_id.split(" ") ++ if len(parts) != 2 or sorted(source.keys()) != ["patches", "sha256", "strip_prefix", "url"]: ++ fail("Invalid immutable Cargo source metadata for " + crate_id) ++ name, version = parts ++ if ( ++ source["strip_prefix"] != name + "-" + version or ++ not source["url"].startswith("https://") or ++ len(source["sha256"]) != 64 or ++ [c for c in source["sha256"].elems() if c not in "0123456789abcdef"] ++ ): ++ fail("Invalid immutable Cargo archive identity for " + crate_id) ++ annotation = _crate_universe_crate.annotation( ++ version = version, ++ patches = [Label(patch) for patch in source["patches"]], ++ patch_args = ["-p1"], ++ ) ++ annotations[name] = list(annotations.get(name, [])) + [annotation] ++ + config_file = tag_path.get_child("config.json") + module_ctx.file( + config_file, +@@ -669,6 +744,22 @@ + "metadata": splice_outputs.metadata, + }) + ++ if source_metadata: ++ metadata = json.decode(module_ctx.read(splice_outputs.metadata)) ++ sources = metadata["metadata"]["cargo-bazel"]["sources"] ++ for crate_id, source in source_metadata.items(): ++ name, version = crate_id.split(" ") ++ packages = [ ++ p ++ for p in metadata["packages"] ++ if p["name"] == name and p["version"] == version ++ ] ++ if len(packages) != 1 or packages[0]["source"] != None or crate_id in sources: ++ fail("Immutable source must match exactly one path-patched Cargo package: " + crate_id) ++ sources[crate_id] = {"url": source["url"], "sha256": source["sha256"]} ++ _project_configured_target_features(metadata, cfg.supported_platform_triples) ++ module_ctx.file(splice_outputs.metadata, json.encode(metadata)) ++ + for path_to_track in splice_outputs.extra_paths_to_track: + # We can only watch paths in our workspace. + if path_to_track.startswith(str(nonhermetic_root_bazel_workspace_dir)): +@@ -708,12 +799,39 @@ + print("WARN: {}".format(warning)) + + crates_dir = tag_path.get_child(cfg.name) ++ if source_metadata: ++ # The generator models annotation patches as a set. Preserve the ++ # canonical series in both native HTTP spokes and the exported macro. ++ contents = json.decode(module_ctx.read(lockfile)) ++ rendered_file = crates_dir.get_child("crates.bzl") ++ rendered = module_ctx.read(rendered_file) ++ for crate_id, source in source_metadata.items(): ++ repository = contents["crates"][crate_id]["repository"]["Http"] ++ patches = repository.get("patches", []) ++ if ( ++ repository["url"] != source["url"] or ++ repository["sha256"] != source["sha256"] or ++ repository.get("patch_args") != ["-p1"] or ++ sorted(patches) != sorted(source["patches"]) ++ ): ++ fail("Generated HTTP source differs from canonical acquisition: " + crate_id) ++ if patches != source["patches"]: ++ original = " patches = [\n" + "".join([" %s,\n" % json.encode(patch) for patch in patches]) + " ]," ++ ordered = " patches = [\n" + "".join([" %s,\n" % json.encode(patch) for patch in source["patches"]]) + " ]," ++ if rendered.count(original) != 1: ++ fail("Expected one generated HTTP patch list for " + crate_id) ++ rendered = rendered.replace(original, ordered) ++ repository["patches"] = source["patches"] ++ module_ctx.file(rendered_file, rendered) ++ module_ctx.file(lockfile, json.encode(contents)) + hub_contents = { + "BUILD.bazel": module_ctx.read(crates_dir.get_child("BUILD.bazel")), + "alias_rules.bzl": module_ctx.read(crates_dir.get_child("alias_rules.bzl")), + "crates.bzl": module_ctx.read(crates_dir.get_child("crates.bzl")), + "defs.bzl": module_ctx.read(crates_dir.get_child("defs.bzl")), + } ++ if source_metadata: ++ hub_contents["cargo-bazel.json"] = module_ctx.read(lockfile) + + # Per-alias subpackages always render so users can consume + # `@//`. `module_ctx` cannot enumerate a directory, so the +@@ -1226,6 +1344,9 @@ + return module_ctx.extension_metadata(**metadata_kwargs) + + _FROM_COMMON_ATTRS = { ++ "source_metadata": attr.label( ++ doc = "One-way immutable HTTP archive identities and ordered patches for path-patched Cargo packages. Requires generation from the conventional Cargo lock, without a separate Bazel lockfile.", ++ ), + "cargo_config": CRATES_VENDOR_ATTRS["cargo_config"], + "cargo_lockfile": CRATES_VENDOR_ATTRS["cargo_lockfile"], + "generate_binaries": CRATES_VENDOR_ATTRS["generate_binaries"], diff --git a/build_defs/wasix/browser/defs.bzl b/build_defs/wasix/browser/defs.bzl new file mode 100644 index 000000000..f5df78b5d --- /dev/null +++ b/build_defs/wasix/browser/defs.bzl @@ -0,0 +1,271 @@ +"""Bounded browser compiler actions over the isolated canonical source context.""" + +load("@aspect_rules_js//npm:providers.bzl", "NpmPackageInfo") +load("//build_defs/foundation:bun-toolchain.bzl", "BUN_TOOLCHAIN_TYPE") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") +load("//build_defs/foundation:bun-sources.bzl", "bun_source_path", "bun_source_runfile", "bun_source_tree") + +_NODE_TOOLCHAIN = "@rules_nodejs//nodejs:toolchain_type" + +def _browser_wasm_transition_impl(settings, attr): + return { + "//command_line_option:platforms": "@rules_rust//rust/platform:wasm32", + "//command_line_option:compilation_mode": "opt", + "@rules_rust//rust/toolchain/channel:channel": "nightly", + "@rules_rust//rust/settings:lto": attr.lto, + } + +_browser_wasm_transition = transition( + implementation = _browser_wasm_transition_impl, + inputs = [], + outputs = ["//command_line_option:platforms", "//command_line_option:compilation_mode", "@rules_rust//rust/toolchain/channel:channel", "@rules_rust//rust/settings:lto"], +) + +def _browser_wasm_impl(ctx): + return [DefaultInfo(files = ctx.attr.crate[0][DefaultInfo].files)] + +browser_wasm = rule( + implementation = _browser_wasm_impl, + attrs = { + "crate": attr.label(mandatory = True, cfg = _browser_wasm_transition), + "lto": attr.string(mandatory = True, values = ["fat", "off"]), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), + }, +) + +def _bindings_impl(ctx): + output = ctx.actions.declare_directory(ctx.label.name) + bun_file_action( + ctx, + ctx.file._runner, + arguments = [ctx.attr.mode, ctx.file.input.path, output.path, ctx.file.compiler.path, ctx.file.context.path], + inputs = [ctx.file.input, ctx.file.context], + source_files = [], + tools = [ctx.file.compiler], + outputs = [output], + mnemonic = "BrowserWasmBindgen" if ctx.attr.mode == "bindgen" else "BrowserWasmOptimize", + ) + return [DefaultInfo(files = depset([output]))] + +browser_bindings = rule( + implementation = _bindings_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = { + "input": attr.label(mandatory = True, allow_single_file = True), + "compiler": attr.label(mandatory = True, allow_single_file = True, cfg = "exec"), + "context": attr.label(default = "@browser_sources//:metadata.json", allow_single_file = True), + "mode": attr.string(mandatory = True, values = ["bindgen", "optimize"]), + "_runner": attr.label(default = "//build_defs/wasix/browser:compile.mts", allow_single_file = True), + }, +) + +def _bundle_impl(ctx): + node = ctx.toolchains[_NODE_TOOLCHAIN].nodeinfo.node + if not node: + fail("Browser bundling requires the pinned Node toolchain") + sources = {} + for file in ctx.files.sources: + parts = file.path.split("/wasmer-js/") + if len(parts) != 2: + fail("Browser source is outside the immutable JS package: " + file.path) + sources[parts[1]] = file.path + packages = {} + package_files = [] + for target, key in ctx.attr.packages.items(): + source = target[NpmPackageInfo].src + packages[key] = source.path + package_files.append(source) + specification = ctx.actions.declare_file(ctx.label.name + ".compiler-inputs.json") + # IDs and physical package paths come from the same canonical npm lock. + ctx.actions.write(specification, json.encode({"sources": sources, "packages": packages})) + output = ctx.actions.declare_directory(ctx.label.name) + code = bun_source_tree(ctx, ctx.label.name + ".sources", [ctx.file._runner, ctx.file._driver, ctx.file._archives]) + bun_file_action( + ctx, + ctx.file._runner, + sources = code, + arguments = [ctx.file.bindings.path, output.path, node.path, ctx.file.context.path, specification.path, bun_source_path(ctx, code, ctx.file._driver)], + inputs = [ctx.file.bindings, ctx.file.context, specification] + ctx.files.sources + package_files, + tools = [node], + outputs = [output], + mnemonic = "BrowserRollup", + ) + return [DefaultInfo(files = depset([output]))] + +browser_bundle = rule( + implementation = _bundle_impl, + toolchains = BUN_SOURCE_TOOLCHAINS + [_NODE_TOOLCHAIN], + attrs = { + "bindings": attr.label(mandatory = True, allow_single_file = True), + "sources": attr.label_list(mandatory = True, allow_files = True), + "packages": attr.label_keyed_string_dict(providers = [NpmPackageInfo]), + "context": attr.label(default = "@browser_sources//:metadata.json", allow_single_file = True), + "_runner": attr.label(default = "//build_defs/wasix/browser:bundle.mts", allow_single_file = True), + "_driver": attr.label(default = "//build_defs/wasix/browser:rollup-compile.mts", allow_single_file = True), + "_archives": attr.label(default = "//build_defs/wasix/browser:npm-archives.mts", allow_single_file = True), + }, +) + +def _host_impl(ctx): + node = ctx.toolchains[_NODE_TOOLCHAIN].nodeinfo.node + if not node: + fail("Browser ABI admission requires the pinned Node toolchain") + package_files = [] + packages = {} + for target, key in ctx.attr.packages.items(): + source = target[NpmPackageInfo].src + package_files.append(source) + packages[key] = source.path + specification = ctx.actions.declare_file(ctx.label.name + ".compiler-inputs.json") + ctx.actions.write(specification, json.encode({"packages": packages})) + output = ctx.actions.declare_directory(ctx.label.name) + inputs = [ctx.file.dist, ctx.file.curated, ctx.file.license, ctx.file.std_receipt, ctx.file.context, ctx.file._node_version, specification] + package_files + code = bun_source_tree(ctx, ctx.label.name + ".sources", [ctx.file._runner, ctx.file._driver] + ctx.files._helpers) + bun_file_action( + ctx, + ctx.file._runner, + sources = code, + arguments = [ctx.file.dist.path, ctx.file.curated.path, ctx.file.license.path, ctx.file.std_receipt.path, ctx.file.context.path, node.path, ctx.file._node_version.path, specification.path, bun_source_path(ctx, code, ctx.file._driver), output.path], + inputs = inputs, + tools = [node], + outputs = [output], + mnemonic = "BrowserHostEnvelope", + ) + return [DefaultInfo(files = depset([output]))] + +browser_host_package = rule( + implementation = _host_impl, + toolchains = BUN_SOURCE_TOOLCHAINS + [_NODE_TOOLCHAIN], + attrs = { + "dist": attr.label(mandatory = True, allow_single_file = True), + "curated": attr.label(default = "//src/wasix/sdks/ts/src/host:index.d.mts", allow_single_file = True), + "license": attr.label(default = "@browser_sources//:wasmer-js/LICENSE", allow_single_file = True), + "std_receipt": attr.label(mandatory = True, allow_single_file = True), + "context": attr.label(default = "@browser_sources//:metadata.json", allow_single_file = True), + "packages": attr.label_keyed_string_dict(providers = [NpmPackageInfo]), + "_node_version": attr.label(default = "@oliphaunt_toolchain_metadata//:node-version", allow_single_file = True), + "_runner": attr.label(default = "//build_defs/wasix/browser:package-host.mts", allow_single_file = True), + "_driver": attr.label(default = "//build_defs/wasix/browser:check-host-abi.mts", allow_single_file = True), + "_helpers": attr.label_list(default = ["//build_defs/wasix/browser:npm-archives.mts", "//build_defs/wasix/browser:provenance.mts", "//build_defs/wasix/browser:metadata.mts"], allow_files = True), + }, +) + +def _host_assets_impl(ctx): + outputs = [ctx.actions.declare_file("lib/host/" + name) for name in ["index.mjs", "worker.mjs", "wasmer_js_bg.wasm", "index.d.mts", "LICENSE", "provenance.json"]] + bun_file_action( + ctx, + ctx.file._copier, + arguments = [ctx.file.host.path] + [file.path for file in outputs], + inputs = [ctx.file.host], + source_files = ctx.files._helpers, + outputs = outputs, + mnemonic = "BrowserSdkHostAssets", + ) + return [DefaultInfo(files = depset(outputs))] + +browser_host_assets = rule( + implementation = _host_assets_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = { + "host": attr.label(mandatory = True, allow_single_file = True), + "_copier": attr.label(default = "//build_defs/wasix/browser:copy-host-assets.mts", allow_single_file = True), + "_helpers": attr.label_list(default = ["//build_defs/wasix/browser:provenance.mts", "//build_defs/wasix/browser:metadata.mts"], allow_files = True), + }, +) + +def _runfile(ctx, file): + return file.short_path[3:] if file.short_path.startswith("../") else ctx.workspace_name + "/" + file.short_path + +def _consumer_launcher(ctx, mode, extra): + node = ctx.toolchains[_NODE_TOOLCHAIN].nodeinfo.node + if not node: + fail("Browser consumers require the pinned Node toolchain") + bun = ctx.toolchains[BUN_TOOLCHAIN_TYPE].bun + packages = {} + sources = [] + for target, key in ctx.attr.packages.items(): + source = target[NpmPackageInfo].src + packages[key] = _runfile(ctx, source) + sources.append(source) + specification = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + data = {"packages": packages, "roots": ctx.attr.roots} + if mode != "tools": + data["runtime"] = ctx.attr.runtime_packages + data["runtimeAcquisition"] = _runfile(ctx, ctx.file.runtime_acquisition) + data["manifest"] = _runfile(ctx, ctx.file.manifest) + sources += [ctx.file.runtime_acquisition, ctx.file.manifest] + data["storageFixtures"] = {file.basename: _runfile(ctx, file) for file in ctx.files.storage_fixtures} + data["seedArchive"] = _runfile(ctx, ctx.file.seed_archive) + data["seedManifest"] = _runfile(ctx, ctx.file.seed_manifest) + sources += ctx.files.storage_fixtures + [ctx.file.seed_archive, ctx.file.seed_manifest] + ctx.actions.write(specification, json.encode(data)) + arguments = [ctx.file._runner, specification, ctx.file.acquisition, node, ctx.file._driver] + extra + code = bun_source_tree(ctx, ctx.label.name + ".sources", [ctx.file._runner, ctx.file._driver] + ctx.files._helpers) + launcher = ctx.actions.declare_file(ctx.label.name + ".sh") + command = ['"$runfiles_dir/%s"' % bun_source_runfile(ctx, code, ctx.file._runner), mode] + ['"$runfiles_dir/%s"' % (bun_source_runfile(ctx, code, file) if file == ctx.file._driver else _runfile(ctx, file)) for file in arguments[1:]] + ctx.actions.write(launcher, """#!/usr/bin/env bash +set -euo pipefail +runfiles_dir="$(cd "${RUNFILES_DIR:-${TEST_SRCDIR:-$0.runfiles}}" && pwd)" +cd "$runfiles_dir/%s" +export OLIPHAUNT_BAZEL_RUNFILES="$runfiles_dir" +exec "$runfiles_dir/%s" --no-install --no-env-file %s "$@" +""" % (ctx.workspace_name, _runfile(ctx, bun), " ".join(command)), is_executable = True) + return [DefaultInfo(executable = launcher, runfiles = ctx.runfiles(files = arguments + sources + ctx.files._helpers + [bun], transitive_files = code.files))] + +def _consumer_tools_impl(ctx): + return _consumer_launcher(ctx, "tools", []) + +_CONSUMER_ATTRS = { + "packages": attr.label_keyed_string_dict(providers = [NpmPackageInfo]), + "roots": attr.string_dict(mandatory = True), + "acquisition": attr.label(default = "@javascript_consumer_packages//:acquisition.json", allow_single_file = True), + "_runner": attr.label(default = "//build_defs/wasix/browser:consumer.mts", allow_single_file = True), + "_driver": attr.label(default = "//build_defs/wasix/browser:consumer-tools-driver.mts", allow_single_file = True), + "_helpers": attr.label_list(default = ["//build_defs/wasix/browser:npm-archives.mts", "//build_defs/wasix/browser:chrome-receipt.mts", "//build_defs/wasix/browser:provenance.mts", "//build_defs/wasix/browser:metadata.mts"], allow_files = True), +} + +browser_consumer_tools_test = rule( + implementation = _consumer_tools_impl, + test = True, + toolchains = BUN_SOURCE_TOOLCHAINS + [_NODE_TOOLCHAIN], + attrs = _CONSUMER_ATTRS, +) + +def _consumer_impl(ctx): + return _consumer_launcher(ctx, "package", [ctx.file.sdk, ctx.file.query, ctx.file.runtime, ctx.file.fixture, ctx.file.cdp, ctx.file.extensions]) + +_SQL_CONSUMER_ATTRS = _CONSUMER_ATTRS | { + "storage_fixtures": attr.label(default = "//src/examples/wasix/browser:opfs_fixtures"), + "seed_archive": attr.label(default = "//src/database-resources:wasix_standard_archive", allow_single_file = True), + "seed_manifest": attr.label(default = "//src/database-resources:wasix_standard_manifest", allow_single_file = True), + "manifest": attr.label(mandatory = True, allow_single_file = [".json"]), + "fixture": attr.label(mandatory = True, allow_single_file = [".mts"]), + "cdp": attr.label(mandatory = True, allow_single_file = [".mts"]), + "extensions": attr.label(default = "//tools/release:frozen-extension-consumer.mts", allow_single_file = [".mts"]), + "runtime_acquisition": attr.label(default = "@javascript_packages//:acquisition.json", allow_single_file = True), + "runtime_packages": attr.string_dict(mandatory = True), +} + +_browser_sql_consumer_test = rule( + implementation = _consumer_impl, + test = True, + toolchains = BUN_SOURCE_TOOLCHAINS + [_NODE_TOOLCHAIN], + attrs = _SQL_CONSUMER_ATTRS | { + "sdk": attr.label(mandatory = True, allow_single_file = [".tgz"]), + "query": attr.label(mandatory = True, allow_single_file = [".tgz"]), + "runtime": attr.label(mandatory = True, allow_single_file = [".tgz"]), + }, +) + +def browser_sql_consumer(name, **kwargs): + _browser_sql_consumer_test(name = name, **kwargs) + +def _consumer_lifecycle_impl(ctx): + return _consumer_launcher(ctx, "archives", [ctx.file.fixture, ctx.file.cdp, ctx.file.extensions]) + +browser_sql_lifecycle = rule( + implementation = _consumer_lifecycle_impl, + executable = True, + toolchains = BUN_SOURCE_TOOLCHAINS + [_NODE_TOOLCHAIN], + attrs = _SQL_CONSUMER_ATTRS, +) diff --git a/build_defs/wasix/browser/metadata.mts b/build_defs/wasix/browser/metadata.mts new file mode 100644 index 000000000..65446f307 --- /dev/null +++ b/build_defs/wasix/browser/metadata.mts @@ -0,0 +1,379 @@ +import { createHash } from 'node:crypto'; +import { readFileSync, writeFileSync } from 'node:fs'; +import { isBuiltin } from 'node:module'; +import { dirname, join } from 'node:path'; + +type Table = Record; +const sourceNames = ['wasmer-js', 'wasmer-wasix', 'wasmer', 'virtual-fs', 'virtual-mio']; + +export function browserSources(source: Table) { + const sources = sourceNames.map((name) => { + const pin = source[name]; + if ( + !pin || + pin.name !== (name === 'wasmer-js' ? '@wasmer/sdk' : name) || + !/^\d+\.\d+\.\d+$/.test(pin.version ?? '') + ) + throw new Error(`Invalid canonical browser source ${name}`); + if (name === 'wasmer-js') { + if ( + pin.url !== 'https://github.com/wasmerio/wasmer-js.git' || + !/^[a-f0-9]{40}$/.test(pin.commit) + ) + throw new Error('Invalid immutable Wasmer JS source'); + return { ...pin, name, directory: name }; + } + if ( + pin.url !== `https://static.crates.io/crates/${name}/${name}-${pin.version}.crate` || + !/^[a-f0-9]{64}$/.test(pin.sha256) + ) + throw new Error(`Invalid immutable browser crate ${name}`); + return { ...pin, name, directory: `${name}-${pin.version}` }; + }); + const series = source.patches?.series; + if (!Array.isArray(series) || !series.length || new Set(series).size !== series.length) + throw new Error('Browser patch series must be non-empty and unique'); + const patches = series.map((name: string) => { + const match = + /^\d{4}-(wasmer-js|wasmer-wasix|wasmer|virtual-fs|virtual-mio)-[a-z0-9-]+\.patch$/.exec(name); + if (!match) throw new Error(`Unsafe canonical browser patch ${name}`); + return { name, source: match[1] }; + }); + return { sources, patches }; +} + +/** Acquisition facts for crate_universe's existing HTTP source provider. */ +export function browserCargoSources(source: Table) { + const contract = browserSources(source); + return Object.fromEntries( + contract.sources.slice(1).map((row) => [ + `${row.name} ${row.version}`, + { + url: row.url, + sha256: row.sha256, + strip_prefix: row.directory, + patches: contract.patches + .filter((patch) => patch.source === row.name) + .map((patch) => `patches/${patch.name}`), + }, + ]), + ); +} + +export function browserRustFlags(value: unknown): string[] { + const flags = typeof value === 'string' ? value.trim().split(/\s+/) : value; + if ( + !Array.isArray(flags) || + !flags.length || + flags.some((flag) => typeof flag !== 'string' || !flag) + ) + throw new Error('Canonical browser rustflags must be a non-empty Cargo argument list'); + return [...flags]; +} + +export function browserNpmAcquisition( + manifest: Table, + lock: Table, + compilerImports: string[], + platform = { os: 'linux', cpu: 'x64' }, +) { + if ( + lock.lockfileVersion !== 3 || + lock.packages?.['']?.name !== manifest.name || + lock.packages[''].version !== manifest.version + ) + throw new Error('Browser npm lock has a stale conventional package identity'); + const result: Table = {}; + const visiting = new Set(); + const accepts = (items: string[] | undefined, value: string) => + !items || + ((!items.some((item) => !item.startsWith('!')) || items.includes(value)) && + !items.includes(`!${value}`)); + function locate(parent: string, name: string): string | undefined { + let cursor = parent; + for (;;) { + const candidate = [cursor, 'node_modules', name].filter(Boolean).join('/'); + if (lock.packages[candidate]) return candidate; + if (!cursor) return undefined; + cursor = dirname(cursor).replaceAll('\\', '/'); + if (cursor === '.') cursor = ''; + if (cursor.endsWith('node_modules')) cursor = dirname(cursor).replaceAll('\\', '/'); + if (cursor === '.' || cursor === 'node_modules') cursor = ''; + } + } + function record(key: string, name: string, requirement: string): string { + const row = lock.packages[key]; + if ( + !row || + !Bun.semver.satisfies(row.version, requirement) || + !/^sha512-[A-Za-z0-9+/]+=*$/.test(row.integrity ?? '') || + row.resolved !== + `https://registry.npmjs.org/${name}/-/${name.split('/').at(-1)}-${row.version}.tgz` + ) + throw new Error(`Missing exact integrity-bearing browser npm resolution for ${key}`); + const id = `p_${createHash('sha256').update(key).digest('hex').slice(0, 16)}`; + if (result[id]) return id; + if (visiting.has(key)) throw new Error(`Browser compiler npm dependency cycle at ${key}`); + visiting.add(key); + const dependencies: Record = {}; + const requirements = { + ...row.dependencies, + ...row.optionalDependencies, + ...row.peerDependencies, + }; + for (const [dependency, range] of Object.entries(requirements) as [string, string][]) { + const child = locate(key, dependency); + const optional = + dependency in (row.optionalDependencies ?? {}) || + row.peerDependenciesMeta?.[dependency]?.optional; + if (!child) { + if (optional) continue; + throw new Error(`Missing locked browser compiler dependency ${key} -> ${dependency}`); + } + const target = lock.packages[child]; + if (!accepts(target.os, platform.os) || !accepts(target.cpu, platform.cpu)) { + if (optional) continue; + throw new Error( + `Browser compiler dependency ${child} is unavailable on ${platform.os}/${platform.cpu}`, + ); + } + dependencies[dependency] = record(child, dependency, range); + } + result[id] = { + key, + package: name, + version: row.version, + integrity: row.integrity, + url: row.resolved, + dependencies, + }; + visiting.delete(key); + return id; + } + const roots: Record = {}; + for (const name of new Set([ + ...compilerImports, + ...Object.keys(manifest.dependencies ?? {}), + 'typescript', + '@types/node', + ])) { + const requirement = manifest.dependencies?.[name] ?? manifest.devDependencies?.[name]; + const locked = + lock.packages[''].dependencies?.[name] ?? lock.packages[''].devDependencies?.[name]; + if (!requirement || locked !== requirement) + throw new Error(`Stale canonical browser npm declaration ${name}`); + const key = locate('', name); + if (!key) throw new Error(`Missing browser compiler acquisition ${name}`); + roots[name] = record(key, name, requirement); + } + return { roots, packages: result, platform }; +} + +function projectContext(root: string, source: Table, sourceFile: string) { + const contract = browserSources(source); + const js = join(root, 'wasmer-js'); + const read = (file: string) => readFileSync(join(js, file), 'utf8'); + const manifest = Bun.TOML.parse(read('Cargo.toml')); + const lockText = read('Cargo.lock'); + const lock = Bun.TOML.parse(lockText); + if ( + lock.version !== 4 || + manifest.package?.name !== 'wasmer-js' || + manifest.lib?.['crate-type']?.join(',') !== 'cdylib' + ) + throw new Error('Unexpected canonical browser Cargo construction contract'); + const patched = Object.fromEntries( + contract.sources + .filter((row) => row.name !== 'wasmer-js') + .map((row) => [ + row.name, + Bun.TOML.parse(readFileSync(join(root, row.directory, 'Cargo.toml'), 'utf8')), + ]), + ); + const originals = Object.fromEntries( + contract.sources + .filter((row) => row.name !== 'wasmer-js') + .map((row) => [ + row.name, + Bun.TOML.parse(readFileSync(join(root, '_original_manifests', `${row.name}.toml`), 'utf8')), + ]), + ); + writeFileSync( + join(js, 'Cargo.bazel.lock'), + projectPatchedCargoLock(source, patched, lockText, originals), + ); + writeFileSync(join(root, 'Cargo.bazel.toml'), browserCargoWorkspace(source, manifest)); + const npm = JSON.parse(read('package.json')); + if (npm.name !== source['wasmer-js'].name || npm.version !== source['wasmer-js'].version) + throw new Error('Canonical browser npm source version differs from the source manifest'); + const toolchain = Bun.TOML.parse(read('rust-toolchain.toml')).toolchain; + const config = Bun.TOML.parse(read('.cargo/config.toml')); + if ( + !/^nightly-\d{4}-\d{2}-\d{2}$/.test(toolchain.channel) || + config.build?.target !== 'wasm32-unknown-unknown' || + config.unstable?.['build-std']?.join(',') !== 'std,panic_abort' + ) + throw new Error('Browser requires its exact nightly wasm32 atomics sysroot construction'); + const bindgen = lock.package.filter((row: Table) => row.name === 'wasm-bindgen'); + if ( + bindgen.length !== 1 || + manifest.dependencies['wasm-bindgen'].version !== `=${bindgen[0].version}` + ) + throw new Error('Browser wasm-bindgen CLI must match its exact Cargo lock version'); + const imports = new Bun.Transpiler({ loader: 'js' }) + .scanImports(read('rollup.config.mjs')) + .map((row) => row.path) + .filter((name) => !name.startsWith('.') && !isBuiltin(name)); + const acquisition = browserNpmAcquisition(npm, JSON.parse(read('package-lock.json')), imports); + return { + ...contract, + cargoSources: browserCargoSources(source), + sourceInputs: Object.fromEntries( + [ + ['src/wasix/browser-host/source.toml', sourceFile], + ...contract.patches.map((patch) => [ + `src/wasix/browser-host/patches/${patch.name}`, + join(dirname(sourceFile), 'patches', patch.name), + ]), + ].map(([name, file]) => [ + name, + createHash('sha256').update(readFileSync(file)).digest('hex'), + ]), + ), + acquisition, + npm, + rust: { + channel: toolchain.channel, + edition: manifest.package.edition, + target: config.build.target, + flags: browserRustFlags(config.target[config.build.target].rustflags), + buildStd: config.unstable['build-std'], + profile: manifest.profile.release, + }, + bindgen: { + version: bindgen[0].version, + profile: manifest.package.metadata['wasm-pack'].profile.release['wasm-bindgen'], + }, + wasmOpt: manifest.package.metadata['wasm-pack'].profile.release['wasm-opt'], + }; +} + +/** Preserve sibling patches without making their default features workspace roots. */ +export function browserCargoWorkspace(source: Table, manifest: Table): string { + const crates = browserSources(source).sources.filter((row) => row.name !== 'wasmer-js'); + const patches = manifest.patch?.['crates-io']; + if (!patches || Object.keys(patches).length !== crates.length || manifest.workspace) + throw new Error('Unexpected canonical browser path-patch workspace'); + const lines = [ + '[workspace]', + 'members = ["wasmer-js"]', + `exclude = ${JSON.stringify(crates.map((row) => row.directory))}`, + 'resolver = "2"', + '', + '[patch.crates-io]', + ]; + for (const row of crates) { + if ( + patches[row.name]?.path !== `../${row.directory}` || + Object.keys(patches[row.name]).join(',') !== 'path' + ) + throw new Error(`Unexpected canonical browser patch path ${row.name}`); + lines.push(`${row.name} = { path = ${JSON.stringify(row.directory)} }`); + } + lines.push('', '[profile.release]'); + for (const [name, value] of Object.entries(manifest.profile.release)) { + if (!['number', 'boolean', 'string'].includes(typeof value)) + throw new Error(`Unsupported browser Cargo profile field ${name}`); + lines.push(`${name} = ${JSON.stringify(value)}`); + } + return `${lines.join('\n')}\n`; +} + +/** Keep every canonical resolution; only path-source identity and new patch edges change. */ +export function projectPatchedCargoLock( + source: Table, + manifests: Table, + original: string, + originals: Table, +): string { + const lock = Bun.TOML.parse(original); + const blocks = original.split('\n[[package]]\n'); + for (const [name, manifest] of Object.entries(manifests) as [string, Table][]) { + const pin = source[name]; + const candidates = lock.package.filter( + (row: Table) => row.name === name && row.version === pin.version, + ); + if ( + candidates.length !== 1 || + candidates[0].checksum !== pin.sha256 || + manifest.package?.name !== name || + manifest.package.version !== pin.version + ) + throw new Error( + `Patched browser Cargo source differs from its canonical lock entry: ${name}`, + ); + const row = candidates[0]; + const dependencies = [...(row.dependencies ?? [])]; + const tables = Object.entries({ root: manifest, ...manifest.target }) as [string, Table][]; + for (const [condition, table] of tables) + for (const declaration of ['dependencies', 'build-dependencies']) + for (const [alias, specification] of Object.entries(table[declaration] ?? {}) as [ + string, + any, + ][]) { + const target = specification?.package ?? alias; + const before = + condition === 'root' ? originals[name] : originals[name]?.target?.[condition]; + if (JSON.stringify(before?.[declaration]?.[alias]) === JSON.stringify(specification)) + continue; + const existing = dependencies.filter((value) => value.split(' ')[0] === target); + const requirement = + typeof specification === 'string' ? specification : specification.version; + const range = /^\d/.test(requirement) ? `^${requirement}` : requirement; + const candidates = lock.package.filter((value: Table) => value.name === target); + const matching = candidates.filter( + (value: Table) => + Bun.semver.satisfies(value.version, range) && + (!existing.length || + existing.some( + (dependency) => + (dependency === target && candidates.length === 1) || + dependency.split(' ')[1] === value.version, + )), + ); + if (matching.length !== 1) + throw new Error( + `Patch requires a missing or ambiguous canonical Cargo resolution: ${name} -> ${target}`, + ); + if (existing.length) continue; + dependencies.push( + lock.package.filter((value: Table) => value.name === target).length === 1 + ? target + : `${target} ${matching[0].version}`, + ); + } + const index = blocks.findIndex((block) => + block.startsWith(`name = "${name}"\nversion = "${pin.version}"\n`), + ); + if (index === -1) throw new Error(`Cannot project canonical browser Cargo lock block ${name}`); + blocks[index] = blocks[index].replace(/^source = .*\nchecksum = .*\n/m, '').replace( + /dependencies = \[[\s\S]*?\]/, + `dependencies = [\n${dependencies + .sort() + .map((value) => ` ${JSON.stringify(value)},`) + .join('\n')}\n]`, + ); + } + return blocks.join('\n[[package]]\n'); +} + +if (import.meta.main) { + const [mode, sourceFile, root] = Bun.argv.slice(2); + if (!sourceFile || !['sources', 'context'].includes(mode)) + throw new Error('Expected sources|context SOURCE.toml [ROOT]'); + const source = Bun.TOML.parse(readFileSync(sourceFile, 'utf8')); + const data = + mode === 'sources' ? browserSources(source) : projectContext(root, source, sourceFile); + if (mode === 'context') writeFileSync(join(root, 'metadata.json'), JSON.stringify(data)); + console.log(JSON.stringify(data)); +} diff --git a/build_defs/wasix/browser/metadata.test.mts b/build_defs/wasix/browser/metadata.test.mts new file mode 100644 index 000000000..073cc2d36 --- /dev/null +++ b/build_defs/wasix/browser/metadata.test.mts @@ -0,0 +1,173 @@ +import { expect, test } from 'bun:test'; +import { + browserCargoSources, + browserCargoWorkspace, + browserNpmAcquisition, + browserRustFlags, + browserSources, + projectPatchedCargoLock, +} from './metadata.mts'; + +function sourceFixture() { + const source: any = { + 'wasmer-js': { + name: '@wasmer/sdk', + version: '0.8.0', + url: 'https://github.com/wasmerio/wasmer-js.git', + commit: 'a'.repeat(40), + }, + patches: { series: ['0001-wasmer-js-example.patch', '0002-wasmer-example.patch'] }, + }; + for (const name of ['wasmer-wasix', 'wasmer', 'virtual-fs', 'virtual-mio']) + source[name] = { + name, + version: '6.1.0', + url: `https://static.crates.io/crates/${name}/${name}-6.1.0.crate`, + sha256: 'b'.repeat(64), + }; + return source; +} + +test('browser sources retain their separate immutable identity and ordered patch ownership', () => { + const source = sourceFixture(); + const imported = browserSources(source); + expect(imported.sources[0].directory).toBe('wasmer-js'); + expect(imported.sources[2].directory).toBe('wasmer-6.1.0'); + expect(imported.patches.map((row) => row.source)).toEqual(['wasmer-js', 'wasmer']); + source.patches.series.push('../escape.patch'); + expect(() => browserSources(source)).toThrow('Unsafe'); +}); + +test('Cargo string and array rustflags preserve the same compiler argument sequence', () => { + const flags = [ + '-Ctarget-feature=+atomics,+bulk-memory', + '-Clink-args=--no-check-features', + '--cfg=web_sys_unstable_apis', + ]; + expect(browserRustFlags(` ${flags.join(' ')}\n`)).toEqual(flags); + expect(browserRustFlags(flags)).toEqual(flags); + expect(() => browserRustFlags('')).toThrow('argument list'); + expect(() => browserRustFlags([false])).toThrow('argument list'); +}); + +test('patched Cargo HTTP identities and patch order come only from the canonical source', () => { + const source = sourceFixture(); + source.patches.series.push('0003-wasmer-next.patch'); + const projected = browserCargoSources(source); + expect(Object.keys(projected)).toHaveLength(4); + expect(projected['wasmer 6.1.0']).toEqual({ + url: source.wasmer.url, + sha256: source.wasmer.sha256, + strip_prefix: 'wasmer-6.1.0', + patches: ['patches/0002-wasmer-example.patch', 'patches/0003-wasmer-next.patch'], + }); + expect(Object.keys(projected).some((id) => id.startsWith('wasmer-js '))).toBe(false); + const duplicate = sourceFixture(); + duplicate.patches.series.push(duplicate.patches.series[0]); + expect(() => browserCargoSources(duplicate)).toThrow('unique'); + source.wasmer.sha256 = 'not-a-digest'; + expect(() => browserCargoSources(source)).toThrow('immutable'); +}); + +test('complete Cargo projection preserves path patches without extra root feature activation', () => { + const source = sourceFixture(); + const manifest: any = { + patch: { + 'crates-io': Object.fromEntries( + browserSources(source) + .sources.slice(1) + .map((row) => [row.name, { path: `../${row.directory}` }]), + ), + }, + profile: { release: { lto: true, 'opt-level': 3 } }, + }; + const projected = Bun.TOML.parse(browserCargoWorkspace(source, manifest)); + expect(projected.workspace.members).toEqual(['wasmer-js']); + expect(projected.workspace.exclude).toHaveLength(4); + expect(projected.patch['crates-io'].wasmer.path).toBe('wasmer-6.1.0'); + expect(projected.profile.release).toEqual(manifest.profile.release); + manifest.patch['crates-io'].wasmer.path = '../../ambient'; + expect(() => browserCargoWorkspace(source, manifest)).toThrow('patch path'); +}); + +function npmFixture() { + const declarations = { rollup: '^4.0.0', typescript: '^5.3.0', '@types/node': '^22.0.0' }; + const manifest = { name: '@wasmer/sdk', version: '0.8.0', devDependencies: declarations }; + const row = (name: string, version: string, extra = {}) => ({ + version, + resolved: `https://registry.npmjs.org/${name}/-/${name.split('/').at(-1)}-${version}.tgz`, + integrity: 'sha512-Ynl0ZXM=', + ...extra, + }); + const lock: any = { + lockfileVersion: 3, + packages: { + '': { name: manifest.name, version: manifest.version, devDependencies: declarations }, + 'node_modules/rollup': row('rollup', '4.20.0', { + dependencies: { helper: '^1.0.0' }, + optionalDependencies: { native: '1.0.0' }, + }), + 'node_modules/rollup/node_modules/helper': row('helper', '1.4.0'), + 'node_modules/helper': row('helper', '2.0.0'), + 'node_modules/native': row('native', '1.0.0', { os: ['darwin'], cpu: ['arm64'] }), + 'node_modules/typescript': row('typescript', '5.3.3'), + 'node_modules/@types/node': row('@types/node', '22.20.1'), + }, + }; + return { manifest, lock }; +} + +test('npm acquisition follows physical nested lock resolutions and optional compiler platforms', () => { + const { manifest, lock } = npmFixture(); + const imported = browserNpmAcquisition(manifest, lock, ['rollup']); + const rollup = imported.packages[imported.roots.rollup]; + expect(imported.packages[rollup.dependencies.helper].version).toBe('1.4.0'); + expect(rollup.dependencies.native).toBeUndefined(); + expect(Object.values(imported.packages).some((row: any) => row.version === '2.0.0')).toBe(false); + for (const mutate of [ + (value: any) => { + value.lock.packages[''].version = '0.7.0'; + }, + (value: any) => { + value.lock.packages['node_modules/typescript'].integrity = ''; + }, + (value: any) => { + value.lock.packages['node_modules/rollup/node_modules/helper'].version = '2.0.0'; + }, + ]) { + const value = npmFixture(); + mutate(value); + expect(() => browserNpmAcquisition(value.manifest, value.lock, ['rollup'])).toThrow(); + } +}); + +test('patched Cargo projection preserves exact locked versions and rejects new resolution', () => { + const checksum = 'c'.repeat(64); + const source = { wasmer: { version: '6.1.0', sha256: checksum } }; + const original = `version = 4\n\n[[package]]\nname = "wasmer"\nversion = "6.1.0"\nsource = "registry+https://github.com/rust-lang/crates.io-index"\nchecksum = "${checksum}"\ndependencies = [\n "existing",\n]\n\n[[package]]\nname = "existing"\nversion = "1.0.0"\n\n[[package]]\nname = "wasm-bindgen-futures"\nversion = "0.4.51"\nsource = "registry+https://github.com/rust-lang/crates.io-index"\nchecksum = "retained"\n`; + const before = { + package: { name: 'wasmer', version: '6.1.0' }, + dependencies: { existing: '1.0' }, + }; + const patched = { + ...before, + dependencies: { ...before.dependencies, 'wasm-bindgen-futures': '0.4.51' }, + }; + const projected = projectPatchedCargoLock(source, { wasmer: patched }, original, { + wasmer: before, + }); + const lock = Bun.TOML.parse(projected); + expect(lock.package[0].source).toBeUndefined(); + expect(lock.package[0].checksum).toBeUndefined(); + expect(lock.package[0].dependencies).toEqual(['existing', 'wasm-bindgen-futures']); + expect(lock.package.slice(1)).toEqual(Bun.TOML.parse(original).package.slice(1)); + patched.dependencies['wasm-bindgen-futures'] = '=0.4.52'; + expect(() => + projectPatchedCargoLock(source, { wasmer: patched }, original, { wasmer: before }), + ).toThrow('missing or ambiguous'); + patched.dependencies['wasm-bindgen-futures'] = '0.4.51'; + patched.dependencies.existing = '=2.0.0'; + expect(() => + projectPatchedCargoLock(source, { wasmer: patched }, original, { wasmer: before }), + ).toThrow('missing or ambiguous'); +}); diff --git a/build_defs/wasix/browser/npm-archives.mts b/build_defs/wasix/browser/npm-archives.mts new file mode 100644 index 000000000..3242e66f0 --- /dev/null +++ b/build_defs/wasix/browser/npm-archives.mts @@ -0,0 +1,64 @@ +import assert from 'node:assert/strict'; +import { cp, mkdir, readFile, writeFile } from 'node:fs/promises'; +import { dirname, join, resolve } from 'node:path'; + +export async function extractNpmPackage( + source: string, + destination: string, + { allowIdenticalAliases = false } = {}, +) { + if (!source.endsWith('.tgz')) { + await mkdir(dirname(destination), { recursive: true }); + await cp(source, destination, { recursive: true }); + return; + } + const files = await new Bun.Archive(await readFile(source)).files(); + assert(files.size > 0, `empty compiler package ${source}`); + const prefix = `${files.keys().next().value?.split('/')[0]}/`; + const names = new Map(); + for (const [name, bytes] of files) { + assert( + name.startsWith(prefix) && !name.split('/').some((part) => part === '..' || !part), + `Unsafe npm member ${name} in ${source}`, + ); + const relative = name + .slice(prefix.length) + .split('/') + .filter((part) => part !== '.') + .join('/'); + assert(relative, `Empty npm member ${name} in ${source}`); + const content = await bytes.bytes(); + const previous = names.get(relative); + if (previous) { + assert(allowIdenticalAliases, `Duplicate shipping npm member ${name} in ${source}`); + const original = files.get(previous); + assert(original); + assert( + Buffer.from(content).equals(Buffer.from(await original.bytes())), + `Conflicting npm member ${name} in ${source}`, + ); + continue; + } + names.set(relative, name); + const target = join(destination, relative); + await mkdir(dirname(target), { recursive: true }); + await writeFile(target, content, { mode: 0o644 }); + } +} + +export async function materializeCompilerPackages( + acquisition: { packages: Record }, + sources: Record, + workspace: string, +) { + assert.deepEqual(Object.keys(sources).sort(), Object.keys(acquisition.packages).sort()); + for (const [id, row] of Object.entries(acquisition.packages)) { + assert( + row.key.startsWith('node_modules/') && + !row.key.split('/').some((part) => part === '..' || part === '.'), + ); + await extractNpmPackage(resolve(sources[id]), join(workspace, row.key), { + allowIdenticalAliases: true, + }); + } +} diff --git a/build_defs/wasix/browser/package-host.mts b/build_defs/wasix/browser/package-host.mts new file mode 100644 index 000000000..66bd5c82b --- /dev/null +++ b/build_defs/wasix/browser/package-host.mts @@ -0,0 +1,74 @@ +import assert from 'node:assert/strict'; +import { cp, mkdir, mkdtemp, readFile, writeFile } from 'node:fs/promises'; +import { dirname, join, resolve } from 'node:path'; +import { materializeCompilerPackages } from './npm-archives.mts'; +import { HOST_FILES, nativeBrowserHostProvenance } from './provenance.mts'; + +const [ + dist, + curated, + license, + stdReceipt, + context, + node, + nodeVersionFile, + specificationFile, + driver, + output, +] = Bun.argv.slice(2); +assert( + dist && + curated && + license && + stdReceipt && + context && + node && + nodeVersionFile && + specificationFile && + driver && + output, +); +const metadata = JSON.parse(await readFile(context, 'utf8')); +const std = JSON.parse(await readFile(stdReceipt, 'utf8')); +const specification = JSON.parse(await readFile(specificationFile, 'utf8')); +const destination = resolve(output); +const workspace = await mkdtemp(join(dirname(destination), '.browser-host-abi-')); +await writeFile(join(workspace, 'package.json'), '{"type":"module"}\n'); +await cp(dist, join(workspace, 'generated'), { recursive: true, dereference: true }); +await mkdir(join(workspace, 'curated')); +await cp(curated, join(workspace, 'curated/index.d.mts'), { dereference: true }); +await materializeCompilerPackages(metadata.acquisition, specification.packages, workspace); +const check = Bun.spawnSync([resolve(node), resolve(driver), workspace], { + cwd: workspace, + env: { ...process.env, PATH: '', NODE_PATH: '', NODE_OPTIONS: '' }, + stdout: 'inherit', + stderr: 'inherit', +}); +assert.equal( + check.exitCode, + 0, + 'Generated browser host ABI differs from curated package declaration', +); +const checked = JSON.parse(await readFile(join(workspace, 'abi-check.json'), 'utf8')); +const nodeVersion = (await readFile(nodeVersionFile, 'utf8')).trim(); +assert.equal(checked.compatible, true); +assert.equal( + checked.typescriptVersion, + metadata.acquisition.packages[metadata.acquisition.roots.typescript].version, +); +assert.equal(checked.nodeVersion, nodeVersion); +const files: Record = {}; +for (const name of HOST_FILES) + files[name] = await readFile( + name === 'index.d.mts' ? curated : name === 'LICENSE' ? license : join(dist, name), + ); +const provenance = nativeBrowserHostProvenance( + metadata, + files, + await readFile(join(dist, 'index.d.mts')), + std, + nodeVersion, +); +await mkdir(destination, { recursive: true }); +for (const name of HOST_FILES) await writeFile(join(destination, name), files[name]); +await writeFile(join(destination, 'provenance.json'), `${JSON.stringify(provenance, null, 2)}\n`); diff --git a/build_defs/wasix/browser/provenance.mts b/build_defs/wasix/browser/provenance.mts new file mode 100644 index 000000000..2f201e18d --- /dev/null +++ b/build_defs/wasix/browser/provenance.mts @@ -0,0 +1,214 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { readFile } from 'node:fs/promises'; +import { join } from 'node:path'; +import { browserSources } from './metadata.mts'; + +export const NATIVE_BROWSER_HOST_SCHEMA = 'oliphaunt-browser-host-native-v1'; +export const HOST_FILES = [ + 'index.mjs', + 'worker.mjs', + 'wasmer_js_bg.wasm', + 'index.d.mts', + 'LICENSE', +] as const; +type Table = Record; +type SourceContract = { sources: Table[]; sourceInputs: Record }; +const sha256 = (bytes: string | Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +const digest = (value: unknown) => typeof value === 'string' && /^[a-f0-9]{64}$/.test(value); + +export function nativeBrowserSourceContract(metadata: SourceContract): SourceContract { + return { + sources: metadata.sources.map(({ archive_sha256, ...source }) => source), + sourceInputs: metadata.sourceInputs, + }; +} + +export async function readNativeBrowserSourceContract( + repositoryRoot: string, +): Promise { + const manifest = 'src/wasix/browser-host/source.toml'; + const text = await readFile(join(repositoryRoot, manifest), 'utf8'); + const source = browserSources(Bun.TOML.parse(text)); + const sourceInputs: Record = { [manifest]: sha256(text) }; + for (const patch of source.patches) { + const file = `src/wasix/browser-host/patches/${patch.name}`; + sourceInputs[file] = sha256(await readFile(join(repositoryRoot, file))); + } + return { sources: source.sources, sourceInputs }; +} + +export function nativeBrowserHostProvenance( + metadata: Table, + files: Record, + generatedDeclarations: Uint8Array, + std: Table, + nodeVersion: string, +) { + const source = nativeBrowserSourceContract(metadata as SourceContract); + const result = { + schema: NATIVE_BROWSER_HOST_SCHEMA, + source, + compilers: { + ...metadata.compilerSources, + node: { version: nodeVersion.trim() }, + npm: metadata.acquisition, + }, + rust: { ...metadata.rust, std }, + guestConcurrency: 'denied-for-oliphaunt-single-backend', + optimization: { + cargoProfile: 'release', + rustOptLevel: metadata.rust.profile['opt-level'], + lto: metadata.rust.profile.lto, + wasmOpt: metadata.wasmOpt, + }, + abi: { + curatedSha256: sha256(files['index.d.mts']), + generatedSha256: sha256(generatedDeclarations), + compatibility: 'generated-assignable-to-curated', + }, + files: Object.fromEntries( + HOST_FILES.map((name) => [ + name, + { sha256: sha256(files[name]), size: files[name].byteLength }, + ]), + ), + }; + assertNativeBrowserHostProvenance(result, { source, files }); + return result; +} + +export function assertNativeBrowserHostProvenance( + provenance: Table, + expected: { source?: SourceContract; files: Record }, +) { + assert.equal( + provenance?.schema, + NATIVE_BROWSER_HOST_SCHEMA, + 'Unsupported native browser host provenance', + ); + assert.deepEqual( + Object.keys(provenance).sort(), + [ + 'schema', + 'source', + 'compilers', + 'rust', + 'guestConcurrency', + 'optimization', + 'abi', + 'files', + ].sort(), + ); + if (expected.source) + assert.deepEqual( + provenance.source, + expected.source, + 'Native browser host canonical sources differ', + ); + assert(provenance.source?.sources?.length === 5); + const sourceInputs = provenance.source.sourceInputs; + assert(digest(sourceInputs['src/wasix/browser-host/source.toml'])); + assert(Object.values(sourceInputs).every(digest)); + const patchPaths = Object.keys(sourceInputs).filter( + (name) => name !== 'src/wasix/browser-host/source.toml', + ); + assert(patchPaths.every((name) => name.startsWith('src/wasix/browser-host/patches/'))); + const pins = Object.fromEntries( + provenance.source.sources.map((row: Table) => [ + row.name, + { ...row, name: row.name === 'wasmer-js' ? '@wasmer/sdk' : row.name }, + ]), + ); + assert.deepEqual( + browserSources({ + ...pins, + patches: { + series: patchPaths.map((name) => name.slice('src/wasix/browser-host/patches/'.length)), + }, + }).sources, + provenance.source.sources, + ); + assert.equal(provenance.guestConcurrency, 'denied-for-oliphaunt-single-backend'); + assert.deepEqual(provenance.optimization, { + cargoProfile: 'release', + rustOptLevel: provenance.rust.profile['opt-level'], + lto: provenance.rust.profile.lto, + wasmOpt: provenance.optimization.wasmOpt, + }); + assert.equal(provenance.optimization.rustOptLevel, 3); + assert.equal(provenance.optimization.lto, true); + assert.deepEqual(provenance.optimization.wasmOpt, [ + '--enable-threads', + '--enable-bulk-memory', + '-O3', + ]); + assert(/^nightly-\d{4}-\d{2}-\d{2}$/.test(provenance.rust.channel)); + assert.equal(provenance.rust.target, 'wasm32-unknown-unknown'); + assert.deepEqual(provenance.rust.buildStd, ['std', 'panic_abort']); + assert.equal(provenance.rust.std?.schema, 'oliphaunt-browser-rust-std-native-v1'); + assert.equal(provenance.rust.std.channel, provenance.rust.channel); + assert.equal(provenance.rust.std.target, provenance.rust.target); + assert.deepEqual(provenance.rust.std.buildStd, provenance.rust.buildStd); + assert(Array.isArray(provenance.rust.std.targetFeatures)); + for (const feature of ['atomics', 'bulk-memory']) + assert(provenance.rust.std.targetFeatures.includes(feature)); + assert.deepEqual(provenance.rust.std.rust, { + channel: provenance.rust.channel, + edition: provenance.rust.edition, + target: provenance.rust.target, + flags: provenance.rust.flags, + buildStd: provenance.rust.buildStd, + profile: provenance.rust.profile, + }); + assert( + digest(provenance.rust.std.compiler?.sha256) && digest(provenance.rust.std.rustSrc?.sha256), + ); + assert(/^[a-f0-9]{40}$/.test(provenance.rust.std.rustSrc.commit)); + assert(Array.isArray(provenance.rust.std.stdlib) && provenance.rust.std.stdlib.length > 0); + for (const artifact of provenance.rust.std.stdlib) + assert( + artifact.path?.startsWith(`lib/rustlib/${provenance.rust.target}/lib/`) && + !artifact.path.split('/').some((part: string) => part === '..' || part === '.') && + digest(artifact.sha256), + ); + for (const name of ['wasm-bindgen', 'wasm-opt']) + assert(provenance.compilers[name]?.version && digest(provenance.compilers[name].sha256)); + assert(/^\d+\.\d+\.\d+$/.test(provenance.compilers.node.version)); + assert.deepEqual(provenance.compilers.npm.platform, { os: 'linux', cpu: 'x64' }); + const packages = provenance.compilers.npm.packages; + for (const name of ['typescript', 'rollup', '@types/node']) + assert.equal(packages[provenance.compilers.npm.roots[name]]?.package, name); + for (const [id, row] of Object.entries(packages) as [string, Table][]) { + assert( + row.package && + row.version && + row.key.startsWith('node_modules/') && + /^sha512-[A-Za-z0-9+/]+=*$/.test(row.integrity), + ); + assert.equal( + row.url, + `https://registry.npmjs.org/${row.package}/-/${row.package.split('/').at(-1)}-${row.version}.tgz`, + ); + assert.equal(id, `p_${sha256(row.key).slice(0, 16)}`); + assert(!row.key.split('/').some((part: string) => part === '..' || part === '.')); + for (const [name, dependency] of Object.entries(row.dependencies) as [string, string][]) + assert.equal(packages[dependency]?.package, name); + } + assert.deepEqual(Object.keys(provenance.files).sort(), [...HOST_FILES].sort()); + for (const name of HOST_FILES) { + assert(expected.files[name]?.byteLength > 0, `Missing native browser payload ${name}`); + assert.deepEqual( + provenance.files[name], + { sha256: sha256(expected.files[name]), size: expected.files[name].byteLength }, + `Native browser payload ${name} differs`, + ); + } + assert.deepEqual( + Buffer.from(expected.files['wasmer_js_bg.wasm'].subarray(0, 8)), + Buffer.from([0, 97, 115, 109, 1, 0, 0, 0]), + ); + assert.equal(provenance.abi.compatibility, 'generated-assignable-to-curated'); + assert.equal(provenance.abi.curatedSha256, sha256(expected.files['index.d.mts'])); + assert(digest(provenance.abi.generatedSha256)); +} diff --git a/build_defs/wasix/browser/provenance.test.mts b/build_defs/wasix/browser/provenance.test.mts new file mode 100644 index 000000000..008e0327b --- /dev/null +++ b/build_defs/wasix/browser/provenance.test.mts @@ -0,0 +1,118 @@ +import { expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { browserSources } from './metadata.mts'; +import { + assertNativeBrowserHostProvenance, + HOST_FILES, + nativeBrowserHostProvenance, +} from './provenance.mts'; + +function fixture() { + const rust = { + channel: 'nightly-2025-07-05', + edition: '2021', + target: 'wasm32-unknown-unknown', + flags: '-Ctarget-feature=+atomics,+bulk-memory --cfg=web_sys_unstable_apis', + buildStd: ['std', 'panic_abort'], + profile: { lto: true, 'opt-level': 3 }, + }; + const std = { + schema: 'oliphaunt-browser-rust-std-native-v1', + channel: rust.channel, + target: rust.target, + buildStd: rust.buildStd, + targetFeatures: ['atomics', 'bulk-memory', 'mutable-globals'], + compiler: { sha256: 'a'.repeat(64) }, + rustSrc: { commit: 'b'.repeat(40), sha256: 'c'.repeat(64) }, + stdlib: [ + { path: 'lib/rustlib/wasm32-unknown-unknown/lib/libstd.rlib', sha256: 'd'.repeat(64) }, + ], + rust, + }; + const sourceInputs = { + 'src/wasix/browser-host/source.toml': 'e'.repeat(64), + 'src/wasix/browser-host/patches/0001-wasmer-js-example.patch': 'f'.repeat(64), + }; + const source: any = { + 'wasmer-js': { + name: '@wasmer/sdk', + version: '0.8.0', + url: 'https://github.com/wasmerio/wasmer-js.git', + commit: 'a'.repeat(40), + }, + patches: { series: ['0001-wasmer-js-example.patch'] }, + }; + for (const name of ['wasmer-wasix', 'wasmer', 'virtual-fs', 'virtual-mio']) + source[name] = { + name, + version: '6.1.0', + url: `https://static.crates.io/crates/${name}/${name}-6.1.0.crate`, + sha256: 'b'.repeat(64), + }; + const packages: Record = {}; + const roots: Record = {}; + for (const name of ['typescript', 'rollup', '@types/node']) { + const key = `node_modules/${name}`; + const id = `p_${createHash('sha256').update(key).digest('hex').slice(0, 16)}`; + roots[name] = id; + packages[id] = { + key, + package: name, + version: '1.0.0', + url: `https://registry.npmjs.org/${name}/-/${name.split('/').at(-1)}-1.0.0.tgz`, + integrity: 'sha512-Zml4dHVyZQ==', + dependencies: {}, + }; + } + const metadata = { + sources: browserSources(source).sources, + sourceInputs, + rust, + compilerSources: { + 'wasm-bindgen': { version: '0.2.101', sha256: '1'.repeat(64) }, + 'wasm-opt': { version: '117', sha256: '2'.repeat(64) }, + }, + wasmOpt: ['--enable-threads', '--enable-bulk-memory', '-O3'], + acquisition: { platform: { os: 'linux', cpu: 'x64' }, roots, packages }, + }; + const files = Object.fromEntries(HOST_FILES.map((name) => [name, Buffer.from(name)])); + files['wasmer_js_bg.wasm'] = Buffer.from([0, 97, 115, 109, 1, 0, 0, 0]); + const result = nativeBrowserHostProvenance( + metadata, + files, + Buffer.from('generated declaration fixture'), + std, + '24.14.0', + ); + return { result, files, source: { sources: metadata.sources, sourceInputs } }; +} + +test('native receipt binds payload bytes, source identities, and actual std capability', () => { + const { result, files, source } = fixture(); + expect(() => assertNativeBrowserHostProvenance(result, { source, files })).not.toThrow(); + expect(result.schema).toBe('oliphaunt-browser-host-native-v1'); + expect(result).not.toHaveProperty('inputsSha256'); + expect(result.abi.curatedSha256).toBe(result.files['index.d.mts'].sha256); + for (const mutate of [ + (value: ReturnType) => { + value.files['index.mjs'] = Buffer.from('changed'); + }, + (value: ReturnType) => { + value.result.source.sourceInputs['src/wasix/browser-host/source.toml'] = '0'.repeat(64); + }, + (value: ReturnType) => { + value.result.rust.std.targetFeatures = ['bulk-memory']; + }, + (value: ReturnType) => { + value.result.optimization.wasmOpt = ['-O2']; + }, + (value: ReturnType) => { + value.result.abi.compatibility = 'unchecked'; + }, + ]) { + const value = fixture(); + value.source = structuredClone(value.source); + mutate(value); + expect(() => assertNativeBrowserHostProvenance(value.result, value)).toThrow(); + } +}); diff --git a/build_defs/wasix/browser/repositories.bzl b/build_defs/wasix/browser/repositories.bzl new file mode 100644 index 000000000..7c675152f --- /dev/null +++ b/build_defs/wasix/browser/repositories.bzl @@ -0,0 +1,142 @@ +"""Immutable, separately patched browser source and compiler acquisition.""" + +load("@aspect_rules_js//npm:repositories.bzl", "npm_import") + +_JS_COMMIT = "93b8b738ebd3ee57e118da0f0eb795b97d5b999e" +_JS_ARCHIVE_SHA256 = "ca5df306ffcb260fb3086e89d450aafac106e200ccf7b49bb03c348bc2208712" +_BINDGEN_SHA256 = "f36a778bb0bdc5b04f6c6070ba7d0c51546a6ac7104aee302136894ac52f9e62" +_BINARYEN_SHA256 = "3dc677006555b355ea2da5e82602065a161d5e83eaefd3f759afa00b96e83212" + +def _run_metadata(ctx, arguments): + result = ctx.execute([ctx.path(ctx.attr.bun), ctx.path(ctx.attr.converter)] + arguments, quiet = True) + if result.return_code: + fail("Cannot import canonical browser construction inputs: " + result.stderr) + return json.decode(result.stdout) + +def _prefixed_patch(text, directory): + lines = [] + for line in text.splitlines(): + if line.startswith("diff --git a/"): + line = line.replace(" a/", " a/" + directory + "/").replace(" b/", " b/" + directory + "/") + elif line.startswith("--- a/") or line.startswith("+++ b/"): + line = line[:6] + directory + "/" + line[6:] + lines.append(line) + return "\n".join(lines) + "\n" + +def _sources_impl(ctx): + ctx.read(ctx.attr.source_manifest) + ctx.read(ctx.attr.converter) + ctx.watch(ctx.path(ctx.attr.bun)) + contract = _run_metadata(ctx, ["sources", ctx.path(ctx.attr.source_manifest)]) + directories = {} + for source in contract["sources"]: + directory = source["directory"] + directories[source["name"]] = directory + if source["name"] == "wasmer-js": + if source["commit"] != _JS_COMMIT: + fail("Browser JS commit changed; verify the immutable commit archive digest for this source") + ctx.download_and_extract( + url = "https://codeload.github.com/wasmerio/wasmer-js/tar.gz/" + source["commit"], + sha256 = _JS_ARCHIVE_SHA256, + type = "tar.gz", + stripPrefix = "wasmer-sdk-" + source["commit"], + output = directory, + ) + else: + ctx.download_and_extract(url = source["url"], sha256 = source["sha256"], type = "tar.gz", stripPrefix = directory, output = directory) + ctx.file("_original_manifests/" + source["name"] + ".toml", ctx.read(directory + "/Cargo.toml")) + for patch in contract["patches"]: + original = ctx.path(ctx.attr.source_manifest).dirname.get_child("patches", patch["name"]) + projected = "_patches/" + patch["name"] + ctx.file(projected, _prefixed_patch(ctx.read(original), directories[patch["source"]])) + ctx.patch(ctx.path(projected), strip = 1) + data = _run_metadata(ctx, ["context", ctx.path(ctx.attr.source_manifest), ctx.path(".")]) + for source in data["sources"]: + ctx.symlink(source["directory"], "cargo/" + source["directory"]) + ctx.file("cargo/Cargo.toml", ctx.read("Cargo.bazel.toml")) + ctx.file("cargo/Cargo.lock", ctx.read("wasmer-js/Cargo.bazel.lock")) + data["sources"][0]["archive_sha256"] = _JS_ARCHIVE_SHA256 + data["compilerSources"] = {"wasm-bindgen": {"version": data["bindgen"]["version"], "sha256": _BINDGEN_SHA256}, "wasm-opt": {"version": "117", "sha256": _BINARYEN_SHA256}} + ctx.file("metadata.json", json.encode(data)) + cargo_sources = {} + patch_prefix = str(ctx.attr.source_manifest).split(":")[0] + ":" + for crate, row in data["cargoSources"].items(): + cargo_sources[crate] = dict(row, patches = [patch_prefix + path for path in row["patches"]]) + ctx.file("cargo-sources.json", json.encode(cargo_sources)) + ctx.file("rust-construction.json", json.encode({"rust": data["rust"]})) + ctx.file("metadata.bzl", "BROWSER = " + repr(data) + "\n") + ctx.file("BUILD.bazel", """package(default_visibility = ["//visibility:public"]) +exports_files(["metadata.bzl", "metadata.json", "cargo-sources.json", "rust-construction.json", "cargo/Cargo.toml", "cargo/Cargo.lock", "wasmer-js/Cargo.toml", "wasmer-js/Cargo.lock", "wasmer-js/Cargo.bazel.lock", "wasmer-js/package.json", "wasmer-js/package-lock.json", "wasmer-js/rust-toolchain.toml", "wasmer-js/.cargo/config.toml", "wasmer-js/src/lib.rs", "wasmer-js/src-js/worker.js", "wasmer-js/LICENSE"]) +filegroup(name = "rust_sources", srcs = glob(["wasmer-js/src/**/*.rs"])) +filegroup(name = "rollup_sources", srcs = glob(["wasmer-js/src-js/**"]) + ["wasmer-js/rollup.config.mjs", "wasmer-js/tsconfig.json", "wasmer-js/package.json"]) +""") + return ctx.repo_metadata(reproducible = True) + +browser_sources_repository = repository_rule( + implementation = _sources_impl, + attrs = { + "source_manifest": attr.label(default = Label("//src/wasix/browser-host:source.toml"), allow_single_file = True), + "converter": attr.label(default = Label("//build_defs/wasix/browser:metadata.mts"), allow_single_file = True), + "bun": attr.label(default = Label("@bun_runtime//:bun"), allow_single_file = True), + }, +) + +def _compiler_tool_impl(ctx): + ctx.download_and_extract(url = ctx.attr.url, sha256 = ctx.attr.sha256, stripPrefix = ctx.attr.strip_prefix) + ctx.file("BUILD.bazel", 'exports_files([%s], visibility = ["//visibility:public"])\n' % repr(ctx.attr.binary)) + +_compiler_tool = repository_rule( + implementation = _compiler_tool_impl, + attrs = {"url": attr.string(mandatory = True), "sha256": attr.string(mandatory = True), "strip_prefix": attr.string(mandatory = True), "binary": attr.string(mandatory = True)}, +) + +def _npm_hub_impl(ctx): + metadata = json.decode(ctx.read(ctx.attr.metadata)) + acquisition = metadata["acquisition"] + lines = ["BROWSER_NPM = {"] + for key, row in acquisition["packages"].items(): + lines.append(" Label(%s): %s," % (repr("@browser_npm_" + key + "//:pkg"), repr(key))) + lines.append("}\n") + ctx.file("defs.bzl", "\n".join(lines)) + ctx.file("acquisition.json", json.encode(acquisition)) + ctx.file("BUILD.bazel", 'exports_files(["defs.bzl", "acquisition.json"], visibility = ["//visibility:public"])\n') + return ctx.repo_metadata(reproducible = True) + +_npm_hub = repository_rule(implementation = _npm_hub_impl, attrs = {"metadata": attr.label(mandatory = True)}) + +def _compilers_impl(ctx): + tags = [tag for module in ctx.modules for tag in module.tags.configure] + if len(tags) != 1: + fail("Exactly one canonical isolated browser construction context is required") + for module in ctx.modules: + if module.tags.configure and not module.is_root: + fail("Only the root module may configure browser compiler acquisition") + metadata = json.decode(ctx.read(tags[0].metadata)) + for key, row in metadata["acquisition"]["packages"].items(): + npm_import(name = "browser_npm_" + key, package = row["package"], version = row["version"], integrity = row["integrity"], lifecycle_hooks = []) + _npm_hub(name = "browser_npm", metadata = tags[0].metadata) + version = metadata["bindgen"]["version"] + if version != "0.2.101": + fail("Browser wasm-bindgen lock version changed; verify its exact CLI archive digest") + _compiler_tool( + name = "browser_wasm_bindgen_linux_x64", + url = "https://github.com/wasm-bindgen/wasm-bindgen/releases/download/%s/wasm-bindgen-%s-x86_64-unknown-linux-musl.tar.gz" % (version, version), + sha256 = _BINDGEN_SHA256, + strip_prefix = "wasm-bindgen-%s-x86_64-unknown-linux-musl" % version, + binary = "wasm-bindgen", + ) + # wasm-pack 0.15.0's installer selects Binaryen version_117; preserve that + # compiler, without its ambient PATH override or any wasm-pack scheduler. + _compiler_tool( + name = "browser_binaryen_linux_x64", + url = "https://github.com/WebAssembly/binaryen/releases/download/version_117/binaryen-version_117-x86_64-linux.tar.gz", + sha256 = _BINARYEN_SHA256, + strip_prefix = "binaryen-version_117", + binary = "bin/wasm-opt", + ) + return ctx.extension_metadata(root_module_direct_deps = ["browser_npm", "browser_wasm_bindgen_linux_x64", "browser_binaryen_linux_x64"], root_module_direct_dev_deps = [], reproducible = True) + +browser_compilers = module_extension( + implementation = _compilers_impl, + tag_classes = {"configure": tag_class(attrs = {"metadata": attr.label(mandatory = True)})}, +) diff --git a/build_defs/wasix/browser/rollup-compile.mts b/build_defs/wasix/browser/rollup-compile.mts new file mode 100644 index 000000000..7e6217118 --- /dev/null +++ b/build_defs/wasix/browser/rollup-compile.mts @@ -0,0 +1,23 @@ +import assert from 'node:assert/strict'; +import { createRequire } from 'node:module'; +import { join, resolve } from 'node:path'; +import { pathToFileURL } from 'node:url'; + +const workspace = resolve(process.argv[2]); +process.chdir(workspace); +const require = createRequire(join(workspace, 'package.json')); +const { rollup } = await import(pathToFileURL(require.resolve('rollup')).href); +const { default: configure } = await import( + pathToFileURL(join(workspace, 'rollup.config.mjs')).href +); +const configurations = configure({ environment: 'BUILD:production' }); +assert(Array.isArray(configurations) && configurations.length === 2); +for (const configuration of configurations) { + const { output, ...input } = configuration; + const bundle = await rollup(input); + try { + for (const options of Array.isArray(output) ? output : [output]) await bundle.write(options); + } finally { + await bundle.close(); + } +} diff --git a/build_defs/wasix/browser/std/BUILD.bazel b/build_defs/wasix/browser/std/BUILD.bazel new file mode 100644 index 000000000..d95c6f41b --- /dev/null +++ b/build_defs/wasix/browser/std/BUILD.bazel @@ -0,0 +1,32 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/foundation:bun.bzl", "bun_test") +load(":defs.bzl", "nightly_artifact") + +package(default_visibility = ["//visibility:public"]) +exports_files(["metadata.mts", "build-script.mts", "receipt.mts", "repositories.bzl", "defs.bzl"]) + +bun_test(name = "metadata_test", entry_point = "metadata.test.mts", data = ["metadata.mts"]) +bun_test(name = "build_script_test", entry_point = "build-script.test.mts", data = ["build-script.mts"]) +nightly_artifact(name = "stdlib", artifact = "@browser_rust_std//:stdlib", tags = ["manual"]) +nightly_artifact(name = "construction_receipt", artifact = "@browser_rust_std//:construction_receipt", tags = ["manual"]) + +# Keep registration cheap: only a selected nightly configuration loads the +# immutable compiler/source repository and constructs its actual sysroot. +toolchain( + name = "host_toolchain", + toolchain = "@browser_rust_std//:host_compiler", + toolchain_type = "@rules_rust//rust:toolchain", + target_settings = ["@rules_rust//rust/toolchain/channel:nightly"], + exec_compatible_with = ["@platforms//cpu:x86_64", "@platforms//os:linux"], + target_compatible_with = ["@platforms//cpu:x86_64", "@platforms//os:linux"], +) +toolchain( + name = "wasm_toolchain", + toolchain = "@browser_rust_std//:wasm_compiler", + toolchain_type = "@rules_rust//rust:toolchain", + target_settings = ["@rules_rust//rust/toolchain/channel:nightly"], + exec_compatible_with = ["@platforms//cpu:x86_64", "@platforms//os:linux"], + target_compatible_with = ["@platforms//cpu:wasm32", "@rules_rust//rust/platform/os:unknown"], +) + +source_quality_files() diff --git a/build_defs/wasix/browser/std/build-script.mts b/build_defs/wasix/browser/std/build-script.mts new file mode 100644 index 000000000..b79e643da --- /dev/null +++ b/build_defs/wasix/browser/std/build-script.mts @@ -0,0 +1,58 @@ +import { mkdir } from 'node:fs/promises'; +import { resolve } from 'node:path'; + +export function buildScriptDirectives(stdout: string) { + const flags: string[] = []; + const env: Record = {}; + for (const line of stdout.split('\n')) { + const directive = line.startsWith('cargo::') + ? line.slice(7) + : line.startsWith('cargo:') + ? line.slice(6) + : null; + if (directive === null) continue; + const separator = directive.indexOf('='); + if (separator < 1) throw new Error(`Invalid standard-library build directive: ${line}`); + const key = directive.slice(0, separator); + const value = directive.slice(separator + 1); + if (key === 'rustc-cfg' || key === 'rustc-check-cfg') flags.push(`--${key.slice(6)}`, value); + else if (key === 'rustc-env') { + const equal = value.indexOf('='); + if (equal < 1 || value.includes('\r')) + throw new Error(`Invalid standard-library environment directive: ${line}`); + env[value.slice(0, equal)] = value.slice(equal + 1); + } else if (key.startsWith('rustc-')) { + throw new Error(`Undeclared standard-library compiler/linker directive: ${line}`); + } + } + return { flags, env }; +} + +if (import.meta.main) { + const [, , binary, directory, output, flagsPath, envPath, compiler] = process.argv; + const cwd = resolve(directory); + const out = resolve(output); + const script = resolve(binary); + const rustc = resolve(compiler); + await mkdir(out, { recursive: true }); + const child = Bun.spawn([script], { + cwd, + env: { ...process.env, CARGO_MANIFEST_DIR: cwd, OUT_DIR: out, RUSTC: rustc }, + stdout: 'pipe', + stderr: 'pipe', + }); + const [status, stdout, stderr] = await Promise.all([ + child.exited, + new Response(child.stdout).text(), + new Response(child.stderr).text(), + ]); + if (status !== 0) throw new Error(`Standard-library build script failed (${status}): ${stderr}`); + const directives = buildScriptDirectives(stdout); + await Bun.write(flagsPath, directives.flags.join('\n') + (directives.flags.length ? '\n' : '')); + await Bun.write( + envPath, + Object.entries(directives.env) + .map(([key, value]) => `${key}=${value}`) + .join('\n') + (Object.keys(directives.env).length ? '\n' : ''), + ); +} diff --git a/build_defs/wasix/browser/std/build-script.test.mts b/build_defs/wasix/browser/std/build-script.test.mts new file mode 100644 index 000000000..6c3966e2d --- /dev/null +++ b/build_defs/wasix/browser/std/build-script.test.mts @@ -0,0 +1,17 @@ +import { expect, test } from 'bun:test'; +import { buildScriptDirectives } from './build-script.mts'; + +test('preserves native upstream cfg/check-cfg/env directives', () => { + expect( + buildScriptDirectives( + 'cargo::rustc-cfg=feature="mem"\ncargo:rustc-check-cfg=cfg(test)\ncargo:rustc-env=STD_ENV_ARCH=wasm32\ncargo:rerun-if-changed=build.rs\n', + ), + ).toEqual({ + flags: ['--cfg', 'feature="mem"', '--check-cfg', 'cfg(test)'], + env: { STD_ENV_ARCH: 'wasm32' }, + }); +}); + +test('fails closed when a source pin asks for a new native linker dependency', () => { + expect(() => buildScriptDirectives('cargo:rustc-link-lib=external')).toThrow('Undeclared'); +}); diff --git a/build_defs/wasix/browser/std/defs.bzl b/build_defs/wasix/browser/std/defs.bzl new file mode 100644 index 000000000..5df9f853e --- /dev/null +++ b/build_defs/wasix/browser/std/defs.bzl @@ -0,0 +1,209 @@ +"""Native per-crate construction of the browser's atomics-enabled Rust sysroot.""" + +load("@rules_rust//rust:defs.bzl", "rust_binary") +load("@rules_rust//rust:toolchain.bzl", "rust_stdlib_filegroup", "rust_toolchain") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") + +_StdCrateInfo = provider(fields = ["output", "closure"]) +_StdBuildInfo = provider(fields = ["flags", "environment", "out_dir"]) + +def _script_impl(ctx): + flags = ctx.actions.declare_file(ctx.label.name + ".flags") + environment = ctx.actions.declare_file(ctx.label.name + ".env") + out_dir = ctx.actions.declare_directory(ctx.label.name + ".out") + source_root = ctx.file.manifest.dirname + bun_file_action( + ctx, + ctx.file._runner, + arguments = [ctx.executable.binary.path, source_root, out_dir.path, flags.path, environment.path, ctx.file.compiler.path], + inputs = depset([ctx.file.manifest, ctx.file.compiler] + ctx.files.srcs + ctx.files.compiler_files), + source_files = [], + tools = [ctx.attr.binary[DefaultInfo].files_to_run], + outputs = [flags, environment, out_dir], + env = ctx.attr.environment, + mnemonic = "BrowserStdBuildScript", + progress_message = "Running native browser std configuration %{label}", + ) + return [DefaultInfo(files = depset([flags, environment, out_dir])), _StdBuildInfo(flags = flags, environment = environment, out_dir = out_dir)] + +_script = rule( + implementation = _script_impl, + attrs = { + "binary": attr.label(executable = True, cfg = "exec", mandatory = True), + "manifest": attr.label(allow_single_file = True, mandatory = True), + "srcs": attr.label_list(allow_files = True), + "compiler": attr.label(allow_single_file = True, mandatory = True), + "compiler_files": attr.label_list(allow_files = True), + "environment": attr.string_dict(), + "_runner": attr.label(default = Label("//build_defs/wasix/browser/std:build-script.mts"), allow_single_file = True), + }, + toolchains = BUN_SOURCE_TOOLCHAINS, +) + +def _crate_impl(ctx): + output = ctx.actions.declare_file("lib/rustlib/wasm32-unknown-unknown/lib/lib" + ctx.attr.crate_name + ".rlib") + empty = ctx.actions.declare_file(ctx.label.name + ".empty-sysroot/anchor") + ctx.actions.write(empty, "") + arguments = ctx.actions.args() + for name in ["pwd", "exec_root", "output_base"]: + arguments.add_all(["--subst", name + "=${" + name + "}"]) + if ctx.attr.build_script: + script = ctx.attr.build_script[_StdBuildInfo] + arguments.add("--env-file", script.environment) + arguments.add("--arg-file", script.flags) + arguments.add("--out-dir", script.out_dir.path) + arguments.add("--") + arguments.add(ctx.file.compiler) + arguments.add(ctx.file.crate_root) + arguments.add_all(["--crate-name", ctx.attr.crate_name, "--crate-type", "rlib", "--edition", ctx.attr.edition, "--target", "wasm32-unknown-unknown", "--sysroot", empty.dirname, "--emit=link", "--cap-lints=allow", "-Zforce-unstable-if-unmarked", "-Copt-level=" + str(ctx.attr.opt_level), "-Clto=fat", "-Clinker-plugin-lto", "-Cmetadata=oliphaunt-browser-std-" + ctx.attr.crate_name + "-" + ctx.attr.version, "-o", output.path]) + # Match rules_rust's execution-path remapping, then give this pinned + # source repository a namespace independent of its generated repo name. + # Rust applies the most specific (last) matching prefix first. + for root in ["${output_base}", "${pwd}", "${exec_root}"]: + arguments.add("--remap-path-prefix=" + root + "=.") + for root in ["${output_base}/", "${pwd}/", "${exec_root}/", ""]: + arguments.add("--remap-path-prefix=" + root + ctx.label.workspace_root + "=/oliphaunt/browser-rust-std") + arguments.add_all(ctx.attr.flags) + if ctx.attr.codegen_units: + arguments.add("-Ccodegen-units=" + str(ctx.attr.codegen_units)) + for feature in ctx.attr.crate_features: + arguments.add_all(["--cfg", 'feature="' + feature + '"']) + dependencies = [] + for target, name in ctx.attr.deps.items(): + info = target[_StdCrateInfo] + arguments.add_all(["--extern", name + "=" + info.output.path]) + dependencies.append(info.closure) + closure = depset(transitive = dependencies) + for directory in sorted({file.dirname: True for file in closure.to_list()}.keys()): + arguments.add_all(["-L", "dependency=" + directory]) + ctx.actions.run( + executable = ctx.executable._wrapper, + arguments = [arguments], + inputs = depset([empty, ctx.file.crate_root, ctx.file.compiler] + ctx.files.srcs + ctx.files.compiler_files, transitive = dependencies + ([ctx.attr.build_script[DefaultInfo].files] if ctx.attr.build_script else [])), + outputs = [output], + env = ctx.attr.environment, + mnemonic = "BrowserStdRustc", + progress_message = "Compiling atomics-enabled browser std crate %{label}", + resource_set = _resources, + ) + return [DefaultInfo(files = depset([output])), _StdCrateInfo(output = output, closure = depset([output], transitive = dependencies))] + +def _resources(os_name, inputs): + return {"cpu": 1, "memory": 768} + +_crate = rule( + implementation = _crate_impl, + attrs = { + "crate_root": attr.label(allow_single_file = [".rs"], mandatory = True), + "srcs": attr.label_list(allow_files = True), + "crate_name": attr.string(mandatory = True), + "edition": attr.string(mandatory = True), + "version": attr.string(mandatory = True), + "crate_features": attr.string_list(), + "flags": attr.string_list(), + "opt_level": attr.string(mandatory = True), + "codegen_units": attr.int(), + "deps": attr.label_keyed_string_dict(providers = [_StdCrateInfo]), + "build_script": attr.label(providers = [_StdBuildInfo]), + "compiler": attr.label(allow_single_file = True, mandatory = True), + "compiler_files": attr.label_list(allow_files = True), + "environment": attr.string_dict(), + "_wrapper": attr.label(default = Label("@rules_rust//util/process_wrapper"), executable = True, cfg = "exec"), + }, +) + +def _receipt_impl(ctx): + output = ctx.actions.declare_file("construction-receipt.json") + bun_file_action( + ctx, + ctx.file._receipt, + arguments = [ctx.file.metadata.path, output.path] + [file.path for file in ctx.files.stdlib], + inputs = [ctx.file.metadata] + ctx.files.stdlib, + source_files = [], + outputs = [output], + mnemonic = "BrowserStdReceipt", + ) + return [DefaultInfo(files = depset([output]))] + +_receipt = rule( + implementation = _receipt_impl, + attrs = { + "metadata": attr.label(allow_single_file = True, mandatory = True), + "stdlib": attr.label_list(allow_files = True), + "_receipt": attr.label(default = Label("//build_defs/wasix/browser/std:receipt.mts"), allow_single_file = True), + }, + toolchains = BUN_SOURCE_TOOLCHAINS, +) + +def browser_std(graph, rust, target_env): + """Instantiate the conventional locked std graph and two matched toolchains.""" + if rust["profile"].get("opt-level") != 3 or rust["profile"].get("lto") != True: + fail("Browser std recipe requires the canonical release opt3/fat-LTO profile") + native.filegroup(name = "compiler_files", srcs = native.glob(["bin/rustc", "lib/*.so*", "lib/rustlib/x86_64-unknown-linux-gnu/bin/**"])) + native.filegroup(name = "rustc", srcs = ["bin/rustc"]) + native.filegroup(name = "rustdoc", srcs = ["bin/rustdoc"]) + native.filegroup(name = "cargo", srcs = ["bin/cargo"]) + native.filegroup(name = "rust_lld", srcs = ["lib/rustlib/x86_64-unknown-linux-gnu/bin/rust-lld"]) + native.filegroup(name = "rustc_lib", srcs = native.glob(["lib/*.so*", "lib/rustlib/x86_64-unknown-linux-gnu/lib/*.so*"])) + rust_stdlib_filegroup(name = "host_stdlib", srcs = native.glob(["lib/rustlib/x86_64-unknown-linux-gnu/lib/*.rlib", "lib/rustlib/x86_64-unknown-linux-gnu/lib/*.so*"])) + std_sources = native.glob(["sources/lib/rustlib/src/rust/library/**"], exclude = ["**/tests/**", "**/benches/**"]) + for row in graph: + sources = std_sources if row["directory"].startswith("sources/") else native.glob([row["directory"] + "/**"], exclude = ["**/tests/**", "**/benches/**"]) + env = row["env"] | {"CARGO_CRATE_NAME": row["crate_name"]} + script = None + if row["build"]: + rust_binary( + name = row["name"] + "_build_binary", + crate_root = row["build"], + srcs = [file for file in sources if file.endswith(".rs")], + compile_data = sources, + crate_name = row["name"] + "_build", + edition = row["edition"], + version = row["version"], + crate_features = row["features"], + rustc_env = env, + rustc_flags = ["--cap-lints=allow"], + ) + build_env = env | target_env | {"HOST": "x86_64-unknown-linux-gnu", "TARGET": rust["target"], "OPT_LEVEL": str(row["profile"].get("opt-level", rust["profile"]["opt-level"])), "PROFILE": "release", "DEBUG": "false", "NUM_JOBS": "1"} + for feature in row["features"]: + build_env["CARGO_FEATURE_" + feature.replace("-", "_").upper()] = "1" + script = ":" + row["name"] + "_build" + _script(name = row["name"] + "_build", binary = ":" + row["name"] + "_build_binary", manifest = row["directory"] + "/Cargo.toml", srcs = sources, compiler = "bin/rustc", compiler_files = [":compiler_files"], environment = build_env) + _crate(name = row["name"], crate_name = row["crate_name"], crate_root = row["root"], srcs = sources, edition = row["edition"], version = row["version"], crate_features = row["features"], flags = rust["flags"] + row["profile"].get("rustflags", []), opt_level = str(row["profile"].get("opt-level", rust["profile"]["opt-level"])), codegen_units = row["profile"].get("codegen-units", 0), environment = env, deps = {":" + target: name for name, target in row["deps"].items()}, build_script = script, compiler = "bin/rustc", compiler_files = [":compiler_files"]) + rust_stdlib_filegroup(name = "stdlib", srcs = [":" + row["name"] for row in graph]) + _receipt(name = "construction_receipt", metadata = "construction.json", stdlib = [":stdlib"]) + for name, target, stdlib, flags, dylib in [("host", "x86_64-unknown-linux-gnu", ":host_stdlib", ["-Zlinker-features=-lld"], ".so"), ("wasm", rust["target"], ":stdlib", rust["flags"], ".wasm")]: + rust_toolchain( + name = name + "_compiler", + rustc = ":rustc", rust_doc = ":rustdoc", cargo = ":cargo", rustc_lib = ":rustc_lib", rust_std = stdlib, + linker = ":rust_lld", linker_type = "direct", + exec_triple = "x86_64-unknown-linux-gnu", target_triple = target, + binary_ext = "" if name == "host" else ".wasm", staticlib_ext = ".a", dylib_ext = dylib, + default_edition = "2024", stdlib_linkflags = ["-ldl", "-lpthread"] if name == "host" else [], + extra_rustc_flags = flags, extra_exec_rustc_flags = ["-Zlinker-features=-lld"] if name == "host" else [], + opt_level = {"opt": "3", "dbg": "0", "fastbuild": "0"}, + version = "1.90.0", channel = "nightly", iso_date = "2025-07-05", + ) +def _nightly_impl(settings, attr): + # A standalone std/receipt request must select the same configured producer + # as the actual browser crate; otherwise its identical sysroot compiles twice. + return { + "//command_line_option:platforms": "@rules_rust//rust/platform:wasm32", + "//command_line_option:compilation_mode": "opt", + "@rules_rust//rust/toolchain/channel:channel": "nightly", + "@rules_rust//rust/settings:lto": "fat", + } + +_nightly = transition(implementation = _nightly_impl, inputs = [], outputs = ["//command_line_option:platforms", "//command_line_option:compilation_mode", "@rules_rust//rust/toolchain/channel:channel", "@rules_rust//rust/settings:lto"]) + +def _artifact_impl(ctx): + info = ctx.attr.artifact[0][DefaultInfo] + return [DefaultInfo(files = info.files)] + +nightly_artifact = rule( + implementation = _artifact_impl, + attrs = { + "artifact": attr.label(cfg = _nightly, mandatory = True), + "_allowlist_function_transition": attr.label(default = Label("@bazel_tools//tools/allowlists/function_transition_allowlist")), + }, +) diff --git a/build_defs/wasix/browser/std/metadata.mts b/build_defs/wasix/browser/std/metadata.mts new file mode 100644 index 000000000..0496f5e43 --- /dev/null +++ b/build_defs/wasix/browser/std/metadata.mts @@ -0,0 +1,183 @@ +import { dirname, join, relative } from 'node:path'; + +type Target = { name: string; kind: string[]; src_path: string; edition: string }; +type Package = { + id: string; + name: string; + version: string; + manifest_path: string; + targets: Target[]; + authors: string[]; + description: string | null; + license: string | null; + repository: string | null; +}; +type Node = { + id: string; + features: string[]; + deps: { name: string; pkg: string; dep_kinds: { kind: string | null }[] }[]; +}; +type Metadata = { packages: Package[]; resolve: { nodes: Node[] } }; +type Profile = { + 'opt-level'?: number | string; + debug?: number; + 'codegen-units'?: number; + rustflags?: string[]; +}; + +function releaseProfile(profile: Profile): Profile { + if ( + Object.keys(profile).some( + (key) => !['opt-level', 'debug', 'codegen-units', 'rustflags'].includes(key), + ) + ) + throw new Error('Unsupported conventional standard-library package profile'); + if ( + profile['opt-level'] !== undefined && + !['0', '1', '2', '3', 's', 'z'].includes(String(profile['opt-level'])) + ) + throw new Error('Invalid conventional standard-library optimization profile'); + if (profile.debug !== undefined && profile.debug !== 0) + throw new Error( + 'Standard-library debug profile requires an explicit native construction recipe', + ); + if ( + profile['codegen-units'] !== undefined && + (!Number.isSafeInteger(profile['codegen-units']) || profile['codegen-units'] < 1) + ) + throw new Error('Invalid conventional standard-library codegen units'); + if ( + profile.rustflags !== undefined && + (!Array.isArray(profile.rustflags) || + profile.rustflags.some((flag) => typeof flag !== 'string')) + ) + throw new Error('Invalid conventional standard-library rustflags'); + return profile; +} + +function localPath(root: string, path: string): string { + const result = relative(root, path).replaceAll('\\', '/'); + if (!result || result === '..' || result.startsWith('../') || result.startsWith('/')) { + throw new Error(`Standard-library input escapes the immutable repository: ${path}`); + } + return result; +} + +export function standardLibraryGraph( + metadata: Metadata, + root: string, + profiles: Record = {}, +) { + const packages = new Map(metadata.packages.map((row) => [row.id, row])); + const nodes = new Map(metadata.resolve.nodes.map((row) => [row.id, row])); + const roots = ['std', 'panic_abort'].map((name) => { + const matching = metadata.packages.filter((row) => row.name === name); + if (matching.length !== 1) throw new Error(`Expected exactly one locked ${name} crate`); + return matching[0].id; + }); + const required = new Set(); + const pending = [...roots]; + for (const id of pending) { + if (required.has(id)) continue; + required.add(id); + const node = nodes.get(id); + if (!node) throw new Error(`Missing locked standard-library resolution: ${id}`); + for (const dependency of node.deps) { + if (dependency.dep_kinds.some((kind) => kind.kind === 'build')) { + throw new Error( + 'Standard-library native build dependencies require an explicit host compiler graph', + ); + } + if (dependency.dep_kinds.some((kind) => kind.kind === null)) pending.push(dependency.pkg); + } + } + const names = new Set(); + const rows = [...required].map((id) => { + const pkg = packages.get(id); + const node = nodes.get(id); + if (!pkg || !node || names.has(pkg.name)) + throw new Error('Ambiguous locked standard-library crate identity'); + names.add(pkg.name); + const libraries = pkg.targets.filter((target) => + target.kind.some((kind) => ['lib', 'rlib', 'dylib'].includes(kind)), + ); + const scripts = pkg.targets.filter((target) => target.kind.includes('custom-build')); + if (libraries.length !== 1 || scripts.length > 1) + throw new Error(`Unsupported standard-library targets for ${pkg.name}`); + const directory = localPath(root, dirname(pkg.manifest_path)); + const env = { + CARGO_PKG_NAME: pkg.name, + CARGO_PKG_VERSION: pkg.version, + CARGO_PKG_VERSION_MAJOR: pkg.version.split('.')[0], + CARGO_PKG_VERSION_MINOR: pkg.version.split('.')[1], + CARGO_PKG_VERSION_PATCH: pkg.version.split('.')[2].split('-')[0], + CARGO_PKG_VERSION_PRE: pkg.version.includes('-') + ? pkg.version.split('-').slice(1).join('-') + : '', + CARGO_PKG_AUTHORS: pkg.authors.join(':'), + CARGO_PKG_DESCRIPTION: pkg.description ?? '', + CARGO_PKG_LICENSE: pkg.license ?? '', + CARGO_PKG_REPOSITORY: pkg.repository ?? '', + }; + return { + name: pkg.name.replaceAll('-', '_'), + crate_name: libraries[0].name, + version: pkg.version, + directory, + root: localPath(root, libraries[0].src_path), + edition: libraries[0].edition, + build: scripts.length ? localPath(root, scripts[0].src_path) : null, + features: [...node.features].sort(), + profile: releaseProfile(profiles[pkg.name] ?? {}), + deps: Object.fromEntries( + node.deps + .filter((dependency) => dependency.dep_kinds.some((kind) => kind.kind === null)) + .map((dependency) => { + const dependencyPackage = packages.get(dependency.pkg); + if (!dependencyPackage) + throw new Error(`Missing locked standard-library package: ${dependency.pkg}`); + return [dependency.name, dependencyPackage.name.replaceAll('-', '_')]; + }), + ), + env, + }; + }); + return rows.sort((left, right) => (left.name < right.name ? -1 : left.name > right.name ? 1 : 0)); +} + +if (import.meta.main) { + const [, , input, root, host] = process.argv; + if (input === 'dist') { + const dist = Bun.TOML.parse(await Bun.file(root).text()) as { + pkg: Record< + string, + { + git_commit_hash: string; + target: Record; + } + >; + }; + const archives = Object.fromEntries( + ['rustc', 'cargo'].map((name) => { + const row = dist.pkg[name].target[host]; + if (!row?.available || !row.xz_url || !row.xz_hash) + throw new Error(`Unavailable pinned nightly metadata host ${host}`); + return [name, { url: row.xz_url, sha256: row.xz_hash }]; + }), + ); + process.stdout.write(JSON.stringify(archives)); + } else { + const manifest = Bun.TOML.parse( + await Bun.file(join(root, 'sources/lib/rustlib/src/rust/library/Cargo.toml')).text(), + ) as { profile: { release: { package: Record } } }; + if (Object.keys(manifest.profile.release).some((key) => key !== 'package')) + throw new Error( + 'Standard-library global profile requires an explicit native construction recipe', + ); + process.stdout.write( + JSON.stringify( + standardLibraryGraph(await Bun.file(input).json(), root, manifest.profile.release.package), + ), + ); + } +} diff --git a/build_defs/wasix/browser/std/metadata.test.mts b/build_defs/wasix/browser/std/metadata.test.mts new file mode 100644 index 000000000..37a16970e --- /dev/null +++ b/build_defs/wasix/browser/std/metadata.test.mts @@ -0,0 +1,75 @@ +import { expect, test } from 'bun:test'; +import { standardLibraryGraph } from './metadata.mts'; + +const pkg = (name: string) => ({ + id: name, + name, + version: '0.0.0', + manifest_path: `/immutable/library/${name}/Cargo.toml`, + targets: [ + { name, kind: ['lib'], src_path: `/immutable/library/${name}/src/lib.rs`, edition: '2024' }, + ], + authors: [], + description: null, + license: null, + repository: null, +}); +const edge = (name: string, kind: string | null = null) => ({ + name, + pkg: name, + dep_kinds: [{ kind }], +}); +const metadata = { + packages: ['std', 'panic_abort', 'core', 'dev_only'].map(pkg), + resolve: { + nodes: [ + { id: 'std', features: ['backtrace'], deps: [edge('core'), edge('dev_only', 'dev')] }, + { id: 'panic_abort', features: [], deps: [edge('core')] }, + { id: 'core', features: [], deps: [] }, + { id: 'dev_only', features: [], deps: [] }, + ], + }, +}; + +test('uses the locked normal closure and preserves conventional compiler facts', () => { + const graph = standardLibraryGraph(metadata, '/immutable'); + expect(graph.map((row) => row.name)).toEqual(['core', 'panic_abort', 'std']); + expect(graph.find((row) => row.name === 'std')).toMatchObject({ + root: 'library/std/src/lib.rs', + crate_name: 'std', + features: ['backtrace'], + deps: { core: 'core' }, + edition: '2024', + }); +}); + +test('rejects undeclared native build-dependency and external source inputs', () => { + const host = structuredClone(metadata); + host.resolve.nodes[0].deps.push(edge('dev_only', 'build')); + expect(() => standardLibraryGraph(host, '/immutable')).toThrow('explicit host compiler graph'); + const outside = structuredClone(metadata); + outside.packages[0].targets[0].src_path = '/ambient/src/lib.rs'; + expect(() => standardLibraryGraph(outside, '/immutable')).toThrow('escapes'); +}); + +test('preserves upstream per-crate release overrides and rejects unsupported profile behavior', () => { + const profiles = { + core: { 'opt-level': 's', 'codegen-units': 10000, debug: 0 }, + panic_abort: { rustflags: ['-Cpanic=abort'] }, + }; + const graph = standardLibraryGraph(metadata, '/immutable', profiles); + expect(graph.find((row) => row.name === 'core')?.profile).toEqual(profiles.core); + expect(graph.find((row) => row.name === 'panic_abort')?.profile).toEqual(profiles.panic_abort); + expect(() => standardLibraryGraph(metadata, '/immutable', { core: { debug: 2 } })).toThrow( + 'debug profile', + ); + expect(() => + standardLibraryGraph(metadata, '/immutable', { core: { 'opt-level': 'fast' } }), + ).toThrow('optimization'); + expect(() => + standardLibraryGraph(metadata, '/immutable', { core: { 'codegen-units': 0 } }), + ).toThrow('codegen'); + expect(() => + standardLibraryGraph(metadata, '/immutable', { core: { incremental: true } } as any), + ).toThrow('Unsupported'); +}); diff --git a/build_defs/wasix/browser/std/receipt.mts b/build_defs/wasix/browser/std/receipt.mts new file mode 100644 index 000000000..6a8b516c4 --- /dev/null +++ b/build_defs/wasix/browser/std/receipt.mts @@ -0,0 +1,15 @@ +import { createHash } from 'node:crypto'; +import { readFile } from 'node:fs/promises'; +import { basename } from 'node:path'; + +const [, , metadata, output, ...artifacts] = process.argv; +const receipt = await Bun.file(metadata).json(); +receipt.stdlib = await Promise.all( + artifacts.sort().map(async (path) => ({ + path: `lib/rustlib/${receipt.target}/lib/${basename(path)}`, + sha256: createHash('sha256') + .update(await readFile(path)) + .digest('hex'), + })), +); +await Bun.write(output, `${JSON.stringify(receipt)}\n`); diff --git a/build_defs/wasix/browser/std/repositories.bzl b/build_defs/wasix/browser/std/repositories.bzl new file mode 100644 index 000000000..215ca6f93 --- /dev/null +++ b/build_defs/wasix/browser/std/repositories.bzl @@ -0,0 +1,97 @@ +"""Pinned browser nightly acquisition and locked read-only std metadata import.""" + +_DATE = "2025-07-05" +_COMMIT = "e3843659e9f65f589d184d1221ac6149d5fa07b5" +_DIST_MANIFEST_SHA256 = "ee277f0e2373a6211c9f059bdc50416ab1e65538b82bfd6ab7c9075bfeac8ebd" +_ARCHIVES = { + "rustc": ("x86_64-unknown-linux-gnu", "5d38c748377f4b2e38b1a40c5972f00a1ced501d736a75bd26798f6c5acce421"), + "cargo": ("x86_64-unknown-linux-gnu", "4fd0ce38fe3b7e985c0ea5b8b53392d0ac8a3c17627ea05256082f7da01a8ec5"), + "rust-std": ("x86_64-unknown-linux-gnu", "dc65f8d9d96f2e3ea1e39093e1cd9b4e8d229bd2313ba7348555b98116233cb0"), + "rust-src": (None, "8f43ecd89129ffa4af2147f99a9fe0ec383be7391c8c61c586059e47b94be52b"), +} + +def _checked(ctx, command, environment = {}): + result = ctx.execute(command, environment = environment, quiet = True, timeout = 600) + if result.return_code: + fail("Cannot import pinned browser standard library: " + result.stderr) + return result.stdout + +def _impl(ctx): + browser = json.decode(ctx.read(ctx.attr.metadata))["rust"] + if browser["channel"] != "nightly-" + _DATE or browser["target"] != "wasm32-unknown-unknown" or browser["buildStd"] != ["std", "panic_abort"]: + fail("Browser nightly std contract changed; review its source/target construction recipe") + ctx.read(ctx.attr.converter) + ctx.watch(ctx.path(ctx.attr.bun)) + for component, (host, checksum) in _ARCHIVES.items(): + suffix = "-" + host if host else "" + archive_root = component + "-nightly" + suffix + inner = component + suffix if component == "rust-std" else component + ctx.download_and_extract( + url = "https://static.rust-lang.org/dist/%s/%s.tar.xz" % (_DATE, archive_root), + sha256 = checksum, + stripPrefix = archive_root + "/" + inner, + output = "sources" if component == "rust-src" else "", + ) + library = ctx.path("sources/lib/rustlib/src/rust/library") + cargo = ctx.path("bin/cargo") + compiler = ctx.path("bin/rustc") + # The target executor is Linux x64; acquisition metadata must also work + # when another supported host merely loads this registered toolchain. + if ctx.os.name != "linux" or ctx.os.arch not in ["amd64", "x86_64"]: + host = {("mac os x", "aarch64"): "aarch64-apple-darwin", ("mac os x", "arm64"): "aarch64-apple-darwin", ("windows", "amd64"): "x86_64-pc-windows-msvc", ("windows", "x86_64"): "x86_64-pc-windows-msvc", ("linux", "aarch64"): "aarch64-unknown-linux-gnu", ("linux", "arm64"): "aarch64-unknown-linux-gnu"}.get((ctx.os.name, ctx.os.arch)) + if not host: + fail("Unsupported browser nightly metadata host " + ctx.os.name + "/" + ctx.os.arch) + ctx.download(url = "https://static.rust-lang.org/dist/%s/channel-rust-nightly.toml" % _DATE, sha256 = _DIST_MANIFEST_SHA256, output = "_metadata_tools/dist.toml") + archives = json.decode(_checked(ctx, [str(ctx.path(ctx.attr.bun)), str(ctx.path(ctx.attr.converter)), "dist", str(ctx.path("_metadata_tools/dist.toml")), host])) + for component, row in archives.items(): + ctx.download_and_extract(url = row["url"], sha256 = row["sha256"], stripPrefix = component + "-nightly-" + host + "/" + component, output = "_metadata_tools") + suffix = ".exe" if ctx.os.name == "windows" else "" + cargo = ctx.path("_metadata_tools/bin/cargo" + suffix) + compiler = ctx.path("_metadata_tools/bin/rustc" + suffix) + else: + ctx.symlink(ctx.path("bin"), "_metadata_tools/bin") + ctx.symlink(ctx.path("lib"), "_metadata_tools/lib") + # Standard crate_universe reads this anchor's directory to find native + # host tools. Browser resolution and construction use the same nightly. + ctx.file("_metadata_tools/host-tools", "nightly-" + _DATE + "\n") + environment = { + "CARGO_HOME": str(ctx.path("_cargo")), + "HOME": str(ctx.path("_home")), + "RUSTC": str(compiler), + "CARGO_ENCODED_RUSTFLAGS": json.decode('"\\u001f"').join(browser["flags"]), + } + # Cargo is only the conventional locked resolver here. Construction below + # consists of separate native rustc and build-script actions. + version = _checked(ctx, [str(compiler), "--version", "--verbose"]) + if "commit-hash: " + _COMMIT not in version: + fail("Pinned browser nightly compiler and rust-src identities differ") + metadata = _checked(ctx, [str(cargo), "metadata", "--locked", "--no-default-features", "--filter-platform", browser["target"], "--format-version", "1", "--features", "std/backtrace,std/panic-unwind", "--manifest-path", str(library.get_child("Cargo.toml"))], environment) + ctx.file("cargo-metadata.json", metadata) + graph = json.decode(_checked(ctx, [str(ctx.path(ctx.attr.bun)), str(ctx.path(ctx.attr.converter)), str(ctx.path("cargo-metadata.json")), str(ctx.path("."))])) + cfg = _checked(ctx, [str(compiler), "--print", "cfg", "--target", browser["target"], "-Copt-level=" + str(browser["profile"]["opt-level"])] + browser["flags"]) + target_env = {} + for line in cfg.splitlines(): + key, _, value = line.partition("=") + key = "CARGO_CFG_" + key.upper() + value = value.strip('"') + target_env[key] = target_env.get(key, "") + ("," if key in target_env else "") + value + receipt = {"schema": "oliphaunt-browser-rust-std-native-v1", "channel": browser["channel"], "target": browser["target"], "buildStd": browser["buildStd"], "targetFeatures": target_env.get("CARGO_CFG_TARGET_FEATURE", "").split(","), "compiler": {"sha256": _ARCHIVES["rustc"][1]}, "rustSrc": {"commit": _COMMIT, "sha256": _ARCHIVES["rust-src"][1]}, "archives": {component: row[1] for component, row in _ARCHIVES.items()}, "rust": browser, "std_features": ["backtrace", "panic-unwind"], "stdProfiles": {row["name"]: row["profile"] for row in graph}} + ctx.file("construction.json", json.encode(receipt)) + ctx.file("graph.bzl", "GRAPH = " + repr(graph) + "\nRUST = " + repr(browser) + "\nTARGET_ENV = " + repr(target_env) + "\n") + ctx.file("BUILD.bazel", """load(%s, "browser_std") +load(":graph.bzl", "GRAPH", "RUST", "TARGET_ENV") +package(default_visibility = ["//visibility:public"]) +exports_files(["graph.bzl", "construction.json", "_metadata_tools/host-tools", "sources/lib/rustlib/src/rust/library/Cargo.toml", "sources/lib/rustlib/src/rust/library/Cargo.lock"]) +browser_std(GRAPH, RUST, TARGET_ENV) +""" % repr(str(ctx.attr.rules))) + return ctx.repo_metadata(reproducible = True) + +browser_std_repository = repository_rule( + implementation = _impl, + attrs = { + "metadata": attr.label(default = Label("@browser_sources//:rust-construction.json"), allow_single_file = True), + "converter": attr.label(default = Label("//build_defs/wasix/browser/std:metadata.mts"), allow_single_file = True), + "rules": attr.label(default = Label("//build_defs/wasix/browser/std:defs.bzl"), allow_single_file = True), + "bun": attr.label(default = Label("@bun_runtime//:bun"), allow_single_file = True), + }, +) diff --git a/build_defs/wasix/capture-cargo.mts b/build_defs/wasix/capture-cargo.mts new file mode 100644 index 000000000..16c07fd80 --- /dev/null +++ b/build_defs/wasix/capture-cargo.mts @@ -0,0 +1,196 @@ +/** Capture final WASIX core and bounded host-smoke Cargo inputs from one invocation. */ +import { + copyFileSync, + lstatSync, + mkdtempSync, + readFileSync, + renameSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { + AOT_PACKAGES, + RUNTIME_PACKAGE, +} from '../../src/wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; +import { requireSafeDirectoryChain } from '../../tools/packaging/release-directory-safety.mts'; +import { buildShippingInputView } from '../../tools/release/bazel-shipping-inputs.mts'; +import type { NativeRoot } from '../../tools/release/native-publication-artifacts.mts'; +import type { NativeCandidateCohort } from '../../tools/release/native-publication-candidate.mts'; +import { captureNativePublicationOutputs } from '../../tools/release/native-publication-staging.mts'; +import { loadPublicationCatalog } from '../../tools/release/publication-catalog.mts'; +import { sourceIdentity } from '../../tools/release/publication-lock.mts'; +import { ROOT } from '../../tools/release/release-graph.mts'; +import { + type CargoInput, + wasixHostSmokeCargoIdentities, + writeWasixCargoConstructionReceipt, +} from './cargo-inputs.mts'; + +const PRODUCT = 'liboliphaunt-wasix'; +const TARGETS = new Map([ + [RUNTIME_PACKAGE, 'portable'], + ...Object.entries(AOT_PACKAGES).map(([target, name]) => [name, target]), +]); + +function targetDirectory(relative: string) { + if ( + typeof relative !== 'string' || + !relative.startsWith('target/') || + relative.includes('\\') || + /[\u0000-\u001f\u007f]/u.test(relative) || + relative.normalize('NFC') !== relative || + relative.split('/').some((part) => !part || part === '.' || part === '..') + ) + throw new Error('WASIX Cargo capture destination must be a safe path under target/'); + return path.join(ROOT, relative); +} + +/** + * The caller captures cquery roots, their complete aquery closure, and execroot + * from one source/configuration. This copies observed final files; it does not + * certify qualification, completed-publication equivalence, or a release lock. + */ +export function captureWasixCargoConstructionInputs({ + cohorts, + outputDirectory, + headRef = 'HEAD', +}: { + cohorts: NativeCandidateCohort[]; + outputDirectory: string; + headRef?: string; +}) { + const source = sourceIdentity(headRef); + const catalog = loadPublicationCatalog('WASIX Cargo construction capture', { + products: [PRODUCT, 'postgres-tools-wasix'], + }); + const runtimeVersion = Bun.TOML.parse( + readFileSync(path.join(ROOT, 'src/wasix/runtime/crates/assets/Cargo.toml'), 'utf8'), + ).package.version; + const targets = new Map([ + ...TARGETS, + ...wasixHostSmokeCargoIdentities(ROOT, runtimeVersion).map( + (row) => [row.name, row.target] as const, + ), + ]); + const carriers = new Map( + catalog.carriers + .filter((carrier) => carrier.ecosystem === 'cargo' && targets.has(carrier.name)) + .map((carrier) => [carrier.name, carrier]), + ); + if (carriers.size !== targets.size || [...targets.keys()].some((name) => !carriers.has(name))) + throw new Error( + 'WASIX Cargo capture must match the core and contrib/tools publication carriers', + ); + if (!Array.isArray(cohorts) || !cohorts.length) + throw new Error('WASIX Cargo capture requires actual configured physical cohorts'); + const seen = new Set(); + for (const cohort of cohorts) { + if (cohort.source?.commit !== source.commit || cohort.source?.tree !== source.tree) + throw new Error('WASIX Cargo cohort differs from the exact captured source'); + if (!Array.isArray(cohort.roots) || !cohort.roots.length) + throw new Error('WASIX Cargo cohort requires actual shipping roots'); + for (const root of cohort.roots as NativeRoot[]) { + const pkg = root.package; + const carrier = carriers.get(pkg?.name); + if ( + !carrier || + seen.has(pkg.name) || + pkg.product !== carrier.product || + pkg.ecosystem !== 'cargo' || + pkg.version !== carrier.version || + pkg.role !== carrier.role || + pkg.configuration !== targets.get(pkg.name) || + pkg.outputs?.length !== 1 || + path.posix.basename(pkg.outputs[0].path) !== `${pkg.name}-${pkg.version}.crate` + ) + throw new Error(`WASIX Cargo root differs from its canonical final carrier: ${root.label}`); + seen.add(pkg.name); + } + buildShippingInputView( + { + schema: 'oliphaunt-bazel-shipping-v1', + scope: 'construction', + packages: (cohort.roots as NativeRoot[]).map((root) => root.package), + }, + cohort.aquery, + ); + } + if (seen.size !== carriers.size) + throw new Error('WASIX Cargo capture is missing a canonical final carrier'); + + const staged = captureNativePublicationOutputs(cohorts, { sourceCommit: source.commit }).stage(); + const inputs: CargoInput[] = staged.map((file) => { + if (!lstatSync(file).isFile()) + throw new Error('WASIX Cargo capture requires final regular Files'); + const name = [...carriers.keys()].find( + (candidate) => + path.basename(file) === `${candidate}-${carriers.get(candidate)?.version}.crate`, + ); + if (!name) throw new Error(`unexpected staged WASIX Cargo file: ${file}`); + const target = targets.get(name); + if (!target) throw new Error(`staged WASIX Cargo file has no canonical target: ${file}`); + return { file, name, target }; + }); + const receiptOptions = { + sourceCommit: source.commit, + sourceTree: source.tree, + releaseManifest: path.join(ROOT, 'src/wasix/runtime/release.toml'), + toolchainManifest: path.join(ROOT, 'src/wasix/runtime/toolchain.toml'), + cargoLock: path.join(ROOT, 'Cargo.lock'), + versionManifest: path.join(ROOT, 'src/wasix/runtime/crates/assets/Cargo.toml'), + sourceRoot: ROOT, + }; + const receiptFor = (values: CargoInput[]) => + writeWasixCargoConstructionReceipt( + values.filter((row) => TARGETS.has(row.name)), + { + ...receiptOptions, + hostSmokeInputs: values.filter((row) => !TARGETS.has(row.name)), + }, + ); + const captured = receiptFor(inputs); + const destination = targetDirectory(outputDirectory); + const parent = requireSafeDirectoryChain(path.dirname(destination), { + create: true, + label: 'WASIX Cargo capture', + }); + const temporary = mkdtempSync(path.join(parent, '.wasix-cargo-capture-')); + try { + const copied = inputs.map((input) => { + const file = path.join(temporary, path.basename(input.file)); + copyFileSync(input.file, file); + return { ...input, file }; + }); + const receipt = receiptFor(copied); + if ( + JSON.stringify(receipt) !== JSON.stringify(captured) || + JSON.stringify(receiptFor(inputs)) !== JSON.stringify(captured) + ) + throw new Error('WASIX Cargo files changed while copying captured construction inputs'); + writeFileSync(path.join(temporary, 'receipt.json'), `${JSON.stringify(receipt, null, 2)}\n`); + // A prior receipt directory is never overwritten by a new construction. + try { + lstatSync(destination); + throw new Error('WASIX Cargo capture destination already exists'); + } catch (cause) { + if ((cause as NodeJS.ErrnoException).code !== 'ENOENT') throw cause; + } + renameSync(temporary, destination); + return { directory: destination, receipt }; + } finally { + rmSync(temporary, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + const [cohortsFile, outputDirectory, headRef = 'HEAD', ...extra] = process.argv.slice(2); + if (!cohortsFile || !outputDirectory || extra.length) + throw new Error('usage: capture-cargo.mts COHORTS_JSON target/OUTPUT_DIRECTORY [HEAD_REF]'); + const result = captureWasixCargoConstructionInputs({ + cohorts: JSON.parse(readFileSync(cohortsFile, 'utf8')), + outputDirectory, + headRef, + }); + console.log(JSON.stringify(result)); +} diff --git a/build_defs/wasix/cargo-inputs.mts b/build_defs/wasix/cargo-inputs.mts new file mode 100644 index 000000000..ab5a1e9e3 --- /dev/null +++ b/build_defs/wasix/cargo-inputs.mts @@ -0,0 +1,536 @@ +/** Captured construction inputs for the five public WASIX runtime crates. */ +import { createHash } from 'node:crypto'; +import { + copyFileSync, + cpSync, + lstatSync, + mkdirSync, + readFileSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { isDeepStrictEqual } from 'node:util'; +import { + AOT_PACKAGES, + AOT_TARGET_TRIPLES, + RUNTIME_PACKAGE, + TOOLS_AOT_PACKAGES, + TOOLS_PACKAGE, + wasixExtensionAotPackageName, + wasixExtensionPackageName, +} from '../../src/wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; +import { stageCargoCarrierInputs } from '../../tools/packaging/frozen-cargo.mts'; +import { readPortableArchiveEntries } from '../../tools/packaging/portable-archive.mts'; +import { projectCargoWorkspace } from '../languages/cargo-metadata.mts'; +import { validatePackedRuntimeCargo } from './cargo.mts'; + +const SCHEMA = 'oliphaunt-wasix-cargo-construction-v1'; +const AOT_BY_NAME = new Map(Object.entries(AOT_PACKAGES).map(([target, name]) => [name, target])); +const PACKAGE_PATHS = new Map([ + [RUNTIME_PACKAGE, 'src/wasix/runtime/crates/assets'], + ...[...AOT_BY_NAME].map(([name, target]) => [ + name, + `src/wasix/runtime/crates/aot/${AOT_TARGET_TRIPLES[target]}`, + ]), +]); +const PACKAGE_NAMES = [...PACKAGE_PATHS.keys()].sort(); +const SHA = /^[a-f0-9]{64}$/u; +const COMMIT = /^[a-f0-9]{40}$/u; + +/** The current source owns these same public envelope identities. */ +export function wasixHostSmokeCargoIdentities(sourceRoot: string, runtimeVersion: string) { + const tools = Bun.TOML.parse( + readFileSync(path.join(sourceRoot, 'src/wasix/postgres-tools/crates/tools/Cargo.toml'), 'utf8'), + ).package; + if (tools?.name !== TOOLS_PACKAGE || typeof tools.version !== 'string' || !tools.version) + throw new Error('WASIX host smoke requires the canonical tools version manifest'); + const contrib = 'oliphaunt-extension-contrib-pg18'; + return [ + { + name: wasixExtensionPackageName(contrib), + product: 'liboliphaunt-wasix', + version: runtimeVersion, + target: 'wasix-portable', + }, + ...Object.values(AOT_TARGET_TRIPLES).map((target) => ({ + name: wasixExtensionAotPackageName(contrib, target), + product: 'liboliphaunt-wasix', + version: runtimeVersion, + target, + })), + { + name: TOOLS_PACKAGE, + product: 'postgres-tools-wasix', + version: tools.version, + target: 'portable', + }, + ...Object.entries(TOOLS_AOT_PACKAGES).map(([target, name]) => ({ + name, + product: 'postgres-tools-wasix', + version: tools.version, + target: AOT_TARGET_TRIPLES[target], + })), + ].sort((left, right) => (left.name < right.name ? -1 : left.name > right.name ? 1 : 0)); +} + +/** Validate/copy support envelopes without compiling their public Cargo source. */ +export function wasixHostSmokeCargoRows( + inputs: CargoInput[], + sourceRoot: string, + runtimeVersion: string, +) { + const expected = wasixHostSmokeCargoIdentities(sourceRoot, runtimeVersion); + if ( + !Array.isArray(inputs) || + inputs.length !== expected.length || + new Set(inputs.map((row) => row.name)).size !== inputs.length + ) + throw new Error( + 'WASIX host smoke requires exactly the ten canonical contrib/tools Cargo archives', + ); + return expected.map((identity) => { + const input = inputs.find((row) => row.name === identity.name); + if (!input || input.target !== identity.target || !path.isAbsolute(input.file)) + throw new Error(`WASIX host smoke Cargo target differs: ${identity.name}`); + const stat = lstatSync(input.file); + if ( + !stat.isFile() || + stat.isSymbolicLink() || + path.basename(input.file) !== `${identity.name}-${identity.version}.crate` + ) + throw new Error(`WASIX host smoke requires a canonical regular Cargo file: ${identity.name}`); + readCargoManifest(input.file, identity.name, identity.version); + const bytes = readFileSync(input.file); + return { + ...identity, + path: path.basename(input.file), + size: bytes.length, + sha256: sha256(bytes), + }; + }); +} + +function sha256(bytes: Uint8Array) { + return createHash('sha256').update(bytes).digest('hex'); +} + +function readCargoManifest(archive: string, name: string, version?: string) { + const entries = readPortableArchiveEntries(archive); + const roots = [...entries.values()].filter( + (entry) => entry.isFile && /^[^/]+\/Cargo\.toml$/u.test(entry.name), + ); + if (roots.length !== 1) throw new Error(`${name} crate must contain one root Cargo.toml`); + const root = roots[0].name.split('/')[0]; + if (version !== undefined && root !== `${name}-${version}`) + throw new Error(`${name} archive root differs from its declared version`); + const manifest = Bun.TOML.parse(roots[0].data().toString('utf8')); + if ( + manifest.package?.name !== name || + (version !== undefined && manifest.package.version !== version) + ) + throw new Error(`WASIX Cargo archive identity differs: ${name}`); + return { entries, manifest, root }; +} + +function expectedTarget(name: string) { + if (name === RUNTIME_PACKAGE) return 'portable'; + const target = AOT_BY_NAME.get(name); + if (!target) throw new Error(`unknown WASIX Cargo carrier ${name}`); + return target; +} + +function expectedRole(name: string) { + return name === RUNTIME_PACKAGE ? 'platform-leaf' : 'aot-leaf'; +} + +function expectedKind(name: string) { + return name === RUNTIME_PACKAGE ? 'wasix-runtime' : 'wasix-aot'; +} + +function expectedLinks(name: string) { + if (name === RUNTIME_PACKAGE) return 'oliphaunt_artifact_liboliphaunt_wasix_runtime'; + return `oliphaunt_artifact_liboliphaunt_wasix_aot_${expectedTarget(name).replaceAll('-', '_')}`; +} + +function exactRows(rows: CargoInput[]) { + if (!Array.isArray(rows) || rows.length !== PACKAGE_NAMES.length) + throw new Error('WASIX construction receipt requires exactly five Cargo archives'); + const byName = new Map(); + for (const row of rows) { + if (!row || typeof row.name !== 'string' || byName.has(row.name)) + throw new Error('WASIX construction receipt has duplicate or invalid package names'); + if (row.target !== expectedTarget(row.name)) + throw new Error(`WASIX Cargo target differs for ${row.name}`); + if (!path.isAbsolute(row.file)) + throw new Error(`WASIX Cargo archive path must be absolute: ${row.name}`); + byName.set(row.name, row); + } + if (PACKAGE_NAMES.some((name) => !byName.has(name))) + throw new Error('WASIX construction receipt is missing a canonical Cargo archive'); + return PACKAGE_NAMES.map((name) => byName.get(name)!); +} + +export type CargoInput = { file: string; name: string; target: string }; + +/** Write a deterministic receipt over final copied .crate envelopes. */ +export function writeWasixCargoConstructionReceipt( + inputs: CargoInput[], + { + sourceCommit, + sourceTree, + releaseManifest, + toolchainManifest, + cargoLock, + versionManifest, + hostSmokeInputs, + sourceRoot, + }: { + sourceCommit: string; + sourceTree: string; + releaseManifest: string; + toolchainManifest: string; + cargoLock: string; + versionManifest: string; + hostSmokeInputs?: CargoInput[]; + sourceRoot?: string; + }, +) { + if (!COMMIT.test(sourceCommit) || !COMMIT.test(sourceTree)) + throw new Error('WASIX construction receipt requires exact source commit and tree SHAs'); + const release = Bun.TOML.parse(readFileSync(releaseManifest, 'utf8')); + if (release.id !== 'liboliphaunt-wasix') + throw new Error('WASIX construction receipt release identity is not canonical'); + const versionManifestData = Bun.TOML.parse(readFileSync(versionManifest, 'utf8')); + const version = versionManifestData.package?.version; + if ( + versionManifestData.package?.name !== RUNTIME_PACKAGE || + typeof version !== 'string' || + !version + ) + throw new Error('WASIX version manifest has no canonical package version'); + const releaseCrates = (release.registry_packages ?? []) + .filter((name: string) => name.startsWith('crates:')) + .map((name: string) => name.slice('crates:'.length)) + .sort(); + if (JSON.stringify(releaseCrates) !== JSON.stringify(PACKAGE_NAMES)) + throw new Error('WASIX release manifest does not declare the canonical five Cargo carriers'); + const rows = exactRows(inputs).map(({ file, name, target }) => { + const stat = lstatSync(file); + if (!stat.isFile() || stat.isSymbolicLink()) + throw new Error(`WASIX Cargo archive must be a regular file: ${name}`); + const bytes = readFileSync(file); + const { manifest } = readCargoManifest(file, name); + if ( + manifest.package.version !== version || + manifest.package.links !== expectedLinks(name) || + path.basename(file) !== `${name}-${version}.crate` + ) + throw new Error(`WASIX Cargo version differs from release manifest: ${name}`); + return { + name, + version, + target, + kind: expectedKind(name), + role: expectedRole(name), + path: path.basename(file), + size: bytes.length, + sha256: sha256(bytes), + }; + }); + if (hostSmokeInputs && !sourceRoot) + throw new Error('WASIX host smoke requires its declared conventional source manifests'); + const hostSmokeCrates = + hostSmokeInputs && sourceRoot + ? wasixHostSmokeCargoRows(hostSmokeInputs, sourceRoot, version) + : undefined; + return { + schema: SCHEMA, + source: { commit: sourceCommit, tree: sourceTree }, + product: release.id, + version, + releaseManifestSha256: sha256(readFileSync(releaseManifest)), + toolchainManifestSha256: sha256(readFileSync(toolchainManifest)), + cargoLockSha256: sha256(readFileSync(cargoLock)), + versionManifestSha256: sha256(readFileSync(versionManifest)), + crates: rows, + ...(hostSmokeCrates ? { hostSmokeCrates } : {}), + }; +} + +function starlark(value: unknown): string { + if (value === null) return 'None'; + if (value === true) return 'True'; + if (value === false) return 'False'; + if (Array.isArray(value)) return `[${value.map(starlark).join(', ')}]`; + if (typeof value === 'object') + return `{${Object.entries(value as Record) + .map(([key, item]) => `${JSON.stringify(key)}: ${starlark(item)}`) + .join(', ')}}`; + return JSON.stringify(value); +} + +/** Verify, privately extract, and project the exact packed source into a Bazel repo. */ +export function extractWasixCargoConstructionInputs( + receipt: unknown, + inputDirectory: string, + expectedSourceCommit: string, + outputDirectory: string, + { + releaseManifest, + toolchainManifest, + cargoLock, + versionManifest, + rustDefs, + cratesDefs, + sourceRoot, + }: { + releaseManifest: string; + toolchainManifest: string; + cargoLock: string; + versionManifest: string; + rustDefs: string; + cratesDefs: string; + sourceRoot: string; + }, +) { + const value = receipt as any; + if ( + !value || + value.schema !== SCHEMA || + value.product !== 'liboliphaunt-wasix' || + !COMMIT.test(expectedSourceCommit) || + value.source?.commit !== expectedSourceCommit || + !COMMIT.test(value.source?.tree ?? '') || + value.releaseManifestSha256 !== sha256(readFileSync(releaseManifest)) || + value.toolchainManifestSha256 !== sha256(readFileSync(toolchainManifest)) || + value.cargoLockSha256 !== sha256(readFileSync(cargoLock)) || + value.versionManifestSha256 !== sha256(readFileSync(versionManifest)) + ) + throw new Error('WASIX construction receipt does not match the exact source inputs'); + const rows = exactRows( + (value.crates ?? []).map((row: any) => ({ + file: path.resolve(inputDirectory, row.path ?? ''), + name: row.name, + target: row.target, + })), + ); + if (rows.some((row, index) => row.name !== value.crates[index]?.name)) + throw new Error('WASIX construction receipt crates must use canonical ordering'); + const release = Bun.TOML.parse(readFileSync(releaseManifest, 'utf8')); + const versionPackage = Bun.TOML.parse(readFileSync(versionManifest, 'utf8')).package; + const declaredVersion = versionPackage?.version; + if ( + release.id !== value.product || + versionPackage?.name !== RUNTIME_PACKAGE || + declaredVersion !== value.version + ) + throw new Error('WASIX construction receipt version differs from release manifest'); + for (const row of value.crates) { + if ( + row.version !== value.version || + row.kind !== expectedKind(row.name) || + row.role !== expectedRole(row.name) || + !Number.isSafeInteger(row.size) || + row.size <= 0 || + !SHA.test(row.sha256) || + path.basename(row.path) !== row.path || + !row.path.endsWith('.crate') + ) + throw new Error(`invalid WASIX Cargo receipt row: ${row.name}`); + const file = path.join(inputDirectory, row.path); + const stat = lstatSync(file); + if (!stat.isFile() || stat.isSymbolicLink()) + throw new Error(`WASIX Cargo archive must be a regular file: ${row.name}`); + if (row.path !== `${row.name}-${row.version}.crate`) + throw new Error(`WASIX Cargo archive filename differs: ${row.name}`); + const bytes = readFileSync(file); + if (bytes.length !== row.size || sha256(bytes) !== row.sha256) + throw new Error(`WASIX Cargo archive hash differs: ${row.name}`); + const { manifest } = readCargoManifest(file, row.name, row.version); + if (manifest.package.links !== expectedLinks(row.name)) + throw new Error(`WASIX Cargo links identity differs: ${row.name}`); + } + if (value.hostSmokeCrates !== undefined) { + if ( + !Array.isArray(value.hostSmokeCrates) || + value.hostSmokeCrates.some( + (row: any) => row?.path !== `${row?.name}-${row?.version}.crate` || /[\\/]/u.test(row.path), + ) + ) + throw new Error('WASIX host smoke receipt requires canonical regular archive filenames'); + const support = wasixHostSmokeCargoRows( + value.hostSmokeCrates.map((row: any) => ({ + name: row.name, + target: row.target, + file: path.join(inputDirectory, row.path ?? ''), + })), + sourceRoot, + value.version, + ); + if (!isDeepStrictEqual(support, value.hostSmokeCrates)) + throw new Error('WASIX host smoke Cargo identities or hashes differ from the receipt'); + const supportDirectory = path.join(outputDirectory, 'host-smoke'); + mkdirSync(supportDirectory, { recursive: true }); + for (const row of [ + ...value.crates.filter((row: any) => row.name === RUNTIME_PACKAGE), + ...support, + ]) + copyFileSync(path.join(inputDirectory, row.path), path.join(supportDirectory, row.path)); + } + mkdirSync(outputDirectory, { recursive: true }); + const staged = path.join(outputDirectory, '.staged'); + stageCargoCarrierInputs( + value.crates.map((row: any) => ({ + file: path.join(inputDirectory, row.path), + name: row.name, + version: row.version, + sha256: row.sha256, + })), + staged, + ); + const workspace = { + workspace: { members: PACKAGE_NAMES.map((name) => PACKAGE_PATHS.get(name)), resolver: '3' }, + }; + const lock = Bun.TOML.parse(readFileSync(cargoLock, 'utf8')); + const manifests = new Map(); + for (const name of PACKAGE_NAMES) { + const stagedPath = path.join(staged, 'crates', `${name}-${value.version}`); + const memberPath = PACKAGE_PATHS.get(name)!; + const destination = path.join(outputDirectory, memberPath); + mkdirSync(path.dirname(destination), { recursive: true }); + cpSync(stagedPath, destination, { recursive: true, errorOnExist: true, force: false }); + const manifest = Bun.TOML.parse(readFileSync(path.join(destination, 'Cargo.toml'), 'utf8')); + if (manifest.workspace && Object.keys(manifest.workspace).length) + throw new Error(`${name} packed workspace metadata is not empty`); + delete manifest.workspace; + manifests.set(memberPath, manifest); + const target = expectedTarget(name); + validatePackedRuntimeCargo( + destination, + { packageName: name, target: target === 'portable' ? null : target }, + sourceRoot, + ); + } + const projection = projectCargoWorkspace( + workspace, + lock, + PACKAGE_NAMES.map((name) => PACKAGE_PATHS.get(name)!), + (relative) => { + const member = path.posix.dirname(relative); + if (relative.endsWith('/Cargo.toml')) return manifests.get(member); + throw new Error(`unexpected projected Cargo manifest: ${relative}`); + }, + (relative) => { + const file = path.join(outputDirectory, relative); + try { + return readFileSync(file).length >= 0; + } catch { + return false; + } + }, + ); + for (const [relative, contents] of Object.entries(projection.files)) { + if (relative === 'Cargo.lock' || relative !== 'Cargo.toml') continue; + const file = path.join(outputDirectory, relative); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, contents); + } + cpSync(cargoLock, path.join(outputDirectory, 'Cargo.lock')); + writeFileSync(path.join(outputDirectory, 'cargo-facts.json'), JSON.stringify(projection.facts)); + const rootBuild = [ + 'package(default_visibility = ["//visibility:public"])', + 'exports_files(["Cargo.toml", "Cargo.lock", "cargo.bzl", "cargo-facts.json"])', + 'filegroup(name = "host_smoke", srcs = glob(["host-smoke/*.crate"]))', + '', + ].join('\n'); + writeFileSync(path.join(outputDirectory, 'BUILD.bazel'), rootBuild); + writeFileSync( + path.join(outputDirectory, 'cargo.bzl'), + `CARGO = ${starlark(projection.facts)}\n\ndef packed_cargo_manifest_dir():\n return Label("//:Cargo.toml").workspace_root + "/" + native.package_name()\n`, + ); + for (const name of PACKAGE_NAMES) { + const memberPath = PACKAGE_PATHS.get(name)!; + const payload = name === RUNTIME_PACKAGE ? 'payload/**' : 'artifacts/**'; + const build = [ + `load(${JSON.stringify(rustDefs)}, "cargo_generator", "cargo_library", "cargo_package_env")`, + `load(${JSON.stringify(cratesDefs)}, "crate_deps")`, + `load("//:cargo.bzl", "CARGO", "packed_cargo_manifest_dir")`, + 'package(default_visibility = ["//visibility:public"])', + 'exports_files(["Cargo.toml"])', + `filegroup(name = "packed_payload", srcs = glob([${JSON.stringify(payload)}]))`, + 'cargo_package_env(workspace_manifest = "//:Cargo.toml")', + '# Generated includes must refer to declared package files, not pruned build-script runfiles.', + 'cargo_generator(srcs = ["build-support.rs"], data = [":packed_payload"], build_script_env = {"CARGO_MANIFEST_DIR": packed_cargo_manifest_dir(), "OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD": "1", "OLIPHAUNT_ARTIFACT_CRATE_EMIT_CARGO_MANIFEST": "0"}, cargo_facts = CARGO, crate_dependencies = crate_deps)', + 'cargo_library(build_script = ":build_script", compile_data = [":packed_payload"], cargo_facts = CARGO, crate_dependencies = crate_deps)', + '', + ].join('\n'); + writeFileSync(path.join(outputDirectory, memberPath, 'BUILD.bazel'), build); + } + rmSync(staged, { recursive: true, force: true }); + return { + packages: PACKAGE_NAMES.map((name) => ({ + name, + path: PACKAGE_PATHS.get(name), + target: expectedTarget(name), + })), + }; +} + +if (import.meta.main) { + const [command, ...args] = process.argv.slice(2); + if (command === 'receipt') { + const [ + inputJson, + output, + sourceCommit, + sourceTree, + releaseManifest, + toolchainManifest, + cargoLock, + versionManifest, + ] = args; + const input = JSON.parse(readFileSync(inputJson, 'utf8')); + const receipt = writeWasixCargoConstructionReceipt(input, { + sourceCommit, + sourceTree, + releaseManifest, + toolchainManifest, + cargoLock, + versionManifest, + }); + writeFileSync(output, `${JSON.stringify(receipt, null, 2)}\n`); + } else if (command === 'extract') { + const [ + receiptFile, + inputDirectory, + expectedCommit, + outputDirectory, + releaseManifest, + toolchainManifest, + cargoLock, + versionManifest, + rustDefs, + cratesDefs, + sourceRoot, + ] = args; + const result = extractWasixCargoConstructionInputs( + JSON.parse(readFileSync(receiptFile, 'utf8')), + inputDirectory, + expectedCommit, + outputDirectory, + { + releaseManifest, + toolchainManifest, + cargoLock, + versionManifest, + rustDefs, + cratesDefs, + sourceRoot, + }, + ); + console.log(JSON.stringify(result)); + } else { + throw new Error('usage: cargo-inputs.mts receipt|extract ...'); + } +} diff --git a/build_defs/wasix/cargo-inputs.test.mts b/build_defs/wasix/cargo-inputs.test.mts new file mode 100644 index 000000000..cfc7b3b9a --- /dev/null +++ b/build_defs/wasix/cargo-inputs.test.mts @@ -0,0 +1,401 @@ +import { test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { gzipSync, zstdCompressSync } from 'node:zlib'; +import { canonicalWasixAotMetadata } from '../../src/wasix/runtime/tools/wasix-aot-manifest.mts'; +import { + AOT_PACKAGES, + AOT_TARGET_TRIPLES, + CORE_AOT_ARTIFACTS, + CORE_RUNTIME_ARCHIVE_FILES, + RUNTIME_PACKAGE, +} from '../../src/wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; +import { packageRuntimeCargo, type RuntimeCargoSpec } from './cargo.mts'; +import { + extractWasixCargoConstructionInputs, + wasixHostSmokeCargoIdentities, + writeWasixCargoConstructionReceipt, +} from './cargo-inputs.mts'; + +const root = mkdtempSync(path.join(os.tmpdir(), 'wasix-packed-carriers-')); +const versionManifest = path.resolve('src/wasix/runtime/crates/assets/Cargo.toml'); +const version = Bun.TOML.parse(readFileSync(versionManifest, 'utf8')).package.version; +const sha = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); + +function copyFile(sourceRoot: string, relative: string, source: string) { + const destination = path.join(sourceRoot, relative); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, readFileSync(source)); +} + +async function makeInput(targetId: string | null) { + const packageName = targetId === null ? RUNTIME_PACKAGE : AOT_PACKAGES[targetId]; + const triple = targetId === null ? null : AOT_TARGET_TRIPLES[targetId]; + const payload = path.join(root, `payload-${targetId ?? 'portable'}`); + mkdirSync(payload, { recursive: true }); + const moduleBytes = Buffer.from('\0asm\x01\0\0\0'); + const payloadManifest = + targetId === null + ? { + extensions: [], + runtime: { + archive: 'oliphaunt.wasix.tar.zst', + sha256: sha(zstdCompressSync(Buffer.from('placeholder'))), + }, + } + : { + 'source-lane': canonicalWasixAotMetadata().sourceLane, + engine: canonicalWasixAotMetadata().engine, + 'wasmer-version': canonicalWasixAotMetadata().wasmerVersion, + 'wasmer-wasix-version': canonicalWasixAotMetadata().wasmerWasixVersion, + 'format-version': 1, + 'target-triple': triple, + 'source-fingerprint': 'independent fixture', + artifacts: [], + }; + if (targetId === null) { + const archive = new Bun.Archive( + Object.fromEntries(CORE_RUNTIME_ARCHIVE_FILES.map((file) => [file, moduleBytes])), + ); + const bytes = zstdCompressSync(Buffer.from(await archive.bytes())); + writeFileSync(path.join(payload, 'oliphaunt.wasix.tar.zst'), bytes); + payloadManifest.runtime.sha256 = sha(bytes); + mkdirSync(path.join(payload, 'bin'), { recursive: true }); + writeFileSync(path.join(payload, 'bin/initdb.wasix.wasm'), moduleBytes); + } else { + payloadManifest.artifacts = CORE_AOT_ARTIFACTS.map((name, index) => { + const raw = Buffer.from(`independent serialized-image fixture ${name}`); + const bytes = zstdCompressSync(raw); + const file = `${index}.bin.zst`; + writeFileSync(path.join(payload, file), bytes); + return { + name, + path: file, + compressed: true, + sha256: sha(bytes), + 'module-sha256': sha(moduleBytes), + 'raw-sha256': sha(raw), + 'raw-size': raw.length, + }; + }); + } + const manifestFile = path.join(payload, 'manifest.json'); + writeFileSync(manifestFile, `${JSON.stringify(payloadManifest)}\n`); + + const template = + targetId === null + ? path.resolve('src/wasix/runtime/crates/assets') + : path.resolve('src/wasix/runtime/crates/aot', triple!); + const sources = Object.fromEntries( + ['Cargo.toml', 'README.md', 'build.rs', 'build-support.rs', 'src/lib.rs'].map((file) => [ + file, + path.join(template, file), + ]), + ); + const notices = { + LICENSE: path.resolve('LICENSE'), + 'THIRD_PARTY_NOTICES.md': path.resolve('THIRD_PARTY_NOTICES.md'), + 'src/wasix/sdks/rust/THIRD_PARTY_NOTICES.md': path.resolve( + 'src/wasix/sdks/rust/THIRD_PARTY_NOTICES.md', + ), + 'src/third-party/postgres/COPYRIGHT': path.resolve('src/third-party/postgres/COPYRIGHT'), + 'src/third-party/postgres/source.toml': path.resolve('src/third-party/postgres/source.toml'), + 'src/third-party/icu/LICENSE': path.resolve('src/third-party/icu/LICENSE'), + 'src/third-party/icu/source.toml': path.resolve('src/third-party/icu/source.toml'), + }; + const sourceRoot = path.join(root, `source-${targetId ?? 'portable'}`); + for (const [relative, source] of Object.entries(notices)) copyFile(sourceRoot, relative, source); + copyFile( + sourceRoot, + 'src/wasix/runtime/toolchain.toml', + path.resolve('src/wasix/runtime/toolchain.toml'), + ); + + const payloadFiles = [manifestFile]; + if (targetId === null) { + payloadFiles.push( + path.join(payload, 'oliphaunt.wasix.tar.zst'), + path.join(payload, 'bin/initdb.wasix.wasm'), + ); + } else { + payloadFiles.push(...payloadManifest.artifacts.map((row) => path.join(payload, row.path))); + } + const spec: RuntimeCargoSpec = { + version, + packageName, + target: targetId, + payload, + payloadFiles, + sources, + notices, + toolchain: path.resolve('src/wasix/runtime/toolchain.toml'), + }; + const file = path.join(root, `${packageName}-${version}.crate`); + packageRuntimeCargo(spec, file); + return { file, name: packageName, target: targetId ?? 'portable', sourceRoot }; +} + +test('imports genuine canonical crate envelopes and rejects receipt substitutions', async () => { + try { + const inputDirectory = path.join(root, 'inputs'); + mkdirSync(inputDirectory); + const packed = await Promise.all([null, ...Object.keys(AOT_PACKAGES)].map(makeInput)); + const inputs = packed.map((row) => { + const file = path.join(inputDirectory, path.basename(row.file)); + writeFileSync(file, readFileSync(row.file)); + return { ...row, file }; + }); + const releaseManifest = path.resolve('src/wasix/runtime/release.toml'); + const toolchainManifest = path.resolve('src/wasix/runtime/toolchain.toml'); + const cargoLock = path.resolve('Cargo.lock'); + const receipt = writeWasixCargoConstructionReceipt(inputs, { + sourceCommit: '1'.repeat(40), + sourceTree: '2'.repeat(40), + releaseManifest, + toolchainManifest, + cargoLock, + versionManifest, + }); + const output = path.join(root, 'repository'); + extractWasixCargoConstructionInputs(receipt, inputDirectory, '1'.repeat(40), output, { + releaseManifest, + toolchainManifest, + cargoLock, + versionManifest, + rustDefs: '@@main//build_defs/languages:rust.bzl', + cratesDefs: '@@cargo_crates//:defs.bzl', + sourceRoot: packed[0].sourceRoot, + }); + for (const row of packed) { + const triple = row.target === 'portable' ? null : AOT_TARGET_TRIPLES[row.target]; + const packagePath = triple + ? path.join(output, 'src/wasix/runtime/crates/aot', triple) + : path.join(output, 'src/wasix/runtime/crates/assets'); + const sourcePath = triple + ? path.resolve('src/wasix/runtime/crates/aot', triple) + : path.resolve('src/wasix/runtime/crates/assets'); + assert.equal( + readFileSync(path.join(packagePath, 'src/lib.rs'), 'utf8'), + readFileSync(path.join(sourcePath, 'src/lib.rs'), 'utf8'), + ); + assert.equal( + readFileSync(path.join(packagePath, 'build-support.rs'), 'utf8'), + readFileSync(path.join(sourcePath, 'build-support.rs'), 'utf8'), + ); + assert.equal( + readFileSync(path.join(packagePath, 'build.rs'), 'utf8'), + 'const PACKAGE_LOCAL: bool = true;\ninclude!("build-support.rs");\n', + ); + const payloadDir = path.join(packagePath, triple ? 'artifacts' : 'payload'); + assert(existsSync(path.join(payloadDir, 'manifest.json'))); + assert.match( + readFileSync(path.join(packagePath, 'BUILD.bazel'), 'utf8'), + /cargo_generator\(/u, + ); + } + const cargoBzl = readFileSync(path.join(output, 'cargo.bzl'), 'utf8'); + assert.match(cargoBzl, /^CARGO = \{/u); + assert.match(cargoBzl, /release_strip": None/u); + assert.match(cargoBzl, /oliphaunt_artifact_liboliphaunt_wasix_runtime/u); + assert(!cargoBzl.includes('wasix_runtime_carriers')); + const generatedBuild = readFileSync( + path.join(output, 'src/wasix/runtime/crates/assets/BUILD.bazel'), + 'utf8', + ); + assert(generatedBuild.includes('@@main//build_defs/languages:rust.bzl')); + assert(generatedBuild.includes('@@cargo_crates//:defs.bzl')); + assert.equal( + readFileSync(path.join(output, 'Cargo.lock'), 'utf8'), + readFileSync(cargoLock, 'utf8'), + ); + assert(!existsSync(path.join(output, '.staged'))); + assert.equal(receipt.crates.find((row) => row.name === RUNTIME_PACKAGE)?.role, 'platform-leaf'); + + // Public support envelopes are immutable data inputs, never projected into + // foreign Cargo libraries or used to start a foreign WASIX producer. + const toolsManifestPath = 'src/wasix/postgres-tools/crates/tools/Cargo.toml'; + copyFile(packed[0].sourceRoot, toolsManifestPath, path.resolve(toolsManifestPath)); + const hostSmokeInputs = await Promise.all( + wasixHostSmokeCargoIdentities(packed[0].sourceRoot, version).map(async (identity) => { + const file = path.join(inputDirectory, `${identity.name}-${identity.version}.crate`); + const envelope = new Bun.Archive({ + [`${identity.name}-${identity.version}/Cargo.toml`]: `[package]\nname="${identity.name}"\nversion="${identity.version}"\n`, + }); + writeFileSync(file, gzipSync(Buffer.from(await envelope.bytes()))); + return { file, name: identity.name, target: identity.target }; + }), + ); + const supportReceipt = writeWasixCargoConstructionReceipt(inputs, { + sourceCommit: '1'.repeat(40), + sourceTree: '2'.repeat(40), + releaseManifest, + toolchainManifest, + cargoLock, + versionManifest, + hostSmokeInputs, + sourceRoot: packed[0].sourceRoot, + }); + const supportOutput = path.join(root, 'host-repository'); + const importSupport = (value: unknown, destination: string) => + extractWasixCargoConstructionInputs(value, inputDirectory, '1'.repeat(40), destination, { + releaseManifest, + toolchainManifest, + cargoLock, + versionManifest, + rustDefs: '@@main//build_defs/languages:rust.bzl', + cratesDefs: '@@cargo_crates//:defs.bzl', + sourceRoot: packed[0].sourceRoot, + }); + importSupport(supportReceipt, supportOutput); + const reordered = structuredClone(supportReceipt); + assert(reordered.hostSmokeCrates); + reordered.hostSmokeCrates = reordered.hostSmokeCrates.map( + (row) => Object.fromEntries(Object.entries(row).reverse()) as typeof row, + ); + importSupport(reordered, path.join(root, 'reordered-host-repository')); + for (const row of [...hostSmokeInputs, ...inputs.filter((row) => row.name === RUNTIME_PACKAGE)]) + assert.deepEqual( + readFileSync(path.join(supportOutput, 'host-smoke', path.basename(row.file))), + readFileSync(row.file), + ); + assert.equal( + readFileSync(path.join(supportOutput, 'cargo-facts.json'), 'utf8'), + readFileSync(path.join(output, 'cargo-facts.json'), 'utf8'), + ); + assert.match( + readFileSync(path.join(supportOutput, 'BUILD.bazel'), 'utf8'), + /filegroup\(name = "host_smoke"/u, + ); + for (const [key, mutation] of [ + [ + 'hash', + (rows: any[]) => { + rows[0].sha256 = '0'.repeat(64); + }, + ], + [ + 'target', + (rows: any[]) => { + rows[0].target = 'different-target'; + }, + ], + [ + 'version', + (rows: any[]) => { + rows[0].version = 'different-version'; + }, + ], + [ + 'path', + (rows: any[]) => { + rows[0].path = `../${rows[0].path}`; + }, + ], + [ + 'missing', + (rows: any[]) => { + rows.pop(); + }, + ], + [ + 'duplicate', + (rows: any[]) => { + rows[0] = rows[1]; + }, + ], + ] as const) { + const invalid = structuredClone(supportReceipt); + assert(invalid.hostSmokeCrates); + mutation(invalid.hostSmokeCrates); + assert.throws(() => importSupport(invalid, path.join(root, `invalid-support-${key}`))); + } + + const badRole = structuredClone(receipt); + badRole.crates[0].role = 'artifact'; + assert.throws( + () => + extractWasixCargoConstructionInputs( + badRole, + inputDirectory, + '1'.repeat(40), + path.join(root, 'bad-role'), + { + releaseManifest, + toolchainManifest, + cargoLock, + versionManifest, + rustDefs: '@@main//build_defs/languages:rust.bzl', + cratesDefs: '@@cargo_crates//:defs.bzl', + sourceRoot: packed[0].sourceRoot, + }, + ), + /invalid WASIX Cargo receipt row/u, + ); + assert.throws( + () => + extractWasixCargoConstructionInputs( + receipt, + inputDirectory, + '3'.repeat(40), + path.join(root, 'bad-source'), + { + releaseManifest, + toolchainManifest, + cargoLock, + versionManifest, + rustDefs: '@@main//build_defs/languages:rust.bzl', + cratesDefs: '@@cargo_crates//:defs.bzl', + sourceRoot: packed[0].sourceRoot, + }, + ), + /exact source inputs/u, + ); + const wrongLock = path.join(root, 'wrong-Cargo.lock'); + writeFileSync(wrongLock, `${readFileSync(cargoLock, 'utf8')}\n# changed\n`); + assert.throws( + () => + extractWasixCargoConstructionInputs( + receipt, + inputDirectory, + '1'.repeat(40), + path.join(root, 'bad-lock'), + { + releaseManifest, + toolchainManifest, + cargoLock: wrongLock, + versionManifest, + rustDefs: '@@main//build_defs/languages:rust.bzl', + cratesDefs: '@@cargo_crates//:defs.bzl', + sourceRoot: packed[0].sourceRoot, + }, + ), + /exact source inputs/u, + ); + const replaced = inputs[0]; + writeFileSync(replaced.file, 'replaced crate bytes'); + assert.throws( + () => + extractWasixCargoConstructionInputs( + receipt, + inputDirectory, + '1'.repeat(40), + path.join(root, 'bad-hash'), + { + releaseManifest, + toolchainManifest, + cargoLock, + versionManifest, + rustDefs: '@@main//build_defs/languages:rust.bzl', + cratesDefs: '@@cargo_crates//:defs.bzl', + sourceRoot: packed[0].sourceRoot, + }, + ), + /hash differs/u, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/build_defs/wasix/cargo.bzl b/build_defs/wasix/cargo.bzl new file mode 100644 index 000000000..4bd5482ad --- /dev/null +++ b/build_defs/wasix/cargo.bzl @@ -0,0 +1,118 @@ +"""Canonical runtime Cargo envelopes from the declared portable/AOT payloads.""" + +load("@native_cargo_metadata//:cargo.bzl", "CARGO") +load("@oliphaunt_metadata//:metadata.bzl", "PUBLICATION_CARRIERS") +load("@wasix_tool_metadata//:targets.bzl", "WASIX_AOT_TARGETS") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") +load("//build_defs/release:identity.bzl", "ReleaseIdentityInfo") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") +load(":npm.bzl", "RUNTIME_NPM_NOTICES") + +RUNTIME_CARGO_HELPERS = [ + "//src/wasix/runtime:tools/package_liboliphaunt_wasix_cargo_artifacts.mts", + "//src/wasix/runtime:tools/check-release-assets.mts", + "//src/wasix/runtime:tools/wasix-aot-manifest.mts", + "//src/wasix/runtime:tools/wasix-cargo-toolchain-policy.mts", + "//src/wasix/runtime:tools/wasix-cargo-artifact-contract.mts", + "//src/wasix/runtime:tools/wasix-runtime-npm-contract.mts", + "//src/extensions/tools:extension-upstream-licenses.mts", + "//src/extensions/contracts:wasix-extension-install.mts", + "//:tools/packaging/wasix-cargo-payload.mts", + "//:tools/packaging/cargo-source-package.mts", + "//:tools/packaging/cargo-manifest.mts", + "//:tools/packaging/rust-build-script-sha256.mts", + "//:tools/packaging/package-archive.mts", + "//:tools/packaging/archive-directory.mts", + "//:tools/packaging/portable-archive.mts", + "//:tools/packaging/release-notices.mts", + "//:tools/packaging/release-directory-safety.mts", + "//tools/release:release-artifact-targets.mts", + "//tools/release:release-graph.mts", + "//tools/release:release-history.mts", + "//tools/release:compatibility-version-parser.mts", + "//tools/release:extension-release-metadata.mts", + "//tools/release:platform-compatibility-policy.mts", + "//:src/extensions/artifacts/packages/tools/contrib-carriers.mts", + "//:src/extensions/artifacts/packages/tools/extension-registry-packages.mts", + "//src/extensions/contracts:extension-target-profiles.mts", + "//src/database-resources:seeds/carrier-identities.mts", + "//src/native/mobile-bindings:tools/dependency-license-contract.mts", + "//:tools/packaging/rust-dependency-license-contract.mts", +] + +def _source_map(entries, inputs): + result = {} + for target, destination in entries.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1 or files[0].is_directory or destination in result: + fail("WASIX Cargo source must be one unique declared File") + result[destination] = files[0].path + inputs += files + return result + +def _runtime_cargo_impl(ctx): + payload = ctx.attr.payload[DefaultInfo].files.to_list() + if len(payload) != 1 or not payload[0].is_directory: + fail("WASIX Cargo envelope requires the actual portable/AOT payload tree") + identity = ctx.attr.product[ReleaseIdentityInfo] + if identity.id != "liboliphaunt-wasix": + fail("WASIX runtime Cargo envelope requires its canonical release owner") + inputs = payload + [ctx.file.toolchain] + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode({ + "version": identity.version, + "packageName": ctx.attr.package_name, + "target": ctx.attr.target_id or None, + "payload": payload[0].path, + "sources": _source_map(ctx.attr.sources, inputs), + "notices": _source_map(ctx.attr.notices, inputs), + "toolchain": ctx.file.toolchain.path, + })) + output = ctx.actions.declare_file(ctx.attr.package_name + "-" + identity.version + ".crate") + args = ctx.actions.args() + args.add_all(["--spec", spec, "--output", output]) + leaves = ctx.actions.args() + leaves.add_all(payload, expand_directories = True) + leaves.use_param_file("--payload-files=%s", use_always = True) + leaves.set_param_file_format("multiline") + bun_file_action(ctx, ctx.file._packager, arguments = [args, leaves], inputs = depset(inputs + [spec]), + source_files = ctx.files._helpers, outputs = [output], mnemonic = "WasixRuntimeCargoEnvelope") + return [DefaultInfo(files = depset([output]))] + +_runtime_cargo = rule( + implementation = _runtime_cargo_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = { + "payload": attr.label(mandatory = True), + "product": attr.label(mandatory = True, providers = [ReleaseIdentityInfo]), + "package_name": attr.string(mandatory = True), + "target_id": attr.string(), + "sources": attr.label_keyed_string_dict(allow_files = True, mandatory = True), + "notices": attr.label_keyed_string_dict(default = RUNTIME_NPM_NOTICES, allow_files = True), + "toolchain": attr.label(default = "//src/wasix/runtime:toolchain.toml", allow_single_file = True), + "_packager": attr.label(default = "//build_defs/wasix:cargo.mts", allow_single_file = True), + "_helpers": attr.label_list(default = RUNTIME_CARGO_HELPERS, allow_files = True), + }, +) + +def wasix_runtime_cargo(payload, target_id = ""): + package = CARGO[native.package_name()]["name"] + rows = [row for row in PUBLICATION_CARRIERS if row["product"] == "liboliphaunt-wasix" and row["ecosystem"] == "cargo" and row["name"] == package] + if target_id and target_id not in WASIX_AOT_TARGETS: + fail("WASIX runtime Cargo envelope has no canonical AOT target") + target = WASIX_AOT_TARGETS[target_id] if target_id else "portable" + if len(rows) != 1 or rows[0]["target"] != target: + fail("WASIX runtime Cargo envelope must match its canonical carrier target") + owner = "@oliphaunt_metadata//:product_liboliphaunt-wasix" + sources = native.glob(["Cargo.toml", "README.md", "build.rs", "build-support.rs", "src/**"]) + native.filegroup(name = "package_sources", srcs = sources) + _runtime_cargo(name = "crate", payload = payload, product = owner, package_name = package, + target_id = target_id, sources = {file: file for file in sources}) + shipping_package(name = "shipping_package", owner = owner, artifacts = [":crate"], ecosystem = "cargo", + package_name = package, configuration = target_id or "portable", role = rows[0]["role"], suppliers = "//src/wasix/runtime:runtime_public_suppliers") + shipping_export(name = "shipping_export", packages = [":shipping_package"]) + +def wasix_runtime_cargo_exports(): + packages = ["//src/wasix/runtime/crates/assets"] + ["//src/wasix/runtime/crates/aot/" + triple for triple in WASIX_AOT_TARGETS.values()] + native.filegroup(name = "cargo", srcs = [package + ":crate" for package in packages], tags = ["manual"]) + shipping_export(name = "cargo_shipping_export", packages = [package + ":shipping_package" for package in packages]) diff --git a/build_defs/wasix/cargo.mts b/build_defs/wasix/cargo.mts new file mode 100644 index 000000000..7a9a8b5eb --- /dev/null +++ b/build_defs/wasix/cargo.mts @@ -0,0 +1,162 @@ +import { chmodSync, copyFileSync, mkdirSync, mkdtempSync, readFileSync, rmSync } from 'node:fs'; +import path from 'node:path'; +import { parseArgs } from 'node:util'; +import { + validateRuntimeAotPayload, + validateRuntimePayload, +} from '../../src/wasix/runtime/tools/package_liboliphaunt_wasix_cargo_artifacts.mts'; +import { + AOT_PACKAGES, + AOT_TARGET_TRIPLES, + RUNTIME_PACKAGE, +} from '../../src/wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; +import { cargoPackageRelativePathParts } from '../../tools/packaging/cargo-source-package.mts'; +import { + assertReleaseNoticesInDirectory, + stageReleaseNotices, +} from '../../tools/packaging/release-notices.mts'; +import { packageSpec } from '../../tools/packaging/wasix-cargo-payload.mts'; + +export interface RuntimeCargoSpec { + version: string; + packageName: string; + target: string | null; + payload: string; + payloadFiles: string[]; + sources: Record; + notices: Record; + toolchain: string; +} + +export function copyDeclaredSources(files: Record, destination: string): void { + for (const [relative, source] of Object.entries(files)) { + const file = path.join(destination, ...cargoPackageRelativePathParts(relative)); + mkdirSync(path.dirname(file), { recursive: true }); + copyFileSync(source, file); + chmodSync(file, 0o644); + } +} + +export function stageDeclaredPayload( + spec: Pick, + destination: string, +): void { + if (!Array.isArray(spec.payloadFiles) || spec.payloadFiles.length === 0) + throw new Error('WASIX Cargo payload requires its declared TreeArtifact leaves'); + const sources: Record = {}; + for (const source of spec.payloadFiles) { + const relative = path + .relative(path.resolve(spec.payload), path.resolve(source)) + .split(path.sep) + .join('/'); + cargoPackageRelativePathParts(relative); + if (Object.hasOwn(sources, relative)) + throw new Error(`Duplicate declared WASIX Cargo payload leaf: ${relative}`); + sources[relative] = source; + } + copyDeclaredSources(sources, destination); +} + +export function validatePackedRuntimeCargo( + directory: string, + { packageName, target }: Pick, + sourceRoot: string, +): void { + if (packageName !== (target === null ? RUNTIME_PACKAGE : AOT_PACKAGES[target])) { + throw new Error('Packed WASIX Cargo package has the wrong target identity'); + } + if ( + readFileSync(path.join(directory, 'build.rs'), 'utf8') !== + 'const PACKAGE_LOCAL: bool = true;\ninclude!("build-support.rs");\n' + ) { + throw new Error('Packed WASIX Cargo build script must require its package-local payload'); + } + assertReleaseNoticesInDirectory(directory, { + profile: target === null ? 'wasix-runtime' : 'wasix-aot', + sourceRoot, + }); + if (target === null) { + validateRuntimePayload(path.join(directory, 'payload')); + } else { + validateRuntimeAotPayload(path.join(directory, 'artifacts'), AOT_TARGET_TRIPLES[target], { + sourceRoot, + }); + } +} + +export function packageRuntimeCargo(spec: RuntimeCargoSpec, output: string): void { + const portable = spec.target === null; + if ( + spec.packageName !== (portable ? RUNTIME_PACKAGE : AOT_PACKAGES[spec.target]) || + (!portable && !Object.hasOwn(AOT_TARGET_TRIPLES, spec.target)) + ) { + throw new Error('Canonical release package name disagrees with the WASIX Cargo target'); + } + const manifest = Bun.TOML.parse(readFileSync(spec.sources['Cargo.toml'], 'utf8')); + if (manifest.package?.name !== spec.packageName) { + throw new Error('Declared WASIX Cargo template has the wrong package identity'); + } + output = path.resolve(output); + mkdirSync(path.dirname(output), { recursive: true }); + const scratch = mkdtempSync(path.join(path.dirname(output), '.wasix-cargo-')); + try { + const templateDir = path.join(scratch, 'template'); + const noticeSourceRoot = path.join(scratch, 'notices'); + copyDeclaredSources(spec.sources, templateDir); + copyDeclaredSources(spec.notices, noticeSourceRoot); + copyDeclaredSources({ 'src/wasix/runtime/toolchain.toml': spec.toolchain }, noticeSourceRoot); + const payloadRoot = path.join(scratch, 'payload'); + stageDeclaredPayload(spec, payloadRoot); + if (portable) { + validateRuntimePayload(payloadRoot); + } else { + // The canonical AOT Cargo validator includes payload-local legal notices. + stageReleaseNotices(payloadRoot, { profile: 'wasix-aot', sourceRoot: noticeSourceRoot }); + validateRuntimeAotPayload(payloadRoot, AOT_TARGET_TRIPLES[spec.target], { + sourceRoot: noticeSourceRoot, + }); + } + const generated = packageSpec( + { + name: spec.packageName, + target: spec.target, + kind: portable ? 'wasix-runtime' : 'wasix-aot', + templateDir, + payloadRoot, + payloadDirName: portable ? 'payload' : 'artifacts', + }, + { + version: spec.version, + sourceRoot: path.join(scratch, 'sources'), + outputDir: scratch, + cargoTargetDir: path.join(scratch, 'cargo-target'), + noticeSourceRoot, + }, + ); + copyFileSync(generated.cratePath, output); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + const { values } = parseArgs({ + options: { + spec: { type: 'string' }, + output: { type: 'string' }, + 'payload-files': { type: 'string' }, + }, + strict: true, + }); + if (!values.spec || !values.output || !values['payload-files']) + throw new Error( + 'usage: cargo.mts --spec --output --payload-files ', + ); + packageRuntimeCargo( + { + ...JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(readFileSync(values.spec))), + payloadFiles: readFileSync(values['payload-files'], 'utf8').trimEnd().split(/\r?\n/u), + }, + values.output, + ); +} diff --git a/build_defs/wasix/cargo.test.mts b/build_defs/wasix/cargo.test.mts new file mode 100644 index 000000000..644b0db71 --- /dev/null +++ b/build_defs/wasix/cargo.test.mts @@ -0,0 +1,225 @@ +import { afterEach, expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; +import os from 'node:os'; +import path from 'node:path'; +import { zstdCompressSync } from 'node:zlib'; +import { canonicalWasixAotMetadata } from '../../src/wasix/runtime/tools/wasix-aot-manifest.mts'; +import { + AOT_PACKAGES, + AOT_TARGET_TRIPLES, + CORE_AOT_ARTIFACTS, + CORE_RUNTIME_ARCHIVE_FILES, + RUNTIME_PACKAGE, +} from '../../src/wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; +import { extractPortableArchiveTree } from '../../tools/packaging/portable-archive.mts'; +import { + packageRuntimeCargo, + type RuntimeCargoSpec, + validatePackedRuntimeCargo, +} from './cargo.mts'; + +const roots: string[] = []; +afterEach(async () => { + await Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true }))); +}); +const sha = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); + +async function fixture(target: string | null = null) { + const root = await mkdtemp(path.join(os.tmpdir(), 'oliphaunt-wasix-cargo-')); + roots.push(root); + const payload = path.join(root, 'payload'); + await mkdir(payload); + const module = Buffer.from('\0asm\x01\0\0\0'); + const template = target + ? `src/wasix/runtime/crates/aot/${AOT_TARGET_TRIPLES[target]}` + : 'src/wasix/runtime/crates/assets'; + const sources = Object.fromEntries( + ['Cargo.toml', 'README.md', 'build.rs', 'build-support.rs', 'src/lib.rs'].map((file) => [ + file, + path.resolve(template, file), + ]), + ); + const notices = Object.fromEntries( + [ + 'LICENSE', + 'THIRD_PARTY_NOTICES.md', + 'src/wasix/sdks/rust/THIRD_PARTY_NOTICES.md', + 'src/third-party/postgres/COPYRIGHT', + 'src/third-party/postgres/source.toml', + 'src/third-party/icu/LICENSE', + 'src/third-party/icu/source.toml', + ].map((file) => [file, path.resolve(file)]), + ); + let manifest; + if (target) { + const canonical = canonicalWasixAotMetadata(); + manifest = { + 'format-version': 1, + 'source-lane': canonical.sourceLane, + engine: canonical.engine, + 'wasmer-version': canonical.wasmerVersion, + 'wasmer-wasix-version': canonical.wasmerWasixVersion, + 'target-triple': AOT_TARGET_TRIPLES[target], + 'source-fingerprint': 'independent fixture', + artifacts: await Promise.all( + CORE_AOT_ARTIFACTS.map(async (name, index) => { + const raw = Buffer.from(`independent serialized-image framing fixture ${name}`); + const bytes = zstdCompressSync(raw); + const file = `${index}.bin.zst`; + await writeFile(path.join(payload, file), bytes); + return { + name, + path: file, + compressed: true, + sha256: sha(bytes), + 'module-sha256': sha(module), + 'raw-sha256': sha(raw), + 'raw-size': raw.length, + }; + }), + ), + }; + } else { + const runtime = zstdCompressSync( + Buffer.from( + await new Bun.Archive( + Object.fromEntries(CORE_RUNTIME_ARCHIVE_FILES.map((name) => [name, module])), + ).bytes(), + ), + ); + await writeFile(path.join(payload, 'oliphaunt.wasix.tar.zst'), runtime); + await mkdir(path.join(payload, 'bin')); + await writeFile(path.join(payload, 'bin/initdb.wasix.wasm'), module); + manifest = { + extensions: [], + runtime: { archive: 'oliphaunt.wasix.tar.zst', sha256: sha(runtime) }, + }; + } + const manifestPath = path.join(payload, 'manifest.json'); + await writeFile(manifestPath, `${JSON.stringify(manifest)}\n`); + const spec: RuntimeCargoSpec = { + version: '7.8.9', + packageName: target ? AOT_PACKAGES[target] : RUNTIME_PACKAGE, + target, + payload, + payloadFiles: [ + manifestPath, + ...(target + ? manifest.artifacts.map((row) => path.join(payload, row.path)) + : ['oliphaunt.wasix.tar.zst', 'bin/initdb.wasix.wasm'].map((file) => + path.join(payload, file), + )), + ], + sources, + notices, + toolchain: path.resolve('src/wasix/runtime/toolchain.toml'), + }; + const sourceRoot = path.join(root, 'canonical-source'); + for (const [relative, source] of Object.entries({ + ...notices, + 'src/wasix/runtime/toolchain.toml': spec.toolchain, + })) { + const file = path.join(sourceRoot, relative); + await mkdir(path.dirname(file), { recursive: true }); + await writeFile(file, await readFile(source)); + } + return { root, spec, manifest, manifestPath, sourceRoot }; +} + +async function verifyCanonicalEnvelope(target: string | null) { + const { root, spec, sourceRoot } = await fixture(target); + const first = path.join(root, 'first.crate'); + const second = path.join(root, 'second.crate'); + packageRuntimeCargo(spec, first); + packageRuntimeCargo(spec, second); + expect(await readFile(first)).toEqual(await readFile(second)); + const files = await new Bun.Archive(await readFile(first)).files(); + const read = async (name: string) => { + const file = files.get(`${spec.packageName}-${spec.version}/${name}`); + if (!file) throw new Error(`independent archive reader found no ${name}`); + return Buffer.from(await file.arrayBuffer()); + }; + const manifest = Bun.TOML.parse((await read('Cargo.toml')).toString()); + expect(manifest.package).toMatchObject({ name: spec.packageName, version: spec.version }); + expect(manifest.package.publish).toBeUndefined(); + expect((await read('build.rs')).toString()).toBe( + 'const PACKAGE_LOCAL: bool = true;\ninclude!("build-support.rs");\n', + ); + expect(await read('build-support.rs')).toEqual(await readFile(spec.sources['build-support.rs'])); + expect(await read('src/lib.rs')).toEqual(await readFile(spec.sources['src/lib.rs'])); + expect(await read(`${target ? 'artifacts' : 'payload'}/manifest.json`)).toEqual( + await readFile(path.join(spec.payload, 'manifest.json')), + ); + expect([...files.keys()].some((member) => member.includes('BUILD.bazel'))).toBe(false); + const extracted = path.join(root, 'installed'); + extractPortableArchiveTree(first, extracted, `${spec.packageName}-${spec.version}`); + validatePackedRuntimeCargo(extracted, spec, sourceRoot); + await writeFile(path.join(extracted, 'build.rs'), await readFile(spec.sources['build.rs'])); + expect(() => validatePackedRuntimeCargo(extracted, spec, sourceRoot)).toThrow( + 'must require its package-local payload', + ); +} + +for (const target of [null, ...Object.keys(AOT_TARGET_TRIPLES)]) { + test(`canonical ${target ?? 'portable'} Cargo envelope preserves sources and payload bytes`, () => { + return verifyCanonicalEnvelope(target); + }); +} + +test('runtime Cargo rejects wrong carrier identity, unsafe sources, missing notices and stale payloads', async () => { + const { root, spec, manifest, manifestPath } = await fixture(); + const output = path.join(root, 'invalid.crate'); + expect(() => packageRuntimeCargo({ ...spec, target: 'linux-x64-gnu' }, output)).toThrow( + 'Canonical release package name disagrees', + ); + expect(() => + packageRuntimeCargo({ ...spec, sources: { ...spec.sources, '../escape': 'LICENSE' } }, output), + ).toThrow('non-portable Cargo package path'); + expect(() => packageRuntimeCargo({ ...spec, payloadFiles: [] }, output)).toThrow( + 'requires its declared TreeArtifact leaves', + ); + expect(() => + packageRuntimeCargo( + { ...spec, payloadFiles: [...spec.payloadFiles, spec.payloadFiles[0]] }, + output, + ), + ).toThrow('Duplicate declared WASIX Cargo payload leaf'); + const outsideManifest = path.join(root, 'outside-Cargo.toml'); + await writeFile(outsideManifest, await readFile(spec.sources['Cargo.toml'])); + expect(() => packageRuntimeCargo({ ...spec, payloadFiles: [outsideManifest] }, output)).toThrow( + 'non-portable Cargo package path', + ); + expect(() => packageRuntimeCargo({ ...spec, notices: {} }, output)).toThrow(); + manifest.extensions = ['omitted extension']; + await writeFile(manifestPath, JSON.stringify(manifest)); + expect(() => packageRuntimeCargo(spec, output)).toThrow('empty extensions array'); + manifest.extensions = []; + await writeFile(manifestPath, JSON.stringify(manifest)); + await writeFile(path.join(spec.payload, 'oliphaunt.wasix.tar.zst'), 'stale bytes'); + expect(() => packageRuntimeCargo(spec, output)).toThrow('runtime.sha256 mismatch'); +}); + +test('AOT Cargo rejects mixed target/engine, incomplete closure and mismatched serialized bytes', async () => { + const { root, spec, manifest, manifestPath } = await fixture('linux-x64-gnu'); + const output = path.join(root, 'invalid.crate'); + for (const [field, bad] of [ + ['target-triple', 'aarch64-apple-darwin'], + ['engine', 'unqualified-engine'], + ]) { + const original = manifest[field]; + manifest[field] = bad; + await writeFile(manifestPath, JSON.stringify(manifest)); + expect(() => packageRuntimeCargo(spec, output)).toThrow(`${field} must match canonical`); + manifest[field] = original; + } + const omitted = manifest.artifacts.pop(); + await writeFile(manifestPath, JSON.stringify(manifest)); + await rm(path.join(spec.payload, omitted.path)); + spec.payloadFiles = spec.payloadFiles.filter( + (file) => file !== path.join(spec.payload, omitted.path), + ); + expect(() => packageRuntimeCargo(spec, output)).toThrow('missing core runtime AOT artifacts'); + await writeFile(path.join(spec.payload, manifest.artifacts[0].path), 'stale bytes'); + expect(() => packageRuntimeCargo(spec, output)).toThrow('compressed SHA-256 mismatch'); +}); diff --git a/build_defs/wasix/carriers-repository.bzl b/build_defs/wasix/carriers-repository.bzl new file mode 100644 index 000000000..0fd901dc5 --- /dev/null +++ b/build_defs/wasix/carriers-repository.bzl @@ -0,0 +1,113 @@ +"""Import the final packed WASIX runtime crates for construction-only compilation.""" + +load(":cargo.bzl", "RUNTIME_CARGO_HELPERS") +load(":npm.bzl", "RUNTIME_NPM_NOTICES") + +_SOURCE_COMMIT_ENV = "OLIPHAUNT_WASIX_SOURCE_COMMIT" +_INPUTS_ENV = "OLIPHAUNT_WASIX_CARGO_INPUTS" + +def _valid_sha(value, length): + return len(value) == length and value.lower() == value and all([character in "0123456789abcdef" for character in value.elems()]) + +def _wasix_runtime_carriers_repository_impl(ctx): + source_commit = ctx.os.environ.get(_SOURCE_COMMIT_ENV, "") + inputs_root = ctx.os.environ.get(_INPUTS_ENV, "") + if not source_commit and not inputs_root and ctx.os.name.lower() == "linux" and ctx.os.arch.lower() in ["amd64", "x86_64"]: + for name, source in ctx.attr.source_packages.items(): + package_path = source.split("//", 1)[1].split(":", 1)[0] + ctx.file("%s/BUILD.bazel" % package_path, 'package(default_visibility = ["//visibility:public"])\nalias(name = "lib", actual = %s)\n' % repr(source)) + ctx.file("BUILD.bazel", 'package(default_visibility = ["//visibility:public"])\nfilegroup(name = "host_smoke", srcs = %s)\n' % repr(ctx.attr.host_smoke_sources)) + return + if not _valid_sha(source_commit, 40): + fail(_SOURCE_COMMIT_ENV + " must contain the exact 40-character source commit SHA") + if not inputs_root: + fail(_INPUTS_ENV + " must name the captured WASIX Cargo receipt directory") + + for source in [ctx.attr.release_manifest, ctx.attr.toolchain_manifest, ctx.attr.cargo_lock, ctx.attr.version_manifest, ctx.attr.tools_version_manifest, ctx.attr.root_package_json, ctx.attr._helper] + ctx.attr._helpers + ctx.attr._notices: + ctx.read(source) + ctx.watch(ctx.path(source)) + bun = ctx.path(ctx.attr.bun) + ctx.watch(bun) + receipt = ctx.path(inputs_root).get_child("receipt.json") + if not receipt.exists: + fail(_INPUTS_ENV + " is missing receipt.json") + ctx.watch(receipt) + receipt_data = json.decode(ctx.read(receipt)) + expected_names = [ + "liboliphaunt-wasix-aot-aarch64-apple-darwin", + "liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu", + "liboliphaunt-wasix-aot-x86_64-pc-windows-msvc", + "liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu", + "liboliphaunt-wasix-portable", + ] + rows = receipt_data.get("crates", []) + if len(rows) != 5 or sorted([row.get("name", "") for row in rows]) != expected_names: + fail(_INPUTS_ENV + " receipt must identify exactly the five canonical Cargo crates") + for row in rows + receipt_data.get("hostSmokeCrates", []): + filename = row.get("path", "") + name = row.get("name", "") + version = row.get("version", "") + if filename != name + "-" + version + ".crate" or "/" in filename or "\\" in filename: + fail(_INPUTS_ENV + " receipt contains a non-canonical crate path") + crate = ctx.path(inputs_root).get_child(filename) + if not crate.exists: + fail(_INPUTS_ENV + " is missing " + filename) + ctx.watch(crate) + source_root = ctx.path(ctx.attr.root_package_json).dirname + rust_defs = str(ctx.attr.rust_defs) + crates_defs = str(ctx.attr.crates_defs) + result = ctx.execute([ + str(bun), + str(ctx.path(ctx.attr._helper)), + "extract", + str(receipt), + str(receipt.dirname), + source_commit, + str(ctx.path(".")), + str(ctx.path(ctx.attr.release_manifest)), + str(ctx.path(ctx.attr.toolchain_manifest)), + str(ctx.path(ctx.attr.cargo_lock)), + str(ctx.path(ctx.attr.version_manifest)), + rust_defs, + crates_defs, + str(source_root), + ], quiet = True, timeout = 600) + if result.return_code: + fail("Cannot import exact packed WASIX Cargo inputs:\n" + result.stdout + result.stderr) + return + +wasix_runtime_carriers_repository = repository_rule( + implementation = _wasix_runtime_carriers_repository_impl, + environ = [_SOURCE_COMMIT_ENV, _INPUTS_ENV], + configure = True, + attrs = { + "release_manifest": attr.label(default = Label("//src/wasix/runtime:release.toml"), allow_single_file = True), + "toolchain_manifest": attr.label(default = Label("//src/wasix/runtime:toolchain.toml"), allow_single_file = True), + "cargo_lock": attr.label(default = Label("//:Cargo.lock"), allow_single_file = True), + "root_package_json": attr.label(default = Label("//:package.json"), allow_single_file = True), + "version_manifest": attr.label(default = Label("//src/wasix/runtime/crates/assets:Cargo.toml"), allow_single_file = True), + "tools_version_manifest": attr.label(default = Label("//src/wasix/postgres-tools:crates/tools/Cargo.toml"), allow_single_file = True), + "rust_defs": attr.label(default = Label("//build_defs/languages:rust.bzl"), allow_single_file = True), + "crates_defs": attr.label(default = Label("@cargo_crates//:defs.bzl"), allow_single_file = True), + "bun": attr.label(default = Label("@bun_runtime//:bun"), allow_single_file = True), + "_helper": attr.label(default = Label("//build_defs/wasix:cargo-inputs.mts"), allow_single_file = True), + "_helpers": attr.label_list(default = RUNTIME_CARGO_HELPERS + ["//build_defs/wasix:cargo.mts", "//build_defs/languages:cargo-metadata.mts", "//:tools/packaging/frozen-cargo.mts"], allow_files = True), + "_notices": attr.label_list(default = RUNTIME_NPM_NOTICES.keys(), allow_files = True), + "source_packages": attr.string_dict(default = { + "liboliphaunt-wasix-portable": str(Label("//src/wasix/runtime/crates/assets:lib")), + "liboliphaunt-wasix-aot-aarch64-apple-darwin": str(Label("//src/wasix/runtime/crates/aot/aarch64-apple-darwin:lib")), + "liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu": str(Label("//src/wasix/runtime/crates/aot/aarch64-unknown-linux-gnu:lib")), + "liboliphaunt-wasix-aot-x86_64-pc-windows-msvc": str(Label("//src/wasix/runtime/crates/aot/x86_64-pc-windows-msvc:lib")), + "liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu": str(Label("//src/wasix/runtime/crates/aot/x86_64-unknown-linux-gnu:lib")), + }), + "host_smoke_sources": attr.string_list(default = [ + str(Label("//src/wasix/runtime/crates/assets:crate")), + str(Label("//build_defs/extensions/wasix:contrib")), + str(Label("//src/wasix/postgres-tools:portable_cargo")), + str(Label("//src/wasix/postgres-tools:linux_arm64_gnu_cargo")), + str(Label("//src/wasix/postgres-tools:linux_x64_gnu_cargo")), + str(Label("//src/wasix/postgres-tools:macos_arm64_cargo")), + str(Label("//src/wasix/postgres-tools:windows_x64_msvc_cargo")), + ]), + }, +) diff --git a/build_defs/wasix/config.bzl b/build_defs/wasix/config.bzl new file mode 100644 index 000000000..c2da3ec4e --- /dev/null +++ b/build_defs/wasix/config.bzl @@ -0,0 +1,57 @@ +"""PostgreSQL WASIX product policy; compiler/libc availability is measured.""" + +WASIX_POLICY = { + "ALIGNOF_DOUBLE": "8", + "ALIGNOF_INT": "4", + "ALIGNOF_INT64_T": "8", + "ALIGNOF_LONG": "4", + "ALIGNOF_SHORT": "2", + "BLCKSZ": "8192", + "CONFIGURE_ARGS": '"Bazel wasm32 WASIX exceptions/PIC static ICU"', + "DEF_PGPORT": "5432", + "DEF_PGPORT_STR": '"5432"', + "DLSUFFIX": '".so"', + "MAXIMUM_ALIGNOF": "8", + "MEMSET_LOOP_LIMIT": "1024", + "PACKAGE_BUGREPORT": '"pgsql-bugs@lists.postgresql.org"', + "PACKAGE_NAME": '"PostgreSQL"', + "PACKAGE_TARNAME": '"postgresql"', + "PACKAGE_URL": '"https://www.postgresql.org/"', + "PG_CXX_PRINTF_ATTRIBUTE": "printf", + "PG_C_PRINTF_ATTRIBUTE": "printf", + "PG_KRB_SRVNAM": '"postgres"', + "RELSEG_SIZE": "131072", + "SIZEOF_LONG": "4", + "SIZEOF_LONG_LONG": "8", + "SIZEOF_OFF_T": "8", + "SIZEOF_SIZE_T": "4", + "SIZEOF_VOID_P": "4", + "STDC_HEADERS": "1", + "USE_ICU": "1", + "USE_SLICING_BY_8_CRC32C": "1", + "USE_SYSV_SHARED_MEMORY": "1", + "USE_UNNAMED_POSIX_SEMAPHORES": "1", + "XLOG_BLCKSZ": "8192", + "pg_restrict": "__restrict", + "restrict": "__restrict", +} + +WASIX_COPTS = [ + "-ffile-prefix-map=" + Label("@postgres_wasix//:src/include/pg_config.h.in").workspace_root + "/=postgres/", + "-std=gnu11", + "-O2", + "-g0", + "-flto=thin", + "-fno-strict-aliasing", + "-fwrapv", + "-Wno-declaration-after-statement", + "-Wno-macro-redefined", + "-Wno-unused-function", + "-Wno-missing-prototypes", + "-Wno-incompatible-pointer-types", +] + +WASIX_DEFINES = ["_GNU_SOURCE", "OLIPHAUNT_WASM_SINGLE_USER"] + [ + name + "=oliphaunt_wasix_" + name + for name in ["system", "popen", "pclose", "exit", "munmap", "fcntl", "atexit", "setsockopt", "getsockopt", "getsockname", "socket", "connect", "recv", "send", "poll", "longjmp", "siglongjmp"] +] diff --git a/build_defs/wasix/config_probe.c b/build_defs/wasix/config_probe.c new file mode 100644 index 000000000..45b498882 --- /dev/null +++ b/build_defs/wasix/config_probe.c @@ -0,0 +1,34 @@ +#define _GNU_SOURCE 1 +#include +#include +#include +#include +#include "pg_config.h" + +#define ABI_SIZE(type, macro) _Static_assert(sizeof(type) == macro, #macro) +#define ABI_ALIGN(type, macro) _Static_assert(_Alignof(type) == macro, #macro) +ABI_SIZE(long, SIZEOF_LONG); +ABI_SIZE(long long, SIZEOF_LONG_LONG); +ABI_SIZE(off_t, SIZEOF_OFF_T); +ABI_SIZE(size_t, SIZEOF_SIZE_T); +ABI_SIZE(void *, SIZEOF_VOID_P); +ABI_ALIGN(double, ALIGNOF_DOUBLE); +ABI_ALIGN(int, ALIGNOF_INT); +ABI_ALIGN(int64_t, ALIGNOF_INT64_T); +ABI_ALIGN(long, ALIGNOF_LONG); +ABI_ALIGN(short, ALIGNOF_SHORT); + +/* Availability and port sources share actual autoconf compile/link facts. + * This contract retains explicit wasm32 ABI and atomic checks. Interface + * enumeration uses PostgreSQL's supported ioctl or generic loopback fallback. + * The final declared link requires libm; a dead linker cannot mean that all + * optional capabilities are absent. */ +#ifndef HAVE_LIBM +#error "WASIX configuration must link the declared libm dependency" +#endif +#if !defined(HAVE_GETIFADDRS) && defined(SIOCGIFCONF) +_Static_assert(SIOCGIFCONF != 0, "PostgreSQL interface enumeration fallback"); +#endif + +_Static_assert(__atomic_always_lock_free(4, 0), "32-bit WASIX atomics"); +_Static_assert(__atomic_always_lock_free(8, 0), "64-bit WASIX atomics"); diff --git a/build_defs/wasix/dependencies/BUILD.bazel b/build_defs/wasix/dependencies/BUILD.bazel new file mode 100644 index 000000000..ebffe25b9 --- /dev/null +++ b/build_defs/wasix/dependencies/BUILD.bazel @@ -0,0 +1,20 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/foundation:bun.bzl", "bun_binary") +load(":postgis.bzl", "wasix_postgis_dependencies") +load(":modules.bzl", "wasix_postgis_modules") + +package(default_visibility = ["//visibility:public"]) + +exports_files(glob(["*.bzl", "*.pm", "*.mts"])) + +bun_binary(name = "proj_embed", entry_point = "proj_embed.mts") +bun_binary( + name = "configure_headers", + entry_point = "configure_headers.mts", + data = ["//build_defs/extensions/postgis:configure_headers.mts"], +) + +wasix_postgis_dependencies() +wasix_postgis_modules() + +source_quality_files() diff --git a/build_defs/wasix/dependencies/configure_headers.mts b/build_defs/wasix/dependencies/configure_headers.mts new file mode 100644 index 000000000..8b426782b --- /dev/null +++ b/build_defs/wasix/dependencies/configure_headers.mts @@ -0,0 +1,249 @@ +/** Bounded WASIX wasm32 LP32 configuration over the pinned upstream templates. */ +import assert from 'node:assert/strict'; +import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import { dirname, join, resolve } from 'node:path'; +import { parseArgs } from 'node:util'; +import { configure } from '../../extensions/postgis/configure_headers.mts'; + +type Values = Record; +const utf8 = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }); +const read = (file: string): string => utf8.decode(readFileSync(file)); +const enabled = (names: string): Values => + Object.fromEntries( + names + .split(' ') + .filter(Boolean) + .map((name) => [name, '1']), + ); + +export function generateWasixHeaders({ + kind, + source, + output, + identity, +}: { + kind: string; + source: string; + output: string; + identity?: string; +}) { + source = resolve(source); + output = resolve(output); + const emit = (input: string, member: string, values: Values) => { + const destination = join(output, member); + mkdirSync(dirname(destination), { recursive: true }); + writeFileSync(destination, configure(read(join(source, input)), values)); + }; + + if (kind === 'json_c') { + const version = /project\(json-c LANGUAGES C VERSION ([0-9]+)\.([0-9]+)\)/u.exec( + read(join(source, 'CMakeLists.txt')), + ); + assert(version, 'Review pinned json-c upstream version syntax'); + // The selected WASIX ehpic driver supplies process-clock emulation. + // JSON's optional threading and x86 RDRAND remain disabled. + const values = { + ...enabled( + 'HAVE_DLFCN_H HAVE_ENDIAN_H HAVE_FCNTL_H HAVE_INTTYPES_H HAVE_LIMITS_H HAVE_LOCALE_H HAVE_MEMORY_H HAVE_STDARG_H HAVE_STDINT_H HAVE_STDLIB_H HAVE_STRINGS_H HAVE_STRING_H HAVE_SYSLOG_H HAVE_SYS_CDEFS_H HAVE_SYS_PARAM_H HAVE_SYS_RANDOM_H HAVE_SYS_RESOURCE_H HAVE_SYS_STAT_H HAVE_SYS_TYPES_H HAVE_UNISTD_H HAVE_ATOMIC_BUILTINS HAVE_DECL_INFINITY HAVE_DECL_ISINF HAVE_DECL_ISNAN HAVE_DECL_NAN HAVE_OPEN HAVE_REALLOC HAVE_SETLOCALE HAVE_SNPRINTF HAVE_STRCASECMP HAVE_STRDUP HAVE_STRERROR HAVE_STRNCASECMP HAVE_USELOCALE HAVE_VASPRINTF HAVE_VPRINTF HAVE_VSNPRINTF HAVE_VSYSLOG HAVE_GETRANDOM HAVE_GETRUSAGE HAVE_STRTOLL HAVE_STRTOULL HAVE___THREAD JSON_C_HAVE_INTTYPES_H JSON_C_HAVE_STDINT_H STDC_HEADERS', + ), + PROJECT_NAME: 'json-c', + JSON_C_BUGREPORT: 'json-c@googlegroups.com', + CPACK_PACKAGE_VERSION_MAJOR: version[1], + CPACK_PACKAGE_VERSION_MINOR: version[2], + CPACK_PACKAGE_VERSION_PATCH: '0', + SIZEOF_INT: '4', + SIZEOF_INT64_T: '8', + SIZEOF_LONG: '4', + SIZEOF_LONG_LONG: '8', + SIZEOF_SIZE_T: '4', + SIZEOF_SSIZE_T: '4', + SPEC___THREAD: '__thread', + json_c_strtoll: 'strtoll', + json_c_strtoull: 'strtoull', + JSON_H_JSON_POINTER: '#include "json_pointer.h"', + JSON_H_JSON_PATCH: '#include "json_patch.h"', + }; + emit('cmake/config.h.in', 'config.h', values); + emit('cmake/json_config.h.in', 'json_config.h', values); + emit('json.h.cmakein', 'json.h', values); + } else if (kind === 'libxml2') { + const version = read(join(source, 'VERSION')).trim(); + assert.match(version, /^\d+\.\d+\.\d+$/u, 'Invalid pinned libxml2 VERSION'); + const [major, minor, patch] = version.split('.').map(Number); + const values = { + ...enabled( + 'HAVE_DECL_GETENTROPY HAVE_DECL_GLOB HAVE_FUNC_ATTRIBUTE_DESTRUCTOR HAVE_POLL_H HAVE_STDINT_H WITH_C14N WITH_CATALOG WITH_DEBUG WITH_HTML WITH_ISO8859X WITH_OUTPUT WITH_PATTERN WITH_PUSH WITH_READER WITH_REGEXPS WITH_RELAXNG WITH_SAX1 WITH_SCHEMAS WITH_SCHEMATRON WITH_VALID WITH_WRITER WITH_XINCLUDE WITH_XPATH WITH_XPTR', + ), + // The selected WASIX ehpic driver supplies mmap emulation. Canonical + // XML disables threads, modules, iconv, HTTP and compressed input. + HAVE_DECL_MMAP: '1', + VERSION: version, + LIBXML_VERSION_NUMBER: String(major * 10000 + minor * 100 + patch), + LIBXML_VERSION_EXTRA: '', + MODULE_EXTENSION: '.so', + XML_SYSCONFDIR: '/oliphaunt/runtime/etc', + WITH_THREADS: '0', + WITH_THREAD_ALLOC: '0', + WITH_MODULES: '0', + WITH_ICONV: '0', + WITH_HTTP: '0', + WITH_ICU: '0', + WITH_LZMA: '0', + WITH_ZLIB: '0', + }; + emit('config.h.cmake.in', 'config.h', values); + emit('include/libxml/xmlversion.h.in', 'libxml/xmlversion.h', values); + } else if (kind === 'libiconv') { + const values = { + ...enabled( + 'HAVE_GETC_UNLOCKED HAVE_LANGINFO_CODESET HAVE_MBRTOWC HAVE_SETLOCALE HAVE_STDDEF_H HAVE_STDLIB_H HAVE_STRING_H HAVE_VISIBILITY HAVE_WCRTOMB HAVE_WORKING_O_NOFOLLOW WORDS_LITTLEENDIAN HAVE_STDIO_H HAVE_STRINGS_H HAVE_SYS_STAT_H HAVE_SYS_TYPES_H HAVE_UNISTD_H HAVE_INTTYPES_H HAVE_STDINT_H', + ), + DLL_VARIABLE: '', + ICONV_CONST: '', + // iconv.h includes errno.h first. Preserve the selected WASI sysroot's + // exact ABI symbol (__errno_values.h), rather than a Linux errno number. + EILSEQ: '__WASI_ERRNO_ILSEQ', + USE_MBSTATE_T: '1', + BROKEN_WCHAR_H: '0', + INSTALLPREFIX: '"/oliphaunt/runtime"', + prefix: '/oliphaunt/runtime', + }; + emit('lib/config.h.in', 'config.h', values); + emit('include/iconv.h.build.in', 'iconv.h', values); + emit('libcharset/include/localcharset.h.build.in', 'localcharset.h', values); + emit('libcharset/include/libcharset.h.build.in', 'libcharset.h', values); + } else if (kind === 'proj') { + // Canonical WASIX PROJ has no libdl, TIFF, curl or Emscripten fetch. + emit('cmake/proj_config.cmake.in', 'proj_config.h', enabled('HAVE_LOCALECONV HAVE_STRERROR')); + } else if (kind === 'geos') { + const version = Object.fromEntries( + [...read(join(source, 'Version.txt')).matchAll(/^(\w+)=(.*)$/gmu)].map((match) => [ + match[1], + match[2], + ]), + ); + const major = version.GEOS_VERSION_MAJOR; + const minor = version.GEOS_VERSION_MINOR; + const patch = version.GEOS_VERSION_PATCH; + const apiMajor = Number(version.CAPI_INTERFACE_CURRENT) - Number(version.CAPI_INTERFACE_AGE); + assert( + major && minor && patch && Number.isInteger(apiMajor), + 'Invalid pinned GEOS Version.txt', + ); + const values = { + VERSION_MAJOR: major, + VERSION_MINOR: minor, + VERSION_PATCH: patch, + VERSION: `${major}.${minor}.${patch}${version.GEOS_PATCH_WORD ?? ''}`, + JTS_PORT: version.JTS_PORT, + CAPI_VERSION_MAJOR: String(apiMajor), + CAPI_VERSION_MINOR: version.CAPI_INTERFACE_AGE, + CAPI_VERSION_PATCH: version.CAPI_INTERFACE_REVISION, + CAPI_VERSION: `${apiMajor}.${version.CAPI_INTERFACE_AGE}.${version.CAPI_INTERFACE_REVISION}`, + }; + emit('include/geos/version.h.in', 'geos/version.h', values); + emit('capi/geos_c.h.in', 'geos_c.h', values); + } else if (kind === 'postgis') { + assert(identity, 'PostGIS configuration requires declared --identity'); + const facts = JSON.parse(read(identity)) as { + commit: string; + source_date_epoch: number; + default_version: string; + postgres_major: number; + postgres_version: string; + dependencies: Record; + }; + const version = Object.fromEntries( + [...read(join(source, 'Version.config')).matchAll(/^(\w+)=(.*)$/gmu)].map((match) => [ + match[1], + match[2], + ]), + ); + const major = version.POSTGIS_MAJOR_VERSION; + const minor = version.POSTGIS_MINOR_VERSION; + const micro = version.POSTGIS_MICRO_VERSION; + const fullVersion = `${major}.${minor}.${micro}`; + assert( + fullVersion === facts.default_version && + facts.postgres_major === 18 && + /^[a-f0-9]{40}$/u.test(facts.commit), + 'PostGIS source/configuration disagrees with canonical identity', + ); + const dependencyVersion = (name: string) => { + const value = facts.dependencies[name].branch.replace(/^v/u, ''); + assert.match(value, /^\d+\.\d+\.\d+$/u, `Invalid pinned ${name} version`); + return value; + }; + const number = (value: string) => + value + .split('.') + .map((part, index) => (index ? part.padStart(2, '0') : part)) + .join(''); + const date = new Date(facts.source_date_epoch * 1000); + assert( + Number.isSafeInteger(facts.source_date_epoch) && + facts.source_date_epoch > 0 && + !Number.isNaN(date.valueOf()), + 'Invalid canonical PostGIS build epoch', + ); + const displayVersion = `${major}.${minor} USE_GEOS=1 USE_PROJ=1 USE_STATS=1`; + const values = { + ...enabled( + 'HAVE_FSEEKO HAVE_ICONV HAVE_ICONVCTL HAVE_LIBGEOS_C HAVE_LIBICONVCTL HAVE_LIBJSON HAVE_LIBPROJ HAVE_LIBXML2 HAVE_LIBXML_PARSER_H HAVE_LIBXML_TREE_H HAVE_LIBXML_XPATHINTERNALS_H HAVE_LIBXML_XPATH_H HAVE_UNISTD_H STDC_HEADERS YYTEXT_POINTER', + ), + POSTGIS_LIB_VERSION: fullVersion, + POSTGIS_MAJOR_VERSION: major, + POSTGIS_MINOR_VERSION: minor, + POSTGIS_MICRO_VERSION: micro, + POSTGIS_GEOS_VERSION: number(dependencyVersion('geos')), + POSTGIS_PROJ_VERSION: number(dependencyVersion('proj')), + POSTGIS_LIBXML2_VERSION: dependencyVersion('libxml2'), + POSTGIS_SFCGAL_VERSION: '0', + POSTGIS_PGSQL_VERSION: '180', + POSTGIS_PGSQL_HR_VERSION: facts.postgres_version, + POSTGIS_VERSION: displayVersion, + POSTGIS_BUILD_DATE: date.toISOString().slice(0, 19).replace('T', ' '), + POSTGIS_SCRIPTS_VERSION: fullVersion, + SRID_MAX: '999999', + SRID_USR_MAX: '998999', + EXTVERSION: fullVersion, + EXTENSION: 'postgis', + MODULEPATH: '$libdir/postgis-3', + }; + const quoted = { + ...values, + POSTGIS_LIB_VERSION: JSON.stringify(fullVersion), + POSTGIS_LIBXML2_VERSION: JSON.stringify(values.POSTGIS_LIBXML2_VERSION), + POSTGIS_VERSION: JSON.stringify(displayVersion), + POSTGIS_BUILD_DATE: JSON.stringify(values.POSTGIS_BUILD_DATE), + POSTGIS_SCRIPTS_VERSION: JSON.stringify(fullVersion), + PGSQL_LOCALEDIR: '"/oliphaunt/runtime/share/locale"', + LT_OBJDIR: '".libs/"', + }; + emit('postgis_config.h.in', 'postgis_config.h', quoted); + emit('liblwgeom/liblwgeom.h.in', 'liblwgeom/liblwgeom.h', values); + emit('postgis/sqldefines.h.in', 'postgis/sqldefines.h', values); + emit('extensions/postgis/postgis.control.in', 'extensions/postgis/postgis.control', values); + writeFileSync(join(output, 'postgis_revision.h'), `#define POSTGIS_REVISION ${facts.commit}\n`); + } else { + throw new Error(`Unknown WASIX configuration ${kind}`); + } +} + +if (import.meta.main) { + const { values } = parseArgs({ + options: { + kind: { type: 'string' }, + source: { type: 'string' }, + output: { type: 'string' }, + identity: { type: 'string' }, + }, + }); + assert(values.kind && values.source && values.output, 'Expected --kind --source --output'); + generateWasixHeaders({ + kind: values.kind, + source: values.source, + output: values.output, + identity: values.identity, + }); +} diff --git a/build_defs/wasix/dependencies/headers.bzl b/build_defs/wasix/dependencies/headers.bzl new file mode 100644 index 000000000..6ea25a2e3 --- /dev/null +++ b/build_defs/wasix/dependencies/headers.bzl @@ -0,0 +1,56 @@ +"""Declared upstream-template configuration for the actual WASI LP32 profile.""" + +load("@oliphaunt_metadata//:metadata.bzl", "EXTENSION_DEPENDENCIES", "EXTENSION_SOURCES", "POSTGRES_SOURCE") +load("@rules_cc//cc/common:cc_common.bzl", "cc_common") +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") +load("//build_defs/foundation:bun.bzl", "BunScriptInfo", "bun_action") + +def _impl(ctx): + outputs = [ctx.actions.declare_file(ctx.label.name + "/" + path) for path in ctx.attr.outs] + root = outputs[0].path[:-len(ctx.attr.outs[0])].rstrip("/") + args = ctx.actions.args() + args.add("--kind", ctx.attr.kind) + args.add("--source", ctx.file.root.dirname) + args.add("--output", root) + inputs = ctx.files.inputs + [ctx.file.root] + if ctx.attr.kind == "postgis": + source = EXTENSION_SOURCES["postgis"] + identity = ctx.actions.declare_file(ctx.label.name + ".identity.json") + ctx.actions.write(identity, json.encode({ + "commit": source["commit"], + "source_date_epoch": source["source_date_epoch"], + "default_version": source["extension-control"]["default-version"], + "postgres_major": int(POSTGRES_SOURCE["postgresql"]["version"].split(".")[0]), + "postgres_version": POSTGRES_SOURCE["postgresql"]["version"], + "dependencies": EXTENSION_DEPENDENCIES["postgis"], + })) + args.add("--identity", identity) + inputs.append(identity) + bun_action( + ctx, + ctx.attr._generator, + inputs = inputs, + outputs = outputs, + arguments = [args], + mnemonic = "WasixDependencyConfig", + ) + return [ + DefaultInfo(files = depset(outputs)), + OutputGroupInfo(control = depset([file for file in outputs if file.basename.endswith(".control")])), + CcInfo(compilation_context = cc_common.create_compilation_context( + headers = depset(outputs), + includes = depset([root + ("/" + directory if directory else "") for directory in ctx.attr.include_dirs]), + )), + ] + +wasix_dependency_headers = rule( + implementation = _impl, + attrs = { + "kind": attr.string(mandatory = True), + "root": attr.label(allow_single_file = True, mandatory = True), + "inputs": attr.label_list(allow_files = True), + "outs": attr.string_list(mandatory = True), + "include_dirs": attr.string_list(default = [""]), + "_generator": attr.label(default = "//build_defs/wasix/dependencies:configure_headers", providers = [BunScriptInfo], cfg = "exec"), + }, +) diff --git a/build_defs/wasix/dependencies/modules.bzl b/build_defs/wasix/dependencies/modules.bzl new file mode 100644 index 000000000..69d28a18b --- /dev/null +++ b/build_defs/wasix/dependencies/modules.bzl @@ -0,0 +1,83 @@ +"""Actual PostGIS core and C++ dependency WASI side modules.""" + +load("@rules_cc//cc:defs.bzl", "cc_library") +load("//build_defs/extensions:contrib.bzl", "contrib_generated_sources") +load("//build_defs/extensions/postgis:generators.bzl", "postgis_flex") +load("//build_defs/extensions/postgis:libraries.bzl", "postgis_source_headers") +load("//build_defs/extensions/postgis:modules.bzl", "POSTGIS_LWGEOM_SOURCES", "POSTGIS_PG_SOURCES") +load("//build_defs/extensions/postgis:sql.bzl", "postgis_sql") +load("//build_defs/wasix:config.bzl", "WASIX_COPTS") +load("//build_defs/wasix:wasm.bzl", "wasix_module") +load(":headers.bzl", "wasix_dependency_headers") +load(":postgis.bzl", "WASIX_DEPENDENCY_COMPATIBLE") + +def wasix_postgis_modules(name = "postgis"): + prefix = "@postgis//:" + wasix_dependency_headers( + name = name + "_config", + kind = "postgis", + root = prefix + "Version.config", + inputs = [prefix + path for path in ["postgis_config.h.in", "liblwgeom/liblwgeom.h.in", "postgis/sqldefines.h.in", "extensions/postgis/postgis.control.in"]], + outs = ["postgis_config.h", "liblwgeom/liblwgeom.h", "postgis/sqldefines.h", "extensions/postgis/postgis.control", "postgis_revision.h"], + include_dirs = ["", "liblwgeom", "postgis"], + ) + postgis_source_headers( + name = name + "_headers", + root = prefix + "Version.config", + headers = [prefix + "postgis_headers"], + include_dirs = ["liblwgeom", "libpgcommon", "postgis", "deps", "deps/flatgeobuf", "deps/flatgeobuf/include", ""], + ) + contrib_generated_sources( + name = name + "_wkt", + grammar = prefix + "liblwgeom/lwin_wkt_parse.y", + scanner = prefix + "liblwgeom/lwin_wkt_lex.l", + grammar_options = ["-d", "-p", "wkt_yy"], + scanner_options = ["-i"], + scanner_rule = postgis_flex, + ) + cc_library(name = name + "_ryu", srcs = [prefix + "deps/ryu/d2s.c"], deps = [":" + name + "_headers"], defines = ["RYU_NO_TRAILING_ZEROS"], copts = WASIX_COPTS + ["-fPIC", "-fvisibility=hidden"], linkstatic = True, target_compatible_with = WASIX_DEPENDENCY_COMPATIBLE) + cc_library( + name = name + "_lwgeom", + srcs = [prefix + source for source in POSTGIS_LWGEOM_SOURCES] + [":" + name + "_wkt"], + deps = [":" + name + "_config", ":" + name + "_headers", ":" + name + "_wkt", ":" + name + "_ryu", ":geos", ":proj", ":json_c"], + copts = WASIX_COPTS + ["-fPIC", "-fvisibility=hidden"], + linkstatic = True, + target_compatible_with = WASIX_DEPENDENCY_COMPATIBLE, + ) + cc_library( + name = name + "_flatgeobuf", + srcs = [prefix + "deps/flatgeobuf/" + source + ".cpp" for source in ["flatgeobuf_c", "geometrywriter", "geometryreader", "packedrtree"]], + deps = [":" + name + "_config", ":" + name + "_headers", ":proj"], + copts = ["-std=c++17", "-O2", "-g0", "-fPIC", "-flto=thin", "-fvisibility=hidden", "-fvisibility-inlines-hidden"], + defines = ["flatbuffers=postgis_flatbuffers"], + linkstatic = True, + target_compatible_with = WASIX_DEPENDENCY_COMPATIBLE, + ) + cc_library(name = name + "_lifecycle", srcs = ["postgis_lifecycle.c"], copts = WASIX_COPTS + ["-fPIC", "-fvisibility=hidden"], linkstatic = True, target_compatible_with = WASIX_DEPENDENCY_COMPATIBLE) + wasix_module( + name = name + "_dependency_module", + output_name = "liboliphaunt_postgis_deps.so", + deps = [":" + name + "_lifecycle"] + [":" + library for library in ["geos", "proj", "sqlite", "json_c", "libxml2", "iconv"]], + cxx_runtime = True, + linkopts = ["--export-all", "--no-gc-sections"], + target_compatible_with = WASIX_DEPENDENCY_COMPATIBLE, + ) + cc_library( + name = name + "_objects", + srcs = [prefix + source for source in POSTGIS_PG_SOURCES], + deps = [":" + name + "_config", ":" + name + "_headers", ":" + name + "_lwgeom", ":" + name + "_flatgeobuf", ":libxml2", ":iconv", "@postgres_wasix//:server_headers"], + copts = WASIX_COPTS + ["-fPIC", "-fvisibility=hidden"], + linkstatic = True, + target_compatible_with = WASIX_DEPENDENCY_COMPATIBLE, + ) + wasix_module( + name = name, + output_name = "postgis-3.so", + deps = [":" + name + "_objects"], + dynamic_deps = [":" + name + "_dependency_module"], + target_compatible_with = WASIX_DEPENDENCY_COMPATIBLE, + ) + postgis_sql(name = name + "_sql_resources", configuration = ":" + name + "_config", headers = ":" + name + "_headers", target_compatible_with = WASIX_DEPENDENCY_COMPATIBLE) + native.filegroup(name = name + "_extension_sql", srcs = [":" + name + "_sql_resources"], output_group = "extension_sql") + native.filegroup(name = name + "_data_sql", srcs = [":" + name + "_sql_resources"], output_group = "data_sql") + native.filegroup(name = name + "_control", srcs = [":" + name + "_config"], output_group = "control") diff --git a/build_defs/wasix/dependencies/openssl-configdata.pm b/build_defs/wasix/dependencies/openssl-configdata.pm new file mode 100644 index 000000000..71dafc94b --- /dev/null +++ b/build_defs/wasix/dependencies/openssl-configdata.pm @@ -0,0 +1,169 @@ +# Reviewed OpenSSL 3.5.6 WASI configuration for direct upstream templates. +# Source profile: canonical build_wasix_openssl.sh Configure gcc options. +# 32-bit unsigned-long bignum limbs; no threads, engines, modules, DSO or sockets. +# generate_constants.py reads this file and fills in @@PLACEHOLDER@@ values +# to produce per-platform configdata.pm stubs. +# +# Provides data for direct util/dofile.pl header/table processing. +# - include/openssl/configuration.h.in (platform-specific values) +# - include/crypto/bn_conf.h.in +# - include/crypto/dso_conf.h.in + +package configdata; +use strict; +use warnings; +use Exporter; +use File::Basename; + +our @ISA = qw(Exporter); +our @EXPORT = qw(%config %target %withargs %unified_info %disabled @disablables); +our @EXPORT_OK = qw(@disablables %unified_info %disabled); + +# This file lives at /configdata//configdata.pm. +# Resolve the repo root so paths work inside Bazel runfiles. +my $_repo_root = dirname(dirname(dirname(__FILE__))); + +# Read version from VERSION.dat (relative to source root) +my %version_data; +open(my $fh, '<', "$_repo_root/VERSION.dat") + or die "Cannot open $_repo_root/VERSION.dat: $!"; +while (<$fh>) { + chomp; + if (/^(\w+)=(.*)$/) { + my ($key, $val) = ($1, $2); + $val =~ s/^"(.*)"$/$1/; + $version_data{$key} = $val; + } +} +close($fh); + +for my $required (qw(MAJOR MINOR PATCH SHLIB_VERSION)) { + defined $version_data{$required} + or die "VERSION.dat missing required field: $required"; +} + +my $major = $version_data{MAJOR}; +my $minor = $version_data{MINOR}; +my $patch = $version_data{PATCH}; +my $pre = $version_data{PRE_RELEASE_TAG} // ''; +my $build_meta = $version_data{BUILD_METADATA} // ''; +my $release_date = $version_data{RELEASE_DATE} // ''; +my $shlib_version = $version_data{SHLIB_VERSION}; +my $version = "$major.$minor.$patch"; +my $full_version = $version . ($pre ? "-$pre" : "") . ($build_meta ? "+$build_meta" : ""); + +our @autowarntext = ( + "WARNING: do not edit!", + "Generated by configdata.pm (Bazel stub)", +); + +our %config = ( + target => "bazel", + sourcedir => $_repo_root, + builddir => $_repo_root, + major => $major, + minor => $minor, + patch => $patch, + prerelease => $pre, + build_metadata => $build_meta, + version => $version, + full_version => $full_version, + release_date => $release_date, + shlib_version => $shlib_version, + + b64l => 0, + b64 => 0, + b32 => 1, + bn_ll => 1, + rc4_int => "unsigned int", + processor => "", + + openssl_sys_defines => [], + openssl_api_defines => ["OPENSSL_CONFIGURED_API=30500"], + openssl_feature_defines => [ + "OPENSSL_RAND_SEED_OS", + "OPENSSL_NO_ACVP_TESTS", + "OPENSSL_NO_AFALGENG", + "OPENSSL_NO_APPS", + "OPENSSL_NO_ASAN", + "OPENSSL_NO_ASM", + "OPENSSL_NO_BROTLI", + "OPENSSL_NO_BROTLI_DYNAMIC", + "OPENSSL_NO_CAPIENG", + "OPENSSL_NO_CRYPTO_MDEBUG", + "OPENSSL_NO_CRYPTO_MDEBUG_BACKTRACE", + "OPENSSL_NO_DEFAULT_THREAD_POOL", + "OPENSSL_NO_DEMOS", + "OPENSSL_NO_DEVCRYPTOENG", + "OPENSSL_NO_DGRAM", + "OPENSSL_NO_DOCS", + "OPENSSL_NO_DSO", + "OPENSSL_NO_DTLS", + "OPENSSL_NO_DTLS1", + "OPENSSL_NO_DTLS1_2", + "OPENSSL_NO_EC_NISTP_64_GCC_128", + "OPENSSL_NO_EGD", + "OPENSSL_NO_ENGINE", + "OPENSSL_NO_EXTERNAL_TESTS", + "OPENSSL_NO_FIPS_JITTER", + "OPENSSL_NO_FIPS_POST", + "OPENSSL_NO_FIPS_SECURITYCHECKS", + "OPENSSL_NO_FUZZ_AFL", + "OPENSSL_NO_FUZZ_LIBFUZZER", + "OPENSSL_NO_H3DEMO", + "OPENSSL_NO_HQINTEROP", + "OPENSSL_NO_JITTER", + "OPENSSL_NO_KTLS", + "OPENSSL_NO_LOADERENG", + "OPENSSL_NO_MD2", + "OPENSSL_NO_MSAN", + "OPENSSL_NO_PADLOCKENG", + "OPENSSL_NO_PIE", + "OPENSSL_NO_PINSHARED", + "OPENSSL_NO_QLOG", + "OPENSSL_NO_QUIC", + "OPENSSL_NO_RC5", + "OPENSSL_NO_SCTP", + "OPENSSL_NO_SECURE_MEMORY", + "OPENSSL_NO_SOCK", + "OPENSSL_NO_SSL3", + "OPENSSL_NO_SSL3_METHOD", + "OPENSSL_NO_SSLKEYLOG", + "OPENSSL_NO_TESTS", + "OPENSSL_NO_TFO", + "OPENSSL_NO_THREAD_POOL", + "OPENSSL_NO_TRACE", + "OPENSSL_NO_UBSAN", + "OPENSSL_NO_UNIT_TEST", + "OPENSSL_NO_UNSTABLE_QLOG", + "OPENSSL_NO_UPLINK", + "OPENSSL_NO_WEAK_SSL_CIPHERS", + "OPENSSL_NO_WINSTORE", + "OPENSSL_NO_ZLIB", + "OPENSSL_NO_ZLIB_DYNAMIC", + "OPENSSL_NO_ZSTD", + "OPENSSL_NO_ZSTD_DYNAMIC", + "OPENSSL_NO_DYNAMIC_ENGINE", + ], + + FIPSKEY => "f4556650ac31d35461610bac4ed81b1a181b2d8a43ea2854cbae22ca74560813", +); + +our %target = ( + build_file => "Makefile", + perl_platform => "Unix", + dso_scheme => "NONE", + dso_extension => ".so", +); + +our %withargs = (); + +our %disabled = (q(acvp-tests) => q(cascade),q(afalgeng) => q(cascade),q(apps) => q(option),q(asan) => q(default),q(asm) => q(no asm_arch),q(brotli) => q(default),q(brotli-dynamic) => q(default),q(buildtest-c++) => q(default),q(capieng) => q(cascade),q(crypto-mdebug) => q(default),q(crypto-mdebug-backtrace) => q(default),q(default-thread-pool) => q(cascade),q(demos) => q(default),q(devcryptoeng) => q(default),q(dgram) => q(option),q(docs) => q(option),q(dso) => q(option),q(dtls) => q(cascade),q(dtls1) => q(cascade),q(dtls1_2) => q(cascade),q(dynamic-engine) => q(cascade),q(ec_nistp_64_gcc_128) => q(default),q(egd) => q(default),q(engine) => q(option),q(external-tests) => q(default),q(fips) => q(default),q(fips-jitter) => q(default),q(fips-post) => q(cascade),q(fips-securitychecks) => q(cascade),q(fuzz-afl) => q(default),q(fuzz-libfuzzer) => q(default),q(h3demo) => q(default),q(hqinterop) => q(default),q(jitter) => q(default),q(ktls) => q(default),q(loadereng) => q(cascade),q(md2) => q(default),q(module) => q(option),q(msan) => q(default),q(padlockeng) => q(cascade),q(pic) => q(no-shared-target),q(pie) => q(default),q(pinshared) => q(option),q(qlog) => q(1),q(quic) => q(cascade),q(rc5) => q(default),q(sctp) => q(default),q(secure-memory) => q(option),q(shared) => q(option),q(sock) => q(option),q(ssl3) => q(default),q(ssl3-method) => q(default),q(sslkeylog) => q(default),q(tests) => q(option),q(tfo) => q(default),q(thread-pool) => q(cascade),q(threads) => q(option),q(trace) => q(default),q(ubsan) => q(default),q(unit-test) => q(default),q(unstable-qlog) => q(cascade),q(uplink) => q(no uplink_arch),q(weak-ssl-ciphers) => q(default),q(winstore) => q(not-windows),q(zlib) => q(option),q(zlib-dynamic) => q(default),q(zstd) => q(default),q(zstd-dynamic) => q(default)); + +# No apps are constructed in this profile. The upstream templates only need +# the source attribute map, so there are no undeclared app-directory reads. +our %unified_info = (sources => {}, attributes => { sources => {} }); + +our @disablables = qw(acvp-tests afalgeng apps argon2 aria asan asm async atexit autoalginit autoerrinit autoload-config bf blake2 brotli brotli-dynamic buildtest-c++ bulk cached-fetch camellia capieng winstore cast chacha cmac cmp cms comp crypto-mdebug ct default-thread-pool demos h3demo hqinterop deprecated des devcryptoeng dgram dh docs dsa dso dtls dynamic-engine ec ec2m ec_nistp_64_gcc_128 ecdh ecdsa ecx egd engine err external-tests filenames fips fips-securitychecks fips-post fips-jitter fuzz-afl fuzz-libfuzzer gost http idea integrity-only-ciphers jitter ktls legacy loadereng makedepend md2 md4 mdc2 ml-dsa ml-kem module msan multiblock nextprotoneg ocb ocsp padlockeng pic pie pinshared poly1305 posix-io psk quic unstable-qlog rc2 rc4 rc5 rdrand rfc3779 rmd160 scrypt sctp secure-memory seed shared siphash siv slh-dsa sm2 sm2-precomp sm3 sm4 sock srp srtp sse2 ssl ssl-trace static-engine stdio sslkeylog tests tfo thread-pool threads tls tls-deprecated-ec trace ts ubsan ui-console unit-test uplink weak-ssl-ciphers whirlpool zlib zlib-dynamic zstd zstd-dynamic ssl3 ssl3-method tls1 tls1-method tls1_1 tls1_1-method tls1_2 tls1_2-method tls1_3 dtls1 dtls1-method dtls1_2 dtls1_2-method); + +1; diff --git a/build_defs/wasix/dependencies/openssl.bzl b/build_defs/wasix/dependencies/openssl.bzl new file mode 100644 index 000000000..0d1c44b85 --- /dev/null +++ b/build_defs/wasix/dependencies/openssl.bzl @@ -0,0 +1,115 @@ +"""Direct OpenSSL libcrypto construction for the maintained WASI profile. + +Called in the canonical @openssl source repository. Host Perl expands the +upstream templates; the wasm32 toolchain compiles the resulting C units. +""" + +load("@rules_cc//cc:defs.bzl", "cc_library") +load("@rules_cc//cc/common:cc_common.bzl", "cc_common") +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") +load("@rules_perl//perl:perl.bzl", "perl_binary", "perl_library") +load(":openssl_sources.bzl", "OPENSSL_WASIX_C_SOURCES", "OPENSSL_WASIX_TEMPLATES") + +_COMPATIBLE = ["@platforms//cpu:wasm32", "@platforms//os:wasi"] + +def _generate_impl(ctx): + outputs = [] + for template, destination in ctx.attr.templates.items(): + file = template.files.to_list()[0] + output = ctx.actions.declare_file(ctx.label.name + "/" + destination) + outputs.append(output) + args = ctx.actions.args() + args.add("--in=" + file.path) + args.add("--out=" + output.path) + # ASN.1 OID registration is process-global; each upstream template + # expansion needs a fresh interpreter to match util/dofile.pl. + ctx.actions.run( + executable = ctx.attr.batch[DefaultInfo].files_to_run, + inputs = [file], + outputs = [output], + arguments = [args], + mnemonic = "OpenSslWasixTemplate", + ) + buildinf = ctx.actions.declare_file(ctx.label.name + "/crypto/buildinf.h") + args = ctx.actions.args() + args.add(ctx.executable.buildinf) + args.add(buildinf) + args.add("--") + args.add("wasm32-wasi no-asm static") + args.add("wasm32-wasi") + ctx.actions.run( + executable = ctx.attr.redirect[DefaultInfo].files_to_run, + tools = [ctx.attr.buildinf[DefaultInfo].files_to_run], + outputs = [buildinf], + arguments = [args], + env = {"SOURCE_DATE_EPOCH": "443779200"}, + mnemonic = "OpenSslWasixBuildInfo", + ) + headers = [file for file in outputs if file.basename.endswith(".h")] + [buildinf] + sources = [file for file in outputs if file.basename.endswith(".c")] + # Derive the generated tree root independently of the first template depth. + root = outputs[0].path.split("/" + ctx.label.name + "/")[0] + "/" + ctx.label.name + return [ + DefaultInfo(files = depset(headers + sources)), + OutputGroupInfo(headers = depset(headers), library_sources = depset(sources)), + CcInfo(compilation_context = cc_common.create_compilation_context( + headers = depset(headers), + includes = depset([root + "/include", root + "/crypto", root + "/providers/common/include"]), + )), + ] + +_openssl_generate = rule( + implementation = _generate_impl, + attrs = { + "templates": attr.label_keyed_string_dict(allow_files = True), + "batch": attr.label(executable = True, cfg = "exec", mandatory = True), + "buildinf": attr.label(executable = True, cfg = "exec", mandatory = True), + "redirect": attr.label(executable = True, cfg = "exec", mandatory = True), + }, +) + +def wasix_openssl(name): + """Compile the canonical static libcrypto and its built-in legacy provider.""" + perl_library( + name = name + "_configdata", + srcs = ["configdata/wasix/configdata.pm"], + includes = ["configdata/wasix"], + data = ["VERSION.dat"], + ) + perl_library( + name = name + "_platform", + srcs = ["Configurations/platform.pm"] + native.glob(["Configurations/platform/*.pm"]), + includes = ["Configurations"], + deps = [":" + name + "_configdata"], + ) + perl_binary( + name = name + "_batch", + srcs = ["util/wasix_batch_dofile.pl"], + main = "util/wasix_batch_dofile.pl", + perlopt = ["-Mconfigdata", "-Moids_to_c"], + deps = [":" + name + "_configdata", ":" + name + "_platform", ":der_codegen", ":external_perl", ":perl_utils"], + ) + generated = name + "_generated" + _openssl_generate( + name = generated, + templates = OPENSSL_WASIX_TEMPLATES, + batch = ":" + name + "_batch", + buildinf = ":mkbuildinf", + redirect = "//bazel:redirect_stdout", + ) + native.filegroup(name = name + "_generated_sources", srcs = [":" + generated], output_group = "library_sources") + native.filegroup(name = name + "_generated_headers", srcs = [":" + generated], output_group = "headers") + cc_library( + name = name, + srcs = OPENSSL_WASIX_C_SOURCES + [":" + name + "_generated_sources"], + hdrs = native.glob(["crypto/**/*.h", "include/crypto/**/*.h", "include/internal/*.h", "include/openssl/*.h", "providers/**/*.h", "providers/**/*.inc"]), + textual_hdrs = ["crypto/des/ncbc_enc.c", "crypto/LPdir_unix.c"] + native.glob(["providers/implementations/**/*.c"]), + deps = [":" + generated], + includes = ["include", "crypto", "providers/implementations/macs", "providers/implementations/include", "providers/common/include", "providers/fips/include"], + local_defines = ["NDEBUG", "OPENSSL_BUILDING_OPENSSL", "OPENSSL_PIC", "L_ENDIAN", "STATIC_LEGACY", "OPENSSL_NO_MODULE"], + copts = ["-std=gnu11", "-O2", "-g0", "-fPIC", "-flto=thin", "-fvisibility=hidden", "-Wno-unused-command-line-argument", '-DOPENSSLDIR=\\"/oliphaunt/runtime/openssl/ssl\\"', '-DENGINESDIR=\\"/dev/null\\"', '-DMODULESDIR=\\"/dev/null\\"', + "-ffile-prefix-map=" + Label("@openssl//:crypto/cryptlib.c").workspace_root + "/=openssl/"], + linkstatic = True, + target_compatible_with = _COMPATIBLE, + visibility = ["//visibility:public"], + ) diff --git a/build_defs/wasix/dependencies/openssl_sources.bzl b/build_defs/wasix/dependencies/openssl_sources.bzl new file mode 100644 index 000000000..6142f08cc --- /dev/null +++ b/build_defs/wasix/dependencies/openssl_sources.bzl @@ -0,0 +1,1035 @@ +"""Pinned OpenSSL 3.5.6 WASI construction units. + +Reviewed from the canonical gcc no-asm/static/no-thread/no-socket/no-DSO +configuration. This file is inventory, never a foreign build scheduler. +""" + +OPENSSL_WASIX_C_SOURCES = [ + "crypto/aes/aes_cbc.c", + "crypto/aes/aes_cfb.c", + "crypto/aes/aes_core.c", + "crypto/aes/aes_ecb.c", + "crypto/aes/aes_ige.c", + "crypto/aes/aes_misc.c", + "crypto/aes/aes_ofb.c", + "crypto/aes/aes_wrap.c", + "crypto/aria/aria.c", + "crypto/asn1/a_bitstr.c", + "crypto/asn1/a_d2i_fp.c", + "crypto/asn1/a_digest.c", + "crypto/asn1/a_dup.c", + "crypto/asn1/a_gentm.c", + "crypto/asn1/a_i2d_fp.c", + "crypto/asn1/a_int.c", + "crypto/asn1/a_mbstr.c", + "crypto/asn1/a_object.c", + "crypto/asn1/a_octet.c", + "crypto/asn1/a_print.c", + "crypto/asn1/a_sign.c", + "crypto/asn1/a_strex.c", + "crypto/asn1/a_strnid.c", + "crypto/asn1/a_time.c", + "crypto/asn1/a_type.c", + "crypto/asn1/a_utctm.c", + "crypto/asn1/a_utf8.c", + "crypto/asn1/a_verify.c", + "crypto/asn1/ameth_lib.c", + "crypto/asn1/asn1_err.c", + "crypto/asn1/asn1_gen.c", + "crypto/asn1/asn1_item_list.c", + "crypto/asn1/asn1_lib.c", + "crypto/asn1/asn1_parse.c", + "crypto/asn1/asn_mime.c", + "crypto/asn1/asn_moid.c", + "crypto/asn1/asn_mstbl.c", + "crypto/asn1/asn_pack.c", + "crypto/asn1/bio_asn1.c", + "crypto/asn1/bio_ndef.c", + "crypto/asn1/d2i_param.c", + "crypto/asn1/d2i_pr.c", + "crypto/asn1/d2i_pu.c", + "crypto/asn1/evp_asn1.c", + "crypto/asn1/f_int.c", + "crypto/asn1/f_string.c", + "crypto/asn1/i2d_evp.c", + "crypto/asn1/n_pkey.c", + "crypto/asn1/nsseq.c", + "crypto/asn1/p5_pbe.c", + "crypto/asn1/p5_pbev2.c", + "crypto/asn1/p5_scrypt.c", + "crypto/asn1/p8_pkey.c", + "crypto/asn1/t_bitst.c", + "crypto/asn1/t_pkey.c", + "crypto/asn1/t_spki.c", + "crypto/asn1/tasn_dec.c", + "crypto/asn1/tasn_enc.c", + "crypto/asn1/tasn_fre.c", + "crypto/asn1/tasn_new.c", + "crypto/asn1/tasn_prn.c", + "crypto/asn1/tasn_scn.c", + "crypto/asn1/tasn_typ.c", + "crypto/asn1/tasn_utl.c", + "crypto/asn1/x_algor.c", + "crypto/asn1/x_bignum.c", + "crypto/asn1/x_info.c", + "crypto/asn1/x_int64.c", + "crypto/asn1/x_long.c", + "crypto/asn1/x_pkey.c", + "crypto/asn1/x_sig.c", + "crypto/asn1/x_spki.c", + "crypto/asn1/x_val.c", + "crypto/asn1_dsa.c", + "crypto/async/arch/async_null.c", + "crypto/async/arch/async_posix.c", + "crypto/async/arch/async_win.c", + "crypto/async/async.c", + "crypto/async/async_err.c", + "crypto/async/async_wait.c", + "crypto/bf/bf_cfb64.c", + "crypto/bf/bf_ecb.c", + "crypto/bf/bf_enc.c", + "crypto/bf/bf_ofb64.c", + "crypto/bf/bf_skey.c", + "crypto/bio/bf_buff.c", + "crypto/bio/bf_lbuf.c", + "crypto/bio/bf_nbio.c", + "crypto/bio/bf_null.c", + "crypto/bio/bf_prefix.c", + "crypto/bio/bf_readbuff.c", + "crypto/bio/bio_addr.c", + "crypto/bio/bio_cb.c", + "crypto/bio/bio_dump.c", + "crypto/bio/bio_err.c", + "crypto/bio/bio_lib.c", + "crypto/bio/bio_meth.c", + "crypto/bio/bio_print.c", + "crypto/bio/bio_sock.c", + "crypto/bio/bio_sock2.c", + "crypto/bio/bss_acpt.c", + "crypto/bio/bss_bio.c", + "crypto/bio/bss_conn.c", + "crypto/bio/bss_core.c", + "crypto/bio/bss_dgram.c", + "crypto/bio/bss_dgram_pair.c", + "crypto/bio/bss_fd.c", + "crypto/bio/bss_file.c", + "crypto/bio/bss_log.c", + "crypto/bio/bss_mem.c", + "crypto/bio/bss_null.c", + "crypto/bio/bss_sock.c", + "crypto/bio/ossl_core_bio.c", + "crypto/bn/bn_add.c", + "crypto/bn/bn_asm.c", + "crypto/bn/bn_blind.c", + "crypto/bn/bn_const.c", + "crypto/bn/bn_conv.c", + "crypto/bn/bn_ctx.c", + "crypto/bn/bn_depr.c", + "crypto/bn/bn_dh.c", + "crypto/bn/bn_div.c", + "crypto/bn/bn_err.c", + "crypto/bn/bn_exp.c", + "crypto/bn/bn_exp2.c", + "crypto/bn/bn_gcd.c", + "crypto/bn/bn_gf2m.c", + "crypto/bn/bn_intern.c", + "crypto/bn/bn_kron.c", + "crypto/bn/bn_lib.c", + "crypto/bn/bn_mod.c", + "crypto/bn/bn_mont.c", + "crypto/bn/bn_mpi.c", + "crypto/bn/bn_mul.c", + "crypto/bn/bn_nist.c", + "crypto/bn/bn_prime.c", + "crypto/bn/bn_print.c", + "crypto/bn/bn_rand.c", + "crypto/bn/bn_recp.c", + "crypto/bn/bn_rsa_fips186_4.c", + "crypto/bn/bn_shift.c", + "crypto/bn/bn_sqr.c", + "crypto/bn/bn_sqrt.c", + "crypto/bn/bn_srp.c", + "crypto/bn/bn_word.c", + "crypto/bn/bn_x931p.c", + "crypto/bsearch.c", + "crypto/buffer/buf_err.c", + "crypto/buffer/buffer.c", + "crypto/camellia/camellia.c", + "crypto/camellia/cmll_cbc.c", + "crypto/camellia/cmll_cfb.c", + "crypto/camellia/cmll_ctr.c", + "crypto/camellia/cmll_ecb.c", + "crypto/camellia/cmll_misc.c", + "crypto/camellia/cmll_ofb.c", + "crypto/cast/c_cfb64.c", + "crypto/cast/c_ecb.c", + "crypto/cast/c_enc.c", + "crypto/cast/c_ofb64.c", + "crypto/cast/c_skey.c", + "crypto/chacha/chacha_enc.c", + "crypto/cmac/cmac.c", + "crypto/cmp/cmp_asn.c", + "crypto/cmp/cmp_client.c", + "crypto/cmp/cmp_ctx.c", + "crypto/cmp/cmp_err.c", + "crypto/cmp/cmp_genm.c", + "crypto/cmp/cmp_hdr.c", + "crypto/cmp/cmp_http.c", + "crypto/cmp/cmp_msg.c", + "crypto/cmp/cmp_protect.c", + "crypto/cmp/cmp_server.c", + "crypto/cmp/cmp_status.c", + "crypto/cmp/cmp_util.c", + "crypto/cmp/cmp_vfy.c", + "crypto/cms/cms_asn1.c", + "crypto/cms/cms_att.c", + "crypto/cms/cms_cd.c", + "crypto/cms/cms_dd.c", + "crypto/cms/cms_dh.c", + "crypto/cms/cms_ec.c", + "crypto/cms/cms_enc.c", + "crypto/cms/cms_env.c", + "crypto/cms/cms_err.c", + "crypto/cms/cms_ess.c", + "crypto/cms/cms_io.c", + "crypto/cms/cms_kari.c", + "crypto/cms/cms_lib.c", + "crypto/cms/cms_pwri.c", + "crypto/cms/cms_rsa.c", + "crypto/cms/cms_sd.c", + "crypto/cms/cms_smime.c", + "crypto/comp/c_brotli.c", + "crypto/comp/c_zlib.c", + "crypto/comp/c_zstd.c", + "crypto/comp/comp_err.c", + "crypto/comp/comp_lib.c", + "crypto/comp_methods.c", + "crypto/conf/conf_api.c", + "crypto/conf/conf_def.c", + "crypto/conf/conf_err.c", + "crypto/conf/conf_lib.c", + "crypto/conf/conf_mall.c", + "crypto/conf/conf_mod.c", + "crypto/conf/conf_sap.c", + "crypto/conf/conf_ssl.c", + "crypto/context.c", + "crypto/core_algorithm.c", + "crypto/core_fetch.c", + "crypto/core_namemap.c", + "crypto/cpt_err.c", + "crypto/cpuid.c", + "crypto/crmf/crmf_asn.c", + "crypto/crmf/crmf_err.c", + "crypto/crmf/crmf_lib.c", + "crypto/crmf/crmf_pbm.c", + "crypto/cryptlib.c", + "crypto/ct/ct_b64.c", + "crypto/ct/ct_err.c", + "crypto/ct/ct_log.c", + "crypto/ct/ct_oct.c", + "crypto/ct/ct_policy.c", + "crypto/ct/ct_prn.c", + "crypto/ct/ct_sct.c", + "crypto/ct/ct_sct_ctx.c", + "crypto/ct/ct_vfy.c", + "crypto/ct/ct_x509v3.c", + "crypto/ctype.c", + "crypto/cversion.c", + "crypto/defaults.c", + "crypto/der_writer.c", + "crypto/des/cbc_cksm.c", + "crypto/des/cbc_enc.c", + "crypto/des/cfb64ede.c", + "crypto/des/cfb64enc.c", + "crypto/des/cfb_enc.c", + "crypto/des/des_enc.c", + "crypto/des/ecb3_enc.c", + "crypto/des/ecb_enc.c", + "crypto/des/fcrypt.c", + "crypto/des/fcrypt_b.c", + "crypto/des/ofb64ede.c", + "crypto/des/ofb64enc.c", + "crypto/des/ofb_enc.c", + "crypto/des/pcbc_enc.c", + "crypto/des/qud_cksm.c", + "crypto/des/rand_key.c", + "crypto/des/set_key.c", + "crypto/des/str2key.c", + "crypto/des/xcbc_enc.c", + "crypto/deterministic_nonce.c", + "crypto/dh/dh_ameth.c", + "crypto/dh/dh_asn1.c", + "crypto/dh/dh_backend.c", + "crypto/dh/dh_check.c", + "crypto/dh/dh_depr.c", + "crypto/dh/dh_err.c", + "crypto/dh/dh_gen.c", + "crypto/dh/dh_group_params.c", + "crypto/dh/dh_kdf.c", + "crypto/dh/dh_key.c", + "crypto/dh/dh_lib.c", + "crypto/dh/dh_meth.c", + "crypto/dh/dh_pmeth.c", + "crypto/dh/dh_prn.c", + "crypto/dh/dh_rfc5114.c", + "crypto/dsa/dsa_ameth.c", + "crypto/dsa/dsa_asn1.c", + "crypto/dsa/dsa_backend.c", + "crypto/dsa/dsa_check.c", + "crypto/dsa/dsa_depr.c", + "crypto/dsa/dsa_err.c", + "crypto/dsa/dsa_gen.c", + "crypto/dsa/dsa_key.c", + "crypto/dsa/dsa_lib.c", + "crypto/dsa/dsa_meth.c", + "crypto/dsa/dsa_ossl.c", + "crypto/dsa/dsa_pmeth.c", + "crypto/dsa/dsa_prn.c", + "crypto/dsa/dsa_sign.c", + "crypto/dsa/dsa_vrf.c", + "crypto/dso/dso_dl.c", + "crypto/dso/dso_dlfcn.c", + "crypto/dso/dso_err.c", + "crypto/dso/dso_lib.c", + "crypto/dso/dso_openssl.c", + "crypto/dso/dso_vms.c", + "crypto/dso/dso_win32.c", + "crypto/ebcdic.c", + "crypto/ec/curve25519.c", + "crypto/ec/curve448/arch_32/f_impl32.c", + "crypto/ec/curve448/arch_64/f_impl64.c", + "crypto/ec/curve448/curve448.c", + "crypto/ec/curve448/curve448_tables.c", + "crypto/ec/curve448/eddsa.c", + "crypto/ec/curve448/f_generic.c", + "crypto/ec/curve448/scalar.c", + "crypto/ec/ec2_oct.c", + "crypto/ec/ec2_smpl.c", + "crypto/ec/ec_ameth.c", + "crypto/ec/ec_asn1.c", + "crypto/ec/ec_backend.c", + "crypto/ec/ec_check.c", + "crypto/ec/ec_curve.c", + "crypto/ec/ec_cvt.c", + "crypto/ec/ec_deprecated.c", + "crypto/ec/ec_err.c", + "crypto/ec/ec_key.c", + "crypto/ec/ec_kmeth.c", + "crypto/ec/ec_lib.c", + "crypto/ec/ec_mult.c", + "crypto/ec/ec_oct.c", + "crypto/ec/ec_pmeth.c", + "crypto/ec/ec_print.c", + "crypto/ec/ecdh_kdf.c", + "crypto/ec/ecdh_ossl.c", + "crypto/ec/ecdsa_ossl.c", + "crypto/ec/ecdsa_sign.c", + "crypto/ec/ecdsa_vrf.c", + "crypto/ec/eck_prn.c", + "crypto/ec/ecp_mont.c", + "crypto/ec/ecp_nist.c", + "crypto/ec/ecp_oct.c", + "crypto/ec/ecp_smpl.c", + "crypto/ec/ecx_backend.c", + "crypto/ec/ecx_key.c", + "crypto/ec/ecx_meth.c", + "crypto/encode_decode/decoder_err.c", + "crypto/encode_decode/decoder_lib.c", + "crypto/encode_decode/decoder_meth.c", + "crypto/encode_decode/decoder_pkey.c", + "crypto/encode_decode/encoder_err.c", + "crypto/encode_decode/encoder_lib.c", + "crypto/encode_decode/encoder_meth.c", + "crypto/encode_decode/encoder_pkey.c", + "crypto/err/err.c", + "crypto/err/err_all.c", + "crypto/err/err_all_legacy.c", + "crypto/err/err_blocks.c", + "crypto/err/err_mark.c", + "crypto/err/err_prn.c", + "crypto/err/err_save.c", + "crypto/ess/ess_asn1.c", + "crypto/ess/ess_err.c", + "crypto/ess/ess_lib.c", + "crypto/evp/asymcipher.c", + "crypto/evp/bio_b64.c", + "crypto/evp/bio_enc.c", + "crypto/evp/bio_md.c", + "crypto/evp/bio_ok.c", + "crypto/evp/c_allc.c", + "crypto/evp/c_alld.c", + "crypto/evp/cmeth_lib.c", + "crypto/evp/ctrl_params_translate.c", + "crypto/evp/dh_ctrl.c", + "crypto/evp/dh_support.c", + "crypto/evp/digest.c", + "crypto/evp/dsa_ctrl.c", + "crypto/evp/e_aes.c", + "crypto/evp/e_aes_cbc_hmac_sha1.c", + "crypto/evp/e_aes_cbc_hmac_sha256.c", + "crypto/evp/e_aria.c", + "crypto/evp/e_bf.c", + "crypto/evp/e_camellia.c", + "crypto/evp/e_cast.c", + "crypto/evp/e_chacha20_poly1305.c", + "crypto/evp/e_des.c", + "crypto/evp/e_des3.c", + "crypto/evp/e_idea.c", + "crypto/evp/e_null.c", + "crypto/evp/e_old.c", + "crypto/evp/e_rc2.c", + "crypto/evp/e_rc4.c", + "crypto/evp/e_rc4_hmac_md5.c", + "crypto/evp/e_rc5.c", + "crypto/evp/e_seed.c", + "crypto/evp/e_sm4.c", + "crypto/evp/e_xcbc_d.c", + "crypto/evp/ec_ctrl.c", + "crypto/evp/ec_support.c", + "crypto/evp/encode.c", + "crypto/evp/evp_cnf.c", + "crypto/evp/evp_enc.c", + "crypto/evp/evp_err.c", + "crypto/evp/evp_fetch.c", + "crypto/evp/evp_key.c", + "crypto/evp/evp_lib.c", + "crypto/evp/evp_pbe.c", + "crypto/evp/evp_pkey.c", + "crypto/evp/evp_rand.c", + "crypto/evp/evp_utils.c", + "crypto/evp/exchange.c", + "crypto/evp/kdf_lib.c", + "crypto/evp/kdf_meth.c", + "crypto/evp/kem.c", + "crypto/evp/keymgmt_lib.c", + "crypto/evp/keymgmt_meth.c", + "crypto/evp/legacy_blake2.c", + "crypto/evp/legacy_md4.c", + "crypto/evp/legacy_md5.c", + "crypto/evp/legacy_md5_sha1.c", + "crypto/evp/legacy_mdc2.c", + "crypto/evp/legacy_ripemd.c", + "crypto/evp/legacy_sha.c", + "crypto/evp/legacy_wp.c", + "crypto/evp/m_null.c", + "crypto/evp/m_sigver.c", + "crypto/evp/mac_lib.c", + "crypto/evp/mac_meth.c", + "crypto/evp/names.c", + "crypto/evp/p5_crpt.c", + "crypto/evp/p5_crpt2.c", + "crypto/evp/p_dec.c", + "crypto/evp/p_enc.c", + "crypto/evp/p_legacy.c", + "crypto/evp/p_lib.c", + "crypto/evp/p_open.c", + "crypto/evp/p_seal.c", + "crypto/evp/p_sign.c", + "crypto/evp/p_verify.c", + "crypto/evp/pbe_scrypt.c", + "crypto/evp/pmeth_check.c", + "crypto/evp/pmeth_gn.c", + "crypto/evp/pmeth_lib.c", + "crypto/evp/s_lib.c", + "crypto/evp/signature.c", + "crypto/evp/skeymgmt_meth.c", + "crypto/ex_data.c", + "crypto/ffc/ffc_backend.c", + "crypto/ffc/ffc_dh.c", + "crypto/ffc/ffc_key_generate.c", + "crypto/ffc/ffc_key_validate.c", + "crypto/ffc/ffc_params.c", + "crypto/ffc/ffc_params_generate.c", + "crypto/ffc/ffc_params_validate.c", + "crypto/getenv.c", + "crypto/hashtable/hashfunc.c", + "crypto/hashtable/hashtable.c", + "crypto/hmac/hmac.c", + "crypto/hpke/hpke.c", + "crypto/hpke/hpke_util.c", + "crypto/http/http_client.c", + "crypto/http/http_err.c", + "crypto/http/http_lib.c", + "crypto/idea/i_cbc.c", + "crypto/idea/i_cfb64.c", + "crypto/idea/i_ecb.c", + "crypto/idea/i_ofb64.c", + "crypto/idea/i_skey.c", + "crypto/indicator_core.c", + "crypto/info.c", + "crypto/init.c", + "crypto/initthread.c", + "crypto/kdf/kdf_err.c", + "crypto/lhash/lh_stats.c", + "crypto/lhash/lhash.c", + "crypto/md4/md4_dgst.c", + "crypto/md4/md4_one.c", + "crypto/md5/md5_dgst.c", + "crypto/md5/md5_one.c", + "crypto/md5/md5_sha1.c", + "crypto/mdc2/mdc2_one.c", + "crypto/mdc2/mdc2dgst.c", + "crypto/mem.c", + "crypto/mem_clr.c", + "crypto/mem_sec.c", + "crypto/ml_dsa/ml_dsa_encoders.c", + "crypto/ml_dsa/ml_dsa_key.c", + "crypto/ml_dsa/ml_dsa_key_compress.c", + "crypto/ml_dsa/ml_dsa_matrix.c", + "crypto/ml_dsa/ml_dsa_ntt.c", + "crypto/ml_dsa/ml_dsa_params.c", + "crypto/ml_dsa/ml_dsa_sample.c", + "crypto/ml_dsa/ml_dsa_sign.c", + "crypto/ml_kem/ml_kem.c", + "crypto/modes/cbc128.c", + "crypto/modes/ccm128.c", + "crypto/modes/cfb128.c", + "crypto/modes/ctr128.c", + "crypto/modes/cts128.c", + "crypto/modes/gcm128.c", + "crypto/modes/ocb128.c", + "crypto/modes/ofb128.c", + "crypto/modes/siv128.c", + "crypto/modes/wrap128.c", + "crypto/modes/xts128.c", + "crypto/modes/xts128gb.c", + "crypto/o_dir.c", + "crypto/o_fopen.c", + "crypto/o_init.c", + "crypto/o_str.c", + "crypto/o_time.c", + "crypto/objects/o_names.c", + "crypto/objects/obj_dat.c", + "crypto/objects/obj_err.c", + "crypto/objects/obj_lib.c", + "crypto/objects/obj_xref.c", + "crypto/ocsp/ocsp_asn.c", + "crypto/ocsp/ocsp_cl.c", + "crypto/ocsp/ocsp_err.c", + "crypto/ocsp/ocsp_ext.c", + "crypto/ocsp/ocsp_http.c", + "crypto/ocsp/ocsp_lib.c", + "crypto/ocsp/ocsp_prn.c", + "crypto/ocsp/ocsp_srv.c", + "crypto/ocsp/ocsp_vfy.c", + "crypto/ocsp/v3_ocsp.c", + "crypto/packet.c", + "crypto/param_build.c", + "crypto/param_build_set.c", + "crypto/params.c", + "crypto/params_dup.c", + "crypto/params_from_text.c", + "crypto/passphrase.c", + "crypto/pem/pem_all.c", + "crypto/pem/pem_err.c", + "crypto/pem/pem_info.c", + "crypto/pem/pem_lib.c", + "crypto/pem/pem_oth.c", + "crypto/pem/pem_pk8.c", + "crypto/pem/pem_pkey.c", + "crypto/pem/pem_sign.c", + "crypto/pem/pem_x509.c", + "crypto/pem/pem_xaux.c", + "crypto/pem/pvkfmt.c", + "crypto/pkcs12/p12_add.c", + "crypto/pkcs12/p12_asn.c", + "crypto/pkcs12/p12_attr.c", + "crypto/pkcs12/p12_crpt.c", + "crypto/pkcs12/p12_crt.c", + "crypto/pkcs12/p12_decr.c", + "crypto/pkcs12/p12_init.c", + "crypto/pkcs12/p12_key.c", + "crypto/pkcs12/p12_kiss.c", + "crypto/pkcs12/p12_mutl.c", + "crypto/pkcs12/p12_npas.c", + "crypto/pkcs12/p12_p8d.c", + "crypto/pkcs12/p12_p8e.c", + "crypto/pkcs12/p12_sbag.c", + "crypto/pkcs12/p12_utl.c", + "crypto/pkcs12/pk12err.c", + "crypto/pkcs7/bio_pk7.c", + "crypto/pkcs7/pk7_asn1.c", + "crypto/pkcs7/pk7_attr.c", + "crypto/pkcs7/pk7_doit.c", + "crypto/pkcs7/pk7_lib.c", + "crypto/pkcs7/pk7_mime.c", + "crypto/pkcs7/pk7_smime.c", + "crypto/pkcs7/pkcs7err.c", + "crypto/poly1305/poly1305.c", + "crypto/property/defn_cache.c", + "crypto/property/property.c", + "crypto/property/property_err.c", + "crypto/property/property_parse.c", + "crypto/property/property_query.c", + "crypto/property/property_string.c", + "crypto/provider.c", + "crypto/provider_child.c", + "crypto/provider_conf.c", + "crypto/provider_core.c", + "crypto/provider_predefined.c", + "crypto/punycode.c", + "crypto/quic_vlint.c", + "crypto/rand/prov_seed.c", + "crypto/rand/rand_deprecated.c", + "crypto/rand/rand_err.c", + "crypto/rand/rand_lib.c", + "crypto/rand/rand_meth.c", + "crypto/rand/rand_pool.c", + "crypto/rand/rand_uniform.c", + "crypto/rand/randfile.c", + "crypto/rc2/rc2_cbc.c", + "crypto/rc2/rc2_ecb.c", + "crypto/rc2/rc2_skey.c", + "crypto/rc2/rc2cfb64.c", + "crypto/rc2/rc2ofb64.c", + "crypto/rc4/rc4_enc.c", + "crypto/rc4/rc4_skey.c", + "crypto/ripemd/rmd_dgst.c", + "crypto/ripemd/rmd_one.c", + "crypto/rsa/rsa_ameth.c", + "crypto/rsa/rsa_asn1.c", + "crypto/rsa/rsa_backend.c", + "crypto/rsa/rsa_chk.c", + "crypto/rsa/rsa_crpt.c", + "crypto/rsa/rsa_depr.c", + "crypto/rsa/rsa_err.c", + "crypto/rsa/rsa_gen.c", + "crypto/rsa/rsa_lib.c", + "crypto/rsa/rsa_meth.c", + "crypto/rsa/rsa_mp.c", + "crypto/rsa/rsa_mp_names.c", + "crypto/rsa/rsa_none.c", + "crypto/rsa/rsa_oaep.c", + "crypto/rsa/rsa_ossl.c", + "crypto/rsa/rsa_pk1.c", + "crypto/rsa/rsa_pmeth.c", + "crypto/rsa/rsa_prn.c", + "crypto/rsa/rsa_pss.c", + "crypto/rsa/rsa_saos.c", + "crypto/rsa/rsa_schemes.c", + "crypto/rsa/rsa_sign.c", + "crypto/rsa/rsa_sp800_56b_check.c", + "crypto/rsa/rsa_sp800_56b_gen.c", + "crypto/rsa/rsa_x931.c", + "crypto/rsa/rsa_x931g.c", + "crypto/seed/seed.c", + "crypto/seed/seed_cbc.c", + "crypto/seed/seed_cfb.c", + "crypto/seed/seed_ecb.c", + "crypto/seed/seed_ofb.c", + "crypto/self_test_core.c", + "crypto/sha/keccak1600.c", + "crypto/sha/sha1_one.c", + "crypto/sha/sha1dgst.c", + "crypto/sha/sha256.c", + "crypto/sha/sha3.c", + "crypto/sha/sha512.c", + "crypto/siphash/siphash.c", + "crypto/sleep.c", + "crypto/slh_dsa/slh_adrs.c", + "crypto/slh_dsa/slh_dsa.c", + "crypto/slh_dsa/slh_dsa_hash_ctx.c", + "crypto/slh_dsa/slh_dsa_key.c", + "crypto/slh_dsa/slh_fors.c", + "crypto/slh_dsa/slh_hash.c", + "crypto/slh_dsa/slh_hypertree.c", + "crypto/slh_dsa/slh_params.c", + "crypto/slh_dsa/slh_wots.c", + "crypto/slh_dsa/slh_xmss.c", + "crypto/sm2/sm2_crypt.c", + "crypto/sm2/sm2_err.c", + "crypto/sm2/sm2_key.c", + "crypto/sm2/sm2_sign.c", + "crypto/sm3/legacy_sm3.c", + "crypto/sm3/sm3.c", + "crypto/sm4/sm4.c", + "crypto/sparse_array.c", + "crypto/srp/srp_lib.c", + "crypto/srp/srp_vfy.c", + "crypto/ssl_err.c", + "crypto/stack/stack.c", + "crypto/store/store_err.c", + "crypto/store/store_init.c", + "crypto/store/store_lib.c", + "crypto/store/store_meth.c", + "crypto/store/store_register.c", + "crypto/store/store_result.c", + "crypto/store/store_strings.c", + "crypto/thread/api.c", + "crypto/thread/arch/thread_win.c", + "crypto/threads_lib.c", + "crypto/threads_none.c", + "crypto/threads_pthread.c", + "crypto/threads_win.c", + "crypto/time.c", + "crypto/trace.c", + "crypto/ts/ts_asn1.c", + "crypto/ts/ts_conf.c", + "crypto/ts/ts_err.c", + "crypto/ts/ts_lib.c", + "crypto/ts/ts_req_print.c", + "crypto/ts/ts_req_utils.c", + "crypto/ts/ts_rsp_print.c", + "crypto/ts/ts_rsp_sign.c", + "crypto/ts/ts_rsp_utils.c", + "crypto/ts/ts_rsp_verify.c", + "crypto/ts/ts_verify_ctx.c", + "crypto/txt_db/txt_db.c", + "crypto/ui/ui_err.c", + "crypto/ui/ui_lib.c", + "crypto/ui/ui_null.c", + "crypto/ui/ui_openssl.c", + "crypto/ui/ui_util.c", + "crypto/uid.c", + "crypto/whrlpool/wp_block.c", + "crypto/whrlpool/wp_dgst.c", + "crypto/x509/by_dir.c", + "crypto/x509/by_file.c", + "crypto/x509/by_store.c", + "crypto/x509/pcy_cache.c", + "crypto/x509/pcy_data.c", + "crypto/x509/pcy_lib.c", + "crypto/x509/pcy_map.c", + "crypto/x509/pcy_node.c", + "crypto/x509/pcy_tree.c", + "crypto/x509/t_acert.c", + "crypto/x509/t_crl.c", + "crypto/x509/t_req.c", + "crypto/x509/t_x509.c", + "crypto/x509/v3_aaa.c", + "crypto/x509/v3_ac_tgt.c", + "crypto/x509/v3_addr.c", + "crypto/x509/v3_admis.c", + "crypto/x509/v3_akeya.c", + "crypto/x509/v3_akid.c", + "crypto/x509/v3_asid.c", + "crypto/x509/v3_attrdesc.c", + "crypto/x509/v3_attrmap.c", + "crypto/x509/v3_audit_id.c", + "crypto/x509/v3_authattid.c", + "crypto/x509/v3_battcons.c", + "crypto/x509/v3_bcons.c", + "crypto/x509/v3_bitst.c", + "crypto/x509/v3_conf.c", + "crypto/x509/v3_cpols.c", + "crypto/x509/v3_crld.c", + "crypto/x509/v3_enum.c", + "crypto/x509/v3_extku.c", + "crypto/x509/v3_genn.c", + "crypto/x509/v3_group_ac.c", + "crypto/x509/v3_ia5.c", + "crypto/x509/v3_ind_iss.c", + "crypto/x509/v3_info.c", + "crypto/x509/v3_int.c", + "crypto/x509/v3_iobo.c", + "crypto/x509/v3_ist.c", + "crypto/x509/v3_lib.c", + "crypto/x509/v3_ncons.c", + "crypto/x509/v3_no_ass.c", + "crypto/x509/v3_no_rev_avail.c", + "crypto/x509/v3_pci.c", + "crypto/x509/v3_pcia.c", + "crypto/x509/v3_pcons.c", + "crypto/x509/v3_pku.c", + "crypto/x509/v3_pmaps.c", + "crypto/x509/v3_prn.c", + "crypto/x509/v3_purp.c", + "crypto/x509/v3_rolespec.c", + "crypto/x509/v3_san.c", + "crypto/x509/v3_sda.c", + "crypto/x509/v3_single_use.c", + "crypto/x509/v3_skid.c", + "crypto/x509/v3_soa_id.c", + "crypto/x509/v3_sxnet.c", + "crypto/x509/v3_timespec.c", + "crypto/x509/v3_tlsf.c", + "crypto/x509/v3_usernotice.c", + "crypto/x509/v3_utf8.c", + "crypto/x509/v3_utl.c", + "crypto/x509/v3err.c", + "crypto/x509/x509_acert.c", + "crypto/x509/x509_att.c", + "crypto/x509/x509_cmp.c", + "crypto/x509/x509_d2.c", + "crypto/x509/x509_def.c", + "crypto/x509/x509_err.c", + "crypto/x509/x509_ext.c", + "crypto/x509/x509_lu.c", + "crypto/x509/x509_meth.c", + "crypto/x509/x509_obj.c", + "crypto/x509/x509_r2x.c", + "crypto/x509/x509_req.c", + "crypto/x509/x509_set.c", + "crypto/x509/x509_trust.c", + "crypto/x509/x509_txt.c", + "crypto/x509/x509_v3.c", + "crypto/x509/x509_vfy.c", + "crypto/x509/x509_vpm.c", + "crypto/x509/x509aset.c", + "crypto/x509/x509cset.c", + "crypto/x509/x509name.c", + "crypto/x509/x509rset.c", + "crypto/x509/x509spki.c", + "crypto/x509/x509type.c", + "crypto/x509/x_all.c", + "crypto/x509/x_attrib.c", + "crypto/x509/x_crl.c", + "crypto/x509/x_exten.c", + "crypto/x509/x_ietfatt.c", + "crypto/x509/x_name.c", + "crypto/x509/x_pubkey.c", + "crypto/x509/x_req.c", + "crypto/x509/x_x509.c", + "crypto/x509/x_x509a.c", + "providers/baseprov.c", + "providers/common/bio_prov.c", + "providers/common/capabilities.c", + "providers/common/der/der_dsa_key.c", + "providers/common/der/der_dsa_sig.c", + "providers/common/der/der_ec_key.c", + "providers/common/der/der_ec_sig.c", + "providers/common/der/der_ecx_key.c", + "providers/common/der/der_ml_dsa_key.c", + "providers/common/der/der_rsa_key.c", + "providers/common/der/der_rsa_sig.c", + "providers/common/der/der_slh_dsa_key.c", + "providers/common/der/der_sm2_key.c", + "providers/common/der/der_sm2_sig.c", + "providers/common/digest_to_nid.c", + "providers/common/provider_ctx.c", + "providers/common/provider_err.c", + "providers/common/provider_seeding.c", + "providers/common/provider_util.c", + "providers/common/securitycheck.c", + "providers/common/securitycheck_default.c", + "providers/defltprov.c", + "providers/implementations/asymciphers/rsa_enc.c", + "providers/implementations/asymciphers/sm2_enc.c", + "providers/implementations/ciphers/cipher_aes.c", + "providers/implementations/ciphers/cipher_aes_cbc_hmac_sha.c", + "providers/implementations/ciphers/cipher_aes_cbc_hmac_sha1_hw.c", + "providers/implementations/ciphers/cipher_aes_cbc_hmac_sha256_hw.c", + "providers/implementations/ciphers/cipher_aes_ccm.c", + "providers/implementations/ciphers/cipher_aes_ccm_hw.c", + "providers/implementations/ciphers/cipher_aes_gcm.c", + "providers/implementations/ciphers/cipher_aes_gcm_hw.c", + "providers/implementations/ciphers/cipher_aes_gcm_siv.c", + "providers/implementations/ciphers/cipher_aes_gcm_siv_hw.c", + "providers/implementations/ciphers/cipher_aes_gcm_siv_polyval.c", + "providers/implementations/ciphers/cipher_aes_hw.c", + "providers/implementations/ciphers/cipher_aes_ocb.c", + "providers/implementations/ciphers/cipher_aes_ocb_hw.c", + "providers/implementations/ciphers/cipher_aes_siv.c", + "providers/implementations/ciphers/cipher_aes_siv_hw.c", + "providers/implementations/ciphers/cipher_aes_wrp.c", + "providers/implementations/ciphers/cipher_aes_xts.c", + "providers/implementations/ciphers/cipher_aes_xts_fips.c", + "providers/implementations/ciphers/cipher_aes_xts_hw.c", + "providers/implementations/ciphers/cipher_aria.c", + "providers/implementations/ciphers/cipher_aria_ccm.c", + "providers/implementations/ciphers/cipher_aria_ccm_hw.c", + "providers/implementations/ciphers/cipher_aria_gcm.c", + "providers/implementations/ciphers/cipher_aria_gcm_hw.c", + "providers/implementations/ciphers/cipher_aria_hw.c", + "providers/implementations/ciphers/cipher_blowfish.c", + "providers/implementations/ciphers/cipher_blowfish_hw.c", + "providers/implementations/ciphers/cipher_camellia.c", + "providers/implementations/ciphers/cipher_camellia_hw.c", + "providers/implementations/ciphers/cipher_cast5.c", + "providers/implementations/ciphers/cipher_cast5_hw.c", + "providers/implementations/ciphers/cipher_chacha20.c", + "providers/implementations/ciphers/cipher_chacha20_hw.c", + "providers/implementations/ciphers/cipher_chacha20_poly1305.c", + "providers/implementations/ciphers/cipher_chacha20_poly1305_hw.c", + "providers/implementations/ciphers/cipher_cts.c", + "providers/implementations/ciphers/cipher_des.c", + "providers/implementations/ciphers/cipher_des_hw.c", + "providers/implementations/ciphers/cipher_desx.c", + "providers/implementations/ciphers/cipher_desx_hw.c", + "providers/implementations/ciphers/cipher_idea.c", + "providers/implementations/ciphers/cipher_idea_hw.c", + "providers/implementations/ciphers/cipher_null.c", + "providers/implementations/ciphers/cipher_rc2.c", + "providers/implementations/ciphers/cipher_rc2_hw.c", + "providers/implementations/ciphers/cipher_rc4.c", + "providers/implementations/ciphers/cipher_rc4_hmac_md5.c", + "providers/implementations/ciphers/cipher_rc4_hmac_md5_hw.c", + "providers/implementations/ciphers/cipher_rc4_hw.c", + "providers/implementations/ciphers/cipher_seed.c", + "providers/implementations/ciphers/cipher_seed_hw.c", + "providers/implementations/ciphers/cipher_sm4.c", + "providers/implementations/ciphers/cipher_sm4_ccm.c", + "providers/implementations/ciphers/cipher_sm4_ccm_hw.c", + "providers/implementations/ciphers/cipher_sm4_gcm.c", + "providers/implementations/ciphers/cipher_sm4_gcm_hw.c", + "providers/implementations/ciphers/cipher_sm4_hw.c", + "providers/implementations/ciphers/cipher_sm4_xts.c", + "providers/implementations/ciphers/cipher_sm4_xts_hw.c", + "providers/implementations/ciphers/cipher_tdes.c", + "providers/implementations/ciphers/cipher_tdes_common.c", + "providers/implementations/ciphers/cipher_tdes_default.c", + "providers/implementations/ciphers/cipher_tdes_default_hw.c", + "providers/implementations/ciphers/cipher_tdes_hw.c", + "providers/implementations/ciphers/cipher_tdes_wrap.c", + "providers/implementations/ciphers/cipher_tdes_wrap_hw.c", + "providers/implementations/ciphers/ciphercommon.c", + "providers/implementations/ciphers/ciphercommon_block.c", + "providers/implementations/ciphers/ciphercommon_ccm.c", + "providers/implementations/ciphers/ciphercommon_ccm_hw.c", + "providers/implementations/ciphers/ciphercommon_gcm.c", + "providers/implementations/ciphers/ciphercommon_gcm_hw.c", + "providers/implementations/ciphers/ciphercommon_hw.c", + "providers/implementations/digests/blake2_prov.c", + "providers/implementations/digests/blake2b_prov.c", + "providers/implementations/digests/blake2s_prov.c", + "providers/implementations/digests/digestcommon.c", + "providers/implementations/digests/md4_prov.c", + "providers/implementations/digests/md5_prov.c", + "providers/implementations/digests/md5_sha1_prov.c", + "providers/implementations/digests/mdc2_prov.c", + "providers/implementations/digests/null_prov.c", + "providers/implementations/digests/ripemd_prov.c", + "providers/implementations/digests/sha2_prov.c", + "providers/implementations/digests/sha3_prov.c", + "providers/implementations/digests/sm3_prov.c", + "providers/implementations/digests/wp_prov.c", + "providers/implementations/encode_decode/decode_der2key.c", + "providers/implementations/encode_decode/decode_epki2pki.c", + "providers/implementations/encode_decode/decode_msblob2key.c", + "providers/implementations/encode_decode/decode_pem2der.c", + "providers/implementations/encode_decode/decode_pvk2key.c", + "providers/implementations/encode_decode/decode_spki2typespki.c", + "providers/implementations/encode_decode/encode_key2any.c", + "providers/implementations/encode_decode/encode_key2blob.c", + "providers/implementations/encode_decode/encode_key2ms.c", + "providers/implementations/encode_decode/encode_key2text.c", + "providers/implementations/encode_decode/endecoder_common.c", + "providers/implementations/encode_decode/ml_common_codecs.c", + "providers/implementations/encode_decode/ml_dsa_codecs.c", + "providers/implementations/encode_decode/ml_kem_codecs.c", + "providers/implementations/exchange/dh_exch.c", + "providers/implementations/exchange/ecdh_exch.c", + "providers/implementations/exchange/ecx_exch.c", + "providers/implementations/exchange/kdf_exch.c", + "providers/implementations/kdfs/argon2.c", + "providers/implementations/kdfs/hkdf.c", + "providers/implementations/kdfs/hmacdrbg_kdf.c", + "providers/implementations/kdfs/kbkdf.c", + "providers/implementations/kdfs/krb5kdf.c", + "providers/implementations/kdfs/pbkdf1.c", + "providers/implementations/kdfs/pbkdf2.c", + "providers/implementations/kdfs/pbkdf2_fips.c", + "providers/implementations/kdfs/pkcs12kdf.c", + "providers/implementations/kdfs/pvkkdf.c", + "providers/implementations/kdfs/scrypt.c", + "providers/implementations/kdfs/sshkdf.c", + "providers/implementations/kdfs/sskdf.c", + "providers/implementations/kdfs/tls1_prf.c", + "providers/implementations/kdfs/x942kdf.c", + "providers/implementations/kem/ec_kem.c", + "providers/implementations/kem/ecx_kem.c", + "providers/implementations/kem/kem_util.c", + "providers/implementations/kem/ml_kem_kem.c", + "providers/implementations/kem/mlx_kem.c", + "providers/implementations/kem/rsa_kem.c", + "providers/implementations/keymgmt/dh_kmgmt.c", + "providers/implementations/keymgmt/dsa_kmgmt.c", + "providers/implementations/keymgmt/ec_kmgmt.c", + "providers/implementations/keymgmt/ecx_kmgmt.c", + "providers/implementations/keymgmt/kdf_legacy_kmgmt.c", + "providers/implementations/keymgmt/mac_legacy_kmgmt.c", + "providers/implementations/keymgmt/ml_dsa_kmgmt.c", + "providers/implementations/keymgmt/ml_kem_kmgmt.c", + "providers/implementations/keymgmt/mlx_kmgmt.c", + "providers/implementations/keymgmt/rsa_kmgmt.c", + "providers/implementations/keymgmt/slh_dsa_kmgmt.c", + "providers/implementations/macs/blake2b_mac.c", + "providers/implementations/macs/blake2s_mac.c", + "providers/implementations/macs/cmac_prov.c", + "providers/implementations/macs/gmac_prov.c", + "providers/implementations/macs/hmac_prov.c", + "providers/implementations/macs/kmac_prov.c", + "providers/implementations/macs/poly1305_prov.c", + "providers/implementations/macs/siphash_prov.c", + "providers/implementations/rands/drbg.c", + "providers/implementations/rands/drbg_ctr.c", + "providers/implementations/rands/drbg_hash.c", + "providers/implementations/rands/drbg_hmac.c", + "providers/implementations/rands/seed_src.c", + "providers/implementations/rands/seed_src_jitter.c", + "providers/implementations/rands/seeding/rand_cpu_x86.c", + "providers/implementations/rands/seeding/rand_tsc.c", + "providers/implementations/rands/seeding/rand_unix.c", + "providers/implementations/rands/seeding/rand_win.c", + "providers/implementations/rands/test_rng.c", + "providers/implementations/signature/dsa_sig.c", + "providers/implementations/signature/ecdsa_sig.c", + "providers/implementations/signature/eddsa_sig.c", + "providers/implementations/signature/mac_legacy_sig.c", + "providers/implementations/signature/ml_dsa_sig.c", + "providers/implementations/signature/rsa_sig.c", + "providers/implementations/signature/slh_dsa_sig.c", + "providers/implementations/signature/sm2_sig.c", + "providers/implementations/skeymgmt/aes_skmgmt.c", + "providers/implementations/skeymgmt/generic.c", + "providers/implementations/storemgmt/file_store.c", + "providers/implementations/storemgmt/file_store_any2obj.c", + "providers/legacyprov.c", + "providers/nullprov.c", + "providers/prov_running.c", + "ssl/record/methods/ssl3_cbc.c", + "ssl/record/methods/tls_pad.c" +] + +OPENSSL_WASIX_TEMPLATES = { + "crypto/params_idx.c.in": "crypto/params_idx.c", + "include/crypto/bn_conf.h.in": "include/crypto/bn_conf.h", + "include/crypto/dso_conf.h.in": "include/crypto/dso_conf.h", + "include/internal/param_names.h.in": "include/internal/param_names.h", + "include/openssl/asn1.h.in": "include/openssl/asn1.h", + "include/openssl/asn1t.h.in": "include/openssl/asn1t.h", + "include/openssl/bio.h.in": "include/openssl/bio.h", + "include/openssl/cmp.h.in": "include/openssl/cmp.h", + "include/openssl/cms.h.in": "include/openssl/cms.h", + "include/openssl/comp.h.in": "include/openssl/comp.h", + "include/openssl/conf.h.in": "include/openssl/conf.h", + "include/openssl/configuration.h.in": "include/openssl/configuration.h", + "include/openssl/core_names.h.in": "include/openssl/core_names.h", + "include/openssl/crmf.h.in": "include/openssl/crmf.h", + "include/openssl/crypto.h.in": "include/openssl/crypto.h", + "include/openssl/ct.h.in": "include/openssl/ct.h", + "include/openssl/err.h.in": "include/openssl/err.h", + "include/openssl/ess.h.in": "include/openssl/ess.h", + "include/openssl/fipskey.h.in": "include/openssl/fipskey.h", + "include/openssl/lhash.h.in": "include/openssl/lhash.h", + "include/openssl/ocsp.h.in": "include/openssl/ocsp.h", + "include/openssl/opensslv.h.in": "include/openssl/opensslv.h", + "include/openssl/pkcs12.h.in": "include/openssl/pkcs12.h", + "include/openssl/pkcs7.h.in": "include/openssl/pkcs7.h", + "include/openssl/safestack.h.in": "include/openssl/safestack.h", + "include/openssl/srp.h.in": "include/openssl/srp.h", + "include/openssl/ssl.h.in": "include/openssl/ssl.h", + "include/openssl/ui.h.in": "include/openssl/ui.h", + "include/openssl/x509.h.in": "include/openssl/x509.h", + "include/openssl/x509_acert.h.in": "include/openssl/x509_acert.h", + "include/openssl/x509_vfy.h.in": "include/openssl/x509_vfy.h", + "include/openssl/x509v3.h.in": "include/openssl/x509v3.h", + "providers/common/der/der_digests_gen.c.in": "providers/common/der/der_digests_gen.c", + "providers/common/der/der_dsa_gen.c.in": "providers/common/der/der_dsa_gen.c", + "providers/common/der/der_ec_gen.c.in": "providers/common/der/der_ec_gen.c", + "providers/common/der/der_ecx_gen.c.in": "providers/common/der/der_ecx_gen.c", + "providers/common/der/der_ml_dsa_gen.c.in": "providers/common/der/der_ml_dsa_gen.c", + "providers/common/der/der_rsa_gen.c.in": "providers/common/der/der_rsa_gen.c", + "providers/common/der/der_slh_dsa_gen.c.in": "providers/common/der/der_slh_dsa_gen.c", + "providers/common/der/der_sm2_gen.c.in": "providers/common/der/der_sm2_gen.c", + "providers/common/der/der_wrap_gen.c.in": "providers/common/der/der_wrap_gen.c", + "providers/common/include/prov/der_digests.h.in": "providers/common/include/prov/der_digests.h", + "providers/common/include/prov/der_dsa.h.in": "providers/common/include/prov/der_dsa.h", + "providers/common/include/prov/der_ec.h.in": "providers/common/include/prov/der_ec.h", + "providers/common/include/prov/der_ecx.h.in": "providers/common/include/prov/der_ecx.h", + "providers/common/include/prov/der_ml_dsa.h.in": "providers/common/include/prov/der_ml_dsa.h", + "providers/common/include/prov/der_rsa.h.in": "providers/common/include/prov/der_rsa.h", + "providers/common/include/prov/der_slh_dsa.h.in": "providers/common/include/prov/der_slh_dsa.h", + "providers/common/include/prov/der_sm2.h.in": "providers/common/include/prov/der_sm2.h", + "providers/common/include/prov/der_wrap.h.in": "providers/common/include/prov/der_wrap.h" +} diff --git a/build_defs/wasix/dependencies/postgis.bzl b/build_defs/wasix/dependencies/postgis.bzl new file mode 100644 index 000000000..788961282 --- /dev/null +++ b/build_defs/wasix/dependencies/postgis.bzl @@ -0,0 +1,97 @@ +"""Direct WASI PostGIS dependency compilation with real LP32 configuration.""" + +load("@rules_cc//cc:defs.bzl", "cc_library") +load("@oliphaunt_metadata//:metadata.bzl", "EXTENSION_DEPENDENCIES") +load("//build_defs/extensions/postgis:libraries.bzl", "postgis_source_headers") +load("//build_defs/extensions/postgis:sqlite.bzl", "SQLITE_CORE_SOURCES", "SQLITE_FTS3_SOURCES", "sqlite_generate") +load(":headers.bzl", "wasix_dependency_headers") +load(":proj_resources.bzl", "wasix_proj_database", "wasix_proj_embed") + +WASIX_DEPENDENCY_COMPATIBLE = ["@platforms//cpu:wasm32", "@platforms//os:wasi"] +# The maintained WASIX recipe emits conventional O2 objects for the aggregate +# geospatial side module; its complete C++ archive closure must not use ThinLTO. +_C = ["-std=gnu11", "-O2", "-g0", "-fPIC", "-fvisibility=hidden"] +_CXX = ["-std=c++17", "-O2", "-g0", "-fPIC", "-fvisibility=hidden", "-fvisibility-inlines-hidden"] +_JSON_C = "arraylist debug json_c_version json_object json_object_iterator json_tokener json_util json_visit linkhash printbuf random_seed strerror_override json_pointer json_patch".split(" ") +_XML = "HTMLparser HTMLtree SAX2 buf c14n catalog chvalid debugXML dict encoding entities error globals hash list nanohttp parser parserInternals pattern relaxng schematron threads tree uri valid xinclude xlink xmlIO xmlmemory xmlmodule xmlreader xmlregexp xmlsave xmlschemas xmlschemastypes xmlstring xmlunicode xmlwriter xpath xpointer xzlib".split(" ") + +def _pin(name, commit): + if EXTENSION_DEPENDENCIES["postgis"][name]["commit"] != commit: + fail("review the WASI %s source/configuration recipe before updating its canonical pin" % name) + +def wasix_postgis_sqlite(name): + _pin("sqlite", "ccd445d76a9362c63add000354fac84ba9022176") + prefix = "@postgis_sqlite//:" + generated = name + "_generated" + sqlite_generate( + name = generated, + inputs = [prefix + "all_sources"], + version = prefix + "VERSION", + jim = "//build_defs/extensions/postgis:sqlite_jim", + lemon = "//build_defs/extensions/postgis:sqlite_lemon", + mksourceid = "//build_defs/extensions/postgis:sqlite_mksourceid", + mkkeywordhash = "//build_defs/extensions/postgis:sqlite_mkkeywordhash", + ) + native.filegroup(name = name + "_generated_sources", srcs = [":" + generated], output_group = "library_sources") + postgis_source_headers(name = name + "_headers", root = prefix + "VERSION", headers = [prefix + "headers", prefix + "ext/rtree/geopoly.c"], include_dirs = ["src", "ext/rtree", "ext/icu", "ext/fts3", "ext/session"]) + cc_library( + name = name, + srcs = [prefix + "src/" + source + ".c" for source in SQLITE_CORE_SOURCES] + [prefix + "ext/fts3/" + source + ".c" for source in SQLITE_FTS3_SOURCES] + [prefix + path for path in ["ext/icu/icu.c", "ext/rtree/rtree.c", "ext/session/sqlite3session.c", "ext/rbu/sqlite3rbu.c", "ext/misc/stmt.c"]] + [":" + name + "_generated_sources"], + hdrs = [prefix + "headers"], + deps = [":" + generated, ":" + name + "_headers"], + local_defines = ["SQLITE_CORE"], + defines = ["SQLITE_THREADSAFE=0", "SQLITE_OMIT_LOAD_EXTENSION"], + copts = _C, + linkstatic = True, + target_compatible_with = WASIX_DEPENDENCY_COMPATIBLE, + ) + +def wasix_postgis_geos(name): + _pin("geos", "c389f532d25fe6228861d9b19339f9cb57ca4bdb") + prefix = "@postgis_geos//:" + wasix_dependency_headers(name = name + "_config", kind = "geos", root = prefix + "Version.txt", inputs = [prefix + "include/geos/version.h.in", prefix + "capi/geos_c.h.in"], outs = ["geos_c.h", "geos/version.h"]) + postgis_source_headers(name = name + "_headers", root = prefix + "Version.txt", headers = [prefix + "headers"], include_dirs = ["include", "src/deps"]) + cc_library(name = name + "_ryu", srcs = [prefix + "native_c_sources"], deps = [":" + name + "_headers"], copts = _C, linkstatic = True, target_compatible_with = WASIX_DEPENDENCY_COMPATIBLE) + cc_library(name = name, srcs = [prefix + "native_sources"], hdrs = [prefix + "headers"], deps = [":" + name + "_config", ":" + name + "_headers", ":" + name + "_ryu"], copts = _CXX, defines = ["USE_UNSTABLE_GEOS_CPP_API", "HAVE_FENV"], linkstatic = True, target_compatible_with = WASIX_DEPENDENCY_COMPATIBLE) + +def wasix_postgis_json_c(name): + _pin("json-c", "41a55cfcedb54d9c1874f2f0eb07b504091d7e37") + prefix = "@postgis_json_c//:" + wasix_dependency_headers(name = name + "_config", kind = "json_c", root = prefix + "CMakeLists.txt", inputs = [prefix + "cmake/config.h.in", prefix + "cmake/json_config.h.in", prefix + "json.h.cmakein"], outs = ["config.h", "json_config.h", "json.h"]) + postgis_source_headers(name = name + "_headers", root = prefix + "CMakeLists.txt", headers = [prefix + "headers"], include_dirs = ["."]) + cc_library(name = name, srcs = [prefix + stem + ".c" for stem in _JSON_C], hdrs = [prefix + "headers"], deps = [":" + name + "_config", ":" + name + "_headers"], defines = ["_GNU_SOURCE"], copts = _C, linkstatic = True, target_compatible_with = WASIX_DEPENDENCY_COMPATIBLE) + +def wasix_postgis_libxml2(name): + _pin("libxml2", "d23960a130c5bb82779c9405fbbf85e65fb3c57c") + prefix = "@postgis_libxml2//:" + wasix_dependency_headers(name = name + "_config", kind = "libxml2", root = prefix + "VERSION", inputs = [prefix + "config.h.cmake.in", prefix + "include/libxml/xmlversion.h.in"], outs = ["config.h", "libxml/xmlversion.h"]) + postgis_source_headers(name = name + "_headers", root = prefix + "VERSION", headers = [prefix + "headers"], include_dirs = ["include", "."]) + cc_library(name = name, srcs = [prefix + stem + ".c" for stem in _XML], hdrs = [prefix + "headers"], deps = [":" + name + "_config", ":" + name + "_headers"], defines = ["HAVE_STRINGS_H", "HAVE_UNISTD_H"], copts = _C, linkstatic = True, target_compatible_with = WASIX_DEPENDENCY_COMPATIBLE) + +def wasix_postgis_iconv(name): + if EXTENSION_DEPENDENCIES["postgis"]["libiconv"]["sha256"] != "88dd96a8c0464eca144fc791ae60cd31cd8ee78321e67397e25fc095c4a19aa6": + fail("review the WASI libiconv source/configuration recipe before changing its canonical pin") + prefix = "@postgis_libiconv//:" + wasix_dependency_headers(name = name + "_config", kind = "libiconv", root = prefix + "configure", inputs = [prefix + path for path in ["lib/config.h.in", "include/iconv.h.build.in", "libcharset/include/localcharset.h.build.in", "libcharset/include/libcharset.h.build.in"]], outs = ["config.h", "iconv.h", "localcharset.h", "libcharset.h"]) + postgis_source_headers(name = name + "_headers", root = prefix + "configure", headers = [prefix + "headers", prefix + "lib/encodings.def", prefix + "lib/encodings_local.def"], include_dirs = ["lib", "include", "libcharset/include"]) + cc_library(name = name, srcs = [prefix + path for path in ["lib/iconv.c", "lib/compat.c", "libcharset/lib/localcharset.c", "libcharset/lib/relocatable-stub.c"]], hdrs = [prefix + "headers"], deps = [":" + name + "_config", ":" + name + "_headers"], local_defines = ["BUILDING_LIBICONV", "BUILDING_LIBCHARSET"], copts = _C, linkstatic = True, target_compatible_with = WASIX_DEPENDENCY_COMPATIBLE) + +def wasix_postgis_proj(name, sqlite): + _pin("proj", "f08fa86c478c4bbbf003b1ec751dd84aa6eca486") + prefix = "@postgis_proj//:" + wasix_dependency_headers(name = name + "_config", kind = "proj", root = prefix + "CMakeLists.txt", inputs = [prefix + "cmake/proj_config.cmake.in"], outs = ["proj_config.h"]) + postgis_source_headers(name = name + "_headers", root = prefix + "CMakeLists.txt", headers = [prefix + "headers"], include_dirs = ["include", "src"]) + wasix_proj_database(name = name + "_database") + wasix_proj_embed(name = name + "_embedded", database = ":" + name + "_database") + native.filegroup(name = name + "_embedded_sources", srcs = [":" + name + "_embedded"], output_group = "library_sources") + defines = ["PROJ_DLL=", "PROJ_HAS_PTHREADS", "EMBED_RESOURCE_FILES=1", "USE_ONLY_EMBEDDED_RESOURCE_FILES=1"] + cc_library(name = name + "_c", srcs = [prefix + "native_c_sources", prefix + "src/embedded_resources.c", prefix + "src/memvfs.c", ":" + name + "_embedded_sources"], hdrs = [prefix + "headers"], deps = [":" + name + "_config", ":" + name + "_headers", ":" + name + "_embedded", sqlite], defines = defines, copts = _C, linkstatic = True, target_compatible_with = WASIX_DEPENDENCY_COMPATIBLE) + cc_library(name = name, srcs = [prefix + "native_sources"], hdrs = [prefix + "headers"], deps = [":" + name + "_config", ":" + name + "_headers", ":" + name + "_c", sqlite], defines = defines, copts = _CXX, linkstatic = True, target_compatible_with = WASIX_DEPENDENCY_COMPATIBLE) + +def wasix_postgis_dependencies(): + wasix_postgis_sqlite(name = "sqlite") + wasix_postgis_geos(name = "geos") + wasix_postgis_json_c(name = "json_c") + wasix_postgis_libxml2(name = "libxml2") + wasix_postgis_iconv(name = "iconv") + wasix_postgis_proj(name = "proj", sqlite = ":sqlite") diff --git a/build_defs/wasix/dependencies/postgis_lifecycle.c b/build_defs/wasix/dependencies/postgis_lifecycle.c new file mode 100644 index 000000000..682572d62 --- /dev/null +++ b/build_defs/wasix/dependencies/postgis_lifecycle.c @@ -0,0 +1,14 @@ +/* The maintained WASIX PostGIS dependency module lives for the process. + * Its C++ objects have no separate thread-local destructor lifecycle. + * Kept from src/extensions/external/postgis/tools/build_wasix.sh. + */ +__attribute__((visibility("hidden"))) void _ZTH5errno(void) {} + +__attribute__((visibility("hidden"))) int __cxa_thread_atexit_impl( + void (*destructor)(void *), void *object, void *dso_symbol) +{ + (void)destructor; + (void)object; + (void)dso_symbol; + return 0; +} diff --git a/build_defs/wasix/dependencies/proj_embed.mts b/build_defs/wasix/dependencies/proj_embed.mts new file mode 100644 index 000000000..7ee4a6012 --- /dev/null +++ b/build_defs/wasix/dependencies/proj_embed.mts @@ -0,0 +1,55 @@ +/** PROJ's pinned FileEmbed/lib_proj resource generation, with declared inputs. */ +import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import { dirname, join } from 'node:path'; +import { parseArgs } from 'node:util'; + +const { values } = parseArgs({ options: { spec: { type: 'string' } } }); +if (!values.spec) throw new Error('expected --spec'); +const spec = JSON.parse(readFileSync(values.spec, 'utf8')) as { + output: string; + database: string; + resources: Record; +}; +const emit = (name: string, content: string): void => { + const destination = join(spec.output, 'file_embed', name); + mkdirSync(dirname(destination), { recursive: true }); + writeFileSync(destination, content); +}; +for (const [name, path] of Object.entries({ 'proj.db': spec.database, ...spec.resources })) { + const identifier = name.replace(/[^A-Za-z_0-9]/gu, '_'); + const bytes = readFileSync(path); + const chunks: string[] = []; + for (let offset = 0; offset < bytes.length; offset += 16) { + chunks.push( + Array.from( + bytes.subarray(offset, offset + 16), + (byte) => `0x${byte.toString(16).padStart(2, '0')},`, + ).join(''), + ); + } + emit( + `${identifier}.h`, + `#ifndef ${identifier}_H\n#define ${identifier}_H\n#include \nextern const uint8_t ${identifier}_data[];\nextern const unsigned ${identifier}_size;\n#endif\n`, + ); + emit( + `${identifier}.c`, + `#include "${identifier}.h"\nconst uint8_t ${identifier}_data[] = {\n${chunks.join('\n')}\n};\nconst unsigned ${identifier}_size = sizeof(${identifier}_data);\n`, + ); +} +emit( + 'embedded_resources.c', + `const unsigned char *pj_get_embedded_resource(const char *filename, unsigned int *pnSize) {\n${Object.keys( + spec.resources, + ) + .map((name) => { + const identifier = name.replace(/[^A-Za-z_0-9]/gu, '_'); + return ` if (strcmp(filename, ${JSON.stringify(name)}) == 0) { *pnSize = ${identifier}_size; return ${identifier}_data; }`; + }) + .join('\n')}\n *pnSize = 0; return NULL;\n}\n`, +); +// The upstream dispatcher includes this file and sees the generated declarations. +const declarations = Object.keys(spec.resources) + .map((name) => `#include "${name.replace(/[^A-Za-z_0-9]/gu, '_')}.h"`) + .join('\n'); +const dispatcher = join(spec.output, 'file_embed', 'embedded_resources.c'); +writeFileSync(dispatcher, `${declarations}\n${readFileSync(dispatcher, 'utf8')}`); diff --git a/build_defs/wasix/dependencies/proj_resources.bzl b/build_defs/wasix/dependencies/proj_resources.bzl new file mode 100644 index 000000000..ef7fe1740 --- /dev/null +++ b/build_defs/wasix/dependencies/proj_resources.bzl @@ -0,0 +1,67 @@ +"""Source-built execution SQLite database and target PROJ embedded data.""" + +load("@rules_cc//cc/common:cc_common.bzl", "cc_common") +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") +load("//build_defs/foundation:bun.bzl", "BunScriptInfo", "bun_action") + +PROJ_DICTIONARY_FILES = ["proj.ini", "world", "other.extra", "nad27", "GL27", "nad83", "nad.lst", "CH", "ITRF2000", "ITRF2008", "ITRF2014", "ITRF2020"] + +def _database_impl(ctx): + output = ctx.actions.declare_file(ctx.label.name + "/proj.db") + args = ctx.actions.args() + args.add("--source", ctx.file.root.dirname) + args.add("--output", output) + args.add("--sqlite", ctx.executable.sqlite) + bun_action( + ctx, + ctx.attr._generator, + tools = [ctx.attr.sqlite[DefaultInfo].files_to_run], + inputs = ctx.files.inputs + [ctx.file.root], + outputs = [output], + arguments = [args], + mnemonic = "WasixProjDatabase", + ) + return [DefaultInfo(files = depset([output]))] + +wasix_proj_database = rule( + implementation = _database_impl, + attrs = { + "root": attr.label(default = "@postgis_proj//:CMakeLists.txt", allow_single_file = True), + "inputs": attr.label_list(default = ["@postgis_proj//:all_sources"], allow_files = True), + "sqlite": attr.label(default = "//build_defs/extensions/postgis:sqlite_cli", executable = True, cfg = "exec"), + "_generator": attr.label(default = "//build_defs/extensions/postgis:proj_db", providers = [BunScriptInfo], cfg = "exec"), + }, +) + +def _embed_impl(ctx): + identifiers = ["proj_db"] + [name.replace(".", "_").replace("-", "_") for name in PROJ_DICTIONARY_FILES] + outputs = [ctx.actions.declare_file(ctx.label.name + "/file_embed/" + name + suffix) for name in identifiers for suffix in [".c", ".h"]] + dispatcher = ctx.actions.declare_file(ctx.label.name + "/file_embed/embedded_resources.c") + outputs.append(dispatcher) + root = dispatcher.dirname.rsplit("/", 1)[0] + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode({"output": root, "database": ctx.file.database.path, "resources": {file.basename: file.path for file in ctx.files.resources}})) + args = ctx.actions.args() + args.add("--spec", spec) + bun_action( + ctx, + ctx.attr._generator, + inputs = [spec, ctx.file.database] + ctx.files.resources, + outputs = outputs, + arguments = [args], + mnemonic = "WasixProjEmbed", + ) + return [ + DefaultInfo(files = depset(outputs)), + OutputGroupInfo(library_sources = depset([file for file in outputs if file.basename.endswith(".c") and file != dispatcher])), + CcInfo(compilation_context = cc_common.create_compilation_context(headers = depset(outputs), includes = depset([root]))), + ] + +wasix_proj_embed = rule( + implementation = _embed_impl, + attrs = { + "database": attr.label(allow_single_file = True, mandatory = True), + "resources": attr.label_list(default = ["@postgis_proj//:data/" + name for name in PROJ_DICTIONARY_FILES], allow_files = True), + "_generator": attr.label(default = "//build_defs/wasix/dependencies:proj_embed", providers = [BunScriptInfo], cfg = "exec"), + }, +) diff --git a/build_defs/wasix/extensions.bzl b/build_defs/wasix/extensions.bzl new file mode 100644 index 000000000..1ecc38d51 --- /dev/null +++ b/build_defs/wasix/extensions.bzl @@ -0,0 +1,76 @@ +"""Portable extension modules using shared reviewed source construction units.""" + +load("@rules_cc//cc:defs.bzl", "cc_library") +load("@oliphaunt_metadata//:metadata.bzl", "CONTRIB_MEMBERS") +load("//build_defs/extensions:contrib.bzl", "CONTRIB_C_SOURCES", "CONTRIB_HEADERS", "contrib_generated_sources") +load("//build_defs/extensions:external.bzl", "EXTERNAL_C_SOURCES", "VECTOR_COPTS", "external_extension_inputs") +load(":config.bzl", "WASIX_COPTS") +load(":wasm.bzl", "wasix_module") + +_COMPATIBLE = ["@platforms//cpu:wasm32", "@platforms//os:wasi"] + +def wasix_contrib_modules(crypto = None): + modules = [] + for member in CONTRIB_MEMBERS: + identity = member["id"] + if identity not in CONTRIB_C_SOURCES: + fail("No reviewed WASIX contrib construction unit: " + identity) + # The OpenSSL WASIX profile must be real before admitting pgcrypto. + if identity == "pgcrypto" and crypto == None: + continue + name = "contrib_" + identity + prefix = "@postgres_wasix//:contrib/" + member["contrib-dir"] + "/" + sources = [prefix + stem + ".c" for stem in CONTRIB_C_SOURCES[identity]] + headers = [prefix + header for header in CONTRIB_HEADERS.get(identity, [])] + deps = ["@postgres_wasix//:server_headers"] + copts = WASIX_COPTS + if identity in ["cube", "seg"]: + generated = name + "_generated" + contrib_generated_sources(name = generated, grammar = prefix + identity + "parse.y", scanner = prefix + identity + "scan.l", include_headers = headers) + sources.append(":" + generated) + deps.append(":" + generated) + elif identity == "fuzzystrmatch": + generated = name + "_generated" + contrib_generated_sources(name = generated, header_script = prefix + "daitch_mokotoff_header.pl") + sources.append(":" + generated) + deps.append(":" + generated) + elif identity == "uuid_ossp": + sources.append("//src/extensions/contrib:portable-uuid/portable_uuid.c") + uuid_headers = name + "_uuid_headers" + cc_library( + name = uuid_headers, + hdrs = ["//src/extensions/contrib:portable-uuid/include/uuid/uuid.h"], + strip_include_prefix = "/src/extensions/contrib/portable-uuid/include", + linkstatic = True, + target_compatible_with = _COMPATIBLE, + ) + headers.append("//build_defs/extensions:uuid_config.h") + deps.append(":" + uuid_headers) + copts = copts + ["-include", "build_defs/extensions/uuid_config.h"] + elif identity == "pgcrypto": + deps.append(crypto) + cc_library(name = name + "_objects", srcs = sources, hdrs = headers, deps = deps, copts = copts, linkstatic = True, target_compatible_with = _COMPATIBLE) + wasix_module(name = name, output_name = member["module-file"], deps = [":" + name + "_objects"], target_compatible_with = _COMPATIBLE) + modules.append(":" + name) + return modules + +def wasix_external_c_modules(): + modules = [] + for sql_name in EXTERNAL_C_SOURCES: + name = "external_" + sql_name + attrs = external_extension_inputs(name = name, sql_name = sql_name, link_profile = "wasix") + # The CcInfo linker context must contain archives only. Forward the + # reviewed math dependency explicitly to the WASIX side-module link. + linkopts = attrs.pop("linkopts", []) + if type(linkopts) != "list": + fail("external WASIX input requires explicit literal linker options: " + sql_name) + attrs["deps"] = attrs.get("deps", []) + ["@postgres_wasix//:server_headers"] + attrs["copts"] = attrs.get("copts", []) + WASIX_COPTS + (VECTOR_COPTS if sql_name == "vector" else []) + if sql_name == "pg_hashids": + # PG_FUNCTION_INFO_V1 keeps every SQL entry point PGDLLEXPORT. + # Internal hashids helpers are not the PostgreSQL module API. + attrs["copts"].append("-fvisibility=hidden") + cc_library(name = name + "_objects", linkstatic = True, target_compatible_with = _COMPATIBLE, **attrs) + wasix_module(name = name, output_name = sql_name + ".so", deps = [":" + name + "_objects"], linkopts = linkopts, target_compatible_with = _COMPATIBLE) + modules.append(":" + name) + return modules diff --git a/build_defs/wasix/held-wasix-relocatable-includes.patch b/build_defs/wasix/held-wasix-relocatable-includes.patch new file mode 100644 index 000000000..ac2c2dfd4 --- /dev/null +++ b/build_defs/wasix/held-wasix-relocatable-includes.patch @@ -0,0 +1,59 @@ +--- a/build-support.rs ++++ b/build-support.rs +@@ -1,3 +1,55 @@ + fn rust_string_literal(path: &Path) -> String { +- format!("{:?}", path.to_string_lossy()) ++ // Generated Rust is compiled in a later action. Keep references relative ++ // to its output directory instead of retaining a build-script sandbox. ++ fn lexical_absolute(path: &Path) -> PathBuf { ++ let mut normalized = PathBuf::new(); ++ for component in std::path::absolute(path) ++ .expect("absolute generated include path") ++ .components() ++ { ++ match component { ++ std::path::Component::ParentDir => { ++ normalized.pop(); ++ } ++ std::path::Component::CurDir => {} ++ component => normalized.push(component.as_os_str()), ++ } ++ } ++ normalized ++ } ++ ++ let base = lexical_absolute(&PathBuf::from( ++ env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"), ++ )); ++ let target = lexical_absolute(path); ++ if !target.starts_with(&base) { ++ let manifest_dir = lexical_absolute(&PathBuf::from( ++ env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"), ++ )); ++ if let Ok(member) = target.strip_prefix(&manifest_dir) { ++ return format!( ++ "concat!(env!(\"CARGO_MANIFEST_DIR\"), {:?})", ++ format!("/{}", member.to_string_lossy().replace('\\', "/")) ++ ); ++ } ++ } ++ let base_components = base.components().collect::>(); ++ let target_components = target.components().collect::>(); ++ let common = base_components ++ .iter() ++ .zip(&target_components) ++ .take_while(|(left, right)| left == right) ++ .count(); ++ if common == 0 { ++ // Ordinary Windows Cargo may place inputs and outputs on separate drives. ++ return format!("{:?}", target.to_string_lossy()); ++ } ++ let mut relative = PathBuf::new(); ++ for _ in &base_components[common..] { ++ relative.push(".."); ++ } ++ for component in &target_components[common..] { ++ relative.push(component.as_os_str()); ++ } ++ format!("{:?}", relative.to_string_lossy()) + } diff --git a/build_defs/wasix/hermetic-cc-fused-colon.patch b/build_defs/wasix/hermetic-cc-fused-colon.patch new file mode 100644 index 000000000..d50535852 --- /dev/null +++ b/build_defs/wasix/hermetic-cc-fused-colon.patch @@ -0,0 +1,73 @@ +--- a/toolchain/zig-wrapper.zig ++++ b/toolchain/zig-wrapper.zig +@@ -302,8 +302,8 @@ + } + + // Workaround for https://github.com/ziglang/zig/issues/23287: zig 0.14.0 lld +-// does not handle the colon-link syntax (-l:filename). When we see "-l" followed +-// by ":filename", resolve it to a full path by searching the -L directories. ++// does not handle the colon-link syntax. Resolve both "-l" ":filename" and ++// "-l:filename" to a full path by searching the declared -L directories. + fn resolveColonLibraries( + arena: mem.Allocator, + cwd: fs.Dir, +@@ -324,22 +324,52 @@ + } + + var i: usize = 0; +- while (i + 1 < args.items.len) : (i += 1) { +- if (!mem.eql(u8, args.items[i], "-l")) continue; +- const next = args.items[i + 1]; +- if (!mem.startsWith(u8, next, ":")) continue; +- +- const filename = next[1..]; ++ while (i < args.items.len) : (i += 1) { ++ const arg = args.items[i]; ++ const split = mem.eql(u8, arg, "-l") and i + 1 < args.items.len and ++ mem.startsWith(u8, args.items[i + 1], ":"); ++ const filename = if (split) args.items[i + 1][1..] else if (mem.startsWith(u8, arg, "-l:")) arg[3..] else continue; ++ if (filename.len == 0) continue; + for (lib_paths.items) |lib_path| { + const full_path = try fs.path.join(arena, &[_][]const u8{ lib_path, filename }); + cwd.access(full_path, .{}) catch continue; + args.items[i] = full_path; +- _ = args.orderedRemove(i + 1); ++ if (split) _ = args.orderedRemove(i + 1); + break; + } + } + } + ++test "zig-wrapper:colon-libraries" { ++ var arena = std.heap.ArenaAllocator.init(testing.allocator); ++ defer arena.deinit(); ++ const allocator = arena.allocator(); ++ var tmp = testing.tmpDir(.{}); ++ defer tmp.cleanup(); ++ try tmp.dir.makeDir("sdk"); ++ try tmp.dir.writeFile(.{ .sub_path = "sdk/libpresent.so.1", .data = "" }); ++ ++ var args = ArrayListUnmanaged([]const u8){}; ++ try args.appendSlice(allocator, &[_][]const u8{ ++ "zig", "-L", "missing", "-Lsdk", "-l", ":libpresent.so.1", ++ "-l:libpresent.so.1", "-l", ":libmissing.so.1", "-l:libmissing.so.1", ++ }); ++ try resolveColonLibraries(allocator, tmp.dir, &args); ++ const present = try fs.path.join(allocator, &[_][]const u8{ "sdk", "libpresent.so.1" }); ++ const expected = [_][]const u8{ ++ "zig", "-L", "missing", "-Lsdk", present, present, ++ "-l", ":libmissing.so.1", "-l:libmissing.so.1", ++ }; ++ try testing.expectEqual(expected.len, args.items.len); ++ for (expected, args.items) |want, got| try testing.expectEqualStrings(want, got); ++ ++ // The fused form also works when it is the last argument and -L is split. ++ args.clearRetainingCapacity(); ++ try args.appendSlice(allocator, &[_][]const u8{ "zig", "-L", "sdk", "-l:libpresent.so.1" }); ++ try resolveColonLibraries(allocator, tmp.dir, &args); ++ try testing.expectEqualStrings(present, args.items[3]); ++} ++ + fn parseFatal( + arena: mem.Allocator, + comptime fmt: []const u8, diff --git a/build_defs/wasix/host-aot-smoke-test.bzl b/build_defs/wasix/host-aot-smoke-test.bzl new file mode 100644 index 000000000..f3cdb38aa --- /dev/null +++ b/build_defs/wasix/host-aot-smoke-test.bzl @@ -0,0 +1,55 @@ +"""The actual host smoke rule must cross Bun's resolved File-argument boundary.""" + +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") +load("@oliphaunt_metadata//:metadata.bzl", "PRODUCTS") +load(":host-aot-smoke.bzl", "wasix_host_aot_smoke_test") + +def _archive_names(): + runtime = PRODUCTS["liboliphaunt-wasix"]["version"] + tools = PRODUCTS["postgres-tools-wasix"]["version"] + return [ + "liboliphaunt-wasix-portable-" + runtime + ".crate", + "oliphaunt-extension-contrib-pg18-wasix-" + runtime + ".crate", + "oliphaunt-extension-contrib-pg18-aot-linux-x64-" + runtime + ".crate", + "oliphaunt-wasix-tools-" + tools + ".crate", + "oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu-" + tools + ".crate", + ] + +def _fixtures_impl(ctx): + files = [ctx.actions.declare_file(ctx.label.name + "/" + name) for name in _archive_names()] + for file in files: + ctx.actions.write(file, "analysis-only declared archive fixture") + binary = ctx.actions.declare_file(ctx.label.name + ".binary") + ctx.actions.write(binary, "analysis-only executable fixture", is_executable = True) + return [DefaultInfo(files = depset(files), executable = binary, runfiles = ctx.runfiles(files = files))] + +_fixtures = rule(implementation = _fixtures_impl, executable = True) + +def _arguments_impl(ctx): + env = analysistest.begin(ctx) + actions = analysistest.target_actions(env) + entries = [action for action in actions if action.mnemonic == "TemplateExpand"] + asserts.equals(env, 1, len(entries)) + configuration = json.decode(entries[0].substitutions["@@CONFIG@@"]) + arguments = configuration["arguments"] + asserts.equals(env, 7, len(arguments)) + asserts.true(env, all([sorted(argument.keys()) == ["file"] for argument in arguments])) + paths = [argument["file"] for argument in arguments] + asserts.equals(env, sorted(_archive_names()), sorted([path.rsplit("/", 1)[-1] for path in paths[2:]])) + asserts.true(env, all([path.startswith(configuration["workspace"] + "/") for path in paths])) + specification = analysistest.target_under_test(env).label.name + ".inputs.json" + metadata = [action for action in actions if action.mnemonic == "FileWrite" and specification in [file.basename for file in action.outputs.to_list()]] + asserts.equals(env, 1, len(metadata)) + asserts.equals(env, ["runtimeVersion", "target", "toolsVersion"], sorted(json.decode(metadata[0].content).keys())) + runfiles = analysistest.target_under_test(env)[DefaultInfo].default_runfiles.files.to_list() + for name in _archive_names(): + asserts.true(env, name in [file.basename for file in runfiles]) + return analysistest.end(env) + +_arguments_test = analysistest.make(_arguments_impl) + +def wasix_host_aot_smoke_argument_tests(): + _fixtures(name = "host_aot_smoke_argument_files", tags = ["manual"]) + wasix_host_aot_smoke_test(name = "host_aot_smoke_argument_fixture", target_triple = "x86_64-unknown-linux-gnu", + carriers = ":host_aot_smoke_argument_files", binary = ":host_aot_smoke_argument_files", tags = ["manual"]) + _arguments_test(name = "host_aot_smoke_arguments_test", target_under_test = ":host_aot_smoke_argument_fixture") diff --git a/build_defs/wasix/host-aot-smoke.bzl b/build_defs/wasix/host-aot-smoke.bzl new file mode 100644 index 000000000..e9867c995 --- /dev/null +++ b/build_defs/wasix/host-aot-smoke.bzl @@ -0,0 +1,44 @@ +"""Execute a bounded source-built side module and split tools on their native host.""" + +load("@oliphaunt_metadata//:metadata.bzl", "PRODUCTS", "PUBLICATION_CARRIERS") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/extensions:wasix_carriers.bzl", "wasix_sql_carrier_helpers") +load(":npm.bzl", "RUNTIME_NPM_NOTICES") + +def _host_aot_smoke_impl(ctx): + binary = ctx.attr.binary[DefaultInfo].files_to_run.executable + rows = [row for row in PUBLICATION_CARRIERS if row["ecosystem"] == "cargo" and ( + row["name"] == "liboliphaunt-wasix-portable" or + (row["name"].startswith("oliphaunt-extension-contrib-pg18-") and row["target"] in ["wasix-portable", ctx.attr.target_triple]) or + (row["product"] == "postgres-tools-wasix" and row["target"] in [None, ctx.attr.target_triple]) + )] + expected = [row["name"] + "-" + row["version"] + ".crate" for row in rows] + crates = [file for file in ctx.files.carriers if file.basename in expected] + if len(expected) != 5 or sorted([file.basename for file in crates]) != sorted(expected) or any([file.is_directory for file in crates]): + fail("WASIX host smoke requires its exact portable core, contrib/tools and matching host AOT Files") + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode({ + "target": ctx.attr.target_triple, + "runtimeVersion": PRODUCTS["liboliphaunt-wasix"]["version"], + "toolsVersion": PRODUCTS["postgres-tools-wasix"]["version"], + })) + files = crates + [spec, binary] + ctx.files._helpers + return bun_test_entrypoint(ctx, ctx.file._runner, [spec, binary] + crates, files, + source_files = [ctx.file._runner] + ctx.files._helpers, + additional_runfiles = ctx.attr.binary[DefaultInfo].default_runfiles) + +_host_aot_smoke_test = rule( + implementation = _host_aot_smoke_impl, + test = True, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "target_triple": attr.string(mandatory = True), + "carriers": attr.label(default = "@wasix_runtime_carriers//:host_smoke", allow_files = True), + "binary": attr.label(default = "//src/wasix/sdks/rust:host_aot_smoke_unit_test", executable = True, cfg = "target"), + "_runner": attr.label(default = "//build_defs/wasix:host-aot-smoke.mts", allow_single_file = True), + "_helpers": attr.label_list(default = wasix_sql_carrier_helpers() + ["//src/wasix/postgres-tools:tools/package-assets.mts", "//src/wasix/runtime:tools/package-release-assets.mts"] + RUNTIME_NPM_NOTICES.keys(), allow_files = True), + }), +) + +def wasix_host_aot_smoke_test(name, **kwargs): + _host_aot_smoke_test(name = name, args = bun_test_entrypoint_args(name), **kwargs) diff --git a/build_defs/wasix/host-aot-smoke.mts b/build_defs/wasix/host-aot-smoke.mts new file mode 100644 index 000000000..4d771d875 --- /dev/null +++ b/build_defs/wasix/host-aot-smoke.mts @@ -0,0 +1,263 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + mkdirSync, + mkdtempSync, + readFileSync, + realpathSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { + validatePortableToolsPayload, + validateToolsAotPayload, +} from '../../src/wasix/postgres-tools/tools/package-assets.mts'; +import { assertWasixAotArtifactPayloads } from '../../src/wasix/runtime/tools/check-release-assets.mts'; +import { assertCanonicalWasixAotManifest } from '../../src/wasix/runtime/tools/wasix-aot-manifest.mts'; +import { + AOT_TARGET_TRIPLES, + RUNTIME_PACKAGE, + TOOLS_AOT_PACKAGES, + TOOLS_PACKAGE, + wasixExtensionAotPackageName, + wasixExtensionPackageName, +} from '../../src/wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; +import { + readPortableArchiveEntries, + readPortableTarZstdBufferEntries, +} from '../../tools/packaging/portable-archive.mts'; + +export type HostSmokeSpec = { + target: string; + runtimeVersion: string; + toolsVersion: string; + crates: Record; +}; +const PRODUCT = 'oliphaunt-extension-contrib-pg18'; +const digest = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); + +export function readWasixHostAotSmokeSpec( + specification: string, + crates: readonly string[], +): HostSmokeSpec { + assert( + crates.length === 5 && crates.every((file) => path.isAbsolute(file)), + 'WASIX host smoke requires five resolved declared archive Files', + ); + const byName = Object.fromEntries(crates.map((file) => [path.basename(file), file])); + assert.equal(Object.keys(byName).length, 5, 'WASIX host smoke archive names must be unique'); + return { ...JSON.parse(readFileSync(specification, 'utf8')), crates: byName }; +} + +export function assertWasixAotSmokeHost( + target: string, + platform: string = process.platform, + architecture: string = process.arch, +) { + const hostId = { + 'linux-x64': 'linux-x64-gnu', + 'linux-arm64': 'linux-arm64-gnu', + 'darwin-arm64': 'macos-arm64', + 'win32-x64': 'windows-x64-msvc', + }[`${platform}-${architecture}`]; + assert( + hostId && target === AOT_TARGET_TRIPLES[hostId], + 'WASIX AOT smoke must execute on its declared native host', + ); +} + +/** Extract the selected host's genuine final envelopes; no WASIX producer runs here. */ +export function prepareWasixHostAotSmoke(spec: HostSmokeSpec, root: string) { + const targetId = Object.keys(AOT_TARGET_TRIPLES).find( + (key) => AOT_TARGET_TRIPLES[key] === spec.target, + ); + assert(targetId, 'WASIX host smoke needs a canonical native target'); + const write = (relative: string, bytes: Uint8Array | string) => { + const file = path.join(root, relative); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, bytes); + chmodSync(file, 0o644); + return file; + }; + const crate = (name: string, version: string) => { + const filename = `${name}-${version}.crate`; + assert(spec.crates[filename], `WASIX host smoke is missing its exact final ${filename}`); + const entries = readPortableArchiveEntries(realpathSync(spec.crates[filename])); + const prefix = `${name}-${version}/`; + const bytes = (relative: string) => { + const entry = entries.get(prefix + relative); + assert( + entry?.isFile && !entry.isSymbolicLink, + `WASIX host smoke needs regular ${filename}:${relative}`, + ); + return Buffer.from(entry.data()); + }; + const manifest = Bun.TOML.parse(bytes('Cargo.toml').toString()).package; + assert.equal(manifest.name, name); + assert.equal(manifest.version, version); + const extract = (directory: string, destination: string) => { + const memberPrefix = `${prefix}${directory}/`; + for (const [member, entry] of entries) { + if (!member.startsWith(memberPrefix) || entry.isDirectory) continue; + assert(entry.isFile && !entry.isSymbolicLink, 'WASIX host smoke payload must be regular'); + const relative = member.slice(memberPrefix.length); + assert(relative && !relative.split('/').some((part) => ['', '.', '..'].includes(part))); + write(`${destination}/${relative}`, entry.data()); + } + return path.join(root, destination); + }; + return { bytes, extract }; + }; + const core = crate(RUNTIME_PACKAGE, spec.runtimeVersion); + const coreManifest = JSON.parse(core.bytes('payload/manifest.json').toString()); + const coreArchive = core.bytes('payload/oliphaunt.wasix.tar.zst'); + assert.equal(digest(coreArchive), coreManifest.runtime.sha256); + const coreModule = readPortableTarZstdBufferEntries(coreArchive).get('oliphaunt/bin/postgres'); + assert( + coreModule?.isFile && !coreModule.isSymbolicLink, + 'WASIX host smoke requires its actual current core module', + ); + const coreModuleSha256 = digest(coreModule.data()); + assert.equal(coreModuleSha256, coreManifest.runtime['module-sha256']); + const sourceFingerprint = coreManifest['source-fingerprint']; + assert.equal(typeof sourceFingerprint, 'string'); + + const portable = crate(wasixExtensionPackageName(PRODUCT), spec.runtimeVersion); + const archive = portable.bytes('payload/files/extensions/uuid-ossp/extension.tar.zst'); + const module = readPortableTarZstdBufferEntries(archive).get('lib/postgresql/uuid-ossp.so'); + assert(module?.isFile && !module.isSymbolicLink, 'UUID-OSSP final archive has no side module'); + const aot = crate(wasixExtensionAotPackageName(PRODUCT, spec.target), spec.runtimeVersion); + const aotManifest = JSON.parse(aot.bytes('manifests/uuid-ossp.json').toString()); + assertCanonicalWasixAotManifest(aotManifest, { expectedTarget: spec.target }); + assert.equal( + aotManifest['source-fingerprint'], + sourceFingerprint, + 'UUID-OSSP AOT source differs from its exact core', + ); + assert.equal( + aotManifest['postgres-version'], + coreManifest.runtime['postgres-version'], + 'UUID-OSSP AOT PostgreSQL identity differs from its exact core', + ); + assert.deepEqual( + aotManifest.artifacts.map((row: { name: string }) => row.name), + ['extension:uuid-ossp'], + ); + assert.equal( + aotManifest.artifacts[0]['module-sha256'], + digest(module.data()), + 'UUID-OSSP AOT side-module identity differs from its final portable archive', + ); + assertWasixAotArtifactPayloads(aotManifest, { + readArtifact: (relative: string) => aot.bytes(`payload/files/extensions/uuid-ossp/${relative}`), + }); + const extensionPacket = write( + 'extension-packet.json', + JSON.stringify({ + product: PRODUCT, + version: spec.runtimeVersion, + runtimeVersion: spec.runtimeVersion, + archives: [ + { + sqlName: 'uuid-ossp', + path: write('extension.tar.zst', archive), + sha256: digest(archive), + }, + ], + aotManifest: write('extension-aot/manifest.json', JSON.stringify(aotManifest)), + aotArtifacts: aotManifest.artifacts.map((row: { path: string }) => ({ + path: row.path, + source: write( + `extension-aot/${row.path}`, + aot.bytes(`payload/files/extensions/uuid-ossp/${row.path}`), + ), + })), + coreModuleSha256, + coreManifest: write('core-manifest.json', JSON.stringify(coreManifest)), + }), + ); + const toolsPortable = crate(TOOLS_PACKAGE, spec.toolsVersion).extract( + 'payload', + 'tools/portable', + ); + const toolsAot = crate(TOOLS_AOT_PACKAGES[targetId], spec.toolsVersion).extract( + 'artifacts', + 'tools/aot', + ); + const portableManifest = validatePortableToolsPayload(toolsPortable, spec.toolsVersion, { + runtimeVersion: spec.runtimeVersion, + sourceFingerprint, + }); + const toolsManifest = validateToolsAotPayload(toolsAot, spec.target, { sourceFingerprint }); + const tool = (key: 'pgDump' | 'psql') => { + const wasm = portableManifest[key]; + const image = toolsManifest.artifacts.find( + (row: { name: string }) => row.name === `tool:${wasm.name}`, + ); + assert(image, 'WASIX host smoke needs the matching split-tool AOT image'); + assert.equal(image['module-sha256'], wasm.sha256); + return { + wasm: path.join(toolsPortable, wasm.path), + aot: path.join(toolsAot, image.path), + manifest: path.join(toolsAot, 'manifest.json'), + }; + }; + const toolsPacket = write( + 'tools-packet.json', + JSON.stringify({ + version: spec.toolsVersion, + runtimeVersion: spec.runtimeVersion, + pgDump: tool('pgDump'), + psql: tool('psql'), + }), + ); + return { extensionPacket, toolsPacket }; +} + +if (import.meta.main) { + assert.equal( + process.argv.length, + 9, + 'WASIX host smoke requires its configured specification, Rust test binary and five archive Files', + ); + const spec = readWasixHostAotSmokeSpec(process.argv[2], process.argv.slice(4)); + assertWasixAotSmokeHost(spec.target); + const root = mkdtempSync( + path.join(process.env.TEST_TMPDIR ?? os.tmpdir(), 'wasix-host-aot-smoke-'), + ); + try { + const { extensionPacket, toolsPacket } = prepareWasixHostAotSmoke(spec, root); + const result = Bun.spawnSync( + [ + realpathSync(process.argv[3]), + '--ignored', + '--exact', + 'oliphaunt::extensions::extension_tests::declared_uuid_ossp_carriers_pass_aot_host_smoke', + '--nocapture', + '--test-threads=1', + ], + { + env: { + ...process.env, + OLIPHAUNT_WASM_AOT_VERIFY: 'full', + OLIPHAUNT_DECLARED_EXTENSION_PACKET: extensionPacket, + OLIPHAUNT_DECLARED_TOOLS_PACKET: toolsPacket, + }, + stdout: 'pipe', + stderr: 'pipe', + timeout: 900000, + }, + ); + assert.equal(result.exitCode, 0, `${result.stderr.toString()}\n${result.stdout.toString()}`); + assert.match(result.stdout.toString(), /\b1 passed; 0 failed;/u); + console.log(result.stdout.toString().trim()); + console.log( + 'Actual current-source UUID-OSSP AOT execution/restart/materialization and split-tool dump/restore: PASS', + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} diff --git a/build_defs/wasix/host-aot-smoke.test.mts b/build_defs/wasix/host-aot-smoke.test.mts new file mode 100644 index 000000000..893eb1e15 --- /dev/null +++ b/build_defs/wasix/host-aot-smoke.test.mts @@ -0,0 +1,283 @@ +import { afterEach, expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { copyFileSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { gzipSync, zstdCompressSync } from 'node:zlib'; +import { canonicalWasixAotMetadata } from '../../src/wasix/runtime/tools/wasix-aot-manifest.mts'; +import { + AOT_TARGET_TRIPLES, + RUNTIME_PACKAGE, + TOOLS_AOT_PACKAGES, + TOOLS_PACKAGE, + wasixExtensionAotPackageName, + wasixExtensionPackageName, +} from '../../src/wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; +import { releaseNoticeRows, stageReleaseNotices } from '../../tools/packaging/release-notices.mts'; +import { wasixHostSmokeCargoIdentities, wasixHostSmokeCargoRows } from './cargo-inputs.mts'; +import { + assertWasixAotSmokeHost, + type HostSmokeSpec, + prepareWasixHostAotSmoke, + readWasixHostAotSmokeSpec, +} from './host-aot-smoke.mts'; + +const roots: string[] = []; +afterEach(() => { + for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true }); +}); +const sha = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +const module = Buffer.from('\0asm\x01\0\0\0'); +const product = 'oliphaunt-extension-contrib-pg18'; +const version = '8.9.10'; +const toolsVersion = '4.5.6'; +const fingerprint = 'independent source/hash fixture; no executable AOT claim'; + +async function fixture(targetId: string, mutation: string = '') { + const root = mkdtempSync(path.join(os.tmpdir(), 'wasix-host-smoke-format-')); + roots.push(root); + const target = AOT_TARGET_TRIPLES[targetId]; + const crates: Record = {}; + const pack = async ( + name: string, + packageVersion: string, + files: Record, + ) => { + const prefix = `${name}-${packageVersion}`; + const members = Object.fromEntries( + Object.entries({ + 'Cargo.toml': `[package]\nname="${name}"\nversion="${packageVersion}"\n`, + ...files, + }).map(([file, bytes]) => [`${prefix}/${file}`, bytes]), + ); + const file = path.join(root, `${prefix}.crate`); + writeFileSync(file, gzipSync(Buffer.from(await new Bun.Archive(members).bytes()))); + crates[path.basename(file)] = file; + }; + const coreArchive = zstdCompressSync( + Buffer.from(await new Bun.Archive({ 'oliphaunt/bin/postgres': module }).bytes()), + ); + await pack(RUNTIME_PACKAGE, version, { + 'payload/manifest.json': JSON.stringify({ + 'source-fingerprint': fingerprint, + runtime: { + sha256: sha(coreArchive), + 'module-sha256': sha(module), + 'postgres-version': '18.3', + }, + }), + 'payload/oliphaunt.wasix.tar.zst': coreArchive, + }); + const uuid = mutation === 'module' ? Buffer.concat([module, Buffer.from('changed')]) : module; + const archive = zstdCompressSync( + Buffer.from(await new Bun.Archive({ 'lib/postgresql/uuid-ossp.so': uuid }).bytes()), + ); + await pack(wasixExtensionPackageName(product), version, { + 'payload/files/extensions/uuid-ossp/extension.tar.zst': archive, + }); + const canonical = canonicalWasixAotMetadata(); + const manifest = (artifacts: unknown[]) => ({ + 'format-version': 1, + 'source-lane': canonical.sourceLane, + engine: canonical.engine, + 'wasmer-version': canonical.wasmerVersion, + 'wasmer-wasix-version': canonical.wasmerWasixVersion, + 'target-triple': target, + 'source-fingerprint': fingerprint, + 'postgres-version': '18.3', + artifacts, + }); + const image = (name: string, file: string) => { + const raw = Buffer.from(`independent serialized hash fixture ${name}`); + const compressed = zstdCompressSync(raw); + return { + bytes: compressed, + row: { + name, + path: file, + compressed: true, + sha256: sha(compressed), + 'module-sha256': sha(module), + 'raw-sha256': sha(raw), + 'raw-size': raw.length, + }, + }; + }; + const side = image('extension:uuid-ossp', 'uuid.bin.zst'); + const sideManifest = manifest([side.row]); + if (mutation === 'target') sideManifest['target-triple'] = 'unsupported-target'; + if (mutation === 'source') sideManifest['source-fingerprint'] = 'stale source'; + if (mutation === 'postgres') sideManifest['postgres-version'] = 'different PostgreSQL'; + await pack(wasixExtensionAotPackageName(product, target), version, { + 'manifests/uuid-ossp.json': JSON.stringify(sideManifest), + 'payload/files/extensions/uuid-ossp/uuid.bin.zst': + mutation === 'image' ? Buffer.from('changed image') : side.bytes, + }); + const legal = (profile: string) => { + const directory = path.join(root, profile); + stageReleaseNotices(directory, { profile }); + return Object.fromEntries( + releaseNoticeRows({ profile }).map((row) => [ + row.member, + readFileSync(path.join(directory, row.member)), + ]), + ); + }; + const toolsManifest: Record = { + schema: 'postgres-tools-wasix-portable-v1', + version: toolsVersion, + runtimeVersion: mutation === 'runtime' ? 'stale runtime' : version, + sourceFingerprint: fingerprint, + }; + for (const [key, name] of [ + ['pgDump', 'pg_dump'], + ['psql', 'psql'], + ]) + toolsManifest[key] = { + name, + path: `bin/${name}.wasix.wasm`, + sha256: sha(module), + size: module.length, + }; + await pack(TOOLS_PACKAGE, toolsVersion, { + ...Object.fromEntries( + Object.entries(legal('wasix-tools')).map(([file, bytes]) => [`payload/${file}`, bytes]), + ), + 'payload/manifest.json': JSON.stringify(toolsManifest), + 'payload/bin/pg_dump.wasix.wasm': module, + ...(mutation === 'missing-tool' ? {} : { 'payload/bin/psql.wasix.wasm': module }), + }); + const dump = image('tool:pg_dump', 'tools/pg_dump.bin.zst'); + const psql = image('tool:psql', 'tools/psql.bin.zst'); + await pack(TOOLS_AOT_PACKAGES[targetId], toolsVersion, { + ...Object.fromEntries( + Object.entries(legal('wasix-aot')).map(([file, bytes]) => [`artifacts/${file}`, bytes]), + ), + 'artifacts/manifest.json': JSON.stringify(manifest([dump.row, psql.row])), + 'artifacts/tools/pg_dump.bin.zst': dump.bytes, + 'artifacts/tools/psql.bin.zst': psql.bytes, + }); + return { + root, + spec: { target, runtimeVersion: version, toolsVersion, crates } satisfies HostSmokeSpec, + }; +} + +for (const [targetId, target] of Object.entries(AOT_TARGET_TRIPLES)) { + test(`prepares exactly UUID-OSSP and split tools for ${target}`, async () => { + const { root, spec } = await fixture(targetId); + const packets = prepareWasixHostAotSmoke(spec, path.join(root, 'prepared')); + const extension = JSON.parse(readFileSync(packets.extensionPacket, 'utf8')); + const tools = JSON.parse(readFileSync(packets.toolsPacket, 'utf8')); + expect(extension.archives.map((row: any) => row.sqlName)).toEqual(['uuid-ossp']); + expect(extension.aotArtifacts).toHaveLength(1); + expect(extension.coreModuleSha256).toEqual(sha(module)); + expect(JSON.parse(readFileSync(extension.aotManifest, 'utf8'))['target-triple']).toEqual( + target, + ); + expect(tools.runtimeVersion).toEqual(version); + expect(readFileSync(tools.pgDump.wasm)).toEqual(module); + expect(readFileSync(tools.psql.wasm)).toEqual(module); + expect(JSON.parse(readFileSync(tools.psql.manifest, 'utf8'))['target-triple']).toEqual(target); + }); +} +test('resolved main and external runfiles preserve exact host envelope inputs', async () => { + const { root, spec } = await fixture('linux-arm64-gnu'); + const runfiles = path.join(root, 'runfiles'); + const archiveFiles = Object.values(spec.crates).map((file, index) => { + const directory = path.join( + runfiles, + index === 0 ? '_main/generated-carriers' : '+_repo_rules32+wasix_runtime_carriers/host-smoke', + ); + mkdirSync(directory, { recursive: true }); + const output = path.join(directory, path.basename(file)); + copyFileSync(file, output); + return output; + }); + const specification = path.join(root, 'host.inputs.json'); + const { crates: _crates, ...metadata } = spec; + writeFileSync(specification, JSON.stringify(metadata)); + const resolved = readWasixHostAotSmokeSpec(specification, archiveFiles); + const packets = prepareWasixHostAotSmoke(resolved, path.join(root, 'from-runfiles')); + const tools = JSON.parse(readFileSync(packets.toolsPacket, 'utf8')); + expect(readFileSync(tools.pgDump.wasm)).toEqual(module); + expect(readFileSync(tools.psql.wasm)).toEqual(module); + expect(JSON.parse(readFileSync(tools.psql.manifest, 'utf8'))['target-triple']).toEqual( + spec.target, + ); + expect(() => readWasixHostAotSmokeSpec(specification, archiveFiles.slice(1))).toThrow( + /five resolved/u, + ); + expect(() => + readWasixHostAotSmokeSpec(specification, [...archiveFiles.slice(1), archiveFiles[1]]), + ).toThrow(/unique/u); + expect(() => + readWasixHostAotSmokeSpec( + specification, + archiveFiles.map((file) => path.relative(runfiles, file)), + ), + ).toThrow(/resolved declared/u); +}); +test('rejects wrong target/source/core module and changed/missing utility inputs', async () => { + for (const mutation of [ + 'target', + 'source', + 'postgres', + 'module', + 'image', + 'runtime', + 'missing-tool', + ]) { + const { root, spec } = await fixture('linux-x64-gnu', mutation); + expect(() => prepareWasixHostAotSmoke(spec, path.join(root, 'prepared'))).toThrow(); + } +}); +test('host execution accepts each supported native executor and rejects cross-host execution', () => { + for (const [platform, architecture, targetId] of [ + ['linux', 'x64', 'linux-x64-gnu'], + ['linux', 'arm64', 'linux-arm64-gnu'], + ['darwin', 'arm64', 'macos-arm64'], + ['win32', 'x64', 'windows-x64-msvc'], + ]) { + expect(() => + assertWasixAotSmokeHost(AOT_TARGET_TRIPLES[targetId], platform, architecture), + ).not.toThrow(); + expect(() => assertWasixAotSmokeHost('different-target', platform, architecture)).toThrow(); + } + expect(() => + assertWasixAotSmokeHost(AOT_TARGET_TRIPLES['macos-arm64'], 'darwin', 'x64'), + ).toThrow(); +}); +test('canonical support receipt rejects absent, duplicate, wrong version and target archives', async () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'wasix-host-smoke-receipt-')); + roots.push(root); + const toolsManifest = path.join(root, 'src/wasix/postgres-tools/crates/tools/Cargo.toml'); + mkdirSync(path.dirname(toolsManifest), { recursive: true }); + writeFileSync(toolsManifest, `[package]\nname="${TOOLS_PACKAGE}"\nversion="${toolsVersion}"\n`); + const identities = wasixHostSmokeCargoIdentities(root, version); + const inputs = await Promise.all( + identities.map(async (identity) => { + const file = path.join(root, `${identity.name}-${identity.version}.crate`); + const contents = new Bun.Archive({ + [`${identity.name}-${identity.version}/Cargo.toml`]: `[package]\nname="${identity.name}"\nversion="${identity.version}"\n`, + }); + writeFileSync(file, gzipSync(Buffer.from(await contents.bytes()))); + return { file, name: identity.name, target: identity.target }; + }), + ); + const receipt = wasixHostSmokeCargoRows(inputs, root, version); + expect(receipt).toHaveLength(10); + expect( + receipt.every((row) => row.sha256 === sha(readFileSync(path.join(root, row.path)))), + ).toBeTrue(); + expect(() => wasixHostSmokeCargoRows(inputs.slice(1), root, version)).toThrow(); + expect(() => wasixHostSmokeCargoRows([...inputs.slice(1), inputs[1]], root, version)).toThrow(); + expect(() => + wasixHostSmokeCargoRows( + inputs.map((row, index) => (index === 0 ? { ...row, target: 'wrong-target' } : row)), + root, + version, + ), + ).toThrow(); + expect(() => wasixHostSmokeCargoRows(inputs, root, 'different-version')).toThrow(); +}); diff --git a/build_defs/wasix/icu.BUILD.bazel b/build_defs/wasix/icu.BUILD.bazel new file mode 100644 index 000000000..1fbbc650f --- /dev/null +++ b/build_defs/wasix/icu.BUILD.bazel @@ -0,0 +1,89 @@ +load("@rules_cc//cc:defs.bzl", "cc_library") +load(":icu_sources.bzl", "ICU_COMMON_HEADERS", "ICU_COMMON_SOURCES", "ICU_I18N_HEADERS", "ICU_I18N_SOURCES", "ICU_STUBDATA_HEADERS", "ICU_STUBDATA_SOURCES") + +package(default_visibility = ["//visibility:public"]) + +_WASIX = ["@platforms//cpu:wasm32", "@platforms//os:wasi"] +_COPTS = ["-std=c++17", "-O2", "-g0", "-flto=thin", "-fvisibility=hidden", "-fvisibility-inlines-hidden"] + +# Match the WASIX files-data/static profile. The sysroot has POSIX headers but +# no tzname symbol; ICU's undefined-platform default otherwise references it. +cc_library( + name = "common_headers", + linkstatic = True, + hdrs = ICU_COMMON_HEADERS, + defines = ["U_STATIC_IMPLEMENTATION", "U_HAVE_TZNAME=0", "U_HAVE_TIMEZONE=0"], + includes = ["common"], + target_compatible_with = _WASIX, +) + +cc_library( + name = "data_stub", + linkstatic = True, + srcs = ICU_STUBDATA_SOURCES, + hdrs = ICU_STUBDATA_HEADERS, + copts = _COPTS, + deps = [":common_headers"], + target_compatible_with = _WASIX, +) + +cc_library( + name = "common", + linkstatic = True, + srcs = ICU_COMMON_SOURCES, + local_defines = ["U_COMMON_IMPLEMENTATION"], + copts = _COPTS, + deps = [":common_headers", ":data_stub"], + target_compatible_with = _WASIX, +) + +cc_library( + name = "i18n_headers", + linkstatic = True, + hdrs = ICU_I18N_HEADERS, + includes = ["i18n"], + deps = [":common_headers"], + target_compatible_with = _WASIX, +) + +cc_library( + name = "i18n", + linkstatic = True, + srcs = ICU_I18N_SOURCES, + local_defines = ["U_I18N_IMPLEMENTATION"], + copts = _COPTS, + deps = [":common", ":i18n_headers"], + target_compatible_with = _WASIX, +) + +# Canonical frontend tools use a separate O2/no-LTO ICU closure: the pinned +# WASIX LLVM has failed on their large libpq/ICU ThinLTO links. Headers and data +# layout are shared; runtime and initdb retain the original release profile. +_TOOLS_COPTS = [option for option in _COPTS if option != "-flto=thin"] +cc_library( + name = "data_stub_tools", + linkstatic = True, + srcs = ICU_STUBDATA_SOURCES, + hdrs = ICU_STUBDATA_HEADERS, + copts = _TOOLS_COPTS, + deps = [":common_headers"], + target_compatible_with = _WASIX, +) +cc_library( + name = "common_tools", + linkstatic = True, + srcs = ICU_COMMON_SOURCES, + local_defines = ["U_COMMON_IMPLEMENTATION"], + copts = _TOOLS_COPTS, + deps = [":common_headers", ":data_stub_tools"], + target_compatible_with = _WASIX, +) +cc_library( + name = "i18n_tools", + linkstatic = True, + srcs = ICU_I18N_SOURCES, + local_defines = ["U_I18N_IMPLEMENTATION"], + copts = _TOOLS_COPTS, + deps = [":common_tools", ":i18n_headers"], + target_compatible_with = _WASIX, +) diff --git a/build_defs/wasix/llvm-sys-declared-prefix.patch b/build_defs/wasix/llvm-sys-declared-prefix.patch new file mode 100644 index 000000000..0a55ce3f0 --- /dev/null +++ b/build_defs/wasix/llvm-sys-declared-prefix.patch @@ -0,0 +1,42 @@ +--- a/build.rs ++++ b/build.rs +@@ -256,6 +256,23 @@ + let stdout = String::from_utf8(stdout).context("stdout")?; + let stderr = String::from_utf8(stderr).context("stderr")?; + if status.success() { ++ // llvm-config resolves symlinks to its installed prefix. Preserve the ++ // explicit caller prefix so declared sandbox paths remain relocatable. ++ let stdout = if let Some(prefix) = env::var_os(&*ENV_LLVM_PREFIX) { ++ let prefix = prefix.to_str().context("LLVM prefix is not UTF-8")?; ++ let reported = Command::new(binary).arg("--prefix").output()?; ++ anyhow::ensure!( ++ reported.status.success(), ++ "llvm-config --prefix failed: {}", ++ String::from_utf8_lossy(&reported.stderr) ++ ); ++ let reported = String::from_utf8(reported.stdout).context("LLVM reported prefix")?; ++ let reported = reported.trim(); ++ anyhow::ensure!(!reported.is_empty(), "llvm-config reported an empty prefix"); ++ stdout.replace(reported, prefix) ++ } else { ++ stdout ++ }; + Ok(stdout) + } else { + Err(anyhow::anyhow!( +@@ -718,7 +735,14 @@ + + // Build the extra wrapper functions. + if !cfg!(feature = "disable-alltargets-init") { +- std::env::set_var("CFLAGS", get_llvm_cflags(&llvm_config_path)); ++ // LLVM include paths and macros must retain the selected C toolchain ++ // target and SDK flags. Caller flags take precedence over LLVM flags. ++ let cflags = format!( ++ "{} {}", ++ get_llvm_cflags(&llvm_config_path), ++ env::var("CFLAGS").unwrap_or_default() ++ ); ++ std::env::set_var("CFLAGS", cflags); + cc::Build::new() + .file("wrappers/target.c") + .compile("targetwrappers"); diff --git a/build_defs/wasix/llvm.bzl b/build_defs/wasix/llvm.bzl new file mode 100644 index 000000000..2e4acf156 --- /dev/null +++ b/build_defs/wasix/llvm.bzl @@ -0,0 +1,48 @@ +"""Expose only the current execution platform's canonical Wasmer LLVM files.""" + +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") + +def _exec_files_impl(ctx): + return [DefaultInfo(files = depset(ctx.files.srcs), runfiles = ctx.runfiles(files = ctx.files.srcs))] + +exec_files = rule( + implementation = _exec_files_impl, + attrs = {"srcs": attr.label_list(allow_files = True, cfg = "exec", mandatory = True)}, +) + +def _helper_runtime_impl(ctx): + files = ctx.files.libraries + names = {file.basename: True for file in files} + if "libstdc++.so.6" not in names or "libgcc_s.so.1" not in names: + fail("LLVM helper runtime requires declared GNU C++ and unwind SONAME files") + directories = sorted({file.dirname: True for file in files}.keys()) + environment = ctx.actions.declare_file(ctx.label.name + ".env") + ctx.actions.write(environment, "LD_LIBRARY_PATH=" + ":".join(["${pwd}/" + directory for directory in directories]) + "\n") + return [ + DefaultInfo(files = depset([environment])), + OutputGroupInfo(runtime_files = depset(files)), + ] + +llvm_helper_runtime = rule( + implementation = _helper_runtime_impl, + attrs = {"libraries": attr.label_list(allow_files = True, cfg = "exec", mandatory = True)}, +) + +# LLVM22 runs on glibc 2.34; its XML dependency can retain the qualified lower +# native ABI floor without expanding the published extension profiles. +def _arm64_libxml2_configuration(_settings, _attr): + return {"//command_line_option:platforms": [str(Label("//build_defs/native:linux_aarch64_glibc_2_28"))]} + +_ARM64_LIBXML2_CONFIGURATION = transition(implementation = _arm64_libxml2_configuration, inputs = [], outputs = ["//command_line_option:platforms"]) + +def _arm64_libxml2_impl(ctx): + library = ctx.attr._library[0] + return [library[DefaultInfo], library[CcInfo]] + +llvm_libxml2_arm64 = rule( + implementation = _arm64_libxml2_impl, + attrs = { + "_library": attr.label(default = "//build_defs/extensions/postgis:libxml2", providers = [CcInfo], cfg = _ARM64_LIBXML2_CONFIGURATION), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), + }, +) diff --git a/build_defs/wasix/napi-consumer.mts b/build_defs/wasix/napi-consumer.mts new file mode 100644 index 000000000..6fcd2c27f --- /dev/null +++ b/build_defs/wasix/napi-consumer.mts @@ -0,0 +1,193 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { readFileSync } from 'node:fs'; +import { createRequire } from 'node:module'; +import path from 'node:path'; +import { + connect, + onceClosed, + onceConnected, + readExchange, + simpleQuery, + startupPacket, +} from '../../src/wasix/sdks/ts/tools/pgwire-client.mts'; + +const [packageName, lifecycleFile] = process.argv.slice(2); +const require = createRequire(path.join(process.cwd(), 'consumer-package.json')); +const manifest = require(`${packageName}/package.json`); +const binary = require.resolve(`${packageName}/oliphaunt_wasix_napi.node`); +const addon = require(binary); +const provenance = require(`${packageName}/artifact-provenance.json`); +assert.equal(provenance.schema, 'oliphaunt-wasix-napi-construction-data-v3'); +assert(!Object.hasOwn(provenance, 'scope')); +assert(!Object.hasOwn(manifest.oliphaunt, 'qualificationOnly')); +assert.equal( + createHash('sha256').update(readFileSync(binary)).digest('hex'), + provenance.binary.sha256, +); +assert.equal(addon.addonAbiVersion(), manifest.oliphaunt.addonAbiVersion); +assert.equal(addon.nodeApiVersion(), manifest.oliphaunt.nodeApiVersion); +assert.equal(addon.runtimeVersion(), manifest.oliphaunt.runtimeVersion); +assert.deepEqual(addon.supportedProfiles(), ['standard', 'icu']); +const identity = ({ sha256, size }) => `${sha256}:${size}`; +assert.equal( + addon.payloadIdentity('runtimeArchive'), + identity(provenance.buildInputs.inputs.runtimeArchive), +); +const extensions = provenance.buildInputs.inputs.extensionArtifacts[0].portableArchives; +for (const row of extensions) + assert.equal( + addon.extensionIdentity(row.sqlName), + identity(row), + `compiled extension differs: ${row.sqlName}`, + ); +assert.throws(() => addon.extensionIdentity('unselected-extension')); +const { lifecycles } = JSON.parse(readFileSync(lifecycleFile, 'utf8')); +assert.deepEqual( + lifecycles.map((row) => row.sqlName).sort(), + extensions.map((row) => row.sqlName).sort(), +); + +function exchange(bytes: Uint8Array) { + const rows = [] as string[][]; + let ready = false; + for (let offset = 0; offset < bytes.length; ) { + assert(offset + 5 <= bytes.length, 'truncated PostgreSQL frame'); + const tag = String.fromCharCode(bytes[offset]); + const data = Buffer.from( + bytes.buffer, + bytes.byteOffset + offset + 5, + bytes.length - offset - 5, + ); + const length = new DataView(bytes.buffer, bytes.byteOffset + offset + 1, 4).getUint32(0); + assert(length >= 4 && offset + length + 1 <= bytes.length, 'invalid PostgreSQL frame length'); + assert.notEqual( + tag, + 'E', + `PostgreSQL ErrorResponse: ${data.subarray(0, length - 4).toString()}`, + ); + if (tag === 'D') { + const row = [] as string[]; + for (let count = data.readUInt16BE(0), field = 2; count > 0; count--) { + const size = data.readInt32BE(field); + field += 4; + row.push(size < 0 ? '' : data.subarray(field, field + size).toString()); + if (size >= 0) field += size; + } + rows.push(row); + } + if (tag === 'Z') ready = true; + offset += length + 1; + } + assert(ready, 'PostgreSQL response omitted ReadyForQuery'); + return rows; +} + +const options = { + profile: 'standard', + storage: { kind: 'memory' }, + username: 'postgres', + database: 'postgres', + startupGucs: {}, + extensions: extensions.map((row) => row.sqlName), +}; +const direct = addon.NativeWasixDatabase.open(options); +let backup: Uint8Array; +try { + assert.deepEqual(exchange(direct.execProtocolRaw(simpleQuery('SELECT 42::text'))), [['42']]); + const created = new Set(); + const pending = new Map(lifecycles.map((row) => [row.sqlName, row])); + while (pending.size) { + const ready = [...pending.values()].filter((row: any) => + row.dependencies.every((name) => !pending.has(name)), + ); + assert(ready.length, 'canonical extension lifecycle contains a dependency cycle'); + for (const row of ready as any[]) { + if (row.create) { + const schema = row.schema ? ` WITH SCHEMA "${row.schema}"` : ''; + exchange(direct.execProtocolRaw(simpleQuery(`CREATE EXTENSION "${row.sqlName}"${schema}`))); + created.add(row.sqlName); + } + for (const sql of row.loadSql) exchange(direct.execProtocolRaw(simpleQuery(sql))); + for (const sql of row.postCreateSql) exchange(direct.execProtocolRaw(simpleQuery(sql))); + pending.delete(row.sqlName); + } + } + const installed = exchange( + direct.execProtocolRaw( + simpleQuery("SELECT extname FROM pg_extension WHERE extname <> 'plpgsql' ORDER BY extname"), + ), + ).map(([name]) => name); + assert.deepEqual(installed, [...created].sort()); + exchange( + direct.execProtocolRaw( + simpleQuery( + "CREATE TABLE carrier_roundtrip(value text); INSERT INTO carrier_roundtrip VALUES ('persisted')", + ), + ), + ); + const chunks: Uint8Array[] = []; + assert.equal( + direct.execProtocolRawStream( + simpleQuery('SELECT value FROM carrier_roundtrip'), + (chunk: Uint8Array) => chunks.push(chunk), + ), + 'complete', + ); + assert.deepEqual(exchange(Buffer.concat(chunks.map((chunk) => Buffer.from(chunk)))), [ + ['persisted'], + ]); + backup = direct.backup(); + assert(backup.byteLength > 0, 'physical backup is empty'); +} finally { + direct.close(); +} +assert(direct.closed); + +const actor = await addon.NativeWasixActorDatabase.open(options); +try { + assert.deepEqual(exchange(await actor.execProtocolRaw(simpleQuery('SELECT 42::text'))), [['42']]); +} finally { + await actor.close(); +} +assert(actor.closed); + +const server = await addon.NativeWasixServer.open({ ...options, listen: { transport: 'tcp' } }); +const socket = connect(server.connectionString); +try { + await onceConnected(socket); + const startup = readExchange(socket); + socket.write(startupPacket('postgres', 'postgres')); + await startup; + const query = readExchange(socket); + const chunks: Buffer[] = []; + const capture = (chunk: Buffer) => chunks.push(Buffer.from(chunk)); + socket.on('data', capture); + try { + socket.write(simpleQuery('SELECT 42::text')); + await query; + assert.deepEqual(exchange(Buffer.concat(chunks)), [['42']]); + } finally { + socket.off('data', capture); + } +} finally { + socket.end(); + await onceClosed(socket); + await server.close(); +} +assert(server.closed); +const storage = { kind: 'directory', path: path.join(process.cwd(), 'restored-database') }; +assert(backup, 'physical backup was not produced'); +addon.restoreDirect(storage.path, backup); +const restored = addon.NativeWasixDatabase.open({ ...options, storage }); +try { + assert.deepEqual( + exchange(restored.execProtocolRaw(simpleQuery('SELECT value FROM carrier_roundtrip'))), + [['persisted']], + ); +} finally { + restored.close(); +} +console.log( + `Installed native WASIX addon: exact runtime + ${extensions.length} contrib identities/lifecycles; direct/actor/server SQL + stream + backup restore: PASS`, +); diff --git a/build_defs/wasix/napi-inputs.mts b/build_defs/wasix/napi-inputs.mts new file mode 100644 index 000000000..ad1e8c56e --- /dev/null +++ b/build_defs/wasix/napi-inputs.mts @@ -0,0 +1,289 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { mkdirSync, readFileSync, realpathSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { assertCanonicalWasixAotManifest } from '../../src/wasix/runtime/tools/wasix-aot-manifest.mts'; +import { + AOT_PACKAGES, + AOT_TARGET_CFGS, + AOT_TARGET_TRIPLES, + CORE_AOT_ARTIFACTS, + wasixExtensionAotPackageName, + wasixExtensionPackageName, +} from '../../src/wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; +import { cargoSatisfies } from '../../tools/packaging/cargo-manifest.mts'; +import { readPortableArchiveEntries } from '../../tools/packaging/portable-archive.mts'; +import { copyNativeInputFile, safeRelative } from '../../tools/release/native-file-identity.mts'; + +export type WasixNapiInputsSpec = { + target: string; + targetTriple: string; + sdkManifest: string; + runtimeVersion: string; + sdkVersion: string; + sqlNames: string[]; + portableArchive: string; + coreAotArchive: string; + contribFrozen: string; + contribPortable: string; + contribAot: string; + output: string; +}; +type FileIdentity = { path: string; sha256: string; size: number }; +const PRODUCT = 'oliphaunt-extension-contrib-pg18'; +const sha256 = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +const comparePath = (a: FileIdentity, b: FileIdentity) => + a.path < b.path ? -1 : a.path > b.path ? 1 : 0; + +/** Stage current source Cargo inputs and the exact qualified payloads its build scripts consume. */ +export function stageWasixNapiInputs(spec: WasixNapiInputsSpec) { + assert.equal( + AOT_TARGET_TRIPLES[spec.target], + spec.targetTriple, + 'unsupported WASIX addon target', + ); + assert(AOT_PACKAGES[spec.target], 'unsupported WASIX addon target'); + for (const version of [spec.runtimeVersion, spec.sdkVersion]) + assert.match( + version, + /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/u, + 'source version must be exact', + ); + const names = [...spec.sqlNames].sort(); + assert(names.length > 0, 'WASIX release requires its declared contrib members'); + assert.equal(new Set(names).size, names.length, 'duplicate release contrib member'); + assert( + names.every((name) => /^[a-z0-9][a-z0-9_-]*$/u.test(name)), + 'invalid contrib SQL name', + ); + const files = new Map(); + const remember = (member: string, identity: { sha256: string; size: number }) => { + safeRelative(member); + assert(!files.has(member), `duplicate WASIX construction file ${member}`); + assert(identity.size > 0, `empty WASIX construction file ${member}`); + const record = { path: member, sha256: identity.sha256, size: identity.size }; + files.set(member, record); + return record; + }; + const copy = (input: string, member: string) => { + safeRelative(member); + const absolute = path.resolve(input); + const root = path.parse(absolute).root; + return remember( + member, + copyNativeInputFile( + root, + path.relative(root, absolute).split(path.sep).join('/'), + path.join(spec.output, member), + ), + ); + }; + const write = (member: string, bytes: Uint8Array) => { + safeRelative(member); + assert(!files.has(member), `duplicate WASIX construction file ${member}`); + mkdirSync(path.dirname(path.join(spec.output, member)), { recursive: true }); + writeFileSync(path.join(spec.output, member), bytes, { flag: 'wx', mode: 0o644 }); + return remember(member, { sha256: sha256(bytes), size: bytes.length }); + }; + const json = (record: FileIdentity) => + JSON.parse(readFileSync(path.join(spec.output, record.path), 'utf8')); + const sdk = Bun.TOML.parse(readFileSync(spec.sdkManifest, 'utf8')); + assert.equal(sdk.package?.name, 'oliphaunt-wasix', 'source SDK package name differs'); + assert.equal(sdk.package.version, spec.sdkVersion, 'source SDK version differs'); + for (const [dependency, relative] of [ + [sdk.dependencies?.['liboliphaunt-wasix-portable'], '../../runtime/crates/assets'], + [ + sdk.target?.[AOT_TARGET_CFGS[spec.targetTriple]]?.dependencies?.[AOT_PACKAGES[spec.target]], + `../../runtime/crates/aot/${spec.targetTriple}`, + ], + ] as const) { + assert.equal(typeof dependency?.path, 'string', 'source SDK requires its local runtime path'); + assert.equal( + path.resolve(path.dirname(spec.sdkManifest), dependency.path), + path.resolve(path.dirname(spec.sdkManifest), relative), + 'source SDK runtime path differs', + ); + assert( + typeof dependency.version === 'string' && + cargoSatisfies(spec.runtimeVersion, dependency.version), + 'source SDK runtime requirement excludes the constructed core', + ); + } + const crate = (archive: string, name: string) => { + const entries = readPortableArchiveEntries(realpathSync(archive), { format: 'tar.gz' }); + const root = `${name}-${spec.runtimeVersion}`; + const member = (relative: string) => { + safeRelative(relative); + const entry = entries.get(`${root}/${relative}`); + assert( + entry?.isFile && !entry.isSymbolicLink && entry.size > 0, + `missing regular Cargo payload ${name}/${relative}`, + ); + return Buffer.from(entry.data()); + }; + const manifests = [...entries.values()].filter((entry) => + /^[^/]+\/Cargo\.toml$/u.test(entry.name), + ); + assert.equal(manifests.length, 1, 'Cargo input must contain one canonical root manifest'); + const manifest = Bun.TOML.parse(member('Cargo.toml').toString('utf8')); + assert.equal(manifest.package?.name, name, 'constructed Cargo package name differs'); + assert.equal( + manifest.package.version, + spec.runtimeVersion, + 'constructed Cargo version differs', + ); + assert( + !Object.hasOwn(manifest.package.metadata?.oliphaunt ?? {}, 'qualificationOnly'), + 'WASIX payload is a qualification package', + ); + return member; + }; + const portable = crate(spec.portableArchive, 'liboliphaunt-wasix-portable'); + const portableManifest = write('portable/manifest.json', portable('payload/manifest.json')); + const portableValue = json(portableManifest); + assert.equal(portableValue['format-version'], 2, 'portable manifest format differs'); + assert.equal(typeof portableValue['source-fingerprint'], 'string'); + assert(portableValue['source-fingerprint'].length > 0, 'portable source fingerprint is empty'); + assert.equal(portableValue.runtime.archive, 'oliphaunt.wasix.tar.zst'); + const runtimeArchive = write( + 'portable/oliphaunt.wasix.tar.zst', + portable('payload/oliphaunt.wasix.tar.zst'), + ); + assert.equal( + runtimeArchive.sha256, + portableValue.runtime.sha256, + 'portable runtime hash differs', + ); + if (portableValue.runtime.size !== undefined) + assert.equal(runtimeArchive.size, portableValue.runtime.size, 'portable runtime size differs'); + write('portable/bin/initdb.wasix.wasm', portable('payload/bin/initdb.wasix.wasm')); + const aot = ( + manifest: FileIdentity, + member: (relative: string) => Buffer, + expectedModules: Map, + payloadRoot: string, + archiveRoot: string, + ) => { + const value = json(manifest); + assertCanonicalWasixAotManifest(value, { + context: manifest.path, + expectedTarget: spec.targetTriple, + }); + assert.equal( + value['source-fingerprint'], + portableValue['source-fingerprint'], + 'AOT and portable source fingerprints differ', + ); + assert(Array.isArray(value.artifacts) && value.artifacts.length > 0, 'AOT manifest is empty'); + const actualNames = value.artifacts.map((artifact: any) => { + assert(expectedModules.has(artifact.name), 'AOT manifest includes a foreign artifact'); + const relative = safeRelative(artifact.path); + const payload = write(`${payloadRoot}/${relative}`, member(`${archiveRoot}/${relative}`)); + assert.equal(payload.sha256, artifact.sha256, 'AOT payload hash differs from manifest'); + const moduleSha = expectedModules.get(artifact.name); + if (moduleSha !== undefined) + assert.equal(artifact['module-sha256'], moduleSha, 'AOT portable module identity differs'); + return artifact.name; + }); + assert.deepEqual( + [...actualNames].sort(), + [...expectedModules.keys()].sort(), + 'AOT inventory differs', + ); + }; + const core = crate(spec.coreAotArchive, AOT_PACKAGES[spec.target]); + const aotRoot = `aot/${spec.targetTriple}`; + const runtimeAotManifest = write(`${aotRoot}/manifest.json`, core('artifacts/manifest.json')); + aot( + runtimeAotManifest, + core, + new Map(CORE_AOT_ARTIFACTS.map((name) => [name, undefined])), + aotRoot, + 'artifacts', + ); + const productRoot = `extensions/${PRODUCT}`; + const frozen = json(copy(spec.contribFrozen, `${productRoot}/extension-artifacts.json`)); + assert.equal( + frozen.schema, + 'oliphaunt-extension-ci-artifacts-v2', + 'contrib metadata must be a bundle', + ); + assert.equal(frozen.product, PRODUCT, 'contrib metadata product differs'); + assert.equal(frozen.version, spec.runtimeVersion, 'contrib version differs from runtime owner'); + assert.equal(frozen.compatibility?.wasixRuntimeProduct, 'liboliphaunt-wasix'); + assert.equal(frozen.compatibility.wasixRuntimeVersion, spec.runtimeVersion); + assert(Array.isArray(frozen.extensions), 'contrib metadata has no member inventory'); + const members = new Map(); + for (const member of frozen.extensions) { + assert(!members.has(member.sqlName), 'contrib metadata repeats a member'); + members.set(member.sqlName, member); + } + const contribPortable = crate(spec.contribPortable, wasixExtensionPackageName(PRODUCT)); + const contribAot = crate( + spec.contribAot, + wasixExtensionAotPackageName(PRODUCT, spec.targetTriple), + ); + const portableArchives = []; + const aotManifests = []; + for (const sqlName of names) { + const member = members.get(sqlName); + assert(member, `contrib metadata is missing ${sqlName}`); + const assets = member.assets.filter((asset: any) => asset.target === 'wasix-portable'); + assert.equal(assets.length, 1, 'contrib member requires one portable asset'); + const archive = write( + `${productRoot}/member-assets/${sqlName}/${PRODUCT}-${spec.runtimeVersion}-wasix-portable.tar.zst`, + contribPortable(`payload/files/extensions/${sqlName}/extension.tar.zst`), + ); + assert.equal(archive.sha256, assets[0].sha256, 'contrib portable payload hash differs'); + assert.equal(archive.size, assets[0].bytes, 'contrib portable payload size differs'); + portableArchives.push({ sqlName, ...archive }); + const root = `${productRoot}/wasix-aot/${spec.target}/${sqlName}`; + const manifest = write(`${root}/manifest.json`, contribAot(`manifests/${sqlName}.json`)); + const modules = member.wasixInstall?.nativeModules; + assert(Array.isArray(modules) && modules.length > 0, 'selected contrib member has no modules'); + const expected = new Map( + modules.map((module: any) => { + assert.match(module.moduleSha256, /^[0-9a-f]{64}$/u, 'contrib module has no SHA-256'); + return [ + `extension:${sqlName}${module.name === sqlName ? '' : `:${module.name}`}`, + module.moduleSha256, + ]; + }), + ); + assert.equal(expected.size, modules.length, 'contrib metadata repeats a native module'); + aot(manifest, contribAot, expected, root, `payload/files/extensions/${sqlName}`); + aotManifests.push({ sqlName, targetTriple: spec.targetTriple, ...manifest }); + } + const layout = { + runtimeVersion: spec.runtimeVersion, + portableRoot: 'portable', + aotRoot, + extensionRoot: 'extensions', + }; + write('layout.json', Buffer.from(`${JSON.stringify(layout, null, 2)}\n`)); + const inventory = { + schema: 'oliphaunt-wasix-napi-build-inputs-v3', + target: spec.target, + targetTriple: spec.targetTriple, + runtimeVersion: spec.runtimeVersion, + sdk: { name: 'oliphaunt-wasix', version: spec.sdkVersion }, + files: [...files.values()].sort(comparePath), + inputs: { + portableManifest, + runtimeArchive, + runtimeAotManifest: { targetTriple: spec.targetTriple, ...runtimeAotManifest }, + extensionArtifacts: [{ product: PRODUCT, portableArchives, aotManifests }], + }, + }; + writeFileSync( + path.join(spec.output, 'build-inputs.json'), + `${JSON.stringify(inventory, null, 2)}\n`, + { flag: 'wx', mode: 0o644 }, + ); + return { inventory, ...layout }; +} + +if (import.meta.main) { + const [spec] = process.argv.slice(2); + stageWasixNapiInputs(JSON.parse(readFileSync(spec, 'utf8'))); +} diff --git a/build_defs/wasix/napi-inputs.test.mts b/build_defs/wasix/napi-inputs.test.mts new file mode 100644 index 000000000..f7ccccb74 --- /dev/null +++ b/build_defs/wasix/napi-inputs.test.mts @@ -0,0 +1,806 @@ +import { test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + lstatSync, + mkdirSync, + mkdtempSync, + readFileSync, + readdirSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { assertWasixNapiConstructionData } from '../../src/wasix/node-addon/tools/carrier-contract.mts'; +import { canonicalWasixAotMetadata } from '../../src/wasix/runtime/tools/wasix-aot-manifest.mts'; +import { + AOT_PACKAGES, + AOT_TARGET_CFGS, + AOT_TARGET_TRIPLES, + CORE_AOT_ARTIFACTS, + wasixExtensionAotPackageName, + wasixExtensionPackageName, +} from '../../src/wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; +import { tarHeader } from '../../tools/packaging/archive-directory.mts'; +import { + canonicalGzipSync, + readPortableArchiveEntries, + releaseZstdCompressSync, +} from '../../tools/packaging/portable-archive.mts'; +import { + elfFixture, + machoFixture, + windowsPeFixture, +} from '../../tools/packaging/testdata/release-fixture-utils.mts'; +import { + WINDOWS_VC_RUNTIME_RECEIPT, + windowsVcRuntimeProfileNames, +} from '../../tools/packaging/windows-vc-runtime-closure.mts'; +import { packageNativeWasixNapi } from './napi.mts'; +import { stageWasixNapiInputs, type WasixNapiInputsSpec } from './napi-inputs.mts'; + +const PRODUCT = 'oliphaunt-extension-contrib-pg18'; +const digest = (bytes: string | Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +function tar(files: Record) { + return Buffer.concat([ + ...Object.entries(files) + .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)) + .flatMap(([name, bytes]) => [ + tarHeader({ name, isDirectory: false }, bytes.length, 0o644), + bytes, + Buffer.alloc((512 - (bytes.length % 512)) % 512), + ]), + Buffer.alloc(1024), + ]); +} +function releaseSqlNames() { + const catalog = JSON.parse( + readFileSync('src/extensions/generated/extensions.catalog.json', 'utf8'), + ).extensions; + const release = Bun.TOML.parse(readFileSync('src/wasix/node-addon/Cargo.toml', 'utf8')).features + .release; + const names = release + .filter((feature: string) => feature.startsWith('extension-')) + .map((feature: string) => { + const matches = catalog.filter( + (row: any) => `extension-${row['sql-name'].replaceAll('_', '-')}` === feature, + ); + assert.equal(matches.length, 1); + return matches[0]['sql-name']; + }); + assert.equal(names.length, 32); + return names.sort(); +} +function fixture( + root: string, + target = 'linux-x64-gnu', + sqlNames = releaseSqlNames(), + sdkVersion = '0.3.2', + runtimeVersion = '0.3.2', +): WasixNapiInputsSpec { + const targetTriple = AOT_TARGET_TRIPLES[target]; + const input = path.join(root, 'inputs'); + mkdirSync(input, { recursive: true }); + const write = (name: string, bytes: Uint8Array | string) => { + const file = path.join(input, name); + writeFileSync(file, bytes); + return file; + }; + const crate = (name: string, files: Record) => + write( + `${name}-${runtimeVersion}.crate`, + canonicalGzipSync( + tar( + Object.fromEntries( + Object.entries({ + 'Cargo.toml': Buffer.from( + `[package]\nname=${JSON.stringify(name)}\nversion=${JSON.stringify(runtimeVersion)}\n`, + ), + ...files, + }).map(([member, bytes]) => [`${name}-${runtimeVersion}/${member}`, bytes]), + ), + ), + ), + ); + const fingerprint = 'current source-qualified fixture'; + const canonical = canonicalWasixAotMetadata(); + const manifest = (artifacts: any[]) => + Buffer.from( + JSON.stringify({ + 'format-version': 1, + 'source-lane': canonical.sourceLane, + engine: canonical.engine, + 'wasmer-version': canonical.wasmerVersion, + 'wasmer-wasix-version': canonical.wasmerWasixVersion, + 'target-triple': targetTriple, + 'source-fingerprint': fingerprint, + artifacts, + }), + ); + const wasm = Buffer.from([0, 97, 115, 109, 1, 0, 0, 0]); + const runtime = releaseZstdCompressSync( + tar({ + 'oliphaunt/bin/postgres': wasm, + 'oliphaunt/bin/initdb': wasm, + }), + ); + const portableArchive = crate('liboliphaunt-wasix-portable', { + 'payload/manifest.json': Buffer.from( + JSON.stringify({ + 'format-version': 2, + 'source-fingerprint': fingerprint, + extensions: [], + runtime: { + archive: 'oliphaunt.wasix.tar.zst', + sha256: digest(runtime), + size: runtime.length, + 'module-sha256': digest(wasm), + }, + }), + ), + 'payload/oliphaunt.wasix.tar.zst': runtime, + 'payload/bin/initdb.wasix.wasm': wasm, + }); + const artifact = (name: string, member: string, raw: Buffer, moduleSha = digest(wasm)) => { + const bytes = releaseZstdCompressSync(raw); + return { + bytes, + row: { + name, + path: member, + sha256: digest(bytes), + 'raw-sha256': digest(raw), + 'raw-size': raw.length, + 'module-sha256': moduleSha, + compressed: true, + }, + }; + }; + const core = CORE_AOT_ARTIFACTS.map((name, i) => + artifact(name, `core-${i}-llvm-opta.bin.zst`, Buffer.from(`current core ${name}`)), + ); + const coreAotArchive = crate(AOT_PACKAGES[target], { + 'artifacts/manifest.json': manifest(core.map(({ row }) => row)), + ...Object.fromEntries(core.map(({ row, bytes }) => [`artifacts/${row.path}`, bytes])), + }); + const portableFiles: Record = {}; + const aotFiles: Record = {}; + const extensions = sqlNames.map((sqlName, i) => { + const moduleNames = i === 0 ? [sqlName, `${sqlName}_helper`] : [sqlName]; + const nativeModules = moduleNames.map((name) => ({ + name, + moduleSha256: digest(`portable module ${name}`), + })); + const portable = releaseZstdCompressSync( + tar({ + [`share/postgresql/extension/${sqlName}.control`]: Buffer.from("default_version = '1.0'\n"), + ...Object.fromEntries(moduleNames.map((name) => [`lib/postgresql/${name}.so`, wasm])), + }), + ); + portableFiles[`payload/files/extensions/${sqlName}/extension.tar.zst`] = portable; + const artifacts = nativeModules.map(({ name, moduleSha256 }) => + artifact( + `extension:${sqlName}${name === sqlName ? '' : `:${name}`}`, + `${name}-llvm-opta.bin.zst`, + Buffer.from(`current extension ${name}`), + moduleSha256, + ), + ); + aotFiles[`manifests/${sqlName}.json`] = manifest(artifacts.map(({ row }) => row)); + for (const { row, bytes } of artifacts) + aotFiles[`payload/files/extensions/${sqlName}/${row.path}`] = bytes; + return { + sqlName, + nativeModuleStem: sqlName, + wasixInstall: { nativeModules }, + assets: [ + { + name: `${PRODUCT}-${runtimeVersion}-${sqlName}-wasix-portable.tar.zst`, + target: 'wasix-portable', + family: 'wasix', + kind: 'wasix-runtime', + sha256: digest(portable), + bytes: portable.length, + }, + ], + }; + }); + return { + target, + targetTriple, + runtimeVersion, + sdkVersion, + sqlNames, + portableArchive, + coreAotArchive, + contribPortable: crate(wasixExtensionPackageName(PRODUCT), portableFiles), + contribAot: crate(wasixExtensionAotPackageName(PRODUCT, targetTriple), aotFiles), + contribFrozen: write( + 'extension-artifacts.json', + JSON.stringify({ + schema: 'oliphaunt-extension-ci-artifacts-v2', + product: PRODUCT, + version: runtimeVersion, + compatibility: { + wasixRuntimeProduct: 'liboliphaunt-wasix', + wasixRuntimeVersion: runtimeVersion, + }, + extensions, + }), + ), + sdkManifest: write( + 'sdk-Cargo.toml', + `[package]\nname="oliphaunt-wasix"\nversion=${JSON.stringify(sdkVersion)}\n[package.metadata.oliphaunt]\nruntime-version="0.3.2"\n[dependencies]\nliboliphaunt-wasix-portable = { version = "*", path = "../../runtime/crates/assets" }\n[target.${JSON.stringify(AOT_TARGET_CFGS[targetTriple])}.dependencies]\n${AOT_PACKAGES[target]} = { version = "*", path = "../../runtime/crates/aot/${targetTriple}" }\n`, + ), + output: path.join(root, 'output'), + }; +} +function rewriteCrate(file: string, change: (files: Record) => void) { + const files = Object.fromEntries( + [...readPortableArchiveEntries(file)] + .filter(([, entry]) => entry.isFile) + .map(([name, entry]) => [name, Buffer.from(entry.data())]), + ); + change(files); + writeFileSync(file, canonicalGzipSync(tar(files))); +} +function rewriteJson(files: Record, suffix: string, change: (value: any) => void) { + const member = Object.keys(files).find((name) => name.endsWith(suffix)); + assert(member, `fixture missing ${suffix}`); + const value = JSON.parse(files[member].toString()); + change(value); + files[member] = Buffer.from(JSON.stringify(value)); +} +function physicalFiles(root: string, prefix = ''): string[] { + return readdirSync(root, { withFileTypes: true }) + .flatMap((entry) => { + const relative = prefix + entry.name; + const file = path.join(root, entry.name); + if (entry.isDirectory()) return physicalFiles(file, `${relative}/`); + assert(lstatSync(file).isFile() && !lstatSync(file).isSymbolicLink()); + return [relative]; + }) + .sort(); +} + +test('current source Cargo, complete contrib and canonical carriers bind exactly on all supported hosts', async () => { + for (const target of Object.keys(AOT_TARGET_TRIPLES)) { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-napi-source-')); + try { + const spec = fixture(root, target); + const actual = stageWasixNapiInputs(spec); + assert.equal(actual.runtimeVersion, spec.runtimeVersion); + assert.equal(actual.inventory.schema, 'oliphaunt-wasix-napi-build-inputs-v3'); + assert.deepEqual(actual.inventory.sdk, { name: 'oliphaunt-wasix', version: spec.sdkVersion }); + assert.equal(actual.inventory.inputs.extensionArtifacts[0].portableArchives.length, 32); + assert.equal(actual.inventory.inputs.extensionArtifacts[0].aotManifests.length, 32); + assert(!Object.hasOwn(actual.inventory, 'dependencies')); + assert(!Object.hasOwn(actual.inventory, 'sourcePatch')); + assert(!Object.hasOwn(actual.inventory, 'cargoLock')); + assert(!actual.inventory.files.some((row) => row.path === 'Cargo.lock')); + assert(!actual.inventory.files.some((row) => row.path === 'src/wasix/sdks/rust/Cargo.toml')); + assert.deepEqual( + physicalFiles(spec.output).filter((name) => name !== 'build-inputs.json'), + actual.inventory.files.map((row) => row.path), + ); + for (const row of actual.inventory.files) { + const bytes = readFileSync(path.join(spec.output, row.path)); + assert.equal(bytes.length, row.size); + assert.equal(digest(bytes), row.sha256); + } + assert.deepEqual( + readFileSync(path.join(spec.output, `extensions/${PRODUCT}/extension-artifacts.json`)), + readFileSync(spec.contribFrozen), + ); + const binarySha = digest('independently compiled addon'); + const provenance = { + schema: 'oliphaunt-wasix-napi-construction-data-v3', + product: 'oliphaunt-wasix-napi', + target, + build: { + cargoProfile: 'release', + incremental: false, + codegenUnits: 1, + lto: 'thin', + strip: 'symbols', + features: ['release'], + targetTriple: spec.targetTriple, + }, + buildInputs: actual.inventory, + binary: { filename: 'oliphaunt_wasix_napi.node', sha256: binarySha }, + }; + const contract = { + targetTriple: spec.targetTriple, + sdkVersion: spec.sdkVersion, + runtimeVersion: actual.runtimeVersion, + sqlNames: spec.sqlNames, + }; + assertWasixNapiConstructionData(provenance, target, binarySha, contract); + for (const mutate of [ + (value: any) => { + value.sourceSha = 'a'.repeat(40); + }, + (value: any) => { + value.build.features = []; + }, + (value: any) => { + value.buildInputs.inputs.runtimeArchive.sha256 = '0'.repeat(64); + }, + (value: any) => { + value.buildInputs.files.push(value.buildInputs.files[0]); + }, + (value: any) => { + value.buildInputs.files.reverse(); + }, + (value: any) => { + value.buildInputs.sdk.version = '9.9.9'; + }, + (value: any) => { + value.buildInputs.runtimeVersion = '9.9.9'; + }, + (value: any) => { + value.buildInputs.inputs.extensionArtifacts[0].aotManifests.pop(); + }, + (value: any) => { + value.scope = 'release'; + }, + (value: any) => { + value.buildInputs.targetTriple = 'x86_64-unknown-other'; + value.build.targetTriple = value.buildInputs.targetTriple; + }, + (value: any) => { + value.buildInputs.inputs.extensionArtifacts[0].portableArchives.pop(); + value.buildInputs.inputs.extensionArtifacts[0].aotManifests.pop(); + }, + ]) { + const changed = JSON.parse(JSON.stringify(provenance)); + mutate(changed); + assert.throws(() => assertWasixNapiConstructionData(changed, target, binarySha, contract)); + } + const reverse = stageWasixNapiInputs({ + ...spec, + output: path.join(root, 'reverse'), + sqlNames: [...spec.sqlNames].reverse(), + }); + assert.deepEqual(reverse.inventory, actual.inventory); + const rootPackage = 'src/wasix/node-addon/package.json'; + const product = JSON.parse(readFileSync(rootPackage, 'utf8')); + const directory = + target === 'macos-arm64' + ? 'darwin-arm64' + : target === 'windows-x64-msvc' + ? 'win32-x64-msvc' + : target; + const manifestPath = `src/wasix/node-addon/packages/${directory}/package.json`; + const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')); + const binary = path.join(root, 'compiled.node'); + writeFileSync( + binary, + target === 'macos-arm64' + ? machoFixture() + : target === 'windows-x64-msvc' + ? windowsPeFixture({ imports: ['VCRUNTIME140.dll'] }) + : elfFixture({ machine: target === 'linux-arm64-gnu' ? 183 : 62 }), + ); + const windowsRuntime: Record = {}; + if (target === 'windows-x64-msvc') { + const bytes = windowsPeFixture(); + for (const member of windowsVcRuntimeProfileNames('provider')) { + const file = path.join(root, member); + writeFileSync(file, bytes); + windowsRuntime[member] = file; + } + assert(!Object.hasOwn(windowsRuntime, WINDOWS_VC_RUNTIME_RECEIPT)); + } + const outputs = await packageNativeWasixNapi({ + target: target as any, + version: product.version, + sdkVersion: contract.sdkVersion, + sqlNames: spec.sqlNames, + binary, + inputs: spec.output, + manifest: manifestPath, + productManifest: rootPackage, + readme: `src/wasix/node-addon/packages/${directory}/README.md`, + targetContract: { + triple: spec.targetTriple, + npm_package: manifest.name, + npm_os: manifest.os[0], + npm_cpu: manifest.cpu[0], + npm_libc: manifest.libc?.[0], + }, + windowsRuntime, + notices: Object.fromEntries( + [ + 'LICENSE', + 'THIRD_PARTY_NOTICES.md', + 'src/wasix/sdks/rust/THIRD_PARTY_NOTICES.md', + 'src/third-party/postgres/COPYRIGHT', + 'src/third-party/postgres/source.toml', + 'src/third-party/icu/LICENSE', + 'src/third-party/icu/source.toml', + 'src/third-party/openssl/LICENSE.txt', + 'src/third-party/openssl/source.toml', + ].map((file) => [file, file]), + ), + outputs: { + npm: path.join(root, 'addon.tgz'), + github: path.join(root, target === 'windows-x64-msvc' ? 'addon.zip' : 'addon.tar.gz'), + provenance: path.join(root, 'provenance.json'), + }, + }); + const npm = readPortableArchiveEntries(outputs.npm); + if (target === 'windows-x64-msvc') { + const dll = readFileSync(windowsRuntime['vcruntime140.dll']); + const receipt = `${digest(dll)} vcruntime140.dll\n`; + for (const [entries, prefix] of [ + [npm, 'package/prebuilds/'], + [readPortableArchiveEntries(outputs.github), ''], + ] as const) { + const runtime = entries.get(`${prefix}vcruntime140.dll`); + const manifest = entries.get(prefix + WINDOWS_VC_RUNTIME_RECEIPT); + assert(runtime?.isFile && !runtime.isSymbolicLink); + assert(manifest?.isFile && !manifest.isSymbolicLink); + assert.deepEqual(Buffer.from(runtime.data()), dll); + assert.equal(Buffer.from(manifest.data()).toString(), receipt); + assert(!entries.has(`${prefix}msvcp140.dll`)); + assert(!entries.has(`${prefix}vcruntime140_1.dll`)); + } + } + const published = JSON.parse( + Buffer.from(npm.get('package/artifact-provenance.json')!.data()).toString(), + ); + assert.deepEqual(published.buildInputs, actual.inventory); + assert(!Object.hasOwn(published, 'scope')); + assert( + !Object.hasOwn( + JSON.parse(Buffer.from(npm.get('package/package.json')!.data()).toString()).oliphaunt, + 'qualificationOnly', + ), + ); + assertWasixNapiConstructionData(published, target, digest(readFileSync(binary)), contract); + } finally { + rmSync(root, { recursive: true, force: true }); + } + } +}); + +test('one, several and all selected contrib members stage an exact source closure with independent SDK versions', () => { + for (const count of [1, 3, 32]) { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-napi-source-members-')); + try { + const spec = fixture(root, 'linux-x64-gnu', releaseSqlNames().slice(0, count), '0.9.1'); + const { inventory } = stageWasixNapiInputs(spec); + assert.equal(inventory.sdk.version, '0.9.1'); + assert.equal(inventory.runtimeVersion, '0.3.2'); + const extension = inventory.inputs.extensionArtifacts[0]; + assert.deepEqual( + extension.portableArchives.map((row) => row.sqlName), + spec.sqlNames, + ); + assert.deepEqual( + extension.aotManifests.map((row) => row.sqlName), + spec.sqlNames, + ); + for (const row of extension.portableArchives) + assert.equal( + row.path, + `extensions/${PRODUCT}/member-assets/${row.sqlName}/${PRODUCT}-${spec.runtimeVersion}-wasix-portable.tar.zst`, + ); + assert.equal( + inventory.files.filter((row) => row.path.includes('/wasix-aot/')).length, + count * 2 + 1, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } + } +}); + +test('a runtime-only release embeds the constructed core while the SDK public minimum stays held', () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-napi-runtime-only-')); + try { + const spec = fixture(root, 'linux-x64-gnu', releaseSqlNames().slice(0, 3), '0.3.2', '0.3.3'); + const sdk = Bun.TOML.parse(readFileSync(spec.sdkManifest, 'utf8')); + assert.equal(sdk.package.metadata.oliphaunt['runtime-version'], '0.3.2'); + const { inventory, runtimeVersion } = stageWasixNapiInputs(spec); + assert.equal(runtimeVersion, '0.3.3'); + assert.equal(inventory.runtimeVersion, '0.3.3'); + assert.equal(inventory.sdk.version, '0.3.2'); + const frozen = JSON.parse( + readFileSync( + path.join(spec.output, `extensions/${PRODUCT}/extension-artifacts.json`), + 'utf8', + ), + ); + assert.equal(frozen.version, '0.3.3'); + for (const row of inventory.files) { + const bytes = readFileSync(path.join(spec.output, row.path)); + assert.equal(bytes.length, row.size); + assert.equal(digest(bytes), row.sha256); + } + const extensions = inventory.inputs.extensionArtifacts[0]; + assert.equal(extensions.portableArchives.length, 3); + assert.equal(extensions.aotManifests.length, 3); + assert( + extensions.portableArchives.every((row) => + row.path.includes('-0.3.3-wasix-portable.tar.zst'), + ), + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('equivalent SDK manifest formatting and local paths do not alter staged payload identities', () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-napi-sdk-manifest-')); + try { + const spec = fixture(root, 'linux-x64-gnu', releaseSqlNames().slice(0, 3)); + const before = stageWasixNapiInputs(spec).inventory; + const original = readFileSync(spec.sdkManifest, 'utf8'); + writeFileSync( + spec.sdkManifest, + '# Source Cargo validation input\n\n' + + original + .replace('name="oliphaunt-wasix"', 'name = "oliphaunt-wasix"') + .replaceAll('../../runtime/crates/', '../../runtime/./crates/'), + ); + const output = path.join(root, 'after'); + const after = stageWasixNapiInputs({ ...spec, output }).inventory; + assert.deepEqual(after, before); + assert.deepEqual(after.sdk, { name: 'oliphaunt-wasix', version: spec.sdkVersion }); + const files = physicalFiles(spec.output); + assert.deepEqual(physicalFiles(output), files); + assert(!files.includes('src/wasix/sdks/rust/Cargo.toml')); + for (const file of files) + assert.deepEqual( + readFileSync(path.join(output, file)), + readFileSync(path.join(spec.output, file)), + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('unrelated workspace lock changes do not alter embedded source construction data', () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-napi-unrelated-lock-')); + try { + const spec = fixture(root, 'linux-x64-gnu', releaseSqlNames().slice(0, 3)); + const lock = path.join(root, 'Cargo.lock'); + writeFileSync(lock, 'version=4\n[[package]]\nname="oliphaunt-native"\nversion="0.3.3"\n'); + const before = stageWasixNapiInputs(spec).inventory; + writeFileSync(lock, 'version=4\n[[package]]\nname="oliphaunt-native"\nversion="0.3.4"\n'); + const output = path.join(root, 'after'); + const after = stageWasixNapiInputs({ ...spec, output }).inventory; + assert.deepEqual(after, before); + assert(!Object.hasOwn(after, 'cargoLock')); + assert(!after.files.some((row) => row.path === 'Cargo.lock')); + for (const row of after.files) { + const bytes = readFileSync(path.join(output, row.path)); + assert.equal(bytes.length, row.size); + assert.equal(digest(bytes), row.sha256); + assert.deepEqual(bytes, readFileSync(path.join(spec.output, row.path))); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('rejects mismatched source versions, incomplete physical crates and incompatible target or payload identities', () => { + const mutations: [string, (spec: WasixNapiInputsSpec) => void][] = [ + [ + 'source SDK version', + (spec) => { + writeFileSync( + spec.sdkManifest, + readFileSync(spec.sdkManifest, 'utf8').replace('0.3.2', '0.3.0'), + ); + }, + ], + [ + 'source SDK runtime requirement', + (spec) => { + writeFileSync( + spec.sdkManifest, + readFileSync(spec.sdkManifest, 'utf8').replace('version = "*"', 'version = "=0.3.0"'), + ); + }, + ], + [ + 'source SDK runtime local path', + (spec) => { + writeFileSync( + spec.sdkManifest, + readFileSync(spec.sdkManifest, 'utf8').replace( + '../../runtime/crates/assets', + '../../another-runtime/crates/assets', + ), + ); + }, + ], + [ + 'source SDK target AOT requirement', + (spec) => { + writeFileSync( + spec.sdkManifest, + readFileSync(spec.sdkManifest, 'utf8').replace( + `${AOT_PACKAGES[spec.target]} = { version = "*"`, + `${AOT_PACKAGES[spec.target]} = { version = "=0.3.0"`, + ), + ); + }, + ], + [ + 'source SDK package identity', + (spec) => { + writeFileSync( + spec.sdkManifest, + readFileSync(spec.sdkManifest, 'utf8').replace( + 'name="oliphaunt-wasix"', + 'name="foreign-sdk"', + ), + ); + }, + ], + [ + 'constructed version', + (spec) => + rewriteCrate(spec.contribPortable, (files) => { + const member = Object.keys(files).find((name) => name.endsWith('/Cargo.toml'))!; + files[member] = Buffer.from(files[member].toString().replace('0.3.2', '0.3.0')); + }), + ], + [ + 'runtime missing', + (spec) => + rewriteCrate(spec.portableArchive, (files) => { + delete files[ + Object.keys(files).find((name) => name.endsWith('/payload/oliphaunt.wasix.tar.zst'))! + ]; + }), + ], + [ + 'runtime changed', + (spec) => + rewriteCrate(spec.portableArchive, (files) => { + files[ + Object.keys(files).find((name) => name.endsWith('/payload/oliphaunt.wasix.tar.zst'))! + ] = Buffer.from('corrupt runtime'); + }), + ], + [ + 'initdb missing', + (spec) => + rewriteCrate(spec.portableArchive, (files) => { + delete files[ + Object.keys(files).find((name) => name.endsWith('/payload/bin/initdb.wasix.wasm'))! + ]; + }), + ], + [ + 'member missing', + (spec) => + rewriteCrate(spec.contribPortable, (files) => { + delete files[ + Object.keys(files).find((name) => + name.endsWith(`/extensions/${spec.sqlNames[0]}/extension.tar.zst`), + )! + ]; + }), + ], + [ + 'member changed', + (spec) => + rewriteCrate(spec.contribPortable, (files) => { + files[ + Object.keys(files).find((name) => + name.endsWith(`/extensions/${spec.sqlNames[0]}/extension.tar.zst`), + )! + ] = Buffer.from('corrupt extension'); + }), + ], + [ + 'AOT member missing', + (spec) => + rewriteCrate(spec.contribAot, (files) => { + delete files[ + Object.keys(files).find((name) => name.endsWith(`/manifests/${spec.sqlNames[0]}.json`))! + ]; + }), + ], + [ + 'duplicate requested member', + (spec) => { + spec.sqlNames.push(spec.sqlNames[0]); + }, + ], + [ + 'wrong target pair', + (spec) => { + spec.targetTriple = AOT_TARGET_TRIPLES['macos-arm64']; + }, + ], + [ + 'foreign core target', + (spec) => + rewriteCrate(spec.coreAotArchive, (files) => + rewriteJson(files, '/artifacts/manifest.json', (value) => { + value['target-triple'] = 'aarch64-apple-darwin'; + }), + ), + ], + [ + 'incompatible fingerprint', + (spec) => + rewriteCrate(spec.coreAotArchive, (files) => + rewriteJson(files, '/artifacts/manifest.json', (value) => { + value['source-fingerprint'] = 'another producer'; + }), + ), + ], + [ + 'wrong core hash', + (spec) => + rewriteCrate(spec.coreAotArchive, (files) => + rewriteJson(files, '/artifacts/manifest.json', (value) => { + value.artifacts[0].sha256 = '0'.repeat(64); + }), + ), + ], + [ + 'incomplete core inventory', + (spec) => + rewriteCrate(spec.coreAotArchive, (files) => + rewriteJson(files, '/artifacts/manifest.json', (value) => { + value.artifacts.pop(); + }), + ), + ], + [ + 'wrong portable module', + (spec) => + rewriteCrate(spec.contribAot, (files) => + rewriteJson(files, `/manifests/${spec.sqlNames[0]}.json`, (value) => { + value.artifacts[0]['module-sha256'] = '0'.repeat(64); + }), + ), + ], + [ + 'foreign extension artifact', + (spec) => + rewriteCrate(spec.contribAot, (files) => + rewriteJson(files, `/manifests/${spec.sqlNames[0]}.json`, (value) => { + value.artifacts[0].name = 'extension:foreign'; + }), + ), + ], + [ + 'unsafe AOT path', + (spec) => + rewriteCrate(spec.coreAotArchive, (files) => + rewriteJson(files, '/artifacts/manifest.json', (value) => { + value.artifacts[0].path = '../escape'; + }), + ), + ], + [ + 'wrong frozen owner version', + (spec) => { + const frozen = JSON.parse(readFileSync(spec.contribFrozen, 'utf8')); + frozen.version = '0.3.0'; + writeFileSync(spec.contribFrozen, JSON.stringify(frozen)); + }, + ], + ]; + for (const [scenario, mutate] of mutations) { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-napi-source-invalid-')); + try { + const spec = fixture(root, 'linux-x64-gnu', releaseSqlNames().slice(0, 3)); + mutate(spec); + assert.throws(() => stageWasixNapiInputs(spec), undefined, scenario); + } finally { + rmSync(root, { recursive: true, force: true }); + } + } +}); diff --git a/build_defs/wasix/napi-installed.test.mts b/build_defs/wasix/napi-installed.test.mts new file mode 100644 index 000000000..a2a4ad056 --- /dev/null +++ b/build_defs/wasix/napi-installed.test.mts @@ -0,0 +1,78 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { mkdtempSync, readFileSync, rmSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { assertWasixNapiConstructionData } from '../../src/wasix/node-addon/tools/carrier-contract.mts'; +import { + extractPortableArchiveTree, + readPortableArchiveEntries, +} from '../../tools/packaging/portable-archive.mts'; +import { copyNativeInputFile } from '../../tools/release/native-file-identity.mts'; + +const [archiveInput, lifecycle, node, consumer, productManifest] = process.argv.slice(2); +const root = mkdtempSync( + path.join(process.env.TEST_TMPDIR ?? os.tmpdir(), 'oliphaunt-installed-wasix-'), +); +try { + const declared = path.resolve(archiveInput); + const executionRoot = path.parse(declared).root; + const archive = path.join(root, 'carrier.tgz'); + copyNativeInputFile( + executionRoot, + path.relative(executionRoot, declared).split(path.sep).join('/'), + archive, + ); + const product = JSON.parse(readFileSync(productManifest, 'utf8')); + const contract = JSON.parse(readFileSync(lifecycle, 'utf8')); + const entries = readPortableArchiveEntries(archive); + assert( + [...entries.keys()].every((member) => member === 'package' || member.startsWith('package/')), + ); + const member = (name: string) => { + const entry = entries.get(name); + assert( + entry?.isFile && !entry.isSymbolicLink && entry.size > 0, + `missing regular installed member ${name}`, + ); + return Buffer.from(entry.data()); + }; + const manifest = JSON.parse(member('package/package.json').toString()); + const provenance = JSON.parse(member('package/artifact-provenance.json').toString()); + assert.equal(manifest.version, product.version); + assert.equal(manifest.oliphaunt.runtimeVersion, product.oliphaunt.runtimeVersion); + assert(!Object.hasOwn(manifest.oliphaunt, 'qualificationOnly')); + assertWasixNapiConstructionData( + provenance, + manifest.oliphaunt.target, + createHash('sha256') + .update(member('package/prebuilds/oliphaunt_wasix_napi.node')) + .digest('hex'), + { + targetTriple: contract.targetTriple, + sdkVersion: contract.sdkVersion, + runtimeVersion: product.oliphaunt.runtimeVersion, + sqlNames: contract.lifecycles.map((row: any) => row.sqlName), + }, + ); + assert(/^@oliphaunt\/wasix-napi-[a-z0-9-]+$/u.test(manifest.name)); + extractPortableArchiveTree(archive, path.join(root, 'node_modules', manifest.name), 'package'); + const env = { ...process.env, NODE_OPTIONS: '', NODE_PATH: '' }; + for (const key of Object.keys(env)) + if (/^(?:BUN_|RUNFILES|TEST_SRCDIR)/u.test(key)) delete env[key]; + const result = Bun.spawnSync( + [ + node, + '--experimental-strip-types', + '--preserve-symlinks-main', + consumer, + manifest.name, + lifecycle, + ], + { cwd: root, env, stdout: 'pipe', stderr: 'pipe', timeout: 240_000 }, + ); + assert.equal(result.exitCode, 0, `${result.stderr.toString()}\n${result.stdout.toString()}`); + console.log(result.stdout.toString().trim()); +} finally { + rmSync(root, { recursive: true, force: true }); +} diff --git a/build_defs/wasix/napi.bzl b/build_defs/wasix/napi.bzl new file mode 100644 index 000000000..14974e215 --- /dev/null +++ b/build_defs/wasix/napi.bzl @@ -0,0 +1,288 @@ +"""Release-feature Node-API construction from its actual locked Cargo inputs.""" + +load("@oliphaunt_metadata//:metadata.bzl", "EXTENSIONS", "EXTENSION_FINAL_INPUTS", "NATIVE_CURRENT_ARTIFACTS", "PRODUCTS", "PUBLICATION_CARRIERS", "WASIX_ARTIFACTS") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_file_action", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/languages:rust.bzl", "cargo_features", "rust_cdylib_output") +load("@rules_rust//rust:defs.bzl", "rust_common") +load("//build_defs/release:identity.bzl", "ReleaseIdentityInfo") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") +load("//build_defs/release:supplier.bzl", "ShippingSupplierInfo", "current_rust_shipping_supplier", "merge_shipping_suppliers") +load(":cargo.bzl", "RUNTIME_CARGO_HELPERS") +load(":npm.bzl", "RUNTIME_NPM_NOTICES") +load(":platform.bzl", "WASIX_PAYLOAD_PROFILE") + +WasixNapiInputsInfo = provider(fields = ["tree", "target", "triple", "sql_names", "sdk_version"]) +WasixNapiReleaseInfo = provider(fields = ["binary", "inputs"]) +WasixNapiCarrierInfo = provider(fields = ["npm", "github", "provenance", "target", "construction_contract"]) + +NAPI_NOTICES = RUNTIME_NPM_NOTICES | { + "//src/third-party/openssl:LICENSE.txt": "src/third-party/openssl/LICENSE.txt", + "//src/third-party/openssl:source.toml": "src/third-party/openssl/source.toml", +} +NAPI_HELPERS = {label: True for label in RUNTIME_CARGO_HELPERS + [ + "//src/wasix/runtime:toolchain.toml", + "//src/wasix/node-addon:tools/package-platform.mts", + "//src/wasix/node-addon:tools/workspace-runtime-contract.mts", + "//src/wasix/node-addon:tools/carrier-contract.mts", + "//:tools/packaging/npm-package.mts", + "//:tools/packaging/npm-trusted-publishing.mts", + "//:tools/packaging/platform-binary-contract.mts", + "//:tools/packaging/windows-vc-runtime-closure.mts", + "//:tools/packaging/windows-vc-runtime-policy.json", + "//tools/release:native-file-identity.mts", +]}.keys() + +def _targets(): + return {row["target"]: row for row in WASIX_ARTIFACTS if row["product"] == "oliphaunt-wasix-napi" and row["kind"] == "wasix-napi-addon"} + +def _selected(values): + return select({"@rules_rust//rust/platform:" + row["triple"]: values[target] for target, row in _targets().items()}) + +def release_sql_names(facts): + enabled = cargo_features(facts, ["release"]) + names = [] + for feature in enabled: + if feature.startswith("extension-"): + matches = [row["sql-name"] for row in EXTENSIONS.values() if feature == "extension-" + row["sql-name"].replace("_", "-")] + if len(matches) != 1: + fail("release Cargo extension feature has no unique canonical SQL member: " + feature) + names.append(matches[0]) + if not names or len(names) != len({name: True for name in names}): + fail("release Cargo extension closure must be nonempty and unique") + return sorted(names) + +def _inputs_impl(ctx): + if not ctx.file.contrib_frozen: + fail("WASIX addon is missing its original current contrib frozen File") + inputs = [ctx.file.sdk_manifest, ctx.file.contrib_frozen] + archives, suppliers = {}, [] + for target, role in ctx.attr.archives.items(): + record = json.decode(ctx.attr.archive_records[role]) + expected = record["package"] + "-" + ctx.attr.runtime_version + ".crate" + files = [file for file in target[DefaultInfo].files.to_list() if file.basename == expected] + if len(files) != 1 or files[0].is_directory: + fail("WASIX addon needs one original constructed Cargo archive for " + role) + file = files[0] + archives[role] = file.path + origin = {"kind": "current-source"} + if "producer" in record.get("file", {}): + original = record["file"] + origin["producer"] = dict(original["producer"], **({"member": original["member"]} if "member" in original else {})) + suppliers.append({"product": "liboliphaunt-wasix", "version": ctx.attr.runtime_version, + "configuration": record["configuration"], "binding": "compiled-input", + "origin": origin, "files": [{"path": file.path}]}) + inputs.append(file) + if sorted(archives) != ["contribAot", "contribPortable", "coreAotArchive", "portableArchive"]: + fail("WASIX addon is missing original current portable/AOT constructor Files") + output = ctx.actions.declare_directory(ctx.label.name) + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode(dict(archives, target = ctx.attr.target_id, targetTriple = ctx.attr.triple, + sdkManifest = ctx.file.sdk_manifest.path, + runtimeVersion = ctx.attr.runtime_version, sdkVersion = ctx.attr.sdk_version, + sqlNames = ctx.attr.sql_names, contribFrozen = ctx.file.contrib_frozen.path, output = output.path))) + bun_file_action(ctx, ctx.file._stager, arguments = [spec.path], inputs = inputs + [spec], + source_files = ctx.files._helpers, outputs = [output], mnemonic = "WasixNapiConstructedInputs") + return [DefaultInfo(files = depset([output])), WasixNapiInputsInfo(tree = output, target = ctx.attr.target_id, triple = ctx.attr.triple, sql_names = ctx.attr.sql_names, sdk_version = ctx.attr.sdk_version), + ShippingSupplierInfo(suppliers = suppliers, files = depset(inputs))] + +_inputs = rule(implementation = _inputs_impl, toolchains = BUN_SOURCE_TOOLCHAINS, attrs = { + "archives": attr.label_keyed_string_dict(allow_files = True, mandatory = True, cfg = WASIX_PAYLOAD_PROFILE), + "archive_records": attr.string_dict(mandatory = True), + "target_id": attr.string(mandatory = True), "triple": attr.string(mandatory = True), "sql_names": attr.string_list(mandatory = True), + "sdk_version": attr.string(mandatory = True), + "runtime_version": attr.string(mandatory = True), + "sdk_manifest": attr.label(default = "//src/wasix/sdks/rust:Cargo.toml", allow_single_file = True), + "contrib_frozen": attr.label(allow_single_file = True, cfg = WASIX_PAYLOAD_PROFILE), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), + "_stager": attr.label(default = "//build_defs/wasix:napi-inputs.mts", allow_single_file = True), + "_helpers": attr.label_list(default = NAPI_HELPERS, allow_files = True), +}) + +def wasix_napi_inputs(name, cargo_facts): + targets = _targets() + runtime_version = PRODUCTS["liboliphaunt-wasix"]["version"] + archives, records = {}, {} + for target, definition in targets.items(): + selected, declarations = {}, {} + for role, package, source in [ + ("portableArchive", "liboliphaunt-wasix-portable", "//src/wasix/runtime/crates/assets:crate"), + ("coreAotArchive", "liboliphaunt-wasix-aot-" + definition["triple"], "//src/wasix/runtime/crates/aot/" + definition["triple"] + ":crate"), + ("contribPortable", "oliphaunt-extension-contrib-pg18-wasix", ""), + ("contribAot", "oliphaunt-extension-contrib-pg18-aot-" + target.removesuffix("-gnu").removesuffix("-msvc"), ""), + ]: + rows = [row for row in PUBLICATION_CARRIERS if row["product"] == "liboliphaunt-wasix" and row["ecosystem"] == "cargo" and row["name"] == package] + if len(rows) != 1: + fail("WASIX addon needs one canonical current carrier: " + package) + record = {"package": package, "configuration": target if role == "coreAotArchive" else (rows[0]["target"] or "portable")} + if NATIVE_CURRENT_ARTIFACTS != None: + original = NATIVE_CURRENT_ARTIFACTS.get("liboliphaunt-wasix/" + runtime_version + "/cargo:" + package) + if original: + source = original["file"]["path"] + record = dict(original, package = package) + else: + source = "" + elif not source: + source = name + "_" + target.replace("-", "_") + "_" + role + native.filegroup(name = source, srcs = ["//build_defs/extensions/wasix:contrib"], output_group = "cargo") + source = ":" + source + if source: + selected[source] = role + declarations[role] = json.encode(record) + archives[target], records[target] = selected, declarations + frozen = name + "_contrib_frozen" + if NATIVE_CURRENT_ARTIFACTS == None: + native.filegroup(name = frozen, srcs = ["//build_defs/extensions/wasix:contrib"], output_group = "frozen") + frozen = ":" + frozen + else: + imported = EXTENSION_FINAL_INPUTS.get("oliphaunt-extension-contrib-pg18/wasix/wasix-portable") + frozen = imported["frozen"]["path"] if imported else None + _inputs(name = name, archives = _selected(archives), archive_records = _selected(records), + target_id = _selected({target: target for target in targets}), + triple = _selected({target: row["triple"] for target, row in targets.items()}), + sql_names = release_sql_names(cargo_facts[native.package_name()]), + contrib_frozen = frozen, runtime_version = runtime_version, + sdk_version = PRODUCTS["oliphaunt-wasix-rust"]["version"]) + +def _release_profile_impl(settings, attr): + return {"//command_line_option:compilation_mode": "opt", "@rules_rust//rust/settings:lto": "thin", + "@rules_rust//rust/settings:codegen_units": 1, "@rules_rust//rust/settings:extra_rustc_flags": ["-Cstrip=symbols"]} + +_release_profile = transition(implementation = _release_profile_impl, inputs = [], outputs = [ + "//command_line_option:compilation_mode", "@rules_rust//rust/settings:lto", + "@rules_rust//rust/settings:codegen_units", "@rules_rust//rust/settings:extra_rustc_flags", +]) + +def _producer_impl(ctx): + binary = rust_cdylib_output(ctx.attr.library[0]) + if binary.is_directory: + fail("WASIX addon release must supply exactly its maintained native cdylib") + inputs = ctx.attr.inputs[0][WasixNapiInputsInfo] + suppliers = [ctx.attr.inputs[0][ShippingSupplierInfo]] + compiled = {} + for name, target, owner, source in [ + ("sdk", ctx.attr.sdk[0], ctx.attr.sdk_owner, "src/wasix/sdks/rust"), + ("server", ctx.attr.server[0], ctx.attr.server_owner, "src/wasix/pgwire-server"), + ]: + supplier = current_rust_shipping_supplier(target[rust_common.crate_info], target.label, + owner[ReleaseIdentityInfo], source, inputs.target) + suppliers.append(supplier) + compiled[name + "_compiled"] = supplier.files + return [DefaultInfo(files = depset([binary])), WasixNapiReleaseInfo(binary = binary, inputs = inputs), + merge_shipping_suppliers(suppliers), OutputGroupInfo(**compiled)] + +wasix_napi_release = rule(implementation = _producer_impl, attrs = { + "library": attr.label(mandatory = True, providers = [rust_common.test_crate_info], cfg = _release_profile), + "inputs": attr.label(mandatory = True, providers = [WasixNapiInputsInfo], cfg = _release_profile), + "sdk": attr.label(default = "//src/wasix/sdks/rust:napi_release_lib", cfg = _release_profile), + "sdk_owner": attr.label(default = "@oliphaunt_metadata//:product_oliphaunt-wasix-rust", providers = [ReleaseIdentityInfo]), + "server": attr.label(default = "//src/wasix/pgwire-server:napi_release_lib", cfg = _release_profile), + "server_owner": attr.label(default = "@oliphaunt_metadata//:product_oliphaunt-pgwire-server", providers = [ReleaseIdentityInfo]), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), +}) + +def _carrier_impl(ctx): + producer = ctx.attr.producer[WasixNapiReleaseInfo] + owner = ctx.attr.owner[ReleaseIdentityInfo] + row = _targets()[producer.inputs.target] + if owner.id != "oliphaunt-wasix-napi": + fail("WASIX addon carrier requires its canonical independent release owner") + npm = ctx.actions.declare_file(ctx.label.name + ".tgz") + github = ctx.actions.declare_file(row["asset"].replace("{version}", owner.version)) + provenance = ctx.actions.declare_file(ctx.label.name + ".provenance.json") + inputs = [producer.binary, producer.inputs.tree, ctx.file.manifest, ctx.file.product_manifest, ctx.file.readme] + notices = {} + for target, destination in ctx.attr.notices.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1 or files[0].is_directory: + fail("WASIX addon notice must be one declared File") + notices[destination] = files[0].path + inputs += files + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode({"target": producer.inputs.target, "version": owner.version, "targetContract": row, + "sdkVersion": producer.inputs.sdk_version, "sqlNames": producer.inputs.sql_names, + "binary": producer.binary.path, "inputs": producer.inputs.tree.path, "manifest": ctx.file.manifest.path, "productManifest": ctx.file.product_manifest.path, + "readme": ctx.file.readme.path, "notices": notices, "windowsRuntime": {file.basename: file.path for file in ctx.files.windows_runtime}, + "outputs": {"npm": npm.path, "github": github.path, "provenance": provenance.path}})) + inputs += ctx.files.windows_runtime + bun_file_action(ctx, ctx.file._packager, arguments = [spec.path], inputs = inputs + [spec], source_files = ctx.files._helpers, + outputs = [npm, github, provenance], mnemonic = "WasixNapiReleaseEnvelopes") + return [DefaultInfo(files = depset([npm, github, provenance])), WasixNapiCarrierInfo(npm = npm, github = github, provenance = provenance, target = producer.inputs.target, + construction_contract = {"targetTriple": producer.inputs.triple, "sdkVersion": producer.inputs.sdk_version, "sqlNames": producer.inputs.sql_names}), + ctx.attr.producer[ShippingSupplierInfo], + OutputGroupInfo(npm = depset([npm]), github = depset([github]), provenance = depset([provenance]))] + +_carrier = rule(implementation = _carrier_impl, toolchains = BUN_SOURCE_TOOLCHAINS, attrs = { + "producer": attr.label(mandatory = True, providers = [WasixNapiReleaseInfo]), + "owner": attr.label(mandatory = True, providers = [ReleaseIdentityInfo]), + "manifest": attr.label(allow_single_file = True, mandatory = True), "readme": attr.label(allow_single_file = True, mandatory = True), + "product_manifest": attr.label(default = "//src/wasix/node-addon:package.json", allow_single_file = True), + "windows_runtime": attr.label_list(allow_files = True), + "notices": attr.label_keyed_string_dict(default = NAPI_NOTICES, allow_files = True), + "_packager": attr.label(default = "//build_defs/wasix:napi.mts", allow_single_file = True), + "_helpers": attr.label_list(default = NAPI_HELPERS, allow_files = True), +}) + +def wasix_napi_carriers(producer, qualification = []): + targets = _targets() + directories = {target: row["npm_os"] + "-" + row["npm_cpu"] + ("-gnu" if row["npm_libc"] else "-msvc" if row["npm_os"] == "win32" else "") for target, row in targets.items()} + _carrier(name = "release_carriers", producer = producer, owner = "@oliphaunt_metadata//:product_oliphaunt-wasix-napi", + manifest = _selected({target: "packages/" + directory + "/package.json" for target, directory in directories.items()}), + readme = _selected({target: "packages/" + directory + "/README.md" for target, directory in directories.items()}), + windows_runtime = select({"//build_defs/native:windows_x64": ["@native_msvc_sdk//:runtime_dlls"], "//conditions:default": []})) + packages = [] + for ecosystem in ["npm", "github", "provenance"]: + name = ecosystem + "_release_shipping" + native.filegroup(name = name + "_files", srcs = [":release_carriers"], output_group = ecosystem) + package_name = _selected({target: row["npm_package"] if ecosystem == "npm" else row["asset"].replace("{version}", PRODUCTS["oliphaunt-wasix-napi"]["version"]) if ecosystem == "github" else "wasix-napi-provenance" for target, row in targets.items()}) + npm_rows = {} + if ecosystem == "npm": + for target, row in targets.items(): + carriers = [carrier for carrier in PUBLICATION_CARRIERS if carrier["product"] == "oliphaunt-wasix-napi" and carrier["ecosystem"] == "npm" and carrier["name"] == row["npm_package"]] + if len(carriers) != 1: + fail("WASIX addon must own exactly its canonical npm platform leaf") + npm_rows[target] = carriers[0] + shipping_package(name = name, owner = "@oliphaunt_metadata//:product_oliphaunt-wasix-napi", artifacts = [":" + name + "_files"], ecosystem = ecosystem if ecosystem != "provenance" else "internal", package_name = package_name, + configuration = _selected({target: npm_rows[target]["target"] if ecosystem == "npm" else target for target in targets}), + role = _selected({target: npm_rows[target]["role"] for target in targets}) if ecosystem == "npm" else "github-release-asset" if ecosystem == "github" else "construction-provenance", + suppliers = ":release_carriers") + packages.append(":" + name) + shipping_export(name = "release_shipping_export", packages = packages, qualification = qualification, testonly = True) + +def _installed_impl(ctx): + producer = ctx.attr.producer[WasixNapiReleaseInfo] + carrier = ctx.attr.carrier[WasixNapiCarrierInfo] + if carrier.target != producer.inputs.target: + fail("installed addon must use the exact native release producer configuration") + lifecycles = [] + for name in producer.inputs.sql_names: + rows = [row for row in EXTENSIONS.values() if row["sql-name"] == name] + if len(rows) != 1: + fail("installed addon SQL lifecycle must be canonical and unique: " + name) + row = rows[0] + lifecycle = row["lifecycle"] + if lifecycle["preload-required"] or lifecycle["restart-required"] or lifecycle["shared-memory-required"]: + fail("installed default addon member requires an unmodeled server lifecycle: " + name) + lifecycles.append({"sqlName": name, "dependencies": row["dependencies"], "create": lifecycle["create-extension"], + "schema": lifecycle.get("create-schema"), "loadSql": lifecycle["load-sql"], "postCreateSql": lifecycle["post-create-sql"]}) + metadata = ctx.actions.declare_file(ctx.label.name + ".lifecycles.json") + ctx.actions.write(metadata, json.encode({"targetTriple": producer.inputs.triple, "sdkVersion": producer.inputs.sdk_version, "lifecycles": lifecycles})) + node = ctx.toolchains["@rules_nodejs//nodejs:toolchain_type"].nodeinfo.node + if not node: + fail("installed WASIX addon requires its pinned Node toolchain") + files = [carrier.npm, metadata, node, ctx.file._consumer, ctx.file.product_manifest] + ctx.files._helpers + return bun_test_entrypoint(ctx, ctx.file._runner, [carrier.npm, metadata, node, ctx.file._consumer, ctx.file.product_manifest], files, + source_files = [ctx.file._runner, ctx.file._consumer] + ctx.files._helpers) + +_installed_test = rule(implementation = _installed_impl, test = True, + toolchains = BUN_SOURCE_TOOLCHAINS + ["@rules_nodejs//nodejs:toolchain_type"], + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "producer": attr.label(mandatory = True, providers = [WasixNapiReleaseInfo]), + "carrier": attr.label(mandatory = True, providers = [WasixNapiCarrierInfo]), + "product_manifest": attr.label(default = "//src/wasix/node-addon:package.json", allow_single_file = True), + "_runner": attr.label(default = "//build_defs/wasix:napi-installed.test.mts", allow_single_file = True), + "_consumer": attr.label(default = "//build_defs/wasix:napi-consumer.mts", allow_single_file = True), + "_helpers": attr.label_list(default = NAPI_HELPERS + ["//src/wasix/sdks/ts:tools/pgwire-client.mts"], allow_files = True), + })) + +def wasix_napi_installed_test(name, **kwargs): + _installed_test(name = name, args = bun_test_entrypoint_args(name), **kwargs) diff --git a/build_defs/wasix/napi.mts b/build_defs/wasix/napi.mts new file mode 100644 index 000000000..953bcb43f --- /dev/null +++ b/build_defs/wasix/napi.mts @@ -0,0 +1,166 @@ +import assert from 'node:assert/strict'; +import { copyFileSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { assertWasixNapiCarrierManifest } from '../../src/wasix/node-addon/tools/carrier-contract.mts'; +import { + packageWasixNapiCarrier, + WASIX_NAPI_BINARY, + type WasixNapiStage, +} from '../../src/wasix/node-addon/tools/package-platform.mts'; +import { releaseProfilePackageLicense } from '../../tools/packaging/release-notices.mts'; +import { + renderWindowsVcRuntimeSourceReceipt, + WINDOWS_VC_RUNTIME_RECEIPT, +} from '../../tools/packaging/windows-vc-runtime-closure.mts'; +import { copyNativeInputFile } from '../../tools/release/native-file-identity.mts'; + +export type WasixNapiCarrierSpec = { + target: WasixNapiStage['target']; + version: string; + sdkVersion: string; + sqlNames: string[]; + targetContract: Record; + binary: string; + inputs: string; + manifest: string; + productManifest: string; + readme: string; + notices: Record; + windowsRuntime: Record; + outputs: { npm: string; github: string; provenance: string }; +}; + +/** Render canonical bytes; source/run authentication and admission belong to outer evidence. */ +export async function packageNativeWasixNapi(spec: WasixNapiCarrierSpec) { + const scratch = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-native-napi-')); + const copy = (input: string, output: string) => { + const absolute = path.resolve(input), + root = path.parse(absolute).root; + return copyNativeInputFile( + root, + path.relative(root, absolute).split(path.sep).join('/'), + output, + ); + }; + try { + const binary = path.join(scratch, WASIX_NAPI_BINARY); + const subject = copy(spec.binary, binary); + const buildInputs = JSON.parse( + readFileSync(path.join(spec.inputs, 'build-inputs.json'), 'utf8'), + ); + const layout = JSON.parse(readFileSync(path.join(spec.inputs, 'layout.json'), 'utf8')); + const product = JSON.parse(readFileSync(spec.productManifest, 'utf8')); + assert.equal( + product.version, + spec.version, + 'addon owner version differs from conventional package', + ); + assert.equal( + product.oliphaunt.runtimeVersion, + layout.runtimeVersion, + 'addon runtime pin differs from compiled source SDK', + ); + const sourceRoot = path.join(scratch, 'source'); + for (const [member, input] of Object.entries(spec.notices)) + copy(input, path.join(sourceRoot, member)); + const manifest = JSON.parse(readFileSync(spec.manifest, 'utf8')); + manifest.oliphaunt = { + ...manifest.oliphaunt, + runtimeVersion: layout.runtimeVersion, + }; + assert( + !Object.hasOwn(manifest.oliphaunt, 'qualificationOnly'), + 'native carrier template is a qualification package', + ); + const row = spec.targetContract; + assertWasixNapiCarrierManifest( + manifest, + { + target: spec.target, + npmPackage: row.npm_package, + npmOs: row.npm_os, + npmCpu: row.npm_cpu, + npmLibc: row.npm_libc ?? undefined, + }, + spec.version, + 'native addon carrier', + { + ...product.oliphaunt, + runtimeVersion: layout.runtimeVersion, + packageLicense: releaseProfilePackageLicense('wasix-napi-addon', { sourceRoot }).spdx, + }, + ); + const provenance = { + schema: 'oliphaunt-wasix-napi-construction-data-v3', + product: 'oliphaunt-wasix-napi', + target: spec.target, + build: { + cargoProfile: 'release', + incremental: false, + codegenUnits: 1, + lto: 'thin', + strip: 'symbols', + features: ['release'], + targetTriple: buildInputs.targetTriple, + }, + buildInputs, + binary: { filename: WASIX_NAPI_BINARY, sha256: subject.sha256 }, + }; + let windowsRuntimeSourceDirectory: string | undefined; + if (spec.target === 'windows-x64-msvc') { + assert( + Object.keys(spec.windowsRuntime).length > 0, + 'Windows addon requires its declared SDK runtime closure', + ); + windowsRuntimeSourceDirectory = path.join(scratch, 'redist'); + for (const [member, input] of Object.entries(spec.windowsRuntime)) { + assert.equal(path.basename(member), member, 'Windows runtime must be a flat declared File'); + copy(input, path.join(windowsRuntimeSourceDirectory, member)); + } + writeFileSync( + path.join(windowsRuntimeSourceDirectory, WINDOWS_VC_RUNTIME_RECEIPT), + renderWindowsVcRuntimeSourceReceipt({ + sourceDirectory: windowsRuntimeSourceDirectory, + profile: 'provider', + }), + ); + } else + assert.equal( + Object.keys(spec.windowsRuntime).length, + 0, + 'foreign VC runtime in addon envelope', + ); + const readme = path.join(scratch, 'README.md'); + copy(spec.readme, readme); + const outputs = await packageWasixNapiCarrier({ + target: spec.target, + manifest, + binary, + provenance, + constructionContract: { + targetTriple: row.triple, + sdkVersion: spec.sdkVersion, + runtimeVersion: layout.runtimeVersion, + sqlNames: spec.sqlNames, + }, + sourceRoot, + readme, + windowsRuntimeSourceDirectory, + packageStage: path.join(scratch, 'npm'), + releaseStage: path.join(scratch, 'github'), + tarballRoot: path.join(scratch, 'packages'), + releaseArchive: spec.outputs.github, + }); + mkdirSync(path.dirname(spec.outputs.npm), { recursive: true }); + copyFileSync(outputs.npm, spec.outputs.npm); + mkdirSync(path.dirname(spec.outputs.provenance), { recursive: true }); + writeFileSync(spec.outputs.provenance, `${JSON.stringify(provenance, null, 2)}\n`); + return spec.outputs; + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +} + +if (import.meta.main) + await packageNativeWasixNapi(JSON.parse(readFileSync(process.argv[2], 'utf8'))); diff --git a/build_defs/wasix/npm.bzl b/build_defs/wasix/npm.bzl new file mode 100644 index 000000000..a57eaff16 --- /dev/null +++ b/build_defs/wasix/npm.bzl @@ -0,0 +1,82 @@ +"""Npm envelope for the declared portable runtime, using the shared formatter.""" + +load("@oliphaunt_metadata//:metadata.bzl", "PRODUCTS") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") +load("//build_defs/release:identity.bzl", "ReleaseIdentityInfo") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") + +RUNTIME_NPM_HELPERS = [ + "//src/wasix/runtime:tools/wasix-runtime-npm-payload.mts", + "//src/wasix/runtime:tools/wasix-runtime-npm-contract.mts", + "//src/wasix/runtime:tools/wasix-runtime-npm-descriptor.mts", + "//:tools/packaging/package-archive.mts", + "//:tools/packaging/archive-directory.mts", + "//:tools/packaging/portable-archive.mts", + "//:tools/packaging/release-notices.mts", + "//:tools/packaging/release-directory-safety.mts", + "//:tools/packaging/npm-trusted-publishing.mts", +] + +RUNTIME_NPM_NOTICES = { + "//:LICENSE": "LICENSE", + "//:THIRD_PARTY_NOTICES.md": "THIRD_PARTY_NOTICES.md", + "//src/wasix/sdks/rust:THIRD_PARTY_NOTICES.md": "src/wasix/sdks/rust/THIRD_PARTY_NOTICES.md", + "//src/third-party/postgres:COPYRIGHT": "src/third-party/postgres/COPYRIGHT", + "//src/third-party/postgres:source.toml": "src/third-party/postgres/source.toml", + "//src/third-party/icu:LICENSE": "src/third-party/icu/LICENSE", + "//src/third-party/icu:source.toml": "src/third-party/icu/source.toml", +} + +def _runtime_npm_impl(ctx): + payloads = ctx.attr.payload[DefaultInfo].files.to_list() + if len(payloads) != 1 or not payloads[0].is_directory: + fail("WASIX runtime npm carrier requires the actual portable payload tree") + identity = ctx.attr.product[ReleaseIdentityInfo] + if identity.id != "liboliphaunt-wasix": + fail("WASIX runtime npm carrier requires its canonical product owner") + inputs = payloads[:] + notices = {} + for target, destination in ctx.attr.notices.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1 or files[0].is_directory or destination in notices: + fail("WASIX runtime npm notice must be one unique declared file") + notices[destination] = files[0].path + inputs += files + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode({"version": identity.version, "packageName": ctx.attr.package_name, "portableAssets": payloads[0].path, "notices": notices})) + output = ctx.actions.declare_file(ctx.label.name + ".tgz") + args = ctx.actions.args() + args.add_all(["--spec", spec, "--output", output]) + bun_file_action( + ctx, + ctx.file._packager, + arguments = [args], + inputs = depset(inputs + [spec]), + source_files = ctx.files._helpers, + outputs = [output], + mnemonic = "WasixRuntimeNpmEnvelope", + ) + return [DefaultInfo(files = depset([output]))] + +_runtime_npm = rule( + implementation = _runtime_npm_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = { + "payload": attr.label(mandatory = True), + "product": attr.label(mandatory = True, providers = [ReleaseIdentityInfo]), + "package_name": attr.string(mandatory = True), + "notices": attr.label_keyed_string_dict(default = RUNTIME_NPM_NOTICES, allow_files = True), + "_packager": attr.label(default = "//build_defs/wasix:npm.mts", allow_single_file = True), + "_helpers": attr.label_list(default = RUNTIME_NPM_HELPERS, allow_files = True), + }, +) + +def wasix_runtime_npm(): + product = "liboliphaunt-wasix" + names = [name[len("npm:"):] for name in PRODUCTS[product]["registry_packages"] if name.startswith("npm:")] + if len(names) != 1: + fail("WASIX portable runtime product must own exactly one npm carrier") + owner = "@oliphaunt_metadata//:product_" + product + _runtime_npm(name = "npm", payload = ":portable_payload", product = owner, package_name = names[0]) + shipping_package(name = "npm_shipping_package", owner = owner, artifacts = [":npm"], ecosystem = "npm", package_name = names[0], configuration = "portable", role = "portable-leaf", suppliers = "//src/wasix/runtime:runtime_public_suppliers") + shipping_export(name = "npm_shipping_export", packages = [":npm_shipping_package"]) diff --git a/build_defs/wasix/npm.mts b/build_defs/wasix/npm.mts new file mode 100644 index 000000000..ad2be0e62 --- /dev/null +++ b/build_defs/wasix/npm.mts @@ -0,0 +1,83 @@ +import { copyFileSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { parseArgs } from 'node:util'; +import { WASIX_RUNTIME_NPM_PACKAGE } from '../../src/wasix/runtime/tools/wasix-runtime-npm-contract.mts'; +import { + assertWasixRuntimeNpmArchive, + stageWasixRuntimeNpmPayload, + wasixRuntimeNpmPayloadInputs, +} from '../../src/wasix/runtime/tools/wasix-runtime-npm-payload.mts'; +import { createDeterministicTar } from '../../tools/packaging/package-archive.mts'; +import { canonicalGzipSync } from '../../tools/packaging/portable-archive.mts'; + +export interface RuntimeNpmSpec { + version: string; + packageName: string; + portableAssets: string; + notices: Record; +} + +export function packageRuntimeNpm(spec: RuntimeNpmSpec, output: string): void { + output = path.resolve(output); + if (spec.packageName !== WASIX_RUNTIME_NPM_PACKAGE) { + throw new Error('Canonical release package name disagrees with the WASIX runtime contract'); + } + const inputs = wasixRuntimeNpmPayloadInputs({ + manifestBytes: readFileSync(path.join(spec.portableAssets, 'manifest.json')), + runtimeBytes: readFileSync(path.join(spec.portableAssets, 'oliphaunt.wasix.tar.zst')), + label: 'declared portable runtime', + }); + mkdirSync(path.dirname(output), { recursive: true }); + const scratch = mkdtempSync(path.join(path.dirname(output), '.wasix-npm-')); + try { + const sourceRoot = path.join(scratch, 'notices'); + for (const [destination, source] of Object.entries(spec.notices)) { + if ( + !destination || + destination.includes('\\') || + destination.split('/').some((part) => !part || part === '.' || part === '..') || + path.isAbsolute(destination) + ) { + throw new Error(`Unsafe declared notice destination: ${destination}`); + } + const file = path.join(sourceRoot, destination); + mkdirSync(path.dirname(file), { recursive: true }); + copyFileSync(source, file); + } + // Canonical notice readers intentionally reject symbolic links. Copy only + // these declared file projections into a real temporary source root. + const noticeOptions = { profile: 'wasix-runtime', sourceRoot }; + const staged = stageWasixRuntimeNpmPayload({ + version: spec.version, + inputs, + packageDir: path.join(scratch, 'package'), + noticeOptions, + }); + writeFileSync( + output, + canonicalGzipSync( + createDeterministicTar(staged.packageDir, 'package', { fixedFileMode: 0o644 }), + ), + ); + assertWasixRuntimeNpmArchive(output, { + version: spec.version, + descriptor: staged.descriptor, + noticeOptions, + }); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + const { values } = parseArgs({ + options: { spec: { type: 'string' }, output: { type: 'string' } }, + strict: true, + }); + if (!values.spec || !values.output) + throw new Error('usage: npm.mts --spec --output '); + packageRuntimeNpm( + JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(readFileSync(values.spec))), + values.output, + ); +} diff --git a/build_defs/wasix/npm.test.mts b/build_defs/wasix/npm.test.mts new file mode 100644 index 000000000..d0fa83a7a --- /dev/null +++ b/build_defs/wasix/npm.test.mts @@ -0,0 +1,102 @@ +import { afterEach, expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; +import os from 'node:os'; +import path from 'node:path'; +import { zstdCompressSync } from 'node:zlib'; +import { WASIX_RUNTIME_NPM_PACKAGE } from '../../src/wasix/runtime/tools/wasix-runtime-npm-contract.mts'; +import { packageRuntimeNpm, type RuntimeNpmSpec } from './npm.mts'; + +const roots: string[] = []; +afterEach(async () => { + await Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true }))); +}); +const sha = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +async function fixture() { + const root = await mkdtemp(path.join(os.tmpdir(), 'oliphaunt-native-runtime-npm-')); + roots.push(root); + const portableAssets = path.join(root, 'portable'); + await mkdir(portableAssets); + const module = Buffer.from('\0asm\x01\0\0\0'); + const runtime = zstdCompressSync( + Buffer.from(await new Bun.Archive({ 'oliphaunt/bin/postgres': module }).bytes()), + ); + await writeFile(path.join(portableAssets, 'oliphaunt.wasix.tar.zst'), runtime); + const manifest = Buffer.from( + `${JSON.stringify( + { + 'format-version': 2, + 'source-fingerprint': 'independent fixture', + runtime: { + archive: 'oliphaunt.wasix.tar.zst', + sha256: sha(runtime), + size: runtime.length, + 'module-sha256': sha(module), + 'postgres-version': '18.4', + link: { exports: [] }, + }, + 'runtime-support': [], + extensions: [], + }, + null, + 2, + )}\n`, + ); + await writeFile(path.join(portableAssets, 'manifest.json'), manifest); + const notices = Object.fromEntries( + [ + 'LICENSE', + 'THIRD_PARTY_NOTICES.md', + 'src/wasix/sdks/rust/THIRD_PARTY_NOTICES.md', + 'src/third-party/postgres/COPYRIGHT', + 'src/third-party/postgres/source.toml', + 'src/third-party/icu/LICENSE', + 'src/third-party/icu/source.toml', + ].map((file) => [file, path.resolve(file)]), + ); + const spec: RuntimeNpmSpec = { + version: '7.8.9', + packageName: WASIX_RUNTIME_NPM_PACKAGE, + portableAssets, + notices, + }; + return { root, spec, runtime, manifest }; +} + +test('runtime npm preserves physical assets and deterministic framing read by an independent archive consumer', async () => { + const { root, spec, runtime, manifest } = await fixture(); + const first = path.join(root, 'first.tgz'); + const second = path.join(root, 'second.tgz'); + packageRuntimeNpm(spec, first); + packageRuntimeNpm(spec, path.relative(process.cwd(), second)); + expect(await readFile(first)).toEqual(await readFile(second)); + const files = await new Bun.Archive(await readFile(first)).files(); + const read = async (name: string) => { + const file = files.get(`package/${name}`); + if (!file) throw new Error(`independent archive consumer found no ${name}`); + return Buffer.from(await file.arrayBuffer()); + }; + expect(await read('assets/manifest.json')).toEqual(manifest); + expect(await read('assets/oliphaunt.wasix.tar.zst')).toEqual(runtime); + expect(JSON.parse((await read('package.json')).toString())).toMatchObject({ + name: WASIX_RUNTIME_NPM_PACKAGE, + version: spec.version, + type: 'module', + }); + expect((await read('index.js')).toString()).toContain(spec.version); + expect(await read('LICENSE')).toEqual(await readFile('LICENSE')); +}); + +test('runtime npm rejects mismatched names, stale bytes, missing notices and unsafe notice paths', async () => { + const { root, spec } = await fixture(); + const output = path.join(root, 'invalid.tgz'); + expect(() => packageRuntimeNpm({ ...spec, packageName: '@oliphaunt/wrong' }, output)).toThrow( + 'Canonical release package name disagrees', + ); + expect(() => + packageRuntimeNpm({ ...spec, notices: { ...spec.notices, '../outside': 'LICENSE' } }, output), + ).toThrow('Unsafe declared notice destination'); + expect(() => packageRuntimeNpm({ ...spec, notices: {} }, output)).toThrow(); + await writeFile(path.join(spec.portableAssets, 'oliphaunt.wasix.tar.zst'), 'changed bytes'); + expect(() => packageRuntimeNpm(spec, output)).toThrow('does not match manifest.runtime.sha256'); +}); diff --git a/build_defs/wasix/package-aot.mts b/build_defs/wasix/package-aot.mts new file mode 100644 index 000000000..c2ae93510 --- /dev/null +++ b/build_defs/wasix/package-aot.mts @@ -0,0 +1,61 @@ +/** Stage four declared serializer outputs and their frozen runtime manifest. */ +import { chmod, copyFile, mkdir, readFile } from 'node:fs/promises'; +import path from 'node:path'; +import { parseArgs } from 'node:util'; + +export interface AotPayloadSpec { + portable_manifest: string; + toolchain: string; + target_triple: string; + artifacts: { name: string; path: string; image: string; module: string }[]; +} + +export async function packageAot( + spec: AotPayloadSpec, + specPath: string, + output: string, + manifestTool: string, +): Promise { + if (path.basename(output) !== spec.target_triple) + throw new Error('AOT payload directory must match its declared target triple'); + const paths = new Set(); + await mkdir(output, { recursive: true }); + for (const artifact of spec.artifacts) { + if (!/^[a-z_]+-llvm-opta\.bin\.zst$/u.test(artifact.path) || paths.has(artifact.path)) + throw new Error(`unsafe or duplicate AOT artifact path: ${artifact.path}`); + paths.add(artifact.path); + const destination = path.join(output, artifact.path); + await copyFile(artifact.image, destination); + await chmod(destination, 0o644); + } + const result = Bun.spawnSync( + [ + manifestTool, + 'assets', + 'declared-aot-manifest', + '--spec', + specPath, + '--output', + path.join(output, 'manifest.json'), + ], + { stdout: 'inherit', stderr: 'inherit', env: { ...process.env, LC_ALL: 'C' } }, + ); + if (result.exitCode !== 0) + throw new Error(`AOT manifest tool failed with exit ${result.exitCode}`); +} + +if (import.meta.main) { + const { values } = parseArgs({ + options: { + spec: { type: 'string' }, + output: { type: 'string' }, + 'manifest-tool': { type: 'string' }, + }, + }); + if (!values.spec || !values.output || !values['manifest-tool']) + throw new Error('--spec, --output and --manifest-tool are required'); + const spec = JSON.parse( + new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(await readFile(values.spec)), + ) as AotPayloadSpec; + await packageAot(spec, values.spec, values.output, values['manifest-tool']); +} diff --git a/build_defs/wasix/package.bzl b/build_defs/wasix/package.bzl new file mode 100644 index 000000000..b63dd8058 --- /dev/null +++ b/build_defs/wasix/package.bzl @@ -0,0 +1,103 @@ +"""A declared portable runtime tree for source carriers and installed consumers.""" + +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") +load(":wasm.bzl", "WasmExportPolicyInfo", "WasmModuleInfo") + +def postgres_patch_inputs(paths): + labels = [] + for path in paths: + matched = False + for owner in ["src/wasix/runtime", "src/third-party/postgres", "src/native/runtime"]: + if path.startswith(owner + "/"): + labels.append("//" + owner + ":" + path[len(owner) + 1:]) + matched = True + break + if not matched: + fail("unsupported PostgreSQL patch owner: " + path) + return labels + +def _payload_impl(ctx): + runtime = ctx.attr.runtime[WasmModuleInfo].module + initdb = ctx.attr.initdb[WasmModuleInfo].module + policy = ctx.attr.export_policy[WasmExportPolicyInfo].exports + inputs = [runtime, initdb, policy, ctx.file.postgres_source, ctx.file.postgres_series, ctx.file.icu_source] + entries = [ + {"source": runtime.path, "destination": "bin/postgres", "executable": True}, + {"source": initdb.path, "destination": "bin/initdb", "executable": True}, + ] + support = [] + trees = [] + for target, name in ctx.attr.support.items(): + file = target[WasmModuleInfo].module + destination = "lib/postgresql/" + name + ".so" + inputs.append(file) + entries.append({"source": file.path, "destination": destination, "executable": True}) + support.append({"name": name, "source": file.path, "path": destination}) + for target, destination in ctx.attr.resources.items(): + for file in target[DefaultInfo].files.to_list(): + inputs.append(file) + if file.is_directory: + trees.append(file) + entries.append({ + "source": file.path, + "destination": destination + (file.basename if destination.endswith("/") and not file.is_directory else ""), + "tree": file.is_directory, + }) + patches = {file.short_path: file.path for file in ctx.files.patches} + inputs += ctx.files.patches + specification = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(specification, json.encode({ + "entries": entries, + "runtime": runtime.path, + "initdb": initdb.path, + "exportPolicy": policy.path, + "support": support, + "postgresSource": ctx.file.postgres_source.path, + "postgresSeries": ctx.file.postgres_series.path, + "patches": patches, + "icuSource": ctx.file.icu_source.path, + })) + output = ctx.actions.declare_directory(ctx.label.name) + arguments = ctx.actions.args() + arguments.add("--spec", specification) + arguments.add("--output", output.path) + arguments.add("--manifest-tool", ctx.executable._manifest_tool) + # Bazel expands TreeArtifacts into their declared leaf paths at execution. + # These leaves are ordinary sandbox projections, not symlink directories + # that the packager should discover through an ambient recursive walk. + tree_arguments = ctx.actions.args() + tree_arguments.add_all(trees, expand_directories = True) + tree_arguments.use_param_file("--tree-files=%s", use_always = True) + tree_arguments.set_param_file_format("multiline") + bun_file_action( + ctx, + ctx.file._packager, + arguments = [arguments, tree_arguments], + inputs = depset(inputs + [specification]), + source_files = ctx.files._helpers, + tools = [ctx.attr._manifest_tool[DefaultInfo].files_to_run], + outputs = [output], + env = {"LC_ALL": "C"}, + mnemonic = "WasixRuntimeEnvelope", + progress_message = "Package declared portable WASIX runtime %{label}", + ) + return [DefaultInfo(files = depset([output]))] + +wasix_runtime_payload = rule( + implementation = _payload_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = { + "runtime": attr.label(providers = [WasmModuleInfo], mandatory = True), + "initdb": attr.label(providers = [WasmModuleInfo], mandatory = True), + "export_policy": attr.label(providers = [WasmExportPolicyInfo], mandatory = True), + "support": attr.label_keyed_string_dict(providers = [WasmModuleInfo], mandatory = True), + "resources": attr.label_keyed_string_dict(allow_files = True, mandatory = True), + "patches": attr.label_list(allow_files = [".patch"], mandatory = True), + "postgres_source": attr.label(default = "//src/third-party/postgres:source.toml", allow_single_file = True), + "postgres_series": attr.label(default = "//src/wasix/runtime:postgres/series", allow_single_file = True), + "icu_source": attr.label(default = "//src/third-party/icu:source.toml", allow_single_file = True), + "_packager": attr.label(default = "//build_defs/wasix:package.mts", allow_single_file = True), + "_helpers": attr.label_list(default = ["//:tools/packaging/archive-directory.mts", "//:tools/packaging/portable-archive.mts"], allow_files = True), + "_manifest_tool": attr.label(default = "//src/wasix/runtime/tools/xtask:xtask", executable = True, cfg = "exec"), + }, +) diff --git a/build_defs/wasix/package.mts b/build_defs/wasix/package.mts new file mode 100644 index 000000000..44b47e596 --- /dev/null +++ b/build_defs/wasix/package.mts @@ -0,0 +1,311 @@ +/** Stage the declared portable runtime files and its deterministic private archive. */ +import { createHash } from 'node:crypto'; +import { + chmod, + copyFile, + lstat, + mkdir, + readdir, + readFile, + realpath, + rm, + stat, + writeFile, +} from 'node:fs/promises'; +import path from 'node:path'; +import { parseArgs } from 'node:util'; +import { createDeterministicTar } from '../../tools/packaging/archive-directory.mts'; +import { + portableMemberName, + releaseZstdCompressSync, +} from '../../tools/packaging/portable-archive.mts'; + +export interface RuntimeEntry { + source: string; + destination: string; + tree?: boolean; + executable?: boolean; +} + +export interface RuntimePayloadSpec { + entries: RuntimeEntry[]; + runtime: string; + initdb: string; + exportPolicy: string; + support: { name: string; source: string; path: string }[]; + postgresSource: string; + postgresSeries: string; + patches: Record; + icuSource: string; +} + +/** Consume Bazel's declared TreeArtifact leaf inventory without walking links. */ +export function expandDeclaredTrees(entries: RuntimeEntry[], files: string[]): RuntimeEntry[] { + const roots = entries.filter((entry) => entry.tree); + const leaves = new Map(roots.map((entry) => [entry, []])); + const seen = new Set(); + for (const file of files) { + if (seen.has(file)) throw new Error(`duplicate declared runtime tree leaf: ${file}`); + seen.add(file); + const owners = roots.filter((entry) => { + const relative = path.relative(path.resolve(entry.source), path.resolve(file)); + return ( + relative && + relative !== '..' && + !relative.startsWith(`..${path.sep}`) && + !path.isAbsolute(relative) + ); + }); + if (owners.length !== 1) + throw new Error(`runtime tree leaf is outside its unique declared directory: ${file}`); + const owner = owners[0]; + const relative = path + .relative(path.resolve(owner.source), path.resolve(file)) + .split(path.sep) + .join('/'); + const ownedLeaves = leaves.get(owner); + if (!ownedLeaves) throw new Error('declared runtime tree owner is missing'); + ownedLeaves.push({ + source: file, + destination: safePath(`${owner.destination}/${relative}`), + executable: owner.executable, + }); + } + return entries.flatMap((entry) => (entry.tree ? (leaves.get(entry) ?? []) : [entry])); +} + +function safePath(value: string): string { + if ( + typeof value !== 'string' || + !value || + value.startsWith('/') || + value.includes('\\') || + value.split('/').some((part) => !part || part === '.' || part === '..') + ) + throw new Error(`unsafe runtime destination: ${value}`); + portableMemberName(value, 'file', value); + return value; +} + +async function treeFiles(directory: string): Promise { + const files: string[] = []; + for (const entry of await readdir(directory, { withFileTypes: true })) { + const file = path.join(directory, entry.name); + const metadata = await lstat(file); + if (metadata.isSymbolicLink()) throw new Error(`runtime input tree contains a link: ${file}`); + if (metadata.isDirectory()) files.push(...(await treeFiles(file))); + else if (metadata.isFile()) files.push(file); + else throw new Error(`runtime input tree contains a special entry: ${file}`); + } + return files.sort(); +} + +export async function stageRuntimeArchive( + entries: RuntimeEntry[], + stage: string, + archive: string, +): Promise { + if (path.basename(stage) !== 'oliphaunt') + throw new Error('runtime archive parent must be oliphaunt'); + const destinations = new Set(); + const modes: Record = {}; + await mkdir(stage, { recursive: true }); + for (const entry of entries) { + safePath(entry.destination); + // Bazel projects ordinary declared files as links. Flatten those leaf links; + // a directory artifact is followed once, then every child must be real. + const source = await realpath(entry.source); + const files = entry.tree ? await treeFiles(source) : [source]; + for (const file of files) { + if (!(await stat(file)).isFile()) throw new Error(`runtime input is not a file: ${file}`); + const destination = safePath( + entry.tree + ? `${entry.destination}/${path.relative(source, file).split(path.sep).join('/')}` + : entry.destination, + ); + if (destination === 'password' || destinations.has(destination)) { + throw new Error(`duplicate runtime destination: ${destination}`); + } + destinations.add(destination); + modes[`oliphaunt/${destination}`] = entry.executable ? 0o755 : 0o644; + const output = path.join(stage, destination); + await mkdir(path.dirname(output), { recursive: true }); + await copyFile(file, output); + await chmod(output, entry.executable ? 0o755 : 0o644); + } + } + await writeFile(path.join(stage, 'password'), 'password\n', { mode: 0o644 }); + for (const required of [ + 'bin/postgres', + 'bin/initdb', + 'lib/postgresql/plpgsql.so', + 'lib/postgresql/dict_snowball.so', + 'share/postgresql/postgres.bki', + 'share/postgresql/system_constraints.sql', + 'share/postgresql/snowball_create.sql', + 'share/postgresql/extension/plpgsql.control', + 'share/postgresql/extension/plpgsql--1.0.sql', + ...['UTC', 'GMT', 'Etc/UTC', 'America/New_York'].map( + (zone) => `share/postgresql/timezone/${zone}`, + ), + ]) { + if (!destinations.has(required)) throw new Error(`runtime payload is missing ${required}`); + } + await writeFile( + archive, + releaseZstdCompressSync(await createDeterministicTar(stage, { keepParent: true, modes })), + ); +} + +function sha256(bytes: Uint8Array | string): string { + return createHash('sha256').update(bytes).digest('hex'); +} + +export async function sourceFacts( + spec: Pick, +) { + const text = async (file: string) => + new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(await readFile(file)); + const postgres = ( + Bun.TOML.parse(await text(spec.postgresSource)) as { + postgresql: { version: string; url: string; sha256: string }; + } + ).postgresql; + if ( + !postgres || + !/^\d+\.\d+$/u.test(postgres.version) || + !/^[0-9a-f]{64}$/u.test(postgres.sha256) + ) { + throw new Error('invalid canonical PostgreSQL source facts'); + } + const series = await text(spec.postgresSeries); + const names = series + .split(/\r?\n/u) + .map((line) => line.trim()) + .filter((line) => line && !line.startsWith('#')); + if (!names.length || new Set(names).size !== names.length) + throw new Error('invalid canonical PostgreSQL patch series'); + const hashes = [sha256(series.replace(/\r\n/gu, '\n'))]; + for (const name of names) { + safePath(name); + if (!name.endsWith('.patch') || !Object.hasOwn(spec.patches, name)) + throw new Error(`undeclared PostgreSQL patch: ${name}`); + hashes.push(sha256((await text(spec.patches[name])).replace(/\r\n/gu, '\n'))); + } + const patchHash = sha256(`${hashes.join('\n')}\n`); + const icu = Bun.TOML.parse(await text(spec.icuSource)) as Record; + if ( + !icu || + typeof icu.name !== 'string' || + typeof icu.url !== 'string' || + typeof icu.branch !== 'string' || + typeof icu.commit !== 'string' + ) { + throw new Error('invalid canonical ICU source facts'); + } + return { + source_fingerprint: `${postgres.version}:${postgres.sha256}:${patchHash}`, + postgres_version: postgres.version, + sources: [ + icu, + { + name: 'postgresql', + url: postgres.url, + branch: `v${postgres.version}`, + commit: postgres.sha256, + }, + { + name: 'oliphaunt-wasix-stable-patches', + url: 'src/wasix/runtime/postgres/series', + branch: 'series', + commit: patchHash, + }, + ], + }; +} + +export async function packageRuntime( + spec: RuntimePayloadSpec, + output: string, + manifestTool: string, +): Promise { + const stage = path.join(output, 'oliphaunt'); + await mkdir(output, { recursive: true }); + const archive = path.join(output, 'oliphaunt.wasix.tar.zst'); + try { + await stageRuntimeArchive(spec.entries, stage, archive); + const initdb = path.join(output, 'bin/initdb.wasix.wasm'); + await mkdir(path.dirname(initdb), { recursive: true }); + await copyFile(spec.initdb, initdb); + await chmod(initdb, 0o644); + const support = []; + const names = new Set(); + for (const item of spec.support) { + safePath(item.path); + if (names.has(item.name)) throw new Error(`duplicate runtime support module: ${item.name}`); + names.add(item.name); + const file = path.join(output, item.path); + await mkdir(path.dirname(file), { recursive: true }); + await copyFile(item.source, file); + await chmod(file, 0o644); + support.push({ name: item.name, path: item.path, source: file }); + } + const manifestSpec = path.join(output, '.manifest-inputs.json'); + await writeFile( + manifestSpec, + JSON.stringify({ + ...(await sourceFacts(spec)), + runtime: spec.runtime, + archive, + initdb, + export_policy: spec.exportPolicy, + support, + }), + ); + const result = Bun.spawnSync( + [ + manifestTool, + 'assets', + 'declared-manifest', + '--spec', + manifestSpec, + '--output', + path.join(output, 'manifest.json'), + ], + { + stdout: 'inherit', + stderr: 'inherit', + env: { ...process.env, LC_ALL: 'C' }, + }, + ); + if (result.exitCode !== 0) + throw new Error(`runtime manifest tool failed with exit ${result.exitCode}`); + await rm(manifestSpec); + } finally { + await rm(stage, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + const { values } = parseArgs({ + options: { + spec: { type: 'string' }, + output: { type: 'string' }, + 'manifest-tool': { type: 'string' }, + 'tree-files': { type: 'string' }, + }, + }); + if (!values.spec || !values.output || !values['manifest-tool']) + throw new Error('--spec, --output and --manifest-tool are required'); + const spec = JSON.parse( + new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(await readFile(values.spec)), + ) as RuntimePayloadSpec; + if (values['tree-files']) { + const leaves = new TextDecoder('utf-8', { fatal: true }) + .decode(await readFile(values['tree-files'])) + .split('\n') + .filter(Boolean); + spec.entries = expandDeclaredTrees(spec.entries, leaves); + } + await packageRuntime(spec, values.output, values['manifest-tool']); +} diff --git a/build_defs/wasix/package.test.mts b/build_defs/wasix/package.test.mts new file mode 100644 index 000000000..79700b73d --- /dev/null +++ b/build_defs/wasix/package.test.mts @@ -0,0 +1,200 @@ +import { afterEach, expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdir, mkdtemp, readFile, rm, symlink, writeFile } from 'node:fs/promises'; +import os from 'node:os'; +import path from 'node:path'; +import { zstdDecompressSync } from 'node:zlib'; +import { readPortableArchiveEntries } from '../../tools/packaging/portable-archive.mts'; +import { + expandDeclaredTrees, + type RuntimeEntry, + sourceFacts, + stageRuntimeArchive, +} from './package.mts'; + +const roots: string[] = []; +afterEach(async () => { + await Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true }))); +}); + +async function fixture() { + const root = await mkdtemp(path.join(os.tmpdir(), 'oliphaunt-wasix-package-')); + roots.push(root); + const file = path.join(root, 'bytes'); + await writeFile(file, '\0asm\x01\0\0\0'); + const timezone = path.join(root, 'zones'); + for (const name of ['UTC', 'GMT', 'Etc/UTC', 'America/New_York']) { + const zone = path.join(timezone, name); + await mkdir(path.dirname(zone), { recursive: true }); + await writeFile(zone, `TZif${name}`); + } + const entries: RuntimeEntry[] = [ + ...[ + 'bin/postgres', + 'bin/initdb', + 'lib/postgresql/plpgsql.so', + 'lib/postgresql/dict_snowball.so', + ].map((destination) => ({ source: file, destination, executable: true })), + ...[ + 'postgres.bki', + 'system_constraints.sql', + 'snowball_create.sql', + 'extension/plpgsql.control', + 'extension/plpgsql--1.0.sql', + ].map((name) => ({ source: file, destination: `share/postgresql/${name}` })), + { source: timezone, destination: 'share/postgresql/timezone', tree: true }, + ]; + return { root, file, timezone, entries }; +} + +test('runtime archive has independent readable payload, fixed prefix/modes and deterministic bytes', async () => { + const { root, file, entries } = await fixture(); + const link = path.join(root, 'projected-input'); + await symlink(file, link); + entries[0].source = link; + const first = path.join(root, 'first.tar.zst'); + const second = path.join(root, 'second.tar.zst'); + await stageRuntimeArchive(entries, path.join(root, 'first/oliphaunt'), first); + await stageRuntimeArchive([...entries].reverse(), path.join(root, 'second/oliphaunt'), second); + expect(await readFile(first)).toEqual(await readFile(second)); + const raw = zstdDecompressSync(await readFile(first)); + const oracle = await new Bun.Archive(raw).files(); + expect(await oracle.get('oliphaunt/password')?.text()).toBe('password\n'); + const postgres = oracle.get('oliphaunt/bin/postgres'); + if (!postgres) throw new Error('independent archive reader found no postgres module'); + expect(Buffer.from(await postgres.arrayBuffer())).toEqual(await readFile(file)); + expect([...oracle.keys()].filter((name) => !name.endsWith('/')).sort()).toEqual( + [ + ...entries.filter((entry) => !entry.tree).map((entry) => `oliphaunt/${entry.destination}`), + ...['UTC', 'GMT', 'Etc/UTC', 'America/New_York'].map( + (zone) => `oliphaunt/share/postgresql/timezone/${zone}`, + ), + 'oliphaunt/password', + ].sort(), + ); + const strict = readPortableArchiveEntries(first, { format: 'tar.zst' }); + expect(strict.get('oliphaunt/bin/postgres')?.mode).toBe(0o755); + expect(strict.get('oliphaunt/share/postgresql/postgres.bki')?.mode).toBe(0o644); +}); + +test('runtime staging rejects omitted files, duplicate and unsafe destinations', async () => { + const { root, file, entries } = await fixture(); + const run = (items: RuntimeEntry[], name: string) => + stageRuntimeArchive( + items, + path.join(root, `${name}/oliphaunt`), + path.join(root, `${name}.tar.zst`), + ); + await expect( + run( + entries.filter((entry) => entry.destination !== 'bin/initdb'), + 'missing', + ), + ).rejects.toThrow('missing bin/initdb'); + for (const [index, destination] of [ + 'password', + 'bin/postgres', + '../outside', + './alias', + 'nested/../outside', + '/absolute', + 'back\\slash', + ].entries()) { + await expect( + run([...entries, { source: file, destination }], `bad-${index}`), + ).rejects.toThrow(); + } +}); + +test('runtime directory artifacts cannot add linked files or directories', async () => { + const { root, file, timezone, entries } = await fixture(); + await symlink(file, path.join(timezone, 'linked-file')); + await expect( + stageRuntimeArchive( + entries, + path.join(root, 'file-link/oliphaunt'), + path.join(root, 'file.tar.zst'), + ), + ).rejects.toThrow('input tree contains a link'); + await rm(path.join(timezone, 'linked-file')); + await symlink(root, path.join(timezone, 'linked-directory')); + await expect( + stageRuntimeArchive( + entries, + path.join(root, 'directory-link/oliphaunt'), + path.join(root, 'directory.tar.zst'), + ), + ).rejects.toThrow('input tree contains a link'); +}); + +test('declared TreeArtifact leaves preserve nested destinations and reject undeclared or duplicate paths', async () => { + const { root, file, entries, timezone } = await fixture(); + const leaves = ['UTC', 'GMT', 'Etc/UTC', 'America/New_York'].map((name) => + path.join(timezone, name), + ); + const projected = expandDeclaredTrees(entries, leaves); + expect(projected.some((entry) => entry.tree)).toBe(false); + expect( + projected.find((entry) => entry.source.endsWith(path.join('America', 'New_York')))?.destination, + ).toBe('share/postgresql/timezone/America/New_York'); + await expect( + stageRuntimeArchive( + projected, + path.join(root, 'declared/oliphaunt'), + path.join(root, 'declared.tar.zst'), + ), + ).resolves.toBeUndefined(); + expect(() => expandDeclaredTrees(entries, [file])).toThrow( + 'outside its unique declared directory', + ); + expect(() => expandDeclaredTrees(entries, [leaves[0], leaves[0]])).toThrow( + 'duplicate declared runtime tree leaf', + ); + expect(() => + expandDeclaredTrees( + [...entries, { source: timezone, destination: 'overlap', tree: true }], + leaves, + ), + ).toThrow('outside its unique declared directory'); +}); + +test('source receipt hashes only the declared series in order and normalizes CRLF like the Rust authority', async () => { + const { root } = await fixture(); + const postgresSource = path.join(root, 'postgres.toml'); + const postgresSeries = path.join(root, 'series'); + const icuSource = path.join(root, 'icu.toml'); + const patch = path.join(root, 'one.patch'); + const sourceSha = 'a'.repeat(64); + const series = 'src/wasix/runtime/one.patch\n'; + const bytes = '--- old\n+++ new\n'; + await writeFile( + postgresSource, + `[postgresql]\nversion = "18.4"\nurl = "https://source.test/pg.tar.bz2"\nsha256 = "${sourceSha}"\n`, + ); + await writeFile( + icuSource, + 'name = "icu"\nurl = "https://source.test/icu.git"\nbranch = "release-76-1"\ncommit = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"\n', + ); + await writeFile(postgresSeries, series); + await writeFile(patch, bytes); + const facts = { + postgresSource, + postgresSeries, + icuSource, + patches: { 'src/wasix/runtime/one.patch': patch }, + }; + const digest = (value: string) => createHash('sha256').update(value).digest('hex'); + const patchSha = digest(`${digest(series)}\n${digest(bytes)}\n`); + const result = await sourceFacts(facts); + expect(result.source_fingerprint).toBe(`18.4:${sourceSha}:${patchSha}`); + expect(result.postgres_version).toBe('18.4'); + expect(result.sources.at(-1)?.commit).toBe(patchSha); + await writeFile(postgresSeries, series.replaceAll('\n', '\r\n')); + await writeFile(patch, bytes.replaceAll('\n', '\r\n')); + expect(await sourceFacts(facts)).toEqual(result); + await expect(sourceFacts({ ...facts, patches: {} })).rejects.toThrow( + 'undeclared PostgreSQL patch', + ); + await writeFile(patch, bytes.replaceAll('\n', '\r')); + expect((await sourceFacts(facts)).source_fingerprint).not.toBe(result.source_fingerprint); +}); diff --git a/build_defs/wasix/platform.bzl b/build_defs/wasix/platform.bzl new file mode 100644 index 000000000..703cf161a --- /dev/null +++ b/build_defs/wasix/platform.bzl @@ -0,0 +1,30 @@ +"""Configure WASIX payload producers independently of their host consumers.""" + +def _payload_profile_impl(_settings, _attr): + # Cargo payload construction keeps the pinned Rust defaults, outside addon link policy. + return {"@rules_rust//rust/settings:lto": "unspecified", "@rules_rust//rust/settings:codegen_units": -1, + "@rules_rust//rust/settings:extra_rustc_flags": []} + +WASIX_PAYLOAD_PROFILE = transition(implementation = _payload_profile_impl, inputs = [], outputs = [ + "@rules_rust//rust/settings:lto", "@rules_rust//rust/settings:codegen_units", "@rules_rust//rust/settings:extra_rustc_flags", +]) + +def _portable_impl(_settings, _attr): + return {"//command_line_option:platforms": [str(Label("//build_defs/wasix:portable"))]} + +WASIX_PORTABLE_TRANSITION = transition( + implementation = _portable_impl, + inputs = [], + outputs = ["//command_line_option:platforms"], +) + +def _artifact_impl(ctx): + return [ctx.attr.artifact[0][DefaultInfo]] + +wasix_artifact = rule( + implementation = _artifact_impl, + attrs = { + "artifact": attr.label(mandatory = True, cfg = WASIX_PORTABLE_TRANSITION), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), + }, +) diff --git a/build_defs/wasix/postgres.BUILD.bazel b/build_defs/wasix/postgres.BUILD.bazel new file mode 100644 index 000000000..aea37a6a0 --- /dev/null +++ b/build_defs/wasix/postgres.BUILD.bazel @@ -0,0 +1,19 @@ +load("@rules_cc//cc:defs.bzl", "cc_library") +load("@oliphaunt//build_defs/wasix:postgres.bzl", "postgres_wasix_targets") +load(":version.bzl", "POSTGRES_VERSION") + +package(default_visibility = ["//visibility:public"]) + +exports_files(glob(["contrib/**", "src/include/**/*.h"])) + +# These real patched headers supply the SysV declarations used by the bridge +# and by PostgreSQL's wasm32 port; they are absent from the WASIX libc sysroot. +cc_library( + name = "port_headers", + linkstatic = True, + hdrs = glob(["src/include/port/wasix-dl/**/*.h"]), + includes = ["src/include/port/wasix-dl"], + target_compatible_with = ["@platforms//cpu:wasm32", "@platforms//os:wasi"], +) + +postgres_wasix_targets(version = POSTGRES_VERSION) diff --git a/build_defs/wasix/postgres.bzl b/build_defs/wasix/postgres.bzl new file mode 100644 index 000000000..b3e57cbd0 --- /dev/null +++ b/build_defs/wasix/postgres.bzl @@ -0,0 +1,103 @@ +"""Actual wasm32 PostgreSQL compilation, with separate backend/frontend roles.""" + +load("@rules_cc//cc:defs.bzl", _cc_library = "cc_library") +load("@rules_cc_autoconf//autoconf:autoconf.bzl", "autoconf") +load("@rules_cc_autoconf//autoconf:autoconf_hdr.bzl", "autoconf_hdr") +load("@rules_cc_autoconf//autoconf:autoconf_srcs.bzl", "autoconf_srcs") +load("@rules_cc_autoconf//autoconf:checks.bzl", "checks") +load("//build_defs/native:config.bzl", "pg_config_layout", "postgres_configuration_values") +load("//build_defs/native:host_config.bzl", "postgres_capability_checks") +load("//build_defs/native:postgres.bzl", "postgres_generated_targets", "postgres_frontend_generated_targets", "postgres_resource_targets") +load("//build_defs/native:resources.bzl", "timezone_database") +load("//build_defs/native:frontend_sources.bzl", "POSTGRES_DUMP_COMMON_SOURCES", "POSTGRES_DUMP_SOURCES", "POSTGRES_PSQL_SOURCES") +load("//build_defs/native:postgres_sources.bzl", "POSTGRES_FRONTEND_UTIL_SOURCES") +load("//build_defs/native:postgres_sources.bzl", "POSTGRES_BACKEND_SOURCES", "POSTGRES_BACKEND_LINUX_SOURCES", "POSTGRES_BACKEND_GENERATED_SOURCES", "POSTGRES_BACKEND_TEXTUAL_SOURCES", "POSTGRES_BACKEND_INCLUDE_DIRECTORIES", "POSTGRES_CATALOG_GENERATED_HEADERS", "POSTGRES_NODE_GENERATED_TEXTUAL_SOURCES", "POSTGRES_WAIT_EVENT_GENERATED_TEXTUAL_SOURCES", "POSTGRES_BACKEND_GENERATED_HEADERS", "POSTGRES_COMMON_GENERATED_HEADERS", "POSTGRES_PLPGSQL_GENERATED_HEADERS", "POSTGRES_COMMON_SOURCES", "POSTGRES_COMMON_RYU_SOURCES", "POSTGRES_COMMON_CONFIG_INFO_SOURCES", "POSTGRES_COMMON_BUILTIN_CRYPTO_SOURCES", "POSTGRES_COMMON_FRONTEND_SHARED_ADDITIONAL_SOURCES", "POSTGRES_COMMON_FRONTEND_STATIC_ADDITIONAL_SOURCES", "POSTGRES_PORT_SOURCES", "POSTGRES_PORT_REPLACEMENT_SOURCES", "POSTGRES_PORT_CRC_GENERIC_SOURCES", "POSTGRES_TIMEZONE_SOURCES", "POSTGRES_MAIN_SOURCES", "POSTGRES_PLPGSQL_SOURCES", "POSTGRES_PLPGSQL_GENERATED_SOURCES", "POSTGRES_SNOWBALL_SOURCES", "POSTGRES_LIBPQ_SOURCES", "POSTGRES_INITDB_SOURCES") +load(":config.bzl", "WASIX_POLICY", "WASIX_COPTS", "WASIX_DEFINES") + +_COMPATIBLE = ["@platforms//cpu:wasm32", "@platforms//os:wasi"] +_INITDB_IDENTITY_DEFINES = [name + "=oliphaunt_wasix_" + name for name in ["geteuid", "getuid", "getegid", "getgid", "getpwuid", "getpwuid_r"]] + +def cc_library(**kwargs): + _cc_library(linkstatic = True, **kwargs) + +def postgres_wasix_targets(version): + # Probe libc itself, before the backend's host-I/O symbol redirections. + definitions = ["_GNU_SOURCE"] + policy = postgres_configuration_values(version, WASIX_POLICY, "wasm32 WASIX") + facts = postgres_capability_checks(WASIX_COPTS, definitions, abi = False, excluded = ["HAVE_SYSLOG", "HAVE_PTHREAD_PRIO_INHERIT"]) + facts += [checks.AC_TRY_LINK(code = "#include \ndouble (*volatile required_math)(double) = exp; int main(void) { return required_math(1.0) > 0; }", define = "HAVE_LIBM", copts = WASIX_COPTS, linkopts = ["-lm"], if_false = None)] + autoconf(name = "configuration_facts", checks = [checks.AC_DEFINE(d, 1) for d in definitions + ["__STDC_WANT_LIB_EXT1__"]] + facts + [checks.AC_DEFINE(key, value) for key, value in policy.items()], visibility = ["//visibility:private"], target_compatible_with = _COMPATIBLE) + autoconf_hdr(name = "configuration_header", out = "src/include/pg_config.h", template = "src/include/pg_config.h.in", deps = [":configuration_facts"], defaults = False, visibility = ["//visibility:private"], target_compatible_with = _COMPATIBLE) + pg_config_layout(name = "configuration_layout", os_header = "src/include/port/wasix-dl.h", output_directory = "src/include", prefix = "", visibility = ["//visibility:private"], target_compatible_with = _COMPATIBLE) + native.filegroup(name = "configuration", srcs = [":configuration_header", ":configuration_layout"], target_compatible_with = _COMPATIBLE) + _cc_library(name = "configuration_contract", srcs = ["@oliphaunt//build_defs/wasix:config_probe.c"], hdrs = [":configuration"], includes = ["src/include"], copts = WASIX_COPTS, linkstatic = True, visibility = ["@oliphaunt//build_defs/wasix:__pkg__"], target_compatible_with = _COMPATIBLE) + autoconf_srcs(name = "conditional_port_replacements", srcs = {source: "!ac_cv_func_" + macro[len("HAVE_"):].lower() for macro, source in POSTGRES_PORT_REPLACEMENT_SOURCES.items()}, deps = [":configuration_facts"], defaults = False, visibility = ["//visibility:private"], target_compatible_with = _COMPATIBLE) + postgres_generated_targets(version) + postgres_frontend_generated_targets() + postgres_resource_targets() + timezone_database(name = "timezone_data", source = "src/timezone/data/tzdata.zi", zic = "@postgres//:zic", posixrules = "") + native.filegroup(name = "tsearch_dictionaries", srcs = native.glob(["src/backend/tsearch/dicts/*"])) + native.filegroup(name = "wasix_timezone_abbreviations", srcs = native.glob(["src/timezone/tznames/*"], exclude = ["src/timezone/tznames/README", "src/timezone/tznames/Makefile", "src/timezone/tznames/meson.build"])) + generated_headers = POSTGRES_CATALOG_GENERATED_HEADERS + POSTGRES_NODE_GENERATED_TEXTUAL_SOURCES + POSTGRES_WAIT_EVENT_GENERATED_TEXTUAL_SOURCES + POSTGRES_BACKEND_GENERATED_HEADERS + POSTGRES_COMMON_GENERATED_HEADERS + POSTGRES_PLPGSQL_GENERATED_HEADERS + for role, definitions in [("server", WASIX_DEFINES), ("frontend", ["_GNU_SOURCE"])]: + cc_library( + name = role + "_headers", + hdrs = native.glob(["src/include/**/*.h", "src/backend/**/*.h", "src/common/**/*.h", "src/pl/plpgsql/src/*.h", "src/interfaces/libpq/*.h", "src/timezone/*.h"]) + generated_headers + [":configuration"], + textual_hdrs = POSTGRES_BACKEND_TEXTUAL_SOURCES, + includes = ["src/include/port/wasix-dl"] + POSTGRES_BACKEND_INCLUDE_DIRECTORIES + ["src/common", "src/pl/plpgsql/src", "src/interfaces/libpq", "src/include/snowball", "src/timezone"], + defines = definitions, + deps = ["@icu_wasix//:i18n_headers", ":configuration_contract"], + target_compatible_with = _COMPATIBLE, + ) + common = POSTGRES_COMMON_SOURCES + POSTGRES_COMMON_RYU_SOURCES + POSTGRES_COMMON_CONFIG_INFO_SOURCES + POSTGRES_COMMON_BUILTIN_CRYPTO_SOURCES + port = POSTGRES_PORT_SOURCES + POSTGRES_PORT_CRC_GENERIC_SOURCES + [":conditional_port_replacements"] + for role, definitions, additions in [ + ("server", [], []), + ("frontend", ["FRONTEND", "USE_PRIVATE_ENCODING_FUNCS"] + _INITDB_IDENTITY_DEFINES, POSTGRES_COMMON_FRONTEND_SHARED_ADDITIONAL_SOURCES + POSTGRES_COMMON_FRONTEND_STATIC_ADDITIONAL_SOURCES), + ]: + cc_library(name = "common_" + role, srcs = common + additions, local_defines = definitions, deps = [":" + role + "_headers"], copts = WASIX_COPTS, target_compatible_with = _COMPATIBLE) + cc_library(name = "port_" + role, srcs = port, local_defines = definitions, deps = [":" + role + "_headers"], copts = WASIX_COPTS, target_compatible_with = _COMPATIBLE) + cc_library(name = "timezone", srcs = POSTGRES_TIMEZONE_SOURCES, deps = [":server_headers"], copts = WASIX_COPTS, target_compatible_with = _COMPATIBLE) + cc_library(name = "backend", srcs = POSTGRES_BACKEND_SOURCES + POSTGRES_BACKEND_LINUX_SOURCES + POSTGRES_BACKEND_GENERATED_SOURCES, + deps = [":server_headers", ":common_server", ":port_server", ":timezone"], local_defines = ["OLIPHAUNT_WASM_SINGLE_BACKEND_ATOMICS"], copts = WASIX_COPTS, alwayslink = True, target_compatible_with = _COMPATIBLE) + cc_library(name = "main", srcs = POSTGRES_MAIN_SOURCES, deps = [":server_headers"], local_defines = ["OLIPHAUNT_WASM_SINGLE_BACKEND_ATOMICS"], copts = WASIX_COPTS, target_compatible_with = _COMPATIBLE) + cc_library(name = "plpgsql", srcs = POSTGRES_PLPGSQL_SOURCES + POSTGRES_PLPGSQL_GENERATED_SOURCES, deps = [":server_headers"], copts = WASIX_COPTS, alwayslink = True, target_compatible_with = _COMPATIBLE) + cc_library(name = "snowball", srcs = POSTGRES_SNOWBALL_SOURCES, deps = [":server_headers"], copts = WASIX_COPTS, alwayslink = True, target_compatible_with = _COMPATIBLE) + # This command-private libpq uses initdb's encoding/identity profile. + # Keep the public libpq-facing tools closure independent below. + cc_library(name = "libpq", srcs = POSTGRES_LIBPQ_SOURCES, deps = [":frontend_headers", ":common_frontend", ":port_frontend"], + local_defines = ["FRONTEND", "SO_MAJOR_VERSION=5", "USE_PRIVATE_ENCODING_FUNCS"] + _INITDB_IDENTITY_DEFINES, copts = WASIX_COPTS, target_compatible_with = _COMPATIBLE) + initdb_utils = ["src/fe_utils/option_utils.c", "src/fe_utils/string_utils.c"] + cc_library(name = "initdb_frontend_utils", srcs = initdb_utils, + deps = [":frontend_headers", ":common_frontend", ":port_frontend", ":libpq"], local_defines = ["FRONTEND", "USE_PRIVATE_ENCODING_FUNCS"] + _INITDB_IDENTITY_DEFINES, copts = WASIX_COPTS, target_compatible_with = _COMPATIBLE) + cc_library(name = "initdb_objects", srcs = POSTGRES_INITDB_SOURCES, + deps = [":frontend_headers", ":common_frontend", ":port_frontend", ":libpq", ":initdb_frontend_utils"], + local_defines = ["FRONTEND", "USE_PRIVATE_ENCODING_FUNCS"] + _INITDB_IDENTITY_DEFINES + [name + "=oliphaunt_wasix_initdb_" + name for name in ["system", "popen", "pclose"]], copts = WASIX_COPTS, target_compatible_with = _COMPATIBLE) + cc_library(name = "tools_headers", hdrs = native.glob(["src/bin/pg_dump/*.h", "src/bin/pg_basebackup/*.h", "src/bin/psql/*.h"]) + ["src/bin/psql/sql_help.h"], + deps = [":frontend_headers"], includes = ["src/bin/pg_dump", "src/bin/pg_basebackup", "src/bin/psql"], target_compatible_with = _COMPATIBLE) + # The canonical frontend-tools profile intentionally avoids ThinLTO. Keep + # its shared archives separate from initdb's release objects, with one + # compiled instance per source/profile and shared maintained headers. + tools_copts = [option for option in WASIX_COPTS if option != "-flto=thin"] + # Standalone tools use libpq's public encoding names. Project its shared + # common profile plus the static-only memory/logging files once, rather + # than linking both encnames variants with duplicated global tables. + # PostgreSQL applies PQExpBuffer only to jsonapi_shlib.o. + cc_library(name = "common_tools_json", srcs = ["src/common/jsonapi.c"], + local_defines = ["FRONTEND", "JSONAPI_USE_PQEXPBUFFER"], deps = [":frontend_headers"], copts = tools_copts, target_compatible_with = _COMPATIBLE) + cc_library(name = "common_tools", srcs = [source for source in common if source != "src/common/jsonapi.c"] + POSTGRES_COMMON_FRONTEND_SHARED_ADDITIONAL_SOURCES + POSTGRES_COMMON_FRONTEND_STATIC_ADDITIONAL_SOURCES, + local_defines = ["FRONTEND"], deps = [":frontend_headers", ":common_tools_json"], copts = tools_copts, target_compatible_with = _COMPATIBLE) + cc_library(name = "port_tools", srcs = port, local_defines = ["FRONTEND"], deps = [":frontend_headers"], copts = tools_copts, target_compatible_with = _COMPATIBLE) + cc_library(name = "libpq_tools", srcs = POSTGRES_LIBPQ_SOURCES, deps = [":frontend_headers", ":common_tools", ":port_tools"], + local_defines = ["FRONTEND", "SO_MAJOR_VERSION=5"], copts = tools_copts, target_compatible_with = _COMPATIBLE) + cc_library(name = "frontend_utils_tools", srcs = POSTGRES_FRONTEND_UTIL_SOURCES + ["src/fe_utils/psqlscan.c"], + deps = [":frontend_headers", ":common_tools", ":port_tools", ":libpq_tools"], local_defines = ["FRONTEND"], copts = tools_copts, target_compatible_with = _COMPATIBLE) + frontend_deps = [":frontend_headers", ":common_tools", ":port_tools", ":libpq_tools", ":frontend_utils_tools", ":tools_headers"] + # Patch 0025's no-fork stub uses SINGLE_USER. Scope it to parallel.c, + # which has no UID/pwd/SysV calls, rather than changing every frontend ABI. + cc_library(name = "dump_parallel", srcs = ["src/bin/pg_dump/parallel.c"], deps = frontend_deps, + local_defines = ["FRONTEND", "OLIPHAUNT_WASM_SINGLE_USER"], copts = tools_copts, target_compatible_with = _COMPATIBLE) + cc_library(name = "dump_common", srcs = [source for source in POSTGRES_DUMP_COMMON_SOURCES if source != "src/bin/pg_dump/parallel.c"], deps = frontend_deps + [":dump_parallel"], local_defines = ["FRONTEND"], copts = tools_copts, target_compatible_with = _COMPATIBLE) + cc_library(name = "pg_dump_objects", srcs = POSTGRES_DUMP_SOURCES, deps = frontend_deps + [":dump_common"], local_defines = ["FRONTEND"], copts = tools_copts, target_compatible_with = _COMPATIBLE) + cc_library(name = "psql_objects", srcs = POSTGRES_PSQL_SOURCES + ["src/bin/psql/psqlscanslash.c", "src/bin/psql/tab-complete.c", "src/bin/psql/sql_help.c"], + deps = frontend_deps, local_defines = ["FRONTEND"], copts = tools_copts, target_compatible_with = _COMPATIBLE) diff --git a/build_defs/wasix/postmaster/BUILD.bazel b/build_defs/wasix/postmaster/BUILD.bazel new file mode 100644 index 000000000..493c27044 --- /dev/null +++ b/build_defs/wasix/postmaster/BUILD.bazel @@ -0,0 +1,155 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/foundation:bun.bzl", "bun_script_test", "bun_test") +load(":postgres-overlay-test.bzl", "postgres_overlay_tests") +load(":runtime-probe.bzl", "postmaster_runtime_probes") +load("@postmaster_compile_metadata//:cargo.bzl", "POSTMASTER_CARGO") +load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") + +package(default_visibility = ["//visibility:public"]) + +exports_files(glob(["*.bzl", "*.mts", "*.patch"])) + +exports_files(["postgres.BUILD.bazel", "libc.BUILD.bazel", "postgres-abi.c"]) +exports_files(["runtime-probe.rs"]) + +cc_library(name = "linked_unwinder", srcs = ["unwinder.c"], linkstatic = True, alwayslink = True) + +cc_test( + name = "linked_unwinder_present_test", + srcs = ["unwinder-test.c"], + defines = ["TEST_LINKED_LIBUNWIND"], + deps = [":linked_unwinder"], + target_compatible_with = ["@platforms//os:linux"], + size = "small", +) + +cc_test( + name = "linked_unwinder_absent_test", + srcs = ["unwinder-test.c"], + deps = [":linked_unwinder"], + target_compatible_with = ["@platforms//os:linux"], + size = "small", +) + +postmaster_runtime_probes() + +bun_test(name = "native_receipts_test", entry_point = "native-receipts.test.mts", data = ["native-receipts.mts"], size = "small") + +bun_test( + name = "guest_inputs_test", + entry_point = "guest-inputs.test.mts", + data = ["guest-inputs.mts", "native-receipts.mts", "//:tools/packaging/strict-json.mts", + "//src/wasix/postmaster:lib/guest-build-provenance.mts", + "//src/wasix/postmaster:wasmer/policies/sealed-side-modules.v1.tsv"], + size = "small", +) + +bun_test( + name = "receipt_reader_test", + entry_point = "receipt-reader.test.mts", + data = [ + "//src/wasix/postmaster:lib/verify-sealed-carrier.mts", + "//src/wasix/postmaster:lib/guest-build-provenance.mts", + "//src/wasix/postmaster:lib/linear-memory-profile.mts", + "//src/wasix/postmaster:lib/receipt-files.mts", + "//src/wasix/postmaster:lib/sealed-export-chain.mts", + "//src/wasix/postmaster:wasmer/bin/verify-postmaster-concurrency-contract.mts", + "//src/wasix/postmaster:wasmer/bin/verify-postmaster-wasm-import.mts", + "//src/wasix/postmaster:wasmer/policies/sealed-side-modules.v1.tsv", + "//:tools/packaging/strict-json.mts", + ], + size = "small", +) + +postgres_overlay_tests() + +bun_test( + name = "qualification_profile_test", + entry_point = "qualification-profile.test.mts", + data = ["qualification-profile.mts", "//src/wasix/postmaster:lib/common.sh"], + size = "small", +) + +bun_test( + name = "seal_modules_test", + entry_point = "seal-modules.test.mts", + data = [ + "seal-modules.mts", + "guest-inputs.mts", + "native-receipts.mts", + "//:tools/packaging/strict-json.mts", + "//src/wasix/postmaster:wasmer/policies/sealed-side-modules.v1.tsv", + "//src/wasix/postmaster:lib/linear-memory-profile.mts", + "//src/wasix/postmaster:lib/receipt-files.mts", + "//src/wasix/postmaster:lib/sealed-export-chain.mts", + "//src/wasix/postmaster:wasmer/bin/verify-postmaster-wasm-import.mts", + "//src/wasix/postmaster:wasmer/bin/verify-postmaster-concurrency-contract.mts", + ], + size = "small", +) + +bun_test( + name = "libc_metadata_test", + entry_point = "libc-metadata.test.mts", + data = ["libc-metadata.mts"], + size = "small", +) + +bun_test( + name = "libc_headers_test", + entry_point = "libc-headers.test.mts", + data = ["libc-headers.mts", "testdata/mkalltypes.sed"], + size = "small", +) + +bun_test( + name = "source_modes_test", + entry_point = "source-modes.test.mts", + data = ["source-modes.mts"], + size = "small", + target_compatible_with = ["@platforms//os:linux"], +) + +alias(name = "llvm_zstd", actual = POSTMASTER_CARGO["compiler_zstd"]) + +bun_test( + name = "compile_metadata_test", + entry_point = "compile-metadata.test.mts", + data = ["compile-metadata.mts"], + size = "small", +) + +bun_test( + name = "runtime_abi_test", + entry_point = "runtime-abi.test.mts", + data = ["runtime-abi.mts", "compile-metadata.mts"], + size = "small", +) + +bun_test( + name = "metadata_test", + entry_point = "metadata.test.mts", + data = ["metadata.mts", "//:tools/packaging/cargo-manifest.mts"], + size = "small", +) + +bun_script_test( + name = "cargo_source_projection_test", + entry_point = "cargo-source-projection-test.mts", + data = [ + "@postmaster_cargo//:cargo-sources.json", + "@postmaster_cargo//:executor/Cargo.toml", + "@postmaster_cargo//:executor/Cargo.lock", + "@postmaster_cargo//:compiler/Cargo.toml", + "@postmaster_cargo//:compiler/Cargo.lock", + "@postmaster_executor_crates//:cargo-bazel.json", + "@postmaster_executor_crates//:crates.bzl", + "@postmaster_compiler_crates//:cargo-bazel.json", + "@postmaster_compiler_crates//:crates.bzl", + "//src/wasix/postmaster:executor/Cargo.toml", + "//src/wasix/postmaster:executor/Cargo.lock", + ], + size = "small", +) + +source_quality_files() diff --git a/build_defs/wasix/postmaster/aot.bzl b/build_defs/wasix/postmaster/aot.bzl new file mode 100644 index 000000000..d83f7b277 --- /dev/null +++ b/build_defs/wasix/postmaster/aot.bzl @@ -0,0 +1,48 @@ +"""One declared LLVM compilation and admission check per sealed module.""" + +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") + +PostmasterModulesInfo = provider(fields = ["modules"]) + +def postmaster_module_outputs(ctx, paths): + return {path: ctx.actions.declare_file(ctx.label.name + ".aot-inputs/" + path) for path in paths} + +def _aot_impl(ctx): + relative = ctx.attr.module_path + if not relative or relative.startswith("/") or any([part in ["", ".", ".."] for part in relative.split("/")]): + fail("Invalid sealed module path: " + relative) + module = ctx.attr.sealed[PostmasterModulesInfo].modules.get(relative) + if module == None or not module.path.endswith("/" + relative): + fail("Postmaster AOT module is absent from the declared sealed outputs: " + relative) + artifact = ctx.actions.declare_file(ctx.label.name + ".bin") + receipt = ctx.actions.declare_file(ctx.label.name + ".json") + arguments = ctx.actions.args() + arguments.add_all([ctx.executable._compiler, ctx.file._abi, module.path.removesuffix(relative), relative, artifact, receipt], expand_directories = False) + bun_file_action( + ctx, + ctx.file._writer, + arguments = [arguments], + source_files = [ctx.file._writer], + inputs = [module, ctx.file._abi], + tools = [ctx.attr._compiler[DefaultInfo].files_to_run], + outputs = [artifact, receipt], + mnemonic = "PostmasterLlvmAot", + progress_message = "Compile and verify sealed postmaster AOT %{label}", + resource_set = _resources, + ) + return [DefaultInfo(files = depset([artifact])), OutputGroupInfo(receipt = depset([receipt]))] + +def _resources(_os, _input_count): + return {"cpu": 1, "memory": 4096} + +postmaster_aot = rule( + implementation = _aot_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = { + "sealed": attr.label(mandatory = True, providers = [PostmasterModulesInfo]), + "module_path": attr.string(mandatory = True), + "_compiler": attr.label(default = "//src/wasix/postmaster:compiler", cfg = "exec", executable = True), + "_abi": attr.label(default = "//src/wasix/postmaster:runtime_abi_contract", cfg = "exec", allow_single_file = True), + "_writer": attr.label(default = "//build_defs/wasix/postmaster:aot.mts", allow_single_file = True), + }, +) diff --git a/build_defs/wasix/postmaster/aot.mts b/build_defs/wasix/postmaster/aot.mts new file mode 100644 index 000000000..8eb4f2e07 --- /dev/null +++ b/build_defs/wasix/postmaster/aot.mts @@ -0,0 +1,77 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { readFileSync, statSync, writeFileSync } from 'node:fs'; +import { join, resolve } from 'node:path'; + +const identity = (file: string) => { + // These are exact declared action paths; Bazel may project input files and + // executable tools as sandbox symlinks. Shipped carrier members use the + // separate no-follow inventory validator. + assert(statSync(file).isFile(), `Expected regular AOT input/output: ${file}`); + const bytes = readFileSync(file); + return { sha256: createHash('sha256').update(bytes).digest('hex'), size: bytes.length }; +}; + +if (import.meta.main) { + const [compilerArg, abiPath, sealed, relative, artifact, receipt] = Bun.argv.slice(2); + assert.equal(Bun.argv.length, 8, 'usage: aot.mts COMPILER ABI SEALED MODULE ARTIFACT RECEIPT'); + const compiler = resolve(compilerArg); + assert( + relative && + !relative.startsWith('/') && + relative.split('/').every((part) => part && part !== '.' && part !== '..'), + ); + const module = join(sealed, relative); + const moduleIdentity = identity(module); + const abi = JSON.parse(readFileSync(abiPath, 'utf8')); + assert.equal(abi.schema, 'oliphaunt.wasix-postmaster.runtime-abi.native.v2'); + assert.match(abi.runtime_abi_id, /^[0-9a-f]{64}$/); + const flags = [ + '--llvm', + '--llvm-opt-level', + 'aggressive', + '--compiler-threads', + '1', + '--enable-exceptions', + '--enable-threads', + ]; + for (const args of [ + [...flags, '-o', resolve(artifact), resolve(module)], + ['verify-aot', resolve(module), resolve(artifact)], + ]) { + const child = Bun.spawn([compiler, ...args], { + env: { LC_ALL: 'C' }, + stdout: 'pipe', + stderr: 'pipe', + }); + const stdout = new Response(child.stdout).text(); + const stderr = new Response(child.stderr).text(); + assert.equal(await child.exited, 0, `Postmaster compiler failed: ${await stderr}`); + const output = (await stdout).trim(); + if (args[0] === 'verify-aot') + assert.equal( + output.toLowerCase(), + moduleIdentity.sha256, + 'AOT embedded module identity differs', + ); + } + assert.deepEqual(identity(module), moduleIdentity, 'Sealed input changed during compilation'); + writeFileSync( + receipt, + `${JSON.stringify({ + schema: 'oliphaunt.wasix-postmaster.aot.native.v1', + module_path: relative, + module: moduleIdentity, + artifact: identity(artifact), + compiler: identity(compiler), + runtime_abi_id: abi.runtime_abi_id, + artifact_abi_version: abi.artifact_abi_version, + target: abi.rust.target, + engine: 'llvm-opta', + flags, + cpu_policy: 'generic-baseline', + cpu_features: [], + })}\n`, + { flag: 'wx' }, + ); +} diff --git a/build_defs/wasix/postmaster/cargo-extension.bzl b/build_defs/wasix/postmaster/cargo-extension.bzl new file mode 100644 index 000000000..356da363b --- /dev/null +++ b/build_defs/wasix/postmaster/cargo-extension.bzl @@ -0,0 +1,5 @@ +"""Independent maintained Cargo contexts for the pinned postmaster workspace.""" + +load("@rules_rust//crate_universe:extensions.bzl", _crate = "crate") + +crate = _crate diff --git a/build_defs/wasix/postmaster/cargo-source-projection-test.mts b/build_defs/wasix/postmaster/cargo-source-projection-test.mts new file mode 100644 index 000000000..a06d8468e --- /dev/null +++ b/build_defs/wasix/postmaster/cargo-source-projection-test.mts @@ -0,0 +1,80 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { join } from 'node:path'; + +const runfiles = process.env.RUNFILES_DIR; +assert(runfiles, 'This check consumes the actual standard Cargo extension outputs'); +const mapping = readFileSync(join(runfiles, '_repo_mapping'), 'utf8') + .trim() + .split('\n') + .map((line) => line.split(',')); +function external(repository: string, file: string) { + const roots = new Set(mapping.filter((row) => row[1] === repository).map((row) => row[2])); + assert.equal(roots.size, 1, `Expected one declared ${repository} repository`); + return join(runfiles, [...roots][0], file); +} +const original = Bun.TOML.parse( + readFileSync(join(runfiles, '_main/src/wasix/postmaster/executor/Cargo.toml'), 'utf8'), +); +const canonicalLock = readFileSync( + join(runfiles, '_main/src/wasix/postmaster/executor/Cargo.lock'), +); +const sources = JSON.parse( + readFileSync(external('postmaster_cargo', 'cargo-sources.json'), 'utf8'), +); +const ownId = `${original.package.name} ${original.package.version}`; +for (const role of ['executor', 'compiler']) { + const repository = `postmaster_${role}_crates`; + const context = JSON.parse(readFileSync(external(repository, 'cargo-bazel.json'), 'utf8')); + const rendered = readFileSync(external(repository, 'crates.bzl'), 'utf8'); + const manifest = Bun.TOML.parse( + readFileSync(external('postmaster_cargo', `${role}/Cargo.toml`), 'utf8'), + ); + assert.deepEqual(readFileSync(external('postmaster_cargo', `${role}/Cargo.lock`)), canonicalLock); + assert.deepEqual(Object.keys(context.workspace_members), [ownId]); + const binary = original.bin.find((row: any) => row.name.endsWith(`postmaster-${role}`)); + assert(binary, `Missing canonical ${role} binary`); + assert.deepEqual(manifest.features.default, binary['required-features']); + const rootFeatures = context.crates[ownId].common_attrs.crate_features; + for (const feature of binary['required-features']) + assert(rootFeatures.includes(feature), `${role} lost its canonical feature ${feature}`); + let selected = 0; + for (const [id, crate] of Object.entries(context.crates) as [string, any][]) { + assert(!crate.repository?.Path, `${role} retained an ambient path source for ${id}`); + const source = sources[id]; + if (!source) continue; + selected++; + assert.deepEqual(Object.keys(crate.repository), ['Http']); + const actual = crate.repository.Http; + assert.equal(actual.url, source.url); + assert.equal(actual.sha256, source.sha256); + assert.equal(actual.strip_prefix, source.strip_prefix); + assert.deepEqual(actual.patches, source.patches); + assert.deepEqual(actual.patch_args, ['-p1']); + const marker = ` http_archive,\n name = ${JSON.stringify(`${repository}__${crate.name}-${crate.version.replaceAll('+', '-')}`)},\n`; + const blocks = rendered.split('\n maybe(\n').filter((block) => block.includes(marker)); + assert.equal(blocks.length, 1, `${role} must declare ${id} exactly once`); + const block = blocks[0]; + assert(block.includes(` strip_prefix = ${JSON.stringify(source.strip_prefix)},\n`)); + let previous = -1; + for (const patch of source.patches) { + const offset = block.indexOf(JSON.stringify(patch)); + assert(offset > previous, `${role} changed the canonical patch order for ${id}`); + previous = offset; + } + } + assert(selected > 0, `${role} selected no immutable Wasmer leaf sources`); + const compilerName = 'wasmer-compiler-llvm'; + const selectedCompiler = Object.keys(context.crates).some( + (id) => id.split(' ')[0] === compilerName, + ); + assert.equal( + selectedCompiler, + role === 'compiler', + 'Executor/compiler Cargo features were unified', + ); + assert(!Object.keys(context.crates).some((id) => id.startsWith('wasmer-compiler-cranelift '))); + console.log( + `Verified ${role}: ${selected} immutable leaf sources and isolated canonical features`, + ); +} diff --git a/build_defs/wasix/postmaster/carrier.bzl b/build_defs/wasix/postmaster/carrier.bzl new file mode 100644 index 000000000..5d004f986 --- /dev/null +++ b/build_defs/wasix/postmaster/carrier.bzl @@ -0,0 +1,102 @@ +"""Assemble the native headless carrier from exact declared physical outputs.""" + +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") +load(":import-guest.bzl", "GUEST_INPUT_ATTRIBUTES", "guest_input_files", "guest_input_spec") + +def _executor_configuration(_settings, attr): + return {"//command_line_option:platforms": [str(attr.native_platform)], "//command_line_option:compilation_mode": "opt"} + +_EXECUTOR_CONFIGURATION = transition(implementation = _executor_configuration, inputs = [], outputs = ["//command_line_option:platforms", "//command_line_option:compilation_mode"]) + +def _carrier_impl(ctx): + output = ctx.actions.declare_directory(ctx.label.name) + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + executor_target = ctx.attr._executor[0] + executor = executor_target[DefaultInfo].files_to_run.executable + if not ctx.file.guest_receipt and not ctx.file.sysroot: + fail("Native postmaster requires its constructed sysroot or original imported guest receipt") + if ctx.file.guest_receipt and ctx.file.sysroot: + fail("Imported guest must preserve its original sysroot provenance") + if not ctx.file.guest_receipt and not ctx.file.clang: + fail("Constructed guest requires its actual declared guest compiler") + trees = [ctx.file.sealed] + ([ctx.file.sysroot] if ctx.file.sysroot else []) + resources = [] + inputs = [executor, ctx.file._executor_abi, ctx.file._compiler_abi, ctx.executable._compiler, ctx.file.wasmer_patch] + guest_input_files(ctx) + inputs += [ctx.file.guest_receipt] if ctx.file.guest_receipt else [ctx.file.clang] + for target, destination in ctx.attr.resources.items(): + for file in target[DefaultInfo].files.to_list(): + resources.append({"source": file.path, "destination": destination + (file.basename if destination.endswith("/") and not file.is_directory else ""), "tree": file.is_directory}) + if file.is_directory: + trees.append(file) + else: + inputs.append(file) + ctx.actions.write(spec, json.encode(guest_input_spec(ctx) | { + "sealed": ctx.file.sealed.path, + "sysroot": ctx.file.sysroot.path if ctx.file.sysroot else None, + "guestReceipt": ctx.file.guest_receipt.path if ctx.file.guest_receipt else None, + "executor": executor.path, + "executorAbi": ctx.file._executor_abi.path, + "compilerAbi": ctx.file._compiler_abi.path, + "compiler": ctx.executable._compiler.path, + "aot": [file.path for file in ctx.files.aot], + "aotReceipts": [file.path for file in ctx.files.aot_receipts], + "resources": resources, + "wasmerPatch": ctx.file.wasmer_patch.path, + "clang": ctx.file.clang.path if not ctx.file.guest_receipt else None, + })) + arguments = ctx.actions.args() + arguments.add_all([spec, output], expand_directories = False) + leaves = ctx.actions.args() + leaves.add_all(trees, expand_directories = True) + leaves.use_param_file("--tree-files=%s", use_always = True) + leaves.set_param_file_format("multiline") + bun_file_action( + ctx, + ctx.file._writer, + source_files = ctx.files._sources, + arguments = [arguments, leaves], + inputs = inputs + trees + [spec] + ctx.files.aot + ctx.files.aot_receipts, + tools = [executor_target[DefaultInfo].files_to_run, ctx.attr._compiler[DefaultInfo].files_to_run], + outputs = [output], + mnemonic = "PostmasterNativeCarrier", + progress_message = "Assemble and validate exact native postmaster carrier %{label}", + ) + return [DefaultInfo(files = depset([output]))] + +postmaster_carrier = rule( + implementation = _carrier_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = GUEST_INPUT_ATTRIBUTES | { + "sealed": attr.label(mandatory = True, allow_single_file = True), + "sysroot": attr.label(allow_single_file = True), + "guest_receipt": attr.label(allow_single_file = True), + "native_platform": attr.label(default = "//build_defs/native:linux_x86_64_glibc_2_28"), + "aot": attr.label(mandatory = True, allow_files = True), + "aot_receipts": attr.label(mandatory = True, allow_files = True), + "resources": attr.label_keyed_string_dict(allow_files = True), + "wasmer_patch": attr.label(default = "//src/wasix/postmaster:wasmer/patches/wasmer/0001-postgres-wasix-blockers.patch", allow_single_file = True), + "clang": attr.label(allow_single_file = True), + "_executor": attr.label(default = "//src/wasix/postmaster:executor", cfg = _EXECUTOR_CONFIGURATION), + "_executor_abi": attr.label(default = "//src/wasix/postmaster:runtime_abi_contract", allow_single_file = True, cfg = _EXECUTOR_CONFIGURATION), + "_compiler": attr.label(default = "//src/wasix/postmaster:compiler", executable = True, cfg = "exec"), + "_compiler_abi": attr.label(default = "//src/wasix/postmaster:runtime_abi_contract", allow_single_file = True, cfg = "exec"), + "_writer": attr.label(default = "//build_defs/wasix/postmaster:carrier.mts", allow_single_file = True), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), + "_sources": attr.label_list(default = [ + "//build_defs/wasix/postmaster:guest-inputs.mts", + "//build_defs/wasix/postmaster:native-receipts.mts", + "//:tools/packaging/strict-json.mts", + "//src/wasix/postmaster:lib/build-sealed-carrier.mts", + "//src/wasix/postmaster:lib/verify-sealed-carrier.mts", + "//src/wasix/postmaster:lib/guest-build-provenance.mts", + "//src/wasix/postmaster:lib/receipt-files.mts", + "//src/wasix/postmaster:lib/linear-memory-profile.mts", + "//src/wasix/postmaster:lib/sealed-export-chain.mts", + "//src/wasix/postmaster:wasmer/bin/verify-postmaster-concurrency-contract.mts", + "//src/wasix/postmaster:wasmer/bin/verify-postmaster-wasm-import.mts", + "//src/wasix/postmaster:wasmer/policies/sealed-side-modules.v1.tsv", + "//src/wasix/postmaster:wasmer/policies/sealed-main-runtime-exports.v1.txt", + "//src/wasix/postmaster:wasmer/policies/sealed-main-dlsym-exports.v1.txt", + ], allow_files = True), + }, +) diff --git a/build_defs/wasix/postmaster/carrier.mts b/build_defs/wasix/postmaster/carrier.mts new file mode 100644 index 000000000..b2a24f7e8 --- /dev/null +++ b/build_defs/wasix/postmaster/carrier.mts @@ -0,0 +1,304 @@ +import assert from 'node:assert/strict'; +import { + chmodSync, + lstatSync, + mkdirSync, + readFileSync, + rmSync, + statSync, + writeFileSync, +} from 'node:fs'; +import { basename, dirname, join, resolve } from 'node:path'; +import { manifest as writeManifest } from '../../../src/wasix/postmaster/lib/build-sealed-carrier.mts'; +import { + installedClosureIdentityFromRecords, + requiredModules, +} from '../../../src/wasix/postmaster/lib/guest-build-provenance.mts'; +import { + AGGREGATE_RELATIVE, + safeRelative, +} from '../../../src/wasix/postmaster/lib/receipt-files.mts'; +import { + carrierTree, + hashRegular, + sourceFingerprint, + verify, +} from '../../../src/wasix/postmaster/lib/verify-sealed-carrier.mts'; +import { verifyReceipt } from '../../../src/wasix/postmaster/wasmer/bin/verify-postmaster-concurrency-contract.mts'; +import { parseStrictJson } from '../../../tools/packaging/strict-json.mts'; +import { declaredGuestInputs, validateImportedGuestReceipt } from './guest-inputs.mts'; +import { + canonicalJson, + digest, + nativeGuestReceipt, + nativeWasmerReceipt, + runtimeAbiFacts, +} from './native-receipts.mts'; + +const identity = (path: string) => { + // Exact action inputs may be Bazel sandbox file projections. Output members + // are checked independently by the strict no-follow carrier inventory. + assert(statSync(path).isFile(), `Declared carrier input is not regular: ${path}`); + const bytes = readFileSync(path); + return { sha256: digest(bytes), size: bytes.length }; +}; +const json = (path: string) => parseStrictJson(readFileSync(path, 'utf8')); +const encode = (value: unknown) => `${canonicalJson(value)}\n`; + +export function aotPlan(receipts: any[], artifacts: string[], abi: any) { + const selected = new Map(); + for (const artifact of artifacts) { + assert(!selected.has(basename(artifact)), 'Duplicate AOT output basename'); + selected.set(basename(artifact), artifact); + } + const rows = new Map(); + for (const { file, value } of receipts) { + assert.equal(value.schema, 'oliphaunt.wasix-postmaster.aot.native.v1'); + assert.equal(value.runtime_abi_id, abi.runtime_abi_id); + assert.equal(value.artifact_abi_version, abi.artifact_abi_version); + assert.equal(value.target, abi.rust.target); + assert.equal(value.engine, 'llvm-opta'); + assert.equal(value.cpu_policy, 'generic-baseline'); + assert.deepEqual(value.cpu_features, []); + assert.deepEqual(value.flags, [ + '--llvm', + '--llvm-opt-level', + 'aggressive', + '--compiler-threads', + '1', + '--enable-exceptions', + '--enable-threads', + ]); + assert( + requiredModules.includes(value.module_path) && !rows.has(value.module_path), + 'Unknown/duplicate AOT module', + ); + const name = basename(file).replace(/\.json$/, '.bin'); + const artifact = selected.get(name); + assert(artifact, `Missing matching declared AOT artifact: ${name}`); + selected.delete(name); + rows.set(value.module_path, { receipt: value, artifact }); + } + assert.deepEqual( + [...rows.keys()].sort(), + [...requiredModules].sort(), + 'AOT module closure differs', + ); + assert.equal(selected.size, 0, 'Extra declared AOT artifact'); + return requiredModules.map((path) => { + const row = rows.get(path); + assert(row, `Missing AOT module: ${path}`); + return { path, ...row }; + }); +} + +export function constructCarrier(spec: any, output: string, leaves: string[]) { + assert.equal(new Set(leaves).size, leaves.length, 'Duplicate declared TreeArtifact child'); + const used = new Set(); + const put = (relative: string, bytes: Uint8Array | string, executable = false) => { + safeRelative(relative); + const destination = join(output, relative); + assert( + !lstatSync(destination, { throwIfNoEntry: false }), + `Carrier output collision: ${relative}`, + ); + mkdirSync(dirname(destination), { recursive: true }); + writeFileSync(destination, bytes, { flag: 'wx', mode: executable ? 0o755 : 0o644 }); + }; + const tree = (root: string) => { + const records = leaves + .filter((path) => path.startsWith(`${root}/`)) + .map((path) => { + used.add(path); + const relative = path.slice(root.length + 1); + safeRelative(relative); + return { relative, path, ...identity(path) }; + }) + .sort((a, b) => (a.relative < b.relative ? -1 : a.relative > b.relative ? 1 : 0)); + assert(records.length, `Empty declared TreeArtifact: ${root}`); + return records; + }; + for (const row of tree(spec.sealed)) + put(row.relative, readFileSync(row.path), row.relative.startsWith('bin/')); + const sysroot = spec.guestReceipt + ? undefined + : tree(spec.sysroot).map(({ relative, sha256, size }) => ({ + relative, + sha256, + size, + })); + for (const resource of spec.resources) { + if (resource.tree) + for (const row of tree(resource.source)) + put(`${resource.destination}/${row.relative}`, readFileSync(row.path)); + else put(resource.destination, readFileSync(resource.source)); + } + assert.equal(used.size, leaves.length, 'TreeArtifact child outside declared carrier inputs'); + put('bin/wasmer-headless', readFileSync(spec.executor), true); + const executorAbi = json(spec.executorAbi), + compilerAbi = json(spec.compilerAbi); + assert.deepEqual( + executorAbi, + compilerAbi, + 'Executor/compiler actual serialization contracts differ', + ); + const facts = runtimeAbiFacts(compilerAbi); + const wasmer = { + schema: 'oliphaunt.wasix-postmaster.wasmer-build.native.v1', + runtime_abi: compilerAbi, + canonical_patch_sha256: identity(spec.wasmerPatch).sha256, + compiler: identity(spec.compiler), + }; + const wasmerFacts = nativeWasmerReceipt(wasmer); + put('wasmer-build.receipt', encode(wasmer)); + put( + 'postmaster-executor.receipt', + encode({ + schema: 'oliphaunt.wasix-postmaster.executor-build.native.v1', + runtime_abi_id: executorAbi.runtime_abi_id, + wasmer_build_receipt_sha256: digest(encode(wasmer)), + binary: identity(spec.executor), + package: executorAbi.package.name, + features: executorAbi.roles.executor.features, + }), + ); + const expectedGuest = declaredGuestInputs(spec); + const source = { postgresql: expectedGuest.source.postgresql }; + const concurrencyPath = 'share/postgresql/wasix-postmaster.final-wasm-concurrency.receipt'; + if (!spec.guestReceipt) + put( + concurrencyPath, + readFileSync(join(output, 'share/postgresql/wasix-postmaster.concurrency.receipt')), + ); + const observed = verifyReceipt( + readFileSync(join(output, concurrencyPath), 'utf8'), + readFileSync(join(output, 'bin/postgres')), + ); + const closure = [ + ...new Set([ + ...requiredModules, + ...[...carrierTree(output)] + .filter(([path, info]) => info.isFile() && path.startsWith('share/postgresql/')) + .map(([path]) => path), + ]), + ].sort(); + const guest = spec.guestReceipt + ? validateImportedGuestReceipt(readFileSync(spec.guestReceipt), spec) + : { + schema: 'oliphaunt.wasix-postmaster.guest-build.native.v1', + source: expectedGuest.source, + configuration: expectedGuest.configuration, + sysroot: { + schema: wasmerFacts.sysroot_variant, + source: expectedGuest.libcSource, + patch_sha256: expectedGuest.libcPatch, + closure_sha256: digest(canonicalJson(sysroot)), + }, + compiler: identity(spec.clang), + core_profile: 'release-o3', + postgres_version: source.postgresql.version, + installed_closure_sha256: installedClosureIdentityFromRecords( + closure.map((relative) => ({ relative, ...hashRegular(join(output, relative)) })), + ), + atomic_fence_total: Number(observed.atomic_fence_total), + final_wasm_concurrency_receipt_sha256: hashRegular(join(output, concurrencyPath)).sha256, + linear_memory_install_receipt_sha256: hashRegular(join(output, AGGREGATE_RELATIVE)).sha256, + }; + nativeGuestReceipt(guest); + const guestBytes = spec.guestReceipt ? readFileSync(spec.guestReceipt) : encode(guest); + put('guest-build.receipt', guestBytes); + const memory = json(join(output, AGGREGATE_RELATIVE)); + const rows: string[] = []; + for (const { path, artifact, receipt } of aotPlan( + spec.aotReceipts.map((file: string) => ({ file, value: json(file) })), + spec.aot, + compilerAbi, + )) { + const module = hashRegular(join(output, path)); + assert.deepEqual(module, receipt.module, `AOT source differs: ${path}`); + assert.deepEqual(identity(artifact), receipt.artifact, `AOT bytes differ: ${path}`); + assert.deepEqual(receipt.compiler, wasmer.compiler, `AOT compiler differs: ${path}`); + const record = memory.modules.find((row: any) => row.path === path); + assert(record && record['module-sha256'] === module.sha256, 'Missing memory-sealed module'); + const aotPath = `aot/${module.sha256.toUpperCase()}.bin`; + put(aotPath, readFileSync(artifact)); + const alias = path.startsWith('bin/') ? `/${path}` : ''; + rows.push( + [ + `runtime:${basename(path)}`, + alias ? 'executable' : 'side-module', + aotPath, + path, + receipt.artifact.sha256, + receipt.artifact.size, + module.sha256, + module.size, + alias, + ].join('\t'), + ); + } + const rowFile = join(output, '.artifact-rows.tsv'); + writeFileSync(rowFile, `${rows.join('\n')}\n`, { flag: 'wx' }); + writeManifest([ + rowFile, + output, + join(output, 'manifest.json'), + sourceFingerprint(output), + 'release-o3', + digest(guestBytes), + facts.target, + facts.hostAbi, + 'llvm-opta;non-volatile-memops;readonly-funcref-table;generic-baseline', + wasmerFacts.wasmer_source_commit, + wasmerFacts.wasmer_patch_sha256, + wasmerFacts.wasmer_cargo_lock_sha256, + compilerAbi.runtime_abi_id, + digest(encode(wasmer)), + identity(spec.executor).sha256, + String(identity(spec.executor).size), + source.postgresql.version, + facts.wasmerVersion, + facts.wasixVersion, + String(compilerAbi.artifact_abi_version), + AGGREGATE_RELATIVE, + guest.linear_memory_install_receipt_sha256, + ]); + rmSync(rowFile); + const entries = [...carrierTree(output)]; + const inventory = entries + .filter(([, info]) => info.isFile()) + .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)) + .map(([path]) => { + const identity = hashRegular(join(output, path)); + return `${identity.sha256}\t${identity.size}\t${path}`; + }); + put( + 'payload.files', + `schema=oliphaunt.wasix-postmaster.payload-files.v1\n${inventory.join('\n')}\n`, + ); + for (const [path, info] of [...carrierTree(output)].reverse()) + chmodSync( + path === '.' ? output : join(output, path), + info.isDirectory() || info.mode & 0o111 ? 0o555 : 0o444, + ); + verify( + output, + digest(encode(wasmer)), + source.postgresql.version, + facts.wasmerVersion, + facts.wasixVersion, + compilerAbi.artifact_abi_version, + output, + ); +} + +if (import.meta.main) { + const [spec, output, treeArgument] = Bun.argv.slice(2); + assert.equal(Bun.argv.length, 5, 'usage: carrier.mts SPEC OUTPUT --tree-files=PARAM'); + assert(treeArgument.startsWith('--tree-files=')); + constructCarrier( + json(spec), + resolve(output), + readFileSync(treeArgument.slice('--tree-files='.length), 'utf8').split('\n').filter(Boolean), + ); +} diff --git a/build_defs/wasix/postmaster/compile-metadata.mts b/build_defs/wasix/postmaster/compile-metadata.mts new file mode 100644 index 000000000..71068a261 --- /dev/null +++ b/build_defs/wasix/postmaster/compile-metadata.mts @@ -0,0 +1,87 @@ +import assert from 'node:assert/strict'; +import { readFileSync, writeFileSync } from 'node:fs'; + +export function compilerZstdLabel(context: any, rendered: string, canonicalHub: string) { + const rows = Object.values(context.crates).filter((row) => row.name === 'zstd'); + assert.equal(rows.length, 1, 'Expected one actual selected compiler zstd crate'); + const row = rows[0]; + const source = row.repository?.Http; + assert( + source && row.library_target_name, + 'Selected compiler zstd must have a genuine HTTP library', + ); + const blocks = rendered + .split('\n maybe(\n') + .filter((block) => + [ + ` strip_prefix = ${JSON.stringify(`${row.name}-${row.version}`)},\n`, + ` sha256 = ${JSON.stringify(source.sha256)},\n`, + ` urls = [${JSON.stringify(source.url)}],\n`, + ].every((field) => block.includes(field)), + ); + assert.equal(blocks.length, 1, 'Expected one exact rendered compiler zstd repository'); + const name = /\n {8}name = "([^"]+)",\n/u.exec(blocks[0])?.[1]; + const apparentHub = /\n {8}build_file = Label\("@([^/]+)\/\//u.exec(blocks[0])?.[1]; + assert( + name && apparentHub && canonicalHub.endsWith(apparentHub), + 'Compiler repository mapping differs', + ); + return `@@${canonicalHub.slice(0, -apparentHub.length)}${name}//:${row.library_target_name}`; +} + +export function postmasterCompileMetadata(manifest: any, contexts: Record) { + const pkg = manifest.package; + assert(pkg?.name && pkg.version && pkg.edition, 'Canonical executor package facts required'); + const id = `${pkg.name} ${pkg.version}`; + assert.deepEqual(manifest.features.default, [], 'Canonical default features must remain empty'); + const roles: Record = {}; + const patches = new Set(); + for (const [role, context] of Object.entries(contexts)) { + assert.deepEqual(Object.keys(context.workspace_members), [id]); + const binaries = manifest.bin.filter((row: any) => row.name.endsWith(`postmaster-${role}`)); + assert.equal(binaries.length, 1, `Expected one canonical ${role} binary`); + const binary = binaries[0]; + const features = context.crates[id].common_attrs.crate_features; + assert(Array.isArray(features) && new Set(features).size === features.length); + for (const feature of binary['required-features']) + assert(features.includes(feature), `Resolved ${role} lost canonical feature ${feature}`); + for (const feature of features) + assert(Object.hasOwn(manifest.features, feature), `Unknown resolved feature ${feature}`); + roles[role] = { + binary: binary.name, + source: binary.path, + // The role overlay enables Cargo metadata's default feature solely to + // select the authored binary. Conventional construction disables it. + features: features.filter((feature: string) => feature !== 'default'), + }; + for (const row of Object.values(context.crates)) { + if (row.repository?.Http?.strip_prefix) { + for (const patch of row.repository.Http.patches ?? []) patches.add(patch); + } + } + } + assert.deepEqual(Object.keys(roles).sort(), ['compiler', 'executor']); + return { + name: pkg.name, + crate_name: pkg.name.replaceAll('-', '_'), + version: pkg.version, + edition: pkg.edition, + library: manifest.lib?.path ?? 'src/lib.rs', + roles, + patches: [...patches].sort(), + }; +} + +if (import.meta.main) { + const [manifest, executor, compiler, rendered, canonicalHub, output] = Bun.argv.slice(2); + assert(manifest && executor && compiler && rendered && canonicalHub && output); + const compilerContext = JSON.parse(readFileSync(compiler, 'utf8')); + const facts = postmasterCompileMetadata(Bun.TOML.parse(readFileSync(manifest, 'utf8')), { + executor: JSON.parse(readFileSync(executor, 'utf8')), + compiler: compilerContext, + }); + writeFileSync( + output, + `POSTMASTER_CARGO = ${JSON.stringify({ ...facts, compiler_zstd: compilerZstdLabel(compilerContext, readFileSync(rendered, 'utf8'), canonicalHub) })}\n`, + ); +} diff --git a/build_defs/wasix/postmaster/compile-metadata.test.mts b/build_defs/wasix/postmaster/compile-metadata.test.mts new file mode 100644 index 000000000..3fc0cdc49 --- /dev/null +++ b/build_defs/wasix/postmaster/compile-metadata.test.mts @@ -0,0 +1,78 @@ +import { expect, test } from 'bun:test'; +import { compilerZstdLabel, postmasterCompileMetadata } from './compile-metadata.mts'; + +const manifest = { + package: { name: 'executor', version: '7.2.0-alpha.2', edition: '2024' }, + features: { default: [], execute: ['memory'], memory: [], compile: [] }, + bin: [ + { name: 'postmaster-executor', path: 'src/executor.rs', 'required-features': ['execute'] }, + { name: 'postmaster-compiler', path: 'src/compiler.rs', 'required-features': ['compile'] }, + ], +}; +const context = (features: string[]) => ({ + workspace_members: { 'executor 7.2.0-alpha.2': '' }, + crates: { 'executor 7.2.0-alpha.2': { common_attrs: { crate_features: features } } }, +}); + +test('projects the exact selected transitive zstd repository instead of assuming a hub alias', () => { + const row = { + name: 'zstd', + version: '0.13.3', + library_target_name: 'zstd', + repository: { Http: { sha256: 'a'.repeat(64), url: 'https://registry.test/zstd/0.13.3' } }, + }; + const context = { crates: { 'zstd 0.13.3': row } }; + const rendered = `\n maybe(\n http_archive,\n name = "compiler_hub__zstd-0.13.3",\n sha256 = "${row.repository.Http.sha256}",\n urls = ["${row.repository.Http.url}"],\n strip_prefix = "zstd-0.13.3",\n build_file = Label("@compiler_hub//compiler_hub:BUILD.zstd-0.13.3.bazel"),\n )\n`; + expect(compilerZstdLabel(context, rendered, '+actual_extension+compiler_hub')).toBe( + '@@+actual_extension+compiler_hub__zstd-0.13.3//:zstd', + ); + expect(() => + compilerZstdLabel({ crates: {} }, rendered, '+actual_extension+compiler_hub'), + ).toThrow('one actual selected'); + expect(() => + compilerZstdLabel( + { crates: { one: row, two: { ...row, version: 'other' } } }, + rendered, + '+actual_extension+compiler_hub', + ), + ).toThrow('one actual selected'); + expect(() => + compilerZstdLabel( + context, + rendered.replace(row.repository.Http.sha256, 'b'.repeat(64)), + '+actual_extension+compiler_hub', + ), + ).toThrow('one exact rendered'); + expect(() => + compilerZstdLabel(context, rendered + rendered, '+actual_extension+compiler_hub'), + ).toThrow('one exact rendered'); + expect(() => compilerZstdLabel(context, rendered, '+actual_extension+different_hub')).toThrow( + 'mapping differs', + ); +}); +test('projects actual resolved role features while preserving no-default conventional compilation', () => { + const contexts = { + executor: context(['default', 'execute', 'memory']), + compiler: context(['default', 'compile']), + }; + const facts = postmasterCompileMetadata(manifest, contexts); + expect(facts.roles.executor.features).toEqual(['execute', 'memory']); + expect(facts.roles.compiler.features).toEqual(['compile']); + expect(facts.version).toBe(manifest.package.version); + expect(facts.roles.compiler.source).toBe(manifest.bin[1].path); + expect(() => + postmasterCompileMetadata(manifest, { ...contexts, executor: context(['default']) }), + ).toThrow('lost canonical feature'); + expect(() => + postmasterCompileMetadata(manifest, { ...contexts, compiler: context(['compile', 'fake']) }), + ).toThrow('Unknown resolved feature'); + expect(() => + postmasterCompileMetadata(manifest, { ...contexts, executor: context(['execute', 'execute']) }), + ).toThrow(); + expect(() => + postmasterCompileMetadata( + { ...manifest, package: { ...manifest.package, version: '7.2.1' } }, + contexts, + ), + ).toThrow(); +}); diff --git a/build_defs/wasix/postmaster/crate-monorepo-source.patch b/build_defs/wasix/postmaster/crate-monorepo-source.patch new file mode 100644 index 000000000..6d3aea5c5 --- /dev/null +++ b/build_defs/wasix/postmaster/crate-monorepo-source.patch @@ -0,0 +1,149 @@ +diff --git a/crate_universe/extensions.bzl b/crate_universe/extensions.bzl +index 99ce629..543ef14 100644 +--- a/crate_universe/extensions.bzl ++++ b/crate_universe/extensions.bzl +@@ -637,38 +637,32 @@ def _generate_hub_and_spokes( + fail("Invalid immutable Cargo source metadata for " + crate_id) + name, version = parts + if ( +- source["strip_prefix"] != name + "-" + version or ++ type(source["strip_prefix"]) != "string" or ++ not source["strip_prefix"] or ++ [c for c in source["strip_prefix"].elems() if c not in "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._+/"] or ++ [part for part in source["strip_prefix"].split("/") if part in ["", ".", ".."]] or + not source["url"].startswith("https://") or + len(source["sha256"]) != 64 or + [c for c in source["sha256"].elems() if c not in "0123456789abcdef"] + ): + fail("Invalid immutable Cargo archive identity for " + crate_id) +- annotation = _crate_universe_crate.annotation( +- version = version, +- patches = [Label(patch) for patch in source["patches"]], +- patch_args = ["-p1"], +- ) +- annotations[name] = list(annotations.get(name, [])) + [annotation] + + config_file = tag_path.get_child("config.json") +- module_ctx.file( +- config_file, +- executable = False, +- content = generate_config_file( +- module_ctx, +- mode = "remote", +- annotations = annotations, +- generate_build_scripts = cfg.generate_build_scripts, +- supported_platform_triples = cfg.supported_platform_triples, +- generate_target_compatible_with = True, +- repository_name = cfg.name, +- output_pkg = cfg.name, +- workspace_name = cfg.name, +- generate_binaries = cfg.generate_binaries, +- render_config = render_config, +- repository_ctx = module_ctx, +- ), ++ config_args = dict( ++ ctx = module_ctx, ++ mode = "remote", ++ annotations = annotations, ++ generate_build_scripts = cfg.generate_build_scripts, ++ supported_platform_triples = cfg.supported_platform_triples, ++ generate_target_compatible_with = True, ++ repository_name = cfg.name, ++ output_pkg = cfg.name, ++ workspace_name = cfg.name, ++ generate_binaries = cfg.generate_binaries, ++ render_config = dict(render_config), ++ repository_ctx = module_ctx, + ) ++ module_ctx.file(config_file, executable = False, content = generate_config_file(**config_args)) + + splicing_manifest = tag_path.get_child("splicing_manifest.json") + module_ctx.file( +@@ -747,16 +741,37 @@ def _generate_hub_and_spokes( + if source_metadata: + metadata = json.decode(module_ctx.read(splice_outputs.metadata)) + sources = metadata["metadata"]["cargo-bazel"]["sources"] ++ selected_sources = {} ++ for package in metadata["packages"]: ++ crate_id = package["name"] + " " + package["version"] ++ if package["id"] in metadata["workspace_members"]: ++ if crate_id in source_metadata: ++ fail("Immutable acquisition cannot override a Cargo workspace member: " + crate_id) ++ continue ++ if package["source"] != None: ++ if crate_id in source_metadata: ++ fail("Immutable acquisition cannot override a registry or Git Cargo source: " + crate_id) ++ continue ++ if crate_id not in source_metadata or crate_id in selected_sources or crate_id in sources: ++ fail("Immutable acquisition must cover each selected path-patched Cargo package exactly once: " + crate_id) ++ selected_sources[crate_id] = source_metadata[crate_id] ++ if not selected_sources: ++ fail("Immutable acquisition selected no nonworkspace path-patched Cargo packages") ++ source_metadata = selected_sources + for crate_id, source in source_metadata.items(): +- name, version = crate_id.split(" ") +- packages = [ +- p +- for p in metadata["packages"] +- if p["name"] == name and p["version"] == version +- ] +- if len(packages) != 1 or packages[0]["source"] != None or crate_id in sources: +- fail("Immutable source must match exactly one path-patched Cargo package: " + crate_id) + sources[crate_id] = {"url": source["url"], "sha256": source["sha256"]} ++ name, version = crate_id.split(" ") ++ annotation = _crate_universe_crate.annotation( ++ version = version, ++ patches = [Label(patch) for patch in source["patches"]], ++ patch_args = ["-p1"], ++ ) ++ annotations[name] = list(annotations.get(name, [])) + [annotation] ++ # Acquisition annotations follow the standard selected dependency ++ # closure; optional unselected crates must retain strict rejection. ++ config_args["annotations"] = annotations ++ config_args["render_config"] = dict(render_config) ++ module_ctx.file(config_file, executable = False, content = generate_config_file(**config_args)) + _project_configured_target_features(metadata, cfg.supported_platform_triples) + module_ctx.file(splice_outputs.metadata, json.encode(metadata)) + +@@ -815,12 +830,30 @@ def _generate_hub_and_spokes( + sorted(patches) != sorted(source["patches"]) + ): + fail("Generated HTTP source differs from canonical acquisition: " + crate_id) ++ crate = contents["crates"][crate_id] ++ default_prefix = crate["name"] + "-" + crate["version"] ++ repository_name = cfg.name + "__" + crate["name"] + "-" + crate["version"].replace("+", "-") ++ blocks = rendered.split("\n maybe(\n") ++ marker = " http_archive,\n name = " + json.encode(repository_name) + ",\n" ++ matches = [index for index in range(len(blocks)) if marker in blocks[index]] ++ if len(matches) != 1 or blocks[matches[0]].count(marker) != 1: ++ fail("Expected one generated HTTP repository for " + crate_id) ++ index = matches[0] ++ block = blocks[index] ++ original_prefix = " strip_prefix = " + json.encode(default_prefix) + ",\n" ++ if block.count(original_prefix) != 1: ++ fail("Expected the generated HTTP crate prefix for " + crate_id) ++ if source["strip_prefix"] != default_prefix: ++ block = block.replace(original_prefix, " strip_prefix = " + json.encode(source["strip_prefix"]) + ",\n") ++ repository["strip_prefix"] = source["strip_prefix"] + if patches != source["patches"]: + original = " patches = [\n" + "".join([" %s,\n" % json.encode(patch) for patch in patches]) + " ]," + ordered = " patches = [\n" + "".join([" %s,\n" % json.encode(patch) for patch in source["patches"]]) + " ]," +- if rendered.count(original) != 1: ++ if block.count(original) != 1: + fail("Expected one generated HTTP patch list for " + crate_id) +- rendered = rendered.replace(original, ordered) ++ block = block.replace(original, ordered) ++ blocks[index] = block ++ rendered = "\n maybe(\n".join(blocks) + repository["patches"] = source["patches"] + module_ctx.file(rendered_file, rendered) + module_ctx.file(lockfile, json.encode(contents)) +@@ -876,7 +909,7 @@ def _generate_hub_and_spokes( + sha256 = repo.get("sha256", None), + type = "tar.gz", + urls = [repo["url"]], +- strip_prefix = "%s-%s" % (crate["name"], crate["version"]), ++ strip_prefix = repo.get("strip_prefix", "%s-%s" % (crate["name"], crate["version"])), + build_file_content = build_file_content, + ) + elif "Git" in repo: diff --git a/build_defs/wasix/postmaster/guest-inputs.mts b/build_defs/wasix/postmaster/guest-inputs.mts new file mode 100644 index 000000000..f9600525a --- /dev/null +++ b/build_defs/wasix/postmaster/guest-inputs.mts @@ -0,0 +1,93 @@ +/** Bind an imported Linux guest to the exact current declared construction sources. */ +import assert from 'node:assert/strict'; +import { mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'; +import { dirname, join } from 'node:path'; +import { parseStrictJson } from '../../../tools/packaging/strict-json.mts'; +import { digest, nativeGuestReceipt, runtimeAbiFacts } from './native-receipts.mts'; + +export interface GuestInputs { + source: string; + series: string; + patches: Record; + overlays: Record; + configuration: Record; + libcSource: string; + libcPatch: string; +} + +const identity = (file: string) => { + assert(statSync(file).isFile(), `Declared guest input is not regular: ${file}`); + const bytes = readFileSync(file); + return { sha256: digest(bytes), size: bytes.length }; +}; + +export function declaredGuestInputs(spec: GuestInputs) { + const source = Bun.TOML.parse(readFileSync(spec.source, 'utf8')) as any; + const patches = readFileSync(spec.series, 'utf8') + .split('\n') + .map((line) => line.trim()) + .filter((line) => line && !line.startsWith('#')); + assert.equal(new Set(patches).size, patches.length, 'Duplicate canonical PostgreSQL patch'); + assert.deepEqual( + [...patches].sort(), + Object.keys(spec.patches).sort(), + 'Declared PostgreSQL patches differ from canonical ordered series', + ); + return { + source: { + postgresql: source.postgresql, + overlays: Object.entries(spec.overlays) + .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)) + .map(([path, file]) => ({ path, ...identity(file) })), + patches: patches.map((path) => ({ path, ...identity(spec.patches[path]) })), + }, + configuration: Object.fromEntries( + Object.entries(spec.configuration).map(([name, file]) => [name, identity(file)]), + ), + libcSource: parseStrictJson(readFileSync(spec.libcSource, 'utf8')), + libcPatch: identity(spec.libcPatch).sha256, + }; +} + +export function validateImportedGuestReceipt(bytes: Uint8Array | string, spec: GuestInputs) { + const guest = parseStrictJson(Buffer.from(bytes).toString('utf8')) as any; + nativeGuestReceipt(guest); + const expected = declaredGuestInputs(spec); + assert.deepEqual(guest.source, expected.source, 'Imported guest source/ordered patches differ'); + assert.deepEqual( + guest.configuration, + expected.configuration, + 'Imported guest configuration differs', + ); + assert.deepEqual(guest.sysroot.source, expected.libcSource, 'Imported guest libc source differs'); + assert.equal(guest.sysroot.patch_sha256, expected.libcPatch, 'Imported guest libc patch differs'); + // Sysroot closure and guest compiler identities describe the original Linux + // construction. They remain unchanged; no foreign compiler is relabeled here. + return guest; +} + +// Emit ordinary sibling Files from the already admitted final tree for per-module AOT caching. +export function writeAotModuleOutputs( + tree: string, + modules: string[], + outputs: Record, +) { + assert.deepEqual( + Object.keys(outputs).sort(), + [...modules].sort(), + 'Declared AOT module outputs differ', + ); + for (const [relative, file] of Object.entries(outputs)) { + mkdirSync(dirname(file), { recursive: true }); + writeFileSync(file, readFileSync(join(tree, relative)), { flag: 'wx', mode: 0o644 }); + } +} + +export function validateGuestProducer(abi: any, canonicalTriple: string) { + assert.equal( + canonicalTriple, + 'x86_64-unknown-linux-gnu', + 'Guest producer must be canonical Linux x64', + ); + assert.equal(runtimeAbiFacts(abi).target, canonicalTriple, 'Imported guest producer differs'); +} diff --git a/build_defs/wasix/postmaster/guest-inputs.test.mts b/build_defs/wasix/postmaster/guest-inputs.test.mts new file mode 100644 index 000000000..8e833573e --- /dev/null +++ b/build_defs/wasix/postmaster/guest-inputs.test.mts @@ -0,0 +1,401 @@ +import { test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join } from 'node:path'; +import { requiredModules } from '../../../src/wasix/postmaster/lib/guest-build-provenance.mts'; +import { + validateGuestProducer, + validateImportedGuestReceipt, + writeAotModuleOutputs, +} from './guest-inputs.mts'; +import { canonicalJson, digest, nativeGuestReceipt } from './native-receipts.mts'; + +type Spec = Parameters[1]; +const linuxTriple = 'x86_64-unknown-linux-gnu'; +const identity = (bytes: string | Uint8Array) => ({ + sha256: digest(bytes), + size: Buffer.byteLength(bytes), +}); + +function fixture(root: string): { spec: Spec; receipt: any } { + const put = (relative: string, bytes: string) => { + const file = join(root, relative); + mkdirSync(dirname(file), { recursive: true }); + writeFileSync(file, bytes); + return file; + }; + const postgresql = { + version: '18.4', + url: 'https://example.test/postgresql-18.4.tar.bz2', + sha256: digest('immutable PostgreSQL archive'), + }; + const libcSource = { + commit: 'c'.repeat(40), + sha256: digest('immutable WASIX libc archive'), + strip_prefix: 'wasix-libc', + url: 'https://example.test/wasix-libc.tar.gz', + }; + const patches = { + 'src/postgres/first.patch': put('patches/first.patch', 'first patch bytes'), + 'src/postgres/second.patch': put('patches/second.patch', 'second patch bytes'), + }; + const overlays = { + 'src/port/wasix.h': put('overlays/wasix.h', 'WASIX port header'), + 'src/backend/wasix.c': put('overlays/wasix.c', 'WASIX backend overlay'), + }; + const configuration = { + 'pg_config.h': put('configuration/pg_config.h', '#define EXEC_BACKEND 1\n'), + 'pg_config_os.h': put('configuration/pg_config_os.h', '#define WASIX_CORE 1\n'), + }; + const spec: Spec = { + source: put( + 'source.toml', + `[postgresql]\n${Object.entries(postgresql) + .map(([key, value]) => `${key}=${JSON.stringify(value)}`) + .join('\n')}\n`, + ), + series: put('series', `# Canonical ordered patches\n${Object.keys(patches).join('\n')}\n`), + patches, + overlays, + configuration, + libcSource: put('libc-source.json', `${JSON.stringify(libcSource)}\n`), + libcPatch: put('libc.patch', 'canonical WASIX libc patch bytes'), + }; + const fileIdentity = (file: string) => identity(readFileSync(file)); + const receipt = { + schema: 'oliphaunt.wasix-postmaster.guest-build.native.v1', + source: { + postgresql, + patches: Object.entries(patches).map(([path, file]) => ({ path, ...fileIdentity(file) })), + overlays: Object.entries(overlays) + .sort(([a], [b]) => a.localeCompare(b)) + .map(([path, file]) => ({ path, ...fileIdentity(file) })), + }, + configuration: Object.fromEntries( + Object.entries(configuration).map(([name, file]) => [name, fileIdentity(file)]), + ), + sysroot: { + schema: 'oliphaunt.wasix-postmaster.libc.native.v1', + source: libcSource, + patch_sha256: fileIdentity(spec.libcPatch).sha256, + closure_sha256: digest('original Linux construction sysroot closure'), + }, + compiler: identity('original Linux construction Clang bytes'), + core_profile: 'release-o3', + postgres_version: postgresql.version, + installed_closure_sha256: digest('original installed module closure'), + atomic_fence_total: 995, + final_wasm_concurrency_receipt_sha256: digest('original final concurrency receipt'), + linear_memory_install_receipt_sha256: digest('original linear memory receipt'), + }; + return { spec, receipt }; +} + +function withFixture(run: (value: ReturnType) => void) { + const root = mkdtempSync(join(tmpdir(), 'postmaster-guest-inputs-')); + try { + run(fixture(root)); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +test('imported guest binds declared inputs and preserves original Linux construction provenance', () => + withFixture(({ spec, receipt }) => { + const bytes = `${canonicalJson(receipt)}\n`; + for (const input of [bytes, Buffer.from(bytes)]) { + const actual = validateImportedGuestReceipt(input, spec); + assert.deepEqual(actual, receipt); + assert.deepEqual(actual.compiler, identity('original Linux construction Clang bytes')); + assert.equal( + actual.sysroot.closure_sha256, + digest('original Linux construction sysroot closure'), + ); + } + assert.deepEqual( + validateImportedGuestReceipt(bytes, { + ...spec, + patches: Object.fromEntries(Object.entries(spec.patches).reverse()), + overlays: Object.fromEntries(Object.entries(spec.overlays).reverse()), + configuration: Object.fromEntries(Object.entries(spec.configuration).reverse()), + }), + receipt, + ); + })); + +test('structurally valid guest receipts reject stale source, patches, overlays, configuration and libc', () => { + const cases: [string, (receipt: any) => void][] = [ + [ + 'source archive', + (value) => { + value.source.postgresql.sha256 = digest('foreign PostgreSQL archive'); + }, + ], + [ + 'source URL', + (value) => { + value.source.postgresql.url = 'https://example.test/foreign.tar.bz2'; + }, + ], + [ + 'source version', + (value) => { + value.source.postgresql.version = value.postgres_version = '18.5'; + }, + ], + [ + 'patch order', + (value) => { + value.source.patches.reverse(); + }, + ], + [ + 'patch bytes', + (value) => { + value.source.patches[0].sha256 = digest('foreign patch bytes'); + }, + ], + [ + 'patch size', + (value) => { + value.source.patches[0].size += 1; + }, + ], + [ + 'missing patch', + (value) => { + value.source.patches.pop(); + }, + ], + [ + 'foreign patch', + (value) => { + value.source.patches[0].path = 'src/postgres/foreign.patch'; + }, + ], + [ + 'overlay bytes', + (value) => { + value.source.overlays[0].sha256 = digest('foreign overlay bytes'); + }, + ], + [ + 'missing overlay', + (value) => { + value.source.overlays.pop(); + }, + ], + [ + 'foreign overlay', + (value) => { + value.source.overlays[0].path = 'src/port/foreign.h'; + }, + ], + [ + 'configuration bytes', + (value) => { + value.configuration['pg_config.h'].sha256 = digest('foreign config bytes'); + }, + ], + [ + 'configuration size', + (value) => { + value.configuration['pg_config.h'].size += 1; + }, + ], + [ + 'missing configuration', + (value) => { + delete value.configuration['pg_config_os.h']; + }, + ], + [ + 'extra configuration', + (value) => { + value.configuration['foreign.h'] = identity('foreign config'); + }, + ], + [ + 'libc source', + (value) => { + value.sysroot.source.commit = 'd'.repeat(40); + }, + ], + [ + 'libc patch', + (value) => { + value.sysroot.patch_sha256 = digest('foreign libc patch'); + }, + ], + ]; + for (const [name, mutate] of cases) + withFixture(({ spec, receipt }) => { + mutate(receipt); + nativeGuestReceipt(receipt); + assert.throws(() => validateImportedGuestReceipt(canonicalJson(receipt), spec), name); + }); +}); + +test('unchanged receipt rejects changed declared bytes and incomplete or foreign input maps', () => { + const replaceSameSize = (file: string) => { + const original = readFileSync(file); + writeFileSync(file, Buffer.alloc(original.length, 0x78)); + }; + const cases: [string, (spec: Spec) => void][] = [ + ['patch bytes', (spec) => replaceSameSize(spec.patches['src/postgres/first.patch'])], + ['overlay bytes', (spec) => replaceSameSize(spec.overlays['src/backend/wasix.c'])], + ['configuration bytes', (spec) => replaceSameSize(spec.configuration['pg_config.h'])], + ['libc patch bytes', (spec) => replaceSameSize(spec.libcPatch)], + [ + 'canonical series order', + (spec) => writeFileSync(spec.series, `${Object.keys(spec.patches).reverse().join('\n')}\n`), + ], + [ + 'duplicate canonical patch', + (spec) => + writeFileSync( + spec.series, + `${Object.keys(spec.patches).join('\n')}\n${Object.keys(spec.patches)[0]}\n`, + ), + ], + [ + 'missing declared patch', + (spec) => { + delete spec.patches['src/postgres/second.patch']; + }, + ], + [ + 'extra declared patch', + (spec) => { + spec.patches['src/postgres/foreign.patch'] = spec.patches['src/postgres/first.patch']; + }, + ], + [ + 'missing declared overlay', + (spec) => { + delete spec.overlays['src/port/wasix.h']; + }, + ], + [ + 'extra declared configuration', + (spec) => { + spec.configuration['foreign.h'] = spec.configuration['pg_config.h']; + }, + ], + [ + 'canonical source version', + (spec) => + writeFileSync(spec.source, readFileSync(spec.source, 'utf8').replace('18.4', '18.5')), + ], + [ + 'canonical libc source', + (spec) => { + const source = JSON.parse(readFileSync(spec.libcSource, 'utf8')); + source.sha256 = digest('another canonical libc archive'); + writeFileSync(spec.libcSource, JSON.stringify(source)); + }, + ], + ]; + for (const [name, mutate] of cases) + withFixture(({ spec, receipt }) => { + mutate(spec); + assert.throws(() => validateImportedGuestReceipt(canonicalJson(receipt), spec), name); + }); +}); + +test('import rejects legacy and wrong receipt schemas', () => + withFixture(({ spec, receipt }) => { + for (const input of [ + 'schema=oliphaunt.wasix-postmaster.guest-build.v5\ncore_profile=release-o3\n', + canonicalJson({ ...receipt, schema: 'oliphaunt.wasix-postmaster.guest-build.v5' }), + canonicalJson({ ...receipt, schema: 'oliphaunt.wasix-postmaster.executor-build.native.v1' }), + ]) + assert.throws(() => validateImportedGuestReceipt(input, spec)); + })); + +function producer(target = linuxTriple) { + const contract = { + schema: 'oliphaunt.wasix-postmaster.runtime-abi.native.v2', + artifact_abi_version: 21, + source: { wasmer: { commit: 'a'.repeat(40) } }, + lock_sha256: digest('producer Cargo lock bytes'), + rust: { target }, + roles: Object.fromEntries( + ['executor', 'compiler'].map((role) => [ + role, + { + features: [`product-${role}`], + dependencies: [{ id: 'wasmer 7.2.0-alpha.2' }, { id: 'wasmer-wasix 0.702.0-alpha.2' }], + }, + ]), + ), + }; + return { ...contract, runtime_abi_id: digest(canonicalJson(contract)) }; +} + +test('guest producer requires the canonical Linux x64 ABI rather than a foreign or stale contract', () => { + validateGuestProducer(producer(), linuxTriple); + for (const target of ['aarch64-unknown-linux-gnu', 'aarch64-apple-darwin']) + assert.throws(() => validateGuestProducer(producer(target), linuxTriple)); + assert.throws(() => + validateGuestProducer(producer('aarch64-unknown-linux-gnu'), 'aarch64-unknown-linux-gnu'), + ); + const stale = producer(); + stale.rust.target = 'aarch64-unknown-linux-gnu'; + assert.throws(() => validateGuestProducer(stale, linuxTriple)); + assert.throws(() => + validateGuestProducer( + { ...producer(), schema: 'oliphaunt.wasix-postmaster.runtime-abi.v1' }, + linuxTriple, + ), + ); +}); + +test('scalar AOT outputs preserve the canonical final bytes without unrelated tree metadata', () => { + const root = mkdtempSync(join(tmpdir(), 'postmaster-aot-output-')); + try { + const tree = join(root, 'tree'); + for (const relative of requiredModules) { + const file = join(tree, relative); + mkdirSync(dirname(file), { recursive: true }); + writeFileSync(file, Buffer.from([0, 97, 115, 109, 1, 0, 0, 0])); + } + const metadata = join(tree, 'share/postgresql/receipt.json'); + mkdirSync(dirname(metadata), { recursive: true }); + writeFileSync(metadata, '{"receipt":1}'); + const project = (name: string) => { + const outputs = Object.fromEntries( + requiredModules.map((relative) => [relative, join(root, name, relative)]), + ); + writeAotModuleOutputs(tree, requiredModules, outputs); + return Object.fromEntries( + Object.entries(outputs).map(([relative, file]) => [relative, identity(readFileSync(file))]), + ); + }; + const before = project('before'); + writeFileSync(metadata, '{"receipt":2}'); + assert.deepEqual(project('metadata-only'), before); + writeFileSync(join(tree, 'bin/initdb'), Buffer.from([0, 97, 115, 109, 1, 0, 0, 0, 0, 1, 0])); + const changed = project('own-module'); + assert.notDeepEqual(changed['bin/initdb'], before['bin/initdb']); + for (const relative of requiredModules.filter((path) => path !== 'bin/initdb')) + assert.deepEqual(changed[relative], before[relative]); + const outputs = Object.fromEntries( + requiredModules.map((relative) => [relative, join(root, 'invalid', relative)]), + ); + const missing = { ...outputs }; + delete missing['bin/postgres']; + assert.throws(() => writeAotModuleOutputs(tree, requiredModules, missing), /outputs differ/); + assert.throws( + () => + writeAotModuleOutputs(tree, requiredModules, { + ...outputs, + foreign: join(root, 'foreign'), + }), + /outputs differ/, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/build_defs/wasix/postmaster/guest-repository.bzl b/build_defs/wasix/postmaster/guest-repository.bzl new file mode 100644 index 000000000..751899769 --- /dev/null +++ b/build_defs/wasix/postmaster/guest-repository.bzl @@ -0,0 +1,67 @@ +"""Expose authenticated public archive Files for guest import and family checksums.""" + +_ARCHIVE_ENV = "OLIPHAUNT_POSTMASTER_GUEST_ARCHIVE" +_RELEASE_ARCHIVES_ENV = "OLIPHAUNT_POSTMASTER_RELEASE_ARCHIVES" +_FAMILY_ARCHIVES_ENV = "OLIPHAUNT_NATIVE_RELEASE_ARCHIVES" + +# The reviewed controller authenticates these bytes before import; this rule +# only validates and watches the actual regular Files. +def _import_archive(ctx, file, destination, imported, names): + if not file.exists or file.is_dir or file.realpath != file: + fail("release archive transport must contain regular non-symlink Files") + if file.basename in names: + fail("release archive transport repeats a public archive name: " + file.basename) + names[file.basename] = True + ctx.watch(file) + ctx.symlink(file, destination) + imported.append(destination) + +def _guest_repository_impl(ctx): + modules = ["bin/initdb", "bin/postgres"] + for line in ctx.read(ctx.attr.side_modules).splitlines(): + if line and not line.startswith("#"): + fields = line.split("\t") + if len(fields) != 3 or not fields[0].startswith("lib/") or fields[0] in modules: + fail("Invalid canonical postmaster side-module policy") + modules.append(fields[0]) + ctx.file("guest.bzl", "POSTMASTER_GUEST_MODULE_PATHS = " + repr(modules) + "\n") + release_archives = ctx.os.environ.get(_RELEASE_ARCHIVES_ENV, "") + imported = [] + names = {} + if release_archives: + directory = ctx.path(release_archives) + if not directory.exists or not directory.is_dir: + fail(_RELEASE_ARCHIVES_ENV + " must name the authenticated final archive directory") + ctx.watch(directory) + for file in directory.readdir(): + _import_archive(ctx, file, "release-archives/" + file.basename, imported, names) + families = ctx.os.environ.get(_FAMILY_ARCHIVES_ENV, "") + if families: + directory = ctx.path(families) + if not directory.exists or not directory.is_dir: + fail(_FAMILY_ARCHIVES_ENV + " must name the authenticated public archive families") + ctx.watch(directory) + for family in directory.readdir(): + if not family.is_dir or family.realpath != family: + fail("release archive families must be regular product directories") + ctx.watch(family) + for file in family.readdir(): + _import_archive(ctx, file, "release-archives/" + family.basename + "/" + file.basename, imported, names) + archive = ctx.os.environ.get(_ARCHIVE_ENV, "") + declarations = 'package(default_visibility = ["//visibility:public"])\nfilegroup(name = "release_archives", srcs = %s)\n' % repr(imported) + if not archive: + ctx.file("BUILD.bazel", declarations + 'filegroup(name = "archive", srcs = [])\n') + return + path = ctx.path(archive) + if not path.exists: + fail(_ARCHIVE_ENV + " must name the authenticated regular public archive File") + ctx.watch(path) + ctx.symlink(path, path.basename) + ctx.file("BUILD.bazel", declarations + 'filegroup(name = "archive", srcs = [%s])\n' % repr(path.basename)) + +postmaster_guest_repository = repository_rule( + implementation = _guest_repository_impl, + environ = [_ARCHIVE_ENV, _RELEASE_ARCHIVES_ENV, _FAMILY_ARCHIVES_ENV], + configure = True, + attrs = {"side_modules": attr.label(default = Label("//src/wasix/postmaster:wasmer/policies/sealed-side-modules.v1.tsv"), allow_single_file = True)}, +) diff --git a/build_defs/wasix/postmaster/host-carrier.bzl b/build_defs/wasix/postmaster/host-carrier.bzl new file mode 100644 index 000000000..0bde3830c --- /dev/null +++ b/build_defs/wasix/postmaster/host-carrier.bzl @@ -0,0 +1,39 @@ +"""Regenerate host AOT and the public carrier from the preserved Linux guest.""" + +load("@postmaster_guest//:guest.bzl", "POSTMASTER_GUEST_MODULE_PATHS") +load("@postmaster_postgres//:patches.bzl", "POSTGRES_PATCHES") +load(":aot.bzl", "postmaster_aot") +load(":carrier.bzl", "postmaster_carrier") +load(":import-guest.bzl", "postmaster_import_guest") +load(":postgres.bzl", "postmaster_patch_inputs") +load(":release-asset.bzl", "postmaster_release_asset") +load(":runtime-test.bzl", "postmaster_runtime_test") + +def postmaster_imported_host_carrier(target, native_platform, execution, name = None, archive = "@postmaster_guest//:archive", aot_modules = None, aot_receipts = None): + """A declared host profile; runtime qualification executes on that host.""" + name = name or target.replace("-", "_") + compatible = ["@platforms//cpu:wasm32", "@platforms//os:wasi"] + guest = name + "_guest" + postmaster_import_guest(name = guest, archive = archive, module_paths = POSTMASTER_GUEST_MODULE_PATHS, configuration = "@postmaster_postgres//:configuration", patches = postmaster_patch_inputs(POSTGRES_PATCHES), + target_compatible_with = compatible, exec_compatible_with = execution) + native.filegroup(name = guest + "_receipt", srcs = [":" + guest], output_group = "receipt", target_compatible_with = compatible) + if not aot_modules: + aot = [] + for path in POSTMASTER_GUEST_MODULE_PATHS: + module = name + "_" + path.replace("/", "_").replace(".", "_") + "_aot" + postmaster_aot(name = module, sealed = ":" + guest, module_path = path, + target_compatible_with = compatible, exec_compatible_with = execution) + aot.append(":" + module) + native.filegroup(name = name + "_aot", srcs = aot, target_compatible_with = compatible) + native.filegroup(name = name + "_aot_receipts", srcs = aot, output_group = "receipt", target_compatible_with = compatible) + aot_modules = ":" + name + "_aot" + aot_receipts = ":" + name + "_aot_receipts" + carrier = name + "_carrier" + postmaster_carrier(name = carrier, sealed = ":" + guest, guest_receipt = ":" + guest + "_receipt", + native_platform = native_platform, aot = aot_modules, aot_receipts = aot_receipts, + configuration = "@postmaster_postgres//:configuration", patches = postmaster_patch_inputs(POSTGRES_PATCHES), + target_compatible_with = compatible, exec_compatible_with = execution) + postmaster_runtime_test(name = name + "_runtime_test", carrier = ":" + carrier, native_platform = native_platform, + target = target, target_compatible_with = compatible, exec_compatible_with = execution, + tags = ["manual"], size = "medium", timeout = "long") + postmaster_release_asset(name = name, target = target, carrier = ":" + carrier, execution = execution, qualification = [":" + name + "_runtime_test"]) diff --git a/build_defs/wasix/postmaster/import-guest.bzl b/build_defs/wasix/postmaster/import-guest.bzl new file mode 100644 index 000000000..0fbbde729 --- /dev/null +++ b/build_defs/wasix/postmaster/import-guest.bzl @@ -0,0 +1,63 @@ +"""Validate and extract the exact portable guest from one authenticated final File.""" + +load("@oliphaunt_metadata//:metadata.bzl", "WASIX_ARTIFACTS") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") +load("//build_defs/release:identity.bzl", "ReleaseIdentityInfo") +load(":release-asset.bzl", "POSTMASTER_RELEASE_HELPERS") +load(":aot.bzl", "PostmasterModulesInfo", "postmaster_module_outputs") + +GUEST_INPUT_ATTRIBUTES = { + "configuration": attr.label(mandatory = True, allow_files = True), + "patches": attr.label_list(mandatory = True, allow_files = [".patch"]), + "overlays": attr.label(default = "//src/wasix/postmaster:postgres_overlays", allow_files = True), + "source": attr.label(default = "//src/third-party/postgres:source.toml", allow_single_file = True), + "series": attr.label(default = "//src/wasix/postmaster:postgres/series", allow_single_file = True), + "libc_source": attr.label(default = "@postmaster_wasix_libc//:source.json", allow_single_file = True), + "libc_patch": attr.label(default = "//src/wasix/postmaster:wasmer/patches/wasix-libc/0001-postgres-wasix-blockers.patch", allow_single_file = True), +} + +def guest_input_spec(ctx): + configuration = {} + for file in ctx.files.configuration: + if file.basename in configuration: + fail("Duplicate declared guest configuration basename: " + file.basename) + configuration[file.basename] = file.path + return { + "source": ctx.file.source.path, + "series": ctx.file.series.path, + "patches": {file.short_path: file.path for file in ctx.files.patches}, + "overlays": {file.short_path.removeprefix("src/wasix/postmaster/postgres/overlays/wasix-core/"): file.path for file in ctx.files.overlays}, + "configuration": configuration, + "libcSource": ctx.file.libc_source.path, + "libcPatch": ctx.file.libc_patch.path, + } + +def guest_input_files(ctx): + return [ctx.file.source, ctx.file.series, ctx.file.libc_source, ctx.file.libc_patch] + ctx.files.patches + ctx.files.overlays + ctx.files.configuration + +def _import_guest_impl(ctx): + owner = ctx.attr.owner[ReleaseIdentityInfo] + rows = [row for row in WASIX_ARTIFACTS if row["product"] == owner.id and row["target"] == "linux-x64-gnu" and row["kind"] == "wasix-postmaster-runtime"] + if len(rows) != 1: + fail("Imported postmaster guest requires one canonical Linux producer row") + output = ctx.actions.declare_directory(ctx.label.name) + receipt = ctx.actions.declare_file(ctx.label.name + ".guest-build.receipt") + modules = postmaster_module_outputs(ctx, ctx.attr.module_paths) + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode(guest_input_spec(ctx) | {"archive": ctx.file.archive.path, "version": owner.version, "artifact": rows[0], "moduleOutputs": {path: file.path for path, file in modules.items()}})) + bun_file_action(ctx, ctx.file._writer, arguments = [spec.path, output.path, receipt.path], + source_files = ctx.files._helpers, + inputs = [spec, ctx.file.archive] + guest_input_files(ctx), outputs = [output, receipt] + modules.values(), mnemonic = "PostmasterImportedGuest") + return [DefaultInfo(files = depset([output])), OutputGroupInfo(receipt = depset([receipt])), PostmasterModulesInfo(modules = modules)] + +postmaster_import_guest = rule( + implementation = _import_guest_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = GUEST_INPUT_ATTRIBUTES | { + "archive": attr.label(default = "@postmaster_guest//:archive", allow_single_file = True), + "module_paths": attr.string_list(mandatory = True), + "owner": attr.label(default = "@oliphaunt_metadata//:product_liboliphaunt-wasix-postmaster", providers = [ReleaseIdentityInfo]), + "_writer": attr.label(default = "//build_defs/wasix/postmaster:import-guest.mts", allow_single_file = True), + "_helpers": attr.label_list(default = POSTMASTER_RELEASE_HELPERS + ["//build_defs/wasix/postmaster:guest-inputs.mts"], allow_files = True), + }, +) diff --git a/build_defs/wasix/postmaster/import-guest.mts b/build_defs/wasix/postmaster/import-guest.mts new file mode 100644 index 000000000..b4daf2ac3 --- /dev/null +++ b/build_defs/wasix/postmaster/import-guest.mts @@ -0,0 +1,158 @@ +/** Read the canonical public Linux archive; retain only its portable sealed guest. */ +import assert from 'node:assert/strict'; +import { + chmodSync, + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + realpathSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { basename, dirname, join, resolve } from 'node:path'; +import { + requiredModules, + sideModulePolicy, +} from '../../../src/wasix/postmaster/lib/guest-build-provenance.mts'; +import { + carrierTree, + hashRegular, + verify, +} from '../../../src/wasix/postmaster/lib/verify-sealed-carrier.mts'; +import { inspectPlatformBinaryBuffer } from '../../../tools/packaging/platform-binary-contract.mts'; +import { + extractPortableArchiveTree, + readPortableArchiveEntries, +} from '../../../tools/packaging/portable-archive.mts'; +import { parseStrictJson } from '../../../tools/packaging/strict-json.mts'; +import { + type GuestInputs, + validateGuestProducer, + validateImportedGuestReceipt, + writeAotModuleOutputs, +} from './guest-inputs.mts'; +import { nativeWasmerReceipt, runtimeAbiFacts } from './native-receipts.mts'; + +export interface ImportedGuest extends GuestInputs { + archive: string; + moduleOutputs: Record; + version: string; + artifact: { product: string; kind: string; asset: string; target: string; triple: string }; +} + +export function importPostmasterGuest(spec: ImportedGuest, output: string, receipt: string) { + assert.equal(spec.artifact.product, 'liboliphaunt-wasix-postmaster'); + assert.equal(spec.artifact.kind, 'wasix-postmaster-runtime'); + assert.equal( + spec.artifact.target, + 'linux-x64-gnu', + 'Imported guest must come from the Linux producer', + ); + assert(/^\d+\.\d+\.\d+$/.test(spec.version)); + const asset = spec.artifact.asset.replaceAll('{version}', spec.version); + assert.equal(basename(spec.archive), asset, 'Imported archive differs from canonical identity'); + const parent = asset.replace(/\.tar\.zst$/u, ''); + assert.notEqual(parent, asset); + // Resolve the declared repository/sandbox projection; the archive reader + // continues to require the resulting owned transport File to be regular. + const archive = realpathSync(resolve(spec.archive)); + const entries = readPortableArchiveEntries(archive); + assert(entries.get(parent)?.isDirectory, 'Imported public archive parent is absent'); + const outerFiles = new Set([ + 'LICENSE', + 'README.md', + 'THIRD_PARTY_NOTICES.md', + 'bin/oliphaunt-wasix-postmaster', + ]); + for (const [name, entry] of entries) { + assert(name === parent || name.startsWith(`${parent}/`), 'Imported archive has a foreign root'); + const relative = name.slice(parent.length + 1); + assert( + (entry.isDirectory && ['', 'bin', 'carrier'].includes(relative)) || + relative.startsWith('carrier/') || + outerFiles.delete(relative), + `Foreign public archive member: ${relative}`, + ); + if (entry.isDirectory) + assert.equal(entry.mode, 0o755, `Imported archive directory mode: ${name}`); + else if (relative.startsWith('carrier/')) + assert([0o644, 0o755].includes(entry.mode), `Imported carrier mode: ${name}`); + else + assert.equal( + entry.mode, + relative === 'bin/oliphaunt-wasix-postmaster' ? 0o755 : 0o644, + `Imported archive mode differs: ${name}`, + ); + } + assert.equal(outerFiles.size, 0, 'Imported public archive metadata is missing'); + mkdirSync(dirname(resolve(output)), { recursive: true }); + const scratch = mkdtempSync(join(dirname(resolve(output)), '.postmaster-guest-')); + try { + extractPortableArchiveTree(archive, scratch); + const carrier = join(scratch, parent, 'carrier'); + for (const [path, info] of [...carrierTree(carrier)].reverse()) + chmodSync(path === '.' ? carrier : join(carrier, path), info.mode & 0o555); + const wasmer = parseStrictJson( + readFileSync(join(carrier, 'wasmer-build.receipt'), 'utf8'), + ) as any; + nativeWasmerReceipt(wasmer); + validateGuestProducer(wasmer.runtime_abi, spec.artifact.triple); + const facts = runtimeAbiFacts(wasmer.runtime_abi); + const bytes = readFileSync(join(carrier, 'guest-build.receipt')); + const guest = validateImportedGuestReceipt(bytes, spec); + verify( + carrier, + hashRegular(join(carrier, 'wasmer-build.receipt')).sha256, + guest.postgres_version, + facts.wasmerVersion, + facts.wasixVersion, + wasmer.runtime_abi.artifact_abi_version, + carrier, + ); + inspectPlatformBinaryBuffer(readFileSync(join(carrier, 'bin/wasmer-headless')), { + target: spec.artifact.target, + label: 'imported postmaster guest producer', + }); + const modules = new Set([ + ...requiredModules, + ...sideModulePolicy.flatMap((row) => row.aliases), + ]); + mkdirSync(output, { recursive: true }); + for (const [path, info] of carrierTree(carrier)) { + if ( + !info.isFile() || + !(modules.has(path) || path.startsWith('share/postgresql/') || path.startsWith('memory/')) + ) + continue; + const destination = join(output, path); + mkdirSync(dirname(destination), { recursive: true }); + writeFileSync(destination, readFileSync(join(carrier, path)), { + flag: 'wx', + mode: path.startsWith('bin/') ? 0o755 : 0o644, + }); + } + writeAotModuleOutputs(output, requiredModules, spec.moduleOutputs); + writeFileSync(receipt, bytes, { flag: 'wx' }); + } finally { + // Only our private extracted copy is made writable for deletion. + const carrier = join(scratch, parent, 'carrier'); + if (existsSync(carrier)) + for (const [path, info] of carrierTree(carrier)) + if (info.isDirectory()) chmodSync(path === '.' ? carrier : join(carrier, path), 0o755); + rmSync(scratch, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + const [spec, output, receipt] = Bun.argv.slice(2); + assert( + spec && output && receipt && Bun.argv.length === 5, + 'usage: import-guest.mts SPEC OUTPUT RECEIPT', + ); + importPostmasterGuest( + parseStrictJson(readFileSync(spec, 'utf8')) as ImportedGuest, + output, + receipt, + ); +} diff --git a/build_defs/wasix/postmaster/libc-archive.mts b/build_defs/wasix/postmaster/libc-archive.mts new file mode 100644 index 000000000..2a4ea3d63 --- /dev/null +++ b/build_defs/wasix/postmaster/libc-archive.mts @@ -0,0 +1,52 @@ +import assert from 'node:assert/strict'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join, resolve } from 'node:path'; + +// Canonical Makefile-eh archive packaging over already compiled native objects. +// Its sorted crs batches intentionally replace basename collisions. +const [specPath, archiver, output] = process.argv.slice(2); +assert( + specPath && archiver && output && process.argv.length === 5, + 'Expected object specification, llvm-ar and output', +); +const records = JSON.parse(readFileSync(specPath, 'utf8')) as { source: string; path: string }[]; +assert( + records.length && new Set(records.map((row) => row.source)).size === records.length, + 'Empty or duplicate libc object sources', +); +const staging = mkdtempSync(join(tmpdir(), 'postmaster-libc-archive-')); +try { + const objects = records + .sort((a, b) => (a.source < b.source ? -1 : a.source > b.source ? 1 : 0)) + .map((row) => { + assert( + /^[A-Za-z0-9_./-]+\.[cs]$/.test(row.source) && + !row.source.split('/').some((part) => !part || part === '.' || part === '..'), + 'Invalid libc object source', + ); + const path = join(staging, `${row.source.slice(0, -2)}.o`); + mkdirSync(dirname(path), { recursive: true }); + writeFileSync(path, readFileSync(row.path)); + return path; + }); + mkdirSync(dirname(output), { recursive: true }); + const destination = resolve(output); + for (const [start, end] of [ + [0, 199], + [199, 399], + [399, 599], + [599, 799], + [799, objects.length], + ]) { + if (start >= objects.length) continue; + const child = Bun.spawn([archiver, 'crs', destination, ...objects.slice(start, end)], { + stdout: 'inherit', + stderr: 'inherit', + env: { ...process.env, LC_ALL: 'C' }, + }); + assert.equal(await child.exited, 0, 'Native patched libc archiving failed'); + } +} finally { + rmSync(staging, { recursive: true, force: true }); +} diff --git a/build_defs/wasix/postmaster/libc-headers.mts b/build_defs/wasix/postmaster/libc-headers.mts new file mode 100644 index 000000000..b463ca5a3 --- /dev/null +++ b/build_defs/wasix/postmaster/libc-headers.mts @@ -0,0 +1,100 @@ +import assert from 'node:assert/strict'; +import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import { dirname, join } from 'node:path'; + +const expectedSed = String.raw`/^TYPEDEF/s/TYPEDEF \(.*\) \([^ ]*\);$/#if defined(__NEED_\2) \&\& !defined(__DEFINED_\2)\ +typedef \1 \2;\ +#define __DEFINED_\2\ +#endif\ +/ +/^STRUCT/s/STRUCT * \([^ ]*\) \(.*\);$/#if defined(__NEED_struct_\1) \&\& !defined(__DEFINED_struct_\1)\ +struct \1 \2;\ +#define __DEFINED_struct_\1\ +#endif\ +/ +/^UNION/s/UNION * \([^ ]*\) \(.*\);$/#if defined(__NEED_union_\1) \&\& !defined(__DEFINED_union_\1)\ +union \1 \2;\ +#define __DEFINED_union_\1\ +#endif\ +/ +`; + +export function muslAlltypes(script: string, templates: string[]): string { + assert.equal(script, expectedSed, 'Canonical mkalltypes.sed semantics changed'); + return templates + .join('') + .replace( + /^TYPEDEF (.*) ([^ ]*);$/gm, + (_line, type: string, name: string) => + `#if defined(__NEED_${name}) && !defined(__DEFINED_${name})\ntypedef ${type} ${name};\n#define __DEFINED_${name}\n#endif\n`, + ) + .replace( + /^(STRUCT|UNION) * ([^ ]*) (.*);$/gm, + (_line, kind: string, name: string, body: string) => { + const type = kind.toLowerCase(); + return `#if defined(__NEED_${type}_${name}) && !defined(__DEFINED_${type}_${name})\n${type} ${name} ${body};\n#define __DEFINED_${type}_${name}\n#endif\n`; + }, + ); +} + +export function publicLibcHeaders(files: Map, omit: string[]): Map { + const result = new Map(); + const copy = (prefix: string, destination = '') => { + for (const [path, bytes] of [...files].sort(([a], [b]) => a.localeCompare(b))) { + if (path.startsWith(prefix)) result.set(destination + path.slice(prefix.length), bytes); + } + }; + const text = (path: string) => { + const bytes = files.get(path); + assert(bytes, `Missing libc header input ${path}`); + return bytes.toString('utf8'); + }; + const musl = 'libc-top-half/musl/'; + copy('libc-bottom-half/headers/public/'); + result.set( + 'bits/alltypes.h', + Buffer.from( + muslAlltypes(text(`${musl}tools/mkalltypes.sed`), [ + text(`${musl}arch/wasm32/bits/alltypes.h.in`), + text(`${musl}include/alltypes.h.in`), + ]), + ), + ); + copy(`${musl}include/`); + copy(`${musl}arch/generic/bits/`, 'bits/'); + copy(`${musl}arch/wasm32/bits/`, 'bits/'); + for (const path of omit) result.delete(path); + assert( + result.has('bits/alltypes.h') && result.has('sys/mman.h') && result.has('wasix/context.h'), + 'Incomplete patched libc public headers', + ); + return result; +} + +if (import.meta.main) { + const [specPath, output] = process.argv.slice(2); + assert( + specPath && output && process.argv.length === 4, + 'Expected declared header specification and output directory', + ); + const spec = JSON.parse(readFileSync(specPath, 'utf8')) as { + files: { relative: string; path: string }[]; + omit: string[]; + }; + const files = new Map(); + for (const file of spec.files) { + assert( + !files.has(file.relative) && + !file.relative.startsWith('/') && + !file.relative.split('/').some((part) => !part || part === '.' || part === '..') && + !file.relative.includes('\\'), + 'Invalid or duplicate libc header member', + ); + files.set(file.relative, readFileSync(file.path)); + } + for (const [relative, bytes] of publicLibcHeaders(files, spec.omit)) { + const path = join(output, relative); + mkdirSync(dirname(path), { recursive: true }); + writeFileSync(path, bytes, { mode: 0o644 }); + } +} diff --git a/build_defs/wasix/postmaster/libc-headers.test.mts b/build_defs/wasix/postmaster/libc-headers.test.mts new file mode 100644 index 000000000..884a7b798 --- /dev/null +++ b/build_defs/wasix/postmaster/libc-headers.test.mts @@ -0,0 +1,53 @@ +import { expect, test } from 'bun:test'; +import { readFileSync } from 'node:fs'; +import { muslAlltypes, publicLibcHeaders } from './libc-headers.mts'; + +// The fixture is the genuine pinned musl program; actual full-template sed +// parity is also checked separately from native producer qualification. +const script = readFileSync(`${import.meta.dir}/testdata/mkalltypes.sed`, 'utf8'); + +test('canonical musl needs guards retain declarations and trailing blank lines', () => { + expect( + muslAlltypes(script, [ + 'TYPEDEF unsigned long size_t;\n', + 'STRUCT pair { int x; };\nUNION value { int i; };\n', + ]), + ).toBe( + '#if defined(__NEED_size_t) && !defined(__DEFINED_size_t)\ntypedef unsigned long size_t;\n#define __DEFINED_size_t\n#endif\n\n' + + '#if defined(__NEED_struct_pair) && !defined(__DEFINED_struct_pair)\nstruct pair { int x; };\n#define __DEFINED_struct_pair\n#endif\n\n' + + '#if defined(__NEED_union_value) && !defined(__DEFINED_union_value)\nunion value { int i; };\n#define __DEFINED_union_value\n#endif\n\n', + ); + expect(() => muslAlltypes(`${script}arbitrary new command\n`, ['TYPEDEF int size_t;\n'])).toThrow( + 'semantics changed', + ); +}); + +test('public headers retain canonical overwrite order and omit unsupported musl headers', () => { + const files = new Map([ + ['libc-top-half/musl/tools/mkalltypes.sed', Buffer.from(script)], + [ + 'libc-top-half/musl/arch/wasm32/bits/alltypes.h.in', + Buffer.from('TYPEDEF unsigned size_t;\n'), + ], + ['libc-top-half/musl/include/alltypes.h.in', Buffer.from('')], + ['libc-bottom-half/headers/public/sys/mman.h', Buffer.from('patched mmap')], + ['libc-bottom-half/headers/public/wasix/context.h', Buffer.from('actual context')], + ['libc-bottom-half/headers/public/string.h', Buffer.from('bottom')], + ['libc-top-half/musl/include/string.h', Buffer.from('musl')], + ['libc-top-half/musl/include/unsupported.h', Buffer.from('omit')], + ['libc-top-half/musl/arch/generic/bits/selected.h', Buffer.from('generic')], + ['libc-top-half/musl/arch/wasm32/bits/selected.h', Buffer.from('wasm32')], + ]); + const headers = publicLibcHeaders(files, [ + 'unsupported.h', + 'bits/alltypes.h.in', + 'alltypes.h.in', + ]); + expect(headers.get('string.h')?.toString()).toBe('musl'); + expect(headers.get('bits/selected.h')?.toString()).toBe('wasm32'); + expect(headers.has('unsupported.h')).toBeFalse(); + expect(headers.get('sys/mman.h')?.toString()).toBe('patched mmap'); + expect(() => + publicLibcHeaders(new Map([...files].filter(([path]) => !path.endsWith('mkalltypes.sed'))), []), + ).toThrow('Missing libc header input'); +}); diff --git a/build_defs/wasix/postmaster/libc-metadata.mts b/build_defs/wasix/postmaster/libc-metadata.mts new file mode 100644 index 000000000..f7aedfaf6 --- /dev/null +++ b/build_defs/wasix/postmaster/libc-metadata.mts @@ -0,0 +1,178 @@ +import assert from 'node:assert/strict'; +import { lstatSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'; +import { join } from 'node:path'; + +// A source inventory projection for the canonical wasm32/POSIX/PIC profile; +// this never executes Make recipes or source shell expressions. +export function libcSourceInventory(makefile: string, files: string[]) { + assert.equal(new Set(files).size, files.length); + for (const path of files) + assert( + !path.startsWith('/') && + !path.split('/').some((part) => !part || part === '.' || part === '..') && + !path.includes('\\'), + ); + const variables: Record = { + TARGET_ARCH: 'wasm32', + THREAD_MODEL: 'posix', + PIC: 'yes', + }; + function split(value: string): string[] { + let level = 0; + let start = 0; + const result: string[] = []; + for (let index = 0; index < value.length; index++) { + if (value.startsWith('$(', index)) { + level++; + index++; + } else if (value[index] === ')') { + assert(level); + level--; + } else if (value[index] === ',' && level === 0) { + result.push(value.slice(start, index)); + start = index + 1; + } + } + assert.equal(level, 0); + result.push(value.slice(start)); + return result; + } + const words = (value: string) => value.trim().split(/\s+/).filter(Boolean); + function expression(value: string): string { + let output = ''; + for (let index = 0; index < value.length; index++) { + if (value[index] !== '$') { + output += value[index]; + continue; + } + assert(value.startsWith('$(', index), 'Unsupported source expression'); + let level = 1; + const start = index + 2; + index = start; + for (; index < value.length; index++) { + if (value.startsWith('$(', index)) { + level++; + index++; + } else if (value[index] === ')' && --level === 0) break; + } + assert.equal(level, 0); + const body = value.slice(start, index); + const firstSpace = body.indexOf(' '); + if (firstSpace < 0) { + assert(Object.hasOwn(variables, body), `Unknown source variable ${body}`); + output += variables[body]; + continue; + } + const name = body.slice(0, firstSpace); + const args = split(body.slice(firstSpace + 1)).map(expression); + let result: string[]; + if (name === 'sort') { + assert.equal(args.length, 1); + result = [...new Set(words(args[0]))].sort(); + } else if (name === 'addprefix') { + assert.equal(args.length, 2); + result = words(args[1]).map((path) => args[0].trim() + path); + } else if (name === 'wildcard') { + assert.equal(args.length, 1); + result = words(args[0]) + .flatMap((pattern) => files.filter((path) => new Bun.Glob(pattern).match(path))) + .sort(); + } else if (name === 'filter-out') { + assert.equal(args.length, 2); + result = words(args[1]).filter( + (path) => + !words(args[0]).some((pattern) => { + const parts = pattern.split('%'); + assert(parts.length <= 2); + return parts.length === 1 + ? pattern === path + : path.startsWith(parts[0]) && path.endsWith(parts[1]); + }), + ); + } else if (name === 'shell') { + assert.equal(args.length, 1); + const match = /^find ([A-Za-z0-9_./-]+) -name (\\?\*\.(?:c|\[cs\]))$/.exec(args[0].trim()); + assert(match, 'Only declared source membership find expressions are supported'); + const pattern = `${match[1]}/**/${match[2].replaceAll('\\', '')}`; + result = files.filter((path) => new Bun.Glob(pattern).match(path)).sort(); + } else throw new Error(`Unsupported source function ${name}`); + output += result.join(' '); + } + return output; + } + function assignments(text: string) { + const active: boolean[] = [true]; + for (const raw of text.replaceAll(/\\\r?\n/g, ' ').split(/\r?\n/)) { + const line = raw.trim(); + if (!line || line.startsWith('#')) continue; + const condition = /^(ifeq|ifneq)\s+\((.*)\)$/.exec(line); + if (condition) { + const args = split(condition[2]).map((value) => expression(value).trim()); + assert.equal(args.length, 2); + active.push(Boolean(active.at(-1)) && (args[0] === args[1]) === (condition[1] === 'ifeq')); + } else if (line === 'endif') { + assert(active.length > 1); + active.pop(); + } else { + const row = /^([A-Z_]+)\s*(\+=|:=|=)\s*(.*)$/.exec(line); + assert(row, `Unsupported source assignment ${line}`); + if (active.at(-1)) + variables[row[1]] = + `${row[2] === '+=' ? `${variables[row[1]] ?? ''} ` : ''}${expression(row[3])}`; + } + } + assert.equal(active.length, 1); + } + const sourceStart = makefile.indexOf('DLMALLOC_DIR ='); + const sourceEnd = makefile.indexOf('# Add any extra flags'); + assert(sourceStart >= 0 && sourceEnd > sourceStart); + assignments(makefile.slice(sourceStart, sourceEnd)); + const omitStart = makefile.indexOf('MUSL_OMIT_HEADERS :='); + const omitEnd = makefile.indexOf('\ndefault:'); + assert(omitStart > sourceEnd && omitEnd > omitStart); + assignments(makefile.slice(omitStart, omitEnd)); + const selected = { + bottom: 'LIBC_BOTTOM_HALF_ALL_SOURCES', + top: 'LIBC_TOP_HALF_ALL_SOURCES', + malloc: 'DLMALLOC_SOURCES', + mman: 'LIBWASI_EMULATED_MMAN_SOURCES', + printscan: 'MUSL_PRINTSCAN_SOURCES', + bulk: 'BULK_MEMORY_SOURCES', + omit: 'MUSL_OMIT_HEADERS', + }; + const lists = Object.fromEntries( + Object.entries(selected).map(([name, key]) => [ + name, + [...new Set(words(variables[key].replaceAll('"', '')))].sort(), + ]), + ); + for (const [name, paths] of Object.entries(lists)) + if (name !== 'omit') + for (const path of paths) + assert(files.includes(path), `Missing selected libc source ${path}`); + return lists; +} + +export function libcMembers(directory: string, prefix = ''): string[] { + return readdirSync(join(directory, prefix)) + .sort() + .flatMap((name) => { + const relative = prefix ? `${prefix}/${name}` : name; + const stat = lstatSync(join(directory, relative)); + assert(!stat.isSymbolicLink(), `Libc source member is a symlink: ${relative}`); + return stat.isDirectory() ? libcMembers(directory, relative) : [relative]; + }); +} + +if (import.meta.main) { + const [source, output] = process.argv.slice(2); + assert( + source && output && process.argv.length === 4, + 'Expected source directory and output .bzl', + ); + const lists = libcSourceInventory( + readFileSync(join(source, 'Makefile-eh'), 'utf8'), + libcMembers(source), + ); + writeFileSync(output, `LIBC_SOURCES = ${JSON.stringify(lists, null, 2)}\n`); +} diff --git a/build_defs/wasix/postmaster/libc-metadata.test.mts b/build_defs/wasix/postmaster/libc-metadata.test.mts new file mode 100644 index 000000000..f0bf9557e --- /dev/null +++ b/build_defs/wasix/postmaster/libc-metadata.test.mts @@ -0,0 +1,61 @@ +import { expect, test } from 'bun:test'; +import { libcSourceInventory } from './libc-metadata.mts'; + +const makefile = `DLMALLOC_DIR = allocator +DLMALLOC_SOURCES = $(DLMALLOC_DIR)/malloc.c +LIBC_BOTTOM_HALF_ALL_SOURCES = $(sort $(shell find bottom -name \\*.c)) +LIBC_TOP_HALF_ALL_SOURCES = $(wildcard top/*.c) +ifeq ($(THREAD_MODEL), posix) +LIBC_TOP_HALF_ALL_SOURCES += top/thread.s +endif +LIBWASI_EMULATED_MMAN_SOURCES = $(filter-out %/shm_open.c,$(sort $(shell find mman -name \\*.c))) +MUSL_PRINTSCAN_SOURCES = top/printf.c +BULK_MEMORY_SOURCES = top/memcpy.c +# Add any extra flags +MUSL_OMIT_HEADERS := "alltypes.h.in" +ifeq ($(PIC), no) +MUSL_OMIT_HEADERS += dlfcn.h +endif +default: +`; +const files = [ + 'allocator/malloc.c', + 'bottom/z.c', + 'bottom/a.c', + 'top/memcpy.c', + 'top/printf.c', + 'top/thread.s', + 'mman/mman.c', + 'mman/shm_open.c', +]; + +test('canonical POSIX/PIC membership retains assembly and excludes separate shm_open', () => { + const inventory = libcSourceInventory(makefile, files); + expect(inventory.bottom).toEqual(['bottom/a.c', 'bottom/z.c']); + expect(inventory.top).toEqual(['top/memcpy.c', 'top/printf.c', 'top/thread.s']); + expect(inventory.mman).toEqual(['mman/mman.c']); + expect(inventory.omit).toEqual(['alltypes.h.in']); +}); + +test('source projection rejects missing selected sources and ambiguous membership', () => { + expect(() => + libcSourceInventory( + makefile, + files.filter((path) => path !== 'top/thread.s'), + ), + ).toThrow('Missing selected libc source'); + expect(() => libcSourceInventory(makefile, [...files, files[0]])).toThrow(); + expect(() => libcSourceInventory(makefile, [...files, '../escape.c'])).toThrow(); +}); + +test('make shell recipes and unrecognized source expansion cannot become acquisition commands', () => { + expect(() => + libcSourceInventory( + makefile.replace('find bottom -name \\*.c', 'curl https://example.test'), + files, + ), + ).toThrow('Only declared source membership'); + expect(() => + libcSourceInventory(makefile.replace('$(wildcard top/*.c)', '$(eval arbitrary)'), files), + ).toThrow('Unsupported source function'); +}); diff --git a/build_defs/wasix/postmaster/libc-sysroot.mts b/build_defs/wasix/postmaster/libc-sysroot.mts new file mode 100644 index 000000000..f23cbebde --- /dev/null +++ b/build_defs/wasix/postmaster/libc-sysroot.mts @@ -0,0 +1,68 @@ +import assert from 'node:assert/strict'; +import { + chmodSync, + lstatSync, + mkdirSync, + readdirSync, + readFileSync, + statSync, + writeFileSync, +} from 'node:fs'; +import { dirname, join } from 'node:path'; + +const [specPath, output] = process.argv.slice(2); +assert( + specPath && output && process.argv.length === 4, + 'Expected declared sysroot specification and output', +); +const spec = JSON.parse(readFileSync(specPath, 'utf8')) as { + base: { relative: string; path: string }[]; + headers: string; + libc: string; + mman: string; +}; +const seen = new Set(); +for (const file of spec.base) { + assert( + !seen.has(file.relative) && + !file.relative.startsWith('/') && + !file.relative.split('/').some((part) => !part || part === '.' || part === '..') && + !file.relative.includes('\\'), + 'Invalid or duplicate base sysroot member', + ); + seen.add(file.relative); + const path = join(output, file.relative); + mkdirSync(dirname(path), { recursive: true }); + writeFileSync(path, readFileSync(file.path)); + chmodSync(path, statSync(file.path).mode & 0o777); +} +assert( + seen.has('include/stdio.h') && seen.has('lib/wasm32-wasi/crt1.o'), + 'Incomplete selected base sysroot', +); +function headers(relative = '') { + for (const name of readdirSync(join(spec.headers, relative)).sort()) { + const path = relative ? `${relative}/${name}` : name; + const source = join(spec.headers, path); + const stat = lstatSync(source); + if (stat.isDirectory()) headers(path); + else { + // Bazel stages declared TreeArtifact children as sandbox leaf symlinks. + // The header producer writes regular files; do not recurse through links. + assert(statSync(source).isFile(), 'Generated libc header is not regular'); + const destination = join(output, 'include', path); + mkdirSync(dirname(destination), { recursive: true }); + writeFileSync(destination, readFileSync(source)); + chmodSync(destination, 0o644); + } + } +} +headers(); +for (const [name, source] of [ + ['libc.a', spec.libc], + ['libwasi-emulated-mman.a', spec.mman], +]) { + const destination = join(output, 'lib/wasm32-wasi', name); + writeFileSync(destination, readFileSync(source)); + chmodSync(destination, 0o644); +} diff --git a/build_defs/wasix/postmaster/libc-toolchain.bzl b/build_defs/wasix/postmaster/libc-toolchain.bzl new file mode 100644 index 000000000..424a7ad2e --- /dev/null +++ b/build_defs/wasix/postmaster/libc-toolchain.bzl @@ -0,0 +1,45 @@ +"""Raw pinned Clang for the canonical libc bootstrap C profile.""" + +load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES") +load("@rules_cc//cc:cc_toolchain_config_lib.bzl", "action_config", "feature", "flag_group", "flag_set", "tool") +load("@rules_cc//cc/common:cc_common.bzl", "cc_common") + +_COMPILE = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.linkstamp_compile] + +def _config_impl(ctx): + llvm = ctx.file.compiler.dirname.rsplit("/", 1)[0] + return [cc_common.create_cc_toolchain_config_info( + ctx = ctx, + toolchain_identifier = "oliphaunt-postmaster-patched-libc-clang", + host_system_name = "x86_64-unknown-linux-gnu", + target_system_name = "wasm32-wasi", + target_cpu = "wasm32", + target_libc = "wasix", + compiler = "clang", + abi_version = "wasm32", + abi_libc_version = "wasix", + action_configs = [action_config(action_name = action, enabled = True, tools = [tool(tool = ctx.file.compiler)]) for action in _COMPILE] + [action_config(action_name = ACTION_NAMES.cpp_link_static_library, enabled = True, tools = [tool(tool = ctx.file.archiver)])], + features = [ + feature(name = "supports_pic", enabled = True), + feature(name = "prefer_pic_for_opt_binaries", enabled = True), + feature(name = "target", enabled = True, flag_sets = [flag_set(actions = _COMPILE, flag_groups = [flag_group(flags = ["--target=wasm32-wasi", "-no-canonical-prefixes", "-resource-dir=" + llvm + "/lib/clang/21"])])]), + ], + cxx_builtin_include_directories = [llvm + "/lib/clang/21/include"], + )] + +libc_cc_toolchain_config = rule( + implementation = _config_impl, + attrs = { + "compiler": attr.label(default = "@wasix_toolchain//:llvm/bin/clang", allow_single_file = True), + "archiver": attr.label(default = "@wasix_toolchain//:llvm/bin/llvm-ar", allow_single_file = True), + }, +) + +def _libc_impl(_settings, _attr): + return {"//command_line_option:platforms": [str(Label("//build_defs/wasix/postmaster/libc_toolchain:construction"))]} + +LIBC_CONSTRUCTION_TRANSITION = transition( + implementation = _libc_impl, + inputs = [], + outputs = ["//command_line_option:platforms"], +) diff --git a/build_defs/wasix/postmaster/libc.BUILD.bazel b/build_defs/wasix/postmaster/libc.BUILD.bazel new file mode 100644 index 000000000..a63287081 --- /dev/null +++ b/build_defs/wasix/postmaster/libc.BUILD.bazel @@ -0,0 +1,9 @@ +load("@oliphaunt//build_defs/wasix/postmaster:libc.bzl", "patched_libc_targets") +load(":source-inventory.bzl", "LIBC_SOURCES") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["source.json", "source-inventory.bzl", "Makefile-eh"]) +filegroup(name = "sources", srcs = glob(["**"], exclude = ["BUILD.bazel", "source.json", "source-inventory.bzl"])) + +patched_libc_targets(LIBC_SOURCES) diff --git a/build_defs/wasix/postmaster/libc.bzl b/build_defs/wasix/postmaster/libc.bzl new file mode 100644 index 000000000..c7e8f4079 --- /dev/null +++ b/build_defs/wasix/postmaster/libc.bzl @@ -0,0 +1,143 @@ +"""The pinned patched libc uses maintained C/C++ compilation and archiving.""" + +load("@rules_cc//cc:defs.bzl", "cc_library") +load("@rules_cc//cc/common:cc_common.bzl", "cc_common") +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") +load(":libc-toolchain.bzl", "LIBC_CONSTRUCTION_TRANSITION") + +_COMPATIBLE = ["@platforms//cpu:wasm32", "@platforms//os:wasi"] + +def _headers_impl(ctx): + output = ctx.actions.declare_directory(ctx.label.name + "/include") + spec = ctx.actions.declare_file(ctx.label.name + ".json") + prefix = ctx.file.makefile.dirname + "/" + ctx.actions.write(spec, json.encode({ + "files": [{"relative": file.path[len(prefix):], "path": file.path} for file in ctx.files.sources], + "omit": ctx.attr.omit, + })) + arguments = ctx.actions.args() + arguments.add(spec) + arguments.add(output.path) + bun_file_action(ctx, ctx.file._writer, source_files = [ctx.file._writer], arguments = [arguments], inputs = [spec] + ctx.files.sources, outputs = [output], mnemonic = "PostmasterLibcHeaders") + return [DefaultInfo(files = depset([output])), CcInfo(compilation_context = cc_common.create_compilation_context(headers = depset([output]), system_includes = depset([output.path])))] + +libc_headers = rule( + implementation = _headers_impl, + attrs = { + "makefile": attr.label(allow_single_file = True, mandatory = True), + "sources": attr.label_list(allow_files = True, mandatory = True), + "omit": attr.string_list(mandatory = True), + "_writer": attr.label(default = Label("//build_defs/wasix/postmaster:libc-headers.mts"), allow_single_file = True), + }, + toolchains = BUN_SOURCE_TOOLCHAINS, +) + +def _archive_impl(ctx): + objects = [] + records = [] + for index, dependency in enumerate(ctx.attr.deps): + sources = json.decode(ctx.attr.source_groups[index]) + compiled = [] + for linker_input in dependency[CcInfo].linking_context.linker_inputs.to_list(): + if linker_input.user_link_flags or linker_input.additional_inputs: + fail("Patched libc requires explicit compilation objects") + for library in linker_input.libraries: + compiled.extend(library.pic_objects or library.objects) + if len(compiled) != len(sources): + fail("Patched libc source/object membership differs for " + str(dependency.label)) + for source, file in zip(sources, compiled): + records.append({"source": source, "path": file.path}) + objects.extend(compiled) + output = ctx.actions.declare_file(ctx.attr.output_name) + spec = ctx.actions.declare_file(ctx.label.name + ".json") + ctx.actions.write(spec, json.encode(records)) + arguments = ctx.actions.args() + arguments.add_all([spec, ctx.executable._archiver, output]) + bun_file_action(ctx, ctx.file._writer, source_files = [ctx.file._writer], arguments = [arguments], inputs = [spec] + objects, tools = ctx.files._archiver_files, outputs = [output], mnemonic = "PostmasterLibcArchive") + return [DefaultInfo(files = depset([output]))] + +_libc_archive = rule( + implementation = _archive_impl, + attrs = { + "deps": attr.label_list(providers = [CcInfo], mandatory = True, cfg = LIBC_CONSTRUCTION_TRANSITION), + "source_groups": attr.string_list(mandatory = True), + "output_name": attr.string(mandatory = True), + "_writer": attr.label(default = Label("//build_defs/wasix/postmaster:libc-archive.mts"), allow_single_file = True), + "_archiver": attr.label(default = Label("@wasix_toolchain//:llvm/bin/llvm-ar"), allow_single_file = True, executable = True, cfg = "exec"), + "_archiver_files": attr.label(default = Label("@wasix_toolchain//:llvm_files"), cfg = "exec"), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), + }, + toolchains = BUN_SOURCE_TOOLCHAINS, +) + +def _sysroot_impl(ctx): + output = ctx.actions.declare_directory(ctx.label.name) + spec = ctx.actions.declare_file(ctx.label.name + ".json") + marker = "/sysroot/sysroot-exnref-ehpic/" + base = [file for file in ctx.files._base if marker in file.path] + ctx.actions.write(spec, json.encode({ + "base": [{"relative": file.path.split(marker)[1], "path": file.path} for file in base], + "headers": ctx.file.headers.path, + "libc": ctx.file.libc.path, + "mman": ctx.file.mman.path, + })) + arguments = ctx.actions.args() + arguments.add(spec) + arguments.add(output.path) + bun_file_action(ctx, ctx.file._writer, source_files = [ctx.file._writer], arguments = [arguments], inputs = [spec, ctx.file.headers, ctx.file.libc, ctx.file.mman] + base, outputs = [output], mnemonic = "PostmasterLibcSysroot") + return [DefaultInfo(files = depset([output])), CcInfo(compilation_context = cc_common.create_compilation_context(headers = depset([output]), system_includes = depset([output.path + "/include"])))] + +_libc_sysroot = rule( + implementation = _sysroot_impl, + attrs = { + "headers": attr.label(allow_single_file = True, mandatory = True), + "libc": attr.label(allow_single_file = True, mandatory = True), + "mman": attr.label(allow_single_file = True, mandatory = True), + "_base": attr.label(default = Label("@wasix_toolchain//:linker_files")), + "_writer": attr.label(default = Label("//build_defs/wasix/postmaster:libc-sysroot.mts"), allow_single_file = True), + }, + toolchains = BUN_SOURCE_TOOLCHAINS, +) + +def patched_libc_targets(sources): + """Canonical wasm32/POSIX/PIC/exnref Makefile-eh profile, no Make driver.""" + libc_headers( + name = "headers", + makefile = "Makefile-eh", + sources = native.glob(["libc-bottom-half/headers/public/**", "libc-top-half/musl/include/**", "libc-top-half/musl/arch/generic/bits/**", "libc-top-half/musl/arch/wasm32/bits/**"]) + ["libc-top-half/musl/tools/mkalltypes.sed"], + omit = sources["omit"], + target_compatible_with = _COMPATIBLE, + ) + # Package-relative paths in repository source copts are prefixed by the + # caller's actual canonical repository, never the workspace CWD. + prefix = native.package_relative_label(":Makefile-eh").workspace_root + "/" + common = [ + "-O2", "-DNDEBUG", "-ftls-model=local-exec", "-D_WASI_EMULATED_MMAN", "-D_WASI_EMULATED_PROCESS_CLOCKS", + "-fno-trapping-math", "-Wall", "-Wextra", "-Werror", "-mexception-handling", "-fwasm-exceptions", + "-mllvm", "--wasm-enable-sjlj", "-mllvm", "--wasm-enable-eh", "-mllvm", "--wasm-use-legacy-eh=false", + "-mthread-model", "posix", "-pthread", "-fPIC", "-nostdinc", + "-isystem", Label("@wasix_toolchain//:llvm/bin/clang").workspace_root + "/llvm/lib/clang/21/include", + "-I" + prefix + "libc-bottom-half/cloudlibc/src", + ] + ["-Wno-" + name for name in ["incompatible-function-pointer-types", "null-pointer-arithmetic", "unused-parameter", "sign-compare", "unused-variable", "unused-function", "ignored-attributes", "missing-braces", "ignored-pragmas", "unused-but-set-variable", "unknown-warning-option", "unused-command-line-argument"]] + private_headers = native.glob(["libc-bottom-half/**/*.h", "libc-top-half/**/*.h", "dlmalloc/include/**"]) + bottom_includes = ["libc-bottom-half/headers/private", "libc-bottom-half/cloudlibc/src/include", "libc-bottom-half/cloudlibc/src", "libc-top-half/musl/src/include", "libc-top-half/musl/src/internal"] + top_includes = ["libc-top-half/musl/src/include", "libc-top-half/musl/src/internal", "libc-top-half/musl/arch/wasm32", "libc-top-half/musl/arch/generic", "libc-top-half/headers/private"] + top_flags = ["-Wno-" + name for name in ["parentheses", "shift-op-parentheses", "bitwise-op-parentheses", "logical-op-parentheses", "string-plus-int", "dangling-else", "unknown-pragmas"]] + special = sources["printscan"] + sources["bulk"] + groups = [ + ("bottom", sources["bottom"], bottom_includes, []), + ("top", [path for path in sources["top"] if path not in special and not path.endswith(".s")], top_includes, top_flags), + ("malloc", sources["malloc"], ["dlmalloc/include"], []), + ("printscan", sources["printscan"], top_includes, top_flags + ['-D__wasilibc_printscan_full_support_option="add -lc-printscan-long-double to the link command"']), + ("bulk", sources["bulk"], top_includes, top_flags + ["-mbulk-memory", "-DBULK_MEMORY_THRESHOLD=32"]), + ("mman", sources["mman"], [], []), + ] + for name, paths, includes, flags in groups: + cc_library(name = name, srcs = paths, hdrs = private_headers, textual_hdrs = ["dlmalloc/src/malloc.c"] if name == "malloc" else [], deps = [":headers"], copts = common + ["-I" + prefix + path for path in includes] + flags, linkstatic = True, target_compatible_with = _COMPATIBLE) + cc_library(name = "assembly", srcs = [path for path in sources["top"] if path.endswith(".s")], copts = common, linkstatic = True, target_compatible_with = _COMPATIBLE) + cc_library(name = "libc", deps = [":" + name for name in ["bottom", "top", "malloc", "printscan", "bulk", "assembly"]], target_compatible_with = _COMPATIBLE) + archive_groups = [(name, paths) for name, paths, _includes, _flags in groups if name != "mman"] + [("assembly", [path for path in sources["top"] if path.endswith(".s")])] + _libc_archive(name = "libc_archive", deps = [":" + name for name, _paths in archive_groups], source_groups = [json.encode(paths) for _name, paths in archive_groups], output_name = "libc.a", target_compatible_with = _COMPATIBLE, exec_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"]) + _libc_archive(name = "mman_archive", deps = [":mman"], source_groups = [json.encode(sources["mman"])], output_name = "libwasi-emulated-mman.a", target_compatible_with = _COMPATIBLE, exec_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"]) + _libc_sysroot(name = "sysroot", headers = ":headers", libc = ":libc_archive", mman = ":mman_archive", target_compatible_with = _COMPATIBLE) diff --git a/build_defs/wasix/postmaster/libc_toolchain/BUILD.bazel b/build_defs/wasix/postmaster/libc_toolchain/BUILD.bazel new file mode 100644 index 000000000..e46297b2c --- /dev/null +++ b/build_defs/wasix/postmaster/libc_toolchain/BUILD.bazel @@ -0,0 +1,31 @@ +load("@rules_cc//cc:defs.bzl", "cc_toolchain") +load("//build_defs/wasix/postmaster:libc-toolchain.bzl", "libc_cc_toolchain_config") + +package(default_visibility = ["//visibility:public"]) + +constraint_setting(name = "compiler_kind") +constraint_value(name = "raw_clang", constraint_setting = ":compiler_kind") +platform(name = "construction", constraint_values = ["@platforms//cpu:wasm32", "@platforms//os:wasi", ":raw_clang"]) +libc_cc_toolchain_config(name = "config") +filegroup(name = "empty") +cc_toolchain( + name = "compiler", + toolchain_identifier = "oliphaunt-postmaster-patched-libc-clang", + toolchain_config = ":config", + all_files = "@wasix_toolchain//:llvm_files", + ar_files = "@wasix_toolchain//:llvm_files", + as_files = "@wasix_toolchain//:llvm_files", + compiler_files = "@wasix_toolchain//:llvm_files", + linker_files = "@wasix_toolchain//:llvm_files", + dwp_files = ":empty", + objcopy_files = ":empty", + strip_files = ":empty", + supports_param_files = 0, +) +toolchain( + name = "toolchain", + toolchain = ":compiler", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", + target_compatible_with = ["@platforms//cpu:wasm32", "@platforms//os:wasi", ":raw_clang"], + exec_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) diff --git a/build_defs/wasix/postmaster/metadata.mts b/build_defs/wasix/postmaster/metadata.mts new file mode 100644 index 000000000..4eda4408a --- /dev/null +++ b/build_defs/wasix/postmaster/metadata.mts @@ -0,0 +1,304 @@ +import assert from 'node:assert/strict'; +import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { + renderCargoToml, + resolveCargoWorkspaceInheritance, +} from '../../../tools/packaging/cargo-manifest.mts'; + +type Table = Record; + +export function postmasterSource(pin: Table, sha256: string) { + const upstream = /^https:\/\/github\.com\/([^/]+)\/([^/.]+)\.git$/u.exec(pin.url ?? ''); + assert(upstream && /^[a-f0-9]{40}$/u.test(pin.commit), 'Immutable GitHub source required'); + assert(/^[a-f0-9]{64}$/u.test(sha256), 'Immutable source archive digest required'); + return { + url: `https://codeload.github.com/${upstream[1]}/${upstream[2]}/tar.gz/${pin.commit}`, + sha256, + strip_prefix: `${upstream[2]}-${pin.commit}`, + commit: pin.commit, + }; +} + +function normalized(value: string) { + assert( + typeof value === 'string' && + value && + /^[A-Za-z0-9_./+-]+$/u.test(value) && + !value.includes('\\') && + !path.posix.isAbsolute(value) && + value.split('/').every((part) => part && part !== '.' && part !== '..'), + `Unsafe source path: ${value}`, + ); + return value; +} + +/** Keep complete diff sections and hunk bytes, changing only the leaf path prefix. */ +export function postmasterLeafPatch(original: string, directory: string): string { + const prefix = `${normalized(directory)}/`; + assert(original.startsWith('diff --git '), 'Expected canonical Git patch sections'); + const result: string[] = []; + for (const section of original.split(/(?=^diff --git )/mu)) { + if (!section) continue; + const paths = /^diff --git a\/([^\n ]+) b\/([^\n ]+)\n/u.exec(section); + assert(paths, 'Unsupported canonical Git patch path'); + normalized(paths[1]); + normalized(paths[2]); + const before = paths[1].startsWith(prefix); + const after = paths[2].startsWith(prefix); + assert.equal(before, after, 'Canonical patch crosses a crate source boundary'); + if (!before) continue; + assert(!/^rename (?:from|to) /mu.test(section), 'Crate patch renames require explicit support'); + result.push( + section + .replace( + paths[0], + `diff --git a/${paths[1].slice(prefix.length)} b/${paths[2].slice(prefix.length)}\n`, + ) + .replace( + new RegExp( + `^(--- a/|\\+\\+\\+ b/)${prefix.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&')}`, + 'gm', + ), + '$1', + ), + ); + } + return result.join(''); +} + +/** Select the authored binary's features; Cargo remains the dependency/feature resolver. */ +export function postmasterRoleManifest(original: Table, binary: string): string { + assert(original.package && original.workspace, 'Expected the canonical standalone executor'); + assert.deepEqual(original.features?.default, [], 'Executor default features must remain empty'); + const binaries = original.bin?.filter((row: Table) => row.name === binary); + assert.equal(binaries?.length, 1, `Expected one canonical binary ${binary}`); + const features = binaries[0]['required-features']; + assert(Array.isArray(features) && features.length, 'Canonical binary features required'); + for (const feature of features) + assert( + Object.hasOwn(original.features, feature), + `Unknown canonical binary feature ${feature}`, + ); + const result = structuredClone(original); + delete result.workspace; + result.features.default = [...features]; + return renderCargoToml(result); +} + +/** Move only the conventional path patches into a self-contained Cargo workspace. */ +export function postmasterCargoManifest( + original: Table, + lock: Table, + wasmerWorkspace: Table, + readManifest: (relative: string) => Table, + binary: string, +): string { + assert.equal(lock.version, 4); + assert(!original.patch && !original.replace, 'Unexpected authored executor source override'); + assert.deepEqual(original.workspace, {}, 'Expected the conventional standalone workspace'); + const local = new Map(); + for (const member of wasmerWorkspace.members) { + normalized(member); + const manifest = resolveCargoWorkspaceInheritance( + readManifest(`${member}/Cargo.toml`), + wasmerWorkspace, + ); + const pkg = manifest.package; + assert(!local.has(pkg.name), `Duplicate pinned workspace package ${pkg.name}`); + local.set(pkg.name, { ...pkg, member }); + } + const patches: Table = {}; + for (const table of [original, ...Object.values(original.target ?? {})] as Table[]) { + for (const section of ['dependencies', 'build-dependencies', 'dev-dependencies']) { + for (const [name, dependency] of Object.entries(table[section] ?? {}) as [string, Table][]) { + const pkg = local.get(dependency?.package ?? name); + if (!pkg) continue; + const resolutions = lock.package.filter( + (row: Table) => row.name === pkg.name && row.version === pkg.version, + ); + assert.equal(resolutions.length, 1, `Expected canonical local resolution ${pkg.name}`); + assert.equal( + resolutions[0].source, + undefined, + `Expected canonical path source ${pkg.name}`, + ); + assert.equal(dependency.version, `=${pkg.version}`, `Stale executor pin ${name}`); + patches[pkg.name] = { path: `wasmer/${pkg.member}` }; + } + } + } + assert(Object.keys(patches).length, 'No canonical Wasmer path dependencies'); + const result = Bun.TOML.parse(postmasterRoleManifest(original, binary)); + result.workspace = { exclude: ['wasmer'] }; + result.patch = { 'crates-io': patches }; + return renderCargoToml(result); +} + +/** Import every genuine path-source row; standard Cargo selects the role's closure. */ +export function postmasterCargoSources( + lock: Table, + ownPackage: Table, + source: ReturnType, + canonicalPatch: string, + readManifest: (relative: string) => Table, +) { + assert.equal(lock.version, 4); + const ownRows = lock.package.filter( + (row: Table) => row.name === ownPackage.name && row.version === ownPackage.version, + ); + assert.equal( + ownRows.length, + 1, + 'Canonical executor package must match its Cargo lock exactly once', + ); + assert.equal(ownRows[0].source, undefined, 'Canonical executor must retain its path source'); + const workspace = readManifest('Cargo.toml').workspace; + assert(Array.isArray(workspace?.members), 'Expected the pinned Wasmer workspace'); + const members = workspace.members.map((directory: string) => { + normalized(directory); + return { + directory, + manifest: resolveCargoWorkspaceInheritance( + readManifest(`${directory}/Cargo.toml`), + workspace, + ), + }; + }); + const sources: Table = {}; + const patches: Record = {}; + for (const pkg of lock.package) { + if ( + pkg.source !== undefined || + (pkg.name === ownPackage.name && pkg.version === ownPackage.version) + ) + continue; + const id = `${pkg.name} ${pkg.version}`; + assert(/^[A-Za-z0-9_-]+$/u.test(pkg.name), `Unsafe Cargo package name ${pkg.name}`); + assert(!Object.hasOwn(sources, id), `Duplicate canonical path package ${id}`); + const resolutions = lock.package.filter( + (row: Table) => row.name === pkg.name && row.version === pkg.version, + ); + assert.equal(resolutions.length, 1, `Ambiguous canonical source identity ${id}`); + const matching = members.filter( + ({ manifest }: Table) => + manifest.package.name === pkg.name && manifest.package.version === pkg.version, + ); + assert.equal(matching.length, 1, `Expected one immutable workspace member ${id}`); + const directory = matching[0].directory; + const patch = postmasterLeafPatch(canonicalPatch, directory); + const patchPath = `patches/cargo/${pkg.name}.patch`; + if (patch) patches[patchPath] = patch; + sources[id] = { + url: source.url, + sha256: source.sha256, + strip_prefix: `${source.strip_prefix}/${directory}`, + patches: patch ? [patchPath] : [], + }; + } + assert(Object.keys(sources).length, 'Canonical Cargo lock contains no patched path sources'); + return { sources, patches }; +} + +/** Metadata target placeholders come from the authored manifest and existing sources. */ +export function postmasterCargoTargets(manifest: Table, exists: (relative: string) => boolean) { + const targets: string[] = []; + for (const row of [ + ...(manifest.bin ?? []), + ...(manifest.example ?? []), + ...(manifest.test ?? []), + ...(manifest.bench ?? []), + ]) { + const relative = normalized(row.path); + assert(exists(relative), `Missing canonical Cargo target ${relative}`); + targets.push(relative); + } + const library = manifest.lib?.path ?? 'src/lib.rs'; + if (manifest.lib || exists(library)) { + normalized(library); + assert(exists(library), `Missing canonical Cargo target ${library}`); + targets.push(library); + } + const build = manifest.package.build; + if (build !== false && (typeof build === 'string' || exists('build.rs'))) { + const relative = normalized(build ?? 'build.rs'); + assert(exists(relative), `Missing canonical Cargo target ${relative}`); + targets.push(relative); + } + assert(targets.length, 'Canonical Cargo package has no source targets'); + return [...new Set(targets)].sort(); +} + +if (import.meta.main) { + if (Bun.argv[2] === 'source') { + const [, sourcePin, expectedCommit, sha256] = Bun.argv.slice(2); + const pin = Bun.TOML.parse(readFileSync(sourcePin, 'utf8')); + assert.equal(pin.commit, expectedCommit, 'Source pin changed; verify its immutable archive'); + console.log(JSON.stringify(postmasterSource(pin, sha256))); + process.exit(0); + } + const [command, workspaceFile, lockFile, wasmerFile, sourceFile, patchFile, output, rolesJson] = + Bun.argv.slice(2); + assert( + command === 'cargo' && + workspaceFile && + lockFile && + wasmerFile && + sourceFile && + patchFile && + output && + rolesJson, + ); + const original = Bun.TOML.parse(readFileSync(workspaceFile, 'utf8')); + const lockBytes = readFileSync(lockFile); + const lock = Bun.TOML.parse(lockBytes.toString('utf8')); + const sourceRoot = path.dirname(wasmerFile); + const readManifest = (relative: string) => + Bun.TOML.parse(readFileSync(path.join(sourceRoot, relative), 'utf8')); + const workspace = readManifest('Cargo.toml').workspace; + const projection = postmasterCargoSources( + lock, + original.package, + JSON.parse(readFileSync(sourceFile, 'utf8')).wasmer, + readFileSync(patchFile, 'utf8'), + readManifest, + ); + const targets = postmasterCargoTargets(original, (relative) => + existsSync(path.join(path.dirname(workspaceFile), relative)), + ); + const roles = JSON.parse(rolesJson); + assert(Object.keys(roles).length, 'Canonical binary role selections required'); + for (const [role, binary] of Object.entries(roles) as [string, string][]) { + assert.equal(normalized(role).split('/').length, 1, 'Cargo role must name one directory'); + const directory = path.join(output, role); + mkdirSync(directory, { recursive: true }); + writeFileSync( + path.join(directory, 'Cargo.toml'), + postmasterCargoManifest(original, lock, workspace, readManifest, binary), + ); + writeFileSync(path.join(directory, 'Cargo.lock'), lockBytes); + for (const target of targets) { + const file = path.join(directory, target); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, ''); + } + } + mkdirSync(output, { recursive: true }); + for (const [relative, content] of Object.entries(projection.patches)) { + const file = path.join(output, relative); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, content); + } + writeFileSync( + path.join(output, 'cargo-sources.json'), + `${JSON.stringify(projection.sources, null, 2)}\n`, + ); + console.log( + JSON.stringify({ + packages: Object.keys(projection.sources), + patches: Object.keys(projection.patches), + manifests: workspace.members.map((member: string) => `${member}/Cargo.toml`), + targets, + }), + ); +} diff --git a/build_defs/wasix/postmaster/metadata.test.mts b/build_defs/wasix/postmaster/metadata.test.mts new file mode 100644 index 000000000..4b689cf7d --- /dev/null +++ b/build_defs/wasix/postmaster/metadata.test.mts @@ -0,0 +1,242 @@ +import { expect, test } from 'bun:test'; +import { + postmasterCargoManifest, + postmasterCargoSources, + postmasterCargoTargets, + postmasterLeafPatch, + postmasterRoleManifest, + postmasterSource, +} from './metadata.mts'; + +const pin = { url: 'https://github.com/wasmerio/wasmer.git', commit: 'a'.repeat(40) }; +const source = postmasterSource(pin, 'b'.repeat(64)); +const patch = `diff --git a/Cargo.lock b/Cargo.lock +--- a/Cargo.lock ++++ b/Cargo.lock +@@ -1 +1 @@ +-workspace ++workspace-new +diff --git a/lib/engine/src/lib.rs b/lib/engine/src/lib.rs +--- a/lib/engine/src/lib.rs ++++ b/lib/engine/src/lib.rs +@@ -1 +1 @@ +-old ++new +diff --git a/lib/other/src/new.rs b/lib/other/src/new.rs +--- /dev/null ++++ b/lib/other/src/new.rs +@@ -0,0 +1 @@ ++added +`; + +test('projects full canonical hunks into a leaf without changing content', () => { + expect(postmasterLeafPatch(patch, 'lib/engine')).toBe(`diff --git a/src/lib.rs b/src/lib.rs +--- a/src/lib.rs ++++ b/src/lib.rs +@@ -1 +1 @@ +-old ++new +`); + expect(postmasterLeafPatch(patch, 'lib/other')).toContain('--- /dev/null\n+++ b/src/new.rs'); + expect(postmasterLeafPatch(patch, 'lib/untouched')).toBe(''); + expect(() => postmasterLeafPatch(patch, '../engine')).toThrow('Unsafe source path'); + expect(() => + postmasterLeafPatch(patch.replace('b/lib/engine/', 'b/lib/other/'), 'lib/engine'), + ).toThrow('crosses'); +}); + +test('uses the canonical binary feature and retains package and dependency pins', () => { + const manifest = { + package: { name: 'executor', version: '7.2.0-alpha.2' }, + workspace: {}, + features: { default: [], execute: ['dep:runtime'], compile: ['dep:llvm'] }, + dependencies: { + runtime: { version: '=1.0.0', optional: true }, + llvm: { version: '=2.0.0', optional: true }, + }, + 'dev-dependencies': { testCompiler: '=3.0.0' }, + bin: [ + { name: 'executor', 'required-features': ['execute'] }, + { name: 'compiler', 'required-features': ['compile'] }, + ], + }; + const result = Bun.TOML.parse(postmasterRoleManifest(manifest, 'executor')); + expect(result.features.default).toEqual(['execute']); + expect(result.package).toEqual(manifest.package); + expect(result.dependencies).toEqual(manifest.dependencies); + expect(result['dev-dependencies']).toEqual(manifest['dev-dependencies']); + expect(result.workspace).toBeUndefined(); + expect(() => postmasterRoleManifest(manifest, 'missing')).toThrow('one canonical binary'); + expect(() => + postmasterRoleManifest( + { ...manifest, features: { ...manifest.features, default: ['compile'] } }, + 'executor', + ), + ).toThrow('empty'); +}); + +test('imports every genuine locked path source without selecting optional features', () => { + const own = { name: 'executor', version: '7.2.0-alpha.2' }; + const lock = { + version: 4, + package: [ + own, + { name: 'engine', version: '1.2.3' }, + { name: 'optional-compiler', version: '1.2.3' }, + { name: 'registry', version: '1.0.0', source: 'registry+https://example.invalid' }, + ], + }; + const manifests = { + 'Cargo.toml': { + workspace: { + members: ['lib/engine', 'lib/compiler', 'lib/unlocked'], + package: { version: '1.2.3' }, + }, + }, + 'lib/engine/Cargo.toml': { package: { name: 'engine', version: { workspace: true } } }, + 'lib/compiler/Cargo.toml': { + package: { name: 'optional-compiler', version: { workspace: true } }, + }, + 'lib/unlocked/Cargo.toml': { package: { name: 'unlocked', version: { workspace: true } } }, + }; + const read = (relative: string) => manifests[relative]; + const projection = postmasterCargoSources(lock, own, source, patch, read); + expect(Object.keys(projection.sources)).toEqual(['engine 1.2.3', 'optional-compiler 1.2.3']); + expect(projection.sources['engine 1.2.3'].strip_prefix).toBe(`wasmer-${pin.commit}/lib/engine`); + expect(projection.sources['engine 1.2.3'].patches).toEqual(['patches/cargo/engine.patch']); + expect(Object.keys(projection.patches)).toEqual(['patches/cargo/engine.patch']); + expect(projection.sources['optional-compiler 1.2.3'].patches).toEqual([]); + expect(projection.sources['unlocked 1.2.3']).toBeUndefined(); + expect(() => + postmasterCargoSources({ ...lock, package: [own] }, own, source, patch, read), + ).toThrow('no patched path sources'); + expect(() => + postmasterCargoSources(lock, { ...own, version: '7.2.0-alpha.3' }, source, patch, read), + ).toThrow('executor package must match'); + expect(() => + postmasterCargoSources( + { + ...lock, + package: [{ ...own, source: 'registry+https://example.invalid' }, ...lock.package.slice(1)], + }, + own, + source, + patch, + read, + ), + ).toThrow('retain its path source'); + expect(() => + postmasterCargoSources( + { + ...lock, + package: [ + ...lock.package, + { name: 'engine', version: '1.2.3', source: 'registry+https://example.invalid' }, + ], + }, + own, + source, + patch, + read, + ), + ).toThrow('Ambiguous canonical source identity'); + expect(() => + postmasterCargoSources( + { ...lock, package: [own, { name: 'engine', version: '1.2.4' }] }, + own, + source, + patch, + read, + ), + ).toThrow('one immutable workspace member'); + expect(() => + postmasterCargoSources(lock, own, source, patch, (relative) => + relative === 'Cargo.toml' ? { workspace: { members: ['../engine'] } } : read(relative), + ), + ).toThrow('Unsafe source path'); + expect(() => + postmasterCargoSources( + { ...lock, package: [own, { name: '../engine', version: '1.2.3' }] }, + own, + source, + patch, + read, + ), + ).toThrow('Unsafe Cargo package'); + expect(() => postmasterSource({ ...pin, commit: 'main' }, 'b'.repeat(64))).toThrow( + 'Immutable GitHub', + ); +}); + +test('metadata target placeholders require authentic declared source paths', () => { + const manifest = { + package: { name: 'executor' }, + bin: [{ name: 'executor', path: 'src/bin/executor.rs' }], + }; + const files = new Set(['src/lib.rs', 'src/bin/executor.rs']); + expect(postmasterCargoTargets(manifest, (relative) => files.has(relative))).toEqual([ + 'src/bin/executor.rs', + 'src/lib.rs', + ]); + expect(() => postmasterCargoTargets(manifest, (relative) => relative === 'src/lib.rs')).toThrow( + 'Missing canonical Cargo target src/bin/executor.rs', + ); + expect(() => + postmasterCargoTargets( + { ...manifest, bin: [{ name: 'executor', path: '../other.rs' }] }, + () => true, + ), + ).toThrow('Unsafe source path'); + expect(() => + postmasterCargoTargets( + { ...manifest, bin: [{ name: 'executor', path: 'src/\nother.rs' }] }, + () => true, + ), + ).toThrow('Unsafe source path'); + expect(() => + postmasterCargoTargets( + { ...manifest, package: { name: 'executor', build: 'other-build.rs' } }, + (relative) => files.has(relative), + ), + ).toThrow('Missing canonical Cargo target other-build.rs'); +}); + +test('derives conventional direct path patches from exact workspace and lock identities', () => { + const original = { + package: { name: 'executor', version: '7.2.0-alpha.2', edition: '2024' }, + workspace: {}, + features: { default: [], execute: ['dep:runtime'] }, + dependencies: { runtime: { package: 'engine', version: '=1.2.3', optional: true } }, + 'dev-dependencies': { test: '1.0' }, + bin: [{ name: 'executor', 'required-features': ['execute'] }], + }; + const lock = { version: 4, package: [{ name: 'engine', version: '1.2.3' }] }; + const workspace = { members: ['lib/engine'], package: { version: '1.2.3' } }; + const read = (relative: string) => { + expect(relative).toBe('lib/engine/Cargo.toml'); + return { package: { name: 'engine', version: { workspace: true } } }; + }; + const result = Bun.TOML.parse( + postmasterCargoManifest(original, lock, workspace, read, 'executor'), + ); + expect(result.patch['crates-io']).toEqual({ engine: { path: 'wasmer/lib/engine' } }); + expect(result.workspace).toEqual({ exclude: ['wasmer'] }); + expect(result.features.default).toEqual(['execute']); + expect(result.dependencies).toEqual(original.dependencies); + expect(result['dev-dependencies']).toEqual(original['dev-dependencies']); + expect(() => + postmasterCargoManifest(original, { ...lock, package: [] }, workspace, read, 'executor'), + ).toThrow('canonical local resolution'); + expect(() => + postmasterCargoManifest( + { + ...original, + dependencies: { runtime: { package: 'engine', version: '=1.2.4', optional: true } }, + }, + lock, + workspace, + read, + 'executor', + ), + ).toThrow('Stale executor pin'); +}); diff --git a/build_defs/wasix/postmaster/native-receipts.mts b/build_defs/wasix/postmaster/native-receipts.mts new file mode 100644 index 000000000..3e0943977 --- /dev/null +++ b/build_defs/wasix/postmaster/native-receipts.mts @@ -0,0 +1,199 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; + +export const canonicalJson = (value: any): string => + JSON.stringify(value, (_key, row) => + row && typeof row === 'object' && !Array.isArray(row) + ? Object.fromEntries( + Object.keys(row) + .sort() + .map((key) => [key, row[key]]), + ) + : row, + ); +export const digest = (bytes: string | Uint8Array) => + createHash('sha256').update(bytes).digest('hex'); +const sha = (value: unknown) => + assert( + typeof value === 'string' && /^[0-9a-f]{64}$/.test(value), + 'Invalid native receipt SHA-256', + ); +const keys = (value: any, names: string[]) => { + assert( + value && typeof value === 'object' && !Array.isArray(value), + 'Native receipt must be an object', + ); + assert.deepEqual(Object.keys(value).sort(), [...names].sort(), 'Native receipt fields differ'); +}; +export function fileIdentity(value: any) { + keys(value, ['sha256', 'size']); + sha(value.sha256); + assert(Number.isSafeInteger(value.size) && value.size > 0, 'Invalid native receipt file size'); + return value; +} +export function runtimeAbiFacts(abi: any) { + assert.equal(abi.schema, 'oliphaunt.wasix-postmaster.runtime-abi.native.v2'); + const { runtime_abi_id: id, ...contract } = abi; + sha(id); + assert.equal(id, digest(canonicalJson(contract)), 'Native runtime ABI contract hash differs'); + assert.equal(abi.artifact_abi_version, 21, 'Native serialized ABI differs'); + const version = (name: string) => { + const ids = new Set( + Object.values(abi.roles) + .flatMap((role) => role.dependencies.map((row: any) => row.id)) + .filter((id: string) => id.startsWith(`${name} `)), + ); + assert.equal(ids.size, 1, `Ambiguous actual native ${name} identity`); + return [...ids][0].slice(name.length + 1); + }; + const target = abi.rust.target; + assert(typeof target === 'string'); + const hostAbi = target.endsWith('-linux-gnu') + ? 'linux-gnu' + : target.endsWith('-apple-darwin') + ? 'darwin' + : undefined; + assert(hostAbi, `Unsupported postmaster native host target: ${target}`); + assert.match(abi.source.wasmer.commit, /^[0-9a-f]{40}$/); + sha(abi.lock_sha256); + return { + wasmerVersion: version('wasmer'), + wasixVersion: version('wasmer-wasix'), + hostAbi, + target, + }; +} +export function nativeWasmerReceipt(value: any): Record { + keys(value, ['schema', 'runtime_abi', 'canonical_patch_sha256', 'compiler']); + assert.equal(value.schema, 'oliphaunt.wasix-postmaster.wasmer-build.native.v1'); + const facts = runtimeAbiFacts(value.runtime_abi); + sha(value.canonical_patch_sha256); + fileIdentity(value.compiler); + const features = value.runtime_abi.roles.executor.features; + assert( + Array.isArray(features) && features.every((feature: unknown) => typeof feature === 'string'), + ); + assert.equal(new Set(features).size, features.length); + return { + schema: value.schema, + runtime_abi_id: value.runtime_abi.runtime_abi_id, + artifact_abi_version: String(value.runtime_abi.artifact_abi_version), + rustc_host: facts.target, + host_abi: facts.hostAbi, + wasmer_source_commit: value.runtime_abi.source.wasmer.commit, + wasmer_patch_sha256: value.canonical_patch_sha256, + wasmer_cargo_lock_sha256: value.runtime_abi.lock_sha256, + sysroot_variant: 'oliphaunt.wasix-postmaster.libc.native.v1', + executor_features: canonicalJson([...features].sort()), + }; +} +export function nativeExecutorReceipt( + value: any, + wasmer: Record, + wasmerHash: string, + executor: any, +) { + keys(value, [ + 'schema', + 'runtime_abi_id', + 'wasmer_build_receipt_sha256', + 'binary', + 'package', + 'features', + ]); + assert.equal(value.schema, 'oliphaunt.wasix-postmaster.executor-build.native.v1'); + assert.equal(value.runtime_abi_id, wasmer.runtime_abi_id); + assert.equal(value.wasmer_build_receipt_sha256, wasmerHash); + assert.equal(value.package, 'oliphaunt-wasix-postmaster-executor'); + assert( + Array.isArray(value.features) && + value.features.includes('product-executor') && + !value.features.includes('product-compiler'), + ); + assert.equal(new Set(value.features).size, value.features.length); + assert.equal( + canonicalJson([...value.features].sort()), + wasmer.executor_features, + 'Executor features differ from the selected native ABI role', + ); + assert.deepEqual(fileIdentity(value.binary), executor); + return { schema: value.schema, executor_binary_sha256: value.binary.sha256 }; +} +export function nativeGuestReceipt(value: any): Record { + keys(value, [ + 'schema', + 'source', + 'configuration', + 'sysroot', + 'compiler', + 'core_profile', + 'postgres_version', + 'installed_closure_sha256', + 'atomic_fence_total', + 'final_wasm_concurrency_receipt_sha256', + 'linear_memory_install_receipt_sha256', + ]); + assert.equal(value.schema, 'oliphaunt.wasix-postmaster.guest-build.native.v1'); + keys(value.source, ['postgresql', 'overlays', 'patches']); + keys(value.source.postgresql, ['version', 'url', 'sha256']); + assert.equal(value.core_profile, 'release-o3'); + assert.equal(value.postgres_version, value.source.postgresql.version); + assert.match(value.postgres_version, /^[0-9]+\.[0-9]+$/); + sha(value.source.postgresql.sha256); + assert.equal(new URL(value.source.postgresql.url).protocol, 'https:'); + for (const kind of ['overlays', 'patches']) { + assert(Array.isArray(value.source[kind]) && value.source[kind].length > 0); + const paths = new Set(); + for (const row of value.source[kind]) { + keys(row, ['path', 'sha256', 'size']); + assert( + typeof row.path === 'string' && + row.path.startsWith('src/') && + row.path.split('/').every((part: string) => part && part !== '.' && part !== '..') && + !paths.has(row.path), + ); + paths.add(row.path); + fileIdentity({ sha256: row.sha256, size: row.size }); + } + } + assert(value.configuration && Object.keys(value.configuration).length > 0); + for (const identity of Object.values(value.configuration)) fileIdentity(identity); + keys(value.sysroot, ['schema', 'source', 'patch_sha256', 'closure_sha256']); + assert.equal(value.sysroot.schema, 'oliphaunt.wasix-postmaster.libc.native.v1'); + keys(value.sysroot.source, ['commit', 'sha256', 'strip_prefix', 'url']); + assert.match(value.sysroot.source.commit, /^[0-9a-f]{40}$/); + assert.equal(new URL(value.sysroot.source.url).protocol, 'https:'); + assert( + typeof value.sysroot.source.strip_prefix === 'string' && + value.sysroot.source.strip_prefix + .split('/') + .every((part: string) => part && part !== '.' && part !== '..'), + ); + sha(value.sysroot.source.sha256); + sha(value.sysroot.patch_sha256); + sha(value.sysroot.closure_sha256); + fileIdentity(value.compiler); + assert(Number.isSafeInteger(value.atomic_fence_total) && value.atomic_fence_total > 0); + for (const name of [ + 'installed_closure_sha256', + 'final_wasm_concurrency_receipt_sha256', + 'linear_memory_install_receipt_sha256', + ]) + sha(value[name]); + return Object.fromEntries( + Object.entries(value) + .filter(([key]) => + [ + 'schema', + 'core_profile', + 'postgres_version', + 'installed_closure_sha256', + 'atomic_fence_total', + 'final_wasm_concurrency_receipt_sha256', + 'linear_memory_install_receipt_sha256', + ].includes(key), + ) + .map(([key, row]) => [key, String(row)]) + .concat([['sysroot_variant', value.sysroot.schema]]), + ); +} diff --git a/build_defs/wasix/postmaster/native-receipts.test.mts b/build_defs/wasix/postmaster/native-receipts.test.mts new file mode 100644 index 000000000..c392db7aa --- /dev/null +++ b/build_defs/wasix/postmaster/native-receipts.test.mts @@ -0,0 +1,146 @@ +import { test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { + canonicalJson, + digest, + nativeExecutorReceipt, + nativeGuestReceipt, + nativeWasmerReceipt, + runtimeAbiFacts, +} from './native-receipts.mts'; + +const file = { sha256: 'a'.repeat(64), size: 42 }; +function contract() { + const abi: any = { + schema: 'oliphaunt.wasix-postmaster.runtime-abi.native.v2', + artifact_abi_version: 21, + package: { name: 'oliphaunt-wasix-postmaster-executor', version: '7.2.0-alpha.2' }, + lock_sha256: 'b'.repeat(64), + source: { wasmer: { commit: 'c'.repeat(40) } }, + rust: { target: 'x86_64-unknown-linux-gnu' }, + roles: Object.fromEntries( + ['executor', 'compiler'].map((role) => [ + role, + { + features: [`product-${role}`], + dependencies: [{ id: 'wasmer 7.2.0-alpha.2' }, { id: 'wasmer-wasix 0.702.0-alpha.2' }], + }, + ]), + ), + }; + abi.runtime_abi_id = digest(canonicalJson(abi)); + return abi; +} +test('native serialized contract rejects changed content and conflicting selected versions', () => { + const abi = contract(); + assert.equal(runtimeAbiFacts(abi).wasmerVersion, '7.2.0-alpha.2'); + abi.rust.target = 'aarch64-unknown-linux-gnu'; + assert.throws(() => runtimeAbiFacts(abi), /contract hash/); + const conflict = contract(); + conflict.roles.compiler.dependencies[0].id = 'wasmer 7.2.1'; + const { runtime_abi_id: _id, ...unsigned } = conflict; + conflict.runtime_abi_id = digest(canonicalJson(unsigned)); + assert.throws(() => runtimeAbiFacts(conflict), /Ambiguous/); +}); +test('native executor binding rejects stale carrier identity and compiler-bearing features', () => { + const wasmer = nativeWasmerReceipt({ + schema: 'oliphaunt.wasix-postmaster.wasmer-build.native.v1', + runtime_abi: contract(), + canonical_patch_sha256: file.sha256, + compiler: file, + }); + const receipt = { + schema: 'oliphaunt.wasix-postmaster.executor-build.native.v1', + runtime_abi_id: wasmer.runtime_abi_id, + wasmer_build_receipt_sha256: file.sha256, + binary: file, + package: 'oliphaunt-wasix-postmaster-executor', + features: ['product-executor'], + }; + nativeExecutorReceipt(receipt, wasmer, file.sha256, file); + assert.throws(() => + nativeExecutorReceipt( + { ...receipt, features: ['product-executor', 'product-compiler'] }, + wasmer, + file.sha256, + file, + ), + ); + assert.throws(() => nativeExecutorReceipt(receipt, wasmer, 'b'.repeat(64), file)); + assert.throws(() => nativeExecutorReceipt(receipt, wasmer, file.sha256, { ...file, size: 43 })); + assert.throws( + () => + nativeExecutorReceipt( + { ...receipt, features: ['product-executor', 'extra-feature'] }, + wasmer, + file.sha256, + file, + ), + /features differ/, + ); +}); +test('native guest namespace rejects legacy builder claims and duplicate source inputs', () => { + const receipt = { + schema: 'oliphaunt.wasix-postmaster.guest-build.native.v1', + source: { + postgresql: { + version: '18.4', + url: 'https://example.test/postgresql.tar.bz2', + sha256: file.sha256, + }, + patches: [{ path: 'src/postgres/patch.patch', ...file }], + overlays: [{ path: 'src/port.c', ...file }], + }, + configuration: { 'pg_config.h': file }, + sysroot: { + schema: 'oliphaunt.wasix-postmaster.libc.native.v1', + source: { + commit: 'c'.repeat(40), + sha256: file.sha256, + url: 'https://example.test/libc.tar.gz', + strip_prefix: 'libc', + }, + patch_sha256: file.sha256, + closure_sha256: file.sha256, + }, + compiler: file, + core_profile: 'release-o3', + postgres_version: '18.4', + installed_closure_sha256: file.sha256, + atomic_fence_total: 995, + final_wasm_concurrency_receipt_sha256: file.sha256, + linear_memory_install_receipt_sha256: file.sha256, + }; + nativeGuestReceipt(receipt); + assert.throws( + () => nativeGuestReceipt({ ...receipt, docker_image_id: `sha256:${file.sha256}` }), + /fields differ/, + ); + assert.throws(() => + nativeGuestReceipt({ + ...receipt, + source: { + ...receipt.source, + patches: [...receipt.source.patches, ...receipt.source.patches], + }, + }), + ); + assert.throws(() => nativeGuestReceipt({ ...receipt, postgres_version: '18.5' })); + assert.throws( + () => + nativeGuestReceipt({ + ...receipt, + source: { ...receipt.source, docker_image_id: file.sha256 }, + }), + /fields differ/, + ); + assert.throws(() => + nativeGuestReceipt({ + ...receipt, + sysroot: { + ...receipt.sysroot, + source: { ...receipt.sysroot.source, strip_prefix: '../libc' }, + }, + }), + ); +}); diff --git a/build_defs/wasix/postmaster/postgres-abi.c b/build_defs/wasix/postmaster/postgres-abi.c new file mode 100644 index 000000000..8166b3c04 --- /dev/null +++ b/build_defs/wasix/postmaster/postgres-abi.c @@ -0,0 +1,27 @@ +#include "postgres.h" +#include + +#if !defined(__wasi__) || !defined(EXEC_BACKEND) +#error The postmaster requires the actual WASI EXEC_BACKEND port +#endif +#if !defined(PG_WASIX_ATOMIC_LATCH_STATE) || PG_WASIX_ATOMIC_LATCH_STATE != 1 +#error The postmaster requires the canonical packed atomic latch state +#endif +#if defined(OLIPHAUNT_WASM_SINGLE_USER) || defined(OLIPHAUNT_WASM_SINGLE_BACKEND_ATOMICS) +#error The postmaster cannot consume the embedded single-backend profile +#endif +#if !defined(HAVE_SYNC_FILE_RANGE) || HAVE_SYNC_FILE_RANGE != 1 +#error The constructed libc must supply sync_file_range +#endif +#if !defined(USE_UNNAMED_POSIX_SEMAPHORES) || defined(USE_ICU) || defined(USE_OPENSSL) || defined(HAVE_LIBZ) +#error The postmaster must preserve the canonical wasix-core capabilities +#endif + +_Static_assert(sizeof(long) == 4 && SIZEOF_LONG == 4, "Actual long must be LP32"); +_Static_assert(sizeof(void *) == 4 && SIZEOF_VOID_P == 4, "Actual pointers must be LP32"); +_Static_assert(sizeof(size_t) == 4 && SIZEOF_SIZE_T == 4, "Actual size_t must be LP32"); +_Static_assert(sizeof(off_t) == 8 && SIZEOF_OFF_T == 8, "Actual off_t must be 64 bits"); +_Static_assert(sizeof(Datum) == 4, "Actual PostgreSQL Datum must be LP32"); +_Static_assert(!FLOAT8PASSBYVAL, "LP32 PostgreSQL float8 must pass by reference"); +_Static_assert(MAXIMUM_ALIGNOF == 8 && BLCKSZ == 8192 && XLOG_BLCKSZ == 8192, + "Actual PostgreSQL storage ABI must retain the canonical profile"); diff --git a/build_defs/wasix/postmaster/postgres-config.bzl b/build_defs/wasix/postmaster/postgres-config.bzl new file mode 100644 index 000000000..13b7dd6d3 --- /dev/null +++ b/build_defs/wasix/postmaster/postgres-config.bzl @@ -0,0 +1,115 @@ +"""LP32 facts from the canonical wasix-core Configure oracle on built libc. + +The ABI/capability values were verified against the patched native sysroot. +Package and PostgreSQL versions come from the canonical source repository. +""" + +POSTMASTER_PG_CONFIG = { + "ALIGNOF_DOUBLE": "8", + "ALIGNOF_INT": "4", + "ALIGNOF_INT64_T": "8", + "ALIGNOF_LONG": "4", + "ALIGNOF_PG_INT128_TYPE": "16", + "ALIGNOF_SHORT": "2", + "BLCKSZ": "8192", + "CONFIGURE_ARGS": "\"Bazel wasm32 WASIX EXEC_BACKEND O3 ThinLTO PIC; canonical wasix-core template\"", + "DEF_PGPORT": "5432", + "DEF_PGPORT_STR": "\"5432\"", + "DLSUFFIX": "\".so\"", + "HAVE_COMPUTED_GOTO": "1", + "HAVE_DECL_FDATASYNC": "1", + "HAVE_DECL_F_FULLFSYNC": "0", + "HAVE_DECL_MEMSET_S": "0", + "HAVE_DECL_POSIX_FADVISE": "1", + "HAVE_DECL_PREADV": "1", + "HAVE_DECL_PWRITEV": "1", + "HAVE_DECL_STRCHRNUL": "1", + "HAVE_DECL_STRLCAT": "1", + "HAVE_DECL_STRLCPY": "1", + "HAVE_DECL_STRNLEN": "1", + "HAVE_DECL_STRSEP": "1", + "HAVE_DECL_TIMINGSAFE_BCMP": "0", + "HAVE_EXPLICIT_BZERO": "1", + "HAVE_FSEEKO": "1", + "HAVE_GCC__ATOMIC_INT32_CAS": "1", + "HAVE_GCC__ATOMIC_INT64_CAS": "1", + "HAVE_GCC__SYNC_CHAR_TAS": "1", + "HAVE_GCC__SYNC_INT32_CAS": "1", + "HAVE_GCC__SYNC_INT32_TAS": "1", + "HAVE_GCC__SYNC_INT64_CAS": "1", + "HAVE_GETOPT": "1", + "HAVE_GETOPT_H": "1", + "HAVE_GETOPT_LONG": "1", + "HAVE_IFADDRS_H": "1", + "HAVE_INET_ATON": "1", + "HAVE_INET_PTON": "1", + "HAVE_INTTYPES_H": "1", + "HAVE_INT_OPTERR": "1", + "HAVE_INT_OPTRESET": "1", + "HAVE_LIBM": "1", + "HAVE_MEMORY_H": "1", + "HAVE_MKDTEMP": "1", + "HAVE_POSIX_FADVISE": "1", + "HAVE_POSIX_FALLOCATE": "1", + "HAVE_PTHREAD": "1", + "HAVE_PTHREAD_BARRIER_WAIT": "1", + "HAVE_PTHREAD_PRIO_INHERIT": "1", + "HAVE_SOCKLEN_T": "1", + "HAVE_STDINT_H": "1", + "HAVE_STDLIB_H": "1", + "HAVE_STRERROR_R": "1", + "HAVE_STRINGS_H": "1", + "HAVE_STRING_H": "1", + "HAVE_STRLCAT": "1", + "HAVE_STRLCPY": "1", + "HAVE_STRNLEN": "1", + "HAVE_STRSEP": "1", + "HAVE_STRSIGNAL": "1", + "HAVE_STRUCT_OPTION": "1", + "HAVE_STRUCT_TM_TM_ZONE": "1", + "HAVE_SYNC_FILE_RANGE": "1", + "HAVE_SYSLOG": "1", + "HAVE_SYS_EPOLL_H": "1", + "HAVE_SYS_STAT_H": "1", + "HAVE_SYS_TYPES_H": "1", + "HAVE_TERMIOS_H": "1", + "HAVE_TYPEOF": "1", + "HAVE_UNISTD_H": "1", + "HAVE_USELOCALE": "1", + "HAVE__BUILTIN_BSWAP16": "1", + "HAVE__BUILTIN_BSWAP32": "1", + "HAVE__BUILTIN_BSWAP64": "1", + "HAVE__BUILTIN_CLZ": "1", + "HAVE__BUILTIN_CONSTANT_P": "1", + "HAVE__BUILTIN_CTZ": "1", + "HAVE__BUILTIN_FRAME_ADDRESS": "1", + "HAVE__BUILTIN_OP_OVERFLOW": "1", + "HAVE__BUILTIN_POPCOUNT": "1", + "HAVE__BUILTIN_TYPES_COMPATIBLE_P": "1", + "HAVE__BUILTIN_UNREACHABLE": "1", + "HAVE__STATIC_ASSERT": "1", + "MAXIMUM_ALIGNOF": "8", + "MEMSET_LOOP_LIMIT": "1024", + "PACKAGE_BUGREPORT": "\"pgsql-bugs@lists.postgresql.org\"", + "PACKAGE_NAME": "\"PostgreSQL\"", + "PACKAGE_TARNAME": "\"postgresql\"", + "PACKAGE_URL": "\"https://www.postgresql.org/\"", + "PG_CXX_PRINTF_ATTRIBUTE": "gnu_printf", + "PG_C_PRINTF_ATTRIBUTE": "__syslog__", + "PG_INT128_TYPE": "__int128", + "PG_KRB_SRVNAM": "\"postgres\"", + "RELSEG_SIZE": "131072", + "SIZEOF_LONG": "4", + "SIZEOF_LONG_LONG": "8", + "SIZEOF_OFF_T": "8", + "SIZEOF_SIZE_T": "4", + "SIZEOF_VOID_P": "4", + "STDC_HEADERS": "1", + "STRERROR_R_INT": "1", + "USE_SLICING_BY_8_CRC32C": "1", + "USE_SYSV_SHARED_MEMORY": "1", + "USE_UNNAMED_POSIX_SEMAPHORES": "1", + "XLOG_BLCKSZ": "8192", + "pg_restrict": "__restrict", + "restrict": "__restrict" +} diff --git a/build_defs/wasix/postmaster/postgres-overlay-test.bzl b/build_defs/wasix/postmaster/postgres-overlay-test.bzl new file mode 100644 index 000000000..428c015ac --- /dev/null +++ b/build_defs/wasix/postmaster/postgres-overlay-test.bzl @@ -0,0 +1,44 @@ +"""Declared PostgreSQL overlay paths fail before source acquisition.""" + +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts", "unittest") +load("//build_defs/native:repositories.bzl", "postgres_overlay_paths") + +def _paths_test_impl(ctx): + env = unittest.begin(ctx) + asserts.equals(env, {}, postgres_overlay_paths({})) + paths = postgres_overlay_paths({"template": "src/template/wasix-core", "header": "src/include/port/wasix-core.h"}) + asserts.equals(env, ["src/include/port/wasix-core.h", "src/template/wasix-core"], paths.keys()) + asserts.equals(env, "header", paths["src/include/port/wasix-core.h"]) + return unittest.end(env) + +_paths_test = unittest.make(_paths_test_impl) + +def _subject_impl(ctx): + postgres_overlay_paths(ctx.attr.overlays) + return [] + +_subject = rule(implementation = _subject_impl, attrs = {"overlays": attr.string_dict()}) + +def _rejected_test_impl(ctx): + env = analysistest.begin(ctx) + asserts.expect_failure(env, ctx.attr.message) + return analysistest.end(env) + +_rejected_test = analysistest.make(_rejected_test_impl, expect_failure = True, attrs = {"message": attr.string()}) + +def postgres_overlay_tests(): + _paths_test(name = "postgres_overlay_paths_test") + cases = { + "traversal": {"one": "src/backend/../port/file.c"}, + "absolute": {"one": "/src/backend/file.c"}, + "empty_component": {"one": "src//backend/file.c"}, + "backslash": {"one": "src/backend\\file.c"}, + "duplicate": {"one": "src/backend/file.c", "two": "src/backend/file.c"}, + } + for name, overlays in cases.items(): + _subject(name = "postgres_overlay_" + name + "_subject", overlays = overlays, tags = ["manual"]) + _rejected_test( + name = "postgres_overlay_" + name + "_test", + target_under_test = ":postgres_overlay_" + name + "_subject", + message = "duplicate PostgreSQL overlay destination" if name == "duplicate" else "invalid PostgreSQL overlay destination", + ) diff --git a/build_defs/wasix/postmaster/postgres.BUILD.bazel b/build_defs/wasix/postmaster/postgres.BUILD.bazel new file mode 100644 index 000000000..35aa693e7 --- /dev/null +++ b/build_defs/wasix/postmaster/postgres.BUILD.bazel @@ -0,0 +1,14 @@ +load("@oliphaunt//build_defs/wasix/postmaster:postgres.bzl", "postgres_postmaster_targets") +load(":version.bzl", "POSTGRES_VERSION") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["SOURCE_VERSION", "version.bzl", "patches.bzl"] + glob(["src/**"])) + +# Immutable source acquisition is proved independently before compilation. +filegroup( + name = "source_tree", + srcs = glob(["**"], exclude = ["BUILD.bazel", "SOURCE_VERSION", "version.bzl", "patches.bzl"]), +) + +postgres_postmaster_targets(POSTGRES_VERSION) diff --git a/build_defs/wasix/postmaster/postgres.bzl b/build_defs/wasix/postmaster/postgres.bzl new file mode 100644 index 000000000..d0c57d952 --- /dev/null +++ b/build_defs/wasix/postmaster/postgres.bzl @@ -0,0 +1,130 @@ +"""The actual LP32 EXEC_BACKEND PostgreSQL source graph for the postmaster.""" + +load("@rules_cc//cc:defs.bzl", "cc_library") +load("//build_defs/native:config.bzl", "pg_config") +load("//build_defs/native:postgres.bzl", "postgres_generated_targets", "postgres_resource_targets") +load("//build_defs/native:resources.bzl", "timezone_database") +load("//build_defs/native:postgres_sources.bzl", "POSTGRES_BACKEND_SOURCES", "POSTGRES_BACKEND_LINUX_SOURCES", "POSTGRES_BACKEND_GENERATED_SOURCES", "POSTGRES_BACKEND_TEXTUAL_SOURCES", "POSTGRES_BACKEND_INCLUDE_DIRECTORIES", "POSTGRES_CATALOG_GENERATED_HEADERS", "POSTGRES_NODE_GENERATED_TEXTUAL_SOURCES", "POSTGRES_WAIT_EVENT_GENERATED_TEXTUAL_SOURCES", "POSTGRES_BACKEND_GENERATED_HEADERS", "POSTGRES_COMMON_GENERATED_HEADERS", "POSTGRES_PLPGSQL_GENERATED_HEADERS", "POSTGRES_COMMON_SOURCES", "POSTGRES_COMMON_RYU_SOURCES", "POSTGRES_COMMON_CONFIG_INFO_SOURCES", "POSTGRES_COMMON_BUILTIN_CRYPTO_SOURCES", "POSTGRES_COMMON_FRONTEND_SHARED_ADDITIONAL_SOURCES", "POSTGRES_COMMON_FRONTEND_STATIC_ADDITIONAL_SOURCES", "POSTGRES_PORT_SOURCES", "POSTGRES_PORT_REPLACEMENT_SOURCES", "POSTGRES_PORT_CRC_GENERIC_SOURCES", "POSTGRES_TIMEZONE_SOURCES", "POSTGRES_MAIN_SOURCES", "POSTGRES_PLPGSQL_SOURCES", "POSTGRES_PLPGSQL_GENERATED_SOURCES", "POSTGRES_SNOWBALL_SOURCES", "POSTGRES_LIBPQ_SOURCES", "POSTGRES_INITDB_SOURCES") +load("//build_defs/wasix:wasm.bzl", "wasix_module") +load(":postgres-config.bzl", "POSTMASTER_PG_CONFIG") +load(":sealing.bzl", "postmaster_seal_modules") +load(":aot.bzl", "postmaster_aot") +load(":carrier.bzl", "postmaster_carrier") +load("@postmaster_postgres//:patches.bzl", "POSTGRES_PATCHES") + +_COMPATIBLE = ["@platforms//cpu:wasm32", "@platforms//os:wasi"] +_SYSROOT = "@postmaster_wasix_libc//:sysroot" +_OPTIMIZATION = ["--enable-threads", "--enable-mutable-globals", "--enable-bulk-memory", "--enable-bulk-memory-opt", "--enable-exception-handling", "--enable-simd", "--enable-relaxed-simd", "--enable-extended-const", "--emit-exnref", "--converge", "--strip-debug", "--strip-producers"] + +def postmaster_patch_inputs(paths): + result = [] + for path in paths: + found = False + for owner in ["src/wasix/postmaster", "src/third-party/postgres"]: + if path.startswith(owner + "/"): + result.append("@oliphaunt//" + owner + ":" + path.removeprefix(owner + "/")) + found = True + break + if not found: + fail("Unsupported canonical postmaster patch owner: " + path) + return result + +def postgres_postmaster_targets(version): + """Use canonical patched sources, native generators, and real libc headers.""" + pg_config(name = "configuration", template = "src/include/pg_config.h.in", os_header = "src/include/port/wasix-core.h", version = version, values = POSTMASTER_PG_CONFIG, profile = "Bazel wasm32 WASIX EXEC_BACKEND", prefix = "") + postgres_generated_targets(version) + postgres_resource_targets() + timezone_database(name = "timezone_data", source = "src/timezone/data/tzdata.zi", zic = "@postgres//:zic", posixrules = "") + native.filegroup(name = "tsearch_dictionaries", srcs = native.glob(["src/backend/tsearch/dicts/*"])) + native.filegroup(name = "postmaster_timezone_abbreviations", srcs = native.glob(["src/timezone/tznames/*"], exclude = ["src/timezone/tznames/README", "src/timezone/tznames/Makefile", "src/timezone/tznames/meson.build"])) + generated_headers = POSTGRES_CATALOG_GENERATED_HEADERS + POSTGRES_NODE_GENERATED_TEXTUAL_SOURCES + POSTGRES_WAIT_EVENT_GENERATED_TEXTUAL_SOURCES + POSTGRES_BACKEND_GENERATED_HEADERS + POSTGRES_COMMON_GENERATED_HEADERS + POSTGRES_PLPGSQL_GENERATED_HEADERS + cc_library( + name = "headers", + hdrs = native.glob(["src/include/**/*.h", "src/backend/**/*.h", "src/common/**/*.h", "src/pl/plpgsql/src/*.h", "src/interfaces/libpq/*.h", "src/timezone/*.h"]) + generated_headers + [":configuration"], + textual_hdrs = POSTGRES_BACKEND_TEXTUAL_SOURCES + native.glob(["src/backend/utils/mb/Unicode/*.map", "src/backend/utils/mb/conversion_procs/**/*.map"]), + includes = POSTGRES_BACKEND_INCLUDE_DIRECTORIES + ["src/common", "src/pl/plpgsql/src", "src/interfaces/libpq", "src/include/snowball", "src/timezone"], + defines = ["_GNU_SOURCE", "PG_WASIX_ATOMIC_LATCH_STATE=1"], + deps = [_SYSROOT], + target_compatible_with = _COMPATIBLE, + ) + prefix = native.package_relative_label(":src/include/pg_config.h.in").workspace_root + "/" + copts = ["-ffile-prefix-map=" + prefix + "=postgres/", "-std=gnu11", "-O3", "-g0", "-flto=thin", "-fPIC", "-pthread", "-fno-strict-aliasing", "-fwrapv", "-nostdinc", "-isystem", Label("@wasix_toolchain//:llvm/bin/clang").workspace_root + "/llvm/lib/clang/21/include", "-Wno-declaration-after-statement", "-Wno-macro-redefined", "-Wno-unused-function", "-Wno-missing-prototypes"] + common = POSTGRES_COMMON_SOURCES + POSTGRES_COMMON_RYU_SOURCES + POSTGRES_COMMON_CONFIG_INFO_SOURCES + POSTGRES_COMMON_BUILTIN_CRYPTO_SOURCES + cc_library(name = "abi_check", srcs = ["@oliphaunt//build_defs/wasix/postmaster:postgres-abi.c"], deps = [":headers"], copts = copts, linkstatic = True, target_compatible_with = _COMPATIBLE) + port = POSTGRES_PORT_SOURCES + POSTGRES_PORT_CRC_GENERIC_SOURCES + [source for macro, source in POSTGRES_PORT_REPLACEMENT_SOURCES.items() if macro not in POSTMASTER_PG_CONFIG] + for role, definitions, additions in [ + ("server", [], []), + ("frontend_static", ["FRONTEND", "USE_PRIVATE_ENCODING_FUNCS"], POSTGRES_COMMON_FRONTEND_SHARED_ADDITIONAL_SOURCES + POSTGRES_COMMON_FRONTEND_STATIC_ADDITIONAL_SOURCES), + ("frontend_shared", ["FRONTEND"], POSTGRES_COMMON_FRONTEND_SHARED_ADDITIONAL_SOURCES), + ]: + sources = [source for source in common if source != "src/common/jsonapi.c"] if role == "frontend_shared" else common + dependencies = [":headers"] + if role == "frontend_shared": + cc_library(name = "common_shared_json", srcs = ["src/common/jsonapi.c"], local_defines = ["FRONTEND", "JSONAPI_USE_PQEXPBUFFER"], deps = dependencies, copts = copts, linkstatic = True, target_compatible_with = _COMPATIBLE) + dependencies = dependencies + [":common_shared_json"] + cc_library(name = "common_" + role, srcs = sources + additions, local_defines = definitions, deps = dependencies, copts = copts, linkstatic = True, target_compatible_with = _COMPATIBLE) + cc_library(name = "port_" + role, srcs = port, local_defines = definitions, deps = [":headers"], copts = copts, linkstatic = True, target_compatible_with = _COMPATIBLE) + cc_library(name = "timezone", srcs = POSTGRES_TIMEZONE_SOURCES, deps = [":headers"], copts = copts, linkstatic = True, target_compatible_with = _COMPATIBLE) + cc_library(name = "backend", srcs = POSTGRES_BACKEND_SOURCES + POSTGRES_BACKEND_LINUX_SOURCES + POSTGRES_BACKEND_GENERATED_SOURCES, deps = [":headers", ":common_server", ":port_server", ":timezone"], copts = copts, linkstatic = True, target_compatible_with = _COMPATIBLE) + cc_library(name = "main", srcs = POSTGRES_MAIN_SOURCES, deps = [":headers"], copts = copts, linkstatic = True, target_compatible_with = _COMPATIBLE) + # The postmaster Makefile expands backend/main/timezone object files before + # its common and port archives. Preserve ThinLTO until that final link; + # the embedded core's early no-inline relocatable lowering is a different + # construction profile. + wasix_module(name = "postgres_seed", kind = "command", output_name = "postgres", object_deps = [":backend", ":main", ":timezone"], archive_deps = [":common_server", ":port_server"], constructed_sysroot = _SYSROOT, linkopts = ["--export-all", "-Bsymbolic"], optimization_flags = _OPTIMIZATION, target_compatible_with = _COMPATIBLE) + for role, sources, definitions, dependencies in [ + ("libpq_static", POSTGRES_LIBPQ_SOURCES + ["src/interfaces/libpq/wasix_encoding_shim.c"], ["FRONTEND", "SO_MAJOR_VERSION=5"], [":common_frontend_static", ":port_frontend_static"]), + ("libpq_shared", POSTGRES_LIBPQ_SOURCES, ["FRONTEND", "SO_MAJOR_VERSION=5", "USE_DYNAMIC_OAUTH"], []), + ]: + cc_library(name = role, srcs = sources, local_defines = definitions, deps = [":headers"] + dependencies, copts = copts, linkstatic = True, target_compatible_with = _COMPATIBLE) + cc_library(name = "initdb_utils", srcs = ["src/fe_utils/option_utils.c", "src/fe_utils/string_utils.c"], deps = [":headers", ":libpq_static"], local_defines = ["FRONTEND", "USE_PRIVATE_ENCODING_FUNCS"], copts = copts, linkstatic = True, target_compatible_with = _COMPATIBLE) + cc_library(name = "initdb_objects", srcs = POSTGRES_INITDB_SOURCES, deps = [":headers", ":libpq_static", ":initdb_utils"], local_defines = ["FRONTEND", "USE_PRIVATE_ENCODING_FUNCS"], copts = copts, linkstatic = True, target_compatible_with = _COMPATIBLE) + wasix_module(name = "initdb", kind = "command", output_name = "initdb", deps = [":initdb_objects"], constructed_sysroot = _SYSROOT, linkopts = ["-Bsymbolic"], optimization_flags = _OPTIMIZATION, target_compatible_with = _COMPATIBLE) + # The libpq Makefile links its own OBJS directly, then selects members of + # libpgcommon_shlib.a and libpgport_shlib.a on demand. Their unrelated + # frontend utilities must not become exported libpq definitions. + wasix_module(name = "libpq", output_name = "libpq.so.5.18", deps = [":libpq_shared"], archive_deps = [":common_frontend_shared", ":port_frontend_shared"], constructed_sysroot = _SYSROOT, linkopts = ["-Bsymbolic"], optimization_flags = _OPTIMIZATION, target_compatible_with = _COMPATIBLE) + for name, sources in [("plpgsql", POSTGRES_PLPGSQL_SOURCES + POSTGRES_PLPGSQL_GENERATED_SOURCES), ("dict_snowball", POSTGRES_SNOWBALL_SOURCES)]: + cc_library(name = name + "_objects", srcs = sources, deps = [":headers"], copts = copts, linkstatic = True, target_compatible_with = _COMPATIBLE) + wasix_module(name = name, output_name = name + ".so", deps = [":" + name + "_objects"], constructed_sysroot = _SYSROOT, linkopts = ["-Bsymbolic"], optimization_flags = _OPTIMIZATION, target_compatible_with = _COMPATIBLE) + side_targets = [":libpq", ":plpgsql", ":dict_snowball"] + module_paths = {"libpq": "lib/libpq.so.5.18", "plpgsql": "lib/postgresql/plpgsql.so", "dict_snowball": "lib/postgresql/dict_snowball.so"} + for makefile in native.glob(["src/backend/utils/mb/conversion_procs/*/Makefile"]): + directory = makefile.rsplit("/", 1)[0] + name = directory.rsplit("/", 1)[1] + cc_library(name = name + "_objects", srcs = native.glob([directory + "/*.c"]), deps = [":headers"], copts = copts, linkstatic = True, target_compatible_with = _COMPATIBLE) + wasix_module(name = name, output_name = name + ".so", deps = [":" + name + "_objects"], constructed_sysroot = _SYSROOT, linkopts = ["-Bsymbolic"], optimization_flags = _OPTIMIZATION, target_compatible_with = _COMPATIBLE) + side_targets.append(":" + name) + module_paths[name] = "lib/postgresql/" + name + ".so" + native.filegroup(name = "side_modules", srcs = side_targets, target_compatible_with = _COMPATIBLE) + native.filegroup(name = "unsealed_modules", srcs = [":postgres_seed", ":initdb", ":side_modules"], target_compatible_with = _COMPATIBLE) + postmaster_seal_modules(name = "sealed_modules", module_paths = ["bin/postgres", "bin/initdb"] + module_paths.values(), main = ":postgres_seed", initdb = ":initdb", sides = ":side_modules", abi_check = ":abi_check", target_compatible_with = _COMPATIBLE, exec_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64", "@zig_sdk//libc:gnu.2.34"]) + native.alias(name = "sealed_profile_test", actual = "@oliphaunt//src/wasix/postmaster:linux_sealed_profile_test") + aot_targets = [] + for name, path in dict(module_paths, postgres = "bin/postgres", initdb = "bin/initdb").items(): + target = name + "_aot" + postmaster_aot(name = target, sealed = ":sealed_modules", module_path = path, target_compatible_with = _COMPATIBLE, exec_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64", "@zig_sdk//libc:gnu.2.34"]) + aot_targets.append(":" + target) + native.filegroup(name = "aot_modules", srcs = aot_targets, target_compatible_with = _COMPATIBLE) + native.filegroup(name = "aot_receipts", srcs = aot_targets, output_group = "receipt", target_compatible_with = _COMPATIBLE) + postmaster_carrier( + name = "native_carrier", + sealed = ":sealed_modules", + sysroot = _SYSROOT, + clang = "@wasix_toolchain//:llvm/bin/clang", + aot = ":aot_modules", + aot_receipts = ":aot_receipts", + configuration = ":configuration", + patches = postmaster_patch_inputs(POSTGRES_PATCHES), + resources = { + ":catalog_runtime_data": "share/postgresql/", + ":builtin_extension_data": "share/postgresql/extension/", + ":tsearch_dictionaries": "share/postgresql/tsearch_data/", + ":stopwords": "share/postgresql/tsearch_data/", + ":postmaster_timezone_abbreviations": "share/postgresql/timezonesets/", + ":timezone_data": "share/postgresql/timezone", + }, + target_compatible_with = _COMPATIBLE, + exec_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64", "@zig_sdk//libc:gnu.2.34"], + ) + native.alias(name = "runtime_test", actual = "@oliphaunt//src/wasix/postmaster:linux_runtime_test") diff --git a/build_defs/wasix/postmaster/qualification-profile.mts b/build_defs/wasix/postmaster/qualification-profile.mts new file mode 100644 index 000000000..29a81564c --- /dev/null +++ b/build_defs/wasix/postmaster/qualification-profile.mts @@ -0,0 +1,27 @@ +import assert from 'node:assert/strict'; +import { readFileSync, writeFileSync } from 'node:fs'; + +export function qualificationProfile(contents: string) { + const clauses = [...contents.matchAll(/^ {4}release-o3\)\n([\s\S]*?)^ {6};;$/gmu)]; + assert.equal(clauses.length, 1, 'expected one canonical release-o3 clause'); + const get = (key: string) => { + const values = [...clauses[0][1].matchAll(new RegExp(`^ ${key}="([0-9]+)"$`, 'gmu'))]; + assert.equal(values.length, 1, `expected one canonical ${key} assignment`); + const value = Number(values[0][1]); + assert(Number.isSafeInteger(value) && value >= 4, 'invalid canonical fence count'); + return value; + }; + return { + profile: 'release-o3', + expected_seed_fences: get('FRESH_WASIX_CORE_PROFILE_EXPECTED_ATOMIC_FENCE_TOTAL'), + expected_final_fences: get('FRESH_WASIX_CORE_PROFILE_EXPECTED_FINAL_ATOMIC_FENCE_TOTAL'), + }; +} + +if (import.meta.main) { + assert.equal(process.argv.length, 4, 'usage: qualification-profile.mts COMMON OUTPUT'); + writeFileSync( + process.argv[3], + `${JSON.stringify(qualificationProfile(readFileSync(process.argv[2], 'utf8')))}\n`, + ); +} diff --git a/build_defs/wasix/postmaster/qualification-profile.test.mts b/build_defs/wasix/postmaster/qualification-profile.test.mts new file mode 100644 index 000000000..e92dd0081 --- /dev/null +++ b/build_defs/wasix/postmaster/qualification-profile.test.mts @@ -0,0 +1,48 @@ +import { test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { qualificationProfile } from './qualification-profile.mts'; + +const source = readFileSync( + new URL('../../../src/wasix/postmaster/lib/common.sh', import.meta.url), + 'utf8', +); + +test('projects only selected canonical expectations, ignoring unused driver text', () => { + const observed = qualificationProfile(source); + assert.equal(observed.profile, 'release-o3'); + assert.deepEqual( + qualificationProfile(`# unrelated driver comment\n${source}\n# another comment\n`), + observed, + ); + const selected = source.match(/^ {4}release-o3\)\n([\s\S]*?)^ {6};;$/mu)[0]; + const expectations = [ + ...selected.matchAll(/EXPECTED_(?:FINAL_)?ATOMIC_FENCE_TOTAL="([0-9]+)"/gu), + ].map((row) => Number(row[1])); + assert.deepEqual([observed.expected_seed_fences, observed.expected_final_fences], expectations); +}); + +test('rejects missing, ambiguous and unpinned qualification clauses', () => { + const selected = source.match(/^ {4}release-o3\)\n([\s\S]*?)^ {6};;$/mu)[0]; + assert.throws(() => qualificationProfile(source.replace(selected, ''))); + assert.throws(() => qualificationProfile(`${source}\n${selected}\n`)); + assert.throws(() => + qualificationProfile( + source.replace( + selected, + selected.replace(/(EXPECTED_ATOMIC_FENCE_TOTAL=)"[0-9]+"/u, '$1"$override"'), + ), + ), + ); + assert.throws(() => + qualificationProfile( + source.replace( + selected, + selected.replace( + /(^ {6}FRESH_WASIX_CORE_PROFILE_EXPECTED_ATOMIC_FENCE_TOTAL=.*)$/mu, + '$1\n$1', + ), + ), + ), + ); +}); diff --git a/build_defs/wasix/postmaster/receipt-reader.test.mts b/build_defs/wasix/postmaster/receipt-reader.test.mts new file mode 100644 index 000000000..ad425f870 --- /dev/null +++ b/build_defs/wasix/postmaster/receipt-reader.test.mts @@ -0,0 +1,47 @@ +import { test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { copyFileSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join } from 'node:path'; + +test('relocated legacy reader parses text without the native helper and fails closed for native JSON', async () => { + const root = mkdtempSync(join(tmpdir(), 'postmaster-legacy-reader-')); + const files = [ + 'src/wasix/postmaster/lib/verify-sealed-carrier.mts', + 'src/wasix/postmaster/lib/guest-build-provenance.mts', + 'src/wasix/postmaster/lib/linear-memory-profile.mts', + 'src/wasix/postmaster/lib/receipt-files.mts', + 'src/wasix/postmaster/lib/sealed-export-chain.mts', + 'src/wasix/postmaster/wasmer/bin/verify-postmaster-concurrency-contract.mts', + 'src/wasix/postmaster/wasmer/bin/verify-postmaster-wasm-import.mts', + 'src/wasix/postmaster/wasmer/policies/sealed-side-modules.v1.tsv', + 'tools/packaging/strict-json.mts', + ]; + try { + for (const relative of files) { + const destination = join(root, relative); + mkdirSync(dirname(destination), { recursive: true }); + copyFileSync(new URL(`../../../${relative}`, import.meta.url), destination); + } + const reader = await import(join(root, files[0])); + const receipt = join(root, 'wasmer-build.receipt'); + writeFileSync( + receipt, + 'schema=oliphaunt.wasix-postmaster.wasmer-build.v2\nruntime_abi_id=legacy-identity\n', + ); + assert.deepEqual( + reader.parseReceipt(root, undefined, 'wasmer-build.receipt', ['schema', 'runtime_abi_id']), + { + schema: 'oliphaunt.wasix-postmaster.wasmer-build.v2', + runtime_abi_id: 'legacy-identity', + }, + ); + writeFileSync(receipt, '{}\n'); + assert.throws( + () => reader.parseReceipt(root, undefined, 'wasmer-build.receipt', []), + /native-receipts|Cannot find/, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/build_defs/wasix/postmaster/release-asset-test.mts b/build_defs/wasix/postmaster/release-asset-test.mts new file mode 100644 index 000000000..1fb8142d0 --- /dev/null +++ b/build_defs/wasix/postmaster/release-asset-test.mts @@ -0,0 +1,158 @@ +/** Exercise the conventional launcher from the actual final public archive. */ +import assert from 'node:assert/strict'; +import { + chmodSync, + lstatSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + realpathSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import { basename, isAbsolute, join, resolve } from 'node:path'; +import { + carrierTree, + hashRegular, + verify, +} from '../../../src/wasix/postmaster/lib/verify-sealed-carrier.mts'; +import { + extractPortableArchiveTree, + readPortableArchiveEntries, +} from '../../../tools/packaging/portable-archive.mts'; +import { nativeWasmerReceipt, runtimeAbiFacts } from './native-receipts.mts'; + +const [archiveArg, shell, launcherSource, readmeSource, licenseSource, noticesSource] = + Bun.argv.slice(2); +assert( + archiveArg && + shell && + launcherSource && + readmeSource && + licenseSource && + noticesSource && + Bun.argv.length === 8, + 'usage: release-asset-test.mts ARCHIVE BASH LAUNCHER README LICENSE NOTICES', +); +assert(isAbsolute(shell), 'The selected shell toolchain must provide an absolute executable'); +const archive = realpathSync(resolve(archiveArg)); +const parent = basename(archive).replace(/\.tar\.zst$/u, ''); +assert.notEqual(parent, basename(archive), 'Expected the conventional tar.zst release archive'); +const entries = readPortableArchiveEntries(archive); +assert(entries.get(parent)?.isDirectory, 'The public archive must retain its conventional parent'); +for (const [name, entry] of entries) { + assert(name === parent || name.startsWith(`${parent}/`), `Unexpected archive root: ${name}`); + if (entry.isDirectory) assert.equal(entry.mode, 0o755, `Archive directory mode: ${name}`); + else if (name.startsWith(`${parent}/carrier/`)) + assert([0o644, 0o755].includes(entry.mode), `Archive carrier mode: ${name}`); + else + assert.equal( + entry.mode, + name === `${parent}/bin/oliphaunt-wasix-postmaster` ? 0o755 : 0o644, + `Unexpected conventional archive mode: ${name}`, + ); +} +const work = mkdtempSync(join(process.env.TEST_TMPDIR ?? tmpdir(), 'postmaster-public-archive-')); +const diagnostics = process.env.TEST_UNDECLARED_OUTPUTS_DIR + ? join(process.env.TEST_UNDECLARED_OUTPUTS_DIR, 'postmaster-public-archive') + : join(work, 'diagnostics'); +mkdirSync(diagnostics, { recursive: true }); +extractPortableArchiveTree(archive, join(work, 'installed')); +const installed = join(work, 'installed', parent); +assert.deepEqual(readdirSync(installed).sort(), [ + 'LICENSE', + 'README.md', + 'THIRD_PARTY_NOTICES.md', + 'bin', + 'carrier', +]); +assert.deepEqual(readdirSync(join(installed, 'bin')), ['oliphaunt-wasix-postmaster']); +for (const [member, source] of [ + ['bin/oliphaunt-wasix-postmaster', launcherSource], + ['README.md', readmeSource], + ['LICENSE', licenseSource], + ['THIRD_PARTY_NOTICES.md', noticesSource], +]) + assert.deepEqual( + readFileSync(join(installed, member)), + readFileSync(realpathSync(resolve(source))), + `Shipping source bytes differ: ${member}`, + ); +const carrier = join(installed, 'carrier'); +// The canonical public archiver normalizes modes. Seal only this private +// installed copy before the unchanged receipt/inventory admission checks. +for (const [member, stat] of [...carrierTree(carrier)].reverse()) + chmodSync(member === '.' ? carrier : join(carrier, member), stat.mode & 0o555); +const wasmer = JSON.parse(readFileSync(join(carrier, 'wasmer-build.receipt'), 'utf8')); +nativeWasmerReceipt(wasmer); +const facts = runtimeAbiFacts(wasmer.runtime_abi); +const manifest = JSON.parse(readFileSync(join(carrier, 'manifest.json'), 'utf8')); +verify( + carrier, + hashRegular(join(carrier, 'wasmer-build.receipt')).sha256, + manifest['postgres-version'], + facts.wasmerVersion, + facts.wasixVersion, + wasmer.runtime_abi.artifact_abi_version, + carrier, +); +const launcher = join(installed, 'bin/oliphaunt-wasix-postmaster'); +const data = join(work, 'pgdata'); +async function command(name: string, args: string[]) { + const child = Bun.spawn([shell, ...args], { + env: { PATH: process.env.PATH ?? '', LC_ALL: 'C' }, + stdin: 'ignore', + stdout: Bun.file(join(diagnostics, `${name}.stdout`)), + stderr: Bun.file(join(diagnostics, `${name}.stderr`)), + }); + let timer: ReturnType | undefined; + try { + const code = await Promise.race([ + child.exited, + new Promise((_resolve, reject) => { + timer = setTimeout(() => { + child.kill('SIGKILL'); + reject(new Error(`${name} timed out`)); + }, 120_000); + }), + ]); + assert.equal( + code, + 0, + `${name} failed: ${readFileSync(join(diagnostics, `${name}.stderr`), 'utf8')}`, + ); + return readFileSync(join(diagnostics, `${name}.stdout`), 'utf8'); + } finally { + if (timer) clearTimeout(timer); + } +} +const shellVersion = (await command('shell-version', ['--version'])).split('\n')[0]; +await command('initialize', [launcher, 'init', '--data-dir', data]); +const postgresVersion = readFileSync(join(data, 'PG_VERSION'), 'utf8').trim(); +assert.equal(postgresVersion, String(manifest['postgres-version']).split('.')[0]); +assert( + lstatSync(join(data, 'global/pg_control')).isFile(), + 'The shipped launcher must produce an actual cluster', +); +const uri = (await command('uri', [launcher, 'uri', '--data-dir', data])).trim(); +assert.equal(uri, 'postgresql://postgres@127.0.0.1:5432/postgres'); +writeFileSync( + join(diagnostics, 'archive-result.json'), + `${JSON.stringify( + { + archive: { name: basename(archive), ...hashRegular(archive), members: entries.size }, + manifest: hashRegular(join(carrier, 'manifest.json')), + executor: hashRegular(join(carrier, 'bin/wasmer-headless')), + shell: { path: shell, ...hashRegular(realpathSync(shell)), version: shellVersion }, + postgresVersion, + uri, + level: 'initialize-cluster', + }, + null, + 2, + )}\n`, +); +console.log( + `Actual public postmaster archive launcher initialized PostgreSQL ${postgresVersion}; ${uri}`, +); diff --git a/build_defs/wasix/postmaster/release-asset.bzl b/build_defs/wasix/postmaster/release-asset.bzl new file mode 100644 index 000000000..69384e65c --- /dev/null +++ b/build_defs/wasix/postmaster/release-asset.bzl @@ -0,0 +1,122 @@ +"""One canonical host archive; full-family checksum assembly stays separate.""" + +load("@oliphaunt_metadata//:metadata.bzl", "PRODUCTS", "WASIX_ARTIFACTS") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_file_action", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/native/carriers:release-family.bzl", "native_release_checksum_family") +load("//build_defs/release:identity.bzl", "ReleaseIdentityInfo") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") + +POSTMASTER_RELEASE_HELPERS = [ + "//:tools/packaging/archive-directory.mts", + "//:tools/packaging/portable-archive.mts", + "//:tools/packaging/platform-binary-contract.mts", + "//:tools/packaging/windows-vc-runtime-closure.mts", + "//:tools/packaging/windows-vc-runtime-policy.json", + "//tools/release:platform-compatibility-policy.mts", + "//:tools/packaging/strict-json.mts", + "//build_defs/wasix/postmaster:native-receipts.mts", + "//src/wasix/postmaster:lib/verify-sealed-carrier.mts", + "//src/wasix/postmaster:lib/guest-build-provenance.mts", + "//src/wasix/postmaster:lib/receipt-files.mts", + "//src/wasix/postmaster:lib/linear-memory-profile.mts", + "//src/wasix/postmaster:lib/sealed-export-chain.mts", + "//src/wasix/postmaster:wasmer/bin/verify-postmaster-concurrency-contract.mts", + "//src/wasix/postmaster:wasmer/bin/verify-postmaster-wasm-import.mts", + "//src/wasix/postmaster:wasmer/policies/sealed-side-modules.v1.tsv", + "//src/wasix/postmaster:wasmer/policies/sealed-main-runtime-exports.v1.txt", + "//src/wasix/postmaster:wasmer/policies/sealed-main-dlsym-exports.v1.txt", +] + +def _release_asset_impl(ctx): + owner = ctx.attr.owner[ReleaseIdentityInfo] + artifact = json.decode(ctx.attr.artifact) + if artifact["product"] != owner.id: + fail("Postmaster asset row differs from canonical owner") + output = ctx.actions.declare_file(ctx.label.name + "/" + artifact["asset"].replace("{version}", owner.version)) + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + sources = {"launcher": ctx.file.launcher.path, "readme": ctx.file.readme.path, "license": ctx.file.license.path, "notices": ctx.file.notices.path} + ctx.actions.write(spec, json.encode({"product": owner.id, "version": owner.version, "artifact": artifact, "carrier": ctx.file.carrier.path, "sources": sources, "output": output.path})) + leaves = ctx.actions.args() + leaves.add_all([ctx.file.carrier], expand_directories = True) + leaves.use_param_file("--carrier-files=%s", use_always = True) + leaves.set_param_file_format("multiline") + bun_file_action(ctx, ctx.file._writer, arguments = [spec.path, leaves], source_files = ctx.files._helpers, + inputs = [spec, ctx.file.carrier, ctx.file.launcher, ctx.file.readme, ctx.file.license, ctx.file.notices], + outputs = [output], mnemonic = "PostmasterPublicArchive") + return [DefaultInfo(files = depset([output]))] + +_release_asset = rule( + implementation = _release_asset_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = { + "owner": attr.label(providers = [ReleaseIdentityInfo], mandatory = True), + "artifact": attr.string(mandatory = True), + "carrier": attr.label(mandatory = True, allow_single_file = True), + "launcher": attr.label(default = "//src/wasix/postmaster:bin/run-release-carrier.sh", allow_single_file = True), + "readme": attr.label(default = "//src/wasix/postmaster:README.md", allow_single_file = True), + "license": attr.label(default = "//:LICENSE", allow_single_file = True), + "notices": attr.label(default = "//:THIRD_PARTY_NOTICES.md", allow_single_file = True), + "_writer": attr.label(default = "//build_defs/wasix/postmaster:release-asset.mts", allow_single_file = True), + "_helpers": attr.label_list(default = POSTMASTER_RELEASE_HELPERS, allow_files = True), + }, +) + +_ShellPathInfo = provider(fields = ["path"]) + +def _shell_impl(ctx): + return [_ShellPathInfo(path = ctx.toolchains["@rules_shell//shell:toolchain_type"].path)] + +_shell = rule(implementation = _shell_impl, toolchains = ["@rules_shell//shell:toolchain_type"]) + +def _archive_test_impl(ctx): + shell = ctx.attr.shell[_ShellPathInfo].path + return bun_test_entrypoint(ctx, runner = ctx.file._runner, + arguments = [ctx.file.archive, shell, ctx.file.launcher, ctx.file.readme, ctx.file.license, ctx.file.notices], + files = [ctx.file.archive, ctx.file.launcher, ctx.file.readme, ctx.file.license, ctx.file.notices], + source_files = [ctx.file._runner] + ctx.files._helpers) + +_archive_test = rule( + implementation = _archive_test_impl, + test = True, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "archive": attr.label(mandatory = True, allow_single_file = True), + "shell": attr.label(mandatory = True, cfg = "exec", providers = [_ShellPathInfo]), + "launcher": attr.label(default = "//src/wasix/postmaster:bin/run-release-carrier.sh", allow_single_file = True), + "readme": attr.label(default = "//src/wasix/postmaster:README.md", allow_single_file = True), + "license": attr.label(default = "//:LICENSE", allow_single_file = True), + "notices": attr.label(default = "//:THIRD_PARTY_NOTICES.md", allow_single_file = True), + "_runner": attr.label(default = "//build_defs/wasix/postmaster:release-asset-test.mts", allow_single_file = True), + "_helpers": attr.label_list(default = POSTMASTER_RELEASE_HELPERS, allow_files = True), + }), +) + +def postmaster_release_asset(name, target, carrier, execution, qualification): + rows = [row for row in WASIX_ARTIFACTS if row["product"] == "liboliphaunt-wasix-postmaster" and row["target"] == target and row["kind"] == "wasix-postmaster-runtime"] + if len(rows) != 1: + fail("Postmaster release needs one canonical artifact row for " + target) + row = rows[0] + owner = "@oliphaunt_metadata//:product_liboliphaunt-wasix-postmaster" + compatible = ["@platforms//cpu:wasm32", "@platforms//os:wasi"] + _release_asset(name = name + "_release_asset", owner = owner, artifact = json.encode(row), carrier = carrier, + target_compatible_with = compatible, exec_compatible_with = execution) + legacy = name == "linux_x64_gnu" + prefix = "linux" if legacy else name + _shell(name = prefix + "_archive_shell") + _archive_test(name = prefix + "_public_archive_test", archive = ":" + name + "_release_asset", shell = ":" + prefix + "_archive_shell", + args = bun_test_entrypoint_args(prefix + "_public_archive_test"), target_compatible_with = compatible, + exec_compatible_with = execution, tags = ["manual"], size = "medium") + shipping_package(name = prefix + "_carrier_construction", owner = owner, artifacts = [carrier], ecosystem = "internal", + package_name = "native_carrier", configuration = row["target"], role = "construction", suppliers = "//build_defs/release:no_suppliers") + shipping_package(name = prefix + "_release_asset_shipping", owner = owner, artifacts = [":" + name + "_release_asset"], ecosystem = "github", + package_name = row["asset"].replace("{version}", PRODUCTS[row["product"]]["version"]), configuration = row["target"], role = "github-release-asset", suppliers = "//build_defs/release:no_suppliers") + shipping_export(name = prefix + "_shipping_export", packages = [":" + prefix + "_carrier_construction", ":" + prefix + "_release_asset_shipping"], qualification = [":" + prefix + "_public_archive_test"] + qualification, testonly = True) + +def postmaster_linux_release_asset(qualification): + postmaster_release_asset(name = "linux_x64_gnu", target = "linux-x64-gnu", carrier = "@postmaster_postgres//:native_carrier", + execution = ["@platforms//os:linux", "@platforms//cpu:x86_64", "@zig_sdk//libc:gnu.2.34"], qualification = qualification) + +def postmaster_release_family(): + """Keep the three host archive roots unique; qualify and export their checksum.""" + native_release_checksum_family(product = "liboliphaunt-wasix-postmaster", artifact_rows = WASIX_ARTIFACTS, + export_name = "release_shipping_export") diff --git a/build_defs/wasix/postmaster/release-asset.mts b/build_defs/wasix/postmaster/release-asset.mts new file mode 100644 index 000000000..ef3dd1f62 --- /dev/null +++ b/build_defs/wasix/postmaster/release-asset.mts @@ -0,0 +1,127 @@ +/** Canonical GitHub archive envelope around the actual native postmaster carrier. */ +import assert from 'node:assert/strict'; +import { + chmodSync, + lstatSync, + mkdirSync, + mkdtempSync, + readFileSync, + readlinkSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { basename, dirname, join, relative, resolve } from 'node:path'; +import { safeRelative, stableRead } from '../../../src/wasix/postmaster/lib/receipt-files.mts'; +import { + carrierTree, + hashRegular, + verify, +} from '../../../src/wasix/postmaster/lib/verify-sealed-carrier.mts'; +import { archiveDirectory } from '../../../tools/packaging/archive-directory.mts'; +import { inspectPlatformBinaryBuffer } from '../../../tools/packaging/platform-binary-contract.mts'; +import { nativeWasmerReceipt, runtimeAbiFacts } from './native-receipts.mts'; + +export interface PostmasterReleaseAsset { + product: string; + version: string; + artifact: { product: string; kind: string; asset: string; target: string; triple: string }; + carrier: string; + carrierFiles: string[]; + sources: { launcher: string; readme: string; license: string; notices: string }; + output: string; +} + +export async function packagePostmasterReleaseAsset(spec: PostmasterReleaseAsset) { + assert.equal(spec.product, 'liboliphaunt-wasix-postmaster'); + assert.equal(spec.artifact.product, spec.product); + assert.equal(spec.artifact.kind, 'wasix-postmaster-runtime'); + assert(/^\d+\.\d+\.\d+$/.test(spec.version), 'Invalid canonical postmaster version'); + const asset = spec.artifact.asset.replaceAll('{version}', spec.version); + safeRelative(asset); + assert.equal(basename(asset), asset); + assert(asset.endsWith('.tar.zst')); + assert.equal(basename(spec.output), asset, 'Postmaster output filename differs from catalog'); + assert( + spec.carrierFiles.length > 0, + 'Postmaster release requires actual declared carrier leaves', + ); + assert.equal( + new Set(spec.carrierFiles).size, + spec.carrierFiles.length, + 'Duplicate declared carrier leaf', + ); + mkdirSync(dirname(spec.output), { recursive: true }); + const scratch = mkdtempSync(join(dirname(resolve(spec.output)), '.postmaster-release-')); + const packageRoot = join(scratch, asset.slice(0, -'.tar.zst'.length)); + const carrier = join(packageRoot, 'carrier'); + mkdirSync(carrier, { recursive: true }); + try { + for (const source of spec.carrierFiles) { + const member = relative(resolve(spec.carrier), resolve(source)); + safeRelative(member); + // Dereference only Bazel's single declared-file sandbox projection. + const input = lstatSync(source).isSymbolicLink() + ? resolve(dirname(source), readlinkSync(source)) + : source; + assert(lstatSync(input).isFile(), `Declared carrier leaf is not regular: ${source}`); + const chunks: Buffer[] = []; + const stat = stableRead(input, (chunk) => chunks.push(Buffer.from(chunk))); + const destination = join(carrier, member); + mkdirSync(dirname(destination), { recursive: true }); + writeFileSync(destination, Buffer.concat(chunks), { flag: 'wx' }); + chmodSync(destination, Number(stat.mode & 0o777n)); + } + // Source TreeArtifact files are already readonly; seal the new directories. + for (const [member, stat] of [...carrierTree(carrier)].reverse()) + if (stat.isDirectory()) chmodSync(member === '.' ? carrier : join(carrier, member), 0o555); + const wasmer = JSON.parse(readFileSync(join(carrier, 'wasmer-build.receipt'), 'utf8')); + nativeWasmerReceipt(wasmer); + const facts = runtimeAbiFacts(wasmer.runtime_abi); + assert.equal( + facts.target, + spec.artifact.triple, + 'Postmaster carrier differs from canonical host', + ); + const manifest = JSON.parse(readFileSync(join(carrier, 'manifest.json'), 'utf8')); + verify( + carrier, + hashRegular(join(carrier, 'wasmer-build.receipt')).sha256, + manifest['postgres-version'], + facts.wasmerVersion, + facts.wasixVersion, + wasmer.runtime_abi.artifact_abi_version, + carrier, + ); + inspectPlatformBinaryBuffer(readFileSync(join(carrier, 'bin/wasmer-headless')), { + target: spec.artifact.target, + label: 'postmaster executor', + }); + for (const [source, destination, mode] of [ + [spec.sources.launcher, 'bin/oliphaunt-wasix-postmaster', 0o555], + [spec.sources.readme, 'README.md', 0o644], + [spec.sources.license, 'LICENSE', 0o644], + [spec.sources.notices, 'THIRD_PARTY_NOTICES.md', 0o644], + ] as const) { + const output = join(packageRoot, destination); + mkdirSync(dirname(output), { recursive: true }); + writeFileSync(output, readFileSync(source), { flag: 'wx' }); + chmodSync(output, mode); + } + await archiveDirectory(packageRoot, spec.output, { keepParent: true }); + } finally { + for (const [member, stat] of carrierTree(carrier)) + if (stat.isDirectory()) chmodSync(member === '.' ? carrier : join(carrier, member), 0o755); + rmSync(scratch, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + const [specFile, members] = Bun.argv.slice(2); + assert(specFile && members?.startsWith('--carrier-files=') && Bun.argv.length === 4); + await packagePostmasterReleaseAsset({ + ...JSON.parse(readFileSync(specFile, 'utf8')), + carrierFiles: readFileSync(members.slice('--carrier-files='.length), 'utf8') + .trimEnd() + .split('\n'), + }); +} diff --git a/build_defs/wasix/postmaster/repositories.bzl b/build_defs/wasix/postmaster/repositories.bzl new file mode 100644 index 000000000..7ee7819ed --- /dev/null +++ b/build_defs/wasix/postmaster/repositories.bzl @@ -0,0 +1,176 @@ +"""Immutable full postmaster source acquisition, separate from other Wasmer contexts.""" + +_WASMER_COMMIT = "1d1b3420beef28550afbb4692b664bd7f6bc2581" +_WASMER_SHA256 = "f93a21ecac7bea2aaee00a98d60069690701a3185f85b582684ff1735bf46912" +_NAPI_COMMIT = "706383f42391cb4e4e82e5fd5e63a0ebf81ae19d" +_NAPI_SHA256 = "61d281d14542bf51f54f87fb9438984b3dcb3c177e9974cb4ef7850791b43ef8" +_LIBC_COMMIT = "34178a6272804f90448b5bd08dc7bcf0d85438e3" +_LIBC_SHA256 = "8453723052a27f22ed98a3ac77d8e8cd41df5c3ded8a89150d34171093450cbf" + +def _archive(ctx, pin, commit, digest, output = ""): + result = ctx.execute([ + ctx.path(ctx.attr.bun), + ctx.path(ctx.attr.converter), + "source", + ctx.path(pin), + commit, + digest, + ], quiet = True) + if result.return_code: + fail("Cannot import canonical postmaster source: " + result.stderr) + source = json.decode(result.stdout) + ctx.download_and_extract( + url = source["url"], + sha256 = source["sha256"], + stripPrefix = source["strip_prefix"], + type = "tar.gz", + output = output, + ) + return source + +def _read_inputs(ctx): + ctx.read(ctx.attr.converter) + ctx.read(ctx.attr.manifest_helper) + ctx.read(ctx.attr.patch) + ctx.read(ctx.attr.source_manifest) + ctx.watch(ctx.path(ctx.attr.bun)) + +def _wasmer_impl(ctx): + _read_inputs(ctx) + ctx.read(ctx.attr.napi_manifest) + wasmer = _archive(ctx, ctx.attr.source_manifest, _WASMER_COMMIT, _WASMER_SHA256) + napi = _archive(ctx, ctx.attr.napi_manifest, _NAPI_COMMIT, _NAPI_SHA256, "lib/napi") + ctx.patch(ctx.path(ctx.attr.patch), strip = 1) + ctx.file("source.json", json.encode({"wasmer": wasmer, "napi": napi})) + ctx.file("BUILD.bazel", """package(default_visibility = ["//visibility:public"]) +exports_files(["Cargo.toml", "Cargo.lock", "source.json", "lib/types/src/serialize.rs"]) +filegroup(name = "cargo_manifests", srcs = glob(["**/Cargo.toml"])) +""") + return ctx.repo_metadata(reproducible = True) + +def _libc_impl(ctx): + _read_inputs(ctx) + source = _archive(ctx, ctx.attr.source_manifest, _LIBC_COMMIT, _LIBC_SHA256) + ctx.patch(ctx.path(ctx.attr.patch), strip = 1) + ctx.read(ctx.attr.mode_converter) + result = ctx.execute([ctx.path(ctx.attr.bun), "--no-install", "--no-env-file", ctx.path(ctx.attr.mode_converter), "patch", ctx.path("."), ctx.path(ctx.attr.patch)], quiet = True) + if result.return_code: + fail("Cannot apply patch-declared libc new-file modes: " + result.stderr) + ctx.file("source.json", json.encode(source)) + ctx.read(ctx.attr.inventory_converter) + result = ctx.execute([ctx.path(ctx.attr.bun), ctx.path(ctx.attr.inventory_converter), ctx.path("."), ctx.path("source-inventory.bzl")], quiet = True) + if result.return_code: + fail("Cannot project canonical patched libc source inventory: " + result.stderr) + ctx.symlink(ctx.attr.build_file, "BUILD.bazel") + return ctx.repo_metadata(reproducible = True) + +def _cargo_impl(ctx): + for source in [ctx.attr.workspace, ctx.attr.lockfile, ctx.attr.wasmer_manifest, ctx.attr.source_identity, ctx.attr.patch, ctx.attr.converter, ctx.attr.manifest_helper]: + ctx.read(source) + ctx.watch(ctx.path(ctx.attr.bun)) + result = ctx.execute([ + ctx.path(ctx.attr.bun), + ctx.path(ctx.attr.converter), + "cargo", + ctx.path(ctx.attr.workspace), + ctx.path(ctx.attr.lockfile), + ctx.path(ctx.attr.wasmer_manifest), + ctx.path(ctx.attr.source_identity), + ctx.path(ctx.attr.patch), + ctx.path("."), + json.encode(ctx.attr.roles), + ], quiet = True) + if result.return_code: + fail("Cannot import canonical postmaster Cargo roles: " + result.stderr) + observed = json.decode(result.stdout) + wasmer = ctx.path(ctx.attr.wasmer_manifest).dirname + for relative in observed["manifests"]: + ctx.watch(wasmer.get_child(relative)) + for relative in observed["targets"]: + ctx.watch(ctx.path(ctx.attr.workspace).dirname.get_child(relative)) + ctx.read(ctx.attr.qualification_source) + ctx.read(ctx.attr.qualification_converter) + result = ctx.execute([ctx.path(ctx.attr.bun), "--no-install", "--no-env-file", ctx.path(ctx.attr.qualification_converter), ctx.path(ctx.attr.qualification_source), ctx.path("qualification-profile.json")], quiet = True) + if result.return_code: + fail("Cannot project canonical postmaster qualification profile: " + result.stderr) + exported = ["cargo-sources.json", "qualification-profile.json"] + observed["patches"] + for role in ctx.attr.roles: + ctx.symlink(wasmer, role + "/wasmer") + exported.extend([role + "/Cargo.toml", role + "/Cargo.lock"]) + sources = json.decode(ctx.read("cargo-sources.json")) + for crate_id, source in sources.items(): + source["patches"] = ["@@" + ctx.name + "//:" + patch for patch in source["patches"]] + ctx.file("cargo-sources.json", json.encode(sources)) + ctx.file("BUILD.bazel", "package(default_visibility = [\"//visibility:public\"])\nexports_files(" + repr(exported) + ")\n") + return ctx.repo_metadata(reproducible = True) + +_COMMON = { + "converter": attr.label(default = Label("//build_defs/wasix/postmaster:metadata.mts"), allow_single_file = True), + "manifest_helper": attr.label(default = Label("//:tools/packaging/cargo-manifest.mts"), allow_single_file = True), + "bun": attr.label(default = Label("@bun_runtime//:bun"), allow_single_file = True), +} + +postmaster_wasmer_repository = repository_rule( + implementation = _wasmer_impl, + attrs = dict(_COMMON, **{ + "source_manifest": attr.label(default = Label("//src/wasix/postmaster:sources/wasmer.toml"), allow_single_file = True), + "napi_manifest": attr.label(default = Label("//src/wasix/postmaster:sources/wasmer-napi.toml"), allow_single_file = True), + "patch": attr.label(default = Label("//src/wasix/postmaster:wasmer/patches/wasmer/0001-postgres-wasix-blockers.patch"), allow_single_file = True), + }), +) + +postmaster_wasix_libc_repository = repository_rule( + implementation = _libc_impl, + attrs = dict(_COMMON, **{ + "source_manifest": attr.label(default = Label("//src/wasix/postmaster:sources/wasix-libc.toml"), allow_single_file = True), + "patch": attr.label(default = Label("//src/wasix/postmaster:wasmer/patches/wasix-libc/0001-postgres-wasix-blockers.patch"), allow_single_file = True), + "inventory_converter": attr.label(default = Label("//build_defs/wasix/postmaster:libc-metadata.mts"), allow_single_file = True), + "mode_converter": attr.label(default = Label("//build_defs/wasix/postmaster:source-modes.mts"), allow_single_file = True), + "build_file": attr.label(default = Label("//build_defs/wasix/postmaster:libc.BUILD.bazel"), allow_single_file = True), + }), +) + +postmaster_cargo_repository = repository_rule( + implementation = _cargo_impl, + attrs = dict(_COMMON, **{ + "workspace": attr.label(default = Label("//src/wasix/postmaster:executor/Cargo.toml"), allow_single_file = True), + "lockfile": attr.label(default = Label("//src/wasix/postmaster:executor/Cargo.lock"), allow_single_file = True), + "wasmer_manifest": attr.label(default = Label("@postmaster_wasmer//:Cargo.toml"), allow_single_file = True), + "source_identity": attr.label(default = Label("@postmaster_wasmer//:source.json"), allow_single_file = True), + "patch": attr.label(default = Label("//src/wasix/postmaster:wasmer/patches/wasmer/0001-postgres-wasix-blockers.patch"), allow_single_file = True), + "roles": attr.string_dict(mandatory = True), + "qualification_source": attr.label(default = Label("//src/wasix/postmaster:lib/common.sh"), allow_single_file = True), + "qualification_converter": attr.label(default = Label("//build_defs/wasix/postmaster:qualification-profile.mts"), allow_single_file = True), + }), +) + +def _compile_metadata_impl(ctx): + for file in [ctx.attr.manifest, ctx.attr.executor, ctx.attr.compiler, ctx.attr.compiler_rendering, ctx.attr.converter]: + ctx.read(file) + ctx.watch(ctx.path(ctx.attr.bun)) + result = ctx.execute([ + ctx.path(ctx.attr.bun), + ctx.path(ctx.attr.converter), + ctx.path(ctx.attr.manifest), + ctx.path(ctx.attr.executor), + ctx.path(ctx.attr.compiler), + ctx.path(ctx.attr.compiler_rendering), + ctx.attr.compiler.workspace_name, + ctx.path("cargo.bzl"), + ], quiet = True) + if result.return_code: + fail("Cannot project actual postmaster Cargo compile facts: " + result.stderr) + ctx.file("BUILD.bazel", "exports_files([\"cargo.bzl\"], visibility = [\"//visibility:public\"])\n") + return ctx.repo_metadata(reproducible = True) + +postmaster_compile_metadata_repository = repository_rule( + implementation = _compile_metadata_impl, + attrs = { + "manifest": attr.label(default = Label("//src/wasix/postmaster:executor/Cargo.toml"), allow_single_file = True), + "executor": attr.label(default = Label("@postmaster_executor_crates//:cargo-bazel.json"), allow_single_file = True), + "compiler": attr.label(default = Label("@postmaster_compiler_crates//:cargo-bazel.json"), allow_single_file = True), + "compiler_rendering": attr.label(default = Label("@postmaster_compiler_crates//:crates.bzl"), allow_single_file = True), + "converter": attr.label(default = Label("//build_defs/wasix/postmaster:compile-metadata.mts"), allow_single_file = True), + "bun": attr.label(default = Label("@bun_runtime//:bun"), allow_single_file = True), + }, +) diff --git a/build_defs/wasix/postmaster/runtime-abi.bzl b/build_defs/wasix/postmaster/runtime-abi.bzl new file mode 100644 index 000000000..a8980244f --- /dev/null +++ b/build_defs/wasix/postmaster/runtime-abi.bzl @@ -0,0 +1,104 @@ +"""Bind the native serialized protocol to actual configured Rust dependencies.""" + +load("@rules_rust//rust:defs.bzl", "rust_common") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") + +_FeaturesInfo = provider(fields = ["crates"]) +_RUST_TOOLCHAIN = "@rules_rust//rust:toolchain_type" + +def _features_impl(target, ctx): + transitive = [] + for dep in getattr(ctx.rule.attr, "deps", []): + if _FeaturesInfo in dep: + transitive.append(dep[_FeaturesInfo].crates) + direct = [] + if rust_common.crate_info in target: + crate = target[rust_common.crate_info] + if crate.type == "rlib": + direct.append(struct( + crate_name = crate.name, + version = ctx.rule.attr.version, + target = ctx.toolchains[_RUST_TOOLCHAIN].target_triple.str, + features = tuple(ctx.rule.attr.crate_features), + )) + return [_FeaturesInfo(crates = depset(direct, transitive = transitive))] + +_features = aspect( + implementation = _features_impl, + attr_aspects = ["deps"], + toolchains = [_RUST_TOOLCHAIN], +) + +def _role_features(dependencies): + return [ + {"crate_name": row.crate_name, "version": row.version, "target": row.target, "features": list(row.features)} + for row in depset(transitive = [dep[_FeaturesInfo].crates for dep in dependencies]).to_list() + ] + +def _runtime_abi_impl(ctx): + rust = ctx.toolchains[_RUST_TOOLCHAIN] + patches = {} + for patch in ctx.files.patches: + if patch.basename in patches: + fail("Duplicate declared postmaster patch basename: " + patch.basename) + patches[patch.basename] = patch.path + root_sources = {} + for source in ctx.files.root_sources: + prefix = ctx.label.package + "/executor/" + if not source.short_path.startswith(prefix): + fail("Expected declared canonical executor source: " + source.short_path) + relative = source.short_path.removeprefix(prefix) + if relative in root_sources: + fail("Duplicate canonical executor source: " + relative) + root_sources[relative] = source.path + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode({ + "manifest": ctx.file.manifest.path, + "lock": ctx.file.lock.path, + "contexts": {"executor": ctx.file.executor_context.path, "compiler": ctx.file.compiler_context.path}, + "sources": ctx.file.sources.path, + "sourceIdentity": ctx.file.source_identity.path, + "serializer": ctx.file.serializer.path, + "loader": ctx.file.loader.path, + "patches": patches, + "rootSources": root_sources, + "rust": {"target": rust.target_triple.str, "version": rust.version, "flags": rust.extra_rustc_flags, "exec_flags": rust.extra_exec_rustc_flags, "compilation_mode": ctx.var["COMPILATION_MODE"]}, + "rustc": rust.rustc.path, + "roles": {"executor": _role_features(ctx.attr.executor_deps), "compiler": _role_features(ctx.attr.compiler_deps)}, + })) + contract = ctx.actions.declare_file(ctx.label.name + ".json") + environment = ctx.actions.declare_file(ctx.label.name + ".env") + arguments = ctx.actions.args() + arguments.add_all([spec, contract, environment]) + bun_file_action( + ctx, + ctx.file._writer, + arguments = [arguments], + inputs = [spec, rust.rustc, ctx.file.manifest, ctx.file.lock, ctx.file.executor_context, ctx.file.compiler_context, ctx.file.sources, ctx.file.source_identity, ctx.file.serializer, ctx.file.loader] + ctx.files.patches + ctx.files.root_sources, + source_files = [ctx.file._compile_metadata], + outputs = [contract, environment], + mnemonic = "PostmasterNativeRuntimeAbi", + progress_message = "Bind configured native postmaster serialization ABI %{label}", + ) + return [DefaultInfo(files = depset([environment])), OutputGroupInfo(contract = depset([contract]))] + +postmaster_runtime_abi = rule( + implementation = _runtime_abi_impl, + toolchains = BUN_SOURCE_TOOLCHAINS + [_RUST_TOOLCHAIN], + attrs = { + "executor_deps": attr.label_list(mandatory = True, aspects = [_features]), + "compiler_deps": attr.label_list(mandatory = True, aspects = [_features]), + "patches": attr.label_list(allow_files = True), + "root_sources": attr.label_list(allow_files = [".rs"], mandatory = True), + "manifest": attr.label(default = "//src/wasix/postmaster:executor/Cargo.toml", allow_single_file = True), + "lock": attr.label(default = "//src/wasix/postmaster:executor/Cargo.lock", allow_single_file = True), + "executor_context": attr.label(default = "@postmaster_executor_crates//:cargo-bazel.json", allow_single_file = True), + "compiler_context": attr.label(default = "@postmaster_compiler_crates//:cargo-bazel.json", allow_single_file = True), + "sources": attr.label(default = "@postmaster_cargo//:cargo-sources.json", allow_single_file = True), + "source_identity": attr.label(default = "@postmaster_wasmer//:source.json", allow_single_file = True), + "serializer": attr.label(default = "@postmaster_wasmer//:lib/types/src/serialize.rs", allow_single_file = True), + "loader": attr.label(default = "//src/wasix/postmaster:executor/src/sealed.rs", allow_single_file = True), + "_writer": attr.label(default = "//build_defs/wasix/postmaster:runtime-abi.mts", allow_single_file = True), + "_compile_metadata": attr.label(default = "//build_defs/wasix/postmaster:compile-metadata.mts", allow_single_file = True), + }, +) diff --git a/build_defs/wasix/postmaster/runtime-abi.mts b/build_defs/wasix/postmaster/runtime-abi.mts new file mode 100644 index 000000000..62a931729 --- /dev/null +++ b/build_defs/wasix/postmaster/runtime-abi.mts @@ -0,0 +1,183 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { readFileSync, writeFileSync } from 'node:fs'; +import { basename } from 'node:path'; +import { postmasterCompileMetadata } from './compile-metadata.mts'; + +const sha256 = (bytes: string | Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +const canonical = (value: any): string => + JSON.stringify(value, (_key, row) => + row && typeof row === 'object' && !Array.isArray(row) + ? Object.fromEntries( + Object.keys(row) + .sort() + .map((key) => [key, row[key]]), + ) + : row, + ); + +function configuredFeatures(context: any, crate: any, target: string): string[] { + const declared = crate.common_attrs?.crate_features ?? []; + if (Array.isArray(declared)) return [...declared].sort(); + const values = [...(declared.common ?? [])]; + for (const [condition, features] of Object.entries(declared.selects ?? {})) { + assert( + Array.isArray(context.conditions[condition]), + `Missing standard feature condition ${condition}`, + ); + if (context.conditions[condition].includes(target)) values.push(...features); + } + return [...new Set(values)].sort(); +} + +export function nativeRuntimeAbi(input: any) { + const facts = postmasterCompileMetadata(input.manifest, input.contexts); + const serialized = /\bCURRENT_VERSION:\s*u32\s*=\s*(\d+)\s*;/g; + const loader = /\bARTIFACT_ABI_VERSION:\s*u32\s*=\s*(\d+)\s*;/g; + const upstreamVersions = [...input.serializer.matchAll(serialized)]; + const loaderVersions = [...input.loader.matchAll(loader)]; + assert.equal(upstreamVersions.length, 1, 'Expected one real Wasmer serialization ABI'); + assert.equal(loaderVersions.length, 1, 'Expected one sealed-loader serialization ABI'); + const artifactAbiVersion = Number(upstreamVersions[0][1]); + assert.equal(artifactAbiVersion, Number(loaderVersions[0][1]), 'Wasmer/loader ABI mismatch'); + assert(input.rust.target && input.rust.version && Array.isArray(input.rust.flags)); + for (const path of [facts.library, ...Object.values(facts.roles).map((role) => role.source)]) + assert( + Object.hasOwn(input.rootSources, path), + `Missing actual first-party compile source ${path}`, + ); + const roles: Record = {}; + const usedPatches = new Set(); + for (const role of ['executor', 'compiler']) { + const context = input.contexts[role]; + const configured = new Map(); + for (const row of input.roles[role]) { + assert(row.target && row.crate_name && row.version && Array.isArray(row.features)); + assert.equal(new Set(row.features).size, row.features.length, 'Duplicate configured feature'); + const matches = Object.entries(context.crates).filter( + ([_id, crate]) => + crate.library_target_name === row.crate_name && crate.version === row.version, + ); + assert.equal( + matches.length, + 1, + `Unknown configured ${role} crate ${row.crate_name} ${row.version}`, + ); + const [id] = matches[0]; + assert.deepEqual( + [...row.features].sort(), + configuredFeatures(context, matches[0][1], row.target), + `Configured ${role} features disagree with standard Cargo context for ${id}`, + ); + const key = `${id} ${row.target}`; + const value = { id, target: row.target, features: [...row.features].sort() }; + if (configured.has(key)) + assert.deepEqual(configured.get(key), value, 'Conflicting configured crate features'); + configured.set(key, value); + } + assert(configured.size, `Missing actual configured ${role} dependencies`); + const sources: Record = {}; + for (const [id, crate] of Object.entries(context.crates)) { + const source = input.sources[id]; + if (!source) continue; + const acquired = crate.repository?.Http; + assert(acquired, `Selected path source ${id} lacks immutable HTTP acquisition`); + for (const key of ['url', 'sha256', 'strip_prefix', 'patches']) + assert.deepEqual( + acquired[key] ?? [], + source[key] ?? [], + `Source acquisition mismatch ${id}/${key}`, + ); + // The canonical source projection uses ctx.patch(strip = 1); the + // maintained source_metadata seam renders its equivalent -p1 argument. + assert.deepEqual(acquired.patch_args, ['-p1'], `Source patch strip differs ${id}`); + sources[id] = { + url: source.url, + sha256: source.sha256, + strip_prefix: source.strip_prefix, + patch_args: acquired.patch_args, + patches: (source.patches ?? []).map((label: string) => { + const name = basename(label); + assert(Object.hasOwn(input.patches, name), `Missing declared patch ${name}`); + usedPatches.add(name); + return sha256(input.patches[name]); + }), + }; + } + assert(Object.keys(sources).length, `Missing selected immutable ${role} sources`); + roles[role] = { + features: facts.roles[role].features, + dependencies: [...configured.values()].sort((a, b) => + `${a.id} ${a.target}` < `${b.id} ${b.target}` + ? -1 + : `${a.id} ${a.target}` > `${b.id} ${b.target}` + ? 1 + : 0, + ), + sources, + }; + } + assert.deepEqual( + [...usedPatches].sort(), + Object.keys(input.patches).sort(), + 'Unexpected declared source patches', + ); + const contract = { + schema: 'oliphaunt.wasix-postmaster.runtime-abi.native.v2', + package: { name: facts.name, version: facts.version, edition: facts.edition }, + manifest_sha256: sha256(input.manifestBytes), + lock_sha256: sha256(input.lock), + source: Object.fromEntries( + Object.entries(input.sourceIdentity).filter(([_name, origin]) => + Object.values(roles).some((role) => + Object.values(role.sources).some( + (source) => source.url === origin.url && source.sha256 === origin.sha256, + ), + ), + ), + ), + root_sources: Object.fromEntries( + Object.entries(input.rootSources).map(([path, bytes]) => [path, sha256(bytes)]), + ), + artifact_abi_version: artifactAbiVersion, + rust: { ...input.rust, compiler_sha256: sha256(input.rustc) }, + roles, + }; + const id = sha256(canonical(contract)); + return { ...contract, runtime_abi_id: id }; +} + +if (import.meta.main) { + const [specPath, jsonOutput, envOutput] = Bun.argv.slice(2); + assert(specPath && jsonOutput && envOutput); + const spec = JSON.parse(readFileSync(specPath, 'utf8')); + const manifestBytes = readFileSync(spec.manifest); + const identity = nativeRuntimeAbi({ + ...spec, + manifest: Bun.TOML.parse(manifestBytes.toString('utf8')), + manifestBytes, + contexts: Object.fromEntries( + Object.entries(spec.contexts).map(([role, path]) => [ + role, + JSON.parse(readFileSync(path, 'utf8')), + ]), + ), + sources: JSON.parse(readFileSync(spec.sources, 'utf8')), + sourceIdentity: JSON.parse(readFileSync(spec.sourceIdentity, 'utf8')), + lock: readFileSync(spec.lock), + serializer: readFileSync(spec.serializer, 'utf8'), + loader: readFileSync(spec.loader, 'utf8'), + rustc: readFileSync(spec.rustc), + patches: Object.fromEntries( + Object.entries(spec.patches).map(([name, path]) => [name, readFileSync(path)]), + ), + rootSources: Object.fromEntries( + Object.entries(spec.rootSources).map(([path, source]) => [ + path, + readFileSync(source), + ]), + ), + }); + writeFileSync(jsonOutput, `${canonical(identity)}\n`); + writeFileSync(envOutput, `OLIPHAUNT_WASIX_RUNTIME_ABI_ID=${identity.runtime_abi_id}\n`); +} diff --git a/build_defs/wasix/postmaster/runtime-abi.test.mts b/build_defs/wasix/postmaster/runtime-abi.test.mts new file mode 100644 index 000000000..2d8456a17 --- /dev/null +++ b/build_defs/wasix/postmaster/runtime-abi.test.mts @@ -0,0 +1,150 @@ +import { expect, test } from 'bun:test'; +import { nativeRuntimeAbi } from './runtime-abi.mts'; + +const source = { + url: 'https://example.test/immutable/archive', + sha256: 'a'.repeat(64), + strip_prefix: 'archive/lib/types', + patches: ['@@source//:patches/types.patch'], +}; +const manifest = { + package: { name: 'postmaster', version: '7.2.0-alpha.2', edition: '2024' }, + features: { default: [], execute: [], compile: [] }, + bin: ['executor', 'compiler'].map((role) => ({ + name: `postmaster-${role}`, + path: `${role}.rs`, + 'required-features': [role === 'executor' ? 'execute' : 'compile'], + })), +}; +const context = (feature: string) => ({ + workspace_members: { 'postmaster 7.2.0-alpha.2': '' }, + crates: { + 'postmaster 7.2.0-alpha.2': { common_attrs: { crate_features: ['default', feature] } }, + 'wasmer-types 7.2.0-alpha.2': { + version: '7.2.0-alpha.2', + library_target_name: 'wasmer_types', + common_attrs: { crate_features: feature === 'execute' ? ['std'] : ['std', 'compiler'] }, + repository: { Http: { ...source, patch_args: ['-p1'] } }, + }, + }, +}); +const configured = { + crate_name: 'wasmer_types', + version: '7.2.0-alpha.2', + target: 'x86_64-unknown-linux-gnu', + features: ['std'], +}; +const fixture = () => ({ + manifest, + manifestBytes: 'conventional manifest bytes', + lock: 'conventional lock bytes', + contexts: { executor: context('execute'), compiler: context('compile') }, + sources: { 'wasmer-types 7.2.0-alpha.2': source }, + patches: { 'types.patch': 'actual ordered patch bytes' }, + sourceIdentity: { + wasmer: { commit: 'immutable commit', url: source.url, sha256: source.sha256 }, + unused: { commit: 'unused source' }, + }, + rootSources: { + 'src/lib.rs': 'actual Rust library source', + 'executor.rs': 'executor entry', + 'compiler.rs': 'compiler entry', + }, + serializer: 'pub const CURRENT_VERSION: u32 = 21;', + loader: 'const ARTIFACT_ABI_VERSION: u32 = 21;', + rust: { target: configured.target, version: '1.93.1', flags: [] }, + rustc: 'actual compiler bytes', + roles: { executor: [configured], compiler: [{ ...configured, features: ['std', 'compiler'] }] }, +}); + +test('native ABI keeps actual configured roles separate and ignores repository label spelling', () => { + const input = fixture(); + const result = nativeRuntimeAbi(input); + expect(result.schema).toBe('oliphaunt.wasix-postmaster.runtime-abi.native.v2'); + expect(result.roles.executor.dependencies[0].features).toEqual(['std']); + expect(result.roles.compiler.dependencies[0].features).toEqual(['compiler', 'std']); + const renamedSource = { ...source, patches: ['@@other_canonical_index//:patches/types.patch'] }; + const renamed = fixture(); + renamed.sources['wasmer-types 7.2.0-alpha.2'] = renamedSource; + for (const context of Object.values(renamed.contexts)) + context.crates['wasmer-types 7.2.0-alpha.2'].repository.Http = { + ...renamedSource, + patch_args: ['-p1'], + }; + expect(nativeRuntimeAbi(renamed).runtime_abi_id).toBe(result.runtime_abi_id); + const unused = fixture(); + unused.sourceIdentity.unused.commit = 'changed unused source'; + expect(nativeRuntimeAbi(unused).runtime_abi_id).toBe(result.runtime_abi_id); + for (const mutate of [ + (value: any) => { + value.patches['types.patch'] += ' changed'; + }, + (value: any) => { + value.rust.target = 'aarch64-unknown-linux-gnu'; + }, + (value: any) => { + value.rustc += ' changed'; + }, + (value: any) => { + value.roles.executor = [{ ...configured, features: ['std', 'different'] }]; + value.contexts.executor.crates['wasmer-types 7.2.0-alpha.2'].common_attrs.crate_features = [ + 'std', + 'different', + ]; + }, + (value: any) => { + value.roles.compiler = [{ ...configured, features: ['std'] }]; + value.contexts.compiler.crates['wasmer-types 7.2.0-alpha.2'].common_attrs.crate_features = [ + 'std', + ]; + }, + (value: any) => { + value.rootSources['src/lib.rs'] += ' changed'; + }, + ]) { + const changed = fixture(); + mutate(changed); + expect(nativeRuntimeAbi(changed).runtime_abi_id).not.toBe(result.runtime_abi_id); + } +}); + +test('native ABI rejects protocol disagreement and incomplete or conflicting source/configured inputs', () => { + for (const mutate of [ + (value: any) => { + value.loader = 'const ARTIFACT_ABI_VERSION: u32 = 22;'; + }, + (value: any) => { + value.patches = {}; + }, + (value: any) => { + value.patches['unexpected.patch'] = 'extra'; + }, + (value: any) => { + value.contexts.executor.crates['wasmer-types 7.2.0-alpha.2'].repository = null; + }, + (value: any) => { + value.contexts.executor.crates['wasmer-types 7.2.0-alpha.2'].repository.Http.patch_args = [ + '-p0', + ]; + }, + (value: any) => { + value.roles.executor = []; + }, + (value: any) => { + value.roles.executor = [configured, { ...configured, features: ['conflict'] }]; + }, + (value: any) => { + value.roles.executor = [{ ...configured, version: '7.2.1' }]; + }, + (value: any) => { + value.roles.executor = [{ ...configured, features: ['unknown'] }]; + }, + (value: any) => { + delete value.rootSources['src/lib.rs']; + }, + ]) { + const changed = fixture(); + mutate(changed); + expect(() => nativeRuntimeAbi(changed)).toThrow(); + } +}); diff --git a/build_defs/wasix/postmaster/runtime-probe-test.mts b/build_defs/wasix/postmaster/runtime-probe-test.mts new file mode 100644 index 000000000..47a520e65 --- /dev/null +++ b/build_defs/wasix/postmaster/runtime-probe-test.mts @@ -0,0 +1,17 @@ +import assert from 'node:assert/strict'; +import { resolve } from 'node:path'; + +const [executable, module, artifact, expected] = Bun.argv.slice(2); +assert.equal(Bun.argv.length, 6); +const child = Bun.spawn([resolve(executable), resolve(module), resolve(artifact)], { + env: { LC_ALL: 'C', TEST_TMPDIR: process.env.TEST_TMPDIR }, + stdout: 'pipe', + stderr: 'pipe', +}); +const stdout = new Response(child.stdout).text(); +const stderr = new Response(child.stderr).text(); +const status = await child.exited; +console.log(await stdout); +console.error(await stderr); +assert.equal(status, 0, 'The actual compiled primitive probe failed'); +assert((await stdout).includes(expected), 'The primitive probe did not confirm its invariants'); diff --git a/build_defs/wasix/postmaster/runtime-probe.bzl b/build_defs/wasix/postmaster/runtime-probe.bzl new file mode 100644 index 000000000..e2930146b --- /dev/null +++ b/build_defs/wasix/postmaster/runtime-probe.bzl @@ -0,0 +1,97 @@ +"""Declared primitive probes for the exact postmaster compiler/runtime boundary.""" + +load("@rules_cc//cc:defs.bzl", "cc_library") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_file_action", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/foundation:bun-sources.bzl", "bun_source_tree") +load("//build_defs/wasix:wasm.bzl", "WasmModuleInfo", "wasix_module") + +def _executor_configuration(_settings, _attr): + return {"//command_line_option:platforms": [str(Label("//build_defs/native:linux_x86_64_glibc_2_28"))], "//command_line_option:compilation_mode": "opt"} + +_EXECUTOR_CONFIGURATION = transition(implementation = _executor_configuration, inputs = [], outputs = ["//command_line_option:platforms", "//command_line_option:compilation_mode"]) + +def _probe_impl(ctx): + source = ctx.attr.module[WasmModuleInfo].module + module = ctx.actions.declare_file(ctx.label.name + ".assets/probe.wasm") + memory_receipt = ctx.actions.declare_file(ctx.label.name + ".assets/memory.json") + artifact = ctx.actions.declare_file(ctx.label.name + ".assets/probe.bin") + receipt = ctx.actions.declare_file(ctx.label.name + ".assets/aot.json") + ctx.actions.run( + executable = ctx.executable._memory, + arguments = ["seal", "--output", module.path, "--receipt", memory_receipt.path, source.path], + inputs = [source], + outputs = [module, memory_receipt], + mnemonic = "PostmasterProbeMemory", + ) + bun_file_action( + ctx, + ctx.file._aot, + source_files = [ctx.file._aot], + sources = bun_source_tree(ctx, ctx.label.name + ".aot-sources", [ctx.file._aot]), + arguments = [ctx.executable._compiler.path, ctx.file._abi.path, module.dirname, module.basename, artifact.path, receipt.path], + inputs = [module, ctx.file._abi], + tools = [ctx.attr._compiler[DefaultInfo].files_to_run], + outputs = [artifact, receipt], + mnemonic = "PostmasterProbeLlvmAot", + ) + probe = ctx.attr._probe[0] + executable = probe[DefaultInfo].files_to_run.executable + return bun_test_entrypoint( + ctx, + runner = ctx.file._runner, + arguments = [executable, module, artifact, ctx.attr.expected], + files = [executable, module, artifact, receipt, memory_receipt], + source_files = [ctx.file._runner], + additional_runfiles = probe[DefaultInfo].default_runfiles, + ) + +_probe_test = rule( + implementation = _probe_impl, + test = True, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "module": attr.label(mandatory = True, providers = [WasmModuleInfo]), + "expected": attr.string(mandatory = True), + "_probe": attr.label(default = "//src/wasix/postmaster:runtime_probe", cfg = _EXECUTOR_CONFIGURATION), + "_memory": attr.label(default = "//src/wasix/postmaster:memory_profile", cfg = "exec", executable = True), + "_compiler": attr.label(default = "//src/wasix/postmaster:compiler", cfg = "exec", executable = True), + "_abi": attr.label(default = "//src/wasix/postmaster:runtime_abi_contract", cfg = "exec", allow_single_file = True), + "_aot": attr.label(default = "//build_defs/wasix/postmaster:aot.mts", allow_single_file = True), + "_runner": attr.label(default = "//build_defs/wasix/postmaster:runtime-probe-test.mts", allow_single_file = True), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), + }), +) + +def postmaster_runtime_probes(): + compatible = ["@platforms//cpu:wasm32", "@platforms//os:wasi"] + for name, source, expected in [ + ("sjlj", "wasm_eh_sjlj_probe.c", "sjlj-ok plain=7 signal=1"), + ("vfork", "dynamic_vfork_exec_probe.c", "parent_value=7"), + ]: + cc_library( + name = name + "_probe_objects", + srcs = ["//src/wasix/postmaster:wasmer/probes/" + source], + deps = ["@postmaster_wasix_libc//:sysroot"], + copts = ["-std=gnu11", "-O3", "-g0", "-flto=thin", "-fPIC", "-pthread", "-nostdinc", "-isystem", Label("@wasix_toolchain//:llvm/bin/clang").workspace_root + "/llvm/lib/clang/21/include"], + target_compatible_with = compatible, + ) + wasix_module( + name = name + "_probe_wasm", + kind = "command", + output_name = name + ".wasm", + object_deps = [":" + name + "_probe_objects"], + constructed_sysroot = "@postmaster_wasix_libc//:sysroot", + linkopts = ["-Bsymbolic"], + optimization_flags = ["--enable-threads", "--enable-mutable-globals", "--enable-bulk-memory", "--enable-exception-handling", "--emit-exnref", "--strip-debug", "--strip-producers"], + target_compatible_with = compatible, + ) + _probe_test( + name = name + "_runtime_probe_test", + module = ":" + name + "_probe_wasm", + expected = expected, + args = bun_test_entrypoint_args(name + "_runtime_probe_test"), + target_compatible_with = compatible, + exec_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64", "@zig_sdk//libc:gnu.2.34"], + tags = ["manual"], + size = "small", + ) diff --git a/build_defs/wasix/postmaster/runtime-probe.rs b/build_defs/wasix/postmaster/runtime-probe.rs new file mode 100644 index 000000000..69f1b768b --- /dev/null +++ b/build_defs/wasix/postmaster/runtime-probe.rs @@ -0,0 +1,106 @@ +//! Test-only primitive execution with the product's actual runtime implementation. +//! +//! This does not construct or admit a public PostgreSQL carrier. Its immutable +//! one-module cache is solely for isolating SjLj and vfork lowering failures. + +use std::{env, fs, os::unix::fs::MetadataExt, path::PathBuf, sync::Arc}; + +use anyhow::{Context, Result, ensure}; +use oliphaunt_wasix_postmaster_executor::{exit_code_for_result, memory_profile}; +use wasmer::{Engine, Module}; +use wasmer_types::ModuleHash; +use wasmer_wasix::{ + Runtime, + runners::wasi::{RuntimeOrEngine, WasiRunner}, +}; + +// Compile the unchanged production runtime, not a copied runtime policy. +#[path = "../../../src/wasix/postmaster/executor/src/runtime.rs"] +mod runtime; + +mod sealed { + use super::*; + use wasmer_wasix::runtime::module_cache::{CacheError, ModuleCache}; + + #[derive(Debug)] + pub(crate) struct SealedModuleCache { + pub(crate) engine: wasmer::EngineId, + pub(crate) hash: ModuleHash, + pub(crate) module: Module, + } + + #[async_trait::async_trait] + impl ModuleCache for SealedModuleCache { + fn is_authoritative(&self) -> bool { + true + } + async fn load(&self, key: ModuleHash, engine: &Engine) -> Result { + if key != self.hash || engine.id() != self.engine { + return Err(CacheError::NotFound); + } + Ok(self.module.clone()) + } + async fn contains(&self, key: ModuleHash, engine: &Engine) -> Result { + Ok(key == self.hash && engine.id() == self.engine) + } + async fn save( + &self, + _key: ModuleHash, + _engine: &Engine, + _module: &Module, + ) -> Result<(), CacheError> { + Err(CacheError::other(std::io::Error::new( + std::io::ErrorKind::PermissionDenied, + "immutable primitive probe cache", + ))) + } + } +} + +fn run() -> Result<()> { + let mut arguments = env::args_os().skip(1); + let wasm = PathBuf::from(arguments.next().context("expected probe WASM")?); + let artifact = PathBuf::from(arguments.next().context("expected verified probe AOT")?); + ensure!( + arguments.next().is_none(), + "expected only WASM and verified AOT paths" + ); + let bytes = fs::read(&wasm)?; + let hash = ModuleHash::sha256(&bytes); + let temporary = PathBuf::from( + env::var_os("TEST_TMPDIR").unwrap_or_else(|| env::temp_dir().into_os_string()), + ); + let directory = temporary.join(format!("postmaster-runtime-probe-{}", std::process::id())); + fs::create_dir(&directory)?; + use std::os::unix::fs::PermissionsExt; + fs::set_permissions(&directory, fs::Permissions::from_mode(0o700))?; + let metadata = fs::metadata(&directory)?; + let engine = runtime::headless_engine(Some((&directory, metadata.dev(), metadata.ino())))?; + // The declared compiler action has verified the embedded module digest and + // memory plan before this test receives these exact local artifact bytes. + let module = unsafe { Module::deserialize_from_file(&engine, &artifact) }?; + let cache = Arc::new(sealed::SealedModuleCache { + engine: engine.id(), + hash, + module: module.clone(), + }); + let tokio = runtime::build_tokio_runtime()?; + let handle = tokio.handle().clone(); + let _guard = handle.enter(); + let (tty, _restore) = runtime::prepare_system_tty(); + let runtime: Arc = Arc::new(runtime::SealedPostmasterRuntime::new( + handle, + engine, + cache, + runtime::configure_stack(8 * 1024 * 1024), + tty, + )); + let mut runner = WasiRunner::new(); + runner.capabilities_mut().threading.max_threads = Some(runtime::HOST_TASK_BUDGET); + runner.with_sealed_module("/probe".to_owned(), hash, None); + runner.run_wasm(RuntimeOrEngine::Runtime(runtime), "/probe", module, hash) +} + +fn main() { + std::process::exit(exit_code_for_result(run())); +} diff --git a/build_defs/wasix/postmaster/runtime-test.bzl b/build_defs/wasix/postmaster/runtime-test.bzl new file mode 100644 index 000000000..da5b1e333 --- /dev/null +++ b/build_defs/wasix/postmaster/runtime-test.bzl @@ -0,0 +1,78 @@ +"""Declared lifecycle qualification of the actual native postmaster carrier.""" + +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_file_action", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/foundation:bun-sources.bzl", "bun_source_tree") + +def _client_configuration(_settings, attr): + return {"//command_line_option:platforms": [str(attr.native_platform)], "//command_line_option:compilation_mode": "opt"} + +_CLIENT_CONFIGURATION = transition(implementation = _client_configuration, inputs = [], outputs = ["//command_line_option:platforms", "//command_line_option:compilation_mode"]) + +def _runtime_test_impl(ctx): + client = ctx.attr.psql[0][DefaultInfo] + psql = client.files_to_run.executable + libraries = ctx.attr.libpq[0][DefaultInfo].files.to_list() + if len(libraries) != 1: + fail("The selected native libpq target must expose one shared library File") + libpq = libraries[0] + archive = ctx.actions.declare_file(ctx.label.name + ".carrier.tar.gz") + leaves = ctx.actions.args() + leaves.add_all([ctx.file.carrier], expand_directories = True) + leaves.use_param_file("--tree-files=%s", use_always = True) + leaves.set_param_file_format("multiline") + # Preserve the strict installed-tree reader: Bazel presents TreeArtifact + # runfiles as per-leaf symlinks, so transport the declared bytes as an archive. + bun_file_action( + ctx, + ctx.file._archive_driver, + source_files = [ctx.file._archive_driver, ctx.file._archiver, ctx.file._portable_archive], + sources = bun_source_tree(ctx, ctx.label.name + ".archive-sources", [ctx.file._archive_driver, ctx.file._archiver, ctx.file._portable_archive]), + arguments = [ctx.file.carrier.path, archive.path, leaves], + inputs = [ctx.file.carrier], + outputs = [archive], + mnemonic = "PostmasterTestArchive", + ) + return bun_test_entrypoint( + ctx, + runner = ctx.file._runner, + arguments = ["--archive", archive, psql, libpq, "--libpq-name", "libpq.5.dylib" if ctx.attr.target == "macos-arm64" else "libpq.so.5"], + files = [archive, psql, libpq] + ctx.files._sources, + source_files = [ctx.file._runner] + ctx.files._sources, + additional_runfiles = client.default_runfiles, + ) + +_postmaster_runtime_test = rule( + implementation = _runtime_test_impl, + test = True, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "carrier": attr.label(mandatory = True, allow_single_file = True), + "native_platform": attr.label(default = "//build_defs/native:linux_x86_64_glibc_2_28"), + "target": attr.string(default = "linux-x64-gnu", values = ["linux-x64-gnu", "linux-arm64-gnu", "macos-arm64"]), + "psql": attr.label(default = "@postgres//:psql", cfg = _CLIENT_CONFIGURATION), + "libpq": attr.label(default = "@postgres//:libpq_shared", cfg = _CLIENT_CONFIGURATION), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), + "_runner": attr.label(default = "//build_defs/wasix/postmaster:runtime-test.mts", allow_single_file = True), + "_archiver": attr.label(default = "//:tools/packaging/archive-directory.mts", allow_single_file = True), + "_archive_driver": attr.label(default = "//build_defs/wasix/postmaster:test-archive.mts", allow_single_file = True), + "_portable_archive": attr.label(default = "//:tools/packaging/portable-archive.mts", allow_single_file = True), + "_sources": attr.label_list(default = [ + "//:tools/packaging/portable-archive.mts", + "//build_defs/wasix/postmaster:native-receipts.mts", + "//:tools/packaging/strict-json.mts", + "//src/wasix/postmaster:lib/verify-sealed-carrier.mts", + "//src/wasix/postmaster:lib/guest-build-provenance.mts", + "//src/wasix/postmaster:lib/receipt-files.mts", + "//src/wasix/postmaster:lib/linear-memory-profile.mts", + "//src/wasix/postmaster:lib/sealed-export-chain.mts", + "//src/wasix/postmaster:wasmer/bin/verify-postmaster-concurrency-contract.mts", + "//src/wasix/postmaster:wasmer/bin/verify-postmaster-wasm-import.mts", + "//src/wasix/postmaster:wasmer/policies/sealed-main-runtime-exports.v1.txt", + "//src/wasix/postmaster:wasmer/policies/sealed-main-dlsym-exports.v1.txt", + "//src/wasix/postmaster:wasmer/policies/sealed-side-modules.v1.tsv", + ], allow_files = True), + }), +) + +def postmaster_runtime_test(name, **kwargs): + _postmaster_runtime_test(name = name, args = bun_test_entrypoint_args(name), **kwargs) diff --git a/build_defs/wasix/postmaster/runtime-test.mts b/build_defs/wasix/postmaster/runtime-test.mts new file mode 100644 index 000000000..9b7a37270 --- /dev/null +++ b/build_defs/wasix/postmaster/runtime-test.mts @@ -0,0 +1,400 @@ +import assert from 'node:assert/strict'; +import { + chmodSync, + lstatSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + realpathSync, + writeFileSync, +} from 'node:fs'; +import { createServer } from 'node:net'; +import { tmpdir } from 'node:os'; +import { join, resolve } from 'node:path'; +import { hashRegular, verify } from '../../../src/wasix/postmaster/lib/verify-sealed-carrier.mts'; +import { extractPortableArchiveTree } from '../../../tools/packaging/portable-archive.mts'; +import { nativeWasmerReceipt, runtimeAbiFacts } from './native-receipts.mts'; + +const arguments_ = Bun.argv.slice(2); +const libraryNameAt = arguments_.indexOf('--libpq-name'); +const libraryName = libraryNameAt < 0 ? 'libpq.so.5' : arguments_.splice(libraryNameAt, 2)[1]; +assert( + ['libpq.so.5', 'libpq.5.dylib'].includes(libraryName), + 'Unsupported native libpq installed name', +); +const archiveInput = arguments_[0] === '--archive'; +if (archiveInput) arguments_.shift(); +const [carrierArg, psqlArg, libraryOrWork, archiveWork] = arguments_; +assert( + carrierArg && + psqlArg && + (archiveInput ? libraryOrWork && arguments_.length <= 4 : arguments_.length <= 3), + 'usage: runtime-test.mts CARRIER PSQL [WORK] | --archive CARRIER PSQL LIBPQ [WORK]', +); +const psqlSource = realpathSync(resolve(psqlArg)); +const workArg = archiveInput ? archiveWork : libraryOrWork; +const work = workArg + ? resolve(workArg) + : process.env.TEST_UNDECLARED_OUTPUTS_DIR + ? join(process.env.TEST_UNDECLARED_OUTPUTS_DIR, 'postmaster-runtime') + : mkdtempSync(join(tmpdir(), 'postmaster-native-runtime-')); +mkdirSync(work, { recursive: true }); +let psql = psqlSource; +const libpq = archiveInput && libraryOrWork ? realpathSync(resolve(libraryOrWork)) : undefined; +if (libpq) { + psql = join(work, 'client/bin/psql'); + const library = join(work, 'client/lib', libraryName); + // Match the maintained native psql loader path and libpq installed identity. + for (const [source, destination] of [ + [psqlSource, psql], + [libpq, library], + ]) { + mkdirSync(join(destination, '..'), { recursive: true }); + writeFileSync(destination, readFileSync(source), { flag: 'wx' }); + chmodSync(destination, lstatSync(source).mode & 0o555); + assert.deepEqual(hashRegular(destination), hashRegular(source)); + } +} +const carrier = archiveInput ? join(work, 'carrier') : resolve(carrierArg); +const archive = archiveInput ? realpathSync(resolve(carrierArg)) : undefined; +if (archive) { + extractPortableArchiveTree(archive, carrier, '', { format: 'tar.gz' }); + // The portable archive writer normalizes writable modes; seal the installed carrier again. + const readonly = (file: string) => { + const stat = lstatSync(file); + assert(stat.isDirectory() || stat.isFile(), 'Installed carrier contains a special entry'); + if (stat.isDirectory()) for (const name of readdirSync(file)) readonly(join(file, name)); + chmodSync(file, stat.mode & 0o555); + }; + readonly(carrier); +} +const wasmer = JSON.parse(readFileSync(join(carrier, 'wasmer-build.receipt'), 'utf8')); +nativeWasmerReceipt(wasmer); +const facts = runtimeAbiFacts(wasmer.runtime_abi); +if (libpq) + assert.equal( + libraryName, + facts.hostAbi === 'darwin' ? 'libpq.5.dylib' : 'libpq.so.5', + 'Native client library differs from actual carrier host', + ); +const manifest = JSON.parse(readFileSync(join(carrier, 'manifest.json'), 'utf8')); +verify( + carrier, + hashRegular(join(carrier, 'wasmer-build.receipt')).sha256, + manifest['postgres-version'], + facts.wasmerVersion, + facts.wasixVersion, + wasmer.runtime_abi.artifact_abi_version, + carrier, +); +const data = join(work, 'pgdata'), + shm = join(work, 'dev-shm'); +mkdirSync(data); +mkdirSync(shm); +const executor = join(carrier, 'bin/wasmer-headless'); +const common = [ + 'run', + '--quiet', + '--disable-cache', + '--sealed-module-manifest', + join(carrier, 'manifest.json'), + '--stack-size', + '33554432', + '--enable-exceptions', + '--enable-threads', + '--net', + '--volume', + `${carrier}:${carrier}`, + '--volume', + `${carrier}/share:/share`, + '--volume', + `${carrier}/lib:/lib`, + '--volume', + `${data}:/pgdata`, + '--volume', + `${shm}:/dev/shm`, +]; +const commands: any[] = []; +const launch = (name: string, module: string, args: string[]) => { + const argv = [executor, ...common, join(carrier, `bin/${module}`), '--', ...args]; + const child = Bun.spawn(argv, { + env: { + LC_ALL: 'C', + OLIPHAUNT_WASIX_SEALED_LOADER_AUDIT_FILE: join(work, `${name}.loader.jsonl`), + }, + stdin: 'ignore', + stdout: Bun.file(join(work, `${name}.stdout`)), + stderr: Bun.file(join(work, `${name}.stderr`)), + }); + commands.push({ name, argv, pid: child.pid }); + return child; +}; +async function exited(child: ReturnType, name: string, seconds = 120) { + let timer: ReturnType | undefined; + try { + const code = await Promise.race([ + child.exited, + new Promise((_resolve, reject) => { + timer = setTimeout(() => { + child.kill('SIGKILL'); + reject(new Error(`${name} timed out; logs: ${work}`)); + }, seconds * 1000); + }), + ]); + assert.equal( + code, + 0, + `${name} failed; logs: ${work}\n${readFileSync(join(work, `${name}.stderr`), 'utf8')}`, + ); + } finally { + if (timer) clearTimeout(timer); + } +} +await exited( + launch('initdb', 'initdb', [ + '-D', + '/pgdata', + '-A', + 'trust', + '--username', + 'postgres', + '--no-locale', + '--encoding=UTF8', + '--no-instructions', + ]), + 'initdb', +); +assert.equal(readFileSync(join(data, 'PG_VERSION'), 'utf8'), '18\n'); +const listener = createServer(); +await new Promise((resolve, reject) => + listener.once('error', reject).listen(0, '127.0.0.1', resolve), +); +const port = (listener.address() as { port: number }).port; +await new Promise((resolve, reject) => + listener.close((error) => (error ? reject(error) : resolve())), +); +const sql = async (query: string) => { + const child = Bun.spawn( + [ + psql, + '-X', + '-A', + '-t', + '-q', + '-v', + 'ON_ERROR_STOP=1', + '-h', + '127.0.0.1', + '-p', + String(port), + '-U', + 'postgres', + '-d', + 'postgres', + '-c', + query, + ], + { env: { LC_ALL: 'C', PGCONNECT_TIMEOUT: '1' }, stdout: 'pipe', stderr: 'pipe' }, + ); + const output = new Response(child.stdout).text(), + error = new Response(child.stderr).text(); + assert.equal(await child.exited, 0, `SQL failed: ${await error}`); + return (await output).trim(); +}; +const assertDurability = async () => { + assert.equal( + await sql(`SELECT + current_setting('fsync') = 'on' AND + current_setting('synchronous_commit') = 'on' AND + current_setting('full_page_writes') = 'on' AND + current_setting('checkpoint_timeout')::interval = interval '1 hour'`), + 't', + 'Recovery qualification requires durable commits and a controlled checkpoint interval', + ); +}; +const contents = () => sql('SELECT value FROM native_carrier_probe ORDER BY value'); +const start = async (name: string) => { + const child = launch(name, 'postgres', [ + '-D', + '/pgdata', + '-h', + '127.0.0.1', + '-p', + String(port), + '-c', + 'unix_socket_directories=', + ...[ + 'fsync=on', + 'synchronous_commit=on', + 'full_page_writes=on', + 'checkpoint_timeout=1h', + ].flatMap((setting) => ['-c', setting]), + ]); + const deadline = Date.now() + 120_000; + while (Date.now() < deadline) { + assert(child.exitCode === null, `${name} exited early; logs: ${work}`); + try { + assert.equal(await sql('SELECT 42'), '42'); + return child; + } catch { + await Bun.sleep(200); + } + } + child.kill('SIGKILL'); + await child.exited; + assert.fail(`${name} startup timed out; logs: ${work}`); +}; +let active: ReturnType | undefined; +try { + active = await start('start'); + await assertDurability(); + await sql(`CREATE TABLE native_carrier_probe(value integer); + INSERT INTO native_carrier_probe VALUES (42); + CREATE TABLE native_concurrent_probe( + client integer NOT NULL, iteration integer NOT NULL, backend_pid integer NOT NULL, + started_at timestamptz NOT NULL, finished_at timestamptz, value integer NOT NULL, + PRIMARY KEY(client, iteration) + )`); + const clients = 4, + perClientRows = 32; + // Commit arrivals before waiting so every backend can observe the rendezvous. + const pids = await Promise.all( + Array.from({ length: clients }, (_, index) => { + const client = index + 1; + return sql(`SET statement_timeout = '30s'; + BEGIN; + INSERT INTO native_concurrent_probe + SELECT ${client}, iteration, pg_backend_pid(), clock_timestamp(), NULL, + ${client} * 100 + iteration + FROM generate_series(1, ${perClientRows}) AS iteration; + COMMIT; + DO $$ BEGIN + WHILE (SELECT count(DISTINCT client) FROM native_concurrent_probe) <> ${clients} LOOP + PERFORM pg_sleep(0.01); + END LOOP; + END $$ LANGUAGE plpgsql; + UPDATE native_concurrent_probe SET finished_at = clock_timestamp(), value = value + 1 + WHERE client = ${client}; + SELECT pg_backend_pid()`); + }), + ); + assert.equal( + new Set(pids).size, + clients, + 'Concurrent connections must have independent backend PIDs', + ); + const concurrent = ( + await sql(`SELECT count(*), count(DISTINCT client), count(DISTINCT backend_pid), + count(finished_at), bool_and(value = client * 100 + iteration + 1), + max(started_at) <= min(finished_at) + FROM native_concurrent_probe`) + ).split('|'); + const concurrentRows = String(clients * perClientRows); + assert.deepEqual( + concurrent, + [concurrentRows, String(clients), String(clients), concurrentRows, 't', 't'], + 'Concurrent indexed writers must all overlap, acknowledge their inserts and finish their updates', + ); + assert.equal( + await sql("SELECT to_tsvector('english', 'running') @@ to_tsquery('english', 'run')"), + 't', + 'Packaged Snowball stemming must execute', + ); + assert.equal(await sql('SELECT sum(value) FROM native_carrier_probe'), '42'); + active.kill('SIGTERM'); + await exited(active, 'start'); + active = undefined; + active = await start('restart'); + await assertDurability(); + assert.equal(await sql('SELECT sum(value) FROM native_carrier_probe'), '42'); + // Checkpoint a multi-page indexed baseline before changing heap and index entries. + await sql(`CREATE UNIQUE INDEX native_carrier_probe_value ON native_carrier_probe(value); + INSERT INTO native_carrier_probe SELECT generate_series(1000, 2023)`); + assert.equal( + await sql( + `SELECT pg_relation_size('native_carrier_probe') > current_setting('block_size')::int`, + ), + 't', + 'Recovery qualification must cover more than one heap page', + ); + await sql('CHECKPOINT'); + const [baselineCheckpoint, baselineFlush] = ( + await sql('SELECT (pg_control_checkpoint()).checkpoint_lsn, pg_current_wal_flush_lsn()') + ).split('|'); + assert.match(baselineCheckpoint, /^[0-9A-F]+\/[0-9A-F]+$/); + assert.match(baselineFlush, /^[0-9A-F]+\/[0-9A-F]+$/); + await sql(`UPDATE native_carrier_probe SET value = value + 10000 + WHERE value BETWEEN 1000 AND 2023 AND value % 2 = 0`); + // sql returns after COMMIT; retain this batch's position before later background WAL. + const acknowledgedInsert = await sql(`WITH inserted AS ( + INSERT INTO native_carrier_probe SELECT generate_series(3000, 3511) RETURNING value + ) SELECT pg_current_wal_insert_lsn() FROM inserted HAVING count(*) = 512`); + assert.match(acknowledgedInsert, /^[0-9A-F]+\/[0-9A-F]+$/); + const expectedValues = [ + 42, + ...Array.from({ length: 1024 }, (_, index) => { + const value = 1000 + index; + return value % 2 === 0 ? value + 10000 : value; + }), + ...Array.from({ length: 512 }, (_, index) => 3000 + index), + ].sort((left, right) => left - right); + const beforeCrash = await contents(); + assert.equal(beforeCrash, expectedValues.join('\n')); + const [preCrashCheckpoint, preCrashFlush, flushCoversInserts, flushAdvanced] = ( + await sql(`SELECT + (pg_control_checkpoint()).checkpoint_lsn, + pg_current_wal_flush_lsn(), + '${acknowledgedInsert}'::pg_lsn <= pg_current_wal_flush_lsn(), + pg_current_wal_flush_lsn() > '${baselineFlush}'::pg_lsn`) + ).split('|'); + assert.equal(preCrashCheckpoint, baselineCheckpoint, 'Checkpoint advanced after the baseline'); + assert.equal(flushCoversInserts, 't', 'Acknowledged inserts must be flushed to WAL'); + assert.equal(flushAdvanced, 't', 'Post-checkpoint commits must advance flushed WAL'); + // Match the canonical immediate-recovery gate: the host signal must reach + // PostgreSQL, clean up shared objects, and leave WAL recovery for the restart. + // Hard host SIGKILL remains the canonical fail-closed shared-object liveness + // limitation; this test never deletes shared objects to admit a restart. + active.kill('SIGQUIT'); + await exited(active, 'restart'); + assert.match( + readFileSync(join(work, 'restart.stderr'), 'utf8'), + /received immediate shutdown request/, + ); + assert.deepEqual(readdirSync(shm), [], 'Shared objects survived immediate guest shutdown'); + active = undefined; + active = await start('recovery'); + await assertDurability(); + assert.equal(await contents(), beforeCrash, 'WAL recovery changed acknowledged rows'); + const recoveryLog = readFileSync(join(work, 'recovery.stderr'), 'utf8'); + assert.match(recoveryLog, /database system was interrupted/); + assert.match(recoveryLog, /redo starts at/); + active.kill('SIGTERM'); + await exited(active, 'recovery'); + assert.match( + readFileSync(join(work, 'recovery.stderr'), 'utf8'), + /received smart shutdown request/, + ); + active = undefined; + active = await start('clean-reopen'); + await assertDurability(); + assert.equal(await contents(), beforeCrash, 'Clean reopen changed recovered rows'); + const cleanLog = readFileSync(join(work, 'clean-reopen.stderr'), 'utf8'); + assert.match(cleanLog, /database system was shut down at/); + assert.doesNotMatch(cleanLog, /automatic recovery in progress/); + active.kill('SIGTERM'); + await exited(active, 'clean-reopen'); + active = undefined; + writeFileSync( + join(work, 'runtime-result.json'), + `${JSON.stringify({ ...(archive ? { archive: hashRegular(archive) } : {}), ...(libpq ? { libpq: hashRegular(libpq) } : {}), carrier_manifest: hashRegular(join(carrier, 'manifest.json')), executor: hashRegular(executor), psql: hashRegular(psql), commands, sql: { answer: 42, concurrent_backend_pids: pids, reopen: 42, recovered: expectedValues.reduce((sum, value) => sum + value, 0) }, immediate_shutdown: { signal: 'SIGQUIT', exit_code: 0, shared_objects_empty: true, redo: true, baseline_checkpoint_lsn: baselineCheckpoint, baseline_flush_lsn: baselineFlush, acknowledged_insert_lsn: acknowledgedInsert, pre_crash_flush_lsn: preCrashFlush, exact_row_count: expectedValues.length, clean_reopen: true } }, null, 2)}\n`, + ); + console.log( + `Native postmaster initdb/start/concurrent SQL/reopen/immediate WAL recovery/clean reopen PASS: ${work}`, + ); +} finally { + if (active && active.exitCode === null) { + active.kill('SIGKILL'); + await active.exited; + } +} diff --git a/build_defs/wasix/postmaster/rust.bzl b/build_defs/wasix/postmaster/rust.bzl new file mode 100644 index 000000000..6f234f42f --- /dev/null +++ b/build_defs/wasix/postmaster/rust.bzl @@ -0,0 +1,155 @@ +"""Compile the authentic postmaster roles using their separate Cargo contexts.""" + +load("@postmaster_compile_metadata//:cargo.bzl", "POSTMASTER_CARGO") +load("@postmaster_compiler_crates//:defs.bzl", compiler_aliases = "aliases", compiler_deps = "all_crate_deps", compiler_crate_deps = "crate_deps") +load("@postmaster_executor_crates//:defs.bzl", executor_aliases = "aliases", executor_deps = "all_crate_deps") +load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") +load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library", "rust_test") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") +load(":runtime-abi.bzl", "postmaster_runtime_abi") + +_COMPILER_COMPATIBLE = select({ + "//build_defs/wasix:llvm_linux_x64": ["@zig_sdk//libc:gnu.2.34"], + "//build_defs/wasix:llvm_linux_arm64": ["@zig_sdk//libc:gnu.2.34"], + "//build_defs/wasix:llvm_macos_arm64": [], + "//conditions:default": ["@platforms//:incompatible"], +}) + +def _version_test_impl(ctx): + binary = ctx.attr.binary[DefaultInfo].files_to_run.executable + result = bun_test_entrypoint( + ctx, + runner = ctx.file._runner, + arguments = [binary, ctx.file.manifest, ctx.attr.role], + files = [binary, ctx.file.manifest], + source_files = [ctx.file._runner], + additional_runfiles = ctx.attr.binary[DefaultInfo].default_runfiles, + ) + return result + ([ctx.attr.binary[RunEnvironmentInfo]] if RunEnvironmentInfo in ctx.attr.binary else []) + +_version_test = rule( + implementation = _version_test_impl, + test = True, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "binary": attr.label(mandatory = True, executable = True, cfg = "target"), + "manifest": attr.label(default = "//src/wasix/postmaster:executor/Cargo.toml", allow_single_file = True), + "role": attr.string(mandatory = True, values = ["executor", "compiler"]), + "_runner": attr.label(default = "//build_defs/wasix/postmaster:version-test.mts", allow_single_file = True), + }), +) + +def postmaster_rust_targets(library_sources): + cargo_toml_env_vars(name = "cargo_env", src = "executor/Cargo.toml") + postmaster_runtime_abi( + name = "runtime_abi", + executor_deps = executor_deps(normal = True, package_name = ""), + compiler_deps = compiler_deps(normal = True, package_name = ""), + patches = POSTMASTER_CARGO["patches"], + root_sources = library_sources + ["executor/" + facts["source"] for facts in POSTMASTER_CARGO["roles"].values()], + ) + native.filegroup(name = "runtime_abi_contract", srcs = [":runtime_abi"], output_group = "contract") + # Diagnostic only: compile the production runtime source unchanged, with + # the executor's genuine role dependencies and a one-probe immutable cache. + rust_binary( + name = "runtime_probe", + srcs = ["//build_defs/wasix/postmaster:runtime-probe.rs", "executor/src/runtime.rs"], + crate_root = "//build_defs/wasix/postmaster:runtime-probe.rs", + edition = POSTMASTER_CARGO["edition"], + version = POSTMASTER_CARGO["version"], + crate_features = POSTMASTER_CARGO["roles"]["executor"]["features"], + deps = [":executor_library"] + executor_deps(normal = True, package_name = ""), + proc_macro_deps = executor_deps(proc_macro = True, package_name = ""), + aliases = executor_aliases(package_name = ""), + rustc_env_files = [":cargo_env", ":runtime_abi"], + tags = ["manual"], + ) + for role, dependencies, aliases in [ + ("executor", executor_deps, executor_aliases), + ("compiler", compiler_deps, compiler_aliases), + ]: + facts = POSTMASTER_CARGO["roles"][role] + normal = dependencies(normal = True, package_name = "") + macros = dependencies(proc_macro = True, package_name = "") + env = [":cargo_env", ":runtime_abi"] + rust_library( + name = role + "_library", + srcs = library_sources, + crate_root = "executor/" + POSTMASTER_CARGO["library"], + crate_name = POSTMASTER_CARGO["crate_name"], + edition = POSTMASTER_CARGO["edition"], + version = POSTMASTER_CARGO["version"], + crate_features = facts["features"], + deps = normal, + proc_macro_deps = macros, + aliases = aliases(package_name = ""), + rustc_env_files = env, + tags = ["manual"], + ) + # LLVM22's native archives have the same internal 2.34 construction + # floor as the maintained serializer; the public executor is separate. + compatible = _COMPILER_COMPATIBLE if role == "compiler" else [] + rust_binary( + name = role, + binary_name = facts["binary"], + srcs = ["executor/" + facts["source"]], + crate_root = "executor/" + facts["source"], + crate_name = facts["binary"].replace("-", "_"), + edition = POSTMASTER_CARGO["edition"], + version = POSTMASTER_CARGO["version"], + crate_features = facts["features"], + deps = [":" + role + "_library"] + normal, + proc_macro_deps = macros, + aliases = aliases(package_name = ""), + rustc_env_files = env, + experimental_use_cc_common_link = 1 if role == "compiler" else -1, + target_compatible_with = compatible, + tags = ["manual"], + ) + # The conventional library unit lane is the compiler-free product role. + if role == "executor": + rust_test( + name = role + "_unit_test", + crate = ":" + role + "_library", + crate_features = facts["features"], + deps = dependencies(normal_dev = True, package_name = ""), + proc_macro_deps = dependencies(proc_macro_dev = True, package_name = ""), + aliases = aliases(normal = True, normal_dev = True, proc_macro = True, proc_macro_dev = True, package_name = ""), + rustc_env_files = env, + tags = ["manual"], + size = "small", + ) + _version_test( + name = role + "_version_test", + binary = ":" + role, + role = role, + args = bun_test_entrypoint_args(role + "_version_test"), + target_compatible_with = compatible, + tags = ["manual"], + size = "small", + ) + rust_binary( + name = "memory_profile", + srcs = ["executor/src/bin/memory-profile.rs"], + crate_root = "executor/src/bin/memory-profile.rs", + crate_name = "oliphaunt_wasix_memory_profile", + edition = POSTMASTER_CARGO["edition"], + version = POSTMASTER_CARGO["version"], + crate_features = POSTMASTER_CARGO["roles"]["compiler"]["features"], + deps = [":compiler_library"] + compiler_crate_deps(["anyhow"], package_name = ""), + rustc_env_files = [":cargo_env", ":runtime_abi"], + experimental_use_cc_common_link = 1, + target_compatible_with = _COMPILER_COMPATIBLE, + tags = ["manual"], + ) + rust_binary( + name = "start_proof", + srcs = ["executor/src/bin/start-proof.rs"], + crate_root = "executor/src/bin/start-proof.rs", + crate_name = "oliphaunt_wasix_start_proof", + edition = POSTMASTER_CARGO["edition"], + version = POSTMASTER_CARGO["version"], + deps = compiler_crate_deps(["anyhow", "hex", "serde", "serde_json", "sha2", "wasmparser"], package_name = ""), + rustc_env_files = [":cargo_env"], + tags = ["manual"], + ) diff --git a/build_defs/wasix/postmaster/seal-modules.mts b/build_defs/wasix/postmaster/seal-modules.mts new file mode 100644 index 000000000..44df0f953 --- /dev/null +++ b/build_defs/wasix/postmaster/seal-modules.mts @@ -0,0 +1,271 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + createReadStream, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import { basename, dirname, join, resolve } from 'node:path'; +import { createInterface } from 'node:readline'; +import { Readable } from 'node:stream'; +import { aggregate } from '../../../src/wasix/postmaster/lib/linear-memory-profile.mts'; +import { + AGGREGATE_RELATIVE, + safeRelative, +} from '../../../src/wasix/postmaster/lib/receipt-files.mts'; +import { + linearMemorySourceHashes, + receiptRelative, + validateExportChain, +} from '../../../src/wasix/postmaster/lib/sealed-export-chain.mts'; +import { + checkInventory, + receipt, + structure, + verifyReceipt, + watInventory, +} from '../../../src/wasix/postmaster/wasmer/bin/verify-postmaster-concurrency-contract.mts'; +import { verify } from '../../../src/wasix/postmaster/wasmer/bin/verify-postmaster-wasm-import.mts'; +import { parseStrictJson } from '../../../tools/packaging/strict-json.mts'; +import { writeAotModuleOutputs } from './guest-inputs.mts'; + +const hash = (data: Uint8Array) => createHash('sha256').update(data).digest('hex'); +type Side = { path: string; input: string; aliases: string[] }; + +export function modulePlan(manifest: string, inputs: string[]): Side[] { + assert.equal( + manifest.split('\n')[0], + '# schema=oliphaunt.wasix-postmaster.sealed-side-modules.v1', + ); + const byName = new Map(); + for (const input of inputs) { + assert(!byName.has(basename(input)), `duplicate side input basename: ${input}`); + byName.set(basename(input), input); + } + const paths = new Set(); + const plan = manifest + .split('\n') + .filter((line) => line && !line.startsWith('#')) + .map((line) => { + const columns = line.split('\t'); + assert.equal(columns.length, 3, 'side module row must have three columns'); + const [path, aliasText, policy] = columns; + const aliases = aliasText === '-' ? [] : aliasText.split(','); + assert(policy, 'side module ABI policy is empty'); + for (const name of [path, ...aliases]) { + safeRelative(name); + assert(!paths.has(name), `duplicate side path: ${name}`); + paths.add(name); + } + const input = byName.get(basename(path)); + assert(input, `missing declared side module: ${path}`); + byName.delete(basename(path)); + return { path, input, aliases }; + }); + assert.equal(plan.length, 27, 'canonical side closure must contain 27 modules'); + assert.equal(byName.size, 0, 'declared side module is absent from canonical policy'); + return plan; +} + +function put(path: string, bytes: Uint8Array | string) { + mkdirSync(dirname(path), { recursive: true }); + writeFileSync(path, bytes, { flag: 'wx', mode: 0o644 }); +} + +function command(tool: string, args: string[], cwd: string) { + const result = Bun.spawnSync([tool, ...args], { + cwd, + env: { LC_ALL: 'C', BINARYEN_CORES: '2' }, + stdout: 'pipe', + stderr: 'pipe', + }); + assert.equal(result.exitCode, 0, `${basename(tool)} failed: ${result.stderr.toString()}`); + return result.stdout.toString().trimEnd(); +} + +async function concurrency(module: string, wasmDis: string, work: string, destination: string) { + const wat = join(work, 'postgres.wat'); + const child = Bun.spawn([wasmDis, module], { + env: { LC_ALL: 'C', BINARYEN_CORES: '2' }, + stdout: Bun.file(wat), + stderr: 'pipe', + }); + const stderr = new Response(child.stderr).text(); + assert.equal(await child.exited, 0, `wasm-dis failed: ${await stderr}`); + const input = createReadStream(wat); + const stream = Readable.toWeb(input) + .pipeThrough(new TextDecoderStream('utf8', { fatal: true })) + .pipeThrough( + new TransformStream({ + transform(chunk, controller) { + assert(!chunk.includes('\r'), 'wasm-dis emitted non-canonical CR text'); + controller.enqueue(chunk); + }, + }), + ); + const lines = createInterface({ input: Readable.fromWeb(stream), crlfDelay: Infinity }); + try { + const inventory = await watInventory(lines); + structure(readFileSync(module)); + checkInventory(inventory); + const contents = receipt( + readFileSync(module), + inventory, + hash(readFileSync(wasmDis)), + command(wasmDis, ['--version'], work), + ); + verifyReceipt(contents, readFileSync(module)); + put(destination, contents); + } finally { + lines.close(); + input.destroy(); + rmSync(wat, { force: true }); + } +} + +export async function sealModules(specPath: string, outputPath: string) { + const spec = parseStrictJson(readFileSync(specPath, 'utf8')); + const output = resolve(outputPath); + const work = mkdtempSync(join(tmpdir(), 'postmaster-sealing-')); + const seed = join(work, 'seed'), + project = join(work, 'project'); + const tools = Object.fromEntries( + Object.entries(spec.tools).map(([key, file]) => [key, resolve(file as string)]), + ); + const policies = Object.fromEntries( + Object.entries(spec.policies).map(([key, file]) => [key, resolve(file as string)]), + ); + try { + for (const file of Object.values(policies)) + put(join(project, 'wasmer/policies', basename(file)), readFileSync(file)); + const sideManifest = readFileSync(policies.sides, 'utf8'); + const plan = modulePlan( + sideManifest, + spec.sides.map((file: string) => resolve(file)), + ); + put(join(seed, 'bin/postgres'), readFileSync(spec.main)); + put(join(seed, 'bin/initdb'), readFileSync(spec.initdb)); + for (const side of plan) put(join(seed, side.path), readFileSync(side.input)); + const prefix = join(output, 'share/postgresql/wasix-postmaster.sealed-export.'); + mkdirSync(dirname(prefix), { recursive: true }); + const sides = plan.map((side) => side.path); + await concurrency( + join(seed, 'bin/postgres'), + tools.wasmDis, + work, + `${prefix}concurrency.seed.receipt`, + ); + command( + tools.sealer, + [ + 'seal', + 'bin/postgres', + policies.mandatory, + policies.dlsym, + `${prefix}seed-proof.json`, + `${prefix}allowlist`, + ...sides, + ], + seed, + ); + const stripped = join(work, 'postgres.stripped'), + final = join(work, 'postgres.exports-sealed'); + command(tools.sealer, ['rewrite', 'bin/postgres', `${prefix}allowlist`, stripped], seed); + command( + tools.wasmOpt, + [ + stripped, + '--remove-unused-module-elements', + '--enable-bulk-memory', + '--enable-threads', + '--enable-mutable-globals', + '--enable-exception-handling', + '--enable-extended-const', + '-o', + final, + ], + seed, + ); + command( + tools.sealer, + [ + 'attest-final', + 'bin/postgres', + final, + policies.mandatory, + policies.dlsym, + `${prefix}allowlist`, + `${prefix}seed-proof.json`, + `${prefix}final-proof.json`, + join(output, receiptRelative), + hash(readFileSync(tools.wasmOpt)), + command(tools.wasmOpt, ['--version'], work), + hash(Buffer.from(sideManifest)), + ...sides, + ], + seed, + ); + verify(readFileSync(final)); + put(`${prefix}start-proof.intermediate.json`, `${command(tools.start, [final], seed)}\n`); + await concurrency(final, tools.wasmDis, work, `${prefix}concurrency.intermediate.receipt`); + const beforeMemory = new Map([ + ['bin/postgres', hash(readFileSync(final))], + ...plan.map((side) => [side.path, hash(readFileSync(side.input))] as [string, string]), + ]); + validateExportChain(output, project, beforeMemory); + const index: string[] = []; + for (const relative of ['bin/postgres', 'bin/initdb', ...sides].sort()) { + const source = relative === 'bin/postgres' ? final : join(seed, relative); + const receiptPath = `receipts/${relative}.json`; + mkdirSync(dirname(join(output, relative)), { recursive: true }); + mkdirSync(dirname(join(work, receiptPath)), { recursive: true }); + command( + tools.memory, + ['seal', '--output', join(output, relative), '--receipt', join(work, receiptPath), source], + seed, + ); + command(tools.memory, ['verify', join(output, relative)], seed); + index.push(`${relative}\t${receiptPath}`); + } + for (const side of plan) + for (const alias of side.aliases) + put(join(output, alias), readFileSync(join(output, side.path))); + put(join(work, 'modules.tsv'), `${index.join('\n')}\n`); + const profile = parseStrictJson(command(tools.memory, ['--profile-json'], work)); + aggregate( + work, + join(work, 'modules.tsv'), + receiptRelative, + hash(readFileSync(join(output, receiptRelative))), + join(output, AGGREGATE_RELATIVE), + profile, + ); + validateExportChain(output, project, linearMemorySourceHashes(output)); + verify(readFileSync(join(output, 'bin/postgres'))); + put( + join(output, 'share/postgresql/wasix-postmaster.start-proof.json'), + `${command(tools.start, [join(output, 'bin/postgres')], seed)}\n`, + ); + await concurrency( + join(output, 'bin/postgres'), + tools.wasmDis, + work, + join(output, 'share/postgresql/wasix-postmaster.concurrency.receipt'), + ); + writeAotModuleOutputs(output, ['bin/postgres', 'bin/initdb', ...sides], spec.moduleOutputs); + console.log( + `Sealed exact postmaster closure: ${index.length} modules, ${plan.length} side modules`, + ); + } finally { + rmSync(work, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + assert.equal(process.argv.length, 4, 'usage: seal-modules.mts SPEC OUTPUT'); + await sealModules(process.argv[2], process.argv[3]); +} diff --git a/build_defs/wasix/postmaster/seal-modules.test.mts b/build_defs/wasix/postmaster/seal-modules.test.mts new file mode 100644 index 000000000..268cae839 --- /dev/null +++ b/build_defs/wasix/postmaster/seal-modules.test.mts @@ -0,0 +1,64 @@ +import { test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { basename } from 'node:path'; +import { modulePlan } from './seal-modules.mts'; + +const manifest = readFileSync( + new URL( + '../../../src/wasix/postmaster/wasmer/policies/sealed-side-modules.v1.tsv', + import.meta.url, + ), + 'utf8', +); +const paths = manifest + .split('\n') + .filter((line) => line && !line.startsWith('#')) + .map((line) => line.split('\t')[0]); +const inputs = paths.map((path) => `declared/${basename(path)}`); + +test('actual canonical side policy preserves paths and aliases independent of File order', () => { + const plan = modulePlan(manifest, [...inputs].reverse()); + assert.deepEqual( + plan.map((row) => row.path), + paths, + ); + for (const row of plan) assert.equal(basename(row.input), basename(row.path)); + assert.equal(plan.length, 27); + assert.deepEqual(plan[0].aliases, manifest.split('\n')[2].split('\t')[1].split(',')); +}); + +test('rejects omitted, extra and duplicate declared side inputs', () => { + assert.throws(() => modulePlan(manifest, inputs.slice(1)), /missing declared/u); + assert.throws( + () => modulePlan(manifest, [...inputs, 'foreign/unknown.so']), + /absent from canonical/u, + ); + assert.throws( + () => modulePlan(manifest, [...inputs, `foreign/${basename(inputs[0])}`]), + /duplicate side input/u, + ); +}); + +test('rejects duplicate or escaping policy paths and aliases', () => { + const first = manifest.split('\n')[2]; + assert.throws(() => modulePlan(`${manifest}${first}\n`, inputs), /duplicate side path/u); + assert.throws( + () => + modulePlan(manifest.replace(first, first.replace('lib/libpq.so,', '../escape.so,')), inputs), + /unsafe receipt path/u, + ); + assert.throws( + () => + modulePlan(manifest.replace(first, first.replace('lib/libpq.so,', '/escape.so,')), inputs), + /unsafe receipt path/u, + ); + assert.throws( + () => + modulePlan( + manifest.replace(first, first.replace('lib/libpq.so,', 'lib/libpq.so.5.18,')), + inputs, + ), + /duplicate side path/u, + ); +}); diff --git a/build_defs/wasix/postmaster/sealed-profile-test.mts b/build_defs/wasix/postmaster/sealed-profile-test.mts new file mode 100644 index 000000000..252d8faee --- /dev/null +++ b/build_defs/wasix/postmaster/sealed-profile-test.mts @@ -0,0 +1,33 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { verifyReceipt } from '../../../src/wasix/postmaster/wasmer/bin/verify-postmaster-concurrency-contract.mts'; +import { parseStrictJson } from '../../../tools/packaging/strict-json.mts'; + +assert.equal(process.argv.length, 5, 'usage: sealed-profile-test.mts SEED SEALED_TREE PROFILE'); +const [seed, sealed, projection] = process.argv.slice(2); +const profile = parseStrictJson(readFileSync(projection, 'utf8')); +assert.deepEqual(Object.keys(profile).sort(), [ + 'expected_final_fences', + 'expected_seed_fences', + 'profile', +]); +assert.equal(profile.profile, 'release-o3'); +for (const field of ['expected_seed_fences', 'expected_final_fences']) + assert(Number.isSafeInteger(profile[field]) && profile[field] >= 4); +verifyReceipt( + readFileSync( + join(sealed, 'share/postgresql/wasix-postmaster.sealed-export.concurrency.seed.receipt'), + 'utf8', + ), + readFileSync(seed), + profile.expected_seed_fences, +); +verifyReceipt( + readFileSync(join(sealed, 'share/postgresql/wasix-postmaster.concurrency.receipt'), 'utf8'), + readFileSync(join(sealed, 'bin/postgres')), + profile.expected_final_fences, +); +console.log( + `Canonical release-o3 fence counts verified: seed=${profile.expected_seed_fences}, sealed=${profile.expected_final_fences}`, +); diff --git a/build_defs/wasix/postmaster/sealing.bzl b/build_defs/wasix/postmaster/sealing.bzl new file mode 100644 index 000000000..7c7b289e6 --- /dev/null +++ b/build_defs/wasix/postmaster/sealing.bzl @@ -0,0 +1,100 @@ +"""Bounded typed export and memory sealing of the native postmaster modules.""" + +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_file_action", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/wasix:wasm.bzl", "WasmModuleInfo") +load(":aot.bzl", "PostmasterModulesInfo", "postmaster_module_outputs") + +def _seal_impl(ctx): + output = ctx.actions.declare_directory(ctx.label.name) + spec = ctx.actions.declare_file(ctx.label.name + ".json") + modules = postmaster_module_outputs(ctx, ctx.attr.module_paths) + main = ctx.attr.main[WasmModuleInfo].module + initdb = ctx.attr.initdb[WasmModuleInfo].module + policies = {"mandatory": ctx.file.mandatory_policy, "dlsym": ctx.file.dlsym_policy, "sides": ctx.file.side_policy} + tools = {"sealer": ctx.executable._sealer, "memory": ctx.executable._memory, "start": ctx.executable._start, "wasmOpt": ctx.executable._optimizer, "wasmDis": ctx.executable._disassembler} + ctx.actions.write(spec, json.encode({ + "moduleOutputs": {path: file.path for path, file in modules.items()}, + "main": main.path, + "initdb": initdb.path, + "sides": [file.path for file in ctx.files.sides], + "policies": {key: file.path for key, file in policies.items()}, + "tools": {key: file.path for key, file in tools.items()}, + })) + arguments = ctx.actions.args() + arguments.add_all([spec, output.path]) + bun_file_action( + ctx, + ctx.file._writer, + source_files = [ctx.file._writer] + ctx.files._writer_sources, + arguments = [arguments], + inputs = [spec, main, initdb] + ctx.files.sides + policies.values() + ctx.files.abi_check, + tools = [ctx.attr._sealer[DefaultInfo].files_to_run, ctx.attr._memory[DefaultInfo].files_to_run, ctx.attr._start[DefaultInfo].files_to_run] + ctx.files._binaryen_files, + outputs = [output] + modules.values(), + mnemonic = "PostmasterSealModules", + progress_message = "Seal and verify exact postmaster module closure %{label}", + resource_set = _resources, + ) + return [DefaultInfo(files = depset([output])), PostmasterModulesInfo(modules = modules)] + +def _resources(_os, _input_count): + return {"cpu": 2, "memory": 2048} + +postmaster_seal_modules = rule( + implementation = _seal_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = { + "module_paths": attr.string_list(mandatory = True), + "main": attr.label(mandatory = True, providers = [WasmModuleInfo]), + "initdb": attr.label(mandatory = True, providers = [WasmModuleInfo]), + "sides": attr.label(mandatory = True, allow_files = True), + "abi_check": attr.label(mandatory = True, allow_files = True), + "mandatory_policy": attr.label(default = "//src/wasix/postmaster:wasmer/policies/sealed-main-runtime-exports.v1.txt", allow_single_file = True), + "dlsym_policy": attr.label(default = "//src/wasix/postmaster:wasmer/policies/sealed-main-dlsym-exports.v1.txt", allow_single_file = True), + "side_policy": attr.label(default = "//src/wasix/postmaster:wasmer/policies/sealed-side-modules.v1.tsv", allow_single_file = True), + "_writer": attr.label(default = "//build_defs/wasix/postmaster:seal-modules.mts", allow_single_file = True), + "_writer_sources": attr.label_list(default = [ + "//:tools/packaging/strict-json.mts", + "//build_defs/wasix/postmaster:guest-inputs.mts", + "//build_defs/wasix/postmaster:native-receipts.mts", + "//src/wasix/postmaster:lib/linear-memory-profile.mts", + "//src/wasix/postmaster:lib/receipt-files.mts", + "//src/wasix/postmaster:lib/sealed-export-chain.mts", + "//src/wasix/postmaster:wasmer/bin/verify-postmaster-wasm-import.mts", + "//src/wasix/postmaster:wasmer/bin/verify-postmaster-concurrency-contract.mts", + ], allow_files = True), + "_sealer": attr.label(default = "//src/wasix/postmaster/tools/sealed-export-closure:sealed_export_closure", executable = True, cfg = "exec"), + "_memory": attr.label(default = "//src/wasix/postmaster:memory_profile", executable = True, cfg = "exec"), + "_start": attr.label(default = "//src/wasix/postmaster:start_proof", executable = True, cfg = "exec"), + "_optimizer": attr.label(default = "@wasix_toolchain//:binaryen/bin/wasm-opt", executable = True, allow_single_file = True, cfg = "exec"), + "_disassembler": attr.label(default = "@wasix_toolchain//:binaryen/bin/wasm-dis", executable = True, allow_single_file = True, cfg = "exec"), + "_binaryen_files": attr.label(default = "@wasix_toolchain//:binaryen_files", cfg = "exec"), + }, +) + +def _profile_test_impl(ctx): + seed = ctx.attr.main[WasmModuleInfo].module + sealed = ctx.file.sealed + if not sealed.is_directory: + fail("Postmaster profile qualification requires the real sealed module tree") + return bun_test_entrypoint(ctx, runner = ctx.file._runner, arguments = [seed, sealed, ctx.file.profile], files = [seed, sealed, ctx.file.profile], source_files = [ctx.file._runner] + ctx.files._sources) + +_postmaster_sealed_profile_test = rule( + implementation = _profile_test_impl, + test = True, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "main": attr.label(mandatory = True, providers = [WasmModuleInfo]), + "sealed": attr.label(mandatory = True, allow_single_file = True), + "profile": attr.label(default = "@postmaster_cargo//:qualification-profile.json", allow_single_file = True), + "_runner": attr.label(default = "//build_defs/wasix/postmaster:sealed-profile-test.mts", allow_single_file = True), + "_sources": attr.label_list(default = [ + "//:tools/packaging/strict-json.mts", + "//src/wasix/postmaster:lib/receipt-files.mts", + "//src/wasix/postmaster:wasmer/bin/verify-postmaster-wasm-import.mts", + "//src/wasix/postmaster:wasmer/bin/verify-postmaster-concurrency-contract.mts", + ], allow_files = True), + }), +) + +def postmaster_sealed_profile_test(name, **kwargs): + _postmaster_sealed_profile_test(name = name, args = bun_test_entrypoint_args(name), **kwargs) diff --git a/build_defs/wasix/postmaster/source-modes.mts b/build_defs/wasix/postmaster/source-modes.mts new file mode 100644 index 000000000..dac0e6af2 --- /dev/null +++ b/build_defs/wasix/postmaster/source-modes.mts @@ -0,0 +1,70 @@ +import assert from 'node:assert/strict'; +import { chmodSync, lstatSync, readFileSync } from 'node:fs'; +import { join } from 'node:path'; + +function safePath(path: string) { + assert( + /^[A-Za-z0-9_./-]+$/.test(path) && + !path.startsWith('/') && + !path.split('/').some((part) => !part || part === '.' || part === '..'), + 'Invalid source mode path', + ); +} + +export function patchNewFileModes(patch: string): Map { + const modes = new Map(); + let pending: number | undefined; + for (const line of patch.split('\n')) { + if (line.startsWith('diff --git ')) + assert.equal(pending, undefined, 'Unconsumed patch new-file mode'); + if (line.startsWith('new file mode ')) { + assert.equal(pending, undefined, 'Duplicate patch new-file mode'); + const mode = line.slice('new file mode '.length); + assert(mode === '100644' || mode === '100755', 'Unsupported patch new-file mode'); + pending = Number.parseInt(mode.slice(3), 8); + } else if (pending !== undefined && line.startsWith('+++ ')) { + assert(line.startsWith('+++ b/'), 'Unexpected patch new-file path'); + const path = line.slice('+++ b/'.length); + safePath(path); + assert(!modes.has(path), 'Duplicate patch new-file identity'); + modes.set(path, pending); + pending = undefined; + } + } + assert.equal(pending, undefined, 'Unconsumed patch new-file mode'); + return modes; +} + +export function applySourceModes(root: string, modes: Map) { + assert(lstatSync(root).isDirectory(), 'Source repository root is not a regular directory'); + // Validate every destination before changing any permission. + for (const [path, mode] of modes) { + safePath(path); + assert(mode === 0o644 || mode === 0o755, 'Unsupported declared source mode'); + const components = path.split('/'); + for (let index = 1; index < components.length; index++) + assert( + lstatSync(join(root, ...components.slice(0, index))).isDirectory(), + 'Source mode ancestor is not a regular directory', + ); + assert(lstatSync(join(root, path)).isFile(), 'Source mode member is not a regular file'); + } + for (const [path, mode] of modes) chmodSync(join(root, path), mode); +} + +if (import.meta.main) { + const [kind, root, input] = process.argv.slice(2); + assert( + kind && root && input && process.argv.length === 5, + 'Expected source mode kind, root and declared input', + ); + let modes: Map; + if (kind === 'patch') modes = patchNewFileModes(readFileSync(input, 'utf8')); + else { + assert.equal(kind, 'overlay', 'Unknown source mode kind'); + const paths = JSON.parse(input) as string[]; + assert(new Set(paths).size === paths.length, 'Duplicate overlay mode identity'); + modes = new Map(paths.map((path) => [path, 0o644])); + } + applySourceModes(root, modes); +} diff --git a/build_defs/wasix/postmaster/source-modes.test.mts b/build_defs/wasix/postmaster/source-modes.test.mts new file mode 100644 index 000000000..751a72475 --- /dev/null +++ b/build_defs/wasix/postmaster/source-modes.test.mts @@ -0,0 +1,68 @@ +import { expect, test } from 'bun:test'; +import { + chmodSync, + mkdirSync, + mkdtempSync, + rmSync, + statSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { applySourceModes, patchNewFileModes } from './source-modes.mts'; + +const patch = `diff --git a/src/added.c b/src/added.c +new file mode 100644 +--- /dev/null ++++ b/src/added.c +@@ -0,0 +1 @@ ++new source +diff --git a/test/probe.sh b/test/probe.sh +new file mode 100755 +--- /dev/null ++++ b/test/probe.sh +@@ -0,0 +1 @@ ++exit 0 +`; + +test('new source modes come only from exact patch declarations', () => { + expect([...patchNewFileModes(patch)]).toEqual([ + ['src/added.c', 0o644], + ['test/probe.sh', 0o755], + ]); + expect(() => + patchNewFileModes(patch.replace('+++ b/src/added.c\n', '+++ b/../escape.c\n')), + ).toThrow('Invalid source mode path'); + expect(() => patchNewFileModes(patch.replace('100644', '120000'))).toThrow( + 'Unsupported patch new-file mode', + ); + expect(() => patchNewFileModes(patch + patch)).toThrow('Duplicate patch new-file identity'); +}); + +test('mode repair touches declared regular files only and fails before writes on symlink escapes', () => { + const root = mkdtempSync(join(tmpdir(), 'postmaster-source-modes-')); + try { + mkdirSync(join(root, 'src')); + writeFileSync(join(root, 'src/added.c'), 'source'); + writeFileSync(join(root, 'untouched.c'), 'unchanged'); + chmodSync(join(root, 'src/added.c'), 0o664); + chmodSync(join(root, 'untouched.c'), 0o664); + applySourceModes(root, new Map([['src/added.c', 0o644]])); + expect(statSync(join(root, 'src/added.c')).mode & 0o777).toBe(0o644); + expect(statSync(join(root, 'untouched.c')).mode & 0o777).toBe(0o664); + symlinkSync(join(root, 'src'), join(root, 'escape')); + expect(() => + applySourceModes( + root, + new Map([ + ['src/added.c', 0o755], + ['escape/added.c', 0o644], + ]), + ), + ).toThrow('ancestor'); + expect(statSync(join(root, 'src/added.c')).mode & 0o777).toBe(0o644); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/build_defs/wasix/postmaster/test-archive.mts b/build_defs/wasix/postmaster/test-archive.mts new file mode 100644 index 000000000..270dfcdaa --- /dev/null +++ b/build_defs/wasix/postmaster/test-archive.mts @@ -0,0 +1,43 @@ +import assert from 'node:assert/strict'; +import { + chmodSync, + lstatSync, + mkdirSync, + mkdtempSync, + readFileSync, + readlinkSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { dirname, join, relative, resolve } from 'node:path'; +import { archiveDirectory } from '../../../tools/packaging/archive-directory.mts'; + +const [rootArg, outputArg, membersArg] = Bun.argv.slice(2); +assert(rootArg && outputArg && membersArg?.startsWith('--tree-files=')); +assert.equal(Bun.argv.length, 5); +const root = resolve(rootArg), + output = resolve(outputArg); +const files = readFileSync(membersArg.slice('--tree-files='.length), 'utf8').trim().split('\n'); +assert(files.length > 0 && new Set(files).size === files.length); +const stage = mkdtempSync(join(dirname(output), '.postmaster-test-carrier-')); +try { + for (const source of files) { + const name = relative(root, resolve(source)); + assert(name && !name.startsWith('../') && !name.includes('\\') && name !== '..'); + // Process-wrapper inputs use a single symlink to the declared output File. + // Accept that presentation while rejecting a source artifact that itself + // points onward to another file or contains a special filesystem entry. + const input = lstatSync(source).isSymbolicLink() + ? resolve(dirname(source), readlinkSync(source)) + : source; + const stat = lstatSync(input); + assert(stat.isFile(), `Declared carrier member is not regular: ${source}`); + const destination = join(stage, name); + mkdirSync(dirname(destination), { recursive: true }); + writeFileSync(destination, readFileSync(input), { flag: 'wx' }); + chmodSync(destination, stat.mode & 0o777); + } + await archiveDirectory(stage, output); +} finally { + rmSync(stage, { recursive: true, force: true }); +} diff --git a/build_defs/wasix/postmaster/testdata/mkalltypes.sed b/build_defs/wasix/postmaster/testdata/mkalltypes.sed new file mode 100644 index 000000000..fa15efc35 --- /dev/null +++ b/build_defs/wasix/postmaster/testdata/mkalltypes.sed @@ -0,0 +1,15 @@ +/^TYPEDEF/s/TYPEDEF \(.*\) \([^ ]*\);$/#if defined(__NEED_\2) \&\& !defined(__DEFINED_\2)\ +typedef \1 \2;\ +#define __DEFINED_\2\ +#endif\ +/ +/^STRUCT/s/STRUCT * \([^ ]*\) \(.*\);$/#if defined(__NEED_struct_\1) \&\& !defined(__DEFINED_struct_\1)\ +struct \1 \2;\ +#define __DEFINED_struct_\1\ +#endif\ +/ +/^UNION/s/UNION * \([^ ]*\) \(.*\);$/#if defined(__NEED_union_\1) \&\& !defined(__DEFINED_union_\1)\ +union \1 \2;\ +#define __DEFINED_union_\1\ +#endif\ +/ diff --git a/build_defs/wasix/postmaster/unwinder-test.c b/build_defs/wasix/postmaster/unwinder-test.c new file mode 100644 index 000000000..faf14a362 --- /dev/null +++ b/build_defs/wasix/postmaster/unwinder-test.c @@ -0,0 +1,14 @@ +int oliphaunt_wasmer_has_linked_libunwind(void); + +#ifdef TEST_LINKED_LIBUNWIND +__attribute__((visibility("hidden"))) +void __unw_add_dynamic_fde(unsigned long address) { (void)address; } +#endif + +int main(void) { +#ifdef TEST_LINKED_LIBUNWIND + return oliphaunt_wasmer_has_linked_libunwind() == 1 ? 0 : 1; +#else + return oliphaunt_wasmer_has_linked_libunwind() == 0 ? 0 : 1; +#endif +} diff --git a/build_defs/wasix/postmaster/unwinder.c b/build_defs/wasix/postmaster/unwinder.c new file mode 100644 index 000000000..e32c9287d --- /dev/null +++ b/build_defs/wasix/postmaster/unwinder.c @@ -0,0 +1,13 @@ +/* A statically linked LLVM unwinder can hide this symbol from dlsym. */ +#if defined(__ELF__) +extern void __unw_add_dynamic_fde(unsigned long) __attribute__((weak)); +#endif + +int oliphaunt_wasmer_has_linked_libunwind(void) +{ +#if defined(__ELF__) + return __unw_add_dynamic_fde != 0; +#else + return 0; +#endif +} diff --git a/build_defs/wasix/postmaster/version-test.mts b/build_defs/wasix/postmaster/version-test.mts new file mode 100644 index 000000000..1cb900f00 --- /dev/null +++ b/build_defs/wasix/postmaster/version-test.mts @@ -0,0 +1,16 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; + +const [binary, manifest, role] = Bun.argv.slice(2); +assert(binary && manifest && (role === 'executor' || role === 'compiler')); +const canonical = Bun.TOML.parse(readFileSync(manifest, 'utf8')) as any; +const candidates = canonical.bin.filter((row: any) => row.name.endsWith(`postmaster-${role}`)); +assert.equal(candidates.length, 1); +const result = Bun.spawnSync([binary, '--version'], { env: process.env }); +assert.equal(result.exitCode, 0, result.stderr.toString()); +const version = result.stdout.toString().trim(); +const expected = `${candidates[0].name} ${canonical.package.version}`; +assert(role === 'compiler' ? version.startsWith(`${expected} `) : version === expected, version); +const invalid = Bun.spawnSync([binary, '--version', 'extra'], { env: process.env }); +assert.notEqual(invalid.exitCode, 0, 'The actual product CLI must reject extra version arguments'); +console.log(version); diff --git a/build_defs/wasix/repositories.bzl b/build_defs/wasix/repositories.bzl new file mode 100644 index 000000000..353559d1e --- /dev/null +++ b/build_defs/wasix/repositories.bzl @@ -0,0 +1,117 @@ +"""Import the canonical immutable WASIX compiler, sysroots and Binaryen pins.""" + +def _asset_rows(text): + rows = [] + names = {} + for line in text.splitlines(): + if not line or line.startswith("#"): + continue + fields = line.split("\t") + if len(fields) != 5: + fail("WASIX asset manifest must contain five tab-separated fields") + kind, name, size, sha256, url = fields + if kind not in ["driver", "sysroot", "llvm", "binaryen"] or name in names: + fail("WASIX asset manifest has an unknown kind or duplicate asset: " + name) + if not size.isdigit() or int(size) <= 0 or int(size) > 500000000: + fail("WASIX asset manifest has an invalid size: " + name) + if len(sha256) != 64 or any([character not in "0123456789abcdef" for character in sha256.elems()]): + fail("WASIX asset manifest has an invalid SHA-256: " + name) + if not url.startswith("https://github.com/") or url.rsplit("/", 1)[-1] != name: + fail("WASIX asset manifest has an invalid immutable asset URL: " + name) + names[name] = True + rows.append(struct(kind = kind, name = name, size = int(size), sha256 = sha256, url = url)) + required = [ + "wasixcc-x86_64-unknown-linux-gnu.tar.gz", + "LLVM-Linux-x86_64.tar.gz", + "binaryen-version_130-x86_64-linux.tar.gz", + "sysroot.tar.gz", + "sysroot-eh.tar.gz", + "sysroot-ehpic.tar.gz", + "sysroot-exnref-eh.tar.gz", + "sysroot-exnref-ehpic.tar.gz", + ] + if sorted(names) != sorted(required): + fail("WASIX Linux-x64 toolchain requires the canonical closed eight-asset inventory") + return rows + +def _wasix_toolchain_repository_impl(ctx): + rows = _asset_rows(ctx.read(ctx.attr.asset_manifest)) + for row in rows: + # This native profile always enables exnref exceptions and PIC. Keep + # validating the complete canonical pin inventory, while acquiring only + # the sysroot selected by actual compiler/linker actions. + if row.kind == "sysroot" and row.name != "sysroot-exnref-ehpic.tar.gz": + continue + if row.kind == "sysroot": + name = row.name[:-len(".tar.gz")] + output = "sysroot/" + name + prefix = "wasix-" + name + "/sysroot" + elif row.kind == "binaryen": + output = "binaryen" + prefix = "binaryen-version_130" + else: + output = row.kind + prefix = "" + # The exact digest also commits to the canonical byte count/layout. + ctx.download_and_extract(url = row.url, sha256 = row.sha256, output = output, stripPrefix = prefix) + for command in ["wasixcc", "wasix++", "wasixcc++", "wasixar", "wasixnm", "wasixranlib", "wasixld"]: + ctx.symlink("driver/wasixccenv", "bin/" + command) + ctx.symlink(ctx.attr.asset_manifest, "ASSETS.tsv") + ctx.symlink(ctx.attr.build_file, "BUILD.bazel") + +wasix_toolchain_repository = repository_rule( + implementation = _wasix_toolchain_repository_impl, + attrs = { + "asset_manifest": attr.label(default = "//src/wasix/runtime:assets/build/docker/pinned-wasixcc-assets.tsv", allow_single_file = True), + "build_file": attr.label(default = "//build_defs/wasix:toolchain.BUILD.bazel", allow_single_file = True), + }, +) + +def _wasix_tool_metadata_impl(ctx): + root = ctx.path(ctx.attr.root_marker).dirname + converter = ctx.path(ctx.attr.converter) + ctx.read(converter) + ctx.watch(ctx.path(ctx.attr.bun)) + result = ctx.execute([str(ctx.path(ctx.attr.bun)), str(converter), "--root", str(root), "--output-dir", str(ctx.path("."))], timeout = 120) + if result.return_code: + fail("WASIX tool metadata import failed:\n" + result.stdout + result.stderr) + observed = json.decode(ctx.read(".metadata-inputs.json")) + for relative, content in observed.items(): + source = root.get_child(relative) + ctx.watch(source) + if ctx.read(source) != content: + fail("WASIX tool metadata changed during import: " + relative) + ctx.file("BUILD.bazel", "package(default_visibility = [\"//visibility:public\"])\nexports_files([\"llvm.json\", \"targets.bzl\"])\n") + +wasix_tool_metadata = repository_rule( + implementation = _wasix_tool_metadata_impl, + attrs = { + "root_marker": attr.label(default = "//:package.json", allow_single_file = True), + "converter": attr.label(default = "//build_defs/wasix:tool-metadata.mts", allow_single_file = True), + "bun": attr.label(mandatory = True, allow_single_file = True), + }, +) + +def _wasmer_llvm_repository_impl(ctx): + metadata = json.decode(ctx.read(ctx.attr.metadata)) + if ctx.attr.host not in metadata["hosts"]: + fail("no canonical Wasmer LLVM acquisition pin for " + ctx.attr.host) + pin = metadata["hosts"][ctx.attr.host] + ctx.download_and_extract(url = pin["url"], sha256 = pin["sha256"], type = "tar.xz") + ctx.file("TOOLCHAIN.json", json.encode({"version": metadata["version"], "host": ctx.attr.host, "triple": pin["triple"], "sha256": pin["sha256"]}) + "\n") + # The standard Cargo build-script runner expands ${pwd} to its execroot. + # Derive both the ABI key and canonical repository path; do not discover an + # LLVM installation through the host environment or copy a repository name. + ctx.file("llvm.env", "LLVM_SYS_" + str(metadata["llvm_sys_abi"]) + "_PREFIX=${pwd}/external/" + ctx.name + "\n") + ctx.file("BUILD.bazel", """package(default_visibility = ["//visibility:public"]) +exports_files(["TOOLCHAIN.json", "llvm.env"] + glob(["bin/*"])) +filegroup(name = "files", srcs = glob(["bin/**", "lib/**", "usr/include/**", "include/**", "share/**"], allow_empty = True) + ["TOOLCHAIN.json"]) +""") + +wasmer_llvm_repository = repository_rule( + implementation = _wasmer_llvm_repository_impl, + attrs = { + "metadata": attr.label(default = "@wasix_tool_metadata//:llvm.json", allow_single_file = True), + "host": attr.string(mandatory = True), + }, +) diff --git a/build_defs/wasix/runtime-release.bzl b/build_defs/wasix/runtime-release.bzl new file mode 100644 index 000000000..995b82f2a --- /dev/null +++ b/build_defs/wasix/runtime-release.bzl @@ -0,0 +1,172 @@ +"""Current-source core runtime GitHub, npm and Cargo carriers.""" + +load("@oliphaunt_metadata//:metadata.bzl", "PRODUCTS", "PUBLICATION_CARRIERS", "WASIX_ARTIFACTS") +load("@wasix_tool_metadata//:targets.bzl", "WASIX_AOT_TARGETS") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_file_action", "bun_test_entrypoint", "bun_test_entrypoint_args") +load("//build_defs/extensions:contrib_carriers.bzl", "native_contrib_carrier_metadata") +load("//build_defs/native/carriers:defs.bzl", "native_checksum_manifest") +load("//build_defs/release:identity.bzl", "ReleaseIdentityInfo") +load("//build_defs/release:shipping.bzl", "ShippingInfo", "shipping_export", "shipping_package") +load(":cargo.bzl", "RUNTIME_CARGO_HELPERS") +load(":npm.bzl", "RUNTIME_NPM_HELPERS", "RUNTIME_NPM_NOTICES") +load(":platform.bzl", "WASIX_PORTABLE_TRANSITION") +load(":wasm.bzl", "WasmExportPolicyInfo") + +_PRODUCT = "liboliphaunt-wasix" +_OWNER = "@oliphaunt_metadata//:product_" + _PRODUCT +_SUPPLIERS = "//src/wasix/runtime:runtime_public_suppliers" + +RUNTIME_RELEASE_HELPERS = {label: True for label in RUNTIME_CARGO_HELPERS + RUNTIME_NPM_HELPERS + [ + "//build_defs/wasix:cargo.mts", + "//build_defs/wasix:package.mts", + "//src/wasix/runtime:tools/package-release-assets.mts", + "//build_defs/native/carriers:checksums.mts", +]}.keys() + +def _sources(entries, inputs): + result = {} + for target, destination in entries.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1 or files[0].is_directory or destination in result: + fail("Runtime release input requires one unique declared File") + result[destination] = files[0].path + inputs.extend(files) + return result + +def _release_asset_impl(ctx): + owner = ctx.attr.owner[ReleaseIdentityInfo] + if owner.id != _PRODUCT: + fail("Runtime release archive has a foreign source owner") + payload = ctx.attr.payload[DefaultInfo].files.to_list() + if len(payload) != 1 or not payload[0].is_directory: + fail("Runtime release archive requires its actual current payload TreeArtifact") + artifact = json.decode(ctx.attr.artifact) + output = ctx.actions.declare_file(ctx.label.name + "/" + artifact["asset"].replace("{version}", owner.version)) + inputs = payload + [ctx.file.toolchain, ctx.file.postgres_source, ctx.file.postgres_series, ctx.file.icu_source] + ctx.files.patches + generated = _sources(ctx.attr.generated, inputs) + if artifact["target"] == "portable": + exports = ctx.attr.export_policy[0][WasmExportPolicyInfo].exports + inputs.append(exports) + generated["src/runtimes/liboliphaunt-wasix/assets/generated/wasix-dl.exports"] = exports.path + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode({ + "version": owner.version, + "artifact": artifact, + "payload": payload[0].path, + "notices": _sources(ctx.attr.notices, inputs), + "generated": generated, + "toolchain": ctx.file.toolchain.path, + "postgresSource": ctx.file.postgres_source.path, + "postgresSeries": ctx.file.postgres_series.path, + "patches": {file.short_path: file.path for file in ctx.files.patches}, + "icuSource": ctx.file.icu_source.path, + "output": output.path, + })) + args = ctx.actions.args() + args.add_all(["package", spec]) + leaves = ctx.actions.args() + leaves.add_all(payload, expand_directories = True) + leaves.use_param_file("--payload-files=%s", use_always = True) + leaves.set_param_file_format("multiline") + bun_file_action(ctx, ctx.file._runner, arguments = [args, leaves], inputs = depset(inputs + [spec]), + source_files = ctx.files._helpers + [ctx.file.toolchain] + ctx.files.notices, + outputs = [output], mnemonic = "WasixRuntimeReleaseArchive") + return [DefaultInfo(files = depset([output]))] + +_release_asset = rule( + implementation = _release_asset_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = { + "owner": attr.label(default = _OWNER, providers = [ReleaseIdentityInfo]), + "payload": attr.label(mandatory = True), + "export_policy": attr.label(default = "//src/wasix/runtime:export_policy", providers = [WasmExportPolicyInfo], cfg = WASIX_PORTABLE_TRANSITION), + "artifact": attr.string(mandatory = True), + "generated": attr.label_keyed_string_dict(allow_files = True), + "notices": attr.label_keyed_string_dict(default = RUNTIME_NPM_NOTICES, allow_files = True), + "patches": attr.label_list(allow_files = [".patch"], mandatory = True), + "toolchain": attr.label(default = "//src/wasix/runtime:toolchain.toml", allow_single_file = True), + "postgres_source": attr.label(default = "//src/third-party/postgres:source.toml", allow_single_file = True), + "postgres_series": attr.label(default = "//src/wasix/runtime:postgres/series", allow_single_file = True), + "icu_source": attr.label(default = "//src/third-party/icu:source.toml", allow_single_file = True), + "_runner": attr.label(default = "//build_defs/wasix:runtime-release.mts", allow_single_file = True), + "_helpers": attr.label_list(default = RUNTIME_RELEASE_HELPERS, allow_files = True), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), + }, +) + +def _final_packages_test_impl(ctx): + owner = ctx.attr.owner[ReleaseIdentityInfo] + if owner.id != _PRODUCT: + fail("Final runtime package test requires the canonical source owner") + portable = ctx.attr.portable[DefaultInfo].files.to_list() + if len(portable) != 1 or not portable[0].is_directory: + fail("Final runtime package test requires the actual current portable TreeArtifact") + exports = ctx.attr.export_policy[0][WasmExportPolicyInfo].exports + inputs, packages = portable + [exports], [] + for target in ctx.attr.packages: + info = target[ShippingInfo] + if info.product != owner.id or info.version != owner.version: + fail("Final runtime package test cannot mix product owners or versions") + files = info.files.to_list() + inputs.extend(files) + packages.append({"ecosystem": info.ecosystem, "name": info.name, "version": info.version, "files": [file.short_path for file in files]}) + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + contrib_identities = {(row["ecosystem"], row["name"]): True for row in native_contrib_carrier_metadata("wasix-portable", family = "wasix")["carriers"]} + ctx.actions.write(spec, json.encode({ + "version": owner.version, + "artifacts": [row for row in WASIX_ARTIFACTS if row["product"] == _PRODUCT and "github-release" in row["surfaces"]], + "registryCarriers": [row for row in PUBLICATION_CARRIERS if row["product"] == _PRODUCT and row["ecosystem"] in ["cargo", "npm"] and (row["ecosystem"], row["name"]) not in contrib_identities], + "packages": packages, + "portable": portable[0].short_path, + "exportPolicy": exports.short_path, + })) + return bun_test_entrypoint(ctx, ctx.file._runner, ["verify", spec], inputs + [spec] + ctx.files._helpers + ctx.files._notices + [ctx.file._toolchain]) + +_final_packages_test = rule( + implementation = _final_packages_test_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + test = True, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "owner": attr.label(default = _OWNER, providers = [ReleaseIdentityInfo]), + "portable": attr.label(mandatory = True), + "export_policy": attr.label(default = "//src/wasix/runtime:export_policy", providers = [WasmExportPolicyInfo], cfg = WASIX_PORTABLE_TRANSITION), + "packages": attr.label_list(mandatory = True, providers = [ShippingInfo]), + "_runner": attr.label(default = "//build_defs/wasix:runtime-release.mts", allow_single_file = True), + "_helpers": attr.label_list(default = RUNTIME_RELEASE_HELPERS, allow_files = True), + "_notices": attr.label_list(default = RUNTIME_NPM_NOTICES.keys(), allow_files = True), + "_toolchain": attr.label(default = "//src/wasix/runtime:toolchain.toml", allow_single_file = True), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), + }), +) + +def wasix_runtime_release_assets(patches, generated, qualification): + rows = [row for row in WASIX_ARTIFACTS if row["product"] == _PRODUCT and "github-release" in row["surfaces"]] + archives = [] + for row in rows: + if row["kind"] == "checksums": + continue + name = row["target"].replace("-", "_") + _release_asset(name = "release_archive_" + name, + artifact = json.encode(row), patches = patches, + generated = generated if row["target"] == "portable" else {}, + payload = ":portable_payload" if row["target"] == "portable" else ":aot_" + name + "_payload") + archives.append(":release_archive_" + name) + native_checksum_manifest(name = "release_assets", product = _PRODUCT, archives = archives, + artifact_rows = WASIX_ARTIFACTS, assemble = True) + packages = [":npm_shipping_package", "//src/wasix/runtime/crates/assets:shipping_package"] + [ + "//src/wasix/runtime/crates/aot/" + triple + ":shipping_package" for triple in WASIX_AOT_TARGETS.values() + ] + for row in rows: + name = "release_" + ("checksums" if row["kind"] == "checksums" else row["target"].replace("-", "_")) + asset = row["asset"].replace("{version}", PRODUCTS[_PRODUCT]["version"]) + native.filegroup(name = name, srcs = [":release_assets"], output_group = "checksums" if row["kind"] == "checksums" else asset) + shipping_package(name = name + "_shipping", owner = _OWNER, artifacts = [":" + name], + ecosystem = "github", package_name = asset, configuration = row.get("target") or "portable", + role = "github-release-asset", suppliers = _SUPPLIERS) + packages.append(":" + name + "_shipping") + _final_packages_test(name = "final_package_test", args = bun_test_entrypoint_args("final_package_test"), portable = ":portable_payload", packages = packages, + size = "medium", tags = ["manual"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"]) + shipping_export(name = "shipping_export", packages = packages, + qualification = [":final_package_test"] + qualification, testonly = True, + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"]) diff --git a/build_defs/wasix/runtime-release.mts b/build_defs/wasix/runtime-release.mts new file mode 100644 index 000000000..acb7b1bbb --- /dev/null +++ b/build_defs/wasix/runtime-release.mts @@ -0,0 +1,272 @@ +/** Canonical final core-runtime carriers from declared current payloads. */ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { + validateAotReleaseAsset, + validatePortableReleaseAsset, +} from '../../src/wasix/runtime/tools/check-release-assets.mts'; +import { + stageAotAssets, + stagePortableAssets, +} from '../../src/wasix/runtime/tools/package-release-assets.mts'; +import { + AOT_PACKAGES, + AOT_TARGET_TRIPLES, + RUNTIME_PACKAGE, +} from '../../src/wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; +import { WASIX_PORTABLE_RELEASE_MEMBERS } from '../../src/wasix/runtime/tools/wasix-runtime-npm-contract.mts'; +import { + assertWasixRuntimeNpmArchive, + wasixRuntimeNpmPayloadInputs, +} from '../../src/wasix/runtime/tools/wasix-runtime-npm-payload.mts'; +import { createDeterministicTar } from '../../tools/packaging/archive-directory.mts'; +import { + extractPortableArchiveTree, + readPortableArchiveEntries, + releaseZstdCompressSync, +} from '../../tools/packaging/portable-archive.mts'; +import { stageReleaseNotices } from '../../tools/packaging/release-notices.mts'; +import { ROOT } from '../../tools/release/release-artifact-targets.mts'; +import { writeNativeChecksums } from '../native/carriers/checksums.mts'; +import { copyDeclaredSources, stageDeclaredPayload, validatePackedRuntimeCargo } from './cargo.mts'; +import { type RuntimePayloadSpec, sourceFacts } from './package.mts'; + +interface RuntimeArtifact { + product: string; + kind: string; + target?: string; + triple?: string; + asset: string; +} + +export interface RuntimeReleaseSpec + extends Pick { + version: string; + artifact: RuntimeArtifact; + payload: string; + payloadFiles: string[]; + notices: Record; + generated: Record; + toolchain: string; + output: string; +} + +export async function packageRuntimeReleaseAsset(spec: RuntimeReleaseSpec): Promise { + const portable = spec.artifact.target === 'portable'; + assert.equal(spec.artifact.product, 'liboliphaunt-wasix'); + assert.equal(spec.artifact.kind, portable ? 'wasix-runtime' : 'wasix-aot-runtime'); + assert.match(spec.version, /^\d+\.\d+\.\d+$/u); + assert( + portable || + (typeof spec.artifact.target === 'string' && + Object.hasOwn(AOT_TARGET_TRIPLES, spec.artifact.target) && + spec.artifact.triple === AOT_TARGET_TRIPLES[spec.artifact.target]), + ); + const asset = spec.artifact.asset.replaceAll('{version}', spec.version); + assert.equal(path.basename(asset), asset); + assert.equal(path.basename(spec.output), asset); + assert(asset.endsWith('.tar.zst')); + mkdirSync(path.dirname(spec.output), { recursive: true }); + const scratch = mkdtempSync( + path.join(path.dirname(path.resolve(spec.output)), '.wasix-runtime-release-'), + ); + try { + const payload = path.join(scratch, 'payload'); + stageDeclaredPayload(spec, payload); + const sourceRoot = path.join(scratch, 'sources'); + copyDeclaredSources(spec.notices, sourceRoot); + copyDeclaredSources({ 'src/wasix/runtime/toolchain.toml': spec.toolchain }, sourceRoot); + const stage = path.join(scratch, 'archive'); + const { source_fingerprint: fingerprint } = await sourceFacts(spec); + if (portable) { + stagePortableAssets(payload, path.join(stage, 'target/oliphaunt-wasix/assets'), fingerprint); + copyDeclaredSources(spec.generated, stage); + stageReleaseNotices(stage, { profile: 'wasix-runtime', sourceRoot }); + } else { + const target = path.join(stage, 'target/oliphaunt-wasix/aot', spec.artifact.triple); + stageAotAssets(payload, target, spec.artifact.triple, fingerprint); + stageReleaseNotices(target, { profile: 'wasix-aot', sourceRoot }); + } + writeFileSync(spec.output, releaseZstdCompressSync(await createDeterministicTar(stage))); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +} + +interface RegistryCarrier { + ecosystem: string; + name: string; + target?: string; +} +export interface RuntimeFinalPackageSpec { + version: string; + artifacts: RuntimeArtifact[]; + registryCarriers: RegistryCarrier[]; + packages: { ecosystem: string; name: string; version: string; files: string[] }[]; + portable: string; + exportPolicy: string; +} + +export function verifyRuntimeFinalPackages(spec: RuntimeFinalPackageSpec): void { + const sha = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); + const json = (file: string) => JSON.parse(readFileSync(file, 'utf8')); + const currentManifestBytes = readFileSync( + realpathSync(path.join(spec.portable, 'manifest.json')), + ); + const currentRuntimeBytes = readFileSync( + realpathSync(path.join(spec.portable, 'oliphaunt.wasix.tar.zst')), + ); + const currentManifest = JSON.parse(currentManifestBytes.toString('utf8')); + const current = wasixRuntimeNpmPayloadInputs({ + manifestBytes: currentManifestBytes, + runtimeBytes: currentRuntimeBytes, + label: 'actual current portable producer', + }); + const expected = [ + ...spec.artifacts.map((row) => `github:${row.asset.replaceAll('{version}', spec.version)}`), + ...spec.registryCarriers.map((row) => `${row.ecosystem}:${row.name}`), + ].sort(); + assert.equal( + new Set(expected).size, + expected.length, + 'Canonical runtime carrier identities must be unique', + ); + assert.deepEqual( + spec.packages.map((row) => `${row.ecosystem}:${row.name}`).sort(), + expected, + 'Final runtime carrier inventory differs from its canonical owner', + ); + const byIdentity = new Map( + spec.packages.map((row) => { + assert.equal(row.version, spec.version); + assert.equal(row.files.length, 1, 'Each final runtime carrier must own exactly one archive'); + return [`${row.ecosystem}:${row.name}`, realpathSync(row.files[0])] as const; + }), + ); + const scratch = mkdtempSync( + path.join(process.env.TEST_TMPDIR ?? os.tmpdir(), 'wasix-final-packages-'), + ); + try { + const githubManifests = new Map(); + const archives = []; + const rows = spec.artifacts.filter((row) => row.kind !== 'checksums'); + assert.equal(rows.length, 5); + for (const row of rows) { + const file = byIdentity.get(`github:${row.asset.replaceAll('{version}', spec.version)}`); + assert(file); + archives.push(file); + if (row.target === 'portable') { + const entries = validatePortableReleaseAsset(file); + assert.deepEqual( + entries.get('src/runtimes/liboliphaunt-wasix/assets/generated/wasix-dl.exports')?.data(), + readFileSync(realpathSync(spec.exportPolicy)), + 'Portable release export policy differs from its actual current compiled producer', + ); + const manifest = JSON.parse( + entries.get(WASIX_PORTABLE_RELEASE_MEMBERS.manifest).data().toString('utf8'), + ); + assert.deepEqual( + manifest, + currentManifest, + 'GitHub portable metadata differs from the actual current producer', + ); + assert.equal( + sha(entries.get(WASIX_PORTABLE_RELEASE_MEMBERS.runtimeArchive).data()), + current.runtimeArchive.sha256, + ); + githubManifests.set('portable', manifest); + } else { + assert.equal(row.triple, AOT_TARGET_TRIPLES[row.target]); + const entries = validateAotReleaseAsset(file, row.triple); + const manifest = JSON.parse( + entries + .get(`target/oliphaunt-wasix/aot/${row.triple}/manifest.json`) + .data() + .toString('utf8'), + ); + assert.equal(manifest['source-fingerprint'], currentManifest['source-fingerprint']); + assert.equal( + manifest.artifacts.find((item) => item.name === 'runtime:oliphaunt')?.['module-sha256'], + currentManifest.runtime['module-sha256'], + ); + githubManifests.set(row.target, manifest); + } + } + const checksumRows = spec.artifacts.filter((row) => row.kind === 'checksums'); + assert.equal(checksumRows.length, 1); + const checksum = byIdentity.get( + `github:${checksumRows[0].asset.replaceAll('{version}', spec.version)}`, + ); + assert(checksum); + const expectedChecksum = path.join(scratch, 'expected.sha256'); + writeNativeChecksums({ + expected: rows.map((row) => row.asset.replaceAll('{version}', spec.version)), + files: archives, + output: expectedChecksum, + }); + assert.deepEqual( + readFileSync(checksum), + readFileSync(expectedChecksum), + 'Final checksum does not cover exactly the canonical five runtime archives', + ); + for (const carrier of spec.registryCarriers) { + const file = byIdentity.get(`${carrier.ecosystem}:${carrier.name}`); + assert(file); + if (carrier.ecosystem === 'npm') { + assertWasixRuntimeNpmArchive(file, { + version: spec.version, + descriptor: { version: spec.version, ...current }, + }); + } else { + assert.equal(carrier.ecosystem, 'cargo'); + const target = + carrier.name === RUNTIME_PACKAGE + ? null + : Object.keys(AOT_PACKAGES).find((id) => AOT_PACKAGES[id] === carrier.name); + assert(target !== undefined, 'Unknown final runtime Cargo carrier'); + const archiveRoot = `${carrier.name}-${spec.version}`; + const cargoManifest = readPortableArchiveEntries(file).get(`${archiveRoot}/Cargo.toml`); + assert(cargoManifest?.isFile); + const manifest = Bun.TOML.parse(cargoManifest.data().toString('utf8')); + assert.equal(manifest.package.name, carrier.name); + assert.equal(manifest.package.version, spec.version); + const extracted = path.join(scratch, carrier.name); + extractPortableArchiveTree(file, extracted, archiveRoot); + validatePackedRuntimeCargo(extracted, { packageName: carrier.name, target }, ROOT); + const payload = path.join(extracted, target === null ? 'payload' : 'artifacts'); + assert.deepEqual( + json(path.join(payload, 'manifest.json')), + githubManifests.get(target ?? 'portable'), + 'Cargo and GitHub runtime metadata differ', + ); + if (target === null) + assert.equal( + sha(readFileSync(path.join(payload, 'oliphaunt.wasix.tar.zst'))), + current.runtimeArchive.sha256, + ); + } + } + console.log(`Verified ${spec.packages.length} actual current runtime carriers`); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + const [operation, specFile, leaves] = Bun.argv.slice(2); + assert(specFile && (operation === 'package' || operation === 'verify')); + const spec = JSON.parse(readFileSync(specFile, 'utf8')); + if (operation === 'verify') verifyRuntimeFinalPackages(spec); + else { + assert(leaves?.startsWith('--payload-files=')); + await packageRuntimeReleaseAsset({ + ...spec, + payloadFiles: readFileSync(leaves.slice('--payload-files='.length), 'utf8') + .trimEnd() + .split(/\r?\n/u), + }); + } +} diff --git a/build_defs/wasix/sdk-installed.bzl b/build_defs/wasix/sdk-installed.bzl new file mode 100644 index 000000000..9dc7927b7 --- /dev/null +++ b/build_defs/wasix/sdk-installed.bzl @@ -0,0 +1,73 @@ +"""Original public SDK host contracts over its actual declared package tuple.""" + +load("@aspect_rules_js//npm:providers.bzl", "NpmPackageInfo") +load("@oliphaunt_metadata//:metadata.bzl", "COMPLETED_SUPPLIER_ARTIFACTS", "PREPARED_NATIVE_SELECTED_PRODUCTS", "PRODUCTS", "PUBLICATION_CARRIERS", "WASIX_ARTIFACTS") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_test_entrypoint", "bun_test_entrypoint_args") + +def _runfile(ctx, file): + return file.short_path[3:] if file.short_path.startswith("../") else ctx.workspace_name + "/" + file.short_path + +def _installed_impl(ctx): + if ctx.attr.error: + fail(ctx.attr.error) + node = ctx.toolchains["@rules_nodejs//nodejs:toolchain_type"].nodeinfo.node + if not node or not ctx.executable.deno or not ctx.executable.electron or not ctx.files.electron_runtime: + fail("WASIX public SDK host contracts require pinned Node, Deno and complete Electron inputs") + packages = [] + files = [ctx.file.sdk, ctx.file.runtime, ctx.file.addon, ctx.file.extension, ctx.file.fixture, ctx.file.pgwire, ctx.file._runner, node, ctx.executable.deno, ctx.executable.electron] + ctx.files.electron_runtime + for target, name in ctx.attr.packages.items(): + package = target[NpmPackageInfo] + if package.package != name or package.src.is_directory: + fail("installed WASIX SDK requires its declared npm package archive: " + name) + packages.append({"name": name, "version": package.version, "archive": _runfile(ctx, package.src)}) + files.append(package.src) + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode({"packages": packages})) + return bun_test_entrypoint(ctx, ctx.file._runner, + [ctx.file.sdk, ctx.file.runtime, ctx.file.addon, ctx.file.extension, ctx.file.fixture, ctx.file.pgwire, node, ctx.executable.deno, ctx.executable.electron, spec], + files + [spec] + ctx.files._helpers, + source_files = [ctx.file._runner] + ctx.files._helpers, + runfiles_environment = ["OLIPHAUNT_BAZEL_RUNFILES"]) + +_installed_test = rule(implementation = _installed_impl, test = True, + toolchains = BUN_SOURCE_TOOLCHAINS + ["@rules_nodejs//nodejs:toolchain_type"], + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **{ + "sdk": attr.label(mandatory = True, allow_single_file = [".tgz"]), + "runtime": attr.label(allow_single_file = [".tgz"]), + "addon": attr.label(allow_single_file = [".tgz"]), + "extension": attr.label(mandatory = True, allow_single_file = [".tgz"]), + "fixture": attr.label(mandatory = True, allow_single_file = [".mts"]), + "pgwire": attr.label(mandatory = True, allow_single_file = [".mts"]), + "packages": attr.label_keyed_string_dict(providers = [NpmPackageInfo]), + "error": attr.string(), + "deno": attr.label(executable = True, cfg = "exec", allow_files = True, mandatory = True), + "electron": attr.label(executable = True, cfg = "exec", allow_files = True, mandatory = True), + "electron_runtime": attr.label_list(cfg = "exec", allow_files = True, mandatory = True), + "_runner": attr.label(default = "//build_defs/wasix:sdk-installed.mts", allow_single_file = True), + "_helpers": attr.label_list(default = ["//build_defs/wasix/browser:npm-archives.mts"], allow_files = True), + })) + +def _package_input(product, version, package_name, current): + key = product + "/" + version + "/npm:" + package_name + captured = COMPLETED_SUPPLIER_ARTIFACTS.get(key) + if captured: + return struct(archive = captured["file"]["path"], error = "") + if product in PREPARED_NATIVE_SELECTED_PRODUCTS and PRODUCTS[product]["version"] == version: + return struct(archive = current, error = "") + return struct(archive = None, error = "installed WASIX SDK requires completed npm:" + package_name + "@" + version) + +def wasix_sdk_installed_test(name, **kwargs): + descriptor = PRODUCTS["oliphaunt-wasix-ts"] + runtime_version = descriptor["compatibility_versions"]["liboliphaunt-wasix"] + addon_version = descriptor["compatibility_versions"]["oliphaunt-wasix-napi"] + runtime_rows = [row for row in PUBLICATION_CARRIERS if row["product"] == "liboliphaunt-wasix" and row["ecosystem"] == "npm" and "npm:" + row["name"] in PRODUCTS["liboliphaunt-wasix"]["registry_packages"]] + addon_rows = [row for row in WASIX_ARTIFACTS if row["product"] == "oliphaunt-wasix-napi" and row["kind"] == "wasix-napi-addon" and row["target"] == "linux-x64-gnu"] + if len(runtime_rows) != 1 or len(addon_rows) != 1: + fail("WASIX SDK host contracts require canonical runtime and GNU x64 addon packages") + runtime = _package_input("liboliphaunt-wasix", runtime_version, runtime_rows[0]["name"], "//src/wasix/runtime:npm") + addon = _package_input("oliphaunt-wasix-napi", addon_version, addon_rows[0]["npm_package"], "//src/wasix/node-addon:npm_release_shipping_files") + _installed_test(name = name, args = bun_test_entrypoint_args(name), + runtime = runtime.archive, addon = addon.archive, + error = runtime.error or addon.error, + deno = "@deno_linux_x64//:deno", electron = "@electron_linux_x64//:electron", electron_runtime = ["@electron_linux_x64//:runtime_files"], + **kwargs) diff --git a/build_defs/wasix/sdk-installed.mts b/build_defs/wasix/sdk-installed.mts new file mode 100644 index 000000000..c757fe220 --- /dev/null +++ b/build_defs/wasix/sdk-installed.mts @@ -0,0 +1,233 @@ +import assert from 'node:assert/strict'; +import { mkdir, mkdtemp, readFile, rename, rm, writeFile } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { extractNpmPackage } from './browser/npm-archives.mts'; + +type Package = { name: string; version: string; archive: string }; +type Inputs = { packages: Package[] }; + +export async function stageWasixSdkPackages( + root: string, + { + sdk, + runtime, + addon, + extension, + packages, + }: { + sdk: string; + runtime: string; + addon: string; + extension: string; + packages: Package[]; + }, +) { + const modules = path.join(root, 'node_modules'); + const manifests = new Map(); + const stage = async (archive: string, expected?: Package) => { + const directory = path.join(root, `package-${manifests.size}`); + await extractNpmPackage(archive, directory); + const manifest = JSON.parse(await readFile(path.join(directory, 'package.json'), 'utf8')); + assert.match(manifest.name, /^(?:@[a-z0-9._-]+\/)?[a-z0-9._-]+$/u); + assert(Bun.semver.satisfies(manifest.version, manifest.version), 'invalid packed version'); + if (expected) { + assert.equal(manifest.name, expected.name, 'installed SDK package identity differs'); + assert.equal(manifest.version, expected.version, 'installed SDK package version differs'); + } + assert(!manifests.has(manifest.name), 'duplicate installed SDK package'); + const destination = path.join(modules, manifest.name); + await mkdir(path.dirname(destination), { recursive: true }); + // Keep actual package bytes intact; this is an ordinary private install tree. + await rename(directory, destination); + manifests.set(manifest.name, manifest); + return manifest; + }; + const candidate = await stage(sdk); + const core = await stage(runtime); + const native = await stage(addon); + const member = await stage(extension); + for (const pkg of packages) await stage(pkg.archive, pkg); + assert.equal(candidate.name, '@oliphaunt/wasix-ts'); + assert.equal(core.name, '@oliphaunt/liboliphaunt-wasix'); + assert.equal(native.name, '@oliphaunt/wasix-napi-linux-x64-gnu'); + assert.equal(member.name, '@oliphaunt/extension-pgtap-wasix'); + assert.equal(candidate.oliphaunt.runtimeProduct, 'liboliphaunt-wasix'); + assert.equal(core.version, candidate.oliphaunt.runtimeVersion, 'SDK runtime pin differs'); + assert.equal(native.version, candidate.oliphaunt.wasixNapiVersion, 'SDK addon pin differs'); + assert.equal(candidate.optionalDependencies[native.name], native.version); + assert.equal(native.oliphaunt.runtimeVersion, core.version, 'addon runtime pin differs'); + assert.equal(member.oliphaunt.wasixRuntimeVersion, core.version, 'pgTAP runtime pin differs'); + assert.deepEqual(native.os, ['linux']); + assert.deepEqual(native.cpu, ['x64']); + assert.deepEqual(native.libc, ['glibc']); + for (const manifest of manifests.values()) + for (const [name, requirement] of Object.entries(manifest.dependencies ?? {})) { + const dependency = manifests.get(name); + assert(dependency, `installed SDK omits declared dependency ${name}`); + assert( + typeof requirement === 'string' && Bun.semver.satisfies(dependency.version, requirement), + `installed SDK dependency ${name}@${dependency.version} does not satisfy ${requirement}`, + ); + } + await writeFile( + path.join(root, 'package.json'), + JSON.stringify({ + private: true, + type: 'module', + dependencies: Object.fromEntries( + [...manifests].map(([name, manifest]) => [name, manifest.version]), + ), + }), + ); + return { candidate: candidate.name, extension: member.name }; +} + +export async function runWasixSdkHostContracts({ + sdk, + runtime, + addon, + extension, + fixture, + pgwire, + node, + deno, + electron, + specification, + runfiles, +}: { + sdk: string; + runtime: string; + addon: string; + extension: string; + fixture: string; + pgwire: string; + node: string; + deno: string; + electron: string; + specification: string; + runfiles: string; +}) { + const inputs: Inputs = JSON.parse(await readFile(specification, 'utf8')); + const root = await mkdtemp(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'wasix-sdk-hosts-')); + try { + const installed = await stageWasixSdkPackages(root, { + sdk, + runtime, + addon, + extension, + packages: inputs.packages.map((pkg) => ({ + ...pkg, + archive: path.join(runfiles, pkg.archive), + })), + }); + const transpiler = new Bun.Transpiler({ loader: 'ts' }); + const assertions = transpiler.transformSync(await readFile(fixture, 'utf8')); + const wire = path.join(root, 'pgwire-client.mjs'); + await writeFile(wire, transpiler.transformSync(await readFile(pgwire, 'utf8'))); + const env = { + ...process.env, + NODE_OPTIONS: '', + NODE_PATH: '', + ELECTRON_RUN_AS_NODE: '1', + DENO_NO_UPDATE_CHECK: '1', + DENO_DIR: path.join(root, 'deno-cache'), + }; + for (const key of Object.keys(env)) + if ( + key !== 'OLIPHAUNT_WASM_AOT_VERIFY' && + /^(?:BUN_|RUNFILES|TEST_SRCDIR|OLIPHAUNT_|LIBOLIPHAUNT_|LD_|DYLD_)/u.test(key) + ) + delete env[key]; + for (const host of ['node', 'bun', 'deno', 'electron'] as const) { + const directory = path.join(root, host); + await mkdir(directory); + const entry = path.join(directory, 'verify.mjs'); + await writeFile(entry, assertions); + const condition = host === 'electron' ? 'node' : host; + await writeFile( + path.join(directory, 'fixture.json'), + JSON.stringify({ + ...installed, + runtime: host, + runtimeName: + host === 'electron' + ? 'Electron' + : host === 'deno' + ? 'Deno' + : host === 'bun' + ? 'Bun' + : 'Node', + storageCondition: condition, + packageOnly: false, + expectedEntrypoint: `index.${condition}.js`, + expectedDirectEntrypoint: 'direct.node.js', + expectedWorkerEntrypoint: `worker-entry.${condition}.js`, + expectedServerEntrypoint: 'server.node.js', + pgwireClientUrl: pathToFileURL(wire).href, + }), + ); + const command = + host === 'node' + ? [node, entry] + : host === 'bun' + ? [process.execPath, '--no-install', '--no-env-file', entry] + : host === 'deno' + ? [deno, 'run', '--no-config', '--node-modules-dir=manual', '--allow-all', entry] + : [electron, entry]; + const child = Bun.spawn(command, { + cwd: directory, + env, + stdout: 'pipe', + stderr: 'pipe', + timeout: 180_000, + killSignal: 'SIGKILL', + }); + const [status, stdout, stderr] = await Promise.all([ + child.exited, + new Response(child.stdout).text(), + new Response(child.stderr).text(), + ]); + assert.equal(status, 0, `${host} original public SDK contract failed\n${stdout}\n${stderr}`); + console.log( + `${host} original public SDK actor/direct/worker/server contract passed\n${stdout}`, + ); + } + } finally { + await rm(root, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + const [sdk, runtime, addon, extension, fixture, pgwire, node, deno, electron, specification] = + process.argv.slice(2); + const runfiles = process.env.OLIPHAUNT_BAZEL_RUNFILES; + assert( + sdk && + runtime && + addon && + extension && + fixture && + pgwire && + node && + deno && + electron && + specification && + runfiles, + 'WASIX SDK contracts require the complete declared package/tool/fixture inputs', + ); + await runWasixSdkHostContracts({ + sdk, + runtime, + addon, + extension, + fixture, + pgwire, + node, + deno, + electron, + specification, + runfiles, + }); +} diff --git a/build_defs/wasix/tool-metadata.mts b/build_defs/wasix/tool-metadata.mts new file mode 100644 index 000000000..e6035363d --- /dev/null +++ b/build_defs/wasix/tool-metadata.mts @@ -0,0 +1,142 @@ +/** Acquisition-only projection of the existing Wasmer LLVM host pins. */ +import { existsSync, readFileSync, statSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { parseArgs } from 'node:util'; +import { DESKTOP_TARGETS } from '../../tools/release/release-artifact-targets.mts'; + +interface HostPin { + triple: string; + wasixLlvmUrl?: string; + wasixLlvmSha256?: string; + wasixLlvmBytes?: number; +} + +export function llvmPins(hosts: Record, llvmSysVersion: string) { + const encoded = Number(llvmSysVersion.split('.')[0]); + if (!Number.isSafeInteger(encoded) || encoded < 100) throw new Error('invalid llvm-sys version'); + const version = `${Math.floor(encoded / 10)}.${encoded % 10}`; + const pins: Record = {}; + const unavailable: string[] = []; + for (const [host, facts] of Object.entries(hosts).sort(([a], [b]) => a.localeCompare(b))) { + if (facts.wasixLlvmUrl === undefined) { + if (facts.wasixLlvmSha256 !== undefined || facts.wasixLlvmBytes !== undefined) { + throw new Error(`incomplete LLVM pin: ${host}`); + } + unavailable.push(host); + continue; + } + if ( + !facts.wasixLlvmUrl.startsWith( + 'https://github.com/wasmerio/llvm-custom-builds/releases/download/', + ) || + !/^[0-9a-f]{64}$/u.test(facts.wasixLlvmSha256 ?? '') || + !Number.isSafeInteger(facts.wasixLlvmBytes) || + (facts.wasixLlvmBytes ?? 0) <= 0 || + (facts.wasixLlvmBytes ?? 0) > 2_147_483_648 + ) + throw new Error(`invalid LLVM pin: ${host}`); + pins[host] = { + triple: facts.triple, + url: facts.wasixLlvmUrl, + sha256: facts.wasixLlvmSha256 as string, + bytes: facts.wasixLlvmBytes as number, + }; + } + return { version, llvm_sys_abi: encoded, hosts: pins, unavailable }; +} + +interface CargoPackage { + name: string; + version: string; + dependencies?: string[]; +} + +export function llvmSysVersion(packages: CargoPackage[], wasmerVersion: string): string { + const compiler = packages.find( + (entry) => entry.name === 'wasmer-compiler-llvm' && entry.version === wasmerVersion, + ); + if (!compiler) throw new Error('locked Wasmer compiler is missing'); + const pending = [compiler]; + const visited = new Set(); + const versions = new Set(); + for (let index = 0; index < pending.length; index += 1) { + const entry = pending[index]; + if (visited.has(entry)) continue; + visited.add(entry); + if (entry.name === 'llvm-sys') versions.add(entry.version); + for (const dependency of entry.dependencies ?? []) { + const [name, version] = dependency.split(' '); + const candidates = packages.filter( + (item) => item.name === name && (version === undefined || item.version === version), + ); + if (candidates.length !== 1) throw new Error(`ambiguous locked dependency: ${dependency}`); + pending.push(candidates[0]); + } + } + if (versions.size !== 1) throw new Error('locked Wasmer compiler requires one LLVM ABI'); + return [...versions][0]; +} + +if (import.meta.main) { + const { values } = parseArgs({ + options: { root: { type: 'string' }, 'output-dir': { type: 'string' } }, + }); + if (!values.root || !values['output-dir']) + throw new Error('--root and --output-dir are required'); + const root = path.resolve(values.root); + const observed: Record = {}; + const read = (file: string): string => { + const absolute = path.resolve(root, file); + const relative = path.relative(root, absolute).split(path.sep).join('/'); + if (relative.startsWith('../') || path.isAbsolute(relative)) + throw new Error('metadata input escapes workspace'); + const source = readFileSync(absolute, 'utf8'); + observed[relative] = source; + return source; + }; + const pending = [path.resolve(import.meta.filename)]; + const visited = new Set(); + const scanner = new Bun.Transpiler({ loader: 'ts' }); + for (let index = 0; index < pending.length; index += 1) { + const module = pending[index]; + if (visited.has(module)) continue; + visited.add(module); + for (const entry of scanner.scanImports(read(module).replace(/^#![^\r\n]*/u, ''))) { + if (entry.path.startsWith('node:') || entry.path === 'bun') continue; + if (!entry.path.startsWith('.')) + throw new Error(`undeclared metadata dependency: ${entry.path}`); + let dependency = path.resolve(path.dirname(module), entry.path); + if (!existsSync(dependency)) { + const authored = dependency.replace(/\.js$/u, '.ts'); + if (existsSync(authored)) dependency = authored; + } + if (!existsSync(dependency) || !statSync(dependency).isFile()) + throw new Error(`missing metadata dependency: ${dependency}`); + pending.push(dependency); + } + } + const toolchain = Bun.TOML.parse(read('src/wasix/runtime/toolchain.toml')) as { + toolchain: { wasmer: string }; + }; + const lock = Bun.TOML.parse(read('Cargo.lock')) as { package: CargoPackage[] }; + const projection = llvmPins( + DESKTOP_TARGETS, + llvmSysVersion(lock.package, toolchain.toolchain.wasmer), + ); + writeFileSync( + path.join(values['output-dir'], 'llvm.json'), + `${JSON.stringify(projection, null, 2)}\n`, + ); + writeFileSync( + path.join(values['output-dir'], 'targets.bzl'), + `# Derived from the canonical DESKTOP_TARGETS reader.\nWASIX_AOT_TARGETS = ${JSON.stringify( + Object.fromEntries(Object.entries(projection.hosts).map(([id, pin]) => [id, pin.triple])), + null, + 2, + )}\n`, + ); + writeFileSync( + path.join(values['output-dir'], '.metadata-inputs.json'), + `${JSON.stringify(observed)}\n`, + ); +} diff --git a/build_defs/wasix/tool-metadata.test.mts b/build_defs/wasix/tool-metadata.test.mts new file mode 100644 index 000000000..d6d884225 --- /dev/null +++ b/build_defs/wasix/tool-metadata.test.mts @@ -0,0 +1,58 @@ +import { expect, test } from 'bun:test'; +import { DESKTOP_TARGETS } from '../../tools/release/release-artifact-targets.mts'; +import { llvmPins, llvmSysVersion } from './tool-metadata.mts'; + +test('LLVM projection preserves canonical host pins without product metadata', () => { + const result = llvmPins(DESKTOP_TARGETS, '221.0.0'); + const canonical = DESKTOP_TARGETS['linux-x64-gnu']; + expect(result.hosts['linux-x64-gnu']).toEqual({ + triple: canonical.triple, + url: canonical.wasixLlvmUrl, + sha256: canonical.wasixLlvmSha256, + bytes: canonical.wasixLlvmBytes, + }); + expect(result.version).toBe('22.1'); + expect(result.llvm_sys_abi).toBe(221); + expect(result.unavailable).toEqual(['macos-x64']); + expect(JSON.stringify(result)).not.toContain('wasixNapiPackage'); +}); + +test('LLVM projection rejects incomplete or unsafe acquisition pins', () => { + const canonical = DESKTOP_TARGETS['linux-x64-gnu']; + for (const bad of [ + { ...canonical, wasixLlvmUrl: undefined }, + { ...canonical, wasixLlvmSha256: 'bad' }, + { ...canonical, wasixLlvmBytes: 0 }, + { ...canonical, wasixLlvmUrl: 'http://example.invalid/llvm.tar.xz' }, + ]) + expect(() => llvmPins({ host: bad }, '221.0.0')).toThrow(); +}); + +test('LLVM ABI comes from the selected locked Wasmer compiler dependency', () => { + const compiler = { + name: 'wasmer-compiler-llvm', + version: 'fixture', + dependencies: ['llvm-sys 221.0.0'], + }; + const llvm = { name: 'llvm-sys', version: '221.0.0' }; + expect(llvmSysVersion([compiler, llvm, { ...llvm, version: '180.0.0' }], 'fixture')).toBe( + llvm.version, + ); + expect( + llvmSysVersion( + [ + { ...compiler, dependencies: ['inkwell'] }, + { name: 'inkwell', version: 'fixture', dependencies: ['llvm-sys 221.0.0'] }, + llvm, + ], + 'fixture', + ), + ).toBe(llvm.version); + expect(() => llvmSysVersion([compiler], 'fixture')).toThrow(); + expect(() => + llvmSysVersion( + [{ ...compiler, dependencies: ['llvm-sys'] }, llvm, { ...llvm, version: '180.0.0' }], + 'fixture', + ), + ).toThrow('ambiguous'); +}); diff --git a/build_defs/wasix/toolchain.BUILD.bazel b/build_defs/wasix/toolchain.BUILD.bazel new file mode 100644 index 000000000..f444503c4 --- /dev/null +++ b/build_defs/wasix/toolchain.BUILD.bazel @@ -0,0 +1,38 @@ +load("@rules_cc//cc:defs.bzl", "cc_toolchain") +load("@oliphaunt//build_defs/wasix:toolchain.bzl", "wasix_cc_toolchain_config") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["ASSETS.tsv"] + glob(["bin/*", "llvm/bin/*", "binaryen/bin/*"])) + +filegroup(name = "empty") +filegroup(name = "compiler_files", srcs = glob(["bin/*", "driver/*", "llvm/**", "sysroot/**"])) +filegroup(name = "llvm_files", srcs = glob(["llvm/**"])) +filegroup(name = "linker_files", srcs = [":llvm_files"] + glob(["sysroot/sysroot-exnref-ehpic/**"])) +filegroup(name = "binaryen_files", srcs = glob(["binaryen/**"])) +# ASSETS.tsv records all supported source pins for inspection. Unused sysroot +# identities and the separate optimizer are not C compiler action inputs. +filegroup(name = "all_files", srcs = [":compiler_files"]) + +wasix_cc_toolchain_config( + name = "config", + compiler = "bin/wasixcc", + llvm_compiler = "llvm/bin/clang", + optimizer = "binaryen/bin/wasm-opt", + sysroot_header = "sysroot/sysroot-exnref-ehpic/include/stdio.h", +) + +cc_toolchain( + name = "compiler", + toolchain_identifier = "oliphaunt-wasix-linux-x86_64", + toolchain_config = ":config", + all_files = ":all_files", + ar_files = ":compiler_files", + as_files = ":compiler_files", + compiler_files = ":compiler_files", + dwp_files = ":empty", + linker_files = ":compiler_files", + objcopy_files = ":empty", + strip_files = ":empty", + supports_param_files = 0, +) diff --git a/build_defs/wasix/toolchain.bzl b/build_defs/wasix/toolchain.bzl new file mode 100644 index 000000000..9f0d066c3 --- /dev/null +++ b/build_defs/wasix/toolchain.bzl @@ -0,0 +1,65 @@ +"""Standard C/C++ toolchain using the pinned WASIX compiler driver.""" + +load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES") +load("@rules_cc//cc:cc_toolchain_config_lib.bzl", "artifact_name_pattern", "env_entry", "env_set", "feature", "flag_group", "flag_set", "tool_path") +load("@rules_cc//cc/common:cc_common.bzl", "cc_common") +load("@rules_cc//cc/toolchains:cc_toolchain_config_info.bzl", "CcToolchainConfigInfo") + +_COMPILE = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.linkstamp_compile] +_LINK = [ACTION_NAMES.cpp_link_executable, ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library] + +def _wasix_cc_toolchain_config_impl(ctx): + llvm = ctx.file.llvm_compiler.dirname.rsplit("/", 1)[0] + binaryen = ctx.file.optimizer.dirname.rsplit("/", 1)[0] + sysroot = ctx.file.sysroot_header.dirname.rsplit("/", 1)[0] + environment = [ + env_entry(key = "WASIXCC_LLVM_LOCATION", value = llvm), + env_entry(key = "WASIXCC_BINARYEN_LOCATION", value = binaryen), + env_entry(key = "WASIXCC_SYSROOT_PREFIX", value = sysroot.rsplit("/", 1)[0]), + env_entry(key = "WASIXCC_RUN_WASM_OPT", value = "no"), + ] + return [cc_common.create_cc_toolchain_config_info( + ctx = ctx, + toolchain_identifier = "oliphaunt-wasix-linux-x86_64", + host_system_name = "x86_64-unknown-linux-gnu", + target_system_name = "wasm32-wasix", + target_cpu = "wasm32", + target_libc = "wasix", + compiler = "wasixcc", + abi_version = "wasm32", + abi_libc_version = "wasix-2026-03-02.1", + builtin_sysroot = sysroot, + cxx_builtin_include_directories = [sysroot + "/include", llvm + "/lib/clang/21/include"], + features = [ + feature(name = "supports_pic", enabled = True), + feature(name = "prefer_pic_for_opt_binaries", enabled = True), + feature(name = "supports_dynamic_linker", enabled = True), + feature(name = "wasix_environment", enabled = True, env_sets = [env_set(actions = _COMPILE + _LINK + [ACTION_NAMES.cpp_link_static_library], env_entries = environment)]), + feature(name = "wasix_compile_flags", enabled = True, flag_sets = [ + flag_set(actions = _COMPILE + _LINK, flag_groups = [flag_group(flags = ["-sWASM_EXCEPTIONS=yes", "-sPIC=yes"])]), + flag_set(actions = _COMPILE, flag_groups = [flag_group(flags = ["-Wno-unused-command-line-argument", "-no-canonical-prefixes", "-resource-dir=" + llvm + "/lib/clang/21"])]), + ]), + ], + artifact_name_patterns = [artifact_name_pattern(category_name = "dynamic_library", prefix = "", extension = ".wasm")], + tool_paths = [ + tool_path(name = "gcc", path = "bin/wasixcc"), + tool_path(name = "cpp", path = "bin/wasixcc"), + tool_path(name = "ar", path = "bin/wasixar"), + tool_path(name = "ld", path = "bin/wasixld"), + tool_path(name = "nm", path = "bin/wasixnm"), + tool_path(name = "objdump", path = "llvm/bin/llvm-objdump"), + tool_path(name = "strip", path = "llvm/bin/llvm-strip"), + tool_path(name = "gcov", path = "llvm/bin/llvm-cov"), + ], + )] + +wasix_cc_toolchain_config = rule( + implementation = _wasix_cc_toolchain_config_impl, + attrs = { + "compiler": attr.label(allow_single_file = True, mandatory = True), + "llvm_compiler": attr.label(allow_single_file = True, mandatory = True), + "optimizer": attr.label(allow_single_file = True, mandatory = True), + "sysroot_header": attr.label(allow_single_file = True, mandatory = True), + }, + provides = [CcToolchainConfigInfo], +) diff --git a/build_defs/wasix/tools-carriers.bzl b/build_defs/wasix/tools-carriers.bzl new file mode 100644 index 000000000..093b1e2df --- /dev/null +++ b/build_defs/wasix/tools-carriers.bzl @@ -0,0 +1,140 @@ +"""Canonical public WASIX tools carriers from their independent command graph.""" + +load("@oliphaunt_metadata//:metadata.bzl", "PRODUCTS", "PUBLICATION_CARRIERS", "WASIX_ARTIFACTS") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") +load("//build_defs/native/carriers:defs.bzl", "native_checksum_manifest") +load("//build_defs/release:identity.bzl", "ReleaseIdentityInfo") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") +load(":cargo.bzl", "RUNTIME_CARGO_HELPERS") +load(":npm.bzl", "RUNTIME_NPM_NOTICES") + +TOOLS_CARRIER_HELPERS = RUNTIME_CARGO_HELPERS + [ + "//build_defs/wasix:cargo.mts", + "//build_defs/wasix:package.mts", + "//src/wasix/postgres-tools:tools/package-assets.mts", + "//src/wasix/postgres-tools:tools/wasix-tools-aot-npm.mts", + "//src/wasix/postgres-tools:tools/wasix-tools-npm-carrier.mts", + "//src/wasix/runtime:tools/package-release-assets.mts", + "//:tools/packaging/npm-trusted-publishing.mts", +] + +def _source_map(entries, inputs): + result = {} + for target, destination in entries.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1 or files[0].is_directory or destination in result: + fail("WASIX tools source must be one unique declared file") + result[destination] = files[0].path + inputs += files + return result + +def _tools_carriers_impl(ctx): + product = ctx.attr.product[ReleaseIdentityInfo] + runtime = ctx.attr.runtime_product[ReleaseIdentityInfo] + if product.id != "postgres-tools-wasix" or runtime.id != "liboliphaunt-wasix": + fail("WASIX tools envelopes require their canonical product and runtime owners") + payload = ctx.attr.payload[DefaultInfo].files.to_list() + if len(payload) != 1 or not payload[0].is_directory: + fail("WASIX tools envelopes require their actual declared payload tree") + artifact = json.decode(ctx.attr.artifact) + prefix = ctx.label.name + "/" + github = ctx.actions.declare_file(prefix + artifact["asset"].replace("{version}", product.version)) + npm = ctx.actions.declare_file(prefix + ctx.attr.npm_package.replace("@", "").replace("/", "-") + "-" + product.version + ".tgz") + cargo = ctx.actions.declare_file(prefix + ctx.attr.cargo_package + "-" + product.version + ".crate") + inputs = payload + [ctx.file.toolchain, ctx.file.postgres_source, ctx.file.postgres_series, ctx.file.icu_source] + ctx.files.patches + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode({ + "version": product.version, + "runtimeVersion": runtime.version, + "artifact": artifact, + "cargoPackage": ctx.attr.cargo_package, + "npmPackage": ctx.attr.npm_package, + "payload": payload[0].path, + "sources": _source_map(ctx.attr.sources, inputs), + "notices": _source_map(ctx.attr.notices, inputs), + "toolchain": ctx.file.toolchain.path, + "postgresSource": ctx.file.postgres_source.path, + "postgresSeries": ctx.file.postgres_series.path, + "patches": {file.short_path: file.path for file in ctx.files.patches}, + "icuSource": ctx.file.icu_source.path, + "outputs": {"github": github.path, "npm": npm.path, "cargo": cargo.path}, + })) + args = ctx.actions.args() + args.add_all(["--spec", spec]) + leaves = ctx.actions.args() + leaves.add_all(payload, expand_directories = True) + leaves.use_param_file("--payload-files=%s", use_always = True) + leaves.set_param_file_format("multiline") + bun_file_action(ctx, ctx.file._packager, arguments = [args, leaves], inputs = depset(inputs + [spec]), + source_files = ctx.files._helpers, outputs = [github, npm, cargo], mnemonic = "WasixToolsFinalEnvelopes") + return [DefaultInfo(files = depset([github, npm, cargo])), + OutputGroupInfo(github = depset([github]), npm = depset([npm]), cargo = depset([cargo]))] + +_tools_carriers = rule( + implementation = _tools_carriers_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = { + "payload": attr.label(mandatory = True), + "product": attr.label(default = "@oliphaunt_metadata//:product_postgres-tools-wasix", providers = [ReleaseIdentityInfo]), + "runtime_product": attr.label(default = "@oliphaunt_metadata//:product_liboliphaunt-wasix", providers = [ReleaseIdentityInfo]), + "artifact": attr.string(mandatory = True), + "cargo_package": attr.string(mandatory = True), + "npm_package": attr.string(mandatory = True), + "sources": attr.label_keyed_string_dict(allow_files = True, mandatory = True), + "notices": attr.label_keyed_string_dict(default = dict(RUNTIME_NPM_NOTICES, **{"//src/wasix/postgres-tools:npm/native.mts": "src/wasix/postgres-tools/npm/native.mts"}), allow_files = True), + "patches": attr.label_list(allow_files = [".patch"], mandatory = True), + "toolchain": attr.label(default = "//src/wasix/runtime:toolchain.toml", allow_single_file = True), + "postgres_source": attr.label(default = "//src/third-party/postgres:source.toml", allow_single_file = True), + "postgres_series": attr.label(default = "//src/wasix/runtime:postgres/series", allow_single_file = True), + "icu_source": attr.label(default = "//src/third-party/icu:source.toml", allow_single_file = True), + "_packager": attr.label(default = "//build_defs/wasix:tools-carriers.mts", allow_single_file = True), + "_helpers": attr.label_list(default = TOOLS_CARRIER_HELPERS, allow_files = True), + }, +) + +def wasix_tools_carriers(patches, qualification = []): + owner = "@oliphaunt_metadata//:product_postgres-tools-wasix" + rows = [row for row in WASIX_ARTIFACTS if row["product"] == "postgres-tools-wasix" and row["kind"] != "checksums"] + carriers = [row for row in PUBLICATION_CARRIERS if row["product"] == "postgres-tools-wasix"] + packages, archives, github_groups = ["//src/wasix/postgres-tools/ts:shipping_package"], [], [] + for row in rows: + portable = row["target"] == "portable" + name = row["target"].replace("-", "_") + cargo_rows = [carrier for carrier in carriers if carrier["ecosystem"] == "cargo" and carrier["target"] == row.get("triple")] + npm_name = "@oliphaunt/liboliphaunt-wasix-tools" if portable else row["npm_package"] + npm_rows = [carrier for carrier in carriers if carrier["ecosystem"] == "npm" and carrier["name"] == npm_name] + if len(cargo_rows) != 1 or len(npm_rows) != 1: + fail("WASIX tools envelope has no unique canonical carrier identities") + template = "crates/" + ("tools" if portable else "aot/" + row["triple"]) + "/" + sources = native.glob([template + pattern for pattern in ["Cargo.toml", "README.md", "build.rs", "build-support.rs", "src/**"]]) + native.filegroup(name = name + "_package_sources", srcs = sources) + payload = ":portable_payload" if portable else ":aot_" + name + "_payload" + _tools_carriers(name = "carriers_" + name, payload = payload, artifact = json.encode(row), + cargo_package = cargo_rows[0]["name"], npm_package = npm_name, patches = patches, + sources = {source: source[len(template):] for source in sources}) + for ecosystem in ["github", "npm", "cargo"]: + group = name + "_" + ecosystem + if ecosystem == "github": + private = group + "_input" + native.filegroup(name = private, srcs = [":carriers_" + name], output_group = ecosystem) + archives.append(":" + private) + github_groups.append((group, row["asset"].replace("{version}", PRODUCTS["postgres-tools-wasix"]["version"]))) + else: + native.filegroup(name = group, srcs = [":carriers_" + name], output_group = ecosystem) + carrier = cargo_rows[0] if ecosystem == "cargo" else npm_rows[0] + shipping_package(name = group + "_shipping", owner = owner, artifacts = [":" + group], ecosystem = ecosystem, + package_name = row["asset"].replace("{version}", PRODUCTS["postgres-tools-wasix"]["version"]) if ecosystem == "github" else carrier["name"], + configuration = row["target"] if ecosystem == "github" else (carrier["target"] or row["target"]), role = "github-release-asset" if ecosystem == "github" else carrier["role"], suppliers = "//build_defs/release:no_suppliers") + packages.append(":" + group + "_shipping") + native_checksum_manifest(name = "assembled_release_assets", product = "postgres-tools-wasix", archives = archives, artifact_rows = WASIX_ARTIFACTS, assemble = True) + for group, asset in github_groups: + native.filegroup(name = group, srcs = [":assembled_release_assets"], output_group = asset) + native.filegroup(name = "checksums", srcs = [":assembled_release_assets"], output_group = "checksums") + checksum = [row for row in WASIX_ARTIFACTS if row["product"] == "postgres-tools-wasix" and row["kind"] == "checksums"] + shipping_package(name = "checksums_shipping", owner = owner, artifacts = [":checksums"], ecosystem = "github", + package_name = checksum[0]["asset"].replace("{version}", PRODUCTS["postgres-tools-wasix"]["version"]), + configuration = "portable", role = "github-release-asset", suppliers = "//build_defs/release:no_suppliers") + packages.append(":checksums_shipping") + native.filegroup(name = "release_assets", srcs = [":assembled_release_assets"]) + native.filegroup(name = "carriers", srcs = [":carriers_" + row["target"].replace("-", "_") for row in rows] + ["//src/wasix/postgres-tools/ts:npm"]) + shipping_export(name = "shipping_export", packages = packages, qualification = qualification, testonly = True) diff --git a/build_defs/wasix/tools-carriers.mts b/build_defs/wasix/tools-carriers.mts new file mode 100644 index 000000000..d2c141d7f --- /dev/null +++ b/build_defs/wasix/tools-carriers.mts @@ -0,0 +1,161 @@ +/** Final tools envelopes from one declared portable or target AOT payload. */ +import { copyFileSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { parseArgs } from 'node:util'; +import { + validatePortableToolsPayload, + validateToolsAotPayload, +} from '../../src/wasix/postgres-tools/tools/package-assets.mts'; +import { packWasixToolsAotNpmCarrier } from '../../src/wasix/postgres-tools/tools/wasix-tools-aot-npm.mts'; +import { packWasixToolsNpmCarrier } from '../../src/wasix/postgres-tools/tools/wasix-tools-npm-carrier.mts'; +import { + AOT_TARGET_TRIPLES, + TOOLS_AOT_PACKAGES, + TOOLS_PACKAGE, +} from '../../src/wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; +import { createDeterministicTar } from '../../tools/packaging/cargo-source-package.mts'; +import { canonicalGzipSync } from '../../tools/packaging/portable-archive.mts'; +import { stageReleaseNotices } from '../../tools/packaging/release-notices.mts'; +import { packageSpec } from '../../tools/packaging/wasix-cargo-payload.mts'; +import { copyDeclaredSources, stageDeclaredPayload } from './cargo.mts'; +import { type RuntimePayloadSpec, sourceFacts } from './package.mts'; + +export interface ToolsCarrierSpec + extends Pick { + version: string; + runtimeVersion: string; + artifact: { + target: string; + asset: string; + triple?: string; + npm_package?: string; + npm_os?: string; + npm_cpu?: string; + npm_libc?: string; + }; + cargoPackage: string; + npmPackage: string; + payload: string; + payloadFiles: string[]; + sources: Record; + notices: Record; + toolchain: string; + outputs: { github: string; npm: string; cargo: string }; +} + +export async function packageToolsCarriers(spec: ToolsCarrierSpec): Promise { + const portable = spec.artifact.target === 'portable'; + if ( + spec.cargoPackage !== (portable ? TOOLS_PACKAGE : TOOLS_AOT_PACKAGES[spec.artifact.target]) || + (!portable && spec.artifact.triple !== AOT_TARGET_TRIPLES[spec.artifact.target]) || + spec.npmPackage !== + (portable ? '@oliphaunt/liboliphaunt-wasix-tools' : spec.artifact.npm_package) + ) + throw new Error('WASIX tools carrier differs from its canonical target identity'); + const manifest = Bun.TOML.parse(readFileSync(spec.sources['Cargo.toml'], 'utf8')); + if (manifest.package?.name !== spec.cargoPackage) + throw new Error('Declared WASIX tools Cargo template has the wrong package identity'); + const asset = spec.artifact.asset.replaceAll('{version}', spec.version); + const expected = { + github: asset, + npm: `${spec.npmPackage.replace('@', '').replace('/', '-')}-${spec.version}.tgz`, + cargo: `${spec.cargoPackage}-${spec.version}.crate`, + }; + for (const [kind, file] of Object.entries(spec.outputs)) { + if (path.basename(file) !== expected[kind]) + throw new Error(`WASIX tools ${kind} output has the wrong canonical filename`); + mkdirSync(path.dirname(file), { recursive: true }); + } + const scratch = mkdtempSync( + path.join(path.dirname(path.resolve(spec.outputs.github)), '.wasix-tools-'), + ); + try { + const templateDir = path.join(scratch, 'template'); + const sourceRoot = path.join(scratch, 'notices'); + copyDeclaredSources(spec.sources, templateDir); + copyDeclaredSources(spec.notices, sourceRoot); + copyDeclaredSources({ 'src/wasix/runtime/toolchain.toml': spec.toolchain }, sourceRoot); + const payloadRoot = path.join(scratch, 'payload'); + stageDeclaredPayload(spec, payloadRoot); + const { source_fingerprint: sourceFingerprint } = await sourceFacts(spec); + if (portable) { + validatePortableToolsPayload(payloadRoot, spec.version, { + runtimeVersion: spec.runtimeVersion, + sourceFingerprint, + sourceRoot, + }); + } else { + stageReleaseNotices(payloadRoot, { profile: 'wasix-aot', sourceRoot }); + validateToolsAotPayload(payloadRoot, spec.artifact.triple, { sourceFingerprint, sourceRoot }); + } + const github = path.join(scratch, asset); + writeFileSync( + github, + canonicalGzipSync( + createDeterministicTar(payloadRoot, '.', { + fail: (message) => { + throw new Error(message); + }, + fixedFileMode: 0o644, + }), + ), + ); + const npm = portable + ? packWasixToolsNpmCarrier({ + version: spec.version, + portableReleaseArchive: github, + packageDir: path.join(scratch, 'npm-source'), + tarballRoot: path.join(scratch, 'npm'), + sourceRoot, + }).tarball + : packWasixToolsAotNpmCarrier({ + version: spec.version, + assetDir: scratch, + target: { + ...spec.artifact, + npmPackage: spec.npmPackage, + npmOs: spec.artifact.npm_os, + npmCpu: spec.artifact.npm_cpu, + npmLibc: spec.artifact.npm_libc, + }, + workRoot: scratch, + sourceRoot, + sourceFingerprint, + }); + const cargo = packageSpec( + { + name: spec.cargoPackage, + target: spec.artifact.triple ?? 'portable', + kind: portable ? 'wasix-tools' : 'wasix-tools-aot', + templateDir, + payloadRoot, + payloadDirName: portable ? 'payload' : 'artifacts', + }, + { + version: spec.version, + sourceRoot: path.join(scratch, 'cargo-sources'), + outputDir: scratch, + cargoTargetDir: path.join(scratch, 'cargo-target'), + noticeSourceRoot: sourceRoot, + }, + ).cratePath; + copyFileSync(github, spec.outputs.github); + copyFileSync(npm, spec.outputs.npm); + copyFileSync(cargo, spec.outputs.cargo); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + const { values } = parseArgs({ + options: { spec: { type: 'string' }, 'payload-files': { type: 'string' } }, + strict: true, + }); + if (!values.spec || !values['payload-files']) + throw new Error('usage: tools-carriers.mts --spec --payload-files '); + await packageToolsCarriers({ + ...JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(readFileSync(values.spec))), + payloadFiles: readFileSync(values['payload-files'], 'utf8').trimEnd().split(/\r?\n/u), + }); +} diff --git a/build_defs/wasix/tools-carriers.test.mts b/build_defs/wasix/tools-carriers.test.mts new file mode 100644 index 000000000..01f7917d9 --- /dev/null +++ b/build_defs/wasix/tools-carriers.test.mts @@ -0,0 +1,420 @@ +import { afterEach, expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { chmod, mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'; +import os from 'node:os'; +import path from 'node:path'; +import { zstdCompressSync, zstdDecompressSync } from 'node:zlib'; +import { canonicalWasixAotMetadata } from '../../src/wasix/runtime/tools/wasix-aot-manifest.mts'; +import { + AOT_TARGET_TRIPLES, + TOOLS_AOT_PACKAGES, + TOOLS_PACKAGE, +} from '../../src/wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; +import { readPortableArchiveEntries } from '../../tools/packaging/portable-archive.mts'; +import { releaseNoticeRows, stageReleaseNotices } from '../../tools/packaging/release-notices.mts'; +import { sourceFacts } from './package.mts'; +import { packageToolsCarriers, type ToolsCarrierSpec } from './tools-carriers.mts'; + +const roots: string[] = []; +afterEach(async () => { + await Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true }))); +}); +const sha = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +const platforms = { + 'linux-arm64-gnu': { suffix: 'linux-arm64-gnu', os: 'linux', cpu: 'arm64', libc: 'glibc' }, + 'linux-x64-gnu': { suffix: 'linux-x64-gnu', os: 'linux', cpu: 'x64', libc: 'glibc' }, + 'macos-arm64': { suffix: 'darwin-arm64', os: 'darwin', cpu: 'arm64' }, + 'windows-x64-msvc': { suffix: 'win32-x64-msvc', os: 'win32', cpu: 'x64' }, +}; +type Target = 'portable' | keyof typeof platforms; + +async function fixture(target: Target = 'portable', version = '7.8.9', runtimeVersion = '3.4.5') { + const root = await mkdtemp(path.join(os.tmpdir(), 'oliphaunt-wasix-tools-carriers-')); + roots.push(root); + const payload = path.join(root, 'payload'); + await mkdir(payload); + const portable = target === 'portable'; + const platform = portable ? undefined : platforms[target]; + const cargoPackage = portable ? TOOLS_PACKAGE : TOOLS_AOT_PACKAGES[target]; + const npmPackage = `@oliphaunt/liboliphaunt-wasix-tools${platform ? `-${platform.suffix}` : ''}`; + const template = `src/wasix/postgres-tools/crates/${portable ? 'tools' : `aot/${AOT_TARGET_TRIPLES[target]}`}`; + const sources = Object.fromEntries( + ['Cargo.toml', 'README.md', 'build.rs', 'build-support.rs', 'src/lib.rs'].map((file) => [ + file, + path.resolve(template, file), + ]), + ); + const notices = Object.fromEntries( + [ + 'LICENSE', + 'THIRD_PARTY_NOTICES.md', + 'src/wasix/sdks/rust/THIRD_PARTY_NOTICES.md', + 'src/third-party/postgres/COPYRIGHT', + 'src/third-party/postgres/source.toml', + 'src/third-party/icu/LICENSE', + 'src/third-party/icu/source.toml', + 'src/wasix/postgres-tools/npm/native.mts', + ].map((file) => [file, path.resolve(file)]), + ); + const postgresSeries = path.resolve('src/wasix/runtime/postgres/series'); + const patchNames = (await readFile(postgresSeries, 'utf8')) + .split(/\r?\n/u) + .map((line) => line.trim()) + .filter((line) => line && !line.startsWith('#')); + const facts = { + postgresSource: path.resolve('src/third-party/postgres/source.toml'), + postgresSeries, + patches: Object.fromEntries(patchNames.map((file) => [file, path.resolve(file)])), + icuSource: path.resolve('src/third-party/icu/source.toml'), + }; + const sourceFingerprint = (await sourceFacts(facts)).source_fingerprint; + const bytesByPath = new Map(); + const modules = [0, 1].map((index) => + Buffer.concat([Buffer.from('\0asm\x01\0\0\0'), Buffer.from([0, 3, 1, 120, index])]), + ); + let manifest: any; + if (portable) { + manifest = { + schema: 'postgres-tools-wasix-portable-v1', + version, + runtimeVersion, + sourceFingerprint, + }; + for (const [index, key] of ['pgDump', 'psql'].entries()) { + const name = index === 0 ? 'pg_dump' : 'psql'; + const file = `bin/${name}.wasix.wasm`; + bytesByPath.set(file, modules[index]); + manifest[key] = { + name, + path: file, + sha256: sha(modules[index]), + size: modules[index].length, + }; + } + stageReleaseNotices(payload, { profile: 'wasix-tools' }); + for (const row of releaseNoticeRows({ profile: 'wasix-tools' })) + bytesByPath.set(row.member, await readFile(path.join(payload, row.member))); + } else { + const canonical = canonicalWasixAotMetadata(); + manifest = { + 'format-version': 1, + 'source-lane': canonical.sourceLane, + engine: canonical.engine, + 'wasmer-version': canonical.wasmerVersion, + 'wasmer-wasix-version': canonical.wasmerWasixVersion, + 'target-triple': AOT_TARGET_TRIPLES[target], + 'source-fingerprint': sourceFingerprint, + artifacts: ['pg_dump', 'psql'].map((name, index) => { + // Format/hash fixtures only; these bytes make no executable AOT claim. + const raw = Buffer.from(`independent ${target} serialized-tool fixture ${name}`); + const bytes = zstdCompressSync(raw); + const file = `tools/${name}.bin.zst`; + bytesByPath.set(file, bytes); + return { + name: `tool:${name}`, + path: file, + compressed: true, + sha256: sha(bytes), + 'module-sha256': sha(modules[index]), + 'raw-sha256': sha(raw), + 'raw-size': raw.length, + }; + }), + }; + } + bytesByPath.set('manifest.json', Buffer.from(`${JSON.stringify(manifest)}\n`)); + for (const [relative, bytes] of bytesByPath) { + const file = path.join(payload, relative); + await mkdir(path.dirname(file), { recursive: true }); + await writeFile(file, bytes); + // Public archive modes must not inherit writable Windows-style input modes. + await chmod(file, 0o666); + } + const spec: ToolsCarrierSpec = { + ...facts, + version, + runtimeVersion, + artifact: { + target, + asset: `postgres-tools-wasix-{version}-${portable ? 'portable' : `aot-${target}`}.tar.gz`, + ...(platform + ? { + triple: AOT_TARGET_TRIPLES[target], + npm_package: npmPackage, + npm_os: platform.os, + npm_cpu: platform.cpu, + ...('libc' in platform ? { npm_libc: platform.libc } : {}), + } + : {}), + }, + cargoPackage, + npmPackage, + payload, + payloadFiles: [...bytesByPath.keys()].map((file) => path.join(payload, file)), + sources, + notices, + toolchain: path.resolve('src/wasix/runtime/toolchain.toml'), + outputs: { + github: path.join( + root, + `postgres-tools-wasix-${version}-${portable ? 'portable' : `aot-${target}`}.tar.gz`, + ), + npm: path.join(root, `${npmPackage.replace('@', '').replace('/', '-')}-${version}.tgz`), + cargo: path.join(root, `${cargoPackage}-${version}.crate`), + }, + }; + const saveManifest = () => + writeFile(path.join(payload, 'manifest.json'), `${JSON.stringify(manifest)}\n`); + return { root, spec, manifest, bytesByPath, saveManifest }; +} + +async function archive(file: string) { + // The public GitHub tar convention uses a single leading ./ prefix. + const entries = new Map( + [...(await new Bun.Archive(await readFile(file)).files())].map(([name, item]) => [ + name.replace(/^\.\//u, ''), + item, + ]), + ); + const read = async (name: string) => { + const item = entries.get(name); + if (!item) throw new Error(`independent archive inspection found no ${name}`); + return Buffer.from(await item.arrayBuffer()); + }; + const files = [...entries.keys()].filter((name) => !name.endsWith('/')).sort(); + return { files, read }; +} + +for (const target of ['portable', ...Object.keys(platforms)] as Target[]) { + test(`final ${target} tools archives preserve the exact payload, identities, local Cargo sources and notices`, async () => { + const { root, spec, manifest, bytesByPath } = await fixture(target); + await packageToolsCarriers(spec); + const first = await Promise.all(Object.values(spec.outputs).map((file) => readFile(file))); + const repeated = { + ...spec, + payloadFiles: [...spec.payloadFiles].reverse(), + outputs: Object.fromEntries( + Object.entries(spec.outputs).map(([kind, file]) => [ + kind, + path.join(root, 'repeat', path.basename(file)), + ]), + ) as ToolsCarrierSpec['outputs'], + }; + await packageToolsCarriers(repeated); + expect( + await Promise.all(Object.values(repeated.outputs).map((file) => readFile(file))), + ).toEqual(first); + + const portable = target === 'portable'; + const payloadNotices = releaseNoticeRows({ profile: portable ? 'wasix-tools' : 'wasix-aot' }); + const payloadNames = [ + ...new Set([...bytesByPath.keys(), ...payloadNotices.map((row) => row.member)]), + ].sort(); + const github = await archive(spec.outputs.github); + expect(github.files).toEqual(payloadNames); + const cargo = await archive(spec.outputs.cargo); + const cargoPrefix = `${spec.cargoPackage}-${spec.version}/`; + const payloadPrefix = `${cargoPrefix}${portable ? 'payload' : 'artifacts'}/`; + expect(cargo.files).toEqual( + [ + ...Object.keys(spec.sources).map((file) => `${cargoPrefix}${file}`), + ...payloadNotices.map((row) => `${cargoPrefix}${row.member}`), + ...payloadNames.map((file) => `${payloadPrefix}${file}`), + ].sort(), + ); + expect( + cargo.files + .filter((file) => file.startsWith(payloadPrefix)) + .map((file) => file.slice(payloadPrefix.length)), + ).toEqual(payloadNames); + const cargoManifest = Bun.TOML.parse((await cargo.read(`${cargoPrefix}Cargo.toml`)).toString()); + const original = Bun.TOML.parse(await readFile(spec.sources['Cargo.toml'], 'utf8')); + expect(cargoManifest.package).toMatchObject({ + name: spec.cargoPackage, + version: spec.version, + links: original.package.links, + }); + expect(cargoManifest.package.publish).toBeUndefined(); + expect(await cargo.read(`${cargoPrefix}build.rs`)).toEqual( + Buffer.from('const PACKAGE_LOCAL: bool = true;\ninclude!("build-support.rs");\n'), + ); + for (const file of ['build-support.rs', 'src/lib.rs', 'README.md']) + expect(await cargo.read(`${cargoPrefix}${file}`)).toEqual(await readFile(spec.sources[file])); + expect( + cargo.files.some((file) => /(?:BUILD\.bazel|moon\.yml|target\/|\.inputs\.json)$/u.test(file)), + ).toBe(false); + + const npm = await archive(spec.outputs.npm); + const npmManifest = JSON.parse((await npm.read('package/package.json')).toString()); + expect(npmManifest.name).toBe(spec.npmPackage); + expect(npmManifest.version).toBe(spec.version); + expect(npmManifest.publishConfig).toEqual({ access: 'public', provenance: true }); + const npmNotices = releaseNoticeRows({ profile: 'wasix-runtime' }); + expect(npm.files).toEqual( + [ + 'package/package.json', + ...npmNotices.map((row) => `package/${row.member}`), + ...(portable + ? [ + 'README.md', + 'index.js', + 'native.js', + 'index.d.ts', + 'assets/pg_dump.wasix.wasm', + 'assets/psql.wasix.wasm', + ].map((name) => `package/${name}`) + : payloadNames.map((name) => `package/assets/${name}`)), + ].sort(), + ); + if (portable) { + expect(npmManifest.oliphaunt.runtimeVersion).toBe('3.4.5'); + expect(npmManifest.oliphaunt.runtimeVersion).not.toBe(npmManifest.version); + expect(Object.values(npmManifest.optionalDependencies)).toEqual(Array(4).fill(spec.version)); + for (const [key, name] of [ + ['pgDump', 'pg_dump'], + ['psql', 'psql'], + ]) { + const bytes = await npm.read(`package/assets/${name}.wasix.wasm`); + expect(sha(bytes)).toBe(manifest[key].sha256); + expect(bytes.length).toBe(manifest[key].size); + } + } else { + const platform = platforms[target]; + expect(npmManifest.os).toEqual([platform.os]); + expect(npmManifest.cpu).toEqual([platform.cpu]); + expect(npmManifest.libc).toEqual('libc' in platform ? [platform.libc] : undefined); + for (const row of manifest.artifacts) { + const bytes = await npm.read(`package/assets/${row.path}`); + expect(sha(bytes)).toBe(row.sha256); + const raw = zstdDecompressSync(bytes); + expect(sha(raw)).toBe(row['raw-sha256']); + expect(raw.length).toBe(row['raw-size']); + } + } + for (const [relative, bytes] of bytesByPath) { + expect(await github.read(relative)).toEqual(bytes); + expect(await cargo.read(`${payloadPrefix}${relative}`)).toEqual(bytes); + } + for (const [file, prefix, rows] of [ + [spec.outputs.github, '', payloadNotices], + [spec.outputs.cargo, cargoPrefix, payloadNotices], + [spec.outputs.npm, 'package/', npmNotices], + ] as const) { + const strict = readPortableArchiveEntries(file); + for (const row of rows) { + const notice = strict.get(`${prefix}${row.member}`); + expect(notice?.data()).toEqual(await readFile(row.source)); + expect(notice?.mode).toBe(0o644); + } + expect( + [...strict.values()].filter((entry) => entry.isFile).every((entry) => entry.mode === 0o644), + ).toBe(true); + } + }); +} + +test('tools carriers reject wrong family, target, template and final filename identities', async () => { + const { spec } = await fixture('linux-x64-gnu'); + for (const invalid of [ + { ...spec, cargoPackage: 'liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu' }, + { ...spec, artifact: { ...spec.artifact, triple: 'aarch64-apple-darwin' } }, + { ...spec, npmPackage: '@oliphaunt/liboliphaunt-wasix' }, + { + ...spec, + sources: { + ...spec.sources, + 'Cargo.toml': path.resolve('src/wasix/runtime/crates/assets/Cargo.toml'), + }, + }, + { + ...spec, + outputs: { + ...spec.outputs, + github: path.join(path.dirname(spec.outputs.github), 'runtime.tar.gz'), + }, + }, + ]) + await expect(packageToolsCarriers(invalid)).rejects.toThrow(); +}); + +test('portable tools reject corrupt bytes, missing tools and mismatched independent producer versions', async () => { + const { spec, manifest, saveManifest } = await fixture(); + const tool = path.join(spec.payload, 'bin/pg_dump.wasix.wasm'); + const original = await readFile(tool); + await writeFile(tool, Buffer.concat([original, Buffer.from('corrupt')])); + await expect(packageToolsCarriers(spec)).rejects.toThrow('archive bytes do not match'); + await writeFile(tool, original); + await expect( + packageToolsCarriers({ + ...spec, + payloadFiles: spec.payloadFiles.filter((file) => file !== tool), + }), + ).rejects.toThrow(); + for (const field of ['version', 'runtimeVersion', 'sourceFingerprint']) { + const original = manifest[field]; + manifest[field] = field === 'sourceFingerprint' ? 'stale source' : '99.0.0'; + await saveManifest(); + await expect(packageToolsCarriers(spec)).rejects.toThrow('incompatible producer identity'); + manifest[field] = original; + } +}); + +test('AOT tools reject foreign/runtime members, stale source, wrong target and corrupt serialized framing', async () => { + const { spec, manifest, saveManifest } = await fixture('linux-x64-gnu'); + for (const [object, field, bad] of [ + [manifest, 'target-triple', 'aarch64-apple-darwin'], + [manifest, 'source-fingerprint', 'stale source'], + [manifest.artifacts[0], 'name', 'runtime'], + [manifest.artifacts[0], 'raw-sha256', 'f'.repeat(64)], + ] as const) { + const original = object[field]; + object[field] = bad; + await saveManifest(); + await expect(packageToolsCarriers(spec)).rejects.toThrow(); + object[field] = original; + } + await saveManifest(); + const artifact = path.join(spec.payload, manifest.artifacts[0].path); + await expect( + packageToolsCarriers({ + ...spec, + payloadFiles: spec.payloadFiles.filter((file) => file !== artifact), + }), + ).rejects.toThrow(); + await writeFile(artifact, 'invalid compressed bytes'); + await expect(packageToolsCarriers(spec)).rejects.toThrow(); +}); + +test('tools final envelopes reject undeclared/duplicate/unsafe leaves and incomplete legal sources', async () => { + const { spec } = await fixture(); + for (const invalid of [ + { ...spec, payloadFiles: [] }, + { ...spec, payloadFiles: [...spec.payloadFiles, spec.payloadFiles[0]] }, + { ...spec, payloadFiles: [...spec.payloadFiles, spec.sources['Cargo.toml']] }, + { ...spec, sources: { ...spec.sources, '../escape': spec.sources['README.md'] } }, + { ...spec, notices: {} }, + ]) + await expect(packageToolsCarriers(invalid)).rejects.toThrow(); +}); + +test('a declared runtime file cannot leak into portable tools GitHub or Cargo archives', async () => { + const { spec } = await fixture(); + const runtime = path.join(spec.payload, 'bin/postgres'); + await writeFile(runtime, '\0asm\x01\0\0\0'); + await expect( + packageToolsCarriers({ ...spec, payloadFiles: [...spec.payloadFiles, runtime] }), + ).rejects.toThrow(); +}); + +test('portable tools preserve required legal bytes instead of silently omitting or replacing them', async () => { + const { spec } = await fixture(); + const notice = path.join(spec.payload, 'THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT'); + await expect( + packageToolsCarriers({ + ...spec, + payloadFiles: spec.payloadFiles.filter((file) => file !== notice), + }), + ).rejects.toThrow(); + await writeFile(notice, 'wrong legal notice'); + await expect(packageToolsCarriers(spec)).rejects.toThrow(); +}); diff --git a/build_defs/wasix/tools.bzl b/build_defs/wasix/tools.bzl new file mode 100644 index 000000000..b7d582b5a --- /dev/null +++ b/build_defs/wasix/tools.bzl @@ -0,0 +1,69 @@ +"""Portable frontend payloads depend only on their actual command producers.""" + +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") +load("//build_defs/release:identity.bzl", "ReleaseIdentityInfo") +load(":npm.bzl", "RUNTIME_NPM_NOTICES") +load(":wasm.bzl", "WasmModuleInfo") + +def _tools_impl(ctx): + product = ctx.attr.product[ReleaseIdentityInfo] + runtime = ctx.attr.runtime_product[ReleaseIdentityInfo] + if product.id != "postgres-tools-wasix" or runtime.id != "liboliphaunt-wasix": + fail("WASIX tools payload requires its canonical product/runtime owners") + pg_dump = ctx.attr.pg_dump[WasmModuleInfo].module + psql = ctx.attr.psql[WasmModuleInfo].module + inputs = [pg_dump, psql, ctx.file.postgres_source, ctx.file.postgres_series, ctx.file.icu_source] + ctx.files.patches + notices = {} + for target, destination in ctx.attr.notices.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1 or files[0].is_directory or destination in notices: + fail("WASIX tools notice must be one unique declared file") + notices[destination] = files[0].path + inputs += files + specification = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(specification, json.encode({ + "pgDump": pg_dump.path, + "psql": psql.path, + "version": product.version, + "runtimeVersion": runtime.version, + "postgresSource": ctx.file.postgres_source.path, + "postgresSeries": ctx.file.postgres_series.path, + "patches": {file.short_path: file.path for file in ctx.files.patches}, + "icuSource": ctx.file.icu_source.path, + "notices": notices, + })) + output = ctx.actions.declare_directory(ctx.label.name) + arguments = ctx.actions.args() + arguments.add_all(["--spec", specification, "--output", output.path, "--manifest-tool", ctx.executable._manifest_tool]) + bun_file_action( + ctx, + ctx.file._packager, + arguments = [arguments], + inputs = depset(inputs + [specification]), + source_files = ctx.files._helpers, + tools = [ctx.attr._manifest_tool[DefaultInfo].files_to_run], + outputs = [output], + env = {"LC_ALL": "C"}, + mnemonic = "WasixToolsEnvelope", + progress_message = "Package declared portable WASIX tools %{label}", + ) + return [DefaultInfo(files = depset([output]))] + +wasix_tools_payload = rule( + implementation = _tools_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = { + "pg_dump": attr.label(providers = [WasmModuleInfo], mandatory = True), + "psql": attr.label(providers = [WasmModuleInfo], mandatory = True), + "product": attr.label(default = "@oliphaunt_metadata//:product_postgres-tools-wasix", providers = [ReleaseIdentityInfo]), + "runtime_product": attr.label(default = "@oliphaunt_metadata//:product_liboliphaunt-wasix", providers = [ReleaseIdentityInfo]), + "patches": attr.label_list(allow_files = [".patch"], mandatory = True), + "notices": attr.label_keyed_string_dict(default = RUNTIME_NPM_NOTICES, allow_files = True), + "postgres_source": attr.label(default = "//src/third-party/postgres:source.toml", allow_single_file = True), + "postgres_series": attr.label(default = "//src/wasix/runtime:postgres/series", allow_single_file = True), + "icu_source": attr.label(default = "//src/third-party/icu:source.toml", allow_single_file = True), + "_packager": attr.label(default = "//build_defs/wasix:tools.mts", allow_single_file = True), + "_helpers": attr.label_list(default = ["//build_defs/wasix:package.mts", "//:tools/packaging/archive-directory.mts", "//:tools/packaging/portable-archive.mts", "//:tools/packaging/release-notices.mts", "//:tools/packaging/release-directory-safety.mts"], allow_files = True), + "_manifest_tool": attr.label(default = "//src/wasix/runtime/tools/xtask:xtask", executable = True, cfg = "exec"), + }, +) diff --git a/build_defs/wasix/tools.mts b/build_defs/wasix/tools.mts new file mode 100644 index 000000000..f625ec840 --- /dev/null +++ b/build_defs/wasix/tools.mts @@ -0,0 +1,99 @@ +/** Stage the two declared frontend commands with their existing public manifest. */ +import { chmod, copyFile, mkdir, readFile, rm, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import { parseArgs } from 'node:util'; +import { stageReleaseNotices } from '../../tools/packaging/release-notices.mts'; +import { type RuntimePayloadSpec, sourceFacts } from './package.mts'; + +export interface ToolsPayloadSpec + extends Pick { + pgDump: string; + psql: string; + version: string; + runtimeVersion: string; + notices: Record; +} + +export async function packageTools( + spec: ToolsPayloadSpec, + output: string, + manifestTool: string, +): Promise { + output = path.resolve(output); + await mkdir(path.join(output, 'bin'), { recursive: true }); + const manifestSpec = path.join(output, '.manifest-inputs.json'); + const noticeRoot = path.join(output, '.notice-source'); + try { + const paths: Record = {}; + for (const [name, source] of [ + ['pg_dump', spec.pgDump], + ['psql', spec.psql], + ]) { + const file = path.join(output, `bin/${name}.wasix.wasm`); + await copyFile(source, file); + await chmod(file, 0o644); + paths[name] = file; + } + await writeFile( + manifestSpec, + JSON.stringify({ + ...(await sourceFacts(spec)), + ...paths, + version: spec.version, + runtime_version: spec.runtimeVersion, + }), + ); + const result = Bun.spawnSync( + [ + manifestTool, + 'assets', + 'declared-tools-manifest', + '--spec', + manifestSpec, + '--output', + path.join(output, 'manifest.json'), + ], + { stdout: 'inherit', stderr: 'inherit', env: { ...process.env, LC_ALL: 'C' } }, + ); + if (result.exitCode !== 0) + throw new Error(`tools manifest tool failed with exit ${result.exitCode}`); + for (const [destination, source] of Object.entries(spec.notices)) { + if ( + !destination || + path.isAbsolute(destination) || + destination.includes('\\') || + destination.split('/').some((part) => !part || part === '.' || part === '..') + ) + throw new Error(`unsafe declared notice destination: ${destination}`); + const file = path.join(noticeRoot, destination); + await mkdir(path.dirname(file), { recursive: true }); + await copyFile(source, file); + } + stageReleaseNotices(output, { profile: 'wasix-tools', sourceRoot: noticeRoot }); + } finally { + await rm(manifestSpec, { force: true }); + await rm(noticeRoot, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + const { values } = parseArgs({ + options: { + spec: { type: 'string' }, + output: { type: 'string' }, + 'manifest-tool': { type: 'string' }, + }, + strict: true, + }); + if (!values.spec || !values.output || !values['manifest-tool']) + throw new Error('--spec, --output and --manifest-tool are required'); + await packageTools( + JSON.parse( + new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode( + await readFile(values.spec), + ), + ), + values.output, + values['manifest-tool'], + ); +} diff --git a/build_defs/wasix/wasm.bzl b/build_defs/wasix/wasm.bzl new file mode 100644 index 000000000..2186dfd62 --- /dev/null +++ b/build_defs/wasix/wasm.bzl @@ -0,0 +1,253 @@ +"""Declared WASIX relocatable, side-module, sealed-link and optimization actions.""" + +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") + +WasmModuleInfo = provider(fields = { + "module": "The optimized portable module.", + "archives": "Static archives owned by this module and its dynamic dependencies.", +}) +WasmExportPolicyInfo = provider(fields = {"exports": "Sorted LF export list.", "response": "Linker export response file."}) + +def _link_resources(_os, _input_count): + return {"cpu": 2, "memory": 2048} + +def _archives(dependencies): + archives = {} + for dependency in dependencies: + for linker_input in dependency[CcInfo].linking_context.linker_inputs.to_list(): + if linker_input.user_link_flags or linker_input.additional_inputs: + fail("WASIX static archive link needs explicit handling of CcInfo flags/additional inputs from " + str(linker_input.owner)) + for library in linker_input.libraries: + archive = library.pic_static_library or library.static_library + if not archive: + fail("WASIX module requires a static CcInfo library: " + str(dependency.label)) + archives[archive.path] = archive + return archives.values() + +def _objects(dependencies): + objects = [] + for dependency in dependencies: + owned = [] + for linker_input in dependency[CcInfo].linking_context.linker_inputs.to_list(): + if linker_input.owner != dependency.label: + continue + if linker_input.user_link_flags or linker_input.additional_inputs: + fail("WASIX direct objects require explicit CcInfo flags/additional inputs from " + str(dependency.label)) + for library in linker_input.libraries: + owned.extend(library.pic_objects or library.objects) + if not owned: + fail("WASIX direct objects require the maintained compilation outputs owned by " + str(dependency.label)) + objects.extend(owned) + if len({file.path: True for file in objects}) != len(objects): + fail("WASIX direct object ownership overlaps") + return objects + +def _relocatable_impl(ctx): + archives = _archives(ctx.attr.deps) + output = ctx.actions.declare_file(ctx.label.name + ".o") + arguments = ctx.actions.args() + arguments.add("-r") + arguments.add("--threads=2") + # Canonical PG patch0022 lowers ThinLTO here, before the final sealed link. + # Prevent inlining from hiding sigsetjmp from WASIX exception lowering. + arguments.add_all([ + "-mllvm", "-inline-threshold=0", + "-mllvm", "--wasm-enable-eh", "-mllvm", "--wasm-enable-sjlj", + "-mllvm", "--wasm-use-legacy-eh=false", "-mllvm", "--exception-model=wasm", + ]) + arguments.add("--whole-archive") + arguments.add_all(archives) + arguments.add("--no-whole-archive") + arguments.add("-o", output) + ctx.actions.run( + executable = ctx.executable._linker, + arguments = [arguments], + inputs = depset(archives), + tools = ctx.files._linker_files, + outputs = [output], + env = {"LC_ALL": "C"}, + mnemonic = "WasixRelocatableLink", + progress_message = "Combine WASIX backend objects %{label}", + resource_set = _link_resources, + ) + return [DefaultInfo(files = depset([output]))] + +wasix_relocatable = rule( + implementation = _relocatable_impl, + attrs = { + "deps": attr.label_list(providers = [CcInfo], mandatory = True), + "_linker": attr.label(default = "@wasix_toolchain//:llvm/bin/wasm-ld", executable = True, allow_single_file = True, cfg = "exec"), + "_linker_files": attr.label(default = "@wasix_toolchain//:llvm_files", cfg = "exec"), + }, +) + +def _policy_impl(ctx): + modules = [dependency[WasmModuleInfo].module for dependency in ctx.attr.modules] + exports = ctx.actions.declare_file(ctx.label.name + ".exports") + response = ctx.actions.declare_file(ctx.label.name + ".rsp") + arguments = ctx.actions.args() + arguments.add_all(["assets", "export-policy"]) + for module in modules: + arguments.add("--module") + arguments.add(module.basename + "=" + module.path) + arguments.add("--output", exports) + arguments.add("--response", response) + ctx.actions.run( + executable = ctx.executable._analyzer, + arguments = [arguments], + inputs = depset(modules), + outputs = [exports, response], + env = {"LC_ALL": "C"}, + mnemonic = "WasixExportPolicy", + progress_message = "Derive sealed WASIX exports %{label}", + ) + return [DefaultInfo(files = depset([exports, response])), WasmExportPolicyInfo(exports = exports, response = response)] + +wasix_export_policy = rule( + implementation = _policy_impl, + attrs = { + "modules": attr.label_list(providers = [WasmModuleInfo], mandatory = True), + "_analyzer": attr.label(default = "//src/wasix/runtime/tools/xtask:xtask", executable = True, cfg = "exec"), + }, +) + +def _module_impl(ctx): + objects = ctx.files.srcs + _objects(ctx.attr.object_deps) + whole_archives = _archives(ctx.attr.deps) + lazy_archives = _archives(ctx.attr.archive_deps) + whole_paths = {archive.path: True for archive in whole_archives} + for archive in lazy_archives: + if archive.path in whole_paths: + fail("WASIX whole and lazy archive ownership overlap: " + archive.path) + dynamic_modules = [dependency[WasmModuleInfo] for dependency in ctx.attr.dynamic_deps] + dynamic_archives = {} + for dependency in dynamic_modules: + for archive in dependency.archives.to_list(): + if archive.path in dynamic_archives: + fail("WASIX dynamic dependencies have overlapping archive ownership: " + archive.path) + dynamic_archives[archive.path] = True + whole_archives = [archive for archive in whole_archives if archive.path not in dynamic_archives] + lazy_archives = [archive for archive in lazy_archives if archive.path not in dynamic_archives] + archives = whole_archives + lazy_archives + raw = ctx.actions.declare_file(ctx.label.name + "/" + ctx.attr.output_name + ".unoptimized") + output = ctx.actions.declare_file(ctx.label.name + "/" + ctx.attr.output_name) + # These flags are the pinned wasixcc dynamic-linking ABI. Invoke its LLVM + # linker directly so optimization and sealed export selection are actions. + root = ctx.executable._linker.dirname[:-len("/llvm/bin")] + sysroot = ctx.file.constructed_sysroot.path if ctx.attr.constructed_sysroot else root + "/sysroot/sysroot-exnref-ehpic" + if ctx.attr.constructed_sysroot and not ctx.file.constructed_sysroot.is_directory: + fail("WASIX constructed_sysroot must be the declared source-built sysroot tree") + arguments = ctx.actions.args() + arguments.add_all([ + "--threads=2", + "--no-entry", + "--extra-features=atomics,bulk-memory,mutable-globals", + "--shared-memory", "--max-memory=4294967296", "--import-memory", + "--export=__wasm_call_ctors", "--no-demangle", + "-mllvm", "--wasm-enable-eh", "-mllvm", "--wasm-enable-sjlj", + "-mllvm", "--wasm-use-legacy-eh=false", "-mllvm", "--exception-model=wasm", + "--export=__wasm_init_tls", "--export=__wasm_signal", + "--export=__tls_size", "--export=__tls_align", "--export=__tls_base", + "--export-if-defined=__indirect_function_table", + "--experimental-pic", "--export-if-defined=__wasm_apply_data_relocs", + "--export-if-defined=__wasm_apply_tls_relocs", + "-L" + sysroot + "/lib", "-L" + sysroot + "/lib/wasm32-wasi", + ]) + inputs = archives + objects + [dependency.module for dependency in dynamic_modules] + if ctx.attr.constructed_sysroot: + inputs.append(ctx.file.constructed_sysroot) + is_command = bool(ctx.attr.export_policy) or ctx.attr.kind == "command" + if is_command and (ctx.attr.cxx_runtime or dynamic_modules): + fail("WASIX cxx_runtime/dynamic_deps apply only to side modules") + if is_command: + arguments.add_all([ + "--export-if-defined=__stack_pointer", "--export-if-defined=__heap_base", + "--export-if-defined=__data_end", "-pie", + "--whole-archive", "-lwasi-emulated-getpid", "-lwasi-emulated-mman", + "-lwasi-emulated-process-clocks", "-lc", "-lresolv", "-lrt", "-lm", + "-lpthread", "-lutil", "--no-whole-archive", "-lclang_rt.builtins-wasm32", + "-lcommon-tag-stubs", + ]) + if ctx.attr.export_policy: + policy = ctx.attr.export_policy[WasmExportPolicyInfo] + arguments.add("@" + policy.response.path) + inputs.append(policy.response) + else: + arguments.add("--export=_start") + arguments.add_all(objects) + arguments.add_all(whole_archives) + arguments.add_all(lazy_archives) + arguments.add_all([sysroot + "/lib/wasm32-wasi/" + library for library in ["libc++.a", "libc++abi.a", "libunwind.a", "crt1.o"]]) + else: + arguments.add_all(["-shared", "--unresolved-symbols=import-dynamic", "--export-dynamic", "--soname=" + ctx.attr.output_name]) + arguments.add("--whole-archive") + arguments.add_all(objects) + arguments.add_all(whole_archives) + if ctx.attr.cxx_runtime: + arguments.add_all([sysroot + "/lib/wasm32-wasi/" + library for library in ["libc++.a", "libc++abi.a", "libunwind.a"]]) + arguments.add("--no-whole-archive") + arguments.add_all(lazy_archives) + if ctx.attr.cxx_runtime: + arguments.add_all(["-lm", "-lc"]) + if dynamic_modules: + arguments.add("--Bdynamic") + arguments.add_all([dependency.module for dependency in dynamic_modules]) + arguments.add_all(["-rpath", "$ORIGIN"]) + arguments.add("-lclang_rt.builtins-wasm32") + arguments.add(sysroot + "/lib/wasm32-wasi/scrt1.o") + arguments.add_all(ctx.attr.linkopts) + arguments.add("-o", raw) + ctx.actions.run( + executable = ctx.executable._linker, + arguments = [arguments], + inputs = depset(inputs), + tools = ctx.files._llvm_files if ctx.attr.constructed_sysroot else ctx.files._linker_files, + outputs = [raw], + env = {"LC_ALL": "C"}, + mnemonic = "WasixSealedLink" if is_command else "WasixSideLink", + progress_message = "Link portable WASIX module %{label}", + resource_set = _link_resources, + ) + optimize = ctx.actions.args() + optimize.add(raw) + optimize.add_all(ctx.attr.optimization_flags) + optimize.add("-o", output) + ctx.actions.run( + executable = ctx.executable._optimizer, + arguments = [optimize], + inputs = [raw], + tools = ctx.files._optimizer_files, + outputs = [output], + env = {"LC_ALL": "C", "BINARYEN_CORES": "2"}, + mnemonic = "WasixOptimize", + progress_message = "Optimize portable WASIX module %{label}", + resource_set = _link_resources, + ) + return [ + DefaultInfo(files = depset([output])), + WasmModuleInfo(module = output, archives = depset(archives, transitive = [dependency.archives for dependency in dynamic_modules])), + OutputGroupInfo(unoptimized = depset([raw])), + ] + +wasix_module = rule( + implementation = _module_impl, + attrs = { + "output_name": attr.string(mandatory = True), + "kind": attr.string(default = "side", values = ["side", "command"]), + "deps": attr.label_list(providers = [CcInfo]), + "object_deps": attr.label_list(providers = [CcInfo]), + "archive_deps": attr.label_list(providers = [CcInfo]), + "dynamic_deps": attr.label_list(providers = [WasmModuleInfo]), + "cxx_runtime": attr.bool(default = False), + "srcs": attr.label_list(allow_files = [".o"]), + "export_policy": attr.label(providers = [WasmExportPolicyInfo]), + "linkopts": attr.string_list(), + "constructed_sysroot": attr.label(allow_single_file = True, providers = [CcInfo]), + "optimization_flags": attr.string_list(default = ["-O2", "--enable-threads", "--enable-mutable-globals", "--enable-bulk-memory", "--enable-bulk-memory-opt", "--enable-exception-handling", "--enable-simd", "--enable-relaxed-simd", "--enable-extended-const", "--emit-exnref", "--converge", "--strip-debug", "--strip-producers"]), + "_linker": attr.label(default = "@wasix_toolchain//:llvm/bin/wasm-ld", executable = True, allow_single_file = True, cfg = "exec"), + "_linker_files": attr.label(default = "@wasix_toolchain//:linker_files", cfg = "exec"), + "_llvm_files": attr.label(default = "@wasix_toolchain//:llvm_files", cfg = "exec"), + "_optimizer": attr.label(default = "@wasix_toolchain//:binaryen/bin/wasm-opt", executable = True, allow_single_file = True, cfg = "exec"), + "_optimizer_files": attr.label(default = "@wasix_toolchain//:binaryen_files", cfg = "exec"), + }, +) diff --git a/build_defs/wasix/wasmer-macho-trampoline.patch b/build_defs/wasix/wasmer-macho-trampoline.patch new file mode 100644 index 000000000..e9c17b2b1 --- /dev/null +++ b/build_defs/wasix/wasmer-macho-trampoline.patch @@ -0,0 +1,57 @@ +diff --git a/src/translator/trampoline.rs b/src/translator/trampoline.rs +--- a/src/translator/trampoline.rs ++++ b/src/translator/trampoline.rs +@@ -55,6 +55,16 @@ + } + + impl FuncTrampoline { ++ // LLVM requires a segment and section for Mach-O; the object loader below ++ // still looks up the unqualified section name stored in func_section. ++ fn llvm_function_section(&self) -> String { ++ if matches!(self.binary_fmt, BinaryFormat::Macho) { ++ format!("__TEXT,{}", self.func_section) ++ } else { ++ self.func_section.clone() ++ } ++ } ++ + pub fn new( + target_machine: TargetMachine, + target_triple: Triple, +@@ -118,7 +128,7 @@ + let trampoline_func = module.add_function(name, trampoline_ty, Some(Linkage::External)); + trampoline_func + .as_global_value() +- .set_section(Some(&self.func_section)); ++ .set_section(Some(&self.llvm_function_section())); + trampoline_func + .as_global_value() + .set_linkage(Linkage::DLLExport); +@@ -285,7 +295,7 @@ + } + trampoline_func + .as_global_value() +- .set_section(Some(&self.func_section)); ++ .set_section(Some(&self.llvm_function_section())); + trampoline_func + .as_global_value() + .set_linkage(Linkage::DLLExport); +diff --git a/src/compiler.rs b/src/compiler.rs +--- a/src/compiler.rs ++++ b/src/compiler.rs +@@ -497,6 +497,15 @@ + let got_data: Vec = vec![0; got_targets.len() * got_entry_size]; + let mut got_relocs = vec![]; + ++ // Randomized set iteration must not become serialized GOT offsets. ++ let mut got_targets = got_targets.into_iter().collect::>(); ++ got_targets.sort_unstable_by_key(|target| match target { ++ RelocationTarget::LocalFunc(index) => (0_u8, index.as_u32()), ++ RelocationTarget::DynamicTrampoline(index) => (1, index.as_u32()), ++ RelocationTarget::LibCall(libcall) => (2, *libcall as u16 as u32), ++ RelocationTarget::CustomSection(index) => (3, index.as_u32()), ++ }); ++ + for (i, target) in got_targets.into_iter().enumerate() { + got_relocs.push(wasmer_compiler::types::relocation::Relocation { + kind: got_entry_reloc_kind, diff --git a/bun.lock b/bun.lock index bf6de7a21..03408dac3 100644 --- a/bun.lock +++ b/bun.lock @@ -23,6 +23,9 @@ "name": "@oliphaunt/docs", "version": "0.0.0", "dependencies": { + "@fontsource-variable/dm-sans": "5.3.0", + "@fontsource-variable/geist-mono": "5.3.0", + "@fontsource/instrument-serif": "5.3.0", "@mdx-js/react": "^3.1.0", "clsx": "^2.1.1", "fumadocs-core": "16.9.3", @@ -309,6 +312,7 @@ "tools/release": { "name": "@oliphaunt/release-tools", "dependencies": { + "protobufjs": "8.8.1", "release-please": "17.3.0", }, }, @@ -639,6 +643,12 @@ "@floating-ui/utils": ["@floating-ui/utils@0.2.11", "", {}, "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg=="], + "@fontsource-variable/dm-sans": ["@fontsource-variable/dm-sans@5.3.0", "", {}, "sha512-BpUG5bqePiDFMBM4ZtLSlPdAIOM990uB1dlXzIf4aw21yQR7BmykedLXXXMqGWsR18aMLOsbWccwJNh3ztTQaA=="], + + "@fontsource-variable/geist-mono": ["@fontsource-variable/geist-mono@5.3.0", "", {}, "sha512-vBbuwDEo9AkrqADMXOrlAR3DFcJi4/JxeuU43FoiQERnNwsfXNnvxvReZG02cQKmyk4DZkZdBZX3oTDvy2zBAw=="], + + "@fontsource/instrument-serif": ["@fontsource/instrument-serif@5.3.0", "", {}, "sha512-mDiaIg0u67sYV59fie92Wz4sM8UiVlbL7fLxnFPCKkX15DMASEnQTREbaP5S5/3DCcsoAOcQ0sV9E4AeY4QqYQ=="], + "@fumadocs/tailwind": ["@fumadocs/tailwind@0.0.5", "", { "peerDependencies": { "@tailwindcss/oxide": "^4.0.0", "tailwindcss": "^4.0.0" }, "optionalPeers": ["@tailwindcss/oxide", "tailwindcss"] }, "sha512-ENKPWUDRmriccsrUDE4bDBq3FNr/ms3BP2rWlsAEMV1yP23pcCaan+ceGfeBUsAQjw7sj9Q3R4Kl3g/TCStPzQ=="], "@google-automations/git-file-utils": ["@google-automations/git-file-utils@3.2.0", "", { "dependencies": { "@octokit/rest": "^20.1.1", "minimatch": "^10.2.4" } }, "sha512-EtQD1DX17kGpckDNCdI0jvMdF98EWR/TM9uogQtnhK0ODv8z5tPSPMICv2lk54c/9ucUgbfdLDrRdDyx56Sznw=="], @@ -2071,6 +2081,8 @@ "logkitty": ["logkitty@0.7.1", "", { "dependencies": { "ansi-fragments": "0.2.1", "dayjs": "1.11.21", "yargs": "15.4.1" }, "bin": { "logkitty": "bin/logkitty.js" } }, "sha512-/3ER20CTTbahrCrpYfPn7Xavv9diBROZpoXGVZDWMw4b/X4uuUwAC0ki85tgsdMRONURyIJbcOvS94QsUBYPbQ=="], + "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], + "longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="], "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], @@ -2443,6 +2455,8 @@ "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], + "protobufjs": ["protobufjs@8.8.1", "", { "dependencies": { "long": "^5.3.2" } }, "sha512-d9e9179bjXSJdpJ3+R9fP8hzXsnKLyxTjHLG1dUzje8a27pPyXCe6PrcRtgx2rjoM3IZzHd2vAs+6J/BsO1k7Q=="], + "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], diff --git a/src/benchmarks/perf/wasix-browser/benchmark.mts b/src/benchmarks/perf/wasix-browser/benchmark.mts index 750994f68..ba31e3ef3 100644 --- a/src/benchmarks/perf/wasix-browser/benchmark.mts +++ b/src/benchmarks/perf/wasix-browser/benchmark.mts @@ -5,6 +5,12 @@ import { arch, cpus, hostname, platform, release, totalmem } from 'node:os'; import { dirname, relative, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; import { isDeepStrictEqual } from 'node:util'; +import { + assertNativeBrowserHostProvenance, + HOST_FILES, + NATIVE_BROWSER_HOST_SCHEMA, + readNativeBrowserSourceContract, +} from '../../../../build_defs/wasix/browser/provenance.mts'; import { loadHostBuildContract } from '../../../wasix/browser-host/build-provenance.mts'; import { directoryTreeSha256, installedPackageClosure } from '../wasix-node/installed-closure.mts'; import { assertRuntimeBuildConfiguration, runtimeBuildProvenance } from '../wasix-node/plan.mts'; @@ -134,10 +140,7 @@ async function candidateProvenance(plan) { if (clusterSeedSha256 !== clusterSeed.sha256) { throw new Error('canonical WASIX standard cluster seed does not match its manifest'); } - const hostBuild = await installedHostBuildProvenance( - packageFile, - (await loadHostBuildContract()).provenance, - ); + const hostBuild = await installedHostBuildProvenance(packageFile); const runtimeBuild = await runtimeBuildProvenance(manifest); assertRuntimeBuildConfiguration( runtimeBuild.configuration, @@ -183,7 +186,7 @@ async function candidateProvenance(plan) { }; } -async function installedHostBuildProvenance(packageManifestFile, expected) { +async function installedHostBuildProvenance(packageManifestFile) { const file = resolve(dirname(packageManifestFile), 'lib/host/provenance.json'); let provenance; try { @@ -193,7 +196,17 @@ async function installedHostBuildProvenance(packageManifestFile, expected) { cause: error, }); } - if (!isDeepStrictEqual(provenance, expected)) { + if (provenance.schema === NATIVE_BROWSER_HOST_SCHEMA) { + const host = dirname(file); + assertNativeBrowserHostProvenance(provenance, { + source: await readNativeBrowserSourceContract(repositoryRoot), + files: Object.fromEntries( + await Promise.all( + HOST_FILES.map(async (name) => [name, await readFile(resolve(host, name))]), + ), + ), + }); + } else if (!isDeepStrictEqual(provenance, (await loadHostBuildContract()).provenance)) { throw new Error( 'installed @oliphaunt/wasix-ts host provenance does not match the source build contract', ); diff --git a/src/database-resources/BUILD.bazel b/src/database-resources/BUILD.bazel new file mode 100644 index 000000000..39daaafdf --- /dev/null +++ b/src/database-resources/BUILD.bazel @@ -0,0 +1,64 @@ +load("@oliphaunt_metadata//:metadata.bzl", "DATABASE_RESOURCE_ARTIFACTS") +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/resources:resources.bzl", "linux_resource_slice", "linux_resource_test", "native_resource_test", "resource_compile_data", "wasix_resource_slice", "wasix_resource_test") +load("//build_defs/resources:mobile.bzl", "android_resource_slice", "ios_resource_slice", "mobile_resource_test", "native_abi_receipt") +load("//build_defs/android:toolchain.bzl", "android_artifact") +load("//build_defs/native/carriers:release-family.bzl", "native_release_checksum_family") + +package(default_visibility = ["//visibility:public"]) + +exports_files([ + "VERSION", + "seeds/carrier-identities.mts", +] + glob(["contracts/*.mts", "contracts/*.json", "seeds/*.mts", "seeds/native/tools/*.mts"])) + +filegroup( + name = "cluster_seed_contract_fixtures", + srcs = glob(["contracts/fixtures/*.properties", "contracts/fixtures/*.json"]), +) + +# rules_rust stages authored Rust sources beneath bazel-out. These symlinks +# preserve the existing relative include_str! paths to the exact contracts. +resource_compile_data(name = "contract_compile_data", src = "contracts/contract.json", out = "contracts/contract.json") +resource_compile_data(name = "profile_probe_compile_data", src = "contracts/profile-probe.json", out = "contracts/profile-probe.json") + +native_abi_receipt(name = "native_target_abi") + +[android_artifact( + name = "android_" + architecture + "_abi", + artifact = ":native_target_abi", + platform = "//build_defs/android:android_" + architecture, +) for architecture in ["arm64", "x86_64"]] + +linux_resource_slice(name = "linux_shipping_export", qualification = [":native_resource_test"], templates = { + "//src/database-resources/icu:npm/package.json": "npm/package.json", + "//src/database-resources/icu:npm/README.md": "npm/README.md", + "//src/database-resources/icu:npm/OliphauntICU.podspec": "npm/OliphauntICU.podspec", + "//src/database-resources/icu:npm/react-native.config.cts": "npm/react-native.config.cts", + "//src/database-resources/icu:cargo/Cargo.toml": "cargo/Cargo.toml", + "//src/database-resources/icu:cargo/README.md": "cargo/README.md", + "//src/database-resources/icu:cargo/build.rs": "cargo/build.rs", + "//src/database-resources/icu:cargo/build-support.rs": "cargo/build-support.rs", + "//src/database-resources/icu:cargo/src/lib.rs": "cargo/src/lib.rs", +}) + +android_resource_slice(name = "android_shipping_export", qualification = [":android_resource_test", ":native_resource_test"]) +ios_resource_slice(name = "ios_shipping_export", qualification = [":ios_resource_test", ":native_resource_test"]) +mobile_resource_test(name = "android_resource_test", target = "android-datum64") +mobile_resource_test(name = "ios_resource_test", target = "ios-datum64") + +wasix_resource_slice(name = "wasix_shipping_export", qualification = [":wasix_resource_test"]) +wasix_resource_test(name = "wasix_resource_test") + +linux_resource_test(name = "linux_resource_test") +native_resource_test(name = "native_resource_test") + +native_release_checksum_family(product = "database-resources", artifact_rows = DATABASE_RESOURCE_ARTIFACTS) + +source_quality_files() + +# Source-only inputs for the existing SDK package policy tests. +exports_files([ + "contracts/contract.json", + "contracts/native-manifest.mts", +], visibility = ["//visibility:public"]) diff --git a/src/database-resources/icu/BUILD.bazel b/src/database-resources/icu/BUILD.bazel new file mode 100644 index 000000000..74e0b390d --- /dev/null +++ b/src/database-resources/icu/BUILD.bazel @@ -0,0 +1,39 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files", "source_quality_files") +load("@rules_rust//rust:defs.bzl", "rust_clippy_test") +load("//build_defs/languages:rust.bzl", "cargo_generator", "cargo_library", "cargo_library_test", "cargo_package_env") +package(default_visibility = ["//visibility:public"]) + +exports_files(["source.toml"] + glob(["tools/*.mts", "npm/*", "cargo/*", "cargo/src/*.rs"])) + +cargo_package_env(name = "icu_cargo_env", package_name = "src/database-resources/icu/cargo") +cargo_generator( + name = "icu_cargo_build_script", + package_name = "src/database-resources/icu/cargo", + cargo_env = ":icu_cargo_env", + srcs = ["cargo/build-support.rs"], +) +cargo_library( + name = "icu_cargo_lib", + package_name = "src/database-resources/icu/cargo", + cargo_env = ":icu_cargo_env", + build_script = ":icu_cargo_build_script", +) +cargo_library_test( + name = "icu_cargo_unit_test", + package_name = "src/database-resources/icu/cargo", + cargo_env = ":icu_cargo_env", + crate = ":icu_cargo_lib", + tags = ["manual"], +) + +rust_clippy_test( + name = "clippy_test", + targets = [":icu_cargo_lib", ":icu_cargo_unit_test", ":icu_cargo_build_script_"], + transitive = False, + size = "small", + tags = ["quality", "static"], +) + +source_quality_files() + +rust_quality_files() diff --git a/src/database-resources/icu/tools/package-cargo.mts b/src/database-resources/icu/tools/package-cargo.mts index 5cbea026b..b9de6d88a 100644 --- a/src/database-resources/icu/tools/package-cargo.mts +++ b/src/database-resources/icu/tools/package-cargo.mts @@ -17,25 +17,29 @@ function fail(message) { throw new Error(message); } -export function packageIcuCargo(argv) { +export function packageIcuCargo(argv, context = {}) { const { values } = parseArgs({ args: argv, options: { - version: { type: 'string', default: currentProductVersionSync('database-resources') }, + version: { + type: 'string', + default: context.version ?? currentProductVersionSync('database-resources'), + }, asset: { type: 'string' }, 'output-dir': { type: 'string', default: 'target/database-resources/cargo-artifacts' }, 'work-dir': { type: 'string', default: 'target/database-resources' }, }, }); + const root = context.root ?? ROOT; const prefix = `database-resources-${values.version}-icu-data`; const archive = path.resolve( - ROOT, + root, values.asset ?? `target/database-resources/release-assets/${prefix}.tar.gz`, ); - const work = path.resolve(ROOT, values['work-dir']); + const work = path.resolve(root, values['work-dir']); const extracted = path.join(work, 'icu-cargo-extracted'); const sourceRoot = path.join(work, 'cargo-package-sources'); - const outputDir = path.resolve(ROOT, values['output-dir']); + const outputDir = path.resolve(root, values['output-dir']); // Own only this crate's scratch: future resource carriers share the output directory. for (const directory of [extracted, path.join(sourceRoot, 'oliphaunt-icu')]) rmSync(directory, { recursive: true, force: true }); @@ -59,7 +63,7 @@ export function packageIcuCargo(argv) { name: 'oliphaunt-icu', target: 'portable', kind: 'icu-data', - templateDir: path.join(ROOT, 'src/database-resources/icu/cargo'), + templateDir: context.templateDir ?? path.join(ROOT, 'src/database-resources/icu/cargo'), payloadRoot, payloadDirName: 'payload', }, @@ -68,9 +72,10 @@ export function packageIcuCargo(argv) { sourceRoot, outputDir, cargoTargetDir: path.join(work, 'cargo-package-target'), + noticeSourceRoot: context.noticeSourceRoot, }, ); - const relative = (value) => path.relative(ROOT, value).split(path.sep).join('/'); + const relative = (value) => path.relative(root, value).split(path.sep).join('/'); writeFileSync( path.join(outputDir, 'packages.json'), `${JSON.stringify( diff --git a/src/database-resources/icu/tools/package-npm.mts b/src/database-resources/icu/tools/package-npm.mts index a0e6ae68e..fef0eac18 100644 --- a/src/database-resources/icu/tools/package-npm.mts +++ b/src/database-resources/icu/tools/package-npm.mts @@ -1,6 +1,7 @@ #!/usr/bin/env bun import { copyFileSync, readFileSync, writeFileSync } from 'node:fs'; import path from 'node:path'; +import { packGeneratedNpmCarrier } from '../../../../tools/packaging/npm-package.mts'; import { extractPortableArchiveTree, readPortableArchiveEntries, @@ -8,7 +9,6 @@ import { import { extractReleaseArchiveFile, fail, - packStagedNpmCarrier, rel, stageNpmPackageDescriptor, } from '../../../../tools/packaging/release-carrier.mts'; @@ -33,25 +33,24 @@ import { const LIBOLIPHAUNT_ICU_PACKAGE_NAME = '@oliphaunt/icu'; const LIBOLIPHAUNT_ICU_PACKAGE_ROOT = path.join(ROOT, 'src/database-resources/icu/npm'); -function stageLiboliphauntIcuNpmPayload(version) { - const stage = stageNpmPackageDescriptor( - LIBOLIPHAUNT_ICU_PACKAGE_NAME, - LIBOLIPHAUNT_ICU_PACKAGE_ROOT, - version, - { - extraDescriptors: [ICU_PODSPEC], - target: 'portable', - }, - ); +function stageLiboliphauntIcuNpmPayload(version, context) { + const packageRoot = context.packageRoot ?? LIBOLIPHAUNT_ICU_PACKAGE_ROOT; + const stage = stageNpmPackageDescriptor(LIBOLIPHAUNT_ICU_PACKAGE_NAME, packageRoot, version, { + extraDescriptors: [ICU_PODSPEC], + target: 'portable', + ...(context.stageDir === undefined ? {} : { stageDir: context.stageDir }), + }); copyFileSync( - path.join(LIBOLIPHAUNT_ICU_PACKAGE_ROOT, 'react-native.config.cts'), + path.join(packageRoot, 'react-native.config.cts'), path.join(stage, ICU_REACT_NATIVE_CONFIG), ); - const sourceArchive = path.join( - ROOT, - 'target/database-resources/release-assets', - `database-resources-${version}-icu-data.tar.gz`, - ); + const sourceArchive = + context.sourceArchive ?? + path.join( + ROOT, + 'target/database-resources/release-assets', + `database-resources-${version}-icu-data.tar.gz`, + ); extractPortableArchiveTree( sourceArchive, path.join(stage, ...ICU_DATA_RELATIVE_PATH.split('/')), @@ -74,8 +73,11 @@ function stageLiboliphauntIcuNpmPayload(version) { } packageJson.oliphaunt.icuDataTreeSha256 = digest; writeFileSync(manifestFile, `${JSON.stringify(packageJson, null, 2)}\n`); - stageReleaseNotices(stage, { profile: 'native-icu-data' }); - assertReleaseNoticesInDirectory(stage, { profile: 'native-icu-data' }); + stageReleaseNotices(stage, { profile: 'native-icu-data', sourceRoot: context.noticeSourceRoot }); + assertReleaseNoticesInDirectory(stage, { + profile: 'native-icu-data', + sourceRoot: context.noticeSourceRoot, + }); try { assertIcuPackageManifest( JSON.parse(readFileSync(path.join(stage, 'package.json'), 'utf8')), @@ -87,7 +89,8 @@ function stageLiboliphauntIcuNpmPayload(version) { return stage; } -function validatePackedIcuPackage(packageName, version, tarball, sourceArchive) { +function validatePackedIcuPackage(packageName, version, tarball, sourceArchive, context) { + const packageRoot = context.packageRoot ?? LIBOLIPHAUNT_ICU_PACKAGE_ROOT; let entries; let sourceEntries; try { @@ -125,10 +128,8 @@ function validatePackedIcuPackage(packageName, version, tarball, sourceArchive) packageJson, packedConfig: entries.get(`package/${ICU_REACT_NATIVE_CONFIG}`)?.data(), packedPodspec: entries.get(`package/${ICU_PODSPEC}`)?.data(), - sourceConfig: readFileSync( - path.join(LIBOLIPHAUNT_ICU_PACKAGE_ROOT, 'react-native.config.cts'), - ), - sourcePodspec: readFileSync(path.join(LIBOLIPHAUNT_ICU_PACKAGE_ROOT, ICU_PODSPEC)), + sourceConfig: readFileSync(path.join(packageRoot, 'react-native.config.cts')), + sourcePodspec: readFileSync(path.join(packageRoot, ICU_PODSPEC)), label: rel(tarball), }); assertIcuPackedClosureMatchesSource({ @@ -141,21 +142,33 @@ function validatePackedIcuPackage(packageName, version, tarball, sourceArchive) } catch (error) { fail(error instanceof Error ? error.message : String(error)); } - assertReleaseNoticesInArchive(tarball, { profile: 'native-icu-data', prefix: 'package' }); + assertReleaseNoticesInArchive(tarball, { + profile: 'native-icu-data', + prefix: 'package', + sourceRoot: context.noticeSourceRoot, + }); } -export function resourceNpmTarballs(version = currentProductVersionSync('database-resources')) { - const stage = stageLiboliphauntIcuNpmPayload(version); - const tarball = packStagedNpmCarrier(stage); +export function resourceNpmTarballs( + version = currentProductVersionSync('database-resources'), + context = {}, +) { + const stage = stageLiboliphauntIcuNpmPayload(version, context); + const tarball = packGeneratedNpmCarrier( + stage, + context.outputDir ?? path.join(ROOT, 'target/release/npm-packages'), + ); validatePackedIcuPackage( LIBOLIPHAUNT_ICU_PACKAGE_NAME, version, tarball, - path.join( - ROOT, - 'target/database-resources/release-assets', - `database-resources-${version}-icu-data.tar.gz`, - ), + context.sourceArchive ?? + path.join( + ROOT, + 'target/database-resources/release-assets', + `database-resources-${version}-icu-data.tar.gz`, + ), + context, ); return [[LIBOLIPHAUNT_ICU_PACKAGE_NAME, tarball]]; } diff --git a/src/database-resources/release.toml b/src/database-resources/release.toml index a0b2652a4..2280091b6 100644 --- a/src/database-resources/release.toml +++ b/src/database-resources/release.toml @@ -39,3 +39,9 @@ registry_packages = [ "crates:oliphaunt-seed-wasix-icu", ] release_artifacts = ["icu-data", "cluster-seeds"] + +[compatibility_versions.wasix_runtime] +public_support = false +source_product = "liboliphaunt-wasix" +path = "src/database-resources/seeds/wasix/Cargo.toml" +parser = "toml:package.metadata.oliphaunt.runtime-version" diff --git a/src/database-resources/seeds/carrier-identities.mts b/src/database-resources/seeds/carrier-identities.mts index fe3f9037c..9a6547221 100644 --- a/src/database-resources/seeds/carrier-identities.mts +++ b/src/database-resources/seeds/carrier-identities.mts @@ -1,10 +1,10 @@ import { readFileSync } from 'node:fs'; -const contract = JSON.parse( - readFileSync(new URL('../contracts/contract.json', import.meta.url), 'utf8'), -); - -export function seedCarrierIdentities() { +export function seedCarrierIdentities( + contract = JSON.parse( + readFileSync(new URL('../contracts/contract.json', import.meta.url), 'utf8'), + ), +) { return [ ...Object.keys(contract.compatibilityKeys.native).map((target) => ({ family: 'native', diff --git a/src/database-resources/seeds/native/tools/stage-native-cluster-seed.mts b/src/database-resources/seeds/native/tools/stage-native-cluster-seed.mts index 152d9cb38..c0ebe5a9f 100644 --- a/src/database-resources/seeds/native/tools/stage-native-cluster-seed.mts +++ b/src/database-resources/seeds/native/tools/stage-native-cluster-seed.mts @@ -53,31 +53,23 @@ function requireDirectory(directory, label) { if (!existsSync(directory)) fail(`${label} does not exist: ${directory}`); } -const [mode, ...argv] = process.argv.slice(2); -const source = mode === 'install' ? argv.shift() : undefined; -if (!['prepare', 'install'].includes(mode) || (mode === 'install' && !source)) { - fail('usage: stage-native-cluster-seed.mts prepare|install [prepared-seed] '); +function validateArgs(args) { + requireDirectory(args.runtime, 'native runtime'); + if (args.icuData !== undefined) requireDirectory(args.icuData, 'ICU data'); + if (!NATIVE_CLUSTER_SEED_TARGETS.includes(args.target)) + fail('unsupported native cluster-seed target'); + if ( + !['standard', 'icu'].includes(args.profile) || + (args.profile === 'icu') !== Boolean(args.icuData) + ) + fail('seed profile must match its explicit ICU data'); + if (args.destination === path.parse(args.destination).root) + fail('destination must not be a filesystem root'); } -const args = parseArgs(argv); -requireDirectory(args.runtime, 'native runtime'); -if (args.icuData !== undefined) requireDirectory(args.icuData, 'ICU data'); -if (!NATIVE_CLUSTER_SEED_TARGETS.includes(args.target)) - fail('unsupported native cluster-seed target'); -if (args.destination === path.parse(args.destination).root) - fail('destination must not be a filesystem root'); -if (mode === 'prepare') { - for (const value of [ - args.runtime, - args.destination, - args.target, - args.profile, - args.icuData ?? '', - ]) { - if (value.includes('\0')) fail('cluster-seed paths must not contain NUL'); - process.stdout.write(`${value}\0`); - } -} else { - const contract = JSON.parse( + +export function installNativeClusterSeed(source, args, contract) { + validateArgs(args); + contract ??= JSON.parse( readFileSync(new URL('../../../contracts/contract.json', import.meta.url), 'utf8'), ); const files = path.join(source, 'files'); @@ -139,7 +131,30 @@ if (mode === 'prepare') { }); rmSync(args.destination, { recursive: true, force: true }); cpSync(source, args.destination, { recursive: true, errorOnExist: true }); - console.log( - `clusterSeed=${args.destination}\ncatalogProfile=${args.profile}\ntarget=${args.target}`, - ); +} + +if (import.meta.main) { + const [mode, ...argv] = process.argv.slice(2); + const source = mode === 'install' ? argv.shift() : undefined; + if (!['prepare', 'install'].includes(mode) || (mode === 'install' && !source)) + fail('usage: stage-native-cluster-seed.mts prepare|install [prepared-seed] '); + const args = parseArgs(argv); + validateArgs(args); + if (mode === 'prepare') { + for (const value of [ + args.runtime, + args.destination, + args.target, + args.profile, + args.icuData ?? '', + ]) { + if (value.includes('\0')) fail('cluster-seed paths must not contain NUL'); + process.stdout.write(`${value}\0`); + } + } else { + installNativeClusterSeed(source, args); + console.log( + `clusterSeed=${args.destination}\ncatalogProfile=${args.profile}\ntarget=${args.target}`, + ); + } } diff --git a/src/database-resources/seeds/package-carriers.mts b/src/database-resources/seeds/package-carriers.mts index 7cac2e9d3..f261d31b6 100644 --- a/src/database-resources/seeds/package-carriers.mts +++ b/src/database-resources/seeds/package-carriers.mts @@ -33,7 +33,17 @@ import { } from '../../../tools/release/release-artifact-targets.mts'; import { seedCarrierIdentities } from './carrier-identities.mts'; -export function packageSeedCarriers(argv = [], { assetDir, outputDir, sourceDir } = {}) { +export function packageSeedCarriers( + argv = [], + { + assetDir, + outputDir, + sourceDir, + version = currentProductVersionSync('database-resources'), + contract, + noticeSourceRoot, + } = {}, +) { const { values } = parseArgs({ args: argv, options: { @@ -42,11 +52,10 @@ export function packageSeedCarriers(argv = [], { assetDir, outputDir, sourceDir profile: { type: 'string' }, }, }); - const selected = seedCarrierIdentities().filter((item) => + const selected = seedCarrierIdentities(contract).filter((item) => Object.entries(values).every(([key, value]) => item[key] === value), ); if (!selected.length) throw new Error('no declared seed carrier matches the selection'); - const version = currentProductVersionSync('database-resources'); const output = path.resolve( outputDir ?? path.join(ROOT, 'target/database-resources/seed-carriers'), ); @@ -84,8 +93,10 @@ export function packageSeedCarriers(argv = [], { assetDir, outputDir, sourceDir copyFileSync(archive, path.join(stage, 'seed.tar.zst')); copyFileSync(manifestFile, path.join(stage, 'manifest.json')); const noticeProfile = 'native-runtime-resources'; - const license = releaseProfilePackageLicense(noticeProfile).spdx; - stageReleaseNotices(stage, { profile: noticeProfile }); + const license = releaseProfilePackageLicense(noticeProfile, { + sourceRoot: noticeSourceRoot, + }).spdx; + stageReleaseNotices(stage, { profile: noticeProfile, sourceRoot: noticeSourceRoot }); writeFileSync( path.join(stage, 'README.md'), `# ${identity.npm}\n\nOne ${identity.profile} ${identity.family} PostgreSQL cluster seed for ${identity.target}.\nSee manifest.json for physical compatibility and producer identity.\n${identity.profile === 'icu' ? 'ICU data comes from the separate canonical ICU dependency.\n' : ''}`, @@ -131,6 +142,7 @@ export function packageSeedCarriers(argv = [], { assetDir, outputDir, sourceDir target: identity.target, profile: identity.profile, icuData, + contract, }); rmSync(icuStage, { recursive: true, force: true }); directory = `${bundle}/${resource}/files`; @@ -191,7 +203,7 @@ export function packageSeedCarriers(argv = [], { assetDir, outputDir, sourceDir const crate = packageGeneratedCargoSource( path.join(stage, 'Cargo.toml'), path.join(output, 'cargo'), - { root: ROOT }, + { root: ROOT, fixedFileMode: 0o644 }, ); if (statSync(crate).size > 10 * 1024 * 1024) throw new Error(`${identity.cargo} exceeds the registry package limit`); diff --git a/src/database-resources/seeds/package-mobile-carriers.mts b/src/database-resources/seeds/package-mobile-carriers.mts index 0454fcfb5..440657d7e 100644 --- a/src/database-resources/seeds/package-mobile-carriers.mts +++ b/src/database-resources/seeds/package-mobile-carriers.mts @@ -7,17 +7,18 @@ import { createDeterministicTar, createDeterministicZip, } from '../../../tools/packaging/archive-directory.mts'; +import { stageMavenArtifactManifest } from '../../../tools/packaging/maven-artifact-staging.mts'; import { extractPortableArchiveTree } from '../../../tools/packaging/portable-archive.mts'; import { releaseProfileMavenLicenses, releaseProfilePackageLicense, stageReleaseNotices, } from '../../../tools/packaging/release-notices.mts'; -import { stageMavenArtifactManifest } from '../../../tools/packaging/maven-artifact-staging.mts'; import { currentProductVersionSync, ROOT, } from '../../../tools/release/release-artifact-targets.mts'; +import { validateNativeIcuDataManifest } from '../contracts/icu-data.mts'; import { bindNativeClusterSeedManifest, filesystemTreeRows, @@ -25,14 +26,21 @@ import { nativeClusterSeedCompatibilityKey, validateNativeClusterSeedDirectory, } from '../contracts/native-manifest.mts'; -import { validateNativeIcuDataManifest } from '../contracts/icu-data.mts'; -const contract = JSON.parse( +const defaultContract = JSON.parse( readFileSync(new URL('../contracts/contract.json', import.meta.url), 'utf8'), ); /** Adapt the canonical seed into the existing native mobile resource contract. */ -export function stageMobileSeed({ archive, manifest, destination, target, profile, icuData }) { +export function stageMobileSeed({ + archive, + manifest, + destination, + target, + profile, + icuData, + contract = defaultContract, +}) { if ( !['android-datum64', 'ios-datum64'].includes(target) || !['standard', 'icu'].includes(profile) @@ -75,9 +83,9 @@ export function stageMobileSeed({ archive, manifest, destination, target, profil cacheKey: logicalTreeSha256(filesystemTreeRows(files)), }; const unbound = Buffer.from( - Object.entries(properties) + `${Object.entries(properties) .map(([key, value]) => `${key}=${value}`) - .join('\n') + '\n', + .join('\n')}\n`, ); writeFileSync( path.join(destination, 'manifest.properties'), @@ -93,8 +101,12 @@ export async function packageMobileSeedCarriers({ assetDir, workDir, mavenDir, + version = currentProductVersionSync('database-resources'), + noticeSourceRoot, + contract = defaultContract, } = {}) { - const version = currentProductVersionSync('database-resources'); + if (!/^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u.test(version)) + throw new Error('mobile seed carriers require an exact resource version'); const assets = path.resolve( assetDir ?? path.join(ROOT, 'target/database-resources/release-assets'), ); @@ -137,8 +149,12 @@ export async function packageMobileSeedCarriers({ target, profile, icuData: profile === 'icu' ? path.join(extractedIcu, 'share/icu') : undefined, + contract, + }); + stageReleaseNotices(swift ? swiftRoot : stage, { + profile: swift ? 'native-runtime' : 'native-runtime-resources', + sourceRoot: noticeSourceRoot, }); - stageReleaseNotices(swift ? swiftRoot : stage, { profile: 'native-runtime-resources' }); if (swift) { writeFileSync( path.join(resourceRoot, 'Resources.swift'), @@ -161,11 +177,14 @@ export async function packageMobileSeedCarriers({ `Selectable PostgreSQL native ${profile} cluster seed for Android.`, '', '', - releaseProfilePackageLicense('native-runtime-resources').spdx, + releaseProfilePackageLicense('native-runtime-resources', { + sourceRoot: noticeSourceRoot, + }).spdx, JSON.stringify( releaseProfileMavenLicenses('native-runtime-resources', { product: 'database-resources', version, + sourceRoot: noticeSourceRoot, }), ), ].join('\t'), @@ -205,10 +224,11 @@ export async function packageMobileSeedCarriers({ } if (rows.length) { const manifest = path.join(work, 'maven.tsv'); - writeFileSync(manifest, rows.join('\n') + '\n'); + writeFileSync(manifest, `${rows.join('\n')}\n`); await stageMavenArtifactManifest( manifest, mavenDir ?? path.join(ROOT, 'target/release/maven-staging/database-resources-seeds'), + { noticeSourceRoot }, ); } return results; diff --git a/src/database-resources/seeds/package-mobile-carriers.test.mts b/src/database-resources/seeds/package-mobile-carriers.test.mts index cc8c0c52e..c00fcbf56 100644 --- a/src/database-resources/seeds/package-mobile-carriers.test.mts +++ b/src/database-resources/seeds/package-mobile-carriers.test.mts @@ -13,10 +13,15 @@ import os from 'node:os'; import path from 'node:path'; import { createDeterministicTar } from '../../../tools/packaging/archive-directory.mts'; import { + canonicalGzipSync, readPortableArchiveEntries, releaseZstdCompressSync, } from '../../../tools/packaging/portable-archive.mts'; -import { currentProductVersionSync } from '../../../tools/release/release-artifact-targets.mts'; +import { + assertReleaseNoticesInEntries, + stageReleaseNotices, +} from '../../../tools/packaging/release-notices.mts'; +import { nativeIcuDataManifest, parseNativeIcuDataIdentity } from '../contracts/icu-data.mts'; import { NATIVE_PGDATA_DIRECTORIES, nativeClusterSeedCompatibilityKey, @@ -79,7 +84,8 @@ test('mobile carrier preserves seed bytes and rejects wrong target, profile and const work = path.join(scratch, 'mobile-carriers'); const maven = path.join(scratch, 'maven'); mkdirSync(assets); - const version = currentProductVersionSync('database-resources'); + // Explicit action context must not fall back to the checkout's current owner version. + const version = '7.8.9'; const stem = `database-resources-${version}-seed-native-android-datum64-standard`; copyFileSync(archive, path.join(assets, `${stem}.tar.zst`)); copyFileSync(manifest, path.join(assets, `${stem}.json`)); @@ -90,6 +96,8 @@ test('mobile carrier preserves seed bytes and rejects wrong target, profile and assetDir: assets, workDir: work, mavenDir: maven, + version, + contract, }); expect(readdirSync(assets).sort()).toEqual(inputNames); expect(outputs).toEqual([path.join(work, `${stem}-maven.tar.gz`)]); @@ -109,6 +117,12 @@ test('mobile carrier preserves seed bytes and rejects wrong target, profile and ), ), ).toEqual(readFileSync(outputs[0])); + expect( + readFileSync( + path.join(maven, 'dev/oliphaunt/runtime', artifact, version, `${artifact}-${version}.pom`), + 'utf8', + ), + ).toContain('7.8.9'); writeFileSync(archive, Buffer.from('corrupt')); expect(() => stageMobileSeed(options)).toThrow('checksum'); @@ -116,3 +130,114 @@ test('mobile carrier preserves seed bytes and rejects wrong target, profile and rmSync(scratch, { recursive: true, force: true }); } }); + +test('Swift carrier preserves both seed profiles, ICU data and complete canonical legal inputs', async () => { + const scratch = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-swift-seed-carrier-')); + try { + const version = '7.8.9'; + const assets = path.join(scratch, 'assets'); + const sourceRoot = path.resolve(import.meta.dir, '../../..'); + const legalRoot = path.join(scratch, 'legal'); + mkdirSync(assets); + for (const relative of [ + 'LICENSE', + 'THIRD_PARTY_NOTICES.md', + 'src/native/runtime/THIRD_PARTY_NOTICES.md', + 'src/third-party/postgres/COPYRIGHT', + 'src/third-party/postgres/source.toml', + 'src/third-party/icu/LICENSE', + 'src/third-party/icu/source.toml', + ]) { + const destination = path.join(legalRoot, relative); + mkdirSync(path.dirname(destination), { recursive: true }); + copyFileSync(path.join(sourceRoot, relative), destination); + } + const icu = path.join(scratch, 'icu'); + const data = path.join(icu, 'share/icu'); + mkdirSync(data, { recursive: true }); + const dataBytes = Buffer.from('ICU archive fixture data'); + writeFileSync(path.join(data, 'icudt76l.dat'), dataBytes); + const icuManifest = nativeIcuDataManifest(data); + const identity = parseNativeIcuDataIdentity(icuManifest); + writeFileSync(path.join(icu, 'manifest.properties'), icuManifest); + stageReleaseNotices(icu, { profile: 'native-icu-data', sourceRoot: legalRoot }); + writeFileSync( + path.join(assets, `database-resources-${version}-icu-data.tar.gz`), + canonicalGzipSync(await createDeterministicTar(icu)), + ); + const seed = path.join(scratch, 'seed'); + for (const directory of NATIVE_PGDATA_DIRECTORIES) + mkdirSync(path.join(seed, directory), { recursive: true }); + writeFileSync(path.join(seed, 'PG_VERSION'), '18\n'); + const controlBytes = Buffer.from('archive-layout-fixture-only'); + writeFileSync(path.join(seed, 'global/pg_control'), controlBytes); + const seedBytes = releaseZstdCompressSync(await createDeterministicTar(seed)); + const contract = JSON.parse( + readFileSync(new URL('../contracts/contract.json', import.meta.url), 'utf8'), + ); + for (const profile of ['standard', 'icu']) { + const stem = `database-resources-${version}-seed-native-ios-datum64-${profile}`; + writeFileSync(path.join(assets, `${stem}.tar.zst`), seedBytes); + writeFileSync( + path.join(assets, `${stem}.json`), + JSON.stringify({ + schema: contract.manifests.wasix.schema, + catalogProfile: profile, + artifactRole: contract.profiles[profile].artifactRole, + runtime: { + engineFamily: 'native', + target: 'ios-datum64', + postgresMajor: 18, + physicalFormat: contract.physicalFormats.native, + compatibilityKey: nativeClusterSeedCompatibilityKey('ios-datum64'), + }, + archive: { sha256: createHash('sha256').update(seedBytes).digest('hex') }, + icu: profile === 'icu' ? identity : null, + }), + ); + } + const outputs = await packageMobileSeedCarriers({ + targets: ['ios-datum64'], + profiles: ['standard', 'icu'], + assetDir: assets, + workDir: path.join(scratch, 'mobile'), + version, + contract, + noticeSourceRoot: legalRoot, + }); + expect(outputs).toEqual([path.join(assets, `database-resources-${version}-swift.zip`)]); + const entries = readPortableArchiveEntries(outputs[0]); + assertReleaseNoticesInEntries(entries, { profile: 'native-runtime', sourceRoot: legalRoot }); + expect(entries.get('THIRD_PARTY_LICENSES/ICU-LICENSE').data()).toEqual( + readFileSync(path.join(legalRoot, 'src/third-party/icu/LICENSE')), + ); + expect(entries.get('Sources/OliphauntICU/share/icu/icudt76l.dat').data()).toEqual(dataBytes); + expect(entries.get('Sources/OliphauntICU/manifest.properties').data()).toEqual(icuManifest); + expect( + [...entries.keys()].filter((name) => /^Sources\/[^/]+\/Resources.swift$/u.test(name)).sort(), + ).toEqual([ + 'Sources/OliphauntICU/Resources.swift', + 'Sources/OliphauntSeedNativeIOSICU/Resources.swift', + 'Sources/OliphauntSeedNativeIOSStandard/Resources.swift', + ]); + for (const [name, resource, profile] of [ + ['OliphauntSeedNativeIOSStandard', 'cluster-seed', 'standard'], + ['OliphauntSeedNativeIOSICU', 'cluster-seed-icu', 'icu'], + ]) { + const prefix = `Sources/${name}/${resource}`; + expect(entries.get(`${prefix}/files/global/pg_control`).data()).toEqual(controlBytes); + const manifest = parseProperties(entries.get(`${prefix}/manifest.properties`).data(), prefix); + expect(manifest.get('target')).toBe('ios-datum64'); + expect(manifest.get('catalogProfile')).toBe(profile); + expect(manifest.get('runtimeFeatures')).toBe(profile === 'icu' ? 'icu' : ''); + expect(manifest.get('icuDataTreeSha256')).toBe( + profile === 'icu' ? identity.dataTreeSha256 : '', + ); + } + expect( + [...entries.keys()].some((name) => /(?:^|\/)(?:extensions|static-registry)\//u.test(name)), + ).toBe(false); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +}); diff --git a/src/database-resources/seeds/package.mts b/src/database-resources/seeds/package.mts index c6b46e7d5..4ef7baedb 100644 --- a/src/database-resources/seeds/package.mts +++ b/src/database-resources/seeds/package.mts @@ -2,10 +2,11 @@ import { createHash } from 'node:crypto'; import { mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'; import path from 'node:path'; -import { parseArgs } from 'node:util'; +import { isDeepStrictEqual, parseArgs } from 'node:util'; import { createDeterministicTar } from '../../../tools/packaging/archive-directory.mts'; import { releaseZstdCompressSync } from '../../../tools/packaging/portable-archive.mts'; import { currentProductVersionSync } from '../../../tools/release/release-artifact-targets.mts'; +import { productCompatibilityVersion } from '../../../tools/release/release-graph.mts'; import { filesystemTreeRows, logicalTreeSha256, @@ -13,96 +14,181 @@ import { validatePgdataDirectories, } from '../contracts/native-manifest.mts'; -const { values } = parseArgs({ - options: Object.fromEntries( - ['family', 'profile', 'target', 'pgdata', 'runtime', 'icu-data', 'output-dir'].map((name) => [ - name, - { type: 'string' }, - ]), - ), -}); -const { family, profile, target, pgdata, runtime } = values; -if ( - !['native', 'wasix'].includes(family) || - !['standard', 'icu'].includes(profile) || - !pgdata || - !runtime || - !target -) - throw new Error('family, profile, target, pgdata and runtime are required'); -if ((profile === 'icu') !== Boolean(values['icu-data'])) - throw new Error('only ICU seeds require --icu-data'); -const contract = JSON.parse( - readFileSync(new URL('../contracts/contract.json', import.meta.url), 'utf8'), -); -const postgresMajor = Number(readFileSync(path.join(pgdata, 'PG_VERSION'), 'utf8').trim()); -validatePgdataDirectories(pgdata); -if (postgresMajor !== 18 || statSync(path.join(pgdata, 'global/pg_control')).size === 0) - throw new Error('seed is not a complete PostgreSQL 18 cluster'); -const digest = (bytes) => createHash('sha256').update(bytes).digest('hex'); -const executable = (name) => - path.join(runtime, 'bin', `${name}${target.startsWith('windows-') ? '.exe' : ''}`); -const runtimeDigest = digest(readFileSync(executable('postgres'))); -const initdbDigest = digest(readFileSync(executable('initdb'))); -const version = currentProductVersionSync('database-resources'); -const name = `database-resources-${version}-seed-${family}${family === 'native' ? `-${target}` : ''}-${profile}`; -const output = path.resolve(values['output-dir'] ?? 'target/database-resources/release-assets'); -const rows = filesystemTreeRows(pgdata); -let directories = 0; -function countDirectories(root) { - for (const entry of readdirSync(root, { withFileTypes: true })) - if (entry.isDirectory()) { - directories++; - countDirectories(path.join(root, entry.name)); - } -} -countDirectories(pgdata); -const archive = releaseZstdCompressSync(await createDeterministicTar(pgdata)); -const icu = - profile === 'icu' - ? { - artifactRole: contract.icu.artifactRole, - dataVersion: contract.icu.dataVersion, - dataForm: contract.icu.dataForm, - dataTreeSha256: logicalTreeSha256(filesystemTreeRows(values['icu-data'])), +export async function packageClusterSeed({ + family, + profile, + target, + pgdata, + runtime, + icuData, + outputDir, + version, + runtimeVersion, + contract, + producer, + nativeSourceManifest, +}) { + if ( + !['native', 'wasix'].includes(family) || + !['standard', 'icu'].includes(profile) || + !pgdata || + (!runtime && !(family === 'native' && producer)) || + !target + ) + throw new Error('family, profile, target, pgdata and runtime are required'); + if ((profile === 'icu') !== Boolean(icuData)) + throw new Error('only ICU seeds require --icu-data'); + const originalNative = + nativeSourceManifest === undefined ? undefined : JSON.parse(nativeSourceManifest); + if (originalNative) { + if (family !== 'native' || !producer) + throw new Error('original native descriptor requires native producer facts'); + runtimeVersion = originalNative.runtime?.version; + } + if ( + ![version, runtimeVersion].every((value) => + /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u.test(value), + ) + ) + throw new Error('seed packaging requires exact resource and consumed runtime versions'); + contract ??= JSON.parse( + readFileSync(new URL('../contracts/contract.json', import.meta.url), 'utf8'), + ); + const postgresMajor = Number(readFileSync(path.join(pgdata, 'PG_VERSION'), 'utf8').trim()); + validatePgdataDirectories(pgdata); + if (postgresMajor !== 18 || statSync(path.join(pgdata, 'global/pg_control')).size === 0) + throw new Error('seed is not a complete PostgreSQL 18 cluster'); + const digest = (bytes) => createHash('sha256').update(bytes).digest('hex'); + const executable = (name) => + path.join(runtime, 'bin', `${name}${target.startsWith('windows-') ? '.exe' : ''}`); + const runtimeDigest = + family === 'wasix' || !producer ? digest(readFileSync(executable('postgres'))) : undefined; + producer ??= { + postgresSha256: runtimeDigest, + initdbSha256: digest(readFileSync(executable('initdb'))), + }; + for (const value of [producer.postgresSha256, producer.initdbSha256]) + if (!/^[a-f0-9]{64}$/u.test(value)) + throw new Error('seed original producer requires exact hashes'); + const name = `database-resources-${version}-seed-${family}${family === 'native' ? `-${target}` : ''}-${profile}`; + const output = path.resolve(outputDir ?? 'target/database-resources/release-assets'); + const rows = filesystemTreeRows(pgdata); + let directories = 0; + function countDirectories(root) { + for (const entry of readdirSync(root, { withFileTypes: true })) + if (entry.isDirectory()) { + directories++; + countDirectories(path.join(root, entry.name)); } - : null; -const manifest = { - schema: contract.manifests.wasix.schema, - artifactRole: contract.profiles[profile].artifactRole, - catalogProfile: profile, - runtime: { - product: `liboliphaunt-${family}`, - version: currentProductVersionSync(`liboliphaunt-${family}`), - engineFamily: family, - target, - physicalFormat: contract.physicalFormats[family], - postgresMajor, - compatibilityKey: - family === 'native' - ? nativeClusterSeedCompatibilityKey(target) - : contract.compatibilityKeys.wasixDatum32, - ...(family === 'wasix' - ? { consumerSha256: runtimeDigest, producerSha256: runtimeDigest, initdbSha256: initdbDigest } - : {}), - }, - source: { - producer: `${family}-initdb`, - ...(family === 'native' ? { postgresSha256: runtimeDigest, initdbSha256: initdbDigest } : {}), - }, - archive: { - path: `${name}.tar.zst`, - sha256: digest(archive), - compressedBytes: archive.length, - expandedBytes: rows.reduce((sum, row) => sum + row.bytes.length, 0), - regularFiles: rows.length, - directories, - }, - requiredRuntimeFeatures: contract.profiles[profile].requiredRuntimeFeatures, - extensions: { selected: [], startupConfiguration: [] }, - icu, -}; -mkdirSync(output, { recursive: true }); -writeFileSync(path.join(output, `${name}.tar.zst`), archive); -writeFileSync(path.join(output, `${name}.json`), `${JSON.stringify(manifest, null, 2)}\n`); -console.log(path.join(output, `${name}.tar.zst`)); + } + countDirectories(pgdata); + const archive = releaseZstdCompressSync(await createDeterministicTar(pgdata)); + const icu = + profile === 'icu' + ? { + artifactRole: contract.icu.artifactRole, + dataVersion: contract.icu.dataVersion, + dataForm: contract.icu.dataForm, + dataTreeSha256: logicalTreeSha256(filesystemTreeRows(icuData)), + } + : null; + if (originalNative) { + const expectedRuntime = { + product: 'liboliphaunt-native', + engineFamily: 'native', + target, + physicalFormat: contract.physicalFormats.native, + postgresMajor, + compatibilityKey: nativeClusterSeedCompatibilityKey(target), + }; + for (const [key, value] of Object.entries(expectedRuntime)) + if (originalNative.runtime?.[key] !== value) + throw new Error(`original native descriptor physical identity differs: ${key}`); + if ( + originalNative.schema !== contract.manifests.wasix.schema || + originalNative.catalogProfile !== profile || + originalNative.artifactRole !== contract.profiles[profile].artifactRole || + originalNative.source?.producer !== 'native-initdb' || + originalNative.source.postgresSha256 !== producer.postgresSha256 || + originalNative.source.initdbSha256 !== producer.initdbSha256 + ) + throw new Error('original native descriptor producer/profile differs'); + if ( + !isDeepStrictEqual(originalNative.icu, icu) || + !isDeepStrictEqual( + originalNative.requiredRuntimeFeatures, + contract.profiles[profile].requiredRuntimeFeatures, + ) || + !isDeepStrictEqual(originalNative.extensions, { selected: [], startupConfiguration: [] }) + ) + throw new Error('original native descriptor catalog/ICU requirements differ'); + } + const manifest = { + schema: contract.manifests.wasix.schema, + artifactRole: contract.profiles[profile].artifactRole, + catalogProfile: profile, + runtime: originalNative?.runtime ?? { + product: `liboliphaunt-${family}`, + version: runtimeVersion, + engineFamily: family, + target, + physicalFormat: contract.physicalFormats[family], + postgresMajor, + compatibilityKey: + family === 'native' + ? nativeClusterSeedCompatibilityKey(target) + : contract.compatibilityKeys.wasixDatum32, + ...(family === 'wasix' + ? { + consumerSha256: runtimeDigest, + producerSha256: producer.postgresSha256, + initdbSha256: producer.initdbSha256, + } + : {}), + }, + source: originalNative?.source ?? { + producer: `${family}-initdb`, + ...(family === 'native' ? producer : {}), + }, + archive: { + path: `${name}.tar.zst`, + sha256: digest(archive), + compressedBytes: archive.length, + expandedBytes: rows.reduce((sum, row) => sum + row.bytes.length, 0), + regularFiles: rows.length, + directories, + }, + requiredRuntimeFeatures: contract.profiles[profile].requiredRuntimeFeatures, + extensions: { selected: [], startupConfiguration: [] }, + icu, + }; + mkdirSync(output, { recursive: true }); + writeFileSync(path.join(output, `${name}.tar.zst`), archive); + writeFileSync(path.join(output, `${name}.json`), `${JSON.stringify(manifest, null, 2)}\n`); + return { + archive: path.join(output, `${name}.tar.zst`), + manifest: path.join(output, `${name}.json`), + }; +} + +if (import.meta.main) { + const { values } = parseArgs({ + options: Object.fromEntries( + ['family', 'profile', 'target', 'pgdata', 'runtime', 'icu-data', 'output-dir'].map((name) => [ + name, + { type: 'string' }, + ]), + ), + }); + const result = await packageClusterSeed({ + ...values, + icuData: values['icu-data'], + outputDir: values['output-dir'], + version: currentProductVersionSync('database-resources'), + runtimeVersion: + values.family === 'wasix' + ? productCompatibilityVersion('database-resources', 'liboliphaunt-wasix') + : currentProductVersionSync('liboliphaunt-native'), + }); + console.log(result.archive); +} diff --git a/src/database-resources/seeds/wasix/BUILD.bazel b/src/database-resources/seeds/wasix/BUILD.bazel new file mode 100644 index 000000000..e8d20476a --- /dev/null +++ b/src/database-resources/seeds/wasix/BUILD.bazel @@ -0,0 +1,43 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files") +load("//build_defs/languages:rust.bzl", "cargo_binary", "cargo_library", "cargo_library_test", "cargo_package_env") +load("@wasix_seed_crates//:defs.bzl", seed_all_crate_deps = "all_crate_deps", seed_crate_deps = "crate_deps") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["Cargo.toml", "consumer-contract.mts"]) + +cargo_package_env() + +cargo_library( + name = "lib", + features = ["cluster-seed-runner"], + proc_macro_names = ["async-trait"], + crate_dependencies = seed_crate_deps, + compile_data = [ + "//src/database-resources:contract_compile_data", + "//src/database-resources:profile_probe_compile_data", + ], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64", "@zig_sdk//libc:gnu.2.34"], +) + +cargo_binary( + name = "seed_runner", + source = "src/main.rs", + library = ":lib", + features = ["cluster-seed-runner"], + proc_macro_names = ["async-trait"], + crate_dependencies = seed_crate_deps, + experimental_use_cc_common_link = 1, + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64", "@zig_sdk//libc:gnu.2.34"], +) + +cargo_library_test( + name = "unit_test", + all_dependencies = seed_all_crate_deps, + features = ["cluster-seed-runner"], + experimental_use_cc_common_link = 1, + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64", "@zig_sdk//libc:gnu.2.34"], + size = "small", +) + +rust_quality_files() diff --git a/src/database-resources/seeds/wasix/Cargo.toml b/src/database-resources/seeds/wasix/Cargo.toml index d47bbd121..a6a7d525c 100644 --- a/src/database-resources/seeds/wasix/Cargo.toml +++ b/src/database-resources/seeds/wasix/Cargo.toml @@ -6,6 +6,9 @@ rust-version = "1.93" license.workspace = true publish = false +[package.metadata.oliphaunt] +runtime-version = "0.3.2" + [[bin]] name = "oliphaunt-wasix-seed-producer" path = "src/main.rs" diff --git a/src/database-resources/seeds/wasix/consumer-contract.mts b/src/database-resources/seeds/wasix/consumer-contract.mts new file mode 100644 index 000000000..672b41a49 --- /dev/null +++ b/src/database-resources/seeds/wasix/consumer-contract.mts @@ -0,0 +1,36 @@ +/** One authored WASIX seed consumer choice, shared by acquisition and Bazel. */ +import assert from 'node:assert/strict'; +export function wasixSeedConsumerDeclaration( + manifest: any, + version: string, + currentVersion: string, +) { + const authored = manifest?.package?.metadata?.oliphaunt; + assert.ok(authored && typeof authored === 'object', 'WASIX seed consumer metadata is missing'); + assert.match( + version, + /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u, + 'WASIX consumer version must be exact', + ); + assert.equal( + authored['runtime-version'], + version, + 'WASIX consumer declaration differs from its conventional compatibility pin', + ); + const source = authored['runtime-source'] ?? 'completed'; + assert.ok( + source === 'completed' || source === 'current', + 'WASIX runtime-source must be current or completed', + ); + assert.match(currentVersion, /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u); + // Current construction can satisfy only the explicitly requested source version. + // A later source version leaves the conventional pin held; its completed File + // remains mandatory and independently authenticated by acquisition. + return Object.freeze({ + source: + source === 'current' && version === currentVersion + ? ('current' as const) + : ('completed' as const), + version, + }); +} diff --git a/src/database-resources/seeds/wasix/consumer-contract.test.mts b/src/database-resources/seeds/wasix/consumer-contract.test.mts new file mode 100644 index 000000000..ced270f60 --- /dev/null +++ b/src/database-resources/seeds/wasix/consumer-contract.test.mts @@ -0,0 +1,51 @@ +import { expect, test } from 'bun:test'; +import { wasixSeedConsumerDeclaration } from './consumer-contract.mts'; +test('completed is the sole default and same version never infers current origin', () => { + const manifest = { + package: { + metadata: { + oliphaunt: { + 'runtime-version': '0.3.2', + 'runtime-source': undefined as string | undefined, + }, + }, + }, + }; + expect(wasixSeedConsumerDeclaration(manifest, '0.3.2', '0.3.2')).toEqual({ + source: 'completed', + version: '0.3.2', + }); + manifest.package.metadata.oliphaunt['runtime-source'] = 'current'; + expect(wasixSeedConsumerDeclaration(manifest, '0.3.2', '0.3.2')).toEqual({ + source: 'current', + version: '0.3.2', + }); + expect(() => wasixSeedConsumerDeclaration(manifest, '0.4.0', '0.4.0')).toThrow('conventional'); + manifest.package.metadata.oliphaunt['runtime-source'] = 'same-version'; + expect(() => wasixSeedConsumerDeclaration(manifest, '0.3.2', '0.3.2')).toThrow('runtime-source'); +}); + +test('current intent is scoped to its conventional pinned version across repeated release cycles', () => { + const manifest = { + package: { + metadata: { oliphaunt: { 'runtime-version': '0.3.2', 'runtime-source': 'current' } }, + }, + }; + expect(wasixSeedConsumerDeclaration(manifest, '0.3.2', '0.3.2').source).toBe('current'); + // A core-only release and the next ordinary source CI both retain the old exact request. + expect(wasixSeedConsumerDeclaration(manifest, '0.3.2', '0.3.3')).toEqual({ + source: 'completed', + version: '0.3.2', + }); + expect(wasixSeedConsumerDeclaration(manifest, '0.3.2', '0.3.4')).toEqual({ + source: 'completed', + version: '0.3.2', + }); + manifest.package.metadata.oliphaunt['runtime-version'] = '0.3.4'; + expect(wasixSeedConsumerDeclaration(manifest, '0.3.4', '0.3.4').source).toBe('current'); + // Completing an explicit new adoption leaves that source intent scoped to its exact version again. + expect(wasixSeedConsumerDeclaration(manifest, '0.3.4', '0.3.5')).toEqual({ + source: 'completed', + version: '0.3.4', + }); +}); diff --git a/src/database-resources/seeds/wasix/src/lib.rs b/src/database-resources/seeds/wasix/src/lib.rs index 7aada9464..fa39a8f6b 100644 --- a/src/database-resources/seeds/wasix/src/lib.rs +++ b/src/database-resources/seeds/wasix/src/lib.rs @@ -3,14 +3,14 @@ use std::path::Path; use anyhow::{Context, Result, bail}; -#[cfg(feature = "cluster-seed-runner")] +#[cfg(any(feature = "cluster-seed-runner", test))] pub const INTERNAL_ICU_READY_ENV: &str = "OLIPHAUNT_INTERNAL_ICU_READY"; -#[cfg(feature = "cluster-seed-runner")] +#[cfg(any(feature = "cluster-seed-runner", test))] pub const INTERNAL_ICU_READY_VALUE: &str = "1"; -#[cfg(feature = "cluster-seed-runner")] +#[cfg(any(feature = "cluster-seed-runner", test))] const SKIP_SYSTEM_COLLATION_DISCOVERY_ENV: &str = "OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY"; -#[cfg(feature = "cluster-seed-runner")] +#[cfg(any(feature = "cluster-seed-runner", test))] const SKIP_ICU_COLLATION_DISCOVERY_ENV: &str = "OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY"; #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -41,6 +41,30 @@ pub fn default_initdb_profile() -> &'static str { "allow-group-access,encoding=UTF8,locale=C.UTF-8,locale-provider=libc,auth=trust,no-sync" } +#[cfg(any(feature = "cluster-seed-runner", test))] +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)] +#[serde(rename_all = "camelCase")] +pub struct BootstrapRecipe { + pub schema: &'static str, + pub profile: &'static str, + pub command: &'static str, + pub working_directory: &'static str, + pub arguments: Vec<&'static str>, + pub environment: Vec<(&'static str, &'static str)>, +} + +#[cfg(any(feature = "cluster-seed-runner", test))] +pub fn bootstrap_recipe(profile: CatalogProfile) -> BootstrapRecipe { + BootstrapRecipe { + schema: "oliphaunt-wasix-bootstrap-recipe-v1", + profile: profile.as_str(), + command: "initdb", + working_directory: "/", + arguments: default_initdb_args(), + environment: cluster_seed_producer_environment(profile), + } +} + pub fn clean_generated_cluster_seed(pgdata: &Path) -> Result<()> { #[derive(serde::Deserialize)] #[serde(rename_all = "camelCase")] @@ -74,16 +98,109 @@ pub fn run_wasix_initdb_cluster_seed( profile: CatalogProfile, icu_data_root: Option<&Path>, ) -> Result<()> { - use std::env; + use wasmer_wasix::runners::wasi::{RuntimeOrEngine, WasiRunner}; + use wasmer_wasix::virtual_fs::null_file::NullFile; + + let recipe = bootstrap_recipe(profile); + with_wasix_cluster_seed_runner( + runtime_stage, + work_root, + profile, + icu_data_root, + None, + |seed_runner| { + let (stdout_file, stdout_capture) = TailCaptureFile::new(64 * 1024); + let (stderr_file, stderr_capture) = TailCaptureFile::new(64 * 1024); + let run_result = { + let mut runner = WasiRunner::new(); + runner.with_current_dir(recipe.working_directory); + runner.with_mount("/".to_owned(), seed_runner.root_fs.clone()); + runner.with_mount("/base".to_owned(), seed_runner.pgdata_fs.clone()); + runner.with_args(recipe.arguments.clone()); + runner.with_envs(recipe.environment.clone()); + runner.with_stdin(Box::::default()); + runner.with_stdout(Box::new(stdout_file)); + runner.with_stderr(Box::new(stderr_file)); + runner.run_command( + recipe.command, + &seed_runner.package, + RuntimeOrEngine::Runtime(seed_runner.runtime.clone()), + ) + }; + let stdout = stdout_capture.text(); + let stderr = stderr_capture.text(); + if std::env::var_os("OLIPHAUNT_WASM_CLUSTER_SEED_LOG").is_some() || run_result.is_err() + { + print_captured_wasix_output("initdb stdout", &stdout); + print_captured_wasix_output("initdb stderr", &stderr); + } + run_result.context("run WASIX initdb to generate cluster seed")?; + verify_wasix_cluster_seed_profile(seed_runner, profile) + }, + ) +} + +#[cfg(feature = "cluster-seed-runner")] +pub fn verify_wasix_cluster_seed( + runtime_stage: &Path, + work_root: &Path, + profile: CatalogProfile, + pgdata_source: &Path, + icu_data_root: Option<&Path>, +) -> Result<()> { + with_wasix_cluster_seed_runner( + runtime_stage, + work_root, + profile, + icu_data_root, + Some(pgdata_source), + |runner| { + verify_wasix_cluster_seed_profile(runner, profile)?; + runner.run_sql( + profile, + "CREATE TABLE public.oliphaunt_seed_consumer_probe (id integer PRIMARY KEY, marker text NOT NULL);\nINSERT INTO public.oliphaunt_seed_consumer_probe VALUES (1, 'persisted-after-reopen');\n", + "create and populate WASIX cluster-seed persistence probe", + )?; + let stdout = runner.run_sql( + profile, + "SELECT CASE WHEN count(*) = 1 AND min(marker) = 'persisted-after-reopen' THEN 'oliphaunt-wasix-seed-persistence-ok' ELSE 'oliphaunt-wasix-seed-persistence-invalid' END FROM public.oliphaunt_seed_consumer_probe WHERE id = 1;\n", + "reopen WASIX cluster seed and read persistence probe", + )?; + anyhow::ensure!( + stdout.contains("oliphaunt-wasix-seed-persistence-ok"), + "reopened WASIX cluster seed did not preserve the inserted row" + ); + Ok(()) + }, + ) +} + +#[cfg(feature = "cluster-seed-runner")] +struct ClusterSeedRunner { + package: wasmer_wasix::bin_factory::BinaryPackage, + runtime: std::sync::Arc, + root_fs: std::sync::Arc, + pgdata_fs: std::sync::Arc, +} + +#[cfg(feature = "cluster-seed-runner")] +fn with_wasix_cluster_seed_runner( + runtime_stage: &Path, + work_root: &Path, + profile: CatalogProfile, + icu_data_root: Option<&Path>, + pgdata_source: Option<&Path>, + run: impl FnOnce(&ClusterSeedRunner) -> Result<()>, +) -> Result<()> { use std::sync::Arc; use wasmer::Engine; use wasmer_wasix::bin_factory::BinaryPackage; - use wasmer_wasix::runners::wasi::{RuntimeOrEngine, WasiRunner}; use wasmer_wasix::runtime::task_manager::tokio::TokioTaskManager; use wasmer_wasix::runtime::{PluggableRuntime, Runtime}; use wasmer_wasix::virtual_fs; - use wasmer_wasix::virtual_fs::null_file::NullFile; + + validate_cluster_seed_work_root(runtime_stage, work_root, icu_data_root, pgdata_source)?; let package_dir = work_root.join("package"); let package_root = work_root.join("root"); @@ -92,6 +209,15 @@ pub fn run_wasix_initdb_cluster_seed( .with_context(|| format!("create {}", package_dir.join("modules").display()))?; fs::create_dir_all(&pgdata_root) .with_context(|| format!("create {}", pgdata_root.display()))?; + if let Some(source) = pgdata_source { + copy_tree(source, &pgdata_root)?; + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + fs::set_permissions(&pgdata_root, fs::Permissions::from_mode(0o700)) + .context("set private copied PGDATA permissions")?; + } + } copy_tree(runtime_stage, &package_root)?; let staged_icu_data = package_root.join("share/icu"); if staged_icu_data.exists() { @@ -101,13 +227,18 @@ pub fn run_wasix_initdb_cluster_seed( match (profile, icu_data_root) { (CatalogProfile::Standard, None) => {} (CatalogProfile::Standard, Some(_)) => { - bail!("standard cluster-seed generation must not receive ICU data") + bail!("standard cluster seed must not receive ICU data") } (CatalogProfile::Icu, Some(icu_data_root)) => { + anyhow::ensure!( + fs::symlink_metadata(icu_data_root.join("icudt76l.dat")) + .is_ok_and(|metadata| metadata.is_file() && metadata.len() > 0), + "ICU cluster seed requires a nonempty icudt76l.dat file" + ); copy_tree(icu_data_root, &staged_icu_data)?; } (CatalogProfile::Icu, None) => { - bail!("ICU cluster-seed generation requires verified ICU data") + bail!("ICU cluster seed requires verified ICU data") } } copy_file( @@ -148,7 +279,7 @@ module = "postgres" let tokio_runtime = tokio::runtime::Builder::new_multi_thread() .enable_all() .build() - .context("create Tokio runtime for WASIX cluster-seed generation")?; + .context("create Tokio runtime for WASIX cluster seed")?; let _guard = tokio_runtime.enter(); let engine = Engine::default(); let task_manager = Arc::new(TokioTaskManager::new(tokio_runtime.handle().clone())); @@ -158,7 +289,7 @@ module = "postgres" let runtime: Arc = Arc::new(runtime); let package = tokio_runtime .block_on(BinaryPackage::from_dir(&package_dir, runtime.as_ref())) - .context("load WASIX initdb package")?; + .context("load local WASIX cluster-seed package")?; let root_fs = Arc::new( virtual_fs::host_fs::FileSystem::new(tokio_runtime.handle().clone(), &package_root) .with_context(|| { @@ -178,32 +309,70 @@ module = "postgres" })?, ) as Arc; - let (stdout_file, stdout_capture) = TailCaptureFile::new(64 * 1024); - let (stderr_file, stderr_capture) = TailCaptureFile::new(64 * 1024); - let run_result = { - let mut runner = WasiRunner::new(); - runner.with_current_dir("/"); - runner.with_mount("/".to_owned(), root_fs.clone()); - runner.with_mount("/base".to_owned(), pgdata_fs.clone()); - runner.with_args(default_initdb_args()); - runner.with_envs(cluster_seed_producer_environment(profile)); - runner.with_stdin(Box::::default()); - runner.with_stdout(Box::new(stdout_file)); - runner.with_stderr(Box::new(stderr_file)); - runner.run_command( - "initdb", - &package, - RuntimeOrEngine::Runtime(runtime.clone()), - ) + run(&ClusterSeedRunner { + package, + runtime, + root_fs, + pgdata_fs, + }) +} + +#[cfg(feature = "cluster-seed-runner")] +fn validate_cluster_seed_work_root( + runtime_stage: &Path, + work_root: &Path, + icu_data_root: Option<&Path>, + pgdata_source: Option<&Path>, +) -> Result<()> { + anyhow::ensure!( + !work_root + .components() + .any(|component| component == std::path::Component::ParentDir), + "work directory must not contain parent components" + ); + anyhow::ensure!(!work_root.exists(), "work directory must be new"); + let mut ancestor = if work_root.is_absolute() { + work_root.to_path_buf() + } else { + std::env::current_dir()?.join(work_root) + }; + let mut missing = Vec::new(); + let mut resolved = loop { + match fs::canonicalize(&ancestor) { + Ok(path) => break path, + Err(error) if error.kind() == std::io::ErrorKind::NotFound => { + missing.push( + ancestor + .file_name() + .context("work directory has no existing ancestor")? + .to_os_string(), + ); + anyhow::ensure!(ancestor.pop(), "work directory has no existing ancestor"); + } + Err(error) => return Err(error).context("resolve cluster-seed work directory"), + } }; - let stdout = stdout_capture.text(); - let stderr = stderr_capture.text(); - if env::var_os("OLIPHAUNT_WASM_CLUSTER_SEED_LOG").is_some() || run_result.is_err() { - print_captured_wasix_output("initdb stdout", &stdout); - print_captured_wasix_output("initdb stderr", &stderr); + for component in missing.into_iter().rev() { + resolved.push(component); + } + match fs::symlink_metadata(&resolved) { + Ok(_) => bail!("work directory must be new"), + Err(error) if error.kind() == std::io::ErrorKind::NotFound => {} + Err(error) => return Err(error).context("inspect resolved cluster-seed work directory"), + } + for source in [Some(runtime_stage), pgdata_source, icu_data_root] + .into_iter() + .flatten() + { + let input = fs::canonicalize(source) + .with_context(|| format!("resolve seed input directory {}", source.display()))?; + anyhow::ensure!( + !resolved.starts_with(&input), + "work directory must be outside seed input directory {}", + source.display() + ); } - run_result.context("run WASIX initdb to generate cluster seed")?; - verify_wasix_cluster_seed_profile(&package, runtime, root_fs, pgdata_fs, profile) + Ok(()) } #[cfg(not(feature = "cluster-seed-runner"))] @@ -218,6 +387,17 @@ pub fn run_wasix_initdb_cluster_seed( ) } +#[cfg(not(feature = "cluster-seed-runner"))] +pub fn verify_wasix_cluster_seed( + _runtime_stage: &Path, + _work_root: &Path, + _profile: CatalogProfile, + _pgdata_source: &Path, + _icu_data_root: Option<&Path>, +) -> Result<()> { + bail!("WASIX seed verification requires the seed producer's `cluster-seed-runner` feature") +} + #[cfg_attr(not(feature = "cluster-seed-runner"), allow(dead_code))] fn default_initdb_args() -> Vec<&'static str> { vec![ @@ -233,7 +413,7 @@ fn default_initdb_args() -> Vec<&'static str> { ] } -#[cfg(feature = "cluster-seed-runner")] +#[cfg(any(feature = "cluster-seed-runner", test))] fn cluster_seed_environment(profile: CatalogProfile) -> Vec<(&'static str, &'static str)> { let mut environment = vec![ ("PGDATA", "/base"), @@ -254,7 +434,7 @@ fn cluster_seed_environment(profile: CatalogProfile) -> Vec<(&'static str, &'sta environment } -#[cfg(feature = "cluster-seed-runner")] +#[cfg(any(feature = "cluster-seed-runner", test))] fn cluster_seed_producer_environment(profile: CatalogProfile) -> Vec<(&'static str, &'static str)> { let mut environment = cluster_seed_environment(profile); environment.push((SKIP_SYSTEM_COLLATION_DISCOVERY_ENV, "1")); @@ -268,15 +448,9 @@ fn cluster_seed_producer_environment(profile: CatalogProfile) -> Vec<(&'static s #[cfg(feature = "cluster-seed-runner")] fn verify_wasix_cluster_seed_profile( - package: &wasmer_wasix::bin_factory::BinaryPackage, - runtime: std::sync::Arc, - root_fs: std::sync::Arc, - pgdata_fs: std::sync::Arc, + runner: &ClusterSeedRunner, profile: CatalogProfile, ) -> Result<()> { - use wasmer_wasix::runners::wasi::{RuntimeOrEngine, WasiRunner}; - use wasmer_wasix::virtual_fs; - const CONTRACT_JSON: &str = include_str!("../../../contracts/profile-probe.json"); let contract: ClusterSeedProfileProbeContract = @@ -293,46 +467,62 @@ fn verify_wasix_cluster_seed_profile( }; for attempt in 1..=2 { + let label = format!( + "{} WASIX cluster-seed profile probe (attempt {attempt})", + profile.as_str() + ); + let stdout = runner.run_sql(profile, &format!("{};\n", probe.sql), &label)?; + if !stdout.contains(&probe.expected) { + print_captured_wasix_output("profile probe stdout", &stdout); + bail!( + "{} WASIX cluster-seed profile probe attempt {attempt} did not emit {:?}", + profile.as_str(), + probe.expected + ); + } + } + Ok(()) +} + +#[cfg(feature = "cluster-seed-runner")] +impl ClusterSeedRunner { + fn run_sql(&self, profile: CatalogProfile, sql: &str, label: &str) -> Result { + use wasmer_wasix::runners::wasi::{RuntimeOrEngine, WasiRunner}; + use wasmer_wasix::virtual_fs; + let (stdout_file, stdout_capture) = TailCaptureFile::new(64 * 1024); let (stderr_file, stderr_capture) = TailCaptureFile::new(64 * 1024); let mut runner = WasiRunner::new(); runner.with_current_dir("/"); - runner.with_mount("/".to_owned(), root_fs.clone()); - runner.with_mount("/base".to_owned(), pgdata_fs.clone()); + runner.with_mount("/".to_owned(), self.root_fs.clone()); + runner.with_mount("/base".to_owned(), self.pgdata_fs.clone()); runner.with_args(vec!["--single", "-D", "/base", "postgres"]); runner.with_envs(cluster_seed_environment(profile)); runner.with_stdin(Box::new(virtual_fs::StaticFile::new( - format!("{};\n", probe.sql).into_bytes(), + sql.as_bytes().to_vec(), ))); runner.with_stdout(Box::new(stdout_file)); runner.with_stderr(Box::new(stderr_file)); let result = runner.run_command( "postgres", - package, - RuntimeOrEngine::Runtime(runtime.clone()), + &self.package, + RuntimeOrEngine::Runtime(self.runtime.clone()), ); let stdout = stdout_capture.text(); let stderr = stderr_capture.text(); - let failed = result.is_err() || !stdout.contains(&probe.expected); + let sql_failed = stdout_capture.saw_postgres_error() || stderr_capture.saw_postgres_error(); + let failed = result.is_err() || sql_failed; if std::env::var_os("OLIPHAUNT_WASM_CLUSTER_SEED_LOG").is_some() || failed { - print_captured_wasix_output("profile probe stdout", &stdout); - print_captured_wasix_output("profile probe stderr", &stderr); - } - result.with_context(|| { - format!( - "run {} WASIX cluster-seed profile probe (attempt {attempt})", - profile.as_str() - ) - })?; - if !stdout.contains(&probe.expected) { - bail!( - "{} WASIX cluster-seed profile probe attempt {attempt} did not emit {:?}", - profile.as_str(), - probe.expected - ); + print_captured_wasix_output(&format!("{label} stdout"), &stdout); + print_captured_wasix_output(&format!("{label} stderr"), &stderr); } + result.with_context(|| format!("run {label}"))?; + anyhow::ensure!( + !sql_failed, + "{label} emitted PostgreSQL ERROR, FATAL, or PANIC" + ); + Ok(stdout) } - Ok(()) } #[cfg(feature = "cluster-seed-runner")] @@ -385,6 +575,7 @@ struct TailCaptureFile { #[derive(Debug, Default)] struct TailCaptureState { bytes: std::collections::VecDeque, + postgres_error: bool, } #[cfg(feature = "cluster-seed-runner")] @@ -410,6 +601,19 @@ impl TailCaptureFile { let Ok(mut state) = self.inner.lock() else { return; }; + // Keep failure evidence even when later output displaces it from the captured tail. + let mut scan = state + .bytes + .iter() + .rev() + .take(5) + .copied() + .collect::>(); + scan.reverse(); + scan.extend_from_slice(bytes); + state.postgres_error |= scan + .windows(6) + .any(|window| matches!(window, b"ERROR:" | b"FATAL:" | b"PANIC:")); for byte in bytes { state.bytes.push_back(*byte); while state.bytes.len() > self.limit { @@ -421,6 +625,13 @@ impl TailCaptureFile { #[cfg(feature = "cluster-seed-runner")] impl TailCaptureHandle { + fn saw_postgres_error(&self) -> bool { + self.inner + .lock() + .map(|state| state.postgres_error) + .unwrap_or(true) + } + fn text(&self) -> String { let Ok(state) = self.inner.lock() else { return "".to_owned(); @@ -585,6 +796,11 @@ fn copy_file(source: &Path, destination: &Path) -> Result<()> { #[cfg(feature = "cluster-seed-runner")] fn copy_tree(source: &Path, destination: &Path) -> Result<()> { + anyhow::ensure!( + fs::symlink_metadata(source)?.is_dir(), + "seed input must be a regular directory: {}", + source.display() + ); fs::create_dir_all(destination)?; for entry in fs::read_dir(source)? { let entry = entry?; @@ -607,6 +823,44 @@ fn copy_tree(source: &Path, destination: &Path) -> Result<()> { mod layout_tests { use super::*; + #[test] + fn bootstrap_recipe_describes_the_actual_profile_policy() -> Result<()> { + for profile in CatalogProfile::ALL { + let recipe = bootstrap_recipe(profile); + assert_eq!(recipe.profile, profile.as_str()); + assert_eq!(recipe.arguments, default_initdb_args()); + assert_eq!( + recipe.environment, + cluster_seed_producer_environment(profile) + ); + let json = serde_json::to_value(&recipe)?; + assert_eq!(json["schema"], "oliphaunt-wasix-bootstrap-recipe-v1"); + assert_eq!(json["command"], "initdb"); + assert_eq!(json["workingDirectory"], "/"); + assert_eq!(json["arguments"], serde_json::to_value(&recipe.arguments)?); + assert_eq!( + json["environment"], + serde_json::to_value(&recipe.environment)? + ); + let environment: std::collections::BTreeMap<_, _> = + recipe.environment.into_iter().collect(); + assert_eq!(environment[SKIP_SYSTEM_COLLATION_DISCOVERY_ENV], "1"); + if profile == CatalogProfile::Standard { + assert_eq!(environment[SKIP_ICU_COLLATION_DISCOVERY_ENV], "1"); + assert!(!environment.contains_key(INTERNAL_ICU_READY_ENV)); + assert!(!environment.contains_key("ICU_DATA")); + } else { + assert_eq!( + environment[INTERNAL_ICU_READY_ENV], + INTERNAL_ICU_READY_VALUE + ); + assert_eq!(environment["ICU_DATA"], "/share/icu"); + assert!(!environment.contains_key(SKIP_ICU_COLLATION_DISCOVERY_ENV)); + } + } + Ok(()) + } + #[test] fn rejects_missing_empty_pgdata_directory() -> Result<()> { let nonce = std::time::SystemTime::now() @@ -628,4 +882,139 @@ mod layout_tests { assert!(error.to_string().contains("pg_notify")); Ok(()) } + + #[cfg(feature = "cluster-seed-runner")] + fn work_root_fixture() -> Result { + let nonce = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH)? + .as_nanos(); + let root = std::env::temp_dir().join(format!( + "oliphaunt-seed-work-root-{}-{nonce}", + std::process::id() + )); + for name in ["runtime", "pgdata", "icu", "outside"] { + fs::create_dir_all(root.join(name))?; + } + Ok(root) + } + + #[cfg(feature = "cluster-seed-runner")] + #[test] + fn rejects_work_inside_inputs_before_creating_missing_parents() -> Result<()> { + let root = work_root_fixture()?; + let runtime = root.join("runtime"); + let pgdata = root.join("pgdata"); + let icu = root.join("icu"); + for input in [&runtime, &pgdata, &icu] { + let work = input.join("missing/also-missing/work"); + let error = validate_cluster_seed_work_root(&runtime, &work, Some(&icu), Some(&pgdata)) + .unwrap_err(); + assert!(error.to_string().contains("outside seed input directory")); + assert!(!input.join("missing").exists()); + let error = validate_cluster_seed_work_root(&runtime, input, Some(&icu), Some(&pgdata)) + .unwrap_err(); + assert!(error.to_string().contains("work directory must be new")); + } + fs::remove_dir_all(root)?; + Ok(()) + } + + #[cfg(feature = "cluster-seed-runner")] + #[test] + fn accepts_unrelated_new_workspace_without_creating_it() -> Result<()> { + let root = work_root_fixture()?; + let work = root.join("outside/missing/also-missing/work"); + validate_cluster_seed_work_root( + &root.join("runtime"), + &work, + Some(&root.join("icu")), + Some(&root.join("pgdata")), + )?; + assert!(!root.join("outside/missing").exists()); + fs::remove_dir_all(root)?; + Ok(()) + } + + #[cfg(feature = "cluster-seed-runner")] + #[test] + fn rejects_parent_components_before_mutating_inputs() -> Result<()> { + let root = work_root_fixture()?; + let runtime = root.join("runtime"); + let pgdata = root.join("pgdata"); + let icu = root.join("icu"); + for input in [&runtime, &pgdata, &icu] { + fs::write(input.join("frozen-input"), "unchanged")?; + let work = input.join("missing/../../outside/work"); + let error = validate_cluster_seed_work_root(&runtime, &work, Some(&icu), Some(&pgdata)) + .unwrap_err(); + assert!( + error + .to_string() + .contains("must not contain parent components") + ); + assert_eq!(fs::read_to_string(input.join("frozen-input"))?, "unchanged"); + assert_eq!(fs::read_dir(input)?.count(), 1); + } + assert!(!root.join("outside/work").exists()); + fs::remove_dir_all(root)?; + Ok(()) + } + + #[cfg(all(feature = "cluster-seed-runner", unix))] + #[test] + fn rejects_work_inside_symlink_aliased_inputs() -> Result<()> { + let root = work_root_fixture()?; + let runtime = root.join("runtime"); + let pgdata = root.join("pgdata"); + let icu = root.join("icu"); + let aliases = [ + root.join("runtime-alias"), + root.join("pgdata-alias"), + root.join("icu-alias"), + ]; + for (input, alias) in [&runtime, &pgdata, &icu].into_iter().zip(&aliases) { + std::os::unix::fs::symlink(input, alias)?; + } + for (input, alias) in [&runtime, &pgdata, &icu].into_iter().zip(&aliases) { + for work in [ + input.join("missing/also-missing/work"), + alias.join("missing/also-missing/work"), + ] { + let error = validate_cluster_seed_work_root( + &aliases[0], + &work, + Some(&aliases[2]), + Some(&aliases[1]), + ) + .unwrap_err(); + assert!(error.to_string().contains("outside seed input directory")); + assert!(!input.join("missing").exists()); + } + } + fs::remove_dir_all(root)?; + Ok(()) + } + + #[cfg(feature = "cluster-seed-runner")] + #[test] + fn retains_postgres_errors_across_chunks_and_tail_eviction() { + for severity in [b"ERROR:".as_slice(), b"FATAL:", b"PANIC:"] { + let (file, capture) = TailCaptureFile::new(64); + file.push_tail(&severity[..3]); + assert!(!capture.saw_postgres_error()); + file.push_tail(&severity[3..]); + file.push_tail(&vec![b' '; 128]); + file.push_tail(b"oliphaunt-standard-seed-ok"); + assert!(capture.text().contains("oliphaunt-standard-seed-ok")); + assert!( + !capture + .text() + .contains(std::str::from_utf8(severity).unwrap()) + ); + assert!(capture.saw_postgres_error()); + } + let (file, capture) = TailCaptureFile::new(64); + file.push_tail(b"oliphaunt-standard-seed-ok"); + assert!(!capture.saw_postgres_error()); + } } diff --git a/src/database-resources/seeds/wasix/src/main.rs b/src/database-resources/seeds/wasix/src/main.rs index fd8bf4827..6c1efe6dc 100644 --- a/src/database-resources/seeds/wasix/src/main.rs +++ b/src/database-resources/seeds/wasix/src/main.rs @@ -2,19 +2,39 @@ use std::path::PathBuf; use anyhow::{Result, bail}; use oliphaunt_wasix_seed_producer::{ - CatalogProfile, clean_generated_cluster_seed, run_wasix_initdb_cluster_seed, + CatalogProfile, bootstrap_recipe, clean_generated_cluster_seed, run_wasix_initdb_cluster_seed, + verify_wasix_cluster_seed, }; +fn catalog_profile(argument: Option) -> Result { + match argument.as_deref().and_then(|arg| arg.to_str()) { + Some("standard") => Ok(CatalogProfile::Standard), + Some("icu") => Ok(CatalogProfile::Icu), + _ => bail!( + "usage: oliphaunt-wasix-seed-producer RUNTIME_DIR WORK_DIR standard|icu [ICU_DATA_DIR]\n oliphaunt-wasix-seed-producer verify RUNTIME_DIR WORK_DIR standard|icu PGDATA_DIR [ICU_DATA_DIR]\n oliphaunt-wasix-seed-producer recipe standard|icu" + ), + } +} + fn main() -> Result<()> { let mut args = std::env::args_os().skip(1); - let runtime = args.next().map(PathBuf::from); + let first = args.next(); + if first.as_deref().and_then(|arg| arg.to_str()) == Some("recipe") { + let profile = catalog_profile(args.next())?; + if args.next().is_some() { + bail!("recipe description accepts only its catalog profile"); + } + println!("{}", serde_json::to_string(&bootstrap_recipe(profile))?); + return Ok(()); + } + let verify = first.as_deref().and_then(|arg| arg.to_str()) == Some("verify"); + let runtime = if verify { args.next() } else { first }.map(PathBuf::from); let output = args.next().map(PathBuf::from); - let profile = match args.next().as_deref().and_then(|arg| arg.to_str()) { - Some("standard") => CatalogProfile::Standard, - Some("icu") => CatalogProfile::Icu, - _ => bail!( - "usage: oliphaunt-wasix-seed-producer RUNTIME_DIR WORK_DIR standard|icu [ICU_DATA_DIR]" - ), + let profile = catalog_profile(args.next())?; + let pgdata = if verify { + args.next().map(PathBuf::from) + } else { + None }; let icu = args.next().map(PathBuf::from); let (Some(runtime), Some(output)) = (runtime, output) else { @@ -23,6 +43,13 @@ fn main() -> Result<()> { if args.next().is_some() || output.exists() { bail!("work directory must be new; no extra arguments are accepted"); } - run_wasix_initdb_cluster_seed(&runtime, &output, profile, icu.as_deref())?; - clean_generated_cluster_seed(&output.join("pgdata")) + if verify { + let Some(pgdata) = pgdata else { + bail!("verification requires a source PGDATA directory") + }; + verify_wasix_cluster_seed(&runtime, &output, profile, &pgdata, icu.as_deref()) + } else { + run_wasix_initdb_cluster_seed(&runtime, &output, profile, icu.as_deref())?; + clean_generated_cluster_seed(&output.join("pgdata")) + } } diff --git a/src/docs/BUILD.bazel b/src/docs/BUILD.bazel new file mode 100644 index 000000000..fa2fa0853 --- /dev/null +++ b/src/docs/BUILD.bazel @@ -0,0 +1,127 @@ +load("//build_defs/foundation:bun.bzl", "bun_test") +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("@aspect_rules_js//js:defs.bzl", "js_binary", "js_test") +load("@bazel_lib//lib:directory_path.bzl", "directory_path") +load("@javascript_consumer_packages//:defs.bzl", "javascript_type_links") +load("@javascript_consumer_packages//:roots.bzl", "CONSUMER_BINS", "CONSUMER_CLOSURES", "CONSUMER_PACKAGES", "CONSUMER_TOOLS") +load(":bazel.bzl", "docs_content", "docs_next_export", "docs_static_export") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["bazel.bzl", "package.json"] + glob(["tools/*.mts"])) + +filegroup( + name = "content_sources", + srcs = ["docs-manifest.toml"] + glob(["content/**/*.md", "content/**/*.mdx", "src/**/*.ts", "src/**/*.tsx"]), +) + +DOCS = "@oliphaunt/docs" +DOCS_ROOTS = CONSUMER_TOOLS[DOCS] +DOCS_PACKAGES = {identity: json.encode(CONSUMER_PACKAGES[identity]) for identity in CONSUMER_CLOSURES[DOCS]} +DOCS_DEPS = [":node_modules/" + name for name in DOCS_ROOTS] +FONT_PACKAGES = [name for name in DOCS_ROOTS if name.startswith("@fontsource/") or name.startswith("@fontsource-variable/")] + +javascript_type_links(DOCS_ROOTS) + +filegroup(name = "next_package_directory", srcs = [":node_modules/next"], output_group = "package_directory") +filegroup(name = "typescript_package_directory", srcs = [":node_modules/typescript"], output_group = "package_directory") +directory_path(name = "next_entry_point", directory = ":next_package_directory", path = CONSUMER_BINS[DOCS]["next"]["next"]) +js_binary(name = "next_cli", entry_point = ":next_entry_point", data = DOCS_DEPS) + +docs_content( + name = "generated_content", + sources = {":content_sources": "src/docs/"}, + completed_releases = "@docs_build_inputs//:completed-releases.json", + provenance = "@docs_build_inputs//:provenance.json", +) + +docs_next_export( + name = "next_export", + content = ":generated_content", + next_binary = ":next_cli", + sources = {":site_sources": "src/docs/"}, + package_identities = DOCS_PACKAGES, + deps = DOCS_DEPS, +) + +[filegroup(name = "font_directory_" + name.split("/")[-1].replace("-", "_"), srcs = [":node_modules/" + name], output_group = "package_directory") for name in FONT_PACKAGES] +[directory_path(name = "font_license_" + name.split("/")[-1].replace("-", "_"), directory = ":font_directory_" + name.split("/")[-1].replace("-", "_"), path = "LICENSE") for name in FONT_PACKAGES] + +docs_static_export( + name = "site", + content = ":generated_content", + site = ":next_export", + font_licenses = {":font_license_" + name.split("/")[-1].replace("-", "_"): "third-party-fonts/" + name.split("/")[-1] + "/LICENSE" for name in FONT_PACKAGES}, +) + +filegroup(name = "snippet_content", srcs = [":generated_content"], output_group = "site_docs") +filegroup(name = "site_routes", srcs = [":generated_content"], output_group = "routes") + +js_test( + name = "snippets_test", + entry_point = "tools/check-docs-snippets.mts", + args = ["--native", "$(rootpath :snippet_content)", "$(rootpath :typescript_package_directory)"], + data = [":snippet_content", ":typescript_package_directory", ":node_modules/typescript", "//src/query/ts:source_inputs", "//src/native/sdks/ts:source_inputs", "//src/native/sdks/ts:source_config", "//src/native/sdks/react-native:source_inputs", "//src/native/sdks/react-native:base_tsconfig", "//src/wasix/sdks/ts:source_inputs", "//src/wasix/sdks/ts:source_config"], + include_types = True, + include_transitive_types = True, + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + exec_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + size = "medium", +) + +js_test( + name = "smoke_test", + entry_point = "tools/smoke-built-site.mts", + args = ["$(rootpath :site)", "$(rootpath :site_routes)", ""], + data = [":site", ":site_routes", ":node_modules/fumadocs-core"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + exec_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + size = "medium", +) + +test_suite(name = "site_checks", tests = [":snippets_test", ":smoke_test"]) + +filegroup( + name = "site_sources", + srcs = ["next.config.ts", "package.json", "postcss.config.json", "proxy.ts", "source.config.ts", "tsconfig.json"] + glob(["src/**", "public/**"]), +) + +bun_test( + name = "generation_test", + entry_point = "tools/generate-content.test.mts", + data = ["tools/generate-content.mts", "tools/check-docs-product.mts", "tools/published-products.mts", "//tools/release:platform-compatibility-policy.mts"], + tags = ["source-check"], + size = "small", +) + +bun_test( + name = "native_adapter_test", + entry_point = "tools/native-docs.test.mts", + data = [ + "tools/native-docs.mts", "tools/generate-content.mts", "tools/check-docs-product.mts", "tools/published-products.mts", + "//tools/release:platform-compatibility-policy.mts", + ], + tags = ["source-check"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + size = "small", +) + +bun_test( + name = "published_products_test", + entry_point = "tools/published-products.test.mts", + data = ["tools/published-products.mts"], + tags = ["source-check"], + size = "small", +) + +bun_test( + name = "live_refresh_test", + entry_point = "tools/verify-live.test.mts", + data = ["tools/verify-live.mts", "tools/published-products.mts"], + tags = ["source-check"], + size = "small", +) + +test_suite(name = "source_checks", tests = [":generation_test", ":native_adapter_test", ":published_products_test", ":live_refresh_test"]) + +source_quality_files() diff --git a/src/docs/architecture/bazel-migration-inventory.md b/src/docs/architecture/bazel-migration-inventory.md new file mode 100644 index 000000000..486e1e452 --- /dev/null +++ b/src/docs/architecture/bazel-migration-inventory.md @@ -0,0 +1,307 @@ +# Native Bazel migration coverage inventory + +Status: verified source inventory for the [proposed migration](bazel-migration-strategy.md), not active implementation. +Audited: 2026-10-11. Owner: repository maintainers. + +Baseline: main `8316eb419999f47d6d4a61a8444e6c5ef32caf46`, tree `91138aa6cc458471d81769e9d6543a1e3f99f0dc`. Workspace `a43b10770ae0e843fe26b2dddc460c9db5cef981` has the identical tracked tree. Versions below are observed baseline values, not installation recommendations or proposed PR #294 versions. + +## Verified counts and scope + +| Inventory | Verified count | Evidence / scope | +|---|---:|---| +| Independent release products | 27 | Actual `loadPublicationCatalog()` and `loadProducts()` output | +| Declared registry identities | 265 | 121 Cargo + 119 npm + 25 Maven; identity minima, not an exhaustive dynamic frozen-candidate count | +| Moon projects | 56 | Actual pinned Moon project query | +| Release / other Moon projects | 27 / 29 | Resolved `project.metadata.release` | +| Configured task entries | 303 | Raw per-project `config.tasks` counts | +| Resolved task entries | 407 | Pinned Moon task graph, including inherited configuration | +| GitHub workflows / job declarations / composite actions | 8 / 83 / 15 | Before matrix expansion; 64 CI jobs and ten release jobs | +| Tracked Cargo manifests | 39 | 1 root workspace + 38 crate manifests | +| Root Cargo workspace members | 28 | Root `Cargo.toml` | +| Tracked npm manifests | 44 | Includes private applications and carrier templates | +| Tracked Swift manifests | 3 | Root, Swift SDK, public API consumer fixture | +| Gradle Kotlin DSL manifests | 6 builds + 3 settings | SDK producer, plugin, carrier renderer and two consumer fixtures; additional React Native Groovy Gradle files also exist | +| Exact SQL extension members | 39 | 32 PostgreSQL contrib + 7 external, actual generated extension catalog | +| Existing Bazel configuration | None located | No tracked `MODULE.bazel`, BUILD or `.bzl` configuration returned in the manifest search | + +The 265 count excludes GitHub archives, the Swift source tag/release tree, and generated Cargo `-part-NNN` identities. The final publication lock, rather than this static count, must enumerate every physical artifact. Catalog target strings include ecosystem aliases; do not count `darwin-arm64` and `macos-arm64` as two machines. + +## Coverage workstreams + +These codes identify workstreams, not sequential cutover steps or permission to omit a surface. Follow the numbered gates in the migration strategy: + +- **F: foundation:** Bzlmod/toolchains/platforms, pinned source acquisition, shared contract/source/file targets, test runners, artifact providers and inventory checks. +- **L: language libraries:** Rust/TypeScript implementation, shared unpublished tools, pure tests, source SDK build and package rendering. +- **N: native production:** PostgreSQL/OpenSSL/ICU builds, native runtimes/tools/extensions, platform prebuilds and resources. +- **W: WASIX production:** WASIX compiler/sysroot, portable modules, AOT, browser host and independent postmaster producer. +- **M: mobile and applications:** UniFFI, Swift/Kotlin/Android/iOS/React Native, real app integration, examples, browser/desktop performance and docs. +- **P: promotion integration:** exact-source CI outputs, installed frozen consumers, publication lock, existing protected publisher/recovery and docs refresh. + +An independently versioned product can span workstreams. A non-release target can contribute bytes to several independently versioned products. Each product's final package root must name its own constructed outputs; the shared producer itself must not acquire an invented SemVer. + +## All 27 release products + +Registry columns are counts of declared Cargo/npm/Maven identities. `0` never means a product has no public artifacts. + +| Product / current version | Path | Cargo / npm / Maven | Required Bazel build / package roots and proofs | Workstream | +|---|---|---:|---|---| +| `database-resources` 0.2.2 | `src/database-resources` | 15 / 15 / 3 | ICU data, native/WASIX standard and ICU cluster-seed producers; per-profile/per-target immutable resources; Cargo/npm/Maven rendering; metadata plus installed resource/profile identity checks | F,N,W,M,P | +| `liboliphaunt-native` 0.3.3 | `src/native/runtime` | 9 / 9 / 5 | Patched PostgreSQL/native C ABI, desktop dynamic runtime, Android ABI outputs, iOS XCFramework; runtime resources and owned native contrib facade/leaves; C/ABI/SQL/installed carrier checks | F,N,M,P | +| `liboliphaunt-native-bindings` 0.2.0 | `src/native/rust-bindings` | 1 / 0 / 0 | Rust source library, unit/integration targets and Cargo source envelope; reused source compilation in broker/addons/mobile must be explicit edges | L,N,P | +| `liboliphaunt-wasix` 0.3.2 | `src/wasix/runtime` | 10 / 2 / 0 | Shared C compiler output, portable runtime, host AOT modules; portable/AOT Cargo leaves and owned WASIX contrib facade/leaves; runtime/export/serializer/installed checks | F,W,P | +| `liboliphaunt-wasix-postmaster` 0.1.1 | `src/wasix/postmaster` | 0 / 0 / 0 | Separate patched PostgreSQL/Wasmer/libc/sysroot, sealed core, executor/compiler and host AOT carrier; GitHub-only sealed-postmaster archives; concurrency/recovery/export-contract tests | F,W,P | +| `oliphaunt-query` 0.1.1 | `src/query/rust` | 1 / 0 / 0 | Rust query encoding/decoding/types, Cargo source package, library/unit/consumer tests | L,P | +| `oliphaunt-query-ts` 0.1.1 | `src/query/ts` | 0 / 1 / 0 | TS library, ESM/CommonJS plus types, npm envelope/export tests | L,P | +| `postgres-tools-native` 0.2.2 | `src/native/postgres-tools` | 5 / 5 / 0 | PostgreSQL `pg_dump`/`pg_basebackup`/`psql` binaries and dynamic dependency closure from native producer, Cargo/npm facade/leaves, GitHub archives; executable/backup/restore/tool checks | N,P | +| `oliphaunt-broker` 0.3.1 | `src/native/broker` | 5 / 4 / 0 | Distinct Rust broker library and executable targets; host helper binary packages; Cargo facade plus four Cargo/npm helpers; socket/process/application tests. Mobile library consumers do not consume `main.rs` | L,N,P | +| `oliphaunt-extension-pg-hashids` 0.3.2 | `src/extensions/external/pg_hashids` | 10 / 10 / 2 | Pinned upstream/recipe, native dynamic/mobile static and portable/AOT producers; generated ecosystem facade/leaves, host descriptors, SQL lifecycle plus installed compositions | F,N,W,M,P | +| `oliphaunt-extension-pg-ivm` 0.3.2 | `src/extensions/external/pg_ivm` | 10 / 10 / 2 | Same family with its own source/patch/target support and preload/lifecycle rules | F,N,W,M,P | +| `oliphaunt-extension-pg-textsearch` 0.3.2 | `src/extensions/external/pg_textsearch` | 10 / 10 / 2 | Same family with its own compiled module and target/static-registry contract | F,N,W,M,P | +| `oliphaunt-extension-pg-uuidv7` 0.3.2 | `src/extensions/external/pg_uuidv7` | 10 / 10 / 2 | Same family with its own upstream pin and lifecycle fixture | F,N,W,M,P | +| `oliphaunt-extension-pgtap` 0.3.2 | `src/extensions/external/pgtap` | 6 / 6 / 2 | SQL-only resource package; native/mobile/portable targets require resource assembly, not invented C compilation or AOT module leaves; SQL installed checks | F,N,W,M,P | +| `oliphaunt-extension-postgis` 0.3.2 | `src/extensions/external/postgis` | 10 / 10 / 2 | PostGIS and its GEOS/PROJ/libxml2/libiconv/json-c/SQLite pinned dependencies; native/static/portable/AOT modules and additional SQL data/load order; independently packaged product | F,N,W,M,P | +| `oliphaunt-extension-vector` 0.3.2 | `src/extensions/external/vector` | 10 / 10 / 2 | Own source and all declared target recipes; carrier descriptor and installed SDK+extension SQL execution | F,N,W,M,P | +| `oliphaunt-kotlin` 0.3.3 | `src/native/sdks/kotlin` | 0 / 0 / 3 | Generated UniFFI Kotlin/JNI; Android AAR/POM/sources/javadoc, plugin JAR/POM/module/sources/javadoc, marker POM; signing at publication. Android/public-API/broker-app/resource acquisition tests; no Android module or extra KMP/JVM coordinates | L,N,M,P | +| `oliphaunt-node-direct` 0.2.2 | `src/native/node-addon` | 0 / 4 / 0 | Unpublished Rust cdylib producer, four Node-API `.node` platform leaves and GitHub archives, adapter dependency closure; separately loaded native runtime compatibility and Node/Bun/Deno installed SDK composition proofs | L,N,P | +| `oliphaunt-swift` 0.8.2 | `src/native/sdks/swift` | 0 / 0 / 0 | Generated UniFFI Swift/FFI + native bindings, Swift modules, public Package.swift/source tag, XCFramework/resources, frozen extension generator/catalog; empty default extension set and separately owned opt-in carriers; macOS/public API/iOS installed app proofs | L,N,M,P | +| `oliphaunt-wasix-rust` 0.3.2 | `src/wasix/sdks/rust` | 1 / 0 / 0 | Rust SDK and optional dump CLI/tool feature, published Cargo source package; runtime/ABI/SDK feature and installed composition checks | L,W,P | +| `oliphaunt-js` 0.3.1 | `src/native/sdks/ts` | 0 / 1 / 0 | TS source/library/default native and broker topology, npm envelope plus preserved conventional pins; Node/Bun/Deno and Electron/Tauri installed consumers | L,N,M,P | +| `oliphaunt-pgwire-server` 0.2.1 | `src/wasix/pgwire-server` | 1 / 0 / 0 | Rust library, feature-gated CLI, source crate, socket/client and SDK composition tests | L,W,P | +| `oliphaunt-react-native` 0.3.2 | `src/native/sdks/react-native` | 0 / 1 / 0 | TS API, C++ JSI/TurboModule/codegen, Android Kotlin/JNI and iOS Swift/podspec/template integration, Expo plugin/package; Android/iOS real app build/e2e plus installer/resource checks | L,N,M,P | +| `oliphaunt-rust` 0.3.2 | `src/native/sdks/rust` | 2 / 0 / 0 | Separate published `oliphaunt` SDK and `oliphaunt-build` helper roots sharing one product version; features/build scripts/runtime-resource CLI; actual staged native carrier pins and installed extension execution | L,N,P | +| `oliphaunt-wasix-napi` 0.2.1 | `src/wasix/node-addon` | 0 / 4 / 0 | Unpublished Rust cdylib producer, platform Node-API leaves, embedded WASIX runtime/tools/resources and provenance; four platform packages + GitHub archives | L,W,P | +| `oliphaunt-wasix-ts` 0.2.2 | `src/wasix/sdks/ts` | 0 / 1 / 0 | Universal SDK: browser Worker/Wasmer JS/WASM plus native N-API paths; source npm package with host machinery, browser and Node/Bun/Deno installed checks | L,W,M,P | +| `postgres-tools-wasix` 0.2.4 | `src/wasix/postgres-tools` | 5 / 6 / 0 | Portable tool modules, per-host AOT tool leaves, Cargo/npm facade/leaves and public TS wrapper from nested `ts/`; CLI, browser/Node SDK tool consumers | L,W,M,P | + +Product registration must continue to include registry-free products (Swift/postmaster), and products with no physical checked-in carrier source directory (all generated facade/leaves). Product versions are not Bazel target versions or language crate versions by default. + +## All 29 non-release Moon projects + +| Existing project | Path | Existing role / task surface | Bazel ownership and verification role | Workstream | +|---|---|---|---|---| +| `artifact-packaging` | `tools/packaging` | Deterministic archive/manifest/license/carrier helpers; unit tests | Executable/library tool targets with declared runfiles; archive/cargo/npm/Maven generators consumed by product package actions; independent tests. Writer changes can affect owned deliverables, validator changes affect proofs | F,L,P | +| `benchmarks` | `src/benchmarks` | SQL fixtures, comparison baselines/report shape; no direct tasks | Data filegroups for consumers, explicitly separate measurement inputs from public production inputs | F,M | +| `ci-tools` | `tools/ci` | Current Moon-to-hosted-job planning, transfer and unit tests | Port necessary host routing and proof tests; replace task selection/cache inference with native Bazel construction. Transport lock-derived final packages to native behavior cohorts without producer-tree satisfaction or implicit reconstruction; no remote executor/cache prerequisite | F,P | +| `ci-workflows` | `.github` | Workflow/security/cache/setup checks and LLVM installer unit tests | Retain security/admission and actual setup/toolchain contracts; delete tests of retired Moon, Docker and nested Cargo cache/setup bodies. Preserve GitHub permissions/environments/credentials orchestration outside build actions | F,P | +| `cluster-seed-contract` | `src/database-resources/contracts` | Standard/ICU seed + portable ICU identity formats and negative fixtures | Shared contract/data targets and tests consumed by resource producer and actual SDK installers | F,N,W,M | +| `dev-tools` | `tools/dev` | Pinned acquisition, tool bootstrap/hooks/smoke/mobile setup tests | Repository/module extensions and declared toolchains for build dependencies; local setup/hook `bazel run` utilities where useful; setup tests remain genuine tests | F,M | +| `docs` | `src/docs` | Next/Fumadocs generate/typecheck/build/static smoke/live metadata tools; dev server | Next/TS action graph, explicit authored/generated content inputs, static export artifact and smoke tests; snapshot completed releases as explicit input. Dev server runnable. Vercel trigger/live check remain uncached protected operations | L,M,P | +| `extension-artifacts-native` | `src/extensions/artifacts/native` | Native target producers and native packager/Rust unit checks | Per-extension/per-target action outputs plus artifact-contract tests; split compiler output from archive assembly; artifacts owned by external products or runtime contrib owners | N,M | +| `extension-artifacts-wasix` | `src/extensions/artifacts/wasix` | WASIX extension compiler output, portable package and AOT build | Declared compiler/sysroot/configured PostgreSQL headers/providers/module dependencies, separate portable and per-execution-platform AOT outputs | W | +| `extension-packages` | `src/extensions/artifacts/packages` | Ecosystem envelopes, mobile carriers, carrier validator/unit tests | Package roots per owner/configuration, generated manifest/assets providers; generated public crates/npm/Maven/Swift envelopes are not an independently versioned tool product | F,N,W,M,P | +| `extension-runtime-contract` | `src/extensions/contracts` | Runtime/extension contract TOML, target profiles, archive policy, validators | Contract filegroups/tool libraries and tests; used by actual loaders and package generators, not a second installed-version authority | F,N,W,M | +| `extensions` | `src/extensions` | Catalog generation, generated SDK/build/mobile/docs tables, license audits/lint/unit checks | Explicit generation actions from catalog/source/recipe inputs; generated outputs/providers and consistency tests. Distinguish build generation from runtime fixtures/proof tables | F,N,W,M | +| `integration-examples` | `src/examples` | Browser typecheck; Expo Android/iOS build/e2e/drills; shared harness tests | Separate application and integration-test targets per application/host; device/browser resources explicit; do not aggregate examples into product shipping ownership | L,M,P | +| `native-extension-lifecycle` | `src/extensions/tests/native` | Unpublished Rust extension proof; lifecycle and unit tests | Rust test/executable target observing constructed native SDK/runtime/extensions and SQL fixtures; never a shipping owner | N,P | +| `native-packaging` | `src/native/runtime/packaging` | Unpublished Rust `oliphaunt-resources` binary; Rust/TS tests/typecheck | Tool binary with typed resource/archive inputs, declared generated outputs and contract/unit tests; package writer is part of consumer artifacts' construction closure | F,L,N,M | +| `native-tools-proof` | `src/native/postgres-tools/tests` | Unpublished Rust cross-product SDK/server/tool conformance | Integration test target observing tool executable facade, server/socket/backup fixtures and SDK; does not own an independent release | N,P | +| `oliphaunt-extension-contrib-pg18` | `src/extensions/contrib` | 32 contrib declarations, PostgreSQL18 source linkage; no independent release | Logical bundle/data/producer targets; native and WASIX physical carriers inherit their runtime owners. Do not create a new versioned Bazel product | F,N,W,M,P | +| `oliphaunt-mobile-bindings` | `src/native/mobile-bindings` | Private Rust staticlib/cdylib and bindgen binary; UniFFI generation/native tests/license audit | Rust library configured for desktop/Android/Apple ABIs, host executable tool, generated Swift/Kotlin/FFI outputs; actual bytes ship in SDKs despite `publish=false` | L,N,M | +| `oliphaunt-wasix-tools-ts` | `src/wasix/postgres-tools/ts` | Public `@oliphaunt/wasix-tools` build/package/tests, no independent product version | TS library/npm package output root assigned to `postgres-tools-wasix`; conventional requirements preserved; CLI/browser installed tests | L,W,M,P | +| `perf-tools` | `src/benchmarks/perf` | Private Rust runner; native/Node/browser measurement, planner validation, lint | Runner/benchmark tools and plan unit tests; explicit manual/uncached measurement run targets and report outputs. PGlite/SQLite comparison dependencies belong to benchmark graph | L,M | +| `postgres18` | `src/third-party/postgres` | Source pin/checksum/shared patch set; no compile task itself | Pinned external repository/source target with patches; actual runtime and CLI target consumers both represented | F,N,W | +| `release-tools` | `tools/release` | Private Release Please library/tooling, metadata/graph/pin/check tests; protected controllers and verifiers | TS tool libraries/executables and tests; migrate input discovery/producer enumeration to declared Bazel providers; retain versions, frozen bytes, journal/reconciliation, credential and promotion boundaries | F,L,P | +| `repo` | `.` | Workspace/root metadata, JS format/lint, hooks and shared task groups | Root metadata/check/file targets; language dependency lockfiles and toolchains declaratively connected; keep formatting separate from shipping output invalidation | F,L | +| `shared-test-fixtures` | `src/test-fixtures` | Canonical protocol/storage/postgres/extension SQL files; no direct tasks | Shared test `data` filegroups, consumed by actual tests only unless a specific package deliberately ships a fixture | F,N,W,M | +| `source-inputs` | `src/third-party/tools` | Neutral source acquisition for native/WASIX/postmaster/extensions/ICU-data plus fetch tests | Bzlmod/module/repository acquisition with immutable URLs/commits/checksums; build actions consume declared extracted/patch outputs and have no opportunistic fetch; preserve bounded transport/extraction tests | F,N,W | +| `third-party-icu` | `src/third-party/icu` | ICU implementation pin; contract/fetch unit test | Pinned implementation repository and native/WASIX build toolchain/source targets; separate ICU data source under `database-resources/icu/source.toml` | F,N,W | +| `third-party-openssl` | `src/third-party/openssl` | OpenSSL implementation pin; no direct tasks | Pinned source repository and actual native/WASIX compiled library consumers | F,N,W | +| `wasix-browser-host` | `src/wasix/browser-host` | Patched Wasmer JS/WASIX/virtual-fs/virtual-mio build producing JS/Worker/WASM | Native Rust→WASM, matching wasm-bindgen, Binaryen and Rollup action outputs with pinned acquisition/toolchains; produced host artifacts explicitly consumed and shipped by WASIX TS SDK | F,L,W,M | +| `xtask` | `src/wasix/runtime/tools/xtask` | Private Rust build/generator utilities; AOT serializer typecheck and unit/lint checks | Host Rust executable/tool library plus generators and serializer contract tests; consumed by runtime/extensions/resources producers without creating runtime release merely for unrelated tool tests | F,L,W | + +## Cargo manifests and private crates: complete group coverage + +The root workspace has 28 members. Ten other crate manifests have isolated `[workspace]` roots, and root itself is the 39th manifest. Native carrier crates and example/postmaster crates must not accidentally be made root members or forced to share one Cargo feature set. + +| Group / count of crate manifests | Paths or exact crate names | Publication / Bazel treatment | +|---|---|---| +| Public source libraries/SDKs/CLI, 7 | `src/query/rust`, `src/native/rust-bindings`, `src/native/broker`, `src/native/sdks/rust`, `src/native/sdks/rust/crates/oliphaunt-build`, `src/wasix/sdks/rust`, `src/wasix/pgwire-server` | Native Rust library/binary/test actions with explicit feature configurations; separate source package envelopes owned by catalog products | +| Resource/tool facade crates, 2 | `src/database-resources/icu/cargo`, `src/native/postgres-tools/crates/tools` | Rust source glue + immutable payload providers; packaging/build.rs resolver checks | +| Broker platform crate templates, 4 | `src/native/broker/crates/{linux-arm64-gnu,linux-x64-gnu,macos-arm64,windows-x64-msvc}` | Isolated Cargo source packages include generated binaries; no independent product version | +| Private checkout templates for public WASIX crates, 10 | Runtime `crates/assets` + four `crates/aot/*`; tools `crates/tools` + four `crates/aot/*` | `publish=false` protects checkout. Staged rendered crates are public catalog carriers; generate full source/build.rs/payload manifests and optional dynamic parts | +| Private production/tools/proofs, 11 | `oliphaunt-wasix-seed-producer`, `oliphaunt-mobile-bindings`, `oliphaunt-node-direct`, `oliphaunt-wasix-napi`, `oliphaunt-perf`, `oliphaunt-native-extension-proof`, `oliphaunt-native-packaging`, `oliphaunt-native-tools-proof`, `xtask`, `oliphaunt-wasix-postmaster-executor`, `oliphaunt-wasix-sealed-export-closure` | Private does not imply nonshipping: mobile/static/addon/postmaster producer outputs ship. Bench/proof/tools themselves remain private. Executor Cargo.lock is independent of root and sealer | +| Isolated app/consumer crates, 4 | `src/examples/native/tauri/src-tauri`, `src/examples/wasix/tauri/src-tauri`, `src/examples/wasix/electron/src-wasix`, `src/native/sdks/rust/tests/release-consumer` | Explicit app/test roots preserving actual installed versus checkout dependency resolution; Tauri build.rs/generated contexts and WASIX Electron sidecar included | + +The postmaster executor manifest exposes four separately feature-gated binaries: product executor, product compiler, start-proof tool and memory-profile tool. The compiler is an execution tool while the executor is a release payload; feature constraints must not be collapsed into one generic Rust binary. + +## npm, Swift, Gradle and C/C++ coverage + +| Surface | Complete grouping and migration requirement | +|---|---| +| 44 npm manifests | 10 private repository/docs/release/perf/example apps; 2 private addon producer roots; 5 public TS/library/SDK roots; 1 public ICU resource package; 21 native/helper/addon platform or tool facade templates; 5 private WASIX tools carrier templates that render public carriers. Depend on final rendered manifest identity, not `private` or directory name | +| Root npm workspace | `package.json` + `bun.lock`: broad Bun workspace, dependency catalogs, overrides/trustedDependencies and pinned Bun. Private Electron/Tauri apps are not all root workspace members; their independent install closure matters. No new ad-hoc package resolver | +| 3 Swift manifests | Root `Package.swift`, `src/native/sdks/swift/Package.swift`, `src/native/sdks/swift/Tests/PublicApiConsumer/Package.swift`. Six public libraries: COliphaunt, Oliphaunt, OliphauntCore, OliphauntBroker, OliphauntBrokerExtension, OliphauntExtensionSupport. Generated FFI/native bindings also exist. Checkout manifest points at local generated `.build` outputs; published source-tree manifest is rendered differently. Preserve actual SwiftPM install/tag contract | +| Kotlin/Gradle | `src/native/sdks/kotlin` root, `oliphaunt` Android AAR, Java Android Gradle plugin and marker, `oliphaunt-maven-artifacts` renderer for runtime/resources/extensions; `tests/public-api-consumer`, `tests/broker-app`; wrapper JAR/properties/version catalog. Consumer plugin behavior is part of shipped product API even when producer uses Bazel | +| React Native | `src/native/sdks/react-native` source package: TS/C++ codegen/TurboModule/JSI, Android Groovy Gradle + JNI CMake, iOS podspecs/Swift integration, Expo plugin/templates. Preserve consumer Gradle/CocoaPods/RN codegen paths; Bazel producer cannot replace external consumers' conventional entrypoints | +| Native C/C++ | Native runtime C ABI/headers and patched PostgreSQL; native shared/CLI dependency libraries; Kotlin and RN JNI/CMake C++ sources; mobile static registries; Windows DLL/MSVC redistributable closure. Compile and binary/package ABI checks are distinct targets | +| Legal sources | Root `LICENSE`, `THIRD_PARTY_NOTICES.md`, product notices/upstream license data and generated THIRD_PARTY_LICENSES trees are actual package inputs. Explicit artifact action inputs; don't globally ignore Markdown | +| Generated carriers with no checked-in `src/` | Native runtime Cargo leaves, resource seeds, extension facades/native/portable/AOT leaves, dynamic Cargo split parts, npm platform packages, Maven POM/JAR/AAR and Swift resource source trees. Give the package generator declared outputs/provider metadata; don't invent source directories | + +Conventional distribution manifests stay first-class outputs and consumer contracts. A Bazel implementation library need not be named/versioned like every package carrier, and private build libraries must not be mistaken for private installed packages. + +## Non-product artifacts and operational paths that must not disappear + +| Surface | Paths / outputs | Build, verification and operations | +|---|---|---| +| Native Electron example | `src/examples/native/electron` | TS main/renderer+Vite build; actual SDK/helper/tools/contrib installed closure; GUI/browser harness and broker SQL/tool scenarios. Private application, no product release | +| WASIX Electron example | `src/examples/wasix/electron`, nested `src-wasix` Rust sidecar | Independent JS install/build plus Rust sidecar binary; host application topology and pgwire integration; Electron target/ABI separate from Node source typecheck | +| Native Tauri example | `src/examples/native/tauri`, nested `src-tauri` | Frontend + Rust Tauri build.rs app context, WebDriver app staging/test harness; native SDK/extensions/resources/tools installed composition | +| WASIX Tauri example | `src/examples/wasix/tauri`, nested `src-tauri` | Frontend + Rust WASIX SDK/server topology, independent consumer manifests; actual WebDriver app execution | +| Browser example | `src/examples/wasix/browser` | Vite app, Worker/host WASM/static assets, browser smoke/integration and benchmark variants; cross-origin/runtime headers are meaningful test inputs | +| Expo example | `src/examples/native/react-native-expo` | Android/iOS generated app roots, extension staging, APK/IPA/app/simulator artifacts, real device/emulator test receipts, smoke/drill/crash/benchmark modes; local dev servers remain runnable operations | +| Performance | `src/benchmarks/{native/sql,wasix}` and `src/benchmarks/perf` | Private Rust native/PostgreSQL/SQLite runner and Node/browser WASIX/PGlite comparisons; result JSON/reports not immutable product artifacts; validate plans in CI, measurements explicitly uncached/manual with host information | +| Docs export | `src/docs` → `target/docs/build`, `target/docs/generated/routes.json`, generated Markdown/LLM/search/static assets | Published website is public though npm package is private. Explicit generator/build/static smoke targets; published-release snapshot an explicit external input. Ordinary docs source edits don't release SDKs | +| Docs refresh/deployment | `.github/workflows/release.yml:request-docs-refresh`, `src/docs/tools/request-refresh.sh`, `verify-live.mts` | Protected Vercel deploy hook after full promotion; completed product snapshot and live site evidence. Hook acceptance is not deployment success. Retry docs operation independently from publication; keep outside cacheable builds | +| Main/PR/device CI | `.github/workflows/ci.yml`, `mobile-e2e.yml`, hosted reusable producer workflows/actions | Bazel owns target construction/check graph; GitHub owns host allocation, device lifecycle, exact-source/protected context and artifact attestation/evidence. Required/Qualified semantics and causal failed-run diagnosis must survive | +| Frozen release transaction | `tools/release` + `.github/workflows/release.yml` | Candidate, exhaustive publication lock, consumer proof, original SHA/tree, transport tag, staged archives and approved capsule remain. Bazel output collection replaces Moon artifact transfer; immutable publication/recovery must not rebuild or substitute source | +| Installed/public consumers | Product-owned `tools/frozen-consumer*`, tests/public API fixtures, `tools/release/frozen-consumer.mts`, `public-consumer-smoke.mts` | Distinct staged package resolver checks and anonymous postpublication registry checks. Running Bazel source tests cannot replace genuine Cargo/npm/SwiftPM/Gradle consumer resolution | +| Source acquisition | `src/third-party/tools`, all `source.toml` and postmaster `sources/*.toml`, `src/wasix/browser-host/source.toml`, extension-owned dependency pins | Immutable acquisition/checksum/patch/extraction outputs with declared repository ownership; product-specific pins retained. No action fetches undeclared current network state | +| Developer/bootstrap workflow | `tools/dev`, `.prototools`, `.moon/toolchains.yml`, `.moon/tasks`, `rust-toolchain.toml`, setup GitHub actions | Pin toolchains/runners/build images/native SDKs and migrate users' commands/hooks; remove obsolete Moon/proto/bootstrap duplication only after equivalent local and hosted paths work | + +## Configuration and target surfaces + +- **Desktop:** Linux x86_64/aarch64 GNU, macOS arm64, Windows x86_64 MSVC. npm aliases are darwin/win32, Cargo aliases are Rust triples; preserve one normalized platform identity with rendered ecosystem names. +- **Native mobile:** Android arm64-v8a and x86_64; iOS XCFramework is an aggregate artifact, not one architecture. iOS device/simulator component selection and macOS consumer execution need explicit configuration, not host OS guessing. +- **WASIX:** Portable producer modules and host-specific AOT serialization are different outputs/configurations. WASIX portable extension runtime and shared AOT serializer ABI/toolchain rules stay explicit. +- **Postmaster:** Its declared release targets are Linux arm64/x64 and macOS arm64. It has a separate patched Wasmer/libc/source closure, independent locks, executor/compiler and concurrency qualification. Do not inherit ordinary WASIX Windows support. +- **Extension resources:** SQL-only pgtap and contrib resource sets do not require compiled modules solely because other extensions do. Extension target support remains catalog/recipe-driven, not assumed from runtime support. +- **Database profiles:** Standard versus ICU, native platform/mobile datum64 versus WASIX seeds, shared ICU data versus ICU compiled library. Profile/resource identity must survive producer and consumer tests. +- **SDK/runtime modes:** Rust feature gates, Node/Bun/Deno/browser placements, native direct/broker/server topology, RN generated/native configs, Swift module/resource variants. A single broad all-features build does not prove each shipped mode. +- **Tools vs targets:** Host compilers/generators/bindgen/Wasmer serializers and target libraries/binaries require distinct execution/target platforms. Downloaded compiler images/sysroots/toolchain pins are inputs. +- **Construction vs behavior hosts:** Linux constructs every supported cross-target package that its declared toolchains can produce so maintainers can reproduce shared CI locally. Native SDK construction exceptions remain explicit. macOS/Windows and device checks consume the exact transported final files and verify target behavior; selecting a foreign platform never provides a remote machine or permits an implicit producer rebuild. + +## Minimal complete Bazel ownership requirements + +1. Every compiled/generated output has one producer action and declared inputs. Product package roots consume producers, version/manifests, legal files and resource providers. Tests consume outputs and fixtures without becoming package prerequisites or output owners. +2. Each of the 27 release roots exports an exhaustive artifact manifest/provider. Enforce one owner for all 265 declared registry identities plus every dynamically generated part/GitHub/source-tag artifact. A private or absent checkout source directory does not exempt a carrier. +3. Keep public Cargo/npm/Gradle/SwiftPM contracts conventional. Source-native Bazel build dependencies describe actual checkout compilation; rendered installed requirements describe historical/candidate package resolution. Never infer one from the other. +4. Source/upstream pins are immutable repository/module inputs. Network/secret/device/publication/live-docs operations are explicit uncached run/hosted operations, not hidden cacheable action effects. +5. Cut over by dependency families but require all 56 rows and the non-product surfaces above before deleting Moon. A collection of shell/cargo/gradle wrappers with broad repository inputs is a transition harness, not a complete native Bazel migration. +6. Verify through independent inventory equality, real file-change expected-impact fixtures, actual rendered envelope contents/resolution, platform/feature installed consumers, and end-to-end frozen-candidate/recovery tests. A Bazel graph query proves declared reachability; sandboxed clean execution and actual consumers provide evidence that declarations are complete. +7. Every release cross-host consumer receives a lock-derived final-file closure, exact source/configuration and original construction evidence. Verify hashes and required directory/mode fidelity on receipt and bind the behavior result to the same bytes. Do not import producer output trees, rewrite their provenance, or satisfy a foreign producer dependency from downloaded files. Migration construction receipts bind final files without claiming publication or foreign-host qualification. Shared construction remains reproducible on Linux without hosted execution or cache infrastructure; remote execution is optional future infrastructure. + +This inventory was validated against the actual catalog and resolved projects. No producer builds or hosted qualification were run for the audit. Native rule implementations and toolchain feasibility require execution evidence at the strategy's acceptance gates. + +## Every existing workflow job + +These are source job IDs before matrix expansion. The strategy's workflow disposition table states what replaces their construction, proof, or operational role. Existing aggregator names are not a requirement to retain separate jobs. + +| Workflow | Complete current job set | +| --- | --- | +| `broker-runtime.yml` | `build` | +| `ci.yml` | `affected`, `release-intent`, `check-targets`, `policy-targets`, `checks`, `test-targets`, `tests`, `extension-artifacts-native-linux`, `extension-artifacts-native-android-static`, `extension-artifacts-native-android`, `extension-artifacts-native-ios`, `extension-artifacts-native-other`, `extension-artifacts-native`, `extension-artifacts-wasix`, `extension-packages`, `mobile-extension-packages-android`, `mobile-extension-packages-ios`, `mobile-extension-packages`, `liboliphaunt-native-desktop-linux`, `liboliphaunt-native-desktop-other`, `liboliphaunt-native-desktop`, `liboliphaunt-native-android`, `liboliphaunt-native-ios`, `liboliphaunt-native-android-abi`, `liboliphaunt-native-ios-abi`, `liboliphaunt-native-release-assets`, `rust-sdk-package`, `broker-runtime-linux`, `broker-runtime-other`, `broker-runtime`, `node-direct`, `broker-release-assets`, `node-direct-release-assets`, `wasix-napi`, `wasix-napi-release-assets`, `swift-bindings`, `swift-sdk-package`, `kotlin-sdk-package`, `kotlin-maven-staging`, `react-native-sdk-package`, `js-sdk-package`, `native-consumers`, `wasix-ts-package`, `wasix-ts-sdk-package`, `wasix-rust-package`, `liboliphaunt-wasix-runtime`, `wasix-host-linux`, `wasix-host-other`, `liboliphaunt-wasix-aot`, `liboliphaunt-wasix-release-assets`, `wasix-postmaster-portable`, `wasix-postmaster-target`, `wasix-postmaster`, `native-extension-lifecycle`, `native-extension-lifecycle-aggregate`, `wasix-release-regression`, `mobile-build-android`, `mobile-build-ios`, `builds`, `mobile-e2e-android`, `mobile-e2e-ios`, `e2e`, `required`, `qualified` | +| `extension-artifacts-native.yml` | `build` | +| `liboliphaunt-native-desktop.yml` | `build` | +| `mobile-e2e.yml` | `resolve`, `android`, `ios`, `required` | +| `mobile-extension-packages.yml` | `package` | +| `release.yml` | `validate-inputs`, `prepare-release-pr`, `plan-candidate`, `request-qualification`, `prepare-candidate`, `frozen-consumers`, `publication-ready`, `publish-bootstrap`, `publish`, `request-docs-refresh` | +| `wasix-host.yml` | `build` | + +## Every composite action + +These are all 15 current action directories under `.github/actions`. Operational setup can survive only for its stated external role; compilation inputs move into registered toolchains. + +| Current action | Final role | +| --- | --- | +| `setup-moon` | Delete after all construction and operational tool entrypoints migrate | +| `setup-node-runtime`, `setup-bun`, `setup-node-bun`, `setup-deno` | Declared build/test runtimes; narrow remaining controller/device setup uses the same pins | +| `setup-rust`, `setup-rust-tools` | Native Rust/tool/test rules; retain exact conventional Cargo tooling for installed consumers | +| `setup-swift` | Declared Swift compiler; conventional SwiftPM remains an installed-consumer test tool | +| `setup-apple` | Exact Xcode/SDK registration and device facilities; remove ambient Homebrew production dependencies | +| `setup-android` | Explicit SDK/NDK/JVM compile toolchains; keep emulator/ADB/KVM/licensing operations | +| `setup-msvc` | Register observed exact MSVC/Windows SDK; no invisible PATH-only production contract | +| `setup-wasmer-llvm` | Pinned repository/toolchain dependency replaces installer/cache setup | +| `setup-wasix-builder` | Remove Docker Buildx construction engine; pinned Linux execution environment is registered infrastructure | +| `setup-npm-publisher` | Retain trusted-publishing client/auth readiness at protected mutation boundary | +| `run-mobile-e2e` | Retain shared fresh installed-app harness with exact app digest and no build fallback | + +## Every CI-tagged task assignment + +The 84 rows map existing task-to-CI-group assignments to source owners. These labels are proposed migration references, not implemented BUILD targets or a requirement for one target per Moon task. The strategy's [minimal verification policy](bazel-migration-strategy.md#minimal-checks-tests-and-builds) governs what survives: delete tests of retired machinery, merge repeated guarantees and retain distinct consumer/trust contracts. Inherited checks and untagged developer/tool tasks are covered by the 56-project inventory and the 407-entry resolved task snapshot; each must have a surviving owner, native replacement guarantee or justified deletion before Moon removal. + +| Current CI group | Current task | Proposed source-local native label | Native role | +| --- | --- | --- | --- | +| `broker-release-assets` | `oliphaunt-broker:finalize-release-assets` | `//src/native/broker:finalize-release-assets` | replace in-place finalizer with pure declared archive/index output | +| `broker-runtime` | `oliphaunt-broker:build-release-assets` | `//src/native/broker:build-release-assets` | native production action/output | +| `extension-artifacts-native` | `extension-artifacts-native:build-target` | `//src/extensions/artifacts/native:build-target` | native production action/output | +| `extension-artifacts-wasix` | `extension-artifacts-wasix:build-target` | `//src/extensions/artifacts/wasix:build-target` | native production action/output | +| `extension-packages` | `extension-packages:package` | `//src/extensions/artifacts/packages:package` | native production action/output | +| `js-sdk-package` | `database-resources:package-icu` | `//src/database-resources:package-icu` | native production action/output | +| `js-sdk-package` | `oliphaunt-js:package` | `//src/native/sdks/ts:package` | native production action/output | +| `js-sdk-package` | `oliphaunt-query-ts:package` | `//src/query/ts:package` | native production action/output | +| `js-sdk-package` | `oliphaunt-wasix-tools-ts:package` | `//src/wasix/postgres-tools/ts:package` | native production action/output | +| `kotlin-maven-staging` | `oliphaunt-kotlin:maven-staging` | `//src/native/sdks/kotlin:maven-staging` | native production action/output | +| `kotlin-sdk-package` | `oliphaunt-kotlin:package` | `//src/native/sdks/kotlin:package` | native production action/output | +| `liboliphaunt-native-android` | `liboliphaunt-native:build-runtime-android-arm64-v8a` | `//src/native/runtime:build-runtime-android-arm64-v8a` | native production action/output | +| `liboliphaunt-native-android` | `liboliphaunt-native:build-runtime-android-x86_64` | `//src/native/runtime:build-runtime-android-x86_64` | native production action/output | +| `liboliphaunt-native-android` | `liboliphaunt-native:package-runtime-android-arm64-v8a` | `//src/native/runtime:package-runtime-android-arm64-v8a` | native production action/output | +| `liboliphaunt-native-android` | `liboliphaunt-native:package-runtime-android-x86_64` | `//src/native/runtime:package-runtime-android-x86_64` | native production action/output | +| `liboliphaunt-native-android-abi` | `database-resources:build-native-android-icu` | `//src/database-resources:build-native-android-icu` | native production action/output | +| `liboliphaunt-native-android-abi` | `database-resources:build-native-android-standard` | `//src/database-resources:build-native-android-standard` | native production action/output | +| `liboliphaunt-native-android-abi` | `liboliphaunt-native:finalize-runtime-android-abi` | `//src/native/runtime:finalize-runtime-android-abi` | replace in-place finalizer with pure declared archive/index output | +| `liboliphaunt-native-desktop` | `database-resources:build-native-icu` | `//src/database-resources:build-native-icu` | native production action/output | +| `liboliphaunt-native-desktop` | `database-resources:build-native-standard` | `//src/database-resources:build-native-standard` | native production action/output | +| `liboliphaunt-native-desktop` | `liboliphaunt-native:package-runtime-desktop-target` | `//src/native/runtime:package-runtime-desktop-target` | native production action/output | +| `liboliphaunt-native-desktop` | `liboliphaunt-native:test-artifacts-desktop-target` | `//src/native/runtime:test-artifacts-desktop-target` | test-only native consumer/check | +| `liboliphaunt-native-desktop` | `postgres-tools-native:package-assets` | `//src/native/postgres-tools:package-assets` | native production action/output | +| `liboliphaunt-native-desktop` | `postgres-tools-native:test-assets` | `//src/native/postgres-tools:test-assets` | test-only native consumer/check | +| `liboliphaunt-native-ios` | `liboliphaunt-native:build-runtime-ios-xcframework` | `//src/native/runtime:build-runtime-ios-xcframework` | native production action/output | +| `liboliphaunt-native-ios` | `liboliphaunt-native:package-runtime-ios-xcframework` | `//src/native/runtime:package-runtime-ios-xcframework` | native production action/output | +| `liboliphaunt-native-ios-abi` | `database-resources:build-native-ios-icu` | `//src/database-resources:build-native-ios-icu` | native production action/output | +| `liboliphaunt-native-ios-abi` | `database-resources:build-native-ios-standard` | `//src/database-resources:build-native-ios-standard` | native production action/output | +| `liboliphaunt-native-ios-abi` | `liboliphaunt-native:finalize-runtime-ios-abi` | `//src/native/runtime:finalize-runtime-ios-abi` | replace in-place finalizer with pure declared archive/index output | +| `liboliphaunt-native-release-assets` | `liboliphaunt-native:release-assets` | `//src/native/runtime:release-assets` | replace in-place finalizer with pure declared archive/index output | +| `liboliphaunt-wasix-aot` | `extension-artifacts-wasix:build-aot` | `//src/extensions/artifacts/wasix:build-aot` | native production action/output | +| `liboliphaunt-wasix-aot` | `liboliphaunt-wasix:runtime-aot` | `//src/wasix/runtime:runtime-aot` | native production action/output | +| `liboliphaunt-wasix-aot` | `oliphaunt-pgwire-server:test-aot` | `//src/wasix/pgwire-server:test-aot` | test-only native consumer/check | +| `liboliphaunt-wasix-aot` | `oliphaunt-pgwire-server:test-integration` | `//src/wasix/pgwire-server:test-integration` | test-only native consumer/check | +| `liboliphaunt-wasix-aot` | `oliphaunt-wasix-rust:test-aot` | `//src/wasix/sdks/rust:test-aot` | test-only native consumer/check | +| `liboliphaunt-wasix-aot` | `postgres-tools-wasix:build-aot` | `//src/wasix/postgres-tools:build-aot` | native production action/output | +| `liboliphaunt-wasix-aot` | `postgres-tools-wasix:package-aot` | `//src/wasix/postgres-tools:package-aot` | native production action/output | +| `liboliphaunt-wasix-release-assets` | `liboliphaunt-wasix:release-assets` | `//src/wasix/runtime:release-assets` | replace in-place finalizer with pure declared archive/index output | +| `liboliphaunt-wasix-runtime` | `database-resources:build-wasix-icu` | `//src/database-resources:build-wasix-icu` | native production action/output | +| `liboliphaunt-wasix-runtime` | `database-resources:build-wasix-standard` | `//src/database-resources:build-wasix-standard` | native production action/output | +| `liboliphaunt-wasix-runtime` | `extension-artifacts-wasix:compiler-output` | `//src/extensions/artifacts/wasix:compiler-output` | native production action/output | +| `liboliphaunt-wasix-runtime` | `liboliphaunt-wasix:runtime-portable` | `//src/wasix/runtime:runtime-portable` | native production action/output | +| `liboliphaunt-wasix-runtime` | `postgres-tools-wasix:compiler-output` | `//src/wasix/postgres-tools:compiler-output` | native production action/output | +| `liboliphaunt-wasix-runtime` | `postgres-tools-wasix:package-portable` | `//src/wasix/postgres-tools:package-portable` | native production action/output | +| `mobile-build-android` | `integration-examples:react-native-android-build` | `//src/examples:react-native-android-build` | native production action/output | +| `mobile-build-ios` | `integration-examples:react-native-ios-build` | `//src/examples:react-native-ios-build` | native production action/output | +| `mobile-extension-packages` | `extension-packages:package-mobile` | `//src/extensions/artifacts/packages:package-mobile` | native production action/output | +| `native-consumers` | `oliphaunt-broker:test-consumer` | `//src/native/broker:test-consumer` | test-only native consumer/check | +| `native-consumers` | `oliphaunt-js:test-consumer` | `//src/native/sdks/ts:test-consumer` | test-only native consumer/check | +| `native-consumers` | `oliphaunt-js:test-consumer-published` | `//src/native/sdks/ts:test-consumer-published` | test-only native consumer/check | +| `native-consumers` | `oliphaunt-kotlin:test-native-bindings` | `//src/native/sdks/kotlin:test-native-bindings` | test-only native consumer/check | +| `native-consumers` | `oliphaunt-mobile-bindings:test-native` | `//src/native/mobile-bindings:test-native` | test-only native consumer/check | +| `native-consumers` | `oliphaunt-rust:test-consumer-runtime` | `//src/native/sdks/rust:test-consumer-runtime` | test-only native consumer/check | +| `native-consumers` | `oliphaunt-rust:test-integration` | `//src/native/sdks/rust:test-integration` | test-only native consumer/check | +| `native-consumers` | `oliphaunt-swift:test-native` | `//src/native/sdks/swift:test-native` | test-only native consumer/check | +| `native-extension-lifecycle` | `native-extension-lifecycle:lifecycle` | `//src/extensions/tests/native:lifecycle` | test-only native consumer/check | +| `node-direct` | `oliphaunt-node-direct:build-release-assets` | `//src/native/node-addon:build-release-assets` | native production action/output | +| `node-direct` | `oliphaunt-node-direct:qualify` | `//src/native/node-addon:qualify` | test-only native consumer/check | +| `node-direct-release-assets` | `oliphaunt-node-direct:finalize-release-assets` | `//src/native/node-addon:finalize-release-assets` | replace in-place finalizer with pure declared archive/index output | +| `react-native-sdk-package` | `oliphaunt-react-native:package` | `//src/native/sdks/react-native:package` | native production action/output | +| `react-native-sdk-package` | `oliphaunt-react-native:test-consumer` | `//src/native/sdks/react-native:test-consumer` | test-only native consumer/check | +| `rust-sdk-package` | `liboliphaunt-native-bindings:package` | `//src/native/rust-bindings:package` | native production action/output | +| `rust-sdk-package` | `oliphaunt-broker:package` | `//src/native/broker:package` | native production action/output | +| `rust-sdk-package` | `oliphaunt-query:package` | `//src/query/rust:package` | native production action/output | +| `rust-sdk-package` | `oliphaunt-rust:package` | `//src/native/sdks/rust:package` | native production action/output | +| `rust-sdk-package` | `oliphaunt-rust:test-consumer` | `//src/native/sdks/rust:test-consumer` | test-only native consumer/check | +| `swift-bindings` | `oliphaunt-swift:package-bindings` | `//src/native/sdks/swift:package-bindings` | native production action/output | +| `swift-sdk-package` | `oliphaunt-swift:package` | `//src/native/sdks/swift:package` | native production action/output | +| `wasix-napi` | `oliphaunt-wasix-napi:build-release-assets` | `//src/wasix/node-addon:build-release-assets` | native production action/output | +| `wasix-napi-release-assets` | `oliphaunt-wasix-napi:finalize-release-assets` | `//src/wasix/node-addon:finalize-release-assets` | replace in-place finalizer with pure declared archive/index output | +| `wasix-postmaster` | `liboliphaunt-wasix-postmaster:finalize-release-assets` | `//src/wasix/postmaster:finalize-release-assets` | replace in-place finalizer with pure declared archive/index output | +| `wasix-postmaster` | `liboliphaunt-wasix-postmaster:portable-inputs` | `//src/wasix/postmaster:portable-inputs` | native declared portable prerequisites; Linux execution | +| `wasix-postmaster` | `liboliphaunt-wasix-postmaster:release-assets` | `//src/wasix/postmaster:release-assets` | replace in-place finalizer with pure declared archive/index output | +| `wasix-release-regression` | `oliphaunt-wasix-rust:test-integration` | `//src/wasix/sdks/rust:test-integration` | test-only native consumer/check | +| `wasix-release-regression` | `oliphaunt-wasix-rust:test-regression` | `//src/wasix/sdks/rust:test-regression` | test-only native consumer/check | +| `wasix-rust-package` | `oliphaunt-pgwire-server:package` | `//src/wasix/pgwire-server:package` | native production action/output | +| `wasix-rust-package` | `oliphaunt-pgwire-server:test-consumer` | `//src/wasix/pgwire-server:test-consumer` | test-only native consumer/check | +| `wasix-rust-package` | `oliphaunt-wasix-rust:package` | `//src/wasix/sdks/rust:package` | native production action/output | +| `wasix-rust-package` | `oliphaunt-wasix-rust:test-consumer` | `//src/wasix/sdks/rust:test-consumer` | test-only native consumer/check | +| `wasix-ts-package` | `oliphaunt-wasix-ts:package` | `//src/wasix/sdks/ts:package` | native production action/output | +| `wasix-ts-sdk-package` | `oliphaunt-wasix-ts:test-browser` | `//src/wasix/sdks/ts:test-browser` | test-only native consumer/check | +| `wasix-ts-sdk-package` | `oliphaunt-wasix-ts:test-consumer` | `//src/wasix/sdks/ts:test-consumer` | test-only native consumer/check | +| `wasix-ts-sdk-package` | `postgres-tools-wasix:test-browser` | `//src/wasix/postgres-tools:test-browser` | test-only native consumer/check | +| `wasix-ts-sdk-package` | `postgres-tools-wasix:test-consumer` | `//src/wasix/postgres-tools:test-consumer` | test-only native consumer/check | diff --git a/src/docs/architecture/bazel-migration-strategy.md b/src/docs/architecture/bazel-migration-strategy.md new file mode 100644 index 000000000..2cc8acbac --- /dev/null +++ b/src/docs/architecture/bazel-migration-strategy.md @@ -0,0 +1,1241 @@ +# Native Bazel migration strategy + +Status: migration in progress; the existing qualification and publication policy remains active. +Audited: 2026-10-11. Owner: repository maintainers. + +This proposal replaces construction and qualification machinery with native +Bazel rules. It preserves independently versioned public products, conventional +consumer manifests, Release Please, and the frozen publication transaction. +The [current architecture](final-product-source-architecture.md) remains active +until the corresponding migration gates pass. The native foundation, query +packages and Linux PostgreSQL/extension construction now have executable +targets. Labels for the remaining products below describe the intended end +state. + +The implementation imports existing product identities, versions and extension +ownership before Bazel analysis. Those metadata-only targets have no payload +dependencies. Rust and TypeScript query packages use native language rules and +bounded package writers. The PostgreSQL slice invokes generators, compilers and +linkers directly. The declared glibc 2.28 Linux profiles use the pinned Zig, +Perl, Bison and Flex toolchains; the ambient compiler profile remains a local +development lane. +Construction exports are marked `scope = construction`: they cannot authorize +publication, and unclassified changed inputs cannot mean unaffected. The +acceptance fixtures exercise actual native outputs and cached action reuse. +Native release preparation now selects changed deliveries through authenticated +configured production observations and completed publication history. Release +Please calculates the versions of those selected owners. Complete hosted +construction, consumer coverage and the seed adoption anchor remain acceptance +gates; the implemented entrypoint alone does not establish release readiness. + +Linux construction and local reproduction are the default. This preserves the +reason for the existing Linux-first design: maintainers must be able to reproduce +shared CI construction and failures locally using the same declared inputs, +platforms and commands. No remote executor is required or configured. +GitHub-hosted runners provide native host and SDK verification. A foreign target +does not by itself justify moving its construction off Linux; platform SDK +requirements and actual runtime execution determine the exceptions. +Keep the construction host, package target and execution host separate. A +Linux-built foreign package retains its configured target and frozen hashes +when it moves to a native consumer; the consumer must neither reconstruct the +producer closure nor relabel those bytes as a native-host build. Every shared +construction command must work locally without a remote executor or cache. +Full WASIX, mobile, macOS and Windows construction, final carrier coverage and +publication cutover remain migration gates. Moon and the current producer +engines remain in use for products whose replacements have not passed those +gates. + +### Implementation checkpoint + +This table records demonstrated construction and qualification. A passing row +does not admit a release or establish coverage of the other rows. + +| Boundary | Demonstrated | Remaining before cutover | +| --- | --- | --- | +| Linux runtime and WASIX | Both Linux runtime jobs and the shared WASIX producer pass at `c7fa3750`, including installed browser SQL/OPFS/crash checks and the imported ARM consumer. The macOS imported consumer previously passed at `93c8079f`. | Fresh qualification of revised source and all declared host consumers. | +| WASIX tools | All 17 final shipping outputs pass the canonical publication reader, frozen staging and CI at `c7fa3750`. An installed test resolves the actual candidate tools beside an integrity-pinned public SDK. | Fresh qualification after source changes and remaining native host behavior. | +| Native extensions | Seven external extension envelopes pass installed Linux SQL/restart tests. All 32 contrib members produce canonical Linux GitHub/npm/Cargo envelopes; selective loading and actual static OpenSSL legal closure pass. The complete eight-distribution/39-member Linux ARM envelope contract passes locally against real AArch64 outputs, including split PostGIS crates and static OpenSSL legal closure; that x64-hosted check does not execute ARM SQL. Canonical 39-member and shared 38-member Linux SQL tests pass against the actual published runtime `0.3.3`, with consumers compiled against its immutable header/library. Genuine macOS/Windows pgTAP final envelopes and independent upstream SQL parity pass locally. | Full owner facades, actual macOS/Windows execution, all declared mobile/WASIX outputs, and complete installed compositions. | +| Apple and Windows | Native package/toolchain contracts and local SDK watching scenarios pass. Actual macOS profiling identified repeated sandbox input-tree traversal after completed analysis; the built-in in-memory sandbox reuse passes focused input-edit/removal and stale-output regressions, and the initial macOS host qualifier passes at `c7fa3750`. Windows startup uses a short output base; its imported build-script private name and pinned native Flex/Bison providers have local regressions. Maintained npm signature/attestation verification and completed GitHub byte binding pass for all four held SDK runtime packages `0.3.2`; installed Linux direct/broker and Cargo consumers pass. | Complete macOS job, actual Windows compiler/generated-object and generator execution, foreign installed SDK consumers, complete Apple slices, and installed application tests. | +| Postmaster | The genuine sysroot, all 29 sealed modules, AOT images, carrier and `initdb` build and run locally. Correct linked-unwinder detection passes real `longjmp` and `vfork` probes, startup/SQL, four concurrent backends, clean reopening and the existing immediate-shutdown/WAL-redo recovery contract. Canonical fence, ABI, memory and export checks pass. At `c7fa3750`, all eight declared CI tests pass, including the actual Linux x64 public archive and installed launcher initialization. | Both foreign public archives and the complete family checksum. The existing host-SIGKILL/shared-memory-liveness limitation remains separate from immediate PostgreSQL recovery. | +| Source SDK packages | Three actual Rust source crates match conventional manifests, features, held pins and canonical legal bytes. The installed native Cargo compiler/link/SQL/reopen consumer passes. Swift's declared source tree contains its root manifest and conventional version files. React Native's public npm package passes installed compiler/codegen and offline materialization/verification of the genuine held iOS carrier, using its immutable public header. | Installed WASIX Cargo execution, fresh macOS Swift qualification, final source-tag transport and installed mobile application tests. | +| SQL-only WASIX extension | pgTAP GitHub/npm/Cargo envelopes contain identical bytes for all 24 actual SQL/control files. Cargo output is byte-identical to the existing canonical dispatcher; an unchanged Bazel request runs no packaging or tests. | Complete external owner assembly and actual WASIX installed execution alongside the remaining extension families. | +| Construction evidence | The producing build emits shipping identities. Its BEP binds their bytes and configuration; physical inputs/outputs and required configured tests are checked. Final public file leaves are copied into the evidence packet and independently verified through the authenticated Actions ZIP; internal producer trees remain local. Reviewed exact-main assurance is retained in explicitly opted-in controller metadata, preserving PR construction-only transport. | Actual revised-source CI handoff, source-tag transport and complete canonical qualification for admission. The reviewed isolated builder attests input lifetime and the retained configured action capture; parsing bytes alone does not prove those execution claims. | +| Release integration | Authenticated construction observations and explicitly opted-in controller metadata have focused regressions, including physical split-Cargo transport and historical producer versions. Default publication inventory and frozen locks reject incomplete native admission. | Complete hosted coverage of all products/platforms, durable admitted baselines, the seed adoption anchor and retirement of legacy qualification machinery. | + +The migration remains incomplete. Native release preparation and publication +admission are implemented, but the complete hosted run and seed adoption anchor +have not passed. Legacy CI remains for parity until that proof permits its +atomic retirement. These construction checkpoints cannot justify publishing +or removing an existing gate. + +macOS construction uses `--config=macos-sandbox` and the same +`--host_jvm_args=-Xmx3g` startup setting throughout its shared output base. The +extra heap is a bounded allowance for Bazel's retained sandbox input maps; +actual hosted timing and memory remain qualification evidence. SDK inputs and +sandbox isolation remain declared. Linux postmaster qualification has its own +parallel owner job and reuses one base across its portable/serializer and native +marker-test profiles. Installed desktop SQL includes construction validation, +so CI does not also execute the separate construction check or duplicate the +existing Linux 39-member SQL lane. + +The audit baseline is main commit +`8316eb419999f47d6d4a61a8444e6c5ef32caf46`, tree +`91138aa6cc458471d81769e9d6543a1e3f99f0dc`. The workspace commit +`a43b10770ae0e843fe26b2dddc460c9db5cef981` has exactly that tree. +PR #294 is historical investigation context, not the authority for this plan. +The [coverage inventory](bazel-migration-inventory.md) enumerates every current +product, other project, workflow job, and CI-tagged root. + +## Recommendation and the underlying problem + +Use Bazel for source acquisition, configured construction, generation, package +assembly, deterministic checks, and build/test reuse. Remove Moon and the nested +producer engines after their replacements are proven. Keep parallel GitHub +Actions platform jobs, device operations, protected publication, and deployment. +Keep Release Please as the only semantic-version calculator and release-PR +writer. Keep Cargo/npm/Gradle/SwiftPM/CocoaPods contracts for installed consumers. + +The underlying defect is the use of approximate project relationships as a +substitute for actual construction and delivery relationships. Directory +ownership, Moon dependency scopes, task ordering, Cargo source inference, +embedded-product lists, compatibility pins, job capability booleans, and copied +build trees each encode a partial answer. Release and CI adapters combine them +as if they described the same fact. They do not. + +For example, changing a broker executable need not affect its mobile library; +a source SDK can retain its published runtime pin while tests exercise the new +workspace runtime; an unpublished browser host ships inside the WASIX TS SDK; +and an initialized seed depends on an executable producer without requiring +that producer's product to be published. These distinctions require explicit +construction, package, and installed-compatibility boundaries. + +The correct simplification is one construction authority with typed projections. +It is not one universal dependency edge. Bazel does not infer independent +versions, semantic compatibility, completed publication, or approval. Those +facts retain their own authoritative declarations and are checked against the +constructed packages. + +The final state has these non-negotiable properties: + +1. Every generated file, object, library, transformed module, package tree, and + archive has one producer and declared inputs/tools/configuration. +2. Production actions invoke compilers and bounded generators directly. They + do not invoke Moon, Cargo build, Gradle assemble, SwiftPM build, Make, Meson, + CMake, wasm-pack, or Docker scripts as another construction scheduler. +3. Tests consume production outputs; they do not become shipping dependencies + merely because they run before publication. +4. Shipping roots describe actual delivered contents, including source packages, + generated carrier sources, manifests, resources, and legal files. +5. Installed requirements remain conventional and agree with actual loaded or + incorporated runtime identities. Workspace overrides are separate tests. +6. Every release has an explicit completed baseline, bounded intent, reason for + selection, supported target coverage, immutable outputs, and consumer proof. +7. Publication and recovery upload qualified frozen bytes. They never rebuild. + +An upstream compiler, Next's framework compilation, a pinned Perl/Bison +generator, or `xcodebuild -create-xcframework` operating on completed slices can +be a bounded action. Wrapping an existing whole-product builder is a temporary +comparison harness, not this end state. Installed-consumer tests deliberately +use conventional build tools because those tools are the customer interface. + +## What was evaluated + +The resolved inventory contains 27 release products, 29 other Moon projects, +407 resolved task entries, and 265 declared registry identities: 121 Cargo, +119 npm, and 25 Maven. There are 39 tracked Cargo manifests, 44 npm manifests, +three Swift manifests, and Android/Kotlin/React Native build integration. +The eight workflows declare 83 jobs before matrix expansion, including 64 CI +jobs and ten release jobs; there are 15 composite actions. + +The 265 identities are a minimum catalog, not the final artifact count. Generated +Cargo payload parts, GitHub archives, and Swift source tags add outputs. The +publication lock must enumerate the actual set. There are 32 contrib extensions +and seven external extensions. Private producer roots, generated carriers +without `src/`, examples, performance tools, docs, and recovery paths are in +scope. + +Source findings explain why changing the scheduler alone is insufficient: + +| Current mechanism | Concrete gap | Required correction | +| --- | --- | --- | +| `tools/release/release-graph.mts`, `releaseProductsForSourceProjects` and `buildPlan` | Reverse generic non-development project edges and first release boundaries approximate shipping ownership; blanket Markdown exclusions can exclude delivered legal/content changes | Derive impact from configured shipping outputs and their production inputs; classify verification and release projections structurally | +| `tools/release/prepare-release-candidate.mts`, `includeOwnedSourceCommits` | Starts with already path-filtered commits, then adds observed ownership; old entries are not inherently bounded by the completed product boundary | Start with a complete verified history and an empty per-product selection; require every boundary to be reached | +| `with-product-history.sh` versus Release Please history | Git tags and GitHub release discovery can disagree about the last completed delivery | One completed-publication snapshot shared by preparation and admission | +| `tools/ci/ci_plan.mts` and `.github/scripts/*moon*` | Reconstruct closures, setup capability propagation, target grouping, and execution batches outside the task engine | Bazel handles dependencies and execution; a thin scheduler partitions explicit roots/configurations into GitHub jobs | +| `run-planned-moon-job.sh` | Transferred output trees lead to disabled cache/prerequisite traversal | Remove intermediate producer-tree transfers and satisfaction overrides; construction requests its complete Bazel closure. Transport verified final packages explicitly to native consumers | +| Persistent exact-extension Android/iOS builders | Source invalidation clears the PG build directory while dependency archives survive; OpenSSL/PostGIS helpers can return on archive/header presence. This finding does not establish stale extension-free base CI | Native dependency actions keyed by actual source/tools/flags; remove readiness-based reuse | +| Native desktop dependency selection | Host OpenSSL/Homebrew/PostGIS libraries and ambient generator executables influence production | Pinned repositories/toolchains and explicit parity qualification of changed dependency selection | +| WASIX initdb/frontends | Mutable common/port archives are rebuilt with different frontend/backend flags | Separate configured libraries and outputs | +| Rust SDK extension-runtime exemption | Metadata exemption conflicts with the actual loaded-runtime equality contract | Resolve the contract and test the real installed SDK plus extension; do not preserve the exemption blindly | +| Frozen-consumer workflow conditional | A skipped optional ancestor can suppress a dependent job without explicit status handling | Credential-free hosted topology test and strict expected-proof gate | + +These are source-grounded findings from the audit baseline. The implementation +now builds and tests the bounded Linux PostgreSQL/ICU/extension slice described +above. It does not establish that a particular Bazel/rules combination works on +every platform; remaining native source/generator inventories are migration +gates. + +## Authority and file disposition + +| Existing authority or machinery | Final disposition | +| --- | --- | +| `.moon/`, project `moon.yml`, Moon/Proto orchestration | Remove after all construction/check/dev surfaces have replacements | +| Source-local build definitions | Add `BUILD.bazel` beside their source owners; standard language providers describe compilation/linking | +| Tool/bootstrap pins and immutable `source.toml` files | Retain one pin authority; import through Bzlmod repository/module extensions and registered toolchains | +| `release-please-config.json`, `.release-please-manifest.json`, product version mirrors | Retain Release Please policy; validate deterministic conventional mirrors | +| Product `release.toml` | Retain irreducible authored product membership/version ownership, upstream and public support/recipe facts. Import canonical public names into construction; derive carrier/target inventories from actual shipping exports. Keep generated projections where consumers need them; remove competing authored inventories and inferred shared-source/embedded-construction arrays after native replacement | +| Extension catalog, recipes, component and target contracts | Retain SQL identities, support, ABI, resources, and legal facts; replace producer-kind dispatch with native targets and check agreement | +| Cargo/npm/Gradle/Swift/podspec manifests and downstream build scripts | Retain installed contracts; import or validate overlapping facts rather than authoring two dependency resolutions | +| `tools/release/release-graph.mts`, `release_plan.mts` | Split retained metadata/history/admission readers from obsolete Moon/path/Cargo construction inference; consume Bazel exports | +| `prepare-release-candidate.mts`, `release-dependency-plan.mts`, `default-extension-release-plan.mts`, `consumer-compatibility.mts` | One bounded Release Please adapter and explicit supported-recipe/adoption policy; remove overlapping cascades and bump monkey-patches | +| `sync-release-pr.mts`, `verify-release-commit.mts`, metadata checks | Retain deterministic projection/admission, with independent manifest/history/output oracles and fixed-point checks | +| `package-release-carriers.{mts,sh}` | Remove central product build dispatch; selected shipping labels construct outputs | +| `tools/packaging/` and product assembly algorithms | Retain useful TS/Rust format, split, legal, ABI, checksum, and safety logic as declared leaf tools; remove ambient discovery and internal caches | +| Native/WASIX broad shell producers and stamp caches | Remove production bodies after source-native compiler/generator/link actions pass parity gates | +| `publication-catalog.mts`, `release-artifact-targets.mts` | Retain normalization/strict ownership contracts; replace Moon scans and independently authored target matrices with configured product exports | +| `publication-lock.mts`, capsule, lifecycle, frozen publishers, controller | Retain immutable identities, exhaustive discovery, exact-source admission, recovery, and reconciliation; adapt output paths/evidence | +| GitHub Actions | Retain event identity, runner allocation, device setup, approvals, credentials, immutable evidence transport, and external mutations | +| Docs/examples/performance/developer scripts | Native build/check/run targets; network, live deployment, device control, and measurements remain explicit operations | + +Delete `.github/scripts/moon-task-capabilities.mts`, +`select-moon-target-groups.mts`, `select-planned-moon-targets.mts`, +`resolve-planned-moon-execution.mts`, `write-affected-moon-target-matrices.*`, +`run-moon-targets.sh`, and `run-planned-moon-job.sh` after their guarantees have +native owners. Remove `tools/ci/affected.mts`, Moon snapshot/context/observation +adapters, `setup-moon`, Moon-only tool pins, construction output-tree transfers, +and their obsolete implementation-shape tests. Preserve behavioral guarantees +through real graph/action/consumer tests before deleting the old tests. + +Do not delete multifunction release modules wholesale. Historical compatibility +readers, frozen-byte validators, source/tag guards, and publication receipts are +valuable; project inference and construction dispatch are the replaceable parts. +Recovery needs a bounded reader for old approved capsules until their supported +recovery window closes. + +## Native construction model + +### Targets and outputs + +Keep source navigation intact. Use source-local labels such as: + +```text +//src/query/rust:query +//src/query/rust:source_package +//src/native/broker:broker_lib +//src/native/broker:broker +//src/native/runtime:liboliphaunt +//src/native/runtime:runtime_archive +//src/extensions/external/postgis:embedded_module +//src/extensions/external/postgis:static_archive +//src/wasix/runtime:portable_archive +//src/wasix/runtime:runtime_aot +//src/native/sdks/swift:release_source_tree +``` + +The `BUILD.bazel` graph owns actual compilation, generator, link, embed, resource, +and packaging prerequisites. A product shipping root exports its product ID, +supported configurations, carrier roles, exact outputs, and applicable package +contracts. Use standard `CcInfo`, Rust, JS, JVM, and Swift providers first. Add +small providers only for missing domain facts such as a Wasm module/interface, +AOT descriptor, resource/seed identity, or publication envelope. + +A provider/aspect exports these declarations for the release adapter and CI +scheduler. It must not become another handwritten graph. Its production view +starts from actual shipping files and producer actions, excluding independent +test/validation outputs. Tools that produce shipping bytes are included; a +validator does not become a shipping input merely because it inspects them. +`cquery deps(...)` alone is too broad for this distinction. + +Rules own declared immutable outputs. Replace in-place finalizers with assembly +from the payload plus ABI/license/descriptor inputs into a new output. An action +must not rewrite another action's output, mutate source files, find a sibling +`target/` tree, or decide reuse from a private stamp. Archive creators consume +explicit mappings; package validators independently inspect their result. +[Bazel rules and providers](https://bazel.build/extending/rules) supply these +mechanisms, not the Oliphaunt-specific declarations. + +Do not add a generic artifact framework, custom cache, universal dependency DSL, +or one Bazel module per release product. One repository module can contain many +independently versioned products. Bzlmod resolves build dependencies; it is not +an installed-package SemVer compatibility engine. +[Bzlmod resolution](https://bazel.build/external/module). + +### Where dependencies and version ownership come from + +Every relationship has a declared meaning and one authoritative source. Bazel +does not infer release version equality from compilation dependencies. + +| Fact | Authority and how the system uses it | +| --- | --- | +| Uses source, a library, generator, tool or resource to construct output | Native target/action inputs and language providers. Import actual conventional dependency declarations where appropriate; explicitly declare C/PG sources and generators. Derived configured production exports explain rebuild and delivery impact | +| A carrier takes a product's publication version | Product/carrier ownership metadata, imported into shipping rules. A carrier's version is rendered from its owner's selected version, never independently bumped | +| An installed package accepts a dependency version | Cargo/npm/POM/Swift/podspec requirements; extension ABI/host/support facts retain their explicit descriptor where these formats cannot express them. Rendered and packed manifests must agree | +| A test observes a product | Test inputs/runfiles and supported configurations. This requests verification, not shared versioning or release ownership | + +For contrib, the existing authoritative declaration is +[`src/extensions/contrib/carriers.toml`](../../extensions/contrib/carriers.toml): + +```toml +native_owner = "liboliphaunt-native" +wasix_owner = "liboliphaunt-wasix" +``` + +Keep/import that declaration rather than duplicating those IDs in BUILD rules +and release scripts. TOML is the existing compact authority, not a Bazel +requirement: ownership solely in BUILD would also be valid if the old authored +copy were removed. Choose one location per fact. Public naming/support policy +can remain explicit, but configured carrier inventories must be derived from +the actual package targets rather than separately maintained in release scripts. +Successful compilation does not establish a public support promise. + +Generated snapshots may repeat facts for consumers; they must be one-way and +must not become an independent selection authority. For example, external +extension `registry_packages`/`publish_targets` arrays are already regenerated +by `sync-release-pr.mts`; their presence alone is not evidence of competing +authored inventories. Change their producer to consume native exports where +appropriate, rather than deleting required public/recovery metadata blindly. + +Expose owner identity/version as data or a metadata-only target with no payload +dependencies. A carrier must not point back to the shipping aggregate that +contains it: that would create a target cycle. Construction flows from identity +and payload inputs to carriers, then to the product aggregate. Production uses +only relevant product versions, avoiding global version-manifest invalidation. + +Ordinary Starlark rule analysis cannot read TOML file contents. The metadata +import must be tracked repository/module evaluation or a checked generated +projection available before analysis, with one-way provenance to its authored +source. A build action cannot generate a `.bzl` file and load it during that same +analysis. The foundation gate must prove owner/version edits propagate and +unrelated product edits leave production reusable; this is implementation work, +not an implied automatic import. +[Rule analysis and file inputs](https://bazel.build/extending/rules). + +Native contrib envelopes take the native runtime owner's +version; WASIX envelopes take the WASIX runtime owner's version. Those two +products remain independently versioned. There is no third contrib release +version or a release product per SQL member. PostgreSQL's upstream version and +each SQL extension's control-file version are separate identities; for example, +`pg_trgm`'s SQL version is not its carrier's publication version. + +The actual contrib modules, SQL/control files and legal contents are explicit +package inputs. A changed member selects each runtime owner whose supported +shipping closure includes that change, measured against that owner's completed +baseline. Its envelopes receive that owner's candidate version. A runtime +release renders its owned contrib carrier versions even when the member bytes +are unchanged; shared source alone never couples the native/WASIX bump numbers. + +External extensions instead own independent release products. Their declared +runtime host requirement is compatibility, not version equality. An SDK's +installed historical pin is also distinct from its checkout build dependency. +Mandatory adoption follows explicit public-support/default-install policy and +actual requirements; it cannot be inferred from every Bazel reverse dependency. + +The thin release adapter consumes derived construction facts plus these explicit +ownership/support facts. Require one release owner per publication identity, +valid referenced products, correct owner-derived carrier versions, and actual +packed requirements matching the claimed compatibility. Reject missing or +conflicting ownership rather than guess from names or paths. A small independent +scenario must cover distinct native/WASIX versions, a contrib-only change, an +external-only change and an unchanged historical SDK pin. These refine the +existing coverage/selection fixtures; they do not introduce another graph DSL. + +Runtime-owned contrib is appropriate for the current distribution contract. +Giving contrib independent versions would be a deliberate product change with +its own host/support/adoption policy. Do not introduce another release component +merely to reuse a version-group plugin. Release Please's +[linked-versions plugin](https://github.com/googleapis/release-please/blob/main/docs/manifest-releaser.md#linked-versions) +can synchronize genuinely separate components; these carriers already inherit +one owner's selected version and need no additional version calculation. + +### Platforms, tools, and reproducibility + +Introduce pinned `.bazelversion`, `MODULE.bazel` and its lock, +`.bazelrc`, `build/platforms`, `build/toolchains`, and a small `tools/bazel` +integration area. Verify the Bazel bootstrap itself. Pins in existing TOMLs +should feed repository registration instead of being copied into workflows, +BUILD attributes, and shell installers. + +Separate target platform from execution platform. Desktop outputs cover Linux +x64/arm64 GNU, macOS arm64, and Windows x64 MSVC. Android covers arm64-v8a and +x86_64. Apple aggregates macOS/device/simulator slices. Portable WASIX, browser +Wasm, AOT host triples, and mobile seed compatibility domains are distinct. +`ios-xcframework` and `ios-datum64` are not CPU architectures. + +Toolchain identity includes compiler/linker/archiver, sysroot/SDK, target API or +deployment floor, CRT/C++ runtime, CPU baseline, feature flags, generators, and +output-affecting environment. Xcode and Windows SDKs remain licensed host +facilities, but their exact observed identities must enter registered build +configuration and cache identity. An ambient PATH/Homebrew lookup is not a +production contract. Sandbox/offline builds, changed-tool probes, and clean +execution are necessary evidence of input completeness. +[Hermeticity](https://bazel.build/basics/hermeticity), +[platforms](https://bazel.build/concepts/platforms), and +[toolchains](https://bazel.build/extending/toolchains). + +Preserve safe extraction, bounded transport, checksums, notices, platform binary +baselines, ABI/export/import checks, relocation, empty directories, and archive +limits. Declared input symlinks in Bazel's execroot/runfiles are legitimate; +existing blanket symlink rejection must distinguish them from unsafe symlinks +inside delivered archives. Reuse format/security algorithms with explicit +materialization or validated input mappings. + +Require repeatable bytes for compilers, generators and package encoding under +the same declared inputs and configuration. Normalize incidental timestamps, +paths, locale and linker metadata; different configurations can differ. + +PostgreSQL initialization intentionally consumes the clock, process identity and +secure randomness. Its PGDATA system identifier, WAL/control records and +authentication nonce can differ between equivalent initializations. Archive +normalization cannot make these databases identical. Treat initialization as +an explicit state-producing boundary: declare its real producer, resources, +recipe, configuration and ABI/compatibility facts, qualify one produced tree, +then freeze its exact bytes in the existing publication capsule. Reopen and +restore probes operate on disposable copies. Do not normalize WAL/control +records or replace secure randomness to manufacture byte equality. + +Seed release selection compares consumed inputs against the completed baseline, +not fresh PGDATA hashes or volatile probe fields. Package hashes establish +integrity of the frozen result. Exact runtime-version and WASIX-module admission +remain required compatibility facts. Recovery reuses completed frozen bytes; +missing bytes cannot justify regenerating an already published version. Seed +acceptance must prove those selection, compatibility, freeze and recovery +contracts rather than promise identical independent database initialization. + +### Native PostgreSQL, libraries, extensions, and seeds + +The main effort is a native build-description port, not installing Bazel: + +| Construction family | Required native boundary and acceptance | +| --- | --- | +| PostgreSQL source/configuration | Acquire the exact PG pin and ordered semantic patches. Inventory every source, platform replacement, config header, catalog/BKI, nodes/fmgr/errors/lwlocks/wait-events, grammar/scanner, probe, timezone and support-data generator. Generate named outputs using pinned tools | +| Ordinary versus embedded PG | Separate standalone backend/frontends/libpq/tools from embedded backend/common/port/timezone/JIT stubs. Preserve distinct definitions, provider imports, exports, signal/IPC semantics, and Windows import libraries | +| Oliphaunt C runtime | Compile wrapper units and shared/mobile links directly. The actual embedded version literal is an input to its C unit; a version update need not recompile every PG unit | +| Contrib and external extensions | Per-member server/embedded/static/SQL targets. Contrib has runtime release owners, not a new independent product. Preserve optional-extension-clean base runtime, registration aliases, preload/lifecycle and target restrictions | +| PostgreSQL tools | Native product owns pg_dump, pg_basebackup and psql. Build requested frontend closures without a required embedded-runtime link. WASIX tool product owns pg_dump and psql | +| ICU | Separate common/i18n/stubdata libraries from canonical ICU data. Inspect which host generators are actually needed; do not rebuild a discarded data-generation pipeline. Existing pinned Windows ICU binaries can be declared external imports until an intentional source port is qualified | +| OpenSSL/PostGIS dependencies | Source-native crypto, GEOS, PROJ, SQLite, JSON-C, libxml2 and Android libiconv. Qualify replacing desktop host libraries with pinned sources. PROJ needs a target SQLite library and a separate execution SQLite tool; database embedding affects compilation | +| PostGIS | Explicit config/parser/geometry/FlatGeobuf/SQL/resource actions, disabled-feature profile, provider-specific modules and prefixed mobile archives. Keep SQL generation prerequisites even where the corresponding optional module is excluded | +| Mobile extension libraries | Compile selected registry C and whole-archive selected extensions/dependencies into the Android library; preserve C++ linkage and 16KB alignment. Apple XCFrameworks consume exact configured slices | +| Resources/seeds | Canonical ICU extraction is independent of PG compilation. Seed generation consumes actual initdb/runtime/share-data launch closure. Android/iOS datum64 producer domains require ABI receipts; do not run target phone binaries on the build host | +| Broker | Distinct Rust library and executable targets. Preserve its Linux minimum-host loader/argument probe through declared Rust/linker/sysroot baseline inputs before deleting the Docker/Cargo producer. Runtime loading/fixtures belong to applicable consumer tests; a main.rs change must not reach library-only mobile consumers | + +Remove Make/Meson/CMake/nmake/PGXS producer authority, fake pg_config/config +discovery, archive/object scanning to recover source inventories, source-tree +mutation, depth-limited fingerprints, readiness shortcuts, and ccache layers. +Retain semantic source patches and output checks. Build-system-only patches +become native flags/provider relationships when their foreign engine disappears. +Source inventories for pinned upstream libraries must be inspected and reviewed; +this audit cannot honestly predeclare absent upstream generator files. + +### WASIX, AOT, browser host, and postmaster + +Preserve three distinct Wasmer contexts: single-backend/AOT 7.2.1/0.702.1, +browser 6.1/0.601 with its backports, and patched postmaster +7.2.0-alpha.2/0.702.0-alpha.2. Do not unify their Cargo locks/features or +serialization contracts. + +Portable construction must expose separate backend/frontend common/port, shims, +support modules, initdb, tool links, runtime data, strict main links and Binaryen +transforms. Tools retain their frontend optimization/import-closure profile. +AOT is one transform per module/configuration, with the exact serializer/LLVM, +host triple, CPU baseline, exception/features and options recorded. Runtime, +tools and extensions can share the serializer without sharing release ownership. + +The runtime's required exports are derived from compiled side-module imports. +The acyclic native order is side modules plus configured headers, then canonical +required-export list, then strict main link and closure validation. A changed +extension can require compilation to prove its import interface is unchanged; +if the emitted list is identical, Bazel can avoid a runtime relink. Static +reachability cannot predict that value. Release treatment is addressed below. + +Postmaster remains a separate product. Port its patched libc variants/sysroots, +native Rust compiler/executor feature split, core and 27 side modules, +export sealing, Binaryen pass, final export/start/atomic validation, then +linear-memory sealing, then per-module AOT, then the 29-module compiler-free +carrier. Preserve the memory/ABI/concurrency policies and final receipts; do +not serialize an earlier unsealed module or ship the compiler feature union. +Native clients used by regression tests are their own build prerequisites. + +The browser host becomes native Rust Wasm compilation, matching wasm-bindgen, +Binaryen, and Rollup actions with separately resolved patched Cargo/npm inputs. +Its JS/Worker/Wasm/provenance outputs ship in `oliphaunt-wasix-ts`; the private +host has no new product version. Replace wasm-pack orchestration while preserving +its actual transform behavior. + +WASIX N-API explicitly incorporates SDK/server source and runtime/tools/resource +payloads. Native direct N-API loads the native runtime separately. These are +different release-impact contracts. Preserve the WASIX addon glibc baseline by +a pinned execution sysroot/image and binary checks before deleting its Docker +build wrapper. + +### SDKs, source packages, applications, docs, and tools + +Use `rules_rust` and Cargo-lock import contexts for dependencies, with explicit +first-party library/binary/features/build-script data. Compilers run directly; +published Cargo build helpers and build.rs remain downstream functionality. +Source-package roots contain source/legal/generated files and normalized +manifests, not checkout rlibs or freshly built dependencies that are not shipped. +[Cargo import](https://bazelbuild.github.io/rules_rust/crate_universe_bzlmod.html) +and [build-script integration](https://bazelbuild.github.io/rules_rust/cargo_build_script.html). + +Audit imported build.rs behavior too, particularly native compression and +Wasmer/LLVM dependencies. Pure cfg/metadata/code generation can remain a declared +leaf. A build script that compiles an opaque native library, launches a foreign +producer, or downloads assets must instead consume declared native library/tool +providers, with appropriate import annotations or reviewed BUILD overlays. +Cargo-lock import alone does not prove that third-party construction is native +or hermetic; this is part of the acquired-source/toolchain acceptance inventory. + +Use mature `rules_js`/`rules_ts`, pinned Node, and one pnpm resolution for the +internal npm graph. Migrate the root Bun lock without dependency upgrades: +compare versions/integrities, peers, optional/platform dependencies, catalogs, +overrides and native lifecycle outputs. Do not maintain two root resolutions +indefinitely or assume rules_js imports bun.lock. Keep pinned Bun as an explicit +tool/test runtime for existing Bun APIs and supported consumer tests; authored +scripting stays TypeScript. Isolated consumer locks can legitimately remain. +Keep docs' separately resolved TypeScript where required. +[rules_js design](https://github.com/aspect-build/rules_js). + +TypeScript package actions preserve ESM/CJS/declarations, nested module markers, +conditional exports and emitted consumer tools. Select typechecking explicitly +when emit rules permit split validation; do not pay for duplicate full tsc runs. +Use declared esbuild/Rollup/Bun compiler actions only with their real input sets. + +UniFFI generation is a declared execution tool using exact library/configured +metadata. Share compatible generation across Swift/Kotlin without merging their +platform binaries or public versions. Kotlin requires Android/JNI/AIDL/resource +compilation plus the exact AAR/plugin/marker/POM/source/javadoc/module envelope; +JVM export rules alone do not implement it. Its currently expected ten primary +publication files are Android AAR/POM/sources JAR/javadoc JAR, plugin +JAR/POM/module/sources JAR/javadoc JAR, and marker POM. Only the plugin publishes +module metadata: Android module metadata would redirect to an unpublished root. +Preserve Android-only public coordinates; do not invent JVM/KMP publications. +Signatures are handled by publication. + +Swift uses native Swift/C/Rust targets and Apple archive rules; assembly and +consumer checks run on macOS. Render the public Package.swift/source tag and +binary URL/checksum closure from final outputs. Development `.build` paths and +unsafe local links must not appear in that public tree. +Preserve the empty default extension set, separately owned opt-in extension +carriers, and frozen extension-generator/catalog inputs in the release tree. + +RN needs explicit TS/spec/codegen/JSI/Objective-C++/Swift/Kotlin/JNI targets and +the declared Android mobile extension library. Its npm package still ships +Gradle/CMake/podspec/codegen/templates because consumers use them. Run installed +RN/Expo builds to prove those public entrypoints. Internal Bazel app compilation +alone is not that proof. +[Kotlin](https://github.com/bazel-contrib/rules_kotlin), +[Android](https://github.com/bazelbuild/rules_android), +[Swift](https://github.com/bazelbuild/rules_swift), +[Apple](https://github.com/bazelbuild/rules_apple), and +[RN codegen](https://reactnative.dev/docs/turbo-native-modules-introduction). + +All six example surfaces remain: native/WASIX Electron and Tauri, WASIX browser, +and native Expo Android/iOS. Separate native application construction from +installed-ecosystem integration tests. Preserve Tauri build context, Electron +sidecars, workers, serving headers, supported topologies and extension profiles. +GUI/device launching is an operation, not a hidden compiler fallback. + +Docs becomes declared content/catalog/MDX/Next/static-export/smoke targets. +Completed-release data is acquired outside construction and passed as a frozen +input; ordinary builds must not read live release state invisibly. Deployment +hook/live verification remain separate operations. Docs does not recommend +package versions. Benchmarks retain declared runners/fixtures and plan tests; +measurements run uncached with host metadata. Formatting, hooks, acquisition +tests, security checks and developer commands get explicit targets; remove +obsolete bootstrap duplication when their consumers have migrated. + +## Affectedness, execution, and release selection + +| Question | Deterministic answer | +| --- | --- | +| What might be affected? | Old and new configured construction relationships identify potential impact, including removed edges/files | +| What is requested? | CI/release selects explicit product/test roots and supported configurations | +| What must build now? | Bazel executes demanded invalid actions and materializes valid cached outputs; affectedness is not an instruction to rerun everything | +| What must be checked? | Required semantic tests/validators, reusing trusted results for identical complete inputs; fresh observations where external state or current execution is part of the claim | +| What needs publication? | Delivery changes since that product's completed publication, plus required explicit compatibility adoption or deliberate release intent | +| What version? | Release Please applies bounded Conventional Commit and public-support intent to the published version | + +A product needing no release may still be a build prerequisite or test subject. +A product needing no new compilation may need new package assembly, manifest +validation, installed-consumer proof, or publication. A docs-only change can +need a docs build/check while selecting zero package releases. + +Start CI with bounded platform cohorts and native cache reuse. Add job-elision +only where measured startup/download cost justifies it. If retained, root +selection uses both old and new configured graphs, including deleted/renamed +inputs, BUILD/Starlark changes, toolchain/config changes and removed support. +Unknown analysis widens checks or fails required admission; it never silently +means unaffected. Loading-phase query is conservative; cquery evaluates selected +configuration; aquery exposes declared actions. An aquery ActionKey is not the +content-based remote cache identity or a package compatibility proof. +[cquery](https://bazel.build/query/cquery), +[aquery](https://bazel.build/query/aquery). + +### Concrete release decision + +Adopt a conservative, explicit delivery rule: an authored change to actual +shipping source, source pins, rules, used toolchains, resources, manifests, +supported targets, packaging writers, or legal inputs since the product's last +completed publication selects its shipping owner. Verification-only inputs +outside those roots do not. An unclassified delivery change receives patch +intent through the same Release Please strategy; authored feature/breaking +intent can require more. Removed public exact-host support contributes breaking +intent. Do not silently skip delivery changes because their commit says chore. + +This is minimal with respect to the declared delivery/support contract, not a +universal semantic-equivalence test. A changed compiler recipe can warrant a +release even if a particular build happens to emit identical bytes. Narrow +construction-only migration parity and derived-interface exceptions require +explicit policy and independent evidence. There is no generic tooling bypass. + +For a derived interface such as required WASIX exports, declare the contract +boundary in the native provider: runtime linking consumes that interface, not +external-extension implementation semantics. To exclude the runtime from a +release, compare the newly emitted interface to the actual completed baseline, +verify its contract, and establish that no other runtime delivery input changed. +Admit this exclusion only for version-independent canonical contract outputs +under matching contract configurations and generator/tool identities. Retain +the scope receipt and revalidate it against the final production interface; +candidate-version-bearing output cannot justify pre-assignment exclusion. +The changed external extension still releases. Runtime-owned contrib payloads +are shipping runtime inputs and do not qualify for that exclusion. Missing +baseline interface evidence means conservative selection. This exception can +require building the changed module; no static no-build guarantee is possible. + +Do not use final version-bearing package bytes to seed release decisions. +Select authored changes before the generated bump. Recognize only validated +structural Release Please projections when excluding generated version/changelog +updates from later intent; do not ignore entire Cargo/package/version files. +Actual version and requirement changes remain inputs to final package actions. +Net source changes that cancel exactly at the declared input level need not +select a new delivery merely because an old feature commit appears in history. + +### Baselines and Release Please integration + +Preparation follows this sequence: + +1. Freeze main source SHA/tree and the completed-publication snapshot. Per product + record version, original source, actual immutable manifest requirements and + lock/receipt identity. Drafts, tags alone, merged PRs and partial publication + are not completion. Preserve the unresolved merged-release guard. +2. Load complete history before product filtering, to the oldest required + boundary, and verify every boundary was reached. History/page limits are + errors. A release commit outside a product directory still ends its history. +3. Compare each product's own old/new configured shipping production inputs, + including removed dependencies and action-producing tools. Retain changed + input, root/configuration, baseline and dependency-path witnesses. This is + a graph export and diff, not another build/cache hash engine. +4. Select direct delivery intents, then close mandatory compatibility adoption + from real manifests, incorporated-source facts and declared supported recipes. + Recompute Release Please strategies from the same published versions and + accumulated intents to a monotonic selection fixed point; never bump an + already bumped candidate again on each iteration. +5. Render conventional versions/requirements/carrier metadata/locks. A second + run must change nothing. Before updating the release branch, independently + check rendered/normalized manifest semantics, allowed projection fields, + baseline witnesses and excluded products. Actual archive/packed-manifest + validation runs after final native assembly, before freeze/publication; this + does not add a full platform package pass before creating the PR. + +Capture configured production facts at completed publication and reuse that +immutable baseline. Analyze/export once per distinct source/configuration, not +once per carrier or product sharing that source. Cache the read-only derived +analysis by its exact inputs; it must not grow a second action cache. Preparation +normally needs head analysis and saved completed facts, with historical analysis +only for the bridge or missing legacy evidence. + +Use one typed adapter around Release Please's versioned APIs/plugin hooks. +Remove automatic cross-product `node-workspace` propagation, global Rust +workspace intent and private version-strategy monkey-patches once explicit +adoption covers their intended guarantees. Keep ecosystem version updaters and +the deliberate shared product containing `oliphaunt` and `oliphaunt-build`. +If the pinned library lacks a clean hook for the frozen bounded context, obtain +that narrow capability before cutover; do not preserve an unverified fallback. +[Release Please manifest mode](https://github.com/googleapis/release-please/blob/main/docs/manifest-releaser.md). + +Historical publications predate Bazel BUILD files. Running today's rules at an +old source SHA does not reconstruct its old production graph. Before switching +selection, establish an audited baseline per product from actual published +source/artifacts/recipes, with an explicit mapping to native roots. A read-only +legacy baseline adapter can exist during this bridge; missing facts fail or +widen review. Do not substitute an empty old graph or stamp today's closure as +historical truth. Retire the adapter for each product after its first completed +native publication carries native facts. Migration parity can avoid gratuitous +bulk bumps; behavior-changing ports require justified delivery releases. + +### Independent versions and installed compatibility + +A compiled binary that incorporates changed source/payload is a delivery +dependent. A source package referencing an immutable historical product is an +installed dependent: that requirement can remain unless adoption is required. +The Bazel checkout compile edge does not automatically rewrite its public pin. +Shipping configurations use declared/adopted candidate identities or verified +historical artifacts; current workspace bytes cannot be labeled as an older pin. + +Keep source/candidate compatibility tests and final installed-package tests +separate. The latter use final normalized Cargo/npm/POM/Swift/RN requirements, +supported features/targets and the runtime the consumer actually loads. Include +default SDK plus external/contrib extension recipes, standard/ICU, tools, +direct/broker/server/browser and mobile surfaces where supported. Resolve the +Rust SDK equality/exemption gap before claiming the policy coherent. + +An extension's exact runtime promise remains exact until a versioned ABI/support +contract and actual consumer matrix justify a broader range. Independent SemVer +numbers, identical PG majors, or successful source compilation do not prove +compatibility. Conversely, a producer release alone is not a reason to update +every compatible historical consumer. + +## GitHub Actions and execution infrastructure + +Keep multiple jobs/invocations. The thin TS plan contains source/request identity, +explicit `(root, configuration)` requirements, compatible runner cohorts, +expected outputs, and required external proof cases. It does not topologically +schedule actions, infer tool availability, or mark downloaded prerequisites +satisfied. Construction roots include their complete native prerequisites on +their declared execution host. Consumer roots instead receive the exact frozen +package inputs they test; their closure must not pull those producer actions +onto a different host. + +Use parallel construction and behavior cohorts with distinct purposes. Batch +related Linux roots per execution configuration so one invocation shares +analysis and actions. Construct supported Linux, Android and portable WASIX +outputs on Linux. Keep native Apple/MSVC construction where the declared SDK or +toolchain requires it. Swift compilation, Apple SDK-dependent framework actions +and SwiftPM consumers run on macOS; pure archive assembly stays on Linux when +its complete final inputs are available. Devices/browser/GUI tests use separately +allocated suitable hosts; `--platforms` does not allocate a runner or emulator. +A native compiler/rule integration probe can deliberately +construct a small fixture on its host, but cannot stand in for testing the final +Linux-constructed package. + +Keep portable WASIX production and supported cross-compilation on Linux so +maintainers can reproduce them locally. The existing serializer supports a +target independent of its execution host; expose that target explicitly and +prove each produced AOT envelope by deserializing and running it on its real +target host. Foreign object generation alone is insufficient. Apple SDK and +MSVC-dependent actions stay on native GitHub runners with declared SDK/compiler +inputs. This architecture requires no hosted remote executor. + +For example, the Linux x64 runtime and installed package cohort uses the same +command in a checkout and in `.github/workflows/bazel.yml`: + +```sh +profile=//build_defs/native:linux_x86_64_glibc_2_28 +bash tools/dev/bazel.sh test -c opt //:native_linux_tests \ + --platforms="$profile" --host_platform="$profile" \ + --java_runtime_version=remotejdk_17 --tool_java_runtime_version=remotejdk_17 --jobs=2 +``` + +Android construction stays on this Linux execution profile while its declared +target transitions select the Android ABI. Platform execution tests add the +actual device or foreign host; they do not change the Linux construction proof. + +Complete final packages can move between qualification jobs at the frozen +artifact boundary. Intermediate compiler inputs inside a construction closure +must remain native declared dependencies. Where a target genuinely cannot be +constructed on Linux, port the necessary execution toolchain to its native host +or construct the complete package on that host; do not silently skip the +prerequisite. Cache hits do not confer execution capability. +[Execution groups](https://bazel.build/extending/exec-groups), +[remote rule requirements](https://bazel.build/remote/rules), and +[execution/cache controls](https://bazel.build/reference/be/common-definitions). + +A remote execution service may later improve throughput. Adopt it only after +local and hosted execution establish the platform contracts; credentials, +executor images and cold-cache capability then become explicit configuration. +Its absence cannot block the default Linux reproduction path. Temporary +intermediate imports during migration still require exact +digest/configuration/producer descriptors and a removal gate. + +No global compiler root needs every desktop OS in one invocation. Linux +construction exports the complete supported cross-target packages; native +construction exceptions export their own complete configured packages. Frozen +publication collates these packages without reconstructing them. This is an +explicit operational trust boundary, not a shortcut within construction. Apple +aggregate artifacts can be fully constructed on the Apple host. Device jobs +similarly consume an exact qualified app envelope. + +The release cross-host handoff is the lock-derived `frozenFiles` projection, +not a copied Bazel output base or a second authored inventory. Reuse the existing +physical output capture and publication-lock file expansion: preserve the source commit +and tree, configured shipping roots, target identity, relative member paths, +hashes, sizes and required modes/directory boundaries. Transport only the final +package closure plus its construction evidence, then verify the files again on +the receiving host. Consumer evidence identifies that same source and lock +digest, the package hashes it actually consumed, and the observed host/SDK/device +identity. It does not rewrite construction provenance. + +During migration, construction-only capture can use the same physical output +boundary before publication integration. The WASIX helper captures the five +final Cargo envelopes; its importer verifies exact source identity, canonical +targets, archive hashes and packaged contents. These receipts neither authorize +publication nor prove foreign-host execution. GitHub artifact transport and +installed macOS/Windows consumption must still pass for those exact files. + +Host/device tests install or execute these files directly, using conventional +consumer compilers where that is the public interface. Missing, substituted or +wrong-target bytes fail before execution. They must not invoke the shipping +producer, satisfy a Bazel dependency by placing files in its output directory, +fall back to workspace runtime sources, or use a cache entry as host execution +proof. For example, a Linux-only WASIX serializer stays in the Linux construction +cohort; macOS and Windows qualification must deserialize and execute its +transported AOT images with their native runtime. Calling a target that still depends on the +serializer on those hosts would request an unavailable Linux execution action, +not provide cross-host qualification. + +| Workflow | Migration | +| --- | --- | +| `.github/workflows/ci.yml` | Native platform build/test cohorts, fresh operational proof, one strict Required/Qualified admission path | +| `.github/workflows/liboliphaunt-native-desktop.yml` | Remove reusable construction workflow after native desktop cutover | +| `.github/workflows/extension-artifacts-native.yml` | Remove after native extension roots work in platform cohorts | +| `.github/workflows/broker-runtime.yml` | Remove after native library/executable/package targets | +| `.github/workflows/mobile-extension-packages.yml` | Remove after Android/Apple construction/assembly targets | +| `.github/workflows/wasix-host.yml` | Remove after complete portable-to-host execution is proven | +| `.github/workflows/mobile-e2e.yml` | Keep exact-artifact diagnostic replay, sharing the ordinary installed-app harness | +| `.github/workflows/release.yml` | Keep prepare/qualify/freeze/consumer/ready/bootstrap/publish/docs state machine; replace construction context and transport | + +Replace setup actions with declared language/tools where possible. Retain narrow +Xcode/MSVC registration, device/ADB/KVM/licensing setup, orchestrator bootstrap +and publisher readiness. Wasmer LLVM becomes a pinned dependency; Docker Buildx +ceases to be a construction engine. Do not duplicate pins in remaining setup +actions. Genuine installed consumers still need their exact package-manager +clients. + +Preserve PR/merge-group versus exact-main publication trust. Focused/debug runs +cannot become Qualified. Check every expected label/configuration/output/proof, +not just green jobs or `bazel test //...`: incompatible/manual targets can be +skipped. BEP supplies actual configured target, output and test results; the +admission gate compares them with the expected inventory. +[Build Event Protocol](https://bazel.build/remote/bep). + +Retain event/concurrency cancellation, including the current runnerless PR-closed +tombstone. Preserve exact-main dispatch comparison admission: a manual request +cannot narrow qualification by inventing a comparison base instead of the +required immutable sole parent. Test these rules through credential-free hosted +events as well as local policy checks. + +## Cache, tests, and efficient verification + +Local Bazel action reuse and declared toolchains are the baseline. The slow +Linux WASIX job can transport Bazel's standard disk action cache with GitHub's +existing cache service; no remote executor or separately hosted cache is +required. The optional cache is scoped by OS, CPU, cohort and Bazel version, +with immutable source keys and a matching restore prefix. Stop the writer +before saving. Retain the action cache's 2 GiB logical-byte garbage collection +target and permit at most 3 GiB of allocated storage for each transported action +cache. Repository downloads retain Bazel's per-job content-addressed cache; +fetch missing pinned files normally rather than spending the shared GitHub +storage budget on download archives for every cohort. GitHub evicts caches by +last access when the repository limit is reached, so cache hits are not +guaranteed. Cache failure must not determine qualification success. The fixture +verifies reuse from a fresh output base, +selective invalidation and identical physical archive consumers; the actual +WASIX job must establish the retained working set and speedup. +Use Bazel's default concurrent-change guard; the selected external SDK and +toolchain inputs remain fixed throughout the isolated qualification job. +Rescanning every SDK file after every action adds substantial repeated work. +[Disk cache collection](https://bazel.build/remote/caching#garbage-collection), +[Repository downloads](https://bazel.build/run/build#repository-cache), +[GitHub cache eviction](https://docs.github.com/en/actions/reference/workflows-and-actions/dependency-caching#usage-limits-and-eviction-policy). + +Untrusted PRs must not replace trusted publication cache results. GitHub's +server-enforced PR-ref isolation provides that boundary for transported disk +caches. A future shared remote action cache/CAS needs server-side ACLs and +scoped credentials; a client flag is insufficient. Repository download caching +is separate, and frozen candidate storage must survive cache eviction. +[GitHub cache access restrictions](https://docs.github.com/en/actions/reference/workflows-and-actions/dependency-caching#restrictions-for-accessing-a-cache), +[remote caching](https://bazel.build/remote/caching). + +A cold miss requested simultaneously by independent clients may duplicate work; +remote caching is not global scheduling. Keep expensive producer-first cohort +ordering where measurement shows it useful, or use executor-supported operation +deduplication after verifying it. Dependencies remain in every consumer's graph. +Do not restore upstream suppression to optimize a cache miss. + +The current stricter same-run qualification policy remains active until its +replacement passes the cutover gates. The end state classifies evidence by its +claim, rather than by a task name or workflow phase: + +- Hermetic unit, format, ABI, package, process, lifecycle and offline installed- + consumer tests may reuse trusted passing results. Their declared inputs must + include every actually consumed input: transitive dependencies, requirements, + features, harness/fixtures, tools, relevant policy and execution environment. + Final envelopes are required when installation/delivery is the claim; pure + unit/format fixtures must not acquire unnecessary package prerequisites. + Include loaded provider libraries and the actual OS/CPU/runtime configuration + where relevant; an OS label or source SHA alone is insufficient. +- Device/host behavior with unmodelled state, live registry/auth/deployment + observations and claims about an operation in the current run require fresh + execution. Compile their runners once; execute only the required distinct + environments, modes and shards. +- Admission binds the candidate's actual bytes/configurations to the original + trusted result and retains its original execution identity/logs. A cache hit + is evidence reuse, never a new execution receipt. PR/main trust remains a + separate condition; identical source does not authorize promoting untrusted + test results. + +Use Bazel's test-result cache and BEP, with the existing publication admission +records. Do not add a second proof cache or freshness ledger. A candidate SHA, +global publication-lock digest or workflow phase must not invalidate every test +when it is only admission context, rather than a real test input. For offline +resolver tests, pin the historical package inputs and tools; acquire mutable +external state before the hermetic test or classify that test as fresh. The +[test contract](https://bazel.build/reference/test-encyclopedia) describes the +conditions under which test-result reuse is valid. + +Before allowing reuse, negative fixtures must show rejection of changed payload, +transitive dependency, harness, toolchain/environment, requirements/features, +policy and untrusted origin. Current same-run checks can be removed only when +these cases and real supported consumer execution establish equivalent claims. +Do not carry a blanket release-wide `--nocache_test_results` into the end state. + +Measure existing cold/warm builds, action counts, repeated tests, transfer bytes, +runner time and cost first. Acceptance must show: + +- warm identical requests execute no unnecessary production actions; +- one translation-unit edit rebuilds its actual compile/link/package consumers; +- legal/manifest-only changes assemble/check packages without broad C rebuilds; +- test-only edits request relevant proof without selecting package releases; +- changed pins/tools/headers cannot reuse stale dependency outputs; +- identical shared generators/compilations execute once per compatible config; +- warm identical hermetic test requests reuse trusted results; only required + current external observations execute again; +- aliases and root unions do not execute both an aggregate suite and its members; +- selected one/few/many products do not publish prerequisites automatically; +- provenance source SHA does not globally stamp/recompile unrelated payloads; +- broad-versus-focused selection differences are measured before job elision. + +Do not invent percentage savings before native representative measurements. +Keep bounded old/new comparison runs during each cutover, then remove them; +permanent dual-build CI defeats the migration's efficiency goal. + +### Minimal checks, tests, and builds + +Migrate observable guarantees, not the current task count. Retain a check only +when it proves a distinct repository/product/operational contract, or tests +first-party code that implements that contract. Give it one executable owner; +convenience suites and CI cohorts request a union of those owners. Different +platforms, features, loaders, consumer manifests and failure boundaries can be +distinct contracts even when their scripts look similar. Identical wrappers, +workflow phases and scratch directories do not create new contracts. + +Bazel owns dependency scheduling, configured output separation and cached-output +materialization. Delete tests of the retired implementations of those facilities +with their implementations. Keep small fixtures for our custom rules' actual +inputs, platform constraints and providers: Bazel does not discover omitted +inputs or establish consumer semantics. Validate a final transformed artifact +once within an immutable trusted phase; verify identity/content again when it +crosses a real download, extraction, approval or publication boundary. + +The following dispositions are grounded in the audited source baseline. None +authorizes deleting a necessary check while its current producer remains. + +| Current work and concrete evidence | End-state disposition | +| --- | --- | +| `tools/release/release-check.sh:31–53` discovers `independent-version-pins.test.sh`; `tools/release/moon.yml:162–166` also runs it separately | One native test owner for those scenarios, included by command-free suites. Remove duplicate execution without removing unchanged-SDK pin-preservation proof | +| `.github/scripts/*moon*` scheduler/capability/batch tests; `tools/ci/workflow-moon-transfers.test.mts:59–100,190–244,262–382`; `.moon/tasks/cargo.yml:14–23` | Delete recursive capability inference, producer subtraction, copied construction-tree/no-cache assertions and command-free source-hash graph. Keep immutable event/source selection, expected supported-root coverage and failed/skipped/cancelled admission cases | +| `tools/ci/workflow-moon-transfers.test.mts:104–148` requires all producers to wait for source checks/tests | Remove universal source-gate-before-production ordering. Independent checks and construction can run concurrently; final admission waits for all required results. Necessary authorization/acquisition preconditions remain | +| `tools/ci/workflow-caches.test.mts:13–131`; native/WASIX `build-orchestration-test`; `test-symbol-scope.sh:99–243`; postmaster `wasix-build-lock.test.sh:17–58` | Delete Docker/Cargo nesting, dispatch, stamps, readiness invalidation and mutable-prefix lock tests with those engines. Split mixed suites: keep actual symbol/provider/loader/ABI/AOT/sealing/unsafe deployment assertions | +| `src/native/runtime/bin/check-postgres18-ios-simulator.sh:164–211` builds ICU and selected PG objects, then checks patch text | Remove extra probe production and patch substring assertions after real configured simulator compilation and semantic mobile tests cover the contract. Do not remove actual open/reopen/persistence checks | +| Mobile `build-ci-target.sh:9,33` creates per-target host builds; `package-liboliphaunt-mobile-assets.sh:203–206` calls the XCFramework producer; ABI generation/comparison repeats at `:125–128,178–194` | Share identical configured prerequisites. Assembly consumes exact slice/resource/ABI outputs and cannot call producers. Generate/compare each ABI domain once, then assemble immutable final envelopes; remove in-place archive repair | +| Kotlin declares `mobile-bindings:generate` but `oliphaunt/build.gradle.kts:164–169,971,990` also invokes it; Swift `build-bindings-xcframework.sh:6` does the same | One declared UniFFI generation action supplies both languages and headers. Keep distinct configured Android/Apple library slices; remove downstream generation/build fallbacks | +| Native NAPI `moon.yml:182` requests both release packaging and `test-built`; `package-node-direct-runtime.sh:100` invokes the default release producer again | One cdylib/strip action per configuration, consumed by package and lifecycle tests. This is repeated current engine invocation, not proof of repeated code generation; final tests must consume the stripped delivered payload | +| Swift `stage-release-artifacts.mts:130–133` emits generator bundles; `check-package.mts:170–175` recompiles the same sources with the same helpers/flags | Generate once as declared outputs; independent final package reader compares actual packed files with those outputs and checks contents/requirements without compiling again | +| `src/wasix/sdks/ts/tools/integration/smoke-node.sh:16` and `smoke-browser.sh:40` repack query for each consumer | One declared immutable query tarball shared by Node/Bun/Deno/Electron/browser fixtures. Keep each supported resolver/export/runtime case; share installation only where requirements/environment match | +| `src/wasix/node-addon/moon.yml:75` runs `local-npm-tarball.test.mts`, also discovered by `tools/packaging/test.sh:5` | One packaging-owned test label reused by both suites; retain distinct addon platform/content tests | +| `src/query/ts/moon.yml:88–93` uses `**/*` for packaging; WASIX compiler inputs include legal/archive metadata; native/WASIX packaging units include broad tool globs | Separate compilation, envelope assembly and test inputs. Test-only edits run relevant tests; legal-only edits assemble/check affected envelopes. Neither forces unchanged PG compilation. Source membership/tool/patch/header changes still invalidate actual production | +| `tools/release/release-metadata-check.sh:8–16` runs overlapping RP/product/target checks | Share parsing and common assertions in one cheap static admission path; preserve each unique assertion and projection fixed-point check. Do not carry several overlapping traversals into native tasks or aggregate every product test under broad metadata inputs | +| `.github/workflows/release.yml:881–892` creates/validates the lock, immediately verifies it, then packs/validates it; `:1211–1217` repeats verification after verified capsule extraction | Remove adjacent redundant passes once create/pack/extract negative tests prove the same rejection guarantees. Keep actual archive parsing, capsule verification on each new host and immutable identity checks at protected boundaries | +| `tools/release/check_release_versions.mts:307–326` revisits historical dependencies per consumer | Share immutable historical facts within one preflight and check the actual required carrier/asset closure. Refresh mutable registry/auth state at the publication boundary; preserve anonymous postpublication resolver proof | +| `tools/release/publication-consumer-proof.mts:25–72` hashes a global list of unrelated platform/controller/harness files | Replace with each native test's actual transitive inputs and applicable policy. Bind candidate/approval context at admission. An unrelated product version or Android setup edit must not invalidate an identical query test; a real transitive dependency must | +| Source qualification and frozen-consumer tests have similar SQL/lifecycle scenarios | Share harness code. Share results only when final installed envelopes, resolved dependencies, features, environment and claims coincide. Today's workspace overrides, stub Cargo dependencies and rewritten WASIX requirements cannot prove frozen installation | +| Per-phase publisher workers reload immutable context | Keep inexpensive worker admission unless measurement justifies consolidation. Do not build a long-lived controller or custom cache merely to avoid cheap parsing; remote race/auth/byte checks remain per relevant operation | +| Native Rust's ordinary suite compiles runtime tests that return when runtime inputs are absent (`native_smoke.rs:64`, `native_sql_regression.rs:73`, `mobile_broker.rs:69`) | Separate pure unit and configured integration roots. Unit selection need not compile unused integration binaries; selected integration tests require actual runtime inputs and fail when absent, rather than producing a vacuous PASS | + +Several apparent duplicates are already distinct or suppressed. Release and +packaging runners skip a TypeScript test when its same-name Shell wrapper owns +it. All seven coverage tasks have `runInCI: false`; coverage is not currently +doubling ordinary CI. Native raw-tree integration is also not an always-running +CI duplicate of packed-artifact smoke. Formatter versus lint, TS type checking +versus transpilation, Rust compilation versus clippy, and unit fixtures of a +validator versus validating a candidate prove different facts. Combine compatible +invocations only when all diagnostics/configurations survive. Optional coverage +must not become an automatic second complete suite; instrumented and ordinary +builds nevertheless have different inputs and cannot be assumed equivalent. + +Docs generation/snippet checks can be shared between fast checks and full site +builds, without removing consumer snippet typing. Source SDK semantic checking +can be shared with equivalent production compilation; preserve test typing and +different public resolver/feature configurations. Cargo's packaged-test +`--no-run` check proves shipped fixture/source completeness under its requested +features; it does not execute the unit suite again. Conventional consumer +compilation remains independent of internal Bazel compilation. Broad lower- +layer semantics need not be replayed through every SDK, but each binding retains +its actual API/resource/lifecycle behavior and installed compatibility. This +audit has not established equivalence sufficient to delete those behavior cases. + +The permanent verification model has five responsibilities: + +1. **Declared contracts:** cheap deterministic checks for supported roots, + conventional requirements, rendered versions/legal contents and completed- + history/release intent. Pure unit fixtures use small explicit data. +2. **Custom rule/tool correctness:** narrow positive/negative fixtures for our + generators, package formats, resources, ABI/provider rules and ownership. + Share common tool fixtures rather than importing them into every product. +3. **Actual product behavior:** public APIs/features, SQL/lifecycle, installed + resolvers/loaders, supported runtime/platform and device behavior. Use final + envelopes where delivery is the claim; cache only eligible hermetic cases. +4. **Admission and trust boundaries:** workflow security, cache-write authority, + immutable source/configuration, expected proof completeness, safe extraction, + exact approved bytes and resumable publication. Keep actionlint/zizmor while + GHA remains. Required/Qualified are admission views, not extra test suites. +5. **Current external observations:** selected identity/auth/signing readiness, + public resolver visibility, real device/deployment state and remote race + checks. Retry a failed external operation without rebuilding or replaying + successful offline behavior tests. + +Use native validation actions for appropriate deterministic build contracts; +do not add validator outputs as artificial compiler inputs merely to serialize +checks. Explicit test/admission roots still cover tools and configurations that +automatic validations omit. +[Validation actions](https://bazel.build/extending/rules#validation-actions). +Actual archive parsing is independent of writer unit tests. Public consumer +smoke already checks anonymous Cargo/npm/Maven/Swift resolution without replaying +the frozen SQL suite; retain that separate boundary. + +For each cutover, record the old guarantee, surviving owner or native facility, +positive/negative semantic evidence, and obsolete code/tests removed in that +same change. This belongs in the slice's review, not a new permanent check +registry. Bounded legacy comparisons, cold/cache parity and repeatability +experiments qualify the port/toolchain; do not run two production engines or +recompile PG for every randomized policy fixture forever. Permanent scenarios +use small actual native actions plus independent expected consumers; rerun real +integration when relevant rules/toolchains/platform contracts change. + +Assert work as well as results. The fixture/cutover budget must demonstrate: + +- a warm unchanged request executes no production actions or eligible hermetic + test attempts; required current external observations remain; +- docs/test-only changes select zero unrelated releases and compile no unrelated + runtime; legal/envelope-only edits reassemble affected packages without C rebuilds; +- one SDK or embedded payload edit reaches its real consumers, while an unrelated + independently versioned sibling remains reusable; +- one/few/many requested roots execute each shared action/test once per identical + configured identity within an invocation, including aggregate/member requests; +- altered transitive inputs or unsupported/untrusted evidence prevent reuse; +- freeze, publication retries and docs recovery consume existing bytes/results, + performing no producer build or complete source-suite rerun. + +Count executed action/test attempts through BEP/execution evidence, with explicit +exceptions for separate configurations, instrumentation, fresh observations and +cold misses across independent clients. Do not promise global deduplication from +remote caching. Required support coverage remains complete even when matching +results are reused. A releaser should see a small selected contract set, rather +than every former task relabelled as a mandatory Bazel test. + +## Frozen release and recovery + +The delivery pipeline becomes: + +```text +completed-publication snapshot + source + -> bounded delivery/adoption intent -> Release Please candidate + -> final versioned tree -> native configured packages + qualification + -> exhaustive actual-output lock -> artifact-bound installed-consumer evidence + -> publication-ready + approval -> upload those bytes -> reconcile/promote + -> docs refresh and independent live verification +``` + +Parse actual archives after packaging. Dynamic Cargo splitting uses a declared +tree output plus inventory because size determines part count after execution. +Verify allowed parent/target, contiguous part names, exact product version, +limits/legal contents, complete aggregator dependencies and actual packed +dependency order. Do not invent a product or static label per hypothetical part. +Existing deterministic split/reassembly algorithms are valuable leaf tools. + +Freeze final npm tarballs, Cargo crates/parts, Maven envelopes, Swift source/tree +and archives, GitHub assets, checksums and descriptors. Installed tests use +normal resolvers against a controlled transport of these exact bytes plus +verified historical dependencies. They must not substitute workspace sources +or rewrite requirements. Transport routing is allowed; changing declared +identity/constraint semantics is not. Anonymous live-registry installation and +visibility are fresh postpublication operations. +[Cargo packaging](https://doc.rust-lang.org/cargo/commands/cargo-package.html). + +Preflight selected registry/auth/bootstrap/signing requirements before avoidable +mutations. Sign approved Maven contents at the protected boundary and record +the signed upload bytes. Publishing is an explicit runtime operation, possibly +launched by `bazel run`, never a cached build action. Cross-registry delivery is +resumable, not atomic: reconcile already-existing matching bytes, fail conflicting +immutable identities, publish missing dependencies before dependents, preserve +receipts and verify public visibility before promoting GitHub drafts/marking +completion. Cover Maven pagination and ambiguous upload responses. + +Recovery uses the original source, lock, approval capsule and bytes. A narrowly +allowlisted controller repair can change transport logic; native BUILD/rule, +compiler or package-writer changes cannot be disguised as controller-only +recovery. Main advancing does not authorize replacement producer outputs. +Preserve all tag/lease/exact-PR guards. Failure of docs deployment after completed +publication retries docs only. + +## Migration sequence and hard gates + +Each step ends with a deletion or authority cutover after proof. Parallel work +within a step is useful; dependents cannot cut over before their full closure. +Use scoped PRs around these gates rather than one unreviewable rewrite. + +| Step | Concrete deliverable | Acceptance and removal | +| --- | --- | --- | +| 0. Stabilize current delivery | Correct completed-history bounding, exact-runtime/default-recipe checks, frozen-consumer skip topology and publisher reconciliation/preflight; capture actual baseline inventories and performance | Independent failing scenarios now pass through the real preparation/consumer/controller entrypoints. Do not wait for Bazel to repair unrelated release bugs | +| 1. Establish the foundation | Pin Bazel/rules; acquire upstream source inventories; register native and cross-compilation toolchains; define small shipping/domain exports, manifest imports and the historical bridge | Clean Linux construction plus native macOS/Windows SDK probes pass. Cross-built packages run on their real hosts. No cutover with unavailable execution capability or unknown historical ownership | +| 2. Prove hard construction slices | Native PG configured headers/generators and ordinary/embedded/frontends; one representative compiled extension, SQL-only pgTAP, portable WASIX plus host AOT; query/package tools as fast test infrastructure | Clean sandboxed production works with no existing target tree or foreign producer. ABI/provider/SQL/package tests and declared-action inspection match the supported contract. Compare legacy behavior, diagnose differences, then delete slice-specific producer/cache/handoff bodies | +| 3. Complete runtime/dependency families | All native platforms, ICU/crypto/PostGIS and its generators, contrib/external targets, seeds/mobile ABI, complete WASIX/tools/AOT/postmaster/browser production | Full declared support and actual content/ABI/feature/lifecycle coverage; stale dependency and interface-change cases pass. Prove repeatable compilation/encoding and explicit seed initialization, compatibility, freeze and recovery contracts. Remove all broad C/WASIX producer engines | +| 4. Complete SDK/application/dev surfaces | Rust/TS/NAPI/UniFFI/Swift/Kotlin/RN native targets and exact envelopes; all examples, docs, benchmark checks, security/hooks/developer commands; JS resolution cutover | Real installed Cargo/npm/SwiftPM/Gradle/RN consumers, browser and app proofs pass. Preserve public integration manifests; remove internal Cargo/Gradle/SwiftPM/Bun task dispatch and duplicate lock/bootstrap authority | +| 5. Switch CI and release | Platform cohort workflow, BEP/expected-coverage gate, native delivery selection plus historical bridge, bounded RP/adoption adapter, freeze integration and capsule compatibility | Zero/few/many/all-product simulation, exact merged qualification, skipped ancestor, recovery and fake registries pass. Evidence-reuse negative cases and the warm-run work budget pass; required fresh observations remain. One real credential-free hosted topology probe passes. Remove reusable construction workflows and every Moon closure/capability/transfer bypass | +| 6. Complete the authority cutover | All inventory rows have native owners; current docs/skills/local commands route to them; retire legacy baselines product by product and capsule readers by recovery policy | No ordinary path requires Moon/Proto, a mutable producer tree, foreign producer engine, handwritten shared-source graph or hidden latest fetch. Delete `.moon/`, obsolete project task files/pins/actions and implementation-shape tests. Record remaining external facilities explicitly | + +Do not force a mass release just to install BUILD files. Where the port changes +compiler/dependency/payload/support behavior, release the resulting delivery +change with its reason. Where audited parity establishes a construction-only +migration, record that evidence in the baseline bridge. A product still lacking +an honest old baseline cannot be claimed precisely unchanged. + +## Verification scenarios and independent oracles + +The test harness must exercise real Bazel analysis/actions, the real Release +Please adapter/projections, package writers/parsers and the publication controller. +It must not ask a planner to produce both the result and expected answer. + +| Scenario family | Required independently asserted result | +| --- | --- | +| Zero/one/few/many/all changes | Exact selected products, versions, requirements, build roots, final artifacts and required proofs; examples/docs/tests alone select zero package releases unless their contents ship | +| Shared source and different baselines | An older change already delivered by one product but not another selects only remaining delivery owners; out-of-directory release commits and component renames retain boundaries | +| Deletion/rename/removed edge | Union of old/new native facts preserves impact; missing historical facts or exhausted pagination blocks precise preparation | +| Broker/query/source versus binary | main-only change excludes library-only mobile; shared library change reaches actual embedded SDKs; source SDK historical pins remain unless mandatory adoption applies | +| Package-only and legal input | Correct owned envelope changes without unnecessary runtime compilation; Markdown file extension never silently exempts shipped notices | +| Source/tool/platform configuration | New nested header/table/assembly, host SQLite, Perl/Bison/Flex, NDK/API/CRT/CPU/LLVM changes invalidate the right actions; an unused toolchain does not select unrelated products | +| WASIX interface and sealing | Stable imports avoid main relink/mandatory runtime delivery under the admitted interface policy; changed imports select main work; wrong Wasmer family or pre-seal AOT is rejected | +| Installed compatibility | Actual packed requirements plus loaded runtime/extension/profile/target agree; historical pin unavailable, wrong host, unsupported feature, missing resource or wrong default recipe fails | +| Generated parts and envelopes | Size thresholds, several targets, missing/extra/noncontiguous/wrong-version parts, aggregator pins, exports, Swift URLs/checksums, plugin marker and optional npm dependency cases are detected | +| Cached versus clean construction | For representative edits/configs, a clean execution and incremental execution have equivalent final contents/contracts; no presence stamp or prepopulated target tree hides an omission | +| Linux construction and cross-host transport | Cold local construction works without remote execution/cache. Native consumers receive the same frozen files and construction evidence; changed source/lock/target/hash/member mode or missing bytes fails. Consumer requests cannot reconstruct producers or relabel a Linux-built package as native-host output | +| Qualification coverage and evidence reuse | Identical complete inputs reuse the original trusted result. Changed/missing transitive input, wrong environment, stale policy, untrusted result, missing config/shard/manual target, debug run, wrong app digest, failed/skipped proof and main/source mismatch block admission; required current external observations cannot use cached PASS | +| Publication and recovery | Fail after each registry boundary, replay matching identity, conflicting byte, later-page Maven deployment, auth failure, ambiguous response, delayed visibility, main movement and controller-only repair reconcile correctly without rebuilding | +| Completed publication/docs | Partial publication never becomes the next baseline; a docs failure retries only deployment; no recommended-version edits or product bumps | + +Use a tiny fixture repository with an independently authored physical-consumer +truth table and immutable prior publication records. Seed random edits across +zero/few/many inputs, graph/config changes, old/new pins and failure points. +Exhaustively enumerate admissible small product subsets to verify required +compatibility closure, run actual entrypoints, and retain the random seed and +minimal failing fixture. Most scenarios need small native actions and fake +registries, not repeated full PG matrices. + +Use a bounded real clean-platform suite for compiler/rule integration, binary +contracts and installed lifecycle; use broad candidate-specific supported +platform coverage for releases. Tests of the former planner's string shape +cannot replace either. No tool can prove arbitrary semantic defects impossible; +this design makes omitted inputs, incomplete history, unsupported configurations, +metadata drift, package substitution and transaction failures explicit and +testable before avoidable publication. + +## Audit validation and remaining work + +The audit loaded the actual product/catalog parsers and pinned Moon project/task +snapshots, checked the main/workspace tree equivalence, and independently +validated inventory coverage. The current publication-catalog suite passed +five tests and 583 assertions. Document coverage and links are checked separately. + +The initial strategy audit preceded implementation. The current local migration +has executable foundation/import targets, native Rust/TypeScript query packages +and installed consumers, direct Linux PostgreSQL/ICU and 39 extension members, +native Rust SDK/mobile/Node targets, the TypeScript SDK source envelope, a +physically verified portable WASIX runtime, the browser's exact nightly Rust +standard library built from source, and both complete Android runtime ABI +outputs. Kotlin's native common-source compilation and tests also pass. Actual Linux runtime +tests cover the embedded C ABI, persisted SQL, ordinary server frontends, +dump/restore and physical-backup reopen. Warm runs reuse completed actions. +The real installed browser SDK/query/runtime archives execute SQL through both +default and worker exports in Chrome. The native browser host and portable +runtime are constructed on Linux; Chrome's observed executable and host identity +are explicit consumer inputs. +All sixteen WASIX AOT images, covering four modules on all four canonical host +triples, are constructed through the declared Linux LLVM execution profile. +The five final portable/AOT Cargo envelopes are built from those declared +payloads. Seven source-SDK AOT tests cover SQL, savepoints, error handling, +isolation, reopen and abrupt durability. Foreign-host deserialization and +installed Cargo execution remain separate qualifications. +Finished Linux runtime/tools GitHub, npm and Cargo carriers pass relocation, +offline Cargo reconstruction, persistence, dump/restore and backup/reopen. The +tools npm consumer executes the declared Node toolchain. Resource construction +and physical seed consumers pass for Linux x64; Android domain admission uses +both actual configured runtime ABI receipts and preserves the frozen seed bytes. +The WASIX standard/ICU seeds also pass actual PostgreSQL reopen and persistence, +packed-byte verification, resource-parser consumption and six Rust verifier +tests. These slices cover 17 of 33 registry carriers and 13 of 31 GitHub +identities. Android device execution and the remaining resource identities are +separate gates. Warm requests reuse the frozen seed bytes; bootstrapping a new +seed is not a repeatable byte-generation claim. +Physical conformance fixtures cover seeded edit subsets, independent release +baselines, malformed ownership and cached reuse. These construction results do +not admit all products or replace real installed compatibility qualification. + +The installed native Rust source packages resolve through Cargo against the +actual published runtime and broker versions. WASIX's optional tools and ICU +requirements are now explicit held Cargo metadata, verified against its +published crate. Current source construction does not replace those installed +contracts. The macOS and Windows native runtime and Swift package targets are +authored; their real host qualification remains a separate gate. Draft PR #295 +has passed hosted native runtime, frontend, crypto and extension qualification +on Linux x64 and ARM, plus Android cross-compilation and ABI checks on Linux +x64. Local regression tests cover the initial macOS SDK symlink cycles, +Windows script-launch failure and incremental metadata-directory deletion. +The corresponding hosted platform results remain required at the revised SHA. +Native-host construction probes establish their compiler/rule integration; +they cannot certify a different package constructed on Linux. The final-file +transport and target-host/device consumption gates must bind their results to +the original frozen bytes before the cross-target paths can cut over. + +The next checkpoint adds both Android extension ABIs and the three Apple +extension profiles to the existing construction graph. Both Android ABIs pass +the eight-distribution final-carrier checks and link all compiled members +against their public C API. Maven payloads match their canonical GitHub archive +bytes. Actual Android device execution and Apple construction/installed +execution are separate pending qualifications. The full Apple XCFramework +carrier uses the canonical owner inventory; authored targets alone do not +establish successful construction. + +The WASIX Node-API release feature resolves its held public SDK, runtime and +contrib requirements through conventional Cargo metadata. Its real Linux +package passes direct, actor and TCP SQL, contrib lifecycle, persistence and +backup/restore checks. The other three hosts remain required. Shipping exports +now declare their qualification tests as Bazel dependencies; the coordinator +requires PASS for those exact configured tests in the captured invocation. +The installed browser lifecycle is a Bazel test in that invocation. Its local, +external tags require a fresh observed Chrome execution while allowing package +construction actions to reuse their cache. + +Source qualification now declares repository-owned Biome/rustfmt inputs, +conventional TypeScript configurations, Rust compile roots and meaningful +doctests. These source checks exclude generated carrier outputs and retain +the conventional dependency features. Full Rust aggregate qualification is +required; a discovered published adapter sandbox-path defect is not grounds +for excluding an owner. Kotlin, documentation/application checks and complete +native affectedness planning still require integration before Moon can retire. + +Completed-history preparation uses exact captured Git ancestry and verified +publication boundaries, with merge/clock-skew regressions. The baseline bridge +also handles the genuine historical contrib declarations and Swift source tag, +authenticating their completed publication and suppliers before comparison. +It does not invent a historical Bazel graph or a source archive that was never +published. A changed VCS stamp or freshly bootstrapped PGDATA archive can change +bytes without justifying a release; causal source equality and reuse of +authenticated frozen deliveries still need live release-controller integration. + +Native release preparation now selects necessary deliveries and supplies their +owners to Release Please for version calculation. Legacy CI remains until the +complete native hosted/platform/device run, 27-product audit and genuine seed +adoption anchor pass. Results from an earlier commit do not qualify the next +source revision. No registry mutation, public version bump or legacy CI +retirement has been performed. diff --git a/src/docs/bazel.bzl b/src/docs/bazel.bzl new file mode 100644 index 000000000..51761a1ca --- /dev/null +++ b/src/docs/bazel.bzl @@ -0,0 +1,160 @@ +"""Declared docs content, one Next compiler action, and checks of its static export.""" + +load("@aspect_rules_js//js:defs.bzl", "js_run_binary") +load("@bazel_lib//lib:directory_path.bzl", "DirectoryPathInfo") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") + +_NODE_TOOLCHAIN = "@rules_nodejs//nodejs:toolchain_type" +_LINUX = ["@platforms//os:linux", "@platforms//cpu:x86_64"] +_HELPERS = [ + Label("//src/docs:tools/generate-content.mts"), + Label("//src/docs:tools/published-products.mts"), + Label("//src/docs:tools/check-docs-product.mts"), + Label("//tools/release:platform-compatibility-policy.mts"), +] + +DocsContentInfo = provider(fields = ["site_docs", "static", "routes", "metadata"]) +DocsSiteInfo = provider(fields = ["site", "routes"]) + +def _sources(ctx): + rows = [] + files = [] + names = {} + for target, destination in ctx.attr.sources.items(): + for file in target[DefaultInfo].files.to_list(): + name = destination + if destination.endswith("/"): + prefix = target.label.package + "/" + if not file.short_path.startswith(prefix): + fail("Docs source must retain its declared package path: " + file.short_path) + name += file.short_path[len(prefix):] + if name in names: + fail("Duplicate declared docs source: " + name) + names[name] = True + rows.append({"path": name, "source": file.path}) + files.append(file) + return rows, files + +def _action(ctx, operation, specification, inputs, outputs, mnemonic): + file = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(file, json.encode(specification)) + bun_file_action( + ctx, + entry_point = ctx.file._runner, + arguments = [operation, file.path], + inputs = depset(inputs + [file, ctx.file._runner] + ctx.files._helpers), + source_files = [ctx.file._runner] + ctx.files._helpers, + outputs = outputs, + execution_requirements = {"block-network": "1"}, + mnemonic = mnemonic, + ) + +def _content_impl(ctx): + sources, files = _sources(ctx) + for file, destination in [(ctx.file.release_config, "release-please-config.json"), (ctx.file.source_versions, ".release-please-manifest.json"), (ctx.file.extension_catalog, "src/extensions/generated/extensions.catalog.json")]: + sources.append({"path": destination, "source": file.path}) + files.append(file) + content = ctx.actions.declare_directory(ctx.label.name + "/site-docs") + static = ctx.actions.declare_directory(ctx.label.name + "/static") + metadata = ctx.actions.declare_directory(ctx.label.name + "/metadata") + routes = ctx.actions.declare_file(ctx.label.name + "/routes.json") + _action(ctx, "content", { + "sources": sources, + "releasesFile": ctx.file.completed_releases.path, + "provenanceFile": ctx.file.provenance.path, + "outputs": {"siteDocs": content.path, "static": static.path, "metadata": metadata.path, "routes": routes.path}, + }, files + [ctx.file.completed_releases, ctx.file.provenance], [content, static, metadata, routes], "DocsContent") + return [DefaultInfo(files = depset([content, static, metadata, routes])), DocsContentInfo(site_docs = content, static = static, metadata = metadata, routes = routes), OutputGroupInfo(site_docs = depset([content]), static = depset([static]), routes = depset([routes]))] + +_RUNNER_ATTRS = { + "_runner": attr.label(default = Label("//src/docs:tools/native-docs.mts"), allow_single_file = True), + "_helpers": attr.label_list(default = _HELPERS, allow_files = True), +} +_SOURCE_ATTRS = {"sources": attr.label_keyed_string_dict(allow_files = True, mandatory = True)} +docs_content = rule( + implementation = _content_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(_RUNNER_ATTRS, **dict(_SOURCE_ATTRS, **{ + "completed_releases": attr.label(mandatory = True, allow_single_file = [".json"]), + "provenance": attr.label(mandatory = True, allow_single_file = [".json"]), + "release_config": attr.label(default = Label("//:release-please-config.json"), allow_single_file = True), + "source_versions": attr.label(default = Label("//:.release-please-manifest.json"), allow_single_file = True), + "extension_catalog": attr.label(default = Label("//:src/extensions/generated/extensions.catalog.json"), allow_single_file = True), + })), +) + +def _build_id_impl(ctx): + sources, files = _sources(ctx) + content = ctx.attr.content[DocsContentInfo] + node = ctx.toolchains[_NODE_TOOLCHAIN].nodeinfo.node + output = ctx.actions.declare_file(ctx.label.name + ".sha256.txt") + _action(ctx, "build-id", { + "sources": sources, + "siteDocs": content.site_docs.path, + "packages": {identity: json.decode(row) for identity, row in ctx.attr.package_identities.items()}, + "tools": [{"path": "node", "source": node.path}], + "basePath": ctx.attr.base_path, + "siteUrl": ctx.attr.site_url, + "output": output.path, + }, files + [content.site_docs, node], [output], "DocsBuildIdentity") + return [DefaultInfo(files = depset([output]))] + +_docs_build_id = rule( + implementation = _build_id_impl, + toolchains = BUN_SOURCE_TOOLCHAINS + [_NODE_TOOLCHAIN], + attrs = dict(_RUNNER_ATTRS, **dict(_SOURCE_ATTRS, **{ + "content": attr.label(mandatory = True, providers = [DocsContentInfo]), + "package_identities": attr.string_dict(mandatory = True), + "base_path": attr.string(), + "site_url": attr.string(default = "https://oliphaunt.dev"), + })), +) + +def docs_next_export(name, content, next_binary, sources, package_identities, deps, base_path = "", site_url = "https://oliphaunt.dev", **kwargs): + native.filegroup(name = name + "_content", srcs = [content], output_group = "site_docs") + _docs_build_id(name = name + "_build_id", content = content, sources = sources, package_identities = package_identities, base_path = base_path, site_url = site_url, target_compatible_with = _LINUX, exec_compatible_with = _LINUX) + js_run_binary( + name = name, + tool = next_binary, + args = ["build", "--webpack"], + srcs = sources.keys() + deps + [":" + name + "_content", ":" + name + "_build_id"], + out_dirs = ["out"], + chdir = native.package_name(), + env = { + "NEXT_TELEMETRY_DISABLED": "1", + "NEXT_DISABLE_SWC_WASM": "1", + "OLIPHAUNT_DOCS_BUILD_CPUS": "1", + "OLIPHAUNT_DOCS_CONTENT_ROOT": "../../$(rootpath :" + name + "_content)", + "OLIPHAUNT_DOCS_BUILD_ID_FILE": "../../$(rootpath :" + name + "_build_id)", + "OLIPHAUNT_DOCS_BASE_PATH": base_path, + "NEXT_PUBLIC_OLIPHAUNT_DOCS_URL": site_url, + }, + execution_requirements = {"block-network": "1"}, + target_compatible_with = _LINUX, + exec_compatible_with = _LINUX, + mnemonic = "NextDocsExport", + **kwargs + ) + +def _export_impl(ctx): + content = ctx.attr.content[DocsContentInfo] + output = ctx.actions.declare_directory(ctx.label.name + "/out") + licenses = [] + files = [ctx.file.site, content.static] + for target, destination in ctx.attr.font_licenses.items(): + file = target[DirectoryPathInfo] + licenses.append({"source": file.directory.path + "/" + file.path, "path": destination}) + files.append(file.directory) + _action(ctx, "export", {"site": ctx.file.site.path, "static": content.static.path, "licenses": licenses, "output": output.path}, files, [output], "DocsProvenanceExport") + return [DefaultInfo(files = depset([output])), DocsSiteInfo(site = output, routes = content.routes)] + +docs_static_export = rule( + implementation = _export_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(_RUNNER_ATTRS, **{ + "content": attr.label(mandatory = True, providers = [DocsContentInfo]), + "site": attr.label(mandatory = True, allow_single_file = True), + "font_licenses": attr.label_keyed_string_dict(providers = [DirectoryPathInfo]), + }), +) + diff --git a/src/docs/maintainers/README.md b/src/docs/maintainers/README.md index 31c817d1d..860e6da6d 100644 --- a/src/docs/maintainers/README.md +++ b/src/docs/maintainers/README.md @@ -15,6 +15,7 @@ Executable configuration is authoritative. Documentation explains intent and ope | Extension support and packaging | `extension-packaging-policy.md` | extension catalog, global target profiles, native-component contract, release catalog | | SDK contracts | `sdk-products-policy.md`, `sdk-parity-policy.md`, `sdk-api-surface.md` | SDK manifests, package manifests, generated extension metadata, clean-consumer tests | | Product, task, qualification, and release boundaries | `../architecture/final-product-source-architecture.md` | Moon graph, release metadata, and workflows | +| Proposed native Bazel migration and audited coverage | [Migration strategy](../architecture/bazel-migration-strategy.md), [coverage inventory](../architecture/bazel-migration-inventory.md) | Proposed replacement and acceptance gates; current architecture above remains active | | Repository layout | `repo-structure.md` | Moon projects and ecosystem manifests | The repository-local skills under `.codex/skills/` are the procedural entry diff --git a/src/docs/maintainers/release.md b/src/docs/maintainers/release.md index d88c4bcd3..6e9571346 100644 --- a/src/docs/maintainers/release.md +++ b/src/docs/maintainers/release.md @@ -4,40 +4,38 @@ Windows publishers must also follow the [Visual C++ runtime release contract](./windows-vc-runtime.md); it defines redistributable provenance, extension-provider ownership, app-local placement, and receipt evidence. -Status: normative operation guide. Last verified: 2026-07-30. Owner: repository maintainers. +Status: operation guide reviewed against native release entrypoints on 2026-10-13. Complete hosted qualification, the seed adoption anchor and legacy CI retirement remain pending. Owner: repository maintainers. Oliphaunt releases independent products from one monorepo. There is no repository-wide product version. -CI can qualify selected products using the `release_products_json` dispatch -input, for example `["oliphaunt-js"]`. Leave all platform selectors at `all`. -Moon selects those owners' tasks, downstream compatibility checks and required -producer dependencies. An empty product array retains the exhaustive audit. -Publication accepts this record only for covered products at the exact candidate -SHA; it still verifies the immutable artifacts and required native/WASIX evidence. -Generated release PRs and their main merge automatically select the products -whose Release Please manifest versions advance. Exact main pushes and eligible -main dispatches can produce publishable qualification; PR checks use the same -scope but cannot authorize publication. Publication reuses covering successful -CI, waits for active matching CI, or requests one missing run while main still -equals the candidate SHA. Failed causal runs require recovery; ambiguous -dispatches are not automatically repeated. Pre-publication recovery may reuse -an explicitly selected exact-source qualification after permitted release-control -fixes. It never substitutes another source's artifacts or changes their identity. - -`Qualified` binds every planned native extension lifecycle aggregate and WASIX -regression proof to the candidate's source SHA/tree and CI repository/run. A -successful earlier attempt of that same run can supply proof when only failed -jobs are rerun; a different run or newer attempt cannot. Both aggregate proof -artifacts retain 90 days. The native artifact includes its complete shard -receipts, so it does not depend on the shorter-lived diagnostic shard uploads. - -Publishing native extension carriers, including runtime-owned contrib, requires -the native proof. Release revalidates the aggregate and every shard, checks the -published SQL extension set, and compares the evidence digest with the candidate -record. SDK-only publications continue to qualify their consumers against their -declared payload versions. WASIX publications retain the existing product-derived -regression requirement. Missing, changed, wrong-run or incomplete required proof -blocks publication; an overall successful CI result does not replace it. +The release entrypoints require `Native Bazel qualification / Required` for the +exact source SHA/tree. The workflow in `.github/workflows/bazel.yml` constructs +source-owned Bazel shipping exports and runs their mandatory configured tests. +Bazel's dependency graph and action cache determine execution; release preparation +compares delivered bytes with each product's authenticated completed publication +before selecting necessary owners. An ordinary build or test dependency is not +an automatic release bump. + +Ordinary source CI imports one immutable public-input pool. A generated release +PR imports the authenticated inputs retained by its canonical `Release / Prepare +release PR` producer. Required checks every predecessor and audits construction +across all 27 products. That audit is construction evidence, not publication +admission. PR and merge-queue runs cannot supply reviewed-main assurance. + +Native release preparation and freezing are implemented, but the migration is +not yet fully qualified: complete hosted platform/device results, the genuine +14-seed adoption contract and retirement of legacy CI are still outstanding. +Legacy CI remains for parity; its `Qualified` result is not the native release +selector or publication gate. A successful individual native job or local test +does not close these gaps. + +Publication requires an exact successful eligible-main Native run, authenticated +final selected outputs, complete supplier and owner qualification coverage, and +the prepared-source bridge. Final installed consumers and `Publication ready` +remain separate prerequisites. Missing, failed, wrong-source or incomplete +proof blocks publication. Pre-publication recovery may retain a prior exact +source after allowlisted control fixes; it preserves original source/run/file +identity and never rebuilds binary producers. ## Model @@ -48,7 +46,7 @@ release use their product's version. The canonical model is composed from: -- Moon project/release metadata for source ownership and qualification impact; +- source-owned Bazel rules, configured shipping exports and captured production inputs for construction and qualification; - `release-please-config.json` and `.release-please-manifest.json` for product versions, changelogs, components, and tag naming; - the protected release workflow for exact-SHA tag and draft-release creation; @@ -116,12 +114,6 @@ and participates in the same carrier checks as other public products. their own WASIX install metadata and payloads. - `feat`, `fix`, `perf`, `refactor`, and `revert` are release-impacting types because the Release Please `changelog-sections` catalog says so. A Conventional Commit `!` is breaking. Release-intent checks derive this set from config. - Product source PRs never edit product versions or generated changelogs. Source PRs may author dependency requirements in conventional manifests. Release Please owns product versions and its ecosystem dependency updates; sync projects actual compiled inputs and manifest requirements into package metadata and lockfiles. -- While every product is still `0.0.0`, top-level `bootstrap-sha` is the full - legacy-history boundary `07a9054faa03d5737dc0193f7a77ed4a71920c05`. - Release Please considers only commits after that exclusive boundary. Derived - release-PR sync removes the key in the first generated release-bump change; - do not remove it before Release Please has consumed it or retain it after the - first bump. `bash tools/release/sync-release-pr.sh` closes the generated candidate metadata: compatibility values for selected @@ -130,38 +122,35 @@ consumer release merely because one of its dependencies changed. Its `--check` mode proves that the same state is already closed. Pure version/changelog changes alter package envelopes but do not alter committed runtime binaries. -PR CI runs `sync-release-pr.sh --check-generated-release` only for the -same-repository `release-please--branches--main` head, before artifact planning. -That cheap barrier checks the dependency/compatibility/lock fixed point and the -exact structured release commit without compiling the asset -verifier. The prepare workflow generates and validates the candidate locally -before its first push. This admission check verifies the already-closed pushed -head before expensive matrices begin. - -Release Please selects changes under each configured product path. Shared code -that changes published bytes must therefore live in, or be represented by, the -product that owns those bytes. Pure workflow, validation, registry transport, -test, and documentation changes do not bump products. If another unreleased -product change is already present, Release Please may still prepare that -product's release. A manually constructed `chore(release):` commit without an -actual manifest/version/changelog transition is rejected by the structured -release-commit verifier. +The prepare workflow generates and validates the candidate locally before its +first push. It retains `native-release-inputs` before publishing the completed +PR tree. Native CI resolves the canonical Prepare run and verifies the exact +version-only source transition before expensive construction. A normalized +release PR has one source parent and the expected manifest/version/changelog +transition; an arbitrary `chore(release):` title is insufficient. + +Native preparation supplies necessary owners from physical delivery comparison. +Pinned Release Please remains responsible for version and changelog calculation, +using commit intent bounded to those owners' captured source and loaded recipes. +Workflow, validation, transport, test and documentation changes do not themselves +require a product release. An unknown completed baseline or incomplete physical +coverage blocks the decision rather than falling back to path ownership. ### Independent candidates and pinned dependencies -Release Please remains the sole authority for product candidates and version -policy: it selects product paths changed since their last releases. Shared -contrib inputs may select both runtime owners because those source files are -physically bundled into both products. No Moon dependency edge creates another -release candidate. +Native delivery comparison selects necessary product owners; Release Please +owns their versions and changelogs. Shared contrib bytes can select both runtime +owners because each delivers those bytes. Dependency declarations and ordinary +Bazel build/test edges do not create another release candidate. A dependency requirement is a consumer declaration. Releasing a producer does not rewrite unselected consumers. Source-only SDKs preserve their authored requirements except for Release Please ecosystem updates and the default extension install closure described below. -A compiled payload names the source versions it actually incorporates. Shared -carrier writers are explicit `shared_source_paths` of every product whose bytes -they render. Carrier versions continue to equal their owning product version. +A compiled payload names the source versions it actually incorporates. The +shipping owner's typed supplier Files and their original configured producer +closures establish that incorporation. ABI-only relationships do not silently +retarget held consumers. Carrier versions equal their owning product version. Every compatibility reference declares `public_support`. Set it to `true` for an exact host supplied independently by the caller, such as an external extension's @@ -189,107 +178,89 @@ create the extensions and execute extension SQL through the existing host cases. Recipes also depend on extension members, provider ABI and target profile; runtime version equality alone is insufficient. -Binary products declare `embedded_cargo_manifests` in their `release.toml`. -Release planning reads Cargo's versioned `metadata --no-deps --frozen` output -and follows local runtime, build, and target dependencies through independent -product boundaries. Cargo resolves workspace inheritance, renamed dependencies, -and custom library, binary, and build-script source paths. All optional and -target dependencies participate, so adding a platform does not require another -release-planner branch. Development dependencies stay local. This read requires -the pinned Cargo toolchain but never compiles, fetches registries, or changes a -lockfile; source planning and release preparation declare that capability. -The workspace Cargo manifest and lockfile conservatively select these binaries, -since dependency resolution and build settings also determine their shipped bytes. -This covers both Node addons, the native broker, and Swift/Kotlin native -bindings. Generated assets use `embedded_payload_products`: changes to an -embedded producer's sources, pins, or recipes also select the embedding binary. -Source-only facades and dynamically loaded runtimes retain independent releases. - -For a new compiled SDK, declare its shipped Cargo root once. Dependencies then -follow the Cargo manifests, including new targets. Declare generated payload -producers separately because Cargo cannot infer external artifact generation. -Non-Cargo shared inputs belong in `shared_source_paths`. New source-only SDKs -need compatibility pins and package qualification without a compiled-source -root. The shared version-drift gate discovers producer products from every SDK's -compatibility declarations, so a new dependency enters the fixture automatically. -Every SDK must test its packager with an independently advanced producer; release -packaging preserves the consumer's exact pin, while a source fixture that uses -newer workspace bytes must identify those bytes and remain unpublishable. -Moon's shared Cargo source group includes Rust files throughout each project, -including custom source directories and build helpers. Inputs outside the Cargo -project, such as resources read by a build script, still need explicit Moon -inputs and release ownership. - -Moon `production` and `peer` edges describe source and qualification impact. -Product-local `compatibility_versions` describe the exact published product -versions a carrier consumes. A native runtime can therefore be published -without bumping an SDK, and the unchanged SDK continues to pin the older native -version. A selected compiled consumer records the versions of the inputs it -actually embeds. Other requirements retain their authored values except for -Release Please ecosystem updates or required default extension install updates. -If a required dependency is also -selected at a satisfying version, publication orders it first. - -Before publishing a selected consumer, version checks require each pinned +Bazel owns compiler inputs, generated payload dependencies and execution +configuration. Native evidence retains the full reached action DAG and hashes +its required physical boundary: source/tool/repository leaves, consumed typed +supplier Files, reached seed receipt/frozen pairs and final outputs. A valid +cached action need not leave arbitrary intermediate objects on disk. Missing or +unreadable required inputs still fail; incomplete supplier origin coverage stays +unknown. Cargo metadata ownership and a second declaration graph are not release +selection fallbacks. + +For a new shipped owner, declare its actual output roots, consumed supplier Files +and mandatory configured tests in the source-owned shipping export. Source-only +facades preserve conventional requirements and qualify their packages without +inventing compiled incorporation. Package tests must exercise independently +advanced producers: held requirements use authentic completed archives even when +the workspace has the same version, while current construction identifies its +actual Files. A version match alone proves no physical origin. + +Product-local `compatibility_versions` describe the requirements a carrier +consumes. A native runtime may release without bumping an SDK, whose older pin +remains intact. A selected compiled consumer records its actual incorporated +inputs. Other requirements retain authored values except for Release Please +ecosystem updates or necessary default-install adoption. Publication orders a +selected satisfying dependency before its consumer. + +Cargo library declarations keep [Cargo's normal version requirement semantics](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#version-requirement-syntax): +`0.3.1` is a compatible minimum; `=0.3.1` is exact. Completed source-baseline +acquisition currently uses a stable literal minimum or exact `=` value as a +locator for one immutable completed source carrier. That lookup does not resolve +arbitrary registry ranges. Local `path` declarations remain normal Cargo +requirements checked against the local package. A library requirement and its +separately authored installed-helper locator can differ; source packages retain +the library requirement, while helper payload acquisition uses its own locator. + +Before publishing a selected consumer, version checks require each exact artifact dependency to be either selected at that exact version or already available at its exact product tag and registry/GitHub carriers. Selecting a newer dependency does not satisfy an older consumer pin. Structured release-commit verification also rejects source changes hidden inside compatibility-only edits. -Source qualification uses current workspace producers and identifies the -runtime actually compiled. If those producers differ from immutable release -pins, npm fixtures carry `qualificationOnly` and publication rejects them. -Release package tests retain their declared pins: Cargo uses a local source -patch only at the matching exact version and otherwise resolves the published -dependency. A WASIX TypeScript release must pair the portable runtime with an -addon embedding the same runtime version. -WASIX source builds resolve local extension archive versions from each staged -extension product manifest. External extension versions are independent of the -runtime; contrib manifests carry their owning runtime's version. Cargo tracks -those manifests so a changed extension identity refreshes its embedded bytes. -Swift and React Native carrier staging also retains the exact native pin. -React Native resolves that pin through its declared Swift release, including -immutable historical metadata when Swift has advanced. Older runtime pins use -verified published Apple archives; current pins require same-run producer assets. -Mobile app qualification stages private extension and Swift carrier fixtures -under `target/qualification` against the current workspace runtimes. It leaves -the release packages intact, retains payload hashes and exact runtime validation, -and marks extension fixtures `qualificationOnly` so publication rejects them. - -PR CI recognizes generated `chore(release):` changes only on the generated -Release Please branch. Before merge it requires the release commit's parent to -equal the exact base SHA, derives the product set from the manifest diff, and -runs the same structured release-commit verifier used by publish. A multi-commit -or source-bearing release PR therefore fails before it can reach `main`. -Release Please may transport a large generated change as multiple file-chunk -commits. The protected prepare job accepts those chunks only from the exact -open canonical Release Please PR, requires a linear exact-main descendant with -the configured release title on every chunk, collapses their tree to one commit, -reapplies derived release synchronization, runs the structured verifier, and -pushes with a lease against the inspected PR head. The normalized tree must be -byte-identical before derived synchronization; a moved PR head is never replaced. -Before the prepare job spends time on toolchains or release metadata, the -read-only validation job directly inventories the exact -`release-please--branches--main` head against `main` through the Pulls REST API -and rejects any merged result that still carries `autorelease: pending`. It -does not use GitHub Search or the Issues API's eventually consistent label - index. A pending merged PR means publication is unfinished; it is never - reported as “no releasable changes.â€� - -Publication derives its product scope from the latest verified Release Please -release commit before checking product tags. Later changes to products outside -that candidate do not block the pending release or add products to it. Selected -products still require valid version transitions and exact dependency pins; -unscoped tag planning continues to reject unversioned release-affecting changes. +Workspace source checks and final installed admission are separate. Source +checks may compile against current workspace producers, while the prospective +public carrier preserves its authored held header, archive and requirement. +For Swift, the preparation export uses the same constructed roots with workspace +source/API/iOS checks; the final export additionally requires the exact installed +consumer. A Native-only change must not restamp unchanged held Swift bytes. +Changed Swift source can select Swift, but a new API requiring a newer native +base still needs explicit conventional adoption and final qualification. + +WASIX source builds resolve extension archive versions from each staged product +manifest. External extensions retain independent versions; contrib follows its +actual runtime owner. Installed WASIX consumers require the exact declared +module/version contract. Resource creator provenance remains distinct from the +admitted consumer, and a runtime release does not automatically release held +compatible resource data. + +Swift and React Native final staging retain their conventional requirements. +Held Swift source tags, bindings and Apple runtime archives come from the existing +authenticated completed readers. Explicitly adopted unpublished inputs require +actual matching candidate producer Files and their source-bound transport. +The Mac producer captures native/Swift inputs before the downstream React Native +consumer uses them; source checks cannot substitute for final installed proof. +Private workspace fixtures remain unpublishable. + +Generated release trees resolve through `native-release-inputs.mts`, which checks +the canonical PR/Prepare identity, immutable source and exact version-only bridge. +Queue trees additionally need the matching original PR tree; a mixed queue or +synthetic title cannot bypass those checks. Publication plans use the same +verified Prepare record and its exact selected scope. + +Publication derives its exact scope from the authenticated Prepare record for +the selected Release Please commit before checking product tags. Later changes +outside that candidate do not add products. Selected owners still require valid +version transitions, complete final carrier coverage and exact dependency pins. ## Qualification contract Root publication admission accepts a current-main candidate or an explicit ancestor source under an allowlisted current-main recovery controller. Source -qualification requires one successful, non-cancelled CI run whose `head_sha` -is exact and whose `Qualified` gate succeeded. That record covers required -checks, tests, builds, policy, selected E2E, and named build artifacts. A -successful `Builds` job alone is insufficient. After the root job pins the +qualification requires one successful, non-cancelled `Native Bazel qualification` +run whose `head_sha` is exact and whose `Required` gate succeeded. It must cover +the configured owners, mandatory tests, platform/device behavior and original +final artifacts. A successful producer job or construction audit alone is +insufficient. After the root job pins the immutable release transport tag, the rest of that run remains bound to the exact transaction without re-evaluating the moving main branch. @@ -324,25 +295,61 @@ bash tools/release/release-check.sh tools/dev/bun.sh src/extensions/tools/check-extension-model.mts --check ``` -If the candidate changes a GitHub workflow or local action, also run -`bash tools/ci/check-workflows.sh`. That conditional gate runs the pinned -`actionlint` and `zizmor` configuration, focused workflow security checks, and -helper behavior tests; -`actionlint` by itself is not equivalent. +For a workflow or local-action change, run the source-owned +`//tools/ci:source_checks` Bazel tests on the declared Linux profile. They use +pinned actionlint, zizmor and ShellCheck plus behavioral workflow/security tests; +actionlint alone is not equivalent. `tools/bazel/README.md` records the target/host +profiles and focused package rehearsals. -The default `release-check.sh` invocation includes publication metadata plus -the release-owned and policy-owned mutation unit suites. `check-release-metadata.mts` -is the canonical product, version, registry ownership, and dependency graph -validator. The release-PR job runs `release-metadata-check.sh` once after the -generated commit is synchronized, while hosted qualification owns candidate -source-metadata evidence. Publishers verify the frozen candidate identity and -live external state instead of replaying source-only metadata checks. +The default `release-check.sh` invocation covers product metadata and controller +mutation tests. Its `--mutation-tests-only` mode exercises release behavior, +including pinned Release Please integration, without repeating metadata gates. +Native preparation supplies authenticated supplier relationships to candidate +calculation, synchronization and verification. Publishers verify the frozen +candidate identity and live external state instead of replaying source-only tests. The `Release` workflow has two operations: 1. `prepare-release-pr` — run from current `main`; creates or updates the generated release PR and synchronizes derived files. 2. `publish` — waits for exact-SHA qualification, prepares and freezes the candidate, bootstraps missing Cargo/npm names when necessary, publishes verified bytes, checks public consumers, and promotes GitHub drafts last. +The Prepare job requires an exact successful eligible-main Native run before +calling `prepare-release-pr.sh`. For local preparation, use an isolated clean +checkout of that qualified main source. Set `QUALIFIED_NATIVE_RUN_ID` to the +verified positive run ID, then: + +```sh +export GITHUB_REPOSITORY=f0rr0/oliphaunt +export NATIVE_QUALIFICATION_RUN_ID="$QUALIFIED_NATIVE_RUN_ID" +bash tools/release/prepare-release-pr.sh /absolute/new/release-candidate +bash tools/release/close-release-candidate.sh /absolute/new/release-candidate +``` + +Use the shell's existing authenticated GitHub context; do not put credentials in +a candidate file. Preparation reads GitHub metadata and writes locally. Close +creates the local normalized release commit only when `required` is true. +`.github/scripts/publish-release-pr.sh` is the separate remote PR mutation. + +The one-time resource migration uses actual constructor captures, not invented +history for the old resource release. At the exact captured source, the existing +proposal command is: + +```sh +bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh \ + tools/release/native-release-preparation.mts --seed-adoption-anchor \ + --run-id "$NATIVE_QUALIFICATION_RUN_ID" --ref "$QUALIFICATION_REF" \ + --output-directory /absolute/new/seed-adoption-proposal +``` + +Review the genuine 14-slot receipt/frozen/public-PGDATA join before committing +`construction-anchor.json` at `src/database-resources/seeds/construction-anchor.json`. +A successful PR source can propose that contract with its truthful source/run +identity; it does not become reviewed-main evidence. The committed declaration +and subsequent qualified source remain mandatory. Never edit the old public +metadata, fabricate its constructor intent or rerun initdb after version changes +to widen release scope. Whole hosted qualification and legacy retirement remain +separate cutover requirements. + Ordinary publication needs no approval run ID or separate dry-run/bootstrap dispatch. Preparation uploads `oliphaunt-publication-lock` and `oliphaunt-publication-candidate`; dependent jobs download their immutable @@ -414,9 +421,9 @@ creation requires both `--apply` and confirmation of the exact lock digest. Wrong or extra configurations are blockers and are never automatically replaced. -Candidate assembly installs the full workspace; normal publish and bootstrap -install only the verified command-line tools required for signing, uploading, -and public verification. Neither path relies on Corepack. When the selected +Native candidate preparation installs the locked release tooling and consumes +authenticated producer outputs. Normal publish and bootstrap install only the +verified command-line tools needed for signing, uploading and public verification. Neither path relies on Corepack. When the selected carrier set includes npm, both normal and bootstrap jobs use `setup-npm-publisher` to install the workflow-pinned npm archive. That action verifies the canonical URL, compressed digests and byte count, safe archive @@ -427,24 +434,23 @@ observed Node/npm trusted-publishing runtime plus the command-specific configuration. This local tool setup neither requests an OIDC token nor changes the frozen registry mutation logic. -Installer fault-injection suites are owned by the exact-SHA -`ci-workflows:check` gate. Publication does not execute those download, cache, -and rollback suites again. Release-PR preparation runs the live metadata checker -once after structured commit verification. The candidate preparation job verifies the -same-SHA `Qualified` record before freezing the candidate; slim publishers do -not replay that source-only validation. +Installer and transport fault-injection suites belong to source-owned Bazel +policy tests and the release controller suites. Publication does not rerun them. +Candidate freezing authenticates the exact-source Native record, final outputs +and Prepare bridge; slim publishers do not replay source-only qualification. For local read-only validation, run `bash tools/release/release-check.sh` for source metadata and release-tool tests. Check selected public version state with `bash tools/release/release-check-registries.sh --products-json '["oliphaunt-js"]' --head-ref HEAD` (replace the example selection with the actual products). Neither command assembles release packages; the retired dry-run wrapper did not assemble them -either. Use the selected products' package and artifact/consumer test tasks for -local package rehearsal. +either. Use the selected owners' actual Bazel package and consumer tests for local +rehearsal. Release admission checks consumer combinations before uploading registry bytes. -The CI release-intent job runs the same compatibility gate on generated release -PRs, their main release commits and explicitly selected main qualification -dispatches; ordinary source PRs and feature diagnostics keep source qualification. +Native CI verifies the canonical prepared source and conventional requirement +transition before qualifying generated release trees. Candidate admission then +checks the selected final delivery against unchanged immutable dependencies; +ordinary source checks do not substitute for that final contract. `consumer-compatibility.mts` reads selected consumers' declared pins and reads unselected dependencies from their immutable product tags. It compares the WASIX SDK runtime with the runtime embedded by its exact N-API dependency, follows @@ -458,9 +464,9 @@ its extension compatibility policy before metadata admission. Cargo extension facades use compatible SemVer requirements for SDK, build-helper and binding APIs; extension payload and AOT carrier versions remain exact. -The shared facade generator is a release source of every external extension and -the native runtime product that owns the contrib facade, so Release Please -includes those products when its shipped output changes. WASIX tools declare +Each owner's Bazel package construction consumes the shared facade generator. +When its delivered output changes, native comparison selects the affected +external extension or runtime contrib owner before Release Please versions it. WASIX tools declare their SDK pin explicitly instead of deriving it from the current workspace SDK. These rules preserve independent packaging versions; they do not establish cross-runtime extension compatibility or waive ABI, AOT, export or integrity @@ -475,21 +481,14 @@ installed carrier for every installed WASIX SDK, including unselected historical SDKs and nested dependency installations. Source qualification and installed release compatibility remain separate requirements. -For a release packaging failure, download the failed candidate's inputs from its -exact CI run into an isolated checkout and run the same assembly entrypoint: - -```sh -bash tools/release/package-release-carriers.sh --products-json '["postgres-tools-native"]' -``` - -Use the failed release's complete product selection when checking for subsequent -failures. Then run `tools/release/publication-lock.mts candidate` with that selection -and the artifact roots used by Release's "Freeze exhaustive publication lock" step. This -checks the complete GitHub and registry inventory, including missing and extra -carriers, without publishing or rebuilding product binaries. Rehearse packaging -fixes this way before expensive qualification; diagnostic outputs are not -publication evidence. A changed packager still requires qualification of the new -candidate. +For a candidate failure, retain the exact source, Native run, Prepare record and +original artifact identities. Use the same `native-freeze-publication-candidate.mts` +entrypoint and arguments as Release's “Freeze authenticated native publication +outputsâ€� step in an isolated checkout. This reuses the actual producer Files; +it does not substitute a local compiler build or the old carrier assembly path. +Use the complete selected scope when diagnosing missing or extra final carriers. +A construction diagnostic is not an admitted publication lock, and changed +production code requires fresh source qualification. Candidate preparation verifies its exact-SHA qualification record once and performs registry preflight once. Immediately before assembly, @@ -831,24 +830,13 @@ Release qualification must inspect the binaries themselves: Mach-O requirements must satisfy these floors. Package labels, runner versions, and successful builds are not compatibility evidence by themselves. -Rust 1.93.1's Linux `std::process` implementation contains weak -`pidfd_getpid`/`pidfd_spawnp` references. Linking the broker directly on an -Ubuntu 24.04 runner binds those otherwise optional references to -`GLIBC_2.39`, which raises the load-time floor even when the fast path is never -used. Linux broker release assets are therefore linked from a clean target -directory in the exact, digest-pinned `rust:1.93.1-slim-bookworm` container. -After any bounded digest-pinned image acquisition, only Cargo's locked -dependency-fetch phase may use the network inside the container; package code -and build scripts run in a read-only, networkless, capability-free container. -The resulting broker is then executed in that baseline before staging. - -Linux release stages also run in the exact digest-pinned Fedora 39 fixture -after verifying that `getconf GNU_LIBC_VERSION` is exactly `glibc 2.38`. -The rehearsal resolves every staged dynamic ELF dependency and executes the -safe version/argument probes available in the carrier. Fedora 39 is retained -solely as a reproducible ABI fixture: it is end-of-life and this check is not a -claim that Fedora 39 is a security-supported production OS. Oliphaunt's public -contract is the GNU architecture and symbol-version floor, not a distro name. +Native Linux construction uses the declared Bazel target/host toolchains, +including the GNU 2.28 profiles. Those construction profiles do not change the +published compatibility ceilings above. Inspect the actual ELF dependencies and +symbol versions of every final carrier, and run its installed consumer on the +required host. Do not link release outputs against arbitrary workstation or +runner-image libraries or restore the former Cargo/Docker producer path as an +alternative authority. Every release-ready exact extension has stable ecosystem façades. PostgreSQL contrib carriers belong to the matching native or WASIX runtime product; each @@ -858,7 +846,7 @@ against the runtime target matrix. ## Frozen consumer readiness -The publication path is: source `Qualified`, final carrier rendering, exhaustive +The publication path is: exact-source Native `Required`, authenticated final outputs, exhaustive publication lock and candidate capsule, `Frozen consumers` on the required hosts, `Publication ready`, then bootstrap and normal publication. Both protected jobs require the ready gate. Every supported mutation entry point also checks the @@ -940,10 +928,10 @@ Ordinary clean-state control-plane workflow, policy, validator, registry-transport, test, or documentation changes do not use recovery and do not create a release. With no other unreleased product change, `prepare-release-pr` reports no releasable products and creates no PR; a direct -publish selects no release changes and performs no registry work. A change to a -compiler, SDK, linker, build command, source selection, target, or packaging -output requires the affected versions to advance even when the change lives in -CI. +publish selects no release changes and performs no registry work. A compiler, SDK, linker, recipe, source-selection or target change requires +qualification of its affected construction. Delivered payload changes select +necessary owners before Release Please calculates versions; an unchanged +qualified delivery does not release merely because a recipe or comment changed. ## Handoff evidence diff --git a/src/docs/next.config.ts b/src/docs/next.config.ts index 89273bcc4..735bd0a17 100644 --- a/src/docs/next.config.ts +++ b/src/docs/next.config.ts @@ -1,7 +1,13 @@ +import { readFileSync } from 'node:fs'; import { createMDX } from 'fumadocs-mdx/next'; import type { NextConfig } from 'next'; const withMDX = createMDX(); +const buildId = + process.env.OLIPHAUNT_DOCS_BUILD_ID ?? + (process.env.OLIPHAUNT_DOCS_BUILD_ID_FILE + ? readFileSync(process.env.OLIPHAUNT_DOCS_BUILD_ID_FILE, 'utf8').trim() + : undefined); const config: NextConfig = { output: 'export', @@ -12,7 +18,11 @@ const config: NextConfig = { }, experimental: { optimizePackageImports: ['lucide-react', 'simple-icons'], + ...(process.env.OLIPHAUNT_DOCS_BUILD_CPUS + ? { cpus: Number(process.env.OLIPHAUNT_DOCS_BUILD_CPUS) } + : {}), }, + ...(buildId ? { generateBuildId: async () => buildId } : {}), basePath: process.env.OLIPHAUNT_DOCS_BASE_PATH || undefined, }; diff --git a/src/docs/package.json b/src/docs/package.json index dede350e8..741461f6d 100644 --- a/src/docs/package.json +++ b/src/docs/package.json @@ -13,6 +13,9 @@ "test": "bash ../../tools/dev/bun.sh test --cwd src/docs tools/published-products.test.mts tools/verify-live.test.mts && bash tools/request-refresh.test.sh" }, "dependencies": { + "@fontsource-variable/dm-sans": "5.3.0", + "@fontsource-variable/geist-mono": "5.3.0", + "@fontsource/instrument-serif": "5.3.0", "@mdx-js/react": "^3.1.0", "clsx": "^2.1.1", "fumadocs-core": "16.9.3", diff --git a/src/docs/source.config.ts b/src/docs/source.config.ts index 5e0235f5a..f771303ea 100644 --- a/src/docs/source.config.ts +++ b/src/docs/source.config.ts @@ -3,7 +3,7 @@ import { defineConfig, defineDocs } from 'fumadocs-mdx/config'; import indexFile from 'fumadocs-mdx/plugins/index-file'; export const docs = defineDocs({ - dir: '../../target/docs/site-docs', + dir: process.env.OLIPHAUNT_DOCS_CONTENT_ROOT ?? '../../target/docs/site-docs', docs: { schema: pageSchema, postprocess: { diff --git a/src/docs/src/app/layout.tsx b/src/docs/src/app/layout.tsx index de8cd72d4..a68937644 100644 --- a/src/docs/src/app/layout.tsx +++ b/src/docs/src/app/layout.tsx @@ -1,20 +1,29 @@ import { RootProvider } from 'fumadocs-ui/provider/next'; import './global.css'; import type { Metadata } from 'next'; -import { DM_Sans, Geist_Mono, Instrument_Serif } from 'next/font/google'; +import localFont from 'next/font/local'; -const sans = DM_Sans({ - subsets: ['latin'], +const sans = localFont({ + src: '../../node_modules/@fontsource-variable/dm-sans/files/dm-sans-latin-wght-normal.woff2', + weight: '100 1000', + style: 'normal', + display: 'swap', variable: '--font-oliphaunt-sans', }); -const mono = Geist_Mono({ - subsets: ['latin'], +const mono = localFont({ + src: '../../node_modules/@fontsource-variable/geist-mono/files/geist-mono-latin-wght-normal.woff2', + weight: '100 900', + style: 'normal', + display: 'swap', variable: '--font-oliphaunt-mono', }); -const serif = Instrument_Serif({ - subsets: ['latin'], +const serif = localFont({ + src: '../../node_modules/@fontsource/instrument-serif/files/instrument-serif-latin-400-normal.woff2', + style: 'normal', + display: 'swap', + adjustFontFallback: 'Times New Roman', weight: '400', variable: '--font-oliphaunt-serif', }); diff --git a/src/docs/tools/check-docs-product.mts b/src/docs/tools/check-docs-product.mts index 230c571df..90b7337e8 100644 --- a/src/docs/tools/check-docs-product.mts +++ b/src/docs/tools/check-docs-product.mts @@ -4,15 +4,6 @@ import path from 'node:path'; import { generateDocs } from './generate-content.mts'; -const result = await generateDocs(); -const { routeRecords, paths } = result; -const { repoRoot } = paths; - -function fail(message) { - console.error(message); - process.exit(1); -} - function stripMarkdownCodeBlocks(markdown) { return markdown.replace(/```[\s\S]*?```/gu, ''); } @@ -65,7 +56,8 @@ function collectSourceTextFiles(dirPath, output = []) { return output; } -function assertDocsInternalLinksResolve() { +export function checkDocsProduct({ routeRecords, paths }) { + const { repoRoot, generatedRoot } = paths; const validDocsPaths = new Set(['/docs']); for (const record of routeRecords) { validDocsPaths.add(`/docs${record.route}`); @@ -73,7 +65,7 @@ function assertDocsInternalLinksResolve() { const failures = []; const files = [ - ...routeRecords.map((record) => record.file), + ...routeRecords.map((record) => path.join(generatedRoot, record.file)), ...collectSourceTextFiles(path.join(repoRoot, 'src/docs/src')), ]; for (const file of files) { @@ -87,9 +79,15 @@ function assertDocsInternalLinksResolve() { } } if (failures.length > 0) { - fail(`public docs contain unresolved internal links:\n${failures.join('\n')}`); + throw new Error(`public docs contain unresolved internal links:\n${failures.join('\n')}`); } } -assertDocsInternalLinksResolve(); -console.log(`docs links passed (${routeRecords.length} routes)`); +if (import.meta.main) { + const specification = process.argv[2]; + const result = await generateDocs( + specification ? JSON.parse(fs.readFileSync(specification, 'utf8')) : {}, + ); + checkDocsProduct(result); + console.log(`docs links passed (${result.routeRecords.length} routes)`); +} diff --git a/src/docs/tools/check-docs-snippets.mts b/src/docs/tools/check-docs-snippets.mts index 0ecc59de4..873d44a2e 100644 --- a/src/docs/tools/check-docs-snippets.mts +++ b/src/docs/tools/check-docs-snippets.mts @@ -4,63 +4,100 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; -const docsRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); -const repoRoot = path.resolve(docsRoot, '../..'); -const generatedRoot = path.join(repoRoot, 'target/docs'); -const scratch = fs.mkdtempSync(path.join(generatedRoot, 'snippet-check-')); +const defaultRepoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../..'); const sdks = [ ['typescript', 'src/native/sdks/ts', '@oliphaunt/ts'], ['react-native', 'src/native/sdks/react-native', '@oliphaunt/react-native'], ['wasix-typescript', 'src/wasix/sdks/ts', '@oliphaunt/wasix-ts'], ]; -try { - for (const [slug, sdkPath, packageName] of sdks) { - const sdkRoot = path.join(repoRoot, sdkPath); - const markdown = fs.readFileSync( - path.join(generatedRoot, `site-docs/sdk/${slug}/index.mdx`), - 'utf8', - ); - const code = markdown.match(/```(?:ts|typescript)\n([\s\S]*?)\n```/u)?.[1]; - if (!code) throw new Error(`${slug}: quickstart has no TypeScript example`); - const file = path.join(scratch, `${slug}.mts`); - fs.writeFileSync(file, code); - const config = path.join(scratch, `${slug}.json`); - fs.writeFileSync( - config, - JSON.stringify({ - extends: path.join(sdkRoot, 'tsconfig.json'), - compilerOptions: { - rootDir: repoRoot, - noEmit: true, - noUnusedLocals: false, - lib: [ - 'ES2023', - 'ESNext.Disposable', - 'DOM', - 'DOM.Iterable', - 'DOM.AsyncIterable', - 'WebWorker', - ], - typeRoots: [path.join(sdkRoot, 'node_modules/@types')], - types: ['node', 'bun'], - paths: { - [packageName]: [path.join(sdkRoot, 'src/index.ts')], - '@oliphaunt/ts-query/*': [path.join(repoRoot, 'src/query/ts/src/*.ts')], - '@oliphaunt/liboliphaunt-wasix': [ - path.join(repoRoot, 'src/wasix/sdks/ts/src/runtime-carrier-shim.d.ts'), +export function checkDocsSnippets({ + repoRoot = defaultRepoRoot, + generatedRoot = path.join(repoRoot, 'target/docs'), + siteDocsRoot = path.join(generatedRoot, 'site-docs'), + compiler = undefined as { node: string; typescript: string; arguments?: string[] } | undefined, +} = {}) { + const docsRoot = path.join(repoRoot, 'src/docs'); + const scratchRoot = process.env.TEST_TMPDIR ?? path.join(repoRoot, 'target/docs'); + fs.mkdirSync(scratchRoot, { recursive: true }); + const scratch = fs.mkdtempSync(path.join(scratchRoot, 'snippet-check-')); + // noEmit includes the scratch example as well as the declared SDK source tree. + let rootDir = repoRoot; + while (path.relative(rootDir, scratch).startsWith(`..${path.sep}`)) + rootDir = path.dirname(rootDir); + try { + for (const [slug, sdkPath, packageName] of sdks) { + const sdkRoot = path.join(repoRoot, sdkPath); + const markdown = fs.readFileSync(path.join(siteDocsRoot, `sdk/${slug}/index.mdx`), 'utf8'); + const code = markdown.match(/```(?:ts|typescript)\n([\s\S]*?)\n```/u)?.[1]; + if (!code) throw new Error(`${slug}: quickstart has no TypeScript example`); + const file = path.join(scratch, `${slug}.mts`); + fs.writeFileSync(file, code); + const config = path.join(scratch, `${slug}.json`); + fs.writeFileSync( + config, + JSON.stringify({ + extends: path.join(sdkRoot, 'tsconfig.json'), + compilerOptions: { + rootDir, + noEmit: true, + noUnusedLocals: false, + lib: [ + 'ES2023', + 'ESNext.Disposable', + 'DOM', + 'DOM.Iterable', + 'DOM.AsyncIterable', + 'WebWorker', ], + typeRoots: [path.join(sdkRoot, 'node_modules/@types')], + types: ['node', 'bun'], + paths: { + [packageName]: [path.join(sdkRoot, 'src/index.ts')], + '@oliphaunt/ts-query/*': [path.join(repoRoot, 'src/query/ts/src/*.ts')], + '@oliphaunt/liboliphaunt-wasix': [ + path.join(repoRoot, 'src/wasix/sdks/ts/src/runtime-carrier-shim.d.ts'), + ], + }, }, + include: [file], + exclude: [], + }), + ); + execFileSync( + compiler?.node ?? path.join(docsRoot, 'node_modules/.bin/tsc'), + [ + ...(compiler + ? [...(compiler.arguments ?? []), path.join(compiler.typescript, 'bin/tsc')] + : []), + '-p', + config, + ], + { + stdio: 'inherit', }, - include: [file], - exclude: [], - }), - ); - execFileSync(path.join(docsRoot, 'node_modules/.bin/tsc'), ['-p', config], { - stdio: 'inherit', - }); - console.log(`${slug} quickstart: type-checked against SDK source (not executed)`); + ); + console.log(`${slug} quickstart: type-checked against SDK source (not executed)`); + } + } finally { + fs.rmSync(scratch, { recursive: true, force: true }); } -} finally { - fs.rmSync(scratch, { recursive: true, force: true }); +} + +if (import.meta.main) { + const [specification, siteDocsRoot, typescript] = process.argv.slice(2); + checkDocsSnippets( + specification === '--native' + ? { + siteDocsRoot: path.resolve(siteDocsRoot), + compiler: { + node: process.execPath, + typescript: path.resolve(typescript), + arguments: process.execArgv, + }, + } + : specification + ? JSON.parse(fs.readFileSync(specification, 'utf8')) + : {}, + ); } diff --git a/src/docs/tools/generate-content.mts b/src/docs/tools/generate-content.mts index 049f13906..6c62939e3 100644 --- a/src/docs/tools/generate-content.mts +++ b/src/docs/tools/generate-content.mts @@ -2,7 +2,7 @@ import { execFileSync } from 'node:child_process'; import fs from 'node:fs'; import path from 'node:path'; -import { fileURLToPath, pathToFileURL } from 'node:url'; +import { fileURLToPath } from 'node:url'; const parseToml = Bun.TOML.parse; @@ -10,14 +10,39 @@ import { renderPublicPlatformCompatibilityTable } from '../../../tools/release/p import { publishedProducts, sourceProducts } from './published-products.mts'; const scriptDir = path.dirname(fileURLToPath(import.meta.url)); -const docsRoot = path.resolve(scriptDir, '..'); -const repoRoot = path.resolve(scriptDir, '../../..'); -const manifestPath = path.join(docsRoot, 'docs-manifest.toml'); -const generatedRoot = path.join(repoRoot, 'target', 'docs'); -const siteDocsRoot = path.join(generatedRoot, 'site-docs'); -const staticRoot = path.join(generatedRoot, 'static'); +const defaultRepoRoot = path.resolve(scriptDir, '../../..'); -const generatedMetaRoot = path.join(generatedRoot, 'generated'); +export type DocsGenerationOptions = { + repoRoot?: string; + generatedRoot?: string; + releasesFile?: string; + provenanceFile?: string; +}; + +export type DocsProvenance = { sourceRevision: string; dirty: boolean }; + +export function readDocsProvenance(file: string): DocsProvenance { + const value = JSON.parse(fs.readFileSync(file, 'utf8')); + if ( + !value || + typeof value !== 'object' || + Array.isArray(value) || + typeof value.sourceRevision !== 'string' || + !/^[a-f0-9]{40}$/.test(value.sourceRevision ?? '') || + typeof value.dirty !== 'boolean' || + Object.keys(value).some((key) => !['sourceRevision', 'dirty'].includes(key)) + ) + throw new Error('Docs provenance requires an exact source revision and dirty state'); + return value; +} + +type DocsPaths = { + repoRoot: string; + docsRoot: string; + siteDocsRoot: string; + staticRoot: string; + generatedMetaRoot: string; +}; const SKIP_DIRS = new Set(['node_modules', '.git', '.moon', '.docusaurus', 'build', 'target']); @@ -38,8 +63,14 @@ function resetDir(dirPath) { ensureDir(dirPath); } -function assertInsideRepo(relativePath, label) { - if (!relativePath || path.isAbsolute(relativePath) || relativePath.includes('\0')) { +function assertInsideRepo(relativePath, label, repoRoot) { + if ( + !relativePath || + path.isAbsolute(relativePath) || + relativePath.includes('\0') || + relativePath.includes('\\') || + relativePath.split('/').some((part) => !part || part === '.' || part === '..') + ) { throw new Error(`${label} must be a repository-relative path`); } const resolved = path.resolve(repoRoot, relativePath); @@ -103,6 +134,7 @@ function normalizeCodeFenceInfoStrings(markdown) { } function routeSourcePagePath(source, page) { + assertInsideRepo(page, 'docs page', source); for (const extension of ['.md', '.mdx']) { const candidate = path.join(source, `${page}${extension}`); if (fs.existsSync(candidate)) { @@ -126,9 +158,9 @@ function copyMarkdownPage(from, to) { fs.writeFileSync(to, normalizePageMarkdown(markdown, fallbackTitle)); } -function copyRoutePages(route) { - const source = assertInsideRepo(route.source, `source for ${route.id}`); - const destination = path.join(siteDocsRoot, route.route); +function copyRoutePages(route, { repoRoot, siteDocsRoot }: DocsPaths) { + const source = assertInsideRepo(route.source, `source for ${route.id}`, repoRoot); + const destination = assertInsideRepo(route.route, `destination for ${route.id}`, siteDocsRoot); ensureDir(destination); for (const page of uniqueInOrder([ ...(route.page_order ?? []), @@ -136,6 +168,8 @@ function copyRoutePages(route) { ])) { const from = routeSourcePagePath(source, page); if (!from) { + if (route.required_pages?.includes(page)) + throw new Error(`${route.id}: missing required docs page ${page}`); continue; } const to = path.join(destination, `${page}${path.extname(from)}`); @@ -188,21 +222,21 @@ function collectMarkdownFiles(root) { return files.sort(); } -function markdownRouteFor(filePath) { +function markdownRouteFor(filePath, siteDocsRoot) { const relative = path.relative(siteDocsRoot, filePath).replaceAll(path.sep, '/'); const withoutExtension = relative.replace(/\.mdx?$/, ''); const route = withoutExtension.replace(/\/index$/, ''); return `/${route}`; } -function markdownDocIdFor(filePath) { +function markdownDocIdFor(filePath, siteDocsRoot) { return path .relative(siteDocsRoot, filePath) .replaceAll(path.sep, '/') .replace(/\.mdx?$/, ''); } -function generateExtensionCatalog() { +function generateExtensionCatalog(repoRoot) { const catalogPath = path.join(repoRoot, 'src/extensions/generated/extensions.catalog.json'); if (!fs.existsSync(catalogPath)) { throw new Error('extension catalog source is required for public docs generation'); @@ -251,7 +285,7 @@ function extensionActivation(extension) { return 'CREATE EXTENSION'; } -function writeMetadata(routeRecords) { +function writeMetadata(routeRecords, generatedMetaRoot) { ensureDir(generatedMetaRoot); fs.writeFileSync( path.join(generatedMetaRoot, 'routes.json'), @@ -389,7 +423,7 @@ function titleForPathSegment(segment) { .join(' '); } -function writeRouteMeta(route) { +function writeRouteMeta(route, siteDocsRoot) { const routeRoot = path.join(siteDocsRoot, route.route); const metadata = { title: route.title, @@ -426,7 +460,7 @@ function writeRouteMeta(route) { } } -function writeFumadocsMeta(manifest) { +function writeFumadocsMeta(manifest, siteDocsRoot) { const sdkRoutes = (manifest.routes ?? []).filter((route) => route.kind === 'sdk'); writeJson(path.join(siteDocsRoot, 'meta.json'), { title: 'Oliphaunt', @@ -436,7 +470,7 @@ function writeFumadocsMeta(manifest) { }); for (const route of manifest.routes ?? []) { if (route.id !== 'sdk') { - writeRouteMeta(route); + writeRouteMeta(route, siteDocsRoot); } } writeJson(path.join(siteDocsRoot, 'sdk', 'meta.json'), { @@ -450,7 +484,11 @@ function writeFumadocsMeta(manifest) { }); } -function writeNavigationMetadata(manifest, routeRecords) { +function writeNavigationMetadata( + manifest, + routeRecords, + { siteDocsRoot, generatedMetaRoot }: DocsPaths, +) { const byId = new Map((manifest.routes ?? []).map((route) => [route.id, route])); const sdkRoutes = (manifest.routes ?? []).filter((route) => route.kind === 'sdk'); const navigation = { @@ -467,10 +505,10 @@ function writeNavigationMetadata(manifest, routeRecords) { ], }; writeJson(path.join(generatedMetaRoot, 'navigation.json'), navigation); - writeFumadocsMeta(manifest); + writeFumadocsMeta(manifest, siteDocsRoot); } -function currentGitSha() { +function currentGitSha(repoRoot) { return ( process.env.OLIPHAUNT_DOCS_GIT_SHA || process.env.VERCEL_GIT_COMMIT_SHA || @@ -478,9 +516,48 @@ function currentGitSha() { ); } -export async function generateDocs() { +export async function generateDocs(options: DocsGenerationOptions = {}) { + const repoRoot = path.resolve(options.repoRoot ?? defaultRepoRoot); + const docsRoot = path.join(repoRoot, 'src/docs'); + const generatedRoot = path.resolve(options.generatedRoot ?? path.join(repoRoot, 'target/docs')); + if ( + repoRoot === generatedRoot || + repoRoot.startsWith(generatedRoot + path.sep) || + (generatedRoot.startsWith(repoRoot + path.sep) && + !generatedRoot.startsWith(path.join(repoRoot, 'target') + path.sep)) + ) + throw new Error('Docs output must be outside source inputs or beneath target/'); + const siteDocsRoot = path.join(generatedRoot, 'site-docs'); + const staticRoot = path.join(generatedRoot, 'static'); + const generatedMetaRoot = path.join(generatedRoot, 'generated'); + const paths = { repoRoot, docsRoot, siteDocsRoot, staticRoot, generatedMetaRoot }; + const manifestPath = path.join(docsRoot, 'docs-manifest.toml'); const manifest = parseTomlFile(manifestPath); - const products = await publishedProducts(manifest.routes); + const provenanceFile = options.provenanceFile ?? process.env.OLIPHAUNT_DOCS_PROVENANCE_FILE; + const provenance = provenanceFile + ? readDocsProvenance(provenanceFile) + : { + sourceRevision: currentGitSha(repoRoot), + dirty: + execFileSync('git', ['status', '--porcelain'], { cwd: repoRoot, encoding: 'utf8' }).trim() + .length > 0, + }; + const products = await publishedProducts(manifest.routes, { + repoRoot, + releasesFile: options.releasesFile, + }); + const sourceVersions = await sourceProducts(repoRoot); + const extensionCatalog = generateExtensionCatalog(repoRoot); + for (const route of manifest.routes ?? []) { + const source = assertInsideRepo(route.source, `source for ${route.id}`, repoRoot); + assertInsideRepo(route.route, `destination for ${route.id}`, siteDocsRoot); + for (const page of uniqueInOrder([ + ...(route.page_order ?? []), + ...(route.required_pages ?? []), + ])) + if (!routeSourcePagePath(source, page) && route.required_pages?.includes(page)) + throw new Error(`${route.id}: missing required docs page ${page}`); + } resetDir(siteDocsRoot); resetDir(staticRoot); resetDir(generatedMetaRoot); @@ -488,24 +565,15 @@ export async function generateDocs() { path.join(generatedMetaRoot, 'published-products.json'), JSON.stringify(products, null, 2) + '\n', ); - const sourceVersions = await sourceProducts(); writeJson(path.join(staticRoot, 'docs-version.json'), { - sourceRevision: currentGitSha(), - dirty: - execFileSync('git', ['status', '--porcelain'], { - cwd: repoRoot, - encoding: 'utf8', - }).trim().length > 0, + ...provenance, products: sourceVersions, }); for (const route of manifest.routes ?? []) { - copyRoutePages(route); + copyRoutePages(route, paths); } - fs.writeFileSync( - path.join(siteDocsRoot, 'reference', 'extension-catalog.md'), - generateExtensionCatalog(), - ); + fs.writeFileSync(path.join(siteDocsRoot, 'reference', 'extension-catalog.md'), extensionCatalog); const rows = Object.entries(products).map(([id, published]) => { return `| ${id} | ${published ? `[${published.version}](${published.url})` : 'No completed release'} |`; }); @@ -519,24 +587,24 @@ export async function generateDocs() { const routeRecords = collectMarkdownFiles(siteDocsRoot).map((file) => { const markdown = readText(file); return { - route: markdownRouteFor(file), - docId: markdownDocIdFor(file), + route: markdownRouteFor(file, siteDocsRoot), + docId: markdownDocIdFor(file, siteDocsRoot), title: frontmatterValue(markdown, 'title') || firstHeading(markdown, path.basename(file, path.extname(file))), - file, - source: path.relative(repoRoot, file), + file: path.relative(generatedRoot, file).split(path.sep).join('/'), + source: path.relative(generatedRoot, file).split(path.sep).join('/'), }; }); - writeMetadata(routeRecords); - writeNavigationMetadata(manifest, routeRecords); + writeMetadata(routeRecords, generatedMetaRoot); + writeNavigationMetadata(manifest, routeRecords, paths); fs.writeFileSync( path.join(generatedMetaRoot, 'build-metadata.json'), `${JSON.stringify( { - generatedAt: new Date().toISOString(), - gitSha: currentGitSha(), + ...(provenanceFile ? {} : { generatedAt: new Date().toISOString() }), + gitSha: provenance.sourceRevision, routeCount: routeRecords.length, }, null, @@ -548,16 +616,14 @@ export async function generateDocs() { manifest, routeRecords, paths: { - repoRoot, - docsRoot, - siteDocsRoot, - staticRoot, - generatedMetaRoot, + ...paths, + generatedRoot, }, }; } -if (import.meta.url === pathToFileURL(process.argv[1]).href) { - const result = await generateDocs(); +if (import.meta.main) { + const specification = process.argv[2]; + const result = await generateDocs(specification ? JSON.parse(readText(specification)) : {}); console.log(`generated ${result.routeRecords.length} docs routes`); } diff --git a/src/docs/tools/generate-content.test.mts b/src/docs/tools/generate-content.test.mts new file mode 100644 index 000000000..d22b34f11 --- /dev/null +++ b/src/docs/tools/generate-content.test.mts @@ -0,0 +1,188 @@ +import { afterEach, expect, test } from 'bun:test'; +import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { checkDocsProduct } from './check-docs-product.mts'; +import { generateDocs, readDocsProvenance } from './generate-content.mts'; + +const scratch: string[] = []; +afterEach(() => { + for (const root of scratch.splice(0)) rmSync(root, { recursive: true, force: true }); +}); + +function fixture() { + const repoRoot = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'docs-inputs-')); + scratch.push(repoRoot); + function write(relative: string, contents: string | object) { + const file = path.join(repoRoot, relative); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, typeof contents === 'string' ? contents : JSON.stringify(contents)); + return file; + } + const groups = ['start', 'sdk', 'learn', 'reference']; + write( + 'src/docs/docs-manifest.toml', + groups + .map( + (id) => `[[routes]] +id = "${id}" +title = "${id}" +kind = "public" +route = "${id}" +source = "src/docs/content/${id}" +page_order = ${id === 'reference' ? '["index", "extensions"]' : '["index"]'} +`, + ) + .join('\n'), + ); + for (const id of groups) + write(`src/docs/content/${id}/index.mdx`, `# ${id}\n\n[Start](/docs/start)\n`); + write('src/docs/content/reference/extensions.mdx', '# Extensions\n'); + write('src/docs/src/links.tsx', 'Releases'); + write('release-please-config.json', { packages: { 'src/sdk': { component: 'sdk' } } }); + write('.release-please-manifest.json', { 'src/sdk': '9.0.0' }); + write('src/extensions/generated/extensions.catalog.json', { extensions: [] }); + const releasesFile = write('releases.json', [ + { + tag_name: 'sdk-v1.2.3', + html_url: 'https://github.com/f0rr0/oliphaunt/releases/tag/sdk-v1.2.3', + draft: false, + prerelease: false, + published_at: '2026-09-11T00:00:00Z', + }, + ]); + const provenanceFile = write('provenance.json', { sourceRevision: 'a'.repeat(40), dirty: false }); + return { repoRoot, releasesFile, provenanceFile, write }; +} + +function contents(root: string) { + const files: Record = {}; + function visit(directory: string) { + for (const entry of readdirSync(directory, { withFileTypes: true })) { + const file = path.join(directory, entry.name); + if (entry.isDirectory()) visit(file); + else files[path.relative(root, file)] = readFileSync(file, 'utf8'); + } + } + visit(root); + return files; +} + +test('declared snapshots generate identical relocatable content without a Git checkout', async () => { + const first = fixture(); + const second = fixture(); + const left = await generateDocs(first); + const right = await generateDocs(second); + expect(contents(left.paths.generatedRoot)).toEqual(contents(right.paths.generatedRoot)); + checkDocsProduct(left); + for (const record of left.routeRecords) { + expect(path.isAbsolute(record.file)).toBe(false); + expect(record.file).toStartWith('site-docs/'); + } + expect( + JSON.parse(readFileSync(path.join(left.paths.staticRoot, 'docs-version.json'), 'utf8')), + ).toEqual({ + sourceRevision: 'a'.repeat(40), + dirty: false, + products: { sdk: { version: '9.0.0' } }, + }); + const releases = readFileSync( + path.join(left.paths.siteDocsRoot, 'reference/version-matrix.md'), + 'utf8', + ); + expect(releases).toContain('[1.2.3]'); + expect(releases).not.toContain('9.0.0'); + expect(contents(left.paths.generatedRoot)['generated/build-metadata.json']).not.toContain( + 'generatedAt', + ); +}); + +test('a relocated output directory keeps route metadata and source-link checks valid', async () => { + const inputs = fixture(); + const generatedRoot = path.join(inputs.repoRoot, 'target/relocated-docs'); + const result = await generateDocs({ ...inputs, generatedRoot }); + checkDocsProduct(result); + inputs.write('src/docs/src/links.tsx', 'Broken'); + expect(() => checkDocsProduct(result)).toThrow('unresolved docs link /docs/missing'); +}); + +test('explicit provenance rejects volatile, missing and malformed fields', () => { + const inputs = fixture(); + for (const value of [ + null, + [], + {}, + { sourceRevision: 'main', dirty: false }, + { sourceRevision: ['a'.repeat(40)], dirty: false }, + { sourceRevision: 'a'.repeat(40), dirty: 'false' }, + { sourceRevision: 'a'.repeat(40), dirty: false, generatedAt: 'now' }, + ]) { + inputs.write('provenance.json', JSON.stringify(value)); + expect(() => readDocsProvenance(inputs.provenanceFile)).toThrow('exact source revision'); + } +}); + +test('bad declared inputs fail before deleting a previous generated result', async () => { + const inputs = fixture(); + const result = await generateDocs(inputs); + const before = contents(result.paths.generatedRoot); + inputs.write('releases.json', {}); + await expect(generateDocs(inputs)).rejects.toThrow('GitHub releases array'); + expect(contents(result.paths.generatedRoot)).toEqual(before); + inputs.write('releases.json', [ + { + tag_name: 'sdk-v1.2.3', + html_url: 'javascript:alert(1)', + draft: false, + prerelease: false, + published_at: '2026-09-11', + }, + ]); + await expect(generateDocs(inputs)).rejects.toThrow('invalid GitHub release record'); + expect(contents(result.paths.generatedRoot)).toEqual(before); +}); + +test('an empty completed-release snapshot never advertises a checkout candidate', async () => { + const inputs = fixture(); + inputs.write('releases.json', []); + const result = await generateDocs(inputs); + const releases = readFileSync( + path.join(result.paths.siteDocsRoot, 'reference/version-matrix.md'), + 'utf8', + ); + expect(releases).toContain('No completed release'); + expect(releases).not.toContain('9.0.0'); +}); + +test('declared output and route paths cannot overwrite source inputs', async () => { + const inputs = fixture(); + for (const generatedRoot of [ + inputs.repoRoot, + path.dirname(inputs.repoRoot), + path.join(inputs.repoRoot, 'src/docs'), + ]) + await expect(generateDocs({ ...inputs, generatedRoot })).rejects.toThrow( + 'outside source inputs', + ); + const manifest = readFileSync(path.join(inputs.repoRoot, 'src/docs/docs-manifest.toml'), 'utf8'); + for (const route of ['../escape', '/absolute', 'start/../../escape']) { + inputs.write( + 'src/docs/docs-manifest.toml', + manifest.replace('route = "start"', `route = "${route}"`), + ); + await expect(generateDocs(inputs)).rejects.toThrow('repository-relative path'); + } +}); + +test('missing required pages fail before producing a misleading partial site', async () => { + const inputs = fixture(); + const manifest = readFileSync(path.join(inputs.repoRoot, 'src/docs/docs-manifest.toml'), 'utf8'); + inputs.write( + 'src/docs/docs-manifest.toml', + manifest.replace( + 'page_order = ["index"]', + 'page_order = ["index"]\nrequired_pages = ["missing"]', + ), + ); + await expect(generateDocs(inputs)).rejects.toThrow('missing required docs page missing'); +}); diff --git a/src/docs/tools/native-docs.mts b/src/docs/tools/native-docs.mts new file mode 100644 index 000000000..238c772de --- /dev/null +++ b/src/docs/tools/native-docs.mts @@ -0,0 +1,162 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + copyFileSync, + cpSync, + lstatSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + realpathSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { checkDocsProduct } from './check-docs-product.mts'; +import { generateDocs } from './generate-content.mts'; + +export type DocsSource = { path: string; source: string }; +export type DocsPackage = { + package: string; + version: string; + integrity: string; + dependencies: Record; +}; +function relativePath(value: string) { + assert( + typeof value === 'string' && + value && + !path.isAbsolute(value) && + !value.includes('\\') && + !value.includes('\0') && + value.split('/').every((part) => part && part !== '.' && part !== '..'), + `Invalid declared docs path: ${value}`, + ); + return value; +} + +export function stageDocsSources(root: string, sources: DocsSource[]) { + const paths = new Set(); + for (const file of sources) { + relativePath(file.path); + assert(!paths.has(file.path), `Duplicate declared docs path: ${file.path}`); + assert( + lstatSync(realpathSync(file.source)).isFile(), + `Docs input must be a regular file: ${file.path}`, + ); + paths.add(file.path); + } + for (const file of sources) { + const target = path.join(root, file.path); + mkdirSync(path.dirname(target), { recursive: true }); + copyFileSync(file.source, target); + chmodSync(target, 0o644); + } +} + +export function docsBuildId( + sources: DocsSource[], + contentRoot: string, + packages: Record, + options: { basePath: string; siteUrl: string }, + tools: DocsSource[] = [], +) { + const hash = createHash('sha256'); + function member(name: string, contents: Buffer | string) { + hash.update(JSON.stringify(name)).update('\0').update(contents).update('\0'); + } + for (const file of [...sources].sort((a, b) => a.path.localeCompare(b.path))) + member(file.path, readFileSync(file.source)); + for (const tool of [...tools].sort((a, b) => a.path.localeCompare(b.path))) + member(`toolchain/${relativePath(tool.path)}`, readFileSync(tool.source)); + function visit(directory: string) { + for (const entry of readdirSync(directory, { withFileTypes: true }).sort((a, b) => + a.name.localeCompare(b.name), + )) { + const file = path.join(directory, entry.name); + const resolved = lstatSync(realpathSync(file)); + if (resolved.isDirectory()) visit(file); + else { + assert(resolved.isFile(), 'Docs content must contain regular files'); + member( + `content/${path.relative(contentRoot, file).split(path.sep).join('/')}`, + readFileSync(file), + ); + } + } + } + visit(contentRoot); + for (const [id, row] of Object.entries(packages).sort(([a], [b]) => a.localeCompare(b))) + member( + `package/${id}`, + JSON.stringify({ + package: row.package, + version: row.version, + integrity: row.integrity, + dependencies: Object.fromEntries( + Object.entries(row.dependencies).sort(([a], [b]) => a.localeCompare(b)), + ), + }), + ); + member('configuration', JSON.stringify(options)); + return hash.digest('hex'); +} + +async function scratch(operation: (root: string) => T | Promise): Promise { + const root = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'oliphaunt-docs-')); + try { + return await operation(root); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +type ContentSpec = { + sources: DocsSource[]; + releasesFile: string; + provenanceFile: string; + outputs: { siteDocs: string; static: string; routes: string; metadata: string }; +}; + +export async function buildDocsContent(specification: ContentSpec) { + assert( + specification.releasesFile && specification.provenanceFile, + 'Native docs generation requires completed-release and source-provenance inputs', + ); + return scratch(async (root) => { + stageDocsSources(root, specification.sources); + const result = await generateDocs({ + repoRoot: root, + releasesFile: path.resolve(specification.releasesFile), + provenanceFile: path.resolve(specification.provenanceFile), + }); + checkDocsProduct(result); + cpSync(result.paths.siteDocsRoot, specification.outputs.siteDocs, { recursive: true }); + cpSync(result.paths.staticRoot, specification.outputs.static, { recursive: true }); + cpSync(result.paths.generatedMetaRoot, specification.outputs.metadata, { recursive: true }); + copyFileSync( + path.join(result.paths.generatedMetaRoot, 'routes.json'), + specification.outputs.routes, + ); + }); +} + +if (import.meta.main) { + const [operation, specificationFile] = Bun.argv.slice(2); + assert(specificationFile, 'Expected a declared docs operation and input specification'); + const specification = JSON.parse(readFileSync(specificationFile, 'utf8')); + if (operation === 'content') await buildDocsContent(specification); + else if (operation === 'build-id') + writeFileSync( + specification.output, + `${docsBuildId(specification.sources, specification.siteDocs, specification.packages, { basePath: specification.basePath, siteUrl: specification.siteUrl }, specification.tools)}\n`, + ); + else if (operation === 'export') { + cpSync(specification.site, specification.output, { recursive: true }); + cpSync(specification.static, specification.output, { recursive: true }); + stageDocsSources(specification.output, specification.licenses ?? []); + } else throw new Error(`Unknown docs operation: ${operation}`); +} diff --git a/src/docs/tools/native-docs.test.mts b/src/docs/tools/native-docs.test.mts new file mode 100644 index 000000000..5d3b28863 --- /dev/null +++ b/src/docs/tools/native-docs.test.mts @@ -0,0 +1,130 @@ +import { afterEach, expect, test } from 'bun:test'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { type DocsPackage, docsBuildId, stageDocsSources } from './native-docs.mts'; + +const scratch: string[] = []; +afterEach(() => { + for (const root of scratch.splice(0)) rmSync(root, { recursive: true, force: true }); +}); + +function directory() { + const root = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'docs-native-inputs-')); + scratch.push(root); + return root; +} + +function file(root: string, name: string, content: string, mode = 0o644) { + const target = path.join(root, name); + mkdirSync(path.dirname(target), { recursive: true }); + writeFileSync(target, content, { mode }); + return target; +} + +test('source staging validates the entire declared input set before writing files', () => { + const source = directory(); + const destination = directory(); + const input = file(source, 'valid.ts', 'export const answer = 42;'); + file(destination, 'src/docs/valid.ts', 'previous'); + for (const pathName of ['../escape', '/absolute', 'src/../escape', 'src\\escape']) { + expect(() => + stageDocsSources(destination, [ + { path: 'src/docs/valid.ts', source: input }, + { path: pathName, source: input }, + ]), + ).toThrow('Invalid declared docs path'); + expect(readFileSync(path.join(destination, 'src/docs/valid.ts'), 'utf8')).toBe('previous'); + } + expect(() => + stageDocsSources(destination, [ + { path: 'src/docs/valid.ts', source: input }, + { path: 'src/docs/valid.ts', source: input }, + ]), + ).toThrow('Duplicate declared docs path'); + const link = path.join(source, 'linked.ts'); + symlinkSync(input, link); + stageDocsSources(destination, [{ path: 'src/docs/linked.ts', source: link }]); + expect(readFileSync(path.join(destination, 'src/docs/linked.ts'), 'utf8')).toContain('42'); + expect(() => stageDocsSources(destination, [{ path: 'src/docs/not-a-file', source }])).toThrow( + 'regular file', + ); + stageDocsSources(destination, [{ path: 'src/docs/valid.ts', source: input }]); + expect(readFileSync(path.join(destination, 'src/docs/valid.ts'), 'utf8')).toContain('42'); +}); + +test('build IDs follow delivered pages and declared package identities, independently of scratch paths', () => { + const first = directory(); + const second = directory(); + const a = file(first, 'src.tsx', 'export default function Page() { return null; }'); + const b = file(second, 'src.tsx', readFileSync(a, 'utf8')); + const left = directory(); + const right = directory(); + file(left, 'start/index.mdx', '# Start\n'); + file(right, 'start/index.mdx', '# Start\n'); + const row: DocsPackage = { + package: 'docs-fixture', + version: '1.0.0', + integrity: `sha512-${Buffer.alloc(64).toString('base64')}`, + dependencies: {}, + }; + const options = { basePath: '', siteUrl: 'https://oliphaunt.dev' }; + const baseline = docsBuildId( + [{ path: 'src/docs/src/page.tsx', source: a }], + left, + { a: row }, + options, + ); + expect( + docsBuildId([{ path: 'src/docs/src/page.tsx', source: b }], right, { a: row }, options), + ).toBe(baseline); + file(right, 'start/index.mdx', '# Changed\n'); + expect( + docsBuildId([{ path: 'src/docs/src/page.tsx', source: b }], right, { a: row }, options), + ).not.toBe(baseline); + expect( + docsBuildId( + [{ path: 'src/docs/src/page.tsx', source: a }], + left, + { a: { ...row, version: '2.0.0' } }, + options, + ), + ).not.toBe(baseline); + expect( + docsBuildId( + [{ path: 'src/docs/src/page.tsx', source: a }], + left, + { a: row }, + { ...options, basePath: '/preview' }, + ), + ).not.toBe(baseline); + const tool = file(first, 'node', 'pinned node identity'); + const withTool = docsBuildId( + [{ path: 'src/docs/src/page.tsx', source: a }], + left, + { a: row }, + options, + [{ path: 'node', source: tool }], + ); + expect(withTool).not.toBe(baseline); + file(first, 'node', 'another pinned node identity'); + expect( + docsBuildId([{ path: 'src/docs/src/page.tsx', source: a }], left, { a: row }, options, [ + { path: 'node', source: tool }, + ]), + ).not.toBe(withTool); +}); + +test('build IDs retain logical names across sandbox tree and leaf symlink transport', () => { + const regular = directory(); + const input = file(regular, 'sdk/index.mdx', '# Declared content\n'); + const leaves = directory(); + mkdirSync(path.join(leaves, 'sdk')); + symlinkSync(input, path.join(leaves, 'sdk/index.mdx')); + const root = path.join(directory(), 'site-docs'); + symlinkSync(regular, root, 'dir'); + const options = { basePath: '', siteUrl: 'https://oliphaunt.dev' }; + const expected = docsBuildId([], regular, {}, options); + expect(docsBuildId([], leaves, {}, options)).toBe(expected); + expect(docsBuildId([], root, {}, options)).toBe(expected); +}); diff --git a/src/docs/tools/published-products.mts b/src/docs/tools/published-products.mts index c4a0a4cfa..509594ee8 100644 --- a/src/docs/tools/published-products.mts +++ b/src/docs/tools/published-products.mts @@ -1,6 +1,8 @@ import fs from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; -const cache = new URL('../../../target/docs/published-releases.json', import.meta.url); +const defaultRepoRoot = fileURLToPath(new URL('../../../', import.meta.url)); export function selectProducts(releases, ids) { return Object.fromEntries( @@ -33,14 +35,17 @@ export function selectProducts(releases, ids) { ); } -export async function publishedProducts(routes) { +export async function publishedProducts( + routes, + { repoRoot = defaultRepoRoot, releasesFile = process.env.OLIPHAUNT_DOCS_RELEASES_FILE } = {}, +) { // Release ownership supplies identities only; candidate versions are never read. const releaseConfig = JSON.parse( - await fs.readFile(new URL('../../../release-please-config.json', import.meta.url), 'utf8'), + await fs.readFile(path.join(repoRoot, 'release-please-config.json'), 'utf8'), ); const ids = Object.values(releaseConfig.packages).map((product) => product.component); // Offline builds must explicitly select a previously resolved input or fixture. - const input = process.env.OLIPHAUNT_DOCS_RELEASES_FILE; + const input = releasesFile; const releases = input ? JSON.parse(await fs.readFile(input, 'utf8')) : []; if (!input) { for (let page = 1; ; page++) { @@ -64,11 +69,23 @@ export async function publishedProducts(routes) { releases.push(...batch); if (batch.length < 100) break; } - await fs.mkdir(new URL('./', cache), { recursive: true }); + const cache = path.join(repoRoot, 'target/docs/published-releases.json'); + await fs.mkdir(path.dirname(cache), { recursive: true }); await fs.writeFile(cache, JSON.stringify(releases, null, 2) + '\n'); } if (!Array.isArray(releases)) throw new Error('Docs release input must be a GitHub releases array'); + for (const release of releases) + if ( + !release || + typeof release !== 'object' || + typeof release.tag_name !== 'string' || + typeof release.draft !== 'boolean' || + typeof release.prerelease !== 'boolean' || + (release.published_at !== null && typeof release.published_at !== 'string') || + release.html_url !== `https://github.com/f0rr0/oliphaunt/releases/tag/${release.tag_name}` + ) + throw new Error('Docs release input contains an invalid GitHub release record'); return selectProducts(releases, [ ...ids, ...routes.flatMap((route) => (route.product_id ? [route.product_id] : [])), @@ -89,10 +106,10 @@ export function selectSourceProducts(config, versions) { ); } -export async function sourceProducts() { +export async function sourceProducts(repoRoot = defaultRepoRoot) { const [config, versions] = await Promise.all([ - fs.readFile(new URL('../../../release-please-config.json', import.meta.url), 'utf8'), - fs.readFile(new URL('../../../.release-please-manifest.json', import.meta.url), 'utf8'), + fs.readFile(path.join(repoRoot, 'release-please-config.json'), 'utf8'), + fs.readFile(path.join(repoRoot, '.release-please-manifest.json'), 'utf8'), ]); return selectSourceProducts(JSON.parse(config), JSON.parse(versions)); } diff --git a/src/docs/tools/smoke-built-site.mts b/src/docs/tools/smoke-built-site.mts index caa5d6512..9b10066c3 100644 --- a/src/docs/tools/smoke-built-site.mts +++ b/src/docs/tools/smoke-built-site.mts @@ -6,8 +6,11 @@ import { oramaStaticClient } from 'fumadocs-core/search/client/orama-static'; const scriptDir = path.dirname(fileURLToPath(import.meta.url)); const repoRoot = path.resolve(scriptDir, '../../..'); -const buildRoot = path.join(repoRoot, 'target', 'docs', 'build'); -const routesPath = path.join(repoRoot, 'target', 'docs', 'generated', 'routes.json'); +const [declaredBuildRoot, declaredRoutesPath, declaredBasePath] = process.argv.slice(2); +const buildRoot = path.resolve(declaredBuildRoot ?? path.join(repoRoot, 'target/docs/build')); +const routesPath = path.resolve( + declaredRoutesPath ?? path.join(repoRoot, 'target/docs/generated/routes.json'), +); function fail(message) { console.error(message); @@ -70,7 +73,7 @@ const idsByPath = new Map( new Set([...html.matchAll(/\bid="([^"]+)"/gu)].map((match) => match[1])), ]), ); -const basePath = process.env.OLIPHAUNT_DOCS_BASE_PATH || ''; +const basePath = declaredBasePath ?? process.env.OLIPHAUNT_DOCS_BASE_PATH ?? ''; for (const [file, html] of htmlByPath) { const pagePath = `/${path.relative(buildRoot, file).split(path.sep).join('/')}`; for (const match of html.matchAll(/]*\bhref="([^"]+)"/gu)) { diff --git a/src/docs/tools/verify-live.mts b/src/docs/tools/verify-live.mts index 1e60d732b..3ea2c550d 100644 --- a/src/docs/tools/verify-live.mts +++ b/src/docs/tools/verify-live.mts @@ -1,8 +1,36 @@ -import { readFile, writeFile } from 'node:fs/promises'; +import { execFileSync } from 'node:child_process'; +import { copyFile, mkdir, readFile, writeFile } from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; import { publishedProducts } from './published-products.mts'; const pageUrl = 'https://oliphaunt.dev/docs/reference/version-matrix/'; type Products = Record; +const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../..'); + +export async function writeNativeDocsInputs( + directory: string, + releasesFile: string, + source: { sourceRevision: string; dirty: boolean }, +) { + if ( + typeof source.sourceRevision !== 'string' || + !/^[a-f0-9]{40}$/.test(source.sourceRevision) || + typeof source.dirty !== 'boolean' + ) + throw new Error('Native docs inputs require actual Git revision and dirty state'); + await mkdir(directory, { recursive: true }); + await copyFile(releasesFile, path.join(directory, 'completed-releases.json')); + await writeFile(path.join(directory, 'provenance.json'), `${JSON.stringify(source, null, 2)}\n`); + await writeFile( + path.join(directory, 'WORKSPACE.bazel'), + 'workspace(name = "docs_build_inputs")\n', + ); + await writeFile( + path.join(directory, 'BUILD.bazel'), + 'exports_files(["completed-releases.json", "provenance.json"], visibility = ["//visibility:public"])\n', + ); +} // Verify what users can read, independently of a deployment provider's job status. export function missingPublishedProducts(html: string, products: Products) { @@ -50,11 +78,30 @@ export async function verifyLive( } if (import.meta.main) { - const [mode, file] = process.argv.slice(2); + const [mode, file, nativeInputs] = process.argv.slice(2); if (!file || !['snapshot', 'verify'].includes(mode)) - throw new Error('usage: verify-live.mts snapshot|verify EXPECTED_PRODUCTS_JSON'); + throw new Error( + 'usage: verify-live.mts snapshot|verify EXPECTED_PRODUCTS_JSON [NATIVE_INPUTS_DIRECTORY]', + ); if (mode === 'snapshot') { await writeFile(file, `${JSON.stringify(await publishedProducts([]), null, 2)}\n`); + if (nativeInputs) { + await writeNativeDocsInputs( + nativeInputs, + path.join(repoRoot, 'target/docs/published-releases.json'), + { + sourceRevision: execFileSync('git', ['rev-parse', 'HEAD'], { + cwd: repoRoot, + encoding: 'utf8', + }).trim(), + dirty: + execFileSync('git', ['status', '--porcelain'], { + cwd: repoRoot, + encoding: 'utf8', + }).trim().length > 0, + }, + ); + } } else { await verifyLive(JSON.parse(await readFile(file, 'utf8'))); console.log('Live documentation advertises the expected completed public releases.'); diff --git a/src/docs/tools/verify-live.test.mts b/src/docs/tools/verify-live.test.mts index 0f8f9c1c8..38c059ab4 100644 --- a/src/docs/tools/verify-live.test.mts +++ b/src/docs/tools/verify-live.test.mts @@ -1,5 +1,31 @@ import { expect, test } from 'bun:test'; -import { missingPublishedProducts, verifyLive } from './verify-live.mts'; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { missingPublishedProducts, verifyLive, writeNativeDocsInputs } from './verify-live.mts'; + +test('native build inputs retain the acquired release bytes and explicit source diagnostic', async () => { + const root = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'docs-input-snapshot-')); + try { + const acquired = path.join(root, 'acquired.json'); + const raw = '[{"tag_name":"sdk-v1.0.0","draft":false,"prerelease":false}]\n'; + writeFileSync(acquired, raw); + const output = path.join(root, 'native'); + const source = { sourceRevision: 'a'.repeat(40), dirty: true }; + await writeNativeDocsInputs(output, acquired, source); + expect(readFileSync(path.join(output, 'completed-releases.json'), 'utf8')).toBe(raw); + expect(JSON.parse(readFileSync(path.join(output, 'provenance.json'), 'utf8'))).toEqual(source); + expect(readFileSync(path.join(output, 'BUILD.bazel'), 'utf8')).toContain( + '"completed-releases.json", "provenance.json"', + ); + await expect( + writeNativeDocsInputs(output, acquired, { ...source, sourceRevision: 'main' }), + ).rejects.toThrow('actual Git revision'); + expect(readFileSync(path.join(output, 'completed-releases.json'), 'utf8')).toBe(raw); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); test('live docs must link the released version, not merely mention it or expose an old release', async () => { const url = 'https://github.com/f0rr0/oliphaunt/releases/tag/sdk-v2.0.0'; diff --git a/src/examples/native/react-native-expo/BUILD.bazel b/src/examples/native/react-native-expo/BUILD.bazel new file mode 100644 index 000000000..9c37f5020 --- /dev/null +++ b/src/examples/native/react-native-expo/BUILD.bazel @@ -0,0 +1,335 @@ +load("//build_defs/android:installed-app.bzl", "expo_android_installed_test") +load("@expo_android_sources//:apple-metadata.bzl", "APPLE_NATIVE") +load("@rules_apple//apple:ios.bzl", "ios_application") +load("@rules_apple//apple:resources.bzl", "apple_resource_bundle") +load("@rules_swift//swift:swift_library.bzl", "swift_library") +load("@rules_cc//cc:objc_library.bzl", "objc_library") +load("//build_defs/apple:app.bzl", "expo_ios_bundle", "expo_ios_project", "ios_project_file", "ios_project_file_name") +load("//build_defs/apple:native.bzl", "react_apple_headers", "react_apple_swift_copts") +load("//build_defs/apple:generated-files.bzl", "IOS_GENERATED_FILES") +load("//build_defs/apple:final-libraries.bzl", "expo_ios_final_libraries") +load("//build_defs/apple:resources.bzl", "expo_ios_resources") +load("//build_defs/resources:resources.bzl", "ios_declared_standard_seed_npm") +load("//build_defs/apple:installed-app.bzl", "expo_ios_installed_test") +load("@oliphaunt_metadata//:metadata.bzl", "EXTENSION_RELEASE_METADATA") +load("@javascript_android_app_packages//:roots.bzl", "CONSUMER_CLOSURES", "CONSUMER_PACKAGES", "CONSUMER_TOOLS") +load("@oliphaunt_javascript_metadata//:metadata.bzl", "JAVASCRIPT") +load("@expo_android_sources//:metadata.bzl", "ANDROID_NATIVE") +load("@oliphaunt_metadata//:metadata.bzl", "COMPLETED_SUPPLIER_ARTIFACTS", "EXTENSIONS", "PREPARED_NATIVE_SELECTED_PRODUCTS", "PRODUCTS") +load("@rules_android//android:rules.bzl", "aar_import", "android_binary", "android_library") +load("@rules_kotlin//kotlin:android.bzl", "kt_android_library") +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_import", "cc_library") +load("//build_defs/android:app.bzl", "android_aar_native", "android_apk_proof", "android_app_runtime_assets", "android_extension_receipt", "android_final_aar", "android_header_tree", "android_jni_aar", "android_workspace_npm", "expo_android_bundle", "expo_android_project", "expo_autolinking_test", "mobile_query_input", "react_native_android_codegen") +load("//build_defs/android:native-cpp.bzl", "REACT_NATIVE_RELEASE_DEFINES") +load("//build_defs/extensions:mobile.bzl", "mobile_extension_registry") +load("//build_defs/extensions:mobile_members.bzl", "MOBILE_MEMBER_LIBRARIES", "MOBILE_MEMBER_TARGETS", "MOBILE_SQL_ONLY_MEMBERS") +load("//build_defs/quality:sources.bzl", "source_quality_files") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["package.json", "app.json"]) + +APP_NAME = "react-native-oliphaunt-expo" +# iOS retains its independent example cohort. Android exercises every supported +# SQL extension, including SQL-only members, in the existing ICU installed app. +SELECTED_EXTENSIONS = ["vector"] +ANDROID_COMPILED_EXTENSIONS = sorted(MOBILE_MEMBER_TARGETS.keys()) +ANDROID_SELECTED_EXTENSIONS = sorted(ANDROID_COMPILED_EXTENSIONS + MOBILE_SQL_ONLY_MEMBERS) +ANDROID_CATALOG_PROFILE = "icu" +ROOTS = CONSUMER_TOOLS[APP_NAME] +PACKAGES = {key: CONSUMER_PACKAGES[key] for key in CONSUMER_CLOSURES[APP_NAME]} +INPUTS = {"@javascript_android_app_packages//:" + key: key for key in PACKAGES} +IDENTITIES = {key: json.encode(row) for key, row in PACKAGES.items()} + +android_workspace_npm(name = "react_native_sdk", archive = "//src/native/sdks/react-native:npm", + package_name = JAVASCRIPT["@oliphaunt/react-native"]["name"], version = JAVASCRIPT["@oliphaunt/react-native"]["version"]) +# This is the canonical owner of the RN manifest's authored npm dependency. +_QUERY_OWNER = "oliphaunt-query-ts" +_QUERY = mobile_query_input(_QUERY_OWNER, + JAVASCRIPT["@oliphaunt/react-native"]["dependencies"]["@oliphaunt/ts-query"], + JAVASCRIPT["@oliphaunt/ts-query"]["version"], PRODUCTS[_QUERY_OWNER]["version"], + PREPARED_NATIVE_SELECTED_PRODUCTS, COMPLETED_SUPPLIER_ARTIFACTS) +android_workspace_npm(name = "query_sdk", archive = _QUERY["archive"], + package_name = _QUERY["metadata"]["package"], version = _QUERY["metadata"]["version"], error = _QUERY.get("error", "")) + +WORKSPACE_INPUTS = {":react_native_sdk": "workspace_react_native", ":query_sdk": "workspace_query"} +WORKSPACE_IDENTITIES = { + "workspace_react_native": json.encode({"package": "@oliphaunt/react-native", "version": JAVASCRIPT["@oliphaunt/react-native"]["version"], "dependencies": {"@oliphaunt/ts-query": "workspace_query"}}), + "workspace_query": json.encode(_QUERY["metadata"]), +} + +filegroup(name = "app_sources", srcs = ["app.json", "package.json", "index.ts", "metro.config.cts"] + glob(["src/**/*.ts", "src/**/*.tsx", "assets/**"])) + +COMMON_INPUTS = { + "sources": {":app_sources": ""}, + "package_inputs": INPUTS, "package_identities": IDENTITIES, "package_roots": ROOTS, + "workspace_inputs": WORKSPACE_INPUTS, "workspace_identities": WORKSPACE_IDENTITIES, + "exec_compatible_with": ["@platforms//os:linux", "@platforms//cpu:x86_64"], +} + +expo_autolinking_test(name = "autolinking_consumer_test", + icu_archive = "//src/database-resources:icu_carriers_npm_files", + sources = {}, package_inputs = INPUTS, package_identities = IDENTITIES, + package_roots = ROOTS, workspace_inputs = WORKSPACE_INPUTS, workspace_identities = WORKSPACE_IDENTITIES) + +expo_android_project(name = "android_project", sources = COMMON_INPUTS["sources"], package_inputs = INPUTS, package_identities = IDENTITIES, + package_roots = ROOTS, workspace_inputs = WORKSPACE_INPUTS, workspace_identities = WORKSPACE_IDENTITIES, + exec_compatible_with = COMMON_INPUTS["exec_compatible_with"]) +expo_android_bundle(name = "android_bundle", sources = COMMON_INPUTS["sources"], package_inputs = INPUTS, package_identities = IDENTITIES, + package_roots = ROOTS, workspace_inputs = WORKSPACE_INPUTS, workspace_identities = WORKSPACE_IDENTITIES, + selected_extensions = ANDROID_SELECTED_EXTENSIONS, catalog_profile = ANDROID_CATALOG_PROFILE, + catalog_profile_probe = "//src/database-resources:contracts/profile-probe.json", + exec_compatible_with = COMMON_INPUTS["exec_compatible_with"]) +react_native_android_codegen( + name = "android_codegen", library_name = "OliphauntReactNativeSpec", + java_package_name = "dev.oliphaunt.reactnative", + specs = ["node_modules/@oliphaunt/react-native/src/specs/NativeOliphaunt.ts"], + sources = COMMON_INPUTS["sources"], package_inputs = INPUTS, package_identities = IDENTITIES, + package_roots = ROOTS, workspace_inputs = WORKSPACE_INPUTS, workspace_identities = WORKSPACE_IDENTITIES, + exec_compatible_with = COMMON_INPUTS["exec_compatible_with"] +) + +react_native_android_codegen( + name = "safe_area_codegen", library_name = "safeareacontext", java_package_name = "com.th3rdwave.safeareacontext", + specs = ["node_modules/react-native-safe-area-context/src/specs"], + sources = COMMON_INPUTS["sources"], package_inputs = INPUTS, package_identities = IDENTITIES, + package_roots = ROOTS, workspace_inputs = WORKSPACE_INPUTS, workspace_identities = WORKSPACE_IDENTITIES, + exec_compatible_with = COMMON_INPUTS["exec_compatible_with"] +) + +[filegroup(name = name, srcs = [target], output_group = group) for name, target, group in [ + ("android_manifest", ":android_project", "manifest"), + ("android_resources", ":android_project", "resources"), + ("android_keystore", ":android_project", "keystore"), + ("android_expo_registry", ":android_project", "expo_registry"), + ("android_expo_assets", ":android_project", "expo_assets"), + ("android_autolinking_cpp", ":android_project", "native_cpp"), + ("android_autolinking_headers", ":android_project", "native_headers"), + ("android_codegen_cpp", ":android_codegen", "cpp"), + ("android_codegen_headers", ":android_codegen", "headers"), + ("safe_area_codegen_cpp", ":safe_area_codegen", "cpp"), + ("safe_area_codegen_headers", ":safe_area_codegen", "headers"), + ("android_bundle_assets", ":android_bundle", "assets"), + ("android_bundle_resources", ":android_bundle", "resources"), +]] +[android_header_tree(name = name, headers = headers, include_suffixes = suffixes) for name, headers, suffixes in [ + ("android_autolinking_includes", ":android_autolinking_headers", [""]), + ("android_codegen_includes", ":android_codegen_headers", ["", "react/renderer/components/OliphauntReactNativeSpec"]), + ("safe_area_codegen_includes", ":safe_area_codegen_headers", ["", "react/renderer/components/safeareacontext"]), +]] + +_ARM64 = "@platforms//cpu:aarch64" +_X64 = "@platforms//cpu:x86_64" +_ABI = select({_ARM64: "arm64-v8a", _X64: "x86_64"}) +_SHARED = ["-static_link_cpp_runtimes"] +_RN_NATIVE = ["@expo_android_sources//:react_native_prefab", "@expo_android_sources//:fbjni", "@expo_android_sources//:shared_cxx_runtime"] +_JNA = ANDROID_NATIVE["reactNativeSdk"]["jna"] +_MIN_SDK = ANDROID_NATIVE["minSdkVersion"] + +android_final_aar(name = "kotlin_final_aar", source = "//src/native/sdks/kotlin:android_maven_archive") +aar_import(name = "kotlin_installed", aar = ":kotlin_final_aar", package = "dev.oliphaunt", deps = [ + "@oliphaunt_kotlin_maven//:net_java_dev_jna_jna", "@oliphaunt_kotlin_maven//:org_jetbrains_annotations", + "@oliphaunt_kotlin_maven//:org_jetbrains_kotlin_kotlin_stdlib", "@oliphaunt_kotlin_maven//:org_jetbrains_kotlinx_kotlinx_coroutines_core_jvm", +]) +[android_final_aar(name = "runtime_" + name + "_aar", source = "//src/native/runtime:android_maven_liboliphaunt_android_" + name, + kind = "runtime", package = "dev.oliphaunt.runtime", abi = abi) for name, abi in [("arm64_v8a", "arm64-v8a"), ("x86_64", "x86_64")]] +android_final_aar(name = "seed_final_aar", source = "//src/database-resources:android_datum64_icu_carriers_maven_files", kind = "seed", package = "dev.oliphaunt.resources", catalog_profile = ANDROID_CATALOG_PROFILE) +aar_import(name = "seed_installed", aar = ":seed_final_aar", package = "dev.oliphaunt.resources") +aar_import(name = "runtime_installed", aar = select({_ARM64: ":runtime_arm64_v8a_aar", _X64: ":runtime_x86_64_aar"}), package = "dev.oliphaunt.runtime") +android_aar_native(name = "runtime_library", aar = select({_ARM64: ":runtime_arm64_v8a_aar", _X64: ":runtime_x86_64_aar"}), abi = _ABI, library = "liboliphaunt.so") +cc_import(name = "runtime_cc", shared_library = ":runtime_library") +cc_library(name = "runtime_headers", hdrs = ["//src/native/runtime:include/oliphaunt.h"], strip_include_prefix = "/src/native/runtime/include") +android_aar_native(name = "jna_library", aar = "@expo_android_jna_maven//:net_java_dev_jna_jna_aar_" + _JNA.replace(".", "_") + "_extension", abi = _ABI, library = "libjnidispatch.so") + +kt_android_library( + name = "oliphaunt_android_classes", + srcs = ["//src/native/sdks/react-native:android_kotlin_sources", ":android_codegen", "@expo_android_sources//:generated/oliphaunt_react_native/BuildConfig.java"], + manifest = "//src/native/sdks/react-native:android/src/main/AndroidManifest.xml", custom_package = "dev.oliphaunt.reactnative", + deps = [":kotlin_installed", "@expo_android_sources//:react_android_release", "@expo_android_maven//:org_jetbrains_kotlinx_kotlinx_coroutines_android"], +) +cc_library(name = "oliphaunt_reactnative_sources", srcs = ["//src/native/sdks/react-native:android_jsi_source"], + hdrs = ["//src/native/sdks/react-native:cpp_headers"], deps = _RN_NATIVE, + copts = ["-std=c++20", "-O2", "-fexceptions", "-frtti"], local_defines = REACT_NATIVE_RELEASE_DEFINES, features = _SHARED, + alwayslink = True, target_compatible_with = ["@platforms//os:android"]) +cc_binary(name = "liboliphauntreactnative.so", deps = [":oliphaunt_reactnative_sources"], features = _SHARED, + linkshared = True, linkstatic = True, linkopts = ["-Wl,-z,defs", "-Wl,-z,max-page-size=16384", "-Wl,-z,common-page-size=16384", "-Wl,-soname,liboliphauntreactnative.so"], + target_compatible_with = ["@platforms//os:android"]) + +# Static registration consumes the actual ABI-specific archive; final proof +# binds its definitions to the same cohort embedded in the Hermes bundle. +_DESCRIPTORS = {row["sql-name"]: row for row in EXTENSIONS.values()} +_MEMBERS = [MOBILE_MEMBER_TARGETS[name] for name in ANDROID_COMPILED_EXTENSIONS] +mobile_extension_registry(name = "selected_registry", members = _MEMBERS, sql_names = ANDROID_COMPILED_EXTENSIONS) +cc_binary(name = "liboliphaunt_extensions.so", srcs = [":selected_registry"], + deps = [":runtime_cc", ":runtime_headers", "@expo_android_sources//:shared_cxx_runtime"] + [MOBILE_MEMBER_LIBRARIES[name] for name in ANDROID_COMPILED_EXTENSIONS], + features = _SHARED, linkshared = True, linkstatic = True, + linkopts = ["-Wl,-z,defs", "-Wl,-z,max-page-size=16384", "-Wl,-z,common-page-size=16384", "-Wl,-soname,liboliphaunt_extensions.so"], target_compatible_with = ["@platforms//os:android"]) +android_extension_receipt(name = "extension_receipt", library = ":liboliphaunt_extensions.so", registry = ":selected_registry", members = _MEMBERS, selected_extensions = ANDROID_SELECTED_EXTENSIONS, abi = _ABI) +android_app_runtime_assets(name = "selected_runtime_assets", receipt = ":extension_receipt", selected_extensions = ANDROID_SELECTED_EXTENSIONS, + mobile_static_modules = [_DESCRIPTORS[name]["native-module-file"][:-3] for name in ANDROID_COMPILED_EXTENSIONS], icu = "//src/database-resources:icu_payload", version = PRODUCTS["liboliphaunt-native"]["version"], abi = _ABI, + leaves = select({_ARM64: ["//build_defs/extensions/mobile/final:" + product.replace("-", "_") + "_android_arm64_v8a" for product in sorted({row["artifactProduct"]: True for row in EXTENSION_RELEASE_METADATA if row["sqlName"] in ANDROID_SELECTED_EXTENSIONS}.keys())], + _X64: ["//build_defs/extensions/mobile/final:" + product.replace("-", "_") + "_android_x86_64" for product in sorted({row["artifactProduct"]: True for row in EXTENSION_RELEASE_METADATA if row["sqlName"] in ANDROID_SELECTED_EXTENSIONS}.keys())]})) + +_LIBRARIES = { + ":liboliphauntreactnative.so": "liboliphauntreactnative.so", ":liboliphaunt_extensions.so": "liboliphaunt_extensions.so", + ":jna_library": "libjnidispatch.so", "@expo_android_sources//:libexpo-modules-core.so": "libexpo-modules-core.so", + "@expo_android_sources//:libreact_codegen_safeareacontext.so": "libreact_codegen_safeareacontext.so", "@expo_android_sources//:libappmodules.so": "libappmodules.so", +} +android_jni_aar(name = "source_jni_aar", package = "dev.oliphaunt.reactnative.jni", + libraries = select({_ARM64: {target: "jni/arm64-v8a/" + name for target, name in _LIBRARIES.items()}, _X64: {target: "jni/x86_64/" + name for target, name in _LIBRARIES.items()}})) +aar_import(name = "source_jni", aar = ":source_jni_aar", package = "dev.oliphaunt.reactnative.jni") + +android_library(name = "bundle_assets", manifest = ":android_manifest", custom_package = "dev.oliphaunt.reactnative.example", assets = [":android_bundle_assets"], assets_dir = "android_bundle/assets") +android_library(name = "expo_config_assets", manifest = ":android_manifest", custom_package = "dev.oliphaunt.reactnative.example", assets = [":android_expo_assets"], assets_dir = "android_project/expo-assets") +android_library(name = "runtime_assets", manifest = ":android_manifest", custom_package = "dev.oliphaunt.reactnative.example", assets = [":selected_runtime_assets"], assets_dir = "selected_runtime_assets/assets") +kt_android_library(name = "app_release_classes", srcs = [":android_project", ":android_expo_registry"], manifest = ":android_manifest", + custom_package = "dev.oliphaunt.reactnative.example", resource_files = [":android_resources", ":android_bundle_resources"], + deps = [":oliphaunt_android_classes", "@expo_android_sources//:expo_modules", "@expo_android_sources//:react_android_release"]) +android_binary(name = "release_binary", manifest = ":android_manifest", custom_package = "dev.oliphaunt.reactnative.example", + resource_files = [":android_resources", ":android_bundle_resources"], + manifest_values = {"applicationId": "dev.oliphaunt.reactnative.example", "minSdkVersion": str(_MIN_SDK), "targetSdkVersion": "36", "versionCode": "1", "versionName": "0.0.0"}, + deps = [":app_release_classes", ":bundle_assets", ":expo_config_assets", ":runtime_assets", ":seed_installed", ":runtime_installed", ":source_jni", "@expo_android_maven//:com_facebook_hermes_hermes_android_release"], + multidex = "native", incremental_dexing = 0, nocompress_extensions = ["so", "bundle"]) +[android_apk_proof(name = name, apk = ":release_binary", abi = abi, keystore = ":android_keystore", selected_extensions = ANDROID_SELECTED_EXTENSIONS, + catalog_profile = ANDROID_CATALOG_PROFILE, catalog_profile_probe = "//src/database-resources:contracts/profile-probe.json", + min_sdk_version = _MIN_SDK, + expected_classes = ["dev.oliphaunt.reactnative.example.MainApplication", "dev.oliphaunt.reactnative.example.MainActivity", "expo.modules.splashscreen.SplashScreenModule", "expo.modules.sqlite.SQLiteModule", "com.th3rdwave.safeareacontext.SafeAreaContextPackage", "com.facebook.soloader.SoLoader", "com.facebook.drawee.backends.pipeline.Fresco"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"]) + for name, abi in [("android_release", "arm64-v8a"), ("android_release_x86_64", "x86_64")]] + +source_quality_files() + +# Merge into the existing Expo example BUILD after the shared npm inputs. + +expo_ios_project( + name = "ios_project", target_name = "reactnativeoliphauntexpo", + expected_modules = APPLE_NATIVE["expectedModules"], + swift_sdk_version = APPLE_NATIVE["swiftSdkVersion"], + sources = COMMON_INPUTS["sources"], package_inputs = INPUTS, package_identities = IDENTITIES, + package_roots = ROOTS, workspace_inputs = WORKSPACE_INPUTS, workspace_identities = WORKSPACE_IDENTITIES, +) +expo_ios_bundle( + name = "ios_bundle", sources = COMMON_INPUTS["sources"], + selected_extensions = SELECTED_EXTENSIONS, catalog_profile = "standard", + package_inputs = INPUTS, package_identities = IDENTITIES, package_roots = ROOTS, + workspace_inputs = WORKSPACE_INPUTS, workspace_identities = WORKSPACE_IDENTITIES, +) +[ios_project_file(name = ios_project_file_name(relative), project = ":ios_project", path = relative) for relative in IOS_GENERATED_FILES] +_IOS = {relative: ":" + ios_project_file_name(relative) for relative in IOS_GENERATED_FILES} +react_apple_headers( + name = "ios_react_headers", + react = "@react_native_apple_release//:React", + template = "@react_native_apple_release//:React.xcframework/React-VFS-template.yaml", + hermes_header = "@react_native_apple_release//:destroot/include/hermes/hermes.h", + dependencies_header = "@react_native_apple_release//:packages/react-native/third-party/ReactNativeDependencies.xcframework/Headers/folly/Traits.h", + headers = ["@react_native_apple_release//:hermes_headers", "@react_native_apple_release//:dependency_headers"], + swift_bridging = "@native_apple_sdk//:toolchain/include/swift/bridging", + swift_headers = ["@native_apple_sdk//:swift_interop_headers"], +) +filegroup(name = "ios_react_jsi_header", srcs = [":ios_react_headers"], output_group = "jsi_header") +filegroup(name = "ios_react_module_map", srcs = [":ios_react_headers"], output_group = "module_map") +_IOS_REACT = ["@react_native_apple_release//:React", ":ios_react_headers"] +_IOS_SWIFT = ["-swift-version", "5"] + react_apple_swift_copts(":ios_react_headers") +_CODEGEN = [relative for relative in IOS_GENERATED_FILES if relative.startswith("codegen/ReactCodegen/")] + +objc_library( + name = "ios_ReactCodegen", + srcs = [_IOS[relative] for relative in _CODEGEN if relative.endswith(".mm") or relative.endswith(".cpp")], + hdrs = [_IOS[relative] for relative in _CODEGEN if relative.endswith(".h")], + includes = ["ios_project/codegen", "ios_project/codegen/ReactCodegen"], deps = _IOS_REACT, + defines = ["RCT_NEW_ARCH_ENABLED=1"], alwayslink = True, + copts = ["-ivfsoverlay", "$(location :ios_react_headers)"], data = [":ios_react_headers"], +) +objc_library( + name = "ios_ReactAppDependencyProvider", + srcs = [_IOS["codegen/ReactAppDependencyProvider/RCTAppDependencyProvider.mm"]], + hdrs = [_IOS["codegen/ReactAppDependencyProvider/RCTAppDependencyProvider.h"]], + includes = ["ios_project/codegen/ReactAppDependencyProvider"], + deps = [":ios_ReactCodegen"] + _IOS_REACT, + enable_modules = True, module_name = "ReactAppDependencyProvider", alwayslink = True, + copts = ["-ivfsoverlay", "$(location :ios_react_headers)"], data = [":ios_react_headers"], +) +# Actual SDK Swift adapters link the declared held Swift package. The Objective-C +# facade uses the shipped manual interface, so it does not import its own Swift header. +swift_library( + name = "ios_RNAdapter", module_name = "OliphauntReactNative", + srcs = [_IOS["sdk/ios/OliphauntAdapter.swift"]], + hdrs = [_IOS["sdk/ios/OliphauntAdapter.h"]], + deps = ["@react_native_swift_package//:Oliphaunt"], copts = ["-swift-version", "6"], + alwayslink = True, +) +objc_library( + name = "ios_RNFacade", + srcs = [_IOS["sdk/ios/Oliphaunt.mm"], _IOS["sdk/ios/OliphauntReactNative.h"], _IOS["sdk/ios/OliphauntAdapter.h"], + _IOS["sdk/cpp/Jsi.h"], _IOS["sdk/cpp/Lifecycle.h"]], + deps = [":ios_RNAdapter", ":ios_ReactCodegen"] + _IOS_REACT, + defines = ["RCT_NEW_ARCH_ENABLED=1"], alwayslink = True, + copts = ["-ivfsoverlay", "$(location :ios_react_headers)"], data = [":ios_react_headers"], +) +swift_library( + name = "ios_AppDelegate", module_name = "reactnativeoliphauntexpo", + # Expo discovers the generated provider through the application's Swift module. + srcs = [_IOS["app/AppDelegate.swift"], _IOS["ExpoModulesProvider.swift"]], + deps = [":ios_ReactAppDependencyProvider"] + + ["@expo_android_sources//:" + row["module"] for row in APPLE_NATIVE["modules"]] + + ["@expo_android_sources//:" + row["module"] for row in APPLE_NATIVE["frameworks"]] + _IOS_REACT, + copts = _IOS_SWIFT, swiftc_inputs = [":ios_react_headers"], +) +filegroup(name = "ios_constants_config", srcs = [":ios_project"], output_group = "constants") +filegroup(name = "ios_bundle_assets", srcs = [":ios_bundle"], output_group = "resources") + +# This is the same selected member as the previous mandatory mobile example. +IOS_FINAL_LEAVES = expo_ios_final_libraries(name = "ios_final_libraries", extensions = SELECTED_EXTENSIONS, base = "@react_native_swift_package//:native_requirement") +ios_declared_standard_seed_npm(name = "ios_standard_seed_npm") +expo_ios_resources(name = "ios_selected_resources", base = "@react_native_swift_package//:native_requirement", + seed = ":ios_standard_seed_npm", + leaves = IOS_FINAL_LEAVES, extensions = SELECTED_EXTENSIONS) +filegroup(name = "ios_selected_registry", srcs = [":ios_selected_resources"], output_group = "registry") +apple_resource_bundle(name = "ios_selected_runtime_resources", bundle_name = "OliphauntReactNativeResources", + structured_resources = [":ios_selected_resources"], + strip_structured_resources_prefixes = ["ios_selected_resources"]) +filegroup(name = "ios_standard_seed_files", srcs = [":ios_selected_resources"], output_group = "seed") +apple_resource_bundle(name = "ios_standard_seed", bundle_name = "OliphauntSeedNativeIOSStandard", + structured_resources = [":ios_standard_seed_files"], + strip_structured_resources_prefixes = ["ios_selected_resources"]) +cc_library(name = "ios_selected_extensions", srcs = [":ios_selected_registry"], alwayslink = True, + linkopts = ["-Wl,-u,_liboliphaunt_selected_static_extensions"], + deps = ["@react_native_native_base//:runtime", "@react_native_native_base//:runtime_headers"] + [":ios_final_libraries"]) + +ios_application( + name = "ios_release", bundle_name = "reactnativeoliphauntexpo", + tags = ["no-remote"], + bundle_id = "dev.oliphaunt.reactnative.example", families = ["iphone"], + minimum_os_version = "17.0", + frameworks = ["@expo_android_sources//:ExpoModulesJSI"], + infoplists = [_IOS["app/Info.plist"]], + entitlements = _IOS["app/reactnativeoliphauntexpo.entitlements"], + app_icons = [_IOS[relative] for relative in IOS_GENERATED_FILES if "/expo.icon/" in relative], + resources = [_IOS[relative] for relative in IOS_GENERATED_FILES if "/Images.xcassets/" in relative and "/AppIcon.appiconset/" not in relative] + + [_IOS["app/SplashScreen.storyboard"], _IOS["app/Supporting/Expo.plist"], ":ios_bundle", ":ios_bundle_assets"], + deps = [ + ":ios_AppDelegate", ":ios_RNFacade", ":ios_selected_extensions", + "@expo_android_sources//:SafeAreaContext", "@expo_android_sources//:EXConstants_config", + ":ios_selected_runtime_resources", ":ios_standard_seed", + ] + ["@expo_android_sources//:" + row["module"] + "_privacy" for row in APPLE_NATIVE["modules"] + APPLE_NATIVE["frameworks"] if row["privacy"]], +) + +expo_ios_installed_test( + name = "ios_installed_test", application = ":ios_release", + sdk = "//src/native/sdks/react-native:npm", extensions = SELECTED_EXTENSIONS, + helpers = ["//src/native/sdks/react-native:mobile_ios_e2e_sources", + "//src/native/runtime:mobile_e2e_sources", "//src/extensions/generated/sdk:metadata", + "//:src/extensions/generated/mobile/static-registry.json", + "//src/database-resources:contracts/profile-probe.json"], +) + +# Install the exact final verified/re-signed File already requested by this job. +filegroup(name = "android_installed_apk", srcs = [":android_release_x86_64"], output_group = "apk") +filegroup(name = "android_installed_apk_proof", srcs = [":android_release_x86_64"], output_group = "proof") +expo_android_installed_test( + name = "android_installed_test", apk = ":android_installed_apk", proof = ":android_installed_apk_proof", + sdk = "//src/native/sdks/react-native:npm", extensions = ANDROID_SELECTED_EXTENSIONS, + helpers = ["//src/native/sdks/react-native:mobile_android_e2e_sources", "//src/native/runtime:mobile_e2e_sources", + "//src/extensions/generated/sdk:metadata", "//:src/extensions/generated/mobile/static-registry.json", + "//src/database-resources:contracts/profile-probe.json"], +) diff --git a/src/examples/native/react-native-expo/app.json b/src/examples/native/react-native-expo/app.json index f974da6c3..6a6f8de24 100644 --- a/src/examples/native/react-native-expo/app.json +++ b/src/examples/native/react-native-expo/app.json @@ -45,7 +45,8 @@ "expo-sqlite" ], "experiments": { - "reactCompiler": true + "reactCompiler": true, + "autolinkingModuleResolution": true } } } diff --git a/src/examples/native/react-native-expo/src/SmokeDashboard.tsx b/src/examples/native/react-native-expo/src/SmokeDashboard.tsx index 234588110..3a6b2d2f8 100644 --- a/src/examples/native/react-native-expo/src/SmokeDashboard.tsx +++ b/src/examples/native/react-native-expo/src/SmokeDashboard.tsx @@ -32,6 +32,7 @@ import { Platform, Pressable, ScrollView, + Settings, StyleSheet, Text, View, @@ -235,6 +236,7 @@ export default function HomeScreen() { extensionCatalogSha256: GENERATED_MOBILE_EXTENSION_METADATA_SHA256, catalogProfile: profileProof.catalogProfile, icuRuntimeProof: profileProof.catalogProfile === 'icu', + lifecycleResume: lifecycle !== undefined, }); setReport(nextReport); (globalThis as Record).__OLIPHAUNT_EXPO_SMOKE_REPORT__ = nextReport; @@ -611,7 +613,7 @@ function waitForBackgroundAndForeground( const subscription = AppState.addEventListener('change', (nextState) => { states.push(nextState); stage('lifecycle:state', { state: nextState }); - if (nextState === 'background' || nextState === 'inactive') { + if (nextState === 'background') { sawBackground = true; return; } @@ -1048,12 +1050,19 @@ async function resolveBenchmarkPreset(): Promise { } function resolveInitialLaunchUrl(): Promise { - initialLaunchUrlPromise ??= Promise.race([ - Linking.getInitialURL().catch(() => null), - new Promise((resolve) => { - setTimeout(() => resolve(null), initialUrlTimeoutMs); - }), - ]); + if (!initialLaunchUrlPromise) { + // Direct simulator launches pass configuration through iOS's argument domain. + const launchUrl = Platform.OS === 'ios' ? Settings.get('liboliphauntLaunchURL') : undefined; + initialLaunchUrlPromise = + typeof launchUrl === 'string' && launchUrl.length > 0 + ? Promise.resolve(launchUrl) + : Promise.race([ + Linking.getInitialURL().catch(() => null), + new Promise((resolve) => { + setTimeout(() => resolve(null), initialUrlTimeoutMs); + }), + ]); + } return initialLaunchUrlPromise; } diff --git a/src/examples/native/react-native-expo/src/generated/extension-smoke.ts b/src/examples/native/react-native-expo/src/generated/extension-smoke.ts index 08d274371..28f10745f 100644 --- a/src/examples/native/react-native-expo/src/generated/extension-smoke.ts +++ b/src/examples/native/react-native-expo/src/generated/extension-smoke.ts @@ -222,58 +222,60 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = { "CREATE TEMP TABLE oliphaunt_bloom (id int, value int);", "CREATE INDEX oliphaunt_bloom_idx ON oliphaunt_bloom USING bloom (id, value);", "INSERT INTO oliphaunt_bloom SELECT i, i % 3 FROM generate_series(1, 20) AS i;", - "DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_bloom WHERE id = 7 AND value = 1; IF n <> 1 THEN RAISE EXCEPTION 'bloom lookup failed: %', n; END IF; END $$;" + "DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_bloom WHERE id = 7 AND value = 1; IF n IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'bloom lookup failed: %', n; END IF; END $$;" ], "btree_gin": [ "CREATE TEMP TABLE oliphaunt_btree_gin (id int);", "CREATE INDEX oliphaunt_btree_gin_idx ON oliphaunt_btree_gin USING gin (id);", "INSERT INTO oliphaunt_btree_gin SELECT generate_series(1, 10);", - "DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_btree_gin WHERE id = 5; IF n <> 1 THEN RAISE EXCEPTION 'btree_gin lookup failed: %', n; END IF; END $$;" + "DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_btree_gin WHERE id = 5; IF n IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'btree_gin lookup failed: %', n; END IF; END $$;" ], "btree_gist": [ "CREATE TEMP TABLE oliphaunt_btree_gist (id int);", "CREATE INDEX oliphaunt_btree_gist_idx ON oliphaunt_btree_gist USING gist (id);", "INSERT INTO oliphaunt_btree_gist SELECT generate_series(1, 10);", - "DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_btree_gist WHERE id = 5; IF n <> 1 THEN RAISE EXCEPTION 'btree_gist lookup failed: %', n; END IF; END $$;" + "DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_btree_gist WHERE id = 5; IF n IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'btree_gist lookup failed: %', n; END IF; END $$;" ], "citext": [ "CREATE TEMP TABLE oliphaunt_citext (value citext);", "INSERT INTO oliphaunt_citext VALUES ('Postgres');", - "DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_citext WHERE value = 'postgres'; IF n <> 1 THEN RAISE EXCEPTION 'citext comparison failed: %', n; END IF; END $$;" + "DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_citext WHERE value = 'postgres'; IF n IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'citext comparison failed: %', n; END IF; END $$;" ], "cube": [ - "DO $$ DECLARE d float8; BEGIN SELECT cube(array[1,2,3]) <-> cube(array[1,2,4]) INTO d; IF d <> 1 THEN RAISE EXCEPTION 'cube distance failed: %', d; END IF; END $$;" + "DO $$ DECLARE d float8; BEGIN SELECT cube(array[1,2,3]) <-> cube(array[1,2,4]) INTO d; IF d IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'cube distance failed: %', d; END IF; END $$;" ], "dict_int": [ - "DO $$ DECLARE lex text; BEGIN SELECT array_to_string(ts_lexize('intdict', '40865854'), ',') INTO lex; IF lex <> '408658' THEN RAISE EXCEPTION 'dict_int lexize failed: %', lex; END IF; END $$;" + "DO $$ DECLARE lex text; BEGIN SELECT array_to_string(ts_lexize('intdict', '40865854'), ',') INTO lex; IF lex IS DISTINCT FROM '408658' THEN RAISE EXCEPTION 'dict_int lexize failed: %', lex; END IF; END $$;" ], "dict_xsyn": [ "ALTER TEXT SEARCH DICTIONARY xsyn (RULES = 'xsyn_sample', KEEPORIG = true, MATCHORIG = true, KEEPSYNONYMS = true, MATCHSYNONYMS = false);", "DO $$ DECLARE lex text; BEGIN SELECT array_to_string(ts_lexize('xsyn', 'supernova'), ',') INTO lex; IF lex IS NULL OR lex !~ 'sn' THEN RAISE EXCEPTION 'dict_xsyn lexize failed: %', lex; END IF; END $$;" ], "earthdistance": [ - "DO $$ DECLARE d float8; BEGIN SELECT earth_distance(ll_to_earth(0, 0), ll_to_earth(0, 1)) INTO d; IF d <= 0 THEN RAISE EXCEPTION 'earthdistance failed: %', d; END IF; END $$;" + "DO $$ DECLARE d float8; BEGIN SELECT earth_distance(ll_to_earth(0, 0), ll_to_earth(0, 1)) INTO d; IF d IS NULL OR d <= 0 THEN RAISE EXCEPTION 'earthdistance failed: %', d; END IF; END $$;" ], "file_fdw": [ + "DROP FOREIGN TABLE IF EXISTS oliphaunt_file_version_probe;", "DROP SERVER IF EXISTS oliphaunt_file_server;", "CREATE SERVER oliphaunt_file_server FOREIGN DATA WRAPPER file_fdw;", - "-- oliphaunt-verify\nDO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_foreign_server WHERE srvname = 'oliphaunt_file_server') THEN RAISE EXCEPTION 'file_fdw server missing'; END IF; END $$;" + "DO $$\nBEGIN\n EXECUTE format(\n 'CREATE FOREIGN TABLE oliphaunt_file_version_probe(version integer) SERVER oliphaunt_file_server OPTIONS (filename %L, format %L)',\n current_setting('data_directory') || '/PG_VERSION', 'text'\n );\nEND\n$$;", + "-- oliphaunt-verify\nDO $$\nDECLARE\n file_rows bigint;\n postgres_major integer;\nBEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_foreign_server WHERE srvname = 'oliphaunt_file_server') THEN\n RAISE EXCEPTION 'file_fdw server missing';\n END IF;\n EXECUTE format(\n 'ALTER FOREIGN TABLE oliphaunt_file_version_probe OPTIONS (SET filename %L)',\n current_setting('data_directory') || '/PG_VERSION'\n );\n SELECT count(*), min(version) INTO file_rows, postgres_major FROM oliphaunt_file_version_probe;\n IF file_rows IS DISTINCT FROM 1::bigint OR postgres_major IS DISTINCT FROM 18 THEN\n RAISE EXCEPTION 'file_fdw did not read the expected database version: rows %, version %', file_rows, postgres_major;\n END IF;\nEND\n$$;" ], "fuzzystrmatch": [ - "DO $$ BEGIN IF levenshtein('kitten', 'sitting') <> 3 THEN RAISE EXCEPTION 'levenshtein failed'; END IF; IF soundex('kitten') <> 'K350' THEN RAISE EXCEPTION 'soundex failed'; END IF; END $$;" + "DO $$ BEGIN IF levenshtein('kitten', 'sitting') IS DISTINCT FROM 3 THEN RAISE EXCEPTION 'levenshtein failed'; END IF; IF soundex('kitten') IS DISTINCT FROM 'K350' THEN RAISE EXCEPTION 'soundex failed'; END IF; END $$;" ], "hstore": [ "CREATE TEMP TABLE oliphaunt_hstore (attrs hstore);", "INSERT INTO oliphaunt_hstore VALUES ('a=>1,b=>2'::hstore);", - "DO $$ DECLARE v text; BEGIN SELECT attrs -> 'b' INTO v FROM oliphaunt_hstore; IF v <> '2' THEN RAISE EXCEPTION 'hstore lookup failed: %', v; END IF; END $$;" + "DO $$ DECLARE v text; BEGIN SELECT attrs -> 'b' INTO v FROM oliphaunt_hstore; IF v IS DISTINCT FROM '2' THEN RAISE EXCEPTION 'hstore lookup failed: %', v; END IF; END $$;" ], "intarray": [ "CREATE TEMP TABLE oliphaunt_intarray (tags int[]);", "INSERT INTO oliphaunt_intarray VALUES (ARRAY[1, 2, 5]), (ARRAY[3, 4]);", - "DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_intarray WHERE tags && ARRAY[2, 9]; IF n <> 1 THEN RAISE EXCEPTION 'intarray overlap failed: %', n; END IF; SELECT count(*) INTO n FROM oliphaunt_intarray WHERE tags @@ '1 & (2|3)'::query_int; IF n <> 1 THEN RAISE EXCEPTION 'intarray query_int failed: %', n; END IF; END $$;" + "DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_intarray WHERE tags && ARRAY[2, 9]; IF n IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'intarray overlap failed: %', n; END IF; SELECT count(*) INTO n FROM oliphaunt_intarray WHERE tags @@ '1 & (2|3)'::query_int; IF n IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'intarray query_int failed: %', n; END IF; END $$;" ], "isn": [ - "DO $$ BEGIN IF isbn('978-0-393-04002-9')::text <> '0-393-04002-X' THEN RAISE EXCEPTION 'isbn failed'; END IF; IF isbn13('0901690546')::text <> '978-0-901690-54-8' THEN RAISE EXCEPTION 'isbn13 failed'; END IF; IF issn('1436-4522')::text <> '1436-4522' THEN RAISE EXCEPTION 'issn failed'; END IF; END $$;" + "DO $$ BEGIN IF isbn('978-0-393-04002-9')::text IS DISTINCT FROM '0-393-04002-X' THEN RAISE EXCEPTION 'isbn failed'; END IF; IF isbn13('0901690546')::text IS DISTINCT FROM '978-0-901690-54-8' THEN RAISE EXCEPTION 'isbn13 failed'; END IF; IF issn('1436-4522')::text IS DISTINCT FROM '1436-4522' THEN RAISE EXCEPTION 'issn failed'; END IF; END $$;" ], "lo": [ "CREATE TEMP TABLE oliphaunt_lo (id int, data oid);", @@ -283,7 +285,7 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = { "ltree": [ "CREATE TEMP TABLE oliphaunt_ltree (path ltree);", "INSERT INTO oliphaunt_ltree VALUES ('Top.Science.Astronomy'), ('Top.Collections.Pictures');", - "DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_ltree WHERE path <@ 'Top.Science'; IF n <> 1 THEN RAISE EXCEPTION 'ltree ancestor query failed: %', n; END IF; END $$;" + "DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_ltree WHERE path <@ 'Top.Science'; IF n IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'ltree ancestor query failed: %', n; END IF; END $$;" ], "pageinspect": [ "CREATE TEMP TABLE oliphaunt_pageinspect (id int);", @@ -301,7 +303,7 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = { "SELECT * FROM pg_freespace('oliphaunt_fsm') LIMIT 1;" ], "pg_hashids": [ - "DO $$ BEGIN IF id_encode(1001) <> 'jNl' THEN RAISE EXCEPTION 'pg_hashids encode failed'; END IF; IF id_decode_once('jNl') <> 1001 THEN RAISE EXCEPTION 'pg_hashids decode failed'; END IF; END $$;" + "DO $$ BEGIN IF id_encode(1001) IS DISTINCT FROM 'jNl' THEN RAISE EXCEPTION 'pg_hashids encode failed'; END IF; IF id_decode_once('jNl') IS DISTINCT FROM 1001 THEN RAISE EXCEPTION 'pg_hashids decode failed'; END IF; END $$;" ], "pg_ivm": [ "DROP TABLE IF EXISTS oliphaunt_ivm_summary;", @@ -309,10 +311,13 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = { "CREATE TABLE oliphaunt_ivm_orders (id int, amount int);", "INSERT INTO oliphaunt_ivm_orders VALUES (1, 10), (2, 20);", "SELECT pgivm.create_immv('oliphaunt_ivm_summary', $$ SELECT id, amount FROM oliphaunt_ivm_orders $$);", - "-- oliphaunt-verify\nDO $$\nDECLARE n int;\nBEGIN\n SELECT count(*) INTO n FROM oliphaunt_ivm_summary;\n IF n <> 2 THEN RAISE EXCEPTION 'pg_ivm count failed: %', n; END IF;\n UPDATE oliphaunt_ivm_orders SET amount = 11 WHERE id = 1;\n SELECT amount INTO n FROM oliphaunt_ivm_summary WHERE id = 1;\n IF n IS DISTINCT FROM 11 THEN RAISE EXCEPTION 'pg_ivm maintenance failed: %', n; END IF;\n UPDATE oliphaunt_ivm_orders SET amount = 10 WHERE id = 1;\nEND $$;" + "-- oliphaunt-verify\nDO $$\nDECLARE n int;\nBEGIN\n SELECT count(*) INTO n FROM oliphaunt_ivm_summary;\n IF n IS DISTINCT FROM 2 THEN RAISE EXCEPTION 'pg_ivm count failed: %', n; END IF;\n UPDATE oliphaunt_ivm_orders SET amount = 11 WHERE id = 1;\n SELECT amount INTO n FROM oliphaunt_ivm_summary WHERE id = 1;\n IF n IS DISTINCT FROM 11 THEN RAISE EXCEPTION 'pg_ivm maintenance failed: %', n; END IF;\n UPDATE oliphaunt_ivm_orders SET amount = 10 WHERE id = 1;\nEND $$;" ], "pg_surgery": [ - "DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'heap_force_kill') THEN RAISE EXCEPTION 'pg_surgery function missing'; END IF; END $$;" + "DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'heap_force_kill') THEN RAISE EXCEPTION 'pg_surgery function missing'; END IF; END $$;", + "CREATE TEMP TABLE oliphaunt_pg_surgery_probe(value integer);", + "INSERT INTO oliphaunt_pg_surgery_probe VALUES (1), (2);", + "DO $$\nDECLARE\n target_tid tid;\nBEGIN\n SELECT ctid INTO STRICT target_tid FROM oliphaunt_pg_surgery_probe WHERE value = 1;\n PERFORM heap_force_freeze('oliphaunt_pg_surgery_probe'::regclass, ARRAY[target_tid]::tid[]);\n IF (SELECT xmin::text FROM oliphaunt_pg_surgery_probe WHERE value = 1) IS DISTINCT FROM '2' THEN\n RAISE EXCEPTION 'pg_surgery did not freeze the temporary tuple';\n END IF;\n PERFORM heap_force_kill('oliphaunt_pg_surgery_probe'::regclass, ARRAY[target_tid]::tid[]);\n IF (SELECT count(*) FROM oliphaunt_pg_surgery_probe) IS DISTINCT FROM 1::bigint\n OR (SELECT sum(value) FROM oliphaunt_pg_surgery_probe) IS DISTINCT FROM 2::bigint THEN\n RAISE EXCEPTION 'pg_surgery did not retain only the expected temporary tuple';\n END IF;\nEND\n$$;" ], "pg_textsearch": [ "-- A nonempty English index must resolve PostgreSQL's Snowball runtime-support\n-- module and stopword data. An empty index does not load the dictionary and\n-- therefore cannot prove the packaged runtime closure.\nDROP TABLE IF EXISTS oliphaunt_pg_textsearch_english;", @@ -327,10 +332,10 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = { "-- oliphaunt-verify\nDO $oliphaunt$\nDECLARE\n hit bigint;\n probe record;\nBEGIN\n SELECT id\n INTO hit\n FROM oliphaunt_pg_textsearch_english\n ORDER BY body <@> to_bm25query(\n 'running database',\n 'oliphaunt_pg_textsearch_english_bm25'\n )\n LIMIT 1;\n IF hit IS DISTINCT FROM 1 THEN\n RAISE EXCEPTION 'pg_textsearch English BM25 smoke returned id %, expected 1', hit;\n END IF;\n IF (SELECT count(*) FROM oliphaunt_pg_textsearch_english) <> 6 THEN\n RAISE EXCEPTION 'pg_textsearch mutation changed the expected row count';\n END IF;\n FOR probe IN SELECT * FROM (VALUES\n ('mutationproof', 2), ('legacyalpha', 3), ('legacybeta', 5),\n ('deletionproof', 6), ('freshposting', 7)\n ) AS expected(term, id)\n LOOP\n SELECT id INTO hit\n FROM oliphaunt_pg_textsearch_english\n ORDER BY body <@> to_bm25query(probe.term, 'oliphaunt_pg_textsearch_english_bm25')\n LIMIT 1;\n IF hit IS DISTINCT FROM probe.id THEN\n RAISE EXCEPTION 'pg_textsearch query % returned id %, expected %', probe.term, hit, probe.id;\n END IF;\n END LOOP;\n -- This also runs after restart and restore, before recreating any index.\n INSERT INTO oliphaunt_pg_textsearch_english VALUES (8, 'reopenproof reopenproof fresh write');\n PERFORM bm25_force_merge('oliphaunt_pg_textsearch_english_bm25');\n SELECT id INTO hit\n FROM oliphaunt_pg_textsearch_english\n ORDER BY body <@> to_bm25query('reopenproof', 'oliphaunt_pg_textsearch_english_bm25')\n LIMIT 1;\n IF hit IS DISTINCT FROM 8 THEN\n RAISE EXCEPTION 'pg_textsearch fresh write returned id %, expected 8', hit;\n END IF;\n DELETE FROM oliphaunt_pg_textsearch_english WHERE id = 8;\nEND\n$oliphaunt$;" ], "pg_trgm": [ - "DO $$ DECLARE score float8; BEGIN SELECT similarity('postgres', 'postgrex') INTO score; IF score <= 0 THEN RAISE EXCEPTION 'pg_trgm similarity failed: %', score; END IF; END $$;" + "DO $$ DECLARE score float8; BEGIN SELECT similarity('postgres', 'postgrex') INTO score; IF score IS NULL OR score <= 0 THEN RAISE EXCEPTION 'pg_trgm similarity failed: %', score; END IF; END $$;" ], "pg_uuidv7": [ - "DO $$ DECLARE id uuid; ts timestamptz; BEGIN SELECT uuid_generate_v7() INTO id; IF length(id::text) <> 36 THEN RAISE EXCEPTION 'uuidv7 length failed'; END IF; SELECT uuid_v7_to_timestamptz('018570bb-4a7d-7c7e-8df4-6d47afd8c8fc') INTO ts; IF ts IS NULL THEN RAISE EXCEPTION 'uuidv7 timestamp failed'; END IF; END $$;" + "DO $$ DECLARE id uuid; ts timestamptz; BEGIN SELECT uuid_generate_v7() INTO id; IF length(id::text) IS DISTINCT FROM 36 THEN RAISE EXCEPTION 'uuidv7 length failed'; END IF; SELECT uuid_v7_to_timestamptz('018570bb-4a7d-7c7e-8df4-6d47afd8c8fc') INTO ts; IF ts IS NULL THEN RAISE EXCEPTION 'uuidv7 timestamp failed'; END IF; END $$;" ], "pg_visibility": [ "CREATE TEMP TABLE oliphaunt_visibility (id int);", @@ -345,10 +350,10 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = { "SELECT * FROM pg_get_wal_block_info((SELECT before_lsn FROM oliphaunt_walinspect_lsn), pg_current_wal_lsn()) ORDER BY start_lsn, block_id LIMIT 20;" ], "pgcrypto": [ - "DO $$ DECLARE hashed text; encrypted bytea; BEGIN IF encode(digest('abc', 'sha256'), 'hex') <> 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad' THEN RAISE EXCEPTION 'sha256 digest failed'; END IF; IF length(gen_random_bytes(16)) <> 16 THEN RAISE EXCEPTION 'random bytes length failed'; END IF; SELECT crypt('secret', gen_salt('bf', 4)) INTO hashed; IF crypt('secret', hashed) <> hashed THEN RAISE EXCEPTION 'password hash verify failed'; END IF; SELECT pgp_sym_encrypt('oliphaunt secret', 'passphrase') INTO encrypted; IF pgp_sym_decrypt(encrypted, 'passphrase') <> 'oliphaunt secret' THEN RAISE EXCEPTION 'PGP symmetric decrypt failed'; END IF; END $$;", - "DO $$ BEGIN IF encode(hmac('test', 'key', 'sha1'), 'hex') <> '671f54ce0c540f78ffe1e26dcf9c2a047aea4fda' THEN RAISE EXCEPTION 'hmac failed'; END IF; IF gen_random_uuid()::text !~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$' THEN RAISE EXCEPTION 'random uuid format failed'; END IF; END $$;", - "DO $$ DECLARE armored text; header_count int; BEGIN SELECT armor(digest('test', 'sha1'), ARRAY['Version'], ARRAY['oliphaunt']) INTO armored; IF position('Version: oliphaunt' in armored) = 0 THEN RAISE EXCEPTION 'armor header failed'; END IF; SELECT count(*) INTO header_count FROM pgp_armor_headers(armored); IF header_count <> 1 THEN RAISE EXCEPTION 'armor header count failed: %', header_count; END IF; END $$;", - "DO $$ DECLARE encrypted bytea; crypto_key bytea := decode('000102030405060708090a0b0c0d0e0f', 'hex'); crypto_iv bytea := decode('101112131415161718191a1b1c1d1e1f', 'hex'); BEGIN SELECT pgp_sym_encrypt('oliphaunt secret', 'passphrase') INTO encrypted; IF pgp_key_id(encrypted) <> 'SYMKEY' THEN RAISE EXCEPTION 'PGP symmetric key id failed'; END IF; SELECT encrypt(convert_to('oliphaunt raw cipher', 'UTF8'), crypto_key, 'aes') INTO encrypted; IF convert_from(decrypt(encrypted, crypto_key, 'aes'), 'UTF8') <> 'oliphaunt raw cipher' THEN RAISE EXCEPTION 'raw decrypt failed'; END IF; SELECT encrypt_iv(convert_to('oliphaunt iv cipher', 'UTF8'), crypto_key, crypto_iv, 'aes-cbc') INTO encrypted; IF convert_from(decrypt_iv(encrypted, crypto_key, crypto_iv, 'aes-cbc'), 'UTF8') <> 'oliphaunt iv cipher' THEN RAISE EXCEPTION 'raw iv decrypt failed'; END IF; END $$;" + "DO $$ DECLARE hashed text; encrypted bytea; BEGIN IF encode(digest('abc', 'sha256'), 'hex') IS DISTINCT FROM 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad' THEN RAISE EXCEPTION 'sha256 digest failed'; END IF; IF length(gen_random_bytes(16)) IS DISTINCT FROM 16 THEN RAISE EXCEPTION 'random bytes length failed'; END IF; SELECT crypt('secret', gen_salt('bf', 4)) INTO hashed; IF hashed IS NULL OR crypt('secret', hashed) IS DISTINCT FROM hashed THEN RAISE EXCEPTION 'password hash verify failed'; END IF; SELECT pgp_sym_encrypt('oliphaunt secret', 'passphrase') INTO encrypted; IF pgp_sym_decrypt(encrypted, 'passphrase') IS DISTINCT FROM 'oliphaunt secret' THEN RAISE EXCEPTION 'PGP symmetric decrypt failed'; END IF; END $$;", + "DO $$ BEGIN IF encode(hmac('test', 'key', 'sha1'), 'hex') IS DISTINCT FROM '671f54ce0c540f78ffe1e26dcf9c2a047aea4fda' THEN RAISE EXCEPTION 'hmac failed'; END IF; IF (gen_random_uuid()::text ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$') IS DISTINCT FROM true THEN RAISE EXCEPTION 'random uuid format failed'; END IF; END $$;", + "DO $$ DECLARE armored text; header_count int; BEGIN SELECT armor(digest('test', 'sha1'), ARRAY['Version'], ARRAY['oliphaunt']) INTO armored; IF armored IS NULL OR position('Version: oliphaunt' in armored) = 0 THEN RAISE EXCEPTION 'armor header failed'; END IF; SELECT count(*) INTO header_count FROM pgp_armor_headers(armored); IF header_count IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'armor header count failed: %', header_count; END IF; END $$;", + "DO $$ DECLARE encrypted bytea; crypto_key bytea := decode('000102030405060708090a0b0c0d0e0f', 'hex'); crypto_iv bytea := decode('101112131415161718191a1b1c1d1e1f', 'hex'); BEGIN SELECT pgp_sym_encrypt('oliphaunt secret', 'passphrase') INTO encrypted; IF pgp_key_id(encrypted) IS DISTINCT FROM 'SYMKEY' THEN RAISE EXCEPTION 'PGP symmetric key id failed'; END IF; SELECT encrypt(convert_to('oliphaunt raw cipher', 'UTF8'), crypto_key, 'aes') INTO encrypted; IF convert_from(decrypt(encrypted, crypto_key, 'aes'), 'UTF8') IS DISTINCT FROM 'oliphaunt raw cipher' THEN RAISE EXCEPTION 'raw decrypt failed'; END IF; SELECT encrypt_iv(convert_to('oliphaunt iv cipher', 'UTF8'), crypto_key, crypto_iv, 'aes-cbc') INTO encrypted; IF convert_from(decrypt_iv(encrypted, crypto_key, crypto_iv, 'aes-cbc'), 'UTF8') IS DISTINCT FROM 'oliphaunt iv cipher' THEN RAISE EXCEPTION 'raw iv decrypt failed'; END IF; END $$;" ], "pgtap": [ "SELECT plan(2);", @@ -361,13 +366,13 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = { "CREATE TABLE oliphaunt_postgis_points(id int PRIMARY KEY, geom geometry(Point, 4326));", "INSERT INTO oliphaunt_postgis_points VALUES\n (1, ST_SetSRID(ST_MakePoint(-71.060316, 48.432044), 4326)),\n (2, ST_SetSRID(ST_MakePoint(-71.061, 48.433), 4326));", "CREATE INDEX oliphaunt_postgis_points_gix ON oliphaunt_postgis_points USING GIST (geom);", - "-- oliphaunt-verify\nDO $$\nDECLARE\n distance float8;\n srid int;\n area float8;\n polygons int;\n nearby int;\nBEGIN\n SELECT ST_Distance(ST_GeomFromText('POINT(0 0)'), ST_GeomFromText('POINT(3 4)')) INTO distance;\n IF distance <> 5 THEN\n RAISE EXCEPTION 'postgis geometry distance failed: %', distance;\n END IF;\n IF ST_AsText(ST_Buffer(ST_GeomFromText('POINT(0 0)'), 1, 'quad_segs=1')) IS NULL THEN\n RAISE EXCEPTION 'postgis buffer failed';\n END IF;\n IF NOT ST_Within(\n ST_GeomFromText('POINT(0.5 0.5)'),\n ST_GeomFromText('POLYGON((0 0,0 1,1 1,1 0,0 0))')\n ) THEN\n RAISE EXCEPTION 'postgis within failed';\n END IF;\n SELECT ST_SRID(ST_Transform(ST_SetSRID(ST_MakePoint(-71.060316, 48.432044), 4326), 3857)) INTO srid;\n IF srid <> 3857 THEN\n RAISE EXCEPTION 'postgis transform failed: %', srid;\n END IF;\n SELECT ST_Area(ST_Transform(ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(-71.1776848522251 42.3902896512902,-71.1776843766797 42.3903701743239,-71.1775844305465 42.3903829478009,-71.1775825927231 42.3902893647987,-71.1776848522251 42.3902896512902)')), 4326), 26986)) INTO area;\n IF area <= 0 THEN\n RAISE EXCEPTION 'postgis projected area failed: %', area;\n END IF;\n SELECT ST_NumGeometries(ST_Polygonize(ARRAY[\n ST_GeomFromText('LINESTRING(0 0, 1 0)'),\n ST_GeomFromText('LINESTRING(1 0, 1 1)'),\n ST_GeomFromText('LINESTRING(1 1, 0 1)'),\n ST_GeomFromText('LINESTRING(0 1, 0 0)')\n ])) INTO polygons;\n IF polygons <> 1 THEN\n RAISE EXCEPTION 'postgis polygonize failed: %', polygons;\n END IF;\n SELECT count(*) INTO nearby\n FROM oliphaunt_postgis_points\n WHERE ST_DWithin(\n geom::geography,\n ST_SetSRID(ST_MakePoint(-71.060316, 48.432044), 4326)::geography,\n 200\n );\n IF nearby <> 2 THEN\n RAISE EXCEPTION 'postgis dwithin failed: %', nearby;\n END IF;\nEND $$;" + "-- oliphaunt-verify\nDO $$\nDECLARE\n distance float8;\n srid int;\n area float8;\n polygons int;\n nearby int;\nBEGIN\n SELECT ST_Distance(ST_GeomFromText('POINT(0 0)'), ST_GeomFromText('POINT(3 4)')) INTO distance;\n IF distance IS DISTINCT FROM 5 THEN\n RAISE EXCEPTION 'postgis geometry distance failed: %', distance;\n END IF;\n IF ST_AsText(ST_Buffer(ST_GeomFromText('POINT(0 0)'), 1, 'quad_segs=1')) IS NULL THEN\n RAISE EXCEPTION 'postgis buffer failed';\n END IF;\n IF ST_Within(\n ST_GeomFromText('POINT(0.5 0.5)'),\n ST_GeomFromText('POLYGON((0 0,0 1,1 1,1 0,0 0))')\n ) IS DISTINCT FROM true THEN\n RAISE EXCEPTION 'postgis within failed';\n END IF;\n SELECT ST_SRID(ST_Transform(ST_SetSRID(ST_MakePoint(-71.060316, 48.432044), 4326), 3857)) INTO srid;\n IF srid IS DISTINCT FROM 3857 THEN\n RAISE EXCEPTION 'postgis transform failed: %', srid;\n END IF;\n SELECT ST_Area(ST_Transform(ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(-71.1776848522251 42.3902896512902,-71.1776843766797 42.3903701743239,-71.1775844305465 42.3903829478009,-71.1775825927231 42.3902893647987,-71.1776848522251 42.3902896512902)')), 4326), 26986)) INTO area;\n IF area IS NULL OR area <= 0 THEN\n RAISE EXCEPTION 'postgis projected area failed: %', area;\n END IF;\n SELECT ST_NumGeometries(ST_Polygonize(ARRAY[\n ST_GeomFromText('LINESTRING(0 0, 1 0)'),\n ST_GeomFromText('LINESTRING(1 0, 1 1)'),\n ST_GeomFromText('LINESTRING(1 1, 0 1)'),\n ST_GeomFromText('LINESTRING(0 1, 0 0)')\n ])) INTO polygons;\n IF polygons IS DISTINCT FROM 1 THEN\n RAISE EXCEPTION 'postgis polygonize failed: %', polygons;\n END IF;\n SELECT count(*) INTO nearby\n FROM oliphaunt_postgis_points\n WHERE ST_DWithin(\n geom::geography,\n ST_SetSRID(ST_MakePoint(-71.060316, 48.432044), 4326)::geography,\n 200\n );\n IF nearby IS DISTINCT FROM 2 THEN\n RAISE EXCEPTION 'postgis dwithin failed: %', nearby;\n END IF;\nEND $$;" ], "seg": [ - "DO $$ BEGIN IF '7(+-)1'::seg::text <> '6 .. 8' THEN RAISE EXCEPTION 'seg cast failed'; END IF; END $$;" + "DO $$ BEGIN IF '7(+-)1'::seg::text IS DISTINCT FROM '6 .. 8' THEN RAISE EXCEPTION 'seg cast failed'; END IF; END $$;" ], "tablefunc": [ - "DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM normal_rand(10, 5, 3); IF n <> 10 THEN RAISE EXCEPTION 'normal_rand failed: %', n; END IF; END $$;", + "DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM normal_rand(10, 5, 3); IF n IS DISTINCT FROM 10 THEN RAISE EXCEPTION 'normal_rand failed: %', n; END IF; END $$;", "SELECT * FROM crosstab('SELECT 1, 1, 10 UNION ALL SELECT 1, 2, 20') AS ct(rowid int, c1 int, c2 int);" ], "tcn": [ @@ -384,12 +389,12 @@ export const GENERATED_MOBILE_EXTENSION_SMOKE = { "SELECT * FROM oliphaunt_tsm_time TABLESAMPLE SYSTEM_TIME(50);" ], "unaccent": [ - "DO $$ DECLARE lex text; BEGIN SELECT array_to_string(ts_lexize('unaccent', 'H\u00f4tel'), ',') INTO lex; IF lex <> 'Hotel' THEN RAISE EXCEPTION 'unaccent failed: %', lex; END IF; END $$;" + "DO $$ DECLARE lex text; BEGIN SELECT array_to_string(ts_lexize('unaccent', 'H\u00f4tel'), ',') INTO lex; IF lex IS DISTINCT FROM 'Hotel' THEN RAISE EXCEPTION 'unaccent failed: %', lex; END IF; END $$;" ], "uuid-ossp": [ - "DO $$ DECLARE id uuid; BEGIN SELECT uuid_generate_v1() INTO id; IF length(id::text) <> 36 THEN RAISE EXCEPTION 'uuid-ossp v1 length failed'; END IF; SELECT uuid_generate_v4() INTO id; IF length(id::text) <> 36 THEN RAISE EXCEPTION 'uuid-ossp v4 length failed'; END IF; END $$;", - "DO $$ BEGIN IF uuid_generate_v3(uuid_ns_dns(), 'www.example.com')::text <> '5df41881-3aed-3515-88a7-2f4a814cf09e' THEN RAISE EXCEPTION 'uuid-ossp v3 failed'; END IF; IF uuid_generate_v5(uuid_ns_dns(), 'www.example.com')::text <> '2ed6657d-e927-568b-95e1-2665a8aea6a2' THEN RAISE EXCEPTION 'uuid-ossp v5 failed'; END IF; END $$;", - "DO $$ BEGIN IF uuid_nil()::text <> '00000000-0000-0000-0000-000000000000' THEN RAISE EXCEPTION 'uuid-ossp nil failed'; END IF; IF uuid_ns_dns()::text <> '6ba7b810-9dad-11d1-80b4-00c04fd430c8' THEN RAISE EXCEPTION 'uuid-ossp dns namespace failed'; END IF; IF uuid_ns_oid()::text <> '6ba7b812-9dad-11d1-80b4-00c04fd430c8' THEN RAISE EXCEPTION 'uuid-ossp oid namespace failed'; END IF; END $$;" + "DO $$ DECLARE id uuid; BEGIN SELECT uuid_generate_v1() INTO id; IF length(id::text) IS DISTINCT FROM 36 THEN RAISE EXCEPTION 'uuid-ossp v1 length failed'; END IF; SELECT uuid_generate_v4() INTO id; IF length(id::text) IS DISTINCT FROM 36 THEN RAISE EXCEPTION 'uuid-ossp v4 length failed'; END IF; END $$;", + "DO $$ BEGIN IF uuid_generate_v3(uuid_ns_dns(), 'www.example.com')::text IS DISTINCT FROM '5df41881-3aed-3515-88a7-2f4a814cf09e' THEN RAISE EXCEPTION 'uuid-ossp v3 failed'; END IF; IF uuid_generate_v5(uuid_ns_dns(), 'www.example.com')::text IS DISTINCT FROM '2ed6657d-e927-568b-95e1-2665a8aea6a2' THEN RAISE EXCEPTION 'uuid-ossp v5 failed'; END IF; END $$;", + "DO $$ BEGIN IF uuid_nil()::text IS DISTINCT FROM '00000000-0000-0000-0000-000000000000' THEN RAISE EXCEPTION 'uuid-ossp nil failed'; END IF; IF uuid_ns_dns()::text IS DISTINCT FROM '6ba7b810-9dad-11d1-80b4-00c04fd430c8' THEN RAISE EXCEPTION 'uuid-ossp dns namespace failed'; END IF; IF uuid_ns_oid()::text IS DISTINCT FROM '6ba7b812-9dad-11d1-80b4-00c04fd430c8' THEN RAISE EXCEPTION 'uuid-ossp oid namespace failed'; END IF; END $$;" ], "vector": [ "DROP TABLE IF EXISTS oliphaunt_vector;", diff --git a/src/examples/native/react-native-expo/src/smoke-pass-receipt.ts b/src/examples/native/react-native-expo/src/smoke-pass-receipt.ts index fe2a8a749..49690b7d8 100644 --- a/src/examples/native/react-native-expo/src/smoke-pass-receipt.ts +++ b/src/examples/native/react-native-expo/src/smoke-pass-receipt.ts @@ -13,6 +13,7 @@ export type ExpoSmokePassReceiptInput = { readonly extensionCatalogSha256: string; readonly catalogProfile: ExpoSmokePassCatalogProfile; readonly icuRuntimeProof: boolean; + readonly lifecycleResume: boolean; }; function utf8ByteLength(value: string): number { @@ -34,6 +35,9 @@ export function serializeExpoSmokePassReceipt(input: ExpoSmokePassReceiptInput): if (typeof input.icuRuntimeProof !== 'boolean') { throw new Error('installed-app receipt requires an ICU runtime proof boolean'); } + if (typeof input.lifecycleResume !== 'boolean') { + throw new Error('installed-app receipt requires a lifecycle resume proof boolean'); + } if (input.catalogProfile !== 'standard' && input.catalogProfile !== 'icu') { throw new Error( `installed-app receipt has unsupported catalog profile: ${String(input.catalogProfile)}`, @@ -75,7 +79,7 @@ export function serializeExpoSmokePassReceipt(input: ExpoSmokePassReceiptInput): } const serialized = JSON.stringify({ - schema: 'oliphaunt-expo-smoke-pass-v4', + schema: 'oliphaunt-expo-smoke-pass-v5', runner: 'smoke', platform: input.platform, extensionCount: extensions.length, @@ -85,6 +89,7 @@ export function serializeExpoSmokePassReceipt(input: ExpoSmokePassReceiptInput): extensionCatalogSha256: input.extensionCatalogSha256, catalogProfile: input.catalogProfile, icuRuntimeProof: input.icuRuntimeProof, + lifecycleResume: input.lifecycleResume, }); const eventBytes = utf8ByteLength(`${EXPO_SMOKE_PASS_TAG} ${serialized}`); if (eventBytes > EXPO_SMOKE_PASS_EVENT_MAX_BYTES) { diff --git a/src/examples/native/react-native-expo/tools/mobile-extension-proof.test.mts b/src/examples/native/react-native-expo/tools/mobile-extension-proof.test.mts index 5a457d9e7..1f00e9a4f 100644 --- a/src/examples/native/react-native-expo/tools/mobile-extension-proof.test.mts +++ b/src/examples/native/react-native-expo/tools/mobile-extension-proof.test.mts @@ -94,9 +94,10 @@ test('the successful pg_textsearch producer supplies every semantic PASS fact', extensionCatalogSha256: 'a'.repeat(64), catalogProfile: 'icu', icuRuntimeProof: true, + lifecycleResume: false, }), ); - assert.equal(receipt.schema, 'oliphaunt-expo-smoke-pass-v4'); + assert.equal(receipt.schema, 'oliphaunt-expo-smoke-pass-v5'); assert.equal(receipt.catalogProfile, 'icu'); assert.equal(receipt.allExtensionsActivated, true); assert.equal(receipt.extensionCatalogComplete, true); diff --git a/src/examples/native/react-native-expo/tools/smoke-pass-receipt.test.mts b/src/examples/native/react-native-expo/tools/smoke-pass-receipt.test.mts index 279879aa3..32b43dabc 100644 --- a/src/examples/native/react-native-expo/tools/smoke-pass-receipt.test.mts +++ b/src/examples/native/react-native-expo/tools/smoke-pass-receipt.test.mts @@ -1,15 +1,15 @@ import assert from 'node:assert/strict'; import test from 'node:test'; - +import { + GENERATED_MOBILE_EXTENSION_METADATA_SHA256, + GENERATED_MOBILE_EXTENSION_PLAN, + GENERATED_MOBILE_EXTENSION_SMOKE, +} from '../src/generated/extension-smoke.ts'; import { EXPO_SMOKE_PASS_EVENT_MAX_BYTES, EXPO_SMOKE_PASS_TAG, serializeExpoSmokePassReceipt, } from '../src/smoke-pass-receipt.ts'; -import { - GENERATED_MOBILE_EXTENSION_METADATA_SHA256, - GENERATED_MOBILE_EXTENSION_PLAN, -} from '../src/generated/extension-smoke.ts'; function platformExtensions() { return GENERATED_MOBILE_EXTENSION_PLAN.map((extension) => extension.sqlName).sort(); @@ -26,6 +26,7 @@ function receiptInput(platform, overrides = {}) { extensionCatalogSha256: GENERATED_MOBILE_EXTENSION_METADATA_SHA256, catalogProfile: 'icu', icuRuntimeProof: true, + lifecycleResume: true, ...overrides, }; } @@ -43,6 +44,7 @@ test('the exact mobile catalog produces a bounded authoritative receipt', () => 'extensionCatalogSha256', 'extensionCount', 'icuRuntimeProof', + 'lifecycleResume', 'pgTextsearchEnglishBm25', 'platform', 'runner', @@ -58,15 +60,49 @@ test('an extension-free developer smoke emits a non-release receipt', () => { extensions: [], activatedExtensions: [], pgTextsearchEnglishBm25: false, + lifecycleResume: false, }), ), ); assert.equal(receipt.extensionCount, 0); assert.equal(receipt.allExtensionsActivated, true); + assert.equal(receipt.lifecycleResume, false); +}); + +test('lifecycle receipts distinguish a completed resume from an ordinary smoke', () => { + for (const platform of ['android', 'ios']) { + for (const lifecycleResume of [false, true]) + assert.equal( + JSON.parse(serializeExpoSmokePassReceipt(receiptInput(platform, { lifecycleResume }))) + .lifecycleResume, + lifecycleResume, + ); + for (const lifecycleResume of [undefined, 'true', 1]) + assert.throws( + () => serializeExpoSmokePassReceipt(receiptInput(platform, { lifecycleResume })), + /lifecycle resume proof boolean/u, + ); + } }); test('receipt serialization fails closed on proof drift and remains constant-size as catalogs grow', () => { const extensions = platformExtensions(); + const sqlOnly = GENERATED_MOBILE_EXTENSION_PLAN.find( + (extension) => extension.sqlName === 'pgtap', + ); + assert( + sqlOnly && GENERATED_MOBILE_EXTENSION_SMOKE[sqlOnly.sqlName].length > 0, + 'SQL-only mobile member must have smoke SQL', + ); + assert.throws( + () => + serializeExpoSmokePassReceipt( + receiptInput('android', { + activatedExtensions: extensions.filter((name) => name !== sqlOnly.sqlName), + }), + ), + /activated extension mismatch/u, + ); assert.throws( () => serializeExpoSmokePassReceipt( @@ -131,6 +167,7 @@ test('receipt serialization fails closed on proof drift and remains constant-siz extensionCatalogSha256: GENERATED_MOBILE_EXTENSION_METADATA_SHA256, catalogProfile: 'standard', icuRuntimeProof: false, + lifecycleResume: false, }); assert( Buffer.byteLength(`${EXPO_SMOKE_PASS_TAG} ${serialized}`) <= EXPO_SMOKE_PASS_EVENT_MAX_BYTES, diff --git a/src/examples/wasix/browser/BUILD.bazel b/src/examples/wasix/browser/BUILD.bazel new file mode 100644 index 000000000..435a5df47 --- /dev/null +++ b/src/examples/wasix/browser/BUILD.bazel @@ -0,0 +1,36 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("@aspect_rules_js//js:defs.bzl", "js_library") +load("@aspect_rules_ts//ts:defs.bzl", "ts_config") +load("@bazel_lib//lib:copy_to_bin.bzl", "copy_to_bin") +load("@javascript_packages//:defs.bzl", "javascript_type_links") +load("@javascript_compiler_packages//:defs.bzl", "compiler_input_links") +load("@javascript_compiler_packages//:roots.bzl", "COMPILER_INPUTS") +load("@oliphaunt_javascript_metadata//:metadata.bzl", "JAVASCRIPT") + +package(default_visibility = ["//visibility:public"]) +exports_files(["package.json"]) + +EXAMPLE = JAVASCRIPT["oliphaunt-example-browser-wasix"] + +javascript_type_links(EXAMPLE["types"]) +compiler_input_links(COMPILER_INPUTS[EXAMPLE["name"]]) +copy_to_bin(name = "source_files", srcs = glob(["**/*.ts"], exclude = ["node_modules/**"])) +ts_config(name = "source_config", src = "tsconfig.json", deps = ["//src/wasix/sdks/ts:source_config"]) +js_library( + name = "source_inputs", + srcs = ["package.json"], + deps = ["//src/wasix/sdks/ts:source_inputs", "//src/wasix/sdks/ts:node_modules/@oliphaunt/ts-query"] + [":node_modules/" + name for name in EXAMPLE["types"]] + [":node_modules/" + name for name in COMPILER_INPUTS[EXAMPLE["name"]]], +) +test_suite(name = "source_checks", tests = ["//:browser_example_source_checks_typecheck_test"]) + +filegroup( + name = "opfs_fixtures", + srcs = [ + "opfs-crash-probe-worker.ts", + "opfs-smoke.ts", + "opfs-transport-probe-worker.ts", + "resources.ts", + ], +) + +source_quality_files() diff --git a/src/examples/wasix/browser/main.ts b/src/examples/wasix/browser/main.ts index e9da7f498..4a8d83668 100644 --- a/src/examples/wasix/browser/main.ts +++ b/src/examples/wasix/browser/main.ts @@ -4,12 +4,14 @@ import Oliphaunt, { PostgresError, type QueryParam, type WasixExtensionDescriptor, - type WasixStorage, - WasixStorageError, } from '@oliphaunt/wasix-ts'; import { indexedDB } from '@oliphaunt/wasix-ts/storage/indexed-db'; -import { opfs } from '@oliphaunt/wasix-ts/storage/opfs'; import WorkerOliphaunt from '@oliphaunt/wasix-ts/worker'; +import { + expectExclusiveOwnership, + expectOpfsCrashRecovery, + expectOpfsPersistence, +} from './opfs-smoke.js'; import { standardSeed } from './resources.js'; import { expectStructuredApi } from './structured-api-smoke.js'; @@ -103,7 +105,7 @@ try { } await database.close(); smokePhase('OPFS persistence'); - const opfsAnswers = await expectOpfsPersistence(extensions); + const opfsAnswers = await expectOpfsPersistence(extensions, smokePhase); smokePhase('OPFS crash recovery'); const opfsCrash = await expectOpfsCrashRecovery(); smokePhase('PostGIS Worker'); @@ -154,7 +156,7 @@ try { function smokePhase(phase: string): void { if (!smoke) return; document.documentElement.dataset.oliphauntSmokePhase = phase; - console.debug(`browser smoke phase: ${phase}`); + console.debug(`browser smoke phase: ${phase} (${Math.round(performance.now())}ms)`); } function simpleQuery(sql: string): Uint8Array { @@ -385,174 +387,6 @@ async function expectFailedWorkerOpenRecovery(): Promise { } } -async function expectExclusiveOwnership( - storage: WasixStorage, - extensions: readonly WasixExtensionDescriptor[], - provider: string, -): Promise { - try { - const duplicate = await Oliphaunt.open({ seed: standardSeed, storage, extensions }); - await duplicate.close(); - throw new Error(`browser smoke opened one ${provider} database twice`); - } catch (error) { - if (!(error instanceof WasixStorageError) || error.code !== 'busy') { - throw error; - } - } -} - -async function expectOpfsPersistence( - extensions: readonly WasixExtensionDescriptor[], -): Promise { - const storage = opfs('browser-smoke'); - let database = await Oliphaunt.open({ seed: standardSeed, storage, extensions }); - await expectExclusiveOwnership(storage, extensions, 'OPFS'); - await database.queryRaw('CREATE TABLE opfs_reopen_probe (answer integer NOT NULL)'); - await database.queryRaw('INSERT INTO opfs_reopen_probe VALUES (1)'); - // PostgreSQL normally retains the relation and WAL descriptors. This second - // operation proves that the host journal observes writes after initial open. - await database.queryRaw('INSERT INTO opfs_reopen_probe VALUES (2)'); - await database.close(); - - database = await WorkerOliphaunt.open({ storage, extensions }); - try { - await expectSynchronousOpfsTransport('browser-smoke'); - const reopened = await database.queryRaw( - 'SELECT string_agg(answer::text, $1 ORDER BY answer) AS answers FROM opfs_reopen_probe', - [','], - ); - const answers = reopened.getText(0, 'answers'); - if (answers !== '1,2') { - throw new Error(`browser smoke did not reopen OPFS state: ${answers}`); - } - await database.queryRaw('INSERT INTO opfs_reopen_probe VALUES (3)'); - await database.queryRaw('CREATE TABLE opfs_sync_create_probe (answer integer NOT NULL)'); - await database.queryRaw('INSERT INTO opfs_sync_create_probe VALUES (99)'); - await database.execute('CHECKPOINT'); - } finally { - await database.close(); - } - - database = await Oliphaunt.open({ storage, extensions }); - try { - const reopened = await database.queryRaw( - 'SELECT string_agg(answer::text, $1 ORDER BY answer) AS answers FROM opfs_reopen_probe', - [','], - ); - const answers = reopened.getText(0, 'answers'); - if (answers !== '1,2,3') { - throw new Error(`browser smoke did not reopen synchronous OPFS writes: ${answers}`); - } - const created = await database.queryRaw('SELECT answer FROM opfs_sync_create_probe'); - if (created.getText(0, 'answer') !== '99') { - throw new Error('browser smoke did not reopen a relation created through synchronous OPFS'); - } - return answers; - } finally { - await database.close(); - } -} - -async function expectSynchronousOpfsTransport(name: string): Promise { - const worker = new Worker(new URL('./opfs-transport-probe-worker.ts', import.meta.url), { - type: 'module', - }); - try { - const response = await new Promise< - { ok: true; transport: 'synchronous-access' | 'portable' } | { ok: false; error: string } - >((resolve, reject) => { - const timeout = setTimeout(() => reject(new Error('OPFS transport probe timed out')), 10_000); - worker.addEventListener( - 'error', - (event) => { - clearTimeout(timeout); - reject(event.error ?? new Error(event.message)); - }, - { once: true }, - ); - worker.addEventListener( - 'message', - (event: MessageEvent) => { - clearTimeout(timeout); - resolve( - event.data as - | { ok: true; transport: 'synchronous-access' | 'portable' } - | { ok: false; error: string }, - ); - }, - { once: true }, - ); - worker.postMessage({ name }); - }); - if (!response.ok) throw new Error(`OPFS transport probe failed: ${response.error}`); - if (response.transport !== 'synchronous-access') { - throw new Error( - 'browser smoke selected portable OPFS instead of the synchronous-access Worker path', - ); - } - } finally { - worker.terminate(); - } -} - -async function expectOpfsCrashRecovery(): Promise> { - const name = `browser-crash-${crypto.randomUUID()}`; - const worker = new Worker(new URL('./opfs-crash-probe-worker.ts', import.meta.url), { - type: 'module', - }); - try { - const response = await new Promise< - Readonly<{ ok: true }> | Readonly<{ ok: false; error: string }> - >((resolve, reject) => { - const timeout = setTimeout( - () => reject(new Error('OPFS crash-recovery setup timed out')), - 60_000, - ); - worker.addEventListener( - 'error', - (event) => { - clearTimeout(timeout); - reject(event.error ?? new Error(event.message)); - }, - { once: true }, - ); - worker.addEventListener( - 'message', - (event: MessageEvent) => { - clearTimeout(timeout); - resolve(event.data as Readonly<{ ok: true }> | Readonly<{ ok: false; error: string }>); - }, - { once: true }, - ); - worker.postMessage({ name }); - }); - if (!response.ok) throw new Error(`OPFS crash-recovery setup failed: ${response.error}`); - } finally { - worker.terminate(); - } - - const database = await Oliphaunt.open({ seed: standardSeed, storage: opfs(name) }); - try { - const result = await database.queryRaw('SELECT answer FROM opfs_crash_probe'); - const answer = result.getText(0, 'answer'); - if (answer !== '73') { - throw new Error(`OPFS crash recovery returned an unexpected answer: ${answer}`); - } - const relationResult = await database.queryRaw(` - SELECT count(*)::text AS count - FROM pg_class - WHERE relname LIKE 'opfs_crash_burst_%' - `); - const relations = relationResult.getText(0, 'count'); - if (relations !== '48') { - throw new Error(`OPFS crash recovery returned an unexpected relation count: ${relations}`); - } - return { answer, relations }; - } finally { - await database.close(); - } -} - async function exercisePgtap(database: OliphauntDatabase): Promise { const version = await readPgtapVersion(database); const plan = await database.queryRaw('SELECT plan(1)::text AS tap'); diff --git a/src/examples/wasix/browser/opfs-smoke.ts b/src/examples/wasix/browser/opfs-smoke.ts new file mode 100644 index 000000000..d3a99b2fc --- /dev/null +++ b/src/examples/wasix/browser/opfs-smoke.ts @@ -0,0 +1,197 @@ +import Oliphaunt, { + type WasixExtensionDescriptor, + type WasixStorage, + WasixStorageError, +} from '@oliphaunt/wasix-ts'; +import { opfs } from '@oliphaunt/wasix-ts/storage/opfs'; +import WorkerOliphaunt from '@oliphaunt/wasix-ts/worker'; +import { standardSeed } from './resources.js'; + +export async function expectExclusiveOwnership( + storage: WasixStorage, + extensions: readonly WasixExtensionDescriptor[], + provider: string, +): Promise { + try { + const duplicate = await Oliphaunt.open({ seed: standardSeed, storage, extensions }); + await duplicate.close(); + throw new Error(`browser smoke opened one ${provider} database twice`); + } catch (error) { + if (!(error instanceof WasixStorageError) || error.code !== 'busy') { + throw error; + } + } +} + +export async function expectOpfsPersistence( + extensions: readonly WasixExtensionDescriptor[], + smokePhase: (phase: string) => void = () => {}, +): Promise { + const storage = opfs('browser-smoke'); + smokePhase('OPFS direct open'); + let database = await Oliphaunt.open({ seed: standardSeed, storage, extensions }); + smokePhase('OPFS exclusive ownership'); + await expectExclusiveOwnership(storage, extensions, 'OPFS'); + smokePhase('OPFS direct create'); + await database.queryRaw('CREATE TABLE opfs_reopen_probe (answer integer NOT NULL)'); + smokePhase('OPFS direct first write'); + await database.queryRaw('INSERT INTO opfs_reopen_probe VALUES (1)'); + // PostgreSQL normally retains the relation and WAL descriptors. This second + // operation proves that the host journal observes writes after initial open. + smokePhase('OPFS direct retained-descriptor write'); + await database.queryRaw('INSERT INTO opfs_reopen_probe VALUES (2)'); + smokePhase('OPFS direct close'); + await database.close(); + + smokePhase('OPFS Worker reopen'); + database = await WorkerOliphaunt.open({ storage, extensions }); + try { + smokePhase('OPFS synchronous transport'); + await expectSynchronousOpfsTransport('browser-smoke'); + smokePhase('OPFS Worker read'); + const reopened = await database.queryRaw( + 'SELECT string_agg(answer::text, $1 ORDER BY answer) AS answers FROM opfs_reopen_probe', + [','], + ); + const answers = reopened.getText(0, 'answers'); + if (answers !== '1,2') { + throw new Error(`browser smoke did not reopen OPFS state: ${answers}`); + } + smokePhase('OPFS Worker write'); + await database.queryRaw('INSERT INTO opfs_reopen_probe VALUES (3)'); + smokePhase('OPFS Worker create'); + await database.queryRaw('CREATE TABLE opfs_sync_create_probe (answer integer NOT NULL)'); + smokePhase('OPFS Worker created-relation write'); + await database.queryRaw('INSERT INTO opfs_sync_create_probe VALUES (99)'); + smokePhase('OPFS Worker checkpoint'); + await database.execute('CHECKPOINT'); + } finally { + smokePhase('OPFS Worker close'); + await database.close(); + } + + smokePhase('OPFS direct reopen'); + database = await Oliphaunt.open({ storage, extensions }); + try { + smokePhase('OPFS direct read'); + const reopened = await database.queryRaw( + 'SELECT string_agg(answer::text, $1 ORDER BY answer) AS answers FROM opfs_reopen_probe', + [','], + ); + const answers = reopened.getText(0, 'answers'); + if (answers !== '1,2,3') { + throw new Error(`browser smoke did not reopen synchronous OPFS writes: ${answers}`); + } + smokePhase('OPFS direct created-relation read'); + const created = await database.queryRaw('SELECT answer FROM opfs_sync_create_probe'); + if (created.getText(0, 'answer') !== '99') { + throw new Error('browser smoke did not reopen a relation created through synchronous OPFS'); + } + return answers; + } finally { + smokePhase('OPFS reopened direct close'); + await database.close(); + } +} + +async function expectSynchronousOpfsTransport(name: string): Promise { + const worker = new Worker(new URL('./opfs-transport-probe-worker.ts', import.meta.url), { + type: 'module', + }); + try { + const response = await new Promise< + { ok: true; transport: 'synchronous-access' | 'portable' } | { ok: false; error: string } + >((resolve, reject) => { + const timeout = setTimeout(() => reject(new Error('OPFS transport probe timed out')), 10_000); + worker.addEventListener( + 'error', + (event) => { + clearTimeout(timeout); + reject(event.error ?? new Error(event.message)); + }, + { once: true }, + ); + worker.addEventListener( + 'message', + (event: MessageEvent) => { + clearTimeout(timeout); + resolve( + event.data as + | { ok: true; transport: 'synchronous-access' | 'portable' } + | { ok: false; error: string }, + ); + }, + { once: true }, + ); + worker.postMessage({ name }); + }); + if (!response.ok) throw new Error(`OPFS transport probe failed: ${response.error}`); + if (response.transport !== 'synchronous-access') { + throw new Error( + 'browser smoke selected portable OPFS instead of the synchronous-access Worker path', + ); + } + } finally { + worker.terminate(); + } +} + +export async function expectOpfsCrashRecovery(): Promise< + Readonly<{ answer: string; relations: string }> +> { + const name = `browser-crash-${crypto.randomUUID()}`; + const worker = new Worker(new URL('./opfs-crash-probe-worker.ts', import.meta.url), { + type: 'module', + }); + try { + const response = await new Promise< + Readonly<{ ok: true }> | Readonly<{ ok: false; error: string }> + >((resolve, reject) => { + const timeout = setTimeout( + () => reject(new Error('OPFS crash-recovery setup timed out')), + 60_000, + ); + worker.addEventListener( + 'error', + (event) => { + clearTimeout(timeout); + reject(event.error ?? new Error(event.message)); + }, + { once: true }, + ); + worker.addEventListener( + 'message', + (event: MessageEvent) => { + clearTimeout(timeout); + resolve(event.data as Readonly<{ ok: true }> | Readonly<{ ok: false; error: string }>); + }, + { once: true }, + ); + worker.postMessage({ name }); + }); + if (!response.ok) throw new Error(`OPFS crash-recovery setup failed: ${response.error}`); + } finally { + worker.terminate(); + } + + const database = await Oliphaunt.open({ seed: standardSeed, storage: opfs(name) }); + try { + const result = await database.queryRaw('SELECT answer FROM opfs_crash_probe'); + const answer = result.getText(0, 'answer'); + if (answer !== '73') { + throw new Error(`OPFS crash recovery returned an unexpected answer: ${answer}`); + } + const relationResult = await database.queryRaw(` + SELECT count(*)::text AS count + FROM pg_class + WHERE relname LIKE 'opfs_crash_burst_%' + `); + const relations = relationResult.getText(0, 'count'); + if (relations !== '48') { + throw new Error(`OPFS crash recovery returned an unexpected relation count: ${relations}`); + } + return { answer, relations }; + } finally { + await database.close(); + } +} diff --git a/src/extensions/artifacts/native/moon.yml b/src/extensions/artifacts/native/moon.yml index f0d413683..6509fa658 100644 --- a/src/extensions/artifacts/native/moon.yml +++ b/src/extensions/artifacts/native/moon.yml @@ -36,6 +36,7 @@ tasks: - /src/extensions/artifacts/native/tools/run-observed-phase.sh - /src/extensions/artifacts/native/tools/run-observed-phase.test.sh - /src/extensions/artifacts/native/tools/*.{mts,sh} + - /build_defs/extensions/windows_source_portability.mts - /src/extensions/artifacts/packages/tools/extension-artifact-inventory.mts - /src/extensions/artifacts/native/tools/extension-artifact-packager.mts - "@group(legal-files)" @@ -87,6 +88,7 @@ tasks: group: sources - /src/native/runtime/sources/*.toml - /src/extensions/artifacts/native/tools/**/* + - /build_defs/extensions/windows_source_portability.mts - "!/src/extensions/artifacts/native/tools/**/*.test.*" - /tools/packaging/check-linux-consumer-baseline.sh - /src/third-party/tools/source-fetch-core.mts diff --git a/src/extensions/artifacts/native/tools/create-artifact.test.mts b/src/extensions/artifacts/native/tools/create-artifact.test.mts index 7fc1ace03..638702628 100644 --- a/src/extensions/artifacts/native/tools/create-artifact.test.mts +++ b/src/extensions/artifacts/native/tools/create-artifact.test.mts @@ -2,7 +2,10 @@ import assert from 'node:assert/strict'; import fs from 'node:fs/promises'; import path from 'node:path'; import { elfFixture } from '../../../../../tools/packaging/testdata/release-fixture-utils.mts'; -import { validateExtensionArtifactArchive } from '../../packages/tools/extension-artifact-inventory.mts'; +import { + readCanonicalExtensionArtifactArchive, + validateExtensionArtifactArchive, +} from '../../packages/tools/extension-artifact-inventory.mts'; const [phase, root, kind] = process.argv.slice(2); const metadata = { @@ -20,7 +23,38 @@ const dataFiles = [ 'oliphaunt-streaming/b.bin', 'oliphaunt-streaming/c.bin', ]; -if (phase === 'prepare-binaries') { +if (phase === 'prepare-android') { + const out = path.join(root, 'mobile/android-arm64-v8a/android-arm64/out'); + const write = async (file: string, bytes: Buffer | string) => { + await fs.mkdir(path.dirname(file), { recursive: true }); + await fs.writeFile(file, bytes); + }; + const object = elfFixture({ machine: 183, type: 1 }); + const header = ['vector.o/', '0', '0', '0', '100644', String(object.length)] + .map((value, index) => value.padEnd([16, 12, 6, 6, 8, 10][index], ' ')) + .join(''); + await write( + path.join(out, 'extensions/vector/liboliphaunt_extension_vector.a'), + Buffer.concat([Buffer.from('!\n' + header + '`\n', 'ascii'), object]), + ); + const utility = elfFixture({ machine: 183, androidApi: 24 }); + utility.writeBigUInt64LE(4096n, 112); + await write(path.join(out, 'dependencies/libiconv/bin/iconv'), utility); + await write(path.join(root, 'host/lib/postgresql/vector.so'), elfFixture()); + await write( + path.join(root, 'host/share/postgresql/extension/vector.control'), + "default_version = '0.8.2'\n", + ); + await write(path.join(root, 'host/share/postgresql/extension/vector--0.8.2.sql'), 'select 1;\n'); +} else if (phase === 'verify-android') { + const entries = readCanonicalExtensionArtifactArchive(kind, 'actual Android extension producer'); + assert.ok( + entries.has( + 'mobile-static/android-arm64-v8a/extensions/vector/liboliphaunt_extension_vector.a', + ), + ); + assert.ok(![...entries.keys()].some((name) => name.includes('libiconv/bin/iconv'))); +} else if (phase === 'prepare-binaries') { for (const [directory, requiredVersions] of [ ['runtime/lib/postgresql', []], ['embedded', ['GLIBC_2.17']], diff --git a/src/extensions/artifacts/native/tools/extension-artifact-packager.mts b/src/extensions/artifacts/native/tools/extension-artifact-packager.mts index e2adc9f29..36bbbdcfd 100755 --- a/src/extensions/artifacts/native/tools/extension-artifact-packager.mts +++ b/src/extensions/artifacts/native/tools/extension-artifact-packager.mts @@ -1041,9 +1041,24 @@ async function writeArtifactDirectory(artifactRoot, args) { } export async function validateExactArtifactBinaryContract(artifactRoot, args) { - if (args.nativeModuleStem === undefined || !DESKTOP_NATIVE_TARGETS.has(args.nativeTarget)) { + if (args.nativeModuleStem === undefined) { return; } + if (args.nativeTarget === 'android-arm64-v8a' || args.nativeTarget === 'android-x86_64') { + const primary = path.join( + artifactRoot, + mobileStaticArchiveRelativePath(args.nativeTarget, args.nativeModuleStem), + ); + if (!(await isFile(primary))) { + fail( + `missing staged ${args.nativeTarget} static archive for ${args.nativeModuleStem}: ${primary}`, + ); + } + return inspectPlatformBinaryTree(path.join(artifactRoot, 'mobile-static', args.nativeTarget), { + target: args.nativeTarget, + }); + } + if (!DESKTOP_NATIVE_TARGETS.has(args.nativeTarget)) return; if (args.nativeTarget === 'windows-x64-msvc') { return validateWindowsExtensionArtifactBinaryContract({ artifactRoot, diff --git a/src/extensions/artifacts/native/tools/ios-extension-registration.mts b/src/extensions/artifacts/native/tools/ios-extension-registration.mts index 2312b8113..231d7e79a 100755 --- a/src/extensions/artifacts/native/tools/ios-extension-registration.mts +++ b/src/extensions/artifacts/native/tools/ios-extension-registration.mts @@ -1,5 +1,6 @@ #!/usr/bin/env bun +import assert from 'node:assert/strict'; import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; import path from 'node:path'; @@ -10,6 +11,31 @@ const SCHEMA = 'oliphaunt-ios-extension-registration-v1'; const PORTABLE_RE = /^[A-Za-z0-9._-]{1,128}$/u; const C_IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/u; +export function staticSymbolPrefix(stem: string) { + assert(PORTABLE_RE.test(stem), 'static module stem must be portable'); + return `oliphaunt_static_${stem.replaceAll(/[^A-Za-z0-9_]/gu, '_')}`; +} + +/** The existing PostGIS collision has the same namespace in every static slice. */ +export function staticMemberAliases(sqlName: string, stem: string | null) { + assert(PORTABLE_RE.test(sqlName), 'SQL member name must be portable'); + if (sqlName !== 'postgis') return []; + assert(stem !== null, 'PostGIS aliases require its canonical static module'); + const address = `${staticSymbolPrefix(stem)}_difference`; + return [ + { name: 'difference', address }, + { name: 'pg_finfo_difference', address: `pg_finfo_${address}` }, + ]; +} + +export function assertStaticMemberAliases(sqlName: string, stem: string | null, aliases) { + assert.deepEqual( + [...aliases].sort((left, right) => compareText(left.name, right.name)), + staticMemberAliases(sqlName, stem), + 'static member aliases differ from its canonical namespace', + ); +} + function fail(message) { console.error(`${PREFIX}: ${message}`); process.exit(1); @@ -74,7 +100,7 @@ function definedSymbols(file) { } function registration(out, sqlName, stem, inventory) { - const prefix = `oliphaunt_static_${stem.replaceAll(/[^A-Za-z0-9_]/gu, '_')}`; + const prefix = staticSymbolPrefix(stem); const names = definedSymbols(inventory); const magicSymbol = `${prefix}_Pg_magic_func`; if (!names.has(magicSymbol)) { diff --git a/src/extensions/artifacts/native/tools/package-release-assets.sh b/src/extensions/artifacts/native/tools/package-release-assets.sh index ccbcb86aa..5e0b7bae2 100755 --- a/src/extensions/artifacts/native/tools/package-release-assets.sh +++ b/src/extensions/artifacts/native/tools/package-release-assets.sh @@ -729,9 +729,6 @@ package_android_target() { ;; *) fail "Android target packager called for $target_id" ;; esac - if [ -n "$mobile_extensions" ]; then - tools/dev/bun.sh tools/packaging/platform-binary-contract.mts --target "$target_id" --root "$android_root/out" - fi local sql_name pg_major creates_extension stem dependencies shared_preload desktop_prebuilt mobile_prebuilt mobile_static_required mobile_static_targets data_files artifact_policy runtime_artifact android_archive static_prefix while IFS=$'\t' read -r sql_name pg_major creates_extension stem dependencies shared_preload desktop_prebuilt mobile_prebuilt mobile_static_required mobile_static_targets data_files artifact_policy; do [ -n "$sql_name" ] || continue diff --git a/src/extensions/artifacts/native/tools/package-release-assets.test.sh b/src/extensions/artifacts/native/tools/package-release-assets.test.sh index b68aa39df..e86abc613 100644 --- a/src/extensions/artifacts/native/tools/package-release-assets.test.sh +++ b/src/extensions/artifacts/native/tools/package-release-assets.test.sh @@ -30,6 +30,17 @@ if OLIPHAUNT_EXTENSION_PHASE=android-package OLIPHAUNT_EXTENSION_PRODUCTS=olipha echo 'accepted missing static archive' >&2; exit 1 fi grep -Eq 'no ELF binaries|missing Android static archive for vector' "$scratch/missing-static.log" +# Construction outputs can contain utilities that are not part of any carrier. +# Package-only qualification must inspect the selected staged static archive. +fixture=src/extensions/artifacts/native/tools/create-artifact.test.mts +bun "$fixture" prepare-android "$scratch" +printf '#!/usr/bin/env sh\nexit 0\n' > "$scratch/strip" +chmod +x "$scratch/strip" +OLIPHAUNT_EXTENSION_PHASE=android-package OLIPHAUNT_EXTENSION_PRODUCTS=oliphaunt-extension-vector \ + OLIPHAUNT_ANDROID_STRIP="$scratch/strip" bash "$producer" +vector_archive="$(find "$scratch/assets" -name '*-vector-*-runtime.tar.gz')" +[ -f "$vector_archive" ] +bun "$fixture" verify-android "$scratch" "$vector_archive" rm -rf "$scratch/host" if OLIPHAUNT_EXTENSION_PHASE=android-package bash "$producer" > "$scratch/missing-host.log" 2>&1; then echo 'accepted missing Linux support' >&2; exit 1 diff --git a/src/extensions/artifacts/native/tools/windows-extension-binary-contract.test.mts b/src/extensions/artifacts/native/tools/windows-extension-binary-contract.test.mts index 5e8914402..e7eeb59c4 100644 --- a/src/extensions/artifacts/native/tools/windows-extension-binary-contract.test.mts +++ b/src/extensions/artifacts/native/tools/windows-extension-binary-contract.test.mts @@ -173,6 +173,67 @@ async function relativeFiles(root, relative = '') { return files.sort(); } +function staticElfArchive(machine) { + const object = elfFixture({ machine, type: 1 }); + const header = ['extension.o/', '0', '0', '0', '100644', String(object.length)] + .map((value, index) => value.padEnd([16, 12, 6, 6, 8, 10][index], ' ')) + .join(''); + return Buffer.concat([ + Buffer.from('!\n' + header + '`\n', 'ascii'), + object, + ...(object.length % 2 ? [Buffer.from('\n')] : []), + ]); +} + +describe('Android exact-extension staged static archive qualification', () => { + for (const [target, machine, wrongMachine] of [ + ['android-arm64-v8a', 183, 62], + ['android-x86_64', 62, 183], + ]) { + test(`${target} validates shipped extension/dependency objects and excludes build utilities`, async () => { + const root = await fixture(target); + const artifact = path.join(root, 'artifact'); + const scratch = path.join(root, 'build/out'); + const extension = `mobile-static/${target}/extensions/vector/liboliphaunt_extension_vector.a`; + const dependency = `mobile-static/${target}/dependencies/libiconv/libiconv.a`; + await writeRuntimeFile(artifact, extension, staticElfArchive(machine)); + await writeRuntimeFile(artifact, dependency, staticElfArchive(machine)); + // Mobile carriers also contain their Linux support module. Its separate + // target contract must not be applied to Android static objects. + await writeRuntimeFile(artifact, 'files/lib/postgresql/vector.so', elfFixture()); + const utility = elfFixture({ machine, androidApi: 24 }); + utility.writeBigUInt64LE(4096n, 112); + await writeRuntimeFile(scratch, 'dependencies/libiconv/bin/iconv', utility); + await expect(inspectPlatformBinaryTree(scratch, { target })).rejects.toThrow( + /PT_LOAD alignment 4096/u, + ); + const args = { nativeModuleStem: 'vector', nativeTarget: target }; + await expect(validateExactArtifactBinaryContract(artifact, args)).resolves.toMatchObject({ + target, + binaries: 2, + slices: 2, + }); + await rm(path.join(artifact, extension)); + await expect(validateExactArtifactBinaryContract(artifact, args)).rejects.toThrow( + /missing staged .* static archive for vector/u, + ); + await writeRuntimeFile(artifact, extension, staticElfArchive(wrongMachine)); + await expect(validateExactArtifactBinaryContract(artifact, args)).rejects.toThrow( + /ELF machine/u, + ); + await writeRuntimeFile(artifact, extension, staticElfArchive(machine)); + await writeRuntimeFile(artifact, dependency, staticElfArchive(wrongMachine)); + await expect(validateExactArtifactBinaryContract(artifact, args)).rejects.toThrow( + /ELF machine/u, + ); + await writeRuntimeFile(artifact, dependency, Buffer.from('!\ntruncated')); + await expect(validateExactArtifactBinaryContract(artifact, args)).rejects.toThrow( + /ar member header/u, + ); + }); + } +}); + describe('desktop exact-extension post-strip binary qualification', () => { test('validates both Linux profiles and rejects a corrupt or over-floor embedded module', async () => { const root = await fixture('linux-exact-profiles'); diff --git a/src/extensions/artifacts/native/tools/windows-extension-sources.mts b/src/extensions/artifacts/native/tools/windows-extension-sources.mts index 3a2ef1259..1e969fa86 100644 --- a/src/extensions/artifacts/native/tools/windows-extension-sources.mts +++ b/src/extensions/artifacts/native/tools/windows-extension-sources.mts @@ -10,6 +10,7 @@ import { } from 'node:fs'; import path from 'node:path'; import { parseArgs } from 'node:util'; +import { windowsExtensionSource } from '../../../../../build_defs/extensions/windows_source_portability.mts'; import { preprocessSql } from '../../../external/postgis/tools/preprocess-sql.mts'; const read = (file: string) => readFileSync(file, 'utf8'); @@ -37,13 +38,6 @@ function copy(source: string, destination: string) { filter: (file) => path.basename(file) !== '.git', }); } -function replace(file: string, before: string | RegExp, after: string) { - const original = read(file); - const updated = original.replace(before, after); - assert.notEqual(updated, original, `missing Windows source patch anchor in ${file}`); - write(file, updated); -} - // Only the literal object list is needed from these pinned PGXS projects. // Reject expressions rather than attempting to implement GNU Make here. export function pgxsSources(root: string) { @@ -156,11 +150,8 @@ export function prepareSimple(config: Config, extension: string) { includes.push('src'); } if (extension === 'pg_uuidv7') { - replace( - path.join(destination, 'pg_uuidv7.c'), - '#define EPOCH_DIFF_USECS ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * USECS_PER_DAY)', - `#define EPOCH_DIFF_USECS ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * USECS_PER_DAY)\n#ifdef _WIN32\n#ifndef CLOCK_REALTIME\n#define CLOCK_REALTIME 0\n#endif\nstatic int oliphaunt_pg_uuidv7_clock_gettime(int clock_id, struct timespec *ts) {\n TimestampTz unix_usecs;\n if (clock_id != CLOCK_REALTIME || ts == NULL) return -1;\n unix_usecs = GetCurrentTimestamp() + EPOCH_DIFF_USECS;\n ts->tv_sec = (time_t) (unix_usecs / USECS_PER_SEC);\n ts->tv_nsec = (long) ((unix_usecs % USECS_PER_SEC) * 1000);\n return 0;\n}\n#define clock_gettime oliphaunt_pg_uuidv7_clock_gettime\n#endif`, - ); + const target = path.join(destination, 'pg_uuidv7.c'); + write(target, windowsExtensionSource(extension, 'pg_uuidv7.c', read(target))); } } for (const file of [...sources, ...data]) @@ -293,28 +284,15 @@ export function preparePostgis(config: Config) { for (const file of glob(path.join(directory, folder), '**/*.{c,h}')) { const target = path.join(directory, folder, file), text = read(target); - const updated = text.replace( - /^[ \t]*(?!(?:extern\s+)?PGDLLEXPORT\s+)(?:extern\s+)?Datum\s+(\w+)\s*\(PG_FUNCTION_ARGS\);\r?$/gm, - 'extern PGDLLEXPORT Datum $1(PG_FUNCTION_ARGS);', - ); + const updated = windowsExtensionSource('postgis', `${folder}/${file}`, text); if (updated !== text) write(target, updated); } } - replace( - path.join(directory, 'postgis/postgis_legacy.c'), - /^([ \t]*)Datum[ \t]+funcname[ \t]*\(PG_FUNCTION_ARGS\);[ \t]*\\\r?$/gm, - '$1extern PGDLLEXPORT Datum funcname(PG_FUNCTION_ARGS); \\', + const geometryReader = path.join(directory, 'deps/flatgeobuf/geometryreader.cpp'); + write( + geometryReader, + windowsExtensionSource('postgis', 'deps/flatgeobuf/geometryreader.cpp', read(geometryReader)), ); - for (const variables of [ - ['x', 'y', 'z', 'm'], - ['xv', 'yv', 'zv', 'mv'], - ]) { - replace( - path.join(directory, 'deps/flatgeobuf/geometryreader.cpp'), - `pt = (POINT4D) { ${variables.join(', ')} };`, - ['x', 'y', 'z', 'm'].map((field, index) => `pt.${field} = ${variables[index]};`).join('\n'), - ); - } const comments = path.join(directory, 'doc/postgis_comments.sql'); if (!existsSync(comments)) write(comments, '-- Optional SQL comments are not generated by the Windows producer.\n'); diff --git a/src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts b/src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts index b9113a2d1..73cf90b20 100644 --- a/src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts +++ b/src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts @@ -1,6 +1,7 @@ #!/usr/bin/env bun import { createHash } from 'node:crypto'; import { + chmodSync, copyFileSync, cpSync, existsSync, @@ -10,25 +11,9 @@ import { rmSync, statSync, writeFileSync, - chmodSync, } from 'node:fs'; import path from 'node:path'; - import { - assertReleaseNoticesInArchive, - stageReleaseNotices, -} from '../../../../../tools/packaging/release-notices.mts'; -import { - assertExtensionUpstreamLicensesInArchive, - extensionCarrierLegalContract, - stageExtensionUpstreamLicenses, -} from '../../../tools/extension-upstream-licenses.mts'; - -import { createDeterministicTar } from '../../../../../tools/packaging/cargo-source-package.mts'; -import { extensionRuntimeAssetContract } from './extension-runtime-asset-contract.mts'; -import { canonicalGzipSync } from '../../../../../tools/packaging/portable-archive.mts'; -import { - ROOT, compareText, currentProductVersionSync, exactExtensionProducts, @@ -39,18 +24,21 @@ import { extensionReleaseVersion, extensionSourceIdentity, extensionSqlNames, + ROOT, } from '../../../../../tools/release/release-artifact-targets.mts'; import { swiftExtensionCarrierAssetName, writeSwiftExtensionCarrierManifest, } from '../../../../native/sdks/swift/tools/ios-carrier-manifest.mts'; -import { AOT_TARGET_TRIPLES } from '../../../../wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; import { assertCanonicalWasixAotManifest } from '../../../../wasix/runtime/tools/wasix-aot-manifest.mts'; +import { AOT_TARGET_TRIPLES } from '../../../../wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; import { assertWasixExtensionArchiveInstall, assertWasixExtensionInstallSidecar, projectWasixExtensionInstallSidecar, } from '../../../contracts/wasix-extension-install.mts'; +import { bundleCarrierAssets as assembleBundleCarrierAssets } from './bundle-carrier-assets.mts'; +import { extensionRuntimeAssetContract } from './extension-runtime-asset-contract.mts'; const PREFIX = 'build-extension-ci-artifacts.mts'; @@ -504,7 +492,7 @@ function nativeAssetName(product, version, target, kind, source) { fail(`unsupported native extension artifact target ${target} for ${path.basename(source)}`); } -function nativeAssetNameForRow(product, version, row) { +export function nativeAssetNameForRow(product, version, row) { if (row.kind === 'ios-dependency-xcframework') { return `${product}-${version}-native-ios-dependency-${row.identity}-xcframework${archiveSuffix(row.asset)}`; } @@ -715,139 +703,11 @@ function stageMember( } function bundleCarrierAssets(product, version, productRoot, members, compatibility) { - const assetDir = path.join(productRoot, 'release-assets'); - const stageRoot = path.join(productRoot, '.bundle-stage'); - const groups = new Map(); - for (const member of members) { - for (const asset of member.assets) { - const key = `${asset.family}\0${asset.target}`; - const group = groups.get(key) ?? { family: asset.family, target: asset.target, rows: [] }; - group.rows.push({ sqlName: member.sqlName, asset }); - groups.set(key, group); - } - } - const carrierAssets = []; - for (const group of [...groups.values()].sort((left, right) => - compareText(`${left.family}\0${left.target}`, `${right.family}\0${right.target}`), - )) { - const memberNames = [...new Set(group.rows.map((row) => row.sqlName))].sort(compareText); - const expectedNames = members.map((member) => member.sqlName).sort(compareText); - if (JSON.stringify(memberNames) !== JSON.stringify(expectedNames)) { - fail( - `${product} ${group.family}/${group.target} bundle is missing exact members: expected ${expectedNames.join(',')}, got ${memberNames.join(',')}`, - ); - } - const archiveRoot = `${product}-${version}-${group.family}-${group.target}-bundle`; - const stageDir = path.join(stageRoot, archiveRoot); - rmSync(stageDir, { recursive: true, force: true }); - mkdirSync(stageDir, { recursive: true }); - const manifestMembers = []; - for (const row of group.rows.sort((left, right) => - compareText( - `${left.sqlName}\0${left.asset.kind}\0${left.asset.identity ?? ''}`, - `${right.sqlName}\0${right.asset.kind}\0${right.asset.identity ?? ''}`, - ), - )) { - const memberPath = `extensions/${row.sqlName}/${row.asset.name}`; - const source = path.join(ROOT, row.asset.path); - const destination = path.join(stageDir, ...memberPath.split('/')); - mkdirSync(path.dirname(destination), { recursive: true }); - copyFileSync(source, destination); - chmodSync(destination, 0o644); - const copiedSha256 = sha256(destination); - const copiedBytes = statSync(destination).size; - if (copiedSha256 !== row.asset.sha256 || copiedBytes !== row.asset.bytes) { - fail( - `${product} ${group.family}/${group.target} changed ${row.sqlName} member bytes while staging ${memberPath}`, - ); - } - const member = { - sqlName: row.sqlName, - kind: row.asset.kind, - identity: row.asset.identity ?? null, - path: memberPath, - sha256: row.asset.sha256, - bytes: row.asset.bytes, - }; - manifestMembers.push(member); - row.asset.carrierAsset = `${archiveRoot}.tar.gz`; - row.asset.carrierRoot = archiveRoot; - row.asset.memberPath = memberPath; - } - const externalLicenseFiles = []; - for (const sqlName of memberNames) { - externalLicenseFiles.push(...stageExtensionUpstreamLicenses(sqlName, stageDir)); - } - const legal = extensionCarrierLegalContract(product, memberNames, { - family: group.family, - target: group.target, - }); - const stagedLicenseFiles = [...new Set(externalLicenseFiles)].sort(compareText); - if (JSON.stringify(stagedLicenseFiles) !== JSON.stringify(legal.licenseFiles)) { - fail( - `${product} ${group.family}/${group.target} staged upstream licenses differ from its legal contract: ` + - `expected ${legal.licenseFiles.join(',')}, got ${stagedLicenseFiles.join(',')}`, - ); - } - const bundleManifest = path.join(stageDir, 'bundle-manifest.json'); - writeFileSync( - bundleManifest, - `${JSON.stringify( - sortValue({ - schema: 'oliphaunt-extension-bundle-v1', - product, - version, - compatibility, - family: group.family, - target: group.target, - licenseProfile: legal.profile, - licenseFiles: legal.licenseFiles, - members: manifestMembers, - }), - null, - 2, - )}\n`, - 'utf8', - ); - chmodSync(bundleManifest, 0o644); - stageReleaseNotices(stageDir, { profile: legal.profile }); - const output = path.join(assetDir, `${archiveRoot}.tar.gz`); - writeFileSync( - output, - canonicalGzipSync( - createDeterministicTar(stageDir, archiveRoot, { - fail, - includeDirectories: false, - // Every bundle member is data. Windows filesystem modes are synthetic, - // so encode the portable carrier contract instead of copying stat bits. - fixedFileMode: 0o644, - }), - ), - ); - assertReleaseNoticesInArchive(output, { - prefix: archiveRoot, - profile: legal.profile, - }); - if (legal.upstreamMembers.length > 0) { - assertExtensionUpstreamLicensesInArchive(legal.upstreamMembers, output, { - prefix: archiveRoot, - }); - } - carrierAssets.push({ - name: path.basename(output), - path: rel(output), - sha256: sha256(output), - bytes: statSync(output).size, - family: group.family, - target: group.target, - kind: 'extension-bundle', - memberCount: memberNames.length, - }); - } - rmSync(stageRoot, { recursive: true, force: true }); - return carrierAssets; + return assembleBundleCarrierAssets(product, version, productRoot, members, compatibility, { + root: ROOT, + fail, + }); } - export function extensionReleasePropertiesText({ product, releaseProduct = product, @@ -861,7 +721,7 @@ export function extensionReleasePropertiesText({ const propertiesLines = [ `schema=${releaseData.schema}\n`, `product=${product}\n`, - ...(releaseProduct === product + ...(releaseProduct === product && family === null ? [] : [`releaseProduct=${releaseProduct}\n`, `carrierFamily=${family ?? 'combined'}\n`]), `version=${version}\n`, @@ -927,7 +787,103 @@ export function extensionReleasePropertiesText({ return propertiesLines.join(''); } -function writeReleaseControls({ +/** Compose the canonical release documents from explicitly supplied final members. */ +export function composeExtensionReleaseDocuments({ + product, + releaseProduct = product, + family = null, + version, + members, + directAssets, + releaseMetadata, + sourceIdentity = releaseMetadata.sourceIdentity, +}) { + // A singleton frozen document also carries its leaf envelope, unlike a bundle member. + members = members.map( + ({ + schema: _schema, + product: _product, + releaseProduct: _releaseProduct, + family: _family, + version: _version, + compatibility: _compatibility, + ...member + }) => member, + ); + const ownership = + releaseProduct === product && family === null + ? {} + : { releaseProduct, family: family ?? 'combined' }; + if (members.length > 1) { + return { + manifest: { + schema: 'oliphaunt-extension-ci-artifacts-v2', + product, + ...ownership, + version, + compatibility: releaseMetadata.compatibility, + extensions: members, + carrierAssets: directAssets, + }, + releaseData: { + schema: 'oliphaunt-extension-release-manifest-v2', + product, + ...ownership, + version, + extensionClass: releaseMetadata.class, + versioning: releaseMetadata.versioning, + sourceIdentity, + compatibility: releaseMetadata.compatibility, + extensions: members.map((member) => ({ + ...member, + assets: member.assets.map(publicMemberAsset), + })), + assets: directAssets.map(publicExtensionReleaseAsset), + }, + }; + } + const member = members[0]; + return { + manifest: { + schema: 'oliphaunt-extension-ci-artifacts-v1', + product, + ...ownership, + version, + compatibility: releaseMetadata.compatibility, + ...member, + }, + releaseData: { + schema: 'oliphaunt-extension-release-manifest-v1', + product, + ...ownership, + version, + sqlName: member.sqlName, + extensionClass: releaseMetadata.class, + versioning: releaseMetadata.versioning, + sourceIdentity, + compatibility: releaseMetadata.compatibility, + dependencies: member.dependencies, + dataFiles: member.dataFiles, + extensionSqlFileNames: member.extensionSqlFileNames, + extensionSqlFilePrefixes: member.extensionSqlFilePrefixes, + createsExtension: member.createsExtension, + nativeModuleStem: member.nativeModuleStem, + ...(member.nativeDependencyModules === undefined + ? {} + : { nativeDependencyModules: member.nativeDependencyModules }), + ...(member.nativeConstructionLicenseFiles === undefined + ? {} + : { nativeConstructionLicenseFiles: member.nativeConstructionLicenseFiles }), + iosNativeDependencies: member.iosNativeDependencies, + iosRegistration: member.iosRegistration, + wasixInstall: member.wasixInstall, + sharedPreloadLibraries: member.sharedPreloadLibraries, + assets: member.assets.map(publicExtensionReleaseAsset), + }, + }; +} + +export function writeReleaseControls({ product, releaseProduct, family, @@ -937,7 +893,10 @@ function writeReleaseControls({ releaseData, releaseMetadata, directAssets, + root = ROOT, + swiftOptions = {}, }) { + const relative = (file) => path.relative(root, file).split(path.sep).join('/'); const assetDir = path.join(productRoot, 'release-assets'); const extensionManifest = path.join(productRoot, 'extension-artifacts.json'); writeFileSync(extensionManifest, `${JSON.stringify(sortValue(manifest), null, 2)}\n`, 'utf8'); @@ -950,6 +909,7 @@ function writeReleaseControls({ writeSwiftExtensionCarrierManifest(swiftCarrier, { extensionManifest, nativeRuntimeVersion: releaseMetadata.compatibility.nativeRuntimeVersion, + ...swiftOptions, }); } const releaseManifest = path.join(assetDir, `${product}-${version}-manifest.json`); @@ -979,10 +939,10 @@ function writeReleaseControls({ writeFileSync(checksumManifest, checksumLines.join(''), 'utf8'); const payloadPaths = Object.freeze(directAssets.map((asset) => asset.path)); const controlPaths = Object.freeze([ - rel(releaseManifest), - rel(propertiesManifest), - ...(swiftCarrier === null ? [] : [rel(swiftCarrier)]), - rel(checksumManifest), + relative(releaseManifest), + relative(propertiesManifest), + ...(swiftCarrier === null ? [] : [relative(swiftCarrier)]), + relative(checksumManifest), ]); const artifactPaths = [...new Set([...payloadPaths, ...controlPaths])]; writeFileSync( @@ -1005,8 +965,6 @@ function stageProductVariant( } const families = new Set(family === null ? ['native', 'wasix'] : [family]); const releaseProduct = extensionReleaseProduct(product, family ?? 'native', PREFIX); - const ownership = - releaseProduct === product ? {} : { releaseProduct, family: family ?? 'combined' }; const sqlNames = extensionSqlNames(product, PREFIX); const version = extensionReleaseVersion(product, family ?? 'native', PREFIX); const productRoot = extensionArtifactProductRoot(product, family ?? 'native', outputRoot, PREFIX); @@ -1025,75 +983,19 @@ function stageProductVariant( }), ); const releaseMetadata = extensionMetadata(product, PREFIX); - let manifest; - let releaseData; - let directAssets; - if (bundle) { - directAssets = bundleCarrierAssets( - product, - version, - productRoot, - members, - releaseMetadata.compatibility, - ); - manifest = { - schema: 'oliphaunt-extension-ci-artifacts-v2', - product, - ...ownership, - version, - compatibility: releaseMetadata.compatibility, - extensions: members, - carrierAssets: directAssets, - }; - releaseData = { - schema: 'oliphaunt-extension-release-manifest-v2', - product, - ...ownership, - version, - extensionClass: releaseMetadata.class, - versioning: releaseMetadata.versioning, - sourceIdentity: extensionSourceIdentity(product, PREFIX), - compatibility: releaseMetadata.compatibility, - extensions: members.map((member) => ({ - ...member, - assets: member.assets.map(publicMemberAsset), - })), - assets: directAssets.map(publicExtensionReleaseAsset), - }; - } else { - const member = members[0]; - directAssets = member.assets; - manifest = { - schema: 'oliphaunt-extension-ci-artifacts-v1', - product, - ...ownership, - version, - compatibility: releaseMetadata.compatibility, - ...member, - }; - releaseData = { - schema: 'oliphaunt-extension-release-manifest-v1', - product, - ...ownership, - version, - sqlName: member.sqlName, - extensionClass: releaseMetadata.class, - versioning: releaseMetadata.versioning, - sourceIdentity: extensionSourceIdentity(product, PREFIX), - compatibility: releaseMetadata.compatibility, - dependencies: member.dependencies, - dataFiles: member.dataFiles, - extensionSqlFileNames: member.extensionSqlFileNames, - extensionSqlFilePrefixes: member.extensionSqlFilePrefixes, - createsExtension: member.createsExtension, - nativeModuleStem: member.nativeModuleStem, - iosNativeDependencies: member.iosNativeDependencies, - iosRegistration: member.iosRegistration, - wasixInstall: member.wasixInstall, - sharedPreloadLibraries: member.sharedPreloadLibraries, - assets: member.assets.map(publicExtensionReleaseAsset), - }; - } + const directAssets = bundle + ? bundleCarrierAssets(product, version, productRoot, members, releaseMetadata.compatibility) + : members[0].assets; + const { manifest, releaseData } = composeExtensionReleaseDocuments({ + product, + releaseProduct, + family, + version, + members, + directAssets, + releaseMetadata, + sourceIdentity: extensionSourceIdentity(product, PREFIX), + }); writeReleaseControls({ product, releaseProduct, diff --git a/src/extensions/artifacts/packages/tools/bundle-carrier-assets.mts b/src/extensions/artifacts/packages/tools/bundle-carrier-assets.mts new file mode 100644 index 000000000..aa606ec03 --- /dev/null +++ b/src/extensions/artifacts/packages/tools/bundle-carrier-assets.mts @@ -0,0 +1,201 @@ +/** Canonical contrib bundle archive assembly shared by declared producers. */ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + copyFileSync, + mkdirSync, + readFileSync, + rmSync, + statSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { createDeterministicTar } from '../../../../../tools/packaging/cargo-source-package.mts'; +import { canonicalGzipSync } from '../../../../../tools/packaging/portable-archive.mts'; +import { + assertReleaseNoticesInArchive, + stageReleaseNotices, +} from '../../../../../tools/packaging/release-notices.mts'; +import { + assertExtensionUpstreamLicensesInArchive, + extensionCarrierLegalContract, + stageExtensionUpstreamLicenses, +} from '../../../tools/extension-upstream-licenses.mts'; + +const compareText = (left: string, right: string) => (left < right ? -1 : left > right ? 1 : 0); +const sha256 = (file: string) => createHash('sha256').update(readFileSync(file)).digest('hex'); +function sortValue(value: any): any { + if (Array.isArray(value)) return value.map(sortValue); + if (value !== null && typeof value === 'object') + return Object.fromEntries( + Object.keys(value) + .sort(compareText) + .map((key) => [key, sortValue(value[key])]), + ); + return value; +} + +export function bundleCarrierAssets( + product, + version, + productRoot, + members, + compatibility, + { + root, + fail = (message: string): never => { + throw new Error(message); + }, + }, +) { + const rel = (file: string) => path.relative(root, file).split(path.sep).join('/'); + assert.equal( + new Set(members.map((member) => member.sqlName)).size, + members.length, + 'bundle members must be unique', + ); + const assetDir = path.join(productRoot, 'release-assets'); + const stageRoot = path.join(productRoot, '.bundle-stage'); + const groups = new Map(); + for (const member of members) { + for (const asset of member.assets) { + const key = `${asset.family}\0${asset.target}`; + const group = groups.get(key) ?? { family: asset.family, target: asset.target, rows: [] }; + group.rows.push({ sqlName: member.sqlName, asset }); + groups.set(key, group); + } + } + const carrierAssets = []; + for (const group of [...groups.values()].sort((left, right) => + compareText(`${left.family}\0${left.target}`, `${right.family}\0${right.target}`), + )) { + const memberNames = [...new Set(group.rows.map((row) => row.sqlName))].sort(compareText); + const expectedNames = members.map((member) => member.sqlName).sort(compareText); + if (JSON.stringify(memberNames) !== JSON.stringify(expectedNames)) { + fail( + `${product} ${group.family}/${group.target} bundle is missing exact members: expected ${expectedNames.join(',')}, got ${memberNames.join(',')}`, + ); + } + const archiveRoot = `${product}-${version}-${group.family}-${group.target}-bundle`; + const stageDir = path.join(stageRoot, archiveRoot); + rmSync(stageDir, { recursive: true, force: true }); + mkdirSync(stageDir, { recursive: true }); + const manifestMembers = []; + for (const row of group.rows.sort((left, right) => + compareText( + `${left.sqlName}\0${left.asset.kind}\0${left.asset.identity ?? ''}`, + `${right.sqlName}\0${right.asset.kind}\0${right.asset.identity ?? ''}`, + ), + )) { + const memberPath = `extensions/${row.sqlName}/${row.asset.name}`; + const source = path.resolve(root, row.asset.path); + assert( + !path.relative(root, source).startsWith('..') && + !path.isAbsolute(path.relative(root, source)), + 'bundle member must be a declared root-relative file', + ); + assert( + !memberPath + .split('/') + .some((part) => !part || part === '.' || part === '..' || part.includes('\\\\')), + 'bundle member path must be safe', + ); + const destination = path.join(stageDir, ...memberPath.split('/')); + mkdirSync(path.dirname(destination), { recursive: true }); + copyFileSync(source, destination); + chmodSync(destination, 0o644); + const copiedSha256 = sha256(destination); + const copiedBytes = statSync(destination).size; + if (copiedSha256 !== row.asset.sha256 || copiedBytes !== row.asset.bytes) { + fail( + `${product} ${group.family}/${group.target} changed ${row.sqlName} member bytes while staging ${memberPath}`, + ); + } + const member = { + sqlName: row.sqlName, + kind: row.asset.kind, + identity: row.asset.identity ?? null, + path: memberPath, + sha256: row.asset.sha256, + bytes: row.asset.bytes, + }; + manifestMembers.push(member); + row.asset.carrierAsset = `${archiveRoot}.tar.gz`; + row.asset.carrierRoot = archiveRoot; + row.asset.memberPath = memberPath; + } + const externalLicenseFiles = []; + for (const sqlName of memberNames) { + externalLicenseFiles.push(...stageExtensionUpstreamLicenses(sqlName, stageDir)); + } + const legal = extensionCarrierLegalContract(product, memberNames, { + family: group.family, + target: group.target, + memberContracts: members, + }); + const stagedLicenseFiles = [...new Set(externalLicenseFiles)].sort(compareText); + if (JSON.stringify(stagedLicenseFiles) !== JSON.stringify(legal.licenseFiles)) { + fail( + `${product} ${group.family}/${group.target} staged upstream licenses differ from its legal contract: ` + + `expected ${legal.licenseFiles.join(',')}, got ${stagedLicenseFiles.join(',')}`, + ); + } + const bundleManifest = path.join(stageDir, 'bundle-manifest.json'); + writeFileSync( + bundleManifest, + `${JSON.stringify( + sortValue({ + schema: 'oliphaunt-extension-bundle-v1', + product, + version, + compatibility, + family: group.family, + target: group.target, + licenseProfile: legal.profile, + licenseFiles: legal.licenseFiles, + members: manifestMembers, + }), + null, + 2, + )}\n`, + 'utf8', + ); + chmodSync(bundleManifest, 0o644); + stageReleaseNotices(stageDir, { profile: legal.profile }); + const output = path.join(assetDir, `${archiveRoot}.tar.gz`); + writeFileSync( + output, + canonicalGzipSync( + createDeterministicTar(stageDir, archiveRoot, { + fail, + includeDirectories: false, + // Every bundle member is data. Windows filesystem modes are synthetic, + // so encode the portable carrier contract instead of copying stat bits. + fixedFileMode: 0o644, + }), + ), + ); + assertReleaseNoticesInArchive(output, { + prefix: archiveRoot, + profile: legal.profile, + }); + if (legal.upstreamMembers.length > 0) { + assertExtensionUpstreamLicensesInArchive(legal.upstreamMembers, output, { + prefix: archiveRoot, + }); + } + carrierAssets.push({ + name: path.basename(output), + path: rel(output), + sha256: sha256(output), + bytes: statSync(output).size, + family: group.family, + target: group.target, + kind: 'extension-bundle', + memberCount: memberNames.length, + }); + } + rmSync(stageRoot, { recursive: true, force: true }); + return carrierAssets; +} diff --git a/src/extensions/artifacts/packages/tools/check-carriers.mts b/src/extensions/artifacts/packages/tools/check-carriers.mts index 33118746f..cc9085353 100644 --- a/src/extensions/artifacts/packages/tools/check-carriers.mts +++ b/src/extensions/artifacts/packages/tools/check-carriers.mts @@ -1,10 +1,6 @@ import { createHash } from 'node:crypto'; import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'; import path from 'node:path'; -import { - buildSwiftExtensionCarrierManifest, - swiftExtensionCarrierAssetName, -} from '../../../../native/sdks/swift/tools/ios-carrier-manifest.mts'; import { portableMemberName, readFileOnlyTarGzipEntries, @@ -36,12 +32,21 @@ import { extensionSqlNames, ROOT, } from '../../../../../tools/release/release-artifact-targets.mts'; +import { + buildSwiftExtensionCarrierManifest, + swiftExtensionCarrierAssetName, +} from '../../../../native/sdks/swift/tools/ios-carrier-manifest.mts'; import { assertWasixExtensionMemberInstall } from '../../../contracts/wasix-extension-install.mts'; import { assertExtensionUpstreamLicensesInArchive, extensionCarrierLegalContract, } from '../../../tools/extension-upstream-licenses.mts'; -import { extensionRuntimeAssetContract } from './extension-runtime-asset-contract.mts'; +import { + expectedExtensionRoles, + extensionRuntimeAssetContract, + projectNativeRuntimeAssetMember, +} from './extension-runtime-asset-contract.mts'; +import { frozenExtensionMemberInventory } from './package-extension-release-carriers.mts'; export const EXTENSION_ROOT = path.resolve( ROOT, @@ -250,6 +255,26 @@ function requireExactKeys(value, expected, context) { } } +function nativeInventoryKeys(value) { + return ['nativeDependencyModules', 'nativeConstructionLicenseFiles'].filter((key) => + Object.hasOwn(value, key), + ); +} + +function requireRuntimeAssetKeys(asset, expected, member, context, product, version) { + const optional = nativeInventoryKeys(asset); + requireExactKeys(asset, new Set([...expected, ...optional]), context); + if (optional.length > 0) { + if (asset.family !== 'native' || asset.kind !== 'runtime') + fail(`${context} construction inventory requires a native runtime asset`); + try { + frozenExtensionMemberInventory(member, { product, version, target: asset.target, asset }); + } catch (error) { + fail(`${context}: ${error.message}`); + } + } +} + function requireSortedUniqueStrings(value, context) { if ( !Array.isArray(value) || @@ -284,7 +309,13 @@ export function expectedExtensionBundleManifest({ product, version, data, carrie const legal = extensionCarrierLegalContract( product, [...new Set(rows.map(({ member }) => member.sqlName))].sort(compareText), - { family: carrier.family, target: carrier.target }, + { + family: carrier.family, + target: carrier.target, + memberContracts: rows.map(({ member, asset }) => + projectNativeRuntimeAssetMember(member, asset), + ), + }, ); return { schema: 'oliphaunt-extension-bundle-v1', @@ -306,32 +337,10 @@ export function expectedExtensionBundleManifest({ product, version, data, carrie }; } -function expectedExtensionRoles(member, targets) { - const roles = []; - const nativeStem = - typeof member.nativeModuleStem === 'string' && member.nativeModuleStem - ? member.nativeModuleStem - : null; - for (const target of [...targets].sort(compareText)) { - if (target === 'wasix-portable') { - roles.push(`wasix:${target}:wasix-runtime:`); - continue; - } - roles.push(`native:${target}:runtime:`); - if (target === 'ios-xcframework' && nativeStem !== null) { - roles.push(`native:${target}:ios-xcframework:${nativeStem}`); - for (const dependency of member.iosNativeDependencies) { - roles.push(`native:${target}:ios-dependency-xcframework:${dependency}`); - } - } - } - return roles.sort(compareText); -} - function validateBundleMemberMetadata(member, manifest, stagedTargets) { requireExactKeys( member, - EXTENSION_BUNDLE_MEMBER_KEYS, + new Set([...EXTENSION_BUNDLE_MEMBER_KEYS, ...nativeInventoryKeys(member)]), `${rel(manifest)} member ${JSON.stringify(member?.sqlName)}`, ); if (typeof member.sqlName !== 'string' || !member.sqlName) { @@ -418,7 +427,7 @@ async function checkExtensionBundleProduct( { family, requireFullTargets }, ) { const releaseProduct = extensionReleaseProduct(product, family ?? 'native', PREFIX); - const ownership = releaseProduct === product ? {} : { releaseProduct, family }; + const ownership = releaseProduct === product && family === null ? {} : { releaseProduct, family }; requireExactKeys( data, new Set([...INTERNAL_EXTENSION_BUNDLE_ROOT_KEYS, ...Object.keys(ownership)]), @@ -521,7 +530,18 @@ async function checkExtensionBundleProduct( `${rel(manifest)} aggregate carrier ${name} is missing or does not match its outer size/digest`, ); } - const legal = extensionCarrierLegalContract(product, expectedSqlNames, { family, target }); + const legal = extensionCarrierLegalContract(product, expectedSqlNames, { + family, + target, + memberContracts: data.extensions.map((member) => { + const asset = member.assets.find( + (row) => row.family === family && row.target === target && row.kind === 'runtime', + ); + return asset + ? frozenExtensionMemberInventory(member, { product, version, target, asset }) + : member; + }), + }); const carrierRoot = name.replace(/\.tar\.gz$/u, ''); assertReleaseNoticesInArchive(carrierPath, { prefix: carrierRoot, @@ -553,10 +573,13 @@ async function checkExtensionBundleProduct( const roles = new Set(); const memberTargets = new Set(); for (const asset of member.assets) { - requireExactKeys( + requireRuntimeAssetKeys( asset, INTERNAL_EXTENSION_BUNDLE_MEMBER_ASSET_KEYS, + member, `${rel(manifest)} member ${member.sqlName} asset ${JSON.stringify(asset?.name)}`, + product, + version, ); const { name, @@ -778,14 +801,17 @@ async function checkExtensionBundleProduct( for (const member of releaseData.extensions) { requireExactKeys( member, - EXTENSION_BUNDLE_MEMBER_KEYS, + new Set([...EXTENSION_BUNDLE_MEMBER_KEYS, ...nativeInventoryKeys(member)]), `${rel(releaseManifest)} member ${member?.sqlName}`, ); for (const asset of member.assets) { - requireExactKeys( + requireRuntimeAssetKeys( asset, PUBLIC_EXTENSION_BUNDLE_MEMBER_ASSET_KEYS, + member, `${rel(releaseManifest)} member ${member.sqlName} asset ${asset?.name}`, + product, + version, ); } } @@ -838,7 +864,9 @@ async function checkExtensionBundleProduct( const expectedProperties = { schema: 'oliphaunt-extension-release-manifest-v2', product, - ...(releaseProduct === product ? {} : { releaseProduct, carrierFamily: family }), + ...(releaseProduct === product && family === null + ? {} + : { releaseProduct, carrierFamily: family }), version: String(version), extensionClass: String(releaseData.extensionClass), versioning: String(releaseData.versioning), @@ -911,7 +939,7 @@ async function checkExtensionProductVariant( }); } const releaseProduct = extensionReleaseProduct(product, family ?? 'native', PREFIX); - const ownership = releaseProduct === product ? {} : { releaseProduct, family }; + const ownership = releaseProduct === product && family === null ? {} : { releaseProduct, family }; const expected = { schema: 'oliphaunt-extension-ci-artifacts-v1', product, @@ -1115,6 +1143,12 @@ async function checkExtensionProductVariant( extensionSqlFileNames: data.extensionSqlFileNames, extensionSqlFilePrefixes: data.extensionSqlFilePrefixes, nativeModuleStem: data.nativeModuleStem, + ...(data.nativeDependencyModules === undefined + ? {} + : { nativeDependencyModules: data.nativeDependencyModules }), + ...(data.nativeConstructionLicenseFiles === undefined + ? {} + : { nativeConstructionLicenseFiles: data.nativeConstructionLicenseFiles }), iosNativeDependencies: data.iosNativeDependencies, iosRegistration: data.iosRegistration, wasixInstall: data.wasixInstall, @@ -1123,7 +1157,11 @@ async function checkExtensionProductVariant( }; requireExactKeys( releaseData, - new Set([...PUBLIC_EXTENSION_RELEASE_MANIFEST_KEYS, ...Object.keys(ownership)]), + new Set([ + ...PUBLIC_EXTENSION_RELEASE_MANIFEST_KEYS, + ...Object.keys(ownership), + ...nativeInventoryKeys(data), + ]), rel(releaseManifest), ); if (!deepEqual(releaseData, expectedRelease)) { @@ -1156,11 +1194,14 @@ async function checkExtensionProductVariant( if (asset === null || Array.isArray(asset) || typeof asset !== 'object') { fail(`${rel(releaseManifest)} contains a non-object public asset row`); } - if (!setEquals(new Set(Object.keys(asset)), PUBLIC_EXTENSION_RELEASE_ASSET_KEYS)) { - fail( - `${rel(releaseManifest)} public asset ${JSON.stringify(asset.name)} keys must be ${JSON.stringify([...PUBLIC_EXTENSION_RELEASE_ASSET_KEYS].sort(compareText))}, got ${JSON.stringify(Object.keys(asset).sort(compareText))}`, - ); - } + requireRuntimeAssetKeys( + asset, + PUBLIC_EXTENSION_RELEASE_ASSET_KEYS, + releaseData, + `${rel(releaseManifest)} public asset ${JSON.stringify(asset.name)}`, + product, + expected.version, + ); } const propertiesManifest = path.join( root, @@ -1174,7 +1215,9 @@ async function checkExtensionProductVariant( const expectedProperties = { schema: 'oliphaunt-extension-release-manifest-v1', product, - ...(releaseProduct === product ? {} : { releaseProduct, carrierFamily: family }), + ...(releaseProduct === product && family === null + ? {} + : { releaseProduct, carrierFamily: family }), version: String(expected.version), sqlName: String(expectedSqlName), extensionClass: String(releaseData.extensionClass), diff --git a/src/extensions/artifacts/packages/tools/check-carriers.test.mts b/src/extensions/artifacts/packages/tools/check-carriers.test.mts index b603d9117..ea62259ca 100644 --- a/src/extensions/artifacts/packages/tools/check-carriers.test.mts +++ b/src/extensions/artifacts/packages/tools/check-carriers.test.mts @@ -1,8 +1,297 @@ import test from 'node:test'; import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; import { expectedExtensionBundleManifest } from './check-carriers.mts'; -import { extensionReleasePropertiesText } from './build-extension-ci-artifacts.mts'; +import { + composeExtensionReleaseDocuments, + extensionReleasePropertiesText, + writeReleaseControls, +} from './build-extension-ci-artifacts.mts'; import { parseUniquePropertiesText } from '../../../../../tools/packaging/release-carrier.mts'; +import { createDeterministicTar } from '../../../../../tools/packaging/cargo-source-package.mts'; +import { canonicalGzipSync } from '../../../../../tools/packaging/portable-archive.mts'; +import { + extensionMetadata, + extensionSourceIdentity, + ROOT, +} from '../../../../../tools/release/release-artifact-targets.mts'; +import { loadPublicationCatalog } from '../../../../../tools/release/publication-catalog.mts'; +import { extensionGithubReleaseFixture } from '../../../../../tools/release/testdata/publication-artifact-fixtures.mts'; +import { bundleCarrierAssets } from './bundle-carrier-assets.mts'; + +test('checks composed singleton and bundle optional member facts against their frozen values', () => { + mkdirSync(path.join(ROOT, 'target'), { recursive: true }); + const root = mkdtempSync(path.join(ROOT, 'target/check-carriers-optional-')); + try { + const payloadRoot = path.join(root, 'payload'); + mkdirSync(payloadRoot); + writeFileSync(path.join(payloadRoot, 'fixture.txt'), 'runtime fixture\n'); + const payload = canonicalGzipSync(createDeterministicTar(payloadRoot, 'runtime', {})); + for (const [id, product] of [ + ['oliphaunt-extension-vector', 'oliphaunt-extension-vector'], + ['liboliphaunt-native', 'oliphaunt-extension-contrib-pg18'], + ]) { + const catalogProduct = loadPublicationCatalog('check-carriers.test', { products: [id] }) + .products[0]; + const fixture = extensionGithubReleaseFixture(root, catalogProduct, { + artifactProduct: product, + family: 'native', + }); + const frozen = JSON.parse(readFileSync(fixture.manifestPath, 'utf8')); + const members = frozen.extensions ?? [frozen]; + rmSync(fixture.directory, { recursive: true }); + mkdirSync(fixture.directory); + for (const member of members) { + member.iosNativeDependencies = []; + member.iosRegistration = null; + member.assets = member.assets + .filter((asset) => asset.target === 'linux-x64-gnu') + .map((asset) => { + writeFileSync(asset.path, payload); + return { + ...asset, + source: 'fixture', + path: path.relative(ROOT, asset.path).split(path.sep).join('/'), + sha256: createHash('sha256').update(payload).digest('hex'), + bytes: payload.length, + }; + }); + } + const productRoot = path.dirname(fixture.manifestPath); + const directAssets = + members.length === 1 + ? members[0].assets + : bundleCarrierAssets( + product, + frozen.version, + productRoot, + members, + frozen.compatibility, + { + root: ROOT, + }, + ); + const metadata = extensionMetadata(product, 'check-carriers.test'); + const controls = () => + writeReleaseControls({ + product, + releaseProduct: id, + family: 'native', + version: frozen.version, + members, + directAssets, + productRoot, + releaseMetadata: metadata, + ...composeExtensionReleaseDocuments({ + product, + releaseProduct: id, + family: 'native', + version: frozen.version, + members, + directAssets, + releaseMetadata: metadata, + sourceIdentity: extensionSourceIdentity(product, 'check-carriers.test'), + }), + }); + const check = () => + spawnSync( + process.execPath, + [ + '--no-env-file', + '--no-install', + path.join(import.meta.dir, 'check-carriers.mts'), + product, + '--family', + 'native', + ], + { + cwd: ROOT, + env: { + ...process.env, + OLIPHAUNT_EXTENSION_ARTIFACT_ROOT: path.relative( + ROOT, + path.join(root, 'target/extension-artifacts'), + ), + }, + encoding: 'utf8', + }, + ); + controls(); + let result = check(); + assert.equal(result.status, 0, result.stderr); + const selected = members.find((member) => member.nativeModuleStem !== null); + selected.nativeDependencyModules = ['fixture.so']; + selected.nativeConstructionLicenseFiles = []; + controls(); + result = check(); + assert.equal(result.status, 0, result.stderr); + for (const field of ['nativeDependencyModules', 'nativeConstructionLicenseFiles']) { + const { releaseManifest } = controls(); + const publicDocument = JSON.parse(readFileSync(releaseManifest, 'utf8')); + const publicMember = + publicDocument.extensions?.find((member) => member.sqlName === selected.sqlName) ?? + publicDocument; + delete publicMember[field]; + writeFileSync(releaseManifest, JSON.stringify(publicDocument)); + result = check(); + assert.notEqual(result.status, 0); + assert.match(result.stderr, /keys must be|must exactly match stable metadata/u); + } + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('explicit external native controls retain their family while combined defaults stay unchanged', () => { + const product = 'oliphaunt-extension-pgtap'; + const inputs = { + product, + version: '9.1.0', + members: [ + { + sqlName: 'pgtap', + createsExtension: true, + dependencies: [], + dataFiles: [], + extensionSqlFileNames: [], + extensionSqlFilePrefixes: [], + nativeModuleStem: null, + iosNativeDependencies: [], + iosRegistration: null, + wasixInstall: null, + sharedPreloadLibraries: [], + assets: [], + }, + ], + directAssets: [], + releaseMetadata: { + class: 'external', + versioning: 'independent', + sourceIdentity: { kind: 'git' }, + compatibility: {}, + }, + }; + const legacy = composeExtensionReleaseDocuments(inputs); + for (const document of [legacy.manifest, legacy.releaseData]) { + assert.equal(Object.hasOwn(document, 'releaseProduct'), false); + assert.equal(Object.hasOwn(document, 'family'), false); + } + const legacyProperties = parseUniquePropertiesText( + extensionReleasePropertiesText({ + ...inputs, + ...legacy, + }), + ); + assert.equal(legacyProperties.releaseProduct, undefined); + assert.equal(legacyProperties.carrierFamily, undefined); + + const native = composeExtensionReleaseDocuments({ ...inputs, family: 'native' }); + for (const document of [native.manifest, native.releaseData]) { + assert.equal(document.releaseProduct, product); + assert.equal(document.family, 'native'); + } + const nativeBefore = structuredClone(native.manifest); + const combined = composeExtensionReleaseDocuments({ ...inputs, members: [native.manifest] }); + for (const document of [combined.manifest, combined.releaseData]) { + assert.equal(Object.hasOwn(document, 'releaseProduct'), false); + assert.equal(Object.hasOwn(document, 'family'), false); + } + assert.deepEqual(native.manifest, nativeBefore); + + const member = { + ...inputs.members[0], + assets: [ + { + name: 'fixture.tar.gz', + family: 'native', + target: 'linux-x64-gnu', + kind: 'runtime', + identity: null, + sha256: 'a'.repeat(64), + bytes: 1, + }, + ], + }; + const envelope = ['schema', 'product', 'releaseProduct', 'family', 'version', 'compatibility']; + for (const count of [1, 2]) { + const members = Array.from({ length: count }, (_, index) => ({ + ...member, + sqlName: `member${index}`, + schema: 'foreign-schema', + product: 'foreign-product', + releaseProduct: 'foreign-owner', + family: 'foreign-family', + version: '0.0.0', + compatibility: { foreign: true }, + })); + const before = structuredClone(members); + for (const ownership of [ + { releaseProduct: product, family: null }, + { releaseProduct: product, family: 'native' }, + { releaseProduct: 'liboliphaunt-wasix', family: 'wasix' }, + ]) { + const documents = composeExtensionReleaseDocuments({ + ...inputs, + ...ownership, + members, + directAssets: member.assets, + }); + for (const [kind, document] of Object.entries(documents)) { + assert.equal( + document.schema, + `oliphaunt-extension-${kind === 'manifest' ? 'ci-artifacts' : 'release-manifest'}-v${count}`, + ); + assert.equal(document.product, product); + assert.equal(document.version, inputs.version); + assert.deepEqual(document.compatibility, inputs.releaseMetadata.compatibility); + if (count === 2) + assert.deepEqual( + document[kind === 'manifest' ? 'carrierAssets' : 'assets'], + member.assets, + ); + if (ownership.family === null) { + assert.equal(Object.hasOwn(document, 'releaseProduct'), false); + assert.equal(Object.hasOwn(document, 'family'), false); + } else { + assert.equal(document.releaseProduct, ownership.releaseProduct); + assert.equal(document.family, ownership.family); + } + for (const [index, row] of (count === 1 ? [document] : document.extensions).entries()) { + for (const [key, value] of Object.entries({ ...member, sqlName: `member${index}` })) + assert.deepEqual(row[key], value); + if (count === 2) for (const key of envelope) assert.equal(Object.hasOwn(row, key), false); + } + } + } + assert.deepEqual(members, before); + } + const root = mkdtempSync(path.join(tmpdir(), 'external-native-controls-test-')); + try { + const productRoot = path.join(root, product); + mkdirSync(path.join(productRoot, 'release-assets'), { recursive: true }); + const controls = writeReleaseControls({ + ...inputs, + ...native, + releaseProduct: product, + family: 'native', + productRoot, + root, + }); + const manifest = JSON.parse(readFileSync(controls.releaseManifest, 'utf8')); + assert.equal(manifest.releaseProduct, product); + assert.equal(manifest.family, 'native'); + const properties = parseUniquePropertiesText(readFileSync(controls.propertiesManifest, 'utf8')); + assert.equal(properties.releaseProduct, product); + assert.equal(properties.carrierFamily, 'native'); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); test('derives nested bundle compatibility from the staged bundle data', () => { const compatibility = { diff --git a/src/extensions/artifacts/packages/tools/contrib-carriers.mts b/src/extensions/artifacts/packages/tools/contrib-carriers.mts index 663559938..4f5431a07 100644 --- a/src/extensions/artifacts/packages/tools/contrib-carriers.mts +++ b/src/extensions/artifacts/packages/tools/contrib-carriers.mts @@ -7,10 +7,10 @@ function fail(prefix, message) { throw new Error(`${prefix}: ${message}`); } -function toml(root, relativePath, prefix) { +function toml(root, relativePath, prefix, readText) { const file = path.join(root, relativePath); if (!existsSync(file)) fail(prefix, `missing ${relativePath}`); - const value = Bun.TOML.parse(readFileSync(file, 'utf8')); + const value = Bun.TOML.parse(readText(relativePath)); if (value === null || Array.isArray(value) || typeof value !== 'object') { fail(prefix, `${relativePath} must contain a TOML table`); } @@ -23,15 +23,19 @@ function string(value, context, prefix) { return value; } -export function loadContribCarriers(root, prefix = 'contrib-carriers') { - const descriptor = toml(root, CONTRIB_CARRIERS_PATH, prefix); +export function loadContribCarriers( + root, + prefix = 'contrib-carriers', + { readText = (relativePath) => readFileSync(path.join(root, relativePath), 'utf8') } = {}, +) { + const descriptor = toml(root, CONTRIB_CARRIERS_PATH, prefix, readText); const artifactProduct = string(descriptor.logical_product, 'logical_product', prefix); const memberManifest = string(descriptor.member_manifest, 'member_manifest', prefix); const source = string(descriptor.source, 'source', prefix); const contract = string(descriptor.contract, 'contract', prefix); const nativeOwner = string(descriptor.native_owner, 'native_owner', prefix); const wasixOwner = string(descriptor.wasix_owner, 'wasix_owner', prefix); - const members = toml(root, memberManifest, prefix).extensions; + const members = toml(root, memberManifest, prefix, readText).extensions; if ( !Array.isArray(members) || members.some( @@ -56,6 +60,7 @@ export function loadContribCarriers(root, prefix = 'contrib-carriers') { ]; for (const file of inputFiles) { if (!existsSync(path.join(root, file))) fail(prefix, `missing contrib carrier input ${file}`); + readText(file); } return { artifactProduct, diff --git a/src/extensions/artifacts/packages/tools/extension-artifact-inventory.mts b/src/extensions/artifacts/packages/tools/extension-artifact-inventory.mts index 96f8ca457..79ab015ed 100644 --- a/src/extensions/artifacts/packages/tools/extension-artifact-inventory.mts +++ b/src/extensions/artifacts/packages/tools/extension-artifact-inventory.mts @@ -2,6 +2,7 @@ import { createHash } from 'node:crypto'; import { closeSync, constants, + existsSync, fstatSync, lstatSync, openSync, @@ -11,14 +12,18 @@ import { import path from 'node:path'; import { TextDecoder } from 'node:util'; import { strictGunzip } from '../../../../../tools/packaging/portable-archive.mts'; - +import { releaseNoticeRows } from '../../../../../tools/packaging/release-notices.mts'; +import { extensionProductForSqlName } from '../../../../../tools/release/release-artifact-targets.mts'; +import { + nativeExtensionDependencyModulePaths, + nativeExtensionModuleHostTarget, +} from '../../../contracts/extension-target-profiles.mts'; import { EXTENSION_ARTIFACT_ARCHIVE_POLICY } from '../../../tools/extension-artifact-archive-policy.mts'; import { extensionCarrierLegalContract, extensionUpstreamLicenseRow, + validateNativeExtensionConstructionLicenseInventory, } from '../../../tools/extension-upstream-licenses.mts'; -import { extensionProductForSqlName } from '../../../../../tools/release/release-artifact-targets.mts'; -import { releaseNoticeRows } from '../../../../../tools/packaging/release-notices.mts'; export const EXTENSION_ARTIFACT_PROPERTY_KEYS = Object.freeze([ 'packageLayout', @@ -454,6 +459,12 @@ function normalizeMetadata(row, label) { extensionSqlFileNames: list('extensionSqlFileNames', 'extension-sql-file-names'), extensionSqlFilePrefixes: list('extensionSqlFilePrefixes', 'extension-sql-file-prefixes'), sharedPreloadLibraries: list('sharedPreloadLibraries', 'shared-preload-libraries'), + nativeDependencyModules: list( + 'nativeDependencyModules', + 'native-dependency-modules', + row?.nativeDependencyModules ?? [], + ), + nativeConstructionLicenseFiles: row?.nativeConstructionLicenseFiles ?? [], }; for (const [field, values] of [ ['selected-extension-dependencies', metadata.dependencies], @@ -463,6 +474,13 @@ function normalizeMetadata(row, label) { throw inventoryError(label, `${field} contains a non-portable identifier`); } } + if ( + metadata.nativeDependencyModules.some( + (file) => !/^[A-Za-z0-9_-]+\.(?:so|dylib|dll)$/u.test(file), + ) + ) { + throw inventoryError(label, 'native-dependency-modules must contain portable module basenames'); + } if ( metadata.extensionSqlFileNames.some( (item) => path.posix.basename(item) !== item || !item.endsWith('.sql'), @@ -481,12 +499,41 @@ function normalizeMetadata(row, label) { return metadata; } -function moduleSuffix(target) { +export function moduleSuffix(target) { if (target === 'windows-x64-msvc') return '.dll'; if (target === 'macos-arm64' || target === 'ios-xcframework') return '.dylib'; return '.so'; } +export function isDesktopNativeTarget(target) { + return DESKTOP_NATIVE_TARGETS.has(target); +} + +/** Project the canonical recipe's module stems into an existing desktop profile. */ +export const nativeModuleHostTarget = nativeExtensionModuleHostTarget; + +export function nativeDependencyModuleBasenames(files = [], target, byTarget = {}) { + const hostTarget = nativeModuleHostTarget(target); + if (!isDesktopNativeTarget(hostTarget)) { + if (files.length === 0) return []; + throw inventoryError( + 'native dependency modules', + `target ${target} has no desktop module contract`, + ); + } + return nativeExtensionDependencyModulePaths(files, target, byTarget) + .map((file) => { + const match = /^lib\/postgresql\/([A-Za-z0-9_-]+)\.(?:so|dylib|dll)$/u.exec(file); + if (!match) + throw inventoryError( + 'native dependency modules', + 'canonical recipe requires a portable PostgreSQL module destination', + ); + return match[1] + moduleSuffix(hostTarget); + }) + .sort(compareText); +} + function sqlFileOwned(fileName, metadata) { return ( (metadata.createsExtension && fileName === `${metadata.sqlName}.control`) || @@ -665,16 +712,14 @@ function validateStaticLinkage(properties, metadata, target, label) { } } -function canonicalLegalContract(metadata, target, label) { +function canonicalLegalContract(metadata, target, label, product) { let contract; try { - const product = extensionProductForSqlName( - metadata.sqlName, - 'extension-artifact-inventory.mts', - ); + product ??= extensionProductForSqlName(metadata.sqlName, 'extension-artifact-inventory.mts'); contract = extensionCarrierLegalContract(product, [metadata.sqlName], { family: 'native', target, + memberContracts: [metadata], }); } catch (cause) { throw inventoryError(label, `cannot resolve canonical legal contract: ${cause.message}`); @@ -707,6 +752,20 @@ function canonicalLegalContract(metadata, target, label) { for (const row of upstreamFiles) { add(`files/${row.destination}`, row.sha256, `${metadata.sqlName}:${row.path}`); } + const construction = validateNativeExtensionConstructionLicenseInventory( + metadata.sqlName, + target, + metadata.nativeConstructionLicenseFiles, + ); + for (const row of construction) + add(`files/${row.path}`, row.sha256, 'immutable construction source'); + if (construction.length > 0) + contract = { + ...contract, + licenseFiles: [...contract.licenseFiles, ...construction.map((row) => row.path)].sort( + compareText, + ), + }; return { contract, members }; } @@ -719,12 +778,15 @@ export function validateExtensionArtifactEntries({ metadata: rawMetadata, target, nativeRuntimeVersion, + product, label, + mobileContract, }) { - if (!DESKTOP_NATIVE_TARGETS.has(target)) { + const desktop = DESKTOP_NATIVE_TARGETS.has(target); + if (!desktop && mobileContract?.target !== target) { throw inventoryError( label, - `native target ${JSON.stringify(target)} is not a canonical desktop target`, + `native target ${JSON.stringify(target)} requires its declared mobile inventory contract`, ); } if ( @@ -740,7 +802,26 @@ export function validateExtensionArtifactEntries({ decodeUtf8(manifestEntry.data, `${label} manifest.properties`), `${label} manifest.properties`, ); - const legal = canonicalLegalContract(metadata, target, label); + const legal = canonicalLegalContract(metadata, target, label, product); + if (metadata.nativeDependencyModules.length > 0) { + const recipePath = path.resolve( + import.meta.dirname, + '../../../external', + metadata.sqlName, + 'recipe.toml', + ); + if (!existsSync(recipePath)) + throw inventoryError(label, 'native dependency modules require their canonical recipe'); + const recipe = Bun.TOML.parse(readFileSync(recipePath, 'utf8')); + const declared = nativeDependencyModuleBasenames( + recipe.artifacts?.native_dependency_modules, + target, + recipe.artifacts?.native_dependency_modules_by_target, + ); + if (JSON.stringify(declared) !== JSON.stringify(metadata.nativeDependencyModules)) { + throw inventoryError(label, 'native dependency modules differ from the canonical recipe'); + } + } const expectedProperties = new Map([ ['packageLayout', 'oliphaunt-extension-artifact-v1'], ['pgMajor', '18'], @@ -777,6 +858,23 @@ export function validateExtensionArtifactEntries({ throw inventoryError(label, 'manifest mobilePrebuilt must be yes or no'); } validateStaticLinkage(properties, metadata, target, label); + if (!desktop) { + const expectedMobile = new Map([ + ['mobilePrebuilt', metadata.nativeModuleStem === null ? 'no' : 'yes'], + ['mobileStaticArchives', mobileContract.archives.join(',')], + ['mobileStaticDependencyArchives', mobileContract.dependencies.join(',')], + ['staticSymbolPrefix', mobileContract.symbolPrefix], + ]); + if (mobileContract.symbolAliases !== undefined) + expectedMobile.set('staticSymbolAliases', mobileContract.symbolAliases.join(',')); + for (const [key, expected] of expectedMobile) { + if (properties.get(key) !== expected) + throw inventoryError( + label, + `manifest ${key} differs from its declared mobile inventory contract`, + ); + } + } const allowed = new Set(['manifest.properties']); for (const [member, expected] of legal.members) { @@ -832,6 +930,12 @@ export function validateExtensionArtifactEntries({ if (DESKTOP_NATIVE_TARGETS.has(target)) { allowed.add(`files/lib/modules/${properties.get('nativeModuleFile')}`); } + for (const dependency of metadata.nativeDependencyModules) { + allowed.add(`files/lib/postgresql/${dependency}`); + if (DESKTOP_NATIVE_TARGETS.has(target)) allowed.add(`files/lib/modules/${dependency}`); + } + } else if (metadata.nativeDependencyModules.length > 0) { + throw inventoryError(label, 'SQL-only artifacts must not declare native dependency modules'); } const mobilePaths = declaredMobilePaths(properties, metadata, label); if ( diff --git a/src/extensions/artifacts/packages/tools/extension-artifact-inventory.test.mts b/src/extensions/artifacts/packages/tools/extension-artifact-inventory.test.mts index 2740113a5..ef6b5f5bb 100644 --- a/src/extensions/artifacts/packages/tools/extension-artifact-inventory.test.mts +++ b/src/extensions/artifacts/packages/tools/extension-artifact-inventory.test.mts @@ -22,10 +22,80 @@ import { } from '../../../tools/extension-upstream-licenses.mts'; import { EXTENSION_ARTIFACT_PROPERTY_KEYS, + nativeDependencyModuleBasenames, parseExtensionArtifactProperties, validateExtensionArtifactArchive, } from './extension-artifact-inventory.mts'; +test('canonical native dependency stems project into desktop and mobile host module suffixes', async () => { + const recipe = Bun.TOML.parse( + await fs.readFile( + path.resolve(import.meta.dirname, '../../../external/postgis/recipe.toml'), + 'utf8', + ), + ); + const paths = recipe.artifacts.native_dependency_modules; + for (const [target, suffix] of [ + ['linux-x64-gnu', '.so'], + ['linux-arm64-gnu', '.so'], + ['macos-arm64', '.dylib'], + ['windows-x64-msvc', '.dll'], + ['ios-xcframework', '.dylib'], + ['android-arm64-v8a', '.so'], + ['android-x86_64', '.so'], + ]) { + assert.deepEqual( + nativeDependencyModuleBasenames(paths, target), + paths.map((file) => path.posix.basename(file).replace(/\.so$/u, suffix)).sort(), + ); + } + for (const invalid of [ + ['lib/modules/wrong.so'], + ['lib/postgresql/nested/wrong.so'], + ['lib/postgresql/../wrong.so'], + ['lib/postgresql/wrong.txt'], + ]) + assert.throws( + () => nativeDependencyModuleBasenames(invalid, 'windows-x64-msvc'), + /canonical recipe/u, + ); + assert.deepEqual( + nativeDependencyModuleBasenames( + paths, + 'windows-x64-msvc', + recipe.artifacts.native_dependency_modules_by_target, + ), + [], + ); + for (const target of [ + 'linux-x64-gnu', + 'linux-arm64-gnu', + 'macos-arm64', + 'ios-xcframework', + 'android-arm64-v8a', + 'android-x86_64', + ]) + assert.deepEqual( + nativeDependencyModuleBasenames( + paths, + target, + recipe.artifacts.native_dependency_modules_by_target, + ), + nativeDependencyModuleBasenames(paths, target), + ); + assert.throws( + () => + nativeDependencyModuleBasenames( + paths, + 'wasix-portable', + recipe.artifacts.native_dependency_modules_by_target, + ), + /no desktop/u, + ); + assert.throws(() => nativeDependencyModuleBasenames(paths, 'wasix-portable'), /no desktop/u); + assert.deepEqual(nativeDependencyModuleBasenames([], 'ios-xcframework'), []); +}); + function writeString(buffer, offset, length, value) { const bytes = Buffer.from(value); assert.ok(bytes.length <= length); @@ -244,6 +314,58 @@ async function main() { nativeRuntimeVersion: '1.2.3', label: 'legitimate', }); + for (const target of ['ios-xcframework', 'android-arm64-v8a', 'android-x86_64']) { + const mobileEntries = new Map(legitimate); + mobileEntries.set('manifest.properties', manifest({ nativeTarget: target })); + const file = await writeArchive(root, `${target}-metadata-fixture.tar.gz`, mobileEntries); + const mobileContract = { + target, + archives: [], + dependencies: [], + symbolPrefix: '', + symbolAliases: [], + }; + const mobile = validateExtensionArtifactArchive({ + file, + metadata: pgtapMetadata, + target, + nativeRuntimeVersion: '1.2.3', + mobileContract, + }); + assert.deepEqual(mobile.runtimeFiles, validated.runtimeFiles); + assert.throws( + () => + validateExtensionArtifactArchive({ + file, + metadata: pgtapMetadata, + target, + nativeRuntimeVersion: '1.2.3', + }), + /declared mobile inventory contract/u, + ); + assert.throws( + () => + validateExtensionArtifactArchive({ + file, + metadata: pgtapMetadata, + target, + nativeRuntimeVersion: '1.2.3', + mobileContract: { ...mobileContract, target: 'wrong-target' }, + }), + /declared mobile inventory contract/u, + ); + assert.throws( + () => + validateExtensionArtifactArchive({ + file, + metadata: pgtapMetadata, + target, + nativeRuntimeVersion: '1.2.3', + mobileContract: { ...mobileContract, dependencies: ['unselected:dependency:wrong.a'] }, + }), + /mobile inventory contract/u, + ); + } assert.deepEqual( validated.legalFiles.map(({ path: member }) => member), [...pgtapLegal.keys()].sort(), @@ -625,6 +747,65 @@ async function main() { [...postgisLegal.keys()].sort(), ); + // These synthetic archive bytes exercise the reader's alias contract; + // actual target archives are qualified by the mobile final-carrier roots. + for (const target of ['android-arm64-v8a', 'android-x86_64']) { + const archive = `mobile-static/${target}/extensions/postgis-3/liboliphaunt_extension_postgis-3.a`; + const aliases = [ + 'difference:oliphaunt_static_postgis_3_difference', + 'pg_finfo_difference:pg_finfo_oliphaunt_static_postgis_3_difference', + ]; + const contract = { + target, + archives: [`${target}:${archive}`], + dependencies: [], + symbolPrefix: 'oliphaunt_static_postgis_3', + symbolAliases: aliases, + }; + const entries = new Map(postgis); + entries.delete('files/lib/modules/postgis-3.so'); + entries.set(archive, 'synthetic target archive'); + const properties = { + sqlName: 'postgis', + nativeTarget: target, + nativeModuleStem: 'postgis-3', + nativeModuleFile: 'postgis-3.so', + dataFiles: postgisMetadata.dataFiles.join(','), + extensionSqlFileNames: '', + extensionSqlFilePrefixes: postgisMetadata.extensionSqlFilePrefixes.join(','), + mobilePrebuilt: 'yes', + mobileStaticArchives: contract.archives.join(','), + staticSymbolPrefix: contract.symbolPrefix, + staticSymbolAliases: aliases.join(','), + }; + const read = async (label, actualAliases) => { + entries.set( + 'manifest.properties', + manifest({ ...properties, staticSymbolAliases: [...actualAliases].sort().join(',') }), + ); + const file = await writeArchive(root, `postgis-${target}-${label}.tar.gz`, entries); + return () => + validateExtensionArtifactArchive({ + file, + metadata: postgisMetadata, + target, + nativeRuntimeVersion: '1.2.3', + mobileContract: contract, + }); + }; + (await read('valid', aliases))(); + for (const [label, actualAliases] of [ + ['missing', []], + ['wrong', aliases.map((value) => `${value}_wrong`)], + ['extra', [...aliases, 'extra:oliphaunt_static_postgis_3_extra']], + ]) { + assert.throws( + await read(label, actualAliases), + /staticSymbolAliases.*mobile inventory contract/u, + ); + } + } + const missingEmbeddedPostgis = new Map(postgis); missingEmbeddedPostgis.delete('files/lib/modules/postgis-3.so'); await expectArchiveFailure( diff --git a/src/extensions/artifacts/packages/tools/extension-registry-packages.mts b/src/extensions/artifacts/packages/tools/extension-registry-packages.mts index 71a27ccd3..3375068b3 100644 --- a/src/extensions/artifacts/packages/tools/extension-registry-packages.mts +++ b/src/extensions/artifacts/packages/tools/extension-registry-packages.mts @@ -1,3 +1,4 @@ +import { extensionNpmPackageForProduct } from '../../../../../tools/release/extension-release-metadata.mts'; import { AOT_TARGET_TRIPLES, expectedExtensionAotTargets, @@ -5,6 +6,8 @@ import { wasixExtensionPackageName, } from '../../../../wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; +export { extensionNpmPackageForProduct }; + function compareText(left, right) { return left < right ? -1 : left > right ? 1 : 0; } @@ -33,15 +36,6 @@ export function extensionNpmTargetPackage(sqlName, target) { return `${extensionNpmPackage(sqlName)}-${target}`; } -export function extensionNpmPackageForProduct(product) { - if (typeof product !== 'string' || !product.startsWith('oliphaunt-extension-')) { - throw new TypeError( - `extension product must start with oliphaunt-extension-: ${JSON.stringify(product)}`, - ); - } - return `@oliphaunt/${product.slice('oliphaunt-'.length)}`; -} - /** * Host-neutral npm carrier for one product's portable WASIX extension bytes. * diff --git a/src/extensions/artifacts/packages/tools/extension-runtime-asset-contract.mts b/src/extensions/artifacts/packages/tools/extension-runtime-asset-contract.mts index b3c157b7c..65f8d0be2 100644 --- a/src/extensions/artifacts/packages/tools/extension-runtime-asset-contract.mts +++ b/src/extensions/artifacts/packages/tools/extension-runtime-asset-contract.mts @@ -10,6 +10,8 @@ const EXTENSION_RUNTIME_ASSET_CONTRACT_FIELDS = Object.freeze([ 'carrierRoot', 'memberPath', 'memberCount', + 'nativeDependencyModules', + 'nativeConstructionLicenseFiles', ]); export function extensionRuntimeAssetContract(asset) { @@ -19,3 +21,44 @@ export function extensionRuntimeAssetContract(asset) { } return result; } + +/** Select the existing member inventory for one actual native runtime asset. + * Old manifests retain their member-global defaults. New joined manifests bind + * construction receipts and required modules to the asset that carries them. + */ +export function projectNativeRuntimeAssetMember(member, asset) { + const result = { ...member }; + for (const field of ['nativeDependencyModules', 'nativeConstructionLicenseFiles']) { + if (!Object.hasOwn(asset, field)) continue; + if (asset.family !== 'native' || asset.kind !== 'runtime') { + throw new Error(`${field} is only valid on a native runtime asset`); + } + if (!Array.isArray(asset[field])) throw new Error(`${field} must be an array`); + if (asset[field].length === 0) delete result[field]; + else result[field] = asset[field]; + } + return result; +} + +/** Exact public member roles from the canonical target profiles and built iOS facts. */ +export function expectedExtensionRoles(member, targets) { + const roles = []; + const nativeStem = + typeof member.nativeModuleStem === 'string' && member.nativeModuleStem + ? member.nativeModuleStem + : null; + for (const target of [...targets].sort()) { + if (target === 'wasix-portable') { + roles.push(`wasix:${target}:wasix-runtime:`); + continue; + } + roles.push(`native:${target}:runtime:`); + if (target === 'ios-xcframework' && nativeStem !== null) { + roles.push(`native:${target}:ios-xcframework:${nativeStem}`); + for (const dependency of member.iosNativeDependencies) { + roles.push(`native:${target}:ios-dependency-xcframework:${dependency}`); + } + } + } + return roles.sort(); +} diff --git a/src/extensions/artifacts/packages/tools/package-extension-cargo-facades.mts b/src/extensions/artifacts/packages/tools/package-extension-cargo-facades.mts index 919cbc5b4..9b47ddd64 100644 --- a/src/extensions/artifacts/packages/tools/package-extension-cargo-facades.mts +++ b/src/extensions/artifacts/packages/tools/package-extension-cargo-facades.mts @@ -97,16 +97,89 @@ export function renderUnsupportedNativeGuard(product, nativeTargets, nativeCfgs) }); } -export function writeFacadeSource(product, outputRoot, { dependencyPaths = {} } = {}) { - if (!exactExtensionProducts('package-extension-cargo-facades').includes(product)) { - fail(`${product} is not an exact extension product`); +export interface ExtensionCargoFacadeMetadata { + nativeOwner: string; + wasixOwner: string; + version: string; + sqlNames: string[]; + targets: { nativeCargoTargets: string[]; includeWasixAot: boolean }; + sdkVersion: string; + bindingVersion: string; + wasixSdkVersion?: string; + compatibility: { nativeRuntimeVersion: string; wasixRuntimeVersion: string }; +} + +export function writeFacadeSource( + product, + outputRoot, + { + dependencyPaths = {}, + metadata = undefined, + }: { + dependencyPaths?: Record; + metadata?: ExtensionCargoFacadeMetadata; + } = {}, +) { + if (metadata === undefined) { + if (!exactExtensionProducts('package-extension-cargo-facades').includes(product)) { + fail(`${product} is not an exact extension product`); + } + metadata = { + nativeOwner: extensionReleaseProduct(product, 'native', 'package-extension-cargo-facades'), + wasixOwner: extensionReleaseProduct(product, 'wasix', 'package-extension-cargo-facades'), + version: extensionReleaseVersion(product, 'native', 'package-extension-cargo-facades'), + sqlNames: extensionSqlNames(product, 'package-extension-cargo-facades'), + targets: extensionRegistryPackageTargetSets(product, 'package-extension-cargo-facades'), + sdkVersion: currentProductVersionSync('oliphaunt-rust'), + bindingVersion: currentProductVersionSync('liboliphaunt-native-bindings'), + compatibility: extensionMetadata(product).compatibility, + }; + if (metadata.nativeOwner === metadata.wasixOwner) { + metadata.wasixSdkVersion = currentProductVersionSync('oliphaunt-wasix-rust'); + } } - const nativeOwner = extensionReleaseProduct(product, 'native', 'package-extension-cargo-facades'); - const wasixOwner = extensionReleaseProduct(product, 'wasix', 'package-extension-cargo-facades'); + if (metadata === null || Array.isArray(metadata) || typeof metadata !== 'object') { + fail(`${product} facade metadata must be an object`); + } + const { + nativeOwner, + wasixOwner, + version, + sqlNames, + targets, + sdkVersion, + bindingVersion, + wasixSdkVersion, + compatibility, + } = metadata; const nativeOnly = nativeOwner !== wasixOwner; - const version = extensionReleaseVersion(product, 'native', 'package-extension-cargo-facades'); - const sqlNames = extensionSqlNames(product, 'package-extension-cargo-facades'); - const targets = extensionRegistryPackageTargetSets(product, 'package-extension-cargo-facades'); + const uniqueStrings = (values) => + Array.isArray(values) && + values.length > 0 && + values.every((value) => typeof value === 'string' && /^[A-Za-z0-9_-]+$/u.test(value)) && + new Set(values).size === values.length; + const stableVersion = (value) => + typeof value === 'string' && + /^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)$/u.test(value); + if ( + typeof product !== 'string' || + !/^oliphaunt-extension-[A-Za-z0-9_-]+$/u.test(product) || + ![nativeOwner, wasixOwner].every((owner) => typeof owner === 'string' && owner.length > 0) || + !uniqueStrings(sqlNames) || + !uniqueStrings(targets?.nativeCargoTargets) || + typeof targets.includeWasixAot !== 'boolean' || + ![ + version, + sdkVersion, + bindingVersion, + compatibility?.nativeRuntimeVersion, + compatibility?.wasixRuntimeVersion, + ...(nativeOnly ? [] : [wasixSdkVersion]), + ].every(stableVersion) + ) { + fail(`${product} facade metadata must declare exact owners, members, targets and versions`); + } + for (const target of targets.nativeCargoTargets) rustNativeTargetCfg(target); const wasixAotTargets = !nativeOnly && targets.includeWasixAot ? expectedExtensionAotTargets() : []; const sourceDir = path.join(outputRoot, 'sources', product); @@ -159,25 +232,18 @@ export function writeFacadeSource(product, outputRoot, { dependencyPaths = {} } if (existing < 0) targetDependencies.push(`${header}\n${row}`); else targetDependencies[existing] += `\n${row}`; } - const sdkVersion = currentProductVersionSync('oliphaunt-rust'); - const bindingVersion = currentProductVersionSync('liboliphaunt-native-bindings'); const optionalDependencies = [ dependency('liboliphaunt-native-bindings', bindingVersion, false), ...(wasixName === null ? [] : [ dependency(wasixName, version), - dependency( - 'oliphaunt-wasix', - currentProductVersionSync('oliphaunt-wasix-rust'), - false, - ).replace( + dependency('oliphaunt-wasix', wasixSdkVersion, false).replace( 'default-features = false', 'default-features = false, features = ["extensions"]', ), ]), ].join('\n'); - const compatibility = extensionMetadata(product).compatibility; const unsupportedNativeGuard = renderUnsupportedNativeGuard( product, targets.nativeCargoTargets, @@ -291,16 +357,39 @@ pub use wasix::*; return { product, releaseProduct: nativeOwner, version, sourceDir }; } -export function packageExtensionCargoFacades(products, outputRoot) { +export function packageExtensionCargoFacades( + products, + outputRoot, + { metadataByProduct }: { metadataByProduct?: Record } = {}, +) { const selected = [...new Set(products)].sort(compareText); if (selected.length !== products.length || selected.length === 0) { fail('products must be a non-empty duplicate-free list'); } + if (metadataByProduct !== undefined) { + if ( + metadataByProduct === null || + Array.isArray(metadataByProduct) || + typeof metadataByProduct !== 'object' || + JSON.stringify(Object.keys(metadataByProduct).sort(compareText)) !== + JSON.stringify(selected) || + selected.some( + (product) => + metadataByProduct[product] === null || + Array.isArray(metadataByProduct[product]) || + typeof metadataByProduct[product] !== 'object', + ) + ) { + fail('declared facade metadata must exactly match the selected products'); + } + } rmSync(outputRoot, { recursive: true, force: true }); mkdirSync(path.join(outputRoot, 'crates'), { recursive: true }); const packages = []; for (const product of selected) { - const source = writeFacadeSource(product, outputRoot); + const source = writeFacadeSource(product, outputRoot, { + metadata: metadataByProduct?.[product], + }); const cratePath = packageGeneratedCargoSource( path.join(source.sourceDir, 'Cargo.toml'), path.join(outputRoot, 'crates'), diff --git a/src/extensions/artifacts/packages/tools/package-extension-cargo-facades.test.mts b/src/extensions/artifacts/packages/tools/package-extension-cargo-facades.test.mts index 7a5490234..a016d5b78 100644 --- a/src/extensions/artifacts/packages/tools/package-extension-cargo-facades.test.mts +++ b/src/extensions/artifacts/packages/tools/package-extension-cargo-facades.test.mts @@ -300,6 +300,67 @@ function findFile(root, basename) { } describe('exact extension Cargo facade', () => { + test('packages supplied metadata without consulting the product graph', () => { + const output = mkdtempSync(path.join(tmpdir(), 'declared-extension-facade-test-')); + directories.push(output); + const product = 'oliphaunt-extension-declared-fixture'; + const metadata = { + nativeOwner: product, + wasixOwner: product, + version: '9.1.0', + sqlNames: ['fixture'], + targets: { + nativeCargoTargets: ['linux-arm64-gnu', 'linux-x64-gnu', 'macos-arm64', 'windows-x64-msvc'], + includeWasixAot: true, + }, + sdkVersion: '8.1.0', + bindingVersion: '8.2.0', + wasixSdkVersion: '8.3.0', + compatibility: { nativeRuntimeVersion: '7.1.0', wasixRuntimeVersion: '7.2.0' }, + }; + const [pkg] = packageExtensionCargoFacades([product], output, { + metadataByProduct: { [product]: metadata }, + }); + const manifest = Bun.TOML.parse(readFileSync(pkg.manifestPath, 'utf8')); + expect(pkg.version).toBe(metadata.version); + expect(Object.keys(manifest.target)).toHaveLength(4); + expect(manifest.dependencies['liboliphaunt-native-bindings'].version).toBe('^8.2.0'); + expect(manifest['build-dependencies']['oliphaunt-build'].version).toBe('^8.1.0'); + expect(manifest.dependencies['oliphaunt-wasix'].version).toBe('^8.3.0'); + expect(manifest.features.wasix).toContain(`dep:${product}-wasix`); + expect(manifest.features.wasix).toHaveLength(6); + const source = readFileSync(path.join(path.dirname(pkg.manifestPath), 'src/lib.rs'), 'utf8'); + expect(source).toContain('runtime_version: "7.1.0"'); + expect(source).toContain('PRODUCT, VERSION, "7.2.0"'); + + metadata.wasixOwner = 'liboliphaunt-wasix'; + const native = writeFacadeSource(product, output, { metadata }); + const nativeManifest = Bun.TOML.parse( + readFileSync(path.join(native.sourceDir, 'Cargo.toml'), 'utf8'), + ); + expect(nativeManifest.features.wasix).toBeUndefined(); + expect(nativeManifest.dependencies['oliphaunt-wasix']).toBeUndefined(); + metadata.targets.nativeCargoTargets = ['ios-xcframework']; + expect(() => writeFacadeSource(product, output, { metadata })).toThrow( + 'unsupported native Cargo target', + ); + }); + + test('supplied metadata cannot silently fall back to missing product facts', () => { + const output = mkdtempSync(path.join(tmpdir(), 'declared-extension-facade-missing-test-')); + directories.push(output); + expect(() => + packageExtensionCargoFacades(['oliphaunt-extension-pgtap'], output, { + metadataByProduct: {}, + }), + ).toThrow('exactly match the selected products'); + expect(() => + packageExtensionCargoFacades(['oliphaunt-extension-pgtap'], output, { + metadataByProduct: { 'oliphaunt-extension-pgtap': undefined }, + }), + ).toThrow('exactly match the selected products'); + }); + test('packages explicit native and WASIX feature selections', () => { const output = mkdtempSync(path.join(tmpdir(), 'extension-facade-test-')); directories.push(output); diff --git a/src/extensions/artifacts/packages/tools/package-extension-native-npm-facade.test.mts b/src/extensions/artifacts/packages/tools/package-extension-native-npm-facade.test.mts new file mode 100644 index 000000000..a292d4ba5 --- /dev/null +++ b/src/extensions/artifacts/packages/tools/package-extension-native-npm-facade.test.mts @@ -0,0 +1,131 @@ +import { afterEach, expect, test } from 'bun:test'; +import { mkdtempSync, readFileSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { readPortableArchiveEntries } from '../../../../../tools/packaging/portable-archive.mts'; +import { IOS_CARRIER_FILENAME } from '../../../../native/sdks/swift/tools/ios-carrier-manifest.mts'; +import { stageExtensionNativeNpmFacade } from './package-extension-release-carriers.mts'; + +const directories = []; +afterEach(() => { + while (directories.length) rmSync(directories.pop(), { recursive: true, force: true }); +}); + +function fixture() { + const root = mkdtempSync(path.join(tmpdir(), 'extension-npm-facade-test-')); + directories.push(root); + const iosCarrier = JSON.parse( + readFileSync( + path.resolve( + import.meta.dirname, + '../../../../../build_defs/release/testdata/swift-0.8.2-carrier.json', + ), + 'utf8', + ), + ); + iosCarrier.extensions = [ + { + product: 'oliphaunt-extension-pgtap', + version: '1.3.4', + sqlName: 'pgtap', + assets: [{ role: 'runtime-resources', carrier: 'pgtap-ios-fixture.tar.gz' }], + }, + ]; + return { + root, + metadata: { + product: 'oliphaunt-extension-pgtap', + version: '1.3.4', + members: ['pgtap'], + targets: ['linux-arm64-gnu', 'linux-x64-gnu', 'macos-arm64', 'windows-x64-msvc'], + iosCarrier, + liboliphauntVersion: iosCarrier.base.version, + runtimeBound: false, + }, + result: { staged: [], skipped: [] }, + }; +} + +test('facade packing preserves Apple metadata and every supplied desktop identity', () => { + const { root, metadata, result } = fixture(); + const tarball = stageExtensionNativeNpmFacade( + path.join(root, 'package'), + path.join(root, 'tarballs'), + metadata, + result, + ); + expect(tarball).not.toBeNull(); + const entries = readPortableArchiveEntries(tarball); + const manifest = JSON.parse(entries.get('package/package.json').data().toString('utf8')); + expect(manifest.name).toBe('@oliphaunt/extension-pgtap'); + expect(Object.keys(manifest.oliphaunt.targetPackageNames)).toEqual(metadata.targets); + expect(manifest.optionalDependencies).toEqual( + Object.fromEntries( + metadata.targets.map((target) => [`@oliphaunt/extension-pgtap-${target}`, metadata.version]), + ), + ); + expect( + JSON.parse(entries.get(`package/${IOS_CARRIER_FILENAME}`).data().toString('utf8')), + ).toEqual(metadata.iosCarrier); + expect(entries.has('package/LICENSE')).toBe(true); + expect(result.staged).toHaveLength(1); +}); + +test('single Linux facade retains the legacy optional Apple metadata contract', () => { + const { root, metadata, result } = fixture(); + metadata.targets = ['linux-x64-gnu']; + metadata.iosCarrier = undefined; + const tarball = stageExtensionNativeNpmFacade( + path.join(root, 'package'), + path.join(root, 'tarballs'), + metadata, + result, + ); + expect(tarball).not.toBeNull(); + const manifest = JSON.parse( + readPortableArchiveEntries(tarball).get('package/package.json').data().toString('utf8'), + ); + expect(manifest.optionalDependencies).toEqual({ + '@oliphaunt/extension-pgtap-linux-x64-gnu': metadata.version, + }); + expect(result.staged).toHaveLength(1); +}); + +test('facade rejects missing targets, repeated members and mismatched Apple identities', () => { + const { root, metadata, result } = fixture(); + const stage = () => + stageExtensionNativeNpmFacade( + path.join(root, 'package'), + path.join(root, 'tarballs'), + metadata, + result, + ); + const targets = metadata.targets; + metadata.targets = []; + expect(stage).toThrow('explicit non-empty unique target list'); + metadata.targets = targets; + metadata.members = ['pgtap', 'pgtap']; + expect(stage).toThrow('unique members'); + metadata.members = ['pgtap']; + metadata.iosCarrier.extensions[0].version = '1.3.5'; + expect(stage).toThrow('mismatched Apple carrier identity'); + expect(result.staged).toEqual([]); +}); + +test('facade requires Apple identity for an explicit iOS target and checks it when supplied', () => { + const { root, metadata, result } = fixture(); + metadata.iosCarrier = undefined; + metadata.targets = ['ios-xcframework']; + const stage = () => + stageExtensionNativeNpmFacade( + path.join(root, 'package'), + path.join(root, 'tarballs'), + metadata, + result, + ); + expect(stage).toThrow('mismatched Apple carrier identity'); + metadata.targets = ['linux-x64-gnu']; + metadata.iosCarrier = null; + expect(stage).toThrow('mismatched Apple carrier identity'); + expect(result.staged).toEqual([]); +}); diff --git a/src/extensions/artifacts/packages/tools/package-extension-release-carriers.mts b/src/extensions/artifacts/packages/tools/package-extension-release-carriers.mts index 67ee51748..98d214a6d 100644 --- a/src/extensions/artifacts/packages/tools/package-extension-release-carriers.mts +++ b/src/extensions/artifacts/packages/tools/package-extension-release-carriers.mts @@ -18,23 +18,13 @@ import { statSync, writeFileSync, } from 'node:fs'; +import { tmpdir } from 'node:os'; import path from 'node:path'; -import { extensionRuntimeAssetContract } from './extension-runtime-asset-contract.mts'; -import { RUST_BUILD_SCRIPT_SHA256 } from '../../../../../tools/packaging/rust-build-script-sha256.mts'; -import { - AOT_TARGET_TRIPLES, - CORE_RUNTIME_ARCHIVE_FILES, -} from '../../../../wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; -import { parseNpmExtensionLicenseFiles } from '../../../../native/sdks/ts/src/native/extension-contract.ts'; import { fitCargoPayloadParts, packageGeneratedCargoSource, readCargoPackageNameVersion, } from '../../../../../tools/packaging/cargo-source-package.mts'; -import { - buildIosCarrierManifest, - IOS_CARRIER_FILENAME, -} from '../../../../native/sdks/swift/tools/ios-carrier-manifest.mts'; import { packGeneratedNpmCarrier } from '../../../../../tools/packaging/npm-package.mts'; import { NPM_TRUSTED_PUBLISHING_REPOSITORY } from '../../../../../tools/packaging/npm-trusted-publishing.mts'; import { @@ -47,6 +37,23 @@ import { releaseNoticeRows, stageReleaseNotices, } from '../../../../../tools/packaging/release-notices.mts'; +import { RUST_BUILD_SCRIPT_SHA256 } from '../../../../../tools/packaging/rust-build-script-sha256.mts'; +import { + compareText, + extensionRegistryPackageTargetSets, +} from '../../../../../tools/release/release-artifact-targets.mts'; +import { + buildIosCarrierManifest, + IOS_CARRIER_FILENAME, + IOS_CARRIER_SCHEMA, +} from '../../../../native/sdks/swift/tools/ios-carrier-manifest.mts'; +import { parseNpmExtensionLicenseFiles } from '../../../../native/sdks/ts/src/native/extension-contract.ts'; +import { assertWasixAotArtifactPayloads } from '../../../../wasix/runtime/tools/check-release-assets.mts'; +import { assertCanonicalWasixAotManifest } from '../../../../wasix/runtime/tools/wasix-aot-manifest.mts'; +import { + AOT_TARGET_TRIPLES, + CORE_RUNTIME_ARCHIVE_FILES, +} from '../../../../wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; import { assertWasixExtensionArchiveInstall, assertWasixExtensionInstall, @@ -56,30 +63,32 @@ import { WASIX_EXTENSION_INSTALL_SCHEMA, WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA, } from '../../../contracts/wasix-extension-install.mts'; -import { - compareText, - extensionRegistryPackageTargetSets, -} from '../../../../../tools/release/release-artifact-targets.mts'; import { assertExtensionUpstreamLicensesInArchive, assertExtensionUpstreamLicensesInDirectory, extensionCarrierLegalContract, extensionUpstreamLicenseFileInventory, + nativeExtensionCarrierLegal, stageExtensionUpstreamLicenses, + validateNativeExtensionConstructionLicenseInventory, } from '../../../tools/extension-upstream-licenses.mts'; + +export { nativeExtensionCarrierLegal } from '../../../tools/extension-upstream-licenses.mts'; + import { validateExtensionArtifactArchive } from './extension-artifact-inventory.mts'; import { extensionNpmPackageForProduct, extensionNpmTargetPackageForProduct, - extensionNpmWasixPackageForProduct, extensionNpmWasixAotTargets, + extensionNpmWasixPackageForProduct, nativeExtensionCargoLinksName, nativeExtensionCargoPackageName, nativeExtensionCargoPartPackageName, } from './extension-registry-packages.mts'; - -import { assertCanonicalWasixAotManifest } from '../../../../wasix/runtime/tools/wasix-aot-manifest.mts'; -import { assertWasixAotArtifactPayloads } from '../../../../wasix/runtime/tools/check-release-assets.mts'; +import { + extensionRuntimeAssetContract, + projectNativeRuntimeAssetMember, +} from './extension-runtime-asset-contract.mts'; const ROOT = path.resolve(import.meta.dirname, '../../../../..'); const TOOL = 'package-extension-release-carriers.mts'; @@ -230,9 +239,7 @@ export function discoverExtensionManifests(roots) { } function archiveTempDir() { - const root = path.join(ROOT, 'target', 'extension-carrier-archive-extract'); - mkdirSync(root, { recursive: true }); - return mkdtempSync(path.join(root, 'extract-')); + return mkdtempSync(path.join(tmpdir(), 'extension-carrier-extract-')); } function cargoTargetTriple(targetId) { @@ -255,33 +262,6 @@ function localFail(message) { fail(TOOL, message); } -export function nativeExtensionCarrierLegal(product, members, { target = null, carriesPayload }) { - if ( - typeof product !== 'string' || - !Array.isArray(members) || - members.length === 0 || - members.some((member) => typeof member !== 'string' || !member) || - new Set(members).size !== members.length || - typeof carriesPayload !== 'boolean' - ) { - throw new Error( - `${TOOL}: native extension carrier legal lookup requires a product, unique members, and carriesPayload`, - ); - } - try { - return extensionCarrierLegalContract(product, members, { - family: 'native', - target, - carriesPayload, - }); - } catch (cause) { - throw new Error( - `${TOOL}: cannot derive the canonical native extension carrier legal contract: ${cause.message}`, - { cause }, - ); - } -} - export function wasixExtensionCarrierLegal(product, members) { if ( typeof product !== 'string' || @@ -342,12 +322,13 @@ function assertExtensionCarrierArchive(archive, legal, prefix) { function assertNpmExtensionRuntimeLegalArchive( archive, - { product, members, target, bundle, memberRuntimeRelativePaths }, + { product, members, target, bundle, memberRuntimeRelativePaths, memberContracts }, ) { for (const sqlName of members) { const legal = nativeExtensionCarrierLegal(product, [sqlName], { carriesPayload: true, target, + memberContracts: memberContracts.filter((member) => member.sqlName === sqlName), }); if (legal.upstreamMembers.length === 0) continue; const runtimeRelativePath = bundle ? memberRuntimeRelativePaths?.[sqlName] : 'runtime'; @@ -356,6 +337,10 @@ function assertNpmExtensionRuntimeLegalArchive( } assertExtensionUpstreamLicensesInArchive(legal.upstreamMembers, archive, { prefix: `package/${runtimeRelativePath}`, + constructionLicenseFiles: + memberContracts.find((member) => member.sqlName === sqlName) + ?.nativeConstructionLicenseFiles ?? [], + target, }); } } @@ -396,22 +381,37 @@ export function renderNpmExtensionBundleManifest({ product, version, target, mem } export function npmExtensionMemberContract(product, version, target, member) { - const inventory = frozenExtensionMemberInventory(member, { product, version }); + const { nativeConstructionLicenseFiles = [], ...inventory } = frozenExtensionMemberInventory( + member, + { product, version, target }, + ); const legal = nativeExtensionCarrierLegal(product, [inventory.sqlName], { target, carriesPayload: true, + memberContracts: [member], }); const licenseFiles = Object.freeze( parseNpmExtensionLicenseFiles( - legal.upstreamMembers.length === 0 - ? [] - : extensionUpstreamLicenseFileInventory([inventory.sqlName]), + [ + ...(legal.upstreamMembers.length === 0 + ? [] + : extensionUpstreamLicenseFileInventory([inventory.sqlName])), + ...validateNativeExtensionConstructionLicenseInventory( + inventory.sqlName, + target, + nativeConstructionLicenseFiles, + ), + ].sort((a, b) => compareText(a.path, b.path)), `${product}@${version}/${inventory.sqlName} npm extension licenseFiles`, ).map((file) => Object.freeze(file)), ); if ( JSON.stringify(licenseFiles.map(({ path: file }) => file)) !== - JSON.stringify([...legal.licenseFiles]) + JSON.stringify( + [...legal.licenseFiles, ...nativeConstructionLicenseFiles.map((row) => row.path)].sort( + compareText, + ), + ) ) { fail( TOOL, @@ -475,7 +475,13 @@ const FROZEN_EXTENSION_INVENTORY_LIST_FIELDS = Object.freeze([ * generated SDK catalog: independently versioned external products must remain * bound to the metadata that was qualified and versioned with that product. */ -export function frozenExtensionMemberInventory(member, { product, version } = {}) { +export function frozenExtensionMemberInventory( + member, + { product, version, asset, target = asset?.target ?? 'linux-x64-gnu' } = {}, +) { + if (asset !== undefined && asset.target !== target) + throw new Error(`${TOOL}: selected native asset target differs from its inventory target`); + if (asset !== undefined) member = projectNativeRuntimeAssetMember(member, asset); const owner = [product, version].every((value) => typeof value === 'string' && value.length > 0) ? `${product}@${version}` : 'extension release'; @@ -513,6 +519,30 @@ export function frozenExtensionMemberInventory(member, { product, version } = {} } inventory[field] = canonical; } + if (Object.hasOwn(member, 'nativeDependencyModules')) { + const values = member.nativeDependencyModules; + if ( + !Array.isArray(values) || + values.length === 0 || + values.some( + (file) => typeof file !== 'string' || !/^[A-Za-z0-9_-]+\.(?:so|dylib|dll)$/u.test(file), + ) || + JSON.stringify(values) !== JSON.stringify([...new Set(values)].sort(compareText)) || + inventory.nativeModuleStem === null + ) { + throw new Error( + `${TOOL}: ${owner}/${sqlName} nativeDependencyModules must be sorted unique native module basenames`, + ); + } + inventory.nativeDependencyModules = [...values]; + } + if (Object.hasOwn(member, 'nativeConstructionLicenseFiles')) { + inventory.nativeConstructionLicenseFiles = validateNativeExtensionConstructionLicenseInventory( + sqlName, + target, + member.nativeConstructionLicenseFiles, + ); + } if (inventory.dependencies.includes(sqlName)) { throw new Error(`${TOOL}: ${owner}/${sqlName} frozen dependencies must exclude itself`); } @@ -685,7 +715,24 @@ function extensionRuntimeAssets(extensionDir, manifest, releaseManifest, target) `${TOOL}: ${product}@${version}/${member.sqlName} CI and release runtime asset contracts differ`, ); } - return { sqlName, metadata, asset: matches[0] }; + const selectedMetadata = frozenExtensionMemberInventory(member, { + product, + version, + target, + asset: matches[0], + }); + const selectedReleaseMetadata = frozenExtensionMemberInventory(releaseMember, { + product, + version, + target, + asset: releaseMatches[0], + }); + if (!sameFrozenValue(selectedMetadata, selectedReleaseMetadata)) { + throw new Error( + `${TOOL}: ${product}@${version}/${sqlName} selected native asset inventories differ`, + ); + } + return { sqlName, metadata: selectedMetadata, asset: matches[0] }; }); if (runtimeMembers.some((member) => member === null)) { return null; @@ -1018,7 +1065,11 @@ function checkedArchiveMemberPath(name, archive) { return parts.join('/'); } -function extractExtensionRuntime(asset, runtimeDir, { metadata, target, nativeRuntimeVersion }) { +function extractExtensionRuntime( + asset, + runtimeDir, + { metadata, target, nativeRuntimeVersion, product }, +) { // Native release assets are stripped and platform-validated on their target // builders. Carrier assembly preserves those qualified bytes; host-side // binary rewriting would make output coordinator-dependent. @@ -1030,6 +1081,7 @@ function extractExtensionRuntime(asset, runtimeDir, { metadata, target, nativeRu metadata, target, nativeRuntimeVersion, + product, }); } catch (error) { throw new Error(`${TOOL}: ${error instanceof Error ? error.message : String(error)}`, { @@ -1729,6 +1781,49 @@ function npmPackageSizeSafe(tarball, result) { return false; } +/** Package the complete facade without rebuilding a platform leaf. */ +export function stageExtensionNativeNpmFacade(packageDir, tarballRoot, metadata, result) { + const { product, version, members, targets, iosCarrier, liboliphauntVersion, runtimeBound } = + metadata; + if ( + !Array.isArray(targets) || + targets.length === 0 || + targets.some((target) => typeof target !== 'string' || !target) || + new Set(targets).size !== targets.length + ) { + fail(TOOL, 'native npm facade requires an explicit non-empty unique target list'); + } + const legal = nativeExtensionCarrierLegal(product, members, { carriesPayload: false }); + const requiresAppleIdentity = iosCarrier !== undefined || targets.includes('ios-xcframework'); + if ( + typeof version !== 'string' || + !/^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)$/u.test(version) || + typeof liboliphauntVersion !== 'string' || + !/^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)$/u.test(liboliphauntVersion) || + typeof runtimeBound !== 'boolean' || + (runtimeBound && version !== liboliphauntVersion) || + (requiresAppleIdentity && + (iosCarrier?.schema !== IOS_CARRIER_SCHEMA || + iosCarrier.base?.product !== 'liboliphaunt-native' || + iosCarrier.base.version !== liboliphauntVersion || + !Array.isArray(iosCarrier.extensions) || + JSON.stringify(iosCarrier.extensions.map((member) => member?.sqlName).sort(compareText)) !== + JSON.stringify([...members].sort(compareText)) || + iosCarrier.extensions.some( + (member) => member.product !== product || member.version !== version, + ))) + ) { + fail(TOOL, `${product}@${version} native npm facade has mismatched Apple carrier identity`); + } + writeExtensionMetaPackage(packageDir, { ...metadata, legal }); + stageExtensionCarrierLegal(packageDir, legal); + const tarball = packGeneratedNpmCarrier(packageDir, tarballRoot); + assertExtensionCarrierArchive(tarball, legal, 'package'); + if (!npmPackageSizeSafe(tarball, result)) return null; + result.staged.push(rel(tarball)); + return tarball; +} + export function stageExtensionNativeNpmPackages(roots, stagingRoot, target, result, options = {}) { const manifests = discoverExtensionManifests(roots); if (manifests.length === 0) { @@ -1839,6 +1934,7 @@ export function stageExtensionNativeNpmPackages(roots, stagingRoot, target, resu metadata: member.metadata, target, nativeRuntimeVersion: liboliphauntVersion, + product, }); if (walkFiles(runtimeDir).length === 0) { fail( @@ -1885,6 +1981,7 @@ export function stageExtensionNativeNpmPackages(roots, stagingRoot, target, resu metadata: runtimeSet.members[0].metadata, target, nativeRuntimeVersion: liboliphauntVersion, + product, }); if (walkFiles(runtimeDir).length === 0) { result.skipped.push( @@ -1897,12 +1994,10 @@ export function stageExtensionNativeNpmPackages(roots, stagingRoot, target, resu typeof options.metaTargetsForProduct === 'function' ? options.metaTargetsForProduct(product) : options.metaTargets; - const metaLegal = nativeExtensionCarrierLegal(product, members, { - carriesPayload: false, - }); const targetLegal = nativeExtensionCarrierLegal(product, members, { carriesPayload: true, target, + memberContracts: runtimeSet.members.map(({ metadata }) => metadata), }); writeExtensionTargetPackage(targetDir, { product, @@ -1924,6 +2019,7 @@ export function stageExtensionNativeNpmPackages(roots, stagingRoot, target, resu target, bundle: runtimeSet.bundle, memberRuntimeRelativePaths, + memberContracts: runtimeSet.members.map(({ metadata }) => metadata), }); if (!npmPackageSizeSafe(targetTarball, result)) { continue; @@ -1936,25 +2032,25 @@ export function stageExtensionNativeNpmPackages(roots, stagingRoot, target, resu baseCarrierManifest: options.baseCarrierManifest, extensionManifests: [manifestPath], }); - writeExtensionMetaPackage(metaDir, { - product, - version, - members, - target, - targets: metaTargets ?? [target], - iosCarrier, - liboliphauntVersion, - runtimeBound, - legal: metaLegal, - }); - stageExtensionCarrierLegal(metaDir, metaLegal); - const metaTarball = packGeneratedNpmCarrier(metaDir, tarballRoot); - assertExtensionCarrierArchive(metaTarball, metaLegal, 'package'); - if (!npmPackageSizeSafe(metaTarball, result)) { + const metaTarball = stageExtensionNativeNpmFacade( + metaDir, + tarballRoot, + { + product, + version, + members, + target, + targets: metaTargets ?? [target], + iosCarrier, + liboliphauntVersion, + runtimeBound, + }, + result, + ); + if (metaTarball === null) { rmSync(targetTarball, { force: true }); continue; } - result.staged.push(rel(metaTarball)); } result.staged.push(rel(targetTarball)); stagedAny = true; @@ -2218,9 +2314,13 @@ function copyPayloadFile(source, destination) { export function buildNativeExtensionPartCrates( runtimeDir, sourceRoot, - { product, version, members, target, partBytes }, + { product, version, members, target, partBytes, memberContracts = [] }, ) { - const legal = nativeExtensionCarrierLegal(product, members, { target, carriesPayload: true }); + const legal = nativeExtensionCarrierLegal(product, members, { + target, + carriesPayload: true, + memberContracts, + }); const partDirs = []; let currentDir = null; let currentSize = 0; @@ -2679,6 +2779,7 @@ function cargoPackage(crateDir, targetDir, legal) { { fail: localFail, rel, + fixedFileMode: 0o644, // The caller splits using the finished archive's compressed size. packageSizeLimitBytes: Number.MAX_SAFE_INTEGER, }, @@ -2693,7 +2794,11 @@ function discardCargoPackageArtifact(cratePath) { rmSync(path.dirname(cratePath), { recursive: true, force: true }); } -function stageNativeExtensionCargoPayload(crateDir, runtimeSet, { target, nativeRuntimeVersion }) { +function stageNativeExtensionCargoPayload( + crateDir, + runtimeSet, + { target, nativeRuntimeVersion, product }, +) { const payload = path.join(crateDir, 'payload'); rmSync(payload, { recursive: true, force: true }); if (!runtimeSet.bundle) { @@ -2701,6 +2806,7 @@ function stageNativeExtensionCargoPayload(crateDir, runtimeSet, { target, native metadata: runtimeSet.members[0].metadata, target, nativeRuntimeVersion, + product, }); return payload; } @@ -2716,6 +2822,7 @@ function stageNativeExtensionCargoPayload(crateDir, runtimeSet, { target, native metadata: member.metadata, target, nativeRuntimeVersion, + product, }); } } finally { @@ -2738,7 +2845,11 @@ function writeNativeExtensionCargoCrate( runtimeSet, }, ) { - const legal = nativeExtensionCarrierLegal(product, members, { target, carriesPayload: true }); + const legal = nativeExtensionCarrierLegal(product, members, { + target, + carriesPayload: true, + memberContracts: runtimeSet.members.map(({ metadata }) => metadata), + }); const name = nativeExtensionCargoPackageName(product, target); const links = nativeExtensionCargoLinksName(product, target); const subject = members.length === 1 ? members[0] : `${members.length}-member bundle`; @@ -2746,6 +2857,7 @@ function writeNativeExtensionCargoCrate( const runtimeDir = stageNativeExtensionCargoPayload(crateDir, runtimeSet, { target, nativeRuntimeVersion: runtimeVersion, + product, }); if (walkFiles(runtimeDir).length === 0) { throw new Error(`${product}@${version} did not contain extension runtime files`); @@ -2933,7 +3045,7 @@ export function packageNativeExtensionCargoCrates(roots, stagingRoot, target, st mkdirSync(outputDir, { recursive: true }); const outputs = []; - const packageOptions = { root: ROOT, fail: localFail, rel }; + const packageOptions = { root: ROOT, fail: localFail, rel, fixedFileMode: 0o644 }; const stagedIdentities = new Map(); try { for (const manifestPath of manifests) { @@ -3035,6 +3147,7 @@ export function packageNativeExtensionCargoCrates(roots, stagingRoot, target, st memberDependencies, target, partBytes, + memberContracts: runtimeSet.members.map(({ metadata }) => metadata), }), (partDir) => packageGeneratedCargoSource( @@ -3046,6 +3159,7 @@ export function packageNativeExtensionCargoCrates(roots, stagingRoot, target, st const partLegal = nativeExtensionCarrierLegal(product, members, { target, carriesPayload: true, + memberContracts: runtimeSet.members.map(({ metadata }) => metadata), }); const aggregatorLegal = writeNativeExtensionSplitAggregatorCrate(crateDir, { product, diff --git a/src/extensions/catalog/BUILD.bazel b/src/extensions/catalog/BUILD.bazel new file mode 100644 index 000000000..5fa00e596 --- /dev/null +++ b/src/extensions/catalog/BUILD.bazel @@ -0,0 +1,6 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +package(default_visibility = ["//visibility:public"]) + +exports_files(["native-components.toml", "extensions.source.json"]) + +source_quality_files() diff --git a/src/extensions/contracts/BUILD.bazel b/src/extensions/contracts/BUILD.bazel new file mode 100644 index 000000000..6baa2a45f --- /dev/null +++ b/src/extensions/contracts/BUILD.bazel @@ -0,0 +1,12 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/extensions:compile_data.bzl", "extension_compile_data") + +package(default_visibility = ["//visibility:public"]) + +extension_compile_data(name = "archive_policy_compile_data", src = "extension-artifact-archive-policy.properties") + +exports_files(["extension-target-profiles.mts", "extension-target-profiles.toml"]) +exports_files(["wasix-extension-install.mts"]) +exports_files(["extension-artifact-archive-policy.properties"]) + +source_quality_files() diff --git a/src/extensions/contracts/extension-target-profiles.mts b/src/extensions/contracts/extension-target-profiles.mts index 03504b7ed..a728a8ac7 100644 --- a/src/extensions/contracts/extension-target-profiles.mts +++ b/src/extensions/contracts/extension-target-profiles.mts @@ -6,6 +6,26 @@ export const EXTENSION_TARGET_PROFILES_RELATIVE_PATH = const ROOT = path.resolve(import.meta.dir, '../../..'); const ID = /^[a-z][a-z0-9_-]*$/u; +/** Mobile exact archives retain the existing ordinary host module alongside static units. */ +export function nativeExtensionModuleHostTarget(target) { + if (target === 'ios-xcframework') return 'macos-arm64'; + if (target === 'android-arm64-v8a' || target === 'android-x86_64') return 'linux-x64-gnu'; + return target; +} + +/** Select a target's carried subset; the default remains the legacy module universe. */ +export function nativeExtensionDependencyModulePaths(files = [], target, byTarget = {}) { + table(byTarget, 'native dependency module overrides'); + const desktopTargets = ['linux-x64-gnu', 'linux-arm64-gnu', 'macos-arm64', 'windows-x64-msvc']; + for (const [overrideTarget, selected] of Object.entries(byTarget)) { + if (!desktopTargets.includes(overrideTarget)) + fail('native dependency module override requires a desktop native target'); + if (!Array.isArray(selected) || selected.some((file) => !files.includes(file))) + fail('native dependency module override must select declared module paths'); + } + return byTarget[nativeExtensionModuleHostTarget(target)] ?? files; +} + function fail(message) { throw new Error(`extension target profiles: ${message}`); } diff --git a/src/extensions/contracts/extension-target-profiles.test.mts b/src/extensions/contracts/extension-target-profiles.test.mts index b304564e2..9752241d2 100644 --- a/src/extensions/contracts/extension-target-profiles.test.mts +++ b/src/extensions/contracts/extension-target-profiles.test.mts @@ -1,6 +1,9 @@ import { expect, test } from 'bun:test'; -import { validateExtensionTargetProfiles } from './extension-target-profiles.mts'; +import { + nativeExtensionDependencyModulePaths, + validateExtensionTargetProfiles, +} from './extension-target-profiles.mts'; function fixture() { return { @@ -38,3 +41,31 @@ test('rejects a target declared by more than one profile', () => { raw.profiles.push({ ...raw.profiles[0], id: 'duplicate-v1' }); expect(() => validateExtensionTargetProfiles(raw)).toThrow(/duplicate target linux-x64-gnu/u); }); + +test('native dependency overrides select only a declared desktop host subset', () => { + const files = ['lib/postgresql/private.so']; + const overrides = { 'windows-x64-msvc': [] }; + expect(nativeExtensionDependencyModulePaths(files, 'windows-x64-msvc', overrides)).toEqual([]); + for (const target of [ + 'linux-x64-gnu', + 'linux-arm64-gnu', + 'macos-arm64', + 'ios-xcframework', + 'android-arm64-v8a', + ]) + expect(nativeExtensionDependencyModulePaths(files, target, overrides)).toEqual(files); + expect(() => nativeExtensionDependencyModulePaths(files, 'linux-x64-gnu', { typo: [] })).toThrow( + /desktop native target/u, + ); + expect(() => + nativeExtensionDependencyModulePaths(files, 'linux-x64-gnu', { + 'windows-x64-msvc': ['lib/postgresql/foreign.so'], + }), + ).toThrow(/declared module paths/u); + expect(() => + nativeExtensionDependencyModulePaths(files, 'linux-x64-gnu', { 'windows-x64-msvc': 'invalid' }), + ).toThrow(/declared module paths/u); + expect(() => nativeExtensionDependencyModulePaths(files, undefined, [])).toThrow( + /must be a table/u, + ); +}); diff --git a/src/extensions/contrib/BUILD.bazel b/src/extensions/contrib/BUILD.bazel new file mode 100644 index 000000000..8300d7fa4 --- /dev/null +++ b/src/extensions/contrib/BUILD.bazel @@ -0,0 +1,9 @@ +load("//build_defs/extensions:contrib.bzl", "native_contrib_members") +load("//build_defs/extensions:contrib_carriers.bzl", "native_contrib_carriers") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["carriers.toml", "postgres18.toml"]) + +native_contrib_members(crypto = "@openssl//:crypto") +native_contrib_carriers() diff --git a/src/extensions/evidence/matrix.toml b/src/extensions/evidence/matrix.toml index f2f3de647..9bc48bb7f 100644 --- a/src/extensions/evidence/matrix.toml +++ b/src/extensions/evidence/matrix.toml @@ -32,6 +32,9 @@ source-digest-inputs = [ "src/extensions/external/pg_textsearch/recipe.toml", "src/extensions/external/pg_textsearch/targets/native-static-registry.toml", "src/extensions/external/pg_textsearch/tests/qualify.sh", + "src/extensions/external/pg_textsearch/tests/seed.sql", + "src/extensions/external/pg_textsearch/tests/upgrade.sql", + "src/extensions/external/pg_textsearch/tests/verify.sql", "src/extensions/external/pg_textsearch/upstream-license-data.json", "src/extensions/external/pg_uuidv7/upstream-license-data.json", "src/extensions/external/pgtap/recipe.toml", diff --git a/src/extensions/external/pg_hashids/BUILD.bazel b/src/extensions/external/pg_hashids/BUILD.bazel new file mode 100644 index 000000000..e04e22d39 --- /dev/null +++ b/src/extensions/external/pg_hashids/BUILD.bazel @@ -0,0 +1,28 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/extensions:external.bzl", "native_external_extension_modules") +load("//build_defs/extensions:extensions.bzl", "NATIVE_EXTENSION_CONFIGURATION", "extension_identity", "extension_member_payload", "extension_member_validation_test") +load("//build_defs/release:shipping.bzl", "shipping_package") +load("//build_defs/extensions:native_carriers.bzl", "native_external_extension_carriers") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["upstream-license-data.json", "release.toml", "source.toml"]) + +native_external_extension_carriers(sql_name = "pg_hashids") + +native_external_extension_modules(name = "pg_hashids") + + +extension_member_payload( + name = "native_payload", + sql_name = "pg_hashids", + owner = extension_identity("pg_hashids"), + resources = ["@pg_hashids//:sql_resources"], + server_module = ":pg_hashids_server_module", + embedded_module = ":pg_hashids_embedded_module", +) + +shipping_package(name = "native_member", owner = extension_identity("pg_hashids"), artifacts = [":native_payload"], ecosystem = "internal", package_name = "pg_hashids", configuration = NATIVE_EXTENSION_CONFIGURATION, role = "extension-member", suppliers = ":native_payload") +extension_member_validation_test(name = "native_payload_test", payload = ":native_payload", sql_name = "pg_hashids") + +source_quality_files() diff --git a/src/extensions/external/pg_hashids/source.toml b/src/extensions/external/pg_hashids/source.toml index 81fb473d4..9f89eab65 100644 --- a/src/extensions/external/pg_hashids/source.toml +++ b/src/extensions/external/pg_hashids/source.toml @@ -7,3 +7,6 @@ commit = "8c404dd86408f3a987a3ff6825ac7e42bd618b98" sql-name = "pg_hashids" source-path = "pg_hashids.control" default-version = "1.3" + +[archive] +sha256 = "01805af758549c7f3da80198451c42db976167ef7a1a5a8abafd10292ee128ab" diff --git a/src/extensions/external/pg_ivm/BUILD.bazel b/src/extensions/external/pg_ivm/BUILD.bazel new file mode 100644 index 000000000..08e3fc484 --- /dev/null +++ b/src/extensions/external/pg_ivm/BUILD.bazel @@ -0,0 +1,28 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/extensions:external.bzl", "native_external_extension_modules") +load("//build_defs/extensions:extensions.bzl", "NATIVE_EXTENSION_CONFIGURATION", "extension_identity", "extension_member_payload", "extension_member_validation_test") +load("//build_defs/release:shipping.bzl", "shipping_package") +load("//build_defs/extensions:native_carriers.bzl", "native_external_extension_carriers") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["upstream-license-data.json", "release.toml", "source.toml"]) + +native_external_extension_carriers(sql_name = "pg_ivm") + +native_external_extension_modules(name = "pg_ivm") + + +extension_member_payload( + name = "native_payload", + sql_name = "pg_ivm", + owner = extension_identity("pg_ivm"), + resources = ["@pg_ivm//:sql_resources"], + server_module = ":pg_ivm_server_module", + embedded_module = ":pg_ivm_embedded_module", +) + +shipping_package(name = "native_member", owner = extension_identity("pg_ivm"), artifacts = [":native_payload"], ecosystem = "internal", package_name = "pg_ivm", configuration = NATIVE_EXTENSION_CONFIGURATION, role = "extension-member", suppliers = ":native_payload") +extension_member_validation_test(name = "native_payload_test", payload = ":native_payload", sql_name = "pg_ivm") + +source_quality_files() diff --git a/src/extensions/external/pg_ivm/source.toml b/src/extensions/external/pg_ivm/source.toml index 30babd02e..2ea97a8e4 100644 --- a/src/extensions/external/pg_ivm/source.toml +++ b/src/extensions/external/pg_ivm/source.toml @@ -7,3 +7,6 @@ commit = "b66487f7a6f8deee3998e858d773e19923e4bd4b" sql-name = "pg_ivm" source-path = "pg_ivm.control" default-version = "1.13" + +[archive] +sha256 = "a7c29129e959dd4233a7e565883e15e97bf9aa8e40650597868447227788fd12" diff --git a/src/extensions/external/pg_textsearch/BUILD.bazel b/src/extensions/external/pg_textsearch/BUILD.bazel new file mode 100644 index 000000000..6804fef53 --- /dev/null +++ b/src/extensions/external/pg_textsearch/BUILD.bazel @@ -0,0 +1,49 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/extensions:external.bzl", "native_external_extension_modules") +load("//build_defs/extensions:extensions.bzl", "NATIVE_EXTENSION_CONFIGURATION", "extension_default_version", "extension_identity", "extension_member_payload", "extension_member_validation_test") +load("//build_defs/release:shipping.bzl", "shipping_package") +load("//build_defs/extensions:native_carriers.bzl", "native_external_extension_carriers") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["upstream-license-data.json", "release.toml", "source.toml", "recipe.toml"]) + +native_external_extension_carriers( + sql_name = "pg_textsearch", + additional_qualification = select({ + "//build_defs/native:linux_x86_64": ["//src/extensions/external/pg_textsearch/tests:native_upstream_test"], + "//conditions:default": [], + }), +) + +native_external_extension_modules(name = "pg_textsearch") + +filegroup( + name = "sql_resources", + srcs = [ + "@pg_textsearch//:pg_textsearch.control", + "@pg_textsearch//:sql/pg_textsearch--" + extension_default_version("pg_textsearch") + ".sql", + "@pg_textsearch//:sql_upgrade_resources", + ], +) + +extension_member_payload( + name = "native_payload", + sql_name = "pg_textsearch", + owner = extension_identity("pg_textsearch"), + resources = [":sql_resources"], + server_module = ":pg_textsearch_server_module", + embedded_module = ":pg_textsearch_embedded_module", + construction_licenses = select({ + "//build_defs/native:linux_x86_64_gnu_2_28": { + "@pgvector_compiler_rt//:LICENSE.TXT": "share/licenses/llvm-compiler-rt/LICENSE.TXT", + "@pgvector_compiler_rt//:SOURCE.json": "share/licenses/llvm-compiler-rt/SOURCE.json", + }, + "//conditions:default": {}, + }), +) + +shipping_package(name = "native_member", owner = extension_identity("pg_textsearch"), artifacts = [":native_payload"], ecosystem = "internal", package_name = "pg_textsearch", configuration = NATIVE_EXTENSION_CONFIGURATION, role = "extension-member", suppliers = ":native_payload") +extension_member_validation_test(name = "native_payload_test", payload = ":native_payload", sql_name = "pg_textsearch") + +source_quality_files() diff --git a/src/extensions/external/pg_textsearch/source.toml b/src/extensions/external/pg_textsearch/source.toml index 2b92baf04..20365eeba 100644 --- a/src/extensions/external/pg_textsearch/source.toml +++ b/src/extensions/external/pg_textsearch/source.toml @@ -7,3 +7,6 @@ commit = "fa142d049d08eac45a263f5abc250c8877ae076e" sql-name = "pg_textsearch" source-path = "pg_textsearch.control" default-version = "1.5.1" + +[archive] +sha256 = "445a546810cbc17e15d05ff8a391f1b693eab382a2ef6efbf72e1c37fa0c48d0" diff --git a/src/extensions/external/pg_textsearch/tests/BUILD.bazel b/src/extensions/external/pg_textsearch/tests/BUILD.bazel new file mode 100644 index 000000000..0c3e843a9 --- /dev/null +++ b/src/extensions/external/pg_textsearch/tests/BUILD.bazel @@ -0,0 +1,87 @@ +load("@rules_cc//cc:defs.bzl", "cc_binary") +load("//build_defs/extensions:extensions.bzl", "extension_source_headers", "native_extension_modules") +load("//build_defs/extensions:platforms.bzl", "NATIVE_EXTENSION_LINUX_COMPATIBLE") +load("//build_defs/foundation:bun.bzl", "bun_script_test") +load("//build_defs/quality:sources.bzl", "source_quality_files") + +package(default_visibility = ["//visibility:public"], default_testonly = True) + +exports_files(["upgrade/source.toml", "seed.sql", "upgrade.sql", "verify.sql"]) + +extension_source_headers( + name = "old_headers", + hdrs = ["@pg_textsearch_upgrade_from//:headers"], + include_root = "@pg_textsearch_upgrade_from//:src/constants.h", +) + +# The exact 0.6.1 PGXS object inventory; only its ordinary server module is used. +native_extension_modules( + name = "upgrade_from", + srcs = ["@pg_textsearch_upgrade_from//:src/" + unit + ".c" for unit in [ + "mod", "source", "am/handler", "am/build", "am/build_context", "am/build_parallel", "am/scan", "am/vacuum", + "memtable/arena", "memtable/expull", "memtable/memtable", "memtable/posting", "memtable/stringtable", "memtable/scan", "memtable/source", + "segment/segment", "segment/dictionary", "segment/scan", "segment/merge", "segment/docmap", "segment/compression", + "query/bmw", "query/score", "types/vector", "types/query", "state/state", "state/registry", "state/metapage", "state/limit", + "planner/hooks", "planner/cost", "debug/dump", + ]], + deps = [":old_headers"], + copts = ["-DPG_TEXTSEARCH_VERSION=\\\"0.6.1\\\""], + linux_only = True, +) + +extension_source_headers( + name = "upstream_headers", + hdrs = ["@pg_textsearch//:headers", "@pg_textsearch//:src/segment/compression.c"], + include_root = "@pg_textsearch//:src/constants.h", +) + +# Match the three standalone C executions required by upstream installcheck. +# Keep assert() active in optimized CI builds; these tests do not link a backend. +[ + cc_binary( + name = name, + srcs = ["@pg_textsearch//:test/scripts/" + source + ".c"], + deps = [":upstream_headers", "//src/native/runtime:postgres_server_headers"] + (select({ + "//build_defs/native:linux_x86_64_gnu_2_28": ["@pgvector_compiler_rt//:cpu_model"], + "//conditions:default": [], + }) if source == "compression_test" else []), + copts = ["-std=gnu11", "-UNDEBUG"] + options, + target_compatible_with = NATIVE_EXTENSION_LINUX_COMPATIBLE, + ) + for name, source, options in [ + ("segment_io_limits_test", "segment_io_limits_test", []), + ("compression_test", "compression_test", []), + ("compression_scalar_test", "compression_test", ["-DTP_TEST_NO_AVX2"]), + ] +] + +_INPUTS = [ + "//src/native/runtime:runtime_payload", + "//src/native/runtime:tools_payload", + "//src/extensions/external/pg_textsearch:native_payload_test_archive", + ":upgrade_from_server.so", + "@pg_textsearch_upgrade_from//:pg_textsearch.control", + "@pg_textsearch//:Makefile", + "@postgres//:pg_regress", + ":segment_io_limits_test", + ":compression_test", + ":compression_scalar_test", +] + +bun_script_test( + name = "native_upstream_test", + entry_point = "native-upstream.test.mts", + args = ["$(location %s)" % label for label in _INPUTS], + data = _INPUTS + [ + "@pg_textsearch_upgrade_from//:sql_resources", + "@pg_textsearch//:test_inputs", + "upgrade/source.toml", "seed.sql", "upgrade.sql", "verify.sql", + "//build_defs/native:host-runtime-test-helpers.mts", + "//build_defs/extensions:native_carrier_install_helpers.mts", + "//:tools/packaging/portable-archive.mts", + ], + size = "large", + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) + +source_quality_files() diff --git a/src/extensions/external/pg_textsearch/tests/native-upstream.test.mts b/src/extensions/external/pg_textsearch/tests/native-upstream.test.mts new file mode 100644 index 000000000..6cbec0d62 --- /dev/null +++ b/src/extensions/external/pg_textsearch/tests/native-upstream.test.mts @@ -0,0 +1,357 @@ +/** Original upstream SQL/C regressions and the shared persisted 0.6.1 upgrade proof. */ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + copyFileSync, + cpSync, + existsSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { endianness, tmpdir } from 'node:os'; +import { dirname, join, resolve } from 'node:path'; +import { extractNativeArchive } from '../../../../../build_defs/extensions/native_carrier_install_helpers.mts'; +import { + extractNativePayload, + hostRuntimeEnvironment, + runHostBinary, +} from '../../../../../build_defs/native/host-runtime-test-helpers.mts'; + +assert.equal(process.platform, 'linux', 'upstream qualification uses the declared Linux profile'); +assert.equal(endianness(), 'LE', 'the two upstream native-endian fixtures require this LE profile'); +assert.equal( + process.argv.length, + 12, + 'expected actual runtime, modules, regression driver and C tests', +); +const [ + runtimeArchive, + toolsArchive, + currentArchive, + oldModule, + oldControl, + currentMakefile, + regress, + ...cTests +] = process.argv.slice(2).map((file) => resolve(file)); +const root = mkdtempSync(join(process.env.TEST_TMPDIR ?? tmpdir(), 'pg-textsearch-upgrade-')); +const socket = mkdtempSync('/tmp/oliphaunt-textsearch-'); +const runtime = join(root, 'runtime'); +const tools = join(root, 'tools'); +const current = join(root, 'current'); +const database = join(root, 'data'); +const source = dirname(currentMakefile); +const extension = join(runtime, 'share/postgresql/extension'); +const module = join(runtime, 'lib/postgresql/pg_textsearch.so'); +const log = join(root, 'postgres.log'); +const env = { + ...hostRuntimeEnvironment(runtime, root), + PGHOST: socket, + PGPORT: '5432', + PGUSER: 'postgres', + PGDATABASE: 'postgres', +}; +let running = false; +let failed = false; +const run = (binary: string, args: string[]) => runHostBinary(binary, args, env, root); +const psql = (database: string, args: string[]) => + run(join(tools, 'bin/psql'), ['-X', '-v', 'ON_ERROR_STOP=1', '-d', database, ...args]); +const sql = (database: string, statement: string) => + psql(database, ['-A', '-t', '-c', statement]).trim(); +const sharedSql = (name: string) => join(import.meta.dirname, `${name}.sql`); + +function start() { + running = true; + run(join(runtime, 'bin/pg_ctl'), ['-D', database, '-l', log, '-w', 'start']); +} + +function stop() { + run(join(runtime, 'bin/pg_ctl'), ['-D', database, '-m', 'fast', '-w', 'stop']); + running = false; +} + +function install(moduleFile: string, directory: string) { + copyFileSync(moduleFile, module); + chmodSync(module, 0o755); + copyFileSync(join(directory, 'pg_textsearch.control'), join(extension, 'pg_textsearch.control')); + chmodSync(join(extension, 'pg_textsearch.control'), 0o644); + for (const file of readdirSync(extension)) + if (/^pg_textsearch--.*\.sql$/u.test(file)) rmSync(join(extension, file)); + const sqlRoot = existsSync(join(directory, 'sql')) ? join(directory, 'sql') : directory; + const files = readdirSync(sqlRoot).filter((name) => /^pg_textsearch--.*\.sql$/u.test(name)); + assert(files.length > 0, 'the declared source must retain its SQL install/upgrade chain'); + for (const file of files) { + copyFileSync(join(sqlRoot, file), join(extension, file)); + chmodSync(join(extension, file), 0o644); + } +} + +/** Match the two fixed COPY BINARY producers in the pinned upstream test sources. */ +function vectorFixtures() { + const word = (value: number, endian: 'BE' | 'LE') => { + const bytes = Buffer.alloc(4); + if (endian === 'BE') bytes.writeInt32BE(value); + else bytes.writeInt32LE(value); + return bytes; + }; + const name = Buffer.alloc(16); + name.write('compat_idx'); + const entry = (frequency: number, lexeme: string) => { + const bytes = Buffer.alloc(16); + bytes.writeInt32LE(frequency, 0); + bytes.writeInt32LE(Buffer.byteLength(lexeme), 4); + bytes.write(lexeme, 8); + return bytes; + }; + const legacy = Buffer.concat([ + word(60, 'BE'), + word(10, 'LE'), + word(2, 'LE'), + name, + entry(1, 'alpha'), + entry(2, 'bravo'), + ]); + const nul = Buffer.concat([ + word(45, 'BE'), + Buffer.from('BM25'), + Buffer.from([2, 0, 0, 0]), + word(10, 'LE'), + word(1, 'LE'), + name, + Buffer.from([1, 7]), + Buffer.from('bad\0lex'), + ]); + const copy = (value: Buffer) => + Buffer.concat([ + Buffer.from('PGCOPY\n\xff\r\n\0', 'latin1'), + Buffer.alloc(8), + Buffer.from([0, 2]), + word(4, 'BE'), + word(42, 'BE'), + word(value.length, 'BE'), + value, + Buffer.from([255, 255]), + ]); + return [ + { + script: 'gen_v1_bm25vector.py', + sourceSha: '9a8a345a1bbf00c8bcf55d1fb7c9daec478c68ea7ee2b31d3a7c9a9047cbfbc1', + output: 'legacy-vector.bin', + bytes: copy(legacy), + sha: '85ea5f9e125da70a0cfa1bfe8a07904e9e7a3ad9ce7f74c1c91fcbe7bd800f1a', + }, + { + script: 'gen_nul_lexeme_bm25vector.py', + sourceSha: '4c173535c653a5b4a86e761490c3bb1cc4dac189a0b585e740b9ccebdc7116d2', + output: 'nul-vector.bin', + bytes: copy(nul), + sha: '05a6307ba70a75adde3a727a662df52c482b6e0a67c4e5b5673c4687b8321350', + }, + ]; +} + +function upstreamInputs(): string[] { + const makefile = readFileSync(currentMakefile, 'utf8'); + const initial = /^REGRESS = (.+)$/mu.exec(makefile); + assert(initial, 'upstream must declare its production regression schedule'); + const schedule = [ + initial[1], + ...[...makefile.matchAll(/^REGRESS \+= ([a-z0-9_ ]+)$/gmu)].map((match) => match[1]), + ] + .join(' ') + .trim() + .split(/\s+/u); + assert.equal(schedule.length, 82, 'review a changed upstream production regression schedule'); + assert.equal(new Set(schedule).size, schedule.length); + assert.equal(schedule[0], 'preload'); + // The configured native host has injection points disabled; upstream itself + // adds INJECTION_REGRESS only to an injection-enabled PostgreSQL build. + assert( + makefile.includes('ifeq ($(enable_injection_points),yes)\nREGRESS += $(INJECTION_REGRESS)'), + ); + for (const directory of ['sql', 'expected']) { + mkdirSync(join(root, 'test', directory), { recursive: true }); + const suffix = directory === 'sql' ? '.sql' : '.out'; + for (const file of readdirSync(join(source, 'test', directory))) + if (file.endsWith(suffix)) { + copyFileSync(join(source, 'test', directory, file), join(root, 'test', directory, file)); + chmodSync(join(root, 'test', directory, file), 0o644); + } + } + for (const test of schedule) { + assert(existsSync(join(root, 'test/sql', `${test}.sql`)), `missing declared SQL ${test}`); + assert( + existsSync(join(root, 'test/expected', `${test}.out`)), + `missing declared expectation ${test}`, + ); + } + mkdirSync(join(root, 'test/fixtures')); + const digest = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); + for (const fixture of vectorFixtures()) { + assert.equal( + digest(readFileSync(join(source, 'test/scripts', fixture.script))), + fixture.sourceSha, + ); + assert.equal( + digest(fixture.bytes), + fixture.sha, + 'TS fixture differs from the pinned upstream binary format', + ); + writeFileSync(join(root, 'test/fixtures', fixture.output), fixture.bytes); + for (const file of ['sql/vector_v1_rejected.sql', 'expected/vector_v1_rejected.out']) { + const target = join(root, 'test', file); + const before = readFileSync(target, 'utf8'); + const command = `PROGRAM 'python3 test/scripts/${fixture.script}'`; + assert.equal( + before.split(command).length, + 2, + 'review a changed upstream COPY fixture command', + ); + writeFileSync(target, before.replace(command, `'test/fixtures/${fixture.output}'`)); + } + } + for (const file of ['sql/binary_io.sql', 'expected/binary_io.out']) { + const target = join(root, 'test', file); + let text = readFileSync(target, 'utf8'); + for (const name of ['query_export.bin', 'vector_export.bin']) { + assert.equal(text.split(`/tmp/${name}`).length, 4, 'review upstream binary I/O isolation'); + text = text.replaceAll(`/tmp/${name}`, `test/fixtures/${name}`); + } + writeFileSync(target, text); + } + return schedule; +} + +try { + await extractNativePayload(runtimeArchive, runtime); + await extractNativePayload(toolsArchive, tools); + extractNativeArchive(currentArchive, current); + cpSync(current, runtime, { recursive: true }); + const currentExtension = join(current, 'share/postgresql/extension'); + const currentVersion = /default_version\s*=\s*'([^']+)'/u.exec( + readFileSync(join(currentExtension, 'pg_textsearch.control'), 'utf8'), + )?.[1]; + const oldVersion = /default_version\s*=\s*'([^']+)'/u.exec(readFileSync(oldControl, 'utf8'))?.[1]; + assert.equal(oldVersion, '0.6.1'); + assert.equal(currentVersion, '1.5.1'); + const dataAssignments = [ + ...readFileSync(currentMakefile, 'utf8') + .replace(/\\\r?\n[ \t]*/gu, ' ') + .matchAll(/^DATA[ \t]*([+:?]?=)[ \t]*(.*)$/gmu), + ]; + assert.equal(dataAssignments.length, 1, 'upstream must declare one literal DATA inventory'); + assert.equal(dataAssignments[0][1], '='); + const dataFiles = dataAssignments[0][2].trim().split(/\s+/u); + assert( + dataFiles.every((file) => /^sql\/pg_textsearch--[0-9.]+(?:--[0-9.]+)?\.sql$/u.test(file)), + 'review a nonliteral upstream DATA inventory', + ); + assert.deepEqual( + readdirSync(currentExtension).filter((file) => file.endsWith('.sql')).sort(), + dataFiles.map((file) => file.slice('sql/'.length)).sort(), + 'shipped SQL differs from the upstream PGXS DATA inventory', + ); + for (const binary of cTests) run(binary, []); + install(oldModule, dirname(oldControl)); + run(join(runtime, 'bin/initdb'), [ + '-D', + database, + '-U', + env.PGUSER, + '--auth-local=trust', + '--auth-host=reject', + '--locale=C', + '--encoding=UTF8', + '--no-sync', + ]); + writeFileSync( + join(database, 'postgresql.conf'), + [ + readFileSync(join(database, 'postgresql.conf'), 'utf8'), + "listen_addresses = ''", + `unix_socket_directories = '${socket}'`, + "shared_preload_libraries = 'pg_textsearch'", + 'shared_buffers = 256MB', + 'max_connections = 20', + ].join('\n') + '\n', + ); + start(); + sql('postgres', 'CREATE DATABASE pg_textsearch_upgrade'); + psql('pg_textsearch_upgrade', ['-v', `old_version=${oldVersion}`, '-f', sharedSql('seed')]); + stop(); + install(join(current, 'lib/postgresql/pg_textsearch.so'), currentExtension); + start(); + // This shared SQL first reads the old persisted postings with the new library, + // then ALTERs the extension and performs inserts/updates/deletes/compaction. + psql('pg_textsearch_upgrade', ['-f', sharedSql('upgrade')]); + const verify = (name: string) => { + psql(name, ['-f', sharedSql('verify')]); + assert.equal( + sql(name, "SELECT extversion FROM pg_extension WHERE extname = 'pg_textsearch'"), + currentVersion, + ); + }; + verify('pg_textsearch_upgrade'); + stop(); + start(); + verify('pg_textsearch_upgrade'); + const dump = run(join(tools, 'bin/pg_dump'), [ + '-d', + 'pg_textsearch_upgrade', + '--no-owner', + '--no-privileges', + ]); + const dumped = join(root, 'upgrade.sql'); + writeFileSync(dumped, dump); + sql('postgres', 'CREATE DATABASE pg_textsearch_upgrade_restore'); + psql('pg_textsearch_upgrade_restore', ['-f', dumped]); + verify('pg_textsearch_upgrade_restore'); + const schedule = upstreamInputs(); + // Original pg_regress owns psql execution and exact expected/alternate matching. + // Benchmark harness self-tests, optional replication and injection suites are + // outside this artifact gate; none of the production REGRESS cases are dropped. + run(regress, [ + '--bindir=' + join(tools, 'bin'), + '--inputdir=test', + '--outputdir=test', + '--host=' + socket, + '--port=5432', + '--user=' + env.PGUSER, + '--dbname=contrib_regression', + ...schedule, + ]); + stop(); + console.log( + `pg_textsearch ${oldVersion} -> ${currentVersion}: persisted upgrade/restart/dump-restore, ${schedule.length} upstream SQL cases and ${cTests.length} native C executions PASS`, + ); +} catch (error) { + failed = true; + for (const file of [log, join(root, 'test/regression.diffs')]) + if (existsSync(file)) console.error(readFileSync(file, 'utf8').slice(-64000)); + throw error; +} finally { + let mayRemove = true; + if (running && existsSync(join(database, 'postmaster.pid'))) { + const result = Bun.spawnSync( + [join(runtime, 'bin/pg_ctl'), '-D', database, '-m', 'immediate', '-w', 'stop'], + { env, cwd: root, stdout: 'pipe', stderr: 'pipe' }, + ); + if (result.exitCode !== 0) { + mayRemove = false; + const error = new Error( + `server stop failed; preserving ${root}: ${result.stderr.toString()}`, + ); + if (!failed) throw error; + console.error(error); + } + } + if (mayRemove) { + rmSync(socket, { recursive: true, force: true }); + rmSync(root, { recursive: true, force: true }); + } +} diff --git a/src/extensions/external/pg_textsearch/tests/qualify.sh b/src/extensions/external/pg_textsearch/tests/qualify.sh index 1251fc381..3b8cdef08 100755 --- a/src/extensions/external/pg_textsearch/tests/qualify.sh +++ b/src/extensions/external/pg_textsearch/tests/qualify.sh @@ -163,36 +163,7 @@ psql_db() { start_server psql_db postgres -c 'CREATE DATABASE pg_textsearch_upgrade' >/dev/null -psql_db pg_textsearch_upgrade -v old_version="$old_version" <<'SQL' -CREATE EXTENSION pg_textsearch VERSION :'old_version'; -CREATE TABLE upgrade_docs(id integer PRIMARY KEY, body text NOT NULL); -INSERT INTO upgrade_docs -SELECT id, - CASE - WHEN id = 1 THEN 'postgres database postgres database query migration' - WHEN id = 3 THEN 'legacyalpha legacyalpha persisted posting' - WHEN id = 4 THEN 'deletionproof deletionproof persisted posting' - WHEN id = 5 THEN 'legacybeta legacybeta persisted posting' - WHEN id = 6 THEN 'deletionproof surviving persisted posting' - WHEN id % 2 = 0 THEN 'postgres database guide' - ELSE 'unrelated document about wildlife' - END -FROM generate_series(1, 256) AS id; -CREATE INDEX upgrade_docs_bm25 ON upgrade_docs USING bm25(body) - WITH (text_config = 'english'); -SELECT bm25_spill_index('upgrade_docs_bm25'); -DO $$ -DECLARE top_id integer; -BEGIN - SELECT id INTO top_id - FROM upgrade_docs - ORDER BY body <@> to_bm25query('postgres database', 'upgrade_docs_bm25') - LIMIT 1; - IF top_id IS DISTINCT FROM 1 THEN - RAISE EXCEPTION 'old pg_textsearch query returned unexpected top id %', top_id; - END IF; -END $$; -SQL +psql_db pg_textsearch_upgrade -v old_version="$old_version" -f "$script_dir/seed.sql" stop_server find "$extension_dir" -maxdepth 1 -type f -name 'pg_textsearch--*.sql' -delete @@ -201,67 +172,12 @@ install -m 0644 "$source_runtime/share/postgresql/extension/pg_textsearch.contro install -m 0644 "${current_sql_files[@]}" "$extension_dir/" start_server -psql_db pg_textsearch_upgrade <<'SQL' -DO $$ -DECLARE top_id integer; -BEGIN - SELECT id INTO top_id - FROM upgrade_docs - ORDER BY body <@> to_bm25query('postgres database', 'upgrade_docs_bm25') - LIMIT 1; - IF top_id IS DISTINCT FROM 1 THEN - RAISE EXCEPTION 'pre-upgrade query with the current library returned unexpected top id %', top_id; - END IF; -END $$; -ALTER EXTENSION pg_textsearch UPDATE; -INSERT INTO upgrade_docs VALUES - (1000, 'upgrade sentinel upgrade sentinel upgrade sentinel migration proof'); -UPDATE upgrade_docs -SET body = 'mutationproof mutationproof updated persisted row' -WHERE id = 2; -DELETE FROM upgrade_docs WHERE id = 4; -SELECT bm25_force_merge('upgrade_docs_bm25'); -SQL +psql_db pg_textsearch_upgrade -f "$script_dir/upgrade.sql" assert_upgraded_state() { local database="$1" local installed_version - psql_db "$database" <<'SQL' -DO $$ -DECLARE - actual_body text; - actual_count bigint; - top_id integer; - probe record; -BEGIN - SELECT count(*) INTO actual_count FROM upgrade_docs; - IF actual_count IS DISTINCT FROM 256 THEN - RAISE EXCEPTION 'upgraded table contains % rows, expected 256', actual_count; - END IF; - - SELECT body INTO actual_body FROM upgrade_docs WHERE id = 2; - IF actual_body IS DISTINCT FROM 'mutationproof mutationproof updated persisted row' THEN - RAISE EXCEPTION 'updated row 2 has unexpected body %', actual_body; - END IF; - IF EXISTS (SELECT 1 FROM upgrade_docs WHERE id = 4) THEN - RAISE EXCEPTION 'deleted row 4 is still visible'; - END IF; - - FOR probe IN SELECT * FROM (VALUES - ('postgres database', 1), ('legacyalpha', 3), ('legacybeta', 5), - ('mutationproof', 2), ('upgrade sentinel', 1000), ('deletionproof', 6) - ) AS expected(term, id) - LOOP - SELECT id INTO top_id - FROM upgrade_docs - ORDER BY body <@> to_bm25query(probe.term, 'upgrade_docs_bm25') - LIMIT 1; - IF top_id IS DISTINCT FROM probe.id THEN - RAISE EXCEPTION 'upgraded query % returned id %, expected %', probe.term, top_id, probe.id; - END IF; - END LOOP; -END $$; -SQL + psql_db "$database" -f "$script_dir/verify.sql" installed_version="$(psql_db "$database" -Atc \ "SELECT extversion FROM pg_extension WHERE extname = 'pg_textsearch'")" [ "$installed_version" = "$current_version" ] || \ diff --git a/src/extensions/external/pg_textsearch/tests/seed.sql b/src/extensions/external/pg_textsearch/tests/seed.sql new file mode 100644 index 000000000..c1782343c --- /dev/null +++ b/src/extensions/external/pg_textsearch/tests/seed.sql @@ -0,0 +1,28 @@ +CREATE EXTENSION pg_textsearch VERSION :'old_version'; +CREATE TABLE upgrade_docs(id integer PRIMARY KEY, body text NOT NULL); +INSERT INTO upgrade_docs +SELECT id, + CASE + WHEN id = 1 THEN 'postgres database postgres database query migration' + WHEN id = 3 THEN 'legacyalpha legacyalpha persisted posting' + WHEN id = 4 THEN 'deletionproof deletionproof persisted posting' + WHEN id = 5 THEN 'legacybeta legacybeta persisted posting' + WHEN id = 6 THEN 'deletionproof surviving persisted posting' + WHEN id % 2 = 0 THEN 'postgres database guide' + ELSE 'unrelated document about wildlife' + END +FROM generate_series(1, 256) AS id; +CREATE INDEX upgrade_docs_bm25 ON upgrade_docs USING bm25(body) + WITH (text_config = 'english'); +SELECT bm25_spill_index('upgrade_docs_bm25'); +DO $$ +DECLARE top_id integer; +BEGIN + SELECT id INTO top_id + FROM upgrade_docs + ORDER BY body <@> to_bm25query('postgres database', 'upgrade_docs_bm25') + LIMIT 1; + IF top_id IS DISTINCT FROM 1 THEN + RAISE EXCEPTION 'old pg_textsearch query returned unexpected top id %', top_id; + END IF; +END $$; diff --git a/src/extensions/external/pg_textsearch/tests/upgrade.sql b/src/extensions/external/pg_textsearch/tests/upgrade.sql new file mode 100644 index 000000000..4f5f19156 --- /dev/null +++ b/src/extensions/external/pg_textsearch/tests/upgrade.sql @@ -0,0 +1,19 @@ +DO $$ +DECLARE top_id integer; +BEGIN + SELECT id INTO top_id + FROM upgrade_docs + ORDER BY body <@> to_bm25query('postgres database', 'upgrade_docs_bm25') + LIMIT 1; + IF top_id IS DISTINCT FROM 1 THEN + RAISE EXCEPTION 'pre-upgrade query with the current library returned unexpected top id %', top_id; + END IF; +END $$; +ALTER EXTENSION pg_textsearch UPDATE; +INSERT INTO upgrade_docs VALUES + (1000, 'upgrade sentinel upgrade sentinel upgrade sentinel migration proof'); +UPDATE upgrade_docs +SET body = 'mutationproof mutationproof updated persisted row' +WHERE id = 2; +DELETE FROM upgrade_docs WHERE id = 4; +SELECT bm25_force_merge('upgrade_docs_bm25'); diff --git a/src/extensions/external/pg_textsearch/tests/upgrade/source.toml b/src/extensions/external/pg_textsearch/tests/upgrade/source.toml index cf5bc57d5..78dca4979 100644 --- a/src/extensions/external/pg_textsearch/tests/upgrade/source.toml +++ b/src/extensions/external/pg_textsearch/tests/upgrade/source.toml @@ -7,3 +7,6 @@ commit = "07936f7cd67f7a183659d3acd459c0a5efc93756" sql-name = "pg_textsearch" source-path = "pg_textsearch.control" default-version = "0.6.1" + +[archive] +sha256 = "7ea1578c622667eb48937a3205ed1449ae470abea43e1fdee6df0c81aeff4914" diff --git a/src/extensions/external/pg_textsearch/tests/verify.sql b/src/extensions/external/pg_textsearch/tests/verify.sql new file mode 100644 index 000000000..712b7819e --- /dev/null +++ b/src/extensions/external/pg_textsearch/tests/verify.sql @@ -0,0 +1,34 @@ +DO $$ +DECLARE + actual_body text; + actual_count bigint; + top_id integer; + probe record; +BEGIN + SELECT count(*) INTO actual_count FROM upgrade_docs; + IF actual_count IS DISTINCT FROM 256 THEN + RAISE EXCEPTION 'upgraded table contains % rows, expected 256', actual_count; + END IF; + + SELECT body INTO actual_body FROM upgrade_docs WHERE id = 2; + IF actual_body IS DISTINCT FROM 'mutationproof mutationproof updated persisted row' THEN + RAISE EXCEPTION 'updated row 2 has unexpected body %', actual_body; + END IF; + IF EXISTS (SELECT 1 FROM upgrade_docs WHERE id = 4) THEN + RAISE EXCEPTION 'deleted row 4 is still visible'; + END IF; + + FOR probe IN SELECT * FROM (VALUES + ('postgres database', 1), ('legacyalpha', 3), ('legacybeta', 5), + ('mutationproof', 2), ('upgrade sentinel', 1000), ('deletionproof', 6) + ) AS expected(term, id) + LOOP + SELECT id INTO top_id + FROM upgrade_docs + ORDER BY body <@> to_bm25query(probe.term, 'upgrade_docs_bm25') + LIMIT 1; + IF top_id IS DISTINCT FROM probe.id THEN + RAISE EXCEPTION 'upgraded query % returned id %, expected %', probe.term, top_id, probe.id; + END IF; + END LOOP; +END $$; diff --git a/src/extensions/external/pg_uuidv7/BUILD.bazel b/src/extensions/external/pg_uuidv7/BUILD.bazel new file mode 100644 index 000000000..68833fcc5 --- /dev/null +++ b/src/extensions/external/pg_uuidv7/BUILD.bazel @@ -0,0 +1,28 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/extensions:external.bzl", "native_external_extension_modules") +load("//build_defs/extensions:extensions.bzl", "NATIVE_EXTENSION_CONFIGURATION", "extension_identity", "extension_member_payload", "extension_member_validation_test") +load("//build_defs/release:shipping.bzl", "shipping_package") +load("//build_defs/extensions:native_carriers.bzl", "native_external_extension_carriers") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["upstream-license-data.json", "release.toml", "source.toml"]) + +native_external_extension_carriers(sql_name = "pg_uuidv7") + +native_external_extension_modules(name = "pg_uuidv7") + + +extension_member_payload( + name = "native_payload", + sql_name = "pg_uuidv7", + owner = extension_identity("pg_uuidv7"), + resources = ["@pg_uuidv7//:sql_resources"], + server_module = ":pg_uuidv7_server_module", + embedded_module = ":pg_uuidv7_embedded_module", +) + +shipping_package(name = "native_member", owner = extension_identity("pg_uuidv7"), artifacts = [":native_payload"], ecosystem = "internal", package_name = "pg_uuidv7", configuration = NATIVE_EXTENSION_CONFIGURATION, role = "extension-member", suppliers = ":native_payload") +extension_member_validation_test(name = "native_payload_test", payload = ":native_payload", sql_name = "pg_uuidv7") + +source_quality_files() diff --git a/src/extensions/external/pg_uuidv7/source.toml b/src/extensions/external/pg_uuidv7/source.toml index 5c31a9e72..95d0688c3 100644 --- a/src/extensions/external/pg_uuidv7/source.toml +++ b/src/extensions/external/pg_uuidv7/source.toml @@ -7,3 +7,6 @@ commit = "c707aae2411181be4802f5fa565b44d9c0bcbc29" sql-name = "pg_uuidv7" source-path = "pg_uuidv7.control" default-version = "1.7" + +[archive] +sha256 = "422b882887ace16a1358150eb8bcfcf41a74ae60db89818929ba4f59ba360251" diff --git a/src/extensions/external/pgtap/BUILD.bazel b/src/extensions/external/pgtap/BUILD.bazel new file mode 100644 index 000000000..197332529 --- /dev/null +++ b/src/extensions/external/pgtap/BUILD.bazel @@ -0,0 +1,46 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/extensions:extensions.bzl", "NATIVE_EXTENSION_CONFIGURATION", "PGTAP_TARGET_OS_ARGS", "extension_identity", "extension_member_payload", "extension_member_validation_test", "pgtap_sql") +load("//build_defs/release:shipping.bzl", "shipping_package") +load("//build_defs/foundation:bun.bzl", "bun_script_test") +load("//build_defs/extensions:native_carriers.bzl", "native_external_extension_carriers") +load("//build_defs/extensions:wasix_carriers.bzl", "wasix_sql_extension_carriers") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["upstream-license-data.json", "release.toml", "source.toml", "recipe.toml"]) + +native_external_extension_carriers(sql_name = "pgtap") +wasix_sql_extension_carriers(sql_name = "pgtap") + +pgtap_sql(name = "sql", inputs = ["@pgtap//:sql_inputs"], control = "@pgtap//:pgtap.control") + +extension_member_payload( + name = "native_payload", + sql_name = "pgtap", + owner = extension_identity("pgtap"), + resources = [":sql"], +) + +shipping_package( + name = "native_member", + owner = extension_identity("pgtap"), + artifacts = [":native_payload"], + suppliers = ":native_payload", + ecosystem = "internal", + package_name = "pgtap", + configuration = NATIVE_EXTENSION_CONFIGURATION, + role = "extension-member", +) + +extension_member_validation_test(name = "native_payload_test", payload = ":native_payload", sql_name = "pgtap") + +bun_script_test( + name = "upstream_sql_parity_test", + entry_point = "//build_defs/extensions:pgtap_upstream_parity_test.mts", + args = ["--control", "$(location @pgtap//:pgtap.control)", "--installed", "$(location :sql)", + "--perl", "$(location //build_defs/extensions:perl)", "--perl-options", "$(location //build_defs/extensions:perl_options)", "--patch", "$(location @native_exec_tools//:patch)"] + PGTAP_TARGET_OS_ARGS, + data = ["@pgtap//:sql_inputs", "@pgtap//:pgtap.control", ":sql", "//build_defs/extensions:perl", "//build_defs/extensions:perl_runtime", "//build_defs/extensions:perl_options", "@native_exec_tools//:patch"], + size = "small", +) + +source_quality_files() diff --git a/src/extensions/external/pgtap/source.toml b/src/extensions/external/pgtap/source.toml index 98265fca1..7f8751b21 100644 --- a/src/extensions/external/pgtap/source.toml +++ b/src/extensions/external/pgtap/source.toml @@ -7,3 +7,6 @@ commit = "b89585a64ffef012ff0f219de9197c669aa8485b" sql-name = "pgtap" source-path = "pgtap.control" default-version = "1.3.5" + +[archive] +sha256 = "ffd501f27670a7d3d7f0cfd4ea7f291848112c2ef408a0b73e4cb727ac83e604" diff --git a/src/extensions/external/postgis/BUILD.bazel b/src/extensions/external/postgis/BUILD.bazel new file mode 100644 index 000000000..ef66c957c --- /dev/null +++ b/src/extensions/external/postgis/BUILD.bazel @@ -0,0 +1,35 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/extensions/postgis:modules.bzl", "native_postgis_modules", "postgis_dependency_module_labels") +load("@oliphaunt_metadata//:metadata.bzl", "EXTENSION_RECIPES", "EXTENSION_SOURCES") +load("//build_defs/extensions:extensions.bzl", "NATIVE_EXTENSION_CONFIGURATION", "extension_identity", "extension_member_payload", "extension_member_validation_test") +load("//build_defs/release:shipping.bzl", "shipping_package") +load("//build_defs/extensions:native_carriers.bzl", "native_external_extension_carriers") +load("//build_defs/extensions:owner_carriers.bzl", "native_extension_final_contract_test") +load("//build_defs/extensions:platforms.bzl", "NATIVE_EXTENSION_COMPATIBLE") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["release.toml", "source.toml", "recipe.toml", "upstream-license-data.json"] + glob(["dependencies/*/source.toml"])) +exports_files(["tools/windows/postgis-compat.h", "tools/windows/flatgeobuf-compat.h"]) + +native_external_extension_carriers(sql_name = "postgis") +native_extension_final_contract_test(name = "native_final_contract_test", products = [EXTENSION_SOURCES["postgis"]["product"]], target_compatible_with = NATIVE_EXTENSION_COMPATIBLE) + +native_postgis_modules(name = "postgis", standalone = "//build_defs/extensions/postgis:postgis", + dependency_module = "//build_defs/extensions/postgis:dependency_module") + +_DATA = EXTENSION_RECIPES["postgis"]["artifacts"]["data_files"] +_CONTRIB_DIRECTORIES = {"/".join(path.split("/")[:-1]): True for path in _DATA if path.endswith(".sql")}.keys() + +extension_member_payload(name = "native_payload", sql_name = "postgis", owner = extension_identity("postgis"), + resources = ["//build_defs/extensions/postgis:extension_sql", "//build_defs/extensions/postgis:control"], + data_resources = {"//build_defs/extensions/postgis:data_sql": _CONTRIB_DIRECTORIES[0], + "//build_defs/extensions/postgis:database": [path for path in _DATA if path.endswith("/proj.db")][0]}, + dependency_modules = postgis_dependency_module_labels("//build_defs/extensions/postgis:dependency_module"), + server_module = ":postgis_server_module", embedded_module = ":postgis_embedded_module") + +shipping_package(name = "native_member", owner = extension_identity("postgis"), artifacts = [":native_payload"], + ecosystem = "internal", package_name = "postgis", configuration = NATIVE_EXTENSION_CONFIGURATION, role = "extension-member", suppliers = ":native_payload") +extension_member_validation_test(name = "native_payload_test", payload = ":native_payload", sql_name = "postgis") + +source_quality_files() diff --git a/src/extensions/external/postgis/dependencies/geos/source.toml b/src/extensions/external/postgis/dependencies/geos/source.toml index a066a551b..4749e5edc 100644 --- a/src/extensions/external/postgis/dependencies/geos/source.toml +++ b/src/extensions/external/postgis/dependencies/geos/source.toml @@ -2,3 +2,6 @@ name = "geos" url = "https://github.com/libgeos/geos.git" branch = "3.14.1" commit = "c389f532d25fe6228861d9b19339f9cb57ca4bdb" + +[archive] +sha256 = "c6ef7660abd410d20b4f30085dfc1b0f804f487967aeddda6eca2aaa36abfa5a" diff --git a/src/extensions/external/postgis/dependencies/json-c/source.toml b/src/extensions/external/postgis/dependencies/json-c/source.toml index 9e3862321..2a789e6ef 100644 --- a/src/extensions/external/postgis/dependencies/json-c/source.toml +++ b/src/extensions/external/postgis/dependencies/json-c/source.toml @@ -2,3 +2,6 @@ name = "json-c" url = "https://github.com/json-c/json-c.git" branch = "json-c-0.18-20240915" commit = "41a55cfcedb54d9c1874f2f0eb07b504091d7e37" + +[archive] +sha256 = "a090046b2d24901eb8dca4d370c28991299e8c7cfb698b44e09ce809b1ff20b4" diff --git a/src/extensions/external/postgis/dependencies/libxml2/source.toml b/src/extensions/external/postgis/dependencies/libxml2/source.toml index 349df0ecb..062dad7a5 100644 --- a/src/extensions/external/postgis/dependencies/libxml2/source.toml +++ b/src/extensions/external/postgis/dependencies/libxml2/source.toml @@ -3,3 +3,6 @@ url = "https://gitlab.gnome.org/GNOME/libxml2.git" mirror_url = "https://github.com/GNOME/libxml2.git" branch = "v2.14.6" commit = "d23960a130c5bb82779c9405fbbf85e65fb3c57c" + +[archive] +sha256 = "2ac9ff16a006d9793ed23d31b40867aa41d23ae7762f8a25868f733944d5d775" diff --git a/src/extensions/external/postgis/dependencies/proj/source.toml b/src/extensions/external/postgis/dependencies/proj/source.toml index 4e7134ddc..beec50fce 100644 --- a/src/extensions/external/postgis/dependencies/proj/source.toml +++ b/src/extensions/external/postgis/dependencies/proj/source.toml @@ -2,3 +2,6 @@ name = "proj" url = "https://github.com/OSGeo/PROJ.git" branch = "9.8.1" commit = "f08fa86c478c4bbbf003b1ec751dd84aa6eca486" + +[archive] +sha256 = "db00adb24cb064895f9055095ea21fecc1349ffac1f225def2ef38f3dbc4831b" diff --git a/src/extensions/external/postgis/dependencies/sqlite/source.toml b/src/extensions/external/postgis/dependencies/sqlite/source.toml index 61eab3638..909435307 100644 --- a/src/extensions/external/postgis/dependencies/sqlite/source.toml +++ b/src/extensions/external/postgis/dependencies/sqlite/source.toml @@ -2,3 +2,6 @@ name = "sqlite" url = "https://github.com/sqlite/sqlite.git" branch = "version-3.53.1" commit = "ccd445d76a9362c63add000354fac84ba9022176" + +[archive] +sha256 = "96f14610a11721fbd5bd254db3ca833de9e4d922ce3da7122e092fdb19838b30" diff --git a/src/extensions/external/postgis/recipe.toml b/src/extensions/external/postgis/recipe.toml index 1a0758969..f58214592 100644 --- a/src/extensions/external/postgis/recipe.toml +++ b/src/extensions/external/postgis/recipe.toml @@ -62,6 +62,10 @@ licenses = [ "share/licenses/sqlite/LICENSE.md", ] +# Windows incorporates these dependencies into each ABI module. +[artifacts.native_dependency_modules_by_target] +windows-x64-msvc = [] + [[runtime_environment]] name = "PROJ_DATA" path = "share/postgresql/proj" diff --git a/src/extensions/external/postgis/source.toml b/src/extensions/external/postgis/source.toml index f5ea03afb..0d6003fd7 100644 --- a/src/extensions/external/postgis/source.toml +++ b/src/extensions/external/postgis/source.toml @@ -9,3 +9,6 @@ sql-name = "postgis" source-path = "extensions/postgis/postgis.control.in" source-default-version = "@EXTVERSION@" default-version = "3.6.3" + +[archive] +sha256 = "0cab012a4e470b2479d4dcaa6a64f5322fe64092e5c3018da94dfcfd106ef874" diff --git a/src/extensions/external/vector/BUILD.bazel b/src/extensions/external/vector/BUILD.bazel new file mode 100644 index 000000000..e342a7c12 --- /dev/null +++ b/src/extensions/external/vector/BUILD.bazel @@ -0,0 +1,46 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/extensions:external.bzl", "native_external_extension_modules") +load("//build_defs/extensions:extensions.bzl", "NATIVE_EXTENSION_CONFIGURATION", "extension_identity", "extension_member_payload", "extension_member_validation_test") +load("//build_defs/release:shipping.bzl", "shipping_package") +load("//build_defs/extensions:native_carriers.bzl", "native_external_extension_carriers") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["upstream-license-data.json", "release.toml", "source.toml", "recipe.toml"]) + +native_external_extension_carriers(sql_name = "vector") + +native_external_extension_modules(name = "vector") + + +extension_member_payload( + name = "native_payload", + sql_name = "vector", + owner = extension_identity("vector"), + resources = ["@pgvector//:sql_resources"], + main_sql = "@pgvector//:sql/vector.sql", + server_module = ":vector_server_module", + embedded_module = ":vector_embedded_module", + construction_licenses = select({ + "//build_defs/native:linux_x86_64_gnu_2_28": { + "@pgvector_compiler_rt//:LICENSE.TXT": "share/licenses/llvm-compiler-rt/LICENSE.TXT", + "@pgvector_compiler_rt//:SOURCE.json": "share/licenses/llvm-compiler-rt/SOURCE.json", + }, + "//conditions:default": {}, + }), +) + +shipping_package( + name = "native_member", + owner = extension_identity("vector"), + artifacts = [":native_payload"], + suppliers = ":native_payload", + ecosystem = "internal", + package_name = "vector", + configuration = NATIVE_EXTENSION_CONFIGURATION, + role = "extension-member", +) + +extension_member_validation_test(name = "native_payload_test", payload = ":native_payload", sql_name = "vector") + +source_quality_files() diff --git a/src/extensions/external/vector/source.toml b/src/extensions/external/vector/source.toml index 9793cfe07..4859801d6 100644 --- a/src/extensions/external/vector/source.toml +++ b/src/extensions/external/vector/source.toml @@ -7,3 +7,6 @@ commit = "d238409becebb8172fe696ffa776badfad4b631c" sql-name = "vector" source-path = "vector.control" default-version = "0.8.2" + +[archive] +sha256 = "64692fe3b2da7c1c3f53a37d6100400597008375960ab4ce3ddd79e0cd188226" diff --git a/src/extensions/generated/docs/extension-evidence.json b/src/extensions/generated/docs/extension-evidence.json index 7eec97f1b..3179350f5 100644 --- a/src/extensions/generated/docs/extension-evidence.json +++ b/src/extensions/generated/docs/extension-evidence.json @@ -1346,7 +1346,7 @@ "collector": "src/extensions/tools/collect-wasix-evidence.sh", "kind": "exact-sha-ci" }, - "source-digest": "sha256:9bd5bb09681d1ca3f0057fc0e91cddd2b1516d87940544ae17eb9ea4f1ddffa3", + "source-digest": "sha256:bf765062e908e2e5628e1064e8d1238fd9929ff736980a9351c8452b1d165945", "source-digest-inputs": [ "src/third-party/postgres/source.toml", "src/extensions/catalog/extensions.source.json", @@ -1380,6 +1380,9 @@ "src/extensions/external/pg_textsearch/recipe.toml", "src/extensions/external/pg_textsearch/targets/native-static-registry.toml", "src/extensions/external/pg_textsearch/tests/qualify.sh", + "src/extensions/external/pg_textsearch/tests/seed.sql", + "src/extensions/external/pg_textsearch/tests/upgrade.sql", + "src/extensions/external/pg_textsearch/tests/verify.sql", "src/extensions/external/pg_textsearch/upstream-license-data.json", "src/extensions/external/pg_uuidv7/upstream-license-data.json", "src/extensions/external/pgtap/recipe.toml", diff --git a/src/extensions/generated/sdk/BUILD.bazel b/src/extensions/generated/sdk/BUILD.bazel new file mode 100644 index 000000000..3455d1389 --- /dev/null +++ b/src/extensions/generated/sdk/BUILD.bazel @@ -0,0 +1,10 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/extensions:sdk_projections.bzl", "sdk_extension_metadata") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["ios-static-dependencies.json"]) + +sdk_extension_metadata(name = "metadata", out = "extensions.json") + +source_quality_files() diff --git a/src/extensions/moon.yml b/src/extensions/moon.yml index 1d2534ff6..bcbb262b6 100644 --- a/src/extensions/moon.yml +++ b/src/extensions/moon.yml @@ -141,6 +141,7 @@ tasks: - /tools/dev/bun.sh - "/tools/packaging/*.{mts,sh}" - "/tools/release/*.{mjs,mts}" + - /build_defs/extensions/windows_source_portability.mts options: cache: true runFromWorkspaceRoot: true diff --git a/src/extensions/tools/BUILD.bazel b/src/extensions/tools/BUILD.bazel new file mode 100644 index 000000000..ed380bd36 --- /dev/null +++ b/src/extensions/tools/BUILD.bazel @@ -0,0 +1,16 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +package(default_visibility = ["//visibility:public"]) + +exports_files([ + "extension-projections.mts", + "native-component-contract.mts", + "extension-upstream-licenses.mts", + "extension-artifact-archive-policy.mts", +]) + +source_quality_files() + +# Source-only inputs for the existing SDK package policy tests. +exports_files([ + "extension-evidence.mts", +], visibility = ["//visibility:public"]) diff --git a/src/extensions/tools/extension-evidence.mts b/src/extensions/tools/extension-evidence.mts index 1cbbed4b4..8c7bec548 100644 --- a/src/extensions/tools/extension-evidence.mts +++ b/src/extensions/tools/extension-evidence.mts @@ -1,6 +1,7 @@ import assert from 'node:assert/strict'; import { createHash } from 'node:crypto'; import { readFileSync } from 'node:fs'; +import path from 'node:path'; import { catalogPath, contribPath, @@ -22,10 +23,10 @@ const string = (value: unknown): value is string => typeof value === 'string' && const list = (value: unknown): value is string[] => Array.isArray(value) && value.every(string); const id = (value: unknown): value is string => typeof value === 'string' && /^[a-z][a-z0-9_]*$/.test(value); -const files = (pattern: string) => - [...new Bun.Glob(pattern).scanSync({ cwd: '.', onlyFiles: true })].sort(); +const files = (pattern: string, root = '.') => + [...new Bun.Glob(pattern).scanSync({ cwd: root, onlyFiles: true })].sort(); -export function sourceDigestInputs(): string[] { +export function sourceDigestInputs(root = '.'): string[] { const envelope = new Set(['CHANGELOG.md', 'VERSION', 'moon.yml', 'release.toml']); return [ 'src/third-party/postgres/source.toml', @@ -35,32 +36,42 @@ export function sourceDigestInputs(): string[] { catalogPath, 'src/extensions/generated/contrib-build.tsv', 'src/extensions/generated/pgxs-build.tsv', - ...files('src/third-party/{icu,openssl}/source.toml') - .concat(files('src/native/runtime/sources/*.toml')) - .concat(files('src/extensions/external/**/source.toml')) + ...files('src/third-party/{icu,openssl}/source.toml', root) + .concat(files('src/native/runtime/sources/*.toml', root)) + .concat(files('src/extensions/external/**/source.toml', root)) .concat('src/database-resources/icu/source.toml') .sort(), - ...files('src/extensions/external/**/*').filter( + ...files('src/extensions/external/**/*', root).filter( (file) => !envelope.has(file.split('/').at(-1)!) && + // This evidence tier covers legacy WASIX PGXS/target adapters. Native + // Bazel construction has separate proof; moving WASIX to that graph + // must explicitly revise its evidence inputs/tier before reuse. + !file.endsWith('/BUILD.bazel') && !file.endsWith('/source.toml') && !/\.test\.[cm]?ts$/.test(file), ), 'src/test-fixtures/extensions/manifest.json', - ...files('src/test-fixtures/extensions/*.sql'), + ...files('src/test-fixtures/extensions/*.sql', root), ]; } export function sourceDigest( - paths = sourceDigestInputs(), + paths: string[] | undefined = undefined, overrides = new Map(), + root = '.', ): string { const digest = createHash('sha256'); - for (const file of paths) + for (const file of paths ?? sourceDigestInputs(root)) digest .update(file) .update('\0') - .update((overrides.get(file) ?? readFileSync(file, 'utf8')).replace(/\r\n?/g, '\n')) + .update( + (overrides.get(file) ?? readFileSync(path.join(root, file), 'utf8')).replace( + /\r\n?/g, + '\n', + ), + ) .update('\0'); return `sha256:${digest.digest('hex')}`; } diff --git a/src/extensions/tools/extension-model.test.mts b/src/extensions/tools/extension-model.test.mts index 64b618a52..86a4803c9 100644 --- a/src/extensions/tools/extension-model.test.mts +++ b/src/extensions/tools/extension-model.test.mts @@ -1,5 +1,13 @@ import assert from 'node:assert/strict'; -import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { + copyFileSync, + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + writeFileSync, +} from 'node:fs'; import { tmpdir } from 'node:os'; import path from 'node:path'; import test from 'node:test'; @@ -10,7 +18,14 @@ import { sourceDigest, sourceDigestInputs, } from './extension-evidence.mts'; -import { discoverCatalog, extensionProjections, readJson } from './extension-projections.mts'; +import { + contribPath, + discoverCatalog, + extensionProjections, + readJson, + readToml, +} from './extension-projections.mts'; +import { nativeComponentInventory } from './native-component-contract.mts'; const identity = { commit: '1'.repeat(40), tree: '2'.repeat(40) }; const catalog = { extensions: [{ id: 'vector', 'sql-name': 'vector' }] }; @@ -56,6 +71,36 @@ function run() { }; } +test('native BUILD files leave legacy WASIX evidence unchanged while recipe edits invalidate it', () => { + const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-evidence-inputs-')); + const inputs = sourceDigestInputs(); + const digest = sourceDigest(inputs); + try { + for (const file of inputs) { + const destination = path.join(root, file); + mkdirSync(path.dirname(destination), { recursive: true }); + copyFileSync(file, destination); + } + assert.deepEqual(sourceDigestInputs(root), inputs); + assert.equal(sourceDigest(inputs, new Map(), root), digest); + + const nativeBuild = 'src/extensions/external/pgtap/BUILD.bazel'; + writeFileSync(path.join(root, nativeBuild), 'filegroup(name = "native_member")\n'); + assert.deepEqual(sourceDigestInputs(root), inputs); + assert.equal(sourceDigest(sourceDigestInputs(root), new Map(), root), digest); + + const recipe = path.join(root, 'src/extensions/external/pgtap/recipe.toml'); + const original = readFileSync(recipe, 'utf8'); + const changed = original.replace(/^postgres_majors\s*=.+$/m, 'postgres_majors = [18, 19]'); + assert.notEqual(changed, original); + writeFileSync(recipe, changed); + assert.deepEqual(sourceDigestInputs(root), inputs); + assert.notEqual(sourceDigest(sourceDigestInputs(root), new Map(), root), digest); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + test('only observed passing results for the current source commit qualify', () => { const passing = run(); const original = JSON.stringify(passing); @@ -137,10 +182,65 @@ test('extension projections retain dependency and runtime data while deriving mo mavenArtifact: row['maven-artifact'], })); const outputs = extensionProjections(source, releases); + const context = { + inventory: nativeComponentInventory(), + contrib: readToml(contribPath).extensions, + recipes: new Map( + source.extensions.map((row: any) => { + const file = `src/extensions/external/${row['sql-name']}/recipe.toml`; + return [row['sql-name'], existsSync(file) ? readToml(file) : {}]; + }), + ), + }; + for (const sdk of ['ts', 'react-native', 'kotlin'] as const) { + const selected = extensionProjections(source, releases, { context, sdkOnly: sdk }); + assert.equal(selected.size, 2); + for (const [file, text] of selected) { + assert.equal(text, outputs.get(file), file); + if (sdk === 'kotlin') assert.equal(text, readFileSync(file, 'utf8'), file); + } + } assert.deepEqual( JSON.parse(outputs.get('src/extensions/generated/sdk/extensions.json')!), metadata, ); + const rustPath = 'src/native/rust-bindings/src/generated/extensions.rs'; + assert.match(outputs.get(rustPath)!, /ExtensionId::Postgis => &\["liboliphaunt_postgis_deps"\]/u); + assert.match( + outputs.get(rustPath)!, + /if cfg!\(all\(target_os = "windows", target_arch = "x86_64"\)\)/u, + ); + assert.match(outputs.get(rustPath)!, /ExtensionId::Postgis => &\[\]/u); + const postgisRecipe = context.recipes.get('postgis')!; + const dependencyRecipes = new Map(context.recipes); + dependencyRecipes.set('postgis', { + ...postgisRecipe, + artifacts: { + ...postgisRecipe.artifacts, + native_dependency_modules: ['lib/postgresql/lib_fixture_dependency.so'], + }, + }); + const dependencyOutputs = extensionProjections(source, releases, { + context: { ...context, recipes: dependencyRecipes }, + }); + assert.match( + dependencyOutputs.get(rustPath)!, + /ExtensionId::Postgis => &\["lib_fixture_dependency"\]/u, + ); + for (const [file, text] of outputs) { + if (file !== rustPath) assert.equal(dependencyOutputs.get(file), text, file); + } + dependencyRecipes.set('postgis', { + ...postgisRecipe, + artifacts: { ...postgisRecipe.artifacts, native_dependency_modules: ['../undeclared.so'] }, + }); + assert.throws( + () => + extensionProjections(source, releases, { + context: { ...context, recipes: dependencyRecipes }, + }), + /requires a canonical native dependency module/u, + ); const extension = source.extensions.find((row: any) => row.id === 'pg_textsearch'); extension.control['default-version'] = '9.8.7'; const updated = extensionProjections(source, releases).get( diff --git a/src/extensions/tools/extension-projections.mts b/src/extensions/tools/extension-projections.mts index da44b182a..ce2899dc2 100644 --- a/src/extensions/tools/extension-projections.mts +++ b/src/extensions/tools/extension-projections.mts @@ -2,6 +2,7 @@ import assert from 'node:assert/strict'; import { createHash } from 'node:crypto'; import { existsSync, readFileSync } from 'node:fs'; import { nativeComponentInventory } from './native-component-contract.mts'; +import { nativeExtensionDependencyModulePaths } from '../contracts/extension-target-profiles.mts'; type Row = Record; export const modelPath = 'src/extensions/tools/check-extension-model.sh'; @@ -30,9 +31,23 @@ const moduleStem = (row: Row): string | null => (row['native-module-file'] || row['module-file'])?.replace(/\.(so|dylib|dll)$/, '') ?? null; const generated = `// This file is generated by ${modelPath}.\n// Do not edit by hand.\n\n`; -export function extensionProjections(catalog: Row, releases: Row[]): Map { - const inventory = nativeComponentInventory(); - const contrib = readToml(contribPath).extensions; +export type ExtensionProjectionContext = { + inventory: ReturnType; + contrib: Row[]; + recipes: ReadonlyMap; +}; + +export function extensionProjections( + catalog: Row, + releases: Row[], + options: { + context?: ExtensionProjectionContext; + sdkOnly?: 'ts' | 'react-native' | 'kotlin'; + metadataOnly?: boolean; + } = {}, +): Map { + const inventory = options.context?.inventory ?? nativeComponentInventory(); + const contrib = options.context?.contrib ?? readToml(contribPath).extensions; const extensions: Row[] = [...catalog.extensions].sort((a, b) => a['sql-name'] < b['sql-name'] ? -1 : 1, ); @@ -42,12 +57,14 @@ export function extensionProjections(catalog: Row, releases: Row[]): Map { - const file = `${externalRoot}/${row['sql-name']}/recipe.toml`; - return [row['sql-name'], existsSync(file) ? readToml(file) : {}]; - }), - ); + const recipes = + options.context?.recipes ?? + new Map( + extensions.map((row) => { + const file = `${externalRoot}/${row['sql-name']}/recipe.toml`; + return [row['sql-name'], existsSync(file) ? readToml(file) : {}]; + }), + ); const resolutions = (sql: string) => inventory.resolutions.filter((row) => row.extension === sql); const mobile = ( sql: string, @@ -69,7 +86,7 @@ export function extensionProjections(catalog: Row, releases: Row[]): Map row['sql-name'] === sql); const files = [...(recipe.artifacts?.data_files ?? contribRow?.['data-files'] ?? [])].sort(); const requirements = resolutions(sql); @@ -166,6 +183,10 @@ export function extensionProjections(catalog: Row, releases: Row[]): Map [ row['sql-name'], @@ -238,6 +259,17 @@ export function extensionProjections(catalog: Row, releases: Row[]): Map { + const text = outputs.get(file); + assert(text, `SDK projection renderer omitted ${file}`); + return [file, text]; + }), + ); + } outputs.set( 'src/native/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/OliphauntExtension.kt', `${generated}package dev.oliphaunt @@ -254,6 +286,21 @@ ${metadataRows.map((row) => ` ${row['sql-name'].replaceAll('-', '_').toUpperC } `, ); + outputs.set( + 'src/native/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt', + `${generated}package dev.oliphaunt\n\ninternal data class GeneratedExtensionRuntimeContract(\n val createsExtension: Boolean,\n val nativeModuleStem: String?,\n)\n\ninternal val generatedExtensionRuntimeContracts: Map = mapOf(\n${metadataRows.map((row) => ` ${literal(row['sql-name'])} to GeneratedExtensionRuntimeContract(createsExtension = ${row['creates-extension']}, nativeModuleStem = ${literal(row['native-module-stem'])}),`).join('\n')}\n)\n\ninternal val generatedExtensionSqlNames: Set = generatedExtensionRuntimeContracts.keys\n\ninternal fun generatedExtensionSqlNameExists(sqlName: String): Boolean = generatedExtensionSqlNames.contains(sqlName)\n\ninternal fun generatedExtensionRuntimeContract(sqlName: String): GeneratedExtensionRuntimeContract? = generatedExtensionRuntimeContracts[sqlName]\n`, + ); + if (options.sdkOnly === 'kotlin') { + const base = 'src/native/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt'; + return new Map( + ['GeneratedExtensions.kt', 'OliphauntExtension.kt'].map((name) => { + const path = `${base}/${name}`; + const text = outputs.get(path); + assert(text, `SDK projection renderer omitted ${path}`); + return [path, text]; + }), + ); + } outputs.set( 'src/native/sdks/swift/Sources/OliphauntCore/OliphauntExtension.swift', `${generated}import Foundation @@ -312,10 +359,6 @@ ${metadataRows.map((row) => ` public static let ${row.id.replace(/[-_]([a-z]) 'src/examples/native/react-native-expo/src/generated/extension-smoke.ts', `// This file is generated by ${modelPath}.\n// Do not edit by hand. It belongs only to installed mobile qualification.\n\nexport type GeneratedMobileExtensionProof = {\n readonly sqlName: string;\n readonly createsExtension: boolean;\n readonly selectedExtensionDependencies: readonly string[];\n};\n\nexport const GENERATED_MOBILE_EXTENSION_METADATA_SHA256 = ${literal(hash)} as const;\n\nexport const GENERATED_MOBILE_EXTENSION_PLAN = ${JSON.stringify(smokePlan, null, 2)} as const satisfies readonly GeneratedMobileExtensionProof[];\n\nexport const GENERATED_MOBILE_EXTENSION_SMOKE = ${JSON.stringify(sorted(smoke), null, 2).replace(/[\u007f-\uffff]/g, (character) => `\\u${character.charCodeAt(0).toString(16).padStart(4, '0')}`)} as const satisfies Readonly>;\n`, ); - outputs.set( - 'src/native/sdks/kotlin/oliphaunt/src/commonMain/kotlin/dev/oliphaunt/GeneratedExtensions.kt', - `${generated}package dev.oliphaunt\n\ninternal data class GeneratedExtensionRuntimeContract(\n val createsExtension: Boolean,\n val nativeModuleStem: String?,\n)\n\ninternal val generatedExtensionRuntimeContracts: Map = mapOf(\n${metadataRows.map((row) => ` ${literal(row['sql-name'])} to GeneratedExtensionRuntimeContract(createsExtension = ${row['creates-extension']}, nativeModuleStem = ${literal(row['native-module-stem'])}),`).join('\n')}\n)\n\ninternal val generatedExtensionSqlNames: Set = generatedExtensionRuntimeContracts.keys\n\ninternal fun generatedExtensionSqlNameExists(sqlName: String): Boolean = generatedExtensionSqlNames.contains(sqlName)\n\ninternal fun generatedExtensionRuntimeContract(sqlName: String): GeneratedExtensionRuntimeContract? = generatedExtensionRuntimeContracts[sqlName]\n`, - ); outputs.set( 'src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources/dev/oliphaunt/android/extensions.properties', [ @@ -342,6 +385,29 @@ ${metadataRows.map((row) => ` public static let ${row.id.replace(/[-_]([a-z]) metadataRows.map((row) => ({ ...row, 'rust-constant': extensions.find((extension) => extension.id === row.id)!['rust-constant'], + 'native-dependency-module-stems': unique( + nativeExtensionDependencyModulePaths( + recipes.get(row['sql-name'])?.artifacts?.native_dependency_modules ?? [], + undefined, + recipes.get(row['sql-name'])?.artifacts?.native_dependency_modules_by_target, + ).map((file: string) => { + const match = /^lib\/postgresql\/([A-Za-z0-9_-]+)\.so$/u.exec(file); + assert(match, `${row['sql-name']} requires a canonical native dependency module`); + return match[1]; + }), + ), + 'native-dependency-module-overrides': Object.fromEntries( + Object.keys( + recipes.get(row['sql-name'])?.artifacts?.native_dependency_modules_by_target ?? {}, + ).map((target) => [ + target, + nativeExtensionDependencyModulePaths( + recipes.get(row['sql-name'])?.artifacts?.native_dependency_modules ?? [], + target, + recipes.get(row['sql-name'])?.artifacts?.native_dependency_modules_by_target, + ).map((file: string) => file.slice('lib/postgresql/'.length, -3)), + ]), + ), })), ), ); @@ -478,6 +544,33 @@ function rustModule(rows: Row[]): string { `Rust Extension supports one preload library: ${row.id}`, ); } + const nativeTargetCfg: Record = { + 'linux-x64-gnu': 'all(target_os = "linux", target_arch = "x86_64")', + 'linux-arm64-gnu': 'all(target_os = "linux", target_arch = "aarch64")', + 'macos-arm64': 'all(target_os = "macos", target_arch = "aarch64")', + 'windows-x64-msvc': 'all(target_os = "windows", target_arch = "x86_64")', + }; + const currentDependencyBranches = Object.entries(nativeTargetCfg).flatMap(([target, cfg]) => { + const overridden = rows.filter((row) => + Object.hasOwn(row['native-dependency-module-overrides'], target), + ); + if (!overridden.length) return []; + return [ + ' if cfg!(' + cfg + ') {', + ' return match extension.id {', + ...overridden.map( + (row) => + ' ' + + id(row) + + ' => ' + + array(row['native-dependency-module-overrides'][target].map(literal)) + + ',', + ), + ' _ => native_dependency_module_stems(extension),', + ' };', + ' }', + ]; + }); return [ `// @generated by ${modelPath} --write`, '// Do not edit by hand.', @@ -509,6 +602,18 @@ function rustModule(rows: Row[]): string { match('sql_name', "&'static str", (row) => literal(row['sql-name'])), match('artifact_product', "&'static str", (row) => literal(row['artifact-product'])), match('native_module_stem', "Option<&'static str>", (row) => option(row['native-module-stem'])), + match('native_dependency_module_stems', "&'static [&'static str]", (row) => + array(row['native-dependency-module-stems'].map(literal)), + ), + [ + '/// Current host dependency modules; frozen inputs retain their own inventory.', + '#[cfg(feature = "internal-native-packaging")]', + "pub(super) const fn native_dependency_module_stems_for_host(extension: Extension) -> &'static [&'static str] {", + ...currentDependencyBranches, + ' native_dependency_module_stems(extension)', + '}', + '', + ].join('\n'), match('creates_extension', 'bool', (row) => String(row['creates-extension'])), match('dependencies', "&'static [Extension]", (row) => array( diff --git a/src/extensions/tools/extension-upstream-licenses.mts b/src/extensions/tools/extension-upstream-licenses.mts index 29e2f6039..3af582070 100644 --- a/src/extensions/tools/extension-upstream-licenses.mts +++ b/src/extensions/tools/extension-upstream-licenses.mts @@ -4,22 +4,23 @@ import { existsSync, lstatSync, mkdirSync, - readFileSync, readdirSync, + readFileSync, realpathSync, writeFileSync, } from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; - -import { requireSafeDirectoryChain as requireReleaseDirectoryChain } from '../../../tools/packaging/release-directory-safety.mts'; +import { isDeepStrictEqual } from 'node:util'; import { readPortableArchiveEntries } from '../../../tools/packaging/portable-archive.mts'; +import { requireSafeDirectoryChain as requireReleaseDirectoryChain } from '../../../tools/packaging/release-directory-safety.mts'; import { hasCanonicalReleaseStagingMode, - releaseNoticeRows, releaseMavenLicenses, + releaseNoticeRows, releaseProfilePackageLicense, } from '../../../tools/packaging/release-notices.mts'; +import { nativeExtensionModuleHostTarget } from '../contracts/extension-target-profiles.mts'; const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../..'); const EXTERNAL_ROOT = path.join(ROOT, 'src/extensions/external'); @@ -49,6 +50,12 @@ const CONTRIB_LICENSE = Object.freeze({ upstreamSpdx: 'PostgreSQL', packageSpdx: 'MIT AND PostgreSQL', }); +export const PGCRYPTO_NATIVE_CONSTRUCTION_TARGETS = Object.freeze([ + 'linux-x64-gnu', + 'linux-arm64-gnu', + 'macos-arm64', + 'windows-x64-msvc', +]); const OPENSSL_EMBEDDED_NATIVE_TARGETS = new Set([ 'android-arm64-v8a', 'android-x86_64', @@ -442,7 +449,6 @@ export function externalReleaseExtensionSqlNames() { fail(`${path.relative(ROOT, releaseFile)} must declare a safe extension_sql_name`); } sqlNames.push(release.extension_sql_name); - continue; } } const canonical = [...new Set(sqlNames)].sort(compareText); @@ -523,6 +529,24 @@ export function extensionMavenLicenses(product, members, { version } = {}) { return Object.freeze(entries); } +/** Supplemental Maven entries follow the same validated physical receipts. */ +export function nativeExtensionConstructionMavenLicenses(sqlName, target, files = []) { + const validated = validateNativeExtensionConstructionLicenseInventory(sqlName, target, files); + if (!validated.some((file) => file.path.startsWith('share/licenses/llvm-compiler-rt/'))) + return []; + const source = JSON.parse( + readFileSync(path.join(ROOT, 'build_defs/extensions/compiler_rt/source.json'), 'utf8'), + ); + const license = source.files.find((file) => file.destination === 'LICENSE.TXT'); + return [ + { + name: `${source.license} (${source.project})`, + url: `https://github.com/llvm/llvm-project/blob/${source.commit}/${license.path}`, + distribution: 'repo', + }, + ]; +} + function hashFile(file) { return createHash('sha256').update(readFileSync(file)).digest('hex'); } @@ -706,10 +730,84 @@ export function extensionUpstreamLicenseFileInventory(sqlNames) { ); } +/** Construction receipts bind bundled implementations to their immutable source pins. */ +export function nativeExtensionConstructionLicenseInventory(sqlName, target) { + target = nativeExtensionModuleHostTarget(target); + if (sqlName === 'pgcrypto' && PGCRYPTO_NATIVE_CONSTRUCTION_TARGETS.includes(target)) { + const license = releaseNoticeRows({ profile: 'contrib-native-openssl' }).find( + (row) => row.id === 'openssl', + ); + return Object.freeze( + [ + { + path: 'share/licenses/openssl-native/LICENSE.txt', + sha256: createHash('sha256').update(readFileSync(license.source)).digest('hex'), + mode: '0644', + }, + { + path: 'share/licenses/openssl-native/SOURCE.toml', + sha256: createHash('sha256').update(readFileSync(license.sourceManifest)).digest('hex'), + mode: '0644', + }, + ].map(Object.freeze), + ); + } + if (!['vector', 'pg_textsearch'].includes(sqlName) || target !== 'linux-x64-gnu') { + return Object.freeze([]); + } + const source = JSON.parse( + readFileSync(path.join(ROOT, 'build_defs/extensions/compiler_rt/source.json'), 'utf8'), + ); + const sortKeys = (value) => + Array.isArray(value) + ? value.map(sortKeys) + : value && typeof value === 'object' + ? Object.fromEntries( + Object.keys(value) + .sort(compareText) + .map((key) => [key, sortKeys(value[key])]), + ) + : value; + const license = source.files.find((file) => file.destination === 'LICENSE.TXT'); + if ( + source.schema !== 'oliphaunt-compiler-runtime-source-v1' || + source.project !== 'llvm-compiler-rt' || + source.license !== 'Apache-2.0 WITH LLVM-exception' || + !GIT_COMMIT.test(source.commit) || + !license || + !SHA256.test(license.sha256) + ) { + fail('invalid immutable compiler-runtime legal source'); + } + return Object.freeze( + [ + { path: 'share/licenses/llvm-compiler-rt/LICENSE.TXT', sha256: license.sha256, mode: '0644' }, + { + path: 'share/licenses/llvm-compiler-rt/SOURCE.json', + sha256: createHash('sha256') + .update(JSON.stringify(sortKeys(source))) + .digest('hex'), + mode: '0644', + }, + ].map(Object.freeze), + ); +} + +export function validateNativeExtensionConstructionLicenseInventory(sqlName, target, files = []) { + if (!Array.isArray(files)) fail('native construction legal inventory must be an array'); + if (files.length === 0) return Object.freeze([]); + const expected = nativeExtensionConstructionLicenseInventory(sqlName, target); + if (expected.length === 0) + fail('native construction legal closure has no declared source for this member/target'); + if (!isDeepStrictEqual(files, expected)) + fail('native construction legal inventory differs from the immutable construction source'); + return expected; +} + export function extensionCarrierLegalContract( product, sqlNames, - { family, target, carriesPayload = true } = {}, + { family, target, carriesPayload = true, memberContracts = [] } = {}, ) { if ( typeof product !== 'string' || @@ -738,7 +836,17 @@ export function extensionCarrierLegalContract( if (product === CONTRIB_LICENSE.product) { const embedsOpenSsl = sqlNames.includes('pgcrypto') && - (family === 'wasix' || OPENSSL_EMBEDDED_NATIVE_TARGETS.has(target)); + (family === 'wasix' || + OPENSSL_EMBEDDED_NATIVE_TARGETS.has(target) || + memberContracts.some( + (member) => + member.sqlName === 'pgcrypto' && + validateNativeExtensionConstructionLicenseInventory( + member.sqlName, + target, + member.nativeConstructionLicenseFiles ?? [], + ).length > 0, + )); const profile = `${family === 'native' ? 'contrib-native' : 'contrib-wasix'}${embedsOpenSsl ? '-openssl' : ''}`; return Object.freeze({ profile, @@ -757,15 +865,64 @@ export function extensionCarrierLegalContract( }); } +export function nativeExtensionCarrierLegal( + product, + members, + { target = null, carriesPayload, memberContracts = [] }, +) { + if ( + typeof product !== 'string' || + !Array.isArray(members) || + members.length === 0 || + members.some((member) => typeof member !== 'string' || !member) || + new Set(members).size !== members.length || + typeof carriesPayload !== 'boolean' + ) { + fail( + 'native extension carrier legal lookup requires a product, unique members, and carriesPayload', + ); + } + try { + const legal = extensionCarrierLegalContract(product, members, { + family: 'native', + target, + carriesPayload, + memberContracts, + }); + const construction = memberContracts.flatMap((member) => + validateNativeExtensionConstructionLicenseInventory( + member.sqlName, + target, + member.nativeConstructionLicenseFiles ?? [], + ), + ); + const incorporatesCompilerRuntime = construction.some((file) => + file.path.startsWith('share/licenses/llvm-compiler-rt/'), + ); + return !incorporatesCompilerRuntime + ? legal + : Object.freeze({ + ...legal, + packageSpdx: `${legal.packageSpdx} AND Apache-2.0 WITH LLVM-exception`, + }); + } catch (cause) { + throw new Error( + `extension-upstream-licenses: cannot derive the canonical native extension carrier legal contract: ${cause.message}`, + { cause }, + ); + } +} + export function extensionCarrierLegalFileInventory( product, sqlNames, - { family, target, carriesPayload = true } = {}, + { family, target, carriesPayload = true, memberContracts = [] } = {}, ) { const legal = extensionCarrierLegalContract(product, sqlNames, { family, target, carriesPayload, + memberContracts, }); const files = new Map(); const add = (file, bytes, expectedSha256 = undefined) => { @@ -913,10 +1070,25 @@ function archiveEntryKind(entry) { return 'special'; } -export function assertExtensionUpstreamLicensesInEntries(sqlNames, entries, { prefix = '' } = {}) { +export function assertExtensionUpstreamLicensesInEntries( + sqlNames, + entries, + { prefix = '', constructionLicenseFiles = [], target = null } = {}, +) { if (!(entries instanceof Map)) fail('upstream license archive entries must be a Map'); const normalizedPrefix = checkedArchivePrefix(prefix); const expected = expectedLicenseFiles(sqlNames); + if (constructionLicenseFiles.length > 0) { + if (sqlNames.length !== 1) + fail('construction license closure requires its exact extension owner'); + for (const row of validateNativeExtensionConstructionLicenseInventory( + sqlNames[0], + target, + constructionLicenseFiles, + )) { + expected.set(row.path, { destination: row.path, sha256: row.sha256 }); + } + } const expectedNames = [...expected.keys()] .map((member) => prefixed(normalizedPrefix, member)) .sort(compareText); diff --git a/src/extensions/tools/extension-upstream-licenses.test.mts b/src/extensions/tools/extension-upstream-licenses.test.mts index e412a37a2..0a73a5145 100644 --- a/src/extensions/tools/extension-upstream-licenses.test.mts +++ b/src/extensions/tools/extension-upstream-licenses.test.mts @@ -19,25 +19,128 @@ import { canonicalGzipSync, readPortableArchiveEntries, } from '../../../tools/packaging/portable-archive.mts'; -import { hasCanonicalReleaseStagingMode } from '../../../tools/packaging/release-notices.mts'; import { - assertExtensionUpstreamLicensesInEntries, + hasCanonicalReleaseStagingMode, + releaseNoticeRows, +} from '../../../tools/packaging/release-notices.mts'; +import { assertExtensionUpstreamLicensesInArchive, assertExtensionUpstreamLicensesInDirectory, + assertExtensionUpstreamLicensesInEntries, assertSupportedExtensionUpstreamSpdxId, - externalReleaseExtensionSqlNames, extensionCarrierLegalContract, extensionCarrierLegalFileInventory, extensionMavenLicenses, extensionRegistryLicense, - stageExtensionUpstreamLicenses, extensionUpstreamLicenseFileInventory, extensionUpstreamLicenseRows, + externalReleaseExtensionSqlNames, + nativeExtensionCarrierLegal, + nativeExtensionConstructionLicenseInventory, + nativeExtensionConstructionMavenLicenses, + PGCRYPTO_NATIVE_CONSTRUCTION_TARGETS, + stageExtensionUpstreamLicenses, validateExtensionUpstreamLicenseContract, + validateNativeExtensionConstructionLicenseInventory, } from './extension-upstream-licenses.mts'; const ROOT = path.resolve(import.meta.dirname, '../../..'); +for (const [sqlName, product] of [ + ['vector', 'oliphaunt-extension-vector'], + ['pg_textsearch', 'oliphaunt-extension-pg-textsearch'], +]) { + test(`${sqlName} native carrier SPDX follows actual compiler-runtime receipts and rejects altered receipts`, () => { + const target = 'android-arm64-v8a'; + const files = nativeExtensionConstructionLicenseInventory(sqlName, target); + const legal = nativeExtensionCarrierLegal(product, [sqlName], { + target, + carriesPayload: true, + memberContracts: [{ sqlName, nativeConstructionLicenseFiles: files }], + }); + assert.equal( + legal.packageSpdx, + `${extensionCarrierLegalContract(product, [sqlName], { family: 'native', target }).packageSpdx} AND Apache-2.0 WITH LLVM-exception`, + ); + assert.equal(Object.isFrozen(legal), true); + assert.equal( + nativeExtensionCarrierLegal(product, [sqlName], { carriesPayload: false }).profile, + 'code-facade', + ); + for (const changedIndex of [0, 1]) { + assert.throws( + () => + nativeExtensionCarrierLegal(product, [sqlName], { + target, + carriesPayload: true, + memberContracts: [ + { + sqlName, + nativeConstructionLicenseFiles: files.map((file, index) => + index === changedIndex ? { ...file, sha256: '0'.repeat(64) } : file, + ), + }, + ], + }), + /differs from the immutable construction source/u, + ); + } + }); + + test(`${sqlName} Maven compiler-runtime entries follow validated canonical receipts`, () => { + const receipts = nativeExtensionConstructionLicenseInventory(sqlName, 'android-arm64-v8a'); + const source = JSON.parse( + readFileSync(path.join(ROOT, 'build_defs/extensions/compiler_rt/source.json'), 'utf8'), + ); + assert.deepEqual( + nativeExtensionConstructionMavenLicenses(sqlName, 'android-arm64-v8a', receipts), + [ + { + name: `${source.license} (${source.project})`, + url: `https://github.com/llvm/llvm-project/blob/${source.commit}/${source.files.find((file) => file.destination === 'LICENSE.TXT').path}`, + distribution: 'repo', + }, + ], + ); + assert.deepEqual( + nativeExtensionConstructionMavenLicenses(sqlName, 'android-arm64-v8a', []), + [], + ); + for (const changedIndex of [0, 1]) { + assert.throws(() => + nativeExtensionConstructionMavenLicenses( + sqlName, + 'android-arm64-v8a', + receipts.map((file, index) => + index === changedIndex ? { ...file, sha256: '0'.repeat(64) } : file, + ), + ), + ); + } + }); +} + +test('members without construction sources have frozen empty inventories and reject supplied receipts', () => { + const target = 'linux-x64-gnu'; + const receipts = nativeExtensionConstructionLicenseInventory('vector', target); + for (const sqlName of ['pg_hashids', 'hstore', 'unknown_extension']) { + const files = nativeExtensionConstructionLicenseInventory(sqlName, target); + assert.deepEqual(files, []); + assert.equal(Object.isFrozen(files), true); + const validated = validateNativeExtensionConstructionLicenseInventory(sqlName, target); + assert.deepEqual(validated, []); + assert.equal(Object.isFrozen(validated), true); + assert.throws( + () => validateNativeExtensionConstructionLicenseInventory(sqlName, target, receipts), + /no declared source for this member\/target/u, + ); + assert.throws( + () => nativeExtensionConstructionMavenLicenses(sqlName, target, receipts), + /no declared source for this member\/target/u, + ); + } +}); + test('every active external release has an exact upstream license contract', () => { const rows = validateExtensionUpstreamLicenseContract(); assert.deepEqual( @@ -74,6 +177,216 @@ test('npm extension legal inventory binds canonical paths, bytes, and modes', () ); }); +test('pgcrypto native construction receipts bind desktop and mobile-host OpenSSL source bytes', () => { + assert.deepEqual(PGCRYPTO_NATIVE_CONSTRUCTION_TARGETS, [ + 'linux-x64-gnu', + 'linux-arm64-gnu', + 'macos-arm64', + 'windows-x64-msvc', + ]); + assert.equal(Object.isFrozen(PGCRYPTO_NATIVE_CONSTRUCTION_TARGETS), true); + const openssl = releaseNoticeRows({ profile: 'contrib-native-openssl' }).find( + ({ id }) => id === 'openssl', + ); + assert.ok(openssl, 'the canonical native OpenSSL profile must declare its source'); + const expected = [ + ['share/licenses/openssl-native/LICENSE.txt', openssl.source], + ['share/licenses/openssl-native/SOURCE.toml', openssl.sourceManifest], + ].map(([file, source]) => ({ + path: file, + sha256: createHash('sha256').update(readFileSync(source)).digest('hex'), + mode: '0644', + })); + for (const target of [ + ...PGCRYPTO_NATIVE_CONSTRUCTION_TARGETS, + 'android-arm64-v8a', + 'android-x86_64', + 'ios-xcframework', + ]) { + const files = nativeExtensionConstructionLicenseInventory('pgcrypto', target); + assert.deepEqual(files, expected, target); + assert.equal(Object.isFrozen(files), true); + assert.equal(files.every(Object.isFrozen), true); + assert.deepEqual( + validateNativeExtensionConstructionLicenseInventory('pgcrypto', target, files), + expected, + ); + assert.equal( + extensionCarrierLegalContract('oliphaunt-extension-contrib-pg18', ['pgcrypto'], { + family: 'native', + target, + memberContracts: [{ sqlName: 'pgcrypto', nativeConstructionLicenseFiles: files }], + }).profile, + 'contrib-native-openssl', + ); + } +}); + +test('Linux contrib legal file inventories follow validated pgcrypto construction receipts', () => { + const product = 'oliphaunt-extension-contrib-pg18'; + const openssl = releaseNoticeRows({ profile: 'contrib-native-openssl' }).find( + ({ id }) => id === 'openssl', + ); + assert.ok(openssl); + const bytes = readFileSync(openssl.source); + for (const target of ['linux-x64-gnu', 'linux-arm64-gnu']) { + const options = { family: 'native', target }; + const absent = extensionCarrierLegalFileInventory(product, ['pgcrypto'], options); + assert.equal( + extensionCarrierLegalContract(product, ['pgcrypto'], options).profile, + 'contrib-native', + ); + assert.equal( + absent.some((file) => file.path === openssl.member), + false, + ); + assert.deepEqual( + extensionCarrierLegalFileInventory(product, ['pgcrypto'], { + ...options, + memberContracts: [{ sqlName: 'pgcrypto', nativeConstructionLicenseFiles: [] }], + }), + absent, + ); + const receipts = nativeExtensionConstructionLicenseInventory('pgcrypto', target); + const memberContracts = [{ sqlName: 'pgcrypto', nativeConstructionLicenseFiles: receipts }]; + const present = extensionCarrierLegalFileInventory(product, ['pgcrypto'], { + ...options, + memberContracts, + }); + assert.equal( + extensionCarrierLegalContract(product, ['pgcrypto'], { + ...options, + memberContracts, + }).profile, + 'contrib-native-openssl', + ); + assert.deepEqual( + present.find((file) => file.path === openssl.member), + { + path: openssl.member, + sha256: createHash('sha256').update(bytes).digest('hex'), + bytes: bytes.length, + mode: '0644', + }, + ); + assert.throws( + () => + extensionCarrierLegalFileInventory(product, ['pgcrypto'], { + ...options, + memberContracts: [ + { + sqlName: 'pgcrypto', + nativeConstructionLicenseFiles: receipts.map((file, index) => + index === 0 ? { ...file, sha256: '0'.repeat(64) } : file, + ), + }, + ], + }), + /differs from the immutable construction source/u, + ); + } +}); + +test('construction receipts survive canonical JSON key order and retain exact inventory checks', () => { + for (const [sqlName, target] of [ + ['pgcrypto', 'linux-x64-gnu'], + ['pgcrypto', 'linux-arm64-gnu'], + ['vector', 'linux-x64-gnu'], + ['pg_textsearch', 'android-x86_64'], + ]) { + const expected = nativeExtensionConstructionLicenseInventory(sqlName, target); + const serialized = JSON.parse( + JSON.stringify(expected.map(({ mode, path, sha256 }) => ({ mode, path, sha256 }))), + ); + assert.deepEqual( + validateNativeExtensionConstructionLicenseInventory(sqlName, target, serialized), + expected, + ); + for (const invalid of [ + [...serialized].reverse(), + [serialized[0], serialized[0]], + serialized.slice(0, 1), + [...serialized, serialized[0]], + serialized.map((file) => ({ ...file, mode: '0666' })), + serialized.map((file) => ({ ...file, extra: true })), + serialized.map(({ mode, path }) => ({ mode, path })), + ]) { + assert.throws( + () => validateNativeExtensionConstructionLicenseInventory(sqlName, target, invalid), + /differs from the immutable construction source/u, + `${sqlName}/${target}`, + ); + } + } +}); + +test('pgcrypto construction receipts reject unsupported targets and changed source digests', () => { + const files = nativeExtensionConstructionLicenseInventory('pgcrypto', 'linux-x64-gnu'); + for (const target of ['macos-x64', 'linux-x64-musl', 'wasix']) { + const inventory = nativeExtensionConstructionLicenseInventory('pgcrypto', target); + assert.deepEqual(inventory, []); + assert.equal(Object.isFrozen(inventory), true); + assert.throws( + () => validateNativeExtensionConstructionLicenseInventory('pgcrypto', target, files), + /no declared source for this member\/target/u, + target, + ); + assert.deepEqual(validateNativeExtensionConstructionLicenseInventory('pgcrypto', target), []); + } + for (const target of [ + ...PGCRYPTO_NATIVE_CONSTRUCTION_TARGETS, + 'android-arm64-v8a', + 'android-x86_64', + 'ios-xcframework', + ]) { + for (const changedIndex of [0, 1]) { + const changed = files.map((file, index) => + index === changedIndex + ? { ...file, sha256: `${file.sha256[0] === '0' ? '1' : '0'}${file.sha256.slice(1)}` } + : file, + ); + assert.throws( + () => validateNativeExtensionConstructionLicenseInventory('pgcrypto', target, changed), + /differs from the immutable construction source/u, + `${target}: ${files[changedIndex].path}`, + ); + } + assert.deepEqual(validateNativeExtensionConstructionLicenseInventory('pgcrypto', target), []); + } + for (const target of ['android-arm64-v8a', 'android-x86_64', 'ios-xcframework', 'macos-x64']) { + assert.equal( + extensionCarrierLegalContract('oliphaunt-extension-contrib-pg18', ['pgcrypto'], { + family: 'native', + target, + }).profile, + 'contrib-native-openssl', + ); + } +}); + +for (const sqlName of ['vector', 'pg_textsearch']) { + test(`Android ${sqlName} host receipts retain the actual Linux compiler runtime without admitting Apple receipts`, () => { + const files = nativeExtensionConstructionLicenseInventory(sqlName, 'linux-x64-gnu'); + for (const target of ['android-arm64-v8a', 'android-x86_64']) { + assert.deepEqual(nativeExtensionConstructionLicenseInventory(sqlName, target), files); + assert.deepEqual( + validateNativeExtensionConstructionLicenseInventory(sqlName, target, files), + files, + ); + } + for (const target of ['ios-xcframework', 'macos-arm64', 'linux-arm64-gnu']) { + const inventory = nativeExtensionConstructionLicenseInventory(sqlName, target); + assert.deepEqual(inventory, []); + assert.equal(Object.isFrozen(inventory), true); + assert.deepEqual(validateNativeExtensionConstructionLicenseInventory(sqlName, target), []); + assert.throws( + () => validateNativeExtensionConstructionLicenseInventory(sqlName, target, files), + /no declared source/u, + ); + } + }); +} + test('carrier legal inventory binds release notices and PostGIS upstream bytes', () => { const legal = extensionCarrierLegalContract('oliphaunt-extension-postgis', ['postgis'], { family: 'native', diff --git a/src/native/broker/BUILD.bazel b/src/native/broker/BUILD.bazel new file mode 100644 index 000000000..eb0d23e54 --- /dev/null +++ b/src/native/broker/BUILD.bazel @@ -0,0 +1,46 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files", "source_quality_files") +load("//build_defs/languages:rust.bzl", "cargo_binary", "cargo_integration_test", "cargo_library", "cargo_library_test", "cargo_package_env") +load("@rules_rust//rust:defs.bzl", "rust_clippy_test") +load("//build_defs/languages:source.bzl", "cargo_source_package") +load("//build_defs/languages/carriers:defs.bzl", "native_helper_carriers") +load("//build_defs/native/carriers:release-family.bzl", "native_release_checksum_family") +load("//build_defs/native:rust-runtime-test.bzl", "native_rust_runtime_test") +load("@oliphaunt_metadata//:metadata.bzl", "NATIVE_CURRENT_ARTIFACTS") + +package(default_visibility = ["//visibility:public"]) + +native_release_checksum_family(product = "oliphaunt-broker") +exports_files(["Cargo.toml", "tools/broker-dependency-license-contract.mts"]) +filegroup(name = "carrier_legal_sources", srcs = ["dependency-licenses.json"] + glob(["dependency-license-blobs/*.base64"])) +filegroup(name = "carrier_template_sources", srcs = glob(["packages/*/package.json", "packages/*/README.md", "crates/*/Cargo.toml", "crates/*/build.rs", "crates/*/src/lib.rs", "crates/*/README.md"])) + +PATH_DEPS = {"liboliphaunt-native-bindings": "//src/native/rust-bindings:lib"} + +cargo_package_env() +cargo_library(path_dependencies = PATH_DEPS) +cargo_binary(name = "broker", source = "src/main.rs", path_dependencies = PATH_DEPS, library = ":lib") +cargo_library_test() +cargo_library_test(name = "binary_test", crate = ":broker") +cargo_integration_test( + name = "postgres_client_test", + source = "tests/postgres_client.rs", + path_dependencies = PATH_DEPS, + rustc_env = {"CARGO_BIN_EXE_oliphaunt-broker": "$(rootpath :broker)" if NATIVE_CURRENT_ARTIFACTS == None else ""}, + data = [":broker"] if NATIVE_CURRENT_ARTIFACTS == None else [], + tags = ["manual"], +) +rust_clippy_test(name = "clippy_test", targets = [":lib", ":unit_test", ":broker", ":binary_test", ":postgres_client_test"], transitive = False, size = "small") +native_rust_runtime_test( + name = "postgres_client_runtime_test", + binary = ":postgres_client_test", + test_args = ["--ignored", "--test-threads=1", "--nocapture"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + size = "large", + timeout = "long", +) +cargo_source_package(product = "oliphaunt-broker", qualification = [":unit_test", ":binary_test", ":postgres_client_runtime_test", "//build_defs/languages/installed:consumer_test"]) +native_helper_carriers(product = "oliphaunt-broker", binary = ":broker", qualification = ["//build_defs/languages/carriers:installed_sql_test"], path_dependencies = PATH_DEPS) + +source_quality_files() + +rust_quality_files() diff --git a/src/native/broker/Cargo.toml b/src/native/broker/Cargo.toml index d8ea33285..6b571b1ad 100644 --- a/src/native/broker/Cargo.toml +++ b/src/native/broker/Cargo.toml @@ -16,7 +16,7 @@ path = "src/main.rs" [dependencies] liboliphaunt-native-bindings = { path = "../rust-bindings", version = "0.2.0" } -oliphaunt-query = { path = "../../query/rust", version = "0.1.1" } +oliphaunt-query = { version = "0.1.1" } getrandom = "0.3" [target.'cfg(unix)'.dev-dependencies] diff --git a/src/native/broker/README.md b/src/native/broker/README.md index e8ae66544..24e0b7fee 100644 --- a/src/native/broker/README.md +++ b/src/native/broker/README.md @@ -75,7 +75,7 @@ requests and responses, COPY, cancellation, callback recovery, connection reset, backup/shutdown, abrupt disconnect, and parent death. They fail when required runtime inputs are missing; source-only tests report them as ignored. -Native Cargo entry points remain available: `cargo build -p oliphaunt-broker --locked`, `cargo test -p oliphaunt-broker --locked`, `cargo clippy -p oliphaunt-broker --all-targets --locked -- -D warnings`, and `cargo fmt -p oliphaunt-broker --check`. Moon supplies the additional source-test feature matrix and artifact staging where defined. `package` assembles bytes; it does not run the project test suite. +Native Cargo entry points from this directory remain available: `cargo build --locked`, `cargo test --locked`, `cargo clippy --all-targets --locked -- -D warnings`, and `cargo fmt --check`. Moon supplies the additional source-test feature matrix and artifact staging where defined. `package` assembles bytes; it does not run the project test suite. The native SDK’s `moon run oliphaunt-rust:test-consumer` installs the real packed query, bindings and broker crates together with the SDK. This tests their public dependency closure without duplicate per-crate consumer harnesses. diff --git a/src/native/broker/crates/linux-arm64-gnu/build.rs b/src/native/broker/crates/linux-arm64-gnu/build.rs index aeff05c78..1ed6e1a4a 100644 --- a/src/native/broker/crates/linux-arm64-gnu/build.rs +++ b/src/native/broker/crates/linux-arm64-gnu/build.rs @@ -30,8 +30,8 @@ fn emit_manifest() { } return; } - let sha256 = fs::read_to_string(&checksum) - .expect("read packaged oliphaunt-broker payload checksum"); + let sha256 = + fs::read_to_string(&checksum).expect("read packaged oliphaunt-broker payload checksum"); let sha256 = sha256.trim(); if sha256.len() != 64 || !sha256.bytes().all(|byte| byte.is_ascii_hexdigit()) { panic!("invalid packaged oliphaunt-broker payload checksum"); diff --git a/src/native/broker/crates/linux-x64-gnu/build.rs b/src/native/broker/crates/linux-x64-gnu/build.rs index 6f26fae6b..bf414a63e 100644 --- a/src/native/broker/crates/linux-x64-gnu/build.rs +++ b/src/native/broker/crates/linux-x64-gnu/build.rs @@ -30,8 +30,8 @@ fn emit_manifest() { } return; } - let sha256 = fs::read_to_string(&checksum) - .expect("read packaged oliphaunt-broker payload checksum"); + let sha256 = + fs::read_to_string(&checksum).expect("read packaged oliphaunt-broker payload checksum"); let sha256 = sha256.trim(); if sha256.len() != 64 || !sha256.bytes().all(|byte| byte.is_ascii_hexdigit()) { panic!("invalid packaged oliphaunt-broker payload checksum"); diff --git a/src/native/broker/crates/macos-arm64/build.rs b/src/native/broker/crates/macos-arm64/build.rs index 19d33f487..6f45a1f26 100644 --- a/src/native/broker/crates/macos-arm64/build.rs +++ b/src/native/broker/crates/macos-arm64/build.rs @@ -30,8 +30,8 @@ fn emit_manifest() { } return; } - let sha256 = fs::read_to_string(&checksum) - .expect("read packaged oliphaunt-broker payload checksum"); + let sha256 = + fs::read_to_string(&checksum).expect("read packaged oliphaunt-broker payload checksum"); let sha256 = sha256.trim(); if sha256.len() != 64 || !sha256.bytes().all(|byte| byte.is_ascii_hexdigit()) { panic!("invalid packaged oliphaunt-broker payload checksum"); diff --git a/src/native/broker/dependency-license-blobs/20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830.base64 b/src/native/broker/dependency-license-blobs/20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830.base64 new file mode 100644 index 000000000..8102d7ab2 --- /dev/null +++ b/src/native/broker/dependency-license-blobs/20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830.base64 @@ -0,0 +1,15 @@ +IyBUaGlyZC1QYXJ0eSBOb3RpY2VzCgpPbGlwaGF1bnQgc291cmNlIGNvZGUgaW4gdGhpcyByZXBv +c2l0b3J5IGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZSBpbgpgTElDRU5TRWAuCgpU +aGlzIGZpbGUgaXMgdGhlIHJlcG9zaXRvcnktbGV2ZWwgbm90aWNlIGluZGV4LiBQcm9kdWN0LXNw +ZWNpZmljIHJ1bnRpbWUgYW5kCnBhY2thZ2luZyBub3RpY2VzIGxpdmUgbmV4dCB0byB0aGUgcHJv +ZHVjdCB0aGF0IHNoaXBzIHRoZSByZWxldmFudCBhcnRpZmFjdHM6CgotIGBzcmMvbmF0aXZlL3J1 +bnRpbWUvVEhJUkRfUEFSVFlfTk9USUNFUy5tZGAKLSBgc3JjL3dhc2l4L3Nka3MvcnVzdC9USElS +RF9QQVJUWV9OT1RJQ0VTLm1kYAoKU2hhcmVkIFBvc3RncmVTUUwgc291cmNlIHBpbnMsIHRoaXJk +LXBhcnR5IHNvdXJjZSBwaW5zLCBhbmQgZXh0ZW5zaW9uIG1ldGFkYXRhCmFyZSBtYWludGFpbmVk +IGluIGBzcmMvdGhpcmQtcGFydHkvcG9zdGdyZXMvYCwgYHNyYy90aGlyZC1wYXJ0eS9gLCBhbmQK +YHNyYy9leHRlbnNpb25zL2AuIEdlbmVyYXRlZCByZWxlYXNlIGFydGlmYWN0cyBtdXN0IGluY2x1 +ZGUgdGhlIG5vdGljZXMgYW5kCmV4YWN0IHBpbm5lZCBsaWNlbnNlIGJ5dGVzIGZvciBldmVyeSBw +cm9kdWN0IGFuZCB0aGlyZC1wYXJ0eSBjb21wb25lbnQgdGhleQpzaGlwLgoKQ2Fub25pY2FsIHJ1 +bnRpbWUgbGljZW5zZSBzbmFwc2hvdHMgbGl2ZSBpbgpgc3JjL3RoaXJkLXBhcnR5L2A7IHRoZWly +IHNvdXJjZSBwaW5zIGFuZCBkaWdlc3RzIGFyZQplbmZvcmNlZCBieSBgdG9vbHMvcGFja2FnaW5n +L3JlbGVhc2Utbm90aWNlcy5tdHNgLgo= diff --git a/src/native/broker/dependency-license-blobs/6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10.base64 b/src/native/broker/dependency-license-blobs/6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10.base64 new file mode 100644 index 000000000..ed642faf0 --- /dev/null +++ b/src/native/broker/dependency-license-blobs/6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10.base64 @@ -0,0 +1,20 @@ +TUlUIExpY2Vuc2UKCkNvcHlyaWdodCAoYykgMjAyNCBvbGlwaGF1bnQtd2FzaXggQ29udHJpYnV0 +b3JzCgpQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55 +IHBlcnNvbiBvYnRhaW5pbmcgYSBjb3B5Cm9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQg +ZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlICJTb2Z0d2FyZSIpLCB0byBkZWFsCmluIHRoZSBTb2Z0 +d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uIHRo +ZSByaWdodHMKdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRl +LCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbApjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8g +cGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXMKZnVybmlzaGVkIHRvIGRvIHNv +LCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczoKClRoZSBhYm92ZSBjb3B5cmln +aHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGlu +IGFsbApjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLgoKVEhF +IFNPRlRXQVJFIElTIFBST1ZJREVEICJBUyBJUyIsIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJ +TkQsIEVYUFJFU1MgT1IKSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUg +V0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksCkZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQ +VVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRQpBVVRIT1JT +IE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLCBEQU1BR0VTIE9S +IE9USEVSCkxJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQg +T1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sCk9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEgg +VEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU4gVEhFClNPRlRXQVJF +Lgo= diff --git a/src/native/broker/dependency-licenses.json b/src/native/broker/dependency-licenses.json index 2aba460b2..44340c7a3 100644 --- a/src/native/broker/dependency-licenses.json +++ b/src/native/broker/dependency-licenses.json @@ -22,6 +22,7 @@ "libloading@0.8.9", "linux-raw-sys@0.12.1", "memchr@2.8.1", + "oliphaunt-query@0.1.1", "proc-macro2@1.0.106", "quote@1.0.45", "rustix@1.1.4", @@ -59,6 +60,7 @@ "libloading@0.8.9", "linux-raw-sys@0.12.1", "memchr@2.8.1", + "oliphaunt-query@0.1.1", "proc-macro2@1.0.106", "quote@1.0.45", "rustix@1.1.4", @@ -96,6 +98,7 @@ "libc@0.2.186", "libloading@0.8.9", "memchr@2.8.1", + "oliphaunt-query@0.1.1", "proc-macro2@1.0.106", "quote@1.0.45", "rustix@1.1.4", @@ -130,6 +133,7 @@ "itoa@1.0.18", "libloading@0.8.9", "memchr@2.8.1", + "oliphaunt-query@0.1.1", "proc-macro2@1.0.106", "quote@1.0.45", "serde@1.0.228", @@ -476,6 +480,26 @@ } ] }, + { + "name": "oliphaunt-query", + "version": "0.1.1", + "checksum": "523a7416f6a830ef02928994a2a89e9fd9d01e4fe67b22f0480d377d5f9b235c", + "declaredLicense": "MIT", + "selectedLicense": "MIT", + "targets": ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"], + "licenseFiles": [ + { + "name": "LICENSE", + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "bytes": 1085 + }, + { + "name": "THIRD_PARTY_NOTICES.md", + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "bytes": 821 + } + ] + }, { "name": "proc-macro2", "version": "1.0.106", diff --git a/src/native/broker/moon.yml b/src/native/broker/moon.yml index 5dadc8ef7..83b3c1b2c 100644 --- a/src/native/broker/moon.yml +++ b/src/native/broker/moon.yml @@ -19,13 +19,6 @@ project: release: component: "oliphaunt-broker" packagePath: "src/native/broker" - artifactTargets: - preset: "broker-helper" - targets: - - "linux-arm64-gnu" - - "linux-x64-gnu" - - "macos-arm64" - - "windows-x64-msvc" owners: defaultOwner: "@oliphaunt/broker" @@ -58,7 +51,7 @@ tasks: set -eu . src/native/runtime/tools/runtime-preflight.sh oliphaunt_runtime_native_host_require basic - cargo test -p oliphaunt-broker --locked --test postgres_client -- --ignored + cargo test --manifest-path src/native/broker/Cargo.toml --locked --test postgres_client -- --ignored inputs: - "@group(code)" - "/Cargo.toml" @@ -69,22 +62,19 @@ tasks: runFromWorkspaceRoot: true format: - command: "cargo fmt -p oliphaunt-broker" + command: "cargo fmt --manifest-path src/native/broker/Cargo.toml" options: cache: false runInCI: false runFromWorkspaceRoot: true package: - deps: ["liboliphaunt-native-bindings:package", "oliphaunt-query:package"] tags: ["release", "artifact-package", "ci-rust-sdk-package"] script: | set -eu version="$(bun tools/release/product-version.mts version oliphaunt-broker)" - bindings_version="$(bun tools/release/product-version.mts version liboliphaunt-native-bindings)" - query_version="$(bun tools/release/product-version.mts version oliphaunt-query)" - rm -f "target/package/oliphaunt-broker-$version.crate" "target/package/liboliphaunt-native-bindings-$bindings_version.crate" "target/package/oliphaunt-query-$query_version.crate" - cargo package -p oliphaunt-query -p liboliphaunt-native-bindings -p oliphaunt-broker --locked --allow-dirty --no-verify + rm -f "target/package/oliphaunt-broker-$version.crate" + cargo package --manifest-path src/native/broker/Cargo.toml --locked --allow-dirty --no-verify rm -rf target/sdk-artifacts/oliphaunt-broker mkdir -p target/sdk-artifacts/oliphaunt-broker cp "target/package/oliphaunt-broker-$version.crate" target/sdk-artifacts/oliphaunt-broker/ @@ -99,7 +89,7 @@ tasks: - target: cargo-sources cacheStrategy: hash tags: ["build", "requires-rust"] - command: "cargo build -p oliphaunt-broker --locked" + command: "cargo build --manifest-path src/native/broker/Cargo.toml --locked" env: CARGO_TARGET_DIR: "target" inputs: @@ -117,7 +107,7 @@ tasks: - target: cargo-sources cacheStrategy: hash tags: ["quality", "unit", "requires-rust"] - command: "cargo test -p oliphaunt-broker --locked" + command: "cargo test --manifest-path src/native/broker/Cargo.toml --locked" env: CARGO_TARGET_DIR: "target" inputs: @@ -130,7 +120,7 @@ tasks: format-check: tags: ["quality", "static", "format", "requires-rust"] - command: "cargo fmt -p oliphaunt-broker --check" + command: "cargo fmt --manifest-path src/native/broker/Cargo.toml --check" inputs: ["/src/native/broker/**/*.rs","/src/native/broker/Cargo.toml","/clippy.toml","@group(cargo-workspace)"] options: runFromWorkspaceRoot: true @@ -139,7 +129,7 @@ tasks: - target: cargo-sources cacheStrategy: hash tags: ["quality", "static", "requires-rust"] - command: "cargo clippy -p oliphaunt-broker --all-targets --locked -- -D warnings" + command: "cargo clippy --manifest-path src/native/broker/Cargo.toml --all-targets --locked -- -D warnings" env: CARGO_TARGET_DIR: "target" inputs: ["/src/native/broker/**/*.rs","/src/native/broker/Cargo.toml","/clippy.toml","@group(cargo-workspace)"] diff --git a/src/native/broker/release.toml b/src/native/broker/release.toml index 76fd18ba2..c4cfd8734 100644 --- a/src/native/broker/release.toml +++ b/src/native/broker/release.toml @@ -27,3 +27,12 @@ public_support = false source_product = "oliphaunt-query" path = "src/native/broker/Cargo.toml" parser = "toml:dependencies.oliphaunt-query.version" + +[artifact_targets] +preset = "broker-helper" +targets = [ + "linux-arm64-gnu", + "linux-x64-gnu", + "macos-arm64", + "windows-x64-msvc", +] diff --git a/src/native/broker/tools/broker-dependency-license-contract.mts b/src/native/broker/tools/broker-dependency-license-contract.mts index 9f10d1b99..e74e8f1ed 100644 --- a/src/native/broker/tools/broker-dependency-license-contract.mts +++ b/src/native/broker/tools/broker-dependency-license-contract.mts @@ -1,11 +1,15 @@ #!/usr/bin/env bun import { createRustDependencyLicenseContract } from '../../../../tools/packaging/rust-dependency-license-contract.mts'; -const contract = createRustDependencyLicenseContract({ - owner: 'src/native/broker', - product: 'oliphaunt-broker', - payloadLicense: 'MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause', - noticeProfile: 'broker', -}); +export function createBrokerDependencyLicenseContract(sourceRoot?: string) { + return createRustDependencyLicenseContract({ + sourceRoot, + owner: 'src/native/broker', + product: 'oliphaunt-broker', + payloadLicense: 'MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause', + noticeProfile: 'broker', + }); +} +const contract = createBrokerDependencyLicenseContract(); export const { RUST_DEPENDENCY_LICENSE_ROOT: BROKER_DEPENDENCY_LICENSE_ROOT, RUST_PAYLOAD_LICENSE: BROKER_PAYLOAD_LICENSE, diff --git a/src/native/broker/tools/build-linux-broker-baseline.sh b/src/native/broker/tools/build-linux-broker-baseline.sh index c1845dae3..6a659580d 100755 --- a/src/native/broker/tools/build-linux-broker-baseline.sh +++ b/src/native/broker/tools/build-linux-broker-baseline.sh @@ -142,7 +142,7 @@ if ! CARGO_NET_OFFLINE=true docker_cargo none cargo fetch --locked --offline; th fi CARGO_NET_OFFLINE=true docker_cargo none \ - cargo build -p oliphaunt-broker --release --locked --offline + cargo build --manifest-path src/native/broker/Cargo.toml --release --locked --offline broker="$target_dir/release/oliphaunt-broker" [ -x "$broker" ] || fail "sealed build did not produce $broker" diff --git a/src/native/broker/tools/package-broker-assets.sh b/src/native/broker/tools/package-broker-assets.sh index 6bfc71549..5639fa1af 100755 --- a/src/native/broker/tools/package-broker-assets.sh +++ b/src/native/broker/tools/package-broker-assets.sh @@ -54,7 +54,7 @@ if [[ "$target_id" == linux-*-gnu ]]; then broker_bin="$cargo_target_dir/release/$broker_stage_name" src/native/broker/tools/build-linux-broker-baseline.sh "$cargo_target_dir" else - cargo build -p oliphaunt-broker --release --locked + cargo build --manifest-path src/native/broker/Cargo.toml --release --locked fi [ -x "$broker_bin" ] || fail "missing broker helper at $broker_bin" diff --git a/src/native/broker/tools/test-consumer.sh b/src/native/broker/tools/test-consumer.sh index 353b7be63..005b717ea 100644 --- a/src/native/broker/tools/test-consumer.sh +++ b/src/native/broker/tools/test-consumer.sh @@ -20,4 +20,4 @@ export LIBOLIPHAUNT_PATH="$consumer/native/lib/liboliphaunt.so" export OLIPHAUNT_INSTALL_DIR="$consumer/native/runtime" export OLIPHAUNT_EMBEDDED_MODULE_DIR="$consumer/native/lib/modules" export OLIPHAUNT_BROKER="$consumer/broker/bin/oliphaunt-broker" -cargo test -p oliphaunt-broker --locked --test postgres_client -- --ignored +cargo test --manifest-path src/native/broker/Cargo.toml --locked --test postgres_client -- --ignored diff --git a/src/native/mobile-bindings/BUILD.bazel b/src/native/mobile-bindings/BUILD.bazel new file mode 100644 index 000000000..32ca8ced8 --- /dev/null +++ b/src/native/mobile-bindings/BUILD.bazel @@ -0,0 +1,36 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files", "source_quality_files") +load("//build_defs/languages:rust.bzl", "cargo_generator", "cargo_library", "cargo_library_test", "cargo_package_env") +load("//build_defs/languages:mobile.bzl", "mobile_bindgen") +load("@rules_rust//rust:defs.bzl", "rust_clippy_test") + +package(default_visibility = ["//visibility:public"]) +exports_files(["Cargo.toml", "uniffi.toml"]) +filegroup( + name = "license_inputs", + srcs = ["dependency-licenses.json", "tools/dependency-license-contract.mts"] + glob(["dependency-license-blobs/*.base64"]), +) + +# The conventional mobile dependency disables the desktop SDK's default +# broker implementation. Keep this variant explicit in the native graph. +PATH_DEPS = { + "oliphaunt": "//src/native/sdks/rust:mobile_lib", + "liboliphaunt-native-bindings": "//src/native/rust-bindings:lib", +} + +cargo_package_env() +cargo_generator(path_dependencies = PATH_DEPS) +cargo_library(name = "shared", kind = "cdylib", path_dependencies = PATH_DEPS, build_script = ":build_script") +cargo_library(name = "static", kind = "staticlib", path_dependencies = PATH_DEPS, build_script = ":build_script") +cargo_library(name = "lib", path_dependencies = PATH_DEPS, build_script = ":build_script") +cargo_library_test() +rust_clippy_test(name = "clippy_test", targets = [":lib", ":unit_test", ":build_script_"], transitive = False, size = "small") +mobile_bindgen() + +source_quality_files() + +rust_quality_files() + +# Source-only inputs for the existing SDK package policy tests. +exports_files([ + "tools/dependency-license-contract.mts", +], visibility = ["//visibility:public"]) diff --git a/src/native/mobile-bindings/Cargo.toml b/src/native/mobile-bindings/Cargo.toml index e29d9916d..3807b1cf5 100644 --- a/src/native/mobile-bindings/Cargo.toml +++ b/src/native/mobile-bindings/Cargo.toml @@ -14,7 +14,7 @@ bindgen = ["uniffi/cli"] [dependencies] oliphaunt = { path = "../sdks/rust", default-features = false, features = ["mobile-bindings"] } -liboliphaunt-native-bindings = { path = "../rust-bindings" } +liboliphaunt-native-bindings.workspace = true uniffi = { version = "=0.32.1", default-features = false } thiserror = "2" diff --git a/src/native/mobile-bindings/dependency-license-blobs/20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830.base64 b/src/native/mobile-bindings/dependency-license-blobs/20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830.base64 new file mode 100644 index 000000000..8102d7ab2 --- /dev/null +++ b/src/native/mobile-bindings/dependency-license-blobs/20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830.base64 @@ -0,0 +1,15 @@ +IyBUaGlyZC1QYXJ0eSBOb3RpY2VzCgpPbGlwaGF1bnQgc291cmNlIGNvZGUgaW4gdGhpcyByZXBv +c2l0b3J5IGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZSBpbgpgTElDRU5TRWAuCgpU +aGlzIGZpbGUgaXMgdGhlIHJlcG9zaXRvcnktbGV2ZWwgbm90aWNlIGluZGV4LiBQcm9kdWN0LXNw +ZWNpZmljIHJ1bnRpbWUgYW5kCnBhY2thZ2luZyBub3RpY2VzIGxpdmUgbmV4dCB0byB0aGUgcHJv +ZHVjdCB0aGF0IHNoaXBzIHRoZSByZWxldmFudCBhcnRpZmFjdHM6CgotIGBzcmMvbmF0aXZlL3J1 +bnRpbWUvVEhJUkRfUEFSVFlfTk9USUNFUy5tZGAKLSBgc3JjL3dhc2l4L3Nka3MvcnVzdC9USElS +RF9QQVJUWV9OT1RJQ0VTLm1kYAoKU2hhcmVkIFBvc3RncmVTUUwgc291cmNlIHBpbnMsIHRoaXJk +LXBhcnR5IHNvdXJjZSBwaW5zLCBhbmQgZXh0ZW5zaW9uIG1ldGFkYXRhCmFyZSBtYWludGFpbmVk +IGluIGBzcmMvdGhpcmQtcGFydHkvcG9zdGdyZXMvYCwgYHNyYy90aGlyZC1wYXJ0eS9gLCBhbmQK +YHNyYy9leHRlbnNpb25zL2AuIEdlbmVyYXRlZCByZWxlYXNlIGFydGlmYWN0cyBtdXN0IGluY2x1 +ZGUgdGhlIG5vdGljZXMgYW5kCmV4YWN0IHBpbm5lZCBsaWNlbnNlIGJ5dGVzIGZvciBldmVyeSBw +cm9kdWN0IGFuZCB0aGlyZC1wYXJ0eSBjb21wb25lbnQgdGhleQpzaGlwLgoKQ2Fub25pY2FsIHJ1 +bnRpbWUgbGljZW5zZSBzbmFwc2hvdHMgbGl2ZSBpbgpgc3JjL3RoaXJkLXBhcnR5L2A7IHRoZWly +IHNvdXJjZSBwaW5zIGFuZCBkaWdlc3RzIGFyZQplbmZvcmNlZCBieSBgdG9vbHMvcGFja2FnaW5n +L3JlbGVhc2Utbm90aWNlcy5tdHNgLgo= diff --git a/src/native/mobile-bindings/dependency-license-blobs/6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10.base64 b/src/native/mobile-bindings/dependency-license-blobs/6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10.base64 new file mode 100644 index 000000000..ed642faf0 --- /dev/null +++ b/src/native/mobile-bindings/dependency-license-blobs/6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10.base64 @@ -0,0 +1,20 @@ +TUlUIExpY2Vuc2UKCkNvcHlyaWdodCAoYykgMjAyNCBvbGlwaGF1bnQtd2FzaXggQ29udHJpYnV0 +b3JzCgpQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55 +IHBlcnNvbiBvYnRhaW5pbmcgYSBjb3B5Cm9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQg +ZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlICJTb2Z0d2FyZSIpLCB0byBkZWFsCmluIHRoZSBTb2Z0 +d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uIHRo +ZSByaWdodHMKdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRl +LCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbApjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8g +cGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXMKZnVybmlzaGVkIHRvIGRvIHNv +LCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczoKClRoZSBhYm92ZSBjb3B5cmln +aHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGlu +IGFsbApjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLgoKVEhF +IFNPRlRXQVJFIElTIFBST1ZJREVEICJBUyBJUyIsIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJ +TkQsIEVYUFJFU1MgT1IKSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUg +V0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksCkZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQ +VVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRQpBVVRIT1JT +IE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLCBEQU1BR0VTIE9S +IE9USEVSCkxJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQg +T1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sCk9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEgg +VEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU4gVEhFClNPRlRXQVJF +Lgo= diff --git a/src/native/mobile-bindings/dependency-licenses.json b/src/native/mobile-bindings/dependency-licenses.json index 8e47fb8b1..623d8923b 100644 --- a/src/native/mobile-bindings/dependency-licenses.json +++ b/src/native/mobile-bindings/dependency-licenses.json @@ -33,6 +33,7 @@ "libloading@0.8.9", "linux-raw-sys@0.12.1", "memchr@2.8.1", + "oliphaunt-query@0.1.1", "once_cell@1.21.4", "proc-macro2@1.0.106", "quote@1.0.45", @@ -99,6 +100,7 @@ "libloading@0.8.9", "linux-raw-sys@0.12.1", "memchr@2.8.1", + "oliphaunt-query@0.1.1", "once_cell@1.21.4", "proc-macro2@1.0.106", "quote@1.0.45", @@ -164,6 +166,7 @@ "libloading@0.8.9", "linux-raw-sys@0.12.1", "memchr@2.8.1", + "oliphaunt-query@0.1.1", "once_cell@1.21.4", "proc-macro2@1.0.106", "quote@1.0.45", @@ -230,6 +233,7 @@ "libloading@0.8.9", "linux-raw-sys@0.12.1", "memchr@2.8.1", + "oliphaunt-query@0.1.1", "once_cell@1.21.4", "proc-macro2@1.0.106", "quote@1.0.45", @@ -296,6 +300,7 @@ "libloading@0.8.9", "linux-raw-sys@0.12.1", "memchr@2.8.1", + "oliphaunt-query@0.1.1", "once_cell@1.21.4", "proc-macro2@1.0.106", "quote@1.0.45", @@ -362,6 +367,7 @@ "libloading@0.8.9", "linux-raw-sys@0.12.1", "memchr@2.8.1", + "oliphaunt-query@0.1.1", "once_cell@1.21.4", "proc-macro2@1.0.106", "quote@1.0.45", @@ -428,6 +434,7 @@ "libloading@0.8.9", "linux-raw-sys@0.12.1", "memchr@2.8.1", + "oliphaunt-query@0.1.1", "once_cell@1.21.4", "proc-macro2@1.0.106", "quote@1.0.45", @@ -1194,6 +1201,34 @@ } ] }, + { + "name": "oliphaunt-query", + "version": "0.1.1", + "checksum": "523a7416f6a830ef02928994a2a89e9fd9d01e4fe67b22f0480d377d5f9b235c", + "declaredLicense": "MIT", + "selectedLicense": "MIT", + "targets": [ + "android-arm", + "android-arm64", + "android-x86", + "android-x86_64", + "ios-arm64", + "ios-simulator-arm64", + "macos-arm64" + ], + "licenseFiles": [ + { + "name": "LICENSE", + "sha256": "6f8300e2f43c5a012d6f914fe5affa9090b97b0be39ddf3846f01b905edd8c10", + "bytes": 1085 + }, + { + "name": "THIRD_PARTY_NOTICES.md", + "sha256": "20fd67487d1a631ba959cf7ec3fdbaf4977997ed624c0188dcb3c8870eded830", + "bytes": 821 + } + ] + }, { "name": "once_cell", "version": "1.21.4", diff --git a/src/native/mobile-bindings/tools/dependency-license-contract.mts b/src/native/mobile-bindings/tools/dependency-license-contract.mts index 67d2299e5..a3f05b9a8 100644 --- a/src/native/mobile-bindings/tools/dependency-license-contract.mts +++ b/src/native/mobile-bindings/tools/dependency-license-contract.mts @@ -1,19 +1,23 @@ import { createRustDependencyLicenseContract } from '../../../../tools/packaging/rust-dependency-license-contract.mts'; -const contract = createRustDependencyLicenseContract({ - owner: 'src/native/mobile-bindings', - product: 'oliphaunt-mobile-bindings', - payloadLicense: 'MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause AND MPL-2.0', - targets: [ - { id: 'android-arm64', cargoTarget: 'aarch64-linux-android' }, - { id: 'android-x86_64', cargoTarget: 'x86_64-linux-android' }, - { id: 'android-arm', cargoTarget: 'armv7-linux-androideabi' }, - { id: 'android-x86', cargoTarget: 'i686-linux-android' }, - { id: 'ios-arm64', cargoTarget: 'aarch64-apple-ios' }, - { id: 'ios-simulator-arm64', cargoTarget: 'aarch64-apple-ios-sim' }, - { id: 'macos-arm64', cargoTarget: 'aarch64-apple-darwin' }, - ], -}); +export function createMobileDependencyLicenseContract(sourceRoot?: string) { + return createRustDependencyLicenseContract({ + sourceRoot, + owner: 'src/native/mobile-bindings', + product: 'oliphaunt-mobile-bindings', + payloadLicense: 'MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause AND MPL-2.0', + targets: [ + { id: 'android-arm64', cargoTarget: 'aarch64-linux-android' }, + { id: 'android-x86_64', cargoTarget: 'x86_64-linux-android' }, + { id: 'android-arm', cargoTarget: 'armv7-linux-androideabi' }, + { id: 'android-x86', cargoTarget: 'i686-linux-android' }, + { id: 'ios-arm64', cargoTarget: 'aarch64-apple-ios' }, + { id: 'ios-simulator-arm64', cargoTarget: 'aarch64-apple-ios-sim' }, + { id: 'macos-arm64', cargoTarget: 'aarch64-apple-darwin' }, + ], + }); +} +const contract = createMobileDependencyLicenseContract(); export const { RUST_DEPENDENCY_LICENSE_ROOT, RUST_PAYLOAD_LICENSE, diff --git a/src/native/node-addon/BUILD.bazel b/src/native/node-addon/BUILD.bazel new file mode 100644 index 000000000..96371392a --- /dev/null +++ b/src/native/node-addon/BUILD.bazel @@ -0,0 +1,36 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files", "source_quality_files") +load("//build_defs/languages:rust.bzl", "cargo_generator", "cargo_napi_library", "cargo_library_test", "cargo_package_env", "napi_artifact") +load("@rules_rust//rust:defs.bzl", "rust_clippy_test") +load("//build_defs/languages/carriers:defs.bzl", "native_helper_carriers") +load("//build_defs/native/carriers:release-family.bzl", "native_release_checksum_family") + +package(default_visibility = ["//visibility:public"]) + +native_release_checksum_family(product = "oliphaunt-node-direct") +exports_files(["Cargo.toml", "tools/dependency-license-contract.mts"]) +filegroup(name = "carrier_legal_sources", srcs = ["dependency-licenses.json"] + glob(["dependency-license-blobs/*.base64"])) +filegroup(name = "carrier_template_sources", srcs = glob(["packages/*/package.json", "packages/*/README.md"])) + +cargo_package_env() +PATH_DEPS = {"liboliphaunt-native-bindings": "//src/native/rust-bindings:lib"} +cargo_generator(path_dependencies = PATH_DEPS, proc_macro_names = ["napi-derive"]) +cargo_napi_library( + name = "addon_library", + build_script = ":build_script", + proc_macro_names = ["napi-derive"], + path_dependencies = PATH_DEPS, +) + +napi_artifact( + name = "addon", + library = ":addon_library", + out = "oliphaunt_node.node", +) +cargo_library_test(crate = ":addon_library", tags = ["manual"]) +rust_clippy_test(name = "clippy_test", targets = [":addon_library", ":unit_test", ":build_script_"], transitive = False, size = "small") + +native_helper_carriers(product = "oliphaunt-node-direct", binary = ":addon", qualification = ["//build_defs/languages/carriers:installed_sql_test"], path_dependencies = PATH_DEPS) + +source_quality_files() + +rust_quality_files() diff --git a/src/native/node-addon/Cargo.toml b/src/native/node-addon/Cargo.toml index a3e4b6ae1..6d6f9e4c9 100644 --- a/src/native/node-addon/Cargo.toml +++ b/src/native/node-addon/Cargo.toml @@ -10,7 +10,7 @@ publish = false crate-type = ["cdylib"] [dependencies] -liboliphaunt-native-bindings = { path = "../rust-bindings" } +liboliphaunt-native-bindings = { path = "../rust-bindings", version = "0.2.0" } napi = { version = "=3.12.2", default-features = false, features = ["napi8"] } napi-derive = { version = "=3.6.3", default-features = false, features = ["strict", "type-def"] } diff --git a/src/native/node-addon/moon.yml b/src/native/node-addon/moon.yml index 905fe90c9..8f6a92c37 100644 --- a/src/native/node-addon/moon.yml +++ b/src/native/node-addon/moon.yml @@ -16,13 +16,6 @@ project: release: component: "oliphaunt-node-direct" packagePath: "src/native/node-addon" - artifactTargets: - preset: "node-direct-addon" - targets: - - "linux-arm64-gnu" - - "linux-x64-gnu" - - "macos-arm64" - - "windows-x64-msvc" owners: defaultOwner: "@oliphaunt/node-direct" diff --git a/src/native/node-addon/release.toml b/src/native/node-addon/release.toml index 4353fb730..329fc3a82 100644 --- a/src/native/node-addon/release.toml +++ b/src/native/node-addon/release.toml @@ -11,8 +11,23 @@ registry_packages = [ release_artifacts = ["node-api-prebuilds", "npm-optional-platform-packages"] embedded_cargo_manifests = ["src/native/node-addon/Cargo.toml"] +[compatibility_versions.node_native_bindings] +public_support = false +source_product = "liboliphaunt-native-bindings" +path = "src/native/node-addon/Cargo.toml" +parser = "toml:dependencies.liboliphaunt-native-bindings.version" + [compatibility_versions.oliphaunt-node-direct-liboliphaunt] public_support = false source_product = "liboliphaunt-native" path = "src/native/node-addon/package.json" parser = "json:oliphaunt.liboliphauntVersion" + +[artifact_targets] +preset = "node-direct-addon" +targets = [ + "linux-arm64-gnu", + "linux-x64-gnu", + "macos-arm64", + "windows-x64-msvc", +] diff --git a/src/native/node-addon/tools/dependency-license-contract.mts b/src/native/node-addon/tools/dependency-license-contract.mts index 47e5e09a4..c2e200138 100644 --- a/src/native/node-addon/tools/dependency-license-contract.mts +++ b/src/native/node-addon/tools/dependency-license-contract.mts @@ -1,11 +1,16 @@ #!/usr/bin/env bun import { createRustDependencyLicenseContract } from '../../../../tools/packaging/rust-dependency-license-contract.mts'; -const contract = createRustDependencyLicenseContract({ - owner: 'src/native/node-addon', - product: 'oliphaunt-node-direct', - payloadLicense: 'MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause', -}); +export function createNodeDependencyLicenseContract(sourceRoot?: string) { + return createRustDependencyLicenseContract({ + sourceRoot, + owner: 'src/native/node-addon', + product: 'oliphaunt-node-direct', + payloadLicense: 'MIT AND ISC AND Unicode-3.0 AND BSD-3-Clause', + }); +} + +const contract = createNodeDependencyLicenseContract(); export const { RUST_DEPENDENCY_LICENSE_ROOT, diff --git a/src/native/postgres-tools/BUILD.bazel b/src/native/postgres-tools/BUILD.bazel new file mode 100644 index 000000000..7b9f3badf --- /dev/null +++ b/src/native/postgres-tools/BUILD.bazel @@ -0,0 +1,123 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files", "source_quality_files") +load("@rules_rust//rust:defs.bzl", "rust_clippy_test") +load("//build_defs/languages:rust.bzl", "cargo_generator", "cargo_integration_test", "cargo_library", "cargo_library_test", "cargo_package_env") +load("//build_defs/native/carriers:defs.bzl", "native_desktop_carriers", "native_tools_facades") +load("//build_defs/native/carriers:release-family.bzl", "native_release_checksum_family") +load("//build_defs/native/carriers:tests.bzl", "native_cargo_consumer_test", "native_installed_carrier_test") +load("//build_defs/native:platform_config.bzl", "NATIVE_COMPATIBLE") +load("//build_defs/native:rust-runtime-test.bzl", "native_rust_runtime_test") + +package(default_visibility = ["//visibility:public"]) + +native_release_checksum_family(product = "postgres-tools-native") +exports_files(["release.toml", "tools/package-cargo-artifacts.mts"]) +exports_files(glob(["npm/*", "npm-platforms/*/package.json", "npm-platforms/*/README.md", "crates/tools/**"], exclude = ["**/target/**"])) + +native_desktop_carriers( + product = "postgres-tools-native", + root_mappings = [], + runtime_mappings = ["//src/native/runtime:tools_binaries", "//src/native/runtime:runtime_libpq"], + binary_mappings = ["//src/native/runtime:tools_binaries", "//src/native/runtime:runtime_libpq"], + qualification = [":installed_cargo_test", ":installed_carrier_test"], +) + +native_tools_facades(qualification = [ + ":tools_cargo_unit_test", + ":tools_build_support_test", + ":logical_round_trip_test", + ":installed_carrier_test", +]) + +cargo_package_env(name = "tools_cargo_env", package_name = "src/native/postgres-tools/crates/tools") +cargo_generator( + name = "tools_cargo_build_script", + package_name = "src/native/postgres-tools/crates/tools", + cargo_env = ":tools_cargo_env", + srcs = ["crates/tools/build_support.rs"], +) +cargo_library( + name = "tools_cargo_lib", + package_name = "src/native/postgres-tools/crates/tools", + cargo_env = ":tools_cargo_env", + build_script = ":tools_cargo_build_script", +) +cargo_library_test( + name = "tools_cargo_unit_test", + package_name = "src/native/postgres-tools/crates/tools", + cargo_env = ":tools_cargo_env", + crate = ":tools_cargo_lib", + data = ["//src/test-fixtures:rust_fixtures"], + tags = ["manual"], +) +cargo_integration_test( + name = "tools_build_support_test", + package_name = "src/native/postgres-tools/crates/tools", + cargo_env = ":tools_cargo_env", + source = "crates/tools/tests/build_support.rs", + srcs = ["crates/tools/build_support.rs"], + crate = ":tools_cargo_lib", + tags = ["manual"], +) + +cargo_package_env(name = "proof_cargo_env", package_name = "src/native/postgres-tools/tests") +cargo_library( + name = "proof_cargo_lib", + package_name = "src/native/postgres-tools/tests", + cargo_env = ":proof_cargo_env", +) +cargo_library_test( + name = "proof_cargo_unit_test", + package_name = "src/native/postgres-tools/tests", + cargo_env = ":proof_cargo_env", + crate = ":proof_cargo_lib", + path_dependencies = { + "oliphaunt": "//src/native/sdks/rust:lib", + "oliphaunt-tools": ":tools_cargo_lib", + }, + data = ["//src/test-fixtures:rust_fixtures"], + tags = ["manual"], +) + +native_rust_runtime_test( + name = "logical_round_trip_test", + binary = ":proof_cargo_unit_test", + extensions = ["//src/extensions/external/pgtap:native_payload"], + test_args = ["--ignored", "--test-threads=1", "--nocapture"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + size = "large", + timeout = "long", +) + +rust_clippy_test( + name = "clippy_test", + targets = [ + ":tools_cargo_lib", + ":tools_cargo_unit_test", + ":tools_cargo_build_script_", + ":tools_build_support_test", + ":proof_cargo_lib", + ":proof_cargo_unit_test", + ], + transitive = False, + size = "small", + tags = ["quality", "static"], +) + +native_cargo_consumer_test( + name = "installed_cargo_test", + packages = ":cargo_packages", + archive = ":github_archive", + target_compatible_with = NATIVE_COMPATIBLE, + size = "medium", +) + +native_installed_carrier_test( + name = "installed_carrier_test", + inputs = ["//src/native/runtime:github_archive", "//src/native/runtime:npm", ":github_archive", ":npm_facade", ":npm", "//src/native/runtime:profile_smoke", "//build_defs/native/carriers:tools-consumer.mts", "//src/test-fixtures:postgres/logical-tools.json"], + target_compatible_with = NATIVE_COMPATIBLE, + size = "medium", +) + +source_quality_files() + +rust_quality_files() diff --git a/src/native/postgres-tools/crates/tools/src/arguments.rs b/src/native/postgres-tools/crates/tools/src/arguments.rs index 95e560d5d..a5499f4ea 100644 --- a/src/native/postgres-tools/crates/tools/src/arguments.rs +++ b/src/native/postgres-tools/crates/tools/src/arguments.rs @@ -218,6 +218,11 @@ mod tests { #[test] fn arguments_match_the_canonical_contract() { let owner = std::path::Path::new(env!("CARGO_MANIFEST_DIR")); + let owner = std::env::var_os("TEST_SRCDIR") + .zip(std::env::var_os("TEST_WORKSPACE")) + .filter(|_| !owner.is_absolute()) + .map(|(root, workspace)| std::path::PathBuf::from(root).join(workspace).join(owner)) + .unwrap_or_else(|| owner.to_path_buf()); let source = owner.join("../../../../test-fixtures/postgres/logical-tools.json"); let fixture = if source.is_file() { source diff --git a/src/native/postgres-tools/moon.yml b/src/native/postgres-tools/moon.yml index 3462e4809..c0d4c0c57 100644 --- a/src/native/postgres-tools/moon.yml +++ b/src/native/postgres-tools/moon.yml @@ -15,9 +15,6 @@ project: release: component: "postgres-tools-native" packagePath: "src/native/postgres-tools" - artifactTargets: - preset: "postgres-tools-native" - targets: ["linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"] fileGroups: sources: ["**/*", "!**/node_modules/**/*", "!**/target/**/*"] tasks: diff --git a/src/native/postgres-tools/release.toml b/src/native/postgres-tools/release.toml index c10ff29b2..c4f82fe14 100644 --- a/src/native/postgres-tools/release.toml +++ b/src/native/postgres-tools/release.toml @@ -16,3 +16,12 @@ registry_packages = [ "npm:@oliphaunt/tools", ] release_artifacts = ["postgres-tools"] + +[artifact_targets] +preset = "postgres-tools-native" +targets = [ + "linux-arm64-gnu", + "linux-x64-gnu", + "macos-arm64", + "windows-x64-msvc", +] diff --git a/src/native/postgres-tools/tests/src/lib.rs b/src/native/postgres-tools/tests/src/lib.rs index cfdde14a9..3447ed275 100644 --- a/src/native/postgres-tools/tests/src/lib.rs +++ b/src/native/postgres-tools/tests/src/lib.rs @@ -67,12 +67,14 @@ mod tests { } fn fixture(name: &str) -> String { - std::fs::read_to_string( - Path::new(env!("CARGO_MANIFEST_DIR")) - .join("../../../test-fixtures/postgres") - .join(name), - ) - .unwrap_or_else(|error| panic!("read canonical logical tools fixture {name}: {error}")) + let owner = Path::new(env!("CARGO_MANIFEST_DIR")); + let owner = std::env::var_os("TEST_SRCDIR") + .zip(std::env::var_os("TEST_WORKSPACE")) + .filter(|_| !owner.is_absolute()) + .map(|(root, workspace)| PathBuf::from(root).join(workspace).join(owner)) + .unwrap_or_else(|| owner.to_path_buf()); + std::fs::read_to_string(owner.join("../../../test-fixtures/postgres").join(name)) + .unwrap_or_else(|error| panic!("read canonical logical tools fixture {name}: {error}")) } fn expected_logical_tools_row() -> String { diff --git a/src/native/postgres-tools/tools/package-cargo-artifacts.mts b/src/native/postgres-tools/tools/package-cargo-artifacts.mts index 06c9aa0cd..48feb2dfd 100644 --- a/src/native/postgres-tools/tools/package-cargo-artifacts.mts +++ b/src/native/postgres-tools/tools/package-cargo-artifacts.mts @@ -38,21 +38,27 @@ export function renderUnsupportedToolsTargetGuard(nativeTargets, nativeCfgs) { }); } -function writeToolsFacadeCrate(sourceRoot, { version, toolsTargets }) { +export function writeToolsFacadeCrate( + sourceRoot, + { + version, + toolsTargets, + templateRoot = TOOLS_FACADE_TEMPLATE, + fixture = path.join(ROOT, 'src/test-fixtures/postgres/logical-tools.json'), + noticeSourceRoot, + }, +) { const crateDir = path.join(sourceRoot, TOOLS_PRODUCT); if (existsSync(crateDir)) { fail(`duplicate generated ${TOOLS_PRODUCT} source crate: ${rel(crateDir)}`); } - cpSync(TOOLS_FACADE_TEMPLATE, crateDir, { + cpSync(templateRoot, crateDir, { recursive: true, filter: (source) => - path.basename(source) !== 'target' && source !== path.join(TOOLS_FACADE_TEMPLATE, 'tests'), + path.basename(source) !== 'target' && source !== path.join(templateRoot, 'tests'), }); mkdirSync(path.join(crateDir, 'testdata'), { recursive: true }); - copyFileSync( - path.join(ROOT, 'src/test-fixtures/postgres/logical-tools.json'), - path.join(crateDir, 'testdata/logical-tools.json'), - ); + copyFileSync(fixture, path.join(crateDir, 'testdata/logical-tools.json')); const cargoToml = path.join(crateDir, 'Cargo.toml'); let text = readFileSync(cargoToml, 'utf8'); text = text @@ -90,8 +96,11 @@ function writeToolsFacadeCrate(sourceRoot, { version, toolsTargets }) { libRs, `${readFileSync(libRs, 'utf8').trimEnd()}\n\n// Generated release-only native target guard.\n${releaseOnlyGuard}\n`, ); - stageReleaseNotices(crateDir, { profile: 'code-facade' }); - assertReleaseNoticesInDirectory(crateDir, { profile: 'code-facade' }); + stageReleaseNotices(crateDir, { profile: 'code-facade', sourceRoot: noticeSourceRoot }); + assertReleaseNoticesInDirectory(crateDir, { + profile: 'code-facade', + sourceRoot: noticeSourceRoot, + }); return { name: TOOLS_PRODUCT, version, diff --git a/src/native/runtime/BUILD.bazel b/src/native/runtime/BUILD.bazel new file mode 100644 index 000000000..d7ebd5ca2 --- /dev/null +++ b/src/native/runtime/BUILD.bazel @@ -0,0 +1,290 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_import", "cc_library", "cc_test") +load("@rules_pkg//pkg:mappings.bzl", "pkg_attributes", "pkg_files", "strip_prefix") +load("@rules_pkg//pkg:tar.bzl", "pkg_tar") +load("@rules_shell//shell:sh_test.bzl", "sh_test") +load("//build_defs/native:platform_config.bzl", "NATIVE_COMPATIBLE", "NATIVE_C_COMPATIBLE", "NATIVE_EMBEDDED_DEFINES", "NATIVE_BUILTIN_SNOWBALL", "NATIVE_BUILTIN_SNOWBALL_DEPS", "NATIVE_LINKOPTS", "NATIVE_RELEASE_LINKOPTS", "NATIVE_WRAPPER_COPTS", "NATIVE_WRAPPER_DEFINES", "NATIVE_BUILTIN_PLPGSQL_DEPS", "NATIVE_RUNTIME_LINKOPTS", "NATIVE_EMBEDDED_MODULE_LINKOPTS", "NATIVE_ELF_C_COMPATIBLE", "NATIVE_MACOS_COMPATIBLE", "NATIVE_WINDOWS_COMPATIBLE", "NATIVE_HOST_COMPATIBLE", "NATIVE_LINUX_COMPATIBLE", "NATIVE_UNIX_COMPATIBLE") +load("//build_defs/native:windows_link.bzl", "postgres_windows_exports") +load("//build_defs/native:mobile.bzl", "native_apple_runtime_targets", "native_ios_runtime_targets") +load("//build_defs/native/apple:static-carrier-consumer.bzl", "apple_static_carrier_consumer_test") +load("//build_defs/native/android:runtime.bzl", "native_android_runtime_targets") +load("//build_defs/foundation:bun.bzl", "bun_script_test") +load("//build_defs/native/carriers:defs.bzl", "native_desktop_carriers") +load("//build_defs/native/carriers:release-family.bzl", "native_release_checksum_family") +load("//build_defs/native/carriers:tests.bzl", "native_cargo_consumer_test") + +package(default_visibility = ["//visibility:public"]) + +native_release_checksum_family(product = "liboliphaunt-native") + +exports_files(["release.toml", "postgres/series", "include/oliphaunt.h", "bin/android-cxx-runtime.map", "tools/native-mobile-abi-contract.mts"] + glob(["patches/**/*.patch"])) +exports_files(["THIRD_PARTY_NOTICES.md", "tools/native-runtime-payload.mts", "tools/native-runtime-payload-policy.json"]) +exports_files(["tools/finalize-native-runtime-carrier.mts", "tools/native-runtime-carrier-contract.mts"]) +exports_files(["tools/testdata/native-runtime-fixture.mts"], visibility = ["//build_defs/android:__pkg__"]) +exports_files(glob(["packages/*/package.json", "packages/*/README.md"])) + +alias(name = "postgres_server_headers", actual = "@postgres//:server_headers") +alias(name = "postgres_embedded_headers", actual = "@postgres//:embedded_headers") + +cc_library( + name = "wrapper", + srcs = [ + "src/liboliphaunt_native.c", + "src/liboliphaunt_error.c", + "src/liboliphaunt_runtime.c", + "src/liboliphaunt_protocol.c", + "src/liboliphaunt_config.c", + "src/liboliphaunt_process.c", + "src/liboliphaunt_trace.c", + "src/liboliphaunt_fs.c", + "src/liboliphaunt_backup_state.c", + "src/liboliphaunt_archive.c", + "src/liboliphaunt_archive_tar.c", + "src/liboliphaunt_static_extensions.c", + "src/liboliphaunt_builtin_extensions.c", + ], + hdrs = glob(["include/*.h", "src/*.h"]), + defines = ["OLIPHAUNT_EMBEDDED", "OLIPHAUNT_BUILTIN_PLPGSQL"] + NATIVE_EMBEDDED_DEFINES + NATIVE_BUILTIN_SNOWBALL, + local_defines = NATIVE_WRAPPER_DEFINES, + copts = NATIVE_WRAPPER_COPTS, + includes = ["include", "src"], + # Resolve builtin libraries in the same slice as their wrapper defines. + implementation_deps = NATIVE_BUILTIN_PLPGSQL_DEPS + NATIVE_BUILTIN_SNOWBALL_DEPS, + alwayslink = True, + target_compatible_with = NATIVE_C_COMPATIBLE, +) + +cc_binary( + name = "liboliphaunt.so", + deps = [":wrapper", "@postgres//:backend_embedded", "@postgres//:main_embedded"], + linkshared = True, + linkopts = NATIVE_RUNTIME_LINKOPTS + NATIVE_LINKOPTS + NATIVE_RELEASE_LINKOPTS + select({ + "//build_defs/native:android": ["-Wl,--exclude-libs,libc++_static.a:libc++abi.a:libunwind.a", "-Wl,--version-script,$(location :bin/android-cxx-runtime.map)"], + "//conditions:default": [], + }), + additional_linker_inputs = select({"//build_defs/native:android": ["bin/android-cxx-runtime.map"], "//conditions:default": []}), + target_compatible_with = NATIVE_ELF_C_COMPATIBLE, + tags = ["native-development-slice"], +) + +cc_binary( + name = "liboliphaunt.dylib", + deps = [":wrapper", "@postgres//:backend_embedded", "@postgres//:main_embedded"], + linkshared = True, + linkopts = NATIVE_RUNTIME_LINKOPTS + NATIVE_LINKOPTS, + target_compatible_with = NATIVE_MACOS_COMPATIBLE, + tags = ["native-development-slice"], +) + +postgres_windows_exports( + name = "runtime_windows_exports", + roots = ["@postgres//:backend_embedded", "@postgres//:main_embedded"], + target_compatible_with = NATIVE_WINDOWS_COMPATIBLE, +) + +cc_binary( + name = "oliphaunt.dll", + deps = [":wrapper", "@postgres//:backend_embedded", "@postgres//:main_embedded"], + linkshared = True, + win_def_file = ":runtime_windows_exports", + features = ["no_windows_export_all_symbols"], + linkopts = NATIVE_RUNTIME_LINKOPTS + NATIVE_LINKOPTS, + target_compatible_with = NATIVE_WINDOWS_COMPATIBLE, + tags = ["native-development-slice"], +) + +alias(name = "runtime_shared", actual = select({"//build_defs/native:macos_arm64": ":liboliphaunt.dylib", "//build_defs/native:windows_x64": ":oliphaunt.dll", "//conditions:default": ":liboliphaunt.so"})) +native_android_runtime_targets() +native_ios_runtime_targets() +native_apple_runtime_targets(qualification = [ + "//build_defs/native:ios_device_builtin_link_test", + "//build_defs/native:ios_simulator_builtin_link_test", + ":apple_final_contract_test", + "//build_defs/native/apple:framework_contract_test", + ":apple_static_carrier_consumer_test", +]) +apple_static_carrier_consumer_test( + name = "apple_static_carrier_consumer_test", + base = ":apple_swiftpm", + ios_resources = ":apple_resources", + macos_resources = ":apple_macos_resources", + base_manifest = ":apple_ios_manifest", + leaves = ["//build_defs/extensions/mobile/final:oliphaunt_extension_contrib_pg18_ios_xcframework"], + extensions = ["cube", "pg_trgm"], + target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:aarch64", "//build_defs/host:apple_package"], + size = "large", + timeout = "long", + tags = ["no-remote"], +) +# The ABI receipt consumes the producer's exact File, including the iOS archive. +alias(name = "runtime_abi_binary", actual = select({"//build_defs/native:ios": ":mobile_static_archive", "//conditions:default": ":runtime_shared"})) +filegroup(name = "runtime_windows_interface", srcs = [":oliphaunt.dll"], output_group = "interface_library", target_compatible_with = NATIVE_WINDOWS_COMPATIBLE) + +cc_import( + name = "runtime_shared_library", + shared_library = ":runtime_shared", + interface_library = select({"//build_defs/native:windows_x64": ":runtime_windows_interface", "//conditions:default": None}), + # An imported DLL does not inherit the producing binary's dependencies. + # Keep ICU's import/runtime closure so normal Windows C consumers receive + # the same three actual DLLs as the installed runtime payload. + deps = select({"//build_defs/native:windows_x64": ["@icu//:i18n"], "//conditions:default": []}), +) + +cc_library( + name = "liboliphaunt", + deps = select({"//build_defs/native:ios": [":mobile_static"], "//conditions:default": [":runtime_shared_library"]}), + hdrs = ["include/oliphaunt.h"], + includes = ["include"], +) + +cc_binary( + name = "dict_snowball.so", + deps = [":liboliphaunt", "@postgres//:snowball_embedded"], + linkshared = True, + linkopts = ["-Wl,-z,defs"] + NATIVE_RELEASE_LINKOPTS, + target_compatible_with = NATIVE_ELF_C_COMPATIBLE, +) + +cc_binary( + name = "plpgsql.so", + deps = [":liboliphaunt", "@postgres//:plpgsql_embedded"], + linkshared = True, + linkopts = ["-Wl,-z,defs"] + NATIVE_RELEASE_LINKOPTS, + target_compatible_with = NATIVE_ELF_C_COMPATIBLE, +) + +[cc_binary(name = name + suffix, deps = [":liboliphaunt", "@postgres//:" + role + "_embedded"], linkshared = True, + linkopts = NATIVE_EMBEDDED_MODULE_LINKOPTS, target_compatible_with = compatible) + for name, role in [("plpgsql", "plpgsql"), ("dict_snowball", "snowball")] + for suffix, compatible in [(".dylib", NATIVE_MACOS_COMPATIBLE), (".dll", NATIVE_WINDOWS_COMPATIBLE)]] +[alias(name = name + "_module", actual = select({"//build_defs/native:macos_arm64": ":" + name + ".dylib", "//build_defs/native:windows_x64": ":" + name + ".dll", "//conditions:default": ":" + name + ".so"})) + for name in ["plpgsql", "dict_snowball"]] + +cc_test( + name = "unix_abi_conformance_test", + srcs = ["smoke/liboliphaunt_abi_conformance.c"], + deps = [":liboliphaunt"], + copts = ["-std=c11", "-pedantic", "-Wall", "-Wextra", "-Werror"], + target_compatible_with = NATIVE_UNIX_COMPATIBLE, +) + +cc_binary( + name = "windows_abi_conformance", + srcs = ["smoke/liboliphaunt_abi_conformance.c"], + deps = [":liboliphaunt"], + copts = ["/std:c11", "/W4", "/WX"], + target_compatible_with = NATIVE_WINDOWS_COMPATIBLE, +) + +bun_script_test( + name = "windows_abi_conformance_test", + entry_point = "//build_defs/native:windows-abi-conformance.test.mts", + args = ["$(location :runtime_payload)", "$(location :windows_abi_conformance)", "$(locations @native_msvc_sdk//:runtime_dlls)"], + data = [":runtime_payload", ":windows_abi_conformance", "@native_msvc_sdk//:runtime_dlls", "//build_defs/native:host-runtime-test-helpers.mts", "//:tools/packaging/portable-archive.mts", "//:tools/packaging/windows-vc-runtime-closure.mts", "//:tools/packaging/windows-vc-runtime-policy.json"], + target_compatible_with = NATIVE_WINDOWS_COMPATIBLE, + size = "small", +) + +alias(name = "abi_conformance_test", actual = select({"//build_defs/native:windows_x64": ":windows_abi_conformance_test", "//conditions:default": ":unix_abi_conformance_test"})) + +cc_binary( + name = "runtime_smoke", + srcs = ["smoke/liboliphaunt_smoke.c"], + deps = [":liboliphaunt", ":smoke_internal_headers", "@postgres//:embedded_headers"], + copts = select({"//build_defs/native:windows_x64": ["/std:c11"], "//conditions:default": ["-std=c11", "-Wall", "-Wextra", "-Werror"]}), + linkopts = select({"//build_defs/native:windows_x64": [], "//conditions:default": ["-lpthread"]}), + target_compatible_with = NATIVE_COMPATIBLE, +) + +cc_library(name = "smoke_internal_headers", hdrs = glob(["src/*.h"]), includes = ["src"]) + +cc_binary( + name = "profile_smoke", + srcs = ["smoke/liboliphaunt_cluster_seed_smoke.c"], + deps = [":liboliphaunt"], + copts = select({"//build_defs/native:windows_x64": ["/std:c11"], "//conditions:default": ["-std=c11", "-Wall", "-Wextra", "-Werror"]}), + target_compatible_with = NATIVE_COMPATIBLE, +) + +pkg_files(name = "runtime_binaries", srcs = ["@postgres//:initdb", "@postgres//:pg_ctl", "@postgres//:server_executable"], prefix = "bin", attributes = pkg_attributes(mode = "0755")) +pkg_files(name = "tools_binaries", srcs = ["@postgres//:pg_basebackup", "@postgres//:pg_dump", "@postgres//:psql"], prefix = "bin", attributes = pkg_attributes(mode = "0755")) +pkg_tar(name = "tools_payload", srcs = [":tools_binaries", ":runtime_libpq", ":runtime_vc_libraries"], tags = ["native-development-slice"]) +pkg_files(name = "runtime_libpq", srcs = ["@postgres//:libpq_shared"], prefix = select({"//build_defs/native:windows_x64": "bin", "//conditions:default": "lib"}), + renames = select({"//build_defs/native:windows_x64": {}, "//build_defs/native:macos_arm64": {"@postgres//:libpq_shared": "libpq.5.dylib"}, "//conditions:default": {"@postgres//:libpq_shared": "libpq.so.5"}})) +pkg_files(name = "runtime_library", srcs = [":runtime_shared"], prefix = select({"//build_defs/native:windows_x64": "bin", "//conditions:default": "lib"})) +pkg_files(name = "runtime_icu_libraries", srcs = select({"//build_defs/native:windows_x64": ["@icu//:windows_runtime_dlls"], "//conditions:default": []}), prefix = "bin") +pkg_files(name = "runtime_vc_libraries", srcs = select({"//build_defs/native:windows_x64": ["@native_msvc_sdk//:runtime_dlls"], "//conditions:default": []}), prefix = "bin") +pkg_files(name = "runtime_windows_import_library", srcs = select({"//build_defs/native:windows_x64": [":runtime_windows_interface"], "//conditions:default": []}), prefix = "lib", + renames = select({"//build_defs/native:windows_x64": {":runtime_windows_interface": "oliphaunt.lib"}, "//conditions:default": {}})) +pkg_files(name = "runtime_public_header", srcs = ["include/oliphaunt.h"], prefix = "include") +pkg_files(name = "runtime_server_modules", srcs = ["@postgres//:plpgsql_module", "@postgres//:dict_snowball_module"], prefix = "lib/postgresql") +pkg_files(name = "runtime_embedded_modules", srcs = [":plpgsql_module", ":dict_snowball_module"], prefix = "lib/modules") +pkg_files(name = "runtime_catalog", srcs = ["@postgres//:catalog_runtime_data"], prefix = "share/postgresql") +pkg_files(name = "runtime_stopwords", srcs = ["@postgres//:stopwords"], prefix = "share/postgresql/tsearch_data") +pkg_files(name = "runtime_extension_data", srcs = ["@postgres//:builtin_extension_data"], prefix = "share/postgresql/extension") +pkg_files(name = "runtime_timezone", srcs = ["@postgres//:timezone"], prefix = "share/postgresql", strip_prefix = strip_prefix.files_only()) +pkg_files(name = "runtime_timezone_abbreviations", srcs = ["@postgres//:timezone_abbreviations"], prefix = "share/postgresql/timezonesets") +pkg_files(name = "runtime_postgres_license", srcs = ["@postgres//:license"], prefix = "share/licenses/postgresql") +pkg_files(name = "runtime_icu_data", srcs = ["@icu_data//:data"], prefix = "share/icu") +pkg_files(name = "runtime_icu_notices", srcs = ["@icu_data//:notices"], prefix = "share/licenses/icu") + +native_desktop_carriers( + product = "liboliphaunt-native", + root_mappings = [":runtime_library", ":runtime_public_header", ":runtime_embedded_modules", ":runtime_windows_import_library", ":runtime_icu_libraries"], + runtime_mappings = [":runtime_binaries", ":runtime_libpq", ":runtime_server_modules", ":runtime_catalog", ":runtime_stopwords", ":runtime_extension_data", ":runtime_timezone", ":runtime_timezone_abbreviations", ":runtime_icu_libraries"], + binary_mappings = [":runtime_library", ":runtime_embedded_modules", ":runtime_binaries", ":runtime_libpq", ":runtime_server_modules", ":runtime_icu_libraries"], + qualification = [":installed_cargo_test"] + select({ + "//build_defs/native:macos_arm64": [":host_runtime_sql_test"], + "//build_defs/native:windows_x64": [":host_runtime_sql_test", "//build_defs/native:windows_restricted_process_test"], + "//conditions:default": [":unix_runtime_sql_test"], + }), +) + +native_cargo_consumer_test( + name = "installed_cargo_test", + packages = ":cargo_packages", + archive = ":github_archive", + target_compatible_with = NATIVE_COMPATIBLE, + size = "medium", +) + +# This development payload proves the slice; release carriers keep their current +# producer until profile, toolchain, platform and envelope equivalence is proven. +pkg_tar( + name = "runtime_payload", + srcs = [":runtime_binaries", ":runtime_libpq", ":runtime_library", ":runtime_icu_libraries", ":runtime_vc_libraries", ":runtime_windows_import_library", ":runtime_public_header", ":runtime_server_modules", ":runtime_embedded_modules", ":runtime_catalog", ":runtime_stopwords", ":runtime_extension_data", ":runtime_timezone", ":runtime_timezone_abbreviations", ":runtime_postgres_license", ":runtime_icu_data", ":runtime_icu_notices"], + tags = ["native-development-slice"], +) + +sh_test( + name = "unix_runtime_sql_test", + srcs = ["//build_defs/native:runtime_sql_test.sh"], + args = ["$(location :runtime_payload)", "$(location :runtime_smoke)", "$(location smoke/fixtures/physical-archive-native-v1.properties)", "$(location :profile_smoke)"], + data = [":runtime_payload", ":runtime_smoke", ":profile_smoke", "smoke/fixtures/physical-archive-native-v1.properties", "//src/test-fixtures:storage/physical-backup-wal-range-v1.properties"], + target_compatible_with = NATIVE_LINUX_COMPATIBLE, + size = "medium", +) + +bun_script_test( + name = "host_runtime_sql_test", + entry_point = "//build_defs/native:host-runtime-sql.test.mts", + args = ["$(location :runtime_payload)", "$(location :runtime_smoke)", "$(location smoke/fixtures/physical-archive-native-v1.properties)", "$(location :profile_smoke)"], + data = [":runtime_payload", ":runtime_smoke", ":profile_smoke", "smoke/fixtures/physical-archive-native-v1.properties", "//src/test-fixtures:storage/physical-backup-wal-range-v1.properties", "//:tools/packaging/portable-archive.mts", "//build_defs/native:host-runtime-test-helpers.mts"], + target_compatible_with = NATIVE_HOST_COMPATIBLE, + size = "medium", +) + +alias(name = "runtime_sql_test", actual = select({"//build_defs/native:macos_arm64": ":host_runtime_sql_test", "//build_defs/native:windows_x64": ":host_runtime_sql_test", "//conditions:default": ":unix_runtime_sql_test"})) + +bun_script_test( + name = "native_tools_sql_test", + entry_point = "//build_defs/native:native-tools-sql.test.mts", + args = ["$(location :runtime_payload)", "$(location :tools_payload)"], + data = [":runtime_payload", ":tools_payload", "//:tools/packaging/portable-archive.mts", "//build_defs/native:host-runtime-test-helpers.mts"], + target_compatible_with = NATIVE_COMPATIBLE, + size = "medium", +) + +source_quality_files() + +filegroup(name = "mobile_e2e_sources", srcs = ["bin/build-output.bash", "bin/mobile-static-extensions.sh"]) diff --git a/src/native/runtime/bin/build-macos-extension-archives.sh b/src/native/runtime/bin/build-macos-extension-archives.sh index 912130e42..fa82b9306 100755 --- a/src/native/runtime/bin/build-macos-extension-archives.sh +++ b/src/native/runtime/bin/build-macos-extension-archives.sh @@ -283,7 +283,7 @@ archive_mobile_static_extension_objects() { } build_static_extension_objects() { - local extension source source_dir source_rel object object_dir objects_file stem prefix include_dir cflag + local extension source source_dir source_rel object object_dir objects_file sources stem prefix include_dir cflag local -a compile_args extension_include_args extension_cflags for extension in ${mobile_static_extensions[@]+"${mobile_static_extensions[@]}"}; do if [ "$extension" = "postgis" ]; then @@ -317,6 +317,7 @@ build_static_extension_objects() { rm -rf "$object_dir" mkdir -p "$object_dir" : > "$objects_file" + sources="$(set -e; oliphaunt_mobile_static_extension_source_files "$repo_root" "$build_dir" "$extension")" while IFS= read -r source; do [ -n "$source" ] || continue [ -f "$source" ] || fail "macOS static extension source is missing: $source" @@ -343,7 +344,7 @@ build_static_extension_objects() { -o "$object" ) "${compile_args[@]}" - done < <(oliphaunt_mobile_static_extension_source_files "$repo_root" "$build_dir" "$extension") + done <<< "$sources" [ -s "$objects_file" ] || fail "macOS static extension $extension did not produce object inputs" archive_mobile_static_extension_objects "$extension" "$object_dir" "$objects_file" done diff --git a/src/native/runtime/bin/build-postgres18-android-arm64.sh b/src/native/runtime/bin/build-postgres18-android-arm64.sh index 6a441bca3..acbb1be84 100755 --- a/src/native/runtime/bin/build-postgres18-android-arm64.sh +++ b/src/native/runtime/bin/build-postgres18-android-arm64.sh @@ -695,7 +695,7 @@ build_mobile_static_dependencies() { } build_mobile_static_extension_objects() { - local extension source source_dir source_rel object object_dir objects_file stem prefix + local extension source source_dir source_rel object object_dir objects_file sources stem prefix local -a compile_args extension_include_args extension_cflags for extension in ${mobile_static_extensions[@]+"${mobile_static_extensions[@]}"}; do if [ "$extension" = "postgis" ]; then @@ -730,6 +730,7 @@ build_mobile_static_extension_objects() { objects_file="$object_dir/objects.list" mkdir -p "$object_dir" : > "$objects_file" + sources="$(set -e; oliphaunt_mobile_static_extension_source_files "$repo_root" "$build_dir" "$extension")" while IFS= read -r source; do [ -n "$source" ] || continue source_rel="${source#$source_dir/}" @@ -755,7 +756,7 @@ build_mobile_static_extension_objects() { -o "$object" ) "${compile_args[@]}" - done < <(oliphaunt_mobile_static_extension_source_files "$repo_root" "$build_dir" "$extension") + done <<< "$sources" if [ ! -s "$objects_file" ]; then fail "mobile static extension $extension did not produce object inputs" fi @@ -947,6 +948,7 @@ link_liboliphaunt() { -Wl,-soname,liboliphaunt.so \ -Wl,-z,defs \ -Wl,-z,max-page-size=16384 \ + -Wl,-z,common-page-size=16384 \ -o "$lib_out" \ "${liboliphaunt_objects[@]}" \ "${mobile_static_objects[@]}" \ diff --git a/src/native/runtime/bin/build-postgres18-ios-device.sh b/src/native/runtime/bin/build-postgres18-ios-device.sh index 24e68fc79..dd3160e66 100755 --- a/src/native/runtime/bin/build-postgres18-ios-device.sh +++ b/src/native/runtime/bin/build-postgres18-ios-device.sh @@ -732,7 +732,7 @@ build_mobile_static_dependencies() { } build_mobile_static_extension_objects() { - local extension source source_dir source_rel object object_dir objects_file stem prefix + local extension source source_dir source_rel object object_dir objects_file sources stem prefix local -a compile_args extension_include_args extension_cflags for extension in ${mobile_static_extensions[@]+"${mobile_static_extensions[@]}"}; do if [ "$extension" = "postgis" ]; then @@ -765,6 +765,7 @@ build_mobile_static_extension_objects() { objects_file="$object_dir/objects.list" mkdir -p "$object_dir" : > "$objects_file" + sources="$(set -e; oliphaunt_mobile_static_extension_source_files "$repo_root" "$build_dir" "$extension")" while IFS= read -r source; do [ -n "$source" ] || continue source_rel="${source#$source_dir/}" @@ -790,7 +791,7 @@ build_mobile_static_extension_objects() { -o "$object" ) "${compile_args[@]}" - done < <(oliphaunt_mobile_static_extension_source_files "$repo_root" "$build_dir" "$extension") + done <<< "$sources" if [ ! -s "$objects_file" ]; then echo "mobile static extension $extension did not produce object inputs" >&2 exit 1 diff --git a/src/native/runtime/bin/build-postgres18-ios-simulator.sh b/src/native/runtime/bin/build-postgres18-ios-simulator.sh index 678eb4c06..5acf227d8 100755 --- a/src/native/runtime/bin/build-postgres18-ios-simulator.sh +++ b/src/native/runtime/bin/build-postgres18-ios-simulator.sh @@ -732,7 +732,7 @@ build_mobile_static_dependencies() { } build_mobile_static_extension_objects() { - local extension source source_dir source_rel object object_dir objects_file stem prefix + local extension source source_dir source_rel object object_dir objects_file sources stem prefix local -a compile_args extension_include_args extension_cflags for extension in ${mobile_static_extensions[@]+"${mobile_static_extensions[@]}"}; do if [ "$extension" = "postgis" ]; then @@ -765,6 +765,7 @@ build_mobile_static_extension_objects() { objects_file="$object_dir/objects.list" mkdir -p "$object_dir" : > "$objects_file" + sources="$(set -e; oliphaunt_mobile_static_extension_source_files "$repo_root" "$build_dir" "$extension")" while IFS= read -r source; do [ -n "$source" ] || continue source_rel="${source#$source_dir/}" @@ -790,7 +791,7 @@ build_mobile_static_extension_objects() { -o "$object" ) "${compile_args[@]}" - done < <(oliphaunt_mobile_static_extension_source_files "$repo_root" "$build_dir" "$extension") + done <<< "$sources" if [ ! -s "$objects_file" ]; then echo "mobile static extension $extension did not produce object inputs" >&2 exit 1 diff --git a/src/native/runtime/moon.yml b/src/native/runtime/moon.yml index 7fc3992af..6eb0f72cb 100644 --- a/src/native/runtime/moon.yml +++ b/src/native/runtime/moon.yml @@ -32,16 +32,6 @@ project: release: component: liboliphaunt-native packagePath: src/native/runtime - artifactTargets: - preset: liboliphaunt-native - targets: - - android-arm64-v8a - - android-x86_64 - - ios-xcframework - - linux-arm64-gnu - - linux-x64-gnu - - macos-arm64 - - windows-x64-msvc owners: defaultOwner: "@oliphaunt/core" paths: @@ -264,6 +254,10 @@ tasks: - /src/native/runtime/tools/native-readiness-probes.test.sh - /src/native/runtime/bin/common.sh - /src/native/runtime/bin/mobile-static-extensions.sh + - /src/native/runtime/bin/build-macos-extension-archives.sh + - /src/native/runtime/bin/build-postgres18-ios-device.sh + - /src/native/runtime/bin/build-postgres18-ios-simulator.sh + - /src/native/runtime/bin/build-postgres18-android-arm64.sh - /src/native/runtime/include/oliphaunt.h - /src/native/runtime/src/liboliphaunt_internal.h - /src/native/runtime/src/liboliphaunt_platform.h diff --git a/src/native/runtime/packaging/BUILD.bazel b/src/native/runtime/packaging/BUILD.bazel new file mode 100644 index 000000000..50f16670f --- /dev/null +++ b/src/native/runtime/packaging/BUILD.bazel @@ -0,0 +1,21 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files") +load("//build_defs/languages:rust.bzl", "cargo_binary", "cargo_library", "cargo_library_test", "cargo_package_env") +load("@rules_rust//rust:defs.bzl", "rust_clippy_test") + +package(default_visibility = ["//visibility:public"]) +exports_files(["Cargo.toml"]) + +PATH_DEPS = {"liboliphaunt-native-bindings": "//src/native/rust-bindings:packaging_lib"} + +cargo_package_env() +cargo_library(path_dependencies = PATH_DEPS, compile_data = ["//src/extensions/generated/sdk:extensions.json", "//src/extensions/contracts:archive_policy_compile_data"]) +cargo_binary(name = "resources", source = "src/bin/package_resources.rs", path_dependencies = PATH_DEPS, library = ":lib") +cargo_library_test() +cargo_library_test(name = "resources_cli_test", crate = ":resources") + +# Private packaging code has source obligations rather than public shipping roots. +test_suite(name = "source_tests", tests = [":unit_test", ":resources_cli_test"]) + +rust_clippy_test(name = "clippy_test", targets = [":lib", ":unit_test", ":resources", ":resources_cli_test"], transitive = False, size = "small") + +rust_quality_files() diff --git a/src/native/runtime/packaging/src/bin/package_resources.rs b/src/native/runtime/packaging/src/bin/package_resources.rs index 18e940d6f..ac919d1ec 100644 --- a/src/native/runtime/packaging/src/bin/package_resources.rs +++ b/src/native/runtime/packaging/src/bin/package_resources.rs @@ -6,6 +6,7 @@ use liboliphaunt_native_bindings::Extension; use oliphaunt_native_packaging::{ Error, MobileStaticRegistryState, NativePrebuiltExtensionArtifact, NativeRuntimeFeature, NativeRuntimeResourceOptions, Result, build_native_runtime_resources, + validate_runtime_cache_identity, }; fn main() { @@ -45,6 +46,9 @@ fn run_with_package_args(args: PackageArgs) -> Result<()> { if let Some(version) = args.liboliphaunt_version { options = options.native_runtime_version(version); } + if let Some(identity) = args.runtime_cache_identity { + options = options.runtime_cache_identity(identity); + } for name in args.extensions { let extension = Extension::by_sql_name(&name).ok_or_else(|| Error::InvalidConfig(format!("unknown built-in extension {name}; supply external artifacts with --prebuilt-extension")))?; options = options.extension(extension); @@ -140,6 +144,7 @@ struct PackageArgs { force: bool, require_mobile_static_registry: bool, liboliphaunt_version: Option, + runtime_cache_identity: Option, help: bool, } impl PackageArgs { @@ -165,6 +170,7 @@ impl PackageArgs { force: false, require_mobile_static_registry: false, liboliphaunt_version: native_runtime_version, + runtime_cache_identity: None, help: false, }; let mut args = args.into_iter(); @@ -193,6 +199,21 @@ impl PackageArgs { "--require-mobile-static-registry" => parsed.require_mobile_static_registry = true, "--output" | "-o" => parsed.output_dir = Some(PathBuf::from(value()?)), "--liboliphaunt-native-version" => parsed.liboliphaunt_version = Some(value()?), + "--runtime-cache-identity" => { + if parsed.runtime_cache_identity.is_some() { + return Err(Error::InvalidConfig( + "--runtime-cache-identity may be supplied only once".to_owned(), + )); + } + let identity = value()?; + if inline.is_none() && identity.starts_with("--") { + return Err(Error::InvalidConfig( + "--runtime-cache-identity requires a value; use '=' for an identity starting with '--'".to_owned(), + )); + } + validate_runtime_cache_identity(&identity)?; + parsed.runtime_cache_identity = Some(identity); + } "--extension" => push_extension_names(&mut parsed.extensions, &value()?), "--runtime-feature" | "--runtime-features" => { push_runtime_feature_names(&mut parsed.runtime_features, &value()?)? @@ -277,7 +298,7 @@ fn default_extension_artifact_target() -> String { fn print_help() { println!( - "oliphaunt-resources --output [--runtime-feature icu] [--extension name] [--prebuilt-extension artifact] [--liboliphaunt-native-version version] [--extension-target target] [--mobile-static-module module] [--require-mobile-static-registry] [--force]" + "oliphaunt-resources --output [--runtime-feature icu] [--extension name] [--prebuilt-extension artifact] [--liboliphaunt-native-version version] [--extension-target target] [--runtime-cache-identity identity] [--mobile-static-module module] [--require-mobile-static-registry] [--force]" ); } @@ -295,6 +316,55 @@ mod tests { #[cfg(unix)] static ENV_LOCK: OnceLock> = OnceLock::new(); + #[test] + fn runtime_cache_identity_option_is_optional_and_preserves_the_exact_token() { + let parsed = PackageArgs::parse_with_native_runtime_version(Vec::new(), None).unwrap(); + assert_eq!(parsed.runtime_cache_identity, None); + for (args, expected) in [ + ( + strings(["--runtime-cache-identity", "bazel-runtime_18.4"]), + "bazel-runtime_18.4", + ), + ( + strings(["--runtime-cache-identity=bazel-runtime_18.4"]), + "bazel-runtime_18.4", + ), + (strings(["--runtime-cache-identity=--key"]), "--key"), + ] { + let parsed = PackageArgs::parse_with_native_runtime_version(args, None).unwrap(); + assert_eq!(parsed.runtime_cache_identity.as_deref(), Some(expected)); + } + } + + #[test] + fn runtime_cache_identity_option_rejects_invalid_repeated_and_missing_values() { + for args in [ + strings(["--runtime-cache-identity"]), + strings(["--runtime-cache-identity", "--force"]), + strings(["--runtime-cache-identity="]), + strings(["--runtime-cache-identity=."]), + strings(["--runtime-cache-identity=.."]), + strings(["--runtime-cache-identity=a/b"]), + strings(["--runtime-cache-identity=a b"]), + strings(["--runtime-cache-identity=é"]), + vec![format!("--runtime-cache-identity={}", "a".repeat(129))], + strings([ + "--runtime-cache-identity=first", + "--runtime-cache-identity=second", + ]), + strings([ + "--runtime-cache-identity", + "first", + "--runtime-cache-identity=second", + ]), + ] { + assert!( + PackageArgs::parse_with_native_runtime_version(args.clone(), None).is_err(), + "accepted {args:?}" + ); + } + } + #[test] fn value_options_preserve_equals_and_flags_reject_values() { for args in [ @@ -390,6 +460,47 @@ mod tests { ); } + let override_output = temp.join("override-output"); + let args = PackageArgs::parse_with_native_runtime_version( + strings([ + "--output", + override_output.to_str().unwrap(), + "--prebuilt-extension", + artifact.to_str().unwrap(), + "--extension-target", + "test-target", + "--liboliphaunt-native-version", + "1.2.3", + "--runtime-cache-identity", + "bazel-runtime_18.4", + ]), + None, + ) + .unwrap(); + run_with_package_args(args).unwrap(); + let original_key = manifest + .lines() + .find_map(|line| line.strip_prefix("cacheKey=")) + .unwrap(); + assert!(!original_key.is_empty()); + let identity_manifest = + fs::read_to_string(override_output.join("oliphaunt/runtime/manifest.properties")) + .unwrap(); + let derived_key = identity_manifest + .lines() + .find_map(|line| line.strip_prefix("cacheKey=")) + .unwrap(); + assert!(derived_key.starts_with("runtime-")); + assert_ne!(derived_key, "bazel-runtime_18.4"); + validate_runtime_cache_identity(derived_key).unwrap(); + assert_eq!( + identity_manifest, + manifest.replace( + &format!("cacheKey={original_key}\n"), + &format!("cacheKey={derived_key}\n") + ) + ); + let _ = fs::remove_dir_all(temp); } diff --git a/src/native/runtime/packaging/src/extension_artifact.rs b/src/native/runtime/packaging/src/extension_artifact.rs index a2440fe81..283fba31c 100644 --- a/src/native/runtime/packaging/src/extension_artifact.rs +++ b/src/native/runtime/packaging/src/extension_artifact.rs @@ -36,6 +36,10 @@ pub(super) const EXTENSION_ARTIFACT_POSTGRESQL_LICENSE: &str = "THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT"; pub(super) const EXTENSION_ARTIFACT_OPENSSL_LICENSE: &str = "THIRD_PARTY_LICENSES/OpenSSL-LICENSE.txt"; +pub(super) const EXTENSION_ARTIFACT_OPENSSL_CONSTRUCTION_LICENSES: [&str; 2] = [ + "share/licenses/openssl-native/LICENSE.txt", + "share/licenses/openssl-native/SOURCE.toml", +]; fn extension_artifact_legal_members( profile: NativeExtensionArtifactLicenseProfile, @@ -89,9 +93,16 @@ pub(super) fn validate_extension_artifact_license_profile( let external = catalog::by_sql_name(sql_name) .and_then(|extension| extension.artifact_product.as_deref()) .is_none_or(|product| product != "oliphaunt-extension-contrib-pg18"); + let openssl_construction_files = license_files.iter().map(PathBuf::as_path).eq( + EXTENSION_ARTIFACT_OPENSSL_CONSTRUCTION_LICENSES + .iter() + .map(Path::new), + ); let embeds_openssl = !external && sql_name == "pgcrypto" && (matches!(native_target, Some("macos-arm64" | "windows-x64-msvc")) + || (openssl_construction_files + && native_target.is_some_and(|target| DESKTOP_NATIVE_TARGETS.contains(&target))) || mobile_static_dependency_archives .iter() .any(|archive| archive.name == "openssl")); @@ -118,7 +129,7 @@ pub(super) fn validate_extension_artifact_license_profile( manifest_path.display() ))); } - if !external && !license_files.is_empty() { + if !(external || license_files.is_empty() || embeds_openssl && openssl_construction_files) { return Err(Error::InvalidConfig(format!( "manifest {} contrib profile must not declare upstream licenseFiles leaves", manifest_path.display() @@ -130,7 +141,7 @@ pub(super) fn validate_extension_artifact_license_profile( pub(super) fn validate_prebuilt_extension_leaf_inventory( root: &Path, manifest_path: &Path, - extension: &RuntimeResourceExtension, + extension: &mut RuntimeResourceExtension, ) -> Result<()> { let profile = extension.license_profile.ok_or_else(|| { Error::Engine(format!( @@ -193,7 +204,29 @@ pub(super) fn validate_prebuilt_extension_leaf_inventory( for relative in &extension.data_files { expected.insert(PathBuf::from("files/share/postgresql").join(relative)); } - if let Some(module) = &extension.native_module_file { + if let Some(module) = &extension.native_module_file + && let Some((_, suffix @ ("so" | "dylib" | "dll"))) = module.rsplit_once('.') + && let Some(canonical) = Extension::by_sql_name(&extension.sql_name) + && let Some(stem) = canonical.native_module_stem() + && extension.native_module_stem.as_deref() == Some(stem) + && module == &format!("{stem}.{suffix}") + { + let dependencies = canonical + .native_dependency_module_stems() + .iter() + .map(|stem| format!("{stem}.{suffix}")) + .collect::>(); + // Historical carriers may incorporate these dependencies into the main + // module. A separate canonical sidecar requires its complete profile. + if dependencies.iter().any(|module| { + ["files/lib/postgresql", "files/lib/modules"] + .iter() + .any(|prefix| actual.contains(&PathBuf::from(prefix).join(module))) + }) { + extension.native_dependency_module_files = dependencies; + } + } + for module in extension.native_module_files() { expected.insert(PathBuf::from("files/lib/postgresql").join(module)); let embedded = PathBuf::from("files/lib/modules").join(module); if extension diff --git a/src/native/runtime/packaging/src/lib.rs b/src/native/runtime/packaging/src/lib.rs index 6e82905ef..d283d444d 100644 --- a/src/native/runtime/packaging/src/lib.rs +++ b/src/native/runtime/packaging/src/lib.rs @@ -174,6 +174,9 @@ pub struct NativeRuntimeResourceOptions { /// module, including iOS and Android artifacts whose modules are linked /// through `mobile-static` archives instead of copied as dynamic modules. pub extension_target: Option, + /// Optional stable identity hashed with the packaged runtime manifest. + /// This does not change native resource acquisition or its cache. + pub runtime_cache_identity: Option, } impl NativeRuntimeResourceOptions { @@ -189,6 +192,7 @@ impl NativeRuntimeResourceOptions { prebuilt_extensions: Vec::new(), native_runtime_version: None, extension_target: None, + runtime_cache_identity: None, } } @@ -244,6 +248,29 @@ impl NativeRuntimeResourceOptions { self.extension_target = Some(target.into()); self } + + /// Derive the packaged runtime cache key from a stable identity and manifest. + pub fn runtime_cache_identity(mut self, identity: impl Into) -> Self { + self.runtime_cache_identity = Some(identity.into()); + self + } +} + +/// Validate the portable token accepted by `validNativeCacheKey` in the native +/// database-resource manifest contract. +pub fn validate_runtime_cache_identity(identity: &str) -> Result<()> { + if identity.is_empty() + || identity.len() > 128 + || matches!(identity, "." | "..") + || !identity + .bytes() + .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'_' | b'-')) + { + return Err(Error::InvalidConfig( + "runtime cache identity must be a portable identifier of 1–128 ASCII letters, digits, '.', '_' or '-', excluding '.' and '..'".to_owned(), + )); + } + Ok(()) } /// Optional runtime data/features selected independently from PostgreSQL @@ -415,7 +442,7 @@ pub struct NativeRuntimeResources { pub root: PathBuf, /// Runtime files directory copied into app storage before opening. pub runtime_files: PathBuf, - /// Content key of the source runtime cache. + /// Cache identity written into the packaged runtime manifest. pub runtime_cache_key: String, /// Built-in extensions materialized into the runtime resources. pub extensions: Vec, @@ -444,6 +471,7 @@ struct RuntimeResourceExtension { creates_extension: bool, native_module_stem: Option, native_module_file: Option, + native_dependency_module_files: Vec, native_target: Option, dependencies: Vec, data_files: Vec, @@ -522,6 +550,9 @@ impl Drop for PreparedPrebuiltExtensionArtifacts { pub fn build_native_runtime_resources( options: NativeRuntimeResourceOptions, ) -> Result { + if let Some(identity) = options.runtime_cache_identity.as_deref() { + validate_runtime_cache_identity(identity)?; + } if options.output_dir.as_os_str().is_empty() { return Err(Error::InvalidConfig( "native runtime-resource output directory must not be empty".to_owned(), @@ -556,7 +587,7 @@ pub fn build_native_runtime_resources( let root = options.output_dir.join("oliphaunt"); prepare_output_root(&root, options.replace_existing)?; - write_runtime_resource_tree( + let runtime_cache_key = write_runtime_resource_tree( &root, &materialized, &selected_extensions, @@ -564,6 +595,7 @@ pub fn build_native_runtime_resources( &shared_preload_libraries, &mobile_static_registry, options.extension_target.as_deref(), + options.runtime_cache_identity.as_deref(), )?; let size_report = runtime_resource_size_report( &root, @@ -580,7 +612,7 @@ pub fn build_native_runtime_resources( == MobileStaticRegistryState::Complete) .then(|| root.join(format!("static-registry/{STATIC_REGISTRY_SOURCE_FILE}"))), root, - runtime_cache_key: materialized.runtime_cache_key, + runtime_cache_key, extensions, runtime_features, extension_names, @@ -763,6 +795,11 @@ fn built_in_runtime_resource_extension(extension: Extension) -> RuntimeResourceE .native_module_stem .as_deref() .map(|stem| format!("{stem}{}", std::env::consts::DLL_SUFFIX)), + native_dependency_module_files: extension + .native_dependency_module_stems_for_host() + .iter() + .map(|stem| format!("{stem}{}", std::env::consts::DLL_SUFFIX)) + .collect(), native_target: None, dependencies: catalog.dependencies.clone(), data_files: catalog @@ -964,12 +1001,13 @@ fn load_prebuilt_extension_artifact(root: &Path) -> Result Result impl Iterator { + self.native_module_file + .iter() + .chain(&self.native_dependency_module_files) + .map(String::as_str) + } + fn dependencies(&self) -> Vec<&str> { self.dependencies.iter().map(String::as_str).collect() } @@ -1034,6 +1079,174 @@ mod tests { use std::time::{SystemTime, UNIX_EPOCH}; use tar::EntryType; + #[test] + fn runtime_cache_identity_uses_the_native_manifest_token_contract() { + for key in ["A-z_0.9-", "--key", "...", &"a".repeat(128)] { + validate_runtime_cache_identity(key).unwrap(); + } + for key in [ + "", + ".", + "..", + "a/b", + "a\\b", + "a b", + "a\n", + "é", + &"a".repeat(129), + ] { + assert!( + validate_runtime_cache_identity(key).is_err(), + "accepted {key:?}" + ); + } + let output = tempfile::tempdir().unwrap(); + let options = NativeRuntimeResourceOptions::new(output.path()).runtime_cache_identity("."); + assert!(build_native_runtime_resources(options).is_err()); + assert!(!output.path().join("oliphaunt").exists()); + assert_eq!( + NativeRuntimeResourceOptions::new("output").runtime_cache_identity, + None + ); + } + + #[test] + fn runtime_cache_identity_binds_the_manifest_and_preserves_default_output() { + let temp = tempfile::tempdir().unwrap(); + let materialized = MaterializedNativeResources { + runtime_dir: temp.path().join("materialized"), + runtime_cache_key: "installed-runtime-cache".to_owned(), + }; + let relative = "share/postgresql/postgresql.conf.sample"; + write_file(&materialized.runtime_dir.join(relative), b"core-runtime"); + write_file( + &materialized.runtime_dir.join("share/icu/icudt76l.dat"), + b"icu-data", + ); + write_file( + &materialized.runtime_dir.join(".manifest"), + b"key=private-cache-a\n", + ); + write_file(&materialized.runtime_dir.join(".complete"), b"ok\n"); + write_file( + &materialized.runtime_dir.join("share/.manifest"), + b"public nested data\n", + ); + let metadata = mobile_static_registry_metadata(&[], &[]).unwrap(); + let mut manifests = Vec::new(); + let mut keys = Vec::new(); + for (name, identity, features) in [ + ("default", None, &[][..]), + ("identity", Some("bazel-runtime_18.4"), &[][..]), + ("repeat", Some("bazel-runtime_18.4"), &[][..]), + ("different-identity", Some("bazel-runtime_18.5"), &[][..]), + ( + "icu-context", + Some("bazel-runtime_18.4"), + &[NativeRuntimeFeature::Icu][..], + ), + ] { + let root = temp.path().join(name); + let key = write_runtime_resource_tree( + &root, + &materialized, + &[], + features, + &[], + &metadata, + None, + identity, + ) + .unwrap(); + assert_eq!( + fs::read(root.join("runtime/files").join(relative)).unwrap(), + b"core-runtime" + ); + let text = fs::read_to_string(root.join("runtime/manifest.properties")).unwrap(); + assert!(text.lines().any(|line| line == format!("cacheKey={key}"))); + validate_runtime_cache_identity(&key).unwrap(); + if identity.is_some() { + assert!(!root.join("runtime/files/.manifest").exists()); + assert!(!root.join("runtime/files/.complete").exists()); + let digest = key.strip_prefix("runtime-").unwrap(); + assert_eq!(digest.len(), 64); + assert!( + digest + .bytes() + .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte)) + ); + } else { + assert_eq!( + fs::read(root.join("runtime/files/.manifest")).unwrap(), + b"key=private-cache-a\n" + ); + assert_eq!( + fs::read(root.join("runtime/files/.complete")).unwrap(), + b"ok\n" + ); + } + assert_eq!( + fs::read(root.join("runtime/files/share/.manifest")).unwrap(), + b"public nested data\n" + ); + keys.push(key); + manifests.push(text); + } + assert_eq!( + manifests[0], + "schema=oliphaunt-runtime-resources-v1\nlayout=postgres-runtime-files-v1\nartifactRole=runtime\ncatalogProfile=\nclusterSeedTarget=\nicuDataTreeSha256=\nmode=native-direct\ncacheKey=installed-runtime-cache\nselectedExtensions=\nextensions=\nruntimeFeatures=\nsharedPreloadLibraries=\nmobileStaticRegistryState=not-required\nmobileStaticRegistryRegistered=\nmobileStaticRegistryPending=\nnativeModuleStems=\nmobileStaticRegistrySource=\n" + ); + assert_eq!(keys[0], "installed-runtime-cache"); + assert_eq!(keys[1], keys[2]); + assert_eq!(manifests[1], manifests[2]); + assert_ne!(keys[1], keys[3]); + assert_ne!(keys[1], keys[4]); + assert_eq!( + manifests[1], + manifests[0].replace( + "cacheKey=installed-runtime-cache\n", + &format!("cacheKey={}\n", keys[1]) + ) + ); + let different_acquired_cache = MaterializedNativeResources { + runtime_dir: temp.path().join("different-private-acquisition-path"), + runtime_cache_key: "different-acquired-cache".to_owned(), + }; + copy_portable_tree( + &materialized.runtime_dir, + &different_acquired_cache.runtime_dir, + ) + .unwrap(); + write_file( + &different_acquired_cache.runtime_dir.join(".manifest"), + b"key=private-cache-b\n", + ); + write_file( + &different_acquired_cache.runtime_dir.join(".complete"), + b"different-private-marker\n", + ); + assert_eq!( + write_runtime_resource_tree( + &temp.path().join("different-acquired-cache"), + &different_acquired_cache, + &[], + &[], + &[], + &metadata, + None, + Some("bazel-runtime_18.4") + ) + .unwrap(), + keys[1] + ); + assert_eq!( + logical_tree_sha256(&temp.path().join("identity")).unwrap(), + logical_tree_sha256(&temp.path().join("different-acquired-cache")).unwrap(), + "all packaged paths and file bytes must ignore private acquisition paths/markers" + ); + assert_eq!(materialized.runtime_cache_key, "installed-runtime-cache"); + } + #[test] fn logical_tree_digest_uses_portable_path_order() { let root = tempfile::tempdir().unwrap(); @@ -1237,7 +1450,8 @@ mod tests { fs::create_dir_all(&root).unwrap(); let metadata = mobile_static_registry_metadata(&[], &[]).unwrap(); - write_runtime_resource_tree(&root, &materialized, &[], &[], &[], &metadata, None).unwrap(); + write_runtime_resource_tree(&root, &materialized, &[], &[], &[], &metadata, None, None) + .unwrap(); assert!( !root.join("runtime/files/share/icu").exists(), @@ -1276,6 +1490,7 @@ mod tests { &[], &metadata, None, + None, ) .unwrap(); @@ -1773,6 +1988,7 @@ CREATE FUNCTION sql_only(integer) RETURNS integer &[], &metadata, Some("test-target"), + None, ) .unwrap(); @@ -2588,6 +2804,141 @@ CREATE FUNCTION sql_only(integer) RETURNS integer Some(NativeExtensionArtifactLicenseProfile::ContribNativeOpenSsl) ); + for (target, profile) in [ + ( + "linux-x64-gnu", + NativeExtensionArtifactLicenseProfile::ContribNative, + ), + ( + "windows-x64-msvc", + NativeExtensionArtifactLicenseProfile::ContribNativeOpenSsl, + ), + ] { + let historical = temp.join(format!("pgcrypto-empty-{target}")); + write_profiled_extension_artifact( + &historical, + "pgcrypto", + "pgcrypto", + target, + profile, + &[], + ); + assert_eq!( + load_prebuilt_extension_artifact(&historical) + .unwrap() + .license_profile, + Some(profile) + ); + } + + for (target, static_targets) in [ + ("android-arm64-v8a", &["android-arm64-v8a"][..]), + ("android-x86_64", &["android-x86_64"][..]), + ("ios-xcframework", &["ios-device", "ios-simulator"][..]), + ("linux-x64-gnu", &[][..]), + ("linux-arm64-gnu", &[][..]), + ("macos-arm64", &[][..]), + ("windows-x64-msvc", &[][..]), + ] { + let artifact = temp.join(format!("pgcrypto-construction-{target}")); + write_profiled_extension_artifact( + &artifact, + "pgcrypto", + "pgcrypto", + target, + NativeExtensionArtifactLicenseProfile::ContribNativeOpenSsl, + &EXTENSION_ARTIFACT_OPENSSL_CONSTRUCTION_LICENSES, + ); + if !static_targets.is_empty() { + let mut archives = Vec::new(); + let mut dependencies = Vec::new(); + for static_target in static_targets { + let archive = + mobile_static_archive_artifact_relative_path(static_target, "pgcrypto"); + let dependency = mobile_static_dependency_archive_artifact_relative_path( + static_target, + "openssl", + "libcrypto.a", + ); + write_file( + &artifact.join(&archive), + b"fixture pgcrypto static archive\n", + ); + write_file( + &artifact.join(&dependency), + b"fixture OpenSSL static archive\n", + ); + archives.push(format!( + "{static_target}:{}", + archive.display().to_string().replace('\\', "/"), + )); + dependencies.push(format!( + "{static_target}:openssl:{}", + dependency.display().to_string().replace('\\', "/"), + )); + } + let manifest = artifact.join("manifest.properties"); + let text = fs::read_to_string(&manifest) + .unwrap() + .replace("mobilePrebuilt=no\n", "mobilePrebuilt=yes\n") + .replace( + "mobileStaticArchives=\n", + &format!("mobileStaticArchives={}\n", archives.join(",")), + ) + .replace( + "mobileStaticDependencyArchives=\n", + &format!( + "mobileStaticDependencyArchives={}\n", + dependencies.join(",") + ), + ) + .replace( + "staticSymbolPrefix=\n", + "staticSymbolPrefix=oliphaunt_static_pgcrypto\n", + ); + fs::write(manifest, text).unwrap(); + } + let loaded = load_prebuilt_extension_artifact(&artifact).unwrap(); + assert_eq!( + loaded.license_profile, + Some(NativeExtensionArtifactLicenseProfile::ContribNativeOpenSsl) + ); + assert_eq!( + loaded.license_files, + EXTENSION_ARTIFACT_OPENSSL_CONSTRUCTION_LICENSES + .map(PathBuf::from) + .to_vec() + ); + let extensions = [loaded]; + let stems = if static_targets.is_empty() { + Vec::new() + } else { + vec!["pgcrypto".to_owned()] + }; + let metadata = mobile_static_registry_metadata(&extensions, &stems).unwrap(); + let resources = temp.join(format!("resources-{target}")); + let runtime = resources.join("runtime/files"); + copy_prebuilt_extension_artifacts(&runtime, &extensions, Some(target), &metadata) + .unwrap(); + for relative in EXTENSION_ARTIFACT_OPENSSL_CONSTRUCTION_LICENSES { + assert_eq!( + fs::read(runtime.join(relative)).unwrap(), + fs::read(artifact.join("files").join(relative)).unwrap() + ); + } + write_file( + &resources.join("static-registry/manifest.properties"), + b"fixture static registry report marker\n", + ); + let report = + runtime_resource_size_report(&resources, &extensions, Some(target), &metadata) + .unwrap(); + assert_eq!( + report.extensions[0].file_count, + if static_targets.is_empty() { 5 } else { 4 } + ); + } + let postgis = temp.join("postgis"); let postgis_licenses = [ "share/licenses/geos/COPYING", @@ -2602,6 +2953,7 @@ CREATE FUNCTION sql_only(integer) RETURNS integer &postgis_licenses, ); let loaded = load_prebuilt_extension_artifact(&postgis).unwrap(); + assert!(loaded.native_dependency_module_files.is_empty()); assert_eq!( loaded.license_profile, Some(NativeExtensionArtifactLicenseProfile::ExternalNative) @@ -2614,6 +2966,306 @@ CREATE FUNCTION sql_only(integer) RETURNS integer let _ = fs::remove_dir_all(temp); } + #[test] + fn canonical_native_dependency_modules_preserve_profiles_and_runtime_accounting() { + let temp = unique_temp_root("canonical-native-dependency-modules"); + let canonical = Extension::POSTGIS; + let stem = canonical.native_module_stem().unwrap(); + assert!(!canonical.native_dependency_module_stems().is_empty()); + let fixture = |root: &Path, target: &str, suffix: &str, slices: &[&str]| { + write_profiled_extension_artifact( + root, + canonical.sql_name(), + stem, + target, + NativeExtensionArtifactLicenseProfile::ExternalNative, + &["share/licenses/postgis/COPYING"], + ); + let module = format!("{stem}.{suffix}"); + if suffix != "so" { + for profile in ["postgresql", "modules"] { + fs::rename( + root.join(format!("files/lib/{profile}/{stem}.so")), + root.join(format!("files/lib/{profile}/{module}")), + ) + .unwrap(); + } + } + let mut text = fs::read_to_string(root.join("manifest.properties")) + .unwrap() + .replace( + &format!("nativeModuleFile={stem}.so\n"), + &format!("nativeModuleFile={module}\n"), + ); + if !slices.is_empty() { + fs::remove_dir_all(root.join("files/lib/modules")).unwrap(); + let archives = slices + .iter() + .map(|target| { + let file = mobile_static_archive_artifact_relative_path(target, stem); + write_file(&root.join(&file), b"fixture static extension archive\n"); + format!("{target}:{}", file.display().to_string().replace('\\', "/")) + }) + .collect::>(); + text = text + .replace("mobilePrebuilt=no\n", "mobilePrebuilt=yes\n") + .replace( + "mobileStaticArchives=\n", + &format!("mobileStaticArchives={}\n", archives.join(",")), + ) + .replace( + "staticSymbolPrefix=\n", + "staticSymbolPrefix=oliphaunt_static_postgis_3\n", + ); + } + fs::write(root.join("manifest.properties"), text).unwrap(); + let modules = canonical + .native_dependency_module_stems() + .iter() + .map(|stem| format!("{stem}.{suffix}")) + .collect::>(); + for module in &modules { + write_file( + &root.join("files/lib/postgresql").join(module), + b"fixture standalone dependency\n", + ); + if slices.is_empty() { + write_file( + &root.join("files/lib/modules").join(module), + b"fixture embedded dependency\n", + ); + } + } + modules + }; + + for (target, suffix, slices) in [ + ("linux-x64-gnu", "so", &[][..]), + ("linux-arm64-gnu", "so", &[][..]), + ("macos-arm64", "dylib", &[][..]), + ("windows-x64-msvc", "dll", &[][..]), + ("android-arm64-v8a", "so", &["android-arm64-v8a"][..]), + ("android-x86_64", "so", &["android-x86_64"][..]), + ( + "ios-xcframework", + "dylib", + &["ios-device", "ios-simulator"][..], + ), + ] { + let artifact = temp.join(target); + let modules = fixture(&artifact, target, suffix, slices); + let loaded = load_prebuilt_extension_artifact(&artifact).unwrap(); + assert_eq!(loaded.native_dependency_module_files, modules); + let extensions = [loaded]; + let registered = if slices.is_empty() { + Vec::new() + } else { + vec![stem.to_owned()] + }; + let registry = mobile_static_registry_metadata(&extensions, ®istered).unwrap(); + let resources = temp.join(format!("resources-{target}")); + let runtime = resources.join("runtime/files"); + let base = temp.join(format!("base-{target}")); + for module in extensions[0].native_module_files() { + write_file( + &base.join("lib/postgresql").join(module), + b"stale base module\n", + ); + } + write_runtime_resource_tree( + &resources, + &MaterializedNativeResources { + runtime_dir: base, + runtime_cache_key: "fixture-runtime".to_owned(), + }, + &extensions, + &[], + &[], + ®istry, + Some(target), + None, + ) + .unwrap(); + for module in &modules { + let output = runtime.join("lib/postgresql").join(module); + if slices.is_empty() { + assert_eq!(fs::read(output).unwrap(), b"fixture embedded dependency\n"); + } else { + assert!( + !output.exists(), + "complete static registry leaked dynamic sidecar" + ); + } + } + let report = + runtime_resource_size_report(&resources, &extensions, Some(target), ®istry) + .unwrap(); + assert_eq!( + report.extensions[0].file_count, + if slices.is_empty() { + 4 + modules.len() + } else { + 3 + } + ); + let mut expected = vec![ + PathBuf::from("share/postgresql/extension/postgis.control"), + PathBuf::from("share/postgresql/extension/postgis--1.0.sql"), + PathBuf::from("share/licenses/postgis/COPYING"), + ]; + if slices.is_empty() { + expected.extend( + extensions[0] + .native_module_files() + .map(|module| PathBuf::from("lib/postgresql").join(module)), + ); + } + let bytes = expected + .iter() + .map(|file| fs::metadata(runtime.join(file)).unwrap().len()) + .sum::(); + assert_eq!(report.extensions[0].bytes, bytes); + } + + for fault in ["missing", "extra", "wrong-suffix", "wrong-main"] { + let artifact = temp.join(format!("negative-{fault}")); + let modules = fixture(&artifact, "linux-x64-gnu", "so", &[]); + let module = &modules[0]; + match fault { + "missing" => { + fs::remove_file(artifact.join("files/lib/modules").join(module)).unwrap() + } + "extra" => write_file( + &artifact.join("files/lib/postgresql/undeclared.so"), + b"undeclared dependency\n", + ), + "wrong-suffix" => { + for profile in ["postgresql", "modules"] { + fs::rename( + artifact.join(format!("files/lib/{profile}/{module}")), + artifact.join(format!( + "files/lib/{profile}/{}.dll", + canonical.native_dependency_module_stems()[0] + )), + ) + .unwrap(); + } + } + _ => { + let manifest = artifact.join("manifest.properties"); + let text = fs::read_to_string(&manifest) + .unwrap() + .replace( + &format!("nativeModuleStem={stem}\n"), + "nativeModuleStem=foreign\n", + ) + .replace( + &format!("nativeModuleFile={stem}.so\n"), + "nativeModuleFile=foreign.so\n", + ); + fs::write(manifest, text).unwrap(); + for profile in ["postgresql", "modules"] { + fs::rename( + artifact.join(format!("files/lib/{profile}/{stem}.so")), + artifact.join(format!("files/lib/{profile}/foreign.so")), + ) + .unwrap(); + } + } + } + let error = load_prebuilt_extension_artifact(&artifact).unwrap_err(); + assert!( + error.to_string().contains("leaf inventory mismatch"), + "{error}" + ); + } + let duplicate = temp.join("duplicate-sidecar"); + let modules = fixture(&duplicate, "linux-x64-gnu", "so", &[]); + let archive = temp.join("duplicate-sidecar.tar"); + let mut writer = tar::Builder::new(File::create(&archive).unwrap()); + writer.append_dir_all("extension", &duplicate).unwrap(); + let member = PathBuf::from("files/lib/modules").join(&modules[0]); + writer + .append_path_with_name( + duplicate.join(&member), + Path::new("extension").join(&member), + ) + .unwrap(); + writer.finish().unwrap(); + let error = + PreparedPrebuiltExtensionArtifacts::prepare(&[NativePrebuiltExtensionArtifact::new( + &archive, + )]) + .unwrap_err(); + assert!(error.to_string().contains("repeats file entry"), "{error}"); + + let other = temp.join("other-member"); + write_profiled_extension_artifact( + &other, + "cube", + "cube", + "linux-x64-gnu", + NativeExtensionArtifactLicenseProfile::ContribNative, + &[], + ); + write_file( + &other.join("files/lib/postgresql").join(format!( + "{}.so", + canonical.native_dependency_module_stems()[0] + )), + b"foreign member dependency\n", + ); + let error = load_prebuilt_extension_artifact(&other).unwrap_err(); + assert!(error.to_string().contains("undeclared:"), "{error}"); + + let built_in = built_in_runtime_resource_extension(canonical); + assert_eq!( + built_in.native_dependency_module_files, + if cfg!(windows) { + Vec::::new() + } else { + canonical + .native_dependency_module_stems() + .iter() + .map(|stem| format!("{stem}{}", std::env::consts::DLL_SUFFIX)) + .collect() + }, + "current Windows construction incorporates dependencies; historical sidecar fixtures above remain valid", + ); + let base = temp.join("built-in-base"); + for module in built_in.native_module_files() { + write_file( + &base.join("lib/postgresql").join(module), + b"built-in module\n", + ); + } + let registry = mobile_static_registry_metadata(&[], &[]).unwrap(); + let resources = temp.join("built-in-prune"); + write_runtime_resource_tree( + &resources, + &MaterializedNativeResources { + runtime_dir: base, + runtime_cache_key: "fixture-runtime".to_owned(), + }, + &[], + &[], + &[], + ®istry, + None, + None, + ) + .unwrap(); + for module in built_in.native_module_files() { + assert!( + !resources + .join("runtime/files/lib/postgresql") + .join(module) + .exists() + ); + } + let _ = fs::remove_dir_all(temp); + } + #[test] fn prebuilt_extension_rejects_missing_extra_unsafe_and_wrong_profile_legal_files() { let temp = unique_temp_root("oliphaunt-extension-legal-adversarial"); @@ -2701,6 +3353,90 @@ CREATE FUNCTION sql_only(integer) RETURNS integer "unexpected wrong legal profile error: {error}" ); + for (case, sql_name, target, profile, license_files, error_text) in [ + ( + "partial-construction", + "pgcrypto", + "macos-arm64", + NativeExtensionArtifactLicenseProfile::ContribNativeOpenSsl, + vec![EXTENSION_ARTIFACT_OPENSSL_CONSTRUCTION_LICENSES[0]], + "must not declare upstream licenseFiles", + ), + ( + "extra-construction", + "pgcrypto", + "macos-arm64", + NativeExtensionArtifactLicenseProfile::ContribNativeOpenSsl, + vec![ + EXTENSION_ARTIFACT_OPENSSL_CONSTRUCTION_LICENSES[0], + EXTENSION_ARTIFACT_OPENSSL_CONSTRUCTION_LICENSES[1], + "share/licenses/unrelated/LICENSE", + ], + "must not declare upstream licenseFiles", + ), + ( + "wrong-construction-member", + "cube", + "linux-x64-gnu", + NativeExtensionArtifactLicenseProfile::ContribNative, + EXTENSION_ARTIFACT_OPENSSL_CONSTRUCTION_LICENSES.to_vec(), + "must not declare upstream licenseFiles", + ), + ( + "wrong-construction-target", + "pgcrypto", + "foreign-target", + NativeExtensionArtifactLicenseProfile::ContribNativeOpenSsl, + EXTENSION_ARTIFACT_OPENSSL_CONSTRUCTION_LICENSES.to_vec(), + "expected 'contrib-native'", + ), + ( + "wrong-construction-profile", + "pgcrypto", + "linux-x64-gnu", + NativeExtensionArtifactLicenseProfile::ContribNative, + EXTENSION_ARTIFACT_OPENSSL_CONSTRUCTION_LICENSES.to_vec(), + "expected 'contrib-native-openssl'", + ), + ] { + let artifact = temp.join(case); + write_profiled_extension_artifact( + &artifact, + sql_name, + sql_name, + target, + profile, + &license_files, + ); + let error = load_prebuilt_extension_artifact(&artifact).unwrap_err(); + assert!( + error.to_string().contains(error_text), + "unexpected {case} error: {error}" + ); + } + let construction = temp.join("missing-construction-file"); + write_profiled_extension_artifact( + &construction, + "pgcrypto", + "pgcrypto", + "macos-arm64", + NativeExtensionArtifactLicenseProfile::ContribNativeOpenSsl, + &EXTENSION_ARTIFACT_OPENSSL_CONSTRUCTION_LICENSES, + ); + fs::remove_file( + construction + .join("files") + .join(EXTENSION_ARTIFACT_OPENSSL_CONSTRUCTION_LICENSES[1]), + ) + .unwrap(); + let error = load_prebuilt_extension_artifact(&construction).unwrap_err(); + assert!( + error + .to_string() + .contains("missing: files/share/licenses/openssl-native/SOURCE.toml"), + "unexpected missing construction file error: {error}" + ); + let _ = fs::remove_dir_all(temp); } @@ -2725,6 +3461,38 @@ CREATE FUNCTION sql_only(integer) RETURNS integer error.to_string().contains("LICENSE must have mode 0644"), "unexpected legal mode error: {error}" ); + let construction = temp.join("pgcrypto-construction-mode"); + write_profiled_extension_artifact( + &construction, + "pgcrypto", + "pgcrypto", + "macos-arm64", + NativeExtensionArtifactLicenseProfile::ContribNativeOpenSsl, + &EXTENSION_ARTIFACT_OPENSSL_CONSTRUCTION_LICENSES, + ); + let license = construction + .join("files") + .join(EXTENSION_ARTIFACT_OPENSSL_CONSTRUCTION_LICENSES[0]); + fs::set_permissions(&license, fs::Permissions::from_mode(0o600)).unwrap(); + let error = load_prebuilt_extension_artifact(&construction).unwrap_err(); + assert!( + error + .to_string() + .contains("share/licenses/openssl-native/LICENSE.txt must have mode 0644"), + "unexpected construction license mode error: {error}" + ); + fs::remove_file(&license).unwrap(); + std::os::unix::fs::symlink( + construction.join(EXTENSION_ARTIFACT_OPENSSL_LICENSE), + &license, + ) + .unwrap(); + let error = load_prebuilt_extension_artifact(&construction).unwrap_err(); + assert!( + error.to_string().contains("contains unsafe symlink"), + "unexpected construction license symlink error: {error}" + ); + let _ = fs::remove_dir_all(temp); } diff --git a/src/native/runtime/packaging/src/package.rs b/src/native/runtime/packaging/src/package.rs index 806580f94..f00ab4d1f 100644 --- a/src/native/runtime/packaging/src/package.rs +++ b/src/native/runtime/packaging/src/package.rs @@ -25,10 +25,19 @@ pub(super) fn write_runtime_resource_tree( shared_preload_libraries: &[String], mobile_static_registry: &MobileStaticRegistryMetadata, extension_target: Option<&str>, -) -> Result<()> { + runtime_cache_identity: Option<&str>, +) -> Result { let runtime_package = root.join("runtime"); let runtime_files = runtime_package.join("files"); - copy_portable_tree(&materialized.runtime_dir, &runtime_files)?; + // These two files validate the SDK's private acquisition cache. Public + // resource loaders use runtime/manifest.properties and create their own + // cache stamps; explicit content identities must not embed the private key. + let excluded = if runtime_cache_identity.is_some() { + &[".manifest", ".complete"][..] + } else { + &[][..] + }; + copy_portable_tree_excluding(&materialized.runtime_dir, &runtime_files, excluded)?; let icu_data_tree_sha256 = if runtime_features.contains(&NativeRuntimeFeature::Icu) { logical_tree_sha256(&runtime_files.join("share/icu"))? } else { @@ -49,10 +58,14 @@ pub(super) fn write_runtime_resource_tree( extension_target, mobile_static_registry, )?; - write_manifest( + let runtime_cache_key = write_manifest( &runtime_package, &RuntimeResourceManifest { - cache_key: &materialized.runtime_cache_key, + cache_key: if runtime_cache_identity.is_some() { + "" + } else { + &materialized.runtime_cache_key + }, layout: RUNTIME_FILES_LAYOUT, artifact_role: "runtime", catalog_profile: "", @@ -63,10 +76,11 @@ pub(super) fn write_runtime_resource_tree( shared_preload_libraries, mobile_static_registry, }, + runtime_cache_identity, )?; write_static_registry_package(root, &runtime_files, extensions, mobile_static_registry)?; - Ok(()) + Ok(runtime_cache_key) } fn remove_unselected_icu_data(runtime_files: &Path) -> Result<()> { @@ -167,27 +181,26 @@ fn prune_built_in_extension_module_files( ) -> Result<()> { let mut selected_modules = BTreeSet::new(); for extension in selected_built_in { - if extension_dynamic_module_required(extension, extension_target, mobile_static_registry)? - && let Some(module) = &extension.native_module_file - { - selected_modules.insert(module.clone()); + if extension_dynamic_module_required(extension, extension_target, mobile_static_registry)? { + selected_modules.extend(extension.native_module_files().map(str::to_owned)); } } for extension in Extension::ALL { - let Some(stem) = catalog::for_extension(*extension) - .native_module_stem - .as_deref() - else { - continue; - }; - let module = format!("{stem}{}", std::env::consts::DLL_SUFFIX); - if selected_modules.contains(&module) { - continue; + let modules = extension.native_module_file().into_iter().chain( + extension + .native_dependency_module_stems() + .iter() + .map(|stem| format!("{stem}{}", std::env::consts::DLL_SUFFIX)), + ); + for module in modules { + if selected_modules.contains(&module) { + continue; + } + remove_runtime_file_if_present( + runtime_files, + &PathBuf::from("lib/postgresql").join(module), + )?; } - remove_runtime_file_if_present( - runtime_files, - &PathBuf::from("lib/postgresql").join(module), - )?; } Ok(()) } @@ -221,7 +234,7 @@ fn prune_prebuilt_extension_base_artifact_paths( &PathBuf::from("share/postgresql").join(relative), )?; } - if let Some(module) = &extension.native_module_file { + for module in extension.native_module_files() { remove_runtime_file_if_present( runtime_files, &PathBuf::from("lib/postgresql").join(module), @@ -259,15 +272,14 @@ pub(super) fn copy_prebuilt_extension_artifacts( extension_target, mobile_static_registry, )? { - let Some(module) = &extension.native_module_file else { - continue; - }; - copy_artifact_runtime_file_to( - files_root, - runtime_files, - &PathBuf::from("lib/modules").join(module), - &PathBuf::from("lib/postgresql").join(module), - )?; + for module in extension.native_module_files() { + copy_artifact_runtime_file_to( + files_root, + runtime_files, + &PathBuf::from("lib/modules").join(module), + &PathBuf::from("lib/postgresql").join(module), + )?; + } } } Ok(()) @@ -471,12 +483,11 @@ fn extension_asset_paths( paths.insert(relative.clone()); } if extension_dynamic_module_required(extension, extension_target, mobile_static_registry)? { - let Some(module) = &extension.native_module_file else { - continue; - }; - let relative = PathBuf::from("lib/postgresql").join(module); - require_report_file(runtime_files, &relative)?; - paths.insert(relative); + for module in extension.native_module_files() { + let relative = PathBuf::from("lib/postgresql").join(module); + require_report_file(runtime_files, &relative)?; + paths.insert(relative); + } } } Ok(paths) @@ -623,19 +634,33 @@ pub(super) struct RuntimeResourceManifest<'a> { pub(super) mobile_static_registry: &'a MobileStaticRegistryMetadata, } -fn write_manifest(package_dir: &Path, manifest: &RuntimeResourceManifest<'_>) -> Result<()> { +fn write_manifest( + package_dir: &Path, + manifest: &RuntimeResourceManifest<'_>, + runtime_cache_identity: Option<&str>, +) -> Result { + let mut text = manifest_text(manifest); + let cache_key = if let Some(identity) = runtime_cache_identity { + let mut digest = Sha256::new(); + for field in [identity.as_bytes(), text.as_bytes()] { + digest.update((field.len() as u64).to_be_bytes()); + digest.update(field); + } + let key = format!("runtime-{:x}", digest.finalize()); + text = text.replacen("\ncacheKey=\n", &format!("\ncacheKey={key}\n"), 1); + key + } else { + manifest.cache_key.to_owned() + }; fs::create_dir_all(package_dir) .map_err(|err| Error::Engine(format!("create {}: {err}", package_dir.display())))?; - fs::write( - package_dir.join("manifest.properties"), - manifest_text(manifest), - ) - .map_err(|err| { + fs::write(package_dir.join("manifest.properties"), text).map_err(|err| { Error::Engine(format!( "write native resource manifest {}: {err}", package_dir.join("manifest.properties").display() )) - }) + })?; + Ok(cache_key) } pub(super) fn manifest_text(manifest: &RuntimeResourceManifest<'_>) -> String { @@ -732,6 +757,14 @@ pub(super) fn logical_tree_sha256_files(mut files: Vec<(String, PathBuf)>) -> Re } pub(super) fn copy_portable_tree(source: &Path, destination: &Path) -> Result<()> { + copy_portable_tree_excluding(source, destination, &[]) +} + +fn copy_portable_tree_excluding( + source: &Path, + destination: &Path, + excluded: &[&str], +) -> Result<()> { let metadata = fs::symlink_metadata(source) .map_err(|err| Error::Engine(format!("stat {}: {err}", source.display())))?; let file_type = metadata.file_type(); @@ -772,6 +805,17 @@ pub(super) fn copy_portable_tree(source: &Path, destination: &Path) -> Result<() })?; entries.sort_by_key(|entry| entry.file_name()); for entry in entries { + if excluded.iter().any(|name| entry.file_name() == *name) { + let metadata = fs::symlink_metadata(entry.path()) + .map_err(|err| Error::Engine(format!("stat {}: {err}", entry.path().display())))?; + if !metadata.is_file() { + return Err(Error::Engine(format!( + "private acquisition marker must be a regular file: {}", + entry.path().display() + ))); + } + continue; + } copy_portable_tree(&entry.path(), &destination.join(entry.file_name()))?; } Ok(()) diff --git a/src/native/runtime/patches/postgresql-18.4/0022-liboliphaunt-match-msvc-variadic-preprocessor.patch b/src/native/runtime/patches/postgresql-18.4/0022-liboliphaunt-match-msvc-variadic-preprocessor.patch new file mode 100644 index 000000000..48d996a03 --- /dev/null +++ b/src/native/runtime/patches/postgresql-18.4/0022-liboliphaunt-match-msvc-variadic-preprocessor.patch @@ -0,0 +1,10 @@ +--- a/src/include/c.h ++++ b/src/include/c.h +@@ -392,6 +392,6 @@ + * definition that also works on older compilers. + */ +-#ifdef _MSC_VER ++#if defined(_MSC_VER) && (!defined(_MSVC_TRADITIONAL) || _MSVC_TRADITIONAL) + #define EXPAND(args) args + #define VA_ARGS_NARGS(...) \ + VA_ARGS_NARGS_ EXPAND((__VA_ARGS__, \ diff --git a/src/native/runtime/postgres/series b/src/native/runtime/postgres/series index 6b96afc4a..226cf1290 100644 --- a/src/native/runtime/postgres/series +++ b/src/native/runtime/postgres/series @@ -20,3 +20,4 @@ src/native/runtime/patches/postgresql-18.4/0018-liboliphaunt-contain-embedded-pr src/native/runtime/patches/postgresql-18.4/0019-liboliphaunt-link-windows-embedded-modules-to-host.patch src/native/runtime/patches/postgresql-18.4/0020-liboliphaunt-enforce-embedded-signal-boundary.patch src/native/runtime/patches/postgresql-18.4/0021-liboliphaunt-wake-embedded-epoll-through-self-pipe.patch +src/native/runtime/patches/postgresql-18.4/0022-liboliphaunt-match-msvc-variadic-preprocessor.patch diff --git a/src/native/runtime/release.toml b/src/native/runtime/release.toml index 963653a11..63f5beea0 100644 --- a/src/native/runtime/release.toml +++ b/src/native/runtime/release.toml @@ -27,3 +27,15 @@ release_artifacts = [ "runtime-resources-android-datum64", "icu-data", ] + +[artifact_targets] +preset = "liboliphaunt-native" +targets = [ + "android-arm64-v8a", + "android-x86_64", + "ios-xcframework", + "linux-arm64-gnu", + "linux-x64-gnu", + "macos-arm64", + "windows-x64-msvc", +] diff --git a/src/native/runtime/smoke/liboliphaunt_smoke.c b/src/native/runtime/smoke/liboliphaunt_smoke.c index e47868b88..de7a2f5f9 100644 --- a/src/native/runtime/smoke/liboliphaunt_smoke.c +++ b/src/native/runtime/smoke/liboliphaunt_smoke.c @@ -37,6 +37,12 @@ #include #endif +/* Syscache KEY initializers require constant, exact variadic key counts. */ +StaticAssertDecl(VA_ARGS_NARGS(1) == 1, "one syscache key"); +StaticAssertDecl(VA_ARGS_NARGS(1, 2) == 2, "two syscache keys"); +StaticAssertDecl(VA_ARGS_NARGS(1, 2, 3) == 3, "three syscache keys"); +StaticAssertDecl(VA_ARGS_NARGS(1, 2, 3, 4) == 4, "four syscache keys"); + #undef PG_MAGIC_FUNCTION_NAME #define PG_MAGIC_FUNCTION_NAME liboliphaunt_smoke_static_magic PG_MODULE_MAGIC_EXT( @@ -1454,6 +1460,12 @@ static int parent_path(const char *path, char *out, size_t out_len) { return -1; } char *slash = strrchr(out, '/'); +#ifdef _WIN32 + char *backslash = strrchr(out, '\\'); + if (backslash != NULL && (slash == NULL || backslash > slash)) { + slash = backslash; + } +#endif if (slash == NULL) { return snprintf(out, out_len, ".") >= (int)out_len ? -1 : 0; } @@ -1461,6 +1473,12 @@ static int parent_path(const char *path, char *out, size_t out_len) { slash[1] = '\0'; return 0; } +#ifdef _WIN32 + if (slash == out + 2 && out[1] == ':') { + slash[1] = '\0'; + return 0; + } +#endif *slash = '\0'; return 0; } diff --git a/src/native/runtime/tools/native-mobile-abi-contract.mts b/src/native/runtime/tools/native-mobile-abi-contract.mts index 60ec4c163..7a82d25b3 100644 --- a/src/native/runtime/tools/native-mobile-abi-contract.mts +++ b/src/native/runtime/tools/native-mobile-abi-contract.mts @@ -47,8 +47,13 @@ function defineValue(text, name, label) { return match[1].replace(/^\((.*)\)$/u, '$1'); } -function integerDefine(text, name, label) { - const raw = defineValue(text, name, label).replace(/[uUlL]+$/u, ''); +function integerDefine(text, name, label, aliases = []) { + if (aliases.includes(name)) + fail(`${label} has cyclic integer aliases ${[...aliases, name].join(' -> ')}`); + const token = defineValue(text, name, label); + if (/^[A-Za-z_][A-Za-z0-9_]*$/u.test(token)) + return integerDefine(text, token, label, [...aliases, name]); + const raw = token.replace(/[uUlL]+$/u, ''); if (!/^(?:0[xX][0-9a-fA-F]+|[0-9]+)$/u.test(raw)) { fail(`${label} has invalid ${name}=${raw}`); } diff --git a/src/native/runtime/tools/native-mobile-abi-contract.test.mts b/src/native/runtime/tools/native-mobile-abi-contract.test.mts index 690e1b195..68c8d5cae 100644 --- a/src/native/runtime/tools/native-mobile-abi-contract.test.mts +++ b/src/native/runtime/tools/native-mobile-abi-contract.test.mts @@ -18,6 +18,7 @@ function fixture(target, overrides = {}) { [ `#define SIZEOF_VOID_P ${overrides.pointerBytes ?? 8}`, `#define MAXIMUM_ALIGNOF ${overrides.alignment ?? 8}`, + ...(overrides.extraDefines ?? []), '#define BLCKSZ 8192', '#define XLOG_BLCKSZ 8192', '#define RELSEG_SIZE 131072', @@ -83,6 +84,26 @@ test('rejects non-Datum64 producer headers', () => { ); }); +test('resolves integer aliases from the actual header and rejects unresolved, cyclic or expression aliases', () => { + const receipt = fixture('linux-x64-gnu', { + alignment: '(ALIGNOF_DOUBLE)', + extraDefines: ['#define ALIGNOF_DOUBLE ALIGNMENT_BYTES', '#define ALIGNMENT_BYTES 0x8UL'], + }); + expect(parseNativeMobileAbiReceipt(receipt.text).get('maximumAlignof')).toBe('8'); + expect(() => fixture('linux-x64-gnu', { alignment: 'ABSENT_ALIGNMENT' })).toThrow( + /does not define ABSENT_ALIGNMENT/u, + ); + expect(() => + fixture('linux-x64-gnu', { + alignment: 'ALIGNOF_DOUBLE', + extraDefines: ['#define ALIGNOF_DOUBLE MAXIMUM_ALIGNOF'], + }), + ).toThrow(/cyclic integer aliases/u); + expect(() => fixture('linux-x64-gnu', { alignment: '(4+4)' })).toThrow( + /invalid MAXIMUM_ALIGNOF/u, + ); +}); + test('rejects malformed or internally inconsistent receipts', () => { const valid = fixture('android-x86_64').text; expect(() => diff --git a/src/native/runtime/tools/native-readiness-probes.test.sh b/src/native/runtime/tools/native-readiness-probes.test.sh index df0bfdd78..e83283072 100644 --- a/src/native/runtime/tools/native-readiness-probes.test.sh +++ b/src/native/runtime/tools/native-readiness-probes.test.sh @@ -64,3 +64,82 @@ excerpt="$(oliphaunt_tail_log_excerpt "$log" 10 200)" printf '%s\n' "$excerpt" | awk 'length($0) > 221 { exit 1 }' printf "native symbol, target, and bounded-log probes passed\n" + +source_enumeration_work="$(mktemp -d)" +trap 'rm -f "$log"; rm -rf "$source_enumeration_work"' EXIT +for caller in build-macos-extension-archives.sh build-postgres18-ios-device.sh build-postgres18-ios-simulator.sh build-postgres18-android-arm64.sh; do + for mode in failure intermediate_failure success; do + case_dir="$source_enumeration_work/$caller-$mode" + mkdir -p "$case_dir/source" + : > "$case_dir/source/createas.c" + : > "$case_dir/source/pg_ivm.c" + if "$BASH" -s -- "$root" "$caller" "$case_dir" "$mode" > "$case_dir/output.log" 2>&1 <<'SH' +set -euo pipefail +root="$1" +caller="$2" +case_dir="$3" +mode="$4" +. "$root/src/native/runtime/bin/mobile-static-extensions.sh" +case "$caller" in + build-macos-extension-archives.sh) build_function=build_static_extension_objects ;; + *) build_function=build_mobile_static_extension_objects ;; +esac +eval "$(awk -v name="$build_function" '$0 == name "() {" { printing=1 } printing { print } printing && /^\}/ { exit }' "$root/src/native/runtime/bin/$caller")" +fail() { exit 1; } +oliphaunt_mobile_static_extension_module_stem() { printf 'fixture\n'; } +oliphaunt_mobile_static_extension_source_dir() { printf '%s\n' "$case_dir/source"; } +oliphaunt_mobile_static_extension_include_dirs() { :; } +oliphaunt_mobile_static_extension_cflags() { :; } +oliphaunt_mobile_static_extension_kind() { printf 'external\n'; } +oliphaunt_mobile_static_extension_source_files() { + printf '%s\n' "$case_dir/source/createas.c" + [ "$mode" != failure ] || return 37 + if [ "$mode" = intermediate_failure ]; then false; fi + printf '%s\n' "$case_dir/source/pg_ivm.c" +} +compile_spy() { + local previous='' source='' object='' argument + for argument in "$@"; do + case "$previous" in -c) source="$argument" ;; -o) object="$argument" ;; esac + previous="$argument" + done + printf '%s\n' "$source" >> "$case_dir/compiled.list" + printf '%s\n' "$@" > "$case_dir/$(basename "$source").args" + : > "$object" +} +archive_mobile_static_extension_objects() { : > "$case_dir/archive.called"; } +repo_root="$root" +build_dir="$case_dir/build" +out_dir="$case_dir/out" +mobile_static_extensions=(fixture) +mobile_static_objects=() +cc=(compile_spy) +pg_extension_cflags='-O2 -DOLIPHAUNT_EMBEDDED' +pg_extension_cflag_args=(-O2 -DOLIPHAUNT_EMBEDDED) +"$build_function" +SH + then + status=0 + else + status=$? + fi + if [ "$mode" != success ]; then + expected_status=37 + [ "$mode" != intermediate_failure ] || expected_status=1 + if [ "$status" -ne "$expected_status" ] || [ -e "$case_dir/compiled.list" ] || [ -e "$case_dir/archive.called" ]; then + echo "$caller compiled or archived a partial source enumeration" >&2 + exit 1 + fi + else + [ "$status" -eq 0 ] || { echo "$caller rejected complete source enumeration" >&2; exit 1; } + printf '%s\n' "$case_dir/source/createas.c" "$case_dir/source/pg_ivm.c" > "$case_dir/expected.list" + cmp -s "$case_dir/compiled.list" "$case_dir/expected.list" + [ -e "$case_dir/archive.called" ] + for source in createas.c pg_ivm.c; do + grep -F -x -- '-DPg_magic_func=oliphaunt_static_fixture_Pg_magic_func' "$case_dir/$source.args" >/dev/null + grep -F -x -- '-D_PG_init=oliphaunt_static_fixture__PG_init' "$case_dir/$source.args" >/dev/null + done + fi + done +done +printf 'checked static extension source enumeration passed\n' diff --git a/src/native/runtime/tools/package-liboliphaunt-cargo-artifacts.test.mts b/src/native/runtime/tools/package-liboliphaunt-cargo-artifacts.test.mts index 6b6c2e605..d5e853375 100644 --- a/src/native/runtime/tools/package-liboliphaunt-cargo-artifacts.test.mts +++ b/src/native/runtime/tools/package-liboliphaunt-cargo-artifacts.test.mts @@ -187,12 +187,13 @@ test('freezes deterministic .crate bytes and prepares an extracted native consum path.resolve(ROOT, packedAggregator.cratePath), `${packedAggregator.name}-9.8.7/Cargo.toml`, ); - assert.doesNotMatch(packedManifest, /oliphaunt-package-deps|registry\s*=/u); - assert.doesNotMatch( - packedManifest, - /\[build-dependencies[.]liboliphaunt-native-linux-x64-gnu-part-001\][\s\S]*?path\s*=/u, + assert.doesNotMatch(packedManifest, /oliphaunt-package-deps/u); + assert.deepEqual( + Bun.TOML.parse(packedManifest)['build-dependencies'][ + 'liboliphaunt-native-linux-x64-gnu-part-001' + ], + { version: '=9.8.7' }, ); - assert.match(packedManifest, /version\s*=\s*"=9[.]8[.]7"/u); const facade = manifest.packages.find(({ role }) => role === 'facade'); assert.ok(facade); diff --git a/src/native/rust-bindings/BUILD.bazel b/src/native/rust-bindings/BUILD.bazel new file mode 100644 index 000000000..8654ace07 --- /dev/null +++ b/src/native/rust-bindings/BUILD.bazel @@ -0,0 +1,50 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files") +load("//build_defs/languages:rust.bzl", "cargo_integration_test", "cargo_library", "cargo_library_test", "cargo_package_env") +load("@rules_rust//rust:defs.bzl", "rust_clippy_test") +load("//build_defs/languages:source.bzl", "cargo_source_package") +load("//build_defs/extensions:platforms.bzl", "NATIVE_EXTENSION_COMPATIBLE", "NATIVE_EXTENSION_CONFIGURATION") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") +load("//build_defs/release:supplier.bzl", "shipping_suppliers") + +package(default_visibility = ["//visibility:public"]) +exports_files(["Cargo.toml"]) + +cargo_package_env() +cargo_library() +cargo_library(name = "packaging_lib", features = ["internal-native-packaging"]) +cargo_library_test(data = ["//src/test-fixtures:rust_fixtures"], isolated_cache = True) +_INTEGRATION_ROOTS = glob(["tests/*.rs"]) +[ + cargo_integration_test(name = source.removeprefix("tests/").removesuffix(".rs") + "_test", source = source, tags = ["manual"]) + for source in _INTEGRATION_ROOTS +] +rust_clippy_test( + name = "clippy_test", + targets = [":lib", ":unit_test_binary"] + [":" + source.removeprefix("tests/").removesuffix(".rs") + "_test" for source in _INTEGRATION_ROOTS], + transitive = False, + size = "small", +) +cargo_source_package(product = "liboliphaunt-native-bindings", fixtures = "testdata/", qualification = ["//build_defs/languages/installed:consumer_test"]) + +# This is the existing compiler output incorporated by desktop helpers, not a public carrier. +shipping_suppliers(name = "compiled_suppliers", inputs = []) +shipping_package( + name = "compiled_shipping", + owner = "@oliphaunt_metadata//:product_liboliphaunt-native-bindings", + artifacts = [":lib"], + ecosystem = "internal", + package_name = "liboliphaunt-native-bindings", + configuration = NATIVE_EXTENSION_CONFIGURATION, + role = "compiled-source", + suppliers = ":compiled_suppliers", + target_compatible_with = NATIVE_EXTENSION_COMPATIBLE, +) +shipping_export( + name = "compiled_shipping_export", + packages = [":compiled_shipping"], + qualification = [":unit_test"], + testonly = True, + target_compatible_with = NATIVE_EXTENSION_COMPATIBLE, +) + +rust_quality_files() diff --git a/src/native/rust-bindings/Cargo.toml b/src/native/rust-bindings/Cargo.toml index f9c8343cd..44cbedde3 100644 --- a/src/native/rust-bindings/Cargo.toml +++ b/src/native/rust-bindings/Cargo.toml @@ -8,7 +8,7 @@ homepage.workspace = true license.workspace = true description = "Rust bindings and database resource management for native liboliphaunt." readme = "README.md" -exclude = ["moon.yml", "release.toml", "tools/**"] +exclude = ["BUILD.bazel", "moon.yml", "release.toml", "tools/**"] [features] internal-native-packaging = [] [dependencies] diff --git a/src/native/rust-bindings/README.md b/src/native/rust-bindings/README.md index 206c5d50f..bab42359d 100644 --- a/src/native/rust-bindings/README.md +++ b/src/native/rust-bindings/README.md @@ -49,6 +49,6 @@ Run these commands from this directory with the repository-pinned Rust toolchain | `moon run liboliphaunt-native-bindings:test` | Run source tests; Cargo compiles the required test targets. | | `moon run liboliphaunt-native-bindings:package` | Stage distributable source crates under target/sdk-artifacts/liboliphaunt-native-bindings; repeated runs replace this owner’s candidates. | -Native Cargo entry points remain available: `cargo build -p liboliphaunt-native-bindings --locked`, `cargo test -p liboliphaunt-native-bindings --locked`, `cargo clippy -p liboliphaunt-native-bindings --all-targets --locked -- -D warnings`, and `cargo fmt -p liboliphaunt-native-bindings --check`. Moon supplies the additional source-test feature matrix and artifact staging where defined. `package` assembles bytes; it does not run the project test suite. +Native Cargo entry points from this directory remain available: `cargo build --locked`, `cargo test --locked`, `cargo clippy --all-targets --locked -- -D warnings`, and `cargo fmt --check`. Moon supplies the additional source-test feature matrix and artifact staging where defined. `package` assembles bytes; it does not run the project test suite. The native SDK’s `moon run oliphaunt-rust:test-consumer` installs the real packed query, bindings and broker crates together with the SDK. This tests their public dependency closure without duplicate per-crate consumer harnesses. diff --git a/src/native/rust-bindings/src/extension.rs b/src/native/rust-bindings/src/extension.rs index fa4ac3196..f2c65df66 100644 --- a/src/native/rust-bindings/src/extension.rs +++ b/src/native/rust-bindings/src/extension.rs @@ -42,6 +42,31 @@ impl Extension { .map(|stem| format!("{}{}", stem, std::env::consts::DLL_SUFFIX)) } + /// Canonical dependency modules consumed by unpublished native packaging. + #[cfg(feature = "internal-native-packaging")] + #[doc(hidden)] + pub const fn native_dependency_module_stems(self) -> &'static [&'static str] { + generated_extensions::native_dependency_module_stems(self) + } + + /// Current host construction; historical carriers retain their physical inventory. + #[cfg(feature = "internal-native-packaging")] + #[doc(hidden)] + pub const fn native_dependency_module_stems_for_host(self) -> &'static [&'static str] { + generated_extensions::native_dependency_module_stems_for_host(self) + } + + pub(crate) fn native_module_files(self) -> impl Iterator { + self.native_module_stem() + .into_iter() + .chain( + generated_extensions::native_dependency_module_stems(self) + .iter() + .copied(), + ) + .map(|stem| format!("{}{}", stem, std::env::consts::DLL_SUFFIX)) + } + pub const fn creates_extension(self) -> bool { generated_extensions::creates_extension(self) } diff --git a/src/native/rust-bindings/src/generated/extensions.rs b/src/native/rust-bindings/src/generated/extensions.rs index 711cff99a..777c02eae 100644 --- a/src/native/rust-bindings/src/generated/extensions.rs +++ b/src/native/rust-bindings/src/generated/extensions.rs @@ -468,6 +468,67 @@ pub(super) const fn native_module_stem(extension: Extension) -> Option<&'static } } +/// Generated extension metadata accessor. +pub(super) const fn native_dependency_module_stems( + extension: Extension, +) -> &'static [&'static str] { + match extension.id { + ExtensionId::Amcheck => &[], + ExtensionId::AutoExplain => &[], + ExtensionId::Bloom => &[], + ExtensionId::BtreeGin => &[], + ExtensionId::BtreeGist => &[], + ExtensionId::Citext => &[], + ExtensionId::Cube => &[], + ExtensionId::DictInt => &[], + ExtensionId::DictXsyn => &[], + ExtensionId::Earthdistance => &[], + ExtensionId::FileFdw => &[], + ExtensionId::Fuzzystrmatch => &[], + ExtensionId::Hstore => &[], + ExtensionId::Intarray => &[], + ExtensionId::Isn => &[], + ExtensionId::Lo => &[], + ExtensionId::Ltree => &[], + ExtensionId::Pageinspect => &[], + ExtensionId::PgBuffercache => &[], + ExtensionId::PgFreespacemap => &[], + ExtensionId::PgHashids => &[], + ExtensionId::PgIvm => &[], + ExtensionId::PgSurgery => &[], + ExtensionId::PgTextsearch => &[], + ExtensionId::PgTrgm => &[], + ExtensionId::PgUuidv7 => &[], + ExtensionId::PgVisibility => &[], + ExtensionId::PgWalinspect => &[], + ExtensionId::Pgcrypto => &[], + ExtensionId::Pgtap => &[], + ExtensionId::Postgis => &["liboliphaunt_postgis_deps"], + ExtensionId::Seg => &[], + ExtensionId::Tablefunc => &[], + ExtensionId::Tcn => &[], + ExtensionId::TsmSystemRows => &[], + ExtensionId::TsmSystemTime => &[], + ExtensionId::Unaccent => &[], + ExtensionId::UuidOssp => &[], + ExtensionId::Vector => &[], + } +} + +/// Current host dependency modules; frozen inputs retain their own inventory. +#[cfg(feature = "internal-native-packaging")] +pub(super) const fn native_dependency_module_stems_for_host( + extension: Extension, +) -> &'static [&'static str] { + if cfg!(all(target_os = "windows", target_arch = "x86_64")) { + return match extension.id { + ExtensionId::Postgis => &[], + _ => native_dependency_module_stems(extension), + }; + } + native_dependency_module_stems(extension) +} + /// Generated extension metadata accessor. pub(super) const fn creates_extension(extension: Extension) -> bool { match extension.id { diff --git a/src/native/rust-bindings/src/liboliphaunt/root/cluster_seed.rs b/src/native/rust-bindings/src/liboliphaunt/root/cluster_seed.rs index 1dac37f4a..d1c3bcda4 100644 --- a/src/native/rust-bindings/src/liboliphaunt/root/cluster_seed.rs +++ b/src/native/rust-bindings/src/liboliphaunt/root/cluster_seed.rs @@ -222,7 +222,8 @@ mod tests { #[test] fn fresh_initdb_uses_fixed_bootstrap_identity_and_packaged_storage() { - let args = initdb_args(Path::new("/runtime"), Path::new("/app/database/pgdata")); + let runtime = Path::new("/runtime"); + let args = initdb_args(runtime, Path::new("/app/database/pgdata")); assert_eq!(args[0], OsStr::new("-D")); assert_eq!(args[1], OsStr::new("/app/database/pgdata")); @@ -232,17 +233,14 @@ mod tests { assert!(!args.iter().any(|arg| arg == OsStr::new("--no-sync"))); assert!( args.iter() - .any(|arg| arg == OsStr::new("/runtime/share/postgresql")) + .any(|arg| arg == runtime.join("share/postgresql").as_os_str()) ); } #[test] fn cluster_seed_initdb_sets_icu_data_when_materialized() { - let root = std::env::temp_dir().join(format!( - "oliphaunt-cluster-seed-icu-{}-{}", - std::process::id(), - std::thread::current().name().unwrap_or("test") - )); + let root = + std::env::temp_dir().join(format!("oliphaunt-cluster-seed-icu-{}", std::process::id())); let _ = fs::remove_dir_all(&root); let runtime = root.join("runtime"); let icu_data = runtime.join("share/icu"); @@ -320,9 +318,8 @@ mod tests { #[test] fn distributed_icu_seed_suppresses_only_host_locale_discovery() { let root = std::env::temp_dir().join(format!( - "oliphaunt-cluster-seed-mobile-{}-{}", - std::process::id(), - std::thread::current().name().unwrap_or("test") + "oliphaunt-cluster-seed-mobile-{}", + std::process::id() )); let _ = fs::remove_dir_all(&root); let runtime = root.join("runtime"); @@ -388,9 +385,8 @@ mod tests { #[test] fn cluster_seed_config_normalization_forces_posix_host_values() { let root = std::env::temp_dir().join(format!( - "oliphaunt-cluster-seed-normalize-{}-{}", - std::process::id(), - std::thread::current().name().unwrap_or("test") + "oliphaunt-cluster-seed-normalize-{}", + std::process::id() )); let _ = fs::remove_dir_all(&root); fs::create_dir_all(&root).unwrap(); @@ -428,9 +424,8 @@ mod tests { #[test] fn cluster_seed_config_normalization_uses_windows_dsm_on_windows() { let root = std::env::temp_dir().join(format!( - "oliphaunt-cluster-seed-normalize-windows-{}-{}", - std::process::id(), - std::thread::current().name().unwrap_or("test") + "oliphaunt-cluster-seed-normalize-windows-{}", + std::process::id() )); let _ = fs::remove_dir_all(&root); fs::create_dir_all(&root).unwrap(); diff --git a/src/native/rust-bindings/src/liboliphaunt/root/extensions.rs b/src/native/rust-bindings/src/liboliphaunt/root/extensions.rs index 8617b3740..f7f0b1c26 100644 --- a/src/native/rust-bindings/src/liboliphaunt/root/extensions.rs +++ b/src/native/rust-bindings/src/liboliphaunt/root/extensions.rs @@ -1,8 +1,9 @@ use std::collections::BTreeSet; use std::ffi::OsStr; use std::fs; -use std::path::Path; +use std::path::{Path, PathBuf}; +use super::NativeRuntimeProfile; use super::files::copy_file_preserving_permissions; use crate::error::{Error, Result}; #[cfg(test)] @@ -36,7 +37,169 @@ pub(super) fn core_share_file(relative: &Path) -> bool { pub(super) fn packaged_extension_module_files() -> BTreeSet { Extension::ALL .iter() - .filter_map(|extension| extension.native_module_file()) + .flat_map(|extension| extension.native_module_files()) + .collect() +} + +pub(super) struct ResolvedExtensionModules { + pub(super) extension: Extension, + pub(super) source_root: PathBuf, + pub(super) files: Vec, + pub(super) embedded_fallback_file: Option, +} + +impl ResolvedExtensionModules { + pub(super) fn module_source( + &self, + profile: NativeRuntimeProfile, + embedded_modules: Option<&Path>, + module: &str, + ) -> Result { + let directory = if profile.needs_embedded_modules() { + "lib/modules" + } else { + "lib/postgresql" + }; + let source = self.source_root.join(directory).join(module); + if !profile.needs_embedded_modules() + || source.is_file() + || self.embedded_fallback_file.as_deref() != Some(module) + { + return Ok(source); + } + embedded_modules + .map(|directory| directory.join(module)) + .ok_or_else(|| { + Error::Engine( + "native liboliphaunt runtime requires embedded PostgreSQL extension modules" + .to_owned(), + ) + }) + } +} + +pub(super) fn resolve_extension_modules( + profile: NativeRuntimeProfile, + install_dir: &Path, + extension_artifact_dirs: &[PathBuf], + extensions: &[Extension], +) -> Result> { + #[derive(serde::Deserialize)] + struct MemberDescriptor { + schema: String, + sql_name: String, + dependency_modules: Vec, + } + + let module_profile = if profile.needs_embedded_modules() { + "modules" + } else { + "postgresql" + }; + + extensions + .iter() + .map(|&extension| { + let source_root = super::runtime::extension_artifact_root_for( + install_dir, + extension_artifact_dirs, + extension, + ) + .to_path_buf(); + let main_module = extension.native_module_file(); + let candidates: Vec<_> = extension + .native_module_files() + .filter(|module| Some(module) != main_module.as_ref()) + .collect(); + let mut embedded_fallback_file = None; + let dependencies = if let Some(package) = extension.package() { + // The immutable resource index owns the selected package's shape; + // older carriers may statically link what a new recipe splits out. + let indexed = |module: &str| { + let relative = format!( + "extension/{}/lib/{module_profile}/{module}", + package.product + ); + package + .resources + .iter() + .any(|resource| resource.0 == relative) + }; + if profile.needs_embedded_modules() + && main_module.as_ref().is_some_and(|module| !indexed(module)) + { + embedded_fallback_file = main_module.clone(); + } + candidates + .iter() + .filter(|module| indexed(module)) + .cloned() + .collect::>() + } else { + let descriptor_path = source_root.join("extension.json"); + match fs::read(&descriptor_path) { + Ok(bytes) => { + let descriptor: MemberDescriptor = + serde_json::from_slice(&bytes).map_err(|error| { + Error::Engine(format!( + "read native extension descriptor {}: {error}", + descriptor_path.display() + )) + })?; + if descriptor.schema != "oliphaunt-extension-member-payload-v1" + || descriptor.sql_name != extension.sql_name() + || descriptor + .dependency_modules + .iter() + .any(|module| !candidates.contains(module)) + || descriptor + .dependency_modules + .iter() + .collect::>() + .len() + != descriptor.dependency_modules.len() + { + return Err(Error::Engine(format!( + "invalid native extension module declaration in {}", + descriptor_path.display() + ))); + } + descriptor.dependency_modules + } + Err(error) if error.kind() == std::io::ErrorKind::NotFound => { + // Undeclared legacy installs can only expose present owned + // files. Actual loading still proves their runtime linkage. + if profile.needs_embedded_modules() { + embedded_fallback_file = main_module.clone(); + } + candidates + .into_iter() + .filter(|module| { + source_root + .join("lib") + .join(module_profile) + .join(module) + .is_file() + }) + .collect() + } + Err(error) => { + return Err(Error::Engine(format!( + "read native extension descriptor {}: {error}", + descriptor_path.display() + ))); + } + } + }; + let mut files: Vec<_> = main_module.into_iter().collect(); + files.extend(dependencies); + Ok(ResolvedExtensionModules { + extension, + source_root, + files, + embedded_fallback_file, + }) + }) .collect() } @@ -159,6 +322,206 @@ mod tests { use super::*; + #[test] + fn module_resolution_preserves_legacy_static_and_frozen_package_shapes() { + let temp = TempTree::new("frozen-module-declarations"); + let root = temp.path().join("postgis"); + write_file( + &root.join("share/postgresql/extension/postgis.control"), + b"postgis", + ); + let main = Extension::POSTGIS.native_module_file().unwrap(); + let dependency = Extension::POSTGIS + .native_module_files() + .find(|module| module != &main) + .unwrap(); + let resolve = |profile, extension| { + resolve_extension_modules( + profile, + temp.path(), + std::slice::from_ref(&root), + &[extension], + ) + .unwrap() + .remove(0) + .files + }; + + assert_eq!( + resolve(NativeRuntimeProfile::PostgresServer, Extension::POSTGIS), + vec![main.clone()], + "legacy static installs require only their main module" + ); + write_file( + &root.join("lib/postgresql").join(&dependency), + b"declared candidate", + ); + assert_eq!( + resolve(NativeRuntimeProfile::PostgresServer, Extension::POSTGIS), + vec![main.clone(), dependency.clone()] + ); + + static OLD_PACKAGE: crate::ExtensionPackage = crate::ExtensionPackage { + product: "oliphaunt-extension-postgis", + version: "3.6.3", + runtime_version: "0.3.3", + resources: &[( + "extension/oliphaunt-extension-postgis/lib/postgresql/postgis-3.so", + b"static", + "unused-in-resolver", + true, + )], + }; + assert_eq!( + resolve( + NativeRuntimeProfile::PostgresServer, + Extension::POSTGIS.with_package(&OLD_PACKAGE) + ), + vec![main.clone()], + "an old immutable package must not inherit a new producer's module layout" + ); + + let selected_path = Box::leak( + format!("extension/oliphaunt-extension-postgis/lib/modules/{dependency}") + .into_boxed_str(), + ); + let foreign_path = Box::leak( + format!("extension/other-product/lib/postgresql/{dependency}").into_boxed_str(), + ); + let indexed_package = Box::leak(Box::new(crate::ExtensionPackage { + product: OLD_PACKAGE.product, + version: "3.6.4", + runtime_version: OLD_PACKAGE.runtime_version, + resources: Box::leak( + vec![ + ( + selected_path as &str, + b"dynamic".as_slice(), + "unused-in-resolver", + true, + ), + ( + foreign_path as &str, + b"foreign".as_slice(), + "unused-in-resolver", + true, + ), + ] + .into_boxed_slice(), + ), + })); + assert_eq!( + resolve( + NativeRuntimeProfile::OliphauntEmbedded, + Extension::POSTGIS.with_package(indexed_package) + ), + vec![main.clone(), dependency.clone()] + ); + assert_eq!( + resolve( + NativeRuntimeProfile::PostgresServer, + Extension::POSTGIS.with_package(indexed_package) + ), + vec![main.clone()], + "a static server profile must not inherit an embedded dependency" + ); + let server_path = Box::leak( + format!("extension/oliphaunt-extension-postgis/lib/postgresql/{dependency}") + .into_boxed_str(), + ); + let server_package = Box::leak(Box::new(crate::ExtensionPackage { + resources: Box::leak( + vec![( + server_path as &str, + b"dynamic".as_slice(), + "unused-in-resolver", + true, + )] + .into_boxed_slice(), + ), + ..*indexed_package + })); + assert_eq!( + resolve( + NativeRuntimeProfile::PostgresServer, + Extension::POSTGIS.with_package(server_package) + ), + vec![main.clone(), dependency.clone()] + ); + assert_eq!( + resolve( + NativeRuntimeProfile::OliphauntEmbedded, + Extension::POSTGIS.with_package(server_package) + ), + vec![main.clone()], + "a static embedded profile must not inherit a server dependency" + ); + fs::remove_file(root.join("lib/postgresql").join(&dependency)).unwrap(); + assert_eq!( + resolve( + NativeRuntimeProfile::OliphauntEmbedded, + Extension::POSTGIS.with_package(indexed_package) + ), + vec![main, dependency], + "a missing materialized file must not erase its frozen package requirement" + ); + } + + #[test] + fn current_member_declarations_bind_missing_modules_and_reject_other_members() { + let temp = TempTree::new("current-module-declarations"); + let root = temp.path().join("postgis"); + write_file( + &root.join("share/postgresql/extension/postgis.control"), + b"postgis", + ); + let main = Extension::POSTGIS.native_module_file().unwrap(); + let dependency = Extension::POSTGIS + .native_module_files() + .find(|module| module != &main) + .unwrap(); + let descriptor = serde_json::json!({ + "schema": "oliphaunt-extension-member-payload-v1", "sql_name": "postgis", "dependency_modules": [&dependency], + }); + write_file( + &root.join("extension.json"), + descriptor.to_string().as_bytes(), + ); + let modules = resolve_extension_modules( + NativeRuntimeProfile::PostgresServer, + temp.path(), + std::slice::from_ref(&root), + &[Extension::POSTGIS], + ) + .unwrap(); + assert_eq!(modules[0].files, vec![main, dependency.clone()]); + for (key, value) in [ + ("sql_name", serde_json::json!("hstore")), + ("schema", serde_json::json!("unknown")), + ( + "dependency_modules", + serde_json::json!(["../undeclared.so"]), + ), + ( + "dependency_modules", + serde_json::json!([&dependency, &dependency]), + ), + ] { + let mut changed = descriptor.clone(); + changed[key] = value; + write_file(&root.join("extension.json"), changed.to_string().as_bytes()); + assert!( + resolve_extension_modules( + NativeRuntimeProfile::PostgresServer, + temp.path(), + std::slice::from_ref(&root), + &[Extension::POSTGIS] + ) + .is_err() + ); + } + } + #[test] fn create_extension_assets_require_control_and_sql_files() { let temp = TempTree::new("extension-assets"); diff --git a/src/native/rust-bindings/src/liboliphaunt/root/fingerprint.rs b/src/native/rust-bindings/src/liboliphaunt/root/fingerprint.rs index 9a7127daf..e34e4c5d7 100644 --- a/src/native/rust-bindings/src/liboliphaunt/root/fingerprint.rs +++ b/src/native/rust-bindings/src/liboliphaunt/root/fingerprint.rs @@ -47,8 +47,14 @@ pub(super) fn fingerprint_named_extension_sql_files( state: &mut u64, source_share: &Path, sql_name: &str, + require_control: bool, ) -> Result<()> { let source_dir = source_share.join("extension"); + if !require_control + && matches!(fs::metadata(&source_dir), Err(error) if error.kind() == std::io::ErrorKind::NotFound) + { + return Ok(()); + } for entry in sorted_read_dir(&source_dir)? { let file_name = entry.file_name().to_string_lossy().into_owned(); if extension_sql_file_belongs(sql_name, &file_name) { diff --git a/src/native/rust-bindings/src/liboliphaunt/root/runtime.rs b/src/native/rust-bindings/src/liboliphaunt/root/runtime.rs index db6b5d129..12c205b95 100644 --- a/src/native/rust-bindings/src/liboliphaunt/root/runtime.rs +++ b/src/native/rust-bindings/src/liboliphaunt/root/runtime.rs @@ -20,6 +20,7 @@ use locate::{ locate_native_icu_data, locate_native_install_dir, }; +use super::extensions::resolve_extension_modules; use super::files::{sorted_read_dir, sync_directory, sync_file}; use super::{NativeCatalogProfile, NativeRuntimeProfile}; use crate::error::{Error, Result}; @@ -87,6 +88,8 @@ pub(super) fn materialize_runtime( ) -> Result { let resources = crate::extension::materialize_extension_resources(extensions)?; let extension_artifact_dirs = locate_native_extension_artifact_dirs(resources.as_deref()); + let extension_modules = + resolve_extension_modules(profile, install_dir, &extension_artifact_dirs, extensions)?; let embedded_modules = if profile.needs_embedded_modules() { Some(locate_native_embedded_modules_dir(install_dir)?) } else { @@ -96,8 +99,7 @@ pub(super) fn materialize_runtime( profile, install_dir, embedded_modules.as_deref(), - &extension_artifact_dirs, - extensions, + &extension_modules, icu_data, icu_data_tree_sha256, )?; @@ -137,8 +139,13 @@ pub(super) fn materialize_runtime( )) })?; - if !cached_runtime_is_valid_with_icu(profile, &cache_dir, &key, extensions, icu_data.is_some()) - { + if !cached_runtime_is_valid_with_icu( + profile, + &cache_dir, + &key, + &extension_modules, + icu_data.is_some(), + ) { let build_dir = cache_root.join(format!( ".build-{}-{}", std::process::id(), @@ -163,9 +170,8 @@ pub(super) fn materialize_runtime( profile, install_dir, embedded_modules.as_deref(), - &extension_artifact_dirs, &build_dir, - extensions, + &extension_modules, icu_data, ); if let Err(error) = build_result { diff --git a/src/native/rust-bindings/src/liboliphaunt/root/runtime/cache_key.rs b/src/native/rust-bindings/src/liboliphaunt/root/runtime/cache_key.rs index 056ec98e6..bb8baa825 100644 --- a/src/native/rust-bindings/src/liboliphaunt/root/runtime/cache_key.rs +++ b/src/native/rust-bindings/src/liboliphaunt/root/runtime/cache_key.rs @@ -1,10 +1,13 @@ use std::fs; -use std::path::{Path, PathBuf}; +use std::path::Path; +#[cfg(test)] +use std::path::PathBuf; use super::super::NativeRuntimeProfile; use super::super::extensions::{ - core_share_file, data_files, embedded_core_module_files, extension_sql_file_is_control, - extension_sql_file_is_sql, packaged_extension_module_files, selected_extension_names, + ResolvedExtensionModules, core_share_file, data_files, embedded_core_module_files, + extension_sql_file_is_control, extension_sql_file_is_sql, packaged_extension_module_files, + selected_extension_names, }; use super::super::files::sorted_read_dir; use super::super::fingerprint::{ @@ -13,7 +16,6 @@ use super::super::fingerprint::{ new_state, }; use super::super::{NATIVE_RUNTIME_TOOLS, existing_native_tool_path, native_tool_path}; -use super::extension_artifact_root_for; use crate::error::{Error, Result}; use crate::extension::Extension; @@ -27,12 +29,17 @@ pub(super) fn runtime_cache_key( extension_artifact_dirs: &[PathBuf], extensions: &[Extension], ) -> Result { - runtime_cache_key_with_icu( + let extension_modules = super::super::extensions::resolve_extension_modules( profile, install_dir, - embedded_modules, extension_artifact_dirs, extensions, + )?; + runtime_cache_key_with_icu( + profile, + install_dir, + embedded_modules, + &extension_modules, None, None, ) @@ -42,8 +49,7 @@ pub(super) fn runtime_cache_key_with_icu( profile: NativeRuntimeProfile, install_dir: &Path, embedded_modules: Option<&Path>, - extension_artifact_dirs: &[PathBuf], - extensions: &[Extension], + extension_modules: &[ResolvedExtensionModules], icu_data: Option<&Path>, icu_data_tree_sha256: Option<&str>, ) -> Result { @@ -56,7 +62,11 @@ pub(super) fn runtime_cache_key_with_icu( } hash_str(&mut state, std::env::consts::DLL_SUFFIX); - for name in selected_extension_names(extensions) { + let extensions: Vec<_> = extension_modules + .iter() + .map(|modules| modules.extension) + .collect(); + for name in selected_extension_names(&extensions) { hash_str(&mut state, name); } hash_str( @@ -85,13 +95,16 @@ pub(super) fn runtime_cache_key_with_icu( } let source_share = install_dir.join("share/postgresql"); fingerprint_directory_filtered(&mut state, &source_share, &source_share, core_share_file)?; - fingerprint_named_extension_sql_files(&mut state, &source_share, "plpgsql")?; - for extension in extensions { - let extension_root = - extension_artifact_root_for(install_dir, extension_artifact_dirs, *extension); - let extension_share = extension_root.join("share/postgresql"); - fingerprint_named_extension_sql_files(&mut state, &extension_share, extension.sql_name())?; - for relative in data_files(*extension) { + fingerprint_named_extension_sql_files(&mut state, &source_share, "plpgsql", true)?; + for extension in extension_modules { + let extension_share = extension.source_root.join("share/postgresql"); + fingerprint_named_extension_sql_files( + &mut state, + &extension_share, + extension.extension.sql_name(), + extension.extension.creates_extension(), + )?; + for relative in data_files(extension.extension) { fingerprint_optional_file( &mut state, &extension_share, @@ -109,7 +122,7 @@ pub(super) fn runtime_cache_key_with_icu( } } let source_lib = install_dir.join("lib/postgresql"); - let extension_modules = packaged_extension_module_files(); + let packaged_modules = packaged_extension_module_files(); let embedded_core_modules = embedded_core_module_files(); for entry in sorted_read_dir(&source_lib)? { let source = entry.path(); @@ -117,67 +130,35 @@ pub(super) fn runtime_cache_key_with_icu( continue; } let file_name = entry.file_name().to_string_lossy().into_owned(); - if extension_modules.contains(&file_name) + if packaged_modules.contains(&file_name) || (profile.needs_embedded_modules() && embedded_core_modules.contains(&file_name)) { continue; } fingerprint_file(&mut state, &source_lib, &source)?; } - match profile { - NativeRuntimeProfile::OliphauntEmbedded => { - let embedded_modules = embedded_modules.ok_or_else(|| { - Error::Engine( - "native liboliphaunt runtime requires embedded PostgreSQL modules".to_owned(), - ) - })?; - for module in embedded_core_modules { - fingerprint_optional_file( - &mut state, - embedded_modules, - &embedded_modules.join(&module), - )?; - } - for extension in extensions { - if let Some(module) = extension.native_module_file() { - let extension_root = extension_artifact_root_for( - install_dir, - extension_artifact_dirs, - *extension, - ); - let extension_lib = extension_root.join("lib/modules"); - if extension_lib.join(&module).is_file() { - fingerprint_optional_file( - &mut state, - &extension_lib, - &extension_lib.join(&module), - )?; - } else { - fingerprint_optional_file( - &mut state, - embedded_modules, - &embedded_modules.join(&module), - )?; - } - } - } + if profile.needs_embedded_modules() { + let embedded_modules = embedded_modules.ok_or_else(|| { + Error::Engine( + "native liboliphaunt runtime requires embedded PostgreSQL modules".to_owned(), + ) + })?; + for module in embedded_core_modules { + fingerprint_optional_file( + &mut state, + embedded_modules, + &embedded_modules.join(module), + )?; } - NativeRuntimeProfile::PostgresServer => { - for extension in extensions { - if let Some(module) = extension.native_module_file() { - let extension_root = extension_artifact_root_for( - install_dir, - extension_artifact_dirs, - *extension, - ); - let extension_lib = extension_root.join("lib/postgresql"); - fingerprint_optional_file( - &mut state, - &extension_lib, - &extension_lib.join(module), - )?; - } - } + } + for extension in extension_modules { + for module in &extension.files { + let source = extension.module_source(profile, embedded_modules, module)?; + fingerprint_optional_file( + &mut state, + source.parent().expect("native module source directory"), + &source, + )?; } } @@ -191,14 +172,23 @@ pub(super) fn cached_runtime_is_valid( key: &str, extensions: &[Extension], ) -> bool { - cached_runtime_is_valid_with_icu(profile, cache_dir, key, extensions, false) + let modules: Vec<_> = extensions + .iter() + .map(|&extension| ResolvedExtensionModules { + extension, + source_root: PathBuf::new(), + files: extension.native_module_files().collect(), + embedded_fallback_file: None, + }) + .collect(); + cached_runtime_is_valid_with_icu(profile, cache_dir, key, &modules, false) } pub(super) fn cached_runtime_is_valid_with_icu( profile: NativeRuntimeProfile, cache_dir: &Path, key: &str, - extensions: &[Extension], + extension_modules: &[ResolvedExtensionModules], has_icu_data: bool, ) -> bool { if !cache_dir.join(".complete").is_file() @@ -243,22 +233,25 @@ pub(super) fn cached_runtime_is_valid_with_icu( return false; } - for extension in extensions { + for modules in extension_modules { + let extension = modules.extension; if extension.creates_extension() && (!cache_dir .join("share/postgresql/extension") .join(format!("{}.control", extension.sql_name())) .is_file() - || !cache_contains_extension_sql_file(cache_dir, *extension)) + || !cache_contains_extension_sql_file(cache_dir, extension)) { return false; } - if let Some(module) = extension.native_module_file() - && !cache_dir.join("lib/postgresql").join(module).is_file() + if !modules + .files + .iter() + .all(|module| cache_dir.join("lib/postgresql").join(module).is_file()) { return false; } - for relative in data_files(*extension) { + for relative in data_files(extension) { if !cache_dir.join("share/postgresql").join(relative).is_file() { return false; } @@ -312,6 +305,51 @@ mod tests { use super::*; + #[test] + fn module_only_sidecars_do_not_require_an_empty_sql_directory() { + let temp = TempTree::new("module-only-sidecar"); + let install = temp.path().join("install"); + let sidecar = temp.path().join("auto_explain"); + write_fake_install(&install); + let module = Extension::AUTO_EXPLAIN.native_module_file().unwrap(); + let source = sidecar.join("lib/postgresql").join(module); + write_file(&source, b"module-v1"); + let key = || { + runtime_cache_key( + NativeRuntimeProfile::PostgresServer, + &install, + None, + std::slice::from_ref(&sidecar), + &[Extension::AUTO_EXPLAIN], + ) + .unwrap() + }; + let without_directory = key(); + fs::create_dir_all(sidecar.join("share/postgresql/extension")).unwrap(); + assert_eq!( + without_directory, + key(), + "empty optional SQL directories do not change delivered assets" + ); + write_file(&source, b"module-v2"); + assert_ne!( + without_directory, + key(), + "the selected module remains part of the cache key" + ); + fs::remove_dir_all(sidecar.join("share")).unwrap(); + assert!( + fingerprint_named_extension_sql_files( + &mut new_state(), + &sidecar.join("share/postgresql"), + "hstore", + true, + ) + .is_err(), + "SQL extensions still require their source directory" + ); + } + struct TempTree { path: PathBuf, } @@ -506,6 +544,192 @@ mod tests { ); } + #[test] + fn declared_dependency_module_changes_track_only_the_selected_profile() { + let temp = TempTree::new("dependency-module-profiles"); + let install_dir = temp.path().join("install"); + let extension_dir = temp.path().join("postgis-sidecar"); + let embedded_modules = temp.path().join("embedded-modules"); + write_fake_install(&install_dir); + write_file( + &extension_dir.join("share/postgresql/extension/postgis.control"), + b"postgis", + ); + write_file( + &extension_dir.join("share/postgresql/extension/postgis--1.0.sql"), + b"postgis sql", + ); + for module in embedded_core_module_files() { + write_file(&embedded_modules.join(module), b"embedded core"); + } + let main_module = Extension::POSTGIS.native_module_file().unwrap(); + let dependency = Extension::POSTGIS + .native_module_files() + .find(|module| module != &main_module) + .unwrap(); + for profile in [ + NativeRuntimeProfile::PostgresServer, + NativeRuntimeProfile::OliphauntEmbedded, + ] { + for module in Extension::POSTGIS.native_module_files() { + write_file( + &extension_dir.join("lib/postgresql").join(&module), + b"server v1", + ); + write_file( + &extension_dir.join("lib/modules").join(module), + b"embedded v1", + ); + } + let key = || { + runtime_cache_key( + profile, + &install_dir, + Some(&embedded_modules), + std::slice::from_ref(&extension_dir), + &[Extension::POSTGIS], + ) + .unwrap() + }; + let first = key(); + let (active, inactive) = if profile.needs_embedded_modules() { + ("lib/modules", "lib/postgresql") + } else { + ("lib/postgresql", "lib/modules") + }; + write_file( + &extension_dir.join(inactive).join(&dependency), + b"other ABI changed", + ); + assert_eq!( + first, + key(), + "an inactive dependency ABI must not invalidate the cache" + ); + write_file( + &extension_dir.join(active).join(&dependency), + b"selected ABI changed", + ); + let changed = key(); + assert_ne!( + first, changed, + "selected dependency bytes must invalidate the cache" + ); + fs::remove_file(extension_dir.join(active).join(&dependency)).unwrap(); + assert_ne!( + changed, + key(), + "a missing selected dependency must invalidate the cache" + ); + } + } + + #[test] + fn unselected_dependency_modules_do_not_pollute_the_cache_key() { + let temp = TempTree::new("unselected-dependency-module"); + let install_dir = temp.path().join("install"); + write_fake_install(&install_dir); + let key = || { + runtime_cache_key( + NativeRuntimeProfile::PostgresServer, + &install_dir, + None, + &[], + &[Extension::HSTORE], + ) + .unwrap() + }; + let first = key(); + for module in Extension::POSTGIS.native_module_files() { + write_file( + &install_dir.join("lib/postgresql").join(module), + b"unselected PostGIS", + ); + } + assert_eq!( + first, + key(), + "unselected dependency modules must stay invisible to runtime identity" + ); + } + + #[test] + fn cached_runtime_requires_declared_dependency_modules_in_both_profiles() { + let temp = TempTree::new("cached-dependency-module"); + let main_module = Extension::POSTGIS.native_module_file().unwrap(); + let dependency = Extension::POSTGIS + .native_module_files() + .find(|module| module != &main_module) + .unwrap(); + let source = temp.path().join("original-sidecar"); + write_file( + &source.join("share/postgresql/extension/postgis.control"), + b"postgis", + ); + write_file(&source.join("extension.json"), serde_json::json!({ + "schema": "oliphaunt-extension-member-payload-v1", "sql_name": "postgis", "dependency_modules": [&dependency], + }).to_string().as_bytes()); + let resolved = super::super::super::extensions::resolve_extension_modules( + NativeRuntimeProfile::PostgresServer, + temp.path(), + std::slice::from_ref(&source), + &[Extension::POSTGIS], + ) + .unwrap(); + for profile in [ + NativeRuntimeProfile::PostgresServer, + NativeRuntimeProfile::OliphauntEmbedded, + ] { + let cache_dir = temp.path().join(profile.cache_id()); + write_minimal_cache_dir(&cache_dir, "cache-key"); + write_file( + &cache_dir.join(".manifest"), + runtime_cache_manifest(profile, "cache-key", &[Extension::POSTGIS]).as_bytes(), + ); + write_file( + &cache_dir.join("share/postgresql/extension/postgis.control"), + b"postgis", + ); + write_file( + &cache_dir.join("share/postgresql/extension/postgis--1.0.sql"), + b"postgis sql", + ); + write_file( + &cache_dir.join("lib/postgresql").join(&main_module), + b"main module", + ); + for relative in data_files(Extension::POSTGIS) { + write_file( + &cache_dir.join("share/postgresql").join(relative), + b"postgis data", + ); + } + for module in embedded_core_module_files() { + write_file( + &cache_dir.join("lib/postgresql").join(module), + b"embedded core", + ); + } + let valid = || { + cached_runtime_is_valid_with_icu(profile, &cache_dir, "cache-key", &resolved, false) + }; + assert!( + !valid(), + "main module alone cannot satisfy its declared dependencies" + ); + write_file( + &cache_dir.join("lib/postgresql").join(&dependency), + b"dependency module", + ); + assert!( + valid(), + "the complete declared module closure must be accepted" + ); + fs::remove_file(cache_dir.join("lib/postgresql").join(&dependency)).unwrap(); + assert!(!valid(), "removing a dependency must invalidate the cache"); + } + } + #[test] fn unselected_extension_assets_do_not_pollute_cache_key() { let temp = TempTree::new("unselected-extension"); @@ -607,7 +831,6 @@ mod tests { &install_dir, None, &[], - &[], Some(&icu_data), Some(&first_digest), ) @@ -618,7 +841,6 @@ mod tests { &install_dir, None, &[], - &[], Some(&icu_data), Some(&first_digest), ) @@ -628,7 +850,6 @@ mod tests { &install_dir, None, &[], - &[], Some(&temp.path().join("missing-managed-icu-tree")), Some(&first_digest), ) @@ -638,7 +859,6 @@ mod tests { &install_dir, None, &[], - &[], Some(&icu_data), Some(&second_digest), ) @@ -653,7 +873,6 @@ mod tests { &install_dir, None, &[], - &[], Some(&icu_data), None, ) @@ -664,7 +883,6 @@ mod tests { &install_dir, None, &[], - &[], Some(&icu_data), None, ) @@ -865,12 +1083,9 @@ mod tests { &cache_dir.join(".manifest"), runtime_cache_manifest(NativeRuntimeProfile::PostgresServer, key, &[]).as_bytes(), ); - write_file(&cache_dir.join("bin/postgres"), b"postgres"); - write_file(&cache_dir.join("bin/initdb"), b"initdb"); - write_file(&cache_dir.join("bin/pg_ctl"), b"pg_ctl"); - write_file(&cache_dir.join("bin/pg_basebackup"), b"pg_basebackup"); - write_file(&cache_dir.join("bin/pg_dump"), b"pg_dump"); - write_file(&cache_dir.join("bin/psql"), b"psql"); + for tool in NATIVE_RUNTIME_TOOLS { + write_file(&native_tool_path(cache_dir, tool), tool.as_bytes()); + } write_file( &cache_dir.join("share/postgresql/postgresql.conf.sample"), b"# sample\n", diff --git a/src/native/rust-bindings/src/liboliphaunt/root/runtime/install.rs b/src/native/rust-bindings/src/liboliphaunt/root/runtime/install.rs index 6bc185c5b..eaa5d0d0b 100644 --- a/src/native/rust-bindings/src/liboliphaunt/root/runtime/install.rs +++ b/src/native/rust-bindings/src/liboliphaunt/root/runtime/install.rs @@ -1,19 +1,21 @@ use std::fs; -use std::path::{Path, PathBuf}; +use std::path::Path; +#[cfg(test)] +use std::path::PathBuf; use super::super::NativeRuntimeProfile; use super::super::extensions::{ - copy_embedded_module, copy_extension_data_files, copy_extension_sql_files, - copy_named_extension_sql_files, core_share_file, embedded_core_module_files, - packaged_extension_module_files, + ResolvedExtensionModules, copy_embedded_module, copy_extension_data_files, + copy_extension_sql_files, copy_named_extension_sql_files, core_share_file, + embedded_core_module_files, packaged_extension_module_files, }; use super::super::files::{ copy_directory_filtered, copy_directory_tree, copy_file_preserving_permissions, remove_file_if_exists, }; use super::super::{NATIVE_RUNTIME_TOOLS, existing_native_tool_path, native_tool_path}; -use super::extension_artifact_root_for; use crate::error::{Error, Result}; +#[cfg(test)] use crate::extension::Extension; #[cfg(test)] @@ -25,13 +27,18 @@ pub(super) fn install_cached_runtime( runtime_dir: &Path, extensions: &[Extension], ) -> Result<()> { + let extension_modules = super::super::extensions::resolve_extension_modules( + profile, + install_dir, + extension_artifact_dirs, + extensions, + )?; install_cached_runtime_with_icu( profile, install_dir, embedded_modules, - extension_artifact_dirs, runtime_dir, - extensions, + &extension_modules, None, ) } @@ -40,9 +47,8 @@ pub(super) fn install_cached_runtime_with_icu( profile: NativeRuntimeProfile, install_dir: &Path, embedded_modules: Option<&Path>, - extension_artifact_dirs: &[PathBuf], runtime_dir: &Path, - extensions: &[Extension], + extension_modules: &[ResolvedExtensionModules], icu_data: Option<&Path>, ) -> Result<()> { fs::create_dir_all(runtime_dir).map_err(|err| { @@ -56,19 +62,13 @@ pub(super) fn install_cached_runtime_with_icu( install_required_runtime_tool(install_dir, runtime_dir, tool, "native runtime")?; } - install_native_share_tree( - install_dir, - extension_artifact_dirs, - runtime_dir, - extensions, - )?; + install_native_share_tree(install_dir, runtime_dir, extension_modules)?; install_native_library_tree( profile, install_dir, embedded_modules, - extension_artifact_dirs, runtime_dir, - extensions, + extension_modules, )?; if let Some(icu_data) = icu_data { copy_directory_tree( @@ -132,9 +132,8 @@ fn ensure_runtime_tool_executable(_path: &Path) -> Result<()> { fn install_native_share_tree( install_dir: &Path, - extension_artifact_dirs: &[PathBuf], runtime_dir: &Path, - extensions: &[Extension], + extension_modules: &[ResolvedExtensionModules], ) -> Result<()> { let source_share = install_dir.join("share/postgresql"); let target_share = runtime_dir.join("share/postgresql"); @@ -155,12 +154,10 @@ fn install_native_share_tree( })?; copy_named_extension_sql_files(&source_share, &target_share, "plpgsql", true)?; - for extension in extensions { - let extension_root = - extension_artifact_root_for(install_dir, extension_artifact_dirs, *extension); - let extension_share = extension_root.join("share/postgresql"); - copy_extension_sql_files(&extension_share, &target_share, *extension)?; - copy_extension_data_files(&extension_share, &target_share, *extension)?; + for extension in extension_modules { + let extension_share = extension.source_root.join("share/postgresql"); + copy_extension_sql_files(&extension_share, &target_share, extension.extension)?; + copy_extension_data_files(&extension_share, &target_share, extension.extension)?; } Ok(()) } @@ -172,7 +169,7 @@ mod tests { use std::time::{SystemTime, UNIX_EPOCH}; use super::*; - use crate::extension::resolve_extensions; + use crate::extension::{extension_data_files, resolve_extensions}; #[test] fn install_rejects_missing_transitive_extension_dependency_assets() { @@ -345,6 +342,402 @@ mod tests { ); } + #[test] + fn install_copies_declared_dependency_modules_from_the_selected_profile() { + let temp = TempTree::new("selected-dependency-modules"); + let install_dir = temp.path().join("install"); + let extension_dir = temp.path().join("postgis-sidecar"); + let embedded_modules = temp.path().join("embedded-modules"); + write_minimal_install(&install_dir); + write_extension_assets(&install_dir, Extension::POSTGIS); + write_extension_assets(&install_dir, Extension::HSTORE); + write_extension_assets(&extension_dir, Extension::POSTGIS); + for relative in extension_data_files(Extension::POSTGIS) { + write_file( + &extension_dir.join("share/postgresql").join(relative), + b"postgis data", + ); + } + for module in embedded_core_module_files() { + write_file(&embedded_modules.join(module), b"embedded core"); + } + for module in Extension::POSTGIS.native_module_files() { + write_file( + &extension_dir.join("lib/postgresql").join(&module), + b"server module", + ); + write_file( + &extension_dir.join("lib/modules").join(&module), + b"embedded module", + ); + write_file( + &embedded_modules.join(module), + b"global fallback must not win", + ); + } + for (profile, expected) in [ + ( + NativeRuntimeProfile::PostgresServer, + b"server module".as_slice(), + ), + ( + NativeRuntimeProfile::OliphauntEmbedded, + b"embedded module".as_slice(), + ), + ] { + let runtime = temp.path().join(profile.cache_id()); + install_cached_runtime( + profile, + &install_dir, + Some(&embedded_modules), + std::slice::from_ref(&extension_dir), + &runtime, + &[Extension::POSTGIS], + ) + .unwrap(); + for module in Extension::POSTGIS.native_module_files() { + assert_eq!( + fs::read(runtime.join("lib/postgresql").join(module)).unwrap(), + expected + ); + } + assert!( + !runtime + .join("lib/postgresql") + .join(Extension::HSTORE.native_module_file().unwrap()) + .exists() + ); + } + } + + #[test] + fn install_rejects_missing_declared_dependency_modules_in_both_profiles() { + let temp = TempTree::new("missing-dependency-modules"); + let install_dir = temp.path().join("install"); + let extension_dir = temp.path().join("postgis-sidecar"); + let embedded_modules = temp.path().join("embedded-modules"); + write_minimal_install(&install_dir); + write_extension_assets(&extension_dir, Extension::POSTGIS); + for relative in extension_data_files(Extension::POSTGIS) { + write_file( + &extension_dir.join("share/postgresql").join(relative), + b"postgis data", + ); + } + for module in embedded_core_module_files() { + write_file(&embedded_modules.join(module), b"embedded core"); + } + let main_module = Extension::POSTGIS.native_module_file().unwrap(); + write_file( + &extension_dir.join("lib/modules").join(&main_module), + b"embedded module", + ); + let dependency = Extension::POSTGIS + .native_module_files() + .find(|module| module != &main_module) + .unwrap(); + write_file( + &extension_dir.join("extension.json"), + serde_json::json!({ + "schema": "oliphaunt-extension-member-payload-v1", + "sql_name": "postgis", + "dependency_modules": [&dependency], + }) + .to_string() + .as_bytes(), + ); + fs::remove_file(extension_dir.join("lib/postgresql").join(&dependency)).unwrap(); + for profile in [ + NativeRuntimeProfile::PostgresServer, + NativeRuntimeProfile::OliphauntEmbedded, + ] { + let error = install_cached_runtime( + profile, + &install_dir, + Some(&embedded_modules), + std::slice::from_ref(&extension_dir), + &temp.path().join(profile.cache_id()), + &[Extension::POSTGIS], + ) + .unwrap_err(); + assert!( + error.to_string().contains(&dependency), + "unexpected dependency error: {error}" + ); + } + } + + #[test] + fn install_preserves_legacy_statically_linked_modules_in_both_profiles() { + let temp = TempTree::new("legacy-static-dependency-modules"); + let install_dir = temp.path().join("install"); + let extension_dir = temp.path().join("postgis-sidecar"); + let embedded_modules = temp.path().join("embedded-modules"); + write_minimal_install(&install_dir); + write_extension_assets(&extension_dir, Extension::POSTGIS); + let main = Extension::POSTGIS.native_module_file().unwrap(); + for module in Extension::POSTGIS + .native_module_files() + .filter(|module| module != &main) + { + fs::remove_file(extension_dir.join("lib/postgresql").join(module)).unwrap(); + } + for relative in extension_data_files(Extension::POSTGIS) { + write_file( + &extension_dir.join("share/postgresql").join(relative), + b"postgis data", + ); + } + for module in embedded_core_module_files() { + write_file(&embedded_modules.join(module), b"embedded core"); + } + write_file( + &extension_dir.join("lib/modules").join(&main), + b"static embedded module", + ); + let resolved = super::super::super::extensions::resolve_extension_modules( + NativeRuntimeProfile::PostgresServer, + &install_dir, + std::slice::from_ref(&extension_dir), + &[Extension::POSTGIS], + ) + .unwrap(); + assert_eq!(resolved[0].files, vec![main.clone()]); + for profile in [ + NativeRuntimeProfile::PostgresServer, + NativeRuntimeProfile::OliphauntEmbedded, + ] { + let runtime = temp.path().join(profile.cache_id()); + install_cached_runtime( + profile, + &install_dir, + Some(&embedded_modules), + std::slice::from_ref(&extension_dir), + &runtime, + &[Extension::POSTGIS], + ) + .unwrap(); + fs::write(runtime.join(".complete"), b"ok").unwrap(); + fs::write( + runtime.join(".manifest"), + super::super::cache_key::runtime_cache_manifest( + profile, + "legacy-key", + &[Extension::POSTGIS], + ), + ) + .unwrap(); + assert!(super::super::cache_key::cached_runtime_is_valid_with_icu( + profile, + &runtime, + "legacy-key", + &resolved, + false + )); + assert!(runtime.join("lib/postgresql").join(&main).is_file()); + } + } + + #[test] + fn install_excludes_unselected_dependency_modules_from_the_base_install() { + let temp = TempTree::new("unselected-dependency-modules"); + let install_dir = temp.path().join("install"); + let runtime_dir = temp.path().join("runtime"); + write_minimal_install(&install_dir); + write_extension_assets(&install_dir, Extension::POSTGIS); + write_extension_assets(&install_dir, Extension::HSTORE); + install_cached_runtime( + NativeRuntimeProfile::PostgresServer, + &install_dir, + None, + &[], + &runtime_dir, + &[Extension::HSTORE], + ) + .unwrap(); + for module in Extension::POSTGIS.native_module_files() { + assert!(!runtime_dir.join("lib/postgresql").join(module).exists()); + } + } + + #[test] + fn declared_embedded_modules_cannot_use_different_global_fallback_bytes() { + let temp = TempTree::new("declared-embedded-no-fallback"); + let install_dir = temp.path().join("install"); + let extension_dir = temp.path().join("postgis-sidecar"); + let embedded_modules = temp.path().join("embedded-modules"); + write_minimal_install(&install_dir); + write_extension_assets(&extension_dir, Extension::POSTGIS); + for relative in extension_data_files(Extension::POSTGIS) { + write_file( + &extension_dir.join("share/postgresql").join(relative), + b"postgis data", + ); + } + for module in embedded_core_module_files() { + write_file(&embedded_modules.join(module), b"embedded core"); + } + let files: Vec<_> = Extension::POSTGIS.native_module_files().collect(); + let package = Box::leak(Box::new(crate::ExtensionPackage { + product: "oliphaunt-extension-postgis", + version: "3.6.4", + runtime_version: "0.3.3", + resources: Box::leak( + files + .iter() + .map(|module| { + let relative: &'static str = Box::leak( + format!("extension/oliphaunt-extension-postgis/lib/modules/{module}") + .into_boxed_str(), + ); + ( + relative, + b"selected embedded".as_slice(), + "unused-in-resolver", + true, + ) + }) + .collect::>() + .into_boxed_slice(), + ), + })); + for extension in [Extension::POSTGIS, Extension::POSTGIS.with_package(package)] { + write_file(&extension_dir.join("extension.json"), serde_json::json!({ + "schema": "oliphaunt-extension-member-payload-v1", "sql_name": "postgis", "dependency_modules": &files[1..], + }).to_string().as_bytes()); + for missing in &files { + for module in &files { + write_file( + &extension_dir.join("lib/modules").join(module), + b"selected embedded", + ); + write_file(&embedded_modules.join(module), b"different global bytes"); + } + fs::remove_file(extension_dir.join("lib/modules").join(missing)).unwrap(); + let key = || { + super::super::cache_key::runtime_cache_key( + NativeRuntimeProfile::OliphauntEmbedded, + &install_dir, + Some(&embedded_modules), + std::slice::from_ref(&extension_dir), + &[extension], + ) + .unwrap() + }; + let missing_key = key(); + write_file( + &embedded_modules.join(missing), + b"global bytes changed again", + ); + assert_eq!( + missing_key, + key(), + "missing declared files must not hash global fallback bytes" + ); + let error = install_cached_runtime( + NativeRuntimeProfile::OliphauntEmbedded, + &install_dir, + Some(&embedded_modules), + std::slice::from_ref(&extension_dir), + &temp.path().join("runtime"), + &[extension], + ) + .unwrap_err(); + assert!( + error.to_string().contains( + &extension_dir + .join("lib/modules") + .join(missing) + .display() + .to_string() + ), + "unexpected owned-file error: {error}" + ); + write_file( + &extension_dir.join("lib/modules").join(missing), + b"selected embedded", + ); + assert_ne!( + missing_key, + key(), + "restoring the original declared file must change its cache identity" + ); + } + } + } + + #[test] + fn legacy_primary_modules_keep_their_undeclared_embedded_fallback() { + let temp = TempTree::new("legacy-primary-fallback"); + let install_dir = temp.path().join("install"); + let extension_dir = temp.path().join("hstore-sidecar"); + let embedded_modules = temp.path().join("embedded-modules"); + write_minimal_install(&install_dir); + write_extension_assets(&extension_dir, Extension::HSTORE); + for module in embedded_core_module_files() { + write_file(&embedded_modules.join(module), b"embedded core"); + } + let main = Extension::HSTORE.native_module_file().unwrap(); + let old_path: &'static str = Box::leak( + format!("extension/oliphaunt-extension-contrib-pg18/lib/postgresql/{main}") + .into_boxed_str(), + ); + let old_package = Box::leak(Box::new(crate::ExtensionPackage { + product: "oliphaunt-extension-contrib-pg18", + version: "0.3.3", + runtime_version: "0.3.3", + resources: Box::leak( + vec![( + old_path, + b"legacy server".as_slice(), + "unused-in-resolver", + true, + )] + .into_boxed_slice(), + ), + })); + for (index, extension) in [ + Extension::HSTORE, + Extension::HSTORE.with_package(old_package), + ] + .into_iter() + .enumerate() + { + let runtime = temp.path().join(format!("runtime-{index}")); + write_file(&embedded_modules.join(&main), b"legacy embedded v1"); + let key = || { + super::super::cache_key::runtime_cache_key( + NativeRuntimeProfile::OliphauntEmbedded, + &install_dir, + Some(&embedded_modules), + std::slice::from_ref(&extension_dir), + &[extension], + ) + .unwrap() + }; + let first = key(); + install_cached_runtime( + NativeRuntimeProfile::OliphauntEmbedded, + &install_dir, + Some(&embedded_modules), + std::slice::from_ref(&extension_dir), + &runtime, + &[extension], + ) + .unwrap(); + assert_eq!( + fs::read(runtime.join("lib/postgresql").join(&main)).unwrap(), + b"legacy embedded v1" + ); + write_file(&embedded_modules.join(&main), b"legacy embedded v2"); + assert_ne!( + first, + key(), + "allowed legacy fallback bytes must remain part of cache identity" + ); + } + } + #[test] fn install_copies_module_only_extension_from_product_sidecar() { let temp = TempTree::new("module-only-sidecar-extension"); @@ -567,7 +960,7 @@ mod tests { .join(format!("{}--1.0.sql", extension.sql_name())), format!("select '{} install';\n", extension.sql_name()).as_bytes(), ); - if let Some(module) = extension.native_module_file() { + for module in extension.native_module_files() { write_file( &install_dir.join("lib/postgresql").join(module), format!("{} module\n", extension.sql_name()).as_bytes(), @@ -587,9 +980,8 @@ fn install_native_library_tree( profile: NativeRuntimeProfile, install_dir: &Path, embedded_modules: Option<&Path>, - extension_artifact_dirs: &[PathBuf], runtime_dir: &Path, - extensions: &[Extension], + extension_modules: &[ResolvedExtensionModules], ) -> Result<()> { install_runtime_library_root(install_dir, runtime_dir)?; @@ -608,7 +1000,7 @@ fn install_native_library_tree( )) })?; - let extension_modules = packaged_extension_module_files(); + let packaged_modules = packaged_extension_module_files(); let embedded_core_modules = embedded_core_module_files(); for entry in fs::read_dir(&source_lib) .map_err(|err| Error::Engine(format!("read native library dir: {err}")))? @@ -620,7 +1012,7 @@ fn install_native_library_tree( continue; } let file_name = entry.file_name().to_string_lossy().into_owned(); - if extension_modules.contains(&file_name) + if packaged_modules.contains(&file_name) || (profile.needs_embedded_modules() && embedded_core_modules.contains(&file_name)) { continue; @@ -638,37 +1030,17 @@ fn install_native_library_tree( copy_embedded_module(embedded_modules, &target_lib, &module)?; } } - for extension in extensions { - let Some(module) = extension.native_module_file() else { - continue; - }; - let extension_root = - extension_artifact_root_for(install_dir, extension_artifact_dirs, *extension); - let extension_lib = extension_root.join("lib/postgresql"); - match profile { - NativeRuntimeProfile::OliphauntEmbedded => { - let embedded_extension_lib = extension_root.join("lib/modules"); - if embedded_extension_lib.join(&module).is_file() { - copy_file_preserving_permissions( - &embedded_extension_lib.join(&module), - &target_lib.join(&module), - )?; - } else { - let embedded_modules = embedded_modules.ok_or_else(|| { - Error::Engine( - "native liboliphaunt runtime requires embedded PostgreSQL extension modules" - .to_owned(), - ) - })?; - copy_embedded_module(embedded_modules, &target_lib, &module)?; - } - } - NativeRuntimeProfile::PostgresServer => { - copy_file_preserving_permissions( - &extension_lib.join(&module), - &target_lib.join(&module), - )?; + for extension in extension_modules { + for module in &extension.files { + let source = extension.module_source(profile, embedded_modules, module)?; + if !source.is_file() { + return Err(Error::Engine(format!( + "native extension '{}' module is missing {}", + extension.extension.sql_name(), + source.display() + ))); } + copy_file_preserving_permissions(&source, &target_lib.join(module))?; } } Ok(()) diff --git a/src/native/sdks/kotlin/BUILD.bazel b/src/native/sdks/kotlin/BUILD.bazel new file mode 100644 index 000000000..f8b6c8a22 --- /dev/null +++ b/src/native/sdks/kotlin/BUILD.bazel @@ -0,0 +1,242 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/languages/jvm:bindings.bzl", "uniffi_kotlin") +load("//build_defs/languages/jvm:maven.bzl", "kotlin_installed_maven_test", "kotlin_maven_package") +load("//build_defs/languages/jvm:compiled-inputs-test.bzl", "kotlin_compiled_inputs_test") +load("//build_defs/languages/jvm:quality.bzl", "kotlin_format_test") +load("//build_defs/languages/jvm:android-lint.bzl", "kotlin_android_lint_test") +load("//build_defs/android:toolchain.bzl", "android_artifact") +load("//build_defs/release:shipping.bzl", "shipping_export") +load("//build_defs/extensions:sdk_projections.bzl", "sdk_extension_projections") +load("@oliphaunt_kotlin_manifest//:metadata.bzl", "KOTLIN") +load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library", "kt_jvm_test") +load("@rules_kotlin//kotlin:android.bzl", "kt_android_library") +load("@rules_android//android:rules.bzl", "aar_import", "android_library") +load("@rules_java//java:java_import.bzl", "java_import") +load("@bazel_skylib//rules:expand_template.bzl", "expand_template") + +package(default_visibility = ["//visibility:public"]) + +exports_files([ + "VERSION", + "release.toml", + "gradle.properties", + "oliphaunt/build.gradle.kts", + "gradle/libs.versions.toml", + "gradle/wrapper/gradle-wrapper.properties", + "tools/kotlin-maven-staging.mts", + "tools/check-package.mts", + "maven_install.json", +]) + +# UniFFI reads archive metadata; the shipped cdylib keeps its authored stripping. +uniffi_kotlin( + name = "generated_bindings", + generator = "//src/native/mobile-bindings:bindgen", + library = "//src/native/mobile-bindings:lib", + configuration = "//src/native/mobile-bindings:uniffi.toml", +) + +sdk_extension_projections( + name = "generated_extensions", + sdk = "kotlin", + generated = "generated/GeneratedExtensions.kt", + descriptors = "generated/OliphauntExtension.kt", +) + +COMMON_SOURCES = glob(["oliphaunt/src/commonMain/kotlin/**/*.kt"], exclude = ["oliphaunt/src/commonMain/kotlin/**/GeneratedExtensions.kt", "oliphaunt/src/commonMain/kotlin/**/OliphauntExtension.kt"]) + [":generated_extensions"] +ANDROID_SOURCES = glob(["oliphaunt/src/androidMain/kotlin/**/*.kt"]) +AIDL_SOURCES = glob(["oliphaunt/src/androidMain/aidl/**/*.aidl"]) +LINUX_EXECUTION = ["@platforms//os:linux", "@platforms//cpu:x86_64"] + +kt_jvm_library( + name = "common", + srcs = COMMON_SOURCES, + deps = ["@oliphaunt_kotlin_maven//:org_jetbrains_kotlinx_kotlinx_coroutines_core"], + target_compatible_with = LINUX_EXECUTION, +) + +kt_jvm_library( + name = "common_test_support", + testonly = True, + srcs = glob(["oliphaunt/src/commonTest/kotlin/**/*.kt", "oliphaunt/src/jvmTest/kotlin/**/*.kt"]), + associates = [":common"], + deps = ["@oliphaunt_kotlin_maven//:org_jetbrains_kotlin_kotlin_test_junit", "@oliphaunt_kotlin_maven//:org_jetbrains_kotlinx_kotlinx_coroutines_test", "@oliphaunt_kotlin_maven//:org_jetbrains_kotlinx_kotlinx_serialization_json"], + target_compatible_with = LINUX_EXECUTION, +) + +[kt_jvm_test( + name = name, + deps = [":common_test_support"], + test_class = "dev.oliphaunt." + test_class, + target_compatible_with = LINUX_EXECUTION, +) for name, test_class in [("database_test", "OliphauntDatabaseTest"), ("broker_test", "BrokerFacadeTest")]] + +kt_jvm_test( + name = "shared_protocol_test", + deps = [":common_test_support"], + test_class = "dev.oliphaunt.SharedProtocolFixtureTest", + data = ["//src/test-fixtures:protocol/query-response-cases.json", "//src/test-fixtures:protocol/structured-sql-cases.json"], + target_compatible_with = LINUX_EXECUTION, +) + +test_suite(name = "common_test", tests = [":database_test", ":broker_test", ":shared_protocol_test"]) + +android_library( + name = "broker_aidl", + idl_srcs = AIDL_SOURCES, + idl_import_root = "oliphaunt/src/androidMain/aidl", + target_compatible_with = LINUX_EXECUTION, +) + +expand_template( + name = "android_manifest", + template = "oliphaunt/src/androidMain/AndroidManifest.xml", + out = "AndroidManifest.native.xml", + substitutions = { + "": "\n " % (KOTLIN["minSdk"], KOTLIN["compileSdk"]), + }, +) + +kt_android_library( + name = "android_classes", + srcs = COMMON_SOURCES + ANDROID_SOURCES + [":generated_bindings"], + manifest = ":android_manifest", + custom_package = KOTLIN["namespace"], + proguard_specs = ["oliphaunt/consumer-rules.pro"], + deps = [":broker_aidl", "@oliphaunt_kotlin_maven//:net_java_dev_jna_jna", "@oliphaunt_kotlin_maven//:org_jetbrains_kotlinx_kotlinx_coroutines_core"], + target_compatible_with = LINUX_EXECUTION, +) + +kt_jvm_library( + name = "android_test_support", + testonly = True, + srcs = glob(["oliphaunt/src/androidUnitTest/kotlin/**/*.kt"]), + associates = [":android_classes"], + deps = ["@oliphaunt_kotlin_maven//:org_jetbrains_kotlin_kotlin_test_junit", "@oliphaunt_kotlin_maven//:org_jetbrains_kotlinx_kotlinx_coroutines_core", "@oliphaunt_kotlin_maven//:org_json_json"], + target_compatible_with = LINUX_EXECUTION, +) + +# JVM tests link Android exception/API types from the same pinned SDK used by +# the compiler. These tests exercise the host implementation, not a device. +java_import( + name = "android_unit_test_runtime", + testonly = True, + jars = ["@oliphaunt_android_sdk_archive//:platforms/android-%s/android.jar" % KOTLIN["compileSdk"]], + target_compatible_with = LINUX_EXECUTION, +) + +[kt_jvm_test( + name = name, + deps = [":android_test_support"], + runtime_deps = [":android_unit_test_runtime"], + test_class = "dev.oliphaunt." + test_class, + data = ["//src/test-fixtures:rust_fixtures"] + (["//src/database-resources:cluster_seed_contract_fixtures"] if name == "android_runtime_assets_test" else []), + target_compatible_with = LINUX_EXECUTION, +) for name, test_class in [("android_configuration_test", "OliphauntAndroidTest"), ("android_java_test", "OliphauntJavaTest"), ("android_runtime_assets_test", "OliphauntAndroidRuntimeAssetsTest")]] + +kt_jvm_test( + name = "native_bindings_test", + deps = [":android_test_support"], + runtime_deps = [":android_unit_test_runtime"], + test_class = "dev.oliphaunt.NativeBindingsTest", + data = ["//src/test-fixtures:rust_fixtures", "//src/native/mobile-bindings:shared", "@kotlin_frozen_native//:inputs.json", "@kotlin_frozen_native//:runtime_linux_x64_gnu"], + jvm_flags = ["-Doliphaunt.native.facts=$(rootpath @kotlin_frozen_native//:inputs.json)", "-Doliphaunt.native.bindings=$(rootpath //src/native/mobile-bindings:shared)"], + target_compatible_with = LINUX_EXECUTION, + size = "medium", +) + +test_suite(name = "android_test", tests = [":android_configuration_test", ":android_java_test", ":android_runtime_assets_test", ":native_bindings_test", "//src/native/sdks/react-native:android_temporary_root_test"]) + +[android_artifact( + name = "mobile_" + abi, + artifact = "//src/native/mobile-bindings:shared", + platform = "//build_defs/android:android_" + abi, + output = "mobile-" + abi + "/liboliphaunt_mobile_bindings.so", +) for abi in ["arm64", "x86_64"]] + +kotlin_maven_package( + name = "android_maven", + coordinate = "dev.oliphaunt:oliphaunt-android", + packaging = "aar", + classes = [":android_classes", ":broker_aidl"], + android_aar = ":android_classes.aar", + native_libraries = {":mobile_arm64": "arm64-v8a", ":mobile_x86_64": "x86_64"}, + sources = COMMON_SOURCES + ANDROID_SOURCES + AIDL_SOURCES + [":generated_bindings"], + legal_sources = ["//:LICENSE", "//:THIRD_PARTY_NOTICES.md", "//:Cargo.lock", "//src/native/mobile-bindings:license_inputs"], + coroutines_jvm = "@oliphaunt_kotlin_maven//:org_jetbrains_kotlinx_kotlinx_coroutines_core_jvm", + target_compatible_with = LINUX_EXECUTION, +) + +# Consumer compilers see the actual final AAR, including merged AIDL classes, +# rather than the producing source/library targets. +aar_import( + name = "installed_android", + aar = ":android_maven_archive", + package = KOTLIN["namespace"], + deps = [ + "@oliphaunt_kotlin_maven//:net_java_dev_jna_jna", + "@oliphaunt_kotlin_maven//:org_jetbrains_annotations", + "@oliphaunt_kotlin_maven//:org_jetbrains_kotlin_kotlin_stdlib", + "@oliphaunt_kotlin_maven//:org_jetbrains_kotlinx_kotlinx_coroutines_core_jvm", + ], + target_compatible_with = LINUX_EXECUTION, +) + +kt_android_library( + name = "installed_public_api_consumer", + srcs = glob(["tests/public-api-consumer/src/main/kotlin/**/*.kt", "tests/public-api-consumer/src/main/java/**/*.java"]), + manifest = ":android_manifest", + custom_package = "dev.oliphaunt.consumer", + deps = [":installed_android", "@oliphaunt_kotlin_maven//:org_jetbrains_kotlinx_kotlinx_coroutines_core"], + target_compatible_with = LINUX_EXECUTION, +) + +kotlin_installed_maven_test( + name = "installed_maven_test", + packages = [":android_maven", "//src/native/sdks/kotlin/oliphaunt-android-gradle-plugin:plugin_maven", "//src/native/sdks/kotlin/oliphaunt-android-gradle-plugin:marker_maven"], + consumer = ":installed_public_api_consumer", + target_compatible_with = LINUX_EXECUTION, + size = "medium", +) + +shipping_export( + name = "shipping_export", + exports = [":android_maven_compiled_shipping_export"], + packages = [":android_maven_shipping", "//src/native/sdks/kotlin/oliphaunt-android-gradle-plugin:plugin_maven_shipping", "//src/native/sdks/kotlin/oliphaunt-android-gradle-plugin:marker_maven_shipping"], + qualification = [ + ":installed_maven_test", + ":database_test", ":broker_test", ":shared_protocol_test", + ":android_configuration_test", ":android_java_test", ":android_runtime_assets_test", ":native_bindings_test", + "//src/native/sdks/react-native:android_temporary_root_test", + "//src/native/sdks/kotlin/oliphaunt-android-gradle-plugin:contract_test", + ":compiled_supplier_analysis_test", + ], + testonly = True, +) + +kotlin_compiled_inputs_test( + name = "compiled_supplier_analysis_test", + target_under_test = ":android_maven_compiled_shipping_export", + maven = ":android_maven", + plugin = "//src/native/sdks/kotlin/oliphaunt-android-gradle-plugin:plugin_maven_shipping", + marker = "//src/native/sdks/kotlin/oliphaunt-android-gradle-plugin:marker_maven_shipping", + target_compatible_with = LINUX_EXECUTION, + size = "small", +) + +kotlin_format_test(name = "format_test", target_compatible_with = LINUX_EXECUTION, size = "small") + +kotlin_android_lint_test( + name = "lint_test", + library = ":android_classes", + additional_classes = [":broker_aidl"], + srcs = [source for source in COMMON_SOURCES if source != ":generated_extensions"] + ANDROID_SOURCES + AIDL_SOURCES, + generated_srcs = [":generated_extensions", ":generated_bindings"], + conventional_files = ["oliphaunt/build.gradle.kts", "build.gradle.kts", "settings.gradle.kts", "gradle/libs.versions.toml", "gradle.properties", "gradle/wrapper/gradle-wrapper.properties"], + manifest = "oliphaunt/src/androidMain/AndroidManifest.xml", + proguard = ["oliphaunt/consumer-rules.pro"], + target_compatible_with = LINUX_EXECUTION, + size = "medium", +) + +source_quality_files() diff --git a/src/native/sdks/kotlin/gradle/libs.versions.toml b/src/native/sdks/kotlin/gradle/libs.versions.toml index 60b1d5c09..9e0d801c4 100644 --- a/src/native/sdks/kotlin/gradle/libs.versions.toml +++ b/src/native/sdks/kotlin/gradle/libs.versions.toml @@ -1,14 +1,23 @@ [versions] android-gradle-plugin = "8.11.1" +android-lint = "31.11.1" kotlin = "2.2.21" kotlinx-coroutines = "1.10.2" kotlinx-serialization = "1.8.1" +jna = "5.18.1" +org-json = "20240303" maven-publish = "0.34.0" spotless = "8.5.1" +ktlint = "1.8.0" detekt = "2.0.0-alpha.3" kover = "0.9.8" [libraries] +kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" } +ktlint-cli = { module = "com.pinterest.ktlint:ktlint-cli", version.ref = "ktlint" } +kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" } +jna = { module = "net.java.dev.jna:jna", version.ref = "jna" } +org-json = { module = "org.json:json", version.ref = "org-json" } kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" } kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" } diff --git a/src/native/sdks/kotlin/maven_install.json b/src/native/sdks/kotlin/maven_install.json new file mode 100755 index 000000000..78f281794 --- /dev/null +++ b/src/native/sdks/kotlin/maven_install.json @@ -0,0 +1,2016 @@ +{ + "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL", + "__INPUT_ARTIFACTS_HASH": { + "com.pinterest.ktlint:ktlint-cli": 1585961342, + "net.java.dev.jna:jna": 929040997, + "org.jetbrains.kotlin:kotlin-stdlib": 52847824, + "org.jetbrains.kotlin:kotlin-test-junit": -6674303, + "org.jetbrains.kotlinx:kotlinx-coroutines-core": -636748508, + "org.jetbrains.kotlinx:kotlinx-coroutines-test": -797019823, + "org.jetbrains.kotlinx:kotlinx-serialization-json": -293138828, + "org.json:json": 1214128896, + "repositories": 514854214 + }, + "__RESOLVED_ARTIFACTS_HASH": { + "ch.qos.logback:logback-classic": -2105031400, + "ch.qos.logback:logback-core": 244402530, + "com.github.ajalt.clikt:clikt-core-jvm": 1140283057, + "com.github.ajalt.clikt:clikt-jvm": 1187237415, + "com.github.ajalt.colormath:colormath-jvm": -1907886187, + "com.github.ajalt.mordant:mordant-core-jvm": -71961512, + "com.github.ajalt.mordant:mordant-jvm": 1387559391, + "com.github.ajalt.mordant:mordant-jvm-ffm-jvm": 679968147, + "com.github.ajalt.mordant:mordant-jvm-graal-ffi-jvm": 675962156, + "com.github.ajalt.mordant:mordant-jvm-jna-jvm": -1467220389, + "com.pinterest.ktlint:ktlint-cli": 276003675, + "com.pinterest.ktlint:ktlint-cli-reporter-baseline": -712073882, + "com.pinterest.ktlint:ktlint-cli-reporter-checkstyle": 1080968215, + "com.pinterest.ktlint:ktlint-cli-reporter-core": -1802725104, + "com.pinterest.ktlint:ktlint-cli-reporter-format": 136580934, + "com.pinterest.ktlint:ktlint-cli-reporter-html": 1573168496, + "com.pinterest.ktlint:ktlint-cli-reporter-json": 2078422396, + "com.pinterest.ktlint:ktlint-cli-reporter-plain": 1594021539, + "com.pinterest.ktlint:ktlint-cli-reporter-plain-summary": -531834123, + "com.pinterest.ktlint:ktlint-cli-reporter-sarif": -1324534591, + "com.pinterest.ktlint:ktlint-cli-ruleset-core": -16574195, + "com.pinterest.ktlint:ktlint-logger": 728812393, + "com.pinterest.ktlint:ktlint-rule-engine": 2125157541, + "com.pinterest.ktlint:ktlint-rule-engine-core": 1094034415, + "com.pinterest.ktlint:ktlint-ruleset-standard": -151339667, + "dev.drewhamilton.poko:poko-annotations-jvm": 1625176628, + "io.github.detekt.sarif4k:sarif4k-jvm": -1105186400, + "io.github.oshai:kotlin-logging-jvm": -1377412556, + "junit:junit": 712711302, + "net.java.dev.jna:jna": -1951542637, + "org.ec4j.core:ec4j-core": 1512281368, + "org.hamcrest:hamcrest-core": 866476646, + "org.jetbrains.kotlin:kotlin-compiler-embeddable": -1321290013, + "org.jetbrains.kotlin:kotlin-daemon-embeddable": 2061427585, + "org.jetbrains.kotlin:kotlin-reflect": -1130939180, + "org.jetbrains.kotlin:kotlin-script-runtime": -1297335692, + "org.jetbrains.kotlin:kotlin-stdlib": -1768306952, + "org.jetbrains.kotlin:kotlin-test": -253700323, + "org.jetbrains.kotlin:kotlin-test-junit": 1228550349, + "org.jetbrains.kotlinx:kotlinx-coroutines-core": -1644507233, + "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm": 815382491, + "org.jetbrains.kotlinx:kotlinx-coroutines-test": -997868401, + "org.jetbrains.kotlinx:kotlinx-coroutines-test-jvm": -1064042162, + "org.jetbrains.kotlinx:kotlinx-serialization-core-jvm": -1733165943, + "org.jetbrains.kotlinx:kotlinx-serialization-json": 872430150, + "org.jetbrains.kotlinx:kotlinx-serialization-json-jvm": 457554054, + "org.jetbrains:annotations": 1311519737, + "org.json:json": 151278621, + "org.slf4j:slf4j-api": -332179038 + }, + "artifacts": { + "ch.qos.logback:logback-classic": { + "shasums": { + "jar": "3f63cbc593b91670f75890ab256aa47c123a9b125185939a272c720ca1417c2c" + }, + "version": "1.3.16" + }, + "ch.qos.logback:logback-core": { + "shasums": { + "jar": "f153c7d582ad19219c906dd728df335232790663f5b3d2db187ac83d9e5a3b8b" + }, + "version": "1.3.16" + }, + "com.github.ajalt.clikt:clikt-core-jvm": { + "shasums": { + "jar": "69cba94a2291f74b78c88239cd8b67eaf3f08e0dad297749abe6477b3e9b81b1" + }, + "version": "5.0.3" + }, + "com.github.ajalt.clikt:clikt-jvm": { + "shasums": { + "jar": "9cd19e04782f461dffeb183d17e576984febb7934932cb406646ac41e428863b" + }, + "version": "5.0.3" + }, + "com.github.ajalt.colormath:colormath-jvm": { + "shasums": { + "jar": "59f741adfe62053066782d8b1a45afd06685a4bc64b33277e54876b993ed885c" + }, + "version": "3.6.0" + }, + "com.github.ajalt.mordant:mordant-core-jvm": { + "shasums": { + "jar": "9cf9b46d1f49f2d6cf2635462b29dc59e0c29b1fb2f085b3312888bbe9c7cd31" + }, + "version": "3.0.1" + }, + "com.github.ajalt.mordant:mordant-jvm": { + "shasums": { + "jar": "9ed3b976fcccc78da746d49866fa8ebb8f10530a93c544ea0420259a607dd95e" + }, + "version": "3.0.1" + }, + "com.github.ajalt.mordant:mordant-jvm-ffm-jvm": { + "shasums": { + "jar": "2041c2f5f7b87095b115cb19155ee9257451854d08e5b8671165b43bc7e114cf" + }, + "version": "3.0.1" + }, + "com.github.ajalt.mordant:mordant-jvm-graal-ffi-jvm": { + "shasums": { + "jar": "6dd4bebc164aeacddacc8f98e8f871e00fd21ce7bc2eb0d18230ea83bddfc86a" + }, + "version": "3.0.1" + }, + "com.github.ajalt.mordant:mordant-jvm-jna-jvm": { + "shasums": { + "jar": "41063442c8891b2774536a9b87a5062a7fd20e6f1949974c6da72f49472d6f4d" + }, + "version": "3.0.1" + }, + "com.pinterest.ktlint:ktlint-cli": { + "shasums": { + "jar": "eb540f5ad442ba0b3392c7947c87929dab709ac056fdde7e300beaffcb86e243" + }, + "version": "1.8.0" + }, + "com.pinterest.ktlint:ktlint-cli-reporter-baseline": { + "shasums": { + "jar": "be11607d9cebcc1456ab6ccb2578484c0f63c0288ad0fff278813d7251b8f6ed" + }, + "version": "1.8.0" + }, + "com.pinterest.ktlint:ktlint-cli-reporter-checkstyle": { + "shasums": { + "jar": "c8c0789cf5e146d9bf8f57b1e8d1af928f1eac5653a4fbc0ccfcbe5d7906e427" + }, + "version": "1.8.0" + }, + "com.pinterest.ktlint:ktlint-cli-reporter-core": { + "shasums": { + "jar": "554d980c1e8b0afd6404dcc77e6022e0466273d1300fda5a6d25a85759cbafaa" + }, + "version": "1.8.0" + }, + "com.pinterest.ktlint:ktlint-cli-reporter-format": { + "shasums": { + "jar": "0f6639379e3341ffea2ca6aff2b72e904e778cdcba31f885edb412270e591bb8" + }, + "version": "1.8.0" + }, + "com.pinterest.ktlint:ktlint-cli-reporter-html": { + "shasums": { + "jar": "9c45e72d24ae81b2b1c028fcf95c8d8f914a050fcf6029e2d4c2cd9c55340d72" + }, + "version": "1.8.0" + }, + "com.pinterest.ktlint:ktlint-cli-reporter-json": { + "shasums": { + "jar": "115db6ad3a6eb18b33bb44a0f7b8dc7639b429ba1fa4fc39863d163a3003efb5" + }, + "version": "1.8.0" + }, + "com.pinterest.ktlint:ktlint-cli-reporter-plain": { + "shasums": { + "jar": "05bd03b465fe6bfe885777adf8c251bfe6ddc004086dbfcdfacb0061936b111d" + }, + "version": "1.8.0" + }, + "com.pinterest.ktlint:ktlint-cli-reporter-plain-summary": { + "shasums": { + "jar": "003eb83d33467f43bf32b6cb7390d387a823301344fd0705750f9cf4fa42fb28" + }, + "version": "1.8.0" + }, + "com.pinterest.ktlint:ktlint-cli-reporter-sarif": { + "shasums": { + "jar": "8dd41428e258947f9731e7c14f80b795b7d19321c3b4f8eac7549dc335824f35" + }, + "version": "1.8.0" + }, + "com.pinterest.ktlint:ktlint-cli-ruleset-core": { + "shasums": { + "jar": "3cde07dd36b3d2b0ad9bf6320a15d74a1d16999361a2943ec89a77035f88cef8" + }, + "version": "1.8.0" + }, + "com.pinterest.ktlint:ktlint-logger": { + "shasums": { + "jar": "323a2587bc5d658acac2ab84081be1a91ec272447ddae23e889ffeeea03a6a19" + }, + "version": "1.8.0" + }, + "com.pinterest.ktlint:ktlint-rule-engine": { + "shasums": { + "jar": "26b2bc7b840dad219d56a276f11fe4a39c35e567a061d719a50914b30f403772" + }, + "version": "1.8.0" + }, + "com.pinterest.ktlint:ktlint-rule-engine-core": { + "shasums": { + "jar": "bd99dbc888be66aea31db45f4dce5ca56f465afbf02fee639bd2346d2cd864ec" + }, + "version": "1.8.0" + }, + "com.pinterest.ktlint:ktlint-ruleset-standard": { + "shasums": { + "jar": "82972b4cb2e9cd682840061b2de9d342044846f0d816ecc58f50958824760d69" + }, + "version": "1.8.0" + }, + "dev.drewhamilton.poko:poko-annotations-jvm": { + "shasums": { + "jar": "173fc443f30b8185295c9c9b9401272be84f553e5835e3767c7daafe5be606c9" + }, + "version": "0.20.1" + }, + "io.github.detekt.sarif4k:sarif4k-jvm": { + "shasums": { + "jar": "b3ac96dd97acba8318dbe26f6a432d6c6db91c46c780805e8928b8103e5763dc" + }, + "version": "0.6.0" + }, + "io.github.oshai:kotlin-logging-jvm": { + "shasums": { + "jar": "c373f7f4c9efc85c4f70f11519f2a1b7878bc0ed75a325364d034af3fa21f776" + }, + "version": "7.0.13" + }, + "junit:junit": { + "shasums": { + "jar": "8e495b634469d64fb8acfa3495a065cbacc8a0fff55ce1e31007be4c16dc57d3" + }, + "version": "4.13.2" + }, + "net.java.dev.jna:jna": { + "shasums": { + "jar": "260c4b1e22b1db9e110ee441c4f13ce115f841fa48c41d78750986214b395557" + }, + "version": "5.18.1" + }, + "org.ec4j.core:ec4j-core": { + "shasums": { + "jar": "d73dee44fefb725dfc658267465fe5a768a666313d8acd701209f5836f1431d8" + }, + "version": "1.1.1" + }, + "org.hamcrest:hamcrest-core": { + "shasums": { + "jar": "66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9" + }, + "version": "1.3" + }, + "org.jetbrains.kotlin:kotlin-compiler-embeddable": { + "shasums": { + "jar": "9588fa696ac5507af764fd5660df6894185e12704ec1bc3f5cb772af4987f295" + }, + "version": "2.2.21" + }, + "org.jetbrains.kotlin:kotlin-daemon-embeddable": { + "shasums": { + "jar": "91c0673c22e44b054ae0314d323860ebe1f3aff3f0ebc74fff82c4733dde09be" + }, + "version": "2.2.21" + }, + "org.jetbrains.kotlin:kotlin-reflect": { + "shasums": { + "jar": "3277ac102ae17aad10a55abec75ff5696c8d109790396434b496e75087854203" + }, + "version": "1.6.10" + }, + "org.jetbrains.kotlin:kotlin-script-runtime": { + "shasums": { + "jar": "2b1519b427b514d1536c1b425674b03fe914af637924028e9959c6625442df51" + }, + "version": "2.2.21" + }, + "org.jetbrains.kotlin:kotlin-stdlib": { + "shasums": { + "jar": "6558a3d233da56a20934b32159f9db5f86ed5816ef098f78a2c223dc6abb79dd" + }, + "version": "2.2.21" + }, + "org.jetbrains.kotlin:kotlin-test": { + "shasums": { + "jar": "612966ddee4d3d0486156f10c77a57c5c47dae65eb98a2bddf34cf2aeeb894c4" + }, + "version": "2.2.21" + }, + "org.jetbrains.kotlin:kotlin-test-junit": { + "shasums": { + "jar": "5d88fcf9a56ee501fbf874ee65e82375ea1221423867c598ff29b11e0ad49317" + }, + "version": "2.2.21" + }, + "org.jetbrains.kotlinx:kotlinx-coroutines-core": { + "shasums": { + "jar": "319b653009d49c70982f98df29cc84fc7025b092cb0571c8e7532e3ad4366dae" + }, + "version": "1.10.2" + }, + "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm": { + "shasums": { + "jar": "5ca175b38df331fd64155b35cd8cae1251fa9ee369709b36d42e0a288ccce3fd" + }, + "version": "1.10.2" + }, + "org.jetbrains.kotlinx:kotlinx-coroutines-test": { + "shasums": { + "jar": "fadbe04fbda7a27728770d8eaecbdec0a9b0b29693c20cbea77655d783d8bd78" + }, + "version": "1.10.2" + }, + "org.jetbrains.kotlinx:kotlinx-coroutines-test-jvm": { + "shasums": { + "jar": "590a549f8c1db590c9d98a8a20424a1f581a34162a369e6a6bd884ce7d36d3d7" + }, + "version": "1.10.2" + }, + "org.jetbrains.kotlinx:kotlinx-serialization-core-jvm": { + "shasums": { + "jar": "3565b6d4d789bf70683c45566944287fc1d8dc75c23d98bd87d01059cc76f2b3" + }, + "version": "1.8.1" + }, + "org.jetbrains.kotlinx:kotlinx-serialization-json": { + "shasums": { + "jar": "58adf3358a0f99dd8d66a550fbe19064d395e0d5f7f1e46515cd3470a56fbbb0" + }, + "version": "1.8.1" + }, + "org.jetbrains.kotlinx:kotlinx-serialization-json-jvm": { + "shasums": { + "jar": "8769e5647557e3700919c32d508f5c5dad53c5d8234cd10846354fbcff14aa24" + }, + "version": "1.8.1" + }, + "org.jetbrains:annotations": { + "shasums": { + "jar": "7b0f19724082cbfcbc66e5abea2b9bc92cf08a1ea11e191933ed43801eb3cd05" + }, + "version": "23.0.0" + }, + "org.json:json": { + "shasums": { + "jar": "3cf6cd6892e32e2b4c1c39e0f52f5248a2f5b37646fdfbb79a66b46b618414ed" + }, + "version": "20240303" + }, + "org.slf4j:slf4j-api": { + "shasums": { + "jar": "5d6298b93a1905c32cda6478808ac14c2d4a47e91535e53c41f7feeb85d946f4" + }, + "version": "2.0.7" + } + }, + "dependencies": { + "ch.qos.logback:logback-classic": [ + "ch.qos.logback:logback-core", + "org.slf4j:slf4j-api" + ], + "com.github.ajalt.clikt:clikt-core-jvm": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.github.ajalt.clikt:clikt-jvm": [ + "com.github.ajalt.clikt:clikt-core-jvm", + "com.github.ajalt.mordant:mordant-jvm", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.github.ajalt.colormath:colormath-jvm": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.github.ajalt.mordant:mordant-core-jvm": [ + "com.github.ajalt.colormath:colormath-jvm", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.github.ajalt.mordant:mordant-jvm": [ + "com.github.ajalt.mordant:mordant-core-jvm", + "com.github.ajalt.mordant:mordant-jvm-ffm-jvm", + "com.github.ajalt.mordant:mordant-jvm-graal-ffi-jvm", + "com.github.ajalt.mordant:mordant-jvm-jna-jvm", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.github.ajalt.mordant:mordant-jvm-ffm-jvm": [ + "com.github.ajalt.mordant:mordant-core-jvm", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.github.ajalt.mordant:mordant-jvm-graal-ffi-jvm": [ + "com.github.ajalt.mordant:mordant-core-jvm", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.github.ajalt.mordant:mordant-jvm-jna-jvm": [ + "com.github.ajalt.mordant:mordant-core-jvm", + "net.java.dev.jna:jna", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.pinterest.ktlint:ktlint-cli": [ + "ch.qos.logback:logback-classic", + "com.github.ajalt.clikt:clikt-jvm", + "com.pinterest.ktlint:ktlint-cli-reporter-baseline", + "com.pinterest.ktlint:ktlint-cli-reporter-checkstyle", + "com.pinterest.ktlint:ktlint-cli-reporter-core", + "com.pinterest.ktlint:ktlint-cli-reporter-format", + "com.pinterest.ktlint:ktlint-cli-reporter-html", + "com.pinterest.ktlint:ktlint-cli-reporter-json", + "com.pinterest.ktlint:ktlint-cli-reporter-plain", + "com.pinterest.ktlint:ktlint-cli-reporter-plain-summary", + "com.pinterest.ktlint:ktlint-cli-reporter-sarif", + "com.pinterest.ktlint:ktlint-logger", + "com.pinterest.ktlint:ktlint-rule-engine", + "com.pinterest.ktlint:ktlint-ruleset-standard", + "dev.drewhamilton.poko:poko-annotations-jvm", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.pinterest.ktlint:ktlint-cli-reporter-baseline": [ + "com.pinterest.ktlint:ktlint-cli-reporter-core", + "com.pinterest.ktlint:ktlint-logger", + "com.pinterest.ktlint:ktlint-rule-engine-core", + "dev.drewhamilton.poko:poko-annotations-jvm", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.pinterest.ktlint:ktlint-cli-reporter-checkstyle": [ + "com.pinterest.ktlint:ktlint-cli-reporter-core", + "dev.drewhamilton.poko:poko-annotations-jvm", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.pinterest.ktlint:ktlint-cli-reporter-core": [ + "dev.drewhamilton.poko:poko-annotations-jvm", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.pinterest.ktlint:ktlint-cli-reporter-format": [ + "com.pinterest.ktlint:ktlint-cli-reporter-core", + "dev.drewhamilton.poko:poko-annotations-jvm", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.pinterest.ktlint:ktlint-cli-reporter-html": [ + "com.pinterest.ktlint:ktlint-cli-reporter-core", + "dev.drewhamilton.poko:poko-annotations-jvm", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.pinterest.ktlint:ktlint-cli-reporter-json": [ + "com.pinterest.ktlint:ktlint-cli-reporter-core", + "dev.drewhamilton.poko:poko-annotations-jvm", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.pinterest.ktlint:ktlint-cli-reporter-plain": [ + "com.pinterest.ktlint:ktlint-cli-reporter-core", + "dev.drewhamilton.poko:poko-annotations-jvm", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.pinterest.ktlint:ktlint-cli-reporter-plain-summary": [ + "com.pinterest.ktlint:ktlint-cli-reporter-core", + "dev.drewhamilton.poko:poko-annotations-jvm", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.pinterest.ktlint:ktlint-cli-reporter-sarif": [ + "com.pinterest.ktlint:ktlint-cli-reporter-core", + "dev.drewhamilton.poko:poko-annotations-jvm", + "io.github.detekt.sarif4k:sarif4k-jvm", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.pinterest.ktlint:ktlint-cli-ruleset-core": [ + "com.pinterest.ktlint:ktlint-rule-engine-core", + "dev.drewhamilton.poko:poko-annotations-jvm", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.pinterest.ktlint:ktlint-logger": [ + "dev.drewhamilton.poko:poko-annotations-jvm", + "io.github.oshai:kotlin-logging-jvm", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.pinterest.ktlint:ktlint-rule-engine": [ + "com.pinterest.ktlint:ktlint-logger", + "com.pinterest.ktlint:ktlint-rule-engine-core", + "dev.drewhamilton.poko:poko-annotations-jvm", + "org.ec4j.core:ec4j-core", + "org.jetbrains.kotlin:kotlin-compiler-embeddable", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.pinterest.ktlint:ktlint-rule-engine-core": [ + "com.pinterest.ktlint:ktlint-logger", + "dev.drewhamilton.poko:poko-annotations-jvm", + "org.ec4j.core:ec4j-core", + "org.jetbrains.kotlin:kotlin-compiler-embeddable", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "com.pinterest.ktlint:ktlint-ruleset-standard": [ + "com.pinterest.ktlint:ktlint-cli-ruleset-core", + "com.pinterest.ktlint:ktlint-logger", + "com.pinterest.ktlint:ktlint-rule-engine-core", + "dev.drewhamilton.poko:poko-annotations-jvm", + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "dev.drewhamilton.poko:poko-annotations-jvm": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "io.github.detekt.sarif4k:sarif4k-jvm": [ + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlinx:kotlinx-serialization-json-jvm" + ], + "io.github.oshai:kotlin-logging-jvm": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "junit:junit": [ + "org.hamcrest:hamcrest-core" + ], + "org.jetbrains.kotlin:kotlin-compiler-embeddable": [ + "org.jetbrains.kotlin:kotlin-daemon-embeddable", + "org.jetbrains.kotlin:kotlin-reflect", + "org.jetbrains.kotlin:kotlin-script-runtime", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm" + ], + "org.jetbrains.kotlin:kotlin-stdlib": [ + "org.jetbrains:annotations" + ], + "org.jetbrains.kotlin:kotlin-test": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "org.jetbrains.kotlin:kotlin-test-junit": [ + "junit:junit", + "org.jetbrains.kotlin:kotlin-test" + ], + "org.jetbrains.kotlinx:kotlinx-coroutines-core": [ + "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm" + ], + "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm": [ + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains:annotations" + ], + "org.jetbrains.kotlinx:kotlinx-coroutines-test": [ + "org.jetbrains.kotlinx:kotlinx-coroutines-test-jvm" + ], + "org.jetbrains.kotlinx:kotlinx-coroutines-test-jvm": [ + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm", + "org.jetbrains:annotations" + ], + "org.jetbrains.kotlinx:kotlinx-serialization-core-jvm": [ + "org.jetbrains.kotlin:kotlin-stdlib" + ], + "org.jetbrains.kotlinx:kotlinx-serialization-json": [ + "org.jetbrains.kotlinx:kotlinx-serialization-json-jvm" + ], + "org.jetbrains.kotlinx:kotlinx-serialization-json-jvm": [ + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlinx:kotlinx-serialization-core-jvm" + ] + }, + "packages": { + "ch.qos.logback:logback-classic": [ + "ch.qos.logback.classic", + "ch.qos.logback.classic.boolex", + "ch.qos.logback.classic.encoder", + "ch.qos.logback.classic.filter", + "ch.qos.logback.classic.helpers", + "ch.qos.logback.classic.html", + "ch.qos.logback.classic.joran", + "ch.qos.logback.classic.joran.action", + "ch.qos.logback.classic.joran.sanity", + "ch.qos.logback.classic.joran.serializedModel", + "ch.qos.logback.classic.jul", + "ch.qos.logback.classic.layout", + "ch.qos.logback.classic.log4j", + "ch.qos.logback.classic.model", + "ch.qos.logback.classic.model.processor", + "ch.qos.logback.classic.model.util", + "ch.qos.logback.classic.net", + "ch.qos.logback.classic.net.server", + "ch.qos.logback.classic.pattern", + "ch.qos.logback.classic.pattern.color", + "ch.qos.logback.classic.selector", + "ch.qos.logback.classic.selector.servlet", + "ch.qos.logback.classic.servlet", + "ch.qos.logback.classic.sift", + "ch.qos.logback.classic.spi", + "ch.qos.logback.classic.turbo", + "ch.qos.logback.classic.util" + ], + "ch.qos.logback:logback-core": [ + "ch.qos.logback.core", + "ch.qos.logback.core.boolex", + "ch.qos.logback.core.encoder", + "ch.qos.logback.core.filter", + "ch.qos.logback.core.helpers", + "ch.qos.logback.core.hook", + "ch.qos.logback.core.html", + "ch.qos.logback.core.joran", + "ch.qos.logback.core.joran.action", + "ch.qos.logback.core.joran.conditional", + "ch.qos.logback.core.joran.event", + "ch.qos.logback.core.joran.node", + "ch.qos.logback.core.joran.sanity", + "ch.qos.logback.core.joran.spi", + "ch.qos.logback.core.joran.util", + "ch.qos.logback.core.joran.util.beans", + "ch.qos.logback.core.layout", + "ch.qos.logback.core.model", + "ch.qos.logback.core.model.conditional", + "ch.qos.logback.core.model.processor", + "ch.qos.logback.core.model.processor.conditional", + "ch.qos.logback.core.model.util", + "ch.qos.logback.core.net", + "ch.qos.logback.core.net.server", + "ch.qos.logback.core.net.ssl", + "ch.qos.logback.core.pattern", + "ch.qos.logback.core.pattern.color", + "ch.qos.logback.core.pattern.parser", + "ch.qos.logback.core.pattern.util", + "ch.qos.logback.core.property", + "ch.qos.logback.core.read", + "ch.qos.logback.core.recovery", + "ch.qos.logback.core.rolling", + "ch.qos.logback.core.rolling.helper", + "ch.qos.logback.core.sift", + "ch.qos.logback.core.spi", + "ch.qos.logback.core.status", + "ch.qos.logback.core.subst", + "ch.qos.logback.core.testUtil", + "ch.qos.logback.core.util" + ], + "com.github.ajalt.clikt:clikt-core-jvm": [ + "com.github.ajalt.clikt.command", + "com.github.ajalt.clikt.completion", + "com.github.ajalt.clikt.core", + "com.github.ajalt.clikt.internal", + "com.github.ajalt.clikt.output", + "com.github.ajalt.clikt.parameters.arguments", + "com.github.ajalt.clikt.parameters.groups", + "com.github.ajalt.clikt.parameters.internal", + "com.github.ajalt.clikt.parameters.options", + "com.github.ajalt.clikt.parameters.transform", + "com.github.ajalt.clikt.parameters.types", + "com.github.ajalt.clikt.parsers", + "com.github.ajalt.clikt.sources" + ], + "com.github.ajalt.clikt:clikt-jvm": [ + "com.github.ajalt.clikt.command", + "com.github.ajalt.clikt.core", + "com.github.ajalt.clikt.output", + "com.github.ajalt.clikt.parameters.options", + "com.github.ajalt.clikt.parameters.transform", + "com.github.ajalt.clikt.testing" + ], + "com.github.ajalt.colormath:colormath-jvm": [ + "com.github.ajalt.colormath", + "com.github.ajalt.colormath.calculate", + "com.github.ajalt.colormath.internal", + "com.github.ajalt.colormath.model", + "com.github.ajalt.colormath.transform" + ], + "com.github.ajalt.mordant:mordant-core-jvm": [ + "com.github.ajalt.mordant.animation", + "com.github.ajalt.mordant.animation.progress", + "com.github.ajalt.mordant.input", + "com.github.ajalt.mordant.internal", + "com.github.ajalt.mordant.internal.gen", + "com.github.ajalt.mordant.platform", + "com.github.ajalt.mordant.rendering", + "com.github.ajalt.mordant.table", + "com.github.ajalt.mordant.terminal", + "com.github.ajalt.mordant.terminal.terminalinterface", + "com.github.ajalt.mordant.widgets", + "com.github.ajalt.mordant.widgets.progress" + ], + "com.github.ajalt.mordant:mordant-jvm-ffm-jvm": [ + "com.github.ajalt.mordant.terminal.terminalinterface.ffm" + ], + "com.github.ajalt.mordant:mordant-jvm-graal-ffi-jvm": [ + "com.github.ajalt.mordant.terminal.terminalinterface.nativeimage" + ], + "com.github.ajalt.mordant:mordant-jvm-jna-jvm": [ + "com.github.ajalt.mordant.terminal.terminalinterface.jna" + ], + "com.pinterest.ktlint:ktlint-cli": [ + "com.pinterest.ktlint", + "com.pinterest.ktlint.cli.internal" + ], + "com.pinterest.ktlint:ktlint-cli-reporter-baseline": [ + "com.pinterest.ktlint.cli.reporter.baseline" + ], + "com.pinterest.ktlint:ktlint-cli-reporter-checkstyle": [ + "com.pinterest.ktlint.cli.reporter.checkstyle" + ], + "com.pinterest.ktlint:ktlint-cli-reporter-core": [ + "com.pinterest.ktlint.cli.reporter.core.api" + ], + "com.pinterest.ktlint:ktlint-cli-reporter-format": [ + "com.pinterest.ktlint.cli.reporter.format" + ], + "com.pinterest.ktlint:ktlint-cli-reporter-html": [ + "com.pinterest.ktlint.cli.reporter.html" + ], + "com.pinterest.ktlint:ktlint-cli-reporter-json": [ + "com.pinterest.ktlint.cli.reporter.json" + ], + "com.pinterest.ktlint:ktlint-cli-reporter-plain": [ + "com.pinterest.ktlint.cli.reporter.plain" + ], + "com.pinterest.ktlint:ktlint-cli-reporter-plain-summary": [ + "com.pinterest.ktlint.cli.reporter.plainsummary" + ], + "com.pinterest.ktlint:ktlint-cli-reporter-sarif": [ + "com.pinterest.ktlint.cli.reporter.sarif" + ], + "com.pinterest.ktlint:ktlint-cli-ruleset-core": [ + "com.pinterest.ktlint.cli.ruleset.core.api" + ], + "com.pinterest.ktlint:ktlint-logger": [ + "com.pinterest.ktlint.logger.api" + ], + "com.pinterest.ktlint:ktlint-rule-engine": [ + "com.pinterest.ktlint.rule.engine.api", + "com.pinterest.ktlint.rule.engine.internal", + "com.pinterest.ktlint.rule.engine.internal.rulefilter", + "com.pinterest.ktlint.rule.engine.internal.rules" + ], + "com.pinterest.ktlint:ktlint-rule-engine-core": [ + "com.pinterest.ktlint.rule.engine.core.api", + "com.pinterest.ktlint.rule.engine.core.api.editorconfig", + "com.pinterest.ktlint.rule.engine.core.api.editorconfig.ec4j", + "com.pinterest.ktlint.rule.engine.core.internal", + "com.pinterest.ktlint.rule.engine.core.util" + ], + "com.pinterest.ktlint:ktlint-ruleset-standard": [ + "com.pinterest.ktlint.ruleset.standard", + "com.pinterest.ktlint.ruleset.standard.rules", + "com.pinterest.ktlint.ruleset.standard.rules.internal", + "com.pinterest.ktlint.ruleset.standard.rules.internal.importordering" + ], + "dev.drewhamilton.poko:poko-annotations-jvm": [ + "dev.drewhamilton.poko" + ], + "io.github.detekt.sarif4k:sarif4k-jvm": [ + "io.github.detekt.sarif4k" + ], + "io.github.oshai:kotlin-logging-jvm": [ + "io.github.oshai.kotlinlogging", + "io.github.oshai.kotlinlogging.coroutines", + "io.github.oshai.kotlinlogging.internal", + "io.github.oshai.kotlinlogging.jul.internal", + "io.github.oshai.kotlinlogging.logback", + "io.github.oshai.kotlinlogging.logback.internal", + "io.github.oshai.kotlinlogging.slf4j", + "io.github.oshai.kotlinlogging.slf4j.internal" + ], + "junit:junit": [ + "junit.extensions", + "junit.framework", + "junit.runner", + "junit.textui", + "org.junit", + "org.junit.experimental", + "org.junit.experimental.categories", + "org.junit.experimental.max", + "org.junit.experimental.results", + "org.junit.experimental.runners", + "org.junit.experimental.theories", + "org.junit.experimental.theories.internal", + "org.junit.experimental.theories.suppliers", + "org.junit.function", + "org.junit.internal", + "org.junit.internal.builders", + "org.junit.internal.management", + "org.junit.internal.matchers", + "org.junit.internal.requests", + "org.junit.internal.runners", + "org.junit.internal.runners.model", + "org.junit.internal.runners.rules", + "org.junit.internal.runners.statements", + "org.junit.matchers", + "org.junit.rules", + "org.junit.runner", + "org.junit.runner.manipulation", + "org.junit.runner.notification", + "org.junit.runners", + "org.junit.runners.model", + "org.junit.runners.parameterized", + "org.junit.validator" + ], + "net.java.dev.jna:jna": [ + "com.sun.jna", + "com.sun.jna.internal", + "com.sun.jna.ptr", + "com.sun.jna.win32" + ], + "org.ec4j.core:ec4j-core": [ + "org.ec4j.core", + "org.ec4j.core.cli", + "org.ec4j.core.model", + "org.ec4j.core.parser" + ], + "org.hamcrest:hamcrest-core": [ + "org.hamcrest", + "org.hamcrest.core", + "org.hamcrest.internal" + ], + "org.jetbrains.kotlin:kotlin-compiler-embeddable": [ + "org.jetbrains.concurrency", + "org.jetbrains.kotlin", + "org.jetbrains.kotlin.analysis.decompiled.light.classes", + "org.jetbrains.kotlin.analysis.decompiled.light.classes.origin", + "org.jetbrains.kotlin.analysis.decompiler.js", + "org.jetbrains.kotlin.analysis.decompiler.konan", + "org.jetbrains.kotlin.analysis.decompiler.psi", + "org.jetbrains.kotlin.analysis.decompiler.psi.file", + "org.jetbrains.kotlin.analysis.decompiler.psi.text", + "org.jetbrains.kotlin.analysis.decompiler.stub", + "org.jetbrains.kotlin.analysis.decompiler.stub.file", + "org.jetbrains.kotlin.analysis.decompiler.stub.flags", + "org.jetbrains.kotlin.analyzer", + "org.jetbrains.kotlin.analyzer.common", + "org.jetbrains.kotlin.asJava", + "org.jetbrains.kotlin.asJava.builder", + "org.jetbrains.kotlin.asJava.classes", + "org.jetbrains.kotlin.asJava.elements", + "org.jetbrains.kotlin.asJava.finder", + "org.jetbrains.kotlin.backend.common", + "org.jetbrains.kotlin.backend.common.actualizer", + "org.jetbrains.kotlin.backend.common.actualizer.checker", + "org.jetbrains.kotlin.backend.common.checkers", + "org.jetbrains.kotlin.backend.common.checkers.context", + "org.jetbrains.kotlin.backend.common.checkers.declaration", + "org.jetbrains.kotlin.backend.common.checkers.expression", + "org.jetbrains.kotlin.backend.common.checkers.symbol", + "org.jetbrains.kotlin.backend.common.checkers.type", + "org.jetbrains.kotlin.backend.common.descriptors", + "org.jetbrains.kotlin.backend.common.diagnostics", + "org.jetbrains.kotlin.backend.common.extensions", + "org.jetbrains.kotlin.backend.common.ir", + "org.jetbrains.kotlin.backend.common.linkage", + "org.jetbrains.kotlin.backend.common.linkage.issues", + "org.jetbrains.kotlin.backend.common.linkage.partial", + "org.jetbrains.kotlin.backend.common.lower", + "org.jetbrains.kotlin.backend.common.lower.coroutines", + "org.jetbrains.kotlin.backend.common.lower.inline", + "org.jetbrains.kotlin.backend.common.lower.loops", + "org.jetbrains.kotlin.backend.common.lower.loops.handlers", + "org.jetbrains.kotlin.backend.common.lower.optimizations", + "org.jetbrains.kotlin.backend.common.output", + "org.jetbrains.kotlin.backend.common.overrides", + "org.jetbrains.kotlin.backend.common.phaser", + "org.jetbrains.kotlin.backend.common.serialization", + "org.jetbrains.kotlin.backend.common.serialization.encodings", + "org.jetbrains.kotlin.backend.common.serialization.mangle", + "org.jetbrains.kotlin.backend.common.serialization.mangle.descriptor", + "org.jetbrains.kotlin.backend.common.serialization.mangle.ir", + "org.jetbrains.kotlin.backend.common.serialization.metadata", + "org.jetbrains.kotlin.backend.common.serialization.proto", + "org.jetbrains.kotlin.backend.common.serialization.signature", + "org.jetbrains.kotlin.backend.js", + "org.jetbrains.kotlin.backend.jvm", + "org.jetbrains.kotlin.backend.jvm.caches", + "org.jetbrains.kotlin.backend.jvm.codegen", + "org.jetbrains.kotlin.backend.jvm.extensions", + "org.jetbrains.kotlin.backend.jvm.intrinsics", + "org.jetbrains.kotlin.backend.jvm.ir", + "org.jetbrains.kotlin.backend.jvm.lower", + "org.jetbrains.kotlin.backend.jvm.lower.indy", + "org.jetbrains.kotlin.backend.jvm.mapping", + "org.jetbrains.kotlin.backend.jvm.metadata", + "org.jetbrains.kotlin.backend.jvm.overrides", + "org.jetbrains.kotlin.backend.jvm.serialization", + "org.jetbrains.kotlin.backend.jvm.serialization.proto", + "org.jetbrains.kotlin.backend.konan", + "org.jetbrains.kotlin.backend.konan.descriptors", + "org.jetbrains.kotlin.backend.konan.ir", + "org.jetbrains.kotlin.backend.konan.lower", + "org.jetbrains.kotlin.backend.konan.serialization", + "org.jetbrains.kotlin.backend.wasm", + "org.jetbrains.kotlin.backend.wasm.dce", + "org.jetbrains.kotlin.backend.wasm.dwarf", + "org.jetbrains.kotlin.backend.wasm.dwarf.entries", + "org.jetbrains.kotlin.backend.wasm.dwarf.lines", + "org.jetbrains.kotlin.backend.wasm.dwarf.utils", + "org.jetbrains.kotlin.backend.wasm.export", + "org.jetbrains.kotlin.backend.wasm.ic", + "org.jetbrains.kotlin.backend.wasm.ir2wasm", + "org.jetbrains.kotlin.backend.wasm.lower", + "org.jetbrains.kotlin.backend.wasm.serialization", + "org.jetbrains.kotlin.backend.wasm.utils", + "org.jetbrains.kotlin.build", + "org.jetbrains.kotlin.build.report", + "org.jetbrains.kotlin.build.report.metrics", + "org.jetbrains.kotlin.build.report.statistics", + "org.jetbrains.kotlin.build.report.statistics.file", + "org.jetbrains.kotlin.buildtools.api", + "org.jetbrains.kotlin.buildtools.api.internal", + "org.jetbrains.kotlin.buildtools.api.internal.wrappers", + "org.jetbrains.kotlin.buildtools.api.jvm", + "org.jetbrains.kotlin.buildtools.internal", + "org.jetbrains.kotlin.builtins", + "org.jetbrains.kotlin.builtins.functions", + "org.jetbrains.kotlin.builtins.jvm", + "org.jetbrains.kotlin.builtins.konan", + "org.jetbrains.kotlin.cfg", + "org.jetbrains.kotlin.cfg.pseudocode", + "org.jetbrains.kotlin.cfg.pseudocode.instructions", + "org.jetbrains.kotlin.cfg.pseudocode.instructions.eval", + "org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps", + "org.jetbrains.kotlin.cfg.pseudocode.instructions.special", + "org.jetbrains.kotlin.cfg.pseudocodeTraverser", + "org.jetbrains.kotlin.cfg.variable", + "org.jetbrains.kotlin.checkers", + "org.jetbrains.kotlin.checkers.diagnostics", + "org.jetbrains.kotlin.checkers.diagnostics.factories", + "org.jetbrains.kotlin.checkers.utils", + "org.jetbrains.kotlin.cli.common", + "org.jetbrains.kotlin.cli.common.arguments", + "org.jetbrains.kotlin.cli.common.config", + "org.jetbrains.kotlin.cli.common.environment", + "org.jetbrains.kotlin.cli.common.extensions", + "org.jetbrains.kotlin.cli.common.fir", + "org.jetbrains.kotlin.cli.common.localfs", + "org.jetbrains.kotlin.cli.common.messages", + "org.jetbrains.kotlin.cli.common.modules", + "org.jetbrains.kotlin.cli.common.output", + "org.jetbrains.kotlin.cli.common.profiling", + "org.jetbrains.kotlin.cli.common.repl", + "org.jetbrains.kotlin.cli.js", + "org.jetbrains.kotlin.cli.js.klib", + "org.jetbrains.kotlin.cli.jvm", + "org.jetbrains.kotlin.cli.jvm.compiler", + "org.jetbrains.kotlin.cli.jvm.compiler.jarfs", + "org.jetbrains.kotlin.cli.jvm.compiler.legacy.pipeline", + "org.jetbrains.kotlin.cli.jvm.config", + "org.jetbrains.kotlin.cli.jvm.index", + "org.jetbrains.kotlin.cli.jvm.javac", + "org.jetbrains.kotlin.cli.jvm.modules", + "org.jetbrains.kotlin.cli.jvm.plugins", + "org.jetbrains.kotlin.cli.metadata", + "org.jetbrains.kotlin.cli.pipeline", + "org.jetbrains.kotlin.cli.pipeline.jvm", + "org.jetbrains.kotlin.cli.pipeline.metadata", + "org.jetbrains.kotlin.cli.pipeline.web", + "org.jetbrains.kotlin.cli.pipeline.web.js", + "org.jetbrains.kotlin.cli.pipeline.web.wasm", + "org.jetbrains.kotlin.cli.plugins", + "org.jetbrains.kotlin.codegen", + "org.jetbrains.kotlin.codegen.coroutines", + "org.jetbrains.kotlin.codegen.extensions", + "org.jetbrains.kotlin.codegen.inline", + "org.jetbrains.kotlin.codegen.inline.coroutines", + "org.jetbrains.kotlin.codegen.intrinsics", + "org.jetbrains.kotlin.codegen.optimization", + "org.jetbrains.kotlin.codegen.optimization.boxing", + "org.jetbrains.kotlin.codegen.optimization.common", + "org.jetbrains.kotlin.codegen.optimization.fixStack", + "org.jetbrains.kotlin.codegen.optimization.nullCheck", + "org.jetbrains.kotlin.codegen.optimization.temporaryVals", + "org.jetbrains.kotlin.codegen.optimization.transformer", + "org.jetbrains.kotlin.codegen.pseudoInsns", + "org.jetbrains.kotlin.codegen.serialization", + "org.jetbrains.kotlin.codegen.signature", + "org.jetbrains.kotlin.codegen.state", + "org.jetbrains.kotlin.codegen.when", + "org.jetbrains.kotlin.com.fasterxml.aalto", + "org.jetbrains.kotlin.com.fasterxml.aalto.impl", + "org.jetbrains.kotlin.com.fasterxml.aalto.in", + "org.jetbrains.kotlin.com.fasterxml.aalto.stax", + "org.jetbrains.kotlin.com.fasterxml.aalto.util", + "org.jetbrains.kotlin.com.google.common.base", + "org.jetbrains.kotlin.com.google.common.collect", + "org.jetbrains.kotlin.com.google.common.graph", + "org.jetbrains.kotlin.com.google.common.hash", + "org.jetbrains.kotlin.com.google.common.io", + "org.jetbrains.kotlin.com.google.common.math", + "org.jetbrains.kotlin.com.google.common.primitives", + "org.jetbrains.kotlin.com.google.common.util.concurrent", + "org.jetbrains.kotlin.com.google.gwt.dev.js", + "org.jetbrains.kotlin.com.google.gwt.dev.js.parserExceptions", + "org.jetbrains.kotlin.com.google.gwt.dev.js.rhino", + "org.jetbrains.kotlin.com.intellij", + "org.jetbrains.kotlin.com.intellij.codeInsight", + "org.jetbrains.kotlin.com.intellij.codeInsight.completion.scope", + "org.jetbrains.kotlin.com.intellij.codeInsight.daemon.impl.analysis", + "org.jetbrains.kotlin.com.intellij.codeInsight.folding", + "org.jetbrains.kotlin.com.intellij.codeInsight.folding.impl", + "org.jetbrains.kotlin.com.intellij.codeInsight.highlighting", + "org.jetbrains.kotlin.com.intellij.codeInsight.javadoc", + "org.jetbrains.kotlin.com.intellij.codeInsight.runner", + "org.jetbrains.kotlin.com.intellij.codeWithMe", + "org.jetbrains.kotlin.com.intellij.concurrency", + "org.jetbrains.kotlin.com.intellij.core", + "org.jetbrains.kotlin.com.intellij.diagnostic", + "org.jetbrains.kotlin.com.intellij.extapi.psi", + "org.jetbrains.kotlin.com.intellij.formatting", + "org.jetbrains.kotlin.com.intellij.ide", + "org.jetbrains.kotlin.com.intellij.ide.highlighter", + "org.jetbrains.kotlin.com.intellij.ide.plugins", + "org.jetbrains.kotlin.com.intellij.ide.plugins.cl", + "org.jetbrains.kotlin.com.intellij.ide.util", + "org.jetbrains.kotlin.com.intellij.idea", + "org.jetbrains.kotlin.com.intellij.injected.editor", + "org.jetbrains.kotlin.com.intellij.lang", + "org.jetbrains.kotlin.com.intellij.lang.folding", + "org.jetbrains.kotlin.com.intellij.lang.impl", + "org.jetbrains.kotlin.com.intellij.lang.injection", + "org.jetbrains.kotlin.com.intellij.lang.java", + "org.jetbrains.kotlin.com.intellij.lang.java.beans", + "org.jetbrains.kotlin.com.intellij.lang.java.lexer", + "org.jetbrains.kotlin.com.intellij.lang.java.parser", + "org.jetbrains.kotlin.com.intellij.lang.jvm", + "org.jetbrains.kotlin.com.intellij.lang.jvm.annotation", + "org.jetbrains.kotlin.com.intellij.lang.jvm.facade", + "org.jetbrains.kotlin.com.intellij.lang.jvm.types", + "org.jetbrains.kotlin.com.intellij.lexer", + "org.jetbrains.kotlin.com.intellij.mock", + "org.jetbrains.kotlin.com.intellij.model", + "org.jetbrains.kotlin.com.intellij.model.psi", + "org.jetbrains.kotlin.com.intellij.navigation", + "org.jetbrains.kotlin.com.intellij.notebook.editor", + "org.jetbrains.kotlin.com.intellij.openapi", + "org.jetbrains.kotlin.com.intellij.openapi.application", + "org.jetbrains.kotlin.com.intellij.openapi.application.ex", + "org.jetbrains.kotlin.com.intellij.openapi.application.impl", + "org.jetbrains.kotlin.com.intellij.openapi.client", + "org.jetbrains.kotlin.com.intellij.openapi.command", + "org.jetbrains.kotlin.com.intellij.openapi.command.impl", + "org.jetbrains.kotlin.com.intellij.openapi.command.undo", + "org.jetbrains.kotlin.com.intellij.openapi.components", + "org.jetbrains.kotlin.com.intellij.openapi.diagnostic", + "org.jetbrains.kotlin.com.intellij.openapi.editor", + "org.jetbrains.kotlin.com.intellij.openapi.editor.actionSystem", + "org.jetbrains.kotlin.com.intellij.openapi.editor.colors", + "org.jetbrains.kotlin.com.intellij.openapi.editor.event", + "org.jetbrains.kotlin.com.intellij.openapi.editor.ex", + "org.jetbrains.kotlin.com.intellij.openapi.editor.impl", + "org.jetbrains.kotlin.com.intellij.openapi.editor.impl.event", + "org.jetbrains.kotlin.com.intellij.openapi.editor.markup", + "org.jetbrains.kotlin.com.intellij.openapi.extensions", + "org.jetbrains.kotlin.com.intellij.openapi.extensions.impl", + "org.jetbrains.kotlin.com.intellij.openapi.fileEditor", + "org.jetbrains.kotlin.com.intellij.openapi.fileEditor.impl", + "org.jetbrains.kotlin.com.intellij.openapi.fileTypes", + "org.jetbrains.kotlin.com.intellij.openapi.module", + "org.jetbrains.kotlin.com.intellij.openapi.progress", + "org.jetbrains.kotlin.com.intellij.openapi.progress.impl", + "org.jetbrains.kotlin.com.intellij.openapi.progress.util", + "org.jetbrains.kotlin.com.intellij.openapi.project", + "org.jetbrains.kotlin.com.intellij.openapi.projectRoots", + "org.jetbrains.kotlin.com.intellij.openapi.roots", + "org.jetbrains.kotlin.com.intellij.openapi.roots.impl", + "org.jetbrains.kotlin.com.intellij.openapi.ui", + "org.jetbrains.kotlin.com.intellij.openapi.util", + "org.jetbrains.kotlin.com.intellij.openapi.util.io", + "org.jetbrains.kotlin.com.intellij.openapi.util.objectTree", + "org.jetbrains.kotlin.com.intellij.openapi.util.registry", + "org.jetbrains.kotlin.com.intellij.openapi.util.text", + "org.jetbrains.kotlin.com.intellij.openapi.vfs", + "org.jetbrains.kotlin.com.intellij.openapi.vfs.encoding", + "org.jetbrains.kotlin.com.intellij.openapi.vfs.impl", + "org.jetbrains.kotlin.com.intellij.openapi.vfs.impl.jar", + "org.jetbrains.kotlin.com.intellij.openapi.vfs.local", + "org.jetbrains.kotlin.com.intellij.openapi.vfs.newvfs", + "org.jetbrains.kotlin.com.intellij.openapi.vfs.newvfs.events", + "org.jetbrains.kotlin.com.intellij.openapi.vfs.pointers", + "org.jetbrains.kotlin.com.intellij.openapi.wm.ex", + "org.jetbrains.kotlin.com.intellij.patterns", + "org.jetbrains.kotlin.com.intellij.patterns.compiler", + "org.jetbrains.kotlin.com.intellij.platform.backend.navigation", + "org.jetbrains.kotlin.com.intellij.platform.diagnostic.telemetry", + "org.jetbrains.kotlin.com.intellij.platform.diagnostic.telemetry.helpers", + "org.jetbrains.kotlin.com.intellij.pom", + "org.jetbrains.kotlin.com.intellij.pom.core.impl", + "org.jetbrains.kotlin.com.intellij.pom.event", + "org.jetbrains.kotlin.com.intellij.pom.impl", + "org.jetbrains.kotlin.com.intellij.pom.java", + "org.jetbrains.kotlin.com.intellij.pom.tree", + "org.jetbrains.kotlin.com.intellij.pom.tree.events", + "org.jetbrains.kotlin.com.intellij.pom.tree.events.impl", + "org.jetbrains.kotlin.com.intellij.pom.wrappers", + "org.jetbrains.kotlin.com.intellij.psi", + "org.jetbrains.kotlin.com.intellij.psi.augment", + "org.jetbrains.kotlin.com.intellij.psi.codeStyle", + "org.jetbrains.kotlin.com.intellij.psi.compiled", + "org.jetbrains.kotlin.com.intellij.psi.controlFlow", + "org.jetbrains.kotlin.com.intellij.psi.css", + "org.jetbrains.kotlin.com.intellij.psi.filters", + "org.jetbrains.kotlin.com.intellij.psi.filters.classes", + "org.jetbrains.kotlin.com.intellij.psi.filters.element", + "org.jetbrains.kotlin.com.intellij.psi.filters.position", + "org.jetbrains.kotlin.com.intellij.psi.impl", + "org.jetbrains.kotlin.com.intellij.psi.impl.cache", + "org.jetbrains.kotlin.com.intellij.psi.impl.compiled", + "org.jetbrains.kotlin.com.intellij.psi.impl.file", + "org.jetbrains.kotlin.com.intellij.psi.impl.file.impl", + "org.jetbrains.kotlin.com.intellij.psi.impl.java.stubs", + "org.jetbrains.kotlin.com.intellij.psi.impl.java.stubs.impl", + "org.jetbrains.kotlin.com.intellij.psi.impl.java.stubs.index", + "org.jetbrains.kotlin.com.intellij.psi.impl.light", + "org.jetbrains.kotlin.com.intellij.psi.impl.meta", + "org.jetbrains.kotlin.com.intellij.psi.impl.search", + "org.jetbrains.kotlin.com.intellij.psi.impl.smartPointers", + "org.jetbrains.kotlin.com.intellij.psi.impl.source", + "org.jetbrains.kotlin.com.intellij.psi.impl.source.codeStyle", + "org.jetbrains.kotlin.com.intellij.psi.impl.source.javadoc", + "org.jetbrains.kotlin.com.intellij.psi.impl.source.resolve", + "org.jetbrains.kotlin.com.intellij.psi.impl.source.resolve.graphInference", + "org.jetbrains.kotlin.com.intellij.psi.impl.source.resolve.graphInference.constraints", + "org.jetbrains.kotlin.com.intellij.psi.impl.source.resolve.reference", + "org.jetbrains.kotlin.com.intellij.psi.impl.source.resolve.reference.impl", + "org.jetbrains.kotlin.com.intellij.psi.impl.source.resolve.reference.impl.manipulators", + "org.jetbrains.kotlin.com.intellij.psi.impl.source.resolve.reference.impl.providers", + "org.jetbrains.kotlin.com.intellij.psi.impl.source.tree", + "org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.injected", + "org.jetbrains.kotlin.com.intellij.psi.impl.source.tree.java", + "org.jetbrains.kotlin.com.intellij.psi.infos", + "org.jetbrains.kotlin.com.intellij.psi.javadoc", + "org.jetbrains.kotlin.com.intellij.psi.meta", + "org.jetbrains.kotlin.com.intellij.psi.presentation.java", + "org.jetbrains.kotlin.com.intellij.psi.scope", + "org.jetbrains.kotlin.com.intellij.psi.scope.conflictResolvers", + "org.jetbrains.kotlin.com.intellij.psi.scope.processor", + "org.jetbrains.kotlin.com.intellij.psi.scope.util", + "org.jetbrains.kotlin.com.intellij.psi.search", + "org.jetbrains.kotlin.com.intellij.psi.search.impl", + "org.jetbrains.kotlin.com.intellij.psi.search.searches", + "org.jetbrains.kotlin.com.intellij.psi.stub", + "org.jetbrains.kotlin.com.intellij.psi.stubs", + "org.jetbrains.kotlin.com.intellij.psi.targets", + "org.jetbrains.kotlin.com.intellij.psi.templateLanguages", + "org.jetbrains.kotlin.com.intellij.psi.text", + "org.jetbrains.kotlin.com.intellij.psi.tree", + "org.jetbrains.kotlin.com.intellij.psi.tree.java", + "org.jetbrains.kotlin.com.intellij.psi.util", + "org.jetbrains.kotlin.com.intellij.reference", + "org.jetbrains.kotlin.com.intellij.serialization", + "org.jetbrains.kotlin.com.intellij.serviceContainer", + "org.jetbrains.kotlin.com.intellij.testFramework", + "org.jetbrains.kotlin.com.intellij.ui", + "org.jetbrains.kotlin.com.intellij.ui.icons", + "org.jetbrains.kotlin.com.intellij.util", + "org.jetbrains.kotlin.com.intellij.util.cls", + "org.jetbrains.kotlin.com.intellij.util.codeInsight", + "org.jetbrains.kotlin.com.intellij.util.concurrency", + "org.jetbrains.kotlin.com.intellij.util.containers", + "org.jetbrains.kotlin.com.intellij.util.containers.hash", + "org.jetbrains.kotlin.com.intellij.util.diff", + "org.jetbrains.kotlin.com.intellij.util.execution", + "org.jetbrains.kotlin.com.intellij.util.graph", + "org.jetbrains.kotlin.com.intellij.util.graph.impl", + "org.jetbrains.kotlin.com.intellij.util.indexing", + "org.jetbrains.kotlin.com.intellij.util.indexing.impl", + "org.jetbrains.kotlin.com.intellij.util.io", + "org.jetbrains.kotlin.com.intellij.util.io.keyStorage", + "org.jetbrains.kotlin.com.intellij.util.io.pagecache", + "org.jetbrains.kotlin.com.intellij.util.io.pagecache.impl", + "org.jetbrains.kotlin.com.intellij.util.io.stats", + "org.jetbrains.kotlin.com.intellij.util.io.storage", + "org.jetbrains.kotlin.com.intellij.util.keyFMap", + "org.jetbrains.kotlin.com.intellij.util.lang", + "org.jetbrains.kotlin.com.intellij.util.messages", + "org.jetbrains.kotlin.com.intellij.util.messages.impl", + "org.jetbrains.kotlin.com.intellij.util.pico", + "org.jetbrains.kotlin.com.intellij.util.ref", + "org.jetbrains.kotlin.com.intellij.util.system", + "org.jetbrains.kotlin.com.intellij.util.text", + "org.jetbrains.kotlin.com.intellij.util.ui", + "org.jetbrains.kotlin.com.intellij.util.xml.dom", + "org.jetbrains.kotlin.com.intellij.util.xmlb", + "org.jetbrains.kotlin.com.intellij.util.xmlb.annotations", + "org.jetbrains.kotlin.compiler.plugin", + "org.jetbrains.kotlin.compilerRunner", + "org.jetbrains.kotlin.config", + "org.jetbrains.kotlin.config.phaser", + "org.jetbrains.kotlin.constant", + "org.jetbrains.kotlin.container", + "org.jetbrains.kotlin.context", + "org.jetbrains.kotlin.contracts", + "org.jetbrains.kotlin.contracts.description", + "org.jetbrains.kotlin.contracts.description.expressions", + "org.jetbrains.kotlin.contracts.interpretation", + "org.jetbrains.kotlin.contracts.model", + "org.jetbrains.kotlin.contracts.model.functors", + "org.jetbrains.kotlin.contracts.model.structure", + "org.jetbrains.kotlin.contracts.model.visitors", + "org.jetbrains.kotlin.contracts.parsing", + "org.jetbrains.kotlin.contracts.parsing.effects", + "org.jetbrains.kotlin.coroutines", + "org.jetbrains.kotlin.descriptors", + "org.jetbrains.kotlin.descriptors.annotations", + "org.jetbrains.kotlin.descriptors.deserialization", + "org.jetbrains.kotlin.descriptors.impl", + "org.jetbrains.kotlin.descriptors.java", + "org.jetbrains.kotlin.descriptors.konan", + "org.jetbrains.kotlin.descriptors.runtime.components", + "org.jetbrains.kotlin.descriptors.runtime.structure", + "org.jetbrains.kotlin.descriptors.synthetic", + "org.jetbrains.kotlin.diagnostics", + "org.jetbrains.kotlin.diagnostics.impl", + "org.jetbrains.kotlin.diagnostics.rendering", + "org.jetbrains.kotlin.extensions", + "org.jetbrains.kotlin.extensions.internal", + "org.jetbrains.kotlin.fileClasses", + "org.jetbrains.kotlin.fir", + "org.jetbrains.kotlin.fir.analysis", + "org.jetbrains.kotlin.fir.analysis.cfa", + "org.jetbrains.kotlin.fir.analysis.cfa.util", + "org.jetbrains.kotlin.fir.analysis.checkers", + "org.jetbrains.kotlin.fir.analysis.checkers.cfa", + "org.jetbrains.kotlin.fir.analysis.checkers.config", + "org.jetbrains.kotlin.fir.analysis.checkers.context", + "org.jetbrains.kotlin.fir.analysis.checkers.declaration", + "org.jetbrains.kotlin.fir.analysis.checkers.experimental", + "org.jetbrains.kotlin.fir.analysis.checkers.expression", + "org.jetbrains.kotlin.fir.analysis.checkers.extra", + "org.jetbrains.kotlin.fir.analysis.checkers.syntax", + "org.jetbrains.kotlin.fir.analysis.checkers.type", + "org.jetbrains.kotlin.fir.analysis.collectors", + "org.jetbrains.kotlin.fir.analysis.collectors.components", + "org.jetbrains.kotlin.fir.analysis.diagnostics", + "org.jetbrains.kotlin.fir.analysis.diagnostics.js", + "org.jetbrains.kotlin.fir.analysis.diagnostics.jvm", + "org.jetbrains.kotlin.fir.analysis.diagnostics.native", + "org.jetbrains.kotlin.fir.analysis.diagnostics.wasm", + "org.jetbrains.kotlin.fir.analysis.diagnostics.web.common", + "org.jetbrains.kotlin.fir.analysis.extensions", + "org.jetbrains.kotlin.fir.analysis.js.checkers", + "org.jetbrains.kotlin.fir.analysis.js.checkers.declaration", + "org.jetbrains.kotlin.fir.analysis.js.checkers.expression", + "org.jetbrains.kotlin.fir.analysis.jvm", + "org.jetbrains.kotlin.fir.analysis.jvm.checkers", + "org.jetbrains.kotlin.fir.analysis.jvm.checkers.declaration", + "org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression", + "org.jetbrains.kotlin.fir.analysis.jvm.checkers.type", + "org.jetbrains.kotlin.fir.analysis.native.checkers", + "org.jetbrains.kotlin.fir.analysis.wasm.checkers", + "org.jetbrains.kotlin.fir.analysis.wasm.checkers.declaration", + "org.jetbrains.kotlin.fir.analysis.wasm.checkers.expression", + "org.jetbrains.kotlin.fir.analysis.web.common.checkers", + "org.jetbrains.kotlin.fir.analysis.web.common.checkers.declaration", + "org.jetbrains.kotlin.fir.analysis.web.common.checkers.expression", + "org.jetbrains.kotlin.fir.backend", + "org.jetbrains.kotlin.fir.backend.generators", + "org.jetbrains.kotlin.fir.backend.jvm", + "org.jetbrains.kotlin.fir.backend.native", + "org.jetbrains.kotlin.fir.backend.native.interop", + "org.jetbrains.kotlin.fir.backend.utils", + "org.jetbrains.kotlin.fir.builder", + "org.jetbrains.kotlin.fir.caches", + "org.jetbrains.kotlin.fir.checkers", + "org.jetbrains.kotlin.fir.contracts", + "org.jetbrains.kotlin.fir.contracts.builder", + "org.jetbrains.kotlin.fir.contracts.description", + "org.jetbrains.kotlin.fir.contracts.impl", + "org.jetbrains.kotlin.fir.declarations", + "org.jetbrains.kotlin.fir.declarations.builder", + "org.jetbrains.kotlin.fir.declarations.comparators", + "org.jetbrains.kotlin.fir.declarations.impl", + "org.jetbrains.kotlin.fir.declarations.synthetic", + "org.jetbrains.kotlin.fir.declarations.utils", + "org.jetbrains.kotlin.fir.descriptors", + "org.jetbrains.kotlin.fir.deserialization", + "org.jetbrains.kotlin.fir.diagnostics", + "org.jetbrains.kotlin.fir.expressions", + "org.jetbrains.kotlin.fir.expressions.builder", + "org.jetbrains.kotlin.fir.expressions.impl", + "org.jetbrains.kotlin.fir.extensions", + "org.jetbrains.kotlin.fir.extensions.predicate", + "org.jetbrains.kotlin.fir.extensions.utils", + "org.jetbrains.kotlin.fir.impl", + "org.jetbrains.kotlin.fir.java", + "org.jetbrains.kotlin.fir.java.declarations", + "org.jetbrains.kotlin.fir.java.deserialization", + "org.jetbrains.kotlin.fir.java.enhancement", + "org.jetbrains.kotlin.fir.java.scopes", + "org.jetbrains.kotlin.fir.java.symbols", + "org.jetbrains.kotlin.fir.lazy", + "org.jetbrains.kotlin.fir.lightTree", + "org.jetbrains.kotlin.fir.lightTree.converter", + "org.jetbrains.kotlin.fir.lightTree.fir", + "org.jetbrains.kotlin.fir.lightTree.fir.modifier", + "org.jetbrains.kotlin.fir.modules", + "org.jetbrains.kotlin.fir.pipeline", + "org.jetbrains.kotlin.fir.plugin", + "org.jetbrains.kotlin.fir.references", + "org.jetbrains.kotlin.fir.references.builder", + "org.jetbrains.kotlin.fir.references.impl", + "org.jetbrains.kotlin.fir.renderer", + "org.jetbrains.kotlin.fir.resolve", + "org.jetbrains.kotlin.fir.resolve.calls", + "org.jetbrains.kotlin.fir.resolve.calls.candidate", + "org.jetbrains.kotlin.fir.resolve.calls.js", + "org.jetbrains.kotlin.fir.resolve.calls.jvm", + "org.jetbrains.kotlin.fir.resolve.calls.overloads", + "org.jetbrains.kotlin.fir.resolve.calls.stages", + "org.jetbrains.kotlin.fir.resolve.calls.tower", + "org.jetbrains.kotlin.fir.resolve.dfa", + "org.jetbrains.kotlin.fir.resolve.dfa.cfg", + "org.jetbrains.kotlin.fir.resolve.diagnostics", + "org.jetbrains.kotlin.fir.resolve.inference", + "org.jetbrains.kotlin.fir.resolve.inference.model", + "org.jetbrains.kotlin.fir.resolve.providers", + "org.jetbrains.kotlin.fir.resolve.providers.impl", + "org.jetbrains.kotlin.fir.resolve.scopes", + "org.jetbrains.kotlin.fir.resolve.substitution", + "org.jetbrains.kotlin.fir.resolve.transformers", + "org.jetbrains.kotlin.fir.resolve.transformers.body.resolve", + "org.jetbrains.kotlin.fir.resolve.transformers.contracts", + "org.jetbrains.kotlin.fir.resolve.transformers.mpp", + "org.jetbrains.kotlin.fir.resolve.transformers.plugin", + "org.jetbrains.kotlin.fir.scopes", + "org.jetbrains.kotlin.fir.scopes.impl", + "org.jetbrains.kotlin.fir.scopes.jvm", + "org.jetbrains.kotlin.fir.serialization", + "org.jetbrains.kotlin.fir.serialization.constant", + "org.jetbrains.kotlin.fir.session", + "org.jetbrains.kotlin.fir.session.environment", + "org.jetbrains.kotlin.fir.symbols", + "org.jetbrains.kotlin.fir.symbols.impl", + "org.jetbrains.kotlin.fir.types", + "org.jetbrains.kotlin.fir.types.builder", + "org.jetbrains.kotlin.fir.types.impl", + "org.jetbrains.kotlin.fir.types.jvm", + "org.jetbrains.kotlin.fir.util", + "org.jetbrains.kotlin.fir.utils.exceptions", + "org.jetbrains.kotlin.fir.visitors", + "org.jetbrains.kotlin.frontend.di", + "org.jetbrains.kotlin.frontend.java.di", + "org.jetbrains.kotlin.frontend.js.di", + "org.jetbrains.kotlin.idea", + "org.jetbrains.kotlin.idea.references", + "org.jetbrains.kotlin.incremental", + "org.jetbrains.kotlin.incremental.classpathDiff", + "org.jetbrains.kotlin.incremental.classpathDiff.impl", + "org.jetbrains.kotlin.incremental.components", + "org.jetbrains.kotlin.incremental.dirtyFiles", + "org.jetbrains.kotlin.incremental.impl", + "org.jetbrains.kotlin.incremental.javaInterop", + "org.jetbrains.kotlin.incremental.js", + "org.jetbrains.kotlin.incremental.multiproject", + "org.jetbrains.kotlin.incremental.parsing", + "org.jetbrains.kotlin.incremental.snapshots", + "org.jetbrains.kotlin.incremental.storage", + "org.jetbrains.kotlin.incremental.util", + "org.jetbrains.kotlin.inline", + "org.jetbrains.kotlin.io.opentelemetry.api", + "org.jetbrains.kotlin.io.opentelemetry.api.common", + "org.jetbrains.kotlin.io.opentelemetry.api.internal", + "org.jetbrains.kotlin.io.opentelemetry.api.logs", + "org.jetbrains.kotlin.io.opentelemetry.api.metrics", + "org.jetbrains.kotlin.io.opentelemetry.api.trace", + "org.jetbrains.kotlin.io.vavr", + "org.jetbrains.kotlin.io.vavr.collection", + "org.jetbrains.kotlin.io.vavr.concurrent", + "org.jetbrains.kotlin.io.vavr.control", + "org.jetbrains.kotlin.ir", + "org.jetbrains.kotlin.ir.backend.js", + "org.jetbrains.kotlin.ir.backend.js.checkers", + "org.jetbrains.kotlin.ir.backend.js.checkers.declarations", + "org.jetbrains.kotlin.ir.backend.js.checkers.expressions", + "org.jetbrains.kotlin.ir.backend.js.dce", + "org.jetbrains.kotlin.ir.backend.js.export", + "org.jetbrains.kotlin.ir.backend.js.ic", + "org.jetbrains.kotlin.ir.backend.js.ir", + "org.jetbrains.kotlin.ir.backend.js.lower", + "org.jetbrains.kotlin.ir.backend.js.lower.calls", + "org.jetbrains.kotlin.ir.backend.js.lower.cleanup", + "org.jetbrains.kotlin.ir.backend.js.lower.coroutines", + "org.jetbrains.kotlin.ir.backend.js.lower.inline", + "org.jetbrains.kotlin.ir.backend.js.lower.serialization.ir", + "org.jetbrains.kotlin.ir.backend.js.transformers.irToJs", + "org.jetbrains.kotlin.ir.backend.js.utils", + "org.jetbrains.kotlin.ir.backend.js.utils.serialization", + "org.jetbrains.kotlin.ir.backend.jvm", + "org.jetbrains.kotlin.ir.backend.jvm.serialization", + "org.jetbrains.kotlin.ir.builders", + "org.jetbrains.kotlin.ir.builders.declarations", + "org.jetbrains.kotlin.ir.declarations", + "org.jetbrains.kotlin.ir.declarations.impl", + "org.jetbrains.kotlin.ir.declarations.lazy", + "org.jetbrains.kotlin.ir.descriptors", + "org.jetbrains.kotlin.ir.expressions", + "org.jetbrains.kotlin.ir.expressions.impl", + "org.jetbrains.kotlin.ir.inline", + "org.jetbrains.kotlin.ir.inline.konan", + "org.jetbrains.kotlin.ir.interpreter", + "org.jetbrains.kotlin.ir.interpreter.builtins", + "org.jetbrains.kotlin.ir.interpreter.checker", + "org.jetbrains.kotlin.ir.interpreter.exceptions", + "org.jetbrains.kotlin.ir.interpreter.intrinsics", + "org.jetbrains.kotlin.ir.interpreter.preprocessor", + "org.jetbrains.kotlin.ir.interpreter.proxy", + "org.jetbrains.kotlin.ir.interpreter.proxy.reflection", + "org.jetbrains.kotlin.ir.interpreter.stack", + "org.jetbrains.kotlin.ir.interpreter.state", + "org.jetbrains.kotlin.ir.interpreter.state.reflection", + "org.jetbrains.kotlin.ir.interpreter.transformer", + "org.jetbrains.kotlin.ir.objcinterop", + "org.jetbrains.kotlin.ir.overrides", + "org.jetbrains.kotlin.ir.symbols", + "org.jetbrains.kotlin.ir.symbols.impl", + "org.jetbrains.kotlin.ir.types", + "org.jetbrains.kotlin.ir.types.impl", + "org.jetbrains.kotlin.ir.util", + "org.jetbrains.kotlin.ir.visitors", + "org.jetbrains.kotlin.it.unimi.dsi.fastutil", + "org.jetbrains.kotlin.it.unimi.dsi.fastutil.booleans", + "org.jetbrains.kotlin.it.unimi.dsi.fastutil.bytes", + "org.jetbrains.kotlin.it.unimi.dsi.fastutil.chars", + "org.jetbrains.kotlin.it.unimi.dsi.fastutil.doubles", + "org.jetbrains.kotlin.it.unimi.dsi.fastutil.floats", + "org.jetbrains.kotlin.it.unimi.dsi.fastutil.ints", + "org.jetbrains.kotlin.it.unimi.dsi.fastutil.longs", + "org.jetbrains.kotlin.it.unimi.dsi.fastutil.objects", + "org.jetbrains.kotlin.it.unimi.dsi.fastutil.shorts", + "org.jetbrains.kotlin.javac", + "org.jetbrains.kotlin.javac.components", + "org.jetbrains.kotlin.javac.resolve", + "org.jetbrains.kotlin.javac.wrappers.symbols", + "org.jetbrains.kotlin.javac.wrappers.trees", + "org.jetbrains.kotlin.javax.inject", + "org.jetbrains.kotlin.js", + "org.jetbrains.kotlin.js.analyze", + "org.jetbrains.kotlin.js.analyzer", + "org.jetbrains.kotlin.js.backend", + "org.jetbrains.kotlin.js.backend.ast", + "org.jetbrains.kotlin.js.backend.ast.metadata", + "org.jetbrains.kotlin.js.common", + "org.jetbrains.kotlin.js.config", + "org.jetbrains.kotlin.js.descriptorUtils", + "org.jetbrains.kotlin.js.inline.clean", + "org.jetbrains.kotlin.js.inline.util", + "org.jetbrains.kotlin.js.inline.util.collectors", + "org.jetbrains.kotlin.js.naming", + "org.jetbrains.kotlin.js.parser", + "org.jetbrains.kotlin.js.parser.sourcemaps", + "org.jetbrains.kotlin.js.patterns", + "org.jetbrains.kotlin.js.resolve", + "org.jetbrains.kotlin.js.resolve.diagnostics", + "org.jetbrains.kotlin.js.sourceMap", + "org.jetbrains.kotlin.js.translate.context", + "org.jetbrains.kotlin.js.translate.utils", + "org.jetbrains.kotlin.js.util", + "org.jetbrains.kotlin.kapt3.diagnostic", + "org.jetbrains.kotlin.kdoc.lexer", + "org.jetbrains.kotlin.kdoc.parser", + "org.jetbrains.kotlin.kdoc.psi.api", + "org.jetbrains.kotlin.kdoc.psi.impl", + "org.jetbrains.kotlin.konan", + "org.jetbrains.kotlin.konan.exec", + "org.jetbrains.kotlin.konan.file", + "org.jetbrains.kotlin.konan.library", + "org.jetbrains.kotlin.konan.library.impl", + "org.jetbrains.kotlin.konan.properties", + "org.jetbrains.kotlin.konan.target", + "org.jetbrains.kotlin.konan.util", + "org.jetbrains.kotlin.kotlinx.collections.immutable", + "org.jetbrains.kotlin.kotlinx.collections.immutable.implementations.immutableList", + "org.jetbrains.kotlin.kotlinx.collections.immutable.implementations.immutableMap", + "org.jetbrains.kotlin.kotlinx.collections.immutable.implementations.immutableSet", + "org.jetbrains.kotlin.kotlinx.collections.immutable.implementations.persistentOrderedMap", + "org.jetbrains.kotlin.kotlinx.collections.immutable.implementations.persistentOrderedSet", + "org.jetbrains.kotlin.kotlinx.collections.immutable.internal", + "org.jetbrains.kotlin.lang", + "org.jetbrains.kotlin.lexer", + "org.jetbrains.kotlin.library", + "org.jetbrains.kotlin.library.abi", + "org.jetbrains.kotlin.library.abi.impl", + "org.jetbrains.kotlin.library.encodings", + "org.jetbrains.kotlin.library.impl", + "org.jetbrains.kotlin.library.loader", + "org.jetbrains.kotlin.library.metadata", + "org.jetbrains.kotlin.library.metadata.impl", + "org.jetbrains.kotlin.library.metadata.resolver", + "org.jetbrains.kotlin.library.metadata.resolver.impl", + "org.jetbrains.kotlin.load.java", + "org.jetbrains.kotlin.load.java.components", + "org.jetbrains.kotlin.load.java.descriptors", + "org.jetbrains.kotlin.load.java.lazy", + "org.jetbrains.kotlin.load.java.lazy.descriptors", + "org.jetbrains.kotlin.load.java.lazy.types", + "org.jetbrains.kotlin.load.java.sam", + "org.jetbrains.kotlin.load.java.sources", + "org.jetbrains.kotlin.load.java.structure", + "org.jetbrains.kotlin.load.java.structure.impl", + "org.jetbrains.kotlin.load.java.structure.impl.classFiles", + "org.jetbrains.kotlin.load.java.structure.impl.source", + "org.jetbrains.kotlin.load.java.typeEnhancement", + "org.jetbrains.kotlin.load.kotlin", + "org.jetbrains.kotlin.load.kotlin.header", + "org.jetbrains.kotlin.load.kotlin.incremental", + "org.jetbrains.kotlin.load.kotlin.incremental.components", + "org.jetbrains.kotlin.metadata", + "org.jetbrains.kotlin.metadata.builtins", + "org.jetbrains.kotlin.metadata.deserialization", + "org.jetbrains.kotlin.metadata.java", + "org.jetbrains.kotlin.metadata.js", + "org.jetbrains.kotlin.metadata.jvm", + "org.jetbrains.kotlin.metadata.jvm.deserialization", + "org.jetbrains.kotlin.metadata.jvm.serialization", + "org.jetbrains.kotlin.metadata.serialization", + "org.jetbrains.kotlin.modules", + "org.jetbrains.kotlin.mpp", + "org.jetbrains.kotlin.name", + "org.jetbrains.kotlin.native.interop", + "org.jetbrains.kotlin.net.jpountz.lz4", + "org.jetbrains.kotlin.net.jpountz.util", + "org.jetbrains.kotlin.net.jpountz.xxhash", + "org.jetbrains.kotlin.one.util.streamex", + "org.jetbrains.kotlin.org.apache.log4j", + "org.jetbrains.kotlin.org.codehaus.stax2", + "org.jetbrains.kotlin.org.codehaus.stax2.ri", + "org.jetbrains.kotlin.org.codehaus.stax2.ri.typed", + "org.jetbrains.kotlin.org.codehaus.stax2.typed", + "org.jetbrains.kotlin.org.fusesource.jansi", + "org.jetbrains.kotlin.org.fusesource.jansi.internal", + "org.jetbrains.kotlin.org.fusesource.jansi.io", + "org.jetbrains.kotlin.org.jdom", + "org.jetbrains.kotlin.org.jdom.filter2", + "org.jetbrains.kotlin.org.jdom.output", + "org.jetbrains.kotlin.org.jline.builtins", + "org.jetbrains.kotlin.org.jline.console", + "org.jetbrains.kotlin.org.jline.keymap", + "org.jetbrains.kotlin.org.jline.reader", + "org.jetbrains.kotlin.org.jline.reader.impl", + "org.jetbrains.kotlin.org.jline.reader.impl.history", + "org.jetbrains.kotlin.org.jline.terminal", + "org.jetbrains.kotlin.org.jline.terminal.impl", + "org.jetbrains.kotlin.org.jline.terminal.spi", + "org.jetbrains.kotlin.org.jline.utils", + "org.jetbrains.kotlin.org.picocontainer", + "org.jetbrains.kotlin.parsing", + "org.jetbrains.kotlin.platform", + "org.jetbrains.kotlin.platform.js", + "org.jetbrains.kotlin.platform.jvm", + "org.jetbrains.kotlin.platform.konan", + "org.jetbrains.kotlin.platform.wasm", + "org.jetbrains.kotlin.plugin.references", + "org.jetbrains.kotlin.progress", + "org.jetbrains.kotlin.protobuf", + "org.jetbrains.kotlin.psi", + "org.jetbrains.kotlin.psi.addRemoveModifier", + "org.jetbrains.kotlin.psi.codeFragmentUtil", + "org.jetbrains.kotlin.psi.debugText", + "org.jetbrains.kotlin.psi.findDocComment", + "org.jetbrains.kotlin.psi.impl", + "org.jetbrains.kotlin.psi.psiUtil", + "org.jetbrains.kotlin.psi.stubs", + "org.jetbrains.kotlin.psi.stubs.elements", + "org.jetbrains.kotlin.psi.stubs.impl", + "org.jetbrains.kotlin.psi.synthetics", + "org.jetbrains.kotlin.psi.typeRefHelpers", + "org.jetbrains.kotlin.psi.utils", + "org.jetbrains.kotlin.psi2ir", + "org.jetbrains.kotlin.psi2ir.descriptors", + "org.jetbrains.kotlin.psi2ir.generators", + "org.jetbrains.kotlin.psi2ir.generators.fragments", + "org.jetbrains.kotlin.psi2ir.intermediate", + "org.jetbrains.kotlin.psi2ir.lazy", + "org.jetbrains.kotlin.psi2ir.preprocessing", + "org.jetbrains.kotlin.psi2ir.transformations", + "org.jetbrains.kotlin.renderer", + "org.jetbrains.kotlin.resolve", + "org.jetbrains.kotlin.resolve.annotations", + "org.jetbrains.kotlin.resolve.bindingContextUtil", + "org.jetbrains.kotlin.resolve.calls", + "org.jetbrains.kotlin.resolve.calls.callUtil", + "org.jetbrains.kotlin.resolve.calls.checkers", + "org.jetbrains.kotlin.resolve.calls.components", + "org.jetbrains.kotlin.resolve.calls.components.candidate", + "org.jetbrains.kotlin.resolve.calls.context", + "org.jetbrains.kotlin.resolve.calls.inference", + "org.jetbrains.kotlin.resolve.calls.inference.components", + "org.jetbrains.kotlin.resolve.calls.inference.constraintPosition", + "org.jetbrains.kotlin.resolve.calls.inference.model", + "org.jetbrains.kotlin.resolve.calls.model", + "org.jetbrains.kotlin.resolve.calls.mpp", + "org.jetbrains.kotlin.resolve.calls.results", + "org.jetbrains.kotlin.resolve.calls.smartcasts", + "org.jetbrains.kotlin.resolve.calls.tasks", + "org.jetbrains.kotlin.resolve.calls.tower", + "org.jetbrains.kotlin.resolve.calls.util", + "org.jetbrains.kotlin.resolve.checkers", + "org.jetbrains.kotlin.resolve.constants", + "org.jetbrains.kotlin.resolve.constants.evaluate", + "org.jetbrains.kotlin.resolve.deprecation", + "org.jetbrains.kotlin.resolve.descriptorUtil", + "org.jetbrains.kotlin.resolve.diagnostics", + "org.jetbrains.kotlin.resolve.extensions", + "org.jetbrains.kotlin.resolve.inline", + "org.jetbrains.kotlin.resolve.jvm", + "org.jetbrains.kotlin.resolve.jvm.annotations", + "org.jetbrains.kotlin.resolve.jvm.checkers", + "org.jetbrains.kotlin.resolve.jvm.diagnostics", + "org.jetbrains.kotlin.resolve.jvm.extensions", + "org.jetbrains.kotlin.resolve.jvm.jvmSignature", + "org.jetbrains.kotlin.resolve.jvm.kotlinSignature", + "org.jetbrains.kotlin.resolve.jvm.modules", + "org.jetbrains.kotlin.resolve.jvm.multiplatform", + "org.jetbrains.kotlin.resolve.jvm.platform", + "org.jetbrains.kotlin.resolve.konan.diagnostics", + "org.jetbrains.kotlin.resolve.konan.platform", + "org.jetbrains.kotlin.resolve.lazy", + "org.jetbrains.kotlin.resolve.lazy.data", + "org.jetbrains.kotlin.resolve.lazy.declarations", + "org.jetbrains.kotlin.resolve.lazy.descriptors", + "org.jetbrains.kotlin.resolve.multiplatform", + "org.jetbrains.kotlin.resolve.references", + "org.jetbrains.kotlin.resolve.repl", + "org.jetbrains.kotlin.resolve.sam", + "org.jetbrains.kotlin.resolve.scopes", + "org.jetbrains.kotlin.resolve.scopes.optimization", + "org.jetbrains.kotlin.resolve.scopes.receivers", + "org.jetbrains.kotlin.resolve.scopes.synthetic", + "org.jetbrains.kotlin.resolve.scopes.utils", + "org.jetbrains.kotlin.resolve.source", + "org.jetbrains.kotlin.resolve.typeBinding", + "org.jetbrains.kotlin.serialization", + "org.jetbrains.kotlin.serialization.deserialization", + "org.jetbrains.kotlin.serialization.deserialization.builtins", + "org.jetbrains.kotlin.serialization.deserialization.descriptors", + "org.jetbrains.kotlin.serialization.js", + "org.jetbrains.kotlin.serialization.js.ast", + "org.jetbrains.kotlin.stats", + "org.jetbrains.kotlin.storage", + "org.jetbrains.kotlin.synthetic", + "org.jetbrains.kotlin.type", + "org.jetbrains.kotlin.types", + "org.jetbrains.kotlin.types.checker", + "org.jetbrains.kotlin.types.error", + "org.jetbrains.kotlin.types.expressions", + "org.jetbrains.kotlin.types.expressions.typeInfoFactory", + "org.jetbrains.kotlin.types.expressions.unqualifiedSuper", + "org.jetbrains.kotlin.types.extensions", + "org.jetbrains.kotlin.types.model", + "org.jetbrains.kotlin.types.typeUtil", + "org.jetbrains.kotlin.types.typesApproximation", + "org.jetbrains.kotlin.util", + "org.jetbrains.kotlin.util.capitalizeDecapitalize", + "org.jetbrains.kotlin.util.collectionUtils", + "org.jetbrains.kotlin.util.slicedMap", + "org.jetbrains.kotlin.util.vavr", + "org.jetbrains.kotlin.utils", + "org.jetbrains.kotlin.utils.addToStdlib", + "org.jetbrains.kotlin.utils.concurrent.block", + "org.jetbrains.kotlin.utils.exceptions", + "org.jetbrains.kotlin.utils.fileUtils", + "org.jetbrains.kotlin.utils.kapt", + "org.jetbrains.kotlin.utils.repl", + "org.jetbrains.kotlin.utils.strings", + "org.jetbrains.kotlin.wasm.analyze", + "org.jetbrains.kotlin.wasm.config", + "org.jetbrains.kotlin.wasm.ir", + "org.jetbrains.kotlin.wasm.ir.convertors", + "org.jetbrains.kotlin.wasm.ir.debug", + "org.jetbrains.kotlin.wasm.ir.source.location", + "org.jetbrains.kotlin.wasm.resolve", + "org.jetbrains.kotlin.wasm.resolve.diagnostics", + "org.jetbrains.kotlin.wasm.util", + "org.jetbrains.org.objectweb.asm", + "org.jetbrains.org.objectweb.asm.commons", + "org.jetbrains.org.objectweb.asm.signature", + "org.jetbrains.org.objectweb.asm.tree", + "org.jetbrains.org.objectweb.asm.tree.analysis", + "org.jetbrains.org.objectweb.asm.util" + ], + "org.jetbrains.kotlin:kotlin-daemon-embeddable": [ + "org.jetbrains.kotlin.daemon", + "org.jetbrains.kotlin.daemon.common", + "org.jetbrains.kotlin.daemon.report" + ], + "org.jetbrains.kotlin:kotlin-reflect": [ + "kotlin.reflect.full", + "kotlin.reflect.jvm", + "kotlin.reflect.jvm.internal", + "kotlin.reflect.jvm.internal.calls", + "kotlin.reflect.jvm.internal.impl", + "kotlin.reflect.jvm.internal.impl.builtins", + "kotlin.reflect.jvm.internal.impl.builtins.functions", + "kotlin.reflect.jvm.internal.impl.builtins.jvm", + "kotlin.reflect.jvm.internal.impl.descriptors", + "kotlin.reflect.jvm.internal.impl.descriptors.annotations", + "kotlin.reflect.jvm.internal.impl.descriptors.deserialization", + "kotlin.reflect.jvm.internal.impl.descriptors.impl", + "kotlin.reflect.jvm.internal.impl.descriptors.java", + "kotlin.reflect.jvm.internal.impl.descriptors.runtime.components", + "kotlin.reflect.jvm.internal.impl.descriptors.runtime.structure", + "kotlin.reflect.jvm.internal.impl.incremental", + "kotlin.reflect.jvm.internal.impl.incremental.components", + "kotlin.reflect.jvm.internal.impl.load.java", + "kotlin.reflect.jvm.internal.impl.load.java.components", + "kotlin.reflect.jvm.internal.impl.load.java.descriptors", + "kotlin.reflect.jvm.internal.impl.load.java.lazy", + "kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors", + "kotlin.reflect.jvm.internal.impl.load.java.lazy.types", + "kotlin.reflect.jvm.internal.impl.load.java.sources", + "kotlin.reflect.jvm.internal.impl.load.java.structure", + "kotlin.reflect.jvm.internal.impl.load.java.typeEnhancement", + "kotlin.reflect.jvm.internal.impl.load.kotlin", + "kotlin.reflect.jvm.internal.impl.load.kotlin.header", + "kotlin.reflect.jvm.internal.impl.metadata", + "kotlin.reflect.jvm.internal.impl.metadata.builtins", + "kotlin.reflect.jvm.internal.impl.metadata.deserialization", + "kotlin.reflect.jvm.internal.impl.metadata.jvm", + "kotlin.reflect.jvm.internal.impl.metadata.jvm.deserialization", + "kotlin.reflect.jvm.internal.impl.name", + "kotlin.reflect.jvm.internal.impl.platform", + "kotlin.reflect.jvm.internal.impl.protobuf", + "kotlin.reflect.jvm.internal.impl.renderer", + "kotlin.reflect.jvm.internal.impl.resolve", + "kotlin.reflect.jvm.internal.impl.resolve.calls.inference", + "kotlin.reflect.jvm.internal.impl.resolve.constants", + "kotlin.reflect.jvm.internal.impl.resolve.deprecation", + "kotlin.reflect.jvm.internal.impl.resolve.descriptorUtil", + "kotlin.reflect.jvm.internal.impl.resolve.jvm", + "kotlin.reflect.jvm.internal.impl.resolve.sam", + "kotlin.reflect.jvm.internal.impl.resolve.scopes", + "kotlin.reflect.jvm.internal.impl.resolve.scopes.receivers", + "kotlin.reflect.jvm.internal.impl.serialization", + "kotlin.reflect.jvm.internal.impl.serialization.deserialization", + "kotlin.reflect.jvm.internal.impl.serialization.deserialization.builtins", + "kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors", + "kotlin.reflect.jvm.internal.impl.storage", + "kotlin.reflect.jvm.internal.impl.types", + "kotlin.reflect.jvm.internal.impl.types.checker", + "kotlin.reflect.jvm.internal.impl.types.error", + "kotlin.reflect.jvm.internal.impl.types.model", + "kotlin.reflect.jvm.internal.impl.types.typeUtil", + "kotlin.reflect.jvm.internal.impl.types.typesApproximation", + "kotlin.reflect.jvm.internal.impl.util", + "kotlin.reflect.jvm.internal.impl.util.capitalizeDecapitalize", + "kotlin.reflect.jvm.internal.impl.util.collectionUtils", + "kotlin.reflect.jvm.internal.impl.utils", + "kotlin.reflect.jvm.internal.pcollections" + ], + "org.jetbrains.kotlin:kotlin-script-runtime": [ + "kotlin.script.dependencies", + "kotlin.script.experimental.dependencies", + "kotlin.script.experimental.location", + "kotlin.script.extensions", + "kotlin.script.templates", + "kotlin.script.templates.standard" + ], + "org.jetbrains.kotlin:kotlin-stdlib": [ + "kotlin", + "kotlin.annotation", + "kotlin.collections", + "kotlin.collections.builders", + "kotlin.collections.jdk8", + "kotlin.collections.unsigned", + "kotlin.comparisons", + "kotlin.concurrent", + "kotlin.concurrent.atomics", + "kotlin.concurrent.internal", + "kotlin.contracts", + "kotlin.coroutines", + "kotlin.coroutines.cancellation", + "kotlin.coroutines.intrinsics", + "kotlin.coroutines.jvm.internal", + "kotlin.enums", + "kotlin.experimental", + "kotlin.internal", + "kotlin.internal.jdk7", + "kotlin.internal.jdk8", + "kotlin.io", + "kotlin.io.encoding", + "kotlin.io.path", + "kotlin.jdk7", + "kotlin.js", + "kotlin.jvm", + "kotlin.jvm.functions", + "kotlin.jvm.internal", + "kotlin.jvm.internal.markers", + "kotlin.jvm.internal.unsafe", + "kotlin.jvm.jdk8", + "kotlin.jvm.optionals", + "kotlin.math", + "kotlin.properties", + "kotlin.random", + "kotlin.random.jdk8", + "kotlin.ranges", + "kotlin.reflect", + "kotlin.sequences", + "kotlin.streams.jdk8", + "kotlin.system", + "kotlin.text", + "kotlin.text.jdk8", + "kotlin.time", + "kotlin.time.jdk8", + "kotlin.uuid" + ], + "org.jetbrains.kotlin:kotlin-test": [ + "kotlin.test" + ], + "org.jetbrains.kotlin:kotlin-test-junit": [ + "kotlin.test.junit", + "kotlin.test.junit.annotations" + ], + "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm": [ + "_COROUTINE", + "kotlinx.coroutines", + "kotlinx.coroutines.channels", + "kotlinx.coroutines.debug.internal", + "kotlinx.coroutines.flow", + "kotlinx.coroutines.flow.internal", + "kotlinx.coroutines.future", + "kotlinx.coroutines.internal", + "kotlinx.coroutines.intrinsics", + "kotlinx.coroutines.scheduling", + "kotlinx.coroutines.selects", + "kotlinx.coroutines.stream", + "kotlinx.coroutines.sync", + "kotlinx.coroutines.time" + ], + "org.jetbrains.kotlinx:kotlinx-coroutines-test-jvm": [ + "kotlinx.coroutines.test", + "kotlinx.coroutines.test.internal" + ], + "org.jetbrains.kotlinx:kotlinx-serialization-core-jvm": [ + "kotlinx.serialization", + "kotlinx.serialization.builtins", + "kotlinx.serialization.descriptors", + "kotlinx.serialization.encoding", + "kotlinx.serialization.internal", + "kotlinx.serialization.modules" + ], + "org.jetbrains.kotlinx:kotlinx-serialization-json-jvm": [ + "kotlinx.serialization.json", + "kotlinx.serialization.json.internal" + ], + "org.jetbrains:annotations": [ + "org.intellij.lang.annotations", + "org.jetbrains.annotations" + ], + "org.json:json": [ + "org.json" + ], + "org.slf4j:slf4j-api": [ + "org.slf4j", + "org.slf4j.event", + "org.slf4j.helpers", + "org.slf4j.spi" + ] + }, + "repositories": { + "https://repo.maven.apache.org/maven2/": [ + "ch.qos.logback:logback-classic", + "ch.qos.logback:logback-core", + "com.github.ajalt.clikt:clikt-core-jvm", + "com.github.ajalt.clikt:clikt-jvm", + "com.github.ajalt.colormath:colormath-jvm", + "com.github.ajalt.mordant:mordant-core-jvm", + "com.github.ajalt.mordant:mordant-jvm", + "com.github.ajalt.mordant:mordant-jvm-ffm-jvm", + "com.github.ajalt.mordant:mordant-jvm-graal-ffi-jvm", + "com.github.ajalt.mordant:mordant-jvm-jna-jvm", + "com.pinterest.ktlint:ktlint-cli", + "com.pinterest.ktlint:ktlint-cli-reporter-baseline", + "com.pinterest.ktlint:ktlint-cli-reporter-checkstyle", + "com.pinterest.ktlint:ktlint-cli-reporter-core", + "com.pinterest.ktlint:ktlint-cli-reporter-format", + "com.pinterest.ktlint:ktlint-cli-reporter-html", + "com.pinterest.ktlint:ktlint-cli-reporter-json", + "com.pinterest.ktlint:ktlint-cli-reporter-plain", + "com.pinterest.ktlint:ktlint-cli-reporter-plain-summary", + "com.pinterest.ktlint:ktlint-cli-reporter-sarif", + "com.pinterest.ktlint:ktlint-cli-ruleset-core", + "com.pinterest.ktlint:ktlint-logger", + "com.pinterest.ktlint:ktlint-rule-engine", + "com.pinterest.ktlint:ktlint-rule-engine-core", + "com.pinterest.ktlint:ktlint-ruleset-standard", + "dev.drewhamilton.poko:poko-annotations-jvm", + "io.github.detekt.sarif4k:sarif4k-jvm", + "io.github.oshai:kotlin-logging-jvm", + "junit:junit", + "net.java.dev.jna:jna", + "org.ec4j.core:ec4j-core", + "org.hamcrest:hamcrest-core", + "org.jetbrains.kotlin:kotlin-compiler-embeddable", + "org.jetbrains.kotlin:kotlin-daemon-embeddable", + "org.jetbrains.kotlin:kotlin-reflect", + "org.jetbrains.kotlin:kotlin-script-runtime", + "org.jetbrains.kotlin:kotlin-stdlib", + "org.jetbrains.kotlin:kotlin-test", + "org.jetbrains.kotlin:kotlin-test-junit", + "org.jetbrains.kotlinx:kotlinx-coroutines-core", + "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm", + "org.jetbrains.kotlinx:kotlinx-coroutines-test", + "org.jetbrains.kotlinx:kotlinx-coroutines-test-jvm", + "org.jetbrains.kotlinx:kotlinx-serialization-core-jvm", + "org.jetbrains.kotlinx:kotlinx-serialization-json", + "org.jetbrains.kotlinx:kotlinx-serialization-json-jvm", + "org.jetbrains:annotations", + "org.json:json", + "org.slf4j:slf4j-api" + ] + }, + "services": { + "ch.qos.logback:logback-classic": { + "javax.servlet.ServletContainerInitializer": [ + "ch.qos.logback.classic.servlet.LogbackServletContainerInitializer" + ], + "org.slf4j.spi.SLF4JServiceProvider": [ + "ch.qos.logback.classic.spi.LogbackServiceProvider" + ] + }, + "com.github.ajalt.mordant:mordant-jvm-ffm-jvm": { + "com.github.ajalt.mordant.terminal.TerminalInterfaceProvider": [ + "com.github.ajalt.mordant.terminal.terminalinterface.ffm.TerminalInterfaceProviderFfm" + ] + }, + "com.github.ajalt.mordant:mordant-jvm-graal-ffi-jvm": { + "com.github.ajalt.mordant.terminal.TerminalInterfaceProvider": [ + "com.github.ajalt.mordant.terminal.terminalinterface.nativeimage.TerminalInterfaceProviderNativeImage" + ] + }, + "com.github.ajalt.mordant:mordant-jvm-jna-jvm": { + "com.github.ajalt.mordant.terminal.TerminalInterfaceProvider": [ + "com.github.ajalt.mordant.terminal.terminalinterface.jna.TerminalInterfaceProviderJna" + ] + }, + "com.pinterest.ktlint:ktlint-cli-reporter-baseline": { + "com.pinterest.ktlint.cli.reporter.core.api.ReporterProviderV2": [ + "com.pinterest.ktlint.cli.reporter.baseline.BaselineReporterProvider" + ] + }, + "com.pinterest.ktlint:ktlint-cli-reporter-checkstyle": { + "com.pinterest.ktlint.cli.reporter.core.api.ReporterProviderV2": [ + "com.pinterest.ktlint.cli.reporter.checkstyle.CheckStyleReporterProvider" + ] + }, + "com.pinterest.ktlint:ktlint-cli-reporter-format": { + "com.pinterest.ktlint.cli.reporter.core.api.ReporterProviderV2": [ + "com.pinterest.ktlint.cli.reporter.format.FormatReporterProvider" + ] + }, + "com.pinterest.ktlint:ktlint-cli-reporter-html": { + "com.pinterest.ktlint.cli.reporter.core.api.ReporterProviderV2": [ + "com.pinterest.ktlint.cli.reporter.html.HtmlReporterProvider" + ] + }, + "com.pinterest.ktlint:ktlint-cli-reporter-json": { + "com.pinterest.ktlint.cli.reporter.core.api.ReporterProviderV2": [ + "com.pinterest.ktlint.cli.reporter.json.JsonReporterProvider" + ] + }, + "com.pinterest.ktlint:ktlint-cli-reporter-plain": { + "com.pinterest.ktlint.cli.reporter.core.api.ReporterProviderV2": [ + "com.pinterest.ktlint.cli.reporter.plain.PlainReporterProvider" + ] + }, + "com.pinterest.ktlint:ktlint-cli-reporter-plain-summary": { + "com.pinterest.ktlint.cli.reporter.core.api.ReporterProviderV2": [ + "com.pinterest.ktlint.cli.reporter.plainsummary.PlainSummaryReporterProvider" + ] + }, + "com.pinterest.ktlint:ktlint-cli-reporter-sarif": { + "com.pinterest.ktlint.cli.reporter.core.api.ReporterProviderV2": [ + "com.pinterest.ktlint.cli.reporter.sarif.SarifReporterProvider" + ] + }, + "com.pinterest.ktlint:ktlint-ruleset-standard": { + "com.pinterest.ktlint.cli.ruleset.core.api.RuleSetProviderV3": [ + "com.pinterest.ktlint.ruleset.standard.StandardRuleSetProvider" + ] + }, + "org.jetbrains.kotlin:kotlin-compiler-embeddable": { + "org.jetbrains.kotlin.builtins.BuiltInsLoader": [ + "org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInsLoaderImpl" + ], + "org.jetbrains.kotlin.resolve.ExternalOverridabilityCondition": [ + "org.jetbrains.kotlin.load.java.ErasedOverridabilityCondition", + "org.jetbrains.kotlin.load.java.FieldOverridabilityCondition", + "org.jetbrains.kotlin.load.java.JavaIncompatibilityRulesOverridabilityCondition" + ], + "org.jetbrains.kotlin.resolve.jvm.KotlinToJvmSignatureMapper": [ + "org.jetbrains.kotlin.codegen.signature.KotlinToJvmSignatureMapperImpl" + ], + "org.jetbrains.kotlin.util.ModuleVisibilityHelper": [ + "org.jetbrains.kotlin.cli.common.ModuleVisibilityHelperImpl" + ], + "org/jline/terminal/provider/exec": [ + "class=org.jline.terminal.impl.exec.ExecTerminalProvider" + ], + "org/jline/terminal/provider/jansi": [ + "class=org.jline.terminal.impl.jansi.JansiTerminalProvider" + ], + "org/jline/terminal/provider/jna": [ + "class=org.jline.terminal.impl.jna.JnaTerminalProvider" + ], + "org/jline/terminal/provider/jni": [ + "class=org.jline.terminal.impl.jni.JniTerminalProvider" + ] + }, + "org.jetbrains.kotlin:kotlin-reflect": { + "kotlin.reflect.jvm.internal.impl.builtins.BuiltInsLoader": [ + "kotlin.reflect.jvm.internal.impl.serialization.deserialization.builtins.BuiltInsLoaderImpl" + ], + "kotlin.reflect.jvm.internal.impl.resolve.ExternalOverridabilityCondition": [ + "kotlin.reflect.jvm.internal.impl.load.java.ErasedOverridabilityCondition", + "kotlin.reflect.jvm.internal.impl.load.java.FieldOverridabilityCondition", + "kotlin.reflect.jvm.internal.impl.load.java.JavaIncompatibilityRulesOverridabilityCondition" + ] + }, + "org.jetbrains.kotlin:kotlin-test-junit": { + "kotlin.test.AsserterContributor": [ + "kotlin.test.junit.JUnitContributor" + ] + }, + "org.jetbrains.kotlinx:kotlinx-coroutines-test-jvm": { + "kotlinx.coroutines.CoroutineExceptionHandler": [ + "kotlinx.coroutines.test.internal.ExceptionCollectorAsService" + ], + "kotlinx.coroutines.internal.MainDispatcherFactory": [ + "kotlinx.coroutines.test.internal.TestMainDispatcherFactory" + ] + } + }, + "version": "3" +} diff --git a/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/BUILD.bazel b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/BUILD.bazel new file mode 100644 index 000000000..89257e65c --- /dev/null +++ b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/BUILD.bazel @@ -0,0 +1,94 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("@bazel_skylib//rules:copy_file.bzl", "copy_file") +load("@rules_java//java:defs.bzl", "java_library", "java_test") +load("//build_defs/languages/jvm:maven.bzl", "java_javadoc", "kotlin_maven_package") +load("//build_defs/foundation:bun.bzl", "bun_source_output") +load("//build_defs/extensions:platforms.bzl", "NATIVE_EXTENSION_CONFIGURATION") +load("//build_defs/release:supplier.bzl", "file_shipping_supplier") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["build.gradle.kts", "src/main/resources/dev/oliphaunt/android/liboliphaunt.version"]) + +bun_source_output( + name = "plugin_descriptor", + source = "build.gradle.kts", + tool = "//build_defs/languages/jvm:plugin_descriptor", + out = "src/main/resources/META-INF/gradle-plugins/dev.oliphaunt.android.properties", +) + +copy_file(name = "database_version", src = "//src/database-resources:VERSION", out = "src/main/resources/dev/oliphaunt/android/database-resources.version") +copy_file(name = "public_header", src = "//src/native/runtime:include/oliphaunt.h", out = "src/main/resources/dev/oliphaunt/android/oliphaunt.h") +copy_file(name = "cxx_map", src = "//src/native/runtime:bin/android-cxx-runtime.map", out = "src/main/resources/dev/oliphaunt/android/android-cxx-runtime.map") +copy_file(name = "archive_policy", src = "//src/extensions/contracts:extension-artifact-archive-policy.properties", out = "src/main/resources/dev/oliphaunt/android/extension-artifact-archive-policy.properties") +copy_file(name = "license", src = "//:LICENSE", out = "src/main/resources/META-INF/LICENSE") +copy_file(name = "notices", src = "//:THIRD_PARTY_NOTICES.md", out = "src/main/resources/META-INF/THIRD_PARTY_NOTICES.md") + +java_library( + name = "plugin", + srcs = glob(["src/main/java/**/*.java"]), + resources = glob(["src/main/resources/**/*"]) + [":plugin_descriptor", ":database_version", ":public_header", ":cxx_map", ":archive_policy", ":license", ":notices"], + resource_strip_prefix = "src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/resources", + deps = ["@oliphaunt_gradle_api//:api"], + javacopts = ["--release", "17"], +) + +java_test( + name = "contract_test", + srcs = glob(["src/test/java/**/*.java"]), + deps = [":plugin", "@oliphaunt_gradle_api//:test_runtime"], + main_class = "dev.oliphaunt.android.OliphauntExtensionCatalogContractTest", + use_testrunner = False, + jvm_flags = ["--add-opens=java.base/java.lang=ALL-UNNAMED"], + javacopts = ["--release", "17"], + data = [ + "//:LICENSE", + "//:THIRD_PARTY_NOTICES.md", + "//src/extensions/generated/sdk:metadata", + "//src/extensions/contrib:carriers.toml", + "//src/third-party/postgres:COPYRIGHT", + "//src/third-party/openssl:LICENSE.txt", + "//src/extensions/external/pg_hashids:upstream-license-data.json", + "//src/extensions/external/pg_uuidv7:upstream-license-data.json", + "//src/extensions/external/pg_ivm:upstream-license-data.json", + "//src/extensions/external/pg_textsearch:upstream-license-data.json", + "//src/extensions/external/pgtap:upstream-license-data.json", + "//src/extensions/external/vector:upstream-license-data.json", + "//src/extensions/external/postgis:upstream-license-data.json", + ], + size = "medium", +) + +java_javadoc( + name = "plugin_javadoc", + srcs = glob(["src/main/java/**/*.java"]), + deps = ["@oliphaunt_gradle_api//:api"], +) + +file_shipping_supplier( + name = "native_contract_suppliers", + inputs = {"//src/native/runtime:include/oliphaunt.h": "", "//src/native/runtime:bin/android-cxx-runtime.map": ""}, + owner = "@oliphaunt_metadata//:product_liboliphaunt-native", + configuration = NATIVE_EXTENSION_CONFIGURATION, + binding = "abi-contract", + origin = json.encode({"kind": "current-source"}), +) + +kotlin_maven_package( + name = "plugin_maven", + coordinate = "dev.oliphaunt:oliphaunt-android-gradle-plugin", + packaging = "jar", + classes = [":plugin"], + sources = glob(["src/main/java/**/*.java"]), + legal_sources = ["//:LICENSE", "//:THIRD_PARTY_NOTICES.md"], + javadoc = ":plugin_javadoc", + suppliers = ":native_contract_suppliers", +) + +kotlin_maven_package( + name = "marker_maven", + coordinate = "dev.oliphaunt.android:dev.oliphaunt.android.gradle.plugin", + packaging = "pom", +) + +source_quality_files() diff --git a/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/java/dev/oliphaunt/android/OliphauntExtensionCatalog.java b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/java/dev/oliphaunt/android/OliphauntExtensionCatalog.java index 6dd1f2e1e..6a2eb4fd5 100644 --- a/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/java/dev/oliphaunt/android/OliphauntExtensionCatalog.java +++ b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/main/java/dev/oliphaunt/android/OliphauntExtensionCatalog.java @@ -92,7 +92,7 @@ static List resolveOwners( } } - Map overrideValues = new LinkedHashMap<>(); + Map overrideValues = new LinkedHashMap<>(); for (Map.Entry override : overrides.entrySet()) { String releaseProduct = override.getKey().trim(); String version = override.getValue().trim(); @@ -104,12 +104,12 @@ static List resolveOwners( + " does not identify a selected extension release owner"); } validateVersion(version, "Oliphaunt extension release owner " + owner.entry.releaseProduct()); - overrideValues.put(owner, version); + overrideValues.put(releaseProduct, version); } List result = new ArrayList<>(); for (OwnerBuilder builder : builders.values()) { - String version = overrideValues.get(builder); + String version = overrideValues.get(builder.entry.releaseProduct()); if (version == null) { if (!builder.entry.runtimeBound()) { throw new GradleException( diff --git a/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/test/java/dev/oliphaunt/android/OliphauntExtensionCatalogContractTest.java b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/test/java/dev/oliphaunt/android/OliphauntExtensionCatalogContractTest.java index c906a044e..dbfbe82c4 100644 --- a/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/test/java/dev/oliphaunt/android/OliphauntExtensionCatalogContractTest.java +++ b/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/src/test/java/dev/oliphaunt/android/OliphauntExtensionCatalogContractTest.java @@ -37,6 +37,12 @@ public final class OliphauntExtensionCatalogContractTest { private OliphauntExtensionCatalogContractTest() {} public static void main(String[] args) throws Exception { + String testTmpDir = System.getenv("TEST_TMPDIR"); + if (testTmpDir != null) { + System.setProperty( + "gradle.user.home", + Files.createDirectories(Path.of(testTmpDir, "gradle-user-home")).toString()); + } createsManagedPluginExtensionWithoutGradleNameCollision(); resolvesRuntimeBoundBundleOnceWithDependencyClosure(); acceptsProductionShapedRuntimeBundlesForBothAndroidAbis(); diff --git a/src/native/sdks/kotlin/oliphaunt/build.gradle.kts b/src/native/sdks/kotlin/oliphaunt/build.gradle.kts index e0d35047b..8d7bbc63f 100644 --- a/src/native/sdks/kotlin/oliphaunt/build.gradle.kts +++ b/src/native/sdks/kotlin/oliphaunt/build.gradle.kts @@ -73,11 +73,16 @@ version = providers.gradleProperty("VERSION_NAME").orElse("0.0.0").get() spotless { kotlin { target("src/**/*.kt", "../tests/public-api-consumer/src/**/*.kt") - ktlint().editorConfigOverride(mapOf("ktlint_standard_property-naming" to "disabled")) + ktlint(libs.versions.ktlint.get()).editorConfigOverride( + mapOf( + "ktlint_standard_property-naming" to "disabled", + "ktlint_code_style" to "intellij_idea", + ), + ) } kotlinGradle { target("*.gradle.kts", "../*.gradle.kts", "../tests/public-api-consumer/*.gradle.kts") - ktlint() + ktlint(libs.versions.ktlint.get()) } } @@ -735,21 +740,21 @@ kotlin { androidMain { kotlin.srcDir(generateNativeBindings.map { mobileBindingsRoot.dir("generated/dev") }) dependencies { - implementation("net.java.dev.jna:jna:5.14.0@aar") + implementation("net.java.dev.jna:jna:${libs.versions.jna.get()}@aar") } } commonMain.dependencies { - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2") + implementation(libs.kotlinx.coroutines.core) } commonTest.dependencies { implementation(kotlin("test")) - implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.2") + implementation(libs.kotlinx.coroutines.test) implementation(libs.kotlinx.serialization.json) } androidUnitTest.dependencies { - implementation("net.java.dev.jna:jna:5.14.0") + implementation(libs.jna) // Android's SDK jar contains only throwing org.json stubs on the host JVM. - implementation("org.json:json:20240303") + implementation(libs.org.json) } } } diff --git a/src/native/sdks/kotlin/oliphaunt/src/androidMain/cpp/CMakeLists.txt b/src/native/sdks/kotlin/oliphaunt/src/androidMain/cpp/CMakeLists.txt index 4de8b808e..9b9223e36 100644 --- a/src/native/sdks/kotlin/oliphaunt/src/androidMain/cpp/CMakeLists.txt +++ b/src/native/sdks/kotlin/oliphaunt/src/androidMain/cpp/CMakeLists.txt @@ -113,5 +113,6 @@ if(DEFINED OLIPHAUNT_MOBILE_STATIC_MODULES AND NOT "${OLIPHAUNT_MOBILE_STATIC_MO endif() target_link_options(oliphaunt_extensions PRIVATE "-Wl,-z,max-page-size=16384" + "-Wl,-z,common-page-size=16384" ) endif() diff --git a/src/native/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/NativeBindingsTest.kt b/src/native/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/NativeBindingsTest.kt index 91b1a69a0..38c07335a 100644 --- a/src/native/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/NativeBindingsTest.kt +++ b/src/native/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/NativeBindingsTest.kt @@ -6,9 +6,11 @@ import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking +import org.json.JSONArray import org.json.JSONObject import org.junit.Assume.assumeTrue import java.io.File +import java.nio.file.Files import kotlin.test.Test import kotlin.test.assertContentEquals import kotlin.test.assertEquals @@ -19,23 +21,21 @@ import kotlin.test.assertTrue class NativeBindingsTest { @Test fun generatedBridgePreservesTypedQueriesCancellationAndRecovery() = runBlocking { - val pgdata = System.getenv("OLIPHAUNT_MOBILE_TEST_PGDATA") + val declared = if (System.getenv("OLIPHAUNT_MOBILE_TEST_PGDATA") == null) declaredNativeFixture() else null + val pgdata = System.getenv("OLIPHAUNT_MOBILE_TEST_PGDATA") ?: declared?.pgdata assumeTrue("requires a prepared native database", pgdata != null) val descriptor = File(File(requireNotNull(pgdata)).parentFile, ".oliphaunt.json") if (!descriptor.exists()) { - val fixture = JSONObject(File(System.getProperty("oliphaunt.sharedFixturesDir"), "storage/database-root.json").readText()) - val descriptors = fixture.getJSONArray("validDescriptors") - val native = (0 until descriptors.length()).map(descriptors::getJSONObject) - .first { it.getString("engineFamily") == "native" } - descriptor.writeText("$native\n") + descriptor.writeText("${nativeDatabaseDescriptor()}\n") } - System.setProperty("jna.library.path", System.getenv("OLIPHAUNT_MOBILE_BINDINGS_DIR")) + val library = System.getenv("LIBOLIPHAUNT_PATH") ?: declared?.library + System.setProperty("jna.library.path", System.getenv("OLIPHAUNT_MOBILE_BINDINGS_DIR") ?: declared?.bindings) val native = NativeDatabase.open( OpenOptions( - System.getenv("LIBOLIPHAUNT_PATH"), + library, requireNotNull(pgdata), - System.getenv("OLIPHAUNT_INSTALL_DIR"), - System.getenv("OLIPHAUNT_EMBEDDED_MODULE_DIR"), + System.getenv("OLIPHAUNT_INSTALL_DIR") ?: declared?.runtime, + System.getenv("OLIPHAUNT_EMBEDDED_MODULE_DIR") ?: declared?.modules, null, "postgres", "postgres", @@ -46,7 +46,7 @@ class NativeBindingsTest { EngineConfig(), object : OliphauntEngine { override suspend fun open(config: EngineConfig): OliphauntSession = AndroidNativeDirectSession(native) - override suspend fun restore(destination: String, bytes: ByteArray) = dev.oliphaunt.bindings.restore(System.getenv("LIBOLIPHAUNT_PATH"), destination, bytes) + override suspend fun restore(destination: String, bytes: ByteArray) = dev.oliphaunt.bindings.restore(library, destination, bytes) }, ) try { @@ -100,3 +100,50 @@ class NativeBindingsTest { } } } + +private data class NativeFixture( + val pgdata: String, + val library: String, + val runtime: String, + val modules: String, + val bindings: String, +) + +private fun nativeDatabaseDescriptor(): JSONObject { + val fixture = JSONObject(File(sharedFixtureDirectory(), "storage/database-root.json").readText()) + val descriptors = fixture.getJSONArray("validDescriptors") + return (0 until descriptors.length()).map(descriptors::getJSONObject) + .first { it.getString("engineFamily") == "native" } +} + +private fun declaredNativeFixture(): NativeFixture? { + val supplied = System.getProperty("oliphaunt.native.facts") ?: return null + val facts = File(supplied).absoluteFile + val rows = JSONArray(facts.readText()) + val row = (0 until rows.length()).map(rows::getJSONObject).single { it.getString("target") == "linux-x64-gnu" } + val root = File(facts.parentFile, row.getString("target")) + val runtime = File(root, "runtime") + val library = File(root, row.getString("library")) + val bindings = File(checkNotNull(System.getProperty("oliphaunt.native.bindings"))).absoluteFile + check(library.isFile && bindings.isFile) { "Native test requires both declared shared libraries" } + val temporary = Files.createTempDirectory(File(checkNotNull(System.getenv("TEST_TMPDIR"))).toPath(), "native-bindings-").toFile() + val pgdata = File(temporary, nativeDatabaseDescriptor().getString("pgdata")) + val process = ProcessBuilder( + File(runtime, "bin/initdb").absolutePath, + "-D", pgdata.absolutePath, + "-L", File(runtime, "share/postgresql").absolutePath, + "--no-sync", "-U", "postgres", "--locale-provider=libc", "--locale=C", "-E", "UTF8", + ).redirectErrorStream(true) + process.environment().apply { + clear() + put("LANG", "C") + put("LD_LIBRARY_PATH", listOf(File(root, "lib"), File(runtime, "lib")).joinToString(File.pathSeparator) { it.absolutePath }) + // The default published runtime has no optional ICU data carrier. + put("OLIPHAUNT_INTERNAL_SKIP_SYSTEM_COLLATION_DISCOVERY", "1") + put("OLIPHAUNT_INTERNAL_SKIP_ICU_DISCOVERY", "1") + } + val initialized = process.start() + val output = initialized.inputStream.bufferedReader().readText() + check(initialized.waitFor() == 0) { "Declared runtime initdb failed: $output" } + return NativeFixture(pgdata.absolutePath, library.absolutePath, runtime.absolutePath, File(runtime, "lib").absolutePath, checkNotNull(bindings.parentFile).absolutePath) +} diff --git a/src/native/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/OliphauntAndroidRuntimeAssetsTest.kt b/src/native/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/OliphauntAndroidRuntimeAssetsTest.kt index ecb1b5b34..951a626c5 100644 --- a/src/native/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/OliphauntAndroidRuntimeAssetsTest.kt +++ b/src/native/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/OliphauntAndroidRuntimeAssetsTest.kt @@ -1101,10 +1101,7 @@ class OliphauntAndroidRuntimeAssetsTest { } private fun databaseRootFixture(): JSONObject { - val directory = - checkNotNull(System.getProperty("oliphaunt.sharedFixturesDir")?.takeIf(String::isNotBlank)) { - "Run fixture tests through Gradle to configure oliphaunt.sharedFixturesDir" - } + val directory = sharedFixtureDirectory() return JSONObject(Path.of(directory, "storage", "database-root.json").toFile().readText()) } @@ -1257,12 +1254,7 @@ private fun retargetNativeClusterSeedFixture( target: String, icuDataTreeSha256: String? = null, ): String { - val fixtureRoot = - System - .getProperty("oliphaunt.clusterSeedFixturesDir") - ?.takeIf(String::isNotBlank) - ?.let(Path::of) - ?: error("oliphaunt.clusterSeedFixturesDir is not configured") + val fixtureRoot = clusterSeedFixtureDirectory() val overrides = buildMap { put("target", target) diff --git a/src/native/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/TestFixtures.kt b/src/native/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/TestFixtures.kt new file mode 100644 index 000000000..5522374ba --- /dev/null +++ b/src/native/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/TestFixtures.kt @@ -0,0 +1,17 @@ +package dev.oliphaunt + +import java.nio.file.Path + +internal fun sharedFixtureDirectory(): String = System.getProperty("oliphaunt.sharedFixturesDir")?.takeIf(String::isNotBlank) + ?: Path.of( + checkNotNull(System.getenv("TEST_SRCDIR")) { "Shared fixtures require a declared test runfiles directory" }, + checkNotNull(System.getenv("TEST_WORKSPACE")), + "src/test-fixtures", + ).toString() + +internal fun clusterSeedFixtureDirectory(): Path = System.getProperty("oliphaunt.clusterSeedFixturesDir")?.takeIf(String::isNotBlank)?.let(Path::of) + ?: Path.of( + checkNotNull(System.getenv("TEST_SRCDIR")) { "Cluster-seed fixtures require a declared test runfiles directory" }, + checkNotNull(System.getenv("TEST_WORKSPACE")), + "src/database-resources/contracts/fixtures", + ) diff --git a/src/native/sdks/kotlin/oliphaunt/src/jvmTest/kotlin/dev/oliphaunt/SharedProtocolFixtureTest.kt b/src/native/sdks/kotlin/oliphaunt/src/jvmTest/kotlin/dev/oliphaunt/SharedProtocolFixtureTest.kt index e3ade9dc0..258da96f3 100644 --- a/src/native/sdks/kotlin/oliphaunt/src/jvmTest/kotlin/dev/oliphaunt/SharedProtocolFixtureTest.kt +++ b/src/native/sdks/kotlin/oliphaunt/src/jvmTest/kotlin/dev/oliphaunt/SharedProtocolFixtureTest.kt @@ -146,8 +146,13 @@ class SharedProtocolFixtureTest { private fun sharedProtocolFixturePath(name: String): Path { val directory = - checkNotNull(System.getProperty("oliphaunt.sharedFixturesDir")?.takeIf(String::isNotBlank)) { - "Run fixture tests through Gradle to configure oliphaunt.sharedFixturesDir" + checkNotNull( + System.getProperty("oliphaunt.sharedFixturesDir")?.takeIf(String::isNotBlank) + ?: System.getenv("TEST_SRCDIR")?.let { runfiles -> + Path.of(runfiles, requireNotNull(System.getenv("TEST_WORKSPACE")), "src/test-fixtures").toString() + }, + ) { + "The fixture test requires the declared shared fixture directory" } return Path.of(directory, "protocol", name) } diff --git a/src/native/sdks/kotlin/settings.gradle.kts b/src/native/sdks/kotlin/settings.gradle.kts index 15bcfa028..03a01c019 100644 --- a/src/native/sdks/kotlin/settings.gradle.kts +++ b/src/native/sdks/kotlin/settings.gradle.kts @@ -23,7 +23,8 @@ dependencyResolutionManagement { } val oliphauntBuildRoot = - providers.gradleProperty("oliphauntBuildRoot") + providers + .gradleProperty("oliphauntBuildRoot") .orElse(providers.environmentVariable("OLIPHAUNT_GRADLE_BUILD_ROOT")) .orNull ?.takeIf(String::isNotBlank) diff --git a/src/native/sdks/kotlin/tests/broker-app/build.gradle.kts b/src/native/sdks/kotlin/tests/broker-app/build.gradle.kts index ad9e087c9..66d8e416b 100644 --- a/src/native/sdks/kotlin/tests/broker-app/build.gradle.kts +++ b/src/native/sdks/kotlin/tests/broker-app/build.gradle.kts @@ -14,5 +14,5 @@ kotlin { jvmToolchain(17) } dependencies { implementation(files(providers.gradleProperty("aar").get())) implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2") - implementation("net.java.dev.jna:jna:5.14.0@aar") + implementation("net.java.dev.jna:jna:5.18.1@aar") } diff --git a/src/native/sdks/kotlin/tests/public-api-consumer/build.gradle.kts b/src/native/sdks/kotlin/tests/public-api-consumer/build.gradle.kts index 9da706fd3..a2edaf3d2 100644 --- a/src/native/sdks/kotlin/tests/public-api-consumer/build.gradle.kts +++ b/src/native/sdks/kotlin/tests/public-api-consumer/build.gradle.kts @@ -3,8 +3,9 @@ plugins { alias(libs.plugins.kotlin.android) } -val consumerAar = providers.gradleProperty("oliphauntConsumerAar").orNull - ?: error("oliphauntConsumerAar must point to the packaged Oliphaunt Android AAR") +val consumerAar = + providers.gradleProperty("oliphauntConsumerAar").orNull + ?: error("oliphauntConsumerAar must point to the packaged Oliphaunt Android AAR") layout.buildDirectory.set( file( diff --git a/src/native/sdks/kotlin/tools/check-package.mts b/src/native/sdks/kotlin/tools/check-package.mts index 074bed86e..f7de6db7f 100644 --- a/src/native/sdks/kotlin/tools/check-package.mts +++ b/src/native/sdks/kotlin/tools/check-package.mts @@ -1,4 +1,6 @@ #!/usr/bin/env bun +import path from 'node:path'; +import { readPortableArchiveEntries } from '../../../../../tools/packaging/portable-archive.mts'; import { archiveZipNames, fail, @@ -9,9 +11,7 @@ import { walkFiles, } from '../../../../../tools/packaging/release-carrier.mts'; import { compareText } from '../../../../../tools/release/release-artifact-targets.mts'; -import path from 'node:path'; -import { readPortableArchiveEntries } from '../../../../../tools/packaging/portable-archive.mts'; -import { assertRustDependencyLicensesInEntries } from '../../../mobile-bindings/tools/dependency-license-contract.mts'; +import { createMobileDependencyLicenseContract } from '../../../mobile-bindings/tools/dependency-license-contract.mts'; const KOTLIN_RELEASE_ABIS = new Set(['arm64-v8a', 'x86_64']); const GRADLE_PLUGIN_DESCRIPTOR = 'META-INF/gradle-plugins/dev.oliphaunt.android.properties'; @@ -66,7 +66,12 @@ export function validateKotlinGradlePluginJar(artifact, entries) { return true; } -export async function checkKotlinPackage(root) { +export async function checkKotlinPackage( + root, + { sourceRoot = undefined as string | undefined } = {}, +) { + const { assertRustDependencyLicensesInEntries } = + createMobileDependencyLicenseContract(sourceRoot); const product = 'oliphaunt-kotlin'; let checked = false; let checkedGradlePlugin = false; diff --git a/src/native/sdks/react-native/BUILD.bazel b/src/native/sdks/react-native/BUILD.bazel new file mode 100644 index 000000000..9a5957077 --- /dev/null +++ b/src/native/sdks/react-native/BUILD.bazel @@ -0,0 +1,214 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("@aspect_rules_js//js:defs.bzl", "js_library") +load("@aspect_rules_ts//ts:defs.bzl", "ts_config", "ts_project") +load("@bazel_lib//lib:copy_file.bzl", "copy_file") +load("@javascript_packages//:defs.bzl", "PACKAGES", "javascript_type_links") +load("@javascript_compiler_packages//:defs.bzl", "compiler_input_links") +load("@javascript_compiler_packages//:roots.bzl", "COMPILER_CLOSURES", "COMPILER_INPUTS", "COMPILER_PACKAGES") +load("@oliphaunt_javascript_metadata//:metadata.bzl", "JAVASCRIPT") +load("@rules_cc//cc:cc_test.bzl", "cc_test") +load("//build_defs/extensions:sdk_projections.bzl", "sdk_extension_metadata", "sdk_extension_projections") +load("//build_defs/languages/ts:defs.bzl", "workspace_dependency_package", "workspace_dependency_link") +load("//build_defs/languages/jvm:robolectric.bzl", "robolectric_sdk") +load("@rules_java//java:java_import.bzl", "java_import") +load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_test") +load("//build_defs/query:defs.bzl", "query_envelope") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") +load(":native-package.bzl", "react_native_bundle", "react_native_consumer_test", "react_native_manifest", "react_native_npm", "react_native_package_test", "react_native_templates") + +package(default_visibility = ["//visibility:public"]) + +_LIB_OUT_DIR = "lib" +_TOOLS_OUT_DIR = "native-tools" +_DELIVERED_HELPERS = { + "app_plugin": "app.plugin.js", + "react_native_config": "react-native.config.js", + "codegen_check": "tools/codegen-check.cjs", + "resource_closure": "tools/native-resource-closure.mjs", + "ios_verifier": "tools/verify-ios-package.mjs", + "ios_stager": "tools/stage-ios-app.mjs", +} + +exports_files(["package.json", "native-package.bzl", "ios/OliphauntAdapter.swift", "ios/OliphauntAdapter.h"]) + +SDK = JAVASCRIPT["@oliphaunt/react-native"] +QUERY = JAVASCRIPT["@oliphaunt/ts-query"] +SDK_SRCS = glob(["src/**/*.ts"], exclude = ["src/__tests__/**", "src/extensions.ts", "src/generated/extensions.ts"]) +SOURCE_FILES = glob(["android/**", "ios/**", "cpp/**", "README.md", "CHANGELOG.md", "OliphauntReactNative.podspec"], exclude = ["android/.gradle/**", "android/.cxx/**", "android/build/**", "android/src/main/assets/**", "android/src/main/jniLibs/**", "android/src/test/**", "ios/vendor/**", "ios/extension-frameworks/**", "ios/frameworks/**", "ios/generated/**", "ios/resources/**", "ios/templates/**", "cpp/*.test.cpp"]) + +javascript_type_links(SDK["types"]) +compiler_input_links(COMPILER_INPUTS[SDK["name"]]) +workspace_dependency_package(name = "query_package", workspace = SDK, dependency = QUERY["name"], current = "//src/query/ts:shipping_package") +workspace_dependency_link(name = "node_modules/@oliphaunt/ts-query", package = ":query_package", workspace = SDK, dependency = QUERY["name"]) +js_library(name = "package_metadata", srcs = ["package.json"]) + +sdk_extension_projections(name = "extension_projections", sdk = "react-native") +sdk_extension_metadata(name = "extension_metadata", out = "src/generated/extensions.json") + +COMPILER_DEPS = [":package_metadata", ":node_modules/@oliphaunt/ts-query"] + [":node_modules/" + name for name in SDK["types"]] + [":node_modules/" + name for name in COMPILER_INPUTS[SDK["name"]]] + +ts_config(name = "base_tsconfig", src = "tsconfig.json", deps = [":node_modules/@react-native/typescript-config"]) +js_library( + name = "source_inputs", + types = SDK_SRCS + [":extension_projections"], + deps = [":package_metadata", ":base_tsconfig", ":node_modules/react-native"] + [":node_modules/" + name for name in SDK["types"]], +) +ts_project(name = "module", srcs = SDK_SRCS + [":extension_projections"], tsconfig = "tsconfig.build.module.json", extends = ":base_tsconfig", allow_js = True, resolve_json_module = True, out_dir = _LIB_OUT_DIR + "/module", root_dir = "src", transpiler = "tsc", supports_workers = 0, deps = COMPILER_DEPS) +ts_project(name = "commonjs", srcs = SDK_SRCS + [":extension_projections"], tsconfig = "tsconfig.build.commonjs.json", extends = ":base_tsconfig", allow_js = True, resolve_json_module = True, out_dir = _LIB_OUT_DIR + "/commonjs", root_dir = "src", transpiler = "tsc", supports_workers = 0, deps = COMPILER_DEPS) +ts_project(name = "types", srcs = SDK_SRCS + [":extension_projections"], tsconfig = "tsconfig.build.types.json", extends = ":base_tsconfig", allow_js = True, resolve_json_module = True, declaration = True, declaration_map = True, emit_declaration_only = True, out_dir = _LIB_OUT_DIR + "/typescript", root_dir = "src", transpiler = "tsc", supports_workers = 0, deps = COMPILER_DEPS) + +ts_project( + name = "source_checks", + srcs = SDK_SRCS + glob(["src/__tests__/**/*.ts"]) + [":extension_projections"], + tsconfig = ":base_tsconfig", + allow_js = True, + resolve_json_module = True, + no_emit = True, + declaration = True, + declaration_map = True, + out_dir = _LIB_OUT_DIR + "/typescript", + root_dir = "src", + supports_workers = 0, + deps = COMPILER_DEPS, +) + +ts_project( + name = "helpers", + srcs = ["app.plugin.cts", "react-native.config.cts", "tools/codegen-check.cts", "tools/native-resource-closure.mts", "tools/verify-ios-package.mts"], + tsconfig = {"compilerOptions": {"target": "ES2022", "module": "NodeNext", "rewriteRelativeImportExtensions": True, "noCheck": True}}, + root_dir = ".", out_dir = _TOOLS_OUT_DIR, transpiler = "tsc", supports_workers = 0, + deps = [":package_metadata"] + [":node_modules/" + name for name in SDK["types"]], +) +copy_file(name = "app_plugin", src = _TOOLS_OUT_DIR + "/app.plugin.cjs", out = _DELIVERED_HELPERS["app_plugin"]) +copy_file(name = "react_native_config", src = _TOOLS_OUT_DIR + "/react-native.config.cjs", out = _DELIVERED_HELPERS["react_native_config"]) +copy_file(name = "codegen_check", src = _TOOLS_OUT_DIR + "/tools/codegen-check.cjs", out = _DELIVERED_HELPERS["codegen_check"]) +copy_file(name = "resource_closure", src = _TOOLS_OUT_DIR + "/tools/native-resource-closure.mjs", out = _DELIVERED_HELPERS["resource_closure"]) +copy_file(name = "ios_verifier", src = _TOOLS_OUT_DIR + "/tools/verify-ios-package.mjs", out = _DELIVERED_HELPERS["ios_verifier"]) +react_native_bundle( + name = "ios_stager", out = _DELIVERED_HELPERS["ios_stager"], + sources = { + "tools/stage-ios-app.mts": "src/native/sdks/react-native/tools/stage-ios-app.mts", + "tools/native-resource-closure.mts": "src/native/sdks/react-native/tools/native-resource-closure.mts", + "//:tools/packaging/portable-archive.mts": "tools/packaging/portable-archive.mts", + }, +) +react_native_templates(name = "broker_templates", sources = "//src/native/sdks/swift:broker_templates") + +react_native_manifest(name = "publish_files", manifest = "package.json") +filegroup(name = "publish_manifest", srcs = [":publish_files"], output_group = "manifest") +filegroup(name = "license", srcs = [":publish_files"], output_group = "license") +filegroup(name = "notices", srcs = [":publish_files"], output_group = "notices") + +# This source envelope remains an independent compiler/consumer input. +query_envelope( + name = "source_npm", format = "npm", manifest = ":publish_manifest", out = "oliphaunt-react-native-source.tgz", + entries = {file: file for file in SOURCE_FILES + SDK_SRCS} | { + ":module": "lib/module/", ":commonjs": "lib/commonjs/", ":types": "lib/typescript/", + ":extension_projections": "src/", ":extension_metadata": "src/generated/extensions.json", + ":broker_templates": "ios/templates/", + ":publish_manifest": "package.json", ":license": "LICENSE", ":notices": "THIRD_PARTY_NOTICES.md", + ":app_plugin": "app.plugin.js", ":react_native_config": "react-native.config.js", + ":codegen_check": "tools/codegen-check.cjs", ":resource_closure": "tools/native-resource-closure.mjs", + ":ios_verifier": "tools/verify-ios-package.mjs", ":ios_stager": "tools/stage-ios-app.mjs", + }, +) + +shipping_package(name = "construction", owner = "@oliphaunt_metadata//:product_oliphaunt-react-native", artifacts = [":source_npm"], ecosystem = "internal", package_name = SDK["name"], configuration = "portable", role = "construction", suppliers = "//build_defs/release:no_suppliers") + +# The final package follows its conventional Swift pin and genuine native Files. +react_native_npm(name = "npm", out = "oliphaunt-react-native-" + SDK["version"] + ".tgz", source_archive = ":source_npm", manifest = "package.json") +filegroup(name = "ios_carrier_input", srcs = [":npm"], output_group = "carrier") +react_native_package_test(name = "package_test", archive = ":npm", carrier_output = ":ios_carrier_input", source_archive = ":source_npm", manifest = "package.json", size = "small") +shipping_package(name = "ios_carrier_shipping", owner = "@oliphaunt_metadata//:product_oliphaunt-react-native", artifacts = [":ios_carrier_input"], ecosystem = "github", package_name = "oliphaunt-react-native-ios-carriers.json", configuration = "portable", role = "release-input", suppliers = "@react_native_swift_package//:package_suppliers") +shipping_package(name = "package", owner = "@oliphaunt_metadata//:product_oliphaunt-react-native", artifacts = [":npm"], ecosystem = "npm", package_name = SDK["name"], configuration = "portable", role = "source-sdk", suppliers = "@react_native_swift_package//:package_suppliers") +shipping_export(name = "apple_shipping_export", packages = [":construction", ":package", ":ios_carrier_shipping"], qualification = [":package_test", ":installed_consumer_test", "//src/examples/native/react-native-expo:autolinking_consumer_test", "//src/examples/native/react-native-expo:ios_installed_test"], testonly = True, target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:aarch64"]) + +CONSUMER_COMPILER_IDS = [key for root in COMPILER_INPUTS[SDK["name"]].values() for key in COMPILER_CLOSURES[root]] +CONSUMER_COMPILER_PACKAGES = {key: row for key, row in COMPILER_PACKAGES.items() if key in CONSUMER_COMPILER_IDS} + +CONSUMER_PACKAGES = {key: json.encode({"dependencies": row["dependencies"]}) for key, row in PACKAGES.items()} | {key: json.encode({"dependencies": row["dependencies"]}) for key, row in CONSUMER_COMPILER_PACKAGES.items()} +CONSUMER_ARCHIVES = {"@javascript_packages//:" + key: key for key in PACKAGES} | {"@javascript_compiler_packages//:" + key: key for key in CONSUMER_COMPILER_PACKAGES if key not in PACKAGES} +CONSUMER_ROOTS = SDK["types"] | COMPILER_INPUTS[SDK["name"]] + +react_native_consumer_test( + name = "source_consumer_test", archive = ":source_npm", query = ":query_package", manifest = "package.json", + package_name = SDK["name"], version = SDK["version"], + packages = CONSUMER_PACKAGES, inputs = CONSUMER_ARCHIVES, roots = CONSUMER_ROOTS, size = "medium", +) +react_native_consumer_test( + name = "installed_consumer_test", archive = ":npm", final_package = True, + runtime_resources = "@react_native_swift_package//:runtime_resources_archive", size = "medium", + query = ":query_package", manifest = "package.json", source_archive = ":source_npm", + package_name = SDK["name"], version = SDK["version"], + packages = CONSUMER_PACKAGES, inputs = CONSUMER_ARCHIVES, roots = CONSUMER_ROOTS, + native_base = "@react_native_swift_package//:native_requirement", + carrier = "@react_native_swift_package//:carrier", carrier_source = "@react_native_swift_package//:construction.json", + ios_static_dependencies = "//src/extensions/generated/sdk:ios-static-dependencies.json", +) + +cc_test( + name = "lifecycle_test", + srcs = ["cpp/Lifecycle.test.cpp", "cpp/Lifecycle.h"], + copts = select({ + "@bazel_tools//src/conditions:windows": ["/std:c++17", "/W4", "/WX", "/UNDEBUG"], + "//conditions:default": ["-std=c++17", "-Wall", "-Wextra", "-Werror", "-UNDEBUG"], + }), + linkopts = select({ + "@bazel_tools//src/conditions:windows": [], + "//conditions:default": ["-pthread"], + }), + size = "small", +) + +java_import( + name = "android_test_api", + testonly = True, + jars = ["@rules_android//tools/android:android_jar"], +) +robolectric_sdk(name = "android_test_sdk", jar = "@robolectric_android_35//file", testonly = True) +kt_jvm_test( + name = "android_temporary_root_test", + srcs = ["android/src/test/java/dev/oliphaunt/reactnative/AndroidTemporaryRootTest.kt"], + test_class = "dev.oliphaunt.reactnative.AndroidTemporaryRootTest", + deps = [ + ":android_test_api", "//src/native/sdks/kotlin:android_classes", + "@rules_android_maven//:org_robolectric_robolectric", "@rules_android_maven//:org_robolectric_annotations", + "@oliphaunt_kotlin_maven//:junit_junit", "@oliphaunt_kotlin_maven//:org_json_json", + "@oliphaunt_kotlin_maven//:org_jetbrains_kotlinx_kotlinx_coroutines_core", + ], + data = [":android_test_sdk", "//src/test-fixtures:storage/database-root.json"], + jvm_flags = [ + "-Drobolectric.offline=true", + "-Drobolectric-deps.properties=$(rootpath :android_test_sdk)", + "-Doliphaunt.storage.fixture=$(rootpath //src/test-fixtures:storage/database-root.json)", + ], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + size = "medium", +) + +source_quality_files(exclude = [_LIB_OUT_DIR + "/**", _TOOLS_OUT_DIR + "/**"] + _DELIVERED_HELPERS.values()) + +exports_files(["android/build.gradle", "android/src/main/AndroidManifest.xml"]) +filegroup(name = "android_kotlin_sources", srcs = glob(["android/src/main/java/**/*.kt"]) + glob(["android/src/main/java/**/*.java"], allow_empty = True)) +filegroup(name = "android_jsi_source", srcs = ["android/src/main/cpp/OliphauntJsiBindings.cpp"]) +filegroup(name = "cpp_headers", srcs = glob(["cpp/*.h"])) + +# Original source helpers used by the E2E_ONLY installed path. No build wrappers +# execute: the actual stock application archive is the test's declared input. +exports_files(["tools/stage-ios-app.mts", "tools/native-resource-closure.mts", "tools/icu-autolinking-fixture.mts"]) +filegroup(name = "mobile_ios_e2e_sources", srcs = [ + "package.json", "tools/mobile-e2e.sh", "tools/expo-ios-runner.sh", + "tools/expo-runner-common.sh", "tools/expo-runner-common.mts", + "tools/expo-runner-metro.sh", "tools/expo-runner-workspace.sh", + "tools/expo-runner-reporting.sh", "tools/expo-runner-reporting.mts", + "tools/mobile-extension-runtime.sh", "tools/mobile-extension-runtime.mts", + "tools/expo-runner-runtime-resources.sh", "tools/expo-runner-ios-device.sh", + "tools/expo-runner-ios-device.mts", "tools/expo-runner-ios-installed-app.sh", +]) + +filegroup(name = "mobile_android_e2e_sources", srcs = [ + "package.json", "tools/mobile-e2e.sh", "tools/expo-android-runner.sh", "tools/expo-android-gradle-limits.sh", + "tools/expo-runner-common.sh", "tools/expo-runner-common.mts", "tools/expo-runner-metro.sh", "tools/expo-runner-workspace.sh", + "tools/expo-runner-reporting.sh", "tools/expo-runner-reporting.mts", "tools/mobile-extension-runtime.sh", "tools/mobile-extension-runtime.mts", + "tools/expo-runner-runtime-resources.sh", "tools/expo-runner-android-device.sh", +]) diff --git a/src/native/sdks/react-native/README.md b/src/native/sdks/react-native/README.md index de0a6f429..28366d6b8 100644 --- a/src/native/sdks/react-native/README.md +++ b/src/native/sdks/react-native/README.md @@ -10,7 +10,7 @@ npm install @oliphaunt/react-native @oliphaunt/seed-native-ios-datum64-standard For Expo, add `"@oliphaunt/react-native"` to `expo.plugins` in `app.json`, then build with `npx expo run:ios` or `npx expo run:android`. Expo Go does not include this native module. For bare projects, follow the [native integration guide](https://oliphaunt.dev/docs/sdk/react-native/architecture). -The [quickstart](https://oliphaunt.dev/docs/sdk/react-native) covers prerequisites and the versions documented by the current site. Pin dependencies in your application manifest or lockfile. +The [quickstart](https://oliphaunt.dev/docs/sdk/react-native) covers prerequisites. Pin dependencies in your application manifest or lockfile. ## First query diff --git a/src/native/sdks/react-native/android/build.gradle b/src/native/sdks/react-native/android/build.gradle index 7bb2ffc8d..3939a83eb 100644 --- a/src/native/sdks/react-native/android/build.gradle +++ b/src/native/sdks/react-native/android/build.gradle @@ -927,7 +927,7 @@ dependencies { // coordinate cannot win through another Gradle repository or cache. implementation files(kotlinSdkAar) // File dependencies have no Maven metadata; supply the Kotlin SDK's JNA runtime. - implementation "net.java.dev.jna:jna:5.14.0@aar" + implementation "net.java.dev.jna:jna:5.18.1@aar" } else { implementation kotlinSdkDependency } diff --git a/src/native/sdks/react-native/android/src/main/cpp/CMakeLists.txt b/src/native/sdks/react-native/android/src/main/cpp/CMakeLists.txt index d9cfb1bf6..c7ab0ddfa 100644 --- a/src/native/sdks/react-native/android/src/main/cpp/CMakeLists.txt +++ b/src/native/sdks/react-native/android/src/main/cpp/CMakeLists.txt @@ -128,5 +128,6 @@ if(DEFINED OLIPHAUNT_MOBILE_STATIC_MODULES AND NOT "${OLIPHAUNT_MOBILE_STATIC_MO endif() target_link_options(oliphaunt_extensions PRIVATE "-Wl,-z,max-page-size=16384" + "-Wl,-z,common-page-size=16384" ) endif() diff --git a/src/native/sdks/react-native/android/src/test/java/dev/oliphaunt/reactnative/AndroidTemporaryRootTest.kt b/src/native/sdks/react-native/android/src/test/java/dev/oliphaunt/reactnative/AndroidTemporaryRootTest.kt index 0734507de..03fb19faa 100644 --- a/src/native/sdks/react-native/android/src/test/java/dev/oliphaunt/reactnative/AndroidTemporaryRootTest.kt +++ b/src/native/sdks/react-native/android/src/test/java/dev/oliphaunt/reactnative/AndroidTemporaryRootTest.kt @@ -47,7 +47,10 @@ class AndroidTemporaryRootTest { val staging = context.cacheDir.listFiles()!!.single { it.name.startsWith(".oliphaunt-root-") } // Model the complete tree published by a concurrent initializer while // the first attempt is waiting for its seed. No native backend is mocked. - val fixture = JSONObject(File("../../../../test-fixtures/storage/database-root.json").readText()) + val fixture = JSONObject(File( + System.getProperty("oliphaunt.storage.fixture") + ?: "../../../../test-fixtures/storage/database-root.json", + ).readText()) val descriptors = fixture.getJSONArray("validDescriptors") val descriptor = (0 until descriptors.length()).map(descriptors::getJSONObject) .first { it.getString("engineFamily") == "native" } diff --git a/src/native/sdks/react-native/moon.yml b/src/native/sdks/react-native/moon.yml index 617902e7c..4ba447839 100644 --- a/src/native/sdks/react-native/moon.yml +++ b/src/native/sdks/react-native/moon.yml @@ -121,11 +121,16 @@ tasks: - /src/native/sdks/react-native/tools/check-package.mts - /src/extensions/artifacts/packages/tools/contrib-carriers.mts - /src/native/sdks/swift/tools/ios-carrier-manifest.mts + - /src/native/sdks/swift/tools/native-legal-source-basis.mts + - /src/native/sdks/swift/tools/swift-native-carrier-contract.mts - /src/native/sdks/swift/tools/pinned-native-carrier.mts - /tools/release/github-read.mts - /tools/release/github-core-request-journal.mts - /src/native/sdks/swift/tools/swift-carrier-resolver.mts - /src/native/sdks/swift/tools/render_swiftpm_release_package.mts + - /src/native/sdks/swift/tools/swift-release-manifest.mts + - /src/native/sdks/swift/tools/swift-xcframework-contract.mts + - /src/native/sdks/swift/tools/prepare-swift-release-consumer.mts - /src/native/sdks/swift/tools/swift-source-carrier-contract.mts - /tools/release/release-graph.mts - /tools/release/product-version.mts @@ -198,10 +203,14 @@ tasks: - "@group(legal-files)" - /src/extensions/tools/extension-upstream-licenses.mts - /src/native/sdks/swift/tools/ios-carrier-manifest.mts + - /src/native/sdks/swift/tools/native-legal-source-basis.mts + - /src/native/sdks/swift/tools/swift-native-carrier-contract.mts - /src/native/sdks/swift/tools/swift-source-carrier-contract.mts - /src/native/sdks/swift/tools/pinned-native-carrier.mts - /src/native/sdks/swift/tools/swift-carrier-resolver.mts - /src/native/sdks/swift/tools/render_swiftpm_release_package.mts + - /src/native/sdks/swift/tools/swift-release-manifest.mts + - /src/native/sdks/swift/tools/swift-xcframework-contract.mts - /src/native/sdks/swift/tools/prepare-swift-release-consumer.mts - /src/native/sdks/swift/tools/swift-extension-release-consumer-inputs.mts - /src/native/runtime/VERSION diff --git a/src/native/sdks/react-native/native-package.bzl b/src/native/sdks/react-native/native-package.bzl new file mode 100644 index 000000000..d5f79b108 --- /dev/null +++ b/src/native/sdks/react-native/native-package.bzl @@ -0,0 +1,213 @@ +"""Bounded React Native source-envelope actions; TypeScript owns compilation.""" + +load("@aspect_rules_js//npm:providers.bzl", "NpmPackageInfo") +load("@javascript_compiler_packages//:roots.bzl", "COMPILER_PACKAGES", "COMPILER_TOOLS") +load("@bazel_lib//lib:copy_file.bzl", "COPY_FILE_TOOLCHAINS", "copy_file_action") +load("//build_defs/extensions:final_leaf.bzl", "NativeAppleBaseInfo") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "BUN_TEST_ENTRYPOINT_ATTRS", "bun_file_action", "bun_test_entrypoint", "bun_test_entrypoint_args") + +_PACKAGE_HELPERS = [ + ":tools/native-package.mts", ":tools/native-carrier-package.mts", + "//build_defs/query:package.mts", + "//src/native/sdks/swift:tools/native-legal-source-basis.mts", + "//src/native/sdks/swift:tools/swift-native-carrier-contract.mts", + "//src/native/sdks/swift:tools/swift-xcframework-contract.mts", + "//:tools/packaging/source-only-sdk-package.mts", "//:tools/packaging/archive-directory.mts", + "//:tools/packaging/portable-archive.mts", "//:tools/packaging/release-notices.mts", + "//:tools/packaging/release-directory-safety.mts", "//:LICENSE", "//:THIRD_PARTY_NOTICES.md", +] + +_PACKAGE_ATTRS = { + "source_archive": attr.label(mandatory = True, allow_single_file = [".tgz"]), + "manifest": attr.label(mandatory = True, allow_single_file = [".json"]), + "carrier": attr.label(default = "@react_native_swift_package//:carrier", allow_single_file = True), + "carrier_source": attr.label(default = "@react_native_swift_package//:construction.json", allow_single_file = True), + "native_base": attr.label(default = "@react_native_swift_package//:native_requirement", providers = [NativeAppleBaseInfo]), + "ios_static_dependencies": attr.label(default = "//src/extensions/generated/sdk:ios-static-dependencies.json", allow_single_file = True), + "_helpers": attr.label_list(default = _PACKAGE_HELPERS, allow_files = True), +} + +def _package_spec(ctx, runfiles = False): + fields = {"sourceArchive": "source_archive", "authoredManifest": "manifest", "carrier": "carrier", "carrierSource": "carrier_source", "iosStaticDependencies": "ios_static_dependencies"} + files = [getattr(ctx.file, field) for field in fields.values()] + base = ctx.attr.native_base[NativeAppleBaseInfo] + framework = [file for file in base.archive_files if file.path == base.archives["base-xcframework"]["path"]][0] + files += [framework, base.file] + inputs = {name: _runfile(ctx, getattr(ctx.file, field)) if runfiles else getattr(ctx.file, field).path for name, field in fields.items()} + inputs["xcframework"] = _runfile(ctx, framework) if runfiles else framework.path + return inputs, files + +def _package_impl(ctx): + inputs, files = _package_spec(ctx) + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode(inputs)) + output = ctx.actions.declare_file(ctx.attr.out) + carrier = ctx.actions.declare_file(ctx.label.name + "/ios-carriers/oliphaunt-react-native-ios-carriers.json") + bun_file_action(ctx, entry_point = ctx.file._writer, arguments = [spec.path, output.path, carrier.path], inputs = files + [spec] + ctx.files._helpers, source_files = ctx.files._helpers, outputs = [output, carrier], mnemonic = "ReactNativeNpmPackage") + return [DefaultInfo(files = depset([output])), OutputGroupInfo(carrier = depset([carrier]))] + +react_native_npm = rule( + implementation = _package_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(_PACKAGE_ATTRS, **{"out": attr.string(mandatory = True), "_writer": attr.label(default = ":tools/native-package.mts", allow_single_file = True)}), +) + +def _package_test_impl(ctx): + inputs, files = _package_spec(ctx, runfiles = True) + spec = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + ctx.actions.write(spec, json.encode(inputs)) + return bun_test_entrypoint(ctx, ctx.file._runner, [spec, ctx.file.archive, ctx.file.carrier_output], files + [spec, ctx.file.archive, ctx.file.carrier_output, ctx.file._runner] + ctx.files._helpers, source_files = [ctx.file._runner] + ctx.files._helpers, runfiles_environment = ["OLIPHAUNT_BAZEL_RUNFILES"]) + +_react_native_package_test = rule( + implementation = _package_test_impl, test = True, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **dict(_PACKAGE_ATTRS, **{"archive": attr.label(mandatory = True, allow_single_file = [".tgz"]), "carrier_output": attr.label(mandatory = True, allow_single_file = [".json"]), "_runner": attr.label(default = ":tools/native-package-contract.mts", allow_single_file = True)})), +) + +def react_native_package_test(name, args = [], **kwargs): + _react_native_package_test(name = name, args = bun_test_entrypoint_args(name) + args, **kwargs) + +def _manifest_impl(ctx): + outputs = [ctx.actions.declare_file(ctx.label.name + "/" + name) for name in ["package.json", "LICENSE", "THIRD_PARTY_NOTICES.md"]] + bun_file_action( + ctx, + entry_point = ctx.file._writer, + arguments = [ctx.file.manifest.path, outputs[0].dirname], + inputs = [ctx.file._writer, ctx.file.manifest] + ctx.files._helpers, + source_files = [ctx.file._writer] + ctx.files._helpers, + outputs = outputs, + mnemonic = "ReactNativeSourceManifest", + ) + return [DefaultInfo(files = depset(outputs)), OutputGroupInfo(manifest = depset([outputs[0]]), license = depset([outputs[1]]), notices = depset([outputs[2]]))] + +react_native_manifest = rule( + implementation = _manifest_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = { + "manifest": attr.label(mandatory = True, allow_single_file = [".json"]), + "_writer": attr.label(default = ":tools/native-manifest.mts", allow_single_file = True), + "_helpers": attr.label_list(default = ["//:LICENSE", "//:THIRD_PARTY_NOTICES.md", "//:tools/packaging/source-only-sdk-package.mts", "//:tools/packaging/release-notices.mts", "//:tools/packaging/release-directory-safety.mts", "//:tools/packaging/portable-archive.mts"], allow_files = True), + }, +) + +def _templates_impl(ctx): + outputs = [] + prefix = ctx.attr.sources.label.package + "/Templates/OliphauntBroker/" + for source in ctx.files.sources: + if not source.short_path.startswith(prefix): + fail("Broker template is outside the canonical Swift source template directory: " + source.short_path) + output = ctx.actions.declare_file("ios/templates/OliphauntBroker/" + source.short_path[len(prefix):]) + copy_file_action(ctx, src = source, dst = output) + outputs.append(output) + return [DefaultInfo(files = depset(outputs))] + +react_native_templates = rule( + implementation = _templates_impl, + attrs = {"sources": attr.label(mandatory = True, allow_files = True)}, + toolchains = COPY_FILE_TOOLCHAINS, +) + +def _bundle_impl(ctx): + binary = ctx.attr.binary[NpmPackageInfo].src + sources = {} + for target, destination in ctx.attr.sources.items(): + files = target[DefaultInfo].files.to_list() + if len(files) != 1: + fail("Each helper source must declare exactly one file: " + str(target.label)) + sources[destination] = files[0].path + specification = ctx.actions.declare_file(ctx.label.name + ".sources.json") + ctx.actions.write(specification, json.encode(sources)) + output = ctx.actions.declare_file(ctx.attr.out) + bun_file_action( + ctx, + entry_point = ctx.file._writer, + arguments = [binary.path, specification.path, output.path], + inputs = depset([ctx.file._writer, ctx.file._archive, binary, specification] + [file for target in ctx.attr.sources for file in target[DefaultInfo].files.to_list()]), + source_files = [ctx.file._writer, ctx.file._archive], + outputs = [output], + mnemonic = "ReactNativeHelperBundle", + ) + return [DefaultInfo(files = depset([output]))] + +_react_native_bundle = rule( + implementation = _bundle_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = { + "binary": attr.label(mandatory = True, providers = [NpmPackageInfo], cfg = "exec"), + "sources": attr.label_keyed_string_dict(allow_files = True, mandatory = True), + "out": attr.string(mandatory = True), + "_writer": attr.label(default = ":tools/native-bundle.mts", allow_single_file = True), + "_archive": attr.label(default = "//build_defs/wasix/browser:npm-archives.mts", allow_single_file = True), + }, +) + +def react_native_bundle(name, **kwargs): + binaries = {} + tool = COMPILER_PACKAGES[COMPILER_TOOLS["esbuild"]] + for dependency in tool["dependencies"].values(): + package = COMPILER_PACKAGES[dependency] + if "os" not in package or "cpu" not in package: + fail("esbuild optional binaries require canonical platform metadata") + # Match the supported execution runtimes; source URLs/checksums/versions + # come exclusively from the conventional lock projection. + os = {"linux": "linux", "darwin": "macos", "win32": "windows"}.get(package["os"]) + cpu = {"x64": "x86_64", "arm64": "aarch64"}.get(package["cpu"]) + if not os or not cpu: + continue + setting = name + "_" + os + "_" + cpu + native.config_setting(name = setting, constraint_values = ["@platforms//os:" + os, "@platforms//cpu:" + cpu]) + binaries[":" + setting] = "@javascript_compiler_packages//:" + dependency + native.alias(name = name + "_compiler_binary", actual = select(binaries)) + _react_native_bundle(name = name, binary = ":" + name + "_compiler_binary", **kwargs) + +def _runfile(ctx, file): + return file.short_path[3:] if file.short_path.startswith("../") else ctx.workspace_name + "/" + file.short_path + +def _consumer_impl(ctx): + node = ctx.toolchains["@rules_nodejs//nodejs:toolchain_type"].nodeinfo.node + packages = dict(ctx.attr.packages) + files = [] + seen = {} + for target, key in ctx.attr.inputs.items(): + if key in seen: + fail("Installed compiler input ID was declared more than once: " + key) + seen[key] = True + source = target[NpmPackageInfo].src + files.append(source) + row = json.decode(packages[key]) + row["source"] = _runfile(ctx, source) + row["package"] = target[NpmPackageInfo].package + row["version"] = target[NpmPackageInfo].version + packages[key] = row + specification = ctx.actions.declare_file(ctx.label.name + ".inputs.json") + carrier_inputs, carrier_files = _package_spec(ctx, runfiles = True) if ctx.attr.final_package else (None, []) + ctx.actions.write(specification, json.encode({"name": ctx.attr.package_name, "version": ctx.attr.version, "packages": packages, "roots": ctx.attr.roots, "carrierInputs": carrier_inputs, "runtimeResources": _runfile(ctx, ctx.file.runtime_resources) if ctx.attr.final_package else None})) + arguments = [ctx.file.archive, ctx.file.query, ctx.file.manifest, node, ctx.file.typescript, specification] + return bun_test_entrypoint(ctx, ctx.file._runner, arguments, files + arguments + carrier_files + ([ctx.file.runtime_resources] if ctx.attr.final_package else []) + [ctx.file._runner, ctx.file._archive, ctx.file._shipping_archive] + ctx.files._helpers, source_files = [ctx.file._runner, ctx.file._archive, ctx.file._shipping_archive] + ctx.files._helpers, runfiles_environment = ["OLIPHAUNT_BAZEL_RUNFILES"]) + +_react_native_consumer_test = rule( + implementation = _consumer_impl, test = True, + toolchains = BUN_SOURCE_TOOLCHAINS + ["@rules_nodejs//nodejs:toolchain_type"], + attrs = dict(BUN_TEST_ENTRYPOINT_ATTRS, **dict(_PACKAGE_ATTRS, **{ + "archive": attr.label(mandatory = True, allow_single_file = [".tgz"]), + "query": attr.label(mandatory = True, allow_single_file = [".tgz"]), + "manifest": attr.label(mandatory = True, allow_single_file = [".json"]), + "typescript": attr.label(default = "@npm_typescript//:node_modules/typescript/dir", allow_single_file = True), + "inputs": attr.label_keyed_string_dict(providers = [NpmPackageInfo]), + "packages": attr.string_dict(mandatory = True), "roots": attr.string_dict(mandatory = True), + "package_name": attr.string(mandatory = True), "version": attr.string(mandatory = True), + "final_package": attr.bool(default = False), + "source_archive": attr.label(allow_single_file = [".tgz"]), + "native_base": attr.label(providers = [NativeAppleBaseInfo]), + "carrier": attr.label(allow_single_file = True), + "carrier_source": attr.label(allow_single_file = True), + "ios_static_dependencies": attr.label(allow_single_file = True), + "runtime_resources": attr.label(allow_single_file = True), + "_runner": attr.label(default = ":tools/native-consumer.mts", allow_single_file = True), + "_archive": attr.label(default = "//build_defs/wasix/browser:npm-archives.mts", allow_single_file = True), + "_shipping_archive": attr.label(default = "//:tools/packaging/portable-archive.mts", allow_single_file = True), + })), +) + +def react_native_consumer_test(name, args = [], **kwargs): + _react_native_consumer_test(name = name, args = bun_test_entrypoint_args(name) + args, **kwargs) diff --git a/src/native/sdks/react-native/tools/check-package.mts b/src/native/sdks/react-native/tools/check-package.mts index f68f1d745..30ba7bcd2 100644 --- a/src/native/sdks/react-native/tools/check-package.mts +++ b/src/native/sdks/react-native/tools/check-package.mts @@ -1,24 +1,24 @@ #!/usr/bin/env bun -import { IOS_CARRIER_FILENAME } from '../../swift/tools/ios-carrier-manifest.mts'; +import { readdirSync, readFileSync } from 'node:fs'; +import path from 'node:path'; import { - PREFIX, archiveTarNames, fail, inspectSdkProduct, isFile, + PREFIX, rejectSdkRuntimePayload, rel, tarReadBytes, } from '../../../../../tools/packaging/release-carrier.mts'; -import { validateSelectionNeutralSwiftCarrierIdentity } from '../../swift/tools/swift-source-carrier-contract.mts'; -import { readFileSync, readdirSync } from 'node:fs'; -import path from 'node:path'; -import { compareText } from '../../../../../tools/release/release-artifact-targets.mts'; import { - SOURCE_ONLY_NPM_PROFILES, assertSourceOnlyNpmArchive, + SOURCE_ONLY_NPM_PROFILES, } from '../../../../../tools/packaging/source-only-sdk-package.mts'; +import { compareText } from '../../../../../tools/release/release-artifact-targets.mts'; import { productDependencyCompatibilityVersion } from '../../../../../tools/release/release-graph.mts'; +import { IOS_CARRIER_FILENAME } from '../../swift/tools/ios-carrier-manifest.mts'; +import { validateSelectionNeutralSwiftCarrierIdentity } from '../../swift/tools/swift-source-carrier-contract.mts'; /** * Prove that the selection-neutral Apple carrier users receive in the React @@ -30,6 +30,7 @@ export function validateReactNativePackagedCarrier({ expectedNativeVersion, memberBytes, names, + sourceBasis = undefined, }) { const member = `package/${IOS_CARRIER_FILENAME}`; const matches = names.filter((name) => name === member); @@ -54,10 +55,11 @@ export function validateReactNativePackagedCarrier({ carrier, expectedNativeVersion, label: `${rel(artifact)} packaged React Native Apple carrier`, + sourceBasis, }); } -export async function checkReactNativePackage(root) { +export async function checkReactNativePackage(root, { nativeSourceBasis = undefined } = {}) { const product = 'oliphaunt-react-native'; let checked = false; @@ -100,6 +102,7 @@ export async function checkReactNativePackage(root) { ), memberBytes: tarReadBytes(tarball, carrierMember), names, + sourceBasis: nativeSourceBasis, }); } catch (error) { fail(error instanceof Error ? error.message : String(error)); diff --git a/src/native/sdks/react-native/tools/expo-android-runner.sh b/src/native/sdks/react-native/tools/expo-android-runner.sh index a3d4b01f8..eed90bb9d 100755 --- a/src/native/sdks/react-native/tools/expo-android-runner.sh +++ b/src/native/sdks/react-native/tools/expo-android-runner.sh @@ -44,7 +44,7 @@ example_dir="${OLIPHAUNT_EXPO_ANDROID_EXAMPLE_DIR:-$scratch_root/src/examples/na package_work="$scratch_root/src/native/sdks/react-native" crash_storage_suffix="$(printf '%s' "$(basename "$scratch_root")" | LC_ALL=C tr -c 'A-Za-z0-9_.-' '-')" [ -n "$crash_storage_suffix" ] || crash_storage_suffix="run" -pack_dir="$root/target/oliphaunt-rn-expo-pack/android" +pack_dir="${OLIPHAUNT_EXPO_ANDROID_PACK_DIR:-$root/target/oliphaunt-rn-expo-pack/android}" tarball="$pack_dir/$(react_native_package_tarball_name "$rn_dir")" local_maven_repo="$scratch_root/maven-local" build_type="${OLIPHAUNT_EXPO_ANDROID_BUILD_TYPE:-debug}" @@ -751,7 +751,6 @@ main() { ensure_android_env if is_truthy "$e2e_only"; then need_cmd node - need_cmd unzip [ -f "$apk" ] || fail "Android E2E-only mode requires an existing APK at $apk; run mobile-build:android first or set OLIPHAUNT_EXPO_ANDROID_SCRATCH to its scratch root" export_mobile_e2e_icu_expectation_from_android_apk "$apk" "Android APK" diff --git a/src/native/sdks/react-native/tools/expo-runner-android-device.sh b/src/native/sdks/react-native/tools/expo-runner-android-device.sh index 5edeebf23..8d8873ca4 100644 --- a/src/native/sdks/react-native/tools/expo-runner-android-device.sh +++ b/src/native/sdks/react-native/tools/expo-runner-android-device.sh @@ -217,6 +217,25 @@ exercise_android_crash_recovery() { write_android_process_metrics "$adb" } +wait_for_android_smoke_receipt() { + local adb="$1" android_log_file="$2" receipt_status=0 pass + mobile_app_is_alive() { "$adb" shell pidof "$app_id" >/dev/null 2>&1; } + pass="$(wait_for_mobile_receipt "$android_log_file" "$android_log_pid")" || receipt_status=$? + kill -0 "$android_log_pid" 2>/dev/null || receipt_status=3 + stop_mobile_log_capture "$android_log_pid" + android_log_pid="" + mobile_log_has_failure "$android_log_file" && receipt_status=2 + mobile_app_is_alive || receipt_status=4 + if [ "$receipt_status" != 0 ]; then + write_android_e2e_diagnostics "$adb" receipt-failure + fail "Android smoke receipt failed (status $receipt_status: timeout=1, failure=2, capture=3, app=4)" + fi + [ "$lifecycle_smoke" != 1 ] || [ "${lifecycle_exercised:-0}" = 1 ] || + fail "Android smoke PASS preceded the requested lifecycle exercise" + write_runner_report "$pass" || fail "invalid Android smoke receipt" + write_android_process_metrics "$adb" +} + install_and_launch() { local adb="$ANDROID_HOME/platform-tools/adb" "$adb" devices | grep -Eq 'device$' || fail "no Android emulator/device is connected" @@ -261,27 +280,25 @@ install_and_launch() { local logs pass if [ "$runner" = smoke ] && [ "$lifecycle_smoke" != 1 ]; then - local receipt_status=0 - mobile_app_is_alive() { "$adb" shell pidof "$app_id" >/dev/null 2>&1; } - pass="$(wait_for_mobile_receipt "$android_log_file" "$android_log_pid")" || receipt_status=$? - kill -0 "$android_log_pid" 2>/dev/null || receipt_status=3 - stop_mobile_log_capture "$android_log_pid" - android_log_pid="" - mobile_log_has_failure "$android_log_file" && receipt_status=2 - mobile_app_is_alive || receipt_status=4 - if [ "$receipt_status" != 0 ]; then - write_android_e2e_diagnostics "$adb" receipt-failure - fail "Android smoke receipt failed (status $receipt_status: timeout=1, failure=2, capture=3, app=4)" - fi - write_runner_report "$pass" || fail "invalid Android smoke receipt" - write_android_process_metrics "$adb" + wait_for_android_smoke_receipt "$adb" "$android_log_file" return fi local deadline=$((SECONDS + timeout_seconds)) local fail_line lifecycle_exercised=0 while [ "$SECONDS" -lt "$deadline" ]; do - logs="$("$adb" logcat -d)" + if [ "$runner" = smoke ]; then + logs="$(cat "$android_log_file")" + # Readiness is emitted only after native proofs; reject a failed capture/app before waiting. + if mobile_log_has_failure "$android_log_file" || + ! kill -0 "$android_log_pid" 2>/dev/null || + ! "$adb" shell pidof "$app_id" >/dev/null 2>&1; then + wait_for_android_smoke_receipt "$adb" "$android_log_file" + return + fi + else + logs="$("$adb" logcat -d)" + fi if [ "$lifecycle_smoke" = "1" ] && [ "$lifecycle_exercised" = "0" ] && logs_have_lifecycle_ready "$logs"; then @@ -295,6 +312,10 @@ install_and_launch() { pass="$(printf '%s\n' "$logs" | grep -F "$success_tag" | tail -1 || true)" fi if [ -n "$pass" ]; then + if [ "$runner" = smoke ]; then + wait_for_android_smoke_receipt "$adb" "$android_log_file" + return + fi printf '\n%s\n' "$pass" write_runner_report "$pass" write_android_process_metrics "$adb" diff --git a/src/native/sdks/react-native/tools/expo-runner-android-device.test.sh b/src/native/sdks/react-native/tools/expo-runner-android-device.test.sh index 22fa35959..3940e310c 100644 --- a/src/native/sdks/react-native/tools/expo-runner-android-device.test.sh +++ b/src/native/sdks/react-native/tools/expo-runner-android-device.test.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -root="$(git rev-parse --show-toplevel)" -source "$root/src/native/sdks/react-native/tools/expo-runner-common.sh" +tools_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$tools_dir/expo-runner-common.sh" scratch="$(mktemp -d)" capture_pid="" trap 'stop_mobile_log_capture "$capture_pid"; rm -rf "$scratch"' EXIT @@ -45,14 +45,18 @@ echo 'Mobile receipts: failure precedence, crash, missing receipt, capture/app d # Exercise the installed-app entry point: logcat clearing must discard an old # PASS, and only this app's receipt emitted after this launch can succeed. -source "$root/src/native/sdks/react-native/tools/expo-runner-android-device.sh" +source "$tools_dir/expo-runner-android-device.sh" mkdir -p "$scratch/sdk/platform-tools" "$scratch/app" cat > "$scratch/sdk/platform-tools/adb" <<'ADB' #!/usr/bin/env bash set -eu case "$*" in devices) printf 'List of devices attached\nfixture\tdevice\n' ;; - 'install -r '*|'shell am force-stop '*|'shell pm clear '*|'shell pidof '*) ;; + 'install -r '*|'shell am force-stop '*|'shell pm clear '*) ;; + 'shell pidof dev.oliphaunt.fixture') + [ "$ADB_SCENARIO" != lifecycle-dead-app ] && [ "$ADB_SCENARIO" != lifecycle-pre-ready-dead-app ] || exit 1 + cat "$ADB_CURRENT_PID" + ;; 'shell pm list packages -U --user current dev.oliphaunt.fixture') printf 'package:dev.oliphaunt.fixture.other uid:10099\r\n' case "$ADB_SCENARIO" in @@ -62,6 +66,7 @@ case "$*" in esac ;; 'logcat -c') : > "$ADB_RECEIPT" ;; + 'logcat -d') sed 's/^[0-9]* //' "$ADB_RECEIPT" ;; 'logcat -v '*) trap 'exit 0' TERM uid_filter="" @@ -70,6 +75,7 @@ case "$*" in done while [ ! -s "$ADB_RECEIPT" ]; do sleep 0.05; done awk -v uid="$uid_filter" 'uid == "" || $1 == uid {sub(/^[0-9]+ /, ""); print}' "$ADB_RECEIPT" + [ "$ADB_SCENARIO" != lifecycle-dead-capture ] && [ "$ADB_SCENARIO" != lifecycle-pre-ready-dead-capture ] || exit 7 while :; do sleep 0.05; done ;; 'shell am start -W '*) @@ -77,13 +83,38 @@ case "$*" in stale) ;; unrelated-pass) printf '10099 %s\n' "$ADB_CURRENT_RECEIPT" > "$ADB_RECEIPT" ;; *) + packet="$(mktemp "${ADB_RECEIPT}.XXXXXX")" { case "$ADB_SCENARIO" in - unrelated-crash) printf '10099 FATAL EXCEPTION: main\n' ;; + lifecycle-pre-ready-*|lifecycle-unrequested) + printf '10042 OLIPHAUNT_EXPO_SMOKE_STAGE {"stage":"open:start"}\n' + [ "$ADB_SCENARIO" != lifecycle-pre-ready-fatal ] || printf '10042 FATAL EXCEPTION: main\n' + ;; + lifecycle-*) + printf '10042 OLIPHAUNT_EXPO_SMOKE_STAGE {"stage":"lifecycle:ready","state":"active"}\n' + printf '10042 OLIPHAUNT_EXPO_SMOKE_STAGE {"stage":"lifecycle:state","state":"background"}\n' + printf '10042 OLIPHAUNT_EXPO_SMOKE_STAGE {"stage":"lifecycle:state","state":"active"}\n' + printf '10042 OLIPHAUNT_EXPO_SMOKE_STAGE {"stage":"lifecycle:sql:done"}\n' + ;; + esac + case "$ADB_SCENARIO" in + unrelated-crash|lifecycle-unrelated-crash|benchmark-unrelated-crash) + printf '10099 FATAL EXCEPTION: main\n' + printf '10099 Process: dev.oliphaunt.fixture.other\n' + ;; app-crash) printf '10042 FATAL EXCEPTION: main\n' ;; + benchmark-own-fatal) + printf '10042 FATAL EXCEPTION: main\n' + printf '10042 Process: dev.oliphaunt.fixture\n' + ;; esac - printf '10042 %s\n' "$ADB_CURRENT_RECEIPT" - } > "$ADB_RECEIPT" + case "$ADB_SCENARIO" in + benchmark-own-fatal|lifecycle-pre-ready-*) ;; + *) printf '10042 %s\n' "$ADB_CURRENT_RECEIPT" ;; + esac + [ "$ADB_SCENARIO" != lifecycle-fatal ] || printf '10042 FATAL EXCEPTION: main\n' + } > "$packet" + mv "$packet" "$ADB_RECEIPT" ;; esac ;; @@ -93,8 +124,10 @@ ADB chmod +x "$scratch/sdk/platform-tools/adb" export ADB_RECEIPT="$scratch/adb-receipt" export ADB_CURRENT_RECEIPT="$success_tag current-launch" +export ADB_CURRENT_PID="$scratch/current-app-pid" ANDROID_HOME="$scratch/sdk" app_id=dev.oliphaunt.fixture +metro_port=8081 apk="$scratch/app.apk" build_type=release runner=smoke @@ -106,8 +139,17 @@ android_runner_url() { printf 'fixture://smoke'; } write_android_process_metrics() { :; } write_android_e2e_diagnostics() { :; } write_runner_report() { [ "$1" = "$ADB_CURRENT_RECEIPT" ]; } -for scenario in pass unrelated-crash app-crash stale unrelated-pass missing-uid invalid-uid; do +exercise_android_lifecycle() { printf '67890\n' > "$ADB_CURRENT_PID"; } +for scenario in pass unrelated-crash app-crash stale unrelated-pass missing-uid invalid-uid benchmark-pass benchmark-unrelated-crash benchmark-own-fatal lifecycle-pass lifecycle-unrelated-crash lifecycle-fatal lifecycle-dead-capture lifecycle-dead-app lifecycle-pre-ready-fatal lifecycle-pre-ready-dead-capture lifecycle-pre-ready-dead-app lifecycle-unrequested; do + runner=smoke + success_tag=OLIPHAUNT_EXPO_SMOKE_PASS + failure_tag=OLIPHAUNT_EXPO_SMOKE_FAIL + case "$scenario" in benchmark-*) runner=benchmark; success_tag=OLIPHAUNT_EXPO_BENCH_PASS; failure_tag=OLIPHAUNT_EXPO_BENCH_FAIL ;; esac + export ADB_CURRENT_RECEIPT="$success_tag current-launch" printf '10042 %s stale-launch\n' "$success_tag" > "$ADB_RECEIPT" + printf '12345\n' > "$ADB_CURRENT_PID" + case "$scenario" in lifecycle-*) lifecycle_smoke=1; timeout_seconds=10 ;; *) lifecycle_smoke=0; timeout_seconds=3 ;; esac + case "$scenario" in lifecycle-pre-ready-*) timeout_seconds=5 ;; esac export ADB_SCENARIO="$scenario" status=0 ( @@ -116,8 +158,19 @@ for scenario in pass unrelated-crash app-crash stale unrelated-pass missing-uid install_and_launch ) > "$scratch/$scenario-launch.log" 2>&1 || status=$? case "$scenario" in - pass|unrelated-crash) [ "$status" = 0 ] ;; + pass|unrelated-crash|benchmark-pass|benchmark-unrelated-crash|lifecycle-pass|lifecycle-unrelated-crash) [ "$status" = 0 ] ;; *) [ "$status" != 0 ] ;; esac || { cat "$scratch/$scenario-launch.log" >&2; echo "unexpected $scenario status: $status" >&2; exit 1; } + case "$scenario" in + lifecycle-fatal|lifecycle-pre-ready-fatal) grep -Fq 'receipt failed (status 2:' "$scratch/$scenario-launch.log" ;; + lifecycle-dead-capture|lifecycle-pre-ready-dead-capture) grep -Fq 'receipt failed (status 3:' "$scratch/$scenario-launch.log" ;; + lifecycle-dead-app|lifecycle-pre-ready-dead-app) grep -Fq 'receipt failed (status 4:' "$scratch/$scenario-launch.log" ;; + lifecycle-pass|lifecycle-unrelated-crash) [ "$(cat "$ADB_CURRENT_PID")" = 67890 ] ;; + lifecycle-unrequested) grep -Fq 'PASS preceded the requested lifecycle exercise' "$scratch/$scenario-launch.log" ;; + benchmark-own-fatal) grep -Fq 'Expo Android benchmark failed' "$scratch/$scenario-launch.log" ;; + esac || { cat "$scratch/$scenario-launch.log" >&2; echo "$scenario: terminal guard assertion failed" >&2; exit 1; } done echo 'Android installed-app capture scopes receipts and crashes to the current app and launch' +echo 'Android lifecycle PASS rejects fatal logs, failed capture and dead current app; current app PID may change' +echo 'Android benchmark retains PASS ordering for unrelated prefix fatal and rejects its own fatal without PASS' +echo 'Android pre-readiness guards reject current-app fatal, capture death and app death without requiring a PASS' diff --git a/src/native/sdks/react-native/tools/expo-runner-common.sh b/src/native/sdks/react-native/tools/expo-runner-common.sh index a92faadf5..e68a82ee6 100644 --- a/src/native/sdks/react-native/tools/expo-runner-common.sh +++ b/src/native/sdks/react-native/tools/expo-runner-common.sh @@ -74,7 +74,7 @@ need_cmd() { # The app owns SDK assertions. Read only the continuous capture started for this # launch, and reject failures/dead processes before accepting its receipt. mobile_log_has_failure() { - grep -Eq "$failure_tag|Fatal error|FATAL EXCEPTION|terminating with uncaught exception" "$1" + grep -Eq "$failure_tag|Fatal error|FATAL EXCEPTION|Unhandled JS Exception:|terminating with uncaught exception" "$1" } wait_for_mobile_receipt() { diff --git a/src/native/sdks/react-native/tools/expo-runner-ios-installed-app.fixture.mts b/src/native/sdks/react-native/tools/expo-runner-ios-installed-app.fixture.mts index 1537f4546..531fcb7d0 100644 --- a/src/native/sdks/react-native/tools/expo-runner-ios-installed-app.fixture.mts +++ b/src/native/sdks/react-native/tools/expo-runner-ios-installed-app.fixture.mts @@ -1,4 +1,5 @@ import * as fs from 'node:fs'; + const [command, ...args] = process.argv.slice(2); switch (command) { case 'receipt': { @@ -6,7 +7,7 @@ switch (command) { const extensions = (metadata.extensions ?? []).map((row) => row['sql-name']).sort(); process.stdout.write( JSON.stringify({ - schema: 'oliphaunt-expo-smoke-pass-v4', + schema: 'oliphaunt-expo-smoke-pass-v5', runner: 'smoke', platform: 'ios', extensionCount: extensions.length, @@ -16,6 +17,7 @@ switch (command) { extensionCatalogSha256: metadata['extension-catalog-sha256'], catalogProfile: 'standard', icuRuntimeProof: false, + lifecycleResume: args[1] === 'lifecycle', }), ); break; diff --git a/src/native/sdks/react-native/tools/expo-runner-ios-installed-app.sh b/src/native/sdks/react-native/tools/expo-runner-ios-installed-app.sh index 9b46344e5..e02bbaa1a 100644 --- a/src/native/sdks/react-native/tools/expo-runner-ios-installed-app.sh +++ b/src/native/sdks/react-native/tools/expo-runner-ios-installed-app.sh @@ -320,7 +320,7 @@ exercise_ios_crash_recovery() { echo echo "==> iOS crash recovery: write phase" run xcrun simctl terminate "$device_udid" "$app_id" || true - launch_output="$(xcrun simctl launch "$device_udid" "$app_id" --initialUrl "$write_url")" + launch_output="$(launch_ios_simulator_runner "$device_udid" "$write_url")" printf '%s\n' "$launch_output" launch_pid="$(printf '%s\n' "$launch_output" | awk -F': ' -v app_id="$app_id" '$1 == app_id {print $2; exit}')" write_line="$(wait_for_ios_tag "$device_udid" OLIPHAUNT_EXPO_CRASH_WRITE_READY "$failure_tag" "$scratch_offset" "$dev_offset")" || @@ -336,7 +336,7 @@ exercise_ios_crash_recovery() { scratch_offset="$(file_bytes "$scratch_root/metro.log")" dev_offset="$(file_bytes "$metro_dev_log")" verify_url="$(ios_runner_url crash-verify "$crash_storage")" - launch_output="$(xcrun simctl launch "$device_udid" "$app_id" --initialUrl "$verify_url")" + launch_output="$(launch_ios_simulator_runner "$device_udid" "$verify_url")" printf '%s\n' "$launch_output" launch_pid="$(printf '%s\n' "$launch_output" | awk -F': ' -v app_id="$app_id" '$1 == app_id {print $2; exit}')" pass="$(wait_for_ios_tag "$device_udid" "$success_tag" "$failure_tag" "$scratch_offset" "$dev_offset")" || @@ -410,6 +410,8 @@ wait_for_ios_device_runner() { fi pass="$(latest_metro_runner_pass "$scratch_offset" "$dev_offset")" if [ -n "$pass" ]; then + [ "$lifecycle_smoke" != 1 ] || [ "$lifecycle_exercised" = 1 ] || + fail "iOS smoke PASS preceded the requested lifecycle exercise" printf '\n%s\n' "$pass" write_runner_report "$pass" write_ios_device_process_metrics "$device_id" @@ -492,6 +494,15 @@ wait_for_ios_tag_from_metro() { return 1 } +launch_ios_simulator_runner() { + local device_udid="$1" url="$2" + if uses_ios_metro; then + xcrun simctl launch "$device_udid" "$app_id" --initialUrl "$url" + else + xcrun simctl launch "$device_udid" "$app_id" -liboliphauntLaunchURL "$url" + fi +} + install_and_launch() { local app="$1" if [ "${OLIPHAUNT_EXPO_IOS_BUILD_ONLY:-0}" = "1" ]; then @@ -566,8 +577,7 @@ install_and_launch() { url="$(ios_runner_url "$runner")" local launch_output launch_pid echo - echo "==> xcrun simctl launch $device_udid $app_id --initialUrl $url" - launch_output="$(xcrun simctl launch "$device_udid" "$app_id" --initialUrl "$url")" + launch_output="$(launch_ios_simulator_runner "$device_udid" "$url")" printf '%s\n' "$launch_output" launch_pid="$(printf '%s\n' "$launch_output" | awk -F': ' -v app_id="$app_id" '$1 == app_id {print $2; exit}')" if [ "${OLIPHAUNT_EXPO_IOS_OPENURL_FALLBACK:-0}" = "1" ]; then @@ -576,9 +586,9 @@ install_and_launch() { fi local logs pass + mobile_app_is_alive() { [ -n "$launch_pid" ] && kill -0 "$launch_pid" 2>/dev/null; } if [ "$runner" = smoke ] && [ "$lifecycle_smoke" != 1 ]; then local receipt_status=0 - mobile_app_is_alive() { [ -n "$launch_pid" ] && kill -0 "$launch_pid" 2>/dev/null; } pass="$(wait_for_mobile_receipt "$ios_simulator_log_file" "$ios_simulator_log_pid")" || receipt_status=$? stop_ios_simulator_log_capture || receipt_status=3 mobile_log_has_failure "$ios_simulator_log_file" && receipt_status=2 @@ -593,9 +603,20 @@ install_and_launch() { fi local deadline=$((SECONDS + timeout_seconds)) - local fail_line lifecycle_exercised=0 + local fail_line lifecycle_exercised=0 receipt_status while [ "$SECONDS" -lt "$deadline" ]; do + receipt_status=0 logs="$(cat "$ios_simulator_log_file")" + mobile_log_has_failure "$ios_simulator_log_file" && receipt_status=2 + ios_simulator_log_capture_is_alive || receipt_status=3 + mobile_app_is_alive || receipt_status=4 + if [ "$receipt_status" != 0 ]; then + if [ "$lifecycle_smoke" = 1 ]; then + xcrun simctl io "$device_udid" screenshot "$scratch_root/logs/$runner-lifecycle-failure.png" >&2 || true + fi + tail -200 "$ios_simulator_log_file" >&2 || true + fail "iOS smoke receipt failed (status $receipt_status: timeout=1, failure=2, capture=3, app=4)" + fi if [ "$lifecycle_smoke" = "1" ] && [ "$lifecycle_exercised" = "0" ]; then if { printf '%s\n' "$logs" @@ -610,6 +631,8 @@ install_and_launch() { fi pass="$(printf '%s\n' "$logs" | grep -F "$success_tag" | tail -1 || true)" if [ -n "$pass" ]; then + [ "$lifecycle_smoke" != 1 ] || [ "$lifecycle_exercised" = 1 ] || + fail "iOS smoke PASS preceded the requested lifecycle exercise" printf '\n%s\n' "$pass" write_runner_report "$pass" write_ios_process_metrics "$launch_pid" @@ -618,17 +641,14 @@ install_and_launch() { if uses_ios_metro; then pass="$(latest_metro_runner_pass "$scratch_metro_offset" "$dev_metro_offset")" if [ -n "$pass" ]; then + [ "$lifecycle_smoke" != 1 ] || [ "$lifecycle_exercised" = 1 ] || + fail "iOS smoke PASS preceded the requested lifecycle exercise" printf '\n%s\n' "$pass" write_runner_report "$pass" write_ios_process_metrics "$launch_pid" return fi fi - fail_line="$(printf '%s\n' "$logs" | grep -E "$failure_tag|Fatal error|terminating" | tail -20 || true)" - if [ -n "$fail_line" ]; then - printf '%s\n' "$fail_line" >&2 - fail "Expo iOS $runner failed" - fi if uses_ios_metro; then fail_line="$(latest_metro_runner_failure "$scratch_metro_offset" "$dev_metro_offset")" if [ -n "$fail_line" ]; then @@ -639,7 +659,7 @@ install_and_launch() { sleep 2 done - xcrun simctl spawn "$device_udid" log show --style compact --last 2m 2>/dev/null | tail -200 >&2 || true + tail -200 "$ios_simulator_log_file" >&2 || true file_from_offset "$scratch_root/metro.log" "$scratch_metro_offset" | tail -120 >&2 || true file_from_offset "$metro_dev_log" "$dev_metro_offset" | tail -120 >&2 || true fail "timed out waiting for $success_tag" diff --git a/src/native/sdks/react-native/tools/expo-runner-ios-installed-app.test.sh b/src/native/sdks/react-native/tools/expo-runner-ios-installed-app.test.sh index 935719c0d..e3d10db25 100644 --- a/src/native/sdks/react-native/tools/expo-runner-ios-installed-app.test.sh +++ b/src/native/sdks/react-native/tools/expo-runner-ios-installed-app.test.sh @@ -7,6 +7,7 @@ root="$(git rev-parse --show-toplevel 2>/dev/null)" || { } . "$root/src/native/sdks/react-native/tools/expo-runner-ios-installed-app.sh" . "$root/src/native/sdks/react-native/tools/expo-runner-reporting.sh" +. "$root/src/native/sdks/react-native/tools/expo-runner-common.sh" test_root="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-ios-runner-test.XXXXXX")" trap 'rm -rf "$test_root"' EXIT @@ -70,6 +71,7 @@ success_tag=OLIPHAUNT_EXPO_SMOKE_PASS export CI_HEAD_SHA="$(git rev-parse HEAD)" export OLIPHAUNT_MOBILE_E2E_EXPECT_ICU=0 export OLIPHAUNT_MOBILE_E2E_EXPECT_CATALOG_PROFILE=standard +export OLIPHAUNT_MOBILE_E2E_EXPECT_LIFECYCLE=0 export OLIPHAUNT_MOBILE_E2E_EXPECT_EXTENSIONS="$( bun -e 'const metadata = await Bun.file(process.argv[1]).json(); console.log(metadata.extensions.map((row) => row["sql-name"]).join(","));' \ "$root/src/extensions/generated/sdk/extensions.json" @@ -87,3 +89,195 @@ if verify_mobile_e2e_smoke_receipt ios "$scratch_root" >/dev/null 2>&1; then fi echo "iOS runner failure and receipt checks passed" + +# Release passes its URL through NSArgumentDomain without a scheme confirmation. +# Debug retains the development launcher's supported argument. +calls="$test_root/launch-calls" +app_id=dev.oliphaunt.fixture +launch_failure=0 +xcrun() { + printf '%s\n' "$*" >>"$calls" + printf '%s\n' "$@" >"$test_root/launch-argv" + if [ "$2" = launch ] && [ "$launch_failure" = 1 ]; then return 7; fi + if [ "$2" = launch ]; then printf '%s: %s\n' "$app_id" "$$"; fi +} +uses_ios_metro() { [ "$configuration" = Debug ]; } +configuration=Release +for launch_url in \ + 'fixture://oliphaunt-smoke?liboliphauntRunner=smoke&liboliphauntLifecycle=1' \ + 'fixture://oliphaunt-smoke?liboliphauntRunner=benchmark&liboliphauntBenchmarkPreset=short%20read&liboliphauntStartupGUCs=work_mem%3D4MB%26search_path%3Dpublic' \ + 'fixture://oliphaunt-smoke?liboliphauntRunner=crash-verify&liboliphauntStorageDirectory=%2Ftmp%2Fcrash%20data&label=two words'; do + : >"$calls" + launch_ios_simulator_runner owned-simulator "$launch_url" >"$test_root/launch-output" + [ "$(cat "$test_root/launch-argv")" = "$(printf '%s\n' simctl launch owned-simulator "$app_id" -liboliphauntLaunchURL "$launch_url")" ] + [ "$(wc -l <"$calls" | tr -d '[:space:]')" = 1 ] + if grep -Fq 'simctl openurl ' "$calls"; then + echo 'Release initial launch requested a custom-scheme confirmation' >&2 + exit 1 + fi +done +: >"$calls" +launch_failure=1 +status=0 +launch_output="$(launch_ios_simulator_runner owned-simulator 'fixture://smoke')" || status=$? +[ "$status" = 7 ] +[ -z "$launch_output" ] +[ "$(wc -l <"$calls" | tr -d '[:space:]')" = 1 ] +grep -Fxq 'simctl launch owned-simulator dev.oliphaunt.fixture -liboliphauntLaunchURL fixture://smoke' "$calls" +launch_failure=0 +: >"$calls" +configuration=Debug +launch_ios_simulator_runner owned-simulator 'fixture://development' >"$test_root/launch-output" +grep -Fxq 'simctl launch owned-simulator dev.oliphaunt.fixture --initialUrl fixture://development' "$calls" +[ "$(wc -l <"$calls" | tr -d '[:space:]')" = 1 ] +: >"$calls" +background_seconds=0 +scheme=fixture +exercise_ios_lifecycle owned-simulator >"$test_root/lifecycle-output" +grep -Fxq 'simctl openurl owned-simulator https://example.com/liboliphaunt-lifecycle-background' "$calls" +grep -Fxq 'simctl launch owned-simulator dev.oliphaunt.fixture' "$calls" +[ "$(wc -l <"$calls" | tr -d '[:space:]')" = 2 ] + +# Exercise the actual simulator runner loop: an ordinary PASS before readiness +# cannot stand in for lifecycle, while a completed requested exercise succeeds. +configuration=Release +sdk=iphonesimulator +runner=smoke +lifecycle_smoke=1 +background_seconds=0 +clean_simulator_install=0 +scheme=fixture +startup_gucs="" +failure_tag=OLIPHAUNT_EXPO_SMOKE_FAIL +timeout_seconds=5 +metro_dev_log="$test_root/no-metro.log" +select_ios_simulator_udid() { printf 'owned-simulator'; } +boot_ios_simulator() { :; } +resolve_ios_app_process_name() { printf 'fixture'; } +write_ios_process_metrics() { :; } +start_ios_simulator_log_capture() { + mkdir -p "$scratch_root/logs" + ios_simulator_log_file="$scratch_root/logs/smoke-simulator-unified.log" + : >"$ios_simulator_log_file" + if [ "$scenario" = dead-capture ]; then + ( : ) & + else + sleep 60 & + fi + ios_simulator_log_pid=$! + if [ "$scenario" = dead-capture ]; then wait "$ios_simulator_log_pid"; fi +} +completed_receipt="$(bun "$root/src/native/sdks/react-native/tools/expo-runner-ios-installed-app.fixture.mts" receipt "$root/src/extensions/generated/sdk/extensions.json" lifecycle)" +xcrun() { + printf '%s\n' "$*" >>"$calls" + if [ "$2" = openurl ]; then + [ "$4" = https://example.com/liboliphaunt-lifecycle-background ] || return 9 + printf 'exercised\n' >"$test_root/lifecycle-exercised" + printf 'OLIPHAUNT_EXPO_SMOKE_STAGE {"stage":"lifecycle:state","state":"background"}\n' >>"$ios_simulator_log_file" + elif [ "$2" = io ] && [ "$4" = screenshot ]; then + [ "$scenario" != dead-capture ] || return 7 + printf 'fixture PNG\n' >"$5" + elif [ "$2" = launch ]; then + if [ "${5:-}" = -liboliphauntLaunchURL ]; then + [ "$#" = 6 ] && [ "$6" = "$(ios_runner_url "$runner")" ] || return 9 + if [ "$scenario" = complete ] || [ "$scenario" = lifecycle-js-fatal-pass ] || [ "$scenario" = lifecycle-timeout ]; then + if [ "$scenario" = complete ]; then + printf 'Warning: Cannot find native module ExpoAsset\n' >>"$ios_simulator_log_file" + fi + if [ "$scenario" = lifecycle-timeout ]; then + printf 'OLIPHAUNT_EXPO_SMOKE_STAGE {"stage":"open:start","fixture":"scoped-diagnostic"}\n' >>"$ios_simulator_log_file" + fi + printf 'OLIPHAUNT_EXPO_SMOKE_STAGE {"stage":"lifecycle:ready","state":"inactive"}\n' >>"$ios_simulator_log_file" + elif [ "$scenario" = js-fatal ] || [ "$scenario" = lifecycle-js-fatal ]; then + printf 'Unhandled JS Exception: [runtime not ready]: Error: Cannot find native module ExpoAsset\n' >>"$ios_simulator_log_file" + printf 'OLIPHAUNT_EXPO_SMOKE_STAGE {"stage":"lifecycle:ready","state":"active"}\n' >>"$ios_simulator_log_file" + elif [ "$scenario" = ordinary ]; then + printf '%s %s\n' "$success_tag" "$receipt_json" >>"$ios_simulator_log_file" + else + printf 'OLIPHAUNT_EXPO_SMOKE_STAGE {"stage":"open:start","fixture":"scoped-diagnostic"}\n' >>"$ios_simulator_log_file" + fi + elif [ -s "$test_root/lifecycle-exercised" ]; then + [ "$#" = 4 ] || return 9 + if [ "$scenario" = lifecycle-timeout ]; then + printf '%s lifecycle timeout states=inactive>background\n' "$failure_tag" >>"$ios_simulator_log_file" + else + if [ "$scenario" = lifecycle-js-fatal-pass ]; then + printf 'Unhandled JS Exception: [runtime not ready]: Error: Cannot find native module ExpoAsset\n' >>"$ios_simulator_log_file" + fi + printf '%s\n' \ + 'OLIPHAUNT_EXPO_SMOKE_STAGE {"stage":"lifecycle:state","state":"active"}' \ + 'OLIPHAUNT_EXPO_SMOKE_STAGE {"stage":"lifecycle:sql:done"}' \ + "$success_tag $completed_receipt" >>"$ios_simulator_log_file" + fi + fi + if [ "$scenario" = dead-app ]; then + ( : ) & + local dead_pid=$! + wait "$dead_pid" + printf '%s: %s\n' "$app_id" "$dead_pid" + else + printf '%s: %s\n' "$app_id" "$$" + fi + fi +} +export OLIPHAUNT_MOBILE_E2E_EXPECT_LIFECYCLE=1 +for scenario in ordinary complete js-fatal lifecycle-js-fatal lifecycle-js-fatal-pass dead-capture dead-app timeout lifecycle-timeout; do + scratch_root="$test_root/$scenario" + rm -f "$test_root/lifecycle-exercised" + : >"$calls" + lifecycle_smoke=1 + [ "$scenario" != js-fatal ] || lifecycle_smoke=0 + timeout_seconds=5 + [ "$scenario" != timeout ] || timeout_seconds=1 + status=0 + ( + ios_simulator_log_pid="" + trap 'stop_mobile_log_capture "$ios_simulator_log_pid"' EXIT + install_and_launch "$app" + ) >"$test_root/$scenario.log" 2>&1 || status=$? + if [ "$scenario" = ordinary ]; then + [ "$status" != 0 ] + grep -Fq 'PASS preceded the requested lifecycle exercise' "$test_root/$scenario.log" + [ ! -e "$test_root/lifecycle-exercised" ] + elif [ "$scenario" = complete ]; then + [ "$status" = 0 ] || { cat "$test_root/$scenario.log" >&2; exit 1; } + [ -s "$test_root/lifecycle-exercised" ] + [ ! -e "$scratch_root/logs/smoke-lifecycle-failure.png" ] + verify_mobile_e2e_smoke_receipt ios "$scratch_root" + elif [ "$scenario" = js-fatal ] || [ "$scenario" = lifecycle-js-fatal ] || [ "$scenario" = lifecycle-js-fatal-pass ]; then + [ "$status" != 0 ] + grep -Fq 'iOS smoke receipt failed (status 2:' "$test_root/$scenario.log" + grep -Fq 'Unhandled JS Exception: [runtime not ready]: Error: Cannot find native module ExpoAsset' "$test_root/$scenario.log" + [ ! -e "$scratch_root/reports/smoke-extension-receipt.json" ] + if [ "$scenario" = lifecycle-js-fatal-pass ]; then + [ -s "$test_root/lifecycle-exercised" ] + grep -Fq "$success_tag $completed_receipt" "$test_root/$scenario.log" + else + [ ! -e "$test_root/lifecycle-exercised" ] + fi + if [ "$scenario" = js-fatal ]; then + [ ! -e "$scratch_root/logs/smoke-lifecycle-failure.png" ] + fi + else + [ "$status" != 0 ] + grep -Fq '"fixture":"scoped-diagnostic"' "$test_root/$scenario.log" + case "$scenario" in + dead-capture) grep -Fq 'iOS smoke receipt failed (status 3:' "$test_root/$scenario.log" ;; + dead-app) grep -Fq 'iOS smoke receipt failed (status 4:' "$test_root/$scenario.log" ;; + timeout) grep -Fq "timed out waiting for $success_tag" "$test_root/$scenario.log" ;; + lifecycle-timeout) + grep -Fq 'iOS smoke receipt failed (status 2:' "$test_root/$scenario.log" + grep -Fq 'lifecycle timeout states=inactive>background' "$test_root/$scenario.log" + [ -s "$scratch_root/logs/smoke-lifecycle-failure.png" ] + if grep -Fq '"stage":"lifecycle:state","state":"active"' "$test_root/$scenario.log"; then exit 1; fi + [ ! -e "$scratch_root/reports/smoke-extension-receipt.json" ] + ;; + esac + fi + if [ "$scenario" = complete ] || [ "$scenario" = lifecycle-timeout ]; then + grep -Fxq 'simctl openurl owned-simulator https://example.com/liboliphaunt-lifecycle-background' "$calls" + grep -Fxq "simctl launch owned-simulator dev.oliphaunt.fixture -liboliphauntLaunchURL $(ios_runner_url "$runner")" "$calls" + [ "$(grep -Fxc 'simctl launch owned-simulator dev.oliphaunt.fixture' "$calls")" = 1 ] + fi +done +echo 'iOS direct launch, lifecycle receipt, liveness, and scoped diagnostics passed' diff --git a/src/native/sdks/react-native/tools/expo-runner-reporting.mts b/src/native/sdks/react-native/tools/expo-runner-reporting.mts index 8d3880783..7b70d8e53 100644 --- a/src/native/sdks/react-native/tools/expo-runner-reporting.mts +++ b/src/native/sdks/react-native/tools/expo-runner-reporting.mts @@ -1,6 +1,7 @@ -import * as fs from 'node:fs'; -import * as crypto from 'node:crypto'; import assert from 'node:assert/strict'; +import * as crypto from 'node:crypto'; +import * as fs from 'node:fs'; + function extensionReceipt( reportFile, metadataFile, @@ -26,6 +27,7 @@ function extensionReceipt( 'extensionCatalogComplete', 'extensionCount', 'icuRuntimeProof', + 'lifecycleResume', 'pgTextsearchEnglishBm25', 'platform', 'runner', @@ -38,13 +40,23 @@ function extensionReceipt( ); } if ( - payload.schema !== 'oliphaunt-expo-smoke-pass-v4' || + payload.schema !== 'oliphaunt-expo-smoke-pass-v5' || payload.runner !== 'smoke' || payload.platform !== platform ) { throw new Error(`${platform} app PASS receipt schema, runner, or platform identity mismatch`); } const expectedIcu = process.env.OLIPHAUNT_MOBILE_E2E_EXPECT_ICU; + const expectedLifecycle = process.env.OLIPHAUNT_MOBILE_E2E_EXPECT_LIFECYCLE; + if (expectedLifecycle !== '0' && expectedLifecycle !== '1') { + throw new Error(`${platform} app PASS receipt requires an explicit lifecycle expectation`); + } + if ( + typeof payload.lifecycleResume !== 'boolean' || + (expectedLifecycle === '1' && payload.lifecycleResume !== true) + ) { + throw new Error(`${platform} app PASS receipt omitted the required lifecycle resume proof`); + } const expectedCatalogProfile = process.env.OLIPHAUNT_MOBILE_E2E_EXPECT_CATALOG_PROFILE; if (expectedIcu !== '0' && expectedIcu !== '1') { throw new Error(`${platform} app PASS receipt requires an exact artifact ICU expectation`); @@ -111,12 +123,42 @@ function extensionReceipt( extensions: expected, extensionCatalogSha256: catalogSha256, appPassPayloadSha256: crypto.createHash('sha256').update(JSON.stringify(payload)).digest('hex'), + lifecycleResume: payload.lifecycleResume, }; return receipt; } const [command, ...args] = process.argv.slice(2); switch (command) { + case 'android-apk-manifests': { + const [file, destination] = args; + const { readAndroidApkEntries } = await import( + '../../../../../tools/packaging/portable-archive.mts' + ); + const entries = readAndroidApkEntries(fs.realpathSync(file)); + for (const relative of [ + 'runtime/manifest.properties', + 'cluster-seed/manifest.properties', + 'cluster-seed-icu/manifest.properties', + ]) { + const entry = entries.get('assets/oliphaunt/' + relative); + if (!entry) { + assert( + relative !== 'runtime/manifest.properties', + 'Android APK must carry its exact runtime manifest', + ); + continue; + } + assert( + entry.isFile && !entry.isSymbolicLink, + 'Android APK manifest must be a regular member', + ); + const output = destination + '/' + relative; + fs.mkdirSync(output.slice(0, output.lastIndexOf('/')), { recursive: true }); + fs.writeFileSync(output, entry.data()); + } + break; + } case 'json-object': { const file = args[0]; const value = JSON.parse(fs.readFileSync(file, 'utf8')); diff --git a/src/native/sdks/react-native/tools/expo-runner-reporting.sh b/src/native/sdks/react-native/tools/expo-runner-reporting.sh index 01637c0f1..a44b6e1e2 100644 --- a/src/native/sdks/react-native/tools/expo-runner-reporting.sh +++ b/src/native/sdks/react-native/tools/expo-runner-reporting.sh @@ -144,7 +144,7 @@ export_mobile_e2e_icu_expectation_from_manifest() { export_mobile_e2e_icu_expectation_from_android_apk() { local apk="$1" local label="$2" - local extracted manifest member + local extracted manifest [ -f "$apk" ] || { echo "$label is missing: $apk" >&2 return 1 @@ -154,18 +154,7 @@ export_mobile_e2e_icu_expectation_from_android_apk() { return 1 } manifest="$extracted/runtime/manifest.properties" - mkdir -p "$extracted/runtime" - local extract_status=0 - unzip -p "$apk" "assets/oliphaunt/runtime/manifest.properties" >"$manifest" || - extract_status=$? - zipinfo -1 "$apk" >"$extracted/members" || extract_status=$? - for member in cluster-seed cluster-seed-icu; do - if grep -Fxq "assets/oliphaunt/$member/manifest.properties" "$extracted/members"; then - mkdir -p "$extracted/$member" - unzip -p "$apk" "assets/oliphaunt/$member/manifest.properties" >"$extracted/$member/manifest.properties" || extract_status=$? - fi - done - if [ "$extract_status" -ne 0 ]; then + if ! bun "$root/src/native/sdks/react-native/tools/expo-runner-reporting.mts" android-apk-manifests "$apk" "$extracted"; then rm -rf "$extracted" echo "$label resource manifests could not be read: $apk" >&2 return 1 @@ -284,7 +273,8 @@ verify_mobile_extension_smoke_receipt() { return 1 fi local receipt_status=0 - bun "$root/src/native/sdks/react-native/tools/expo-runner-reporting.mts" extension-receipt "$report" "$metadata" "$platform" "$candidate_sha" "$candidate_tree" "$OLIPHAUNT_MOBILE_E2E_EXPECT_EXTENSIONS" >"$receipt_tmp" || receipt_status=$? + OLIPHAUNT_MOBILE_E2E_EXPECT_LIFECYCLE="${lifecycle_smoke:-${OLIPHAUNT_MOBILE_E2E_EXPECT_LIFECYCLE:-0}}" \ + bun "$root/src/native/sdks/react-native/tools/expo-runner-reporting.mts" extension-receipt "$report" "$metadata" "$platform" "$candidate_sha" "$candidate_tree" "$OLIPHAUNT_MOBILE_E2E_EXPECT_EXTENSIONS" >"$receipt_tmp" || receipt_status=$? if [ "$receipt_status" -ne 0 ]; then rm -f "$receipt_tmp" "$receipt" || true echo "$platform installed-app extension receipt verification failed" >&2 diff --git a/src/native/sdks/react-native/tools/expo-runner-reporting.test.mts b/src/native/sdks/react-native/tools/expo-runner-reporting.test.mts index ad0711e83..b6c77214c 100644 --- a/src/native/sdks/react-native/tools/expo-runner-reporting.test.mts +++ b/src/native/sdks/react-native/tools/expo-runner-reporting.test.mts @@ -23,7 +23,7 @@ test.after(() => rmSync(fixture, { force: true, recursive: true })); function report(extensionCount) { return { - schema: 'oliphaunt-expo-smoke-pass-v4', + schema: 'oliphaunt-expo-smoke-pass-v5', runner: 'smoke', platform: 'android', extensionCount, @@ -33,11 +33,17 @@ function report(extensionCount) { extensionCatalogSha256: catalogSha256, catalogProfile: 'standard', icuRuntimeProof: false, + lifecycleResume: false, }; } -function extensionReceipt(selectedExtensions, extensionCount) { - writeFileSync(reportFile, JSON.stringify(report(extensionCount))); +function extensionReceipt( + selectedExtensions, + extensionCount, + overrides = {}, + expectedLifecycle = '0', +) { + writeFileSync(reportFile, JSON.stringify({ ...report(extensionCount), ...overrides })); return spawnSync( process.execPath, [ @@ -45,7 +51,7 @@ function extensionReceipt(selectedExtensions, extensionCount) { 'extension-receipt', reportFile, metadataFile, - 'android', + (overrides as any).platform ?? 'android', 'a'.repeat(40), 'b'.repeat(40), selectedExtensions, @@ -56,6 +62,7 @@ function extensionReceipt(selectedExtensions, extensionCount) { ...process.env, OLIPHAUNT_MOBILE_E2E_EXPECT_ICU: '0', OLIPHAUNT_MOBILE_E2E_EXPECT_CATALOG_PROFILE: 'standard', + OLIPHAUNT_MOBILE_E2E_EXPECT_LIFECYCLE: expectedLifecycle, }, }, ); @@ -78,3 +85,22 @@ test('rejects unknown, duplicate, and mismatched extension selections', () => { assert.notEqual(extensionReceipt('vector,vector', 2).status, 0); assert.notEqual(extensionReceipt('vector', 0).status, 0); }); + +test('required lifecycle qualification rejects ordinary, old and missing PASS proofs on both platforms', () => { + for (const platform of ['android', 'ios']) { + const valid = extensionReceipt('vector', 1, { platform, lifecycleResume: true }, '1'); + assert.equal(valid.status, 0, valid.stderr); + assert.equal(JSON.parse(valid.stdout).lifecycleResume, true); + for (const overrides of [ + { lifecycleResume: false }, + { lifecycleResume: undefined }, + { lifecycleResume: 'true' }, + { schema: 'oliphaunt-expo-smoke-pass-v4', lifecycleResume: true }, + ]) + assert.notEqual(extensionReceipt('vector', 1, { platform, ...overrides }, '1').status, 0); + assert.notEqual(extensionReceipt('vector', 1, { platform }, 'invalid').status, 0); + const ordinary = extensionReceipt('vector', 1, { platform, lifecycleResume: false }, '0'); + assert.equal(ordinary.status, 0, ordinary.stderr); + assert.equal(JSON.parse(ordinary.stdout).lifecycleResume, false); + } +}); diff --git a/src/native/sdks/react-native/tools/icu-autolinking-fixture.mts b/src/native/sdks/react-native/tools/icu-autolinking-fixture.mts index 358be9811..118004f3f 100644 --- a/src/native/sdks/react-native/tools/icu-autolinking-fixture.mts +++ b/src/native/sdks/react-native/tools/icu-autolinking-fixture.mts @@ -10,7 +10,7 @@ const icuRoot = path.join(consumer, 'node_modules/@oliphaunt/icu'); const readJson = (file) => JSON.parse(readFileSync(file, 'utf8')); const writeJson = (file, value) => writeFileSync(file, JSON.stringify(value)); -if (phase === 'prepare') { +if (phase === 'prepare' || phase === 'prepare-packed') { const [reactNativeTarball, icuSource, expoProject] = args; const resolver = createRequire(path.join(expoProject, 'package.json')); const dependencies = {}; @@ -50,14 +50,18 @@ if (phase === 'prepare') { path.join(consumer, 'node_modules/@oliphaunt/react-native'), 'package', ); - const source = path.join(root, 'icu-source'); - mkdirSync(source); - for (const file of ['package.json', 'OliphauntICU.podspec']) - cpSync(path.join(icuSource, file), path.join(source, file)); - cpSync( - path.join(icuSource, 'react-native.config.cts'), - path.join(source, 'react-native.config.js'), - ); + if (phase === 'prepare-packed') { + extractPortableArchiveTree(icuSource, icuRoot, 'package'); + } else { + const source = path.join(root, 'icu-source'); + mkdirSync(source); + for (const file of ['package.json', 'OliphauntICU.podspec']) + cpSync(path.join(icuSource, file), path.join(source, file)); + cpSync( + path.join(icuSource, 'react-native.config.cts'), + path.join(source, 'react-native.config.js'), + ); + } } else if (phase === 'extract') { extractPortableArchiveTree(args[0], icuRoot, 'package'); } else if (phase === 'control') { diff --git a/src/native/sdks/react-native/tools/mobile-e2e.sh b/src/native/sdks/react-native/tools/mobile-e2e.sh index 90fc49ffe..8f5a3ceab 100755 --- a/src/native/sdks/react-native/tools/mobile-e2e.sh +++ b/src/native/sdks/react-native/tools/mobile-e2e.sh @@ -36,12 +36,9 @@ case "$platform" in export OLIPHAUNT_EXPO_ANDROID_BUILD_TYPE="${OLIPHAUNT_EXPO_ANDROID_BUILD_TYPE:-release}" export OLIPHAUNT_EXPO_ANDROID_E2E_ONLY=1 export OLIPHAUNT_EXPO_ANDROID_LIFECYCLE_SMOKE="${OLIPHAUNT_EXPO_ANDROID_LIFECYCLE_SMOKE:-0}" + export OLIPHAUNT_MOBILE_E2E_EXPECT_LIFECYCLE="$OLIPHAUNT_EXPO_ANDROID_LIFECYCLE_SMOKE" export OLIPHAUNT_EXPO_ANDROID_SCRATCH="$mobile_scratch" if [ "$mobile_runner" = "smoke" ]; then - command -v unzip >/dev/null 2>&1 || { - echo "Android mobile E2E requires unzip to inspect the exact APK runtime manifest." >&2 - exit 1 - } export_mobile_e2e_icu_expectation_from_android_apk "$apk" "Android APK" rm -f \ "$mobile_scratch/reports/smoke-report.json" \ @@ -69,6 +66,7 @@ case "$platform" in export OLIPHAUNT_EXPO_IOS_CONFIGURATION="${OLIPHAUNT_EXPO_IOS_CONFIGURATION:-Release}" export OLIPHAUNT_EXPO_IOS_E2E_ONLY=1 export OLIPHAUNT_EXPO_IOS_LIFECYCLE_SMOKE="${OLIPHAUNT_EXPO_IOS_LIFECYCLE_SMOKE:-0}" + export OLIPHAUNT_MOBILE_E2E_EXPECT_LIFECYCLE="$OLIPHAUNT_EXPO_IOS_LIFECYCLE_SMOKE" export OLIPHAUNT_EXPO_IOS_SCRATCH="$mobile_scratch" if [ "$mobile_runner" = "smoke" ]; then export_mobile_e2e_icu_expectation_from_ios_app "$app" diff --git a/src/native/sdks/react-native/tools/mobile-extension-artifact-paths.mts b/src/native/sdks/react-native/tools/mobile-extension-artifact-paths.mts index 10f5775a7..21016059c 100644 --- a/src/native/sdks/react-native/tools/mobile-extension-artifact-paths.mts +++ b/src/native/sdks/react-native/tools/mobile-extension-artifact-paths.mts @@ -99,10 +99,14 @@ const BUNDLE_CARRIER_ASSET_KEYS = new Set([ 'memberCount', ]); +function declaresReleaseOwnership(manifest) { + return Object.hasOwn(manifest, 'releaseProduct') || Object.hasOwn(manifest, 'family'); +} + function manifestEnvelopeKeys(baseKeys, manifest, repositoryContract) { const owner = repositoryContract.products.get(manifest.product); const keys = - owner?.releaseProduct === owner?.artifactProduct + owner?.releaseProduct === owner?.artifactProduct && !declaresReleaseOwnership(manifest) ? baseKeys : new Set([...baseKeys, 'releaseProduct', 'family']); if (Object.hasOwn(manifest, 'qualificationOnly')) { @@ -675,13 +679,16 @@ function validateManifestEnvelope(manifest, manifestPath, repositoryContract, me fail(`${manifestPath} version must be stable SemVer`); } const owner = validateCompatibility(manifest, manifestPath, repositoryContract); - if (owner.releaseProduct !== owner.artifactProduct) { + if (owner.releaseProduct !== owner.artifactProduct || declaresReleaseOwnership(manifest)) { if (manifest.releaseProduct !== owner.releaseProduct || manifest.family !== 'native') { fail(`${manifestPath} must be owned by ${owner.releaseProduct}/native`); } - if (manifest.version !== repositoryContract.nativeRuntimeVersion) { - fail(`${manifestPath} version must match its native release owner`); - } + } + if ( + owner.releaseProduct !== owner.artifactProduct && + manifest.version !== repositoryContract.nativeRuntimeVersion + ) { + fail(`${manifestPath} version must match its native release owner`); } const actualSqlNames = members.map((member) => member?.sqlName); if (new Set(actualSqlNames).size !== actualSqlNames.length) { diff --git a/src/native/sdks/react-native/tools/mobile-extension-artifact-paths.test.mts b/src/native/sdks/react-native/tools/mobile-extension-artifact-paths.test.mts index 3c23f3d5a..a199602bb 100644 --- a/src/native/sdks/react-native/tools/mobile-extension-artifact-paths.test.mts +++ b/src/native/sdks/react-native/tools/mobile-extension-artifact-paths.test.mts @@ -586,6 +586,8 @@ test('qualifies singleton and bundled workspace bytes without changing release p const value = fixture(t); const aggregate = value.installAggregate(); const leaf = value.installLeaf(); + leaf.manifest.releaseProduct = VECTOR; + leaf.manifest.family = 'native'; leaf.manifest.compatibility = { ...COMPATIBILITY, nativeRuntimeVersion: '0.0.0', @@ -641,6 +643,33 @@ test('qualifies singleton and bundled workspace bytes without changing release p await assert.rejects(resolveMobileExtensionArtifactPaths(args), /must exactly match/); }); +test('singleton manifests retain independent versions and validate paired explicit native ownership', async (t) => { + const value = fixture(t); + const leaf = value.installLeaf(); + assert.notEqual(VERSION, NATIVE_RUNTIME_VERSION); + const options = { + extensions: 'vector', + assetKind: 'runtime', + assetTarget: 'android-arm64-v8a', + }; + const contents = [leaf.contents.get('android-arm64-v8a:runtime')]; + assertContents(outputPaths(await value.resolve(options)), contents); + const canonical = { ...leaf.manifest, releaseProduct: VECTOR, family: 'native' }; + value.writeManifest(VECTOR, canonical); + assertContents(outputPaths(await value.resolve(options)), contents); + for (const mutation of [ + { releaseProduct: CONTRIB }, + { family: 'wasix' }, + { releaseProduct: undefined }, + { family: undefined }, + ]) { + value.writeManifest(VECTOR, { ...canonical, ...mutation }); + const result = await value.resolve(options); + assert.equal(result.status, 1); + assert.match(result.stderr, /must be owned by|fields must be exactly/u); + } +}); + test('rejects outer and nested carrier tampering independently', async (t) => { const outer = fixture(t); const outerAggregate = outer.installAggregate({ targets: ['android-arm64-v8a'] }); diff --git a/src/native/sdks/react-native/tools/native-bundle.mts b/src/native/sdks/react-native/tools/native-bundle.mts new file mode 100644 index 000000000..7cde7ccd9 --- /dev/null +++ b/src/native/sdks/react-native/tools/native-bundle.mts @@ -0,0 +1,46 @@ +import assert from 'node:assert/strict'; +import { chmod, copyFile, mkdir, mkdtemp, readFile, rm } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { dirname, join, resolve } from 'node:path'; +import { extractNpmPackage } from '../../../../../build_defs/wasix/browser/npm-archives.mts'; + +const [archive, specificationFile, output] = Bun.argv.slice(2); +assert(archive && specificationFile && output); +const specification: Record = JSON.parse(await readFile(specificationFile, 'utf8')); +const directory = await mkdtemp(join(tmpdir(), 'oliphaunt-rn-bundle-')); +try { + const tool = join(directory, 'compiler'); + await extractNpmPackage(archive, tool); + for (const [relative, source] of Object.entries(specification)) { + assert( + !relative.startsWith('/') && + !relative.split('/').some((part) => part === '..' || part === '.' || !part), + ); + const destination = join(directory, relative); + await mkdir(dirname(destination), { recursive: true }); + await copyFile(source, destination); + } + const binary = join(tool, 'bin', process.platform === 'win32' ? 'esbuild.exe' : 'esbuild'); + await chmod(binary, 0o755); + const result = Bun.spawnSync( + [ + binary, + 'src/native/sdks/react-native/tools/stage-ios-app.mts', + '--bundle', + '--platform=node', + '--format=esm', + '--target=es2022', + '--external:node:*', + `--outfile=${resolve(output)}`, + ], + { + cwd: directory, + env: { ...process.env, PATH: '', NODE_PATH: '', NODE_OPTIONS: '' }, + stdout: 'inherit', + stderr: 'inherit', + }, + ); + assert.equal(result.exitCode, 0, 'Declared esbuild helper compilation failed'); +} finally { + await rm(directory, { recursive: true, force: true }); +} diff --git a/src/native/sdks/react-native/tools/native-carrier-package.mts b/src/native/sdks/react-native/tools/native-carrier-package.mts new file mode 100644 index 000000000..af1b85c7d --- /dev/null +++ b/src/native/sdks/react-native/tools/native-carrier-package.mts @@ -0,0 +1,17 @@ +import { IOS_CARRIER_FILENAME } from '../../swift/tools/swift-native-carrier-contract.mts'; + +/** Shared conventional and Bazel public-package attachment; carrier bytes stay separate. */ +export function attachReactNativeCarrierManifest(manifest) { + return { + ...manifest, + oliphaunt: { + ...(manifest.oliphaunt ?? {}), + iosCarrierManifest: `./${IOS_CARRIER_FILENAME}`, + }, + files: [...new Set([...(manifest.files ?? []), IOS_CARRIER_FILENAME])], + exports: { + ...(manifest.exports ?? {}), + './ios-carriers': `./${IOS_CARRIER_FILENAME}`, + }, + }; +} diff --git a/src/native/sdks/react-native/tools/native-consumer.mts b/src/native/sdks/react-native/tools/native-consumer.mts new file mode 100644 index 000000000..1c71e3e90 --- /dev/null +++ b/src/native/sdks/react-native/tools/native-consumer.mts @@ -0,0 +1,189 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { copyFile, mkdir, readFile, symlink, writeFile } from 'node:fs/promises'; +import { dirname, join } from 'node:path'; +import { extractNpmPackage } from '../../../../../build_defs/wasix/browser/npm-archives.mts'; +import { readPortableArchiveEntries } from '../../../../../tools/packaging/portable-archive.mts'; +import { IOS_CARRIER_FILENAME } from '../../swift/tools/swift-native-carrier-contract.mts'; +import { attachReactNativeCarrierManifest } from './native-carrier-package.mts'; +import { type ReactNativePackageInputs, validateReactNativeNpm } from './native-package.mts'; + +const [archive, query, sourceManifest, node, typescript, specificationFile] = Bun.argv.slice(2); +assert(archive && query && sourceManifest && node && typescript && specificationFile); +assert(process.env.TEST_TMPDIR && process.env.OLIPHAUNT_BAZEL_RUNFILES); +const runfilesRoot = process.env.OLIPHAUNT_BAZEL_RUNFILES; +const root = join(process.env.TEST_TMPDIR, 'react-native-installed-consumer'); +const specification = JSON.parse(await readFile(specificationFile, 'utf8')); +const canonical = JSON.parse(await readFile(sourceManifest, 'utf8')); +const carrierInputs = + specification.carrierInputs && + (Object.fromEntries( + Object.entries(specification.carrierInputs).map(([name, file]) => [ + name, + join(runfilesRoot, file as string), + ]), + ) as ReactNativePackageInputs | undefined); +const carrier = carrierInputs && validateReactNativeNpm(archive, carrierInputs); +const installed = join(root, 'node_modules/@oliphaunt/react-native'); +await mkdir(root, { recursive: true }); +const installedArchive = join(root, 'react-native.tgz'); +await copyFile(archive, installedArchive); +const entries = [...readPortableArchiveEntries(installedArchive).values()]; +assert(entries.length > 0); +assert( + !entries.some((entry) => /\.(?:so|a|node|dylib|dll)$/u.test(entry.name)), + 'Source envelope must omit compiled native payload', +); +await extractNpmPackage(installedArchive, installed); +await extractNpmPackage(query, join(root, 'node_modules/@oliphaunt/ts-query')); +const manifest = JSON.parse(await readFile(join(installed, 'package.json'), 'utf8')); +assert.equal(manifest.name, specification.name); +assert.equal(manifest.version, specification.version); +assert.deepEqual( + manifest.oliphaunt, + (carrier ? attachReactNativeCarrierManifest(canonical) : canonical).oliphaunt, +); +assert.deepEqual(manifest.dependencies, canonical.dependencies); +assert.deepEqual(manifest.peerDependencies, canonical.peerDependencies); +assert.deepEqual(manifest.scripts, { + 'package:verify-ios': 'node ./tools/verify-ios-package.mjs --package-dir .', +}); +assert.equal(manifest.devDependencies, undefined); +const stores: Record = {}; +for (const [id, row] of Object.entries(specification.packages) as [ + string, + { package: string; source: string }, +][]) { + const destination = join(root, '.compiler', id, 'node_modules', row.package); + stores[id] = destination; + await extractNpmPackage(join(process.env.OLIPHAUNT_BAZEL_RUNFILES, row.source), destination, { + allowIdenticalAliases: true, + }); +} +for (const [id, row] of Object.entries(specification.packages) as [ + string, + { dependencies: Record }, +][]) { + for (const [name, dependency] of Object.entries(row.dependencies)) { + assert(stores[dependency], `Missing declared dependency ${name}`); + const link = join(stores[id], 'node_modules', name); + await mkdir(dirname(link), { recursive: true }); + await symlink(stores[dependency], link, 'dir'); + } +} +for (const [name, id] of Object.entries(specification.roots) as [string, string][]) { + const link = join(root, 'node_modules', name); + await mkdir(dirname(link), { recursive: true }); + await symlink(stores[id], link, 'dir'); +} +function run(script: string, args: string[], cwd = root, preload?: string) { + const execution = Bun.spawnSync( + [node, ...(preload ? ['--require', preload] : []), script, ...args], + { + cwd, + env: { ...process.env, PATH: '', NODE_PATH: '', NODE_OPTIONS: '' }, + stdout: 'inherit', + stderr: 'inherit', + }, + ); + assert.equal(execution.exitCode, 0, `Installed consumer failed: ${script}`); +} +const consumer = join(root, 'consumer.ts'); +await writeFile( + consumer, + ` +import Oliphaunt, { directory, applicationData, type OliphauntClient, type OliphauntDatabase } from '@oliphaunt/react-native'; +import { extensions } from '@oliphaunt/react-native/extensions'; +const client: OliphauntClient = Oliphaunt; +const storage = [directory('file:///data/db'), applicationData('main')]; +async function query(db: OliphauntDatabase) { return db.query('SELECT 42', [], { rowMode: 'array' }); } +void [client, storage, extensions.hstore, query]; +`, +); +run(join(typescript, 'bin/tsc'), [ + '--module', + 'ESNext', + '--moduleResolution', + 'Bundler', + '--target', + 'ES2022', + '--lib', + 'ES2023,DOM', + '--types', + 'node,bun', + '--strict', + '--skipLibCheck', + '--noEmit', + consumer, +]); +const javascript = join(root, 'consumer.cjs'); +await writeFile( + javascript, + ` +const assert = require('node:assert/strict'); +const { directory, applicationData } = require('@oliphaunt/react-native/storage'); +const { extensions } = require('@oliphaunt/react-native/extensions'); +assert.deepEqual(directory('file:///data/my%20db'), { kind: 'directory', path: '/data/my db' }); +assert.deepEqual(applicationData('primary'), { kind: 'applicationData', name: 'primary' }); +assert.throws(() => directory('https://example.invalid/db'), /filesystem path or local file URI/); +assert(extensions.hstore); +assert.equal(typeof require('./node_modules/@oliphaunt/react-native/app.plugin.js'), 'function'); +assert.equal(typeof require('./node_modules/@oliphaunt/react-native/react-native.config.js'), 'object'); +`, +); +run(javascript, []); +run(join(installed, 'tools/verify-ios-package.mjs'), ['--package-dir', installed]); +run(join(installed, 'tools/stage-ios-app.mjs'), ['--help']); +if (carrier && carrierInputs) { + assert.deepEqual( + await readFile(join(installed, IOS_CARRIER_FILENAME)), + await readFile(carrierInputs.carrier), + ); + const cache = join(root, 'ios-cache'); + await mkdir(join(cache, 'objects'), { recursive: true }); + for (const asset of carrier.base.assets) { + const file = + asset.role === 'base-xcframework' + ? carrierInputs.xcframework + : join(process.env.OLIPHAUNT_BAZEL_RUNFILES, specification.runtimeResources); + const bytes = await readFile(file); + assert.equal(bytes.length, asset.bytes); + assert.equal(createHash('sha256').update(bytes).digest('hex'), asset.sha256); + await writeFile(join(cache, 'objects', `${asset.sha256}-${asset.name}`), bytes); + } + // Real published HTTPS identities remain intact. Any cache miss fails before network use. + const offline = join(root, 'offline.cjs'); + await writeFile( + offline, + "globalThis.fetch = () => { throw new Error('Installed consumer attempted undeclared network input'); };\n", + ); + const payload = join(root, 'app/ios/oliphaunt'); + run( + join(installed, 'tools/stage-ios-app.mjs'), + [ + '--carrier', + join(installed, IOS_CARRIER_FILENAME), + '--output-dir', + payload, + '--cache-dir', + cache, + ], + root, + offline, + ); + run(join(installed, 'tools/verify-ios-package.mjs'), ['--payload-dir', payload]); +} +const schema = join(root, 'schema.json'); +run( + join(installed, 'tools/codegen-check.cjs'), + [schema, 'src/specs/NativeOliphaunt.ts'], + installed, +); +const generated = JSON.parse(await readFile(schema, 'utf8')); +assert.equal(Object.keys(generated.modules).length, 1); +assert.equal(Object.values(generated.modules)[0].type, 'NativeModule'); +console.log( + carrier + ? 'Installed React Native public npm: public types, CommonJS helpers, real codegen and authenticated iOS carrier staging/verification passed; native TurboModule execution requires installed mobile app' + : 'Installed React Native source package: public types, CommonJS helpers, iOS verifier/stager and real codegen passed; native TurboModule execution requires installed mobile app', +); diff --git a/src/native/sdks/react-native/tools/native-manifest.mts b/src/native/sdks/react-native/tools/native-manifest.mts new file mode 100644 index 000000000..090614c53 --- /dev/null +++ b/src/native/sdks/react-native/tools/native-manifest.mts @@ -0,0 +1,33 @@ +import assert from 'node:assert/strict'; +import { copyFile, mkdir, mkdtemp, rm } from 'node:fs/promises'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { pathToFileURL } from 'node:url'; + +const [source, output] = Bun.argv.slice(2); +assert(source && output); +const stage = await mkdtemp(join(tmpdir(), 'oliphaunt-rn-manifest-')); +try { + const helpers = join(stage, 'tools/packaging'); + await mkdir(helpers, { recursive: true }); + for (const file of [ + 'source-only-sdk-package.mts', + 'release-notices.mts', + 'release-directory-safety.mts', + 'portable-archive.mts', + ]) + await copyFile(join('tools/packaging', file), join(helpers, file)); + for (const file of ['LICENSE', 'THIRD_PARTY_NOTICES.md']) await copyFile(file, join(stage, file)); + const directory = join(stage, 'package'); + await mkdir(directory); + await copyFile(source, join(directory, 'package.json')); + const { prepareSourceOnlyNpmPackage, SOURCE_ONLY_NPM_PROFILES } = await import( + pathToFileURL(join(helpers, 'source-only-sdk-package.mts')).href + ); + prepareSourceOnlyNpmPackage(directory, SOURCE_ONLY_NPM_PROFILES['react-native']); + await mkdir(output, { recursive: true }); + for (const file of ['package.json', 'LICENSE', 'THIRD_PARTY_NOTICES.md']) + await copyFile(join(directory, file), join(output, file)); +} finally { + await rm(stage, { recursive: true, force: true }); +} diff --git a/src/native/sdks/react-native/tools/native-package-contract.mts b/src/native/sdks/react-native/tools/native-package-contract.mts new file mode 100644 index 000000000..cc2b4b3ab --- /dev/null +++ b/src/native/sdks/react-native/tools/native-package-contract.mts @@ -0,0 +1,107 @@ +/** Declared Bazel archive consumer; requires its runner-supplied package inputs. */ +import assert from 'node:assert/strict'; +import { copyFileSync, readFileSync, writeFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { archive as npmArchive } from '../../../../../build_defs/query/package.mts'; +import { readPortableArchiveEntries } from '../../../../../tools/packaging/portable-archive.mts'; +import { IOS_CARRIER_FILENAME } from '../../swift/tools/swift-native-carrier-contract.mts'; +import { + packageReactNativeNpm, + type ReactNativePackageInputs, + validateReactNativeNpm, +} from './native-package.mts'; + +const [specification, archiveInput, carrierOutput] = Bun.argv.slice(2); +assert( + specification && + archiveInput && + carrierOutput && + process.env.OLIPHAUNT_BAZEL_RUNFILES && + process.env.TEST_TMPDIR, +); +const runfilesRoot = process.env.OLIPHAUNT_BAZEL_RUNFILES; +const archive = join(process.env.TEST_TMPDIR, 'react-native-public.tgz'); +copyFileSync(archiveInput, archive); +const inputs = Object.fromEntries( + Object.entries(JSON.parse(readFileSync(specification, 'utf8'))).map(([name, file]) => [ + name, + join(runfilesRoot, file as string), + ]), +) as unknown as ReactNativePackageInputs; +const carrier = validateReactNativeNpm(archive, inputs); +assert.equal( + carrier.base.version, + JSON.parse(readFileSync(inputs.carrierSource, 'utf8')).nativeVersion, +); +assert.deepEqual( + packageReactNativeNpm(inputs), + readFileSync(archive), + 'Public npm must be deterministic', +); +const entries = Object.fromEntries( + [...readPortableArchiveEntries(archive).values()].map((entry) => [ + entry.name, + Buffer.from(entry.data()), + ]), +); +assert.deepEqual(entries[`package/${IOS_CARRIER_FILENAME}`], readFileSync(inputs.carrier)); +assert.deepEqual( + readFileSync(carrierOutput), + entries[`package/${IOS_CARRIER_FILENAME}`], + 'Source-owned RN carrier output must be the actual final npm member', +); +const manifest = JSON.parse(entries['package/package.json'].toString('utf8')); +assert.equal(manifest.exports['./ios-carriers'], `./${IOS_CARRIER_FILENAME}`); +assert.equal(manifest.oliphaunt.iosCarrierManifest, `./${IOS_CARRIER_FILENAME}`); +assert(manifest.files.includes(IOS_CARRIER_FILENAME)); +assert(entries['package/android/src/main/cpp/include/oliphaunt.h'].length > 0); +assert.deepEqual( + entries['package/src/generated/ios-static-dependencies.json'], + readFileSync(inputs.iosStaticDependencies), +); + +const bad = join(process.env.TEST_TMPDIR, 'react-native-invalid.tgz'); +for (const mutate of [ + (rows) => { + delete rows[`package/${IOS_CARRIER_FILENAME}`]; + }, + (rows) => { + rows[`package/${IOS_CARRIER_FILENAME}`] = Buffer.from('{}\n'); + }, + (rows) => { + rows['package/android/src/main/cpp/include/oliphaunt.h'] = Buffer.from('retargeted header'); + }, + (rows) => { + rows['package/ios/frameworks/liboliphaunt.dylib'] = Buffer.from('unwanted native payload'); + }, + (rows) => { + rows['package/unowned.txt'] = Buffer.from('undeclared member'); + }, + (rows) => { + const changed = JSON.parse(rows['package/package.json'].toString('utf8')); + changed.oliphaunt.swiftSdkVersion = '99.0.0'; + rows['package/package.json'] = Buffer.from(JSON.stringify(changed)); + }, +]) { + const changed = { ...entries }; + mutate(changed); + writeFileSync(bad, npmArchive(changed)); + assert.throws(() => validateReactNativeNpm(bad, inputs)); +} +const authored = JSON.parse(readFileSync(inputs.authoredManifest, 'utf8')); +authored.oliphaunt.swiftSdkVersion = '99.0.0'; +const wrongPin = join(process.env.TEST_TMPDIR, 'wrong-pin.json'); +writeFileSync(wrongPin, JSON.stringify(authored)); +assert.throws( + () => packageReactNativeNpm({ ...inputs, authoredManifest: wrongPin }), + /compatibility pin/u, +); +const changedCarrier = join(process.env.TEST_TMPDIR, 'changed-carrier.json'); +writeFileSync(changedCarrier, `${readFileSync(inputs.carrier, 'utf8')} `); +assert.throws( + () => packageReactNativeNpm({ ...inputs, carrier: changedCarrier }), + /original source member/u, +); +console.log( + 'React Native public npm: exact immutable carrier/header, full deterministic envelope and eight negative cases passed', +); diff --git a/src/native/sdks/react-native/tools/native-package.mts b/src/native/sdks/react-native/tools/native-package.mts new file mode 100644 index 000000000..3ba0acd5e --- /dev/null +++ b/src/native/sdks/react-native/tools/native-package.mts @@ -0,0 +1,154 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { copyFileSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { basename, dirname, join } from 'node:path'; +import { archive } from '../../../../../build_defs/query/package.mts'; +import { readPortableArchiveEntries } from '../../../../../tools/packaging/portable-archive.mts'; +import { + assertSourceOnlyNpmArchive, + SOURCE_ONLY_NPM_PROFILES, +} from '../../../../../tools/packaging/source-only-sdk-package.mts'; +import { + IOS_CARRIER_FILENAME, + validateFrozenNativeCarrierIdentity, +} from '../../swift/tools/swift-native-carrier-contract.mts'; +import { readNativeAppleHeader } from '../../swift/tools/swift-xcframework-contract.mts'; +import { attachReactNativeCarrierManifest } from './native-carrier-package.mts'; + +export interface ReactNativePackageInputs { + sourceArchive: string; + authoredManifest: string; + carrier: string; + carrierSource: string; + xcframework: string; + iosStaticDependencies: string; +} + +const json = (file: string) => JSON.parse(readFileSync(file, 'utf8')); + +function regularArchive(file: string, read: (local: string) => T): T { + const directory = mkdtempSync(join(tmpdir(), 'oliphaunt-react-native-envelope-')); + try { + const local = join(directory, basename(file)); + copyFileSync(file, local); + return read(local); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +} + +export function reactNativeCarrier(inputs: ReactNativePackageInputs) { + const authored = json(inputs.authoredManifest); + const source = json(inputs.carrierSource); + assert.equal( + authored.oliphaunt?.swiftSdkVersion, + source.swiftVersion, + 'React Native Swift compatibility pin must match the genuine source requirement', + ); + const bytes = readFileSync(inputs.carrier); + assert.deepEqual( + { size: bytes.length, sha256: createHash('sha256').update(bytes).digest('hex') }, + source.carrierFile, + 'Carrier differs from its actual original source member', + ); + return validateFrozenNativeCarrierIdentity({ + carrier: JSON.parse(bytes.toString('utf8')), + expectedNativeVersion: source.nativeVersion, + }); +} + +function sourceEntries(inputs: ReactNativePackageInputs) { + return regularArchive(inputs.sourceArchive, (source) => { + assertSourceOnlyNpmArchive(source, SOURCE_ONLY_NPM_PROFILES['react-native']); + const entries: Record = {}; + for (const entry of readPortableArchiveEntries(source).values()) { + assert(entry.isFile && entry.name.startsWith('package/'), 'npm must contain package files'); + assert( + !/\.(?:so(?:\.\d+)*|a|node|dylib|dll|exe|lib)$/u.test(entry.name) && + !/^package\/(?:ios\/(?:vendor|frameworks|extension-frameworks|generated|resources)|android\/(?:\.gradle|\.cxx|build|src\/main\/(?:jniLibs|assets)))\//u.test( + entry.name, + ), + `Source npm must omit compiled native and app-owned payloads: ${entry.name}`, + ); + entries[entry.name] = entry.data(); + } + const manifest = JSON.parse(Buffer.from(entries['package/package.json']).toString('utf8')); + const authored = json(inputs.authoredManifest); + for (const field of [ + 'name', + 'version', + 'oliphaunt', + 'dependencies', + 'peerDependencies', + 'exports', + ]) + assert.deepEqual( + manifest[field], + authored[field], + `Source npm must preserve authored ${field}`, + ); + assert( + !entries[`package/${IOS_CARRIER_FILENAME}`], + 'Source npm already contains carrier metadata', + ); + return { entries, manifest }; + }); +} + +export function packageReactNativeNpm(inputs: ReactNativePackageInputs): Buffer { + const carrier = reactNativeCarrier(inputs); + const framework = carrier.base.assets.find((asset) => asset.role === 'base-xcframework'); + const frameworkBytes = readFileSync(inputs.xcframework); + assert.equal( + frameworkBytes.length, + framework.bytes, + 'Held XCFramework size differs from carrier', + ); + assert.equal( + createHash('sha256').update(frameworkBytes).digest('hex'), + framework.sha256, + 'Held XCFramework digest differs from carrier', + ); + const header = regularArchive(inputs.xcframework, readNativeAppleHeader); + const { entries, manifest } = sourceEntries(inputs); + entries['package/package.json'] = Buffer.from( + `${JSON.stringify(attachReactNativeCarrierManifest(manifest), null, 2)}\n`, + ); + entries[`package/${IOS_CARRIER_FILENAME}`] = readFileSync(inputs.carrier); + entries['package/android/src/main/cpp/include/oliphaunt.h'] = header; + entries['package/src/generated/ios-static-dependencies.json'] = readFileSync( + inputs.iosStaticDependencies, + ); + return archive(entries); +} + +/** Verify the entire final envelope against the declared compiler output and immutable carrier. */ +export function validateReactNativeNpm(file: string, inputs: ReactNativePackageInputs) { + regularArchive(file, (local) => + assertSourceOnlyNpmArchive(local, SOURCE_ONLY_NPM_PROFILES['react-native']), + ); + const expected = packageReactNativeNpm(inputs); + assert.deepEqual( + readFileSync(file), + expected, + 'Final React Native npm differs from its declared source/carrier inputs', + ); + return reactNativeCarrier(inputs); +} + +if (import.meta.main) { + const [specification, output, carrierOutput] = Bun.argv.slice(2); + assert( + specification && output && [4, 5].includes(Bun.argv.length), + 'usage: native-package.mts INPUTS.json OUTPUT.tgz [CARRIER.json]', + ); + const inputs = json(specification) as ReactNativePackageInputs; + writeFileSync(output, packageReactNativeNpm(inputs)); + validateReactNativeNpm(output, inputs); + if (carrierOutput) { + mkdirSync(dirname(carrierOutput), { recursive: true }); + // Retain the very same authenticated held File embedded in the final npm. + writeFileSync(carrierOutput, readFileSync(inputs.carrier), { mode: 0o644 }); + } +} diff --git a/src/native/sdks/react-native/tools/stage-release-artifacts.mts b/src/native/sdks/react-native/tools/stage-release-artifacts.mts index 5668398e0..0d13abe3d 100644 --- a/src/native/sdks/react-native/tools/stage-release-artifacts.mts +++ b/src/native/sdks/react-native/tools/stage-release-artifacts.mts @@ -1,15 +1,19 @@ import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'; import path from 'node:path'; - +import { fail, requireDir } from '../../../../../tools/packaging/staging.mts'; +import { productDependencyCompatibilityVersion } from '../../../../../tools/release/release-graph.mts'; import { - IOS_CARRIER_FILENAME, buildIosCarrierManifest, + IOS_CARRIER_FILENAME, } from '../../swift/tools/ios-carrier-manifest.mts'; -import { fail, requireDir } from '../../../../../tools/packaging/staging.mts'; -import { productDependencyCompatibilityVersion } from '../../../../../tools/release/release-graph.mts'; import { pinnedNativeCarrierDirectory } from '../../swift/tools/pinned-native-carrier.mts'; +import { attachReactNativeCarrierManifest } from './native-carrier-package.mts'; -export async function stageArtifacts(artifactRoot, workRoot) { +export async function stageArtifacts( + artifactRoot, + workRoot, + { nativeSourceBasis = undefined } = {}, +) { const releasePackageDir = path.join(workRoot, 'package'); requireDir(releasePackageDir); const producerAssetDir = process.env.OLIPHAUNT_REACT_NATIVE_IOS_RELEASE_ASSET_DIR; @@ -30,12 +34,14 @@ export async function stageArtifacts(artifactRoot, workRoot) { version: nativeVersion, assetDir: producerAssetDir, workRoot, + sourceBasis: nativeSourceBasis, }); const carrier = buildIosCarrierManifest({ baseAssetDir: assetDir, baseRuntimeVersion: nativeVersion, baseCarrierManifest, extensionManifests: [], + baseSourceBasis: nativeSourceBasis, }); writeFileSync( path.join(releasePackageDir, IOS_CARRIER_FILENAME), @@ -43,16 +49,9 @@ export async function stageArtifacts(artifactRoot, workRoot) { 'utf8', ); const packageJsonFile = path.join(releasePackageDir, 'package.json'); - const packageJson = JSON.parse(readFileSync(packageJsonFile, 'utf8')); - packageJson.oliphaunt = { - ...(packageJson.oliphaunt ?? {}), - iosCarrierManifest: `./${IOS_CARRIER_FILENAME}`, - }; - packageJson.files = [...new Set([...(packageJson.files ?? []), IOS_CARRIER_FILENAME])]; - packageJson.exports = { - ...(packageJson.exports ?? {}), - './ios-carriers': `./${IOS_CARRIER_FILENAME}`, - }; + const packageJson = attachReactNativeCarrierManifest( + JSON.parse(readFileSync(packageJsonFile, 'utf8')), + ); writeFileSync(packageJsonFile, `${JSON.stringify(packageJson, null, 2)}\n`, 'utf8'); const carrierEvidence = path.join(artifactRoot, 'ios-carriers', IOS_CARRIER_FILENAME); mkdirSync(path.dirname(carrierEvidence), { recursive: true }); diff --git a/src/native/sdks/rust/BUILD.bazel b/src/native/sdks/rust/BUILD.bazel new file mode 100644 index 000000000..51b6fe926 --- /dev/null +++ b/src/native/sdks/rust/BUILD.bazel @@ -0,0 +1,104 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files", "source_quality_files") +load("//build_defs/languages:rust.bzl", "cargo_doc_test", "cargo_generator", "cargo_generator_test", "cargo_integration_test", "cargo_library", "cargo_library_test", "cargo_package_env") +load("@rules_rust//rust:defs.bzl", "rust_clippy_test") +load("//build_defs/languages:source.bzl", "cargo_source_package") +load("//build_defs/native:rust-runtime-test.bzl", "native_rust_runtime_test") +load("//build_defs/extensions:imported_members.bzl", "desktop_runtime_member_payloads") + +package(default_visibility = ["//visibility:public"]) +exports_files(["Cargo.toml", "release.toml"]) + +PATH_DEPS = { + "liboliphaunt-native-bindings": "//src/native/rust-bindings:lib", + "oliphaunt-broker": "//src/native/broker:lib", +} + +cargo_package_env() +BUILD_SCRIPT_DEPS = PATH_DEPS +cargo_generator(path_dependencies = BUILD_SCRIPT_DEPS) +cargo_generator(name = "mobile_build_script", path_dependencies = BUILD_SCRIPT_DEPS, features = ["mobile-bindings"], default_features = False) +cargo_generator(name = "minimal_build_script", path_dependencies = BUILD_SCRIPT_DEPS, default_features = False) +cargo_library(path_dependencies = PATH_DEPS, build_script = ":build_script") +cargo_library(name = "mobile_lib", path_dependencies = PATH_DEPS, build_script = ":mobile_build_script", features = ["mobile-bindings"], default_features = False) +cargo_library(name = "minimal_lib", path_dependencies = PATH_DEPS, build_script = ":minimal_build_script", default_features = False) +cargo_library_test(data = ["//src/test-fixtures:rust_fixtures"]) +cargo_generator_test() +cargo_library_test(name = "mobile_unit_test", crate = ":mobile_lib", features = ["mobile-bindings"], default_features = False, data = ["//src/test-fixtures:rust_fixtures"]) +_INTEGRATION_ROOTS = glob(["tests/*.rs"]) +filegroup(name = "integration_sources", srcs = _INTEGRATION_ROOTS + glob(["tests/support/**/*.rs"]) + ["src/test_fixtures.rs"]) +[ + cargo_integration_test( + name = source.removeprefix("tests/").removesuffix(".rs") + "_test", + source = source, + path_dependencies = PATH_DEPS, + srcs = glob(["tests/support/**/*.rs"]) + ["src/test_fixtures.rs"], + data = ["//src/test-fixtures:rust_fixtures"], + tags = ["manual"], + ) + for source in _INTEGRATION_ROOTS +] +cargo_doc_test(size = "small") +rust_clippy_test( + name = "clippy_test", + targets = [":lib", ":unit_test", ":build_script_"] + [":" + source.removeprefix("tests/").removesuffix(".rs") + "_test" for source in _INTEGRATION_ROOTS], + transitive = False, + size = "small", +) +[native_rust_runtime_test( + name = name + "_runtime_test", + binary = ":" + name + "_test", + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + size = "large", + timeout = "long", +) for name in ["native_smoke", "native_sql_regression"]] + +cargo_integration_test( + name = "mobile_broker_feature_test", + source = "tests/mobile_broker.rs", + path_dependencies = PATH_DEPS, + crate = ":mobile_lib", + features = ["mobile-bindings"], + default_features = False, + data = ["//src/test-fixtures:rust_fixtures"], + tags = ["manual"], +) +native_rust_runtime_test( + name = "mobile_broker_runtime_test", + binary = ":mobile_broker_feature_test", + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + size = "large", + timeout = "long", +) + +native_rust_runtime_test( + name = "native_extensions_runtime_test", + binary = ":native_extensions_test", + extensions = desktop_runtime_member_payloads(name = "native_extensions_runtime_members", include_postgis = True), + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + size = "large", + timeout = "long", +) + +cargo_source_package( + product = "oliphaunt-rust", + fixtures = "testdata/", + native_sdk = True, + qualification = [ + ":unit_test", + ":mobile_unit_test", + ":generator_test", + ":public_api_test", + ":build_resources_test", + "//src/native/sdks/rust/crates/oliphaunt-build:unit_test", + "//build_defs/native:rust_runtime_runner_test", + ":native_smoke_runtime_test", + ":native_sql_regression_runtime_test", + ":mobile_broker_runtime_test", + ":native_extensions_runtime_test", + "//build_defs/languages/installed:consumer_test", + ], +) + +source_quality_files() + +rust_quality_files() diff --git a/src/native/sdks/rust/Cargo.toml b/src/native/sdks/rust/Cargo.toml index 60716e12a..f7204a093 100644 --- a/src/native/sdks/rust/Cargo.toml +++ b/src/native/sdks/rust/Cargo.toml @@ -9,6 +9,7 @@ repository.workspace = true homepage.workspace = true license = "MIT" exclude = [ + "BUILD.bazel", ".gitignore", "crates/oliphaunt-build/**", "moon.yml", @@ -34,13 +35,13 @@ native-version = "0.3.2" [dependencies] oliphaunt-broker = { path = "../../broker", version = "0.3.1", optional = true } -liboliphaunt-native-bindings = { version = "0.2.0", path = "../../rust-bindings" } -oliphaunt-query = { version = "0.1.1", path = "../../../query/rust" } +liboliphaunt-native-bindings.workspace = true +oliphaunt-query = { version = "0.1.1" } getrandom = { version = "0.3", optional = true } libc = { version = "0.2", optional = true } [build-dependencies] -oliphaunt-build = { version = "0.3.2", path = "crates/oliphaunt-build" } +oliphaunt-build = { version = "0.3.2" } [dev-dependencies] serde = { version = "1", features = ["derive"] } diff --git a/src/native/sdks/rust/README.md b/src/native/sdks/rust/README.md index 1fa813383..31552464c 100644 --- a/src/native/sdks/rust/README.md +++ b/src/native/sdks/rust/README.md @@ -8,7 +8,7 @@ Embed native PostgreSQL in a Rust application. Use `AsyncOliphaunt` to keep an a cargo add oliphaunt ``` -The [quickstart](https://oliphaunt.dev/docs/sdk/rust) covers prerequisites and the versions documented by the current site. Pin dependencies in your application manifest or lockfile. +The [quickstart](https://oliphaunt.dev/docs/sdk/rust) covers prerequisites. Pin dependencies in your application manifest or lockfile. ## First query diff --git a/src/native/sdks/rust/crates/oliphaunt-build/BUILD.bazel b/src/native/sdks/rust/crates/oliphaunt-build/BUILD.bazel new file mode 100644 index 000000000..869f587c5 --- /dev/null +++ b/src/native/sdks/rust/crates/oliphaunt-build/BUILD.bazel @@ -0,0 +1,16 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files") +load("//build_defs/languages:rust.bzl", "cargo_doc_test", "cargo_library", "cargo_library_test", "cargo_package_env") +load("@rules_rust//rust:defs.bzl", "rust_clippy_test") +load("//build_defs/languages:source.bzl", "cargo_source_package") + +package(default_visibility = ["//visibility:public"]) +exports_files(["Cargo.toml"]) + +cargo_package_env() +cargo_library() +cargo_library_test() +cargo_doc_test(size = "small") +rust_clippy_test(name = "clippy_test", targets = [":lib", ":unit_test"], transitive = False, size = "small") +cargo_source_package(product = "oliphaunt-rust", qualification = ["//build_defs/languages/installed:consumer_test"]) + +rust_quality_files() diff --git a/src/native/sdks/rust/crates/oliphaunt-build/Cargo.toml b/src/native/sdks/rust/crates/oliphaunt-build/Cargo.toml index 3b7a59f9b..d6f321873 100644 --- a/src/native/sdks/rust/crates/oliphaunt-build/Cargo.toml +++ b/src/native/sdks/rust/crates/oliphaunt-build/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "oliphaunt-build" +exclude = ["BUILD.bazel"] version = "0.3.2" edition = "2024" rust-version = "1.93" diff --git a/src/native/sdks/rust/moon.yml b/src/native/sdks/rust/moon.yml index 666456ae9..06a8141a4 100644 --- a/src/native/sdks/rust/moon.yml +++ b/src/native/sdks/rust/moon.yml @@ -40,7 +40,10 @@ fileGroups: tasks: format: - command: "cargo fmt -p oliphaunt-build -p oliphaunt" + script: | + set -e + cargo fmt --manifest-path src/native/sdks/rust/Cargo.toml + cargo fmt --manifest-path src/native/sdks/rust/crates/oliphaunt-build/Cargo.toml options: cache: false runInCI: false @@ -50,7 +53,8 @@ tasks: tags: ["build", "requires-rust"] script: | set -e - cargo build -p oliphaunt -p oliphaunt-build --locked + cargo build --manifest-path src/native/sdks/rust/Cargo.toml --locked + cargo build --manifest-path src/native/sdks/rust/crates/oliphaunt-build/Cargo.toml --locked outputs: ["/target/debug/liboliphaunt.rlib", "/target/debug/liboliphaunt_build.rlib"] env: CARGO_TARGET_DIR: "target" @@ -76,7 +80,7 @@ tasks: fi "$CARGO_TARGET_DIR/build-script-tests" cargo test -p oliphaunt --doc --locked - cargo test -p oliphaunt-build --locked + cargo test --manifest-path src/native/sdks/rust/crates/oliphaunt-build/Cargo.toml --locked cargo nextest run -p oliphaunt --locked --profile ci --no-tests=fail --test-threads=1 env: # Cargo releases its build lock before rustdoc consumes the compiled libraries. @@ -174,13 +178,19 @@ tasks: format-check: tags: ["quality", "static", "format", "requires-rust"] - command: "cargo fmt -p oliphaunt-build -p oliphaunt --check" + script: | + set -e + cargo fmt --manifest-path src/native/sdks/rust/Cargo.toml --check + cargo fmt --manifest-path src/native/sdks/rust/crates/oliphaunt-build/Cargo.toml --check inputs: ["/src/native/sdks/rust/crates/oliphaunt-build/**/*.rs","/src/native/sdks/rust/crates/oliphaunt-build/Cargo.toml","/src/native/sdks/rust/**/*.rs","/src/native/sdks/rust/Cargo.toml","/clippy.toml","@group(cargo-workspace)"] options: runFromWorkspaceRoot: true lint: tags: ["quality", "static", "requires-rust"] - command: "cargo clippy -p oliphaunt-build -p oliphaunt --all-targets --locked -- -D warnings" + script: | + set -e + cargo clippy --manifest-path src/native/sdks/rust/Cargo.toml --all-targets --locked -- -D warnings + cargo clippy --manifest-path src/native/sdks/rust/crates/oliphaunt-build/Cargo.toml --all-targets --locked -- -D warnings env: CARGO_TARGET_DIR: "target" deps: diff --git a/src/native/sdks/rust/release.toml b/src/native/sdks/rust/release.toml index 0fdeeda4b..38db25c1d 100644 --- a/src/native/sdks/rust/release.toml +++ b/src/native/sdks/rust/release.toml @@ -33,8 +33,8 @@ parser = "toml:dependencies.oliphaunt-query.version" [compatibility_versions.rust_native_bindings] public_support = false source_product = "liboliphaunt-native-bindings" -path = "src/native/sdks/rust/Cargo.toml" -parser = "toml:dependencies.liboliphaunt-native-bindings.version" +path = "Cargo.toml" +parser = "toml:workspace.dependencies.liboliphaunt-native-bindings.version" [compatibility_versions.broker_library] public_support = false diff --git a/src/native/sdks/rust/src/direct.rs b/src/native/sdks/rust/src/direct.rs index 0faf8cfed..a6597f5c8 100644 --- a/src/native/sdks/rust/src/direct.rs +++ b/src/native/sdks/rust/src/direct.rs @@ -539,9 +539,10 @@ impl Oliphaunt { /// is terminal even if the runtime reports a failure. New cancellation /// calls are rejected at the teardown cutoff; cancellation already admitted /// before it is allowed to finish before the engine session is closed. - /// Successful teardown releases the session and storage root. A failed - /// teardown deliberately retains that native ownership until process exit - /// rather than risking a second destructive cleanup attempt. + /// Direct mode detaches the session and retains its process-resident backend + /// and storage root until process exit. Broker mode releases the session + /// and storage root after successful teardown. A failed teardown retains + /// native ownership rather than risking a second destructive cleanup attempt. pub fn close(&mut self) -> Result<()> { if let Some(result) = &self.close_result { return result.clone(); diff --git a/src/native/sdks/rust/src/test_fixtures.rs b/src/native/sdks/rust/src/test_fixtures.rs index 8c8054ffa..238478232 100644 --- a/src/native/sdks/rust/src/test_fixtures.rs +++ b/src/native/sdks/rust/src/test_fixtures.rs @@ -3,6 +3,11 @@ use std::path::{Path, PathBuf}; pub(crate) fn root() -> PathBuf { let package_root = Path::new(env!("CARGO_MANIFEST_DIR")); + let package_root = std::env::var_os("TEST_SRCDIR") + .zip(std::env::var_os("TEST_WORKSPACE")) + .filter(|_| !package_root.is_absolute()) + .map(|(root, workspace)| PathBuf::from(root).join(workspace).join(package_root)) + .unwrap_or_else(|| package_root.to_path_buf()); let packaged = package_root.join("testdata"); if packaged.is_dir() { return packaged; diff --git a/src/native/sdks/rust/tests/native_extensions.rs b/src/native/sdks/rust/tests/native_extensions.rs index fba094efc..22b2ff15a 100644 --- a/src/native/sdks/rust/tests/native_extensions.rs +++ b/src/native/sdks/rust/tests/native_extensions.rs @@ -184,18 +184,32 @@ fn native_extension_matrix_when_enabled() { eprintln!("skipping native extension matrix: set OLIPHAUNT_EXTENSION_MATRIX=1"); return; } - if native_runtime_env_is_unavailable() { - eprintln!("skipping native extension matrix: no native library env var is set"); - return; - } - let Some(broker) = option_env!("CARGO_BIN_EXE_oliphaunt-broker") else { - eprintln!("skipping native extension matrix: cargo did not provide broker binary path"); - return; - }; + assert!( + !native_runtime_env_is_unavailable(), + "enabled native extension matrix requires LIBOLIPHAUNT_PATH" + ); + let broker = std::env::var("OLIPHAUNT_BROKER") + .ok() + .or_else(|| option_env!("CARGO_BIN_EXE_oliphaunt-broker").map(str::to_owned)) + .expect("enabled native extension matrix requires an explicit or Cargo-provided broker"); + assert!( + Path::new(&broker).is_file(), + "native extension matrix broker does not exist" + ); + let names = std::env::var("OLIPHAUNT_NATIVE_EXTENSION_PROOF_SQL_NAMES") + .expect("enabled native extension matrix requires its configured SQL-name set"); + assert_eq!( + names.split(',').collect::>(), + Extension::ALL + .iter() + .map(|extension| extension.sql_name()) + .collect::>(), + "configured extension Files must cover the complete SDK catalog" + ); for extension in Extension::ALL { run_direct_extension_smoke(*extension); - run_extension_smoke(TestMode::Broker, Some(broker), *extension).unwrap(); + run_extension_smoke(TestMode::Broker, Some(&broker), *extension).unwrap(); run_extension_smoke(TestMode::Server, None, *extension).unwrap(); } } diff --git a/src/native/sdks/rust/tools/check-package.mts b/src/native/sdks/rust/tools/check-package.mts index af8297f23..b35ba5ad2 100644 --- a/src/native/sdks/rust/tools/check-package.mts +++ b/src/native/sdks/rust/tools/check-package.mts @@ -66,6 +66,7 @@ async function validateRustSdkCrate(crate) { ), 'utf8', ), + readFileSync(path.join(ROOT, 'Cargo.toml'), 'utf8'), ); const expected = Bun.TOML.parse( packageName === 'oliphaunt' ? renderReleaseCargoToml(source) : source, diff --git a/src/native/sdks/rust/tools/prepare-rust-release-source.mts b/src/native/sdks/rust/tools/prepare-rust-release-source.mts index 9d7f29645..c3f63f0f6 100644 --- a/src/native/sdks/rust/tools/prepare-rust-release-source.mts +++ b/src/native/sdks/rust/tools/prepare-rust-release-source.mts @@ -1,6 +1,7 @@ #!/usr/bin/env bun import { cpSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; import path from 'node:path'; +import { renderCargoToml } from '../../../../../tools/packaging/cargo-manifest.mts'; import { packagedCargoManifestText } from '../../../../../tools/packaging/cargo-source-package.mts'; import { assertReleaseNoticesInDirectory, @@ -8,9 +9,11 @@ import { } from '../../../../../tools/packaging/release-notices.mts'; import { assertSameNativeTargetSet, + nativeCargoPackageName, renderUnsupportedNativeTargetGuard, rustNativeTargetCfg, } from '../../../../../tools/packaging/rust-native-targets.mts'; +import { loadReleaseMetadata } from '../../../../../tools/release/bazel-release-metadata.mts'; import { allArtifactTargets, compareText, @@ -18,7 +21,6 @@ import { ROOT, registryPackageRows, } from '../../../../../tools/release/release-artifact-targets.mts'; -import { productCompatibilityVersion } from '../../../../../tools/release/release-graph.mts'; import { stageRustPackageSource } from './package-source.mts'; const TOOL = 'prepare-rust-release-source.mts'; @@ -42,19 +44,19 @@ function rel(file) { } function liboliphauntCargoPackageName(targetId, packageBase = LIBOLIPHAUNT_NATIVE_PRODUCT) { - return `${packageBase}-${targetId}`; + return nativeCargoPackageName(packageBase, targetId); } function brokerCargoPackageName(targetId) { - return `${BROKER_PRODUCT}-${targetId}`; + return nativeCargoPackageName(BROKER_PRODUCT, targetId); } -function packageSection(text) { - const parts = text.split('[package]'); - if (parts.length < 2) { +function packageVersion(text) { + const manifest = Bun.TOML.parse(text); + if (!manifest.package) { fail('generated oliphaunt release source is missing [package]'); } - return parts[1].split('\n[', 1)[0]; + return manifest.package.version; } function artifactTargets({ product, kind, surface }) { @@ -95,14 +97,20 @@ export function renderRustSdkNativeTargetGuard(nativeTargets) { export function renderReleaseCargoToml( source, - nativeVersion = productCompatibilityVersion(RUST_PRODUCT, LIBOLIPHAUNT_NATIVE_PRODUCT, TOOL), - brokerVersion = productCompatibilityVersion(RUST_PRODUCT, BROKER_PRODUCT, TOOL), + nativeVersion, + brokerVersion, artifactTargets = nativeSdkArtifactTargets(), ) { + if (nativeVersion === undefined || brokerVersion === undefined) { + const compatibility = loadReleaseMetadata(ROOT).products[RUST_PRODUCT].compatibility_versions; + nativeVersion ??= compatibility[LIBOLIPHAUNT_NATIVE_PRODUCT]; + brokerVersion ??= compatibility[BROKER_PRODUCT]; + } + if (!nativeVersion || !brokerVersion) fail('Rust SDK installed runtime/helper pins are missing'); let text = source .replace('repository.workspace = true', 'repository = "https://github.com/f0rr0/oliphaunt"') .replace('homepage.workspace = true', 'homepage = "https://oliphaunt.dev"'); - if (!text.includes('[workspace]')) { + if (Bun.TOML.parse(text).workspace === undefined) { text = `${text.trimEnd()}\n\n[workspace]\n`; } @@ -138,15 +146,21 @@ export function renderReleaseCargoToml( lines.push('', `[target.'cfg(${cfg})'.dependencies]`); lines.push(...targetDependencies.get(cfg).sort(compareText)); } - return `${text.trimEnd()}\n${lines.join('\n')}\n`; + return renderCargoToml(Bun.TOML.parse(`${text.trimEnd()}\n${lines.join('\n')}\n`)); } -function validateReleaseArtifactCoverage(manifest, nativeVersion, nativeTargets) { +function validateReleaseArtifactCoverage(text, nativeVersion, nativeTargets) { + const manifest = Bun.TOML.parse(text); + const dependencies = new Map( + [manifest, ...Object.values(manifest.target ?? {})].flatMap((table) => + Object.entries(table.dependencies ?? {}), + ), + ); const brokerCrates = registryPackageRows( { product: BROKER_PRODUCT, packageKind: 'crates' }, TOOL, ).map((row) => row.packageName); - const missingBroker = brokerCrates.filter((crate) => !manifest.includes(`${crate} = `)); + const missingBroker = brokerCrates.filter((crate) => !dependencies.has(crate)); if (missingBroker.length > 0) { fail( `generated oliphaunt release source is missing broker Cargo artifact dependencies: ${missingBroker.join(', ')}`, @@ -170,7 +184,7 @@ function validateReleaseArtifactCoverage(manifest, nativeVersion, nativeTargets) } const missingNative = nativeRuntimeCrates.filter( - (crate) => !manifest.includes(`${crate} = { version = "=${nativeVersion}" }`), + (crate) => dependencies.get(crate)?.version !== `=${nativeVersion}`, ); if (missingNative.length > 0) { fail( @@ -190,25 +204,25 @@ function releaseStageDir(stageDir) { export function prepareRustReleaseSource({ stageDir = DEFAULT_STAGE_DIR, log = true } = {}) { const version = currentProductVersionSync(RUST_PRODUCT, TOOL); - const nativeVersion = productCompatibilityVersion( - RUST_PRODUCT, - LIBOLIPHAUNT_NATIVE_PRODUCT, - TOOL, - ); - const brokerVersion = productCompatibilityVersion(RUST_PRODUCT, BROKER_PRODUCT, TOOL); + const compatibility = loadReleaseMetadata(ROOT).products[RUST_PRODUCT].compatibility_versions; + const nativeVersion = compatibility[LIBOLIPHAUNT_NATIVE_PRODUCT]; + const brokerVersion = compatibility[BROKER_PRODUCT]; const artifactTargets = nativeSdkArtifactTargets(); const outputDir = releaseStageDir(stageDir); stageRustPackageSource(outputDir); const cargoToml = path.join(outputDir, 'Cargo.toml'); const rendered = renderReleaseCargoToml( - readFileSync(cargoToml, 'utf8'), + packagedCargoManifestText( + readFileSync(cargoToml, 'utf8'), + readFileSync(path.join(ROOT, 'Cargo.toml'), 'utf8'), + ), nativeVersion, brokerVersion, artifactTargets, ); writeFileSync(cargoToml, rendered, 'utf8'); - if (!packageSection(rendered).includes(`version = "${version}"`)) { + if (packageVersion(rendered) !== version) { fail(`generated oliphaunt release source must keep SDK version ${version}`); } validateReleaseArtifactCoverage(rendered, nativeVersion, artifactTargets.nativeTargets); @@ -238,9 +252,12 @@ export function prepareOliphauntBuildReleaseSource({ filter: (source) => path.basename(source) !== 'target', }); const cargoToml = path.join(outputDir, 'Cargo.toml'); - const rendered = packagedCargoManifestText(readFileSync(cargoToml, 'utf8')); + const rendered = packagedCargoManifestText( + readFileSync(cargoToml, 'utf8'), + readFileSync(path.join(ROOT, 'Cargo.toml'), 'utf8'), + ); writeFileSync(cargoToml, rendered, 'utf8'); - if (!packageSection(rendered).includes(`version = "${version}"`)) { + if (packageVersion(rendered) !== version) { fail(`generated oliphaunt-build release source must keep SDK version ${version}`); } stageReleaseNotices(outputDir, SOURCE_NOTICE_OPTIONS); diff --git a/src/native/sdks/rust/tools/prepare-rust-release-source.test.mts b/src/native/sdks/rust/tools/prepare-rust-release-source.test.mts index 1ec1c0e66..4d82f9e01 100644 --- a/src/native/sdks/rust/tools/prepare-rust-release-source.test.mts +++ b/src/native/sdks/rust/tools/prepare-rust-release-source.test.mts @@ -8,11 +8,11 @@ import { assertReleaseNoticesInDirectory, } from '../../../../../tools/packaging/release-notices.mts'; import { rustNativeTargetCfg } from '../../../../../tools/packaging/rust-native-targets.mts'; +import { loadReleaseMetadata } from '../../../../../tools/release/bazel-release-metadata.mts'; import { allArtifactTargets, currentProductVersionSync, } from '../../../../../tools/release/release-artifact-targets.mts'; -import { productCompatibilityVersion } from '../../../../../tools/release/release-graph.mts'; const scratch = process.env.OLIPHAUNT_RUST_RELEASE_SOURCE_TEST_ROOT; if (!scratch) @@ -29,16 +29,11 @@ test('freezes the generated target-wired Rust SDK source instead of the workspac const manifestPath = path.join(root, 'source/Cargo.toml'); const manifest = readFileSync(manifestPath, 'utf8'); const source = readFileSync(path.join(root, 'source/src/lib.rs'), 'utf8'); - const nativeVersion = productCompatibilityVersion( - 'oliphaunt-rust', - 'liboliphaunt-native', - 'prepare-rust-release-source.test.mts', - ); - const brokerVersion = productCompatibilityVersion( - 'oliphaunt-rust', - 'oliphaunt-broker', - 'prepare-rust-release-source.test.mts', - ); + const checkout = path.resolve(import.meta.dir, '../../../../..'); + const compatibility = + loadReleaseMetadata(checkout).products['oliphaunt-rust'].compatibility_versions; + const nativeVersion = compatibility['liboliphaunt-native']; + const brokerVersion = compatibility['oliphaunt-broker']; const sdkVersion = currentProductVersionSync( 'oliphaunt-rust', 'prepare-rust-release-source.test.mts', @@ -55,6 +50,14 @@ test('freezes the generated target-wired Rust SDK source instead of the workspac assertReleaseNoticesInDirectory(path.join(root, 'source'), { profile: 'source-sdk' }); const parsed = Bun.TOML.parse(manifest); + const authored = Bun.TOML.parse( + readFileSync(path.join(checkout, 'src/native/sdks/rust/Cargo.toml'), 'utf8'), + ); + assert.equal( + parsed.dependencies['oliphaunt-broker'].version, + authored.dependencies['oliphaunt-broker'].version, + ); + assert.equal(parsed.dependencies['oliphaunt-broker'].path, undefined); for (const target of targets) { const cfg = rustNativeTargetCfg(target); const dependencies = parsed.target['cfg(' + cfg + ')'].dependencies; diff --git a/src/native/sdks/swift/BUILD.bazel b/src/native/sdks/swift/BUILD.bazel new file mode 100644 index 000000000..e12048edc --- /dev/null +++ b/src/native/sdks/swift/BUILD.bazel @@ -0,0 +1,194 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/apple:slices.bzl", "apple_slice_filegroup") +load("//build_defs/languages/swift:bindings.bzl", "uniffi_swift", "uniffi_output") +load("//build_defs/languages/swift:xcframework.bzl", "bindings_xcframework", "bindings_envelope") +load("//build_defs/languages/swift:source.bzl", "swift_source_package") +load("//build_defs/languages/swift:compiled-inputs-test.bzl", "swift_compiled_inputs_test") +load("//build_defs/languages/swift:consumer.bzl", "swift_package_consumer_test") +load("//build_defs/languages/swift:ios-compile.bzl", "swift_ios_compile_test") +load("@rules_cc//cc:cc_library.bzl", "cc_library") +load("@rules_swift//swift:swift_library.bzl", "swift_library") +load("@rules_swift//swift:swift_interop_hint.bzl", "swift_interop_hint") +load("@rules_swift//swift:swift_binary.bzl", "swift_binary") +load("@rules_swift//swift:swift_test.bzl", "swift_test") +load("@rules_shell//shell:sh_test.bzl", "sh_test") + +package(default_visibility = ["//visibility:public"]) + +# Package.swift's source modules and unit suite are portable to Linux. The +# packaged Apple carriers retain their narrower constraints below. +SOURCE_COMPATIBILITY = select({ + "@platforms//os:linux": [], + "@platforms//os:macos": ["@platforms//cpu:aarch64", "//build_defs/host:apple_package"], + "//conditions:default": ["@platforms//:incompatible"], +}) +exports_files(["Package.swift", "VERSION", "LIBOLIPHAUNT_VERSION", "tools/swift-native-carrier-contract.mts", "tools/native-legal-source-basis.mts", "tools/swift-xcframework-contract.mts", "tools/swift-release-manifest.mts", "tools/prepare-swift-release-consumer.mts"]) +exports_files(["tools/ios-carrier-manifest.mts"]) +exports_files(["tools/swift-source-fixture-contract.mts"]) +exports_files(["tools/swift-extension-release-consumer-inputs.mts", "tools/swift-source-carrier-contract.mts", "tools/extension-release-consumer.mts"]) +exports_files(["Tests/OliphauntTests/AsyncStringSignal.swift"]) + +filegroup(name = "broker_templates", srcs = glob(["Templates/OliphauntBroker/*"])) + +uniffi_swift( + name = "generated_bindings", + generator = "//src/native/mobile-bindings:bindgen", + library = "//src/native/mobile-bindings:lib", + configuration = "//src/native/mobile-bindings:uniffi.toml", +) +uniffi_output(name = "generated_swift", bindings = ":generated_bindings", group = "swift") +uniffi_output(name = "generated_ffi_header", bindings = ":generated_bindings", group = "header") +uniffi_output(name = "generated_ffi_modulemap", bindings = ":generated_bindings", group = "modulemap") + +swift_ios_compile_test( + name = "ios_compile_test", + sources = glob(["Sources/OliphauntCore/*.swift", "Sources/Oliphaunt/*.swift", "Sources/OliphauntBroker/*.swift", "Sources/OliphauntBrokerExtension/*.swift"]), + generated_swift = ":generated_swift", + ffi_header = ":generated_ffi_header", + ffi_modulemap = ":generated_ffi_modulemap", + c_header = "Sources/COliphaunt/include/COliphaunt.h", + c_modulemap = "Sources/COliphaunt/include/module.modulemap", + extension_template = "Templates/OliphauntBroker/OliphauntBroker.swift.template", + host_template = "Templates/OliphauntBroker/OliphauntBrokerHost.swift.template", + target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:aarch64", "//build_defs/host:apple_package"], + size = "large", + timeout = "long", + tags = ["no-remote"], +) + +bindings_xcframework( + name = "bindings_xcframework_intermediate", + library = "//src/native/mobile-bindings:static", + header = ":generated_ffi_header", +) +bindings_envelope(name = "bindings_release_assets", intermediate = ":bindings_xcframework_intermediate") +apple_slice_filegroup(name = "bindings_archive", src = ":bindings_release_assets", output_group = "archive") + +swift_source_package( + name = "source_package", + sources = glob(["Sources/**/*", "Templates/**/*", "Tests/**/*", "README.md", "CHANGELOG.md"]) + ["Package.swift", "VERSION", "LIBOLIPHAUNT_VERSION", "//:LICENSE", "//:THIRD_PARTY_NOTICES.md"], + generated_swift = ":generated_swift", + bindings_archive = ":bindings_archive", + bindings_release_assets = ":bindings_release_assets", +) +swift_compiled_inputs_test( + name = "compiled_supplier_analysis_test", + target_under_test = ":source_package_compiled_shipping_export", + bindings = ":bindings_release_assets", + target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:aarch64", "//build_defs/host:apple_package"], + size = "small", +) +filegroup(name = "generator_sources", srcs = ["tools/extension-resource-inventory.mts", "tools/render-extension-products.mts", "tools/swift-carrier-resolver.mts"]) +swift_package_consumer_test( + name = "installed_consumer_test", + archive = ":release_input_Oliphaunt-source_zip", + source_tree = ":release_input_release-tree", + bindings = ":bindings_archive", + consumer = "Tests/PublicApiConsumer/Sources/OliphauntPublicApiConsumer/main.swift", + target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:aarch64", "//build_defs/host:apple_package"], + size = "large", + timeout = "long", + tags = ["no-remote"], +) + +swift_interop_hint( + name = "bindings_ffi_module", + module_name = "OliphauntNativeBindingsFFI", + module_map = ":generated_ffi_modulemap", +) + +cc_library( + name = "bindings_ffi", + hdrs = [":generated_ffi_header"], + deps = ["//src/native/mobile-bindings:static"], + aspect_hints = [":bindings_ffi_module"], +) +swift_library( + name = "OliphauntNativeBindings", + module_name = "OliphauntNativeBindings", + package_name = "Oliphaunt", + srcs = [":generated_swift"], + deps = [":bindings_ffi"], + copts = ["-swift-version", "6"], + target_compatible_with = SOURCE_COMPATIBILITY, +) + +swift_interop_hint(name = "COliphaunt_module", module_name = "COliphaunt", module_map = "Sources/COliphaunt/include/module.modulemap") +cc_library( + name = "COliphaunt", + srcs = ["Sources/COliphaunt/link.c"], + hdrs = glob(["Sources/COliphaunt/include/*.h"]) + ["//src/native/runtime:include/oliphaunt.h"], + includes = ["Sources/COliphaunt/include"], + aspect_hints = [":COliphaunt_module"], +) + +# These are the same public modules and direct dependencies as Package.swift. +# Native source construction uses the conventional package's source tree. +MODULES = { + "OliphauntCore": [":OliphauntNativeBindings"], + "Oliphaunt": [":COliphaunt", ":OliphauntCore", ":OliphauntNativeBindings"], + "OliphauntBroker": [":OliphauntCore", ":OliphauntNativeBindings"], + "OliphauntBrokerExtension": [":Oliphaunt", ":OliphauntCore", ":OliphauntNativeBindings"], + "OliphauntExtensionSupport": [":COliphaunt", ":Oliphaunt"], +} + +[swift_library( + name = module, + module_name = module, + package_name = "Oliphaunt", + srcs = glob(["Sources/" + module + "/*.swift"]), + deps = dependencies, + copts = ["-swift-version", "6"], + features = ["swift.enable_testing"] if module in ["Oliphaunt", "OliphauntCore"] else [], + target_compatible_with = SOURCE_COMPATIBILITY, +) for module, dependencies in MODULES.items()] + +filegroup(name = "sdk_modules", srcs = [":" + module for module in MODULES] + [":OliphauntNativeBindings"]) + +# The rule's standard discovery runner supports both XCTest and Swift Testing. +# Keep the complete conventional test target, including its explicitly gated +# native-runtime suite, rather than maintaining a second list of assertions. +swift_test( + name = "unit_test", + module_name = "OliphauntTests", + package_name = "Oliphaunt", + srcs = glob(["Tests/OliphauntTests/*.swift"]), + deps = [":Oliphaunt", ":OliphauntCore"], + data = [ + "//src/test-fixtures:protocol/query-response-cases.json", + "//src/test-fixtures:protocol/structured-sql-cases.json", + "//src/test-fixtures:storage/database-root.json", + "//src/database-resources:cluster_seed_contract_fixtures", + ] + select({ + "@platforms//os:macos": ["@native_apple_sdk//:swift_test_runtime"], + "//conditions:default": [], + }), + copts = ["-swift-version", "6"], + env = {"LIBDISPATCH_COOPERATIVE_POOL_STRICT": "1"}, + target_compatible_with = SOURCE_COMPATIBILITY, + size = "small", + tags = ["no-remote"], +) + +swift_binary( + name = "public_api_consumer", + srcs = ["Tests/PublicApiConsumer/Sources/OliphauntPublicApiConsumer/main.swift"], + deps = [":Oliphaunt"], + copts = ["-parse-as-library"], + target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:aarch64", "//build_defs/host:apple_package"], +) +sh_test( + name = "public_api_consumer_test", + srcs = ["//build_defs/host:sdk-smoke.sh"], + args = ["$(location :public_api_consumer)"], + data = [":public_api_consumer"], + target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:aarch64", "//build_defs/host:apple_package"], + size = "small", +) + +source_quality_files() + +# Source-only inputs for the existing SDK package policy tests. +exports_files([ + "tools/swift-extension-fixture-consumer.mts", +], visibility = ["//visibility:public"]) diff --git a/src/native/sdks/swift/README.md b/src/native/sdks/swift/README.md index b28fbb896..2cced9f6e 100644 --- a/src/native/sdks/swift/README.md +++ b/src/native/sdks/swift/README.md @@ -4,7 +4,7 @@ Embed PostgreSQL in an iOS 17+ or macOS 14+ application using Swift 6 concurrenc ## Install -Follow the [Swift quickstart](https://oliphaunt.dev/docs/sdk/swift#install) to add the package in Xcode and link `Oliphaunt`. Pin the version shown there in your app's package resolution. +Follow the [Swift quickstart](https://oliphaunt.dev/docs/sdk/swift#install) to add the package in Xcode and link `Oliphaunt`. For new iOS databases, also add the database-resources Swift package and link `OliphauntSeedNativeIOSStandard`. The quickstart includes this required setup. diff --git a/src/native/sdks/swift/Tests/OliphauntTests/AsyncStringSignal.swift b/src/native/sdks/swift/Tests/OliphauntTests/AsyncStringSignal.swift new file mode 100644 index 000000000..180afcebe --- /dev/null +++ b/src/native/sdks/swift/Tests/OliphauntTests/AsyncStringSignal.swift @@ -0,0 +1,21 @@ +actor AsyncStringSignal { + private var result: String? + private var waiters: [CheckedContinuation] = [] + + func complete(_ value: String) { + guard result == nil else { return } + result = value + let current = waiters + waiters.removeAll() + current.forEach { $0.resume(returning: value) } + } + + func wait() async -> String { + if let result { return result } + return await withCheckedContinuation { continuation in + waiters.append(continuation) + } + } + + func current() -> String? { result } +} diff --git a/src/native/sdks/swift/Tests/OliphauntTests/OliphauntTests.swift b/src/native/sdks/swift/Tests/OliphauntTests/OliphauntTests.swift index a2ab532f9..9a387351b 100644 --- a/src/native/sdks/swift/Tests/OliphauntTests/OliphauntTests.swift +++ b/src/native/sdks/swift/Tests/OliphauntTests/OliphauntTests.swift @@ -1828,28 +1828,6 @@ private final class ChunkBox: @unchecked Sendable { } } -actor AsyncStringSignal { - private var result: String? - private var waiters: [CheckedContinuation] = [] - - func complete(_ value: String) { - guard result == nil else { return } - result = value - let current = waiters - waiters.removeAll() - current.forEach { $0.resume(returning: value) } - } - - func wait() async -> String { - if let result { return result } - return await withCheckedContinuation { continuation in - waiters.append(continuation) - } - } - - func current() -> String? { result } -} - private struct UppercaseText: Equatable, Sendable, OliphauntPostgresDecodable { let value: String @@ -1889,12 +1867,18 @@ private func requireRowsStatement( private func captureProtocolStreamCallback( _ chunk: Data, onChunk: @escaping @Sendable (Data) throws -> Void -) -> OliphauntProtocolStreamOutcome { - do { - try onChunk(chunk) - return .complete - } catch { - return .callbackAborted(error) +) async -> OliphauntProtocolStreamOutcome { + // Native callbacks arrive on foreign threads. Keep synchronous callback + // waits off Swift's cooperative executor in the session doubles as well. + await withCheckedContinuation { continuation in + Thread.detachNewThread { + do { + try onChunk(chunk) + continuation.resume(returning: .complete) + } catch { + continuation.resume(returning: .callbackAborted(error)) + } + } } } @@ -2022,7 +2006,7 @@ private actor TestSession: OliphauntSession { _ bytes: Data, onChunk: @escaping @Sendable (Data) throws -> Void ) async throws -> OliphauntProtocolStreamOutcome { - let outcome = captureProtocolStreamCallback(try await execProtocolRaw(bytes), onChunk: onChunk) + let outcome = await captureProtocolStreamCallback(try await execProtocolRaw(bytes), onChunk: onChunk) if failStreamAfterCallback { throw OliphauntError.engine("stream recovery failed") } @@ -2142,7 +2126,7 @@ private actor AdmissionOrderSession: OliphauntSession { _ bytes: Data, onChunk: @escaping @Sendable (Data) throws -> Void ) async throws -> OliphauntProtocolStreamOutcome { - captureProtocolStreamCallback(try await execProtocolRaw(bytes), onChunk: onChunk) + await captureProtocolStreamCallback(try await execProtocolRaw(bytes), onChunk: onChunk) } func backup() async throws -> Data { Data() } @@ -2252,7 +2236,7 @@ private actor SettlementBlockingSession: OliphauntSession { _ bytes: Data, onChunk: @escaping @Sendable (Data) throws -> Void ) async throws -> OliphauntProtocolStreamOutcome { - captureProtocolStreamCallback(try await execProtocolRaw(bytes), onChunk: onChunk) + await captureProtocolStreamCallback(try await execProtocolRaw(bytes), onChunk: onChunk) } func backup() async throws -> Data { Data() } diff --git a/src/native/sdks/swift/Tests/PublicApiConsumer/Sources/OliphauntPublicApiConsumer/main.swift b/src/native/sdks/swift/Tests/PublicApiConsumer/Sources/OliphauntPublicApiConsumer/main.swift index 7b1e1fe84..e40d7ca94 100644 --- a/src/native/sdks/swift/Tests/PublicApiConsumer/Sources/OliphauntPublicApiConsumer/main.swift +++ b/src/native/sdks/swift/Tests/PublicApiConsumer/Sources/OliphauntPublicApiConsumer/main.swift @@ -66,5 +66,27 @@ func compileOliphauntPublicAPI(restoreDestination: URL) async throws { @main enum OliphauntPublicApiConsumer { - static func main() {} + static func main() async throws { + guard CommandLine.arguments.count > 1 else { return } + guard CommandLine.arguments.count == 3, + ["create", "reopen"].contains(CommandLine.arguments[1]) else { + fatalError("Expected create|reopen and database directory") + } + let configuration = OliphauntConfiguration( + storage: .directory(URL(fileURLWithPath: CommandLine.arguments[2], isDirectory: true)), + username: "postgres", database: "postgres" + ) + let database = try await OliphauntDatabase.open(configuration: configuration) + if CommandLine.arguments[1] == "create" { + _ = try await database.execute("CREATE TABLE persisted(value int4 NOT NULL)") + _ = try await database.execute("INSERT INTO persisted VALUES ($1)", parameters: [.int32(42)]) + } + let result = try await database.query("SELECT value AS answer FROM persisted") + guard result.rows.count == 1, + try result.rows[0].value(named: "answer", as: Int32.self) == 42 else { + fatalError("Installed Swift SDK failed the persisted query") + } + try await database.close() + print("installed-swift-\(CommandLine.arguments[1])-42") + } } diff --git a/src/native/sdks/swift/moon.yml b/src/native/sdks/swift/moon.yml index 372761ec5..24d70c2cc 100644 --- a/src/native/sdks/swift/moon.yml +++ b/src/native/sdks/swift/moon.yml @@ -197,11 +197,15 @@ tasks: - "/src/native/sdks/swift/tools/check-package.mts" - "/src/extensions/artifacts/packages/tools/contrib-carriers.mts" - "/src/native/sdks/swift/tools/ios-carrier-manifest.mts" + - "/src/native/sdks/swift/tools/native-legal-source-basis.mts" + - "/src/native/sdks/swift/tools/swift-native-carrier-contract.mts" - "/src/native/sdks/swift/tools/pinned-native-carrier.mts" - "/tools/release/github-read.mts" - "/tools/release/github-core-request-journal.mts" - "/src/native/sdks/swift/tools/swift-carrier-resolver.mts" - "/src/native/sdks/swift/tools/render_swiftpm_release_package.mts" + - "/src/native/sdks/swift/tools/swift-release-manifest.mts" + - "/src/native/sdks/swift/tools/swift-xcframework-contract.mts" - "/src/native/sdks/swift/tools/prepare-swift-release-consumer.mts" - "/tools/release/release-graph.mts" - "/tools/packaging/staging.mts" diff --git a/src/native/sdks/swift/tools/check-package.mts b/src/native/sdks/swift/tools/check-package.mts index 7437ed42a..73aaa558c 100644 --- a/src/native/sdks/swift/tools/check-package.mts +++ b/src/native/sdks/swift/tools/check-package.mts @@ -1,39 +1,38 @@ #!/usr/bin/env bun +import { existsSync, readdirSync, readFileSync } from 'node:fs'; import path from 'node:path'; -import { ROOT, compareText } from '../../../../../tools/release/release-artifact-targets.mts'; import { - PREFIX, + bundleJavaScript, + releaseJavaScript, +} from '../../../../../tools/packaging/emit-javascript.mts'; +import { directoryNames, fail, inspectSdkProduct, isDirectory, isFile, + PREFIX, readZipEntries, rejectSdkRuntimePayload, rel, } from '../../../../../tools/packaging/release-carrier.mts'; -import { existsSync, readFileSync, readdirSync } from 'node:fs'; +import { compareText, ROOT } from '../../../../../tools/release/release-artifact-targets.mts'; +import { productCompatibilityVersion } from '../../../../../tools/release/release-graph.mts'; import { validateSelectionNeutralSwiftSourceCarrierFile, validateSwiftSourceReleaseContract, } from './swift-source-carrier-contract.mts'; -import { productCompatibilityVersion } from '../../../../../tools/release/release-graph.mts'; import { - bundleJavaScript, - releaseJavaScript, -} from '../../../../../tools/packaging/emit-javascript.mts'; + SWIFT_SOURCE_FIXTURE_PREFIX, + validateSwiftSourceFixtureEntries as validateDeclaredSwiftSourceFixtureEntries, +} from './swift-source-fixture-contract.mts'; const SWIFT_SOURCE_FIXTURE_REPOSITORY_ROOT = path.join( ROOT, 'src/native/sdks/swift/Tests/Fixtures/swiftpm-extension-resources', ); -const SWIFT_SOURCE_FIXTURE_ARCHIVE_ROOT = 'package/Tests/Fixtures/swiftpm-extension-resources'; - export function validateSwiftSourceFixtureEntries(artifact, entries) { - if (!(entries instanceof Map)) { - throw new Error(`${rel(artifact)} Swift source fixture entries must be a Map`); - } if (!isDirectory(SWIFT_SOURCE_FIXTURE_REPOSITORY_ROOT)) { throw new Error( `${rel(artifact)} cannot validate Swift source fixtures because ` + @@ -41,46 +40,16 @@ export function validateSwiftSourceFixtureEntries(artifact, entries) { ); } - const prefix = `${SWIFT_SOURCE_FIXTURE_ARCHIVE_ROOT}/`; - const expectedNames = directoryNames(SWIFT_SOURCE_FIXTURE_REPOSITORY_ROOT) - .map((name) => `${prefix}${name}`) - .sort(compareText); - const actualNames = [...entries] - .filter(([name, entry]) => name.startsWith(prefix) && entry.isFile) - .map(([name]) => name) - .sort(compareText); - if (JSON.stringify(actualNames) !== JSON.stringify(expectedNames)) { - const expected = new Set(expectedNames); - const actual = new Set(actualNames); - const missing = expectedNames.filter((name) => !actual.has(name)); - const extra = actualNames.filter((name) => !expected.has(name)); - throw new Error( - `${rel(artifact)} Swift source fixture file set must exactly match ` + - `${rel(SWIFT_SOURCE_FIXTURE_REPOSITORY_ROOT)}; missing=${JSON.stringify(missing)}, ` + - `extra=${JSON.stringify(extra)}`, - ); - } - - for (const archiveName of expectedNames) { - const repositoryName = archiveName.slice(prefix.length); - const repositoryFile = path.join( - SWIFT_SOURCE_FIXTURE_REPOSITORY_ROOT, - ...repositoryName.split('/'), - ); - const actual = Buffer.from(entries.get(archiveName).data()); - const expected = readFileSync(repositoryFile); - if (!actual.equals(expected)) { - throw new Error( - `${rel(artifact)} Swift source fixture ${archiveName} must byte-for-byte match ` + - rel(repositoryFile), - ); - } - } - - return new Set(expectedNames); + const expected = new Map( + directoryNames(SWIFT_SOURCE_FIXTURE_REPOSITORY_ROOT).map((name) => [ + `${SWIFT_SOURCE_FIXTURE_PREFIX}${name}`, + readFileSync(path.join(SWIFT_SOURCE_FIXTURE_REPOSITORY_ROOT, ...name.split('/'))), + ]), + ); + return validateDeclaredSwiftSourceFixtureEntries(rel(artifact), entries, expected); } -export async function checkSwiftPackage(root) { +export async function checkSwiftPackage(root, { nativeSourceBasis = undefined } = {}) { const product = 'oliphaunt-swift'; let checked = false; @@ -129,6 +98,7 @@ export async function checkSwiftPackage(root) { const carrier = validateSelectionNeutralSwiftSourceCarrierFile( sourceCarrier, rel(sourceCarrier), + { sourceBasis: nativeSourceBasis }, ); validateSwiftSourceReleaseContract({ carrier, @@ -139,6 +109,7 @@ export async function checkSwiftPackage(root) { ), label: `${product} staged source release`, manifestText: text, + sourceBasis: nativeSourceBasis, }); } catch (error) { fail(error instanceof Error ? error.message : String(error)); diff --git a/src/native/sdks/swift/tools/extension-release-consumer.mts b/src/native/sdks/swift/tools/extension-release-consumer.mts index ad11db76c..467e44eee 100644 --- a/src/native/sdks/swift/tools/extension-release-consumer.mts +++ b/src/native/sdks/swift/tools/extension-release-consumer.mts @@ -1,8 +1,10 @@ import path from 'node:path'; -const [command, input] = Bun.argv.slice(2); -if (command === 'write-consumer') { - const plan = JSON.parse(process.env.OLIPHAUNT_CARRIER_PLAN); - const products = JSON.parse(await Bun.file(process.env.OLIPHAUNT_EXTENSION_PRODUCTS).text()); +export function swiftExtensionReleaseConsumerFiles({ + plan, + products, + selectedPackage, + releasePackage, +}) { if (!Array.isArray(products.selected) || products.selected.length === 0) { throw new Error('generated extension package selected no products'); } @@ -86,8 +88,8 @@ if (command === 'write-consumer') { } else { throw new Error(`unknown final-link proof kind ${plan.finalLink.kind}`); } - const packagePath = JSON.stringify(path.resolve(process.env.OLIPHAUNT_SELECTED_PACKAGE)); - const releasePackagePath = JSON.stringify(path.resolve(process.env.OLIPHAUNT_RELEASE_PACKAGE)); + const packagePath = JSON.stringify(path.resolve(selectedPackage)); + const releasePackagePath = JSON.stringify(path.resolve(releasePackage)); const dependencies = [ `.product(name: "COliphaunt", package: "oliphaunt")`, `.product(name: "Oliphaunt", package: "oliphaunt")`, @@ -127,27 +129,38 @@ if (command === 'write-consumer') { `let linkedNativeRuntimeVersion = oliphaunt_version().map { String(cString: $0) }\n` + `precondition(linkedNativeRuntimeVersion == ${runtimeVersion}, "linked liboliphaunt runtime version mismatch")\n` + nativeAssertion; - await Bun.write( - path.join(process.env.OLIPHAUNT_EXTENSION_CONSUMER, 'Package.swift'), - packageFile, - ); - await Bun.write( - path.join( - process.env.OLIPHAUNT_EXTENSION_CONSUMER, - 'Sources', - 'OliphauntExtensionReleaseConsumer', - 'main.swift', - ), - main, - ); -} else { - const plan = JSON.parse(input); - const value = { - extensions: plan.extensionsCsv, - extension: plan.finalLink.nativeExtension ?? '', - kind: plan.finalLink.kind, - version: plan.finalLink.runtimeVersion, - }[command]; - if (typeof value !== 'string') throw Error('unknown Swift release consumer command'); - process.stdout.write(value); + return { packageFile, main }; +} + +if (import.meta.main) { + const [command, input] = Bun.argv.slice(2); + if (command === 'write-consumer') { + const { packageFile, main } = swiftExtensionReleaseConsumerFiles({ + plan: JSON.parse(process.env.OLIPHAUNT_CARRIER_PLAN), + products: JSON.parse(await Bun.file(process.env.OLIPHAUNT_EXTENSION_PRODUCTS).text()), + selectedPackage: process.env.OLIPHAUNT_SELECTED_PACKAGE, + releasePackage: process.env.OLIPHAUNT_RELEASE_PACKAGE, + }); + await Bun.write( + path.join(process.env.OLIPHAUNT_EXTENSION_CONSUMER, 'Package.swift'), + packageFile, + ); + await Bun.write( + path.join( + process.env.OLIPHAUNT_EXTENSION_CONSUMER, + 'Sources/OliphauntExtensionReleaseConsumer/main.swift', + ), + main, + ); + } else { + const plan = JSON.parse(input); + const value = { + extensions: plan.extensionsCsv, + extension: plan.finalLink.nativeExtension ?? '', + kind: plan.finalLink.kind, + version: plan.finalLink.runtimeVersion, + }[command]; + if (typeof value !== 'string') throw Error('unknown Swift release consumer command'); + process.stdout.write(value); + } } diff --git a/src/native/sdks/swift/tools/ios-carrier-manifest.mts b/src/native/sdks/swift/tools/ios-carrier-manifest.mts index 7ccaef4ba..d9a307ed3 100644 --- a/src/native/sdks/swift/tools/ios-carrier-manifest.mts +++ b/src/native/sdks/swift/tools/ios-carrier-manifest.mts @@ -5,33 +5,35 @@ import { existsSync, lstatSync, mkdirSync, - readFileSync, readdirSync, + readFileSync, statSync, writeFileSync, } from 'node:fs'; -import { pathToFileURL } from 'node:url'; import path from 'node:path'; - -import { ROOT, compareText, tagPrefix } from '../../../../../tools/release/release-graph.mts'; +import { pathToFileURL } from 'node:url'; +import { readPortableArchiveEntries } from '../../../../../tools/packaging/portable-archive.mts'; +import { + releaseNoticeDeclaration, + releaseNoticeRows, + releaseProfilePackageLicense, +} from '../../../../../tools/packaging/release-notices.mts'; import { currentProductVersionSync, extensionProductForSqlName, + extensionReleaseMetadataRows, extensionReleaseProductForSqlName, extensionSqlNames, } from '../../../../../tools/release/release-artifact-targets.mts'; +import { compareText, ROOT, tagPrefix } from '../../../../../tools/release/release-graph.mts'; import { extensionCarrierLegalContract, extensionUpstreamLicenseRow, } from '../../../../extensions/tools/extension-upstream-licenses.mts'; -import { readPortableArchiveEntries } from '../../../../../tools/packaging/portable-archive.mts'; -import { - releaseNoticeRows, - releaseProfilePackageLicense, -} from '../../../../../tools/packaging/release-notices.mts'; +import { nativeBaseLegalForSource } from './native-legal-source-basis.mts'; +import { IOS_CARRIER_FILENAME, IOS_CARRIER_SCHEMA } from './swift-native-carrier-contract.mts'; -export const IOS_CARRIER_SCHEMA = 'oliphaunt-react-native-ios-carrier-v1'; -export const IOS_CARRIER_FILENAME = 'oliphaunt-react-native-ios-carriers.json'; +export { IOS_CARRIER_FILENAME, IOS_CARRIER_SCHEMA }; export const SWIFT_EXTENSION_CARRIER_SCHEMA = 'oliphaunt-swift-extension-carrier-v1'; export const DEFAULT_IOS_CARRIER = path.join( ROOT, @@ -105,6 +107,53 @@ function canonicalStringList(value, label, validate = portableIdentifier) { return canonical; } +export interface DeclaredIosCarrierProduct { + product: string; + releaseProduct: string; + version: string; + sqlNames: string[]; + tag: string; +} + +function declaredProductMetadata(value): Record | undefined { + if (value === undefined) return undefined; + if (value === null || Array.isArray(value) || typeof value !== 'object') { + throw error('declaredProducts must be an object'); + } + const sqlNames = new Set(); + return Object.fromEntries( + Object.entries(value).map(([key, row]) => { + const label = `declaredProducts.${key}`; + exactObjectKeys(row, ['product', 'releaseProduct', 'version', 'sqlNames', 'tag'], label); + if (row.product !== key || !/^oliphaunt-extension-[A-Za-z0-9._-]+$/u.test(key)) { + throw error(`${label}.product must match its exact-extension product key`); + } + portableIdentifier(row.releaseProduct, `${label}.releaseProduct`); + stableVersion(row.version, `${label}.version`); + const members = canonicalStringList(row.sqlNames, `${label}.sqlNames`); + if (members.length === 0) throw error(`${label}.sqlNames must not be empty`); + for (const sqlName of members) { + if (sqlNames.has(sqlName)) throw error(`declaredProducts repeats SQL name ${sqlName}`); + sqlNames.add(sqlName); + } + if (row.tag !== `${row.releaseProduct}-v${row.version}`) { + throw error(`${label}.tag must match its release product and version`); + } + return [key, { ...row, sqlNames: members }]; + }), + ); +} + +function nativeBaseTag(version, baseTag, declaredProducts) { + if (baseTag !== undefined || declaredProducts !== undefined) { + if (baseTag !== `liboliphaunt-native-v${version}`) { + throw error('baseTag must match the explicit liboliphaunt-native version'); + } + return baseTag; + } + return `${tagPrefix('liboliphaunt-native', 'ios-carrier-manifest')}${version}`; +} + function compatibilityMetadata(value, label) { if (value === null || Array.isArray(value) || typeof value !== 'object') { throw error(`${label} must be an object`); @@ -326,8 +375,8 @@ function prefixedMember(prefix, member) { return prefix ? `${prefix}/${member}` : member; } -function canonicalLegalFileSpecs(profile, memberPrefix = '') { - return releaseNoticeRows({ profile }).map((row) => ({ +function canonicalLegalFileSpecs(profile, memberPrefix = '', sourceRoot = undefined) { + return releaseNoticeRows({ profile, sourceRoot }).map((row) => ({ bytes: statSync(row.source).size, kind: legalKind(row.member), member: prefixedMember(memberPrefix, row.member), @@ -353,17 +402,63 @@ function legalGroupShape({ assetRole, files, profile, spdx }) { * locators remain archive-relative; a consumer chooses the applicable groups * (the ICU sidecar is optional) and never needs this repository to stage them. */ -export function iosBaseLegalMetadata() { +export function iosBaseLegalMetadata({ sourceRoot = undefined } = {}) { return BASE_LEGAL_PROFILES.map(({ assetRole, memberPrefix, profile }) => legalGroupShape({ assetRole, - files: canonicalLegalFileSpecs(profile, memberPrefix), + files: canonicalLegalFileSpecs(profile, memberPrefix, sourceRoot), profile, - spdx: releaseProfilePackageLicense(profile).spdx, + spdx: releaseProfilePackageLicense(profile, { sourceRoot }).spdx, }), ); } +/** A new projection of genuine archived legal bytes. It does not claim the + * historical producer recipe or substitute current notice content. */ +export function iosBaseLegalMetadataFromArchives(archiveFiles, archiveCache = new Map()) { + const roles = Object.keys(archiveFiles).sort(compareText); + if ( + JSON.stringify(roles) !== + JSON.stringify(BASE_LEGAL_PROFILES.map(({ assetRole }) => assetRole).sort(compareText)) + ) + throw error('archived Apple base requires both exact public archive roles'); + return BASE_LEGAL_PROFILES.map(({ assetRole, memberPrefix, profile }) => { + const file = archiveFiles[assetRole].path; + const index = archiveIndex(file, archiveFormat(path.basename(file), assetRole), archiveCache, { + includeDigests: true, + }); + const declaration = releaseNoticeDeclaration(profile); + const members = declaration.members.map((member) => prefixedMember(memberPrefix, member)); + const prefix = memberPrefix ? memberPrefix + '/' : ''; + const actual = [...index.byName.values()] + .filter( + (entry) => + entry.type === 'file' && + entry.name.startsWith(prefix) && + (entry.name.slice(prefix.length) === 'LICENSE' || + entry.name.slice(prefix.length).startsWith('THIRD_PARTY_NOTICES') || + entry.name.slice(prefix.length).startsWith('THIRD_PARTY_LICENSES/')), + ) + .map((entry) => entry.name) + .sort(compareText); + if (JSON.stringify(actual) !== JSON.stringify([...members].sort(compareText))) + throw error(`${assetRole} archived legal namespace differs from its declared profile`); + return legalGroupShape({ + assetRole, + profile, + spdx: declaration.spdx, + files: members.map((member) => { + const entry = index.byName.get(member); + if (entry?.type !== 'file' || (entry.mode & 0o777) !== 0o644 || entry.size <= 0) + throw error( + `${assetRole} archived legal file must be regular, nonempty and mode0644: ${member}`, + ); + return { member, bytes: entry.size, sha256: entry.sha256, kind: legalKind(member) }; + }), + }); + }); +} + function assertLegalGroupArchiveBytes(file, format, group, archiveCache, label) { const index = archiveIndex(file, format, archiveCache, { includeDigests: true }); return legalGroupShape({ @@ -429,9 +524,13 @@ function extensionLegalGroup({ archiveCache, file, format, product, sqlName }) { ); } -function validateFrozenBaseLegalMetadata(value, label) { +function validateFrozenBaseLegalMetadata(value, label, base, sourceBasis) { if (!Array.isArray(value)) throw error(`${label} must be an array`); - const expected = iosBaseLegalMetadata(); + const expected = nativeBaseLegalForSource({ + base, + sourceBasis, + currentLegal: iosBaseLegalMetadata, + }); if (JSON.stringify(stable(value)) !== JSON.stringify(stable(expected))) { throw error(`${label} does not match the canonical native Apple legal locators`); } @@ -474,14 +573,18 @@ function carrierEnvelope({ file, tag, repository, localUrls }) { function baseCarrier({ baseAssetDir, baseRuntimeVersion, + baseTag, repository, localUrls, verifyMembers, archiveCache, + sourceBasis, + legalSourceRoot, + archiveFiles, }) { const product = 'liboliphaunt-native'; const version = stableVersion(baseRuntimeVersion, 'base runtime version'); - const tag = `${tagPrefix(product, 'ios-carrier-manifest')}${version}`; + const tag = baseTag; const rows = [ { role: 'base-xcframework', @@ -497,7 +600,7 @@ function baseCarrier({ const assets = rows.map((row) => asset({ ...row, - file: path.join(baseAssetDir, row.name), + file: archiveFiles?.[row.role]?.path ?? path.join(baseAssetDir, row.name), tag, repository, localUrls, @@ -505,12 +608,20 @@ function baseCarrier({ archiveCache, }), ); - const legal = iosBaseLegalMetadata().map((group) => { + const base = { product, version, tag, assets }; + const legal = nativeBaseLegalForSource({ + base, + sourceBasis, + currentLegal: () => + archiveFiles + ? iosBaseLegalMetadataFromArchives(archiveFiles, archiveCache) + : iosBaseLegalMetadata({ sourceRoot: legalSourceRoot }), + }).map((group) => { const selected = rows.find(({ role }) => role === group.assetRole); if (selected === undefined) throw error(`base legal group references unknown asset role ${group.assetRole}`); return assertLegalGroupArchiveBytes( - path.join(baseAssetDir, selected.name), + archiveFiles?.[selected.role]?.path ?? path.join(baseAssetDir, selected.name), archiveFormat(selected.name, `${selected.role} asset`), group, archiveCache, @@ -518,12 +629,18 @@ function baseCarrier({ ); }); return { - base: { product, version, tag, assets }, + base, legal, }; } -function frozenBaseCarrier(file, baseRuntimeVersion) { +function frozenBaseCarrier( + file, + baseRuntimeVersion, + sourceBasis, + baseTag, + expectedArchiveBase = undefined, +) { let manifest; try { manifest = JSON.parse( @@ -536,7 +653,7 @@ function frozenBaseCarrier(file, baseRuntimeVersion) { const legal = manifest?.schema === IOS_CARRIER_SCHEMA ? manifest.legal?.base : manifest?.legal; const product = 'liboliphaunt-native'; const version = stableVersion(baseRuntimeVersion, 'base runtime version'); - const tag = `${tagPrefix(product, 'ios-carrier-manifest')}${version}`; + const tag = baseTag; if ( base?.product !== product || base.version !== version || @@ -569,9 +686,17 @@ function frozenBaseCarrier(file, baseRuntimeVersion) { throw error(`${file} base asset ${index} name does not match its archive format`); } } + if (expectedArchiveBase) { + if ( + JSON.stringify(stable(base)) !== JSON.stringify(stable(expectedArchiveBase.base)) || + JSON.stringify(stable(legal)) !== JSON.stringify(stable(expectedArchiveBase.legal)) + ) + throw error(`${file} does not match its exact declared public archives/legal bytes`); + return expectedArchiveBase; + } return { base: stable(base), - legal: validateFrozenBaseLegalMetadata(legal, `${file} base legal metadata`), + legal: validateFrozenBaseLegalMetadata(legal, `${file} base legal metadata`, base, sourceBasis), }; } @@ -623,6 +748,7 @@ function extensionCarrier( manifestPath, { aggregateCarriers, + assetRoot, artifactProduct, repository, localUrls, @@ -698,7 +824,7 @@ function extensionCarrier( } const carriers = new Map(); const rows = iOS.map((row) => { - const file = path.resolve(ROOT, row.path); + const file = path.resolve(assetRoot, row.path); requireFile(file, `${manifest.product} ${row.kind}`); const logicalName = portableAssetName(row.name, `${manifest.product} ${row.kind} name`); const logicalFormat = archiveFormat(logicalName, `${manifest.product} ${row.kind}`); @@ -767,7 +893,7 @@ function extensionCarrier( const assets = rows .map(({ row, logicalFormat, envelope, role, member, memberPath }) => { if (verifyMembers) - verifyMember(path.resolve(ROOT, row.path), logicalFormat, member, archiveCache); + verifyMember(path.resolve(assetRoot, row.path), logicalFormat, member, archiveCache); return { role, carrier: envelope.name, @@ -829,7 +955,7 @@ function extensionCarrier( includeLegal !== false ? extensionLegalGroup({ archiveCache, - file: path.resolve(ROOT, runtimeRow.row.path), + file: path.resolve(assetRoot, runtimeRow.row.path), format: runtimeRow.logicalFormat, product: artifactProduct, sqlName, @@ -901,14 +1027,18 @@ function extensionArtifactDocument(manifestPath) { throw error(`${manifestPath} has unsupported exact-extension CI artifact schema`); } -function aggregateCarrierMap(document, manifestPath, { repository, localUrls, release }) { +function aggregateCarrierMap( + document, + manifestPath, + { assetRoot, repository, localUrls, release, expectedSqlNames }, +) { if (document.schema === 'oliphaunt-extension-ci-artifacts-v1') return new Map(); if (!Array.isArray(document.carrierAssets) || document.carrierAssets.length === 0) { throw error(`${manifestPath} bundle manifest must declare aggregate carrierAssets`); } const result = new Map(); const groups = new Set(); - const expectedMemberCount = extensionSqlNames(document.product, 'ios-carrier-manifest').length; + const expectedMemberCount = expectedSqlNames.length; for (const [index, row] of document.carrierAssets.entries()) { if ( row === null || @@ -929,7 +1059,10 @@ function aggregateCarrierMap(document, manifestPath, { repository, localUrls, re throw error(`${manifestPath}.carrierAssets[${index}] is not an exact aggregate carrier row`); } const name = portableAssetName(row.name, `${manifestPath}.carrierAssets[${index}].name`); - const file = requireFile(path.resolve(ROOT, row.path), `${document.product} aggregate carrier`); + const file = requireFile( + path.resolve(assetRoot, row.path), + `${document.product} aggregate carrier`, + ); if ( path.basename(file) !== name || statSync(file).size !== row.bytes || @@ -955,19 +1088,41 @@ function aggregateCarrierMap(document, manifestPath, { repository, localUrls, re function extensionCarriers(manifestPath, options) { const document = extensionArtifactDocument(manifestPath); stableVersion(document.version, `${document.product} version`); - const releaseProducts = new Set( - document.rows.map((row) => - extensionReleaseProductForSqlName(row.sqlName, 'native', 'ios-carrier-manifest'), - ), - ); - if (releaseProducts.size !== 1) { - throw error(`${manifestPath} members do not share one native release owner`); + const declared = + options.declaredProducts === undefined + ? undefined + : Object.hasOwn(options.declaredProducts, document.product) + ? options.declaredProducts[document.product] + : undefined; + if (options.declaredProducts !== undefined && declared === undefined) { + throw error(`${manifestPath} product ${document.product} is not in declaredProducts`); } - const releaseProduct = [...releaseProducts][0]; - const expectedReleaseVersion = currentProductVersionSync(releaseProduct, 'ios-carrier-manifest'); + let release; + let expectedSqlNames; + if (declared === undefined) { + const releaseProducts = new Set( + document.rows.map((row) => + extensionReleaseProductForSqlName(row.sqlName, 'native', 'ios-carrier-manifest'), + ), + ); + if (releaseProducts.size !== 1) { + throw error(`${manifestPath} members do not share one native release owner`); + } + const releaseProduct = [...releaseProducts][0]; + release = { + product: releaseProduct, + tag: `${tagPrefix(releaseProduct, 'ios-carrier-manifest')}${document.version}`, + version: currentProductVersionSync(releaseProduct, 'ios-carrier-manifest'), + }; + expectedSqlNames = extensionSqlNames(document.product, 'ios-carrier-manifest'); + } else { + release = { product: declared.releaseProduct, tag: declared.tag, version: declared.version }; + expectedSqlNames = declared.sqlNames; + } + const expectedReleaseVersion = release.version; if (document.version !== expectedReleaseVersion) { throw error( - `${manifestPath} version ${document.version} does not match ${releaseProduct} ${expectedReleaseVersion}`, + `${manifestPath} version ${document.version} does not match ${release.product} ${expectedReleaseVersion}`, ); } if (options.nativeRuntimeVersion !== undefined) { @@ -982,12 +1137,11 @@ function extensionCarriers(manifestPath, options) { ); } } - const release = { - product: releaseProduct, - tag: `${tagPrefix(releaseProduct, 'ios-carrier-manifest')}${document.version}`, - version: document.version, - }; - const aggregateCarriers = aggregateCarrierMap(document, manifestPath, { ...options, release }); + const aggregateCarriers = aggregateCarrierMap(document, manifestPath, { + ...options, + expectedSqlNames, + release, + }); const built = document.rows.map((row) => extensionCarrier(row, manifestPath, { ...options, @@ -1007,12 +1161,16 @@ function extensionCarriers(manifestPath, options) { throw error(`${manifestPath} repeats an extension SQL name`); } const actualSqlNames = rows.map(({ sqlName }) => sqlName).sort(compareText); - const expectedSqlNames = extensionSqlNames(document.product, 'ios-carrier-manifest'); if (JSON.stringify(actualSqlNames) !== JSON.stringify(expectedSqlNames)) { throw error( `${manifestPath} does not contain the exact ${document.product} extension member set`, ); } + if (options.declaredProducts !== undefined) { + for (const sqlName of rows.flatMap(({ dependencies }) => dependencies)) { + dependencyCarrierReference(sqlName, options.declaredProducts); + } + } const carriers = new Map(); for (const carrier of built.flatMap((row) => row.carriers)) { const existing = carriers.get(carrier.name); @@ -1035,10 +1193,25 @@ export function swiftExtensionCarrierAssetName(product, version) { throw error(`invalid exact-extension product ${product}`); } stableVersion(version, `${product} version`); - return `${product}-${version}-swift-extension-carrier.json`; + return extensionReleaseMetadataRows({ id: product, version }, 'native').find( + ([kind]) => kind === 'swift-extension-carrier', + )[1]; } -function dependencyCarrierReference(sqlName) { +function dependencyCarrierReference(sqlName, declaredProducts = undefined) { + if (declaredProducts !== undefined) { + const declared = Object.values(declaredProducts).find((row) => row.sqlNames.includes(sqlName)); + if (declared === undefined) { + throw error(`dependency SQL name ${sqlName} is not in declaredProducts`); + } + return { + product: declared.product, + releaseProduct: declared.releaseProduct, + sqlName, + tag: declared.tag, + version: declared.version, + }; + } const product = extensionProductForSqlName(sqlName, 'ios-carrier-manifest'); const releaseProduct = extensionReleaseProductForSqlName( sqlName, @@ -1063,17 +1236,26 @@ function dependencyCarrierReference(sqlName) { export function buildSwiftExtensionCarrierManifest({ extensionManifest, nativeRuntimeVersion = undefined, + declaredProducts = undefined, + baseTag = undefined, + assetRoot = ROOT, repository = DEFAULT_REPOSITORY, localUrls = false, verifyMembers = true, } = {}) { validateRepository(repository); + if (typeof assetRoot !== 'string' || assetRoot.length === 0) { + throw error('assetRoot must be a non-empty path'); + } + declaredProducts = declaredProductMetadata(declaredProducts); if (typeof extensionManifest !== 'string' || extensionManifest.length === 0) { throw error('extensionManifest must be an exact-extension CI artifact manifest path'); } const archiveCache = new Map(); const resolved = extensionCarriers(path.resolve(extensionManifest), { archiveCache, + assetRoot: path.resolve(assetRoot), + declaredProducts, includeLegal: false, repository, localUrls, @@ -1087,12 +1269,14 @@ export function buildSwiftExtensionCarrierManifest({ release, base: { product: 'liboliphaunt-native', - tag: `${tagPrefix('liboliphaunt-native', 'ios-carrier-manifest')}${version}`, + tag: nativeBaseTag(version, baseTag, declaredProducts), version, }, carriers, entries: rows.map((extension) => ({ - dependencyCarriers: extension.dependencies.map(dependencyCarrierReference), + dependencyCarriers: extension.dependencies.map((sqlName) => + dependencyCarrierReference(sqlName, declaredProducts), + ), extension, })), }); @@ -1126,30 +1310,87 @@ export function discoveredExtensionManifests(root) { export function buildIosCarrierManifest({ baseAssetDir = path.join(ROOT, 'target/liboliphaunt/release-assets'), - baseRuntimeVersion = currentProductVersionSync('liboliphaunt-native', 'ios-carrier-manifest'), + baseRuntimeVersion = undefined, + declaredProducts = undefined, + baseTag = undefined, + assetRoot = ROOT, baseCarrierManifest = undefined, extensionManifests = [], repository = DEFAULT_REPOSITORY, localUrls = false, verifyMembers = true, + baseSourceBasis = undefined, + baseLegalSourceRoot = undefined, + baseArchiveInputs = undefined, } = {}) { validateRepository(repository); + if (typeof assetRoot !== 'string' || assetRoot.length === 0) { + throw error('assetRoot must be a non-empty path'); + } + declaredProducts = declaredProductMetadata(declaredProducts); + if (baseRuntimeVersion === undefined && declaredProducts === undefined) { + baseRuntimeVersion = currentProductVersionSync('liboliphaunt-native', 'ios-carrier-manifest'); + } + stableVersion(baseRuntimeVersion, 'base runtime version'); + baseTag = nativeBaseTag(baseRuntimeVersion, baseTag, declaredProducts); const archiveCache = new Map(); + let archiveBase; + if (baseArchiveInputs !== undefined) { + archiveBase = baseCarrier({ + baseAssetDir, + baseRuntimeVersion, + baseTag, + repository, + localUrls, + verifyMembers, + archiveCache, + archiveFiles: baseArchiveInputs, + }); + for (const asset of archiveBase.base.assets) { + const file = baseArchiveInputs[asset.role]; + const expectedName = + asset.role === 'base-xcframework' + ? `liboliphaunt-${baseRuntimeVersion}-apple-spm-xcframework.zip` + : `liboliphaunt-${baseRuntimeVersion}-runtime-resources-ios-datum64.tar.gz`; + if ( + !file || + asset.name !== expectedName || + path.basename(file.path) !== expectedName || + asset.bytes !== file.size || + asset.sha256 !== file.sha256 + ) + throw error( + `declared completed Apple archive identity differs: ${asset.role}/${asset.name}`, + ); + } + } const frozenBase = baseCarrierManifest === undefined - ? baseCarrier({ + ? (archiveBase ?? + baseCarrier({ archiveCache, baseAssetDir: path.resolve(baseAssetDir), baseRuntimeVersion, + baseTag, repository, localUrls, verifyMembers, - }) - : frozenBaseCarrier(baseCarrierManifest, baseRuntimeVersion); + sourceBasis: baseSourceBasis, + legalSourceRoot: baseLegalSourceRoot, + })) + : frozenBaseCarrier( + baseCarrierManifest, + baseRuntimeVersion, + baseSourceBasis, + baseTag, + archiveBase, + ); const { base, legal: baseLegal } = frozenBase; const documents = extensionManifests.map((file) => { const document = extensionCarriers(path.resolve(file), { archiveCache, + assetRoot: path.resolve(assetRoot), + declaredProducts, repository, localUrls, verifyMembers, diff --git a/src/native/sdks/swift/tools/ios-carrier-manifest.test.mts b/src/native/sdks/swift/tools/ios-carrier-manifest.test.mts index b9fb1cc61..ffc7cad1c 100644 --- a/src/native/sdks/swift/tools/ios-carrier-manifest.test.mts +++ b/src/native/sdks/swift/tools/ios-carrier-manifest.test.mts @@ -14,6 +14,7 @@ import { writeFileSync, } from 'node:fs'; import path from 'node:path'; +import { tmpdir } from 'node:os'; import test from 'node:test'; import { archiveDirectory } from '../../../../../tools/packaging/archive-directory.mts'; import { stageReleaseNotices } from '../../../../../tools/packaging/release-notices.mts'; @@ -29,6 +30,8 @@ import { buildSwiftExtensionCarrierManifest, discoveredExtensionManifests, swiftExtensionCarrierAssetName, + writeIosCarrierManifest, + writeSwiftExtensionCarrierManifest, } from './ios-carrier-manifest.mts'; const ROOT = path.resolve(import.meta.dir, '../../../../..'); @@ -136,6 +139,172 @@ function writeManifest(root, product, body) { return file; } +test('declared product metadata freezes explicit Apple identities and dependencies', async () => { + const root = mkdtempSync(path.join(tmpdir(), 'ios-declared-carrier-test-')); + const nativeVersion = '9.0.0'; + const product = 'oliphaunt-extension-pgtap'; + const version = '9.1.0'; + const declaredProducts = { + [product]: { + product, + releaseProduct: product, + version, + sqlNames: ['pgtap'], + tag: `${product}-v${version}`, + }, + 'oliphaunt-extension-vector': { + product: 'oliphaunt-extension-vector', + releaseProduct: 'oliphaunt-extension-vector', + version: '9.2.0', + sqlNames: ['vector'], + tag: 'oliphaunt-extension-vector-v9.2.0', + }, + }; + const baseTag = `liboliphaunt-native-v${nativeVersion}`; + try { + await archive( + root, + `liboliphaunt-${nativeVersion}-apple-spm-xcframework.zip`, + 'liboliphaunt.xcframework', + 'zip', + { insideMember: true, profile: 'native-runtime' }, + ); + await archive( + root, + `liboliphaunt-${nativeVersion}-runtime-resources-ios-datum64.tar.gz`, + 'oliphaunt', + 'tar.gz', + { insideMember: false, profile: 'native-runtime-resources' }, + ); + const runtime = await archive(root, 'pgtap-runtime.tar.gz', 'oliphaunt', 'tar.gz', { + insideMember: false, + profile: 'external-native', + sqlName: 'pgtap', + }); + const extensionManifest = writeManifest(root, product, { + version, + compatibility: compatibility(nativeVersion), + sqlName: 'pgtap', + dependencies: ['vector'], + nativeModuleStem: null, + iosNativeDependencies: [], + iosRegistration: null, + assets: [{ ...assetRow(runtime, 'runtime'), path: path.basename(runtime) }], + }); + const swiftOptions = { + extensionManifest, + nativeRuntimeVersion: nativeVersion, + declaredProducts, + baseTag, + assetRoot: root, + }; + const swift = writeSwiftExtensionCarrierManifest(path.join(root, 'swift.json'), swiftOptions); + assert.deepEqual(swift.release, { product, tag: `${product}-v${version}`, version }); + assert.deepEqual(swift.base, { + product: 'liboliphaunt-native', + tag: baseTag, + version: nativeVersion, + }); + assert.deepEqual(swift.entries[0].dependencyCarriers, [ + { + product: 'oliphaunt-extension-vector', + releaseProduct: 'oliphaunt-extension-vector', + sqlName: 'vector', + tag: 'oliphaunt-extension-vector-v9.2.0', + version: '9.2.0', + }, + ]); + assert.ok(swift.carriers.every(({ url }) => url.includes(`/${product}-v${version}/`))); + const iosOptions = { + baseAssetDir: root, + baseRuntimeVersion: nativeVersion, + extensionManifests: [extensionManifest], + declaredProducts, + baseTag, + assetRoot: root, + }; + const ios = writeIosCarrierManifest(path.join(root, 'ios.json'), iosOptions); + assert.equal(ios.base.tag, baseTag); + assert.equal(ios.extensions[0].version, version); + assert.ok(ios.legal.extensions[0].files.length > 0); + assert.deepEqual(JSON.parse(readFileSync(path.join(root, 'ios.json'), 'utf8')), ios); + assert.deepEqual(JSON.parse(readFileSync(path.join(root, 'swift.json'), 'utf8')), swift); + assert.deepEqual( + buildIosCarrierManifest({ + ...iosOptions, + baseCarrierManifest: path.join(root, 'ios.json'), + }), + ios, + ); + assert.throws( + () => buildSwiftExtensionCarrierManifest({ ...swiftOptions, declaredProducts: {} }), + /not in declaredProducts/u, + ); + assert.throws( + () => + buildSwiftExtensionCarrierManifest({ + ...swiftOptions, + declaredProducts: { [product]: declaredProducts[product] }, + }), + /dependency SQL name vector is not in declaredProducts/u, + ); + assert.throws( + () => buildSwiftExtensionCarrierManifest({ ...swiftOptions, baseTag: undefined }), + /baseTag/u, + ); + assert.throws( + () => buildIosCarrierManifest({ ...iosOptions, baseRuntimeVersion: undefined }), + /base runtime version/u, + ); + assert.throws( + () => + buildSwiftExtensionCarrierManifest({ + ...swiftOptions, + declaredProducts: { + [product]: { ...declaredProducts[product], tag: `${product}-v9.3.0` }, + }, + }), + /tag must match/u, + ); + assert.throws( + () => + buildSwiftExtensionCarrierManifest({ + ...swiftOptions, + declaredProducts: { + [product]: { ...declaredProducts[product], unexpected: true }, + }, + }), + /fields must be exactly/u, + ); + assert.throws( + () => + buildSwiftExtensionCarrierManifest({ + ...swiftOptions, + declaredProducts: { + ...declaredProducts, + 'oliphaunt-extension-vector': { + ...declaredProducts['oliphaunt-extension-vector'], + sqlNames: ['pgtap'], + }, + }, + }), + /repeats SQL name pgtap/u, + ); + assert.throws( + () => + buildSwiftExtensionCarrierManifest({ + ...swiftOptions, + declaredProducts: { + [product]: { ...declaredProducts[product], sqlNames: ['pgtap', 'pgtap'] }, + }, + }), + /must not contain duplicates/u, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + test('an independently pinned base carrier uses the pinned release and rejects current runtime assets', async () => { mkdirSync(path.join(ROOT, 'target'), { recursive: true }); const root = mkdtempSync(path.join(ROOT, 'target', 'ios-pinned-carrier-test-')); @@ -593,6 +762,45 @@ test('bundle carriers verify exact nested bytes ', async () => { ), ); + const declaredProduct = 'oliphaunt-extension-declared'; + const declaredVersion = '9.1.0'; + const declaredFile = path.join(root, 'declared-artifacts.json'); + const declaredDocument = JSON.parse(readFileSync(manifestFile, 'utf8')); + declaredDocument.product = declaredProduct; + declaredDocument.version = declaredVersion; + declaredDocument.extensions = declaredDocument.extensions.slice(0, 1); + for (const asset of declaredDocument.extensions[0].assets) { + asset.path = path.relative(root, path.resolve(ROOT, asset.path)); + } + declaredDocument.carrierAssets[0].path = path.relative(root, carrierFile); + declaredDocument.carrierAssets[0].memberCount = 1; + writeFileSync(declaredFile, JSON.stringify(declaredDocument)); + const declaredOptions = { + extensionManifest: declaredFile, + nativeRuntimeVersion: declaredDocument.compatibility.nativeRuntimeVersion, + baseTag: `liboliphaunt-native-v${declaredDocument.compatibility.nativeRuntimeVersion}`, + assetRoot: root, + declaredProducts: { + [declaredProduct]: { + product: declaredProduct, + releaseProduct: declaredProduct, + version: declaredVersion, + sqlNames: [sqlNames[0]], + tag: `${declaredProduct}-v${declaredVersion}`, + }, + }, + }; + const declaredCarrier = buildSwiftExtensionCarrierManifest(declaredOptions); + assert.equal(declaredCarrier.entries.length, 1); + assert.equal(declaredCarrier.entries[0].extension.product, declaredProduct); + assert.equal(declaredCarrier.release.version, declaredVersion); + declaredDocument.carrierAssets[0].memberCount = sqlNames.length; + writeFileSync(declaredFile, JSON.stringify(declaredDocument)); + assert.throws( + () => buildSwiftExtensionCarrierManifest(declaredOptions), + /not an exact aggregate carrier row/u, + ); + const tampered = path.join( carrierStage, 'extensions', diff --git a/src/native/sdks/swift/tools/native-legal-source-basis.mts b/src/native/sdks/swift/tools/native-legal-source-basis.mts new file mode 100644 index 000000000..6fe6b0272 --- /dev/null +++ b/src/native/sdks/swift/tools/native-legal-source-basis.mts @@ -0,0 +1,297 @@ +import { createHash } from 'node:crypto'; +import { isDeepStrictEqual } from 'node:util'; +import type { CompletedPublication } from '../../../../../tools/release/completed-release-publication.mts'; +import { validateFrozenNativeCarrierIdentity } from './swift-native-carrier-contract.mts'; + +const repository = 'f0rr0/oliphaunt'; +const nativeProduct = 'liboliphaunt-native'; +const swiftProduct = 'oliphaunt-swift'; +const sourceMember = 'src/sdks/swift/Carriers/oliphaunt-react-native-ios-carriers.json'; +const sha = /^[0-9a-f]{40}$/u; +const versionPattern = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u; + +export const currentNativeLegalSourceBasis = Object.freeze({ kind: 'current-source' as const }); + +export interface PublishedNativeLegalSourceBasis { + kind: 'completed-publication'; + publication: CompletedPublication; + sourcePublication: CompletedPublication; + source: { commit: string; tree: string; member: string; blob: string }; + assets: readonly { assetId: number; name: string; sha256: string; size: number }[]; +} + +export type NativeLegalSourceBasis = + | typeof currentNativeLegalSourceBasis + | PublishedNativeLegalSourceBasis; + +// A held basis has an explicit trusted capture boundary. Consumers cannot use +// their incoming manifest, or a serialized basis, as its own expected policy. +const authenticated = new WeakMap(); + +function error(message: string) { + return new Error(`native legal source basis: ${message}`); +} + +function checkedCompletion(value, product, version, release): CompletedPublication { + if ( + value?.product !== product || + value.version !== version || + value.tagName !== release.tag_name || + value.publicationSha !== release.target_commitish || + ![value.publicationSha, value.publicationTree, value.releaseSha].every((value) => + sha.test(value), + ) + ) + throw error(`${product}@${version} completion differs from its public release`); + return value; +} + +/** + * Resolve before construction/admission, outside cacheable actions. Reads are + * pinned to completed releases and their immutable Git objects. The source-tag + * carrier supplies its historical policy and member names; current policy is + * never substituted for that independently published declaration. + */ +export async function createPublishedNativeLegalSourceBasis({ + nativeVersion, + swiftVersion, + readJson = undefined, + readPages = undefined, + assertCompletedPublication = undefined, +}: { + nativeVersion: string; + swiftVersion: string; + readJson?: (endpoint: string) => Promise; + readPages?: (endpoint: string, options?: any) => Promise; + assertCompletedPublication?: (identity: { + product: string; + version: string; + publicationSha: string; + tagName: string; + }) => Promise; +}): Promise { + if (!versionPattern.test(nativeVersion) || !versionPattern.test(swiftVersion)) + throw error('published source and native versions must be exact stable versions'); + if (!readJson || !readPages) { + const github = await import('../../../../../tools/release/github-read.mts'); + readJson ??= github.requestGithubRepositoryJson; + readPages ??= github.requestGithubPages; + } + // Completion and source acquisition observe the same release snapshot. + const transport = readJson; + if (!transport || !readPages) + throw error('published acquisition requires GitHub read transports'); + const reads = new Map>(); + const read = (endpoint: string) => { + let result = reads.get(endpoint); + if (!result) { + result = transport(endpoint); + reads.set(endpoint, result); + } + return result; + }; + if (!assertCompletedPublication) { + const { createCompletedPublicationChecker } = await import( + '../../../../../tools/release/completed-release-publication.mts' + ); + assertCompletedPublication = createCompletedPublicationChecker({ + repository, + readJson: read, + readPages, + }); + } + const assertCompletion = assertCompletedPublication; + if (!assertCompletion) + throw error('published acquisition requires completed-publication verification'); + const complete = async (product: string, version: string) => { + const tagName = `${product}-v${version}`; + const release = await read(`repos/${repository}/releases/tags/${tagName}`); + if ( + release?.tag_name !== tagName || + release.draft !== false || + release.prerelease !== false || + !sha.test(release.target_commitish) || + !Number.isSafeInteger(release.id) || + release.id <= 0 + ) + throw error(`${product}@${version} requires an exact stable public release`); + const publication = checkedCompletion( + await assertCompletion({ + product, + version, + publicationSha: release.target_commitish, + tagName, + }), + product, + version, + release, + ); + return { publication, release }; + }; + const [native, swift] = await Promise.all([ + complete(nativeProduct, nativeVersion), + complete(swiftProduct, swiftVersion), + ]); + const reference = await read(`repos/${repository}/git/ref/tags/${swiftVersion}`); + if ( + reference?.ref !== `refs/tags/${swiftVersion}` || + reference.object?.type !== 'commit' || + !sha.test(reference.object.sha) + ) + throw error('published Swift source requires its exact lightweight source tag'); + const commit = await read(`repos/${repository}/git/commits/${reference.object.sha}`); + if (commit?.sha !== reference.object.sha) + throw error('published Swift source differs from its exact tag'); + const contents = await read(`repos/${repository}/contents/${sourceMember}?ref=${commit.sha}`); + const assets = await readPages(`repos/${repository}/releases/${native.release.id}/assets`, { + label: 'held native base assets', + }); + return createCapturedPublishedNativeLegalSourceBasis({ + publication: native.publication, + nativeRelease: native.release, + sourcePublication: swift.publication, + sourceReference: reference, + sourceCommit: commit, + carrierContents: contents, + nativeAssets: assets, + }); +} + +/** + * Bind independently captured facts that the caller has authenticated through + * the completed-publication checker and immutable Git/API source acquisition. + * Repository imports declare those captures as inputs; this function performs + * no network reads and does not authenticate arbitrary JSON receipts. + */ +export function createCapturedPublishedNativeLegalSourceBasis({ + publication, + nativeRelease, + sourcePublication, + sourceReference: reference, + sourceCommit: commit, + carrierContents: contents, + nativeAssets: rows, +}: { + publication: CompletedPublication; + nativeRelease: any; + sourcePublication: CompletedPublication; + sourceReference: any; + sourceCommit: any; + carrierContents: any; + nativeAssets: any[]; +}): PublishedNativeLegalSourceBasis { + if ( + !versionPattern.test(publication?.version) || + nativeRelease?.tag_name !== `${nativeProduct}-v${publication.version}` || + nativeRelease.draft !== false || + nativeRelease.prerelease !== false || + !Number.isSafeInteger(nativeRelease.id) || + nativeRelease.id <= 0 + ) + throw error('captured native facts require an exact stable public release'); + checkedCompletion(publication, nativeProduct, publication.version, nativeRelease); + if ( + sourcePublication?.product !== swiftProduct || + !versionPattern.test(sourcePublication.version) || + sourcePublication.tagName !== `${swiftProduct}-v${sourcePublication.version}` || + ![ + sourcePublication.publicationSha, + sourcePublication.publicationTree, + sourcePublication.releaseSha, + ].every((value) => sha.test(value)) + ) + throw error('captured Swift source requires verified completed publication facts'); + if ( + reference?.ref !== `refs/tags/${sourcePublication.version}` || + reference.object?.type !== 'commit' || + !sha.test(reference.object.sha) || + commit?.sha !== reference.object.sha || + !sha.test(commit.tree?.sha) || + commit.parents?.length !== 1 || + commit.parents[0].sha !== sourcePublication.publicationSha + ) + throw error('published Swift source does not bind the completed publication parent'); + if ( + contents?.path !== sourceMember || + contents.type !== 'file' || + contents.encoding !== 'base64' || + typeof contents.content !== 'string' || + !sha.test(contents.sha) + ) + throw error('published Swift source has no exact carrier member'); + const bytes = Buffer.from(contents.content, 'base64'); + if ( + bytes.length === 0 || + bytes.length > 1024 * 1024 || + createHash('sha1').update(`blob ${bytes.length}\0`).update(bytes).digest('hex') !== contents.sha + ) + throw error('published Swift carrier bytes differ from their immutable Git blob'); + const carrier = validateFrozenNativeCarrierIdentity({ + carrier: JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes)), + expectedNativeVersion: publication.version, + }); + if (!Array.isArray(rows)) throw error('published native release has no asset inventory'); + const assets = carrier.base.assets.map((asset) => { + const matches = rows.filter((row) => row.name === asset.name); + const row = matches[0]; + if ( + matches.length !== 1 || + !Number.isSafeInteger(row.id) || + row.id <= 0 || + row.browser_download_url !== asset.url || + row.digest !== `sha256:${asset.sha256}` || + row.size !== asset.bytes || + asset.bytes > 512 * 1024 * 1024 + ) + throw error(`published native asset differs from immutable source: ${asset.name}`); + return Object.freeze({ + assetId: row.id, + name: asset.name, + sha256: asset.sha256, + size: asset.bytes, + }); + }); + if (new Set(assets.map(({ assetId }) => assetId)).size !== assets.length) + throw error('published native base repeats an asset identity'); + const basis = Object.freeze({ + kind: 'completed-publication' as const, + publication: Object.freeze({ ...publication }), + sourcePublication: Object.freeze({ ...sourcePublication }), + source: Object.freeze({ + commit: commit.sha, + tree: commit.tree.sha, + member: sourceMember, + blob: contents.sha, + }), + assets: Object.freeze(assets), + }); + authenticated.set(basis, { + base: JSON.parse(JSON.stringify(carrier.base)), + legal: JSON.parse(JSON.stringify(carrier.legal.base)), + }); + return basis; +} + +/** Match the full independently authenticated base, not its version alone. */ +export function nativeBaseLegalForSource({ + base, + sourceBasis, + currentLegal, +}: { + base: unknown; + sourceBasis?: NativeLegalSourceBasis; + currentLegal: () => unknown; +}) { + if (sourceBasis === undefined || sourceBasis.kind === 'current-source') return currentLegal(); + const held = authenticated.get(sourceBasis); + if (!held) throw error('held native legal requires an authenticated published source basis'); + if (!isDeepStrictEqual(base, held.base)) + throw error('native base differs from the authenticated publication assets'); + return JSON.parse(JSON.stringify(held.legal)); +} + +export function publishedNativeBaseForSource(sourceBasis: NativeLegalSourceBasis) { + const held = authenticated.get(sourceBasis); + if (!held) throw error('held native assets require an authenticated published source basis'); + return JSON.parse(JSON.stringify(held.base)); +} diff --git a/src/native/sdks/swift/tools/pinned-native-carrier.mts b/src/native/sdks/swift/tools/pinned-native-carrier.mts index 83691163a..8ee078aa9 100644 --- a/src/native/sdks/swift/tools/pinned-native-carrier.mts +++ b/src/native/sdks/swift/tools/pinned-native-carrier.mts @@ -1,12 +1,25 @@ import { copyFileSync, mkdirSync } from 'node:fs'; import path from 'node:path'; -import { currentProductVersionSync } from '../../../../../tools/release/release-artifact-targets.mts'; import { githubReleaseQueryDeadline, requestGithubJsonWithRetry, } from '../../../../../tools/release/github-read.mts'; +import { currentProductVersionSync } from '../../../../../tools/release/release-artifact-targets.mts'; +import { publishedNativeBaseForSource } from './native-legal-source-basis.mts'; import { materialize } from './swift-carrier-resolver.mts'; +async function stagePublishedAssets(assets, version, workRoot, fetchImpl) { + const directory = path.join(workRoot, 'pinned-native-carrier', version); + mkdirSync(directory, { recursive: true }); + for (const asset of assets) { + const file = await materialize(asset, path.join(workRoot, 'pinned-native-carrier-cache'), { + fetchImpl, + }); + copyFileSync(file, path.join(directory, asset.name)); + } + return directory; +} + // Source builds use the same-run producer for the current runtime. Independent // SDK releases keep their exact older runtime and verify its published bytes. export async function pinnedNativeCarrierDirectory({ @@ -14,10 +27,25 @@ export async function pinnedNativeCarrierDirectory({ assetDir, workRoot, fetchImpl = fetch, + sourceBasis = undefined, }) { if (!/^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u.test(version)) { throw new Error(`invalid native runtime pin: ${version}`); } + if (sourceBasis !== undefined) { + if (sourceBasis.kind === 'current-source') { + if (version !== currentProductVersionSync('liboliphaunt-native', 'pinned-native-carrier')) + throw new Error(`fresh native construction does not have version ${version}`); + if (!assetDir) throw new Error(`native runtime ${version} requires same-run producer assets`); + return assetDir; + } + const base = publishedNativeBaseForSource(sourceBasis); + if (base.version !== version) + throw new Error(`published native source basis does not bind runtime ${version}`); + return stagePublishedAssets(base.assets, version, workRoot, fetchImpl); + } + // Existing standalone Moon callers retain their behavior until publication + // preflight supplies the explicit producer/source origin above. if (version === currentProductVersionSync('liboliphaunt-native', 'pinned-native-carrier')) { if (!assetDir) throw new Error(`native runtime ${version} requires same-run producer assets`); return assetDir; @@ -45,12 +73,10 @@ export async function pinnedNativeCarrierDirectory({ assets.push(...rows); if (rows.length < 100) break; } - const directory = path.join(workRoot, 'pinned-native-carrier', version); - mkdirSync(directory, { recursive: true }); - for (const name of [ + const selected = [ `liboliphaunt-${version}-apple-spm-xcframework.zip`, `liboliphaunt-${version}-runtime-resources-ios-datum64.tar.gz`, - ]) { + ].map((name) => { const matches = assets.filter((row) => row.name === name); const row = matches[0]; const url = `https://github.com/f0rr0/oliphaunt/releases/download/${tag}/${name}`; @@ -64,12 +90,7 @@ export async function pinnedNativeCarrierDirectory({ ) { throw new Error(`${tag} must publish one checksummed ${name}`); } - const file = await materialize( - { name, url, bytes: row.size, sha256: row.digest.slice(7) }, - path.join(workRoot, 'pinned-native-carrier-cache'), - { fetchImpl }, - ); - copyFileSync(file, path.join(directory, name)); - } - return directory; + return { name, url, bytes: row.size, sha256: row.digest.slice(7) }; + }); + return stagePublishedAssets(selected, version, workRoot, fetchImpl); } diff --git a/src/native/sdks/swift/tools/render-extension-products.mts b/src/native/sdks/swift/tools/render-extension-products.mts index c9915e835..9df20fb8a 100755 --- a/src/native/sdks/swift/tools/render-extension-products.mts +++ b/src/native/sdks/swift/tools/render-extension-products.mts @@ -41,7 +41,7 @@ function usage() { `--output-dir [--cache-dir ] [--offline] [--allow-file-urls] ` + `[--local-binary-targets] ` + `[--base-package-url ] [--base-package-version ] ` + - `[--base-package-path ]`, + `[--base-package-path ] [--owner-catalog ]`, ); } @@ -74,6 +74,7 @@ function parseArgs(argv) { '--base-package-path', '--base-package-url', '--base-package-version', + '--owner-catalog', ].includes(arg) ) { usage(); @@ -96,6 +97,7 @@ function parseArgs(argv) { if (arg === '--base-package-path') args.basePackagePath = path.resolve(value); if (arg === '--base-package-url') args.basePackageUrl = value; if (arg === '--base-package-version') args.basePackageVersion = value; + if (arg === '--owner-catalog') args.ownerCatalogFile = path.resolve(value); } if (!args.outputDir || !args.extensions?.length) { usage(); @@ -954,6 +956,15 @@ async function writeGeneratedTree(selection, outputDir, basePackagePath, localBi const products = []; const targets = []; const selected = []; + const deliveredAsset = (asset, target) => + asset == null + ? asset + : { + ...asset, + ...(asset.localPath === undefined + ? {} + : { localPath: `Artifacts/${target}.xcframework` }), + }; for (const dependency of selection.nativeDependencies) { if (localBinaryTargets || dependency.asset.localPath !== undefined) { await copyLocalBinaryArtifact(dependency.asset, dependency.binaryTarget, outputDir); @@ -987,10 +998,13 @@ async function writeGeneratedTree(selection, outputDir, basePackagePath, localBi }); targets.push(...targetIR(extension, selection.bySqlName, localBinaryTargets)); selected.push({ - asset: extension.asset, + asset: deliveredAsset(extension.asset, extension.binaryTarget), createsExtension: extension.resources.createsExtension, dependencies: extension.dependencies, - nativeDependencies: extension.nativeDependencies, + nativeDependencies: extension.nativeDependencies.map((dependency) => ({ + ...dependency, + asset: deliveredAsset(dependency.asset, dependency.binaryTarget), + })), nativeModuleStem: extension.nativeModuleStem, product: extension.product, releaseProduct: extension.releaseProduct, @@ -1206,13 +1220,14 @@ export async function renderExtensionProducts(argv = process.argv.slice(2)) { extensions: args.extensions, offline: args.offline, localBinaryTargets: args.localBinaryTargets, + ownerCatalogFile: args.ownerCatalogFile, }); const inputDirectory = process.cwd(); const selection = validateSelection(input, inputDirectory, { allowFileUrls: args.allowFileUrls, localBinaryTargets: args.localBinaryTargets, }); - const canonicalInventory = await loadSwiftExtensionInventoryCatalog(); + const canonicalInventory = await loadSwiftExtensionInventoryCatalog(args.ownerCatalogFile); if (args.basePackagePath !== undefined) { const baseManifest = path.join(args.basePackagePath, 'Package.swift'); const stat = await fs.stat(baseManifest).catch(() => null); diff --git a/src/native/sdks/swift/tools/render_swiftpm_release_package.mts b/src/native/sdks/swift/tools/render_swiftpm_release_package.mts index b1e6bbbc7..bd14f5f30 100755 --- a/src/native/sdks/swift/tools/render_swiftpm_release_package.mts +++ b/src/native/sdks/swift/tools/render_swiftpm_release_package.mts @@ -7,6 +7,11 @@ import { readPortableArchiveEntries } from '../../../../../tools/packaging/porta import { productCompatibilityVersion } from '../../../../../tools/release/release-graph.mts'; import { assertRustDependencyLicensesInEntries } from '../../../mobile-bindings/tools/dependency-license-contract.mts'; +import { renderSwiftReleaseManifest } from './swift-release-manifest.mts'; +import { validateAppleXcframeworkAsset } from './swift-xcframework-contract.mts'; + +export { missingRequiredAppleArm64Slices } from './swift-xcframework-contract.mts'; + const ROOT = path.resolve(import.meta.dir, '../../../../..'); const REPOSITORY = 'f0rr0/oliphaunt'; const MAX_REMOTE_CHECKSUM_MANIFEST_BYTES = 1024 * 1024; @@ -49,256 +54,6 @@ function checksumFromManifest(text, asset) { return undefined; } -async function readZipArchive(file) { - const entries = readPortableArchiveEntries(file, { format: 'zip' }); - return { - names: new Set(entries.keys()), - read(entryName) { - const entry = entries.get(entryName); - return entry?.isFile ? Buffer.from(entry.data()) : undefined; - }, - }; -} - -function xmlDecode(value) { - return value - .replaceAll('"', '"') - .replaceAll(''', "'") - .replaceAll('<', '<') - .replaceAll('>', '>') - .replaceAll('&', '&'); -} - -function tokenizeXml(text) { - return Array.from(text.matchAll(/<[^>]+>|[^<]+/gu), (match) => match[0]); -} - -function tagName(token) { - return token - .replace(/^<\//u, '') - .replace(/^$/u, '') - .trim() - .split(/\s+/u)[0]; -} - -class PlistParser { - constructor(text) { - this.tokens = tokenizeXml(text); - this.index = 0; - } - - parse() { - const token = this.nextToken(); - if (!this.isOpening(token, 'plist')) { - throw new Error('plist root element is missing'); - } - const value = this.parseValue(); - const closing = this.nextToken(); - if (!this.isClosing(closing, 'plist')) { - throw new Error('plist root element is not closed'); - } - return value; - } - - nextToken() { - while (this.index < this.tokens.length) { - const token = this.tokens[this.index]; - this.index += 1; - if (!token.startsWith('<') && token.trim() === '') { - continue; - } - if (token.startsWith('') - ); - } - - isClosing(token, name) { - return token.startsWith(''); - } - - parseValue() { - const token = this.nextToken(); - if (this.isOpening(token, 'dict')) { - return this.parseDict(); - } - if (this.isOpening(token, 'array')) { - return this.parseArray(); - } - if (this.isOpening(token, 'string')) { - return this.parseTextElement('string'); - } - if (this.isSelfClosing(token, 'string')) { - return ''; - } - if (this.isOpening(token, 'integer')) { - return Number.parseInt(this.parseTextElement('integer'), 10); - } - if (this.isSelfClosing(token, 'true')) { - return true; - } - if (this.isSelfClosing(token, 'false')) { - return false; - } - throw new Error(`unsupported plist value ${token}`); - } - - parseDict() { - const result = {}; - while (true) { - const token = this.peekToken(); - if (this.isClosing(token, 'dict')) { - this.nextToken(); - return result; - } - const keyOpen = this.nextToken(); - if (!this.isOpening(keyOpen, 'key')) { - throw new Error(`expected plist dict key, got ${keyOpen}`); - } - const key = this.parseTextElement('key'); - result[key] = this.parseValue(); - } - } - - parseArray() { - const result = []; - while (true) { - const token = this.peekToken(); - if (this.isClosing(token, 'array')) { - this.nextToken(); - return result; - } - result.push(this.parseValue()); - } - } - - parseTextElement(name) { - let text = ''; - while (true) { - const token = this.nextToken(); - if (this.isClosing(token, name)) { - return xmlDecode(text); - } - if (token.startsWith('<')) { - throw new Error(`unexpected tag in plist ${name}: ${token}`); - } - text += token; - } - } -} - -function parsePlist(buffer, source) { - const prefix = buffer.subarray(0, 6).toString('utf8'); - if (prefix === 'bplist') { - fail(`SwiftPM Apple XCFramework Info.plist must be XML for release validation: ${source}`); - } - try { - return new PlistParser(buffer.toString('utf8')).parse(); - } catch (error) { - fail(`SwiftPM Apple XCFramework Info.plist is invalid in ${source}: ${error.message}`); - } -} - -async function validateAppleXcframeworkAsset(file, framework = 'liboliphaunt') { - let archive; - try { - archive = await readZipArchive(file); - } catch (error) { - fail(`SwiftPM Apple XCFramework asset is not a readable zip file: ${file}: ${error.message}`); - } - const infoData = archive.read(`${framework}.xcframework/Info.plist`); - if (infoData === undefined) { - fail(`SwiftPM Apple XCFramework asset is missing ${framework}.xcframework/Info.plist: ${file}`); - } - const info = parsePlist(infoData, file); - if (info === null || Array.isArray(info) || typeof info !== 'object') { - fail(`SwiftPM Apple XCFramework Info.plist must be a plist dictionary in ${file}`); - } - const libraries = info.AvailableLibraries; - if (!Array.isArray(libraries) || libraries.length === 0) { - fail(`SwiftPM Apple XCFramework Info.plist has no AvailableLibraries in ${file}`); - } - - const slices = new Set(); - for (const library of libraries) { - if (library === null || Array.isArray(library) || typeof library !== 'object') { - continue; - } - const platform = library.SupportedPlatform; - const variant = library.SupportedPlatformVariant ?? ''; - const libraryPath = library.LibraryPath; - const identifier = library.LibraryIdentifier; - const architectures = library.SupportedArchitectures; - if ( - typeof platform !== 'string' || - typeof libraryPath !== 'string' || - typeof identifier !== 'string' || - !Array.isArray(architectures) || - architectures.some((architecture) => typeof architecture !== 'string') - ) { - continue; - } - for (const architecture of architectures) { - slices.add(`${platform}\0${typeof variant === 'string' ? variant : ''}\0${architecture}`); - } - const candidate = `${framework}.xcframework/${identifier}/${libraryPath}`; - if ( - !archive.names.has(candidate) && - !Array.from(archive.names).some((name) => name.startsWith(`${candidate}/`)) - ) { - fail(`SwiftPM Apple XCFramework is missing declared library ${candidate}`); - } - } - - const missing = missingRequiredAppleArm64Slices(slices); - if (missing.length > 0) { - fail( - `SwiftPM Apple XCFramework asset ${file} is missing required arm64 slice(s): ${missing.join(', ')}`, - ); - } -} - -export function missingRequiredAppleArm64Slices(slices) { - const required = [ - ['macos', '', 'arm64'], - ['ios', '', 'arm64'], - ['ios', 'simulator', 'arm64'], - ]; - return required - .filter( - ([platform, variant, architecture]) => - !slices.has(`${platform}\0${variant}\0${architecture}`), - ) - .map( - ([platform, variant, architecture]) => - `${platform}${variant ? `-${variant}` : ''}-${architecture}`, - ) - .sort(); -} - export async function fetchText(url, { fetchImpl = fetch, timeoutMs = 20_000 } = {}) { const response = await fetchImpl(url, { redirect: 'follow', @@ -383,91 +138,6 @@ async function resolveChecksum(assetDir, assetBaseUrl, asset, version) { return checksum; } -function renderManifest( - assetBaseUrl, - liboliphauntVersion, - checksum, - bindingsUrl, - bindingsChecksum, -) { - const asset = `liboliphaunt-${liboliphauntVersion}-apple-spm-xcframework.zip`; - const url = `${assetBaseUrl.replace(/\/+$/u, '')}/${asset}`; - return `// swift-tools-version: 6.0 - -import PackageDescription - -// Generated by src/native/sdks/swift/tools/render_swiftpm_release_package.mts. -// This is the public SwiftPM release manifest. The source package under -// src/native/sdks/swift remains the local development package. -// Exact PostgreSQL extensions are released as separate opt-in extension -// artifacts. The base Swift package must not require or publish extension files. -let package = Package( - name: "Oliphaunt", - platforms: [ - .iOS(.v17), - .macOS(.v14) - ], - products: [ - .library(name: "COliphaunt", targets: ["COliphaunt"]), - .library(name: "Oliphaunt", targets: ["Oliphaunt"]), - .library(name: "OliphauntCore", targets: ["OliphauntCore"]), - .library(name: "OliphauntBroker", targets: ["OliphauntBroker"]), - .library(name: "OliphauntBrokerExtension", targets: ["OliphauntBrokerExtension"]), - .library(name: "OliphauntExtensionSupport", targets: ["OliphauntExtensionSupport"]) - ], - targets: [ - .binaryTarget( - name: "OliphauntNativeBindingsFFI", - url: "${bindingsUrl}", - checksum: "${bindingsChecksum}" - ), - .target( - name: "OliphauntNativeBindings", - dependencies: ["OliphauntNativeBindingsFFI"], - path: "src/sdks/swift/Sources/OliphauntNativeBindings" - ), - .binaryTarget( - name: "liboliphaunt", - url: "${url}", - checksum: "${checksum}" - ), - .target( - name: "COliphaunt", - dependencies: ["liboliphaunt"], - path: "src/sdks/swift/Sources/COliphaunt", - publicHeadersPath: "include", - cSettings: [.define("OLIPHAUNT_LINK_RUNTIME")] - ), - .target( - name: "OliphauntCore", - dependencies: ["OliphauntNativeBindings"], - path: "src/sdks/swift/Sources/OliphauntCore" - ), - .target( - name: "OliphauntBroker", - dependencies: ["OliphauntCore", "OliphauntNativeBindings"], - path: "src/sdks/swift/Sources/OliphauntBroker" - ), - .target( - name: "OliphauntBrokerExtension", - dependencies: ["Oliphaunt", "OliphauntCore", "OliphauntNativeBindings"], - path: "src/sdks/swift/Sources/OliphauntBrokerExtension" - ), - .target( - name: "Oliphaunt", - dependencies: ["COliphaunt", "OliphauntCore", "OliphauntNativeBindings"], - path: "src/sdks/swift/Sources/Oliphaunt" - ), - .target( - name: "OliphauntExtensionSupport", - dependencies: ["COliphaunt", "Oliphaunt"], - path: "src/sdks/swift/Sources/OliphauntExtensionSupport" - ) - ] -) -`; -} - function parseArgs(argv) { const usage = 'usage: src/native/sdks/swift/tools/render_swiftpm_release_package.mts [--asset-dir DIR] [--asset-base-url URL] [--output FILE] [--generated-tree DIR]'; @@ -571,7 +241,7 @@ export async function renderSwiftpmReleasePackage(argv) { path.join(ROOT, 'target/mobile-bindings/generated/OliphauntNativeBindings.swift'), ); } - const manifest = renderManifest( + const manifest = renderSwiftReleaseManifest( assetBaseUrl, liboliphauntVersion, checksum, diff --git a/src/native/sdks/swift/tools/stage-release-artifacts.mts b/src/native/sdks/swift/tools/stage-release-artifacts.mts index badaf8d3e..7b85aaaa9 100644 --- a/src/native/sdks/swift/tools/stage-release-artifacts.mts +++ b/src/native/sdks/swift/tools/stage-release-artifacts.mts @@ -1,33 +1,36 @@ -import { renderSwiftpmReleasePackage } from './render_swiftpm_release_package.mts'; +import { copyFileSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { createDeterministicZip } from '../../../../../tools/packaging/archive-directory.mts'; import { bundleJavaScript, emitJavaScript, } from '../../../../../tools/packaging/emit-javascript.mts'; -import { copyFileSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; -import path from 'node:path'; -import { createDeterministicZip } from '../../../../../tools/packaging/archive-directory.mts'; import { extractPortableArchiveTree } from '../../../../../tools/packaging/portable-archive.mts'; - -import { IOS_CARRIER_FILENAME, buildIosCarrierManifest } from './ios-carrier-manifest.mts'; import { assertReleaseNoticesInArchive, assertReleaseNoticesInDirectory, stageReleaseNotices, } from '../../../../../tools/packaging/release-notices.mts'; -import { productCompatibilityVersion } from '../../../../../tools/release/release-graph.mts'; -import { validateSwiftSourceReleaseContract } from './swift-source-carrier-contract.mts'; -import { pinnedNativeCarrierDirectory } from './pinned-native-carrier.mts'; import { - ROOT, copyDirContents, fail, + ROOT, rel, requireFile, } from '../../../../../tools/packaging/staging.mts'; +import { productCompatibilityVersion } from '../../../../../tools/release/release-graph.mts'; +import { buildIosCarrierManifest, IOS_CARRIER_FILENAME } from './ios-carrier-manifest.mts'; +import { pinnedNativeCarrierDirectory } from './pinned-native-carrier.mts'; +import { renderSwiftpmReleasePackage } from './render_swiftpm_release_package.mts'; +import { validateSwiftSourceReleaseContract } from './swift-source-carrier-contract.mts'; const PREFIX = 'swift stage-release-artifacts.mts'; -export async function stageArtifacts(artifactRoot, workRoot) { +export async function stageArtifacts( + artifactRoot, + workRoot, + { nativeSourceBasis = undefined } = {}, +) { const swiftSourceArchive = path.join( ROOT, 'target/liboliphaunt-sdk-check/oliphaunt-swift/package-shape/swift-source-archive/Oliphaunt-source.zip', @@ -48,6 +51,7 @@ export async function stageArtifacts(artifactRoot, workRoot) { version: nativeVersion, assetDir: producerAssetDir, workRoot, + sourceBasis: nativeSourceBasis, }); await renderSwiftpmReleasePackage([ '--asset-dir', @@ -66,6 +70,7 @@ export async function stageArtifacts(artifactRoot, workRoot) { baseAssetDir: assetDir, baseRuntimeVersion: nativeVersion, extensionManifests: [], + baseSourceBasis: nativeSourceBasis, }); const carrierFile = path.join(releaseTree, 'src/sdks/swift/Carriers', IOS_CARRIER_FILENAME); mkdirSync(path.dirname(carrierFile), { recursive: true }); @@ -111,6 +116,7 @@ export async function stageArtifacts(artifactRoot, workRoot) { expectedNativeVersion: nativeVersion, label: `${rel(artifactRoot)} source release`, manifestText: manifest, + sourceBasis: nativeSourceBasis, }); } catch (error) { fail(error instanceof Error ? error.message : String(error)); @@ -140,4 +146,5 @@ export async function stageArtifacts(artifactRoot, workRoot) { } import { stageSdkArtifacts } from '../../../../../tools/packaging/staging.mts'; + if (import.meta.main) await stageSdkArtifacts('oliphaunt-swift', stageArtifacts); diff --git a/src/native/sdks/swift/tools/swift-carrier-resolver.test.mts b/src/native/sdks/swift/tools/swift-carrier-resolver.test.mts index 4a8c4fa24..c1e7f47f1 100755 --- a/src/native/sdks/swift/tools/swift-carrier-resolver.test.mts +++ b/src/native/sdks/swift/tools/swift-carrier-resolver.test.mts @@ -6,6 +6,7 @@ import fs from 'node:fs/promises'; import path from 'node:path'; import { pathToFileURL } from 'node:url'; import { gunzipSync, gzipSync } from 'node:zlib'; +import { buildSwiftExtensionFixture } from '../../../../../build_defs/languages/swift/extension-fixture.mts'; import { archiveDirectory } from '../../../../../tools/packaging/archive-directory.mts'; import { craftedTar } from '../../../../../tools/packaging/testdata/tar-fixture.mts'; import { @@ -13,6 +14,7 @@ import { maliciousZip, metadataZip, } from '../../../../../tools/packaging/testdata/zip-fixture.mts'; +import { iosBaseLegalMetadata } from './ios-carrier-manifest.mts'; import { renderExtensionProducts } from './render-extension-products.mts'; import { extractVerifiedZipArchive, @@ -668,6 +670,21 @@ async function main() { localOutput, ]); const localPackage = await fs.readFile(path.join(localOutput, 'Package.swift'), 'utf8'); + const localProducts = JSON.parse( + await fs.readFile(path.join(localOutput, 'extension-products.json'), 'utf8'), + ); + for (const row of localProducts.selected) { + if (row.asset?.localPath !== undefined) + assert.equal(row.asset.localPath, `Artifacts/${row.swiftProduct}Binary.xcframework`); + for (const dependency of row.nativeDependencies) + assert.equal(dependency.asset.localPath, `Artifacts/${dependency.binaryTarget}.xcframework`); + } + assert.ok( + localProducts.selected.every( + (row) => row.asset?.localPath === undefined || !path.isAbsolute(row.asset.localPath), + ), + 'delivered metadata must not retain private cache paths', + ); assert.match( localPackage, /\.binaryTarget\([\s\S]*path: "Artifacts\/OliphauntExtensionPostgisBinary\.xcframework"/u, @@ -712,6 +729,35 @@ async function main() { ); assert.deepEqual(await fixtureFiles(output), await fixtureFiles(offlineOutput)); + const declaredCatalog = path.join(root, 'declared-owner-catalog.json'); + await fs.copyFile( + path.join(sdk, '../../../extensions/generated/sdk/extensions.json'), + declaredCatalog, + ); + const declaredOutput = path.join(root, 'declared-catalog-output'); + await render([ + ...common, + '--offline', + '--owner-catalog', + declaredCatalog, + '--output-dir', + declaredOutput, + ]); + assert.deepEqual(await fixtureFiles(output), await fixtureFiles(declaredOutput)); + assert.match( + await render( + [ + ...common, + '--owner-catalog', + path.join(root, 'missing-catalog.json'), + '--output-dir', + path.join(root, 'missing-catalog-output'), + ], + { expectFailure: true }, + ), + /missing-catalog|ENOENT/u, + ); + async function expectCarrierFailure(name, candidate, selected, pattern) { const file = path.join(root, `${name}.json`); await fs.writeFile(file, `${JSON.stringify(candidate, null, 2)}\n`); @@ -810,6 +856,91 @@ async function main() { earthdistanceCarrier, `${JSON.stringify(earthdistanceCarrierDocument, null, 2)}\n`, ); + // The constructor consumes exact original source/control/archive Files and + // uses its own offline cache; it cannot retarget the source native pin. + const originalSource = path.join(root, 'original-swift-source/package'); + await fs.mkdir(originalSource, { recursive: true }); + await fs.writeFile(path.join(originalSource, 'VERSION'), '0.1.0\n'); + await fs.writeFile(path.join(originalSource, 'LIBOLIPHAUNT_VERSION'), '0.1.0\n'); + const originalArchive = path.join(root, 'Oliphaunt-source.zip'); + await archiveDirectory(originalSource, originalArchive, { keepParent: true }); + const neutral = { + schema, + base: structuredClone(manifest.base), + carriers: [], + extensions: [], + legal: { base: iosBaseLegalMetadata(), extensions: [] }, + }; + for (const row of neutral.base.assets) + row.url = `https://github.com/f0rr0/oliphaunt/releases/download/${neutral.base.tag}/${row.name}`; + const originalCarrier = path.join(root, 'original-swift-ios-carriers.json'); + await fs.writeFile(originalCarrier, JSON.stringify(neutral)); + const offlineCarrier = structuredClone(earthdistanceCarrierDocument); + for (const row of offlineCarrier.carriers) + row.url = `https://github.com/f0rr0/oliphaunt/releases/download/${offlineCarrier.release.tag}/${row.name}`; + const offlineControl = path.join(root, 'offline-contrib-swift-ios-carrier.json'); + await fs.writeFile(offlineControl, JSON.stringify(offlineCarrier)); + const input = async (file) => ({ + path: file, + size: (await fs.stat(file)).size, + sha256: await checksum(file), + }); + const fixtureSpec = { + version: '0.1.0', + selectedProducts: ['oliphaunt-swift', 'liboliphaunt-native'], + sourceArchive: await input(originalArchive), + sourceCarrier: await input(originalCarrier), + ownerCatalog: await input(declaredCatalog), + carriers: [ + { product: 'liboliphaunt-native', version: '1.1.0', file: await input(offlineControl) }, + ], + assets: await Promise.all( + offlineCarrier.carriers.map(({ name }) => input(path.join(root, 'archives', name))), + ), + }; + const fixtureOutput = path.join(root, 'constructed-offline-fixture'); + const fixtureResult = await buildSwiftExtensionFixture(fixtureOutput, fixtureSpec); + assert.deepEqual( + fixtureResult.selected.map(({ sqlName }) => sqlName), + ['cube', 'earthdistance'], + ); + assert(fixtureResult.selected.every(({ asset }) => asset.localPath.startsWith('Artifacts/'))); + assert( + !JSON.stringify(fixtureResult).includes(root), + 'constructed fixture must not contain private paths', + ); + await assert.rejects( + () => + buildSwiftExtensionFixture(path.join(root, 'wrong-source-version'), { + ...fixtureSpec, + version: '0.2.0', + }), + /cannot restamp/u, + ); + await assert.rejects( + () => + buildSwiftExtensionFixture(path.join(root, 'wrong-carrier-owner'), { + ...fixtureSpec, + carriers: [{ ...fixtureSpec.carriers[0], product: 'oliphaunt-extension-vector' }], + }), + /unselected carrier owner/u, + ); + await assert.rejects( + () => + buildSwiftExtensionFixture(path.join(root, 'missing-carrier-bytes'), { + ...fixtureSpec, + assets: [], + }), + /exact declared public carrier archive/u, + ); + await assert.rejects( + () => + buildSwiftExtensionFixture(path.join(root, 'changed-source-bytes'), { + ...fixtureSpec, + sourceArchive: { ...fixtureSpec.sourceArchive, sha256: '0'.repeat(64) }, + }), + /input bytes differ/u, + ); const composedOutput = path.join(root, 'dependency-composed'); await render([ generator, diff --git a/src/native/sdks/swift/tools/swift-extension-fixture-consumer.mts b/src/native/sdks/swift/tools/swift-extension-fixture-consumer.mts new file mode 100644 index 000000000..b2945a0c2 --- /dev/null +++ b/src/native/sdks/swift/tools/swift-extension-fixture-consumer.mts @@ -0,0 +1,18 @@ +import assert from 'node:assert/strict'; +import path from 'node:path'; + +/** Only replace the already verified SDK requirement in a private consumer + * copy. Public fixture bytes and their exact dependency remain untouched. */ +export function localizeSwiftExtensionFixturePackage(manifest, products, version, sdk) { + assert.equal(products.basePackage?.url, 'https://github.com/f0rr0/oliphaunt.git'); + assert.equal(products.basePackage?.version, version, 'fixture adopts a different Swift source'); + const pattern = /\.package\(\s*url:\s*"([^"]+)"\s*,\s*exact:\s*"([^"]+)"\s*\)/gu; + const rows = [...manifest.matchAll(pattern)]; + assert.equal(rows.length, 1, 'fixture needs exactly one conventional SDK dependency'); + assert.equal(rows[0][1], products.basePackage.url); + assert.equal(rows[0][2], version); + return manifest.replace( + pattern, + `.package(name: "oliphaunt", path: ${JSON.stringify(path.resolve(sdk))})`, + ); +} diff --git a/src/native/sdks/swift/tools/swift-extension-fixture-consumer.test.mts b/src/native/sdks/swift/tools/swift-extension-fixture-consumer.test.mts new file mode 100644 index 000000000..806b3f191 --- /dev/null +++ b/src/native/sdks/swift/tools/swift-extension-fixture-consumer.test.mts @@ -0,0 +1,72 @@ +import { expect, test } from 'bun:test'; +import { swiftExtensionReleaseConsumerFiles } from './extension-release-consumer.mts'; +import { localizeSwiftExtensionFixturePackage } from './swift-extension-fixture-consumer.mts'; + +test('private fixture localization preserves the actual SDK adoption and rejects substituted requirements', () => { + const products = { + basePackage: { url: 'https://github.com/f0rr0/oliphaunt.git', version: '0.8.2' }, + }; + const manifest = '.package(\nurl: "https://github.com/f0rr0/oliphaunt.git", exact: "0.8.2"\n)'; + expect( + localizeSwiftExtensionFixturePackage(manifest, products, '0.8.2', '/private/sdk'), + ).toContain('path: "/private/sdk"'); + expect(() => + localizeSwiftExtensionFixturePackage(manifest, products, '0.8.3', '/private/sdk'), + ).toThrow(); + expect(() => + localizeSwiftExtensionFixturePackage( + manifest.replace('0.8.2', '0.8.3'), + products, + '0.8.2', + '/private/sdk', + ), + ).toThrow(); + expect(() => + localizeSwiftExtensionFixturePackage(manifest + manifest, products, '0.8.2', '/private/sdk'), + ).toThrow(); +}); + +test('the real Swift consumer checks packaged SQL, native registration and exact linked runtime', () => { + const plan = { + extensions: ['vector'], + extensionProducts: ['oliphaunt-extension-vector'], + finalLink: { + kind: 'native-extension', + nativeExtension: 'vector', + nativeModuleStem: 'vector', + runtimeProduct: 'liboliphaunt-native', + runtimeVersion: '0.3.3', + }, + }; + const products = { + nativeRuntime: { product: 'liboliphaunt-native', version: '0.3.3' }, + selected: [ + { + swiftProduct: 'OliphauntVector', + sqlName: 'vector', + product: 'oliphaunt-extension-vector', + nativeModuleStem: 'vector', + }, + ], + }; + const result = swiftExtensionReleaseConsumerFiles({ + plan, + products, + selectedPackage: '/private/selected', + releasePackage: '/private/sdk', + }); + expect(result.main).toContain('try OliphauntVector.register()'); + expect(result.main).toContain('linkedNativeRuntimeVersion == "0.3.3"'); + expect(result.packageFile).toContain('path: "/private/selected"'); + expect(() => + swiftExtensionReleaseConsumerFiles({ + plan, + products: { + ...products, + nativeRuntime: { product: 'liboliphaunt-native', version: '0.3.4' }, + }, + selectedPackage: '/private/selected', + releasePackage: '/private/sdk', + }), + ).toThrow(); +}); diff --git a/src/native/sdks/swift/tools/swift-extension-release-consumer-inputs.mts b/src/native/sdks/swift/tools/swift-extension-release-consumer-inputs.mts index 53a3a9ffc..b23bd4e1b 100644 --- a/src/native/sdks/swift/tools/swift-extension-release-consumer-inputs.mts +++ b/src/native/sdks/swift/tools/swift-extension-release-consumer-inputs.mts @@ -3,6 +3,7 @@ import { readFileSync } from 'node:fs'; import { contribCarrierDescriptor } from '../../../../../tools/release/release-artifact-targets.mts'; +import { buildIosCarrierManifest } from './ios-carrier-manifest.mts'; import { validateSelectionNeutralSwiftSourceCarrier } from './swift-source-carrier-contract.mts'; const PREFIX = 'swift-extension-release-consumer-inputs.mts'; @@ -83,10 +84,57 @@ function readJson(file, label) { } } -export function extensionReleaseConsumerInputs({ sourceCarrierFile, extensionCarrierFiles }) { +/** Request a consumer tuple from source-bound requirements before construction. + * A carrier at another adopted base remains an independent publication; it is + * never relabeled or accepted as part of this SDK's installed composition. + */ +export function requestedSwiftExtensionCarrierProducts({ selectedProducts, sourceBase, carriers }) { + if ( + !Array.isArray(selectedProducts) || + new Set(selectedProducts).size !== selectedProducts.length + ) + fail('selected products must be a unique array'); + if (!selectedProducts.includes('oliphaunt-swift')) return []; + const source = baseReference(sourceBase, 'source carrier base'); + const owners = new Set(); + const requested = []; + for (const carrier of carriers) { + const release = releaseReference(carrier.release, 'independent carrier release'); + const base = baseReference(carrier.base, 'independent carrier base'); + if (!selectedProducts.includes(release.product)) + fail(`independent carrier ${release.product} is outside the selected products`); + if (owners.has(release.product)) fail(`independent carrier ${release.product} repeats`); + owners.add(release.product); + if ( + base.product === source.product && + base.version === source.version && + base.tag === source.tag + ) + requested.push(release.product); + } + return requested.sort(compareText); +} + +export function extensionReleaseConsumerInputs({ + sourceCarrierFile, + extensionCarrierFiles, + nativeSourceBasis = undefined, + nativeBaseArchiveInputs = undefined, +}) { const sourceCarrier = readJson(sourceCarrierFile, 'source carrier'); try { - validateSelectionNeutralSwiftSourceCarrier(sourceCarrier, sourceCarrierFile); + if (nativeBaseArchiveInputs) + buildIosCarrierManifest({ + baseRuntimeVersion: sourceCarrier.base.version, + baseTag: sourceCarrier.base.tag, + declaredProducts: {}, + baseCarrierManifest: sourceCarrierFile, + baseArchiveInputs: nativeBaseArchiveInputs, + }); + else + validateSelectionNeutralSwiftSourceCarrier(sourceCarrier, sourceCarrierFile, { + sourceBasis: nativeSourceBasis, + }); } catch (cause) { fail(cause instanceof Error ? cause.message : String(cause)); } diff --git a/src/native/sdks/swift/tools/swift-native-carrier-contract.mts b/src/native/sdks/swift/tools/swift-native-carrier-contract.mts new file mode 100644 index 000000000..3a4b3180c --- /dev/null +++ b/src/native/sdks/swift/tools/swift-native-carrier-contract.mts @@ -0,0 +1,276 @@ +import path from 'node:path'; + +export const IOS_CARRIER_SCHEMA = 'oliphaunt-react-native-ios-carrier-v1'; +export const IOS_CARRIER_FILENAME = 'oliphaunt-react-native-ios-carriers.json'; + +const STABLE_SEMVER = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u; +const CANONICAL_REPOSITORY = 'https://github.com/f0rr0/oliphaunt'; + +function compareText(left, right) { + return left < right ? -1 : left > right ? 1 : 0; +} + +function error(label, message) { + return new Error(`${label}: ${message}`); +} + +function exactKeys(value, expected, label) { + if (value === null || Array.isArray(value) || typeof value !== 'object') { + throw error(label, 'must be an object'); + } + const actual = Object.keys(value).sort(compareText); + const canonical = [...expected].sort(compareText); + if (JSON.stringify(actual) !== JSON.stringify(canonical)) { + throw error(label, `fields must be exactly ${canonical.join(',')}; got ${actual.join(',')}`); + } + return value; +} + +function safeArchiveMember(value, label) { + if ( + typeof value !== 'string' || + value.length === 0 || + value.includes('\\') || + value.startsWith('/') || + /^[A-Za-z]:/u.test(value) || + /[\u0000-\u001f\u007f]/u.test(value) + ) { + throw error(label, 'must be a safe POSIX archive path'); + } + if (value === '.') return value; + const parts = value.split('/'); + if (parts.some((part) => part.length === 0 || part === '.' || part === '..')) { + throw error(label, 'must be a safe POSIX archive path'); + } + return value; +} + +function portableFilename(value, label) { + if ( + typeof value !== 'string' || + value.length === 0 || + path.posix.basename(value) !== value || + /[<>:"/\\|?*\u0000-\u001f\u007f]/u.test(value) || + /[ .]$/u.test(value) || + /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu.test(value) + ) { + throw error(label, 'must be a portable release asset filename'); + } + return value; +} + +function validateFrozenLegalMetadata(groups, label) { + const roles = [ + { role: 'base-xcframework', profile: 'native-runtime', prefix: 'liboliphaunt.xcframework/' }, + { role: 'runtime-resources', profile: 'native-runtime-resources', prefix: '' }, + ]; + if (!Array.isArray(groups) || groups.length !== roles.length) + throw error( + label, + 'must contain exactly the native framework and runtime resource legal groups', + ); + for (const [index, contract] of roles.entries()) { + const groupLabel = `${label}[${index}]`; + const group = exactKeys(groups[index], ['assetRole', 'files', 'profile', 'spdx'], groupLabel); + if (group.assetRole !== contract.role || group.profile !== contract.profile) + throw error(groupLabel, 'must match the canonical native asset role and legal profile'); + if ( + typeof group.spdx !== 'string' || + group.spdx.length === 0 || + /[\u0000-\u001f\u007f]/u.test(group.spdx) + ) + throw error(`${groupLabel}.spdx`, 'must be a nonempty SPDX expression'); + if (!Array.isArray(group.files) || group.files.length === 0) + throw error(`${groupLabel}.files`, 'must contain frozen legal file locators'); + const members = new Set(); + for (const [fileIndex, raw] of group.files.entries()) { + const fileLabel = `${groupLabel}.files[${fileIndex}]`; + const file = exactKeys(raw, ['bytes', 'kind', 'member', 'sha256'], fileLabel); + safeArchiveMember(file.member, `${fileLabel}.member`); + const relative = file.member.startsWith(contract.prefix) + ? file.member.slice(contract.prefix.length) + : ''; + const notice = /^THIRD_PARTY_NOTICES(?:[.][A-Za-z0-9_-]+)*[.]md$/u.test(relative); + const license = relative === 'LICENSE' || relative.startsWith('THIRD_PARTY_LICENSES/'); + if ((!notice && !license) || file.kind !== (notice ? 'notice' : 'license')) + throw error(fileLabel, 'must address a legal file under the canonical asset root'); + if (members.has(file.member)) throw error(fileLabel, 'repeats a legal archive member'); + members.add(file.member); + if (!Number.isSafeInteger(file.bytes) || file.bytes <= 0) + throw error(`${fileLabel}.bytes`, 'must be a positive safe integer'); + if (typeof file.sha256 !== 'string' || !/^[0-9a-f]{64}$/u.test(file.sha256)) + throw error(`${fileLabel}.sha256`, 'must be a lowercase SHA-256 digest'); + } + if (!members.has(`${contract.prefix}LICENSE`)) + throw error(groupLabel, 'must contain the canonical LICENSE locator'); + } +} + +/** + * Validate the carrier embedded in an Oliphaunt Swift source tag. + * + * Source tags intentionally freeze only the compatible native base. Optional + * extensions are supplied by their independently versioned release carriers, + * so both carrier and extension inventories must remain empty here. + */ +export function validateSelectionNeutralSwiftSourceCarrier( + document, + label = 'oliphaunt-swift source-tag carrier', + { expectedBaseLegal } = {}, +) { + const root = exactKeys(document, ['base', 'carriers', 'extensions', 'legal', 'schema'], label); + if (root.schema !== IOS_CARRIER_SCHEMA) { + throw error(label, `schema must be ${IOS_CARRIER_SCHEMA}`); + } + if (!Array.isArray(root.carriers) || root.carriers.length !== 0) { + throw error( + `${label}.carriers`, + 'must be an empty array; source tags do not own extension payload carriers', + ); + } + if (!Array.isArray(root.extensions) || root.extensions.length !== 0) { + throw error(`${label}.extensions`, 'must be an empty array; source tags are selection-neutral'); + } + const legal = exactKeys(root.legal, ['base', 'extensions'], `${label}.legal`); + if (!Array.isArray(legal.extensions) || legal.extensions.length !== 0) { + throw error( + `${label}.legal.extensions`, + 'must be empty for a selection-neutral source carrier', + ); + } + validateFrozenLegalMetadata(legal.base, `${label}.legal.base`); + if ( + expectedBaseLegal !== undefined && + JSON.stringify(legal.base) !== JSON.stringify(expectedBaseLegal) + ) { + throw error(`${label}.legal.base`, 'must match the canonical native Apple legal locators'); + } + + const base = exactKeys(root.base, ['assets', 'product', 'tag', 'version'], `${label}.base`); + if (base.product !== 'liboliphaunt-native') { + throw error(`${label}.base.product`, 'must be liboliphaunt-native'); + } + if (typeof base.version !== 'string' || !STABLE_SEMVER.test(base.version)) { + throw error(`${label}.base.version`, 'must be a stable SemVer X.Y.Z version'); + } + const expectedTag = `${base.product}-v${base.version}`; + if (base.tag !== expectedTag) { + throw error(`${label}.base.tag`, `must be ${expectedTag}`); + } + + const assetContracts = [ + { + format: 'zip', + member: 'liboliphaunt.xcframework', + name: `liboliphaunt-${base.version}-apple-spm-xcframework.zip`, + role: 'base-xcframework', + }, + { + format: 'tar.gz', + member: 'oliphaunt', + name: `liboliphaunt-${base.version}-runtime-resources-ios-datum64.tar.gz`, + role: 'runtime-resources', + }, + ]; + if (!Array.isArray(base.assets) || base.assets.length !== assetContracts.length) { + throw error( + `${label}.base.assets`, + `must contain exactly ${assetContracts.length} native base assets`, + ); + } + for (const [index, contract] of assetContracts.entries()) { + const assetLabel = `${label}.base.assets[${index}]`; + const asset = exactKeys( + base.assets[index], + ['bytes', 'format', 'member', 'name', 'role', 'sha256', 'url'], + assetLabel, + ); + portableFilename(asset.name, `${assetLabel}.name`); + safeArchiveMember(asset.member, `${assetLabel}.member`); + for (const key of ['format', 'member', 'name', 'role']) { + if (asset[key] !== contract[key]) { + throw error(`${assetLabel}.${key}`, `must be ${contract[key]}`); + } + } + if (!Number.isSafeInteger(asset.bytes) || asset.bytes <= 0) { + throw error(`${assetLabel}.bytes`, 'must be a positive safe integer'); + } + if (typeof asset.sha256 !== 'string' || !/^[0-9a-f]{64}$/u.test(asset.sha256)) { + throw error(`${assetLabel}.sha256`, 'must be a lowercase SHA-256 digest'); + } + let assetUrl; + try { + assetUrl = new URL(asset.url); + } catch { + throw error(`${assetLabel}.url`, 'must be an absolute HTTPS URL'); + } + let urlName; + try { + urlName = decodeURIComponent(path.posix.basename(assetUrl.pathname)); + } catch { + throw error(`${assetLabel}.url`, 'contains invalid percent encoding'); + } + if ( + assetUrl.protocol !== 'https:' || + assetUrl.username !== '' || + assetUrl.password !== '' || + assetUrl.search !== '' || + assetUrl.hash !== '' || + urlName !== asset.name + ) { + throw error( + `${assetLabel}.url`, + `must be a credential-free HTTPS URL ending in ${asset.name}`, + ); + } + const urlParts = assetUrl.pathname + .split('/') + .filter(Boolean) + .map((part) => { + try { + return decodeURIComponent(part); + } catch { + throw error(`${assetLabel}.url`, 'contains invalid percent encoding'); + } + }); + if ( + urlParts.length < 4 || + JSON.stringify(urlParts.slice(-4)) !== + JSON.stringify(['releases', 'download', expectedTag, asset.name]) + ) { + throw error( + `${assetLabel}.url`, + `must address ${asset.name} under release tag ${expectedTag}`, + ); + } + } + return root; +} + +export function validateFrozenNativeCarrierIdentity({ + carrier, + expectedNativeVersion, + repository = CANONICAL_REPOSITORY, + label = 'selection-neutral Apple carrier', + expectedBaseLegal, +}) { + if (repository !== CANONICAL_REPOSITORY) { + throw error(`${label}.repository`, `must be ${CANONICAL_REPOSITORY}`); + } + const validated = validateSelectionNeutralSwiftSourceCarrier(carrier, `${label}.carrier`, { + expectedBaseLegal, + }); + if (expectedNativeVersion !== undefined && validated.base.version !== expectedNativeVersion) { + throw error( + `${label}.carrier.base.version`, + `must match liboliphaunt-native ${expectedNativeVersion}`, + ); + } + for (const asset of validated.base.assets) { + const expectedUrl = `${repository}/releases/download/${validated.base.tag}/${asset.name}`; + if (asset.url !== expectedUrl) { + throw error(`${label}.carrier.base.assets.${asset.role}.url`, `must be ${expectedUrl}`); + } + } + return validated; +} diff --git a/src/native/sdks/swift/tools/swift-release-manifest.mts b/src/native/sdks/swift/tools/swift-release-manifest.mts new file mode 100644 index 000000000..76bff8c3d --- /dev/null +++ b/src/native/sdks/swift/tools/swift-release-manifest.mts @@ -0,0 +1,84 @@ +export function renderSwiftReleaseManifest( + assetBaseUrl: string, + liboliphauntVersion: string, + checksum: string, + bindingsUrl: string, + bindingsChecksum: string, +): string { + const asset = `liboliphaunt-${liboliphauntVersion}-apple-spm-xcframework.zip`; + const url = `${assetBaseUrl.replace(/\/+$/u, '')}/${asset}`; + return `// swift-tools-version: 6.0 + +import PackageDescription + +// Generated by src/native/sdks/swift/tools/render_swiftpm_release_package.mts. +// This is the public SwiftPM release manifest. The source package under +// src/native/sdks/swift remains the local development package. +// Exact PostgreSQL extensions are released as separate opt-in extension +// artifacts. The base Swift package must not require or publish extension files. +let package = Package( + name: "Oliphaunt", + platforms: [ + .iOS(.v17), + .macOS(.v14) + ], + products: [ + .library(name: "COliphaunt", targets: ["COliphaunt"]), + .library(name: "Oliphaunt", targets: ["Oliphaunt"]), + .library(name: "OliphauntCore", targets: ["OliphauntCore"]), + .library(name: "OliphauntBroker", targets: ["OliphauntBroker"]), + .library(name: "OliphauntBrokerExtension", targets: ["OliphauntBrokerExtension"]), + .library(name: "OliphauntExtensionSupport", targets: ["OliphauntExtensionSupport"]) + ], + targets: [ + .binaryTarget( + name: "OliphauntNativeBindingsFFI", + url: "${bindingsUrl}", + checksum: "${bindingsChecksum}" + ), + .target( + name: "OliphauntNativeBindings", + dependencies: ["OliphauntNativeBindingsFFI"], + path: "src/sdks/swift/Sources/OliphauntNativeBindings" + ), + .binaryTarget( + name: "liboliphaunt", + url: "${url}", + checksum: "${checksum}" + ), + .target( + name: "COliphaunt", + dependencies: ["liboliphaunt"], + path: "src/sdks/swift/Sources/COliphaunt", + publicHeadersPath: "include", + cSettings: [.define("OLIPHAUNT_LINK_RUNTIME")] + ), + .target( + name: "OliphauntCore", + dependencies: ["OliphauntNativeBindings"], + path: "src/sdks/swift/Sources/OliphauntCore" + ), + .target( + name: "OliphauntBroker", + dependencies: ["OliphauntCore", "OliphauntNativeBindings"], + path: "src/sdks/swift/Sources/OliphauntBroker" + ), + .target( + name: "OliphauntBrokerExtension", + dependencies: ["Oliphaunt", "OliphauntCore", "OliphauntNativeBindings"], + path: "src/sdks/swift/Sources/OliphauntBrokerExtension" + ), + .target( + name: "Oliphaunt", + dependencies: ["COliphaunt", "OliphauntCore", "OliphauntNativeBindings"], + path: "src/sdks/swift/Sources/Oliphaunt" + ), + .target( + name: "OliphauntExtensionSupport", + dependencies: ["COliphaunt", "Oliphaunt"], + path: "src/sdks/swift/Sources/OliphauntExtensionSupport" + ) + ] +) +`; +} diff --git a/src/native/sdks/swift/tools/swift-source-carrier-contract.mts b/src/native/sdks/swift/tools/swift-source-carrier-contract.mts index 36a5fa99f..e5ecb9a86 100644 --- a/src/native/sdks/swift/tools/swift-source-carrier-contract.mts +++ b/src/native/sdks/swift/tools/swift-source-carrier-contract.mts @@ -1,209 +1,57 @@ import { readFileSync } from 'node:fs'; -import path from 'node:path'; - -import { IOS_CARRIER_SCHEMA, iosBaseLegalMetadata } from './ios-carrier-manifest.mts'; +import { iosBaseLegalMetadata } from './ios-carrier-manifest.mts'; +import { nativeBaseLegalForSource } from './native-legal-source-basis.mts'; import { parseSwiftReleaseBinaryTarget } from './prepare-swift-release-consumer.mts'; +import { + validateSelectionNeutralSwiftSourceCarrier as validateCarrier, + validateFrozenNativeCarrierIdentity, +} from './swift-native-carrier-contract.mts'; -const STABLE_SEMVER = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u; const CANONICAL_REPOSITORY = 'https://github.com/f0rr0/oliphaunt'; - -function compareText(left, right) { - return left < right ? -1 : left > right ? 1 : 0; -} - function error(label, message) { return new Error(`${label}: ${message}`); } -function exactKeys(value, expected, label) { - if (value === null || Array.isArray(value) || typeof value !== 'object') { - throw error(label, 'must be an object'); - } - const actual = Object.keys(value).sort(compareText); - const canonical = [...expected].sort(compareText); - if (JSON.stringify(actual) !== JSON.stringify(canonical)) { - throw error(label, `fields must be exactly ${canonical.join(',')}; got ${actual.join(',')}`); - } - return value; -} - -function safeArchiveMember(value, label) { - if ( - typeof value !== 'string' || - value.length === 0 || - value.includes('\\') || - value.startsWith('/') || - /^[A-Za-z]:/u.test(value) || - /[\u0000-\u001f\u007f]/u.test(value) - ) { - throw error(label, 'must be a safe POSIX archive path'); - } - if (value === '.') return value; - const parts = value.split('/'); - if (parts.some((part) => part.length === 0 || part === '.' || part === '..')) { - throw error(label, 'must be a safe POSIX archive path'); - } - return value; -} - -function portableFilename(value, label) { - if ( - typeof value !== 'string' || - value.length === 0 || - path.posix.basename(value) !== value || - /[<>:"/\\|?*\u0000-\u001f\u007f]/u.test(value) || - /[ .]$/u.test(value) || - /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu.test(value) - ) { - throw error(label, 'must be a portable release asset filename'); - } - return value; -} - -/** - * Validate the carrier embedded in an Oliphaunt Swift source tag. - * - * Source tags intentionally freeze only the compatible native base. Optional - * extensions are supplied by their independently versioned release carriers, - * so both carrier and extension inventories must remain empty here. - */ +// Fresh source binds current legal bytes. Held source requires an independently +// authenticated publication basis; the incoming carrier cannot define its own +// expected legal metadata. export function validateSelectionNeutralSwiftSourceCarrier( document, label = 'oliphaunt-swift source-tag carrier', + { sourceBasis = undefined } = {}, ) { - const root = exactKeys(document, ['base', 'carriers', 'extensions', 'legal', 'schema'], label); - if (root.schema !== IOS_CARRIER_SCHEMA) { - throw error(label, `schema must be ${IOS_CARRIER_SCHEMA}`); - } - if (!Array.isArray(root.carriers) || root.carriers.length !== 0) { - throw error( - `${label}.carriers`, - 'must be an empty array; source tags do not own extension payload carriers', - ); - } - if (!Array.isArray(root.extensions) || root.extensions.length !== 0) { - throw error(`${label}.extensions`, 'must be an empty array; source tags are selection-neutral'); - } - const legal = exactKeys(root.legal, ['base', 'extensions'], `${label}.legal`); - if (!Array.isArray(legal.extensions) || legal.extensions.length !== 0) { - throw error( - `${label}.legal.extensions`, - 'must be empty for a selection-neutral source carrier', - ); - } - if (JSON.stringify(legal.base) !== JSON.stringify(iosBaseLegalMetadata())) { - throw error(`${label}.legal.base`, 'must match the canonical native Apple legal locators'); - } - - const base = exactKeys(root.base, ['assets', 'product', 'tag', 'version'], `${label}.base`); - if (base.product !== 'liboliphaunt-native') { - throw error(`${label}.base.product`, 'must be liboliphaunt-native'); - } - if (typeof base.version !== 'string' || !STABLE_SEMVER.test(base.version)) { - throw error(`${label}.base.version`, 'must be a stable SemVer X.Y.Z version'); - } - const expectedTag = `${base.product}-v${base.version}`; - if (base.tag !== expectedTag) { - throw error(`${label}.base.tag`, `must be ${expectedTag}`); - } + return validateCarrier(document, label, { + expectedBaseLegal: nativeBaseLegalForSource({ + base: document?.base, + sourceBasis, + currentLegal: iosBaseLegalMetadata, + }), + }); +} - const assetContracts = [ - { - format: 'zip', - member: 'liboliphaunt.xcframework', - name: `liboliphaunt-${base.version}-apple-spm-xcframework.zip`, - role: 'base-xcframework', - }, - { - format: 'tar.gz', - member: 'oliphaunt', - name: `liboliphaunt-${base.version}-runtime-resources-ios-datum64.tar.gz`, - role: 'runtime-resources', - }, - ]; - if (!Array.isArray(base.assets) || base.assets.length !== assetContracts.length) { - throw error( - `${label}.base.assets`, - `must contain exactly ${assetContracts.length} native base assets`, - ); - } - for (const [index, contract] of assetContracts.entries()) { - const assetLabel = `${label}.base.assets[${index}]`; - const asset = exactKeys( - base.assets[index], - ['bytes', 'format', 'member', 'name', 'role', 'sha256', 'url'], - assetLabel, - ); - portableFilename(asset.name, `${assetLabel}.name`); - safeArchiveMember(asset.member, `${assetLabel}.member`); - for (const key of ['format', 'member', 'name', 'role']) { - if (asset[key] !== contract[key]) { - throw error(`${assetLabel}.${key}`, `must be ${contract[key]}`); - } - } - if (!Number.isSafeInteger(asset.bytes) || asset.bytes <= 0) { - throw error(`${assetLabel}.bytes`, 'must be a positive safe integer'); - } - if (typeof asset.sha256 !== 'string' || !/^[0-9a-f]{64}$/u.test(asset.sha256)) { - throw error(`${assetLabel}.sha256`, 'must be a lowercase SHA-256 digest'); - } - let assetUrl; - try { - assetUrl = new URL(asset.url); - } catch { - throw error(`${assetLabel}.url`, 'must be an absolute HTTPS URL'); - } - let urlName; - try { - urlName = decodeURIComponent(path.posix.basename(assetUrl.pathname)); - } catch { - throw error(`${assetLabel}.url`, 'contains invalid percent encoding'); - } - if ( - assetUrl.protocol !== 'https:' || - assetUrl.username !== '' || - assetUrl.password !== '' || - assetUrl.search !== '' || - assetUrl.hash !== '' || - urlName !== asset.name - ) { - throw error( - `${assetLabel}.url`, - `must be a credential-free HTTPS URL ending in ${asset.name}`, - ); - } - const urlParts = assetUrl.pathname - .split('/') - .filter(Boolean) - .map((part) => { - try { - return decodeURIComponent(part); - } catch { - throw error(`${assetLabel}.url`, 'contains invalid percent encoding'); - } - }); - if ( - urlParts.length < 4 || - JSON.stringify(urlParts.slice(-4)) !== - JSON.stringify(['releases', 'download', expectedTag, asset.name]) - ) { - throw error( - `${assetLabel}.url`, - `must address ${asset.name} under release tag ${expectedTag}`, - ); - } - } - return root; +export function validateSelectionNeutralSwiftCarrierIdentity(options) { + return validateFrozenNativeCarrierIdentity({ + ...options, + expectedBaseLegal: nativeBaseLegalForSource({ + base: options.carrier?.base, + sourceBasis: options.sourceBasis, + currentLegal: iosBaseLegalMetadata, + }), + }); } -export function validateSelectionNeutralSwiftSourceCarrierFile(carrier, label = String(carrier)) { +export function validateSelectionNeutralSwiftSourceCarrierFile( + carrier, + label = String(carrier), + options = {}, +) { let document; try { document = JSON.parse(readFileSync(carrier, 'utf8')); } catch (cause) { throw error(label, `is not valid JSON: ${cause.message}`); } - return validateSelectionNeutralSwiftSourceCarrier(document, label); + return validateSelectionNeutralSwiftSourceCarrier(document, label, options); } /** @@ -212,43 +60,20 @@ export function validateSelectionNeutralSwiftSourceCarrierFile(carrier, label = * release graph. This contract is shared by SwiftPM source tags and the * carrier embedded in the React Native npm package. */ -export function validateSelectionNeutralSwiftCarrierIdentity({ - carrier, - expectedNativeVersion, - repository = CANONICAL_REPOSITORY, - label = 'selection-neutral Apple carrier', -}) { - if (repository !== CANONICAL_REPOSITORY) { - throw error(`${label}.repository`, `must be ${CANONICAL_REPOSITORY}`); - } - const validated = validateSelectionNeutralSwiftSourceCarrier(carrier, `${label}.carrier`); - if (expectedNativeVersion !== undefined && validated.base.version !== expectedNativeVersion) { - throw error( - `${label}.carrier.base.version`, - `must match liboliphaunt-native ${expectedNativeVersion}`, - ); - } - for (const asset of validated.base.assets) { - const expectedUrl = `${repository}/releases/download/${validated.base.tag}/${asset.name}`; - if (asset.url !== expectedUrl) { - throw error(`${label}.carrier.base.assets.${asset.role}.url`, `must be ${expectedUrl}`); - } - } - return validated; -} - export function validateSwiftSourceReleaseContract({ carrier, manifestText, expectedNativeVersion, repository = CANONICAL_REPOSITORY, label = 'oliphaunt-swift source release', + sourceBasis = undefined, }) { const validated = validateSelectionNeutralSwiftCarrierIdentity({ carrier, expectedNativeVersion, repository, label, + sourceBasis, }); const binaryTarget = parseSwiftReleaseBinaryTarget( manifestText, diff --git a/src/native/sdks/swift/tools/swift-source-fixture-contract.mts b/src/native/sdks/swift/tools/swift-source-fixture-contract.mts new file mode 100644 index 000000000..93e9460e7 --- /dev/null +++ b/src/native/sdks/swift/tools/swift-source-fixture-contract.mts @@ -0,0 +1,35 @@ +import assert from 'node:assert/strict'; + +export const SWIFT_SOURCE_FIXTURE_PREFIX = 'package/Tests/Fixtures/swiftpm-extension-resources/'; + +/** Only the declared, byte-identical test fixtures may contain runtime payloads. */ +export function validateSwiftSourceFixtureEntries( + artifact: string, + entries: Map, + expected: Map, +): Set { + assert(entries instanceof Map, `${artifact} Swift source fixture entries must be a Map`); + const expectedNames = [...expected.keys()].sort(); + const actualNames = [...entries] + .filter(([name, entry]) => name.startsWith(SWIFT_SOURCE_FIXTURE_PREFIX) && entry.isFile) + .map(([name]) => name) + .sort(); + const expectedSet = new Set(expectedNames); + const actualSet = new Set(actualNames); + assert.deepEqual( + actualNames, + expectedNames, + `${artifact} Swift source fixture file set must exactly match declared inputs; missing=${JSON.stringify(expectedNames.filter((name) => !actualSet.has(name)))}, extra=${JSON.stringify(actualNames.filter((name) => !expectedSet.has(name)))}`, + ); + for (const name of expectedNames) { + assert(name.startsWith(SWIFT_SOURCE_FIXTURE_PREFIX), 'unexpected declared Swift fixture'); + const entry = entries.get(name); + const bytes = expected.get(name); + assert(entry?.isFile && bytes, `${artifact} is missing declared Swift fixture ${name}`); + assert( + Buffer.from(entry.data()).equals(Buffer.from(bytes)), + `${artifact} Swift source fixture ${name} must byte-for-byte match declared input`, + ); + } + return expectedSet; +} diff --git a/src/native/sdks/swift/tools/swift-xcframework-contract.mts b/src/native/sdks/swift/tools/swift-xcframework-contract.mts new file mode 100644 index 000000000..1a6de0520 --- /dev/null +++ b/src/native/sdks/swift/tools/swift-xcframework-contract.mts @@ -0,0 +1,270 @@ +import { readPortableArchiveEntries } from '../../../../../tools/packaging/portable-archive.mts'; + +function fail(message: string): never { + throw new Error(message); +} + +async function readZipArchive(file) { + const entries = readPortableArchiveEntries(file, { format: 'zip' }); + return { + names: new Set(entries.keys()), + read(entryName) { + const entry = entries.get(entryName); + return entry?.isFile ? Buffer.from(entry.data()) : undefined; + }, + }; +} + +/** The conventional native requirement owns the SDK's delivered ABI header. */ +export function readNativeAppleHeader(file: string): Buffer { + const headers = [...readPortableArchiveEntries(file, { format: 'zip' }).values()] + .filter( + (entry) => + entry.isFile && /^liboliphaunt\.xcframework\/.+\/Headers\/oliphaunt\.h$/u.test(entry.name), + ) + .map((entry) => Buffer.from(entry.data())); + if (headers.length < 3 || !headers[0].length) + fail('Selected native XCFramework must ship all public C headers'); + if (headers.some((header) => !header.equals(headers[0]))) + fail('Selected native XCFramework slices declare different public C headers'); + return headers[0]; +} + +function xmlDecode(value) { + return value + .replaceAll('"', '"') + .replaceAll(''', "'") + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('&', '&'); +} + +function tokenizeXml(text) { + return Array.from(text.matchAll(/<[^>]+>|[^<]+/gu), (match) => match[0]); +} + +function tagName(token) { + return token + .replace(/^<\//u, '') + .replace(/^$/u, '') + .trim() + .split(/\s+/u)[0]; +} + +class PlistParser { + constructor(text) { + this.tokens = tokenizeXml(text); + this.index = 0; + } + + parse() { + const token = this.nextToken(); + if (!this.isOpening(token, 'plist')) { + throw new Error('plist root element is missing'); + } + const value = this.parseValue(); + const closing = this.nextToken(); + if (!this.isClosing(closing, 'plist')) { + throw new Error('plist root element is not closed'); + } + return value; + } + + nextToken() { + while (this.index < this.tokens.length) { + const token = this.tokens[this.index]; + this.index += 1; + if (!token.startsWith('<') && token.trim() === '') { + continue; + } + if (token.startsWith('') + ); + } + + isClosing(token, name) { + return token.startsWith(''); + } + + parseValue() { + const token = this.nextToken(); + if (this.isOpening(token, 'dict')) { + return this.parseDict(); + } + if (this.isOpening(token, 'array')) { + return this.parseArray(); + } + if (this.isOpening(token, 'string')) { + return this.parseTextElement('string'); + } + if (this.isSelfClosing(token, 'string')) { + return ''; + } + if (this.isOpening(token, 'integer')) { + return Number.parseInt(this.parseTextElement('integer'), 10); + } + if (this.isSelfClosing(token, 'true')) { + return true; + } + if (this.isSelfClosing(token, 'false')) { + return false; + } + throw new Error(`unsupported plist value ${token}`); + } + + parseDict() { + const result = {}; + while (true) { + const token = this.peekToken(); + if (this.isClosing(token, 'dict')) { + this.nextToken(); + return result; + } + const keyOpen = this.nextToken(); + if (!this.isOpening(keyOpen, 'key')) { + throw new Error(`expected plist dict key, got ${keyOpen}`); + } + const key = this.parseTextElement('key'); + result[key] = this.parseValue(); + } + } + + parseArray() { + const result = []; + while (true) { + const token = this.peekToken(); + if (this.isClosing(token, 'array')) { + this.nextToken(); + return result; + } + result.push(this.parseValue()); + } + } + + parseTextElement(name) { + let text = ''; + while (true) { + const token = this.nextToken(); + if (this.isClosing(token, name)) { + return xmlDecode(text); + } + if (token.startsWith('<')) { + throw new Error(`unexpected tag in plist ${name}: ${token}`); + } + text += token; + } + } +} + +function parsePlist(buffer, source) { + const prefix = buffer.subarray(0, 6).toString('utf8'); + if (prefix === 'bplist') { + fail(`SwiftPM Apple XCFramework Info.plist must be XML for release validation: ${source}`); + } + try { + return new PlistParser(buffer.toString('utf8')).parse(); + } catch (error) { + fail(`SwiftPM Apple XCFramework Info.plist is invalid in ${source}: ${error.message}`); + } +} + +export async function validateAppleXcframeworkAsset(file, framework = 'liboliphaunt') { + let archive; + try { + archive = await readZipArchive(file); + } catch (error) { + fail(`SwiftPM Apple XCFramework asset is not a readable zip file: ${file}: ${error.message}`); + } + const infoData = archive.read(`${framework}.xcframework/Info.plist`); + if (infoData === undefined) { + fail(`SwiftPM Apple XCFramework asset is missing ${framework}.xcframework/Info.plist: ${file}`); + } + const info = parsePlist(infoData, file); + if (info === null || Array.isArray(info) || typeof info !== 'object') { + fail(`SwiftPM Apple XCFramework Info.plist must be a plist dictionary in ${file}`); + } + const libraries = info.AvailableLibraries; + if (!Array.isArray(libraries) || libraries.length === 0) { + fail(`SwiftPM Apple XCFramework Info.plist has no AvailableLibraries in ${file}`); + } + + const slices = new Set(); + for (const library of libraries) { + if (library === null || Array.isArray(library) || typeof library !== 'object') { + continue; + } + const platform = library.SupportedPlatform; + const variant = library.SupportedPlatformVariant ?? ''; + const libraryPath = library.LibraryPath; + const identifier = library.LibraryIdentifier; + const architectures = library.SupportedArchitectures; + if ( + typeof platform !== 'string' || + typeof libraryPath !== 'string' || + typeof identifier !== 'string' || + !Array.isArray(architectures) || + architectures.some((architecture) => typeof architecture !== 'string') + ) { + continue; + } + for (const architecture of architectures) { + slices.add(`${platform}\0${typeof variant === 'string' ? variant : ''}\0${architecture}`); + } + const candidate = `${framework}.xcframework/${identifier}/${libraryPath}`; + if ( + !archive.names.has(candidate) && + !Array.from(archive.names).some((name) => name.startsWith(`${candidate}/`)) + ) { + fail(`SwiftPM Apple XCFramework is missing declared library ${candidate}`); + } + } + + const missing = missingRequiredAppleArm64Slices(slices); + if (missing.length > 0) { + fail( + `SwiftPM Apple XCFramework asset ${file} is missing required arm64 slice(s): ${missing.join(', ')}`, + ); + } +} + +export function missingRequiredAppleArm64Slices(slices) { + const required = [ + ['macos', '', 'arm64'], + ['ios', '', 'arm64'], + ['ios', 'simulator', 'arm64'], + ]; + return required + .filter( + ([platform, variant, architecture]) => + !slices.has(`${platform}\0${variant}\0${architecture}`), + ) + .map( + ([platform, variant, architecture]) => + `${platform}${variant ? `-${variant}` : ''}-${architecture}`, + ) + .sort(); +} diff --git a/src/native/sdks/ts/BUILD.bazel b/src/native/sdks/ts/BUILD.bazel new file mode 100644 index 000000000..67ce45984 --- /dev/null +++ b/src/native/sdks/ts/BUILD.bazel @@ -0,0 +1,269 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("@aspect_rules_js//js:defs.bzl", "js_library") +load("@aspect_rules_ts//ts:defs.bzl", "ts_config", "ts_project") +load("@oliphaunt_javascript_metadata//:metadata.bzl", "JAVASCRIPT") +load("@oliphaunt_metadata//:metadata.bzl", "PUBLICATION_CARRIERS") +load("@javascript_packages//:defs.bzl", "PACKAGES", "javascript_type_links") +load("@javascript_compiler_packages//:defs.bzl", "compiler_input_links") +load("@javascript_compiler_packages//:roots.bzl", "COMPILER_INPUTS") +load("//build_defs/extensions:sdk_projections.bzl", "sdk_extension_projections") +load("//build_defs/languages/ts:defs.bzl", "workspace_dependency_package", "workspace_dependency_link", "source_sdk_consumer_test", "source_sdk_publish_files") +load("//build_defs/languages/ts:unit-tests.bzl", "sdk_unit_test") +load("//build_defs/query:defs.bzl", "query_envelope") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") + +package(default_visibility = ["//visibility:public"]) + +_MODULE_OUT_DIR = "lib" + +exports_files(["package.json", "release.toml"]) +exports_files(["src/native/extension-contract.ts"]) +exports_files(["src/__tests__/native-smoke.mts", "src/__tests__/native-direct-contract.mts", "src/__tests__/native-server-smoke.ts"]) + +SDK = JAVASCRIPT["@oliphaunt/ts"] +QUERY = JAVASCRIPT["@oliphaunt/ts-query"] + +SDK_SRCS = glob(["src/**/*.ts"], exclude = ["src/__tests__/**", "src/extensions.ts", "src/generated/extensions.ts"]) + +filegroup(name = "native_asset_sources", srcs = SDK_SRCS + [":extension_projections", "package.json"]) + +javascript_type_links(SDK["types"]) +compiler_input_links(COMPILER_INPUTS[SDK["name"]]) + +workspace_dependency_package(name = "query_package", workspace = SDK, dependency = QUERY["name"], current = "//src/query/ts:shipping_package") + +workspace_dependency_link(name = "node_modules/@oliphaunt/ts-query", package = ":query_package", workspace = SDK, dependency = QUERY["name"]) + +js_library(name = "package_metadata", srcs = ["package.json"]) +ts_config(name = "source_config", src = "tsconfig.json") + +js_library( + name = "source_inputs", + types = SDK_SRCS + [":extension_projections"], + deps = [":package_metadata"] + [":node_modules/" + name for name in SDK["types"]], +) + +sdk_extension_projections(name = "extension_projections", sdk = "ts") + +ts_project( + name = "module", + srcs = SDK_SRCS + [":extension_projections"], + tsconfig = "tsconfig.build.json", + extends = "tsconfig.json", + declaration = True, + declaration_map = True, + out_dir = _MODULE_OUT_DIR, + root_dir = "src", + transpiler = "tsc", + supports_workers = 0, + deps = [":package_metadata", ":node_modules/@oliphaunt/ts-query"] + [":node_modules/" + name for name in SDK["types"]], +) + +source_sdk_publish_files(name = "publish_files", manifest = "package.json") + +# The build configuration excludes tests; use the conventional source configuration +# for this independently requested typecheck, without constructing native packages. +ts_project( + name = "source_checks", + srcs = SDK_SRCS + glob(["src/__tests__/**/*.ts"]) + [":extension_projections"], + tsconfig = "tsconfig.json", + no_emit = True, + declaration = True, + declaration_map = True, + out_dir = _MODULE_OUT_DIR, + root_dir = "src", + supports_workers = 0, + deps = [":package_metadata", ":node_modules/@oliphaunt/ts-query"] + [":node_modules/" + name for name in SDK["types"]] + [":node_modules/" + name for name in COMPILER_INPUTS[SDK["name"]]], +) + +filegroup(name = "publish_manifest", srcs = [":publish_files"], output_group = "manifest") +filegroup(name = "license", srcs = [":publish_files"], output_group = "license") +filegroup(name = "notices", srcs = [":publish_files"], output_group = "notices") + +query_envelope( + name = "npm", + format = "npm", + manifest = ":publish_manifest", + entries = {file: file for file in SDK_SRCS} | { + ":module": "lib/", + ":extension_projections": "src/", + ":publish_manifest": "package.json", + ":license": "LICENSE", + ":notices": "THIRD_PARTY_NOTICES.md", + "README.md": "README.md", + "ARCHITECTURE.md": "ARCHITECTURE.md", + "CHANGELOG.md": "CHANGELOG.md", + }, + out = "oliphaunt-ts.tgz", +) + +shipping_package( + name = "shipping_package", + owner = "@oliphaunt_metadata//:product_oliphaunt-js", + artifacts = [":npm"], + ecosystem = "npm", + package_name = SDK["name"], + configuration = "portable", + role = [carrier["role"] for carrier in PUBLICATION_CARRIERS if carrier["product"] == "oliphaunt-js" and carrier["ecosystem"] == "npm" and carrier["name"] == SDK["name"]][0], + suppliers = "//build_defs/release:no_suppliers", +) + +shipping_export(name = "shipping_export", packages = [":shipping_package"], qualification = [":consumer_test", "//build_defs/languages/carriers:installed_sql_test", ":unit_test", ":package_policy_test"], testonly = True) + +source_sdk_consumer_test( + name = "consumer_test", + size = "small", + archive = ":npm", + query = ":query_package", + consumer = "tools/entrypoint-consumer.mts", + type_packages = {"@javascript_packages//:" + key: key for key in PACKAGES}, + types = SDK["types"], +) + +sdk_unit_test( + name = "unit_test", + manifest = "package.json", + sources = glob(["src/**/*.ts"], exclude = ["src/extensions.ts", "src/generated/extensions.ts"]) + glob(["src/**/*.mts", "src/**/*.json"], allow_empty = True) + [":extension_projections"], + fixtures = ["//src/test-fixtures:rust_fixtures"], + packages = {":query_package": QUERY["name"]}, + package_manifests = ["//src/native/runtime:packages/" + target + "/package.json" for target in ["linux-x64-gnu", "linux-arm64-gnu", "darwin-arm64", "win32-x64-msvc"]], + size = "small", +) + +source_quality_files(exclude = [_MODULE_OUT_DIR + "/**"]) + +# Existing operational package policy tests use only this declared source closure. +sdk_unit_test( + name = "package_policy_test", + manifest = "package.json", + tests = ["tools/published-consumer.test.mts"], + sources = [ + "//build_defs/languages/swift:source-delivery-contract.mts", + "//build_defs/languages:source-package.mts", + "//build_defs/resources:seed_construction.mts", + "//build_defs/wasix/browser:metadata.mts", + "//build_defs/wasix/browser:provenance.mts", + "//src/database-resources:contracts/native-manifest.mts", + "//src/database-resources:seeds/carrier-identities.mts", + "//src/database-resources/seeds/wasix:consumer-contract.mts", + "//:src/examples/tools/example-release-dependencies.mts", + "//:src/extensions/artifacts/packages/tools/contrib-carriers.mts", + "//:src/extensions/artifacts/packages/tools/extension-registry-packages.mts", + "//:src/extensions/artifacts/packages/tools/extension-runtime-asset-contract.mts", + "//src/extensions/contracts:extension-target-profiles.mts", + "//src/extensions/contracts:wasix-extension-install.mts", + "//src/extensions/tools:extension-evidence.mts", + "//src/extensions/tools:extension-projections.mts", + "//src/extensions/tools:extension-upstream-licenses.mts", + "//src/extensions/tools:native-component-contract.mts", + "//src/native/mobile-bindings:tools/dependency-license-contract.mts", + "//src/native/runtime:tools/native-runtime-payload.mts", + "//src/native/sdks/swift:tools/extension-release-consumer.mts", + "//src/native/sdks/swift:tools/ios-carrier-manifest.mts", + "//src/native/sdks/swift:tools/native-legal-source-basis.mts", + "//src/native/sdks/swift:tools/prepare-swift-release-consumer.mts", + "//src/native/sdks/swift:tools/swift-extension-fixture-consumer.mts", + "//src/native/sdks/swift:tools/swift-extension-release-consumer-inputs.mts", + "//src/native/sdks/swift:tools/swift-native-carrier-contract.mts", + "//src/native/sdks/swift:tools/swift-release-manifest.mts", + "//src/native/sdks/swift:tools/swift-source-carrier-contract.mts", + "//src/native/sdks/ts:tools/published-consumer.mts", + "//src/wasix/node-addon:tools/carrier-contract.mts", + "//src/wasix/runtime:tools/wasix-cargo-artifact-contract.mts", + "//src/wasix/runtime:tools/wasix-runtime-npm-contract.mts", + "//src/wasix/sdks/ts:tools/package.mts", + "//src/wasix/sdks/ts:tools/wasix-typescript-package.mts", + "//tools/bazel:shipping-coverage.mts", + "//:tools/packaging/archive-directory.mts", + "//:tools/packaging/cargo-manifest.mts", + "//:tools/packaging/cargo-source-package.mts", + "//:tools/packaging/package-archive.mts", + "//:tools/packaging/emit-javascript.mts", + "//:tools/packaging/frozen-cargo.mts", + "//:tools/packaging/maven-artifact-manifest.mts", + "//:tools/packaging/maven-central-contract.mts", + "//:tools/packaging/npm-trusted-publishing.mts", + "//:tools/packaging/platform-binary-contract.mts", + "//:tools/packaging/portable-archive.mts", + "//:tools/packaging/release-directory-safety.mts", + "//:tools/packaging/release-notices.mts", + "//:tools/packaging/rust-dependency-license-contract.mts", + "//:tools/packaging/windows-vc-runtime-closure.mts", + "//tools/release:authenticate-native-build-evidence.mts", + "//tools/release:bazel-shipping-inputs.mts", + "//tools/release:cargo-payload-part-contract.mts", + "//tools/release:check_registry_publication.mts", + "//tools/release:checksum-manifest.mts", + "//tools/release:compatibility-version-parser.mts", + "//tools/release:compatibility-version-policy.mts", + "//tools/release:completed-contrib-carrier-context.mts", + "//tools/release:completed-release-publication.mts", + "//tools/release:completed-swift-source-delivery.mts", + "//tools/release:consumer-compatibility.mts", + "//tools/release:example-cargo-versions.mts", + "//tools/release:extension-release-metadata.mts", + "//tools/release:frozen-consumer.mts", + "//tools/release:frozen-npm-publish.mts", + "//tools/release:github-content-write-pacer.mts", + "//tools/release:github-core-request-journal.mts", + "//tools/release:github-read.mts", + "//tools/release:github-release-lineage.mts", + "//tools/release:github-release-mutations.mts", + "//tools/release:native-build-files.mts", + "//tools/release:native-build-qualification.mts", + "//tools/release:native-build-source-tag.mts", + "//tools/release:native-completed-delivery.mts", + "//tools/release:native-file-identity.mts", + "//tools/release:native-freeze-publication-candidate.mts", + "//tools/release:native-publication-artifacts.mts", + "//tools/release:native-publication-candidate.mts", + "//tools/release:native-publication-delivery.mts", + "//tools/release:native-publication-metadata-contract.mts", + "//tools/release:native-publication-metadata.mts", + "//tools/release:native-publication-observation.mts", + "//tools/release:native-publication-payloads.mts", + "//tools/release:native-publication-staging.mts", + "//tools/release:native-release-inputs.mts", + "//tools/release:native-release-preparation.mts", + "//tools/release:bazel-release-metadata.mts", + "//tools/release:qualified-native-extension-final-inputs.mts", + "//tools/release:native-extension-final-inputs.mts", + "//:src/extensions/artifacts/native/tools/ios-extension-registration.mts", + "//:tools/packaging/rust-native-targets.mts", + "//tools/release:native-seed-baseline.mts", + "//tools/release:native-seed-inputs.mts", + "//tools/release:native-shipping-suppliers.mts", + "//tools/release:native-source-carrier-changes.mts", + "//tools/release:native-supplier-artifacts.mts", + "//tools/release:native-version-source.mts", + "//tools/release:platform-compatibility-policy.mts", + "//tools/release:product-version.mts", + "//tools/release:public-consumer-smoke.mts", + "//tools/release:publication-catalog.mts", + "//tools/release:publication-consumer-proof.mts", + "//tools/release:publication-controller.mts", + "//tools/release:publication-lock.mts", + "//tools/release:with-source.mts", + "//tools/release:registry-http-retry.mts", + "//tools/release:registry-integrity.mts", + "//tools/release:registry-publication-deferral.mts", + "//tools/release:release-artifact-targets.mts", + "//tools/release:release-dependency-plan.mts", + "//tools/release:release-graph.mts", + "//tools/release:release-history.mts", + "//tools/release:release-please-bootstrap.mts", + "//tools/release:release-please-pr-lifecycle.mts", + "//tools/release:release-please-transition.mts", + "//tools/release:retained-download.mts", + "//tools/release:sync-release-pr.mts", + "//tools/release:verify-release-commit.mts", + "//tools/release:verify_github_release_attestations.mts", + ], + fixtures = ["//:LICENSE", "//:tools/packaging/windows-vc-runtime-policy.json", "//src/database-resources:contracts/contract.json"], + size = "small", +) + +test_suite( + name = "source_unit_tests", + tests = [":unit_test", ":package_policy_test"], +) diff --git a/src/native/sdks/ts/README.md b/src/native/sdks/ts/README.md index 213d021b7..4c3b3c7d4 100644 --- a/src/native/sdks/ts/README.md +++ b/src/native/sdks/ts/README.md @@ -8,7 +8,7 @@ Run native PostgreSQL in Node.js, Bun, Deno, or Electron. For browsers, choose [ npm install @oliphaunt/ts ``` -The [quickstart](https://oliphaunt.dev/docs/sdk/typescript) covers prerequisites and the versions documented by the current site. Pin dependencies in your application manifest or lockfile. +The [quickstart](https://oliphaunt.dev/docs/sdk/typescript) covers prerequisites. Pin dependencies in your application manifest or lockfile. ## First query diff --git a/src/native/sdks/ts/src/__tests__/filesystem-durability.test.ts b/src/native/sdks/ts/src/__tests__/filesystem-durability.test.ts index f7d6a5a32..9101d786a 100644 --- a/src/native/sdks/ts/src/__tests__/filesystem-durability.test.ts +++ b/src/native/sdks/ts/src/__tests__/filesystem-durability.test.ts @@ -1,7 +1,9 @@ -import { mkdtemp, mkdir, rm, symlink, writeFile } from 'node:fs/promises'; +import * as fs from 'node:fs/promises'; +import { mkdtemp, mkdir, readFile, rm, symlink, writeFile } from 'node:fs/promises'; +import * as os from 'node:os'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; -import { afterEach, describe, expect, it } from 'bun:test'; +import { afterEach, describe, expect, it, spyOn } from 'bun:test'; import { syncDirectoryTree, syncRuntimeDirectoryTree } from '../native/filesystem-durability.js'; describe('filesystem durability', () => { @@ -11,6 +13,47 @@ describe('filesystem durability', () => { await Promise.all(roots.splice(0).map((root) => rm(root, { force: true, recursive: true }))); }); + it('flushes Windows regular files with write access and preserves flush failures', async () => { + const root = await mkdtemp(join(tmpdir(), 'oliphaunt-windows-sync-')); + roots.push(root); + await mkdir(join(root, 'nested')); + const file = join(root, 'nested', 'payload'); + await writeFile(file, 'durable bytes'); + const originalOpen = fs.open; + const readOnlyHandleError = Object.assign(new Error('FlushFileBuffers requires write access'), { + code: 'EPERM', + }); + let flushFailure: Error | undefined; + const flushed: string[] = []; + const platformSpy = spyOn(os, 'platform').mockReturnValue('win32'); + const openSpy = spyOn(fs, 'open').mockImplementation( + async (...args: Parameters) => { + const handle = await originalOpen(...args); + if ((await handle.stat()).isFile()) { + const sync = handle.sync.bind(handle); + handle.sync = async () => { + if (args[1] === 'r') throw readOnlyHandleError; + if (flushFailure) throw flushFailure; + await sync(); + flushed.push(String(args[0])); + }; + } + return handle; + }, + ); + try { + for (const sync of [syncDirectoryTree, syncRuntimeDirectoryTree]) await sync(root); + expect(flushed).toEqual([file, file]); + expect(await readFile(file, 'utf8')).toBe('durable bytes'); + flushFailure = Object.assign(new Error('regular-file flush failed'), { code: 'EPERM' }); + for (const sync of [syncDirectoryTree, syncRuntimeDirectoryTree]) + await expect(sync(root)).rejects.toBe(flushFailure); + } finally { + openSpy.mockRestore(); + platformSpy.mockRestore(); + } + }); + it.if(process.platform !== 'win32')( 'accepts packaged runtime symlinks without weakening PGDATA publication', async () => { diff --git a/src/native/sdks/ts/src/__tests__/native-resources.test.ts b/src/native/sdks/ts/src/__tests__/native-resources.test.ts index c598fd740..ad3282280 100644 --- a/src/native/sdks/ts/src/__tests__/native-resources.test.ts +++ b/src/native/sdks/ts/src/__tests__/native-resources.test.ts @@ -1,4 +1,4 @@ -import { test, expect } from 'bun:test'; +import { expect, test } from 'bun:test'; import { createHash } from 'node:crypto'; import { mkdir, mkdtemp, rm, symlink, writeFile } from 'node:fs/promises'; import { tmpdir } from 'node:os'; @@ -48,9 +48,16 @@ test('explicit native resources reject incompatible and altered bytes before ini await expect(validateSelectedNativeSeed(seed, 'linux-arm64-gnu', '1.2.3')).rejects.toThrow( 'incompatible', ); + expect(await validateSelectedNativeSeed(seed, 'linux-x64-gnu', '1.2.4')).toEqual({ + catalogProfile: 'standard', + emptyDirectories: ['pg_notify'], + }); + manifest.runtime.version = 'not-a-version'; + await writeFile(seed.manifestPath, JSON.stringify(manifest)); await expect(validateSelectedNativeSeed(seed, 'linux-x64-gnu', '1.2.4')).rejects.toThrow( 'incompatible', ); + manifest.runtime.version = '1.2.3'; manifest.directory.emptyDirectories = ['../escape']; await writeFile(seed.manifestPath, JSON.stringify(manifest)); await expect(validateSelectedNativeSeed(seed, 'linux-x64-gnu', '1.2.3')).rejects.toThrow( diff --git a/src/native/sdks/ts/src/native/assets.ts b/src/native/sdks/ts/src/native/assets.ts index c90cef39a..7b454b903 100644 --- a/src/native/sdks/ts/src/native/assets.ts +++ b/src/native/sdks/ts/src/native/assets.ts @@ -1,5 +1,3 @@ -import { fileURLToPath } from 'node:url'; -import type { NativeExtension } from '../extensions.js'; import { createHash, randomUUID } from 'node:crypto'; import { createReadStream } from 'node:fs'; import { cp, lstat, mkdir, readdir, readFile, rename, rm, stat, writeFile } from 'node:fs/promises'; @@ -7,18 +5,20 @@ import { createRequire } from 'node:module'; import { arch, platform, tmpdir } from 'node:os'; import { dirname, isAbsolute, join, relative, resolve } from 'node:path'; import { setTimeout as delay } from 'node:timers/promises'; +import { fileURLToPath } from 'node:url'; +import type { NativeExtension } from '../extensions.js'; import { GENERATED_EXTENSION_METADATA, type GeneratedExtensionMetadata, generatedExtensionBySqlName, } from '../generated/extensions.js'; +import { validateManagedRoot } from '../root-descriptor.js'; +import type { NativeResourceDirectory } from '../types.js'; import { type NativeCatalogProfile, validateSelectedIcuData, validateSelectedNativeSeed, } from './cluster-seed.js'; -import type { NativeResourceDirectory } from '../types.js'; -import { validateManagedRoot } from '../root-descriptor.js'; import { liboliphauntPackageTarget, type NativePackageTarget, @@ -100,6 +100,7 @@ type NpmExtensionMemberContract = { sqlName: string; createsExtension: boolean; nativeModuleStem: string | null; + nativeDependencyModules: string[]; dependencies: string[]; dataFiles: string[]; extensionSqlFileNames: string[]; @@ -601,8 +602,11 @@ function parseExtensionMemberContract(value: unknown, label: string): NpmExtensi } const row = value as Record; if ( - JSON.stringify(Object.keys(row).sort(compareText)) !== - JSON.stringify(NPM_EXTENSION_CONTRACT_MEMBER_FIELDS) + JSON.stringify( + Object.keys(row) + .filter((field) => field !== 'nativeDependencyModules') + .sort(compareText), + ) !== JSON.stringify(NPM_EXTENSION_CONTRACT_MEMBER_FIELDS) ) { throw new Error( `${label} fields must be exactly ${NPM_EXTENSION_CONTRACT_MEMBER_FIELDS.join(', ')}`, @@ -629,6 +633,19 @@ function parseExtensionMemberContract(value: unknown, label: string): NpmExtensi throw new Error(`${label}.dependencies contains an invalid or self dependency`); } const dataFiles = parseExtensionContractStringList(row.dataFiles, 'dataFiles', label); + const nativeDependencyModules = parseExtensionContractStringList( + row.nativeDependencyModules ?? [], + 'nativeDependencyModules', + label, + ); + if ( + nativeDependencyModules.some((file) => !/^[A-Za-z0-9_-]+\.(?:so|dylib|dll)$/u.test(file)) || + (nativeDependencyModules.length > 0 && row.nativeModuleStem === null) + ) { + throw new Error( + `${label}.nativeDependencyModules must contain portable native module basenames`, + ); + } requirePortableExtensionContractPaths(dataFiles, 'dataFiles', label); const extensionSqlFileNames = parseExtensionContractStringList( row.extensionSqlFileNames, @@ -663,6 +680,7 @@ function parseExtensionMemberContract(value: unknown, label: string): NpmExtensi sqlName: row.sqlName, createsExtension: row.createsExtension, nativeModuleStem: row.nativeModuleStem as string | null, + nativeDependencyModules, dependencies, dataFiles, extensionSqlFileNames, @@ -1153,6 +1171,12 @@ async function requireExactExtensionRuntimeInventory(config: { const files = await exactRuntimeLeafPaths(config.runtimeDirectory, config.source); const dataFiles = new Set(config.contract.dataFiles.map((file) => `share/postgresql/${file}`)); const licenseFiles = new Map(config.contract.licenseFiles.map((file) => [file.path, file])); + const dependencyModules = new Set( + config.contract.nativeDependencyModules.flatMap((file) => [ + `lib/postgresql/${file}`, + `lib/modules/${file}`, + ]), + ); const moduleFile = config.contract.nativeModuleStem === null ? undefined @@ -1176,6 +1200,7 @@ async function requireExactExtensionRuntimeInventory(config: { } if ( dataFiles.has(file) || + dependencyModules.has(file) || licenseFiles.has(file) || file === moduleFile || file === embeddedModuleFile @@ -1185,6 +1210,11 @@ async function requireExactExtensionRuntimeInventory(config: { throw new Error(`${config.source} contains undeclared runtime file ${file}`); } const missingDataFiles = [...dataFiles].filter((file) => !files.includes(file)); + const missingDependencies = [...dependencyModules].filter((file) => !files.includes(file)); + if (missingDependencies.length > 0) + throw new Error( + `${config.source} is missing declared native dependency module(s): ${missingDependencies.join(', ')}`, + ); if (missingDataFiles.length > 0) { throw new Error( `${config.source} is missing declared data file(s): ${missingDataFiles.join(', ')}`, diff --git a/src/native/sdks/ts/src/native/cluster-seed.ts b/src/native/sdks/ts/src/native/cluster-seed.ts index 406f898a3..466eb9875 100644 --- a/src/native/sdks/ts/src/native/cluster-seed.ts +++ b/src/native/sdks/ts/src/native/cluster-seed.ts @@ -75,7 +75,8 @@ export async function validateSelectedNativeSeed( if ( runtime?.product !== 'liboliphaunt-native' || runtime.engineFamily !== 'native' || - runtime.version !== runtimeVersion || + !/^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u.test(runtime.version ?? '') || + !/^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u.test(runtimeVersion) || runtime.target !== target || runtime.postgresMajor !== 18 || runtime.physicalFormat !== 'native-pg18-v1' || diff --git a/src/native/sdks/ts/src/native/filesystem-durability.ts b/src/native/sdks/ts/src/native/filesystem-durability.ts index ea81cb8ad..99acb98b0 100644 --- a/src/native/sdks/ts/src/native/filesystem-durability.ts +++ b/src/native/sdks/ts/src/native/filesystem-durability.ts @@ -1,4 +1,5 @@ import { lstat, open, readdir, readlink, type FileHandle } from 'node:fs/promises'; +import { platform } from 'node:os'; import { join } from 'node:path'; const UNSUPPORTED_DIRECTORY_SYNC_ERRORS = new Set(['EISDIR', 'EINVAL', 'EPERM', 'ENOTSUP']); @@ -43,7 +44,8 @@ async function syncTree(root: string, allowSymlinks: boolean): Promise { } else if (entryMetadata.isDirectory()) { await syncTree(file, allowSymlinks); } else if (entryMetadata.isFile()) { - const handle = await open(file, 'r'); + // Windows requires write access when flushing regular files. + const handle = await open(file, platform() === 'win32' ? 'r+' : 'r'); try { await handle.sync(); } finally { diff --git a/src/native/sdks/ts/tools/entrypoint-consumer.mts b/src/native/sdks/ts/tools/entrypoint-consumer.mts index dcdf0cfca..8a0501524 100644 --- a/src/native/sdks/ts/tools/entrypoint-consumer.mts +++ b/src/native/sdks/ts/tools/entrypoint-consumer.mts @@ -1,4 +1,6 @@ import assert from 'node:assert/strict'; +import { resolve } from 'node:path'; +import { pathToFileURL } from 'node:url'; import { extensions } from '@oliphaunt/ts'; import { directory } from '@oliphaunt/ts/storage/node'; import { directory as bunDirectory } from '@oliphaunt/ts/storage/bun'; @@ -12,26 +14,28 @@ import direct, { Oliphaunt as namedDirect, } from '@oliphaunt/ts/direct'; +const databasePath = resolve('unused', 'database'); +const brokerPath = resolve('unused', 'broker'); const directConfig: DirectConfig = { - storage: directory('/unused/database'), + storage: directory(databasePath), extensions: [extensions.hstore], }; -const brokerConfig: BrokerConfig = { brokerExecutable: '/unused/broker' }; +const brokerConfig: BrokerConfig = { brokerExecutable: brokerPath }; void [directConfig, brokerConfig]; assert.equal(direct, namedDirect); assert.equal(broker, namedBroker); assert.equal(directory, bunDirectory); assert.equal(directory, denoDirectory); -assert.deepEqual(directory(new URL('file:///unused/database')), directConfig.storage); +assert.deepEqual(directory(pathToFileURL(databasePath)), directConfig.storage); // @ts-expect-error restore accepts the same directory descriptor as open -await assert.rejects(direct.restore('/unused/database', new Uint8Array()), /directory/); +await assert.rejects(direct.restore(databasePath, new Uint8Array()), /directory/); const conflictingTopology = { topology: 'broker' as const }; // @ts-expect-error direct mode is selected by the import, including widened variables await assert.rejects(direct.open(conflictingTopology), /does not accept topology/); // @ts-expect-error broker mode is selected by the import await assert.rejects(broker.open(conflictingTopology), /does not accept topology/); -const conflictingHelper = { brokerExecutable: '/unused/broker' }; +const conflictingHelper = { brokerExecutable: brokerPath }; await assert.rejects( // @ts-expect-error a direct database does not accept a broker helper direct.open(conflictingHelper), diff --git a/src/query/rust/BUILD.bazel b/src/query/rust/BUILD.bazel new file mode 100644 index 000000000..27c5e78d7 --- /dev/null +++ b/src/query/rust/BUILD.bazel @@ -0,0 +1,50 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files") +load("@rules_rust//rust:defs.bzl", "rust_clippy_test", "rust_library", "rust_test") +load("@oliphaunt_toolchain_metadata//:query-rust.bzl", "QUERY_RUST_CRATE_NAME", "QUERY_RUST_EDITION", "QUERY_RUST_ENV", "QUERY_RUST_VERSION") +load("//build_defs/query:defs.bzl", "cargo_consumer_test") +load("//build_defs/languages:source.bzl", "cargo_source_package") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["Cargo.toml"]) + +QUERY_SRCS = glob(["src/**/*.rs"]) +QUERY_DATA = glob(["src/**/*"], exclude = ["src/**/*.rs"], allow_empty = True) + +rust_library( + name = "oliphaunt_query", + srcs = QUERY_SRCS, + crate_name = QUERY_RUST_CRATE_NAME, + crate_root = "src/lib.rs", + edition = QUERY_RUST_EDITION, + version = QUERY_RUST_VERSION, + rustc_env = QUERY_RUST_ENV, + compile_data = ["README.md"] + QUERY_DATA, +) + +rust_test( + name = "unit_test", + size = "small", + crate = ":oliphaunt_query", + version = QUERY_RUST_VERSION, + rustc_env = QUERY_RUST_ENV, +) + +cargo_source_package( + product = "oliphaunt-query", + qualification = [":consumer_test"] + select({ + "//build_defs/native:linux_x86_64": ["//build_defs/languages/installed:query_source_compile_test"], + "//conditions:default": [], + }), +) +rust_clippy_test(name = "clippy_test", targets = [":oliphaunt_query", ":unit_test"], transitive = False, size = "small") + +cargo_consumer_test( + name = "consumer_test", + size = "small", + archive = ":crate", + manifest = "//build_defs/query:consumer/Cargo.toml", + source = "//build_defs/query:consumer/main.rs", +) + +rust_quality_files() diff --git a/src/query/rust/Cargo.toml b/src/query/rust/Cargo.toml index a4528f6dc..cd729ec4b 100644 --- a/src/query/rust/Cargo.toml +++ b/src/query/rust/Cargo.toml @@ -8,4 +8,4 @@ homepage.workspace = true license.workspace = true description = "PostgreSQL query encoding, result decoding and shared types for Oliphaunt SDKs." readme = "README.md" -exclude = ["moon.yml", "release.toml"] +exclude = ["BUILD.bazel", "moon.yml", "release.toml"] diff --git a/src/query/ts/BUILD.bazel b/src/query/ts/BUILD.bazel new file mode 100644 index 000000000..ab168686e --- /dev/null +++ b/src/query/ts/BUILD.bazel @@ -0,0 +1,111 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("@aspect_rules_js//js:defs.bzl", "js_library") +load("@aspect_rules_js//npm:defs.bzl", "npm_link_package") +load("@aspect_rules_ts//ts:defs.bzl", "ts_project") +load("@oliphaunt_toolchain_metadata//:query-package-type.bzl", "QUERY_NPM_NAME", "QUERY_PACKAGE_TYPE") +load("//build_defs/foundation:bun.bzl", "bun_test") +load("//build_defs/query:defs.bzl", "npm_consumer_test", "query_envelope", "require_commonjs_package") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") + +package(default_visibility = ["//visibility:public"]) + +_MODULE_OUT_DIR = "dist" + +exports_files(["package.json"]) + +require_commonjs_package(QUERY_PACKAGE_TYPE) + +QUERY_SRCS = glob(["src/**/*.ts"]) + +js_library(name = "source_inputs", types = QUERY_SRCS, srcs = ["package.json"], deps = [":node_modules/@types/node", ":node_modules/undici-types"]) + +npm_link_package( + name = "node_modules/@types/node", + src = "@query_types_node//:pkg", +) + +npm_link_package( + name = "node_modules/undici-types", + src = "@query_undici_types//:pkg", +) + +ts_project( + name = "module", + srcs = QUERY_SRCS, + tsconfig = "tsconfig.build.module.json", + extends = "tsconfig.json", + declaration = True, + out_dir = _MODULE_OUT_DIR + "/module", + root_dir = "src", + transpiler = "tsc", + supports_workers = 0, + deps = [":node_modules/@types/node", ":node_modules/undici-types"], +) + +ts_project( + name = "commonjs", + srcs = QUERY_SRCS, + tsconfig = "tsconfig.build.commonjs.json", + extends = "tsconfig.json", + declaration = True, + out_dir = _MODULE_OUT_DIR + "/commonjs", + root_dir = "src", + transpiler = "tsc", + supports_workers = 0, + deps = [":node_modules/@types/node", ":node_modules/undici-types"], +) + +bun_test( + name = "unit_test", + size = "small", + entry_point = "test/protocol.test.ts", + args = ["src/query/ts/test/query.test.ts"], + data = QUERY_SRCS + [ + "test/query.test.ts", + "test/protocol-fixtures.mts", + "//src/test-fixtures:protocol/query-response-cases.json", + "//src/test-fixtures:protocol/structured-sql-cases.json", + ], +) + +query_envelope( + name = "npm", + format = "npm", + manifest = "package.json", + entries = { + ":module": "dist/module/", + ":commonjs": "dist/commonjs/", + "package.json": "package.json", + "module.package.json": "dist/module/package.json", + "README.md": "README.md", + "LICENSE": "LICENSE", + }, + out = "oliphaunt-ts-query.tgz", +) + +shipping_package( + name = "shipping_package", + owner = "@oliphaunt_metadata//:product_oliphaunt-query-ts", + artifacts = [":npm"], + ecosystem = "npm", + role = "facade", + package_name = QUERY_NPM_NAME, + configuration = "portable", + suppliers = "//build_defs/release:no_suppliers", +) + +shipping_export( + name = "shipping_export", + packages = [":shipping_package"], + qualification = [":consumer_test"], + testonly = True, +) + +npm_consumer_test( + name = "consumer_test", + size = "small", + archive = ":npm", + consumer = "tools/frozen-consumer.mts", +) + +source_quality_files(exclude = [_MODULE_OUT_DIR + "/**"]) diff --git a/src/test-fixtures/BUILD.bazel b/src/test-fixtures/BUILD.bazel new file mode 100644 index 000000000..2491de46a --- /dev/null +++ b/src/test-fixtures/BUILD.bazel @@ -0,0 +1,13 @@ +exports_files([ + "postgres/logical-tools.json", + "protocol/query-response-cases.json", + "protocol/structured-sql-cases.json", + "storage/database-root.json", + "storage/physical-backup-wal-range-v1.properties", +]) + +filegroup( + name = "rust_fixtures", + srcs = glob(["**/*.json", "**/*.sql", "**/*.properties"]) + ["//src/test-fixtures/extensions:sql"], + visibility = ["//visibility:public"], +) diff --git a/src/test-fixtures/extensions/BUILD.bazel b/src/test-fixtures/extensions/BUILD.bazel new file mode 100644 index 000000000..2e2fdfcad --- /dev/null +++ b/src/test-fixtures/extensions/BUILD.bazel @@ -0,0 +1,4 @@ +package(default_visibility = ["//visibility:public"]) + +exports_files(glob(["*.sql"])) +filegroup(name = "sql", srcs = glob(["*.sql"])) diff --git a/src/test-fixtures/extensions/bloom.sql b/src/test-fixtures/extensions/bloom.sql index 6b304209e..a501a779e 100644 --- a/src/test-fixtures/extensions/bloom.sql +++ b/src/test-fixtures/extensions/bloom.sql @@ -4,4 +4,4 @@ CREATE INDEX oliphaunt_bloom_idx ON oliphaunt_bloom USING bloom (id, value); -- oliphaunt-statement INSERT INTO oliphaunt_bloom SELECT i, i % 3 FROM generate_series(1, 20) AS i; -- oliphaunt-statement -DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_bloom WHERE id = 7 AND value = 1; IF n <> 1 THEN RAISE EXCEPTION 'bloom lookup failed: %', n; END IF; END $$; +DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_bloom WHERE id = 7 AND value = 1; IF n IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'bloom lookup failed: %', n; END IF; END $$; diff --git a/src/test-fixtures/extensions/btree_gin.sql b/src/test-fixtures/extensions/btree_gin.sql index 72b6b5851..b8f3a84fa 100644 --- a/src/test-fixtures/extensions/btree_gin.sql +++ b/src/test-fixtures/extensions/btree_gin.sql @@ -4,4 +4,4 @@ CREATE INDEX oliphaunt_btree_gin_idx ON oliphaunt_btree_gin USING gin (id); -- oliphaunt-statement INSERT INTO oliphaunt_btree_gin SELECT generate_series(1, 10); -- oliphaunt-statement -DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_btree_gin WHERE id = 5; IF n <> 1 THEN RAISE EXCEPTION 'btree_gin lookup failed: %', n; END IF; END $$; +DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_btree_gin WHERE id = 5; IF n IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'btree_gin lookup failed: %', n; END IF; END $$; diff --git a/src/test-fixtures/extensions/btree_gist.sql b/src/test-fixtures/extensions/btree_gist.sql index cf430672d..519547ced 100644 --- a/src/test-fixtures/extensions/btree_gist.sql +++ b/src/test-fixtures/extensions/btree_gist.sql @@ -4,4 +4,4 @@ CREATE INDEX oliphaunt_btree_gist_idx ON oliphaunt_btree_gist USING gist (id); -- oliphaunt-statement INSERT INTO oliphaunt_btree_gist SELECT generate_series(1, 10); -- oliphaunt-statement -DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_btree_gist WHERE id = 5; IF n <> 1 THEN RAISE EXCEPTION 'btree_gist lookup failed: %', n; END IF; END $$; +DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_btree_gist WHERE id = 5; IF n IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'btree_gist lookup failed: %', n; END IF; END $$; diff --git a/src/test-fixtures/extensions/citext.sql b/src/test-fixtures/extensions/citext.sql index 22dfc581f..67becce9d 100644 --- a/src/test-fixtures/extensions/citext.sql +++ b/src/test-fixtures/extensions/citext.sql @@ -2,4 +2,4 @@ CREATE TEMP TABLE oliphaunt_citext (value citext); -- oliphaunt-statement INSERT INTO oliphaunt_citext VALUES ('Postgres'); -- oliphaunt-statement -DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_citext WHERE value = 'postgres'; IF n <> 1 THEN RAISE EXCEPTION 'citext comparison failed: %', n; END IF; END $$; +DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_citext WHERE value = 'postgres'; IF n IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'citext comparison failed: %', n; END IF; END $$; diff --git a/src/test-fixtures/extensions/cube.sql b/src/test-fixtures/extensions/cube.sql index 658665349..46448e941 100644 --- a/src/test-fixtures/extensions/cube.sql +++ b/src/test-fixtures/extensions/cube.sql @@ -1,2 +1,2 @@ -- oliphaunt-statement -DO $$ DECLARE d float8; BEGIN SELECT cube(array[1,2,3]) <-> cube(array[1,2,4]) INTO d; IF d <> 1 THEN RAISE EXCEPTION 'cube distance failed: %', d; END IF; END $$; +DO $$ DECLARE d float8; BEGIN SELECT cube(array[1,2,3]) <-> cube(array[1,2,4]) INTO d; IF d IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'cube distance failed: %', d; END IF; END $$; diff --git a/src/test-fixtures/extensions/dict_int.sql b/src/test-fixtures/extensions/dict_int.sql index bc3af78c0..847f5a835 100644 --- a/src/test-fixtures/extensions/dict_int.sql +++ b/src/test-fixtures/extensions/dict_int.sql @@ -1,2 +1,2 @@ -- oliphaunt-statement -DO $$ DECLARE lex text; BEGIN SELECT array_to_string(ts_lexize('intdict', '40865854'), ',') INTO lex; IF lex <> '408658' THEN RAISE EXCEPTION 'dict_int lexize failed: %', lex; END IF; END $$; +DO $$ DECLARE lex text; BEGIN SELECT array_to_string(ts_lexize('intdict', '40865854'), ',') INTO lex; IF lex IS DISTINCT FROM '408658' THEN RAISE EXCEPTION 'dict_int lexize failed: %', lex; END IF; END $$; diff --git a/src/test-fixtures/extensions/earthdistance.sql b/src/test-fixtures/extensions/earthdistance.sql index ae7537b43..cc6a63973 100644 --- a/src/test-fixtures/extensions/earthdistance.sql +++ b/src/test-fixtures/extensions/earthdistance.sql @@ -1,2 +1,2 @@ -- oliphaunt-statement -DO $$ DECLARE d float8; BEGIN SELECT earth_distance(ll_to_earth(0, 0), ll_to_earth(0, 1)) INTO d; IF d <= 0 THEN RAISE EXCEPTION 'earthdistance failed: %', d; END IF; END $$; +DO $$ DECLARE d float8; BEGIN SELECT earth_distance(ll_to_earth(0, 0), ll_to_earth(0, 1)) INTO d; IF d IS NULL OR d <= 0 THEN RAISE EXCEPTION 'earthdistance failed: %', d; END IF; END $$; diff --git a/src/test-fixtures/extensions/file_fdw.sql b/src/test-fixtures/extensions/file_fdw.sql index 6b7e81d30..6d82f5bd3 100644 --- a/src/test-fixtures/extensions/file_fdw.sql +++ b/src/test-fixtures/extensions/file_fdw.sql @@ -1,6 +1,34 @@ +DROP FOREIGN TABLE IF EXISTS oliphaunt_file_version_probe; +-- oliphaunt-statement DROP SERVER IF EXISTS oliphaunt_file_server; -- oliphaunt-statement CREATE SERVER oliphaunt_file_server FOREIGN DATA WRAPPER file_fdw; -- oliphaunt-statement +DO $$ +BEGIN + EXECUTE format( + 'CREATE FOREIGN TABLE oliphaunt_file_version_probe(version integer) SERVER oliphaunt_file_server OPTIONS (filename %L, format %L)', + current_setting('data_directory') || '/PG_VERSION', 'text' + ); +END +$$; +-- oliphaunt-statement -- oliphaunt-verify -DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_foreign_server WHERE srvname = 'oliphaunt_file_server') THEN RAISE EXCEPTION 'file_fdw server missing'; END IF; END $$; +DO $$ +DECLARE + file_rows bigint; + postgres_major integer; +BEGIN + IF NOT EXISTS (SELECT 1 FROM pg_foreign_server WHERE srvname = 'oliphaunt_file_server') THEN + RAISE EXCEPTION 'file_fdw server missing'; + END IF; + EXECUTE format( + 'ALTER FOREIGN TABLE oliphaunt_file_version_probe OPTIONS (SET filename %L)', + current_setting('data_directory') || '/PG_VERSION' + ); + SELECT count(*), min(version) INTO file_rows, postgres_major FROM oliphaunt_file_version_probe; + IF file_rows IS DISTINCT FROM 1::bigint OR postgres_major IS DISTINCT FROM 18 THEN + RAISE EXCEPTION 'file_fdw did not read the expected database version: rows %, version %', file_rows, postgres_major; + END IF; +END +$$; diff --git a/src/test-fixtures/extensions/fuzzystrmatch.sql b/src/test-fixtures/extensions/fuzzystrmatch.sql index 7d9b6222d..e202aced0 100644 --- a/src/test-fixtures/extensions/fuzzystrmatch.sql +++ b/src/test-fixtures/extensions/fuzzystrmatch.sql @@ -1,2 +1,2 @@ -- oliphaunt-statement -DO $$ BEGIN IF levenshtein('kitten', 'sitting') <> 3 THEN RAISE EXCEPTION 'levenshtein failed'; END IF; IF soundex('kitten') <> 'K350' THEN RAISE EXCEPTION 'soundex failed'; END IF; END $$; +DO $$ BEGIN IF levenshtein('kitten', 'sitting') IS DISTINCT FROM 3 THEN RAISE EXCEPTION 'levenshtein failed'; END IF; IF soundex('kitten') IS DISTINCT FROM 'K350' THEN RAISE EXCEPTION 'soundex failed'; END IF; END $$; diff --git a/src/test-fixtures/extensions/hstore.sql b/src/test-fixtures/extensions/hstore.sql index a13262e3b..0381061d8 100644 --- a/src/test-fixtures/extensions/hstore.sql +++ b/src/test-fixtures/extensions/hstore.sql @@ -2,4 +2,4 @@ CREATE TEMP TABLE oliphaunt_hstore (attrs hstore); -- oliphaunt-statement INSERT INTO oliphaunt_hstore VALUES ('a=>1,b=>2'::hstore); -- oliphaunt-statement -DO $$ DECLARE v text; BEGIN SELECT attrs -> 'b' INTO v FROM oliphaunt_hstore; IF v <> '2' THEN RAISE EXCEPTION 'hstore lookup failed: %', v; END IF; END $$; +DO $$ DECLARE v text; BEGIN SELECT attrs -> 'b' INTO v FROM oliphaunt_hstore; IF v IS DISTINCT FROM '2' THEN RAISE EXCEPTION 'hstore lookup failed: %', v; END IF; END $$; diff --git a/src/test-fixtures/extensions/intarray.sql b/src/test-fixtures/extensions/intarray.sql index 97d3448f3..6560b1619 100644 --- a/src/test-fixtures/extensions/intarray.sql +++ b/src/test-fixtures/extensions/intarray.sql @@ -2,4 +2,4 @@ CREATE TEMP TABLE oliphaunt_intarray (tags int[]); -- oliphaunt-statement INSERT INTO oliphaunt_intarray VALUES (ARRAY[1, 2, 5]), (ARRAY[3, 4]); -- oliphaunt-statement -DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_intarray WHERE tags && ARRAY[2, 9]; IF n <> 1 THEN RAISE EXCEPTION 'intarray overlap failed: %', n; END IF; SELECT count(*) INTO n FROM oliphaunt_intarray WHERE tags @@ '1 & (2|3)'::query_int; IF n <> 1 THEN RAISE EXCEPTION 'intarray query_int failed: %', n; END IF; END $$; +DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_intarray WHERE tags && ARRAY[2, 9]; IF n IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'intarray overlap failed: %', n; END IF; SELECT count(*) INTO n FROM oliphaunt_intarray WHERE tags @@ '1 & (2|3)'::query_int; IF n IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'intarray query_int failed: %', n; END IF; END $$; diff --git a/src/test-fixtures/extensions/isn.sql b/src/test-fixtures/extensions/isn.sql index 222391ec5..cb05a77e3 100644 --- a/src/test-fixtures/extensions/isn.sql +++ b/src/test-fixtures/extensions/isn.sql @@ -1,2 +1,2 @@ -- oliphaunt-statement -DO $$ BEGIN IF isbn('978-0-393-04002-9')::text <> '0-393-04002-X' THEN RAISE EXCEPTION 'isbn failed'; END IF; IF isbn13('0901690546')::text <> '978-0-901690-54-8' THEN RAISE EXCEPTION 'isbn13 failed'; END IF; IF issn('1436-4522')::text <> '1436-4522' THEN RAISE EXCEPTION 'issn failed'; END IF; END $$; +DO $$ BEGIN IF isbn('978-0-393-04002-9')::text IS DISTINCT FROM '0-393-04002-X' THEN RAISE EXCEPTION 'isbn failed'; END IF; IF isbn13('0901690546')::text IS DISTINCT FROM '978-0-901690-54-8' THEN RAISE EXCEPTION 'isbn13 failed'; END IF; IF issn('1436-4522')::text IS DISTINCT FROM '1436-4522' THEN RAISE EXCEPTION 'issn failed'; END IF; END $$; diff --git a/src/test-fixtures/extensions/ltree.sql b/src/test-fixtures/extensions/ltree.sql index 46dfedda1..641471d0e 100644 --- a/src/test-fixtures/extensions/ltree.sql +++ b/src/test-fixtures/extensions/ltree.sql @@ -2,4 +2,4 @@ CREATE TEMP TABLE oliphaunt_ltree (path ltree); -- oliphaunt-statement INSERT INTO oliphaunt_ltree VALUES ('Top.Science.Astronomy'), ('Top.Collections.Pictures'); -- oliphaunt-statement -DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_ltree WHERE path <@ 'Top.Science'; IF n <> 1 THEN RAISE EXCEPTION 'ltree ancestor query failed: %', n; END IF; END $$; +DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_ltree WHERE path <@ 'Top.Science'; IF n IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'ltree ancestor query failed: %', n; END IF; END $$; diff --git a/src/test-fixtures/extensions/pg_hashids.sql b/src/test-fixtures/extensions/pg_hashids.sql index 9c3269dfe..f570def72 100644 --- a/src/test-fixtures/extensions/pg_hashids.sql +++ b/src/test-fixtures/extensions/pg_hashids.sql @@ -1,2 +1,2 @@ -- oliphaunt-statement -DO $$ BEGIN IF id_encode(1001) <> 'jNl' THEN RAISE EXCEPTION 'pg_hashids encode failed'; END IF; IF id_decode_once('jNl') <> 1001 THEN RAISE EXCEPTION 'pg_hashids decode failed'; END IF; END $$; +DO $$ BEGIN IF id_encode(1001) IS DISTINCT FROM 'jNl' THEN RAISE EXCEPTION 'pg_hashids encode failed'; END IF; IF id_decode_once('jNl') IS DISTINCT FROM 1001 THEN RAISE EXCEPTION 'pg_hashids decode failed'; END IF; END $$; diff --git a/src/test-fixtures/extensions/pg_ivm.sql b/src/test-fixtures/extensions/pg_ivm.sql index 6fa633545..84582528a 100644 --- a/src/test-fixtures/extensions/pg_ivm.sql +++ b/src/test-fixtures/extensions/pg_ivm.sql @@ -13,7 +13,7 @@ DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM oliphaunt_ivm_summary; - IF n <> 2 THEN RAISE EXCEPTION 'pg_ivm count failed: %', n; END IF; + IF n IS DISTINCT FROM 2 THEN RAISE EXCEPTION 'pg_ivm count failed: %', n; END IF; UPDATE oliphaunt_ivm_orders SET amount = 11 WHERE id = 1; SELECT amount INTO n FROM oliphaunt_ivm_summary WHERE id = 1; IF n IS DISTINCT FROM 11 THEN RAISE EXCEPTION 'pg_ivm maintenance failed: %', n; END IF; diff --git a/src/test-fixtures/extensions/pg_surgery.sql b/src/test-fixtures/extensions/pg_surgery.sql index 3daaf52f7..248680b97 100644 --- a/src/test-fixtures/extensions/pg_surgery.sql +++ b/src/test-fixtures/extensions/pg_surgery.sql @@ -1,2 +1,23 @@ -- oliphaunt-statement DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'heap_force_kill') THEN RAISE EXCEPTION 'pg_surgery function missing'; END IF; END $$; +-- oliphaunt-statement +CREATE TEMP TABLE oliphaunt_pg_surgery_probe(value integer); +-- oliphaunt-statement +INSERT INTO oliphaunt_pg_surgery_probe VALUES (1), (2); +-- oliphaunt-statement +DO $$ +DECLARE + target_tid tid; +BEGIN + SELECT ctid INTO STRICT target_tid FROM oliphaunt_pg_surgery_probe WHERE value = 1; + PERFORM heap_force_freeze('oliphaunt_pg_surgery_probe'::regclass, ARRAY[target_tid]::tid[]); + IF (SELECT xmin::text FROM oliphaunt_pg_surgery_probe WHERE value = 1) IS DISTINCT FROM '2' THEN + RAISE EXCEPTION 'pg_surgery did not freeze the temporary tuple'; + END IF; + PERFORM heap_force_kill('oliphaunt_pg_surgery_probe'::regclass, ARRAY[target_tid]::tid[]); + IF (SELECT count(*) FROM oliphaunt_pg_surgery_probe) IS DISTINCT FROM 1::bigint + OR (SELECT sum(value) FROM oliphaunt_pg_surgery_probe) IS DISTINCT FROM 2::bigint THEN + RAISE EXCEPTION 'pg_surgery did not retain only the expected temporary tuple'; + END IF; +END +$$; diff --git a/src/test-fixtures/extensions/pg_trgm.sql b/src/test-fixtures/extensions/pg_trgm.sql index a9c18b39d..2afdb7441 100644 --- a/src/test-fixtures/extensions/pg_trgm.sql +++ b/src/test-fixtures/extensions/pg_trgm.sql @@ -1,2 +1,2 @@ -- oliphaunt-statement -DO $$ DECLARE score float8; BEGIN SELECT similarity('postgres', 'postgrex') INTO score; IF score <= 0 THEN RAISE EXCEPTION 'pg_trgm similarity failed: %', score; END IF; END $$; +DO $$ DECLARE score float8; BEGIN SELECT similarity('postgres', 'postgrex') INTO score; IF score IS NULL OR score <= 0 THEN RAISE EXCEPTION 'pg_trgm similarity failed: %', score; END IF; END $$; diff --git a/src/test-fixtures/extensions/pg_uuidv7.sql b/src/test-fixtures/extensions/pg_uuidv7.sql index 899be0b96..ca201cf70 100644 --- a/src/test-fixtures/extensions/pg_uuidv7.sql +++ b/src/test-fixtures/extensions/pg_uuidv7.sql @@ -1,2 +1,2 @@ -- oliphaunt-statement -DO $$ DECLARE id uuid; ts timestamptz; BEGIN SELECT uuid_generate_v7() INTO id; IF length(id::text) <> 36 THEN RAISE EXCEPTION 'uuidv7 length failed'; END IF; SELECT uuid_v7_to_timestamptz('018570bb-4a7d-7c7e-8df4-6d47afd8c8fc') INTO ts; IF ts IS NULL THEN RAISE EXCEPTION 'uuidv7 timestamp failed'; END IF; END $$; +DO $$ DECLARE id uuid; ts timestamptz; BEGIN SELECT uuid_generate_v7() INTO id; IF length(id::text) IS DISTINCT FROM 36 THEN RAISE EXCEPTION 'uuidv7 length failed'; END IF; SELECT uuid_v7_to_timestamptz('018570bb-4a7d-7c7e-8df4-6d47afd8c8fc') INTO ts; IF ts IS NULL THEN RAISE EXCEPTION 'uuidv7 timestamp failed'; END IF; END $$; diff --git a/src/test-fixtures/extensions/pgcrypto.sql b/src/test-fixtures/extensions/pgcrypto.sql index ce9d50b26..8333dabbe 100644 --- a/src/test-fixtures/extensions/pgcrypto.sql +++ b/src/test-fixtures/extensions/pgcrypto.sql @@ -1,7 +1,7 @@ -DO $$ DECLARE hashed text; encrypted bytea; BEGIN IF encode(digest('abc', 'sha256'), 'hex') <> 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad' THEN RAISE EXCEPTION 'sha256 digest failed'; END IF; IF length(gen_random_bytes(16)) <> 16 THEN RAISE EXCEPTION 'random bytes length failed'; END IF; SELECT crypt('secret', gen_salt('bf', 4)) INTO hashed; IF crypt('secret', hashed) <> hashed THEN RAISE EXCEPTION 'password hash verify failed'; END IF; SELECT pgp_sym_encrypt('oliphaunt secret', 'passphrase') INTO encrypted; IF pgp_sym_decrypt(encrypted, 'passphrase') <> 'oliphaunt secret' THEN RAISE EXCEPTION 'PGP symmetric decrypt failed'; END IF; END $$; +DO $$ DECLARE hashed text; encrypted bytea; BEGIN IF encode(digest('abc', 'sha256'), 'hex') IS DISTINCT FROM 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad' THEN RAISE EXCEPTION 'sha256 digest failed'; END IF; IF length(gen_random_bytes(16)) IS DISTINCT FROM 16 THEN RAISE EXCEPTION 'random bytes length failed'; END IF; SELECT crypt('secret', gen_salt('bf', 4)) INTO hashed; IF hashed IS NULL OR crypt('secret', hashed) IS DISTINCT FROM hashed THEN RAISE EXCEPTION 'password hash verify failed'; END IF; SELECT pgp_sym_encrypt('oliphaunt secret', 'passphrase') INTO encrypted; IF pgp_sym_decrypt(encrypted, 'passphrase') IS DISTINCT FROM 'oliphaunt secret' THEN RAISE EXCEPTION 'PGP symmetric decrypt failed'; END IF; END $$; -- oliphaunt-statement -DO $$ BEGIN IF encode(hmac('test', 'key', 'sha1'), 'hex') <> '671f54ce0c540f78ffe1e26dcf9c2a047aea4fda' THEN RAISE EXCEPTION 'hmac failed'; END IF; IF gen_random_uuid()::text !~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$' THEN RAISE EXCEPTION 'random uuid format failed'; END IF; END $$; +DO $$ BEGIN IF encode(hmac('test', 'key', 'sha1'), 'hex') IS DISTINCT FROM '671f54ce0c540f78ffe1e26dcf9c2a047aea4fda' THEN RAISE EXCEPTION 'hmac failed'; END IF; IF (gen_random_uuid()::text ~ '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$') IS DISTINCT FROM true THEN RAISE EXCEPTION 'random uuid format failed'; END IF; END $$; -- oliphaunt-statement -DO $$ DECLARE armored text; header_count int; BEGIN SELECT armor(digest('test', 'sha1'), ARRAY['Version'], ARRAY['oliphaunt']) INTO armored; IF position('Version: oliphaunt' in armored) = 0 THEN RAISE EXCEPTION 'armor header failed'; END IF; SELECT count(*) INTO header_count FROM pgp_armor_headers(armored); IF header_count <> 1 THEN RAISE EXCEPTION 'armor header count failed: %', header_count; END IF; END $$; +DO $$ DECLARE armored text; header_count int; BEGIN SELECT armor(digest('test', 'sha1'), ARRAY['Version'], ARRAY['oliphaunt']) INTO armored; IF armored IS NULL OR position('Version: oliphaunt' in armored) = 0 THEN RAISE EXCEPTION 'armor header failed'; END IF; SELECT count(*) INTO header_count FROM pgp_armor_headers(armored); IF header_count IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'armor header count failed: %', header_count; END IF; END $$; -- oliphaunt-statement -DO $$ DECLARE encrypted bytea; crypto_key bytea := decode('000102030405060708090a0b0c0d0e0f', 'hex'); crypto_iv bytea := decode('101112131415161718191a1b1c1d1e1f', 'hex'); BEGIN SELECT pgp_sym_encrypt('oliphaunt secret', 'passphrase') INTO encrypted; IF pgp_key_id(encrypted) <> 'SYMKEY' THEN RAISE EXCEPTION 'PGP symmetric key id failed'; END IF; SELECT encrypt(convert_to('oliphaunt raw cipher', 'UTF8'), crypto_key, 'aes') INTO encrypted; IF convert_from(decrypt(encrypted, crypto_key, 'aes'), 'UTF8') <> 'oliphaunt raw cipher' THEN RAISE EXCEPTION 'raw decrypt failed'; END IF; SELECT encrypt_iv(convert_to('oliphaunt iv cipher', 'UTF8'), crypto_key, crypto_iv, 'aes-cbc') INTO encrypted; IF convert_from(decrypt_iv(encrypted, crypto_key, crypto_iv, 'aes-cbc'), 'UTF8') <> 'oliphaunt iv cipher' THEN RAISE EXCEPTION 'raw iv decrypt failed'; END IF; END $$; +DO $$ DECLARE encrypted bytea; crypto_key bytea := decode('000102030405060708090a0b0c0d0e0f', 'hex'); crypto_iv bytea := decode('101112131415161718191a1b1c1d1e1f', 'hex'); BEGIN SELECT pgp_sym_encrypt('oliphaunt secret', 'passphrase') INTO encrypted; IF pgp_key_id(encrypted) IS DISTINCT FROM 'SYMKEY' THEN RAISE EXCEPTION 'PGP symmetric key id failed'; END IF; SELECT encrypt(convert_to('oliphaunt raw cipher', 'UTF8'), crypto_key, 'aes') INTO encrypted; IF convert_from(decrypt(encrypted, crypto_key, 'aes'), 'UTF8') IS DISTINCT FROM 'oliphaunt raw cipher' THEN RAISE EXCEPTION 'raw decrypt failed'; END IF; SELECT encrypt_iv(convert_to('oliphaunt iv cipher', 'UTF8'), crypto_key, crypto_iv, 'aes-cbc') INTO encrypted; IF convert_from(decrypt_iv(encrypted, crypto_key, crypto_iv, 'aes-cbc'), 'UTF8') IS DISTINCT FROM 'oliphaunt iv cipher' THEN RAISE EXCEPTION 'raw iv decrypt failed'; END IF; END $$; diff --git a/src/test-fixtures/extensions/postgis.sql b/src/test-fixtures/extensions/postgis.sql index dc5dafeac..086d2852d 100644 --- a/src/test-fixtures/extensions/postgis.sql +++ b/src/test-fixtures/extensions/postgis.sql @@ -18,24 +18,24 @@ DECLARE nearby int; BEGIN SELECT ST_Distance(ST_GeomFromText('POINT(0 0)'), ST_GeomFromText('POINT(3 4)')) INTO distance; - IF distance <> 5 THEN + IF distance IS DISTINCT FROM 5 THEN RAISE EXCEPTION 'postgis geometry distance failed: %', distance; END IF; IF ST_AsText(ST_Buffer(ST_GeomFromText('POINT(0 0)'), 1, 'quad_segs=1')) IS NULL THEN RAISE EXCEPTION 'postgis buffer failed'; END IF; - IF NOT ST_Within( + IF ST_Within( ST_GeomFromText('POINT(0.5 0.5)'), ST_GeomFromText('POLYGON((0 0,0 1,1 1,1 0,0 0))') - ) THEN + ) IS DISTINCT FROM true THEN RAISE EXCEPTION 'postgis within failed'; END IF; SELECT ST_SRID(ST_Transform(ST_SetSRID(ST_MakePoint(-71.060316, 48.432044), 4326), 3857)) INTO srid; - IF srid <> 3857 THEN + IF srid IS DISTINCT FROM 3857 THEN RAISE EXCEPTION 'postgis transform failed: %', srid; END IF; SELECT ST_Area(ST_Transform(ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(-71.1776848522251 42.3902896512902,-71.1776843766797 42.3903701743239,-71.1775844305465 42.3903829478009,-71.1775825927231 42.3902893647987,-71.1776848522251 42.3902896512902)')), 4326), 26986)) INTO area; - IF area <= 0 THEN + IF area IS NULL OR area <= 0 THEN RAISE EXCEPTION 'postgis projected area failed: %', area; END IF; SELECT ST_NumGeometries(ST_Polygonize(ARRAY[ @@ -44,7 +44,7 @@ BEGIN ST_GeomFromText('LINESTRING(1 1, 0 1)'), ST_GeomFromText('LINESTRING(0 1, 0 0)') ])) INTO polygons; - IF polygons <> 1 THEN + IF polygons IS DISTINCT FROM 1 THEN RAISE EXCEPTION 'postgis polygonize failed: %', polygons; END IF; SELECT count(*) INTO nearby @@ -54,7 +54,7 @@ BEGIN ST_SetSRID(ST_MakePoint(-71.060316, 48.432044), 4326)::geography, 200 ); - IF nearby <> 2 THEN + IF nearby IS DISTINCT FROM 2 THEN RAISE EXCEPTION 'postgis dwithin failed: %', nearby; END IF; END $$; diff --git a/src/test-fixtures/extensions/seg.sql b/src/test-fixtures/extensions/seg.sql index 11e65e887..abfb3e0f7 100644 --- a/src/test-fixtures/extensions/seg.sql +++ b/src/test-fixtures/extensions/seg.sql @@ -1,2 +1,2 @@ -- oliphaunt-statement -DO $$ BEGIN IF '7(+-)1'::seg::text <> '6 .. 8' THEN RAISE EXCEPTION 'seg cast failed'; END IF; END $$; +DO $$ BEGIN IF '7(+-)1'::seg::text IS DISTINCT FROM '6 .. 8' THEN RAISE EXCEPTION 'seg cast failed'; END IF; END $$; diff --git a/src/test-fixtures/extensions/tablefunc.sql b/src/test-fixtures/extensions/tablefunc.sql index 6e81b5b53..04a5cb562 100644 --- a/src/test-fixtures/extensions/tablefunc.sql +++ b/src/test-fixtures/extensions/tablefunc.sql @@ -1,3 +1,3 @@ -DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM normal_rand(10, 5, 3); IF n <> 10 THEN RAISE EXCEPTION 'normal_rand failed: %', n; END IF; END $$; +DO $$ DECLARE n int; BEGIN SELECT count(*) INTO n FROM normal_rand(10, 5, 3); IF n IS DISTINCT FROM 10 THEN RAISE EXCEPTION 'normal_rand failed: %', n; END IF; END $$; -- oliphaunt-statement SELECT * FROM crosstab('SELECT 1, 1, 10 UNION ALL SELECT 1, 2, 20') AS ct(rowid int, c1 int, c2 int); diff --git a/src/test-fixtures/extensions/unaccent.sql b/src/test-fixtures/extensions/unaccent.sql index f80f2c141..9ea0e0893 100644 --- a/src/test-fixtures/extensions/unaccent.sql +++ b/src/test-fixtures/extensions/unaccent.sql @@ -1,2 +1,2 @@ -- oliphaunt-statement -DO $$ DECLARE lex text; BEGIN SELECT array_to_string(ts_lexize('unaccent', 'Hôtel'), ',') INTO lex; IF lex <> 'Hotel' THEN RAISE EXCEPTION 'unaccent failed: %', lex; END IF; END $$; +DO $$ DECLARE lex text; BEGIN SELECT array_to_string(ts_lexize('unaccent', 'Hôtel'), ',') INTO lex; IF lex IS DISTINCT FROM 'Hotel' THEN RAISE EXCEPTION 'unaccent failed: %', lex; END IF; END $$; diff --git a/src/test-fixtures/extensions/uuid-ossp.sql b/src/test-fixtures/extensions/uuid-ossp.sql index 64f1479a4..01c9f7d9b 100644 --- a/src/test-fixtures/extensions/uuid-ossp.sql +++ b/src/test-fixtures/extensions/uuid-ossp.sql @@ -1,5 +1,5 @@ -DO $$ DECLARE id uuid; BEGIN SELECT uuid_generate_v1() INTO id; IF length(id::text) <> 36 THEN RAISE EXCEPTION 'uuid-ossp v1 length failed'; END IF; SELECT uuid_generate_v4() INTO id; IF length(id::text) <> 36 THEN RAISE EXCEPTION 'uuid-ossp v4 length failed'; END IF; END $$; +DO $$ DECLARE id uuid; BEGIN SELECT uuid_generate_v1() INTO id; IF length(id::text) IS DISTINCT FROM 36 THEN RAISE EXCEPTION 'uuid-ossp v1 length failed'; END IF; SELECT uuid_generate_v4() INTO id; IF length(id::text) IS DISTINCT FROM 36 THEN RAISE EXCEPTION 'uuid-ossp v4 length failed'; END IF; END $$; -- oliphaunt-statement -DO $$ BEGIN IF uuid_generate_v3(uuid_ns_dns(), 'www.example.com')::text <> '5df41881-3aed-3515-88a7-2f4a814cf09e' THEN RAISE EXCEPTION 'uuid-ossp v3 failed'; END IF; IF uuid_generate_v5(uuid_ns_dns(), 'www.example.com')::text <> '2ed6657d-e927-568b-95e1-2665a8aea6a2' THEN RAISE EXCEPTION 'uuid-ossp v5 failed'; END IF; END $$; +DO $$ BEGIN IF uuid_generate_v3(uuid_ns_dns(), 'www.example.com')::text IS DISTINCT FROM '5df41881-3aed-3515-88a7-2f4a814cf09e' THEN RAISE EXCEPTION 'uuid-ossp v3 failed'; END IF; IF uuid_generate_v5(uuid_ns_dns(), 'www.example.com')::text IS DISTINCT FROM '2ed6657d-e927-568b-95e1-2665a8aea6a2' THEN RAISE EXCEPTION 'uuid-ossp v5 failed'; END IF; END $$; -- oliphaunt-statement -DO $$ BEGIN IF uuid_nil()::text <> '00000000-0000-0000-0000-000000000000' THEN RAISE EXCEPTION 'uuid-ossp nil failed'; END IF; IF uuid_ns_dns()::text <> '6ba7b810-9dad-11d1-80b4-00c04fd430c8' THEN RAISE EXCEPTION 'uuid-ossp dns namespace failed'; END IF; IF uuid_ns_oid()::text <> '6ba7b812-9dad-11d1-80b4-00c04fd430c8' THEN RAISE EXCEPTION 'uuid-ossp oid namespace failed'; END IF; END $$; +DO $$ BEGIN IF uuid_nil()::text IS DISTINCT FROM '00000000-0000-0000-0000-000000000000' THEN RAISE EXCEPTION 'uuid-ossp nil failed'; END IF; IF uuid_ns_dns()::text IS DISTINCT FROM '6ba7b810-9dad-11d1-80b4-00c04fd430c8' THEN RAISE EXCEPTION 'uuid-ossp dns namespace failed'; END IF; IF uuid_ns_oid()::text IS DISTINCT FROM '6ba7b812-9dad-11d1-80b4-00c04fd430c8' THEN RAISE EXCEPTION 'uuid-ossp oid namespace failed'; END IF; END $$; diff --git a/src/third-party/icu/BUILD.bazel b/src/third-party/icu/BUILD.bazel new file mode 100644 index 000000000..8e64e1daf --- /dev/null +++ b/src/third-party/icu/BUILD.bazel @@ -0,0 +1,3 @@ +package(default_visibility = ["//visibility:public"]) + +exports_files(["source.toml", "LICENSE"]) diff --git a/src/third-party/openssl/BUILD.bazel b/src/third-party/openssl/BUILD.bazel new file mode 100644 index 000000000..c1ef96c11 --- /dev/null +++ b/src/third-party/openssl/BUILD.bazel @@ -0,0 +1,3 @@ +package(default_visibility = ["//visibility:public"]) + +exports_files(["source.toml", "LICENSE.txt"]) diff --git a/src/third-party/postgres/BUILD.bazel b/src/third-party/postgres/BUILD.bazel new file mode 100644 index 000000000..c987e6e8c --- /dev/null +++ b/src/third-party/postgres/BUILD.bazel @@ -0,0 +1,6 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +package(default_visibility = ["//visibility:public"]) + +exports_files(["source.toml", "COPYRIGHT"] + glob(["patches/common/*.patch", "patches/wasix/*.patch"])) + +source_quality_files() diff --git a/src/wasix/browser-host/BUILD.bazel b/src/wasix/browser-host/BUILD.bazel new file mode 100644 index 000000000..e56e72d16 --- /dev/null +++ b/src/wasix/browser-host/BUILD.bazel @@ -0,0 +1,64 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("@browser_cargo//:defs.bzl", "all_crate_deps", "aliases") +load("@browser_npm//:defs.bzl", "BROWSER_NPM") +load("@browser_sources//:metadata.bzl", "BROWSER") +load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") +load("@rules_rust//rust:defs.bzl", "rust_shared_library") +load("//build_defs/wasix/browser:defs.bzl", "browser_bindings", "browser_bundle", "browser_host_package", "browser_wasm") + +package(default_visibility = ["//visibility:public"]) +exports_files(["source.toml", "build-provenance.mts", "build-sdk.sh"] + glob(["patches/*.patch"])) + +cargo_toml_env_vars( + name = "cargo_env", + src = "@browser_sources//:wasmer-js/Cargo.toml", + workspace = "@browser_sources//:cargo/Cargo.toml", +) + +rust_shared_library( + name = "host_crate", + crate_name = "wasmer_js", + crate_root = "@browser_sources//:wasmer-js/src/lib.rs", + srcs = ["@browser_sources//:rust_sources"], + compile_data = ["@browser_sources//:wasmer-js/src-js/worker.js"], + edition = BROWSER["rust"]["edition"], + deps = all_crate_deps(normal = True, package_name = "wasmer-js"), + proc_macro_deps = all_crate_deps(proc_macro = True, package_name = "wasmer-js"), + aliases = aliases(package_name = "wasmer-js"), + rustc_env_files = [":cargo_env"], + rustc_flags = ["-Copt-level=" + str(BROWSER["rust"]["profile"]["opt-level"])], +) + +browser_wasm(name = "host_wasm", crate = ":host_crate", lto = "fat" if BROWSER["rust"]["profile"]["lto"] else "off") + +browser_bindings( + name = "bindings", + input = ":host_wasm", + compiler = "@browser_wasm_bindgen_linux_x64//:wasm-bindgen", + mode = "bindgen", + exec_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) + +browser_bindings( + name = "optimized_bindings", + input = ":bindings", + compiler = "@browser_binaryen_linux_x64//:bin/wasm-opt", + mode = "optimize", + exec_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) + +browser_bundle( + name = "dist", + bindings = ":optimized_bindings", + sources = ["@browser_sources//:rollup_sources"], + packages = BROWSER_NPM, +) + +browser_host_package( + name = "host", + dist = ":dist", + std_receipt = "//build_defs/wasix/browser/std:construction_receipt", + packages = BROWSER_NPM, +) + +source_quality_files() diff --git a/src/wasix/browser-host/patches/0018-wasmer-js-bound-direct-stderr.patch b/src/wasix/browser-host/patches/0018-wasmer-js-bound-direct-stderr.patch index d34f7af51..e86045185 100644 --- a/src/wasix/browser-host/patches/0018-wasmer-js-bound-direct-stderr.patch +++ b/src/wasix/browser-host/patches/0018-wasmer-js-bound-direct-stderr.patch @@ -1,6 +1,8 @@ +diff --git a/src/options.rs b/src/options.rs +index d56c81d..d2f8d00 100644 --- a/src/options.rs +++ b/src/options.rs -@@ -189,12 +189,13 @@ +@@ -189,12 +189,13 @@ impl RunOptions { pub(crate) fn configure_direct_builder( &self, builder: &mut WasiEnvBuilder, @@ -15,6 +17,8 @@ Ok(()) } +diff --git a/src/postgres_direct.rs b/src/postgres_direct.rs +index fc015b3..17f74b6 100644 --- a/src/postgres_direct.rs +++ b/src/postgres_direct.rs @@ -1,7 +1,15 @@ @@ -34,7 +38,7 @@ use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; use wasmer::{Instance as WasmerInstance, Store, TypedFunction, Value, WasmTypeList}; use wasmer_wasix::{ -@@ -12,6 +20,133 @@ +@@ -12,6 +20,133 @@ use crate::{runtime::Runtime, tasks::CallerRealmTaskManager, utils::Error, RunOp const DEFAULT_PROGRAM_NAME: &str = "/bin/postgres"; const OLIPHAUNT_EXIT_ALIVE: i32 = 99; @@ -168,7 +172,7 @@ #[wasm_bindgen(inline_js = r#" export function oliphauntCopyToGuest(memory, pointer, input) { -@@ -50,7 +185,10 @@ +@@ -50,7 +185,10 @@ pub async fn instantiate_oliphaunt_direct( module_bytes: Uint8Array, options: RunOptions, ) -> Result { @@ -180,7 +184,7 @@ } #[wasm_bindgen] -@@ -60,6 +198,7 @@ +@@ -60,6 +198,7 @@ pub struct OliphauntDirectInstance { store: Store, _instance: WasmerInstance, _env: WasiFunctionEnv, @@ -188,7 +192,7 @@ guest_memory: JsValue, input_reset: TypedFunction<(), i32>, input_reserve: TypedFunction, -@@ -101,12 +240,18 @@ +@@ -101,12 +240,18 @@ impl OliphauntDirectInstance { /// Execute raw PostgreSQL frontend-protocol bytes synchronously. #[wasm_bindgen(js_name = execProtocolRaw)] pub fn exec_protocol_raw(&mut self, input: Uint8Array) -> Result { @@ -209,7 +213,7 @@ } } -@@ -212,6 +357,7 @@ +@@ -212,6 +357,7 @@ impl OliphauntDirectInstance { module: WebAssembly::Module, module_bytes: Uint8Array, options: RunOptions, @@ -217,7 +221,7 @@ ) -> Result { // Direct execution intentionally has no configurable networking or // worker-backed runtime. RunOptions is reused for args/env/fs mounts. -@@ -222,7 +368,7 @@ +@@ -222,7 +368,7 @@ impl OliphauntDirectInstance { .as_string() .unwrap_or_else(|| DEFAULT_PROGRAM_NAME.to_owned()); let mut builder = WasiEnvBuilder::new(program_name).runtime(runtime.clone()); @@ -226,7 +230,7 @@ let module = wasmer::Module::from((module, module_bytes.to_vec())); let mut store = Store::new(runtime.engine()); -@@ -282,6 +428,7 @@ +@@ -282,6 +428,7 @@ impl OliphauntDirectInstance { store, _instance: instance, _env: env, @@ -234,7 +238,7 @@ guest_memory, input_reset, input_reserve, -@@ -458,6 +605,7 @@ +@@ -458,6 +605,7 @@ impl OliphauntDirectInstance { } fn startup_error(&mut self, error: anyhow::Error) -> Error { diff --git a/src/wasix/browser-host/patches/0021-wasmer-js-stream-direct-pgwire.patch b/src/wasix/browser-host/patches/0021-wasmer-js-stream-direct-pgwire.patch index a33026d70..d81d2a0c3 100644 --- a/src/wasix/browser-host/patches/0021-wasmer-js-stream-direct-pgwire.patch +++ b/src/wasix/browser-host/patches/0021-wasmer-js-stream-direct-pgwire.patch @@ -1,5 +1,5 @@ diff --git a/src/lib.rs b/src/lib.rs -index 6803f8e..0708da4 100644 +index 6803f8e..d8bee81 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,7 @@ mod run; @@ -135,7 +135,7 @@ index d2f8d00..8c0ff2f 100644 builder.add_preopen_dir("/")?; diff --git a/src/postgres_direct.rs b/src/postgres_direct.rs -index 17f74b6..b78334d 100644 +index 17f74b6..ee7708b 100644 --- a/src/postgres_direct.rs +++ b/src/postgres_direct.rs @@ -1,4 +1,5 @@ @@ -144,12 +144,19 @@ index 17f74b6..b78334d 100644 collections::VecDeque, io::{self, SeekFrom}, pin::Pin, -@@ -10 +11 @@ use anyhow::{ensure, Context}; +@@ -7,10 +8,10 @@ use std::{ + }; + + use anyhow::{ensure, Context}; -use js_sys::{Uint8Array, WebAssembly}; +use js_sys::{Function, Uint8Array, WebAssembly}; -@@ -13 +14 @@ use virtual_fs::VirtualFile; + use tokio::io::{AsyncRead, AsyncSeek, AsyncWrite, ReadBuf}; + use virtual_fs::VirtualFile; -use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; +use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue}; + use wasmer::{Instance as WasmerInstance, Store, TypedFunction, Value, WasmTypeList}; + use wasmer_wasix::{ + oliphaunt_direct_memory, Runtime as _, WasiEnvBuilder, WasiError, WasiFunctionEnv, @@ -21,6 +22,292 @@ use crate::{runtime::Runtime, tasks::CallerRealmTaskManager, utils::Error, RunOp const DEFAULT_PROGRAM_NAME: &str = "/bin/postgres"; const OLIPHAUNT_EXIT_ALIVE: i32 = 99; @@ -651,7 +658,7 @@ index 17f74b6..b78334d 100644 wasi_start, diff --git a/src/tool_direct.rs b/src/tool_direct.rs new file mode 100644 -index 0000000..74719c7 +index 0000000..4768438 --- /dev/null +++ b/src/tool_direct.rs @@ -0,0 +1,432 @@ diff --git a/src/wasix/node-addon/BUILD.bazel b/src/wasix/node-addon/BUILD.bazel new file mode 100644 index 000000000..594bceb11 --- /dev/null +++ b/src/wasix/node-addon/BUILD.bazel @@ -0,0 +1,64 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files", "source_quality_files") +load("//build_defs/languages:rust.bzl", "cargo_generator", "cargo_generator_test", "cargo_napi_library", "cargo_library_test", "cargo_package_env", "napi_artifact") +load("//build_defs/languages:napi-noop.bzl", "napi_unit_crate_deps") +load("@rules_rust//rust:defs.bzl", "rust_clippy_test") +load("@native_cargo_metadata//:cargo.bzl", "CARGO") +load("@cargo_crates//:defs.bzl", "crate_deps") +load("//build_defs/wasix:napi.bzl", "wasix_napi_carriers", "wasix_napi_inputs", "wasix_napi_installed_test", "wasix_napi_release") +load("//build_defs/native/carriers:release-family.bzl", "native_release_checksum_family") + +package(default_visibility = ["//visibility:public"]) + +native_release_checksum_family(product = "oliphaunt-wasix-napi") +exports_files(["Cargo.toml", "package.json"] + glob(["tools/*.mts", "packages/*/package.json", "packages/*/README.md"])) + +PATH_DEPS = { + "oliphaunt-pgwire-server": "//src/wasix/pgwire-server:napi_lib", + "oliphaunt-wasix": "//src/wasix/sdks/rust:napi_lib", + "liboliphaunt-wasix-portable": "@wasix_runtime_carriers//src/wasix/runtime/crates/assets:lib", +} + +cargo_package_env() +cargo_generator_test() +cargo_generator(path_dependencies = PATH_DEPS, proc_macro_names = ["napi-derive"], cargo_facts = CARGO, crate_dependencies = crate_deps) +cargo_napi_library(name = "addon_library", path_dependencies = PATH_DEPS, proc_macro_names = ["napi-derive"], build_script = ":build_script", cargo_facts = CARGO, crate_dependencies = crate_deps) +napi_artifact(name = "addon", library = ":addon_library", out = "oliphaunt_wasix_napi.node") +rust_clippy_test(name = "clippy_test", targets = [":addon_library", ":unit_test", ":build_script_"], transitive = False, size = "small") + +wasix_napi_inputs(name = "release_inputs", cargo_facts = CARGO) +_RELEASE_PATH_DEPS = PATH_DEPS | { + "oliphaunt-pgwire-server": "//src/wasix/pgwire-server:napi_release_lib", + "oliphaunt-wasix": "//src/wasix/sdks/rust:napi_release_lib", + "liboliphaunt-wasix-portable": "//src/wasix/runtime/crates/assets:napi_release_lib", +} +cargo_library_test(crate = None, srcs = glob(["src/**/*.rs"]), crate_root = "src/lib.rs", features = ["extensions", "test-noop"], default_features = False, + path_dependencies = _RELEASE_PATH_DEPS, proc_macro_names = ["napi-derive"], build_script = ":build_script", + cargo_facts = CARGO, crate_dependencies = napi_unit_crate_deps, size = "small") +cargo_generator(name = "release_build_script", path_dependencies = _RELEASE_PATH_DEPS, proc_macro_names = ["napi-derive"], features = ["release"], + cargo_facts = CARGO, crate_dependencies = crate_deps, data = [":release_inputs"], build_script_env = { + "OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD": "1", + "OLIPHAUNT_ARTIFACT_CRATE_EMIT_CARGO_MANIFEST": "0", + "OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR": "$(execpath :release_inputs)/portable", + "OLIPHAUNT_WASM_GENERATED_AOT_DIR": "$(execpath :release_inputs)/aot", + "OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT": "$(execpath :release_inputs)/extensions", + "OLIPHAUNT_WASIX_NAPI_BUILD_INPUTS": "$(execpath :release_inputs)/build-inputs.json", +}) +cargo_napi_library(name = "release_addon_library", path_dependencies = _RELEASE_PATH_DEPS, proc_macro_names = ["napi-derive"], features = ["release"], + build_script = ":release_build_script", cargo_facts = CARGO, crate_dependencies = crate_deps) +wasix_napi_release(name = "release_addon", library = ":release_addon_library", inputs = ":release_inputs") +# Unit tests and ordinary Clippy follow the real local SDK payloads; qualify them once where +# the Linux WASIX execution platform is already configured. +wasix_napi_carriers(producer = ":release_addon", qualification = [":release_installed_test", ":generator_test", "//build_defs/wasix:napi_envelopes_test", "//build_defs/languages:napi_payload_profile_test"] + select({ + "//build_defs/native:linux_x86_64": [":clippy_test", ":unit_test"], + "//conditions:default": [], +})) +wasix_napi_installed_test(name = "release_installed_test", producer = ":release_addon", carrier = ":release_carriers", size = "large", timeout = "long", tags = ["manual", "installed-consumer"]) + +source_quality_files() + +rust_quality_files() + +# Source-only inputs for the existing SDK package policy tests. +exports_files([ + "tools/carrier-contract.mts", +], visibility = ["//visibility:public"]) diff --git a/src/wasix/node-addon/Cargo.toml b/src/wasix/node-addon/Cargo.toml index f04684fb2..51c26a823 100644 --- a/src/wasix/node-addon/Cargo.toml +++ b/src/wasix/node-addon/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "oliphaunt-wasix-napi" version = "0.2.1" -edition = "2024" -rust-version = "1.93" +edition.workspace = true +rust-version.workspace = true description = "Node-API adapter for the Oliphaunt WASIX Rust runtime." -repository = "https://github.com/f0rr0/oliphaunt" -homepage = "https://oliphaunt.dev" -license = "MIT" +repository.workspace = true +homepage.workspace = true +license.workspace = true publish = false build = "build.rs" @@ -99,8 +99,8 @@ sha2 = "0.10" oliphaunt-pgwire-server = { path = "../pgwire-server" } napi = { version = "=3.12.2", default-features = false, features = ["napi8"] } napi-derive = { version = "=3.6.3", default-features = false, features = ["strict", "type-def"] } -liboliphaunt-wasix-portable = { version = "*", path = "../runtime/crates/assets" } -oliphaunt-wasix = { version = "*", path = "../sdks/rust", features = ["__internal-napi"] } +liboliphaunt-wasix-portable = { version = "=0.3.2", path = "../runtime/crates/assets" } +oliphaunt-wasix = { workspace = true, features = ["__internal-napi"] } [target.'cfg(unix)'.dependencies] rustix = { version = "=1.1.4", features = ["fs"] } diff --git a/src/wasix/node-addon/build.rs b/src/wasix/node-addon/build.rs index 03deee968..a8ae9f6b1 100644 --- a/src/wasix/node-addon/build.rs +++ b/src/wasix/node-addon/build.rs @@ -2,6 +2,7 @@ use std::path::{Path, PathBuf}; const RELEASE_INPUT_ENVS: &[&str] = &[ "OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD", + "OLIPHAUNT_ARTIFACT_CRATE_EMIT_CARGO_MANIFEST", "OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR", "OLIPHAUNT_WASM_GENERATED_AOT_DIR", "OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT", @@ -62,6 +63,15 @@ fn validate_release_inputs() { required_file(&inventory, "validated WASIX N-API build-input inventory"); println!("cargo::rerun-if-changed={}", inventory.display()); + if !requires_cargo_artifact_manifests( + std::env::var("OLIPHAUNT_ARTIFACT_CRATE_EMIT_CARGO_MANIFEST") + .ok() + .as_deref(), + ) { + // Native construction observes declared payload Files instead of Cargo relay manifests. + return; + } + // `oliphaunt-wasix` relays the manifests emitted by the exact payload // crates it compiled. These prove Cargo selected the embedded // portable/core-AOT inputs, not only that similarly named @@ -83,6 +93,16 @@ fn validate_release_inputs() { } } +fn requires_cargo_artifact_manifests(mode: Option<&str>) -> bool { + match mode { + None | Some("1") => true, + Some("0") => false, + Some(other) => { + panic!("OLIPHAUNT_ARTIFACT_CRATE_EMIT_CARGO_MANIFEST must be 0 or 1, got {other}") + } + } +} + fn required_path(name: &str) -> PathBuf { std::env::var_os(name) .filter(|value| !value.is_empty()) @@ -103,11 +123,12 @@ fn required_directory(name: &str) -> PathBuf { } fn required_file(path: &Path, label: &str) { - let metadata = std::fs::symlink_metadata(path) + // Bazel transports declared input files through sandbox symlinks. + let metadata = std::fs::metadata(path) .unwrap_or_else(|error| panic!("inspect {label} {}: {error}", path.display())); assert!( - metadata.is_file() && !metadata.file_type().is_symlink() && metadata.len() > 0, - "{label} must be a non-empty regular non-symlink file: {}", + metadata.is_file() && metadata.len() > 0, + "{label} must be a non-empty regular file: {}", path.display(), ); } @@ -118,3 +139,20 @@ fn required_env_file(name: &str, label: &str) { required_file(&path, label); println!("cargo::rerun-if-changed={}", path.display()); } + +#[cfg(test)] +mod tests { + use super::requires_cargo_artifact_manifests; + + #[test] + fn only_explicit_native_mode_disables_cargo_manifest_relay() { + assert!(requires_cargo_artifact_manifests(None)); + assert!(requires_cargo_artifact_manifests(Some("1"))); + assert!(!requires_cargo_artifact_manifests(Some("0"))); + for mode in ["", "false", " 0", "0 ", "2"] { + assert!( + std::panic::catch_unwind(|| requires_cargo_artifact_manifests(Some(mode))).is_err() + ); + } + } +} diff --git a/src/wasix/node-addon/moon.yml b/src/wasix/node-addon/moon.yml index 6e6f7f1a9..07eb0479c 100644 --- a/src/wasix/node-addon/moon.yml +++ b/src/wasix/node-addon/moon.yml @@ -22,18 +22,19 @@ project: release: component: "oliphaunt-wasix-napi" packagePath: "src/wasix/node-addon" - artifactTargets: - preset: "wasix-napi-addon" - targets: - - "linux-arm64-gnu" - - "linux-x64-gnu" - - "macos-arm64" - - "windows-x64-msvc" owners: defaultOwner: "@oliphaunt/wasix-napi" +workspace: + mergeStrategies: + fileGroups: replace + fileGroups: + cargo-workspace: + - "/src/wasix/node-addon/Cargo.lock" + - "/src/wasix/node-addon/Cargo.toml" + - "/rust-toolchain.toml" code: - "**/*" - "!**/*.md" @@ -72,7 +73,7 @@ tasks: tags: ["quality", "unit", "requires-rust"] script: | set -e - bash ../../../tools/dev/bun.sh test --cwd src/wasix/node-addon ./tools/detect-linux-libc.test.mts ./tools/package-contract.test.mts ../../../tools/packaging/local-npm-tarball.test.mts + bash ../../../tools/dev/bun.sh test --cwd src/wasix/node-addon ./tools/detect-linux-libc.test.mts ./tools/package-contract.test.mts ./tools/workspace-runtime-contract.test.mts ../../../tools/packaging/local-npm-tarball.test.mts bash tools/package-platform.test.sh cargo test --manifest-path Cargo.toml --locked --no-default-features --features extensions,test-noop --lib env: @@ -89,7 +90,7 @@ tasks: rust-format-check: tags: ["quality", "static", "format", "requires-rust"] - command: "cargo fmt -p oliphaunt-wasix-napi --check" + command: "cargo fmt --manifest-path src/wasix/node-addon/Cargo.toml -p oliphaunt-wasix-napi --check" inputs: ["/src/wasix/node-addon/**/*.rs","/src/wasix/node-addon/Cargo.toml","/clippy.toml","@group(cargo-workspace)"] options: runFromWorkspaceRoot: true @@ -98,7 +99,7 @@ tasks: - target: cargo-sources cacheStrategy: hash tags: ["quality", "static", "requires-rust"] - command: "cargo clippy -p oliphaunt-wasix-napi --all-targets --locked -- -D warnings" + command: "cargo clippy --manifest-path src/wasix/node-addon/Cargo.toml -p oliphaunt-wasix-napi --all-targets --locked -- -D warnings" env: CARGO_TARGET_DIR: "target" inputs: ["/src/wasix/node-addon/**/*.rs","/src/wasix/node-addon/Cargo.toml","/clippy.toml","@group(cargo-workspace)"] diff --git a/src/wasix/node-addon/release.toml b/src/wasix/node-addon/release.toml index 05e0022c3..8e3ebe56c 100644 --- a/src/wasix/node-addon/release.toml +++ b/src/wasix/node-addon/release.toml @@ -10,7 +10,6 @@ registry_packages = [ ] release_artifacts = ["node-api-prebuilds", "npm-optional-platform-packages"] embedded_cargo_manifests = ["src/wasix/node-addon/Cargo.toml"] -embedded_payload_products = ["liboliphaunt-wasix", "postgres-tools-wasix", "database-resources"] [compatibility_versions.oliphaunt-wasix-napi-runtime] public_support = false @@ -47,3 +46,12 @@ public_support = false source_product = "oliphaunt-wasix-rust" path = "src/wasix/node-addon/package.json" parser = "json:oliphaunt.rustBindingVersion" + +[artifact_targets] +preset = "wasix-napi-addon" +targets = [ + "linux-arm64-gnu", + "linux-x64-gnu", + "macos-arm64", + "windows-x64-msvc", +] diff --git a/src/wasix/node-addon/tools/build-native.sh b/src/wasix/node-addon/tools/build-native.sh index 64fe032c4..10596c2b8 100755 --- a/src/wasix/node-addon/tools/build-native.sh +++ b/src/wasix/node-addon/tools/build-native.sh @@ -82,8 +82,8 @@ fi manifest="src/wasix/node-addon/Cargo.toml" package_manifest="src/wasix/node-addon/package.json" -# Source qualification compiles the local runtime. Package staging records this -# identity and marks mismatched release pins as ineligible for publication. +# Cargo resolves the adopted registry runtime. Legacy staging is qualification +# only when its current producer folders differ from those resolved dependencies. metadata_contract="$( bun "$workspace_root/src/wasix/node-addon/tools/native-build-data.mts" metadata "$package_manifest" )" diff --git a/src/wasix/node-addon/tools/carrier-contract.mts b/src/wasix/node-addon/tools/carrier-contract.mts new file mode 100644 index 000000000..0196ce364 --- /dev/null +++ b/src/wasix/node-addon/tools/carrier-contract.mts @@ -0,0 +1,496 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import path from 'node:path'; +import { inspectPlatformBinaryEntries } from '../../../../tools/packaging/platform-binary-contract.mts'; +import { + WINDOWS_VC_RUNTIME_DLLS, + WINDOWS_VC_RUNTIME_RECEIPT, +} from '../../../../tools/packaging/windows-vc-runtime-closure.mts'; +import { + AOT_PACKAGES, + AOT_TARGET_TRIPLES, + EXTENSION_AOT_PACKAGE_SUFFIXES, +} from '../../runtime/tools/wasix-cargo-artifact-contract.mts'; + +const BINARY = 'oliphaunt_wasix_napi.node'; +export const WASIX_NAPI_SOURCE_PATCH_MEMBER = + 'source-patches/held-wasix-relocatable-includes.patch'; +const compareText = (left: string, right: string) => (left < right ? -1 : left > right ? 1 : 0); + +export type WasixNapiRuntimeContract = { + runtimeProduct: string; + runtimeVersion: string; + addonAbiVersion: number; + nodeApiVersion: number; + qualificationOnly?: boolean; + packageLicense: string; +}; +export type WasixNapiTarget = { + target: string; + triple?: string; + npmPackage: string; + npmOs: string; + npmCpu: string; + npmLibc?: string; +}; +export type WasixNapiConstructionContract = { + targetTriple: string; + runtimeVersion: string; + sdkVersion: string; + sqlNames: readonly string[]; + sourcePatch?: { path: string; sha256: string; size: number }; +}; + +/** Conventional Cargo feature expansion supplies the release member expectation. */ +export function wasixNapiReleaseSqlNames(manifest: any, sqlNames: readonly string[]) { + const enabled = new Set([ + 'release', + ...(Object.hasOwn(manifest.features ?? {}, 'default') ? ['default'] : []), + ]); + for (const feature of enabled) { + const members = manifest.features?.[feature]; + assert( + members || manifest.dependencies?.[feature]?.optional === true, + `unknown addon Cargo feature ${feature}`, + ); + for (const member of members ?? []) + if (!member.includes('/') && !member.startsWith('dep:')) enabled.add(member); + } + const names = [...enabled] + .filter((feature) => feature.startsWith('extension-')) + .map((feature) => { + const matches = sqlNames.filter( + (name) => `extension-${name.replaceAll('_', '-')}` === feature, + ); + assert.equal(matches.length, 1, 'release Cargo feature has no unique canonical SQL member'); + return matches[0]; + }) + .sort(); + assert(names.length > 0 && new Set(names).size === names.length); + return names; +} + +/** Source/run authentication is supplied by native build evidence, not a moving Git stamp. */ +export function assertWasixNapiConstructionData( + value: any, + target: string, + binarySha256: string, + contract: WasixNapiConstructionContract, +) { + const source = value.schema === 'oliphaunt-wasix-napi-construction-data-v3'; + assert( + source || value.schema === 'oliphaunt-wasix-napi-construction-data-v2', + 'unknown WASIX Node-API construction schema', + ); + assert(!Object.hasOwn(value, 'scope'), 'construction data does not authorize release'); + assert.equal(value.product, 'oliphaunt-wasix-napi'); + assert.equal(value.target, target); + assert( + !Object.hasOwn(value, 'sourceSha') && !Object.hasOwn(value, 'artifactSourceSha'), + 'construction cannot invent Git source authentication', + ); + const inputs = value.buildInputs; + assert.equal( + inputs.schema, + source ? 'oliphaunt-wasix-napi-build-inputs-v3' : 'oliphaunt-wasix-napi-build-inputs-v2', + ); + assert.equal(inputs.target, target); + assert(Object.hasOwn(AOT_TARGET_TRIPLES, target), 'unsupported addon construction target'); + assert.equal(inputs.targetTriple, AOT_TARGET_TRIPLES[target]); + assert.equal(inputs.targetTriple, contract.targetTriple); + assert.deepEqual(value.build, { + cargoProfile: 'release', + incremental: false, + codegenUnits: 1, + lto: 'thin', + strip: 'symbols', + features: ['release'], + targetTriple: inputs.targetTriple, + }); + assert.equal(value.binary.filename, BINARY); + assert.equal(value.binary.sha256, binarySha256); + assert(!Object.hasOwn(value, 'binaries'), 'construction binds one addon binary'); + assert.match(binarySha256, /^[0-9a-f]{64}$/u); + if (source) { + assert(!Object.hasOwn(value, 'sourcePatch'), 'source construction cannot claim source patches'); + assertWasixNapiSourceInputs(inputs, contract); + return value; + } + assert( + Array.isArray(inputs.dependencies) && inputs.dependencies.length > 0, + 'construction requires exact compiled registry origins', + ); + const files = new Map(); + const names = new Set(); + for (const dependency of inputs.dependencies) { + assert(!names.has(dependency.name), 'duplicate compiled registry origin'); + names.add(dependency.name); + assert.match(dependency.name, /^[a-zA-Z0-9_-]+$/u); + assert.match( + dependency.version, + /^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)(?:[-+][0-9A-Za-z.-]+)?$/u, + ); + assert.equal(dependency.source, 'registry+https://github.com/rust-lang/crates.io-index'); + assert.match(dependency.checksum, /^[0-9a-f]{64}$/u); + assert(Array.isArray(dependency.files) && dependency.files.length > 0); + for (const file of dependency.files) { + assert(!files.has(file.path), 'duplicate compiled registry file'); + assert(file.path.startsWith(`registry/${dependency.name}-${dependency.version}/`)); + assert( + !file.path.includes('\\') && + file.path.split('/').every((part: string) => part && part !== '.' && part !== '..'), + ); + assert.match(file.sha256, /^[0-9a-f]{64}$/u); + assert(Number.isSafeInteger(file.size) && file.size > 0); + files.set(file.path, file); + } + assert( + files.has(`registry/${dependency.name}-${dependency.version}/Cargo.toml`), + 'compiled registry origin has no conventional manifest', + ); + } + const portableName = 'liboliphaunt-wasix-portable'; + const coreName = AOT_PACKAGES[target]; + const contribName = 'oliphaunt-extension-contrib-pg18-wasix'; + const contribAotName = `oliphaunt-extension-contrib-pg18-aot-${EXTENSION_AOT_PACKAGE_SUFFIXES[contract.targetTriple]}`; + assert.deepEqual( + [...names].sort(), + ['oliphaunt-wasix', portableName, coreName, contribName, contribAotName].sort(), + 'construction requires its exact compiled SDK, runtime and contrib origins', + ); + const origin = (name: string) => inputs.dependencies.find((row: any) => row.name === name); + const sourcePatch = contract.sourcePatch; + assert(sourcePatch, 'registry construction requires its declared source patch'); + assert.equal(sourcePatch.path, WASIX_NAPI_SOURCE_PATCH_MEMBER); + assert.match(sourcePatch.sha256, /^[0-9a-f]{64}$/u); + assert(Number.isSafeInteger(sourcePatch.size) && sourcePatch.size > 0); + for (const dependency of inputs.dependencies) { + if (dependency.name === portableName || dependency.name === coreName) { + assert.deepEqual( + dependency.patches, + [sourcePatch], + 'compiled source patch differs from the declared recipe', + ); + assert( + files.has(`registry/${dependency.name}-${dependency.version}/build-support.rs`), + 'compiled patched registry source is missing', + ); + } else + assert( + !Object.hasOwn(dependency, 'patches'), + 'unpatched compiled registry origin claims a patch', + ); + } + assert.equal(origin('oliphaunt-wasix').version, contract.sdkVersion); + assert.equal(origin(portableName).version, contract.runtimeVersion); + assert.equal(origin(coreName).version, contract.runtimeVersion); + const bound = (file: any) => { + assert(file && files.has(file.path), 'construction input is outside compiled registry origins'); + const { sqlName: _sqlName, targetTriple: _targetTriple, ...identity } = file; + assert.deepEqual( + identity, + files.get(file.path), + 'construction input differs from compiled registry file', + ); + }; + bound(inputs.inputs.portableManifest); + bound(inputs.inputs.runtimeArchive); + bound(inputs.inputs.runtimeAotManifest); + assert.equal( + inputs.inputs.portableManifest.path, + `registry/${portableName}-${contract.runtimeVersion}/payload/manifest.json`, + ); + assert( + inputs.inputs.runtimeArchive.path.startsWith( + `registry/${portableName}-${contract.runtimeVersion}/payload/`, + ), + ); + assert.equal( + inputs.inputs.runtimeAotManifest.path, + `registry/${coreName}-${contract.runtimeVersion}/artifacts/manifest.json`, + ); + assert.equal(inputs.inputs.runtimeAotManifest.targetTriple, inputs.targetTriple); + assert.equal(inputs.inputs.extensionArtifacts.length, 1); + const contrib = inputs.inputs.extensionArtifacts[0]; + assert.equal(contrib.product, 'oliphaunt-extension-contrib-pg18'); + const portableNames = contrib.portableArchives.map((row: any) => row.sqlName).sort(); + const aotNames = contrib.aotManifests.map((row: any) => row.sqlName).sort(); + assert(portableNames.length > 0 && new Set(portableNames).size === portableNames.length); + assert.deepEqual( + portableNames, + [...contract.sqlNames].sort(), + 'construction differs from the release Cargo extension closure', + ); + assert.deepEqual(aotNames, portableNames, 'construction portable and AOT member sets differ'); + for (const row of contrib.portableArchives) { + bound(row); + assert.equal( + row.path, + `registry/${contribName}-${origin(contribName).version}/payload/files/extensions/${row.sqlName}/extension.tar.zst`, + ); + } + for (const row of contrib.aotManifests) { + assert.equal(row.targetTriple, inputs.targetTriple); + bound(row); + assert.equal( + row.path, + `registry/${contribAotName}-${origin(contribAotName).version}/manifests/${row.sqlName}.json`, + ); + } + assert.equal(inputs.cargoLock.path, 'Cargo.lock'); + assert.match(inputs.cargoLock.sha256, /^[0-9a-f]{64}$/u); + assert(Number.isSafeInteger(inputs.cargoLock.size) && inputs.cargoLock.size > 0); + return value; +} + +function assertWasixNapiSourceInputs(inputs: any, contract: WasixNapiConstructionContract) { + assert.equal(inputs.runtimeVersion, contract.runtimeVersion); + assert( + !Object.hasOwn(inputs, 'dependencies') && !Object.hasOwn(inputs, 'sourcePatch'), + 'source construction cannot claim registry origins or source patches', + ); + assert( + !Object.hasOwn(inputs, 'cargoLock'), + 'source construction cannot claim the workspace lock', + ); + assert(Array.isArray(inputs.files) && inputs.files.length > 0, 'source inventory is empty'); + const files = new Map(); + for (const file of inputs.files) { + assert.deepEqual(Object.keys(file).sort(), ['path', 'sha256', 'size']); + assert( + typeof file.path === 'string' && + file.path && + !path.posix.isAbsolute(file.path) && + !/^[A-Za-z]:/u.test(file.path) && + !/[\u0000-\u001f\u007f]/u.test(file.path) && + !file.path.includes('\\') && + file.path.split('/').every((part: string) => part && part !== '.' && part !== '..'), + 'noncanonical source construction file', + ); + assert( + !file.path.startsWith('registry/') && file.path !== WASIX_NAPI_SOURCE_PATCH_MEMBER, + 'source construction cannot claim registry origins or source patches', + ); + assert.notEqual(file.path, 'Cargo.lock', 'source inventory cannot include the workspace lock'); + assert.notEqual( + file.path, + 'src/wasix/sdks/rust/Cargo.toml', + 'source inventory cannot include the SDK source manifest', + ); + assert(!files.has(file.path), 'duplicate source construction file'); + assert.match(file.sha256, /^[0-9a-f]{64}$/u); + assert(Number.isSafeInteger(file.size) && file.size >= 0); + files.set(file.path, file); + } + assert.deepEqual( + [...files.keys()], + [...files.keys()].sort(compareText), + 'source inventory is not ordered', + ); + assert(files.get('layout.json')?.size > 0, 'source inventory omits its build layout'); + const bound = (file: any) => { + assert(file && files.has(file.path), 'construction input is outside its source inventory'); + const { sqlName: _sqlName, targetTriple: _targetTriple, ...identity } = file; + assert.deepEqual(identity, files.get(file.path), 'construction input differs from source file'); + assert(file.size > 0, 'construction payload must be nonempty'); + }; + assert.deepEqual(Object.keys(inputs.sdk).sort(), ['name', 'version']); + assert.equal(inputs.sdk.name, 'oliphaunt-wasix'); + assert.equal(inputs.sdk.version, contract.sdkVersion); + bound(inputs.inputs.portableManifest); + bound(inputs.inputs.runtimeArchive); + bound(inputs.inputs.runtimeAotManifest); + assert.equal(inputs.inputs.portableManifest.path, 'portable/manifest.json'); + assert.equal(inputs.inputs.runtimeArchive.path, 'portable/oliphaunt.wasix.tar.zst'); + assert.equal(inputs.inputs.runtimeAotManifest.path, `aot/${contract.targetTriple}/manifest.json`); + assert.equal(inputs.inputs.runtimeAotManifest.targetTriple, contract.targetTriple); + assert( + files.get('portable/bin/initdb.wasix.wasm')?.size > 0, + 'source inventory omits packaged initdb', + ); + const product = 'oliphaunt-extension-contrib-pg18'; + assert( + files.get(`extensions/${product}/extension-artifacts.json`)?.size > 0, + 'source inventory omits the original contrib manifest', + ); + assert.equal(inputs.inputs.extensionArtifacts.length, 1); + const contrib = inputs.inputs.extensionArtifacts[0]; + assert.equal(contrib.product, product); + const portableNames = contrib.portableArchives.map((row: any) => row.sqlName).sort(); + const aotNames = contrib.aotManifests.map((row: any) => row.sqlName).sort(); + assert(portableNames.length > 0 && new Set(portableNames).size === portableNames.length); + assert.deepEqual( + portableNames, + [...contract.sqlNames].sort(), + 'construction differs from the release Cargo extension closure', + ); + assert.deepEqual(aotNames, portableNames, 'construction portable and AOT member sets differ'); + for (const row of contrib.portableArchives) { + bound(row); + assert.equal( + row.path, + `extensions/${product}/member-assets/${row.sqlName}/${product}-${contract.runtimeVersion}-wasix-portable.tar.zst`, + ); + } + for (const row of contrib.aotManifests) { + bound(row); + assert.equal(row.targetTriple, contract.targetTriple); + assert.equal( + row.path, + `extensions/${product}/wasix-aot/${inputs.target}/${row.sqlName}/manifest.json`, + ); + } +} + +/** The expected runtime is the selected consumer pin, independent of current producer versions. */ +export function assertWasixNapiCarrierManifest( + manifest: any, + target: WasixNapiTarget, + version: string, + label: string, + contract: WasixNapiRuntimeContract, +) { + if (manifest.name !== target.npmPackage || manifest.version !== version) + throw new Error(`${label} must identify ${target.npmPackage}@${version}`); + if (manifest.license !== contract.packageLicense) + throw new Error( + `${label} package license must be ${contract.packageLicense}, got ${JSON.stringify(manifest.license)}`, + ); + if ( + manifest.oliphaunt?.target !== target.target || + manifest.oliphaunt?.runtimeProduct !== contract.runtimeProduct || + manifest.oliphaunt?.runtimeVersion !== contract.runtimeVersion || + manifest.oliphaunt?.qualificationOnly !== contract.qualificationOnly || + manifest.oliphaunt?.addonAbiVersion !== contract.addonAbiVersion || + manifest.oliphaunt?.nodeApiVersion !== contract.nodeApiVersion || + JSON.stringify(manifest.oliphaunt?.profiles) !== JSON.stringify(['standard', 'icu']) + ) + throw new Error(`${label} has incompatible WASIX Node-API target/runtime/ABI/profile metadata`); + if ( + JSON.stringify(manifest.os) !== JSON.stringify([target.npmOs]) || + JSON.stringify(manifest.cpu) !== JSON.stringify([target.npmCpu]) || + (target.npmLibc === undefined + ? Object.hasOwn(manifest, 'libc') + : JSON.stringify(manifest.libc) !== JSON.stringify([target.npmLibc])) || + manifest.optional !== true || + manifest.type !== 'commonjs' || + Object.hasOwn(manifest, 'scripts') + ) + throw new Error(`${label} has incompatible npm platform or lifecycle metadata`); + if ( + JSON.stringify(manifest.files) !== + JSON.stringify([ + 'prebuilds', + 'artifact-provenance.json', + 'README.md', + 'LICENSE', + 'THIRD_PARTY_NOTICES.md', + 'THIRD_PARTY_NOTICES.oliphaunt-wasix.md', + 'THIRD_PARTY_LICENSES', + ]) + ) + throw new Error(`${label} must declare the exact one-addon package file surface`); + if ( + manifest.exports?.[`./${BINARY}`] !== `./prebuilds/${BINARY}` || + JSON.stringify(Object.keys(manifest.exports ?? {})) !== + JSON.stringify([`./${BINARY}`, './artifact-provenance.json', './package.json']) + ) + throw new Error(`${label} must expose exactly one stable addon binary subpath`); + return manifest; +} + +export function assertSingleWasixNapiAddonMember(entries, binaryMember, label = 'carrier') { + const nativeMembers = [...entries.keys()].filter((name) => name.endsWith('.node')); + if (JSON.stringify(nativeMembers) !== JSON.stringify([binaryMember])) + throw new Error( + `${label} must contain exactly one native addon member ${binaryMember}; got ${nativeMembers.join(', ')}`, + ); +} + +export function assertWasixNapiPlatformEntries( + entries, + { target, label = 'carrier', prefix = '', binaryDirectory = '' }, +) { + inspectPlatformBinaryEntries( + [...entries].map(([name, entry]) => ({ name, ...entry })), + { target, rootLabel: label }, + ); + if (target !== 'windows-x64-msvc') return; + const sibling = (name) => [prefix, binaryDirectory, name].filter(Boolean).join('/'); + const runtimeNames = new Set(WINDOWS_VC_RUNTIME_DLLS); + const actualRuntimeMembers = [...entries] + .filter( + ([name, entry]) => entry?.isFile && runtimeNames.has(path.posix.basename(name).toLowerCase()), + ) + .map(([name]) => name) + .sort(compareText); + const expectedRuntimeMembers = WINDOWS_VC_RUNTIME_DLLS.filter((name) => + entries.has(sibling(name)), + ) + .map((name) => sibling(name)) + .sort(compareText); + if (JSON.stringify(actualRuntimeMembers) !== JSON.stringify(expectedRuntimeMembers)) + throw new Error( + `${label} must place its exact app-local VC runtime closure beside ${sibling(BINARY)}`, + ); + const expectedReceiptMember = sibling(WINDOWS_VC_RUNTIME_RECEIPT); + const actualReceiptMembers = [...entries.keys()] + .filter((name) => path.posix.basename(name).toLowerCase() === WINDOWS_VC_RUNTIME_RECEIPT) + .sort(compareText); + if ( + JSON.stringify(actualReceiptMembers) !== + JSON.stringify(expectedRuntimeMembers.length > 0 ? [expectedReceiptMember] : []) + ) + throw new Error(`${label} must carry one VC runtime receipt beside its app-local closure`); + if (expectedRuntimeMembers.length === 0) return; + const receipt = entries.get(expectedReceiptMember); + if (!receipt?.isFile || receipt.isSymbolicLink) + throw new Error(`${label} is missing regular member ${expectedReceiptMember}`); + const expectedReceipt = expectedRuntimeMembers + .map((member) => { + const digest = createHash('sha256') + .update(Buffer.from(entries.get(member).data())) + .digest('hex'); + return `${digest} ${path.posix.basename(member)}\n`; + }) + .join(''); + if (Buffer.from(receipt.data()).toString('utf8') !== expectedReceipt) + throw new Error(`${label} ${expectedReceiptMember} does not bind its exact VC runtime bytes`); +} + +export const WASIX_NAPI_PLATFORM_PACKAGES = Object.freeze([ + '@oliphaunt/wasix-napi-darwin-arm64', + '@oliphaunt/wasix-napi-linux-arm64-gnu', + '@oliphaunt/wasix-napi-linux-x64-gnu', + '@oliphaunt/wasix-napi-win32-x64-msvc', +]); + +export function assertWasixTypescriptNativeCarrier(manifest, carrier) { + const sdk = manifest.oliphaunt; + const native = carrier.oliphaunt; + if ( + manifest.name !== '@oliphaunt/wasix-ts' || + sdk?.runtimeProduct !== 'liboliphaunt-wasix' || + sdk?.wasixNapiProduct !== 'oliphaunt-wasix-napi' || + !/^\d+\.\d+\.\d+$/u.test(sdk?.runtimeVersion ?? '') || + !/^\d+\.\d+\.\d+$/u.test(sdk?.wasixNapiVersion ?? '') || + !Number.isSafeInteger(sdk?.wasixAddonAbiVersion) || + sdk.wasixAddonAbiVersion < 1 || + !Number.isSafeInteger(sdk?.nodeApiVersion) || + sdk.nodeApiVersion < 1 || + Object.hasOwn(sdk, 'qualificationOnly') || + Object.hasOwn(native ?? {}, 'qualificationOnly') || + !WASIX_NAPI_PLATFORM_PACKAGES.includes(carrier.name) || + carrier.version !== sdk?.wasixNapiVersion || + manifest.optionalDependencies?.[carrier.name] !== carrier.version || + native?.runtimeProduct !== sdk?.runtimeProduct || + native?.runtimeVersion !== sdk?.runtimeVersion || + native?.addonAbiVersion !== sdk?.wasixAddonAbiVersion || + native?.nodeApiVersion !== sdk?.nodeApiVersion || + JSON.stringify(native?.profiles) !== JSON.stringify(['standard', 'icu']) + ) { + throw new Error( + `wasix-typescript-package.mts: ${carrier.name}@${carrier.version} is incompatible with @oliphaunt/wasix-ts@${manifest.version}: SDK requires N-API ${sdk?.wasixNapiVersion} embedding runtime ${sdk?.runtimeVersion}, carrier embeds runtime ${native?.runtimeVersion}`, + ); + } +} diff --git a/src/wasix/node-addon/tools/check-release-assets.mts b/src/wasix/node-addon/tools/check-release-assets.mts index c479b8699..0dc0986e0 100644 --- a/src/wasix/node-addon/tools/check-release-assets.mts +++ b/src/wasix/node-addon/tools/check-release-assets.mts @@ -4,9 +4,23 @@ import { createHash } from 'node:crypto'; import { readFileSync } from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; -import { workspaceCarrierManifest } from './workspace-runtime-contract.mts'; +import { resolveCargoWorkspaceInheritance } from '../../../../tools/packaging/cargo-manifest.mts'; import { finalizeHelperAssets } from '../../../../tools/packaging/finalize-helper-assets.mts'; -import { inspectPlatformBinaryEntries } from '../../../../tools/packaging/platform-binary-contract.mts'; +import { + assertWasixNapiCarrierManifest as assertCarrierManifest, + assertSingleWasixNapiAddonMember, + assertWasixNapiConstructionData, + assertWasixNapiPlatformEntries, + WASIX_NAPI_SOURCE_PATCH_MEMBER, + wasixNapiReleaseSqlNames, +} from './carrier-contract.mts'; +import { workspaceCarrierManifest } from './workspace-runtime-contract.mts'; + +export { + assertSingleWasixNapiAddonMember, + assertWasixNapiPlatformEntries, +} from './carrier-contract.mts'; + import { readPortableArchiveEntries } from '../../../../tools/packaging/portable-archive.mts'; import { assertFileExists, @@ -18,10 +32,6 @@ import { assertReleaseNoticesInEntries, releaseProfilePackageLicense, } from '../../../../tools/packaging/release-notices.mts'; -import { - WINDOWS_VC_RUNTIME_DLLS, - WINDOWS_VC_RUNTIME_RECEIPT, -} from '../../../../tools/packaging/windows-vc-runtime-closure.mts'; import { artifactTargets, compareText, @@ -38,7 +48,6 @@ const PREFIX = 'check-wasix-napi-release-assets.mts'; const PRODUCT = 'oliphaunt-wasix-napi'; const KIND = 'wasix-napi-addon'; const PROFILE = 'wasix-napi-addon'; -const PACKAGE_LICENSE = releaseProfilePackageLicense(PROFILE).spdx; const BINARY = 'oliphaunt_wasix_napi.node'; const PRODUCT_MANIFEST = JSON.parse( readFileSync(path.join(ROOT, 'src/wasix/node-addon/package.json'), 'utf8'), @@ -214,158 +223,91 @@ export function assertWasixNapiCarrierManifest( label = 'carrier', contract = PRODUCT_MANIFEST.oliphaunt, ) { - if (manifest.name !== target.npmPackage || manifest.version !== version) { - throw new Error(`${label} must identify ${target.npmPackage}@${version}`); - } - if (manifest.license !== PACKAGE_LICENSE) { - throw new Error( - `${label} package license must be ${PACKAGE_LICENSE}, got ${JSON.stringify(manifest.license)}`, - ); - } - if ( - manifest.oliphaunt?.target !== target.target || - manifest.oliphaunt?.runtimeProduct !== PRODUCT_MANIFEST.oliphaunt.runtimeProduct || - manifest.oliphaunt?.runtimeVersion !== contract.runtimeVersion || - manifest.oliphaunt?.qualificationOnly !== contract.qualificationOnly || - manifest.oliphaunt?.addonAbiVersion !== PRODUCT_MANIFEST.oliphaunt.addonAbiVersion || - manifest.oliphaunt?.nodeApiVersion !== PRODUCT_MANIFEST.oliphaunt.nodeApiVersion || - JSON.stringify(manifest.oliphaunt?.profiles) !== JSON.stringify(['standard', 'icu']) - ) { - throw new Error(`${label} has incompatible WASIX Node-API target/runtime/ABI/profile metadata`); - } - if ( - JSON.stringify(manifest.os) !== JSON.stringify([target.npmOs]) || - JSON.stringify(manifest.cpu) !== JSON.stringify([target.npmCpu]) || - (target.npmLibc === undefined - ? Object.hasOwn(manifest, 'libc') - : JSON.stringify(manifest.libc) !== JSON.stringify([target.npmLibc])) || - manifest.optional !== true || - manifest.type !== 'commonjs' || - Object.hasOwn(manifest, 'scripts') - ) { - throw new Error(`${label} has incompatible npm platform or lifecycle metadata`); - } - const expectedFiles = [ - 'prebuilds', - 'artifact-provenance.json', - 'README.md', - 'LICENSE', - 'THIRD_PARTY_NOTICES.md', - 'THIRD_PARTY_NOTICES.oliphaunt-wasix.md', - 'THIRD_PARTY_LICENSES', - ]; - if (JSON.stringify(manifest.files) !== JSON.stringify(expectedFiles)) { - throw new Error(`${label} must declare the exact one-addon package file surface`); - } - if ( - manifest.exports?.[`./${BINARY}`] !== `./prebuilds/${BINARY}` || - JSON.stringify(Object.keys(manifest.exports ?? {})) !== - JSON.stringify([`./${BINARY}`, './artifact-provenance.json', './package.json']) - ) { - throw new Error(`${label} must expose exactly one stable addon binary subpath`); - } - return manifest; -} - -export function assertSingleWasixNapiAddonMember(entries, binaryMember, label = 'carrier') { - const nativeMembers = [...entries.keys()].filter((name) => name.endsWith('.node')); - if (JSON.stringify(nativeMembers) !== JSON.stringify([binaryMember])) { - throw new Error( - `${label} must contain exactly one native addon member ${binaryMember}; got ${nativeMembers.join(', ')}`, - ); - } -} - -export function assertWasixNapiPlatformEntries( - entries, - { target, label = 'carrier', prefix = '', binaryDirectory = '' }, -) { - inspectPlatformBinaryEntries( - [...entries].map(([name, entry]) => ({ name, ...entry })), - { target, rootLabel: label }, - ); - if (target !== 'windows-x64-msvc') return; - - const sibling = (name) => [prefix, binaryDirectory, name].filter(Boolean).join('/'); - const runtimeNames = new Set(WINDOWS_VC_RUNTIME_DLLS); - const actualRuntimeMembers = [...entries] - .filter( - ([name, entry]) => entry?.isFile && runtimeNames.has(path.posix.basename(name).toLowerCase()), - ) - .map(([name]) => name) - .sort(compareText); - const expectedRuntimeMembers = WINDOWS_VC_RUNTIME_DLLS.filter((name) => - entries.has(sibling(name)), - ) - .map((name) => sibling(name)) - .sort(compareText); - if (JSON.stringify(actualRuntimeMembers) !== JSON.stringify(expectedRuntimeMembers)) { - throw new Error( - `${label} must place its exact app-local VC runtime closure beside ${sibling(BINARY)}`, - ); - } - - const expectedReceiptMember = sibling(WINDOWS_VC_RUNTIME_RECEIPT); - const actualReceiptMembers = [...entries.keys()] - .filter((name) => path.posix.basename(name).toLowerCase() === WINDOWS_VC_RUNTIME_RECEIPT) - .sort(compareText); - const expectedReceiptMembers = expectedRuntimeMembers.length > 0 ? [expectedReceiptMember] : []; - if (JSON.stringify(actualReceiptMembers) !== JSON.stringify(expectedReceiptMembers)) { - throw new Error(`${label} must carry one VC runtime receipt beside its app-local closure`); - } - if (expectedRuntimeMembers.length === 0) return; - - const receipt = entries.get(expectedReceiptMember); - if (!receipt?.isFile || receipt.isSymbolicLink) { - throw new Error(`${label} is missing regular member ${expectedReceiptMember}`); - } - const expectedReceipt = expectedRuntimeMembers - .map((member) => `${entrySha256(entries.get(member))} ${path.posix.basename(member)}\n`) - .join(''); - if (Buffer.from(receipt.data()).toString('utf8') !== expectedReceipt) { - throw new Error(`${label} ${expectedReceiptMember} does not bind its exact VC runtime bytes`); - } + return assertCarrierManifest(manifest, target, version, label, { + ...PRODUCT_MANIFEST.oliphaunt, + ...contract, + packageLicense: releaseProfilePackageLicense(PROFILE).spdx, + }); } function assertPayload(entries, { prefix = '', label, target, version, npm = false, contract }) { assertReleaseNoticesInEntries(entries, { profile: PROFILE, prefix, label }); const member = (name) => (prefix ? `${prefix}/${name}` : name); const provenance = archiveJson(entries, member('artifact-provenance.json'), label); - if ( - provenance.schema !== 'oliphaunt-wasix-napi-provenance-v1' || - provenance.product !== PRODUCT || - provenance.target !== target.target || - !/^[0-9a-f]{40}$/u.test(provenance.sourceSha ?? '') || - !/^[0-9a-f]{40}$/u.test(provenance.artifactSourceSha ?? '') - ) { - throw new Error(`${label} has incompatible WASIX Node-API provenance`); - } - if (provenance.sourceSha !== provenance.artifactSourceSha) { - throw new Error( - `${label} provenance must bind addon source and embedded artifacts to one commit`, - ); - } - const expectedBuild = { - cargoProfile: 'release', - incremental: false, - codegenUnits: 1, - lto: 'thin', - strip: 'symbols', - features: ['release'], - targetTriple: target.triple, - }; - if (JSON.stringify(provenance.build) !== JSON.stringify(expectedBuild)) { - throw new Error( - `${label} provenance must record the exact optimized addon build: ${JSON.stringify(expectedBuild)}`, - ); - } - assertBuildInputs(provenance.buildInputs, target, label); const binaryMember = member(npm ? `prebuilds/${BINARY}` : BINARY); const entry = entries.get(binaryMember); if (!entry?.isFile || entry.isSymbolicLink || entry.size <= 0) { throw new Error(`${label} is missing non-empty regular ${binaryMember}`); } const actual = entrySha256(entry); + if ( + provenance.schema === 'oliphaunt-wasix-napi-construction-data-v2' || + provenance.schema === 'oliphaunt-wasix-napi-construction-data-v3' + ) { + const cargo = Bun.TOML.parse( + readFileSync(path.join(ROOT, 'src/wasix/node-addon/Cargo.toml'), 'utf8'), + ); + const workspace = Bun.TOML.parse(readFileSync(path.join(ROOT, 'Cargo.toml'), 'utf8')); + const sdk = resolveCargoWorkspaceInheritance(cargo, workspace.workspace).dependencies[ + 'oliphaunt-wasix' + ]; + const legacy = provenance.schema === 'oliphaunt-wasix-napi-construction-data-v2'; + const patch = legacy + ? readFileSync(path.join(ROOT, 'build_defs/wasix/held-wasix-relocatable-includes.patch')) + : undefined; + const sdkVersion = legacy + ? (typeof sdk === 'string' ? sdk : sdk.version).replace(/^=/u, '') + : Bun.TOML.parse(readFileSync(path.join(ROOT, 'src/wasix/sdks/rust/Cargo.toml'), 'utf8')) + .package.version; + assertWasixNapiConstructionData(provenance, target.target, actual, { + targetTriple: target.triple, + runtimeVersion: (contract ?? PRODUCT_MANIFEST.oliphaunt).runtimeVersion, + sdkVersion, + sqlNames: wasixNapiReleaseSqlNames( + cargo, + extensionSqlNames('oliphaunt-extension-contrib-pg18', PREFIX), + ), + ...(patch + ? { + sourcePatch: { + path: WASIX_NAPI_SOURCE_PATCH_MEMBER, + sha256: createHash('sha256').update(patch).digest('hex'), + size: patch.length, + }, + } + : {}), + }); + } else { + if ( + provenance.schema !== 'oliphaunt-wasix-napi-provenance-v1' || + provenance.product !== PRODUCT || + provenance.target !== target.target || + !/^[0-9a-f]{40}$/u.test(provenance.sourceSha ?? '') || + !/^[0-9a-f]{40}$/u.test(provenance.artifactSourceSha ?? '') + ) { + throw new Error(`${label} has incompatible WASIX Node-API provenance`); + } + if (provenance.sourceSha !== provenance.artifactSourceSha) { + throw new Error( + `${label} provenance must bind addon source and embedded artifacts to one commit`, + ); + } + const expectedBuild = { + cargoProfile: 'release', + incremental: false, + codegenUnits: 1, + lto: 'thin', + strip: 'symbols', + features: ['release'], + targetTriple: target.triple, + }; + if (JSON.stringify(provenance.build) !== JSON.stringify(expectedBuild)) { + throw new Error( + `${label} provenance must record the exact optimized addon build: ${JSON.stringify(expectedBuild)}`, + ); + } + assertBuildInputs(provenance.buildInputs, target, label); + } if ( provenance.binary?.filename !== BINARY || provenance.binary?.sha256 !== actual || diff --git a/src/wasix/node-addon/tools/native-build-data.mts b/src/wasix/node-addon/tools/native-build-data.mts index f9ee896fe..62448be24 100644 --- a/src/wasix/node-addon/tools/native-build-data.mts +++ b/src/wasix/node-addon/tools/native-build-data.mts @@ -1,5 +1,5 @@ import { createRequire } from 'node:module'; -import { workspaceRuntimeVersion } from './workspace-runtime-contract.mts'; +import { resolvedAdapterRuntimeContract } from './workspace-runtime-contract.mts'; const require = createRequire(import.meta.url); const [command, ...args] = process.argv.slice(2); @@ -7,7 +7,7 @@ switch (command) { case 'metadata': { const manifest = JSON.parse(require('node:fs').readFileSync(args[0], 'utf8')); const values = [ - workspaceRuntimeVersion(), + resolvedAdapterRuntimeContract().runtimeVersion, manifest.oliphaunt?.addonAbiVersion, manifest.oliphaunt?.nodeApiVersion, ]; diff --git a/src/wasix/node-addon/tools/package-contract.test.mts b/src/wasix/node-addon/tools/package-contract.test.mts index 43ce690b5..da50353b6 100644 --- a/src/wasix/node-addon/tools/package-contract.test.mts +++ b/src/wasix/node-addon/tools/package-contract.test.mts @@ -1,14 +1,13 @@ -import { createHash } from 'node:crypto'; - import { describe, expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { windowsPeFixture } from '../../../../tools/packaging/testdata/release-fixture-utils.mts'; import productManifest from '../package.json' with { type: 'json' }; - +import { wasixNapiReleaseSqlNames } from './carrier-contract.mts'; import { assertSingleWasixNapiAddonMember, assertWasixNapiCarrierManifest, assertWasixNapiPlatformEntries, } from './check-release-assets.mts'; -import { windowsPeFixture } from '../../../../tools/packaging/testdata/release-fixture-utils.mts'; const target = Object.freeze({ npmPackage: '@oliphaunt/wasix-napi-linux-x64-gnu', @@ -62,6 +61,28 @@ function archiveEntry(data) { } describe('WASIX Node-API carrier fail-closed package contract', () => { + test('release members follow conventional nested Cargo features and reject ambiguous or unknown members', () => { + const cargo = { + features: { + default: [], + release: ['members', 'tools'], + members: ['release', 'extension-uuid-ossp', 'extension-pg-trgm'], + tools: ['oliphaunt-wasix/tools-execution'], + 'extension-uuid-ossp': ['oliphaunt-wasix/extension-uuid-ossp'], + 'extension-pg-trgm': ['oliphaunt-wasix/extension-pg-trgm'], + }, + }; + expect(wasixNapiReleaseSqlNames(cargo, ['uuid-ossp', 'pg_trgm'])).toEqual([ + 'pg_trgm', + 'uuid-ossp', + ]); + expect(() => wasixNapiReleaseSqlNames(cargo, ['uuid-ossp', 'uuid_ossp', 'pg_trgm'])).toThrow( + 'unique canonical SQL member', + ); + expect(() => wasixNapiReleaseSqlNames({ features: { release: ['missing'] } }, [])).toThrow( + 'unknown addon Cargo feature', + ); + }); test('accepts the one-binary, two-profile carrier', () => { expect(() => assertWasixNapiCarrierManifest(manifest(), target, '1.2.3')).not.toThrow(); }); diff --git a/src/wasix/node-addon/tools/package-platform.mts b/src/wasix/node-addon/tools/package-platform.mts index 19165f3e9..7f90fac80 100755 --- a/src/wasix/node-addon/tools/package-platform.mts +++ b/src/wasix/node-addon/tools/package-platform.mts @@ -1,20 +1,35 @@ #!/usr/bin/env bun import { createHash } from 'node:crypto'; -import { cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { + cpSync, + existsSync, + lstatSync, + mkdirSync, + readFileSync, + rmSync, + writeFileSync, +} from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; -import { workspaceCarrierManifest } from './workspace-runtime-contract.mts'; - import { archiveDirectory } from '../../../../tools/packaging/archive-directory.mts'; -import { readPortableArchiveEntries } from '../../../../tools/packaging/portable-archive.mts'; -import { stageReleaseNotices } from '../../../../tools/packaging/release-notices.mts'; +import { packGeneratedNpmCarrier } from '../../../../tools/packaging/npm-package.mts'; import { inspectPlatformBinaryTree } from '../../../../tools/packaging/platform-binary-contract.mts'; +import { readPortableArchiveEntries } from '../../../../tools/packaging/portable-archive.mts'; +import { + releaseNoticeRows, + stageReleaseNotices, +} from '../../../../tools/packaging/release-notices.mts'; import { - WINDOWS_VC_RUNTIME_RECEIPT, stageWindowsVcRuntime, verifyWindowsVcRuntimeClosure, + WINDOWS_VC_RUNTIME_RECEIPT, } from '../../../../tools/packaging/windows-vc-runtime-closure.mts'; +import { + assertWasixNapiConstructionData, + type WasixNapiConstructionContract, +} from './carrier-contract.mts'; +import { workspaceCarrierManifest } from './workspace-runtime-contract.mts'; const WORKSPACE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../..'); const PRODUCT_ROOT = path.join(WORKSPACE_ROOT, 'src/wasix/node-addon'); @@ -24,7 +39,157 @@ const TARGETS = Object.freeze({ 'linux-x64-gnu': 'linux-x64-gnu', 'windows-x64-msvc': 'win32-x64-msvc', }); -const BINARY = 'oliphaunt_wasix_napi.node'; +export const WASIX_NAPI_BINARY = 'oliphaunt_wasix_napi.node'; +const BINARY = WASIX_NAPI_BINARY; + +export type WasixNapiStage = { + target: keyof typeof TARGETS; + manifest: Record; + readme: string; + binary: string; + provenance: Record; + constructionContract?: WasixNapiConstructionContract; + sourceRoot: string; + packageStage: string; + releaseStage: string; + windowsRuntimeSourceDirectory?: string; +}; + +/** Stage the canonical envelope from explicit inputs; qualification is never promoted here. */ +export async function stageWasixNapiCarrier(input: WasixNapiStage) { + if (!Object.hasOwn(TARGETS, input.target)) throw new Error('unknown WASIX Node-API target'); + const binary = lstatSync(input.binary); + if (!binary.isFile() || binary.isSymbolicLink() || binary.size <= 0) + throw new Error('WASIX Node-API binary must be a non-empty regular file'); + const buildInputs = input.provenance.buildInputs; + const constructionVersion = { + 'oliphaunt-wasix-napi-construction-data-v2': 'oliphaunt-wasix-napi-build-inputs-v2', + 'oliphaunt-wasix-napi-construction-data-v3': 'oliphaunt-wasix-napi-build-inputs-v3', + }[input.provenance.schema]; + const construction = constructionVersion !== undefined; + if (!construction && input.provenance.schema !== 'oliphaunt-wasix-napi-provenance-v1') + throw new Error('unknown WASIX Node-API provenance schema'); + if (construction) { + if (!input.constructionContract) + throw new Error('native WASIX Node-API construction requires its declared release contract'); + assertWasixNapiConstructionData( + input.provenance, + input.target, + sha256(input.binary), + input.constructionContract, + ); + } + if ( + buildInputs?.schema !== (constructionVersion ?? 'oliphaunt-wasix-napi-build-inputs-v1') || + buildInputs.target !== input.target || + typeof buildInputs.targetTriple !== 'string' || + buildInputs.targetTriple.length === 0 || + !Array.isArray(buildInputs.inputs?.extensionArtifacts) || + buildInputs.inputs.extensionArtifacts.length === 0 || + input.provenance.target !== input.target || + input.provenance.product !== 'oliphaunt-wasix-napi' || + (!construction && !/^[0-9a-f]{40}$/u.test(input.provenance.sourceSha ?? '')) || + (!construction && !/^[0-9a-f]{40}$/u.test(input.provenance.artifactSourceSha ?? '')) || + input.provenance.binary?.filename !== BINARY || + input.provenance.binary?.sha256 !== sha256(input.binary) + ) + throw new Error('WASIX Node-API provenance differs from its declared binary or inputs'); + const contains = (directory: string, file: string) => { + const relative = path.relative(path.resolve(directory), path.resolve(file)); + return ( + relative === '' || + (!relative.startsWith(`..${path.sep}`) && relative !== '..' && !path.isAbsolute(relative)) + ); + }; + if ( + contains(input.packageStage, input.releaseStage) || + contains(input.releaseStage, input.packageStage) || + [input.packageStage, input.releaseStage].some((stage) => + [input.sourceRoot, input.binary, input.readme].some((source) => contains(stage, source)), + ) + ) + throw new Error('WASIX Node-API staging directories must be distinct from source inputs'); + + const packagePrebuilds = path.join(input.packageStage, 'prebuilds'); + for (const stage of [input.packageStage, input.releaseStage]) { + rmSync(stage, { recursive: true, force: true }); + mkdirSync(stage, { recursive: true }); + stageReleaseNotices(stage, { profile: 'wasix-napi-addon', sourceRoot: input.sourceRoot }); + writeFileSync( + path.join(stage, 'artifact-provenance.json'), + `${JSON.stringify(input.provenance, null, 2)}\n`, + ); + } + writeFileSync( + path.join(input.packageStage, 'package.json'), + `${JSON.stringify(input.manifest, null, 2)}\n`, + ); + cpSync(input.readme, path.join(input.packageStage, 'README.md')); + mkdirSync(packagePrebuilds, { recursive: true }); + cpSync(input.binary, path.join(packagePrebuilds, BINARY)); + cpSync(input.binary, path.join(input.releaseStage, BINARY)); + if (input.target === 'windows-x64-msvc') { + const npm = stageWindowsVcRuntime({ + root: input.packageStage, + sourceDirectory: input.windowsRuntimeSourceDirectory, + destinations: [packagePrebuilds], + }).required; + const github = stageWindowsVcRuntime({ + root: input.releaseStage, + sourceDirectory: packagePrebuilds, + destinations: [input.releaseStage], + }).required; + if (JSON.stringify(npm) !== JSON.stringify(github)) + throw new Error('release and npm carriers derived different Windows VC runtime closures'); + } + await inspectPlatformBinaryTree(input.releaseStage, { target: input.target }); +} + +export async function finishWasixNapiCarrier(input: { + target: keyof typeof TARGETS; + packageStage: string; + releaseStage: string; + tarball: string; + releaseArchive: string; +}) { + const listing = readPortableArchiveEntries(input.tarball); + const windowsRuntimeNames = + input.target === 'windows-x64-msvc' + ? verifyWindowsVcRuntimeClosure({ + root: input.packageStage, + searchRoots: [path.join(input.packageStage, 'prebuilds')], + }).required + : []; + const requiredMembers = [ + `package/prebuilds/${BINARY}`, + 'package/artifact-provenance.json', + 'package/LICENSE', + 'package/THIRD_PARTY_NOTICES.md', + 'package/THIRD_PARTY_NOTICES.oliphaunt-wasix.md', + 'package/THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT', + 'package/THIRD_PARTY_LICENSES/ICU-LICENSE', + 'package/THIRD_PARTY_LICENSES/OpenSSL-LICENSE.txt', + ]; + if (windowsRuntimeNames.length > 0) + requiredMembers.push( + ...windowsRuntimeNames.map((name) => `package/prebuilds/${name}`), + `package/prebuilds/${WINDOWS_VC_RUNTIME_RECEIPT}`, + ); + for (const member of requiredMembers) + if (!listing.get(member)?.isFile || listing.get(member)?.isSymbolicLink) + throw new Error(`${path.basename(input.tarball)} is missing ${member}`); + await archiveDirectory(input.releaseStage, input.releaseArchive); + return { npm: input.tarball, github: input.releaseArchive }; +} + +/** Both public envelopes share the sole compiled binary and provenance subjects. */ +export async function packageWasixNapiCarrier( + input: WasixNapiStage & { tarballRoot: string; releaseArchive: string }, +) { + await stageWasixNapiCarrier(input); + const tarball = packGeneratedNpmCarrier(input.packageStage, input.tarballRoot); + return finishWasixNapiCarrier({ ...input, tarball }); +} function parseArguments(argv) { const options = {}; @@ -110,34 +275,8 @@ async function main() { ); requireFile(path.join(prebuildDirectory, BINARY)); - rmSync(packageWork, { recursive: true, force: true }); - mkdirSync(path.join(packageWork, 'prebuilds'), { recursive: true }); mkdirSync(packageOutput, { recursive: true }); - cpSync(sourcePackage, packageWork, { recursive: true }); - writeFileSync( - path.join(packageWork, 'package.json'), - `${JSON.stringify( - workspaceCarrierManifest( - readJson(path.join(sourcePackage, 'package.json')), - rootManifest.oliphaunt, - WORKSPACE_ROOT, - ), - null, - 2, - )}\n`, - ); - const packagePrebuilds = path.join(packageWork, 'prebuilds'); - mkdirSync(packagePrebuilds, { recursive: true }); - cpSync(path.join(prebuildDirectory, BINARY), path.join(packagePrebuilds, BINARY)); - stageReleaseNotices(packageWork, { profile: 'wasix-napi-addon' }); - const windowsRuntimeNames = - target === 'windows-x64-msvc' - ? stageWindowsVcRuntime({ - root: packageWork, - destinations: [packagePrebuilds], - }).required - : []; - + mkdirSync(releaseAssets, { recursive: true }); const sourceSha = options['source-sha']; if (!/^[0-9a-f]{40}$/u.test(sourceSha ?? '')) throw new Error('--source-sha must be a lowercase Git SHA'); @@ -163,34 +302,23 @@ async function main() { buildInputs, binary: { filename: BINARY, - sha256: sha256(path.join(packageWork, 'prebuilds', BINARY)), + sha256: sha256(path.join(prebuildDirectory, BINARY)), }, }; - writeFileSync( - path.join(packageWork, 'artifact-provenance.json'), - `${JSON.stringify(provenance, null, 2)}\n`, - ); - - rmSync(releaseStage, { recursive: true, force: true }); - mkdirSync(releaseStage, { recursive: true }); - mkdirSync(releaseAssets, { recursive: true }); - cpSync(path.join(prebuildDirectory, BINARY), path.join(releaseStage, BINARY)); - stageReleaseNotices(releaseStage, { profile: 'wasix-napi-addon' }); - cpSync( - path.join(packageWork, 'artifact-provenance.json'), - path.join(releaseStage, 'artifact-provenance.json'), - ); - if (target === 'windows-x64-msvc') { - const releaseRuntimeNames = stageWindowsVcRuntime({ - root: releaseStage, - sourceDirectory: packagePrebuilds, - destinations: [releaseStage], - }).required; - if (JSON.stringify(releaseRuntimeNames) !== JSON.stringify(windowsRuntimeNames)) { - throw new Error('release and npm carriers derived different Windows VC runtime closures'); - } - } - await inspectPlatformBinaryTree(releaseStage, { target }); + await stageWasixNapiCarrier({ + target, + manifest: workspaceCarrierManifest( + readJson(path.join(sourcePackage, 'package.json')), + rootManifest.oliphaunt, + WORKSPACE_ROOT, + ), + readme: path.join(sourcePackage, 'README.md'), + binary: path.join(prebuildDirectory, BINARY), + provenance, + sourceRoot: path.dirname(releaseNoticeRows({ profile: 'wasix-napi-addon' })[0].source), + packageStage: packageWork, + releaseStage, + }); console.log( [releaseStage, packageWork, packageOutput] .map((file) => path.relative(WORKSPACE_ROOT, file).split(path.sep).join('/')) @@ -201,44 +329,23 @@ async function main() { const tarball = options.tarball; requireFile(tarball); - const listing = readPortableArchiveEntries(tarball); - const windowsRuntimeNames = - target === 'windows-x64-msvc' - ? verifyWindowsVcRuntimeClosure({ - root: packageWork, - searchRoots: [path.join(packageWork, 'prebuilds')], - }).required - : []; - const requiredMembers = [ - `package/prebuilds/${BINARY}`, - 'package/artifact-provenance.json', - 'package/LICENSE', - 'package/THIRD_PARTY_NOTICES.md', - 'package/THIRD_PARTY_NOTICES.oliphaunt-wasix.md', - 'package/THIRD_PARTY_LICENSES/PostgreSQL-COPYRIGHT', - 'package/THIRD_PARTY_LICENSES/ICU-LICENSE', - 'package/THIRD_PARTY_LICENSES/OpenSSL-LICENSE.txt', - ]; - if (windowsRuntimeNames.length > 0) { - requiredMembers.push( - ...windowsRuntimeNames.map((name) => `package/prebuilds/${name}`), - `package/prebuilds/${WINDOWS_VC_RUNTIME_RECEIPT}`, - ); - } - for (const member of requiredMembers) { - if (!listing.get(member)?.isFile || listing.get(member)?.isSymbolicLink) { - throw new Error(`${path.basename(tarball)} is missing ${member}`); - } - } - await archiveDirectory(releaseStage, releaseArchive); + await finishWasixNapiCarrier({ + target, + packageStage: packageWork, + releaseStage, + tarball, + releaseArchive, + }); process.stdout.write(`${tarball}\n${releaseArchive}\n`); } -try { - await main(); -} catch (error) { - console.error( - `package-wasix-napi-platform: ${error instanceof Error ? error.message : String(error)}`, - ); - process.exitCode = 1; +if (import.meta.main) { + try { + await main(); + } catch (error) { + console.error( + `package-wasix-napi-platform: ${error instanceof Error ? error.message : String(error)}`, + ); + process.exitCode = 1; + } } diff --git a/src/wasix/node-addon/tools/package-platform.test.mts b/src/wasix/node-addon/tools/package-platform.test.mts new file mode 100644 index 000000000..c7da07aa9 --- /dev/null +++ b/src/wasix/node-addon/tools/package-platform.test.mts @@ -0,0 +1,526 @@ +import { test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + copyFileSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { readPortableArchiveEntries } from '../../../../tools/packaging/portable-archive.mts'; +import { + elfFixture, + machoFixture, + windowsPeFixture, +} from '../../../../tools/packaging/testdata/release-fixture-utils.mts'; +import { + AOT_PACKAGES, + EXTENSION_AOT_PACKAGE_SUFFIXES, +} from '../../runtime/tools/wasix-cargo-artifact-contract.mts'; +import { + assertWasixNapiConstructionData, + WASIX_NAPI_SOURCE_PATCH_MEMBER, +} from './carrier-contract.mts'; +import { + packageWasixNapiCarrier, + stageWasixNapiCarrier, + WASIX_NAPI_BINARY, + type WasixNapiStage, +} from './package-platform.mts'; + +const ROOT = path.resolve(import.meta.dir, '../../../..'); +const notices = [ + 'LICENSE', + 'THIRD_PARTY_NOTICES.md', + 'src/wasix/sdks/rust/THIRD_PARTY_NOTICES.md', + 'src/third-party/postgres/COPYRIGHT', + 'src/third-party/postgres/source.toml', + 'src/third-party/icu/LICENSE', + 'src/third-party/icu/source.toml', + 'src/third-party/openssl/LICENSE.txt', + 'src/third-party/openssl/source.toml', +]; +const targets = [ + ['linux-x64-gnu', 'linux-x64-gnu', 'x86_64-unknown-linux-gnu', () => elfFixture()], + [ + 'linux-arm64-gnu', + 'linux-arm64-gnu', + 'aarch64-unknown-linux-gnu', + () => elfFixture({ machine: 183 }), + ], + ['macos-arm64', 'darwin-arm64', 'aarch64-apple-darwin', () => machoFixture()], + [ + 'windows-x64-msvc', + 'win32-x64-msvc', + 'x86_64-pc-windows-msvc', + () => windowsPeFixture({ imports: ['VCRUNTIME140.dll'] }), + ], +] as const; + +function fixture(root: string, row: (typeof targets)[number]): WasixNapiStage { + const [target, directory, targetTriple, bytes] = row; + const sourceRoot = path.join(root, 'source'); + for (const file of notices) { + const output = path.join(sourceRoot, file); + mkdirSync(path.dirname(output), { recursive: true }); + copyFileSync(path.join(ROOT, file), output); + } + const binary = path.join(root, WASIX_NAPI_BINARY); + writeFileSync(binary, bytes()); + const manifest = JSON.parse( + readFileSync( + path.join(ROOT, 'src/wasix/node-addon/packages', directory, 'package.json'), + 'utf8', + ), + ); + manifest.oliphaunt.qualificationOnly = true; + let windowsRuntimeSourceDirectory: string | undefined; + if (target === 'windows-x64-msvc') { + windowsRuntimeSourceDirectory = path.join(root, 'redist'); + mkdirSync(windowsRuntimeSourceDirectory); + const runtime = windowsPeFixture(); + writeFileSync(path.join(windowsRuntimeSourceDirectory, 'vcruntime140.dll'), runtime); + writeFileSync( + path.join(windowsRuntimeSourceDirectory, 'windows-vc-runtime.sha256'), + `${createHash('sha256').update(runtime).digest('hex')} vcruntime140.dll\n`, + ); + } + return { + target, + manifest, + binary, + sourceRoot, + readme: path.join(ROOT, 'src/wasix/node-addon/packages', directory, 'README.md'), + packageStage: path.join(root, 'npm'), + releaseStage: path.join(root, 'github'), + windowsRuntimeSourceDirectory, + provenance: { + schema: 'oliphaunt-wasix-napi-provenance-v1', + product: 'oliphaunt-wasix-napi', + target, + sourceSha: 'a'.repeat(40), + artifactSourceSha: 'a'.repeat(40), + build: { + cargoProfile: 'release', + incremental: false, + codegenUnits: 1, + lto: 'thin', + strip: 'symbols', + features: ['release'], + targetTriple, + }, + buildInputs: { + schema: 'oliphaunt-wasix-napi-build-inputs-v1', + target, + targetTriple, + inputs: { extensionArtifacts: [{ fixture: true }] }, + }, + binary: { + filename: WASIX_NAPI_BINARY, + sha256: createHash('sha256').update(readFileSync(binary)).digest('hex'), + }, + }, + }; +} + +function constructionFixture(input: WasixNapiStage, version = 3): WasixNapiStage { + const targetTriple = input.provenance.build.targetTriple; + const runtimeVersion = input.manifest.oliphaunt.runtimeVersion; + const sdkVersion = '9.8.7'; + const sqlNames = ['cube', 'pg_trgm']; + const product = 'oliphaunt-extension-contrib-pg18'; + const identity = (file: string) => ({ + path: file, + sha256: createHash('sha256').update(file).digest('hex'), + size: Buffer.byteLength(file), + }); + const cargoLock = identity('Cargo.lock'); + const sourcePatch = { ...identity(WASIX_NAPI_SOURCE_PATCH_MEMBER) }; + const files = [ + identity('portable/bin/initdb.wasix.wasm'), + identity(`extensions/${product}/extension-artifacts.json`), + identity('layout.json'), + ]; + const file = (member: string) => { + const row = identity(member); + files.push(row); + return row; + }; + const dependencies: any[] = []; + const registry = (name: string, packageVersion: string, members: string[], patched = false) => { + const rows = members.map((member) => identity(`registry/${name}-${packageVersion}/${member}`)); + dependencies.push({ + name, + version: packageVersion, + source: 'registry+https://github.com/rust-lang/crates.io-index', + checksum: identity(name).sha256, + files: rows, + ...(patched ? { patches: [sourcePatch] } : {}), + }); + return (member: string) => rows.find((row) => row.path.endsWith(`/${member}`))!; + }; + const sdk = version === 2 ? registry('oliphaunt-wasix', sdkVersion, ['Cargo.toml']) : undefined; + const portable = + version === 2 + ? registry( + 'liboliphaunt-wasix-portable', + runtimeVersion, + [ + 'Cargo.toml', + 'build-support.rs', + 'payload/manifest.json', + 'payload/oliphaunt.wasix.tar.zst', + ], + true, + ) + : undefined; + const core = + version === 2 + ? registry( + AOT_PACKAGES[input.target], + runtimeVersion, + ['Cargo.toml', 'build-support.rs', 'artifacts/manifest.json'], + true, + ) + : undefined; + const contrib = + version === 2 + ? registry(`${product}-wasix`, runtimeVersion, [ + 'Cargo.toml', + ...sqlNames.map((sqlName) => `payload/files/extensions/${sqlName}/extension.tar.zst`), + ]) + : undefined; + const contribAot = + version === 2 + ? registry(`${product}-aot-${EXTENSION_AOT_PACKAGE_SUFFIXES[targetTriple]}`, runtimeVersion, [ + 'Cargo.toml', + ...sqlNames.map((sqlName) => `manifests/${sqlName}.json`), + ]) + : undefined; + const inputs = { + portableManifest: portable ? portable('payload/manifest.json') : file('portable/manifest.json'), + runtimeArchive: portable + ? portable('payload/oliphaunt.wasix.tar.zst') + : file('portable/oliphaunt.wasix.tar.zst'), + runtimeAotManifest: { + targetTriple, + ...(core ? core('artifacts/manifest.json') : file(`aot/${targetTriple}/manifest.json`)), + }, + extensionArtifacts: [ + { + product, + portableArchives: sqlNames.map((sqlName) => ({ + sqlName, + ...(contrib + ? contrib(`payload/files/extensions/${sqlName}/extension.tar.zst`) + : file( + `extensions/${product}/member-assets/${sqlName}/${product}-${runtimeVersion}-wasix-portable.tar.zst`, + )), + })), + aotManifests: sqlNames.map((sqlName) => ({ + sqlName, + targetTriple, + ...(contribAot + ? contribAot(`manifests/${sqlName}.json`) + : file(`extensions/${product}/wasix-aot/${input.target}/${sqlName}/manifest.json`)), + })), + }, + ], + }; + const { + sourceSha: _sourceSha, + artifactSourceSha: _artifactSourceSha, + ...provenance + } = input.provenance; + return { + ...input, + constructionContract: { + targetTriple, + runtimeVersion, + sdkVersion, + sqlNames, + ...(sdk ? { sourcePatch } : {}), + }, + provenance: { + ...provenance, + schema: `oliphaunt-wasix-napi-construction-data-v${version}`, + buildInputs: { + schema: `oliphaunt-wasix-napi-build-inputs-v${version}`, + target: input.target, + targetTriple, + ...(sdk + ? { cargoLock, dependencies } + : { + runtimeVersion, + files: [...files].sort((left, right) => + left.path < right.path ? -1 : left.path > right.path ? 1 : 0, + ), + sdk: { name: 'oliphaunt-wasix', version: sdkVersion }, + }), + inputs, + }, + }, + }; +} + +test('source construction inventories stage unchanged on all four hosts and retain v2 registry parsing', async () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-napi-source-envelopes-')); + try { + for (const row of targets) { + const directory = path.join(root, row[0]); + mkdirSync(directory); + const input = constructionFixture(fixture(directory, row)); + await stageWasixNapiCarrier(input); + assert.deepEqual( + JSON.parse(readFileSync(path.join(input.packageStage, 'artifact-provenance.json'), 'utf8')), + input.provenance, + ); + assert(!Object.hasOwn(input.provenance.buildInputs, 'dependencies')); + assert(!Object.hasOwn(input.provenance.buildInputs, 'cargoLock')); + assert(!input.provenance.buildInputs.files.some((file: any) => file.path === 'Cargo.lock')); + assert.deepEqual(input.provenance.buildInputs.sdk, { + name: 'oliphaunt-wasix', + version: '9.8.7', + }); + assert( + !input.provenance.buildInputs.files.some( + (file: any) => file.path === 'src/wasix/sdks/rust/Cargo.toml', + ), + ); + assert(!Object.hasOwn(input.constructionContract!, 'sourcePatch')); + const legacy = constructionFixture(input, 2); + await stageWasixNapiCarrier(legacy); + assert.deepEqual( + JSON.parse( + readFileSync(path.join(legacy.releaseStage, 'artifact-provenance.json'), 'utf8'), + ), + legacy.provenance, + ); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('source construction rejects unbound files, wrong versions and incomplete release inputs', () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-napi-source-contract-')); + try { + const input = constructionFixture(fixture(root, targets[0])); + const verify = (provenance: any, contract = input.constructionContract!) => + assertWasixNapiConstructionData( + provenance, + input.target, + input.provenance.binary.sha256, + contract, + ); + verify(input.provenance); + for (const mutate of [ + (value: any) => { + value.schema = 'oliphaunt-wasix-napi-construction-data-v2'; + }, + (value: any) => { + value.buildInputs.schema = 'oliphaunt-wasix-napi-build-inputs-v2'; + }, + (value: any) => { + value.buildInputs.dependencies = []; + }, + (value: any) => { + value.sourcePatch = {}; + }, + (value: any) => { + value.buildInputs.sourcePatch = {}; + }, + (value: any) => { + value.scope = 'release'; + }, + (value: any) => { + value.sourceSha = 'a'.repeat(40); + }, + (value: any) => { + value.artifactSourceSha = 'a'.repeat(40); + }, + (value: any) => { + value.binary.sha256 = '0'.repeat(64); + }, + (value: any) => { + value.buildInputs.runtimeVersion = '0.0.1'; + }, + (value: any) => { + value.buildInputs.sdk.name = 'foreign-sdk'; + }, + (value: any) => { + value.buildInputs.sdk.version = '0.0.1'; + }, + (value: any) => { + value.buildInputs.sdk.cargoManifest = { + path: 'src/wasix/sdks/rust/Cargo.toml', + sha256: '0'.repeat(64), + size: 1, + }; + }, + (value: any) => { + value.buildInputs.cargoLock = { + path: 'Cargo.lock', + sha256: '0'.repeat(64), + size: 1, + }; + }, + (value: any) => { + value.buildInputs.files = []; + }, + (value: any) => { + value.buildInputs.files.push(value.buildInputs.files[0]); + }, + (value: any) => { + value.buildInputs.files.reverse(); + }, + (value: any) => { + value.buildInputs.files[2].path = '../escape'; + }, + (value: any) => { + value.buildInputs.files[2].path = 'C:/escape'; + }, + (value: any) => { + value.buildInputs.files[2].sha256 = 'invalid'; + }, + (value: any) => { + value.buildInputs.files[2].size = -1; + }, + (value: any) => { + value.buildInputs.files.unshift({ path: 'Cargo.lock', sha256: '0'.repeat(64), size: 1 }); + }, + (value: any) => { + value.buildInputs.files.push({ + path: 'src/wasix/sdks/rust/Cargo.toml', + sha256: '0'.repeat(64), + size: 1, + }); + }, + (value: any) => { + value.buildInputs.files = value.buildInputs.files.filter( + (file: any) => file.path !== 'layout.json', + ); + }, + (value: any) => { + value.buildInputs.files = value.buildInputs.files.filter( + (file: any) => file.path !== 'portable/bin/initdb.wasix.wasm', + ); + }, + (value: any) => { + value.buildInputs.files = value.buildInputs.files.filter( + (file: any) => + file.path !== 'extensions/oliphaunt-extension-contrib-pg18/extension-artifacts.json', + ); + }, + (value: any) => { + value.buildInputs.inputs.runtimeArchive.sha256 = '0'.repeat(64); + }, + (value: any) => { + value.buildInputs.inputs.runtimeAotManifest.targetTriple = 'aarch64-apple-darwin'; + }, + (value: any) => { + value.buildInputs.inputs.extensionArtifacts[0].portableArchives.pop(); + }, + (value: any) => { + value.buildInputs.inputs.extensionArtifacts[0].portableArchives.push( + value.buildInputs.inputs.extensionArtifacts[0].portableArchives[0], + ); + }, + (value: any) => { + value.buildInputs.inputs.extensionArtifacts[0].aotManifests.pop(); + }, + (value: any) => { + value.buildInputs.inputs.extensionArtifacts[0].aotManifests[0].targetTriple = + 'aarch64-apple-darwin'; + }, + ]) { + const changed = JSON.parse(JSON.stringify(input.provenance)); + mutate(changed); + assert.throws(() => verify(changed)); + } + const legacy = constructionFixture(input, 2); + verify(legacy.provenance, legacy.constructionContract!); + const locklessLegacy = JSON.parse(JSON.stringify(legacy.provenance)); + delete locklessLegacy.buildInputs.cargoLock; + assert.throws(() => verify(locklessLegacy, legacy.constructionContract!)); + legacy.provenance.buildInputs.schema = 'oliphaunt-wasix-napi-build-inputs-v3'; + assert.throws(() => verify(legacy.provenance, legacy.constructionContract!)); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('canonical four-platform envelopes share exact subjects, preserve qualification, and repeat deterministically', async () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-napi-envelopes-')); + try { + for (const row of targets) { + const directory = path.join(root, row[0]); + mkdirSync(directory); + const input = fixture(directory, row); + const options = { + ...input, + tarballRoot: path.join(directory, 'packages'), + releaseArchive: path.join( + directory, + `addon.${row[0] === 'windows-x64-msvc' ? 'zip' : 'tar.gz'}`, + ), + }; + const outputs = await packageWasixNapiCarrier(options); + const npm = readPortableArchiveEntries(outputs.npm); + const github = readPortableArchiveEntries(outputs.github); + const bytes = (entries: typeof npm, member: string) => + Buffer.from(entries.get(member)!.data()); + assert.deepEqual( + bytes(npm, `package/prebuilds/${WASIX_NAPI_BINARY}`), + bytes(github, WASIX_NAPI_BINARY), + ); + assert.deepEqual( + bytes(npm, 'package/artifact-provenance.json'), + bytes(github, 'artifact-provenance.json'), + ); + assert.equal( + JSON.parse(bytes(npm, 'package/package.json').toString()).oliphaunt.qualificationOnly, + true, + ); + assert(![...npm.keys()].some((member) => member.includes('Cargo.lock'))); + const before = [readFileSync(outputs.npm), readFileSync(outputs.github)]; + await packageWasixNapiCarrier(options); + assert.deepEqual([readFileSync(outputs.npm), readFileSync(outputs.github)], before); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('staging rejects changed binary subjects and unsafe output overlap before deleting inputs', async () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-napi-inputs-')); + try { + const input = fixture(root, targets[0]); + await assert.rejects( + stageWasixNapiCarrier({ + ...input, + provenance: { + ...input.provenance, + binary: { filename: WASIX_NAPI_BINARY, sha256: '0'.repeat(64) }, + }, + }), + /provenance differs/, + ); + await assert.rejects( + stageWasixNapiCarrier({ ...input, packageStage: root }), + /distinct from source/, + ); + assert(readFileSync(input.binary).length > 0); + const linked = path.join(root, 'linked.node'); + symlinkSync(input.binary, linked); + await assert.rejects(stageWasixNapiCarrier({ ...input, binary: linked }), /regular file/); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); +import './workspace-runtime-contract.test.mts'; diff --git a/src/wasix/node-addon/tools/package-platform.test.sh b/src/wasix/node-addon/tools/package-platform.test.sh index c7ed10e6c..ee1541c40 100755 --- a/src/wasix/node-addon/tools/package-platform.test.sh +++ b/src/wasix/node-addon/tools/package-platform.test.sh @@ -8,13 +8,19 @@ trap 'rm -rf "$fixture"' EXIT product="$fixture/src/wasix/node-addon" mkdir -p "$product/tools" "$fixture/tools" "$fixture/prebuild" mkdir -p "$fixture/src/wasix/runtime" +mkdir -p "$fixture/src/wasix/runtime/crates/assets" mkdir -p "$fixture/src/wasix/sdks/rust" +cp "$root/Cargo.toml" "$root/Cargo.lock" "$fixture/" cp "$root/src/wasix/runtime/VERSION" "$fixture/src/wasix/runtime/" +cp "$root/src/wasix/runtime/crates/assets/Cargo.toml" "$fixture/src/wasix/runtime/crates/assets/" +ln -s "$root/src/wasix/runtime/tools" "$fixture/src/wasix/runtime/tools" cp "$root/src/wasix/sdks/rust/Cargo.toml" "$fixture/src/wasix/sdks/rust/" cp "$root/src/wasix/node-addon/tools/workspace-runtime-contract.mts" "$product/tools/" +cp "$root/src/wasix/node-addon/tools/carrier-contract.mts" "$product/tools/" cp "$root/src/wasix/node-addon/tools/package-platform."{sh,mts} "$product/tools/" cp "$root/src/wasix/node-addon/tools/smoke-packaged-addon."{sh,mts} "$product/tools/" cp "$root/src/wasix/node-addon/package.json" "$product/" +cp "$root/src/wasix/node-addon/Cargo.toml" "$product/" ln -s "$root/src/wasix/node-addon/packages" "$product/packages" ln -s "$root/tools/packaging" "$fixture/tools/packaging" ln -s "$root/tools/dev" "$fixture/tools/dev" diff --git a/src/wasix/node-addon/tools/workspace-runtime-contract.mts b/src/wasix/node-addon/tools/workspace-runtime-contract.mts index f3af2e276..c76b0511d 100644 --- a/src/wasix/node-addon/tools/workspace-runtime-contract.mts +++ b/src/wasix/node-addon/tools/workspace-runtime-contract.mts @@ -1,7 +1,7 @@ import { readFileSync } from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; -import { readCargoPackageNameVersion } from '../../../../tools/packaging/cargo-source-package.mts'; +import { cargoSatisfies } from '../../../../tools/packaging/cargo-manifest.mts'; const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../..'); @@ -13,23 +13,60 @@ export function workspaceRuntimeVersion(root = ROOT) { return version; } -// A source checkout compiles its local runtime. Preserve committed release -// pins, and identify a carrier built against different workspace dependencies -// so publication cannot mistake it for the immutable released package. -export function workspaceCarrierManifest(manifest, declaredContract, root = ROOT) { - const runtimeVersion = workspaceRuntimeVersion(root); - const rustBindingVersion = readCargoPackageNameVersion( - path.join(root, 'src/wasix/sdks/rust/Cargo.toml'), - ).version; +export function resolvedAdapterRuntimeContract(root = ROOT) { + const manifest = (relative) => + Bun.TOML.parse(readFileSync(path.join(root, relative, 'Cargo.toml'), 'utf8')); + const lock = Bun.TOML.parse(readFileSync(path.join(root, 'Cargo.lock'), 'utf8')); + const workspace = manifest('').workspace; + const version = (owner, name, destination) => { + let dependency = manifest(owner).dependencies?.[name]; + let base = path.join(root, owner); + if (dependency?.workspace === true) { + dependency = workspace.dependencies?.[name]; + base = root; + } + const declared = manifest(destination).package; + const rows = (lock.package ?? []).filter((pkg) => pkg.name === name && !pkg.source); + if ( + rows.length !== 1 || + rows[0].checksum !== undefined || + declared.name !== name || + rows[0].version !== declared.version || + !/^(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)\.(?:0|[1-9][0-9]*)$/u.test(declared.version ?? '') || + typeof dependency?.path !== 'string' || + path.resolve(base, dependency.path) !== path.resolve(root, destination) || + typeof dependency.version !== 'string' || + !cargoSatisfies(declared.version, dependency.version) + ) { + throw new Error( + `WASIX adapter must resolve local ${name} with its declared path and version`, + ); + } + return rows[0].version; + }; + const addon = 'src/wasix/node-addon'; + const sdk = 'src/wasix/sdks/rust'; + const portable = 'src/wasix/runtime/crates/assets'; + const rustBindingVersion = version(addon, 'oliphaunt-wasix', sdk); + const runtimeVersion = version(addon, 'liboliphaunt-wasix-portable', portable); + version(sdk, 'liboliphaunt-wasix-portable', portable); + return { + runtimeVersion, + rustBindingVersion, + }; +} + +// Current-folder inventory cannot attest to registry payload bytes, even when +// its version matches. Publication requires the native File-bound carrier. +export function workspaceCarrierManifest(manifest, _declaredContract, root = ROOT) { + const resolved = resolvedAdapterRuntimeContract(root); return { ...manifest, oliphaunt: { ...manifest.oliphaunt, - runtimeVersion, - ...(runtimeVersion !== declaredContract.runtimeVersion || - rustBindingVersion !== declaredContract.rustBindingVersion - ? { qualificationOnly: true } - : {}), + runtimeVersion: resolved.runtimeVersion, + rustBindingVersion: resolved.rustBindingVersion, + qualificationOnly: true, }, }; } diff --git a/src/wasix/node-addon/tools/workspace-runtime-contract.test.mts b/src/wasix/node-addon/tools/workspace-runtime-contract.test.mts new file mode 100644 index 000000000..2378bad7f --- /dev/null +++ b/src/wasix/node-addon/tools/workspace-runtime-contract.test.mts @@ -0,0 +1,101 @@ +import { afterEach, expect, test } from 'bun:test'; +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { renderCargoToml } from '../../../../tools/packaging/cargo-manifest.mts'; +import { + resolvedAdapterRuntimeContract, + workspaceCarrierManifest, +} from './workspace-runtime-contract.mts'; + +const temporary: string[] = []; +afterEach(() => { + for (const directory of temporary.splice(0)) rmSync(directory, { recursive: true, force: true }); +}); + +function fixture() { + const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-adapter-contract-')); + temporary.push(root); + const files: Record = { + 'Cargo.toml': { + workspace: { + dependencies: { + 'oliphaunt-wasix': { version: '1.2.3', path: 'src/wasix/sdks/rust' }, + }, + }, + }, + 'Cargo.lock': { + version: 4, + package: [ + { name: 'oliphaunt-wasix', version: '1.2.3' }, + { name: 'liboliphaunt-wasix-portable', version: '2.3.4' }, + ], + }, + 'src/wasix/node-addon/Cargo.toml': { + dependencies: { + 'oliphaunt-wasix': { workspace: true }, + 'liboliphaunt-wasix-portable': { version: '=2.3.4', path: '../runtime/crates/assets' }, + }, + }, + 'src/wasix/sdks/rust/Cargo.toml': { + package: { name: 'oliphaunt-wasix', version: '1.2.3' }, + dependencies: { + 'liboliphaunt-wasix-portable': { version: '*', path: '../../runtime/crates/assets' }, + }, + }, + 'src/wasix/runtime/crates/assets/Cargo.toml': { + package: { name: 'liboliphaunt-wasix-portable', version: '2.3.4' }, + }, + }; + const write = () => { + for (const [relative, manifest] of Object.entries(files)) { + const destination = path.join(root, relative); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, renderCargoToml(manifest)); + } + }; + write(); + return { root, files, write }; +} + +test('adapter runtime contract uses root lock and local SDK and portable declarations', () => { + const { root } = fixture(); + expect(resolvedAdapterRuntimeContract(root)).toEqual({ + runtimeVersion: '2.3.4', + rustBindingVersion: '1.2.3', + }); + expect(workspaceCarrierManifest({}, {}, root).oliphaunt).toEqual({ + runtimeVersion: '2.3.4', + rustBindingVersion: '1.2.3', + qualificationOnly: true, + }); +}); + +test('adapter runtime contract rejects registry, path, and version substitutions', () => { + const mutations: ((files: Record) => void)[] = [ + (files) => { + files['Cargo.lock'].package[0].source = + 'registry+https://github.com/rust-lang/crates.io-index'; + }, + (files) => { + files['Cargo.lock'].package[1].version = '2.3.3'; + }, + (files) => { + files['Cargo.toml'].workspace.dependencies['oliphaunt-wasix'].path = 'other-sdk'; + }, + (files) => { + files['src/wasix/node-addon/Cargo.toml'].dependencies['liboliphaunt-wasix-portable'].version = + '=2.3.3'; + }, + (files) => { + files['src/wasix/sdks/rust/Cargo.toml'].dependencies['liboliphaunt-wasix-portable'].path = + 'other-runtime'; + }, + ]; + for (const mutate of mutations) { + const { root, files, write } = fixture(); + mutate(files); + write(); + expect(() => resolvedAdapterRuntimeContract(root)).toThrow(/declared path and version/); + } +}); diff --git a/src/wasix/pgwire-server/BUILD.bazel b/src/wasix/pgwire-server/BUILD.bazel new file mode 100644 index 000000000..e83e9508f --- /dev/null +++ b/src/wasix/pgwire-server/BUILD.bazel @@ -0,0 +1,113 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files") +load("//build_defs/languages:rust.bzl", "cargo_binary", "cargo_integration_test", "cargo_library", "cargo_library_test", "cargo_package_env") +load("@rules_rust//rust:defs.bzl", "rust_clippy_test", "rust_library") +load("//build_defs/languages:source.bzl", "cargo_source_contract_test", "cargo_source_package") +load("@native_cargo_metadata//:cargo.bzl", "CARGO") +load("@cargo_crates//:defs.bzl", "all_crate_deps", "crate_deps") +load("@oliphaunt_metadata//:metadata.bzl", "CONTRIB_MEMBERS", "PRODUCTS") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") +load("//build_defs/release:supplier.bzl", "shipping_suppliers") +load("@wasix_tool_metadata//:targets.bzl", "WASIX_AOT_TARGETS") + +package(default_visibility = ["//visibility:public"]) +exports_files(["Cargo.toml"]) + +rust_library( + name = "shipping_supplier_fixture", + testonly = True, + srcs = ["tools/testdata/shipping_supplier_fixture.rs"], + edition = "2024", + tags = ["manual"], +) + +PATH_DEPS = {"oliphaunt-wasix": "//src/wasix/sdks/rust:lib"} +_NAPI_PATH_DEPS = {"oliphaunt-wasix": "//src/wasix/sdks/rust:napi_lib"} +_NAPI_RELEASE_PATH_DEPS = {"oliphaunt-wasix": "//src/wasix/sdks/rust:napi_release_lib"} +_CONTRIB_PATH_DEPS = {"oliphaunt-wasix": "//src/wasix/sdks/rust:extension_carrier_lib"} + +cargo_package_env() +cargo_library(path_dependencies = PATH_DEPS, cargo_facts = CARGO, crate_dependencies = crate_deps) +# Cargo unifies the SDK's dependency feature from the N-API root across both +# direct and pgwire paths. Keep that one configured SDK instance in this root. +cargo_library(name = "napi_lib", path_dependencies = _NAPI_PATH_DEPS, cargo_facts = CARGO, crate_dependencies = crate_deps) +cargo_library(name = "napi_release_lib", features = ["extensions"], path_dependencies = _NAPI_RELEASE_PATH_DEPS, cargo_facts = CARGO, crate_dependencies = crate_deps) +shipping_suppliers(name = "napi_release_compiled_suppliers", inputs = []) +filegroup(name = "napi_release_compiled_files", srcs = ["//src/wasix/node-addon:release_addon"], output_group = "server_compiled") +shipping_package( + name = "napi_release_compiled_shipping", + owner = "@oliphaunt_metadata//:product_oliphaunt-pgwire-server", + artifacts = [":napi_release_compiled_files"], ecosystem = "internal", package_name = "oliphaunt-pgwire-server", + configuration = select({"@rules_rust//rust/platform:" + triple: target for target, triple in WASIX_AOT_TARGETS.items()}), + role = "compiled-source", suppliers = ":napi_release_compiled_suppliers", +) +shipping_export(name = "napi_release_compiled_shipping_export", packages = [":napi_release_compiled_shipping"], qualification = ["//src/wasix/node-addon:release_installed_test"], testonly = True) +_CONTRIB_FEATURES = ["extension-" + member["sql-name"].replace("_", "-") for member in CONTRIB_MEMBERS] +cargo_library(name = "extension_carrier_lib", features = _CONTRIB_FEATURES, path_dependencies = _CONTRIB_PATH_DEPS, cargo_facts = CARGO, crate_dependencies = crate_deps) +cargo_integration_test( + name = "contrib_carrier_server_test", + source = "tests/extensions.rs", + crate = ":extension_carrier_lib", + features = _CONTRIB_FEATURES, + cargo_facts = CARGO, + path_dependencies = _CONTRIB_PATH_DEPS, + crate_dependencies = crate_deps, + rustc_env = {"OLIPHAUNT_DECLARED_CONTRIB_SQL_NAMES": json.encode([member["sql-name"] for member in CONTRIB_MEMBERS]), "OLIPHAUNT_DECLARED_RUNTIME_VERSION": PRODUCTS["liboliphaunt-wasix"]["version"]}, + data = ["//src/test-fixtures:rust_fixtures", "//src/extensions/catalog:extensions.source.json"], + tags = ["manual"], +) +cargo_integration_test( + name = "held_contrib_server_test", + source = "tests/extensions.rs", + crate = ":napi_release_lib", + features = _CONTRIB_FEATURES, + path_dependencies = _NAPI_RELEASE_PATH_DEPS, + cargo_facts = CARGO, + crate_dependencies = crate_deps, + args = ["--ignored", "--exact", "public_extensions_pass_server_smoke", "--nocapture", "--test-threads=1"], + rustc_env = {"OLIPHAUNT_DECLARED_CONTRIB_SQL_NAMES": json.encode([member["sql-name"] for member in CONTRIB_MEMBERS])}, + data = ["//src/test-fixtures:rust_fixtures", "//src/extensions/catalog:extensions.source.json"], + size = "large", + timeout = "long", + tags = ["manual", "installed-consumer"], +) +cargo_library_test(data = ["//src/test-fixtures:rust_fixtures"], path_dependencies = PATH_DEPS, cargo_facts = CARGO, all_dependencies = all_crate_deps) +cargo_binary(name = "server", source = "src/main.rs", path_dependencies = PATH_DEPS, library = ":lib", cargo_facts = CARGO, crate_dependencies = crate_deps) +cargo_library_test(name = "binary_test", crate = ":server", path_dependencies = PATH_DEPS, cargo_facts = CARGO, all_dependencies = all_crate_deps, tags = ["manual"]) +_INTEGRATION_ROOTS = glob(["tests/*.rs"]) +[ + cargo_integration_test( + name = source.removeprefix("tests/").removesuffix(".rs") + "_test", + source = source, + srcs = glob(["tests/support/**/*.rs"]), + args = ["--include-ignored", "--test-threads=1"], + size = "large", + timeout = "long", + rustc_env = {"CARGO_BIN_EXE_oliphaunt-pgwire-server": "$(rootpath :server)"}, + data = [":server", "//src/test-fixtures:rust_fixtures"], + cargo_facts = CARGO, + path_dependencies = PATH_DEPS, + crate_dependencies = crate_deps, + tags = ["manual"], + ) + for source in _INTEGRATION_ROOTS +] +rust_clippy_test( + name = "clippy_test", + targets = [":lib", ":unit_test", ":server", ":binary_test"] + [":" + source.removeprefix("tests/").removesuffix(".rs") + "_test" for source in _INTEGRATION_ROOTS], + transitive = False, + size = "small", +) +cargo_source_package( + product = "oliphaunt-pgwire-server", + cargo_facts = CARGO, + qualification = [":source_package_test", "//build_defs/languages/installed:pgwire_source_compile_test", ":unit_test", ":binary_test", ":held_contrib_server_test", ":clippy_test"] + + [":" + source.removeprefix("tests/").removesuffix(".rs") + "_test" for source in _INTEGRATION_ROOTS if source != "tests/extensions.rs"], +) +cargo_source_contract_test( + name = "source_package_test", + packages = [":crate"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + size = "small", +) + +rust_quality_files() diff --git a/src/wasix/pgwire-server/Cargo.toml b/src/wasix/pgwire-server/Cargo.toml index b2ea8b4b6..a465bf935 100644 --- a/src/wasix/pgwire-server/Cargo.toml +++ b/src/wasix/pgwire-server/Cargo.toml @@ -1,14 +1,14 @@ [package] name = "oliphaunt-pgwire-server" version = "0.2.1" -edition = "2024" -rust-version = "1.93" -license = "MIT" +edition.workspace = true +rust-version.workspace = true +license.workspace = true repository.workspace = true homepage.workspace = true description = "PostgreSQL socket server and CLI for embedded Oliphaunt databases." readme = "README.md" -exclude = ["moon.yml", "release.toml", "tools"] +exclude = ["BUILD.bazel", "moon.yml", "release.toml", "tools"] [features] default = ["wasix"] @@ -58,8 +58,8 @@ extension-vector = ["extensions", "oliphaunt-wasix/extension-vector"] [dependencies] anyhow = "1" -oliphaunt-query = { path = "../../query/rust", version = "0.1.1" } -oliphaunt-wasix = { path = "../sdks/rust", version = "0.3.2", optional = true } +oliphaunt-query = { version = "0.1.1" } +oliphaunt-wasix = { workspace = true, optional = true } tempfile = { version = "3", optional = true } tokio = { version = "1", features = ["sync"], optional = true } tracing = { version = "0.1", optional = true } diff --git a/src/wasix/pgwire-server/moon.yml b/src/wasix/pgwire-server/moon.yml index 115dbe1e7..3aefd4e2a 100644 --- a/src/wasix/pgwire-server/moon.yml +++ b/src/wasix/pgwire-server/moon.yml @@ -12,7 +12,14 @@ project: release: component: "oliphaunt-pgwire-server" packagePath: "src/wasix/pgwire-server" +workspace: + mergeStrategies: + fileGroups: replace fileGroups: + cargo-workspace: + - "/src/wasix/node-addon/Cargo.lock" + - "/src/wasix/node-addon/Cargo.toml" + - "/rust-toolchain.toml" sources: ["src/**/*", "tests/**/*", "Cargo.toml"] tasks: format: @@ -23,21 +30,25 @@ tasks: format-check: command: "cargo fmt --check" tags: ["quality", "static", "format", "requires-rust"] - inputs: ["@group(sources)"] + inputs: ["@group(sources)", "@group(cargo-workspace)"] lint: deps: - target: cargo-sources cacheStrategy: hash command: "cargo clippy --all-targets --locked -- -D warnings" tags: ["quality", "static", "requires-rust"] - inputs: ["@group(sources)", "/Cargo.toml", "/Cargo.lock"] + inputs: ["@group(sources)", "@group(cargo-workspace)"] + env: + CARGO_TARGET_DIR: "../../../target" build: deps: - target: cargo-sources cacheStrategy: hash command: "cargo build --locked" tags: ["build", "requires-rust"] - inputs: ["@group(sources)", "/Cargo.toml", "/Cargo.lock"] + inputs: ["@group(sources)", "@group(cargo-workspace)"] + env: + CARGO_TARGET_DIR: "../../../target" outputs: ["/target/debug/oliphaunt-pgwire-server*", "/target/debug/liboliphaunt_pgwire_server.rlib"] test: deps: @@ -45,26 +56,30 @@ tasks: cacheStrategy: hash command: "cargo test --locked" tags: ["quality", "unit", "requires-rust"] - inputs: ["@group(sources)", "README.md", "/Cargo.toml", "/Cargo.lock"] + inputs: ["@group(sources)", "README.md", "@group(cargo-workspace)"] + env: + CARGO_TARGET_DIR: "../../../target" test-integration: command: "cargo test --locked -- --ignored --test-threads=1" tags: ["runtime", "integration", "requires-rust", "ci-liboliphaunt-wasix-aot"] deps: [{target: "cargo-sources", cacheStrategy: hash}, "liboliphaunt-wasix:runtime-aot"] - inputs: ["@group(sources)", "/Cargo.toml", "/Cargo.lock", "/src/extensions/catalog/extensions.source.json", "/src/test-fixtures/extensions/**/*"] + inputs: ["@group(sources)", "@group(cargo-workspace)", "/src/extensions/catalog/extensions.source.json", "/src/test-fixtures/extensions/**/*"] + env: + CARGO_TARGET_DIR: "../../../target" options: cache: false test-aot: command: "bash src/wasix/pgwire-server/tools/test-aot.sh" tags: ["runtime", "integration", "requires-rust", "ci-liboliphaunt-wasix-aot"] deps: [{target: "cargo-sources", cacheStrategy: hash}, "liboliphaunt-wasix:runtime-aot", "extension-artifacts-wasix:build-aot"] - inputs: ["@group(sources)", "tools/test-aot.sh", "/Cargo.toml", "/Cargo.lock"] + inputs: ["@group(sources)", "tools/test-aot.sh", "@group(cargo-workspace)"] options: cache: false runFromWorkspaceRoot: true package: command: "bash src/wasix/pgwire-server/tools/package.sh" tags: ["release", "artifact-package", "ci-wasix-rust-package"] - inputs: ["**/*", "@group(legal-files)", "/Cargo.toml", "/Cargo.lock", "@group(packaging-source)"] + inputs: ["**/*", "@group(legal-files)", "@group(cargo-workspace)", "@group(packaging-source)"] outputs: ["/target/sdk-artifacts/oliphaunt-pgwire-server/**/*"] options: runFromWorkspaceRoot: true @@ -77,6 +92,6 @@ tasks: sdk_version="$(bun tools/release/product-version.mts version oliphaunt-wasix-rust)" query_version="$(bun tools/release/product-version.mts version oliphaunt-query)" bash tools/packaging/check-cargo-package-tests.sh --crate "target/sdk-artifacts/oliphaunt-pgwire-server/oliphaunt-pgwire-server-$version.crate" --dependency-crate "target/sdk-artifacts/oliphaunt-wasix-rust/oliphaunt-wasix-$sdk_version.crate" --dependency-crate "target/sdk-artifacts/oliphaunt-query/oliphaunt-query-$query_version.crate" --path-dependencies-from src/wasix/sdks/rust/Cargo.toml - inputs: ["@group(sources)", "/Cargo.toml", "/Cargo.lock", "@group(packaging-source)", "@group(cargo-package-test)"] + inputs: ["@group(sources)", "@group(cargo-workspace)", "@group(packaging-source)", "@group(cargo-package-test)"] options: runFromWorkspaceRoot: true diff --git a/src/wasix/pgwire-server/release.toml b/src/wasix/pgwire-server/release.toml index dd309705f..1b5e70672 100644 --- a/src/wasix/pgwire-server/release.toml +++ b/src/wasix/pgwire-server/release.toml @@ -14,5 +14,5 @@ parser = "toml:dependencies.oliphaunt-query.version" [compatibility_versions.pgwire_server_wasix] public_support = false source_product = "oliphaunt-wasix-rust" -path = "src/wasix/pgwire-server/Cargo.toml" -parser = "toml:dependencies.oliphaunt-wasix.version" +path = "Cargo.toml" +parser = "toml:workspace.dependencies.oliphaunt-wasix.version" diff --git a/src/wasix/pgwire-server/tests/extensions.rs b/src/wasix/pgwire-server/tests/extensions.rs index e4eccb4bf..64e69ecaf 100644 --- a/src/wasix/pgwire-server/tests/extensions.rs +++ b/src/wasix/pgwire-server/tests/extensions.rs @@ -23,11 +23,193 @@ async fn public_extensions_pass_server_smoke() -> Result<()> { let rows = catalog["extensions"] .as_array() .context("extension catalog rows")?; + let supported: std::collections::BTreeSet<_> = Extension::ALL + .iter() + .map(|extension| extension.sql_name()) + .collect(); ensure!( - Extension::ALL.len() == rows.len(), - "enable every catalogued extension for server evidence" + supported.len() == Extension::ALL.len(), + "server SDK supported metadata must contain unique SQL names" ); - for extension in Extension::ALL { + let extensions = if let Some(expected) = option_env!("OLIPHAUNT_DECLARED_CONTRIB_SQL_NAMES") { + let names: Vec = serde_json::from_str(expected)?; + let expected: std::collections::BTreeSet<_> = names.iter().map(String::as_str).collect(); + let contrib_rows: Vec<_> = rows + .iter() + .filter(|row| row["source-kind"] == "postgres-contrib") + .map(|row| row["sql-name"].as_str().context("contrib catalog SQL name")) + .collect::>()?; + let contrib: std::collections::BTreeSet<_> = contrib_rows.iter().copied().collect(); + ensure!(!expected.is_empty() && names.len() == expected.len()); + ensure!( + contrib == expected && contrib.len() == contrib_rows.len(), + "held server test must select its exact canonical contrib inventory" + ); + // ALL describes supported metadata independently of Cargo payload features. + // Activating every selected member below requires its genuine held package. + names + .iter() + .map(|name| Extension::by_sql_name(name).context("held SDK contrib metadata")) + .collect::>>()? + } else { + let catalog_names: std::collections::BTreeSet<_> = rows + .iter() + .map(|row| { + row["sql-name"] + .as_str() + .context("extension catalog SQL name") + }) + .collect::>()?; + ensure!( + supported == catalog_names && catalog_names.len() == rows.len(), + "enable every catalogued extension for server evidence" + ); + Extension::ALL.to_vec() + }; + run_server_smoke_set(&extensions, rows, root).await +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +#[ignore = "requires the declared final contrib packet"] +#[allow(unsafe_code)] +async fn declared_contrib_carriers_pass_server_smoke() -> Result<()> { + use oliphaunt_wasix::ExtensionPackage; + use std::collections::BTreeSet; + fn fields<'a>( + value: &'a serde_json::Value, + names: &[&str], + ) -> Result<&'a serde_json::Map> { + let object = value.as_object().context("declared server packet object")?; + ensure!(object.len() == names.len() && names.iter().all(|name| object.contains_key(*name))); + Ok(object) + } + fn string<'a>(value: &'a serde_json::Value, name: &str) -> Result<&'a str> { + value[name] + .as_str() + .with_context(|| format!("declared server packet {name}")) + } + let packet: serde_json::Value = serde_json::from_slice(&std::fs::read( + std::env::var_os("OLIPHAUNT_DECLARED_EXTENSION_PACKET") + .context("declared contrib server requires its final packet")?, + )?)?; + fields( + &packet, + &[ + "product", + "version", + "runtimeVersion", + "archives", + "aotManifest", + "aotArtifacts", + "coreModuleSha256", + "coreManifest", + ], + )?; + let product = string(&packet, "product")?; + let version = string(&packet, "version")?; + let runtime_version = string(&packet, "runtimeVersion")?; + ensure!(product == "oliphaunt-extension-contrib-pg18"); + ensure!(version == runtime_version); + ensure!(Some(runtime_version) == option_env!("OLIPHAUNT_DECLARED_RUNTIME_VERSION")); + let expected_names: Vec = serde_json::from_str( + option_env!("OLIPHAUNT_DECLARED_CONTRIB_SQL_NAMES") + .context("declared server test requires its canonical compiled member names")?, + )?; + let expected: BTreeSet<_> = expected_names.iter().map(String::as_str).collect(); + let archive_rows = packet["archives"] + .as_array() + .context("declared server archives")?; + let actual: BTreeSet<_> = archive_rows + .iter() + .map(|archive| { + fields(archive, &["sqlName", "path", "sha256"])?; + string(archive, "sqlName") + }) + .collect::>()?; + ensure!(!expected.is_empty() && expected_names.len() == expected.len()); + ensure!(actual == expected && archive_rows.len() == expected.len()); + let core: serde_json::Value = + serde_json::from_slice(&std::fs::read(string(&packet, "coreManifest")?)?)?; + ensure!(core["runtime"]["module-sha256"] == string(&packet, "coreModuleSha256")?); + let aot_manifest = std::fs::read_to_string(string(&packet, "aotManifest")?)?; + let aot: serde_json::Value = serde_json::from_str(&aot_manifest)?; + let artifacts = aot["artifacts"] + .as_array() + .context("declared server AOT manifest has no artifacts")?; + let aot_artifacts = packet["aotArtifacts"] + .as_array() + .context("declared server AOT artifacts")? + .iter() + .map(|artifact| { + fields(artifact, &["path", "source"])?; + let path = string(artifact, "path")?; + let metadata = artifacts + .iter() + .find(|row| row["path"] == path) + .context("declared server AOT has no manifest entry")?; + Ok(( + &*Box::leak( + metadata["name"] + .as_str() + .context("declared server AOT has no module name")? + .to_owned() + .into_boxed_str(), + ), + &*Box::leak(std::fs::read(string(artifact, "source")?)?.into_boxed_slice()), + )) + }) + .collect::>>()?; + let archives = archive_rows + .iter() + .map(|archive| { + Ok(( + &*Box::leak(string(archive, "sqlName")?.to_owned().into_boxed_str()), + &*Box::leak(std::fs::read(string(archive, "path")?)?.into_boxed_slice()), + &*Box::leak(string(archive, "sha256")?.to_owned().into_boxed_str()), + )) + }) + .collect::>>()?; + // SAFETY: the installed runner authenticates the shared final-carrier packet before both tests. + let package = Box::leak(Box::new(unsafe { + ExtensionPackage::from_trusted_release( + Box::leak(product.to_owned().into_boxed_str()), + Box::leak(version.to_owned().into_boxed_str()), + Box::leak(runtime_version.to_owned().into_boxed_str()), + Box::leak(archives.into_boxed_slice()), + Box::leak(aot_manifest.into_boxed_str()), + Box::leak(aot_artifacts.into_boxed_slice()), + ) + })); + let extensions = expected_names + .iter() + .map(|name| { + Ok(Extension::by_sql_name(name) + .context("canonical contrib has no SDK metadata")? + .with_package(package)) + }) + .collect::>>()?; + let root = Path::new(env!("CARGO_MANIFEST_DIR")) + .parent() + .unwrap() + .parent() + .unwrap() + .parent() + .unwrap(); + let catalog: serde_json::Value = serde_json::from_slice(&std::fs::read( + root.join("src/extensions/catalog/extensions.source.json"), + )?)?; + let rows = catalog["extensions"] + .as_array() + .context("extension catalog rows")?; + run_server_smoke_set(&extensions, rows, root).await +} + +async fn run_server_smoke_set( + extensions: &[Extension], + rows: &[serde_json::Value], + root: &Path, +) -> Result<()> { + for extension in extensions { let name = extension.sql_name(); eprintln!("server extension smoke: {name}"); let server = AsyncOliphauntServer::builder() diff --git a/src/wasix/pgwire-server/tools/test-aot.sh b/src/wasix/pgwire-server/tools/test-aot.sh index c192fb77a..4b5b69d6e 100644 --- a/src/wasix/pgwire-server/tools/test-aot.sh +++ b/src/wasix/pgwire-server/tools/test-aot.sh @@ -15,5 +15,6 @@ OLIPHAUNT_WASIX_EXTENSION_AOT_ARTIFACT_ROOT="$PWD/target/extensions/wasix/aot-ar oliphaunt-extension-contrib-pg18 OLIPHAUNT_WASM_AOT_VERIFY=full \ OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT="$proof_root/extension-artifacts" \ - cargo test -p oliphaunt-pgwire-server --locked --features extension-uuid-ossp \ + CARGO_TARGET_DIR="$PWD/target" \ + cargo test --manifest-path src/wasix/pgwire-server/Cargo.toml --locked --features extension-uuid-ossp \ --test extensions uuid_ossp_aot_server_smoke -- --ignored --exact --nocapture diff --git a/src/wasix/pgwire-server/tools/testdata/shipping_supplier_fixture.rs b/src/wasix/pgwire-server/tools/testdata/shipping_supplier_fixture.rs new file mode 100644 index 000000000..8f43dbcd5 --- /dev/null +++ b/src/wasix/pgwire-server/tools/testdata/shipping_supplier_fixture.rs @@ -0,0 +1 @@ +pub const SHIPPING_SUPPLIER_FIXTURE: u8 = 1; diff --git a/src/wasix/postgres-tools/BUILD.bazel b/src/wasix/postgres-tools/BUILD.bazel new file mode 100644 index 000000000..4de24ac05 --- /dev/null +++ b/src/wasix/postgres-tools/BUILD.bazel @@ -0,0 +1,112 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files", "source_quality_files") +load("@rules_rust//rust:defs.bzl", "rust_clippy_test") +load("//build_defs/languages:rust.bzl", "cargo_generator", "cargo_library", "cargo_library_test", "cargo_package_env") +load("@aspect_rules_js//js:defs.bzl", "js_library") +load("@postgres_wasix//:patches.bzl", "POSTGRES_PATCHES") +load("//build_defs/wasix:package.bzl", "postgres_patch_inputs") +load("//build_defs/wasix:platform.bzl", "wasix_artifact") +load("//build_defs/wasix:tools.bzl", "wasix_tools_payload") +load("//build_defs/wasix:aot.bzl", "wasix_tools_aot_targets") +load("//build_defs/wasix:tools-carriers.bzl", "wasix_tools_carriers") + +package(default_visibility = ["//visibility:public"]) + +exports_files(glob(["tools/*.mts", "npm/native.mts"])) +exports_files(["npm/package.json", "npm/index.d.ts", "CHANGELOG.md"]) +exports_files(["crates/tools/Cargo.toml"]) + +js_library(name = "npm_types", srcs = ["npm/index.d.ts", "npm/package.json"]) + +wasix_tools_payload( + name = "portable_payload_files", + pg_dump = "//src/wasix/runtime:pg_dump", + psql = "//src/wasix/runtime:psql", + patches = postgres_patch_inputs(POSTGRES_PATCHES), + target_compatible_with = ["@platforms//cpu:wasm32", "@platforms//os:wasi"], +) + +wasix_artifact(name = "portable_payload", artifact = ":portable_payload_files") + +alias(name = "pg_dump", actual = "//src/wasix/runtime:pg_dump") +alias(name = "psql", actual = "//src/wasix/runtime:psql") + +wasix_tools_aot_targets() + +wasix_tools_carriers( + patches = postgres_patch_inputs(POSTGRES_PATCHES), + qualification = select({ + "//build_defs/native:linux_x86_64": [ + "//src/wasix/sdks/ts:browser_sql_consumer", + "//build_defs/wasix:macos_aot_repeatability_test", + "//src/wasix/sdks/rust:postgres_regression_test", + "//src/database-resources:wasix_resource_test", + "//src/wasix/postgres-tools/ts:installed_consumer_test", + ], + "//conditions:default": [], + }), +) + +filegroup(name = "carrier_source_patches", srcs = postgres_patch_inputs(POSTGRES_PATCHES)) + +_CARGO_PACKAGES = { + "portable": "crates/tools", + "aot_linux_x64_gnu": "crates/aot/x86_64-unknown-linux-gnu", + "aot_linux_arm64_gnu": "crates/aot/aarch64-unknown-linux-gnu", + "aot_macos_arm64": "crates/aot/aarch64-apple-darwin", + "aot_windows_x64_msvc": "crates/aot/x86_64-pc-windows-msvc", +} + +[cargo_package_env( + name = cohort + "_cargo_env", + package_name = "src/wasix/postgres-tools/" + source, +) for cohort, source in _CARGO_PACKAGES.items()] + +[cargo_generator( + name = cohort + "_cargo_build_script", + package_name = "src/wasix/postgres-tools/" + source, + cargo_env = ":" + cohort + "_cargo_env", + srcs = [source + "/build-support.rs"], +) for cohort, source in _CARGO_PACKAGES.items()] + +[cargo_library( + name = cohort + "_cargo_lib", + package_name = "src/wasix/postgres-tools/" + source, + cargo_env = ":" + cohort + "_cargo_env", + build_script = ":" + cohort + "_cargo_build_script", +) for cohort, source in _CARGO_PACKAGES.items()] + +[cargo_library_test( + name = cohort + "_cargo_unit_test", + package_name = "src/wasix/postgres-tools/" + source, + cargo_env = ":" + cohort + "_cargo_env", + crate = ":" + cohort + "_cargo_lib", + tags = ["manual"], +) for cohort, source in _CARGO_PACKAGES.items()] + +rust_clippy_test( + name = "clippy_test", + targets = [ + ":portable_cargo_lib", + ":portable_cargo_unit_test", + ":portable_cargo_build_script_", + ":aot_linux_x64_gnu_cargo_lib", + ":aot_linux_x64_gnu_cargo_unit_test", + ":aot_linux_x64_gnu_cargo_build_script_", + ":aot_linux_arm64_gnu_cargo_lib", + ":aot_linux_arm64_gnu_cargo_unit_test", + ":aot_linux_arm64_gnu_cargo_build_script_", + ":aot_macos_arm64_cargo_lib", + ":aot_macos_arm64_cargo_unit_test", + ":aot_macos_arm64_cargo_build_script_", + ":aot_windows_x64_msvc_cargo_lib", + ":aot_windows_x64_msvc_cargo_unit_test", + ":aot_windows_x64_msvc_cargo_build_script_", + ], + transitive = False, + size = "small", + tags = ["quality", "static"], +) + +source_quality_files() + +rust_quality_files() diff --git a/src/wasix/postgres-tools/crates/aot/aarch64-apple-darwin/build-support.rs b/src/wasix/postgres-tools/crates/aot/aarch64-apple-darwin/build-support.rs index 68dd1f4d7..73c56cddf 100644 --- a/src/wasix/postgres-tools/crates/aot/aarch64-apple-darwin/build-support.rs +++ b/src/wasix/postgres-tools/crates/aot/aarch64-apple-darwin/build-support.rs @@ -217,7 +217,59 @@ fn artifact_name_from_file_stem(stem: &str) -> String { } fn rust_string_literal(path: &Path) -> String { - format!("{:?}", path.to_string_lossy()) + // Generated Rust is compiled in a later action. Keep references relative + // to its output directory instead of retaining a build-script sandbox. + fn lexical_absolute(path: &Path) -> PathBuf { + let mut normalized = PathBuf::new(); + for component in std::path::absolute(path) + .expect("absolute generated include path") + .components() + { + match component { + std::path::Component::ParentDir => { + normalized.pop(); + } + std::path::Component::CurDir => {} + component => normalized.push(component.as_os_str()), + } + } + normalized + } + + let base = lexical_absolute(&PathBuf::from( + env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"), + )); + let target = lexical_absolute(path); + if !target.starts_with(&base) { + let manifest_dir = lexical_absolute(&PathBuf::from( + env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"), + )); + if let Ok(member) = target.strip_prefix(&manifest_dir) { + return format!( + "concat!(env!(\"CARGO_MANIFEST_DIR\"), {:?})", + format!("/{}", member.to_string_lossy().replace('\\', "/")) + ); + } + } + let base_components = base.components().collect::>(); + let target_components = target.components().collect::>(); + let common = base_components + .iter() + .zip(&target_components) + .take_while(|(left, right)| left == right) + .count(); + if common == 0 { + // Ordinary Windows Cargo may place inputs and outputs on separate drives. + return format!("{:?}", target.to_string_lossy()); + } + let mut relative = PathBuf::new(); + for _ in &base_components[common..] { + relative.push(".."); + } + for component in &target_components[common..] { + relative.push(component.as_os_str()); + } + format!("{:?}", relative.to_string_lossy()) } fn artifact_belongs_to_crate(name: &str) -> bool { diff --git a/src/wasix/postgres-tools/crates/aot/aarch64-unknown-linux-gnu/build-support.rs b/src/wasix/postgres-tools/crates/aot/aarch64-unknown-linux-gnu/build-support.rs index 68dd1f4d7..73c56cddf 100644 --- a/src/wasix/postgres-tools/crates/aot/aarch64-unknown-linux-gnu/build-support.rs +++ b/src/wasix/postgres-tools/crates/aot/aarch64-unknown-linux-gnu/build-support.rs @@ -217,7 +217,59 @@ fn artifact_name_from_file_stem(stem: &str) -> String { } fn rust_string_literal(path: &Path) -> String { - format!("{:?}", path.to_string_lossy()) + // Generated Rust is compiled in a later action. Keep references relative + // to its output directory instead of retaining a build-script sandbox. + fn lexical_absolute(path: &Path) -> PathBuf { + let mut normalized = PathBuf::new(); + for component in std::path::absolute(path) + .expect("absolute generated include path") + .components() + { + match component { + std::path::Component::ParentDir => { + normalized.pop(); + } + std::path::Component::CurDir => {} + component => normalized.push(component.as_os_str()), + } + } + normalized + } + + let base = lexical_absolute(&PathBuf::from( + env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"), + )); + let target = lexical_absolute(path); + if !target.starts_with(&base) { + let manifest_dir = lexical_absolute(&PathBuf::from( + env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"), + )); + if let Ok(member) = target.strip_prefix(&manifest_dir) { + return format!( + "concat!(env!(\"CARGO_MANIFEST_DIR\"), {:?})", + format!("/{}", member.to_string_lossy().replace('\\', "/")) + ); + } + } + let base_components = base.components().collect::>(); + let target_components = target.components().collect::>(); + let common = base_components + .iter() + .zip(&target_components) + .take_while(|(left, right)| left == right) + .count(); + if common == 0 { + // Ordinary Windows Cargo may place inputs and outputs on separate drives. + return format!("{:?}", target.to_string_lossy()); + } + let mut relative = PathBuf::new(); + for _ in &base_components[common..] { + relative.push(".."); + } + for component in &target_components[common..] { + relative.push(component.as_os_str()); + } + format!("{:?}", relative.to_string_lossy()) } fn artifact_belongs_to_crate(name: &str) -> bool { diff --git a/src/wasix/postgres-tools/crates/aot/x86_64-pc-windows-msvc/build-support.rs b/src/wasix/postgres-tools/crates/aot/x86_64-pc-windows-msvc/build-support.rs index 68dd1f4d7..73c56cddf 100644 --- a/src/wasix/postgres-tools/crates/aot/x86_64-pc-windows-msvc/build-support.rs +++ b/src/wasix/postgres-tools/crates/aot/x86_64-pc-windows-msvc/build-support.rs @@ -217,7 +217,59 @@ fn artifact_name_from_file_stem(stem: &str) -> String { } fn rust_string_literal(path: &Path) -> String { - format!("{:?}", path.to_string_lossy()) + // Generated Rust is compiled in a later action. Keep references relative + // to its output directory instead of retaining a build-script sandbox. + fn lexical_absolute(path: &Path) -> PathBuf { + let mut normalized = PathBuf::new(); + for component in std::path::absolute(path) + .expect("absolute generated include path") + .components() + { + match component { + std::path::Component::ParentDir => { + normalized.pop(); + } + std::path::Component::CurDir => {} + component => normalized.push(component.as_os_str()), + } + } + normalized + } + + let base = lexical_absolute(&PathBuf::from( + env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"), + )); + let target = lexical_absolute(path); + if !target.starts_with(&base) { + let manifest_dir = lexical_absolute(&PathBuf::from( + env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"), + )); + if let Ok(member) = target.strip_prefix(&manifest_dir) { + return format!( + "concat!(env!(\"CARGO_MANIFEST_DIR\"), {:?})", + format!("/{}", member.to_string_lossy().replace('\\', "/")) + ); + } + } + let base_components = base.components().collect::>(); + let target_components = target.components().collect::>(); + let common = base_components + .iter() + .zip(&target_components) + .take_while(|(left, right)| left == right) + .count(); + if common == 0 { + // Ordinary Windows Cargo may place inputs and outputs on separate drives. + return format!("{:?}", target.to_string_lossy()); + } + let mut relative = PathBuf::new(); + for _ in &base_components[common..] { + relative.push(".."); + } + for component in &target_components[common..] { + relative.push(component.as_os_str()); + } + format!("{:?}", relative.to_string_lossy()) } fn artifact_belongs_to_crate(name: &str) -> bool { diff --git a/src/wasix/postgres-tools/crates/aot/x86_64-unknown-linux-gnu/build-support.rs b/src/wasix/postgres-tools/crates/aot/x86_64-unknown-linux-gnu/build-support.rs index 68dd1f4d7..73c56cddf 100644 --- a/src/wasix/postgres-tools/crates/aot/x86_64-unknown-linux-gnu/build-support.rs +++ b/src/wasix/postgres-tools/crates/aot/x86_64-unknown-linux-gnu/build-support.rs @@ -217,7 +217,59 @@ fn artifact_name_from_file_stem(stem: &str) -> String { } fn rust_string_literal(path: &Path) -> String { - format!("{:?}", path.to_string_lossy()) + // Generated Rust is compiled in a later action. Keep references relative + // to its output directory instead of retaining a build-script sandbox. + fn lexical_absolute(path: &Path) -> PathBuf { + let mut normalized = PathBuf::new(); + for component in std::path::absolute(path) + .expect("absolute generated include path") + .components() + { + match component { + std::path::Component::ParentDir => { + normalized.pop(); + } + std::path::Component::CurDir => {} + component => normalized.push(component.as_os_str()), + } + } + normalized + } + + let base = lexical_absolute(&PathBuf::from( + env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"), + )); + let target = lexical_absolute(path); + if !target.starts_with(&base) { + let manifest_dir = lexical_absolute(&PathBuf::from( + env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"), + )); + if let Ok(member) = target.strip_prefix(&manifest_dir) { + return format!( + "concat!(env!(\"CARGO_MANIFEST_DIR\"), {:?})", + format!("/{}", member.to_string_lossy().replace('\\', "/")) + ); + } + } + let base_components = base.components().collect::>(); + let target_components = target.components().collect::>(); + let common = base_components + .iter() + .zip(&target_components) + .take_while(|(left, right)| left == right) + .count(); + if common == 0 { + // Ordinary Windows Cargo may place inputs and outputs on separate drives. + return format!("{:?}", target.to_string_lossy()); + } + let mut relative = PathBuf::new(); + for _ in &base_components[common..] { + relative.push(".."); + } + for component in &target_components[common..] { + relative.push(component.as_os_str()); + } + format!("{:?}", relative.to_string_lossy()) } fn artifact_belongs_to_crate(name: &str) -> bool { diff --git a/src/wasix/postgres-tools/crates/tools/build-support.rs b/src/wasix/postgres-tools/crates/tools/build-support.rs index 40e2a351a..00b78b6df 100644 --- a/src/wasix/postgres-tools/crates/tools/build-support.rs +++ b/src/wasix/postgres-tools/crates/tools/build-support.rs @@ -152,7 +152,59 @@ fn write_source_only_tools(out: &Path) { } fn rust_string_literal(path: &Path) -> String { - format!("{:?}", path.to_string_lossy()) + // Generated Rust is compiled in a later action. Keep references relative + // to its output directory instead of retaining a build-script sandbox. + fn lexical_absolute(path: &Path) -> PathBuf { + let mut normalized = PathBuf::new(); + for component in std::path::absolute(path) + .expect("absolute generated include path") + .components() + { + match component { + std::path::Component::ParentDir => { + normalized.pop(); + } + std::path::Component::CurDir => {} + component => normalized.push(component.as_os_str()), + } + } + normalized + } + + let base = lexical_absolute(&PathBuf::from( + env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"), + )); + let target = lexical_absolute(path); + if !target.starts_with(&base) { + let manifest_dir = lexical_absolute(&PathBuf::from( + env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"), + )); + if let Ok(member) = target.strip_prefix(&manifest_dir) { + return format!( + "concat!(env!(\"CARGO_MANIFEST_DIR\"), {:?})", + format!("/{}", member.to_string_lossy().replace('\\', "/")) + ); + } + } + let base_components = base.components().collect::>(); + let target_components = target.components().collect::>(); + let common = base_components + .iter() + .zip(&target_components) + .take_while(|(left, right)| left == right) + .count(); + if common == 0 { + // Ordinary Windows Cargo may place inputs and outputs on separate drives. + return format!("{:?}", target.to_string_lossy()); + } + let mut relative = PathBuf::new(); + for _ in &base_components[common..] { + relative.push(".."); + } + for component in &target_components[common..] { + relative.push(component.as_os_str()); + } + format!("{:?}", relative.to_string_lossy()) } fn emit_artifact_manifest(out_dir: &Path, asset_dir: &Path, files: &[&Path]) { diff --git a/src/wasix/postgres-tools/moon.yml b/src/wasix/postgres-tools/moon.yml index bd6741364..4bb6c315b 100644 --- a/src/wasix/postgres-tools/moon.yml +++ b/src/wasix/postgres-tools/moon.yml @@ -13,9 +13,6 @@ project: release: component: "postgres-tools-wasix" packagePath: "src/wasix/postgres-tools" - artifactTargets: - preset: "postgres-tools-wasix" - targets: ["portable", "linux-arm64-gnu", "linux-x64-gnu", "macos-arm64", "windows-x64-msvc"] fileGroups: sources: ["**/*", "!**/node_modules/**/*", "!**/target/**/*"] cargo-carrier-sources: ["crates/**/*.rs", "crates/**/Cargo.toml"] diff --git a/src/wasix/postgres-tools/release.toml b/src/wasix/postgres-tools/release.toml index c2582db59..498cb9c7c 100644 --- a/src/wasix/postgres-tools/release.toml +++ b/src/wasix/postgres-tools/release.toml @@ -34,3 +34,13 @@ public_support = false source_product = "oliphaunt-wasix-ts" path = "src/wasix/postgres-tools/ts/package.json" parser = "json:oliphaunt.wasixSdkVersion" + +[artifact_targets] +preset = "postgres-tools-wasix" +targets = [ + "portable", + "linux-arm64-gnu", + "linux-x64-gnu", + "macos-arm64", + "windows-x64-msvc", +] diff --git a/src/wasix/postgres-tools/tools/package-assets.mts b/src/wasix/postgres-tools/tools/package-assets.mts index 1bf146919..9df852ea8 100644 --- a/src/wasix/postgres-tools/tools/package-assets.mts +++ b/src/wasix/postgres-tools/tools/package-assets.mts @@ -1,18 +1,23 @@ #!/usr/bin/env bun import { createHash } from 'node:crypto'; -import { copyFileSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { copyFileSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { parseArgs } from 'node:util'; +import { createDeterministicTar } from '../../../../tools/packaging/cargo-source-package.mts'; +import { listArchiveEntries } from '../../../../tools/packaging/package-archive.mts'; +import { canonicalGzipSync } from '../../../../tools/packaging/portable-archive.mts'; +import { + assertReleaseNoticesInDirectory, + releaseNoticeRows, + stageReleaseNotices, +} from '../../../../tools/packaging/release-notices.mts'; +import { currentProductVersionSync } from '../../../../tools/release/release-artifact-targets.mts'; import { assertWasixAotArtifactPayloads } from '../../runtime/tools/check-release-assets.mts'; import { validateAotPayload } from '../../runtime/tools/package_liboliphaunt_wasix_cargo_artifacts.mts'; import { postgresSourceFingerprint } from '../../runtime/tools/package-release-assets.mts'; import { assertCanonicalWasixAotManifest } from '../../runtime/tools/wasix-aot-manifest.mts'; import { AOT_TARGET_TRIPLES } from '../../runtime/tools/wasix-cargo-artifact-contract.mts'; -import { createDeterministicTar } from '../../../../tools/packaging/cargo-source-package.mts'; -import { canonicalGzipSync } from '../../../../tools/packaging/portable-archive.mts'; -import { stageReleaseNotices } from '../../../../tools/packaging/release-notices.mts'; -import { currentProductVersionSync } from '../../../../tools/release/release-artifact-targets.mts'; export const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../..'); export const PORTABLE_SCHEMA = 'postgres-tools-wasix-portable-v1'; @@ -26,23 +31,35 @@ export function readJson(file) { return JSON.parse(readFileSync(file, 'utf8')); } -export function validateToolsAotPayload(root, triple) { +export function validateToolsAotPayload( + root, + triple, + { sourceFingerprint = postgresSourceFingerprint(), sourceRoot = ROOT } = {}, +) { const manifest = readJson(path.join(root, 'manifest.json')); - assertSource(manifest); + assertSource(manifest, sourceFingerprint); const names = manifest.artifacts?.map((row) => row.name).sort(); if (JSON.stringify(names) !== JSON.stringify(['tool:pg_dump', 'tool:psql'])) fail('WASIX tools AOT archive must contain exactly pg_dump and psql'); - validateAotPayload(root, triple); + validateAotPayload(root, triple, { sourceRoot }); return manifest; } -export function validatePortableToolsPayload(root, version) { +export function validatePortableToolsPayload( + root, + version, + { + runtimeVersion = currentProductVersionSync('liboliphaunt-wasix'), + sourceFingerprint = postgresSourceFingerprint(), + sourceRoot = ROOT, + } = {}, +) { const manifest = readJson(path.join(root, 'manifest.json')); if ( manifest.schema !== PORTABLE_SCHEMA || manifest.version !== version || - manifest.runtimeVersion !== currentProductVersionSync('liboliphaunt-wasix') || - manifest.sourceFingerprint !== postgresSourceFingerprint() + manifest.runtimeVersion !== runtimeVersion || + manifest.sourceFingerprint !== sourceFingerprint ) fail('WASIX tools portable archive has incompatible producer identity'); for (const [key, name] of [ @@ -60,14 +77,25 @@ export function validatePortableToolsPayload(root, version) { ) fail(`WASIX ${name} archive bytes do not match its manifest`); } + const notices = { profile: 'wasix-tools', sourceRoot }; + assertReleaseNoticesInDirectory(root, notices); + const expected = [ + 'manifest.json', + 'bin/pg_dump.wasix.wasm', + 'bin/psql.wasix.wasm', + ...releaseNoticeRows(notices).map(({ member }) => member), + ].sort(); + const actual = listArchiveEntries(root) + .filter((file) => statSync(file).isFile()) + .map((file) => path.relative(root, file).split(path.sep).join('/')) + .sort(); + if (JSON.stringify(actual) !== JSON.stringify(expected)) + fail('WASIX tools portable payload must contain exactly its two commands and legal notices'); return manifest; } -function assertSource(manifest) { - if ( - manifest['source-lane'] !== 'stable' || - manifest['source-fingerprint'] !== postgresSourceFingerprint() - ) { +function assertSource(manifest, fingerprint = postgresSourceFingerprint()) { + if (manifest['source-lane'] !== 'stable' || manifest['source-fingerprint'] !== fingerprint) { fail( 'WASIX tools inputs do not match the current PostgreSQL source fingerprint; rebuild the producer', ); diff --git a/src/wasix/postgres-tools/tools/wasix-tools-aot-npm.mts b/src/wasix/postgres-tools/tools/wasix-tools-aot-npm.mts index d15496038..1f5ce0972 100644 --- a/src/wasix/postgres-tools/tools/wasix-tools-aot-npm.mts +++ b/src/wasix/postgres-tools/tools/wasix-tools-aot-npm.mts @@ -1,22 +1,84 @@ import { mkdirSync, rmSync, writeFileSync } from 'node:fs'; import path from 'node:path'; -import { artifactTargets, ROOT } from '../../../../tools/release/release-artifact-targets.mts'; +import { createDeterministicTar } from '../../../../tools/packaging/cargo-source-package.mts'; +import { + NPM_TRUSTED_PUBLISHING_REPOSITORY, + validateNpmTrustedPublishingManifest, +} from '../../../../tools/packaging/npm-trusted-publishing.mts'; import { - extractPortableArchiveTree, canonicalGzipSync, + extractPortableArchiveTree, } from '../../../../tools/packaging/portable-archive.mts'; -import { createDeterministicTar } from '../../../../tools/packaging/cargo-source-package.mts'; import { - stageReleaseNotices, assertReleaseNoticesInArchive, releaseProfilePackageLicense, + stageReleaseNotices, } from '../../../../tools/packaging/release-notices.mts'; -import { - NPM_TRUSTED_PUBLISHING_REPOSITORY, - validateNpmTrustedPublishingManifest, -} from '../../../../tools/packaging/npm-trusted-publishing.mts'; +import { artifactTargets, ROOT } from '../../../../tools/release/release-artifact-targets.mts'; import { validateToolsAotPayload } from './package-assets.mts'; +export function packWasixToolsAotNpmCarrier({ + version, + assetDir, + target, + workRoot = path.join(ROOT, 'target/release'), + sourceRoot = ROOT, + sourceFingerprint, +}) { + const packageName = target.npmPackage; + const stage = path.join(workRoot, 'npm-package-sources', packageName.replace('@oliphaunt/', '')); + rmSync(stage, { recursive: true, force: true }); + mkdirSync(stage, { recursive: true }); + extractPortableArchiveTree( + path.join(assetDir, target.asset.replaceAll('{version}', version)), + path.join(stage, 'assets'), + ); + validateToolsAotPayload(path.join(stage, 'assets'), target.triple, { + sourceRoot, + sourceFingerprint, + }); + const manifest = { + name: packageName, + version, + type: 'module', + description: 'Target AOT PostgreSQL tools for the Oliphaunt WASIX tools package.', + license: releaseProfilePackageLicense('wasix-runtime', { sourceRoot }).spdx, + os: [target.npmOs], + cpu: [target.npmCpu], + ...(target.npmLibc ? { libc: [target.npmLibc] } : {}), + repository: { type: 'git', url: NPM_TRUSTED_PUBLISHING_REPOSITORY }, + publishConfig: { access: 'public', provenance: true }, + exports: { './package.json': './package.json' }, + files: ['assets', 'LICENSE', 'THIRD_PARTY_NOTICES.md', 'third-party-licenses'], + }; + validateNpmTrustedPublishingManifest(manifest, packageName); + writeFileSync(path.join(stage, 'package.json'), JSON.stringify(manifest, null, 2) + '\n'); + stageReleaseNotices(stage, { profile: 'wasix-runtime', sourceRoot }); + const output = path.join(workRoot, 'npm-packages', packageName.replace('@oliphaunt/', '')); + mkdirSync(output, { recursive: true }); + const tarball = path.join( + output, + `${packageName.replace('@', '').replace('/', '-')}-${version}.tgz`, + ); + writeFileSync( + tarball, + canonicalGzipSync( + createDeterministicTar(stage, 'package', { + fail: (message) => { + throw new Error(message); + }, + fixedFileMode: 0o644, + }), + ), + ); + assertReleaseNoticesInArchive(tarball, { + profile: 'wasix-runtime', + prefix: 'package', + sourceRoot, + }); + return tarball; +} + export function packWasixToolsAotNpmCarriers( version, assetDir, @@ -24,55 +86,5 @@ export function packWasixToolsAotNpmCarriers( ) { return artifactTargets('postgres-tools-wasix', 'wasix-tools-aot', 'wasix-tools-aot-npm.mts') .filter((target) => targetIds === undefined || targetIds.includes(target.target)) - .map((target) => { - const packageName = target.npmPackage; - const stage = path.join( - workRoot, - 'npm-package-sources', - packageName.replace('@oliphaunt/', ''), - ); - rmSync(stage, { recursive: true, force: true }); - mkdirSync(stage, { recursive: true }); - extractPortableArchiveTree( - path.join(assetDir, target.asset.replaceAll('{version}', version)), - path.join(stage, 'assets'), - ); - validateToolsAotPayload(path.join(stage, 'assets'), target.triple); - const manifest = { - name: packageName, - version, - type: 'module', - description: 'Target AOT PostgreSQL tools for the Oliphaunt WASIX tools package.', - license: releaseProfilePackageLicense('wasix-runtime').spdx, - os: [target.npmOs], - cpu: [target.npmCpu], - ...(target.npmLibc ? { libc: [target.npmLibc] } : {}), - repository: { type: 'git', url: NPM_TRUSTED_PUBLISHING_REPOSITORY }, - publishConfig: { access: 'public', provenance: true }, - exports: { './package.json': './package.json' }, - files: ['assets', 'LICENSE', 'THIRD_PARTY_NOTICES.md', 'third-party-licenses'], - }; - validateNpmTrustedPublishingManifest(manifest, packageName); - writeFileSync(path.join(stage, 'package.json'), JSON.stringify(manifest, null, 2) + '\n'); - stageReleaseNotices(stage, { profile: 'wasix-runtime' }); - const output = path.join(workRoot, 'npm-packages', packageName.replace('@oliphaunt/', '')); - mkdirSync(output, { recursive: true }); - const tarball = path.join( - output, - `${packageName.replace('@', '').replace('/', '-')}-${version}.tgz`, - ); - writeFileSync( - tarball, - canonicalGzipSync( - createDeterministicTar(stage, 'package', { - fail: (message) => { - throw new Error(message); - }, - fixedFileMode: 0o644, - }), - ), - ); - assertReleaseNoticesInArchive(tarball, { profile: 'wasix-runtime', prefix: 'package' }); - return tarball; - }); + .map((target) => packWasixToolsAotNpmCarrier({ version, assetDir, target, workRoot })); } diff --git a/src/wasix/postgres-tools/tools/wasix-tools-npm-carrier.mts b/src/wasix/postgres-tools/tools/wasix-tools-npm-carrier.mts index 9c9e911bb..0299edd4d 100644 --- a/src/wasix/postgres-tools/tools/wasix-tools-npm-carrier.mts +++ b/src/wasix/postgres-tools/tools/wasix-tools-npm-carrier.mts @@ -96,7 +96,13 @@ export function wasixToolsNpmInputs({ portableReleaseArchive }) { return Object.freeze({ tools: Object.freeze(tools), manifest }); } -export function stageWasixToolsNpmCarrier({ version, portableReleaseArchive, packageDir }) { +export function stageWasixToolsNpmCarrier({ + version, + portableReleaseArchive, + packageDir, + sourceRoot = ROOT, +}) { + const noticeOptions = { ...NOTICE_OPTIONS, sourceRoot }; if (typeof version !== 'string' || !/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/u.test(version)) { throw new TypeError(`${TOOL}: version must be an exact semantic version`); } @@ -116,7 +122,7 @@ export function stageWasixToolsNpmCarrier({ version, portableReleaseArchive, pac writeFileSync(path.join(output, 'index.d.ts'), renderTypes(), { mode: 0o644 }); writeFileSync( path.join(output, 'native.js'), - readFileSync(path.join(ROOT, 'src/wasix/postgres-tools/npm/native.mts')), + readFileSync(path.join(sourceRoot, 'src/wasix/postgres-tools/npm/native.mts')), { mode: 0o644 }, ); writeFileSync( @@ -124,13 +130,13 @@ export function stageWasixToolsNpmCarrier({ version, portableReleaseArchive, pac `# ${PACKAGE_NAME}\n\nPortable PostgreSQL \`pg_dump\` and \`psql\` modules used by \`@oliphaunt/wasix-tools\`. Application code should depend on the facade rather than this asset carrier.\n`, { mode: 0o644 }, ); - stageReleaseNotices(output, NOTICE_OPTIONS); - const notices = releaseNoticeRows(NOTICE_OPTIONS).map(({ member }) => member); + stageReleaseNotices(output, noticeOptions); + const notices = releaseNoticeRows(noticeOptions).map(({ member }) => member); const manifest = { name: PACKAGE_NAME, version, description: 'Portable WASIX pg_dump and psql modules for Oliphaunt hosts.', - license: releaseProfilePackageLicense('wasix-runtime').spdx, + license: releaseProfilePackageLicense('wasix-runtime', { sourceRoot }).spdx, type: 'module', sideEffects: false, repository: { type: 'git', url: NPM_TRUSTED_PUBLISHING_REPOSITORY }, @@ -166,7 +172,7 @@ export function stageWasixToolsNpmCarrier({ version, portableReleaseArchive, pac writeFileSync(path.join(output, 'package.json'), `${JSON.stringify(manifest, null, 2)}\n`, { mode: 0o644, }); - assertReleaseNoticesInDirectory(output, NOTICE_OPTIONS); + assertReleaseNoticesInDirectory(output, noticeOptions); return Object.freeze({ packageDir: output, descriptor }); } @@ -175,8 +181,14 @@ export function packWasixToolsNpmCarrier({ portableReleaseArchive, packageDir = path.join(ROOT, 'target/release/npm-package-sources/liboliphaunt-wasix-tools'), tarballRoot = path.join(ROOT, 'target/release/npm-packages/liboliphaunt-wasix-tools'), + sourceRoot = ROOT, }) { - const staged = stageWasixToolsNpmCarrier({ version, portableReleaseArchive, packageDir }); + const staged = stageWasixToolsNpmCarrier({ + version, + portableReleaseArchive, + packageDir, + sourceRoot, + }); const output = path.resolve(tarballRoot); rmSync(output, { recursive: true, force: true }); mkdirSync(output, { recursive: true }); @@ -187,13 +199,14 @@ export function packWasixToolsNpmCarrier({ createDeterministicTar(staged.packageDir, 'package', { fail, fixedFileMode: 0o644 }), ), ); - assertWasixToolsNpmArchive(tarball, staged.descriptor); + assertWasixToolsNpmArchive(tarball, staged.descriptor, { sourceRoot }); return Object.freeze({ ...staged, tarball }); } -export function assertWasixToolsNpmArchive(archive, descriptor) { +export function assertWasixToolsNpmArchive(archive, descriptor, { sourceRoot = ROOT } = {}) { + const noticeOptions = { ...NOTICE_OPTIONS, sourceRoot }; if (statSync(archive).size > 20 * 1024 * 1024) fail(`${archive} exceeds the package size limit`); - assertReleaseNoticesInArchive(archive, { ...NOTICE_OPTIONS, prefix: 'package' }); + assertReleaseNoticesInArchive(archive, { ...noticeOptions, prefix: 'package' }); const entries = readPortableArchiveEntries(archive); const expected = [ 'package/package.json', @@ -203,7 +216,7 @@ export function assertWasixToolsNpmArchive(archive, descriptor) { 'package/index.d.ts', 'package/assets/pg_dump.wasix.wasm', 'package/assets/psql.wasix.wasm', - ...releaseNoticeRows(NOTICE_OPTIONS).map(({ member }) => `package/${member}`), + ...releaseNoticeRows(noticeOptions).map(({ member }) => `package/${member}`), ].sort(); const actual = [...entries] .filter(([, entry]) => entry.isFile) diff --git a/src/wasix/postgres-tools/ts/BUILD.bazel b/src/wasix/postgres-tools/ts/BUILD.bazel new file mode 100644 index 000000000..e727679b4 --- /dev/null +++ b/src/wasix/postgres-tools/ts/BUILD.bazel @@ -0,0 +1,149 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("@aspect_rules_js//js:defs.bzl", "js_library") +load("@aspect_rules_js//npm:defs.bzl", "npm_link_package", "npm_package") +load("@aspect_rules_ts//ts:defs.bzl", "ts_project") +load("@oliphaunt_javascript_metadata//:metadata.bzl", "JAVASCRIPT") +load("@oliphaunt_metadata//:metadata.bzl", "PUBLICATION_CARRIERS") +load("@javascript_packages//:defs.bzl", "javascript_type_links", TYPE_PACKAGES = "PACKAGES") +load("@javascript_installed_packages//:defs.bzl", INSTALLED_PACKAGES = "PACKAGES") +load("@javascript_installed_packages//:roots.bzl", "CONSUMER_TOOLS") +load("//build_defs/languages/ts:defs.bzl", "installed_npm_consumer_test", "npm_archive_package", "npm_dependency_closure", "source_sdk_publish_files") +load("//build_defs/query:defs.bzl", "query_envelope") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") + +package(default_visibility = ["//visibility:public"]) + +_MODULE_OUT_DIR = "lib" + +exports_files(["package.json", "tools/package.mts"]) + +SDK = JAVASCRIPT["@oliphaunt/wasix-tools"] +WASIX = JAVASCRIPT["@oliphaunt/wasix-ts"] +QUERY = JAVASCRIPT["@oliphaunt/ts-query"] +WASIX_DEPENDENCIES = WASIX["types"] | WASIX["packages"] + +javascript_type_links(SDK["types"] | WASIX_DEPENDENCIES) + +# Project type bytes without forwarding package stores rooted in the SDK package. +npm_package( + name = "wasix_types", + srcs = ["//src/wasix/sdks/ts:module_types", "//src/wasix/sdks/ts:publish_manifest"], + package = WASIX["name"], + version = WASIX["version"], + root_paths = ["src/wasix/sdks/ts"], + include_srcs_packages = ["src/wasix/sdks/ts"], + include_srcs_patterns = ["lib/**/*.d.ts", "publish_files/package.json"], + include_transitive_sources = False, + include_transitive_types = False, + replace_prefixes = {"publish_files/": ""}, +) +npm_archive_package( + name = "query_package", + archive = "//src/query/ts:npm", + package_name = QUERY["name"], + version = QUERY["version"], +) +npm_link_package(name = "node_modules/@oliphaunt/ts-query", src = ":query_package") +npm_link_package( + name = "node_modules/@oliphaunt/wasix-ts", + src = ":wasix_types", + deps = {":_javascript_" + key: name for name, key in WASIX_DEPENDENCIES.items()} | { + ":.aspect_rules_js/node_modules/@oliphaunt/ts-query": QUERY["name"], + }, +) +js_library(name = "package_metadata", srcs = ["package.json"], deps = ["//src/wasix/postgres-tools:npm_types"]) + +ts_project( + name = "module", + srcs = glob(["src/**/*.ts"], exclude = ["src/__tests__/**"]), + tsconfig = "tsconfig.build.json", + extends = "tsconfig.json", + declaration = True, + declaration_map = False, + out_dir = _MODULE_OUT_DIR, + root_dir = "src", + transpiler = "tsc", + supports_workers = 0, + deps = [":package_metadata", ":node_modules/@oliphaunt/wasix-ts"] + [":node_modules/" + name for name in SDK["types"]], +) + +source_sdk_publish_files(name = "publish_files", manifest = "package.json", profile = "wasix-tools") + +ts_project( + name = "source_checks", + srcs = glob(["src/**/*.ts"]), + tsconfig = "tsconfig.json", + no_emit = True, + declaration = True, + out_dir = _MODULE_OUT_DIR, + root_dir = "src", + supports_workers = 0, + deps = [":package_metadata", ":node_modules/@oliphaunt/wasix-ts"] + [":node_modules/" + name for name in SDK["types"]], +) +filegroup(name = "publish_manifest", srcs = [":publish_files"], output_group = "manifest") +filegroup(name = "license", srcs = [":publish_files"], output_group = "license") +filegroup(name = "notices", srcs = [":publish_files"], output_group = "notices") + +query_envelope( + name = "npm", + format = "npm", + manifest = ":publish_manifest", + entries = { + ":module": "lib/", + ":publish_manifest": "package.json", + ":license": "LICENSE", + ":notices": "THIRD_PARTY_NOTICES.md", + "README.md": "README.md", + "//src/wasix/postgres-tools:CHANGELOG.md": "CHANGELOG.md", + }, + out = "oliphaunt-wasix-tools.tgz", +) + +shipping_package( + name = "shipping_package", + suppliers = "//build_defs/release:no_suppliers", + owner = "@oliphaunt_metadata//:product_postgres-tools-wasix", + artifacts = [":npm"], + ecosystem = "npm", + package_name = SDK["name"], + configuration = "portable", + role = [carrier["role"] for carrier in PUBLICATION_CARRIERS if carrier["product"] == "postgres-tools-wasix" and carrier["ecosystem"] == "npm" and carrier["name"] == SDK["name"]][0], +) + +shipping_export(name = "shipping_export", packages = [":shipping_package"], qualification = [":installed_consumer_test"], testonly = True) + +INSTALLED_TYPES = {"@types/node": SDK["types"]["@types/node"]} + +installed_npm_consumer_test( + name = "installed_consumer_test", + archives = { + ":npm": SDK["name"], + "//src/wasix/postgres-tools:portable_npm": "@oliphaunt/liboliphaunt-wasix-tools", + "//src/wasix/postgres-tools:linux_x64_gnu_npm": "@oliphaunt/liboliphaunt-wasix-tools-linux-x64-gnu", + }, + packages = {"@javascript_installed_packages//:" + key: key for key in INSTALLED_PACKAGES} | {"@javascript_packages//:" + key: key for key in npm_dependency_closure(TYPE_PACKAGES, INSTALLED_TYPES.values())}, + roots = CONSUMER_TOOLS["oliphaunt-wasix-tools-installed-consumer"] | INSTALLED_TYPES, + acquisitions = ["@javascript_installed_packages//:acquisition.json", "@javascript_packages//:acquisition.json"], + runner = "tools/installed-consumer.mts", + consumer = "//src/wasix/postgres-tools/ts/tests/installed:consumer.mts", + helpers = [ + "tests/direct-pg-dump-smoke.ts", + "src/index.ts", + "tsconfig.json", + "tsconfig.build.json", + "package.json", + "tools/wasix-tools-typescript-package.mts", + "tools/package.mts", + "//build_defs/wasix/browser:npm-archives.mts", + "//:tools/packaging/npm-trusted-publishing.mts", + "//:tools/packaging/portable-archive.mts", + "//:tools/packaging/release-notices.mts", + "//:tools/packaging/release-directory-safety.mts", + "//:LICENSE", + "//:THIRD_PARTY_NOTICES.md", + ], + size = "medium", + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) + +source_quality_files(exclude = [_MODULE_OUT_DIR + "/**"]) diff --git a/src/wasix/postgres-tools/ts/tests/installed/BUILD.bazel b/src/wasix/postgres-tools/ts/tests/installed/BUILD.bazel new file mode 100644 index 000000000..033102e3d --- /dev/null +++ b/src/wasix/postgres-tools/ts/tests/installed/BUILD.bazel @@ -0,0 +1,4 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +exports_files(["package.json", "bun.lock", "consumer.mts"], visibility = ["//visibility:public"]) + +source_quality_files() diff --git a/src/wasix/postgres-tools/ts/tests/installed/bun.lock b/src/wasix/postgres-tools/ts/tests/installed/bun.lock new file mode 100644 index 000000000..84a20cde7 --- /dev/null +++ b/src/wasix/postgres-tools/ts/tests/installed/bun.lock @@ -0,0 +1,37 @@ +{ + "lockfileVersion": 2, + "configVersion": 1, + "workspaces": { + "": { + "name": "oliphaunt-wasix-tools-installed-consumer", + "devDependencies": { + "@oliphaunt/wasix-ts": "0.2.2", + "@types/node": "24.12.4", + "typescript": "6.0.3", + }, + }, + }, + "packages": { + "@oliphaunt/liboliphaunt-wasix": ["@oliphaunt/liboliphaunt-wasix@0.3.2", "", {}, "sha512-MJ/MbFuYcR7UhnlpMtO1gFsBvKrszasD5nZT1WpvlJiaNKbNvN3pHbNyZ7UyO5e21Lb3bHBKci7BqPsOfVkU9g=="], + + "@oliphaunt/ts-query": ["@oliphaunt/ts-query@0.1.1", "", {}, "sha512-QV9Sv0S80qyCfJpgtGd6167nA3rvNdJ1gyFYb+ro11jZlElRALVwMntSdBeiggHK12BXg6BvPuIVora0OC62QQ=="], + + "@oliphaunt/wasix-napi-darwin-arm64": ["@oliphaunt/wasix-napi-darwin-arm64@0.2.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-kOuWdl6f53/uMDltjTm2nIcLOj9dgDLLKvSR8ZNsaa4ysQ1a8UlV1rLFpGyBF9ySDZCyitGFm4b/3XTwrmm7qA=="], + + "@oliphaunt/wasix-napi-linux-arm64-gnu": ["@oliphaunt/wasix-napi-linux-arm64-gnu@0.2.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-GZ9W7/xtdPoEJpSsA42XOFsUhzQhyrB8dhXuaLPIOkAdRrr8lPxpnOjJSfqy2Jnl6dB0dxsFs0qIX+0Gg8Q6CA=="], + + "@oliphaunt/wasix-napi-linux-x64-gnu": ["@oliphaunt/wasix-napi-linux-x64-gnu@0.2.1", "", { "os": "linux", "cpu": "x64" }, "sha512-EO3rHfriV/PtTW+CoG+RXjUF4Rbv06IVTnsjz8n/s3YKz9Yu7nKWptEKvqShbRONshuuOnhkecYzjl8C4okJTw=="], + + "@oliphaunt/wasix-napi-win32-x64-msvc": ["@oliphaunt/wasix-napi-win32-x64-msvc@0.2.1", "", { "os": "win32", "cpu": "x64" }, "sha512-WUo9A/EeOsisMgplvAutc41BfVLwFcC+U7kHo9/3wT0pqEunSackH/yavcNsJ8efYl7g0hqZiKt67gH+AYfwHg=="], + + "@oliphaunt/wasix-ts": ["@oliphaunt/wasix-ts@0.2.2", "", { "dependencies": { "@oliphaunt/liboliphaunt-wasix": "0.3.2", "@oliphaunt/ts-query": "0.1.1", "fzstd": "0.1.1" }, "optionalDependencies": { "@oliphaunt/wasix-napi-darwin-arm64": "0.2.1", "@oliphaunt/wasix-napi-linux-arm64-gnu": "0.2.1", "@oliphaunt/wasix-napi-linux-x64-gnu": "0.2.1", "@oliphaunt/wasix-napi-win32-x64-msvc": "0.2.1" } }, "sha512-zgu2jbaIpIY3S3OvbdX4JpJfwCfS2GBynR0RCAXwgxD6VPKhlsi9AAC6LNAT05923OI4RL5QiCGYctcUgUwbDQ=="], + + "@types/node": ["@types/node@24.12.4", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA=="], + + "fzstd": ["fzstd@0.1.1", "", {}, "sha512-dkuVSOKKwh3eas5VkJy1AW1vFpet8TA/fGmVA5krThl8YcOVE/8ZIoEA1+U1vEn5ckxxhLirSdY837azmbaNHA=="], + + "typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], + + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + } +} diff --git a/src/wasix/postgres-tools/ts/tests/installed/consumer.mts b/src/wasix/postgres-tools/ts/tests/installed/consumer.mts new file mode 100644 index 000000000..0ed789985 --- /dev/null +++ b/src/wasix/postgres-tools/ts/tests/installed/consumer.mts @@ -0,0 +1,14 @@ +import assert from 'node:assert/strict'; +import { PostgresToolError, psql } from '@oliphaunt/wasix-tools'; +import Oliphaunt from '@oliphaunt/wasix-ts'; +import { expectDirectPgDump } from '../direct-pg-dump-smoke.ts'; + +assert.equal(new PostgresToolError('psql', 'installed probe').tool, 'psql'); +const database = await Oliphaunt.open(); +try { + await expectDirectPgDump(database); + assert.match(await psql(database, { command: 'SELECT 42 AS answer' }), /42/u); + assert.equal((await database.queryRaw('SELECT 43 AS answer')).getText(0, 'answer'), '43'); +} finally { + await database.close(); +} diff --git a/src/wasix/postgres-tools/ts/tests/installed/package.json b/src/wasix/postgres-tools/ts/tests/installed/package.json new file mode 100644 index 000000000..6229f5e00 --- /dev/null +++ b/src/wasix/postgres-tools/ts/tests/installed/package.json @@ -0,0 +1,10 @@ +{ + "name": "oliphaunt-wasix-tools-installed-consumer", + "private": true, + "type": "module", + "devDependencies": { + "@oliphaunt/wasix-ts": "0.2.2", + "@types/node": "24.12.4", + "typescript": "6.0.3" + } +} diff --git a/src/wasix/postgres-tools/ts/tools/installed-consumer.mts b/src/wasix/postgres-tools/ts/tools/installed-consumer.mts new file mode 100644 index 000000000..b5f95dc3f --- /dev/null +++ b/src/wasix/postgres-tools/ts/tools/installed-consumer.mts @@ -0,0 +1,205 @@ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { + copyFile, + lstat, + mkdir, + readdir, + readFile, + realpath, + symlink, + writeFile, +} from 'node:fs/promises'; +import { createRequire } from 'node:module'; +import { dirname, join } from 'node:path'; +import { extractNpmPackage } from '../../../../../build_defs/wasix/browser/npm-archives.mts'; +import { assertWasixToolsTypescriptNpmArchive } from './wasix-tools-typescript-package.mts'; + +const [specificationFile, node, compiler] = Bun.argv.slice(2); +assert(specificationFile && node && compiler); +assert(process.env.TEST_TMPDIR && process.env.OLIPHAUNT_BAZEL_RUNFILES); +const root = join(process.env.TEST_TMPDIR, 'wasix-tools-installed'); +const runfiles = process.env.OLIPHAUNT_BAZEL_RUNFILES; +const specification = JSON.parse(await readFile(specificationFile, 'utf8')); +const acquisition: Record< + string, + { package: string; version: string; integrity: string; dependencies: Record } +> = {}; +for (const file of specification.acquisitions) { + for (const [id, row] of Object.entries( + JSON.parse(await readFile(join(runfiles, file), 'utf8')), + )) { + if (acquisition[id]) assert.deepEqual(acquisition[id], row); + else acquisition[id] = row as (typeof acquisition)[string]; + } +} +const receipt: Record = {}; +const stores: Record = {}; +for (const [id, input] of Object.entries(specification.packages) as [string, string][]) { + const row = acquisition[id]; + assert(row, `undeclared installed package ${id}`); + assert.match(row.integrity, /^sha512-[A-Za-z0-9+/]+=*$/u); + const destination = join(root, '.packages', id, 'node_modules', row.package); + const source = await realpath(join(runfiles, input)); + await extractNpmPackage(source, destination, { allowIdenticalAliases: true }); + const manifest = JSON.parse(await readFile(join(destination, 'package.json'), 'utf8')); + assert.equal(manifest.name, row.package); + assert.equal(manifest.version, row.version); + receipt[`${row.package}@${row.version}`] = await verifyBytes(source, destination); + stores[id] = destination; +} +for (const [id, directory] of Object.entries(stores)) { + for (const [name, target] of Object.entries(acquisition[id].dependencies)) { + assert(stores[target], `missing declared installed dependency ${name}`); + const destination = join(directory, 'node_modules', name); + await mkdir(dirname(destination), { recursive: true }); + await symlink(stores[target], destination, 'dir'); + } +} +for (const [name, id] of Object.entries(specification.roots) as [string, string][]) { + assert(stores[id], `missing declared installed root ${name}`); + const destination = join(root, 'node_modules', name); + await mkdir(dirname(destination), { recursive: true }); + await symlink(stores[id], destination, 'dir'); +} +const archives: Record = {}; +for (const [name, input] of Object.entries(specification.archives) as [string, string][]) { + assert(!Object.hasOwn(specification.roots, name), `candidate replaces public fixture ${name}`); + const source = await realpath(join(runfiles, input)); + archives[name] = source; + const destination = join(root, 'node_modules', name); + await extractNpmPackage(source, destination); + const manifest = JSON.parse(await readFile(join(destination, 'package.json'), 'utf8')); + assert.equal(manifest.name, name); + receipt[`${name}@${manifest.version}`] = await verifyBytes(source, destination); +} +const tools = '@oliphaunt/wasix-tools'; +const carrier = '@oliphaunt/liboliphaunt-wasix-tools'; +const aot = `${carrier}-linux-x64-gnu`; +const manifest = assertWasixToolsTypescriptNpmArchive(archives[tools]); +const sdk = acquisition[specification.roots['@oliphaunt/wasix-ts']]; +assert.equal(sdk.version, manifest.peerDependencies['@oliphaunt/wasix-ts']); +const runtime = Object.values(acquisition).find( + (row) => row.package === '@oliphaunt/liboliphaunt-wasix', +); +assert(runtime); +assert.equal(runtime.version, manifest.oliphaunt.runtimeVersion); +const facadeRequire = createRequire(join(root, 'node_modules', tools, 'lib/index.js')); +assert.equal(facadeRequire.resolve(carrier), join(root, 'node_modules', carrier, 'native.js')); +assert.equal( + facadeRequire.resolve('@oliphaunt/wasix-ts/internal/tools'), + join(stores[specification.roots['@oliphaunt/wasix-ts']], 'lib/internal.node.js'), +); +assert.equal( + JSON.parse(await readFile(join(root, 'node_modules', carrier, 'package.json'), 'utf8')).version, + manifest.version, +); +const carrierRequire = createRequire(facadeRequire.resolve(carrier)); +assert.equal( + carrierRequire.resolve(`${aot}/package.json`), + join(root, 'node_modules', aot, 'package.json'), +); +assert.equal( + JSON.parse(await readFile(carrierRequire.resolve(`${aot}/package.json`), 'utf8')).version, + manifest.version, +); + +await writeFile(join(root, 'package.json'), '{"private":true,"type":"module"}\n'); +const consumer = join(root, 'tests/installed/consumer.mts'); +await mkdir(dirname(consumer), { recursive: true }); +await copyFile(join(runfiles, specification.consumer), consumer); +const helper = specification.helpers.find((path: string) => + path.endsWith('/tests/direct-pg-dump-smoke.ts'), +); +assert(helper); +await copyFile(join(runfiles, helper), join(root, 'tests/direct-pg-dump-smoke.ts')); + +const source = join(root, 'source/ts'); +for (const name of ['package.json', 'tsconfig.json', 'tsconfig.build.json', 'src/index.ts']) { + const input = specification.helpers.find((path: string) => + path.endsWith(`/src/wasix/postgres-tools/ts/${name}`), + ); + assert(input); + const destination = join(source, name); + await mkdir(dirname(destination), { recursive: true }); + await copyFile(join(runfiles, input), destination); +} +await mkdir(join(root, 'source/npm'), { recursive: true }); +for (const name of ['package.json', 'index.d.ts']) + await copyFile(join(root, 'node_modules', carrier, name), join(root, 'source/npm', name)); +const environment = { ...process.env, PATH: '', NODE_PATH: '', NODE_OPTIONS: '' }; +function run(arguments_: string[], label: string) { + const result = spawnSync(node, arguments_, { + cwd: root, + env: environment, + timeout: 60_000, + stdio: 'inherit', + }); + assert.equal(result.status, 0, label); +} +run( + [join(compiler, 'bin/tsc'), '-p', join(source, 'tsconfig.build.json')], + 'source facade must compile against the public held SDK', +); +run( + [ + join(compiler, 'bin/tsc'), + '--module', + 'NodeNext', + '--moduleResolution', + 'NodeNext', + '--target', + 'ES2022', + '--lib', + 'ES2023,DOM', + '--types', + 'node', + '--strict', + '--skipLibCheck', + '--allowImportingTsExtensions', + '--noEmit', + consumer, + ], + 'installed tools public types must compile against the public held SDK', +); +run([consumer], 'actual installed tools pg_dump/psql consumer failed'); +await writeFile(join(root, 'inputs.json'), `${JSON.stringify(receipt, null, 2)}\n`); +console.log(`installed WASIX tools with public SDK ${sdk.version}: PASS`, receipt); + +async function verifyBytes(source: string, destination: string): Promise { + const hash = createHash('sha256'); + if (source.endsWith('.tgz')) { + const bytes = await readFile(source); + hash.update(bytes); + for (const [name, content] of await new Bun.Archive(bytes).files()) { + const relative = name + .split('/') + .slice(1) + .filter((part) => part !== '.') + .join('/'); + assert.deepEqual( + await readFile(join(destination, relative)), + Buffer.from(await content.bytes()), + ); + } + } else { + await visit(source, ''); + } + return hash.digest('hex'); + async function visit(directory: string, prefix: string) { + for (const name of (await readdir(directory)).sort()) { + const input = join(directory, name); + const relative = prefix ? `${prefix}/${name}` : name; + const stat = await lstat(input); + if (stat.isDirectory()) await visit(input, relative); + else { + assert(stat.isFile(), `nonregular installed input ${input}`); + const bytes = await readFile(input); + assert.deepEqual(await readFile(join(destination, relative)), bytes); + hash.update(`${relative}\0${bytes.length}\0`); + hash.update(bytes); + } + } + } +} diff --git a/src/wasix/postmaster/BUILD.bazel b/src/wasix/postmaster/BUILD.bazel new file mode 100644 index 000000000..8e35e1304 --- /dev/null +++ b/src/wasix/postmaster/BUILD.bazel @@ -0,0 +1,93 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files", "source_quality_files") +load("//build_defs/wasix/postmaster:rust.bzl", "postmaster_rust_targets") +load("//build_defs/wasix/postmaster:release-asset.bzl", "postmaster_linux_release_asset", "postmaster_release_family") +load("//build_defs/wasix/postmaster:host-carrier.bzl", "postmaster_imported_host_carrier") +load("//build_defs/wasix/postmaster:sealing.bzl", "postmaster_sealed_profile_test") +load("//build_defs/wasix/postmaster:runtime-test.bzl", "postmaster_runtime_test") + +package(default_visibility = ["//visibility:public"]) + +exports_files([ + "README.md", + "bin/run-release-carrier.sh", + "release.toml", + "executor/Cargo.toml", + "executor/Cargo.lock", + "executor/src/sealed.rs", + "executor/src/runtime.rs", + "sources/wasmer.toml", + "sources/wasmer-napi.toml", + "sources/wasix-libc.toml", + "wasmer/patches/wasmer/0001-postgres-wasix-blockers.patch", + "wasmer/patches/wasix-libc/0001-postgres-wasix-blockers.patch", + "lib/common.sh", +] + glob(["postgres/**", "wasmer/policies/*", "wasmer/probes/*.c", "lib/*.mts", "wasmer/bin/*.mts"])) + +filegroup( + name = "executor_sources", + srcs = glob(["executor/src/**/*.rs"]), +) + +filegroup(name = "postgres_overlays", srcs = glob(["postgres/overlays/wasix-core/src/**"])) + +postmaster_rust_targets( + library_sources = glob(["executor/src/**/*.rs"], exclude = ["executor/src/bin/**/*.rs"]), +) + +postmaster_linux_release_asset(qualification = [":linux_sealed_profile_test", ":linux_runtime_test"]) +postmaster_release_family() + +# These are the sole actual test instances. The original source-repository +# labels remain aliases, so old callers run the same behavior once. +postmaster_sealed_profile_test( + name = "linux_sealed_profile_test", + main = "@postmaster_postgres//:postgres_seed", + sealed = "@postmaster_postgres//:sealed_modules", + target_compatible_with = ["@platforms//cpu:wasm32", "@platforms//os:wasi"], + tags = ["manual"], + size = "small", +) + +postmaster_runtime_test( + name = "linux_runtime_test", + carrier = "@postmaster_postgres//:native_carrier", + target_compatible_with = ["@platforms//cpu:wasm32", "@platforms//os:wasi"], + exec_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64", "@zig_sdk//libc:gnu.2.34"], + tags = ["manual"], + size = "medium", + timeout = "long", +) + +# Exercise the imported writer path against an actual Linux public archive. +# Existing AOT may be reused only because the writer verifies every imported +# module's digest against that AOT's declared receipt. +postmaster_imported_host_carrier( + name = "linux_imported", + target = "linux-x64-gnu", + archive = ":linux_x64_gnu_release_asset", + aot_modules = "@postmaster_postgres//:aot_modules", + aot_receipts = "@postmaster_postgres//:aot_receipts", + native_platform = "//build_defs/native:linux_x86_64_glibc_2_28", + execution = ["@platforms//os:linux", "@platforms//cpu:x86_64", "@zig_sdk//libc:gnu.2.34"], +) + +# LLVM22 is an internal host compiler input. The executor and native client +# retain the public Linux glibc floor through their explicit transition. +platform(name = "compiler_linux_arm64", constraint_values = ["@platforms//os:linux", "@platforms//cpu:aarch64", "@zig_sdk//libc:gnu.2.34"]) +platform(name = "native_macos_arm64", constraint_values = ["@platforms//os:macos", "@platforms//cpu:aarch64"]) + +postmaster_imported_host_carrier( + target = "linux-arm64-gnu", + native_platform = "//build_defs/native:linux_aarch64_glibc_2_28", + execution = ["@platforms//os:linux", "@platforms//cpu:aarch64", "@zig_sdk//libc:gnu.2.34"], +) + +postmaster_imported_host_carrier( + target = "macos-arm64", + native_platform = ":native_macos_arm64", + execution = ["@platforms//os:macos", "@platforms//cpu:aarch64"], +) + +source_quality_files() + +rust_quality_files() diff --git a/src/wasix/postmaster/lib/build-sealed-carrier.mts b/src/wasix/postmaster/lib/build-sealed-carrier.mts index f8bc91e53..2254e5008 100644 --- a/src/wasix/postmaster/lib/build-sealed-carrier.mts +++ b/src/wasix/postmaster/lib/build-sealed-carrier.mts @@ -1,26 +1,26 @@ #!/usr/bin/env bun import assert from 'node:assert/strict'; import { - fchmodSync, - openSync, closeSync, - fsyncSync, + constants, + fchmodSync, fstatSync, + fsyncSync, + openSync, writeFileSync, - constants, } from 'node:fs'; -import { member } from './receipt-files.mts'; -import { dirname, basename } from 'node:path'; +import { basename, dirname } from 'node:path'; import { profile, profileId } from './linear-memory-profile.mts'; -import { readRegular, parseJson, requireSha } from './sealed-export-chain.mts'; +import { member } from './receipt-files.mts'; +import { parseJson, readRegular, requireSha } from './sealed-export-chain.mts'; import { - guestReceipt, - sourceFingerprint, carrierTree, + guestReceipt, hashRegular, + sourceFingerprint, } from './verify-sealed-carrier.mts'; -function manifest(args: string[]) { +export function manifest(args: string[]) { assert.equal(args.length, 22, 'manifest requires exact builder inputs'); const [ rows, diff --git a/src/wasix/postmaster/lib/linear-memory-profile.mts b/src/wasix/postmaster/lib/linear-memory-profile.mts index 19ff0e0f6..322703b98 100644 --- a/src/wasix/postmaster/lib/linear-memory-profile.mts +++ b/src/wasix/postmaster/lib/linear-memory-profile.mts @@ -48,14 +48,14 @@ export function closureHash(records: Record[], field: string) { return digest.digest('hex'); } -function aggregate( +export function aggregate( stage: string, index: string, predecessor: string, predecessorHash: string, destination: string, + observed = parseStrictJson(process.env.PROFILE_JSON ?? '') as Record, ) { - const observed = parseStrictJson(process.env.PROFILE_JSON ?? '') as Record; assert.equal(observed.id, profileId, 'memory profile ID differs'); for (const [key, expected] of Object.entries(profile)) assert.equal(observed[key], expected, `memory profile differs: ${key}`); diff --git a/src/wasix/postmaster/lib/verify-sealed-carrier.mts b/src/wasix/postmaster/lib/verify-sealed-carrier.mts index 2b8dad39c..8d0361dfe 100644 --- a/src/wasix/postmaster/lib/verify-sealed-carrier.mts +++ b/src/wasix/postmaster/lib/verify-sealed-carrier.mts @@ -1,26 +1,33 @@ #!/usr/bin/env bun import assert from 'node:assert/strict'; import { createHash } from 'node:crypto'; -import { type Stats, lstatSync, readdirSync } from 'node:fs'; -import { join, basename, posix, resolve } from 'node:path'; -import { member, safeRelative, stableRead, AGGREGATE_RELATIVE } from './receipt-files.mts'; -import { profileId, profile } from './linear-memory-profile.mts'; +import { lstatSync, readdirSync, type Stats } from 'node:fs'; +import { createRequire } from 'node:module'; +import { basename, join, posix, resolve } from 'node:path'; +import { verifyReceipt } from '../wasmer/bin/verify-postmaster-concurrency-contract.mts'; +import { + installedClosureIdentityFromRecords, + requiredModules, + sideModulePolicy, +} from './guest-build-provenance.mts'; +import { profile, profileId } from './linear-memory-profile.mts'; +import { AGGREGATE_RELATIVE, member, safeRelative, stableRead } from './receipt-files.mts'; import { - type Inventory, exactKeys, - requireSha, + type Inventory, + linearMemorySourceHashes, parseJson, readRegular, - linearMemorySourceHashes, + requireSha, validateExportChain, } from './sealed-export-chain.mts'; -import { - sideModulePolicy, - requiredModules, - installedClosureIdentityFromRecords, -} from './guest-build-provenance.mts'; -import { verifyReceipt } from '../wasmer/bin/verify-postmaster-concurrency-contract.mts'; + const names = (value: string) => value.trim().split(/\s+/); +// Historical text receipts retain their original runtime dependency closure. +const nativeReceipts = () => + createRequire(import.meta.url)( + '../../../../build_defs/wasix/postmaster/native-receipts.mts', + ) as typeof import('../../../../build_defs/wasix/postmaster/native-receipts.mts'); const TOP_LEVEL_MANIFEST_KEYS = names( `format-version schema source-lane source-fingerprint core-profile guest-build-recipe-sha256 postgres-version target-triple host-abi engine compiler-config cpu-policy cpu-features wasmer-version wasmer-wasix-version wasmer-source-commit wasmer-patch-sha256 wasmer-cargo-lock-sha256 artifact-abi-version runtime-abi-id producer-recipe-sha256 executor-engine executor-sha256 executor-size linear-memory-profile wasm-features entrypoint artifacts`, ); @@ -93,9 +100,10 @@ export function parseReceipt( keys: string[], flags = false, ) { - const lines = text(readRegular(root, path, inventory)) - .slice(0, -1) - .split('\n'); + const contents = text(readRegular(root, path, inventory)); + if (path === 'wasmer-build.receipt' && contents.startsWith('{')) + return nativeReceipts().nativeWasmerReceipt(parseJson(Buffer.from(contents))); + const lines = contents.slice(0, -1).split('\n'); assert.equal(lines.length, keys.length, `${path} field count differs`); return Object.fromEntries( lines.map((line, index) => { @@ -115,6 +123,14 @@ export function executorReceipt( inventory: Inventory, wasmer: { [key: string]: string }, ) { + const contents = readRegular(root, 'postmaster-executor.receipt', inventory); + if (contents[0] === 123) + return nativeReceipts().nativeExecutorReceipt( + parseJson(contents), + wasmer, + identity(inventory, 'wasmer-build.receipt').sha256, + identity(inventory, 'bin/wasmer-headless'), + ); const receipt = parseReceipt( root, inventory, @@ -158,6 +174,8 @@ export function executorReceipt( return receipt; } export function guestReceipt(root: string, inventory?: Inventory) { + const contents = readRegular(root, 'guest-build.receipt', inventory); + if (contents[0] === 123) return nativeReceipts().nativeGuestReceipt(parseJson(contents)); const receipt = parseReceipt( root, inventory, @@ -337,6 +355,9 @@ export function verify( const wasmer = parseReceipt(root, inventory, 'wasmer-build.receipt', RECEIPT_KEYS); const executor = executorReceipt(root, inventory, wasmer), guest = guestReceipt(root, inventory); + const native = wasmer.schema === 'oliphaunt.wasix-postmaster.wasmer-build.native.v1'; + equal(executor.schema.endsWith('.native.v1'), native, 'executor receipt family'); + equal(guest.schema.endsWith('.native.v1'), native, 'guest receipt family'); equal( identity(inventory, concurrencyPath).sha256, guest.final_wasm_concurrency_receipt_sha256, diff --git a/src/wasix/postmaster/moon.yml b/src/wasix/postmaster/moon.yml index 34ee7db55..8826630b6 100644 --- a/src/wasix/postmaster/moon.yml +++ b/src/wasix/postmaster/moon.yml @@ -26,12 +26,6 @@ project: release: component: liboliphaunt-wasix-postmaster packagePath: src/wasix/postmaster - artifactTargets: - preset: liboliphaunt-wasix-postmaster - targets: - - linux-arm64-gnu - - linux-x64-gnu - - macos-arm64 owners: defaultOwner: "@oliphaunt/wasix" paths: diff --git a/src/wasix/postmaster/release.toml b/src/wasix/postmaster/release.toml index 1e8bd520a..1c7ea168d 100644 --- a/src/wasix/postmaster/release.toml +++ b/src/wasix/postmaster/release.toml @@ -4,3 +4,11 @@ kind = "wasm-runtime" publish_targets = ["github-release-assets"] registry_packages = [] release_artifacts = ["sealed-postmaster-carrier"] + +[artifact_targets] +preset = "liboliphaunt-wasix-postmaster" +targets = [ + "linux-arm64-gnu", + "linux-x64-gnu", + "macos-arm64", +] diff --git a/src/wasix/postmaster/tools/sealed-export-closure/BUILD.bazel b/src/wasix/postmaster/tools/sealed-export-closure/BUILD.bazel new file mode 100644 index 000000000..a62a6e97b --- /dev/null +++ b/src/wasix/postmaster/tools/sealed-export-closure/BUILD.bazel @@ -0,0 +1,32 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files") +load("@postmaster_sealing_crates//:defs.bzl", "aliases", "all_crate_deps", "crate_edition") +load("@rules_rust//cargo:defs.bzl", "cargo_toml_env_vars") +load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_test") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["Cargo.toml", "Cargo.lock"]) + +cargo_toml_env_vars(name = "cargo_env", src = "Cargo.toml") + +rust_binary( + name = "sealed_export_closure", + srcs = ["src/main.rs"], + crate_root = "src/main.rs", + crate_name = "oliphaunt_wasix_sealed_export_closure", + edition = crate_edition(), + deps = all_crate_deps(normal = True), + proc_macro_deps = all_crate_deps(proc_macro = True), + aliases = aliases(), + rustc_env_files = [":cargo_env"], + tags = ["manual"], +) + +rust_test( + name = "unit_test", + crate = ":sealed_export_closure", + tags = ["manual"], + size = "small", +) + +rust_quality_files() diff --git a/src/wasix/postmaster/wasmer/patches/wasix-libc/0001-postgres-wasix-blockers.patch b/src/wasix/postmaster/wasmer/patches/wasix-libc/0001-postgres-wasix-blockers.patch index bbf7ad23c..1ba83da9b 100644 --- a/src/wasix/postmaster/wasmer/patches/wasix-libc/0001-postgres-wasix-blockers.patch +++ b/src/wasix/postmaster/wasmer/patches/wasix-libc/0001-postgres-wasix-blockers.patch @@ -1265,9 +1265,9 @@ index ca43eb8..bb34cce 100644 + } + return 0; #endif ++} -} \ No newline at end of file -+} diff --git a/libc-top-half/musl/src/signal/sigaction.c b/libc-top-half/musl/src/signal/sigaction.c index d2ffaad..332feb2 100644 --- a/libc-top-half/musl/src/signal/sigaction.c @@ -1332,9 +1332,9 @@ index 577ecb5..4ceea6a 100644 + } +#endif longjmp(buf, ret); ++} -} \ No newline at end of file -+} diff --git a/libc-top-half/musl/src/signal/sigsetjmp_tail.c b/libc-top-half/musl/src/signal/sigsetjmp_tail.c index 57b00c5..f35da65 100644 --- a/libc-top-half/musl/src/signal/sigsetjmp_tail.c @@ -1351,8 +1351,6 @@ index 57b00c5..f35da65 100644 #else return EINVAL; #endif --} -\ No newline at end of file +} + +#if !defined(__wasilibc_unmodified_upstream) && defined(__wasm_exception_handling__) @@ -1368,6 +1366,8 @@ index 57b00c5..f35da65 100644 + return 0; +} +#endif +-} +\ No newline at end of file diff --git a/libc-top-half/musl/src/string/memcmp.c b/libc-top-half/musl/src/string/memcmp.c index bdbce9f..3fbc3c5 100644 --- a/libc-top-half/musl/src/string/memcmp.c diff --git a/src/wasix/postmaster/wasmer/patches/wasmer/0001-postgres-wasix-blockers.patch b/src/wasix/postmaster/wasmer/patches/wasmer/0001-postgres-wasix-blockers.patch index 0462a8b78..0c0d9b646 100644 --- a/src/wasix/postmaster/wasmer/patches/wasmer/0001-postgres-wasix-blockers.patch +++ b/src/wasix/postmaster/wasmer/patches/wasmer/0001-postgres-wasix-blockers.patch @@ -2479,10 +2479,10 @@ index 3297890..4cfac63 100644 .set_source(registry) .set_engine(engine); diff --git a/lib/compiler-llvm/src/compiler.rs b/lib/compiler-llvm/src/compiler.rs -index b04e437..3950012 100644 +index b04e437..2c66a6d 100644 --- a/lib/compiler-llvm/src/compiler.rs +++ b/lib/compiler-llvm/src/compiler.rs -@@ -178,13 +178,17 @@ impl Compiler for LLVMCompiler { +@@ -178,13 +178,17 @@ fn deterministic_id(&self) -> String { format!( @@ -2502,6 +2502,22 @@ index b04e437..3950012 100644 ) } +@@ -497,6 +501,15 @@ + let got_data: Vec = vec![0; got_targets.len() * got_entry_size]; + let mut got_relocs = vec![]; + ++ // Randomized set iteration must not become serialized GOT offsets. ++ let mut got_targets = got_targets.into_iter().collect::>(); ++ got_targets.sort_unstable_by_key(|target| match target { ++ RelocationTarget::LocalFunc(index) => (0_u8, index.as_u32()), ++ RelocationTarget::DynamicTrampoline(index) => (1, index.as_u32()), ++ RelocationTarget::LibCall(libcall) => (2, *libcall as u16 as u32), ++ RelocationTarget::CustomSection(index) => (3, index.as_u32()), ++ }); ++ + for (i, target) in got_targets.into_iter().enumerate() { + got_relocs.push(wasmer_compiler::types::relocation::Relocation { + kind: got_entry_reloc_kind, diff --git a/lib/compiler-llvm/src/config.rs b/lib/compiler-llvm/src/config.rs index d732134..58918f0 100644 --- a/lib/compiler-llvm/src/config.rs @@ -38126,3 +38142,26 @@ index 271bd12..6379ce0 100644 #[compiler_test(issues)] fn issue_5795_memory_reset_size(mut config: crate::Config) { let wasm_bytes = wat2wasm( +diff --git a/lib/compiler/src/engine/unwind/systemv.rs b/lib/compiler/src/engine/unwind/systemv.rs +index 11ef2ad9..7bd9a6e1 100644 +--- a/lib/compiler/src/engine/unwind/systemv.rs ++++ b/lib/compiler/src/engine/unwind/systemv.rs +@@ -65,6 +65,18 @@ fn using_libunwind() -> bool { + return true; + } + ++ // Native ELF toolchains can link LLVM libunwind with hidden symbols, ++ // making the existing dlsym probe miss the actual linked implementation. ++ #[cfg(all(target_os = "linux", oliphaunt_linked_libunwind))] ++ { ++ unsafe extern "C" { ++ fn oliphaunt_wasmer_has_linked_libunwind() -> libc::c_int; ++ } ++ if unsafe { oliphaunt_wasmer_has_linked_libunwind() } != 0 { ++ return true; ++ } ++ } ++ + // On other platforms the unwinder can vary. Sometimes the unwinder is + // selected at build time and sometimes it differs at build time and runtime + // (or at least I think that's possible). Fall back to a `libc::dlsym` to diff --git a/src/wasix/runtime/BUILD.bazel b/src/wasix/runtime/BUILD.bazel new file mode 100644 index 000000000..056754a2b --- /dev/null +++ b/src/wasix/runtime/BUILD.bazel @@ -0,0 +1,166 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files", "source_quality_files") +load("@rules_cc//cc:defs.bzl", "cc_library") +load("//build_defs/wasix:wasm.bzl", "wasix_export_policy", "wasix_module", "wasix_relocatable") +load("//build_defs/wasix:extensions.bzl", "wasix_contrib_modules", "wasix_external_c_modules") +load("//build_defs/wasix:aot.bzl", "wasix_runtime_aot_targets") +load("//build_defs/wasix:package.bzl", "postgres_patch_inputs", "wasix_runtime_payload") +load("//build_defs/wasix:platform.bzl", "wasix_artifact") +load("//build_defs/wasix:config.bzl", "WASIX_COPTS") +load("@postgres_wasix//:patches.bzl", "POSTGRES_PATCHES") +load("//build_defs/wasix:npm.bzl", "wasix_runtime_npm") +load("//build_defs/wasix:cargo.bzl", "wasix_runtime_cargo_exports") +load("//build_defs/wasix:runtime-release.bzl", "wasix_runtime_release_assets") +load("//build_defs/release:supplier.bzl", "shipping_suppliers") + +package(default_visibility = ["//visibility:public"]) + +exports_files([ + "toolchain.toml", + "release.toml", + "postgres/series", + "assets/build/docker/pinned-wasixcc-assets.tsv", + "tools/wasix-runtime-npm-payload.mts", + "tools/wasix-runtime-npm-contract.mts", + "tools/wasix-runtime-npm-descriptor.mts", + "tools/wasix-cargo-artifact-contract.mts", + "tools/package_liboliphaunt_wasix_cargo_artifacts.mts", + "tools/package-release-assets.mts", + "tools/check-release-assets.mts", + "tools/wasix-aot-manifest.mts", + "tools/wasix-cargo-toolchain-policy.mts", +] + glob(["assets/build/postgres/patches/*.patch", "assets/build/wasix_shim/*.c"])) + +cc_library( + name = "bridge", + linkstatic = True, + srcs = ["assets/build/wasix_shim/oliphaunt_wasix_bridge.c"], + deps = ["@postgres_wasix//:port_headers"], + copts = WASIX_COPTS + ["-include", "stdbool.h", "-include", "stdlib.h"], + target_compatible_with = ["@platforms//cpu:wasm32", "@platforms//os:wasi"], +) + +wasix_relocatable( + name = "postgres_core", + deps = ["@postgres_wasix//:backend"], + target_compatible_with = ["@platforms//cpu:wasm32", "@platforms//os:wasi"], +) + +wasix_module( + name = "plpgsql", + output_name = "plpgsql.so", + deps = ["@postgres_wasix//:plpgsql"], + target_compatible_with = ["@platforms//cpu:wasm32", "@platforms//os:wasi"], +) + +wasix_module( + name = "dict_snowball", + output_name = "dict_snowball.so", + deps = ["@postgres_wasix//:snowball"], + target_compatible_with = ["@platforms//cpu:wasm32", "@platforms//os:wasi"], +) + +_EXTENSION_MODULES = wasix_contrib_modules(crypto = "@openssl//:wasix_crypto") + wasix_external_c_modules() + [ + "//build_defs/wasix/dependencies:postgis", + "//build_defs/wasix/dependencies:postgis_dependency_module", +] + +# Every policy symbol comes from the admitted compiled side-module closure. +wasix_export_policy( + name = "export_policy", + modules = [":plpgsql", ":dict_snowball"] + _EXTENSION_MODULES, + target_compatible_with = ["@platforms//cpu:wasm32", "@platforms//os:wasi"], +) + +wasix_module( + name = "postgres", + output_name = "postgres.wasm", + srcs = [":postgres_core"], + deps = ["@postgres_wasix//:main", ":bridge", "@icu_wasix//:i18n"], + export_policy = ":export_policy", + target_compatible_with = ["@platforms//cpu:wasm32", "@platforms//os:wasi"], +) + +cc_library( + name = "initdb_shim", + linkstatic = True, + srcs = ["assets/build/wasix_shim/oliphaunt_wasix_initdb_shim.c"], + deps = ["@postgres_wasix//:frontend_headers"], + copts = WASIX_COPTS, + target_compatible_with = ["@platforms//cpu:wasm32", "@platforms//os:wasi"], +) + +wasix_module( + name = "initdb", + output_name = "initdb.wasm", + kind = "command", + deps = ["@postgres_wasix//:initdb_objects", ":initdb_shim", "@icu_wasix//:i18n"], + linkopts = ["--wrap=system", "--wrap=popen", "--wrap=pclose"], + target_compatible_with = ["@platforms//cpu:wasm32", "@platforms//os:wasi"], +) + +wasix_module( + name = "pg_dump", + output_name = "pg_dump.wasm", + kind = "command", + deps = ["@postgres_wasix//:pg_dump_objects", "@icu_wasix//:i18n_tools"], + target_compatible_with = ["@platforms//cpu:wasm32", "@platforms//os:wasi"], +) + +wasix_module( + name = "psql", + output_name = "psql.wasm", + kind = "command", + deps = ["@postgres_wasix//:psql_objects", "@icu_wasix//:i18n_tools"], + target_compatible_with = ["@platforms//cpu:wasm32", "@platforms//os:wasi"], +) + +wasix_runtime_payload( + name = "portable_payload_files", + runtime = ":postgres", + initdb = ":initdb", + export_policy = ":export_policy", + support = {":plpgsql": "plpgsql", ":dict_snowball": "dict_snowball"}, + resources = { + "@postgres_wasix//:catalog_runtime_data": "share/postgresql/", + "@postgres_wasix//:builtin_extension_data": "share/postgresql/extension/", + "@postgres_wasix//:tsearch_dictionaries": "share/postgresql/tsearch_data/", + "@postgres_wasix//:stopwords": "share/postgresql/tsearch_data/", + "@postgres_wasix//:wasix_timezone_abbreviations": "share/postgresql/timezonesets/", + "@postgres_wasix//:timezone_data": "share/postgresql/timezone", + }, + patches = postgres_patch_inputs(POSTGRES_PATCHES), + target_compatible_with = ["@platforms//cpu:wasm32", "@platforms//os:wasi"], +) + +wasix_artifact( + name = "portable_payload", + artifact = ":portable_payload_files", +) + +wasix_runtime_aot_targets() + +shipping_suppliers(name = "runtime_public_suppliers", inputs = []) + +wasix_runtime_npm() + +wasix_runtime_cargo_exports() + +wasix_runtime_release_assets( + patches = postgres_patch_inputs(POSTGRES_PATCHES), + generated = { + "//:src/extensions/generated/extensions.catalog.json": "src/extensions/generated/extensions.catalog.json", + "//:src/extensions/generated/contrib-build.tsv": "src/extensions/generated/contrib-build.tsv", + "//:src/extensions/generated/pgxs-build.tsv": "src/extensions/generated/pgxs-build.tsv", + "//:src/extensions/generated/wasix/extensions.json": "src/extensions/generated/wasix/extensions.json", + "//:src/extensions/generated/mobile/static-extensions.tsv": "src/extensions/generated/mobile/static-extensions.tsv", + "//:src/extensions/generated/mobile/static-registry.json": "src/extensions/generated/mobile/static-registry.json", + "//:src/extensions/generated/docs/extension-evidence.json": "src/extensions/generated/docs/extension-evidence.json", + "//src/extensions/generated/sdk:metadata": "src/extensions/generated/sdk/extensions.json", + "//src/extensions/generated/sdk:ios-static-dependencies.json": "src/extensions/generated/sdk/ios-static-dependencies.json", + }, + qualification = ["//build_defs/extensions/wasix:contrib_installed_test"], +) + +source_quality_files() + +rust_quality_files() diff --git a/src/wasix/runtime/assets/build/postgres/patches/0027-oliphaunt-wasix-avoid-xlog-size-checkpoint-requests.patch b/src/wasix/runtime/assets/build/postgres/patches/0027-oliphaunt-wasix-avoid-xlog-size-checkpoint-requests.patch index f3fae3b20..e8b28d218 100644 --- a/src/wasix/runtime/assets/build/postgres/patches/0027-oliphaunt-wasix-avoid-xlog-size-checkpoint-requests.patch +++ b/src/wasix/runtime/assets/build/postgres/patches/0027-oliphaunt-wasix-avoid-xlog-size-checkpoint-requests.patch @@ -16,10 +16,11 @@ policy without recursive checkpoints or an absent background process. 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c +index 47c04f2..6b4a99e 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c -@@ -164,6 +164,10 @@ static WalLevel wal_level = WAL_LEVEL_MINIMAL; - /* See check_wal_consistency_checking */ +@@ -166,6 +166,10 @@ static double PrevCheckPointDistance = 0; + */ static bool check_wal_consistency_checking_deferred = false; +#ifdef OLIPHAUNT_WASM_SINGLE_USER @@ -27,9 +28,9 @@ diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog +#endif + /* - * During recovery, we keep a copy of the latest checkpoint record here. - * lastCheckPointRecPtr points to start of checkpoint record and -@@ -2300,6 +2304,17 @@ XLogCheckpointNeeded(XLogSegNo new_segno) + * GUC support + */ +@@ -2288,6 +2292,17 @@ XLogCheckpointNeeded(XLogSegNo new_segno) return false; } @@ -47,7 +48,7 @@ diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog /* * Write and/or fsync the log at least as far as WriteRqst indicates. * -@@ -2501,15 +2516,24 @@ XLogWrite(XLogwrtRqst WriteRqst, TimeLineID tli, bool flexible) +@@ -2496,12 +2511,21 @@ XLogWrite(XLogwrtRqst WriteRqst, TimeLineID tli, bool flexible) * like a checkpoint is needed, forcibly update RedoRecPtr and * recheck. */ @@ -69,10 +70,8 @@ diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog } } - if (ispartialpage) - { - /* Only asked to write a partial page */ diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c +index 3914ac8..61145a7 100644 --- a/src/backend/postmaster/checkpointer.c +++ b/src/backend/postmaster/checkpointer.c @@ -1009,7 +1009,9 @@ RequestCheckpoint(int flags) @@ -86,9 +85,10 @@ diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/chec /* * There's no point in doing slow checkpoints in a standalone backend, diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c +index a9fbb15..e56daa9 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c -@@ -31,6 +31,9 @@ +@@ -37,6 +37,9 @@ #include "access/parallel.h" #include "access/printtup.h" #include "access/xact.h" @@ -98,7 +98,7 @@ diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c #include "catalog/pg_type.h" #include "commands/async.h" #include "commands/event_trigger.h" -@@ -4470,6 +4473,9 @@ PostgresSendReadyForQueryIfNecessary(void) +@@ -4374,6 +4377,9 @@ PostgresSendReadyForQueryIfNecessary(void) else { long stats_timeout; @@ -109,10 +109,10 @@ diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c /* * Process incoming notifies (including self-notifies), if diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h +index f20f5ed..b588eae 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h -@@ -242,7 +242,11 @@ extern void LocalProcessControlFile(bool reset); - extern WalLevel GetActiveWalLevelOnStandby(void); +@@ -244,6 +244,10 @@ extern WalLevel GetActiveWalLevelOnStandby(void); extern void StartupXLOG(void); extern void ShutdownXLOG(int code, Datum arg); extern bool CreateCheckPoint(int flags); diff --git a/src/wasix/runtime/assets/build/postgres/patches/0032-oliphaunt-wasix-treat-directory-fsync-eisdir-as-unsupported.patch b/src/wasix/runtime/assets/build/postgres/patches/0032-oliphaunt-wasix-treat-directory-fsync-eisdir-as-unsupported.patch index 9dad7d950..656d298fe 100644 --- a/src/wasix/runtime/assets/build/postgres/patches/0032-oliphaunt-wasix-treat-directory-fsync-eisdir-as-unsupported.patch +++ b/src/wasix/runtime/assets/build/postgres/patches/0032-oliphaunt-wasix-treat-directory-fsync-eisdir-as-unsupported.patch @@ -16,14 +16,30 @@ preserving fatal error handling for regular files and non-directory errors. 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c +index 378c078..48453fe 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c -@@ -3845,1 +3845,1 @@ fsync_fname_ext(const char *fname, bool isdir, bool ignore_perm, int elevel) +@@ -3902,7 +3902,7 @@ fsync_fname_ext(const char *fname, bool isdir, bool ignore_perm, int elevel) + * Some OSes don't allow us to fsync directories at all, so we can ignore + * those errors. Anything else needs to be logged. + */ - if (returncode != 0 && !(isdir && (errno == EBADF || errno == EINVAL))) + if (returncode != 0 && !(isdir && (errno == EBADF || errno == EINVAL || errno == EISDIR))) + { + int save_errno; + diff --git a/src/common/file_utils.c b/src/common/file_utils.c +index 7b62687..dc474fb 100644 --- a/src/common/file_utils.c +++ b/src/common/file_utils.c -@@ -416,1 +416,1 @@ fsync_fname(const char *fname, bool isdir) +@@ -435,7 +435,7 @@ fsync_fname(const char *fname, bool isdir) + * Some OSes don't allow us to fsync directories at all, so we can ignore + * those errors. Anything else needs to be reported. + */ - if (returncode != 0 && !(isdir && (errno == EBADF || errno == EINVAL))) + if (returncode != 0 && !(isdir && (errno == EBADF || errno == EINVAL || errno == EISDIR))) + { + pg_log_error("could not fsync file \"%s\": %m", fname); + (void) close(fd); +-- +2.39.5 diff --git a/src/wasix/runtime/assets/build/postgres/patches/0038-oliphaunt-wasix-disable-unsupported-writeback-hints.patch b/src/wasix/runtime/assets/build/postgres/patches/0038-oliphaunt-wasix-disable-unsupported-writeback-hints.patch index df54aed61..227262d88 100644 --- a/src/wasix/runtime/assets/build/postgres/patches/0038-oliphaunt-wasix-disable-unsupported-writeback-hints.patch +++ b/src/wasix/runtime/assets/build/postgres/patches/0038-oliphaunt-wasix-disable-unsupported-writeback-hints.patch @@ -19,7 +19,7 @@ targets retain the upstream selection logic. 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c -index 739b1b9..b1f0a22 100644 +index 48453fe..80a2146 100644 --- a/src/backend/storage/file/fd.c +++ b/src/backend/storage/file/fd.c @@ -103,7 +103,12 @@ @@ -37,11 +37,11 @@ index 739b1b9..b1f0a22 100644 #elif !defined(WIN32) && defined(MS_ASYNC) #define PG_FLUSH_DATA_WORKS 1 diff --git a/src/common/file_utils.c b/src/common/file_utils.c -index d0ddfd9..066d455 100644 +index dc474fb..62be891 100644 --- a/src/common/file_utils.c +++ b/src/common/file_utils.c @@ -34,7 +34,12 @@ - #include "common/logging.h" + #ifdef FRONTEND /* Define PG_FLUSH_DATA_WORKS if we have an implementation for pg_flush_data */ -#if defined(HAVE_SYNC_FILE_RANGE) @@ -52,7 +52,7 @@ index d0ddfd9..066d455 100644 + */ +#elif defined(HAVE_SYNC_FILE_RANGE) #define PG_FLUSH_DATA_WORKS 1 - #elif !defined(WIN32) && defined(MS_ASYNC) + #elif defined(USE_POSIX_FADVISE) && defined(POSIX_FADV_DONTNEED) #define PG_FLUSH_DATA_WORKS 1 --- -2.51.0 +-- +2.39.5 diff --git a/src/wasix/runtime/crates/aot/aarch64-apple-darwin/BUILD.bazel b/src/wasix/runtime/crates/aot/aarch64-apple-darwin/BUILD.bazel new file mode 100644 index 000000000..77ce25ce0 --- /dev/null +++ b/src/wasix/runtime/crates/aot/aarch64-apple-darwin/BUILD.bazel @@ -0,0 +1,12 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files") +load("//build_defs/languages:wasix.bzl", "wasix_runtime_carrier") +load("//build_defs/wasix:cargo.bzl", "wasix_runtime_cargo") + +package(default_visibility = ["//visibility:public"]) +exports_files(["Cargo.toml"]) + +wasix_runtime_carrier(payload = "//src/wasix/runtime:aot_macos_arm64_payload") + +wasix_runtime_cargo(payload = "//src/wasix/runtime:aot_macos_arm64_payload", target_id = "macos-arm64") + +rust_quality_files() diff --git a/src/wasix/runtime/crates/aot/aarch64-apple-darwin/build-support.rs b/src/wasix/runtime/crates/aot/aarch64-apple-darwin/build-support.rs index 97c8715fa..43cc1d4f8 100644 --- a/src/wasix/runtime/crates/aot/aarch64-apple-darwin/build-support.rs +++ b/src/wasix/runtime/crates/aot/aarch64-apple-darwin/build-support.rs @@ -211,7 +211,59 @@ fn artifact_name_from_file_stem(stem: &str) -> String { } fn rust_string_literal(path: &Path) -> String { - format!("{:?}", path.to_string_lossy()) + // Generated Rust is compiled in a later action. Keep references relative + // to its output directory instead of retaining a build-script sandbox. + fn lexical_absolute(path: &Path) -> PathBuf { + let mut normalized = PathBuf::new(); + for component in std::path::absolute(path) + .expect("absolute generated include path") + .components() + { + match component { + std::path::Component::ParentDir => { + normalized.pop(); + } + std::path::Component::CurDir => {} + component => normalized.push(component.as_os_str()), + } + } + normalized + } + + let base = lexical_absolute(&PathBuf::from( + env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"), + )); + let target = lexical_absolute(path); + if !target.starts_with(&base) { + let manifest_dir = lexical_absolute(&PathBuf::from( + env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"), + )); + if let Ok(member) = target.strip_prefix(&manifest_dir) { + return format!( + "concat!(env!(\"CARGO_MANIFEST_DIR\"), {:?})", + format!("/{}", member.to_string_lossy().replace('\\', "/")) + ); + } + } + let base_components = base.components().collect::>(); + let target_components = target.components().collect::>(); + let common = base_components + .iter() + .zip(&target_components) + .take_while(|(left, right)| left == right) + .count(); + if common == 0 { + // Ordinary Windows Cargo may place inputs and outputs on separate drives. + return format!("{:?}", target.to_string_lossy()); + } + let mut relative = PathBuf::new(); + for _ in &base_components[common..] { + relative.push(".."); + } + for component in &target_components[common..] { + relative.push(component.as_os_str()); + } + format!("{:?}", relative.to_string_lossy()) } fn artifact_belongs_to_crate(name: &str) -> bool { @@ -256,6 +308,11 @@ fn write_core_aot_manifest(source: &Path, destination: &Path) -> Vec { } fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, files: &[PathBuf]) { + println!("cargo:rerun-if-env-changed=OLIPHAUNT_ARTIFACT_CRATE_EMIT_CARGO_MANIFEST"); + let mode = env::var("OLIPHAUNT_ARTIFACT_CRATE_EMIT_CARGO_MANIFEST").ok(); + if !emit_cargo_manifest(mode.as_deref()) { + return; + } let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo"); let manifest_path = out_dir.join("oliphaunt-artifact.toml"); let mut text = format!( @@ -282,6 +339,34 @@ fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, fil println!("cargo::metadata=manifest={}", manifest_path.display()); } +fn emit_cargo_manifest(mode: Option<&str>) -> bool { + match mode { + None | Some("1") => true, + Some("0") => false, + Some(other) => { + panic!("OLIPHAUNT_ARTIFACT_CRATE_EMIT_CARGO_MANIFEST must be 0 or 1, got {other}") + } + } +} + +#[cfg(test)] +mod native_generation_contract { + use super::emit_cargo_manifest; + + #[test] + fn ordinary_cargo_preserves_manifest_emission_and_native_construction_can_disable_it() { + assert!(emit_cargo_manifest(None)); + assert!(emit_cargo_manifest(Some("1"))); + assert!(!emit_cargo_manifest(Some("0"))); + } + + #[test] + #[should_panic(expected = "must be 0 or 1")] + fn unknown_manifest_modes_are_rejected() { + emit_cargo_manifest(Some("unknown")); + } +} + fn sha256_file(path: &Path) -> io::Result { let mut file = fs::File::open(path)?; let mut hasher = Sha256::new(); diff --git a/src/wasix/runtime/crates/aot/aarch64-unknown-linux-gnu/BUILD.bazel b/src/wasix/runtime/crates/aot/aarch64-unknown-linux-gnu/BUILD.bazel new file mode 100644 index 000000000..e551ba783 --- /dev/null +++ b/src/wasix/runtime/crates/aot/aarch64-unknown-linux-gnu/BUILD.bazel @@ -0,0 +1,12 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files") +load("//build_defs/languages:wasix.bzl", "wasix_runtime_carrier") +load("//build_defs/wasix:cargo.bzl", "wasix_runtime_cargo") + +package(default_visibility = ["//visibility:public"]) +exports_files(["Cargo.toml"]) + +wasix_runtime_carrier(payload = "//src/wasix/runtime:aot_linux_arm64_gnu_payload") + +wasix_runtime_cargo(payload = "//src/wasix/runtime:aot_linux_arm64_gnu_payload", target_id = "linux-arm64-gnu") + +rust_quality_files() diff --git a/src/wasix/runtime/crates/aot/aarch64-unknown-linux-gnu/build-support.rs b/src/wasix/runtime/crates/aot/aarch64-unknown-linux-gnu/build-support.rs index 97c8715fa..43cc1d4f8 100644 --- a/src/wasix/runtime/crates/aot/aarch64-unknown-linux-gnu/build-support.rs +++ b/src/wasix/runtime/crates/aot/aarch64-unknown-linux-gnu/build-support.rs @@ -211,7 +211,59 @@ fn artifact_name_from_file_stem(stem: &str) -> String { } fn rust_string_literal(path: &Path) -> String { - format!("{:?}", path.to_string_lossy()) + // Generated Rust is compiled in a later action. Keep references relative + // to its output directory instead of retaining a build-script sandbox. + fn lexical_absolute(path: &Path) -> PathBuf { + let mut normalized = PathBuf::new(); + for component in std::path::absolute(path) + .expect("absolute generated include path") + .components() + { + match component { + std::path::Component::ParentDir => { + normalized.pop(); + } + std::path::Component::CurDir => {} + component => normalized.push(component.as_os_str()), + } + } + normalized + } + + let base = lexical_absolute(&PathBuf::from( + env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"), + )); + let target = lexical_absolute(path); + if !target.starts_with(&base) { + let manifest_dir = lexical_absolute(&PathBuf::from( + env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"), + )); + if let Ok(member) = target.strip_prefix(&manifest_dir) { + return format!( + "concat!(env!(\"CARGO_MANIFEST_DIR\"), {:?})", + format!("/{}", member.to_string_lossy().replace('\\', "/")) + ); + } + } + let base_components = base.components().collect::>(); + let target_components = target.components().collect::>(); + let common = base_components + .iter() + .zip(&target_components) + .take_while(|(left, right)| left == right) + .count(); + if common == 0 { + // Ordinary Windows Cargo may place inputs and outputs on separate drives. + return format!("{:?}", target.to_string_lossy()); + } + let mut relative = PathBuf::new(); + for _ in &base_components[common..] { + relative.push(".."); + } + for component in &target_components[common..] { + relative.push(component.as_os_str()); + } + format!("{:?}", relative.to_string_lossy()) } fn artifact_belongs_to_crate(name: &str) -> bool { @@ -256,6 +308,11 @@ fn write_core_aot_manifest(source: &Path, destination: &Path) -> Vec { } fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, files: &[PathBuf]) { + println!("cargo:rerun-if-env-changed=OLIPHAUNT_ARTIFACT_CRATE_EMIT_CARGO_MANIFEST"); + let mode = env::var("OLIPHAUNT_ARTIFACT_CRATE_EMIT_CARGO_MANIFEST").ok(); + if !emit_cargo_manifest(mode.as_deref()) { + return; + } let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo"); let manifest_path = out_dir.join("oliphaunt-artifact.toml"); let mut text = format!( @@ -282,6 +339,34 @@ fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, fil println!("cargo::metadata=manifest={}", manifest_path.display()); } +fn emit_cargo_manifest(mode: Option<&str>) -> bool { + match mode { + None | Some("1") => true, + Some("0") => false, + Some(other) => { + panic!("OLIPHAUNT_ARTIFACT_CRATE_EMIT_CARGO_MANIFEST must be 0 or 1, got {other}") + } + } +} + +#[cfg(test)] +mod native_generation_contract { + use super::emit_cargo_manifest; + + #[test] + fn ordinary_cargo_preserves_manifest_emission_and_native_construction_can_disable_it() { + assert!(emit_cargo_manifest(None)); + assert!(emit_cargo_manifest(Some("1"))); + assert!(!emit_cargo_manifest(Some("0"))); + } + + #[test] + #[should_panic(expected = "must be 0 or 1")] + fn unknown_manifest_modes_are_rejected() { + emit_cargo_manifest(Some("unknown")); + } +} + fn sha256_file(path: &Path) -> io::Result { let mut file = fs::File::open(path)?; let mut hasher = Sha256::new(); diff --git a/src/wasix/runtime/crates/aot/x86_64-pc-windows-msvc/BUILD.bazel b/src/wasix/runtime/crates/aot/x86_64-pc-windows-msvc/BUILD.bazel new file mode 100644 index 000000000..cf847d274 --- /dev/null +++ b/src/wasix/runtime/crates/aot/x86_64-pc-windows-msvc/BUILD.bazel @@ -0,0 +1,12 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files") +load("//build_defs/languages:wasix.bzl", "wasix_runtime_carrier") +load("//build_defs/wasix:cargo.bzl", "wasix_runtime_cargo") + +package(default_visibility = ["//visibility:public"]) +exports_files(["Cargo.toml"]) + +wasix_runtime_carrier(payload = "//src/wasix/runtime:aot_windows_x64_msvc_payload") + +wasix_runtime_cargo(payload = "//src/wasix/runtime:aot_windows_x64_msvc_payload", target_id = "windows-x64-msvc") + +rust_quality_files() diff --git a/src/wasix/runtime/crates/aot/x86_64-pc-windows-msvc/build-support.rs b/src/wasix/runtime/crates/aot/x86_64-pc-windows-msvc/build-support.rs index 97c8715fa..43cc1d4f8 100644 --- a/src/wasix/runtime/crates/aot/x86_64-pc-windows-msvc/build-support.rs +++ b/src/wasix/runtime/crates/aot/x86_64-pc-windows-msvc/build-support.rs @@ -211,7 +211,59 @@ fn artifact_name_from_file_stem(stem: &str) -> String { } fn rust_string_literal(path: &Path) -> String { - format!("{:?}", path.to_string_lossy()) + // Generated Rust is compiled in a later action. Keep references relative + // to its output directory instead of retaining a build-script sandbox. + fn lexical_absolute(path: &Path) -> PathBuf { + let mut normalized = PathBuf::new(); + for component in std::path::absolute(path) + .expect("absolute generated include path") + .components() + { + match component { + std::path::Component::ParentDir => { + normalized.pop(); + } + std::path::Component::CurDir => {} + component => normalized.push(component.as_os_str()), + } + } + normalized + } + + let base = lexical_absolute(&PathBuf::from( + env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"), + )); + let target = lexical_absolute(path); + if !target.starts_with(&base) { + let manifest_dir = lexical_absolute(&PathBuf::from( + env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"), + )); + if let Ok(member) = target.strip_prefix(&manifest_dir) { + return format!( + "concat!(env!(\"CARGO_MANIFEST_DIR\"), {:?})", + format!("/{}", member.to_string_lossy().replace('\\', "/")) + ); + } + } + let base_components = base.components().collect::>(); + let target_components = target.components().collect::>(); + let common = base_components + .iter() + .zip(&target_components) + .take_while(|(left, right)| left == right) + .count(); + if common == 0 { + // Ordinary Windows Cargo may place inputs and outputs on separate drives. + return format!("{:?}", target.to_string_lossy()); + } + let mut relative = PathBuf::new(); + for _ in &base_components[common..] { + relative.push(".."); + } + for component in &target_components[common..] { + relative.push(component.as_os_str()); + } + format!("{:?}", relative.to_string_lossy()) } fn artifact_belongs_to_crate(name: &str) -> bool { @@ -256,6 +308,11 @@ fn write_core_aot_manifest(source: &Path, destination: &Path) -> Vec { } fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, files: &[PathBuf]) { + println!("cargo:rerun-if-env-changed=OLIPHAUNT_ARTIFACT_CRATE_EMIT_CARGO_MANIFEST"); + let mode = env::var("OLIPHAUNT_ARTIFACT_CRATE_EMIT_CARGO_MANIFEST").ok(); + if !emit_cargo_manifest(mode.as_deref()) { + return; + } let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo"); let manifest_path = out_dir.join("oliphaunt-artifact.toml"); let mut text = format!( @@ -282,6 +339,34 @@ fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, fil println!("cargo::metadata=manifest={}", manifest_path.display()); } +fn emit_cargo_manifest(mode: Option<&str>) -> bool { + match mode { + None | Some("1") => true, + Some("0") => false, + Some(other) => { + panic!("OLIPHAUNT_ARTIFACT_CRATE_EMIT_CARGO_MANIFEST must be 0 or 1, got {other}") + } + } +} + +#[cfg(test)] +mod native_generation_contract { + use super::emit_cargo_manifest; + + #[test] + fn ordinary_cargo_preserves_manifest_emission_and_native_construction_can_disable_it() { + assert!(emit_cargo_manifest(None)); + assert!(emit_cargo_manifest(Some("1"))); + assert!(!emit_cargo_manifest(Some("0"))); + } + + #[test] + #[should_panic(expected = "must be 0 or 1")] + fn unknown_manifest_modes_are_rejected() { + emit_cargo_manifest(Some("unknown")); + } +} + fn sha256_file(path: &Path) -> io::Result { let mut file = fs::File::open(path)?; let mut hasher = Sha256::new(); diff --git a/src/wasix/runtime/crates/aot/x86_64-unknown-linux-gnu/BUILD.bazel b/src/wasix/runtime/crates/aot/x86_64-unknown-linux-gnu/BUILD.bazel new file mode 100644 index 000000000..1a790aa69 --- /dev/null +++ b/src/wasix/runtime/crates/aot/x86_64-unknown-linux-gnu/BUILD.bazel @@ -0,0 +1,15 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files") +load("//build_defs/languages:rust.bzl", "cargo_generator_test") +load("//build_defs/languages:wasix.bzl", "wasix_runtime_carrier") +load("//build_defs/wasix:cargo.bzl", "wasix_runtime_cargo") + +package(default_visibility = ["//visibility:public"]) +exports_files(["Cargo.toml"]) + +wasix_runtime_carrier(payload = "//src/wasix/runtime:aot_linux_x64_gnu_payload") + +wasix_runtime_cargo(payload = "//src/wasix/runtime:aot_linux_x64_gnu_payload", target_id = "linux-x64-gnu") + +cargo_generator_test(srcs = ["build-support.rs"]) + +rust_quality_files() diff --git a/src/wasix/runtime/crates/aot/x86_64-unknown-linux-gnu/build-support.rs b/src/wasix/runtime/crates/aot/x86_64-unknown-linux-gnu/build-support.rs index 97c8715fa..43cc1d4f8 100644 --- a/src/wasix/runtime/crates/aot/x86_64-unknown-linux-gnu/build-support.rs +++ b/src/wasix/runtime/crates/aot/x86_64-unknown-linux-gnu/build-support.rs @@ -211,7 +211,59 @@ fn artifact_name_from_file_stem(stem: &str) -> String { } fn rust_string_literal(path: &Path) -> String { - format!("{:?}", path.to_string_lossy()) + // Generated Rust is compiled in a later action. Keep references relative + // to its output directory instead of retaining a build-script sandbox. + fn lexical_absolute(path: &Path) -> PathBuf { + let mut normalized = PathBuf::new(); + for component in std::path::absolute(path) + .expect("absolute generated include path") + .components() + { + match component { + std::path::Component::ParentDir => { + normalized.pop(); + } + std::path::Component::CurDir => {} + component => normalized.push(component.as_os_str()), + } + } + normalized + } + + let base = lexical_absolute(&PathBuf::from( + env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"), + )); + let target = lexical_absolute(path); + if !target.starts_with(&base) { + let manifest_dir = lexical_absolute(&PathBuf::from( + env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"), + )); + if let Ok(member) = target.strip_prefix(&manifest_dir) { + return format!( + "concat!(env!(\"CARGO_MANIFEST_DIR\"), {:?})", + format!("/{}", member.to_string_lossy().replace('\\', "/")) + ); + } + } + let base_components = base.components().collect::>(); + let target_components = target.components().collect::>(); + let common = base_components + .iter() + .zip(&target_components) + .take_while(|(left, right)| left == right) + .count(); + if common == 0 { + // Ordinary Windows Cargo may place inputs and outputs on separate drives. + return format!("{:?}", target.to_string_lossy()); + } + let mut relative = PathBuf::new(); + for _ in &base_components[common..] { + relative.push(".."); + } + for component in &target_components[common..] { + relative.push(component.as_os_str()); + } + format!("{:?}", relative.to_string_lossy()) } fn artifact_belongs_to_crate(name: &str) -> bool { @@ -256,6 +308,11 @@ fn write_core_aot_manifest(source: &Path, destination: &Path) -> Vec { } fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, files: &[PathBuf]) { + println!("cargo:rerun-if-env-changed=OLIPHAUNT_ARTIFACT_CRATE_EMIT_CARGO_MANIFEST"); + let mode = env::var("OLIPHAUNT_ARTIFACT_CRATE_EMIT_CARGO_MANIFEST").ok(); + if !emit_cargo_manifest(mode.as_deref()) { + return; + } let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo"); let manifest_path = out_dir.join("oliphaunt-artifact.toml"); let mut text = format!( @@ -282,6 +339,34 @@ fn emit_artifact_manifest(out_dir: &Path, target: &str, artifact_dir: &Path, fil println!("cargo::metadata=manifest={}", manifest_path.display()); } +fn emit_cargo_manifest(mode: Option<&str>) -> bool { + match mode { + None | Some("1") => true, + Some("0") => false, + Some(other) => { + panic!("OLIPHAUNT_ARTIFACT_CRATE_EMIT_CARGO_MANIFEST must be 0 or 1, got {other}") + } + } +} + +#[cfg(test)] +mod native_generation_contract { + use super::emit_cargo_manifest; + + #[test] + fn ordinary_cargo_preserves_manifest_emission_and_native_construction_can_disable_it() { + assert!(emit_cargo_manifest(None)); + assert!(emit_cargo_manifest(Some("1"))); + assert!(!emit_cargo_manifest(Some("0"))); + } + + #[test] + #[should_panic(expected = "must be 0 or 1")] + fn unknown_manifest_modes_are_rejected() { + emit_cargo_manifest(Some("unknown")); + } +} + fn sha256_file(path: &Path) -> io::Result { let mut file = fs::File::open(path)?; let mut hasher = Sha256::new(); diff --git a/src/wasix/runtime/crates/assets/BUILD.bazel b/src/wasix/runtime/crates/assets/BUILD.bazel new file mode 100644 index 000000000..982061115 --- /dev/null +++ b/src/wasix/runtime/crates/assets/BUILD.bazel @@ -0,0 +1,30 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files") +load("//build_defs/languages:rust.bzl", "cargo_generator", "cargo_generator_test", "cargo_library") +load("//build_defs/languages:wasix.bzl", "wasix_runtime_carrier") +load("//build_defs/wasix:cargo.bzl", "wasix_runtime_cargo") +load("@oliphaunt_metadata//:metadata.bzl", "CONTRIB_MEMBERS") + +package(default_visibility = ["//visibility:public"]) +exports_files(["Cargo.toml"]) + +wasix_runtime_carrier(payload = "//src/wasix/runtime:portable_payload", portable = True) + +_NAPI_RELEASE_FEATURES = ["extension-" + member["sql-name"].replace("_", "-") for member in CONTRIB_MEMBERS] +_NAPI_RELEASE_INPUTS = "//src/wasix/node-addon:release_inputs" +cargo_generator( + name = "napi_release_build_script", + srcs = ["build-support.rs"], data = [_NAPI_RELEASE_INPUTS], features = _NAPI_RELEASE_FEATURES, + build_script_env = { + "OLIPHAUNT_ARTIFACT_CRATE_REQUIRE_PAYLOAD": "1", + "OLIPHAUNT_ARTIFACT_CRATE_EMIT_CARGO_MANIFEST": "0", + "OLIPHAUNT_WASIX_GENERATED_ASSETS_DIR": "$(execpath " + _NAPI_RELEASE_INPUTS + ")/portable", + "OLIPHAUNT_WASIX_EXTENSION_ARTIFACT_ROOT": "$(execpath " + _NAPI_RELEASE_INPUTS + ")/extensions", + }, +) +cargo_library(name = "napi_release_lib", build_script = ":napi_release_build_script", features = _NAPI_RELEASE_FEATURES, compile_data = [_NAPI_RELEASE_INPUTS]) + +wasix_runtime_cargo(payload = "//src/wasix/runtime:portable_payload") + +cargo_generator_test(srcs = ["build-support.rs"]) + +rust_quality_files() diff --git a/src/wasix/runtime/crates/assets/build-support.rs b/src/wasix/runtime/crates/assets/build-support.rs index e26af1d7b..72d1425c5 100644 --- a/src/wasix/runtime/crates/assets/build-support.rs +++ b/src/wasix/runtime/crates/assets/build-support.rs @@ -566,7 +566,59 @@ pub fn initdb_wasm() -> Option<&'static [u8]> { None } } fn rust_string_literal(path: &Path) -> String { - format!("{:?}", path.to_string_lossy()) + // Generated Rust is compiled in a later action. Keep references relative + // to its output directory instead of retaining a build-script sandbox. + fn lexical_absolute(path: &Path) -> PathBuf { + let mut normalized = PathBuf::new(); + for component in std::path::absolute(path) + .expect("absolute generated include path") + .components() + { + match component { + std::path::Component::ParentDir => { + normalized.pop(); + } + std::path::Component::CurDir => {} + component => normalized.push(component.as_os_str()), + } + } + normalized + } + + let base = lexical_absolute(&PathBuf::from( + env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"), + )); + let target = lexical_absolute(path); + if !target.starts_with(&base) { + let manifest_dir = lexical_absolute(&PathBuf::from( + env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is set by Cargo"), + )); + if let Ok(member) = target.strip_prefix(&manifest_dir) { + return format!( + "concat!(env!(\"CARGO_MANIFEST_DIR\"), {:?})", + format!("/{}", member.to_string_lossy().replace('\\', "/")) + ); + } + } + let base_components = base.components().collect::>(); + let target_components = target.components().collect::>(); + let common = base_components + .iter() + .zip(&target_components) + .take_while(|(left, right)| left == right) + .count(); + if common == 0 { + // Ordinary Windows Cargo may place inputs and outputs on separate drives. + return format!("{:?}", target.to_string_lossy()); + } + let mut relative = PathBuf::new(); + for _ in &base_components[common..] { + relative.push(".."); + } + for component in &target_components[common..] { + relative.push(component.as_os_str()); + } + format!("{:?}", relative.to_string_lossy()) } fn write_core_manifest( @@ -1149,6 +1201,11 @@ fn extension_wasix_crate_ident(package: ExtensionPackage) -> String { } fn emit_artifact_manifest(out_dir: &Path, asset_dir: &Path, files: &[&Path]) { + println!("cargo:rerun-if-env-changed=OLIPHAUNT_ARTIFACT_CRATE_EMIT_CARGO_MANIFEST"); + let mode = env::var("OLIPHAUNT_ARTIFACT_CRATE_EMIT_CARGO_MANIFEST").ok(); + if !emit_cargo_manifest(mode.as_deref()) { + return; + } let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo"); let manifest_path = out_dir.join("oliphaunt-artifact.toml"); let mut text = format!( @@ -1175,6 +1232,34 @@ fn emit_artifact_manifest(out_dir: &Path, asset_dir: &Path, files: &[&Path]) { println!("cargo::metadata=manifest={}", manifest_path.display()); } +fn emit_cargo_manifest(mode: Option<&str>) -> bool { + match mode { + None | Some("1") => true, + Some("0") => false, + Some(other) => { + panic!("OLIPHAUNT_ARTIFACT_CRATE_EMIT_CARGO_MANIFEST must be 0 or 1, got {other}") + } + } +} + +#[cfg(test)] +mod native_generation_contract { + use super::emit_cargo_manifest; + + #[test] + fn ordinary_cargo_preserves_manifest_emission_and_native_construction_can_disable_it() { + assert!(emit_cargo_manifest(None)); + assert!(emit_cargo_manifest(Some("1"))); + assert!(!emit_cargo_manifest(Some("0"))); + } + + #[test] + #[should_panic(expected = "must be 0 or 1")] + fn unknown_manifest_modes_are_rejected() { + emit_cargo_manifest(Some("unknown")); + } +} + fn sha256_file(path: &Path) -> io::Result { let mut file = fs::File::open(path)?; let mut hasher = Sha256::new(); diff --git a/src/wasix/runtime/moon.yml b/src/wasix/runtime/moon.yml index 79e79beab..e51984056 100644 --- a/src/wasix/runtime/moon.yml +++ b/src/wasix/runtime/moon.yml @@ -30,14 +30,6 @@ project: release: component: liboliphaunt-wasix packagePath: src/wasix/runtime - artifactTargets: - preset: liboliphaunt-wasix - targets: - - portable - - linux-arm64-gnu - - linux-x64-gnu - - macos-arm64 - - windows-x64-msvc owners: defaultOwner: "@oliphaunt/wasix" paths: @@ -64,6 +56,9 @@ fileGroups: - /src/query/rust/src/lib.rs - /src/test-fixtures/**/* - tools/runtime-smoke.sh + - tools/source-server-qualification.mts + - /tools/packaging/cargo-manifest.mts + - /src/wasix/node-addon/Cargo.toml - tools/wasix-extension-features.mts - tools/wasix-aot-manifest.mts - tools/wasix-cargo-artifact-contract.mts diff --git a/src/wasix/runtime/release.toml b/src/wasix/runtime/release.toml index 1e63f3f94..152d6d258 100644 --- a/src/wasix/runtime/release.toml +++ b/src/wasix/runtime/release.toml @@ -14,3 +14,13 @@ registry_packages = [ release_artifacts = [ "release-assets", ] + +[artifact_targets] +preset = "liboliphaunt-wasix" +targets = [ + "portable", + "linux-arm64-gnu", + "linux-x64-gnu", + "macos-arm64", + "windows-x64-msvc", +] diff --git a/src/wasix/runtime/tools/check-release-assets.mts b/src/wasix/runtime/tools/check-release-assets.mts index 4d6e2a1c4..5895453ac 100644 --- a/src/wasix/runtime/tools/check-release-assets.mts +++ b/src/wasix/runtime/tools/check-release-assets.mts @@ -292,7 +292,7 @@ function parseChecksumManifest(file) { if (!line) { continue; } - const match = line.match(/^([0-9a-f]{64}) \.\/([^/]+)$/u); + const match = line.match(/^([0-9a-f]{64}) {2}\.\/([^/]+)$/u); if (match === null) { fail(`${rel(file)}:${index + 1} must use ' ./' entries`); } @@ -484,6 +484,7 @@ export function validatePortableReleaseAsset(archive) { `${rel(archive)} must not bundle standalone tools inside ${PORTABLE_RUNTIME_ARCHIVE_MEMBER}: ${bundledTools.join(', ')}`, ); } + return entries; } export function validateAotReleaseAsset(archive, expectedTarget) { @@ -555,6 +556,7 @@ export function validateAotReleaseAsset(archive, expectedTarget) { `expected ${JSON.stringify([...expectedFiles].sort(compareText))}, got ${JSON.stringify([...members].sort(compareText))}`, ); } + return entries; } function validateAssetContents(assetDir, version) { diff --git a/src/wasix/runtime/tools/package_liboliphaunt_wasix_cargo_artifacts.mts b/src/wasix/runtime/tools/package_liboliphaunt_wasix_cargo_artifacts.mts index ea7a9fcc0..e79b7e2bd 100755 --- a/src/wasix/runtime/tools/package_liboliphaunt_wasix_cargo_artifacts.mts +++ b/src/wasix/runtime/tools/package_liboliphaunt_wasix_cargo_artifacts.mts @@ -14,12 +14,6 @@ import fs, { } from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; -import { - assertExtensionUpstreamLicensesInArchive, - assertExtensionUpstreamLicensesInDirectory, - extensionRegistryLicense, - stageExtensionUpstreamLicenses, -} from '../../../extensions/tools/extension-upstream-licenses.mts'; import { createDeterministicTar } from '../../../../tools/packaging/cargo-source-package.mts'; import { portableMemberName, @@ -48,8 +42,21 @@ import { extensionSqlNames, } from '../../../../tools/release/release-artifact-targets.mts'; import { compareText } from '../../../../tools/release/release-graph.mts'; +import { + assertWasixExtensionArchiveInstall, + WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA, +} from '../../../extensions/contracts/wasix-extension-install.mts'; +import { + assertExtensionUpstreamLicensesInArchive, + assertExtensionUpstreamLicensesInDirectory, + extensionRegistryLicense, + stageExtensionUpstreamLicenses, +} from '../../../extensions/tools/extension-upstream-licenses.mts'; import { assertWasixAotArtifactPayloads } from './check-release-assets.mts'; -import { assertCanonicalWasixAotManifest } from './wasix-aot-manifest.mts'; +import { + assertCanonicalWasixAotManifest, + canonicalWasixAotMetadata, +} from './wasix-aot-manifest.mts'; import { AOT_PACKAGES, AOT_TARGET_CFGS, @@ -239,11 +246,12 @@ function readJson(file) { } } -function validateCanonicalAotManifest(manifest, manifestPath, expectedTarget) { +function validateCanonicalAotManifest(manifest, manifestPath, expectedTarget, sourceRoot = ROOT) { try { assertCanonicalWasixAotManifest(manifest, { context: rel(manifestPath), expectedTarget, + canonical: canonicalWasixAotMetadata(sourceRoot), }); } catch (error) { fail(error.message); @@ -421,10 +429,10 @@ function runtimeCorePayload(runtimeRoot, extractRoot) { return coreRoot; } -export function validateAotPayload(root, expectedTarget) { +export function validateAotPayload(root, expectedTarget, { sourceRoot = ROOT } = {}) { const manifestPath = path.join(root, 'manifest.json'); const manifest = readJson(manifestPath); - validateCanonicalAotManifest(manifest, manifestPath, expectedTarget); + validateCanonicalAotManifest(manifest, manifestPath, expectedTarget, sourceRoot); let artifactRows; try { artifactRows = assertWasixAotArtifactPayloads(manifest, { @@ -444,7 +452,7 @@ export function validateAotPayload(root, expectedTarget) { } const expected = new Set([ 'manifest.json', - ...releaseNoticeRows({ profile: 'wasix-aot' }).map((row) => row.member), + ...releaseNoticeRows({ profile: 'wasix-aot', sourceRoot }).map((row) => row.member), ]); for (const row of artifactRows) { if (row.name.startsWith('extension:')) { @@ -452,7 +460,7 @@ export function validateAotPayload(root, expectedTarget) { } expected.add(row.path); } - assertReleaseNoticesInDirectory(root, { profile: 'wasix-aot' }); + assertReleaseNoticesInDirectory(root, { profile: 'wasix-aot', sourceRoot }); const actual = new Set(payloadFiles(root).map((file) => relPath(root, file))); if (!sameSet(actual, expected)) { fail( @@ -461,8 +469,8 @@ export function validateAotPayload(root, expectedTarget) { } } -export function validateRuntimeAotPayload(root, expectedTarget) { - validateAotPayload(root, expectedTarget); +export function validateRuntimeAotPayload(root, expectedTarget, options = {}) { + validateAotPayload(root, expectedTarget, options); const manifestPath = path.join(root, 'manifest.json'); assertCoreRuntimeAotArtifacts(readJson(manifestPath), rel(manifestPath)); } @@ -1545,6 +1553,168 @@ function packageExtensionSource(source, { outputDir, cargoTargetDir }) { return packages; } +/** Package one declared SQL-only leaf without rediscovering workspace release owners. */ +export function packageSqlOnlyWasixExtensionCargo( + spec: { + product: string; + version: string; + runtimeProduct: string; + runtimeVersion: string; + member: { + sqlName: string; + dependencies: string[]; + archive: string; + sha256: string; + size: number; + install: Record; + }; + }, + { outputDir, workDir }: { outputDir: string; workDir: string }, +) { + const { member } = spec; + if (spec.product !== `oliphaunt-extension-${member.sqlName}`) { + fail('SQL-only WASIX Cargo leaf must bind its external member to its release owner'); + } + if (spec.runtimeProduct !== PRODUCT) + fail('SQL-only WASIX Cargo leaf has the wrong runtime owner'); + extensionDependencyRequirement(spec.runtimeVersion, 'runtime-bound'); + const { install } = assertWasixExtensionArchiveInstall(readFileSync(member.archive), { + schema: WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA, + sqlName: member.sqlName, + archive: `extensions/${member.sqlName}.tar.zst`, + sha256: member.sha256, + size: member.size, + install: member.install, + }); + if ( + install.nativeModule !== null || + install.nativeModules.length !== 0 || + install.coreExportsRequired.length !== 0 || + install.unresolvedImports.length !== 0 + ) { + fail('SQL-only WASIX Cargo leaf cannot package a compiled member without its AOT closure'); + } + if (member.size > DEFAULT_EXTENSION_PART_BYTES) { + fail('SQL-only WASIX Cargo leaf exceeds the declared single-crate payload boundary'); + } + const sourceRoot = path.join(workDir, 'cargo-package-sources'); + mkdirSync(sourceRoot, { recursive: true }); + mkdirSync(outputDir, { recursive: true }); + const source = writeExtensionCargoSource( + { + ...spec, + name: wasixExtensionPackageName(spec.product), + members: [{ ...member, nativeModuleStem: null, requiresAot: false }], + versioning: 'upstream-bound', + dependencyRequirement: extensionDependencyRequirement(spec.version, 'upstream-bound'), + aotTargets: [], + }, + sourceRoot, + DEFAULT_EXTENSION_PART_BYTES, + ); + return packageExtensionSource(source, { + outputDir, + cargoTargetDir: path.join(workDir, 'cargo-package-target'), + }); +} + +/** Package a declared owner and complete AOT cohort without checkout discovery. */ +export function packageDeclaredWasixExtensionCargo( + spec: { + product: string; + version: string; + runtimeProduct: string; + runtimeVersion: string; + versioning: 'upstream-bound' | 'runtime-bound'; + extensionRoot: string; + members: { + sqlName: string; + dependencies: string[]; + nativeModuleStem: string | null; + archive: string; + sha256: string; + size: number; + install: Record; + }[]; + }, + { outputDir, workDir }: { outputDir: string; workDir: string }, +) { + if (spec.runtimeProduct !== PRODUCT) fail('declared WASIX extension has the wrong runtime owner'); + extensionDependencyRequirement(spec.runtimeVersion, 'runtime-bound'); + const contrib = spec.product === 'oliphaunt-extension-contrib-pg18'; + if ( + !spec.members.length || + new Set(spec.members.map((member) => member.sqlName)).size !== spec.members.length + ) + fail('declared WASIX extension requires unique SQL members'); + if ( + contrib + ? spec.versioning !== 'runtime-bound' || spec.version !== spec.runtimeVersion + : spec.members.length !== 1 || + spec.product !== `oliphaunt-extension-${spec.members[0].sqlName.replaceAll('_', '-')}` || + spec.versioning !== 'upstream-bound' + ) + fail('declared WASIX extension differs from its release owner or versioning'); + const members = spec.members.map((member) => { + const { install } = assertWasixExtensionArchiveInstall(readFileSync(member.archive), { + schema: WASIX_EXTENSION_INSTALL_SIDECAR_SCHEMA, + sqlName: member.sqlName, + archive: `extensions/${member.sqlName}.tar.zst`, + sha256: member.sha256, + size: member.size, + install: member.install, + }); + const requiresAot = install.nativeModule !== null; + if (requiresAot !== Boolean(member.nativeModuleStem) || install.unresolvedImports.length) + fail('declared WASIX member has inconsistent modules or unresolved imports'); + return { ...member, requiresAot }; + }); + const declared = { + ...spec, + name: wasixExtensionPackageName(spec.product), + members, + dependencyRequirement: extensionDependencyRequirement(spec.version, spec.versioning), + }; + const aotTargets = extensionAotSpecs(spec.extensionRoot, declared); + validateExtensionAotCoverage([{ ...declared, aotTargets }]); + for (const target of aotTargets) + for (const member of target.members) { + const portable = members.find((row) => row.sqlName === member.sqlName)!; + const manifest = readJson(path.join(member.sourceDir, 'manifest.json')); + const expected = new Map( + (portable.install.nativeModules as { name: string; moduleSha256: string }[]).map((row) => [ + `extension:${member.sqlName}${row.name === member.sqlName ? '' : `:${row.name}`}`, + row.moduleSha256, + ]), + ); + if ( + manifest.artifacts.length !== expected.size || + manifest.artifacts.some((row) => expected.get(row.name) !== row['module-sha256']) + ) + fail('declared WASIX AOT cohort differs from its exact portable module identities'); + } + const sourceRoot = path.join(workDir, 'cargo-package-sources'); + const cargoTargetDir = path.join(workDir, 'cargo-package-target'); + mkdirSync(sourceRoot, { recursive: true }); + mkdirSync(outputDir, { recursive: true }); + const source = writeExtensionCargoSource( + { ...declared, aotTargets }, + sourceRoot, + DEFAULT_EXTENSION_PART_BYTES, + ); + const packages = [ + ...packageExtensionSource(source, { outputDir, cargoTargetDir }), + ...aotTargets.flatMap((target) => + packageExtensionAotSource( + writeExtensionAotCargoSource(target, sourceRoot, DEFAULT_EXTENSION_PART_BYTES), + { outputDir, cargoTargetDir }, + ), + ), + ]; + writePackagesManifest(packages, outputDir); + return packages; +} + function packageExtensionAotSource(source, { outputDir, cargoTargetDir }) { const packages = []; for (const part of source.partSources ?? []) { diff --git a/src/wasix/runtime/tools/runtime-smoke.sh b/src/wasix/runtime/tools/runtime-smoke.sh index 69820501b..4046efa22 100755 --- a/src/wasix/runtime/tools/runtime-smoke.sh +++ b/src/wasix/runtime/tools/runtime-smoke.sh @@ -81,7 +81,18 @@ if [ "$asset_mode" = "full" ]; then # Each extension must pass direct execution, restart, physical backup/restore, # server execution and materialization. Tests record only completed modes. oliphaunt_wasix_library_tests extension_tests::public_extensions - server_command=(cargo test -p oliphaunt-pgwire-server --locked --no-default-features + # This full-catalog proof uses current sources, separately from held installed adapters. + mkdir -p "$root/target/wasix-smoke" + source_server_root="$(mktemp -d "$root/target/wasix-smoke/source-server.XXXXXX")" + trap 'rm -rf "$source_server_root"' EXIT + source_server_helper="$root/src/wasix/runtime/tools/source-server-qualification.mts" + source_server_manifest="$(tools/dev/bun.sh "$source_server_helper" prepare "$root" "$source_server_root")" + cargo fetch --manifest-path "$source_server_manifest" + cargo metadata --manifest-path "$source_server_manifest" --locked --offline --no-default-features \ + --features "${full_evidence_features/,tools/}" --format-version 1 > "$source_server_root/metadata.json" + tools/dev/bun.sh "$source_server_helper" verify "$root" "$source_server_manifest" "$source_server_root/metadata.json" + server_command=(cargo test --manifest-path "$source_server_manifest" + --target-dir "${CARGO_TARGET_DIR:-$root/target}" -p oliphaunt-pgwire-server --locked --offline --no-default-features --features "${full_evidence_features/,tools/}" --test extensions public_extensions_pass_server_smoke) oliphaunt_require_cargo_test_filter public_extensions_pass_server_smoke "${server_command[@]}" "${server_command[@]}" -- --ignored --exact --nocapture --test-threads=1 diff --git a/src/wasix/runtime/tools/source-server-qualification.mts b/src/wasix/runtime/tools/source-server-qualification.mts new file mode 100644 index 000000000..9e16edff1 --- /dev/null +++ b/src/wasix/runtime/tools/source-server-qualification.mts @@ -0,0 +1,90 @@ +/** Explicit source lifecycle composition; never installed-package evidence. */ +import { + copyFileSync, + cpSync, + mkdirSync, + readFileSync, + realpathSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { + renderCargoToml, + resolveCargoWorkspaceInheritance, +} from '../../../../tools/packaging/cargo-manifest.mts'; + +const SERVER = 'src/wasix/pgwire-server'; +const SDK = 'src/wasix/sdks/rust'; +const readManifest = (file: string) => Bun.TOML.parse(readFileSync(file, 'utf8')); + +export function stageSourceServerQualification(root: string, directory: string) { + const source = path.join(root, SERVER); + const original = readManifest(path.join(source, 'Cargo.toml')); + const workspace = readManifest(path.join(root, 'Cargo.toml')); + const manifest = resolveCargoWorkspaceInheritance(original, workspace.workspace); + delete manifest.package.workspace; + manifest.package.publish = false; + manifest.workspace = {}; + // Retain the held requirement; Cargo rejects an incompatible source SDK. + manifest.dependencies['oliphaunt-wasix'].path = path.join(root, SDK); + const destination = path.join(directory, SERVER); + mkdirSync(destination, { recursive: true }); + for (const name of ['src', 'tests', 'README.md']) + cpSync(path.join(source, name), path.join(destination, name), { recursive: true }); + for (const relative of [ + 'src/extensions/catalog/extensions.source.json', + 'src/test-fixtures/extensions', + ]) { + const target = path.join(directory, relative); + mkdirSync(path.dirname(target), { recursive: true }); + cpSync(path.join(root, relative), target, { recursive: true }); + } + copyFileSync(path.join(root, 'Cargo.lock'), path.join(destination, 'Cargo.lock')); + const file = path.join(destination, 'Cargo.toml'); + writeFileSync(file, renderCargoToml(manifest)); + return file; +} + +export function verifySourceServerResolution(metadata: any, root: string, manifest: string) { + const packages = metadata.packages; + const server = packages.find((row: any) => row.manifest_path === manifest); + if (!server || metadata.resolve?.root !== server.id) + throw new Error('source server qualification requires its actual resolved root'); + const serverNode = metadata.resolve.nodes.find((row: any) => row.id === server.id); + const sdkId = serverNode?.deps.find((row: any) => row.name === 'oliphaunt_wasix')?.pkg; + const sdk = packages.find((row: any) => row.id === sdkId); + const sdkManifest = path.join(root, SDK, 'Cargo.toml'); + if ( + sdk?.name !== 'oliphaunt-wasix' || + sdk.source !== null || + realpathSync(sdk.manifest_path) !== realpathSync(sdkManifest) + ) + throw new Error('source server qualification resolved an installed or different SDK'); + + const sdkDeclaration = readManifest(sdkManifest); + const expected = new Map(); + for (const table of [sdkDeclaration, ...Object.values(sdkDeclaration.target ?? {})] as any[]) + for (const [name, declaration] of Object.entries(table.dependencies ?? {}) as [string, any][]) + if (declaration.path) + expected.set(name, path.resolve(path.dirname(sdkManifest), declaration.path, 'Cargo.toml')); + for (const row of packages) { + const expectedManifest = expected.get(row.name); + if (expectedManifest === undefined) continue; + if (row.source !== null || realpathSync(row.manifest_path) !== realpathSync(expectedManifest)) + throw new Error( + `source server qualification resolved an installed or different carrier: ${row.name}`, + ); + } +} + +if (import.meta.main) { + const [mode, root, directory, metadataFile] = process.argv.slice(2); + if (mode === 'prepare' && root && directory && !metadataFile) + console.log(stageSourceServerQualification(root, directory)); + else if (mode === 'verify' && root && directory && metadataFile) + verifySourceServerResolution(JSON.parse(readFileSync(metadataFile, 'utf8')), root, directory); + else + throw new Error( + 'usage: source-server-qualification.mts prepare ROOT DIRECTORY | verify ROOT MANIFEST METADATA', + ); +} diff --git a/src/wasix/runtime/tools/source-server-qualification.test.mts b/src/wasix/runtime/tools/source-server-qualification.test.mts new file mode 100644 index 000000000..9d4e61a04 --- /dev/null +++ b/src/wasix/runtime/tools/source-server-qualification.test.mts @@ -0,0 +1,158 @@ +import { afterEach, expect, test } from 'bun:test'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { renderCargoToml } from '../../../../tools/packaging/cargo-manifest.mts'; +import { + stageSourceServerQualification, + verifySourceServerResolution, +} from './source-server-qualification.mts'; + +const temporary: string[] = []; +afterEach(() => { + for (const directory of temporary.splice(0)) rmSync(directory, { recursive: true, force: true }); +}); + +function fixture(sdkVersion = '0.3.2') { + const directory = mkdtempSync(path.join(tmpdir(), 'oliphaunt-source-server-')); + temporary.push(directory); + const root = path.join(directory, 'repository'); + const write = (relative: string, text: string) => { + const file = path.join(root, relative); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, text); + }; + write('Cargo.lock', 'version = 4\n'); + write( + 'Cargo.toml', + renderCargoToml({ + workspace: { + members: [ + 'src/wasix/pgwire-server', + 'src/wasix/sdks/rust', + 'src/wasix/runtime/crates/assets', + ], + resolver: '3', + package: { repository: 'https://example.invalid/repository' }, + dependencies: { 'oliphaunt-wasix': { version: '0.3.2', path: 'src/wasix/sdks/rust' } }, + }, + }), + ); + write( + 'src/wasix/pgwire-server/Cargo.toml', + renderCargoToml({ + package: { + name: 'oliphaunt-pgwire-server', + version: '0.2.1', + edition: '2024', + repository: { workspace: true }, + }, + features: { + default: [], + extensions: ['dep:oliphaunt-wasix', 'oliphaunt-wasix/extension-pg-hashids'], + }, + dependencies: { 'oliphaunt-wasix': { workspace: true, optional: true } }, + }), + ); + write( + 'src/wasix/pgwire-server/src/lib.rs', + '#[cfg(feature="extensions")] pub fn answer() -> u32 { oliphaunt_wasix::answer() }\n', + ); + write( + 'src/wasix/pgwire-server/tests/extensions.rs', + '#[test] fn source_extension() { assert_eq!(oliphaunt_pgwire_server::answer(),42); }\n', + ); + write('src/wasix/pgwire-server/README.md', 'source server fixture\n'); + write('src/extensions/catalog/extensions.source.json', '{"extensions":[]}\n'); + write('src/test-fixtures/extensions/pg_hashids.sql', 'SELECT 42;\n'); + write( + 'src/wasix/sdks/rust/Cargo.toml', + renderCargoToml({ + package: { name: 'oliphaunt-wasix', version: sdkVersion, edition: '2024' }, + features: { 'extension-pg-hashids': ['liboliphaunt-wasix-portable/extension-pg-hashids'] }, + dependencies: { + 'liboliphaunt-wasix-portable': { version: '*', path: '../../runtime/crates/assets' }, + }, + }), + ); + write( + 'src/wasix/sdks/rust/src/lib.rs', + 'pub fn answer() -> u32 { liboliphaunt_wasix_portable::answer() }\n', + ); + write( + 'src/wasix/runtime/crates/assets/Cargo.toml', + renderCargoToml({ + package: { name: 'liboliphaunt-wasix-portable', version: '0.3.2', edition: '2024' }, + features: { 'extension-pg-hashids': [] }, + }), + ); + write('src/wasix/runtime/crates/assets/src/lib.rs', 'pub fn answer() -> u32 { 42 }\n'); + const held = new Map( + ['Cargo.lock', 'Cargo.toml', 'src/wasix/pgwire-server/Cargo.toml'].map((relative) => [ + relative, + readFileSync(path.join(root, relative), 'utf8'), + ]), + ); + const manifest = stageSourceServerQualification(root, path.join(directory, 'source-proof')); + const cargo = (...arguments_: string[]) => + Bun.spawnSync( + [ + 'cargo', + ...arguments_, + '--manifest-path', + manifest, + '--offline', + '--no-default-features', + '--features', + 'extensions', + ], + { stdout: 'pipe', stderr: 'pipe' }, + ); + return { root, manifest, cargo, held }; +} + +test('actual isolated Cargo resolution and execution use current source SDK and carriers without changing held manifests', () => { + const proof = fixture(); + const manifest = Bun.TOML.parse(readFileSync(proof.manifest, 'utf8')); + expect(manifest.dependencies['oliphaunt-wasix'].version).toBe('0.3.2'); + expect(manifest.dependencies['oliphaunt-wasix'].optional).toBe(true); + expect(manifest.package.repository).toBe('https://example.invalid/repository'); + expect(manifest.package.workspace).toBeUndefined(); + expect(manifest.package.publish).toBe(false); + const resolved = proof.cargo('metadata', '--format-version', '1'); + expect(resolved.exitCode, resolved.stderr.toString()).toBe(0); + const metadata = JSON.parse(resolved.stdout.toString()); + verifySourceServerResolution(metadata, proof.root, proof.manifest); + const executed = proof.cargo('test', '--locked', '--test', 'extensions'); + expect(executed.exitCode, executed.stderr.toString()).toBe(0); + expect(executed.stdout.toString()).toContain('1 passed'); + for (const [relative, original] of proof.held) + expect(readFileSync(path.join(proof.root, relative), 'utf8')).toBe(original); +}); + +test('Cargo rejects a source SDK outside the held conventional requirement', () => { + const proof = fixture('0.4.0'); + const resolved = proof.cargo('metadata', '--format-version', '1'); + expect(resolved.exitCode).not.toBe(0); + expect(resolved.stderr.toString()).toContain('failed to select a version'); +}); + +test('resolution verification rejects registry SDK or runtime substitution and wrong root', () => { + const proof = fixture(); + const resolved = proof.cargo('metadata', '--format-version', '1'); + expect(resolved.exitCode, resolved.stderr.toString()).toBe(0); + const metadata = JSON.parse(resolved.stdout.toString()); + for (const name of ['oliphaunt-wasix', 'liboliphaunt-wasix-portable']) { + const invalid = structuredClone(metadata); + invalid.packages.find((row: any) => row.name === name).source = + 'registry+https://github.com/rust-lang/crates.io-index'; + expect(() => verifySourceServerResolution(invalid, proof.root, proof.manifest)).toThrow( + /installed or different/, + ); + } + const invalid = structuredClone(metadata); + invalid.resolve.root = 'different root'; + expect(() => verifySourceServerResolution(invalid, proof.root, proof.manifest)).toThrow( + 'actual resolved root', + ); +}); diff --git a/src/wasix/runtime/tools/wasix-runtime-npm-carrier.mts b/src/wasix/runtime/tools/wasix-runtime-npm-carrier.mts index 820e4e775..45622d0df 100644 --- a/src/wasix/runtime/tools/wasix-runtime-npm-carrier.mts +++ b/src/wasix/runtime/tools/wasix-runtime-npm-carrier.mts @@ -1,68 +1,34 @@ #!/usr/bin/env bun - -import { createHash } from 'node:crypto'; -import { chmodSync, lstatSync, mkdirSync, rmSync, statSync, writeFileSync } from 'node:fs'; -import { isDeepStrictEqual } from 'node:util'; +import { lstatSync, mkdirSync, rmSync, writeFileSync } from 'node:fs'; import path from 'node:path'; - -import { validatePortableReleaseAsset } from './check-release-assets.mts'; -import { createDeterministicTar } from '../../../../tools/packaging/cargo-source-package.mts'; -import { - NPM_TRUSTED_PUBLISHING_REPOSITORY, - validateNpmTrustedPublishingManifest, -} from '../../../../tools/packaging/npm-trusted-publishing.mts'; +import { createDeterministicTar } from '../../../../tools/packaging/package-archive.mts'; import { canonicalGzipSync, readPortableArchiveEntries, - readPortableTarZstdBufferEntries, } from '../../../../tools/packaging/portable-archive.mts'; +import { validatePortableReleaseAsset } from './check-release-assets.mts'; +import { WASIX_PORTABLE_RELEASE_MEMBERS } from './wasix-runtime-npm-contract.mts'; import { - assertReleaseNoticesInArchive, - assertReleaseNoticesInDirectory, - releaseNoticeRows, - releaseProfilePackageLicense, - stageReleaseNotices, -} from '../../../../tools/packaging/release-notices.mts'; -import { - WASIX_PORTABLE_RELEASE_MEMBERS, - WASIX_RUNTIME_ARCHIVE_PATH, - WASIX_RUNTIME_NPM_ASSET_PATHS, - WASIX_RUNTIME_NPM_DESCRIPTOR_SCHEMA, - WASIX_RUNTIME_NPM_PACKAGE, - WASIX_RUNTIME_NPM_TARGET, - WASIX_RUNTIME_PRODUCT, -} from './wasix-runtime-npm-contract.mts'; -import { - renderWasixRuntimeDescriptorModule, - renderWasixRuntimeDescriptorTypes, -} from './wasix-runtime-npm-descriptor.mts'; + assertWasixRuntimeNpmArchive, + stageWasixRuntimeNpmPayload, + wasixRuntimeNpmPayloadInputs, +} from './wasix-runtime-npm-payload.mts'; export { + assertWasixRuntimeNpmArchive, renderWasixRuntimeDescriptorModule, renderWasixRuntimeDescriptorTypes, -} from './wasix-runtime-npm-descriptor.mts'; +} from './wasix-runtime-npm-payload.mts'; -const TOOL = 'wasix-runtime-npm-carrier.mts'; const ROOT = path.resolve(import.meta.dirname, '../../../..'); -const LOWER_SHA256 = /^[0-9a-f]{64}$/u; -const SQL_NAME = /^[a-z0-9][a-z0-9_-]*$/u; -const RUNTIME_MODULE_MEMBER = 'oliphaunt/bin/postgres'; -const NPM_PACKAGE_SAFETY_LIMIT_BYTES = 100 * 1024 * 1024; -const NOTICE_OPTIONS = Object.freeze({ profile: 'wasix-runtime' }); - +const TOOL = 'wasix-runtime-npm-carrier.mts'; function fail(message) { throw new Error(`${TOOL}: ${message}`); } - function rel(file) { const relative = path.relative(ROOT, file).split(path.sep).join('/'); return relative && !relative.startsWith('../') ? relative : String(file); } - -function sha256Bytes(bytes) { - return createHash('sha256').update(bytes).digest('hex'); -} - function regularFile(file, label) { let metadata; try { @@ -70,174 +36,20 @@ function regularFile(file, label) { } catch (cause) { fail(`${label} cannot be inspected: ${cause.message}`); } - if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size <= 0) { + if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size <= 0) fail(`${label} must be a non-empty regular non-symlink file: ${rel(file)}`); - } return metadata; } - -function parseJsonBytes(bytes, label) { - let value; - try { - value = JSON.parse(Buffer.from(bytes).toString('utf8')); - } catch (cause) { - fail(`${label} must contain UTF-8 JSON: ${cause.message}`); - } - if (value === null || Array.isArray(value) || typeof value !== 'object') { - fail(`${label} must contain a JSON object`); - } - return value; -} - -function object(value, label) { - if (value === null || Array.isArray(value) || typeof value !== 'object') { - fail(`${label} must be an object`); - } - return value; -} - -function nonEmptyString(value, label) { - if (typeof value !== 'string' || value.length === 0 || value.includes('\0')) { - fail(`${label} must be a non-empty string without NUL bytes`); - } - return value; -} - -function checkedSha256(value, label) { - if (typeof value !== 'string' || !LOWER_SHA256.test(value)) { - fail(`${label} must be a lowercase SHA-256 digest`); - } - return value; -} - -function safeRelativePath(value, label) { - const result = nonEmptyString(value, label); - const segments = result.split('/'); - if ( - result.startsWith('/') || - result.includes('\\') || - segments.some((segment) => segment.length === 0 || segment === '.' || segment === '..') - ) { - fail(`${label} must be a canonical safe relative path`); - } - return result; -} - -function postgresMajor(value, label) { - return nonEmptyString(value, label).split('.')[0]; -} - -function requireRegularEntry(entries, member, label) { - const entry = entries.get(member); - if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) { - fail(`${label} must contain ${member} as one non-empty regular file`); - } - return entry; -} - -/** - * Validate the complete core-manifest projection consumed by WASIX hosts. - * Keep this producer-side gate in lockstep with the binding's parser so a - * package cannot be publishable but unusable by every consumer. - */ -function assertCoreManifestContract(manifest, runtimeEntries) { - if (manifest['format-version'] !== 2) { - fail('frozen WASIX core manifest must use format-version 2'); - } - nonEmptyString(manifest['source-fingerprint'], 'frozen WASIX core manifest source-fingerprint'); - const runtime = object(manifest.runtime, 'frozen WASIX core manifest runtime'); - safeRelativePath(runtime.archive, 'frozen WASIX core manifest runtime.archive'); - checkedSha256(runtime.sha256, 'frozen WASIX core manifest runtime.sha256'); - if (runtime.size !== undefined && (!Number.isSafeInteger(runtime.size) || runtime.size <= 0)) { - fail('frozen WASIX core manifest runtime.size must be a positive safe integer when present'); - } - const runtimeModuleSha256 = checkedSha256( - runtime['module-sha256'], - 'frozen WASIX core manifest runtime.module-sha256', - ); - postgresMajor(runtime['postgres-version'], 'frozen WASIX core manifest runtime.postgres-version'); - const link = object(runtime.link, 'frozen WASIX core manifest runtime.link'); - if (!Array.isArray(link.exports)) { - fail('frozen WASIX core manifest runtime.link.exports must be an array'); - } - for (const [index, value] of link.exports.entries()) { - const entry = object(value, `frozen WASIX core manifest runtime.link.exports[${index}]`); - nonEmptyString(entry.name, `frozen WASIX core manifest runtime.link.exports[${index}].name`); - nonEmptyString(entry.kind, `frozen WASIX core manifest runtime.link.exports[${index}].kind`); - } - - if (!Array.isArray(manifest['runtime-support'])) { - fail('frozen WASIX core manifest runtime-support must be an array'); - } - const supportNames = new Set(); - const supportPaths = new Set(); - for (const [index, value] of manifest['runtime-support'].entries()) { - const entry = object(value, `frozen WASIX core manifest runtime-support[${index}]`); - const name = nonEmptyString( - entry.name, - `frozen WASIX core manifest runtime-support[${index}].name`, - ); - if (!SQL_NAME.test(name) || supportNames.has(name)) { - fail(`frozen WASIX core manifest runtime-support[${index}].name must be unique and portable`); - } - supportNames.add(name); - const supportPath = safeRelativePath( - entry.path, - `frozen WASIX core manifest runtime-support[${index}].path`, - ); - if (!supportPath.startsWith('lib/postgresql/') || supportPaths.has(supportPath)) { - fail( - `frozen WASIX core manifest runtime-support[${index}].path must be unique under lib/postgresql/`, - ); - } - supportPaths.add(supportPath); - checkedSha256(entry.sha256, `frozen WASIX core manifest runtime-support[${index}].sha256`); - } - - const runtimeModule = requireRegularEntry( - runtimeEntries, - RUNTIME_MODULE_MEMBER, - 'frozen WASIX runtime archive', - ); - if (sha256Bytes(runtimeModule.data()) !== runtimeModuleSha256) { - fail('frozen WASIX runtime module does not match manifest runtime.module-sha256'); - } -} - -function checkedAssetMetadata(value, expectedArchive, label) { - if (value === null || Array.isArray(value) || typeof value !== 'object') { - fail(`${label} must be an object`); - } - if (value.archive !== expectedArchive) { - fail(`${label}.archive must be ${expectedArchive}, got ${JSON.stringify(value.archive)}`); - } - if (typeof value.sha256 !== 'string' || !LOWER_SHA256.test(value.sha256)) { - fail(`${label}.sha256 must be a lowercase SHA-256 digest`); - } - return value; -} - function requireArchiveEntry(entries, member, archive) { const entry = entries.get(member); - if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) { + if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) fail(`${rel(archive)} must contain ${member} as one non-empty regular file`); - } return Buffer.from(entry.data()); } - -function checkedInputArchive(bytes, label) { - try { - return readPortableTarZstdBufferEntries(bytes, { label }); - } catch (cause) { - fail(cause.message); - } -} - export function wasixRuntimeNpmInputs({ portableReleaseArchive }) { const releaseArchive = path.resolve(portableReleaseArchive); regularFile(releaseArchive, 'portable WASIX release archive'); validatePortableReleaseAsset(releaseArchive); - const releaseEntries = readPortableArchiveEntries(releaseArchive); const manifestBytes = requireArchiveEntry( releaseEntries, @@ -249,190 +61,17 @@ export function wasixRuntimeNpmInputs({ portableReleaseArchive }) { WASIX_PORTABLE_RELEASE_MEMBERS.runtimeArchive, releaseArchive, ); - const manifest = parseJsonBytes( - manifestBytes, - `${rel(releaseArchive)} ${WASIX_PORTABLE_RELEASE_MEMBERS.manifest}`, - ); - if (!Array.isArray(manifest.extensions) || manifest.extensions.length !== 0) { - fail('frozen WASIX core manifest must contain an empty extensions array'); - } - if (Object.hasOwn(manifest, 'pg-dump') || Object.hasOwn(manifest, 'psql')) { - fail('frozen WASIX core manifest must not claim split tool payloads'); - } - const runtime = checkedAssetMetadata( - manifest.runtime, - WASIX_RUNTIME_ARCHIVE_PATH, - 'frozen WASIX core manifest runtime', - ); - if (sha256Bytes(runtimeBytes) !== runtime.sha256) { - fail('frozen WASIX runtime archive does not match manifest.runtime.sha256'); - } - if (runtime.size !== undefined && runtimeBytes.length !== runtime.size) { - fail('frozen WASIX runtime archive does not match manifest.runtime.size'); - } - const runtimeEntries = checkedInputArchive( - runtimeBytes, - `${rel(releaseArchive)} runtime archive`, - ); - assertCoreManifestContract(manifest, runtimeEntries); - - return Object.freeze({ - manifest: Object.freeze({ - bytes: manifestBytes, - sha256: sha256Bytes(manifestBytes), - size: manifestBytes.length, - }), - runtimeArchive: Object.freeze({ - archive: runtime.archive, - bytes: runtimeBytes, - sha256: runtime.sha256, - size: runtimeBytes.length, - }), - }); -} - -function writeJson(file, value) { - writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`, { mode: 0o644 }); - chmodSync(file, 0o644); -} - -function writeReadme(packageDir) { - writeFileSync( - path.join(packageDir, 'README.md'), - `# ${WASIX_RUNTIME_NPM_PACKAGE} - -Internal host-neutral portable runtime carrier for \`@oliphaunt/wasix-ts\`. -Application code should depend on the binding, which selects this matching -carrier automatically. The descriptor and assets can be consumed by browser -or Node/Bun/Deno/Electron WASIX hosts; importing them alone is not a host-support claim. -The public binding declares this carrier as an exact release-staged dependency; -applications do not configure its package-relative assets. - -The carried manifest retains the exact qualified core identity projection and -an empty extension inventory. Extension metadata and bytes remain in their -independently versioned \`@oliphaunt/extension-*-wasix\` packages, so an -extension release never mutates this runtime carrier. -`, - ); + return wasixRuntimeNpmPayloadInputs({ manifestBytes, runtimeBytes, label: rel(releaseArchive) }); } - export function stageWasixRuntimeNpmCarrier({ version, portableReleaseArchive, packageDir }) { - if (typeof version !== 'string' || !/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/u.test(version)) { + if (typeof version !== 'string' || !/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/u.test(version)) throw new TypeError(`${TOOL}: version must be an exact stable semantic version`); - } - const output = path.resolve(packageDir); - const inputs = wasixRuntimeNpmInputs({ portableReleaseArchive }); - rmSync(output, { recursive: true, force: true }); - mkdirSync(path.join(output, 'assets'), { recursive: true }); - for (const [name, input] of Object.entries({ - runtimeArchive: inputs.runtimeArchive, - manifest: inputs.manifest, - })) { - const destination = path.join(output, ...WASIX_RUNTIME_NPM_ASSET_PATHS[name].split('/')); - writeFileSync(destination, input.bytes, { flag: 'wx', mode: 0o644 }); - chmodSync(destination, 0o644); - } - - const descriptorInput = { version, ...inputs }; - writeFileSync(path.join(output, 'index.js'), renderWasixRuntimeDescriptorModule(descriptorInput)); - writeFileSync(path.join(output, 'index.d.ts'), renderWasixRuntimeDescriptorTypes()); - chmodSync(path.join(output, 'index.js'), 0o644); - chmodSync(path.join(output, 'index.d.ts'), 0o644); - writeReadme(output); - chmodSync(path.join(output, 'README.md'), 0o644); - stageReleaseNotices(output, NOTICE_OPTIONS); - - const noticeFiles = releaseNoticeRows(NOTICE_OPTIONS).map(({ member }) => member); - const packageJson = { - name: WASIX_RUNTIME_NPM_PACKAGE, + return stageWasixRuntimeNpmPayload({ version, - description: 'Portable liboliphaunt WASIX runtime assets for Oliphaunt hosts.', - license: releaseProfilePackageLicense('wasix-runtime').spdx, - type: 'module', - sideEffects: false, - repository: { type: 'git', url: NPM_TRUSTED_PUBLISHING_REPOSITORY }, - oliphaunt: { - product: WASIX_RUNTIME_PRODUCT, - kind: 'wasix-runtime', - runtime: 'wasix', - target: WASIX_RUNTIME_NPM_TARGET, - descriptorSchema: WASIX_RUNTIME_NPM_DESCRIPTOR_SCHEMA, - manifestProjection: 'core', - }, - publishConfig: { access: 'public', provenance: true }, - files: ['README.md', 'index.js', 'index.d.ts', 'assets', ...noticeFiles], - exports: { - '.': { types: './index.d.ts', import: './index.js', default: './index.js' }, - './package.json': './package.json', - }, - }; - validateNpmTrustedPublishingManifest( - packageJson, - `${WASIX_RUNTIME_NPM_PACKAGE} generated package`, - ); - writeJson(path.join(output, 'package.json'), packageJson); - assertReleaseNoticesInDirectory(output, NOTICE_OPTIONS); - return Object.freeze({ - descriptor: descriptorInput, - packageDir: output, - packageName: WASIX_RUNTIME_NPM_PACKAGE, + inputs: wasixRuntimeNpmInputs({ portableReleaseArchive }), + packageDir, }); } - -function packedFileEntries(entries) { - return [...entries] - .filter(([, entry]) => entry.isFile) - .map(([member]) => member) - .sort(); -} - -export function assertWasixRuntimeNpmArchive(archive, { version, descriptor }) { - const file = path.resolve(archive); - regularFile(file, 'WASIX runtime npm carrier'); - if (statSync(file).size > NPM_PACKAGE_SAFETY_LIMIT_BYTES) { - fail( - `${rel(file)} exceeds the ${NPM_PACKAGE_SAFETY_LIMIT_BYTES}-byte npm carrier safety limit`, - ); - } - assertReleaseNoticesInArchive(file, { ...NOTICE_OPTIONS, prefix: 'package' }); - const entries = readPortableArchiveEntries(file); - const expectedFiles = [ - 'package/package.json', - 'package/README.md', - 'package/index.js', - 'package/index.d.ts', - ...Object.values(WASIX_RUNTIME_NPM_ASSET_PATHS).map((member) => `package/${member}`), - ...releaseNoticeRows(NOTICE_OPTIONS).map(({ member }) => `package/${member}`), - ].sort(); - const actualFiles = packedFileEntries(entries); - if (!isDeepStrictEqual(actualFiles, expectedFiles)) { - fail(`${rel(file)} regular file inventory differs from the generated package allowlist`); - } - for (const [member, entry] of entries) { - if (entry.isSymbolicLink) fail(`${rel(file)} must not contain symbolic link ${member}`); - } - - const packageJson = parseJsonBytes( - requireArchiveEntry(entries, 'package/package.json', file), - `${rel(file)} package/package.json`, - ); - validateNpmTrustedPublishingManifest(packageJson, `${rel(file)} package/package.json`); - if (packageJson.name !== WASIX_RUNTIME_NPM_PACKAGE || packageJson.version !== version) { - fail(`${rel(file)} must identify ${WASIX_RUNTIME_NPM_PACKAGE}@${version}`); - } - for (const name of ['runtimeArchive', 'manifest']) { - const bytes = requireArchiveEntry( - entries, - `package/${WASIX_RUNTIME_NPM_ASSET_PATHS[name]}`, - file, - ); - if (bytes.length !== descriptor[name].size || sha256Bytes(bytes) !== descriptor[name].sha256) { - fail(`${rel(file)} ${name} bytes differ from the generated descriptor`); - } - } - return packageJson; -} - export function packWasixRuntimeNpmCarrier({ version, portableReleaseArchive, diff --git a/src/wasix/runtime/tools/wasix-runtime-npm-payload.mts b/src/wasix/runtime/tools/wasix-runtime-npm-payload.mts new file mode 100644 index 000000000..1accf9d3d --- /dev/null +++ b/src/wasix/runtime/tools/wasix-runtime-npm-payload.mts @@ -0,0 +1,416 @@ +#!/usr/bin/env bun + +import { createHash } from 'node:crypto'; +import { chmodSync, lstatSync, mkdirSync, rmSync, statSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { isDeepStrictEqual } from 'node:util'; + +import { + NPM_TRUSTED_PUBLISHING_REPOSITORY, + validateNpmTrustedPublishingManifest, +} from '../../../../tools/packaging/npm-trusted-publishing.mts'; +import { + readPortableArchiveEntries, + readPortableTarZstdBufferEntries, +} from '../../../../tools/packaging/portable-archive.mts'; +import { + assertReleaseNoticesInArchive, + assertReleaseNoticesInDirectory, + releaseNoticeRows, + releaseProfilePackageLicense, + stageReleaseNotices, +} from '../../../../tools/packaging/release-notices.mts'; +import { + WASIX_RUNTIME_ARCHIVE_PATH, + WASIX_RUNTIME_NPM_ASSET_PATHS, + WASIX_RUNTIME_NPM_DESCRIPTOR_SCHEMA, + WASIX_RUNTIME_NPM_PACKAGE, + WASIX_RUNTIME_NPM_TARGET, + WASIX_RUNTIME_PRODUCT, +} from './wasix-runtime-npm-contract.mts'; +import { + renderWasixRuntimeDescriptorModule, + renderWasixRuntimeDescriptorTypes, +} from './wasix-runtime-npm-descriptor.mts'; + +export { + renderWasixRuntimeDescriptorModule, + renderWasixRuntimeDescriptorTypes, +} from './wasix-runtime-npm-descriptor.mts'; + +const TOOL = 'wasix-runtime-npm-carrier.mts'; +const ROOT = path.resolve(import.meta.dirname, '../../../..'); +const LOWER_SHA256 = /^[0-9a-f]{64}$/u; +const SQL_NAME = /^[a-z0-9][a-z0-9_-]*$/u; +const RUNTIME_MODULE_MEMBER = 'oliphaunt/bin/postgres'; +const NPM_PACKAGE_SAFETY_LIMIT_BYTES = 100 * 1024 * 1024; +const NOTICE_OPTIONS = Object.freeze({ profile: 'wasix-runtime' }); + +function fail(message) { + throw new Error(`${TOOL}: ${message}`); +} + +function rel(file) { + const relative = path.relative(ROOT, file).split(path.sep).join('/'); + return relative && !relative.startsWith('../') ? relative : String(file); +} + +function sha256Bytes(bytes) { + return createHash('sha256').update(bytes).digest('hex'); +} + +function regularFile(file, label) { + let metadata; + try { + metadata = lstatSync(file); + } catch (cause) { + fail(`${label} cannot be inspected: ${cause.message}`); + } + if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size <= 0) { + fail(`${label} must be a non-empty regular non-symlink file: ${rel(file)}`); + } + return metadata; +} + +function parseJsonBytes(bytes, label) { + let value; + try { + value = JSON.parse(Buffer.from(bytes).toString('utf8')); + } catch (cause) { + fail(`${label} must contain UTF-8 JSON: ${cause.message}`); + } + if (value === null || Array.isArray(value) || typeof value !== 'object') { + fail(`${label} must contain a JSON object`); + } + return value; +} + +function object(value, label) { + if (value === null || Array.isArray(value) || typeof value !== 'object') { + fail(`${label} must be an object`); + } + return value; +} + +function nonEmptyString(value, label) { + if (typeof value !== 'string' || value.length === 0 || value.includes('\0')) { + fail(`${label} must be a non-empty string without NUL bytes`); + } + return value; +} + +function checkedSha256(value, label) { + if (typeof value !== 'string' || !LOWER_SHA256.test(value)) { + fail(`${label} must be a lowercase SHA-256 digest`); + } + return value; +} + +function safeRelativePath(value, label) { + const result = nonEmptyString(value, label); + const segments = result.split('/'); + if ( + result.startsWith('/') || + result.includes('\\') || + segments.some((segment) => segment.length === 0 || segment === '.' || segment === '..') + ) { + fail(`${label} must be a canonical safe relative path`); + } + return result; +} + +function postgresMajor(value, label) { + return nonEmptyString(value, label).split('.')[0]; +} + +function requireRegularEntry(entries, member, label) { + const entry = entries.get(member); + if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) { + fail(`${label} must contain ${member} as one non-empty regular file`); + } + return entry; +} + +/** + * Validate the complete core-manifest projection consumed by WASIX hosts. + * Keep this producer-side gate in lockstep with the binding's parser so a + * package cannot be publishable but unusable by every consumer. + */ +function assertCoreManifestContract(manifest, runtimeEntries) { + if (manifest['format-version'] !== 2) { + fail('frozen WASIX core manifest must use format-version 2'); + } + nonEmptyString(manifest['source-fingerprint'], 'frozen WASIX core manifest source-fingerprint'); + const runtime = object(manifest.runtime, 'frozen WASIX core manifest runtime'); + safeRelativePath(runtime.archive, 'frozen WASIX core manifest runtime.archive'); + checkedSha256(runtime.sha256, 'frozen WASIX core manifest runtime.sha256'); + if (runtime.size !== undefined && (!Number.isSafeInteger(runtime.size) || runtime.size <= 0)) { + fail('frozen WASIX core manifest runtime.size must be a positive safe integer when present'); + } + const runtimeModuleSha256 = checkedSha256( + runtime['module-sha256'], + 'frozen WASIX core manifest runtime.module-sha256', + ); + postgresMajor(runtime['postgres-version'], 'frozen WASIX core manifest runtime.postgres-version'); + const link = object(runtime.link, 'frozen WASIX core manifest runtime.link'); + if (!Array.isArray(link.exports)) { + fail('frozen WASIX core manifest runtime.link.exports must be an array'); + } + for (const [index, value] of link.exports.entries()) { + const entry = object(value, `frozen WASIX core manifest runtime.link.exports[${index}]`); + nonEmptyString(entry.name, `frozen WASIX core manifest runtime.link.exports[${index}].name`); + nonEmptyString(entry.kind, `frozen WASIX core manifest runtime.link.exports[${index}].kind`); + } + + if (!Array.isArray(manifest['runtime-support'])) { + fail('frozen WASIX core manifest runtime-support must be an array'); + } + const supportNames = new Set(); + const supportPaths = new Set(); + for (const [index, value] of manifest['runtime-support'].entries()) { + const entry = object(value, `frozen WASIX core manifest runtime-support[${index}]`); + const name = nonEmptyString( + entry.name, + `frozen WASIX core manifest runtime-support[${index}].name`, + ); + if (!SQL_NAME.test(name) || supportNames.has(name)) { + fail(`frozen WASIX core manifest runtime-support[${index}].name must be unique and portable`); + } + supportNames.add(name); + const supportPath = safeRelativePath( + entry.path, + `frozen WASIX core manifest runtime-support[${index}].path`, + ); + if (!supportPath.startsWith('lib/postgresql/') || supportPaths.has(supportPath)) { + fail( + `frozen WASIX core manifest runtime-support[${index}].path must be unique under lib/postgresql/`, + ); + } + supportPaths.add(supportPath); + checkedSha256(entry.sha256, `frozen WASIX core manifest runtime-support[${index}].sha256`); + } + + const runtimeModule = requireRegularEntry( + runtimeEntries, + RUNTIME_MODULE_MEMBER, + 'frozen WASIX runtime archive', + ); + if (sha256Bytes(runtimeModule.data()) !== runtimeModuleSha256) { + fail('frozen WASIX runtime module does not match manifest runtime.module-sha256'); + } +} + +function checkedAssetMetadata(value, expectedArchive, label) { + if (value === null || Array.isArray(value) || typeof value !== 'object') { + fail(`${label} must be an object`); + } + if (value.archive !== expectedArchive) { + fail(`${label}.archive must be ${expectedArchive}, got ${JSON.stringify(value.archive)}`); + } + if (typeof value.sha256 !== 'string' || !LOWER_SHA256.test(value.sha256)) { + fail(`${label}.sha256 must be a lowercase SHA-256 digest`); + } + return value; +} + +function requireArchiveEntry(entries, member, archive) { + const entry = entries.get(member); + if (entry === undefined || !entry.isFile || entry.isSymbolicLink || entry.size <= 0) { + fail(`${rel(archive)} must contain ${member} as one non-empty regular file`); + } + return Buffer.from(entry.data()); +} + +function checkedInputArchive(bytes, label) { + try { + return readPortableTarZstdBufferEntries(bytes, { label }); + } catch (cause) { + fail(cause.message); + } +} + +export function wasixRuntimeNpmPayloadInputs({ manifestBytes, runtimeBytes, label }) { + const manifest = parseJsonBytes(manifestBytes, `${label} manifest`); + if (!Array.isArray(manifest.extensions) || manifest.extensions.length !== 0) { + fail('frozen WASIX core manifest must contain an empty extensions array'); + } + if (Object.hasOwn(manifest, 'pg-dump') || Object.hasOwn(manifest, 'psql')) { + fail('frozen WASIX core manifest must not claim split tool payloads'); + } + const runtime = checkedAssetMetadata( + manifest.runtime, + WASIX_RUNTIME_ARCHIVE_PATH, + 'frozen WASIX core manifest runtime', + ); + if (sha256Bytes(runtimeBytes) !== runtime.sha256) { + fail('frozen WASIX runtime archive does not match manifest.runtime.sha256'); + } + if (runtime.size !== undefined && runtimeBytes.length !== runtime.size) { + fail('frozen WASIX runtime archive does not match manifest.runtime.size'); + } + const runtimeEntries = checkedInputArchive(runtimeBytes, `${label} runtime archive`); + assertCoreManifestContract(manifest, runtimeEntries); + + return Object.freeze({ + manifest: Object.freeze({ + bytes: manifestBytes, + sha256: sha256Bytes(manifestBytes), + size: manifestBytes.length, + }), + runtimeArchive: Object.freeze({ + archive: runtime.archive, + bytes: runtimeBytes, + sha256: runtime.sha256, + size: runtimeBytes.length, + }), + }); +} + +function writeJson(file, value) { + writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`, { mode: 0o644 }); + chmodSync(file, 0o644); +} + +function writeReadme(packageDir) { + writeFileSync( + path.join(packageDir, 'README.md'), + `# ${WASIX_RUNTIME_NPM_PACKAGE} + +Internal host-neutral portable runtime carrier for \`@oliphaunt/wasix-ts\`. +Application code should depend on the binding, which selects this matching +carrier automatically. The descriptor and assets can be consumed by browser +or Node/Bun/Deno/Electron WASIX hosts; importing them alone is not a host-support claim. +The public binding declares this carrier as an exact release-staged dependency; +applications do not configure its package-relative assets. + +The carried manifest retains the exact qualified core identity projection and +an empty extension inventory. Extension metadata and bytes remain in their +independently versioned \`@oliphaunt/extension-*-wasix\` packages, so an +extension release never mutates this runtime carrier. +`, + ); +} + +export function stageWasixRuntimeNpmPayload({ + version, + inputs, + packageDir, + noticeOptions = NOTICE_OPTIONS, +}) { + if (typeof version !== 'string' || !/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/u.test(version)) { + throw new TypeError(`${TOOL}: version must be an exact stable semantic version`); + } + const output = path.resolve(packageDir); + rmSync(output, { recursive: true, force: true }); + mkdirSync(path.join(output, 'assets'), { recursive: true }); + for (const [name, input] of Object.entries({ + runtimeArchive: inputs.runtimeArchive, + manifest: inputs.manifest, + })) { + const destination = path.join(output, ...WASIX_RUNTIME_NPM_ASSET_PATHS[name].split('/')); + writeFileSync(destination, input.bytes, { flag: 'wx', mode: 0o644 }); + chmodSync(destination, 0o644); + } + + const descriptorInput = { version, ...inputs }; + writeFileSync(path.join(output, 'index.js'), renderWasixRuntimeDescriptorModule(descriptorInput)); + writeFileSync(path.join(output, 'index.d.ts'), renderWasixRuntimeDescriptorTypes()); + chmodSync(path.join(output, 'index.js'), 0o644); + chmodSync(path.join(output, 'index.d.ts'), 0o644); + writeReadme(output); + chmodSync(path.join(output, 'README.md'), 0o644); + stageReleaseNotices(output, noticeOptions); + + const noticeFiles = releaseNoticeRows(noticeOptions).map(({ member }) => member); + const packageJson = { + name: WASIX_RUNTIME_NPM_PACKAGE, + version, + description: 'Portable liboliphaunt WASIX runtime assets for Oliphaunt hosts.', + license: releaseProfilePackageLicense('wasix-runtime', noticeOptions).spdx, + type: 'module', + sideEffects: false, + repository: { type: 'git', url: NPM_TRUSTED_PUBLISHING_REPOSITORY }, + oliphaunt: { + product: WASIX_RUNTIME_PRODUCT, + kind: 'wasix-runtime', + runtime: 'wasix', + target: WASIX_RUNTIME_NPM_TARGET, + descriptorSchema: WASIX_RUNTIME_NPM_DESCRIPTOR_SCHEMA, + manifestProjection: 'core', + }, + publishConfig: { access: 'public', provenance: true }, + files: ['README.md', 'index.js', 'index.d.ts', 'assets', ...noticeFiles], + exports: { + '.': { types: './index.d.ts', import: './index.js', default: './index.js' }, + './package.json': './package.json', + }, + }; + validateNpmTrustedPublishingManifest( + packageJson, + `${WASIX_RUNTIME_NPM_PACKAGE} generated package`, + ); + writeJson(path.join(output, 'package.json'), packageJson); + assertReleaseNoticesInDirectory(output, noticeOptions); + return Object.freeze({ + descriptor: descriptorInput, + packageDir: output, + packageName: WASIX_RUNTIME_NPM_PACKAGE, + }); +} + +function packedFileEntries(entries) { + return [...entries] + .filter(([, entry]) => entry.isFile) + .map(([member]) => member) + .sort(); +} + +export function assertWasixRuntimeNpmArchive( + archive, + { version, descriptor, noticeOptions = NOTICE_OPTIONS }, +) { + const file = path.resolve(archive); + regularFile(file, 'WASIX runtime npm carrier'); + if (statSync(file).size > NPM_PACKAGE_SAFETY_LIMIT_BYTES) { + fail( + `${rel(file)} exceeds the ${NPM_PACKAGE_SAFETY_LIMIT_BYTES}-byte npm carrier safety limit`, + ); + } + assertReleaseNoticesInArchive(file, { ...noticeOptions, prefix: 'package' }); + const entries = readPortableArchiveEntries(file); + const expectedFiles = [ + 'package/package.json', + 'package/README.md', + 'package/index.js', + 'package/index.d.ts', + ...Object.values(WASIX_RUNTIME_NPM_ASSET_PATHS).map((member) => `package/${member}`), + ...releaseNoticeRows(noticeOptions).map(({ member }) => `package/${member}`), + ].sort(); + const actualFiles = packedFileEntries(entries); + if (!isDeepStrictEqual(actualFiles, expectedFiles)) { + fail(`${rel(file)} regular file inventory differs from the generated package allowlist`); + } + for (const [member, entry] of entries) { + if (entry.isSymbolicLink) fail(`${rel(file)} must not contain symbolic link ${member}`); + } + + const packageJson = parseJsonBytes( + requireArchiveEntry(entries, 'package/package.json', file), + `${rel(file)} package/package.json`, + ); + validateNpmTrustedPublishingManifest(packageJson, `${rel(file)} package/package.json`); + if (packageJson.name !== WASIX_RUNTIME_NPM_PACKAGE || packageJson.version !== version) { + fail(`${rel(file)} must identify ${WASIX_RUNTIME_NPM_PACKAGE}@${version}`); + } + for (const name of ['runtimeArchive', 'manifest']) { + const bytes = requireArchiveEntry( + entries, + `package/${WASIX_RUNTIME_NPM_ASSET_PATHS[name]}`, + file, + ); + if (bytes.length !== descriptor[name].size || sha256Bytes(bytes) !== descriptor[name].sha256) { + fail(`${rel(file)} ${name} bytes differ from the generated descriptor`); + } + } + return packageJson; +} diff --git a/src/wasix/runtime/tools/xtask/BUILD.bazel b/src/wasix/runtime/tools/xtask/BUILD.bazel new file mode 100644 index 000000000..18cda9256 --- /dev/null +++ b/src/wasix/runtime/tools/xtask/BUILD.bazel @@ -0,0 +1,48 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files") +load("//build_defs/languages:rust.bzl", "cargo_binary", "cargo_package_env") +load("@aot_serializer_crates//:defs.bzl", serializer_crate_deps = "crate_deps") +load("@rules_rust//rust:defs.bzl", "rust_clippy_test", "rust_test") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["Cargo.toml"]) + +cargo_package_env() + +# Native Rust compilation of the existing bounded WASM metadata utility. +cargo_binary(name = "xtask", source = "src/main.rs", proc_macro_names = ["async-trait"]) + +cargo_binary( + name = "aot_serializer", + source = "src/main.rs", + features = ["aot-serializer"], + proc_macro_names = ["async-trait"], + crate_dependencies = serializer_crate_deps, + # Preserve typed native archive/runtime linking through cc_common.link. + experimental_use_cc_common_link = 1, + target_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + "@zig_sdk//libc:gnu.2.34", + ], +) + +rust_test( + name = "export_policy_test", + crate = ":xtask", + args = ["declared_"], + size = "small", +) + +rust_test( + name = "aot_target_test", + crate = ":aot_serializer", + crate_features = ["aot-serializer"], + args = ["target"], + size = "small", + experimental_use_cc_common_link = 1, +) + +rust_quality_files() + +rust_clippy_test(name = "clippy_test", targets = [":xtask", ":export_policy_test"], transitive = False, size = "small") diff --git a/src/wasix/runtime/tools/xtask/Cargo.toml b/src/wasix/runtime/tools/xtask/Cargo.toml index 368e33340..90420f9c1 100644 --- a/src/wasix/runtime/tools/xtask/Cargo.toml +++ b/src/wasix/runtime/tools/xtask/Cargo.toml @@ -9,6 +9,7 @@ publish = false [features] default = [] aot-serializer = [ + "dep:inkwell", "dep:wasmer", "wasmer/llvm", "wasmer/wasmer-artifact-create", @@ -18,6 +19,7 @@ aot-serializer = [ [dependencies] anyhow = "1" async-trait = "0.1" +inkwell = { version = "=0.9.0", default-features = false, features = ["no-libffi-linking"], optional = true } serde = { version = "1", features = ["derive"] } serde_json = "1" sha2 = "0.10" diff --git a/src/wasix/runtime/tools/xtask/src/aot_serializer.rs b/src/wasix/runtime/tools/xtask/src/aot_serializer.rs index a7eff7c42..503b43cb5 100644 --- a/src/wasix/runtime/tools/xtask/src/aot_serializer.rs +++ b/src/wasix/runtime/tools/xtask/src/aot_serializer.rs @@ -5,10 +5,12 @@ use std::fs; #[cfg(feature = "aot-serializer")] use std::io; #[cfg(feature = "aot-serializer")] +use std::num::NonZeroUsize; +#[cfg(feature = "aot-serializer")] use std::path::{Path, PathBuf}; #[cfg(feature = "aot-serializer")] -use anyhow::{Context, anyhow}; +use anyhow::{Context, anyhow, ensure}; use anyhow::{Result, bail}; #[cfg(feature = "aot-serializer")] use zstd::stream::write::Encoder as ZstdEncoder; @@ -19,7 +21,7 @@ use crate::value_after; pub(crate) fn aot_serializer(args: Vec) -> Result<()> { match args.first().map(String::as_str) { Some("serialize") => serialize_aot_cli(&args[1..]), - Some("probe") => probe_aot_serializer_in_process(), + Some("probe") => probe_aot_serializer_in_process(&args[1..]), Some(other) => bail!("unknown aot-serializer subcommand: {other}"), None => bail!( "usage: cargo run -p xtask --features aot-serializer -- aot-serializer " @@ -34,25 +36,34 @@ fn serialize_aot_cli(_args: &[String]) -> Result<()> { #[cfg(feature = "aot-serializer")] fn serialize_aot_cli(args: &[String]) -> Result<()> { + validate_aot_options(args, true)?; let input = value_after(args, "--input") .map(PathBuf::from) .ok_or_else(|| anyhow!("--input is required"))?; let output = value_after(args, "--output") .map(PathBuf::from) .ok_or_else(|| anyhow!("--output is required"))?; - serialize_aot_module(&input, &output) + serialize_aot_module( + &input, + &output, + target_from_args(args)?, + threads_from_args(args)?, + ) } #[cfg(not(feature = "aot-serializer"))] -fn probe_aot_serializer_in_process() -> Result<()> { +fn probe_aot_serializer_in_process(_args: &[String]) -> Result<()> { bail!( "xtask aot-serializer probe requires `cargo run -p xtask --features aot-serializer -- ...`" ) } #[cfg(feature = "aot-serializer")] -fn probe_aot_serializer_in_process() -> Result<()> { - let engine = llvm_aot_engine(); +fn probe_aot_serializer_in_process(args: &[String]) -> Result<()> { + validate_aot_options(args, false)?; + let target = target_from_args(args)?; + let threads = threads_from_args(args)?; + let engine = llvm_aot_engine(&target, threads); let store = wasmer::Store::new(engine.clone()); const EMPTY_WASM: &[u8] = b"\0asm\x01\0\0\0"; let module = @@ -60,15 +71,20 @@ fn probe_aot_serializer_in_process() -> Result<()> { let serialized = module .serialize() .context("serialize LLVM AOT probe module")?; - print_aot_engine_config(&engine); + print_aot_engine_config(&engine, &target, threads); println!("serialized-probe-bytes: {}", serialized.len()); Ok(()) } #[cfg(feature = "aot-serializer")] -fn serialize_aot_module(input: &Path, output: &Path) -> Result<()> { - let engine = llvm_aot_engine(); - print_aot_engine_config(&engine); +fn serialize_aot_module( + input: &Path, + output: &Path, + target: wasmer_types::target::Target, + threads: Option, +) -> Result<()> { + let engine = llvm_aot_engine(&target, threads); + print_aot_engine_config(&engine, &target, threads); println!("host-target: {}-{}", env::consts::OS, env::consts::ARCH); let store = wasmer::Store::new(engine); @@ -98,12 +114,13 @@ fn serialize_aot_module(input: &Path, output: &Path) -> Result<()> { } #[cfg(feature = "aot-serializer")] -fn llvm_aot_engine() -> wasmer::Engine { - use wasmer::sys::{CompilerConfig, EngineBuilder, Features, LLVM}; +fn llvm_aot_config(threads: Option) -> wasmer::sys::LLVM { + use wasmer::sys::{CompilerConfig, LLVM}; - let mut features = Features::new(); - features.exceptions(true); let mut llvm = LLVM::default(); + if let Some(threads) = threads { + llvm.num_threads(threads); + } if env_flag("OLIPHAUNT_WASM_WASMER_PERFMAP") { llvm.enable_perfmap(); } @@ -113,18 +130,52 @@ fn llvm_aot_engine() -> wasmer::Engine { if env_flag_default_true("OLIPHAUNT_WASM_AOT_READONLY_FUNCREF_TABLE") { llvm.enable_readonly_funcref_table(); } - EngineBuilder::new(llvm) - .set_target(Some(portable_aot_target())) + llvm +} + +#[cfg(feature = "aot-serializer")] +fn llvm_aot_engine( + target: &wasmer_types::target::Target, + threads: Option, +) -> wasmer::Engine { + use wasmer::sys::{EngineBuilder, Features}; + + let mut features = Features::new(); + features.exceptions(true); + EngineBuilder::new(llvm_aot_config(threads)) + .set_target(Some(target.clone())) .set_features(Some(features)) .engine() .into() } #[cfg(feature = "aot-serializer")] -fn portable_aot_target() -> wasmer_types::target::Target { +fn target_from_args(args: &[String]) -> Result { use wasmer_types::target::{Architecture, CpuFeature, Target, Triple}; - let triple = Triple::host(); + let mut requested = None; + for (index, argument) in args.iter().enumerate() { + if argument.starts_with("--target=") { + bail!("use --target followed by a target triple"); + } + if argument == "--target" { + ensure!(requested.is_none(), "--target may appear only once"); + let value = args + .get(index + 1) + .context("--target requires a target triple")?; + ensure!( + !value.is_empty() && !value.starts_with("--"), + "--target requires a target triple" + ); + requested = Some(value); + } + } + let triple = match requested { + Some(value) => value + .parse::() + .map_err(|error| anyhow!("invalid AOT target {value}: {error}"))?, + None => Triple::host(), + }; let mut cpu_features = CpuFeature::set(); match triple.architecture { Architecture::X86_64 => { @@ -133,24 +184,79 @@ fn portable_aot_target() -> wasmer_types::target::Target { Architecture::Aarch64(_) => { cpu_features.insert(CpuFeature::NEON); } - _ => {} + _ => bail!( + "unsupported AOT target architecture: {}", + triple.architecture + ), } - Target::new(triple, cpu_features) + Ok(Target::new(triple, cpu_features)) +} + +#[cfg(feature = "aot-serializer")] +fn threads_from_args(args: &[String]) -> Result> { + let mut requested = None; + for (index, argument) in args.iter().enumerate() { + if argument.starts_with("--threads=") { + bail!("use --threads followed by a count from 1 through 64"); + } + if argument == "--threads" { + ensure!(requested.is_none(), "--threads may appear only once"); + let value = args.get(index + 1).context("--threads requires a count")?; + let count = value + .parse::() + .context("--threads requires an integer from 1 through 64")?; + ensure!( + (1..=64).contains(&count), + "--threads must be from 1 through 64" + ); + requested = NonZeroUsize::new(count); + } + } + Ok(requested) } #[cfg(feature = "aot-serializer")] -fn print_aot_engine_config(engine: &wasmer::Engine) { - let target = portable_aot_target(); +fn validate_aot_options(args: &[String], allow_io: bool) -> Result<()> { + let mut seen = std::collections::BTreeSet::new(); + let mut arguments = args.iter(); + while let Some(option) = arguments.next() { + ensure!( + matches!(option.as_str(), "--target" | "--threads") + || (allow_io && matches!(option.as_str(), "--input" | "--output")), + "unknown AOT option {option}" + ); + ensure!(seen.insert(option), "duplicate AOT option {option}"); + let value = arguments + .next() + .with_context(|| format!("{option} requires a value"))?; + ensure!( + !value.is_empty() && !value.starts_with("--"), + "{option} requires a value" + ); + } + Ok(()) +} + +#[cfg(feature = "aot-serializer")] +fn print_aot_engine_config( + engine: &wasmer::Engine, + target: &wasmer_types::target::Target, + threads: Option, +) { println!("wasmer-engine: llvm"); println!("wasmer-engine-id: {}", engine.deterministic_id()); println!("wasmer-target-triple: {}", target.triple()); println!( "wasmer-target-cpu-features: {}", - format_aot_cpu_features(&target) + format_aot_cpu_features(target) ); println!("wasmer-feature-exceptions: enabled"); println!("wasmer-llvm-target-cpu: generic"); + println!( + "wasmer-llvm-threads: {}", + threads.map_or_else(|| "default".to_owned(), |count| count.to_string()) + ); println!( "wasmer-llvm-non-volatile-memops: {}", enabled_label(env_flag_default_true( @@ -211,3 +317,115 @@ fn env_flag_default_true(name: &str) -> bool { fn enabled_label(enabled: bool) -> &'static str { if enabled { "enabled" } else { "disabled" } } + +#[cfg(all(test, feature = "aot-serializer"))] +mod tests { + use super::*; + + #[test] + fn explicit_targets_preserve_portable_cpu_baselines() { + for (triple, baseline) in [ + ("x86_64-unknown-linux-gnu", "sse2"), + ("x86_64-pc-windows-msvc", "sse2"), + ("aarch64-apple-darwin", "neon"), + ] { + let target = target_from_args(&["--target".into(), triple.into()]).unwrap(); + assert_eq!(target.triple().to_string(), triple); + assert_eq!(format_aot_cpu_features(&target), baseline); + } + assert_eq!( + target_from_args(&[]).unwrap().triple(), + &wasmer_types::target::Triple::host() + ); + } + + #[test] + fn target_arguments_fail_closed() { + for args in [ + vec!["--target"], + vec!["--target", "--input"], + vec!["--target", "not-a-triple"], + vec!["--target", "wasm32-unknown-unknown"], + vec!["--target=invalid"], + vec![ + "--target", + "x86_64-unknown-linux-gnu", + "--target", + "aarch64-apple-darwin", + ], + ] { + assert!( + target_from_args(&args.into_iter().map(str::to_owned).collect::>()).is_err() + ); + } + } + + #[test] + fn target_thread_count_uses_the_llvm_setter_and_preserves_default() { + assert_eq!(threads_from_args(&[]).unwrap(), None); + for count in [1, 2, 64] { + let threads = threads_from_args(&["--threads".into(), count.to_string()]).unwrap(); + assert_eq!(threads.unwrap().get(), count); + assert!( + format!("{:?}", llvm_aot_config(threads)) + .contains(&format!("num_threads: {count}")) + ); + } + let default = std::thread::available_parallelism().unwrap_or(NonZeroUsize::new(1).unwrap()); + assert!( + format!("{:?}", llvm_aot_config(None)).contains(&format!("num_threads: {default}")) + ); + } + + #[test] + fn target_thread_arguments_fail_closed() { + for args in [ + vec!["--threads"], + vec!["--threads", "--input"], + vec!["--threads", "0"], + vec!["--threads", "65"], + vec!["--threads", "-1"], + vec!["--threads", "many"], + vec!["--threads", "184467440737095516160"], + vec!["--threads=2"], + vec!["--threads", "2", "--threads", "2"], + ] { + assert!( + threads_from_args(&args.into_iter().map(str::to_owned).collect::>()) + .is_err() + ); + } + } + + #[test] + fn target_cli_rejects_typos_and_ambiguous_input_options() { + assert!( + validate_aot_options( + &[ + "--target".into(), + "aarch64-apple-darwin".into(), + "--threads".into(), + "2".into() + ], + false + ) + .is_ok() + ); + for args in [ + vec!["--targte", "aarch64-apple-darwin"], + vec!["--input", "--output"], + vec!["--input", "one", "--input", "two"], + vec!["--target=triple"], + vec!["--threads", "2", "extra"], + ] { + assert!( + validate_aot_options( + &args.into_iter().map(str::to_owned).collect::>(), + true + ) + .is_err() + ); + } + assert!(validate_aot_options(&["--input".into(), "one".into()], false).is_err()); + } +} diff --git a/src/wasix/runtime/tools/xtask/src/asset_pipeline.rs b/src/wasix/runtime/tools/xtask/src/asset_pipeline.rs index 3b1b105f8..d9cbf1a70 100644 --- a/src/wasix/runtime/tools/xtask/src/asset_pipeline.rs +++ b/src/wasix/runtime/tools/xtask/src/asset_pipeline.rs @@ -812,6 +812,10 @@ fn validate_sealed_runtime_exports(runtime: &WasmLinkMetadataOut) -> Result<()> let policy_path = repo_relative_path("src/wasix/runtime/assets/generated/wasix-dl.exports"); let policy = fs::read_to_string(&policy_path) .with_context(|| format!("read {}", policy_path.display()))?; + validate_runtime_exports_from_policy(runtime, &policy) +} + +fn validate_runtime_exports_from_policy(runtime: &WasmLinkMetadataOut, policy: &str) -> Result<()> { let mut expected = policy .lines() .filter(|line| !line.is_empty()) @@ -830,6 +834,593 @@ fn validate_sealed_runtime_exports(runtime: &WasmLinkMetadataOut) -> Result<()> ensure_exact_runtime_export_surface(&actual, &expected) } +#[derive(serde::Deserialize)] +#[serde(deny_unknown_fields)] +struct DeclaredRuntimeManifestSpec { + runtime: PathBuf, + archive: PathBuf, + initdb: PathBuf, + export_policy: PathBuf, + support: Vec, + source_fingerprint: String, + postgres_version: String, + sources: Vec, +} + +#[derive(serde::Deserialize)] +#[serde(deny_unknown_fields)] +struct DeclaredRuntimeSupport { + name: String, + path: String, + source: PathBuf, +} + +fn declared_manifest_args(args: &[String]) -> Result<(PathBuf, PathBuf)> { + let mut spec = None; + let mut output = None; + let mut args = args.iter(); + while let Some(option) = args.next() { + let value = args + .next() + .ok_or_else(|| anyhow!("{option} requires a path"))?; + ensure!( + !value.is_empty() && !value.starts_with("--"), + "{option} requires a path" + ); + let field = match option.as_str() { + "--spec" => &mut spec, + "--output" => &mut output, + _ => bail!("unknown declared-manifest option {option}"), + }; + ensure!( + field.replace(PathBuf::from(value)).is_none(), + "duplicate {option}" + ); + } + let spec = spec.context("declared-manifest requires --spec")?; + let output = output.context("declared-manifest requires --output")?; + ensure!( + spec != output, + "manifest output must differ from specification input" + ); + Ok((spec, output)) +} + +fn validate_declared_source_facts( + source_fingerprint: &str, + postgres_version: &str, + sources: &[SourcePin], +) -> Result<()> { + let fingerprint = source_fingerprint.split(':').collect::>(); + let is_digest = |value: &str| { + value.len() == 64 + && value + .bytes() + .all(|byte| byte.is_ascii_digit() || (b'a'..=b'f').contains(&byte)) + }; + ensure!( + fingerprint.len() == 3 && is_digest(fingerprint[1]) && is_digest(fingerprint[2]), + "invalid declared PostgreSQL source fingerprint" + ); + ensure_eq( + postgres_version, + fingerprint[0], + "declared PostgreSQL version", + )?; + let names = sources + .iter() + .map(|source| source.name.as_str()) + .collect::>(); + ensure!( + names.len() == sources.len(), + "duplicate declared source pin" + ); + let postgres = sources + .iter() + .find(|source| source.name == "postgresql") + .context("declared sources require PostgreSQL")?; + ensure_eq( + &postgres.branch, + &format!("v{}", fingerprint[0]), + "declared PostgreSQL source branch", + )?; + ensure_eq( + &postgres.commit, + fingerprint[1], + "declared PostgreSQL source digest", + )?; + let patches = sources + .iter() + .find(|source| source.name == "oliphaunt-wasix-stable-patches") + .context("declared sources require WASIX patches")?; + ensure_eq( + &patches.commit, + fingerprint[2], + "declared PostgreSQL patch digest", + )?; + ensure_eq( + &patches.url, + POSTGRES_PATCH_SERIES_PATH, + "declared PostgreSQL patch source", + )?; + Ok(()) +} + +fn declared_runtime_manifest(spec: DeclaredRuntimeManifestSpec) -> Result { + validate_declared_source_facts( + &spec.source_fingerprint, + &spec.postgres_version, + &spec.sources, + )?; + + let runtime_link = read_wasm_link_metadata(&spec.runtime)?; + validate_module_link_metadata(&BuildModuleManifestOut { + name: "runtime:oliphaunt".to_owned(), + kind: "runtime".to_owned(), + path: String::new(), + sha256: String::new(), + link: runtime_link.clone(), + })?; + let policy = fs::read_to_string(&spec.export_policy) + .with_context(|| format!("read {}", spec.export_policy.display()))?; + validate_runtime_exports_from_policy(&runtime_link, &policy)?; + + let support_names = spec + .support + .iter() + .map(|item| item.name.as_str()) + .collect::>(); + ensure!( + support_names == BTreeSet::from(["plpgsql", "dict_snowball"]) + && support_names.len() == spec.support.len(), + "declared runtime requires exactly plpgsql and dict_snowball support modules" + ); + let mut runtime_support = Vec::new(); + for item in &spec.support { + ensure_eq( + &item.path, + &format!("lib/postgresql/{}.so", item.name), + "declared runtime support path", + )?; + let link = read_wasm_link_metadata(&item.source)?; + validate_module_link_metadata(&BuildModuleManifestOut { + name: format!("runtime-support:{}", item.name), + kind: "runtime-support".to_owned(), + path: item.path.clone(), + sha256: String::new(), + link: link.clone(), + })?; + let digest = sha256_file(&item.source)?; + runtime_support.push(BinaryAssetOut { + name: item.name.clone(), + path: item.path.clone(), + sha256: digest.clone(), + module_sha256: digest, + size: fs::metadata(&item.source)?.len(), + link, + }); + } + let links = runtime_support + .iter() + .map(|item| (item.name.clone(), item.link.clone())) + .collect::>(); + let basenames = side_module_basename_index( + spec.support + .iter() + .map(|item| (item.name.as_str(), item.source.as_path())), + )?; + for item in &runtime_support { + let providers = side_module_provider_exports(&item.name, &links, &basenames)?; + for import in item + .link + .imports + .iter() + .filter(|import| import_should_resolve_from_runtime(import)) + { + ensure!( + import_resolves_from_wasm_exports(import, &providers, &item.name)? + || import_resolves_from_wasm_exports(import, &runtime_link.exports, "runtime")?, + "declared runtime support {} has unresolved {}.{}", + item.name, + import.module, + import.name + ); + } + } + let initdb_link = read_wasm_link_metadata(&spec.initdb)?; + validate_module_link_metadata(&BuildModuleManifestOut { + name: "tool:initdb".to_owned(), + kind: "tool".to_owned(), + path: String::new(), + sha256: String::new(), + link: initdb_link.clone(), + })?; + let initdb_digest = sha256_file(&spec.initdb)?; + Ok(AssetManifestOut { + format_version: ASSET_MANIFEST_FORMAT_VERSION, + source_lane: Some(DEFAULT_SOURCE_LANE.to_owned()), + source_fingerprint: Some(spec.source_fingerprint), + runtime: RuntimeAssetOut { + archive: "oliphaunt.wasix.tar.zst".to_owned(), + sha256: sha256_file(&spec.archive)?, + module_sha256: sha256_file(&spec.runtime)?, + postgres_version: spec.postgres_version, + runtime_kind: "wasix-dynamic-main".to_owned(), + link: runtime_link, + }, + runtime_support, + pg_dump: None, + psql: None, + initdb: Some(BinaryAssetOut { + name: "initdb".to_owned(), + path: "bin/initdb.wasix.wasm".to_owned(), + sha256: initdb_digest.clone(), + module_sha256: initdb_digest, + size: fs::metadata(&spec.initdb)?.len(), + link: initdb_link, + }), + extensions: Vec::new(), + sources: spec.sources, + }) +} + +/// Pure I/O assembly of the frozen consumer manifest from explicit native outputs. +pub(crate) fn generate_declared_wasix_manifest(args: &[String]) -> Result<()> { + let (input, output) = declared_manifest_args(args)?; + let bytes = fs::read(&input).with_context(|| format!("read {}", input.display()))?; + let spec: DeclaredRuntimeManifestSpec = + serde_json::from_slice(&bytes).context("parse declared runtime manifest specification")?; + ensure!( + output != spec.runtime + && output != spec.archive + && output != spec.initdb + && output != spec.export_policy + && spec.support.iter().all(|item| item.source != output), + "manifest output must differ from all declared inputs" + ); + let manifest = declared_runtime_manifest(spec)?; + fs::write( + &output, + format!("{}\n", serde_json::to_string_pretty(&manifest)?), + ) + .with_context(|| format!("write {}", output.display()))?; + Ok(()) +} + +#[derive(serde::Deserialize)] +#[serde(deny_unknown_fields)] +struct DeclaredToolsManifestSpec { + pg_dump: PathBuf, + psql: PathBuf, + version: String, + runtime_version: String, + source_fingerprint: String, + postgres_version: String, + sources: Vec, +} + +#[derive(serde::Deserialize, serde::Serialize)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +struct DeclaredToolsManifest { + schema: String, + version: String, + runtime_version: String, + source_fingerprint: String, + pg_dump: DeclaredToolIdentity, + psql: DeclaredToolIdentity, +} + +#[derive(serde::Deserialize, serde::Serialize)] +#[serde(deny_unknown_fields)] +struct DeclaredToolIdentity { + name: String, + path: String, + sha256: String, + size: u64, +} + +fn declared_tool_identity(name: &'static str, module: &Path) -> Result { + let link = read_wasm_link_metadata(module)?; + validate_module_link_metadata(&BuildModuleManifestOut { + name: format!("tool:{name}"), + kind: "tool".to_owned(), + path: String::new(), + sha256: String::new(), + link: link.clone(), + })?; + ensure!( + link.dylink_needed.is_empty() && has_wasm_export(&link, "_start"), + "declared {name} must be a standalone WASIX command" + ); + Ok(DeclaredToolIdentity { + name: name.to_owned(), + path: format!("bin/{name}.wasix.wasm"), + sha256: sha256_file(module)?, + size: fs::metadata(module)?.len(), + }) +} + +/// Package identity for the two physical commands, without requiring the core runtime. +pub(crate) fn generate_declared_tools_manifest(args: &[String]) -> Result<()> { + let (input, output) = declared_manifest_args(args)?; + let spec: DeclaredToolsManifestSpec = serde_json::from_slice(&fs::read(&input)?) + .context("parse declared tools manifest specification")?; + ensure!( + output != spec.pg_dump && output != spec.psql, + "tools manifest output must differ from all declared inputs" + ); + validate_declared_source_facts( + &spec.source_fingerprint, + &spec.postgres_version, + &spec.sources, + )?; + for version in [&spec.version, &spec.runtime_version] { + let parts = version.split('.').collect::>(); + ensure!( + parts.len() == 3 + && parts.iter().all(|part| !part.is_empty() + && (part.len() == 1 || !part.starts_with('0')) + && part.bytes().all(|byte| byte.is_ascii_digit())), + "declared tools require stable semantic product/runtime versions" + ); + } + let manifest = DeclaredToolsManifest { + schema: "postgres-tools-wasix-portable-v1".to_owned(), + pg_dump: declared_tool_identity("pg_dump", &spec.pg_dump)?, + psql: declared_tool_identity("psql", &spec.psql)?, + version: spec.version, + runtime_version: spec.runtime_version, + source_fingerprint: spec.source_fingerprint, + }; + fs::write( + &output, + format!("{}\n", serde_json::to_string_pretty(&manifest)?), + ) + .with_context(|| format!("write {}", output.display()))?; + Ok(()) +} + +#[derive(serde::Deserialize)] +#[serde(deny_unknown_fields)] +struct DeclaredAotManifestSpec { + portable_manifest: PathBuf, + toolchain: PathBuf, + target_triple: String, + artifacts: Vec, +} + +#[derive(serde::Deserialize)] +#[serde(deny_unknown_fields)] +struct DeclaredAotArtifact { + name: String, + path: String, + image: PathBuf, + module: PathBuf, +} + +struct DeclaredAotModules { + source_lane: Option, + source_fingerprint: Option, + postgres_version: String, + modules: BTreeMap, + paths: BTreeMap, +} + +fn declared_aot_modules(file: &Path) -> Result { + let bytes = fs::read(file)?; + let value: serde_json::Value = serde_json::from_slice(&bytes)?; + if value.get("schema").is_some() { + let portable: DeclaredToolsManifest = + serde_json::from_slice(&bytes).context("parse declared portable tools manifest")?; + ensure!( + portable.schema == "postgres-tools-wasix-portable-v1", + "declared AOT requires the canonical portable tools manifest" + ); + for version in [&portable.version, &portable.runtime_version] { + let parts = version.split('.').collect::>(); + ensure!( + parts.len() == 3 + && parts.iter().all(|part| !part.is_empty() + && (part.len() == 1 || !part.starts_with('0')) + && part.bytes().all(|byte| byte.is_ascii_digit())), + "declared tools AOT requires stable product and runtime versions" + ); + } + let fingerprint = portable.source_fingerprint; + let parts = fingerprint.split(':').collect::>(); + ensure!( + parts.len() == 3 + && !parts[0].is_empty() + && parts[1..].iter().all(|part| part.len() == 64 + && part + .bytes() + .all(|byte| byte.is_ascii_hexdigit() && !byte.is_ascii_uppercase())), + "declared tools AOT requires the portable source fingerprint" + ); + let postgres_version = parts[0].to_owned(); + let mut modules = BTreeMap::new(); + let mut paths = BTreeMap::new(); + for (name, identity) in [("pg_dump", portable.pg_dump), ("psql", portable.psql)] { + ensure!( + identity.name == name + && identity.path == format!("bin/{name}.wasix.wasm") + && identity.size > 0 + && identity.sha256.len() == 64 + && identity + .sha256 + .bytes() + .all(|byte| byte.is_ascii_hexdigit() && !byte.is_ascii_uppercase()), + "declared tools AOT requires canonical physical command identities" + ); + let key = format!("tool:{name}"); + modules.insert(key.clone(), identity.sha256); + paths.insert(key, format!("{name}-llvm-opta.bin.zst")); + } + return Ok(DeclaredAotModules { + source_lane: Some(DEFAULT_SOURCE_LANE.to_owned()), + source_fingerprint: Some(fingerprint), + postgres_version, + modules, + paths, + }); + } + let portable: AssetManifestOut = + serde_json::from_slice(&bytes).context("parse declared portable runtime manifest")?; + ensure!( + portable.format_version == ASSET_MANIFEST_FORMAT_VERSION + && portable.runtime.runtime_kind == "wasix-dynamic-main" + && portable.extensions.is_empty() + && portable.pg_dump.is_none() + && portable.psql.is_none(), + "declared AOT requires the portable core runtime manifest" + ); + ensure!( + portable.source_lane.as_deref() == Some(DEFAULT_SOURCE_LANE) + && portable + .source_fingerprint + .as_ref() + .is_some_and(|value| !value.is_empty()), + "declared AOT requires the portable source lane and fingerprint" + ); + let mut modules = BTreeMap::from([( + "runtime:oliphaunt".to_owned(), + portable.runtime.module_sha256.clone(), + )]); + let initdb = portable + .initdb + .as_ref() + .context("portable manifest has no initdb")?; + modules.insert("tool:initdb".to_owned(), initdb.module_sha256.clone()); + for support in &portable.runtime_support { + ensure!( + modules + .insert( + format!("runtime-support:{}", support.name), + support.module_sha256.clone() + ) + .is_none(), + "duplicate portable runtime support module" + ); + } + let paths = BTreeMap::from( + [ + ("runtime:oliphaunt", "oliphaunt-llvm-opta.bin.zst"), + ("tool:initdb", "initdb-llvm-opta.bin.zst"), + ("runtime-support:plpgsql", "plpgsql-llvm-opta.bin.zst"), + ( + "runtime-support:dict_snowball", + "dict_snowball-llvm-opta.bin.zst", + ), + ] + .map(|(name, path)| (name.to_owned(), path.to_owned())), + ); + ensure!( + modules.keys().collect::>() == paths.keys().collect::>(), + "portable manifest must contain exactly the four runtime AOT modules" + ); + Ok(DeclaredAotModules { + source_lane: portable.source_lane, + source_fingerprint: portable.source_fingerprint, + postgres_version: portable.runtime.postgres_version, + modules, + paths, + }) +} + +fn declared_aot_manifest(spec: DeclaredAotManifestSpec) -> Result { + // Admission of the exact target is owned by the canonical Bazel target + // projection. This I/O boundary still rejects empty or path-like triples. + ensure!( + spec.target_triple.split('-').count() >= 3 + && spec.target_triple.split('-').all(|part| !part.is_empty()) + && spec + .target_triple + .bytes() + .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'_')), + "invalid declared AOT target triple" + ); + let portable = declared_aot_modules(&spec.portable_manifest)?; + let toolchain: WasixToolchainManifest = toml::from_str(&fs::read_to_string(&spec.toolchain)?) + .context("parse declared WASIX toolchain manifest")?; + ensure!( + !toolchain.toolchain.wasmer.is_empty() && !toolchain.toolchain.wasmer_wasix.is_empty(), + "declared AOT requires pinned Wasmer versions" + ); + let mut seen = BTreeSet::new(); + let mut artifacts = Vec::new(); + for item in &spec.artifacts { + let expected_path = portable + .paths + .get(item.name.as_str()) + .context("unknown declared AOT module")?; + ensure!( + seen.insert(item.name.as_str()), + "duplicate declared AOT module" + ); + ensure_eq(&item.path, expected_path, "declared AOT artifact path")?; + let module_sha256 = sha256_file(&item.module)?; + ensure_eq( + &module_sha256, + &portable.modules[&item.name], + "declared AOT portable module digest", + )?; + let raw = decode_zstd_file(&item.image)?; + ensure!(!raw.is_empty(), "declared AOT image is empty"); + artifacts.push(AotManifestArtifact { + name: item.name.clone(), + path: item.path.clone(), + sha256: sha256_file(&item.image)?, + raw_sha256: sha256_bytes(&raw), + raw_size: raw.len() as u64, + module_sha256, + compressed: true, + }); + } + ensure!( + seen == portable + .paths + .keys() + .map(String::as_str) + .collect::>(), + "declared AOT requires every portable image" + ); + artifacts.sort_by(|left, right| left.name.cmp(&right.name)); + Ok(AotManifest { + format_version: AOT_MANIFEST_FORMAT_VERSION, + source_lane: portable.source_lane, + source_fingerprint: portable.source_fingerprint, + postgres_version: Some(portable.postgres_version), + target_triple: spec.target_triple, + engine: "llvm-opta".to_owned(), + wasmer_version: toolchain.toolchain.wasmer, + wasmer_wasix_version: toolchain.toolchain.wasmer_wasix, + artifacts, + }) +} + +/// Describe physical native serializer outputs without discovering a checkout. +pub(crate) fn generate_declared_aot_manifest(args: &[String]) -> Result<()> { + let (input, output) = declared_manifest_args(args)?; + let spec: DeclaredAotManifestSpec = serde_json::from_slice(&fs::read(&input)?) + .context("parse declared AOT manifest specification")?; + ensure!( + output != spec.portable_manifest + && output != spec.toolchain + && spec + .artifacts + .iter() + .all(|item| output != item.image && output != item.module), + "AOT manifest output must differ from all declared inputs" + ); + let manifest = declared_aot_manifest(spec)?; + fs::write( + &output, + format!("{}\n", serde_json::to_string_pretty(&manifest)?), + ) + .with_context(|| format!("write {}", output.display()))?; + Ok(()) +} + fn ensure_exact_runtime_export_surface( actual: &BTreeSet, expected: &BTreeSet, @@ -1115,6 +1706,10 @@ fn wasix_export_list_from_modules(modules: &[BuildModuleManifestOut]) -> Result< .iter() .filter(|module| matches!(module.kind.as_str(), "runtime-support" | "extension")) .collect::>(); + wasix_export_list_from_side_modules(&side_modules) +} + +fn wasix_export_list_from_side_modules(side_modules: &[&BuildModuleManifestOut]) -> Result { let side_module_links = side_modules .iter() .map(|module| (module.name.clone(), module.link.clone())) @@ -1150,6 +1745,349 @@ fn wasix_export_list_from_modules(modules: &[BuildModuleManifestOut]) -> Result< Ok(required_exports.into_iter().collect::>().join("\n") + "\n") } +#[derive(Debug, PartialEq, Eq)] +struct DeclaredExportPolicyArgs { + modules: Vec<(String, PathBuf)>, + output: PathBuf, + response: PathBuf, +} + +fn declared_export_policy_args(args: &[String]) -> Result { + let mut modules = BTreeMap::new(); + let mut output = None; + let mut response = None; + let mut args = args.iter(); + while let Some(option) = args.next() { + let value = args + .next() + .ok_or_else(|| anyhow!("{option} requires a value"))?; + ensure!( + !value.is_empty() && !value.starts_with("--"), + "{option} requires a value" + ); + match option.as_str() { + "--module" => { + let (name, path) = value + .split_once('=') + .ok_or_else(|| anyhow!("--module requires name=path"))?; + ensure!( + !name.is_empty() && !path.is_empty(), + "--module requires name=path" + ); + ensure!( + modules + .insert(name.to_owned(), PathBuf::from(path)) + .is_none(), + "duplicate module {name}" + ); + } + "--output" => { + ensure!( + output.replace(PathBuf::from(value)).is_none(), + "duplicate --output" + ); + } + "--response" => { + ensure!( + response.replace(PathBuf::from(value)).is_none(), + "duplicate --response" + ); + } + _ => bail!("unknown export-policy option {option}"), + } + } + let output = output.ok_or_else(|| anyhow!("export-policy requires --output"))?; + let response = response.ok_or_else(|| anyhow!("export-policy requires --response"))?; + ensure!( + output != response, + "policy and response outputs must differ" + ); + ensure!( + modules + .values() + .all(|path| path != &output && path != &response), + "policy outputs must differ from module inputs" + ); + Ok(DeclaredExportPolicyArgs { + modules: modules.into_iter().collect(), + output, + response, + }) +} + +/// Analyze only explicitly declared modules; this command never discovers or builds assets. +pub(crate) fn generate_declared_wasix_export_policy(args: &[String]) -> Result<()> { + let args = declared_export_policy_args(args)?; + let modules = args + .modules + .iter() + .map(|(name, path)| { + let module = BuildModuleManifestOut { + name: name.clone(), + kind: "runtime-support".to_owned(), + path: path + .to_str() + .ok_or_else(|| anyhow!("module path must be UTF-8"))? + .to_owned(), + sha256: String::new(), + link: read_wasm_link_metadata(path)?, + }; + validate_module_link_metadata(&module)?; + Ok(module) + }) + .collect::>>()?; + let policy = wasix_export_list_from_side_modules(&modules.iter().collect::>())?; + let response = policy + .lines() + .map(|symbol| { + ensure!( + symbol + .bytes() + .enumerate() + .all(|(index, byte)| byte.is_ascii_alphabetic() + || byte == b'_' + || (index > 0 + && (byte.is_ascii_digit() + || byte == b'.' + || byte == b'$' + || byte == b'@'))), + "invalid linker export symbol {symbol:?}" + ); + Ok(format!("--export={symbol}\n")) + }) + .collect::>()?; + fs::write(&args.output, policy).with_context(|| format!("write {}", args.output.display()))?; + fs::write(&args.response, response) + .with_context(|| format!("write {}", args.response.display()))?; + Ok(()) +} + +#[derive(serde::Deserialize)] +#[serde(deny_unknown_fields)] +struct DeclaredExtensionLinkSpec { + sql_name: String, + runtime: PathBuf, + runtime_manifest: PathBuf, + modules: Vec, + candidate: Option, +} + +#[derive(serde::Deserialize)] +#[serde(deny_unknown_fields)] +struct DeclaredExtensionRuntimeCandidate { + runtime: PathBuf, + runtime_manifest: PathBuf, + selected_runtime: PathBuf, + selected_runtime_manifest: PathBuf, +} + +#[derive(serde::Deserialize)] +#[serde(deny_unknown_fields)] +struct DeclaredExtensionModule { + name: String, + path: PathBuf, + runtime_path: String, +} + +fn declared_extension_runtime( + runtime: &Path, + manifest: &Path, +) -> Result<(AssetManifestOut, WasmLinkMetadataOut)> { + let portable: AssetManifestOut = serde_json::from_slice(&fs::read(manifest)?)?; + ensure!( + portable.format_version == ASSET_MANIFEST_FORMAT_VERSION + && portable.runtime.runtime_kind == "wasix-dynamic-main" + && portable.source_lane.as_deref() == Some(DEFAULT_SOURCE_LANE), + "extension link requires its canonical portable runtime manifest" + ); + portable + .source_fingerprint + .as_ref() + .context("extension core source fingerprint")?; + ensure_eq( + &sha256_file(runtime)?, + &portable.runtime.module_sha256, + "extension core module digest", + )?; + let link = read_wasm_link_metadata(runtime)?; + ensure!( + serde_json::to_value(&link)? == serde_json::to_value(&portable.runtime.link)?, + "extension core link metadata differs from its physical module" + ); + Ok((portable, link)) +} + +/// Resolve one declared extension's physical side-module closure against its core. +pub(crate) fn generate_declared_extension_link(args: &[String]) -> Result<()> { + let (input, output) = declared_manifest_args(args)?; + let spec: DeclaredExtensionLinkSpec = serde_json::from_slice(&fs::read(&input)?)?; + ensure!( + !spec.sql_name.is_empty() + && spec + .sql_name + .bytes() + .all(|byte| byte.is_ascii_alphanumeric() || byte == b'_' || byte == b'-'), + "invalid declared extension SQL name" + ); + ensure!( + output != spec.runtime + && output != spec.runtime_manifest + && spec.modules.iter().all(|module| output != module.path), + "extension link output must differ from its declared inputs" + ); + if let Some(candidate) = &spec.candidate { + let inputs = [ + &input, + &spec.runtime, + &spec.runtime_manifest, + &candidate.runtime, + &candidate.runtime_manifest, + ]; + let outputs = [ + &output, + &candidate.selected_runtime, + &candidate.selected_runtime_manifest, + ]; + ensure!( + outputs.iter().copied().collect::>().len() == outputs.len() + && outputs.iter().all(|path| !inputs.contains(path) + && spec.modules.iter().all(|module| *path != &module.path)), + "extension runtime selection outputs must differ from each other and all inputs" + ); + } + let (portable, runtime_link) = + declared_extension_runtime(&spec.runtime, &spec.runtime_manifest)?; + let current = spec + .candidate + .as_ref() + .map(|candidate| { + declared_extension_runtime(&candidate.runtime, &candidate.runtime_manifest) + }) + .transpose()?; + let mut links = BTreeMap::new(); + let mut runtime_paths = BTreeSet::new(); + let mut native_modules = Vec::new(); + for module in &spec.modules { + ensure!( + module.runtime_path + == format!( + "lib/postgresql/{}", + module + .path + .file_name() + .context("extension module filename")? + .to_str() + .context("extension module filename UTF-8")? + ), + "extension module has a noncanonical runtime destination" + ); + ensure!( + runtime_paths.insert(&module.runtime_path), + "duplicate extension module destination" + ); + let link = read_wasm_link_metadata(&module.path)?; + validate_module_link_metadata(&BuildModuleManifestOut { + name: module.name.clone(), + kind: "extension".to_owned(), + path: module.path.display().to_string(), + sha256: String::new(), + link: link.clone(), + })?; + ensure!( + links.insert(module.name.clone(), link).is_none(), + "duplicate extension module name" + ); + let digest = sha256_file(&module.path)?; + native_modules.push(serde_json::json!({"name": module.name, "path": module.runtime_path, "sha256": digest, "moduleSha256": digest, "size": fs::metadata(&module.path)?.len()})); + } + ensure!( + links.contains_key(&spec.sql_name), + "extension closure has no primary SQL module" + ); + let basenames = side_module_basename_index( + spec.modules + .iter() + .map(|module| (module.name.as_str(), module.path.as_path())), + )?; + let mut imports = Vec::new(); + for module in &spec.modules { + let providers = side_module_provider_exports(&module.name, &links, &basenames)?; + for import in &links[&module.name].imports { + if !import_should_resolve_from_runtime(import) + || import_resolves_from_wasm_exports(import, &providers, &module.name)? + { + continue; + } + imports.push((module.name.as_str(), import)); + } + } + let resolve_imports = |runtime: &WasmLinkMetadataOut| -> Result<_> { + let mut required = BTreeSet::new(); + let mut missing = Vec::new(); + for (module, import) in &imports { + if let Some(name) = resolved_wasm_export_name(import, &runtime.exports, "runtime")? { + required.insert(name); + } else { + missing.push((*module, *import)); + } + } + Ok((required, missing)) + }; + let (mut required, missing) = resolve_imports(&runtime_link)?; + let mut selected = (&portable, &spec.runtime, &spec.runtime_manifest); + if let Some((module, import)) = missing.first() { + let Some((candidate_portable, candidate_link)) = ¤t else { + bail!( + "extension {} has unresolved import {}.{} ({})", + module, + import.module, + import.name, + import.kind + ); + }; + let (candidate_required, candidate_missing) = resolve_imports(candidate_link)?; + if let Some((module, import)) = candidate_missing.first() { + bail!( + "extension {} has unresolved import {}.{} ({})", + module, + import.module, + import.name, + import.kind + ); + } + required = candidate_required; + let candidate = spec + .candidate + .as_ref() + .expect("validated candidate runtime"); + selected = ( + candidate_portable, + &candidate.runtime, + &candidate.runtime_manifest, + ); + } + native_modules.sort_by(|left, right| left["name"].as_str().cmp(&right["name"].as_str())); + let mut result = serde_json::json!({"schema": "oliphaunt-declared-wasix-extension-link-v1", "sqlName": spec.sql_name, + "nativeModules": native_modules, "coreExportsRequired": required, "unresolvedImports": [], "moduleLinkMetadata": links, + "sourceFingerprint": selected.0.source_fingerprint.as_ref().context("extension core source fingerprint")?, "postgresVersion": selected.0.runtime.postgres_version}); + if let Some(candidate) = &spec.candidate { + result["runtimeSelection"] = serde_json::json!({ + "kind": if missing.is_empty() { "completed-publication" } else { "current-source" }, + "declaredModuleSha256": portable.runtime.module_sha256, + "currentModuleSha256": current.as_ref().expect("validated candidate runtime").0.runtime.module_sha256, + "selectedModuleSha256": selected.0.runtime.module_sha256, + "missingExports": missing.iter().map(|(_, import)| &import.name).collect::>(), + }); + fs::copy(selected.1, &candidate.selected_runtime)?; + fs::copy(selected.2, &candidate.selected_runtime_manifest)?; + } + fs::write( + output, + format!("{}\n", serde_json::to_string_pretty(&result)?), + )?; + Ok(()) +} + pub(crate) fn required_runtime_abi_exports() -> &'static [&'static str] { REQUIRED_RUNTIME_ABI_EXPORTS } @@ -2558,6 +3496,819 @@ fn extension_control_files_for_asset_manifest( mod tests { use super::*; + #[test] + fn declared_export_policy_rejects_ambiguous_arguments() { + for arguments in [ + vec!["--output"], + vec!["--output", "--response"], + vec!["--unknown", "value"], + vec!["--module", "missing-separator"], + vec!["--module", "=path"], + vec!["--module", "name="], + vec!["--module", "one=file", "--module", "one=other"], + vec!["--output", "one", "--output", "two"], + vec!["--output", "same", "--response", "same"], + vec![ + "--module", + "one=input", + "--output", + "input", + "--response", + "other", + ], + ] { + let arguments = arguments.into_iter().map(str::to_owned).collect::>(); + assert!( + declared_export_policy_args(&arguments).is_err(), + "{arguments:?}" + ); + } + } + + #[test] + fn declared_export_policy_analyzes_only_explicit_wasm_inputs() { + let directory = + std::env::temp_dir().join(format!("oliphaunt-export-policy-{}", std::process::id())); + fs::create_dir_all(&directory).expect("create isolated fixture directory"); + let module = directory.join("plugin.so"); + // Independently encoded valid WASM: a dylink.0 side module imports + // env.backend, and reexports that function as plugin. + let wasm = b"\0asm\x01\0\0\0\0\x0f\x08dylink.0\x01\x04\0\0\0\0\x01\x04\x01\x60\0\0\x02\x0f\x01\x03env\x07backend\0\0\x07\x0a\x01\x06plugin\0\0"; + fs::write(&module, wasm).expect("write independent WASM fixture"); + let output = directory.join("exports"); + let response = directory.join("exports.rsp"); + let arguments = vec![ + "--module".to_owned(), + format!("plugin={}", module.display()), + "--output".to_owned(), + output.to_str().unwrap().to_owned(), + "--response".to_owned(), + response.to_str().unwrap().to_owned(), + ]; + generate_declared_wasix_export_policy(&arguments).expect("derive compiled import policy"); + let policy = fs::read_to_string(&output).expect("read export policy"); + assert!(policy.lines().any(|symbol| symbol == "backend")); + assert!(!policy.lines().any(|symbol| symbol == "plugin")); + for abi in REQUIRED_RUNTIME_ABI_EXPORTS { + assert!(policy.lines().any(|symbol| symbol == *abi)); + } + assert_eq!( + fs::read_to_string(&response).unwrap(), + policy + .lines() + .map(|symbol| format!("--export={symbol}\n")) + .collect::() + ); + let first = fs::read(&output).unwrap(); + generate_declared_wasix_export_policy(&arguments).expect("repeat deterministic policy"); + assert_eq!(fs::read(&output).unwrap(), first); + fs::write(&module, b"invalid WASM").expect("replace malformed input"); + assert!(generate_declared_wasix_export_policy(&arguments).is_err()); + fs::remove_dir_all(directory).expect("remove fixture directory"); + } + + #[test] + fn declared_extension_link_binds_physical_core_and_side_module() { + let directory = + std::env::temp_dir().join(format!("oliphaunt-extension-link-{}", std::process::id())); + fs::create_dir_all(&directory).unwrap(); + let module = directory.join("plugin.so"); + fs::write(&module, b"\0asm\x01\0\0\0\0\x0f\x08dylink.0\x01\x04\0\0\0\0\x01\x04\x01\x60\0\0\x02\x0f\x01\x03env\x07backend\0\0\x07\x0a\x01\x06plugin\0\0").unwrap(); + let runtime = directory.join("postgres.wasm"); + fs::write(&runtime, b"\0asm\x01\0\0\0\x01\x04\x01\x60\0\0\x03\x02\x01\0\x07\x0b\x01\x07backend\0\0\x0a\x04\x01\x02\0\x0b").unwrap(); + let manifest = directory.join("manifest.json"); + let portable = serde_json::json!({"format-version": ASSET_MANIFEST_FORMAT_VERSION, "source-lane": "stable", "source-fingerprint": "18.4:declared-test", + "runtime": {"archive": "oliphaunt.wasix.tar.zst", "sha256": "a".repeat(64), "module-sha256": sha256_file(&runtime).unwrap(), "postgres-version": "18.4", "runtime-kind": "wasix-dynamic-main", "link": read_wasm_link_metadata(&runtime).unwrap()}, "runtime-support": [], "extensions": [], "sources": []}); + fs::write(&manifest, serde_json::to_vec(&portable).unwrap()).unwrap(); + let spec = directory.join("spec.json"); + let mut inputs = serde_json::json!({"sql_name": "plugin", "runtime": runtime, "runtime_manifest": manifest, "modules": [{"name": "plugin", "path": module, "runtime_path": "lib/postgresql/plugin.so"}]}); + fs::write(&spec, serde_json::to_vec(&inputs).unwrap()).unwrap(); + let output = directory.join("link.json"); + let args = [ + "--spec".to_owned(), + spec.display().to_string(), + "--output".to_owned(), + output.display().to_string(), + ]; + generate_declared_extension_link(&args).unwrap(); + let first = fs::read(&output).unwrap(); + let result: serde_json::Value = serde_json::from_slice(&first).unwrap(); + assert!(result.get("runtimeSelection").is_none()); + assert_eq!( + result["coreExportsRequired"], + serde_json::json!(["backend"]) + ); + assert_eq!( + result["nativeModules"][0]["moduleSha256"], + sha256_file(&module).unwrap() + ); + generate_declared_extension_link(&args).unwrap(); + assert_eq!(fs::read(&output).unwrap(), first); + inputs["sql_name"] = serde_json::json!("uuid-ossp"); + inputs["modules"][0]["name"] = serde_json::json!("uuid-ossp"); + fs::write(&spec, serde_json::to_vec(&inputs).unwrap()).unwrap(); + generate_declared_extension_link(&args).unwrap(); + let hyphenated: serde_json::Value = + serde_json::from_slice(&fs::read(&output).unwrap()).unwrap(); + assert_eq!(hyphenated["sqlName"], "uuid-ossp"); + for name in [ + "", + "../plugin", + "uuid/ossp", + "uuid ossp", + "uuid'ossp", + "uuid.ossÏ€", + ] { + inputs["sql_name"] = serde_json::json!(name); + fs::write(&spec, serde_json::to_vec(&inputs).unwrap()).unwrap(); + assert!( + generate_declared_extension_link(&args) + .unwrap_err() + .to_string() + .contains("invalid declared extension SQL name") + ); + } + inputs["sql_name"] = serde_json::json!("plugin"); + inputs["modules"][0]["name"] = serde_json::json!("plugin"); + inputs["modules"][0]["runtime_path"] = serde_json::json!("../plugin.so"); + fs::write(&spec, serde_json::to_vec(&inputs).unwrap()).unwrap(); + assert!(generate_declared_extension_link(&args).is_err()); + inputs["modules"][0]["runtime_path"] = serde_json::json!("lib/postgresql/plugin.so"); + fs::write(&spec, serde_json::to_vec(&inputs).unwrap()).unwrap(); + let original_module = fs::read(&module).unwrap(); + let mut unresolved_module = original_module.clone(); + let position = unresolved_module + .windows(7) + .position(|bytes| bytes == b"backend") + .unwrap(); + unresolved_module[position..position + 7].copy_from_slice(b"missing"); + fs::write(&module, unresolved_module).unwrap(); + assert!( + generate_declared_extension_link(&args) + .unwrap_err() + .to_string() + .contains("unresolved import env.missing") + ); + fs::write(&module, original_module).unwrap(); + let mut wrong_link = portable.clone(); + wrong_link["runtime"]["link"]["exports"][0]["name"] = serde_json::json!("invented"); + fs::write(&manifest, serde_json::to_vec(&wrong_link).unwrap()).unwrap(); + assert!(generate_declared_extension_link(&args).is_err()); + fs::write(&manifest, serde_json::to_vec(&portable).unwrap()).unwrap(); + fs::write(&runtime, b"invalid core bytes").unwrap(); + assert!(generate_declared_extension_link(&args).is_err()); + fs::remove_dir_all(directory).unwrap(); + } + + #[test] + fn declared_extension_link_prefers_published_and_selects_current_only_for_missing_exports() { + let directory = std::env::temp_dir().join(format!( + "oliphaunt-extension-runtime-selection-{}", + std::process::id() + )); + fs::create_dir_all(&directory).unwrap(); + let module = directory.join("plugin.so"); + // The same function is imported directly and through GOT.func, matching + // callbacks taken by real side modules. Missing names must be unique. + fs::write(&module, b"\0asm\x01\0\0\0\0\x0f\x08dylink.0\x01\x04\0\0\0\0\x01\x04\x01\x60\0\0\x02\x23\x02\x03env\x07backend\0\0\x08GOT.func\x07backend\x03\x7f\x01\x07\x0a\x01\x06plugin\0\0").unwrap(); + let core = b"\0asm\x01\0\0\0\x01\x04\x01\x60\0\0\x03\x02\x01\0\x07\x0b\x01\x07backend\0\0\x0a\x04\x01\x02\0\x0b"; + let declared = directory.join("declared.wasm"); + let declared_manifest = directory.join("declared.json"); + let current = directory.join("current.wasm"); + let current_manifest = directory.join("current.json"); + fs::write(&declared, core).unwrap(); + let mut current_bytes = core.to_vec(); + current_bytes.extend_from_slice(b"\0\x08\x07current"); + fs::write(¤t, ¤t_bytes).unwrap(); + let write_manifest = |runtime: &Path, manifest: &Path, fingerprint: &str| { + let value = serde_json::json!({"format-version": ASSET_MANIFEST_FORMAT_VERSION, "source-lane": "stable", "source-fingerprint": fingerprint, + "runtime": {"archive": "oliphaunt.wasix.tar.zst", "sha256": "a".repeat(64), "module-sha256": sha256_file(runtime).unwrap(), "postgres-version": fingerprint, "runtime-kind": "wasix-dynamic-main", "link": read_wasm_link_metadata(runtime).unwrap()}, "runtime-support": [], "extensions": [], "sources": []}); + fs::write(manifest, serde_json::to_vec(&value).unwrap()).unwrap(); + }; + write_manifest(&declared, &declared_manifest, "18.4:declared"); + write_manifest(¤t, ¤t_manifest, "18.5:current"); + let selected = directory.join("selected.wasm"); + let selected_manifest = directory.join("selected.json"); + let spec = directory.join("spec.json"); + let output = directory.join("link.json"); + let mut inputs = serde_json::json!({"sql_name": "plugin", "runtime": declared, "runtime_manifest": declared_manifest, + "modules": [{"name": "plugin", "path": module, "runtime_path": "lib/postgresql/plugin.so"}], + "candidate": {"runtime": current, "runtime_manifest": current_manifest, "selected_runtime": selected, "selected_runtime_manifest": selected_manifest}}); + let args = [ + "--spec".to_owned(), + spec.display().to_string(), + "--output".to_owned(), + output.display().to_string(), + ]; + let run = |inputs: &serde_json::Value| { + fs::write(&spec, serde_json::to_vec(inputs).unwrap()).unwrap(); + generate_declared_extension_link(&args) + }; + let result = || -> serde_json::Value { + serde_json::from_slice(&fs::read(&output).unwrap()).unwrap() + }; + run(&inputs).unwrap(); + let published = result(); + assert_eq!( + published["runtimeSelection"], + serde_json::json!({ + "kind": "completed-publication", "declaredModuleSha256": sha256_file(&declared).unwrap(), + "currentModuleSha256": sha256_file(¤t).unwrap(), "selectedModuleSha256": sha256_file(&declared).unwrap(), "missingExports": [] + }) + ); + assert_ne!( + sha256_file(&declared).unwrap(), + sha256_file(¤t).unwrap() + ); + assert_eq!(published["sourceFingerprint"], "18.4:declared"); + assert_eq!(published["postgresVersion"], "18.4:declared"); + assert_eq!(fs::read(&selected).unwrap(), fs::read(&declared).unwrap()); + assert_eq!( + fs::read(&selected_manifest).unwrap(), + fs::read(&declared_manifest).unwrap() + ); + + // Even an unused candidate must authenticate its physical bytes/link. + for (runtime, manifest) in [ + (&declared, &declared_manifest), + (¤t, ¤t_manifest), + ] { + let original = fs::read(manifest).unwrap(); + let mut value: serde_json::Value = serde_json::from_slice(&original).unwrap(); + for field in ["module-sha256", "link"] { + value["runtime"][field] = if field == "module-sha256" { + serde_json::json!("0".repeat(64)) + } else { + serde_json::json!({}) + }; + fs::write(manifest, serde_json::to_vec(&value).unwrap()).unwrap(); + assert!(run(&inputs).is_err()); + value = serde_json::from_slice(&original).unwrap(); + } + fs::write(manifest, &original).unwrap(); + let bytes = fs::read(runtime).unwrap(); + fs::write(runtime, b"invalid core bytes").unwrap(); + assert!(run(&inputs).is_err()); + fs::write(runtime, bytes).unwrap(); + } + + let mut missing_core = core.to_vec(); + let position = missing_core + .windows(7) + .position(|bytes| bytes == b"backend") + .unwrap(); + missing_core[position..position + 7].copy_from_slice(b"legacy_"); + fs::write(&declared, &missing_core).unwrap(); + write_manifest(&declared, &declared_manifest, "18.4:declared"); + run(&inputs).unwrap(); + let needed = result(); + assert_eq!( + needed["runtimeSelection"], + serde_json::json!({ + "kind": "current-source", "declaredModuleSha256": sha256_file(&declared).unwrap(), + "currentModuleSha256": sha256_file(¤t).unwrap(), "selectedModuleSha256": sha256_file(¤t).unwrap(), "missingExports": ["backend"] + }) + ); + assert_eq!( + needed["coreExportsRequired"], + serde_json::json!(["backend"]) + ); + assert_eq!(needed["sourceFingerprint"], "18.5:current"); + assert_eq!(needed["postgresVersion"], "18.5:current"); + assert_eq!(fs::read(&selected).unwrap(), current_bytes); + assert_eq!( + fs::read(&selected_manifest).unwrap(), + fs::read(¤t_manifest).unwrap() + ); + // A candidate must also retain imports that the declared core supplied. + let original_module = fs::read(&module).unwrap(); + fs::write(&module, b"\0asm\x01\0\0\0\0\x0f\x08dylink.0\x01\x04\0\0\0\0\x01\x04\x01\x60\0\0\x02\x31\x03\x03env\x07backend\0\0\x08GOT.func\x07backend\x03\x7f\x01\x03env\x07legacy_\0\0\x07\x0a\x01\x06plugin\0\0").unwrap(); + assert!( + run(&inputs) + .unwrap_err() + .to_string() + .contains("unresolved import env.legacy_") + ); + fs::write(&module, original_module).unwrap(); + let mut strict = inputs.clone(); + strict.as_object_mut().unwrap().remove("candidate"); + // Link metadata orders GOT.func before env, so this is the first + // unresolved import even though both reference the same symbol. + assert!( + run(&strict) + .unwrap_err() + .to_string() + .contains("unresolved import GOT.func.backend (global)") + ); + + fs::write(¤t, &missing_core).unwrap(); + write_manifest(¤t, ¤t_manifest, "18.5:current"); + assert!( + run(&inputs) + .unwrap_err() + .to_string() + .contains("unresolved import GOT.func.backend (global)") + ); + + let wrong_kind = + b"\0asm\x01\0\0\0\x06\x06\x01\x7f\0\x41\0\x0b\x07\x0b\x01\x07backend\x03\0"; + fs::write(¤t, wrong_kind).unwrap(); + write_manifest(¤t, ¤t_manifest, "18.5:current"); + assert!( + run(&inputs) + .unwrap_err() + .to_string() + .contains("expected func") + ); + fs::write(¤t, core).unwrap(); + write_manifest(¤t, ¤t_manifest, "18.5:current"); + fs::write(&declared, wrong_kind).unwrap(); + write_manifest(&declared, &declared_manifest, "18.4:declared"); + assert!( + run(&inputs) + .unwrap_err() + .to_string() + .contains("expected func") + ); + + fs::write(&declared, core).unwrap(); + write_manifest(&declared, &declared_manifest, "18.4:declared"); + for collision in [ + &spec, + &declared, + &declared_manifest, + ¤t, + ¤t_manifest, + &module, + &output, + &selected_manifest, + ] { + inputs["candidate"]["selected_runtime"] = serde_json::json!(collision); + assert!(run(&inputs).is_err(), "{}", collision.display()); + } + fs::remove_dir_all(directory).unwrap(); + } + + #[test] + fn declared_manifest_rejects_ambiguous_arguments() { + for arguments in [ + vec![], + vec!["--spec"], + vec!["--spec", "--output"], + vec!["--spec", "file", "--output", "file"], + vec!["--unknown", "file"], + vec!["--spec", "one", "--spec", "two"], + vec!["--spec", "file", "--output", "one", "--output", "two"], + ] { + assert!( + declared_manifest_args( + &arguments.into_iter().map(str::to_owned).collect::>() + ) + .is_err() + ); + } + } + + #[test] + fn declared_manifest_uses_physical_modules_and_rejects_stale_facts() { + fn uleb(mut value: usize, bytes: &mut Vec) { + loop { + let byte = (value & 0x7f) as u8; + value >>= 7; + bytes.push(byte | if value == 0 { 0 } else { 0x80 }); + if value == 0 { + return; + } + } + } + fn main_wasm(exports: &[String]) -> Vec { + // Independent encoder: one () -> () function with explicit aliases. + let mut wasm = b"\0asm\x01\0\0\0\x01\x04\x01\x60\0\0\x03\x02\x01\0".to_vec(); + let mut section = Vec::new(); + uleb(exports.len(), &mut section); + for name in exports { + uleb(name.len(), &mut section); + section.extend(name.bytes()); + section.extend([0, 0]); + } + wasm.push(7); + uleb(section.len(), &mut wasm); + wasm.extend(section); + wasm.extend([10, 4, 1, 2, 0, 11]); + wasm + } + let root = std::env::temp_dir().join(format!( + "oliphaunt-declared-manifest-{}", + std::process::id() + )); + fs::create_dir_all(&root).unwrap(); + let runtime = root.join("postgres.wasm"); + let initdb = root.join("initdb.wasm"); + let archive = root.join("runtime.tar.zst"); + let policy = root.join("exports"); + let exports = REQUIRED_RUNTIME_ABI_EXPORTS + .iter() + .chain(WASIX_LINKER_RUNTIME_EXPORTS) + .map(|name| (*name).to_owned()) + .chain(std::iter::once("backend".to_owned())) + .collect::>() + .into_iter() + .collect::>(); + fs::write(&runtime, main_wasm(&exports)).unwrap(); + fs::write(&initdb, main_wasm(&["_start".to_owned()])).unwrap(); + fs::write(&archive, b"physical archive bytes").unwrap(); + fs::write( + &policy, + REQUIRED_RUNTIME_ABI_EXPORTS + .iter() + .map(|name| format!("{name}\n")) + .chain(std::iter::once("backend\n".to_owned())) + .collect::(), + ) + .unwrap(); + let side = b"\0asm\x01\0\0\0\0\x0f\x08dylink.0\x01\x04\0\0\0\0\x01\x04\x01\x60\0\0\x02\x0f\x01\x03env\x07backend\0\0\x07\x0a\x01\x06plugin\0\0"; + let support = ["plpgsql", "dict_snowball"].map(|name| { + let source = root.join(format!("{name}.so")); + fs::write(&source, side).unwrap(); + serde_json::json!({"name": name, "path": format!("lib/postgresql/{name}.so"), "source": source}) + }); + let source_hash = "a".repeat(64); + let patch_hash = "b".repeat(64); + let spec = serde_json::json!({ + "runtime": runtime, "initdb": initdb, "archive": archive, "export_policy": policy, "support": support, + "source_fingerprint": format!("42.8:{source_hash}:{patch_hash}"), "postgres_version": "42.8", + "sources": [ + {"name": "postgresql", "url": "https://source.test/pg.tar.bz2", "branch": "v42.8", "commit": source_hash}, + {"name": "oliphaunt-wasix-stable-patches", "url": POSTGRES_PATCH_SERIES_PATH, "branch": "series", "commit": patch_hash}, + ], + }); + let input = root.join("spec.json"); + let output = root.join("manifest.json"); + let args = [ + "--spec".to_owned(), + input.to_str().unwrap().to_owned(), + "--output".to_owned(), + output.to_str().unwrap().to_owned(), + ]; + fs::write(&input, serde_json::to_vec(&spec).unwrap()).unwrap(); + generate_declared_wasix_manifest(&args).unwrap(); + let bytes = fs::read(&output).unwrap(); + let manifest: AssetManifestOut = serde_json::from_slice(&bytes).unwrap(); + assert_eq!( + manifest.runtime.module_sha256, + sha256_file(&runtime).unwrap() + ); + assert_eq!(manifest.runtime.sha256, sha256_file(&archive).unwrap()); + assert_eq!(manifest.runtime.postgres_version, "42.8"); + assert_eq!(manifest.runtime_support.len(), 2); + assert_eq!( + manifest.initdb.unwrap().module_sha256, + sha256_file(&initdb).unwrap() + ); + generate_declared_wasix_manifest(&args).unwrap(); + assert_eq!(bytes, fs::read(&output).unwrap()); + for mutate in [ + "unknown", + "source-digest", + "version", + "version-label", + "support-path", + "missing-support", + "missing-input", + ] { + let mut invalid = spec.clone(); + match mutate { + "unknown" => invalid["undeclared"] = serde_json::json!(true), + "source-digest" => { + invalid["sources"][0]["commit"] = serde_json::json!("c".repeat(64)) + } + "version" => invalid["postgres_version"] = serde_json::json!("42.9"), + "version-label" => { + invalid["postgres_version"] = serde_json::json!("42.8-wasix-oliphaunt") + } + "support-path" => invalid["support"][0]["path"] = serde_json::json!("../outside"), + "missing-support" => invalid["support"] + .as_array_mut() + .unwrap() + .pop() + .map(|_| ()) + .unwrap(), + "missing-input" => invalid["initdb"] = serde_json::json!(root.join("missing.wasm")), + _ => unreachable!(), + } + fs::write(&input, serde_json::to_vec(&invalid).unwrap()).unwrap(); + assert!(generate_declared_wasix_manifest(&args).is_err(), "{mutate}"); + } + fs::write(&input, serde_json::to_vec(&spec).unwrap()).unwrap(); + fs::write(&runtime, main_wasm(&["_start".to_owned()])).unwrap(); + assert!(generate_declared_wasix_manifest(&args).is_err()); + fs::write(&runtime, b"invalid WASM").unwrap(); + assert!(generate_declared_wasix_manifest(&args).is_err()); + fs::remove_dir_all(root).unwrap(); + } + + #[test] + fn declared_tools_manifest_checks_physical_commands_and_independent_versions() { + let root = + std::env::temp_dir().join(format!("oliphaunt-declared-tools-{}", std::process::id())); + fs::create_dir_all(&root).unwrap(); + let pg_dump = root.join("pg_dump.wasm"); + let psql = root.join("psql.wasm"); + // Independent WASM fixture: one empty function exported as _start. + let command = b"\0asm\x01\0\0\0\x01\x04\x01\x60\0\0\x03\x02\x01\0\x07\x0a\x01\x06_start\0\0\x0a\x04\x01\x02\0\x0b"; + fs::write(&pg_dump, command).unwrap(); + fs::write(&psql, command).unwrap(); + let source_hash = "a".repeat(64); + let patch_hash = "b".repeat(64); + let spec = serde_json::json!({ + "pg_dump": pg_dump, "psql": psql, "version": "2.3.4", "runtime_version": "7.8.9", + "source_fingerprint": format!("42.8:{source_hash}:{patch_hash}"), "postgres_version": "42.8", + "sources": [ + {"name": "postgresql", "url": "https://source.test/pg.tar.bz2", "branch": "v42.8", "commit": source_hash}, + {"name": "oliphaunt-wasix-stable-patches", "url": POSTGRES_PATCH_SERIES_PATH, "branch": "series", "commit": patch_hash}, + ], + }); + let input = root.join("spec.json"); + let output = root.join("manifest.json"); + let args = [ + "--spec".to_owned(), + input.to_str().unwrap().to_owned(), + "--output".to_owned(), + output.to_str().unwrap().to_owned(), + ]; + fs::write(&input, serde_json::to_vec(&spec).unwrap()).unwrap(); + generate_declared_tools_manifest(&args).unwrap(); + let bytes = fs::read(&output).unwrap(); + let manifest: serde_json::Value = serde_json::from_slice(&bytes).unwrap(); + assert_eq!(manifest["schema"], "postgres-tools-wasix-portable-v1"); + assert_eq!(manifest["version"], "2.3.4"); + assert_eq!(manifest["runtimeVersion"], "7.8.9"); + assert_eq!(manifest["pgDump"]["path"], "bin/pg_dump.wasix.wasm"); + assert_eq!(manifest["psql"]["size"], command.len()); + assert_eq!( + manifest["pgDump"]["sha256"], + format!("{:x}", Sha256::digest(command)) + ); + generate_declared_tools_manifest(&args).unwrap(); + assert_eq!(bytes, fs::read(&output).unwrap()); + for mutate in [ + "unknown", + "version", + "runtime-version", + "source-digest", + "missing-input", + ] { + let mut invalid = spec.clone(); + match mutate { + "unknown" => invalid["undeclared"] = serde_json::json!(true), + "version" => invalid["version"] = serde_json::json!("2.3"), + "runtime-version" => invalid["runtime_version"] = serde_json::json!("07.8.9"), + "source-digest" => { + invalid["sources"][0]["commit"] = serde_json::json!("c".repeat(64)) + } + "missing-input" => invalid["psql"] = serde_json::json!(root.join("missing.wasm")), + _ => unreachable!(), + } + fs::write(&input, serde_json::to_vec(&invalid).unwrap()).unwrap(); + assert!(generate_declared_tools_manifest(&args).is_err(), "{mutate}"); + } + fs::write(&input, serde_json::to_vec(&spec).unwrap()).unwrap(); + let mut no_start = command.to_vec(); + let position = no_start + .windows(6) + .position(|name| name == b"_start") + .unwrap(); + no_start[position..position + 6].copy_from_slice(b"other!"); + fs::write(&psql, no_start).unwrap(); + assert!(generate_declared_tools_manifest(&args).is_err()); + fs::write(&psql, b"invalid WASM").unwrap(); + assert!(generate_declared_tools_manifest(&args).is_err()); + fs::write(&psql, command).unwrap(); + let mut collision = args.clone(); + collision[3] = psql.to_str().unwrap().to_owned(); + assert!(generate_declared_tools_manifest(&collision).is_err()); + fs::remove_dir_all(root).unwrap(); + } + + #[test] + fn declared_tools_aot_uses_only_its_two_commands_and_rejects_cross_family_inputs() { + let root = std::env::temp_dir().join(format!( + "oliphaunt-declared-tools-aot-{}", + std::process::id() + )); + fs::create_dir_all(&root).unwrap(); + let portable_path = root.join("tools.json"); + let toolchain = root.join("toolchain.toml"); + fs::write( + &toolchain, + "[toolchain]\nwasmer = '9.8.7'\nwasmer-wasix = '0.987.0'\n", + ) + .unwrap(); + let mut artifacts = Vec::new(); + let mut identities = serde_json::Map::new(); + for (key, name) in [("pgDump", "pg_dump"), ("psql", "psql")] { + let module = root.join(format!("{name}.wasm")); + let image = root.join(format!("{name}.bin.zst")); + fs::write(&module, format!("portable command {name}")).unwrap(); + fs::write( + &image, + zstd::stream::encode_all(format!("AOT command {name}").as_bytes(), 19).unwrap(), + ) + .unwrap(); + identities.insert(key.to_owned(), serde_json::json!({"name": name, "path": format!("bin/{name}.wasix.wasm"), "sha256": sha256_file(&module).unwrap(), "size": fs::metadata(&module).unwrap().len()})); + artifacts.push(serde_json::json!({"name": format!("tool:{name}"), "path": format!("{name}-llvm-opta.bin.zst"), "image": image, "module": module})); + } + let mut portable = serde_json::json!({"schema": "postgres-tools-wasix-portable-v1", "version": "0.2.4", "runtimeVersion": "0.3.2", "sourceFingerprint": format!("18.4:{}:{}", "a".repeat(64), "b".repeat(64))}); + portable.as_object_mut().unwrap().extend(identities); + fs::write(&portable_path, serde_json::to_vec(&portable).unwrap()).unwrap(); + let spec = serde_json::json!({"portable_manifest": portable_path, "toolchain": toolchain, "target_triple": "aarch64-apple-darwin", "artifacts": artifacts}); + let input = root.join("spec.json"); + let output = root.join("manifest.json"); + let args = [ + "--spec".to_owned(), + input.to_str().unwrap().to_owned(), + "--output".to_owned(), + output.to_str().unwrap().to_owned(), + ]; + fs::write(&input, serde_json::to_vec(&spec).unwrap()).unwrap(); + generate_declared_aot_manifest(&args).unwrap(); + let first = fs::read(&output).unwrap(); + let manifest: AotManifest = serde_json::from_slice(&first).unwrap(); + assert_eq!( + manifest + .artifacts + .iter() + .map(|row| row.name.as_str()) + .collect::>(), + ["tool:pg_dump", "tool:psql"] + ); + assert_eq!(manifest.postgres_version.as_deref(), Some("18.4")); + assert_eq!(manifest.target_triple, "aarch64-apple-darwin"); + generate_declared_aot_manifest(&args).unwrap(); + assert_eq!(first, fs::read(&output).unwrap()); + for case in ["family", "schema", "missing", "module", "duplicate", "path"] { + let mut invalid = spec.clone(); + match case { + "family" => { + invalid["artifacts"][0]["name"] = serde_json::json!("runtime:oliphaunt") + } + "schema" => { + let mut invalid_portable = portable.clone(); + invalid_portable["schema"] = serde_json::json!("unknown"); + fs::write( + &portable_path, + serde_json::to_vec(&invalid_portable).unwrap(), + ) + .unwrap(); + } + "missing" => { + invalid["artifacts"].as_array_mut().unwrap().pop(); + } + "module" => { + invalid["artifacts"][0]["module"] = invalid["artifacts"][1]["module"].clone() + } + "duplicate" => invalid["artifacts"][0] = invalid["artifacts"][1].clone(), + "path" => invalid["artifacts"][0]["path"] = serde_json::json!("../outside"), + _ => unreachable!(), + } + fs::write(&input, serde_json::to_vec(&invalid).unwrap()).unwrap(); + assert!(generate_declared_aot_manifest(&args).is_err(), "{case}"); + fs::write(&portable_path, serde_json::to_vec(&portable).unwrap()).unwrap(); + } + fs::remove_dir_all(root).unwrap(); + } + + #[test] + fn declared_aot_manifest_records_physical_images_and_rejects_mismatches() { + let root = + std::env::temp_dir().join(format!("oliphaunt-declared-aot-{}", std::process::id())); + fs::create_dir_all(&root).unwrap(); + let portable_path = root.join("portable.json"); + let toolchain = root.join("toolchain.toml"); + fs::write( + &toolchain, + "[toolchain]\nwasmer = '9.8.7'\nwasmer-wasix = '0.987.0'\n", + ) + .unwrap(); + let names = [ + ("runtime:oliphaunt", "oliphaunt"), + ("tool:initdb", "initdb"), + ("runtime-support:plpgsql", "plpgsql"), + ("runtime-support:dict_snowball", "dict_snowball"), + ]; + let mut artifacts = Vec::new(); + let mut digests = BTreeMap::new(); + for (name, stem) in names { + let module = root.join(format!("{stem}.wasm")); + let image = root.join(format!("{stem}.bin.zst")); + fs::write(&module, format!("physical portable {name}")).unwrap(); + fs::write( + &image, + zstd::stream::encode_all(format!("physical AOT {name}").as_bytes(), 19).unwrap(), + ) + .unwrap(); + digests.insert(stem, sha256_file(&module).unwrap()); + artifacts.push(serde_json::json!({ + "name": name, "path": format!("{stem}-llvm-opta.bin.zst"), "image": image, "module": module, + })); + } + let link = serde_json::to_value(WasmLinkMetadataOut::default()).unwrap(); + let binary = |name: &str| { + serde_json::json!({ + "name": name, "path": format!("lib/postgresql/{name}.so"), "sha256": digests[name], + "module-sha256": digests[name], "size": 1, "link": link, + }) + }; + let portable = serde_json::json!({ + "format-version": ASSET_MANIFEST_FORMAT_VERSION, "source-lane": DEFAULT_SOURCE_LANE, + "source-fingerprint": "physical source identity", + "runtime": {"archive": "oliphaunt.wasix.tar.zst", "sha256": "archive digest", "module-sha256": digests["oliphaunt"], + "postgres-version": "42.8-wasix-oliphaunt", "runtime-kind": "wasix-dynamic-main", "link": link}, + "runtime-support": [binary("plpgsql"), binary("dict_snowball")], "initdb": binary("initdb"), "extensions": [], "sources": [], + }); + fs::write(&portable_path, serde_json::to_vec(&portable).unwrap()).unwrap(); + let spec = serde_json::json!({ + "portable_manifest": portable_path, "toolchain": toolchain, + "target_triple": "x86_64-pc-windows-msvc", "artifacts": artifacts, + }); + let input = root.join("spec.json"); + let output = root.join("manifest.json"); + let args = [ + "--spec".to_owned(), + input.to_str().unwrap().to_owned(), + "--output".to_owned(), + output.to_str().unwrap().to_owned(), + ]; + fs::write(&input, serde_json::to_vec(&spec).unwrap()).unwrap(); + generate_declared_aot_manifest(&args).unwrap(); + let bytes = fs::read(&output).unwrap(); + let manifest: AotManifest = serde_json::from_slice(&bytes).unwrap(); + assert_eq!(manifest.format_version, AOT_MANIFEST_FORMAT_VERSION); + assert_eq!(manifest.target_triple, "x86_64-pc-windows-msvc"); + assert_eq!(manifest.wasmer_version, "9.8.7"); + assert_eq!(manifest.wasmer_wasix_version, "0.987.0"); + assert_eq!( + manifest.source_fingerprint.as_deref(), + Some("physical source identity") + ); + assert_eq!( + manifest.postgres_version.as_deref(), + Some("42.8-wasix-oliphaunt") + ); + assert_eq!(manifest.artifacts.len(), 4); + for artifact in &manifest.artifacts { + let raw = format!("physical AOT {}", artifact.name); + assert_eq!(artifact.raw_sha256, sha256_bytes(raw.as_bytes())); + assert_eq!(artifact.raw_size, raw.len() as u64); + assert!(artifact.compressed); + } + generate_declared_aot_manifest(&args).unwrap(); + assert_eq!(bytes, fs::read(&output).unwrap()); + for case in [ + "unknown", + "target", + "module", + "path", + "missing", + "duplicate", + "missing-image", + ] { + let mut invalid = spec.clone(); + match case { + "unknown" => invalid["undeclared"] = serde_json::json!(true), + "target" => invalid["target_triple"] = serde_json::json!("../outside"), + "module" => { + invalid["artifacts"][0]["module"] = invalid["artifacts"][1]["module"].clone() + } + "path" => invalid["artifacts"][0]["path"] = serde_json::json!("../outside"), + "missing" => { + invalid["artifacts"].as_array_mut().unwrap().pop(); + } + "duplicate" => invalid["artifacts"][0] = invalid["artifacts"][1].clone(), + "missing-image" => { + invalid["artifacts"][0]["image"] = serde_json::json!(root.join("missing")) + } + _ => unreachable!(), + } + fs::write(&input, serde_json::to_vec(&invalid).unwrap()).unwrap(); + assert!(generate_declared_aot_manifest(&args).is_err(), "{case}"); + } + fs::write(&input, serde_json::to_vec(&spec).unwrap()).unwrap(); + let mut invalid = portable.clone(); + invalid["format-version"] = serde_json::json!(999); + fs::write(&portable_path, serde_json::to_vec(&invalid).unwrap()).unwrap(); + assert!(generate_declared_aot_manifest(&args).is_err()); + fs::write(&portable_path, serde_json::to_vec(&portable).unwrap()).unwrap(); + let image = PathBuf::from(spec["artifacts"][0]["image"].as_str().unwrap()); + fs::write(&image, b"corrupt compressed image").unwrap(); + assert!(generate_declared_aot_manifest(&args).is_err()); + fs::write(&image, zstd::stream::encode_all(&b""[..], 19).unwrap()).unwrap(); + assert!(generate_declared_aot_manifest(&args).is_err()); + fs::write(&toolchain, "invalid TOML").unwrap(); + assert!(generate_declared_aot_manifest(&args).is_err()); + fs::remove_dir_all(root).unwrap(); + } + fn manifest_extension_metadata( create_extension: bool, control_files: Vec<&str>, diff --git a/src/wasix/runtime/tools/xtask/src/main.rs b/src/wasix/runtime/tools/xtask/src/main.rs index 7b1c1f830..6716e1462 100644 --- a/src/wasix/runtime/tools/xtask/src/main.rs +++ b/src/wasix/runtime/tools/xtask/src/main.rs @@ -151,6 +151,11 @@ fn assets(args: Vec) -> Result<()> { let source_lane = value_after(&args, "--source-lane").unwrap_or(DEFAULT_SOURCE_LANE); generate_wasix_export_list(write, source_lane) } + Some("export-policy") => generate_declared_wasix_export_policy(&args[1..]), + Some("declared-extension-link") => generate_declared_extension_link(&args[1..]), + Some("declared-manifest") => generate_declared_wasix_manifest(&args[1..]), + Some("declared-tools-manifest") => generate_declared_tools_manifest(&args[1..]), + Some("declared-aot-manifest") => generate_declared_aot_manifest(&args[1..]), Some("prepare-aot") => { let target = value_after(&args, "--target-triple").unwrap_or(host_target_triple()); let source_lane = value_after(&args, "--source-lane").unwrap_or(DEFAULT_SOURCE_LANE); @@ -216,4 +221,9 @@ fn print_usage() { eprintln!(" cargo run -p xtask -- assets package-extension-aot [--target-triple ]"); eprintln!(" cargo run -p xtask -- assets check-aot [--target-triple ]"); eprintln!(" cargo run -p xtask -- assets export-list [--write]"); + eprintln!( + " xtask assets export-policy --module ... --output --response " + ); + eprintln!(" xtask assets declared-manifest --spec --output "); + eprintln!(" xtask assets declared-aot-manifest --spec --output "); } diff --git a/src/wasix/sdks/rust/BUILD.bazel b/src/wasix/sdks/rust/BUILD.bazel new file mode 100644 index 000000000..ae896922a --- /dev/null +++ b/src/wasix/sdks/rust/BUILD.bazel @@ -0,0 +1,158 @@ +load("//build_defs/quality:sources.bzl", "rust_quality_files", "source_quality_files") +load("//build_defs/languages:rust.bzl", "cargo_doc_test", "cargo_generator", "cargo_integration_test", "cargo_library", "cargo_library_test", "cargo_package_env") +load("@rules_rust//rust:defs.bzl", "rust_clippy_test", "rust_library") +load("//build_defs/languages:source.bzl", "cargo_source_contract_test", "cargo_source_package") +load("@oliphaunt_metadata//:metadata.bzl", "CONTRIB_MEMBERS", "PRODUCTS") +load("//build_defs/resources:resources.bzl", "wasix_sdk_resource_test") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") +load("//build_defs/release:supplier.bzl", "shipping_suppliers") +load("@wasix_tool_metadata//:targets.bzl", "WASIX_AOT_TARGETS") + +package(default_visibility = ["//visibility:public"]) +exports_files(["Cargo.toml", "THIRD_PARTY_NOTICES.md"]) + +rust_library( + name = "shipping_supplier_fixture", + testonly = True, + srcs = ["tools/testdata/shipping_supplier_fixture.rs"], + edition = "2024", + tags = ["manual"], +) + +PATH_DEPS = { + "liboliphaunt-wasix-portable": "@wasix_runtime_carriers//src/wasix/runtime/crates/assets:lib", + "liboliphaunt-wasix-aot-x86_64-unknown-linux-gnu": "@wasix_runtime_carriers//src/wasix/runtime/crates/aot/x86_64-unknown-linux-gnu:lib", + "liboliphaunt-wasix-aot-aarch64-unknown-linux-gnu": "@wasix_runtime_carriers//src/wasix/runtime/crates/aot/aarch64-unknown-linux-gnu:lib", + "liboliphaunt-wasix-aot-aarch64-apple-darwin": "@wasix_runtime_carriers//src/wasix/runtime/crates/aot/aarch64-apple-darwin:lib", + "liboliphaunt-wasix-aot-x86_64-pc-windows-msvc": "@wasix_runtime_carriers//src/wasix/runtime/crates/aot/x86_64-pc-windows-msvc:lib", +} + +cargo_package_env() +cargo_generator(path_dependencies = PATH_DEPS, proc_macro_names = ["async-trait"]) +cargo_library(path_dependencies = PATH_DEPS, proc_macro_names = ["async-trait"], build_script = ":build_script") +cargo_generator(name = "napi_build_script", path_dependencies = PATH_DEPS, features = ["__internal-napi"], proc_macro_names = ["async-trait"]) +cargo_library(name = "napi_lib", path_dependencies = PATH_DEPS, proc_macro_names = ["async-trait"], build_script = ":napi_build_script", features = ["__internal-napi"]) +_UNIT_TEST_DATA = ["//src/test-fixtures:rust_fixtures", "//src/database-resources:cluster_seed_contract_fixtures"] +cargo_library_test(data = _UNIT_TEST_DATA) + +_CONTRIB_FEATURES = ["extension-" + member["sql-name"].replace("_", "-") for member in CONTRIB_MEMBERS] +cargo_generator(name = "extension_carrier_build_script", path_dependencies = PATH_DEPS, features = _CONTRIB_FEATURES, proc_macro_names = ["async-trait"]) +cargo_library(name = "extension_carrier_lib", path_dependencies = PATH_DEPS, proc_macro_names = ["async-trait"], build_script = ":extension_carrier_build_script", features = _CONTRIB_FEATURES) +cargo_library_test(name = "extension_carrier_unit_test", crate = ":extension_carrier_lib", features = _CONTRIB_FEATURES, rustc_env = {"OLIPHAUNT_DECLARED_CONTRIB_SQL_NAMES": json.encode([member["sql-name"] for member in CONTRIB_MEMBERS])}, path_dependencies = PATH_DEPS, data = _UNIT_TEST_DATA, tags = ["manual"]) +_CONTRIB_TOOLS_FEATURES = _CONTRIB_FEATURES + ["tools-execution"] +_NAPI_RELEASE_FEATURES = ["__internal-napi"] + _CONTRIB_TOOLS_FEATURES +_NAPI_RELEASE_PATH_DEPS = PATH_DEPS | {"liboliphaunt-wasix-portable": "//src/wasix/runtime/crates/assets:napi_release_lib"} +cargo_generator(name = "napi_release_build_script", path_dependencies = _NAPI_RELEASE_PATH_DEPS, features = _NAPI_RELEASE_FEATURES, proc_macro_names = ["async-trait"]) +cargo_library(name = "napi_release_lib", path_dependencies = _NAPI_RELEASE_PATH_DEPS, proc_macro_names = ["async-trait"], build_script = ":napi_release_build_script", features = _NAPI_RELEASE_FEATURES) +shipping_suppliers(name = "napi_release_compiled_suppliers", inputs = []) +filegroup(name = "napi_release_compiled_files", srcs = ["//src/wasix/node-addon:release_addon"], output_group = "sdk_compiled") +shipping_package( + name = "napi_release_compiled_shipping", + owner = "@oliphaunt_metadata//:product_oliphaunt-wasix-rust", + artifacts = [":napi_release_compiled_files"], ecosystem = "internal", package_name = "oliphaunt-wasix", + configuration = select({"@rules_rust//rust/platform:" + triple: target for target, triple in WASIX_AOT_TARGETS.items()}), + role = "compiled-source", suppliers = ":napi_release_compiled_suppliers", +) +shipping_export(name = "napi_release_compiled_shipping_export", packages = [":napi_release_compiled_shipping"], qualification = ["//src/wasix/node-addon:release_installed_test"], testonly = True) +cargo_library(name = "extension_carrier_tools_lib", path_dependencies = PATH_DEPS, proc_macro_names = ["async-trait"], build_script = ":extension_carrier_build_script", features = _CONTRIB_TOOLS_FEATURES) +cargo_library_test(name = "extension_carrier_tools_unit_test", crate = ":extension_carrier_tools_lib", features = _CONTRIB_TOOLS_FEATURES, rustc_env = {"OLIPHAUNT_DECLARED_CONTRIB_SQL_NAMES": json.encode([member["sql-name"] for member in CONTRIB_MEMBERS]), "OLIPHAUNT_DECLARED_TOOLS_VERSION": PRODUCTS["postgres-tools-wasix"]["version"]}, path_dependencies = PATH_DEPS, data = _UNIT_TEST_DATA, tags = ["manual"]) + +# The host lane executes one representative module, rather than repeating the +# exhaustive contrib lifecycle on each native executor. Tools are supplied as +# final declared Files, so this variant does not construct WASIX tools locally. +_HOST_SMOKE_FEATURES = ["extension-uuid-ossp", "tools-execution"] +cargo_generator(name = "host_aot_smoke_build_script", path_dependencies = PATH_DEPS, features = _HOST_SMOKE_FEATURES, proc_macro_names = ["async-trait"]) +cargo_library(name = "host_aot_smoke_lib", path_dependencies = PATH_DEPS, proc_macro_names = ["async-trait"], build_script = ":host_aot_smoke_build_script", features = _HOST_SMOKE_FEATURES) +cargo_library_test(name = "host_aot_smoke_unit_test", crate = ":host_aot_smoke_lib", features = _HOST_SMOKE_FEATURES, rustc_env = {"OLIPHAUNT_DECLARED_CONTRIB_SQL_NAMES": json.encode(["uuid-ossp"]), "OLIPHAUNT_DECLARED_TOOLS_VERSION": PRODUCTS["postgres-tools-wasix"]["version"]}, path_dependencies = PATH_DEPS, data = _UNIT_TEST_DATA, tags = ["manual"]) + +_QUALITY_PATH_DEPS = { + name: "//" + label.split("//", 1)[1].removesuffix(":lib") + ":quality_lib" + for name, label in PATH_DEPS.items() +} +_TOOLS_PATH_DEPS = _QUALITY_PATH_DEPS | { + "oliphaunt-wasix-tools": "//src/wasix/postgres-tools:portable_cargo_lib", + "oliphaunt-wasix-tools-aot-aarch64-unknown-linux-gnu": "//src/wasix/postgres-tools:aot_linux_arm64_gnu_cargo_lib", + "oliphaunt-wasix-tools-aot-x86_64-unknown-linux-gnu": "//src/wasix/postgres-tools:aot_linux_x64_gnu_cargo_lib", + "oliphaunt-wasix-tools-aot-aarch64-apple-darwin": "//src/wasix/postgres-tools:aot_macos_arm64_cargo_lib", + "oliphaunt-wasix-tools-aot-x86_64-pc-windows-msvc": "//src/wasix/postgres-tools:aot_windows_x64_msvc_cargo_lib", +} +cargo_generator(name = "quality_build_script", path_dependencies = _QUALITY_PATH_DEPS, proc_macro_names = ["async-trait"]) +cargo_library(name = "quality_lib", path_dependencies = _QUALITY_PATH_DEPS, proc_macro_names = ["async-trait"], build_script = ":quality_build_script") +cargo_library_test(name = "quality_unit_test", crate = ":quality_lib", data = _UNIT_TEST_DATA) +cargo_generator(name = "tools_build_script", path_dependencies = _TOOLS_PATH_DEPS, proc_macro_names = ["async-trait"], features = ["tools"]) +cargo_library(name = "tools_lib", path_dependencies = _TOOLS_PATH_DEPS, proc_macro_names = ["async-trait"], build_script = ":tools_build_script", features = ["extensions", "tools", "extension-vector"]) +# Runtime integration consumes the genuine constructed payloads. The quality +# library deliberately permits absent payloads and cannot qualify execution. +cargo_library(name = "runtime_test_lib", path_dependencies = PATH_DEPS, proc_macro_names = ["async-trait"], build_script = ":build_script", features = ["extensions"]) +_RESOURCE_PATH_DEPS = PATH_DEPS | {"oliphaunt-icu": "//src/database-resources/icu:icu_cargo_lib"} +cargo_library(name = "resource_test_lib", path_dependencies = _RESOURCE_PATH_DEPS, proc_macro_names = ["async-trait"], build_script = ":build_script", features = ["icu"]) +cargo_doc_test(crate = ":quality_lib", size = "small") +cargo_doc_test(name = "tools_doc_test", crate = ":tools_lib", features = ["tools"], size = "small") +_INTEGRATION_ROOTS = glob(["tests/*.rs"]) +# These roots use the constructed runtime carriers, unlike the source-only +# quality library/tool generators. Qualify their Clippy targets once with WASIX. +_CONSTRUCTED_INTEGRATION_ROOTS = ["tests/resources.rs", "tests/runtime_smoke.rs"] +[ + cargo_integration_test( + name = "quality_" + source.removeprefix("tests/").removesuffix(".rs") + "_test", + source = source, + crate = ":tools_lib" if source == "tests/public_api.rs" else ":runtime_test_lib" if source == "tests/runtime_smoke.rs" else ":resource_test_lib" if source == "tests/resources.rs" else ":quality_lib", + features = ["extensions", "tools", "extension-vector"] if source == "tests/public_api.rs" else ["extensions"] if source == "tests/runtime_smoke.rs" else ["icu"] if source == "tests/resources.rs" else [], + path_dependencies = _TOOLS_PATH_DEPS if source == "tests/public_api.rs" else _RESOURCE_PATH_DEPS if source == "tests/resources.rs" else PATH_DEPS if source == "tests/runtime_smoke.rs" else _QUALITY_PATH_DEPS, + proc_macro_names = ["async-trait"], + data = ["//src/test-fixtures:rust_fixtures"], + tags = ["manual"], + ) + for source in _INTEGRATION_ROOTS +] +rust_clippy_test( + name = "clippy_test", + targets = [":quality_lib", ":quality_unit_test", ":quality_build_script_"] + [":quality_" + source.removeprefix("tests/").removesuffix(".rs") + "_test" for source in _INTEGRATION_ROOTS if source not in _CONSTRUCTED_INTEGRATION_ROOTS], + transitive = False, + size = "small", +) +rust_clippy_test( + name = "constructed_clippy_test", + targets = [":quality_" + source.removeprefix("tests/").removesuffix(".rs") + "_test" for source in _CONSTRUCTED_INTEGRATION_ROOTS], + transitive = False, + size = "small", +) +cargo_integration_test( + name = "postgres_regression_test", + source = "tests/postgres_regression.rs", + path_dependencies = PATH_DEPS, + proc_macro_names = ["async-trait"], + data = ["//src/test-fixtures:rust_fixtures"], + size = "large", + timeout = "long", + tags = ["manual"], +) +wasix_sdk_resource_test(name = "resource_api_test") + +cargo_source_package( + product = "oliphaunt-wasix-rust", + fixtures = "src/testdata/", + qualification = [ + ":source_package_test", + "//build_defs/languages/installed:wasix_sdk_source_compile_test", + ":quality_unit_test", + ":constructed_clippy_test", + ":quality_public_api_test", + ":doc_test", + ":tools_doc_test", + ":quality_runtime_smoke_test", + ":postgres_regression_test", + ":resource_api_test", + "//build_defs/extensions/wasix:contrib_incremental_installed_test", + ], +) +cargo_source_contract_test( + name = "source_package_test", + packages = [":crate"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + size = "small", +) + +source_quality_files() + +rust_quality_files() diff --git a/src/wasix/sdks/rust/Cargo.toml b/src/wasix/sdks/rust/Cargo.toml index a47f56288..811c4d31f 100644 --- a/src/wasix/sdks/rust/Cargo.toml +++ b/src/wasix/sdks/rust/Cargo.toml @@ -14,6 +14,7 @@ license = "MIT" links = "oliphaunt_artifact_wasix_relay" build = "build.rs" exclude = [ + "BUILD.bazel", "Cargo.toml.orig", "moon.yml", "release.toml", @@ -22,6 +23,8 @@ exclude = [ [package.metadata.oliphaunt] runtime-version = "0.3.2" +tools-version = "0.2.4" +icu-version = "0.2.2" [features] default = [] @@ -82,7 +85,7 @@ extension-vector = ["extensions", "liboliphaunt-wasix-portable/extension-vector" icu = ["dep:oliphaunt-icu"] [dependencies] -oliphaunt-query = { version = "0.1.1", path = "../../../query/rust" } +oliphaunt-query = { version = "=0.1.1" } anyhow = "1" async-trait = "0.1" cap-fs-ext = "4" diff --git a/src/wasix/sdks/rust/README.md b/src/wasix/sdks/rust/README.md index c557dec31..96e257f32 100644 --- a/src/wasix/sdks/rust/README.md +++ b/src/wasix/sdks/rust/README.md @@ -8,7 +8,7 @@ Host WebAssembly PostgreSQL in a Rust application. The synchronous handle must b cargo add oliphaunt-wasix ``` -The [quickstart](https://oliphaunt.dev/docs/sdk/wasix-rust) covers prerequisites and the versions documented by the current site. Pin dependencies in your application manifest or lockfile. +The [quickstart](https://oliphaunt.dev/docs/sdk/wasix-rust) covers prerequisites. Pin dependencies in your application manifest or lockfile. ## First query diff --git a/src/wasix/sdks/rust/moon.yml b/src/wasix/sdks/rust/moon.yml index ad463bff4..1b6f34308 100644 --- a/src/wasix/sdks/rust/moon.yml +++ b/src/wasix/sdks/rust/moon.yml @@ -49,7 +49,7 @@ tasks: tags: ["regression", "runtime", "requires-rust", "ci-wasix-release-regression"] command: "bash src/wasix/runtime/tools/runtime-smoke.sh regression" deps: [{target: "cargo-sources", cacheStrategy: hash}, "liboliphaunt-wasix:runtime-aot", "extension-artifacts-wasix:build-target", "extension-artifacts-wasix:build-aot", "postgres-tools-wasix:build-aot"] - inputs: ["@group(code)", "@group(cargo-workspace)", "/src/wasix/runtime/tools/{runtime-smoke,runtime-preflight,cargo-test-filter}.sh", "/src/wasix/runtime/tools/wasix-extension-features.mts", "/src/extensions/artifacts/packages/tools/**/*"] + inputs: ["@group(code)", "@group(cargo-workspace)", "/src/wasix/runtime/tools/{runtime-smoke,runtime-preflight,cargo-test-filter}.sh", "/src/wasix/runtime/tools/{wasix-extension-features,source-server-qualification}.mts", "/tools/packaging/cargo-manifest.mts", "/src/wasix/node-addon/Cargo.toml", "/src/wasix/pgwire-server/Cargo.toml", "/src/wasix/pgwire-server/README.md", "/src/wasix/pgwire-server/src/**/*.rs", "/src/wasix/pgwire-server/tests/**/*.rs", "/src/test-fixtures/extensions/**/*", "/src/extensions/catalog/extensions.source.json", "/src/extensions/artifacts/packages/tools/**/*"] options: {runFromWorkspaceRoot: true, cache: false} test-integration: tags: ["runtime", "integration", "requires-rust", "ci-wasix-release-regression", "platform-linux-x64-gnu"] diff --git a/src/wasix/sdks/rust/release.toml b/src/wasix/sdks/rust/release.toml index 5c280ed86..e0a13d4f6 100644 --- a/src/wasix/sdks/rust/release.toml +++ b/src/wasix/sdks/rust/release.toml @@ -12,6 +12,18 @@ source_product = "liboliphaunt-wasix" path = "src/wasix/sdks/rust/Cargo.toml" parser = "toml:package.metadata.oliphaunt.runtime-version" +[compatibility_versions.tools] +public_support = false +source_product = "postgres-tools-wasix" +path = "src/wasix/sdks/rust/Cargo.toml" +parser = "toml:package.metadata.oliphaunt.tools-version" + +[compatibility_versions.icu] +public_support = false +source_product = "database-resources" +path = "src/wasix/sdks/rust/Cargo.toml" +parser = "toml:package.metadata.oliphaunt.icu-version" + [compatibility_versions.oliphaunt-wasix-rust-query] public_support = false source_product = "oliphaunt-query" diff --git a/src/wasix/sdks/rust/src/oliphaunt/base.rs b/src/wasix/sdks/rust/src/oliphaunt/base.rs index 623fcd44c..358742ba0 100644 --- a/src/wasix/sdks/rust/src/oliphaunt/base.rs +++ b/src/wasix/sdks/rust/src/oliphaunt/base.rs @@ -1187,8 +1187,14 @@ fn validate_cluster_seed_manifest_metadata( "embedded cluster seed has an incompatible WASIX physical identity" ); ensure!( - manifest.runtime.consumer_sha256 == manifest.runtime.producer_sha256, - "embedded cluster seed producer and consumer runtime digests differ" + [ + &manifest.runtime.consumer_sha256, + &manifest.runtime.producer_sha256, + &manifest.runtime.initdb_sha256, + ] + .iter() + .all(|digest| digest.len() == 64 && digest.bytes().all(|byte| byte.is_ascii_hexdigit())), + "embedded cluster seed runtime digests are invalid" ); ensure!( !manifest.archive.path.is_empty() @@ -2376,6 +2382,14 @@ mod tests { }); let seed = ClusterSeed::new(archive.as_slice(), serde_json::to_vec(&manifest)?); validate_selected_cluster_seed(&seed, CatalogProfile::Standard)?; + manifest["runtime"]["producerSha256"] = "a".repeat(64).into(); + manifest["runtime"]["initdbSha256"] = "b".repeat(64).into(); + let adopted = ClusterSeed::new(archive.as_slice(), serde_json::to_vec(&manifest)?); + validate_selected_cluster_seed(&adopted, CatalogProfile::Standard)?; + manifest["runtime"]["producerSha256"] = "invalid-original-producer".into(); + let malformed = ClusterSeed::new(archive.as_slice(), serde_json::to_vec(&manifest)?); + assert!(validate_selected_cluster_seed(&malformed, CatalogProfile::Standard).is_err()); + manifest["runtime"]["producerSha256"] = "a".repeat(64).into(); assert!(validate_selected_cluster_seed(&seed, CatalogProfile::Icu).is_err()); let changed = ClusterSeed::new(b"changed resource bytes".as_slice(), seed.manifest.clone()); assert!(validate_selected_cluster_seed(&changed, CatalogProfile::Standard).is_err()); diff --git a/src/wasix/sdks/rust/src/oliphaunt/extensions.rs b/src/wasix/sdks/rust/src/oliphaunt/extensions.rs index 706da0bbe..34f9a5dbf 100644 --- a/src/wasix/sdks/rust/src/oliphaunt/extensions.rs +++ b/src/wasix/sdks/rust/src/oliphaunt/extensions.rs @@ -369,7 +369,7 @@ mod extension_tests { use crate::DatabaseStorage; use crate::Oliphaunt; use anyhow::{Context, Result, ensure}; - use std::collections::{BTreeMap, BTreeSet}; + use std::collections::BTreeSet; use std::path::{Path, PathBuf}; #[test] @@ -382,6 +382,324 @@ mod extension_tests { run_lifecycle_materialization_set(Extension::ALL) } + #[allow(unsafe_code)] + fn declared_contrib_extensions() -> Result> { + use serde::Deserialize; + use sha2::{Digest, Sha256}; + + #[derive(Deserialize)] + #[serde(rename_all = "camelCase", deny_unknown_fields)] + struct Packet { + product: String, + version: String, + runtime_version: String, + archives: Vec, + aot_manifest: PathBuf, + aot_artifacts: Vec, + core_module_sha256: String, + core_manifest: PathBuf, + } + + #[derive(Deserialize)] + #[serde(rename_all = "camelCase", deny_unknown_fields)] + struct Archive { + sql_name: String, + path: PathBuf, + sha256: String, + } + + #[derive(Deserialize)] + #[serde(deny_unknown_fields)] + struct AotArtifact { + path: String, + source: PathBuf, + } + + let packet_path = std::env::var_os("OLIPHAUNT_DECLARED_EXTENSION_PACKET") + .context("declared contrib lifecycle requires OLIPHAUNT_DECLARED_EXTENSION_PACKET")?; + let packet: Packet = serde_json::from_slice(&std::fs::read(packet_path)?)?; + ensure!(packet.product == "oliphaunt-extension-contrib-pg18"); + ensure!(packet.version == packet.runtime_version); + ensure!(packet.runtime_version == liboliphaunt_wasix_portable::PACKAGE_VERSION); + let runtime = crate::oliphaunt::assets::asset_manifest_metadata()?; + ensure!( + packet.core_module_sha256 == runtime.runtime_module_sha256, + "declared contrib must execute its exact current source-built core" + ); + let core_manifest: serde_json::Value = + serde_json::from_slice(&std::fs::read(&packet.core_manifest)?)?; + ensure!( + core_manifest["runtime"]["module-sha256"].as_str() + == Some(packet.core_module_sha256.as_str()), + "declared core manifest differs from its physical module identity" + ); + ensure!( + core_manifest["source-fingerprint"].as_str() == runtime.source_fingerprint.as_deref() + && core_manifest["runtime"]["postgres-version"].as_str() + == Some(runtime.postgres_version.as_str()), + "declared core manifest differs from the SDK's compiled runtime supplier" + ); + let canonical_names: Vec = serde_json::from_str( + option_env!("OLIPHAUNT_DECLARED_CONTRIB_SQL_NAMES") + .context("declared contrib test requires its compiled canonical member names")?, + )?; + let canonical_extensions: Vec<_> = canonical_names + .iter() + .map(|name| { + Extension::by_sql_name(name) + .context("declared contrib source member has no canonical SDK metadata") + }) + .collect::>()?; + let expected_names: BTreeSet<_> = canonical_extensions + .iter() + .map(|extension| extension.sql_name()) + .collect(); + let archive_names: BTreeSet<_> = packet + .archives + .iter() + .map(|archive| archive.sql_name.as_str()) + .collect(); + ensure!( + !expected_names.is_empty() + && canonical_names.len() == expected_names.len() + && packet.archives.len() == expected_names.len() + && archive_names == expected_names, + "declared contrib packet must contain all canonical members exactly once" + ); + + let aot_manifest_text = std::fs::read_to_string(&packet.aot_manifest)?; + let aot_manifest: serde_json::Value = serde_json::from_str(&aot_manifest_text)?; + ensure!( + aot_manifest["source-fingerprint"].as_str() == runtime.source_fingerprint.as_deref() + && aot_manifest["postgres-version"].as_str() + == Some(runtime.postgres_version.as_str()), + "declared contrib AOT differs from its exact core supplier" + ); + let manifest_artifacts = aot_manifest["artifacts"] + .as_array() + .context("declared contrib AOT manifest has no artifacts")?; + let expected_aot_names: BTreeSet<_> = canonical_extensions + .iter() + .map(|extension| { + extension + .aot_name() + .context("declared contrib member must have an AOT identity") + }) + .collect::>()?; + let actual_aot_names: BTreeSet<_> = manifest_artifacts + .iter() + .map(|artifact| { + artifact["name"] + .as_str() + .context("declared contrib AOT artifact has no name") + }) + .collect::>()?; + let actual_aot_paths: BTreeSet<_> = manifest_artifacts + .iter() + .map(|artifact| { + artifact["path"] + .as_str() + .context("declared contrib AOT artifact has no path") + }) + .collect::>()?; + let packet_aot_paths: BTreeSet<_> = packet + .aot_artifacts + .iter() + .map(|artifact| artifact.path.as_str()) + .collect(); + ensure!( + manifest_artifacts.len() == expected_aot_names.len() + && actual_aot_names == expected_aot_names + && actual_aot_paths.len() == manifest_artifacts.len() + && packet.aot_artifacts.len() == manifest_artifacts.len() + && packet_aot_paths == actual_aot_paths, + "declared contrib AOT packet must contain its exact canonical host cohort" + ); + + let archives: Vec<(&'static str, &'static [u8], &'static str)> = packet + .archives + .into_iter() + .map(|archive| { + let bytes = std::fs::read(&archive.path)?; + ensure!( + format!("{:x}", Sha256::digest(&bytes)) == archive.sha256, + "declared {} archive differs from its final npm identity", + archive.sql_name + ); + Ok(( + &*Box::leak(archive.sql_name.into_boxed_str()), + &*Box::leak(bytes.into_boxed_slice()), + &*Box::leak(archive.sha256.into_boxed_str()), + )) + }) + .collect::>()?; + let aot_artifacts: Vec<(&'static str, &'static [u8])> = packet + .aot_artifacts + .into_iter() + .map(|artifact| { + let bytes = std::fs::read(&artifact.source)?; + let metadata = manifest_artifacts + .iter() + .find(|entry| entry["path"].as_str() == Some(artifact.path.as_str())) + .context("declared AOT input has no manifest identity")?; + ensure!( + Some(format!("{:x}", Sha256::digest(&bytes)).as_str()) + == metadata["sha256"].as_str(), + "declared AOT input differs from its final Cargo identity" + ); + Ok(( + &*Box::leak( + metadata["name"] + .as_str() + .context("declared AOT input has no module name")? + .to_owned() + .into_boxed_str(), + ), + &*Box::leak(bytes.into_boxed_slice()), + )) + }) + .collect::>()?; + // The declared Bazel packet supplies trusted final-carrier AOT bytes; leaks stay in this test. + let package = Box::leak(Box::new(unsafe { + ExtensionPackage::from_trusted_release( + Box::leak(packet.product.into_boxed_str()), + Box::leak(packet.version.into_boxed_str()), + Box::leak(packet.runtime_version.into_boxed_str()), + Box::leak(archives.into_boxed_slice()), + Box::leak(aot_manifest_text.into_boxed_str()), + Box::leak(aot_artifacts.into_boxed_slice()), + ) + })); + let extensions: Vec<_> = canonical_extensions + .iter() + .map(|extension| extension.with_package(package)) + .collect(); + Ok(extensions) + } + + #[test] + #[ignore = "requires declared Bazel packet"] + fn declared_contrib_carriers_pass_full_lifecycle() -> Result<()> { + let extensions = declared_contrib_extensions()?; + let package = extensions[0] + .package() + .context("declared contrib selection has no final package")?; + run_direct_and_restart_smoke_set(&extensions)?; + run_lifecycle_materialization_set(&extensions)?; + + let cube = Extension::by_sql_name("cube") + .context("canonical contrib feature set lacks cube")? + .with_package(package); + let earthdistance = Extension::by_sql_name("earthdistance") + .context("canonical contrib feature set lacks earthdistance")? + .with_package(package); + let root = tempfile::TempDir::new()?; + let mut selected = Oliphaunt::builder() + .storage(DatabaseStorage::Directory(root.path().to_path_buf())) + .extension(cube) + .extension(earthdistance) + .open()?; + let runtime_root = selected + .runtime_storage() + .host_path() + .context("selected contrib must use a host runtime workspace")?; + assert_only_resolved_extension_libraries_are_materialized(runtime_root, earthdistance)?; + ensure!(relative_files(&runtime_root.join("lib/postgresql")).len() == 2); + run_direct_smoke(&mut selected, earthdistance)?; + selected.close()?; + Ok(()) + } + + #[cfg(feature = "tools-execution")] + #[test] + #[ignore = "requires declared Bazel extension and tools packets"] + #[allow(unsafe_code)] + fn declared_contrib_carriers_pass_logical_dump_restore() -> Result<()> { + run_declared_logical_dump_restore(&declared_contrib_extensions()?) + } + + #[cfg(all(feature = "tools-execution", feature = "extension-uuid-ossp"))] + #[test] + #[ignore = "requires exact current-source native-host extension and tools packets"] + fn declared_uuid_ossp_carriers_pass_aot_host_smoke() -> Result<()> { + let extensions = declared_contrib_extensions()?; + ensure!(extensions.len() == 1 && extensions[0].sql_name() == "uuid-ossp"); + run_direct_and_restart_smoke_set(&extensions)?; + run_lifecycle_materialization_set(&extensions)?; + run_declared_logical_dump_restore(&extensions) + } + + #[cfg(feature = "tools-execution")] + #[allow(unsafe_code)] + fn run_declared_logical_dump_restore(extensions: &[Extension]) -> Result<()> { + use crate::tools::{PgDumpOptions, PsqlOptions, ToolAssets}; + use serde::Deserialize; + + #[derive(Deserialize)] + #[serde(deny_unknown_fields)] + struct Tool { + wasm: PathBuf, + aot: PathBuf, + manifest: PathBuf, + } + + #[derive(Deserialize)] + #[serde(rename_all = "camelCase", deny_unknown_fields)] + struct Tools { + version: String, + runtime_version: String, + pg_dump: Tool, + psql: Tool, + } + + let tools_path = std::env::var_os("OLIPHAUNT_DECLARED_TOOLS_PACKET") + .context("declared contrib logical restore requires its final tools packet")?; + let tools: Tools = serde_json::from_slice(&std::fs::read(tools_path)?)?; + ensure!( + Some(tools.version.as_str()) == option_env!("OLIPHAUNT_DECLARED_TOOLS_VERSION"), + "declared tools differ from their canonical compiled product version" + ); + ensure!(tools.runtime_version == liboliphaunt_wasix_portable::PACKAGE_VERSION); + let assets = |tool: Tool| -> Result { + // SAFETY: the runner validates these exact final-carrier bytes and manifests. + Ok(unsafe { + ToolAssets::new( + std::fs::read(tool.wasm)?, + std::fs::read(tool.aot)?, + std::fs::read_to_string(tool.manifest)?, + ) + }) + }; + let pg_dump = assets(tools.pg_dump)?; + let psql = assets(tools.psql)?; + for &extension in extensions { + let name = extension.sql_name(); + eprintln!("logical dump/restore extension: {name}"); + let mut source = Oliphaunt::builder().extension(extension).open()?; + run_direct_smoke(&mut source, extension)?; + source.exec("CREATE TABLE oliphaunt_logical_restore_probe(value text NOT NULL); INSERT INTO oliphaunt_logical_restore_probe VALUES ('retained')")?; + let dump = source + .pg_dump(PgDumpOptions::new().assets(pg_dump.clone())) + .with_context(|| format!("dump declared contrib {name}"))?; + ensure!(dump.contains("COPY public.oliphaunt_logical_restore_probe")); + source.close()?; + let mut restored = Oliphaunt::builder().extension(extension).open()?; + restored + .psql(PsqlOptions::new().assets(psql.clone()).script(dump)) + .with_context(|| format!("restore declared contrib {name}"))?; + assert_extension_catalog_state(&mut restored, extension)?; + verify_persisted_fixture(&mut restored, extension)?; + ensure!( + restored + .query("SELECT value FROM oliphaunt_logical_restore_probe")? + .get_text(0, "value")? + == Some("retained") + ); + restored.close()?; + } + Ok(()) + } + #[test] #[cfg(all(feature = "extension-cube", feature = "extension-earthdistance"))] fn dependent_extension_activation_includes_dependencies_first() -> Result<()> { @@ -461,7 +779,14 @@ mod extension_tests { .iter() .copied() .filter(|extension| { - crate::oliphaunt::assets::extension_archive(extension.sql_name()).is_some() + if let Some(package) = extension.package() { + package + .archives() + .iter() + .any(|(name, _, _)| *name == extension.sql_name()) + } else { + crate::oliphaunt::assets::extension_archive(extension.sql_name()).is_some() + } }) .collect(); let embedded_names: BTreeSet<_> = embedded @@ -475,7 +800,7 @@ mod extension_tests { .collect(); ensure!( missing.is_empty(), - "required WASIX extension archives are not embedded: {}", + "required WASIX extension archives are unavailable: {}", missing.join(", ") ); Ok(embedded) @@ -621,14 +946,28 @@ mod extension_tests { } fn verify_persisted_fixture(db: &mut Oliphaunt, extension: Extension) -> Result<()> { - let recipe = extension_smoke_sql(extension.sql_name()); - if let Some((_, verification)) = recipe.split_once("-- oliphaunt-verify") { - for statement in extension_smoke_statements(verification) { + if !generated::creates_database_object_for_test(extension) { + for statement in extension_activation_sql_for_test(extension)? { db.exec(statement).with_context(|| { - format!("verify persisted state for {}", extension.sql_name()) + format!( + "reactivate session-local extension {}", + extension.sql_name() + ) })?; } } + let recipe = extension_smoke_sql(extension.sql_name()); + let verification = recipe + .split_once("-- oliphaunt-verify") + .map_or(recipe.as_str(), |(_, verification)| verification); + for statement in extension_smoke_statements(verification) { + db.exec(statement).with_context(|| { + format!( + "verify reopened or restored extension {}", + extension.sql_name() + ) + })?; + } Ok(()) } diff --git a/src/wasix/sdks/rust/src/oliphaunt/query/query_fixture_tests.rs b/src/wasix/sdks/rust/src/oliphaunt/query/query_fixture_tests.rs index 06bc3958b..a32d179e8 100644 --- a/src/wasix/sdks/rust/src/oliphaunt/query/query_fixture_tests.rs +++ b/src/wasix/sdks/rust/src/oliphaunt/query/query_fixture_tests.rs @@ -64,7 +64,14 @@ fn typed_parsers_match_shared_query_fixtures() -> Result<()> { for (actual, expected) in result.fields().iter().zip(&expected.fields) { assert_eq!(actual.name, expected.name); assert_eq!(actual.type_oid, expected.type_oid); - assert_eq!(actual.format, if expected.format.as_deref() == Some("text") { QueryFormat::Text } else { QueryFormat::Binary }); + assert_eq!( + actual.format, + if expected.format.as_deref() == Some("text") { + QueryFormat::Text + } else { + QueryFormat::Binary + } + ); } for (actual, expected) in result.rows().iter().zip(&expected.rows) { for (column, expected) in expected.iter().enumerate() { diff --git a/src/wasix/sdks/rust/tests/runtime_smoke.rs b/src/wasix/sdks/rust/tests/runtime_smoke.rs index d3ee6be00..906fe3211 100644 --- a/src/wasix/sdks/rust/tests/runtime_smoke.rs +++ b/src/wasix/sdks/rust/tests/runtime_smoke.rs @@ -713,36 +713,54 @@ async fn managed_async_transaction_rejects_and_chain_before_dispatch() -> Result #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn abandoning_an_in_flight_async_commit_retires_the_owner() -> Result<()> { - let database = AsyncOliphaunt::open().await?; + let workspace = tempfile::tempdir()?; + let database_root = workspace.path().join("database"); + let database = AsyncOliphaunt::builder() + .storage(DatabaseStorage::Directory(database_root.clone())) + .open() + .await?; + database.query("SELECT pg_sleep(0.01)").await?; database .exec( "CREATE TABLE deferred_commit_probe(id int PRIMARY KEY); \ - CREATE FUNCTION deferred_commit_sleep() RETURNS trigger \ - LANGUAGE plpgsql AS $$ BEGIN PERFORM pg_sleep(1); RETURN NEW; END $$; \ - CREATE CONSTRAINT TRIGGER deferred_commit_sleep \ + CREATE FUNCTION deferred_commit_wait() RETURNS trigger \ + LANGUAGE plpgsql AS $$ BEGIN \ + COPY (SELECT 1) TO '/base/commit.started'; \ + FOR attempt IN 1..500 LOOP \ + IF (pg_stat_file('/base/commit.release', true)).size IS NOT NULL THEN \ + RETURN NEW; \ + END IF; \ + PERFORM pg_sleep(0.01); \ + END LOOP; \ + RAISE EXCEPTION 'COMMIT barrier was not released'; END $$; \ + CREATE CONSTRAINT TRIGGER deferred_commit_wait \ AFTER INSERT ON deferred_commit_probe DEFERRABLE INITIALLY DEFERRED \ - FOR EACH ROW EXECUTE FUNCTION deferred_commit_sleep()", + FOR EACH ROW EXECUTE FUNCTION deferred_commit_wait()", ) .await?; let transaction_database = database.clone(); - let (callback_finished, callback_finished_rx) = tokio::sync::oneshot::channel(); let settlement = tokio::spawn(async move { transaction_database .transaction(async |transaction: &mut AsyncTransaction| { transaction .execute("INSERT INTO deferred_commit_probe VALUES (1)") .await?; - let _ = callback_finished.send(()); Ok::<(), oliphaunt_wasix::Error>(()) }) .await }); - callback_finished_rx - .await - .expect("transaction callback reaches settlement"); - tokio::time::sleep(Duration::from_millis(100)).await; + let commit_started = tokio::time::timeout(Duration::from_secs(5), async { + while !database_root.join("pgdata/commit.started").try_exists()? { + tokio::time::sleep(Duration::from_millis(1)).await; + } + Ok::<(), std::io::Error>(()) + }) + .await; settlement.abort(); + // Release PostgreSQL before reporting a failed wait, so the owner cannot strand. + std::fs::write(database_root.join("pgdata/commit.release"), b"release")?; + commit_started.expect("COMMIT reaches its deferred trigger")?; assert!( settlement .await @@ -759,5 +777,18 @@ async fn abandoning_an_in_flight_async_commit_retires_the_owner() -> Result<()> ); database.close().await?; assert!(database.is_closed()); + let reopened = AsyncOliphaunt::builder() + .storage(DatabaseStorage::Directory(database_root)) + .open() + .await?; + assert_eq!( + reopened + .query("SELECT count(*)::text AS rows FROM deferred_commit_probe") + .await? + .get_text(0, "rows")?, + Some("1"), + "the unobserved COMMIT must succeed before the owner retires" + ); + reopened.close().await?; Ok(()) } diff --git a/src/wasix/sdks/rust/tools/prepare-rust-release-source.mts b/src/wasix/sdks/rust/tools/prepare-rust-release-source.mts index e7c2cdba3..d0aa44edc 100644 --- a/src/wasix/sdks/rust/tools/prepare-rust-release-source.mts +++ b/src/wasix/sdks/rust/tools/prepare-rust-release-source.mts @@ -1,11 +1,6 @@ #!/usr/bin/env bun import fs from 'node:fs/promises'; import path from 'node:path'; -import { - canonicalWasixCargoToolchainVersions, - validateWasixConsumerDependencyPins, -} from '../../../runtime/tools/wasix-cargo-toolchain-policy.mts'; - import { packagedCargoManifestText, parseCargoPackageNameVersion, @@ -16,6 +11,10 @@ import { } from '../../../../../tools/packaging/release-notices.mts'; import { loadPublicationCatalog } from '../../../../../tools/release/publication-catalog.mts'; import { productCompatibilityVersion } from '../../../../../tools/release/release-graph.mts'; +import { + canonicalWasixCargoToolchainVersions, + validateWasixConsumerDependencyPins, +} from '../../../runtime/tools/wasix-cargo-toolchain-policy.mts'; import { ROOT as root, stageWasixRustPackageSource } from './package-source.mts'; const SOURCE_NOTICE_OPTIONS = Object.freeze({ profile: 'source-sdk' }); @@ -45,14 +44,13 @@ function escapeRegExp(value) { return value.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&'); } -export function renderOliphauntWasixReleaseCargoToml( - source, - runtimeVersion = productCompatibilityVersion( - 'oliphaunt-wasix-rust', - 'liboliphaunt-wasix', - 'prepare-rust-release-source.mts', - ), -) { +export function renderOliphauntWasixReleaseCargoToml(source, runtimeVersion) { + const metadata = Bun.TOML.parse(source).package?.metadata?.oliphaunt ?? {}; + const requirements = { + 'liboliphaunt-wasix': runtimeVersion ?? metadata['runtime-version'], + 'postgres-tools-wasix': metadata['tools-version'], + 'database-resources': metadata['icu-version'], + }; let text = packagedCargoManifestText(source); const catalog = loadPublicationCatalog('prepare-rust-release-source.mts'); for (const carrier of catalog.carriers.filter((entry) => entry.ecosystem === 'cargo')) { @@ -66,11 +64,12 @@ export function renderOliphauntWasixReleaseCargoToml( } text = text.replace(pattern, (_, before, declaredVersion, after) => { const version = - carrier.product === 'liboliphaunt-wasix' - ? runtimeVersion - : declaredVersion === '*' - ? carrier.version - : declaredVersion.replace(/^=/u, ''); + declaredVersion === '*' + ? requirements[carrier.product] + : declaredVersion.replace(/^=/u, ''); + if (typeof version !== 'string' || version.length === 0) { + throw new Error(`Missing installed compatibility pin for ${crate}`); + } return `${before}=${version}${after}`; }); } diff --git a/src/wasix/sdks/rust/tools/testdata/shipping_supplier_fixture.rs b/src/wasix/sdks/rust/tools/testdata/shipping_supplier_fixture.rs new file mode 100644 index 000000000..8f43dbcd5 --- /dev/null +++ b/src/wasix/sdks/rust/tools/testdata/shipping_supplier_fixture.rs @@ -0,0 +1 @@ +pub const SHIPPING_SUPPLIER_FIXTURE: u8 = 1; diff --git a/src/wasix/sdks/ts/BUILD.bazel b/src/wasix/sdks/ts/BUILD.bazel new file mode 100644 index 000000000..730edc7f4 --- /dev/null +++ b/src/wasix/sdks/ts/BUILD.bazel @@ -0,0 +1,211 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("@aspect_rules_js//js:defs.bzl", "js_library") +load("@aspect_rules_ts//ts:defs.bzl", "ts_config", "ts_project") +load("@oliphaunt_javascript_metadata//:metadata.bzl", "JAVASCRIPT") +load("@oliphaunt_metadata//:metadata.bzl", "PUBLICATION_CARRIERS") +load("@javascript_packages//:defs.bzl", "javascript_type_links", RUNTIME_PACKAGES = "PACKAGES") +load("@javascript_consumer_packages//:roots.bzl", "CONSUMER_ACQUISITIONS", "CONSUMER_CLOSURES", "CONSUMER_TOOLS") +load("//build_defs/languages/ts:defs.bzl", "workspace_dependency_package", "workspace_dependency_link", "source_sdk_publish_files") +load("//build_defs/query:defs.bzl", "query_envelope") +load("//build_defs/languages/ts:unit-tests.bzl", "sdk_unit_test") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") +load("//build_defs/resources:resources.bzl", "wasix_current_seed_assets") +load("//build_defs/wasix/browser:defs.bzl", "browser_host_assets", "browser_sql_consumer", "browser_sql_lifecycle") +load("//build_defs/wasix:sdk-installed.bzl", "wasix_sdk_installed_test") + +package(default_visibility = ["//visibility:public"]) + +_MODULE_OUT_DIR = "lib" +exports_files(["package.json", "tsconfig.json", "tools/package.mts", "tools/frozen-browser-consumer.mts", "tools/browser-cdp.mts"]) +exports_files(["tools/pgwire-client.mts"]) +exports_files(["tools/integration/verify-host.mts"]) +exports_files([ + "src/resources/extensions.ts", + "src/resources/archive.ts", + "src/resources/asset-source.ts", + "src/resources/zstd.ts", + "src/storage/database-root.ts", +]) + +SDK = JAVASCRIPT["@oliphaunt/wasix-ts"] +QUERY = JAVASCRIPT["@oliphaunt/ts-query"] +SDK_SRCS = glob(["src/**/*.ts"], exclude = ["src/__tests__/**"]) +BROWSER_PACKAGES = {"@javascript_packages//:" + key: key for key in RUNTIME_PACKAGES} | {"@javascript_consumer_packages//:" + key: key for key in CONSUMER_CLOSURES[SDK["name"]]} + +javascript_type_links(SDK["types"] | SDK["packages"]) + +workspace_dependency_package(name = "query_package", workspace = SDK, dependency = QUERY["name"], current = "//src/query/ts:shipping_package") +workspace_dependency_link(name = "node_modules/@oliphaunt/ts-query", package = ":query_package", workspace = SDK, dependency = QUERY["name"]) +js_library(name = "package_metadata", srcs = ["package.json"]) +ts_config(name = "source_config", src = "tsconfig.json") + +# Source-mapped examples need the SDK's declared files and typings without its +# emitted module, browser host or runtime carriers. +js_library( + name = "source_inputs", + types = SDK_SRCS, + deps = [":package_metadata", "//src/wasix/sdks/ts/src/host:declaration"] + [":node_modules/" + name for name in SDK["types"] | SDK["packages"]], +) + +ts_project( + name = "module", + srcs = SDK_SRCS, + tsconfig = "tsconfig.build.json", + extends = "tsconfig.json", + declaration = True, + declaration_map = False, + out_dir = _MODULE_OUT_DIR, + root_dir = "src", + transpiler = "tsc", + supports_workers = 0, + deps = [":package_metadata", ":node_modules/@oliphaunt/ts-query", "//src/wasix/sdks/ts/src/host:declaration"] + [":node_modules/" + name for name in SDK["types"] | SDK["packages"]], +) + +filegroup(name = "module_outputs", srcs = [":module"]) + +ts_project( + name = "source_checks", + srcs = glob(["src/**/*.ts"]), + tsconfig = "tsconfig.json", + no_emit = True, + declaration = True, + out_dir = _MODULE_OUT_DIR, + root_dir = "src", + supports_workers = 0, + deps = [":package_metadata", ":node_modules/@oliphaunt/ts-query", "//src/wasix/sdks/ts/src/host:declaration"] + [":node_modules/" + name for name in SDK["types"] | SDK["packages"]], +) +source_sdk_publish_files(name = "publish_files", manifest = "package.json", profile = "wasix-ts") +filegroup(name = "publish_manifest", srcs = [":publish_files"], output_group = "manifest") +filegroup(name = "license", srcs = [":publish_files"], output_group = "license") +filegroup(name = "notices", srcs = [":publish_files"], output_group = "notices") +browser_host_assets(name = "host_assets", host = "//src/wasix/browser-host:host") + +query_envelope( + name = "npm", + format = "npm", + manifest = ":publish_manifest", + entries = { + ":module_outputs": "lib/", + ":module_types": "lib/", + ":host_assets": "lib/", + ":publish_manifest": "package.json", + ":license": "LICENSE", + ":notices": "THIRD_PARTY_NOTICES.md", + "README.md": "README.md", + "ARCHITECTURE.md": "ARCHITECTURE.md", + "CHANGELOG.md": "CHANGELOG.md", + }, + out = "oliphaunt-wasix-ts.tgz", +) + +shipping_package( + name = "shipping_package", + suppliers = "//build_defs/release:no_suppliers", + owner = "@oliphaunt_metadata//:product_oliphaunt-wasix-ts", + artifacts = [":npm"], + ecosystem = "npm", + package_name = SDK["name"], + configuration = "portable", + role = [carrier["role"] for carrier in PUBLICATION_CARRIERS if carrier["product"] == "oliphaunt-wasix-ts" and carrier["ecosystem"] == "npm" and carrier["name"] == SDK["name"]][0], +) + +shipping_export(name = "shipping_export", packages = [":shipping_package"], qualification = [":browser_sql_consumer", ":installed_host_test", ":unit_test", ":package_policy_test"], testonly = True) + +wasix_sdk_installed_test( + name = "installed_host_test", + sdk = ":npm", + extension = "//src/extensions/external/pgtap:wasix_npm_shipping_files", + fixture = "tools/integration/verify-host.mts", + pgwire = "tools/pgwire-client.mts", + packages = {":query_package": QUERY["name"]} | {"@javascript_packages//:" + identity: name for name, identity in SDK["packages"].items()}, + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + size = "large", + timeout = "long", + tags = ["manual", "installed-consumer"], +) + +wasix_current_seed_assets(name = "browser_seed") + +browser_sql_consumer( + name = "browser_sql_consumer", + sdk = ":npm", + query = ":query_package", + runtime = "//src/wasix/runtime:npm", + seed_archive = ":browser_seed_archive", + seed_manifest = ":browser_seed_manifest", + manifest = ":publish_manifest", + fixture = "tools/frozen-browser-consumer.mts", + cdp = "tools/browser-cdp.mts", + packages = BROWSER_PACKAGES, + acquisition = CONSUMER_ACQUISITIONS[SDK["name"]], + roots = CONSUMER_TOOLS[SDK["name"]], + runtime_packages = SDK["packages"], + size = "large", + timeout = "long", + # Chrome is observed on this host; every qualification must execute it. + tags = ["manual", "external", "local", "installed-consumer"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) + +# Local qualification can consume byte-identified outputs from separate producer bases. +# Unified CI uses browser_sql_consumer and its declared archive dependencies above. +browser_sql_lifecycle( + name = "browser_sql_lifecycle", + manifest = ":publish_manifest", + fixture = "tools/frozen-browser-consumer.mts", + cdp = "tools/browser-cdp.mts", + packages = BROWSER_PACKAGES, + acquisition = CONSUMER_ACQUISITIONS[SDK["name"]], + roots = CONSUMER_TOOLS[SDK["name"]], + runtime_packages = SDK["packages"], + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) + +sdk_unit_test( + name = "unit_test", + manifest = "package.json", + configuration = "bunfig.toml", + sources = glob(["src/**/*.ts"]) + glob(["src/**/*.mts", "src/**/*.json"], allow_empty = True) + ["//src/wasix/sdks/ts/src/host:declaration"], + fixtures = ["//src/test-fixtures:rust_fixtures", "//src/database-resources:cluster_seed_contract_fixtures"], + packages = {":query_package": QUERY["name"]} | {"@javascript_packages//:" + identity: name for name, identity in SDK["packages"].items()}, + size = "small", +) + +source_quality_files(exclude = [_MODULE_OUT_DIR + "/**"]) + +# Existing operational package policy tests use only this declared source closure. +sdk_unit_test( + name = "package_policy_test", + manifest = "package.json", + tests = ["tools/wasix-typescript-package.test.mts"], + sources = [ + "//build_defs/wasix/browser:metadata.mts", + "//build_defs/wasix/browser:provenance.mts", + "//:src/extensions/artifacts/packages/tools/contrib-carriers.mts", + "//src/wasix/node-addon:tools/carrier-contract.mts", + "//src/wasix/runtime:tools/wasix-cargo-artifact-contract.mts", + "//src/wasix/sdks/ts:tools/package.mts", + "//src/wasix/sdks/ts:tools/wasix-typescript-package.mts", + "//:tools/packaging/platform-binary-contract.mts", + "//:tools/packaging/portable-archive.mts", + "//:tools/packaging/release-directory-safety.mts", + "//:tools/packaging/release-notices.mts", + "//:tools/packaging/windows-vc-runtime-closure.mts", + "//tools/release:compatibility-version-parser.mts", + "//tools/release:platform-compatibility-policy.mts", + "//tools/release:release-graph.mts", + "//tools/release:release-history.mts", + ], + fixtures = ["//:LICENSE", "//:tools/packaging/windows-vc-runtime-policy.json", "//src/database-resources:contracts/contract.json"], + size = "small", +) + +test_suite( + name = "source_unit_tests", + tests = [":unit_test", ":package_policy_test"], +) + +# Source-only inputs for the existing SDK package policy tests. +exports_files([ + "tools/wasix-typescript-package.mts", +], visibility = ["//visibility:public"]) diff --git a/src/wasix/sdks/ts/src/__tests__/extensions.test.ts b/src/wasix/sdks/ts/src/__tests__/extensions.test.ts index c3b916c90..1a6429f03 100644 --- a/src/wasix/sdks/ts/src/__tests__/extensions.test.ts +++ b/src/wasix/sdks/ts/src/__tests__/extensions.test.ts @@ -14,6 +14,7 @@ import { overlayIcuArchive, parseWasixAssetManifest, resolveWasixExtensions, + verifyClusterSeedIdentity, } from '../resources/extensions.js'; import type { SerializedExtensionCarrier, SerializedRuntimeDescriptor } from '../workers/rpc.js'; import type { WasixAssetManifest } from '../core/types.js'; @@ -22,6 +23,29 @@ type ProjectedExtension = ReturnType['extensions' type ProjectedLifecycle = ProjectedExtension['lifecycle']; describe('WASIX TypeScript extensions', () => { + it('keeps original creator hashes independent of the exact admitted module and version', () => { + const seed = sharedSeedFixture('standard.valid.json') as Parameters< + typeof verifyClusterSeedIdentity + >[2]; + seed.runtime.target = 'portable'; + const runtime = runtimeDescriptor(); + runtime.version = seed.runtime.version; + const outer = manifest(); + outer.runtime['module-sha256'] = seed.runtime.consumerSha256; + const options = { runtime } as Parameters[0]; + expect(seed.runtime.consumerSha256).not.toBe(seed.runtime.producerSha256); + expect(() => verifyClusterSeedIdentity(options, outer, seed)).not.toThrow(); + for (const [field, value] of [ + ['version', '999.0.0'], + ['consumerSha256', 'f'.repeat(64)], + ['target', 'linux-x64-gnu'], + ] as const) { + const changed = structuredClone(seed); + (changed.runtime as unknown as Record)[field] = value; + expect(() => verifyClusterSeedIdentity(options, outer, changed)).toThrow(); + } + }); + it('binds separately supplied ICU bytes to their manifest and rejects corruption', async () => { const data = Uint8Array.of(1, 2, 3); const digest = createHash('sha256') diff --git a/src/wasix/sdks/ts/src/host/BUILD.bazel b/src/wasix/sdks/ts/src/host/BUILD.bazel new file mode 100644 index 000000000..5a750913a --- /dev/null +++ b/src/wasix/sdks/ts/src/host/BUILD.bazel @@ -0,0 +1,9 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("@aspect_rules_js//js:defs.bzl", "js_library") + +package(default_visibility = ["//visibility:public"]) +exports_files(["index.d.mts"]) + +js_library(name = "declaration", srcs = ["index.d.mts"]) + +source_quality_files() diff --git a/src/wasix/sdks/ts/src/resources/extensions.ts b/src/wasix/sdks/ts/src/resources/extensions.ts index ca13a1050..5d767c827 100644 --- a/src/wasix/sdks/ts/src/resources/extensions.ts +++ b/src/wasix/sdks/ts/src/resources/extensions.ts @@ -737,7 +737,8 @@ export function assertClusterSeedProfileContract( } } -function verifyClusterSeedIdentity( +/** @internal Bind the consuming module while retaining the seed's original creator. */ +export function verifyClusterSeedIdentity( options: SerializedOpenOptions, outer: WasixAssetManifest, seed: ClusterSeedManifest, @@ -754,11 +755,8 @@ function verifyClusterSeedIdentity( seed.source.producer !== 'wasix-initdb' ) throw new Error('WASIX seed has an incompatible runtime identity'); - if ( - seed.runtime.consumerSha256 !== seed.runtime.producerSha256 || - seed.runtime.consumerSha256 !== outer.runtime['module-sha256'] - ) { - throw new Error('WASIX seed was produced by a different runtime module'); + if (seed.runtime.consumerSha256 !== outer.runtime['module-sha256']) { + throw new Error('WASIX seed is admitted for a different consuming runtime module'); } if (seed.catalogProfile === 'icu' && seed.icu?.dataTreeSha256 !== icuTree) { throw new Error('WASIX ICU seed does not match the selected ICU data'); diff --git a/src/wasix/sdks/ts/tools/frozen-browser-consumer.mts b/src/wasix/sdks/ts/tools/frozen-browser-consumer.mts index 665b7909c..121af8288 100644 --- a/src/wasix/sdks/ts/tools/frozen-browser-consumer.mts +++ b/src/wasix/sdks/ts/tools/frozen-browser-consumer.mts @@ -10,6 +10,7 @@ import { createCdpClient } from './browser-cdp.mts'; const root = process.argv[2]; assert(root, 'browser consumer requires its external app directory'); const packages: { name: string; sqlName: string }[] = JSON.parse(process.argv[3]); +const storageTests = process.argv[4] === '--opfs'; writeFileSync(path.join(root, 'index.html'), ''); writeFileSync( path.join(root, 'probe.ts'), @@ -17,6 +18,7 @@ writeFileSync( import Default from '@oliphaunt/wasix-ts'; import Worker from '@oliphaunt/wasix-ts/worker'; import { checkExtensions } from './extensions.mts'; +${storageTests ? "import { expectOpfsPersistence, expectOpfsCrashRecovery } from './opfs-smoke.js';" : ''} ${packages.map(({ name }, index) => `import extension${index} from ${JSON.stringify(name)};`).join('\n')} const state = document.documentElement.dataset; state.frozenState = 'running'; @@ -31,6 +33,19 @@ state.frozenState = 'running'; finally { await db.close(); } } state.frozenAnswers = JSON.stringify(answers); + ${ + storageTests + ? ` + const phase = (name: string) => { + state.frozenPhase = name; + console.debug('installed browser phase: ' + name + ' (' + Math.round(performance.now()) + 'ms)'); + }; + state.frozenOpfsAnswers = await expectOpfsPersistence([], phase); + phase('OPFS crash recovery'); + state.frozenOpfsCrash = JSON.stringify(await expectOpfsCrashRecovery()); + ` + : '' + } state.frozenState = 'passed'; })().catch(error => { state.frozenState = 'failed'; @@ -72,7 +87,7 @@ try { const profile = path.join(root, 'chrome-profile'); mkdirSync(profile); chrome = spawn( - 'google-chrome', + process.env.OLIPHAUNT_BROWSER_CHROME ?? 'google-chrome', [ '--headless=new', '--no-sandbox', @@ -116,6 +131,7 @@ try { await cdp.send('Page.navigate', { url: `http://127.0.0.1:${address.port}/` }); // Poll outside the page so navigation cannot destroy an awaited JS promise. let passed = false; + let lastState: Record = {}; while (Date.now() < deadline) { if (failures.length) throw new Error(failures.at(-1)); const result = await cdp.send('Runtime.evaluate', { @@ -124,18 +140,29 @@ try { }); if (result.exceptionDetails) throw new Error(JSON.stringify(result.exceptionDetails)); const state = JSON.parse(result.result?.value ?? '{}'); + lastState = state; if (state.frozenState === 'failed') throw new Error(state.frozenError); if (state.frozenState === 'passed') { assert.deepEqual(JSON.parse(state.frozenAnswers), ['42', '42']); + if (storageTests) { + assert.equal(state.frozenOpfsAnswers, '1,2,3'); + assert.deepEqual(JSON.parse(state.frozenOpfsCrash), { answer: '73', relations: '48' }); + } passed = true; break; } await delay(200); } - assert(passed, 'installed browser module timed out'); + assert(passed, `installed browser module timed out: ${JSON.stringify(lastState)}`); console.log( - 'Installed browser default and worker exports loaded extensions and executed queries', + packages.length + ? 'Installed browser default and worker exports loaded extensions and executed queries' + : 'Installed browser default and worker exports executed queries', ); + if (storageTests) + console.log( + 'Installed browser OPFS persistence, synchronous transport, and crash recovery passed', + ); } finally { socket?.close(); chrome?.kill('SIGKILL'); diff --git a/src/wasix/sdks/ts/tools/wasix-typescript-package.mts b/src/wasix/sdks/ts/tools/wasix-typescript-package.mts index 0662968d0..c4eaef509 100644 --- a/src/wasix/sdks/ts/tools/wasix-typescript-package.mts +++ b/src/wasix/sdks/ts/tools/wasix-typescript-package.mts @@ -1,6 +1,14 @@ +import { WASIX_NAPI_PLATFORM_PACKAGES as NATIVE_PACKAGES } from '../../../node-addon/tools/carrier-contract.mts'; +export { assertWasixTypescriptNativeCarrier } from '../../../node-addon/tools/carrier-contract.mts'; import path from 'node:path'; +import { + assertNativeBrowserHostProvenance, + HOST_FILES, + NATIVE_BROWSER_HOST_SCHEMA, +} from '../../../../../build_defs/wasix/browser/provenance.mts'; import { prepareWasixTypescriptPackage as prepareProductPackage } from './package.mts'; + const QUERY_PACKAGE = '@oliphaunt/ts-query'; import { readPortableArchiveEntries } from '../../../../../tools/packaging/portable-archive.mts'; @@ -16,12 +24,7 @@ const RUNTIME_PACKAGE = '@oliphaunt/liboliphaunt-wasix'; const FZSTD_PACKAGE = 'fzstd'; const FZSTD_VERSION = '0.1.1'; const NATIVE_PRODUCT = 'oliphaunt-wasix-napi'; -const NATIVE_PACKAGES = Object.freeze([ - '@oliphaunt/wasix-napi-darwin-arm64', - '@oliphaunt/wasix-napi-linux-arm64-gnu', - '@oliphaunt/wasix-napi-linux-x64-gnu', - '@oliphaunt/wasix-napi-win32-x64-msvc', -]); + const NOTICE_OPTIONS = Object.freeze({ profile: 'source-sdk' }); function fail(message) { @@ -97,36 +100,6 @@ export function assertWasixTypescriptManifest(manifest, label = `${PACKAGE_NAME} return manifest; } -export function assertWasixTypescriptNativeCarrier(manifest, carrier) { - const sdk = manifest.oliphaunt; - const native = carrier.oliphaunt; - if ( - manifest.name !== PACKAGE_NAME || - sdk?.runtimeProduct !== 'liboliphaunt-wasix' || - sdk?.wasixNapiProduct !== NATIVE_PRODUCT || - !/^\d+\.\d+\.\d+$/u.test(sdk?.runtimeVersion ?? '') || - !/^\d+\.\d+\.\d+$/u.test(sdk?.wasixNapiVersion ?? '') || - !Number.isSafeInteger(sdk?.wasixAddonAbiVersion) || - sdk.wasixAddonAbiVersion < 1 || - !Number.isSafeInteger(sdk?.nodeApiVersion) || - sdk.nodeApiVersion < 1 || - Object.hasOwn(sdk, 'qualificationOnly') || - Object.hasOwn(native ?? {}, 'qualificationOnly') || - !NATIVE_PACKAGES.includes(carrier.name) || - carrier.version !== sdk?.wasixNapiVersion || - manifest.optionalDependencies?.[carrier.name] !== carrier.version || - native?.runtimeProduct !== sdk?.runtimeProduct || - native?.runtimeVersion !== sdk?.runtimeVersion || - native?.addonAbiVersion !== sdk?.wasixAddonAbiVersion || - native?.nodeApiVersion !== sdk?.nodeApiVersion || - JSON.stringify(native?.profiles) !== JSON.stringify(['standard', 'icu']) - ) { - fail( - `${carrier.name}@${carrier.version} is incompatible with ${PACKAGE_NAME}@${manifest.version}: SDK requires N-API ${sdk?.wasixNapiVersion} embedding runtime ${sdk?.runtimeVersion}, carrier embeds runtime ${native?.runtimeVersion}`, - ); - } -} - export function prepareWasixTypescriptPackage(packageDir) { const root = path.resolve(packageDir); const manifest = prepareProductPackage(root); @@ -191,6 +164,13 @@ export function assertWasixTypescriptNpmArchive(archive) { for (const name of exportedFiles) { requireFile(name); } - JSON.parse(requireFile('lib/host/provenance.json').toString('utf8')); + const hostProvenance = JSON.parse(requireFile('lib/host/provenance.json').toString('utf8')); + if (hostProvenance.schema === NATIVE_BROWSER_HOST_SCHEMA) { + assertNativeBrowserHostProvenance(hostProvenance, { + files: Object.fromEntries(HOST_FILES.map((name) => [name, requireFile(`lib/host/${name}`)])), + }); + } else if (hostProvenance.schema !== undefined) { + fail(`Unsupported browser host provenance schema ${hostProvenance.schema}`); + } return manifest; } diff --git a/tools/bazel/BUILD.bazel b/tools/bazel/BUILD.bazel new file mode 100644 index 000000000..e4a305793 --- /dev/null +++ b/tools/bazel/BUILD.bazel @@ -0,0 +1,36 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/foundation:bun.bzl", "bun_binary", "bun_test") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["shipping.cquery.bzl", "shipping-coverage.mts"]) + +bun_test( + name = "shipping_coverage_test", + size = "small", + entry_point = "tests/shipping-coverage.test.mts", + data = [ + "shipping-coverage.mts", + "//tools/release:bazel-shipping-inputs.mts", + ], +) + +bun_test( + name = "execution_log_test", + entry_point = "tests/execution-log.test.mts", + data = ["tests/execution-log.mts"], +) + +bun_binary( + name = "conformance", + entry_point = "tests/conformance.mts", + data = [ + "tests/execution-log.mts", + "//:tools/packaging/portable-archive.mts", + "//tools/release:bazel-shipping-inputs.mts", + "//tools/bazel/tests/fixtures/action-graph:fixture_sources", + ], + tags = ["manual"], +) + +source_quality_files() diff --git a/tools/bazel/README.md b/tools/bazel/README.md new file mode 100644 index 000000000..21f2caeae --- /dev/null +++ b/tools/bazel/README.md @@ -0,0 +1,221 @@ +# Native migration checks + +Run the portable package and dependency checks on the declared Linux profile: + +```sh +profile=//build_defs/native:linux_x86_64_glibc_2_28 +bash tools/dev/bazel.sh test //:portable_tests \ + --platforms="$profile" --host_platform="$profile" --jobs=2 +bash tools/dev/bazel.sh run //tools/bazel:conformance --jobs=2 +``` + +The conformance command uses an isolated source copy and output base. It builds +real shared-library consumers, consumes their assembled packages, then compares +physical results with an independent scenario table and native execution logs. +It covers zero/few/many changes, different completed baselines, shared version +owners, package-only and test-only changes, deletion/rename and invalid facts. +Failed cases preserve their scratch directory and seed. Identical reruns must +execute no compiler, package or test actions. + +The same isolated run constructs the real query archives and checks their +manifests and combined action graph. A major Cargo query version bump leaves +the four SDK/helper consumers on their held registry query dependency and runs +one archive action; an identical request runs no processes. Package versions, +carrier ownership and extension control metadata +must leave source and language acquisition locks unchanged. + +The query consumer tests unpack the actual crate/npm archives into temporary +installations. Rust uses the registered toolchain and an isolated offline Cargo +home; Node checks both ESM and CommonJS. A nested-module fixture checks that +packaging preserves generated module and declaration paths. + +Run Linux PostgreSQL, ICU, frontends, crypto and extension SQL together: + +```sh +profile=//build_defs/native:linux_x86_64_glibc_2_28 +bash tools/dev/bazel.sh test -c opt //:native_linux_tests \ + --platforms="$profile" --host_platform="$profile" \ + --java_runtime_version=remotejdk_17 --tool_java_runtime_version=remotejdk_17 --jobs=2 +``` + +This profile uses declared Zig, Bison, Flex, Perl, PostgreSQL, ICU and OpenSSL +inputs. The installed smoke exercises fresh initialization, +SQL, persistence, backup/recovery, managed ICU and separate embedded/server +extension modules. Linux ARM64 and Android have separate configured targets. +Cross-compilation proves construction and binary contracts; runtime behavior +still requires the actual host or device. + +Installed SDK checks also consume the completed dependencies declared by their +manifests. With an existing GitHub CLI login, acquire their source-bound public +input snapshot once: + +```sh +inputs_root="$(mktemp -d)" +public_inputs="$(GH_TOKEN="$(gh auth token)" bash tools/release/with-source.sh HEAD \ + bash tools/dev/bun.sh tools/release/native-release-preparation.mts \ + --publication-inputs --output-directory "$inputs_root/public")" +``` + +Only acquisition receives the credential; Bazel receives the snapshot path. CI +acquires this snapshot once before its producer jobs. Reuse it for the following +installed-package checks with the same Linux profile and optimized construction: + +```sh +profile=//build_defs/native:linux_x86_64_glibc_2_28 +bash tools/dev/bazel.sh test -c opt \ + //build_defs/languages/installed:consumer_test \ + //build_defs/languages/carriers:installed_sql_test \ + //src/native/rust-bindings:unit_test \ + //build_defs/native/carriers:package_test \ + //src/native/runtime:npm \ + //src/native/runtime:installed_cargo_test \ + //src/native/postgres-tools:cargo_facade \ + //src/native/postgres-tools:installed_cargo_test \ + //src/native/postgres-tools:installed_carrier_test \ + //build_defs/resources:resource_contract_test \ + //src/database-resources:linux_resource_test \ + //src/database-resources:android_datum64_standard_carriers \ + //src/database-resources:android_datum64_icu_carriers \ + //src/native/sdks/react-native:source_consumer_test \ + //src/native/sdks/react-native:lifecycle_test \ + //src/examples/native/react-native-expo:autolinking_consumer_test \ + //src/native/sdks/kotlin:android_maven \ + //src/native/sdks/kotlin:installed_public_api_consumer \ + //src/native/sdks/kotlin:android_test \ + //src/native/sdks/kotlin/oliphaunt-android-gradle-plugin:contract_test \ + //src/native/sdks/kotlin/oliphaunt-android-gradle-plugin:plugin_maven \ + //src/native/sdks/kotlin/oliphaunt-android-gradle-plugin:marker_maven \ + --repo_env=OLIPHAUNT_NATIVE_PUBLICATION_INPUTS="$public_inputs" \ + --platforms="$profile" --host_platform="$profile" \ + --java_runtime_version=remotejdk_17 --tool_java_runtime_version=remotejdk_17 --jobs=2 +``` + +These tests consume the constructed archives, verify direct and broker SQL and +reopening, and check the actual installed dependency versions. Packaging-only +edits reuse the compiler outputs; unchanged requests execute zero actions. +The resource tests reopen the exact frozen seed bytes with the candidate Linux +runtime. Android carrier construction checks actual configured runtime ABI +receipts; device execution remains a separate qualification requirement. + +WASIX AOT construction uses `--config=wasix-aot` to declare the Linux LLVM +execution platform. Its build tools require glibc 2.34; public native Linux +packages retain their glibc 2.28 target profile. Cross-target AOT construction +still needs deserialization and runtime checks on each supported host. + +Construct the four Linux x64 AOT images and exercise the Rust and TypeScript SDKs +locally, reusing the public input snapshot above: + +```sh +sdk_cache="$(mktemp -d)" +bash tools/dev/bazel.sh test --config=wasix-aot \ + //src/wasix/runtime:aot_linux_x64_gnu_payload \ + //src/wasix/sdks/rust:postgres_regression_test \ + //src/wasix/sdks/ts:installed_host_test \ + --repo_env=OLIPHAUNT_NATIVE_PUBLICATION_INPUTS="$public_inputs" \ + --platforms=//build_defs/native:linux_x86_64_glibc_2_28 \ + --host_platform=//build_defs/native:linux_x86_64_glibc_2_28 --jobs=1 --local_test_jobs=1 \ + --test_env=OLIPHAUNT_WASM_AOT_VERIFY=full \ + --test_env=XDG_CACHE_HOME="$sdk_cache" --test_env=RUST_TEST_THREADS=1 +``` + +With Chrome or Chromium installed, run the same actual browser consumer locally: + +```sh +profile=//build_defs/native:linux_x86_64_glibc_2_28 +receipt_dir="$(mktemp -d)" +chrome_binary="$(bash tools/dev/bun.sh build_defs/wasix/browser/chrome-receipt.mts \ + "$receipt_dir/chrome-host.json" local-linux unmanaged)" +bash tools/dev/bazel.sh run --config=wasix-aot //src/wasix/sdks/ts:browser_sql_consumer \ + --platforms="$profile" --host_platform="$profile" --jobs=2 \ + -- "$chrome_binary" "$receipt_dir/chrome-host.json" +``` + +The local labels identify an unmanaged workstation. The receipt records and +rechecks the actual browser executable SHA, version, kernel and OS release hash. +CI supplies its runner image/version labels through the same helper. This test +installs the constructed SDK/query/runtime archives, executes both default and +worker exports, and qualifies OPFS persistence, synchronous Worker transport and +crash recovery against the declared standard seed. It preserves its scratch +directory and receipts on failure. + +The `Native Bazel qualification` workflow uses the same Linux commands and +declared profiles, alongside native macOS/Windows SDK and installed package +checks. Its authenticated construction evidence binds original final archives, +configured production inputs and required tests to the exact source commit. +The native release entrypoints consume this evidence and reject incomplete +product/platform coverage. Frozen installed consumers and publication readiness +remain separate gates. The migration still requires complete hosted qualification +and the seed adoption anchor before retiring legacy CI; a passing local command +or an individual platform job cannot authorize publication. + +Shared construction stays on Linux to reproduce CI locally. macOS/Windows jobs +provide licensed SDK construction and native execution where required. Cross-host +consumers receive exact final archives with their source, target and hash receipts +through GitHub artifacts. The WASIX producer captures the fifteen core, contrib +and tools Cargo files from actual shipping roots; native host jobs download that producing job's immutable +artifact ID and require the checkout commit to match its source receipt. The importer +verifies each archive and compiles its extracted Rust sources and build script. +macOS, Windows and Linux ARM64 then run the same seven SDK SQL scenarios without +requesting Linux WASIX or AOT producers. This is a matching-source construction +handoff; it does not select historical published versions or admit a release. +Foreign-host execution and full carrier coverage must pass before cutover. No remote +executor is needed for this handoff. + +The Node-API release build compiles the workspace Rust SDK and embeds the +constructed core and contrib payloads. Linux constructs those payloads once; +other hosts consume the original captured archives. Cargo path/version +requirements and the addon's exact npm compatibility metadata describe these +relationships. The public Rust SDK's minimum runtime requirement can remain +held while the addon embeds a newer compatible runtime. + +Reproduce an imported Linux SDK consumer using a captured directory locally: + +```sh +profile=//build_defs/native:linux_x86_64_glibc_2_28 +inputs=/absolute/path/to/wasix-cargo-construction +source_commit="$(git rev-parse HEAD)" +sdk_cache="$(mktemp -d)" +bash tools/dev/bazel.sh test //src/wasix/sdks/rust:postgres_regression_test \ + --platforms="$profile" --host_platform="$profile" \ + --repo_env=OLIPHAUNT_WASIX_CARGO_INPUTS="$inputs" \ + --repo_env=OLIPHAUNT_WASIX_SOURCE_COMMIT="$source_commit" \ + --jobs=2 --local_test_jobs=1 \ + --test_env=OLIPHAUNT_WASM_AOT_VERIFY=full \ + --test_env=XDG_CACHE_HOME="$sdk_cache" --test_env=RUST_TEST_THREADS=1 +``` + +`@oliphaunt_metadata` imports existing release and extension manifests. Its +identity targets have no payload dependencies. Construction exports describe +actual output roots; their `scope: construction` cannot certify payload versions, +compatibility, complete rule/acquisition provenance or publication. The aquery +adapter requires per-product baseline deltas and reports unclassified paths. +Acquisition metadata excludes unrelated public versions, so release bumps do +not rewrite the external dependency lock. + +The real query construction exports are `//src/query/rust:shipping_export` and +`//src/query/ts:shipping_export`. Their respective `:shipping_package` roots +construct the archives; exports alone record analysis metadata. Conformance +checks both actual package manifests and their action-input closures. +`tools/release/prepare-release-pr.sh` invokes native release preparation. It +compares authenticated deliveries with each product's completed publication, +closes necessary compatibility adoption and passes those selected owners to +Release Please for version calculation. Missing historical facts block a decision; +the old ownership graph is not a fallback selector. + +Compiled external WASIX extensions first link against their declared completed +runtime. When that floor equals the workspace runtime version, source +qualification can also prove that new imports require the current core. It +records both physical inputs and the missing exports. Preparation uses this +proof to retarget a necessary extension/runtime release pair; it does not select +either product solely from ABI reachability. Generated release trees require +the final exact host and cannot use this source probe as publication evidence. + +Tool/rule repins intentionally update `MODULE.bazel.lock`: + +```sh +bash tools/dev/bazel.sh mod deps --lockfile_mode=update +``` + +Ordinary commands verify that lock. See the +[migration strategy](../../src/docs/architecture/bazel-migration-strategy.md) +for remaining product coverage and cutover gates. diff --git a/tools/bazel/check-shipping-coverage.mts b/tools/bazel/check-shipping-coverage.mts new file mode 100644 index 000000000..058ee64d5 --- /dev/null +++ b/tools/bazel/check-shipping-coverage.mts @@ -0,0 +1,93 @@ +#!/usr/bin/env bun +/** Read-only coverage check; never builds, selects releases or admits publication. */ +import { readFileSync } from 'node:fs'; +import { loadPublicationCatalog, resolveActualCarrier } from '../release/publication-catalog.mts'; +import { expectedProductArtifactRows } from '../release/publication-lock.mts'; +import { type ConfiguredShippingCohort, checkShippingCoverage } from './shipping-coverage.mts'; + +async function main() { + const products: string[] = []; + const cohorts: (ConfiguredShippingCohort & { executionRoot?: string })[] = []; + let includeReleaseInputs = false; + let physical = false; + const args = process.argv.slice(2); + for (let index = 0; index < args.length; index += 1) { + const option = args[index]; + if (option === '--product') { + const product = args[++index]; + if (!product || product.startsWith('--')) throw new Error('--product requires a product id'); + products.push(product); + } else if (option === '--cohort') { + const roots = args[++index]; + const graph = args[++index]; + if (!roots || !graph || roots.startsWith('--') || graph.startsWith('--')) + throw new Error('--cohort requires roots.jsonl and aquery.json'); + cohorts.push({ + roots: readFileSync(roots, 'utf8') + .split(/\r?\n/) + .filter((line) => line.trim()) + .map((line) => JSON.parse(line)), + aquery: JSON.parse(readFileSync(graph, 'utf8')), + }); + } else if (option === '--execution-root') { + const executionRoot = args[++index]; + const cohort = cohorts.at(-1); + if (!executionRoot || executionRoot.startsWith('--') || !cohort || cohort.executionRoot) + throw new Error('--execution-root requires one path for the preceding cohort'); + cohort.executionRoot = executionRoot; + } else if (option === '--physical') { + physical = true; + } else if (option === '--release-inputs') { + includeReleaseInputs = true; + } else { + throw new Error( + `unknown argument ${option}; use [--product ID] --cohort roots.jsonl aquery.json [--release-inputs] [--physical --execution-root ROOT]`, + ); + } + } + if (!cohorts.length) throw new Error('at least one actual configured cohort is required'); + if (!physical && cohorts.some((cohort) => cohort.executionRoot)) + throw new Error('--execution-root requires --physical'); + const catalog = loadPublicationCatalog('native-shipping-coverage'); + const selected = products.length + ? new Set(products) + : new Set(catalog.products.map(({ id }) => id)); + const authority = { + catalog, + artifactRows: expectedProductArtifactRows( + catalog.products.filter(({ id }) => selected.has(id)), + ), + resolveCarrier: (ecosystem: string, name: string) => + resolveActualCarrier(catalog, ecosystem, name, 'native-shipping-coverage'), + }; + const options = { products: products.length ? products : undefined }; + let report; + if (physical) { + const { readNativePublicationArtifacts } = await import( + '../release/native-publication-artifacts.mts' + ); + report = readNativePublicationArtifacts( + authority, + cohorts.map((cohort) => { + if (!cohort.executionRoot) + throw new Error( + '--physical requires an explicit captured --execution-root for every cohort', + ); + return { ...cohort, executionRoot: cohort.executionRoot }; + }), + options, + ); + } else { + report = checkShippingCoverage(authority, cohorts, { ...options, includeReleaseInputs }); + } + console.log(JSON.stringify(report, null, 2)); +} + +if (import.meta.main) { + try { + await main(); + } catch (error) { + console.error(error instanceof Error ? error.message : error); + process.exitCode = 1; + } +} diff --git a/tools/bazel/shipping-coverage.mts b/tools/bazel/shipping-coverage.mts new file mode 100644 index 000000000..ed413b761 --- /dev/null +++ b/tools/bazel/shipping-coverage.mts @@ -0,0 +1,281 @@ +/** Check construction coverage; physical publication admission remains separate. */ +import { buildShippingInputView } from '../release/bazel-shipping-inputs.mts'; + +type Row = Record; + +export interface CanonicalProduct { + id: string; + version: string; + publishTargets?: string[]; +} + +export interface CanonicalCarrier { + id: string; + product: string; + version: string; + ecosystem: string; + name: string; + role: string; + target: string | null; + declared: boolean; + parentCarrier?: string; +} + +export interface CanonicalArtifact { + product: string; + version: string; + id: string; + role: string; + kind: string; + target: string; + identity: string | null; + name: string; +} + +export interface CoverageAuthority { + catalog: { + schema: string; + products: CanonicalProduct[]; + carriers: CanonicalCarrier[]; + }; + artifactRows: CanonicalArtifact[]; + // Production callers use publication-catalog.resolveActualCarrier. Keep + // dynamic Cargo naming policy with its existing conventional authority. + resolveCarrier: (ecosystem: string, name: string) => CanonicalCarrier; +} + +export interface ConfiguredShippingCohort { + roots: unknown[]; + aquery: unknown; +} + +function object(value: unknown, context: string): Row { + if (!value || Array.isArray(value) || typeof value !== 'object') + throw new Error(`${context} must be an object`); + return value as Row; +} + +function text(value: unknown, context: string): string { + if (typeof value !== 'string' || !value) throw new Error(`${context} must be nonempty`); + return value; +} + +function unique(rows: T[], key: (row: T) => string, context: string): Map { + const result = new Map(); + for (const row of rows) { + const identity = key(row); + if (result.has(identity)) throw new Error(`duplicate ${context}: ${identity}`); + result.set(identity, row); + } + return result; +} + +/** + * Exact declared carrier/public-file coverage, backed by actual producer closures. + * A selected product subset is explicit and cannot certify complete migration. + * Root JSON must come from shipping.cquery.bzl; this does not authenticate supplied + * files, consumed bytes, execution images or successful build/test results. + */ +export function checkShippingCoverage( + authority: CoverageAuthority, + cohorts: ConfiguredShippingCohort[], + { + products, + includeReleaseInputs = false, + }: { products?: string[]; includeReleaseInputs?: boolean } = {}, +) { + if (authority.catalog.schema !== 'oliphaunt-publication-catalog-v1') + throw new Error('unsupported canonical publication catalog'); + const knownProducts = unique( + authority.catalog.products, + (product) => product.id, + 'canonical product', + ); + const selected = products ?? [...knownProducts.keys()]; + const selectedSet = new Set(selected); + if (!selected.length || selectedSet.size !== selected.length) + throw new Error('coverage requires a nonempty, unique product selection'); + for (const product of selected) { + if (!knownProducts.has(product)) throw new Error(`unknown selected product: ${product}`); + } + const declaredCarriers = unique( + authority.catalog.carriers, + (carrier) => carrier.id, + 'canonical carrier', + ); + for (const carrier of declaredCarriers.values()) { + const owner = knownProducts.get(carrier.product); + if (!owner || carrier.version !== owner.version || !carrier.declared) + throw new Error(`inconsistent canonical carrier: ${carrier.id}`); + } + const artifactRows = unique( + authority.artifactRows, + (artifact) => `${artifact.product}:${artifact.id}`, + 'canonical artifact', + ); + for (const artifact of artifactRows.values()) { + const owner = knownProducts.get(artifact.product); + if ( + !owner || + artifact.version !== owner.version || + !['github-release-asset', 'github-release-metadata', 'release-input'].includes(artifact.role) + ) + throw new Error(`inconsistent canonical artifact: ${artifact.id}`); + } + // The source-tag publisher consumes a frozen manifest and tree. Their lock + // role remains release-input; candidate-only fixtures cannot replace them. + const sourcePublicationArtifacts = new Set(); + for (const product of knownProducts.values()) { + if ( + !selectedSet.has(product.id) || + !product.publishTargets?.includes('swift-package-source-tag') + ) + continue; + for (const kind of ['swiftpm-release-manifest', 'swiftpm-release-tree']) { + const rows = [...artifactRows.values()].filter( + (artifact) => + artifact.product === product.id && + artifact.kind === kind && + artifact.role === 'release-input', + ); + if (rows.length !== 1) + throw new Error(`source publication requires one canonical ${kind}: ${product.id}`); + sourcePublicationArtifacts.add(`${product.id}:${rows[0].id}`); + } + } + const expectedCarriers = [...declaredCarriers.values()].filter((carrier) => + selectedSet.has(carrier.product), + ); + const expectedArtifacts = [...artifactRows.values()].filter( + (artifact) => + selectedSet.has(artifact.product) && + (includeReleaseInputs || + artifact.role !== 'release-input' || + sourcePublicationArtifacts.has(`${artifact.product}:${artifact.id}`)), + ); + const seen = new Set(); + const actualCarriers = new Map(); + const actualArtifacts = new Set(); + const representedProducts = new Set(); + const labels = new Set(); + const internalLabels = new Set(); + let internalRoots = 0; + let releaseInputRoots = 0; + const constructionActions = new Set(); + for (const cohort of cohorts) { + if (!Array.isArray(cohort.roots)) throw new Error('configured cohort roots must be an array'); + const packages = cohort.roots.map((value) => { + const root = object(value, 'configured root'); + const label = text(root.label, 'configured root label').replace(/^@@?\/\//, '//'); + if (!/^(?:@@?[^/\s:]+\/\/|\/\/)[^:\s]*:[^:\s]+$/.test(label)) + throw new Error(`invalid root label: ${label}`); + const pkg = object(root.package, `ShippingInfo ${label}`); + const product = text(pkg.product, 'product'); + const owner = knownProducts.get(product); + if (!owner || !selectedSet.has(product)) + throw new Error(`unexpected shipping product: ${product}`); + if (pkg.version !== owner.version) throw new Error(`wrong shipping version for ${product}`); + // One publication identity has one final root. Duplicated cohort/root + // scheduling is an error even when its resulting bytes would be equal. + const ecosystem = text(pkg.ecosystem, 'ecosystem'); + const identity = `${ecosystem === 'github' ? `${product}:` : ''}${ecosystem}:${text(pkg.name, 'name')}${ecosystem === 'internal' ? `:${text(pkg.configuration, 'configuration')}` : ''}`; + if (seen.has(identity)) + throw new Error(`duplicate configured shipping identity: ${identity}`); + seen.add(identity); + (ecosystem === 'internal' ? internalLabels : labels).add(label); + return pkg; + }); + const view = buildShippingInputView( + { + schema: 'oliphaunt-bazel-shipping-v1', + scope: 'construction', + packages, + }, + cohort.aquery, + ); + for (const product of Object.values(view.products)) { + for (const action of product.actions) constructionActions.add(action); + } + for (const pkg of packages) { + const product = text(pkg.product, 'product'); + const ecosystem = text(pkg.ecosystem, 'ecosystem'); + const name = text(pkg.name, 'name'); + const configuration = text(pkg.configuration, 'configuration'); + const role = text(pkg.role, 'role'); + if (ecosystem === 'internal') { + internalRoots += 1; + continue; + } + if (['cargo', 'npm', 'maven'].includes(ecosystem)) { + const identity = `${ecosystem}:${name}`; + const carrier = declaredCarriers.get(identity) ?? authority.resolveCarrier(ecosystem, name); + if ( + carrier.id !== identity || + carrier.product !== product || + carrier.version !== pkg.version + ) + throw new Error(`wrong carrier ownership/version: ${identity}`); + if (carrier.target !== null && carrier.target !== configuration) + throw new Error(`wrong carrier target for ${identity}: ${configuration}`); + if (role !== carrier.role) throw new Error(`wrong carrier role for ${identity}: ${role}`); + actualCarriers.set(identity, carrier); + representedProducts.add(product); + } else if (ecosystem === 'github' || role === 'release-input') { + const matches = [...artifactRows.values()].filter( + (artifact) => + artifact.product === product && artifact.name === name && artifact.role === role, + ); + if (matches.length !== 1) + throw new Error(`unexpected public artifact: ${product}:${role}:${name}`); + const artifact = matches[0]; + if (artifact.target !== configuration) + throw new Error(`wrong artifact target for ${artifact.id}: ${configuration}`); + actualArtifacts.add(`${product}:${artifact.id}`); + if (role === 'release-input') releaseInputRoots += 1; + if (role !== 'release-input' || sourcePublicationArtifacts.has(`${product}:${artifact.id}`)) + representedProducts.add(product); + } else { + throw new Error(`unsupported public shipping ecosystem: ${ecosystem}`); + } + } + } + for (const carrier of actualCarriers.values()) { + if (!carrier.declared && (!carrier.parentCarrier || !actualCarriers.has(carrier.parentCarrier))) + throw new Error(`dynamic payload part cannot replace its declared parent: ${carrier.id}`); + } + const missing = [ + ...selected + .filter((product) => !representedProducts.has(product)) + .map((product) => `product:${product}`), + ...expectedCarriers + .filter((carrier) => !actualCarriers.has(carrier.id)) + .map((carrier) => carrier.id), + ...expectedArtifacts + .filter((artifact) => !actualArtifacts.has(`${artifact.product}:${artifact.id}`)) + .map((artifact) => `${artifact.product}:${artifact.id}`), + ].sort(); + if (missing.length) + throw new Error(`incomplete native shipping coverage:\n${missing.join('\n')}`); + return { + scope: 'construction' as const, + completeProductInventory: selectedSet.size === knownProducts.size, + products: [...selected].sort(), + declaredCarriers: expectedCarriers.length, + dynamicCarriers: [...actualCarriers.values()].filter((carrier) => !carrier.declared).length, + publicArtifacts: expectedArtifacts.filter((artifact) => artifact.role !== 'release-input') + .length, + sourcePublicationInputs: sourcePublicationArtifacts.size, + releaseInputsRequired: includeReleaseInputs, + releaseInputRoots, + internalRoots, + rootLabels: [...labels].sort(), + internalRootLabels: [...internalLabels].sort(), + constructionActionDescriptions: constructionActions.size, + unverified: [ + 'packed manifests, artifact kinds and payload identities', + 'consumed content and loaded-rule, acquisition and configuration provenance', + 'producer execution or trusted cached-result provenance', + 'consumer and runtime compatibility', + ], + }; +} diff --git a/tools/bazel/shipping.cquery.bzl b/tools/bazel/shipping.cquery.bzl new file mode 100644 index 000000000..2ac1ed6c6 --- /dev/null +++ b/tools/bazel/shipping.cquery.bzl @@ -0,0 +1,23 @@ +"""Print actual configured ShippingInfo roots as JSON lines for coverage checks. + +Use with cquery --output=starlark --starlark:file=tools/bazel/shipping.cquery.bzl. +Query complete roots in one configured cohort, then aquery deps(the same roots) +with --include_artifacts --include_commandline --output=jsonproto. +""" + +def format(target): + info = providers(target).get("//build_defs/release:shipping.bzl%ShippingInfo") + if info == None: + return "" + package = { + "product": info.product, + "version": info.version, + "ecosystem": info.ecosystem, + "name": info.name, + "configuration": info.configuration, + "role": info.role, + "outputs": [{"path": file.path, "owner": str(file.owner)} for file in info.files.to_list()], + } + if info.supplier_inputs != None: + package["supplierInputs"] = info.supplier_inputs + return json.encode({"label": str(target.label), "package": package}) diff --git a/tools/bazel/tests/conformance.mts b/tools/bazel/tests/conformance.mts new file mode 100644 index 000000000..29196e705 --- /dev/null +++ b/tools/bazel/tests/conformance.mts @@ -0,0 +1,1942 @@ +import { strict as assert } from 'node:assert'; +import { execFileSync, spawnSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + cpSync, + existsSync, + lstatSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + readlinkSync, + realpathSync, + renameSync, + rmdirSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { readPortableArchiveEntries } from '../../packaging/portable-archive.mts'; +import { + buildShippingInputView, + canonicalShippingLabel, + type ShippingInputView, + selectShippingChanges, +} from '../../release/bazel-shipping-inputs.mts'; +import { executedFixtureSpawns, parseExecutionLog, type SpawnExecution } from './execution-log.mts'; + +const sourceRoot = + process.env.BUILD_WORKSPACE_DIRECTORY ?? path.resolve(import.meta.dir, '../../..'); +const fixturePath = 'tools/bazel/tests/fixtures/action-graph'; +const label = `//${fixturePath}`; +const products = ['alpha', 'beta', 'gamma'] as const; +type Product = (typeof products)[number]; +const scratch = mkdtempSync(path.join(tmpdir(), 'oliphaunt-bazel-conformance-')); +const workspace = path.join(scratch, 'source'); +const outputBase = path.join(scratch, 'output'); +const fixture = path.join(workspace, fixturePath); +const wrapper = path.join(workspace, 'tools/dev/bazel.sh'); +const records: { scenario: string; production: Record; tests: string[] }[] = []; +const queryRecords: { scenario: string; producerSpawns: number }[] = []; +const model = { shared: 10, config: 0, alpha: 1, beta: 2, gamma: 3, legal: 1 }; +let invocation = 0; +let completed = false; +let priorView: ShippingInputView; +// BEP includes Bazel's client environment. Keep credentials, local SDK selectors +// and user shell configuration out of both the build and its evidence files. +const subprocessEnvironment = Object.fromEntries( + ['PATH', 'HOME', 'XDG_CACHE_HOME', 'TMPDIR', 'TMP', 'TEMP', 'SYSTEMROOT', 'SystemRoot'].flatMap( + (key) => (process.env[key] === undefined ? [] : [[key, process.env[key] as string]]), + ), +); +const startupOptions = ['--nosystem_rc', '--nohome_rc', `--output_base=${outputBase}`]; + +function removePrivateScratch(directory: string) { + const makeDirectoriesWritable = (current: string) => { + const stat = lstatSync(current); + if (!stat.isDirectory()) return; + // Bazel makes tree outputs read-only. Change only private directories; + // files may be hardlinked, and symlinks may point outside this workspace. + chmodSync(current, (stat.mode & 0o7777) | 0o700); + for (const entry of readdirSync(current, { withFileTypes: true })) { + if (entry.isDirectory()) makeDirectoriesWritable(path.join(current, entry.name)); + } + }; + makeDirectoriesWritable(directory); + rmSync(directory, { recursive: true, force: true }); +} + +function snapshot() { + const files = execFileSync( + 'git', + ['-C', sourceRoot, 'ls-files', '-z', '--cached', '--others', '--exclude-standard'], + { encoding: 'utf8', env: subprocessEnvironment }, + ); + const captured = []; + for (const file of [...new Set(files.split('\0').filter(Boolean))].sort()) { + const input = path.join(sourceRoot, file); + if (!existsSync(input)) continue; + const output = path.join(workspace, file); + mkdirSync(path.dirname(output), { recursive: true }); + cpSync(input, output, { dereference: false }); + const stat = lstatSync(output); + captured.push({ + path: file, + mode: stat.isSymbolicLink() ? '120000' : stat.mode & 0o111 ? '100755' : '100644', + sha256: createHash('sha256') + .update(stat.isSymbolicLink() ? readlinkSync(output) : readFileSync(output)) + .digest('hex'), + }); + } + console.log( + JSON.stringify({ + sourceSnapshot: { + head: execFileSync('git', ['-C', sourceRoot, 'rev-parse', 'HEAD'], { + encoding: 'utf8', + env: subprocessEnvironment, + }).trim(), + files: captured.length, + treeSha256: createHash('sha256').update(JSON.stringify(captured)).digest('hex'), + }, + }), + ); +} + +function bazel(command: string, args: string[], expectFailure = false, base = outputBase) { + const result = spawnSync( + 'bash', + [ + wrapper, + ...startupOptions.map((option) => + option.startsWith('--output_base=') ? `--output_base=${base}` : option, + ), + ...(base === outputBase ? [] : ['--host_jvm_args=-Xmx768m']), + command, + '--repo_env=DO_NOT_TRACK=1', + ...args, + ], + { + cwd: workspace, + encoding: 'utf8', + timeout: command === 'shutdown' ? 30_000 : 180_000, + maxBuffer: 16 * 1024 * 1024, + env: subprocessEnvironment, + }, + ); + if (result.error || (expectFailure ? result.status === 0 : result.status !== 0)) { + throw new Error( + `Bazel ${command} ${args.join(' ')} returned ${result.status}: ${result.error ?? ''}\n${result.stdout}\n${result.stderr}`, + ); + } + return result; +} + +function externalBunEntrypoints() { + const repository = path.join(scratch, 'external-bun'); + cpSync(path.join(workspace, 'build_defs/foundation/fixtures/bun_external'), repository, { + recursive: true, + }); + const build = readFileSync(path.join(repository, 'fixture.BUILD.bazel')); + writeFileSync(path.join(repository, 'BUILD.bazel'), build); + mkdirSync(path.join(repository, 'nested')); + writeFileSync( + path.join(repository, 'nested/BUILD.bazel'), + readFileSync(path.join(repository, 'nested.fixture.BUILD.bazel')), + ); + writeFileSync(path.join(repository, 'WORKSPACE.bazel'), ''); + const injection = `--inject_repository=conformance_external_bun=${repository}`; + const packages = ['@conformance_external_bun//', '@conformance_external_bun//nested']; + bazel('test', [ + '//build_defs/foundation:bun_toolchain_test', + '//build_defs/foundation:native_entry_test', + '//build_defs/foundation:toolchain_metadata_test', + ...packages.flatMap((pkg) => + ['test', 'script_test', 'toolchain_test'].map((name) => `${pkg}:${name}`), + ), + injection, + '--test_output=errors', + '--noshow_progress', + ]); + for (const pkg of packages) { + const result = bazel('run', [`${pkg}:binary`, injection, '--noshow_progress']); + assert.equal(result.stdout.trim(), 'external Bun entrypoint'); + } + for (const name of ['missing_entry_argument_test', 'wrong_entry_argument_test']) { + const result = bazel( + 'build', + [`//build_defs/foundation/fixtures/bun_imports:${name}`, '--nobuild', '--noshow_progress'], + true, + ); + assert.match(result.stderr, /Bun entrypoint requires args\[0\]/u); + } + console.log( + JSON.stringify({ + externalBunEntrypoints: { + mainTests: 3, + externalTests: 6, + binaries: 2, + rejectedEntryArguments: 2, + }, + }), + ); +} + +function capturedSwiftPackageIdentity() { + const repository = path.join(scratch, 'captured-swift'); + const targets = { + Core: { path: 'Sources/Core', dependencies: [] }, + Consumer: { path: 'Sources/Consumer', dependencies: ['Core'] }, + CBridge: { + path: 'Sources/CBridge', + dependencies: ['liboliphaunt'], + publicHeaders: 'include', + define: 'FIXTURE', + }, + }; + for (const [module, target] of Object.entries(targets)) { + const directory = path.join(repository, target.path); + mkdirSync(directory, { recursive: true }); + writeFileSync(path.join(directory, `${module}.${module === 'CBridge' ? 'c' : 'swift'}`), ''); + } + mkdirSync(path.join(repository, targets.CBridge.path, 'include')); + writeFileSync(path.join(repository, targets.CBridge.path, 'include/bridge.h'), ''); + writeFileSync(path.join(repository, 'WORKSPACE.bazel'), ''); + writeFileSync( + path.join(repository, 'BUILD.bazel'), + `load("@oliphaunt//build_defs/apple:captured-swift.bzl", "captured_swift_package") +captured_swift_package(runtime = "@oliphaunt//${fixturePath}:shared", targets = ${JSON.stringify(targets)}, language_version = "6") +`, + ); + const injection = `--inject_repository=conformance_captured_swift=${repository}`; + const libraries = 'kind("swift_library rule", @conformance_captured_swift//:all)'; + const query = (expression: string) => + bazel('query', [expression, injection, '--output=label', '--noshow_progress']) + .stdout.trim() + .split('\n') + .filter(Boolean) + .map((label) => label.slice(label.indexOf('//'))) + .sort(); + const swift = query(libraries); + assert.deepEqual(swift, ['//:Consumer', '//:Core']); + assert.deepEqual( + query(`attr(package_name, "^Oliphaunt$", ${libraries})`), + swift, + 'every imported Swift module must share the conventional SDK package identity', + ); + assert.deepEqual(query('kind("cc_library rule", @conformance_captured_swift//:CBridge)'), [ + '//:CBridge', + ]); +} + +function checksumFamilyOriginalFiles() { + const repository = path.join(scratch, 'checksum-families'); + mkdirSync(repository); + writeFileSync(path.join(repository, 'WORKSPACE.bazel'), ''); + writeFileSync(path.join(repository, 'BUILD.bazel'), ''); + const versions = JSON.parse( + readFileSync(path.join(workspace, '.release-please-manifest.json'), 'utf8'), + ); + const source = { commit: 'a'.repeat(40), tree: 'b'.repeat(40) }; + const bytes = Buffer.from('controlled identical current and completed archive bytes\n'); + const sha256 = createHash('sha256').update(bytes).digest('hex'); + const families = [ + { + product: 'liboliphaunt-native', + path: 'src/native/runtime', + asset: 'liboliphaunt-{version}-linux-x64-gnu.tar.gz', + }, + { + product: 'liboliphaunt-wasix', + path: 'src/wasix/runtime', + asset: 'liboliphaunt-wasix-{version}-runtime-portable.tar.zst', + }, + ].map((family, index) => { + const version = versions[family.path]; + assert.equal(typeof version, 'string'); + const name = family.asset.replaceAll('{version}', version); + const directory = path.join(repository, `family${index}`); + mkdirSync(directory); + writeFileSync( + path.join(directory, 'BUILD.bazel'), + `load("@oliphaunt//build_defs/native/carriers:release-family.bzl", "native_release_checksum_family") +native_release_checksum_family(product = ${JSON.stringify(family.product)}, artifact_rows = ${JSON.stringify( + [ + { + product: family.product, + kind: 'fixture-archive', + asset: family.asset, + surfaces: ['github-release'], + }, + { + product: family.product, + kind: 'checksums', + asset: `${family.product}-{version}-conformance.sha256`, + surfaces: ['github-release'], + }, + ], + )}) +`, + ); + const file = (origin: string) => { + const file = path.join(scratch, origin, family.product, name); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, bytes); + return { path: file, size: bytes.length, sha256 }; + }; + const publication = { + product: family.product, + version, + tagName: `${family.product}-v${version}`, + publicationSha: 'c'.repeat(40), + publicationTree: 'd'.repeat(40), + releaseSha: 'e'.repeat(40), + }; + return { + label: `@conformance_checksum_families//family${index}:release_family_archives`, + alias: `native-current-artifacts/${family.product}/${version}/${sha256}/${name}`, + current: { + product: family.product, + version, + artifact: `github-release:${name}`, + configuration: 'portable', + source, + file: { + ...file('current-checksum-files'), + producer: { + root: `//controlled:family${index}`, + configuration: 'f'.repeat(64), + evidenceDigest: `sha256:${'1'.repeat(64)}`, + invocationId: `controlled-family-${index}`, + output: `bazel-out/controlled/bin/${name}`, + }, + }, + }, + held: { publication, artifact: `github-release:${name}`, file: file('held-checksum-files') }, + }; + }); + const snapshot = path.join(scratch, 'checksum-family-inputs.json'); + const save = (current: (typeof families)[number]['current'][] | undefined) => + writeFileSync( + snapshot, + JSON.stringify({ + source, + supplierPublications: families.map(({ held }) => held.publication), + supplierArtifacts: families.map(({ held }) => held), + ...(current === undefined ? {} : { nativeCurrentArtifacts: current }), + }), + ); + save(families.map(({ current }) => current)); + const flags = [ + `--inject_repository=conformance_checksum_families=${repository}`, + `--repo_env=OLIPHAUNT_NATIVE_PUBLICATION_INPUTS=${snapshot}`, + '--noshow_progress', + ]; + const executionRoot = bazel('info', ['execution_root']).stdout.trim(); + for (const family of families) { + const labels = bazel('query', [`labels(archives, ${family.label})`, ...flags, '--output=label']) + .stdout.trim() + .split('\n'); + assert.equal(labels.length, 1, 'each checksum family reaches only its own original archive'); + assert.match(labels[0], /^@@?[^/]*oliphaunt_metadata\/\/:/u); + assert.equal(labels[0].split('//:')[1], family.alias); + const file = bazel('cquery', [family.label, ...flags, '--output=files']).stdout.trim(); + assert.ok(file.startsWith('external/')); + assert.equal( + realpathSync(path.resolve(executionRoot, '../..', file)), + family.current.file.path, + 'identical completed bytes cannot replace the explicit current File alias', + ); + } + const labels = families.map(({ label }) => label); + for (const current of [undefined, []]) { + save(current); + assert.deepEqual( + bazel('query', [`set(${labels.join(' ')})`, ...flags, '--output=label']) + .stdout.trim() + .split('\n') + .map((label) => label.slice(label.indexOf('//'))) + .sort(), + labels.map((label) => label.slice(label.indexOf('//'))).sort(), + ); + assert.match( + bazel('cquery', [labels[0], ...flags], true).stderr, + /release family is missing canonical public archive Files/u, + ); + } + save(families.map(({ current }) => current)); + bazel('cquery', [labels[0], ...flags, '--output=files']); +} + +function installedAppleFinalInputs() { + const pkg = '//src/examples/native/react-native-expo'; + const resources = `${pkg}:ios_selected_resources`; + const versions = JSON.parse( + readFileSync(path.join(workspace, '.release-please-manifest.json'), 'utf8'), + ); + const source = { commit: 'a'.repeat(40), tree: 'b'.repeat(40) }; + const directory = path.join(scratch, 'installed-apple-inputs'); + mkdirSync(directory); + const file = (name: string) => { + const bytes = Buffer.from(`controlled analysis-only original File ${name}\n`); + const file = path.join(directory, name); + writeFileSync(file, bytes); + return { + path: file, + size: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + producer: { + root: '//controlled:apple_final_files', + configuration: 'f'.repeat(64), + evidenceDigest: `sha256:${'1'.repeat(64)}`, + invocationId: 'controlled-apple-final-files', + output: `bazel-out/controlled/bin/${name}`, + }, + }; + }; + const product = 'oliphaunt-extension-vector'; + const snapshot = { + source, + extensionFinalInputs: [ + { + product, + owner: product, + version: versions['src/extensions/external/vector'], + family: 'native', + target: 'ios-xcframework', + github: [file('controlled-vector-ios.tar.gz')], + npm: [], + cargo: [], + manifest: file('controlled-vector-manifest.json'), + frozen: file('controlled-vector-frozen.json'), + }, + ], + nativeCurrentArtifacts: ['tar.zst', 'json'].map((suffix) => { + const version = versions['src/database-resources']; + const name = `database-resources-${version}-seed-native-ios-datum64-standard.${suffix}`; + return { + product: 'database-resources', + version, + artifact: `github-release:${name}`, + configuration: 'ios-datum64', + source, + file: file(name), + }; + }), + }; + const inputs = path.join(directory, 'inputs.json'); + const save = (value: typeof snapshot) => writeFileSync(inputs, JSON.stringify(value)); + save(snapshot); + const flags = [`--repo_env=OLIPHAUNT_NATIVE_PUBLICATION_INPUTS=${inputs}`, '--noshow_progress']; + const query = (expression: string) => + bazel('query', [expression, ...flags, '--output=label']) + .stdout.trim() + .split('\n') + .filter(Boolean) + .map(canonicalShippingLabel) + .sort(); + const resourceSources = path.join(directory, 'resource-sources'); + for (const label of query( + `kind("source file", deps(labels("$runner", ${resources}) union labels("$helpers", ${resources}) union labels(legal, ${resources})))`, + )) { + assert.ok(label.startsWith('//'), 'app helper sources must retain their workspace paths'); + const relative = label.slice(2).split(':').filter(Boolean).join('/'); + const destination = path.join(resourceSources, relative); + mkdirSync(path.dirname(destination), { recursive: true }); + cpSync(realpathSync(path.join(workspace, relative)), destination); + } + const legalProbe = path.join(resourceSources, 'build_defs/apple/resource-legal-probe.mts'); + writeFileSync( + legalProbe, + `import assert from 'node:assert/strict'; +import { extensionCarrierLegalContract } from '../../src/extensions/tools/extension-upstream-licenses.mts'; +const legal = extensionCarrierLegalContract(${JSON.stringify(product)}, ['vector'], { family: 'native', target: 'ios-xcframework' }); +assert.ok(legal.licenseFiles.length, 'selected app extension requires its actual upstream legal files'); +`, + ); + const legalResult = spawnSync(process.execPath, ['--no-install', '--no-env-file', legalProbe], { + cwd: resourceSources, + encoding: 'utf8', + env: subprocessEnvironment, + timeout: 30_000, + }); + assert.equal(legalResult.error, undefined); + assert.equal( + legalResult.status, + 0, + `app legal policy must run from only its declared resource helper sources: ${legalResult.stderr}`, + ); + const leafSelection = `labels(leaves, ${resources})`; + const seedSelection = `labels(seed, ${resources})`; + const linkSelection = `labels(leaf, labels(static_library, labels(deps, ${pkg}:ios_final_libraries)))`; + const leaves = query(leafSelection); + assert.ok(leaves.length, 'installed app must retain selected final extensions'); + const originals = query(`labels(inputs, ${leafSelection})`); + assert.ok( + originals.length && originals.every((label) => label.includes('//:extension-final-inputs/')), + 'installed app extensions must consume original final File aliases', + ); + assert.deepEqual( + query(linkSelection), + leaves, + 'resources and linker share the same original final leaves', + ); + const selected = query(`${leafSelection} union ${seedSelection}`); + const closure = query(`deps(${leafSelection} union ${seedSelection})`); + assert.ok(closure.some((label) => label.includes('//:extension-final-inputs/'))); + assert.ok( + closure.some((label) => label.includes('//:native-current-artifacts/database-resources/')), + ); + assert.deepEqual( + query(`kind("cc_(library|binary) rule", deps(${leafSelection} union ${seedSelection}))`), + [], + 'installed final-file imports must not reconstruct runtime or extension compiler inputs', + ); + bazel('cquery', [`set(${selected.join(' ')})`, ...flags, '--output=files']); + save({ ...snapshot, extensionFinalInputs: [], nativeCurrentArtifacts: [] }); + assert.deepEqual( + query(`${leafSelection} union ${seedSelection}`), + selected, + 'missing imports must preserve package loading', + ); + assert.match( + bazel('cquery', [leaves[0], ...flags], true).stderr, + /extension family requires its original authenticated source\/run File inputs/u, + ); + assert.match( + bazel('cquery', [query(seedSelection)[0], ...flags], true).stderr, + /installed native seed requires its exact original current archive and manifest Files/u, + ); + save(snapshot); + bazel('cquery', [`set(${selected.join(' ')})`, ...flags, '--output=files']); + assert.deepEqual( + query( + `labels(host, //build_defs/extensions/mobile/final:${product.replaceAll('-', '_')}_ios_xcframework)`, + ), + ['//src/extensions/external/vector:native_payload'], + 'original extension producer remains source-owned', + ); + assert.deepEqual( + query('labels(producer, //src/database-resources:ios_datum64_standard_seed)'), + ['//src/database-resources:macos_arm64_standard_seed'], + 'original seed producer keeps its actual bootstrap', + ); + assert.deepEqual( + query('labels(receipts, //src/database-resources:ios_datum64_standard_seed)'), + ['//src/native/runtime:apple_ios_device_abi', '//src/native/runtime:apple_ios_simulator_abi'], + 'original seed producer keeps both actual iOS ABI inputs', + ); +} + +function ignoreGeneratedOutputDirectories() { + const queryArguments = [ + 'labels(srcs, //:root_quality_sources)', + '--output=label', + '--noshow_progress', + ]; + const original = bazel('query', queryArguments).stdout; + const generated = path.join(workspace, 'bazel-incomplete-output'); + mkdirSync(generated); + writeFileSync(path.join(generated, 'generated.json'), '{}'); + symlinkSync( + path.join(scratch, 'missing-generated-output'), + path.join(generated, 'dangling'), + 'dir', + ); + assert.equal( + bazel('query', queryArguments).stdout, + original, + 'source discovery must prune incomplete generated outputs and keep the source input graph unchanged', + ); + rmSync(generated, { recursive: true }); + const authored = [ + 'build_defs/quality/fixtures/bazel-authored.ts', + 'build_defs/quality/fixtures/bazel-authored/nested.ts', + ]; + try { + for (const file of authored) { + mkdirSync(path.dirname(path.join(workspace, file)), { recursive: true }); + writeFileSync(path.join(workspace, file), 'export const fixture = true;\n'); + } + const qualitySources = new Set( + bazel('query', [ + 'labels(srcs, //build_defs/quality:quality_sources)', + '--output=label', + '--noshow_progress', + ]) + .stdout.split(/\r?\n/u) + .filter(Boolean) + .map(canonicalShippingLabel), + ); + for (const file of authored) + assert.ok( + qualitySources.has( + `//build_defs/quality:${path.posix.relative('build_defs/quality', file)}`, + ), + 'authored bazel-* files and nested directories must remain quality sources', + ); + } finally { + rmSync(path.join(workspace, authored[0]), { force: true }); + rmSync(path.dirname(path.join(workspace, authored[1])), { recursive: true, force: true }); + } + console.log( + JSON.stringify({ generatedOutputDiscovery: 'pruned', nestedBazelSources: 'included' }), + ); +} + +function cargoBuildScriptParity() { + const repository = path.join(scratch, 'external-cargo-build-script'); + cpSync(path.join(workspace, 'tools/bazel/tests/fixtures/cargo-build-script'), repository, { + recursive: true, + }); + cpSync(path.join(repository, 'fixture.BUILD.bazel'), path.join(repository, 'BUILD.bazel')); + writeFileSync(path.join(repository, 'WORKSPACE.bazel'), ''); + for (const file of ['LICENSE', 'THIRD_PARTY_NOTICES.md']) { + cpSync(path.join(workspace, file), path.join(repository, file)); + } + const version = Bun.TOML.parse( + readFileSync(path.join(workspace, 'src/query/rust/Cargo.toml'), 'utf8'), + ).package.version; + const manifest = path.join(repository, 'Cargo.toml'); + writeFileSync( + manifest, + readFileSync(path.join(repository, 'fixture.Cargo.toml'), 'utf8').replace( + /^version = .*$/m, + `version = "${version}"`, + ), + ); + const pkg = '@conformance_cargo_build_script//'; + bazel('test', [ + `${pkg}:unit_test`, + `${pkg}:installed_consumer_test`, + `--inject_repository=conformance_cargo_build_script=${repository}`, + '--jobs=2', + '--test_output=errors', + '--noshow_progress', + ]); + console.log( + JSON.stringify({ cargoBuildScriptParity: { bazelTests: 1, installedCargoTests: 1 } }), + ); +} + +function writeModel() { + writeFileSync( + path.join(fixture, 'shared.h'), + `#define SHARED_VALUE ${model.shared}\nint shared_value(void);\n`, + ); + writeFileSync(path.join(fixture, 'config.txt'), `${model.config}\n`); + for (const product of products) { + const shared = product === 'gamma' ? '' : '#include "shared.h"\n'; + const value = product === 'gamma' ? `${model.gamma}` : `shared_value() + ${model[product]}`; + writeFileSync( + path.join(fixture, `${product}.c`), + `#include \n${shared}int main(void) { printf("%d\\n", ${value}); return 0; }\n`, + ); + // Independently authored physical consumer truth: alpha/beta share the library; gamma does not. + const expected = + product === 'gamma' ? model.gamma : model.shared + model.config + model[product]; + writeFileSync(path.join(fixture, `${product}.expected`), `${expected}\n`); + } + writeFileSync(path.join(fixture, 'LEGAL.txt'), `Fixture license, revision ${model.legal}.\n`); +} + +function targetName(spawn: SpawnExecution) { + return spawn.targetLabel?.split(':').at(-1) ?? ''; +} + +function scenario( + name: string, + allowedProduction: string[], + expectedTests: Product[], + exportName = 'export', +) { + const executionLog = path.join(scratch, `${invocation}.execution.json`); + const events = path.join(scratch, `${invocation++}.bep.json`); + const result = bazel('test', [ + `${label}:all_tests`, + `${label}:alpha_test`, + `${label}:${exportName}`, + '--jobs=2', + '--noshow_progress', + '--noshow_loading_progress', + `--execution_log_json_file=${executionLog}`, + `--build_event_json_file=${events}`, + ]); + assert.ok(existsSync(executionLog), 'execution evidence must exist'); + const executions = executedFixtureSpawns(executionLog, label); + // Bazel also logs its XML report generator with mnemonic TestRunner. + const tests = executions.filter( + (spawn) => + spawn.mnemonic === 'TestRunner' && spawn.commandArgs?.[0]?.endsWith('/test-setup.sh'), + ); + const production = executions.filter((spawn) => spawn.mnemonic !== 'TestRunner'); + assert.deepEqual( + tests.map(targetName).sort(), + expectedTests.map((product) => `${product}_test`).sort(), + `${name}: actual test attempts`, + ); + assert.equal( + new Set(tests.map(targetName)).size, + tests.length, + `${name}: duplicate test execution`, + ); + for (const spawn of production) { + const preparesExpectedTest = + spawn.mnemonic === 'CopyToDirectory' && + expectedTests.some((product) => targetName(spawn) === `${product}_test`); + assert.ok( + allowedProduction.includes(targetName(spawn)) || preparesExpectedTest, + `${name}: unnecessary ${spawn.mnemonic} for ${spawn.targetLabel}`, + ); + } + const buildEvents = readFileSync(events, 'utf8') + .trim() + .split('\n') + .filter(Boolean) + .map((line) => JSON.parse(line)); + const allowedClientEnvironment = new Set([ + ...Object.keys(subprocessEnvironment), + 'PWD', + 'OLDPWD', + 'SHLVL', + '_', + ]); + for (const event of buildEvents) { + for (const section of event.structuredCommandLine?.sections ?? []) { + for (const option of section.optionList?.option ?? []) { + if (option.optionName !== 'client_env') continue; + const key = option.optionValue.split('=', 1)[0]; + assert.ok( + allowedClientEnvironment.has(key), + `${name}: unexpected client environment key ${key}`, + ); + } + } + } + const summaries = buildEvents.filter((event) => + event.id?.testSummary?.label?.startsWith(`${label}:`), + ); + assert.equal( + summaries.length, + products.length, + `${name}: missing supported physical consumer result`, + ); + assert.ok( + summaries.every((event) => event.testSummary.overallStatus === 'PASSED'), + `${name}: unsuccessful consumer proof`, + ); + const counts: Record = {}; + for (const spawn of production) + counts[spawn.mnemonic ?? 'unknown'] = (counts[spawn.mnemonic ?? 'unknown'] ?? 0) + 1; + records.push({ scenario: name, production: counts, tests: tests.map(targetName).sort() }); + console.log(JSON.stringify(records.at(-1))); + return { executions, result }; +} + +function shippingState(exportName = 'export') { + const exported = JSON.parse( + readFileSync(path.join(workspace, 'bazel-bin', fixturePath, `${exportName}.json`), 'utf8'), + ); + const graph = JSON.parse( + bazel('aquery', [ + `deps(${label}:${exportName})`, + '--output=jsonproto', + '--include_artifacts', + '--include_commandline', + '--noshow_progress', + ]).stdout, + ); + return { exported, graph, view: buildShippingInputView(exported, graph) }; +} + +function assertEnvelopeIdentities(exported: { + packages: { + product: string; + version: string; + supplierInputs: unknown[]; + outputs: { path: string }[]; + }[]; +}) { + for (const pkg of exported.packages) { + assert.deepEqual(pkg.supplierInputs, [], 'fixture suppliers must be explicitly known empty'); + assert.equal(pkg.outputs.length, 1, 'fixture shipping envelope has exactly one output'); + const envelope = JSON.parse(readFileSync(path.join(workspace, pkg.outputs[0].path), 'utf8')); + assert.equal( + envelope.version, + pkg.version, + 'actual package version must agree with declared identity', + ); + assert.equal( + envelope.product, + pkg.product, + 'actual package owner must agree with declared identity', + ); + } +} + +function selection(changed: string[], expected: Product[], unclassified: string[] = []) { + const after = shippingState(); + assertEnvelopeIdentities(after.exported); + const paths = changed.map((file) => `${fixturePath}/${file}`); + const deltas = Object.fromEntries(products.map((product) => [`fixture-${product}`, paths])); + const result = selectShippingChanges(priorView.products, after.view, deltas); + assert.deepEqual( + result.affectedProducts, + expected.map((product) => `fixture-${product}`).sort(), + 'real adapter selection must agree with physical consumer truth', + ); + assert.deepEqual( + result.unclassifiedPaths, + unclassified.map((file) => `${fixturePath}/${file}`).sort(), + 'unknown provenance must be visible, never silently unaffected', + ); + priorView = after.view; + return after; +} + +function archives(base = outputBase, consume = false) { + const files = bazel( + 'cquery', + [ + `${label}:alpha_archive + ${label}:beta_archive + ${label}:gamma_archive`, + '--output=files', + '--noshow_progress', + ], + false, + base, + ) + .stdout.trim() + .split('\n'); + return Object.fromEntries( + products.map((product) => { + const file = files.find((entry) => entry.endsWith(`/${product}_archive.json`)); + assert.ok(file, `${product} archive must have a native output`); + const bytes = readFileSync(path.join(workspace, file)); + const envelope = JSON.parse(bytes.toString()); + assert.equal(envelope.version, { alpha: '1.0.0', beta: '2.0.0', gamma: '3.0.0' }[product]); + if (consume) { + // Cache hits need not materialize binaries below the public archive outputs. + const binary = path.join(scratch, `cache-${product}.consumer`); + writeFileSync(binary, Buffer.from(envelope.executable, 'base64'), { mode: 0o755 }); + assert.equal( + execFileSync(binary, { encoding: 'utf8', timeout: 10_000, env: subprocessEnvironment }), + readFileSync(path.join(fixture, `${product}.expected`), 'utf8'), + `${base}: physical ${product} archive consumer`, + ); + } + return [product, createHash('sha256').update(bytes).digest('hex')]; + }), + ) as Record; +} + +function unchanged( + before: Record, + after: Record, + expected: Product[], +) { + assert.deepEqual( + products.filter((product) => before[product] !== after[product]), + expected, + 'physical delivery changes must match the independent fixture truth', + ); +} + +function diskCacheAcrossFreshBases() { + const cache = path.join(scratch, 'disk-cache'); + const originalAlpha = model.alpha; + const phase = (name: string) => { + const base = path.join(scratch, `cache-${name}`); + assert.ok(!existsSync(base), 'disk cache proof requires a fresh output base'); + const log = path.join(scratch, `cache-${name}.execution.json`); + try { + bazel( + 'build', + [ + ...products.map((product) => `${label}:${product}_archive`), + '--config=ci-cache', + `--disk_cache=${cache}`, + '--jobs=2', + '--noshow_progress', + `--execution_log_json_file=${log}`, + ], + false, + base, + ); + const spawns = parseExecutionLog(readFileSync(log, 'utf8')).filter((spawn) => + spawn.targetLabel?.startsWith(`${label}:`), + ); + const executed = spawns + .filter((spawn) => !spawn.cacheHit) + .map((spawn) => ({ + mnemonic: spawn.mnemonic, + target: targetName(spawn), + })); + const hits = spawns.filter((spawn) => spawn.cacheHit); + assert.ok(hits.every((spawn) => spawn.runner === 'disk cache hit')); + const hashes = archives(base, true); + console.log(JSON.stringify({ diskCacheScenario: name, executed, hits: hits.length, hashes })); + return { executed, hits, hashes }; + } finally { + bazel('shutdown', [], false, base); + } + }; + try { + const cold = phase('cold'); + assert.equal(cold.executed.length, 15, 'cold fixture must execute its actual producer actions'); + assert.equal(cold.hits.length, 0); + const restored = phase('restored'); + assert.deepEqual(restored.executed, [], 'fresh output base must restore every producer action'); + assert.equal(restored.hits.length, cold.executed.length); + unchanged(cold.hashes, restored.hashes, []); + model.alpha += 4; + writeModel(); + const changed = phase('changed'); + assert.deepEqual(changed.executed, [ + { mnemonic: 'CppCompile', target: 'alpha_bin' }, + { mnemonic: 'CppLink', target: 'alpha_bin' }, + { mnemonic: 'FixturePackage', target: 'alpha_archive' }, + ]); + assert.equal(changed.hits.length, cold.executed.length - changed.executed.length); + unchanged(cold.hashes, changed.hashes, ['alpha']); + for (const name of ['cold', 'restored', 'changed']) + removePrivateScratch(path.join(scratch, `cache-${name}`)); + } finally { + model.alpha = originalAlpha; + writeModel(); + } +} + +function realQueryShipping(name: string, allowedTargets: string[], expectedEnvelopes?: number) { + const roots = ['src/query/rust', 'src/query/ts']; + const executionLog = path.join(scratch, `${name}.execution.json`); + bazel('build', [ + ...roots.flatMap((root) => [`//${root}:shipping_package`, `//${root}:shipping_export`]), + '--jobs=2', + '--noshow_progress', + `--execution_log_json_file=${executionLog}`, + ]); + const spawns = parseExecutionLog(readFileSync(executionLog, 'utf8')).filter( + (spawn) => !spawn.cacheHit, + ); + for (const spawn of spawns) { + assert.ok( + allowedTargets.includes(spawn.targetLabel ?? ''), + `${name}: unnecessary real query execution ${spawn.mnemonic} for ${spawn.targetLabel}`, + ); + } + if (expectedEnvelopes !== undefined) { + assert.equal(spawns.length, expectedEnvelopes, `${name}: exact packaging work`); + assert.ok( + spawns.every((spawn) => + ['QueryEnvelope', 'CargoSourceEnvelope'].includes(spawn.mnemonic ?? ''), + ), + `${name}: package-only work must not compile, extract dependencies, or run tests`, + ); + } + const exports = roots.map((root) => + JSON.parse( + readFileSync(path.join(workspace, 'bazel-bin', root, 'shipping_export.json'), 'utf8'), + ), + ); + for (const value of exports) { + assert.equal(value.schema, 'oliphaunt-bazel-shipping-v1'); + assert.equal(value.scope, 'construction'); + } + const graph = JSON.parse( + bazel('aquery', [ + 'deps(set(//src/query/rust:shipping_export //src/query/ts:shipping_export))', + '--output=jsonproto', + '--include_artifacts', + '--include_commandline', + '--noshow_progress', + ]).stdout, + ); + const exported = { + schema: 'oliphaunt-bazel-shipping-v1', + scope: 'construction', + packages: exports.flatMap((value) => value.packages), + }; + const view = buildShippingInputView(exported, graph); + const config = JSON.parse( + readFileSync(path.join(workspace, 'release-please-config.json'), 'utf8'), + ); + const versions = JSON.parse( + readFileSync(path.join(workspace, '.release-please-manifest.json'), 'utf8'), + ); + if (name === 'cold-real-query-packages') { + const rootsFile = path.join(scratch, 'query-shipping-roots.jsonl'); + const graphFile = path.join(scratch, 'query-shipping-aquery.json'); + writeFileSync( + rootsFile, + bazel('cquery', [ + 'set(//src/query/rust:shipping_package //src/query/ts:shipping_package)', + '--output=starlark', + '--starlark:file=tools/bazel/shipping.cquery.bzl', + '--noshow_progress', + ]).stdout, + ); + writeFileSync(graphFile, JSON.stringify(graph)); + const executionRoot = bazel('info', ['execution_root']).stdout.trim(); + const checkCoverage = (selected: string[], capturedRoot = executionRoot) => + spawnSync( + process.execPath, + [ + path.join(workspace, 'tools/bazel/check-shipping-coverage.mts'), + ...selected.flatMap((product) => ['--product', product]), + '--cohort', + rootsFile, + graphFile, + '--physical', + ...(capturedRoot ? ['--execution-root', capturedRoot] : []), + ], + { cwd: workspace, encoding: 'utf8', timeout: 30_000, env: subprocessEnvironment }, + ); + const subset = checkCoverage(roots.map((root) => config.packages[root].component)); + assert.equal(subset.status, 0, subset.stderr); + const coverage = JSON.parse(subset.stdout); + assert.equal(coverage.scope, 'construction'); + assert.equal(coverage.completeProductInventory, false); + assert.equal(coverage.declaredCarriers, 2); + assert.equal(coverage.rootLabels.length, 2); + assert.equal(coverage.registryArtifacts.length, 2); + for (const record of coverage.registryArtifacts) { + const pkg = exported.packages.find( + (pkg: { ecosystem: string; name: string }) => + pkg.ecosystem === record.ecosystem && pkg.name === record.name, + ); + assert.ok(pkg); + // Each exported name/version is checked against its conventional source + // manifest below; here the separate physical bridge must observe it too. + assert.equal(record.version, pkg.version); + for (const file of record.artifacts) { + assert.equal( + file.sha256, + createHash('sha256').update(readFileSync(file.path)).digest('hex'), + ); + } + } + const missingExecutionRoot = checkCoverage( + roots.map((root) => config.packages[root].component), + '', + ); + assert.equal(missingExecutionRoot.status, 1); + assert.match(missingExecutionRoot.stderr, /explicit captured --execution-root/); + const incomplete = checkCoverage([]); + assert.equal(incomplete.status, 1, 'two real package roots cannot admit full native migration'); + assert.match(incomplete.stderr, /incomplete native shipping coverage/); + assert.match(incomplete.stderr, /product:/); + } + for (const root of roots) { + const rust = root.endsWith('/rust'); + const manifest = rust + ? Bun.TOML.parse(readFileSync(path.join(workspace, root, 'Cargo.toml'), 'utf8')).package + : JSON.parse(readFileSync(path.join(workspace, root, 'package.json'), 'utf8')); + const product = config.packages[root].component; + const info = view.products[product]; + assert.ok(info, `${root}: actual shipping owner must match canonical product`); + assert.equal(info.version, manifest.version); + assert.equal(info.version, versions[root]); + const pkg = exported.packages.find((pkg: { product: string }) => pkg.product === product); + assert.equal(pkg.name, manifest.name); + assert.equal(pkg.outputs.length, 1); + const entries = readPortableArchiveEntries(path.join(workspace, pkg.outputs[0].path)); + const manifestPath = rust + ? `${manifest.name}-${manifest.version}/Cargo.toml` + : 'package/package.json'; + const packedEntry = entries.get(manifestPath); + assert.ok(packedEntry, `${root}: physical archive must contain its canonical manifest`); + const packed = rust + ? Bun.TOML.parse(packedEntry.data().toString()).package + : JSON.parse(packedEntry.data().toString()); + assert.equal(packed.name, manifest.name); + assert.equal(packed.version, info.version); + assert.ok(info.inputs.includes(`${root}/${rust ? 'Cargo.toml' : 'package.json'}`)); + assert.ok(info.inputs.some((input) => input.startsWith(`${root}/src/`))); + const actions = info.actions.map((action) => JSON.parse(action)); + assert.ok( + actions.every((action) => action.mnemonic !== 'TestRunner'), + 'consumer tests are not construction dependencies', + ); + if (rust) { + assert.ok( + actions.every((action) => + ['FileWrite', 'ExecutableSymlink', 'CopyToDirectory', 'CargoSourceEnvelope'].includes( + action.mnemonic, + ), + ), + 'a source crate requires packaging without compilation', + ); + assert.ok( + !info.inputs.some((input) => + /(?:^|\/)(?:rustc|rustdoc)(?:\.exe)?$|\/lib\/rustlib\/|nodejs_|npm_typescript/.test( + input, + ), + ), + 'Cargo source inventory must not consume compilers or target sysroots', + ); + assert.ok(entries.has(`${manifest.name}-${manifest.version}/THIRD_PARTY_NOTICES.md`)); + assert.ok(!entries.has(`${manifest.name}-${manifest.version}/BUILD.bazel`)); + } else { + for (const target of ['module', 'commonjs']) { + assert.ok( + actions.some( + (action) => action.target === `//${root}:${target}` && action.mnemonic === 'TsProject', + ), + `npm archive must include actual ${target} compilation`, + ); + } + assert.ok( + info.inputs.some((input) => input.includes('npm_typescript')), + 'npm compilation includes its declared TypeScript compiler', + ); + assert.ok( + info.inputs.some((input) => input.includes('nodejs_')), + 'npm compilation includes its declared Node runtime', + ); + } + } + console.log( + JSON.stringify({ + realQueryScenario: name, + spawns: spawns.map((spawn) => ({ mnemonic: spawn.mnemonic, target: spawn.targetLabel })), + }), + ); + queryRecords.push({ scenario: name, producerSpawns: spawns.length }); + return view; +} + +try { + snapshot(); + writeModel(); + diskCacheAcrossFreshBases(); + externalBunEntrypoints(); + capturedSwiftPackageIdentity(); + checksumFamilyOriginalFiles(); + installedAppleFinalInputs(); + cargoBuildScriptParity(); + const allProduction = [ + 'config', + 'shared', + ...products.flatMap((product) => [`${product}_bin`, `${product}_archive`]), + ]; + scenario('cold complete graph + aggregate/member union', allProduction, [...products]); + ignoreGeneratedOutputDirectories(); + assert.ok( + !readdirSync(path.join(outputBase, 'external')).some((name) => name.endsWith('+android_ndk')), + 'unrelated native targets must not acquire the Android NDK merely to register its constraints', + ); + assert.ok( + !readdirSync(path.join(outputBase, 'external')).some((name) => + name.endsWith('+oliphaunt_android_sdk_archive'), + ), + 'unrelated native targets must not acquire Android SDK archives merely to register toolchains', + ); + const sdkProbe = '//tools/bazel/tests/fixtures/android-sdk:selected_sdk'; + const sdkExecutionLog = path.join(scratch, 'selected-sdk.execution.json'); + bazel('build', [sdkProbe, '--noshow_progress', `--execution_log_json_file=${sdkExecutionLog}`]); + assert.deepEqual( + parseExecutionLog(readFileSync(sdkExecutionLog, 'utf8')), + [], + 'observing the selected SDK provider requires no compiler or consumer process', + ); + const sdkOutput = bazel('cquery', [ + sdkProbe, + '--output=files', + '--noshow_progress', + ]).stdout.trim(); + const sdkExecutionRoot = bazel('info', ['execution_root']).stdout.trim(); + const selectedSdk = JSON.parse(readFileSync(path.join(sdkExecutionRoot, sdkOutput), 'utf8')); + const sdkPins = Bun.TOML.parse( + readFileSync(path.join(workspace, 'tools/dev/android-sdk.toml'), 'utf8'), + ).packages; + assert.equal(selectedSdk.buildTools, sdkPins.build_tools); + assert.ok( + selectedSdk.androidJar.endsWith(`/platforms/android-${sdkPins.compile_sdk}/android.jar`), + ); + assert.ok( + selectedSdk.frameworkAidl.endsWith(`/platforms/android-${sdkPins.compile_sdk}/framework.aidl`), + ); + assert.ok(selectedSdk.adb.endsWith('/platform-tools/adb')); + for (const field of ['androidJar', 'frameworkAidl', 'adb']) { + assert.ok( + selectedSdk[field].startsWith('external/'), + 'SDK tools must come from a declared repository', + ); + assert.ok( + existsSync(path.join(outputBase, selectedSdk[field])), + 'selected SDK files must exist', + ); + } + assert.equal( + readFileSync(path.join(outputBase, selectedSdk.androidJar)).subarray(0, 4).toString('hex'), + '504b0304', + 'the selected Android platform jar must be a physical ZIP archive', + ); + assert.ok( + readdirSync(path.join(outputBase, 'external')).some((name) => + name.endsWith('+oliphaunt_android_sdk_archive'), + ), + 'selecting the actual Android SDK provider must materialize its checked archives', + ); + console.log(JSON.stringify({ selectedAndroidSdk: selectedSdk, producerSpawns: 0 })); + const initial = shippingState(); + assertEnvelopeIdentities(initial.exported); + priorView = initial.view; + for (const mutation of ['missing', 'wrong']) { + const tampered = structuredClone(initial.exported); + if (mutation === 'missing') delete tampered.packages[0].outputs[0].owner; + else tampered.packages[0].outputs[0].owner = tampered.packages[1].outputs[0].owner; + assert.throws(() => buildShippingInputView(tampered, initial.graph), /owner|nonempty/); + } + const incomplete = structuredClone(initial.graph); + incomplete.actions = incomplete.actions.filter( + (action: { mnemonic?: string }) => action.mnemonic !== 'FixtureConfigHeader', + ); + assert.throws( + () => buildShippingInputView(initial.exported, incomplete), + /generated|producer|incomplete/, + ); + assert.deepEqual( + buildShippingInputView( + { schema: initial.exported.schema, scope: 'construction', packages: [] }, + initial.graph, + ).products, + {}, + ); + scenario('warm identical graph', [], []); + selection([], []); + let before = archives(); + model.alpha += 4; + writeModel(); + scenario('one translation unit', ['alpha_bin', 'alpha_archive'], ['alpha']); + selection(['alpha.c'], ['alpha']); + let after = archives(); + unchanged(before, after, ['alpha']); + + before = after; + model.legal++; + writeModel(); + scenario( + 'legal envelope only', + products.map((product) => `${product}_archive`), + [...products], + ); + selection(['LEGAL.txt'], [...products]); + after = archives(); + unchanged(before, after, [...products]); + + before = after; + model.config++; + writeModel(); + scenario( + 'configuration input', + ['config', 'shared', 'alpha_bin', 'beta_bin', 'alpha_archive', 'beta_archive'], + ['alpha', 'beta'], + ); + selection(['config.txt'], ['alpha', 'beta']); + after = archives(); + unchanged(before, after, ['alpha', 'beta']); + + // Release bases are per product: beta already includes this shared edit; alpha does not. + const older = priorView; + model.shared++; + writeModel(); + scenario( + 'shared leaf with distinct product baselines', + ['shared', 'alpha_bin', 'beta_bin', 'alpha_archive', 'beta_archive'], + ['alpha', 'beta'], + ); + const newer = selection(['shared.h'], ['alpha', 'beta']); + const mixedBaseline = { + ...newer.view.products, + 'fixture-alpha': older.products['fixture-alpha'], + }; + assert.deepEqual( + selectShippingChanges(mixedBaseline, newer.view, { + 'fixture-alpha': [`${fixturePath}/shared.h`], + 'fixture-beta': [], + 'fixture-gamma': [], + }).affectedProducts, + ['fixture-alpha'], + 'an already released shared change must not bump beta again', + ); + assert.throws( + () => + selectShippingChanges(mixedBaseline, newer.view, { + 'fixture-alpha': [`${fixturePath}/shared.h`], + 'fixture-gamma': [], + }), + /delta|changed paths|baseline/i, + 'every released product needs its own delta', + ); + after = archives(); + + before = after; + const packageTool = path.join(fixture, 'package.mts'); + writeFileSync(packageTool, readFileSync(packageTool, 'utf8').replace("+ '\\n'", "+ '\\n\\n'")); + scenario( + 'package writer tool only', + products.map((product) => `${product}_archive`), + [...products], + ); + selection(['package.mts'], [...products]); + after = archives(); + unchanged(before, after, [...products]); + + writeFileSync( + path.join(fixture, 'consumer.mts'), + readFileSync(path.join(fixture, 'consumer.mts'), 'utf8') + + '\n// Changed proof harness, never a shipping input.\n', + ); + scenario('test harness only', [], [...products]); + selection(['consumer.mts'], [], ['consumer.mts']); + unchanged(after, archives(), []); + + // Enumerate all small change subsets in a reproducible shuffled order, with independent values. + let seed = 0x5eed; + const next = () => { + seed = (Math.imul(seed, 1664525) + 1013904223) >>> 0; + return seed; + }; + const subsets = [0, 1, 2, 3, 4, 5, 6, 7]; + for (let index = subsets.length - 1; index > 0; index--) { + const destination = next() % (index + 1); + [subsets[index], subsets[destination]] = [subsets[destination], subsets[index]]; + } + for (const subset of subsets) { + before = archives(); + const selected = products.filter((_, index) => subset & (1 << index)); + for (const product of selected) model[product] += (next() % 4) + 1; + writeModel(); + scenario( + `seed 0x5eed subset ${subset}`, + selected.flatMap((product) => [`${product}_bin`, `${product}_archive`]), + selected, + ); + selection( + selected.map((product) => `${product}.c`), + selected, + ); + after = archives(); + unchanged(before, after, selected); + } + + const build = path.join(fixture, 'BUILD.bazel'); + const originalBuild = readFileSync(build, 'utf8'); + writeFileSync( + build, + originalBuild.replace( + 'product_id = "fixture-beta", version = "2.0.0"', + 'product_id = "fixture-beta", version = "2.0.1"', + ), + ); + scenario('one identity version', ['beta_archive'], ['beta']); + selection(['BUILD.bazel'], ['beta'], ['BUILD.bazel']); + writeFileSync(build, originalBuild); + // Restoring a previous test variant may rerun it; the immediately repeated request must then be warm. + scenario('restore identity', ['beta_archive'], ['beta']); + selection(['BUILD.bazel'], ['beta'], ['BUILD.bazel']); + scenario('warm restored graph', [], []); + + const mirrorBuild = + originalBuild + + '\nshipping_package(name = "alpha_mirror_ship", owner = ":alpha_identity", artifacts = [":alpha_archive"], ecosystem = "github", package_name = "fixture-alpha-mirror", configuration = "fixture-host", role = "package", suppliers = "//build_defs/release:no_suppliers")\nshipping_export(name = "mirror_export", packages = [":alpha_ship", ":alpha_mirror_ship", ":beta_ship", ":gamma_ship"])\n'; + writeFileSync(build, mirrorBuild); + scenario('two carriers share one product identity', [], [], 'mirror_export'); + const sharedOwnerBefore = shippingState('mirror_export'); + assert.equal(sharedOwnerBefore.view.products['fixture-alpha'].packages.length, 2); + writeFileSync( + build, + mirrorBuild.replace( + 'product_id = "fixture-alpha", version = "1.0.0"', + 'product_id = "fixture-alpha", version = "1.0.1"', + ), + ); + scenario( + 'shared owner version updates both carriers once', + ['alpha_archive'], + ['alpha'], + 'mirror_export', + ); + const sharedOwnerAfter = shippingState('mirror_export'); + assertEnvelopeIdentities(sharedOwnerAfter.exported); + assert.deepEqual( + sharedOwnerAfter.exported.packages + .filter((pkg: { product: string }) => pkg.product === 'fixture-alpha') + .map((pkg: { version: string }) => pkg.version), + ['1.0.1', '1.0.1'], + ); + assert.deepEqual( + selectShippingChanges( + sharedOwnerBefore.view.products, + sharedOwnerAfter.view, + Object.fromEntries( + products.map((product) => [`fixture-${product}`, [`${fixturePath}/BUILD.bazel`]]), + ), + ).affectedProducts, + ['fixture-alpha'], + ); + writeFileSync(build, originalBuild); + scenario('restore shared owner fixture', ['alpha_archive'], ['alpha']); + writeFileSync( + build, + originalBuild + + '\nshipping_package(name = "shared_alpha_input", owner = ":alpha_identity", artifacts = [":config"], ecosystem = "github", package_name = "shared-control.h", configuration = "portable", role = "release-input", suppliers = "//build_defs/release:no_suppliers")\nshipping_package(name = "shared_beta_input", owner = ":beta_identity", artifacts = [":config"], ecosystem = "github", package_name = "shared-control.h", configuration = "portable", role = "release-input", suppliers = "//build_defs/release:no_suppliers")\nshipping_export(name = "shared_input_export", packages = [":shared_alpha_input", ":shared_beta_input"])\n', + ); + scenario('shared candidate input across component owners', [], [], 'shared_input_export'); + const sharedInput = shippingState('shared_input_export'); + assert.deepEqual(Object.keys(sharedInput.view.products).sort(), [ + 'fixture-alpha', + 'fixture-beta', + ]); + assert.deepEqual( + sharedInput.exported.packages[0].outputs, + sharedInput.exported.packages[1].outputs, + ); + assert.deepEqual( + sharedInput.view.products['fixture-alpha'].actions, + sharedInput.view.products['fixture-beta'].actions, + 'one physical producer is shared without inventing a second producer', + ); + writeFileSync(build, originalBuild); + priorView = shippingState().view; + + renameSync(path.join(fixture, 'alpha.c'), path.join(fixture, 'renamed-alpha.c')); + writeFileSync(build, originalBuild.replace('srcs = ["alpha.c"]', 'srcs = ["renamed-alpha.c"]')); + scenario('rename consumed source', ['alpha_bin', 'alpha_archive'], ['alpha']); + selection(['alpha.c', 'renamed-alpha.c', 'BUILD.bazel'], ['alpha'], ['BUILD.bazel']); + const renamed = readFileSync(path.join(fixture, 'renamed-alpha.c')); + rmSync(path.join(fixture, 'renamed-alpha.c')); + bazel('build', [`${label}:alpha_archive`, '--noshow_progress'], true); + writeFileSync(path.join(fixture, 'renamed-alpha.c'), renamed); + + const badCases = [ + { + name: 'missing_suppliers', + body: `shipping_package(name = "bad_ship", owner = ":alpha_identity", artifacts = [":alpha_archive"], ecosystem = "github", package_name = "bad", configuration = "fixture-host", role = "package")`, + target: 'bad_ship', + message: "missing value for mandatory attribute 'suppliers'", + }, + { + name: 'unknown_suppliers', + body: `file_shipping_supplier(name = "unknown_suppliers", inputs = {"LEGAL.txt": ""}, owner = ":alpha_identity", configuration = "fixture-host", binding = "abi-contract")\nshipping_package(name = "bad_ship", owner = ":alpha_identity", artifacts = [":alpha_archive"], ecosystem = "github", package_name = "bad", configuration = "fixture-host", role = "package", suppliers = ":unknown_suppliers")`, + target: 'bad_ship', + message: 'explicit known supplier coverage', + }, + { + name: 'missing_owner', + body: `shipping_package(name = "bad_ship", owner = ":shared", artifacts = [":alpha_archive"], ecosystem = "github", package_name = "bad", configuration = "fixture-host", role = "package", suppliers = "//build_defs/release:no_suppliers")`, + target: 'bad_ship', + message: 'ReleaseIdentityInfo', + }, + { + name: 'empty_payload', + body: `shipping_package(name = "bad_ship", owner = ":alpha_identity", artifacts = [], ecosystem = "github", package_name = "bad", configuration = "fixture-host", role = "package", suppliers = "//build_defs/release:no_suppliers")`, + target: 'bad_ship', + message: 'actual output files', + }, + { + name: 'duplicate_identity', + body: `shipping_package(name = "bad_ship", owner = ":alpha_identity", artifacts = [":alpha_archive"], ecosystem = "github", package_name = "fixture-alpha", configuration = "fixture-host", role = "package", suppliers = "//build_defs/release:no_suppliers")\nshipping_export(name = "bad_export", packages = [":alpha_ship", ":bad_ship"])`, + target: 'bad_export', + message: 'duplicate shipping identity', + }, + { + name: 'conflicting_product_versions', + body: `release_identity(name = "bad_identity", product_id = "fixture-alpha", version = "9.0.0")\nshipping_package(name = "bad_ship", owner = ":bad_identity", artifacts = [":alpha_archive"], ecosystem = "github", package_name = "fixture-alpha-other", configuration = "fixture-host", role = "package", suppliers = "//build_defs/release:no_suppliers")\nshipping_export(name = "bad_export", packages = [":alpha_ship", ":bad_ship"])`, + target: 'bad_export', + message: 'inconsistent shipping version', + }, + ]; + const renamedBuild = readFileSync(build, 'utf8'); + for (const bad of badCases) { + writeFileSync(build, `${renamedBuild}\n${bad.body}\n`); + const result = bazel('build', [`${label}:${bad.target}`, '--noshow_progress'], true); + assert.ok( + result.stderr.includes(bad.message), + `${bad.name}: expected contract rejection, got ${result.stderr}`, + ); + } + writeFileSync(build, renamedBuild); + scenario('warm after rejected ownership/analysis mutations', [], []); + + // Construction exports are not payload certificates: an independent envelope oracle catches a forged claim. + writeFileSync( + build, + renamedBuild + + '\nshipping_package(name = "forged_ship", owner = ":beta_identity", artifacts = [":alpha_archive"], ecosystem = "github", package_name = "fixture-forged", configuration = "fixture-host", role = "package", suppliers = "//build_defs/release:no_suppliers")\nshipping_export(name = "forged_export", packages = [":forged_ship"])\n', + ); + bazel('build', [`${label}:forged_export`, '--noshow_progress']); + const forged = shippingState('forged_export'); + assert.throws(() => assertEnvelopeIdentities(forged.exported), /package version|package owner/); + writeFileSync(build, renamedBuild); + + // A warm repository import must observe both pin and converter changes. + for (const watched of [ + { + file: '.prototools', + change: (text: string) => text.replace(/^node = .*$/m, 'node = "latest"'), + error: /pin|exact|version/, + }, + { + file: 'bun.lock', + change: (text: string) => + text.replace(/("catalog":\s*\{[^}]*"typescript":\s*)"[^"]+"/, '$1"^0.0.0"'), + error: /stale catalog/, + }, + { + file: 'build_defs/foundation/toolchain-metadata.mts', + change: (text: string) => + `${text}\nthrow new Error("conformance watched converter change");\n`, + error: /conformance watched converter change/, + }, + { + file: 'src/query/rust/Cargo.toml', + change: (text: string) => `${text}\n[dependencies]\nserde = "1"\n`, + error: /dependencies|does not yet support/, + }, + ]) { + const file = path.join(workspace, watched.file); + const original = readFileSync(file, 'utf8'); + bazel('build', ['@oliphaunt_toolchain_metadata//:toolchains.json', '--noshow_progress']); + writeFileSync(file, watched.change(original)); + const rejected = bazel( + 'build', + ['@oliphaunt_toolchain_metadata//:toolchains.json', '--noshow_progress'], + true, + ); + assert.match(rejected.stderr, watched.error, 'warm import must reject newly invalid source'); + writeFileSync(file, original); + bazel('build', ['@oliphaunt_toolchain_metadata//:toolchains.json', '--noshow_progress']); + } + const buildScript = path.join(workspace, 'src/query/rust/build.rs'); + assert.ok( + !existsSync(buildScript), + 'query fixture starts without an implicit Cargo build script', + ); + writeFileSync(buildScript, 'fn main() {}\n'); + assert.match( + bazel('build', ['@oliphaunt_toolchain_metadata//:toolchains.json', '--noshow_progress'], true) + .stderr, + /automatically discovered build.rs/, + ); + rmSync(buildScript); + bazel('build', ['@oliphaunt_toolchain_metadata//:toolchains.json', '--noshow_progress']); + + const domain = () => { + bazel('build', ['@oliphaunt_metadata//:metadata.bzl', '--noshow_progress']); + const file = bazel('cquery', [ + '@oliphaunt_metadata//:metadata.bzl', + '--output=files', + '--noshow_progress', + ]).stdout.trim(); + const executionRoot = bazel('info', ['execution_root']).stdout.trim(); + return readFileSync(path.join(executionRoot, file), 'utf8'); + }; + const domainBefore = domain(); + const partialNativeInputs = path.join(scratch, 'partial-native-inputs.json'); + writeFileSync( + partialNativeInputs, + JSON.stringify({ + source: { commit: 'a'.repeat(40), tree: 'b'.repeat(40) }, + nativeCurrentArtifacts: [], + }), + ); + const scopedLabels = [ + '//build_defs/languages:source_package_test', + '//src/wasix/node-addon:tools/carrier-contract.mts', + ]; + const scopedQuery = `set(${scopedLabels.join(' ')})`; + for (const state of ['cold', 'warm']) + assert.deepEqual( + bazel('query', [ + scopedQuery, + `--repo_env=OLIPHAUNT_NATIVE_PUBLICATION_INPUTS=${partialNativeInputs}`, + '--output=label', + '--noshow_progress', + ]) + .stdout.trim() + .split('\n') + .sort(), + scopedLabels, + `${state} scoped current artifacts must not require unrelated WASIX archives at package loading`, + ); + assert.match( + bazel( + 'cquery', + [ + '//src/wasix/node-addon:release_inputs', + `--repo_env=OLIPHAUNT_NATIVE_PUBLICATION_INPUTS=${partialNativeInputs}`, + '--noshow_progress', + ], + true, + ).stderr, + /WASIX addon is missing its original current contrib frozen File/, + 'selected WASIX construction still requires the original frozen File', + ); + assert.deepEqual( + bazel('query', [scopedQuery, '--output=label', '--noshow_progress']) + .stdout.trim() + .split('\n') + .sort(), + scopedLabels, + 'removing scoped current artifacts restores ordinary package loading', + ); + assert.equal(domain(), domainBefore, 'removing scoped inputs restores exact domain metadata'); + const iosPackage = '//src/examples/native/react-native-expo'; + assert.equal( + JSON.parse( + readFileSync(path.join(workspace, 'src/examples/native/react-native-expo/app.json'), 'utf8'), + ).expo.ios.icon, + './assets/expo.icon', + ); + for (const attribute of ['app_icons', 'resources']) { + const labels = bazel('query', [ + `labels(${attribute}, ${iosPackage}:ios_release)`, + '--output=label', + '--noshow_progress', + ]) + .stdout.trim() + .split('\n') + .sort(); + assert.ok( + !labels.some((file) => file.includes('AppIcon_appiconset')), + `${attribute} must not mix legacy icons with Icon Composer`, + ); + if (attribute === 'app_icons') + assert.deepEqual(labels, [ + `${iosPackage}:ios_app_expo_icon_Assets_expo_symbol_2_svg`, + `${iosPackage}:ios_app_expo_icon_Assets_grid_png`, + `${iosPackage}:ios_app_expo_icon_icon_json`, + ]); + } + const lockedAcquisition = () => + bazel('query', ['@pgvector//:all', '--lockfile_mode=error', '--noshow_progress']); + lockedAcquisition(); + const moduleLock = readFileSync(path.join(workspace, 'MODULE.bazel.lock'), 'utf8'); + const absentRecipe = path.join(workspace, 'src/extensions/external/vector/recipe.toml'); + assert.ok( + !existsSync(absentRecipe), + 'recipe watch fixture starts with an absent optional source', + ); + writeFileSync(absentRecipe, 'sql_name = "wrong"\n'); + assert.match( + bazel('build', ['@oliphaunt_metadata//:metadata.bzl', '--noshow_progress'], true).stderr, + /recipe disagrees/, + ); + rmSync(absentRecipe); + assert.equal( + domain(), + domainBefore, + 'removing an invalid new recipe restores the exact domain projection', + ); + const dependenciesDirectory = path.join(workspace, 'src/extensions/external/vector/dependencies'); + const hadDependenciesDirectory = existsSync(dependenciesDirectory); + const addedDependency = path.join(dependenciesDirectory, 'conformance_fixture'); + const missingDependency = path.join(dependenciesDirectory, 'conformance_missing_pin'); + assert.ok(!existsSync(addedDependency) && !existsSync(missingDependency)); + mkdirSync(addedDependency, { recursive: true }); + const dependencyPin = Bun.TOML.parse( + readFileSync(path.join(workspace, 'src/extensions/external/vector/source.toml'), 'utf8'), + ); + writeFileSync( + path.join(addedDependency, 'source.toml'), + `name = "conformance_fixture"\nurl = ${JSON.stringify(dependencyPin.url)}\ncommit = ${JSON.stringify(dependencyPin.commit)}\n\n[archive]\nsha256 = ${JSON.stringify(dependencyPin.archive.sha256)}\n`, + ); + assert.match( + domain(), + /EXTENSION_DEPENDENCIES = [^\n]*"vector": \{[^\n]*"conformance_fixture":/, + 'a warm import must notice a newly added dependency directory', + ); + bazel('query', ['@pgvector//:all', '--lockfile_mode=update', '--noshow_progress']); + assert.notEqual( + readFileSync(path.join(workspace, 'MODULE.bazel.lock'), 'utf8'), + moduleLock, + 'new dependency source pins change acquisition provenance', + ); + mkdirSync(missingDependency); + const missingPin = bazel( + 'build', + ['@oliphaunt_metadata//:metadata.bzl', '--noshow_progress'], + true, + ); + assert.match(missingPin.stderr, /conformance_missing_pin/); + assert.match(missingPin.stderr, /source\.toml/); + rmSync(missingDependency, { recursive: true }); + rmSync(addedDependency, { recursive: true }); + if (!hadDependenciesDirectory) rmdirSync(dependenciesDirectory); + assert.equal( + domain(), + domainBefore, + 'restoring directory membership restores exact domain metadata', + ); + bazel('query', ['@pgvector//:all', '--lockfile_mode=update', '--noshow_progress']); + lockedAcquisition(); + assert.equal( + readFileSync(path.join(workspace, 'MODULE.bazel.lock'), 'utf8'), + moduleLock, + 'restored acquisition facts restore the original native lock', + ); + const versionsFile = path.join(workspace, '.release-please-manifest.json'); + const versionSource = readFileSync(versionsFile, 'utf8'); + const cargoFile = path.join(workspace, 'src/query/rust/Cargo.toml'); + const cargoSource = readFileSync(cargoFile, 'utf8'); + const cargoPackage = Bun.TOML.parse(cargoSource).package; + const nextVersion = `${Number(cargoPackage.version.split('.')[0]) + 1}.0.0`; + const cargoLockFile = path.join(workspace, 'Cargo.lock'); + const cargoLockSource = readFileSync(cargoLockFile, 'utf8'); + const registryQueryRecords = Bun.TOML.parse(cargoLockSource).package.filter( + (record: { name: string; source?: string }) => + record.name === cargoPackage.name && record.source, + ); + assert.ok(registryQueryRecords.length, 'consumers require a separately resolved registry query'); + let localQueryRecords = 0; + const bumpedCargoLock = cargoLockSource + .split(/(?=^\[\[package\]\]$)/m) + .map((block) => { + const record = Bun.TOML.parse(block).package?.[0]; + if (record?.name !== cargoPackage.name || record.source) return block; + localQueryRecords++; + assert.equal(record.version, cargoPackage.version, 'local Cargo lock must match its source'); + return block.replace(/^version = .*$/m, `version = "${nextVersion}"`); + }) + .join(''); + assert.equal(localQueryRecords, 1, 'change only the uniquely resolved local query version'); + const lockedLanguages = () => + bazel('query', [ + 'set(//src/query/rust:oliphaunt_query @rust_toolchains//:all)', + '--lockfile_mode=error', + '--noshow_progress', + ]); + const toolchainProjection = (fileName: string) => { + const file = bazel('cquery', [ + `@oliphaunt_toolchain_metadata//:${fileName}`, + '--output=files', + '--noshow_progress', + ]).stdout.trim(); + // Analysis materializes the external repository, but may not recreate its + // execution-root symlink after a warm repository-rule re-import. + assert.ok(file.startsWith('external/'), 'toolchain projection is a repository source file'); + return readFileSync(path.join(outputBase, file), 'utf8'); + }; + lockedLanguages(); + const acquisitionBefore = toolchainProjection('toolchains.json'); + const typedRustBefore = toolchainProjection('query-rust.bzl'); + const cargoAcquisition = () => { + const expected = ['Cargo.toml', 'Cargo.lock', 'src/query/rust/Cargo.toml']; + const files = bazel('cquery', [ + `set(${expected.map((file) => `@native_cargo_metadata//:${file}`).join(' ')})`, + '--output=files', + '--noshow_progress', + ]) + .stdout.trim() + .split('\n'); + assert.equal(files.length, expected.length); + const projection = Object.fromEntries( + files.map((file) => { + assert.ok(file.startsWith('external/')); + const relative = file.split('/').slice(2).join('/'); + assert.ok(expected.includes(relative), `unexpected Cargo acquisition input ${file}`); + return [relative, readFileSync(path.join(outputBase, file), 'utf8')]; + }), + ); + assert.equal(Object.keys(projection).length, expected.length); + return projection; + }; + const cargoAcquisitionBefore = cargoAcquisition(); + const heldQueryDependencyGraph = () => { + const graph = bazel('cquery', [ + 'filter("oliphaunt_query", deps(set(//src/native/sdks/rust:lib //src/wasix/sdks/rust:lib //src/native/broker:lib //src/wasix/pgwire-server:lib)))', + '--config=wasix-aot', + '--output=label', + '--platforms=//build_defs/native:linux_x86_64_glibc_2_28', + '--host_platform=//build_defs/native:linux_x86_64_glibc_2_28', + '--noshow_progress', + ]).stdout.trim(); + assert.ok(graph, 'configured SDK/helper consumers must resolve the held registry query'); + assert.ok(!graph.includes('//src/query/rust:'), 'held consumers must exclude the local query'); + for (const line of graph.split('\n')) { + assert.ok( + registryQueryRecords.some((record: { version: string }) => + line.includes(`oliphaunt-query-${record.version}//`), + ), + `query dependency must be a genuine held Cargo registry record: ${line}`, + ); + } + return graph; + }; + const heldQueryGraphBefore = heldQueryDependencyGraph(); + const queryBefore = realQueryShipping('cold-real-query-packages', [ + '//src/query/rust:crate', + '//src/query/ts:npm', + '//src/query/ts:module', + '//src/query/ts:commonjs', + '//src/query/ts:.aspect_rules_js/node_modules/@types/node', + '//src/query/ts:.aspect_rules_js/node_modules/undici-types', + '@@aspect_rules_ts++typescript+npm_typescript//:.aspect_rules_js/node_modules/typescript', + ]); + realQueryShipping('warm-identical-real-query-packages', [], 0); + const versions = JSON.parse(versionSource); + versions['src/query/rust'] = nextVersion; + writeFileSync(versionsFile, JSON.stringify(versions)); + writeFileSync(cargoFile, cargoSource.replace(/^version = .*$/m, `version = "${nextVersion}"`)); + writeFileSync(cargoLockFile, bumpedCargoLock); + assert.deepEqual( + Bun.TOML.parse(bumpedCargoLock).package.filter( + (record: { name: string; source?: string }) => + record.name === cargoPackage.name && record.source, + ), + registryQueryRecords, + 'a local major version bump must preserve the genuine held registry query identity', + ); + assert.ok( + domain().includes(`"version": "${nextVersion}"`), + 'domain import must observe the conventional Cargo version mirror', + ); + lockedLanguages(); + assert.equal( + toolchainProjection('toolchains.json'), + acquisitionBefore, + 'Cargo product versions are not language acquisition facts', + ); + assert.deepEqual( + cargoAcquisition(), + cargoAcquisitionBefore, + 'a coherent local major version bump must preserve Cargo acquisition inputs', + ); + assert.equal( + heldQueryDependencyGraph(), + heldQueryGraphBefore, + 'independently versioned SDK/helper consumers retain their configured held query dependency', + ); + const typedRustAfter = toolchainProjection('query-rust.bzl'); + assert.notEqual(typedRustAfter, typedRustBefore); + assert.ok(typedRustAfter.includes(`QUERY_RUST_VERSION = "${nextVersion}"`)); + assert.ok(typedRustAfter.includes(`"CARGO_PKG_VERSION": "${nextVersion}"`)); + const queryAfter = realQueryShipping( + 'one-real-cargo-package-version', + ['//src/query/rust:crate'], + 1, + ); + const rustProduct = JSON.parse( + readFileSync(path.join(workspace, 'release-please-config.json'), 'utf8'), + ).packages['src/query/rust'].component; + const actualDeltas = Object.fromEntries( + Object.keys(queryBefore.products).map((product) => [ + product, + ['src/query/rust/Cargo.toml', 'Cargo.lock', '.release-please-manifest.json'], + ]), + ); + const querySelection = selectShippingChanges(queryBefore.products, queryAfter, actualDeltas); + assert.deepEqual( + querySelection.affectedProducts, + [rustProduct], + 'one Cargo product version must not release the independently versioned npm package', + ); + assert.deepEqual(querySelection.unclassifiedPaths, [ + '.release-please-manifest.json', + 'Cargo.lock', + ]); + lockedAcquisition(); + assert.equal( + readFileSync(path.join(workspace, 'MODULE.bazel.lock'), 'utf8'), + moduleLock, + 'public version changes must not rewrite source-acquisition locks', + ); + writeFileSync(versionsFile, versionSource); + writeFileSync(cargoFile, cargoSource); + writeFileSync(cargoLockFile, cargoLockSource); + lockedLanguages(); + assert.equal(toolchainProjection('toolchains.json'), acquisitionBefore); + assert.equal(toolchainProjection('query-rust.bzl'), typedRustBefore); + assert.deepEqual(cargoAcquisition(), cargoAcquisitionBefore); + assert.equal(heldQueryDependencyGraph(), heldQueryGraphBefore); + realQueryShipping('restore-real-cargo-package-version', ['//src/query/rust:crate'], 1); + const carriersFile = path.join(workspace, 'src/extensions/contrib/carriers.toml'); + const ownerSource = readFileSync(carriersFile, 'utf8'); + writeFileSync( + carriersFile, + ownerSource.replace('native_owner = "liboliphaunt-native"', 'native_owner = "oliphaunt-query"'), + ); + assert.match( + bazel('build', ['@oliphaunt_metadata//:metadata.bzl', '--noshow_progress'], true).stderr, + /oliphaunt-query release\.toml must declare artifact_targets/, + 'a publication owner without the supported carrier targets is invalid', + ); + writeFileSync(carriersFile, ownerSource); + assert.equal( + domain(), + domainBefore, + 'restoring version and owner sources restores the exact domain projection', + ); + lockedAcquisition(); + assert.equal( + readFileSync(path.join(workspace, 'MODULE.bazel.lock'), 'utf8'), + moduleLock, + 'rejected publication ownership must not rewrite source-acquisition locks', + ); + scenario('rejected publication owner keeps unrelated consumers cached', [], []); + const extensionSourceFile = path.join(workspace, 'src/extensions/external/vector/source.toml'); + const extensionSource = readFileSync(extensionSourceFile, 'utf8'); + writeFileSync( + extensionSourceFile, + extensionSource + .replace(/^branch = .*$/m, 'branch = "conformance-metadata-only"') + .replace(/^default-version = .*$/m, 'default-version = "9.8.7"'), + ); + const updatedDomain = domain(); + assert.match(updatedDomain, /"branch": "conformance-metadata-only"/); + assert.match(updatedDomain, /"default-version": "9\.8\.7"/); + lockedAcquisition(); + assert.equal( + readFileSync(path.join(workspace, 'MODULE.bazel.lock'), 'utf8'), + moduleLock, + 'branch and extension-control metadata must not rewrite immutable source-acquisition locks', + ); + scenario('non-acquisition extension metadata keeps unrelated consumers cached', [], []); + writeFileSync(extensionSourceFile, extensionSource); + assert.equal( + domain(), + domainBefore, + 'restoring extension metadata restores the exact domain projection', + ); + scenario('warm after restored external import sources', [], []); + console.log( + JSON.stringify({ + seed: '0x5eed', + scenarios: records.length, + testAttempts: records.reduce((total, record) => total + record.tests.length, 0), + producerSpawns: records.reduce( + (total, record) => + total + Object.values(record.production).reduce((sum, count) => sum + count, 0), + 0, + ), + zeroSpawnScenarios: records.filter( + (record) => record.tests.length === 0 && Object.keys(record.production).length === 0, + ).length, + realPackageScenarios: queryRecords.length, + realPackageProducerSpawns: queryRecords.reduce( + (total, record) => total + record.producerSpawns, + 0, + ), + realPackageZeroSpawnScenarios: queryRecords.filter((record) => record.producerSpawns === 0) + .length, + }), + ); + completed = true; +} finally { + if (existsSync(wrapper)) { + const stopped = spawnSync('bash', [wrapper, ...startupOptions, 'shutdown'], { + cwd: workspace, + timeout: 30_000, + env: subprocessEnvironment, + }); + if (completed) + assert.equal(stopped.status, 0, 'isolated Bazel server must stop before cleanup'); + } + if (completed) removePrivateScratch(scratch); + else console.error(`Conformance failure preserved at ${scratch}; seed 0x5eed.`); +} diff --git a/tools/bazel/tests/execution-log.mts b/tools/bazel/tests/execution-log.mts new file mode 100644 index 000000000..1e671427f --- /dev/null +++ b/tools/bazel/tests/execution-log.mts @@ -0,0 +1,49 @@ +import { readFileSync } from 'node:fs'; + +export interface SpawnExecution { + mnemonic?: string; + targetLabel?: string; + cacheHit?: boolean; + runner?: string; + status?: string; + exitCode?: number; + commandArgs?: string[]; +} + +// Bazel writes successive protobuf JSON objects, not a JSON array or JSONL. +export function parseExecutionLog(text: string): SpawnExecution[] { + const results: SpawnExecution[] = []; + let start = -1; + let depth = 0; + let quoted = false; + let escaped = false; + for (let index = 0; index < text.length; index++) { + const character = text[index]; + if (start === -1) { + if (/\s/.test(character)) continue; + if (character !== '{') throw new Error('execution log must contain JSON objects'); + start = index; + } + if (quoted) { + if (escaped) escaped = false; + else if (character === '\\') escaped = true; + else if (character === '"') quoted = false; + } else if (character === '"') quoted = true; + else if (character === '{' || character === '[') depth++; + else if (character === '}' || character === ']') { + depth--; + if (depth === 0) { + results.push(JSON.parse(text.slice(start, index + 1))); + start = -1; + } + } + } + if (start !== -1) throw new Error('truncated execution log'); + return results; +} + +export function executedFixtureSpawns(file: string, packageLabel: string): SpawnExecution[] { + return parseExecutionLog(readFileSync(file, 'utf8')).filter( + (spawn) => spawn.targetLabel?.startsWith(`${packageLabel}:`) && !spawn.cacheHit, + ); +} diff --git a/tools/bazel/tests/execution-log.test.mts b/tools/bazel/tests/execution-log.test.mts new file mode 100644 index 000000000..7b3a91d0b --- /dev/null +++ b/tools/bazel/tests/execution-log.test.mts @@ -0,0 +1,30 @@ +import { strict as assert } from 'node:assert'; +import test from 'node:test'; +import { parseExecutionLog } from './execution-log.mts'; + +test('decodes Bazel execution records, including multiline JSON and quoted delimiters', () => { + const records = [ + { + mnemonic: 'CppCompile', + targetLabel: '//fixture:alpha', + commandArgs: ['braces }{ and "quote"'], + }, + { + mnemonic: 'TestRunner', + targetLabel: '//fixture:alpha_test', + cacheHit: true, + inputs: [{ path: 'a' }], + }, + ]; + assert.deepEqual( + parseExecutionLog(records.map((record) => JSON.stringify(record, null, 2)).join('\n')), + records, + ); + assert.deepEqual(parseExecutionLog(' \n'), []); +}); + +test('rejects malformed and truncated execution evidence', () => { + for (const value of ['[]', '{"mnemonic":', '{} garbage', '{"value":"unterminated']) { + assert.throws(() => parseExecutionLog(value)); + } +}); diff --git a/tools/bazel/tests/fixtures/action-graph/BUILD.bazel b/tools/bazel/tests/fixtures/action-graph/BUILD.bazel new file mode 100644 index 000000000..b1b211a01 --- /dev/null +++ b/tools/bazel/tests/fixtures/action-graph/BUILD.bazel @@ -0,0 +1,79 @@ +load("@rules_cc//cc:cc_binary.bzl", "cc_binary") +load("@rules_cc//cc:cc_library.bzl", "cc_library") +load("//build_defs/foundation:bun.bzl", "bun_script_test") +load("//build_defs/release:identity.bzl", "release_identity") +load("//build_defs/release:shipping.bzl", "shipping_export", "shipping_package") +load("//build_defs/release:supplier.bzl", "file_shipping_supplier") +load(":fixture.bzl", "fixture_header", "fixture_package") + +package(default_visibility = ["//visibility:public"]) + +fixture_header( + name = "config", + config = "config.txt", + tool = "config-header.mts", +) + +cc_library( + name = "shared", + srcs = ["shared.c", ":config"], + hdrs = ["shared.h"], + includes = ["."], +) + +cc_binary(name = "alpha_bin", srcs = ["alpha.c"], deps = [":shared"]) +cc_binary(name = "beta_bin", srcs = ["beta.c"], deps = [":shared"]) +cc_binary(name = "gamma_bin", srcs = ["gamma.c"]) + +release_identity(name = "alpha_identity", product_id = "fixture-alpha", version = "1.0.0") +release_identity(name = "beta_identity", product_id = "fixture-beta", version = "2.0.0") +release_identity(name = "gamma_identity", product_id = "fixture-gamma", version = "3.0.0") + +[fixture_package( + name = product + "_archive", + binary = ":" + product + "_bin", + legal = "LEGAL.txt", + owner = ":" + product + "_identity", + tool = "package.mts", +) for product in ["alpha", "beta", "gamma"]] + +[shipping_package( + name = product + "_ship", + owner = ":" + product + "_identity", + artifacts = [":" + product + "_archive"], + ecosystem = "github", + package_name = "fixture-" + product, + configuration = "fixture-host", + role = "package", + suppliers = "//build_defs/release:no_suppliers", +) for product in ["alpha", "beta", "gamma"]] + +shipping_export( + name = "alpha_export", + testonly = True, + packages = [":alpha_ship"], + qualification = [":alpha_test"], +) + +shipping_export( + name = "beta_gamma_export", + testonly = True, + packages = [":beta_ship", ":gamma_ship"], + qualification = [":beta_test", ":gamma_test"], +) + +shipping_export( + name = "export", + testonly = True, + exports = [":alpha_export", ":beta_gamma_export"], +) + +[bun_script_test( + name = product + "_test", + entry_point = "consumer.mts", + data = [":" + product + "_archive", product + ".expected"], +) for product in ["alpha", "beta", "gamma"]] + +test_suite(name = "all_tests", tests = [":alpha_test", ":beta_test", ":gamma_test"]) + +filegroup(name = "fixture_sources", srcs = glob(["*.c", "*.h", "*.txt", "*.expected", "*.mts", "*.bzl"]) + ["BUILD.bazel"]) diff --git a/tools/bazel/tests/fixtures/action-graph/LEGAL.txt b/tools/bazel/tests/fixtures/action-graph/LEGAL.txt new file mode 100644 index 000000000..03911de70 --- /dev/null +++ b/tools/bazel/tests/fixtures/action-graph/LEGAL.txt @@ -0,0 +1 @@ +Fixture license, revision 1. diff --git a/tools/bazel/tests/fixtures/action-graph/alpha.c b/tools/bazel/tests/fixtures/action-graph/alpha.c new file mode 100644 index 000000000..1c811a3f2 --- /dev/null +++ b/tools/bazel/tests/fixtures/action-graph/alpha.c @@ -0,0 +1,3 @@ +#include +#include "shared.h" +int main(void) { printf("%d\n", shared_value() + 1); return 0; } diff --git a/tools/bazel/tests/fixtures/action-graph/alpha.expected b/tools/bazel/tests/fixtures/action-graph/alpha.expected new file mode 100644 index 000000000..b4de39476 --- /dev/null +++ b/tools/bazel/tests/fixtures/action-graph/alpha.expected @@ -0,0 +1 @@ +11 diff --git a/tools/bazel/tests/fixtures/action-graph/beta.c b/tools/bazel/tests/fixtures/action-graph/beta.c new file mode 100644 index 000000000..ce071e936 --- /dev/null +++ b/tools/bazel/tests/fixtures/action-graph/beta.c @@ -0,0 +1,3 @@ +#include +#include "shared.h" +int main(void) { printf("%d\n", shared_value() + 2); return 0; } diff --git a/tools/bazel/tests/fixtures/action-graph/beta.expected b/tools/bazel/tests/fixtures/action-graph/beta.expected new file mode 100644 index 000000000..48082f72f --- /dev/null +++ b/tools/bazel/tests/fixtures/action-graph/beta.expected @@ -0,0 +1 @@ +12 diff --git a/tools/bazel/tests/fixtures/action-graph/config-header.mts b/tools/bazel/tests/fixtures/action-graph/config-header.mts new file mode 100644 index 000000000..6395152e8 --- /dev/null +++ b/tools/bazel/tests/fixtures/action-graph/config-header.mts @@ -0,0 +1,6 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +const [output, input] = process.argv.slice(2); +const value = readFileSync(input, 'utf8').trim(); +if (!/^-?\d+$/.test(value)) throw new Error('fixture configuration must be an integer'); +writeFileSync(output, `#define CONFIG_VALUE ${value}\n`); diff --git a/tools/bazel/tests/fixtures/action-graph/config.txt b/tools/bazel/tests/fixtures/action-graph/config.txt new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/tools/bazel/tests/fixtures/action-graph/config.txt @@ -0,0 +1 @@ +0 diff --git a/tools/bazel/tests/fixtures/action-graph/consumer.mts b/tools/bazel/tests/fixtures/action-graph/consumer.mts new file mode 100644 index 000000000..a4f698d7e --- /dev/null +++ b/tools/bazel/tests/fixtures/action-graph/consumer.mts @@ -0,0 +1,24 @@ +import { strict as assert } from 'node:assert'; +import { execFileSync } from 'node:child_process'; +import { chmodSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; + +const product = process.env.TEST_TARGET?.match(/:(alpha|beta|gamma)_test$/)?.[1]; +assert.ok(product, 'fixture test requires a declared Bazel target identity'); +const directory = 'tools/bazel/tests/fixtures/action-graph'; +const envelope = JSON.parse(readFileSync(`${directory}/${product}_archive.json`, 'utf8')); +assert.deepEqual(Object.keys(envelope).sort(), ['executable', 'legal', 'product', 'version']); +assert.equal(envelope.product, 'fixture-' + product); +assert.match(envelope.version, /^\d+[.]\d+[.]\d+$/); +assert.match(envelope.legal, /^Fixture license, revision \d+[.]\n$/); +const scratch = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'physical-consumer-')); +try { + const binary = path.join(scratch, 'consumer-bin'); + writeFileSync(binary, Buffer.from(envelope.executable, 'base64')); + chmodSync(binary, 0o700); + const observed = execFileSync(binary, { encoding: 'utf8' }); + assert.equal(observed, readFileSync(`${directory}/${product}.expected`, 'utf8')); +} finally { + rmSync(scratch, { recursive: true, force: true }); +} diff --git a/tools/bazel/tests/fixtures/action-graph/fixture.bzl b/tools/bazel/tests/fixtures/action-graph/fixture.bzl new file mode 100644 index 000000000..4c1d49a0b --- /dev/null +++ b/tools/bazel/tests/fixtures/action-graph/fixture.bzl @@ -0,0 +1,50 @@ +"""Tiny real producer actions for construction/release conformance fixtures.""" + +load("//build_defs/release:identity.bzl", "ReleaseIdentityInfo") +load("//build_defs/foundation:bun.bzl", "BUN_SOURCE_TOOLCHAINS", "bun_file_action") + +def _header_impl(ctx): + output = ctx.actions.declare_file(ctx.label.name + ".h") + bun_file_action( + ctx, + entry_point = ctx.file.tool, + source_files = [ctx.file.tool], + arguments = [output.path, ctx.file.config.path], + inputs = [ctx.file.tool, ctx.file.config], + outputs = [output], + mnemonic = "FixtureConfigHeader", + ) + return [DefaultInfo(files = depset([output]))] + +fixture_header = rule( + implementation = _header_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = { + "config": attr.label(mandatory = True, allow_single_file = True), + "tool": attr.label(mandatory = True, allow_single_file = True), + }, +) + +def _package_impl(ctx): + output = ctx.actions.declare_file(ctx.label.name + ".json") + bun_file_action( + ctx, + entry_point = ctx.file.tool, + source_files = [ctx.file.tool], + arguments = [output.path, ctx.file.binary.path, ctx.file.legal.path, ctx.attr.owner[ReleaseIdentityInfo].version, ctx.attr.owner[ReleaseIdentityInfo].id], + inputs = [ctx.file.tool, ctx.file.binary, ctx.file.legal], + outputs = [output], + mnemonic = "FixturePackage", + ) + return [DefaultInfo(files = depset([output]))] + +fixture_package = rule( + implementation = _package_impl, + toolchains = BUN_SOURCE_TOOLCHAINS, + attrs = { + "binary": attr.label(mandatory = True, allow_single_file = True), + "legal": attr.label(mandatory = True, allow_single_file = True), + "tool": attr.label(mandatory = True, allow_single_file = True), + "owner": attr.label(mandatory = True, providers = [ReleaseIdentityInfo]), + }, +) diff --git a/tools/bazel/tests/fixtures/action-graph/gamma.c b/tools/bazel/tests/fixtures/action-graph/gamma.c new file mode 100644 index 000000000..c2cc55e91 --- /dev/null +++ b/tools/bazel/tests/fixtures/action-graph/gamma.c @@ -0,0 +1,2 @@ +#include +int main(void) { printf("%d\n", 3); return 0; } diff --git a/tools/bazel/tests/fixtures/action-graph/gamma.expected b/tools/bazel/tests/fixtures/action-graph/gamma.expected new file mode 100644 index 000000000..00750edc0 --- /dev/null +++ b/tools/bazel/tests/fixtures/action-graph/gamma.expected @@ -0,0 +1 @@ +3 diff --git a/tools/bazel/tests/fixtures/action-graph/package.mts b/tools/bazel/tests/fixtures/action-graph/package.mts new file mode 100644 index 000000000..50ddbb02c --- /dev/null +++ b/tools/bazel/tests/fixtures/action-graph/package.mts @@ -0,0 +1,10 @@ +import { readFileSync, writeFileSync } from 'node:fs'; + +const [output, binary, legal, version, product] = process.argv.slice(2); +if (!/^\d+[.]\d+[.]\d+$/.test(version)) throw new Error('invalid fixture version'); +writeFileSync(output, JSON.stringify({ + executable: readFileSync(binary).toString('base64'), + legal: readFileSync(legal, 'utf8'), + version, + product, +}) + '\n'); diff --git a/tools/bazel/tests/fixtures/action-graph/shared.c b/tools/bazel/tests/fixtures/action-graph/shared.c new file mode 100644 index 000000000..2dc8ce136 --- /dev/null +++ b/tools/bazel/tests/fixtures/action-graph/shared.c @@ -0,0 +1,3 @@ +#include "shared.h" +#include "config.h" +int shared_value(void) { return SHARED_VALUE + CONFIG_VALUE; } diff --git a/tools/bazel/tests/fixtures/action-graph/shared.h b/tools/bazel/tests/fixtures/action-graph/shared.h new file mode 100644 index 000000000..ed18e4f7c --- /dev/null +++ b/tools/bazel/tests/fixtures/action-graph/shared.h @@ -0,0 +1,2 @@ +#define SHARED_VALUE 10 +int shared_value(void); diff --git a/tools/bazel/tests/fixtures/android-sdk/BUILD.bazel b/tools/bazel/tests/fixtures/android-sdk/BUILD.bazel new file mode 100644 index 000000000..bbb523316 --- /dev/null +++ b/tools/bazel/tests/fixtures/android-sdk/BUILD.bazel @@ -0,0 +1,6 @@ +load(":fixture.bzl", "selected_android_sdk") + +selected_android_sdk( + name = "selected_sdk", + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], +) diff --git a/tools/bazel/tests/fixtures/android-sdk/fixture.bzl b/tools/bazel/tests/fixtures/android-sdk/fixture.bzl new file mode 100644 index 000000000..7f698c372 --- /dev/null +++ b/tools/bazel/tests/fixtures/android-sdk/fixture.bzl @@ -0,0 +1,19 @@ +"""Observe a maintained SDK provider without compiling Kotlin or Android code.""" + +_SDK_TYPE = "@rules_android//toolchains/android_sdk:toolchain_type" + +def _selected_android_sdk_impl(ctx): + sdk = ctx.toolchains[_SDK_TYPE].android_sdk_info + snapshot = ctx.actions.declare_file(ctx.label.name + ".json") + ctx.actions.write(snapshot, json.encode({ + "buildTools": sdk.build_tools_version, + "androidJar": sdk.android_jar.path, + "frameworkAidl": sdk.framework_aidl.path, + "adb": sdk.adb.executable.path, + }) + "\n") + return [DefaultInfo(files = depset([snapshot]))] + +selected_android_sdk = rule( + implementation = _selected_android_sdk_impl, + toolchains = [_SDK_TYPE], +) diff --git a/tools/bazel/tests/fixtures/cargo-build-script/README.md b/tools/bazel/tests/fixtures/cargo-build-script/README.md new file mode 100644 index 000000000..0acd07a12 --- /dev/null +++ b/tools/bazel/tests/fixtures/cargo-build-script/README.md @@ -0,0 +1,3 @@ +This isolated fixture compiles the same build script through Bazel and an +installed Cargo source crate. It verifies Cargo's private compiler identity, +compile environment, package identity, and consumption of generated source. diff --git a/tools/bazel/tests/fixtures/cargo-build-script/build.rs b/tools/bazel/tests/fixtures/cargo-build-script/build.rs new file mode 100644 index 000000000..ac8c51550 --- /dev/null +++ b/tools/bazel/tests/fixtures/cargo-build-script/build.rs @@ -0,0 +1,18 @@ +use std::{env, fs, path::Path}; + +fn main() { + assert_eq!( + module_path!(), + "build_script_build", + "private compiler identity must match Cargo" + ); + assert_eq!(env!("CARGO_CRATE_NAME"), "build_script_build"); + assert_eq!(env!("CARGO_PKG_NAME"), "oliphaunt-query"); + assert_eq!(env::var("CARGO_PKG_NAME").unwrap(), env!("CARGO_PKG_NAME")); + assert_eq!( + env::var("CARGO_PKG_VERSION").unwrap(), + env!("CARGO_PKG_VERSION") + ); + let output = Path::new(&env::var("OUT_DIR").unwrap()).join("observed.rs"); + fs::write(output, "pub const BUILD_SCRIPT_VALUE: u32 = 42;\n").unwrap(); +} diff --git a/tools/bazel/tests/fixtures/cargo-build-script/consumer.rs b/tools/bazel/tests/fixtures/cargo-build-script/consumer.rs new file mode 100644 index 000000000..d8708fd08 --- /dev/null +++ b/tools/bazel/tests/fixtures/cargo-build-script/consumer.rs @@ -0,0 +1,4 @@ +fn main() { + assert_eq!(probe::observed(), 42); + println!("installed Cargo build-script parity passed"); +} diff --git a/tools/bazel/tests/fixtures/cargo-build-script/consumer.toml b/tools/bazel/tests/fixtures/cargo-build-script/consumer.toml new file mode 100644 index 000000000..2033982ba --- /dev/null +++ b/tools/bazel/tests/fixtures/cargo-build-script/consumer.toml @@ -0,0 +1,9 @@ +[package] +name = "installed-name-parity-consumer" +version = "0.0.0" +edition = "2024" + +[dependencies] +probe = { package = "oliphaunt-query", path = "../installed" } + +[workspace] diff --git a/tools/bazel/tests/fixtures/cargo-build-script/fixture.BUILD.bazel b/tools/bazel/tests/fixtures/cargo-build-script/fixture.BUILD.bazel new file mode 100644 index 000000000..49bcebdae --- /dev/null +++ b/tools/bazel/tests/fixtures/cargo-build-script/fixture.BUILD.bazel @@ -0,0 +1,30 @@ +load("@//build_defs/languages:rust.bzl", "cargo_generator", "cargo_library", "cargo_package_env") +load("@//build_defs/languages:source.bzl", "cargo_source_package") +load("@//build_defs/query:defs.bzl", "cargo_consumer_test") +load("@oliphaunt_metadata//:metadata.bzl", "PRODUCTS") +load("@rules_rust//rust:defs.bzl", "rust_test") + +package(default_visibility = ["//visibility:public"]) + +FACTS = {"": { + "name": "oliphaunt-query", + "crate_name": "public_probe_library", + "version": PRODUCTS["oliphaunt-query"]["version"], + "edition": "2024", + "build": "build.rs", + "library": "src/lib.rs", + "links": None, + "readme": None, + "features": {}, + "dependencies": {}, + "build_dependencies": {}, + "dev_dependencies": {}, + "target_dependencies": {}, +}} + +cargo_package_env(workspace_manifest = "Cargo.toml") +cargo_generator(cargo_facts = FACTS) +cargo_library(build_script = ":build_script", cargo_facts = FACTS) +rust_test(name = "unit_test", crate = ":lib", edition = "2024") +cargo_source_package(product = "oliphaunt-query", cargo_facts = FACTS, workspace_manifest = "Cargo.toml") +cargo_consumer_test(name = "installed_consumer_test", archive = ":crate", manifest = "consumer.toml", source = "consumer.rs") diff --git a/tools/bazel/tests/fixtures/cargo-build-script/fixture.Cargo.toml b/tools/bazel/tests/fixtures/cargo-build-script/fixture.Cargo.toml new file mode 100644 index 000000000..5fe595c34 --- /dev/null +++ b/tools/bazel/tests/fixtures/cargo-build-script/fixture.Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "oliphaunt-query" +version = "0.3.2" +edition = "2024" +build = "build.rs" +include = ["Cargo.toml", "build.rs", "README.md", "LICENSE", "THIRD_PARTY_NOTICES.md", "src/**"] + +[lib] +name = "public_probe_library" +path = "src/lib.rs" + +[workspace] diff --git a/tools/bazel/tests/fixtures/cargo-build-script/src/lib.rs b/tools/bazel/tests/fixtures/cargo-build-script/src/lib.rs new file mode 100644 index 000000000..1ff9f6c6b --- /dev/null +++ b/tools/bazel/tests/fixtures/cargo-build-script/src/lib.rs @@ -0,0 +1,11 @@ +include!(concat!(env!("OUT_DIR"), "/observed.rs")); + +pub fn observed() -> u32 { + assert_eq!(module_path!(), "public_probe_library"); + BUILD_SCRIPT_VALUE +} + +#[test] +fn generated_value_is_consumed() { + assert_eq!(observed(), 42); +} diff --git a/tools/bazel/tests/shipping-coverage.test.mts b/tools/bazel/tests/shipping-coverage.test.mts new file mode 100644 index 000000000..16e275cd9 --- /dev/null +++ b/tools/bazel/tests/shipping-coverage.test.mts @@ -0,0 +1,397 @@ +import { strict as assert } from 'node:assert'; +import { test } from 'node:test'; +import { + type CanonicalArtifact, + type CanonicalCarrier, + type ConfiguredShippingCohort, + type CoverageAuthority, + checkShippingCoverage, +} from '../shipping-coverage.mts'; + +type Package = { + product: string; + version: string; + ecosystem: string; + name: string; + configuration: string; + role: string; +}; + +const carrier: CanonicalCarrier = { + id: 'cargo:fixture-linux', + product: 'fixture', + version: '1.2.3', + ecosystem: 'cargo', + name: 'fixture-linux', + role: 'platform-leaf', + target: 'linux', + declared: true, +}; +const artifact: CanonicalArtifact = { + product: 'fixture', + version: '1.2.3', + id: 'github-release:fixture-linux.tar.gz', + role: 'github-release-asset', + kind: 'runtime', + target: 'linux', + identity: null, + name: 'fixture-linux.tar.gz', +}; +const carrierPackage: Package = { + product: carrier.product, + version: carrier.version, + ecosystem: carrier.ecosystem, + name: carrier.name, + configuration: 'linux', + role: carrier.role, +}; +const artifactPackage: Package = { + product: artifact.product, + version: artifact.version, + ecosystem: 'github', + name: artifact.name, + configuration: artifact.target, + role: artifact.role, +}; + +function authority({ + carriers = [carrier], + artifacts = [artifact], + products = ['fixture'], +} = {}): CoverageAuthority { + return { + catalog: { + schema: 'oliphaunt-publication-catalog-v1', + products: products.map((id) => ({ id, version: '1.2.3' })), + carriers, + }, + artifactRows: artifacts, + resolveCarrier: (_ecosystem, name) => { + if (name === 'fixture-linux-part-001') { + return { + ...carrier, + id: `cargo:${name}`, + name, + declared: false, + parentCarrier: carrier.id, + role: 'payload-part', + }; + } + throw new Error(`undeclared carrier: ${name}`); + }, + }; +} + +// Unit fixtures describe tiny producer graphs. The conformance owner separately +// checks real native archives/graphs; these cases exercise fail-closed boundaries. +function cohort(packages: Package[], prefix = 'fixture'): ConfiguredShippingCohort { + const pathFragments: { id: number; label: string; parentId?: number }[] = []; + const paths = new Map(); + const fragment = (file: string): number => { + let parentId: number | undefined; + let current = ''; + for (const label of file.split('/')) { + current = current ? `${current}/${label}` : label; + let id = paths.get(current); + if (!id) { + id = pathFragments.length + 1; + pathFragments.push({ id, label, ...(parentId ? { parentId } : {}) }); + paths.set(current, id); + } + parentId = id; + } + return parentId as number; + }; + const roots: unknown[] = []; + const targets: unknown[] = []; + const artifacts: unknown[] = []; + const actions: unknown[] = []; + const depSetOfFiles: unknown[] = []; + for (const [index, pkg] of packages.entries()) { + const owner = `//fixture:${prefix}_archive_${index}`; + const output = `bazel-out/fixture/bin/${prefix}/output_${index}`; + const sourceId = index * 2 + 1; + const outputId = sourceId + 1; + roots.push({ + label: `//fixture:${prefix}_ship_${index}`, + package: { ...pkg, outputs: [{ path: output, owner }] }, + }); + targets.push({ id: index + 1, label: owner }); + artifacts.push({ id: sourceId, pathFragmentId: fragment(`fixture/${prefix}/source_${index}`) }); + artifacts.push({ id: outputId, pathFragmentId: fragment(output) }); + depSetOfFiles.push({ id: index + 1, directArtifactIds: [sourceId] }); + actions.push({ + targetId: index + 1, + configurationId: 1, + actionKey: `${prefix}_action_${index}`, + mnemonic: 'FixturePackage', + inputDepSetIds: [index + 1], + outputIds: [outputId], + primaryOutputId: outputId, + arguments: ['package', `fixture/${prefix}/source_${index}`, output], + }); + } + return { + roots, + aquery: { + pathFragments, + targets, + artifacts, + actions, + depSetOfFiles, + configuration: [{ id: 1 }], + }, + }; +} + +test('complete coverage checks actual producer closures while exposing semantic admission limits', () => { + const report = checkShippingCoverage(authority(), [cohort([carrierPackage, artifactPackage])]); + assert.equal(report.completeProductInventory, true); + assert.equal(report.declaredCarriers, 1); + assert.equal(report.publicArtifacts, 1); + assert.equal(report.constructionActionDescriptions, 2); + assert.equal(report.scope, 'construction'); + assert.ok(report.unverified.some((field) => field.includes('packed manifests'))); +}); + +test('missing product, platform or final carrier cannot disappear from discovered roots', () => { + assert.throws(() => checkShippingCoverage(authority(), [cohort([])]), /product:fixture/); + assert.throws( + () => checkShippingCoverage(authority(), [cohort([artifactPackage])]), + /cargo:fixture-linux/, + ); + assert.throws( + () => checkShippingCoverage(authority(), [cohort([carrierPackage])]), + /github-release:fixture-linux.tar.gz/, + ); + const windows = { + ...carrier, + id: 'cargo:fixture-windows', + name: 'fixture-windows', + target: 'windows', + }; + assert.throws( + () => + checkShippingCoverage(authority({ carriers: [carrier, windows] }), [ + cohort([carrierPackage, artifactPackage]), + ]), + /cargo:fixture-windows/, + ); +}); + +test('internal member payloads cannot stand in for public envelopes', () => { + assert.throws( + () => + checkShippingCoverage(authority(), [ + cohort([{ ...artifactPackage, ecosystem: 'internal', role: 'payload' }]), + ]), + /incomplete native shipping coverage/, + ); + const report = checkShippingCoverage(authority(), [ + cohort([ + carrierPackage, + artifactPackage, + { ...artifactPackage, name: 'internal-member', ecosystem: 'internal', role: 'payload' }, + ]), + ]); + assert.equal(report.rootLabels.length, 2, 'internal members never become shipping build roots'); + assert.equal(report.internalRootLabels.length, 1); +}); + +test('wrong owner, version, platform, role and undeclared carrier fail closed', () => { + for (const [change, message] of [ + [{ product: 'unknown' }, /unexpected shipping product/], + [{ version: '9.0.0' }, /wrong shipping version/], + [{ configuration: 'windows' }, /wrong carrier target/], + [{ role: 'github-release-asset' }, /wrong carrier role/], + [{ name: 'undeclared' }, /undeclared carrier/], + ] as const) { + assert.throws( + () => + checkShippingCoverage(authority(), [ + cohort([{ ...carrierPackage, ...change }, artifactPackage]), + ]), + message, + ); + } + const knownOwnerMismatch = authority({ + products: ['fixture', 'other'], + carriers: [{ ...carrier, product: 'other' }], + }); + assert.throws( + () => checkShippingCoverage(knownOwnerMismatch, [cohort([carrierPackage, artifactPackage])]), + /wrong carrier ownership/, + ); + assert.throws( + () => + checkShippingCoverage(authority(), [ + cohort([carrierPackage, { ...artifactPackage, configuration: 'windows' }]), + ]), + /wrong artifact target/, + ); + assert.throws( + () => + checkShippingCoverage(authority(), [ + cohort([carrierPackage, { ...artifactPackage, role: 'github-release-metadata' }]), + ]), + /unexpected public artifact/, + ); +}); + +test('duplicate roots and repeated configured cohorts do not duplicate publication identities', () => { + const complete = cohort([carrierPackage, artifactPackage]); + assert.throws( + () => checkShippingCoverage(authority(), [complete, complete]), + /duplicate configured shipping identity/, + ); + assert.throws( + () => + checkShippingCoverage(authority(), [ + cohort([carrierPackage, carrierPackage, artifactPackage]), + ]), + /duplicate configured shipping identity/, + ); +}); + +test('independent configured cohorts collectively cover one complete canonical inventory', () => { + const report = checkShippingCoverage(authority(), [ + cohort([carrierPackage], 'carrier'), + cohort([artifactPackage], 'public'), + ]); + assert.equal(report.completeProductInventory, true); + assert.equal(report.rootLabels.length, 2); + assert.equal(report.constructionActionDescriptions, 2); +}); + +test('partial action graph and mismatched physical producer ownership fail before coverage', () => { + const partial = cohort([carrierPackage, artifactPackage]); + (partial.aquery as { actions: unknown[] }).actions = []; + assert.throws( + () => checkShippingCoverage(authority(), [partial]), + /shipping output owner disagrees/, + ); + const forged = cohort([carrierPackage, artifactPackage]); + const root = forged.roots[0] as { package: { outputs: { owner: string }[] } }; + root.package.outputs[0].owner = '//fixture:another_archive'; + assert.throws( + () => checkShippingCoverage(authority(), [forged]), + /shipping output owner disagrees/, + ); + const invalidLabel = cohort([carrierPackage, artifactPackage]); + (invalidLabel.roots[0] as { label: string }).label = '@invalid'; + assert.throws(() => checkShippingCoverage(authority(), [invalidLabel]), /invalid root label/); +}); + +test('explicit subset passes only as subset; omitted products cannot certify full migration', () => { + const canonical = authority({ products: ['fixture', 'other'] }); + const actual = [cohort([carrierPackage, artifactPackage])]; + assert.throws(() => checkShippingCoverage(canonical, actual), /product:other/); + const report = checkShippingCoverage(canonical, actual, { products: ['fixture'] }); + assert.equal(report.completeProductInventory, false); + assert.throws( + () => checkShippingCoverage(canonical, actual, { products: ['fixture', 'fixture'] }), + /unique product/, + ); + assert.throws( + () => checkShippingCoverage(canonical, actual, { products: ['unknown'] }), + /unknown selected product/, + ); +}); + +test('dynamic Cargo parts add to declared carrier coverage and never replace their parent', () => { + const part = { ...carrierPackage, name: 'fixture-linux-part-001', role: 'payload-part' }; + assert.throws( + () => checkShippingCoverage(authority(), [cohort([part, artifactPackage])]), + /cannot replace its declared parent/, + ); + const report = checkShippingCoverage(authority(), [ + cohort([carrierPackage, artifactPackage, part]), + ]); + assert.equal(report.dynamicCarriers, 1); +}); + +test('candidate-only release inputs are reported separately and required only when claimed', () => { + const input = { + ...artifact, + id: 'release-input:release-tree', + name: 'release-tree', + role: 'release-input', + target: 'portable', + }; + const canonical = authority({ artifacts: [artifact, input] }); + const publicRoots = [carrierPackage, artifactPackage]; + assert.equal( + checkShippingCoverage(canonical, [cohort(publicRoots)]).releaseInputsRequired, + false, + ); + assert.throws( + () => checkShippingCoverage(canonical, [cohort(publicRoots)], { includeReleaseInputs: true }), + /release-input:release-tree/, + ); + const report = checkShippingCoverage( + canonical, + [ + cohort([ + ...publicRoots, + { ...artifactPackage, name: input.name, configuration: input.target, role: input.role }, + ]), + ], + { includeReleaseInputs: true }, + ); + assert.equal(report.releaseInputRoots, 1); + assert.equal(report.publicArtifacts, 1); +}); + +test('source publication requires its actual manifest and tree while candidate fixtures remain optional', () => { + const sourceInputs = [ + ['Package.swift.release', 'swiftpm-release-manifest'], + ['release-tree', 'swiftpm-release-tree'], + ['swiftpm-extension-consumer-fixture', 'swiftpm-extension-consumer-fixture'], + ].map(([name, kind]) => ({ + ...artifact, + id: `release-input:${kind}`, + name, + kind, + role: 'release-input', + target: 'portable', + })); + const canonical = authority({ carriers: [], artifacts: sourceInputs }); + canonical.catalog.products[0].publishTargets = ['swift-package-source-tag', 'github-release']; + const packages = sourceInputs.map((input) => ({ + ...artifactPackage, + name: input.name, + configuration: input.target, + role: input.role, + })); + const report = checkShippingCoverage(canonical, [cohort(packages.slice(0, 2))]); + assert.equal(report.completeProductInventory, true); + assert.equal(report.declaredCarriers, 0, 'source publication invents no registry carrier'); + assert.equal(report.publicArtifacts, 0); + assert.equal(report.sourcePublicationInputs, 2); + assert.equal(report.releaseInputsRequired, false); + assert.equal(report.releaseInputRoots, 2); + for (const missing of [0, 1]) { + assert.throws( + () => + checkShippingCoverage(canonical, [ + cohort(packages.filter((_, index) => index !== missing)), + ]), + new RegExp(sourceInputs[missing].id), + ); + } + assert.throws(() => checkShippingCoverage(canonical, [cohort([packages[2]])]), /product:fixture/); + assert.throws( + () => + checkShippingCoverage(canonical, [cohort(packages.slice(0, 2))], { + includeReleaseInputs: true, + }), + /release-input:swiftpm-extension-consumer-fixture/, + ); + assert.throws( + () => + checkShippingCoverage({ ...canonical, artifactRows: sourceInputs.slice(1) }, [ + cohort(packages), + ]), + /source publication requires one canonical swiftpm-release-manifest/, + ); +}); diff --git a/tools/ci/BUILD.bazel b/tools/ci/BUILD.bazel new file mode 100644 index 000000000..95b81164c --- /dev/null +++ b/tools/ci/BUILD.bazel @@ -0,0 +1,154 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/foundation:bun.bzl", "bun_script_test", "bun_test") +load(":bazel-disk-cache-gc.bzl", "bazel_disk_cache_gc") + +package(default_visibility = ["//visibility:public"]) + +bazel_disk_cache_gc(name = "bazel_disk_cache_gc", tags = ["manual"]) + +filegroup( + name = "configured_ci_sources", + srcs = [ + "bazel-recorded-inputs.mts", + "configured-scope.mts", + "native-import-projection.mts", + "run-configured-request.mts", + "//build_defs/resources:seed_construction.mts", + "//src/database-resources:contracts/native-manifest.mts", + "//src/database-resources:contracts/contract.json", + "//:tools/packaging/portable-archive.mts", + "//:tools/packaging/release-directory-safety.mts", + "//tools/release:bazel-shipping-inputs.mts", + "//tools/release:github-core-request-journal.mts", + "//tools/release:github-read.mts", + "//tools/release:github-release-lineage.mts", + "//tools/release:native-build-qualification.mts", + "//tools/release:native-configured-inputs.mts", + "//tools/release:native-file-identity.mts", + "//tools/release:native-extension-final-inputs.mts", + "//tools/release:native-supplier-artifacts.mts", + "//tools/release:with-source.mts", + ], +) + +[bun_test( + name = name, + entry_point = entry, + data = ["bazel-recorded-inputs.mts"] if name == "bazel_recorded_inputs_test" else [":configured_ci_sources", "//:workflow_policy_sources", "//:tools/packaging/testdata/zip-fixture.mts", "//:tools/packaging/testdata/tar-fixture.mts", "//tools/release:with-source.sh", "//tools/release:qualified-release-replay.sh"], + tags = ["source-check"], + size = "small", +) for name, entry in [ + ("bazel_recorded_inputs_test", "bazel-recorded-inputs.test.mts"), + ("configured_scope_test", "configured-scope.test.mts"), + ("native_import_projection_test", "native-import-projection.test.mts"), + ("run_configured_request_test", "run-configured-request.test.mts"), +]] + +bun_test( + name = "workflow_security_test", + entry_point = "workflow-security.test.mts", + data = ["workflow-security.mts"], + tags = ["source-check"], + size = "small", +) + +bun_script_test( + name = "workflow_security_check", + entry_point = "workflow-security.mts", + data = ["//:workflow_policy_sources"], + tags = ["source-check"], + size = "small", +) + +bun_test( + name = "workflow_bazel_cache_test", + entry_point = "workflow-bazel-cache.test.mts", + data = ["//:.bazelrc", "//:workflow_policy_sources"], + tags = ["source-check"], + size = "small", +) + +bun_test( + name = "workflow_native_bazel_test", + entry_point = "workflow-native-bazel.test.mts", + data = [ + "//:workflow_policy_sources", + "//:BUILD.bazel", + "//:.github/scripts/check-release-intent.sh", + "//:.github/scripts/release-intent-data.mts", + "//tools/release:with-source.sh", + ], + tags = ["source-check"], + size = "small", +) + +bun_test( + name = "ci_gate_test", + entry_point = "ci-gate.test.mts", + data = ["//:.github/scripts/check-ci-gate.mts"], + tags = ["source-check"], + size = "small", +) + +bun_test( + name = "mobile_e2e_resolver_test", + entry_point = "//:.github/scripts/resolve-mobile-e2e.test.mts", + data = [ + "//:.github/scripts/resolve-mobile-e2e.mts", + "//tools/release:github-read.mts", + "//tools/release:github-core-request-journal.mts", + "//tools/release:github-release-lineage.mts", + ], + tags = ["source-check"], + size = "small", +) + +_WORKFLOW_LINTERS = ["@actionlint_linux_x64//:actionlint", "@zizmor_linux_x64//:zizmor", "@shellcheck_linux_x64//:shellcheck"] +[bun_script_test( + name = name, + entry_point = entry, + args = ["$(location " + tool + ")" for tool in _WORKFLOW_LINTERS], + data = _WORKFLOW_LINTERS + (["workflow-lint.mts"] if name == "workflow_lint_contract_test" else ["//:workflow_policy_sources", "//:.github/zizmor.yml", "//:.gitignore"]), + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + tags = ["source-check"], + size = "small", +) for name, entry in [("workflow_lint_test", "workflow-lint.mts"), ("workflow_lint_contract_test", "workflow-lint.test.mts")]] + +test_suite( + name = "source_checks", + tests = [ + ":bazel_recorded_inputs_test", + ":configured_scope_test", + ":native_import_projection_test", + ":run_configured_request_test", + ":ci_gate_test", + ":installed_replay_tools_test", + ":mobile_e2e_resolver_test", + ":workflow_bazel_cache_test", + ":workflow_native_bazel_test", + ":workflow_security_check", + ":workflow_security_test", + ":workflow_lint_test", + ":workflow_lint_contract_test", + ], +) + +alias( + name = "android_installed_replay_tools", + actual = "//src/examples/native/react-native-expo:android_installed_test_tools", +) + +alias( + name = "ios_installed_replay_tools", + actual = "//src/examples/native/react-native-expo:ios_installed_test_tools", +) + +bun_test( + name = "installed_replay_tools_test", + entry_point = "//build_defs/apple:installed-tools.test.mts", + data = ["//build_defs/apple:installed-tools.mts"], + tags = ["source-check"], + size = "small", +) + +source_quality_files() diff --git a/tools/ci/bazel-disk-cache-gc.bzl b/tools/ci/bazel-disk-cache-gc.bzl new file mode 100644 index 000000000..9dc0c3e58 --- /dev/null +++ b/tools/ci/bazel-disk-cache-gc.bzl @@ -0,0 +1,40 @@ +"""Run the stock collector with its required Java version, scoped to this tool.""" + +def _java21_impl(_settings, _attr): + return { + "//command_line_option:java_language_version": "21", + "//command_line_option:tool_java_language_version": "21", + "//command_line_option:java_runtime_version": "remotejdk_21", + "//command_line_option:tool_java_runtime_version": "remotejdk_21", + } + +_java21 = transition( + implementation = _java21_impl, + inputs = [], + outputs = [ + "//command_line_option:java_language_version", + "//command_line_option:tool_java_language_version", + "//command_line_option:java_runtime_version", + "//command_line_option:tool_java_runtime_version", + ], +) + +def _bazel_disk_cache_gc_impl(ctx): + binary = ctx.attr.binary[0][DefaultInfo] + original = binary.files_to_run.executable + executable = ctx.actions.declare_file(ctx.label.name + "/" + original.basename) + ctx.actions.symlink(output = executable, target_file = original, is_executable = True) + return [DefaultInfo( + executable = executable, + files = depset([executable], transitive = [binary.files]), + runfiles = binary.default_runfiles.merge(ctx.runfiles([executable])), + )] + +bazel_disk_cache_gc = rule( + implementation = _bazel_disk_cache_gc_impl, + executable = True, + attrs = { + "binary": attr.label(default = Label("@bazel_disk_cache_gc//:gc"), cfg = _java21, executable = True), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), + }, +) diff --git a/tools/ci/bazel-recorded-inputs.mts b/tools/ci/bazel-recorded-inputs.mts new file mode 100644 index 000000000..1e3868112 --- /dev/null +++ b/tools/ci/bazel-recorded-inputs.mts @@ -0,0 +1,566 @@ +import { isUtf8 } from 'node:buffer'; +import { createReadStream } from 'node:fs'; +import { readFile } from 'node:fs/promises'; +import path from 'node:path'; + +// Pinned format: Bazel 8.8.1 RepositoryDelegatorFunction marker version 7 and +// BazelLockFileValue version 28; RepoRecordedInput.WithValue and its Gson adapter. +// Record values and unrelated lock data must never become decoded strings. +export class IncompleteBazelRecordedInputsError extends Error { + override name = 'IncompleteBazelRecordedInputsError'; +} + +function incomplete(message: string): never { + throw new IncompleteBazelRecordedInputsError(message); +} + +const readErrorCodes = new Set([ + 'EACCES', + 'EBUSY', + 'EINVAL', + 'EIO', + 'EISDIR', + 'ELOOP', + 'EMFILE', + 'ENAMETOOLONG', + 'ENFILE', + 'ENOENT', + 'ENOMEM', + 'ENOTDIR', + 'EPERM', +]); + +async function readInput(kind: string, input: Promise): Promise { + try { + return await input; + } catch (error) { + if (error instanceof IncompleteBazelRecordedInputsError) throw error; + const code = + error !== null && typeof error === 'object' && 'code' in error ? error.code : undefined; + const errno = typeof code === 'string' && readErrorCodes.has(code) ? code : 'UNKNOWN'; + // Never include the raw I/O message, file path or ignored recorded values. + incomplete(`Missing or unreadable Bazel recorded source input: ${kind} (${errno})`); + } +} + +class LockReader { + private readonly chunks: AsyncIterator; + private chunk = Buffer.alloc(0); + private offset = 0; + + constructor(file: string) { + this.chunks = createReadStream(file)[Symbol.asyncIterator](); + } + + async peek(): Promise { + while (this.offset === this.chunk.length) { + const next = await this.chunks.next(); + if (next.done) return -1; + this.chunk = next.value; + this.offset = 0; + } + return this.chunk[this.offset]; + } + + async take(): Promise { + const byte = await this.peek(); + if (byte >= 0) this.offset++; + return byte; + } + + async space() { + while ([9, 10, 13, 32].includes(await this.peek())) this.offset++; + } + + async expect(byte: number) { + await this.space(); + if ((await this.take()) !== byte) incomplete('Malformed Bazel lock structure'); + } + + async string(mode: 'key' | 'record' | 'skip'): Promise { + await this.expect(34); + const parts: Buffer[] = []; + let capture = mode !== 'skip'; + let separated = false; + const append = (bytes: Buffer) => { + if (!capture) return; + const separator = mode === 'record' ? bytes.indexOf(32) : -1; + if (separator < 0) parts.push(bytes); + else { + parts.push(bytes.subarray(0, separator)); + capture = false; + separated = true; + } + }; + for (;;) { + if ((await this.peek()) < 0) incomplete('Truncated Bazel lock string'); + const start = this.offset; + while (this.offset < this.chunk.length) { + const byte = this.chunk[this.offset]; + if (byte === 34 || byte === 92) break; + if (byte < 32) incomplete('Malformed Bazel lock string'); + this.offset++; + } + append(this.chunk.subarray(start, this.offset)); + if (this.offset === this.chunk.length) continue; + if ((await this.take()) === 34) { + if (mode === 'record' && !separated) incomplete('Missing recorded-input separator'); + const key = Buffer.concat(parts); + if (!isUtf8(key)) incomplete('Unsupported recorded-input key encoding'); + return key.toString('utf8'); + } + const escapedByte = await this.take(); + if (escapedByte === 117) { + const hex = Buffer.alloc(4); + for (let i = 0; i < 4; i++) { + const byte = await this.take(); + if ( + !( + (byte >= 48 && byte <= 57) || + (byte >= 65 && byte <= 70) || + (byte >= 97 && byte <= 102) + ) + ) { + incomplete('Malformed Bazel lock escape'); + } + hex[i] = byte; + } + if (capture) { + const code = Number.parseInt(hex.toString('ascii'), 16); + if (code >= 0xd800 && code <= 0xdfff) + incomplete('Unsupported recorded-input Unicode escape'); + append(Buffer.from(String.fromCharCode(code))); + } + } else { + const escaped = new Map([ + [34, 34], + [92, 92], + [47, 47], + [98, 8], + [102, 12], + [110, 10], + [114, 13], + [116, 9], + ]); + const byte = escaped.get(escapedByte); + if (byte === undefined) incomplete('Malformed Bazel lock escape'); + if (capture) append(Buffer.from([byte])); + } + } + } + + async object(entry: (key: string) => Promise, keys = true) { + await this.expect(123); + await this.space(); + if ((await this.peek()) === 125) { + this.offset++; + return; + } + for (;;) { + const key = await this.string(keys ? 'key' : 'skip'); + await this.expect(58); + await entry(key); + await this.space(); + const byte = await this.take(); + if (byte === 125) return; + if (byte !== 44) incomplete('Malformed Bazel lock object'); + } + } + + async array(entry: () => Promise) { + await this.expect(91); + await this.space(); + if ((await this.peek()) === 93) { + this.offset++; + return; + } + for (;;) { + await entry(); + await this.space(); + const byte = await this.take(); + if (byte === 93) return; + if (byte !== 44) incomplete('Malformed Bazel lock array'); + } + } + + async number(capture = true): Promise { + await this.space(); + let number = ''; + const take = async () => { + const byte = await this.take(); + if (capture) number += String.fromCharCode(byte); + }; + const digits = async () => { + let count = 0; + while ((await this.peek()) >= 48 && (await this.peek()) <= 57) { + await take(); + count++; + } + if (!count) incomplete('Malformed Bazel lock number'); + }; + if ((await this.peek()) === 45) await take(); + if ((await this.peek()) === 48) await take(); + else await digits(); + if ((await this.peek()) === 46) { + await take(); + await digits(); + } + if ([69, 101].includes(await this.peek())) { + await take(); + if ([43, 45].includes(await this.peek())) await take(); + await digits(); + } + return number; + } + + async skip(): Promise { + await this.space(); + const byte = await this.peek(); + if (byte === 34) { + await this.string('skip'); + return; + } + if (byte === 123) { + await this.object(() => this.skip(), false); + return; + } + if (byte === 91) { + await this.array(() => this.skip()); + return; + } + if (byte === 45 || (byte >= 48 && byte <= 57)) { + await this.number(false); + return; + } + const literal = new Map([ + [116, 'true'], + [102, 'false'], + [110, 'null'], + ]).get(byte); + if (!literal) incomplete('Malformed Bazel lock value'); + for (const char of literal) + if ((await this.take()) !== char.charCodeAt(0)) incomplete('Malformed Bazel lock literal'); + } + + async close() { + await this.chunks.return?.(); + } +} + +function currentHostFactors(factor: string): boolean { + if (factor === 'general') return true; + const match = /^(?:os:([^,]+)(?:,arch:([^,]+))?|arch:([^,]+))$/u.exec(factor); + if (!match) incomplete('Unsupported extension evaluation factors'); + const os = match[1]; + const arch = match[2] ?? match[3]; + const hostOs = + process.platform === 'darwin' + ? 'mac os x' + : process.platform === 'win32' + ? 'windows' + : process.platform; + const hostArch = + process.arch === 'x64' + ? ['amd64', 'x86_64', 'x64'] + : process.arch === 'arm64' + ? ['aarch64', 'arm64'] + : [process.arch]; + return ( + (!os || (hostOs === 'windows' ? os.startsWith('windows') : os === hostOs)) && + (!arch || hostArch.includes(arch)) + ); +} + +type ExtensionInputs = { keys: string[]; generated: Set }; + +async function lockInputs(file: string) { + const reader = new LockReader(file); + const inputs = new Map(); + let version = false; + let extensions = false; + try { + await reader.object(async (key) => { + if (key === 'lockFileVersion') { + if (version || (await reader.number()) !== '28') + incomplete('Unsupported Bazel lock version'); + version = true; + } else if (key === 'moduleExtensions') { + if (extensions) incomplete('Duplicate Bazel module extension table'); + extensions = true; + await reader.object(async (extension) => { + if (inputs.has(extension)) incomplete('Duplicate module extension identity'); + const keys: string[] = []; + const generated = new Set(); + let matched = false; + await reader.object(async (factor) => { + if (!currentHostFactors(factor)) { + await reader.skip(); + return; + } + matched = true; + let records = false; + let specs = false; + await reader.object(async (field) => { + if (field === 'recordedInputs') { + if (records) incomplete('Duplicate extension recorded inputs'); + records = true; + await reader.array(async () => keys.push(await reader.string('record'))); + } else if (field === 'generatedRepoSpecs') { + if (specs) incomplete('Duplicate extension generated repositories'); + specs = true; + const names = new Set(); + await reader.object(async (name) => { + repositoryName(name); + if (names.has(name)) incomplete('Duplicate extension generated repository'); + names.add(name); + generated.add(name); + await reader.skip(); + }); + } else { + await reader.skip(); + } + }); + if (!records) incomplete('Missing extension recorded inputs'); + if (!specs) incomplete('Missing extension generated repositories'); + }); + inputs.set(extension, matched ? { keys, generated } : undefined); + }); + } else await reader.skip(); + }); + await reader.space(); + if (!version || !extensions || (await reader.peek()) !== -1) + incomplete('Incomplete Bazel lock'); + } finally { + await reader.close(); + } + return inputs; +} + +/** Group observed internal names by stock canonical prefix; never reconstruct collision ordinals. */ +function extensionGroups(extension: string, repositories: Set) { + const match = /^(?:@@?([^/]*))?\/\/[^%]+%([a-zA-Z][a-zA-Z0-9_]*)(?:%(.+))?$/u.exec(extension); + if (!match) incomplete('Unsupported module extension identity'); + const prefix = `${match[1] ?? ''}+${match[3] ? '_' : ''}${match[2]}`; + const groups = new Map>(); + for (const name of repositories) { + if (!name.startsWith(prefix)) continue; + const suffix = /^(\d*)\+(.+)$/u.exec(name.slice(prefix.length)); + if (!suffix) continue; + if (match[3]) incomplete('Unsupported used isolated module extension'); + const unique = prefix + suffix[1]; + const names = groups.get(unique) ?? new Set(); + names.add(suffix[2]); + groups.set(unique, names); + } + return groups; +} + +async function markerInputs(file: string, add: (key: string) => void) { + const stream = createReadStream(file); + let header = false; + let separated = false; + let parts: Buffer[] = []; + const line = () => { + const key = Buffer.concat(parts); + parts = []; + if (!key.length && !separated) return; + if (!header) { + if (separated || !isUtf8(key) || !/^[a-f0-9]{64}$/u.test(key.toString('utf8'))) + incomplete('Unsupported Bazel marker header'); + header = true; + } else { + if (!separated) incomplete('Missing marker recorded-input separator'); + if (!isUtf8(key)) incomplete('Unsupported recorded-input key encoding'); + add(key.toString('utf8')); + } + separated = false; + }; + try { + for await (const chunk of stream) { + let start = 0; + for (let i = 0; i < chunk.length; i++) { + if (chunk[i] === 10) { + if (!separated) parts.push(chunk.subarray(start, i)); + line(); + start = i + 1; + } else if (!separated && chunk[i] === 32) { + parts.push(chunk.subarray(start, i)); + separated = true; + } + } + if (!separated) parts.push(chunk.subarray(start)); + } + line(); + if (!header) incomplete('Missing Bazel marker header'); + } finally { + stream.destroy(); + } +} + +function recordKey( + encoded: string, +): { kind: 'FILE' | 'DIRENTS' | 'DIRTREE'; location: string } | undefined { + const colon = encoded.indexOf(':'); + if (colon < 1) incomplete('Malformed recorded-input key'); + const kind = encoded.slice(0, colon); + if (kind === 'ENV' || kind === 'REPO_MAPPING') return; + if (kind !== 'FILE' && kind !== 'DIRENTS' && kind !== 'DIRTREE') + incomplete('Unsupported recorded-input key'); + const location = encoded + .slice(colon + 1) + .replace(/\\(.)/gsu, (_all, char: string) => (char === 'n' ? '\n' : char === 's' ? ' ' : char)); + if (!location || encoded.endsWith('\\') || location.includes('\0')) + incomplete('Malformed recorded-input path'); + return { kind, location }; +} + +function repositoryName(name: string): string { + if (!/^[-a-zA-Z0-9._+]+$/u.test(name) || name === '.' || name === '..') + incomplete('Invalid canonical repository name'); + return name; +} + +export async function collectBazelRecordedSourceInputs(options: { + workspaceRoot: string; + outputBase: string; + repositories: string[]; +}): Promise<{ files: string[]; trees: string[]; directories: string[] }> { + const workspace = path.resolve(options.workspaceRoot); + const outputBase = path.resolve(options.outputBase); + const groups = { + FILE: new Set(), + DIRTREE: new Set(), + DIRENTS: new Set(), + }; + const repositories = new Set(options.repositories.filter(Boolean).map(repositoryName)); + const add = (encoded: string) => { + const record = recordKey(encoded); + if (!record) return; + const match = /^(?:@@?([^/]*)\/\/|\/\/)(.*)$/su.exec(record.location); + let relative: string; + if (match) { + if (match[1]) { + repositories.add(repositoryName(match[1])); + return; + } + relative = match[2]; + } else if (path.isAbsolute(record.location)) { + relative = path.relative(workspace, record.location).split(path.sep).join('/'); + if (path.isAbsolute(relative) || relative === '..' || relative.startsWith('../')) return; + } else incomplete('Unsupported recorded-input path'); + if ( + relative.includes('\\') || + path.posix.normalize(relative || '.') !== (relative || '.') || + relative === '..' || + relative.startsWith('../') + ) + incomplete('Noncanonical recorded-input path'); + groups[record.kind].add(relative); + }; + try { + if ( + ( + await readInput('version pin', readFile(path.join(workspace, '.bazelversion'), 'utf8')) + ).trim() !== '8.8.1' + ) + incomplete('Unsupported Bazel marker format'); + const locks = await Promise.all([ + readInput('workspace lock', lockInputs(path.join(workspace, 'MODULE.bazel.lock'))), + readInput('hidden lock', lockInputs(path.join(outputBase, 'MODULE.bazel.lock'))), + ]); + const merged = new Map(); + for (const lock of locks) + for (const [extension, inputs] of lock) + merged.set( + extension, + inputs === undefined + ? merged.get(extension) + : { + keys: [...(merged.get(extension)?.keys ?? []), ...inputs.keys], + generated: new Set([ + ...(merged.get(extension)?.generated ?? []), + ...inputs.generated, + ]), + }, + ); + const rows = [...merged.entries()]; + const usedRows = new Set(); + const visited = new Set(); + const covered = new Set(); + const boundPrefixes = new Map(); + for (;;) { + let changed = false; + const candidates = new Map< + string, + { names: Set; rows: Map; missingHost: boolean } + >(); + for (const [index, [extension, inputs]] of rows.entries()) + for (const [prefix, names] of extensionGroups(extension, repositories)) { + const group = candidates.get(prefix) ?? { + names, + rows: new Map(), + missingHost: false, + }; + if (inputs === undefined) group.missingHost = true; + else if ([...names].every((name) => inputs.generated.has(name))) + group.rows.set(index, inputs); + candidates.set(prefix, group); + } + const selected = new Map(); + for (const [prefix, group] of candidates) { + if (group.missingHost || group.rows.size !== 1) continue; + for (const [index, inputs] of group.rows) { + const previous = boundPrefixes.get(index); + if (previous !== undefined && previous !== prefix) + incomplete('Used module extension has conflicting canonical prefixes'); + boundPrefixes.set(index, prefix); + selected.set(index, inputs); + } + for (const name of group.names) covered.add(`${prefix}+${name}`); + } + for (const [index, inputs] of selected) { + if (usedRows.has(index)) continue; + usedRows.add(index); + changed = true; + for (const key of inputs.keys) add(key); + } + for (const repository of repositories) { + if (visited.has(repository)) continue; + visited.add(repository); + changed = true; + // These two stock repositories are supplied by the verified pinned Bazel + // installation, whose override path deliberately has no fetch marker. + if (repository === 'bazel_tools' || repository === '_builtins') continue; + await readInput( + `repository marker @${repository}`, + markerInputs(path.join(outputBase, 'external', `@${repository}.marker`), add), + ); + } + if (!changed) { + for (const group of candidates.values()) { + if (group.missingHost) + incomplete('Used module extension has no current-host persisted row'); + if (group.rows.size > 1) incomplete('Ambiguous used module extension repository'); + if (!group.rows.size) incomplete('Used module extension has no persisted input record'); + } + break; + } + } + for (const name of repositories) { + if ( + (name.match(/\+/gu)?.length ?? 0) >= 2 && + !/(?:^|\+)_repo_rules\d*\+/u.test(name) && + !covered.has(name) + ) + incomplete('Used module extension has no persisted input record'); + } + } catch (error) { + if (error instanceof IncompleteBazelRecordedInputsError) throw error; + incomplete('Missing or unreadable Bazel recorded source inputs'); + } + return { + files: [...groups.FILE].sort(), + trees: [...groups.DIRTREE].sort(), + directories: [...groups.DIRENTS].sort(), + }; +} diff --git a/tools/ci/bazel-recorded-inputs.test.mts b/tools/ci/bazel-recorded-inputs.test.mts new file mode 100644 index 000000000..ea72fe208 --- /dev/null +++ b/tools/ci/bazel-recorded-inputs.test.mts @@ -0,0 +1,665 @@ +import assert from 'node:assert/strict'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import { + collectBazelRecordedSourceInputs, + IncompleteBazelRecordedInputsError, +} from './bazel-recorded-inputs.mts'; + +// RepoRecordedInput.escape/WithValue and GsonTypeAdapterUtil's string adapter, +// pinned at https://github.com/bazelbuild/bazel/tree/8.8.1/src/main/java/com/google/devtools/build/lib. +const escapeRecorded = (value: string) => + value.replaceAll('\\', '\\\\').replaceAll('\n', '\\n').replaceAll(' ', '\\s'); +const record = (kind: string, key: string, value = 'ignored') => + `${kind}:${escapeRecorded(key)} ${escapeRecorded(value)}`; +const row = (recordedInputs: string[], generatedNames = ['fixture']) => ({ + recordedInputs, + generatedRepoSpecs: Object.fromEntries(generatedNames.map((name) => [name, {}])), + bzlTransitiveDigest: 'ignored', + usagesDigest: 'ignored', +}); +const lock = (recordedInputs: string[] = [], generatedNames = ['fixture']) => ({ + lockFileVersion: 28, + moduleExtensions: { + '//build_defs:acquire.bzl%inputs': { general: row(recordedInputs, generatedNames) }, + }, +}); + +async function fixture( + run: (f: { + workspaceRoot: string; + outputBase: string; + repositories: string[]; + source: (value: unknown) => void; + hidden: (value: unknown) => void; + marker: (name: string, records: string[]) => void; + }) => Promise, +) { + const root = mkdtempSync(path.join(tmpdir(), 'bazel-recorded-inputs-')); + const workspaceRoot = path.join(root, 'source with spaces'); + const outputBase = path.join(root, 'output'); + mkdirSync(workspaceRoot); + mkdirSync(path.join(outputBase, 'external'), { recursive: true }); + writeFileSync(path.join(workspaceRoot, '.bazelversion'), '8.8.1\n'); + const source = (value: unknown) => + writeFileSync(path.join(workspaceRoot, 'MODULE.bazel.lock'), JSON.stringify(value)); + const hidden = (value: unknown) => + writeFileSync(path.join(outputBase, 'MODULE.bazel.lock'), JSON.stringify(value)); + source(lock()); + hidden(lock()); + writeFileSync(path.join(outputBase, 'external/@+inputs+fixture.marker'), `${'a'.repeat(64)}\n`); + try { + await run({ + workspaceRoot, + outputBase, + repositories: ['+inputs+fixture'], + source, + hidden, + marker: (name, records) => { + writeFileSync( + path.join(outputBase, 'external', `@${name}.marker`), + `${'a'.repeat(64)}\n${records.join('\n')}\n`, + ); + }, + }); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +test('unions both lock locations and recursively follows acquisition-only external inputs', async () => { + await fixture(async (f) => { + f.repositories = ['+inputs+product', '+inputs+product']; + f.source( + lock( + [record('FILE', '@@//src/version.toml'), record('FILE', '@@metadata+//model.json')], + ['product'], + ), + ); + f.hidden( + lock( + [ + record('DIRTREE', '//src/resources'), + record('DIRENTS', '//src/extensions'), + record('FILE', '@@//src/version.toml'), + ], + ['product'], + ), + ); + f.marker('+inputs+product', [ + record('FILE', '@@//patches/compiler.patch'), + record('DIRTREE', '@@metadata+//catalog'), + ]); + f.marker('metadata+', [ + record('FILE', '//src/model.toml'), + record('DIRENTS', '@@metadata-helper+//metadata'), + ]); + f.marker('metadata-helper+', [record('FILE', '//src/manifest with space.toml')]); + assert.deepEqual(await collectBazelRecordedSourceInputs(f), { + files: [ + 'patches/compiler.patch', + 'src/manifest with space.toml', + 'src/model.toml', + 'src/version.toml', + ], + trees: ['src/resources'], + directories: ['src/extensions'], + }); + }); +}); + +test('unused extension rows do not broaden a configured request', async () => { + await fixture(async (f) => { + f.hidden({ lockFileVersion: 28, moduleExtensions: {} }); + f.source({ + lockFileVersion: 28, + moduleExtensions: { + '//defs:inputs.bzl%inputs': { general: row([record('FILE', '//used')]) }, + '//defs:unrelated.bzl%unrelated': { + general: row([record('DIRTREE', '//'), record('FILE', '@@unfetched+//secret')]), + }, + }, + }); + assert.deepEqual(await collectBazelRecordedSourceInputs(f), { + files: ['used'], + trees: [], + directories: [], + }); + }); +}); + +test('generated names distinguish extension-name digits from collision ordinals', async () => { + await fixture(async (f) => { + f.repositories = ['+ext2+output']; + f.marker('+ext2+output', []); + f.source({ + lockFileVersion: 28, + moduleExtensions: { + '//defs:one.bzl%ext': { general: row([record('FILE', '//collision')], ['other']) }, + '//defs:two.bzl%ext2': { general: row([record('FILE', '//exact')], ['output']) }, + '//defs:three.bzl%ext3': { general: row([record('FILE', '//unused')]) }, + }, + }); + assert.deepEqual((await collectBazelRecordedSourceInputs(f)).files, ['exact']); + }); +}); + +test('one reached hub binds all shared names to its sibling extension without fetching unused metadata', async () => { + await fixture(async (f) => { + const missing = '+_repo_rules9+wasix_adapter_cargo_metadata'; + const adapter = [ + 'shared', + 'adapter_hub', + ...Array.from({ length: 491 }, (_, i) => `adapter_${i}`), + ]; + const postmaster = [ + 'shared', + 'postmaster_hub', + ...Array.from({ length: 824 }, (_, i) => `postmaster_${i}`), + ]; + f.source({ + lockFileVersion: 28, + moduleExtensions: { + '//defs:adapter.bzl%crate': { + general: row([record('FILE', `@@${missing}//Cargo.toml`)], adapter), + }, + '//defs:postmaster.bzl%crate': { + general: row([record('FILE', '@@postmaster_metadata+//Cargo.toml')], postmaster), + }, + }, + }); + f.repositories = ['+crate3+shared', '+crate3+postmaster_hub']; + for (const name of f.repositories) f.marker(name, []); + f.marker('postmaster_metadata+', [ + record('FILE', '//src/postmaster/Cargo.toml'), + record('DIRTREE', '//src/postmaster/assets'), + record('DIRENTS', '//src/postmaster/manifests'), + ]); + assert.deepEqual(await collectBazelRecordedSourceInputs(f), { + files: ['src/postmaster/Cargo.toml'], + trees: ['src/postmaster/assets'], + directories: ['src/postmaster/manifests'], + }); + f.repositories = ['+crate3+shared', '+crate3+adapter_hub']; + f.marker('+crate3+adapter_hub', []); + await assert.rejects(collectBazelRecordedSourceInputs(f), { + name: 'IncompleteBazelRecordedInputsError', + message: `Missing or unreadable Bazel recorded source input: repository marker @${missing} (ENOENT)`, + }); + }); +}); + +test('unresolved same-name sibling repositories fail closed', async () => { + await fixture(async (f) => { + f.repositories = ['+crate3+shared']; + f.marker('+crate3+shared', []); + f.source({ + lockFileVersion: 28, + moduleExtensions: { + '//defs:one.bzl%crate': { general: row([record('FILE', '//one')], ['shared']) }, + '//defs:two.bzl%crate': { general: row([record('FILE', '//two')], ['shared']) }, + }, + }); + await assert.rejects(collectBazelRecordedSourceInputs(f), /Ambiguous used module extension/u); + }); +}); + +test('reached marker fan-in can disambiguate a shared name before the fixpoint closes', async () => { + await fixture(async (f) => { + f.repositories = ['+crate3+shared']; + f.marker('+crate3+shared', [record('FILE', '@@+crate3+postmaster_hub//metadata')]); + f.marker('+crate3+postmaster_hub', []); + f.source({ + lockFileVersion: 28, + moduleExtensions: { + '//defs:adapter.bzl%crate': { + general: row([record('FILE', '@@unused+//metadata')], ['shared', 'adapter_hub']), + }, + '//defs:postmaster.bzl%crate': { + general: row([record('FILE', '//postmaster')], ['shared', 'postmaster_hub']), + }, + }, + }); + assert.deepEqual((await collectBazelRecordedSourceInputs(f)).files, ['postmaster']); + }); +}); + +test('one extension identity cannot authenticate two canonical unique prefixes', async () => { + await fixture(async (f) => { + f.repositories = ['+crate3+shared', '+crate4+shared']; + for (const name of f.repositories) f.marker(name, []); + f.source({ + lockFileVersion: 28, + moduleExtensions: { + '//defs:one.bzl%crate': { general: row([], ['shared']) }, + }, + }); + await assert.rejects(collectBazelRecordedSourceInputs(f), /conflicting canonical prefixes/u); + }); +}); + +test('missing or malformed generated-repository names remain unknown', async () => { + for (const generated of [ + '', + ',"generatedRepoSpecs":[]', + ',"generatedRepoSpecs":{}', + ',"generatedRepoSpecs":{"fixture":{}},"generatedRepoSpecs":{"fixture":{}}', + ',"generatedRepoSpecs":{"fixture":{},"fixture":{}}', + ',"generatedRepoSpecs":{"bad/name":{}}', + ',"generatedRepoSpecs":{"..":{}}', + ]) + await fixture(async (f) => { + writeFileSync( + path.join(f.workspaceRoot, 'MODULE.bazel.lock'), + `{"lockFileVersion":28,"moduleExtensions":{"//defs:inputs.bzl%inputs":{"general":{"recordedInputs":[]${generated}}}}}`, + ); + f.hidden({ lockFileVersion: 28, moduleExtensions: {} }); + await assert.rejects(collectBazelRecordedSourceInputs(f), IncompleteBazelRecordedInputsError); + }); +}); + +test('metadata repository reads activate transitive extension inputs to a fixpoint', async () => { + await fixture(async (f) => { + f.hidden({ lockFileVersion: 28, moduleExtensions: {} }); + f.source({ + lockFileVersion: 28, + moduleExtensions: { + '@@metadata+//defs:acquire.bzl%next': { + general: row([record('FILE', '//transitive')], ['data']), + }, + '//defs:inputs.bzl%inputs': { + general: row([record('FILE', '@@metadata++next+data//metadata')]), + }, + }, + }); + f.marker('metadata++next+data', [record('FILE', '//marker')]); + assert.deepEqual((await collectBazelRecordedSourceInputs(f)).files, ['marker', 'transitive']); + }); +}); + +test('used isolated or missing extension rows fail closed; innate rows use actual markers', async () => { + await fixture(async (f) => { + f.repositories = ['+_ext+out']; + f.marker('+_ext+out', []); + f.source({ + lockFileVersion: 28, + moduleExtensions: { '//defs:e.bzl%ext%isolation': { general: row([]) } }, + }); + await assert.rejects(collectBazelRecordedSourceInputs(f), /isolated/u); + }); + await fixture(async (f) => { + f.repositories = ['mod++missing+out']; + f.marker('mod++missing+out', []); + await assert.rejects(collectBazelRecordedSourceInputs(f), /persisted/u); + }); + await fixture(async (f) => { + f.repositories = ['mod++_repo_rules2+out']; + f.marker('mod++_repo_rules2+out', [record('FILE', '//definition')]); + assert.deepEqual((await collectBazelRecordedSourceInputs(f)).files, ['definition']); + }); +}); + +test('repository cycles are visited once without losing source inputs', async () => { + await fixture(async (f) => { + f.repositories = ['one+']; + f.marker('one+', [record('FILE', '@@two+//x')]); + f.marker('two+', [record('FILE', '@@one+//x'), record('FILE', '//input.txt')]); + assert.deepEqual((await collectBazelRecordedSourceInputs(f)).files, ['input.txt']); + }); +}); + +test('does not decode secret values, arbitrary attributes or facts, including across stream chunks', async () => { + await fixture(async (f) => { + const secret = 'SYNTHETIC_SECRET_DO_NOT_DECODE'; + const large = `${'x'.repeat(70_000)}${secret}\\n ${'y'.repeat(70_000)}`; + const sourceLock = lock( + [ + record('ENV', 'TOKEN', large), + record('REPO_MAPPING', ',dep', secret), + record('FILE', '//safe'), + ], + ['secret'], + ); + sourceLock.moduleExtensions[ + '//build_defs:acquire.bzl%inputs' + ].general.generatedRepoSpecs.secret = { + attributes: { [secret]: [large, null, true, 123.4] }, + }; + f.source({ + ...sourceLock, + facts: { [secret]: { attributes: [large, null, true, false, 123.4] } }, + }); + f.hidden(lock([record('ENV', 'OTHER', large)], ['secret'])); + f.repositories = ['+inputs+secret']; + f.marker('+inputs+secret', [ + record('ENV', 'TOKEN', large), + record('FILE', '//also-safe', large), + ]); + const original = Buffer.prototype.toString; + const originalJsonParse = JSON.parse; + Buffer.prototype.toString = function (...args) { + assert.equal( + this.includes(Buffer.from(secret)), + false, + 'ignored private bytes reached string decoding', + ); + return original.apply(this, args); + }; + JSON.parse = (text, reviver) => { + assert.equal(text.includes(secret), false, 'ignored private bytes reached JSON decoding'); + return originalJsonParse(text, reviver); + }; + try { + const result = await collectBazelRecordedSourceInputs(f); + assert.deepEqual(result, { files: ['also-safe', 'safe'], trees: [], directories: [] }); + assert.equal(JSON.stringify(result).includes(secret), false); + } finally { + Buffer.prototype.toString = original; + JSON.parse = originalJsonParse; + } + }); +}); + +test('includes current host and general evaluation factors, excluding foreign host rows', async () => { + await fixture(async (f) => { + f.repositories = ['+ext+host']; + f.marker('+ext+host', []); + const os = + process.platform === 'darwin' + ? 'mac os x' + : process.platform === 'win32' + ? 'windows 11' + : process.platform; + const arch = + process.arch === 'x64' ? 'amd64' : process.arch === 'arm64' ? 'aarch64' : process.arch; + f.source({ + lockFileVersion: 28, + moduleExtensions: { + '//defs:extension.bzl%ext': { + general: row([record('FILE', '//general')], ['host']), + [`os:${os},arch:${arch}`]: row([record('FILE', '//host')], ['host']), + 'os:foreign host,arch:unavailable': row([record('FILE', '@@not-fetched-foreign+//x')]), + }, + }, + }); + assert.deepEqual((await collectBazelRecordedSourceInputs(f)).files, ['general', 'host']); + }); +}); + +test('a used extension needs a matched persisted row, including collision candidates', async () => { + await fixture(async (f) => { + f.repositories = ['+ext2+host']; + f.marker('+ext2+host', []); + f.source({ + lockFileVersion: 28, + moduleExtensions: { + '//defs:e.bzl%ext': { general: row([], ['other']) }, + '//defs:e.bzl%ext2': { 'os:foreign host': row([record('FILE', '//omitted')], ['host']) }, + }, + }); + await assert.rejects(collectBazelRecordedSourceInputs(f), /current-host/u); + f.hidden({ + lockFileVersion: 28, + moduleExtensions: { '//defs:e.bzl%ext2': { general: row([], ['host']) } }, + }); + assert.deepEqual(await collectBazelRecordedSourceInputs(f), { + files: [], + trees: [], + directories: [], + }); + }); +}); + +test('absolute source paths normalize; outside-workspace host observations are not source paths', async () => { + await fixture(async (f) => { + f.source( + lock([ + record('FILE', path.join(f.workspaceRoot, 'src/one')), + record('DIRTREE', path.join(f.workspaceRoot, 'src/tree')), + record('FILE', path.join(f.outputBase, 'host SDK/input')), + ]), + ); + assert.deepEqual(await collectBazelRecordedSourceInputs(f), { + files: ['src/one'], + trees: ['src/tree'], + directories: [], + }); + }); +}); + +test('collector keeps Windows workspace sources and omits other drives or network roots', async () => { + // Exercise the real collector with stock Windows path operations and real + // lock/marker files on this host. Bazel 8.8.1 itself does not support UNC roots. + for (const [workspace, absolute, expected] of [ + ['D:/a/repo', 'D:/a/repo/src/lib.rs', 'src/lib.rs'], + ['d:/A/Repo', 'D:\\a\\repo\\src\\lib.rs', 'src/lib.rs'], + ['D:/a/repo', 'D:/a/repo', ''], + ['D:/a/repo', 'D:/a', undefined], + ['D:/a/repo', 'D:/a/repository/lib.rs', undefined], + ['D:/a/repo', 'C:/Program Files/SDK/header.h', undefined], + ['D:/a/repo', 'C:\\SDK\\header.h', undefined], + ['D:/a/repo', '\\\\host\\share\\SDK\\header.h', undefined], + ['\\\\host\\share\\repo', '\\\\host\\share\\repo\\src\\lib.rs', 'src/lib.rs'], + ['\\\\host\\share\\repo', '\\\\other\\share\\SDK\\header.h', undefined], + ['\\\\host\\share\\repo', '\\\\host\\other\\SDK\\header.h', undefined], + ] as const) + await fixture(async (f) => { + const originalRelative = path.relative; + const originalIsAbsolute = path.isAbsolute; + const windowsRelative = path.win32.relative; + const windowsIsAbsolute = path.win32.isAbsolute; + try { + path.relative = (parent, child) => + parent === f.workspaceRoot + ? windowsRelative(workspace, child).split(path.win32.sep).join(path.sep) + : originalRelative(parent, child); + path.isAbsolute = windowsIsAbsolute; + f.source(lock([record('FILE', absolute)])); + assert.deepEqual(await collectBazelRecordedSourceInputs(f), { + files: expected === undefined ? [] : [expected], + trees: [], + directories: [], + }); + } finally { + path.relative = originalRelative; + path.isAbsolute = originalIsAbsolute; + } + }); +}); + +test('missing referenced repository markers reject an incomplete basis', async () => { + await fixture(async (f) => { + f.hidden( + lock([ + record('ENV', 'PRIVATE_NAME', 'PRIVATE_RECORDED_VALUE'), + record('FILE', '@@missing+//metadata'), + ]), + ); + await assert.rejects(collectBazelRecordedSourceInputs(f), { + name: 'IncompleteBazelRecordedInputsError', + message: + 'Missing or unreadable Bazel recorded source input: repository marker @missing+ (ENOENT)', + }); + }); +}); + +test('only pinned stock builtin repositories can lack fetch markers', async () => { + await fixture(async (f) => { + f.repositories = ['bazel_tools', '_builtins']; + assert.deepEqual(await collectBazelRecordedSourceInputs(f), { + files: [], + trees: [], + directories: [], + }); + f.repositories.push('arbitrary_override'); + await assert.rejects(collectBazelRecordedSourceInputs(f), IncompleteBazelRecordedInputsError); + }); +}); + +test('missing either lock or version pin rejects an incomplete basis', async () => { + for (const [file, kind] of [ + ['MODULE.bazel.lock', 'workspace lock'], + ['.bazelversion', 'version pin'], + ['hidden', 'hidden lock'], + ]) + await fixture(async (f) => { + rmSync( + file === 'hidden' + ? path.join(f.outputBase, 'MODULE.bazel.lock') + : path.join(f.workspaceRoot, file), + ); + await assert.rejects(collectBazelRecordedSourceInputs(f), { + name: 'IncompleteBazelRecordedInputsError', + message: `Missing or unreadable Bazel recorded source input: ${kind} (ENOENT)`, + }); + }); +}); + +test('unexpected I/O errors withhold raw messages and unapproved codes', async () => { + await fixture(async (f) => { + await assert.rejects( + collectBazelRecordedSourceInputs({ + ...f, + workspaceRoot: `${f.workspaceRoot}\0PRIVATE_PATH_VALUE`, + }), + { + name: 'IncompleteBazelRecordedInputsError', + message: 'Missing or unreadable Bazel recorded source input: version pin (UNKNOWN)', + }, + ); + }); +}); + +test('malformed records retain their decoding diagnostic without revealing values', async () => { + await fixture(async (f) => { + writeFileSync( + path.join(f.outputBase, 'MODULE.bazel.lock'), + '{"lockFileVersion":28,"moduleExtensions":{},"facts":{"PRIVATE_NAME":"PRIVATE_VALUE\\x"}}', + ); + await assert.rejects(collectBazelRecordedSourceInputs(f), { + name: 'IncompleteBazelRecordedInputsError', + message: 'Malformed Bazel lock escape', + }); + }); +}); + +test('wrong Bazel or lock formats cannot silently yield an empty basis', async () => { + await fixture(async (f) => { + writeFileSync(path.join(f.workspaceRoot, '.bazelversion'), '8.9.0\n'); + await assert.rejects(collectBazelRecordedSourceInputs(f), IncompleteBazelRecordedInputsError); + }); + for (const value of [27, '28', 28.0 + 0.01]) + await fixture(async (f) => { + f.hidden({ ...lock(), lockFileVersion: value }); + await assert.rejects(collectBazelRecordedSourceInputs(f), IncompleteBazelRecordedInputsError); + }); +}); + +test('malformed lock structures and missing extension records fail without exposing ignored data', async () => { + const malformed = [ + '{}', + '{"lockFileVersion":28}', + '{"lockFileVersion":28,"moduleExtensions":[]}', + '{"lockFileVersion":28,"moduleExtensions":{"//x:e.bzl%e":{"general":{}}}}', + '{"lockFileVersion":28,"moduleExtensions":{},"facts":{"secret":"\\x"}}', + '{"lockFileVersion":28,"moduleExtensions":{}} trailing', + '{"lockFileVersion":28,"moduleExtensions":{},"lockFileVersion":28}', + '{"lockFileVersion":28,"moduleExtensions":{"//x:e.bzl%e":{"unknown":{}}}}', + ]; + for (const value of malformed) + await fixture(async (f) => { + writeFileSync(path.join(f.outputBase, 'MODULE.bazel.lock'), value); + await assert.rejects(collectBazelRecordedSourceInputs(f), IncompleteBazelRecordedInputsError); + }); +}); + +test('malformed or unsupported recorded keys fail closed', async () => { + for (const key of [ + 'FILE://x', + 'FUTURE://x value', + 'FILE:relative value', + 'FILE://../escape value', + 'FILE:@@../x value', + 'FILE://x\\ value', + ]) + await fixture(async (f) => { + f.source(lock([key])); + await assert.rejects(collectBazelRecordedSourceInputs(f), IncompleteBazelRecordedInputsError); + }); +}); + +test('invalid marker headers and separators fail closed', async () => { + for (const content of ['', 'version:7\n', `${'a'.repeat(64)}\nFILE://input\n`]) + await fixture(async (f) => { + f.repositories = ['invalid+']; + writeFileSync(path.join(f.outputBase, 'external/@invalid+.marker'), content); + await assert.rejects(collectBazelRecordedSourceInputs(f), IncompleteBazelRecordedInputsError); + }); +}); + +test('Gson key escapes are decoded separately from recorded-key escapes', async () => { + await fixture(async (f) => { + const content = JSON.stringify(lock([record('FILE', '//src/a space é.txt')])); + writeFileSync(path.join(f.workspaceRoot, 'MODULE.bazel.lock'), content.replace('é', '\\u00e9')); + assert.deepEqual((await collectBazelRecordedSourceInputs(f)).files, ['src/a space é.txt']); + }); +}); + +test('reader never modifies source or output-base observations', async () => { + await fixture(async (f) => { + const source = readFileSync(path.join(f.workspaceRoot, 'MODULE.bazel.lock')); + const hidden = readFileSync(path.join(f.outputBase, 'MODULE.bazel.lock')); + await collectBazelRecordedSourceInputs(f); + assert.deepEqual(readFileSync(path.join(f.workspaceRoot, 'MODULE.bazel.lock')), source); + assert.deepEqual(readFileSync(path.join(f.outputBase, 'MODULE.bazel.lock')), hidden); + }); +}); + +test('seeded mixed acquisition observations preserve exact source union regardless of order', async () => { + let seed = 0x88128; + const random = () => { + seed = (Math.imul(seed, 1664525) + 1013904223) >>> 0; + return seed; + }; + for (let scenario = 0; scenario < 24; scenario++) + await fixture(async (f) => { + const expected = { + files: new Set(), + trees: new Set(), + directories: new Set(), + }; + const keys = ['FILE', 'DIRTREE', 'DIRENTS'] as const; + const groups = { + FILE: expected.files, + DIRTREE: expected.trees, + DIRENTS: expected.directories, + }; + const source: string[] = []; + const hidden: string[] = []; + const external: string[] = [record('FILE', '@@cycle+//unused')]; + f.marker('cycle+', [record('FILE', '@@acquisition+//cycle')]); + for (let i = 0; i < 32; i++) { + const kind = keys[random() % keys.length]; + const name = `source/${random() % 13} input`; + groups[kind].add(name); + [source, hidden, external][random() % 3].push( + record(kind, `@@//${name}`, `SYNTHETIC_VALUE_${random()}`), + ); + } + source.push( + record('FILE', '@@acquisition+//metadata'), + record('ENV', 'TOKEN', 'SYNTHETIC_SECRET'), + ); + f.source(lock(source.reverse())); + f.hidden(lock(hidden.reverse())); + f.marker('acquisition+', external.reverse()); + assert.deepEqual( + await collectBazelRecordedSourceInputs(f), + Object.fromEntries( + Object.entries(expected).map(([key, values]) => [key, [...values].sort()]), + ), + ); + }); +}); diff --git a/tools/ci/check-workflows.sh b/tools/ci/check-workflows.sh index 3e8559a17..936096860 100755 --- a/tools/ci/check-workflows.sh +++ b/tools/ci/check-workflows.sh @@ -33,7 +33,6 @@ run tools/dev/bun.sh tools/ci/workflow-security.mts run bash .github/scripts/check-ci-gate.test.sh run bash tools/dev/bun.sh test ./.github/scripts/resolve-mobile-e2e.test.mts run bash .github/scripts/run-moon-targets.test.sh -run bash .github/scripts/freeze-apple-carriers.test.sh graph_file="$(mktemp)" observations="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-ci-observations.XXXXXX")" trap 'rm -f "$graph_file"; rm -rf "$observations"' EXIT diff --git a/tools/ci/ci-gate.test.mts b/tools/ci/ci-gate.test.mts new file mode 100644 index 000000000..dd7be45bc --- /dev/null +++ b/tools/ci/ci-gate.test.mts @@ -0,0 +1,57 @@ +import assert from 'node:assert/strict'; +import path from 'node:path'; +import test from 'node:test'; + +const gate = path.resolve(import.meta.dir, '../../.github/scripts/check-ci-gate.mts'); + +function run(mode: string, needs: unknown, jobs: unknown) { + const result = Bun.spawnSync([process.execPath, '--no-install', '--no-env-file', gate, mode], { + env: { + NEEDS_JSON: JSON.stringify(needs), + SELECTED_JOBS_JSON: JSON.stringify(jobs), + REQUIRED_JOBS_JSON: JSON.stringify(jobs), + GATE_LABEL: 'source check gate', + }, + stdout: 'pipe', + stderr: 'pipe', + }); + return { + status: result.exitCode, + output: Buffer.concat([result.stdout, result.stderr]).toString(), + }; +} + +test('selected gate accepts an empty plan and deduplicates successful jobs', () => { + assert.equal(run('selected', {}, []).status, 0); + const result = run('selected', { android: { result: 'success' }, ios: { result: 'success' } }, [ + 'ios', + 'android', + 'ios', + ]); + assert.equal(result.status, 0); + assert.match(result.output, /passed: android, ios/u); +}); + +test('both gate modes reject missing, failed, cancelled and skipped selected jobs', () => { + for (const mode of ['selected', 'required']) { + for (const result of ['missing', 'failure', 'cancelled', 'skipped']) { + const observed = run(mode, result === 'missing' ? {} : { ios: { result } }, ['ios']); + assert.notEqual(observed.status, 0); + assert.match(observed.output, new RegExp(`ios=${result}`, 'u')); + } + } +}); + +test('CLI rejects malformed job and needs envelopes and unknown modes', () => { + for (const jobs of ['ios', [null], [42]]) { + const result = run('selected', {}, jobs); + assert.notEqual(result.status, 0); + assert.match(result.output, /must be a JSON string array/u); + } + const malformedNeeds = run('required', [], ['ios']); + assert.notEqual(malformedNeeds.status, 0); + assert.match(malformedNeeds.output, /must be a JSON object/u); + const unknown = run('allow-skipped', {}, []); + assert.notEqual(unknown.status, 0); + assert.match(unknown.output, /usage: check-ci-gate.mts/u); +}); diff --git a/tools/ci/ci-plan-node-products.test.mts b/tools/ci/ci-plan-node-products.test.mts index a13598c82..03e51199f 100644 --- a/tools/ci/ci-plan-node-products.test.mts +++ b/tools/ci/ci-plan-node-products.test.mts @@ -2,6 +2,7 @@ import assert from 'node:assert/strict'; import { test } from 'node:test'; import { loadExtensionTargetProfiles } from '../../src/extensions/contracts/extension-target-profiles.mts'; import { publishedConsumerDependencies } from '../../src/native/sdks/ts/tools/published-consumer.mts'; +import { resolvedAdapterRuntimeContract } from '../../src/wasix/node-addon/tools/workspace-runtime-contract.mts'; import { contribCarrierDescriptor, extensionProductForSqlName, @@ -666,29 +667,32 @@ test('combined JavaScript SDK and WASIX N-API changes release only changed produ assert.deepEqual(result.releaseProducts, ['oliphaunt-js', 'oliphaunt-wasix-napi']); }); -test('shared contrib source releases its runtime owners and the addon embedding WASIX payloads', () => { +test('shared contrib source releases its runtime owners while the addon retains its registry payloads', () => { const release = buildPlan( GRAPH, ['src/extensions/contrib/postgres18.toml'], 'ci-plan-node-products.test.mts', ); - assert.deepEqual(release.directProducts, [ - 'liboliphaunt-native', - 'liboliphaunt-wasix', - 'oliphaunt-wasix-napi', - ]); - assert.deepEqual(release.releaseProducts, [ - 'liboliphaunt-native', - 'liboliphaunt-wasix', - 'oliphaunt-wasix-napi', - ]); + assert.deepEqual(release.directProducts, ['liboliphaunt-native', 'liboliphaunt-wasix']); + assert.deepEqual(release.releaseProducts, ['liboliphaunt-native', 'liboliphaunt-wasix']); const plan = planForReleaseProducts(release.releaseProducts, 'c'.repeat(40)); const contrib = contribCarrierDescriptor(); assert(plan.extension_package_products.includes(contrib.artifactProduct)); assert(plan.tasks.includes('native-extension-lifecycle:lifecycle')); assert(plan.tasks.includes('extension-artifacts-wasix:build-target')); - assert(plan.tasks.includes('oliphaunt-wasix-napi:build-release-assets')); - assert(plan.tasks.includes('oliphaunt-wasix-napi:finalize-release-assets')); + assert.deepEqual(plan.qualification_products, release.releaseProducts); + const binding = plan.package_bindings.find( + ({ consumer, producer }) => + consumer === 'oliphaunt-wasix-napi' && producer === 'liboliphaunt-wasix', + ); + assert(binding, 'downstream addon qualification must retain its installed runtime binding'); + assert.equal(binding.producerVersion, resolvedAdapterRuntimeContract().runtimeVersion); + const adoption = buildPlan( + GRAPH, + ['src/wasix/node-addon/Cargo.toml', 'src/wasix/node-addon/Cargo.lock'], + 'ci-plan-node-products.test.mts', + ); + assert(adoption.directProducts.includes('oliphaunt-wasix-napi')); for (const sql of ['hstore', 'pg_trgm']) { assert(plan.native_extension_lifecycle_sql_names.includes(sql)); assert( @@ -767,6 +771,20 @@ test('packaging fixtures select their owner tests without artifact builders', () } }); +test('WASIX source lifecycle tracks the staged server manifest, README, code and nested tests', () => { + for (const file of [ + paths.wasixServerManifest, + paths.wasixServerReadme, + paths.wasixServerSource, + paths.wasixServerNestedTest, + ]) { + assert( + effects(file).directTasks.includes('oliphaunt-wasix-rust:test-regression'), + `${file} is staged by the source lifecycle`, + ); + } +}); + test('WASIX test helpers invalidate only tasks that execute them', () => { const result = effects(paths.runtimesLiboliphauntWasixToolsCargoTestFilterSh); for (const target of [ @@ -932,9 +950,8 @@ test('WASIX N-API production helpers keep the release builder affected', () => { } }); -test('CI planner changes select the focused graph proof', () => { +test('CI planner changes do not run release mutation tests', () => { const result = effects(paths.toolsGraphCiPlanMts); - assert.equal(result.tasks.includes('release-tools:graph-unit'), true); assert.equal(result.tasks.includes('release-tools:test'), false); }); @@ -945,7 +962,6 @@ test('release mutation tests follow release helpers, not policy or workflow file } const result = effects(paths.githubScriptsReleaseCandidateLibMts); assert.equal(result.tasks.includes('release-tools:test'), true); - assert.equal(result.tasks.includes('release-tools:graph-unit'), false); }); test('workflow changes run workflow checks without rebuilding product artifacts', () => { @@ -984,10 +1000,9 @@ test('release helper changes invalidate only their product artifacts', () => { ); }); -test('product Moon topology selects the focused release graph proof', () => { +test('product Moon topology preserves its consumer scope', () => { const result = effects(paths.sdksTsSdkMoonYml); assert.deepEqual(result.jobs, NATIVE_TS_CONSUMER_JOBS); - assert.equal(result.tasks.includes('release-tools:graph-unit'), true); assert.equal(result.tasks.includes('release-tools:test'), false); }); @@ -995,7 +1010,6 @@ test('JavaScript release metadata does not rebuild unrelated products', () => { const result = effects(paths.sdksTsSdkReleaseToml); assert.deepEqual(result.jobs, NATIVE_TS_CONSUMER_JOBS); assert.deepEqual(result.releaseProducts, ['oliphaunt-js']); - assert.equal(result.tasks.includes('release-tools:graph-unit'), true); assert.equal(result.tasks.includes('release-tools:metadata'), true); assert.equal(result.tasks.includes('release-tools:test'), false); assert.equal(result.tasks.includes('release-tools:version-pins-unit'), true); @@ -1016,7 +1030,6 @@ test('JavaScript release metadata does not rebuild unrelated products', () => { test('release-please bookkeeping does not rebuild product artifacts', () => { const result = effects(paths.releasePleaseManifestJson); assert.deepEqual(result.jobs, ['affected']); - assert.equal(result.tasks.includes('release-tools:graph-unit'), true); assert.equal(result.tasks.includes('release-tools:metadata'), true); assert.equal(result.tasks.includes('release-tools:test'), false); assert.equal(result.tasks.includes('release-tools:version-pins-unit'), true); diff --git a/tools/ci/ci-plan-test-inputs.mts b/tools/ci/ci-plan-test-inputs.mts index f286e2b76..65c377251 100644 --- a/tools/ci/ci-plan-test-inputs.mts +++ b/tools/ci/ci-plan-test-inputs.mts @@ -15,6 +15,10 @@ export const paths = { 'src/native/sdks/kotlin/oliphaunt/src/androidUnitTest/kotlin/dev/oliphaunt/NativeBindingsTest.kt', mobileBrokerRuntimeTests: 'src/native/sdks/rust/tests/mobile_broker.rs', wasixResourceRuntimeTests: 'src/wasix/sdks/rust/tests/resources.rs', + wasixServerManifest: 'src/wasix/pgwire-server/Cargo.toml', + wasixServerReadme: 'src/wasix/pgwire-server/README.md', + wasixServerSource: 'src/wasix/pgwire-server/src/lib.rs', + wasixServerNestedTest: 'src/wasix/pgwire-server/tests/support/mod.rs', wasixSdkReadme: 'src/wasix/sdks/ts/README.md', wasixRustReadme: 'src/wasix/sdks/rust/README.md', nativeRustReadme: 'src/native/sdks/rust/README.md', diff --git a/tools/ci/configured-scope.mts b/tools/ci/configured-scope.mts new file mode 100644 index 000000000..cec4e0b58 --- /dev/null +++ b/tools/ci/configured-scope.mts @@ -0,0 +1,1261 @@ +#!/usr/bin/env bun +import assert from 'node:assert/strict'; +import { execFileSync, spawnSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { + appendFileSync, + closeSync, + existsSync, + mkdirSync, + mkdtempSync, + openSync, + readdirSync, + readFileSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { parseArgs } from 'node:util'; +import { readPortableArchiveEntries } from '../packaging/portable-archive.mts'; +import { canonicalShippingLabel } from '../release/bazel-shipping-inputs.mts'; +import { + boundedResponseBytes, + latestGithubJob, + requestGithubDownload, + requestGithubPages, + requestGithubRepositoryJson, +} from '../release/github-read.mts'; +import { + assertNativeBuildGithub, + type NativeBuildEvidence, + type NativeBuildGithub, + type NativeBuildSource, + nativeBuildEventIndex as indexNativeBep, + nativeBuildMetadata, +} from '../release/native-build-qualification.mts'; +import { configuredRecipeGraph } from '../release/native-configured-inputs.mts'; +import { collectBazelRecordedSourceInputs } from './bazel-recorded-inputs.mts'; +import { + type NativeImportedRoot, + createNativeImportProjection, + isNativeImportSourceLabel, +} from './native-import-projection.mts'; + +type NativeOutputProjection = NativeImportedRoot & { + files: string[]; + importedRoots?: NativeImportedRoot[]; +}; +export type ConfiguredCiProjection = { + roots: { label: string; configuration: string }[]; + files: string[]; + trees: string[]; + directories: string[]; + analysisInputs: string[]; + importedRoots?: NativeImportedRoot[]; + nativeOutputs?: NativeOutputProjection[]; +}; +export type ConfiguredCiRequest = { + schema: 'oliphaunt-ci-request-v1'; + id: string; + job: string; + mode: 'full' | 'source'; + status: 'success'; + source: NativeBuildSource; + github: NativeBuildGithub; + requires: string[]; + fullOnly?: boolean; + projection?: ConfiguredCiProjection; +}; +export type ConfiguredCiBasis = { + schema: 'oliphaunt-ci-basis-v1'; + source: NativeBuildSource; + github: NativeBuildGithub; + controllerInputs: string[]; + requests: ConfiguredCiRequest[]; +}; +export type ConfiguredCiPlan = { + schema: 'oliphaunt-ci-plan-v1'; + mode: 'full' | 'source'; + source: NativeBuildSource; + basisSource?: NativeBuildSource; + basisDigest?: string; + selected_requests: string[]; + selected_jobs: string[]; + capture_requests: string[]; +}; +type RequestIdentity = { id: string; job: string; requires: string[]; fullOnly?: boolean }; +type SourceChange = { path: string; kind: string; oldMode?: string; newMode?: string }; +const WORKFLOW = '.github/workflows/bazel.yml'; +const SHA = /^[a-f0-9]{40}$/u; +const CONFIG = /^[a-f0-9]{64}$/u; +const ordered = (values: Iterable) => [...new Set(values)].sort(); +const json = (file: string) => JSON.parse(readFileSync(file, 'utf8')); +const digest = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +const importedRootKey = (value: NativeImportedRoot) => + JSON.stringify([ + value.root, + value.configuration, + value.evidenceDigest, + value.invocationId, + value.output, + ]); +const orderedImportedRoots = (values: T[]): T[] => + [...new Map(values.map((value) => [importedRootKey(value), value])).entries()] + .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)) + .map(([, value]) => value); +const requestIdentity = ({ id, job, requires, fullOnly }: RequestIdentity) => ({ + id, + job, + requires, + fullOnly: fullOnly === true, +}); + +function fullOnlyAnnotation(value: unknown) { + assert( + value === undefined || value === 'true' || value === 'false', + 'CI full-only annotation is invalid', + ); + return value === 'true'; +} + +function identity(value: string) { + assert( + typeof value === 'string' && /^[a-z0-9][a-z0-9_./-]*$/u.test(value), + 'CI request identity is invalid', + ); + assert( + !value.split('/').some((part) => !part || part === '.' || part === '..'), + 'CI request identity escapes', + ); + return value; +} +function sourcePath(value: string, root = false) { + assert(typeof value === 'string' && (root || value.length > 0), 'CI source path is missing'); + assert( + !path.posix.isAbsolute(value) && !/[\\\u0000-\u001f\u007f]/u.test(value), + 'CI source path is invalid', + ); + assert( + value === '' || !value.split('/').some((part) => !part || part === '.' || part === '..'), + 'CI source path escapes', + ); + return value; +} +function workspacePath(label: string) { + label = canonicalShippingLabel(label); + if (!label.startsWith('//')) return undefined; + const separator = label.indexOf(':'); + assert(separator >= 2, 'CI source label is not explicit'); + return sourcePath( + [label.slice(2, separator), label.slice(separator + 1)].filter(Boolean).join('/'), + ); +} +function explicitTarget(value: string) { + value = canonicalShippingLabel(value); + assert(/^(?:@@?[^/]+)?\/\/[^\s:]*:[^\s]+$/u.test(value), 'CI target is not an explicit label'); + return value; +} +function repository(label: string) { + if (label.startsWith('//')) return undefined; + const match = /^@@([^/]+)\/\//u.exec(label); + assert(match, 'CI acquisition requires canonical external labels'); + return match[1]; +} +function git(root: string, ...args: string[]) { + return execFileSync('git', args, { cwd: root, encoding: 'utf8', maxBuffer: 16 * 1024 * 1024 }); +} +function currentSource(root: string): NativeBuildSource { + return { + commit: git(root, 'rev-parse', 'HEAD^{commit}').trim(), + tree: git(root, 'rev-parse', 'HEAD^{tree}').trim(), + }; +} +function validSource(source: NativeBuildSource) { + assert(SHA.test(source?.commit) && SHA.test(source?.tree), 'CI source identity is invalid'); +} + +/** Reuse the existing source replay guard, including index suppression checks. */ +export function assertConfiguredCiSource(workspaceRoot: string, source: NativeBuildSource) { + validSource(source); + execFileSync( + 'bash', + ['tools/release/qualified-release-replay.sh', source.commit, source.commit], + { + cwd: workspaceRoot, + stdio: ['ignore', 'ignore', 'pipe'], + }, + ); + assert.deepEqual(currentSource(workspaceRoot), source, 'CI source changed during execution'); +} + +type CiSuccess = { + id: string; + job: string; + source: NativeBuildSource; + github: NativeBuildGithub; + requires?: string[]; + fullOnly?: boolean; + outputDirectory: string; + workspaceRoot?: string; +}; +function successRecord(request: CiSuccess, mode: 'full' | 'source'): ConfiguredCiRequest { + validSource(request.source); + assertNativeBuildGithub(request.github); + const fullOnly = request.fullOnly ?? fullOnlyAnnotation(process.env.CI_FULL_ONLY); + assert(!fullOnly || mode === 'full', 'full-only CI request cannot emit a source receipt'); + return { + schema: 'oliphaunt-ci-request-v1', + id: identity(request.id), + job: identity(request.job), + mode, + status: 'success', + source: request.source, + github: request.github, + requires: ordered((request.requires ?? []).map(identity)), + ...(fullOnly ? { fullOnly: true } : {}), + }; +} +function writeReceipt(request: CiSuccess, record: ConfiguredCiRequest) { + assertConfiguredCiSource(request.workspaceRoot ?? process.cwd(), request.source); + mkdirSync(request.outputDirectory, { recursive: true }); + const file = path.join(request.outputDirectory, 'ci-request.json'); + writeFileSync(file, `${JSON.stringify(record)}\n`, { flag: 'wx', mode: 0o600 }); + return file; +} +export function writeConfiguredCiSuccessReceipt(request: CiSuccess) { + return writeReceipt(request, successRecord(request, 'source')); +} + +type RecipeQuery = { packages: string[]; labels: string[] }; +export type ConfiguredCiCapture = CiSuccess & { + configuration: string[]; + startup: string[]; + requestedTargets: string[]; + completedRoots: { label: string; configuration: string }[]; + executionRoot: string; + /** Existing qualifier supplies the same post-build query after update-mode persistence. */ + configuredGraph?: unknown; + recipeQueries?: RecipeQuery[]; + /** Original serialized shipping packet produced by this qualifier invocation. */ + nativeEvidence?: string; +}; + +/** Complete source-only projection; no action command lines or environments are serialized. */ +export async function captureConfiguredCiRequest( + request: ConfiguredCiCapture, + execution?: { + bazel(args: string[], stdout: string): Promise; + assertRunning(): void; + }, +) { + execution?.assertRunning(); + const root = request.workspaceRoot ?? process.cwd(); + assertConfiguredCiSource(root, request.source); + const roots = request.completedRoots.map((value) => { + assert(CONFIG.test(value.configuration), 'CI completion lacks a pinned configuration checksum'); + // Pinned BEP Label.toString uses canonical single-@; consistent cquery uses @@. + const label = explicitTarget(value.label).replace(/^@(?=[^@])/u, '@@'); + return { label, configuration: value.configuration }; + }); + assert( + roots.length && + new Set(roots.map((value) => `${value.label}\0${value.configuration}`)).size === roots.length, + 'CI actual completions are missing or duplicated', + ); + const output = path.resolve(request.outputDirectory); + mkdirSync(output, { recursive: true }); + const sourceLock = readFileSync(path.join(root, 'MODULE.bazel.lock')); + const run = async (args: string[]) => { + execution?.assertRunning(); + const temporary = mkdtempSync(path.join(output, '.query-')); + const stdout = path.join(temporary, 'stdout'); + let descriptor: number | undefined; + try { + if (execution) await execution.bazel(args, stdout); + else { + descriptor = openSync(stdout, 'wx', 0o600); + const result = spawnSync('bash', ['tools/dev/bazel.sh', ...request.startup, ...args], { + cwd: root, + stdio: ['ignore', descriptor, 'inherit'], + }); + if (result.error) throw result.error; + if (result.status !== 0) + throw new Error(`CI ${args[0]} failed (${result.signal ?? result.status})`); + } + execution?.assertRunning(); + return readFileSync(stdout, 'utf8'); + } finally { + if (descriptor !== undefined) closeSync(descriptor); + rmSync(temporary, { recursive: true, force: true }); + } + }; + const expression = (names: string[]) => + `set(${ordered(names) + .map((name) => JSON.stringify(name)) + .join(' ')})`; + const queryFile = (name: string, value: string) => { + const file = path.join(output, name); + writeFileSync(file, value, { flag: 'wx' }); + return `--query_file=${file}`; + }; + const raw = + request.configuredGraph ?? + JSON.parse( + await run([ + 'cquery', + queryFile('analysis-deps.query', `deps(${expression(roots.map((value) => value.label))})`), + ...request.configuration, + '--lockfile_mode=update', + '--output=jsonproto', + '--consistent_labels', + '--transitions=lite', + '--proto:include_configurations', + '--proto:output_rule_attrs=', + ]), + ); + assert( + sourceLock.equals(readFileSync(path.join(root, 'MODULE.bazel.lock'))), + 'CI projection changed the tracked module lock', + ); + const graph = configuredRecipeGraph( + raw, + roots, + true, + request.nativeEvidence + ? (name) => name.startsWith('//') || isNativeImportSourceLabel(name) + : undefined, + ); + const sources = new Set(); + const sourceLabels: string[] = []; + const reachable = new Set(graph.labels); + for (const entry of (raw as { results: any[] }).results) { + const name = entry.target?.sourceFile?.name; + if (typeof name !== 'string' || !reachable.has(canonicalShippingLabel(name))) continue; + if (isNativeImportSourceLabel(name)) sourceLabels.push(canonicalShippingLabel(name)); + const file = workspacePath(name); + if (file !== undefined) sources.add(file); + } + const loaded = ordered((request.recipeQueries ?? []).flatMap((query) => query.labels)); + const coveredPackages = new Set((request.recipeQueries ?? []).flatMap((query) => query.packages)); + const representatives = graph.packages + .filter((row) => !coveredPackages.has(row.package)) + .map((row) => row.label); + for (const target of request.requestedTargets) { + const name = explicitTarget(target); + const pkg = name.slice(0, name.indexOf(':')); + if (!coveredPackages.has(pkg)) representatives.push(name); + } + if (representatives.length) { + const loading = request.configuration.filter((flag) => + /^--(?:lockfile_mode|enable_bzlmod|repo_env|override_repository|repository_cache|registry)(?:=|$)/u.test( + flag, + ), + ); + loaded.push( + ...( + await run([ + 'query', + queryFile('analysis-buildfiles.query', `buildfiles(${expression(representatives)})`), + ...loading, + '--consistent_labels', + '--output=label', + ]) + ) + .split(/\r?\n/u) + .filter(Boolean), + ); + } + const recipes = ordered(loaded.map(canonicalShippingLabel)); + for (const row of graph.packages.filter((row) => row.package.startsWith('//'))) { + assert( + recipes.filter( + (name) => name === `${row.package}:BUILD` || name === `${row.package}:BUILD.bazel`, + ).length === 1, + 'CI package BUILD source is missing or ambiguous', + ); + } + const analysisInputs = ordered( + recipes.flatMap((name) => { + const file = workspacePath(name); + return file === undefined ? [] : [file]; + }), + ); + assert(analysisInputs.length, 'CI loaded recipe inputs are missing'); + const repositories = ordered( + [...graph.labels, ...recipes].flatMap((name) => { + const repo = repository(name); + return repo === undefined ? [] : [repo]; + }), + ); + const executionRoot = path.resolve(request.executionRoot); + assert( + path.basename(path.dirname(executionRoot)) === 'execroot', + 'CI execution root has no pinned output-base layout', + ); + const outputBase = path.dirname(path.dirname(executionRoot)); + const recorded = await collectBazelRecordedSourceInputs({ + workspaceRoot: root, + outputBase, + repositories, + }); + execution?.assertRunning(); + const snapshotFile = process.env.OLIPHAUNT_NATIVE_PUBLICATION_INPUTS; + const wasixCargoInputs = request.configuration + .filter((flag) => flag.startsWith('--repo_env=OLIPHAUNT_WASIX_CARGO_INPUTS=')) + .map((flag) => flag.slice('--repo_env=OLIPHAUNT_WASIX_CARGO_INPUTS='.length)); + assert(wasixCargoInputs.length <= 1, 'CI WASIX Cargo input configuration is ambiguous'); + const snapshot = snapshotFile ? json(snapshotFile) : { source: request.source }; + const projectImports = createNativeImportProjection({ + snapshot, + source: request.source, + executionRoot, + wasixCargoInputs: wasixCargoInputs[0], + }); + const importScopes = new Map(); + const importsOf = (labels: string[]) => { + const external = ordered(labels.filter(isNativeImportSourceLabel)); + const key = JSON.stringify(external); + if (!importScopes.has(key)) importScopes.set(key, projectImports(external)); + return importScopes.get(key)!; + }; + const importedRoots = graph.sourceRoots + ? orderedImportedRoots(graph.sourceRoots.flatMap((scope) => importsOf(scope.labels))) + : importsOf(sourceLabels); + const nativeOutputs: NativeOutputProjection[] = []; + if (request.nativeEvidence) { + const bytes = readFileSync(request.nativeEvidence); + const evidenceDigest = `sha256:${digest(bytes)}`; + const evidence = JSON.parse( + new TextDecoder('utf-8', { fatal: true }).decode(bytes), + ) as NativeBuildEvidence; + assert( + evidence.schema === 'oliphaunt-native-build-evidence-v1' && + Array.isArray(evidence.cohorts) && + evidence.cohorts.length, + 'CI original native evidence schema differs', + ); + assert.deepEqual(evidence.source, request.source, 'CI original native evidence source differs'); + assert.deepEqual( + evidence.github, + request.github, + 'CI original native evidence context differs', + ); + const bazelVersion = readFileSync(path.join(root, '.bazelversion'), 'utf8').trim(); + const metadata = nativeBuildMetadata(request.source, request.github); + for (const cohort of evidence.cohorts) { + const bep = indexNativeBep(cohort, bazelVersion, metadata); + for (const producingRoot of cohort.roots) { + const label = explicitTarget(producingRoot.label); + const configurations = cohort.rootConfigurations.filter( + (value) => explicitTarget(value.label) === label, + ); + assert.equal( + configurations.length, + 1, + 'CI original native root configuration is ambiguous', + ); + const configuration = configurations[0].configuration; + assert( + CONFIG.test(configuration) && bep.configs.has(configuration), + 'CI original native root configuration is missing', + ); + const completed = bep.completed.filter( + (value) => + explicitTarget(value.label) === label && + value.configuration === configuration && + value.value.success === true, + ); + assert.equal(completed.length, 1, 'CI original native root did not complete successfully'); + const completedFiles = bep.filesOf(completed[0].value, 'default'); + let completedFileCount = 0; + for (const output of producingRoot.package.outputs) { + assert( + roots.some((value) => value.label === label && value.configuration === configuration), + 'CI original native evidence root is outside this request', + ); + const scopes = graph.sourceRoots!.filter( + (scope) => scope.label === label && scope.configuration === configuration, + ); + assert.equal( + scopes.length, + 1, + 'CI original native evidence lacks its configured source scope', + ); + sourcePath(output.path); + const captures = cohort.outputs.filter((value) => value.path === output.path); + assert.equal( + captures.length, + 1, + 'CI original native output capture is missing or ambiguous', + ); + const members = captures[0].members.filter((member) => member.type === 'file'); + if (!members.length) continue; + for (const member of members) { + const file = member.path ? `${output.path}/${sourcePath(member.path)}` : output.path; + assert( + /^[a-f0-9]{64}$/u.test(member.sha256) && + Number.isSafeInteger(member.size) && + member.size >= 0, + 'CI original native output File identity is invalid', + ); + assert.deepEqual( + completedFiles.get(file), + { size: member.size, sha256: member.sha256 }, + 'CI original native output File is absent from its completion', + ); + } + completedFileCount += members.length; + const imports = importsOf(scopes[0].labels); + nativeOutputs.push({ + root: label, + configuration, + evidenceDigest, + invocationId: bep.invocationId, + output: output.path, + files: ordered([ + ...recorded.files, + ...scopes[0].labels.flatMap((name) => { + const file = workspacePath(name); + return file === undefined ? [] : [file]; + }), + ]), + ...(imports.length ? { importedRoots: imports } : {}), + }); + } + assert( + completedFileCount, + `CI original native root ${label} (${configuration}) has no completed File: ${producingRoot.package.outputs.map((output) => output.path).join(', ')}`, + ); + } + } + } + const record = successRecord(request, 'full'); + record.projection = { + roots, + files: ordered([...sources, ...recorded.files]), + trees: recorded.trees, + directories: recorded.directories, + analysisInputs, + ...(importedRoots.length ? { importedRoots } : {}), + ...(nativeOutputs.length ? { nativeOutputs: orderedImportedRoots(nativeOutputs) } : {}), + }; + execution?.assertRunning(); + return writeReceipt(request, record); +} + +function validateRequest(record: ConfiguredCiRequest, full: boolean) { + assert( + record?.schema === 'oliphaunt-ci-request-v1' && + record.status === 'success' && + ['full', 'source'].includes(record.mode), + 'CI request did not complete successfully', + ); + identity(record.id); + identity(record.job); + assert( + record.fullOnly === undefined || typeof record.fullOnly === 'boolean', + 'CI full-only policy is invalid', + ); + validSource(record.source); + assertNativeBuildGithub(record.github); + assert( + Array.isArray(record.requires) && + JSON.stringify(record.requires) === JSON.stringify(ordered(record.requires.map(identity))), + 'CI transport prerequisites are ambiguous', + ); + if (!full) return; + assert(record.mode === 'full' && record.projection, 'full CI request has no complete projection'); + for (const field of ['files', 'analysisInputs', 'trees', 'directories'] as const) { + const values = record.projection[field]; + assert( + Array.isArray(values) && + JSON.stringify(values) === + JSON.stringify( + ordered( + values.map((name) => sourcePath(name, field === 'trees' || field === 'directories')), + ), + ), + 'CI projection input set is malformed', + ); + } + assert( + record.projection.roots.length && + record.projection.roots.every( + (row) => CONFIG.test(row.configuration) && explicitTarget(row.label), + ), + 'CI projection roots are missing', + ); + const validateRoots = (values: NativeImportedRoot[]) => { + assert(Array.isArray(values), 'CI native source lineage is malformed'); + for (const value of values) { + assert.deepEqual(Object.keys(value).sort(), [ + 'configuration', + 'evidenceDigest', + 'invocationId', + 'output', + 'root', + ]); + explicitTarget(value.root); + assert(CONFIG.test(value.configuration), 'CI native source lineage configuration is invalid'); + assert( + /^sha256:[a-f0-9]{64}$/u.test(value.evidenceDigest), + 'CI native source lineage evidence is invalid', + ); + assert( + typeof value.invocationId === 'string' && + value.invocationId.length && + !/[\u0000-\u001f\u007f]/u.test(value.invocationId), + 'CI native source lineage invocation is invalid', + ); + sourcePath(value.output); + } + assert.deepEqual(values, orderedImportedRoots(values), 'CI native source lineage is ambiguous'); + }; + for (const field of ['importedRoots', 'nativeOutputs'] as const) { + const values = record.projection[field]; + if (values === undefined) continue; + assert(Array.isArray(values), 'CI native source lineage is malformed'); + if (field === 'importedRoots') validateRoots(values); + else + for (const value of record.projection.nativeOutputs!) { + const { files, importedRoots, ...proof } = value; + validateRoots([proof]); + assert(Array.isArray(files), 'CI native producer source scope is missing'); + assert.deepEqual( + files, + ordered(files.map((file) => sourcePath(file))), + 'CI native producer source scope is malformed', + ); + if (importedRoots !== undefined) validateRoots(importedRoots); + assert( + record.projection.roots.some( + (root) => root.label === value.root && root.configuration === value.configuration, + ), + 'CI native producer proof root is outside this request', + ); + } + assert.deepEqual(values, orderedImportedRoots(values), 'CI native source lineage is ambiguous'); + } +} + +/** Join semantic source inputs through exact original producer proofs, never transport prerequisites. */ +export function joinConfiguredCiProjections( + records: ConfiguredCiRequest[], + source: NativeBuildSource, +) { + const producers = new Map< + string, + { record: ConfiguredCiRequest; output: NativeOutputProjection }[] + >(); + for (const record of records) { + validateRequest(record, true); + assert.deepEqual(record.source, source, 'CI native source lineage producer source differs'); + for (const proof of record.projection!.nativeOutputs ?? []) { + const key = importedRootKey(proof); + producers.set(key, [...(producers.get(key) ?? []), { record, output: proof }]); + } + } + type Inputs = Pick; + const resolved = new Map(); + const active = new Set(); + const visit = (record: ConfiguredCiRequest, output?: NativeOutputProjection): Inputs => { + const projection = record.projection!; + const scope = output ?? projection; + if (resolved.has(scope)) return resolved.get(scope)!; + assert(!active.has(scope), 'cycle in CI native source lineage'); + active.add(scope); + const inherited = (scope.importedRoots ?? []).map((proof) => { + const matches = producers.get(importedRootKey(proof)) ?? []; + assert.equal(matches.length, 1, 'CI native source lineage lacks one exact original producer'); + return visit(matches[0].record, matches[0].output); + }); + const joined: Inputs = { ...projection, files: scope.files }; + for (const field of ['files', 'trees', 'directories', 'analysisInputs'] as const) + joined[field] = ordered([joined, ...inherited].flatMap((value) => value[field])); + active.delete(scope); + resolved.set(scope, joined); + return joined; + }; + return records.map((record) => ({ + ...record, + projection: { ...record.projection!, ...visit(record) }, + })); +} +function requestClosure(requests: RequestIdentity[], selected: Iterable) { + const byId = new Map(requests.map((value) => [identity(value.id), value])); + assert(byId.size === requests.length, 'CI request inventory contains duplicate IDs'); + const complete = new Set(); + const active = new Set(); + const capture = new Set(); + const visit = (id: string) => { + assert(byId.has(id), 'CI transport prerequisite is missing'); + assert(!active.has(id), 'cycle in CI transport prerequisites'); + if (complete.has(id)) return; + active.add(id); + for (const dep of byId.get(id)!.requires) { + capture.add(dep); + visit(dep); + } + active.delete(id); + complete.add(id); + }; + for (const request of requests) { + visit(request.id); + } + complete.clear(); + capture.clear(); + for (const id of selected) visit(id); + return { selected: ordered(complete), capture: ordered(capture) }; +} +function structural(file: string) { + const name = path.posix.basename(file); + return ( + file.startsWith('.github/') || + /(?:^|\/)BUILD(?:\.bazel)?$/u.test(file) || + file.endsWith('.bzl') || + /^(?:MODULE\.bazel(?:\.lock)?|WORKSPACE(?:\.bazel)?|\.bazel(?:rc|version|ignore)|\.git(?:attributes|ignore|modules)|Cargo\.lock|bun\.lock|package-lock\.json|yarn\.lock|pnpm-lock\.yaml)$/u.test( + name, + ) + ); +} +/** Baseline is acquired/authenticated separately; this function never grants publication authority. */ +export function selectConfiguredCiRequests(args: { + source: NativeBuildSource; + requests: RequestIdentity[]; + changes: SourceChange[]; + basis?: ConfiguredCiBasis; + full?: boolean; +}): ConfiguredCiPlan { + validSource(args.source); + const inventory = args.requests; + const full = () => { + const closed = requestClosure( + inventory, + inventory.map((request) => request.id), + ); + return { + schema: 'oliphaunt-ci-plan-v1' as const, + mode: 'full' as const, + source: args.source, + selected_requests: closed.selected, + selected_jobs: ordered(inventory.map((value) => value.job)), + capture_requests: closed.capture, + }; + }; + if (args.full || !args.basis) return full(); + const basis = args.basis; + if ( + args.changes.some( + (change) => + change.kind !== 'modified' || + change.oldMode !== change.newMode || + !['100644', '100755'].includes(change.oldMode ?? '') || + structural(change.path), + ) + ) + return full(); + let projections: ConfiguredCiRequest[]; + try { + assert(basis.schema === 'oliphaunt-ci-basis-v1', 'CI basis schema differs'); + validSource(basis.source); + assert(Array.isArray(basis.controllerInputs), 'CI basis controller context is missing'); + assert.deepEqual( + basis.requests.map(requestIdentity).sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)), + inventory.map(requestIdentity).sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)), + 'CI basis request inventory differs', + ); + projections = joinConfiguredCiProjections(basis.requests, basis.source); + } catch { + return full(); + } + if (args.changes.some((change) => basis.controllerInputs.includes(change.path))) return full(); + const changed = args.changes.map((value) => sourcePath(value.path)); + const selected = projections + .filter((request) => !request.fullOnly) + .filter((request) => { + const scope = request.projection!; + const files = new Set([...scope.files, ...scope.analysisInputs]); + return changed.some( + (file) => + files.has(file) || + scope.trees.some((tree) => tree === '' || file === tree || file.startsWith(`${tree}/`)), + ); + }) + .map((value) => value.id); + const closed = requestClosure(inventory, selected); + if (inventory.some((request) => request.fullOnly && closed.selected.includes(request.id))) + return full(); + const selectedSet = new Set(closed.selected); + return { + schema: 'oliphaunt-ci-plan-v1', + mode: 'source', + source: args.source, + basisSource: basis.source, + selected_requests: closed.selected, + selected_jobs: ordered( + inventory.filter((request) => selectedSet.has(request.id)).map((value) => value.job), + ), + capture_requests: closed.capture, + }; +} + +/** Inventory annotations belong to existing executable workflow steps, not product ownership. */ +export function configuredCiWorkflowInventory(workflow: any) { + const matrices = JSON.parse(workflow.env.CI_FULL_MATRICES ?? '{}'); + const requests: RequestIdentity[] = []; + for (const [job, value] of Object.entries(workflow.jobs) as [string, any][]) { + for (const matrix of matrices[job] ?? [{}]) { + const substitute = (text: string) => + text.replace(/\$\{\{\s*matrix\.([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}/gu, (_all, key) => { + assert(typeof matrix[key] === 'string', 'CI matrix field is missing'); + return matrix[key]; + }); + const matrixValue = matrix.platform ?? matrix.arch; + const jobKey = matrixValue === undefined ? job : `${job}/${matrixValue}`; + for (const step of value.steps ?? []) { + const annotation = + step.env?.CI_REQUEST_IDS ?? + (step.env?.CI_REQUEST_ID ? JSON.stringify([step.env.CI_REQUEST_ID]) : undefined); + if (annotation === undefined) continue; + const declared = JSON.parse(substitute(annotation)); + const ids = Array.isArray(declared) ? declared : (declared[matrixValue] ?? []); + const requires = JSON.parse(substitute(step.env?.CI_REQUIRES ?? '[]')); + const fullOnly = fullOnlyAnnotation(step.env?.CI_FULL_ONLY); + assert( + Array.isArray(ids) && Array.isArray(requires), + 'CI workflow request annotation is missing', + ); + for (const id of ids) + requests.push({ + id: identity(id), + job: identity(jobKey), + requires: ordered(requires.map(identity)), + ...(fullOnly ? { fullOnly: true } : {}), + }); + } + } + } + requests.sort((a, b) => a.id.localeCompare(b.id)); + assert(requests.length, 'CI workflow request inventory is missing'); + requestClosure(requests, []); + return { requests, matrices }; +} + +export function verifyConfiguredCiResults( + plan: ConfiguredCiPlan, + records: ConfiguredCiRequest[], + requiredResult: string, + github: NativeBuildGithub, + inventory: RequestIdentity[], +) { + validSource(plan.source); + assertNativeBuildGithub(github); + assert(plan.schema === 'oliphaunt-ci-plan-v1', 'CI plan schema differs'); + if (plan.mode === 'full') + assert(requiredResult === 'success', 'complete Required qualification did not pass'); + const ids = records.map((record) => record.id).sort(); + assert.deepEqual( + ids, + [...plan.selected_requests].sort(), + 'selected CI request receipts are missing or duplicated', + ); + for (const record of records) { + validateRequest(record, plan.mode === 'full'); + const declared = inventory.find((request) => request.id === record.id); + assert(declared && declared.job === record.job, 'CI request receipt job differs'); + assert.deepEqual( + record.requires, + declared.requires, + 'CI request receipt transport prerequisites differ', + ); + assert.equal( + record.fullOnly === true, + declared.fullOnly === true, + 'CI request receipt full-only policy differs', + ); + assert(plan.mode === 'full' || !declared.fullOnly, 'source CI selected a full-only request'); + assert.deepEqual(record.source, plan.source, 'CI request receipt source differs'); + for (const key of ['repository', 'workflow', 'workflowPath', 'runId'] as const) + assert(record.github[key] === github[key], 'CI request receipt producer context differs'); + assert( + record.github.runAttempt <= github.runAttempt, + 'CI request receipt producer attempt is newer than the observer', + ); + } + if (plan.mode === 'full') joinConfiguredCiProjections(records, plan.source); +} + +/** Recompute selected work and every omission from the same transported admitted basis. */ +export function verifyConfiguredCiDecision( + plan: ConfiguredCiPlan, + args: { + source: NativeBuildSource; + requests: RequestIdentity[]; + changes: SourceChange[]; + basis?: ConfiguredCiBasis; + }, +) { + assert(['full', 'source'].includes(plan.mode), 'CI plan mode is invalid'); + assert.deepEqual(plan.source, args.source, 'CI plan source differs'); + const expected = selectConfiguredCiRequests({ ...args, full: plan.mode === 'full' }); + assert.deepEqual( + { ...plan, basisDigest: undefined }, + { ...expected, basisDigest: undefined }, + 'CI selected requests or omissions differ from the admitted decision', + ); +} + +function controllerInputs(root: string) { + const pending = [ + 'tools/ci/configured-scope.mts', + 'tools/ci/run-configured-request.mts', + 'tools/release/qualify-native-shipping.mts', + 'tools/bazel/tests/conformance.mts', + 'build_defs/host/sdk-tree-conformance.mts', + 'src/docs/tools/verify-live.mts', + 'tools/release/native-release-inputs.mts', + 'tools/release/native-release-preparation.mts', + 'build_defs/wasix/browser/chrome-receipt.mts', + ]; + const files = new Set([ + WORKFLOW, + '.bazelversion', + '.bazelrc', + 'tools/dev/bazel.sh', + '.prototools', + 'src/database-resources/contracts/contract.json', + 'tools/dev/bazel-checksums.tsv', + 'tools/dev/acquisition.sh', + 'tools/dev/bun.sh', + 'tools/dev/bun.toml', + 'tools/dev/install-pinned-js-runtime.sh', + 'tools/dev/extract-pinned-binary.sh', + 'tools/dev/curl-platform-flags.sh', + 'tools/release/with-source.sh', + 'tools/release/qualified-release-replay.sh', + ]); + const scanner = new Bun.Transpiler({ loader: 'ts' }); + while (pending.length) { + const file = pending.pop()!; + if (files.has(file)) continue; + files.add(sourcePath(file)); + const source = readFileSync(path.join(root, file), 'utf8').replace( + /^#![^\r\n]*(?:\r?\n|$)/u, + '\n', + ); + for (const entry of scanner.scanImports(source)) { + if (!entry.path.startsWith('.')) continue; // Tool/package bytes have pinned acquisition context. + pending.push( + sourcePath(path.posix.normalize(path.posix.join(path.posix.dirname(file), entry.path))), + ); + } + } + return ordered(files); +} +export function configuredCiSourceChanges( + root: string, + from: NativeBuildSource, + to: NativeBuildSource, +): SourceChange[] { + validSource(from); + validSource(to); + const fields = git(root, 'diff', '--raw', '-z', '--no-renames', from.tree, to.tree).split('\0'); + if (fields.at(-1) === '') fields.pop(); + assert(fields.length % 2 === 0, 'CI Git delta is incomplete'); + const changes: SourceChange[] = []; + for (let index = 0; index < fields.length; index += 2) { + const match = /^:([0-9]{6}) ([0-9]{6}) [a-f0-9]+ [a-f0-9]+ ([A-Z])$/u.exec(fields[index]); + assert(match, 'CI Git delta has an unsupported shape'); + changes.push({ + path: fields[index + 1], + oldMode: match[1], + newMode: match[2], + kind: match[3] === 'M' ? 'modified' : match[3], + }); + } + return changes; +} +function basisIdentity(basis: ConfiguredCiBasis, run: any, jobs: any[], root: string) { + assert(basis.schema === 'oliphaunt-ci-basis-v1', 'CI basis schema differs'); + validSource(basis.source); + assertNativeBuildGithub(basis.github); + assert( + run.status === 'completed' && + run.conclusion === 'success' && + ['push', 'workflow_dispatch'].includes(run.event) && + run.head_branch === 'main' && + run.path === WORKFLOW, + 'CI basis did not come from a completed main workflow', + ); + const required = latestGithubJob({ runAttempt: run.run_attempt, jobs }, 'Required'); + assert( + required?.status === 'completed' && + required.conclusion === 'success' && + required.run_attempt === run.run_attempt, + 'CI basis has no successful complete Required gate', + ); + assert( + basis.source.commit === run.head_sha && + basis.github.runId === run.id && + basis.github.runAttempt === run.run_attempt && + basis.github.workflowPath === WORKFLOW && + basis.github.workflow === 'Native Bazel qualification', + 'CI basis run/source identity differs', + ); + assert( + git(root, 'rev-parse', `${basis.source.commit}^{tree}`).trim() === basis.source.tree, + 'CI basis Git tree differs', + ); + assert( + Array.isArray(basis.controllerInputs) && + basis.controllerInputs.length && + JSON.stringify(basis.controllerInputs) === + JSON.stringify(ordered(basis.controllerInputs.map((name) => sourcePath(name)))), + 'CI basis controller inputs are incomplete', + ); + assert( + Array.isArray(basis.requests) && basis.requests.length, + 'CI basis request inventory is missing', + ); + for (const request of basis.requests) { + validateRequest(request, true); + assert.deepEqual(request.source, basis.source, 'CI basis request source differs'); + for (const key of ['repository', 'workflow', 'workflowPath', 'runId'] as const) + assert(request.github[key] === basis.github[key], 'CI basis request origin differs'); + assert( + request.github.runAttempt <= basis.github.runAttempt, + 'CI basis request producer attempt is newer than the basis', + ); + } + requestClosure(basis.requests, []); + joinConfiguredCiProjections(basis.requests, basis.source); +} + +/** Only the immutable artifact of an authenticated successful full main run is a basis. */ +export async function acquireConfiguredCiBasis( + root: string, + repositoryName: string, + io = { + read: requestGithubRepositoryJson, + pages: requestGithubPages, + download: requestGithubDownload, + }, +) { + assert( + /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u.test(repositoryName), + 'CI repository name is invalid', + ); + const api = `repos/${repositoryName}/actions`; + // Named artifact lookup does not lose the baseline after many scoped successes. + const artifacts = await io.pages(`${api}/artifacts?name=native-ci-basis`, { + itemsField: 'artifacts', + }); + for (const artifact of artifacts + .filter( + (value) => + value.name === 'native-ci-basis' && + value.expired === false && + value.workflow_run?.head_branch === 'main', + ) + .sort((a, b) => b.id - a.id)) { + assert( + Number.isSafeInteger(artifact.workflow_run.id) && artifact.workflow_run.id > 0, + 'CI basis producing run is missing', + ); + const run = await io.read(`${api}/runs/${artifact.workflow_run.id}`); + if ( + run.status !== 'completed' || + run.conclusion !== 'success' || + !['push', 'workflow_dispatch'].includes(run.event) || + run.path !== WORKFLOW + ) + continue; + assert( + Number.isSafeInteger(artifact.id) && + artifact.id > 0 && + Number.isSafeInteger(artifact.size_in_bytes) && + artifact.size_in_bytes > 0 && + artifact.size_in_bytes <= 16 * 1024 * 1024 && + /^sha256:[a-f0-9]{64}$/u.test(artifact.digest), + 'CI basis artifact metadata is invalid', + ); + const jobs = await io.pages(`${api}/runs/${run.id}/attempts/${run.run_attempt}/jobs`, { + itemsField: 'jobs', + }); + const response = await io.download( + `https://api.github.com/${api}/artifacts/${artifact.id}/zip`, + ); + const bytes = await boundedResponseBytes(response, artifact.size_in_bytes, 'CI basis artifact'); + assert( + bytes.length === artifact.size_in_bytes && `sha256:${digest(bytes)}` === artifact.digest, + 'CI basis artifact digest differs', + ); + const temporary = mkdtempSync(path.join(tmpdir(), 'oliphaunt-ci-basis-')); + try { + const zip = path.join(temporary, 'basis.zip'); + writeFileSync(zip, bytes, { mode: 0o600 }); + const entries = [ + ...readPortableArchiveEntries(zip, { + maxArchiveBytes: 16 * 1024 * 1024, + maxEntries: 1, + maxEntryBytes: 64 * 1024 * 1024, + maxExpandedBytes: 64 * 1024 * 1024, + }).values(), + ]; + assert( + entries.length === 1 && entries[0].name === 'basis.json' && entries[0].type === 'file', + 'CI basis artifact payload differs', + ); + const data = typeof entries[0].data === 'function' ? entries[0].data() : entries[0].data; + const basis = JSON.parse( + new TextDecoder('utf-8', { fatal: true }).decode(data), + ) as ConfiguredCiBasis; + assert(basis.github.repository === repositoryName, 'CI basis repository differs'); + basisIdentity(basis, run, jobs, root); + return basis; + } finally { + rmSync(temporary, { recursive: true, force: true }); + } + } + return undefined; +} + +function receipts(directory: string): ConfiguredCiRequest[] { + const files: string[] = []; + const visit = (current: string) => { + for (const entry of readdirSync(current, { withFileTypes: true })) { + assert(!entry.isSymbolicLink(), 'CI receipt transport cannot contain links'); + const file = path.join(current, entry.name); + if (entry.isDirectory()) visit(file); + else { + assert( + entry.isFile() && entry.name === 'ci-request.json', + 'CI receipt transport contains an unexpected file', + ); + files.push(file); + } + } + }; + if (existsSync(directory)) visit(directory); + return files.sort().map(json); +} +function githubContext(): NativeBuildGithub { + const result = { + repository: process.env.GITHUB_REPOSITORY ?? '', + workflow: 'Native Bazel qualification', + workflowPath: WORKFLOW, + runId: Number(process.env.GITHUB_RUN_ID), + runAttempt: Number(process.env.GITHUB_RUN_ATTEMPT), + job: process.env.GITHUB_JOB ?? '', + }; + assertNativeBuildGithub(result); + return result; +} +function outputs(plan: ConfiguredCiPlan, matrices: Record) { + const result: Record = { + ci_mode: plan.mode, + ci_selected_requests: JSON.stringify(plan.selected_requests), + ci_selected_jobs: JSON.stringify(plan.selected_jobs), + ci_capture_requests: JSON.stringify(plan.capture_requests), + }; + for (const [job, rows] of Object.entries(matrices)) { + const include = rows.filter((row) => + plan.selected_jobs.includes(`${job}/${row.platform ?? row.arch}`), + ); + result[`${job.replaceAll('-', '_')}_matrix`] = JSON.stringify({ include }); + } + return result; +} +async function main() { + const { values, positionals } = parseArgs({ + options: { + output: { type: 'string' }, + full: { type: 'boolean', default: false }, + plan: { type: 'string' }, + 'requests-dir': { type: 'string' }, + 'required-result': { type: 'string' }, + 'basis-output': { type: 'string' }, + }, + allowPositionals: true, + strict: true, + }); + const root = process.cwd(); + const source = currentSource(root); + assertConfiguredCiSource(root, source); + const workflow = Bun.YAML.parse(readFileSync(path.join(root, WORKFLOW), 'utf8')); + const { requests, matrices } = configuredCiWorkflowInventory(workflow); + if (positionals[0] === 'plan') { + assert(positionals.length === 1 && values.output, 'CI plan requires one output file'); + let basis: ConfiguredCiBasis | undefined; + const forced = values.full || process.env.GITHUB_EVENT_NAME === 'workflow_dispatch'; + if (!forced) { + try { + basis = await acquireConfiguredCiBasis(root, githubContext().repository); + } catch { + console.error('CI basis unavailable; running complete qualification'); + } + } + const changes = basis ? configuredCiSourceChanges(root, basis.source, source) : []; + const plan = selectConfiguredCiRequests({ source, requests, changes, basis, full: forced }); + if (plan.mode === 'source') { + const bytes = Buffer.from(`${JSON.stringify(basis)}\n`); + plan.basisDigest = digest(bytes); + writeFileSync(`${values.output}.basis.json`, bytes, { flag: 'wx', mode: 0o600 }); + } + writeFileSync(values.output, `${JSON.stringify(plan)}\n`, { flag: 'wx', mode: 0o600 }); + if (process.env.GITHUB_OUTPUT) + appendFileSync( + process.env.GITHUB_OUTPUT, + Object.entries(outputs(plan, matrices)) + .map(([key, value]) => `${key}=${value}\n`) + .join(''), + ); + } else if (positionals[0] === 'verify') { + assert( + positionals.length === 1 && + values.plan && + values['requests-dir'] && + values['required-result'], + 'CI verification requires plan, receipts and Required result', + ); + const plan = json(values.plan) as ConfiguredCiPlan; + assert.deepEqual(plan.source, source, 'CI plan source differs'); + let basis: ConfiguredCiBasis | undefined; + if (plan.mode === 'source') { + const bytes = readFileSync(`${values.plan}.basis.json`); + assert(plan.basisDigest === digest(bytes), 'CI decision basis transport digest differs'); + basis = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes)); + } + verifyConfiguredCiDecision(plan, { + source, + requests, + basis, + changes: basis ? configuredCiSourceChanges(root, basis.source, source) : [], + }); + const records = receipts(values['requests-dir']); + verifyConfiguredCiResults(plan, records, values['required-result'], githubContext(), requests); + if (plan.mode === 'full') { + assert.deepEqual( + [...plan.selected_requests].sort(), + requests.map((request) => request.id).sort(), + 'full CI plan omitted a declared request', + ); + assert(values['basis-output'], 'complete CI requires a basis output'); + const basis: ConfiguredCiBasis = { + schema: 'oliphaunt-ci-basis-v1', + source, + github: githubContext(), + controllerInputs: controllerInputs(root), + requests: records.sort((a, b) => a.id.localeCompare(b.id)), + }; + mkdirSync(path.dirname(values['basis-output']), { recursive: true }); + writeFileSync(values['basis-output'], `${JSON.stringify(basis)}\n`, { + flag: 'wx', + mode: 0o600, + }); + } + } else throw new Error('configured-scope requires plan or verify'); + assertConfiguredCiSource(root, source); +} +if (import.meta.main) await main(); diff --git a/tools/ci/configured-scope.test.mts b/tools/ci/configured-scope.test.mts new file mode 100644 index 000000000..1046acfec --- /dev/null +++ b/tools/ci/configured-scope.test.mts @@ -0,0 +1,1466 @@ +import assert from 'node:assert/strict'; +import { execFileSync, spawnSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import { zipArchive } from '../packaging/testdata/zip-fixture.mts'; +import { nativeBuildMetadata } from '../release/native-build-qualification.mts'; +import { projectNativeCurrentArtifacts } from '../release/native-extension-final-inputs.mts'; +import { + configuredRecipeGraph, + nativeConfiguredRecipeGraph, +} from '../release/native-configured-inputs.mts'; +import { + acquireConfiguredCiBasis, + assertConfiguredCiSource, + type ConfiguredCiBasis, + type ConfiguredCiRequest, + captureConfiguredCiRequest, + configuredCiSourceChanges, + configuredCiWorkflowInventory, + joinConfiguredCiProjections, + selectConfiguredCiRequests, + verifyConfiguredCiDecision, + verifyConfiguredCiResults, + writeConfiguredCiSuccessReceipt, +} from './configured-scope.mts'; +import { isNativeImportSourceLabel } from './native-import-projection.mts'; + +const configuration = 'a'.repeat(64); +const source = { commit: '1'.repeat(40), tree: '2'.repeat(40) }; +const github = { + repository: 'test/repo', + workflow: 'Native Bazel qualification', + workflowPath: '.github/workflows/bazel.yml', + runId: 123, + runAttempt: 1, + job: 'portable', +}; +const request = (id: string, files: string[], requires: string[] = []): ConfiguredCiRequest => ({ + schema: 'oliphaunt-ci-request-v1', + id, + job: id.split('/')[0], + mode: 'full', + status: 'success', + source, + github, + requires, + projection: { + roots: [{ label: '//pkg:root', configuration }], + files: [...files].sort(), + trees: [], + directories: [], + analysisInputs: ['pkg/BUILD'], + }, +}); +const rows = [ + request('linux/producer', ['shared.rs', 'linux.rs']), + request('mac/consumer', ['mac.rs'], ['linux/producer']), + request('docs/site', ['docs.mdx']), +]; +const inventory = rows.map(({ id, job, requires }) => ({ id, job, requires })); +const basis: ConfiguredCiBasis = { + schema: 'oliphaunt-ci-basis-v1', + source, + github, + controllerInputs: ['tools/ci/configured-scope.mts'], + requests: rows, +}; +const modified = (name: string) => ({ + path: name, + kind: 'modified', + oldMode: '100644', + newMode: '100644', +}); +const select = ( + changes: ReturnType[], + override: Partial[0]> = {}, +) => selectConfiguredCiRequests({ source, requests: inventory, basis, changes, ...override }); + +test('one, shared, many and unused source changes select only configured requests and transport', () => { + assert.deepEqual(select([modified('docs.mdx')]).selected_requests, ['docs/site']); + assert.deepEqual(select([modified('shared.rs')]).selected_requests, ['linux/producer']); + assert.deepEqual(select([modified('mac.rs')]).selected_requests, [ + 'linux/producer', + 'mac/consumer', + ]); + assert.deepEqual(select([modified('mac.rs')]).capture_requests, ['linux/producer']); + assert.deepEqual(select([modified('unused.md')]).selected_requests, []); + assert.deepEqual(select([modified('mac.rs'), modified('docs.mdx')]).selected_requests, [ + 'docs/site', + 'linux/producer', + 'mac/consumer', + ]); +}); + +test('current imported roots inherit only their configured producer source scope and transitive inputs', () => { + const proof = (name: string) => ({ + root: `//wasix:${name}`, + configuration, + evidenceDigest: `sha256:${'b'.repeat(64)}`, + invocationId: 'current-combined-wasix-build', + output: `bazel-out/wasix/bin/${name}.crate`, + }); + const core = proof('core'), + tools = proof('tools'), + addon = proof('addon'); + const producer = request('wasix/combined', ['core.rs', 'addon.rs', 'server.rs', 'tools.rs']); + producer.projection!.roots = [core, tools, addon].map(({ root: label, configuration }) => ({ + label, + configuration, + })); + producer.projection!.analysisInputs = ['shared/recipe.mts']; + producer.projection!.trees = ['acquired']; + producer.projection!.directories = ['observed']; + producer.projection!.nativeOutputs = [addon, core, tools].map((row) => ({ + ...row, + files: [`${row.root.split(':')[1]}.rs`], + })); + const runtime = request('wasix-host/runtime', ['runtime.rs'], [producer.id]); + runtime.projection!.importedRoots = [core]; + const napi = request('wasix-host/napi', ['addon.rs', 'napi.rs'], [producer.id]); + napi.projection!.importedRoots = [core]; + const toolConsumer = request('wasix-host/tools', ['tool-consumer.rs'], [producer.id]); + toolConsumer.projection!.importedRoots = [tools]; + const downstream = request('installed/runtime', ['installed.rs']); + const runtimeProof = { + ...proof('runtime'), + evidenceDigest: `sha256:${'c'.repeat(64)}`, + invocationId: 'runtime-build', + }; + runtime.projection!.roots.push({ label: runtimeProof.root, configuration }); + runtime.projection!.nativeOutputs = [ + { ...runtimeProof, files: ['runtime.rs'], importedRoots: [core] }, + ]; + downstream.projection!.importedRoots = [runtimeProof]; + const requests = [producer, runtime, napi, toolConsumer, downstream]; + const identities = requests.map(({ id, job, requires }) => ({ id, job, requires })); + const currentBasis = { ...basis, requests }; + const selected = (file: string) => + select([modified(file)], { requests: identities, basis: currentBasis }); + assert.deepEqual(selected('addon.rs').selected_requests, ['wasix-host/napi', 'wasix/combined']); + assert.deepEqual(selected('server.rs').selected_requests, ['wasix/combined']); + assert.deepEqual(selected('napi.rs').selected_requests, ['wasix-host/napi', 'wasix/combined']); + assert.deepEqual(selected('core.rs').selected_requests, [ + 'installed/runtime', + 'wasix-host/napi', + 'wasix-host/runtime', + 'wasix/combined', + ]); + assert.deepEqual(selected('tools.rs').selected_requests, ['wasix-host/tools', 'wasix/combined']); + const joined = joinConfiguredCiProjections(requests, source); + const installed = joined.find((row) => row.id === downstream.id)!.projection!; + assert.deepEqual(installed.files, ['core.rs', 'installed.rs', 'runtime.rs']); + assert.deepEqual(installed.trees, ['acquired']); + assert.deepEqual(installed.directories, ['observed']); + assert(installed.analysisInputs.includes('shared/recipe.mts')); + assert(!installed.files.includes('addon.rs')); + assert.deepEqual(downstream.requires, []); + assert.deepEqual(downstream.projection!.files, ['installed.rs'], 'retained basis stays local'); +}); + +test('native lineage fails closed for absent, ambiguous, older-source and different original producer proofs', () => { + const proof = { + root: '//pkg:root', + configuration, + evidenceDigest: `sha256:${'b'.repeat(64)}`, + invocationId: 'current-build', + output: 'bazel-out/cfg/bin/core.crate', + }; + const producer = request('wasix/producer', ['core.rs']); + producer.projection!.nativeOutputs = [{ ...proof, files: ['core.rs'] }]; + const consumer = request('host/consumer', ['consumer.rs']); + consumer.projection!.importedRoots = [proof]; + const requests = [producer, consumer]; + const identities = requests.map(({ id, job, requires }) => ({ id, job, requires })); + for (const field of [ + 'evidenceDigest', + 'invocationId', + 'output', + 'root', + 'configuration', + ] as const) { + const corrupt = structuredClone(requests); + const importProof = corrupt[1].projection!.importedRoots![0]; + importProof[field] = + field === 'evidenceDigest' + ? `sha256:${'c'.repeat(64)}` + : field === 'configuration' + ? 'd'.repeat(64) + : `${importProof[field]}-other`; + assert.throws(() => joinConfiguredCiProjections(corrupt, source), /exact original producer/u); + assert.equal( + select([modified('core.rs')], { + requests: identities, + basis: { ...basis, requests: corrupt }, + }).mode, + 'full', + ); + } + const absent = structuredClone(requests); + delete absent[0].projection!.nativeOutputs; + assert.throws(() => joinConfiguredCiProjections(absent, source), /exact original producer/u); + const duplicate = { ...structuredClone(producer), id: 'duplicate/producer', job: 'duplicate' }; + assert.throws( + () => joinConfiguredCiProjections([...requests, duplicate], source), + /exact original producer/u, + ); + const older = structuredClone(requests); + older[0].source.commit = '9'.repeat(40); + assert.throws(() => joinConfiguredCiProjections(older, source), /producer source differs/u); + const unrelated = structuredClone(requests); + unrelated[0].projection!.roots = [{ label: '//different:root', configuration }]; + assert.throws(() => joinConfiguredCiProjections(unrelated, source), /outside this request/u); +}); + +test('authored full-only requests never intersect source changes or leak through transport closure', () => { + const publicSource = request('families/public-source', ['sdk.rs']); + const producer = request('producer/runtime', ['runtime.rs']); + const aggregate = { + ...request('families/aggregate', ['sdk.rs'], [publicSource.id, producer.id].sort()), + fullOnly: true, + }; + const requests = [publicSource, producer, aggregate]; + const identities = requests.map(({ id, job, requires, fullOnly }) => ({ + id, + job, + requires, + ...(fullOnly ? { fullOnly } : {}), + })); + const currentBasis = { ...basis, requests }; + const args = { requests: identities, basis: currentBasis }; + const sourcePlan = select([modified('sdk.rs')], args); + assert.equal(sourcePlan.mode, 'source'); + assert.deepEqual(sourcePlan.selected_requests, [publicSource.id]); + assert.deepEqual(sourcePlan.capture_requests, []); + assert.deepEqual( + select([], { ...args, full: true }).selected_requests, + requests.map((row) => row.id).sort(), + ); + const dependent = structuredClone(requests); + dependent[0].requires = [aggregate.id]; + dependent[2].requires = [producer.id]; + const dependentIdentities = identities.map((row) => + row.id === publicSource.id + ? { ...row, requires: [aggregate.id] } + : row.id === aggregate.id + ? { ...row, requires: [producer.id] } + : row, + ); + assert.equal( + select([modified('sdk.rs')], { + requests: dependentIdentities, + basis: { ...basis, requests: dependent }, + }).mode, + 'full', + ); + const changedPolicy = identities.map((row) => + row.id === aggregate.id ? { ...row, fullOnly: false } : row, + ); + assert.equal( + select([modified('sdk.rs')], { requests: changedPolicy, basis: currentBasis }).mode, + 'full', + ); + const explicitFalse = structuredClone(requests); + explicitFalse[0].fullOnly = false; + assert.equal( + select([modified('sdk.rs')], { ...args, basis: { ...basis, requests: explicitFalse } }).mode, + 'source', + ); + assert.throws( + () => + verifyConfiguredCiResults( + { ...sourcePlan, selected_requests: [aggregate.id] }, + [{ ...aggregate, mode: 'source', projection: undefined }], + 'skipped', + github, + identities, + ), + /full-only/u, + ); + const workflow = { + env: {}, + jobs: { + families: { + steps: [ + { env: { CI_REQUEST_ID: 'families/public-source' } }, + { env: { CI_REQUEST_ID: 'families/aggregate', CI_FULL_ONLY: 'true' } }, + ], + }, + }, + }; + assert.deepEqual(configuredCiWorkflowInventory(workflow).requests, [ + { id: 'families/aggregate', job: 'families', requires: [], fullOnly: true }, + { id: 'families/public-source', job: 'families', requires: [] }, + ]); +}); + +test('unknown basis, structural edits and filesystem membership changes always select full', () => { + for (const change of [ + modified('pkg/BUILD.bazel'), + modified('defs/a.bzl'), + modified('MODULE.bazel.lock'), + modified('.github/workflows/bazel.yml'), + modified('.gitattributes'), + modified('src/docs/.gitignore'), + { ...modified('new.md'), kind: 'A', oldMode: '000000' }, + { ...modified('old.md'), kind: 'D', newMode: '000000' }, + { ...modified('script.sh'), newMode: '100755' }, + { ...modified('link'), oldMode: '120000', newMode: '120000' }, + modified('tools/ci/configured-scope.mts'), + ]) + assert.equal(select([change]).mode, 'full'); + for (const invalid of [ + undefined, + { ...basis, requests: rows.slice(1) }, + { ...basis, requests: [{ ...rows[0], projection: undefined }, ...rows.slice(1)] }, + ]) + assert.equal(select([], { basis: invalid as ConfiguredCiBasis }).mode, 'full'); + assert.equal( + select([modified('.github/workflows/bazel.yml')], { + requests: [...inventory, { id: 'new/request', job: 'new', requires: [] }], + }).mode, + 'full', + ); + assert.equal(select([], { full: true }).mode, 'full'); +}); + +test('recursive recorded trees affect content while directory observations describe unchanged membership', () => { + const treeBasis = structuredClone(basis); + treeBasis.requests[0].projection!.trees = ['catalog']; + treeBasis.requests[1].projection!.directories = ['catalog']; + assert.deepEqual( + select([modified('catalog/entry.toml')], { basis: treeBasis }).selected_requests, + ['linux/producer'], + ); + treeBasis.requests[2].projection!.trees = ['']; + assert.deepEqual(select([modified('anywhere.md')], { basis: treeBasis }).selected_requests, [ + 'docs/site', + ]); +}); + +test('seeded content mutations match an independent request-input and transport oracle', () => { + let seed = 881; + const next = () => (seed = (Math.imul(seed, 1664525) + 1013904223) >>> 0); + const scenarios = new Set(); + for (let scenario = 0; scenario < 128; scenario++) { + const changed = ['shared.rs', 'linux.rs', 'mac.rs', 'docs.mdx', 'unused.md'].filter( + () => (next() >>> 16) % 2, + ); + scenarios.add(JSON.stringify(changed)); + const expected = new Set( + rows + .filter((row) => changed.some((file) => row.projection!.files.includes(file))) + .map((row) => row.id), + ); + if (expected.has('mac/consumer')) expected.add('linux/producer'); + assert.deepEqual(select(changed.map(modified)).selected_requests, [...expected].sort()); + } + assert(scenarios.size >= 24, 'seeded cases must exercise varied change subsets'); +}); + +test('aggregate binds every selected receipt to source, run, job, transport and full Required', () => { + const plan = select([modified('mac.rs')]); + const currentGithub = { ...github, runAttempt: 2 }; + const receipts = rows.slice(0, 2).map((row, index) => ({ + ...row, + github: { ...row.github, runAttempt: index + 1 }, + mode: 'source' as const, + projection: undefined, + })); + verifyConfiguredCiResults(plan, receipts, 'skipped', currentGithub, inventory); + for (const mutation of [ + (row: ConfiguredCiRequest) => { + row.github.runId++; + }, + (row: ConfiguredCiRequest) => { + row.github.runAttempt = 0; + }, + (row: ConfiguredCiRequest) => { + row.github.runAttempt = 3; + }, + (row: ConfiguredCiRequest) => { + row.source.commit = '9'.repeat(40); + }, + (row: ConfiguredCiRequest) => { + row.job = 'wrong'; + }, + (row: ConfiguredCiRequest) => { + row.requires = []; + }, + ]) { + const corrupt = structuredClone(receipts); + mutation(corrupt[1]); + assert.throws(() => + verifyConfiguredCiResults(plan, corrupt, 'skipped', currentGithub, inventory), + ); + } + assert.throws(() => + verifyConfiguredCiResults(plan, receipts.slice(0, 1), 'skipped', currentGithub, inventory), + ); + const full = select([], { full: true }); + assert.throws(() => verifyConfiguredCiResults(full, rows, 'skipped', currentGithub, inventory)); + verifyConfiguredCiResults(full, rows, 'success', currentGithub, inventory); +}); + +test('verification recomputes omissions instead of trusting a shortened plan', () => { + const changes = [modified('mac.rs')]; + const plan = select(changes); + const args = { source, requests: inventory, basis, changes }; + verifyConfiguredCiDecision(plan, args); + for (const field of ['selected_requests', 'selected_jobs', 'capture_requests'] as const) { + const corrupt = structuredClone(plan); + corrupt[field] = []; + assert.throws(() => verifyConfiguredCiDecision(corrupt, args), /omissions/u); + } + assert.throws( + () => verifyConfiguredCiDecision(plan, { ...args, basis: undefined }), + /omissions/u, + ); +}); + +function graph() { + const rule = (name: string, deps: string[] = []) => ({ + configurationId: 1, + target: { + rule: { + name, + configuredRuleInput: deps.map((label) => ({ + label, + configurationId: label.endsWith('.rs') ? 0 : 1, + })), + }, + }, + }); + return { + configurations: [{ id: 1, checksum: configuration }], + results: [ + rule('//one:root', ['//shared:library']), + rule('//two:root', ['//shared:library']), + rule('//shared:library', ['//shared:input.rs']), + { configurationId: 0, target: { sourceFile: { name: '//shared:input.rs' } } }, + ], + }; +} +test('union traversal preserves all shared DAG labels/packages and Native per-root proof', () => { + const roots = ['//one:root', '//two:root'].map((label) => ({ label, configuration })); + const ordinary = configuredRecipeGraph(graph(), roots, true); + const native = nativeConfiguredRecipeGraph(graph(), roots); + assert.deepEqual(ordinary.labels, native.labels); + assert.deepEqual(ordinary.packages, native.packages); + assert.deepEqual(ordinary.roots, []); + assert.equal(native.roots.length, 2); + const imported = + '@@_main+metadata+oliphaunt_metadata//:native-current-artifacts/runtime/archive.tgz'; + const sdk = '@@apple_sdk+//include:SDK.h'; + const withForeignSources = graph(); + for (const label of [imported, sdk]) { + withForeignSources.results[2].target.rule!.configuredRuleInput.push({ + label, + configurationId: 0, + }); + withForeignSources.results.push({ + configurationId: 0, + target: { sourceFile: { name: label } }, + }); + } + const sliced = configuredRecipeGraph( + withForeignSources, + roots, + true, + (name) => name.startsWith('//') || isNativeImportSourceLabel(name), + ); + assert.deepEqual(sliced.roots, [], 'default root recipe shape remains unchanged'); + assert.deepEqual( + sliced.sourceRoots, + roots.map((root) => ({ ...root, labels: ['//shared:input.rs', imported] })), + ); + const external = graph(); + external.results[0].target.rule!.name = '@@icu+//:smoke'; + assert.equal( + configuredRecipeGraph(external, [{ label: '@@icu+//:smoke', configuration }], true).labels[0], + '//shared:input.rs', + ); + assert.throws(() => + nativeConfiguredRecipeGraph(external, [{ label: '@@icu+//:smoke', configuration }]), + ); + const cycle = graph(); + cycle.results[2].target.rule!.configuredRuleInput = [{ label: '//one:root', configurationId: 1 }]; + assert.throws(() => configuredRecipeGraph(cycle, roots, true), /cycle/u); + assert.throws( + () => configuredRecipeGraph(graph(), [{ label: '//missing:root', configuration }], true), + /missing/u, + ); +}); + +test('actual executable workflow inventory covers every 33 request context and authentic handoffs', () => { + const workflow = Bun.YAML.parse( + readFileSync(new URL('../../.github/workflows/bazel.yml', import.meta.url), 'utf8'), + ); + const actual = configuredCiWorkflowInventory(workflow); + assert.equal(actual.requests.length, 33); + assert.equal(new Set(actual.requests.map((row) => row.id)).size, 33); + assert.equal( + actual.requests.find((row) => row.id === 'release-families/checksums')!.fullOnly, + true, + ); + assert.deepEqual( + actual.requests.find((row) => row.id === 'release-families/public-source')!.requires, + [], + ); + assert.equal( + actual.requests.find((row) => row.id === 'release-families/checksums')!.requires.length, + 13, + ); + assert.equal(actual.requests.filter((row) => row.requires.length).length, 10); + assert(!actual.requests.some((row) => /^portable\/[^/]+\/napi$/u.test(row.id))); + for (const platform of ['linux-arm64', 'macos-arm64', 'windows-x64']) { + const napi = actual.requests.find((row) => row.id === `wasix-host/${platform}/napi`); + assert(napi, `missing imported NAPI request for ${platform}`); + assert.equal(napi.job, `wasix-host/${platform}`); + assert.deepEqual(napi.requires, ['wasix/tools-sdk-browser']); + assert( + actual.requests + .find((row) => row.id === 'release-families/checksums')! + .requires.includes(napi.id), + ); + } + const napiId = 'wasix-host/linux-arm64/napi'; + const napiPlan = selectConfiguredCiRequests({ + source, + requests: actual.requests, + basis: { + ...basis, + requests: actual.requests.map((row) => ({ + ...request(row.id, row.id === napiId ? ['napi.rs'] : []), + ...row, + })), + }, + changes: [modified('napi.rs')], + }); + assert.deepEqual(napiPlan.selected_requests, [napiId, 'wasix/tools-sdk-browser']); + assert.deepEqual(napiPlan.selected_jobs, ['wasix', 'wasix-host/linux-arm64']); + assert.deepEqual(napiPlan.capture_requests, ['wasix/tools-sdk-browser']); + assert(actual.requests.some((row) => row.id === 'linux/x86_64/android-packages')); + assert(!actual.requests.some((row) => row.id === 'linux/aarch64/android-packages')); +}); + +async function gitFixture( + run: (root: string, outputBase: string, identity: typeof source) => Promise, +) { + const base = mkdtempSync(path.join(tmpdir(), 'configured-ci-')); + const root = path.join(base, 'source'); + const outputBase = path.join(base, 'output'); + const put = (name: string, value: string) => { + mkdirSync(path.dirname(path.join(root, name)), { recursive: true }); + writeFileSync(path.join(root, name), value); + }; + mkdirSync(root); + mkdirSync(path.join(outputBase, 'external'), { recursive: true }); + put( + 'tools/release/qualified-release-replay.sh', + readFileSync(new URL('../release/qualified-release-replay.sh', import.meta.url), 'utf8'), + ); + put('MODULE.bazel.lock', '{"lockFileVersion":28,"moduleExtensions":{}}'); + put('.bazelversion', '8.8.1\n'); + put('shared/input.rs', 'pub fn input() {}'); + put('one/BUILD', '#root'); + put('two/BUILD', '#root'); + put('one/core.rs', 'pub fn core() {}'); + put('two/addon.rs', 'pub fn addon() {}'); + put('shared/BUILD', '#input'); + put('unused.md', 'docs'); + put( + '.github/workflows/bazel.yml', + readFileSync(new URL('../../.github/workflows/bazel.yml', import.meta.url), 'utf8'), + ); + execFileSync('git', ['init', '--quiet'], { cwd: root }); + execFileSync('git', ['add', '.'], { cwd: root }); + execFileSync( + 'git', + [ + '-c', + 'user.name=Test', + '-c', + 'user.email=test@example.invalid', + 'commit', + '--quiet', + '-m', + 'fixture', + ], + { cwd: root }, + ); + const current = () => ({ + commit: execFileSync('git', ['rev-parse', 'HEAD'], { cwd: root, encoding: 'utf8' }).trim(), + tree: execFileSync('git', ['rev-parse', 'HEAD^{tree}'], { cwd: root, encoding: 'utf8' }).trim(), + }); + writeFileSync( + path.join(outputBase, 'MODULE.bazel.lock'), + '{"lockFileVersion":28,"moduleExtensions":{}}', + ); + const originalSnapshot = process.env.OLIPHAUNT_NATIVE_PUBLICATION_INPUTS; + const originalFullOnly = process.env.CI_FULL_ONLY; + delete process.env.OLIPHAUNT_NATIVE_PUBLICATION_INPUTS; + delete process.env.CI_FULL_ONLY; + try { + await run(root, outputBase, current()); + } finally { + if (originalSnapshot === undefined) delete process.env.OLIPHAUNT_NATIVE_PUBLICATION_INPUTS; + else process.env.OLIPHAUNT_NATIVE_PUBLICATION_INPUTS = originalSnapshot; + if (originalFullOnly === undefined) delete process.env.CI_FULL_ONLY; + else process.env.CI_FULL_ONLY = originalFullOnly; + rmSync(base, { recursive: true, force: true }); + } +} + +test('shared capture uses existing configured/recipe views without query, binds real Git and source guard', async () => { + await gitFixture(async (root, outputBase, actualSource) => { + const executionRoot = path.join(outputBase, 'execroot/_main'); + const outputDirectory = path.join(outputBase, 'receipts/full'); + const file = await captureConfiguredCiRequest({ + id: 'linux/packages', + job: 'linux', + source: actualSource, + github, + outputDirectory, + workspaceRoot: root, + configuration: [], + startup: [], + requestedTargets: ['//one:root', '//two:root'], + completedRoots: ['//one:root', '//two:root'].map((label) => ({ label, configuration })), + executionRoot, + configuredGraph: graph(), + recipeQueries: [ + { + packages: ['//one', '//two', '//shared'], + labels: ['@@//one:BUILD', '@//two:BUILD', '//shared:BUILD'], + }, + ], + }); + const captured = JSON.parse(readFileSync(file, 'utf8')); + assert.deepEqual(captured.projection.files, ['shared/input.rs']); + assert.deepEqual(captured.projection.analysisInputs, [ + 'one/BUILD', + 'shared/BUILD', + 'two/BUILD', + ]); + assert.deepEqual(captured.source, actualSource); + writeFileSync(path.join(root, 'unused.md'), 'edited'); + assert.throws(() => assertConfiguredCiSource(root, actualSource)); + assert.throws(() => + writeConfiguredCiSuccessReceipt({ + id: 'linux/packages', + job: 'linux', + source: actualSource, + github, + outputDirectory: path.join(outputBase, 'source'), + workspaceRoot: root, + }), + ); + execFileSync('git', ['add', '.'], { cwd: root }); + execFileSync( + 'git', + [ + '-c', + 'user.name=Test', + '-c', + 'user.email=test@example.invalid', + 'commit', + '--quiet', + '-m', + 'doc edit', + ], + { cwd: root }, + ); + const now = { + commit: execFileSync('git', ['rev-parse', 'HEAD'], { cwd: root, encoding: 'utf8' }).trim(), + tree: execFileSync('git', ['rev-parse', 'HEAD^{tree}'], { + cwd: root, + encoding: 'utf8', + }).trim(), + }; + assert.deepEqual(configuredCiSourceChanges(root, actualSource, now), [modified('unused.md')]); + }); +}); + +test('capture awaits caller-owned queries and writes no receipt after cancellation', async () => { + await gitFixture(async (root, outputBase, actualSource) => { + const captureRequest = { + id: 'linux/packages', + job: 'linux', + source: actualSource, + github, + outputDirectory: path.join(outputBase, 'receipts/owned'), + workspaceRoot: root, + configuration: [], + startup: [], + requestedTargets: ['//one:root', '//two:root'], + completedRoots: ['//one:root', '//two:root'].map((label) => ({ label, configuration })), + executionRoot: path.join(outputBase, 'execroot/_main'), + }; + const recipes = { + packages: ['//one', '//two', '//shared'], + labels: ['//one:BUILD', '//two:BUILD', '//shared:BUILD'], + }; + const queries: string[] = []; + const file = await captureConfiguredCiRequest(captureRequest, { + async bazel(args, stdout) { + await Promise.resolve(); + queries.push(args[0]); + writeFileSync( + stdout, + args[0] === 'cquery' ? JSON.stringify(graph()) : recipes.labels.join('\n'), + { flag: 'wx' }, + ); + }, + assertRunning() {}, + }); + assert.deepEqual(queries, ['cquery', 'query']); + assert.deepEqual(JSON.parse(readFileSync(file, 'utf8')).projection.files, ['shared/input.rs']); + assert.deepEqual(readdirSync(captureRequest.outputDirectory).sort(), [ + 'analysis-buildfiles.query', + 'analysis-deps.query', + 'ci-request.json', + ]); + + for (const phase of ['query', 'recorded-inputs']) { + let interrupted = false; + const outputDirectory = path.join(outputBase, 'receipts', phase); + const pending = captureConfiguredCiRequest( + { + ...captureRequest, + outputDirectory, + ...(phase === 'recorded-inputs' + ? { configuredGraph: graph(), recipeQueries: [recipes] } + : {}), + }, + { + async bazel(args, stdout) { + assert.equal(phase, 'query'); + assert.equal(args[0], 'cquery'); + await Promise.resolve(); + writeFileSync(stdout, JSON.stringify(graph()), { flag: 'wx' }); + interrupted = true; + }, + assertRunning() { + if (interrupted) throw new Error('fixture interrupted'); + }, + }, + ); + // The supplied views reach the collector's real asynchronous file reads before returning. + if (phase === 'recorded-inputs') interrupted = true; + await assert.rejects(pending, /fixture interrupted/u); + assert.deepEqual( + readdirSync(outputDirectory), + phase === 'query' ? ['analysis-deps.query'] : [], + ); + } + }); +}); + +test('native capture binds original packet bytes to root-local source Files and reached imports', async () => { + await gitFixture(async (root, outputBase, actualSource) => { + const executionRoot = path.join(outputBase, 'execroot/_main'); + const output = 'bazel-out/wasix/bin/one/fixture-runtime-1.0.0.tar.gz'; + const partsOutput = 'bazel-out/wasix/bin/one/cargo-parts/fixture-runtime'; + const original = path.join(executionRoot, output); + mkdirSync(path.dirname(original), { recursive: true }); + mkdirSync(path.join(executionRoot, partsOutput, 'nested'), { recursive: true }); + const bytes = Buffer.from('controlled original public runtime'); + writeFileSync(original, bytes); + const sha256 = createHash('sha256').update(bytes).digest('hex'); + const shipping = { + label: '//one:root', + package: { + product: 'fixture-runtime', + version: '1.0.0', + ecosystem: 'github', + name: 'fixture-runtime-1.0.0.tar.gz', + configuration: 'portable', + role: 'github-release-asset', + outputs: [ + { path: output, owner: '//one:archive' }, + { path: partsOutput, owner: '//one:archive' }, + ], + }, + }; + const evidence = { + schema: 'oliphaunt-native-build-evidence-v1', + source: actualSource, + github, + cohorts: [ + { + executionRoot, + roots: [shipping], + rootConfigurations: [{ label: shipping.label, configuration }], + aquery: { + pathFragments: output.split('/').map((label, index) => ({ + id: index + 1, + label, + ...(index ? { parentId: index } : {}), + })), + artifacts: [{ id: 1, pathFragmentId: output.split('/').length }], + targets: [{ id: 1, label: '//one:archive' }], + configuration: [{ id: 1, checksum: configuration }], + actions: [ + { + targetId: 1, + configurationId: 1, + mnemonic: 'FileWrite', + actionKey: 'controlled-archive', + outputIds: [1], + primaryOutputId: 1, + }, + ], + }, + buildEvents: [ + { + id: { started: {} }, + started: { + uuid: 'controlled-current-invocation', + buildToolVersion: '8.8.1', + command: 'build', + }, + }, + { id: { workspace: {} }, workspaceInfo: { localExecRoot: executionRoot } }, + { id: { configuration: { id: configuration } }, configuration: { mnemonic: 'wasix' } }, + { + id: { namedSet: { id: 'output' } }, + namedSetOfFiles: { + files: [{ name: output, digest: sha256, length: String(bytes.length) }], + }, + }, + { + id: { + targetCompleted: { label: shipping.label, configuration: { id: configuration } }, + }, + completed: { + success: true, + outputGroup: [{ name: 'default', fileSets: [{ id: 'output' }] }], + }, + }, + { + id: { buildFinished: {} }, + finished: { overallSuccess: true, exitCode: { name: 'SUCCESS' } }, + }, + { + id: { buildMetadata: {} }, + buildMetadata: { metadata: nativeBuildMetadata(actualSource, github) }, + }, + { id: { buildMetrics: {} }, lastMessage: true, buildMetrics: {} }, + ], + inputs: [], + outputs: [ + { + path: output, + members: [{ path: '', type: 'file', mode: 0o644, size: bytes.length, sha256 }], + }, + { + path: partsOutput, + members: [ + { path: '', type: 'directory', mode: 0o755 }, + { path: 'nested', type: 'directory', mode: 0o755 }, + ], + }, + ], + }, + ], + }; + const nativeEvidence = path.join(outputBase, 'native-build-evidence.json'); + const packet = Buffer.from(`${JSON.stringify(evidence)}\n`); + writeFileSync(nativeEvidence, packet); + const repository = 'oliphaunt_metadata'; + writeFileSync( + path.join(outputBase, 'external', `@${repository}.marker`), + `${'f'.repeat(64)}\n`, + ); + const rule = (name: string, labels: string[]) => ({ + configurationId: 1, + target: { + rule: { + name, + configuredRuleInput: labels.map((label) => ({ + label, + configurationId: label.endsWith('.rs') ? 0 : 1, + })), + }, + }, + }); + const sourceFile = (name: string) => ({ configurationId: 0, target: { sourceFile: { name } } }); + const aliasRule = `@@${repository}//:rule_alias`; + const raw = { + configurations: [{ id: 1, checksum: configuration }], + results: [ + rule('//one:root', ['//one:core.rs']), + rule('//two:root', ['//two:addon.rs', aliasRule]), + rule(aliasRule, []), + sourceFile('//one:core.rs'), + sourceFile('//two:addon.rs'), + ], + }; + const capture = (id: string, configuredGraph = raw, extra = {}) => + captureConfiguredCiRequest({ + id, + job: id.split('/')[0], + source: actualSource, + github, + outputDirectory: path.join(outputBase, 'receipts', id), + workspaceRoot: root, + configuration: [], + startup: [], + requestedTargets: ['//one:root', '//two:root'], + completedRoots: ['//one:root', '//two:root'].map((label) => ({ label, configuration })), + executionRoot, + configuredGraph, + recipeQueries: [ + { + packages: ['//one', '//two', `@@${repository}//`], + labels: ['//one:BUILD', '//two:BUILD'], + }, + ], + ...extra, + }); + const producer = JSON.parse( + readFileSync(await capture('producer/current', raw, { nativeEvidence }), 'utf8'), + ); + assert.equal( + producer.projection.importedRoots, + undefined, + 'reached rule aliases are not imported Files', + ); + assert.equal(producer.projection.nativeOutputs.length, 1); + const retained = producer.projection.nativeOutputs[0]; + assert.equal(retained.output, output, 'empty companion trees have no imported File lineage'); + assert.deepEqual(retained.files, ['one/core.rs']); + assert.equal( + retained.evidenceDigest, + `sha256:${createHash('sha256').update(packet).digest('hex')}`, + ); + assert.equal(retained.invocationId, 'controlled-current-invocation'); + assert.deepEqual(producer.projection.files, ['one/core.rs', 'two/addon.rs']); + const { files: _files, importedRoots: _imports, ...proof } = retained; + const snapshot = { + source: actualSource, + nativeCurrentArtifacts: [ + { + product: 'fixture-runtime', + version: '1.0.0', + artifact: 'github-release:fixture-runtime-1.0.0.tar.gz', + configuration: 'portable', + source: actualSource, + file: { path: original, size: bytes.length, sha256, producer: proof }, + }, + ], + }; + const aliases = projectNativeCurrentArtifacts( + snapshot.nativeCurrentArtifacts, + actualSource, + ).files; + assert.equal(aliases.length, 1); + const alias = aliases[0]; + const importedFile = path.join(executionRoot, 'external', repository, alias.path); + mkdirSync(path.dirname(importedFile), { recursive: true }); + writeFileSync(importedFile, bytes); + const importedLabel = `@@${repository}//:${alias.path}`; + const consumerGraph = structuredClone(raw); + consumerGraph.results[1].target.rule!.configuredRuleInput.push({ + label: importedLabel, + configurationId: 0, + }); + consumerGraph.results.push(sourceFile(importedLabel)); + const snapshotFile = path.join(outputBase, 'publication-inputs.json'); + writeFileSync(snapshotFile, JSON.stringify(snapshot)); + process.env.OLIPHAUNT_NATIVE_PUBLICATION_INPUTS = snapshotFile; + const consumer = JSON.parse( + readFileSync(await capture('consumer/current', consumerGraph), 'utf8'), + ); + assert.deepEqual(consumer.projection.importedRoots, [proof]); + assert.equal( + consumer.projection.nativeOutputs, + undefined, + 'ordinary capture has no native producer authority', + ); + assert.equal(joinConfiguredCiProjections([producer, consumer], actualSource).length, 2); + delete process.env.OLIPHAUNT_NATIVE_PUBLICATION_INPUTS; + await assert.rejects(capture('consumer/missing-snapshot', consumerGraph), /original producer/u); + const populatedParts = structuredClone(evidence); + const partBytes = Buffer.from('controlled Cargo payload part'); + const partSha256 = createHash('sha256').update(partBytes).digest('hex'); + const partPath = 'nested/fixture-runtime-part-001-1.0.0.crate'; + writeFileSync(path.join(executionRoot, partsOutput, partPath), partBytes); + populatedParts.cohorts[0].outputs[1].members.push({ + path: partPath, + type: 'file', + mode: 0o644, + size: partBytes.length, + sha256: partSha256, + }); + const populatedNamedOutput = populatedParts.cohorts[0].buildEvents.find( + (event) => 'namedSetOfFiles' in event, + ) as { namedSetOfFiles: { files: unknown[] } } | undefined; + assert(populatedNamedOutput); + writeFileSync(nativeEvidence, JSON.stringify(populatedParts)); + await assert.rejects( + capture('producer/missing-completed-part', raw, { nativeEvidence }), + /absent from its completion/u, + ); + populatedNamedOutput.namedSetOfFiles.files.push({ + name: `${partsOutput}/${partPath}`, + digest: partSha256, + length: String(partBytes.length), + }); + writeFileSync(nativeEvidence, JSON.stringify(populatedParts)); + const populatedProducer = JSON.parse( + readFileSync(await capture('producer/populated-parts', raw, { nativeEvidence }), 'utf8'), + ); + assert.deepEqual( + populatedProducer.projection.nativeOutputs.map((value: { output: string }) => value.output), + [partsOutput, output], + ); + rmSync(path.join(executionRoot, partsOutput, partPath)); + const noFiles = structuredClone(evidence); + noFiles.cohorts[0].roots[0].package.outputs = [shipping.package.outputs[1]]; + noFiles.cohorts[0].outputs = [evidence.cohorts[0].outputs[1]]; + writeFileSync(nativeEvidence, JSON.stringify(noFiles)); + await assert.rejects( + capture('producer/no-delivered-files', raw, { nativeEvidence }), + /CI original native root .*one:root.* has no completed File.*cargo-parts\/fixture-runtime/u, + ); + noFiles.cohorts[0].roots[0].label = '//two:root'; + noFiles.cohorts[0].roots.unshift(shipping); + noFiles.cohorts[0].rootConfigurations.push({ label: '//two:root', configuration }); + noFiles.cohorts[0].outputs = evidence.cohorts[0].outputs; + noFiles.cohorts[0].buildEvents.splice(5, 0, { + id: { targetCompleted: { label: '//two:root', configuration: { id: configuration } } }, + completed: { + success: true, + outputGroup: [{ name: 'default', fileSets: [{ id: 'output' }] }], + }, + }); + writeFileSync(nativeEvidence, JSON.stringify(noFiles)); + await assert.rejects( + capture('producer/empty-root-with-valid-sibling', raw, { nativeEvidence }), + /CI original native root .*two:root.* has no completed File.*cargo-parts\/fixture-runtime/u, + ); + const missingCapture = structuredClone(evidence); + missingCapture.cohorts[0].outputs = [evidence.cohorts[0].outputs[0]]; + writeFileSync(nativeEvidence, JSON.stringify(missingCapture)); + await assert.rejects( + capture('producer/missing-companion-capture', raw, { nativeEvidence }), + /capture is missing or ambiguous/u, + ); + const missingOutput = structuredClone(evidence); + const namedOutput = missingOutput.cohorts[0].buildEvents.find( + (event) => 'namedSetOfFiles' in event, + ) as { namedSetOfFiles: { files: unknown[] } } | undefined; + assert(namedOutput); + namedOutput.namedSetOfFiles.files = []; + writeFileSync(nativeEvidence, JSON.stringify(missingOutput)); + await assert.rejects( + capture('producer/missing-completed-output', raw, { nativeEvidence }), + /absent from its completion/u, + ); + writeFileSync(nativeEvidence, packet); + await assert.rejects( + capture('producer/unrelated-root', raw, { + nativeEvidence, + requestedTargets: ['//two:root'], + completedRoots: [{ label: '//two:root', configuration }], + }), + /outside this request/u, + ); + evidence.github = { ...github, job: 'different-producer' }; + writeFileSync(nativeEvidence, JSON.stringify(evidence)); + await assert.rejects( + capture('producer/different-context', raw, { nativeEvidence }), + /context differs/u, + ); + }); +}); + +test('capture preserves large exact query arguments and complete output without truncation', async () => { + await gitFixture(async (root, outputBase) => { + const labels = Array.from({ length: 640 }, (_, i) => `//package_${'x'.repeat(64)}_${i}:root`); + const buildLabels = labels.map((label) => `${label.slice(0, label.indexOf(':'))}:BUILD`); + for (const label of buildLabels) { + const file = path.join(root, label.slice(2).replace(':', '/')); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, '# source recipe fixture\n'); + } + const actualGraph = { + configurations: [{ id: 1, checksum: configuration }], + results: [ + ...labels.map((name, i) => ({ + configurationId: 1, + target: { + rule: { + name, + configuredRuleInput: + i === 0 ? [{ label: '//shared:input.rs', configurationId: 0 }] : [], + }, + }, + })), + { configurationId: 0, target: { sourceFile: { name: '//shared:input.rs' } } }, + ], + }; + const graphFile = path.join(outputBase, 'graph.json'); + const callsFile = path.join(outputBase, 'calls.json'); + const modeFile = path.join(outputBase, 'mode.txt'); + const driver = path.join(outputBase, 'query-driver.mts'); + writeFileSync(graphFile, JSON.stringify(actualGraph)); + writeFileSync(modeFile, 'large'); + writeFileSync( + driver, + ` +import { readFileSync, writeFileSync, writeSync, existsSync } from 'node:fs'; +const args = process.argv.slice(2); +if (args.join(' ').length >= 32767) throw new Error('Windows command-line limit'); +if (!args[1]?.startsWith('--query_file=')) throw new Error('missing query file transport'); +const expression = readFileSync(args[1].slice('--query_file='.length), 'utf8'); +const file = ${JSON.stringify(callsFile)}; +const calls = existsSync(file) ? JSON.parse(readFileSync(file, 'utf8')) : []; +calls.push({ args, expression }); +writeFileSync(file, JSON.stringify(calls)); +if (args[0] === 'cquery') { + const mode = readFileSync(${JSON.stringify(modeFile)}, 'utf8'); + if (mode === 'large') { + const chunk = Buffer.alloc(1024 * 1024, 32); + for (let remaining = 129 * chunk.length; remaining > 0;) + remaining -= writeSync(1, chunk, 0, Math.min(remaining, chunk.length)); + } + writeSync(1, mode === 'malformed' ? '{' : readFileSync(${JSON.stringify(graphFile)})); + if (mode === 'nonzero') process.exit(7); +} +else if (args[0] === 'query') console.log(${JSON.stringify([...buildLabels, '//shared:BUILD'].join('\n'))}); +else throw new Error('unexpected additional Bazel command'); +`, + ); + const shellQuote = (value: string) => `'${value.replaceAll("'", "'\\''")}'`; + const launcher = path.join(root, 'tools/dev/bazel.sh'); + mkdirSync(path.dirname(launcher), { recursive: true }); + writeFileSync( + launcher, + `#!/usr/bin/env bash\nexec ${shellQuote(process.execPath)} --no-install --no-env-file ${shellQuote(driver)} "$@"\n`, + ); + execFileSync('git', ['add', '.'], { cwd: root }); + execFileSync( + 'git', + [ + '-c', + 'user.name=Test', + '-c', + 'user.email=test@example.invalid', + 'commit', + '--quiet', + '-m', + 'large queries', + ], + { cwd: root }, + ); + const actualSource = { + commit: execFileSync('git', ['rev-parse', 'HEAD'], { cwd: root, encoding: 'utf8' }).trim(), + tree: execFileSync('git', ['rev-parse', 'HEAD^{tree}'], { + cwd: root, + encoding: 'utf8', + }).trim(), + }; + const outputDirectory = path.join(outputBase, 'receipts/full'); + const configurationFlags = [ + '--platforms=//native:windows', + '--host_platform=//native:windows', + '--lockfile_mode=error', + ]; + const captureRequest = { + id: 'portable/windows-x64/packages', + job: 'portable/windows-x64', + source: actualSource, + github, + outputDirectory, + workspaceRoot: root, + configuration: configurationFlags, + startup: [], + requestedTargets: labels.toReversed(), + completedRoots: labels.map((label) => ({ label, configuration })), + executionRoot: path.join(outputBase, 'execroot/_main'), + }; + const file = await captureConfiguredCiRequest(captureRequest); + const expression = (values: string[]) => + `set(${[...new Set(values)] + .sort() + .map((value) => JSON.stringify(value)) + .join(' ')})`; + const calls = JSON.parse(readFileSync(callsFile, 'utf8')); + assert.deepEqual(calls, [ + { + args: [ + 'cquery', + `--query_file=${path.join(outputDirectory, 'analysis-deps.query')}`, + ...configurationFlags, + '--lockfile_mode=update', + '--output=jsonproto', + '--consistent_labels', + '--transitions=lite', + '--proto:include_configurations', + '--proto:output_rule_attrs=', + ], + expression: `deps(${expression(labels)})`, + }, + { + args: [ + 'query', + `--query_file=${path.join(outputDirectory, 'analysis-buildfiles.query')}`, + '--lockfile_mode=error', + '--consistent_labels', + '--output=label', + ], + expression: `buildfiles(${expression([...labels, '//shared:input.rs'])})`, + }, + ]); + for (const call of calls) { + assert(call.expression.length > 32767, 'fixture must exceed the Windows command limit'); + assert(call.args.join(' ').length < 32767, 'both subprocess commands must remain bounded'); + } + const captured = JSON.parse(readFileSync(file, 'utf8')); + assert.deepEqual(captured.projection.files, ['shared/input.rs']); + assert.deepEqual( + captured.projection.analysisInputs, + [...buildLabels, '//shared:BUILD'].map((label) => label.slice(2).replace(':', '/')).sort(), + ); + assert.deepEqual( + captured.projection.roots, + labels.map((label) => ({ label, configuration })), + ); + assert.deepEqual(captured.source, actualSource); + assert.deepEqual(readdirSync(outputDirectory).sort(), [ + 'analysis-buildfiles.query', + 'analysis-deps.query', + 'ci-request.json', + ]); + for (const mode of ['nonzero', 'malformed']) { + writeFileSync(modeFile, mode); + const failed = path.join(outputBase, 'receipts', mode); + await assert.rejects( + captureConfiguredCiRequest({ ...captureRequest, outputDirectory: failed }), + mode === 'nonzero' ? /CI cquery failed \(7\)/u : SyntaxError, + ); + assert.deepEqual( + readdirSync(failed), + ['analysis-deps.query'], + 'failed query must retain neither a temporary output nor a success receipt', + ); + } + }); +}); + +test('CLI full fallback and source verification preserve complete Required and reject omitted work', async () => { + await gitFixture(async (root, outputBase, actualSource) => { + const entry = new URL('./configured-scope.mts', import.meta.url).pathname; + const env = { + ...process.env, + GITHUB_EVENT_NAME: 'workflow_dispatch', + GITHUB_REPOSITORY: github.repository, + GITHUB_RUN_ID: String(github.runId), + GITHUB_RUN_ATTEMPT: '1', + GITHUB_JOB: 'source-ci', + }; + const run = (...args: string[]) => + spawnSync(process.execPath, [entry, ...args], { cwd: root, env, encoding: 'utf8' }); + const fullFile = path.join(outputBase, 'full.json'); + const full = run('plan', '--full', '--output', fullFile); + assert.equal(full.status, 0, full.stderr); + assert.equal(JSON.parse(readFileSync(fullFile, 'utf8')).selected_requests.length, 33); + assert.notEqual( + run( + 'verify', + '--plan', + fullFile, + '--requests-dir', + path.join(outputBase, 'empty'), + '--required-result', + 'skipped', + '--basis-output', + path.join(outputBase, 'forbidden.json'), + ).status, + 0, + ); + const actualInventory = configuredCiWorkflowInventory( + Bun.YAML.parse(readFileSync(path.join(root, '.github/workflows/bazel.yml'), 'utf8')), + ).requests; + const selectedId = 'portable/linux-x64/packages'; + const oldBasis: ConfiguredCiBasis = { + ...basis, + source: actualSource, + requests: actualInventory.map((row) => ({ + ...request(row.id, row.id === selectedId ? ['shared/input.rs'] : []), + ...row, + source: actualSource, + })), + }; + writeFileSync(path.join(root, 'shared/input.rs'), 'pub fn updated() {}'); + execFileSync('git', ['add', '.'], { cwd: root }); + execFileSync( + 'git', + [ + '-c', + 'user.name=Test', + '-c', + 'user.email=test@example.invalid', + 'commit', + '--quiet', + '-m', + 'source edit', + ], + { cwd: root }, + ); + const now = { + commit: execFileSync('git', ['rev-parse', 'HEAD'], { cwd: root, encoding: 'utf8' }).trim(), + tree: execFileSync('git', ['rev-parse', 'HEAD^{tree}'], { + cwd: root, + encoding: 'utf8', + }).trim(), + }; + const decision = selectConfiguredCiRequests({ + source: now, + requests: actualInventory, + basis: oldBasis, + changes: configuredCiSourceChanges(root, actualSource, now), + }); + assert.deepEqual(decision.selected_requests, [selectedId]); + const file = path.join(outputBase, 'source-plan.json'); + const bytes = Buffer.from(`${JSON.stringify(oldBasis)}\n`); + const plan = { ...decision, basisDigest: createHash('sha256').update(bytes).digest('hex') }; + writeFileSync(`${file}.basis.json`, bytes); + writeFileSync(file, JSON.stringify(plan)); + const requestsDir = path.join(outputBase, 'receipts'); + writeConfiguredCiSuccessReceipt({ + ...actualInventory.find((row) => row.id === selectedId)!, + source: now, + github, + outputDirectory: requestsDir, + workspaceRoot: root, + }); + const verify = () => + run('verify', '--plan', file, '--requests-dir', requestsDir, '--required-result', 'skipped'); + const valid = verify(); + assert.equal(valid.status, 0, valid.stderr); + writeFileSync(file, JSON.stringify({ ...plan, selected_requests: [], selected_jobs: [] })); + const omitted = verify(); + assert.notEqual(omitted.status, 0); + assert.match(omitted.stderr, /omissions/u); + }); +}); + +test('basis acquisition admits only the exact completed main Required artifact and its immutable bytes', async () => { + await gitFixture(async (root, _outputBase, actualSource) => { + const actual = { + ...basis, + source: actualSource, + github: { ...github, runAttempt: 2 }, + requests: rows.map((row, index) => ({ + ...row, + source: actualSource, + github: { ...row.github, runAttempt: index === 1 ? 2 : 1 }, + })), + }; + const run = { + id: github.runId, + run_attempt: 2, + status: 'completed', + conclusion: 'success', + event: 'push', + head_branch: 'main', + head_sha: actualSource.commit, + path: '.github/workflows/bazel.yml', + }; + const required = { + name: 'Required', + status: 'completed', + conclusion: 'success', + run_attempt: 2, + }; + const bytes = zipArchive([{ name: 'basis.json', data: JSON.stringify(actual) }]); + const artifact = { + id: 77, + name: 'native-ci-basis', + expired: false, + workflow_run: { id: run.id, head_branch: 'main' }, + size_in_bytes: bytes.length, + digest: `sha256:${createHash('sha256').update(bytes).digest('hex')}`, + }; + const io = { + read: async () => run, + pages: async (endpoint: string) => + endpoint.includes('/artifacts?') ? [artifact] : [required], + download: async () => new Response(bytes), + }; + assert.deepEqual(await acquireConfiguredCiBasis(root, github.repository, io as any), actual); + assert.equal( + await acquireConfiguredCiBasis(root, github.repository, { + ...io, + pages: async () => [], + } as any), + undefined, + ); + for (const mutation of [ + { + ...io, + pages: async (endpoint: string) => + endpoint.includes('/artifacts?') ? [artifact] : [{ ...required, run_attempt: 1 }], + }, + { + ...io, + pages: async (endpoint: string) => + endpoint.includes('/artifacts?') + ? [artifact] + : [ + { ...required, run_attempt: 1 }, + { ...required, conclusion: 'failure' }, + ], + }, + { + ...io, + pages: async (endpoint: string) => + endpoint.includes('/artifacts?') ? [artifact] : [{ ...required, conclusion: 'skipped' }], + }, + { + ...io, + pages: async (endpoint: string) => + endpoint.includes('/artifacts?') + ? [{ ...artifact, digest: `sha256:${'0'.repeat(64)}` }] + : [required], + }, + { ...io, read: async () => ({ ...run, head_sha: '9'.repeat(40) }) }, + ]) + await assert.rejects(acquireConfiguredCiBasis(root, github.repository, mutation as any)); + for (const mutate of [ + (value: ConfiguredCiBasis) => { + value.github.runAttempt = 1; + }, + (value: ConfiguredCiBasis) => { + value.requests[0].github.runAttempt = 3; + }, + ]) { + const corrupted = structuredClone(actual); + mutate(corrupted); + const contents = zipArchive([{ name: 'basis.json', data: JSON.stringify(corrupted) }]); + await assert.rejects( + acquireConfiguredCiBasis(root, github.repository, { + ...io, + pages: async (endpoint: string) => + endpoint.includes('/artifacts?') + ? [ + { + ...artifact, + size_in_bytes: contents.length, + digest: `sha256:${createHash('sha256').update(contents).digest('hex')}`, + }, + ] + : [required], + download: async () => new Response(contents), + } as any), + ); + } + }); +}); diff --git a/tools/ci/native-import-projection.mts b/tools/ci/native-import-projection.mts new file mode 100644 index 000000000..f7731b923 --- /dev/null +++ b/tools/ci/native-import-projection.mts @@ -0,0 +1,406 @@ +/** Source lineage of reached constructor imports; this mints no producer authority. */ +import assert from 'node:assert/strict'; +import { existsSync, readFileSync, realpathSync, statSync } from 'node:fs'; +import path from 'node:path'; +import { isDeepStrictEqual } from 'node:util'; +import { + type ExtensionFinalInputFile, + projectNativeAppleBaseInput, + projectNativeCurrentArtifacts, + projectNativeExtensionFinalInputs, + projectNativeSwiftSourceInput, +} from '../release/native-extension-final-inputs.mts'; +import { fileIdentity, safeRelative } from '../release/native-file-identity.mts'; +import type { NativeBuildSource } from '../release/native-build-qualification.mts'; +import { validateNativeSupplierArtifacts } from '../release/native-supplier-artifacts.mts'; + +export type NativeImportedRoot = ExtensionFinalInputFile['producer']; + +const importedRepositories = [ + 'oliphaunt_metadata', + 'postmaster_guest', + 'wasix_runtime_carriers', + 'react_native_native_base', + 'react_native_swift_package', +]; +const matchesRepository = (actual: string, expected: string) => + actual === expected || actual.endsWith(`+${expected}`); + +/** Imported constructors only; unrelated external SDK source leaves have no producer lineage. */ +export function isNativeImportSourceLabel(label: string) { + const match = /^@@?([^/]+)\/\//u.exec(label); + return !!match && importedRepositories.some((name) => matchesRepository(match[1], name)); +} + +type NativeImportContext = { + snapshot: any; + source: NativeBuildSource; + executionRoot: string; + wasixCargoInputs?: string; +}; + +/** Only current constructor Files reached by the configured consumer can inherit source inputs. */ +export function nativeImportProjection({ + labels, + ...context +}: NativeImportContext & { labels: string[] }): NativeImportedRoot[] { + return createNativeImportProjection(context)(labels); +} + +/** Share immutable original File verification across root slices in one capture. */ +export function createNativeImportProjection({ + snapshot, + source, + executionRoot, + wasixCargoInputs, +}: NativeImportContext) { + assert.deepEqual(snapshot.source, source, 'imported source projection source differs'); + const files = [ + ...projectNativeCurrentArtifacts(snapshot.nativeCurrentArtifacts ?? [], source).files, + ...projectNativeExtensionFinalInputs(snapshot.extensionFinalInputs ?? []).files, + ...(snapshot.nativeAppleBase + ? projectNativeAppleBaseInput(snapshot.nativeAppleBase).files + : []), + ...(snapshot.nativeSwiftSource + ? projectNativeSwiftSourceInput(snapshot.nativeSwiftSource).files + : []), + ]; + const originals: ExtensionFinalInputFile[] = []; + const collect = (value: any) => { + if (!value || typeof value !== 'object') return; + if (value.producer && typeof value.path === 'string') originals.push(value); + else for (const child of Object.values(value)) collect(child); + }; + collect(snapshot); + const aliases = new Map( + files.map((alias) => { + const candidates = originals.filter( + (file) => + file.path === alias.source && file.size === alias.size && file.sha256 === alias.sha256, + ); + for (const file of candidates) + assert.ok( + isDeepStrictEqual(file, candidates[0]), + 'imported File has conflicting producer facts', + ); + return [alias.path, candidates[0]] as const; + }), + ); + const current = snapshot.nativeCurrentArtifacts ?? []; + const completed = validateNativeSupplierArtifacts(snapshot.supplierArtifacts ?? []); + let imported = new Map(); + const retain = (file: ExtensionFinalInputFile) => { + assert.ok(file?.producer, 'reached current import has no original producer'); + const { root, configuration, evidenceDigest, invocationId, output } = file.producer; + const key = JSON.stringify([root, configuration, evidenceDigest, invocationId, output]); + imported.set(key, structuredClone(file.producer)); + }; + const matchesRepo = matchesRepository; + const equalFile = (file: ExtensionFinalInputFile, actual: string) => { + const identity = fileIdentity(realpathSync(actual)); + assert.deepEqual( + { size: identity.size, sha256: identity.sha256 }, + { size: file.size, sha256: file.sha256 }, + 'reached import bytes differ from original producer File', + ); + retain(file); + }; + const descriptors = new Map(); + const readDescriptor = (directory: string, name: string) => { + const file = path.join(directory, `${name}.json`); + if (!descriptors.has(file)) descriptors.set(file, JSON.parse(readFileSync(file, 'utf8'))); + return descriptors.get(file); + }; + const verifiedDescriptors = new Map(); + const descriptorFile = (row: any, file = row.file) => { + assert.ok(file && typeof file.path === 'string', 'captured import lacks its original File'); + const key = JSON.stringify([row.publication, row.artifact, file]); + if (verifiedDescriptors.has(key)) { + for (const original of verifiedDescriptors.get(key)!) retain(original); + return; + } + const alias = /^@@?([^/]+)\/\/:(.+)$/u.exec(file.path); + const matchesPath = (original: { path: string }, member: string) => + alias + ? matchesRepo(alias[1], 'oliphaunt_metadata') && alias[2] === member + : path.isAbsolute(file.path) && realpathSync(file.path) === realpathSync(original.path); + if (row.publication) { + const held = completed.filter( + (candidate) => + isDeepStrictEqual(candidate.publication, row.publication) && + candidate.artifact === row.artifact && + candidate.file.size === file.size && + candidate.file.sha256 === file.sha256 && + matchesPath( + candidate.file, + `supplier-artifacts/${candidate.publication.product}/${candidate.publication.version}/${candidate.file.sha256}/${path.basename(candidate.file.path)}`, + ), + ); + assert.equal(held.length, 1, 'captured held import lacks its completed original File'); + const retained = fileIdentity(held[0].file.path); + assert.deepEqual( + { size: retained.size, sha256: retained.sha256 }, + { size: file.size, sha256: file.sha256 }, + 'captured held import differs from its original File', + ); + verifiedDescriptors.set(key, []); + return; + } + const candidates = originals.filter( + (original) => + original.size === file.size && + original.sha256 === file.sha256 && + original.member === file.member && + isDeepStrictEqual(original.producer, file.producer) && + [...aliases].some( + ([member, candidate]) => candidate === original && matchesPath(original, member), + ), + ); + assert.ok(candidates.length, 'captured current import lacks its original producer File'); + for (const original of candidates) { + const identity = fileIdentity(original.path); + assert.deepEqual( + { size: identity.size, sha256: identity.sha256 }, + { size: file.size, sha256: file.sha256 }, + 'captured current import differs from its original producer File', + ); + retain(original); + } + verifiedDescriptors.set(key, candidates); + }; + let receipt: any; + const cargoReceipt = () => { + if (receipt) return receipt; + assert.ok(wasixCargoInputs, 'reached WASIX import needs its original Cargo receipt'); + receipt = JSON.parse(readFileSync(path.join(wasixCargoInputs, 'receipt.json'), 'utf8')); + assert.equal(receipt.schema, 'oliphaunt-wasix-cargo-construction-v1'); + assert.deepEqual(receipt.source, source, 'WASIX import receipt source differs'); + assert.ok(Array.isArray(receipt.crates) && receipt.crates.length); + const rows = [...receipt.crates, ...(receipt.hostSmokeCrates ?? [])]; + assert.equal( + new Set(rows.map((row) => row.name)).size, + rows.length, + 'WASIX import receipt repeats a crate', + ); + for (const row of rows) { + assert.equal(row.path, `${row.name}-${row.version}.crate`); + safeRelative(row.path); + assert.equal(path.posix.basename(row.path), row.path); + const candidates = current.filter( + (artifact) => artifact.artifact === `cargo:${row.name}` && artifact.version === row.version, + ); + assert.equal(candidates.length, 1, 'WASIX receipt lacks one original current Cargo producer'); + assert.deepEqual( + { size: row.size, sha256: row.sha256 }, + { size: candidates[0].file.size, sha256: candidates[0].file.sha256 }, + 'WASIX receipt differs from original current Cargo File', + ); + const copied = fileIdentity(path.join(wasixCargoInputs, row.path)); + assert.deepEqual( + { size: copied.size, sha256: copied.sha256 }, + { size: row.size, sha256: row.sha256 }, + 'WASIX receipt archive changed', + ); + } + return receipt; + }; + const cargoOriginal = (name: string, version: string) => { + const rows = [...cargoReceipt().crates, ...(cargoReceipt().hostSmokeCrates ?? [])].filter( + (row) => row.name === name && row.version === version, + ); + assert.equal(rows.length, 1, 'reached WASIX Cargo source lacks its receipt identity'); + const candidates = current.filter( + (artifact) => artifact.artifact === `cargo:${name}` && artifact.version === version, + ); + assert.equal(candidates.length, 1); + return candidates[0].file as ExtensionFinalInputFile; + }; + const cargoPackages = new Map(); + return (labels: string[]): NativeImportedRoot[] => { + imported = new Map(); + for (const label of [...new Set(labels)]) { + const match = /^@@?([^/]+)\/\/([^:]*):(.+)$/u.exec(label); + if (!match) continue; + const [, repository, pkg, name] = match; + if (!isNativeImportSourceLabel(label)) continue; + assert.match(repository, /^[A-Za-z0-9._+~-]+$/u); + const member = [pkg, name].filter(Boolean).join('/'); + safeRelative(member); + const directory = path.join(executionRoot, 'external', repository); + const actual = path.join(directory, member); + if (matchesRepo(repository, 'react_native_native_base')) { + let role: string; + if (member.startsWith('framework/')) role = 'framework'; + else if (member.startsWith('resources/')) role = 'resources'; + else if (member.startsWith('archives/')) { + const rows = ['framework', 'resources'].map((role) => ({ + role, + row: readDescriptor(directory, role), + })); + const selected = rows.filter( + ({ row }) => path.basename(row.file.path) === path.basename(member), + ); + assert.equal(selected.length, 1, 'captured Apple archive lacks its original role'); + role = selected[0].role; + } else if (member === 'BUILD.bazel') continue; + else assert.fail('unknown reached captured Apple source'); + assert.ok( + statSync(realpathSync(actual)).isFile(), + 'captured Apple input is not a regular File', + ); + const row = readDescriptor(directory, role); + if (member.startsWith('archives/')) { + const identity = fileIdentity(realpathSync(actual)); + assert.deepEqual( + { size: identity.size, sha256: identity.sha256 }, + { size: row.file.size, sha256: row.file.sha256 }, + 'captured Apple archive differs from its original File', + ); + } + descriptorFile(row); + continue; + } + if (matchesRepo(repository, 'react_native_swift_package')) { + if (member === 'BUILD.bazel') continue; + assert.ok( + statSync(realpathSync(actual)).isFile(), + 'captured Swift input is not a regular File', + ); + const sourceRow = readDescriptor(directory, 'source'); + const bindings = readDescriptor(directory, 'bindings'); + const bindingsMember = + member.startsWith('OliphauntNativeBindingsFFI.xcframework/') || + (member.startsWith('archives/') && + path.basename(member) === path.basename(bindings.file.path)); + if (bindingsMember) descriptorFile(bindings); + else { + // Repository construction verifies the original carrier together with source bytes. + descriptorFile(sourceRow, sourceRow.publication ? sourceRow.file : sourceRow.archive); + if (!sourceRow.publication) descriptorFile(sourceRow, sourceRow.carrier); + if (['construction.json', 'construction.bzl'].includes(member)) descriptorFile(bindings); + } + if ( + member.startsWith('archives/') || + (member === 'carrier.json' && !sourceRow.publication) + ) { + const file = bindingsMember + ? bindings.file + : member === 'carrier.json' + ? sourceRow.carrier + : sourceRow.publication + ? sourceRow.file + : sourceRow.archive; + const identity = fileIdentity(realpathSync(actual)); + assert.deepEqual( + { size: identity.size, sha256: identity.sha256 }, + { size: file.size, sha256: file.sha256 }, + 'captured Swift archive differs from its original File', + ); + } + continue; + } + if (matchesRepo(repository, 'oliphaunt_metadata')) { + const original = aliases.get(member); + if (original) equalFile(original, actual); + else if ( + /^(?:native-current-artifacts|native-apple-base|native-swift-source|extension-final-inputs)\//u.test( + member, + ) + ) + assert.fail('reached constructor alias lacks its original producer'); + continue; + } + if (matchesRepo(repository, 'postmaster_guest')) { + if ( + !member.startsWith('release-archives/') && + (pkg || ['BUILD.bazel', 'guest.bzl'].includes(name)) + ) + continue; + const parts = member.split('/'); + const artifact = `github-release:${parts.at(-1)}`; + const candidates = current.filter( + (row) => row.artifact === artifact && (parts.length < 3 || row.product === parts[1]), + ); + const held = completed.filter( + (row) => + row.artifact === artifact && (parts.length < 3 || row.publication.product === parts[1]), + ); + const identity = fileIdentity(realpathSync(actual)); + const sameBytes = ({ file }: { file: { size: number; sha256: string } }) => + file.size === identity.size && file.sha256 === identity.sha256; + let present = candidates.filter(sameBytes); + let published = held.filter(sameBytes); + if (present.length && published.length) { + // Equal bytes alone cannot relabel a held publication as a current producer. + // A direct original File path can disambiguate; copied ambiguous inputs fail closed. + const original = realpathSync(actual); + present = present.filter(({ file }) => realpathSync(file.path) === original); + published = published.filter(({ file }) => realpathSync(file.path) === original); + } + if (published.length && !present.length) { + for (const row of published) { + const retained = fileIdentity(row.file.path); + assert.deepEqual( + { size: retained.size, sha256: retained.sha256 }, + { size: row.file.size, sha256: row.file.sha256 }, + 'reached completed archive differs from its retained File', + ); + } + continue; + } + assert.equal( + present.length, + 1, + 'reached release archive lacks one unambiguous original current producer', + ); + assert.equal( + published.length, + 0, + 'reached release archive mixes completed/current origins', + ); + equalFile(present[0].file, actual); + continue; + } + const value = cargoReceipt(); + const rows = [...value.crates, ...(value.hostSmokeCrates ?? [])]; + if (member.startsWith('host-smoke/')) { + const candidates = rows.filter((row) => row.path === path.posix.basename(member)); + assert.equal(candidates.length, 1, 'reached host-smoke crate is absent from its receipt'); + equalFile(cargoOriginal(candidates[0].name, candidates[0].version), actual); + continue; + } + let parent = path.dirname(actual); + while (parent !== directory && !existsSync(path.join(parent, 'Cargo.toml'))) + parent = path.dirname(parent); + assert.ok( + parent === directory || parent.startsWith(`${directory}${path.sep}`), + 'WASIX Cargo source escaped its imported repository', + ); + if (parent === directory) { + assert.ok( + ['Cargo.toml', 'Cargo.lock', 'cargo.bzl', 'cargo-facts.json', 'BUILD.bazel'].includes( + member, + ), + 'unknown reached WASIX repository source', + ); + for (const row of value.crates) retain(cargoOriginal(row.name, row.version)); + } else { + assert.ok( + statSync(realpathSync(actual)).isFile(), + 'imported Cargo source is not a regular File', + ); + if (!cargoPackages.has(parent)) { + const manifest = Bun.TOML.parse(readFileSync(path.join(parent, 'Cargo.toml'), 'utf8')); + cargoPackages.set( + parent, + cargoOriginal(manifest.package?.name, manifest.package?.version), + ); + } + retain(cargoPackages.get(parent)!); + } + } + return [...imported.entries()] + .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)) + .map(([, root]) => root); + }; +} diff --git a/tools/ci/native-import-projection.test.mts b/tools/ci/native-import-projection.test.mts new file mode 100644 index 000000000..827659331 --- /dev/null +++ b/tools/ci/native-import-projection.test.mts @@ -0,0 +1,468 @@ +import assert from 'node:assert/strict'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { afterEach, test } from 'node:test'; +import { tarArchive } from '../packaging/testdata/tar-fixture.mts'; +import { + projectNativeAppleBaseInput, + projectNativeCurrentArtifacts, + projectNativeSwiftSourceInput, +} from '../release/native-extension-final-inputs.mts'; +import { fileIdentity } from '../release/native-file-identity.mts'; +import { + createNativeImportProjection, + nativeImportProjection, +} from './native-import-projection.mts'; + +const directories: string[] = []; +afterEach(() => { + for (const directory of directories.splice(0)) + rmSync(directory, { recursive: true, force: true }); +}); + +/** Controlled physical transport fixtures never acquire authenticated-origin capabilities. */ +function fixture() { + const root = mkdtempSync(path.join(tmpdir(), 'native-import-projection-')); + directories.push(root); + const executionRoot = path.join(root, 'execroot'); + const source = { commit: 'a'.repeat(40), tree: 'b'.repeat(40) }; + const write = (file: string, bytes: string | Buffer) => { + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, bytes); + return file; + }; + const original = (name: string, bytes: Buffer, shipping: string) => { + const file = write(path.join(root, 'original', name), bytes); + const identity = fileIdentity(file); + return { + path: file, + size: identity.size, + sha256: identity.sha256, + producer: { + evidenceDigest: `sha256:${'c'.repeat(64)}`, + invocationId: 'controlled-wasix-producer', + root: shipping, + configuration: 'd'.repeat(64), + output: `bazel-out/producer/bin/${name}`, + }, + }; + }; + const cargo = (name: string) => { + const prefix = `${name}-1.0.0`; + return original( + `${prefix}.crate`, + tarArchive([ + { name: `${prefix}/Cargo.toml`, data: `[package]\nname = "${name}"\nversion = "1.0.0"\n` }, + { name: `${prefix}/src/lib.rs`, data: `pub fn ${name.replaceAll('-', '_')}() {}\n` }, + ]), + `//producer:${name.replaceAll('-', '_')}_shipping`, + ); + }; + const core = cargo('fixture-core'); + const contrib = cargo('fixture-contrib'); + const archive = original( + 'fixture-runtime-1.0.0.tar.gz', + tarArchive([{ name: 'payload/runtime', data: 'controlled public runtime payload' }]), + '//producer:public_archive_shipping', + ); + const artifact = (file: typeof core, identity: string) => ({ + product: 'fixture-runtime', + version: '1.0.0', + artifact: identity, + configuration: 'portable', + source, + file, + }); + const snapshot = { + source, + supplierArtifacts: [] as any[], + nativeCurrentArtifacts: [ + artifact(core, 'cargo:fixture-core'), + artifact(contrib, 'cargo:fixture-contrib'), + artifact(archive, 'github-release:fixture-runtime-1.0.0.tar.gz'), + ], + }; + const metadataRepository = '_main+metadata+oliphaunt_metadata'; + const metadata = projectNativeCurrentArtifacts(snapshot.nativeCurrentArtifacts, source); + for (const alias of metadata.files) + write( + path.join(executionRoot, 'external', metadataRepository, alias.path), + readFileSync(alias.source), + ); + const metadataCore = metadata.files.find((alias) => alias.source === core.path)!; + const metadataLabel = `@@${metadataRepository}//:${metadataCore.path}`; + const guestRepository = '_main+postmaster+postmaster_guest'; + const guestMember = `release-archives/fixture-runtime/${path.basename(archive.path)}`; + const guestPath = write( + path.join(executionRoot, 'external', guestRepository, guestMember), + readFileSync(archive.path), + ); + const guestLabel = `@@${guestRepository}//:${guestMember}`; + const runtimeRepository = '_main+runtime+wasix_runtime_carriers'; + const runtimeRoot = path.join(executionRoot, 'external', runtimeRepository); + write(path.join(runtimeRoot, 'Cargo.toml'), '[workspace]\nmembers = ["crates/core"]\n'); + write( + path.join(runtimeRoot, 'crates/core/Cargo.toml'), + '[package]\nname = "fixture-core"\nversion = "1.0.0"\n', + ); + write(path.join(runtimeRoot, 'crates/core/src/lib.rs'), 'pub fn fixture_core() {}\n'); + const extractedLabel = `@@${runtimeRepository}//crates/core:src/lib.rs`; + const hostSmokeMember = `host-smoke/${path.basename(contrib.path)}`; + const hostSmokePath = write(path.join(runtimeRoot, hostSmokeMember), readFileSync(contrib.path)); + const hostSmokeLabel = `@@${runtimeRepository}//:${hostSmokeMember}`; + const wasixCargoInputs = path.join(root, 'cargo-receipt'); + const receiptRow = (name: string, file: typeof core) => ({ + name, + version: '1.0.0', + path: path.basename(file.path), + size: file.size, + sha256: file.sha256, + }); + const receipt = { + schema: 'oliphaunt-wasix-cargo-construction-v1', + source, + crates: [receiptRow('fixture-core', core)], + hostSmokeCrates: [receiptRow('fixture-contrib', contrib)], + }; + for (const file of [core, contrib]) + write(path.join(wasixCargoInputs, path.basename(file.path)), readFileSync(file.path)); + const saveReceipt = () => + write(path.join(wasixCargoInputs, 'receipt.json'), JSON.stringify(receipt)); + saveReceipt(); + const inspect = (labels: string[]) => + nativeImportProjection({ snapshot, source, labels, executionRoot, wasixCargoInputs }); + return { + snapshot, + source, + executionRoot, + wasixCargoInputs, + inspect, + receipt, + saveReceipt, + core, + contrib, + archive, + metadataLabel, + guestLabel, + guestPath, + extractedLabel, + hostSmokeLabel, + hostSmokePath, + runtimeRoot, + metadataRepository, + metadataCore, + original, + write, + }; +} + +function completed( + file: { path: string; size: number; sha256: string }, + product = 'fixture-runtime', + artifact = `github-release:${path.basename(file.path)}`, +) { + return { + publication: { + product, + version: '1.0.0', + tagName: `${product}-v1.0.0`, + publicationSha: '1'.repeat(40), + publicationTree: '2'.repeat(40), + releaseSha: '3'.repeat(40), + }, + artifact, + file: { path: file.path, size: file.size, sha256: file.sha256 }, + }; +} + +function heldDescriptor(row: ReturnType) { + return { + ...row, + file: { + ...row.file, + path: `@oliphaunt_metadata//:supplier-artifacts/${row.publication.product}/${row.publication.version}/${row.file.sha256}/${path.basename(row.file.path)}`, + }, + }; +} + +test('metadata File aliases retain only the original producer actually reached by the consumer', () => { + const f = fixture(); + assert.deepEqual(f.inspect([f.metadataLabel]), [f.core.producer]); + assert.deepEqual(f.inspect([f.metadataLabel, f.metadataLabel]), [f.core.producer]); +}); + +test('one capture projector keeps independent root slices while sharing original File verification', () => { + const f = fixture(); + const project = createNativeImportProjection(f); + assert.deepEqual(project([f.metadataLabel]), [f.core.producer]); + assert.deepEqual(project([f.guestLabel]), [f.archive.producer]); + assert.deepEqual(project([]), []); + assert.deepEqual(project([f.metadataLabel]), [f.core.producer]); +}); + +test('public checksum archive aliases inherit their original producer without suppressing aggregate lineage', () => { + const f = fixture(); + assert.deepEqual(f.inspect([f.guestLabel]), [f.archive.producer]); +}); + +test('copied database-resource family archives retain their original current producer', () => { + const f = fixture(); + const product = 'database-resources'; + const archive = f.original( + 'database-resources-1.0.0-linux-x64-gnu.tar.gz', + tarArchive([{ name: 'seed/PG_VERSION', data: '18\n' }]), + '//src/database-resources:native_seed_shipping', + ); + f.snapshot.nativeCurrentArtifacts.push({ + product, + version: '1.0.0', + artifact: `github-release:${path.basename(archive.path)}`, + configuration: 'linux-x64-gnu', + source: f.source, + file: archive, + }); + const repository = '_main+postmaster+postmaster_guest'; + const member = `release-archives/${product}/${path.basename(archive.path)}`; + const copied = f.write( + path.join(f.executionRoot, 'external', repository, member), + readFileSync(archive.path), + ); + const label = `@@${repository}//:${member}`; + assert.deepEqual(f.inspect([label]), [archive.producer]); + f.snapshot.supplierArtifacts.push(completed(archive, product)); + assert.throws(() => f.inspect([label]), /unambiguous/u); + f.snapshot.supplierArtifacts.length = 0; + writeFileSync(copied, 'substituted archive'); + assert.throws(() => f.inspect([label]), /original current producer/u); +}); + +test('the single postmaster guest archive also retains its actual original producer', () => { + const f = fixture(); + const repository = '_main+postmaster+postmaster_guest'; + f.write( + path.join(f.executionRoot, 'external', repository, path.basename(f.archive.path)), + readFileSync(f.archive.path), + ); + assert.deepEqual(f.inspect([`@@${repository}//:${path.basename(f.archive.path)}`]), [ + f.archive.producer, + ]); +}); + +test('held checksum archives skip current lineage and unknown archives fail closed', () => { + const f = fixture(); + f.snapshot.nativeCurrentArtifacts.pop(); + f.snapshot.supplierArtifacts.push(completed(f.archive)); + assert.deepEqual(f.inspect([f.guestLabel]), []); + f.snapshot.supplierArtifacts.length = 0; + assert.throws(() => f.inspect([f.guestLabel]), /original current producer/u); +}); + +test('a copied archive with ambiguous held and current origins cannot invent current lineage', () => { + const f = fixture(); + f.snapshot.supplierArtifacts.push(completed(f.archive)); + assert.throws(() => f.inspect([f.guestLabel]), /unambiguous/u); +}); + +test('captured native Apple members use the existing role descriptor and skip completed inputs', () => { + const f = fixture(); + const native = { + owner: 'liboliphaunt-native', + version: '1.0.0', + file: f.original( + 'ios.json', + Buffer.from('{}'), + '//src/native/runtime:apple_ios_manifest_shipping', + ), + framework: f.original( + 'liboliphaunt-1.0.0-apple-spm-xcframework.zip', + Buffer.from('controlled framework'), + '//src/native/runtime:apple_swiftpm_shipping', + ), + resources: f.original( + 'liboliphaunt-1.0.0-runtime-resources-ios-datum64.tar.gz', + Buffer.from('controlled resources'), + '//src/native/runtime:apple_resources_shipping', + ), + }; + Reflect.set(f.snapshot, 'nativeAppleBase', native); + const projected = projectNativeAppleBaseInput(native).input; + const repository = '_main+apple+react_native_native_base'; + const directory = path.join(f.executionRoot, 'external', repository); + f.write( + path.join(directory, 'framework.json'), + JSON.stringify({ owner: native.owner, version: native.version, file: projected.framework }), + ); + f.write(path.join(directory, 'framework/fixture.h'), 'controlled validated extracted header'); + const label = `@@${repository}//framework:fixture.h`; + assert.deepEqual(f.inspect([label]), [native.framework.producer]); + const held = completed(native.framework, native.owner); + f.snapshot.supplierArtifacts.push(held); + f.write(path.join(directory, 'framework.json'), JSON.stringify(heldDescriptor(held))); + assert.deepEqual(f.inspect([label]), []); + held.file.sha256 = 'f'.repeat(64); + assert.throws(() => f.inspect([label]), /completed original File/u); +}); + +test('captured Swift source and bindings retain only their reached original descriptor Files', () => { + const f = fixture(); + const swift = { + owner: 'oliphaunt-swift', + version: '1.0.0', + archive: f.original( + 'Oliphaunt-source.zip', + Buffer.from('controlled source'), + '//producer:swift_source_shipping', + ), + carrier: f.original( + 'oliphaunt-react-native-ios-carriers.json', + Buffer.from( + JSON.stringify({ + schema: 'oliphaunt-react-native-ios-carrier-v1', + base: { + product: 'liboliphaunt-native', + version: '1.0.0', + tag: 'liboliphaunt-native-v1.0.0', + }, + extensions: [], + carriers: [], + }), + ), + '//producer:swift_carrier_shipping', + ), + ownerCatalog: f.original( + 'extension-owner-catalog.json', + Buffer.from('{}'), + '//producer:swift_owner_catalog_shipping', + ), + bindingsArchive: f.original( + 'oliphaunt-swift-1.0.0-bindings.xcframework.zip', + Buffer.from('controlled bindings'), + '//src/native/sdks/swift:shipping_bindings', + ), + }; + Reflect.set(f.snapshot, 'nativeSwiftSource', swift); + const projected = projectNativeSwiftSourceInput(swift).input; + const repository = '_main+apple+react_native_swift_package'; + const directory = path.join(f.executionRoot, 'external', repository); + f.write( + path.join(directory, 'source.json'), + JSON.stringify({ ...projected, carrier: { ...projected.carrier, path: swift.carrier.path } }), + ); + f.write( + path.join(directory, 'bindings.json'), + JSON.stringify({ file: projected.bindingsArchive }), + ); + f.write(path.join(directory, 'Sources/Fixture.swift'), 'controlled validated extracted Swift'); + f.write( + path.join(directory, 'OliphauntNativeBindingsFFI.xcframework/fixture.h'), + 'controlled validated extracted binding', + ); + const sourceLabel = `@@${repository}//Sources:Fixture.swift`; + const bindingLabel = `@@${repository}//OliphauntNativeBindingsFFI.xcframework:fixture.h`; + const project = createNativeImportProjection(f); + assert.deepEqual(project([sourceLabel]), [swift.carrier.producer, swift.archive.producer]); + assert.deepEqual(project([bindingLabel]), [swift.bindingsArchive.producer]); + assert.deepEqual(project([sourceLabel]), [swift.carrier.producer, swift.archive.producer]); + const held = completed(swift.bindingsArchive, swift.owner); + f.snapshot.supplierArtifacts.push(held); + f.write(path.join(directory, 'bindings.json'), JSON.stringify(heldDescriptor(held))); + assert.deepEqual(f.inspect([bindingLabel]), []); + const heldSource = { + ...completed(swift.archive, swift.owner, 'swift-source-tag:1.0.0'), + source: { + commit: '4'.repeat(40), + tree: '5'.repeat(40), + member: 'carrier.json', + blob: '6'.repeat(40), + }, + }; + f.snapshot.supplierArtifacts.push(heldSource); + f.write( + path.join(directory, 'source.json'), + JSON.stringify({ ...heldDescriptor(heldSource), source: heldSource.source }), + ); + assert.deepEqual(f.inspect([sourceLabel]), []); + const tampered = { + ...projected, + archive: { + ...projected.archive, + producer: { ...projected.archive.producer, invocationId: 'invented' }, + }, + }; + f.write(path.join(directory, 'source.json'), JSON.stringify(tampered)); + assert.throws(() => f.inspect([sourceLabel]), /original producer File/u); +}); + +test('extracted runtime Cargo sources and host-smoke archive copies bind the original receipt Files', () => { + const f = fixture(); + assert.deepEqual(f.inspect([f.extractedLabel]), [f.core.producer]); + assert.deepEqual(f.inspect([f.hostSmokeLabel]), [f.contrib.producer]); +}); + +test('completed-publication metadata aliases do not inherit current producer sources', () => { + const f = fixture(); + const held = completed(f.core, 'fixture-runtime', 'cargo:fixture-core'); + f.snapshot.supplierArtifacts.push(held); + const member = heldDescriptor(held).file.path.split('//:')[1]; + f.write( + path.join(f.executionRoot, 'external', f.metadataRepository, member), + readFileSync(f.core.path), + ); + assert.deepEqual(f.inspect([`@@${f.metadataRepository}//:${member}`]), []); +}); + +for (const fault of [ + 'source', + 'receipt-hash', + 'receipt-name', + 'missing-original', + 'duplicate-receipt', + 'extracted-package', + 'copied-crate', +] as const) + test(`WASIX source lineage fails closed: ${fault}`, () => { + const f = fixture(); + if (fault === 'source') f.receipt.source = { ...f.source, commit: 'f'.repeat(40) }; + if (fault === 'receipt-hash') f.receipt.crates[0].sha256 = 'f'.repeat(64); + if (fault === 'receipt-name') f.receipt.crates[0].name = 'invented'; + if (fault === 'missing-original') f.snapshot.nativeCurrentArtifacts.shift(); + if (fault === 'duplicate-receipt') + f.receipt.hostSmokeCrates.push(structuredClone(f.receipt.crates[0])); + if (fault === 'extracted-package') + writeFileSync( + path.join(f.runtimeRoot, 'crates/core/Cargo.toml'), + '[package]\nname = "invented"\nversion = "1.0.0"\n', + ); + if (fault === 'copied-crate') + writeFileSync(path.join(f.wasixCargoInputs, f.receipt.crates[0].path), 'substituted'); + f.saveReceipt(); + assert.throws(() => f.inspect([f.extractedLabel])); + }); + +test('missing receipt, unknown current alias and archive substitutions cannot become lineage', () => { + const f = fixture(); + assert.throws(() => + nativeImportProjection({ + snapshot: f.snapshot, + source: f.source, + labels: [f.extractedLabel], + executionRoot: f.executionRoot, + }), + ); + assert.throws( + () => f.inspect([`@@${f.metadataRepository}//:native-current-artifacts/missing`]), + /original producer/u, + ); + for (const [label, file] of [ + [ + f.metadataLabel, + path.join(f.executionRoot, 'external', f.metadataRepository, f.metadataCore.path), + ], + [f.guestLabel, f.guestPath], + [f.hostSmokeLabel, f.hostSmokePath], + ]) { + writeFileSync(file, 'substituted'); + assert.throws(() => f.inspect([label]), /original.*producer/u); + } +}); diff --git a/tools/ci/run-configured-request.mts b/tools/ci/run-configured-request.mts new file mode 100644 index 000000000..4c7b8b74a --- /dev/null +++ b/tools/ci/run-configured-request.mts @@ -0,0 +1,333 @@ +#!/usr/bin/env bun +/** Execute one authored CI request; only a full baseline captures its configured scope. */ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { mkdtempSync, readFileSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { parseArgs } from 'node:util'; +import { requireSafeDirectoryChain } from '../packaging/release-directory-safety.mts'; +import { canonicalShippingLabel } from '../release/bazel-shipping-inputs.mts'; +import { + NATIVE_AQUERY_FLAGS, + type NativeBuildGithub, + type NativeRequiredTest, + nativeAqueryExpression, + nativeBuildEventIndex, + nativeBuildMetadata, +} from '../release/native-build-qualification.mts'; +import { sourceIdentity } from '../release/with-source.mts'; +import { + assertConfiguredCiSource, + captureConfiguredCiRequest, + writeConfiguredCiSuccessReceipt, +} from './configured-scope.mts'; + +export type ConfiguredRequest = { + id: string; + job: string; + mode: 'full' | 'source'; + command: 'test' | 'build'; + targets: string[]; + configuration: string[]; + startup?: string[]; + requires?: string[]; + outputDirectory: string; + github: NativeBuildGithub; +}; + +/** Authoritative executed leaves, including expanded suites and mixed build roots. */ +export function completedCiRequestRoots( + index: ReturnType, + requestedTargets: string[], +): NativeRequiredTest[] { + const patterns = index.events.filter((event) => event.expanded && event.id?.pattern); + assert(patterns.length === 1, 'complete CI baseline requires its producing target expansion'); + assert.deepEqual( + patterns[0].id.pattern.pattern, + requestedTargets, + 'CI target expansion differs from its authored request', + ); + const expected = (patterns[0].children ?? []).flatMap((child: any) => + child.targetConfigured ? [canonicalShippingLabel(child.targetConfigured.label)] : [], + ); + assert( + expected.length > 0 && new Set(expected).size === expected.length, + 'CI expanded leaves are missing or duplicated', + ); + assert.deepEqual( + index.events + .filter((event) => event.id?.targetConfigured) + .map((event) => canonicalShippingLabel(event.id.targetConfigured.label)) + .sort(), + [...expected].sort(), + 'CI configured leaves differ from the producing expansion', + ); + const roots = new Map(); + const accounted = new Set(); + const admittedTests = new Set(); + for (const label of expected) { + const configured = index.events.filter( + (event) => + event.id?.targetConfigured && + canonicalShippingLabel(event.id.targetConfigured.label) === label, + ); + assert( + configured.length === 1 && configured[0].configured, + 'CI expanded leaf lacks its configured event', + ); + const advertised = (configured[0].children ?? []).filter((child: any) => child.targetCompleted); + assert( + advertised.length === 1 && + canonicalShippingLabel(advertised[0].targetCompleted.label) === label, + 'CI configured leaf lacks its producing completion ID', + ); + const configuration = advertised[0].targetCompleted.configuration?.id; + assert( + /^[0-9a-f]{64}$/u.test(configuration) && index.configs.has(configuration), + 'complete CI baseline requires a producing configured checksum', + ); + const completed = index.events.filter( + (event) => + event.id?.targetCompleted && + canonicalShippingLabel(event.id.targetCompleted.label) === label && + event.id.targetCompleted.configuration?.id === configuration, + ); + assert(completed.length === 1, 'CI configured leaf lacks its successful producing completion'); + const key = `${label}\0${configuration}`; + assert(!accounted.has(key), 'duplicate completed CI root'); + accounted.add(key); + if (completed[0].aborted !== undefined) { + // Stock Bazel posts this terminal disposition for intentionally skipped + // configured targets. It is coverage accounting, never build/test proof. + assert( + completed[0].completed === undefined && + completed[0].aborted.reason === 'SKIPPED' && + (completed[0].children ?? []).length === 0, + 'CI skipped leaf lacks its explicit terminal SKIPPED disposition', + ); + continue; + } + assert( + completed[0].completed?.success === true, + 'CI configured leaf lacks its successful producing completion', + ); + const scheduled = (completed[0].children ?? []).filter((child: any) => child.testSummary); + if (scheduled.length) { + assert(scheduled.length === 1, 'CI test summary ID is ambiguous'); + const summaryId = scheduled[0].testSummary; + admittedTests.add(`${canonicalShippingLabel(summaryId.label)}\0${configuration}`); + const matches = (event: (typeof index.events)[number], field: 'testSummary' | 'testResult') => + event.id?.[field] && + canonicalShippingLabel(event.id[field].label) === canonicalShippingLabel(summaryId.label) && + event.id[field].configuration?.id === configuration; + const summaries = index.events.filter((event) => matches(event, 'testSummary')); + const results = index.events.filter((event) => matches(event, 'testResult')); + const resultKey = (id: any) => `${id.run ?? 0}:${id.shard ?? 0}:${id.attempt ?? 0}`; + const resultIds = new Set(results.map((event) => resultKey(event.id.testResult))); + const announced = (completed[0].children ?? []).filter((child: any) => child.testResult); + assert( + summaryId.configuration?.id === configuration && + summaries.length === 1 && + summaries[0].testSummary?.overallStatus === 'PASSED' && + Number(summaries[0].testSummary.totalRunCount) > 0 && + Number(summaries[0].testSummary.totalRunCount) === results.length && + results.every((event) => event.testResult?.status === 'PASSED') && + resultIds.size === results.length && + announced.length > 0 && + announced.every( + (child: any) => + canonicalShippingLabel(child.testResult.label) === + canonicalShippingLabel(summaryId.label) && + child.testResult.configuration?.id === configuration && + resultIds.has(resultKey(child.testResult)), + ), + 'complete CI baseline requires successful actual test summaries and results', + ); + } + roots.set(key, { label, configuration }); + } + assert.deepEqual( + index.completed + .map((target) => `${canonicalShippingLabel(target.label)}\0${target.configuration}`) + .sort(), + [...accounted].sort(), + 'CI producing completions differ from the expanded configured leaves', + ); + for (const event of index.events) + for (const field of ['testSummary', 'testResult'] as const) + if (event.id?.[field]) + assert( + admittedTests.has( + `${canonicalShippingLabel(event.id[field].label)}\0${event.id[field].configuration?.id}`, + ), + 'CI test evidence lacks its scheduled producing completion', + ); + return [...roots.entries()] + .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)) + .map(([, root]) => root); +} + +export async function runConfiguredRequest(request: ConfiguredRequest, workspace = process.cwd()) { + assert(['full', 'source'].includes(request.mode), 'CI request mode must be full or source'); + assert(['build', 'test'].includes(request.command), 'CI request command must be build or test'); + assert(request.targets.length > 0, 'CI request must retain its authored targets'); + const source = sourceIdentity('HEAD'); + await assertConfiguredCiSource(workspace, source); + const startup = request.startup ?? []; + const privateDirectory = + request.mode === 'full' ? mkdtempSync(path.join(tmpdir(), 'oliphaunt-ci-request-')) : undefined; + try { + const metadata = + request.mode === 'full' + ? { ...nativeBuildMetadata(source, request.github), oliphaunt_ci_request_id: request.id } + : undefined; + const bepFile = privateDirectory && path.join(privateDirectory, 'build-events.jsonl'); + const args = [ + ...startup, + request.command, + ...request.targets, + ...request.configuration, + ...(bepFile ? [`--build_event_json_file=${bepFile}`] : []), + ...Object.entries(metadata ?? {}).map(([key, value]) => `--build_metadata=${key}=${value}`), + ]; + const result = spawnSync('bash', ['tools/dev/bazel.sh', ...args], { + cwd: workspace, + stdio: ['ignore', 'inherit', 'inherit'], + }); + if (result.error) throw result.error; + if (result.status !== 0) { + try { + await assertConfiguredCiSource(workspace, source); + const diagnostics = requireSafeDirectoryChain( + path.resolve(workspace, request.outputDirectory, 'diagnostics'), + { create: true, label: 'CI failure diagnostics' }, + ); + const query = spawnSync( + 'bash', + [ + 'tools/dev/bazel.sh', + ...startup, + 'aquery', + nativeAqueryExpression(request.targets), + ...request.configuration, + ...NATIVE_AQUERY_FLAGS, + `--output_file=${path.join(diagnostics, 'failed-aquery.json')}`, + ], + { + cwd: workspace, + stdio: ['ignore', 'inherit', 'inherit'], + timeout: 300000, + killSignal: 'SIGKILL', + }, + ); + if (query.error) throw query.error; + if (query.status !== 0) + throw new Error(`CI failure aquery failed (${query.signal ?? query.status})`); + } catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + } + throw new Error(`CI ${request.command} failed (${result.signal ?? result.status})`); + } + const context = { + id: request.id, + job: request.job, + source, + github: request.github, + requires: request.requires ?? [], + outputDirectory: request.outputDirectory, + workspaceRoot: workspace, + }; + if (request.mode === 'source') { + await writeConfiguredCiSuccessReceipt(context); + } else { + const events = readFileSync(bepFile!, 'utf8') + .split(/\r?\n/u) + .filter(Boolean) + .map((line) => JSON.parse(line)); + const roots = events.filter((event) => event.workspaceInfo !== undefined); + assert( + roots.length === 1 && path.isAbsolute(roots[0].workspaceInfo.localExecRoot), + 'CI producer must report one absolute execution root', + ); + const executionRoot = roots[0].workspaceInfo.localExecRoot; + const index = nativeBuildEventIndex( + { executionRoot, buildEvents: events }, + readFileSync(path.join(workspace, '.bazelversion'), 'utf8').trim(), + metadata!, + ); + await captureConfiguredCiRequest({ + ...context, + startup, + configuration: request.configuration, + requestedTargets: request.targets, + completedRoots: completedCiRequestRoots(index, request.targets), + executionRoot, + }); + } + return path.join(request.outputDirectory, 'ci-request.json'); + } finally { + if (privateDirectory) rmSync(privateDirectory, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + try { + const { values } = parseArgs({ + options: { + id: { type: 'string' }, + job: { type: 'string' }, + mode: { type: 'string' }, + command: { type: 'string' }, + 'output-directory': { type: 'string' }, + 'startup-json': { type: 'string' }, + 'configuration-json': { type: 'string' }, + 'targets-json': { type: 'string' }, + 'requires-json': { type: 'string' }, + }, + }); + for (const key of [ + 'id', + 'job', + 'mode', + 'command', + 'output-directory', + 'configuration-json', + 'targets-json', + ] as const) + assert(values[key], `CI request requires --${key}`); + const strings = (file: string) => { + const value = JSON.parse(readFileSync(file, 'utf8')); + assert( + Array.isArray(value) && value.every((item) => typeof item === 'string'), + 'CI request JSON must be a string array', + ); + return value; + }; + const github = { + repository: process.env.GITHUB_REPOSITORY!, + workflow: process.env.GITHUB_WORKFLOW!, + workflowPath: '.github/workflows/bazel.yml', + runId: Number(process.env.GITHUB_RUN_ID), + runAttempt: Number(process.env.GITHUB_RUN_ATTEMPT), + job: process.env.GITHUB_JOB!, + }; + console.log( + await runConfiguredRequest({ + id: values.id!, + job: values.job!, + mode: values.mode as ConfiguredRequest['mode'], + command: values.command as ConfiguredRequest['command'], + outputDirectory: values['output-directory']!, + github, + startup: values['startup-json'] ? strings(values['startup-json']) : [], + configuration: strings(values['configuration-json']!), + targets: strings(values['targets-json']!), + requires: values['requires-json'] ? strings(values['requires-json']) : [], + }), + ); + } catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exitCode = 1; + } +} diff --git a/tools/ci/run-configured-request.test.mts b/tools/ci/run-configured-request.test.mts new file mode 100644 index 000000000..d617c3d3f --- /dev/null +++ b/tools/ci/run-configured-request.test.mts @@ -0,0 +1,416 @@ +import { expect, test } from 'bun:test'; +import { execFileSync, spawnSync } from 'node:child_process'; +import { + copyFileSync, + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { + NATIVE_AQUERY_FLAGS, + nativeAqueryExpression, +} from '../release/native-build-qualification.mts'; + +const runner = fileURLToPath(new URL('./run-configured-request.mts', import.meta.url)); +const metadata = fileURLToPath( + new URL('../release/native-build-qualification.mts', import.meta.url), +); +const labels = fileURLToPath(new URL('../release/bazel-shipping-inputs.mts', import.meta.url)); +const source = fileURLToPath(new URL('../release/with-source.mts', import.meta.url)); +const wrapper = fileURLToPath(new URL('../release/with-source.sh', import.meta.url)); + +function fixture(mode: string, integrated = false) { + const root = mkdtempSync(path.join(tmpdir(), 'configured-ci-request-')); + for (const directory of ['tools/ci', 'tools/dev', 'tools/release', 'tools/packaging']) + mkdirSync(path.join(root, directory), { recursive: true }); + copyFileSync(runner, path.join(root, 'tools/ci/run-configured-request.mts')); + copyFileSync(wrapper, path.join(root, 'tools/release/with-source.sh')); + copyFileSync( + new URL('../packaging/release-directory-safety.mts', import.meta.url), + path.join(root, 'tools/packaging/release-directory-safety.mts'), + ); + copyFileSync( + new URL('../release/qualified-release-replay.sh', import.meta.url), + path.join(root, 'tools/release/qualified-release-replay.sh'), + ); + writeFileSync(path.join(root, '.bazelversion'), '8.8.1\n'); + writeFileSync( + path.join(root, 'MODULE.bazel.lock'), + '{"lockFileVersion":28,"moduleExtensions":{}}', + ); + mkdirSync(path.join(root, 'fixture')); + writeFileSync(path.join(root, 'fixture/BUILD'), '# actual suite recipe'); + writeFileSync(path.join(root, 'fixture/input.rs'), 'pub fn input() {}'); + writeFileSync(path.join(root, '.gitignore'), 'output/\ncalls.jsonl\nexecroot/\n'); + for (const [name, real] of [ + ['native-build-qualification', metadata], + ['bazel-shipping-inputs', labels], + ['with-source', source], + ]) + writeFileSync( + path.join(root, `tools/release/${name}.mts`), + `export * from ${JSON.stringify(real)};\n`, + ); + writeFileSync( + path.join(root, 'tools/ci/configured-scope.mts'), + integrated + ? `export * from ${JSON.stringify(fileURLToPath(new URL('./configured-scope.mts', import.meta.url)))};\n` + : `import{writeFileSync}from'node:fs';import path from'node:path'; +export function assertConfiguredCiSource() {} +export function writeConfiguredCiSuccessReceipt(context){writeFileSync(path.join(context.outputDirectory,'ci-request.json'),JSON.stringify({...context,schema:'oliphaunt-ci-request-v1',mode:'source',status:'success'}));} +export function captureConfiguredCiRequest(context){writeFileSync(path.join(context.outputDirectory,'ci-request.json'),JSON.stringify({...context,schema:'oliphaunt-ci-request-v1',mode:'full',status:'success'}));} +`, + ); + const configuration = [ + '-c', + 'opt', + '--jobs=2', + '--config=macos-sandbox', + '--platforms=//fixture:platform', + '--repo_env=SOURCE_DIR=/fixture/path with spaces', + '--test_env=VALUE=two words', + '--test_env=RUST_TEST_THREADS=1', + ]; + const startup = ['--output_base=/fixture/short base', '--host_jvm_args=-Xmx3g']; + const targets = [ + mode.endsWith('external-root') + ? '@icu//:windows_icu_smoke_test' + : mode === 'alias-root' + ? '//fixture:test_alias' + : '//fixture:suite', + '//fixture:archive', + ]; + const output = path.join(root, 'output'); + mkdirSync(output); + for (const [name, value] of Object.entries({ + configuration, + startup, + targets, + requires: ['inputs/linux'], + })) + writeFileSync(path.join(root, `${name}.json`), JSON.stringify(value)); + writeFileSync( + path.join(root, 'tools/dev/bazel.sh'), + `#!/usr/bin/env bash\nexec '${process.execPath.replaceAll("'", "'\\''")}' tools/dev/bazel-fixture.mts "$@"\n`, + ); + writeFileSync( + path.join(root, 'tools/dev/bazel-fixture.mts'), + `import{appendFileSync,writeFileSync}from'node:fs';import path from'node:path'; +const args=process.argv.slice(2);appendFileSync('calls.jsonl',JSON.stringify(args)+'\\n'); +const command=args.find(arg=>['test','build','cquery','query','aquery'].includes(arg)); +const mode=${JSON.stringify(mode)}; +if(command==='aquery') { + if(mode==='failed-build-query-failure')process.exit(2); + writeFileSync(args.find(arg=>arg.startsWith('--output_file=')).slice(14),'{"actions":[]}');process.exit(0); +} +if(command==='cquery') {console.log(JSON.stringify({configurations:[{id:1,checksum:'c'.repeat(64)}],results:['//fixture:archive','//fixture:executed_test'].map(name=>({configurationId:1,target:{rule:{name,configuredRuleInput:[{label:'//fixture:input.rs'}]}}})).concat([{target:{sourceFile:{name:'//fixture:input.rs'}}}])}));process.exit(0);} +if(command==='query') {console.log('//fixture:BUILD');process.exit(0);} +if(mode.startsWith('failed-build'))process.exit(1); +const bep=args.find(arg=>arg.startsWith('--build_event_json_file='));if(bep){ + const configuration=mode==='opaque'?'opaque-configuration-id':'c'.repeat(64); + const testLabel=mode==='external-root'?'@icu+//:windows_icu_smoke_test':mode==='alias-root'?'//fixture:test_alias':'//fixture:executed_test'; + const summaryLabel=mode==='alias-root'?'//fixture:underlying_test':testLabel; + const tested=args.includes('test'); + const builtOnly=mode==='built-only-test'; + const skipped=mode==='incompatible'||mode.startsWith('invalid-skip-'); + const skippedLabel='//fixture:incompatible_test'; + const completedId=label=>({targetCompleted:{label,configuration:{id:configuration}}}); + const summaryId={testSummary:{label:summaryLabel,configuration:{id:configuration}}}; + const resultId={testResult:{label:summaryLabel,configuration:{id:configuration},run:1,shard:1,attempt:1}}; + const metadata=Object.fromEntries(args.filter(arg=>arg.startsWith('--build_metadata=')).map(arg=>{const value=arg.slice(17);const split=value.indexOf('=');return[value.slice(0,split),value.slice(split+1)];})); + const events=[{started:{uuid:'fixture-build',buildToolVersion:'8.8.1'}},{workspaceInfo:{localExecRoot:path.join(process.cwd(),'execroot/_main')}},{buildMetadata:{metadata}}, + {id:{pattern:{pattern:${JSON.stringify(targets)}}},children:[{targetConfigured:{label:testLabel}},{targetConfigured:{label:'//fixture:archive'}},...(builtOnly?[{targetConfigured:{label:'//fixture:built_only_test'}}]:[]),...(skipped?[{targetConfigured:{label:skippedLabel}}]:[])],expanded:{testSuiteExpansions:[{suiteLabel:'//fixture:suite',testLabels:[testLabel,'//fixture:filtered_test']}]}}, + {id:{configuration:{id:configuration}},configuration:{mnemonic:'fixture'}}, + {id:{targetConfigured:{label:testLabel}},children:[completedId(testLabel)],configured:mode==='alias-root'?{targetKind:'alias rule'}:{testSize:'SMALL'}}, + {id:{targetConfigured:{label:'//fixture:archive'}},children:[completedId('//fixture:archive')],configured:{targetKind:'archive rule'}}, + {id:completedId(testLabel),children:tested?[summaryId,resultId]:[],completed:{success:mode!=='failed-completion'}}, + {id:completedId('//fixture:archive'),completed:{success:true}}, + ...(builtOnly?[{id:{targetConfigured:{label:'//fixture:built_only_test'}},children:[completedId('//fixture:built_only_test')],configured:{testSize:'SMALL'}},{id:completedId('//fixture:built_only_test'),completed:{success:true}}]:[]), + ...(skipped?[{id:{targetConfigured:{label:skippedLabel}},children:[completedId(skippedLabel)],configured:{testSize:'SMALL'}},{id:completedId(skippedLabel),aborted:{reason:'SKIPPED',description:'Target '+skippedLabel+' build was skipped.'}}]:[]), + ...(tested?[{id:summaryId,testSummary:{overallStatus:mode==='failed-test'?'FAILED':'PASSED',totalRunCount:1}},{id:resultId,testResult:{status:'PASSED'}}]:[]), + {finished:{exitCode:{name:'SUCCESS',code:0}}},{buildMetrics:{},lastMessage:true}]; + const captured=events.filter(event=>!( + mode==='missing-completion'&&event.id?.targetCompleted?.label===testLabel|| + mode==='missing-configured'&&event.id?.targetConfigured?.label===testLabel|| + mode==='missing-build-root'&&event.id?.targetCompleted?.label==='//fixture:archive'|| + mode==='missing-summary'&&event.id?.testSummary|| + mode==='missing-result'&&event.id?.testResult|| + mode==='missing-expansion'&&event.expanded)); + if(mode==='wrong-pattern')captured.find(event=>event.expanded).id.pattern.pattern=['//fixture:other']; + if(skipped){ + const skippedEvent=captured.find(event=>event.id?.targetCompleted?.label===skippedLabel); + const skippedConfigured=captured.find(event=>event.id?.targetConfigured?.label===skippedLabel); + if(mode==='invalid-skip-missing-abort')delete skippedEvent.aborted; + if(mode==='invalid-skip-reason')skippedEvent.aborted.reason='ANALYSIS_FAILURE'; + if(mode==='invalid-skip-missing-reason')delete skippedEvent.aborted.reason; + if(mode==='invalid-skip-failed-completion')skippedEvent.completed={success:false}; + if(mode==='invalid-skip-missing-config')delete skippedConfigured.children[0].targetCompleted.configuration; + if(mode==='invalid-skip-wrong-config')skippedEvent.id.targetCompleted.configuration.id='d'.repeat(64); + if(mode==='invalid-skip-child')skippedEvent.children=[summaryId]; + if(mode==='invalid-skip-test-evidence')captured.push({id:{testSummary:{label:skippedLabel,configuration:{id:configuration}}},testSummary:{overallStatus:'FAILED',totalRunCount:1}},{id:{testResult:{label:skippedLabel,configuration:{id:configuration},run:1,shard:1,attempt:1}},testResult:{status:'FAILED'}}); + if(mode==='invalid-skip-missing-completion')captured.splice(captured.indexOf(skippedEvent),1); + } + writeFileSync(bep.slice(24),captured.map(event=>JSON.stringify(event)).join('\\n')+'\\n'); +} +`, + ); + const git = (...args: string[]) => + execFileSync('git', args, { cwd: root, encoding: 'utf8' }).trim(); + git('init', '-q'); + git('add', '.'); + git( + '-c', + 'user.name=Fixture', + '-c', + 'user.email=fixture@example.invalid', + 'commit', + '-qm', + 'fixture', + ); + return { + root, + configuration, + startup, + targets, + output, + run: (executionMode: string, command = 'test') => + spawnSync( + 'bash', + [ + 'tools/release/with-source.sh', + 'HEAD', + process.execPath, + 'tools/ci/run-configured-request.mts', + '--id', + 'portable/macos/plain', + '--job', + 'portable/macos', + '--mode', + executionMode, + '--command', + command, + '--output-directory', + output, + '--startup-json', + 'startup.json', + '--configuration-json', + 'configuration.json', + '--targets-json', + 'targets.json', + '--requires-json', + 'requires.json', + ], + { + cwd: root, + encoding: 'utf8', + env: { + ...process.env, + GITHUB_REPOSITORY: 'f0rr0/oliphaunt', + GITHUB_WORKFLOW: 'Native Bazel qualification', + GITHUB_JOB: 'portable', + GITHUB_RUN_ID: '123', + GITHUB_RUN_ATTEMPT: '1', + }, + }, + ), + calls: () => + existsSync(path.join(root, 'calls.jsonl')) + ? readFileSync(path.join(root, 'calls.jsonl'), 'utf8') + .trim() + .split('\n') + .map((line) => JSON.parse(line)) + : [], + cleanup: () => rmSync(root, { recursive: true, force: true }), + }; +} + +test('ordinary source request retains exact arrays and executes once without BEP or queries', () => { + const f = fixture('success'); + try { + const result = f.run('source'); + expect(result.status).toBe(0); + expect(f.calls()).toEqual([[...f.startup, 'test', ...f.targets, ...f.configuration]]); + const receipt = JSON.parse(readFileSync(path.join(f.output, 'ci-request.json'), 'utf8')); + expect(receipt).toMatchObject({ + id: 'portable/macos/plain', + job: 'portable/macos', + mode: 'source', + github: { job: 'portable' }, + requires: ['inputs/linux'], + }); + expect(receipt.projection).toBeUndefined(); + expect(receipt.workspaceRoot).toBe(f.root); + } finally { + f.cleanup(); + } +}); + +test('plain full and ordinary requests use the real shared capture, source guard and recorded reader', () => { + for (const [scenario, mode] of [ + ['success', 'full'], + ['incompatible', 'full'], + ['success', 'source'], + ]) { + const f = fixture(scenario, true); + try { + const result = f.run(mode); + expect(result.status, result.stderr).toBe(0); + const receipt = JSON.parse(readFileSync(path.join(f.output, 'ci-request.json'), 'utf8')); + expect(receipt.mode).toBe(mode); + expect(f.calls().filter((args) => args.includes('test'))).toHaveLength(1); + if (mode === 'full') { + expect(f.calls()).toHaveLength(3); + expect(receipt.projection.files).toEqual(['fixture/input.rs']); + expect(receipt.projection.analysisInputs).toEqual(['fixture/BUILD']); + expect(receipt.projection.roots.map((row) => row.label)).toEqual([ + '//fixture:archive', + '//fixture:executed_test', + ]); + } else { + expect(f.calls()).toHaveLength(1); + expect(receipt.projection).toBeUndefined(); + } + } finally { + f.cleanup(); + } + } +}); + +test('complete request captures actual successful suite leaves and authored suite recipes once', () => { + const f = fixture('success'); + try { + const result = f.run('full'); + expect(result.status).toBe(0); + const calls = f.calls(); + expect(calls).toHaveLength(1); + expect( + calls[0].slice(0, f.startup.length + 1 + f.targets.length + f.configuration.length), + ).toEqual([...f.startup, 'test', ...f.targets, ...f.configuration]); + const receipt = JSON.parse(readFileSync(path.join(f.output, 'ci-request.json'), 'utf8')); + expect(receipt.completedRoots).toEqual([ + { label: '//fixture:archive', configuration: 'c'.repeat(64) }, + { label: '//fixture:executed_test', configuration: 'c'.repeat(64) }, + ]); + expect(receipt.requestedTargets).toEqual(f.targets); + expect(receipt.configuration).toEqual(f.configuration); + expect(receipt.startup).toEqual(f.startup); + const privateBep = calls[0].find((arg) => arg.startsWith('--build_event_json_file=')).slice(24); + expect(existsSync(privateBep)).toBe(false); + expect(privateBep.startsWith(f.output)).toBe(false); + } finally { + f.cleanup(); + } +}); + +for (const [mode, executionMode] of [ + ['failed-build', 'full'], + ['failed-build', 'source'], + ['failed-test', 'full'], + ['missing-summary', 'full'], + ['missing-completion', 'full'], + ['missing-configured', 'full'], + ['failed-completion', 'full'], + ['missing-build-root', 'full'], + ['missing-result', 'full'], + ['missing-expansion', 'full'], + ['wrong-pattern', 'full'], + ['opaque', 'full'], + ['invalid-skip-missing-abort', 'full'], + ['invalid-skip-reason', 'full'], + ['invalid-skip-missing-reason', 'full'], + ['invalid-skip-failed-completion', 'full'], + ['invalid-skip-missing-config', 'full'], + ['invalid-skip-wrong-config', 'full'], + ['invalid-skip-child', 'full'], + ['invalid-skip-test-evidence', 'full'], + ['invalid-skip-missing-completion', 'full'], +]) + test(`failed/incomplete ${executionMode} ${mode} request never produces success or projection`, () => { + const f = fixture(mode); + try { + const result = f.run(executionMode); + expect(result.status).toBe(1); + expect(f.calls()).toHaveLength(mode === 'failed-build' ? 2 : 1); + expect(existsSync(path.join(f.output, 'ci-request.json'))).toBe(false); + const bep = f.calls()[0].find((arg) => arg.startsWith('--build_event_json_file=')); + if (executionMode === 'full') expect(existsSync(bep.slice(24))).toBe(false); + else expect(bep).toBeUndefined(); + } finally { + f.cleanup(); + } + }); + +test('plain build request keeps its command rather than silently running test', () => { + const f = fixture('success'); + try { + expect(f.run('source', 'build').status).toBe(0); + expect(f.calls()[0]).toEqual([...f.startup, 'build', ...f.targets, ...f.configuration]); + } finally { + f.cleanup(); + } +}); + +for (const mode of ['failed-build', 'failed-build-query-failure', 'failed-build-external-root']) + test(`${mode} preserves the build error and keeps its action graph diagnostic`, () => { + const f = fixture(mode); + try { + const result = f.run('full', 'build'); + expect(result.status).toBe(1); + expect(result.stderr.toString()).toContain('CI build failed (1)'); + const calls = f.calls(); + expect(calls).toHaveLength(mode === 'failed-build-external-root' ? 1 : 2); + if (mode !== 'failed-build-external-root') + expect(calls[1]).toEqual([ + ...f.startup, + 'aquery', + nativeAqueryExpression(f.targets), + ...f.configuration, + ...NATIVE_AQUERY_FLAGS, + `--output_file=${path.join(f.output, 'diagnostics/failed-aquery.json')}`, + ]); + expect(existsSync(path.join(f.output, 'diagnostics/failed-aquery.json'))).toBe( + mode === 'failed-build', + ); + expect(existsSync(path.join(f.output, 'ci-request.json'))).toBe(false); + expect(existsSync(path.join(f.output, 'analysis-deps.query'))).toBe(false); + expect(existsSync(path.join(f.output, 'evidence'))).toBe(false); + } finally { + f.cleanup(); + } + }); + +for (const [mode, command] of [ + ['built-only-test', 'test'], + ['success', 'build'], + ['external-root', 'test'], + ['alias-root', 'test'], + ['incompatible', 'test'], +]) + test(`complete ${mode} ${command} request captures every built leaf and only scheduled test evidence`, () => { + const f = fixture(mode); + try { + expect(f.run('full', command).status).toBe(0); + expect(f.calls()).toHaveLength(1); + const receipt = JSON.parse(readFileSync(path.join(f.output, 'ci-request.json'), 'utf8')); + expect(receipt.requestedTargets).toEqual(f.targets); + expect(receipt.completedRoots.map((root: { label: string }) => root.label).sort()).toEqual( + [ + mode === 'external-root' + ? '@icu+//:windows_icu_smoke_test' + : mode === 'alias-root' + ? '//fixture:test_alias' + : '//fixture:executed_test', + '//fixture:archive', + ...(mode === 'built-only-test' ? ['//fixture:built_only_test'] : []), + ].sort(), + ); + } finally { + f.cleanup(); + } + }); diff --git a/tools/ci/workflow-bazel-cache.test.mts b/tools/ci/workflow-bazel-cache.test.mts new file mode 100644 index 000000000..f1a695f4d --- /dev/null +++ b/tools/ci/workflow-bazel-cache.test.mts @@ -0,0 +1,488 @@ +import assert from 'node:assert/strict'; +import { execFileSync, spawnSync } from 'node:child_process'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; + +const root = path.resolve(import.meta.dir, '../..'); +const action = Bun.YAML.parse( + readFileSync(path.join(root, '.github/actions/bazel-cache/action.yml'), 'utf8'), +) as { + inputs: Record; + runs: { + steps: { + id?: string; + name: string; + uses?: string; + if?: string; + run?: string; + with?: { key?: string; path?: string }; + }[]; + }; +}; +const script = (name: string) => { + const step = action.runs.steps.find((step) => step.id === name || step.name === name); + assert.ok(step?.run, `missing executable cache step ${name}`); + return step.run; +}; + +// Render the actual action's output-only cache expression after executing its Shell step. +function cacheKey(name: string, output: string) { + const step = action.runs.steps.find((step) => step.id === name || step.name === name); + assert.ok(step?.with?.key); + const values = Object.fromEntries( + output + .trim() + .split('\n') + .map((line) => line.split('=')), + ); + return step.with.key.replace( + /\$\{\{\s*steps[.]identity[.]outputs[.](\w+)\s*\}\}/gu, + (_match, name) => { + assert.ok( + Object.hasOwn(values, name), + 'Cache key references an absent actual identity output', + ); + return values[name]; + }, + ); +} + +type FixtureEnvironment = NodeJS.ProcessEnv & { + HOME: string; + GITHUB_OUTPUT: string; + SHUTDOWN_ARGS: string; + COMMAND_TRACE: string; + GC_ARGS: string; + GC_TOOL: string; +}; + +function fixture(run: (directory: string, env: FixtureEnvironment) => void) { + const directory = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'bazel-cache-')); + const home = path.join(directory, 'hosted home with spaces'); + const bin = path.join(directory, 'bin'); + mkdirSync(home); + mkdirSync(bin); + const disk = path.join(home, '.cache/oliphaunt/bazel-ci/disk/cas'); + mkdirSync(disk, { recursive: true }); + writeFileSync(path.join(disk, 'retained-result'), 'completed partial cache entry'); + mkdirSync(path.join(directory, 'tools/dev'), { recursive: true }); + writeFileSync(path.join(directory, '.bazelversion'), '8.8.1\r\n'); + writeFileSync(path.join(home, '.bazelrc'), '# existing hosted configuration\n'); + writeFileSync(path.join(bin, 'git'), '#!/usr/bin/env bash\nprintf "%s\\n" "$SOURCE_COMMIT"\n', { + mode: 0o755, + }); + writeFileSync( + path.join(bin, 'cygpath'), + '#!/usr/bin/env bash\ntest "$1" = -m\ncase "${2##*/}" in disk) printf "%s\\n" "C:/hosted home/bazel-ci/disk" ;; *) printf "%s\\n" "C:/hosted home/bazel-ci" ;; esac\n', + { mode: 0o755 }, + ); + writeFileSync( + path.join(bin, 'du'), + `#!/usr/bin/env bash\ntest "\${2##*/}" = disk\nsize="$DISK_KIB"\n[[ ! -f "$DISK_SIZE_FILE" ]] || size="$(cat "$DISK_SIZE_FILE")"\nprintf "%s\\t%s\\n" "$size" "$2"\n`, + { mode: 0o755 }, + ); + writeFileSync( + path.join(directory, 'tools/dev/bazel.sh'), + `#!/usr/bin/env bash +set -eu +for argument in "$@"; do + case "$argument" in build|cquery|shutdown) fixture_command="$argument"; break ;; esac +done +printf '%s\\n' "$fixture_command" >> "$COMMAND_TRACE" +case "$fixture_command" in + build) printf '%s\\n' "$@" > "$BUILD_ARGS"; exit "$BUILD_STATUS" ;; + cquery) printf '%s\\n' "$@" > "$QUERY_ARGS"; printf '%s\\n' "$GC_TOOL"; exit "$QUERY_STATUS" ;; + shutdown) + printf '%s\\n' "$@" > "$SHUTDOWN_ARGS" + fixture_shutdowns=0 + while read -r fixture_line; do + [[ "$fixture_line" != shutdown ]] || fixture_shutdowns=$((fixture_shutdowns + 1)) + done < "$COMMAND_TRACE" + [[ "$fixture_shutdowns" != 2 ]] || exit "$SECOND_SHUTDOWN_STATUS" + exit "$SHUTDOWN_STATUS" ;; +esac +`, + ); + const gcTool = path.join(bin, 'stock gc fixture'); + writeFileSync( + gcTool, + `#!/usr/bin/env bash +set -eu +test "$(tail -n 1 "$COMMAND_TRACE")" = shutdown +test -z "\${JAVABIN:-}" +printf '%s\\n' "$@" > "$GC_ARGS" +printf 'gc begin\\n' >> "$COMMAND_TRACE" +if [[ "$GC_STATUS" != 0 ]]; then exit "$GC_STATUS"; fi +sleep 0.03 +printf '%s\\n' "$GC_DISK_KIB" > "$DISK_SIZE_FILE" +printf 'gc done\\n' >> "$COMMAND_TRACE" +`, + { mode: 0o755 }, + ); + const output = path.join(directory, 'outputs'); + writeFileSync(output, ''); + const env = { + ...Object.fromEntries( + ['TMPDIR', 'TMP', 'TEMP', 'SYSTEMROOT', 'SystemRoot'].flatMap((key) => + process.env[key] === undefined ? [] : [[key, process.env[key]]], + ), + ), + HOME: home, + PATH: `${bin}${path.delimiter}${process.env.PATH}`, + GITHUB_OUTPUT: output, + RUNNER_OS: 'Linux', + RUNNER_ARCH: 'X64', + PHASE: 'restore', + COHORT: 'react-native', + SOURCE_COMMIT: 'a'.repeat(40), + OUTPUT_BASE: '', + JVM_ARGS: '', + SERVER_LOG: '', + DISK_KIB: '1', + SHUTDOWN_ARGS: path.join(directory, 'shutdown-args'), + SHUTDOWN_STATUS: '0', + SECOND_SHUTDOWN_STATUS: '0', + COMMAND_TRACE: path.join(directory, 'command-trace'), + GC_ARGS: path.join(directory, 'gc-args'), + GC_TOOL: gcTool, + GC_STATUS: '0', + GC_DISK_KIB: '1', + DISK_SIZE_FILE: path.join(directory, 'disk-size'), + BUILD_ARGS: path.join(directory, 'build-args'), + BUILD_STATUS: '0', + QUERY_ARGS: path.join(directory, 'query-args'), + QUERY_STATUS: '0', + }; + try { + run(directory, env); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +} + +// Supply the same internal outputs that Actions passes between the real Shell steps. +function selectedBudget(directory: string, env: NodeJS.ProcessEnv) { + const output = path.join(directory, 'budget-outputs'); + writeFileSync(output, ''); + execFileSync('bash', ['-eu', '-c', script('identity')], { + cwd: directory, + env: { ...env, GITHUB_OUTPUT: output }, + }); + const selected = Object.fromEntries( + readFileSync(output, 'utf8') + .trim() + .split('\n') + .map((line) => line.split('=')), + ); + return { + ...env, + GC_MAX_SIZE: selected.gc_max_size, + CACHE_LIMIT_KIB: selected.cache_limit_kib, + }; +} + +const execute = (directory: string, env: NodeJS.ProcessEnv, source: string) => + execFileSync('bash', ['-eu', '-c', source], { + cwd: directory, + env: source === script('identity') ? env : selectedBudget(directory, env), + encoding: 'utf8', + }); + +test('optional terminal cache saves preserve restore policy, writer bounds and source identity', () => { + const workflow = Bun.YAML.parse( + readFileSync(path.join(root, '.github/workflows/bazel.yml'), 'utf8'), + ); + const callers = Object.values(workflow.jobs).flatMap((job: any) => + job.steps.filter((step: any) => step.uses === './.github/actions/bazel-cache'), + ); + for (const step of callers) { + for (const name of Object.keys(step.with)) + assert.ok(Object.hasOwn(action.inputs, name), `Unknown cache action input: ${name}`); + } + const transports = action.runs.steps.filter((step) => step.uses?.startsWith('actions/cache/')); + assert.equal(transports.length, 2); + for (const step of transports) assert.equal(step.with?.path, '~/.cache/oliphaunt/bazel-ci/disk'); + assert.equal( + action.runs.steps.find((step) => step.id === 'ready')?.if, + '$' + + "{{ always() && inputs.phase == 'save' && steps.identity.outcome == 'success' && inputs.disk-cache-hit != 'true' }}", + ); + assert.equal( + action.runs.steps.find((step) => step.id === 'identity')?.if, + '$' + "{{ inputs.phase == 'save' || !cancelled() }}", + ); + assert.equal( + action.runs.steps.find((step) => step.id === 'disk-restore')?.if, + "inputs.phase == 'restore'", + ); + assert.equal( + action.runs.steps.find((step) => step.name === 'Configure standard hosted Bazel caches')?.if, + "inputs.phase == 'restore'", + ); + assert.equal( + action.runs.steps.find((step) => step.name === 'Save bounded Bazel action cache')?.if, + '$' + "{{ always() && inputs.phase == 'save' && steps.ready.outputs.disk == 'true' }}", + ); + const saves = callers.filter((step: any) => step.with.phase === 'save'); + assert.equal(saves.length, 8); + for (const step of saves) { + assert.equal(step['timeout-minutes'], 10); + assert.equal(step['continue-on-error'], true); + assert.equal(step.if, '$' + '{{ always() }}'); + } +}); + +test('action keys retain source, cohort and platform separation', () => { + fixture((directory, env) => { + const identities = []; + for (const variation of [ + {}, + { SOURCE_COMMIT: 'b'.repeat(40) }, + { COHORT: 'linux' }, + { RUNNER_OS: 'macOS', RUNNER_ARCH: 'ARM64' }, + ]) { + writeFileSync(env.GITHUB_OUTPUT, ''); + execute(directory, { ...env, ...variation }, script('identity')); + identities.push(readFileSync(env.GITHUB_OUTPUT, 'utf8')); + } + assert.equal(new Set(identities).size, identities.length); + assert.match(identities[0], /-react-native-8\.8\.1\nsource=a{40}\n/u); + assert.equal( + new Set(identities.map((identity) => cacheKey('disk-restore', identity))).size, + identities.length, + ); + assert.equal( + cacheKey('disk-restore', identities[0]), + cacheKey('Save bounded Bazel action cache', identities[0]), + ); + for (const variation of [ + { PHASE: 'unknown' }, + { COHORT: 'portable/../linux' }, + { SOURCE_COMMIT: 'invalid' }, + ]) { + const rejected = spawnSync('bash', ['-eu', '-c', script('identity')], { + cwd: directory, + env: { ...env, ...variation }, + }); + assert.notEqual(rejected.status, 0); + } + }); +}); + +test('hosted cache configuration preserves user rc and quotes portable native paths', () => { + const cacheConfiguration = readFileSync(path.join(root, '.bazelrc'), 'utf8') + .split('\n') + .filter((line) => /^build:ci-cache\s/u.test(line)) + .join('\n'); + assert.doesNotMatch(cacheConfiguration, /--experimental_disk_cache_gc_/u); + for (const runnerOS of ['Linux', 'macOS', 'Windows']) { + fixture((directory, env) => { + execute( + directory, + { ...env, RUNNER_OS: runnerOS }, + script('Configure standard hosted Bazel caches'), + ); + const rc = readFileSync(path.join(env.HOME, '.bazelrc'), 'utf8'); + assert.ok(rc.startsWith('# existing hosted configuration\n')); + const cacheRoot = + runnerOS === 'Windows' + ? 'C:/hosted home/bazel-ci' + : `${env.HOME}/.cache/oliphaunt/bazel-ci`; + assert.ok(rc.includes(`build --disk_cache="${cacheRoot}/disk"\n`)); + assert.ok(rc.includes(`common --repository_cache="${cacheRoot}/repositories"\n`)); + assert.doesNotMatch(rc, /--experimental_disk_cache_gc_/u); + }); + } +}); + +test('cache freeze stops exactly the configured writer before the action archive size decision', () => { + for (const scenario of [ + { name: 'default base', disk: '1', expected: ['disk=true'] }, + { name: 'at allocated budget', disk: '3145728', expected: ['disk=true'] }, + { name: 'observed WASIX allocation overhead', disk: '2118144', expected: ['disk=true'] }, + { name: 'action oversize', disk: '3145729', expected: [] }, + { name: 'malformed action size', disk: 'invalid', expected: [] }, + { name: 'missing action cache', disk: '1', missing: true, expected: [] }, + { name: 'allocated empty cache', disk: '4', empty: true, expected: [] }, + { name: 'directory-only cache', disk: '8', empty: true, nested: true, expected: [] }, + { name: 'unused macOS cache', disk: '4', empty: true, os: 'macOS', expected: [] }, + { name: 'unused Windows cache', disk: '4', empty: true, os: 'Windows', expected: [] }, + { name: 'failed shutdown', disk: '1', shutdown: '1', expected: [] }, + ]) { + fixture((directory, env) => { + const hosted = { ...env, RUNNER_OS: scenario.os ?? env.RUNNER_OS }; + execute(directory, hosted, script('Configure standard hosted Bazel caches')); + const disk = path.join(env.HOME, '.cache/oliphaunt/bazel-ci/disk'); + if (scenario.empty) { + rmSync(disk, { recursive: true }); + mkdirSync(scenario.nested ? path.join(disk, 'cas/empty') : disk, { recursive: true }); + } + if (scenario.missing) rmSync(disk, { recursive: true }); + const explicit = scenario.name !== 'default base'; + const outputBase = explicit ? path.join(directory, 'selected output base') : ''; + const serverLog = explicit ? path.join(directory, 'server output.log') : ''; + execute( + directory, + { + ...hosted, + OUTPUT_BASE: outputBase, + JVM_ARGS: explicit ? '-Xmx3g' : '', + SERVER_LOG: serverLog, + DISK_KIB: scenario.disk, + GC_DISK_KIB: scenario.disk, + SHUTDOWN_STATUS: scenario.shutdown ?? '0', + }, + script('ready'), + ); + assert.deepEqual( + readFileSync(env.SHUTDOWN_ARGS, 'utf8').trim().split('\n'), + explicit + ? [ + `--output_base=${outputBase}`, + '--host_jvm_args=-Xmx3g', + `--server_jvm_out=${serverLog}`, + 'shutdown', + ] + : ['shutdown'], + scenario.name, + ); + if (scenario.disk !== '3145729') + assert.equal(readFileSync(env.COMMAND_TRACE, 'utf8'), 'shutdown\n', scenario.name); + assert.deepEqual( + readFileSync(env.GITHUB_OUTPUT, 'utf8').trim().split('\n').filter(Boolean), + scenario.expected, + scenario.name, + ); + }); + } +}); + +test('oversized snapshots use completed stock GC after freezing its utility writer', () => { + for (const runnerOS of ['Linux', 'macOS', 'Windows']) { + fixture((directory, env) => { + execute(directory, env, script('Configure standard hosted Bazel caches')); + execute( + directory, + { + ...env, + RUNNER_OS: runnerOS, + DISK_KIB: '5865772', + GC_DISK_KIB: '2118144', + JAVABIN: '/ambient/java', + }, + script('ready'), + ); + assert.equal( + readFileSync(env.COMMAND_TRACE, 'utf8'), + 'shutdown\nbuild\ncquery\nshutdown\ngc begin\ngc done\n', + ); + assert.equal(readFileSync(env.GITHUB_OUTPUT, 'utf8'), 'disk=true\n'); + assert.deepEqual(readFileSync(env.GC_ARGS, 'utf8').trim().split('\n'), [ + `--disk_cache=${runnerOS === 'Windows' ? 'C:/hosted home/bazel-ci/disk' : path.join(env.HOME, '.cache/oliphaunt/bazel-ci/disk')}`, + '--max_size=2G', + ]); + assert.deepEqual( + readFileSync(path.join(directory, 'build-args'), 'utf8').trim().split('\n'), + ['build', '--jobs=2', '//tools/ci:bazel_disk_cache_gc'], + ); + }); + } +}); + +test('GC failures and logical-versus-allocated overage do not authorize transport', () => { + for (const scenario of [ + { BUILD_STATUS: '1' }, + { QUERY_STATUS: '1' }, + { SECOND_SHUTDOWN_STATUS: '1' }, + { GC_STATUS: '1' }, + { GC_DISK_KIB: '3145729' }, + { GC_DISK_KIB: 'invalid' }, + ]) { + fixture((directory, env) => { + execute(directory, env, script('Configure standard hosted Bazel caches')); + const result = spawnSync('bash', ['-eu', '-c', script('ready')], { + cwd: directory, + env: selectedBudget(directory, { ...env, DISK_KIB: '5865772', ...scenario }), + }); + if (scenario.BUILD_STATUS || scenario.QUERY_STATUS || scenario.GC_STATUS) + assert.notEqual(result.status, 0); + assert.equal(readFileSync(env.GITHUB_OUTPUT, 'utf8'), ''); + }); + } +}); + +test('measured cohorts retain their observed cache population within a bounded archive', () => { + for (const cohort of [ + { RUNNER_OS: 'macOS', RUNNER_ARCH: 'ARM64', COHORT: 'portable' }, + { RUNNER_OS: 'Linux', RUNNER_ARCH: 'X64', COHORT: 'portable' }, + { RUNNER_OS: 'Linux', RUNNER_ARCH: 'X64', COHORT: 'linux' }, + ]) { + for (const scenario of [ + { name: '3.6 GiB allocated snapshot', disk: '3774874', gc: false, saved: true }, + { name: 'allocated boundary', disk: '5242880', gc: false, saved: true }, + { + name: 'completed collection', + disk: '5242881', + gc: true, + collected: '4404019', + saved: true, + }, + { + name: 'allocated overage after collection', + disk: '5242881', + gc: true, + collected: '5242881', + saved: false, + }, + { name: 'failed collection', disk: '5242881', gc: true, status: '1', saved: false }, + ]) { + fixture((directory, env) => { + const label = `${cohort.COHORT} ${cohort.RUNNER_OS} ${scenario.name}`; + const measured = { ...env, ...cohort }; + execute(directory, measured, script('Configure standard hosted Bazel caches')); + const result = spawnSync('bash', ['-eu', '-c', script('ready')], { + cwd: directory, + env: selectedBudget(directory, { + ...measured, + DISK_KIB: scenario.disk, + GC_DISK_KIB: scenario.collected ?? scenario.disk, + GC_STATUS: scenario.status ?? '0', + }), + }); + assert.equal(result.status, scenario.status ? 1 : 0, label); + assert.equal( + readFileSync(env.GITHUB_OUTPUT, 'utf8'), + scenario.saved ? 'disk=true\n' : '', + label, + ); + const commands = readFileSync(env.COMMAND_TRACE, 'utf8'); + if (scenario.gc) { + assert.ok(commands.startsWith('shutdown\nbuild\ncquery\nshutdown\ngc begin\n'), label); + assert.equal( + readFileSync(env.GC_ARGS, 'utf8').trim().split('\n').at(-1), + '--max_size=4G', + ); + } else { + assert.equal(commands, 'shutdown\n', label); + } + }); + } + } +}); + +test('other Apple cohorts keep the standard hosted cache budget', () => { + fixture((directory, env) => { + const other = { + ...env, + RUNNER_OS: 'macOS', + RUNNER_ARCH: 'ARM64', + COHORT: 'react-native', + }; + execute(directory, other, script('Configure standard hosted Bazel caches')); + execute(directory, { ...other, DISK_KIB: '3565159', GC_DISK_KIB: '2118144' }, script('ready')); + assert.equal(readFileSync(env.GC_ARGS, 'utf8').trim().split('\n').at(-1), '--max_size=2G'); + assert.equal(readFileSync(env.GITHUB_OUTPUT, 'utf8'), 'disk=true\n'); + }); +}); diff --git a/tools/ci/workflow-lint.mts b/tools/ci/workflow-lint.mts new file mode 100644 index 000000000..3faffe4eb --- /dev/null +++ b/tools/ci/workflow-lint.mts @@ -0,0 +1,60 @@ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { readdirSync } from 'node:fs'; +import path from 'node:path'; + +export function runWorkflowLinters(root: string, tools: string[], capture = false) { + assert.equal(tools.length, 3, 'Expected declared actionlint, zizmor and ShellCheck Files'); + const [actionlint, zizmor, shellcheck] = tools.map((file) => path.resolve(file)); + const workflows = readdirSync(path.join(root, '.github/workflows')) + .filter((file) => /[.]ya?ml$/u.test(file)) + .sort() + .map((file) => path.join(root, '.github/workflows', file)); + assert(workflows.length > 0, 'Workflow qualification needs declared workflow sources'); + const commands = [ + [ + actionlint, + '-shellcheck', + shellcheck, + '-pyflakes', + '', + '-ignore', + 'unexpected key "queue" for "concurrency" section', + ...workflows, + ], + [ + zizmor, + '--offline', + '--config', + path.join(root, '.github/zizmor.yml'), + '--min-severity', + 'medium', + '--persona', + 'auditor', + path.join(root, '.github/workflows'), + path.join(root, '.github/actions'), + ], + ]; + for (const [binary, ...args] of commands) { + const result = spawnSync(binary, args, { + cwd: root, + env: { PATH: '/usr/bin:/bin', LANG: 'C.UTF-8' }, + stdio: capture ? 'pipe' : 'inherit', + encoding: 'utf8', + }); + if (result.error) throw result.error; + assert( + result.status !== null && !result.signal, + 'Workflow linter terminated without an exit status', + ); + if (result.status !== 0) + return { status: result.status, stdout: result.stdout ?? '', stderr: result.stderr ?? '' }; + } + return { status: 0, stdout: '', stderr: '' }; +} + +if (import.meta.main) + process.exitCode = runWorkflowLinters( + path.resolve(import.meta.dir, '../..'), + Bun.argv.slice(2), + ).status; diff --git a/tools/ci/workflow-lint.test.mts b/tools/ci/workflow-lint.test.mts new file mode 100644 index 000000000..9df26d081 --- /dev/null +++ b/tools/ci/workflow-lint.test.mts @@ -0,0 +1,38 @@ +import assert from 'node:assert/strict'; +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { runWorkflowLinters } from './workflow-lint.mts'; + +const tools = process.argv.slice(2); +assert.equal(tools.length, 3, 'Expected actual declared workflow linter tools'); +{ + const root = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'workflow-lint-')); + try { + mkdirSync(path.join(root, '.github/workflows'), { recursive: true }); + mkdirSync(path.join(root, '.github/actions'), { recursive: true }); + writeFileSync(path.join(root, '.github/zizmor.yml'), 'rules: {}\n'); + const safe = + 'name: Fixture\non: pull_request\npermissions:\n contents: read\njobs:\n verify:\n runs-on: ubuntu-24.04\n steps:\n - name: Exercise shell\n run: printf "%s\\n" safe\n'; + const file = path.join(root, '.github/workflows/fixture.yml'); + for (const [source, valid] of [ + [safe, true], + [safe.replace('contents: read', 'contents: write'), false], + [safe.replace('runs-on: ubuntu-24.04', 'needs: missing\n runs-on: ubuntu-24.04'), false], + [ + safe.replace( + 'printf "%s\\n" safe', + 'echo ' + '$' + '{{ github.event.pull_request.title }}', + ), + false, + ], + [safe.replace('printf "%s\\n" safe', 'echo $MISSING_SHELL_VARIABLE'), false], + ] as const) { + writeFileSync(file, source); + const result = runWorkflowLinters(root, tools, true); + assert.equal(result.status === 0, valid, result.stderr + result.stdout); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +} diff --git a/tools/ci/workflow-moon-transfers.test.mts b/tools/ci/workflow-moon-transfers.test.mts index 57e8f0aa1..f986ff3ad 100644 --- a/tools/ci/workflow-moon-transfers.test.mts +++ b/tools/ci/workflow-moon-transfers.test.mts @@ -1,16 +1,20 @@ #!/usr/bin/env bun import assert from 'node:assert/strict'; +import { execFileSync, spawnSync } from 'node:child_process'; import { chmodSync, existsSync, mkdirSync, + mkdtempSync, readFileSync, readlinkSync, + rmSync, statSync, symlinkSync, writeFileSync, } from 'node:fs'; +import { tmpdir } from 'node:os'; import path from 'node:path'; import test from 'node:test'; import { @@ -30,6 +34,64 @@ const tasks = new Map( ]), ); +if (!process.env.OLIPHAUNT_TRANSFER_FIXTURE_PHASE) + test('WASIX source lifecycle server inputs resolve in the Moon execution hasher', () => { + const scratch = mkdtempSync(path.join(tmpdir(), 'oliphaunt-moon-inputs-')); + const serverRoot = '/src/wasix/pgwire-server/'; + const inputs = tasks + .get('oliphaunt-wasix-rust:test-regression') + .inputs.map((input) => (typeof input === 'string' ? input : (input.file ?? input.glob))) + .filter((input) => input?.startsWith(serverRoot)); + try { + mkdirSync(path.join(scratch, '.moon')); + mkdirSync(path.join(scratch, 'fixture')); + writeFileSync(path.join(scratch, '.moon/workspace.yml'), 'projects:\n fixture: fixture\n'); + for (const file of ['Cargo.toml', 'README.md', 'src/lib.rs', 'tests/support/mod.rs']) { + const destination = path.join(scratch, serverRoot, file); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, 'fixture\n'); + } + const configure = (taskInputs) => + writeFileSync( + path.join(scratch, 'fixture/moon.yml'), + JSON.stringify({ + language: 'bash', + tasks: { qualify: { command: 'true', inputs: taskInputs } }, + }), + ); + configure(inputs); + const git = (args) => execFileSync('git', args, { cwd: scratch, stdio: 'pipe' }); + git(['init', '--quiet', '--initial-branch=main']); + git(['add', '.']); + git([ + '-c', + 'user.name=Fixture', + '-c', + 'user.email=fixture@example.invalid', + '-c', + 'commit.gpgsign=false', + 'commit', + '--quiet', + '-m', + 'fixture', + ]); + // Moon tasks inherit their parent's workspace; this proof owns a separate one. + const env = { ...process.env, MOON_CACHE: 'off', MOON_WORKSPACE_ROOT: scratch }; + delete env.MOON_BASE; + delete env.MOON_HEAD; + const run = () => + spawnSync( + process.env.MOON_BIN ?? 'moon', + ['run', 'fixture:qualify', '--upstream', 'none', '--no-actions'], + { cwd: scratch, env, encoding: 'utf8' }, + ); + const result = run(); + assert.equal(result.status, 0, result.stdout + result.stderr); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } + }); + if (!process.env.OLIPHAUNT_TRANSFER_FIXTURE_PHASE) test('Rust source uploads follow their selected package producers', () => { for (const step of workflow.jobs['rust-sdk-package'].steps) { diff --git a/tools/ci/workflow-native-bazel.test.mts b/tools/ci/workflow-native-bazel.test.mts new file mode 100644 index 000000000..64dfaaffd --- /dev/null +++ b/tools/ci/workflow-native-bazel.test.mts @@ -0,0 +1,1574 @@ +import assert from 'node:assert/strict'; +import { execFileSync, spawnSync } from 'node:child_process'; +import { + cpSync, + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import { runInNewContext } from 'node:vm'; + +const workflow = Bun.YAML.parse( + readFileSync(path.resolve(import.meta.dir, '../../.github/workflows/bazel.yml'), 'utf8'), +) as { env: Record; jobs: Record }; +const { jobs } = workflow; +const needs = (id: string): string[] => + jobs[id].needs === undefined + ? [] + : Array.isArray(jobs[id].needs) + ? jobs[id].needs + : [jobs[id].needs]; + +function requestEnvironment(step: any, env: NodeJS.ProcessEnv, platform: string) { + return { + ...env, + CI_PLATFORM: platform, + ...Object.fromEntries( + Object.entries(step.env ?? {}) + .filter(([name]) => name.startsWith('CI_')) + .map(([name, value]) => [ + name, + String(value).replace(/\$\{\{\s*matrix\.platform\s*\}\}/gu, platform), + ]), + ), + }; +} + +function predecessors(id: string, active = new Set()): Set { + assert.ok(Object.hasOwn(jobs, id), `Unknown native workflow prerequisite: ${id}`); + assert.ok(!active.has(id), `Native workflow dependency cycle: ${id}`); + const stack = new Set(active).add(id); + return new Set(needs(id).flatMap((parent) => [parent, ...predecessors(parent, stack)])); +} + +test('native AOT hosts consume source-bound side-module and tools inputs and stay required', () => { + assert.ok(predecessors('required').has('wasix-host')); + assert.ok(predecessors('wasix-host').has('wasix')); + const host = jobs['wasix-host'].steps.find((step: any) => + step.run?.includes('EXPECTED_SOURCE_COMMIT'), + ); + assert.ok(host.run.includes('//src/wasix/sdks/rust:postgres_regression_test')); + assert.ok(host.run.includes('//build_defs/wasix:host_aot_smoke_test')); + assert.ok( + host.run.includes('"--repo_env=OLIPHAUNT_WASIX_SOURCE_COMMIT=$EXPECTED_SOURCE_COMMIT"'), + ); + assert.ok( + host.run.includes('"--repo_env=OLIPHAUNT_WASIX_CARGO_INPUTS=$RUNNER_TEMP/wasix-cargo-inputs"'), + ); + const capture = jobs.wasix.steps.find( + (step: any) => step.name === 'Capture final WASIX Cargo inputs for native hosts', + ); + const expression = capture.run.match(/jq '([\s\S]*?)' /u)?.[1]; + assert.ok(expression, 'WASIX construction capture needs its actual source-owned root filter'); + const expected = [ + ['liboliphaunt-wasix', 'liboliphaunt-wasix-portable'], + ['liboliphaunt-wasix', 'liboliphaunt-wasix-aot-aarch64-apple-darwin'], + ['liboliphaunt-wasix', 'oliphaunt-extension-contrib-pg18-wasix'], + ['liboliphaunt-wasix', 'oliphaunt-extension-contrib-pg18-aot-macos-arm64'], + ['postgres-tools-wasix', 'oliphaunt-wasix-tools'], + ['postgres-tools-wasix', 'oliphaunt-wasix-tools-aot-aarch64-apple-darwin'], + ].map(([product, name]) => ({ package: { product, name, ecosystem: 'cargo' } })); + const source = { commit: '1'.repeat(40), tree: '2'.repeat(40) }; + const cohort = { + executionRoot: '/actual/execution/root', + aquery: { actions: [] }, + roots: [ + ...expected, + { package: { product: 'oliphaunt-wasix-rust', name: 'oliphaunt-wasix', ecosystem: 'cargo' } }, + { + package: { + product: 'liboliphaunt-wasix', + name: 'liboliphaunt-wasix-portable', + ecosystem: 'npm', + }, + }, + { + package: { product: 'different-owner', name: 'oliphaunt-wasix-tools', ecosystem: 'cargo' }, + }, + ], + }; + const filtered = JSON.parse( + execFileSync('jq', [expression], { + input: JSON.stringify({ source, cohorts: [cohort] }), + encoding: 'utf8', + }), + ); + assert.deepEqual(filtered, [{ ...cohort, source, roots: expected }]); +}); + +test('NAPI shipping shares the Linux WASIX producer and imported native host lanes', () => { + const name = 'Qualify final WASIX addon on its native host'; + assert.ok(!jobs.portable.steps.some((step: any) => step.name === name)); + const producer = jobs.wasix.steps.find((step: any) => + step.run?.includes('--shipping-export //:wasix_shipping_export'), + ); + assert.equal(producer.env.CI_REQUEST_ID, 'wasix/tools-sdk-browser'); + const root = readFileSync(path.resolve(import.meta.dir, '../../BUILD.bazel'), 'utf8'); + const wasix = root.match(/shipping_export\(\s*name = "wasix_shipping_export",([\s\S]*?)\n\)/u); + assert.ok(wasix, 'missing actual WASIX shipping export'); + assert.ok(wasix[1].includes('"//src/wasix/node-addon:release_shipping_export"')); + assert.ok(wasix[1].includes('"//src/wasix/sdks/rust:napi_release_compiled_shipping_export"')); + assert.ok(wasix[1].includes('"//src/wasix/pgwire-server:napi_release_compiled_shipping_export"')); + const combined = root.match( + /shipping_export\(\s*name = "wasix_napi_shipping_export",([\s\S]*?)\n\)/u, + ); + assert.ok(combined, 'missing combined NAPI and compiled SDK export'); + assert.ok(combined[1].includes('"//src/wasix/node-addon:release_shipping_export"')); + assert.ok(combined[1].includes('"//src/wasix/sdks/rust:napi_release_compiled_shipping_export"')); + assert.ok( + combined[1].includes('"//src/wasix/pgwire-server:napi_release_compiled_shipping_export"'), + ); + const host = jobs['wasix-host'].steps.find((step: any) => step.name === name); + assert.ok(host, 'imported host NAPI qualification is missing'); + assert.equal(host.env.CI_REQUEST_ID, 'wasix-host/${{ matrix.platform }}/napi'); + assert.deepEqual(JSON.parse(host.env.CI_REQUIRES), ['wasix/tools-sdk-browser']); + assert.deepEqual( + JSON.parse(workflow.env.CI_FULL_MATRICES) + ['wasix-host'].map((row: any) => row.platform) + .sort(), + ['linux-arm64', 'macos-arm64', 'windows-x64'], + ); + const authentication = jobs['wasix-host'].steps.find( + (step: any) => step.name === 'Authenticate current WASIX constructor inputs', + ); + assert.ok(authentication, 'missing authenticated current WASIX constructor inputs'); + assert.ok(authentication.run.includes(`jq -nc '["oliphaunt-wasix-rust"]'`)); + assert.ok( + authentication.run.includes('--consumer-products-json "$input_root/consumer-products.json"'), + ); + assert.ok(authentication.run.includes('--stage-release-archives --run-id "$GITHUB_RUN_ID"')); + assert.ok(authentication.run.includes('with-source.sh HEAD')); + assert.ok(authentication.if.includes('needs.release-inputs.outputs.ci_selected_jobs')); + assert.ok(authentication.if.includes("format('wasix-host/{0}', matrix.platform)")); + assert.equal(authentication['continue-on-error'], undefined); + for (const consumer of [ + host, + jobs['wasix-host'].steps.find( + (step: any) => step.name === 'Qualify imported AOT runtime on its native host', + ), + ]) + assert.ok( + jobs['wasix-host'].steps.indexOf(authentication) < jobs['wasix-host'].steps.indexOf(consumer), + ); +}); + +test('native package consumers follow their producers and remain required for admission', () => { + for (const id of Object.keys(jobs)) predecessors(id); + assert.ok(predecessors('react-native').has('portable')); + assert.ok(predecessors('react-native').has('release-inputs')); + assert.ok(!predecessors('release-families').has('react-native')); + const required = predecessors('required'); + for (const [id, job] of Object.entries(jobs)) { + if (job.steps.some((step: any) => step.run?.includes('qualify-native-shipping.mts'))) + assert.ok(required.has(id), `Native shipping producer omitted from admission: ${id}`); + } + const admission = jobs.required.steps.find( + (step: any) => step.name === 'Require every native qualification job', + ); + for (const [subject, outcome] of [ + ['', 'success'], + ['react-native', 'failure'], + ['release-families', 'failure'], + ['wasix-host', 'failure'], + ['react-native', 'skipped'], + ['release-families', 'skipped'], + ['wasix-host', 'skipped'], + ]) { + const results = Object.fromEntries( + needs('required').map((id) => [id, { result: id === subject ? outcome : 'success' }]), + ); + const result = spawnSync('bash', ['-eu', '-c', admission.run], { + env: { ...process.env, NEEDS_JSON: JSON.stringify(results) }, + }); + assert.equal(result.status === 0, subject === '', result.stderr.toString()); + } + const consumer = jobs['react-native']; + assert.ok( + consumer.if.includes( + "contains(fromJSON(needs.release-inputs.outputs.ci_selected_jobs), 'react-native')", + ), + ); + const qualify = consumer.steps.filter((step: any) => + step.run?.includes('qualify-native-shipping.mts'), + ); + assert.equal(qualify.length, 1); + assert.ok(qualify[0].if.includes('env.CI_REQUEST_ID')); + assert.equal(qualify[0]['continue-on-error'], undefined); + assert.deepEqual( + [...qualify[0].run.matchAll(/--shipping-export\s+(\S+)/gu)].map((match) => match[1]), + ['//:native_react_native_shipping_export'], + ); + const evidence = consumer.steps.filter( + (step: any) => step.with?.name === 'native-build-evidence-react-native-macos-arm64', + ); + assert.equal(evidence.length, 1); + assert.ok(evidence[0].if.includes("ci_mode == 'full'")); + assert.ok(evidence[0].if.includes("ci_capture_requests), 'react-native/installed-consumer'")); + assert.equal(evidence[0].with['if-no-files-found'], 'error'); + const linux = jobs.linux.steps.map((step: any) => step.run ?? '').join('\n'); + for (const name of ['package_test', 'installed_consumer_test']) + assert.ok(!linux.includes(`//src/native/sdks/react-native:${name}`)); + assert.ok(linux.includes('//src/native/sdks/react-native:lifecycle_test')); + const source = readFileSync(path.resolve(import.meta.dir, '../../BUILD.bazel'), 'utf8'); + const exports = (owner: string) => { + const declaration = source.match( + new RegExp(`shipping_export\\(\\n\\s*name = "${owner}",\\n([\\s\\S]*?)\\n\\)`, 'u'), + ); + assert.ok(declaration, `Missing source-owned shipping export: ${owner}`); + return new Set([...declaration[1].matchAll(/"((?:\/\/|:)[^"\n]+)"/gu)].map((row) => row[1])); + }; + const early = exports('native_shipping_export'); + const publicSource = exports('public_source_shipping_export'); + const family = exports('release_family_shipping_export'); + const sourceOwners = [ + '//src/native/rust-bindings:shipping_export', + '//src/native/sdks/rust:shipping_export', + '//src/native/sdks/rust/crates/oliphaunt-build:shipping_export', + '//src/native/broker:shipping_export', + ]; + assert.deepEqual([...publicSource].sort(), [...sourceOwners].sort()); + assert.ok(family.has(':public_source_shipping_export')); + for (const owner of sourceOwners) { + assert.ok( + !early.has(owner), + `Cargo source owner escaped its separate source qualification: ${owner}`, + ); + assert.ok( + !family.has(owner), + `Cargo source export was duplicated in its full aggregate: ${owner}`, + ); + } + for (const producer of [ + 'portable', + 'linux', + 'wasix', + 'postmaster', + 'postmaster-host', + 'wasix-host', + 'release-inputs', + ]) + assert.ok(predecessors('release-families').has(producer)); + for (const owner of [ + '//src/native/rust-bindings:compiled_shipping_export', + '//src/native/broker:native_shipping_export', + '//src/query/rust:shipping_export', + '//src/query/ts:shipping_export', + ]) + assert.ok(early.has(owner), `Early source/compiled owner was unnecessarily deferred: ${owner}`); + for (const [id, job] of Object.entries(jobs)) { + if (id === 'release-families') continue; + const commands = job.steps.map((step: any) => step.run ?? '').join('\n'); + assert.ok(!commands.includes('//build_defs/languages/installed:consumer_test')); + assert.ok(!commands.includes('//build_defs/languages/installed:consumer_minimum_test')); + } + const sourceStep = jobs['release-families'].steps.find((step: any) => + step.run?.includes('--shipping-export //:public_source_shipping_export'), + ); + const familyStep = jobs['release-families'].steps.find((step: any) => + step.run?.includes('--shipping-export //:release_family_shipping_export'), + ); + assert.equal(sourceStep.env.CI_REQUEST_ID, 'release-families/public-source'); + assert.equal(sourceStep.env.CI_REQUIRES, undefined); + assert.equal(sourceStep.env.CI_FULL_ONLY, undefined); + assert.equal(familyStep.env.CI_REQUEST_ID, 'release-families/checksums'); + assert.equal(familyStep.env.CI_FULL_ONLY, 'true'); + assert.equal(JSON.parse(familyStep.env.CI_REQUIRES).length, 13); + for (const mode of ['source', 'full']) + qualifierFixture((directory, env) => { + const execute = (step: any, shippingExport: string) => { + const result = spawnSync('bash', ['-eu', '-c', step.run], { + cwd: directory, + env: { + ...requestEnvironment(step, env, 'x86_64'), + CI_REQUEST_JOB: 'release-families', + CI_MODE: mode, + }, + }); + assert.equal(result.status, 0, result.stderr.toString()); + const args = readFileSync(env.QUALIFIER_ARGS, 'utf8').split('\0'); + const argument = (flag: string) => args[args.indexOf(flag) + 1]; + assert.equal(argument('--shipping-export'), shippingExport); + assert.equal(argument('--ci-request-id'), step.env.CI_REQUEST_ID); + assert.equal(argument('--ci-job'), 'release-families'); + assert.equal(argument('--ci-mode'), mode); + assert.equal( + JSON.parse(readFileSync(argument('--github-json'), 'utf8')).job, + 'Native release families', + ); + assert.deepEqual( + JSON.parse(readFileSync(argument('--ci-requires-json'), 'utf8')), + JSON.parse(step.env.CI_REQUIRES ?? '[]'), + ); + assert.ok( + existsSync( + path.join(env.RUNNER_TEMP, 'ci-requests', step.env.CI_REQUEST_ID, 'ci-request.json'), + ), + ); + return JSON.parse(readFileSync(argument('--configuration-json'), 'utf8')) as string[]; + }; + const configuration = execute(sourceStep, '//:public_source_shipping_export'); + assert.deepEqual(configuration, [ + '-c', + 'opt', + '--platforms=//build_defs/native:linux_x86_64_glibc_2_28', + '--host_platform=//build_defs/native:linux_x86_64_glibc_2_28', + '--jobs=2', + ]); + if (mode === 'full') { + const complete = execute(familyStep, '//:release_family_shipping_export'); + assert.deepEqual(complete, configuration); + assert.ok( + existsSync( + path.join( + env.RUNNER_TEMP, + 'ci-requests/release-families/public-source/ci-request.json', + ), + ), + ); + } + }); +}); + +test('release-family archive acquisition is full-only while source qualification permits unrelated skipped jobs', () => { + const family = jobs['release-families']; + const acquisition = family.steps.find( + (step: any) => step.name === "Authenticate this run's completed archive producers", + ); + const sourceQualification = family.steps.find( + (step: any) => step.env?.CI_REQUEST_ID === 'release-families/public-source', + ); + assert.ok(acquisition); + assert.ok(sourceQualification); + assert.ok( + family.steps.indexOf(acquisition) < family.steps.indexOf(sourceQualification), + 'authenticate producer archives before source qualification so both family phases share inputs', + ); + const aggregate = family.steps.find( + (step: any) => step.env?.CI_REQUEST_ID === 'release-families/checksums', + ); + const evidence = family.steps.filter((step: any) => + step.with?.name?.startsWith('native-build-evidence-'), + ); + assert.equal(evidence.length, 1); + assert.equal(evidence[0].with.name, 'native-build-evidence-release-families'); + assert.equal(evidence[0].with.path, '${{ runner.temp }}/release-family-build-capture/evidence/'); + const evaluate = (expression: string, mode: string, requests: string[], results: string[]) => + runInNewContext( + expression + .replace(/^\$\{\{\s*|\s*\}\}$/gu, '') + .replaceAll('needs.release-inputs', 'inputs') + .replaceAll('needs.*.result', 'results'), + { + inputs: { + result: 'success', + outputs: { + ci_mode: mode, + ci_selected_requests: JSON.stringify(requests), + ci_selected_jobs: JSON.stringify(requests.length ? ['release-families'] : []), + }, + }, + results, + env: aggregate.env, + cancelled: () => false, + contains: (values: string[], value: string) => values.includes(value), + fromJSON: JSON.parse, + }, + ); + const source = ['release-families/public-source']; + const full = [...source, 'release-families/checksums']; + assert.equal(evaluate(family.if, 'source', source, ['success', 'skipped']), true); + for (const result of ['failure', 'cancelled']) + assert.equal(evaluate(family.if, 'source', source, ['success', result]), false); + assert.equal(evaluate(family.if, 'source', [], ['success', 'skipped']), false); + for (const step of [acquisition, aggregate, evidence[0]]) { + assert.equal(evaluate(step.if, 'source', source, ['success', 'skipped']), false); + assert.equal(evaluate(step.if, 'source', full, ['success']), false); + assert.equal(evaluate(step.if, 'full', source, ['success']), false); + assert.equal(evaluate(step.if, 'full', full, ['success']), true); + } +}); + +test('WASIX probes share the complete opt qualification invocation', () => { + const steps = jobs.wasix.steps.filter( + (step: any) => + step.run?.includes('qualify-native-shipping.mts') || + step.run?.includes('tools/dev/bazel.sh test'), + ); + qualifierFixture((directory, env) => { + const calls = path.join(directory, 'wasix-calls'); + const chrome = path.join(directory, 'chrome'); + mkdirSync(env.RUNNER_TEMP, { recursive: true }); + writeFileSync(path.join(directory, 'tools/dev/bazel.sh'), 'exit 71\n'); + writeFileSync( + path.join(directory, 'tools/dev/bun.sh'), + `#!/usr/bin/env bash +printf '%s\\n' "$1" >> "$WASIX_CALLS" +case "$1" in + build_defs/wasix/browser/chrome-receipt.mts) + printf '{}\\n' > "$2" + printf '%s\\n' "$WASIX_CHROME" ;; + tools/release/qualify-native-shipping.mts) + printf '%s\\0' "$@" > "$QUALIFIER_ARGS" + printf '%s\\n' "$OLIPHAUNT_NATIVE_PUBLICATION_INPUTS" > "$QUALIFIER_SOURCE" + previous='' + for argument in "$@"; do + if [[ "$previous" == --output-directory ]]; then + mkdir -p "$argument" + printf '{}\\n' > "$argument/ci-request.json" + fi + previous="$argument" + done + exit "\${QUALIFIER_STATUS:-0}" ;; + *) exit 72 ;; +esac +`, + ); + const execute = (status = '0') => + spawnSync('bash', ['-eu', '-c', steps.map((step: any) => step.run).join('\n')], { + cwd: directory, + env: { + ...env, + QUALIFICATION_JOB_NAME: jobs.wasix.name, + WASIX_CALLS: calls, + WASIX_CHROME: chrome, + QUALIFIER_STATUS: status, + OLIPHAUNT_NATIVE_PUBLICATION_INPUTS: path.join(directory, 'native-inputs.json'), + ImageOS: 'ubuntu24', + ImageVersion: 'fixture', + }, + }); + const result = execute(); + assert.equal(result.status, 0, result.stderr.toString()); + assert.deepEqual(readFileSync(calls, 'utf8').trim().split('\n'), [ + 'build_defs/wasix/browser/chrome-receipt.mts', + 'tools/release/qualify-native-shipping.mts', + ]); + const args = readFileSync(env.QUALIFIER_ARGS, 'utf8').split('\0'); + const argument = (flag: string) => args[args.indexOf(flag) + 1]; + assert.equal(argument('--shipping-export'), '//:wasix_shipping_export'); + assert.deepEqual(JSON.parse(readFileSync(argument('--complete-products-json'), 'utf8')), [ + 'postgres-tools-wasix', + ]); + assert.deepEqual(JSON.parse(readFileSync(argument('--targets-json'), 'utf8')), [ + '//build_defs/wasix:bridge_abi_test', + '//build_defs/wasix:initdb_shim_abi_test', + '//build_defs/wasix/postmaster:source_modes_test', + ]); + const configuration = JSON.parse(readFileSync(argument('--configuration-json'), 'utf8')); + assert.deepEqual(configuration.slice(0, 3), ['-c', 'opt', '--config=wasix-aot']); + assert.ok(!configuration.some((flag: string) => flag.startsWith('--jobs='))); + assert.ok(configuration.includes('--local_test_jobs=1')); + assert.ok(configuration.includes('--test_env=RUST_TEST_THREADS=1')); + for (const flag of [ + '--platforms=//build_defs/native:linux_x86_64_glibc_2_28', + '--host_platform=//build_defs/native:linux_x86_64_glibc_2_28', + '--test_env=OLIPHAUNT_WASM_AOT_VERIFY=full', + `--test_env=OLIPHAUNT_BROWSER_CHROME=${chrome}`, + '--test_env=OLIPHAUNT_BROWSER_CHROME_RECEIPT=' + + path.join(env.RUNNER_TEMP, 'chrome-host.json'), + ]) + assert.ok(configuration.includes(flag), `Missing WASIX qualification option: ${flag}`); + assert.ok(existsSync(path.join(env.RUNNER_TEMP, 'chrome-host.json'))); + assert.equal( + readFileSync(env.QUALIFIER_SOURCE, 'utf8').trim(), + path.join(directory, 'native-inputs.json'), + ); + assert.equal(execute('7').status, 7); + }); +}); + +test('private Rust packaging source tests execute once on Linux x64', () => { + const label = '//src/native/runtime/packaging:source_tests'; + const callers = Object.entries(jobs).flatMap(([id, job]) => + job.steps.filter((step: any) => step.run?.includes(label)).map((step: any) => ({ id, step })), + ); + assert.equal(callers.length, 1); + assert.equal(callers[0].id, 'linux'); + const { step } = callers[0]; + assert.ok(step.if.includes("matrix.platform == 'x86_64'")); + assert.ok(step.if.includes('env.CI_REQUEST_ID')); + assert.equal(step['continue-on-error'], undefined); + qualifierFixture((directory, env) => { + const argsFile = path.join(env.RUNNER_TEMP, 'args'); + writeFileSync( + path.join(directory, 'tools/dev/bun.sh'), + `#!/usr/bin/env bash +[[ "$1" == tools/ci/run-configured-request.mts ]] || exit 71 +while [[ "$#" -gt 1 ]]; do + case "$1" in + --command) command="$2" ;; + --targets-json) targets="$2" ;; + --configuration-json) configuration="$2" ;; + --startup-json) startup="$2" ;; + --output-directory) output="$2" ;; + esac + shift +done +mapfile -t startup_args < <(jq -r '.[]' "$startup") +mapfile -t target_args < <(jq -r '.[]' "$targets") +mapfile -t config_args < <(jq -r '.[]' "$configuration") +printf '%s\\0' "\${startup_args[@]}" "$command" "\${target_args[@]}" "\${config_args[@]}" > "$SOURCE_ARGS" +mkdir -p "$output" +printf '{}\\n' > "$output/ci-request.json" +exit "\${SOURCE_STATUS:-0}" +`, + ); + const execute = (status = '0') => + spawnSync('bash', ['-eu', '-c', step.run], { + cwd: directory, + env: { + ...requestEnvironment(step, env, 'x86_64'), + SOURCE_ARGS: argsFile, + SOURCE_STATUS: status, + }, + }); + const passed = execute(); + assert.equal(passed.status, 0, passed.stderr.toString()); + const args = readFileSync(argsFile, 'utf8').split('\0'); + assert.equal(args[0], 'test'); + assert.equal(args.filter((value) => value === label).length, 1); + assert.ok(args.includes('--platforms=//build_defs/native:linux_x86_64_glibc_2_28')); + assert.equal(execute('7').status, 7); + }); +}); + +test('merge queue guards use resolved release commit facts and still reject unauthorized version changes', () => { + const steps = jobs['release-inputs'].steps; + const contextIndex = steps.findIndex((step: any) => step.id === 'context'); + const guardIndex = steps.findIndex( + (step: any) => step.name === 'Check release-owned source versions', + ); + const acquireIndex = steps.findIndex( + (step: any) => step.name === 'Acquire completed public inputs once', + ); + assert.ok(contextIndex >= 0 && contextIndex < guardIndex && guardIndex < acquireIndex); + const step = steps[guardIndex]; + assert.equal(step.if, undefined); + assert.equal(step.env.SOURCE_POLICY_HEAD, '$' + '{{ steps.context.outputs.source_policy_head }}'); + qualifierFixture((directory, env) => { + mkdirSync(path.join(directory, '.github/scripts'), { recursive: true }); + mkdirSync(path.join(directory, 'bin')); + symlinkSync(process.execPath, path.join(directory, 'bin/bun')); + for (const file of ['check-release-intent.sh', 'release-intent-data.mts']) + cpSync( + path.resolve(import.meta.dir, '../../.github/scripts', file), + path.join(directory, '.github/scripts', file), + ); + const git = (...args: string[]) => + execFileSync('git', args, { cwd: directory, encoding: 'utf8' }).trim(); + const commit = (subject: string) => { + git('add', '.'); + git('-c', 'user.name=Fixture', '-c', 'user.email=fixture@invalid', 'commit', '-qm', subject); + return git('rev-parse', 'HEAD'); + }; + writeFileSync( + path.join(directory, 'release-please-config.json'), + JSON.stringify({ 'changelog-sections': [{ type: 'fix' }] }), + ); + writeFileSync( + path.join(directory, '.release-please-manifest.json'), + JSON.stringify({ owner: '1.0.0' }), + ); + const base = commit('fix: source'); + const baseTree = git('rev-parse', 'HEAD^{tree}'); + writeFileSync( + path.join(directory, '.release-please-manifest.json'), + JSON.stringify({ owner: '1.0.1' }), + ); + const prepared = commit('chore(release): owner 1.0.1'); + const queued = (tree: string) => + git( + '-c', + 'user.name=Fixture', + '-c', + 'user.email=fixture@invalid', + 'commit-tree', + tree, + '-p', + base, + '-m', + 'Merge queue synthetic title', + ); + const releaseQueue = queued(git('rev-parse', 'HEAD^{tree}')); + const ordinaryQueue = queued(baseTree); + const execute = (head: string, policy = {}) => + spawnSync('bash', ['-eu', '-c', step.run], { + cwd: directory, + env: { + ...env, + PATH: `${path.join(directory, 'bin')}${path.delimiter}${env.PATH}`, + PR_TITLE: '', + BASE_REF: base, + HEAD_REF: head, + HEAD_BRANCH: 'gh-readonly-queue/main/pr-295-aabbcc', + CI_EVENT_NAME: 'merge_group', + CI_FULL_REF: 'refs/heads/gh-readonly-queue/main/pr-295-aabbcc', + SOURCE_POLICY_SUBJECT: '', + SOURCE_POLICY_BASE: '', + SOURCE_POLICY_HEAD: '', + SOURCE_POLICY_BRANCH: '', + ...policy, + }, + }); + const ordinary = execute(ordinaryQueue); + assert.equal(ordinary.status, 0, ordinary.stderr.toString()); + assert.notEqual(execute(releaseQueue).status, 0); + const policy = { + SOURCE_POLICY_SUBJECT: 'chore(release): owner 1.0.1', + SOURCE_POLICY_BASE: base, + SOURCE_POLICY_HEAD: prepared, + SOURCE_POLICY_BRANCH: 'release-please--branches--main', + }; + const release = execute(releaseQueue, policy); + assert.equal(release.status, 0, release.stderr.toString()); + assert.notEqual( + execute(releaseQueue, { ...policy, SOURCE_POLICY_BRANCH: 'feature' }).status, + 0, + ); + }); +}); + +type FixtureEnvironment = NodeJS.ProcessEnv & { + RUNNER_TEMP: string; + QUALIFIER_ARGS: string; + QUALIFIER_SOURCE: string; +}; + +function qualifierFixture(run: (directory: string, env: FixtureEnvironment) => void) { + const directory = mkdtempSync(path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'native-workflow-')); + const env = { + PATH: process.env.PATH, + RUNNER_TEMP: path.join(directory, 'runner temp'), + GITHUB_WORKSPACE: directory, + GITHUB_REPOSITORY: 'f0rr0/oliphaunt', + GITHUB_WORKFLOW: 'Native Bazel qualification', + GITHUB_RUN_ID: '123', + GITHUB_RUN_ATTEMPT: '1', + CI_REQUEST_ID: 'fixture/qualification', + CI_REQUEST_JOB: 'fixture', + CI_MODE: 'full', + CI_CAPTURE_REQUESTS: '[]', + CI_SELECTED_REQUESTS: '["fixture/qualification"]', + QUALIFICATION_JOB_NAME: 'Portable packages (macos-arm64)', + QUALIFIER_ARGS: path.join(directory, 'qualifier-args'), + QUALIFIER_SOURCE: path.join(directory, 'qualifier-source'), + }; + mkdirSync(path.join(directory, 'tools/dev'), { recursive: true }); + writeFileSync( + path.join(directory, 'tools/dev/bun.sh'), + `#!/usr/bin/env bash +printf '%s\\0' "$@" > "$QUALIFIER_ARGS" +printf '%s\\n' "\${OLIPHAUNT_MOBILE_CANDIDATE_CHECKOUT-}" "\${OLIPHAUNT_MOBILE_CANDIDATE_SHA-}" "\${OLIPHAUNT_MOBILE_CANDIDATE_TREE-}" > "$QUALIFIER_SOURCE" +previous='' +for argument in "$@"; do + if [[ "$previous" == --output-directory ]]; then + mkdir -p "$argument" + printf '{}\\n' > "$argument/ci-request.json" + fi + previous="$argument" +done +`, + ); + mkdirSync(path.join(directory, 'tools/release'), { recursive: true }); + writeFileSync( + path.join(directory, 'tools/release/with-source.sh'), + readFileSync(path.resolve(import.meta.dir, '../release/with-source.sh')), + ); + const git = (...args: string[]) => + execFileSync('git', args, { cwd: directory, env, stdio: 'pipe' }); + git('init', '--quiet'); + git('add', 'tools'); + git( + '-c', + 'user.name=Workflow fixture', + '-c', + 'user.email=fixture@invalid', + 'commit', + '--quiet', + '-m', + 'fixture', + ); + try { + run(directory, env); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +} + +test('Apple preparation and final admission use the authenticated input phase', () => { + const step = jobs.portable.steps.find( + (step: any) => + step.name === 'Qualify complete Apple runtime, resources, SDK and extension packages', + ); + assert.equal( + step.env.NATIVE_PREPARED_INPUTS, + '$' + '{{ needs.release-inputs.outputs.native_inputs }}', + ); + for (const [input, target] of [ + ['false', '//:native_apple_preparation_export'], + ['true', '//:native_apple_shipping_export'], + ['unverified', undefined], + ]) { + qualifierFixture((directory, env) => { + const result = spawnSync('bash', ['-eu', '-c', step.run], { + cwd: directory, + env: { ...requestEnvironment(step, env, 'macos-arm64'), NATIVE_PREPARED_INPUTS: input }, + }); + if (!target) { + assert.notEqual(result.status, 0); + return; + } + assert.equal(result.status, 0, result.stderr.toString()); + const args = readFileSync(env.QUALIFIER_ARGS, 'utf8').split('\0'); + assert.equal(args[args.indexOf('--shipping-export') + 1], target); + }); + } +}); + +test('Android qualification constructs ARM and installs the exact x64 APK once', () => { + const step = jobs.linux.steps.find((step: any) => + step.run?.includes('--shipping-export //:native_android_shipping_export'), + ); + assert.ok(step.if.includes("matrix.platform == 'x86_64'")); + assert.ok(step.if.includes('env.CI_REQUEST_ID')); + assert.equal(step['continue-on-error'], undefined); + qualifierFixture((directory, env) => { + const requestEnv = requestEnvironment(step, env, 'x86_64'); + const result = spawnSync('bash', ['-eu', '-c', step.run], { cwd: directory, env: requestEnv }); + assert.equal(result.status, 0, result.stderr.toString()); + const args = readFileSync(env.QUALIFIER_ARGS, 'utf8').split('\0'); + const targets = JSON.parse(readFileSync(args[args.indexOf('--targets-json') + 1], 'utf8')); + for (const label of [ + '//src/examples/native/react-native-expo:android_release', + '//src/examples/native/react-native-expo:autolinking_consumer_test', + '//src/examples/native/react-native-expo:android_installed_test', + ]) + assert.equal(targets.filter((target: string) => target === label).length, 1); + assert.ok(!targets.includes('//src/examples/native/react-native-expo:android_release_x86_64')); + const configuration = JSON.parse( + readFileSync( + path.join(env.RUNNER_TEMP, 'android-extension-build-inputs/configuration.json'), + 'utf8', + ), + ); + assert.ok(configuration.every((flag: string) => !flag.startsWith('--test_env='))); + const git = (...args: string[]) => + execFileSync('git', args, { cwd: directory, env, encoding: 'utf8' }).trim(); + assert.deepEqual(readFileSync(env.QUALIFIER_SOURCE, 'utf8').trim().split('\n'), [ + directory, + git('rev-parse', 'HEAD'), + git('rev-parse', 'HEAD^{tree}'), + ]); + writeFileSync(path.join(directory, 'tools/dev/bun.sh'), '# tracked mutation\n'); + assert.notEqual( + spawnSync('bash', ['-eu', '-c', step.run], { cwd: directory, env: requestEnv }).status, + 0, + ); + assert.ok(predecessors('required').has('linux')); + }); +}); + +test('Required audits completed construction only after every producer succeeds', () => { + const required = jobs.required; + const [guard, checkout, runtime, inputs, audit] = required.steps; + assert.equal(required.steps.length, 5); + assert.equal(guard.env.NEEDS_JSON, '$' + '{{ toJSON(needs) }}'); + assert.match(checkout.uses, /^actions\/checkout@[0-9a-f]{40}$/u); + assert.equal(checkout.with.ref, '$' + '{{ github.event.pull_request.head.sha || github.sha }}'); + assert.equal(checkout.with['persist-credentials'], false); + assert.equal(runtime.uses, './.github/actions/setup-node-bun'); + assert.equal(inputs.uses, './.github/actions/native-release-inputs'); + assert.deepEqual( + inputs.with, + jobs.linux.steps.find((step: any) => step.uses === inputs.uses).with, + ); + assert.equal(audit.env.GH_TOKEN, '$' + '{{ github.token }}'); + for (const step of required.steps) { + assert.equal(step.if, undefined); + assert.equal(step['continue-on-error'], undefined); + } + qualifierFixture((directory, env) => { + const wrapperArgs = path.join(directory, 'wrapper-args'); + const acquisition = path.join(directory, 'acquisition-started'); + const snapshot = path.join(directory, 'native-inputs.json'); + mkdirSync(path.join(directory, 'tools/release'), { recursive: true }); + writeFileSync( + path.join(directory, 'tools/release/with-source.sh'), + `#!/usr/bin/env bash +printf '%s\\0' "$@" > "$AUDIT_WRAPPER_ARGS" +shift +exec "$@" +`, + ); + writeFileSync( + path.join(directory, 'tools/dev/bun.sh'), + `#!/usr/bin/env bash +printf '%s\\0' "$@" > "$QUALIFIER_ARGS" +printf '%s\\n' "$OLIPHAUNT_NATIVE_PUBLICATION_INPUTS" > "$QUALIFIER_SOURCE" +exit "\${AUDIT_STATUS:-0}" +`, + ); + const execute = (result: string, status = '0') => { + for (const file of [wrapperArgs, acquisition, env.QUALIFIER_ARGS, env.QUALIFIER_SOURCE]) + rmSync(file, { force: true }); + return spawnSync( + 'bash', + ['-eu', '-c', `${guard.run}\nprintf acquired > "$AUDIT_ACQUISITION"\n${audit.run}`], + { + cwd: directory, + env: { + ...env, + NEEDS_JSON: JSON.stringify( + Object.fromEntries( + needs('required').map((id, index) => [ + id, + { result: index === 1 ? result : 'success' }, + ]), + ), + ), + GITHUB_REF: 'refs/pull/42/merge', + OLIPHAUNT_NATIVE_PUBLICATION_INPUTS: snapshot, + AUDIT_WRAPPER_ARGS: wrapperArgs, + AUDIT_ACQUISITION: acquisition, + AUDIT_STATUS: status, + }, + }, + ); + }; + const passed = execute('success'); + assert.equal(passed.status, 0, passed.stderr.toString()); + assert.equal(readFileSync(wrapperArgs, 'utf8').split('\0')[0], 'HEAD'); + assert.deepEqual(readFileSync(env.QUALIFIER_ARGS, 'utf8').split('\0').slice(0, -1), [ + 'tools/release/audit-native-construction.mts', + '--run-id', + env.GITHUB_RUN_ID, + '--ref', + 'refs/pull/42/merge', + '--output-directory', + path.join(env.RUNNER_TEMP, 'native-construction-audit'), + ]); + assert.equal(readFileSync(env.QUALIFIER_SOURCE, 'utf8').trim(), snapshot); + for (const result of ['failure', 'cancelled', 'skipped']) { + assert.notEqual(execute(result).status, 0); + assert.equal(existsSync(acquisition), false); + assert.equal(existsSync(wrapperArgs), false); + } + assert.equal(execute('success', '7').status, 7); + }); +}); + +test('React Native qualification retains diagnostics within its job budget', () => { + const job = jobs['react-native']; + const qualifier = job.steps.find((step: any) => + step.run?.includes('--shipping-export //:native_react_native_shipping_export'), + ); + const diagnostics = job.steps.find( + (step: any) => step.name === 'Upload React Native build and query diagnostics', + ); + const cache = job.steps.find((step: any) => step.name === 'Save bounded standard Bazel caches'); + assert.ok( + qualifier['timeout-minutes'] + diagnostics['timeout-minutes'] + cache['timeout-minutes'] < + job['timeout-minutes'], + 'qualification must leave job time for authentication, diagnostics and cleanup', + ); + assert.equal(diagnostics.if, 'always()'); + const capture = qualifier.run.match(/--output-directory "\$RUNNER_TEMP\/([^"\n]+)"/u)?.[1]; + assert.ok(capture, 'qualification must declare its capture directory'); + for (const file of ['diagnostics/', 'build-events.jsonl', 'aquery-build-events.jsonl']) + assert.ok(diagnostics.with.path.includes(`/${capture}/${file}`)); + assert.ok(diagnostics.with.path.includes('/native-bazel/command.log')); + assert.equal(diagnostics.with['if-no-files-found'], 'ignore'); + assert.equal(cache.if, '${{ always() }}'); + assert.ok(job.steps.indexOf(qualifier) < job.steps.indexOf(diagnostics)); + assert.ok(job.steps.indexOf(diagnostics) < job.steps.indexOf(cache)); +}); + +test('only the installed mobile test receives the actual clean candidate checkout identity', () => { + const step = jobs['react-native'].steps.find( + (step: any) => step.name === 'Qualify final React Native package and installed iOS consumer', + ); + qualifierFixture((directory, env) => { + mkdirSync(path.join(env.RUNNER_TEMP, 'react-native-build-inputs'), { recursive: true }); + const execute = () => spawnSync('bash', ['-eu', '-c', step.run], { cwd: directory, env }); + const passed = execute(); + assert.equal(passed.status, 0, passed.stderr.toString()); + const git = (...args: string[]) => + execFileSync('git', args, { cwd: directory, env, encoding: 'utf8' }).trim(); + assert.deepEqual(readFileSync(env.QUALIFIER_SOURCE, 'utf8').trim().split('\n'), [ + directory, + git('rev-parse', 'HEAD'), + git('rev-parse', 'HEAD^{tree}'), + ]); + const configuration = JSON.parse( + readFileSync( + path.join(env.RUNNER_TEMP, 'react-native-build-inputs/configuration.json'), + 'utf8', + ), + ); + assert.ok(configuration.every((flag: string) => !flag.startsWith('--test_env='))); + writeFileSync(path.join(directory, 'tools/dev/bun.sh'), '# tracked mutation\n'); + assert.notEqual(execute().status, 0); + }); +}); + +test('the Linux installed APK owns its emulator and requires provisioned KVM', () => { + const step = jobs.linux.steps.find( + (step: any) => step.name === 'Provision KVM for the exact installed Android APK test', + ); + assert.ok(step.if.includes("matrix.platform == 'x86_64'")); + assert.ok(step.if.includes("format('linux/{0}/android-packages', matrix.platform)")); + assert.equal(step['continue-on-error'], undefined); + assert.ok(step.run.includes('test -c /dev/kvm')); + assert.ok(step.run.includes('test -r /dev/kvm && test -w /dev/kvm')); + assert.ok(!step.run.includes('sdkmanager') && !step.run.includes('emulator -')); +}); + +test('native qualification supports protected merge groups with the same required construction gate', () => { + const source = Bun.YAML.parse( + readFileSync(path.resolve(import.meta.dir, '../../.github/workflows/bazel.yml'), 'utf8'), + ) as any; + assert.deepEqual(source.on.merge_group.types, ['checks_requested']); + assert.equal(jobs.required.name, 'Required'); + assert.ok(predecessors('required').has('release-inputs')); +}); + +test('postmaster host scheduling keeps native tests serial and Linux guest inputs unchanged', () => { + const job = jobs['postmaster-host']; + const diagnostics = job.steps.find( + (step: any) => step.name === 'Upload native postmaster build and query diagnostics', + ); + assert.equal(diagnostics.if, 'always()'); + assert.equal( + diagnostics.with.path, + '$' + '{{ runner.temp }}/postmaster-build-capture/diagnostics/', + ); + assert.equal( + job['timeout-minutes'], + '$' + "{{ matrix.platform == 'macos-arm64' && 180 || 120 }}", + ); + const step = job.steps.find( + (step: any) => step.name === 'Qualify native carrier from authenticated Linux guest', + ); + const authentication = job.steps.find( + (step: any) => step.name === 'Authenticate current Linux postmaster constructor inputs', + ); + assert.ok(authentication, 'missing authenticated current Linux postmaster constructor inputs'); + assert.ok(authentication.run.includes(`'["liboliphaunt-wasix-postmaster"]'`)); + assert.ok(authentication.run.includes('with-source.sh HEAD')); + assert.ok(authentication.run.includes('--stage-release-archives --run-id "$GITHUB_RUN_ID"')); + assert.ok(authentication.run.includes('--ref "$GITHUB_REF"')); + assert.ok( + authentication.run.includes('--consumer-products-json "$input_root/consumer-products.json"'), + ); + assert.ok(authentication.if.includes('needs.release-inputs.outputs.ci_selected_requests')); + assert.ok( + authentication.if.includes("format('postmaster-host/{0}/carrier-lifecycle', matrix.platform)"), + ); + assert.equal(authentication['continue-on-error'], undefined); + assert.ok(job.steps.indexOf(authentication) < job.steps.indexOf(step)); + assert.ok( + !job.steps.some((candidate: any) => candidate.uses?.startsWith('actions/download-artifact@')), + ); + assert.ok(!step.run.includes('native-build-files')); + assert.deepEqual(JSON.parse(step.env.CI_REQUIRES), ['postmaster/linux-carrier-lifecycle']); + const start = step.run.indexOf('archive="$(jq'); + const end = step.run.indexOf('ci_arguments=(', start); + assert.ok(start >= 0 && end > start, 'Missing actual archive and host configuration selection'); + qualifierFixture((directory, env) => { + const inputRoot = path.join(directory, 'host inputs'); + mkdirSync(inputRoot); + const snapshot = path.join(inputRoot, 'native-publication-inputs.json'); + const archive = path.join(directory, 'original-linux-x64-gnu.tar.zst'); + const canonical = { + product: 'liboliphaunt-wasix-postmaster', + artifact: 'github-release:postmaster:postmaster-linux-x64-gnu.tar.zst', + file: { path: archive }, + }; + const artifacts = [ + { ...canonical, product: 'another-product' }, + { ...canonical, artifact: 'github-release:postmaster:postmaster-macos-arm64.tar.zst' }, + { ...canonical, artifact: 'untrusted:postmaster:postmaster-linux-x64-gnu.tar.zst' }, + canonical, + ]; + const execute = (platform: string, compiler: string, prefix: string, current = artifacts) => { + writeFileSync(snapshot, JSON.stringify({ nativeCurrentArtifacts: current })); + return spawnSync( + 'bash', + ['-eu', '-c', `input_root="$HOST_INPUT_ROOT"\n${step.run.slice(start, end)}`], + { + cwd: directory, + env: { + ...requestEnvironment(step, env, platform), + HOST_INPUT_ROOT: inputRoot, + OLIPHAUNT_NATIVE_PUBLICATION_INPUTS: snapshot, + TARGET_PLATFORM: platform, + TARGET_COMPILER: compiler, + TARGET_PREFIX: prefix, + }, + }, + ); + }; + for (const platform of ['macos-arm64', 'linux-arm64']) { + const compiler = + platform === 'macos-arm64' + ? '//src/wasix/postmaster:native_macos_arm64' + : '//src/wasix/postmaster:compiler_linux_arm64'; + const prefix = platform === 'macos-arm64' ? 'macos_arm64' : 'linux_arm64_gnu'; + const result = execute(platform, compiler, prefix); + assert.equal(result.status, 0, result.stderr.toString()); + assert.deepEqual( + JSON.parse(readFileSync(path.join(inputRoot, 'configuration.json'), 'utf8')), + [ + '-c', + 'opt', + '--platforms=//build_defs/wasix:portable', + `--host_platform=${compiler}`, + `--extra_execution_platforms=${compiler}`, + platform === 'macos-arm64' ? '--jobs=2' : '--jobs=1', + '--local_test_jobs=1', + `--repo_env=OLIPHAUNT_POSTMASTER_GUEST_ARCHIVE=${archive}`, + ...(platform === 'macos-arm64' ? ['--config=macos-sandbox'] : []), + ], + `${platform} actual qualification configuration`, + ); + assert.deepEqual(JSON.parse(readFileSync(path.join(inputRoot, 'targets.json'), 'utf8')), [ + `//src/wasix/postmaster:${prefix}_public_archive_test`, + `//src/wasix/postmaster:${prefix}_runtime_test`, + ]); + assert.deepEqual(JSON.parse(readFileSync(path.join(inputRoot, 'ci-requires.json'), 'utf8')), [ + 'postmaster/linux-carrier-lifecycle', + ]); + } + for (const current of [artifacts.slice(0, -1), [...artifacts, canonical]]) + assert.notEqual( + execute( + 'linux-arm64', + '//src/wasix/postmaster:compiler_linux_arm64', + 'linux_arm64_gnu', + current, + ).status, + 0, + ); + }); +}); + +test('native controllers provision locked release tooling before their first dependent command', () => { + const action = Bun.YAML.parse( + readFileSync( + path.resolve(import.meta.dir, '../../.github/actions/native-release-inputs/action.yml'), + 'utf8', + ), + ) as any; + const command = + 'bash tools/dev/bun.sh install --frozen-lockfile --filter @oliphaunt/release-tools --ignore-scripts'; + const installs = action.runs.steps.filter((step: any) => step.run?.trim() === command); + assert.equal(installs.length, 1); + assert.equal(installs[0].if, undefined); + assert.equal(installs[0]['continue-on-error'], undefined); + const firstImport = action.runs.steps.findIndex((step: any) => + step.run?.includes('native-release-inputs.mts'), + ); + assert.ok(action.runs.steps.indexOf(installs[0]) < firstImport); + const resolver = jobs['release-inputs'].steps; + const resolverInstall = resolver.filter((step: any) => step.run?.trim() === command); + assert.equal(resolverInstall.length, 1); + assert.equal(resolverInstall[0].if, undefined); + assert.equal(resolverInstall[0]['continue-on-error'], undefined); + assert.ok( + resolver.indexOf(resolverInstall[0]) < + resolver.findIndex((step: any) => step.run?.includes('native-release-inputs.mts')), + ); + for (const [id, job] of Object.entries(jobs)) { + assert.equal( + job.steps.filter((step: any) => step.run?.trim() === command).length, + id === 'release-inputs' ? 1 : 0, + 'Each controller or acquisition job provisions tooling once', + ); + const capture = job.steps.findIndex((step: any) => + step.run?.includes('qualify-native-shipping.mts'), + ); + if (capture < 0) continue; + const acquisition = job.steps.findIndex( + (step: any) => step.uses === './.github/actions/native-release-inputs', + ); + assert.ok(acquisition >= 0 && acquisition < capture); + } + const release = Bun.YAML.parse( + readFileSync(path.resolve(import.meta.dir, '../../.github/workflows/release.yml'), 'utf8'), + ) as any; + const planning = release.jobs['plan-candidate'].steps; + const planningInstall = planning.filter((step: any) => step.run?.trim() === command); + assert.equal(planningInstall.length, 1); + assert.equal(planningInstall[0].if, undefined); + assert.equal(planningInstall[0]['continue-on-error'], undefined); + assert.ok( + planning.indexOf(planningInstall[0]) < + planning.findIndex((step: any) => + step.run?.includes('native-freeze-publication-candidate.mts'), + ), + ); +}); + +test('Source CI verifies ordinary receipts while full qualification retains Required admission', () => { + assert.ok(jobs.required.if.includes("ci_mode == 'full'")); + const source = jobs['source-ci']; + assert.ok(source.if.startsWith('always()')); + assert.ok(needs('source-ci').includes('required')); + const guard = source.steps[0]; + const results = Object.fromEntries( + needs('source-ci').map((id) => [ + id, + { result: id === 'release-inputs' ? 'success' : 'skipped' }, + ]), + ); + const runGuard = () => + spawnSync('bash', ['-eu', '-c', guard.run], { + env: { PATH: process.env.PATH, NEEDS_JSON: JSON.stringify(results) }, + }).status; + assert.equal(runGuard(), 0, 'a verified empty ordinary selection needs no producer jobs'); + for (const id of ['portable', 'wasix-host']) { + for (const status of ['failure', 'cancelled']) { + results[id].result = status; + assert.notEqual(runGuard(), 0, `Source CI must reject a ${status} selected ${id} job`); + } + results[id].result = 'skipped'; + } + for (const status of ['failure', 'skipped']) { + results['release-inputs'].result = status; + assert.notEqual(runGuard(), 0, `Source CI must reject a ${status} planner`); + } + const verify = source.steps.find( + (step: any) => step.name === 'Verify selected requests and every omission', + ); + assert.ok(verify.run.includes('with-source.sh HEAD')); + assert.ok(verify.run.includes('configured-scope.mts verify')); + assert.ok(verify.run.includes(`--required-result '\${{ needs.required.result }}'`)); + assert.ok(verify.run.includes('--basis-output "$RUNNER_TEMP/native-ci-basis/basis.json"')); + const upload = source.steps.find((step: any) => step.with?.name === 'native-ci-basis'); + assert.equal( + upload.if, + "needs.release-inputs.outputs.ci_mode == 'full' && needs.required.result == 'success'", + ); + assert.equal(upload.with.path, `\${{ runner.temp }}/native-ci-basis/basis.json`); + assert.equal(upload.with['if-no-files-found'], 'error'); + assert.ok( + source.steps + .find((step: any) => step.with?.pattern === 'native-ci-requests-*') + .if.includes("!= '[]'"), + ); +}); + +test('every configured request is annotated and opaque controller qualification executes once', () => { + const matrices = JSON.parse(workflow.env.CI_FULL_MATRICES); + for (const [id, rows] of Object.entries(matrices)) { + assert.ok(Array.isArray(rows) && rows.length > 0); + assert.equal( + jobs[id].strategy.matrix, + `\${{ fromJSON(needs.release-inputs.outputs.${id.replaceAll('-', '_')}_matrix) }}`, + ); + } + let controller = 0; + for (const [id, job] of Object.entries(jobs)) { + for (const step of job.steps) { + const command = step.run ?? ''; + if (command.includes('release-check.sh --mutation-tests-only')) controller++; + assert.ok( + !/tools\/dev\/bazel[.]sh\s+(?:build|test)\s/u.test(command), + `${id}/${step.name} bypasses configured request receipts`, + ); + if ( + !command.includes('run-configured-request.mts') && + !command.includes('qualify-native-shipping.mts') + ) + continue; + assert.ok( + step.env?.CI_REQUEST_ID || step.env?.CI_REQUEST_IDS, + `${id}/${step.name} has no executable request identity`, + ); + assert.equal(step['continue-on-error'], undefined); + assert.ok( + command.includes('"$CI_REQUEST_ID"') && + command.includes('"$CI_REQUEST_JOB"') && + command.includes('"$CI_MODE"'), + ); + const receipts = job.steps.filter((value: any) => + value.with?.name?.startsWith('native-ci-requests-'), + ); + assert.equal(receipts.length, 1); + assert.equal(receipts[0].with.path, `\${{ runner.temp }}/ci-requests/**/ci-request.json`); + assert.equal(receipts[0].with['if-no-files-found'], 'error'); + } + } + assert.equal(controller, 1); + assert.ok( + jobs.portable.steps + .find((step: any) => step.name === 'Exercise cold, incremental and coverage scenarios') + .if.includes("ci_mode == 'full'"), + ); +}); + +test('source producer capture is enabled only for an actual workflow handoff', () => { + const step = jobs['wasix-host'].steps.find( + (value: any) => value.name === 'Qualify final WASIX addon on its native host', + ); + qualifierFixture((directory, env) => { + const source = execFileSync('git', ['rev-parse', 'HEAD'], { + cwd: directory, + env, + encoding: 'utf8', + }).trim(); + for (const handoff of [false, true]) { + for (const generated of [env.RUNNER_TEMP, env.QUALIFIER_ARGS, env.QUALIFIER_SOURCE]) + rmSync(generated, { recursive: true, force: true }); + const request = requestEnvironment(step, env, 'linux-arm64'); + const result = spawnSync('bash', ['-eu', '-c', step.run], { + cwd: directory, + env: { + ...request, + CI_REQUEST_JOB: 'wasix-host/linux-arm64', + CI_MODE: 'source', + TARGET_PLATFORM: 'linux-arm64', + EXPECTED_SOURCE_COMMIT: source, + QUALIFICATION_JOB_NAME: 'WASIX imported runtime (linux-arm64)', + CI_CAPTURE_REQUESTS: JSON.stringify(handoff ? [request.CI_REQUEST_ID] : []), + }, + }); + assert.equal(result.status, 0, result.stderr.toString()); + const args = readFileSync(env.QUALIFIER_ARGS, 'utf8').split('\0'); + assert.equal(args[args.indexOf('--ci-request-id') + 1], 'wasix-host/linux-arm64/napi'); + assert.equal(args[args.indexOf('--ci-mode') + 1], 'source'); + assert.equal(args.includes('--ci-handoff'), handoff); + assert.equal(args[args.indexOf('--shipping-export') + 1], '//:wasix_napi_shipping_export'); + const configuration = JSON.parse( + readFileSync(args[args.indexOf('--configuration-json') + 1], 'utf8'), + ); + for (const flag of [ + '--platforms=//build_defs/native:linux_aarch64_glibc_2_28', + '--host_platform=//build_defs/native:linux_aarch64_glibc_2_28', + `--repo_env=OLIPHAUNT_WASIX_SOURCE_COMMIT=${source}`, + `--repo_env=OLIPHAUNT_WASIX_CARGO_INPUTS=${env.RUNNER_TEMP}/wasix-cargo-inputs`, + '--jobs=1', + '--local_test_jobs=1', + '--test_env=OLIPHAUNT_WASM_AOT_VERIFY=full', + ]) + assert.ok(configuration.includes(flag), `missing imported NAPI configuration: ${flag}`); + assert.deepEqual( + JSON.parse(readFileSync(args[args.indexOf('--ci-requires-json') + 1], 'utf8')), + ['wasix/tools-sdk-browser'], + ); + assert.equal( + JSON.parse(readFileSync(args[args.indexOf('--github-json') + 1], 'utf8')).job, + 'WASIX imported runtime (linux-arm64)', + ); + assert.ok( + existsSync( + path.join(env.RUNNER_TEMP, 'ci-requests/wasix-host/linux-arm64/napi/ci-request.json'), + ), + ); + } + }); +}); + +test('the actual Apple ABI loop runs exactly the selected configured request and preserves full construction', () => { + const step = jobs.portable.steps.find( + (value: any) => value.name === 'Construct native iOS device and simulator ABI consumers', + ); + const ids: string[] = JSON.parse(step.env.CI_REQUEST_IDS)['macos-arm64']; + qualifierFixture((directory, env) => { + const calls = path.join(env.RUNNER_TEMP, 'abi-calls'); + writeFileSync( + path.join(directory, 'tools/dev/bun.sh'), + `#!/usr/bin/env bash +[[ "$1" == tools/ci/run-configured-request.mts ]] || exit 71 +while [[ "$#" -gt 1 ]]; do + case "$1" in + --id) id="$2" ;; + --command) command="$2" ;; + --targets-json) targets="$2" ;; + --configuration-json) configuration="$2" ;; + --startup-json) startup="$2" ;; + --output-directory) output="$2" ;; + esac + shift +done +jq -nc --arg id "$id" --arg command "$command" --slurpfile targets "$targets" --slurpfile config "$configuration" --slurpfile startup "$startup" \\ + '{id:$id,command:$command,targets:$targets[0],configuration:$config[0],startup:$startup[0]}' >> "$ABI_CALLS" +if [[ "\${ABI_STATUS:-0}" != 0 && ( -z "\${ABI_FAIL_ID:-}" || "$id" == "$ABI_FAIL_ID" ) ]]; then exit "$ABI_STATUS"; fi +mkdir -p "$output" +printf '{}\\n' > "$output/ci-request.json" +`, + ); + const execute = (selected: string[], status = '0', failId = '') => { + rmSync(calls, { force: true }); + rmSync(path.join(env.RUNNER_TEMP, 'ci-requests'), { recursive: true, force: true }); + const result = spawnSync('bash', ['-eu', '-c', step.run], { + cwd: directory, + env: { + ...requestEnvironment(step, env, 'macos-arm64'), + CI_SELECTED_REQUESTS: JSON.stringify(selected), + ABI_CALLS: calls, + ABI_STATUS: status, + ABI_FAIL_ID: failId, + }, + }); + const records = existsSync(calls) + ? readFileSync(calls, 'utf8') + .trim() + .split('\n') + .map((value) => JSON.parse(value)) + : []; + return { result, records }; + }; + const selected = execute([ids[1]]); + assert.equal(selected.result.status, 0, selected.result.stderr.toString()); + assert.deepEqual( + selected.records.map((value) => value.id), + [ids[1]], + ); + for (const id of ids) + assert.equal( + existsSync(path.join(env.RUNNER_TEMP, 'ci-requests', id, 'ci-request.json')), + id === ids[1], + ); + const full = execute(ids); + assert.equal(full.result.status, 0, full.result.stderr.toString()); + assert.deepEqual( + full.records.map((value) => value.id), + ids, + ); + for (const record of full.records) { + assert.equal(record.command, 'build'); + assert.ok( + record.configuration.includes( + `--platforms=//build_defs/host:${record.id.split('/abi-')[1]}`, + ), + ); + assert.deepEqual(record.startup, [ + `--output_base=${env.RUNNER_TEMP}/native-bazel`, + '--host_jvm_args=-Xmx3g', + `--server_jvm_out=${env.RUNNER_TEMP}/native-bazel-diagnostics/server-jvm.out`, + ]); + assert.ok(record.targets.includes('//build_defs/extensions/mobile:all_members_consumer')); + } + assert.equal( + full.records[0].targets.filter( + (value: string) => value === '//src/native/runtime:mobile_static_abi_consumer', + ).length, + 1, + ); + assert.equal( + full.records[2].targets.includes('//src/native/runtime:mobile_static_abi_consumer'), + false, + ); + const failed = execute(ids, '7'); + assert.equal(failed.result.status, 1); + assert.deepEqual( + failed.records.map((value) => value.id), + ids, + ); + const partial = execute(ids, '7', ids[1]); + assert.equal(partial.result.status, 1, 'a failed profile must keep qualification failed'); + assert.deepEqual( + partial.records.map((value) => value.id), + ids, + ); + for (const id of ids) + assert.equal( + existsSync(path.join(env.RUNNER_TEMP, 'ci-requests', id, 'ci-request.json')), + id !== ids[1], + `retain only the successful profile receipts: ${id}`, + ); + assert.deepEqual(execute([]).records, []); + }); +}); + +test('macOS collects independent qualifications after sibling failures while preserving setup and capture gates', () => { + const steps = jobs.portable.steps; + const sdk = steps.find((step: any) => step.id === 'apple_sdk'); + assert.equal(sdk.if, "matrix.platform == 'macos-arm64'"); + const packages = steps.find( + (step: any) => step.name === 'Qualify packages and native host behavior', + ); + const abi = steps.find( + (step: any) => step.name === 'Construct native iOS device and simulator ABI consumers', + ); + const native = steps.find((step: any) => step.id === 'native_qualification'); + const evaluate = ( + step: any, + { + platform = 'macos-arm64', + succeeded = false, + sdkOutcome = 'success', + cancelled = false, + selected = true, + capture = true, + mode = 'source', + qualifierOutcome = 'success', + } = {}, + ) => + runInNewContext( + step.if.replace(/^\$\{\{\s*|\s*\}\}$/gu, '').replaceAll('needs.release-inputs', 'inputs'), + { + matrix: { platform }, + inputs: { + outputs: { + ci_mode: mode, + ci_selected_requests: JSON.stringify( + selected + ? [`portable/${platform}/packages`, `portable/${platform}/native-carriers`] + : [], + ), + ci_capture_requests: JSON.stringify( + capture + ? [`portable/${platform}/apple-packages`, `portable/${platform}/native-carriers`] + : [], + ), + }, + }, + env: requestEnvironment(step, {}, platform), + steps: { + apple_sdk: { outcome: sdkOutcome }, + apple_qualification: { outcome: qualifierOutcome }, + native_qualification: { outcome: qualifierOutcome }, + }, + success: () => succeeded, + cancelled: () => cancelled, + contains: (values: string[], value: string) => values.includes(value), + fromJSON: JSON.parse, + format: (template: string, value: string) => template.replace('{0}', value), + }, + ); + for (const step of [packages, abi, native]) { + assert.equal(step['continue-on-error'], undefined); + assert.equal(evaluate(step), true, `${step.name}: finish after a sibling failure`); + for (const sdkOutcome of ['failure', 'skipped']) + assert.equal(evaluate(step, { sdkOutcome }), false, `${step.name}: setup ${sdkOutcome}`); + assert.equal(evaluate(step, { cancelled: true, succeeded: true }), false); + } + for (const step of [packages, native]) { + assert.equal(evaluate(step, { selected: false }), false); + assert.equal(evaluate(step, { platform: 'windows-x64' }), false); + assert.equal(evaluate(step, { platform: 'windows-x64', succeeded: true }), true); + } + assert.equal(evaluate(abi, { platform: 'windows-x64', succeeded: true }), false); + for (const name of [ + 'Upload iOS extension construction evidence', + 'Upload native construction evidence', + ]) { + const step = steps.find((step: any) => step.name === name); + assert.equal(evaluate(step), true, `${name}: retain a successful sibling's evidence`); + for (const qualifierOutcome of ['failure', 'skipped']) + assert.equal(evaluate(step, { qualifierOutcome }), false); + assert.equal(evaluate(step, { capture: false }), false); + assert.equal(evaluate(step, { capture: false, mode: 'full' }), true); + assert.equal(evaluate(step, { cancelled: true }), false); + } +}); + +test('full module preflight follows source planning and retains strict failure propagation', () => { + const steps = jobs['release-inputs'].steps; + const index = (name: string) => steps.findIndex((step: any) => step.name === name); + const context = steps.findIndex((step: any) => step.id === 'context'); + const versions = index('Check release-owned source versions'); + const controller = index('Qualify release controller and Git source policy'); + const planner = steps.findIndex((step: any) => step.id === 'scope'); + const preflight = index('Check every used module extension before producer fanout'); + assert.ok(context >= 0 && context < versions && versions < controller); + assert.ok(controller < planner && planner < preflight); + assert.ok(preflight < index('Upload source request plan')); + assert.ok(preflight < index('Acquire completed public inputs once')); + for (const position of [versions, controller, planner]) { + assert.equal(steps[position].if, undefined); + assert.equal(steps[position]['continue-on-error'], undefined); + } + const step = steps[preflight]; + assert.equal(step.if, "steps.scope.outputs.ci_mode == 'full'"); + assert.equal(step.run, 'bash tools/dev/bazel.sh mod deps --lockfile_mode=error'); + assert.equal(step['continue-on-error'], undefined); + for (const mode of ['source', 'full', '']) + assert.equal( + runInNewContext(step.if, { steps: { scope: { outputs: { ci_mode: mode } } } }), + mode === 'full', + ); + qualifierFixture((directory, env) => { + writeFileSync(path.join(directory, 'tools/dev/bazel.sh'), 'exit 7\n'); + const result = spawnSync('bash', ['-eu', '-c', step.run], { cwd: directory, env }); + assert.equal(result.status, 7, 'a strict full preflight failure must stop producer fanout'); + }); +}); + +test('selected consumers reject failed producers while independent source families permit skipped jobs', () => { + const producers: Record = { + 'postmaster-host': ['postmaster'], + 'wasix-host': ['wasix'], + 'react-native': ['portable'], + 'release-families': [ + 'portable', + 'linux', + 'wasix', + 'wasix-host', + 'postmaster', + 'postmaster-host', + ], + }; + for (const [id, required] of Object.entries(producers)) { + assert.deepEqual([...needs(id)].sort(), [...required, 'release-inputs'].sort()); + const evaluate = (results: Record, selected = true, cancelled = false) => { + const outputs = { + ci_mode: 'source', + ci_selected_requests: JSON.stringify(selected ? ['release-families/public-source'] : []), + ci_selected_jobs: JSON.stringify(selected ? [id] : []), + postmaster_host_matrix: JSON.stringify({ + include: selected ? [{ platform: 'linux-arm64' }] : [], + }), + wasix_host_matrix: JSON.stringify({ + include: selected ? [{ platform: 'linux-arm64' }] : [], + }), + }; + const input = Object.fromEntries( + needs(id).map((producer) => [ + producer, + { result: results[producer] ?? 'success', outputs }, + ]), + ); + const expression = jobs[id].if + .slice(3, -2) + .replace(/needs[.]\*[.]([\w-]+)/gu, "Object.values(needs).map(value => value['$1'])") + .replace(/needs[.]([\w-]+)/gu, "needs['$1']"); + return runInNewContext(expression, { + needs: input, + cancelled: () => cancelled, + fromJSON: JSON.parse, + contains: (values: string[], value: string) => values.includes(value), + }); + }; + assert.equal(evaluate({}), true, `${id}: successful selected producer chain`); + assert.equal(evaluate({}, false), false, `${id}: omitted consumer`); + assert.equal(evaluate({}, true, true), false, `${id}: cancelled workflow`); + for (const producer of needs(id)) { + for (const result of ['failure', 'cancelled']) + assert.equal(evaluate({ [producer]: result }), false, `${id}: ${producer} ${result}`); + assert.equal( + evaluate({ [producer]: 'skipped' }), + id === 'release-families' && producer !== 'release-inputs', + `${id}: ${producer} skipped`, + ); + } + const skipped = Object.fromEntries(required.map((producer) => [producer, 'skipped'])); + assert.equal(evaluate(skipped), id === 'release-families', `${id}: all producers skipped`); + for (const producer of required) + for (const result of ['failure', 'cancelled']) + assert.equal( + evaluate({ ...skipped, [producer]: result }), + false, + `${id}: mixed skipped and ${producer} ${result}`, + ); + } +}); diff --git a/tools/dev/BUILD.bazel b/tools/dev/BUILD.bazel new file mode 100644 index 000000000..61e54c57a --- /dev/null +++ b/tools/dev/BUILD.bazel @@ -0,0 +1,98 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/foundation:bun.bzl", "bun_script_test", "bun_test") + +package(default_visibility = ["//visibility:public"]) + +exports_files([ + "android-sdk.toml", + "bun.toml", + "deno.toml", + "maintainer-tools.toml", + "native-host-toolchains.json", + "winflexbison.toml", +]) + +_SOURCE_ACQUISITION_INPUTS = [ + "//:src/third-party/tools/source-fetch-core.mts", + "//:src/third-party/tools/source-archive.mts", + "//:tools/packaging/portable-archive.mts", + "//:tools/packaging/testdata/tar-fixture.mts", + "//:tools/packaging/testdata/zip-fixture.mts", +] + +bun_test( + name = "source_fetch_core_test", + entry_point = "//:src/third-party/tools/source-fetch-core.test.mts", + data = _SOURCE_ACQUISITION_INPUTS, + tags = ["source-check"], + size = "small", +) + +bun_test( + name = "source_fetch_scopes_test", + entry_point = "//:src/third-party/tools/source-fetch-scopes.test.mts", + data = ["//:src/third-party/tools/source-fetch-scopes.mts"], + tags = ["source-check"], + size = "small", +) + +bun_test( + name = "source_acquisition_test", + entry_point = "source-acquisition.test.mts", + data = _SOURCE_ACQUISITION_INPUTS, + tags = ["source-check"], + size = "small", +) + +bun_script_test( + name = "pinned_zip_test", + entry_point = "extract-pinned-zip.test.mts", + data = [ + "extract-pinned-zip.mts", + "//:tools/packaging/portable-archive.mts", + "//:tools/packaging/testdata/zip-fixture.mts", + ], + tags = ["source-check"], + size = "small", +) + +_RUNTIME_PIN_INPUTS = [ + "bazel-checksums.tsv", + "bun.toml", + "deno.toml", + "node-runtime.toml", + "winflexbison.toml", + "//:.bazelversion", + "//:.prototools", +] + +bun_test( + name = "runtime_pin_policy_test", + entry_point = "runtime-pin-policy.test.mts", + data = ["runtime-pin-policy.mts"] + _RUNTIME_PIN_INPUTS, + tags = ["source-check"], + size = "small", +) + +bun_script_test( + name = "runtime_pin_policy_check", + entry_point = "runtime-pin-policy.mts", + args = ["--root", "."], + data = _RUNTIME_PIN_INPUTS, + tags = ["source-check"], + size = "small", +) + +test_suite( + name = "source_checks", + tests = [ + ":pinned_zip_test", + ":runtime_pin_policy_check", + ":runtime_pin_policy_test", + ":source_acquisition_test", + ":source_fetch_core_test", + ":source_fetch_scopes_test", + ], +) + +source_quality_files() diff --git a/tools/dev/android-sdk.toml b/tools/dev/android-sdk.toml index 3a5fea936..a1b301df6 100644 --- a/tools/dev/android-sdk.toml +++ b/tools/dev/android-sdk.toml @@ -1,4 +1,5 @@ [packages] +emulator = "37.2.12" command_line_tools_build = "14742923" command_line_tools_revision = "20.0" ndk = "27.0.12077973" @@ -7,8 +8,19 @@ expo_ndk = "27.1.12297006" cmake = "3.22.1" compile_sdk = "36" build_tools = "36.0.0" +platform_tools = "37.0.0" + +# Google repository2-3.xml's NDK 27.0.12077973 Linux archive, verified against +# its SHA-1 5e5cd517bdb98d7e0faf2c494a3041291e71bdcc before recording SHA-256. +# Native Bazel cross-compilation runs this archive on Linux x86_64; Expo keeps +# its separately pinned application NDK above. +[ndk.linux] +url = "https://dl.google.com/android/repository/android-ndk-r27-linux.zip" +sha256 = "2f17eb8bcbfdc40201c0b36e9a70826fcd2524ab7a2a235e2c71186c302da1dc" +strip_prefix = "android-ndk-r27" [command_line_tools.linux] +bytes = "172789259" url = "https://dl.google.com/android/repository/commandlinetools-linux-14742923_latest.zip" mirror_url = "https://edgedl.me.gvt1.com/edgedl/android/repository/commandlinetools-linux-14742923_latest.zip" sha256 = "04453066b540409d975c676d781da1477479dde3761310f1a7eb92a1dfb15af7" @@ -19,3 +31,41 @@ url = "https://dl.google.com/android/repository/commandlinetools-mac-14742923_la mirror_url = "https://edgedl.me.gvt1.com/edgedl/android/repository/commandlinetools-mac-14742923_latest.zip" sha256 = "ed304c5ede3718541e4f978e4ae870a4d853db74af6c16d920588d48523b9dee" entry_count = "324" + +# Platform revision 2 and Linux build tools match the conventional SDK pins. +# Both archives were checked against Google's repository2-3.xml SHA-1 and size +# before recording these SHA-256 acquisition identities. +[platform] +url = "https://dl.google.com/android/repository/platform-36_r02.zip" +sha256 = "37607369a28c5b640b3a7998868d45898ebcb777565a0e85f9acf36f29631d2e" +strip_prefix = "android-36" +revision = "2" + +[build_tools.linux] +url = "https://dl.google.com/android/repository/build-tools_r36_linux.zip" +sha256 = "5d9ac77fb6ff43d9da518a337b4fcf8f9097113df531d99ccefe80ef7ce8250b" +strip_prefix = "android-16" + +# The maintained SDK provider includes adb. Preserve the installed platform +# tools revision with its immutable official archive rather than SDK discovery. +[platform_tools.linux] +url = "https://dl.google.com/android/repository/platform-tools_r37.0.0-linux.zip" +sha256 = "198ae156ab285fa555987219af237b31102fefe8b9d2bc274708a8d4f2865a07" +strip_prefix = "platform-tools" + +# Installed APK qualification uses a separate lazy emulator acquisition. +[emulator.linux] +url = "https://dl.google.com/android/repository/emulator-linux_x64-16428233.zip" +sha256 = "b08fc43d8608d2955f607f1b287beb525041e730086bdca3af152accac3af9c1" +bytes = "349654171" +strip_prefix = "emulator" + +[system_image.linux_x86_64] +api = "35" +tag = "google_atd" +abi = "x86_64" +revision = "1" +url = "https://dl.google.com/android/repository/sys-img/google_atd/x86_64-35_r01.zip" +sha256 = "63183925a254127540af31485e8da141e5fb574cd2b183b9b029d0162cb6066b" +bytes = "813411228" +strip_prefix = "x86_64" diff --git a/tools/dev/bazel-bootstrap.test.sh b/tools/dev/bazel-bootstrap.test.sh new file mode 100755 index 000000000..ea4d73885 --- /dev/null +++ b/tools/dev/bazel-bootstrap.test.sh @@ -0,0 +1,141 @@ +#!/usr/bin/env bash +set -euo pipefail + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +scratch="$(mktemp -d)" +trap 'rm -rf "$scratch"' EXIT +checkout="$scratch/checkout" +mkdir -p "$checkout/tools/dev" "$scratch/bin" +cp "$script_dir/bazel.sh" "$script_dir/acquisition.sh" "$checkout/tools/dev/" +printf '8.8.1\n' > "$checkout/.bazelversion" +# Exercise filename-escaped checksum output in every existing bootstrap case. +export XDG_CACHE_HOME="$scratch/cache\\native" +export MOCK_BINARY="$scratch/bazel" +export MOCK_EXECUTION_LOG="$scratch/executions" +export MOCK_DOWNLOAD_LOG="$scratch/downloads" +export MOCK_OS=Linux MOCK_ARCH=x86_64 MOCK_DOWNLOAD_KIND=valid +export MOCK_CREDENTIAL_NAMES='FIXTURE_TOKEN fixture_token FiXtUrE_pAsSwOrD FIXTURE_PASSWORD fixture_secret FIXTURE_SECRET fixture_key FIXTURE_KEY fixture_credentials FIXTURE_CREDENTIALS npm_config__auth npm_config__authToken NPM_CONFIG__AUTHTOKEN' +for credential in $MOCK_CREDENTIAL_NAMES; do export "$credential=synthetic-private-value"; done +export MOCK_STAGED_INPUTS="$scratch/staged publication inputs.json" +export OLIPHAUNT_NATIVE_PUBLICATION_INPUTS="$MOCK_STAGED_INPUTS" +export HTTPS_PROXY='http://fixture.invalid:8080' +export PATH="$scratch/bin:$PATH" + +fail() { echo "bazel-bootstrap.test.sh: $*" >&2; exit 1; } +cat > "$MOCK_BINARY" <<'SH' +#!/usr/bin/env bash +set -euo pipefail +for credential in $MOCK_CREDENTIAL_NAMES; do + if declare -p "$credential" >/dev/null 2>&1; then + echo 'bazel-bootstrap.test.sh: credential variable reached Bazel' >&2 + exit 91 + fi +done +[[ "$OLIPHAUNT_NATIVE_PUBLICATION_INPUTS" == "$MOCK_STAGED_INPUTS" ]] || exit 92 +[[ "$HTTPS_PROXY" == 'http://fixture.invalid:8080' ]] || exit 92 +printf 'cwd=%s\n' "$PWD" >> "$MOCK_EXECUTION_LOG" +printf 'arg=%s\n' "$@" >> "$MOCK_EXECUTION_LOG" +SH +if command -v sha256sum >/dev/null 2>&1; then + checksum="$(sha256sum "$MOCK_BINARY" | awk '{ print $1 }')" +else + checksum="$(shasum -a 256 "$MOCK_BINARY" | awk '{ print $1 }')" +fi +for suffix in linux-x86_64 linux-arm64 darwin-x86_64 darwin-arm64 windows-x86_64.exe; do + printf '8.8.1\tbazel-8.8.1-%s\t%s\n' "$suffix" "$checksum" +done > "$checkout/tools/dev/bazel-checksums.tsv" +cat > "$scratch/bin/uname" <<'SH' +#!/usr/bin/env bash +case "$1" in + -s) printf '%s\n' "$MOCK_OS" ;; + -m) printf '%s\n' "$MOCK_ARCH" ;; + *) exit 1 ;; +esac +SH +cat > "$scratch/bin/curl" <<'SH' +#!/usr/bin/env bash +set -euo pipefail +output='' url='' +while [ "$#" -gt 0 ]; do + case "$1" in + --output) shift; output="$1" ;; + https://*) url="$1" ;; + esac + shift +done +printf '%s\n' "$url" >> "$MOCK_DOWNLOAD_LOG" +case "$MOCK_DOWNLOAD_KIND" in + valid) cp "$MOCK_BINARY" "$output" ;; + corrupt) printf 'unverified download\n' > "$output" ;; + fail) printf 'partial download\n' > "$output"; exit 22 ;; +esac +SH +# Retry behavior is tested without waiting between mock transport failures. +printf '#!/usr/bin/env bash\nexit 0\n' > "$scratch/bin/sleep" +chmod +x "$scratch/bin/"* +launcher="$checkout/tools/dev/bazel.sh" + +for selector in Linux/x86_64 Linux/aarch64 Darwin/x86_64 Darwin/arm64 MINGW64_NT-10.0/x86_64; do + MOCK_OS="${selector%/*}" MOCK_ARCH="${selector#*/}" \ + bash "$launcher" --output_user_root="$scratch/output root" build '//target:two words' + # Every platform's verified cache works without contacting the network. + MOCK_OS="${selector%/*}" MOCK_ARCH="${selector#*/}" MOCK_DOWNLOAD_KIND=fail \ + bash "$launcher" version +done +# Inspect the launcher's own state before exec; child shells reset shopt options. +for expected_casefold in off on; do + ( + shopt -u nocasematch + if [[ "$expected_casefold" == on ]]; then shopt -s nocasematch; fi + exec() { + local actual_casefold=off + if shopt -q nocasematch; then actual_casefold=on; fi + [[ "$actual_casefold" == "$expected_casefold" ]] || exit 93 + command exec "$@" + } + MOCK_DOWNLOAD_KIND=fail source "$launcher" version + ) +done +[ "$(wc -l < "$MOCK_DOWNLOAD_LOG")" -eq 5 ] || fail 'platform downloads were not selected once each' +for suffix in linux-x86_64 linux-arm64 darwin-x86_64 darwin-arm64 windows-x86_64.exe; do + grep -Fxq "https://releases.bazel.build/8.8.1/release/bazel-8.8.1-$suffix" "$MOCK_DOWNLOAD_LOG" || + fail "incorrect official download URL for $suffix" +done +printf 'cwd=%s\narg=--output_user_root=%s/output root\narg=build\narg=//target:two words\n' \ + "$checkout" "$scratch" > "$scratch/expected" +head -n 4 "$MOCK_EXECUTION_LOG" > "$scratch/actual" +cmp "$scratch/expected" "$scratch/actual" || fail 'workspace or argument boundaries changed' + +binary="$XDG_CACHE_HOME/oliphaunt/bazel/8.8.1/bazel-8.8.1-linux-x86_64" +printf 'corrupt cache\n' > "$binary" +bash "$launcher" version +cmp "$MOCK_BINARY" "$binary" || fail 'corrupt cache was reused' +[ "$(wc -l < "$MOCK_DOWNLOAD_LOG")" -eq 6 ] || fail 'corrupt cache was not replaced' + +expect_failure() { + local before + before="$(wc -l < "$MOCK_EXECUTION_LOG")" + if bash "$launcher" version > "$scratch/failure" 2>&1; then + fail 'invalid bootstrap input succeeded' + fi + [ "$(wc -l < "$MOCK_EXECUTION_LOG")" -eq "$before" ] || fail 'unverified binary executed' + for partial in "$XDG_CACHE_HOME/oliphaunt/bazel/8.8.1"/.download.*; do + [ ! -e "$partial" ] || fail 'temporary download survived failure' + done +} +printf 'corrupt cache\n' > "$binary" +MOCK_DOWNLOAD_KIND=corrupt expect_failure +grep -q 'download checksum mismatch' "$scratch/failure" || fail 'missing checksum diagnosis' +MOCK_DOWNLOAD_KIND=fail expect_failure +grep -Fxq 'corrupt cache' "$binary" || fail 'failed download replaced cached bytes' +MOCK_ARCH=riscv64 expect_failure +grep -q 'unsupported bootstrap platform' "$scratch/failure" || fail 'unsupported platform was accepted' +printf '9.9.9\n' > "$checkout/.bazelversion" +expect_failure +grep -q 'missing or ambiguous checksum' "$scratch/failure" || fail 'unlisted version was accepted' +printf '8.8.1\n' > "$checkout/.bazelversion" +printf '8.8.1\tbazel-8.8.1-linux-x86_64\t%s\n' "$checksum" >> "$checkout/tools/dev/bazel-checksums.tsv" +expect_failure +grep -q 'missing or ambiguous checksum' "$scratch/failure" || fail 'duplicate checksum was accepted' + +echo 'Bazel bootstrap passed: platforms, pinned downloads, verified cache, credential exclusion, staged inputs, arguments and failure cleanup' diff --git a/tools/dev/bazel-checksums.tsv b/tools/dev/bazel-checksums.tsv new file mode 100644 index 000000000..875821f1b --- /dev/null +++ b/tools/dev/bazel-checksums.tsv @@ -0,0 +1,8 @@ +# Official full binaries (bundled JDK): https://github.com/bazelbuild/bazel/releases/tag/8.8.1 +# Verified against https://releases.bazel.build/8.8.1/release/ASSET.sha256 +# version asset sha256 +8.8.1 bazel-8.8.1-linux-x86_64 5b5bab2095065817d3416ca9a0678bd39c10c9ede432dbe8187bfe74de285160 +8.8.1 bazel-8.8.1-linux-arm64 41ad5f9e833fcaee7398111343570cb155ca14985abb084b1f0ad2d29eaaec6d +8.8.1 bazel-8.8.1-darwin-x86_64 bb2026bbdec1b857ae5f56ae28bbdba4584b58fe929fb402c76872db0d14ccac +8.8.1 bazel-8.8.1-darwin-arm64 3b5864201e7be5e14fd14a2af2fc25ad9592a8269755793f6f3bfe0cb6136490 +8.8.1 bazel-8.8.1-windows-x86_64.exe 9380555f80ad7e301ab4f9dd360283d434a92f34c30e88b8dae1fe3f59dfc209 diff --git a/tools/dev/bazel.sh b/tools/dev/bazel.sh new file mode 100755 index 000000000..b7386ad0a --- /dev/null +++ b/tools/dev/bazel.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Bazel records its client environment in raw build events. +oliphaunt_bazel_nocasematch=false +if shopt -q nocasematch; then oliphaunt_bazel_nocasematch=true; fi +shopt -s nocasematch +while IFS= read -r oliphaunt_bazel_variable; do + case "$oliphaunt_bazel_variable" in + *_TOKEN|*_PASSWORD|*_SECRET|*_KEY|*_CREDENTIALS|npm_config__auth|npm_config__authToken) unset "$oliphaunt_bazel_variable" ;; + esac +done < <(compgen -e) +if [[ "$oliphaunt_bazel_nocasematch" == false ]]; then shopt -u nocasematch; fi +unset oliphaunt_bazel_nocasematch oliphaunt_bazel_variable + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +root="$(cd "$script_dir/../.." && pwd)" +cd "$root" + +fail() { + echo "bazel.sh: $*" >&2 + exit 1 +} + +[ -f .bazelversion ] || fail "missing $root/.bazelversion" +version="$(tr -d '\r' < .bazelversion)" +[[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || fail "invalid stable Bazel version: $version" + +# Windows requires Git Bash/MSYS2; these selectors do not claim native PowerShell support. +platform="$(uname -s)/$(uname -m)" +case "$platform" in + Linux/x86_64) suffix=linux-x86_64 ;; + Linux/aarch64|Linux/arm64) suffix=linux-arm64 ;; + Darwin/x86_64) suffix=darwin-x86_64 ;; + Darwin/arm64|Darwin/aarch64) suffix=darwin-arm64 ;; + MINGW*/x86_64|MSYS*/x86_64) suffix=windows-x86_64.exe ;; + *) fail "unsupported bootstrap platform: $platform" ;; +esac +asset="bazel-$version-$suffix" +expected="$(awk -v version="$version" -v asset="$asset" \ + '$1 == version && $2 == asset { print $3 }' "$script_dir/bazel-checksums.tsv")" +[[ "$expected" =~ ^[0-9a-f]{64}$ ]] || fail "missing or ambiguous checksum for $asset" + +if command -v sha256sum >/dev/null 2>&1; then + digest() { sha256sum < "$1" | awk '{ print $1 }'; } +elif command -v shasum >/dev/null 2>&1; then + digest() { shasum -a 256 < "$1" | awk '{ print $1 }'; } +else + fail "bootstrap requires sha256sum or shasum" +fi + +cache_dir="${XDG_CACHE_HOME:-${HOME:?set HOME or XDG_CACHE_HOME}/.cache}/oliphaunt/bazel/$version" +binary="$cache_dir/$asset" +if [ -f "$binary" ] && [ -x "$binary" ] && [ "$(digest "$binary")" = "$expected" ]; then + exec "$binary" "$@" +fi + +command -v curl >/dev/null 2>&1 || fail "bootstrap requires curl" +mkdir -p "$cache_dir" +download="$(mktemp "$cache_dir/.download.XXXXXX")" +trap 'rm -f "$download"' EXIT +# shellcheck source=tools/dev/acquisition.sh +. "$script_dir/acquisition.sh" +oliphaunt_acquisition_start "Bazel $version" 300 +echo "Downloading pinned Bazel $version ($suffix)" >&2 +oliphaunt_acquisition_curl 300 3 2 curl \ + --fail --location --silent --show-error --connect-timeout 15 \ + --proto '=https' --proto-redir '=https' \ + --output "$download" "https://releases.bazel.build/$version/release/$asset" +[ "$(digest "$download")" = "$expected" ] || fail "download checksum mismatch for $asset" +chmod +x "$download" +mv -f "$download" "$binary" +trap - EXIT +exec "$binary" "$@" diff --git a/tools/dev/bootstrap-tools.sh b/tools/dev/bootstrap-tools.sh index 06c1d1419..a1c5aa2aa 100755 --- a/tools/dev/bootstrap-tools.sh +++ b/tools/dev/bootstrap-tools.sh @@ -3,7 +3,6 @@ set -euo pipefail PREK_VERSION="${PREK_VERSION:-0.4.3}" CARGO_NEXTEST_VERSION="${CARGO_NEXTEST_VERSION:-0.9.137}" -ZIZMOR_VERSION="${ZIZMOR_VERSION:-1.25.2}" case "${1:-}" in ""|--workflows) ;; @@ -118,6 +117,7 @@ if [ "${1:-}" != --workflows ]; then install_cargo_tool prek prek "$PREK_VERSION" install_cargo_tool cargo-nextest cargo-nextest "$CARGO_NEXTEST_VERSION" fi +ZIZMOR_VERSION="$("$script_dir/install-pinned-maintainer-tool.sh" zizmor --print-version)" install_cargo_tool zizmor zizmor "$ZIZMOR_VERSION" "$script_dir/install-actionlint.sh" diff --git a/tools/dev/install-pinned-maintainer-tool.sh b/tools/dev/install-pinned-maintainer-tool.sh index 36b7ccacd..1dc2a3c52 100755 --- a/tools/dev/install-pinned-maintainer-tool.sh +++ b/tools/dev/install-pinned-maintainer-tool.sh @@ -1,10 +1,16 @@ #!/usr/bin/env bash set -euo pipefail -tool="${1:?usage: install-pinned-maintainer-tool.sh [--print-version|--promote-locked-cargo-source ]}" +tool="${1:?usage: install-pinned-maintainer-tool.sh [--print-version|--promote-locked-cargo-source ], or zizmor --print-version}" shift case "$tool" in cargo-binstall | actionlint) ;; + zizmor) + [ "$#" = 1 ] && [ "$1" = --print-version ] || { + echo 'zizmor supports --print-version here; bootstrap-tools.sh owns its local installation' >&2 + exit 2 + } + ;; *) echo "unsupported pinned maintainer tool: $tool" >&2; exit 2 ;; esac @@ -59,6 +65,12 @@ case "$tool" in exit 1 fi ;; + zizmor) + if [ -n "${ZIZMOR_VERSION:-}" ] && [ "$ZIZMOR_VERSION" != "$version" ]; then + echo "ZIZMOR_VERSION must match $manifest ($version)" >&2 + exit 1 + fi + ;; actionlint) if [ -n "${ACTIONLINT_VERSION:-}" ] && [ "$ACTIONLINT_VERSION" != "$version" ]; then echo "ACTIONLINT_VERSION must match $manifest ($version)" >&2 diff --git a/tools/dev/maintainer-tool-install.test.sh b/tools/dev/maintainer-tool-install.test.sh index 7b14e7dae..c2a36fd8a 100644 --- a/tools/dev/maintainer-tool-install.test.sh +++ b/tools/dev/maintainer-tool-install.test.sh @@ -224,4 +224,13 @@ export FAKE_UNAME_OS=FreeBSD reject 69 install_tool cargo-binstall test ! -e "$FAKE_CURL_LOG" no_debris + +fixture zizmor-pin +cat >> "$OLIPHAUNT_MAINTAINER_TOOLS_MANIFEST" <<'TOML' +[zizmor] +version = "1.25.2" +TOML +test "$(install_tool zizmor --print-version)" = 1.25.2 +reject 2 install_tool zizmor +ZIZMOR_VERSION=9.9.9 reject any install_tool zizmor --print-version echo 'Maintainer tool integrity, cache repair, rollback and pinned fallback checks passed' diff --git a/tools/dev/maintainer-tools.toml b/tools/dev/maintainer-tools.toml index 60a2301fc..f4dd44ef8 100644 --- a/tools/dev/maintainer-tools.toml +++ b/tools/dev/maintainer-tools.toml @@ -81,3 +81,28 @@ format = "tgz" binary_path = "actionlint" max_archive_bytes = "8388608" max_binary_bytes = "16777216" + +[zizmor] +version = "1.25.2" +repository = "zizmorcore/zizmor" +license = "MIT" +source_fallback = "cargo install zizmor --version 1.25.2 --locked" + +[zizmor.assets.linux-amd64] +url = "https://github.com/zizmorcore/zizmor/releases/download/v1.25.2/zizmor-x86_64-unknown-linux-gnu.tar.gz" +sha256 = "aa1facd105f0d83fe5c55b1adcd9d7417de5d83aa27471f91dc0b66cf3803577" +binary_sha256 = "95d59b28ad1b3e6b56a9f2fa0c393a167565b00f65184da09eccc92211983eb2" +format = "tgz" +binary_path = "zizmor" + +[shellcheck] +version = "0.9.0" +repository = "koalaman/shellcheck" +license = "GPL-3.0" + +[shellcheck.assets.linux-amd64] +url = "https://github.com/koalaman/shellcheck/releases/download/v0.9.0/shellcheck-v0.9.0.linux.x86_64.tar.xz" +sha256 = "700324c6dd0ebea0117591c6cc9d7350d9c7c5c287acbad7630fa17b1d4d9e2f" +binary_sha256 = "7087178d54de6652b404c306233264463cb9e7a9afeb259bb663cc4dbfd64149" +format = "tar.xz" +binary_path = "shellcheck-v0.9.0/shellcheck" diff --git a/tools/dev/native-host-toolchains.json b/tools/dev/native-host-toolchains.json new file mode 100644 index 000000000..bbbb6b2bc --- /dev/null +++ b/tools/dev/native-host-toolchains.json @@ -0,0 +1,14 @@ +{ + "apple": { + "xcode_version": "26.5", + "developer_dir": "/Applications/Xcode_26.5.app/Contents/Developer" + }, + "windows": { + "visual_studio_major": 18, + "vc_toolset_major": 14, + "vc_toolset_minor_min": 50, + "vc_toolset_minor_max_exclusive": 60, + "windows_sdk_major": 10, + "crt_family": "VC145" + } +} diff --git a/tools/dev/runtime-pin-policy.mts b/tools/dev/runtime-pin-policy.mts new file mode 100644 index 000000000..1d58441ba --- /dev/null +++ b/tools/dev/runtime-pin-policy.mts @@ -0,0 +1,214 @@ +import { readFileSync } from 'node:fs'; +import path from 'node:path'; + +type Table = Record; + +const HOSTS = [ + ['aarch64-apple-darwin', 'darwin-aarch64', 'darwin-arm64', 'tar.gz'], + ['x86_64-apple-darwin', 'darwin-x64', 'darwin-x64', 'tar.gz'], + ['aarch64-unknown-linux-gnu', 'linux-aarch64', 'linux-arm64', 'tar.xz'], + ['x86_64-unknown-linux-gnu', 'linux-x64', 'linux-x64', 'tar.xz'], + ['x86_64-pc-windows-msvc', 'windows-x64', 'win-x64', 'zip'], +] as const; +const BAZEL_HOSTS = [ + 'linux-x86_64', + 'linux-arm64', + 'darwin-x86_64', + 'darwin-arm64', + 'windows-x86_64.exe', +]; + +function require(condition: unknown, message: string): asserts condition { + if (!condition) throw new Error(`runtime pin policy: ${message}`); +} + +function table(value: unknown, label: string): Table { + require(value !== null && + typeof value === 'object' && + !Array.isArray(value), `${label} must be a TOML table`); + return value as Table; +} + +function string(value: unknown, label: string): string { + require(typeof value === 'string' && value.length > 0, `${label} must be a quoted string`); + return value; +} + +function version(value: unknown, label: string, allowV = false): string { + const pinned = string(value, label); + const normalized = allowV ? pinned.replace(/^v/u, '') : pinned; + require(/^[0-9]+\.[0-9]+\.[0-9]+$/u.test(normalized), `${label} must pin a stable version`); + return normalized; +} + +function digest(value: unknown, label: string) { + require(typeof value === 'string' && + /^[0-9a-f]{64}$/u.test(value), `${label} must contain 64 lowercase hexadecimal characters`); +} + +function integer(value: unknown, label: string, min = 1, max = Number.MAX_SAFE_INTEGER): number { + require(typeof value === 'string' && /^[0-9]+$/u.test(value), `${label} must be numeric`); + const count = Number(value); + require(Number.isSafeInteger(count) && + count >= min && + count <= max, `${label} must be ${min}..${max}`); + return count; +} + +function equal(value: unknown, expected: string | number, label: string) { + require(value === expected, `${label} must be ${expected}`); +} + +function read(root: string, file: string): string { + try { + return readFileSync(path.join(root, file), 'utf8'); + } catch (cause) { + throw new Error(`runtime pin policy: cannot read ${file}: ${(cause as Error).message}`); + } +} + +function toml(root: string, file: string): Table { + let parsed: unknown; + try { + parsed = Bun.TOML.parse(read(root, file)); + } catch (cause) { + throw new Error(`runtime pin policy: cannot parse ${file}: ${(cause as Error).message}`); + } + return table(parsed, file); +} + +function assets(manifest: Table, targets: string[], file: string): Table { + const entries = table(manifest.assets, `${file}.assets`); + require(Object.keys(entries).sort().join(',') === + [...targets] + .sort() + .join( + ',', + ), `${file}.assets must contain exactly the supported targets: ${targets.join(', ')}`); + return entries; +} + +/** Validate the checked source pins without downloading or executing any pinned tool. */ +export function checkRuntimePinPolicy(root: string) { + require(typeof root === 'string' && root.length > 0, 'an explicit checkout root is required'); + const proto = toml(root, '.prototools'); + for (const tool of ['bun', 'deno', 'node'] as const) { + const pinned = version(proto[tool], `.prototools.${tool}`, true); + const file = `tools/dev/${tool === 'node' ? 'node-runtime' : tool}.toml`; + const entries = assets( + toml(root, file), + HOSTS.map((host) => (tool === 'bun' ? host[1] : host[0])), + file, + ); + for (const [target, bunTarget, nodeTarget, format] of HOSTS) { + const label = `${file}.assets.${tool === 'bun' ? bunTarget : target}`; + const entry = table(entries[tool === 'bun' ? bunTarget : target], label); + const executable = `${tool}${format === 'zip' ? '.exe' : ''}`; + digest(entry.sha256, `${label}.sha256`); + digest(entry.binary_sha256, `${label}.binary_sha256`); + if (tool === 'node') { + const prefix = `node-v${pinned}-${nodeTarget}`; + equal( + entry.url, + `https://nodejs.org/download/release/v${pinned}/${prefix}.${format}`, + `${label}.url`, + ); + equal(entry.format, format, `${label}.format`); + equal( + entry.binary_path, + `${prefix}/${format === 'zip' ? '' : 'bin/'}${executable}`, + `${label}.binary_path`, + ); + integer(entry.bytes, `${label}.bytes`); + integer(entry.binary_bytes, `${label}.binary_bytes`, 1, 250_000_000); + } else if (tool === 'bun') { + equal( + entry.url, + `https://github.com/oven-sh/bun/releases/download/bun-v${pinned}/bun-${bunTarget}.zip`, + `${label}.url`, + ); + equal(entry.binary_path, `bun-${bunTarget}/${executable}`, `${label}.binary_path`); + require(entry.mirror_url === undefined, `${label}.mirror_url must be absent`); + integer(entry.entry_count, `${label}.entry_count`, 1, 4096); + } else { + const asset = `deno-${target}.zip`; + equal( + entry.url, + `https://github.com/denoland/deno/releases/download/v${pinned}/${asset}`, + `${label}.url`, + ); + equal( + entry.mirror_url, + `https://dl.deno.land/release/v${pinned}/${asset}`, + `${label}.mirror_url`, + ); + equal(entry.binary_path, executable, `${label}.binary_path`); + integer(entry.entry_count, `${label}.entry_count`, 1, 4096); + } + } + } + + const bazelVersion = version(read(root, '.bazelversion').trim(), '.bazelversion'); + const bazelAssets = new Set(BAZEL_HOSTS.map((host) => `bazel-${bazelVersion}-${host}`)); + const seen = new Set(); + for (const [index, line] of read(root, 'tools/dev/bazel-checksums.tsv') + .split(/\r?\n/u) + .entries()) { + if (!line.trim() || line.trimStart().startsWith('#')) continue; + const label = `tools/dev/bazel-checksums.tsv:${index + 1}`; + const fields = line.split('\t'); + require(fields.length === 3, `${label} must contain version, asset and digest columns`); + const [pinned, asset, sha256] = fields; + equal(pinned, bazelVersion, `${label} version`); + require(bazelAssets.has(asset), `${label} has an unsupported Bazel asset: ${asset}`); + require(!seen.has(asset), `${label} duplicates Bazel asset: ${asset}`); + digest(sha256, `${label} digest`); + seen.add(asset); + } + require(seen.size === + bazelAssets.size, 'tools/dev/bazel-checksums.tsv must pin every supported Bazel asset'); + + const winFile = 'tools/dev/winflexbison.toml'; + const winManifest = toml(root, winFile); + const toolchain = table(winManifest.toolchain, `${winFile}.toolchain`); + const winVersion = version(toolchain.version, `${winFile}.toolchain.version`); + equal(toolchain.repository, 'lexxmark/winflexbison', `${winFile}.toolchain.repository`); + const win = table( + assets(winManifest, ['windows-x64'], winFile)['windows-x64'], + `${winFile}.assets.windows-x64`, + ); + equal( + win.url, + `https://github.com/lexxmark/winflexbison/releases/download/v${winVersion}/win_flex_bison-${winVersion}.zip`, + `${winFile}.url`, + ); + equal(win.flex_path, 'win_flex.exe', `${winFile}.flex_path`); + equal(win.bison_path, 'win_bison.exe', `${winFile}.bison_path`); + for (const key of ['sha256', 'tree_sha256', 'flex_sha256', 'bison_sha256']) + digest(win[key], `${winFile}.${key}`); + integer(win.bytes, `${winFile}.bytes`, 1, 2_000_000); + const entryCount = integer(win.entry_count, `${winFile}.entry_count`, 2, 256); + integer(win.file_count, `${winFile}.file_count`, 2, entryCount); + integer(win.expanded_bytes, `${winFile}.expanded_bytes`, 1, 10_000_000); + return { runtimeAssets: HOSTS.length * 3, bazelAssets: seen.size, winflexbisonAssets: 1 }; +} + +if (import.meta.main) { + const args = process.argv.slice(2); + try { + if (args.length === 1 && ['--help', '-h'].includes(args[0])) { + console.log('usage: runtime-pin-policy.mts --root CHECKOUT_ROOT'); + } else { + require(args.length === 2 && + args[0] === '--root' && + args[1].length > 0, 'usage: runtime-pin-policy.mts --root CHECKOUT_ROOT'); + const result = checkRuntimePinPolicy(path.resolve(args[1])); + console.log( + `runtime pin policy passed (${result.runtimeAssets} runtime, ${result.bazelAssets} Bazel, ${result.winflexbisonAssets} winflexbison assets)`, + ); + } + } catch (cause) { + console.error(cause instanceof Error ? cause.message : String(cause)); + process.exitCode = 1; + } +} diff --git a/tools/dev/runtime-pin-policy.test.mts b/tools/dev/runtime-pin-policy.test.mts new file mode 100644 index 000000000..f73426d1d --- /dev/null +++ b/tools/dev/runtime-pin-policy.test.mts @@ -0,0 +1,217 @@ +import { afterEach, expect, test } from 'bun:test'; +import { spawnSync } from 'node:child_process'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { checkRuntimePinPolicy } from './runtime-pin-policy.mts'; + +const sourceRoot = path.resolve(import.meta.dir, '../..'); +const script = path.join(import.meta.dir, 'runtime-pin-policy.mts'); +const inputs = [ + '.prototools', + '.bazelversion', + 'tools/dev/bun.toml', + 'tools/dev/deno.toml', + 'tools/dev/node-runtime.toml', + 'tools/dev/bazel-checksums.tsv', + 'tools/dev/winflexbison.toml', +]; +const temporaryRoots: string[] = []; + +function fixture() { + const root = mkdtempSync(path.join(tmpdir(), 'runtime-pin-policy-')); + temporaryRoots.push(root); + mkdirSync(path.join(root, 'tools/dev'), { recursive: true }); + for (const input of inputs) + writeFileSync(path.join(root, input), readFileSync(path.join(sourceRoot, input)), { + flag: 'wx', + mode: 0o644, + }); + return root; +} + +function mutate(root: string, file: string, change: (text: string) => string) { + const target = path.join(root, file); + const original = readFileSync(target, 'utf8'); + const modified = change(original); + expect(modified).not.toBe(original); + writeFileSync(target, modified); +} + +afterEach(() => { + for (const root of temporaryRoots.splice(0)) rmSync(root, { recursive: true, force: true }); +}); + +test('accepts all actual source pins from an explicit root', () => { + expect(checkRuntimePinPolicy(fixture())).toEqual({ + runtimeAssets: 15, + bazelAssets: 5, + winflexbisonAssets: 1, + }); +}); + +test.each(['bun', 'deno', 'node'])('rejects a malformed %s version', (tool) => { + const root = fixture(); + mutate(root, '.prototools', (text) => + text.replace(new RegExp(`^${tool} = .*`, 'mu'), `${tool} = "latest"`), + ); + expect(() => checkRuntimePinPolicy(root)).toThrow( + `.prototools.${tool} must pin a stable version`, + ); +}); + +test('uses the authored versions rather than a second maintained version list', () => { + const root = fixture(); + mutate(root, '.prototools', (text) => text.replace(/(bun|deno|node) = "/gu, '$1 = "v')); + expect(checkRuntimePinPolicy(root).runtimeAssets).toBe(15); + mutate(root, '.prototools', (text) => + text.replace( + /(bun = "v[0-9]+\.[0-9]+\.)([0-9]+)/u, + (_, prefix, patch) => `${prefix}${Number(patch) + 1}`, + ), + ); + expect(() => checkRuntimePinPolicy(root)).toThrow('bun.toml.assets.darwin-aarch64.url must be'); +}); + +test.each([ + '.bazelversion', + 'tools/dev/winflexbison.toml', +])('rejects a malformed version in %s', (file) => { + const root = fixture(); + mutate(root, file, (text) => + file === '.bazelversion' ? 'latest\n' : text.replace(/^version = .*$/mu, 'version = "2.5"'), + ); + expect(() => checkRuntimePinPolicy(root)).toThrow('must pin a stable version'); +}); + +test.each([ + ['tools/dev/bun.toml', 'sha256'], + ['tools/dev/bun.toml', 'binary_sha256'], + ['tools/dev/deno.toml', 'sha256'], + ['tools/dev/deno.toml', 'binary_sha256'], + ['tools/dev/node-runtime.toml', 'sha256'], + ['tools/dev/node-runtime.toml', 'binary_sha256'], + ['tools/dev/winflexbison.toml', 'sha256'], + ['tools/dev/winflexbison.toml', 'tree_sha256'], + ['tools/dev/winflexbison.toml', 'flex_sha256'], + ['tools/dev/winflexbison.toml', 'bison_sha256'], +])('rejects malformed %s %s', (file, key) => { + const root = fixture(); + mutate(root, file, (text) => + text.replace(new RegExp(`^${key} = .*`, 'mu'), `${key} = "${'A'.repeat(64)}"`), + ); + expect(() => checkRuntimePinPolicy(root)).toThrow('64 lowercase hexadecimal'); +}); + +test.each([ + ['tools/dev/bun.toml', 'https://github.com/oven-sh/bun', 'https://example.com/oven-sh/bun'], + ['tools/dev/deno.toml', 'https://github.com/denoland/deno', 'http://github.com/denoland/deno'], + ['tools/dev/deno.toml', 'https://dl.deno.land', 'https://example.com'], + ['tools/dev/node-runtime.toml', 'https://nodejs.org', 'https://nodejs.org.evil.invalid'], + ['tools/dev/winflexbison.toml', 'lexxmark/winflexbison', 'other/winflexbison'], +])('rejects a changed pinned origin in %s', (file, original, replacement) => { + const root = fixture(); + mutate(root, file, (text) => text.replace(original, replacement)); + expect(() => checkRuntimePinPolicy(root)).toThrow('must be'); +}); + +test.each([ + 'tools/dev/bun.toml', + 'tools/dev/deno.toml', + 'tools/dev/node-runtime.toml', +])('rejects a changed archive member in %s', (file) => { + const root = fixture(); + mutate(root, file, (text) => text.replace('binary_path = "', 'binary_path = "../')); + expect(() => checkRuntimePinPolicy(root)).toThrow('binary_path must be'); +}); + +test('rejects absent targets, duplicate TOML pins and unsupported mirror URLs', () => { + const missing = fixture(); + mutate(missing, 'tools/dev/bun.toml', (text) => text.split('[assets.windows-x64]')[0]); + expect(() => checkRuntimePinPolicy(missing)).toThrow('exactly the supported targets'); + const duplicate = fixture(); + mutate(duplicate, '.prototools', (text) => { + const bunPin = text.match(/^bun = .*$/mu)?.[0]; + if (!bunPin) throw new Error('fixture is missing its Bun pin'); + return `${text}\n${bunPin}\n`; + }); + expect(() => checkRuntimePinPolicy(duplicate)).toThrow('cannot parse .prototools'); + const mirror = fixture(); + mutate(mirror, 'tools/dev/bun.toml', (text) => + text.replace(/^(url = .*\n)/mu, '$1mirror_url = "https://example.com/bun.zip"\n'), + ); + expect(() => checkRuntimePinPolicy(mirror)).toThrow('mirror_url must be absent'); +}); + +test('rejects archive format, count and byte bounds the installers cannot accept', () => { + const cases: [string, string, string, string][] = [ + ['tools/dev/node-runtime.toml', 'format = "tar.gz"', 'format = "zip"', 'format must be'], + ['tools/dev/node-runtime.toml', 'bytes', '0', '.bytes must be'], + ['tools/dev/node-runtime.toml', 'binary_bytes', '250000001', '.binary_bytes must be'], + ['tools/dev/bun.toml', 'entry_count', '4097', '.entry_count must be'], + ['tools/dev/deno.toml', 'entry_count', '0', '.entry_count must be'], + ['tools/dev/winflexbison.toml', 'bytes', '2000001', '.bytes must be'], + ['tools/dev/winflexbison.toml', 'entry_count', '257', '.entry_count must be'], + ['tools/dev/winflexbison.toml', 'file_count', '256', '.file_count must be'], + ['tools/dev/winflexbison.toml', 'expanded_bytes', '10000001', '.expanded_bytes must be'], + ['tools/dev/winflexbison.toml', 'flex_path', '../win_flex.exe', '.flex_path must be'], + ['tools/dev/winflexbison.toml', 'bison_path', 'other.exe', '.bison_path must be'], + ]; + for (const [file, key, value, error] of cases) { + const root = fixture(); + mutate(root, file, (text) => + key.includes(' = ') + ? text.replace(key, value) + : text.replace(new RegExp(`^${key} = .*`, 'mu'), `${key} = "${value}"`), + ); + expect(() => checkRuntimePinPolicy(root)).toThrow(error); + } +}); + +test('rejects duplicate, missing, malformed and stale Bazel checksum rows', () => { + const changes = [ + (text: string) => `${text}${text.split('\n').find((line) => line && !line.startsWith('#'))}\n`, + (text: string) => text.replace(/^[^#\n].*\n/mu, ''), + (text: string) => text.replace(/\t[0-9a-f]{64}/u, '\tbad'), + (text: string) => + text.replace( + /^(\d+\.\d+\.)(\d+)\t/mu, + (_, prefix, patch) => `${prefix}${Number(patch) + 1}\t`, + ), + (text: string) => text.replace('-linux-x86_64', '-unsupported'), + (text: string) => text.replace(/^(\d+\.\d+\.\d+)\t/mu, '$1 '), + ]; + for (const change of changes) { + const root = fixture(); + mutate(root, 'tools/dev/bazel-checksums.tsv', change); + expect(() => checkRuntimePinPolicy(root)).toThrow('bazel-checksums.tsv'); + } +}); + +test('CLI supports help and an explicit valid root and rejects invalid roots and arguments', () => { + const root = fixture(); + const run = (args: string[]) => + spawnSync(process.execPath, [script, ...args], { cwd: tmpdir(), encoding: 'utf8' }); + const help = run(['--help']); + expect(help.status).toBe(0); + expect(help.stdout).toContain('--root CHECKOUT_ROOT'); + const valid = run(['--root', root]); + expect(valid.status).toBe(0); + expect(valid.stdout).toContain('15 runtime, 5 Bazel, 1 winflexbison assets'); + for (const args of [ + [], + ['--root'], + ['--unknown'], + ['--root', root, 'extra'], + ['--help', '--root', root], + ['--root', path.join(root, 'absent')], + ]) { + const invalid = run(args); + expect(invalid.status).not.toBe(0); + expect(invalid.stderr).toContain('runtime pin policy:'); + } + mutate(root, 'tools/dev/bun.toml', (text) => + text.replace(/^sha256 = .*$/mu, 'sha256 = "invalid"'), + ); + expect(run(['--root', root]).status).toBe(1); +}); diff --git a/tools/dev/source-acquisition.test.mts b/tools/dev/source-acquisition.test.mts new file mode 100644 index 000000000..bd1233d6f --- /dev/null +++ b/tools/dev/source-acquisition.test.mts @@ -0,0 +1,90 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import { + prepareSourceArchive, + sourceCheckoutIsReady, + validateCachedArchive, +} from '../../src/third-party/tools/source-fetch-core.mts'; +import { tarArchive } from '../packaging/testdata/tar-fixture.mts'; +import { zipArchive } from '../packaging/testdata/zip-fixture.mts'; + +function fixture( + bytes: Buffer, + format: 'tar.gz' | 'zip', + run: (value: ReturnType) => void, +) { + const root = mkdtempSync(path.join(tmpdir(), 'native-source-acquisition-')); + try { + const archive = path.join(root, `source.${format}`); + writeFileSync(archive, bytes); + run(pin(bytes, format, archive, path.join(root, 'checkout'))); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +function pin(bytes: Buffer, format: 'tar.gz' | 'zip', archive: string, checkout: string) { + const digest = createHash('sha256').update(bytes).digest('hex'); + return { + archive, + checkout, + source: { + name: 'fixture', + kind: 'archive', + url: `https://example.invalid/source.${format}`, + branch: 'fixture', + commit: digest, + sha256: digest, + stripPrefix: format === 'zip' ? '.' : 'pkg', + }, + }; +} + +test('verified tar and rootless ZIP sources retain bytes and detect checkout edits', () => { + for (const [format, bytes] of [ + ['tar.gz', tarArchive([{ name: 'pkg/file.txt', data: 'trusted' }])], + ['zip', zipArchive([{ name: 'file.txt', data: 'trusted' }])], + ] as const) { + fixture(bytes, format, ({ archive, checkout, source }) => { + prepareSourceArchive(source, archive, checkout); + assert.equal(readFileSync(path.join(checkout, 'file.txt'), 'utf8'), 'trusted'); + assert.equal(sourceCheckoutIsReady(source, checkout), true); + assert.throws(() => prepareSourceArchive(source, archive, checkout)); + assert.equal(readFileSync(path.join(checkout, 'file.txt'), 'utf8'), 'trusted'); + writeFileSync(path.join(checkout, 'file.txt'), 'changed'); + assert.throws(() => sourceCheckoutIsReady(source, checkout), /was modified/u); + }); + } +}); + +test('a digest mismatch never creates or replaces a source checkout', () => { + fixture(tarArchive([{ name: 'pkg/file.txt', data: 'trusted' }]), 'tar.gz', (value) => { + writeFileSync(value.archive, 'corrupt transfer'); + assert.throws(() => validateCachedArchive(value.archive, value.source), /archive sha256/u); + assert.throws(() => prepareSourceArchive(value.source, value.archive, value.checkout)); + assert.equal(existsSync(value.checkout), false); + }); +}); + +test('matching archive digests do not admit escaping, reserved, colliding or truncated members', () => { + const unsafe = [ + tarArchive([{ name: 'pkg/../outside', data: 'bad' }]), + tarArchive([{ name: 'pkg/.git/config', data: 'bad' }]), + tarArchive([ + { name: 'pkg/File', data: 'one' }, + { name: 'pkg/file', data: 'two' }, + ]), + tarArchive([{ name: 'pkg/link', type: '2', linkTarget: '../../outside', data: '' }]), + tarArchive([{ name: 'pkg/file', data: 'bad' }]).subarray(0, -7), + ]; + for (const bytes of unsafe) { + fixture(bytes, 'tar.gz', ({ archive, checkout, source }) => { + assert.throws(() => prepareSourceArchive(source, archive, checkout)); + assert.equal(existsSync(checkout), false); + }); + } +}); diff --git a/tools/packaging/archive-directory.mts b/tools/packaging/archive-directory.mts index b8ad52e35..f7167ba85 100755 --- a/tools/packaging/archive-directory.mts +++ b/tools/packaging/archive-directory.mts @@ -45,7 +45,10 @@ function archiveEntryName(root, item, keepParent) { return relative === '.' ? parent : `${parent}/${relative}`; } -async function archiveEntries(root, { keepParent = false } = {}) { +async function archiveEntries( + root, + { keepParent = false, modes = {} as Record } = {}, +) { const rootStat = await fs.lstat(root); if (!rootStat.isDirectory()) { fail(`source is not a real directory: ${root}`); @@ -101,7 +104,19 @@ async function archiveEntries(root, { keepParent = false } = {}) { } await walk(root); - return entries; + const byName = new Map(entries.map((entry) => [entry.name, entry])); + for (const [name, mode] of Object.entries(modes)) { + const entry = byName.get(name); + if (!entry || entry.isDirectory || typeof mode !== 'number' || ![0o644, 0o755].includes(mode)) { + fail(`explicit mode requires an existing regular member and mode 0644 or 0755: ${name}`); + } + } + return entries.map((entry) => ({ + ...entry, + mode: Object.hasOwn(modes, entry.name) + ? modes[entry.name] + : normalizedMode(entry.stat, entry.isDirectory), + })); } function tarPathParts(relativePath) { @@ -171,10 +186,8 @@ export function tarHeader(entry, size, mode) { export async function createDeterministicTar(root, options = {}) { const chunks = []; for (const entry of await archiveEntries(root, options)) { - const stat = entry.stat; - const mode = normalizedMode(stat, entry.isDirectory); const data = entry.isDirectory ? Buffer.alloc(0) : await fs.readFile(entry.fullPath); - chunks.push(tarHeader(entry, data.length, mode)); + chunks.push(tarHeader(entry, data.length, entry.mode)); if (data.length > 0) { chunks.push(data); const remainder = data.length % 512; @@ -220,8 +233,6 @@ export async function createDeterministicZip(root, options = {}) { if (entry.name === '.') { continue; } - const stat = entry.stat; - const mode = normalizedMode(stat, entry.isDirectory); const name = Buffer.from(zipName(entry)); const data = entry.isDirectory ? Buffer.alloc(0) : await fs.readFile(entry.fullPath); const compressed = entry.isDirectory ? Buffer.alloc(0) : deflateRawSync(data, { level: 9 }); @@ -230,7 +241,7 @@ export async function createDeterministicZip(root, options = {}) { // A Unix-origin ZIP must include the POSIX file type as well as permission // bits. Omitting S_IFREG/S_IFDIR makes the central directory ambiguous to // strict consumers and causes platform-dependent `zipinfo` rendering. - const unixMode = (entry.isDirectory ? 0o040000 : 0o100000) | (mode & 0o777); + const unixMode = (entry.isDirectory ? 0o040000 : 0o100000) | (entry.mode & 0o777); const externalAttributes = (unixMode << 16) | (entry.isDirectory ? 0x10 : 0); const localHeader = Buffer.concat([ writeUInt32(0x04034b50), @@ -305,7 +316,7 @@ function parseArgs(argv) { }; } -export async function archiveDirectory(source, output, { keepParent = false } = {}) { +export async function archiveDirectory(source, output, { keepParent = false, modes = {} } = {}) { const sourceStat = await fs.lstat(source).catch(() => null); if (!sourceStat?.isDirectory()) { fail(`source is not a directory: ${source}`); @@ -314,15 +325,15 @@ export async function archiveDirectory(source, output, { keepParent = false } = if (output.endsWith('.tar.gz')) { await fs.writeFile( output, - canonicalGzipSync(await createDeterministicTar(source, { keepParent })), + canonicalGzipSync(await createDeterministicTar(source, { keepParent, modes })), ); } else if (output.endsWith('.tar.zst')) { await fs.writeFile( output, - releaseZstdCompressSync(await createDeterministicTar(source, { keepParent })), + releaseZstdCompressSync(await createDeterministicTar(source, { keepParent, modes })), ); } else if (path.extname(output) === '.zip') { - await fs.writeFile(output, await createDeterministicZip(source, { keepParent })); + await fs.writeFile(output, await createDeterministicZip(source, { keepParent, modes })); } else { fail(`unsupported archive extension: ${output}`); } diff --git a/tools/packaging/archive-directory.test.mts b/tools/packaging/archive-directory.test.mts index cca610d6b..1099a1b41 100644 --- a/tools/packaging/archive-directory.test.mts +++ b/tools/packaging/archive-directory.test.mts @@ -17,6 +17,46 @@ import test from 'node:test'; import { gunzipSync, zstdDecompressSync } from 'node:zlib'; import { archiveDirectory } from './archive-directory.mts'; +import { readPortableArchiveEntries } from './portable-archive.mts'; + +test('declared member modes survive host permission differences and reject invalid mappings', async () => { + const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-archive-modes-')); + try { + const source = path.join(root, 'source'); + mkdirSync(source); + writeFileSync(path.join(source, 'executable'), 'payload\n', { mode: 0o644 }); + const options = { keepParent: true, modes: { 'source/executable': 0o755 } }; + for (const suffix of ['tar.gz', 'zip']) { + const first = path.join(root, `first.${suffix}`); + const second = path.join(root, `second.${suffix}`); + await archiveDirectory(source, first, options); + assert.equal(readPortableArchiveEntries(first).get('source/executable').mode & 0o777, 0o755); + chmodSync(path.join(source, 'executable'), 0o755); + await archiveDirectory(source, second, options); + assert.equal(digest(first), digest(second)); + chmodSync(path.join(source, 'executable'), 0o644); + } + for (const modes of [ + { 'source/missing': 0o755 }, + { source: 0o644 }, + { 'source/executable': 0o777 }, + ]) { + await assert.rejects( + archiveDirectory(source, path.join(root, 'invalid.tar.gz'), { keepParent: true, modes }), + /existing regular member and mode 0644 or 0755/, + ); + } + // A filename can match Object.prototype; it is not a declared permission. + writeFileSync(path.join(source, 'toString'), 'ordinary member\n', { mode: 0o644 }); + for (const suffix of ['tar.gz', 'zip']) { + const output = path.join(root, `ordinary.${suffix}`); + await archiveDirectory(source, output); + assert.equal(readPortableArchiveEntries(output).get('toString').mode & 0o777, 0o644); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); function tarString(buffer, offset, length) { const end = buffer.indexOf(0, offset); diff --git a/tools/packaging/audit-rust-dependency-licenses.sh b/tools/packaging/audit-rust-dependency-licenses.sh index c66d55b77..6d969e884 100644 --- a/tools/packaging/audit-rust-dependency-licenses.sh +++ b/tools/packaging/audit-rust-dependency-licenses.sh @@ -4,8 +4,10 @@ set -euo pipefail cd "$(dirname "${BASH_SOURCE[0]}")/../.." helper=$1 package=$2 +manifest=${helper%/tools/*}/Cargo.toml [[ -f "$helper" && "$helper" != /* && "$helper" != -* && "$helper" != *..* ]] || { echo 'contract must be a repository-relative file' >&2; exit 2; } [[ "$package" =~ ^[a-zA-Z0-9_-]+$ ]] || { echo 'invalid Cargo package' >&2; exit 2; } +[[ -f "$manifest" ]] || { echo 'owner Cargo manifest is missing' >&2; exit 2; } scratch=$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-rust-licenses-XXXXXX") scratch=$(cd "$scratch" && pwd -P) trap 'rm -rf "$scratch"' EXIT @@ -14,7 +16,7 @@ bun "$helper" audit-targets > "$scratch/targets" CARGO_NET_OFFLINE=false cargo fetch --locked cargo metadata --locked --offline --format-version 1 | head -c 134217729 > "$scratch/metadata.json" while IFS= read -r cargo_target; do - cargo tree -p "$package" --locked --offline -e normal --target "$cargo_target" \ + cargo tree --manifest-path "$manifest" --locked --offline -e normal --target "$cargo_target" \ --prefix none --format '{p}' | head -c 134217729 > "$scratch/$cargo_target.tree" done < "$scratch/targets" bun "$helper" audit-contract "$scratch" diff --git a/tools/packaging/build-maven-artifact-manifest.mts b/tools/packaging/build-maven-artifact-manifest.mts index 26f7d8029..2d3e41abb 100644 --- a/tools/packaging/build-maven-artifact-manifest.mts +++ b/tools/packaging/build-maven-artifact-manifest.mts @@ -1,31 +1,32 @@ #!/usr/bin/env bun import fs from 'node:fs/promises'; import path from 'node:path'; - -import { currentVersion } from '../release/product-version.mts'; +import { + assertExtensionUpstreamLicensesInEntries, + extensionMavenLicenses, + extensionRegistryLicense, + nativeExtensionCarrierLegal, + nativeExtensionConstructionMavenLicenses, +} from '../../src/extensions/tools/extension-upstream-licenses.mts'; import { requireCompatibilityVersionBounds } from '../release/compatibility-version-policy.mts'; +import { currentVersion } from '../release/product-version.mts'; import { allArtifactTargets, - exactExtensionProducts as logicalExactExtensionProducts, extensionArtifactProductRoot, - extensionArtifactTargets as releaseExtensionArtifactTargets, extensionMetadata, extensionReleaseProduct, extensionReleaseVersion, extensionSqlNames, + exactExtensionProducts as logicalExactExtensionProducts, registryPackageRows, + extensionArtifactTargets as releaseExtensionArtifactTargets, } from '../release/release-artifact-targets.mts'; +import { readPortableArchiveEntries } from './portable-archive.mts'; import { assertReleaseNoticesInEntries, releaseProfileMavenLicenses, releaseProfilePackageLicense, } from './release-notices.mts'; -import { - assertExtensionUpstreamLicensesInEntries, - extensionMavenLicenses, - extensionRegistryLicense, -} from '../../src/extensions/tools/extension-upstream-licenses.mts'; -import { readPortableArchiveEntries } from './portable-archive.mts'; const ROOT = path.resolve(import.meta.dir, '../..'); const PREFIX = 'build_maven_artifact_manifest.mts'; @@ -56,17 +57,33 @@ function canonicalMavenPayloadPrefix(file, entries) { return expected; } -function assertMavenPayloadLegal(file, profile, sqlNames = []) { +function assertMavenPayloadLegal( + file, + profile, + sqlNames = [], + sourceRoot, + constructionLicenseFiles = [], + target = null, +) { try { const entries = readPortableArchiveEntries(file); const prefix = canonicalMavenPayloadPrefix(file, entries); - assertReleaseNoticesInEntries(entries, { profile, prefix, label: path.basename(file) }); + assertReleaseNoticesInEntries(entries, { + profile, + prefix, + label: path.basename(file), + sourceRoot, + }); if (sqlNames.length > 0) { // Native singleton payloads install upstream notices with runtime files // below files/, while aggregate bundles stage their combined legal tree // directly below the canonical archive root. const upstreamPrefix = prefix === '' ? 'files' : prefix; - assertExtensionUpstreamLicensesInEntries(sqlNames, entries, { prefix: upstreamPrefix }); + assertExtensionUpstreamLicensesInEntries(sqlNames, entries, { + prefix: upstreamPrefix, + constructionLicenseFiles, + target, + }); } } catch (error) { fail( @@ -80,12 +97,15 @@ function repoPath(value) { return path.isAbsolute(value) ? value : path.join(ROOT, value); } -function productArtifactTargets(product, version) { - return allArtifactTargets( - { - product, - }, - PREFIX, +function productArtifactTargets(product, version, context) { + return ( + context?.artifactTargets ?? + allArtifactTargets( + { + product, + }, + PREFIX, + ) ) .filter((target) => target.surfaces.includes('maven')) .map((target) => ({ @@ -138,9 +158,9 @@ function runtimeMavenArtifactMetadata(target) { fail(`unsupported liboliphaunt-native Maven artifact target ${target.id}`); } -function productMavenArtifacts(product, version) { +function productMavenArtifacts(product, version, context) { const artifacts = new Map(); - for (const target of productArtifactTargets(product, version)) { + for (const target of productArtifactTargets(product, version, context)) { const artifactId = runtimeMavenArtifactId(target); if (artifactId === undefined) { continue; @@ -213,20 +233,21 @@ function tsvRow({ return values.join('\t'); } -async function productRows(assetRoot, product, artifactIds) { - const version = await currentVersion(product); - const artifacts = productMavenArtifacts(product, version); +async function productRows(assetRoot, product, artifactIds, context) { + const version = context?.version ?? (await currentVersion(product)); + const artifacts = productMavenArtifacts(product, version, context); const rows = []; const selected = artifactIds === undefined ? undefined : new Set(artifactIds); - for (const coordinate of registryPackageRows( - { - product, - packageKind: 'maven', - }, - PREFIX, - ) - .map((row) => row.packageName) - .filter((name) => name.startsWith('dev.oliphaunt.runtime:'))) { + for (const coordinate of ( + context?.registryPackages ?? + registryPackageRows( + { + product, + packageKind: 'maven', + }, + PREFIX, + ).map((row) => row.packageName) + ).filter((name) => name.startsWith('dev.oliphaunt.runtime:'))) { const [groupId, artifactId] = splitMavenCoordinate(coordinate); if (selected && !selected.delete(artifactId)) continue; if (groupId !== 'dev.oliphaunt.runtime') { @@ -237,7 +258,7 @@ async function productRows(assetRoot, product, artifactIds) { fail(`${product} Maven artifact ${coordinate} has no release asset mapping`); } const file = await requireFile(path.join(assetRoot, artifact.filename), artifactId); - assertMavenPayloadLegal(file, artifact.licenseProfile); + assertMavenPayloadLegal(file, artifact.licenseProfile, [], context?.noticeSourceRoot); rows.push( tsvRow({ groupId, @@ -246,10 +267,13 @@ async function productRows(assetRoot, product, artifactIds) { file, name: artifact.name, description: artifact.description, - licenseSpdx: releaseProfilePackageLicense(artifact.licenseProfile).spdx, + licenseSpdx: releaseProfilePackageLicense(artifact.licenseProfile, { + sourceRoot: context?.noticeSourceRoot, + }).spdx, licenses: releaseProfileMavenLicenses(artifact.licenseProfile, { product, version, + sourceRoot: context?.noticeSourceRoot, }), }), ); @@ -259,16 +283,38 @@ async function productRows(assetRoot, product, artifactIds) { return rows; } -async function extensionRows(extensionRoot, selectedProducts) { +async function extensionRows(extensionRoot, selectedProducts, context) { + if (context?.extensions && selectedProducts.length === 0) + fail('declared extension Maven inputs require explicit selected products'); const products = selectedProducts.length > 0 ? selectedProducts : logicalExactExtensionProducts(PREFIX); const rows = []; for (const product of [...products].sort()) { - const sqlNames = extensionSqlNames(product, PREFIX); - const version = extensionReleaseVersion(product, 'native', PREFIX); + const declared = context?.extensions?.[product]; + if (context?.extensions && !declared) + fail(`${product} is absent from declared extension Maven inputs`); + if ( + declared && + (!Array.isArray(declared.sqlNames) || + declared.sqlNames.length === 0 || + !Array.isArray(declared.targets) || + !Array.isArray(declared.registryPackages) || + typeof declared.version !== 'string' || + typeof declared.releaseProduct !== 'string' || + typeof declared.runtimeSourceVersion !== 'string' || + typeof declared.productRoot !== 'string' || + !declared.compatibility) + ) + fail(`${product} has incomplete declared extension Maven inputs`); + const sqlNames = declared?.sqlNames ?? extensionSqlNames(product, PREFIX); + if (declared && new Set(sqlNames).size !== sqlNames.length) + fail(`${product} repeats a declared SQL member`); + const version = declared?.version ?? extensionReleaseVersion(product, 'native', PREFIX); const registryLicense = extensionRegistryLicense(product, sqlNames); - const compatibility = extensionMetadata(product, PREFIX).compatibility; - const releaseProduct = extensionReleaseProduct(product, 'native', PREFIX); + const compatibility = + declared?.compatibility ?? extensionMetadata(product, PREFIX).compatibility; + const releaseProduct = + declared?.releaseProduct ?? extensionReleaseProduct(product, 'native', PREFIX); const runtimeProduct = compatibility.nativeRuntimeProduct; const runtimeVersion = compatibility.nativeRuntimeVersion; if ( @@ -286,22 +332,26 @@ async function extensionRows(extensionRoot, selectedProducts) { id: `${product} native runtime`, value: runtimeVersion, sourceProduct: runtimeProduct, - sourceVersion: await currentVersion(runtimeProduct), + sourceVersion: declared?.runtimeSourceVersion ?? (await currentVersion(runtimeProduct)), }, { prefix: PREFIX }, ); const productRoot = path.join( - extensionArtifactProductRoot(product, 'native', extensionRoot, PREFIX), + declared?.productRoot ?? + extensionArtifactProductRoot(product, 'native', extensionRoot, PREFIX), 'release-assets', ); const targets = [ ...new Map( - releaseExtensionArtifactTargets( - { - product, - family: 'native', - }, - PREFIX, + ( + declared?.targets ?? + releaseExtensionArtifactTargets( + { + product, + family: 'native', + }, + PREFIX, + ) ) .filter( (target) => @@ -313,11 +363,26 @@ async function extensionRows(extensionRoot, selectedProducts) { if (targets.length === 0) { fail(`${product} has no published Android Maven extension targets`); } + if ( + declared && + (declared.targets.length !== 2 || + declared.targets.some( + (target) => target.family !== 'native' || target.kind !== 'native-static-registry', + ) || + JSON.stringify(targets.map((target) => target.target).sort()) !== + JSON.stringify(['android-arm64-v8a', 'android-x86_64'])) + ) + fail(`${product} declared Maven inputs must cover both canonical Android targets`); const declaredCoordinates = new Set( - registryPackageRows({ product: releaseProduct, packageKind: 'maven' }, PREFIX) - .map((row) => row.packageName) - .filter((name) => name.startsWith(`dev.oliphaunt.extensions:${product}-`)), + ( + declared?.registryPackages ?? + registryPackageRows({ product: releaseProduct, packageKind: 'maven' }, PREFIX).map( + (row) => row.packageName, + ) + ).filter((name) => name.startsWith(`dev.oliphaunt.extensions:${product}-`)), ); + if (declared && new Set(declared.registryPackages).size !== declared.registryPackages.length) + fail(`${product} repeats a declared Maven coordinate`); for (const target of targets) { const coordinate = `dev.oliphaunt.extensions:${product}-${target.target}`; if (!declaredCoordinates.delete(coordinate)) { @@ -335,14 +400,26 @@ async function extensionRows(extensionRoot, selectedProducts) { path.join(productRoot, filename), `${product} ${target.target} Maven artifact`, ); - const licenseProfile = + const legacyLicenseProfile = product === 'oliphaunt-extension-contrib-pg18' ? 'contrib-native-openssl' : 'external-native'; + const memberContracts = declared?.memberContracts?.[target.target] ?? []; + const legal = declared + ? nativeExtensionCarrierLegal(product, sqlNames, { + target: target.target, + carriesPayload: true, + memberContracts, + }) + : null; + const licenseProfile = legal?.profile ?? legacyLicenseProfile; assertMavenPayloadLegal( file, licenseProfile, product === 'oliphaunt-extension-contrib-pg18' ? [] : sqlNames, + context?.noticeSourceRoot, + memberContracts.flatMap((member) => member.nativeConstructionLicenseFiles ?? []), + target.target, ); rows.push( tsvRow({ @@ -355,13 +432,26 @@ async function extensionRows(extensionRoot, selectedProducts) { runtimeProduct, runtimeVersion, licenseSpdx: - product === 'oliphaunt-extension-contrib-pg18' + legal?.packageSpdx ?? + (product === 'oliphaunt-extension-contrib-pg18' ? releaseProfilePackageLicense(licenseProfile).spdx - : registryLicense.packageSpdx, - licenses: - product === 'oliphaunt-extension-contrib-pg18' - ? releaseProfileMavenLicenses('contrib-native-openssl', { product, version }) - : extensionMavenLicenses(product, sqlNames, { version }), + : registryLicense.packageSpdx), + licenses: [ + ...(product === 'oliphaunt-extension-contrib-pg18' + ? releaseProfileMavenLicenses(licenseProfile, { + product, + version, + sourceRoot: context?.noticeSourceRoot, + }) + : extensionMavenLicenses(product, sqlNames, { version })), + ...memberContracts.flatMap((member) => + nativeExtensionConstructionMavenLicenses( + member.sqlName, + target.target, + member.nativeConstructionLicenseFiles ?? [], + ), + ), + ], }), ); } @@ -435,16 +525,21 @@ export async function buildMavenArtifactManifest( runtime = false, extensions = false, extensionProducts = [], + context, } = {}, ) { const includeRuntime = runtime || !extensions; const includeExtensions = extensions || extensionProducts.length > 0; const rows = []; if (includeRuntime) { - rows.push(...(await productRows(repoPath(runtimeAssetRoot), artifactProduct, artifactIds))); + rows.push( + ...(await productRows(repoPath(runtimeAssetRoot), artifactProduct, artifactIds, context)), + ); } if (includeExtensions) { - rows.push(...(await extensionRows(repoPath(extensionArtifactRoot), extensionProducts))); + rows.push( + ...(await extensionRows(repoPath(extensionArtifactRoot), extensionProducts, context)), + ); } if (rows.length === 0) { fail('manifest would be empty'); diff --git a/tools/packaging/cargo-manifest.mts b/tools/packaging/cargo-manifest.mts new file mode 100644 index 000000000..7fb8e08ef --- /dev/null +++ b/tools/packaging/cargo-manifest.mts @@ -0,0 +1,90 @@ +type Table = Record; + +/** Resolve Cargo's conventional workspace inheritance without changing requirements. */ +export function resolveCargoWorkspaceInheritance(manifest: Table, workspace: Table): Table { + const result = structuredClone(manifest); + for (const [key, value] of Object.entries(result.package ?? {}) as [string, Table][]) { + if (!value || typeof value !== 'object' || value.workspace !== true) continue; + if (workspace.package?.[key] === undefined) + throw new Error(`Missing inherited Cargo package.${key}`); + result.package[key] = structuredClone(workspace.package[key]); + } + for (const table of [result, ...Object.values(result.target ?? {})] as Table[]) { + for (const section of ['dependencies', 'dev-dependencies', 'build-dependencies']) { + for (const [name, value] of Object.entries(table[section] ?? {}) as [string, Table][]) { + if (!value || typeof value !== 'object' || value.workspace !== true) continue; + const inherited = workspace.dependencies?.[name]; + if (inherited === undefined) + throw new Error(`Missing inherited Cargo dependencies.${name}`); + const base = typeof inherited === 'string' ? { version: inherited } : inherited; + const member = Object.fromEntries( + Object.entries(value).filter(([key]) => key !== 'workspace'), + ); + table[section][name] = { ...structuredClone(base), ...member }; + if (base.features || member.features) + table[section][name].features = [ + ...new Set([...(base.features ?? []), ...(member.features ?? [])]), + ]; + } + } + } + return result; +} + +export function cargoSatisfies(version: string, requirement: string): boolean { + // Cargo ignores build metadata for version requirements; Bun does not. + const range = requirement.replaceAll(',', ' '); + return Bun.semver.satisfies(version.split('+', 1)[0], /^\d/.test(range) ? `^${range}` : range); +} + +/** The exact stable floor satisfying an owner's internal Cargo requirements. */ +export function cargoDependencyMinimum(requirement: string | string[]): string { + if (Array.isArray(requirement)) { + if (!requirement.length) + throw new Error('Internal Cargo minimum needs an authored requirement'); + const floor = requirement.map(cargoDependencyMinimum).sort(Bun.semver.order).at(-1)!; + if (!requirement.every((range) => cargoSatisfies(floor, range.trim()))) + throw new Error(`Internal Cargo minimum requirements conflict: ${requirement.join(', ')}`); + return floor; + } + const match = + /^(?:\^|~|=|>=)?\s*(\d+(?:\.\d+){0,2})(?:\s*,\s*<={0,1}\s*\d+(?:\.\d+){0,2})?$/u.exec( + requirement.trim(), + ); + if (!match) + throw new Error(`Internal Cargo minimum needs an explicit stable floor: ${requirement}`); + const floor = [...match[1].split('.'), '0', '0'].slice(0, 3).join('.'); + if (!cargoSatisfies(floor, requirement.trim())) + throw new Error(`Internal Cargo minimum is excluded by its requirement: ${requirement}`); + return floor; +} + +function tomlValue(value: unknown): string { + if (typeof value === 'string') return JSON.stringify(value); + if (typeof value === 'number' || typeof value === 'boolean') return String(value); + if (Array.isArray(value)) return `[${value.map(tomlValue).join(', ')}]`; + if (value && typeof value === 'object') + return `{ ${Object.entries(value) + .map(([key, item]) => `${JSON.stringify(key)} = ${tomlValue(item)}`) + .join(', ')} }`; + throw new Error(`Unsupported Cargo TOML value: ${String(value)}`); +} + +export function renderCargoToml(table: Table): string { + const scalars = Object.entries(table).filter( + ([, value]) => !value || typeof value !== 'object' || Array.isArray(value), + ); + const tables = Object.entries(table).filter( + ([, value]) => value && typeof value === 'object' && !Array.isArray(value), + ); + return `${[ + ...scalars.map(([key, value]) => `${JSON.stringify(key)} = ${tomlValue(value)}`), + ...tables.flatMap(([key, value]) => [ + '', + `[${JSON.stringify(key)}]`, + ...Object.entries(value as Table).map( + ([name, item]) => `${JSON.stringify(name)} = ${tomlValue(item)}`, + ), + ]), + ].join('\n')}\n`; +} diff --git a/tools/packaging/cargo-source-package.mts b/tools/packaging/cargo-source-package.mts index f8527149a..5631d3324 100644 --- a/tools/packaging/cargo-source-package.mts +++ b/tools/packaging/cargo-source-package.mts @@ -1,16 +1,20 @@ import { chmodSync, copyFileSync, + existsSync, lstatSync, mkdirSync, - readdirSync, readFileSync, rmSync, statSync, writeFileSync, } from 'node:fs'; import path from 'node:path'; -import { tarHeader } from './archive-directory.mts'; +import { renderCargoToml, resolveCargoWorkspaceInheritance } from './cargo-manifest.mts'; +import { createDeterministicTar, listArchiveEntries } from './package-archive.mts'; + +export { createDeterministicTar } from './package-archive.mts'; + import { canonicalGzipSync, readPortableArchiveEntries } from './portable-archive.mts'; import { stageReleaseNotices } from './release-notices.mts'; @@ -43,25 +47,14 @@ function abort(fail, message) { } export function parseCargoPackageNameVersion(text, context, { fail = null } = {}) { - let inPackage = false; - let name = null; - let version = null; - for (const rawLine of text.split(/\r?\n/u)) { - const line = rawLine.trim(); - if (line === '[package]') { - inPackage = true; - continue; - } - if (inPackage && line.startsWith('[')) { - break; - } - if (!inPackage) { - continue; - } - name ??= line.match(/^name\s*=\s*"([^"]+)"/u)?.[1] ?? null; - version ??= line.match(/^version\s*=\s*"([^"]+)"/u)?.[1] ?? null; + let manifest; + try { + manifest = Bun.TOML.parse(text); + } catch { + abort(fail, `${context} must contain valid Cargo TOML`); } - if (!name || !version) { + const { name, version } = manifest.package ?? {}; + if (typeof name !== 'string' || !name || typeof version !== 'string' || !version) { abort(fail, `${context} must declare package.name and package.version`); } return { name, version }; @@ -71,19 +64,65 @@ export function readCargoPackageNameVersion(manifest, { fail = null, rel = Strin return parseCargoPackageNameVersion(readFileSync(manifest, 'utf8'), rel(manifest), { fail }); } -export function packagedCargoManifestText(source) { +export function packagedCargoManifestText(source, workspaceText?: string) { + if (workspaceText !== undefined) { + const manifest = resolveCargoWorkspaceInheritance( + Bun.TOML.parse(source), + Bun.TOML.parse(workspaceText).workspace ?? {}, + ); + delete manifest.package.workspace; + manifest.workspace = {}; + for (const table of [manifest, ...Object.values(manifest.target ?? {})] as Record< + string, + any + >[]) { + for (const section of ['dependencies', 'dev-dependencies', 'build-dependencies']) { + for (const [name, dependency] of Object.entries(table[section] ?? {}) as [ + string, + Record, + ][]) { + if (!dependency || typeof dependency !== 'object' || !dependency.path) continue; + if (typeof dependency.version !== 'string') + throw new Error(`Unversioned public Cargo dependency ${name}`); + delete dependency.path; + } + } + } + return renderCargoToml(manifest); + } let text = source .replaceAll('repository.workspace = true', 'repository = "https://github.com/f0rr0/oliphaunt"') .replaceAll('homepage.workspace = true', 'homepage = "https://oliphaunt.dev"'); text = text .replace(/(\{\s*)path\s*=\s*"[^"]+",\s*/gu, '$1') .replace(/,\s*path\s*=\s*"[^"]+"/gu, ''); + if (/workspace\s*=\s*true/u.test(text)) + throw new Error( + 'Public Cargo workspace inheritance requires its conventional workspace manifest', + ); if (!text.includes('\n[workspace]')) { text = `${text.trimEnd()}\n\n[workspace]\n`; } return text; } +function conventionalWorkspaceText(manifest: string): string | undefined { + const packageDirectory = path.dirname(path.resolve(manifest)); + const own = Bun.TOML.parse(readFileSync(manifest, 'utf8')); + if (typeof own.package?.workspace === 'string') { + const workspace = path.resolve(packageDirectory, own.package.workspace, 'Cargo.toml'); + return readFileSync(workspace, 'utf8'); + } + for (let directory = packageDirectory; ; directory = path.dirname(directory)) { + const candidate = path.join(directory, 'Cargo.toml'); + if (existsSync(candidate)) { + const text = readFileSync(candidate, 'utf8'); + if (Bun.TOML.parse(text).workspace !== undefined) return text; + } + if (directory === path.dirname(directory)) return undefined; + } +} + const CARGO_VIRTUAL_PACKAGE_FILES = new Set([ '.cargo_vcs_info.json', 'Cargo.lock', @@ -280,66 +319,11 @@ function requirePackagedCargoTargetSources( } } -function listArchiveEntries(directory) { - const files = []; - const entries = readdirSync(directory, { withFileTypes: true }); - entries.sort((left, right) => compareText(left.name, right.name)); - for (const entry of entries) { - const fullPath = path.join(directory, entry.name); - if (entry.isDirectory()) { - files.push(fullPath, ...listArchiveEntries(fullPath)); - } else if (entry.isFile()) { - files.push(fullPath); - } else { - throw new Error( - 'Cargo archive source must contain only regular files and directories: ' + fullPath, - ); - } - } - return files; -} - -export function createDeterministicTar(stageDir, packageRoot, options) { - const chunks = []; - const fixedFileMode = options.fixedFileMode; - if ( - fixedFileMode !== undefined && - (!Number.isInteger(fixedFileMode) || fixedFileMode < 0 || fixedFileMode > 0o777) - ) { - abort( - options.fail, - 'fixed deterministic tar file mode must be an integer between 0000 and 0777', - ); - } - const files = listArchiveEntries(stageDir).filter( - (file) => options.includeDirectories !== false || statSync(file).isFile(), - ); - files.sort((left, right) => - compareText(path.relative(stageDir, left), path.relative(stageDir, right)), - ); - for (const file of files) { - const relative = path.relative(stageDir, file).split(path.sep).join('/'); - const archivePath = `${packageRoot}/${relative}`; - const stats = statSync(file); - const isDirectory = stats.isDirectory(); - const data = isDirectory ? Buffer.alloc(0) : readFileSync(file); - const mode = isDirectory ? 0o755 : (fixedFileMode ?? stats.mode & 0o777); - chunks.push(tarHeader({ name: archivePath, isDirectory }, data.length, mode)); - chunks.push(data); - const remainder = data.length % 512; - if (remainder !== 0) { - chunks.push(Buffer.alloc(512 - remainder, 0)); - } - } - chunks.push(Buffer.alloc(1024, 0)); - return Buffer.concat(chunks); -} - export function prepareCargoPackageSource( manifest, outputDir, files, - { fail = null, rel = String, noticeProfile = null } = {}, + { fail = null, rel = String, noticeProfile = null, noticeSourceRoot = undefined } = {}, ) { const { name, version } = readCargoPackageNameVersion(manifest, { fail, rel }); const packageRoot = `${name}-${version}`; @@ -348,7 +332,7 @@ export function prepareCargoPackageSource( const cratePath = path.resolve(outputDir, `${packageRoot}.crate`); let expectedMembers = [...copyCargoPackageSource(manifest, stageDir, files, { fail, rel })]; if (noticeProfile !== null) { - stageReleaseNotices(stageDir, { profile: noticeProfile }); + stageReleaseNotices(stageDir, { profile: noticeProfile, sourceRoot: noticeSourceRoot }); // Notice staging may add or remove profile-owned members. Cargo still owns // every other source member; archive validation uses the final staged set. expectedMembers = listArchiveEntries(stageDir) @@ -356,7 +340,13 @@ export function prepareCargoPackageSource( .map((file) => path.relative(stageDir, file).split(path.sep).join('/')); } const stagedManifest = path.join(stageDir, 'Cargo.toml'); - writeFileSync(stagedManifest, packagedCargoManifestText(readFileSync(stagedManifest, 'utf8'))); + writeFileSync( + stagedManifest, + packagedCargoManifestText( + readFileSync(stagedManifest, 'utf8'), + conventionalWorkspaceText(manifest), + ), + ); return { name, version, packageRoot, stageDir, cratePath, expectedMembers, stagedManifest }; } @@ -376,12 +366,17 @@ export function finishCargoPackageSource(state, packageMetadata, options = {}) { function freezeCargoPackageSource( { stageDir, packageRoot, cratePath, expectedMembers }, - { fail = null, rel = String, packageSizeLimitBytes = CARGO_PACKAGE_SIZE_LIMIT_BYTES } = {}, + { + fail = null, + rel = String, + packageSizeLimitBytes = CARGO_PACKAGE_SIZE_LIMIT_BYTES, + fixedFileMode = undefined, + } = {}, ) { rmSync(cratePath, { force: true }); writeFileSync( cratePath, - canonicalGzipSync(createDeterministicTar(stageDir, packageRoot, { fail })), + canonicalGzipSync(createDeterministicTar(stageDir, packageRoot, { fail, fixedFileMode })), ); requireExactCrateMembers(cratePath, packageRoot, expectedMembers, { fail, rel }); const size = statSync(cratePath).size; diff --git a/tools/packaging/cargo-source-package.test.mts b/tools/packaging/cargo-source-package.test.mts index 078010e97..4f3013143 100644 --- a/tools/packaging/cargo-source-package.test.mts +++ b/tools/packaging/cargo-source-package.test.mts @@ -19,7 +19,9 @@ import { cargoPackageRelativePathParts, createDeterministicTar, fitCargoPayloadParts, + packagedCargoManifestText, packageGeneratedCargoSource, + parseCargoPackageNameVersion, } from './cargo-source-package.mts'; import { readPortableArchiveEntries } from './portable-archive.mts'; import { assertReleaseNoticesInArchive } from './release-notices.mts'; @@ -122,6 +124,40 @@ if (['prepare', 'verify'].includes(process.argv[2])) { process.exit(0); } +test('standalone public manifests resolve inherited requirements and structurally remove every path', () => { + const source = + '[package]\nname="sdk"\nversion="0.3.2"\nworkspace="../adapters"\n[dependencies]\nquery={workspace=true,optional=true}\n[build-dependencies]\nhelper={path="../helper",version="0.3.2"}\n[target.\'cfg(unix)\'.dependencies]\nruntime={path="../runtime",version="=0.3.2"}\n[workspace]\n'; + const text = packagedCargoManifestText( + source, + '[workspace.dependencies]\nquery={version="=0.1.1",features=["std"]}\n', + ); + assert.deepEqual(parseCargoPackageNameVersion(text, 'normalized manifest'), { + name: 'sdk', + version: '0.3.2', + }); + assert.throws( + () => + parseCargoPackageNameVersion('[package]\nname="sdk"\nversion={workspace=true}\n', 'source'), + /package.name and package.version/u, + ); + assert.throws( + () => parseCargoPackageNameVersion('[package', 'invalid source'), + /valid Cargo TOML/u, + ); + const standalone = Bun.TOML.parse(text); + assert.deepEqual(standalone.dependencies.query, { + version: '=0.1.1', + features: ['std'], + optional: true, + }); + assert.deepEqual(standalone['build-dependencies'].helper, { version: '0.3.2' }); + assert.deepEqual(standalone.target['cfg(unix)'].dependencies.runtime, { version: '=0.3.2' }); + assert.equal(standalone.package.workspace, undefined); + assert.deepEqual(standalone.workspace, {}); + assert.equal(text.match(/\["workspace"\]/gu)?.length, 1); + assert.throws(() => packagedCargoManifestText(source), /inheritance/); +}); + test('payload splitting follows compressed crate size and preserves every byte', (t) => { const { root } = fixture(t, 'compressed-parts'); for (const payload of [Buffer.alloc(20 * 1024 * 1024, 42), randomBytes(20 * 1024 * 1024)]) { @@ -239,3 +275,48 @@ test('generated Cargo carriers match Cargo-selected source bytes and reject link ); assert.throws(() => createDeterministicTar(source, 'unsafe', {}), /regular files/); }); + +test('generated Cargo carriers apply explicit archive modes and preserve source modes by default', (t) => { + const { root, source } = fixture(t, 'generated-cargo-modes'); + writeFileSync(path.join(source, 'Cargo.toml'), manifest('generated-modes')); + const writable = path.join(source, 'src/lib.rs'); + const executable = path.join(source, 'build.rs'); + writeFileSync(writable, 'pub const VALUE: u32 = 42;\n'); + writeFileSync(executable, 'fn main() {}\n'); + chmodSync(writable, 0o666); + chmodSync(executable, 0o755); + + const archive = (directory, options = {}) => + readPortableArchiveEntries( + packageGeneratedCargoSource( + path.join(source, 'Cargo.toml'), + path.join(root, directory), + options, + ), + ); + const fixed = archive('fixed', { fixedFileMode: 0o644 }); + for (const [name, entry] of fixed) { + assert.equal(entry.mode, entry.isFile ? 0o644 : 0o755, name); + } + assert.equal( + fixed.get('generated-modes-0.1.0/src/lib.rs').data().toString(), + readFileSync(writable, 'utf8'), + ); + assert.equal( + fixed.get('generated-modes-0.1.0/build.rs').data().toString(), + readFileSync(executable, 'utf8'), + ); + + const preserved = archive('preserved'); + assert.equal( + preserved.get('generated-modes-0.1.0/src/lib.rs').mode, + statSync(writable).mode & 0o777, + ); + assert.equal( + preserved.get('generated-modes-0.1.0/build.rs').mode, + statSync(executable).mode & 0o777, + ); + if (process.platform !== 'win32') { + assert.equal(preserved.get('generated-modes-0.1.0/build.rs').mode, 0o755); + } +}); diff --git a/tools/packaging/frozen-cargo.mts b/tools/packaging/frozen-cargo.mts new file mode 100644 index 000000000..eba26b5a1 --- /dev/null +++ b/tools/packaging/frozen-cargo.mts @@ -0,0 +1,72 @@ +import { createHash } from 'node:crypto'; +import { mkdirSync, readFileSync, realpathSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { extractPortableArchiveTree } from './portable-archive.mts'; + +/** Join actual Cargo compiler messages to the original staged source manifests. */ +export function assertCargoSourceArtifacts( + messages: string, + sources: { name: string; version: string; manifestPath: string }[], + requiredNames: string[] = [], +) { + const expected = new Map(sources.map((source) => [source.name, source])); + if (expected.size !== sources.length) + throw new Error('Cargo source artifact names are duplicated'); + const compiled = new Map(); + for (const line of messages.split('\n').filter((line) => line.trim())) { + const message = JSON.parse(line); + if (message.reason !== 'compiler-artifact') continue; + if (typeof message.manifest_path !== 'string' || !path.isAbsolute(message.manifest_path)) + throw new Error('Cargo compiler artifact has no absolute manifest path'); + const manifest = Bun.TOML.parse(readFileSync(message.manifest_path, 'utf8')); + const source = expected.get(manifest.package?.name); + if (!source) continue; + if ( + manifest.package?.version !== source.version || + realpathSync(message.manifest_path) !== realpathSync(source.manifestPath) + ) + throw new Error(`Cargo compiled source differs: ${source.name}@${source.version}`); + compiled.set(source.name, source); + } + for (const name of requiredNames) + if (!compiled.has(name)) throw new Error(`Cargo source was not compiled: ${name}`); + return [...compiled.values()]; +} + +export type CargoCarrierInput = { + file: string; + name: string; + version: string; + sha256: string; +}; + +/** Stage authenticated final source envelopes without choosing their versions. */ +export function stageCargoCarrierInputs(inputs: CargoCarrierInput[], directory: string) { + const patches: string[] = []; + const names = new Set(); + for (const input of inputs) { + if ( + !/^[A-Za-z0-9][A-Za-z0-9_-]*$/u.test(input.name) || + !/^[0-9A-Za-z][0-9A-Za-z.+-]*$/u.test(input.version) || + names.has(input.name) || + !/^[a-f0-9]{64}$/u.test(input.sha256) || + createHash('sha256').update(readFileSync(input.file)).digest('hex') !== input.sha256 + ) + throw new Error(`frozen Cargo input differs: ${input.name}@${input.version}`); + names.add(input.name); + const destination = path.join(directory, 'crates', `${input.name}-${input.version}`); + extractPortableArchiveTree(input.file, destination, `${input.name}-${input.version}`); + const manifest = Bun.TOML.parse(readFileSync(path.join(destination, 'Cargo.toml'), 'utf8')); + if ( + manifest.package?.name !== input.name || + manifest.package?.version !== input.version || + Object.hasOwn(manifest.package?.metadata?.oliphaunt ?? {}, 'qualificationOnly') + ) + throw new Error(`frozen Cargo identity differs: cargo:${input.name}`); + patches.push(`${JSON.stringify(input.name)} = { path = ${JSON.stringify(destination)} }`); + } + const config = path.join(directory, 'cargo-config.toml'); + mkdirSync(directory, { recursive: true }); + writeFileSync(config, `[patch.crates-io]\n${patches.join('\n')}\n`); + return config; +} diff --git a/tools/packaging/linux-abi-baseline.test.sh b/tools/packaging/linux-abi-baseline.test.sh index 577568ff9..c7be593e0 100644 --- a/tools/packaging/linux-abi-baseline.test.sh +++ b/tools/packaging/linux-abi-baseline.test.sh @@ -22,7 +22,7 @@ if [ "${1:-}" = image ] && [ "${2:-}" = inspect ]; then printf '%s\n' "${FAKE_IMAGE_DIGEST:-${!#}}" elif [ "${1:-}" = run ]; then case "$*" in - *'cargo build -p oliphaunt-broker'*) + *'cargo build --manifest-path src/native/broker/Cargo.toml'*) mkdir -p "$FAKE_TARGET_DIR/release" printf '#!/bin/sh\nexit 0\n' > "$FAKE_TARGET_DIR/release/oliphaunt-broker" chmod 755 "$FAKE_TARGET_DIR/release/oliphaunt-broker" ;; diff --git a/tools/packaging/maven-artifact-manifest.test.mts b/tools/packaging/maven-artifact-manifest.test.mts index 37b9d3a49..696b52657 100644 --- a/tools/packaging/maven-artifact-manifest.test.mts +++ b/tools/packaging/maven-artifact-manifest.test.mts @@ -1,21 +1,21 @@ import { afterEach, expect, test } from 'bun:test'; -import { chmodSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { chmodSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; import os from 'node:os'; import path from 'node:path'; - -import { buildMavenArtifactManifest } from './build-maven-artifact-manifest.mts'; -import { archiveDirectory } from './archive-directory.mts'; -import { createDeterministicTar } from './cargo-source-package.mts'; import { stageExtensionUpstreamLicenses } from '../../src/extensions/tools/extension-upstream-licenses.mts'; -import { canonicalGzipSync } from './portable-archive.mts'; -import { parseMavenArtifactManifest } from './maven-artifact-manifest.mts'; -import { renderMavenArtifactPom } from './maven-artifact-staging.mts'; import { currentProductVersionSync, + extensionArtifactTargets, extensionMetadata, extensionReleaseVersion, + registryPackageRows, } from '../release/release-artifact-targets.mts'; -import { ROOT } from '../release/release-graph.mts'; +import { archiveDirectory } from './archive-directory.mts'; +import { buildMavenArtifactManifest } from './build-maven-artifact-manifest.mts'; +import { createDeterministicTar } from './cargo-source-package.mts'; +import { parseMavenArtifactManifest } from './maven-artifact-manifest.mts'; +import { renderMavenArtifactPom } from './maven-artifact-staging.mts'; +import { canonicalGzipSync } from './portable-archive.mts'; import { stageReleaseNotices } from './release-notices.mts'; const temporaryRoots = []; @@ -283,3 +283,48 @@ test('the Maven manifest builder validates singleton upstream licenses in the ru ).rejects.toThrow(pattern); } }); + +test('declared extension Maven inputs preserve canonical writer bytes and reject incomplete targets', async () => { + const root = temporaryDirectory(); + const product = 'oliphaunt-extension-pg-hashids'; + for (const target of ['android-arm64-v8a', 'android-x86_64']) + await singletonAndroidRuntime(root, target); + const baseline = path.join(root, 'baseline.tsv'); + const output = path.join(root, 'declared.tsv'); + const options = { extensions: true, extensionProducts: [product], extensionArtifactRoot: root }; + await buildMavenArtifactManifest(baseline, options); + const row = { + productRoot: path.join(root, product), + releaseProduct: product, + version: currentProductVersionSync(product), + sqlNames: ['pg_hashids'], + compatibility: extensionMetadata(product).compatibility, + runtimeSourceVersion: currentProductVersionSync('liboliphaunt-native'), + targets: extensionArtifactTargets({ product, family: 'native' }).filter( + (target) => target.kind === 'native-static-registry' && target.target.startsWith('android-'), + ), + registryPackages: registryPackageRows({ product, packageKind: 'maven' }).map( + (carrier) => carrier.packageName, + ), + }; + const context = { extensions: { [product]: row } }; + await buildMavenArtifactManifest(output, { ...options, context }); + expect(readFileSync(output)).toEqual(readFileSync(baseline)); + await expect( + buildMavenArtifactManifest(output, { + ...options, + context: { extensions: { [product]: { ...row, targets: row.targets.slice(1) } } }, + }), + ).rejects.toThrow('both canonical Android targets'); + await expect( + buildMavenArtifactManifest(output, { + ...options, + context: { + extensions: { [product]: { ...row, registryPackages: row.registryPackages.slice(1) } }, + }, + }), + ).rejects.toThrow('missing Maven carrier'); + await expect( + buildMavenArtifactManifest(output, { ...options, context: { extensions: {} } }), + ).rejects.toThrow('absent from declared'); +}); diff --git a/tools/packaging/maven-artifact-staging.mts b/tools/packaging/maven-artifact-staging.mts index a9e54b98d..16e555466 100644 --- a/tools/packaging/maven-artifact-staging.mts +++ b/tools/packaging/maven-artifact-staging.mts @@ -5,7 +5,6 @@ import { chmodSync, copyFileSync, existsSync, - lstatSync, mkdirSync, readFileSync, readdirSync, @@ -109,11 +108,14 @@ function exactFiles(directory, expected, label) { return names; } -async function writeCompanionJar(stageRoot, row, classifier) { +async function writeCompanionJar(stageRoot, row, classifier, noticeSourceRoot) { const coordinate = `${row.groupId}:${row.artifactId}:${row.version}`; const root = path.join(stageRoot, `${classifier}-stage`); mkdirSync(path.join(root, 'META-INF'), { recursive: true }); - stageReleaseNotices(path.join(root, 'META-INF'), { profile: 'source-sdk' }); + stageReleaseNotices(path.join(root, 'META-INF'), { + profile: 'source-sdk', + sourceRoot: noticeSourceRoot, + }); writeFileSync(path.join(root, 'META-INF/MANIFEST.MF'), MANIFEST, { mode: 0o644 }); if (classifier === 'sources') { writeFileSync( @@ -135,7 +137,7 @@ async function writeCompanionJar(stageRoot, row, classifier) { * Materialize the immutable, unsigned Maven Central input closure without * Gradle, Java, registry access, credentials, or dependency resolution. */ -export async function stageMavenArtifactManifest(manifest, outputRoot) { +export async function stageMavenArtifactManifest(manifest, outputRoot, { noticeSourceRoot } = {}) { const rows = parseMavenArtifactManifest(path.resolve(manifest)); const destination = path.resolve(outputRoot); const stage = createSiblingStage(destination, 'maven-artifacts'); @@ -153,12 +155,20 @@ export async function stageMavenArtifactManifest(manifest, outputRoot) { chmodSync(primary, 0o644); writeFileSync(pom, renderMavenArtifactPom(row), { mode: 0o644 }); const companionRoot = path.join(stage, '.companion-stage', row.artifactId, row.version); - writeFileSync(sources, await writeCompanionJar(companionRoot, row, 'sources'), { - mode: 0o644, - }); - writeFileSync(javadoc, await writeCompanionJar(companionRoot, row, 'javadoc'), { - mode: 0o644, - }); + writeFileSync( + sources, + await writeCompanionJar(companionRoot, row, 'sources', noticeSourceRoot), + { + mode: 0o644, + }, + ); + writeFileSync( + javadoc, + await writeCompanionJar(companionRoot, row, 'javadoc', noticeSourceRoot), + { + mode: 0o644, + }, + ); rmSync(companionRoot, { recursive: true, force: true }); const files = exactFiles( directory, diff --git a/tools/packaging/maven-central-contract.mts b/tools/packaging/maven-central-contract.mts index c17170d8a..6ded99ed0 100644 --- a/tools/packaging/maven-central-contract.mts +++ b/tools/packaging/maven-central-contract.mts @@ -126,7 +126,7 @@ function requireMetadata(project, context) { * Validate the immutable files for one Maven Central coordinate before any * signing, upload, or GitHub release mutation occurs. */ -export function validateMavenCentralPublication({ pomText, files, context = 'Maven publication' }) { +export function mavenCentralPublicationFiles(pomText, context = 'Maven publication') { if (typeof pomText !== 'string' || pomText.length === 0) { throw error(`${context} POM must be nonempty UTF-8 text`); } @@ -166,19 +166,24 @@ export function validateMavenCentralPublication({ pomText, files, context = 'Mav ); requireMetadata(project, context); - const names = normalizedFiles(files, context); const prefix = `${artifactId}-${version}`; const required = [`${prefix}.pom`]; if (packaging !== 'pom') { required.push(`${prefix}.${packaging}`, `${prefix}-sources.jar`, `${prefix}-javadoc.jar`); } + return { artifactId, groupId, packaging, version, files: required }; +} + +export function validateMavenCentralPublication({ pomText, files, context = 'Maven publication' }) { + const { files: required, ...identity } = mavenCentralPublicationFiles(pomText, context); + const names = normalizedFiles(files, context); for (const name of required) { if (!names.has(name)) { throw error( - `${context} (${groupId}:${artifactId}:${version}, packaging ${packaging}) is missing required file ${name}`, + `${context} (${identity.groupId}:${identity.artifactId}:${identity.version}, packaging ${identity.packaging}) is missing required file ${name}`, ); } } - return { artifactId, groupId, packaging, version }; + return identity; } diff --git a/tools/packaging/native-cargo-payload.mts b/tools/packaging/native-cargo-payload.mts index b80a1d9d4..80d23df55 100644 --- a/tools/packaging/native-cargo-payload.mts +++ b/tools/packaging/native-cargo-payload.mts @@ -1,4 +1,3 @@ -import { assertSameStringSet } from './release-carrier.mts'; import { createHash } from 'node:crypto'; import { closeSync, @@ -14,12 +13,19 @@ import { writeFileSync, } from 'node:fs'; import path from 'node:path'; +import { + allArtifactTargets, + compareText, + currentProductVersion, + ROOT, +} from '../release/release-artifact-targets.mts'; import { createDeterministicTar, fitCargoPayloadParts, packageGeneratedCargoSource, } from './cargo-source-package.mts'; import { canonicalGzipSync } from './portable-archive.mts'; +import { assertSameStringSet } from './release-carrier.mts'; import { assertReleaseNoticesInArchive, assertReleaseNoticesInDirectory, @@ -27,12 +33,6 @@ import { releaseProfilePackageLicense, stageReleaseNotices, } from './release-notices.mts'; -import { - allArtifactTargets, - compareText, - currentProductVersion, - ROOT, -} from '../release/release-artifact-targets.mts'; const PREFIX = 'native-cargo-payload.mts'; const PRODUCT = 'liboliphaunt-native'; @@ -58,7 +58,7 @@ const TARGET: &str = __TARGET__; const PART_ROOTS: &[&str] = &[ __PART_ROOTS__ ]; -const FILE_SHA256: &[(&str, &str)] = &[ +const FILE_SHA256: &[(&str, &str, bool)] = &[ __FILE_SHA256__ ]; @@ -124,15 +124,15 @@ fn emit_manifest() { .expect("payload file stays under payload root") .to_string_lossy() .replace('\\', "/"); - let sha256 = FILE_SHA256.iter() - .find_map(|(candidate, digest)| (*candidate == relative).then_some(*digest)) + let (sha256, executable) = FILE_SHA256.iter() + .find_map(|(candidate, digest, executable)| (*candidate == relative).then_some((*digest, *executable))) .unwrap_or_else(|| panic!("reconstructed liboliphaunt payload has undeclared file {relative}")); text.push_str(&format!( "\n[[files]]\nsource = {:?}\nrelative = {:?}\nsha256 = {:?}\nexecutable = {}\n", file.display().to_string(), relative, sha256, - is_executable_relative(&relative), + executable, )); } fs::write(&manifest, text).expect("write liboliphaunt native artifact manifest"); @@ -232,9 +232,6 @@ fn collect_files_inner(path: &Path, files: &mut Vec) -> io::Result<()> Ok(()) } -fn is_executable_relative(relative: &str) -> bool { - relative.starts_with("runtime/bin/") || relative.starts_with("bin/") -} `; export function fail(message) { @@ -304,16 +301,25 @@ function tomlString(value) { return JSON.stringify(value); } -function cargoIncludeMembers(profile, baseMembers) { +function cargoIncludeMembers(profile, baseMembers, noticeSourceRoot) { return JSON.stringify([ ...baseMembers, - ...releaseNoticeRows({ profile }).map((row) => row.member), + ...releaseNoticeRows({ profile, sourceRoot: noticeSourceRoot }).map((row) => row.member), ]); } function writePartCrate( crateDir, - { targetId, index, version, packageBase, artifactProduct, artifactLabel, noticeProfile }, + { + targetId, + index, + version, + packageBase, + artifactProduct, + artifactLabel, + noticeProfile, + noticeSourceRoot, + }, ) { rmSync(crateDir, { recursive: true, force: true }); const name = partPackageName(targetId, index, { packageBase }); @@ -333,7 +339,7 @@ homepage = "https://oliphaunt.dev" license = "${NATIVE_CARGO_CARRIER_LICENSES[noticeProfile]}" links = "${links}" build = "build.rs" -include = ${cargoIncludeMembers(noticeProfile, ['Cargo.toml', 'README.md', 'build.rs', 'src/**', 'payload/**'])} +include = ${cargoIncludeMembers(noticeProfile, ['Cargo.toml', 'README.md', 'build.rs', 'src/**', 'payload/**'], noticeSourceRoot)} [lib] path = "src/lib.rs" @@ -377,8 +383,11 @@ fn main() { } `, ); - stageReleaseNotices(crateDir, { profile: noticeProfile }); - assertReleaseNoticesInDirectory(crateDir, { profile: noticeProfile }); + stageReleaseNotices(crateDir, { profile: noticeProfile, sourceRoot: noticeSourceRoot }); + assertReleaseNoticesInDirectory(crateDir, { + profile: noticeProfile, + sourceRoot: noticeSourceRoot, + }); } function writeAggregatorCrate( @@ -392,6 +401,7 @@ function writeAggregatorCrate( artifactKind, artifactLabel, payloadFiles, + noticeSourceRoot, }, ) { rmSync(crateDir, { recursive: true, force: true }); @@ -423,7 +433,7 @@ homepage = "https://oliphaunt.dev" license = "${NATIVE_CARGO_CARRIER_LICENSES['code-facade']}" links = "${links}" build = "build.rs" -include = ${cargoIncludeMembers('code-facade', ['Cargo.toml', 'README.md', 'build.rs', 'src/**'])} +include = ${cargoIncludeMembers('code-facade', ['Cargo.toml', 'README.md', 'build.rs', 'src/**'], noticeSourceRoot)} [lib] path = "src/lib.rs" @@ -464,12 +474,18 @@ pub const LIBRARY_RELATIVE_PATH: &str = "${libraryRelativePath}"; .replace( '__FILE_SHA256__', payloadFiles - .map(({ relative, sha256 }) => ` (${tomlString(relative)}, ${tomlString(sha256)}),`) + .map( + ({ relative, sha256, executable }) => + ` (${tomlString(relative)}, ${tomlString(sha256)}, ${executable}),`, + ) .join('\n'), ), ); - stageReleaseNotices(crateDir, { profile: 'code-facade' }); - assertReleaseNoticesInDirectory(crateDir, { profile: 'code-facade' }); + stageReleaseNotices(crateDir, { profile: 'code-facade', sourceRoot: noticeSourceRoot }); + assertReleaseNoticesInDirectory(crateDir, { + profile: 'code-facade', + sourceRoot: noticeSourceRoot, + }); } function walkFiles(root) { @@ -491,11 +507,25 @@ function walkFiles(root) { return files.sort(compareText); } -function frozenPayloadFiles(root) { - return walkFiles(root).map((file) => ({ - relative: path.relative(root, file).split(path.sep).join('/'), - sha256: createHash('sha256').update(readFileSync(file)).digest('hex'), - })); +function frozenPayloadFiles(root, executableFiles?: readonly string[]) { + const executables = executableFiles === undefined ? undefined : new Set(executableFiles); + const files = walkFiles(root).map((file) => { + const relative = path.relative(root, file).split(path.sep).join('/'); + return { + relative, + sha256: createHash('sha256').update(readFileSync(file)).digest('hex'), + executable: executables + ? executables.has(relative) + : relative.startsWith('runtime/bin/') || relative.startsWith('bin/'), + }; + }); + if (executables) + assertSameStringSet( + 'declared executable native payload files', + files.filter(({ executable }) => executable).map(({ relative }) => relative), + executableFiles, + ); + return files; } function nextPartDir( @@ -503,7 +533,7 @@ function nextPartDir( targetId, index, version, - { packageBase, artifactProduct, artifactLabel, noticeProfile }, + { packageBase, artifactProduct, artifactLabel, noticeProfile, noticeSourceRoot }, ) { const crateDir = path.join(sourceRoot, partPackageName(targetId, index, { packageBase })); writePartCrate(crateDir, { @@ -514,6 +544,7 @@ function nextPartDir( artifactProduct, artifactLabel, noticeProfile, + noticeSourceRoot, }); return crateDir; } @@ -531,7 +562,16 @@ function copyPayloadFile(source, destination) { function buildPartCrates( extractedRoot, sourceRoot, - { targetId, version, partBytes, packageBase, artifactProduct, artifactLabel, noticeProfile }, + { + targetId, + version, + partBytes, + packageBase, + artifactProduct, + artifactLabel, + noticeProfile, + noticeSourceRoot, + }, ) { const partDirs = []; let currentDir; @@ -546,6 +586,7 @@ function buildPartCrates( artifactProduct, artifactLabel, noticeProfile, + noticeSourceRoot, }); partDirs.push(partDir); return partDir; @@ -605,15 +646,21 @@ function validateCrateSize(cratePath) { } } -export function freezeSourceCrate(packageData, outputDir, cargoTargetDir) { +export function freezeSourceCrate( + packageData, + outputDir, + cargoTargetDir, + { noticeSourceRoot } = {}, +) { const generated = packageGeneratedCargoSource( packageData.manifestPath, path.join(cargoTargetDir, 'strict-package', packageData.name), - { root: ROOT, fail, rel }, + { root: ROOT, fail, rel, fixedFileMode: 0o644 }, ); assertReleaseNoticesInArchive(generated, { prefix: `${packageData.name}-${packageData.version}`, profile: packageData.noticeProfile, + sourceRoot: noticeSourceRoot, }); validateCrateSize(generated); const cratePath = path.join(outputDir, path.basename(generated)); @@ -635,6 +682,8 @@ export function packagePayload( artifactKind, artifactLabel, noticeProfile, + noticeSourceRoot, + executableFiles, }, ) { const partDirs = fitCargoPayloadParts( @@ -647,6 +696,7 @@ export function packagePayload( artifactProduct, artifactLabel, noticeProfile, + noticeSourceRoot, }), (partDir) => { // Every file here was generated for this payload part; no source selection @@ -657,7 +707,9 @@ export function packagePayload( const crate = path.join(probeDir, `${packageRoot}.crate`); writeFileSync( crate, - canonicalGzipSync(createDeterministicTar(partDir, packageRoot, { fail })), + canonicalGzipSync( + createDeterministicTar(partDir, packageRoot, { fail, fixedFileMode: 0o644 }), + ), ); return crate; }, @@ -672,7 +724,8 @@ export function packagePayload( artifactProduct, artifactKind, artifactLabel, - payloadFiles: frozenPayloadFiles(payloadRoot), + payloadFiles: frozenPayloadFiles(payloadRoot, executableFiles), + noticeSourceRoot, }); const packages = []; @@ -684,6 +737,7 @@ export function packagePayload( assertReleaseNoticesInArchive(cratePath, { prefix: `${name}-${version}`, profile: noticeProfile, + sourceRoot: noticeSourceRoot, }); validateCrateSize(cratePath); const output = path.join(outputDir, path.basename(cratePath)); @@ -716,6 +770,7 @@ export function packagePayload( }, outputDir, cargoTargetDir, + { noticeSourceRoot }, ), ); return packages; diff --git a/tools/packaging/npm-package.mts b/tools/packaging/npm-package.mts index dcc6c00c5..f43654b7d 100644 --- a/tools/packaging/npm-package.mts +++ b/tools/packaging/npm-package.mts @@ -1,15 +1,7 @@ -import { - chmodSync, - mkdirSync, - readdirSync, - readFileSync, - rmSync, - statSync, - writeFileSync, -} from 'node:fs'; +import { mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs'; import path from 'node:path'; -import { createDeterministicTar } from './cargo-source-package.mts'; import { validateNpmTrustedPublishingManifest } from './npm-trusted-publishing.mts'; +import { createDeterministicTar, listArchiveEntries } from './package-archive.mts'; import { canonicalGzipSync, portableMemberName } from './portable-archive.mts'; if (import.meta.main) { @@ -27,6 +19,11 @@ function reject(message) { throw new Error(message); } +export function npmArchiveFileMode(mode, declaredExecutable = false, platform = process.platform) { + // Windows stat bits do not describe Unix executability; declarations do. + return declaredExecutable || (platform !== 'win32' && (mode & 0o100) !== 0) ? 0o755 : 0o644; +} + export function packGeneratedNpmCarrier(packageDir, tarballRoot) { const manifest = JSON.parse(readFileSync(path.join(packageDir, 'package.json'), 'utf8')); validateNpmTrustedPublishingManifest(manifest, `${packageDir}/package.json`); @@ -35,20 +32,33 @@ export function packGeneratedNpmCarrier(packageDir, tarballRoot) { const packDir = path.join(tarballRoot, safeNpmPackageFilenamePrefix(manifest.name)); const filename = `${safeNpmPackageFilenamePrefix(manifest.name)}-${manifest.version}.tgz`; portableMemberName(filename, 'file', packageDir); - for (const member of manifest.publishConfig?.executableFiles ?? []) { - chmodSync(path.join(packageDir, portableMemberName(member, 'file', packageDir)), 0o755); + const executableFiles = new Set( + (manifest.publishConfig?.executableFiles ?? []).map((member) => + portableMemberName(member, 'file', packageDir), + ), + ); + const files = new Set(listArchiveEntries(packageDir).filter((file) => statSync(file).isFile())); + for (const member of executableFiles) { + if (!files.has(path.join(packageDir, member))) + reject(`declared npm executable must be a regular package file: ${member}`); } - for (const entry of readdirSync(packageDir, { recursive: true, withFileTypes: true })) { - if (!entry.isFile()) continue; - const file = path.join(entry.parentPath, entry.name); - chmodSync(file, statSync(file).mode & 0o100 ? 0o755 : 0o644); + for (const file of files) { + const member = path.relative(packageDir, file).split(path.sep).join('/'); + if (npmArchiveFileMode(statSync(file).mode, executableFiles.has(member)) === 0o755) + executableFiles.add(member); } rmSync(packDir, { recursive: true, force: true }); mkdirSync(packDir, { recursive: true }); const tarball = path.join(packDir, filename); writeFileSync( tarball, - canonicalGzipSync(createDeterministicTar(packageDir, 'package', { fail: reject })), + canonicalGzipSync( + createDeterministicTar(packageDir, 'package', { + fail: reject, + fixedFileMode: 0o644, + executableFiles, + }), + ), ); return tarball; } diff --git a/tools/packaging/npm-package.test.mts b/tools/packaging/npm-package.test.mts new file mode 100644 index 000000000..b77b32be7 --- /dev/null +++ b/tools/packaging/npm-package.test.mts @@ -0,0 +1,111 @@ +import assert from 'node:assert/strict'; +import { + chmodSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + statSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import { + assertExtensionUpstreamLicensesInArchive, + stageExtensionUpstreamLicenses, +} from '../../src/extensions/tools/extension-upstream-licenses.mts'; +import { npmArchiveFileMode, packGeneratedNpmCarrier } from './npm-package.mts'; +import { listArchiveEntries } from './package-archive.mts'; +import { readPortableArchiveEntries } from './portable-archive.mts'; + +function fixture(t) { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-npm-modes-')); + const source = path.join(root, 'package'); + mkdirSync(path.join(source, 'bin'), { recursive: true }); + const manifest = { + name: '@oliphaunt/mode-fixture', + version: '1.0.0', + repository: { type: 'git', url: 'git+https://github.com/f0rr0/oliphaunt.git' }, + publishConfig: { access: 'public', provenance: true, executableFiles: ['./bin/declared.exe'] }, + }; + const writeManifest = () => + writeFileSync(path.join(source, 'package.json'), `${JSON.stringify(manifest)}\n`); + writeManifest(); + writeFileSync(path.join(source, 'bin/declared.exe'), 'declared executable bytes\n'); + t.after(() => { + // Windows represents read-only staging files using the read-only attribute. + for (const file of listArchiveEntries(source)) { + if (statSync(file).isFile()) chmodSync(file, 0o666); + } + rmSync(root, { recursive: true, force: true }); + }); + return { root, source, manifest, writeManifest }; +} + +test('npm archive modes ignore Windows synthetic bits and preserve Unix executability', () => { + for (const mode of [0o444, 0o666, 0o777, 0o100666]) { + assert.equal(npmArchiveFileMode(mode, false, 'win32'), 0o644); + assert.equal(npmArchiveFileMode(mode, true, 'win32'), 0o755); + } + assert.equal(npmArchiveFileMode(0o444, false, 'linux'), 0o644); + assert.equal(npmArchiveFileMode(0o666, false, 'darwin'), 0o644); + assert.equal(npmArchiveFileMode(0o755, false, 'linux'), 0o755); + assert.equal(npmArchiveFileMode(0o444, true, 'linux'), 0o755); +}); + +test('real npm carriers encode canonical legal/data and declared executable modes without chmod', (t) => { + const { root, source } = fixture(t); + stageExtensionUpstreamLicenses('pgtap', source); + const license = path.join(source, 'share/licenses/pgtap/README.md'); + const writable = path.join(source, 'writable.txt'); + const readonly = path.join(source, 'readonly.txt'); + const unixExecutable = path.join(source, 'bin/unix-script'); + writeFileSync(writable, 'writable data\n'); + writeFileSync(readonly, 'read-only data\n'); + writeFileSync(unixExecutable, '#!/bin/sh\nexit 0\n'); + chmodSync(writable, 0o666); + for (const file of [license, readonly, path.join(source, 'bin/declared.exe')]) + chmodSync(file, 0o444); + chmodSync(unixExecutable, 0o755); + const inputs = new Map( + listArchiveEntries(source) + .filter((file) => statSync(file).isFile()) + .map((file) => [file, { mode: statSync(file).mode, bytes: readFileSync(file) }]), + ); + const tarball = packGeneratedNpmCarrier(source, path.join(root, 'tarballs')); + const entries = readPortableArchiveEntries(tarball); + for (const [name, entry] of entries) { + const executable = + name === 'package/bin/declared.exe' || + (process.platform !== 'win32' && name === 'package/bin/unix-script'); + assert.equal(entry.mode, entry.isDirectory || executable ? 0o755 : 0o644, name); + } + assert.deepEqual( + assertExtensionUpstreamLicensesInArchive(['pgtap'], tarball, { prefix: 'package' }), + ['package/share/licenses/pgtap/README.md'], + ); + for (const [file, input] of inputs) { + assert.equal(statSync(file).mode, input.mode, file); + assert.deepEqual(readFileSync(file), input.bytes, file); + const member = `package/${path.relative(source, file).split(path.sep).join('/')}`; + assert.deepEqual(entries.get(member).data(), input.bytes, member); + } +}); + +test('npm executable declarations must identify safe regular package files', (t) => { + const { root, source, manifest, writeManifest } = fixture(t); + const pack = () => packGeneratedNpmCarrier(source, path.join(root, 'tarballs')); + for (const member of ['missing', 'bin', '../outside', '/absolute']) { + manifest.publishConfig.executableFiles = [member]; + writeManifest(); + assert.throws(pack, /regular package file|unsafe archive member/u, member); + } + manifest.publishConfig.executableFiles = ['./bin/declared.exe']; + writeManifest(); + const linked = path.join(source, 'linked'); + symlinkSync('bin/declared.exe', linked); + assert.throws(pack, /only regular files and directories/u); + rmSync(linked); +}); diff --git a/tools/packaging/package-archive.mts b/tools/packaging/package-archive.mts new file mode 100644 index 000000000..71006034f --- /dev/null +++ b/tools/packaging/package-archive.mts @@ -0,0 +1,69 @@ +/** Exact deterministic source/package tar framing shared by bounded envelope actions. */ +import { readdirSync, readFileSync, statSync } from 'node:fs'; +import path from 'node:path'; +import { tarHeader } from './archive-directory.mts'; + +function compareText(left, right) { + return left < right ? -1 : left > right ? 1 : 0; +} +function abort(fail, message) { + if (typeof fail === 'function') fail(message); + throw new Error(message); +} + +export function listArchiveEntries(directory) { + const files = []; + const entries = readdirSync(directory, { withFileTypes: true }); + entries.sort((left, right) => compareText(left.name, right.name)); + for (const entry of entries) { + const fullPath = path.join(directory, entry.name); + if (entry.isDirectory()) { + files.push(fullPath, ...listArchiveEntries(fullPath)); + } else if (entry.isFile()) { + files.push(fullPath); + } else { + throw new Error( + `Cargo archive source must contain only regular files and directories: ${fullPath}`, + ); + } + } + return files; +} + +export function createDeterministicTar(stageDir, packageRoot, options) { + const chunks = []; + const fixedFileMode = options.fixedFileMode; + const executableFiles = options.executableFiles ?? new Set(); + if ( + fixedFileMode !== undefined && + (!Number.isInteger(fixedFileMode) || fixedFileMode < 0 || fixedFileMode > 0o777) + ) { + abort( + options.fail, + 'fixed deterministic tar file mode must be an integer between 0000 and 0777', + ); + } + const files = listArchiveEntries(stageDir).filter( + (file) => options.includeDirectories !== false || statSync(file).isFile(), + ); + files.sort((left, right) => + compareText(path.relative(stageDir, left), path.relative(stageDir, right)), + ); + for (const file of files) { + const relative = path.relative(stageDir, file).split(path.sep).join('/'); + const archivePath = `${packageRoot}/${relative}`; + const stats = statSync(file); + const isDirectory = stats.isDirectory(); + const data = isDirectory ? Buffer.alloc(0) : readFileSync(file); + const mode = + isDirectory || executableFiles.has(relative) ? 0o755 : (fixedFileMode ?? stats.mode & 0o777); + chunks.push(tarHeader({ name: archivePath, isDirectory }, data.length, mode)); + chunks.push(data); + const remainder = data.length % 512; + if (remainder !== 0) { + chunks.push(Buffer.alloc(512 - remainder, 0)); + } + } + chunks.push(Buffer.alloc(1024, 0)); + return Buffer.concat(chunks); +} diff --git a/tools/packaging/platform-binary-contract.mts b/tools/packaging/platform-binary-contract.mts index 72f7c45d2..a1af213c8 100644 --- a/tools/packaging/platform-binary-contract.mts +++ b/tools/packaging/platform-binary-contract.mts @@ -1,6 +1,6 @@ #!/usr/bin/env bun -import { lstat, readFile, readdir } from 'node:fs/promises'; +import { lstat, readdir, readFile } from 'node:fs/promises'; import path from 'node:path'; import { @@ -8,8 +8,8 @@ import { platformCompatibilityContract, } from '../release/platform-compatibility-policy.mts'; import { - WINDOWS_VC_RUNTIME_DLLS, inspectPortableExecutable, + WINDOWS_VC_RUNTIME_DLLS, } from './windows-vc-runtime-closure.mts'; const MACHO_LC_BUILD_VERSION = 0x32; @@ -17,6 +17,8 @@ const ELF_TYPE_REL = 1; const ELF_TYPE_EXEC = 2; const ELF_TYPE_DYN = 3; const ELF_SECTION_NOTE = 7; +const ELF_PROGRAM_LOAD = 1; +const ELF_PROGRAM_GNU_RELRO = 0x6474e552; const APPLE_PLATFORM_BY_ID = new Map( Object.values(APPLE_PLATFORM_COMPATIBILITY).map((platform) => [platform.id, platform]), ); @@ -994,6 +996,30 @@ function parseElf(buffer, label, contract) { ); } validateAndroidCppRuntime(buffer, sectionOffset, sectionEntrySize, sectionCount, label); + const minimumAlignment = BigInt(contract.elf.minimumLoadSegmentAlignment); + let loads = 0; + for (let index = 0; index < programCount; index += 1) { + const entry = programOffset + programEntrySize * index; + const type = buffer.readUInt32LE(entry); + const virtualAddress = buffer.readBigUInt64LE(entry + 16); + if (type === ELF_PROGRAM_LOAD) { + loads += 1; + const alignment = buffer.readBigUInt64LE(entry + 48); + if (alignment < minimumAlignment || (alignment & (alignment - 1n)) !== 0n) + fail( + label, + `Android ELF PT_LOAD alignment ${alignment} must be a power of two at least ${minimumAlignment} bytes`, + ); + const fileOffset = buffer.readBigUInt64LE(entry + 8); + if (fileOffset % alignment !== virtualAddress % alignment) + fail(label, 'Android ELF PT_LOAD file and virtual offsets are incongruent'); + } else if (type === ELF_PROGRAM_GNU_RELRO) { + const memorySize = buffer.readBigUInt64LE(entry + 40); + if ((virtualAddress + memorySize) % minimumAlignment !== 0n) + fail(label, `Android ELF GNU_RELRO end must align to ${minimumAlignment} bytes`); + } + } + if (loads === 0) fail(label, 'Android ELF must contain a PT_LOAD segment'); } } else { for (const required of requiredVersions) { @@ -1147,6 +1173,16 @@ function finalizeInspection( const required = requiredApplePlatforms ?? contract.apple.requiredPlatforms.map((key) => contract.apple.platforms[key].id); + if ( + !Array.isArray(required) || + required.length === 0 || + required.some((platform) => !APPLE_PLATFORM_BY_ID.has(platform)) + ) { + fail( + 'platform-binary contract', + 'required Apple platforms must be a nonempty array of Mach-O platform IDs', + ); + } const missing = required.filter((platform) => !platforms.has(platform)); if (missing.length > 0) { fail( @@ -1216,6 +1252,15 @@ function finalizeInspection( }; } +export interface PlatformBinaryInspectionOptions { + target: string; + rootLabel?: string; + /** Numeric Mach-O platform IDs; command-line names are translated by the CLI. */ + requiredApplePlatforms?: readonly number[]; + requireWindowsRuntimeImportLibrary?: boolean; + windowsVcRuntimeProfile?: string; +} + export function inspectPlatformBinaryEntries( entries, { @@ -1224,7 +1269,7 @@ export function inspectPlatformBinaryEntries( requiredApplePlatforms, requireWindowsRuntimeImportLibrary = false, windowsVcRuntimeProfile, - }, + }: PlatformBinaryInspectionOptions, ) { contractFor(target, rootLabel); if (requireWindowsRuntimeImportLibrary && target !== 'windows-x64-msvc') { @@ -1338,7 +1383,7 @@ export async function inspectPlatformBinaryTree( requiredApplePlatforms, requireWindowsRuntimeImportLibrary = false, windowsVcRuntimeProfile, - }, + }: PlatformBinaryInspectionOptions, ) { const absolute = path.resolve(root); const stat = await lstat(absolute).catch(() => null); diff --git a/tools/packaging/platform-binary-contract.test.mts b/tools/packaging/platform-binary-contract.test.mts index 2c65b2ff8..9aff2a3ec 100644 --- a/tools/packaging/platform-binary-contract.test.mts +++ b/tools/packaging/platform-binary-contract.test.mts @@ -1,5 +1,5 @@ import { afterEach, describe, expect, test } from 'bun:test'; -import { mkdtemp, mkdir, rm, symlink, writeFile } from 'node:fs/promises'; +import { mkdir, mkdtemp, rm, symlink, writeFile } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import path from 'node:path'; @@ -10,6 +10,7 @@ import { } from './platform-binary-contract.mts'; import { OLIPHAUNT_WINDOWS_IMPORT_SYMBOLS, + arFixture as ar, windowsImportLibraryFixture, } from './testdata/release-fixture-utils.mts'; @@ -79,20 +80,6 @@ function fatMacho(slices) { return buffer; } -function ar(members) { - const chunks = [Buffer.from('!\n', 'ascii')]; - for (const [name, data] of members) { - const encodedName = `${name}/`.padEnd(16, ' '); - const header = Buffer.from( - `${encodedName}${'0'.padEnd(12, ' ')}${'0'.padEnd(6, ' ')}${'0'.padEnd(6, ' ')}${'100644'.padEnd(8, ' ')}${String(data.length).padEnd(10, ' ')}\`\n`, - 'ascii', - ); - chunks.push(header, data); - if (data.length % 2 !== 0) chunks.push(Buffer.from('\n', 'ascii')); - } - return Buffer.concat(chunks); -} - function elf({ machine = 62, bits = 64, @@ -101,6 +88,9 @@ function elf({ truncateSectionTable = false, androidApi = null, type = 3, + loadAlignment = 16_384, + loadVirtualAddress = 0, + loadSegments = true, } = {}) { const versionBytes = Buffer.from(`\0${versions.join('\0')}\0`, 'ascii'); const note = androidApi === null ? null : Buffer.alloc(24); @@ -111,9 +101,13 @@ function elf({ note.write('Android\0', 12, 'ascii'); note.writeUInt32LE(androidApi, 20); } - const noteOffset = align(64 + versionBytes.length, 4); + const programSize = androidApi !== null && type !== 1 && loadSegments ? 56 : 0; + const dataOffset = 64 + programSize; + const noteOffset = align(dataOffset + versionBytes.length, 4); const sectionOffset = note === null ? 0 : align(noteOffset + note.length, 8); - const buffer = Buffer.alloc(note === null ? 64 + versionBytes.length : sectionOffset + 128); + const buffer = Buffer.alloc( + note === null ? dataOffset + versionBytes.length : sectionOffset + 128, + ); Buffer.from([0x7f, 0x45, 0x4c, 0x46]).copy(buffer, 0); buffer[4] = bits === 64 ? 2 : 1; buffer[5] = littleEndian ? 1 : 2; @@ -127,7 +121,18 @@ function elf({ buffer.writeUInt16LE(64, 58); buffer.writeUInt16LE(2, 60); } - versionBytes.copy(buffer, 64); + versionBytes.copy(buffer, dataOffset); + if (programSize) { + buffer.writeBigUInt64LE(64n, 32); + buffer.writeUInt16LE(56, 54); + buffer.writeUInt16LE(1, 56); + buffer.writeUInt32LE(1, 64); + buffer.writeUInt32LE(5, 68); + buffer.writeBigUInt64LE(BigInt(loadVirtualAddress), 80); + buffer.writeBigUInt64LE(BigInt(buffer.length), 96); + buffer.writeBigUInt64LE(BigInt(buffer.length), 104); + buffer.writeBigUInt64LE(BigInt(loadAlignment), 112); + } if (note !== null) { note.copy(buffer, noteOffset); buffer.writeBigUInt64LE(BigInt(sectionOffset), 40); @@ -344,7 +349,6 @@ describe('Mach-O platform compatibility', () => { expect( inspectPlatformBinaryEntries(entries, { target: 'ios-xcframework', - requiredApplePlatforms: [1, 2, 7], }).slices, ).toBe(3); const malformed = Buffer.from(entries[1].data); @@ -371,10 +375,21 @@ describe('Mach-O platform compatibility', () => { expect(() => inspectPlatformBinaryEntries(entries.slice(1), { target: 'ios-xcframework', - requiredApplePlatforms: [1, 2, 7], }), ).toThrow(/missing macOS/u); }); + + test('rejects invalid programmatic Apple platform overrides with a contract error', () => { + for (const requiredApplePlatforms of [[], [99], ['macos'], 'macos']) { + expect(() => + inspectPlatformBinaryEntries([entry('macos/lib.a', ar([['macos.o', macho()]]))], { + target: 'ios-xcframework', + // @ts-expect-error Exercise malformed callers at the runtime boundary. + requiredApplePlatforms, + }), + ).toThrow(/required Apple platforms must be a nonempty array of Mach-O platform IDs/u); + } + }); }); describe('ELF platform and GNU symbol-version compatibility', () => { @@ -457,6 +472,49 @@ describe('ELF platform and GNU symbol-version compatibility', () => { }), ).toThrow(/API level 26 does not match.*24/u); }); + + test('rejects Android linked images with 4 KiB, invalid or incongruent load alignment', () => { + for (const machine of [62, 183]) { + const target = machine === 62 ? 'android-x86_64' : 'android-arm64-v8a'; + for (const loadAlignment of [4096, 24576]) + expect(() => + inspectPlatformBinaryBuffer(elf({ machine, androidApi: 24, loadAlignment }), { target }), + ).toThrow(/PT_LOAD alignment.*power of two at least 16384/u); + expect(() => + inspectPlatformBinaryBuffer(elf({ machine, androidApi: 24, loadVirtualAddress: 4096 }), { + target, + }), + ).toThrow(/PT_LOAD.*incongruent/u); + expect(() => + inspectPlatformBinaryBuffer(elf({ machine, androidApi: 24, loadSegments: false }), { + target, + }), + ).toThrow(/must contain a PT_LOAD/u); + expect(() => + inspectPlatformBinaryBuffer(elf({ machine, type: 1 }), { target }), + ).not.toThrow(); + } + }); + + test('requires the Android RELRO end to follow the same 16 KiB page contract', () => { + const binary = elf({ androidApi: 24 }); + const originalSize = binary.length; + const withRelro = Buffer.concat([binary, Buffer.alloc(56)]); + binary.copy(withRelro, originalSize, 64, 120); + withRelro.writeBigUInt64LE(BigInt(originalSize), 32); + withRelro.writeUInt16LE(2, 56); + const relro = originalSize + 56; + // Add room for two program headers without altering the valid note/sections. + const image = Buffer.concat([withRelro, Buffer.alloc(56)]); + image.writeUInt32LE(0x6474e552, relro); + image.writeBigUInt64LE(4096n, relro + 16); + image.writeBigUInt64LE(12_288n, relro + 40); + expect(() => inspectPlatformBinaryBuffer(image, { target: 'android-x86_64' })).not.toThrow(); + image.writeBigUInt64LE(4096n, relro + 40); + expect(() => inspectPlatformBinaryBuffer(image, { target: 'android-x86_64' })).toThrow( + /GNU_RELRO end must align to 16384/u, + ); + }); }); describe('PE32+ architecture and self-contained runtime imports', () => { diff --git a/tools/packaging/portable-archive.mts b/tools/packaging/portable-archive.mts index 813c5f9b2..9ce557265 100644 --- a/tools/packaging/portable-archive.mts +++ b/tools/packaging/portable-archive.mts @@ -30,6 +30,7 @@ export const DEFAULT_PORTABLE_ARCHIVE_LIMITS = Object.freeze({ const UTF8 = new TextDecoder('utf-8', { fatal: true }); const ZIP_ALLOWED_FLAGS = 0x080e; const ZIP_ALLOWED_EXTRA_FIELDS = new Set([0x5455, 0x5855, 0x7875]); +const JAVA_ARCHIVE_MAGIC_EXTRA_FIELD_ID = 0xcafe; const ANDROID_ALIGNMENT_EXTRA_FIELD_ID = 0xd935; const APK_SIGNING_BLOCK_MAGIC = Buffer.from('APK Sig Block 42', 'ascii'); const APK_SIGNATURE_SCHEME_BLOCK_IDS = new Set([0x7109871a, 0xf05368c0, 0x1b93ad61]); @@ -322,7 +323,14 @@ function validateZipExtra( extra, file, label, - { source = false, androidApkLocal = false, dataOffset = 0, method = -1, name = '' } = {}, + { + source = false, + javaArchive = false, + androidApkLocal = false, + dataOffset = 0, + method = -1, + name = '', + } = {}, ) { const seen = new Set(); for (let offset = 0; offset < extra.length; ) { @@ -355,6 +363,7 @@ function validateZipExtra( if ( !ZIP_ALLOWED_EXTRA_FIELDS.has(id) && !(source && id === 0x000a) && + !(javaArchive && id === JAVA_ARCHIVE_MAGIC_EXTRA_FIELD_ID) && !(androidApkLocal && id === ANDROID_ALIGNMENT_EXTRA_FIELD_ID) ) { throw archiveError( @@ -363,7 +372,9 @@ function validateZipExtra( ); } const value = extra.subarray(offset, offset + size); - if (id === 0x000a) { + if (id === JAVA_ARCHIVE_MAGIC_EXTRA_FIELD_ID) { + if (size !== 0) throw archiveError(file, 'has non-empty Java archive magic ZIP metadata'); + } else if (id === 0x000a) { if ( size !== 32 || value.readUInt32LE(0) !== 0 || @@ -516,7 +527,7 @@ function validateApkSigningBlock(buffer, recordsEnd, centralOffset, file) { } } -function zipEntryType(versionMadeBy, externalAttributes, rawName, file) { +function zipEntryType(versionMadeBy, externalAttributes, rawName, file, javaArchive = false) { const host = versionMadeBy >>> 8; const unixMode = externalAttributes >>> 16; const unixType = unixMode & 0o170000; @@ -540,7 +551,11 @@ function zipEntryType(versionMadeBy, externalAttributes, rawName, file) { if (unixType !== 0) { throw archiveError(file, `has conflicting FAT/Unix type metadata for ${rawName}`); } - if (pathDirectory !== dosDirectory) { + // Java archive writers leave FAT attributes at zero, including directories. + if ( + pathDirectory !== dosDirectory && + !(javaArchive && pathDirectory && externalAttributes === 0) + ) { throw archiveError(file, `has inconsistent FAT directory metadata for ${rawName}`); } type = pathDirectory ? 'directory' : 'file'; @@ -712,7 +727,11 @@ function inflateZipEntry(buffer, entry, file, maxEntryBytes) { return data; } -function readZipEntries(file, archiveLimits, { source = false, androidApk = false } = {}) { +function readZipEntries( + file, + archiveLimits, + { source = false, javaArchive = false, androidApk = false } = {}, +) { const buffer = readFileSync(file); const eocdOffset = findZipEnd(buffer, file); const eocd = boundedSlice(buffer, eocdOffset, 22, file, 'ZIP end record'); @@ -813,8 +832,15 @@ function readZipEntries(file, archiveLimits, { source = false, androidApk = fals }); validateZipExtra(variable.subarray(nameLength), file, `central ${JSON.stringify(rawName)}`, { source, + javaArchive, }); - const { mode, type } = zipEntryType(versionMadeBy, externalAttributes, rawName, file); + const { mode, type } = zipEntryType( + versionMadeBy, + externalAttributes, + rawName, + file, + javaArchive, + ); const name = portableMemberName(rawName, type, file); if (type === 'directory' && (size !== 0 || expectedCrc !== 0)) { throw archiveError(file, `has a non-empty ZIP directory member ${rawName}`); @@ -853,7 +879,7 @@ function readZipEntries(file, archiveLimits, { source = false, androidApk = fals localVariable.subarray(localNameLength), file, `local ${JSON.stringify(rawName)}`, - { source, androidApkLocal: androidApk, dataOffset, method, name }, + { source, javaArchive, androidApkLocal: androidApk, dataOffset, method, name }, ); const descriptor = (flags & 0x0008) !== 0; const localCrc = local.readUInt32LE(14); @@ -1331,6 +1357,13 @@ export function readPortableArchiveEntries(file, options = {}) { throw archiveError(file, `has an unsupported archive format ${JSON.stringify(format)}`); } +/** Java build inputs additionally permit the empty JarOutputStream magic field. */ +export function readJavaArchiveEntries(file, options = {}) { + const archiveLimits = limits(options); + requireRegularArchive(file, archiveLimits.maxArchiveBytes); + return readZipEntries(file, archiveLimits, { javaArchive: true }); +} + /** Source pins additionally permit V7 tar and links, validated before extraction. */ export function readSourceArchiveEntries(file, options = {}) { const archiveLimits = limits(options); diff --git a/tools/packaging/portable-archive.test.mts b/tools/packaging/portable-archive.test.mts index ca3a661ad..7d1f7de6b 100644 --- a/tools/packaging/portable-archive.test.mts +++ b/tools/packaging/portable-archive.test.mts @@ -24,7 +24,9 @@ import { RELEASE_ZSTD_COMPRESSION_LEVEL, readAndroidApkEntries, readFileOnlyTarGzipEntries, + readJavaArchiveEntries, readPortableArchiveEntries, + readSourceArchiveEntries, readPortableTarStream, readPortableTarZstdBufferEntries, releaseZstdCompressSync, @@ -147,6 +149,152 @@ test('accepts an unambiguous FAT-origin ZIP member', async (t) => { assert.equal(readPortableArchiveEntries(file).get('file.txt').isFile, true); }); +test('accepts the empty JAR magic field only for explicit Java build inputs', (t) => { + const magic = Buffer.from('feca0000', 'hex'); + const { file } = fixtureFile( + t, + 'java-marker.zip', + zipArchive([ + { + name: 'META-INF/', + data: '', + versionMadeBy: 0x0014, + externalAttributes: 0, + localExtra: magic, + centralExtra: magic, + }, + { name: 'META-INF/MANIFEST.MF', data: 'Manifest-Version: 1.0\r\n\r\n' }, + ]), + ); + const entries = readJavaArchiveEntries(file); + assert.equal(entries.get('META-INF').isDirectory, true); + assert.equal( + entries.get('META-INF/MANIFEST.MF').data().toString(), + 'Manifest-Version: 1.0\r\n\r\n', + ); + for (const read of [readPortableArchiveEntries, readSourceArchiveEntries, readAndroidApkEntries]) + assert.throws(() => read(file), /unsupported ZIP central.*0xcafe/u); + assert.throws( + () => readPortableArchiveEntries(file, { javaArchive: true }), + /unsupported ZIP central/u, + ); + const directory = fixtureFile( + t, + 'java-directory.zip', + zipArchive([{ name: 'dev/example/', data: '', versionMadeBy: 0x0014, externalAttributes: 0 }]), + ).file; + assert.equal(readJavaArchiveEntries(directory).get('dev/example').isDirectory, true); + for (const read of [readPortableArchiveEntries, readSourceArchiveEntries, readAndroidApkEntries]) + assert.throws(() => read(directory), /inconsistent FAT directory metadata/u); +}); + +test('rejects malformed or repeated JAR magic fields in either ZIP header', (t) => { + const magic = Buffer.from('feca0000', 'hex'); + for (const location of ['localExtra', 'centralExtra']) + for (const [label, extra, pattern] of [ + ['nonempty', Buffer.from('feca010000', 'hex'), /non-empty Java archive magic/u], + ['duplicate', Buffer.concat([magic, magic]), /repeats ZIP.*extra field 0xcafe/u], + ['truncated', Buffer.from('feca0100', 'hex'), /truncated ZIP.*extra field/u], + ]) { + const { file } = fixtureFile( + t, + `${location}-${label}.jar`, + zipArchive([{ name: 'Example.class', [location]: extra }]), + ); + assert.throws(() => readJavaArchiveEntries(file), pattern); + } +}); + +test('accepts Java-input compressed directories only with verified empty data and descriptors', (t) => { + const directory = { + name: 'res/', + data: '', + method: 8, + flags: 0x0800, + versionMadeBy: 0x0014, + externalAttributes: 0, + }; + for (const descriptor of ['signed', 'unsigned']) { + const { file } = fixtureFile( + t, + `java-directory-${descriptor}.zip`, + zipArchive([{ ...directory, descriptor }]), + ); + const entry = readJavaArchiveEntries(file).get('res'); + assert.equal(entry.isDirectory, true); + assert.equal(entry.size, 0); + assert.deepEqual(entry.data(), Buffer.alloc(0)); + for (const read of [ + readPortableArchiveEntries, + readSourceArchiveEntries, + readAndroidApkEntries, + ]) + assert.throws(() => read(file), /inconsistent FAT directory metadata/u); + } + const badDescriptor = fixtureFile( + t, + 'java-directory-descriptor.jar', + zipArchive([{ ...directory, descriptor: 'signed', descriptorCrc: 1 }]), + ).file; + assert.throws(() => readJavaArchiveEntries(badDescriptor), /descriptor that disagrees/u); + + const nonempty = zipArchive([ + { ...directory, data: 'x', descriptor: 'signed', declaredSize: 0, crc: 0 }, + ]); + nonempty.writeUInt32LE(0, 22); + const central = nonempty.readUInt32LE(nonempty.length - 22 + 16); + nonempty.writeUInt32LE(0, central - 4); + const disguised = fixtureFile(t, 'java-directory-nonempty.jar', nonempty).file; + assert.throws(() => readJavaArchiveEntries(disguised), /expanded ZIP size/u); + + const invalid = zipArchive([{ ...directory, descriptor: 'signed' }]); + invalid.fill(0xff, 30 + directory.name.length, 30 + directory.name.length + 2); + const corrupt = fixtureFile(t, 'java-directory-deflate.jar', invalid).file; + assert.throws(() => readJavaArchiveEntries(corrupt), /invalid or oversized deflate data/u); +}); + +test('retains ZIP safety and limits in the Java input profile', (t) => { + const magic = Buffer.from('feca0000', 'hex'); + for (const [label, row, pattern] of [ + ['path', { name: '../Example.class' }, /unsafe archive member/u], + ['link', { name: 'Example.class', externalAttributes: 0o120777 << 16 }, /link or special/u], + ['flags', { name: 'Example.class', flags: 0x2000 }, /unsupported or encrypted ZIP flags/u], + ['crc', { name: 'Example.class', crc: 0x12345678 }, /CRC-32 mismatch/u], + [ + 'unknown', + { name: 'Example.class', centralExtra: Buffer.from('efbe0000', 'hex') }, + /unsupported ZIP central/u, + ], + [ + 'directory-attributes', + { name: 'dev/', data: '', versionMadeBy: 0x0014, externalAttributes: 0x20 }, + /inconsistent FAT directory metadata/u, + ], + [ + 'directory-payload', + { name: 'dev/', data: 'x', versionMadeBy: 0x0014, externalAttributes: 0 }, + /non-empty ZIP directory/u, + ], + ]) { + const { file } = fixtureFile( + t, + `${label}.jar`, + zipArchive([{ localExtra: magic, centralExtra: magic, ...row }]), + ); + assert.throws(() => readJavaArchiveEntries(file), pattern); + } + const { file } = fixtureFile( + t, + 'bounded.jar', + zipArchive([{ name: 'Example.class', localExtra: magic, centralExtra: magic }]), + ); + assert.throws( + () => readJavaArchiveEntries(file, { maxArchiveBytes: 10 }), + /no larger than 10 bytes/u, + ); + assert.throws(() => readJavaArchiveEntries(file, { maxEntryBytes: 1 }), /entry-size limit/u); +}); + test('accepts Android legacy and 0xd935 alignment only in the APK profile', async (t) => { // This reproduces the exact two zero bytes on the AGP-produced // assets/dexopt/baseline.prof that exposed the release failure. The leading diff --git a/tools/packaging/release-carrier.mts b/tools/packaging/release-carrier.mts index e1dfc9385..b46a557f4 100644 --- a/tools/packaging/release-carrier.mts +++ b/tools/packaging/release-carrier.mts @@ -15,12 +15,15 @@ import { createHash } from 'node:crypto'; import { readPortableArchiveEntries } from './portable-archive.mts'; import { packGeneratedNpmCarrier } from './npm-package.mts'; import { validateNpmTrustedPublishingManifest } from './npm-trusted-publishing.mts'; +import { findSdkRuntimePayloadViolation } from './sdk-runtime-payload.mts'; import { WINDOWS_VC_RUNTIME_RECEIPT, parseWindowsVcRuntimeReceipt, windowsVcRuntimeProfileNames, } from './windows-vc-runtime-closure.mts'; +export { findSdkRuntimePayloadViolation } from './sdk-runtime-payload.mts'; + export const TOOL = 'package-release-carriers.mts'; export function fail(message, exitCode = 1) { @@ -228,9 +231,8 @@ export function stageNpmPackageDescriptor( packageName, sourceDir, version, - { extraDescriptors = [], target = null } = {}, + { extraDescriptors = [], target = null, stageDir = npmPackageSourceStageDir(packageName) } = {}, ) { - const stageDir = npmPackageSourceStageDir(packageName); rmSync(stageDir, { recursive: true, force: true }); mkdirSync(stageDir, { recursive: true }); for (const descriptor of ['package.json', 'README.md', ...extraDescriptors]) { @@ -477,23 +479,6 @@ export function archiveZipNames(file) { const SDK_ROOT = path.join(ROOT, 'target/sdk-artifacts'); -const SDK_RUNTIME_PAYLOAD_PATTERNS = [ - /(^|\/)assets\/oliphaunt\/runtime\//u, - /(^|\/)assets\/oliphaunt\/cluster-seed\//u, - /(^|\/)assets\/oliphaunt\/static-registry\/archives\//u, - /(^|\/)oliphaunt\/runtime\/files\//u, - /(^|\/)runtime\/files\/share\/postgresql\//u, - /(^|\/)share\/postgresql\/extension\/[^/]+\.(control|sql)$/u, - /(^|\/)release-assets\//u, - /(^|\/)extension-artifacts\.json$/u, - /(^|\/)liboliphaunt\.(so|dylib|dll|a|lib)$/u, - /(^|\/)liboliphaunt_extensions\.(so|dylib|dll|a|lib)$/u, - /(^|\/)liboliphaunt_extension_[^/]+\.(so|dylib|dll|a|lib)$/u, - /\.xcframework(\/|$)/u, -]; - -const KOTLIN_ALLOWED_NATIVE_PAYLOADS = new Set(['liboliphaunt_mobile_bindings.so']); - export function tarReadBytes(file, member) { const entry = strictArchiveEntries(file, 'tar.gz').get(member); if (!entry?.isFile) fail(`${rel(file)} is missing regular-file member ${member}`); @@ -592,24 +577,6 @@ function relFrom(root, file) { return path.relative(root, file).split(path.sep).join('/'); } -export function findSdkRuntimePayloadViolation(product, names, allowedNames = new Set()) { - for (const name of names) { - if (allowedNames.has(name)) { - continue; - } - const basename = path.basename(name); - if (product === 'oliphaunt-kotlin' && KOTLIN_ALLOWED_NATIVE_PAYLOADS.has(basename)) { - continue; - } - for (const pattern of SDK_RUNTIME_PAYLOAD_PATTERNS) { - if (pattern.test(name)) { - return name; - } - } - } - return null; -} - export function rejectSdkRuntimePayload(product, artifact, names, allowedNames = new Set()) { const violation = findSdkRuntimePayloadViolation(product, names, allowedNames); if (violation !== null) { diff --git a/tools/packaging/release-directory-safety.mts b/tools/packaging/release-directory-safety.mts index 078ac5e14..5f7d6a7d9 100644 --- a/tools/packaging/release-directory-safety.mts +++ b/tools/packaging/release-directory-safety.mts @@ -1,4 +1,4 @@ -import { lstatSync, mkdirSync, statSync } from 'node:fs'; +import { chmodSync, lstatSync, mkdirSync, readdirSync, rmSync, statSync } from 'node:fs'; import path from 'node:path'; const DARWIN_ROOT_DIRECTORY_ALIASES = Object.freeze( @@ -117,3 +117,28 @@ export function requireSafeDirectoryChain( } return resolved; } + +/** Remove only a caller-owned real directory; captured source modes stay untouched. */ +export function removeOwnedDirectory(directory: string) { + const resolved = canonicalSystemDirectoryPath(directory); + if (resolved === path.parse(resolved).root) + throw new Error('owned directory cleanup must not remove a filesystem root'); + requireSafeDirectoryChain(path.dirname(resolved), { label: 'owned directory cleanup' }); + try { + lstatSync(resolved); + } catch (cause) { + if ((cause as NodeJS.ErrnoException).code === 'ENOENT') return; + throw cause; + } + const makeWritable = (directory: string) => { + const metadata = lstatSync(directory); + if (!metadata.isDirectory() || metadata.isSymbolicLink()) + throw new Error('owned directory cleanup requires a real directory'); + chmodSync(directory, (metadata.mode & 0o777) | 0o700); + for (const entry of readdirSync(directory, { withFileTypes: true })) + if (entry.isDirectory()) makeWritable(path.join(directory, entry.name)); + }; + makeWritable(resolved); + // Recursive removal unlinks nested symlinks; neither traversal nor chmod follows them. + rmSync(resolved, { recursive: true, force: true }); +} diff --git a/tools/packaging/release-directory-safety.test.mts b/tools/packaging/release-directory-safety.test.mts index cbe8ef7bc..3bddcb2ec 100644 --- a/tools/packaging/release-directory-safety.test.mts +++ b/tools/packaging/release-directory-safety.test.mts @@ -1,11 +1,23 @@ import assert from 'node:assert/strict'; -import { lstatSync, mkdtempSync, mkdirSync, realpathSync, rmSync, symlinkSync } from 'node:fs'; +import { + chmodSync, + existsSync, + lstatSync, + mkdirSync, + mkdtempSync, + readFileSync, + realpathSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; import { tmpdir } from 'node:os'; import path from 'node:path'; import test from 'node:test'; import { canonicalSystemDirectoryPath, + removeOwnedDirectory, requireSafeDirectoryChain, } from './release-directory-safety.mts'; @@ -194,3 +206,94 @@ test('accepts the verified Darwin temporary-directory alias', { t.after(() => rmSync(canonical, { recursive: true, force: true })); assert.equal(requireSafeDirectoryChain(raw), canonical); }); + +test('removes owned 0500 and 0555 trees without changing source siblings', { + skip: process.platform === 'win32', +}, (t) => { + const root = realpathSync(mkdtempSync(path.join(tmpdir(), 'owned-directory-modes-'))); + t.after(() => removeOwnedDirectory(root)); + const source = path.join(root, 'source'); + mkdirSync(source); + const original = path.join(source, 'file'); + writeFileSync(original, 'original captured bytes'); + chmodSync(original, 0o444); + chmodSync(source, 0o500); + const owned = path.join(root, 'stage'); + const nested = path.join(owned, 'nested'); + const empty = path.join(nested, 'empty'); + mkdirSync(empty, { recursive: true }); + writeFileSync(path.join(nested, 'file'), 'owned staged bytes'); + chmodSync(path.join(nested, 'file'), 0o444); + chmodSync(empty, 0o555); + chmodSync(nested, 0o555); + chmodSync(owned, 0o500); + + removeOwnedDirectory(owned); + assert.equal(existsSync(owned), false); + assert.equal(readFileSync(original, 'utf8'), 'original captured bytes'); + assert.equal(lstatSync(source).mode & 0o777, 0o500); + assert.equal(lstatSync(original).mode & 0o777, 0o444); +}); + +test('rejects root and ancestor aliases before mutating their target', (t) => { + const root = realpathSync(mkdtempSync(path.join(tmpdir(), 'owned-directory-alias-'))); + t.after(() => removeOwnedDirectory(root)); + const outside = path.join(root, 'outside'); + const directory = path.join(outside, 'retained'); + mkdirSync(directory, { recursive: true }); + writeFileSync(path.join(directory, 'file'), 'target bytes'); + chmodSync(directory, 0o500); + const mode = lstatSync(directory).mode & 0o777; + const alias = path.join(root, 'alias'); + symlinkSync(outside, alias, process.platform === 'win32' ? 'junction' : 'dir'); + + assert.throws(() => removeOwnedDirectory(alias), /requires a real directory/u); + assert.throws( + () => removeOwnedDirectory(path.join(alias, 'retained')), + /symlink or non-directory ancestor/u, + ); + assert.equal(readFileSync(path.join(directory, 'file'), 'utf8'), 'target bytes'); + assert.equal(lstatSync(directory).mode & 0o777, mode); + assert.equal(lstatSync(alias).isSymbolicLink(), true); +}); + +test('unlinks nested aliases while preserving target bytes and permissions', (t) => { + const root = realpathSync(mkdtempSync(path.join(tmpdir(), 'owned-directory-child-alias-'))); + t.after(() => removeOwnedDirectory(root)); + const outside = path.join(root, 'outside'); + mkdirSync(outside); + const original = path.join(outside, 'file'); + writeFileSync(original, 'untouched external target'); + chmodSync(original, 0o444); + chmodSync(outside, 0o500); + const directoryMode = lstatSync(outside).mode & 0o777; + const fileMode = lstatSync(original).mode & 0o777; + const owned = path.join(root, 'owned'); + mkdirSync(owned); + symlinkSync( + outside, + path.join(owned, 'alias'), + process.platform === 'win32' ? 'junction' : 'dir', + ); + + removeOwnedDirectory(owned); + assert.equal(existsSync(owned), false); + assert.equal(readFileSync(original, 'utf8'), 'untouched external target'); + assert.equal(lstatSync(outside).mode & 0o777, directoryMode); + assert.equal(lstatSync(original).mode & 0o777, fileMode); +}); + +test('missing leaves are harmless and filesystem roots and regular files are rejected', (t) => { + const root = realpathSync(mkdtempSync(path.join(tmpdir(), 'owned-directory-boundary-'))); + t.after(() => removeOwnedDirectory(root)); + assert.doesNotThrow(() => removeOwnedDirectory(path.join(root, 'missing'))); + assert.throws(() => removeOwnedDirectory(path.parse(root).root), /filesystem root/u); + const file = path.join(root, 'file'); + writeFileSync(file, 'retained file'); + assert.throws(() => removeOwnedDirectory(file), /requires a real directory/u); + assert.equal(readFileSync(file, 'utf8'), 'retained file'); + assert.throws( + () => removeOwnedDirectory(path.join(root, 'missing', 'child')), + /cannot be inspected/u, + ); +}); diff --git a/tools/packaging/release-notices.mts b/tools/packaging/release-notices.mts index a59a9c33e..405e812fb 100644 --- a/tools/packaging/release-notices.mts +++ b/tools/packaging/release-notices.mts @@ -7,8 +7,8 @@ import { copyFileSync, lstatSync, mkdirSync, - readFileSync, readdirSync, + readFileSync, rmSync, } from 'node:fs'; import path from 'node:path'; @@ -19,6 +19,7 @@ import { requireSafeDirectoryChain as requireReleaseDirectoryChain } from './rel const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); const PREFIX = 'release-notices.mts'; +const OLIPHAUNT_LICENSE_SPDX = 'MIT'; export const RELEASE_NOTICE_PRODUCTS = Object.freeze(['native', 'wasix']); export const RELEASE_LICENSE_COMPONENTS = Object.freeze(['postgresql', 'icu', 'openssl']); @@ -431,13 +432,44 @@ function unexpectedNamespaceEntry(namespaceEntry, expectedMembers) { return true; } +/** Names and license identifiers are delivery declarations, independently of + * the current checkout's notice contents. Historical byte inputs stay intact. */ +export function releaseNoticeDeclaration(profile) { + const selection = releaseCarrierProfile(profile); + return Object.freeze({ + members: Object.freeze( + [ + ...BASE_ROWS.map(({ member }) => member), + ...selection.products.map((product) => PRODUCT_NOTICE_ROWS[product].member), + ...selection.components.map((component) => LICENSE_COMPONENT_ROWS[component].member), + ].sort(compareText), + ), + spdx: [ + OLIPHAUNT_LICENSE_SPDX, + ...selection.components.map((component) => LICENSE_COMPONENT_ROWS[component].spdx), + ].join(' AND '), + }); +} + export function releaseNoticeRows(options = {}) { const selection = checkedSelection(options); + const sourceRoot = options.sourceRoot; + if (sourceRoot !== undefined && (!sourceRoot || !path.isAbsolute(sourceRoot))) + throw new Error('Release notice source root must be an absolute directory'); + const located = (row) => { + if (sourceRoot === undefined) return row; + const source = (file) => path.join(sourceRoot, path.relative(ROOT, file)); + return { + ...row, + source: source(row.source), + ...(row.sourceManifest ? { sourceManifest: source(row.sourceManifest) } : {}), + }; + }; const rows = [ - ...BASE_ROWS, - ...selection.products.map((product) => PRODUCT_NOTICE_ROWS[product]), + ...BASE_ROWS.map(located), + ...selection.products.map((product) => located(PRODUCT_NOTICE_ROWS[product])), ...selection.components.map((component) => - validateRuntimeLicenseSource(LICENSE_COMPONENT_ROWS[component]), + validateRuntimeLicenseSource(located(LICENSE_COMPONENT_ROWS[component])), ), ]; return Object.freeze(rows.map((row) => Object.freeze({ ...row }))); @@ -449,27 +481,35 @@ export function releaseNoticeInputPaths( return Object.freeze(releaseNoticeRows(options).map((row) => row.source)); } -export function releaseLicenseComponents(ids) { +export function releaseLicenseComponents(ids, { sourceRoot } = {}) { + if (sourceRoot !== undefined) + return Object.freeze( + releaseNoticeRows({ components: ids, sourceRoot }).filter((row) => row.id), + ); return Object.freeze( checkedComponents(ids).map((id) => validateRuntimeLicenseSource(LICENSE_COMPONENT_ROWS[id])), ); } -export function releasePackageLicense({ components = [], includeOliphaunt = true } = {}) { +export function releasePackageLicense({ + components = [], + includeOliphaunt = true, + sourceRoot, +} = {}) { const entries = []; if (includeOliphaunt) { entries.push( Object.freeze({ id: 'oliphaunt', - spdx: 'MIT', + spdx: OLIPHAUNT_LICENSE_SPDX, name: 'MIT License (Oliphaunt)', member: 'LICENSE', - source: path.join(ROOT, 'LICENSE'), + source: path.join(sourceRoot ?? ROOT, 'LICENSE'), licenseUrl: 'https://github.com/f0rr0/oliphaunt/blob/main/LICENSE', }), ); } - entries.push(...releaseLicenseComponents(components)); + entries.push(...releaseLicenseComponents(components, { sourceRoot })); return Object.freeze({ spdx: entries.map((entry) => entry.spdx).join(' AND '), entries: Object.freeze(entries), @@ -481,6 +521,7 @@ export function releaseProfilePackageLicense(profile, options = {}) { return releasePackageLicense({ components: selection.components, includeOliphaunt: options.includeOliphaunt ?? true, + sourceRoot: options.sourceRoot, }); } @@ -489,6 +530,7 @@ export function releaseMavenLicenses({ version, components = [], includeOliphaunt = true, + sourceRoot, } = {}) { if (typeof product !== 'string' || !/^[a-z0-9][a-z0-9-]*$/u.test(product)) { throw new Error('release Maven licenses require a canonical product id'); @@ -497,7 +539,7 @@ export function releaseMavenLicenses({ throw new Error('release Maven licenses require a portable package version'); } return Object.freeze( - releasePackageLicense({ components, includeOliphaunt }).entries.map((entry) => + releasePackageLicense({ components, includeOliphaunt, sourceRoot }).entries.map((entry) => Object.freeze({ name: entry.name, url: @@ -512,7 +554,7 @@ export function releaseMavenLicenses({ export function releaseProfileMavenLicenses( profile, - { product, version, includeOliphaunt = true } = {}, + { product, version, includeOliphaunt = true, sourceRoot } = {}, ) { const selection = releaseCarrierProfile(profile); return releaseMavenLicenses({ @@ -520,6 +562,7 @@ export function releaseProfileMavenLicenses( version, components: selection.components, includeOliphaunt, + sourceRoot, }); } diff --git a/tools/packaging/release-notices.test.mts b/tools/packaging/release-notices.test.mts index 676994557..697bad2eb 100644 --- a/tools/packaging/release-notices.test.mts +++ b/tools/packaging/release-notices.test.mts @@ -1,9 +1,8 @@ -import { archiveDirectory } from './archive-directory.mts'; import assert from 'node:assert/strict'; import { chmodSync, - mkdtempSync, mkdirSync, + mkdtempSync, readFileSync, realpathSync, rmSync, @@ -14,6 +13,7 @@ import { tmpdir } from 'node:os'; import path from 'node:path'; import test from 'node:test'; import { zstdCompressSync } from 'node:zlib'; +import { archiveDirectory } from './archive-directory.mts'; import { createDeterministicTar } from './cargo-source-package.mts'; import { @@ -21,8 +21,8 @@ import { assertReleaseNoticesInDirectory, assertReleaseNoticesInEntries, hasCanonicalReleaseStagingMode, - releasePackageLicense, releaseNoticeRows, + releasePackageLicense, stageReleaseNotices, } from './release-notices.mts'; @@ -82,6 +82,24 @@ test('defines stable canonical member names in deterministic order', () => { ); }); +test('declared source roots preserve strict notice staging and reject linked inputs', (t) => { + const { root, stage } = fixture(t); + const sources = path.join(root, 'sources'); + mkdirSync(sources); + for (const row of releaseNoticeRows({ profile: 'source-sdk' })) { + const file = path.join(sources, row.member); + writeFileSync(file, readFileSync(row.source), { mode: 0o644 }); + } + const options = { profile: 'source-sdk', sourceRoot: sources }; + stageReleaseNotices(stage, options); + assertReleaseNoticesInDirectory(stage, options); + assert.throws(() => releaseNoticeRows({ sourceRoot: 'relative' }), /absolute directory/u); + const license = path.join(sources, 'LICENSE'); + rmSync(license); + symlinkSync(path.join(ROOT, 'LICENSE'), license); + assert.throws(() => stageReleaseNotices(stage, options), /regular non-symlink/u); +}); + test('stages exact bytes and removes stale product notices', async (t) => { const { stage } = fixture(t); stageReleaseNotices(stage, { products: ['native', 'wasix'] }); diff --git a/tools/packaging/rust-dependency-license-contract.mts b/tools/packaging/rust-dependency-license-contract.mts index 6e132008e..f0ecfd449 100644 --- a/tools/packaging/rust-dependency-license-contract.mts +++ b/tools/packaging/rust-dependency-license-contract.mts @@ -20,8 +20,11 @@ export function createRustDependencyLicenseContract({ payloadLicense, noticeProfile = 'source-sdk', targets, + sourceRoot = undefined as string | undefined, }) { - const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); + if (sourceRoot !== undefined && (!sourceRoot || !path.isAbsolute(sourceRoot))) + throw new Error('Rust dependency license source root must be an absolute directory'); + const ROOT = sourceRoot ?? path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); const TOOL = `${product} dependency licenses`; const CONTRACT_PATH = path.join(ROOT, owner, 'dependency-licenses.json'); const BLOB_ROOT = path.join(ROOT, owner, 'dependency-license-blobs'); @@ -282,6 +285,17 @@ export function createRustDependencyLicenseContract({ if (candidates.length === 0) { fail(`cargo tree package ${key} is absent from cargo metadata`); } + const localSource = line.match(/^[^\s]+ v[^\s]+ \((.+)\)$/u)?.[1]; + if (localSource !== undefined && path.isAbsolute(localSource)) { + const local = candidates.filter( + (row) => + isAllowedRustPathPackageMetadataRow(row, workspaceMembers) && + path.resolve(path.dirname(row.manifest_path)) === path.resolve(localSource), + ); + if (local.length !== 1) + fail(`Rust graph contains unsupported local dependency ${key}: ${localSource}`); + continue; + } const registry = candidates.filter((row) => row.source === CARGO_SOURCE); if (registry.length === 1) { keys.add(key); @@ -890,6 +904,7 @@ export function createRustDependencyLicenseContract({ } assertReleaseNoticesInEntries(entries, { profile: noticeProfile, + ...(sourceRoot === undefined ? {} : { sourceRoot }), prefix: archivePrefix, exact: false, label, diff --git a/tools/packaging/rust-native-targets.mts b/tools/packaging/rust-native-targets.mts index fb4b852f6..4ee765b8a 100644 --- a/tools/packaging/rust-native-targets.mts +++ b/tools/packaging/rust-native-targets.mts @@ -34,6 +34,35 @@ export function rustNativeTargetCfg(target) { return NATIVE_TARGET_CFG[targetId]; } +export function nativeCargoPackageName(product, target) { + if (typeof product !== 'string' || !product) + fail('Cargo artifact source product must be nonempty'); + rustNativeTargetCfg(target); + const targetId = typeof target === 'string' ? target : target.target; + return `${product}-${targetId}`; +} + +// The Rust surface is the existing native cfg map; registry declarations decide +// the actual package identity. Mobile carriers use other publication surfaces. +export function nativeCargoArtifactRows(product, targets, registryPackages) { + const declared = new Set(nonEmptyUniqueStrings(registryPackages, `${product} registry packages`)); + const rows = []; + for (const target of nonEmptyUniqueStrings(targets, `${product} artifact targets`)) { + if (!(target in NATIVE_TARGET_CFG)) { + if (declared.has(`crates:${product}-${target}`)) rustNativeTargetCfg(target); + continue; + } + const packageName = nativeCargoPackageName(product, target); + if (!declared.has(`crates:${packageName}`)) + fail(`${product} is missing declared Cargo artifact ${packageName}`); + rows.push({ sourceProduct: product, target, packageKind: 'crates', packageName }); + } + if (!rows.length) fail(`${product} has no declared native Cargo artifacts`); + return rows.sort((left, right) => + left.target < right.target ? -1 : left.target > right.target ? 1 : 0, + ); +} + export function assertSameNativeTargetSet(label, expected, actual) { const expectedTargets = [...nonEmptyUniqueStrings(expected, `${label} expected targets`)].sort(); const actualTargets = [...nonEmptyUniqueStrings(actual, `${label} actual targets`)].sort(); diff --git a/tools/packaging/sdk-runtime-payload.mts b/tools/packaging/sdk-runtime-payload.mts new file mode 100644 index 000000000..8bc80885c --- /dev/null +++ b/tools/packaging/sdk-runtime-payload.mts @@ -0,0 +1,34 @@ +import path from 'node:path'; + +const SDK_RUNTIME_PAYLOAD_PATTERNS = [ + /(^|\/)assets\/oliphaunt\/runtime\//u, + /(^|\/)assets\/oliphaunt\/cluster-seed\//u, + /(^|\/)assets\/oliphaunt\/static-registry\/archives\//u, + /(^|\/)oliphaunt\/runtime\/files\//u, + /(^|\/)runtime\/files\/share\/postgresql\//u, + /(^|\/)share\/postgresql\/extension\/[^/]+\.(control|sql)$/u, + /(^|\/)release-assets\//u, + /(^|\/)extension-artifacts\.json$/u, + /(^|\/)liboliphaunt\.(so|dylib|dll|a|lib)$/u, + /(^|\/)liboliphaunt_extensions\.(so|dylib|dll|a|lib)$/u, + /(^|\/)liboliphaunt_extension_[^/]+\.(so|dylib|dll|a|lib)$/u, + /\.xcframework(\/|$)/u, +]; + +const KOTLIN_ALLOWED_NATIVE_PAYLOADS = new Set(['liboliphaunt_mobile_bindings.so']); + +export function findSdkRuntimePayloadViolation( + product: string, + names: Iterable, + allowedNames = new Set(), +) { + for (const name of names) { + if (allowedNames.has(name)) continue; + if (product === 'oliphaunt-kotlin' && KOTLIN_ALLOWED_NATIVE_PAYLOADS.has(path.basename(name))) + continue; + for (const pattern of SDK_RUNTIME_PAYLOAD_PATTERNS) { + if (pattern.test(name)) return name; + } + } + return null; +} diff --git a/tools/packaging/source-only-sdk-package.test.mts b/tools/packaging/source-only-sdk-package.test.mts index 61d5fbd98..0665a92f7 100644 --- a/tools/packaging/source-only-sdk-package.test.mts +++ b/tools/packaging/source-only-sdk-package.test.mts @@ -10,6 +10,7 @@ import { symlinkSync, writeFileSync, } from 'node:fs'; +import { tmpdir } from 'node:os'; import path from 'node:path'; import test from 'node:test'; @@ -28,8 +29,6 @@ const COMPATIBILITY_VERSIONS = { import { assertReleaseNoticesInDirectory } from './release-notices.mts'; -const ROOT = path.resolve(import.meta.dir, '../..'); - function writeJson(file, value) { writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`, 'utf8'); } @@ -112,8 +111,9 @@ if (['prepare', 'verify'].includes(process.argv[2])) { test('rejects a symlinked package directory before rewriting its manifest', { skip: process.platform === 'win32', }, () => { - mkdirSync(path.join(ROOT, 'target'), { recursive: true }); - const scratch = mkdtempSync(path.join(ROOT, 'target', 'source-only-symlink-')); + const scratch = mkdtempSync( + path.join(process.env.TEST_TMPDIR ?? tmpdir(), 'source-only-symlink-'), + ); try { const packageDir = path.join(scratch, 'real-package'); const alias = path.join(scratch, 'package-alias'); diff --git a/tools/packaging/testdata/release-fixture-utils.mts b/tools/packaging/testdata/release-fixture-utils.mts index 00b7fcc60..57a51345c 100644 --- a/tools/packaging/testdata/release-fixture-utils.mts +++ b/tools/packaging/testdata/release-fixture-utils.mts @@ -4,6 +4,7 @@ import os from 'node:os'; import path from 'node:path'; import { archiveDirectory } from '../archive-directory.mts'; + export { archiveDirectory }; export function fail(message) { @@ -68,6 +69,20 @@ export async function writeChecksumManifest(assetDir, name) { await fs.writeFile(checksumAsset, `${lines.join('\n')}\n`, 'utf8'); } +export function arFixture(members: Iterable): Buffer { + const chunks = [Buffer.from('!\n', 'ascii')]; + for (const [name, data] of members) { + const encodedName = `${name}/`.padEnd(16, ' '); + const header = Buffer.from( + `${encodedName}${'0'.padEnd(12, ' ')}${'0'.padEnd(6, ' ')}${'0'.padEnd(6, ' ')}${'100644'.padEnd(8, ' ')}${String(data.length).padEnd(10, ' ')}\`\n`, + 'ascii', + ); + chunks.push(header, data); + if (data.length % 2 !== 0) chunks.push(Buffer.from('\n', 'ascii')); + } + return Buffer.concat(chunks); +} + function packedAppleVersion(major, minor = 0, patch = 0) { return (major << 16) | (minor << 8) | patch; } @@ -116,9 +131,13 @@ export function elfFixture({ note.write('Android\0', 12, 'ascii'); note.writeUInt32LE(androidApi, 20); } - const noteOffset = align(64 + versionBytes.length, 4); + const programSize = androidApi !== null && type !== 1 ? 56 : 0; + const dataOffset = 64 + programSize; + const noteOffset = align(dataOffset + versionBytes.length, 4); const sectionOffset = note === null ? 0 : align(noteOffset + note.length, 8); - const buffer = Buffer.alloc(note === null ? 64 + versionBytes.length : sectionOffset + 128); + const buffer = Buffer.alloc( + note === null ? dataOffset + versionBytes.length : sectionOffset + 128, + ); Buffer.from([0x7f, 0x45, 0x4c, 0x46]).copy(buffer, 0); buffer[4] = 2; buffer[5] = 1; @@ -127,7 +146,17 @@ export function elfFixture({ buffer.writeUInt16LE(machine, 18); buffer.writeUInt32LE(1, 20); buffer.writeUInt16LE(64, 52); - versionBytes.copy(buffer, 64); + versionBytes.copy(buffer, dataOffset); + if (programSize) { + buffer.writeBigUInt64LE(64n, 32); + buffer.writeUInt16LE(56, 54); + buffer.writeUInt16LE(1, 56); + buffer.writeUInt32LE(1, 64); + buffer.writeUInt32LE(5, 68); + buffer.writeBigUInt64LE(BigInt(buffer.length), 96); + buffer.writeBigUInt64LE(BigInt(buffer.length), 104); + buffer.writeBigUInt64LE(16_384n, 112); + } if (note !== null) { note.copy(buffer, noteOffset); buffer.writeBigUInt64LE(BigInt(sectionOffset), 40); diff --git a/tools/packaging/wasix-cargo-payload.mts b/tools/packaging/wasix-cargo-payload.mts index ebe760ff1..18f31fc88 100644 --- a/tools/packaging/wasix-cargo-payload.mts +++ b/tools/packaging/wasix-cargo-payload.mts @@ -30,8 +30,8 @@ function noticeProfileForSpec(spec) { fail(`WASIX Cargo package ${spec.name} has no release notice profile for kind ${spec.kind}`); } -function injectCargoNoticeIncludes(text, profile) { - const members = releaseNoticeRows({ profile }).map((row) => row.member); +function injectCargoNoticeIncludes(text, profile, sourceRoot) { + const members = releaseNoticeRows({ profile, sourceRoot }).map((row) => row.member); const match = text.match(/^include = \[(?[\s\S]*?)^\]$/mu) ?? text.match(/^include = \[(?[^\n]*?)\]$/mu); @@ -44,7 +44,7 @@ function injectCargoNoticeIncludes(text, profile) { function rewriteCargoManifest( manifest, - { packageName, version, transformManifest, noticeProfile }, + { packageName, version, transformManifest, noticeProfile, noticeSourceRoot }, ) { let text = readFileSync(manifest, 'utf8'); text = text.replace(/^name = "[^"]+"$/mu, `name = "${packageName}"`); @@ -52,9 +52,9 @@ function rewriteCargoManifest( text = text.replace(/^publish = false\n?/gmu, ''); text = text.replace( /^license = "[^"]+"$/mu, - `license = ${JSON.stringify(releaseProfilePackageLicense(noticeProfile).spdx)}`, + `license = ${JSON.stringify(releaseProfilePackageLicense(noticeProfile, { sourceRoot: noticeSourceRoot }).spdx)}`, ); - text = injectCargoNoticeIncludes(text, noticeProfile); + text = injectCargoNoticeIncludes(text, noticeProfile, noticeSourceRoot); if (transformManifest) text = transformManifest(text); if (!text.includes('\n[workspace]')) { text = `${text.trimEnd()}\n\n[workspace]\n`; @@ -68,7 +68,7 @@ function rewriteCargoManifest( } } -function copyPackageSource(spec, sourceRoot, version, transformManifest) { +function copyPackageSource(spec, sourceRoot, version, transformManifest, noticeSourceRoot) { const crateDir = path.join(sourceRoot, spec.name); if (existsSync(crateDir)) { fail(`duplicate generated WASIX Cargo package source: ${rel(crateDir)}`); @@ -85,14 +85,18 @@ function copyPackageSource(spec, sourceRoot, version, transformManifest) { ); } const noticeProfile = noticeProfileForSpec(spec); - stageReleaseNotices(crateDir, { profile: noticeProfile }); + stageReleaseNotices(crateDir, { profile: noticeProfile, sourceRoot: noticeSourceRoot }); rewriteCargoManifest(path.join(crateDir, 'Cargo.toml'), { packageName: spec.name, version, transformManifest, noticeProfile, + noticeSourceRoot, + }); + assertReleaseNoticesInDirectory(crateDir, { + profile: noticeProfile, + sourceRoot: noticeSourceRoot, }); - assertReleaseNoticesInDirectory(crateDir, { profile: noticeProfile }); return crateDir; } @@ -103,6 +107,7 @@ export function cargoPackage(crateDir, targetDir) { root: ROOT, fail, rel, + fixedFileMode: 0o644, }); } @@ -117,9 +122,15 @@ export function validateCrateSize(cratePath) { export function packageSpec( spec, - { version, sourceRoot, outputDir, cargoTargetDir, transformManifest }, + { version, sourceRoot, outputDir, cargoTargetDir, transformManifest, noticeSourceRoot }, ) { - const crateDir = copyPackageSource(spec, sourceRoot, version, transformManifest); + const crateDir = copyPackageSource( + spec, + sourceRoot, + version, + transformManifest, + noticeSourceRoot, + ); const cratePath = cargoPackage(crateDir, cargoTargetDir); validateCrateSize(cratePath); const output = path.join(outputDir, path.basename(cratePath)); @@ -128,6 +139,7 @@ export function packageSpec( assertReleaseNoticesInArchive(output, { prefix: `${spec.name}-${version}`, profile: noticeProfile, + sourceRoot: noticeSourceRoot, }); return { name: spec.name, diff --git a/tools/packaging/windows-vc-runtime-closure.mts b/tools/packaging/windows-vc-runtime-closure.mts index f97e7dfa6..684382a25 100644 --- a/tools/packaging/windows-vc-runtime-closure.mts +++ b/tools/packaging/windows-vc-runtime-closure.mts @@ -451,6 +451,13 @@ function receiptText(required) { .join(''); } +/** Seed a private declared SDK projection for the retained import-derived stager. */ +export function renderWindowsVcRuntimeSourceReceipt({ sourceDirectory, profile }) { + const names = windowsVcRuntimeProfileNames(profile); + if (names.length === 0) throw failure('declared VC runtime source requires a nonempty profile'); + return receiptText(closureFromSource(new Set(names), path.resolve(sourceDirectory))); +} + export function parseWindowsVcRuntimeReceipt(input, label = WINDOWS_VC_RUNTIME_RECEIPT) { const text = Buffer.isBuffer(input) ? input.toString('utf8') : String(input); const values = new Map(); diff --git a/tools/packaging/windows-vc-runtime-closure.test.mts b/tools/packaging/windows-vc-runtime-closure.test.mts index f17a56979..70aa86bdc 100644 --- a/tools/packaging/windows-vc-runtime-closure.test.mts +++ b/tools/packaging/windows-vc-runtime-closure.test.mts @@ -16,6 +16,7 @@ import { stageWindowsVcRuntimeMembers } from './release-carrier.mts'; import { inspectPortableExecutable, + renderWindowsVcRuntimeSourceReceipt, resolveInitializedVcRuntimeDirectory, stageWindowsVcRuntime, verifyWindowsVcRuntimeClosure, @@ -115,6 +116,41 @@ if (['prepare', 'verify'].includes(process.argv[2])) { } describe('Windows VC runtime dependency closure', () => { + test('declared SDK files seed the existing receipt and import-derived carrier staging', () => { + const { root, source } = fixture(); + try { + writeFileSync( + path.join(source, WINDOWS_VC_RUNTIME_RECEIPT), + renderWindowsVcRuntimeSourceReceipt({ sourceDirectory: source, profile: 'provider' }), + ); + const carrier = path.join(root, 'carrier'); + const bin = path.join(carrier, 'bin'); + mkdirSync(bin, { recursive: true }); + writeFileSync(path.join(bin, 'app.exe'), pe({ imports: ['VCRUNTIME140.dll'] })); + const result = stageWindowsVcRuntime({ + root: carrier, + sourceDirectory: source, + destinations: [bin], + }); + assert.deepEqual(result.required, ['vcruntime140.dll']); + assert.match( + readFileSync(path.join(bin, WINDOWS_VC_RUNTIME_RECEIPT), 'utf8'), + /^[0-9a-f]{64} {2}vcruntime140\.dll\n$/u, + ); + writeFileSync(path.join(source, 'vcruntime140.dll'), pe({ machine: 0x14c })); + assert.throws( + () => renderWindowsVcRuntimeSourceReceipt({ sourceDirectory: source, profile: 'provider' }), + /not an x64 PE32\+ image/u, + ); + assert.throws( + () => renderWindowsVcRuntimeSourceReceipt({ sourceDirectory: source }), + /nonempty profile/u, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }); + test('parses normal and delay-load imports without an external Windows tool', () => { const parsed = inspectPortableExecutable( pe({ diff --git a/tools/release/BUILD.bazel b/tools/release/BUILD.bazel new file mode 100644 index 000000000..6406c823e --- /dev/null +++ b/tools/release/BUILD.bazel @@ -0,0 +1,154 @@ +load("//build_defs/quality:sources.bzl", "source_quality_files") +load("//build_defs/foundation:bun.bzl", "bun_test") +load("@bazel_lib//lib:copy_file.bzl", "copy_file") +load("@bazel_lib//lib:directory_path.bzl", "directory_path") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["bazel-release-metadata.mts", "bazel-shipping-inputs.mts", "extension-release-metadata.mts", "compatibility-version-parser.mts", "compatibility-version-policy.mts", "product-version.mts", "platform-compatibility-policy.mts", "frozen-extension-consumer.mts", "release-artifact-targets.mts", "release-graph.mts", "release-history.mts"]) +exports_files(["native-file-identity.mts", "with-source.sh", "with-source.mts", "qualified-release-replay.sh", "native-configured-inputs.mts"]) +exports_files(["checksum-manifest.mts"]) +exports_files(["native-extension-final-inputs.mts", "qualified-native-extension-final-inputs.mts"]) +exports_files(["native-extension-release-files.mts"]) +exports_files(["native-supplier-artifacts.mts"]) +exports_files(["cargo-payload-part-contract.mts"]) + +bun_test( + name = "native_extension_final_inputs_test", + entry_point = "native-extension-final-inputs.test.mts", + data = ["native-extension-final-inputs.mts", "native-file-identity.mts", "//:tools/packaging/release-directory-safety.mts"], + size = "small", +) +exports_files(["github-read.mts", "github-core-request-journal.mts", "github-release-lineage.mts"]) + +bun_test( + name = "native_file_identity_test", + entry_point = "native-file-identity.test.mts", + data = ["native-file-identity.mts", "//:tools/packaging/release-directory-safety.mts"], + size = "small", +) + +bun_test( + name = "bazel_metadata_test", + size = "small", + entry_point = "bazel-release-metadata.test.mts", + data = [ + "//:src/extensions/generated/wasix/extensions.json", + "bazel-release-metadata.mts", + "bazel-shipping-inputs.mts", + "compatibility-version-parser.mts", + "extension-release-metadata.mts", + "native-extension-final-inputs.mts", + "native-file-identity.mts", + "native-seed-inputs.mts", + "native-supplier-artifacts.mts", + "platform-compatibility-policy.mts", + "publication-catalog.mts", + "release-artifact-targets.mts", + "release-graph.mts", + "release-history.mts", + "//:src/extensions/artifacts/packages/tools/contrib-carriers.mts", + "//:src/extensions/artifacts/native/tools/ios-extension-registration.mts", + "//:src/extensions/artifacts/packages/tools/extension-registry-packages.mts", + "//:tools/packaging/portable-archive.mts", + "//:tools/packaging/release-directory-safety.mts", + "//:tools/packaging/release-notices.mts", + "//:tools/packaging/rust-dependency-license-contract.mts", + "//:tools/packaging/rust-native-targets.mts", + "//src/database-resources:seeds/carrier-identities.mts", + "//src/database-resources/seeds/wasix:consumer-contract.mts", + "//src/extensions/contracts:extension-target-profiles.mts", + "//src/extensions/catalog:native-components.toml", + "//src/extensions/contracts:extension-target-profiles.toml", + "//src/extensions/tools:native-component-contract.mts", + "//:src/extensions/generated/extensions.catalog.json", + "//src/native/mobile-bindings:tools/dependency-license-contract.mts", + "//src/wasix/runtime:tools/wasix-cargo-artifact-contract.mts", + "//src/wasix/runtime:tools/wasix-runtime-npm-contract.mts", + ], +) + +bun_test( + name = "bazel_shipping_inputs_test", + size = "small", + entry_point = "bazel-shipping-inputs.test.mts", + data = ["bazel-shipping-inputs.mts"], +) + +bun_test( + name = "compatibility_version_parser_test", + size = "small", + entry_point = "compatibility-version-parser.test.mts", + data = ["compatibility-version-parser.mts"], +) + +source_quality_files() + +# Source-only inputs for the existing SDK package policy tests. +exports_files([ + "authenticate-native-build-evidence.mts", + "check_registry_publication.mts", + "completed-contrib-carrier-context.mts", + "completed-release-publication.mts", + "completed-swift-source-delivery.mts", + "consumer-compatibility.mts", + "example-cargo-versions.mts", + "frozen-consumer.mts", + "frozen-npm-publish.mts", + "github-content-write-pacer.mts", + "github-release-mutations.mts", + "native-build-files.mts", + "native-build-qualification.mts", + "native-build-source-tag.mts", + "native-completed-delivery.mts", + "native-freeze-publication-candidate.mts", + "native-publication-artifacts.mts", + "native-publication-candidate.mts", + "native-publication-delivery.mts", + "native-publication-metadata-contract.mts", + "native-publication-metadata.mts", + "native-publication-observation.mts", + "native-publication-payloads.mts", + "native-publication-staging.mts", + "native-release-inputs.mts", + "native-release-preparation.mts", + "qualified-native-current-exact-inputs.mts", + "native-seed-baseline.mts", + "native-seed-inputs.mts", + "native-shipping-suppliers.mts", + "native-source-carrier-changes.mts", + "native-version-source.mts", + "public-consumer-smoke.mts", + "publication-catalog.mts", + "publication-consumer-proof.mts", + "publication-controller.mts", + "publication-lock.mts", + "registry-http-retry.mts", + "registry-integrity.mts", + "registry-publication-deferral.mts", + "release-dependency-plan.mts", + "release-please-bootstrap.mts", + "release-please-pr-lifecycle.mts", + "release-please-transition.mts", + "retained-download.mts", + "sync-release-pr.mts", + "verify-release-commit.mts", + "verify_github_release_attestations.mts", +], visibility = ["//visibility:public"]) + +# Copy the publisher's regular standalone module and original CommonJS manifest. +directory_path( + name = "protobufjs_bundle_module_source", + directory = "//build_defs/languages/ts:protobufjs_native_aquery_package/dir", + path = "dist/protobuf.js", +) +directory_path( + name = "protobufjs_bundle_manifest_source", + directory = "//build_defs/languages/ts:protobufjs_native_aquery_package/dir", + path = "package.json", +) +copy_file(name = "protobufjs_bundle_module", src = ":protobufjs_bundle_module_source", out = "node_modules/protobufjs/dist/protobuf.js") +copy_file(name = "protobufjs_bundle_manifest", src = ":protobufjs_bundle_manifest_source", out = "node_modules/protobufjs/package.json") +exports_files(["package.json", "native-aquery.mts"] + glob(["bazel-8.8.1/*"])) +filegroup(name = "native_aquery_sources", srcs = ["native-aquery.mts", ":protobufjs_bundle_module", ":protobufjs_bundle_manifest"] + glob(["bazel-8.8.1/*"])) +bun_test(name = "native_aquery_test", entry_point = "native-aquery.test.mts", data = [":native_aquery_sources", "bazel-shipping-inputs.mts"] + glob(["fixtures/aquery-bazel-8.8.1/*"]), size = "small") diff --git a/tools/release/audit-native-construction.mts b/tools/release/audit-native-construction.mts new file mode 100644 index 000000000..a540678b5 --- /dev/null +++ b/tools/release/audit-native-construction.mts @@ -0,0 +1,260 @@ +/** Check the complete shipping construction after its source jobs succeed. + * This diagnostic never selects products or admits a publication candidate. */ +import assert from 'node:assert/strict'; +import { execFileSync } from 'node:child_process'; +import { existsSync, mkdirSync, mkdtempSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { parseArgs } from 'node:util'; +import { + removeOwnedDirectory, + requireSafeDirectoryChain, +} from '../packaging/release-directory-safety.mts'; +import { assertAuthenticatedNativeBuildOrigin } from './authenticate-native-build-evidence.mts'; +import type { NativeBuildSource } from './native-build-qualification.mts'; +import { acquireObservedCompletedSuppliers } from './native-freeze-publication-candidate.mts'; +import { observeNativePublicationConstruction } from './native-publication-observation.mts'; +import { + acquireNativePublicationBuilds, + stageNativePublicationConstruction, +} from './native-release-preparation.mts'; +import { projectNativeBuildBoundSuppliers } from './native-shipping-suppliers.mts'; +import { loadPublicationCatalog } from './publication-catalog.mts'; +import { consumerDigest } from './publication-consumer-proof.mts'; +import { lockedPublicationFiles, sourceIdentity } from './publication-lock.mts'; +import { ROOT } from './release-graph.mts'; + +const equal = (actual: unknown, expected: unknown, message: string) => + assert.equal(consumerDigest(actual), consumerDigest(expected), message); + +/** Structural audit assertions return facts only; the caller authenticates every origin. */ +export function assertNativeConstructionAudit({ + source, + candidate, + observation, + suppliers, + expectedProducts, +}: { + source: NativeBuildSource; + candidate: ReturnType['candidate']; + observation: Awaited>; + suppliers: Awaited>; + expectedProducts: ReturnType['products']; +}) { + assert.equal(candidate.scope, 'construction', 'native audit requires construction scope'); + equal(candidate.source, source, 'native audit candidate source differs'); + assert.equal( + candidate.artifactPhase, + 'pre-version', + 'native audit requires preparation inventory', + ); + equal(candidate.products, expectedProducts, 'native audit requires every canonical product'); + assert.deepEqual(candidate.missing, [], 'native audit has missing physical carriers'); + equal( + observation.products.map(({ product }) => product), + expectedProducts, + 'native audit observed products differ', + ); + assert.equal( + observation.coverage.completeProductInventory, + true, + 'native audit has incomplete configured inventory', + ); + assert.equal( + observation.coverage.releaseInputsRequired, + true, + 'native audit requires preparation inputs', + ); + assert.ok(observation.authenticated.length, 'native audit requires original producing builds'); + const versions = new Map(expectedProducts.map(({ id, version }) => [id, version])); + const covered = new Set(); + let configuredRoots = 0; + for (const build of observation.authenticated) { + equal(build.evidence.source, source, 'native audit producer source differs'); + equal(build.qualification.source, source, 'native audit qualified source differs'); + for (const cohort of build.qualification.cohorts) { + for (const root of cohort.roots) { + assert.ok( + versions.has(root.package.product), + 'native audit has an unknown configured owner', + ); + covered.add(root.package.product); + configuredRoots++; + } + } + } + assert.deepEqual( + [...covered].sort(), + [...versions.keys()].sort(), + 'native audit lacks a configured owner', + ); + for (const product of observation.products) { + assert.ok(product.construction.length, 'native audit lacks captured causal construction'); + for (const view of product.construction) + for (const field of ['leafInputPaths', 'analysisInputPaths'] as const) + assert.ok( + Array.isArray(view[field]) && + view[field].every((file) => typeof file === 'string' && file.length), + `native audit lacks captured ${field}`, + ); + } + assert.equal(suppliers.scope, 'construction', 'native audit suppliers exceed construction scope'); + equal(suppliers.source, source, 'native audit supplier source differs'); + assert.deepEqual(suppliers.unknowns, [], 'native audit has unknown supplier bytes or origins'); + assert.ok(suppliers.buildBound, 'native audit lacks a complete configured supplier map'); + assert.deepEqual( + [...suppliers.buildBound.keys()].sort(), + [...versions.keys()].sort(), + 'native audit supplier inventory differs', + ); + for (const [consumer, producers] of suppliers.buildBound) { + assert.ok(producers instanceof Set, 'native audit supplier rows must be configured sets'); + for (const producer of producers) + assert.ok( + producer !== consumer && versions.has(producer), + 'native audit has an unknown or self supplier', + ); + } + return { + scope: 'construction' as const, + source: structuredClone(source), + products: [...versions.keys()].sort(), + configuredRoots, + supplierBindings: suppliers.suppliers.length, + }; +} + +/** All producer jobs have finished; the workflow and its Required job may still run. */ +export async function auditNativeConstruction({ + source, + runId, + ref, + directory, + publicationInputs, +}: { + source: NativeBuildSource; + runId: number; + ref: string; + directory: string; + publicationInputs: string; +}) { + const snapshot = JSON.parse(readFileSync(publicationInputs, 'utf8')); + equal(snapshot.source, source, 'native audit input snapshot source differs'); + const destination = path.resolve(directory); + requireSafeDirectoryChain(path.dirname(destination), { + create: true, + label: 'native construction audit', + }); + assert.ok(!existsSync(destination), 'native audit requires a new owned directory'); + mkdirSync(destination); + let staging: string | undefined; + let keepDiagnostic = false; + try { + const acquisition = await acquireNativePublicationBuilds({ + source, + runId, + ref, + directory: path.join(destination, 'producers'), + }); + for (const origin of acquisition.origins.values()) assertAuthenticatedNativeBuildOrigin(origin); + const parent = requireSafeDirectoryChain(path.join(ROOT, 'target/native-construction-audit'), { + create: true, + label: 'native audit staging', + }); + staging = mkdtempSync(path.join(parent, `${runId}-`)); + const { candidate, bazelVersion } = stageNativePublicationConstruction({ + source, + runId, + ...acquisition, + directory: path.join(staging, 'construction'), + }); + const authenticate = async (evidenceRoot: string, expected) => { + const origin = acquisition.origins.get(evidenceRoot); + const build = acquisition.builds.find((row) => row.evidenceRoot === evidenceRoot); + assert.ok(origin && build, 'native audit cannot import an unacquired producer'); + equal(expected, build.expected, 'native audit producer constraints changed'); + origin.finalFiles?.assertUnchanged(); + return assertAuthenticatedNativeBuildOrigin(origin); + }; + // No reviewedSource: PR and feature sources remain construction observations. + const observation = await observeNativePublicationConstruction( + { + envelope: candidate, + files: lockedPublicationFiles(candidate), + repository: 'f0rr0/oliphaunt', + bazelVersion, + builds: acquisition.builds, + }, + { authenticate }, + ); + const completed = await acquireObservedCompletedSuppliers( + observation, + path.join(destination, 'held'), + snapshot.supplierArtifacts ?? [], + ); + const suppliers = await projectNativeBuildBoundSuppliers({ + products: Object.fromEntries(candidate.products.map((product) => [product.id, product])), + source, + observation, + completed, + }); + const result = assertNativeConstructionAudit({ + source, + candidate, + observation, + suppliers, + expectedProducts: loadPublicationCatalog('native construction audit').products, + }); + for (const origin of acquisition.origins.values()) origin.finalFiles?.assertUnchanged(); + writeFileSync( + path.join(destination, 'native-construction-audit.json'), + `${JSON.stringify(result, null, 2)}\n`, + { flag: 'wx' }, + ); + keepDiagnostic = true; + return result; + } finally { + if (staging) removeOwnedDirectory(staging); + // Only the small diagnostic survives; producer artifacts remain retained upstream. + for (const child of ['producers', 'held']) removeOwnedDirectory(path.join(destination, child)); + if (!keepDiagnostic) removeOwnedDirectory(destination); + } +} + +if (import.meta.main) { + const { values } = parseArgs({ + options: { + 'run-id': { type: 'string' }, + ref: { type: 'string' }, + 'output-directory': { type: 'string' }, + }, + strict: true, + }); + assert.ok( + values['run-id'] && /^[1-9][0-9]*$/u.test(values['run-id']), + 'native audit requires an exact positive run ID', + ); + assert.ok( + values.ref && values['output-directory'], + 'usage: audit-native-construction.mts --run-id ID --ref REF --output-directory DIR', + ); + assert.ok( + process.env.OLIPHAUNT_NATIVE_PUBLICATION_INPUTS, + 'native audit requires source-bound native inputs', + ); + assert.equal( + execFileSync('git', ['status', '--porcelain', '--untracked-files=all'], { + cwd: ROOT, + encoding: 'utf8', + }).trim(), + '', + 'native audit requires a clean source checkout', + ); + const result = await auditNativeConstruction({ + source: sourceIdentity('HEAD'), + runId: Number(values['run-id']), + ref: values.ref, + directory: values['output-directory'], + publicationInputs: process.env.OLIPHAUNT_NATIVE_PUBLICATION_INPUTS, + }); + console.log(JSON.stringify(result)); +} diff --git a/tools/release/audit-native-construction.test.mts b/tools/release/audit-native-construction.test.mts new file mode 100644 index 000000000..53297c727 --- /dev/null +++ b/tools/release/audit-native-construction.test.mts @@ -0,0 +1,299 @@ +import { expect, test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { assertNativeConstructionAudit } from './audit-native-construction.mts'; +import { loadPublicationCatalog } from './publication-catalog.mts'; + +const source = { commit: 'a'.repeat(40), tree: 'b'.repeat(40) }; +const products = loadPublicationCatalog('native construction audit fixture').products; +const swiftRoot = '//src/native/sdks/swift:shipping_Oliphaunt-source_zip'; + +// Structural observations exercise this diagnostic predicate only. These are +// neither authenticated origins nor physical packages, and grant no authority. +function fixture() { + const cohorts = [0, 1, 2].map((part) => { + const configuration = String(part + 1).repeat(64); + const roots = products + .filter((_, index) => index % 3 === part) + .map((product) => ({ + label: product.id === 'oliphaunt-swift' ? swiftRoot : `//fixture/${product.id}:shipping`, + configuration, + package: { + product: product.id, + version: product.version, + ecosystem: product.id === 'oliphaunt-swift' ? 'github' : 'npm', + name: product.id === 'oliphaunt-swift' ? 'Oliphaunt-source.zip' : product.id, + role: product.id === 'oliphaunt-swift' ? 'release-input' : 'facade', + configuration: 'portable', + outputs: [ + { + path: `bazel-out/fixture/${product.id}/package`, + owner: `//fixture/${product.id}:package`, + }, + ], + }, + })); + const policies = roots.map((root) => ({ + owner: + root.package.product === 'oliphaunt-swift' + ? '//src/native/sdks/swift:preparation_shipping_export' + : `//fixture/${root.package.product}:shipping_export`, + roots: [root.label], + requiredTests: [{ label: `//fixture/${root.package.product}:consumer_test`, configuration }], + })); + return { + invocationId: `fixture-${part}`, + roots, + qualificationPolicy: { + owner: `//fixture:cohort_${part}`, + configuration, + roots: roots.map((root) => root.label), + rootConfigurations: roots.map(({ label, configuration }) => ({ label, configuration })), + requiredTests: policies.flatMap((policy) => policy.requiredTests), + policies, + }, + }; + }); + const authenticated = cohorts.map((cohort) => ({ + evidence: { + source: { ...source }, + cohorts: [{ roots: cohort.roots.map(({ configuration: _, ...root }) => root) }], + }, + qualification: { + source: { ...source }, + shippingAnalysis: 'bound', + testQualification: 'passed', + qualificationPolicy: 'bound', + requiredTests: cohort.qualificationPolicy.requiredTests.map((test) => ({ + ...test, + invocationId: cohort.invocationId, + })), + cohorts: [cohort], + }, + })); + const roots = cohorts.flatMap((cohort) => cohort.roots); + const consumer = roots.find((root) => root.package.product === 'oliphaunt-js'); + const producer = roots.find((root) => root.package.product === 'liboliphaunt-wasix'); + assert.ok(consumer); + assert.ok(producer); + return { + source: { ...source }, + expectedProducts: structuredClone(products), + candidate: { + scope: 'construction', + source: { ...source }, + artifactPhase: 'pre-version', + products: structuredClone(products), + missing: [] as string[], + }, + observation: { + products: products.map((product) => ({ + product: structuredClone(product), + construction: [ + { + roots: cohorts + .flatMap((cohort) => cohort.roots) + .filter((root) => root.package.product === product.id), + actions: [], + inputs: [], + leafInputPaths: [], + analysisInputPaths: [] as string[], + }, + ], + })), + authenticated, + coverage: { completeProductInventory: true, releaseInputsRequired: true }, + }, + suppliers: { + scope: 'construction', + source: { ...source }, + suppliers: [ + { + consumer: 'oliphaunt-js', + product: 'liboliphaunt-wasix', + version: producer.package.version, + configuration: 'portable', + binding: 'compiled-input', + origin: { kind: 'current-source' }, + files: [{ path: producer.package.outputs[0].path }], + root: consumer.label, + consumerConfiguration: 'portable', + rootConfiguration: consumer.configuration, + }, + ], + unknowns: [] as string[], + buildBound: new Map( + products.map((product) => [ + product.id, + new Set(product.id === 'oliphaunt-js' ? ['liboliphaunt-wasix'] : []), + ]), + ), + }, + }; +} + +const audit = (input: ReturnType) => assertNativeConstructionAudit(input as any); + +test('all 27 owner observations compose through partial cohorts into construction diagnostics', () => { + const input = fixture(); + expect(products).toHaveLength(27); + expect( + input.observation.authenticated.every( + (build) => build.qualification.cohorts[0].roots.length < 27, + ), + ).toBe(true); + const result = audit(input); + expect(result).toEqual({ + scope: 'construction', + source, + products: products.map((product) => product.id).sort(), + configuredRoots: 27, + supplierBindings: 1, + }); + expect(Object.keys(result).sort()).toEqual([ + 'configuredRoots', + 'products', + 'scope', + 'source', + 'supplierBindings', + ]); + input.source.commit = 'f'.repeat(40); + expect(result.source).toEqual(source); +}); + +test('already-validated final Swift facts compose into the same construction audit', () => { + const input = fixture(); + const build = input.observation.authenticated.find((build) => + build.qualification.cohorts.some((cohort) => + cohort.roots.some((root) => root.label === swiftRoot), + ), + ); + assert.ok(build); + const cohort = build.qualification.cohorts[0]; + const policy = cohort.qualificationPolicy.policies.find((policy) => + policy.roots.includes(swiftRoot), + ); + assert.ok(policy); + policy.owner = '//src/native/sdks/swift:shipping_export'; + const installedTest = { + label: '//src/native/sdks/swift:installed_consumer_test', + configuration: cohort.qualificationPolicy.configuration, + }; + policy.requiredTests.push(installedTest); + cohort.qualificationPolicy.requiredTests.push(installedTest); + build.qualification.requiredTests.push({ + ...installedTest, + invocationId: cohort.invocationId, + }); + expect(audit(input).scope).toBe('construction'); +}); + +const faults: [string, (input: ReturnType) => void][] = [ + [ + 'dropped owner', + (input) => { + input.candidate.products.pop(); + input.observation.products.pop(); + }, + ], + [ + 'wrong candidate source', + (input) => { + input.candidate.source.tree = 'f'.repeat(40); + }, + ], + [ + 'wrong producer source', + (input) => { + input.observation.authenticated[0].evidence.source.tree = 'f'.repeat(40); + }, + ], + [ + 'wrong qualified source', + (input) => { + input.observation.authenticated[0].qualification.source.tree = 'f'.repeat(40); + }, + ], + [ + 'wrong observed version', + (input) => { + input.observation.products[0].product.version = '9.9.9'; + }, + ], + [ + 'missing loaded recipe view', + (input) => { + delete (input.observation.products[0].construction[0] as { analysisInputPaths?: string[] }) + .analysisInputPaths; + }, + ], + [ + 'missing configured owner', + (input) => { + input.observation.authenticated[0].qualification.cohorts[0].roots.pop(); + input.observation.authenticated[0].evidence.cohorts[0].roots.pop(); + }, + ], + [ + 'wrong supplier source', + (input) => { + input.suppliers.source.tree = 'f'.repeat(40); + }, + ], + [ + 'supplier unknown', + (input) => { + input.suppliers.unknowns.push('missing configured supplier'); + }, + ], + [ + 'incomplete supplier map', + (input) => { + input.suppliers.buildBound.delete(products[0].id); + }, + ], + [ + 'foreign supplier producer', + (input) => { + const suppliers = input.suppliers.buildBound.get(products[0].id); + assert.ok(suppliers); + suppliers.add('unknown-producer'); + }, + ], + [ + 'publication scope', + (input) => { + input.candidate.scope = 'publication'; + }, + ], + [ + 'missing final inputs', + (input) => { + input.candidate.missing.push('npm:missing'); + }, + ], + [ + 'incomplete configured inventory', + (input) => { + input.observation.coverage.completeProductInventory = false; + }, + ], + [ + 'unchecked release inputs', + (input) => { + input.observation.coverage.releaseInputsRequired = false; + }, + ], + [ + 'final version envelope', + (input) => { + input.candidate.artifactPhase = 'final'; + }, + ], +]; + +for (const [name, corrupt] of faults) + test(`construction audit rejects ${name}`, () => { + const input = fixture(); + corrupt(input); + expect(() => audit(input)).toThrow(); + }); diff --git a/tools/release/authenticate-native-build-evidence.mts b/tools/release/authenticate-native-build-evidence.mts new file mode 100644 index 000000000..84eaf6b15 --- /dev/null +++ b/tools/release/authenticate-native-build-evidence.mts @@ -0,0 +1,526 @@ +/** Authenticate construction evidence through the existing Actions artifact transport. */ + +import { deepStrictEqual } from 'node:assert'; +import { execFile } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { cpSync, existsSync, lstatSync, mkdtempSync, readFileSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { isDeepStrictEqual, parseArgs, promisify } from 'node:util'; +import { requireSafeDirectoryChain } from '../packaging/release-directory-safety.mts'; +import { githubJobArtifact, latestGithubJob, matchesGithubWorkflowRef } from './github-read.mts'; +import { readNativeBuildFinalFilesBatch } from './native-build-files.mts'; +import { + assertNativeBuildGithub, + type NativeBuildEvidence, + type NativeBuildGithub, + type NativeBuildSource, + type NativeRequiredTest, + nativeBuildMetadata, + validateNativeBuildEvidence, +} from './native-build-qualification.mts'; + +const execute = promisify(execFile); +const authenticatedOrigins = new WeakSet(); +function freezeAuthenticated(value: any) { + if (value && typeof value === 'object' && !Object.isFrozen(value)) { + for (const child of Object.values(value)) freezeAuthenticated(child); + Object.freeze(value); + } + return value; +} +/** This capability is minted by actual GitHub/ZIP acquisition, never JSON parsing. */ +export function assertAuthenticatedNativeBuildOrigin(value: unknown) { + if (!value || typeof value !== 'object' || !authenticatedOrigins.has(value)) + throw new Error('native origin was not acquired through the authenticated producer transport'); + const origin = value as Awaited>; + origin.finalFiles?.assertUnchanged?.(); + return origin; +} + +/** Reuse acquisition's immutable qualification only when no explicit test plan needs replay. */ +export function validateAuthenticatedNativeBuildEvidence( + origin: Pick< + Awaited>, + 'evidence' | 'finalFiles' + >, + expected: Parameters[1], +) { + const qualification = + authenticatedOrigins.has(origin) && expected.requiredTests === undefined + ? origin.finalFiles?.qualification + : undefined; + if (!qualification) return validateNativeBuildEvidence(origin.evidence, expected); + nativeBuildMetadata(expected.source, expected.github); + deepStrictEqual(qualification.source, expected.source, 'native build source'); + deepStrictEqual( + qualification.github, + expected.github, + 'native build producing workflow/run/attempt/job', + ); + const producingVersion = (origin.evidence as NativeBuildEvidence).cohorts[0].buildEvents.find( + (event) => event.started !== undefined, + )?.started?.buildToolVersion; + deepStrictEqual(producingVersion, expected.bazelVersion, 'native BEP Bazel version mismatch'); + if (expected.requireShippingAnalysis === true && qualification.shippingAnalysis !== 'bound') + throw new Error('native qualification requires producing-analysis shipping manifests'); + return qualification; +} +const reviewedProducerArtifacts: readonly (readonly [string, string])[] = [ + ['Linux runtime (x86_64)', 'native-build-evidence-x86_64'], + ['Linux runtime (aarch64)', 'native-build-evidence-aarch64'], + ['Portable packages (macos-arm64)', 'native-build-evidence-native-macos-arm64'], + ['Portable packages (windows-x64)', 'native-build-evidence-native-windows-x64'], + ['Linux WASIX and installed browser', 'native-build-evidence-wasix-tools'], + ['Linux native postmaster lifecycle', 'native-build-evidence-postmaster-linux'], + ['Native postmaster lifecycle (linux-arm64)', 'native-build-evidence-postmaster-linux-arm64'], + ['Native postmaster lifecycle (macos-arm64)', 'native-build-evidence-postmaster-macos-arm64'], + ['WASIX imported runtime (linux-arm64)', 'native-build-evidence-napi-linux-arm64'], + ['WASIX imported runtime (macos-arm64)', 'native-build-evidence-napi-macos-arm64'], + ['WASIX imported runtime (windows-x64)', 'native-build-evidence-napi-windows-x64'], + ['Linux runtime (x86_64)', 'native-build-evidence-mobile-android'], + ['Portable packages (macos-arm64)', 'native-build-evidence-mobile-ios'], + ['Native React Native consumers', 'native-build-evidence-react-native-macos-arm64'], + ['Native release families', 'native-build-evidence-release-families'], +]; +const isReviewedProducerArtifact = (job: string, artifact: unknown) => + reviewedProducerArtifacts.some(([owner, name]) => owner === job && name === artifact); +export function reviewedNativeProducerArtifacts() { + return reviewedProducerArtifacts.map(([job, artifactName]) => ({ job, artifactName })); +} +const acceptedExecutionAssumptions = [ + 'producer inputs remained immutable through capture in the reviewed isolated job', + 'the reviewed coordinator retained the native after-build dump from its producer invocation', +]; +const scopedExecutionAssumptions = [ + acceptedExecutionAssumptions[0], + 'the reviewed coordinator retained each native action graph from its producing build or corresponding scoped analysis in the same immutable producer window', +]; + +/** Shape validation does not authenticate JSON; its public use requires the signed metadata origin. */ +export function validateReviewedNativeProducerAssurance( + value: any, + expected: { + source: NativeBuildSource; + github?: NativeBuildGithub; + artifact?: unknown; + evidenceDigest?: string; + requiredTests?: unknown; + }, +) { + if (!value || typeof value !== 'object' || Array.isArray(value)) + throw new Error('reviewed native producer assurance must be an object'); + deepStrictEqual( + Object.keys(value).sort(), + [ + 'acceptedExecutionAssumptions', + 'artifact', + 'event', + 'evidenceDigest', + 'github', + 'ref', + 'requiredTests', + 'reviewedSource', + 'scope', + 'shippingAnalysis', + 'testQualification', + ].sort(), + 'reviewed native producer assurance fields', + ); + nativeBuildMetadata(value.reviewedSource, value.github); + deepStrictEqual(value.reviewedSource, expected.source, 'reviewed native producer source'); + if ( + value.scope !== 'reviewed-producer-assurance' || + !['push', 'workflow_dispatch'].includes(value.event) || + value.ref !== 'refs/heads/main' || + value.github.repository !== 'f0rr0/oliphaunt' || + value.github.workflow !== 'Native Bazel qualification' || + value.github.workflowPath !== '.github/workflows/bazel.yml' || + !isReviewedProducerArtifact(value.github.job, value.artifact?.name) || + value.shippingAnalysis !== 'bound' || + value.testQualification !== 'passed' || + !Array.isArray(value.requiredTests) || + !value.requiredTests.length || + !Number.isSafeInteger(value.artifact?.id) || + value.artifact.id < 1 || + !Number.isSafeInteger(value.artifact?.size) || + value.artifact.size < 1 || + !/^sha256:[0-9a-f]{64}$/u.test(value.artifact?.digest) || + !/^sha256:[0-9a-f]{64}$/u.test(value.evidenceDigest) + ) + throw new Error('reviewed native producer assurance identity is invalid'); + for (const test of value.requiredTests) + if ( + typeof test.label !== 'string' || + !test.label.startsWith('//') || + !/^[0-9a-f]{64}$/u.test(test.configuration) + ) + throw new Error('reviewed native producer assurance requires exact configured tests'); + if ( + ![acceptedExecutionAssumptions, scopedExecutionAssumptions].some((assumptions) => + isDeepStrictEqual(value.acceptedExecutionAssumptions, assumptions), + ) + ) + throw new Error('reviewed native producer execution assumptions differ'); + for (const key of ['github', 'artifact', 'evidenceDigest', 'requiredTests'] as const) + if (expected[key] !== undefined) + deepStrictEqual(value[key], expected[key], `reviewed native producer ${key}`); + return value; +} + +/** Only an authenticated reviewed producer closes these execution premises. */ +export function reviewedNativeProducerUnknowns(unverified: string[]) { + return unverified.filter( + (check) => + ![ + 'authenticated producing workflow, attempt, job and immutable artifact', + 'immutable input lifetime from the producing build through content capture', + 'native action-graph dump bytes authenticated by the producing invocation', + ].includes(check), + ); +} + +/** Caller expectations are constraints; only the downloader's GitHub API reads supply origin metadata. */ +type NativeBuildOriginExpectation = { + source: NativeBuildSource; + github: NativeBuildGithub; + event: 'push' | 'pull_request' | 'workflow_dispatch' | 'merge_group'; + ref: string; + artifactName: string; +}; + +type NativeBuildOriginSelection = Omit & { + github: Omit; + workflowRunAttempt: number; +}; + +export function authenticateNativeBuildEvidence( + evidenceRoot: string, + expected: NativeBuildOriginExpectation, +) { + return readAuthenticatedNativeBuildEvidence(evidenceRoot, expected); +} + +/** Acquire once into an owned directory; observation can reuse this authenticated origin. */ +export function acquireAuthenticatedNativeBuildEvidence( + directory: string, + expected: NativeBuildOriginExpectation | NativeBuildOriginSelection, +) { + const destination = path.resolve(directory); + requireSafeDirectoryChain(path.dirname(destination), { + create: true, + label: 'native evidence acquisition', + }); + if (existsSync(destination)) + throw new Error('native evidence acquisition requires a new owned directory'); + return readAuthenticatedNativeBuildEvidence(undefined, expected, destination); +} + +/** A controller-owned metadata snapshot is shared across one finite acquisition. + * No caller path or inherited cache can supply origin facts to this session. + */ +export function createNativeBuildEvidenceAcquirer() { + const owner = mkdtempSync(path.join(tmpdir(), 'oliphaunt-native-acquisition-')); + let closed = false; + return { + acquire( + directory: string, + expected: NativeBuildOriginExpectation | NativeBuildOriginSelection, + ) { + if (closed) throw new Error('native evidence acquisition session is closed'); + const destination = path.resolve(directory); + requireSafeDirectoryChain(path.dirname(destination), { + create: true, + label: 'native evidence acquisition', + }); + if (existsSync(destination)) + throw new Error('native evidence acquisition requires a new owned directory'); + return readAuthenticatedNativeBuildEvidence( + undefined, + expected, + destination, + path.join(owner, 'snapshots'), + ); + }, + dispose() { + closed = true; + rmSync(owner, { recursive: true, force: true }); + }, + }; +} + +async function readAuthenticatedNativeBuildEvidence( + evidenceRoot: string | undefined, + expected: NativeBuildOriginExpectation | NativeBuildOriginSelection, + retainedRoot?: string, + snapshotDirectory?: string, +) { + if ('runAttempt' in expected.github) assertNativeBuildGithub(expected.github); + if ( + 'workflowRunAttempt' in expected && + (!Number.isSafeInteger(expected.workflowRunAttempt) || expected.workflowRunAttempt <= 0) + ) + throw new Error('native origin workflow observation requires a positive attempt'); + if (![expected.source.commit, expected.source.tree].every((sha) => /^[0-9a-f]{40}$/u.test(sha))) + throw new Error('native origin requires exact source commit and tree'); + if ( + expected.github.workflow !== 'Native Bazel qualification' || + expected.github.workflowPath !== '.github/workflows/bazel.yml' + ) + throw new Error('native origin requires the canonical Native Bazel qualification workflow'); + if (!matchesGithubWorkflowRef(expected.event, expected.ref)) + throw new Error('native origin requires an eligible exact workflow event and ref'); + if (!/^[A-Za-z0-9_.-]+$/u.test(expected.artifactName)) + throw new Error('native origin artifact name is invalid'); + let bytes: Buffer | undefined; + if (evidenceRoot !== undefined) { + const file = path.join(path.resolve(evidenceRoot), 'native-build-evidence.json'); + const metadata = lstatSync(file); + if (!metadata.isFile() || metadata.isSymbolicLink()) + throw new Error('native origin evidence must be a regular file'); + bytes = readFileSync(file); + } + const scratch = mkdtempSync(path.join(tmpdir(), 'oliphaunt-native-origin-')); + try { + // This cache is created by this controller, never restored from evidence or inherited from a caller. + const snapshots = snapshotDirectory ?? path.join(scratch, 'snapshots'); + const downloaded = path.join(scratch, 'downloaded'); + const repositoryRoot = path.resolve(import.meta.dir, '../..'); + await execute( + 'bash', + [ + path.join(repositoryRoot, '.github/scripts/download-build-artifacts.sh'), + expected.github.workflow, + expected.source.commit, + downloaded, + '--run-id', + String(expected.github.runId), + '--job', + expected.github.job, + '--job-success-only', + '--workflow-path', + expected.github.workflowPath, + '--event', + expected.event, + '--ref', + expected.ref, + ...('runAttempt' in expected.github + ? ['--job-attempt', String(expected.github.runAttempt)] + : []), + ...('workflowRunAttempt' in expected + ? ['--run-attempt', String(expected.workflowRunAttempt)] + : []), + '--source-tree', + expected.source.tree, + '--artifact', + expected.artifactName, + ], + { + cwd: repositoryRoot, + env: { + ...process.env, + GH_REPO: expected.github.repository, + OLIPHAUNT_GITHUB_RUN_SNAPSHOT_DIR: snapshots, + }, + maxBuffer: 1024 * 1024, + }, + ); + const downloadedBytes = readFileSync(path.join(downloaded, 'native-build-evidence.json')); + if (bytes && !bytes.equals(downloadedBytes)) + throw new Error( + 'native build evidence bytes differ from the authenticated immutable artifact', + ); + bytes ??= downloadedBytes; + if (retainedRoot !== undefined) { + cpSync(downloaded, retainedRoot, { recursive: true, errorOnExist: true, force: false }); + evidenceRoot = retainedRoot; + } + if (evidenceRoot === undefined) + throw new Error('native authenticated files require owned storage'); + const snapshot = JSON.parse( + readFileSync(path.join(snapshots, `run-${expected.github.runId}.json`), 'utf8'), + ); + const job = latestGithubJob(snapshot, expected.github.job); + if (!job) throw new Error('native producing job is missing'); + const artifact = githubJobArtifact( + snapshot, + job, + expected.artifactName, + expected.source.commit, + ); + const github: NativeBuildGithub = { + repository: snapshot.repo, + workflow: snapshot.workflowName, + workflowPath: snapshot.workflowPath, + runId: Number(snapshot.runId), + runAttempt: job.run_attempt, + job: job.name, + }; + assertNativeBuildGithub(github); + deepStrictEqual( + 'runAttempt' in expected.github + ? expected.github + : { ...expected.github, runAttempt: job.run_attempt }, + github, + 'native producing GitHub identity differs', + ); + const evidence = JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes)); + const hasFiles = (directory: string) => existsSync(path.join(directory, 'files')); + if (hasFiles(evidenceRoot) !== hasFiles(downloaded)) + throw new Error('local and authenticated native final file transport differ'); + // Transport uses the authenticated producing packet's protocol version. + // Qualification callers still supply their independently expected source pin. + const producingBazelVersion = evidence.cohorts?.[0]?.buildEvents?.find( + (event) => event.started !== undefined, + )?.started?.buildToolVersion; + const [finalFiles, downloadedFiles] = hasFiles(downloaded) + ? readNativeBuildFinalFilesBatch([evidenceRoot, downloaded], evidence, { + source: expected.source, + github, + bazelVersion: producingBazelVersion, + }) + : []; + if (finalFiles) { + deepStrictEqual(finalFiles.files, downloadedFiles.files, 'authenticated native final files'); + finalFiles.assertUnchanged?.(); + } + const origin = { + github, + artifact: { + id: artifact.id, + name: artifact.name, + digest: artifact.digest, + size: artifact.size_in_bytes, + }, + evidenceDigest: `sha256:${createHash('sha256').update(bytes).digest('hex')}`, + // Parsing transports the authenticated bytes; the content validator still owns qualification. + evidence: evidence as unknown, + ...(finalFiles === undefined ? {} : { finalFiles }), + }; + freezeAuthenticated(origin); + authenticatedOrigins.add(origin); + return origin; + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +} + +/** Controller-owned source review accepts the isolated producer's execution discipline. */ +export async function assureReviewedNativeBuildProducer( + evidenceRoot: string, + { + expected, + reviewedSource, + bazelVersion, + requiredTests, + }: { + expected: Parameters[1]; + reviewedSource: NativeBuildSource; + bazelVersion: string; + requiredTests: NativeRequiredTest[]; + }, + // Transport injection is for controlled synthetic fixtures; production uses the authenticated downloader. + { authenticate = authenticateNativeBuildEvidence } = {}, +) { + const metadata = nativeBuildMetadata(reviewedSource, expected.github); + const expectedMetadata = nativeBuildMetadata(expected.source, expected.github); + if (JSON.stringify(metadata) !== JSON.stringify(expectedMetadata)) + throw new Error('reviewed native producer source differs from the frozen build source'); + if ( + !['push', 'workflow_dispatch'].includes(expected.event) || + expected.ref !== 'refs/heads/main' || + expected.github.repository !== 'f0rr0/oliphaunt' || + expected.github.workflow !== 'Native Bazel qualification' || + expected.github.workflowPath !== '.github/workflows/bazel.yml' + ) + throw new Error('reviewed native producer requires the canonical main workflow'); + if (!isReviewedProducerArtifact(expected.github.job, expected.artifactName)) + throw new Error('reviewed native producer job/artifact role is not canonical'); + if (!Array.isArray(requiredTests) || !requiredTests.length) + throw new Error('reviewed native producer requires controller-owned mandatory tests'); + const origin = await authenticate(evidenceRoot, expected); + if ( + JSON.stringify(nativeBuildMetadata(reviewedSource, origin.github)) !== + JSON.stringify(metadata) || + origin.artifact.name !== expected.artifactName || + !Number.isSafeInteger(origin.artifact.id) || + origin.artifact.id < 1 || + !Number.isSafeInteger(origin.artifact.size) || + origin.artifact.size < 1 || + !/^sha256:[0-9a-f]{64}$/u.test(origin.artifact.digest) || + !/^sha256:[0-9a-f]{64}$/u.test(origin.evidenceDigest) + ) + throw new Error('reviewed native producer authenticated origin is inconsistent'); + const qualification = validateNativeBuildEvidence(origin.evidence, { + source: reviewedSource, + github: expected.github, + bazelVersion, + requiredTests, + requireShippingAnalysis: true, + }); + return { + origin, + qualification, + assurance: validateReviewedNativeProducerAssurance( + { + scope: 'reviewed-producer-assurance' as const, + reviewedSource: structuredClone(reviewedSource), + event: expected.event, + ref: expected.ref, + github: structuredClone(origin.github), + artifact: structuredClone(origin.artifact), + evidenceDigest: origin.evidenceDigest, + shippingAnalysis: qualification.shippingAnalysis, + testQualification: qualification.testQualification, + requiredTests: qualification.requiredTests, + acceptedExecutionAssumptions: [ + ...((origin.evidence as NativeBuildEvidence).cohorts.some( + (cohort) => cohort.producerCapture?.aqueryBuildEvents !== undefined, + ) + ? scopedExecutionAssumptions + : acceptedExecutionAssumptions), + ], + }, + { source: reviewedSource }, + ), + }; +} + +if (import.meta.main) { + try { + const { values } = parseArgs({ + options: Object.fromEntries( + [ + 'source-commit', + 'source-tree', + 'github-json', + 'event', + 'ref', + 'artifact-name', + 'evidence-root', + ].map((name) => [name, { type: 'string' as const }]), + ), + allowPositionals: false, + }); + const required = (key: string) => { + const value = values[key]; + if (typeof value !== 'string' || !value) + throw new Error(`native origin authentication requires --${key}`); + return value; + }; + const { evidence: _, ...origin } = await authenticateNativeBuildEvidence( + required('evidence-root'), + { + source: { commit: required('source-commit'), tree: required('source-tree') }, + github: JSON.parse(readFileSync(required('github-json'), 'utf8')), + event: required('event') as NativeBuildOriginExpectation['event'], + ref: required('ref'), + artifactName: required('artifact-name'), + }, + ); + process.stdout.write(`${JSON.stringify(origin)}\n`); + } catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exitCode = 1; + } +} diff --git a/tools/release/authenticate-native-build-evidence.test.mts b/tools/release/authenticate-native-build-evidence.test.mts new file mode 100644 index 000000000..9f8c16501 --- /dev/null +++ b/tools/release/authenticate-native-build-evidence.test.mts @@ -0,0 +1,1196 @@ +import { expect, test } from 'bun:test'; +import { execFileSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + copyFileSync, + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + acquireAuthenticatedNativeBuildEvidence, + assertAuthenticatedNativeBuildOrigin, + assureReviewedNativeBuildProducer, + authenticateNativeBuildEvidence, + createNativeBuildEvidenceAcquirer, + validateAuthenticatedNativeBuildEvidence, + validateReviewedNativeProducerAssurance, +} from './authenticate-native-build-evidence.mts'; +import { + NATIVE_AQUERY_FLAGS, + type NativeBuildEvidence, + nativeAqueryExpression, + nativeBuildMetadata, +} from './native-build-qualification.mts'; + +const expected = { + source: { commit: 'a'.repeat(40), tree: 'b'.repeat(40) }, + github: { + repository: 'f0rr0/oliphaunt', + workflow: 'Native Bazel qualification', + workflowPath: '.github/workflows/bazel.yml', + runId: 77, + runAttempt: 1, + job: 'Linux runtime (x86_64)', + }, + event: 'workflow_dispatch' as const, + ref: 'refs/heads/main', + artifactName: 'native-build-evidence-x86_64', +}; + +/** Synthetic protocol/transport data tests assurance policy; it does not qualify a real builder. */ +function syntheticReviewedProducer( + job = expected.github.job, + artifactName = expected.artifactName, +) { + const request: Parameters[1] = { + expected: structuredClone(expected), + reviewedSource: structuredClone(expected.source), + bazelVersion: '8.8.1', + requiredTests: [{ label: '//fixture:installed', configuration: 'c'.repeat(64) }], + }; + request.expected.github.job = job; + request.expected.artifactName = artifactName; + const configuration = request.requiredTests[0].configuration; + const output = 'bazel-out/k8-opt/bin/fixture/native.tgz'; + const manifest = 'bazel-out/k8-opt/bin/fixture/shipping.shipping.json'; + const executionRoot = path.join(tmpdir(), 'native-assurance-synthetic-execroot'); + const aqueryFile = path.join(tmpdir(), 'native-assurance-synthetic-aquery.json'); + const root = { + label: '//fixture:shipping', + package: { + product: 'fixture-native', + version: '1.0.0', + ecosystem: 'github', + name: 'native.tgz', + configuration: 'linux-x64-gnu', + role: 'github-release-asset', + outputs: [{ path: output, owner: '//fixture:archive' }], + }, + }; + const contents = `${JSON.stringify(root)}\n`; + const identity = (bytes: string) => ({ + sha256: createHash('sha256').update(bytes).digest('hex'), + size: Buffer.byteLength(bytes), + }); + const outputIdentity = identity('synthetic public archive'); + const named = (id: string, file: string, bytes: string) => ({ + id: { namedSet: { id } }, + namedSetOfFiles: { + files: [{ name: file, digest: identity(bytes).sha256, length: String(identity(bytes).size) }], + }, + }); + const evidence: NativeBuildEvidence = { + schema: 'oliphaunt-native-build-evidence-v1', + source: request.expected.source, + github: request.expected.github, + cohorts: [ + { + executionRoot, + roots: [root], + rootConfigurations: [{ label: root.label, configuration }], + aquery: { + pathFragments: [output, manifest].flatMap((file, index) => + file.split('/').map((label, part) => ({ + id: `${index}-${part}`, + label, + ...(part ? { parentId: `${index}-${part - 1}` } : {}), + })), + ), + artifacts: [output, manifest].map((file, index) => ({ + id: index + 1, + pathFragmentId: `${index}-${file.split('/').length - 1}`, + })), + targets: [ + { id: 1, label: '//fixture:archive' }, + { id: 2, label: root.label }, + ], + configuration: [{ id: 1, checksum: configuration }], + actions: [1, 2].map((id) => ({ + targetId: id, + configurationId: 1, + mnemonic: 'FileWrite', + actionKey: `synthetic-file-${id}`, + outputIds: [id], + primaryOutputId: id, + })), + }, + buildEvents: [ + { + id: { started: {} }, + started: { uuid: 'synthetic-invocation', buildToolVersion: '8.8.1' }, + }, + { id: { workspace: {} }, workspaceInfo: { localExecRoot: executionRoot } }, + { id: { configuration: { id: configuration } }, configuration: { mnemonic: 'k8-opt' } }, + named('outputs', output, 'synthetic public archive'), + named('manifest', manifest, contents), + { + id: { targetCompleted: { label: root.label, configuration: { id: configuration } } }, + completed: { + success: true, + outputGroup: [ + { name: 'default', fileSets: [{ id: 'outputs' }] }, + { name: 'shipping_manifest', fileSets: [{ id: 'manifest' }] }, + ], + }, + }, + { + id: { + targetCompleted: { + label: '//fixture:installed', + configuration: { id: configuration }, + }, + }, + completed: { success: true }, + }, + { + id: { + testResult: { + label: '//fixture:installed', + configuration: { id: configuration }, + run: 1, + attempt: 1, + }, + }, + testResult: { status: 'PASSED' }, + }, + { + id: { + testSummary: { label: '//fixture:installed', configuration: { id: configuration } }, + }, + testSummary: { overallStatus: 'PASSED', totalRunCount: 1 }, + }, + { + id: { structuredCommandLine: { commandLineLabel: 'canonical' } }, + structuredCommandLine: { + commandLineLabel: 'canonical', + sections: [ + { + optionList: { + option: [ + { + optionName: 'experimental_aquery_dump_after_build_format', + optionValue: 'jsonproto', + }, + { + optionName: 'experimental_aquery_dump_after_build_output_file', + optionValue: aqueryFile, + }, + { optionName: 'output_groups', optionValue: '+shipping_manifest' }, + ], + }, + }, + ], + }, + }, + { + id: { buildMetadata: {} }, + buildMetadata: { + metadata: nativeBuildMetadata(request.expected.source, request.expected.github), + }, + }, + { id: { buildFinished: {} }, finished: { exitCode: { name: 'SUCCESS' } } }, + { id: { buildMetrics: {} }, buildMetrics: {}, lastMessage: true }, + ], + inputs: [], + outputs: [ + { path: output, members: [{ path: '', type: 'file', mode: 0o644, ...outputIdentity }] }, + ], + producerCapture: { aqueryFile, shippingManifests: [{ path: manifest, contents }] }, + }, + ], + }; + const origin = { + github: structuredClone(request.expected.github), + artifact: { + id: 101, + name: request.expected.artifactName, + digest: `sha256:${'d'.repeat(64)}`, + size: 1024, + }, + evidenceDigest: `sha256:${identity(JSON.stringify(evidence)).sha256}`, + evidence, + }; + return { request, origin, authenticate: async () => origin }; +} + +async function fixture(run: (root: string) => Promise, kind = '') { + const root = mkdtempSync(path.join(tmpdir(), 'oliphaunt-native-auth-test-')); + const keys = [ + 'BUN_OPTIONS', + 'GH_TOKEN', + 'GH_REPO', + 'PATH', + 'FAKE_NATIVE_ORIGIN', + 'FAKE_NATIVE_CASE', + 'FAKE_NATIVE_EVENT', + 'FAKE_NATIVE_HEAD_BRANCH', + 'FAKE_RUN_STATUS', + 'FAKE_ARTIFACT_ARCHIVE', + 'FAKE_GH_LOG', + 'FAKE_GH_STATE', + 'FAKE_MODE', + 'FAKE_RUN_CONCLUSION', + 'FAKE_AMBIENT_BUN_LOG', + 'OLIPHAUNT_PINNED_TOOL_ROOT', + 'OLIPHAUNT_PINNED_TOOL_PROTO_FILE', + 'OLIPHAUNT_BUN_TOOLCHAIN_MANIFEST', + 'OLIPHAUNT_PINNED_TOOL_TARGET', + 'OLIPHAUNT_PINNED_TOOL_CACHE_ROOT', + 'OLIPHAUNT_PINNED_TOOL_CURL', + 'OLIPHAUNT_GITHUB_RUN_SNAPSHOT_DIR', + ]; + const before = Object.fromEntries(keys.map((key) => [key, process.env[key]])); + try { + mkdirSync(path.join(root, 'evidence')); + // Synthetic transport bytes exercise this boundary; they are not a qualified or live-authenticated build packet. + writeFileSync( + path.join(root, 'evidence/native-build-evidence.json'), + JSON.stringify({ synthetic: true }), + ); + execFileSync('zip', ['-q', path.join(root, 'artifact.zip'), 'native-build-evidence.json'], { + cwd: path.join(root, 'evidence'), + }); + mkdirSync(path.join(root, 'untrusted-cache')); + writeFileSync( + path.join(root, 'untrusted-cache/run-77.json'), + '{"untrusted":"downloaded fixture metadata"}', + ); + Object.assign(process.env, { + BUN_OPTIONS: `--preload=${path.resolve(import.meta.dir, 'testdata/download-build-artifacts-github.mts')}`, + GH_TOKEN: 'test-token', + GH_REPO: 'ignored/by-adapter', + PATH: `${path.dirname(process.execPath)}${path.delimiter}${process.env.PATH}`, + FAKE_NATIVE_ORIGIN: 'true', + FAKE_NATIVE_CASE: kind, + FAKE_ARTIFACT_ARCHIVE: path.join(root, 'artifact.zip'), + FAKE_GH_LOG: path.join(root, 'api.log'), + FAKE_GH_STATE: path.join(root, 'download-count'), + FAKE_MODE: 'success', + FAKE_RUN_CONCLUSION: 'failure', + OLIPHAUNT_GITHUB_RUN_SNAPSHOT_DIR: path.join(root, 'untrusted-cache'), + }); + await run(root); + } finally { + for (const key of keys) { + if (before[key] === undefined) delete process.env[key]; + else process.env[key] = before[key]; + } + rmSync(root, { recursive: true, force: true }); + } +} + +test('reviewed main producer assurance preserves construction limits and accepts bound mandatory tests', async () => { + for (const [job, artifact] of [ + ['Linux runtime (x86_64)', 'native-build-evidence-x86_64'], + ['Linux runtime (aarch64)', 'native-build-evidence-aarch64'], + ['Linux WASIX and installed browser', 'native-build-evidence-wasix-tools'], + ['Linux native postmaster lifecycle', 'native-build-evidence-postmaster-linux'], + ['Native postmaster lifecycle (linux-arm64)', 'native-build-evidence-postmaster-linux-arm64'], + ['Native postmaster lifecycle (macos-arm64)', 'native-build-evidence-postmaster-macos-arm64'], + ['WASIX imported runtime (linux-arm64)', 'native-build-evidence-napi-linux-arm64'], + ['WASIX imported runtime (macos-arm64)', 'native-build-evidence-napi-macos-arm64'], + ['WASIX imported runtime (windows-x64)', 'native-build-evidence-napi-windows-x64'], + ['Linux runtime (x86_64)', 'native-build-evidence-mobile-android'], + ['Portable packages (macos-arm64)', 'native-build-evidence-mobile-ios'], + ]) { + for (const event of ['push', 'workflow_dispatch'] as const) { + const f = syntheticReviewedProducer(job, artifact); + f.request.expected.event = event; + const result = await assureReviewedNativeBuildProducer('synthetic', f.request, f); + expect(result.assurance.scope).toBe('reviewed-producer-assurance'); + expect(result.assurance.reviewedSource).toEqual(f.request.reviewedSource); + expect(result.assurance.event).toBe(f.request.expected.event); + expect(result.assurance.ref).toBe('refs/heads/main'); + expect(result.assurance.artifact).toEqual(f.origin.artifact); + expect(result.assurance.shippingAnalysis).toBe('bound'); + expect(result.assurance.testQualification).toBe('passed'); + expect(result.assurance.requiredTests).toMatchObject(f.request.requiredTests); + expect(result.assurance.acceptedExecutionAssumptions).toHaveLength(2); + expect('releaseDecision' in result.assurance).toBe(false); + expect('baselineAdmission' in result.assurance).toBe(false); + expect(result.qualification.scope).toBe('construction'); + expect(result.qualification.releaseDecision).toBe('unverified'); + expect(result.qualification.unverified).toContain( + 'immutable input lifetime from the producing build through content capture', + ); + expect(result.qualification.unverified).toContain( + 'native action-graph dump bytes authenticated by the producing invocation', + ); + } + } +}); + +test('portable matrix roles cannot authenticate the relocated NAPI producer artifacts', async () => { + for (const platform of ['linux-x64', 'linux-arm64', 'macos-arm64', 'windows-x64']) { + const f = syntheticReviewedProducer( + `Portable packages (${platform})`, + `native-build-evidence-napi-${platform}`, + ); + await expect(assureReviewedNativeBuildProducer('synthetic', f.request, f)).rejects.toThrow( + 'job/artifact role is not canonical', + ); + } +}); + +test('reviewed execution assumptions retain immutable dump readback and describe scoped capture honestly', async () => { + const historical = syntheticReviewedProducer(); + const old = await assureReviewedNativeBuildProducer('synthetic', historical.request, historical); + expect(old.assurance.acceptedExecutionAssumptions).toEqual([ + 'producer inputs remained immutable through capture in the reviewed isolated job', + 'the reviewed coordinator retained the native after-build dump from its producer invocation', + ]); + const f = syntheticReviewedProducer(); + const cohort = f.origin.evidence.cohorts[0]; + const producer = cohort.producerCapture; + if (!producer) throw new Error('Missing synthetic producing capture'); + const targets = ['//fixture:shipping', '//fixture:installed']; + const canonical = cohort.buildEvents.find((event: any) => event.structuredCommandLine) as any; + canonical.structuredCommandLine.sections = [ + { sectionLabel: 'command', chunkList: { chunk: ['test'] } }, + { sectionLabel: 'residual', chunkList: { chunk: targets } }, + ]; + producer.aqueryBuildEvents = [ + ...structuredClone( + cohort.buildEvents.filter( + (event: any) => + event.started || + event.workspaceInfo || + event.configuration || + event.buildMetadata || + event.finished || + event.lastMessage, + ), + ), + { + structuredCommandLine: { + commandLineLabel: 'canonical', + sections: [ + { sectionLabel: 'command', chunkList: { chunk: ['aquery'] } }, + { sectionLabel: 'residual', chunkList: { chunk: [nativeAqueryExpression(targets)] } }, + { + sectionLabel: 'command options', + optionList: { + option: [ + ...NATIVE_AQUERY_FLAGS.map((flag) => { + const [optionName, value] = flag.slice(2).split('='); + return { + optionName, + optionValue: value, + }; + }), + { optionName: 'output_file', optionValue: producer.aqueryFile }, + ], + }, + }, + ], + }, + }, + ]; + const events = producer.aqueryBuildEvents as any[]; + events.find((event) => event.started).started.uuid = 'synthetic-aquery'; + const terminal = events.splice( + events.findIndex((event) => event.lastMessage), + 1, + )[0]; + events.push(terminal); + f.origin.evidenceDigest = `sha256:${createHash('sha256').update(JSON.stringify(f.origin.evidence)).digest('hex')}`; + const current = await assureReviewedNativeBuildProducer('synthetic', f.request, f); + expect(current.assurance.acceptedExecutionAssumptions).toEqual([ + old.assurance.acceptedExecutionAssumptions[0], + 'the reviewed coordinator retained each native action graph from its producing build or corresponding scoped analysis in the same immutable producer window', + ]); + for (const assurance of [old.assurance, current.assurance]) { + expect( + validateReviewedNativeProducerAssurance(structuredClone(assurance), { + source: f.request.reviewedSource, + }), + ).toEqual(assurance); + expect(() => + validateReviewedNativeProducerAssurance( + { ...assurance, acceptedExecutionAssumptions: ['arbitrary host assurance'] }, + { source: f.request.reviewedSource }, + ), + ).toThrow(); + } +}); + +test('reviewed producer rejects unreviewed sources, PR origins and noncanonical roles before transport', async () => { + const cases: [string, (f: ReturnType) => void][] = [ + [ + 'repository', + (f) => { + f.request.expected.github.repository = 'attacker/oliphaunt'; + }, + ], + [ + 'source commit', + (f) => { + f.request.reviewedSource.commit = 'e'.repeat(40); + }, + ], + [ + 'source tree', + (f) => { + f.request.reviewedSource.tree = 'e'.repeat(40); + }, + ], + [ + 'PR', + (f) => { + f.request.expected.event = 'pull_request'; + f.request.expected.ref = 'refs/pull/1/merge'; + }, + ], + [ + 'branch', + (f) => { + f.request.expected.ref = 'refs/heads/release'; + }, + ], + [ + 'workflow', + (f) => { + f.request.expected.github.workflow = 'Unreviewed builder'; + }, + ], + [ + 'workflow path', + (f) => { + f.request.expected.github.workflowPath = '.github/workflows/unreviewed.yml'; + }, + ], + [ + 'job', + (f) => { + f.request.expected.github.job = 'Portable packages (windows-x64)'; + }, + ], + [ + 'artifact', + (f) => { + f.request.expected.artifactName = 'native-build-evidence-aarch64'; + }, + ], + [ + 'retired WASIX split producer', + (f) => { + f.request.expected.github.job = 'Linux WASIX and installed browser'; + f.request.expected.artifactName = 'native-build-evidence-wasix-pg-hashids'; + }, + ], + [ + 'unknown job with missing artifact', + (f) => { + f.request.expected.github.job = 'Unreviewed builder'; + Reflect.deleteProperty(f.request.expected, 'artifactName'); + }, + ], + [ + 'missing tests', + (f) => { + Reflect.deleteProperty(f.request, 'requiredTests'); + }, + ], + [ + 'empty tests', + (f) => { + f.request.requiredTests = []; + }, + ], + ]; + for (const [name, mutate] of cases) { + const f = syntheticReviewedProducer(); + mutate(f); + let calls = 0; + await expect( + assureReviewedNativeBuildProducer('synthetic', f.request, { + authenticate: async () => { + calls += 1; + return f.origin; + }, + }), + ).rejects.toThrow(); + expect(calls, name).toBe(0); + } +}); + +test('retained assurance rejects unknown jobs even when the artifact name is absent', async () => { + const f = syntheticReviewedProducer(); + const { assurance } = await assureReviewedNativeBuildProducer('synthetic', f.request, f); + expect( + validateReviewedNativeProducerAssurance(assurance, { source: f.request.reviewedSource }), + ).toBe(assurance); + for (const job of ['Unreviewed builder', expected.github.job]) { + const malformed = structuredClone(assurance); + malformed.github.job = job; + Reflect.deleteProperty(malformed.artifact, 'name'); + expect(() => + validateReviewedNativeProducerAssurance(malformed, { + source: f.request.reviewedSource, + }), + ).toThrow('assurance identity is invalid'); + } +}); + +test('reviewed producer rejects substituted authenticated origin and immutable artifact identities', async () => { + const cases: [string, (f: ReturnType) => void][] = [ + [ + 'repository', + (f) => { + f.origin.github.repository = 'attacker/oliphaunt'; + }, + ], + [ + 'run', + (f) => { + f.origin.github.runId += 1; + }, + ], + [ + 'attempt', + (f) => { + f.origin.github.runAttempt += 1; + }, + ], + [ + 'job', + (f) => { + f.origin.github.job = 'Linux runtime (aarch64)'; + }, + ], + [ + 'artifact name', + (f) => { + f.origin.artifact.name = 'native-build-evidence-aarch64'; + }, + ], + [ + 'artifact id', + (f) => { + f.origin.artifact.id = 0; + }, + ], + [ + 'artifact digest', + (f) => { + f.origin.artifact.digest = 'invalid'; + }, + ], + [ + 'artifact size', + (f) => { + f.origin.artifact.size = 0; + }, + ], + [ + 'evidence digest', + (f) => { + f.origin.evidenceDigest = 'invalid'; + }, + ], + ]; + for (const [name, mutate] of cases) { + const f = syntheticReviewedProducer(); + mutate(f); + await expect( + assureReviewedNativeBuildProducer('synthetic', f.request, f), + name, + ).rejects.toThrow(); + } +}); + +test('reviewed producer requires producing-analysis shipping and complete successful configured tests', async () => { + const cases: [string, (f: ReturnType) => void][] = [ + [ + 'evidence source', + (f) => { + f.origin.evidence.source = { ...f.request.reviewedSource, commit: 'e'.repeat(40) }; + }, + ], + [ + 'legacy analysis', + (f) => { + delete f.origin.evidence.cohorts[0].producerCapture; + }, + ], + [ + 'missing test', + (f) => { + f.request.requiredTests[0].label = '//fixture:missing'; + }, + ], + [ + 'wrong configuration', + (f) => { + f.request.requiredTests[0].configuration = 'e'.repeat(64); + }, + ], + [ + 'missing result', + (f) => { + f.origin.evidence.cohorts[0].buildEvents = f.origin.evidence.cohorts[0].buildEvents.filter( + (event) => !event.testResult, + ); + }, + ], + [ + 'failed result', + (f) => { + const event = f.origin.evidence.cohorts[0].buildEvents.find((event) => event.testResult); + if (!event) throw new Error('synthetic fixture requires its test result'); + event.testResult.status = 'FAILED'; + }, + ], + [ + 'failed summary', + (f) => { + const event = f.origin.evidence.cohorts[0].buildEvents.find((event) => event.testSummary); + if (!event) throw new Error('synthetic fixture requires its test summary'); + event.testSummary.overallStatus = 'FAILED'; + }, + ], + ]; + for (const [name, mutate] of cases) { + const f = syntheticReviewedProducer(); + mutate(f); + await expect( + assureReviewedNativeBuildProducer('synthetic', f.request, f), + name, + ).rejects.toThrow(); + } +}); + +test('native origin uses pinned Bun without ambient Bun for exact-ID/digest transport, ignoring inherited fixture caches', async () => { + await fixture(async (root) => { + const repository = path.resolve(import.meta.dir, '../..'); + const platform = process.platform === 'win32' ? 'windows' : process.platform; + const target = `${platform}-${process.arch === 'arm64' ? 'aarch64' : process.arch}`; + const manifest = path.join(repository, 'tools/dev/bun.toml'); + const proto = path.join(repository, '.prototools'); + const pin = Bun.TOML.parse(readFileSync(manifest, 'utf8')).assets[target]; + const version = Bun.TOML.parse(readFileSync(proto, 'utf8')).bun; + expect(Bun.version).toBe(version); + expect(createHash('sha256').update(readFileSync(process.execPath)).digest('hex')).toBe( + pin.binary_sha256, + ); + const cache = path.join(root, 'pinned-tools'); + const envelope = path.join(cache, 'bun', `v${version}`, target); + const binary = path.join(envelope, 'bin', process.platform === 'win32' ? 'bun.exe' : 'bun'); + mkdirSync(path.dirname(binary), { recursive: true, mode: 0o700 }); + copyFileSync(process.execPath, binary); + chmodSync(binary, 0o555); + writeFileSync( + path.join(envelope, 'receipt'), + `tool=bun\nversion=${version}\ntarget=${target}\narchive_sha256=${pin.sha256}\nbinary_sha256=${pin.binary_sha256}\n`, + { mode: 0o444 }, + ); + const unavailable = path.join(root, 'unavailable'); + mkdirSync(unavailable); + const ambient = path.join(unavailable, 'bun'); + writeFileSync( + ambient, + '#!/bin/sh\nprintf \'%s\\n\' "$*" >> "$FAKE_AMBIENT_BUN_LOG"\necho "ambient Bun unavailable" >&2\nexit 127\n', + { mode: 0o755 }, + ); + Object.assign(process.env, { + PATH: `${unavailable}${path.delimiter}${process.env.PATH}`, + FAKE_AMBIENT_BUN_LOG: path.join(root, 'ambient-bun.log'), + OLIPHAUNT_PINNED_TOOL_ROOT: repository, + OLIPHAUNT_PINNED_TOOL_PROTO_FILE: proto, + OLIPHAUNT_BUN_TOOLCHAIN_MANIFEST: manifest, + OLIPHAUNT_PINNED_TOOL_TARGET: target, + OLIPHAUNT_PINNED_TOOL_CACHE_ROOT: cache, + // A bad cache must fail locally rather than acquire a runtime over the network. + OLIPHAUNT_PINNED_TOOL_CURL: ambient, + }); + const origin = await authenticateNativeBuildEvidence(path.join(root, 'evidence'), expected); + // Each real wrapper phase probes ambient Bun, then runs the validated cached binary. + expect(readFileSync(path.join(root, 'ambient-bun.log'), 'utf8').trim().split('\n')).toEqual([ + '--version', + '--version', + '--version', + ]); + expect(assertAuthenticatedNativeBuildOrigin(origin)).toBe(origin); + expect(() => assertAuthenticatedNativeBuildOrigin(JSON.parse(JSON.stringify(origin)))).toThrow( + /authenticated producer transport/u, + ); + expect(Object.isFrozen(origin.evidence)).toBe(true); + expect(() => { + origin.github.job = 'invented producer'; + }).toThrow(); + expect(origin.github).toEqual(expected.github); + expect(origin.artifact).toMatchObject({ id: 101, name: expected.artifactName }); + expect(origin.artifact.digest).toMatch(/^sha256:[0-9a-f]{64}$/u); + expect(origin.evidence).toEqual({ synthetic: true }); + expect(origin.evidenceDigest).toMatch(/^sha256:[0-9a-f]{64}$/u); + writeFileSync( + path.join(root, 'evidence/native-build-evidence.json'), + JSON.stringify({ changedAfterAuthentication: true }), + ); + expect(origin.evidence).toEqual({ synthetic: true }); + const endpoints: string[] = readFileSync(path.join(root, 'api.log'), 'utf8') + .trim() + .split('\n') + .map(JSON.parse); + expect(endpoints.some((url) => url.endsWith('/actions/artifacts/101/zip'))).toBe(true); + expect(endpoints.some((url) => url.endsWith(`/git/commits/${expected.source.commit}`))).toBe( + true, + ); + expect(readFileSync(path.join(root, 'untrusted-cache/run-77.json'), 'utf8')).toContain( + 'untrusted', + ); + }); +}); + +test('owned native acquisition authenticates and retains one download without accepting an existing destination', async () => { + await fixture(async (root) => { + const destination = path.join(root, 'acquired'); + const origin = await acquireAuthenticatedNativeBuildEvidence(destination, expected); + expect(origin.evidence).toEqual({ synthetic: true }); + expect(() => + validateAuthenticatedNativeBuildEvidence(origin, { ...expected, bazelVersion: '8.8.1' }), + ).toThrow(); + expect( + JSON.parse(readFileSync(path.join(destination, 'native-build-evidence.json'), 'utf8')), + ).toEqual(origin.evidence); + const requests = readFileSync(path.join(root, 'api.log'), 'utf8') + .trim() + .split('\n') + .map(JSON.parse); + expect(requests.filter((url) => url.endsWith('/actions/artifacts/101/zip'))).toHaveLength(1); + expect(() => acquireAuthenticatedNativeBuildEvidence(destination, expected)).toThrow( + /new owned directory/, + ); + }); +}); + +test('an exact merge queue authenticates completed producer transport during construction without reviewed-main assurance', async () => { + await fixture(async (root) => { + const branch = 'gh-readonly-queue/main/pr-295-aabbcc'; + const queued = { ...expected, event: 'merge_group' as const, ref: `refs/heads/${branch}` }; + process.env.FAKE_NATIVE_EVENT = queued.event; + process.env.FAKE_NATIVE_HEAD_BRANCH = branch; + process.env.FAKE_RUN_STATUS = 'in_progress'; + const origin = await acquireAuthenticatedNativeBuildEvidence(path.join(root, 'queued'), queued); + expect(assertAuthenticatedNativeBuildOrigin(origin)).toBe(origin); + expect(origin.evidence).toEqual({ synthetic: true }); + const requests = () => + readFileSync(path.join(root, 'api.log'), 'utf8').trim().split('\n').map(JSON.parse); + expect(requests().filter((url) => url.endsWith('/actions/artifacts/101/zip'))).toHaveLength(1); + const reviewed = syntheticReviewedProducer().request; + reviewed.expected = queued; + await expect( + assureReviewedNativeBuildProducer(path.join(root, 'queued'), reviewed, { + authenticate: async () => origin, + }), + ).rejects.toThrow('canonical main workflow'); + expect(requests().filter((url) => url.endsWith('/actions/artifacts/101/zip'))).toHaveLength(1); + }); +}); + +test('merge queue transport rejects wrong queue branch, base, and source before downloading archive bytes', async () => { + for (const fault of ['branch', 'base', 'source', 'tree'] as const) { + await fixture( + async (root) => { + process.env.FAKE_NATIVE_EVENT = 'merge_group'; + process.env.FAKE_NATIVE_HEAD_BRANCH = 'gh-readonly-queue/main/pr-295-aabbcc'; + const queued = { + ...expected, + event: 'merge_group' as const, + ref: + fault === 'base' + ? 'refs/heads/gh-readonly-queue/develop/pr-295-aabbcc' + : fault === 'branch' + ? 'refs/heads/gh-readonly-queue/main/pr-296-other' + : `refs/heads/${process.env.FAKE_NATIVE_HEAD_BRANCH}`, + }; + await expect( + acquireAuthenticatedNativeBuildEvidence(path.join(root, 'queued'), queued), + ).rejects.toThrow(); + const requests = existsSync(path.join(root, 'api.log')) + ? readFileSync(path.join(root, 'api.log'), 'utf8') + : ''; + expect(requests).not.toContain('/actions/artifacts/101/zip'); + }, + fault === 'source' || fault === 'tree' ? fault : '', + ); + } +}); + +test('one controller session shares only its owned origin metadata and still authenticates every archive', async () => { + await fixture(async (root) => { + const session = createNativeBuildEvidenceAcquirer(); + try { + await session.acquire(path.join(root, 'first'), expected); + await session.acquire(path.join(root, 'second'), expected); + const requests: string[] = readFileSync(path.join(root, 'api.log'), 'utf8') + .trim() + .split('\n') + .map(JSON.parse); + expect(requests.filter((url) => url.endsWith('/actions/artifacts/101/zip'))).toHaveLength(2); + expect(requests.filter((url) => url.endsWith('/actions/runs/77'))).toHaveLength(1); + expect( + requests.filter((url) => url.endsWith(`/git/commits/${expected.source.commit}`)), + ).toHaveLength(1); + } finally { + session.dispose(); + } + expect(() => session.acquire(path.join(root, 'third'), expected)).toThrow('session is closed'); + }); +}); + +test('mixed producer attempts retain untouched and retried job identities from one owned snapshot', async () => { + await fixture(async (root) => { + const session = createNativeBuildEvidenceAcquirer(); + try { + const untouched = await session.acquire(path.join(root, 'untouched'), expected); + const retried = await session.acquire(path.join(root, 'retried'), { + ...expected, + github: { ...expected.github, job: 'Linux runtime (aarch64)', runAttempt: 2 }, + artifactName: 'native-build-evidence-aarch64', + }); + expect(untouched.github).toEqual(expected.github); + expect(retried.github).toEqual({ + ...expected.github, + job: 'Linux runtime (aarch64)', + runAttempt: 2, + }); + expect(untouched.artifact.id).toBe(101); + expect(retried.artifact.id).toBe(103); + expect(untouched.evidence).toEqual({ synthetic: true }); + expect(retried.evidence).toEqual(untouched.evidence); + const requests: string[] = readFileSync(path.join(root, 'api.log'), 'utf8') + .trim() + .split('\n') + .map(JSON.parse); + expect(requests.filter((url) => url.includes('/actions/runs/77/jobs?'))).toHaveLength(1); + expect(requests.find((url) => url.includes('/actions/runs/77/jobs?'))).toContain( + 'filter=all', + ); + expect(requests.some((url) => url.includes('/actions/artifacts/102/zip'))).toBe(false); + } finally { + session.dispose(); + } + }, 'mixed'); +}); + +for (const fault of [ + 'mixed-failed', + 'mixed-cancelled', + 'mixed-pending', + 'mixed-ambiguous', + 'mixed-stale', +]) + test(`mixed producer attempts reject a newer unusable role before archive download (${fault})`, async () => { + await fixture(async (root) => { + await expect( + acquireAuthenticatedNativeBuildEvidence(path.join(root, 'rejected'), { + ...expected, + github: { ...expected.github, job: 'Linux runtime (aarch64)', runAttempt: 2 }, + artifactName: 'native-build-evidence-aarch64', + }), + ).rejects.toThrow(); + expect(existsSync(path.join(root, 'download-count'))).toBe(false); + }, fault); + }); + +test('mixed producer attempts reject a forged producing attempt instead of restamping a retained job', async () => { + await fixture(async (root) => { + await expect( + acquireAuthenticatedNativeBuildEvidence(path.join(root, 'forged'), { + ...expected, + github: { ...expected.github, runAttempt: 2 }, + }), + ).rejects.toThrow(); + expect(existsSync(path.join(root, 'download-count'))).toBe(false); + }, 'mixed'); +}); + +test('mixed producer acquisition can resolve the own attempt without inheriting the observer attempt', async () => { + await fixture(async (root) => { + const { runAttempt: _, ...github } = expected.github; + const origin = await acquireAuthenticatedNativeBuildEvidence(path.join(root, 'selected'), { + ...expected, + github, + workflowRunAttempt: 2, + }); + expect(origin.github).toEqual(expected.github); + expect(origin.evidence).toEqual({ synthetic: true }); + }, 'mixed'); +}); + +test('mixed producer selection rejects a changed workflow observation without relabelling its producer', async () => { + await fixture(async (root) => { + const { runAttempt: _, ...github } = expected.github; + await expect( + acquireAuthenticatedNativeBuildEvidence(path.join(root, 'changed-run'), { + ...expected, + github, + workflowRunAttempt: 1, + }), + ).rejects.toThrow(); + expect(existsSync(path.join(root, 'download-count'))).toBe(false); + }, 'mixed'); +}); + +test('native origin rejects stale source/tree/attempt/job, wrong workflow/event/ref and cross-attempt artifacts', async () => { + for (const kind of [ + 'source', + 'tree', + 'attempt', + 'job-attempt', + 'job-failure', + 'workflow', + 'run-workflow', + 'event', + 'ref', + 'stale-artifact', + 'artifact-source', + 'artifact-missing', + 'artifact-ambiguous', + 'artifact-window-missing', + 'artifact-head-missing', + 'job-window-missing', + ]) { + await fixture(async (root) => { + await expect( + authenticateNativeBuildEvidence(path.join(root, 'evidence'), expected), + ).rejects.toThrow(); + expect(existsSync(path.join(root, 'download-count'))).toBe(false); + }, kind); + } +}); + +test('authentication CLI emits bounded origin metadata and digest without the large parsed packet', async () => { + await fixture(async (root) => { + const context = path.join(root, 'github.json'); + writeFileSync(context, JSON.stringify(expected.github)); + const script = path.resolve(import.meta.dir, 'authenticate-native-build-evidence.mts'); + const output = execFileSync( + process.execPath, + [ + script, + '--source-commit', + expected.source.commit, + '--source-tree', + expected.source.tree, + '--github-json', + context, + '--event', + expected.event, + '--ref', + expected.ref, + '--artifact-name', + expected.artifactName, + '--evidence-root', + path.join(root, 'evidence'), + ], + { encoding: 'utf8', env: process.env }, + ); + const origin = JSON.parse(output); + expect(Object.keys(origin).sort()).toEqual(['artifact', 'evidenceDigest', 'github']); + expect(origin.github).toEqual(expected.github); + expect(origin.artifact.id).toBe(101); + expect(() => + execFileSync(process.execPath, [script, '--evidence-root', path.join(root, 'evidence')], { + env: process.env, + stdio: 'pipe', + }), + ).toThrow(); + }); +}); + +test('native origin rejects tampered downloaded archives and local evidence bytes', async () => { + await fixture(async (root) => { + await expect( + authenticateNativeBuildEvidence(path.join(root, 'evidence'), expected), + ).rejects.toThrow(/ZIP identity mismatch/); + expect(readFileSync(path.join(root, 'download-count'), 'utf8')).toBe('2'); + }, 'digest'); + await fixture(async (root) => { + writeFileSync( + path.join(root, 'evidence/native-build-evidence.json'), + JSON.stringify({ tampered: true }), + ); + await expect( + authenticateNativeBuildEvidence(path.join(root, 'evidence'), expected), + ).rejects.toThrow(/bytes differ/); + }); +}); + +test('controller authenticates transported final bytes from the exact artifact and rejects local or supplier substitution', async () => { + await fixture(async (root) => { + const f = syntheticReviewedProducer(); + const evidenceRoot = path.join(root, 'evidence'); + const output = f.origin.evidence.cohorts[0].outputs[0].path; + const transported = path.join(evidenceRoot, 'files/0', output); + mkdirSync(path.dirname(transported), { recursive: true }); + writeFileSync(transported, 'synthetic public archive'); + writeFileSync( + path.join(evidenceRoot, 'native-build-evidence.json'), + JSON.stringify(f.origin.evidence), + ); + const archive = () => { + rmSync(path.join(root, 'artifact.zip')); + execFileSync( + 'zip', + ['-qr', path.join(root, 'artifact.zip'), 'native-build-evidence.json', 'files'], + { cwd: evidenceRoot }, + ); + }; + archive(); + const origin = await authenticateNativeBuildEvidence(evidenceRoot, expected); + expect(origin.finalFiles?.scope).toBe('construction'); + expect(origin.finalFiles?.files).toEqual([ + { + cohort: 0, + path: output, + size: Buffer.byteLength('synthetic public archive'), + sha256: createHash('sha256').update('synthetic public archive').digest('hex'), + }, + ]); + expect(origin.finalFiles?.artifactRoots).toEqual([transported]); + const qualification = origin.finalFiles?.qualification; + const context = { ...expected, bazelVersion: f.request.bazelVersion }; + expect(validateAuthenticatedNativeBuildEvidence(origin, context)).toBe(qualification); + expect( + validateAuthenticatedNativeBuildEvidence(origin, { + ...context, + requireShippingAnalysis: true, + }), + ).toBe(qualification); + for (const changed of [ + { source: { ...expected.source, commit: 'e'.repeat(40) } }, + { source: { ...expected.source, tree: 'e'.repeat(40) } }, + { github: { ...expected.github, runAttempt: 2 } }, + { github: { ...expected.github, job: 'Other producer' } }, + ]) + expect(() => + validateAuthenticatedNativeBuildEvidence(origin, { ...context, ...changed }), + ).toThrow(); + const replay = validateAuthenticatedNativeBuildEvidence(origin, { + ...context, + requiredTests: f.request.requiredTests, + }); + expect(replay).not.toBe(qualification); + expect(replay.testQualification).toBe('passed'); + expect(() => + validateAuthenticatedNativeBuildEvidence(origin, { ...context, requiredTests: [] }), + ).toThrow('nonempty unique'); + expect( + validateAuthenticatedNativeBuildEvidence(Object.freeze({ ...origin }), context), + ).not.toBe(qualification); + expect(() => + validateAuthenticatedNativeBuildEvidence( + { ...origin, evidence: { synthetic: true } }, + context, + ), + ).toThrow(); + writeFileSync(transported, 'local substitution'); + expect(() => assertAuthenticatedNativeBuildOrigin(origin)).toThrow(); + await expect(authenticateNativeBuildEvidence(evidenceRoot, expected)).rejects.toThrow( + 'native final transport bytes', + ); + // Authenticating the ZIP does not authorize bytes that contradict its evidence. + archive(); + await expect(authenticateNativeBuildEvidence(evidenceRoot, expected)).rejects.toThrow( + 'native final transport bytes', + ); + writeFileSync(transported, 'synthetic public archive'); + archive(); + rmSync(path.join(evidenceRoot, 'files'), { recursive: true }); + await expect(authenticateNativeBuildEvidence(evidenceRoot, expected)).rejects.toThrow( + 'final file transport differ', + ); + }); +}); + +test('authenticated qualification retains unbound shipping and explicit cross-cohort test checks', async () => { + await fixture(async (root) => { + const f = syntheticReviewedProducer(); + delete f.origin.evidence.cohorts[0].producerCapture; + const second = structuredClone(f.origin.evidence.cohorts[0]); + const started = second.buildEvents.find((event) => event.started); + if (!started) throw new Error('synthetic fixture requires its started event'); + started.started.uuid = 'second-synthetic-invocation'; + f.origin.evidence.cohorts.push(second); + const directory = path.join(root, 'evidence'); + for (const [index, cohort] of f.origin.evidence.cohorts.entries()) { + const file = path.join(directory, 'files', String(index), cohort.outputs[0].path); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, 'synthetic public archive'); + } + writeFileSync( + path.join(directory, 'native-build-evidence.json'), + JSON.stringify(f.origin.evidence), + ); + rmSync(path.join(root, 'artifact.zip')); + execFileSync( + 'zip', + ['-qr', path.join(root, 'artifact.zip'), 'native-build-evidence.json', 'files'], + { cwd: directory }, + ); + const origin = await acquireAuthenticatedNativeBuildEvidence( + path.join(root, 'acquired'), + expected, + ); + const context = { ...expected, bazelVersion: f.request.bazelVersion }; + expect(validateAuthenticatedNativeBuildEvidence(origin, context)).toBe( + origin.finalFiles?.qualification, + ); + expect(() => + validateAuthenticatedNativeBuildEvidence(origin, { + ...context, + requireShippingAnalysis: true, + }), + ).toThrow('producing-analysis shipping manifests'); + expect(() => + validateAuthenticatedNativeBuildEvidence(origin, { + ...context, + requiredTests: f.request.requiredTests, + }), + ).toThrow('found 2'); + }); +}); + +test('historical producer transport uses its authenticated version while current qualification retains its explicit pin', async () => { + await fixture(async (root) => { + const f = syntheticReviewedProducer(); + const current = readFileSync(new URL('../../.bazelversion', import.meta.url), 'utf8').trim(); + const historical = current === '8.7.0' ? '8.6.0' : '8.7.0'; + const started = f.origin.evidence.cohorts[0].buildEvents.find( + (event: any) => event.started, + ) as any; + started.started.buildToolVersion = historical; + const directory = path.join(root, 'evidence'); + const output = f.origin.evidence.cohorts[0].outputs[0].path; + const file = path.join(directory, 'files/0', output); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, 'synthetic public archive'); + writeFileSync( + path.join(directory, 'native-build-evidence.json'), + JSON.stringify(f.origin.evidence), + ); + rmSync(path.join(root, 'artifact.zip')); + execFileSync( + 'zip', + ['-qr', path.join(root, 'artifact.zip'), 'native-build-evidence.json', 'files'], + { cwd: directory }, + ); + const origin = await authenticateNativeBuildEvidence(directory, expected); + expect(origin.finalFiles?.artifactRoots).toEqual([file]); + expect(() => + validateAuthenticatedNativeBuildEvidence(origin, { ...expected, bazelVersion: historical }), + ).not.toThrow(); + expect(() => + validateAuthenticatedNativeBuildEvidence(origin, { ...expected, bazelVersion: current }), + ).toThrow('native BEP Bazel version mismatch'); + }); +}); diff --git a/tools/release/bazel-8.8.1/analysis_v2.proto b/tools/release/bazel-8.8.1/analysis_v2.proto new file mode 100644 index 000000000..89ad91c41 --- /dev/null +++ b/tools/release/bazel-8.8.1/analysis_v2.proto @@ -0,0 +1,294 @@ +// Copyright 2018 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package analysis; + +import "src/main/protobuf/build.proto"; + +option java_package = "com.google.devtools.build.lib.analysis"; +option java_outer_classname = "AnalysisProtosV2"; + +// Container for the action graph properties. +message ActionGraphContainer { + repeated Artifact artifacts = 1; + repeated Action actions = 2; + repeated Target targets = 3; + repeated DepSetOfFiles dep_set_of_files = 4; + repeated Configuration configuration = 5; + repeated AspectDescriptor aspect_descriptors = 6; + repeated RuleClass rule_classes = 7; + repeated PathFragment path_fragments = 8; +} + +// Represents a single artifact, whether it's a source file or a derived output +// file. +message Artifact { + // Identifier for this artifact; this is a uint32, only valid for this + // particular dump of the analysis. + uint32 id = 1; + + // The id of the PathFragment that represents the relative path of the file + // within the execution root. + uint32 path_fragment_id = 2; + + // True iff the artifact is a tree artifact, i.e. the above exec_path refers + // a directory. + bool is_tree_artifact = 3; +} + +// Represents a single action, which is a function from Artifact(s) to +// Artifact(s). +message Action { + // The target that was responsible for the creation of the action. + uint32 target_id = 1; + + // The aspects that were responsible for the creation of the action (if any). + // In the case of aspect-on-aspect, AspectDescriptors are listed in + // topological order of the dependency graph. + // e.g. [A, B] would imply that aspect A is applied on top of aspect B. + repeated uint32 aspect_descriptor_ids = 2; + + // Encodes all significant behavior that might affect the output. The key + // must change if the work performed by the execution of this action changes. + // Note that the key doesn't include checksums of the input files. + string action_key = 3; + + // The mnemonic for this kind of action. + string mnemonic = 4; + + // The configuration under which this action is executed. + uint32 configuration_id = 5; + + // The command line arguments of the action. This will be only set if + // explicitly requested. + repeated string arguments = 6; + + // The list of environment variables to be set before executing the command. + repeated KeyValuePair environment_variables = 7; + + // The set of input dep sets that the action depends upon. If the action does + // input discovery and `--include_pruned_outputs` is disabled, the contents of + // this set might differ before and after execution. + repeated uint32 input_dep_set_ids = 8; + + // The list of Artifact IDs that represent the output files that this action + // will generate. + repeated uint32 output_ids = 9; + + // True iff the action does input discovery during execution. + bool discovers_inputs = 10; + + // Execution info for the action. Remote execution services may use this + // information to modify the execution environment, but actions will + // generally not be aware of it. + repeated KeyValuePair execution_info = 11; + + // The list of param files. This will be only set if explicitly requested. + repeated ParamFile param_files = 12; + + // The id to an Artifact that is the primary output of this action. + uint32 primary_output_id = 13; + + // The execution platform for this action. Empty if the action has no + // execution platform. + string execution_platform = 14; + + // The template content of the action, if it is TemplateExpand action. + string template_content = 15; + + // The list of substitution should be performed on the template. The key is + // the string to be substituted and the value is the string to be substituted + // to. + repeated KeyValuePair substitutions = 16; + + // The contents of the file for the ctx.actions.write() action + // (guarded by the --include_file_write_contents flag). + string file_contents = 17; + + // The target of the symlink created by UnresolvedSymlink actions. + // For regular Symlink actions, the target is represented as an input. + string unresolved_symlink_target = 18; + + // If FileWrite actions should make their output executable. + // (ctx.actions.write(is_executable=True)) + bool is_executable = 19; + + reserved 20; +} + +// Represents a single target (without configuration information) that is +// associated with an action. +message Target { + // Identifier for this target; this is a uint32, only valid for this + // particular dump of the analysis. + uint32 id = 1; + + // Label of the target, e.g. //foo:bar. + string label = 2; + + // Class of the rule. + uint32 rule_class_id = 3; +} + +message RuleClass { + // Identifier for this rule class; this is a uint32, only valid for + // this particular dump of the analysis. + uint32 id = 1; + + // Name of the rule class, e.g. cc_library. + string name = 2; +} + +// Represents an invocation specific descriptor of an aspect. +message AspectDescriptor { + // Identifier for this aspect descriptor; this is a uint32, only valid + // for the particular dump of the analysis. + uint32 id = 1; + + // The name of the corresponding aspect. For native aspects, it's the Java + // class name, for Starlark aspects it's the bzl file followed by a % sign + // followed by the name of the aspect. + string name = 2; + + // The list of parameters bound to a particular invocation of that aspect on + // a target. Note that aspects can be executed multiple times on the same + // target in different order. + repeated KeyValuePair parameters = 3; +} + +message DepSetOfFiles { + // Identifier for this named set of files; this is a uint32, only + // valid for the particular dump of the analysis. + uint32 id = 1; + + // Other transitively included named set of files. + repeated uint32 transitive_dep_set_ids = 2; + + // The list of input artifact IDs that are immediately contained in this set. + repeated uint32 direct_artifact_ids = 3; +} + +message Configuration { + // Identifier for this configuration; this is a uint32, only valid for + // the particular dump of the analysis. + uint32 id = 1; + + // The mnemonic representing the build configuration. + string mnemonic = 2; + + // The platform string. + string platform_name = 3; + + // The checksum representation of the configuration options; + string checksum = 4; + + // Whether this configuration is used for building tools. + bool is_tool = 5; + + // The configuration fragments that are a part of this configuration. + repeated Fragment fragments = 6; + + // The union of all the FragmentOptions associated with the Fragments that are + // a part of this configuration. These are returned separately from the + // fragments field because a set of FragmentOptions can be referenced by more + // than one Fragment, and we wish to avoid returning the same FragmentOptions + // repeatedly. These are sorted by the FragmentOptions name field. + repeated FragmentOptions fragment_options = 7; +} + +// A configuration fragment +// (http://bazel.build/rules/lib/fragments). +message Fragment { + // The name of the Fragment. + string name = 1; + + // The names of the FragmentOptions associated with this fragment in sorted + // order. + repeated string fragment_option_names = 2; +} + +// A set of fragment options. +message FragmentOptions { + // The name of this set of fragment options. + string name = 1; + + // The options themselves, in sorted order by name. + repeated Option options = 2; +} + +// A fragment option. +message Option { + // The name of the option. + optional string name = 1; + + // The value of the option. + optional string value = 2; +} + +message KeyValuePair { + // The variable name. + string key = 1; + + // The variable value. + string value = 2; +} + +message ConfiguredTarget { + // The target. We use blaze_query.Target defined in build.proto instead of + // the Target defined in this file because blaze_query.Target is much heavier + // and will output proto results similar to what users are familiar with from + // regular blaze query. + blaze_query.Target target = 1; + + // DEPRECATED. Use configuration_id instead. + Configuration configuration = 2 [deprecated = true]; + + // The id of the configuration this target is configured for. The actual + // Configuration message can be found in CqueryResults. If the target doesn't + // have a configuration, the value will be 0. + uint32 configuration_id = 3; +} + +// Container for cquery results +message CqueryResult { + // All the configuredtargets returns by cquery + repeated ConfiguredTarget results = 1; + + // All the Configurations referenced by results. + repeated Configuration configurations = 2; +} + +// Content of a param file. +message ParamFile { + // The exec path of the param file artifact. + string exec_path = 1; + + // The arguments in the param file. + // Each argument corresponds to a line in the param file. + repeated string arguments = 2; +} + +// The path fragment that makes up a full path. +message PathFragment { + // Identifier for this path fragment. + uint32 id = 1; + + // The label of the section in the path. + string label = 2; + + // The id of the parent path fragment. + uint32 parent_id = 3; +} diff --git a/tools/release/bazel-8.8.1/build.proto b/tools/release/bazel-8.8.1/build.proto new file mode 100644 index 000000000..e665f5e7d --- /dev/null +++ b/tools/release/bazel-8.8.1/build.proto @@ -0,0 +1,601 @@ +// Copyright 2014 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This file contains the protocol buffer representation of a build +// file or 'blaze query --output=proto' call. + +syntax = "proto2"; + +package blaze_query; + +import "src/main/protobuf/stardoc_output.proto"; + +// option cc_api_version = 2; +// option java_api_version = 1; +option java_package = "com.google.devtools.build.lib.query2.proto.proto2api"; + +message License { + repeated string license_type = 1; + repeated string exception = 2; +} + +message StringDictEntry { + required string key = 1; + required string value = 2; +} + +message LabelDictUnaryEntry { + required string key = 1; + required string value = 2; +} + +message LabelListDictEntry { + required string key = 1; + repeated string value = 2; +} + +message LabelKeyedStringDictEntry { + required string key = 1; + required string value = 2; +} + +message StringListDictEntry { + required string key = 1; + repeated string value = 2; +} + +// Represents an entry attribute of a Fileset rule in a build file. +message FilesetEntry { + // Indicates what to do when a source file is actually a symlink. + enum SymlinkBehavior { + COPY = 1; + DEREFERENCE = 2; + } + + // The label pointing to the source target where files are copied from. + required string source = 1; + + // The relative path within the fileset rule where files will be mapped. + required string destination_directory = 2; + + // Whether the files= attribute was specified. This is necessary because + // no files= attribute and files=[] mean different things. + optional bool files_present = 7; + + // A list of file labels to include from the source directory. + repeated string file = 3; + + // If this is a fileset entry representing files within the rule + // package, this lists relative paths to files that should be excluded from + // the set. This cannot contain values if 'file' also has values. + repeated string exclude = 4; + + // This field is optional because there will be some time when the new + // PB is used by tools depending on blaze query, but the new blaze version + // is not yet released. + // TODO(bazel-team): Make this field required once a version of Blaze is + // released that outputs this field. + optional SymlinkBehavior symlink_behavior = 5 [default = COPY]; + + // The prefix to strip from the path of the files in this FilesetEntry. Note + // that no value and the empty string as the value mean different things here. + optional string strip_prefix = 6; +} + +// A rule attribute. Each attribute must have a type and one of the various +// value fields populated - for the most part. +// +// Attributes of BOOLEAN and TRISTATE type may set all of the int, bool, and +// string values for backwards compatibility with clients that expect them to +// be set. +// +// Attributes of INTEGER, STRING, LABEL, LICENSE, BOOLEAN, and TRISTATE type +// may set *none* of the values. This can happen if the Attribute message is +// prepared for a client that doesn't support SELECTOR_LIST, but the rule has +// a selector list value for the attribute. (Selector lists for attributes of +// other types--the collection types--are handled differently when prepared +// for such a client. The possible collection values are gathered together +// and flattened.) +// +// By checking the type, the appropriate value can be extracted - see the +// comments on each type for the associated value. The order of lists comes +// from the blaze parsing. If an attribute is of a list type, the associated +// list should never be empty. +message Attribute { + reserved 12, 16; + + // Indicates the type of attribute. + enum Discriminator { + INTEGER = 1; // int_value + STRING = 2; // string_value + LABEL = 3; // string_value + OUTPUT = 4; // string_value + STRING_LIST = 5; // string_list_value + LABEL_LIST = 6; // string_list_value + OUTPUT_LIST = 7; // string_list_value + DISTRIBUTION_SET = 8; // string_list_value - order is unimportant + LICENSE = 9; // license + STRING_DICT = 10; // string_dict_value + FILESET_ENTRY_LIST = 11; // fileset_list_value + LABEL_LIST_DICT = 12; // label_list_dict_value + STRING_LIST_DICT = 13; // string_list_dict_value + BOOLEAN = 14; // int, bool and string value + TRISTATE = 15; // tristate, int and string value + INTEGER_LIST = 16; // int_list_value + UNKNOWN = 18; // unknown type, use only for build extensions + LABEL_DICT_UNARY = 19; // label_dict_unary_value + SELECTOR_LIST = 20; // selector_list + LABEL_KEYED_STRING_DICT = 21; // label_keyed_string_dict + + DEPRECATED_STRING_DICT_UNARY = 17; + } + + // Values for the TriState field type. + enum Tristate { + NO = 0; + YES = 1; + AUTO = 2; + } + + message SelectorEntry { + reserved 12; + + // The key of the selector entry. At this time, this is the label of a + // config_setting rule, or the pseudo-label "//conditions:default". + optional string label = 1; + + // True if the entry's value is the default value for the type as a + // result of the condition value being specified as None (ie: + // {"//condition": None}). + optional bool is_default_value = 16; + + // Exactly one of the following fields (except for glob_criteria) must be + // populated - note that the BOOLEAN and TRISTATE caveat in Attribute's + // comment does not apply here. The type field in the SelectorList + // containing this entry indicates which of these fields is populated, + // in accordance with the comments on Discriminator enum values above. + // (To be explicit: BOOLEAN populates the boolean_value field and TRISTATE + // populates the tristate_value field.) + optional int32 int_value = 2; + optional string string_value = 3; + optional bool boolean_value = 4; + optional Tristate tristate_value = 5; + repeated string string_list_value = 6; + optional License license = 7; + repeated StringDictEntry string_dict_value = 8; + repeated FilesetEntry fileset_list_value = 9; + repeated LabelListDictEntry label_list_dict_value = 10; + repeated StringListDictEntry string_list_dict_value = 11; + repeated int32 int_list_value = 13; + repeated LabelDictUnaryEntry label_dict_unary_value = 15; + repeated LabelKeyedStringDictEntry label_keyed_string_dict_value = 17; + + repeated bytes DEPRECATED_string_dict_unary_value = 14; + } + + message Selector { + // The list of (label, value) pairs in the map that defines the selector. + // At this time, this cannot be empty, i.e. a selector has at least one + // entry. + repeated SelectorEntry entries = 1; + + // Whether or not this has any default values. + optional bool has_default_value = 2; + + // The error message when no condition matches. + optional string no_match_error = 3; + } + + message SelectorList { + // The type that this selector list evaluates to, and the type that each + // selector in the list evaluates to. At this time, this cannot be + // SELECTOR_LIST, i.e. selector lists do not nest. + optional Discriminator type = 1; + + // The list of selector elements in this selector list. At this time, this + // cannot be empty, i.e. a selector list is never empty. + repeated Selector elements = 2; + } + + // The name of the attribute + required string name = 1; + + // Whether the attribute was explicitly specified + optional bool explicitly_specified = 13; + + // If this attribute has a string value or a string list value, then this + // may be set to indicate that the value may be treated as a label that + // isn't a dependency of this attribute's rule. + optional bool nodep = 20; + + // Represents the aspect that this attribute comes from. It is set to an + // empty string if it does not come from an aspect. + optional string source_aspect_name = 23; + + // The type of attribute. This message is used for all of the different + // attribute types so the discriminator helps for figuring out what is + // stored in the message. + required Discriminator type = 2; + + // If this attribute has an integer value this will be populated. + // Boolean and TriState also use this field as [0,1] and [-1,0,1] + // for [false, true] and [auto, no, yes] respectively. + optional int32 int_value = 3; + + // If the attribute has a string value this will be populated. Label and + // path attributes use this field as the value even though the type may + // be LABEL or something else other than STRING. + optional string string_value = 5; + + // If the attribute has a boolean value this will be populated. + optional bool boolean_value = 14; + + // If the attribute is a Tristate value, this will be populated. + optional Tristate tristate_value = 15; + + // The value of the attribute has a list of string values (label and path + // note from STRING applies here as well). + repeated string string_list_value = 6; + + // If this is a license attribute, the license information is stored here. + optional License license = 7; + + // If this is a string dict, each entry will be stored here. + repeated StringDictEntry string_dict_value = 8; + + // If the attribute is part of a Fileset, the fileset entries are stored in + // this field. + repeated FilesetEntry fileset_list_value = 9; + + // If this is a label list dict, each entry will be stored here. + repeated LabelListDictEntry label_list_dict_value = 10; + + // If this is a string list dict, each entry will be stored here. + repeated StringListDictEntry string_list_dict_value = 11; + + // The value of the attribute has a list of int32 values + repeated int32 int_list_value = 17; + + // If this is a label dict unary, each entry will be stored here. + repeated LabelDictUnaryEntry label_dict_unary_value = 19; + + // If this is a label-keyed string dict, each entry will be stored here. + repeated LabelKeyedStringDictEntry label_keyed_string_dict_value = 22; + + // If this attribute's value is an expression containing one or more select + // expressions, then its type is SELECTOR_LIST and a SelectorList will be + // stored here. + optional SelectorList selector_list = 21; + + repeated bytes DEPRECATED_string_dict_unary_value = 18; +} + +// A rule instance (e.g., cc_library foo, java_binary bar). +message Rule { + reserved 8, 11; + + // The name of the rule (formatted as an absolute label, e.g. //foo/bar:baz). + required string name = 1; + + // The rule class name (e.g., java_library). + // + // Note that the rule class name may not uniquely identify a rule class, since + // two different .bzl files may define different rule classes with the same + // name. To uniquely identify the rule class, see rule_class_key field below. + required string rule_class = 2; + + // The BUILD file and line number of the location (formatted as + // ::) in the rule's package's + // BUILD file where the rule instance was instantiated. The line number will + // be that of a rule invocation or macro call (that in turn invoked a + // rule). See + // https://bazel.build/rules/macros#macro-creation + optional string location = 3; + + // All of the attributes that describe the rule. + repeated Attribute attribute = 4; + + // All of the inputs to the rule (formatted as absolute labels). These are + // predecessors in the dependency graph. + repeated string rule_input = 5; + + repeated ConfiguredRuleInput configured_rule_input = 15; + + // All of the outputs of the rule (formatted as absolute labels). These are + // successors in the dependency graph. + repeated string rule_output = 6; + + // The set of all "features" inherited from the rule's package declaration. + repeated string default_setting = 7; + + // The rule's class's public by default value. + optional bool DEPRECATED_public_by_default = 9; + + optional bool DEPRECATED_is_skylark = 10; + + // Hash encapsulating the behavior of this Starlark rule. Any change to this + // rule's definition that could change its behavior will be reflected here. + optional string skylark_environment_hash_code = 12; + + // The Starlark call stack at the moment the rule was instantiated. + // Each entry has the form "file:line:col: function". + // The outermost stack frame ("", the BUILD file) appears first; + // the frame for the rule function itself is omitted. + // The file name may be relative to package's source root directory. + // + // Requires --proto:instantiation_stack=true. + repeated string instantiation_stack = 13; + + // The Starlark call stack for the definition of the rule class of this + // particular rule instance. If empty, either populating the field was not + // enabled on the command line with the --proto:definition_stack flag or the + // rule is a native one. + repeated string definition_stack = 14; + + // A key uniquely identifying the rule's rule class. Stable between repeated + // blaze query invocations (assuming that there are no changes to Starlark + // files and the same blaze binary is invoked with the same options). + // + // Requires --proto:rule_classes=true + optional string rule_class_key = 16; + + // Stardoc-format rule class API definition for this rule. Includes both + // Starlark-defined and native (including inherited) attributes; does not + // include hidden or explicitly undocumented attributes. + // + // Populated only for the first rule in the stream with a given + // rule_class_key. + // + // Requires --proto:rule_classes=true + optional stardoc_output.RuleInfo rule_class_info = 17; +} + +// A Bazel repository, either representing a module, or created by a module +// extension. +message Repository { + // The canonical name of the repository. + optional string canonical_name = 1; + + // The name of the repository rule (e.g., http_archive). + optional string repo_rule_name = 2; + + // The canonical label of the bzl file that defined the repository rule. + optional string repo_rule_bzl_label = 3; + + // The apparent name of the repository, as visible to --base_module. + optional string apparent_name = 4; + + // If this repository is a module (not created by a module extension), + // this is the module key. + optional string module_key = 5; + + // Original name in the repo as created by a module extension. + optional string original_name = 6; + + // All of the attributes that describe the repository rule. + repeated Attribute attribute = 7; +} + +// Direct dependencies of a rule in form. +message ConfiguredRuleInput { + // Dep's target label. + optional string label = 1; + // Dep's configuration if the dep isn't a source file, else unset. + optional string configuration_checksum = 2; + // Reference to this dep's configuration if --proto:include_configurations is + // set: see + // https://github.com/bazelbuild/bazel/blob/7278be3f9b0c26842ecb8225f0215c1e4aede5a9/src/main/protobuf/analysis_v2.proto#L189. + // If this dep is a source file, this is unset. + optional uint32 configuration_id = 3; +} + +// Summary of all transitive dependencies of 'rule,' where each dependent +// rule is included only once in the 'dependency' field. Gives complete +// information to analyze the single build target labeled rule.name, +// including optional location of target in BUILD file. +message RuleSummary { + required Rule rule = 1; + repeated Rule dependency = 2; + optional string location = 3; +} + +// A package group. Aside from the name, it contains the list of packages +// present in the group (as specified in the BUILD file). +message PackageGroup { + reserved 4; + + // The name of the package group + required string name = 1; + + // The list of packages as specified in the BUILD file. Currently this is + // only a list of packages, but some time in the future, there might be + // some type of wildcard mechanism. + repeated string contained_package = 2; + + // The list of sub package groups included in this one. + repeated string included_package_group = 3; +} + +// An environment group. +message EnvironmentGroup { + // The name of the environment group. + required string name = 1; + + // The environments that belong to this group (as labels). + repeated string environment = 2; + + // The member environments that rules implicitly support if not otherwise + // specified. + repeated string default = 3; +} + +// A file that is an input into the build system. +// Next-Id: 10 +message SourceFile { + reserved 7; + + // The name of the source file (a label). + required string name = 1; + + // The location of the source file. This is a path with a line number and a + // column number not a label in the build system. + optional string location = 2; + + // Labels of .bzl (Starlark) files that are transitively loaded in this BUILD + // file. This is present only when the SourceFile represents a BUILD file that + // loaded .bzl files. + // TODO(bazel-team): Rename this field. + repeated string subinclude = 3; + + // Labels of package groups that are mentioned in the visibility declaration + // for this source file. + repeated string package_group = 4; + + // Labels mentioned in the visibility declaration (including :__pkg__ and + // //visibility: ones) + repeated string visibility_label = 5; + + // The package-level features enabled for this package. Only present if the + // SourceFile represents a BUILD file. + repeated string feature = 6; + + // License attribute for the file. + optional License license = 8; + + // True if the package contains an error. Only present if the SourceFile + // represents a BUILD file. + optional bool package_contains_errors = 9; +} + +// A file that is the output of a build rule. +message GeneratedFile { + // The name of the generated file (a label). + required string name = 1; + + // The label of the target that generates the file. + required string generating_rule = 2; + + // The path, line number, and column number of the output file (not a label). + optional string location = 3; +} + +// A target from a blaze query execution. Similar to the Attribute message, +// the Discriminator is used to determine which field contains information. +// For any given type, only one of these can be populated in a single Target. +message Target { + enum Discriminator { + RULE = 1; + SOURCE_FILE = 2; + GENERATED_FILE = 3; + PACKAGE_GROUP = 4; + ENVIRONMENT_GROUP = 5; + } + + // The type of target contained in the message. + required Discriminator type = 1; + + // If this target represents a rule, the rule is stored here. + optional Rule rule = 2; + + // A file that is not generated by the build system (version controlled + // or created by the test harness). + optional SourceFile source_file = 3; + + // A generated file that is the output of a rule. + optional GeneratedFile generated_file = 4; + + // A package group. + optional PackageGroup package_group = 5; + + // An environment group. + optional EnvironmentGroup environment_group = 6; +} + +// Container for all of the blaze query results. +message QueryResult { + // All of the targets returned by the blaze query. + repeated Target target = 1; +} + +//////////////////////////////////////////////////////////////////////////// +// Messages dealing with querying the BUILD language itself. For now, this is +// quite simplistic: Blaze can only tell the names of the rule classes, their +// attributes with their type. + +// Information about allowed rule classes for a specific attribute of a rule. +message AllowedRuleClassInfo { + enum AllowedRuleClasses { + ANY = 1; // Any rule is allowed to be in this attribute + SPECIFIED = 2; // Only the explicitly listed rules are allowed + } + + required AllowedRuleClasses policy = 1; + + // Rule class names of rules allowed in this attribute, e.g "cc_library", + // "py_binary". Only present if the allowed_rule_classes field is set to + // SPECIFIED. + repeated string allowed_rule_class = 2; +} + +// This message represents a single attribute of a single rule. +// See https://bazel.build/rules/lib/attr. +message AttributeDefinition { + required string name = 1; // e.g. "name", "srcs" + required Attribute.Discriminator type = 2; + optional bool mandatory = 3; + optional AllowedRuleClassInfo allowed_rule_classes = 4; // type=label* + optional string documentation = 5; + optional bool allow_empty = 6; // type=*_list|*_dict + optional bool allow_single_file = 7; // type=label + optional AttributeValue default = + 9; // simple (not computed/late-bound) values only + optional bool executable = 10; // type=label + optional bool configurable = 11; + optional bool nodep = + 12; // label-valued edge does not establish a dependency + optional bool cfg_is_host = + 13; // edge entails a transition to "host" configuration +} + +// An AttributeValue represents the value of an attribute. +// A single field, determined by the attribute type, is populated. +// +// It is used only for AttributeDefinition.default. Attribute and +// SelectorEntry do their own thing for unfortunate historical reasons. +message AttributeValue { + optional int32 int = 1; // type=int|tristate + optional string string = 2; // type=string|label|output + optional bool bool = 3; // type=bool + repeated AttributeValue list = 4; // type=*_list|distrib + repeated DictEntry dict = 5; // type=*_dict + + message DictEntry { + required string key = 1; + required AttributeValue value = 2; + } +} + +message RuleDefinition { + required string name = 1; + // Only contains documented attributes + repeated AttributeDefinition attribute = 2; + optional string documentation = 3; + // Only for build extensions: label to file that defines the extension + optional string label = 4; +} + +message BuildLanguage { + // Only contains documented rule definitions + repeated RuleDefinition rule = 1; +} diff --git a/tools/release/bazel-8.8.1/sources.json b/tools/release/bazel-8.8.1/sources.json new file mode 100644 index 000000000..41cc1422c --- /dev/null +++ b/tools/release/bazel-8.8.1/sources.json @@ -0,0 +1,26 @@ +{ + "bazelVersion": "8.8.1", + "files": [ + { + "file": "analysis_v2.proto", + "url": "https://raw.githubusercontent.com/bazelbuild/bazel/8.8.1/src/main/protobuf/analysis_v2.proto", + "sha256": "2dc3deb978de08a4cd6b95b824b4c2d1801dbf945ab332877c419495b59e908c", + "size": 9625, + "license": "Apache-2.0" + }, + { + "file": "build.proto", + "url": "https://raw.githubusercontent.com/bazelbuild/bazel/8.8.1/src/main/protobuf/build.proto", + "sha256": "5041f18adb0507f0d85ddb2c8ecf62d0cf148c8506dd4cdaff051a40cc4ecd96", + "size": 22263, + "license": "Apache-2.0" + }, + { + "file": "stardoc_output.proto", + "url": "https://raw.githubusercontent.com/bazelbuild/bazel/8.8.1/src/main/protobuf/stardoc_output.proto", + "sha256": "515d7657c0a57903058d6c59cf2f2ac815fc92557bfd3e4856ac96d6e2cf55c0", + "size": 14574, + "license": "Apache-2.0" + } + ] +} diff --git a/tools/release/bazel-8.8.1/stardoc_output.proto b/tools/release/bazel-8.8.1/stardoc_output.proto new file mode 100644 index 000000000..c258ea56f --- /dev/null +++ b/tools/release/bazel-8.8.1/stardoc_output.proto @@ -0,0 +1,418 @@ +// Copyright 2019 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Protos for Stardoc data. +// +// Stardoc collects information about Starlark functions, providers, and rules. +syntax = "proto3"; + +package stardoc_output; + +// option java_api_version = 2; +option java_package = "com.google.devtools.build.lib.starlarkdocextract"; +option java_outer_classname = "StardocOutputProtos"; + +// The root output proto of Stardoc. An invocation of Stardoc on a single file +// will output exactly one instance of this proto, representing all +// documentation for the input Starlark file. +message ModuleInfo { + repeated RuleInfo rule_info = 1; + + repeated ProviderInfo provider_info = 2; + + repeated StarlarkFunctionInfo func_info = 3; + + repeated AspectInfo aspect_info = 4; + + // The docstring present at the top of the input Starlark file. + string module_docstring = 5; + + // The display form of the label of the module file (as seen from the + // starlark_doc_extract or Stardoc target's repo). Unset when there is no + // module file (e.g. when the module is a REPL, or in Bazel's internal tests). + string file = 6; + + repeated ModuleExtensionInfo module_extension_info = 7; + + repeated RepositoryRuleInfo repository_rule_info = 8; + + repeated MacroInfo macro_info = 9; +} + +// Representation of a Starlark rule attribute type. These generally +// have a one-to-one correspondence with functions defined at +// https://bazel.build/rules/lib/attr. +enum AttributeType { + UNKNOWN = 0; + // A special case of STRING; all rules have exactly one implicit + // attribute "name" of type NAME. + NAME = 1; + INT = 2; + LABEL = 3; + STRING = 4; + STRING_LIST = 5; + INT_LIST = 6; + LABEL_LIST = 7; + BOOLEAN = 8; + LABEL_STRING_DICT = 9; + STRING_DICT = 10; + STRING_LIST_DICT = 11; + OUTPUT = 12; + OUTPUT_LIST = 13; + LABEL_DICT_UNARY = 14; +} + +// Representation of a Starlark rule definition. +message RuleInfo { + // In Stardoc and starlark_doc_extract output, this is the name under which + // the rule is made accessible to a user of this module, including any structs + // it is nested in, for example "foo.foo_library". + // + // In query output, this is the name under which the rule was defined (which + // might be a private symbol prefixed with "_"). + string rule_name = 1; + + // The documentation string of the rule. + string doc_string = 2; + + // The attributes of the rule. + repeated AttributeInfo attribute = 3; + + // Note: legacy Stardoc (0.5.x and earlier) does not set any fields below. + + // The module where and the name under which the rule was originally declared. + OriginKey origin_key = 4; + + // The list of providers that the rule's implementation must return. Unset if + // the rule lists no advertised providers. + ProviderNameGroup advertised_providers = 5; + + // True if this is a test rule. + bool test = 6; + + // True if this is an executable rule. + // + // Note: if test is true, executable is also true (test rules are implicitly + // executable). + bool executable = 7; +} + +// Representation of a Starlark symbolic macro definition. +// Note: symbolic macros (and thus, their documentation format) are an +// experimental feature gated by the --experimental_enable_first_class_macros +// flag. +message MacroInfo { + // The name under which the macro is made accessible to a user of this module, + // including any structs it is nested in, for example "foo.foo_library". + string macro_name = 1; + + // The documentation string of the macro. + string doc_string = 2; + + // The attributes of the macro. + repeated AttributeInfo attribute = 3; + + // The module where and the name under which the macro was originally + // declared. + OriginKey origin_key = 4; + + // True if this macro is a rule finalizer. + bool finalizer = 5; +} + +// Representation of a Starlark rule, repository rule, or module extension tag +// attribute definition, comprised of an attribute name, and a schema defined by +// a call to one of the 'attr' module methods enumerated at +// https://bazel.build/rules/lib/attr +message AttributeInfo { + // The name of the attribute. + string name = 1; + + // The documentation string of the attribute, supplied via the 'doc' + // parameter to the schema-creation call. + string doc_string = 2; + + // The type of the attribute, defined generally by which function is invoked + // in the attr module. + AttributeType type = 3; + + // If true, all targets of the rule must specify a value for this attribute. + bool mandatory = 4; + + // The target(s) in this attribute must define all the providers of at least + // one of the ProviderNameGroups in this list. If the Attribute Type is not a + // label, a label list, or a label-keyed string dictionary, the field will be + // left empty. For attributes of a repository rule or a module extension tag, + // this attribute is meaningless and may be ignored. + // TODO(b/290788853): ensure this field is always empty for attributes of a + // repository rule or a module extension tag. + repeated ProviderNameGroup provider_name_group = 5; + + // The string representation of the default value of this attribute. + string default_value = 6; + + // If true, the attribute is non-configurable. + bool nonconfigurable = 7; + + // If true, the attribute is defined in Bazel's native code, not in Starlark. + bool natively_defined = 8; + + // If non-empty, the string representations of the allowed values for this + // attribute. + repeated string values = 9; +} + +// Representation of a set of providers. +message ProviderNameGroup { + // The names of the providers. + // + // This field is only intended for rendering human-readable output. + // Please use origin_key (a list of the same length and in the same order as + // this field) for cross-references and tooling. + // + // Note: legacy Stardoc (0.5.x and earlier) is unable to extract the name in + // some circumstances (for example, if the provider is nested in a struct), + // and in that case, the provider name will be "Unknown Provider". + repeated string provider_name = 1; + + // A list of unambiguous references to providers, of the same length and in + // the same order as the provider_name list. + // + // For provider symbols, this means modules where and the names under which + // the providers were originally declared. + // + // For legacy struct providers, origin_key.file is unset. + // + // Note: legacy Stardoc (0.5.x and earlier) does not set this field. + repeated OriginKey origin_key = 2; +} + +// Representation of Starlark function definition. +message StarlarkFunctionInfo { + // The name under which the function is made accessible to a user of this + // module, including any structs it is nested in, for example + // "foo.frobnicate". + string function_name = 1; + + // The parameters for the function, in the following order: + // - positional parameters + // - keyword-only parameters + // - residual varargs parameter (`*args`) + // - residual keyword arguments parameter (`**kwargs`) + // This order differs from the order in which parameters are listed in the + // function's declaration (where positional parameters and keyword-only + // parameters are separated either by `*` or `*args`). The declaration order + // can be recovered by looking for the transition from ordinary/positional to + // keyword-only. + repeated FunctionParamInfo parameter = 2; + + // The documented description of the function (if specified in the function's + // docstring). + string doc_string = 3; + + // The return value for the function. + FunctionReturnInfo return = 4; + + // The deprecation for the function. + FunctionDeprecationInfo deprecated = 5; + + // The module where and the name under which the function was originally + // declared. + // + // Note: legacy Stardoc (0.5.x and earlier) does not set this field. + OriginKey origin_key = 6; +} + +// Representation of the syntactic role of a given function parameter. +enum FunctionParamRole { + PARAM_ROLE_UNSPECIFIED = 0; + // An ordinary parameter which may be used as a positional or by keyword. + PARAM_ROLE_ORDINARY = 1; + // A positional-only parameter; such parameters cannot be defined in pure + // Starlark code, but exist in some natively-defined functions. + PARAM_ROLE_POSITIONAL_ONLY = 2; + // A keyword-only parameter, i.e. a non-vararg/kwarg parameter that follows + // `*` or `*args` in the function's declaration. + PARAM_ROLE_KEYWORD_ONLY = 3; + // Residual varargs, typically `*args` in the function's declaration. + PARAM_ROLE_VARARGS = 4; + // Residual keyword arguments, typically `**kwargs` in the function's + // declaration. + PARAM_ROLE_KWARGS = 5; +} + +// Representation of a Starlark function parameter definition. +message FunctionParamInfo { + // The name of the parameter. This does *not* include the `*` or `**` prefix + // for varargs or residual keyword argument parameters. + string name = 1; + + // The documented description of the parameter (if specified in the function's + // docstring). + string doc_string = 2; + + // If not an empty string, the default value of the parameter displayed + // as a string. + string default_value = 3; + + // If true, the default value is unset and a value is needed for this + // parameter. This might be false even if defaultValue is empty in the case of + // special parameter such as *args and **kwargs" + bool mandatory = 4; + + // The parameter's syntactic role. + FunctionParamRole role = 5; +} + +message FunctionReturnInfo { + // The documented return value of the function (if specified in the function's + // docstring). + string doc_string = 1; +} + +message FunctionDeprecationInfo { + // The documented deprecation of the function (if specified in the function's + // docstring). + string doc_string = 1; +} + +// Representation of a Starlark provider field definition, comprised of +// the field name and provider description. +message ProviderFieldInfo { + // The name of the field. + string name = 1; + + // The description of the provider. + string doc_string = 2; +} + +// Representation of a Starlark provider definition. +message ProviderInfo { + // The name under which the provider is made accessible to a user of this + // module, including any structs it is nested in, for example "foo.FooInfo". + string provider_name = 1; + + // The description of the provider. + string doc_string = 2; + + // The fields of the provider. + repeated ProviderFieldInfo field_info = 3; + + // Note: legacy Stardoc (0.5.x and earlier) does not set any fields below. + + // The module where and the name under which the provider was originally + // declared. + OriginKey origin_key = 4; + + // The provider's init callback. + StarlarkFunctionInfo init = 5; +} + +// Representation of a Starlark aspect definition. +message AspectInfo { + // The name under which the aspect is made accessible to a user of this + // module, including any structs it is nested in, for example + // "foo.foo_aspect". + string aspect_name = 1; + + // The documentation string of the aspect. + string doc_string = 2; + + // The rule attributes along which the aspect propagates. + repeated string aspect_attribute = 3; + + // The attributes of the aspect. + repeated AttributeInfo attribute = 4; + + // The module where and the name under which the aspect was originally + // declared. + // + // Note: legacy Stardoc (0.5.x and earlier) does not set this field. + OriginKey origin_key = 5; +} + +// Representation of a Bazel module extension, i.e. the object returned by +// calling `module_extension(...)`. +// +// Note: legacy Stardoc (0.5.x and earlier) does not emit this message. +message ModuleExtensionInfo { + // The name under which the extension is made accessible to a user of this + // Starlark module. + string extension_name = 1; + + // The documentation string of the extension. + string doc_string = 2; + + // The tag classes of the extension. + repeated ModuleExtensionTagClassInfo tag_class = 3; + + // The Starlark module where the Bazel module extension was originally + // declared; origin_key.name is currently never set. + // TODO(arostovtsev): attempt to retrieve the name under which the module + // extension was originally declared if it was declared as a global. + OriginKey origin_key = 4; +} + +// Representation of a Bazel module extension tag class. +message ModuleExtensionTagClassInfo { + // The name of the tag for this tag class. + string tag_name = 1; + + // The documentation string of the tag class. + string doc_string = 2; + + // The tag class's attributes. + repeated AttributeInfo attribute = 3; +} + +// Representation of a Bazel repository rule, i.e. the object returned by +// calling `repository_rule(...)`. +// +// Note: legacy Stardoc (0.5.x and earlier) does not emit this message, instead +// using RuleInfo. +message RepositoryRuleInfo { + // The name under which the repository rule is made accessible to a user of + // this Starlark module. + string rule_name = 1; + + // The documentation string of the repository rule. + string doc_string = 2; + + // The attributes of the repository rule. + repeated AttributeInfo attribute = 3; + + // Environment variables that this repository rule depends on. + repeated string environ = 4; + + // The Starlark module where and the name under which the repository rule was + // originally declared. + OriginKey origin_key = 5; +} + +// Representation of the origin of a rule, provider, aspect, or function. +// Intended to be used for building unambiguous cross-references: for example, +// between an element of a ProviderNameGroup required by a rule attribute and +// its corresponding ProviderInfo. +message OriginKey { + // The name under which the entity was originally exported. Unset when the + // entity was not exported in its module. + string name = 1; + + // The display form of the label of the module file in which the entity was + // originally declared (as seen from the starlark_doc_extract or Stardoc + // target's repo), or "" for Bazel's built-in entities implemented in + // Java. Unset when there is no module file (such as for legacy struct + // providers, when the module is a REPL, or in Bazel's internal tests). + string file = 2; +} diff --git a/tools/release/bazel-release-metadata.mts b/tools/release/bazel-release-metadata.mts new file mode 100644 index 000000000..11dff1821 --- /dev/null +++ b/tools/release/bazel-release-metadata.mts @@ -0,0 +1,1127 @@ +import { mkdirSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { seedCarrierIdentities } from '../../src/database-resources/seeds/carrier-identities.mts'; +import { wasixSeedConsumerDeclaration } from '../../src/database-resources/seeds/wasix/consumer-contract.mts'; +import { staticMemberAliases } from '../../src/extensions/artifacts/native/tools/ios-extension-registration.mts'; +import { loadContribCarriers } from '../../src/extensions/artifacts/packages/tools/contrib-carriers.mts'; +import { validateExtensionTargetProfiles } from '../../src/extensions/contracts/extension-target-profiles.mts'; +import { + resolveNativeComponentClosure, + validateNativeComponentContract, +} from '../../src/extensions/tools/native-component-contract.mts'; +import { nativeCargoArtifactRows } from '../packaging/rust-native-targets.mts'; +import { validateNativeSupplierPublications } from './bazel-shipping-inputs.mts'; +import { + cargoCompatibilityDependency, + compatibilityVersionFromText, +} from './compatibility-version-parser.mts'; +import { + contribExtensionMetadata, + declaredExtensionMetadata, + extensionPublicationMetadataRows, + extensionSourceMetadata, +} from './extension-release-metadata.mts'; +import { + projectNativeAppleBaseInput, + projectNativeCurrentArtifacts, + projectNativeExtensionFinalInputs, + projectNativeSwiftSourceInput, +} from './native-extension-final-inputs.mts'; +import { projectNativeSeedInputs } from './native-seed-inputs.mts'; +import { projectNativeSupplierArtifacts } from './native-supplier-artifacts.mts'; +import { loadPublicationCatalog, resolveActualCarrier } from './publication-catalog.mts'; +import { + databaseResourceArtifactRows, + expectedExtensionGithubReleaseAssetRows, + extensionRegistryPackageTargetSetsFromRows, + extensionReleaseMetadataRows, + nativeHelperArtifactRows, + nativeRuntimeArtifactRows, + runtimeExtensionTargetRowsFromConfigs, + swiftArtifactRows, + validateExtensionCatalogRows, + wasixArtifactRows, +} from './release-artifact-targets.mts'; + +export interface ProductIdentity { + id: string; + path: string; + version: string; + registry_packages: string[]; + publish_targets: string[]; + artifact_targets: { preset: string; targets: string[] } | null; + compatibility_versions: Record; + cargo_artifacts: { + sourceProduct: string; + target: string; + packageKind: string; + packageName: string; + }[]; +} + +export interface ReleaseMetadata { + products: Record; + contribOwners: { native: string; wasix: string }; + contribMembers: Record[]; + postgresSource: Record; + extensions: Record>; + wasixExtensions: Record>; + extensionSources: Record>; + extensionRecipes: Record>; + extensionCompatibility: Record>; + extensionDependencies: Record>>; + extensionReleaseMetadata: Record[]; + extensionGithubArtifacts: Record[]; + extensionProfiles: Record; + nativeComponents: Record; + nativeComponentSources: Record>; + nativeMobileComponentClosures: Record< + string, + Record + >; + nativeMobileMemberAliases: Record>; + publicationCarriers: { + product: string; + ecosystem: string; + name: string; + version: string; + target: string | null; + role: string; + }[]; + nativeHelperArtifacts: Record[]; + nativeRuntimeArtifacts: Record[]; + wasixArtifacts: Record[]; + databaseResourceContract: Record | null; + databaseResourceWasixConsumer: ReturnType | null; + databaseResourceArtifacts: Record[]; + databaseSeedCarriers: ReturnType; + inputs: Record; + directories: Record; +} + +function object(value: unknown, context: string): Record { + if (value === null || Array.isArray(value) || typeof value !== 'object') { + throw new Error(`${context} must be an object`); + } + return value as Record; +} + +function string(value: unknown, context: string): string { + if (typeof value !== 'string' || !value) throw new Error(`${context} must be a string`); + return value; +} + +function strings(value: unknown, context: string): string[] { + if (!Array.isArray(value) || value.some((entry) => typeof entry !== 'string' || !entry)) + throw new Error(`${context} must be a string list`); + if (new Set(value).size !== value.length) throw new Error(`${context} must be unique`); + return value; +} + +/** Analysis consumes physical unit IDs from the existing canonical resolver. */ +export function nativeMobileComponentInputs( + raw: Record, + sqlNames: string[], + profiles: { target: string; family: string; kind: string }[], +) { + const components = validateNativeComponentContract(raw, { + checkSourcePaths: false, + knownExtensions: new Set(sqlNames), + targetProfiles: new Map(profiles.map((row) => [row.target, `${row.family}\0${row.kind}`])), + }); + const mobile = profiles.filter( + (row) => row.family === 'native' && row.kind === 'native-static-registry', + ); + return Object.fromEntries( + [...sqlNames].sort().map((sqlName) => [ + sqlName, + Object.fromEntries( + mobile.map((row) => { + const closure = resolveNativeComponentClosure(components, { + extension: sqlName, + family: row.family, + kind: row.kind, + target: row.target, + }); + return [row.target, { linkUnits: closure.linkUnits, runtimeFiles: closure.runtimeFiles }]; + }), + ), + ]), + ); +} + +export function nativeMobileMemberAliasInputs(catalog: Map>) { + return Object.fromEntries( + [...catalog.values()].map((row) => { + const sqlName = string(row['sql-name'], 'static alias SQL name'); + const module = row['native-module-file']; + if (module !== undefined && (typeof module !== 'string' || !module.endsWith('.so'))) + throw new Error(`static aliases require the canonical module stem for ${sqlName}`); + const stem = typeof module === 'string' ? module.slice(0, -3) : null; + return [ + sqlName, + Object.fromEntries( + staticMemberAliases(sqlName, stem).map(({ name, address }) => [name, address]), + ), + ]; + }), + ); +} + +export function extensionGithubArtifactInputs( + identity: { + artifactProduct: string; + owner: string; + version: string; + sqlNames: string[]; + family?: 'native' | 'wasix' | null; + }, + profiles: { target: string; family: string; kind: string }[], + catalog: Map>, + mobile: ReleaseMetadata['nativeMobileComponentClosures'], +) { + const selectedFamily = identity.family === undefined ? 'native' : identity.family; + const requiredRows = identity.sqlNames.flatMap((sqlName) => { + const descriptor = catalog.get(sqlName); + if (!descriptor) throw new Error(`extension asset inventory is missing ${sqlName}`); + const module = descriptor['native-module-file']; + if (module !== undefined && (typeof module !== 'string' || !module.endsWith('.so'))) + throw new Error( + `extension asset inventory requires the canonical module stem for ${sqlName}`, + ); + return profiles + .filter( + (row) => + (selectedFamily === null || row.family === selectedFamily) && + (row.family === 'native' || row.target === 'wasix-portable'), + ) + .flatMap(({ family, target }) => { + const runtime = { + sqlName, + family, + target, + kind: family === 'wasix' ? 'wasix-runtime' : 'runtime', + identity: null, + }; + if (target !== 'ios-xcframework' || module === undefined) return [runtime]; + const closure = mobile[sqlName]?.[target]; + if (!closure) throw new Error(`extension asset inventory is missing ${sqlName}/${target}`); + return [ + runtime, + { sqlName, family, target, kind: 'ios-xcframework', identity: module.slice(0, -3) }, + ...closure.linkUnits.map((dependency) => ({ + sqlName, + family, + target, + kind: 'ios-dependency-xcframework', + identity: dependency, + })), + ]; + }); + }); + requiredRows.sort((left, right) => { + const a = `${left.sqlName}:${left.family}:${left.target}:${left.kind}:${left.identity ?? ''}`; + const b = `${right.sqlName}:${right.family}:${right.target}:${right.kind}:${right.identity ?? ''}`; + return a < b ? -1 : a > b ? 1 : 0; + }); + return expectedExtensionGithubReleaseAssetRows( + { id: identity.artifactProduct, version: identity.version, family: selectedFamily }, + { sqlNames: identity.sqlNames, requiredRows }, + ).map((row) => ({ + artifactProduct: identity.artifactProduct, + owner: identity.owner, + product: identity.owner, + version: identity.version, + id: `github-release:${row.name}`, + role: 'github-release-asset', + family: row.family, + kind: row.kind, + target: row.target, + identity: row.identity, + name: row.name, + })); +} + +export function repositoryPath(value: string): string { + if ( + value.includes('\\') || + value.includes('\0') || + path.posix.isAbsolute(value) || + value.split('/').some((part) => !part || part === '.' || part === '..') + ) { + throw new Error(`metadata path must stay inside the repository: ${JSON.stringify(value)}`); + } + return value; +} + +export function loadReleaseMetadata(root: string): ReleaseMetadata { + const inputs: Record = {}; + const directories: Record = {}; + const read = (file: string) => { + const relative = repositoryPath(file); + const content = readFileSync(path.join(root, relative), 'utf8'); + inputs[relative] = content; + return content; + }; + const json = (file: string) => object(JSON.parse(read(file)), file); + const toml = (file: string) => object(Bun.TOML.parse(read(file)), file); + const optionalToml = (file: string) => { + try { + return toml(file); + } catch (error) { + if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error; + // Absence is also an input: adding a recipe must invalidate the import. + inputs[repositoryPath(file)] = null; + return undefined; + } + }; + const config = object(json('release-please-config.json').packages, 'release packages'); + const versions = json('.release-please-manifest.json'); + const products: Record = {}; + const descriptors = new Map>(); + for (const [source, raw] of Object.entries(config).sort(([a], [b]) => + a < b ? -1 : a > b ? 1 : 0, + )) { + const productPath = repositoryPath(source); + const id = string(object(raw, source).component, `${source}.component`); + if (!/^[a-z][a-z0-9-]*$/.test(id)) throw new Error(`invalid release product id ${id}`); + if (Object.hasOwn(products, id)) throw new Error(`duplicate release product ${id}`); + const version = string(versions[source], `${source} release version`); + if (!/^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/.test(version)) { + throw new Error(`${id} must have a stable release version, got ${version}`); + } + const descriptor = toml(`${productPath}/release.toml`); + if (descriptor.id !== id) throw new Error(`${productPath}/release.toml disagrees with ${id}`); + const artifactTargets = + descriptor.artifact_targets === undefined + ? null + : object(descriptor.artifact_targets, `${id}.artifact_targets`); + products[id] = { + id, + path: productPath, + version, + registry_packages: strings(descriptor.registry_packages ?? [], `${id}.registry_packages`), + publish_targets: strings(descriptor.publish_targets ?? [], `${id}.publish_targets`), + compatibility_versions: {}, + cargo_artifacts: [], + artifact_targets: + artifactTargets === null + ? null + : { + preset: string(artifactTargets.preset, `${id}.artifact_targets.preset`), + targets: strings(artifactTargets.targets, `${id}.artifact_targets.targets`), + }, + }; + if (id === 'liboliphaunt-native' || id === 'oliphaunt-broker') { + if (products[id].artifact_targets === null) + throw new Error(`${id} has no canonical artifact targets`); + products[id].cargo_artifacts = nativeCargoArtifactRows( + id, + products[id].artifact_targets.targets, + products[id].registry_packages, + ); + } + descriptors.set(id, descriptor); + } + const contrib = toml('src/extensions/contrib/carriers.toml'); + const contribOwners = { + native: string(contrib.native_owner, 'contrib.native_owner'), + wasix: string(contrib.wasix_owner, 'contrib.wasix_owner'), + }; + for (const owner of Object.values(contribOwners)) { + if (!Object.hasOwn(products, owner)) throw new Error(`unknown contrib release owner ${owner}`); + } + if (contribOwners.native === contribOwners.wasix) { + throw new Error('native and WASIX contrib must have distinct release owners'); + } + const memberManifest = string(contrib.member_manifest, 'contrib.member_manifest'); + const members = toml(memberManifest).extensions; + if (!Array.isArray(members) || members.length === 0) + throw new Error('contrib members must be nonempty'); + const contribMembers = members.map((member) => object(member, 'contrib member')); + const ids = new Set(); + for (const member of contribMembers) { + const id = string(member.id, 'contrib member.id'); + if (ids.has(id)) throw new Error(`duplicate contrib member ${id}`); + ids.add(id); + } + // Pin inputs remain acquisition facts; publication versions remain product facts. + const postgresSource = toml(string(contrib.source, 'contrib.source')); + toml(string(contrib.contract, 'contrib.contract')); + const catalog = json('src/extensions/catalog/extensions.source.json').extensions; + if (!Array.isArray(catalog)) throw new Error('extension catalog must have an extensions array'); + const extensions: ReleaseMetadata['extensions'] = {}; + for (const value of catalog) { + const row = object(value, 'extension'); + const id = string(row.id, 'extension.id'); + if (Object.hasOwn(extensions, id)) throw new Error(`duplicate extension ${id}`); + extensions[id] = row; + } + for (const member of contribMembers) { + const id = member.id as string; + if (!Object.hasOwn(extensions, id)) + throw new Error(`contrib member ${id} is absent from the catalog`); + } + const extensionSources: ReleaseMetadata['extensionSources'] = {}; + const extensionRecipes: ReleaseMetadata['extensionRecipes'] = {}; + const extensionCompatibility: ReleaseMetadata['extensionCompatibility'] = {}; + const extensionDependencies: ReleaseMetadata['extensionDependencies'] = {}; + for (const [product, descriptor] of descriptors) { + if (descriptor.extension === undefined) continue; + const extension = object(descriptor.extension, `${product}.extension`); + if (extension.class !== 'external') continue; + const sqlName = string(extension.sql_name, `${product}.extension.sql_name`); + if (!Object.hasOwn(extensions, sqlName)) + throw new Error(`external extension ${sqlName} is absent from the catalog`); + if (Object.hasOwn(extensionSources, sqlName)) + throw new Error(`duplicate external SQL identity ${sqlName}`); + const source = object(extension.source, `${product}.extension.source`); + const sourcePath = string(source.path, `${product}.extension.source.path`); + extensionSources[sqlName] = { + ...toml(sourcePath), + product, + }; + extensionCompatibility[sqlName] = object( + extension.compatibility, + `${product}.extension.compatibility`, + ); + const directory = repositoryPath(`${path.posix.dirname(sourcePath)}/dependencies`); + extensionDependencies[sqlName] = {}; + try { + const entries = readdirSync(path.join(root, directory), { withFileTypes: true }); + directories[directory] = entries.map(({ name }) => name).sort(); + for (const entry of entries) { + if (entry.isSymbolicLink()) + throw new Error(`${directory}/${entry.name} cannot be a symlink`); + if (!entry.isDirectory()) continue; + extensionDependencies[sqlName][entry.name] = toml(`${directory}/${entry.name}/source.toml`); + } + } catch (error) { + if ( + (error as NodeJS.ErrnoException).code !== 'ENOENT' || + directories[directory] !== undefined + ) + throw error; + directories[directory] = null; + } + const recipe = optionalToml(`${path.posix.dirname(sourcePath)}/recipe.toml`); + if (recipe) { + if (recipe.sql_name !== sqlName) + throw new Error(`${product} recipe disagrees with SQL identity ${sqlName}`); + extensionRecipes[sqlName] = recipe; + } + } + const extensionProfiles = toml('src/extensions/contracts/extension-target-profiles.toml'); + const nativeComponents = toml('src/extensions/catalog/native-components.toml'); + const nativeComponentSources: Record> = {}; + for (const component of nativeComponents.components as Record[]) { + if (component['source-path']) continue; + const name = string(component.source, 'native component source'); + const dependencies = Object.values(extensionDependencies) + .flatMap((rows) => Object.entries(rows)) + .filter(([key]) => key === name) + .map(([, source]) => source); + if (dependencies.length > 0) { + if (dependencies.some((source) => JSON.stringify(source) !== JSON.stringify(dependencies[0]))) + throw new Error(`native component ${name} has conflicting canonical acquisitions`); + nativeComponentSources[name] = dependencies[0]; + } else { + const source = optionalToml(`src/third-party/${repositoryPath(name)}/source.toml`); + if (source) nativeComponentSources[name] = source; + } + } + const publicationProducts = Object.fromEntries( + [...descriptors].map(([product, descriptor]) => [ + product, + { + ...descriptor, + path: products[product].path, + version: products[product].version, + }, + ]), + ); + const canonicalContrib = loadContribCarriers(root, 'release metadata', { readText: read }); + const targetRows = validateExtensionTargetProfiles(extensionProfiles).targets; + const allowed = new Set( + runtimeExtensionTargetRowsFromConfigs( + publicationProducts, + 'release metadata', + canonicalContrib, + ).map((row) => `${row.target}\0${row.family}\0${row.kind}`), + ); + for (const row of targetRows) { + if (!allowed.has(`${row.target}\0${row.family}\0${row.kind}`)) { + throw new Error( + `extension target ${row.target}/${row.family}/${row.kind} is not backed by runtime artifact metadata`, + ); + } + } + const generatedCatalog = validateExtensionCatalogRows( + json('src/extensions/generated/extensions.catalog.json'), + 'release metadata', + ); + const wasixCatalog = json('src/extensions/generated/wasix/extensions.json').extensions; + if (!Array.isArray(wasixCatalog)) throw new Error('WASIX extensions must be an array'); + const wasixExtensions: ReleaseMetadata['wasixExtensions'] = {}; + for (const value of wasixCatalog) { + const row = object(value, 'WASIX extension'); + const sqlName = string(row['sql-name'], 'WASIX extension SQL name'); + if (Object.hasOwn(wasixExtensions, sqlName)) + throw new Error(`duplicate WASIX extension ${sqlName}`); + wasixExtensions[sqlName] = row; + } + const moduleMembers = new Set( + [...generatedCatalog] + .filter(([, row]) => typeof row['native-module-file'] === 'string') + .map(([name]) => name), + ); + const nativeMobileComponentClosures = nativeMobileComponentInputs( + nativeComponents, + [...generatedCatalog.values()].map((row) => + string(row['sql-name'], 'native component SQL name'), + ), + targetRows, + ); + const nativeMobileMemberAliases = nativeMobileMemberAliasInputs(generatedCatalog); + const contribSqlNames = canonicalContrib.members + .map((member) => string(member['sql-name'], 'contrib SQL name')) + .sort(); + for (const name of contribSqlNames) { + if (!generatedCatalog.has(name)) + throw new Error(`contrib member ${name} is absent from generated extension catalog`); + } + const contribRegistryTargets = extensionRegistryPackageTargetSetsFromRows( + canonicalContrib.artifactProduct, + contribSqlNames, + contribSqlNames.flatMap((sqlName) => targetRows.map((row) => ({ ...row, sqlName }))), + contribSqlNames.filter((name) => moduleMembers.has(name)), + 'release metadata', + ); + const publicationCarriers = loadPublicationCatalog('release metadata', { + inputContext: { + products: publicationProducts, + contrib: canonicalContrib, + contribRegistryTargets, + }, + }).carriers.map(({ product, ecosystem, name, version, target, role }) => ({ + product, + ecosystem, + name, + version, + target, + role, + })); + // Read authored installed requirements through the same parser as release + // preparation. Workspace producer versions do not replace these pins. + for (const [product, descriptor] of descriptors) { + const entries = object( + descriptor.compatibility_versions ?? {}, + `${product}.compatibility_versions`, + ); + for (const [id, value] of Object.entries(entries)) { + const entry = object(value, `${product}.compatibility_versions.${id}`); + const sourceProduct = string(entry.source_product, `${product}.${id}.source_product`); + if (!Object.hasOwn(products, sourceProduct)) + throw new Error(`unknown compatibility product ${sourceProduct}`); + const file = string(entry.path, `${product}.${id}.path`); + const parser = string(entry.parser, `${product}.${id}.parser`); + const locator = { id, path: file, parser }; + const text = read(file); + const dependency = cargoCompatibilityDependency(locator, text); + if (dependency?.path !== undefined) continue; + const carrier = + dependency && + publicationCarriers.find( + (row) => + row.product === sourceProduct && + row.ecosystem === 'cargo' && + row.name === dependency.packageName, + ); + if ( + carrier?.target === null && + publicationCarriers.some( + (row) => + row.product === sourceProduct && row.ecosystem === 'cargo' && row.target !== null, + ) + ) + continue; + const version = compatibilityVersionFromText(locator, text, { + prefix: 'release metadata', + }); + const prior = products[product].compatibility_versions[sourceProduct]; + if (prior !== undefined && prior !== version) + throw new Error( + `${product} declares conflicting compatibility versions for ${sourceProduct}`, + ); + products[product].compatibility_versions[sourceProduct] = version; + } + } + const nativeHelperArtifacts = ['oliphaunt-broker', 'oliphaunt-node-direct'].flatMap((product) => { + const identity = products[product]; + if (!identity) return []; + if (!identity.artifact_targets) + throw new Error(`${product} must declare artifact targets for native helper construction`); + return nativeHelperArtifactRows(product, identity.artifact_targets.targets, 'release metadata'); + }); + const nativeRuntimeArtifacts = ['liboliphaunt-native', 'postgres-tools-native'].flatMap( + (product) => { + const identity = products[product]; + if (!identity) return []; + if (!identity.artifact_targets) + throw new Error(`${product} must declare artifact targets for native runtime construction`); + return nativeRuntimeArtifactRows( + product, + identity.artifact_targets.targets, + 'release metadata', + ); + }, + ); + const databaseResourceContract = products['database-resources'] + ? json('src/database-resources/contracts/contract.json') + : null; + const databaseResourceWasixConsumer = databaseResourceContract + ? wasixSeedConsumerDeclaration( + toml('src/database-resources/seeds/wasix/Cargo.toml'), + products['database-resources'].compatibility_versions['liboliphaunt-wasix'], + products['liboliphaunt-wasix'].version, + ) + : null; + const databaseResourceArtifacts = databaseResourceContract + ? databaseResourceArtifactRows(databaseResourceContract) + : []; + const databaseSeedCarriers = databaseResourceContract + ? seedCarrierIdentities(databaseResourceContract) + : []; + const wasixArtifacts = [ + 'liboliphaunt-wasix', + 'postgres-tools-wasix', + 'liboliphaunt-wasix-postmaster', + 'oliphaunt-wasix-napi', + ].flatMap((product) => { + const identity = products[product]; + if (!identity) return []; + if (!identity.artifact_targets) + throw new Error(`${product} must declare WASIX artifact targets`); + return wasixArtifactRows(product, identity.artifact_targets.targets, 'release metadata'); + }); + const extensionReleaseMetadata = []; + for (const [product, descriptor] of descriptors) { + if (descriptor.extension === undefined) continue; + const extension = object(descriptor.extension, `${product}.extension`); + if (extension.class !== 'external') continue; + const metadata = declaredExtensionMetadata(product, extension); + extensionReleaseMetadata.push( + ...extensionPublicationMetadataRows( + product, + metadata, + extensionSourceMetadata(product, metadata, extensionSources[metadata.sqlName]), + () => products[product].path, + ), + ); + } + const artifactProduct = string(contrib.logical_product, 'contrib.logical_product'); + const postgresVersion = string( + object(postgresSource.postgresql, 'postgresql').version, + 'postgresql.version', + ); + const postgresMajor = postgresVersion.split('.')[0]; + if (!/^[1-9][0-9]*$/.test(postgresMajor)) + throw new Error('PostgreSQL must have a stable major version'); + const contribMetadata = contribExtensionMetadata({ + artifactProduct, + sourcePath: string(contrib.source, 'contrib.source'), + sqlNames: contribMembers.map((member) => string(member['sql-name'], 'contrib SQL name')).sort(), + compatibility: { + postgresMajor, + extensionRuntimeContract: string(contrib.contract, 'contrib.contract'), + nativeRuntimeProduct: contribOwners.native, + nativeRuntimeVersion: products[contribOwners.native].version, + wasixRuntimeProduct: contribOwners.wasix, + wasixRuntimeVersion: products[contribOwners.wasix].version, + }, + }); + extensionReleaseMetadata.push( + ...extensionPublicationMetadataRows( + artifactProduct, + contribMetadata, + extensionSourceMetadata(artifactProduct, contribMetadata, postgresSource), + () => path.posix.dirname(memberManifest), + ), + ); + extensionReleaseMetadata.sort((left, right) => { + const a = `${left.product}:${left.sqlName}`; + const b = `${right.product}:${right.sqlName}`; + return a < b ? -1 : a > b ? 1 : 0; + }); + const extensionGithubArtifacts = [ + ...new Set(extensionReleaseMetadata.map((row) => row.artifactProduct)), + ] + .sort() + .flatMap((artifactProduct) => { + const rows = extensionReleaseMetadata.filter( + (row) => row.artifactProduct === artifactProduct, + ); + const owners = + rows[0].class === 'contrib' + ? [ + { owner: contribOwners.native, family: 'native' as const }, + { owner: contribOwners.wasix, family: 'wasix' as const }, + ] + : [{ owner: string(artifactProduct, 'extension artifact product'), family: null }]; + return owners.flatMap(({ owner, family }) => { + const identity = { + artifactProduct: string(artifactProduct, 'extension artifact product'), + owner, + version: products[owner].version, + sqlNames: rows.map((row) => string(row.sqlName, 'extension SQL name')), + family, + }; + return [ + ...extensionGithubArtifactInputs( + identity, + targetRows, + generatedCatalog, + nativeMobileComponentClosures, + ), + ...extensionReleaseMetadataRows( + { id: identity.artifactProduct, version: identity.version }, + family, + ).map(([kind, name]) => ({ + artifactProduct: identity.artifactProduct, + owner, + product: owner, + version: identity.version, + id: `github-release:${name}`, + role: 'github-release-metadata', + family, + kind, + target: 'portable', + identity: null, + name, + control: true, + })), + ]; + }); + }); + return { + products, + contribOwners, + contribMembers, + postgresSource, + extensions, + wasixExtensions, + extensionSources, + extensionRecipes, + extensionCompatibility, + extensionDependencies, + extensionReleaseMetadata, + extensionGithubArtifacts, + extensionProfiles, + nativeComponents, + nativeComponentSources, + nativeMobileComponentClosures, + nativeMobileMemberAliases, + publicationCarriers, + nativeHelperArtifacts, + nativeRuntimeArtifacts, + wasixArtifacts, + databaseResourceContract, + databaseResourceWasixConsumer, + databaseResourceArtifacts, + databaseSeedCarriers, + inputs, + directories, + }; +} + +function starlark(value: unknown): string { + if (value === null || value === undefined) return 'None'; + if (typeof value === 'boolean') return value ? 'True' : 'False'; + if (Array.isArray(value)) return `[${value.map(starlark).join(', ')}]`; + if (typeof value === 'object') { + return `{${Object.entries(value as Record) + .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)) + .map(([key, child]) => `${JSON.stringify(key)}: ${starlark(child)}`) + .join(', ')}}`; + } + if (typeof value === 'number' && !Number.isFinite(value)) throw new Error('nonfinite metadata'); + return JSON.stringify(value); +} + +/** Complete public GitHub declarations from the supplied source snapshot. + * This view reuses the same owner/version renderers as the carrier graph. */ +export function nativeSupplierGithubArtifactDeclarations(metadata: ReleaseMetadata) { + const declared = (product: string) => + metadata.products[product]?.publish_targets.some( + (target) => target === 'github-release' || target === 'github-release-assets', + ); + const base = [ + ...metadata.nativeRuntimeArtifacts, + ...metadata.nativeHelperArtifacts, + ...metadata.wasixArtifacts, + ...metadata.databaseResourceArtifacts, + ...swiftArtifactRows(), + ].flatMap((row) => + typeof row.product === 'string' && + typeof row.asset === 'string' && + Array.isArray(row.surfaces) && + row.surfaces.includes('github-release') && + declared(row.product) + ? [{ product: row.product, asset: row.asset }] + : [], + ); + const extensions = metadata.extensionGithubArtifacts + .map((row) => { + const product = string(row.product, 'extension GitHub supplier owner'); + const version = string(row.version, 'extension GitHub supplier version'); + if (metadata.products[product]?.version !== version) + throw new Error('extension GitHub supplier version differs from its declared owner'); + const name = string(row.name, 'extension GitHub supplier filename'); + return { product, asset: name.replaceAll(version, '{version}') }; + }) + .filter(({ product }) => declared(product)); + return [ + ...new Map( + [...base, ...extensions].map((row) => [row.product + '\0' + row.asset, row]), + ).values(), + ]; +} + +export function nativePublicationInputProjection(value: unknown, _metadata?: ReleaseMetadata) { + const snapshot = object(value, 'native publication inputs'); + if ( + Object.keys(snapshot).some( + (key) => + ![ + 'source', + 'seedControls', + 'supplierPublications', + 'extensionFinalInputs', + 'nativeAppleBase', + 'nativeSwiftSource', + 'nativeCurrentArtifacts', + 'selectedProducts', + 'supplierArtifacts', + ].includes(key), + ) + ) + throw new Error('native publication inputs contain unknown fields'); + const source = object(snapshot.source, 'native publication source'); + if ( + Object.keys(source).sort().join(',') !== 'commit,tree' || + ![source.commit, source.tree].every( + (sha) => typeof sha === 'string' && /^[a-f0-9]{40}$/u.test(sha), + ) + ) + throw new Error('native publication inputs require an exact source commit and tree'); + const supplierPublications = validateNativeSupplierPublications( + snapshot.supplierPublications ?? [], + ); + const seeds = projectNativeSeedInputs( + snapshot.seedControls ?? [], + source as { commit: string; tree: string }, + ); + const extensions = projectNativeExtensionFinalInputs(snapshot.extensionFinalInputs ?? []); + const apple = + snapshot.nativeAppleBase === undefined + ? { input: null, files: [] } + : projectNativeAppleBaseInput(snapshot.nativeAppleBase); + const swift = + snapshot.nativeSwiftSource === undefined + ? { input: null, files: [] } + : projectNativeSwiftSourceInput(snapshot.nativeSwiftSource); + const current = + snapshot.nativeCurrentArtifacts === undefined + ? { artifacts: null, files: [] } + : projectNativeCurrentArtifacts( + snapshot.nativeCurrentArtifacts, + source as { commit: string; tree: string }, + ); + if (_metadata && current.artifacts) { + const catalog = { + carriers: _metadata.publicationCarriers.map((row) => ({ + ...row, + id: `${row.ecosystem}:${row.name}`, + declared: true, + })), + }; + const github = nativeSupplierGithubArtifactDeclarations(_metadata); + for (const row of Object.values(current.artifacts)) { + if (_metadata.products[row.product]?.version !== row.version) + throw new Error('current native artifact differs from its source owner version'); + if (row.artifact.startsWith('cargo:')) { + const carrier = resolveActualCarrier(catalog, 'cargo', row.artifact.slice(6)); + if (carrier.product !== row.product) + throw new Error('current native Cargo artifact owner differs'); + } else if ( + !github.some( + (declaration) => + declaration.product === row.product && + `github-release:${declaration.asset.replaceAll('{version}', row.version)}` === + row.artifact, + ) + ) { + throw new Error('current native GitHub artifact is not declared'); + } + } + } + const selectedProducts = snapshot.selectedProducts === undefined ? [] : snapshot.selectedProducts; + if ( + !Array.isArray(selectedProducts) || + selectedProducts.some((id) => typeof id !== 'string' || !/^[a-z][a-z0-9-]*$/u.test(id)) || + new Set(selectedProducts).size !== selectedProducts.length + ) + throw new Error('prepared native selected products require unique canonical IDs'); + const suppliers = projectNativeSupplierArtifacts( + snapshot.supplierArtifacts === undefined ? [] : snapshot.supplierArtifacts, + ); + for (const { publication } of Object.values(suppliers.artifacts)) { + const matching = supplierPublications.find( + (row) => row.product === publication.product && row.version === publication.version, + ); + if (matching && Object.keys(matching).some((key) => matching[key] !== publication[key])) + throw new Error('completed supplier artifact source conflicts with supplier publication'); + } + return { + prepared: Object.hasOwn(snapshot, 'selectedProducts'), + selectedProducts: [...selectedProducts], + nativeSwiftSource: swift.input, + nativeCurrentArtifacts: current.artifacts, + supplierArtifacts: suppliers.artifacts, + supplierPublications: Object.fromEntries( + supplierPublications.map((publication) => [ + `${publication.product}@${publication.version}`, + publication, + ]), + ), + seedControls: seeds.controls, + extensionFinalInputs: extensions.leaves, + nativeAppleBase: apple.input, + files: [ + ...seeds.files, + ...extensions.files, + ...apple.files, + ...swift.files, + ...current.files, + ...suppliers.files, + ], + }; +} + +function gitSourceArchive(source: Record, context: string) { + const commit = string(source.commit, `${context} acquisition commit`); + if (!/^[a-f0-9]{40}$/u.test(commit)) + throw new Error(`${context} archive requires an immutable full Git commit`); + const archive = object(source.archive, `${context} required archive SHA-256 pin`); + if (Object.keys(archive).some((key) => key !== 'sha256')) + throw new Error(`${context} source archive accepts only its SHA-256 pin`); + const sha256 = string(archive.sha256, `${context} acquisition archive SHA-256`); + if (!/^[a-f0-9]{64}$/u.test(sha256)) + throw new Error(`${context} archive requires an exact SHA-256`); + const remote = string(source.mirror_url ?? source.url, `${context} acquisition URL`); + const github = /^https:\/\/github\.com\/([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)\/?$/u.exec(remote); + const repository = github?.[2]?.replace(/\.git$/u, ''); + if (!github || !repository || repository === '.' || repository === '..') + throw new Error(`${context} source archive requires its declared GitHub Git remote`); + return { + url: `https://codeload.github.com/${github[1]}/${repository}/tar.gz/${commit}`, + sha256, + strip_prefix: `${repository}-${commit}`, + }; +} + +export function renderReleaseMetadata( + metadata: ReleaseMetadata, + identityRule: string, + publicationInputs = { + prepared: false, + supplierPublications: {}, + seedControls: {}, + extensionFinalInputs: {}, + nativeAppleBase: null, + nativeSwiftSource: null, + nativeCurrentArtifacts: null, + selectedProducts: [], + supplierArtifacts: {}, + files: [], + }, +) { + if (!identityRule.startsWith('@') || !identityRule.endsWith(':identity.bzl')) { + throw new Error('identity rule must be a repository-qualified identity.bzl label'); + } + for (const id of publicationInputs.selectedProducts) + if (!Object.hasOwn(metadata.products, id)) + throw new Error(`unknown prepared native selected product: ${id}`); + const definitions = { + PRODUCTS: metadata.products, + CONTRIB_OWNERS: metadata.contribOwners, + CONTRIB_MEMBERS: metadata.contribMembers, + POSTGRES_SOURCE: metadata.postgresSource, + EXTENSIONS: metadata.extensions, + WASIX_EXTENSIONS: metadata.wasixExtensions, + EXTENSION_SOURCES: metadata.extensionSources, + EXTENSION_RECIPES: metadata.extensionRecipes, + EXTENSION_COMPATIBILITY: metadata.extensionCompatibility, + EXTENSION_DEPENDENCIES: metadata.extensionDependencies, + EXTENSION_RELEASE_METADATA: metadata.extensionReleaseMetadata, + EXTENSION_GITHUB_ARTIFACTS: metadata.extensionGithubArtifacts, + EXTENSION_PROFILES: metadata.extensionProfiles, + NATIVE_COMPONENTS: metadata.nativeComponents, + NATIVE_COMPONENT_SOURCES: metadata.nativeComponentSources, + NATIVE_MOBILE_COMPONENT_CLOSURES: metadata.nativeMobileComponentClosures, + NATIVE_MOBILE_MEMBER_ALIASES: metadata.nativeMobileMemberAliases, + PUBLICATION_CARRIERS: metadata.publicationCarriers, + NATIVE_HELPER_ARTIFACTS: metadata.nativeHelperArtifacts, + NATIVE_RUNTIME_ARTIFACTS: metadata.nativeRuntimeArtifacts, + WASIX_ARTIFACTS: metadata.wasixArtifacts, + DATABASE_RESOURCE_CONTRACT: metadata.databaseResourceContract, + DATABASE_WASIX_SEED_CONSUMER: metadata.databaseResourceWasixConsumer, + DATABASE_RESOURCE_ARTIFACTS: metadata.databaseResourceArtifacts, + DATABASE_SEED_CARRIERS: metadata.databaseSeedCarriers, + COMPLETED_SUPPLIER_PUBLICATIONS: publicationInputs.supplierPublications, + SEED_REUSE_CONTROLS: publicationInputs.seedControls, + EXTENSION_FINAL_INPUTS: publicationInputs.extensionFinalInputs, + NATIVE_APPLE_BASE_INPUT: publicationInputs.nativeAppleBase, + NATIVE_SWIFT_SOURCE_INPUT: publicationInputs.nativeSwiftSource, + NATIVE_CURRENT_ARTIFACTS: publicationInputs.nativeCurrentArtifacts, + PREPARED_NATIVE_INPUTS: publicationInputs.prepared, + PREPARED_NATIVE_SELECTED_PRODUCTS: publicationInputs.selectedProducts, + COMPLETED_SUPPLIER_ARTIFACTS: publicationInputs.supplierArtifacts, + }; + const bzl = `${Object.entries(definitions) + .map(([name, value]) => `${name} = ${starlark(value)}`) + .join('\n\n')}\n`; + const build = [ + `load(${JSON.stringify(identityRule)}, "release_identity")`, + 'package(default_visibility = ["//visibility:public"])', + 'exports_files(["metadata.bzl", "extension-sources.bzl", "completed-supplier-artifacts.json", "native-swift-source-input.json", "native-apple-base-input.json", "prepared-selected-products.json"])', + ...(publicationInputs.files.length + ? [`exports_files(${starlark(publicationInputs.files.map(({ path }) => path))})`] + : []), + ...Object.values(metadata.products) + .sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)) + .map( + ({ id, version }) => + `release_identity(name = "product_${id}", product_id = ${JSON.stringify(id)}, version = ${JSON.stringify(version)})`, + ), + ].join('\n'); + // Module-extension acquisition excludes unrelated product versions. Loading + // metadata.bzl here would change MODULE.bazel.lock on every release bump. + const acquisitionSources = Object.fromEntries( + Object.entries(metadata.extensionSources).map(([sqlName, source]) => [ + sqlName, + { + ...Object.fromEntries( + ['name', 'url', 'commit', ...(source.mirror_url === undefined ? [] : ['mirror_url'])].map( + (key) => [key, string(source[key], `${sqlName} acquisition ${key}`)], + ), + ), + archive: gitSourceArchive(source, sqlName), + }, + ]), + ); + const acquisitionDependencies = Object.fromEntries( + Object.entries(metadata.extensionDependencies).map(([sqlName, dependencies]) => [ + sqlName, + Object.fromEntries( + Object.entries(dependencies).map(([directory, source]) => [ + directory, + (source.kind ?? 'git') === 'git' + ? { ...source, archive: gitSourceArchive(source, `${sqlName}/${directory}`) } + : source, + ]), + ), + ]), + ); + const extensionSourcesBzl = `EXTENSION_SOURCES = ${starlark(acquisitionSources)}\n\nEXTENSION_DEPENDENCIES = ${starlark(acquisitionDependencies)}\n`; + return { + bzl, + extensionSourcesBzl, + completedSupplierArtifacts: `${JSON.stringify(publicationInputs.supplierArtifacts)}\n`, + nativeSwiftSourceInput: `${JSON.stringify(publicationInputs.nativeSwiftSource)}\n`, + nativeAppleBaseInput: `${JSON.stringify(publicationInputs.nativeAppleBase)}\n`, + preparedSelectedProducts: `${JSON.stringify(publicationInputs.selectedProducts)}\n`, + build: `${build}\n`, + }; +} + +if (import.meta.main) { + const args = Bun.argv.slice(2); + if ( + ![6, 8].includes(args.length) || + args[0] !== '--root' || + args[2] !== '--output-dir' || + args[4] !== '--identity-rule' || + (args.length === 8 && args[6] !== '--native-publication-inputs') + ) { + throw new Error( + 'usage: bazel-release-metadata.mts --root ROOT --output-dir DIR --identity-rule LABEL [--native-publication-inputs FILE]', + ); + } + const metadata = loadReleaseMetadata(args[1]); + // Track the complete implementation import closure as well as data reads. + // Builtins come from the declared Bun tool; package imports require their own + // acquisition contract rather than silently resolving checkout node_modules. + const pending = ['tools/release/bazel-release-metadata.mts']; + const scanned = new Set(); + const scanner = new Bun.Transpiler({ loader: 'ts' }); + while (pending.length) { + const projectionFile = pending.pop()!; + if (scanned.has(projectionFile)) continue; + scanned.add(projectionFile); + const source = readFileSync(path.join(args[1], projectionFile), 'utf8'); + metadata.inputs[projectionFile] = source; + for (const { path: imported } of scanner.scanImports( + source.replace(/^#![^\r\n]*(?:\r?\n|$)/u, '\n'), + )) { + if (imported.startsWith('node:') || imported === 'bun') continue; + if (!imported.startsWith('.')) + throw new Error(`metadata implementation has undeclared package import ${imported}`); + pending.push( + repositoryPath( + path.posix.normalize(path.posix.join(path.posix.dirname(projectionFile), imported)), + ), + ); + } + } + const publicationInputs = + args.length === 8 + ? nativePublicationInputProjection( + JSON.parse( + new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode( + readFileSync(args[7]), + ), + ), + metadata, + ) + : undefined; + const rendered = renderReleaseMetadata(metadata, args[5], publicationInputs); + mkdirSync(args[3], { recursive: true }); + writeFileSync(path.join(args[3], 'metadata.bzl'), rendered.bzl); + writeFileSync(path.join(args[3], 'extension-sources.bzl'), rendered.extensionSourcesBzl); + writeFileSync( + path.join(args[3], 'completed-supplier-artifacts.json'), + rendered.completedSupplierArtifacts, + ); + writeFileSync( + path.join(args[3], 'native-swift-source-input.json'), + rendered.nativeSwiftSourceInput, + ); + writeFileSync(path.join(args[3], 'native-apple-base-input.json'), rendered.nativeAppleBaseInput); + writeFileSync( + path.join(args[3], 'prepared-selected-products.json'), + rendered.preparedSelectedProducts, + ); + writeFileSync(path.join(args[3], 'BUILD.bazel'), rendered.build); + writeFileSync( + path.join(args[3], '.metadata-inputs.json'), + JSON.stringify({ + sourceInputs: metadata.inputs, + nativePublicationFiles: publicationInputs?.files ?? [], + }), + ); + writeFileSync( + path.join(args[3], '.metadata-directories.json'), + JSON.stringify(metadata.directories), + ); +} diff --git a/tools/release/bazel-release-metadata.test.mts b/tools/release/bazel-release-metadata.test.mts new file mode 100644 index 000000000..ade0129e6 --- /dev/null +++ b/tools/release/bazel-release-metadata.test.mts @@ -0,0 +1,1441 @@ +import { expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { validateExtensionTargetProfiles } from '../../src/extensions/contracts/extension-target-profiles.mts'; +import { + resolveNativeComponentClosure, + validateNativeComponentContract, +} from '../../src/extensions/tools/native-component-contract.mts'; +import { nativeCargoArtifactRows } from '../packaging/rust-native-targets.mts'; +import { + extensionGithubArtifactInputs, + loadReleaseMetadata, + nativeMobileComponentInputs, + nativeMobileMemberAliasInputs, + nativePublicationInputProjection, + nativeSupplierGithubArtifactDeclarations, + renderReleaseMetadata, + repositoryPath, +} from './bazel-release-metadata.mts'; +import { + databaseResourceArtifactRows, + nativeHelperArtifactRows, + nativeRuntimeArtifactRows, + validateExtensionCatalogRows, + wasixArtifactRows, +} from './release-artifact-targets.mts'; + +test('one per-run metadata snapshot projects exact completed suppliers without an auth claim', () => { + const source = { commit: 'a'.repeat(40), tree: 'b'.repeat(40) }; + const publication = { + product: 'liboliphaunt-wasix', + version: '0.3.2', + tagName: 'liboliphaunt-wasix-v0.3.2', + publicationSha: 'c'.repeat(40), + publicationTree: 'd'.repeat(40), + releaseSha: 'e'.repeat(40), + }; + const input = { source, supplierPublications: [publication] }; + const projected = nativePublicationInputProjection(input); + expect(projected).toEqual({ + prepared: false, + supplierPublications: { 'liboliphaunt-wasix@0.3.2': publication }, + seedControls: {}, + extensionFinalInputs: {}, + nativeAppleBase: null, + nativeSwiftSource: null, + nativeCurrentArtifacts: null, + supplierArtifacts: {}, + selectedProducts: [], + files: [], + }); + input.supplierPublications[0].publicationSha = 'f'.repeat(40); + expect(projected.supplierPublications['liboliphaunt-wasix@0.3.2'].publicationSha).toBe( + 'c'.repeat(40), + ); + for (const corrupt of [ + { source: { ...source, commit: 'main' } }, + { source, supplierPublications: [{ ...publication, tagName: 'latest' }] }, + { source, supplierPublications: [publication, publication] }, + { source, supplierPublications: [{ ...publication, authenticated: true }] }, + { source, ready: true }, + ]) + expect(() => nativePublicationInputProjection(corrupt)).toThrow(); + expect(nativePublicationInputProjection({ source })).toEqual({ + prepared: false, + supplierPublications: {}, + seedControls: {}, + extensionFinalInputs: {}, + nativeAppleBase: null, + nativeSwiftSource: null, + nativeCurrentArtifacts: null, + supplierArtifacts: {}, + selectedProducts: [], + files: [], + }); +}); + +test('the same immutable snapshot projects original final Files through the existing metadata aliases', () => { + const directory = mkdtempSync(path.join(os.tmpdir(), 'native-metadata-final-import-')); + try { + const file = (name: string) => { + const bytes = Buffer.from(`actual retained fixture ${name}`); + const source = path.join(directory, name); + writeFileSync(source, bytes); + return { + path: source, + size: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + producer: { + evidenceDigest: `sha256:${'a'.repeat(64)}`, + invocationId: 'original-native-invocation', + root: '//src/extensions/external/pgtap:native_github_shipping', + configuration: 'b'.repeat(64), + output: `bazel-out/cfg/bin/${name}`, + }, + }; + }; + const leaf = { + product: 'oliphaunt-extension-pgtap', + owner: 'oliphaunt-extension-pgtap', + version: '0.1.1', + family: 'native', + target: 'android-arm64-v8a', + github: [file('pgtap.tar.gz')], + npm: [], + cargo: [], + manifest: file('manifest.json'), + frozen: file('extension-artifacts.json'), + }; + const snapshot = { + source: { commit: 'c'.repeat(40), tree: 'd'.repeat(40) }, + extensionFinalInputs: [leaf], + }; + const projected = nativePublicationInputProjection(snapshot); + expect(projected.files).toHaveLength(3); + const saved = + projected.extensionFinalInputs['oliphaunt-extension-pgtap/native/android-arm64-v8a']; + expect(saved.github[0].producer).toEqual(leaf.github[0].producer); + expect(saved.github[0].path).toStartWith('@oliphaunt_metadata//:extension-final-inputs/'); + expect(projected.seedControls).toEqual({}); + expect(projected.supplierPublications).toEqual({}); + writeFileSync(leaf.github[0].path, 'substituted archive'); + expect(() => nativePublicationInputProjection(snapshot)).toThrow(/bytes differ/); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +function fixture(run: (root: string, write: (name: string, content: string) => void) => void) { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-domain-metadata-')); + const write = (name: string, content: string) => { + mkdirSync(path.dirname(path.join(root, name)), { recursive: true }); + writeFileSync(path.join(root, name), content); + }; + write( + 'release-please-config.json', + JSON.stringify({ + packages: { + 'src/native/runtime': { component: 'native' }, + 'src/wasix/runtime': { component: 'wasix' }, + 'src/extensions/external/example': { component: 'oliphaunt-extension-example' }, + }, + }), + ); + write( + '.release-please-manifest.json', + JSON.stringify({ + 'src/native/runtime': '1.2.3', + 'src/wasix/runtime': '2.3.4', + 'src/extensions/external/example': '3.4.5', + }), + ); + write( + 'src/native/runtime/release.toml', + 'id="native"\n[artifact_targets]\npreset="liboliphaunt-native"\ntargets=["linux-x64-gnu","android-arm64-v8a"]\n', + ); + write( + 'src/wasix/runtime/release.toml', + 'id="wasix"\n[artifact_targets]\npreset="liboliphaunt-wasix"\ntargets=["portable"]\n', + ); + write( + 'src/extensions/external/example/release.toml', + 'id="oliphaunt-extension-example"\nregistry_packages=["crates:example","npm:@oliphaunt/example"]\npublish_targets=["crates-io","npm"]\n[extension]\nclass="external"\nversioning="upstream-bound"\nsql_name="example"\n[extension.compatibility]\npostgres_major="18"\nextension_runtime_contract="src/extensions/contracts/contract.toml"\nnative_runtime_product="native"\nnative_runtime_version="1.0.0"\nwasix_runtime_product="wasix"\nwasix_runtime_version="2.0.0"\n[extension.source]\npath="src/extensions/external/example/source.toml"\n[compatibility_versions.native_runtime]\nsource_product="native"\npath="src/extensions/external/example/native-version"\nparser="raw"\n', + ); + write('src/extensions/external/example/native-version', '1.0.0\n'); + write( + 'src/extensions/external/example/source.toml', + `name="example"\nurl="https://github.com/upstream/example.git"\nbranch="0.8.2"\ncommit="${'a'.repeat(40)}"\nversion="0.8.2"\n[archive]\nsha256="${'c'.repeat(64)}"\n`, + ); + write( + 'src/extensions/contrib/carriers.toml', + 'logical_product="oliphaunt-extension-contrib-pg18"\nnative_owner="native"\nwasix_owner="wasix"\nmember_manifest="src/extensions/contrib/postgres18.toml"\nsource="src/third-party/postgres/source.toml"\ncontract="src/extensions/contracts/contract.toml"\n', + ); + write( + 'src/extensions/contrib/postgres18.toml', + '[[extensions]]\nid="member"\n"sql-name"="member"\npath="src/extensions/contrib/member"\n', + ); + write( + 'src/third-party/postgres/source.toml', + `[postgresql]\nversion="18.4"\nurl="https://example.invalid/postgres.tar.gz"\nsha256="${'a'.repeat(64)}"\n`, + ); + write('src/extensions/contracts/contract.toml', 'postgres_major="18"\n'); + write( + 'src/extensions/catalog/native-components.toml', + 'schema="oliphaunt-native-components-v1"\nrequirements=[]\n[[components]]\nid="fixture"\nsource="fixture"\ndepends-on=[]\nruntime-files=[]\n[[components.link-units]]\nid="fixture"\narchive-candidates=["fixture/libfixture.a"]\n', + ); + write( + 'src/extensions/contracts/extension-target-profiles.toml', + `schema="oliphaunt-extension-artifact-target-profiles-v1" +[[profiles]] +id="fixture" +[[profiles.targets]] +target="linux-x64-gnu" +family="native" +kind="native-dynamic" +[[profiles.targets]] +target="android-arm64-v8a" +family="native" +kind="native-static-registry" +[[profiles.targets]] +target="wasix-portable" +family="wasix" +kind="wasix-runtime" +`, + ); + write( + 'src/extensions/catalog/extensions.source.json', + JSON.stringify({ extensions: [{ id: 'member' }, { id: 'example' }] }), + ); + write( + 'src/extensions/generated/extensions.catalog.json', + JSON.stringify({ + 'format-version': 1, + extensions: [ + { 'sql-name': 'member', 'native-module-file': 'member.so' }, + { 'sql-name': 'example' }, + ], + }), + ); + write( + 'src/extensions/generated/wasix/extensions.json', + readFileSync(path.join(root, 'src/extensions/generated/extensions.catalog.json'), 'utf8'), + ); + try { + run(root, write); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +test('native component projection preserves the parsed canonical source and watches its bytes', () => { + const file = 'src/extensions/catalog/native-components.toml'; + fixture((root) => { + const text = readFileSync(path.join(root, file), 'utf8'); + const metadata = loadReleaseMetadata(root); + expect(metadata.nativeComponents).toEqual(Bun.TOML.parse(text)); + expect(metadata.inputs[file]).toBe(text); + expect(renderReleaseMetadata(metadata, '@test//build_defs/release:identity.bzl').bzl).toContain( + 'NATIVE_COMPONENTS =', + ); + }); +}); + +test('WASIX extension projection preserves all canonical members and PostGIS support metadata', () => { + const root = path.resolve(import.meta.dirname, '../..'); + const file = 'src/extensions/generated/wasix/extensions.json'; + const source = readFileSync(path.join(root, file), 'utf8'); + const canonical = JSON.parse(source).extensions; + const catalog = JSON.parse( + readFileSync(path.join(root, 'src/extensions/generated/extensions.catalog.json'), 'utf8'), + ); + fixture((fixtureRoot, write) => { + write(file, source); + const metadata = loadReleaseMetadata(fixtureRoot); + expect(Object.keys(metadata.wasixExtensions)).toHaveLength(39); + expect(Object.keys(metadata.wasixExtensions).sort()).toEqual( + catalog.extensions.map((row) => row['sql-name']).sort(), + ); + for (const row of canonical) expect(metadata.wasixExtensions[row['sql-name']]).toEqual(row); + expect(metadata.wasixExtensions.postgis['native-support-modules']).toEqual([ + { + name: 'postgis_deps', + 'build-path': 'postgis/postgis/liboliphaunt_postgis_deps.so', + 'runtime-path': 'lib/postgresql/liboliphaunt_postgis_deps.so', + 'aot-file': 'postgis_deps-llvm-opta.bin.zst', + }, + ]); + expect(metadata.inputs[file]).toBe(source); + const rendered = renderReleaseMetadata(metadata, '@test//build_defs/release:identity.bzl'); + expect(rendered.bzl).toContain('WASIX_EXTENSIONS ='); + expect(rendered.bzl).toContain('"aot-file": "postgis_deps-llvm-opta.bin.zst"'); + expect(rendered.extensionSourcesBzl).not.toContain('WASIX_EXTENSIONS'); + }); +}); + +test('all canonical 39 mobile members use the existing component resolver for all three targets', () => { + const root = path.resolve(import.meta.dirname, '../..'); + const raw = Bun.TOML.parse( + readFileSync(path.join(root, 'src/extensions/catalog/native-components.toml'), 'utf8'), + ); + const catalog = JSON.parse( + readFileSync(path.join(root, 'src/extensions/generated/extensions.catalog.json'), 'utf8'), + ); + const sqlNames = catalog.extensions.map((row) => row['sql-name']); + const profiles = validateExtensionTargetProfiles( + Bun.TOML.parse( + readFileSync( + path.join(root, 'src/extensions/contracts/extension-target-profiles.toml'), + 'utf8', + ), + ), + ).targets; + const projected = nativeMobileComponentInputs(raw, sqlNames, profiles); + const descriptors = validateExtensionCatalogRows(catalog); + const aliases = nativeMobileMemberAliasInputs(descriptors); + expect(Object.keys(aliases)).toHaveLength(39); + const contract = validateNativeComponentContract(raw, { + checkSourcePaths: false, + knownExtensions: new Set(sqlNames), + targetProfiles: new Map(profiles.map((row) => [row.target, `${row.family}\0${row.kind}`])), + }); + expect(Object.keys(projected)).toHaveLength(39); + for (const sqlName of sqlNames) { + expect(Object.keys(projected[sqlName])).toHaveLength(3); + for (const target of Object.keys(projected[sqlName])) { + expect(aliases[sqlName], `${sqlName}/${target}`).toEqual( + sqlName === 'postgis' + ? { + difference: 'oliphaunt_static_postgis_3_difference', + pg_finfo_difference: 'pg_finfo_oliphaunt_static_postgis_3_difference', + } + : {}, + ); + } + const assets = extensionGithubArtifactInputs( + { artifactProduct: 'fixture', owner: 'native', version: '1.2.3', sqlNames: [sqlName] }, + profiles, + descriptors, + projected, + ); + for (const [target, actual] of Object.entries(projected[sqlName])) { + const expected = resolveNativeComponentClosure(contract, { + extension: sqlName, + family: 'native', + kind: 'native-static-registry', + target, + }); + expect(actual).toEqual({ + linkUnits: expected.linkUnits, + runtimeFiles: expected.runtimeFiles, + }); + const targetAssets = assets.filter((row) => row.target === target); + expect(targetAssets.filter((row) => row.kind === 'runtime')).toHaveLength(1); + const module = descriptors.get(sqlName)?.['native-module-file']; + expect(targetAssets.filter((row) => row.kind === 'ios-xcframework')).toHaveLength( + target === 'ios-xcframework' && typeof module === 'string' ? 1 : 0, + ); + expect( + targetAssets + .filter((row) => row.kind === 'ios-dependency-xcframework') + .map((row) => row.identity), + ).toEqual( + target === 'ios-xcframework' && module !== undefined ? [...expected.linkUnits].sort() : [], + ); + } + } +}); + +test('canonical extension GitHub projection uses only supplied root metadata and owner versions', () => { + fixture((root, write) => { + const profiles = 'src/extensions/contracts/extension-target-profiles.toml'; + write( + 'src/native/runtime/release.toml', + 'id="native"\n[artifact_targets]\npreset="liboliphaunt-native"\ntargets=["linux-x64-gnu","android-arm64-v8a","android-x86_64","ios-xcframework"]\n', + ); + write( + profiles, + `${readFileSync(path.join(root, profiles), 'utf8')} +[[profiles.targets]] +target="android-x86_64" +family="native" +kind="native-static-registry" +[[profiles.targets]] +target="ios-xcframework" +family="native" +kind="native-static-registry" +`, + ); + const components = 'src/extensions/catalog/native-components.toml'; + write( + components, + `${readFileSync(path.join(root, components), 'utf8').replace('requirements=[]\n', '')} +[[requirements]] +extension="example" +family="native" +kind="native-static-registry" +targets=["ios-xcframework"] +roots=["fixture"] +`, + ); + write( + 'src/extensions/generated/extensions.catalog.json', + JSON.stringify({ + 'format-version': 1, + extensions: [ + { 'sql-name': 'member', 'native-module-file': 'member.so' }, + { 'sql-name': 'example', 'native-module-file': 'different-stem.so' }, + ], + }), + ); + const metadata = loadReleaseMetadata(root); + const external = metadata.extensionGithubArtifacts.filter( + (row) => row.artifactProduct === 'oliphaunt-extension-example', + ); + expect(external.map((row) => row.name)).toEqual([ + 'oliphaunt-extension-example-3.4.5-native-android-arm64-v8a-runtime.tar.gz', + 'oliphaunt-extension-example-3.4.5-native-android-x86_64-runtime.tar.gz', + 'oliphaunt-extension-example-3.4.5-native-ios-dependency-fixture-xcframework.zip', + 'oliphaunt-extension-example-3.4.5-native-ios-xcframework.zip', + 'oliphaunt-extension-example-3.4.5-native-ios-runtime.tar.gz', + 'oliphaunt-extension-example-3.4.5-native-linux-x64-gnu-runtime.tar.gz', + 'oliphaunt-extension-example-3.4.5-wasix-portable.tar.zst', + 'oliphaunt-extension-example-3.4.5-manifest.json', + 'oliphaunt-extension-example-3.4.5-manifest.properties', + 'oliphaunt-extension-example-3.4.5-swift-extension-carrier.json', + 'oliphaunt-extension-example-3.4.5-release-assets.sha256', + ]); + expect(external.every((row) => row.owner === 'oliphaunt-extension-example')).toBe(true); + expect( + external.filter((row) => row.control).every((row) => row.role === 'github-release-metadata'), + ).toBe(true); + expect( + external.filter((row) => !row.control).every((row) => row.role === 'github-release-asset'), + ).toBe(true); + expect(external.find((row) => row.kind === 'ios-xcframework')?.identity).toBe('different-stem'); + const contrib = metadata.extensionGithubArtifacts.filter( + (row) => row.artifactProduct === 'oliphaunt-extension-contrib-pg18', + ); + for (const family of ['native', 'wasix']) { + const owned = contrib.filter((row) => row.family === family); + expect(owned.length).toBeGreaterThan(0); + const version = metadata.products[metadata.contribOwners[family]].version; + expect( + owned.every( + (row) => row.owner === metadata.contribOwners[family] && row.version === version, + ), + ).toBe(true); + expect(owned.every((row) => row.name.includes(`-${version}-`))).toBe(true); + expect(owned.filter((row) => row.control).map((row) => row.kind)).toEqual( + family === 'native' + ? ['manifest-json', 'manifest-properties', 'swift-extension-carrier', 'checksums'] + : ['manifest-json', 'manifest-properties', 'checksums'], + ); + } + expect(renderReleaseMetadata(metadata, '@test//build_defs/release:identity.bzl').bzl).toContain( + 'EXTENSION_GITHUB_ARTIFACTS =', + ); + expect( + renderReleaseMetadata(metadata, '@test//build_defs/release:identity.bzl').extensionSourcesBzl, + ).not.toContain('EXTENSION_GITHUB_ARTIFACTS'); + const descriptors = new Map([['example', { 'native-module-file': 'example.so' }]]); + expect(() => + extensionGithubArtifactInputs( + { artifactProduct: 'example', owner: 'example', version: '1.2.3', sqlNames: ['example'] }, + [{ target: 'ios-xcframework', family: 'native', kind: 'native-static-registry' }], + descriptors, + {}, + ), + ).toThrow('missing example/ios-xcframework'); + }); +}); + +test('native component acquisition projection watches canonical source bytes', () => { + fixture((root, write) => { + const component = 'src/extensions/catalog/native-components.toml'; + write( + component, + readFileSync(path.join(root, component), 'utf8').replaceAll('fixture', 'openssl'), + ); + const sourcePath = 'src/third-party/openssl/source.toml'; + const text = `name="openssl"\nurl="https://example.invalid/openssl.git"\ncommit="${'d'.repeat(40)}"\n`; + write(sourcePath, text); + const metadata = loadReleaseMetadata(root); + expect(metadata.nativeComponentSources).toEqual({ openssl: Bun.TOML.parse(text) }); + expect(metadata.inputs[sourcePath]).toBe(text); + expect(renderReleaseMetadata(metadata, '@test//build_defs/release:identity.bzl').bzl).toContain( + 'NATIVE_COMPONENT_SOURCES =', + ); + }); +}); + +test('WASIX artifact projection follows explicit release targets without loading another source tree', () => { + fixture((root, write) => { + const config = JSON.parse(readFileSync(path.join(root, 'release-please-config.json'), 'utf8')); + const manifest = JSON.parse( + readFileSync(path.join(root, '.release-please-manifest.json'), 'utf8'), + ); + config.packages['src/wasix/postgres-tools'] = { component: 'postgres-tools-wasix' }; + manifest['src/wasix/postgres-tools'] = '4.5.6'; + write('release-please-config.json', JSON.stringify(config)); + write('.release-please-manifest.json', JSON.stringify(manifest)); + write( + 'src/wasix/postgres-tools/release.toml', + 'id="postgres-tools-wasix"\n[artifact_targets]\npreset="postgres-tools-wasix"\ntargets=["portable","macos-arm64"]\n', + ); + const metadata = loadReleaseMetadata(root); + expect(metadata.wasixArtifacts).toEqual( + wasixArtifactRows('postgres-tools-wasix', ['portable', 'macos-arm64']), + ); + expect( + metadata.wasixArtifacts + .filter((row) => row.kind !== 'checksums') + .map((row) => row.target) + .sort(), + ).toEqual(['macos-arm64', 'portable']); + expect(renderReleaseMetadata(metadata, '@test//build_defs/release:identity.bzl').bzl).toContain( + 'WASIX_ARTIFACTS =', + ); + write( + 'src/wasix/postgres-tools/release.toml', + 'id="postgres-tools-wasix"\n[artifact_targets]\npreset="postgres-tools-wasix"\ntargets=["android-x86_64"]\n', + ); + const rejected = Bun.spawnSync([ + process.execPath, + '--eval', + `import { loadReleaseMetadata } from ${JSON.stringify(import.meta.filename.replace('.test.mts', '.mts'))}; loadReleaseMetadata(${JSON.stringify(root)});`, + ]); + expect(rejected.exitCode).toBe(1); + expect(rejected.stderr.toString()).toContain('unknown artifact target(s): android-x86_64'); + }); +}); + +test('native helper projection uses canonical artifact rows and explicit descriptor targets', () => { + fixture((root, write) => { + const config = JSON.parse(readFileSync(path.join(root, 'release-please-config.json'), 'utf8')); + const manifest = JSON.parse( + readFileSync(path.join(root, '.release-please-manifest.json'), 'utf8'), + ); + config.packages['src/native/broker'] = { component: 'oliphaunt-broker' }; + manifest['src/native/broker'] = '4.5.6'; + write('release-please-config.json', JSON.stringify(config)); + write('.release-please-manifest.json', JSON.stringify(manifest)); + write( + 'src/native/broker/release.toml', + 'id="oliphaunt-broker"\nregistry_packages=["crates:oliphaunt-broker-linux-x64-gnu"]\n[artifact_targets]\npreset="oliphaunt-broker"\ntargets=["linux-x64-gnu"]\n', + ); + const metadata = loadReleaseMetadata(root); + expect(metadata.nativeHelperArtifacts).toEqual( + nativeHelperArtifactRows('oliphaunt-broker', ['linux-x64-gnu']), + ); + expect( + metadata.nativeHelperArtifacts.find((row) => row.kind === 'broker-helper'), + ).toMatchObject({ + target: 'linux-x64-gnu', + executable_relative_path: 'bin/oliphaunt-broker', + }); + const rendered = renderReleaseMetadata(metadata, '@//build_defs/release:identity.bzl'); + expect(rendered.bzl).toContain('NATIVE_HELPER_ARTIFACTS'); + expect(rendered.extensionSourcesBzl).not.toContain('NATIVE_HELPER_ARTIFACTS'); + const apple = renderReleaseMetadata( + { + ...metadata, + nativeHelperArtifacts: nativeHelperArtifactRows('oliphaunt-broker', ['macos-arm64']), + }, + '@//build_defs/release:identity.bzl', + ); + expect(apple.bzl).toContain('"npm_libc": None'); + expect(apple.bzl).not.toContain('undefined'); + write( + 'src/native/broker/release.toml', + 'id="oliphaunt-broker"\nregistry_packages=["crates:oliphaunt-broker-linux-x64-gnu"]\n', + ); + expect(() => loadReleaseMetadata(root)).toThrow('has no canonical artifact targets'); + }); +}); + +test('runtime and resource construction reuse canonical artifact rows and captured contracts', () => { + fixture((root, write) => { + const config = JSON.parse(readFileSync(path.join(root, 'release-please-config.json'), 'utf8')); + const manifest = JSON.parse( + readFileSync(path.join(root, '.release-please-manifest.json'), 'utf8'), + ); + config.packages['src/native/postgres-tools'] = { component: 'postgres-tools-native' }; + config.packages['src/database-resources'] = { component: 'database-resources' }; + config.packages['src/wasix/runtime'].component = 'liboliphaunt-wasix'; + manifest['src/native/postgres-tools'] = '4.5.6'; + manifest['src/database-resources'] = '5.6.7'; + write('release-please-config.json', JSON.stringify(config)); + write('.release-please-manifest.json', JSON.stringify(manifest)); + write( + 'src/wasix/runtime/release.toml', + readFileSync(path.join(root, 'src/wasix/runtime/release.toml'), 'utf8').replace( + 'id="wasix"', + 'id="liboliphaunt-wasix"', + ), + ); + write( + 'src/extensions/contrib/carriers.toml', + readFileSync(path.join(root, 'src/extensions/contrib/carriers.toml'), 'utf8').replace( + 'wasix_owner="wasix"', + 'wasix_owner="liboliphaunt-wasix"', + ), + ); + write( + 'src/native/postgres-tools/release.toml', + 'id="postgres-tools-native"\nregistry_packages=["npm:@oliphaunt/tools-linux-x64-gnu"]\n[artifact_targets]\npreset="postgres-tools-native"\ntargets=["linux-x64-gnu"]\n', + ); + write( + 'src/database-resources/release.toml', + 'id="database-resources"\nregistry_packages=["npm:@oliphaunt/icu"]\n[compatibility_versions.liboliphaunt-wasix]\nsource_product="liboliphaunt-wasix"\npath="src/database-resources/seeds/wasix/Cargo.toml"\nparser="toml:package.metadata.oliphaunt.runtime-version"\n', + ); + write( + 'src/database-resources/seeds/wasix/Cargo.toml', + '[package.metadata.oliphaunt]\nruntime-version="2.3.4"\n', + ); + const profiles: Record> = { standard: {} }; + const contract = { + profiles, + compatibilityKeys: { native: { 'linux-x64-gnu': 'fixture' } }, + }; + const contractPath = 'src/database-resources/contracts/contract.json'; + write(contractPath, JSON.stringify(contract)); + const metadata = loadReleaseMetadata(root); + expect(metadata.nativeRuntimeArtifacts).toEqual( + nativeRuntimeArtifactRows('postgres-tools-native', ['linux-x64-gnu']), + ); + expect(metadata.databaseResourceContract).toEqual(contract); + expect(metadata.inputs[contractPath]).toBe(JSON.stringify(contract)); + expect(metadata.databaseResourceArtifacts).toEqual(databaseResourceArtifactRows(contract)); + expect(metadata.databaseResourceArtifacts).toHaveLength(7); + const rendered = renderReleaseMetadata(metadata, '@//build_defs/release:identity.bzl'); + expect(rendered.bzl).toContain('NATIVE_RUNTIME_ARTIFACTS'); + expect(rendered.bzl).toContain('DATABASE_RESOURCE_CONTRACT'); + expect(rendered.bzl).toContain('DATABASE_RESOURCE_ARTIFACTS'); + expect(rendered.extensionSourcesBzl).not.toContain('DATABASE_RESOURCE_ARTIFACTS'); + contract.profiles.icu = {}; + write(contractPath, JSON.stringify(contract)); + const changed = loadReleaseMetadata(root); + expect(changed.databaseResourceArtifacts).toHaveLength(11); + expect( + renderReleaseMetadata(changed, '@//build_defs/release:identity.bzl').extensionSourcesBzl, + ).toBe(rendered.extensionSourcesBzl); + for (const [product, targets, diagnostic] of [ + ['postgres-tools-native', ['unsupported'], 'unknown artifact target'], + ['native', ['linux-x64-gnu'], 'not a native runtime product'], + ] as const) { + const rejected = Bun.spawnSync([ + process.execPath, + '--eval', + `import { nativeRuntimeArtifactRows } from ${JSON.stringify(path.join(import.meta.dir, 'release-artifact-targets.mts'))}; nativeRuntimeArtifactRows(${JSON.stringify(product)}, ${JSON.stringify(targets)});`, + ]); + expect(rejected.exitCode).toBe(1); + expect(rejected.stderr.toString()).toContain(diagnostic); + } + }); +}); + +test('publication versions, upstream versions and contrib ownership stay independent', () => { + fixture((root, write) => { + const initial = loadReleaseMetadata(root); + expect(initial.products['oliphaunt-extension-example'].version).toBe('3.4.5'); + expect(initial.extensionSources.example.version).toBe('0.8.2'); + expect(initial.contribOwners).toEqual({ native: 'native', wasix: 'wasix' }); + expect(initial.products.native.artifact_targets).toEqual({ + preset: 'liboliphaunt-native', + targets: ['linux-x64-gnu', 'android-arm64-v8a'], + }); + expect(initial.products.wasix.artifact_targets).toEqual({ + preset: 'liboliphaunt-wasix', + targets: ['portable'], + }); + expect(initial.products['oliphaunt-extension-example'].compatibility_versions).toEqual({ + native: '1.0.0', + }); + expect(initial.inputs['src/extensions/external/example/native-version']).toBe('1.0.0\n'); + expect(initial.inputs['src/extensions/external/example/recipe.toml']).toBeNull(); + expect(initial.products['oliphaunt-extension-example'].registry_packages).toEqual([ + 'crates:example', + 'npm:@oliphaunt/example', + ]); + expect(initial.products['oliphaunt-extension-example'].publish_targets).toEqual([ + 'crates-io', + 'npm', + ]); + expect(initial.extensionCompatibility.example).toEqual({ + postgres_major: '18', + extension_runtime_contract: 'src/extensions/contracts/contract.toml', + native_runtime_product: 'native', + native_runtime_version: '1.0.0', + wasix_runtime_product: 'wasix', + wasix_runtime_version: '2.0.0', + }); + const external = initial.extensionReleaseMetadata.find((row) => row.sqlName === 'example'); + expect(external.compatibility).toMatchObject({ + nativeRuntimeVersion: '1.0.0', + wasixRuntimeVersion: '2.0.0', + }); + expect(external.sourceIdentity).toMatchObject({ + kind: 'external', + branch: '0.8.2', + commit: 'a'.repeat(40), + }); + const member = initial.extensionReleaseMetadata.find((row) => row.sqlName === 'member'); + expect(member.compatibility).toMatchObject({ + nativeRuntimeVersion: '1.2.3', + wasixRuntimeVersion: '2.3.4', + }); + expect(member.memberPath).toBe('src/extensions/contrib'); + const rendered = renderReleaseMetadata(initial, '@//build_defs/release:identity.bzl'); + expect(rendered.bzl).toContain('EXTENSION_RELEASE_METADATA'); + expect(rendered.extensionSourcesBzl).not.toContain('EXTENSION_RELEASE_METADATA'); + write( + 'src/extensions/external/example/recipe.toml', + 'sql_name="example"\n[artifacts]\ndata_files=["data.txt"]\n', + ); + expect(loadReleaseMetadata(root).extensionRecipes.example.artifacts).toEqual({ + data_files: ['data.txt'], + }); + write('src/extensions/external/example/recipe.toml', 'sql_name="wrong"\n'); + expect(() => loadReleaseMetadata(root)).toThrow('recipe disagrees'); + }); +}); + +test('dependency acquisition records exact pins and directory membership without publication policy', () => { + fixture((root, write) => { + const directory = 'src/extensions/external/example/dependencies'; + expect(loadReleaseMetadata(root).directories[directory]).toBeNull(); + const file = `${directory}/dependency/source.toml`; + const source = + 'name="dependency"\nkind="archive"\nurl="https://example.invalid/dependency.tar.gz"\nsha256="' + + 'a'.repeat(64) + + '"\nstrip_prefix="dependency-1.0"\nmirror_url="https://mirror.invalid/dependency.tar.gz"\n'; + write(file, source); + const metadata = loadReleaseMetadata(root); + expect(metadata.directories[directory]).toEqual(['dependency']); + expect(metadata.inputs[file]).toBe(source); + expect(metadata.extensionDependencies.example.dependency).toEqual(Bun.TOML.parse(source)); + const rendered = renderReleaseMetadata(metadata, '@//build_defs/release:identity.bzl'); + expect(rendered.extensionSourcesBzl).toContain('EXTENSION_DEPENDENCIES'); + expect(rendered.extensionSourcesBzl).toContain('mirror_url'); + const retargeted = structuredClone(metadata); + retargeted.products['oliphaunt-extension-example'].version = '3.5.0'; + retargeted.products['oliphaunt-extension-example'].registry_packages.push( + 'npm:@oliphaunt/example-other', + ); + retargeted.extensionCompatibility.example.native_runtime_version = '1.2.3'; + retargeted.products['oliphaunt-extension-example'].compatibility_versions.native = '1.2.3'; + expect( + renderReleaseMetadata(retargeted, '@//build_defs/release:identity.bzl').extensionSourcesBzl, + ).toBe(rendered.extensionSourcesBzl); + retargeted.extensionDependencies.example.dependency.sha256 = 'b'.repeat(64); + expect( + renderReleaseMetadata(retargeted, '@//build_defs/release:identity.bzl').extensionSourcesBzl, + ).not.toBe(rendered.extensionSourcesBzl); + mkdirSync(path.join(root, directory, 'missing-pin')); + expect(() => loadReleaseMetadata(root)).toThrow('source.toml'); + }); +}); + +test('final carrier projection expands contrib through canonical ownership and declared targets', () => { + fixture((root, write) => { + const initial = loadReleaseMetadata(root); + expect(initial.products.native.registry_packages).toEqual([]); + const name = '@oliphaunt/extension-contrib-pg18-linux-x64-gnu'; + expect(initial.publicationCarriers.find((row) => row.name === name)).toEqual({ + product: 'native', + ecosystem: 'npm', + name, + version: '1.2.3', + target: 'linux-x64-gnu', + role: 'platform-leaf', + }); + expect(initial.inputs['src/extensions/generated/extensions.catalog.json']).toContain( + 'member.so', + ); + expect( + renderReleaseMetadata(initial, '@//build_defs/release:identity.bzl').extensionSourcesBzl, + ).not.toContain('PUBLICATION_CARRIERS'); + write( + '.release-please-manifest.json', + JSON.stringify({ + 'src/native/runtime': '1.2.4', + 'src/wasix/runtime': '2.3.4', + 'src/extensions/external/example': '3.4.5', + }), + ); + const bumped = loadReleaseMetadata(root); + expect(bumped.publicationCarriers.find((row) => row.name === name)?.version).toBe('1.2.4'); + expect( + bumped.publicationCarriers.find((row) => row.name === '@oliphaunt/example')?.version, + ).toBe('3.4.5'); + const profiles = 'src/extensions/contracts/extension-target-profiles.toml'; + write( + profiles, + readFileSync(path.join(root, profiles), 'utf8').replace('linux-x64-gnu', 'macos-arm64'), + ); + expect(() => loadReleaseMetadata(root)).toThrow('not backed by runtime artifact metadata'); + }); +}); + +test('invalid or ambiguous metadata fails instead of producing partial identities', () => { + fixture((root, write) => { + const carrier = readFileSync(path.join(root, 'src/extensions/contrib/carriers.toml'), 'utf8'); + write( + 'src/extensions/contrib/carriers.toml', + carrier.replace('native_owner="native"', 'native_owner="unknown"'), + ); + expect(() => loadReleaseMetadata(root)).toThrow('unknown contrib release owner'); + write( + 'src/extensions/contrib/carriers.toml', + carrier.replace('wasix_owner="wasix"', 'wasix_owner="native"'), + ); + expect(() => loadReleaseMetadata(root)).toThrow('distinct release owners'); + write('src/extensions/contrib/carriers.toml', carrier); + write( + 'src/extensions/contrib/postgres18.toml', + '[[extensions]]\nid="member"\n[[extensions]]\nid="member"\n', + ); + expect(() => loadReleaseMetadata(root)).toThrow('duplicate contrib member'); + }); + fixture((root, write) => { + write('src/native/runtime/release.toml', 'id="different"\n'); + expect(() => loadReleaseMetadata(root)).toThrow('disagrees'); + write( + 'src/native/runtime/release.toml', + 'id="native"\n[artifact_targets]\npreset="liboliphaunt-native"\ntargets=["linux-x64-gnu","android-arm64-v8a"]\n', + ); + write( + '.release-please-manifest.json', + JSON.stringify({ + 'src/native/runtime': '01.2.3', + 'src/wasix/runtime': '2.3.4', + 'src/extensions/external/example': '3.4.5', + }), + ); + expect(() => loadReleaseMetadata(root)).toThrow('stable release version'); + }); +}); + +test('native Cargo rows retain only declared supported Rust carriers', () => { + const product = 'liboliphaunt-native'; + const targets = ['linux-x64-gnu', 'android-arm64-v8a', 'macos-arm64']; + const packages = [ + 'crates:liboliphaunt-native-linux-x64-gnu', + 'crates:liboliphaunt-native-macos-arm64', + 'npm:@oliphaunt/liboliphaunt-linux-x64-gnu', + ]; + expect(nativeCargoArtifactRows(product, targets, packages)).toEqual([ + { + sourceProduct: product, + target: 'linux-x64-gnu', + packageKind: 'crates', + packageName: 'liboliphaunt-native-linux-x64-gnu', + }, + { + sourceProduct: product, + target: 'macos-arm64', + packageKind: 'crates', + packageName: 'liboliphaunt-native-macos-arm64', + }, + ]); + expect(() => nativeCargoArtifactRows(product, targets, packages.slice(1))).toThrow( + 'missing declared Cargo artifact liboliphaunt-native-linux-x64-gnu', + ); + expect(() => + nativeCargoArtifactRows(product, targets, [ + ...packages, + 'crates:liboliphaunt-native-android-arm64-v8a', + ]), + ).toThrow('unsupported native Cargo target'); +}); + +test('authored compatibility mirrors must resolve to one installed requirement', () => { + fixture((root, write) => { + const descriptor = 'src/extensions/external/example/release.toml'; + const original = readFileSync(path.join(root, descriptor), 'utf8'); + write( + descriptor, + `${original} +[compatibility_versions.native_mirror] +source_product="native" +path="src/extensions/external/example/mirror-version" +parser="json:version" +`, + ); + write('src/extensions/external/example/mirror-version', '{"version":"1.0.0"}'); + expect( + loadReleaseMetadata(root).products['oliphaunt-extension-example'].compatibility_versions, + ).toEqual({ native: '1.0.0' }); + write('src/extensions/external/example/mirror-version', '{"version":"1.1.0"}'); + expect(() => loadReleaseMetadata(root)).toThrow( + 'conflicting compatibility versions for native', + ); + write(descriptor, original.replace('source_product="native"', 'source_product="missing"')); + expect(() => loadReleaseMetadata(root)).toThrow('unknown compatibility product missing'); + }); +}); + +test('Cargo source-library requirements remain distinct from independently held installed helper pins', () => { + fixture((root, write) => { + const config = JSON.parse(readFileSync(path.join(root, 'release-please-config.json'), 'utf8')); + const versions = JSON.parse( + readFileSync(path.join(root, '.release-please-manifest.json'), 'utf8'), + ); + config.packages['src/native/broker'] = { component: 'oliphaunt-broker' }; + config.packages['src/native/sdks/rust'] = { component: 'oliphaunt-rust' }; + versions['src/native/broker'] = '0.4.0'; + versions['src/native/sdks/rust'] = '0.3.3'; + write('release-please-config.json', JSON.stringify(config)); + write('.release-please-manifest.json', JSON.stringify(versions)); + write( + 'src/native/broker/release.toml', + 'id="oliphaunt-broker"\nregistry_packages=["crates:oliphaunt-broker","crates:oliphaunt-broker-linux-x64-gnu"]\n[artifact_targets]\npreset="oliphaunt-broker"\ntargets=["linux-x64-gnu"]\n', + ); + write( + 'src/native/sdks/rust/release.toml', + `id="oliphaunt-rust" +[compatibility_versions.broker_library] +source_product="oliphaunt-broker" +path="src/native/sdks/rust/Cargo.toml" +parser="toml:dependencies.oliphaunt-broker.version" +[compatibility_versions.broker_workspace_library] +source_product="oliphaunt-broker" +path="Cargo.toml" +parser="toml:workspace.dependencies.oliphaunt-broker.version" +[compatibility_versions.broker_runtime] +source_product="oliphaunt-broker" +path="src/native/sdks/rust/Cargo.toml" +parser="toml:package.metadata.oliphaunt.broker-version" +[compatibility_versions.broker_runtime_constant] +source_product="oliphaunt-broker" +path="src/native/sdks/rust/src/broker.rs" +parser="rust-const:BROKER_RELEASE_VERSION" +`, + ); + const manifest = `[package] +name="oliphaunt" +version="0.3.3" +[package.metadata.oliphaunt] +broker-version="0.3.1" +[dependencies] +oliphaunt-broker={path="../../broker",version="0.4.0"} +`; + write('src/native/sdks/rust/Cargo.toml', manifest); + write( + 'Cargo.toml', + '[workspace.dependencies]\noliphaunt-broker={path="src/native/broker",version="0.4.0"}\n', + ); + write('src/native/sdks/rust/src/broker.rs', 'const BROKER_RELEASE_VERSION: &str = "0.3.1";\n'); + const metadata = loadReleaseMetadata(root); + expect(metadata.products['oliphaunt-broker'].version).toBe('0.4.0'); + expect(metadata.products['oliphaunt-rust'].compatibility_versions).toEqual({ + 'oliphaunt-broker': '0.3.1', + }); + expect(metadata.inputs['src/native/sdks/rust/Cargo.toml']).toBe(manifest); + expect(metadata.inputs['Cargo.toml']).toContain('version="0.4.0"'); + expect(renderReleaseMetadata(metadata, '@identity//:identity.bzl').bzl).toContain('0.3.1'); + // The registry source library and platform helper remain distinct packages + // even when the current library is consumed through Cargo's registry. + write('src/native/sdks/rust/Cargo.toml', manifest.replace('path="../../broker",', '')); + expect(loadReleaseMetadata(root).products['oliphaunt-rust'].compatibility_versions).toEqual({ + 'oliphaunt-broker': '0.3.1', + }); + write( + 'src/native/sdks/rust/Cargo.toml', + manifest.replace('version="0.4.0"', 'version="0.5.0"'), + ); + expect(loadReleaseMetadata(root).products['oliphaunt-rust'].compatibility_versions).toEqual({ + 'oliphaunt-broker': '0.3.1', + }); + const heldLibrary = manifest + .replace('path="../../broker",', '') + .replace('version="0.4.0"', 'version="0.3.1"') + .replace('broker-version="0.3.1"', 'broker-version="0.3.2"'); + write('src/native/sdks/rust/Cargo.toml', heldLibrary); + write('src/native/sdks/rust/src/broker.rs', 'const BROKER_RELEASE_VERSION: &str = "0.3.2";\n'); + expect(loadReleaseMetadata(root).products['oliphaunt-rust'].compatibility_versions).toEqual({ + 'oliphaunt-broker': '0.3.2', + }); + const descriptor = readFileSync(path.join(root, 'src/native/sdks/rust/release.toml'), 'utf8'); + write( + 'src/native/sdks/rust/release.toml', + `${descriptor} +[compatibility_versions.broker_platform] +source_product="oliphaunt-broker" +path="src/native/sdks/rust/Cargo.toml" +parser="toml:dependencies.broker-carrier.version" +`, + ); + const platform = + '\nbroker-carrier={package="oliphaunt-broker-linux-x64-gnu",version="0.3.2"}\n'; + write('src/native/sdks/rust/Cargo.toml', heldLibrary + platform); + expect(loadReleaseMetadata(root).products['oliphaunt-rust'].compatibility_versions).toEqual({ + 'oliphaunt-broker': '0.3.2', + }); + write( + 'src/native/sdks/rust/Cargo.toml', + heldLibrary + platform.replace('version="0.3.2"', 'version="0.3.3"'), + ); + expect(() => loadReleaseMetadata(root)).toThrow( + 'conflicting compatibility versions for oliphaunt-broker', + ); + }); +}); + +test('Git sources and dependencies derive archives from their exact commit and declared remote', () => { + fixture((root, write) => { + write( + 'src/extensions/external/example/dependencies/library/source.toml', + `name="logical-library"\nurl="https://gitlab.gnome.org/upstream/library.git"\nmirror_url="https://github.com/mirror/physical-library.git/"\ncommit="${'b'.repeat(40)}"\n[archive]\nsha256="${'d'.repeat(64)}"\n`, + ); + const metadata = loadReleaseMetadata(root); + const acquisition = (value = metadata) => { + const rendered = renderReleaseMetadata(value, '@//build_defs/release:identity.bzl'); + const [sources, dependencies] = rendered.extensionSourcesBzl + .slice('EXTENSION_SOURCES = '.length) + .split('\n\nEXTENSION_DEPENDENCIES = '); + return { sources: JSON.parse(sources), dependencies: JSON.parse(dependencies) }; + }; + const initial = acquisition(); + expect(initial.sources.example).toEqual({ + name: 'example', + url: 'https://github.com/upstream/example.git', + commit: 'a'.repeat(40), + archive: { + url: `https://codeload.github.com/upstream/example/tar.gz/${'a'.repeat(40)}`, + sha256: 'c'.repeat(64), + strip_prefix: `example-${'a'.repeat(40)}`, + }, + }); + expect(initial.dependencies.example.library).toMatchObject({ + name: 'logical-library', + url: 'https://gitlab.gnome.org/upstream/library.git', + mirror_url: 'https://github.com/mirror/physical-library.git/', + commit: 'b'.repeat(40), + archive: { + url: `https://codeload.github.com/mirror/physical-library/tar.gz/${'b'.repeat(40)}`, + sha256: 'd'.repeat(64), + strip_prefix: `physical-library-${'b'.repeat(40)}`, + }, + }); + expect(metadata.extensionDependencies.example.library.archive).toEqual({ + sha256: 'd'.repeat(64), + }); + for (const remote of [ + 'https://github.com/upstream/example.git', + 'https://github.com/upstream/example', + 'https://github.com/upstream/example/', + 'https://github.com/upstream/example.git/', + ]) { + const changed = structuredClone(metadata); + changed.extensionSources.example.url = remote; + expect(acquisition(changed).sources.example.archive).toEqual(initial.sources.example.archive); + } + const changed = structuredClone(metadata); + changed.extensionSources.example.commit = 'e'.repeat(40); + changed.extensionDependencies.example.library.commit = 'f'.repeat(40); + const next = acquisition(changed); + expect(next.sources.example.archive).toEqual({ + ...initial.sources.example.archive, + url: `https://codeload.github.com/upstream/example/tar.gz/${'e'.repeat(40)}`, + strip_prefix: `example-${'e'.repeat(40)}`, + }); + expect(next.dependencies.example.library.archive).toEqual({ + ...initial.dependencies.example.library.archive, + url: `https://codeload.github.com/mirror/physical-library/tar.gz/${'f'.repeat(40)}`, + strip_prefix: `physical-library-${'f'.repeat(40)}`, + }); + }); +}); + +test('Git source and dependency acquisition requires a checksum without independent archive authority', () => { + fixture((root, write) => { + write( + 'src/extensions/external/example/dependencies/library/source.toml', + `name="library"\nurl="https://github.com/upstream/library.git"\ncommit="${'b'.repeat(40)}"\n[archive]\nsha256="${'d'.repeat(64)}"\n`, + ); + const metadata = loadReleaseMetadata(root); + for (const location of ['source', 'dependency']) { + const invalidRows = [ + { archive: undefined }, + { archive: { sha256: 'latest' } }, + { archive: { sha256: 'c'.repeat(64), url: 'https://other.invalid/archive.tar.gz' } }, + { archive: { sha256: 'c'.repeat(64), strip_prefix: 'other-root' } }, + { commit: 'main' }, + { url: 'https://gitlab.gnome.org/upstream/library.git' }, + { mirror_url: 'https://mirror.invalid/library.git' }, + ]; + for (const invalid of invalidRows) { + const changed = structuredClone(metadata); + const source = + location === 'source' + ? changed.extensionSources.example + : changed.extensionDependencies.example.library; + Object.assign(source, invalid); + expect(() => + renderReleaseMetadata(changed, '@//build_defs/release:identity.bzl'), + ).toThrow(); + } + } + }); +}); + +test('metadata paths cannot escape; rendered identities have no construction dependencies', () => { + for (const value of ['', '../elsewhere', '/absolute', 'a/../b', 'a//b', 'a\\b', 'a\0b']) { + expect(() => repositoryPath(value)).toThrow('inside the repository'); + } + fixture((root) => { + const metadata = loadReleaseMetadata(root); + const rendered = renderReleaseMetadata(metadata, '@//build_defs/release:identity.bzl'); + const reversed = { + ...metadata, + products: Object.fromEntries(Object.entries(metadata.products).reverse()), + }; + expect(renderReleaseMetadata(reversed, '@//build_defs/release:identity.bzl')).toEqual(rendered); + expect(rendered.build).not.toContain('deps'); + expect(rendered.bzl).toContain('CONTRIB_OWNERS'); + const bumped = structuredClone(metadata); + bumped.products.native.version = '1.2.4'; + const next = renderReleaseMetadata(bumped, '@//build_defs/release:identity.bzl'); + expect(next.bzl).not.toBe(rendered.bzl); + expect(next.extensionSourcesBzl).toBe(rendered.extensionSourcesBzl); + bumped.extensionSources.example.product = 'other-owner'; + bumped.extensionSources.example.branch = 'other-branch'; + bumped.extensionSources.example['extension-control'] = { 'default-version': '0.8.3' }; + const ownershipChanged = renderReleaseMetadata(bumped, '@//build_defs/release:identity.bzl'); + expect(ownershipChanged.bzl).not.toBe(next.bzl); + expect(ownershipChanged.extensionSourcesBzl).toBe(rendered.extensionSourcesBzl); + bumped.extensionSources.example.mirror_url = 'https://github.com/mirror/example.git'; + const mirrored = renderReleaseMetadata(bumped, '@//build_defs/release:identity.bzl'); + expect(mirrored.extensionSourcesBzl).toContain( + '"mirror_url": "https://github.com/mirror/example.git"', + ); + expect(mirrored.extensionSourcesBzl).toContain( + '"url": "https://github.com/upstream/example.git"', + ); + expect(mirrored.extensionSourcesBzl).toContain( + '"commit": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"', + ); + expect(mirrored.extensionSourcesBzl).not.toBe(ownershipChanged.extensionSourcesBzl); + bumped.extensionSources.example.mirror_url = 'https://github.com/other/example.git'; + const mirrorChanged = renderReleaseMetadata(bumped, '@//build_defs/release:identity.bzl'); + expect(mirrorChanged.extensionSourcesBzl).not.toBe(mirrored.extensionSourcesBzl); + bumped.extensionSources.example.commit = 'b'.repeat(40); + expect( + renderReleaseMetadata(bumped, '@//build_defs/release:identity.bzl').extensionSourcesBzl, + ).not.toBe(mirrorChanged.extensionSourcesBzl); + expect(() => renderReleaseMetadata(metadata, '//build_defs/release:identity.bzl')).toThrow( + 'repository-qualified', + ); + }); +}); + +test('prepared selection remains fact-only, validates canonical IDs and renders existing aliases', () => { + const source = { commit: 'a'.repeat(40), tree: 'b'.repeat(40) }; + const selected = ['native']; + const projected = nativePublicationInputProjection({ source, selectedProducts: selected }); + expect(projected.prepared).toBe(true); + const empty = nativePublicationInputProjection({ source, selectedProducts: [] }); + expect(empty.prepared).toBe(true); + expect(nativePublicationInputProjection({ source }).prepared).toBe(false); + selected.push('wasix'); + expect(projected.selectedProducts).toEqual(['native']); + for (const selectedProducts of [['native', 'native'], ['../outside'], null, {}, ['native', 4]]) + expect(() => nativePublicationInputProjection({ source, selectedProducts })).toThrow(); + fixture((root) => { + const metadata = loadReleaseMetadata(root); + expect(renderReleaseMetadata(metadata, '@test//build_defs/release:identity.bzl').bzl).toContain( + 'PREPARED_NATIVE_INPUTS = False', + ); + expect( + renderReleaseMetadata(metadata, '@test//build_defs/release:identity.bzl', empty).bzl, + ).toContain('PREPARED_NATIVE_INPUTS = True'); + expect( + renderReleaseMetadata(metadata, '@test//build_defs/release:identity.bzl', projected).bzl, + ).toContain('PREPARED_NATIVE_SELECTED_PRODUCTS = ["native"]'); + expect(() => + renderReleaseMetadata(metadata, '@test//build_defs/release:identity.bzl', { + ...projected, + selectedProducts: ['absent'], + }), + ).toThrow(/unknown prepared/); + }); +}); + +test('the same snapshot retains actual original Swift source File references and aliases', () => { + const directory = mkdtempSync(path.join(os.tmpdir(), 'native-swift-metadata-')); + try { + const file = (name: string, root: string, member?: string) => { + const bytes = Buffer.from( + name === 'oliphaunt-react-native-ios-carriers.json' + ? JSON.stringify({ + schema: 'oliphaunt-react-native-ios-carrier-v1', + base: { + product: 'liboliphaunt-native', + version: '0.3.3', + tag: 'liboliphaunt-native-v0.3.3', + }, + extensions: [], + carriers: [], + }) + : 'retained original ' + name, + ); + const source = path.join(directory, name); + writeFileSync(source, bytes); + return { + path: source, + size: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + producer: { + evidenceDigest: 'sha256:' + 'c'.repeat(64), + invocationId: 'original-swift-job', + root, + configuration: 'd'.repeat(64), + output: 'bazel-out/cfg/bin/source_package/' + (member ? 'release-tree' : name), + }, + ...(member ? { member } : {}), + }; + }; + const nativeSwiftSource = { + owner: 'oliphaunt-swift', + version: '0.8.2', + archive: file( + 'Oliphaunt-source.zip', + '//src/native/sdks/swift:shipping_Oliphaunt-source_zip', + ), + carrier: file( + 'oliphaunt-react-native-ios-carriers.json', + '//src/native/sdks/swift:shipping_oliphaunt-react-native-ios-carriers_json', + 'src/sdks/swift/Carriers/oliphaunt-react-native-ios-carriers.json', + ), + ownerCatalog: file( + 'extension-owner-catalog.json', + '//src/native/sdks/swift:shipping_extension-owner-catalog_json', + ), + bindingsArchive: file( + 'oliphaunt-swift-0.8.2-bindings.xcframework.zip', + '//src/native/sdks/swift:shipping_bindings', + ), + }; + const snapshot = { + source: { commit: 'a'.repeat(40), tree: 'b'.repeat(40) }, + nativeSwiftSource, + }; + const projected = nativePublicationInputProjection(snapshot); + expect(projected.files).toHaveLength(4); + expect(projected.nativeSwiftSource.nativeVersion).toBe('0.3.3'); + expect(projected.nativeSwiftSource.carrier.member).toBe(nativeSwiftSource.carrier.member); + expect(projected.nativeSwiftSource.archive.producer).toEqual( + nativeSwiftSource.archive.producer, + ); + expect(projected.nativeSwiftSource.ownerCatalog.path).toStartWith( + '@oliphaunt_metadata//:native-swift-source/ownerCatalog/', + ); + fixture((fixtureRoot) => { + const rendered = renderReleaseMetadata( + loadReleaseMetadata(fixtureRoot), + '@//build_defs/release:identity.bzl', + projected, + ); + expect(JSON.parse(rendered.nativeSwiftSourceInput)).toEqual(projected.nativeSwiftSource); + expect(JSON.parse(rendered.nativeAppleBaseInput)).toEqual(projected.nativeAppleBase); + expect(JSON.parse(rendered.preparedSelectedProducts)).toEqual(projected.selectedProducts); + expect(rendered.build).toContain('"native-apple-base-input.json"'); + expect(rendered.build).toContain('"prepared-selected-products.json"'); + expect(rendered.build).toContain('"native-swift-source-input.json"'); + }); + for (const change of [ + (value) => (value.nativeSwiftSource.owner = 'other'), + (value) => (value.nativeSwiftSource.archive.member = 'inside'), + (value) => (value.nativeSwiftSource.ownerCatalog.path = value.nativeSwiftSource.archive.path), + ]) { + const corrupt = structuredClone(snapshot); + change(corrupt); + expect(() => nativePublicationInputProjection(corrupt)).toThrow(); + } + writeFileSync(nativeSwiftSource.archive.path, 'substituted source bytes'); + expect(() => nativePublicationInputProjection(snapshot)).toThrow(/bytes differ/); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('supplied-root supplier projection includes declared Swift and extension carriers without reading controller source', () => { + fixture((root, write) => { + const config = JSON.parse(readFileSync(path.join(root, 'release-please-config.json'), 'utf8')); + config.packages['src/native/sdks/swift'] = { component: 'oliphaunt-swift' }; + write('release-please-config.json', JSON.stringify(config)); + const versions = JSON.parse( + readFileSync(path.join(root, '.release-please-manifest.json'), 'utf8'), + ); + versions['src/native/sdks/swift'] = '9.8.7'; + write('.release-please-manifest.json', JSON.stringify(versions)); + write( + 'src/native/sdks/swift/release.toml', + 'id="oliphaunt-swift"\npublish_targets=["github-release-assets","swift-package-source-tag"]\n', + ); + for (const product of [ + 'src/native/runtime', + 'src/wasix/runtime', + 'src/extensions/external/example', + ]) { + const file = product + '/release.toml'; + const contents = readFileSync(path.join(root, file), 'utf8'); + write( + file, + contents.includes('publish_targets=') + ? contents.replace( + 'publish_targets=["crates-io","npm"]', + 'publish_targets=["crates-io","npm","github-release-assets"]', + ) + : contents.replace( + '\n[artifact_targets]', + '\npublish_targets=["github-release-assets"]\n[artifact_targets]', + ), + ); + } + const metadata = loadReleaseMetadata(root); + const declarations = nativeSupplierGithubArtifactDeclarations(metadata); + const swift = declarations.filter(({ product }) => product === 'oliphaunt-swift'); + expect(swift.map(({ asset }) => asset).sort()).toEqual([ + 'oliphaunt-swift-{version}-bindings.xcframework.zip', + 'oliphaunt-swift-{version}-release-assets.sha256', + ]); + expect( + declarations.filter(({ product }) => product === 'oliphaunt-extension-example').length, + ).toBeGreaterThan(0); + const bytes = Buffer.from('supplied-root physical File fixture; no qualification claim'); + const supplierArtifacts = declarations.map(({ product, asset }) => { + const version = metadata.products[product].version; + const file = path.join(root, asset.replaceAll('{version}', version)); + writeFileSync(file, bytes); + return { + publication: { + product, + version, + tagName: product + '-v' + version, + publicationSha: 'a'.repeat(40), + publicationTree: 'b'.repeat(40), + releaseSha: 'c'.repeat(40), + }, + artifact: 'github-release:' + asset.replaceAll('{version}', version), + file: { + path: file, + size: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + }, + }; + }); + const snapshot = { + source: { commit: 'd'.repeat(40), tree: 'e'.repeat(40) }, + supplierArtifacts, + }; + expect( + Object.keys(nativePublicationInputProjection(snapshot, metadata).supplierArtifacts), + ).toHaveLength(declarations.length); + const binding = supplierArtifacts.find(({ artifact }) => + artifact.endsWith('bindings.xcframework.zip'), + )!; + expect(() => + nativePublicationInputProjection( + { + ...snapshot, + supplierArtifacts: [{ ...binding, artifact: 'github-release:invented.zip' }], + }, + metadata, + ), + ).toThrow('filename differs'); + const sourceOnly = structuredClone(metadata); + sourceOnly.products['oliphaunt-swift'].publish_targets = ['swift-package-source-tag']; + const retained = nativePublicationInputProjection( + { ...snapshot, supplierArtifacts: [binding] }, + sourceOnly, + ); + expect(Object.values(retained.supplierArtifacts)[0].publication).toEqual(binding.publication); + expect(Object.values(retained.supplierArtifacts)[0]).not.toHaveProperty('authenticated'); + }); +}); + +test('late current carrier projection distinguishes absent transport from partial Mac Files and checks the canonical source catalog', () => { + const directory = mkdtempSync(path.join(os.tmpdir(), 'native-current-metadata-')); + try { + const source = { commit: 'a'.repeat(40), tree: 'b'.repeat(40) }; + fixture((root) => { + const metadata = loadReleaseMetadata(root); + const version = metadata.products.native.version; + const name = `runtime-${version}-macos.tar.gz`; + const physical = path.join(directory, name); + const bytes = Buffer.from('original physical protocol fixture'); + writeFileSync(physical, bytes); + const row = { + product: 'native', + version, + artifact: `github-release:${name}`, + configuration: 'macos-arm64', + source, + file: { + path: physical, + size: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + producer: { + evidenceDigest: 'sha256:' + 'c'.repeat(64), + invocationId: 'original-mac-producer', + root: '//src/native/runtime:native_github_shipping', + configuration: 'd'.repeat(64), + output: `bazel-out/cfg/bin/${name}`, + }, + }, + }; + // The supplied snapshot's canonical row renderer owns this test declaration. + metadata.nativeRuntimeArtifacts = [ + { + product: 'native', + asset: 'runtime-{version}-macos.tar.gz', + surfaces: ['github-release'], + }, + ]; + metadata.products.native.publish_targets = ['github-release']; + expect( + nativePublicationInputProjection({ source }, metadata).nativeCurrentArtifacts, + ).toBeNull(); + const absent = renderReleaseMetadata(metadata, '@//build_defs/release:identity.bzl'); + expect(absent.bzl).toContain('NATIVE_CURRENT_ARTIFACTS = None'); + const projected = nativePublicationInputProjection( + { source, nativeCurrentArtifacts: [row] }, + metadata, + ); + const key = `native/${version}/github-release:${name}`; + expect(Object.keys(projected.nativeCurrentArtifacts!)).toEqual([key]); + expect(projected.files[0].source).toBe(physical); + expect(projected.nativeCurrentArtifacts![key].file.producer).toEqual(row.file.producer); + expect( + projected.nativeCurrentArtifacts![`native/${version}/github-release:missing-linux.tar.gz`], + ).toBeUndefined(); + expect( + renderReleaseMetadata(metadata, '@//build_defs/release:identity.bzl', projected).bzl, + ).toContain('NATIVE_CURRENT_ARTIFACTS = {'); + expect( + nativePublicationInputProjection({ source, nativeCurrentArtifacts: [] }, metadata) + .nativeCurrentArtifacts, + ).toEqual({}); + for (const change of [ + (value) => (value.version = '9.0.0'), + (value) => (value.product = 'wasix'), + (value) => (value.source.tree = 'e'.repeat(40)), + (value) => (value.file.sha256 = '0'.repeat(64)), + (value) => (value.artifact = 'github-release:unknown.tar.gz'), + ]) { + const changed = structuredClone(row); + change(changed); + expect(() => + nativePublicationInputProjection({ source, nativeCurrentArtifacts: [changed] }, metadata), + ).toThrow(); + } + }); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); diff --git a/tools/release/bazel-shipping-inputs.mts b/tools/release/bazel-shipping-inputs.mts new file mode 100644 index 000000000..10dc5cf64 --- /dev/null +++ b/tools/release/bazel-shipping-inputs.mts @@ -0,0 +1,826 @@ +/** Declared construction inputs, not a publication or compatibility certificate. */ +import { createHash } from 'node:crypto'; +import type { CompletedPublication } from './completed-release-publication.mts'; + +export type NativeShippingSupplier = { + product: string; + version: string; + /** The supplier's delivery slot, independent of its consumer's configuration. */ + configuration: string; + binding: 'compiled-input' | 'abi-contract'; + origin: + | { + kind: 'current-source'; + /** Original authenticated final archive, for a consumed imported File. */ + producer?: { + evidenceDigest: string; + invocationId: string; + root: string; + configuration: string; + output: string; + /** Original archive's leaf path when its producer output is a Tree. */ + member?: string; + }; + } + | { kind: 'completed-publication'; publication: CompletedPublication; artifact: string }; + /** Imported Files bind the authenticated outer File, or one of its archive members. */ + files: { path: string; member?: string }[]; +}; + +export interface ShippingProductInputs { + version: string; + packages: Record[]; + inputs: string[]; + actions: string[]; +} + +export interface ShippingInputView { + schema: 'oliphaunt-bazel-construction-inputs-v2'; + products: Record; + /** Complete reached action inputs, excluding only declared virtual Middleman outputs. */ + physicalInputs: string[]; + /** Source leaves and explicit consumed supplier values; intermediates remain in the DAG. */ + captureInputs: string[]; +} + +export type ConfiguredFileWriteCheck = ( + output: { path: string; owner: string }, + configuration: string, + context: string, +) => void; + +type Row = Record; +function row(value: unknown): Row { + if (!value || Array.isArray(value) || typeof value !== 'object') + throw new Error('expected an object'); + return value as Row; +} +function array(value: unknown): unknown[] { + if (!Array.isArray(value)) throw new Error('expected an array'); + return value; +} +function text(value: unknown): string { + if (typeof value !== 'string' || !value) throw new Error('expected a nonempty string'); + return value; +} +function id(value: unknown): string { + if (typeof value !== 'number' && typeof value !== 'string') throw new Error('missing aquery id'); + return String(value); +} +function index(value: unknown): Map { + const result = new Map(); + for (const valueRow of array(value ?? [])) { + const item = row(valueRow); + const key = id(item.id); + if (result.has(key)) throw new Error(`duplicate aquery id ${key}`); + result.set(key, item); + } + return result; +} +function required(map: Map, key: string): T { + const value = map.get(key); + if (value === undefined) throw new Error(`incomplete aquery graph: missing ${key}`); + return value; +} +/** Bazel prints the main repository as //, @// or @@// across its query/event APIs. */ +export function canonicalShippingLabel(value: unknown): string { + return text(value).replace(/^@@?\/\//, '//'); +} + +/** The one declared private Apple document needed by foreign final construction. */ +export function isNativeAppleBaseInputRoot(root: { + label: string; + package: { + product: string; + ecosystem: string; + configuration: string; + name: string; + role: string; + outputs: { path: string }[]; + }; +}) { + const pkg = root.package; + return ( + canonicalShippingLabel(root.label) === '//src/native/runtime:apple_ios_manifest_shipping' && + pkg.product === 'liboliphaunt-native' && + pkg.ecosystem === 'internal' && + pkg.configuration === 'ios-xcframework' && + pkg.name === 'ios.json' && + pkg.role === 'apple-base-ios-manifest-input' && + pkg.outputs.length === 1 && + pkg.outputs[0].path.startsWith('bazel-out/') && + pkg.outputs[0].path.endsWith('/apple_release_assets/ios.json') + ); +} + +function canonical(value: unknown): string { + if (Array.isArray(value)) return `[${value.map(canonical).join(',')}]`; + if (value && typeof value === 'object') { + return `{${Object.entries(value) + .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)) + .map(([key, child]) => `${JSON.stringify(key)}:${canonical(child)}`) + .join(',')}}`; + } + return JSON.stringify(value); +} + +/** Structural completed-origin facts only; the controller authenticates their public bytes. */ +export function validateNativeSupplierPublications(value: unknown): CompletedPublication[] { + const seen = new Set(); + return array(value).map((raw) => { + const publication = row(raw); + if ( + Object.keys(publication).sort().join(',') !== + 'product,publicationSha,publicationTree,releaseSha,tagName,version' || + publication.tagName !== `${text(publication.product)}-v${text(publication.version)}` || + ![publication.publicationSha, publication.publicationTree, publication.releaseSha].every( + (sha) => typeof sha === 'string' && /^[a-f0-9]{40}$/u.test(sha), + ) + ) + throw new Error('native suppliers require an exact canonical completed publication'); + const key = `${publication.product}@${publication.version}`; + if (seen.has(key)) throw new Error('duplicate completed supplier publication'); + seen.add(key); + return structuredClone(publication) as unknown as CompletedPublication; + }); +} + +/** Structural provider contract only; actual File/origin binding is checked separately. */ +export function validateNativeShippingSuppliers(value: unknown): NativeShippingSupplier[] { + const exactFields = (value: unknown, names: string[]) => { + const object = row(value); + if (Object.keys(object).sort().join(',') !== names.sort().join(',')) + throw new Error('native suppliers require exact typed fields'); + return object; + }; + const relative = (value: unknown) => { + const path = text(value); + if ( + path.startsWith('/') || + /[\\\u0000-\u001f\u007f]/u.test(path) || + path.normalize('NFC') !== path || + path.split('/').some((part) => !part || part === '.' || part === '..') + ) + throw new Error('native suppliers require safe declared File/member paths'); + return path; + }; + const seen = new Set(); + return array(value).map((raw) => { + const supplier = exactFields(raw, [ + 'product', + 'version', + 'configuration', + 'binding', + 'origin', + 'files', + ]); + for (const key of ['product', 'version', 'configuration']) text(supplier[key]); + if (!['compiled-input', 'abi-contract'].includes(text(supplier.binding))) + throw new Error('native supplier has invalid binding'); + const origin = row(supplier.origin); + if (origin.kind === 'current-source') { + exactFields(origin, Object.hasOwn(origin, 'producer') ? ['kind', 'producer'] : ['kind']); + if (Object.hasOwn(origin, 'producer')) { + const producerFields = [ + 'evidenceDigest', + 'invocationId', + 'root', + 'configuration', + 'output', + ]; + if (Object.hasOwn(row(origin.producer), 'member')) producerFields.push('member'); + const producer = exactFields(origin.producer, producerFields); + if (!/^sha256:[a-f0-9]{64}$/u.test(text(producer.evidenceDigest))) + throw new Error('current supplier requires the authenticated evidence digest'); + for (const name of ['invocationId', 'root', 'configuration']) text(producer[name]); + relative(producer.output); + if (Object.hasOwn(producer, 'member')) relative(producer.member); + } + } else if (origin.kind === 'completed-publication') { + exactFields(origin, ['kind', 'publication', 'artifact']); + const publication = validateNativeSupplierPublications([origin.publication])[0]; + if (publication.product !== supplier.product || publication.version !== supplier.version) + throw new Error('native suppliers require an exact canonical completed publication'); + relative(origin.artifact); + } else throw new Error('native supplier requires an explicit physical origin'); + const key = canonical({ + product: supplier.product, + binding: supplier.binding, + configuration: supplier.configuration, + origin, + }); + if (seen.has(key)) throw new Error('duplicate native supplier binding'); + seen.add(key); + const files = array(supplier.files); + if (!files.length) throw new Error('native supplier requires actual consumed Files'); + const names = new Set(); + for (const rawFile of files) { + const archiveMember = + (origin.kind === 'completed-publication' || Object.hasOwn(origin, 'producer')) && + Object.hasOwn(row(rawFile), 'member'); + const file = exactFields(rawFile, archiveMember ? ['path', 'member'] : ['path']); + const path = relative(file.path); + if (names.has(path)) throw new Error('duplicate native supplier File'); + names.add(path); + if (archiveMember) relative(file.member); + } + return structuredClone(supplier) as NativeShippingSupplier; + }); +} + +function aqueryFileGraph(raw: unknown) { + const graph = row(raw); + const fragments = index(graph.pathFragments); + const artifacts = index(graph.artifacts); + const targets = index(graph.targets); + const depSets = index(graph.depSetOfFiles); + const configurations = index(graph.configuration); + const artifactPaths = new Map(); + const fragmentPath = (key: string, visiting = new Set()): string => { + if (visiting.has(key)) throw new Error('cycle in aquery paths'); + visiting.add(key); + const fragment = required(fragments, key); + const segment = text(fragment.label); + if (segment.includes('/') || segment === '..' || segment === '.') + throw new Error('invalid aquery path segment'); + return fragment.parentId + ? `${fragmentPath(id(fragment.parentId), visiting)}/${segment}` + : segment; + }; + for (const [key, artifact] of artifacts) + artifactPaths.set(key, fragmentPath(id(artifact.pathFragmentId))); + // Reuse each depset's own validated IDs, without retaining expanded input closures. + const directInputs = new Map(); + const inputChildren = new Map(); + const inputsOf = (action: Row): Set => { + const result = new Set(); + const visited = new Set(); + const visit = (key: string, stack: Set) => { + if (stack.has(key)) throw new Error('cycle in aquery input dep sets'); + if (visited.has(key)) return; + const item = required(depSets, key); + stack.add(key); + let children = inputChildren.get(key); + if (children === undefined) { + children = []; + for (const value of array(item.transitiveDepSetIds ?? [])) { + const child = id(value); + visit(child, stack); + children.push(child); + } + inputChildren.set(key, children); + } else for (const child of children) visit(child, stack); + let direct = directInputs.get(key); + if (direct === undefined) { + direct = []; + for (const artifact of array(item.directArtifactIds ?? [])) { + const artifactId = id(artifact); + required(artifactPaths, artifactId); + direct.push(artifactId); + } + directInputs.set(key, direct); + } + for (const artifact of direct) result.add(artifact); + stack.delete(key); + visited.add(key); + }; + for (const key of array(action.inputDepSetIds ?? [])) visit(id(key), new Set()); + return result; + }; + return { + graph, + targets, + configurations, + artifactPaths, + depSets, + directInputs, + inputChildren, + inputsOf, + }; +} + +/** Actual TestRunner input closure and input-free FileWrite outputs of its configured target. */ +export function createConfiguredAqueryTargetInputResolver(raw: unknown) { + const { graph, targets, configurations, artifactPaths, inputsOf } = aqueryFileGraph(raw); + const producers = new Map(); + const actionsByLabel = new Map(); + for (const rawAction of array(graph.actions ?? [])) { + const action = row(rawAction); + for (const output of array(action.outputIds ?? [])) { + const key = id(output); + required(artifactPaths, key); + const previous = producers.get(key); + if (previous && canonical(previous) !== canonical(action)) + throw new Error('native qualification has conflicting aquery producers'); + producers.set(key, action); + } + const label = canonicalShippingLabel(required(targets, id(action.targetId)).label); + const actions = actionsByLabel.get(label); + if (actions) actions.push(action); + else actionsByLabel.set(label, [action]); + } + return (label: string, configuration: string) => { + const inputs = new Set(); + const written = new Set(); + const tests: Row[] = []; + for (const action of actionsByLabel.get(canonicalShippingLabel(label)) ?? []) { + if (text(required(configurations, id(action.configurationId)).checksum) !== configuration) + continue; + if (action.mnemonic === 'TestRunner') tests.push(action); + if (action.mnemonic === 'FileWrite' && inputsOf(action).size === 0) + for (const output of array(action.outputIds ?? [])) + written.add(required(artifactPaths, id(output))); + } + if (!tests.length) + throw new Error('native qualification requires its actual configured TestRunner action'); + const visited = new Set(); + const visit = (key: string, stack: Set) => { + if (stack.has(key)) throw new Error('cycle in native qualification TestRunner inputs'); + if (visited.has(key)) return; + const file = required(artifactPaths, key); + inputs.add(file); + const producer = producers.get(key); + // Runfiles infrastructure expands runtime Files. An APK or package producer + // belongs to construction; its compiler inputs are not installed-test inputs. + if ( + producer && + ['Middleman', 'SourceSymlinkManifest', 'SymlinkTree'].includes(text(producer.mnemonic)) + ) + for (const input of inputsOf(producer)) visit(input, new Set(stack).add(key)); + visited.add(key); + }; + for (const test of tests) for (const input of inputsOf(test)) visit(input, new Set()); + return { inputs, written }; + }; +} + +export function configuredAqueryTargetInputs(raw: unknown, label: string, configuration: string) { + return createConfiguredAqueryTargetInputResolver(raw)(label, configuration); +} + +export function buildShippingInputView( + exportValue: unknown, + aqueryValue: unknown, + { + configurationByOutput, + inspectPackageInputs, + inspectFileWrites, + }: { + configurationByOutput?: ReadonlyMap; + /** Check declared supplier Files against this package, never sibling roots. */ + inspectPackageInputs?: (pkg: Row, consumes: (path: string) => boolean) => void; + /** Check metadata against this call's validated graph without deriving another view. */ + inspectFileWrites?: (check: ConfiguredFileWriteCheck) => void; + } = {}, +): ShippingInputView { + const exported = row(exportValue); + if (exported.schema !== 'oliphaunt-bazel-shipping-v1') + throw new Error('unsupported shipping export'); + if (exported.scope !== 'construction') + throw new Error('shipping export must declare construction scope'); + const { + graph, + targets, + configurations, + artifactPaths, + depSets, + directInputs, + inputChildren, + inputsOf, + } = aqueryFileGraph(aqueryValue); + // Compare long shared SDK prefixes once; each action retains the same lexical path order. + const rankedPaths = [...new Set(artifactPaths.values())].sort(); + const pathRanks = new Map(rankedPaths.map((file, rank) => [file, rank])); + const artifactRanks = new Map( + [...artifactPaths].map(([artifact, file]) => [artifact, required(pathRanks, file)]), + ); + const producers = new Map(); + const products: ShippingInputView['products'] = {}; + const identities = new Set(); + const visitedByProduct = new Map>(); + const visitedActionsByProduct = new Map>(); + const visitedDepSetsByProduct = new Map>(); + const actionDescriptions = new Map(); + const sharedDefinitions = new Map(); + const physicalInputs = new Set(); + const captureInputs = new Set(); + const virtualOutputs = new Set(); + const describeAction = (action: Row) => ({ + ...Object.fromEntries( + Object.entries(action).filter( + ([name]) => + ![ + 'targetId', + 'configurationId', + 'inputDepSetIds', + 'outputIds', + 'primaryOutputId', + 'aspectDescriptorIds', + ].includes(name), + ), + ), + outputs: array(action.outputIds ?? []) + .map((output) => required(artifactPaths, id(output))) + .sort(), + ...(action.primaryOutputId === undefined + ? {} + : { primaryOutput: required(artifactPaths, id(action.primaryOutputId)) }), + }); + // Retain checkpoints for one previous sorted list, preserving its flat JSON digest. + let previousInputPaths: string[] = []; + let previousPrefixHashes = [createHash('sha256').update('[')]; + const digestInputPaths = (paths: string[]) => { + let common = 0; + while ( + common < paths.length && + common < previousInputPaths.length && + paths[common] === previousInputPaths[common] + ) + common++; + const chunkSize = 256; + const reusedChunks = Math.floor(common / chunkSize); + const hashes = previousPrefixHashes.slice(0, reusedChunks + 1); + const hash = hashes.at(-1)!.copy(); + for (let offset = reusedChunks * chunkSize; offset < paths.length; offset += chunkSize) { + const end = Math.min(offset + chunkSize, paths.length); + if (offset) hash.update(','); + hash.update(JSON.stringify(paths.slice(offset, end)).slice(1, -1)); + if (end % chunkSize === 0) hashes.push(hash.copy()); + } + previousInputPaths = paths; + previousPrefixHashes = hashes; + return hash.update(']').digest('hex'); + }; + const actionDescription = (action: Row, inputs: Set) => { + const cached = actionDescriptions.get(action); + if (cached !== undefined) return cached; + const paths = [...new Set([...inputs].map((input) => required(artifactRanks, input)))] + .sort((left, right) => left - right) + .map((rank) => rankedPaths[rank]!); + if (action.mnemonic === 'Middleman') + for (const output of array(action.outputIds ?? [])) + virtualOutputs.add(required(artifactPaths, id(output))); + const description = canonical({ + ...describeAction(action), + // Bind the exact sorted input set without retaining it in every description. + inputs: { + count: paths.length, + sha256: digestInputPaths(paths), + }, + target: canonicalShippingLabel(required(targets, id(action.targetId)).label), + }); + actionDescriptions.set(action, description); + return description; + }; + const sharedActionDefinition = (action: Row, artifactPath: string) => { + const cached = sharedDefinitions.get(action); + if (cached !== undefined) return cached; + text(action.actionKey); + required(configurations, id(action.configurationId)); + const outputs = array(action.outputIds).map(id); + const primary = id(action.primaryOutputId); + if (!outputs.includes(primary)) + throw new Error(`primary output is missing from outputs for ${artifactPath}`); + const inputs = inputsOf(action); + const definition = canonical({ + ...describeAction(action), + configurationId: action.configurationId, + inputs: [...inputs].map((input) => required(artifactPaths, input)), + outputs: outputs.map((output) => required(artifactPaths, output)), + }); + sharedDefinitions.set(action, definition); + return definition; + }; + for (const value of array(graph.actions ?? [])) { + const action = row(value); + required(targets, id(action.targetId)); + for (const output of array(action.outputIds ?? [])) { + const key = id(output); + const artifactPath = required(artifactPaths, key); + const previous = producers.get(key); + if (previous) { + // Bazel can repeat the same complete action record for one artifact ID. + // Ingest it idempotently without changing its producer or owner. + if (canonical(previous) !== canonical(action)) + throw new Error(`multiple producers for ${artifactPath}`); + sharedActionDefinition(action, artifactPath); + } else producers.set(key, action); + } + } + const byPath = new Map(); + for (const [key, artifactPath] of artifactPaths) + byPath.set(artifactPath, [...(byPath.get(artifactPath) ?? []), key]); + for (const [artifactPath, keys] of byPath) { + if (keys.length < 2) continue; + // Native rules may share identical copy actions across target owners. IDs + // differ, but keys, configuration and ordered physical inputs/outputs must + // agree. Incomplete declarations cannot prove Bazel action sharing. + const definitions = keys.map((key) => { + const action = producers.get(key); + if (!action) return 'source'; + return sharedActionDefinition(action, artifactPath); + }); + if (new Set(definitions).size !== 1) + throw new Error(`ambiguous artifact producers for ${artifactPath}`); + } + const configuredOutput = (output: Row, configurationsByOutput?: ReadonlyMap) => { + const keys = required(byPath, text(output.path)); + const key = keys.find((candidate) => { + const action = producers.get(candidate); + return ( + action && + canonicalShippingLabel(required(targets, id(action.targetId)).label) === + canonicalShippingLabel(output.owner) && + (configurationsByOutput?.has(text(output.path)) !== true || + required(configurations, id(action.configurationId)).checksum === + configurationsByOutput.get(text(output.path))) + ); + }); + if (!key) throw new Error(`shipping output owner disagrees with aquery: ${output.path}`); + return key; + }; + // Scalar reachability is shared for requested supplier Files only. Retaining + // transitive header sets or walking the full graph per package is unnecessary. + const supplierReachability = new Map< + string, + { artifacts: Map; depSets: Map } + >(); + const consumes = (output: string, path: string): boolean => { + if (!byPath.has(path) || virtualOutputs.has(path)) return false; + let memo = supplierReachability.get(path); + if (!memo) { + memo = { artifacts: new Map(), depSets: new Map() }; + supplierReachability.set(path, memo); + } + const fromArtifact = (key: string): boolean => { + const cached = memo.artifacts.get(key); + if (cached !== undefined) return cached; + const action = producers.get(key); + const reached = + !!action && array(action.inputDepSetIds ?? []).some((input) => fromDepSet(id(input))); + memo.artifacts.set(key, reached); + return reached; + }; + const fromDepSet = (key: string): boolean => { + const cached = memo.depSets.get(key); + if (cached !== undefined) return cached; + const item = required(depSets, key); + const reached = + array(item.directArtifactIds ?? []).some( + (input) => required(artifactPaths, id(input)) === path || fromArtifact(id(input)), + ) || array(item.transitiveDepSetIds ?? []).some((input) => fromDepSet(id(input))); + memo.depSets.set(key, reached); + return reached; + }; + return fromArtifact(output); + }; + for (const value of array(exported.packages)) { + const pkg = row(value); + const product = text(pkg.product); + const version = text(pkg.version); + const ecosystem = text(pkg.ecosystem); + const identity = `${ecosystem === 'github' ? `${product}:` : ''}${ecosystem}:${text(pkg.name)}${ecosystem === 'internal' ? `:${text(pkg.configuration)}` : ''}`; + if (identities.has(identity)) throw new Error(`duplicate shipping identity ${identity}`); + identities.add(identity); + if (products[product] && products[product].version !== version) + throw new Error(`inconsistent version for ${product}`); + const view = products[product] ?? { version, packages: [], inputs: [], actions: [] }; + products[product] = view; + const leaves = new Set(view.inputs); + const descriptions = new Set(view.actions); + const visited = visitedByProduct.get(product) ?? new Set(); + visitedByProduct.set(product, visited); + const visitedActions = visitedActionsByProduct.get(product) ?? new Set(); + visitedActionsByProduct.set(product, visitedActions); + const visitedDepSets = visitedDepSetsByProduct.get(product) ?? new Set(); + visitedDepSetsByProduct.set(product, visitedDepSets); + const visit = (key: string, stack: Set) => { + if (stack.has(key)) throw new Error('cycle in aquery producers'); + if (visited.has(key)) return; + const action = producers.get(key); + if (!action) { + const inputPath = required(artifactPaths, key); + if (inputPath.startsWith('bazel-out/')) + throw new Error(`missing generated input producer: ${inputPath}`); + leaves.add(inputPath); + captureInputs.add(inputPath); + } else if (!visitedActions.has(action)) { + const cached = actionDescriptions.get(action); + const inputs = cached === undefined ? inputsOf(action) : undefined; + stack.add(key); + const visitDepSet = (input: string) => { + if (visitedDepSets.has(input)) return; + for (const child of required(inputChildren, input)) visitDepSet(child); + for (const artifact of required(directInputs, input)) { + physicalInputs.add(required(artifactPaths, artifact)); + visit(artifact, stack); + } + visitedDepSets.add(input); + }; + for (const input of array(action.inputDepSetIds ?? [])) visitDepSet(id(input)); + // ActionKey describes action declarations, not consumed content or a remote-cache key. + descriptions.add(cached ?? actionDescription(action, inputs!)); + stack.delete(key); + visitedActions.add(action); + } + visited.add(key); + }; + const outputs = array(pkg.outputs); + const outputKeys: string[] = []; + if (!outputs.length) throw new Error(`empty shipping outputs for ${identity}`); + for (const outputValue of outputs) { + const output = row(outputValue); + const key = configuredOutput(output, configurationByOutput); + outputKeys.push(key); + visit(key, new Set()); + } + view.packages.push(pkg); + view.inputs = [...leaves].sort(); + view.actions = [...descriptions].sort(); + if (pkg.supplierInputs !== undefined) + for (const supplier of validateNativeShippingSuppliers(pkg.supplierInputs)) + for (const file of supplier.files) { + if (outputKeys.some((key) => consumes(key, file.path))) captureInputs.add(file.path); + } + inspectPackageInputs?.(pkg, (path) => outputKeys.some((key) => consumes(key, path))); + } + inspectFileWrites?.((output, configuration, context) => { + const key = configuredOutput(output, new Map([[output.path, configuration]])); + const action = required(producers, key); + const definition = row(JSON.parse(actionDescription(action, inputsOf(action)))); + if (definition.mnemonic !== 'FileWrite' || row(definition.inputs).count !== 0) + throw new Error(context); + }); + for (const view of Object.values(products)) + view.packages.sort((a, b) => { + const left = canonical(a); + const right = canonical(b); + return left < right ? -1 : left > right ? 1 : 0; + }); + return { + schema: 'oliphaunt-bazel-construction-inputs-v2', + products, + physicalInputs: [...physicalInputs].filter((path) => !virtualOutputs.has(path)).sort(), + captureInputs: [...captureInputs].sort(), + }; +} + +/** Each product uses its own completed baseline; unclassified paths require policy evidence. */ +export function selectShippingChanges( + beforeByProduct: Record, + after: ShippingInputView, + changedPathsByProduct: Record, +) { + if (after.schema !== 'oliphaunt-bazel-construction-inputs-v2') + throw new Error('unsupported construction input view'); + const affectedProducts: string[] = []; + const unclassified = new Set(); + const knownInputs = new Set([ + ...Object.values(beforeByProduct).flatMap((product) => product.inputs), + ...Object.values(after.products).flatMap((product) => product.inputs), + ]); + for (const product of [ + ...new Set([...Object.keys(beforeByProduct), ...Object.keys(after.products)]), + ].sort()) { + const before = beforeByProduct[product]; + const current = after.products[product]; + const changedPaths = changedPathsByProduct[product]; + if (before && !Array.isArray(changedPaths)) + throw new Error(`missing product baseline delta for ${product}`); + const paths = new Set([...(before?.inputs ?? []), ...(current?.inputs ?? [])]); + let touched = false; + for (const file of changedPaths ?? []) + if (paths.has(file)) { + touched = true; + } else if (!knownInputs.has(file)) unclassified.add(file); + if (!before || !current || touched || canonical(before) !== canonical(current)) + affectedProducts.push(product); + } + return { + affectedProducts, + unclassifiedPaths: [...unclassified].sort(), + }; +} + +type ObservedShippingProduct = { + product: { id: string; version: string }; + construction: readonly Row[]; +}; + +/** Project existing captured facts; this cannot authenticate a historical baseline. + * Shipping affectedness requests construction checks. Bazel independently schedules + * each action and test from its own declared inputs, including test-only changes. + */ +export function selectObservedShippingChanges( + current: readonly ObservedShippingProduct[], + baselines: Readonly>, + deliveries: readonly { product: string; deliveryStatus: string }[] = [], +) { + const project = ({ product, construction }: ObservedShippingProduct) => { + if ( + !construction.length || + construction.some( + (view) => + !Array.isArray(view.leafInputPaths) || + !Array.isArray(view.analysisInputPaths) || + !Array.isArray(view.analysisInputs), + ) + ) + return undefined; + const content = new Map>(); + const packages: Row[] = []; + const actions = new Set(); + for (const view of construction) { + const roots = array(view.roots).map(row); + const context = createHash('sha256') + .update( + canonical( + roots + .map((root) => canonical({ label: root.label, configuration: root.configuration })) + .sort(), + ), + ) + .digest('hex'); + packages.push(...roots.map((root) => row(root.package))); + for (const action of array(view.actions)) actions.add(text(action)); + const paths = new Set([ + ...array(view.leafInputPaths).map(text), + ...array(view.analysisInputPaths).map(text), + ]); + const captures = new Map(); + for (const raw of [...array(view.inputs), ...array(view.analysisInputs)]) { + const file = row(raw); + const path = text(file.path); + captures.set(path, [...(captures.get(path) ?? []), file]); + } + for (const path of paths) { + const capture = captures.get(path); + if (!capture?.length) throw new Error(`shipping causal File was not captured: ${path}`); + const identities = content.get(path) ?? new Set(); + for (const file of capture) + identities.add( + createHash('sha256') + .update(canonical({ context, members: file.members })) + .digest('hex'), + ); + content.set(path, identities); + } + } + packages.sort((left, right) => { + const a = canonical(left); + const b = canonical(right); + return a < b ? -1 : a > b ? 1 : 0; + }); + return { + view: { + version: product.version, + packages, + inputs: [...content.keys()].sort(), + actions: [...actions].sort(), + }, + content: new Map( + [...content].map(([path, identities]) => [path, canonical([...identities].sort())]), + ), + }; + }; + const before: Record = {}; + const after: ShippingInputView = { + schema: 'oliphaunt-bazel-construction-inputs-v2', + products: {}, + physicalInputs: [], + captureInputs: [], + }; + const deltas: Record = {}; + const unknownProducts: string[] = []; + for (const product of current) { + const id = text(product.product.id); + if (Object.hasOwn(after.products, id)) throw new Error('duplicate observed shipping product'); + const baseline = baselines[id]; + if (baseline && baseline.product.id !== id) + throw new Error('shipping baseline owner differs from its lookup'); + const previous = baseline && project(baseline); + const observed = project(product); + if (!previous || !observed) unknownProducts.push(id); + if (previous) before[id] = previous.view; + after.products[id] = observed?.view ?? { + version: product.product.version, + packages: [], + inputs: [], + actions: [], + }; + deltas[id] = previous + ? [...new Set([...previous.content.keys(), ...(observed?.content.keys() ?? [])])] + .filter((path) => previous.content.get(path) !== observed?.content.get(path)) + .sort() + : []; + } + const selection = selectShippingChanges(before, after, deltas); + const affectedProducts = [...new Set([...selection.affectedProducts, ...unknownProducts])].sort(); + for (const delivery of deliveries) { + if (!Object.hasOwn(after.products, delivery.product)) + throw new Error('shipping delivery exceeds the observed product inventory'); + if (delivery.deliveryStatus === 'different' && !affectedProducts.includes(delivery.product)) + throw new Error(`unchanged shipping inputs produced different delivery: ${delivery.product}`); + } + return { ...selection, affectedProducts, unknownProducts: unknownProducts.sort() }; +} diff --git a/tools/release/bazel-shipping-inputs.test.mts b/tools/release/bazel-shipping-inputs.test.mts new file mode 100644 index 000000000..566f9fc64 --- /dev/null +++ b/tools/release/bazel-shipping-inputs.test.mts @@ -0,0 +1,994 @@ +import { expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { + buildShippingInputView, + isNativeAppleBaseInputRoot, + selectObservedShippingChanges, + selectShippingChanges, +} from './bazel-shipping-inputs.mts'; + +test('only the exact declared private Apple File root is transportable', () => { + const root = { + label: '@@//src/native/runtime:apple_ios_manifest_shipping', + package: { + product: 'liboliphaunt-native', + ecosystem: 'internal', + configuration: 'ios-xcframework', + name: 'ios.json', + role: 'apple-base-ios-manifest-input', + outputs: [{ path: 'bazel-out/cfg/bin/src/native/runtime/apple_release_assets/ios.json' }], + }, + }; + expect(isNativeAppleBaseInputRoot(root)).toBe(true); + for (const changed of [ + { product: 'fixture' }, + { ecosystem: 'github' }, + { configuration: 'macos-arm64' }, + { name: 'other.json' }, + { role: 'construction' }, + { outputs: [] }, + { outputs: [...root.package.outputs, ...root.package.outputs] }, + { outputs: [{ path: 'source/apple_release_assets/ios.json' }] }, + { outputs: [{ path: 'bazel-out/cfg/bin/unrelated/ios.json' }] }, + ]) + expect(isNativeAppleBaseInputRoot({ ...root, package: { ...root.package, ...changed } })).toBe( + false, + ); + expect( + isNativeAppleBaseInputRoot({ ...root, label: '//other:apple_ios_manifest_shipping' }), + ).toBe(false); +}); + +function fixture() { + const exported = { + schema: 'oliphaunt-bazel-shipping-v1', + scope: 'construction', + packages: [ + { + product: 'alpha', + version: '1.2.3', + ecosystem: 'npm', + name: '@example/alpha', + configuration: 'linux-x64', + role: 'package', + outputs: [{ path: 'bazel-out/package.tgz', owner: '@@//:package' }], + }, + ], + }; + const graph = { + pathFragments: [ + { id: 1, label: 'src' }, + { id: 2, parentId: 1, label: 'alpha.c' }, + { id: 3, label: 'tools' }, + { id: 4, parentId: 3, label: 'packager' }, + { id: 5, label: 'bazel-out' }, + { id: 6, parentId: 5, label: 'alpha.o' }, + { id: 7, parentId: 5, label: 'package.tgz' }, + ], + artifacts: [ + { id: 1, pathFragmentId: 2 }, + { id: 2, pathFragmentId: 4 }, + { id: 3, pathFragmentId: 6 }, + { id: 4, pathFragmentId: 7 }, + ], + targets: [ + { id: 1, label: '//:compile' }, + { id: 2, label: '//:package' }, + ], + configuration: [{ id: 1, mnemonic: 'fixture' }], + depSetOfFiles: [ + { id: 1, directArtifactIds: [1] }, + { id: 2, directArtifactIds: [2, 3] }, + ], + actions: [ + { + targetId: 1, + configurationId: 1, + actionKey: 'compile-action', + mnemonic: 'CppCompile', + inputDepSetIds: [1], + outputIds: [3], + primaryOutputId: 3, + arguments: ['cc', 'src/alpha.c'], + }, + { + targetId: 2, + configurationId: 1, + actionKey: 'package-action', + mnemonic: 'Package', + inputDepSetIds: [2], + outputIds: [4], + primaryOutputId: 4, + arguments: ['pack', '1.2.3'], + }, + ], + }; + return { exported, graph }; +} + +function observedFixture(product = 'alpha', configuration = 'a'.repeat(64)) { + const { exported, graph } = fixture(); + for (const pkg of exported.packages) pkg.product = product; + const view = buildShippingInputView(exported, graph); + const capture = (path: string) => ({ + path, + members: [{ path: '', type: 'file', mode: 0o644, size: 1, sha256: '1'.repeat(64) }], + }); + return { + product: { id: product, version: view.products[product].version }, + construction: [ + { + roots: exported.packages.map((pkg) => ({ + label: pkg.outputs[0].owner, + configuration, + package: pkg, + })), + actions: view.products[product].actions, + inputs: view.physicalInputs.map(capture), + leafInputPaths: view.products[product].inputs, + analysisInputPaths: ['BUILD.bazel', 'build_defs/package.bzl'], + analysisInputs: ['BUILD.bazel', 'build_defs/package.bzl'].map(capture), + }, + ], + }; +} + +function capturedMember( + view: ReturnType['construction'][number], + path: string, +) { + const capture = view.inputs.find((file) => file.path === path); + if (!capture) throw new Error(`fixture has no captured input: ${path}`); + return capture.members[0]; +} + +test('captured shipping footprints leave docs and test-only changes to Bazel execution', () => { + const before = observedFixture(); + const current = structuredClone(before); + // The execution graph can contain other test inputs. Shipping leaf projection + // must neither classify them as payload changes nor suppress their Bazel test. + current.construction[0].inputs.push({ + path: 'test/alpha.test.ts', + members: [{ path: '', type: 'file', mode: 0o644, size: 2, sha256: '2'.repeat(64) }], + }); + expect(selectObservedShippingChanges([current], { alpha: before })).toEqual({ + affectedProducts: [], + unclassifiedPaths: [], + unknownProducts: [], + }); + capturedMember(current.construction[0], 'bazel-out/alpha.o').sha256 = '3'.repeat(64); + expect(selectObservedShippingChanges([current], { alpha: before }).affectedProducts).toEqual([]); +}); + +test('source and external tool bytes request checks without directory ownership', () => { + for (const changed of ['src/alpha.c', 'tools/packager', 'external/toolchain/compiler']) { + const before = observedFixture(); + if (changed.startsWith('external/')) { + before.construction[0].leafInputPaths.push(changed); + before.construction[0].inputs.push({ + path: changed, + members: [{ path: '', type: 'file', mode: 0o755, size: 1, sha256: '1'.repeat(64) }], + }); + } + const current = structuredClone(before); + capturedMember(current.construction[0], changed).sha256 = '2'.repeat(64); + expect(selectObservedShippingChanges([current], { alpha: before })).toEqual({ + affectedProducts: ['alpha'], + unclassifiedPaths: [], + unknownProducts: [], + }); + } +}); + +test('loaded recipe content and configured action changes request construction checks', () => { + const before = observedFixture(); + const recipe = structuredClone(before); + recipe.construction[0].analysisInputs[1].members[0].sha256 = '2'.repeat(64); + expect(selectObservedShippingChanges([recipe], { alpha: before }).affectedProducts).toEqual([ + 'alpha', + ]); + const action = structuredClone(before); + action.construction[0].actions[0] = action.construction[0].actions[0].replace('cc', 'clang'); + expect(selectObservedShippingChanges([action], { alpha: before }).affectedProducts).toEqual([ + 'alpha', + ]); +}); + +test('missing historical metadata or causal maps remain required and unknown', () => { + const current = observedFixture(); + expect(selectObservedShippingChanges([current], {})).toEqual({ + affectedProducts: ['alpha'], + unclassifiedPaths: [], + unknownProducts: ['alpha'], + }); + const legacy = structuredClone(current) as any; + delete legacy.construction[0].analysisInputPaths; + delete legacy.construction[0].analysisInputs; + expect(selectObservedShippingChanges([current], { alpha: legacy }).unknownProducts).toEqual([ + 'alpha', + ]); + const incomplete = structuredClone(current); + incomplete.construction[0].inputs = []; + expect(() => selectObservedShippingChanges([incomplete], { alpha: current })).toThrow( + 'shipping causal File was not captured', + ); +}); + +test('configured captures preserve context when one logical tool path has different host bytes', () => { + const before = observedFixture(); + const other = observedFixture('alpha', 'b'.repeat(64)); + capturedMember(other.construction[0], 'src/alpha.c').sha256 = '2'.repeat(64); + before.construction.push(other.construction[0]); + const current = structuredClone(before); + current.construction.reverse(); + expect(selectObservedShippingChanges([current], { alpha: before }).affectedProducts).toEqual([]); + // Swapping the same two byte identities between configured roots is a change. + capturedMember(current.construction[0], 'src/alpha.c').sha256 = '1'.repeat(64); + capturedMember(current.construction[1], 'src/alpha.c').sha256 = '2'.repeat(64); + expect(selectObservedShippingChanges([current], { alpha: before }).affectedProducts).toEqual([ + 'alpha', + ]); +}); + +test('few and many owners compare their own completed footprints coherently', () => { + const before = ['alpha', 'beta', 'gamma', 'delta', 'epsilon'].map((id) => observedFixture(id)); + const baselines = Object.fromEntries(before.map((product) => [product.product.id, product])); + for (const changed of [ + [], + ['beta'], + ['alpha', 'gamma', 'epsilon'], + before.map((p) => p.product.id), + ]) { + const current = structuredClone(before); + for (const product of current) + if (changed.includes(product.product.id)) + capturedMember(product.construction[0], 'src/alpha.c').sha256 = '2'.repeat(64); + expect(selectObservedShippingChanges(current, baselines).affectedProducts).toEqual( + [...changed].sort(), + ); + } +}); + +test('a proven unchanged footprint cannot explain changed delivered bytes', () => { + const current = observedFixture(); + const different = [{ product: 'alpha', deliveryStatus: 'different' }]; + expect(() => selectObservedShippingChanges([current], { alpha: current }, different)).toThrow( + 'unchanged shipping inputs produced different delivery: alpha', + ); + expect(selectObservedShippingChanges([current], {}, different).affectedProducts).toEqual([ + 'alpha', + ]); + expect( + selectObservedShippingChanges([current], { alpha: current }, [ + { product: 'alpha', deliveryStatus: 'identical' }, + ]).affectedProducts, + ).toEqual([]); +}); + +test('shipping source and packager inputs follow actual producer edges', () => { + const { exported, graph } = fixture(); + const view = buildShippingInputView(exported, graph); + expect(view.products.alpha.inputs).toEqual(['src/alpha.c', 'tools/packager']); + expect(view.products.alpha.actions).toHaveLength(2); + expect(selectShippingChanges(view.products, view, { alpha: [] })).toEqual({ + affectedProducts: [], + unclassifiedPaths: [], + }); + expect( + selectShippingChanges(view.products, view, { alpha: ['tools/packager'] }).affectedProducts, + ).toEqual(['alpha']); + expect(selectShippingChanges(view.products, view, { alpha: ['test/alpha.test.c'] })).toEqual({ + affectedProducts: [], + unclassifiedPaths: ['test/alpha.test.c'], + }); +}); + +test('supplier File checks retain each sibling closure without changing the shared product view', () => { + const { exported, graph } = fixture(); + exported.packages.push({ + ...exported.packages[0], + name: '@example/alpha-objects', + outputs: [{ path: 'bazel-out/alpha.o', owner: '//:compile' }], + }); + const before = buildShippingInputView(exported, graph); + const observed = new Map(); + const requested = ['bazel-out/alpha.o', 'src/alpha.c', 'tools/packager', 'missing/input']; + expect( + buildShippingInputView(exported, graph, { + inspectPackageInputs: (pkg, consumes) => observed.set(pkg.name, requested.filter(consumes)), + }), + ).toEqual(before); + expect(observed.get('@example/alpha')).toEqual([ + 'bazel-out/alpha.o', + 'src/alpha.c', + 'tools/packager', + ]); + expect(observed.get('@example/alpha-objects')).toEqual(['src/alpha.c']); + graph.actions[0].mnemonic = 'Middleman'; + observed.clear(); + buildShippingInputView(exported, graph, { + inspectPackageInputs: (pkg, consumes) => observed.set(pkg.name, requested.filter(consumes)), + }); + expect(observed.get('@example/alpha')).toEqual(['src/alpha.c', 'tools/packager']); +}); + +test('supplier File checks resolve transitive dep sets and reject the root File itself', () => { + const { exported, graph } = fixture(); + graph.depSetOfFiles[1].transitiveDepSetIds = [3]; + graph.depSetOfFiles.push({ id: 3, directArtifactIds: [1] }); + const observed: Record = {}; + const before = buildShippingInputView(exported, graph); + expect( + buildShippingInputView(exported, graph, { + inspectPackageInputs(_pkg, consumes) { + for (const name of ['src/alpha.c', 'bazel-out/alpha.o', 'bazel-out/package.tgz']) + observed[name] = consumes(name); + }, + }), + ).toEqual(before); + expect(observed).toEqual({ + 'src/alpha.c': true, + 'bazel-out/alpha.o': true, + 'bazel-out/package.tgz': false, + }); +}); + +test('GitHub candidate inputs can share one producer across component releases', () => { + const { exported, graph } = fixture(); + const first = exported.packages[0]; + first.ecosystem = 'github'; + first.name = 'shared-ios-carriers.json'; + first.role = 'release-input'; + exported.packages.push({ ...first, product: 'beta', version: '2.3.4' }); + const view = buildShippingInputView(exported, graph); + expect(view.products.alpha.version).toBe('1.2.3'); + expect(view.products.beta.version).toBe('2.3.4'); + expect(view.products.beta.inputs).toEqual(view.products.alpha.inputs); + expect(view.products.beta.actions).toEqual(view.products.alpha.actions); + exported.packages.push({ ...first }); + expect(() => buildShippingInputView(exported, graph)).toThrow('duplicate shipping identity'); +}); + +test('registry identity ownership remains globally unique across products', () => { + for (const ecosystem of ['cargo', 'npm', 'maven']) { + const { exported, graph } = fixture(); + const first = exported.packages[0]; + first.ecosystem = ecosystem; + exported.packages.push({ ...first, product: 'beta', version: '2.3.4' }); + expect(() => buildShippingInputView(exported, graph)).toThrow('duplicate shipping identity'); + } +}); + +test('before and after roots handle deletion, renaming, removed packages and different baselines', () => { + const { exported, graph } = fixture(); + const before = buildShippingInputView(exported, graph); + graph.pathFragments[1].label = 'renamed.c'; + const after = buildShippingInputView(exported, graph); + expect( + selectShippingChanges(before.products, after, { alpha: ['src/alpha.c', 'src/renamed.c'] }), + ).toEqual({ + affectedProducts: ['alpha'], + unclassifiedPaths: [], + }); + expect(selectShippingChanges({}, after, {}).affectedProducts).toEqual(['alpha']); + expect( + selectShippingChanges(before.products, { ...after, products: {} }, { alpha: [] }) + .affectedProducts, + ).toEqual(['alpha']); + graph.actions[1].arguments[1] = '2.0.0'; + expect( + selectShippingChanges(after.products, buildShippingInputView(exported, graph), { alpha: [] }) + .affectedProducts, + ).toEqual(['alpha']); +}); + +test('already delivered shared-source changes do not select a newer product baseline', () => { + const { exported, graph } = fixture(); + const view = buildShippingInputView(exported, graph); + view.products.beta = structuredClone(view.products.alpha); + expect(selectShippingChanges(view.products, view, { alpha: ['src/alpha.c'], beta: [] })).toEqual({ + affectedProducts: ['alpha'], + unclassifiedPaths: [], + }); + expect(() => selectShippingChanges(view.products, view, { alpha: [] })).toThrow( + 'missing product baseline delta for beta', + ); +}); + +function aliasedFixture() { + const { exported, graph } = fixture(); + graph.artifacts.push({ id: 5, pathFragmentId: 6 }); + graph.targets.push({ id: 3, label: '//:other-compile' }); + graph.actions.push({ ...graph.actions[0], targetId: 3, outputIds: [5], primaryOutputId: 5 }); + graph.depSetOfFiles[1].directArtifactIds.push(5); + return { exported, graph }; +} + +test('identical configured action aliases share a path; conflicting producers fail', () => { + const { exported, graph } = aliasedFixture(); + expect(buildShippingInputView(exported, graph).products.alpha.inputs).toEqual([ + 'src/alpha.c', + 'tools/packager', + ]); + graph.actions[2].arguments = ['different-compiler', 'src/alpha.c']; + expect(() => buildShippingInputView(exported, graph)).toThrow('ambiguous artifact producers'); +}); + +test('action aliases require complete keys, configuration and primary outputs', () => { + for (const field of ['actionKey', 'configurationId', 'primaryOutputId']) { + const { exported, graph } = aliasedFixture(); + Reflect.deleteProperty(graph.actions[2], field); + expect(() => buildShippingInputView(exported, graph)).toThrow(); + } + let { exported, graph } = aliasedFixture(); + graph.actions[2].actionKey = 'different-action'; + expect(() => buildShippingInputView(exported, graph)).toThrow('ambiguous artifact producers'); + ({ exported, graph } = aliasedFixture()); + graph.actions[2].configurationId = 99; + expect(() => buildShippingInputView(exported, graph)).toThrow('incomplete aquery'); + ({ exported, graph } = aliasedFixture()); + graph.configuration.push({ id: 2, mnemonic: 'other-configuration' }); + graph.actions[2].configurationId = 2; + expect(() => buildShippingInputView(exported, graph)).toThrow('ambiguous artifact producers'); + ({ exported, graph } = aliasedFixture()); + graph.actions[2].primaryOutputId = 4; + expect(() => buildShippingInputView(exported, graph)).toThrow('primary output is missing'); +}); + +test('shared outputs retain Bazel output order and primary output semantics', () => { + const { exported, graph } = aliasedFixture(); + graph.pathFragments.push({ id: 8, parentId: 5, label: 'alpha.metadata' }); + graph.artifacts.push({ id: 6, pathFragmentId: 8 }, { id: 7, pathFragmentId: 8 }); + graph.actions[0].outputIds.push(6); + graph.actions[2].outputIds.push(7); + expect(buildShippingInputView(exported, graph).products.alpha.inputs).toEqual([ + 'src/alpha.c', + 'tools/packager', + ]); + graph.actions[2].outputIds.reverse(); + expect(() => buildShippingInputView(exported, graph)).toThrow('ambiguous artifact producers'); + graph.actions[2].outputIds.reverse(); + graph.actions[2].primaryOutputId = 7; + expect(() => buildShippingInputView(exported, graph)).toThrow('ambiguous artifact producers'); +}); + +test('an exported shared output resolves its exact declared owner', () => { + const { exported, graph } = fixture(); + graph.artifacts.unshift({ id: 5, pathFragmentId: 7 }); + graph.targets.push({ id: 3, label: '//:other-package' }); + graph.actions.push({ ...graph.actions[1], targetId: 3, outputIds: [5], primaryOutputId: 5 }); + const view = buildShippingInputView(exported, graph); + expect(view.products.alpha.actions.map((action) => JSON.parse(action).target).sort()).toEqual([ + '//:compile', + '//:package', + ]); +}); + +test('shared producers require the same ordered physical inputs', () => { + const { exported, graph } = aliasedFixture(); + graph.depSetOfFiles[0].directArtifactIds.push(2); + expect(buildShippingInputView(exported, graph).products.alpha.inputs).toEqual([ + 'src/alpha.c', + 'tools/packager', + ]); + graph.depSetOfFiles.push({ id: 3, directArtifactIds: [2, 1] }); + graph.actions[2].inputDepSetIds = [3]; + expect(() => buildShippingInputView(exported, graph)).toThrow('ambiguous artifact producers'); +}); + +test('repeated native Symlink records preserve one complete producer and exact ownership', () => { + // Minimized from Bazel 8.8.1 rules_rust toolchain aquery: the same Symlink + // record occurs twice with one artifact ID when Cargo is used for inventory. + const { exported, graph } = fixture(); + const action = graph.actions[0]; + action.mnemonic = 'Symlink'; + action.actionKey = '7a39b61d5744a8903119e17b3ddc7e56e330f240d2bead98c3ba081a81b5c9ac'; + Reflect.deleteProperty(action, 'arguments'); + Reflect.set(action, 'executionPlatform', '@@platforms//host:host'); + const before = buildShippingInputView(exported, graph); + graph.actions.push(structuredClone(action)); + expect(buildShippingInputView(exported, graph)).toEqual(before); + for (const field of ['actionKey', 'configurationId', 'primaryOutputId']) { + const malformed = structuredClone(graph); + Reflect.deleteProperty(malformed.actions[0], field); + Reflect.deleteProperty(malformed.actions[2], field); + expect(() => buildShippingInputView(exported, malformed)).toThrow(); + } + for (const [field, value] of [ + ['arguments', ['different-command']], + ['environmentVariables', [{ key: 'CHANGED', value: '1' }]], + ['executionPlatform', '//:different-platform'], + ['targetId', 2], + ] as const) { + const conflicting = structuredClone(graph); + Reflect.set(conflicting.actions[2], field, value); + expect(() => buildShippingInputView(exported, conflicting)).toThrow('multiple producers'); + } + exported.packages[0].outputs[0].owner = '//:other'; + expect(() => buildShippingInputView(exported, graph)).toThrow('owner disagrees'); +}); + +test('partial, substituted or cyclic graphs fail closed', () => { + let { exported, graph } = fixture(); + exported.packages[0].outputs[0].owner = '//:other'; + expect(() => buildShippingInputView(exported, graph)).toThrow('owner disagrees'); + ({ exported, graph } = fixture()); + graph.artifacts.pop(); + expect(() => buildShippingInputView(exported, graph)).toThrow('incomplete aquery'); + ({ exported, graph } = fixture()); + graph.depSetOfFiles.push({ id: 1, directArtifactIds: [1] }); + expect(() => buildShippingInputView(exported, graph)).toThrow('duplicate aquery id'); + ({ exported, graph } = fixture()); + graph.actions[0].inputDepSetIds = [2]; + expect(() => buildShippingInputView(exported, graph)).toThrow('cycle in aquery producers'); + ({ exported, graph } = fixture()); + graph.actions.push({ ...graph.actions[1], actionKey: 'conflicting-package-action' }); + expect(() => buildShippingInputView(exported, graph)).toThrow('multiple producers'); + ({ exported, graph } = fixture()); + graph.actions.shift(); + expect(() => buildShippingInputView(exported, graph)).toThrow('missing generated input producer'); +}); + +test('compact descriptions bind exact sorted physical input sets and retain the full capture closure', () => { + const { exported, graph } = fixture(); + const view = buildShippingInputView(exported, graph); + const actions = view.products.alpha.actions.map((action) => JSON.parse(action)); + expect(view.schema).toBe('oliphaunt-bazel-construction-inputs-v2'); + expect(view.physicalInputs).toEqual(['bazel-out/alpha.o', 'src/alpha.c', 'tools/packager']); + expect(view.captureInputs).toEqual(['src/alpha.c', 'tools/packager']); + const packageInputs = ['bazel-out/alpha.o', 'tools/packager']; + expect(actions.find((action) => action.target === '//:package').inputs).toEqual({ + count: packageInputs.length, + sha256: createHash('sha256').update(JSON.stringify(packageInputs)).digest('hex'), + }); + expect(() => + selectShippingChanges( + view.products, + { ...view, schema: 'oliphaunt-bazel-construction-inputs-v1' } as any, + { alpha: [] }, + ), + ).toThrow('unsupported construction input view'); +}); + +test('input-set factoring, ordering and query-local ID changes do not change normalized declarations', () => { + const { exported, graph } = fixture(); + const before = buildShippingInputView(exported, graph); + graph.depSetOfFiles[1].directArtifactIds = []; + Reflect.set(graph.depSetOfFiles[1], 'transitiveDepSetIds', [3, 4]); + graph.depSetOfFiles.push({ id: 3, directArtifactIds: [3] }, { id: 4, directArtifactIds: [2] }); + for (const set of graph.depSetOfFiles) { + set.id += 100; + const children = Reflect.get(set, 'transitiveDepSetIds'); + if (children) + Reflect.set(set, 'transitiveDepSetIds', children.map((id: number) => id + 100).reverse()); + } + for (const action of graph.actions) + action.inputDepSetIds = action.inputDepSetIds.map((id) => id + 100); + graph.depSetOfFiles.reverse(); + graph.actions.reverse(); + graph.pathFragments.reverse(); + expect(buildShippingInputView(exported, graph)).toEqual(before); +}); + +test('input digests preserve lexical path order and collapse aliases across a shared prefix', () => { + const { exported, graph } = fixture(); + const names = [ + 'z.h', + 'a.h', + 'aa.h', + 'A.h', + 'header-2.h', + 'header-10.h', + 'é.h', + 'Ω.h', + '😀.h', + '\ue000.h', + ]; + for (const [index, label] of names.entries()) { + const id = 100 + index; + graph.pathFragments.push({ id, parentId: 1, label }); + graph.artifacts.push({ id, pathFragmentId: id }); + graph.depSetOfFiles[0].directArtifactIds.unshift(id); + } + graph.artifacts.push({ id: 999, pathFragmentId: 2 }); + graph.depSetOfFiles[0].directArtifactIds.push(999); + const paths = ['src/alpha.c', ...names.map((name) => `src/${name}`)].sort(); + const view = buildShippingInputView(exported, graph); + const compile = view.products.alpha.actions + .map((action) => JSON.parse(action)) + .find((action) => action.target === '//:compile'); + expect(compile.inputs).toEqual({ + count: paths.length, + sha256: createHash('sha256').update(JSON.stringify(paths)).digest('hex'), + }); + expect(view.captureInputs).toEqual([...paths, 'tools/packager'].sort()); +}); + +test('same-count input edge swaps and command changes remain visible with identical source and capture unions', () => { + const { exported, graph } = fixture(); + const before = buildShippingInputView(exported, graph); + graph.depSetOfFiles[0].directArtifactIds = [2]; + graph.depSetOfFiles[1].directArtifactIds = [1, 3]; + const swapped = buildShippingInputView(exported, graph); + expect(swapped.physicalInputs).toEqual(before.physicalInputs); + expect(swapped.products.alpha.inputs).toEqual(before.products.alpha.inputs); + expect(swapped.products.alpha.actions).not.toEqual(before.products.alpha.actions); + expect(selectShippingChanges(before.products, swapped, { alpha: [] }).affectedProducts).toEqual([ + 'alpha', + ]); + graph.actions[0].arguments.push('-DCHANGED=1'); + const command = buildShippingInputView(exported, graph); + expect(command.physicalInputs).toEqual(swapped.physicalInputs); + expect(command.products.alpha.actions).not.toEqual(swapped.products.alpha.actions); +}); + +test('shared input prefixes preserve flat JSON digests across chunk boundaries and resets', () => { + const { exported, graph } = fixture(); + const compiler = graph.actions.shift()!; + const names = [ + ...Array.from({ length: 514 }, (_, index) => `header-${String(index).padStart(4, '0')}.h`), + 'quote".h', + 'é.h', + '😀.h', + '\ue000.h', + ]; + const paths = new Map(); + const ids = names.map((label, index) => { + const id = 100 + index; + graph.pathFragments.push({ id, parentId: 1, label }); + graph.artifacts.push({ id, pathFragmentId: id }); + paths.set(id, `src/${label}`); + return id; + }); + const alias = 9999; + graph.artifacts.push({ id: alias, pathFragmentId: ids[0] }); + paths.set(alias, paths.get(ids[0])!); + const cases = [ + ...[0, 1, 255, 256, 257, 511, 512, 513, 512, 256, 0].map((count) => ids.slice(0, count)), + [...ids.slice(0, 255), ids[513]], + ids.slice(0, 256), + ids.slice(514).reverse(), + [...ids.slice(0, 512).reverse(), alias], + ids.slice(256, 512), + ]; + graph.depSetOfFiles[1].directArtifactIds = [2]; + for (const [index, inputs] of cases.entries()) { + const output = 10000 + index; + const inputSet = 100 + index; + graph.pathFragments.push({ id: output, parentId: 5, label: `prefix-${index}.o` }); + graph.artifacts.push({ id: output, pathFragmentId: output }); + graph.depSetOfFiles.push({ id: inputSet, directArtifactIds: inputs }); + graph.depSetOfFiles[1].directArtifactIds.push(output); + graph.actions.push({ + ...compiler, + actionKey: `prefix-${index}`, + inputDepSetIds: [inputSet], + outputIds: [output], + primaryOutputId: output, + }); + } + const actions = new Map( + buildShippingInputView(exported, graph).products.alpha.actions.map((value) => { + const action = JSON.parse(value); + return [action.actionKey, action.inputs]; + }), + ); + for (const [index, inputs] of cases.entries()) { + const expected = [...new Set(inputs.map((id) => paths.get(id)!))].sort(); + expect(actions.get(`prefix-${index}`)).toEqual({ + count: expected.length, + sha256: createHash('sha256').update(JSON.stringify(expected)).digest('hex'), + }); + } +}); + +test('physical source aliases collapse only after validation and repository paths stay distinct', () => { + const { exported, graph } = fixture(); + const before = buildShippingInputView(exported, graph); + graph.artifacts.push({ id: 5, pathFragmentId: 2 }); + graph.depSetOfFiles[0].directArtifactIds.push(5); + expect(buildShippingInputView(exported, graph)).toEqual(before); + graph.pathFragments.push( + { id: 8, label: 'external' }, + { id: 9, parentId: 8, label: 'dependency' }, + { id: 10, parentId: 9, label: 'src' }, + { id: 11, parentId: 10, label: 'alpha.c' }, + ); + graph.artifacts.push({ id: 6, pathFragmentId: 11 }); + graph.depSetOfFiles[0].directArtifactIds.push(6); + const external = buildShippingInputView(exported, graph); + expect(external.physicalInputs).toContain('src/alpha.c'); + expect(external.physicalInputs).toContain('external/dependency/src/alpha.c'); + expect(external.products.alpha.actions).not.toEqual(before.products.alpha.actions); +}); + +test('only declared virtual Middleman outputs are removed from the physical closure', () => { + const { exported, graph } = fixture(); + graph.actions[0].mnemonic = 'Middleman'; + const view = buildShippingInputView(exported, graph); + expect(view.physicalInputs).toEqual(['src/alpha.c', 'tools/packager']); + expect(view.products.alpha.actions).toHaveLength(2); + graph.actions.shift(); + expect(() => buildShippingInputView(exported, graph)).toThrow('missing generated input producer'); +}); + +test('reused compiler headers remain complete without multiplying retained descriptions', () => { + const { exported, graph } = fixture(); + for (let index = 0; index < 2048; index++) { + const id = 100 + index; + graph.pathFragments.push({ id, parentId: 1, label: `header-${index}.h` }); + graph.artifacts.push({ id, pathFragmentId: id }); + graph.depSetOfFiles[0].directArtifactIds.push(id); + } + const compiler = graph.actions[0]; + for (let index = 0; index < 128; index++) { + const id = 10000 + index; + graph.pathFragments.push({ id, parentId: 5, label: `object-${index}.o` }); + graph.artifacts.push({ id, pathFragmentId: id }); + graph.actions.push({ + ...compiler, + actionKey: `compile-${index}`, + outputIds: [id], + primaryOutputId: id, + }); + graph.depSetOfFiles[1].directArtifactIds.push(id); + } + const original = JSON.stringify(graph); + let directIdReads = 0; + const directIdCount = graph.depSetOfFiles.reduce( + (count, set) => count + set.directArtifactIds.length, + 0, + ); + for (const set of graph.depSetOfFiles) + set.directArtifactIds.forEach((value, index, ids) => { + Object.defineProperty(ids, index, { + get() { + directIdReads++; + return value; + }, + }); + }); + const view = buildShippingInputView(exported, graph); + expect(directIdReads).toBe(directIdCount); + expect(view.products.alpha.inputs).toHaveLength(2050); + expect(view.physicalInputs).toHaveLength(2179); + expect(view.products.alpha.actions).toHaveLength(130); + expect(JSON.stringify(view).length).toBeLessThan(512_000); + expect(JSON.stringify(graph)).toBe(original); + directIdReads = 0; + expect(buildShippingInputView(exported, graph)).toEqual(view); + expect(directIdReads).toBe(directIdCount); +}); + +test('multi-output actions expand a shared input DAG once per product and graph read', () => { + const { exported, graph } = fixture(); + exported.packages[0].ecosystem = 'github'; + for (let index = 0; index < 2048; index++) { + const id = 100 + index; + graph.pathFragments.push({ id, parentId: 1, label: `header-${index}.h` }); + graph.artifacts.push({ id, pathFragmentId: id }); + graph.depSetOfFiles[0].directArtifactIds.push(id); + } + for (let index = 0; index < 127; index++) { + const id = 10000 + index; + graph.pathFragments.push({ id, parentId: 5, label: `object-${index}.o` }); + graph.artifacts.push({ id, pathFragmentId: id }); + graph.actions[0].outputIds.push(id); + graph.depSetOfFiles[1].directArtifactIds.push(id); + } + const flatGraph = structuredClone(graph); + const singleProduct = buildShippingInputView(exported, flatGraph); + const sets = graph.depSetOfFiles as { + id: number; + directArtifactIds?: number[]; + transitiveDepSetIds?: number[]; + }[]; + const headers = sets[0].directArtifactIds; + sets[0] = { id: 1, transitiveDepSetIds: [1000, 1001] }; + sets.push( + { id: 1000, transitiveDepSetIds: [1002] }, + { id: 1001, transitiveDepSetIds: [1002] }, + { id: 1002, directArtifactIds: headers }, + ); + const original = JSON.stringify(graph); + let childIdReads = 0; + for (const set of sets) + set.transitiveDepSetIds?.forEach((value, index, ids) => { + Object.defineProperty(ids, index, { + get() { + childIdReads++; + return value; + }, + }); + }); + const view = buildShippingInputView(exported, graph); + expect(childIdReads).toBeLessThanOrEqual(4); + expect(view).toEqual(singleProduct); + expect(view.products.alpha.inputs).toHaveLength(2050); + expect(view.physicalInputs).toHaveLength(2178); + expect(view.products.alpha.actions).toHaveLength(2); + exported.packages.push({ ...exported.packages[0], product: 'beta', version: '2.3.4' }); + const bothProducts = buildShippingInputView(exported, flatGraph); + childIdReads = 0; + expect(buildShippingInputView(exported, graph)).toEqual(bothProducts); + expect(childIdReads).toBeLessThanOrEqual(4); + expect(bothProducts.products.beta.inputs).toEqual(view.products.alpha.inputs); + expect(bothProducts.products.beta.actions).toEqual(view.products.alpha.actions); + childIdReads = 0; + expect(buildShippingInputView(exported, graph)).toEqual(bothProducts); + expect(childIdReads).toBeLessThanOrEqual(4); + expect(JSON.stringify(graph)).toBe(original); + const cyclic = structuredClone(graph); + cyclic.depSetOfFiles.find((set) => set.id === 1002)!.directArtifactIds!.push(10000); + expect(() => buildShippingInputView(exported, cyclic)).toThrow('cycle in aquery producers'); +}); + +test('cached compiler actions share input DAG traversal within each later product', () => { + const { exported, graph } = fixture(); + exported.packages[0].ecosystem = 'github'; + exported.packages.push({ ...exported.packages[0], product: 'beta', version: '2.3.4' }); + for (let index = 0; index < 256; index++) { + const id = 100 + index; + graph.pathFragments.push({ id, parentId: 1, label: `header-${index}.h` }); + graph.artifacts.push({ id, pathFragmentId: id }); + graph.depSetOfFiles[0].directArtifactIds.push(id); + } + for (let index = 0; index < 63; index++) { + const id = 10000 + index; + graph.pathFragments.push({ id, parentId: 5, label: `object-${index}.o` }); + graph.artifacts.push({ id, pathFragmentId: id }); + graph.actions.push({ + ...graph.actions[0], + actionKey: `compile-${index}`, + outputIds: [id], + primaryOutputId: id, + }); + graph.depSetOfFiles[1].directArtifactIds.push(id); + } + const flat = buildShippingInputView(exported, graph); + const sets = graph.depSetOfFiles as { + id: number; + directArtifactIds?: number[]; + transitiveDepSetIds?: number[]; + }[]; + const headers = sets[0].directArtifactIds; + sets[0] = { id: 1, transitiveDepSetIds: [1000, 1001] }; + sets.push( + { id: 1000, transitiveDepSetIds: [1002] }, + { id: 1001, transitiveDepSetIds: [1002] }, + { id: 1002, directArtifactIds: headers }, + ); + const original = JSON.stringify(graph); + let childIdReads = 0; + for (const set of sets) + set.transitiveDepSetIds?.forEach((value, index, ids) => { + Object.defineProperty(ids, index, { + get() { + childIdReads++; + return value; + }, + }); + }); + const view = buildShippingInputView(exported, graph); + expect(childIdReads).toBeLessThanOrEqual(4); + expect(view).toEqual(flat); + expect(view.products.beta.inputs).toEqual(view.products.alpha.inputs); + expect(view.products.beta.actions).toEqual(view.products.alpha.actions); + expect(view.products.beta.inputs).toHaveLength(258); + expect(view.products.beta.actions).toHaveLength(65); + childIdReads = 0; + expect(buildShippingInputView(exported, graph)).toEqual(view); + expect(childIdReads).toBeLessThanOrEqual(4); + expect(JSON.stringify(graph)).toBe(original); +}); + +test('direct input validation remains lazy, ordered and isolated to each graph read', () => { + const { exported, graph } = fixture(); + const before = buildShippingInputView(exported, graph); + const sets = graph.depSetOfFiles as any[]; + sets.push({ id: 9, directArtifactIds: [false] }); + expect(buildShippingInputView(exported, graph)).toEqual(before); + sets[0].transitiveDepSetIds = [9]; + sets[0].directArtifactIds = [null]; + sets[2].transitiveDepSetIds = [1]; + expect(() => buildShippingInputView(exported, graph)).toThrow('cycle in aquery input dep sets'); + sets[2].transitiveDepSetIds = [9999]; + expect(() => buildShippingInputView(exported, graph)).toThrow('incomplete aquery graph'); + sets[2].transitiveDepSetIds = []; + expect(() => buildShippingInputView(exported, graph)).toThrow('missing aquery id'); + sets[2].directArtifactIds = [1, '1', 1]; + sets[0].directArtifactIds = []; + expect(buildShippingInputView(exported, graph)).toEqual(before); + for (const [members, error] of [ + [[9999, false], 'incomplete aquery graph'], + [[false, 9999], 'missing aquery id'], + [Array(1), 'missing aquery id'], + ['not an input list', 'expected an array'], + ] as const) { + sets[2].directArtifactIds = members; + expect(() => buildShippingInputView(exported, graph)).toThrow(error); + } +}); + +test('only consumed typed supplier Files join the required byte frontier', () => { + const { exported, graph } = fixture(); + const pkg = exported.packages[0] as any; + pkg.supplierInputs = [ + { + product: 'supplier', + version: '1.0.0', + configuration: 'linux-x64', + binding: 'abi-contract', + origin: { kind: 'current-source' }, + files: [{ path: 'bazel-out/alpha.o' }], + }, + ]; + expect(buildShippingInputView(exported, graph).captureInputs).toEqual([ + 'bazel-out/alpha.o', + 'src/alpha.c', + 'tools/packager', + ]); + pkg.supplierInputs[0].files[0].path = 'unconsumed'; + expect(buildShippingInputView(exported, graph).captureInputs).toEqual([ + 'src/alpha.c', + 'tools/packager', + ]); +}); + +test('seeded shared input DAG factoring preserves declarations and malformed edges still fail', () => { + for (let seed = 1; seed <= 64; seed++) { + let state = seed; + const random = (bound: number) => { + state ^= state << 13; + state ^= state >>> 17; + state ^= state << 5; + return (state >>> 0) % bound; + }; + const shuffle = (items: T[]) => { + for (let i = items.length - 1; i > 0; i--) { + const j = random(i + 1); + [items[i], items[j]] = [items[j], items[i]]; + } + }; + const { exported, graph } = fixture(); + for (let i = 0; i < 64; i++) { + const id = i + 100; + graph.pathFragments.push({ id, parentId: 1, label: `header-${i}.h` }); + graph.artifacts.push({ id, pathFragmentId: id }); + graph.depSetOfFiles[0].directArtifactIds.push(id); + } + const before = buildShippingInputView(exported, graph); + const groups: number[][] = Array.from({ length: 4 }, () => []); + for (const id of graph.depSetOfFiles[0].directArtifactIds) groups[random(4)].push(id); + const sets = graph.depSetOfFiles as { + id: number; + directArtifactIds?: number[]; + transitiveDepSetIds?: number[]; + }[]; + for (let i = 0; i < groups.length; i++) { + shuffle(groups[i]); + sets.push({ id: 1000 + i, directArtifactIds: groups[i] }); + } + const children = [1000, 1001, 1002, 1003]; + shuffle(children); + sets[0] = { id: 1, transitiveDepSetIds: children }; + sets.push({ id: 2000, transitiveDepSetIds: [1, 1000] }); + graph.actions[0].inputDepSetIds = [2000]; + shuffle(sets); + shuffle(graph.artifacts); + shuffle(graph.actions); + expect(buildShippingInputView(exported, graph)).toEqual(before); + const malformed = structuredClone(graph); + malformed.depSetOfFiles.push({ id: 3000, transitiveDepSetIds: [2000] } as any); + const root = malformed.depSetOfFiles.find((item) => item.id === 2000) as any; + root.transitiveDepSetIds.push(3000); + expect(() => buildShippingInputView(exported, malformed)).toThrow( + 'cycle in aquery input dep sets', + ); + root.transitiveDepSetIds = [9999]; + expect(() => buildShippingInputView(exported, malformed)).toThrow('incomplete aquery'); + root.transitiveDepSetIds = []; + root.directArtifactIds = [9999]; + expect(() => buildShippingInputView(exported, malformed)).toThrow('incomplete aquery'); + } +}); diff --git a/tools/release/bootstrap-publication-capsule.test.mts b/tools/release/bootstrap-publication-capsule.test.mts index 63df4a4c9..4d09f4208 100644 --- a/tools/release/bootstrap-publication-capsule.test.mts +++ b/tools/release/bootstrap-publication-capsule.test.mts @@ -379,7 +379,7 @@ test('packs and verifies all Maven payloads for a Maven-only release', () => { } }); -test('fails closed on selection drift, external-lock drift, and a preexisting destination', () => { +test('fails closed on source, selection, external-lock drift, and a preexisting destination', () => { const value = fixture(); const capsule = path.join(value.root, 'capsule.tar'); const output = workspace(); @@ -394,6 +394,18 @@ test('fails closed on selection drift, external-lock drift, and a preexisting de /selected products do not exactly match/u, ); packBootstrapCapsule({ lockFile: value.lockFile, products: PRODUCTS, output: capsule }); + assert.throws( + () => + verifyExtractBootstrapCapsule({ + transport: capsule, + approvedLock: value.lockFile, + products: PRODUCTS, + headRef: 'HEAD^', + workspaceRoot: output, + }), + /matching Git snapshot|publication lock source .* does not match/u, + ); + assert.throws(() => lstatSync(path.join(output, 'target')), /ENOENT/u); assert.throws( () => extractCandidate({ diff --git a/tools/release/bootstrap-publication-capsule.test.sh b/tools/release/bootstrap-publication-capsule.test.sh index f947fda16..7b59c8cb1 100644 --- a/tools/release/bootstrap-publication-capsule.test.sh +++ b/tools/release/bootstrap-publication-capsule.test.sh @@ -7,7 +7,7 @@ if [ "${1:-}" != --context ]; then done unset CI_RUN_ID BOOTSTRAP_LEDGER_PATH OLIPHAUNT_REQUIRE_GITHUB_CORE_REQUEST_JOURNAL exec bash tools/release/release-please-state.sh "$PWD" HEAD \ - bash tools/release/with-source.sh HEAD bash tools/ci/with-projects.sh --exec \ + bash tools/release/with-source.sh HEAD \ bash tools/release/bootstrap-publication-capsule.test.sh --context fi bash tools/dev/bun.sh test ./tools/release/bootstrap-publication-capsule.test.mts diff --git a/tools/release/capture-native-build-evidence.mts b/tools/release/capture-native-build-evidence.mts new file mode 100644 index 000000000..5bb123ecb --- /dev/null +++ b/tools/release/capture-native-build-evidence.mts @@ -0,0 +1,599 @@ +#!/usr/bin/env bun +import { createHash } from 'node:crypto'; +/** Collect current configured contents after a successful build; this grants no release authority. */ +import { linkSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { SEED_CONSTRUCTION_RECEIPT_SUFFIX } from '../../build_defs/resources/seed_construction.mts'; +import { requireSafeDirectoryChain } from '../packaging/release-directory-safety.mts'; +import { buildShippingInputView, canonicalShippingLabel } from './bazel-shipping-inputs.mts'; +import { readNativeAquery } from './native-aquery.mts'; +import { writeNativeBuildFinalFiles } from './native-build-files.mts'; +import { + NATIVE_AQUERY_FLAGS, + type NativeBuildEvidence, + type NativeBuildGithub, + type NativeBuildSource, + nativeAqueryOutputFormat, + nativeBuildEventIndex, + nativeBuildMetadata, + nativeQualificationInputBindings, + nativeRequiredCaptureInputs, + nativeShippingManifestBindings, + nativeShippingQualificationPolicy, + validateNativeBuildEvidence, +} from './native-build-qualification.mts'; +import { type NativeRoot, nativeOutputPath } from './native-publication-artifacts.mts'; +import { + captureNativeInputMembers, + captureNativeOutputMembers, +} from './native-publication-staging.mts'; +import { sourceIdentity } from './publication-lock.mts'; + +export type NativeBuildCaptureCohort = { + executionRoot: string; + aquery: unknown; + buildEvents: unknown[]; + analysis?: { workspace: string; rootInputs: { label: string; paths: string[] }[] }; +} & ( + | { roots: NativeRoot[]; cquery: unknown } + | { + shippingRoots: string[]; + aqueryFile: string; + shippingExport?: string; + aqueryBuildEvents?: unknown[]; + } +); + +function object(value: unknown): Record { + if (!value || typeof value !== 'object' || Array.isArray(value)) + throw new Error('native capture requires an object'); + return value as Record; +} +function array(value: unknown): any[] { + if (!Array.isArray(value)) throw new Error('native capture requires a list'); + return value; +} +function text(value: unknown): string { + if (typeof value !== 'string' || !value || /[\u0000-\u001f\u007f]/u.test(value)) + throw new Error('native capture requires a nonempty identity'); + return value; +} +function configurationId(value: unknown) { + if (!Number.isSafeInteger(value) || Number(value) <= 0 || Number(value) > 0xffffffff) + throw new Error('native cquery configuration ID is invalid or null'); + return Number(value); +} + +/** CqueryResult IDs are dump-local; BEP identifies the configuration by its checksum. */ +export function nativeRootConfigurations(roots: NativeRoot[], raw: unknown) { + const query = object(raw); + const configurations = new Map(); + for (const item of array(query.configurations)) { + const row = object(item); + const id = configurationId(row.id); + if (configurations.has(id)) throw new Error('duplicate native cquery configuration'); + configurations.set(id, text(row.checksum)); + } + const results = array(query.results).map(object); + return roots.map((root) => { + const matches = results.filter( + (result) => + result.target?.rule?.name !== undefined && + canonicalShippingLabel(result.target.rule.name) === canonicalShippingLabel(root.label), + ); + if (matches.length !== 1) + throw new Error(`native cquery requires one configured rule for ${root.label}`); + const configuration = configurations.get(configurationId(matches[0].configurationId)); + if (!configuration) throw new Error('native cquery root configuration is missing'); + return { label: root.label, configuration }; + }); +} + +/** Physical collection retains raw protocol bindings before packet sanitization. */ +function collectNativeBuildEvidence( + { + source, + github, + cohorts, + bazelVersion, + }: { + source: NativeBuildSource; + github: NativeBuildGithub; + cohorts: NativeBuildCaptureCohort[]; + bazelVersion: string; + }, + report?: (phase: string) => void, +) { + const captures: ReturnType[] = []; + const evidence: NativeBuildEvidence = { + schema: 'oliphaunt-native-build-evidence-v1', + source, + github, + cohorts: cohorts.map((cohort) => { + report?.('deriving capture frontier'); + let roots: NativeRoot[]; + let rootConfigurations: { label: string; configuration: string }[]; + let producerCapture: NativeBuildEvidence['cohorts'][number]['producerCapture']; + let bep: ReturnType | undefined; + if ('shippingRoots' in cohort) { + const labels = array(cohort.shippingRoots).map((label) => + canonicalShippingLabel(text(label)), + ); + if (!labels.length || new Set(labels).size !== labels.length) + throw new Error('native producer requires unique selected shipping roots'); + bep = nativeBuildEventIndex(cohort, bazelVersion, nativeBuildMetadata(source, github)); + const shippingManifests = labels.map((label) => { + const targets = bep.completed.filter( + (target) => canonicalShippingLabel(target.label) === label, + ); + if (targets.length !== 1 || targets[0].value.success !== true) + throw new Error( + `native producer requires one successful configured shipping root: ${label}`, + ); + const files = bep.filesOf(targets[0].value, 'shipping_manifest'); + if (files.size !== 1) + throw new Error(`native producer requires one shipping_manifest file: ${label}`); + const file = [...files.keys()][0]; + const capture = captureNativeOutputMembers(cohort.executionRoot, file); + captures.push(capture); + const contents = readFileSync(nativeOutputPath(cohort.executionRoot, file), 'utf8'); + const bytes = Buffer.from(contents, 'utf8'); + const member = capture.members[0]; + if ( + capture.members.length !== 1 || + member.type !== 'file' || + member.size !== bytes.length || + member.sha256 !== createHash('sha256').update(bytes).digest('hex') + ) + throw new Error('native shipping manifest physical contents changed during capture'); + capture.assertUnchanged(); + return { path: file, contents }; + }); + producerCapture = { + aqueryFile: cohort.aqueryFile, + shippingManifests, + ...(cohort.aqueryBuildEvents === undefined + ? {} + : { aqueryBuildEvents: cohort.aqueryBuildEvents }), + }; + const bindings = nativeShippingManifestBindings(producerCapture, bep); + if ( + JSON.stringify(bindings.map(({ root }) => canonicalShippingLabel(root.label)).sort()) !== + JSON.stringify([...labels].sort()) + ) + throw new Error('native selected/analysis shipping root coverage mismatch'); + roots = bindings.map(({ root }) => root); + rootConfigurations = bindings.map(({ root, configuration }) => ({ + label: root.label, + configuration, + })); + if (cohort.shippingExport !== undefined) { + const owner = canonicalShippingLabel(text(cohort.shippingExport)); + const targets = bep.completed.filter( + (target) => canonicalShippingLabel(target.label) === owner, + ); + if (targets.length !== 1 || targets[0].value.success !== true) + throw new Error('native producer requires one successful configured owner export'); + const files = bep.filesOf(targets[0].value, 'shipping_policy'); + if (files.size !== 1) + throw new Error('native producer requires one shipping_policy output'); + const file = [...files.keys()][0]; + const capture = captureNativeOutputMembers(cohort.executionRoot, file); + captures.push(capture); + const contents = readFileSync(nativeOutputPath(cohort.executionRoot, file), 'utf8'); + const bytes = Buffer.from(contents, 'utf8'); + const member = capture.members[0]; + if ( + capture.members.length !== 1 || + member.type !== 'file' || + member.size !== bytes.length || + member.sha256 !== createHash('sha256').update(bytes).digest('hex') + ) + throw new Error('native owner qualification changed during capture'); + if (canonicalShippingLabel(JSON.parse(contents).owner) !== owner) + throw new Error('native owner qualification differs from selected export'); + capture.assertUnchanged(); + producerCapture.qualificationManifest = { path: file, contents }; + } + } else { + roots = cohort.roots; + rootConfigurations = nativeRootConfigurations(roots, cohort.cquery); + } + const view = buildShippingInputView( + { + schema: 'oliphaunt-bazel-shipping-v1', + scope: 'construction', + packages: roots.map((root) => root.package), + }, + cohort.aquery, + ); + const inputs = nativeRequiredCaptureInputs(view); + const outputs = [ + ...new Set(roots.flatMap((root) => root.package.outputs.map((output) => output.path))), + ].sort(); + report?.('collecting physical members'); + const seedConstructions = inputs + .filter((file) => file.endsWith(SEED_CONSTRUCTION_RECEIPT_SUFFIX)) + .map((file) => ({ + path: file, + contents: readFileSync(nativeOutputPath(cohort.executionRoot, file), 'utf8'), + })); + const capture = (file: string, output: boolean) => { + const value = output + ? captureNativeOutputMembers(cohort.executionRoot, file) + : captureNativeInputMembers(cohort.executionRoot, file); + captures.push(value); + return { path: file, members: value.members }; + }; + const analysisInputs = + cohort.analysis === undefined + ? undefined + : [...new Set(cohort.analysis.rootInputs.flatMap((row) => row.paths))] + .sort() + .map((file) => { + const value = captureNativeInputMembers(cohort.analysis!.workspace, file); + captures.push(value); + return { path: file, members: value.members }; + }); + const qualificationInputs = + producerCapture === undefined + ? [] + : (() => { + if (!bep) throw new Error('native qualification requires the producing event index'); + const policy = nativeShippingQualificationPolicy(producerCapture, bep, roots); + return nativeQualificationInputBindings(cohort.aquery, bep, policy).map( + ({ files, ...test }) => ({ + ...test, + inputs: [...files.keys()].sort().map((file) => capture(file, true)), + }), + ); + })(); + return { + executionRoot: cohort.executionRoot, + roots, + rootConfigurations, + aquery: cohort.aquery, + buildEvents: cohort.buildEvents, + inputs: inputs.map((file) => capture(file, false)), + outputs: outputs.map((file) => capture(file, true)), + ...(producerCapture === undefined ? {} : { producerCapture }), + ...(qualificationInputs.length ? { qualificationInputs } : {}), + ...(seedConstructions.length ? { seedConstructions } : {}), + ...(analysisInputs === undefined + ? {} + : { analysisInputs, rootAnalysisInputPaths: cohort.analysis!.rootInputs }), + }; + }), + }; + return { + evidence, + assertUnchanged() { + for (const capture of captures) capture.assertUnchanged(); + }, + }; +} + +/** The producing job must freeze inputs across build and capture; this observes current contents. */ +export function captureNativeBuildEvidence( + options: Parameters[0], +) { + const captured = collectNativeBuildEvidence(options); + const { source, github, bazelVersion } = options; + return { + ...captured, + qualification: validateNativeBuildEvidence(captured.evidence, { source, github, bazelVersion }), + }; +} + +/** Retain the native event index's protocol, excluding ambient invocation options and logs. */ +function retainedBuildEvents(evidence: NativeBuildEvidence, events: unknown[], scoped = false) { + const pick = (raw: unknown, fields: string[]) => { + const value = object(raw); + return Object.fromEntries( + fields.filter((field) => value[field] !== undefined).map((field) => [field, value[field]]), + ); + }; + const identity = (raw: unknown) => { + const value = { ...object(raw) }; + // Fetch URLs are unused by qualification and can contain credentials. + if (value.fetch !== undefined) value.fetch = pick(value.fetch, []); + return value; + }; + const files = (raw: unknown) => + array(raw ?? []).map((file) => + pick(file, ['pathPrefix', 'name', 'digest', 'length', 'symlinkTargetPath']), + ); + const sets = (raw: unknown) => array(raw ?? []).map((set) => pick(set, ['id'])); + const metadataKeys = new Set(Object.keys(nativeBuildMetadata(evidence.source, evidence.github))); + const nativeOptions = new Set([ + 'experimental_aquery_dump_after_build_format', + 'experimental_aquery_dump_after_build_output_file', + 'output_groups', + ...(scoped + ? ['output_file', ...NATIVE_AQUERY_FLAGS.map((flag) => flag.slice(2).split('=')[0])] + : []), + ]); + return events.map((raw) => { + const event = object(raw); + const retained: Record = pick(event, ['lastMessage']); + if (event.id !== undefined) retained.id = identity(event.id); + if (event.children !== undefined) retained.children = array(event.children).map(identity); + if (event.started !== undefined) + retained.started = pick(event.started, ['uuid', 'buildToolVersion']); + if (event.workspaceInfo !== undefined) + retained.workspaceInfo = pick(event.workspaceInfo, ['localExecRoot']); + if (event.configuration !== undefined) + retained.configuration = pick(event.configuration, [ + 'mnemonic', + 'platformName', + 'cpu', + 'isTool', + ]); + if (event.buildMetadata !== undefined) + retained.buildMetadata = { + metadata: Object.fromEntries( + Object.entries(object(event.buildMetadata.metadata)).filter(([key]) => + metadataKeys.has(key), + ), + ), + }; + if (event.finished !== undefined) + retained.finished = { + ...pick(event.finished, ['overallSuccess']), + exitCode: pick(event.finished.exitCode, ['name', 'code']), + }; + if (event.namedSetOfFiles !== undefined) + retained.namedSetOfFiles = { + files: files(event.namedSetOfFiles.files), + fileSets: sets(event.namedSetOfFiles.fileSets), + }; + if (event.completed !== undefined) + retained.completed = { + ...pick(event.completed, ['success']), + outputGroup: array(event.completed.outputGroup ?? []).map((group) => ({ + ...pick(group, ['name', 'incomplete']), + fileSets: sets(group.fileSets), + inlineFiles: files(group.inlineFiles), + })), + }; + if (event.aborted !== undefined) retained.aborted = pick(event.aborted, ['reason']); + if (event.testSummary !== undefined) + retained.testSummary = pick(event.testSummary, ['overallStatus', 'totalRunCount']); + if (event.testResult !== undefined) retained.testResult = pick(event.testResult, ['status']); + if (event.structuredCommandLine?.commandLineLabel === 'canonical') + retained.structuredCommandLine = { + commandLineLabel: 'canonical', + sections: [ + ...(scoped + ? array(event.structuredCommandLine.sections) + .filter((section) => ['command', 'residual'].includes(section.sectionLabel)) + .map((section) => ({ + sectionLabel: section.sectionLabel, + chunkList: { chunk: array(section.chunkList?.chunk).map(text) }, + })) + : []), + { + sectionLabel: 'command options', + optionList: { + option: array(event.structuredCommandLine.sections).flatMap((section) => + array(section.optionList?.option ?? []) + .filter((option) => nativeOptions.has(option.optionName)) + .map((option) => pick(option, ['optionName', 'optionValue'])), + ), + }, + }, + ], + }; + return retained; + }); +} + +/** Publish one validated packet without replacing a previous capture. */ +function writeCapturedNativeBuildEvidence( + captured: ReturnType, + directory: string, + expected?: Parameters[1], + report?: (phase: string) => void, +) { + const parent = requireSafeDirectoryChain(directory, { create: true, label: 'native evidence' }); + const temporary = mkdtempSync(path.join(parent, '.native-evidence-')); + const output = path.join(parent, 'native-build-evidence.json'); + let copiedFiles = false; + try { + report?.('pre-copy unchanged guard'); + captured.assertUnchanged(); + report?.('copying files/serializing'); + const file = path.join(temporary, 'evidence.json'); + const evidence = { + ...captured.evidence, + cohorts: captured.evidence.cohorts.map((cohort) => ({ + ...cohort, + buildEvents: retainedBuildEvents( + captured.evidence, + cohort.buildEvents, + cohort.producerCapture?.aqueryBuildEvents !== undefined, + ), + ...(cohort.producerCapture?.aqueryBuildEvents === undefined + ? {} + : { + producerCapture: { + ...cohort.producerCapture, + aqueryBuildEvents: retainedBuildEvents( + captured.evidence, + cohort.producerCapture.aqueryBuildEvents, + true, + ), + }, + }), + })), + }; + // The evidence remains the only inventory. Public regular leaves are copied + // before its immutable completion marker is installed. Only authenticated + // reached seed constructor Files accompany public outputs for promotion. + writeNativeBuildFinalFiles(evidence, parent); + copiedFiles = true; + writeFileSync(file, `${JSON.stringify(evidence)}\n`, { flag: 'wx', mode: 0o600 }); + if (expected !== undefined) { + report?.('serialized full validation'); + validateNativeBuildEvidence(JSON.parse(readFileSync(file, 'utf8')), expected); + } + report?.('post-copy unchanged guard'); + captured.assertUnchanged(); + linkSync(file, output); + report?.('completed'); + return output; + } catch (error) { + if (copiedFiles) rmSync(path.join(parent, 'files'), { recursive: true, force: true }); + throw error; + } finally { + rmSync(temporary, { recursive: true, force: true }); + } +} + +/** Preserve the validated programmatic capture boundary. */ +export function writeNativeBuildEvidence( + captured: ReturnType, + directory: string, +) { + return writeCapturedNativeBuildEvidence(captured, directory); +} + +function json(file: string) { + return JSON.parse(readFileSync(file, 'utf8')); +} +function jsonLines(file: string) { + return readFileSync(file, 'utf8') + .split(/\r?\n/u) + .filter((line) => line.trim()) + .map((line) => JSON.parse(line)); +} + +function main() { + const args = process.argv.slice(2); + const cohorts: NativeBuildCaptureCohort[] = []; + let githubFile: string | undefined; + let expectedFile: string | undefined; + let output: string | undefined; + let ref: string | undefined; + let metadata = false; + const value = () => { + const value = args.shift(); + if (!value || value.startsWith('--')) throw new Error('native capture argument is missing'); + return value; + }; + while (args.length) { + const option = args.shift(); + if (option === '--github-json' && githubFile === undefined) githubFile = value(); + else if (option === '--expected-qualification-json' && expectedFile === undefined) + expectedFile = value(); + else if (option === '--output-directory' && output === undefined) output = value(); + else if (option === '--source-ref' && ref === undefined) ref = value(); + else if (option === '--build-metadata' && !metadata) metadata = true; + else if (option === '--cohort') { + const roots = value(); + const cquery = value(); + const aquery = value(); + const buildEvents = value(); + const executionRoot = value(); + cohorts.push({ + roots: jsonLines(roots), + cquery: json(cquery), + aquery: json(aquery), + buildEvents: jsonLines(buildEvents), + executionRoot, + }); + } else if (option === '--producer-cohort') { + const roots = value(); + const aquery = value(); + const buildEvents = value(); + const executionRoot = value(); + cohorts.push({ + shippingRoots: json(roots), + aqueryFile: path.resolve(aquery), + // Query BEP follows this argument; decode only after all flags are parsed. + aquery: undefined, + buildEvents: jsonLines(buildEvents), + executionRoot, + }); + } else if (option === '--aquery-build-events') { + const cohort = cohorts.at(-1); + if (!cohort || !('shippingRoots' in cohort) || cohort.aqueryBuildEvents !== undefined) + throw new Error('--aquery-build-events requires one preceding producer cohort'); + cohort.aqueryBuildEvents = jsonLines(value()); + } else if (option === '--shipping-export') { + const cohort = cohorts.at(-1); + if (!cohort || !('shippingRoots' in cohort) || cohort.shippingExport !== undefined) + throw new Error('--shipping-export requires one preceding producer cohort'); + cohort.shippingExport = value(); + } else if (option === '--analysis-root-inputs') { + const cohort = cohorts.at(-1); + if (!cohort || cohort.analysis !== undefined) + throw new Error('--analysis-root-inputs requires one preceding cohort'); + const inputs = value(); + const workspace = value(); + cohort.analysis = { workspace: path.resolve(workspace), rootInputs: json(inputs) }; + } else throw new Error(`unknown or repeated native capture argument: ${option}`); + } + if (metadata) { + if (!githubFile || expectedFile || output || cohorts.length) + throw new Error('--build-metadata requires --github-json and no capture outputs/cohorts'); + for (const [key, value] of Object.entries( + nativeBuildMetadata(sourceIdentity(ref ?? 'HEAD'), json(githubFile)), + )) + console.log(`--build_metadata=${key}=${value}`); + return; + } + if (!githubFile || !output || !cohorts.length) + throw new Error( + 'usage: capture-native-build-evidence.mts --github-json FILE --producer-cohort ROOT_LABELS.json AQUERY_FILE BEP.jsonl EXECROOT [--producer-cohort ...] --output-directory DIR [--source-ref REF]', + ); + const bazelVersion = readFileSync(new URL('../../.bazelversion', import.meta.url), 'utf8').trim(); + for (const cohort of cohorts) + if ('shippingRoots' in cohort) + cohort.aquery = readNativeAquery( + cohort.aqueryFile, + cohort.aqueryBuildEvents === undefined + ? 'jsonproto' + : nativeAqueryOutputFormat(cohort.aqueryBuildEvents), + bazelVersion, + ); + const options = { + source: sourceIdentity(ref ?? 'HEAD'), + github: json(githubFile), + cohorts, + bazelVersion, + }; + if (expectedFile === undefined) { + console.log(writeNativeBuildEvidence(captureNativeBuildEvidence(options), output)); + } else { + const expected = object(json(expectedFile)); + const fields = ['source', 'github', 'bazelVersion']; + for (const optional of ['requiredTests', 'requireShippingAnalysis']) + if (Object.hasOwn(expected, optional)) fields.push(optional); + if (Object.keys(expected).sort().join(',') !== fields.sort().join(',')) + throw new Error('native qualification expectations require exact fields'); + if ( + Object.hasOwn(expected, 'requireShippingAnalysis') && + typeof expected.requireShippingAnalysis !== 'boolean' + ) + throw new Error('native qualification analysis expectation must be a boolean'); + const report = (phase: string) => console.error(`native capture: ${phase}`); + console.log( + writeCapturedNativeBuildEvidence( + collectNativeBuildEvidence(options, report), + output, + expected as Parameters[1], + report, + ), + ); + } +} + +if (import.meta.main) { + try { + main(); + } catch (error) { + console.error(error instanceof Error ? error.message : error); + process.exitCode = 1; + } +} diff --git a/tools/release/capture-native-build-evidence.test.mts b/tools/release/capture-native-build-evidence.test.mts new file mode 100644 index 000000000..492b4568c --- /dev/null +++ b/tools/release/capture-native-build-evidence.test.mts @@ -0,0 +1,1775 @@ +import { expect, spyOn, test } from 'bun:test'; +import { execFileSync, spawnSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + captureSeedConstructionIntent, + writeSeedConstructionReceipt, +} from '../../build_defs/resources/seed_construction.mts'; +import { buildShippingInputView } from './bazel-shipping-inputs.mts'; +import { + captureNativeBuildEvidence, + nativeRootConfigurations, + writeNativeBuildEvidence, +} from './capture-native-build-evidence.mts'; +import { readNativeBuildFinalFiles } from './native-build-files.mts'; +import { + nativeBuildMetadata, + nativeShippingRootsHaveQualification, + validateNativeBuildEvidence, +} from './native-build-qualification.mts'; +import { projectNativePublicationConstruction } from './native-publication-observation.mts'; + +function fixture() { + const directory = mkdtempSync(path.join(tmpdir(), 'native-build-capture-')); + const executionRoot = path.join(directory, 'execroot'); + const workspace = path.join(directory, 'workspace'); + const external = path.join(directory, 'repositories'); + const source = 'src/main.mts'; + const tool = 'external/compiler/bin/compiler'; + const generated = 'bazel-out/k8-opt/bin/generated'; + const inputTree = 'external/compiler/share'; + const output = 'bazel-out/k8-opt/bin/public/native.tar.gz'; + mkdirSync(path.join(workspace, 'src'), { recursive: true }); + mkdirSync(path.join(external, 'compiler/bin'), { recursive: true }); + mkdirSync(path.join(executionRoot, generated, 'empty'), { recursive: true }); + mkdirSync(path.dirname(path.join(executionRoot, output)), { recursive: true }); + writeFileSync(path.join(workspace, source), 'actual source input'); + writeFileSync(path.join(external, 'compiler/bin/compiler'), 'actual compiler input'); + chmodSync(path.join(external, 'compiler/bin/compiler'), 0o755); + writeFileSync(path.join(executionRoot, generated, 'config.h'), '#define CONFIG 1\n'); + writeFileSync(path.join(executionRoot, output), 'actual archive bytes'); + symlinkSync(path.join(workspace, 'src'), path.join(executionRoot, 'src'), 'dir'); + symlinkSync(external, path.join(executionRoot, 'external'), 'dir'); + mkdirSync(path.join(external, 'compiler/share/empty'), { recursive: true }); + writeFileSync(path.join(external, 'compiler/share/config.h'), '#define CONFIG 1\n'); + const paths = [source, tool, generated, output]; + const aquery = { + pathFragments: paths.flatMap((file, index) => + file.split('/').map((label, part) => ({ + id: `${index}-${part}`, + label, + ...(part ? { parentId: `${index}-${part - 1}` } : {}), + })), + ), + artifacts: paths.map((file, index) => ({ + id: index + 1, + pathFragmentId: `${index}-${file.split('/').length - 1}`, + })), + targets: [ + { id: 1, label: '//src:generate' }, + { id: 2, label: '//src:package' }, + ], + configuration: [{ id: 1, checksum: 'e'.repeat(64), isTool: true }], + depSetOfFiles: [ + { id: 1, directArtifactIds: [1] }, + { id: 2, directArtifactIds: [1, 2, 3] }, + ], + actions: [ + { + targetId: 1, + configurationId: 1, + actionKey: 'generator-definition', + mnemonic: 'Generate', + inputDepSetIds: [1], + outputIds: [3], + primaryOutputId: 3, + }, + { + targetId: 2, + configurationId: 1, + actionKey: 'package-definition', + mnemonic: 'Package', + inputDepSetIds: [2], + outputIds: [4], + primaryOutputId: 4, + }, + ], + }; + aquery.pathFragments.push( + ...inputTree.split('/').map((label, part) => ({ + id: `tree-${part}`, + label, + ...(part ? { parentId: `tree-${part - 1}` } : {}), + })), + ); + aquery.artifacts.push({ id: 10, pathFragmentId: `tree-${inputTree.split('/').length - 1}` }); + aquery.depSetOfFiles[1].directArtifactIds.push(10); + const root = { + label: '//src:shipping', + package: { + product: 'fixture', + version: '1.0.0', + ecosystem: 'github', + name: 'native.tar.gz', + configuration: 'linux-x64-gnu', + role: 'github-release-asset', + outputs: [{ path: output, owner: '//src:package' }], + }, + }; + // Actual CqueryResult JSON-proto field shape; these IDs are unrelated to aquery IDs. + const cquery = { + results: [ + { target: { rule: { name: root.label } }, configurationId: 17 }, + { target: { sourceFile: { name: '//src:main.mts' } } }, + ], + configurations: [{ id: 17, checksum: 'c'.repeat(64), mnemonic: 'k8-opt' }], + }; + const runGit = (...args: string[]) => + execFileSync('git', args, { cwd: workspace, encoding: 'utf8' }).trim(); + runGit('init', '--quiet'); + runGit('add', '.'); + runGit( + '-c', + 'user.name=Fixture', + '-c', + 'user.email=fixture@example.invalid', + 'commit', + '-qm', + 'fixture', + ); + const sourceIdentity = { + commit: runGit('rev-parse', 'HEAD'), + tree: runGit('rev-parse', 'HEAD^{tree}'), + }; + const github = { + repository: 'f0rr0/oliphaunt', + workflow: 'Native Bazel qualification', + workflowPath: '.github/workflows/bazel.yml', + runId: 456, + runAttempt: 2, + job: 'Linux runtime (x86_64)', + }; + const outputBytes = readFileSync(path.join(executionRoot, output)); + const events = [ + { id: { started: {} }, started: { uuid: 'fixture-invocation', buildToolVersion: '8.8.1' } }, + { id: { workspace: {} }, workspaceInfo: { localExecRoot: executionRoot } }, + { id: { configuration: { id: 'c'.repeat(64) } }, configuration: { mnemonic: 'k8-opt' } }, + { + id: { namedSet: { id: 'outputs' } }, + namedSetOfFiles: { + files: [ + { + pathPrefix: ['bazel-out', 'k8-opt', 'bin'], + name: 'public/native.tar.gz', + digest: createHash('sha256').update(outputBytes).digest('hex'), + length: String(outputBytes.length), + }, + ], + }, + }, + { + id: { targetCompleted: { label: root.label, configuration: { id: 'c'.repeat(64) } } }, + completed: { + success: true, + outputGroup: [{ name: 'default', fileSets: [{ id: 'outputs' }] }], + }, + }, + { + id: { buildMetadata: {} }, + buildMetadata: { metadata: nativeBuildMetadata(sourceIdentity, github) }, + }, + { id: { buildFinished: {} }, finished: { exitCode: { name: 'SUCCESS' } } }, + { id: { buildMetrics: {} }, buildMetrics: {}, lastMessage: true }, + ]; + const cohort = { executionRoot, roots: [root], cquery, aquery, buildEvents: events }; + const options = { source: sourceIdentity, github, cohorts: [cohort], bazelVersion: '8.8.1' }; + return { + directory, + executionRoot, + workspace, + external, + source, + tool, + generated, + inputTree, + output, + cohort, + options, + capture: () => captureNativeBuildEvidence(options), + cleanup: () => rmSync(directory, { recursive: true, force: true }), + }; +} + +function producerFixture() { + const f = fixture(); + const manifest = 'bazel-out/k8-opt/bin/src/shipping.shipping.json'; + const aqueryFile = path.join(f.directory, 'native-after-build.json'); + const graph = f.cohort.aquery; + const parts = manifest.split('/'); + graph.pathFragments.push( + ...parts.map((label, part) => ({ + id: `manifest-${part}`, + label, + ...(part ? { parentId: `manifest-${part - 1}` } : {}), + })), + ); + graph.artifacts.push({ id: 5, pathFragmentId: `manifest-${parts.length - 1}` }); + graph.targets.push({ id: 3, label: '//src:shipping' }); + graph.configuration.push({ id: 2, checksum: 'c'.repeat(64), isTool: false }); + const manifestAction = { + targetId: 3, + configurationId: 2, + actionKey: 'manifest-definition', + mnemonic: 'FileWrite', + inputDepSetIds: [], + outputIds: [5], + primaryOutputId: 5, + }; + graph.actions.push(manifestAction); + mkdirSync(path.dirname(path.join(f.executionRoot, manifest)), { recursive: true }); + const contents = `${JSON.stringify({ + ...f.cohort.roots[0], + label: '@@//src:shipping', + })}\n`; + writeFileSync(path.join(f.executionRoot, manifest), contents); + const events: any[] = structuredClone(f.cohort.buildEvents); + events.splice(3, 0, { + id: { namedSet: { id: 'manifest' } }, + namedSetOfFiles: { + files: [ + { + pathPrefix: ['bazel-out', 'k8-opt', 'bin', 'src'], + name: 'shipping.shipping.json', + digest: createHash('sha256').update(contents).digest('hex'), + length: String(Buffer.byteLength(contents)), + }, + ], + }, + }); + events + .find((event) => event.completed) + .completed.outputGroup.push({ + name: 'shipping_manifest', + fileSets: [{ id: 'manifest' }], + }); + events.splice(1, 0, { + id: { structuredCommandLine: { commandLineLabel: 'canonical' } }, + structuredCommandLine: { + commandLineLabel: 'canonical', + sections: [ + { + sectionLabel: 'command options', + optionList: { + option: [ + { + optionName: 'experimental_aquery_dump_after_build_format', + optionValue: 'jsonproto', + }, + { + optionName: 'experimental_aquery_dump_after_build_output_file', + optionValue: aqueryFile, + }, + ], + }, + }, + ], + }, + }); + const cohort = { + executionRoot: f.executionRoot, + aquery: f.cohort.aquery, + buildEvents: events, + shippingRoots: ['//src:shipping'], + aqueryFile, + }; + const options = { ...f.options, cohorts: [cohort] }; + return { + ...f, + manifest, + manifestAction, + contents, + events, + options, + capture: () => captureNativeBuildEvidence(options), + }; +} + +function ownerPolicyFixture() { + const f = producerFixture(); + const owner = '//src:shipping_export'; + const policyFile = 'bazel-out/k8-opt/bin/src/shipping_export.json'; + const configuration = 'c'.repeat(64); + const test = '//src:installed_test'; + const policy = { + schema: 'oliphaunt-bazel-shipping-v1', + scope: 'construction', + owner, + roots: ['//src:shipping'], + packages: f.cohort.roots.map((root) => root.package), + qualification: [test], + }; + const contents = `${JSON.stringify(policy)}\n`; + mkdirSync(path.dirname(path.join(f.executionRoot, policyFile)), { recursive: true }); + writeFileSync(path.join(f.executionRoot, policyFile), contents); + const graph = f.options.cohorts[0].aquery; + const parts = policyFile.split('/'); + graph.pathFragments.push( + ...parts.map((label, part) => ({ + id: `policy-${part}`, + label, + ...(part ? { parentId: `policy-${part - 1}` } : {}), + })), + ); + graph.artifacts.push({ id: 6, pathFragmentId: `policy-${parts.length - 1}` }); + graph.targets.push({ id: 4, label: owner }); + const action = { + targetId: 4, + configurationId: 2, + actionKey: 'owner-policy-definition', + mnemonic: 'FileWrite', + inputDepSetIds: [], + outputIds: [6], + primaryOutputId: 6, + }; + graph.actions.push(action); + const fileSet = { + id: { namedSet: { id: 'policy' } }, + namedSetOfFiles: { + files: [ + { + name: policyFile, + digest: createHash('sha256').update(contents).digest('hex'), + length: String(Buffer.byteLength(contents)), + }, + ], + }, + }; + const ownerEvent = { + id: { targetCompleted: { label: owner, configuration: { id: configuration } } }, + completed: { + success: true, + outputGroup: [{ name: 'shipping_policy', fileSets: [{ id: 'policy' }] }], + }, + }; + const testIdentity = { label: test, configuration: { id: configuration } }; + f.events.splice( + -1, + 0, + fileSet, + ownerEvent, + { id: { targetCompleted: testIdentity }, completed: { success: true } }, + { + id: { testResult: { ...testIdentity, run: 1, shard: 1, attempt: 1 } }, + testResult: { status: 'PASSED' }, + }, + { + id: { testSummary: testIdentity }, + testSummary: { overallStatus: 'PASSED', totalRunCount: 1 }, + }, + ); + const options = { ...f.options, cohorts: [{ ...f.options.cohorts[0], shippingExport: owner }] }; + return { + ...f, + policy, + policyFile, + action, + ownerEvent, + fileSet, + options, + rewrite() { + const contents = `${JSON.stringify(policy)}\n`; + writeFileSync(path.join(f.executionRoot, policyFile), contents); + Object.assign(fileSet.namedSetOfFiles.files[0], { + digest: createHash('sha256').update(contents).digest('hex'), + length: String(Buffer.byteLength(contents)), + }); + }, + }; +} + +function installedObserverFixture(platform: 'android' | 'ios') { + const f = ownerPolicyFixture(); + const graph = f.options.cohorts[0].aquery; + const specification = 'bazel-out/k8-opt/bin/src/installed.inputs.json'; + const replayFiles = + platform === 'android' + ? { + apk: 'bazel-out/k8-opt/bin/app/signed.apk', + proof: 'bazel-out/k8-opt/bin/app/proof.json', + sdk: 'bazel-out/k8-opt/bin/sdk/mobile.tgz', + } + : { + application: 'bazel-out/k8-opt/bin/app/app.zip', + sdk: 'bazel-out/k8-opt/bin/sdk/mobile.tgz', + }; + const files = [specification, ...Object.values(replayFiles)]; + const ids = files.map((_file, index) => 100 + index); + for (const [index, file] of files.entries()) { + const parts = file.split('/'); + graph.pathFragments.push( + ...parts.map((label, part) => ({ + id: `observer-${index}-${part}`, + label, + ...(part ? { parentId: `observer-${index}-${part - 1}` } : {}), + })), + ); + graph.artifacts.push({ + id: ids[index], + pathFragmentId: `observer-${index}-${parts.length - 1}`, + }); + mkdirSync(path.dirname(path.join(f.executionRoot, file)), { recursive: true }); + writeFileSync( + path.join(f.executionRoot, file), + index === 0 + ? JSON.stringify({ + replay: { + schema: 'oliphaunt-installed-mobile-replay-v1', + platform, + files: replayFiles, + }, + }) + : `actual installed observer bytes ${index}`, + ); + } + graph.targets.push({ id: 100, label: '//src:installed_test' }); + graph.depSetOfFiles.push({ id: 100, directArtifactIds: ids }); + const runfilesManifest = 'bazel-out/k8-opt/bin/src/installed.runfiles_manifest'; + const manifestParts = runfilesManifest.split('/'); + graph.pathFragments.push( + ...manifestParts.map((label, part) => ({ + id: `runfiles-${part}`, + label, + ...(part ? { parentId: `runfiles-${part - 1}` } : {}), + })), + ); + graph.artifacts.push({ id: 110, pathFragmentId: `runfiles-${manifestParts.length - 1}` }); + graph.depSetOfFiles.push({ id: 101, directArtifactIds: [110] }); + const specificationAction = { + targetId: 100, + configurationId: 2, + actionKey: 'installed-specification', + mnemonic: 'FileWrite', + inputDepSetIds: [], + outputIds: [ids[0]], + primaryOutputId: ids[0], + }; + const runfilesAction = { + targetId: 100, + configurationId: 2, + actionKey: 'installed-runfiles', + mnemonic: 'Middleman', + inputDepSetIds: [100], + outputIds: [110], + primaryOutputId: 110, + }; + const testAction = { + targetId: 100, + configurationId: 2, + actionKey: 'installed-test', + mnemonic: 'TestRunner', + inputDepSetIds: [101], + outputIds: [], + }; + graph.actions.push(specificationAction, runfilesAction, testAction); + const target = f.events.find( + (event) => event.id?.targetCompleted?.label === '//src:installed_test', + ); + const fileSet = { + id: { namedSet: { id: 'observer' } }, + namedSetOfFiles: { + files: files.map((file) => { + const bytes = readFileSync(path.join(f.executionRoot, file)); + return { + name: file, + digest: createHash('sha256').update(bytes).digest('hex'), + length: String(bytes.length), + }; + }), + }, + }; + target.completed.outputGroup = [{ name: 'observation_inputs', fileSets: [{ id: 'observer' }] }]; + f.events.splice(-1, 0, fileSet); + return { + ...f, + files, + specification, + specificationAction, + runfilesAction, + testAction, + target, + fileSet, + capture: () => captureNativeBuildEvidence(f.options), + }; +} + +for (const platform of ['android', 'ios'] as const) { + test(`exact ${platform} configured installed inputs survive the existing internal transport`, () => { + const f = installedObserverFixture(platform); + try { + const captured = f.capture(); + const records = captured.evidence.cohorts[0].qualificationInputs ?? []; + expect(records).toHaveLength(1); + expect(records[0].specification).toBe(f.specification); + expect(records[0].inputs.map(({ path }) => path).sort()).toEqual([...f.files].sort()); + expect(captured.qualification.testQualification).toBe('passed'); + const publicConstruction = buildShippingInputView( + { + schema: 'oliphaunt-bazel-shipping-v1', + scope: 'construction', + packages: captured.evidence.cohorts[0].roots.map(({ package: pkg }) => pkg), + }, + captured.evidence.cohorts[0].aquery, + ); + const directory = path.join(f.directory, 'observer-packet'); + const evidenceFile = writeNativeBuildEvidence(captured, directory); + const evidence = JSON.parse(readFileSync(evidenceFile, 'utf8')); + const packet = readNativeBuildFinalFiles(directory, evidence, f.options); + expect( + JSON.parse(readFileSync(packet.file(0, f.specification), 'utf8')).replay.platform, + ).toBe(platform); + expect(packet.files).toHaveLength(f.files.length + 1); + expect(packet.artifactRoots).toHaveLength(1); + expect(packet.artifactRoots[0]).toBe(path.join(directory, 'files/0', f.output)); + expect(packet.qualificationInputs).toEqual([{ cohort: 0, ...records[0] }]); + expect(packet.file(0, f.specification)).toBe( + path.join(directory, 'files/0', f.specification), + ); + expect(() => packet.file(1, f.specification)).toThrow(/requested declared File/); + expect(() => packet.file(0, '../substitution')).toThrow(/requested declared File/); + for (const file of f.files) + expect(readFileSync(path.join(directory, 'files/0', file))).toEqual( + readFileSync(path.join(f.executionRoot, file)), + ); + evidence.cohorts[0].qualificationInputs[0].specification = 'substituted.json'; + expect(packet.qualificationInputs[0].specification).toBe(f.specification); + const changed = structuredClone(captured.evidence); + const observer = (changed.cohorts[0].qualificationInputs ?? [])[0].inputs.find( + ({ path }) => path !== f.specification, + ); + if (!observer) throw new Error('missing observer fixture'); + observer.members[0].sha256 = 'f'.repeat(64); + expect(() => validateNativeBuildEvidence(changed, f.options)).toThrow(/observer digest/); + // Qualifier-only observations must not change any conventional publication view. + expect( + Object.values(publicConstruction.products) + .flatMap((product) => product.inputs) + .some((file) => f.files.includes(file)), + ).toBe(false); + writeFileSync( + path.join(directory, 'files/0', f.specification), + 'changed in downloaded packet', + ); + if (!packet.assertUnchanged) throw new Error('missing observed packet'); + expect(packet.assertUnchanged).toThrow(/changed after capture/); + expect(() => readNativeBuildFinalFiles(directory, captured.evidence, f.options)).toThrow( + /transport bytes/, + ); + } finally { + f.cleanup(); + } + }); +} + +test('installed observation records reject injected labels, wrong configuration and incomplete typed coverage', () => { + const f = installedObserverFixture('android'); + try { + const captured = f.capture(); + for (const mutation of [ + (cohort) => { + delete cohort.qualificationInputs; + }, + (cohort) => { + cohort.qualificationInputs.push(structuredClone(cohort.qualificationInputs[0])); + }, + (cohort) => { + cohort.qualificationInputs[0].label = '//src:injected_test'; + }, + (cohort) => { + cohort.qualificationInputs[0].configuration = 'd'.repeat(64); + }, + (cohort) => { + cohort.qualificationInputs[0].specification = f.files[1]; + }, + (cohort) => { + cohort.qualificationInputs[0].inputs.pop(); + }, + (cohort) => { + cohort.qualificationInputs[0].inputs.push(cohort.outputs[0]); + }, + (cohort) => { + cohort.qualificationInputs[0].unknown = true; + }, + (cohort) => { + cohort.qualificationInputs[0].inputs[0].members[0].size++; + }, + (cohort) => { + cohort.qualificationInputs[0].inputs[0].members[0].type = 'directory'; + }, + ]) { + const changed = structuredClone(captured.evidence); + mutation(changed.cohorts[0]); + expect(() => validateNativeBuildEvidence(changed, f.options)).toThrow(/qualification/); + } + const wrongSource = { ...f.options, source: { ...f.options.source, tree: 'f'.repeat(40) } }; + expect(() => validateNativeBuildEvidence(captured.evidence, wrongSource)).toThrow(/source/); + } finally { + f.cleanup(); + } +}); + +for (const fault of [ + 'unconsumed', + 'unrelated-helper', + 'compiler-only-substitute', + 'source-path-substitute', + 'foreign-test', + 'foreign-producer', + 'foreign-configuration', + 'duplicate-specification', + 'missing-specification', + 'duplicate-group', + 'too-many-files', + 'failed-test', +] as const) { + test(`actual installed input collector rejects ${fault}`, () => { + const f = installedObserverFixture('android'); + try { + if (fault === 'unconsumed') + f.options.cohorts[0].aquery.depSetOfFiles + .find(({ id }) => id === 100) + ?.directArtifactIds.pop(); + if (fault === 'unrelated-helper') f.testAction.inputDepSetIds = []; + if (fault === 'compiler-only-substitute') { + const graph = f.options.cohorts[0].aquery; + const compilerInput = 'bazel-out/k8-opt/bin/app/compiler-input.h'; + const parts = compilerInput.split('/'); + graph.pathFragments.push( + ...parts.map((label, part) => ({ + id: `compiler-${part}`, + label, + ...(part ? { parentId: `compiler-${part - 1}` } : {}), + })), + ); + graph.artifacts.push({ id: 120, pathFragmentId: `compiler-${parts.length - 1}` }); + mkdirSync(path.dirname(path.join(f.executionRoot, compilerInput)), { recursive: true }); + writeFileSync(path.join(f.executionRoot, compilerInput), 'compiler-only generated input'); + graph.depSetOfFiles.push({ id: 120, directArtifactIds: [120] }); + graph.actions.push({ + targetId: 2, + configurationId: 2, + actionKey: 'apk-definition', + mnemonic: 'ApkPackage', + inputDepSetIds: [120], + outputIds: [101], + primaryOutputId: 101, + }); + const bytes = readFileSync(path.join(f.executionRoot, compilerInput)); + Object.assign(f.fileSet.namedSetOfFiles.files[1], { + name: compilerInput, + digest: createHash('sha256').update(bytes).digest('hex'), + length: String(bytes.length), + }); + } + if (fault === 'source-path-substitute') { + const bytes = readFileSync(path.join(f.executionRoot, f.source)); + Object.assign(f.fileSet.namedSetOfFiles.files[1], { + name: f.source, + digest: createHash('sha256').update(bytes).digest('hex'), + length: String(bytes.length), + }); + } + if (fault === 'foreign-test') f.testAction.configurationId = 1; + if (fault === 'foreign-producer') f.specificationAction.targetId = 4; + if (fault === 'foreign-configuration') f.specificationAction.configurationId = 1; + if (fault === 'duplicate-specification') f.specificationAction.outputIds.push(101); + if (fault === 'missing-specification') f.specificationAction.mnemonic = 'TemplateExpand'; + if (fault === 'duplicate-group') + f.target.completed.outputGroup.push(f.target.completed.outputGroup[0]); + if (fault === 'too-many-files') + f.fileSet.namedSetOfFiles.files.push({ + name: f.output, + ...(() => { + const bytes = readFileSync(path.join(f.executionRoot, f.output)); + return { + digest: createHash('sha256').update(bytes).digest('hex'), + length: String(bytes.length), + }; + })(), + }); + if (fault === 'failed-test') + Object.assign(f.events.find((event) => event.testResult)?.testResult ?? {}, { + status: 'FAILED', + }); + expect(f.capture).toThrow(/qualification|observer|specification|successful test/); + } finally { + f.cleanup(); + } + }); +} + +test('old diagnostic evidence cannot inject qualification replay inputs', () => { + const f = fixture(); + try { + const captured = f.capture(); + captured.evidence.cohorts[0].qualificationInputs = [ + { + label: '//src:injected_test', + configuration: 'c'.repeat(64), + specification: f.output, + inputs: captured.evidence.cohorts[0].outputs, + }, + ]; + expect(() => validateNativeBuildEvidence(captured.evidence, f.options)).toThrow( + /source-owned observer/, + ); + } finally { + f.cleanup(); + } +}); + +test('one BEP-bound owner export proves exact root coverage and mandatory configured tests', () => { + const f = ownerPolicyFixture(); + try { + const captured = captureNativeBuildEvidence(f.options); + expect(captured.qualification.qualificationPolicy).toBe('bound'); + expect(captured.qualification.testQualification).toBe('passed'); + expect(captured.qualification.requiredTests).toEqual([ + { + label: '//src:installed_test', + configuration: 'c'.repeat(64), + invocationId: 'fixture-invocation', + }, + ]); + expect(captured.qualification.cohorts[0].qualificationPolicy?.roots).toEqual([ + '//src:shipping', + ]); + expect(() => + validateNativeBuildEvidence(captured.evidence, { + ...f.options, + requiredTests: [{ label: '//src:unrelated_test', configuration: 'c'.repeat(64) }], + }), + ).toThrow(/omits source-owned mandatory configured test/); + writeFileSync(path.join(f.executionRoot, f.policyFile), 'substituted after capture'); + expect(() => captured.assertUnchanged()).toThrow(/changed after capture/); + } finally { + f.cleanup(); + } +}); + +test('configuration trimming binds shipping roots separately from their owner and mandatory tests', () => { + const f = ownerPolicyFixture(); + try { + const configuration = 'd'.repeat(64); + f.events.splice(-1, 0, { + id: { configuration: { id: configuration } }, + configuration: { mnemonic: 'trimmed-package' }, + }); + f.events.find( + (event) => event.id?.targetCompleted?.label === '//src:shipping', + ).id.targetCompleted.configuration.id = configuration; + f.options.cohorts[0].aquery.configuration.push({ + id: 3, + checksum: configuration, + isTool: false, + }); + f.manifestAction.configurationId = 3; + const captured = captureNativeBuildEvidence(f.options); + expect(captured.qualification.qualificationPolicy).toBe('bound'); + expect(captured.qualification.cohorts[0].qualificationPolicy?.configuration).toBe( + 'c'.repeat(64), + ); + expect(captured.qualification.cohorts[0].qualificationPolicy?.rootConfigurations).toEqual([ + { label: '//src:shipping', configuration }, + ]); + expect(captured.qualification.requiredTests[0].configuration).toBe('c'.repeat(64)); + } finally { + f.cleanup(); + } +}); + +test('composed source owners retain their own root qualification rather than sharing a test union', () => { + const f = ownerPolicyFixture(); + try { + Object.assign(f.policy, { + policies: [ + { + owner: '//src:original_owner', + roots: f.policy.roots, + qualification: f.policy.qualification, + }, + ], + }); + f.rewrite(); + const policy = captureNativeBuildEvidence(f.options).qualification.cohorts[0] + .qualificationPolicy; + expect(policy?.policies[0].owner).toBe('//src:original_owner'); + expect(nativeShippingRootsHaveQualification(policy, [{ label: '//src:shipping' }])).toBe(true); + const separate = { + ...policy!, + roots: ['//src:shipping', '//src:empty'], + policies: [ + ...policy!.policies, + { owner: '//src:empty_owner', roots: ['//src:empty'], requiredTests: [] }, + ], + }; + expect(nativeShippingRootsHaveQualification(separate, [{ label: '//src:shipping' }])).toBe( + true, + ); + expect(nativeShippingRootsHaveQualification(separate, [{ label: '//src:empty' }])).toBe(false); + expect( + nativeShippingRootsHaveQualification(separate, [ + { label: '//src:shipping' }, + { label: '//src:empty' }, + ]), + ).toBe(false); + f.policy.policies.push({ + owner: '//src:other_owner', + roots: f.policy.roots, + qualification: [], + }); + f.rewrite(); + expect(() => captureNativeBuildEvidence(f.options)).toThrow( + /source owner policy root coverage/, + ); + } finally { + f.cleanup(); + } +}); + +for (const scenario of [ + 'digest', + 'missing-root', + 'extra-root', + 'wrong-package', + 'duplicate-test', + 'foreign-configuration', + 'failed-test', + 'missing-test', + 'different-action', +] as const) + test(`source-owned owner policy rejects ${scenario}`, () => { + const f = ownerPolicyFixture(); + try { + if (scenario === 'digest') f.fileSet.namedSetOfFiles.files[0].digest = 'f'.repeat(64); + else if (scenario === 'missing-root') f.policy.roots = []; + else if (scenario === 'extra-root') f.policy.roots.push('//src:foreign'); + else if (scenario === 'wrong-package') f.policy.packages[0].version = '9.9.9'; + else if (scenario === 'duplicate-test') f.policy.qualification.push('//src:installed_test'); + else if (scenario === 'foreign-configuration') + f.ownerEvent.id.targetCompleted.configuration.id = 'f'.repeat(64); + else if (scenario === 'failed-test') + f.events.find((event) => event.testResult).testResult.status = 'FAILED'; + else if (scenario === 'missing-test') + f.events.splice( + f.events.findIndex((event) => event.testSummary), + 1, + ); + else f.action.mnemonic = 'Package'; + if (scenario !== 'digest') f.rewrite(); + expect(() => captureNativeBuildEvidence(f.options)).toThrow(); + } finally { + f.cleanup(); + } + }); + +test('an empty source-owned policy stays unverified and old packets gain no qualification', () => { + const f = ownerPolicyFixture(); + const old = producerFixture(); + try { + f.policy.qualification = []; + f.rewrite(); + expect(captureNativeBuildEvidence(f.options).qualification.qualificationPolicy).toBe( + 'unverified', + ); + expect(captureNativeBuildEvidence(old.options).qualification.qualificationPolicy).toBe( + 'unverified', + ); + } finally { + f.cleanup(); + old.cleanup(); + } +}); + +test('native producer derives exact roots from BEP manifests without a later query', () => { + const f = producerFixture(); + try { + const captured = f.capture(); + const cohort = captured.evidence.cohorts[0]; + expect(cohort.roots).toEqual([{ ...f.cohort.roots[0], label: '@@//src:shipping' }]); + expect(cohort.rootConfigurations).toEqual([ + { label: '@@//src:shipping', configuration: 'c'.repeat(64) }, + ]); + expect(cohort.producerCapture?.shippingManifests).toEqual([ + { path: f.manifest, contents: f.contents }, + ]); + expect(captured.qualification.shippingAnalysis).toBe('bound'); + expect(captured.qualification.releaseDecision).toBe('unverified'); + expect(captured.qualification.unverified).toContain( + 'native action-graph dump bytes authenticated by the producing invocation', + ); + expect( + validateNativeBuildEvidence(captured.evidence, { + ...f.options, + requireShippingAnalysis: true, + }).shippingAnalysis, + ).toBe('bound'); + writeFileSync(path.join(f.executionRoot, f.manifest), `${f.contents} `); + expect(() => captured.assertUnchanged()).toThrow(/changed after capture/); + expect(() => writeNativeBuildEvidence(captured, path.join(f.directory, 'evidence'))).toThrow(); + } finally { + f.cleanup(); + } +}); + +test('old query-based evidence remains diagnostic and cannot satisfy native analysis policy', () => { + const f = fixture(); + try { + const captured = f.capture(); + expect(captured.qualification.shippingAnalysis).toBe('unverified'); + expect(() => + validateNativeBuildEvidence(captured.evidence, { + ...f.options, + requireShippingAnalysis: true, + }), + ).toThrow(/producing-analysis shipping manifests/); + } finally { + f.cleanup(); + } +}); + +test('serialized native evidence excludes ambient options and logs while retaining qualification facts', () => { + const f = producerFixture(); + const secret = 'sentinel-invocation-secret'; + const configuration = 'c'.repeat(64); + const consumer = '//src:consumer'; + try { + f.events.find((event) => event.started).started.optionsDescription = + `--repo_env=TOKEN=${secret}`; + f.events.find((event) => event.configuration).configuration.makeVariable = { TOKEN: secret }; + f.events.find((event) => event.buildMetadata).buildMetadata.metadata.UNUSED_TOKEN = secret; + const command = f.events.find((event) => event.structuredCommandLine).structuredCommandLine; + command.sections[0].optionList.option[0].combinedForm = secret; + command.sections[0].optionList.option.push( + { optionName: 'client_env', optionValue: `TOKEN=${secret}` }, + { optionName: 'output_groups', optionValue: 'default,shipping_manifest' }, + ); + command.sections.push({ sectionLabel: 'executable', chunkList: { chunk: [secret] } }); + const unused = [ + { id: { unstructuredCommandLine: {} }, unstructuredCommandLine: { args: [secret] } }, + { id: { optionsParsed: {} }, optionsParsed: { cmdLine: [secret] } }, + { + id: { structuredCommandLine: { commandLineLabel: 'original' } }, + structuredCommandLine: { + commandLineLabel: 'original', + sections: [{ chunkList: { chunk: [secret] } }], + }, + }, + { id: { progress: { opaqueCount: 1 } }, progress: { stdout: secret, stderr: secret } }, + { id: { workspaceStatus: {} }, workspaceStatus: { item: [{ key: 'TOKEN', value: secret }] } }, + { + id: { buildToolLogs: {} }, + buildToolLogs: { log: [{ name: 'command', contents: secret, uri: secret }] }, + }, + { + id: { actionCompleted: { primaryOutput: 'unused' } }, + action: { commandLine: [secret], strategyDetails: secret }, + }, + { + id: { execRequest: {} }, + execRequest: { argv: [secret], environmentVariable: [{ name: 'TOKEN', value: secret }] }, + }, + { + id: { fetch: { url: `https://example.invalid/${secret}` } }, + children: [{ fetch: { url: `https://example.invalid/${secret}` } }], + }, + ]; + const testEvents = [ + { + id: { targetCompleted: { label: consumer, configuration: { id: configuration } } }, + completed: { success: true }, + }, + { + id: { + testResult: { + label: consumer, + configuration: { id: configuration }, + run: 1, + shard: 0, + attempt: 1, + }, + }, + testResult: { status: 'PASSED', testActionOutput: [{ contents: secret, uri: secret }] }, + }, + { + id: { testSummary: { label: consumer, configuration: { id: configuration } } }, + testSummary: { + overallStatus: 'PASSED', + totalRunCount: 1, + passed: [{ contents: secret, uri: secret }], + }, + }, + ]; + const named = f.events.find((event) => event.namedSetOfFiles); + command.sections.push( + { sectionLabel: 'command', chunkList: { chunk: ['build'] } }, + { sectionLabel: 'residual', chunkList: { chunk: [secret] } }, + { + sectionLabel: 'command options', + optionList: { option: [{ optionName: 'output_file', optionValue: secret }] }, + }, + ); + named.namedSetOfFiles.files[0].uri = secret; + named.namedSetOfFiles.files[0].contents = secret; + f.events.splice(-1, 0, ...unused, ...testEvents); + const captured = f.capture(); + const output = writeNativeBuildEvidence(captured, path.join(f.directory, 'evidence')); + const contents = readFileSync(output, 'utf8'); + expect(contents).not.toContain(secret); + const packet = JSON.parse(contents); + const retained = packet.cohorts[0].buildEvents; + expect(retained.map((event: any) => event.id)).toEqual( + f.events.map((event) => ({ ...event.id, ...(event.id.fetch ? { fetch: {} } : {}) })), + ); + expect(retained.at(-1).lastMessage).toBe(true); + expect(retained.find((event: any) => event.children).children).toEqual([{ fetch: {} }]); + expect(retained.find((event: any) => event.buildMetadata).buildMetadata.metadata).toEqual( + nativeBuildMetadata(f.options.source, f.options.github), + ); + expect( + retained + .find((event: any) => event.structuredCommandLine) + .structuredCommandLine.sections[0].optionList.option.map( + (option: any) => option.optionName, + ), + ).toEqual([ + 'experimental_aquery_dump_after_build_format', + 'experimental_aquery_dump_after_build_output_file', + 'output_groups', + ]); + const result = validateNativeBuildEvidence(packet, { + ...f.options, + requireShippingAnalysis: true, + requiredTests: [{ label: consumer, configuration }], + }); + expect(result.shippingAnalysis).toBe('bound'); + expect(result.releaseDecision).toBe('unverified'); + } finally { + f.cleanup(); + } +}); + +test('native producer rejects missing, cross-configured, corrupt and misrouted manifest receipts', () => { + for (const mutate of [ + (f: ReturnType) => { + f.options.cohorts[0].shippingRoots.push('//src:shipping'); + }, + (f: ReturnType) => { + f.options.cohorts[0].shippingRoots[0] = '//src:other'; + }, + (f: ReturnType) => { + f.events.find((e) => e.completed).completed.outputGroup.pop(); + }, + (f: ReturnType) => { + f.events.find( + (e) => e.namedSetOfFiles?.files[0]?.name === 'shipping.shipping.json', + ).namedSetOfFiles.files[0].digest = 'f'.repeat(64); + }, + (f: ReturnType) => { + f.events.find((e) => e.completed).id.targetCompleted.configuration.id = 'missing'; + }, + (f: ReturnType) => { + f.events.splice(-1, 0, structuredClone(f.events.find((e) => e.completed))); + }, + (f: ReturnType) => { + f.events + .find((e) => e.structuredCommandLine) + .structuredCommandLine.sections[0].optionList.option.pop(); + }, + (f: ReturnType) => { + f.events.find( + (e) => e.structuredCommandLine, + ).structuredCommandLine.sections[0].optionList.option[0].optionValue = 'textproto'; + }, + (f: ReturnType) => { + writeFileSync(path.join(f.executionRoot, f.manifest), f.contents.replace('1.0.0', '2.0.0')); + }, + (f: ReturnType) => { + f.manifestAction.configurationId = 1; + }, + (f: ReturnType) => { + f.manifestAction.targetId = 2; + }, + (f: ReturnType) => { + f.manifestAction.mnemonic = 'ForeignWrite'; + }, + ]) { + const f = producerFixture(); + try { + mutate(f); + expect(f.capture).toThrow(); + } finally { + f.cleanup(); + } + } +}); + +test('packet validation independently rejects substituted root inventory and manifest contents', () => { + const f = producerFixture(); + try { + const captured = f.capture(); + for (const mutate of [ + (packet: any) => { + packet.cohorts[0].roots[0].package.version = '9.0.0'; + }, + (packet: any) => { + packet.cohorts[0].rootConfigurations[0].configuration = 'wrong'; + }, + (packet: any) => { + packet.cohorts[0].producerCapture.shippingManifests[0].contents += ' '; + }, + (packet: any) => { + packet.cohorts[0].producerCapture.shippingManifests.push( + packet.cohorts[0].producerCapture.shippingManifests[0], + ); + }, + (packet: any) => { + packet.cohorts[0].producerCapture.aqueryFile += '.other'; + }, + ]) { + const packet = structuredClone(captured.evidence); + mutate(packet); + expect(() => validateNativeBuildEvidence(packet, f.options)).toThrow(); + } + } finally { + f.cleanup(); + } +}); + +test('configured metadata FileWrites accept empty transitive sets and reject added or malformed inputs', () => { + for (const kind of ['manifest', 'owner'] as const) { + const f = ownerPolicyFixture(); + try { + const before = captureNativeBuildEvidence(f.options).qualification; + const graph = f.options.cohorts[0].aquery; + const action = kind === 'manifest' ? f.manifestAction : f.action; + const child = { + id: 91, + directArtifactIds: [] as number[], + transitiveDepSetIds: [] as number[], + }; + graph.depSetOfFiles.push( + { id: 90, directArtifactIds: [], transitiveDepSetIds: [91] } as any, + child, + ); + action.inputDepSetIds = [90]; + const after = captureNativeBuildEvidence(f.options).qualification; + expect(after.cohorts[0].actionDefinitionsDigest).toBe( + before.cohorts[0].actionDefinitionsDigest, + ); + expect(after.cohorts[0].inputContentsDigest).toBe(before.cohorts[0].inputContentsDigest); + expect(after.cohorts[0].roots).toEqual(before.cohorts[0].roots); + const primaryOutput = action.primaryOutputId; + action.primaryOutputId = 999; + expect(() => captureNativeBuildEvidence(f.options)).toThrow('incomplete aquery'); + action.primaryOutputId = primaryOutput; + child.directArtifactIds = [1]; + expect(() => captureNativeBuildEvidence(f.options)).toThrow( + kind === 'manifest' + ? 'native shipping manifest requires its configured FileWrite action' + : 'native owner qualification requires its configured FileWrite action', + ); + action.inputDepSetIds = [999]; + expect(() => captureNativeBuildEvidence(f.options)).toThrow('incomplete aquery'); + action.inputDepSetIds = [90]; + child.directArtifactIds = []; + child.transitiveDepSetIds = [90]; + expect(() => captureNativeBuildEvidence(f.options)).toThrow('cycle in aquery input dep sets'); + } finally { + f.cleanup(); + } + } +}); + +test('collector reads declared source/repository links and source trees after cache-backed success', () => { + const f = fixture(); + const stderr = spyOn(console, 'error'); + try { + const capture = f.capture(); + expect(capture.evidence.cohorts[0].rootConfigurations).toEqual([ + { label: '//src:shipping', configuration: 'c'.repeat(64) }, + ]); + expect(capture.evidence.cohorts[0].inputs.map(({ path }) => path)).toEqual( + [f.inputTree, f.tool, f.source].sort(), + ); + const tree = capture.evidence.cohorts[0].inputs.find(({ path }) => path === f.inputTree)!; + expect(tree.members.map(({ path }) => path)).toEqual(['', 'config.h', 'empty']); + expect( + capture.evidence.cohorts[0].inputs.find(({ path }) => path === f.tool)!.members[0].mode, + ).toBe(0o755); + expect(capture.qualification.releaseDecision).toBe('unverified'); + expect(capture.qualification.unverified).toContain( + 'immutable input lifetime from the producing build through content capture', + ); + const output = writeNativeBuildEvidence(capture, path.join(f.directory, 'evidence')); + const packet = JSON.parse(readFileSync(output, 'utf8')); + expect(validateNativeBuildEvidence(packet, f.options).scope).toBe('construction'); + const original = readFileSync(output); + expect(() => writeNativeBuildEvidence(capture, path.dirname(output))).toThrow(); + expect(readFileSync(output)).toEqual(original); + expect(stderr.mock.calls).toHaveLength(0); + } finally { + stderr.mockRestore(); + f.cleanup(); + } +}); + +test('cquery checksum resolution rejects ambiguous, missing, null and substituted root configurations', () => { + const f = fixture(); + try { + for (const mutate of [ + (query: any) => { + query.results = []; + }, + (query: any) => { + query.results.push(query.results[0]); + }, + (query: any) => { + query.results[0].configurationId = 0; + }, + (query: any) => { + query.results[0].configurationId = 99; + }, + (query: any) => { + query.configurations.push(query.configurations[0]); + }, + (query: any) => { + query.configurations[0].checksum = ''; + }, + ]) { + const query = structuredClone(f.cohort.cquery); + mutate(query); + expect(() => nativeRootConfigurations(f.cohort.roots, query)).toThrow(); + } + f.cohort.cquery.configurations[0].checksum = 'd'.repeat(64); + expect(f.capture).toThrow('shipping configuration mismatch'); + } finally { + f.cleanup(); + } +}); + +test('actual main-repository label spellings agree without conflating external repositories', () => { + const f = fixture(); + try { + // Starlark str(Label) uses @@//; CqueryResult and BEP use // for the main repository. + f.cohort.roots[0].label = '@@//src:shipping'; + f.cohort.roots[0].package.outputs[0].owner = '@@//src:package'; + const capture = f.capture(); + expect(capture.evidence.cohorts[0].roots[0].label).toBe('@@//src:shipping'); + expect(capture.evidence.cohorts[0].rootConfigurations[0].label).toBe('@@//src:shipping'); + expect(capture.qualification.cohorts[0].roots[0].label).toBe('@@//src:shipping'); + f.cohort.roots[0].label = '@@foreign//src:shipping'; + expect(f.capture).toThrow(/one configured rule/); + } finally { + f.cleanup(); + } +}); + +test('virtual runfiles Middleman retains its real input closure without requiring a synthetic file', () => { + const f = fixture(); + try { + const virtual = 'bazel-out/k8-opt/internal/_middlemen/compiler-runfiles'; + const parts = virtual.split('/'); + const graph = f.cohort.aquery; + graph.pathFragments.push( + ...parts.map((label, part) => ({ + id: `middleman-${part}`, + label, + ...(part ? { parentId: `middleman-${part - 1}` } : {}), + })), + ); + graph.artifacts.push({ id: 5, pathFragmentId: `middleman-${parts.length - 1}` }); + graph.depSetOfFiles.push({ id: 3, directArtifactIds: [1, 2] }); + graph.depSetOfFiles[1].directArtifactIds.push(5); + const connector = { + targetId: 1, + configurationId: 1, + actionKey: 'virtual-runfiles-connector', + mnemonic: 'Middleman', + inputDepSetIds: [3], + outputIds: [5], + primaryOutputId: 5, + }; + graph.actions.push(connector); + const capture = f.capture(); + expect(capture.evidence.cohorts[0].inputs.map(({ path }) => path)).toEqual( + [f.inputTree, f.tool, f.source].sort(), + ); + expect(capture.evidence.cohorts[0].aquery).toEqual(graph); + expect(existsSync(path.join(f.executionRoot, virtual))).toBe(false); + // A generated intermediate need not be materialized after a cache hit. + connector.mnemonic = 'FileWrite'; + expect(f.capture().evidence.cohorts[0].aquery).toEqual(graph); + connector.mnemonic = 'Middleman'; + rmSync(path.join(f.external, 'compiler/bin/compiler')); + expect(f.capture).toThrow(/compiler\/bin\/compiler/); + } finally { + f.cleanup(); + } +}); + +test('missing required inputs and changed bytes, modes, links or source tree membership prevent publication of capture', () => { + for (const mutate of [ + (f: ReturnType) => + writeFileSync(path.join(f.workspace, f.source), 'changed source'), + (f: ReturnType) => + chmodSync(path.join(f.external, 'compiler/bin/compiler'), 0o644), + (f: ReturnType) => + writeFileSync(path.join(f.executionRoot, f.inputTree, 'extra'), 'extra'), + (f: ReturnType) => { + const replacement = path.join(f.directory, 'replacement'); + mkdirSync(replacement); + writeFileSync(path.join(replacement, 'main.mts'), 'actual source input'); + rmSync(path.join(f.executionRoot, 'src')); + symlinkSync(replacement, path.join(f.executionRoot, 'src'), 'dir'); + }, + ]) { + const f = fixture(); + try { + const capture = f.capture(); + mutate(f); + const output = path.join(f.directory, 'evidence'); + expect(() => writeNativeBuildEvidence(capture, output)).toThrow(/changed after capture/); + expect(existsSync(path.join(output, 'native-build-evidence.json'))).toBe(false); + } finally { + f.cleanup(); + } + } + const f = fixture(); + try { + rmSync(path.join(f.executionRoot, f.inputTree, 'config.h')); + symlinkSync( + path.join(f.workspace, f.source), + path.join(f.executionRoot, f.inputTree, 'config.h'), + ); + expect(f.capture).toThrow(/regular file or directory/); + rmSync(path.join(f.external, 'compiler/bin/compiler')); + expect(f.capture).toThrow(); + } finally { + f.cleanup(); + } +}); + +test('collector CLI consumes captured protocol files, exact Git snapshot context and validates before writing', () => { + const f = fixture(); + try { + const file = (name: string, value: unknown, lines = false) => { + const target = path.join(f.directory, name); + writeFileSync( + target, + lines + ? (value as unknown[]).map((row) => JSON.stringify(row)).join('\n') + : JSON.stringify(value), + ); + return target; + }; + const args = [ + '--github-json', + file('github.json', f.options.github), + '--cohort', + file('roots.jsonl', f.cohort.roots, true), + file('cquery.json', f.cohort.cquery), + file('aquery.json', f.cohort.aquery), + file('bep.jsonl', f.cohort.buildEvents, true), + f.executionRoot, + '--output-directory', + path.join(f.directory, 'evidence'), + ]; + const cli = path.resolve(import.meta.dir, 'capture-native-build-evidence.mts'); + const env = { + ...process.env, + OLIPHAUNT_GIT_SOURCE_JSON: JSON.stringify({ + ...f.options.source, + ref: 'HEAD', + checkout: f.options.source.commit, + }), + }; + const run = (environment = env) => + execFileSync(process.execPath, [cli, ...args], { + cwd: f.workspace, + env: environment, + encoding: 'utf8', + stdio: ['ignore', 'pipe', 'pipe'], + }); + expect(() => run({ ...env, OLIPHAUNT_GIT_SOURCE_JSON: '{}' })).toThrow(); + expect(existsSync(path.join(f.directory, 'evidence/native-build-evidence.json'))).toBe(false); + const failed = structuredClone(f.cohort.buildEvents); + (failed[6] as any).finished.exitCode.name = 'FAILURE'; + file('bep.jsonl', failed, true); + expect(() => run()).toThrow(); + expect(existsSync(path.join(f.directory, 'evidence/native-build-evidence.json'))).toBe(false); + file('bep.jsonl', f.cohort.buildEvents, true); + const output = run().trim(); + expect(JSON.parse(readFileSync(output, 'utf8')).source).toEqual(f.options.source); + expect(() => run()).toThrow(); + } finally { + f.cleanup(); + } +}); + +test('build metadata CLI prints the shared validated flags with spaces and rejects incomplete context', () => { + const f = fixture(); + try { + const github = path.join(f.directory, 'github.json'); + writeFileSync(github, JSON.stringify(f.options.github)); + const cli = path.resolve(import.meta.dir, 'capture-native-build-evidence.mts'); + const args = [cli, '--build-metadata', '--github-json', github]; + const environment = { + ...process.env, + OLIPHAUNT_GIT_SOURCE_JSON: JSON.stringify({ + ...f.options.source, + ref: 'HEAD', + checkout: f.options.source.commit, + }), + }; + const run = () => + execFileSync(process.execPath, args, { + env: environment, + encoding: 'utf8', + stdio: ['ignore', 'pipe', 'pipe'], + }); + expect(run().trim().split('\n')).toEqual( + Object.entries(nativeBuildMetadata(f.options.source, f.options.github)).map( + ([key, value]) => `--build_metadata=${key}=${value}`, + ), + ); + expect(run()).toContain('--build_metadata=oliphaunt_job=Linux runtime (x86_64)\n'); + writeFileSync(github, JSON.stringify({ ...f.options.github, runAttempt: 0 })); + expect(run).toThrow(); + writeFileSync(github, JSON.stringify(f.options.github)); + environment.OLIPHAUNT_GIT_SOURCE_JSON = '{}'; + expect(run).toThrow(); + } finally { + f.cleanup(); + } +}); + +test('collector qualification expectations bind written bytes and both physical mutation windows', () => { + const cli = path.resolve(import.meta.dir, 'capture-native-build-evidence.mts'); + for (const fault of [ + 'none', + 'source', + 'github', + 'version', + 'test-label', + 'test-configuration', + 'unknown-fields', + 'analysis-type', + 'serialized-summary', + 'before-copy', + 'after-serialize', + ]) { + const f = ownerPolicyFixture(); + try { + const cohort = f.options.cohorts[0]; + const file = (name: string, value: unknown, lines = false) => { + const target = path.join(f.directory, name); + writeFileSync( + target, + lines + ? (value as unknown[]).map((row) => JSON.stringify(row)).join('\n') + : JSON.stringify(value), + ); + return target; + }; + writeFileSync(cohort.aqueryFile, JSON.stringify(cohort.aquery)); + const expected: any = { + source: f.options.source, + github: f.options.github, + bazelVersion: f.options.bazelVersion, + requiredTests: [{ label: '//src:installed_test', configuration: 'c'.repeat(64) }], + requireShippingAnalysis: true, + }; + if (fault === 'source') expected.source = { ...expected.source, tree: 'd'.repeat(40) }; + if (fault === 'github') expected.github = { ...expected.github, runAttempt: 99 }; + if (fault === 'version') expected.bazelVersion = '8.8.0'; + if (fault === 'test-label') expected.requiredTests[0].label = '//src:unrelated_test'; + if (fault === 'test-configuration') expected.requiredTests[0].configuration = 'd'.repeat(64); + if (fault === 'unknown-fields') expected.trust = true; + if (fault === 'analysis-type') expected.requireShippingAnalysis = 'true'; + const directory = path.join(f.directory, 'expected-packet'); + const preload = path.join(f.directory, 'written-packet-control.mts'); + writeFileSync( + preload, + `import {spyOn} from 'bun:test'; +import * as fs from 'node:fs'; +import path from 'node:path'; +const write=fs.writeFileSync, temporary=fs.mkdtempSync; +const fault=${JSON.stringify(fault)}; +const mutate=()=>write(${JSON.stringify(path.join(f.workspace, f.source))},'changed after physical capture'); +spyOn(fs,'mkdtempSync').mockImplementation((prefix,...args)=>{const result=temporary(prefix,...args);if(fault==='before-copy'&&String(prefix).includes('.native-evidence-'))mutate();return result;}); +spyOn(fs,'writeFileSync').mockImplementation((file,data,...args)=>{ + if(path.basename(String(file))==='evidence.json') { + if(fault==='serialized-summary'){const packet=JSON.parse(String(data));packet.cohorts[0].buildEvents=packet.cohorts[0].buildEvents.filter(event=>!event.testSummary);data=JSON.stringify(packet)+'\\n';} + write(file,data,...args); + if(fault==='after-serialize')mutate(); + return; + } + return write(file,data,...args); +}); +`, + ); + const args = [ + '--preload', + preload, + cli, + '--github-json', + file('github.json', f.options.github), + '--expected-qualification-json', + file('expected.json', expected), + '--producer-cohort', + file('roots.json', cohort.shippingRoots), + cohort.aqueryFile, + file('bep.jsonl', cohort.buildEvents, true), + f.executionRoot, + '--shipping-export', + cohort.shippingExport, + '--output-directory', + directory, + ]; + const run = () => + spawnSync(process.execPath, args, { + cwd: f.workspace, + env: { + ...process.env, + OLIPHAUNT_GIT_SOURCE_JSON: JSON.stringify({ + ...f.options.source, + ref: 'HEAD', + checkout: f.options.source.commit, + }), + }, + stdio: ['ignore', 'pipe', 'pipe'], + encoding: 'utf8', + }); + if (fault === 'none') { + const result = run(); + expect(result.status).toBe(0); + const output = result.stdout.trim(); + expect(result.stdout).toBe(`${output}\n`); + expect(result.stderr.trim().split('\n')).toEqual([ + 'native capture: deriving capture frontier', + 'native capture: collecting physical members', + 'native capture: pre-copy unchanged guard', + 'native capture: copying files/serializing', + 'native capture: serialized full validation', + 'native capture: post-copy unchanged guard', + 'native capture: completed', + ]); + const packet = JSON.parse(readFileSync(output, 'utf8')); + expect(validateNativeBuildEvidence(packet, expected).testQualification).toBe('passed'); + expect(readFileSync(path.join(directory, 'files/0', f.output))).toEqual( + readFileSync(path.join(f.executionRoot, f.output)), + ); + } else { + const result = run(); + expect(result.status, fault).not.toBe(0); + expect(result.stdout, fault).toBe(''); + expect(result.stderr, fault).not.toContain('native capture: completed'); + expect(existsSync(path.join(directory, 'native-build-evidence.json')), fault).toBe(false); + expect(existsSync(path.join(directory, 'files')), fault).toBe(false); + } + } finally { + f.cleanup(); + } + } +}); + +function seedCompanions(f: ReturnType) { + const stem = 'bazel-out/k8-opt/bin/seed'; + const frozen = `${stem}.tar`; + const receipt = `${stem}.seed-construction.json`; + const graph = f.cohort.aquery; + for (const [index, file] of [frozen, receipt].entries()) { + const parts = file.split('/'); + graph.pathFragments.push( + ...parts.map((label, part) => ({ + id: `seed-${index}-${part}`, + label, + ...(part ? { parentId: `seed-${index}-${part - 1}` } : {}), + })), + ); + graph.artifacts.push({ id: 11 + index, pathFragmentId: `seed-${index}-${parts.length - 1}` }); + graph.actions[0].outputIds.push(11 + index); + } + graph.actions[0].mnemonic = 'PostgresClusterSeed'; + writeFileSync(path.join(f.executionRoot, frozen), 'frozen PGDATA fixture'); + const pgdata = path.join(f.directory, 'pgdata'); + const contract = JSON.parse( + readFileSync( + new URL('../../src/database-resources/contracts/contract.json', import.meta.url), + 'utf8', + ), + ); + for (const name of contract.pgdataDirectories) + mkdirSync(path.join(pgdata, name), { recursive: true }); + writeFileSync(path.join(pgdata, 'PG_VERSION'), '18\n'); + writeSeedConstructionReceipt( + path.join(f.executionRoot, receipt), + captureSeedConstructionIntent( + { family: 'native', target: 'linux-x64-gnu', profile: 'standard' }, + { command: 'fixture-initdb' }, + { source: path.join(f.workspace, f.source) }, + ), + path.join(f.executionRoot, frozen), + pgdata, + ); + return { frozen, receipt }; +} + +test('cached absent intermediates preserve the full action graph and required supplier Files still fail closed', () => { + const f = fixture(); + try { + rmSync(path.join(f.executionRoot, f.generated), { recursive: true }); + const capture = f.capture(); + expect(capture.evidence.cohorts[0].aquery).toEqual(f.cohort.aquery); + expect(capture.qualification.cohorts[0].actionDefinitionsDigest).toMatch(/^sha256:/); + expect(capture.evidence.cohorts[0].inputs.map((input) => input.path)).not.toContain( + f.generated, + ); + (f.cohort.roots[0].package as any).supplierInputs = [ + { + product: 'supplier', + version: '1.0.0', + configuration: 'linux-x64', + binding: 'abi-contract', + origin: { kind: 'current-source' }, + files: [{ path: f.generated }], + }, + ]; + expect(f.capture).toThrow(/ENOENT/); + } finally { + f.cleanup(); + } +}); + +test('reached constructor sibling receipt and frozen TAR are captured, observed and both mandatory', () => { + const f = fixture(); + try { + const { receipt, frozen } = seedCompanions(f); + const captured = f.capture(); + const cohort = captured.evidence.cohorts[0]; + expect(cohort.seedConstructions!.map((row) => row.path)).toEqual([receipt]); + expect(cohort.inputs.map((row) => row.path)).toContain(frozen); + const output = cohort.outputs[0].members[0]; + if (output.type !== 'file') throw new Error('fixture output is a File'); + const artifact = { + id: 'github:native.tar.gz', + product: 'fixture', + name: 'native.tar.gz', + target: 'linux-x64-gnu', + role: 'github-release-asset', + kind: 'fixture', + path: f.output, + size: output.size, + sha256: output.sha256, + }; + const observation = projectNativePublicationConstruction( + { + envelope: { + catalogSchema: 'oliphaunt-publication-catalog-v1', + products: [{ id: 'fixture', version: '1.0.0' }], + carriers: [], + productArtifacts: [artifact], + }, + files: [{ path: f.output, size: output.size, sha256: output.sha256 }], + }, + [ + { + evidence: captured.evidence, + qualification: captured.qualification, + origin: { evidenceDigest: 'sha256:' + 'a'.repeat(64) }, + } as any, + ], + ); + expect(observation.products[0].construction[0].inputs.map((row) => row.path)).toContain(frozen); + expect(observation.products[0].construction[0].seedConstructions).toEqual( + cohort.seedConstructions, + ); + for (const file of [receipt, frozen]) { + const missing = structuredClone(captured.evidence); + missing.cohorts[0].inputs = missing.cohorts[0].inputs.filter((row) => row.path !== file); + expect(() => validateNativeBuildEvidence(missing, f.options)).toThrow( + 'native input content coverage', + ); + const actual = path.join(f.executionRoot, file); + const contents = readFileSync(actual); + rmSync(actual); + expect(f.capture).toThrow(/ENOENT/); + writeFileSync(actual, contents); + } + f.cohort.aquery.actions[0].outputIds = [3, 12]; + expect(f.capture).toThrow('same-action frozen TAR'); + } finally { + f.cleanup(); + } +}); + +test('mobile domain capture retains both original host and domain constructor pairs', () => { + const f = fixture(); + try { + const host = seedCompanions(f); + const frozen = 'bazel-out/k8-opt/bin/mobile-seed.tar'; + const receipt = 'bazel-out/k8-opt/bin/mobile-seed.seed-construction.json'; + const graph = f.cohort.aquery; + for (const [index, file] of [frozen, receipt].entries()) { + const parts = file.split('/'); + graph.pathFragments.push( + ...parts.map((label, part) => ({ + id: `domain-${index}-${part}`, + label, + ...(part ? { parentId: `domain-${index}-${part - 1}` } : {}), + })), + ); + graph.artifacts.push({ + id: 13 + index, + pathFragmentId: `domain-${index}-${parts.length - 1}`, + }); + } + graph.depSetOfFiles.push({ id: 3, directArtifactIds: [11, 12] }); + graph.actions.push({ + targetId: 1, + configurationId: 1, + actionKey: 'domain-construction', + mnemonic: 'NativeSeedDomainAdmission', + inputDepSetIds: [3], + outputIds: [13, 14], + primaryOutputId: 13, + }); + graph.depSetOfFiles[1].directArtifactIds.push(13); + writeFileSync(path.join(f.executionRoot, frozen), 'domain frozen PGDATA fixture'); + writeSeedConstructionReceipt( + path.join(f.executionRoot, receipt), + captureSeedConstructionIntent( + { family: 'native', target: 'android-datum64', profile: 'standard' }, + { command: 'fixture-domain' }, + { host: path.join(f.executionRoot, host.frozen) }, + ), + path.join(f.executionRoot, frozen), + path.join(f.directory, 'pgdata'), + ); + const captured = f.capture(); + expect(captured.evidence.cohorts[0].seedConstructions!.map((row) => row.path)).toEqual( + [receipt, host.receipt].sort(), + ); + for (const file of [host.frozen, host.receipt, frozen, receipt]) { + expect(captured.evidence.cohorts[0].inputs.map((row) => row.path)).toContain(file); + const bytes = readFileSync(path.join(f.executionRoot, file)); + rmSync(path.join(f.executionRoot, file)); + expect(f.capture).toThrow(/ENOENT/); + writeFileSync(path.join(f.executionRoot, file), bytes); + } + } finally { + f.cleanup(); + } +}); diff --git a/tools/release/cargo-payload-part-contract.mts b/tools/release/cargo-payload-part-contract.mts new file mode 100644 index 000000000..3d935751d --- /dev/null +++ b/tools/release/cargo-payload-part-contract.mts @@ -0,0 +1,72 @@ +/** Shared canonical dynamic Cargo payload-part set validation. */ +import { compareText } from './release-graph.mts'; + +function error(message) { + return new Error(`publication-lock: ${message}`); +} + +export function validateCargoPayloadPartSets(carriers) { + const byId = new Map(carriers.map((carrier) => [carrier.id, carrier])); + const partsByParent = new Map(); + for (const carrier of carriers) { + if (carrier.role !== 'payload-part') { + continue; + } + if ( + carrier.declared || + carrier.ecosystem !== 'cargo' || + typeof carrier.parentCarrier !== 'string' + ) { + throw error(`${carrier.id} has invalid dynamic Cargo payload-part metadata`); + } + const list = partsByParent.get(carrier.parentCarrier) ?? []; + list.push(carrier); + partsByParent.set(carrier.parentCarrier, list); + } + + const parents = new Set(partsByParent.keys()); + for (const carrier of carriers) { + if (carrier.ecosystem !== 'cargo' || carrier.role === 'payload-part') { + continue; + } + if ( + (carrier.packageDependencies ?? []).some( + (dependency) => + dependency.ecosystem === 'cargo' && dependency.name.startsWith(`${carrier.name}-part-`), + ) + ) { + parents.add(carrier.id); + } + } + + for (const parentId of [...parents].sort(compareText)) { + const parent = byId.get(parentId); + if (parent === undefined || parent.ecosystem !== 'cargo' || !parent.declared) { + throw error(`dynamic Cargo payload parts require their declared parent carrier ${parentId}`); + } + const parts = [...(partsByParent.get(parentId) ?? [])].sort( + (left, right) => left.part - right.part, + ); + if (parts.length === 0 || parts.length > 999) { + throw error(`${parentId} must have between 1 and 999 Cargo payload parts`); + } + const actualNumbers = parts.map((part) => part.part); + const expectedNumbers = Array.from({ length: parts.length }, (_, index) => index + 1); + if (JSON.stringify(actualNumbers) !== JSON.stringify(expectedNumbers)) { + throw error( + `${parentId} Cargo payload parts must be contiguous from part-001; found ${actualNumbers.map((part) => String(part).padStart(3, '0')).join(', ')}`, + ); + } + const actualIds = parts.map((part) => part.id).sort(compareText); + const dependencyIds = (parent.packageDependencies ?? []) + .filter( + (dependency) => + dependency.ecosystem === 'cargo' && dependency.name.startsWith(`${parent.name}-part-`), + ) + .map((dependency) => `cargo:${dependency.name}`) + .sort(compareText); + if (JSON.stringify(actualIds) !== JSON.stringify(dependencyIds)) { + throw error(`${parentId} must depend on exactly its complete Cargo payload part set`); + } + } +} diff --git a/tools/release/check-release-intent.test.sh b/tools/release/check-release-intent.test.sh index 8185944a7..c12bc53e7 100644 --- a/tools/release/check-release-intent.test.sh +++ b/tools/release/check-release-intent.test.sh @@ -13,7 +13,7 @@ tree="$(git rev-parse 'HEAD^{tree}')" first="$(printf 'fix: validate release intent\n' | git commit-tree "$tree" -p HEAD)" sibling="$(printf 'fix: sibling change\n' | git commit-tree "$tree" -p HEAD)" script=.github/scripts/check-release-intent.sh -bash "$script" 'fix: validate release intent' HEAD "$first" main workflow_dispatch refs/heads/main +bash "$script" 'fix: validate release intent' HEAD "$first" main workflow_dispatch refs/heads/main --source-policy-only reject() { local expected="$1" @@ -27,6 +27,8 @@ reject() { reject 'base must resolve to the exact commit parent' HEAD^ "$first" main workflow_dispatch refs/heads/main reject 'is not an ancestor' "$first" "$sibling" feature push refs/heads/feature reject 'requires matching main branch and full ref' HEAD "$first" main workflow_dispatch refs/heads/diagnostic +merge="$(printf 'fix: merged source\n' | git commit-tree "$tree" -p "$first" -p "$sibling")" +reject 'requires an exact one-parent commit' "$first" "$merge" main workflow_dispatch refs/heads/main --source-policy-only echo 'Release intent exact-parent and ancestry checks passed' # Exercise both generated-PR and main-merge admission without live registries. @@ -80,8 +82,28 @@ for branch in release-please--branches--main main; do (cd "$fixture"; CI_TEST_CONSUMER_STATUS=0 bash .github/scripts/check-release-intent.sh \ 'chore(release): fixture' "$base" HEAD "$branch") [[ -s "$CI_TEST_CONSUMER_CALL" && -e "$CI_TEST_PLAN_CALL" ]] + rm -f "$CI_TEST_PLAN_CALL" "$CI_TEST_CONSUMER_CALL" + (cd "$fixture"; MOON_BIN=/definitely-unavailable-moon CI_TEST_CONSUMER_STATUS=9 bash .github/scripts/check-release-intent.sh \ + 'chore(release): fixture' "$base" HEAD "$branch" pull_request "refs/heads/$branch" --source-policy-only) + [[ ! -e "$CI_TEST_CONSUMER_CALL" && ! -e "$CI_TEST_PLAN_CALL" ]] done -echo 'Release intent: consumer rejection blocks both generated PR and main release qualification' +echo 'Legacy release intent rejects incompatible consumers; native source policy leaves admission to authenticated Prepare' +status=0 +(cd "$fixture"; CI_TEST_CONSUMER_STATUS=0 bash .github/scripts/check-release-intent.sh \ + 'fix: manual version update' "$base" HEAD feature pull_request refs/heads/feature --source-policy-only \ + > "$scratch/manual-version.log" 2>&1) || status=$? +[[ "$status" == 1 ]] +rg -Fq 'Release Please manifest version bumps are release owned' "$scratch/manual-version.log" +normalized_head="$(git -C "$fixture" rev-parse HEAD)" +git -C "$fixture" commit --allow-empty -qm 'chore(release): extra commit' +status=0 +(cd "$fixture"; CI_TEST_CONSUMER_STATUS=0 bash .github/scripts/check-release-intent.sh \ + 'chore(release): fixture' "$base" HEAD release-please--branches--main pull_request refs/heads/release-please--branches--main --source-policy-only \ + > "$scratch/normalized-parent.log" 2>&1) || status=$? +[[ "$status" == 1 ]] +rg -Fq 'does not exactly match base' "$scratch/normalized-parent.log" +git -C "$fixture" reset --hard --quiet "$normalized_head" +echo 'Native source policy preserves manual-version and normalized single-parent guards' base="$(git -C "$fixture" rev-parse HEAD)" git -C "$fixture" commit --allow-empty -qm 'fix: publication controller' rm -f "$CI_TEST_PLAN_CALL" "$CI_TEST_CONSUMER_CALL" @@ -96,3 +118,14 @@ rm -f "$CI_TEST_CONSUMER_CALL" "$base" HEAD diagnostic workflow_dispatch refs/heads/diagnostic) [[ ! -e "$CI_TEST_CONSUMER_CALL" && -e "$CI_TEST_PLAN_CALL" ]] echo 'Release intent: selected main dispatch validates consumers; feature diagnostics retain source checks' +base="$(git -C "$fixture" rev-parse HEAD)" +mkdir -p "$fixture/sdk" +printf '// harmless source maintenance\n' > "$fixture/sdk/source.rs" +git -C "$fixture" add sdk +git -C "$fixture" commit -qm 'chore: source maintenance' +rm -f "$CI_TEST_PLAN_CALL" "$CI_TEST_CONSUMER_CALL" +(cd "$fixture"; MOON_BIN=/definitely-unavailable-moon CI_TEST_CONSUMER_STATUS=0 \ + bash .github/scripts/check-release-intent.sh 'chore: source maintenance' \ + "$base" HEAD feature pull_request refs/heads/feature --source-policy-only) +[[ ! -e "$CI_TEST_PLAN_CALL" && ! -e "$CI_TEST_CONSUMER_CALL" ]] +echo 'Native source policy accepts a clean feature without path selection or Moon lookup' diff --git a/tools/release/check-release-metadata.mts b/tools/release/check-release-metadata.mts index b7c3d4939..31a3bbee8 100755 --- a/tools/release/check-release-metadata.mts +++ b/tools/release/check-release-metadata.mts @@ -290,7 +290,7 @@ function validateReleasePleaseVersions(graph) { } } -function validateCompatibility(graph, { publication = false } = {}) { +function validateCompatibility(graph, { publication = false, buildBound } = {}) { validateConsumerContractCoverage(graph.products); const entries = compatibilityVersionEntries(graph.products, { requireSourceProduct: true, @@ -301,9 +301,14 @@ function validateCompatibility(graph, { publication = false } = {}) { 'compatibility field ids must be globally unique', ); const dependencyPlan = new Map( - (publication ? releaseDependencyPlan(graph.products, Object.keys(graph.products)) : []).map( - (entry) => [entry.id, entry.version], - ), + (publication + ? releaseDependencyPlan( + graph.products, + Object.keys(graph.products), + buildBound === undefined ? {} : { buildBound }, + ) + : [] + ).map((entry) => [entry.id, entry.version]), ); let pendingRelease; let checkedPendingRelease = false; @@ -347,7 +352,10 @@ function validateCompatibility(graph, { publication = false } = {}) { // Published compatibility pins already have immutable tag provenance. // Only an unpublished version needs its release commit validated. if (status.currentTagCommit === null) { - pendingRelease = latestVerifiedReleaseCommit({ repo: ROOT }); + pendingRelease = latestVerifiedReleaseCommit({ + repo: ROOT, + ...(buildBound === undefined ? {} : { buildBound }), + }); pendingVersions = new Map(Object.entries(pendingRelease?.versions ?? {})); checkedPendingRelease = true; } @@ -570,8 +578,7 @@ function parseArgs(argv) { return { json, publication }; } -function main(argv) { - const args = parseArgs(argv); +export function validateReleaseMetadata(args = {}) { const graph = { products: loadProducts(TOOL) }; validateReleasePleaseVersions(graph); const compatibilityFields = validateCompatibility(graph, args); @@ -589,6 +596,12 @@ function main(argv) { sourceNpmManifests: manifests.npm, sourceCargoManifests: manifests.cargo, }; + return report; +} + +function main(argv) { + const args = parseArgs(argv); + const report = validateReleaseMetadata(args); if (args.json) { console.log(`${JSON.stringify(report, null, 2)}\n`); } else { diff --git a/tools/release/check_artifact_targets.mts b/tools/release/check_artifact_targets.mts index 0852e0469..7b61f35dd 100644 --- a/tools/release/check_artifact_targets.mts +++ b/tools/release/check_artifact_targets.mts @@ -36,7 +36,6 @@ import { nativeToolsOptionalPackageProducts, rawArtifactTargetRows, registryPackageRows, - releaseMetadata, sdkPackageProducts, typescriptOptionalRuntimePackageProducts, } from './release-artifact-targets.mts'; diff --git a/tools/release/check_release_versions.mts b/tools/release/check_release_versions.mts index 5a41ffdfd..965f2b580 100644 --- a/tools/release/check_release_versions.mts +++ b/tools/release/check_release_versions.mts @@ -1,13 +1,18 @@ #!/usr/bin/env bun -import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import assert from 'node:assert/strict'; +import { mkdirSync, mkdtempSync, readFileSync, writeFileSync } from 'node:fs'; import path from 'node:path'; +import { requireSafeDirectoryChain } from '../packaging/release-directory-safety.mts'; import { checkRegistryPublication, queryProductPublication, } from './check_registry_publication.mts'; import { validateReleaseConsumerCompatibility } from './consumer-compatibility.mts'; import { parseTagCommits, parseTagRefs } from './git-tag-state.mts'; +import { acquireNativePublicationPreparation } from './native-freeze-publication-candidate.mts'; +import { assertAcquiredPreparedNativeReleaseInputs } from './native-release-inputs.mts'; import { currentVersion } from './product-version.mts'; +import { sourceIdentity } from './publication-lock.mts'; import { compareVersion, compatibilityVersionEntries, @@ -304,8 +309,12 @@ export function selectedDependencySatisfiesPin( return selected.has(dependency) && selectedVersion === pinnedVersion; } -async function validateReleaseDependencies(products, graph) { - validateReleaseConsumerCompatibility(products, { products: graph.products, prefix: TOOL }); +async function validateReleaseDependencies(products, graph, options = {}) { + validateReleaseConsumerCompatibility(products, { + ...options, + products: graph.products, + prefix: TOOL, + }); const selected = new Set(products); const entries = compatibilityVersionEntries(graph.products, { requireSourceProduct: true, @@ -327,11 +336,12 @@ async function validateReleaseDependencies(products, graph) { } } -function parseArgs(argv) { +export function parseReleaseVersionCheckArgs(argv) { const args = { productsJson: undefined, headRef: 'HEAD', checkRegistries: false, + nativePreparation: false, registryInventoryOutput: '', }; for (let index = 0; index < argv.length; index += 1) { @@ -354,6 +364,8 @@ function parseArgs(argv) { args.headRef = value.slice('--head-ref='.length); } else if (value === '--check-registries') { args.checkRegistries = true; + } else if (value === '--native-preparation') { + args.nativePreparation = true; } else if (value === '--registry-inventory-output') { if (index + 1 >= argv.length) { fail('--registry-inventory-output requires a value'); @@ -364,7 +376,7 @@ function parseArgs(argv) { args.registryInventoryOutput = value.slice('--registry-inventory-output='.length); } else if (value === '-h' || value === '--help') { console.log( - 'usage: tools/release/check_release_versions.mts [--products-json JSON] [--head-ref REF] [--check-registries] [--registry-inventory-output FILE]', + 'usage: tools/release/check_release_versions.mts [--products-json JSON] [--head-ref REF] [--native-preparation] [--check-registries] [--registry-inventory-output FILE]', ); process.exit(0); } else { @@ -374,8 +386,28 @@ function parseArgs(argv) { return args; } +/** Parsed facts cannot replace actual authenticated Prepare acquisition. */ +export function nativePreparedRegistryBuildBound( + prepared: unknown, + source: { commit: string; tree: string }, + selected: string[], +) { + const acquired = assertAcquiredPreparedNativeReleaseInputs(prepared); + assert.equal( + source.tree, + acquired.record.preparedSource.tree, + 'native registry source differs from Prepare', + ); + assert.deepEqual( + [...selected].sort(), + acquired.record.selectedProducts, + 'native registry scope differs from Prepare', + ); + return new Map([...acquired.buildBound].map(([id, suppliers]) => [id, new Set(suppliers)])); +} + async function main(argv) { - const args = parseArgs(argv); + const args = parseReleaseVersionCheckArgs(argv); if ( !/^[0-9a-f]{40}$/u.test(process.env.RELEASE_HEAD_COMMIT ?? '') || !process.env.RELEASE_TAG_REFS || @@ -390,6 +422,23 @@ async function main(argv) { }; const graph = { products: loadProducts() }; const selected = parseProducts(args.productsJson, graph); + let buildBound; + if (args.nativePreparation) { + assert.ok( + args.productsJson !== undefined && selected.length, + 'native registry checks require explicit selected products', + ); + const source = sourceIdentity(args.headRef); + assert.equal(source.commit, git.headCommit, 'native registry Git source context differs'); + const parent = requireSafeDirectoryChain(path.join(ROOT, 'target/native-registry-check'), { + create: true, + }); + const { prepared } = await acquireNativePublicationPreparation({ + source, + directory: path.join(mkdtempSync(path.join(parent, 'prepare-')), 'prepared'), + }); + buildBound = nativePreparedRegistryBuildBound(prepared, source, selected); + } if (args.registryInventoryOutput && !args.checkRegistries) { fail('--registry-inventory-output requires --check-registries'); } @@ -402,7 +451,11 @@ async function main(argv) { git, ); } - await validateReleaseDependencies(selected, graph); + await validateReleaseDependencies( + selected, + graph, + buildBound === undefined ? {} : { buildBound }, + ); if (args.checkRegistries) { const inventory = await validateRegistryPublication( selected, diff --git a/tools/release/checksum-manifest.mts b/tools/release/checksum-manifest.mts new file mode 100644 index 000000000..d9cf850aa --- /dev/null +++ b/tools/release/checksum-manifest.mts @@ -0,0 +1,39 @@ +/** The canonical publication checksum contract, shared by final-family qualification. */ +import { createHash } from 'node:crypto'; +import { readFileSync } from 'node:fs'; +import path from 'node:path'; + +export function validateChecksumManifest(file: string, payloadFiles: string[], context: string) { + const declared = new Map(); + for (const [index, rawLine] of readFileSync(file, 'utf8').split(/\r?\n/u).entries()) { + if (rawLine.length === 0) continue; + const match = rawLine.match(/^([0-9a-f]{64}) {2}\.\/([^/\0]+)$/u); + if (match === null) + throw new Error( + `publication-lock: ${context} checksum line ${index + 1} must be ' ./'`, + ); + const [, digest, name] = match; + if (declared.has(name)) + throw new Error( + `publication-lock: ${context} checksum manifest declares ${name} more than once`, + ); + declared.set(name, digest); + } + const expected = new Map( + payloadFiles.map((payload) => [ + path.basename(payload), + createHash('sha256').update(readFileSync(payload)).digest('hex'), + ]), + ); + const declaredNames = [...declared.keys()].sort(); + const expectedNames = [...expected.keys()].sort(); + if (JSON.stringify(declaredNames) !== JSON.stringify(expectedNames)) + throw new Error( + `publication-lock: ${context} checksum entries do not exactly cover public payloads: expected=${JSON.stringify(expectedNames)}, actual=${JSON.stringify(declaredNames)}`, + ); + for (const [name, digest] of expected) + if (declared.get(name) !== digest) + throw new Error( + `publication-lock: ${context} checksum for ${name} does not match its frozen bytes`, + ); +} diff --git a/tools/release/close-release-candidate.sh b/tools/release/close-release-candidate.sh index 5756a94a6..753ff3c27 100644 --- a/tools/release/close-release-candidate.sh +++ b/tools/release/close-release-candidate.sh @@ -1,22 +1,16 @@ #!/usr/bin/env bash set -euo pipefail -cd "$(git rev-parse --show-toplevel)" [[ $# == 1 ]] || { echo 'usage: close-release-candidate.sh OUTPUT_DIRECTORY' >&2 exit 2 } +[[ "${NATIVE_QUALIFICATION_RUN_ID:-}" =~ ^[1-9][0-9]*$ ]] || { + echo 'native close requires an exact positive qualification run ID' >&2 + exit 1 +} +cd "$(git rev-parse --show-toplevel)" [[ "$(cat "$1/required")" == true ]] || exit 0 -title="$(cat "$1/title")" -git config user.name "$(bun -p 'require("./tools/release/release-bot.json").name')" -git config user.email "$(bun -p 'require("./tools/release/release-bot.json").email')" -git add -A -git commit -m "$title" -bash tools/release/sync-release-pr.sh -if [[ -n "$(git status --porcelain --untracked-files=all)" ]]; then - git add -A - git commit --amend --no-edit -fi -products="$(bash tools/release/release-please-state.sh "$PWD" HEAD bash tools/release/with-release-history.sh "$PWD" HEAD tools/dev/bun.sh tools/release/verify-release-commit.mts --derive-products --head-ref HEAD)" -bash tools/release/release-please-state.sh "$PWD" HEAD bash tools/release/with-release-history.sh "$PWD" HEAD tools/dev/bun.sh tools/release/verify-release-commit.mts --products-json "$products" --head-ref HEAD -bash tools/release/with-product-history.sh "$PWD" HEAD '' @workspace bash tools/dev/bun.sh tools/release/consumer-compatibility.mts "$products" -bash tools/release/release-metadata-check.sh --publication +for check in check_release_please_config check_artifact_targets; do + bash tools/dev/bun.sh "tools/release/$check.mts" +done +bash tools/release/with-source.sh HEAD bash tools/release/release-please-state.sh "$PWD" HEAD bash tools/release/with-release-history.sh "$PWD" HEAD bash tools/release/with-product-history.sh "$PWD" HEAD '' @workspace bash tools/dev/bun.sh tools/release/native-close-release-candidate.mts "$1" diff --git a/tools/release/commit-paths.mts b/tools/release/commit-paths.mts new file mode 100644 index 000000000..598a41402 --- /dev/null +++ b/tools/release/commit-paths.mts @@ -0,0 +1,86 @@ +import { readFileSync } from 'node:fs'; +import path from 'node:path'; + +const fullSha = /^[0-9a-f]{40}$/; + +export interface CapturedCommitHistory { + head: string; + commits: ReadonlySet; + after(boundary?: string): ReadonlySet; +} + +/** Git ancestry, captured with changed paths; API ordering is not a release boundary. */ +export function readCommitHistory( + directory = process.env.OLIPHAUNT_COMMIT_PATHS, +): CapturedCommitHistory { + if (!directory) throw new Error('commit history requires a captured history directory'); + const content = readFileSync(path.join(directory, '.parents'), 'utf8'); + if (!content.endsWith('\n')) throw new Error('incomplete captured commit ancestry'); + const [header, ...lines] = content.slice(0, -1).split('\n'); + const head = header?.slice('head '.length); + if (!header?.startsWith('head ') || !head || !fullSha.test(head)) + throw new Error('commit ancestry requires an exact head SHA'); + const parents = new Map(); + for (const line of lines) { + const [sha, ...ancestors] = line.split(' '); + if (!sha || !fullSha.test(sha) || ancestors.some((parent) => !fullSha.test(parent))) + throw new Error('invalid captured commit ancestry'); + if (parents.has(sha)) throw new Error(`duplicate captured ancestry for ${sha}`); + parents.set(sha, ancestors); + } + const ancestorsOf = (boundary: string) => { + const result = new Set(); + const pending = [boundary]; + while (pending.length) { + const sha = pending.pop() as string; + if (result.has(sha)) continue; + const ancestors = parents.get(sha); + if (!ancestors) throw new Error(`captured ancestry is missing ${sha}`); + result.add(sha); + pending.push(...ancestors); + } + return result; + }; + if (ancestorsOf(head).size !== parents.size) + throw new Error('captured ancestry includes commits outside its head'); + const commits = new Set(parents.keys()); + const cache = new Map>(); + return { + head, + commits, + after(boundary) { + if (boundary === undefined) return commits; + if (!cache.has(boundary)) { + const delivered = ancestorsOf(boundary); + cache.set(boundary, new Set([...commits].filter((sha) => !delivered.has(sha)))); + } + return cache.get(boundary) as ReadonlySet; + }, + }; +} + +/** Read immutable changed paths captured once by snapshot-commit-paths.sh. */ +export function readCommitPaths( + sha: string, + directory = process.env.OLIPHAUNT_COMMIT_PATHS, +): string[] { + if (!fullSha.test(sha) || !directory) { + throw new Error('commit paths require an exact SHA and captured history directory'); + } + const content = readFileSync(path.join(directory, sha), 'utf8'); + if (!content) return []; + if (!content.endsWith('\0')) throw new Error(`incomplete captured commit paths for ${sha}`); + const files = content.slice(0, -1).split('\0'); + for (const file of files) { + if ( + !file || + file.startsWith('/') || + file.split('/').some((part) => part === '..' || part === '.') + ) { + throw new Error(`unsafe captured commit path for ${sha}`); + } + } + if (new Set(files).size !== files.length) + throw new Error(`duplicate captured commit paths for ${sha}`); + return files; +} diff --git a/tools/release/compatibility-version-parser.mts b/tools/release/compatibility-version-parser.mts new file mode 100644 index 000000000..87cdf66c6 --- /dev/null +++ b/tools/release/compatibility-version-parser.mts @@ -0,0 +1,109 @@ +type CompatibilityEntry = { id: string; path: string; parser: string }; +type ParserOptions = { + prefix?: string; + missingValue?: Missing; + fail?: (prefix: string, message: string) => never; +}; + +function parserFailure(prefix: string, message: string): never { + throw new Error(`${prefix}: ${message}`); +} + +function valueAtPath(value: unknown, parts: string[]): unknown { + let current = value; + for (const part of parts) { + if (current === null || typeof current !== 'object') return undefined; + current = (current as Record)[part]; + } + return current; +} + +/** Read conventional Cargo dependency identity without assigning release roles. */ +export function cargoCompatibilityDependency( + entry: CompatibilityEntry, + text: string, +): { packageName: string; path?: string } | undefined { + if (!entry.parser.startsWith('toml:') || !entry.parser.endsWith('.version')) return undefined; + const parts = entry.parser.slice(5).split('.'); + const tables = ['dependencies', 'dev-dependencies', 'build-dependencies']; + if ( + !(parts.length === 3 && tables.includes(parts[0])) && + !(parts.length === 4 && parts[0] === 'workspace' && parts[1] === 'dependencies') && + !(parts.length === 5 && parts[0] === 'target' && tables.includes(parts[2])) + ) + return undefined; + const declaration = valueAtPath(Bun.TOML.parse(text), parts.slice(0, -1)) as + | { package?: unknown; path?: unknown } + | undefined; + if (!declaration || typeof declaration !== 'object') return undefined; + return { + packageName: typeof declaration.package === 'string' ? declaration.package : parts.at(-2)!, + ...(typeof declaration.path === 'string' ? { path: declaration.path } : {}), + }; +} + +/** Local Cargo declarations are build requirements, not installed artifact requests. */ +export function isCargoPathCompatibility(entry: CompatibilityEntry, text: string): boolean { + return cargoCompatibilityDependency(entry, text)?.path !== undefined; +} + +/** Parse already-read source bytes without filesystem, history, or graph access. */ +export function compatibilityVersionFromText( + entry: CompatibilityEntry, + text: string, + { + prefix = 'release-graph', + missingValue = undefined, + fail = parserFailure, + }: ParserOptions = {}, +): string | Missing { + if (entry.parser === 'raw') return text.trim(); + if (entry.parser.startsWith('rust-const:')) { + const name = entry.parser.slice('rust-const:'.length); + if (!/^[A-Z][A-Z0-9_]*$/u.test(name)) { + fail(prefix, `${entry.id} has an invalid Rust constant parser`); + } + const matches = [ + ...text.matchAll( + new RegExp(`(?:pub\\s+)?const\\s+${name}\\s*:[^=]+?=\\s*"([^"]+)"\\s*;`, 'gu'), + ), + ]; + if (matches.length !== 1) { + if (matches.length === 0 && missingValue !== undefined) return missingValue; + fail(prefix, `${entry.id} must name exactly one Rust string constant`); + } + return matches[0][1]; + } + const separator = entry.parser.indexOf(':'); + const type = entry.parser.slice(0, separator); + if (type !== 'json' && type !== 'toml') { + fail(prefix, `${entry.id} uses unsupported compatibility parser ${entry.parser}`); + } + const parts = entry.parser.slice(separator + 1).split('.'); + let data: unknown; + try { + data = type === 'json' ? JSON.parse(text) : type === 'toml' ? Bun.TOML.parse(text) : null; + } catch (cause) { + fail(prefix, `${entry.path} is not valid ${type.toUpperCase()}: ${(cause as Error).message}`); + } + const value = valueAtPath(data, parts); + if (typeof value !== 'string' || value.length === 0) { + if (value === undefined && missingValue !== undefined) return missingValue; + fail(prefix, `${entry.id} parser ${entry.parser} must resolve to a non-empty string`); + } + // Cargo's exact requirement spells the same installed version with `=`. + // Keep every other requirement intact so the caller's stable-version check + // still rejects ranges; package rendering retains the authored Cargo text. + if ( + type === 'toml' && + parts.length === 3 && + ['dependencies', 'build-dependencies', 'dev-dependencies'].includes(parts[0]) && + parts[2] === 'version' + ) { + const exact = value.match( + /^=\s*([0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?)$/u, + ); + if (exact) return exact[1]; + } + return value; +} diff --git a/tools/release/compatibility-version-parser.test.mts b/tools/release/compatibility-version-parser.test.mts new file mode 100644 index 000000000..dc6a50791 --- /dev/null +++ b/tools/release/compatibility-version-parser.test.mts @@ -0,0 +1,155 @@ +import { expect, test } from 'bun:test'; +import { + compatibilityVersionFromText, + cargoCompatibilityDependency, + isCargoPathCompatibility, +} from './compatibility-version-parser.mts'; + +const entry = (parser: string) => ({ id: 'sdk.runtime', path: 'sdk/manifest', parser }); + +test('parses the existing raw, structured, and Rust compatibility source contracts', () => { + for (const [parser, source] of [ + ['raw', ' 0.3.2\n'], + ['json:oliphaunt.runtime', '{"oliphaunt":{"runtime":"0.3.2"}}'], + ['toml:runtime.version', '[runtime]\nversion = "0.3.2"\n'], + ['rust-const:RUNTIME_VERSION', 'pub const RUNTIME_VERSION: &str = "0.3.2";'], + ]) + expect(compatibilityVersionFromText(entry(parser), source)).toBe('0.3.2'); + // Stable-version admission belongs to the caller, including raw empty text. + expect(compatibilityVersionFromText(entry('raw'), '\n')).toBe(''); + expect(compatibilityVersionFromText(entry('json:version'), '{"version":"^1.0.0"}')).toBe( + '^1.0.0', + ); +}); + +test('missingValue applies only to absent structured paths and absent Rust constants', () => { + expect( + compatibilityVersionFromText(entry('json:runtime.version'), '{}', { missingValue: null }), + ).toBeNull(); + expect( + compatibilityVersionFromText(entry('toml:runtime.version'), 'runtime = false', { + missingValue: 'absent', + }), + ).toBe('absent'); + expect( + compatibilityVersionFromText(entry('rust-const:RUNTIME_VERSION'), '', { + missingValue: 'absent', + }), + ).toBe('absent'); + for (const source of ['{"version":""}', '{"version":null}', '{"version":123}']) + expect(() => + compatibilityVersionFromText(entry('json:version'), source, { missingValue: 'absent' }), + ).toThrow('must resolve to a non-empty string'); +}); + +test('exact Cargo dependency requirements expose their version without accepting ranges or changing metadata', () => { + for (const table of ['dependencies', 'build-dependencies', 'dev-dependencies']) { + const parser = entry(`toml:${table}.oliphaunt-query.version`); + for (const exact of ['=0.1.1', '= 0.1.1']) + expect( + compatibilityVersionFromText( + parser, + `[${table}]\noliphaunt-query = { version = "${exact}" }`, + ), + ).toBe('0.1.1'); + for (const range of ['^0.1.1', '>=0.1.1', '=0.1.1, <0.2', '0.1.*']) + expect( + compatibilityVersionFromText( + parser, + `[${table}]\noliphaunt-query = { version = "${range}" }`, + ), + ).toBe(range); + } + expect( + compatibilityVersionFromText( + entry('toml:package.metadata.runtime-version'), + '[package.metadata]\nruntime-version = "=0.1.1"', + ), + ).toBe('=0.1.1'); + expect( + compatibilityVersionFromText( + entry('json:dependencies.query.version'), + '{"dependencies":{"query":{"version":"=0.1.1"}}}', + ), + ).toBe('=0.1.1'); +}); + +test('invalid sources preserve diagnostics and the injectable failure boundary', () => { + for (const [parser, source, message] of [ + ['rust-const:invalid', '', 'has an invalid Rust constant parser'], + ['rust-const:RUNTIME_VERSION', '', 'must name exactly one Rust string constant'], + [ + 'rust-const:RUNTIME_VERSION', + 'const RUNTIME_VERSION: &str = "1"; const RUNTIME_VERSION: &str = "2";', + 'must name exactly one Rust string constant', + ], + ['json:version', '{', 'is not valid JSON'], + ['toml:version', 'version = [', 'is not valid TOML'], + ['yaml:version', 'version: "1"', 'uses unsupported compatibility parser'], + ]) + expect(() => + compatibilityVersionFromText(entry(parser), source, { prefix: 'native-import' }), + ).toThrow(message); + expect(() => compatibilityVersionFromText(entry('json:version'), '{}')).toThrow( + 'release-graph: sdk.runtime parser json:version must resolve to a non-empty string', + ); + const calls: string[][] = []; + const sentinel = new Error('original failure boundary'); + expect(() => + compatibilityVersionFromText(entry('json:version'), '{}', { + prefix: 'existing-cli', + fail(prefix, message) { + calls.push([prefix, message]); + throw sentinel; + }, + }), + ).toThrow(sentinel); + expect(calls).toEqual([ + ['existing-cli', 'sdk.runtime parser json:version must resolve to a non-empty string'], + ]); +}); + +test('local Cargo dependency declarations stay separate from installed metadata and registry requirements', () => { + for (const table of [ + 'dependencies', + 'workspace.dependencies', + 'target."cfg(unix)".build-dependencies', + ]) { + const parser = table.startsWith('target') + ? 'target.cfg(unix).build-dependencies.broker.version' + : table + '.broker.version'; + expect( + isCargoPathCompatibility( + entry('toml:' + parser), + '[' + table + ']\nbroker={path="../broker",version="0.4.0"}\n', + ), + ).toBe(true); + expect( + isCargoPathCompatibility( + entry('toml:' + parser), + '[' + table + ']\nbroker={version="0.3.1"}\n', + ), + ).toBe(false); + } + expect( + isCargoPathCompatibility( + entry('toml:package.metadata.broker.version'), + '[package.metadata.broker]\npath="resources/broker"\nversion="0.3.1"\n', + ), + ).toBe(false); +}); + +test('Cargo dependency identities preserve aliases for source and installed carrier classification', () => { + expect( + cargoCompatibilityDependency( + entry('toml:dependencies.alias.version'), + '[dependencies]\nalias={package="oliphaunt-broker",version="0.3.1"}\n', + ), + ).toEqual({ packageName: 'oliphaunt-broker' }); + expect( + cargoCompatibilityDependency( + entry('toml:dependencies.alias.version'), + '[dependencies]\nalias={package="oliphaunt-broker",path="../broker",version="0.4.0"}\n', + ), + ).toEqual({ packageName: 'oliphaunt-broker', path: '../broker' }); +}); diff --git a/tools/release/completed-contrib-carrier-context.mts b/tools/release/completed-contrib-carrier-context.mts new file mode 100644 index 000000000..aca3119d6 --- /dev/null +++ b/tools/release/completed-contrib-carrier-context.mts @@ -0,0 +1,225 @@ +/** Historical declared carriers, never historical Bazel inputs or build provenance. */ +import { deepStrictEqual } from 'node:assert'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + CONTRIB_CARRIERS_PATH, + loadContribCarriers, +} from '../../src/extensions/artifacts/packages/tools/contrib-carriers.mts'; +import { + nativeExtensionModuleHostTarget, + validateExtensionTargetProfiles, +} from '../../src/extensions/contracts/extension-target-profiles.mts'; +import { + AOT_TARGET_TRIPLES, + expectedExtensionAotTargets, +} from '../../src/wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; +import { + type CompletedPublication, + createCompletedPublicationChecker, +} from './completed-release-publication.mts'; +import { requestGithubRepositoryJson } from './github-read.mts'; +import { safeRelative } from './native-file-identity.mts'; +import { PLATFORM_COMPATIBILITY_POLICY } from './platform-compatibility-policy.mts'; +import { + extensionRegistryPackageTargetSetsFromRows, + registryPackageRows, + runtimeExtensionTargetRowsFromConfigs, + validateExtensionCatalogRows, +} from './release-artifact-targets.mts'; + +const prefix = 'completed contrib carrier context'; +const profilesPath = 'src/extensions/contracts/extension-target-profiles.toml'; +const catalogPath = 'src/extensions/generated/extensions.catalog.json'; +const utf8 = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }); +const object = (value, label: string) => { + if (!value || typeof value !== 'object' || Array.isArray(value)) + throw new Error(`${prefix}: ${label} must be an object`); + return value; +}; +const string = (value, label: string): string => { + if (typeof value !== 'string' || !value) + throw new Error(`${prefix}: ${label} must be a nonempty string`); + return value; +}; + +/** + * Read only the canonical metadata at a completed publication's exact commit. + * Source paths and declarations come from that commit, including renamed owner + * directories. Transport overrides are controlled fixtures, not authentication. + */ +export async function readCompletedContribCarrierRows( + publication: CompletedPublication, + { + repository = 'f0rr0/oliphaunt', + assertCompleted = createCompletedPublicationChecker({ repository }), + readJson = requestGithubRepositoryJson, + } = {}, +) { + publication = structuredClone(publication); + if (repository !== 'f0rr0/oliphaunt') throw new Error(`${prefix}: unsupported repository`); + deepStrictEqual(await assertCompleted(publication), publication, 'completed contrib source'); + const sources = new Map(); + const read = async (file: string) => { + safeRelative(file); + if (!sources.has(file)) { + const value = await readJson( + `repos/${repository}/contents/${file}?ref=${publication.publicationSha}`, + ); + if ( + value.type !== 'file' || + value.path !== file || + value.encoding !== 'base64' || + typeof value.content !== 'string' || + !/^[0-9a-f]{40}$/u.test(value.sha) + ) + throw new Error(`${prefix}: missing exact historical file ${file}`); + const bytes = Buffer.from(value.content, 'base64'); + if ( + createHash('sha1').update(`blob ${bytes.length}\0`).update(bytes).digest('hex') !== + value.sha + ) + throw new Error(`${prefix}: historical Git blob differs for ${file}`); + sources.set(file, { text: utf8.decode(bytes), sha: value.sha }); + } + const source = sources.get(file); + if (!source) throw new Error(`${prefix}: historical file was not captured ${file}`); + return source.text; + }; + const toml = async (file: string) => object(Bun.TOML.parse(await read(file)), file); + const config = object(JSON.parse(await read('release-please-config.json')), 'release config'); + const versions = object( + JSON.parse(await read('.release-please-manifest.json')), + 'release versions', + ); + const owners = new Map(); + for (const [ownerPath, value] of Object.entries(object(config.packages, 'release packages'))) { + safeRelative(ownerPath); + const owner = string(object(value, ownerPath).component, `${ownerPath}.component`); + if (owners.has(owner)) throw new Error(`${prefix}: duplicate historical owner ${owner}`); + owners.set(owner, ownerPath); + } + const carrierDescriptor = await toml(CONTRIB_CARRIERS_PATH); + for (const field of ['logical_product', 'native_owner', 'wasix_owner']) + string(carrierDescriptor[field], field); + if (carrierDescriptor.native_owner === carrierDescriptor.wasix_owner) + throw new Error(`${prefix}: native and WASIX ownership must be distinct`); + if ( + ![carrierDescriptor.native_owner, carrierDescriptor.wasix_owner].includes(publication.product) + ) + throw new Error(`${prefix}: publication is not a historical contrib owner`); + const products = {}; + for (const owner of [carrierDescriptor.native_owner, carrierDescriptor.wasix_owner]) { + const ownerPath = owners.get(owner); + if (!ownerPath) throw new Error(`${prefix}: historical contrib owner ${owner} is unconfigured`); + const descriptor = await toml(`${ownerPath}/release.toml`); + const version = string(versions[ownerPath], `${ownerPath} version`); + if (descriptor.id !== owner) throw new Error(`${prefix}: historical descriptor owner differs`); + products[owner] = { ...descriptor, path: ownerPath, version }; + } + if (products[publication.product].version !== publication.version) + throw new Error(`${prefix}: completed product version differs from historical source`); + for (const field of ['member_manifest', 'source', 'contract']) + await read(safeRelative(string(carrierDescriptor[field], field))); + const profiles = validateExtensionTargetProfiles(await toml(profilesPath)).targets; + const catalog = validateExtensionCatalogRows(JSON.parse(await read(catalogPath)), prefix); + for (const row of profiles) { + if ( + (row.family === 'native' && + row.kind === + (nativeExtensionModuleHostTarget(row.target) === row.target + ? 'native-dynamic' + : 'native-static-registry') && + Object.hasOwn(PLATFORM_COMPATIBILITY_POLICY, row.target)) || + (row.family === 'wasix' && + row.kind === 'wasix-runtime' && + (row.target === 'wasix-portable' || Object.hasOwn(AOT_TARGET_TRIPLES, row.target))) + ) + continue; + throw new Error( + `${prefix}: unsupported historical profile ${row.target}/${row.family}/${row.kind}`, + ); + } + + // The old profile declaration is itself the carrier authority. Before the + // release.toml migration, no runtime artifact_targets table existed here. + // Validate a table when actually present; never substitute current defaults. + const hasTargets = Object.values(products).map( + (product: any) => product.artifact_targets !== undefined, + ); + if (hasTargets.some(Boolean) && !hasTargets.every(Boolean)) + throw new Error( + `${prefix}: mixed historical runtime artifact target declarations are unsupported`, + ); + if (hasTargets.every(Boolean)) { + const allowed = new Set( + runtimeExtensionTargetRowsFromConfigs(products, prefix, { + nativeOwner: carrierDescriptor.native_owner, + wasixOwner: carrierDescriptor.wasix_owner, + }).map((row) => `${row.target}\0${row.family}\0${row.kind}`), + ); + for (const row of profiles) + if (!allowed.has(`${row.target}\0${row.family}\0${row.kind}`)) + throw new Error(`${prefix}: profile is not backed by historical runtime targets`); + } + const directory = mkdtempSync(path.join(tmpdir(), 'oliphaunt-completed-contrib-')); + try { + // Reuse the exact existing descriptor/member loader on a disposable source + // snapshot. This is not a persisted manifest, receipt or historical graph. + for (const [file, { text }] of sources) { + const destination = path.join(directory, file); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, text, { flag: 'wx' }); + } + const contrib = loadContribCarriers(directory, prefix, { + readText: (file) => { + const source = sources.get(file); + if (!source) throw new Error(`${prefix}: uncaptured historical contrib input ${file}`); + return source.text; + }, + }); + const names = contrib.members.map((member) => string(member['sql-name'], 'contrib SQL name')); + if (!names.length || new Set(names).size !== names.length) + throw new Error(`${prefix}: historical contrib SQL names must be nonempty and unique`); + for (const name of names) + if (!catalog.has(name)) throw new Error(`${prefix}: historical catalog omits ${name}`); + const contribRegistryTargets = extensionRegistryPackageTargetSetsFromRows( + contrib.artifactProduct, + names, + names.flatMap((sqlName) => profiles.map((row) => ({ ...row, sqlName }))), + names.filter((name) => typeof catalog.get(name)['native-module-file'] === 'string'), + prefix, + ); + if (publication.product === contrib.wasixOwner) { + if (!contribRegistryTargets.includeWasixNpm) + throw new Error(`${prefix}: historical WASIX portable carrier profile is missing`); + if (contribRegistryTargets.includeWasixAot) { + const aotPrefix = `crates:${contrib.wasixOwner}-aot-`; + const entries = products[contrib.wasixOwner].registry_packages; + if (!Array.isArray(entries) || entries.some((entry) => typeof entry !== 'string')) + throw new Error(`${prefix}: historical WASIX registry packages must be a string list`); + const aotTargets = entries + .filter((entry) => entry.startsWith(aotPrefix)) + .map((entry) => entry.slice(aotPrefix.length)) + .sort(); + deepStrictEqual( + aotTargets, + expectedExtensionAotTargets(), + 'historical WASIX AOT carrier mapping', + ); + } + } + const inputContext = { products, contrib, contribRegistryTargets }; + return { + publication, + descriptor: products[publication.product], + inputContext, + registryRows: registryPackageRows({ product: publication.product, inputContext }, prefix), + sourceFiles: [...sources].map(([file, { sha }]) => ({ path: file, sha })), + }; + } finally { + rmSync(directory, { recursive: true, force: true }); + } +} diff --git a/tools/release/completed-contrib-carrier-context.test.mts b/tools/release/completed-contrib-carrier-context.test.mts new file mode 100644 index 000000000..01279e808 --- /dev/null +++ b/tools/release/completed-contrib-carrier-context.test.mts @@ -0,0 +1,296 @@ +import { expect, test } from 'bun:test'; +import { execFileSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { readFileSync } from 'node:fs'; +import { readCompletedContribCarrierRows } from './completed-contrib-carrier-context.mts'; +import { createCompletedPublicationChecker } from './completed-release-publication.mts'; +import { registryPackageRows } from './release-artifact-targets.mts'; + +const repository = 'f0rr0/oliphaunt'; +const captured = JSON.parse( + readFileSync( + new URL('../../build_defs/release/native-0.3.3-completed-publication.json', import.meta.url), + 'utf8', + ), +); +const files = new Map(); +function fixture() { + const changed = new Map(); + const requests: string[] = []; + const raw = (file: string) => { + const replacement = changed.get(file); + if (replacement) return replacement; + if (!files.has(file)) + files.set(file, execFileSync('git', ['show', `${captured.publicationSha}:${file}`])); + const bytes = files.get(file); + if (!bytes) throw new Error(`fixture lacks historical file ${file}`); + return bytes; + }; + const replace = (file: string, text: string) => changed.set(file, Buffer.from(text)); + const readJson = async (endpoint: string) => { + requests.push(endpoint); + const match = endpoint.match(/^repos\/f0rr0\/oliphaunt\/contents\/(.+)\?ref=([a-f0-9]{40})$/u); + if (!match || match[2] !== captured.publicationSha) + throw new Error(`fixture received a foreign source endpoint: ${endpoint}`); + const file = match[1]; + const bytes = raw(file); + return { + type: 'file', + path: file, + encoding: 'base64', + content: bytes.toString('base64'), + sha: createHash('sha1').update(`blob ${bytes.length}\0`).update(bytes).digest('hex'), + }; + }; + // This controlled transport substitutes completion; it does not claim that + // hypothetical source mutations below were actually published or qualified. + const options = { repository, readJson, assertCompleted: async (publication) => publication }; + return { raw, replace, readJson, requests, options }; +} + +function ownerPath(f: ReturnType, owner: string) { + const config = JSON.parse(f.raw('release-please-config.json').toString('utf8')); + const entry = Object.entries(config.packages).find(([, row]: any) => row.component === owner); + if (!entry) throw new Error(`fixture lacks historical owner ${owner}`); + return entry[0]; +} + +function wasixPublication(f: ReturnType) { + const owner = ownerPath(f, 'liboliphaunt-wasix'); + const version = JSON.parse(f.raw('.release-please-manifest.json').toString('utf8'))[owner]; + return { + ...captured, + product: 'liboliphaunt-wasix', + version, + tagName: `liboliphaunt-wasix-v${version}`, + }; +} + +test('genuine completed native source expands its contrib carriers without old BUILD or Moon data', async () => { + const f = fixture(); + const result = await readCompletedContribCarrierRows(captured, f.options); + expect(result.publication).toEqual(captured); + expect(result.descriptor.version).toBe('0.3.3'); + expect(result.descriptor.artifact_targets).toBeUndefined(); + expect(result.registryRows).toEqual(registryPackageRows({ product: 'liboliphaunt-native' })); + const names = result.registryRows.map(({ raw }) => raw); + expect(names).toContain('crates:oliphaunt-extension-contrib-pg18'); + expect(names).toContain('crates:oliphaunt-extension-contrib-pg18-windows-x64-msvc'); + expect(names).toContain('npm:@oliphaunt/extension-contrib-pg18-macos-arm64'); + expect(names).toContain( + 'maven:dev.oliphaunt.extensions:oliphaunt-extension-contrib-pg18-android-arm64-v8a', + ); + expect(result.sourceFiles).toHaveLength(10); + expect(f.requests.every((endpoint) => endpoint.endsWith(`?ref=${captured.publicationSha}`))).toBe( + true, + ); + expect(result.sourceFiles.some(({ path }) => /BUILD|moon/.test(path))).toBe(false); +}); + +test('historical profiles rather than current workspace targets determine expansion', async () => { + const f = fixture(); + const file = 'src/extensions/contracts/extension-target-profiles.toml'; + const profiles = Bun.TOML.parse(f.raw(file).toString('utf8')) as any; + // A hypothetical older declaration promises one desktop carrier only. + f.replace( + file, + `schema = "${profiles.schema}"\n[[profiles]]\nid="old-desktop"\n[[profiles.targets]]\ntarget="linux-x64-gnu"\nfamily="native"\nkind="native-dynamic"\n`, + ); + const result = await readCompletedContribCarrierRows(captured, f.options); + const names = result.registryRows.map(({ raw }) => raw); + expect(names).toContain('crates:oliphaunt-extension-contrib-pg18-linux-x64-gnu'); + expect(names).not.toContain('crates:oliphaunt-extension-contrib-pg18-macos-arm64'); + expect(names).not.toContain( + 'maven:dev.oliphaunt.extensions:oliphaunt-extension-contrib-pg18-android-x86_64', + ); + // Independent directly authored runtime obligations remain present. + expect(names).toContain('crates:liboliphaunt-native-macos-arm64'); +}); + +test('source-declared module membership controls held WASIX AOT carriers', async () => { + const f = fixture(); + const publication = wasixPublication(f); + const before = await readCompletedContribCarrierRows(publication, f.options); + expect( + before.registryRows.some(({ raw }) => raw.includes('contrib-pg18-') && raw.includes('-aot-')), + ).toBe(true); + const file = 'src/extensions/generated/extensions.catalog.json'; + const catalog = JSON.parse(f.raw(file).toString('utf8')); + for (const row of catalog.extensions) delete row['native-module-file']; + f.replace(file, JSON.stringify(catalog)); + const after = await readCompletedContribCarrierRows(publication, f.options); + expect( + after.registryRows.some(({ raw }) => raw.includes('contrib-pg18-') && raw.includes('-aot-')), + ).toBe(false); + expect(after.registryRows.map(({ raw }) => raw)).toContain( + 'crates:oliphaunt-extension-contrib-pg18-wasix', + ); + expect(after.registryRows.map(({ raw }) => raw)).toContain( + 'npm:@oliphaunt/extension-contrib-pg18-wasix', + ); +}); + +test('partial target-table migration cannot silently bypass an authored runtime declaration', async () => { + for (const [owner, target] of [ + ['liboliphaunt-native', 'linux-x64-gnu'], + ['liboliphaunt-wasix', 'portable'], + ]) { + const f = fixture(); + const file = `${ownerPath(f, owner)}/release.toml`; + f.replace( + file, + `${f.raw(file).toString('utf8')}\n[artifact_targets]\npreset="${owner}"\ntargets=["${target}"]\n`, + ); + await expect(readCompletedContribCarrierRows(captured, f.options)).rejects.toThrow( + 'mixed historical runtime artifact target declarations', + ); + } +}); + +test('unsupported historical family, kind and target combinations are not silently omitted', async () => { + for (const [target, family, kind] of [ + ['linux-x64-gnu', 'foreign', 'native-dynamic'], + ['linux-x64-gnu', 'native', 'wasix-runtime'], + ['linux-x64-gnu', 'wasix', 'native-dynamic'], + ['unknown-host', 'native', 'native-dynamic'], + ['ios-xcframework', 'native', 'native-dynamic'], + ['linux-x64-gnu', 'native', 'native-static-registry'], + ['constructor', 'wasix', 'wasix-runtime'], + ['constructor', 'native', 'native-dynamic'], + ]) { + const f = fixture(); + f.replace( + 'src/extensions/contracts/extension-target-profiles.toml', + `schema="oliphaunt-extension-artifact-target-profiles-v1"\n[[profiles]]\nid="old-profile"\n[[profiles.targets]]\ntarget="${target}"\nfamily="${family}"\nkind="${kind}"\n`, + ); + await expect(readCompletedContribCarrierRows(captured, f.options)).rejects.toThrow( + 'unsupported historical profile', + ); + } +}); + +test('held WASIX expansion requires the historical portable and supported AOT declarations', async () => { + const missingPortable = fixture(); + const file = 'src/extensions/contracts/extension-target-profiles.toml'; + missingPortable.replace( + file, + `schema="oliphaunt-extension-artifact-target-profiles-v1"\n[[profiles]]\nid="native-only"\n[[profiles.targets]]\ntarget="linux-x64-gnu"\nfamily="native"\nkind="native-dynamic"\n`, + ); + await expect( + readCompletedContribCarrierRows(wasixPublication(missingPortable), missingPortable.options), + ).rejects.toThrow('historical WASIX portable carrier profile is missing'); + + const missingAot = fixture(); + const descriptor = `${ownerPath(missingAot, 'liboliphaunt-wasix')}/release.toml`; + missingAot.replace( + descriptor, + missingAot + .raw(descriptor) + .toString('utf8') + .replace(/\s*"crates:liboliphaunt-wasix-aot-aarch64-apple-darwin",/u, ''), + ); + await expect( + readCompletedContribCarrierRows(wasixPublication(missingAot), missingAot.options), + ).rejects.toThrow('historical WASIX AOT carrier mapping'); +}); + +test('owner path is resolved from the completed release config, not current directories', async () => { + const f = fixture(); + const file = 'release-please-config.json'; + const config = JSON.parse(f.raw(file).toString('utf8')); + const previous = ownerPath(f, captured.product); + const renamed = 'historical/native-owner'; + config.packages[renamed] = config.packages[previous]; + delete config.packages[previous]; + f.replace(file, JSON.stringify(config)); + f.replace(`${renamed}/release.toml`, f.raw(`${previous}/release.toml`).toString('utf8')); + const versions = JSON.parse(f.raw('.release-please-manifest.json').toString('utf8')); + versions[renamed] = versions[previous]; + delete versions[previous]; + f.replace('.release-please-manifest.json', JSON.stringify(versions)); + const result = await readCompletedContribCarrierRows(captured, f.options); + expect(result.descriptor.path).toBe(renamed); + expect( + f.requests.some((endpoint) => endpoint.includes(`/contents/${previous}/release.toml?`)), + ).toBe(false); +}); + +test('missing, substituted and malformed historical source inputs never fall back to current files', async () => { + for (const mutation of [ + (row) => ({ ...row, path: 'foreign/catalog.json' }), + (row) => ({ ...row, sha: 'f'.repeat(40) }), + (row) => ({ ...row, type: 'symlink' }), + ]) { + const f = fixture(); + await expect( + readCompletedContribCarrierRows(captured, { + ...f.options, + readJson: async (endpoint) => mutation(await f.readJson(endpoint)), + }), + ).rejects.toThrow(); + } + for (const [file, text] of [ + [ + 'src/extensions/contrib/carriers.toml', + (f) => + f + .raw('src/extensions/contrib/carriers.toml') + .toString('utf8') + .replace('src/extensions/contrib/postgres18.toml', '../outside.toml'), + ], + [ + 'src/extensions/generated/extensions.catalog.json', + () => '{"format-version":1,"extensions":[]}', + ], + ['src/extensions/contrib/postgres18.toml', () => 'extensions=[]'], + [ + 'src/extensions/contracts/extension-target-profiles.toml', + () => 'schema="foreign"\nprofiles=[]', + ], + ] as const) { + const f = fixture(); + f.replace(file, text(f)); + await expect(readCompletedContribCarrierRows(captured, f.options)).rejects.toThrow(); + } + const malformed = fixture(); + await expect( + readCompletedContribCarrierRows(captured, { + ...malformed.options, + readJson: async () => { + throw new Error('historical catalog absent'); + }, + }), + ).rejects.toThrow('historical catalog absent'); +}); + +test('completed origin, owner version and canonical source ownership are mandatory', async () => { + const f = fixture(); + await expect( + readCompletedContribCarrierRows(captured, { + ...f.options, + assertCompleted: async (value) => ({ ...value, publicationSha: 'f'.repeat(40) }), + }), + ).rejects.toThrow('completed contrib source'); + expect(f.requests).toHaveLength(0); + await expect( + readCompletedContribCarrierRows(captured, { ...f.options, repository: 'foreign/repo' }), + ).rejects.toThrow('unsupported repository'); + await expect( + readCompletedContribCarrierRows({ ...captured, version: '9.9.9' }, f.options), + ).rejects.toThrow('product version'); + await expect( + readCompletedContribCarrierRows({ ...captured, product: 'oliphaunt-query' }, f.options), + ).rejects.toThrow('not a historical contrib owner'); + const checker = createCompletedPublicationChecker({ + repository, + readJson: async () => ({ + tag_name: captured.tagName, + target_commitish: captured.publicationSha, + draft: true, + prerelease: false, + }), + }); + await expect( + readCompletedContribCarrierRows(captured, { ...f.options, assertCompleted: checker }), + ).rejects.toThrow('public release'); +}); diff --git a/tools/release/completed-native-product-baseline.mts b/tools/release/completed-native-product-baseline.mts new file mode 100644 index 000000000..896ebeb66 --- /dev/null +++ b/tools/release/completed-native-product-baseline.mts @@ -0,0 +1,230 @@ +/** Post-publication observations, not release selection or native admission. */ +import { execFileSync } from 'node:child_process'; +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import { parseArgs } from 'node:util'; +import { requireSafeDirectoryChain } from '../packaging/release-directory-safety.mts'; +import { authenticateNativeBuildEvidence } from './authenticate-native-build-evidence.mts'; +import { + type CompletedPublication, + createCompletedPublicationChecker, +} from './completed-release-publication.mts'; +import { + assertNativePublicationBuildPlan, + type NativePublicationBuild, + type NativePublicationFile, + observeNativePublicationConstruction, +} from './native-publication-observation.mts'; +import { consumerDigest } from './publication-consumer-proof.mts'; +import { + assertPublicationLockSource, + loadPublicationLock, + lockedPublicationFiles, + PUBLICATION_LOCK_SCHEMA, + sourceIdentity, +} from './publication-lock.mts'; +import { + validateLockedRegistryReceipts, + verifyLockedRegistryIntegrity, +} from './registry-integrity.mts'; +import { + normalizeGithubReleaseSnapshot, + queryLockedGithubReleases, + writeImmutableReceipt, +} from './verify_github_release_attestations.mts'; + +export const COMPLETED_NATIVE_BASELINES_SCHEMA = 'oliphaunt-completed-native-product-baselines-v1'; +type Row = Record; +type Build = NativePublicationBuild; +type FrozenFile = NativePublicationFile; + +function equal(actual: unknown, expected: unknown, context: string) { + if (consumerDigest(actual) !== consumerDigest(expected)) throw new Error(`${context} mismatch`); +} + +/** + * The lock and concrete file list must already have been validated together at + * the exact publication checkout/capsule. Do not rehydrate an old catalog from + * today's checkout. The CLI performs that validation at the publication source. + * Callbacks replace authenticated transports only in controlled fixture callers. + */ +export async function captureCompletedNativeProductBaselines( + { + publicationLock, + publicationFiles, + repository, + bazelVersion, + builds, + }: { + publicationLock: Row; + publicationFiles: FrozenFile[]; + repository: string; + bazelVersion: string; + builds: Build[]; + }, + { + authenticate = authenticateNativeBuildEvidence, + assertCompleted = createCompletedPublicationChecker({ repository }), + verifyRegistry = verifyLockedRegistryIntegrity, + readGithubReleases = (lock: Row) => queryLockedGithubReleases(lock, { repo: repository }), + } = {}, +) { + // Snapshot caller inputs before any remote reads; their digests remain those + // of the approved frozen lock, including independent held requirements. + const lock = structuredClone(publicationLock); + const files = structuredClone(publicationFiles); + const requestedBuilds = structuredClone(builds); + if ( + lock.schema !== PUBLICATION_LOCK_SCHEMA || + lock.scope !== undefined || + Object.hasOwn(lock, 'nativePayloads') + ) + throw new Error('completed native observations require a frozen publication lock'); + const { lockDigest, ...locked } = lock; + equal(lockDigest, consumerDigest(locked), 'frozen publication lock digest'); + assertNativePublicationBuildPlan(requestedBuilds); + const publications: CompletedPublication[] = []; + for (const product of lock.products) { + const publication = await assertCompleted({ + product: product.id, + version: product.version, + tagName: `${product.id}-v${product.version}`, + publicationSha: lock.source.commit, + }); + equal( + { + product: publication.product, + version: publication.version, + tagName: publication.tagName, + source: { commit: publication.publicationSha, tree: publication.publicationTree }, + }, + { + product: product.id, + version: product.version, + tagName: `${product.id}-v${product.version}`, + source: lock.source, + }, + 'canonical completed publication', + ); + publications.push(publication); + } + const observation = await observeNativePublicationConstruction( + { + envelope: lock, + files, + repository, + bazelVersion, + builds: requestedBuilds, + }, + { authenticate }, + ); + const { authenticated, coverage } = observation; + const products = observation.products.map((product) => ({ + ...product, + publication: publications.find((publication) => publication.product === product.product.id), + })); + // Reuse the publication controller's byte-level registry and GitHub checks. + // A tagged PR alone cannot authenticate an arbitrary caller-supplied lock. + const receipts = await verifyRegistry(lock); + validateLockedRegistryReceipts(lock, { receipts, receiptMode: 'sealed' }); + const releases = normalizeGithubReleaseSnapshot(lock, await readGithubReleases(lock)); + if (releases.some((release) => release.draft || release.prerelease)) + throw new Error('completed native observations require stable public releases'); + const record = { + schema: COMPLETED_NATIVE_BASELINES_SCHEMA, + scope: 'construction' as const, + repository, + source: lock.source, + frozen: { + lockDigest: lock.lockDigest, + catalogDigest: lock.catalogDigest, + packageEnvelopeDigest: lock.packageEnvelopeDigest, + }, + builds: authenticated.map(({ origin, qualification }) => ({ + github: origin.github, + artifact: origin.artifact, + evidenceDigest: origin.evidenceDigest, + shippingAnalysis: qualification.shippingAnalysis, + unverified: qualification.unverified, + testQualification: qualification.testQualification, + requiredTests: qualification.requiredTests, + })), + products, + publication: { registryReceipts: receipts, githubReleases: releases }, + coverage: { + completeFrozenInventory: coverage.completeProductInventory, + completeMigrationInventory: 'unverified', + }, + releaseDecision: 'unverified' as const, + unverified: [ + 'immutable input lifetime from the producing build through content capture', + 'qualified mapping from pre-envelope members to every delivered product contract', + 'complete migration inventory and product-specific mandatory qualification policy', + 'necessary delivery comparison against a prior admitted native baseline', + ], + }; + return { ...record, observationDigest: consumerDigest(record) }; +} + +/** Publishing the observation file is allowed only after capture has checked completion. */ +export async function recordCompletedNativeProductBaselines( + file: string, + input: Parameters[0], + transports: Parameters[1] = {}, +) { + const record = await captureCompletedNativeProductBaselines(input, transports); + requireSafeDirectoryChain(path.dirname(path.resolve(file)), { + create: true, + label: 'completed native observations', + }); + await writeImmutableReceipt(file, record); + return record; +} + +if (import.meta.main) { + try { + const { values } = parseArgs({ + options: { + lock: { type: 'string' }, + builds: { type: 'string' }, + repository: { type: 'string' }, + 'bazel-version': { type: 'string' }, + output: { type: 'string' }, + 'head-ref': { type: 'string', default: 'HEAD' }, + }, + allowPositionals: false, + }); + const required = (name: string) => { + if (!values[name]) throw new Error(`completed native observations require --${name}`); + return values[name] as string; + }; + // Execute under with-source.sh at the immutable publication checkout. Later + // readers use the captured frozen facts, not current catalog reconstruction. + const source = sourceIdentity(values['head-ref']); + const snapshot = JSON.parse(process.env.OLIPHAUNT_GIT_SOURCE_JSON || '{}'); + if (snapshot.checkout !== source.commit) + throw new Error( + 'completed native CLI must validate the lock at its exact publication checkout', + ); + execFileSync('bash', [ + path.resolve(import.meta.dir, 'qualified-release-replay.sh'), + source.commit, + source.commit, + ]); + const lock = loadPublicationLock(required('lock')); + assertPublicationLockSource(lock, values['head-ref']); + const record = await recordCompletedNativeProductBaselines(required('output'), { + publicationLock: lock, + publicationFiles: lockedPublicationFiles(lock), + repository: required('repository'), + bazelVersion: required('bazel-version'), + builds: JSON.parse(readFileSync(required('builds'), 'utf8')), + }); + process.stdout.write( + `${JSON.stringify({ products: record.products.map(({ product }) => product.id), observationDigest: record.observationDigest, baselineAdmission: 'unknown' })}\n`, + ); + } catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exitCode = 1; + } +} diff --git a/tools/release/completed-native-product-baseline.test.mts b/tools/release/completed-native-product-baseline.test.mts new file mode 100644 index 000000000..61de47ff1 --- /dev/null +++ b/tools/release/completed-native-product-baseline.test.mts @@ -0,0 +1,229 @@ +import { expect, test } from 'bun:test'; +import { execFileSync } from 'node:child_process'; +import { + copyFileSync, + existsSync, + mkdirSync, + readFileSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { + captureCompletedNativeProductBaselines, + recordCompletedNativeProductBaselines, +} from './completed-native-product-baseline.mts'; +import { fixture, source } from './completed-native-publication.fixture.mts'; + +test('completed projection binds genuine packed bytes, cache-backed configured tests and held contracts per product', async () => { + await fixture(async ({ input, transports, requests }) => { + const record = await captureCompletedNativeProductBaselines(input, transports); + expect(requests).toEqual(['alpha', 'beta', 'auth']); + expect(record.coverage.completeFrozenInventory).toBe(true); + expect(record.coverage.completeMigrationInventory).toBe('unverified'); + expect(record.products.map((product) => product.preEnvelopeCapture)).toEqual([ + 'absent', + 'observed', + ]); + expect(record.products.every((product) => product.baselineAdmission === 'unknown')).toBe(true); + expect(record.releaseDecision).toBe('unverified'); + expect(record.products[0].carriers[0].packageDependencies[0].requirement).toBe('=0.3.2'); + expect( + record.products[0].construction[0].inputs.some((input) => input.path.includes('/beta/')), + ).toBe(false); + expect( + record.products[1].construction[0].roots.find((root) => root.package.ecosystem === 'internal') + .outputs[0].members[1].sha256, + ).toMatch(/^[a-f0-9]{64}$/u); + expect(record.builds[0].requiredTests).toHaveLength(2); + expect(record.builds[0].testQualification).toBe('passed'); + expect(record.publication.registryReceipts).toHaveLength(2); + expect(record.unverified).toContain( + 'immutable input lifetime from the producing build through content capture', + ); + }); +}); + +test('pending or mismatched canonical completion cannot write an observation file', async () => { + await fixture(async ({ input, transports, directory }) => { + const output = path.join(directory, 'completed.json'); + for (const assertCompleted of [ + async () => { + throw new Error('publication is not complete'); + }, + async (requested) => ({ + ...requested, + publicationTree: '9'.repeat(40), + releaseSha: 'f'.repeat(40), + }), + ]) { + await expect( + recordCompletedNativeProductBaselines(output, input, { ...transports, assertCompleted }), + ).rejects.toThrow(); + expect(existsSync(output)).toBe(false); + } + }); +}); + +test('stale source/run, failed mandatory test and incomplete configured inventory fail closed', async () => { + await fixture(async ({ input, transports, origin }) => { + const missingPlan = structuredClone(input); + delete missingPlan.builds[0].requiredTests; + await expect(captureCompletedNativeProductBaselines(missingPlan, transports)).rejects.toThrow( + /nonempty configured test plan/, + ); + const wrongSource = structuredClone(input); + wrongSource.builds[0].expected.source = { ...source, commit: '9'.repeat(40) }; + await expect(captureCompletedNativeProductBaselines(wrongSource, transports)).rejects.toThrow( + /source/, + ); + for (const change of [ + (evidence) => { + evidence.github.runAttempt = 2; + }, + (evidence) => { + evidence.cohorts[0].buildEvents.find((event) => event.testResult).testResult.status = + 'FAILED'; + }, + (evidence) => { + evidence.cohorts[0].roots = evidence.cohorts[0].roots.filter( + (root) => root.package.product !== 'alpha', + ); + evidence.cohorts[0].rootConfigurations = evidence.cohorts[0].rootConfigurations.filter( + (root) => !root.label.includes('/alpha:'), + ); + evidence.cohorts[0].outputs = evidence.cohorts[0].outputs.filter( + (output) => !output.path.includes('/alpha/'), + ); + evidence.cohorts[0].inputs = evidence.cohorts[0].inputs.filter( + (input) => !input.path.includes('/alpha/'), + ); + }, + ]) { + const modified = structuredClone(origin); + change(modified.evidence); + await expect( + captureCompletedNativeProductBaselines(input, { + ...transports, + authenticate: async () => modified, + }), + ).rejects.toThrow(); + } + }); +}); + +test('frozen final artifact substitution and remote registry/asset substitution are rejected', async () => { + await fixture(async ({ input, transports, releases, rehash }) => { + const substituted = structuredClone(input); + substituted.publicationLock.carriers[0].artifacts[0] = { + ...substituted.publicationLock.carriers[0].artifacts[0], + sha256: '9'.repeat(64), + }; + rehash(substituted.publicationLock); + await expect(captureCompletedNativeProductBaselines(substituted, transports)).rejects.toThrow( + /frozen file envelope/, + ); + await expect( + captureCompletedNativeProductBaselines(input, { + ...transports, + verifyRegistry: async () => [], + }), + ).rejects.toThrow(/incomplete/); + const wrongAsset = structuredClone(releases); + wrongAsset[1].assets[0].sha256 = '9'.repeat(64); + await expect( + captureCompletedNativeProductBaselines(input, { + ...transports, + readGithubReleases: async () => wrongAsset, + }), + ).rejects.toThrow(/differs/); + const draft = structuredClone(releases); + draft[0].draft = true; + await expect( + captureCompletedNativeProductBaselines(input, { + ...transports, + readGithubReleases: async () => draft, + }), + ).rejects.toThrow(/stable public/); + }); +}); + +test('immutable completion persistence is idempotent and preserves existing files and safe ancestors', async () => { + await fixture(async ({ input, transports, directory }) => { + const output = path.join(directory, 'completed/observations.json'); + const record = await recordCompletedNativeProductBaselines(output, input, transports); + expect(JSON.parse(readFileSync(output, 'utf8'))).toEqual(record); + await recordCompletedNativeProductBaselines(output, input, transports); + const before = readFileSync(output); + const differing = structuredClone(input); + differing.builds[0].requiredTests = differing.builds[0].requiredTests.slice(0, 1); + await expect( + recordCompletedNativeProductBaselines(output, differing, transports), + ).rejects.toThrow(/non-identical/); + expect(readFileSync(output)).toEqual(before); + symlinkSync(path.join(directory, 'completed'), path.join(directory, 'alias'), 'dir'); + await expect( + recordCompletedNativeProductBaselines( + path.join(directory, 'alias/other.json'), + input, + transports, + ), + ).rejects.toThrow(/symlink/); + }); +}); + +test('CLI rejects historical ref validation in a newer checkout before reading the current catalog', async () => { + await fixture(async ({ directory }) => { + const workspace = path.join(directory, 'history'); + mkdirSync(path.join(workspace, 'tools/release'), { recursive: true }); + const wrapper = path.join(workspace, 'tools/release/with-source.sh'); + copyFileSync(path.resolve(import.meta.dir, 'with-source.sh'), wrapper); + const git = (...args: string[]) => + execFileSync('git', args, { cwd: workspace, encoding: 'utf8' }).trim(); + git('init', '-q'); + git('add', 'tools/release/with-source.sh'); + git( + '-c', + 'user.name=Fixture', + '-c', + 'user.email=fixture@example.invalid', + 'commit', + '-qm', + 'old publication source', + ); + const publication = git('rev-parse', 'HEAD'); + writeFileSync(path.join(workspace, 'new-source.txt'), 'unrelated newer source'); + git('add', 'new-source.txt'); + git( + '-c', + 'user.name=Fixture', + '-c', + 'user.email=fixture@example.invalid', + 'commit', + '-qm', + 'new source', + ); + let failure; + try { + execFileSync( + 'bash', + [ + wrapper, + publication, + process.execPath, + path.resolve(import.meta.dir, 'completed-native-product-baseline.mts'), + '--head-ref', + publication, + '--lock', + path.join(workspace, 'does-not-exist.json'), + ], + { encoding: 'utf8', stdio: 'pipe', timeout: 90_000 }, + ); + } catch (error) { + failure = error; + } + expect(failure?.status).toBe(1); + expect(String(failure?.stderr)).toContain('exact publication checkout'); + expect(String(failure?.stderr)).not.toContain('cannot read publication lock'); + }); +}, 120_000); diff --git a/tools/release/completed-native-publication.fixture.mts b/tools/release/completed-native-publication.fixture.mts new file mode 100644 index 000000000..0fc455363 --- /dev/null +++ b/tools/release/completed-native-publication.fixture.mts @@ -0,0 +1,471 @@ +import { expect } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { archiveDirectory } from '../packaging/archive-directory.mts'; +import { captureNativeBuildEvidence } from './capture-native-build-evidence.mts'; +import { nativeBuildMetadata } from './native-build-qualification.mts'; +import { captureNativeOutputMembers } from './native-publication-staging.mts'; +import { consumerDigest } from './publication-consumer-proof.mts'; +import { PUBLICATION_LOCK_SCHEMA } from './publication-lock.mts'; +import { verifyLockedRegistryIntegrity } from './registry-integrity.mts'; +import { ROOT } from './release-graph.mts'; + +const hash = (bytes: Buffer) => createHash('sha256').update(bytes).digest('hex'); +export const source = { commit: 'a'.repeat(40), tree: 'b'.repeat(40) }; +const configuration = 'c'.repeat(64); + +export async function fixture(run, { producerCapture = false, ownerPolicy = false } = {}) { + // These products/transport responses are synthetic. Real packed files and + // the actual collector, BEP validator and registry verifier exercise the seam. + mkdirSync(path.join(ROOT, 'target'), { recursive: true }); + const directory = mkdtempSync(path.join(ROOT, 'target/completed-native-fixture-')); + const executionRoot = path.join(directory, 'execroot'); + const products = ['alpha', 'beta'].map((id, index) => ({ + id, + version: `${index + 1}.0.0`, + publishTargets: ['github-release', 'npm'], + })); + const roots = [], + carrierRows = [], + artifactRows = [], + publicationFiles = []; + const paths = [], + targets = [], + actions = [], + depSetOfFiles = []; + const addFile = (file: string, content?: string) => { + let index = paths.indexOf(file); + if (index >= 0) return index + 1; + paths.push(file); + index = paths.length; + if (content !== undefined) { + mkdirSync(path.dirname(path.join(executionRoot, file)), { recursive: true }); + writeFileSync(path.join(executionRoot, file), content); + } + return index; + }; + const action = ( + label: string, + outputs: number[], + inputs: number[], + cfg = 1, + mnemonic = 'FixturePackage', + ) => { + const id = targets.length + 1; + targets.push({ id, label }); + depSetOfFiles.push({ id, directArtifactIds: inputs }); + actions.push({ + targetId: id, + configurationId: cfg, + mnemonic, + actionKey: `declaration-${id}`, + inputDepSetIds: [id], + outputIds: outputs, + primaryOutputId: outputs[0], + }); + }; + const tool = addFile('external/compiler/compiler', 'immutable compiler'); + for (const product of products) { + const sourceInput = addFile( + `src/${product.id}/index.ts`, + `export const product = '${product.id}';\n`, + ); + const generated = addFile(`bazel-out/k8-opt/bin/${product.id}/config.h`, '#define VALUE 1\n'); + action(`//fixture/${product.id}:config`, [generated], [sourceInput, tool], 2); + const packed = path.join(directory, `${product.id}-source/package`); + mkdirSync(packed, { recursive: true }); + writeFileSync( + path.join(packed, 'package.json'), + JSON.stringify({ + name: `@fixture/${product.id}`, + version: product.version, + dependencies: { '@fixture/held-runtime': '=0.3.2' }, + }), + ); + writeFileSync(path.join(packed, 'index.ts'), `export const product = '${product.id}';\n`); + const output = `bazel-out/k8-opt/bin/${product.id}/${product.id}.tgz`; + await archiveDirectory(path.dirname(packed), `${path.join(executionRoot, output)}.tar.gz`); + renameSync(`${path.join(executionRoot, output)}.tar.gz`, path.join(executionRoot, output)); + const outputId = addFile(output); + action(`//fixture/${product.id}:archive`, [outputId], [sourceInput, tool, generated]); + roots.push({ + label: `//fixture/${product.id}:npm`, + package: { + product: product.id, + version: product.version, + ecosystem: 'npm', + name: `@fixture/${product.id}`, + configuration: 'portable', + role: 'facade', + outputs: [{ path: output, owner: `//fixture/${product.id}:archive` }], + }, + }); + const bytes = readFileSync(path.join(executionRoot, output)); + const frozenPath = path + .relative(ROOT, path.join(executionRoot, output)) + .split(path.sep) + .join('/'); + const artifact = { path: frozenPath, sha256: hash(bytes), size: bytes.length }; + publicationFiles.push(artifact); + carrierRows.push({ + id: `npm:@fixture/${product.id}`, + product: product.id, + version: product.version, + ecosystem: 'npm', + name: `@fixture/${product.id}`, + role: 'facade', + target: null, + declared: true, + dependencies: [], + packageDependencies: [ + { ecosystem: 'npm', name: '@fixture/held-runtime', requirement: '=0.3.2' }, + ], + artifacts: [artifact], + publishOrder: carrierRows.length, + }); + if (product.id !== 'beta') continue; + const payload = `bazel-out/k8-opt/bin/beta/public_payload`; + addFile(payload); + mkdirSync(path.join(executionRoot, payload)); + writeFileSync( + path.join(executionRoot, payload, 'public-interface.bin'), + 'compiled advertised version 2.0.0', + ); + action('//fixture/beta:payload', [paths.length], [sourceInput, tool, generated]); + roots.push({ + label: '//fixture/beta:internal', + package: { + product: product.id, + version: product.version, + ecosystem: 'internal', + name: 'beta-payload', + configuration: 'linux-x64-gnu', + role: 'construction', + outputs: [{ path: payload, owner: '//fixture/beta:payload' }], + }, + }); + const archive = 'bazel-out/k8-opt/bin/beta/release-assets/beta-runtime.tar.gz'; + await archiveDirectory(path.join(executionRoot, payload), path.join(executionRoot, archive)); + const archiveId = addFile(archive); + action('//fixture/beta:github', [archiveId], [paths.indexOf(payload) + 1]); + roots.push({ + label: '//fixture/beta:public', + package: { + product: product.id, + version: product.version, + ecosystem: 'github', + name: 'beta-runtime.tar.gz', + configuration: 'linux-x64-gnu', + role: 'github-release-asset', + outputs: [{ path: archive, owner: '//fixture/beta:github' }], + }, + }); + const githubBytes = readFileSync(path.join(executionRoot, archive)); + const githubArtifact = { + product: product.id, + id: 'github-release:beta-runtime.tar.gz', + role: 'github-release-asset', + kind: 'native-runtime', + target: 'linux-x64-gnu', + identity: null, + name: 'beta-runtime.tar.gz', + path: path.relative(ROOT, path.join(executionRoot, archive)).split(path.sep).join('/'), + sha256: hash(githubBytes), + size: githubBytes.length, + }; + artifactRows.push(githubArtifact); + publicationFiles.push({ + path: githubArtifact.path, + sha256: githubArtifact.sha256, + size: githubArtifact.size, + }); + } + const manifests = new Map(); + const aqueryFile = path.join(directory, 'aquery.json'); + if (producerCapture) { + for (const [index, root] of roots.entries()) { + const file = `bazel-out/k8-opt/bin/fixture/shipping-${index}.json`; + const contents = `${JSON.stringify(root)}\n`; + const id = addFile(file, contents); + action(root.label, [id], [], 1, 'FileWrite'); + manifests.set(root.label, { file, contents }); + } + } + const github = { + repository: 'f0rr0/oliphaunt', + workflow: 'Native Bazel qualification', + workflowPath: '.github/workflows/bazel.yml', + runId: 77, + runAttempt: 1, + job: 'Linux runtime (x86_64)', + }; + const requiredTests = products.map(({ id }) => ({ + label: `//fixture/${id}:installed_test`, + configuration, + })); + const owner = '//fixture:shipping_export'; + let policy; + if (ownerPolicy) { + if (!producerCapture) + throw new Error('owner policy fixture requires producing shipping manifests'); + const file = 'bazel-out/k8-opt/bin/fixture/shipping_export.json'; + const contents = `${JSON.stringify({ schema: 'oliphaunt-bazel-shipping-v1', scope: 'construction', owner, roots: roots.map((root) => root.label), packages: roots.map((root) => root.package), qualification: requiredTests.map((test) => test.label) })}\n`; + action(owner, [addFile(file, contents)], [], 1, 'FileWrite'); + policy = { file, contents }; + } + const events = [ + { id: { started: {} }, started: { uuid: 'fixture-build', buildToolVersion: '8.8.1' } }, + { id: { workspace: {} }, workspaceInfo: { localExecRoot: executionRoot } }, + { id: { configuration: { id: configuration } }, configuration: { mnemonic: 'k8-opt' } }, + { id: { buildMetadata: {} }, buildMetadata: { metadata: nativeBuildMetadata(source, github) } }, + ]; + if (producerCapture) + events.push({ + id: { structuredCommandLine: { commandLineLabel: 'canonical' } }, + structuredCommandLine: { + commandLineLabel: 'canonical', + sections: [ + { + optionList: { + option: [ + { + optionName: 'experimental_aquery_dump_after_build_format', + optionValue: 'jsonproto', + }, + { + optionName: 'experimental_aquery_dump_after_build_output_file', + optionValue: aqueryFile, + }, + { optionName: 'output_groups', optionValue: '+shipping_manifest' }, + ], + }, + }, + ], + }, + }); + if (policy) + events.push( + { + id: { namedSet: { id: 'owner-policy' } }, + namedSetOfFiles: { + files: [ + { + name: policy.file, + digest: hash(Buffer.from(policy.contents)), + length: String(Buffer.byteLength(policy.contents)), + }, + ], + }, + }, + { + id: { targetCompleted: { label: owner, configuration: { id: configuration } } }, + completed: { + success: true, + outputGroup: [{ name: 'shipping_policy', fileSets: [{ id: 'owner-policy' }] }], + }, + }, + ); + for (const [index, root] of roots.entries()) { + const output = root.package.outputs[0].path; + const members = captureNativeOutputMembers(executionRoot, output).members; + events.push({ + id: { namedSet: { id: `output-${index}` } }, + namedSetOfFiles: { + files: members + .filter((member) => member.type === 'file') + .map((member) => ({ + name: member.path ? `${output}/${member.path}` : output, + digest: member.sha256, + length: String(member.size), + })), + }, + }); + const manifest = manifests.get(root.label); + if (manifest) + events.push({ + id: { namedSet: { id: `manifest-${index}` } }, + namedSetOfFiles: { + files: [ + { + name: manifest.file, + digest: hash(Buffer.from(manifest.contents)), + length: String(Buffer.byteLength(manifest.contents)), + }, + ], + }, + }); + events.push({ + id: { targetCompleted: { label: root.label, configuration: { id: configuration } } }, + completed: { + success: true, + outputGroup: [ + { name: 'default', fileSets: [{ id: `output-${index}` }] }, + ...(manifest + ? [{ name: 'shipping_manifest', fileSets: [{ id: `manifest-${index}` }] }] + : []), + ], + }, + }); + } + for (const test of requiredTests) + events.push( + { + id: { targetCompleted: { label: test.label, configuration: { id: configuration } } }, + completed: { success: true }, + }, + { + id: { testResult: { label: test.label, configuration: { id: configuration }, run: 1 } }, + testResult: { status: 'PASSED', cachedLocally: true }, + }, + { + id: { testSummary: { label: test.label, configuration: { id: configuration } } }, + testSummary: { overallStatus: 'PASSED', totalRunCount: 1 }, + }, + ); + events.push( + { id: { buildFinished: {} }, finished: { exitCode: { name: 'SUCCESS' } } }, + { id: { buildMetrics: {} }, buildMetrics: {}, lastMessage: true }, + ); + const aquery = { + pathFragments: paths.flatMap((file, index) => + file.split('/').map((label, part) => ({ + id: `${index}-${part}`, + label, + ...(part ? { parentId: `${index}-${part - 1}` } : {}), + })), + ), + artifacts: paths.map((file, index) => ({ + id: index + 1, + pathFragmentId: `${index}-${file.split('/').length - 1}`, + })), + targets, + depSetOfFiles, + actions, + configuration: [ + { id: 1, checksum: configuration }, + { id: 2, checksum: 'e'.repeat(64), isTool: true }, + ], + }; + const capture = captureNativeBuildEvidence({ + source, + github, + bazelVersion: '8.8.1', + cohorts: [ + { + executionRoot, + ...(producerCapture + ? { + shippingRoots: roots.map((root) => root.label), + aqueryFile, + ...(ownerPolicy ? { shippingExport: owner } : {}), + } + : { + roots, + cquery: { + results: roots.map((root) => ({ + target: { rule: { name: root.label } }, + configurationId: 11, + })), + configurations: [{ id: 11, checksum: configuration }], + }, + }), + aquery, + buildEvents: events, + }, + ], + }); + const lock = { + schema: PUBLICATION_LOCK_SCHEMA, + catalogSchema: 'oliphaunt-publication-catalog-v1', + catalogDigest: '1'.repeat(64), + packageEnvelopeDigest: '2'.repeat(64), + source, + products, + carriers: carrierRows, + productArtifacts: artifactRows, + }; + const rehash = (value) => { + const { lockDigest: _, ...rest } = value; + value.lockDigest = consumerDigest(rest); + }; + rehash(lock); + const origin = { + github, + artifact: { + id: 101, + name: 'native-build-evidence-x86_64', + digest: `sha256:${'3'.repeat(64)}`, + size: 123, + }, + evidenceDigest: `sha256:${hash(Buffer.from(JSON.stringify(capture.evidence)))}`, + evidence: capture.evidence, + }; + const releases = products.map((product, index) => ({ + product: product.id, + version: product.version, + tag: `${product.id}-v${product.version}`, + releaseId: index + 20, + releaseName: `${product.id} v${product.version}`, + targetCommitish: source.commit, + draft: false, + prerelease: false, + assets: artifactRows + .filter((artifact) => artifact.product === product.id) + .map((artifact, asset) => ({ + assetId: asset + 30, + name: artifact.name, + sha256: artifact.sha256, + size: artifact.size, + })), + })); + const requests = []; + const input = { + publicationLock: lock, + publicationFiles, + repository: github.repository, + bazelVersion: '8.8.1', + builds: [ + { + evidenceRoot: path.join(directory, 'evidence'), + expected: { + source, + github, + event: 'push' as const, + ref: 'refs/heads/main', + artifactName: origin.artifact.name, + }, + requiredTests, + }, + ], + }; + const transports = { + authenticate: async (_root, expected) => { + expect(expected.source).toEqual(source); + requests.push('auth'); + return origin; + }, + assertCompleted: async (requested) => { + requests.push(requested.product); + return { ...requested, publicationTree: source.tree, releaseSha: 'f'.repeat(40) }; + }, + verifyRegistry: (locked) => + verifyLockedRegistryIntegrity(locked, { + fetchImpl: async (url) => { + const carrier = carrierRows.find((carrier) => + String(url).includes(encodeURIComponent(carrier.name)), + ); + const bytes = readFileSync(path.join(ROOT, carrier.artifacts[0].path)); + return Response.json({ + dist: { integrity: `sha512-${createHash('sha512').update(bytes).digest('base64')}` }, + }); + }, + }), + readGithubReleases: async () => releases, + }; + try { + await run({ input, transports, origin, releases, directory, requests, rehash, capture }); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +} diff --git a/tools/release/completed-release-publication.mts b/tools/release/completed-release-publication.mts new file mode 100644 index 000000000..d6c6ab2c2 --- /dev/null +++ b/tools/release/completed-release-publication.mts @@ -0,0 +1,213 @@ +import { PullRequestBody } from 'release-please/build/src/util/pull-request-body.js'; +import { requestGithubPages, requestGithubRepositoryJson } from './github-read.mts'; +import { + releasePleaseClosedPullRequestQuery, + releasePleaseLabelState, + selectExactReleasePullRequest, +} from './release-please-pr-lifecycle.mts'; + +const quiet = { error() {}, warn() {} }; +const fullSha = /^[0-9a-f]{40}$/u; + +export interface CompletedPublication { + product: string; + version: string; + tagName: string; + publicationSha: string; + publicationTree: string; + releaseSha: string; +} + +function error(message) { + return new Error(`prepare-release-candidate: ${message}`); +} + +// The existing publication workflow marks the canonical PR tagged only after +// registry verification, public consumer proof and promotion of every draft. +export function createCompletedPublicationChecker({ + repository, + listPullRequests = () => + requestGithubPages( + `repos/${repository}/pulls?${releasePleaseClosedPullRequestQuery(repository)}`, + { label: 'completed release pull requests' }, + ), + readJson = requestGithubRepositoryJson, + readPages = requestGithubPages, +}) { + let pullRequests; + const reads = new Map(); + const versions = new Map(); + const transitions = new Map(); + const pagedComparisons = new Map(); + const read = (endpoint) => { + if (!reads.has(endpoint)) reads.set(endpoint, readJson(endpoint)); + return reads.get(endpoint); + }; + const versionState = (sha) => { + if (!versions.has(sha)) + versions.set( + sha, + (async () => { + const contents = await Promise.all( + ['release-please-config.json', '.release-please-manifest.json'].map(async (file) => { + const response = await read(`repos/${repository}/contents/${file}?ref=${sha}`); + if (response.encoding !== 'base64' || typeof response.content !== 'string') + throw error(`missing historical ${file} at ${sha}`); + return JSON.parse(Buffer.from(response.content, 'base64').toString('utf8')); + }), + ); + const [config, manifest] = contents; + const state = new Map(); + for (const [owner, entry] of Object.entries(config.packages ?? {})) { + if ( + !entry.component || + state.has(entry.component) || + typeof manifest[owner] !== 'string' + ) + throw error(`invalid historical product versions at ${sha}`); + state.set(entry.component, manifest[owner]); + } + return state; + })(), + ); + return versions.get(sha); + }; + const releaseTransition = (sha) => { + if (!transitions.has(sha)) + transitions.set( + sha, + (async () => { + const commit = await read(`repos/${repository}/git/commits/${sha}`); + if ( + commit.sha !== sha || + commit.parents?.length !== 1 || + !fullSha.test(commit.parents[0].sha) + ) + throw error(`release ${sha} is not an exact single-parent version commit`); + const [before, after] = await Promise.all([ + versionState(commit.parents[0].sha), + versionState(sha), + ]); + return new Map( + [...after].filter(([product, version]) => before.get(product) !== version), + ); + })(), + ); + return transitions.get(sha); + }; + + return async ({ product, version, publicationSha, tagName }) => { + if (typeof tagName !== 'string' || !tagName || !fullSha.test(publicationSha)) + throw error(`${product}@${version} has no exact publication identity`); + const published = await read( + `repos/${repository}/releases/tags/${encodeURIComponent(tagName)}`, + ); + if ( + published.tag_name !== tagName || + published.draft !== false || + published.prerelease !== false || + published.target_commitish !== publicationSha + ) + throw error( + `${product}@${version} public release does not bind its exact publication source`, + ); + pullRequests ??= Promise.resolve(listPullRequests()); + const canonical = (await pullRequests).filter((candidate) => { + try { + return ( + selectExactReleasePullRequest([candidate], { + repository, + releaseSha: candidate.merge_commit_sha, + }) === candidate + ); + } catch { + return false; + } + }); + const matches = []; + for (const candidate of canonical) { + let body; + try { + body = typeof candidate.body === 'string' && PullRequestBody.parse(candidate.body, quiet); + } catch { + continue; + } + if ( + !body?.releaseData.some( + (release) => + (!release.component || release.component === product) && + release.version?.toString() === version, + ) + ) + continue; + if ((await releaseTransition(candidate.merge_commit_sha)).get(product) === version) + matches.push(candidate); + } + if (matches.length !== 1) + throw error(`${product}@${version} has no unique canonical release completion`); + const [release] = matches; + const releaseSha = release.merge_commit_sha; + if ( + releasePleaseLabelState(release, { base: 'main', repository, releaseSha }).kind !== 'desired' + ) + throw error(`${product}@${version} publication is not complete`); + const publicationVersions = await versionState(publicationSha); + const releasedVersions = await releaseTransition(releaseSha); + if ( + [...releasedVersions].some( + ([released, expected]) => publicationVersions.get(released) !== expected, + ) + ) + throw error(`${product}@${version} publication source has different product versions`); + const publicationCommit = await read(`repos/${repository}/git/commits/${publicationSha}`); + if (publicationCommit?.sha !== publicationSha || !fullSha.test(publicationCommit.tree?.sha)) + throw error(`${product}@${version} publication source has no exact Git tree`); + const completed: CompletedPublication = Object.freeze({ + product, + version, + tagName, + publicationSha, + publicationTree: publicationCommit.tree.sha, + releaseSha, + }); + if (releaseSha === publicationSha) return completed; + const endpoint = `repos/${repository}/compare/${releaseSha}...${publicationSha}`; + const comparison = await read(`${endpoint}?per_page=100`); + if ( + comparison.status !== 'ahead' || + comparison.behind_by !== 0 || + comparison.base_commit?.sha !== releaseSha || + comparison.merge_base_commit?.sha !== releaseSha + ) + throw error(`${product}@${version} publication source is not a release descendant`); + if (comparison.commits?.length !== comparison.total_commits && !pagedComparisons.has(endpoint)) + pagedComparisons.set( + endpoint, + readPages(endpoint, { + itemsField: 'commits', + label: 'publication recovery history', + }), + ); + const commits = + comparison.commits?.length === comparison.total_commits + ? comparison.commits + : await pagedComparisons.get(endpoint); + const shas = Array.isArray(commits) && commits.map(({ sha }) => sha); + if ( + !Array.isArray(commits) || + commits.length !== comparison.total_commits || + shas.some((sha) => !fullSha.test(sha)) || + new Set(shas).size !== commits.length || + !shas.includes(publicationSha) + ) + throw error(`${product}@${version} publication recovery history is incomplete`); + const intervening = new Set( + canonical + .filter((candidate) => candidate !== release) + .map((candidate) => candidate.merge_commit_sha), + ); + if (commits.some(({ sha }) => intervening.has(sha))) + throw error(`${product}@${version} publication source follows another release candidate`); + return completed; + }; +} diff --git a/tools/release/completed-swift-source-delivery.mts b/tools/release/completed-swift-source-delivery.mts new file mode 100644 index 000000000..a94a51f89 --- /dev/null +++ b/tools/release/completed-swift-source-delivery.mts @@ -0,0 +1,456 @@ +/** The published Swift source tag is a delivered envelope, never an old Bazel graph. */ +import { deepStrictEqual } from 'node:assert'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + lstatSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + assertSwiftSourceDeliveryParity, + readSwiftSourceTagMembers, +} from '../../build_defs/languages/swift/source-delivery-contract.mts'; +import { + createPublishedNativeLegalSourceBasis, + publishedNativeBaseForSource, +} from '../../src/native/sdks/swift/tools/native-legal-source-basis.mts'; +import { + IOS_CARRIER_FILENAME, + validateFrozenNativeCarrierIdentity, +} from '../../src/native/sdks/swift/tools/swift-native-carrier-contract.mts'; +import { renderSwiftReleaseManifest } from '../../src/native/sdks/swift/tools/swift-release-manifest.mts'; +import { createDeterministicTar } from '../packaging/archive-directory.mts'; +import { canonicalGzipSync, extractPortableArchiveTree } from '../packaging/portable-archive.mts'; +import { requireSafeDirectoryChain } from '../packaging/release-directory-safety.mts'; +import { + type CompletedPublication, + createCompletedPublicationChecker, +} from './completed-release-publication.mts'; +import { requestGithubPages, requestGithubRepositoryJson } from './github-read.mts'; +import { fileIdentity, safeRelative } from './native-file-identity.mts'; +import { lockedPublicationFiles } from './publication-lock.mts'; +import { createRetainedDownload } from './retained-download.mts'; + +const repository = 'f0rr0/oliphaunt'; +const prefix = 'src/sdks/swift'; +const carrierMember = `${prefix}/Carriers/${IOS_CARRIER_FILENAME}`; +const sha40 = /^[0-9a-f]{40}$/u; +const stableVersion = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u; +const text = (bytes: Uint8Array) => + new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(bytes); +const gitSha = (kind: string, bytes: Uint8Array) => + createHash('sha1').update(`${kind} ${bytes.length}\0`).update(bytes).digest('hex'); +const digest = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +function requireValue(value: unknown, message: string) { + if (!value) throw new Error(`completed Swift source delivery: ${message}`); +} + +/** Canonical Git objects prove complete membership without reading the unrelated repository tree. */ +export async function captureCompletedSwiftSourceTag( + { + publication, + descriptor, + bindings, + retainedArchive, + }: { + publication: CompletedPublication; + descriptor: any; + /** Already authenticated through the completed public-asset reader. */ + bindings: { name: string; sha256: string }; + /** Reconstructed Git delivery; this File is not a published GitHub asset. */ + retainedArchive?: string; + }, + { + assertCompletedPublication = createCompletedPublicationChecker({ repository }), + readJson = requestGithubRepositoryJson, + readPages = requestGithubPages, + } = {}, +) { + publication = structuredClone(publication); + descriptor = structuredClone(descriptor); + bindings = structuredClone(bindings); + requireValue( + publication.product === 'oliphaunt-swift' && descriptor.id === publication.product, + 'source publisher owner differs', + ); + deepStrictEqual(await assertCompletedPublication(publication), publication); + const reads = new Map>(); + const read = (endpoint: string) => { + let result = reads.get(endpoint); + if (!result) { + result = Promise.resolve(readJson(endpoint)).then((value) => structuredClone(value)); + reads.set(endpoint, result); + } + return result; + }; + const pins = Object.values(descriptor.compatibility_versions ?? {}).filter( + (row: any) => row.source_product === 'liboliphaunt-native', + ) as any[]; + requireValue(pins.length === 1 && pins[0].parser === 'raw', 'native supplier needs one raw pin'); + const pinPath = safeRelative(pins[0].path); + const pin = await read( + `repos/${repository}/contents/${pinPath}?ref=${publication.publicationSha}`, + ); + requireValue( + pin.type === 'file' && + pin.path === pinPath && + pin.encoding === 'base64' && + typeof pin.content === 'string' && + sha40.test(pin.sha), + 'completed native supplier pin is missing', + ); + const pinBytes = Buffer.from(pin.content, 'base64'); + requireValue(gitSha('blob', pinBytes) === pin.sha, 'native supplier pin blob differs'); + const nativeVersion = text(pinBytes).trim(); + requireValue(stableVersion.test(nativeVersion), 'native supplier pin is not exact'); + const basis = await createPublishedNativeLegalSourceBasis({ + nativeVersion, + swiftVersion: publication.version, + readJson: read, + readPages, + assertCompletedPublication, + }); + deepStrictEqual(basis.sourcePublication, publication); + const base = publishedNativeBaseForSource(basis); + const baseArchive = base.assets.find(({ role }) => role === 'base-xcframework'); + requireValue( + bindings.name === `oliphaunt-swift-${publication.version}-bindings.xcframework.zip` && + /^[0-9a-f]{64}$/u.test(bindings.sha256), + 'owned bindings archive differs from the completed owner', + ); + const manifest = Buffer.from( + renderSwiftReleaseManifest( + baseArchive.url.slice(0, baseArchive.url.lastIndexOf('/')), + nativeVersion, + baseArchive.sha256, + `https://github.com/${repository}/releases/download/${publication.tagName}/${bindings.name}`, + bindings.sha256, + ), + ); + const trees = new Map>(); + const tree = (sha: string): Promise => { + let result = trees.get(sha); + if (!result) { + result = (async () => { + const value = await read(`repos/${repository}/git/trees/${sha}`); + requireValue( + value.sha === sha && value.truncated !== true && Array.isArray(value.tree), + 'Git tree is missing or truncated', + ); + const names = new Set(); + for (const row of value.tree) { + safeRelative(row.path); + requireValue( + !row.path.includes('/') && !names.has(row.path) && sha40.test(row.sha), + 'Git tree member is unsafe or duplicated', + ); + names.add(row.path); + requireValue( + (row.type === 'tree' && row.mode === '040000') || + (row.type === 'blob' && ['100644', '100755', '120000'].includes(row.mode)) || + (row.type === 'commit' && row.mode === '160000'), + 'Git tree member type/mode differs', + ); + } + const sorted = [...value.tree].sort((left, right) => + Buffer.compare( + Buffer.from(left.path + (left.type === 'tree' ? '/' : '')), + Buffer.from(right.path + (right.type === 'tree' ? '/' : '')), + ), + ); + const bytes = Buffer.concat( + sorted.flatMap((row) => [ + Buffer.from(`${row.mode.replace(/^0/u, '')} ${row.path}\0`), + Buffer.from(row.sha, 'hex'), + ]), + ); + requireValue( + gitSha('tree', bytes) === sha, + 'Git tree bytes differ from their immutable object', + ); + return value.tree; + })(); + trees.set(sha, result); + } + return result; + }; + const members: any[] = [{ path: '', type: 'directory', mode: 0o755 }]; + const bytesByPath = new Map(); + let bytesRead = 0; + const file = async (row, member: string) => { + requireValue( + row.type === 'blob' && ['100644', '100755'].includes(row.mode), + `source tag requires a regular member: ${member}`, + ); + const value = await read(`repos/${repository}/git/blobs/${row.sha}`); + requireValue( + value.sha === row.sha && value.encoding === 'base64' && typeof value.content === 'string', + 'Git blob identity differs', + ); + const bytes = Buffer.from(value.content, 'base64'); + bytesRead += bytes.length; + requireValue( + bytes.length === value.size && + bytes.length <= 16 * 1024 * 1024 && + bytesRead <= 64 * 1024 * 1024 && + gitSha('blob', bytes) === row.sha, + 'Git blob bytes or size differ', + ); + bytesByPath.set(member, bytes); + members.push({ + path: member, + type: 'file', + mode: Number.parseInt(row.mode, 8) & 0o777, + size: bytes.length, + sha256: digest(bytes), + }); + }; + const walk = async (sha: string, parent: string) => { + for (const row of await tree(sha)) { + requireValue(row.path !== '.git', 'source tag cannot contain Git internals'); + const member = `${parent}/${row.path}`; + requireValue(members.length < 10000, 'source tag member limit exceeded'); + if (row.type === 'tree') { + members.push({ path: member, type: 'directory', mode: 0o755 }); + await walk(row.sha, member); + } else await file(row, member); + } + }; + const root = await tree(basis.source.tree); + for (const name of ['Package.swift', 'LICENSE', 'THIRD_PARTY_NOTICES.md']) { + const row = root.find(({ path }) => path === name); + requireValue(row, `source tag lacks ${name}`); + await file(row, name); + } + let ancestor = root; + let parent = ''; + for (const name of prefix.split('/')) { + const row = ancestor.find(({ path }) => path === name); + requireValue(row?.type === 'tree' && row.mode === '040000', `source tag lacks ${prefix}`); + parent = parent ? `${parent}/${name}` : name; + members.push({ path: parent, type: 'directory', mode: 0o755 }); + ancestor = await tree(row.sha); + } + for (const required of ['Sources', 'Templates', 'Carriers']) + requireValue( + ancestor.some(({ path, type }) => path === required && type === 'tree'), + `source tag lacks ${required}`, + ); + // Reuse the already validated direct SDK rows without inventing any missing legacy version files. + for (const row of ancestor) { + const member = `${prefix}/${row.path}`; + requireValue(row.path !== '.git', 'source tag cannot contain Git internals'); + if (row.type === 'tree') { + members.push({ path: member, type: 'directory', mode: 0o755 }); + await walk(row.sha, member); + } else await file(row, member); + } + requireValue( + bytesByPath.get('Package.swift')?.equals(manifest), + 'source tag manifest differs from completed supplier/bindings contracts', + ); + requireValue( + gitSha('blob', bytesByPath.get(carrierMember) ?? Buffer.alloc(0)) === basis.source.blob, + 'source tag carrier differs from the authenticated supplier', + ); + for (const [name, version] of [ + ['VERSION', publication.version], + ['LIBOLIPHAUNT_VERSION', nativeVersion], + ]) { + const bytes = bytesByPath.get(`${prefix}/${name}`); + if (bytes) requireValue(text(bytes).trim() === version, `source tag ${name} differs`); + } + let retained: { path: string; size: number; sha256: string } | undefined; + if (retainedArchive !== undefined) { + requireValue( + path.isAbsolute(retainedArchive), + 'retained source archive requires an absolute path', + ); + requireSafeDirectoryChain(path.dirname(retainedArchive), { + create: true, + label: 'retained Swift source tag', + }); + const directory = mkdtempSync(path.join(tmpdir(), 'completed-swift-source-')); + const output = await createRetainedDownload(retainedArchive); + try { + chmodSync(directory, 0o755); + for (const member of members.filter(({ type }) => type === 'directory')) { + const target = member.path ? path.join(directory, safeRelative(member.path)) : directory; + mkdirSync(target, { recursive: true }); + chmodSync(target, member.mode); + } + for (const member of members.filter(({ type }) => type === 'file')) { + const target = path.join(directory, safeRelative(member.path)); + writeFileSync(target, bytesByPath.get(member.path), { flag: 'wx', mode: member.mode }); + chmodSync(target, member.mode); + } + deepStrictEqual( + readSwiftSourceTagMembers(directory).sort((a, b) => a.path.localeCompare(b.path)), + [...members].sort((a, b) => a.path.localeCompare(b.path)), + 'retained source tree differs from authenticated Git members', + ); + await output.write(canonicalGzipSync(await createDeterministicTar(directory))); + const file = await output.commit(); + const identity = fileIdentity(file); + retained = { path: file, size: identity.size, sha256: identity.sha256 }; + } catch (error) { + await output.abort(); + throw error; + } finally { + rmSync(directory, { recursive: true, force: true }); + } + } + return { + scope: 'construction' as const, + publication, + source: basis.source, + nativePublication: basis.publication, + ...(retained ? { file: retained } : {}), + members: members.sort((a, b) => a.path.localeCompare(b.path)), + }; +} + +/** Reauthenticate reconstructed Git delivery; outer archive hashes alone are not a published asset origin. */ +export async function replayCompletedSwiftSourceArchive( + input: Parameters[0] & { + source: { commit: string; tree: string; member: string; blob: string }; + file: { path: string; size: number; sha256: string }; + }, + options: Parameters[1] = {}, +) { + const supplied = structuredClone(input); + const before = fileIdentity(supplied.file.path); + deepStrictEqual( + { size: before.size, sha256: before.sha256 }, + { size: supplied.file.size, sha256: supplied.file.sha256 }, + 'retained completed Swift archive bytes differ', + ); + const captured = await captureCompletedSwiftSourceTag( + { + publication: supplied.publication, + descriptor: supplied.descriptor, + bindings: supplied.bindings, + }, + options, + ); + deepStrictEqual(captured.source, supplied.source, 'retained Swift source tag changed'); + const directory = mkdtempSync(path.join(tmpdir(), 'completed-swift-replay-')); + try { + const tree = path.join(directory, 'source'); + extractPortableArchiveTree(supplied.file.path, tree); + deepStrictEqual( + readSwiftSourceTagMembers(tree).sort((a, b) => a.path.localeCompare(b.path)), + captured.members, + 'retained Swift archive member differs from immutable Git source', + ); + deepStrictEqual( + fileIdentity(supplied.file.path), + before, + 'retained Swift archive changed during replay', + ); + return { ...captured, file: supplied.file }; + } finally { + rmSync(directory, { recursive: true, force: true }); + } +} + +/** Current physical files remain bound to the existing candidate and installed ZIP parity. */ +export function currentSwiftSourceTagMembers(candidate: any) { + const product = candidate.products.find(({ id }) => id === 'oliphaunt-swift'); + requireValue(product, 'candidate source publisher is missing'); + const artifacts = candidate.productArtifacts.filter(({ product: id }) => id === product.id); + const select = (kind: string) => { + const matches = artifacts.filter((row) => row.kind === kind); + requireValue(matches.length === 1, `candidate needs exactly one ${kind}`); + return matches[0]; + }; + const tree = select('swiftpm-release-tree'); + const archive = select('swiftpm-source-archive'); + const separateManifest = select('swiftpm-release-manifest'); + const carrier = select('swiftpm-ios-carrier-manifest'); + const bindings = select('swift-bindings'); + const root = path.resolve(import.meta.dir, '../..'); + const absolute = (row) => path.resolve(root, safeRelative(row.path)); + requireValue( + lstatSync(absolute(tree)).isDirectory() && !lstatSync(absolute(tree)).isSymbolicLink(), + 'candidate source tag must be a regular directory', + ); + const envelope = { products: [product], carriers: [], productArtifacts: artifacts }; + const before = lockedPublicationFiles(envelope); + const members = readSwiftSourceTagMembers(absolute(tree)); + // The existing publisher overlays generated files as Git100644. A future + // executable source needs a matching publisher contract, not raw-mode inference. + requireValue( + members.every((member) => member.type !== 'file' || member.mode === 0o644), + 'candidate executable source-tag member has no matching publisher mode contract', + ); + const orderedFiles = (rows) => rows.sort((left, right) => left.path.localeCompare(right.path)); + deepStrictEqual( + orderedFiles( + members + .filter((member) => member.type === 'file') + .map(({ path, size, sha256 }) => ({ path, size, sha256 })), + ), + orderedFiles( + before + .filter(({ path: name }) => name.startsWith(`${tree.path}/`)) + .map(({ path: name, size, sha256 }) => ({ + path: name.slice(tree.path.length + 1), + size, + sha256, + })), + ), + 'candidate source tag members exceed its frozen physical file inventory', + ); + const read = (name) => readFileSync(path.join(absolute(tree), name)); + requireValue( + text(read(`${prefix}/VERSION`)).trim() === product.version, + 'candidate VERSION differs', + ); + const nativeVersion = text(read(`${prefix}/LIBOLIPHAUNT_VERSION`)).trim(); + const value = validateFrozenNativeCarrierIdentity({ + carrier: JSON.parse(text(read(carrierMember))), + expectedNativeVersion: nativeVersion, + }); + requireValue( + path.resolve(absolute(carrier)) === path.join(absolute(tree), carrierMember), + 'candidate carrier does not belong to its source tag', + ); + const asset = value.base.assets.find(({ role }) => role === 'base-xcframework'); + const manifest = Buffer.from( + renderSwiftReleaseManifest( + asset.url.slice(0, asset.url.lastIndexOf('/')), + nativeVersion, + asset.sha256, + `https://github.com/${repository}/releases/download/oliphaunt-swift-v${product.version}/${bindings.name}`, + fileIdentity(absolute(bindings)).sha256, + ), + ); + requireValue( + read('Package.swift').equals(manifest) && + readFileSync(absolute(separateManifest)).equals(manifest), + 'candidate source manifest differs from its supplier/bindings contracts', + ); + assertSwiftSourceDeliveryParity(absolute(archive), members, manifest); + deepStrictEqual( + readSwiftSourceTagMembers(absolute(tree)), + members, + 'candidate source tag changed during comparison', + ); + deepStrictEqual( + lockedPublicationFiles(envelope), + before, + 'candidate source files changed during comparison', + ); + // The publisher records Git file modes, not filesystem directory modes. + // Keep every regular-file mode exact; both trees use the installed directory contract. + return members.map((member) => + member.type === 'directory' ? { ...member, mode: 0o755 } : member, + ); +} diff --git a/tools/release/completed-swift-source-delivery.test.mts b/tools/release/completed-swift-source-delivery.test.mts new file mode 100644 index 000000000..1c910da3f --- /dev/null +++ b/tools/release/completed-swift-source-delivery.test.mts @@ -0,0 +1,689 @@ +import { expect, test } from 'bun:test'; +import { execFileSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + copyFileSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { + assertSwiftSourceDeliveryParity, + readSwiftSourceTagMembers, +} from '../../build_defs/languages/swift/source-delivery-contract.mts'; +import { fixture as swiftInputs } from '../../build_defs/languages/swift/source-package.fixture.mts'; +import { packageSwiftSource } from '../../build_defs/languages/swift/source-package.mts'; +import { createPublishedNativeLegalSourceBasis } from '../../src/native/sdks/swift/tools/native-legal-source-basis.mts'; +import { createDeterministicZip } from '../packaging/archive-directory.mts'; +import { extractPortableArchiveTree } from '../packaging/portable-archive.mts'; +import { + captureCompletedSwiftSourceTag, + currentSwiftSourceTagMembers, + replayCompletedSwiftSourceArchive, +} from './completed-swift-source-delivery.mts'; +import { + captureCompletedNativeSwiftSourceSuppliers, + compareNativeCompletedPhysicalDelivery, +} from './native-completed-delivery.mts'; +import { differentNativeDeliveredMembers } from './native-publication-delivery.mts'; +import { buildPublicationCandidate, expectedProductArtifactRows } from './publication-lock.mts'; +import { ROOT } from './release-graph.mts'; + +const repository = 'repos/f0rr0/oliphaunt'; +const prefix = 'src/sdks/swift'; +const carrierPath = `${prefix}/Carriers/oliphaunt-react-native-ios-carriers.json`; +const hash = (bytes) => createHash('sha256').update(bytes).digest('hex'); +const gitHash = (kind, bytes) => + createHash('sha1').update(`${kind} ${bytes.length}\0`).update(bytes).digest('hex'); +const git = (...args: string[]) => + execFileSync('git', args, { cwd: ROOT, stdio: ['ignore', 'pipe', 'pipe'] }); +const captured = JSON.parse( + readFileSync(path.join(ROOT, 'build_defs/release/swift-0.8.2-publication-source.json'), 'utf8'), +); +const native = JSON.parse( + readFileSync( + path.join(ROOT, 'build_defs/release/native-0.3.3-completed-publication.json'), + 'utf8', + ), +); +const descriptor = Bun.TOML.parse( + git( + 'show', + `${captured.publication.publicationSha}:src/native/sdks/swift/release.toml`, + ).toString(), +); +const blob = (bytes, member?) => ({ + sha: gitHash('blob', bytes), + size: bytes.length, + encoding: 'base64', + content: bytes.toString('base64'), + ...(member ? { path: member, type: 'file' } : {}), +}); + +/** Controlled API transports retain real Git object hashes; they do not authenticate a fixture publication. */ +function transport(source, contents, treeReader, blobReader, carrier) { + const nativeId = 31; + const swiftId = 82; + const readJson = async (endpoint) => { + if (endpoint === `${repository}/releases/tags/${native.tagName}`) + return { + id: nativeId, + tag_name: native.tagName, + target_commitish: native.publicationSha, + draft: false, + prerelease: false, + }; + if (endpoint === `${repository}/releases/tags/${source.publication.tagName}`) + return { + id: swiftId, + tag_name: source.publication.tagName, + target_commitish: source.publication.publicationSha, + draft: false, + prerelease: false, + }; + if (endpoint === `${repository}/git/ref/tags/${source.publication.version}`) + return source.reference; + if (endpoint === `${repository}/git/commits/${source.reference.object.sha}`) + return source.commit; + if (endpoint === `${repository}/contents/${carrierPath}?ref=${source.commit.sha}`) + return contents(carrierPath); + if ( + endpoint === + `${repository}/contents/src/native/sdks/swift/LIBOLIPHAUNT_VERSION?ref=${source.publication.publicationSha}` + ) + return blob(Buffer.from(`${native.version}\n`), 'src/native/sdks/swift/LIBOLIPHAUNT_VERSION'); + if ( + endpoint === + `${repository}/contents/src/native/sdks/swift/release.toml?ref=${source.publication.publicationSha}` + ) + return blob( + Buffer.from( + git('show', `${captured.publication.publicationSha}:src/native/sdks/swift/release.toml`), + ), + 'src/native/sdks/swift/release.toml', + ); + // Historical inventory is pinned to the publication commit, separately + // from the delivered Swift source tag and its immutable Git members. + for (const member of ['release-please-config.json', '.release-please-manifest.json']) + if (endpoint === `${repository}/contents/${member}?ref=${source.publication.publicationSha}`) + return blob(git('show', `${source.publication.publicationSha}:${member}`), member); + if (endpoint.startsWith(`${repository}/git/trees/`)) + return treeReader(endpoint.split('/').at(-1)); + if (endpoint.startsWith(`${repository}/git/blobs/`)) + return blobReader(endpoint.split('/').at(-1)); + throw new Error(`unexpected fixture API read: ${endpoint}`); + }; + const readPages = async (endpoint) => { + if (endpoint !== `${repository}/releases/${nativeId}/assets`) + throw new Error(`unexpected asset read ${endpoint}`); + return carrier.base.assets.map((asset, index) => ({ + id: index + 1, + name: asset.name, + browser_download_url: asset.url, + digest: `sha256:${asset.sha256}`, + size: asset.bytes, + })); + }; + const assertCompletedPublication = async (identity) => { + const expected = identity.product === native.product ? native : source.publication; + for (const key of ['product', 'version', 'tagName', 'publicationSha']) + expect(identity[key]).toBe(expected[key]); + return structuredClone(expected); + }; + return { readJson, readPages, assertCompletedPublication }; +} +function genuine() { + const contents = (member) => blob(git('show', `${captured.commit.sha}:${member}`), member); + const treeReader = (sha) => ({ + sha, + truncated: false, + tree: git('ls-tree', '-z', sha) + .toString() + .split('\0') + .filter(Boolean) + .map((line) => { + const [header, name] = line.split('\t'); + const [mode, type, sha] = header.split(' '); + return { path: name, mode, type, sha }; + }), + }); + const options = transport( + captured, + contents, + treeReader, + (sha) => blob(git('cat-file', 'blob', sha)), + JSON.parse( + contents(carrierPath).content + ? Buffer.from(contents(carrierPath).content, 'base64').toString() + : '', + ), + ); + const manifest = git('show', `${captured.commit.sha}:Package.swift`).toString(); + const checksum = manifest.match( + /name: "OliphauntNativeBindingsFFI",[\s\S]*?checksum: "([0-9a-f]{64})"/u, + )[1]; + return { + options, + input: { + publication: captured.publication, + descriptor, + bindings: { name: 'oliphaunt-swift-0.8.2-bindings.xcframework.zip', sha256: checksum }, + }, + }; +} + +test('genuine immutable Swift tag has its own commit/tree and retains the actual legacy version-file absence', async () => { + const { input, options } = genuine(); + const result = await captureCompletedSwiftSourceTag(input, options); + expect(result.source.commit).toBe(captured.commit.sha); + expect(result.source.commit).not.toBe(result.publication.publicationSha); + expect(result.source.tree).toBe(captured.commit.tree.sha); + expect(result.members.filter(({ type }) => type === 'file')).toHaveLength(29); + expect(result.members.some(({ path }) => path === `${prefix}/VERSION`)).toBe(false); + expect(result.members.some(({ path }) => path.startsWith('src/native/'))).toBe(false); + const swift = result.members.find( + ({ path }) => path === `${prefix}/Sources/Oliphaunt/Oliphaunt.swift`, + ); + expect(swift.sha256).toBe(hash(git('show', `${captured.commit.sha}:${swift.path}`))); + expect(result.scope).toBe('construction'); + expect(result).not.toHaveProperty('releaseDecision'); +}); + +test('caller mutation during immutable acquisition cannot relabel the captured publication or supplier', async () => { + const fixture = genuine(); + const input = structuredClone(fixture.input); + const original = fixture.options.readJson; + const readJson = async (endpoint) => { + if (endpoint.includes('/contents/') && endpoint.includes('LIBOLIPHAUNT_VERSION')) { + input.publication.version = '0.8.1'; + input.descriptor.compatibility_versions['oliphaunt-swift-liboliphaunt'].path = '../outside'; + input.bindings.sha256 = 'f'.repeat(64); + } + return original(endpoint); + }; + const result = await captureCompletedSwiftSourceTag(input, { ...fixture.options, readJson }); + expect(result.publication).toEqual(captured.publication); + expect(result.source.tree).toBe(captured.commit.tree.sha); +}); + +for (const fault of [ + 'wrong-tag', + 'wrong-parent', + 'wrong-tree', + 'missing', + 'extra', + 'duplicate', + 'mode', + 'truncated', + 'blob', + 'pin', + 'bindings', +]) + test(`immutable Swift source-tag acquisition rejects ${fault} substitution`, async () => { + const { input, options } = genuine(); + const original = options.readJson; + const readJson = async (endpoint) => { + const value = structuredClone(await original(endpoint)); + if (fault === 'wrong-tag' && endpoint.includes('/git/ref/')) value.ref = 'refs/tags/0.8.1'; + if (endpoint.includes('/git/commits/')) { + if (fault === 'wrong-parent') value.parents[0].sha = 'f'.repeat(40); + if (fault === 'wrong-tree') value.tree.sha = 'f'.repeat(40); + } + if (endpoint === `${repository}/git/trees/${captured.commit.tree.sha}`) { + if (fault === 'missing') value.tree.pop(); + if (fault === 'extra') value.tree.push({ ...value.tree[0], path: 'extra' }); + if (fault === 'duplicate') value.tree.push(value.tree[0]); + if (fault === 'mode') value.tree.find(({ path }) => path === 'LICENSE').mode = '100755'; + if (fault === 'truncated') value.truncated = true; + } + if (fault === 'blob' && endpoint.includes('/git/blobs/')) + value.content = Buffer.from('substituted').toString('base64'); + if ( + fault === 'pin' && + endpoint.includes('/contents/') && + endpoint.includes('LIBOLIPHAUNT_VERSION') + ) + value.content = Buffer.from('0.3.2\n').toString('base64'); + return value; + }; + if (fault === 'bindings') input.bindings.sha256 = 'f'.repeat(64); + await expect(captureCompletedSwiftSourceTag(input, { ...options, readJson })).rejects.toThrow(); + }); + +function gitObjects(files) { + const trees = new Map(), + blobs = new Map(); + const root = {}; + for (const [member, record] of files) { + const parts = member.split('/'); + let node = root; + for (const name of parts.slice(0, -1)) node = node[name] ??= {}; + node[parts.at(-1)] = record; + } + const visit = (node) => { + const rows = Object.entries(node) + .map(([name, value]: [string, any]) => { + if (value.bytes !== undefined) { + const sha = gitHash('blob', value.bytes); + blobs.set(sha, blob(value.bytes)); + return { path: name, type: 'blob', mode: value.mode ?? '100644', sha }; + } + return { path: name, type: 'tree', mode: '040000', sha: visit(value) }; + }) + .sort((a, b) => + Buffer.compare( + Buffer.from(a.path + (a.type === 'tree' ? '/' : '')), + Buffer.from(b.path + (b.type === 'tree' ? '/' : '')), + ), + ); + const bytes = Buffer.concat( + rows.flatMap((row) => [ + Buffer.from(`${row.mode.replace(/^0/u, '')} ${row.path}\0`), + Buffer.from(row.sha, 'hex'), + ]), + ); + const sha = gitHash('tree', bytes); + trees.set(sha, { sha, tree: rows, truncated: false }); + return sha; + }; + return { tree: visit(root), trees, blobs }; +} +async function writerFixture(run) { + mkdirSync(path.join(ROOT, 'target'), { recursive: true }); + const directory = mkdtempSync(path.join(ROOT, 'target/completed-swift-delivery-')); + try { + const inputs = path.join(directory, 'inputs'); + mkdirSync(inputs); + const spec = await swiftInputs(inputs); + spec.version = '0.8.2'; + writeFileSync(spec.sources.VERSION, `${spec.version}\n`); + const bindings = path.join(inputs, `oliphaunt-swift-${spec.version}-bindings.xcframework.zip`); + copyFileSync(spec.bindingsArchive, bindings); + spec.bindingsArchive = bindings; + const output = path.join(directory, 'source_package'); + await packageSwiftSource(output, spec); + const tree = path.join(output, 'release-tree'); + const files = new Map( + readSwiftSourceTagMembers(tree) + .filter(({ type }) => type === 'file') + .map((row) => [ + row.path, + { + bytes: readFileSync(path.join(tree, row.path)), + mode: row.mode === 0o755 ? '100755' : '100644', + }, + ]), + ); + const objects = gitObjects(files); + const source = { + ...structuredClone(captured), + commit: { ...structuredClone(captured.commit), tree: { sha: objects.tree } }, + }; + const contents = (member) => blob(files.get(member).bytes, member); + const options = transport( + source, + contents, + (sha) => objects.trees.get(sha), + (sha) => objects.blobs.get(sha), + JSON.parse(readFileSync(spec.carrier, 'utf8')), + ); + const basis = await createPublishedNativeLegalSourceBasis({ + nativeVersion: spec.nativeVersion, + swiftVersion: spec.version, + ...options, + }); + const assets = path.join(directory, 'release-assets'); + mkdirSync(assets); + copyFileSync(bindings, path.join(assets, path.basename(bindings))); + writeFileSync( + path.join(assets, `oliphaunt-swift-${spec.version}-release-assets.sha256`), + `${hash(readFileSync(bindings))} ./${path.basename(bindings)}\n`, + ); + const candidate = () => ({ + ...buildPublicationCandidate({ + products: ['oliphaunt-swift'], + artifactRoots: [output, assets], + nativeSourceBasis: basis, + }), + scope: 'construction', + }); + await run({ + directory, + spec, + tree, + files, + objects, + source, + options, + candidate, + input: { + publication: source.publication, + descriptor, + bindings: { name: path.basename(bindings), sha256: hash(readFileSync(bindings)) }, + }, + }); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +} + +test('actual source writer and existing comparison bind the complete physical tree to the installed ZIP', async () => + writerFixture(async (f) => { + const candidate = f.candidate(); + const before = await captureCompletedSwiftSourceTag(f.input, f.options); + expect( + differentNativeDeliveredMembers(before.members, currentSwiftSourceTagMembers(candidate)), + ).toEqual([]); + const product = candidate.products[0]; + const publicRows = expectedProductArtifactRows([product]).filter( + ({ role }) => role === 'github-release-asset', + ); + const publishedFiles = Object.fromEntries( + publicRows.map((row) => [ + row.id, + candidate.productArtifacts.find(({ id }) => id === row.id).path, + ]), + ); + const pages = async (endpoint) => + endpoint.endsWith('/releases/82/assets') + ? publicRows.map((row, index) => { + const file = candidate.productArtifacts.find(({ id }) => id === row.id); + return { + id: 100 + index, + name: row.name, + url: `https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/${100 + index}`, + state: 'uploaded', + digest: `sha256:${file.sha256}`, + size: file.size, + }; + }) + : f.options.readPages(endpoint); + const result = await compareNativeCompletedPhysicalDelivery( + candidate, + [{ publication: f.source.publication, carriers: {}, productArtifacts: publishedFiles }], + { ...f.options, readPages: pages }, + ); + expect(result.products[0].unknowns).toEqual([]); + expect(result.products[0].deliveryStatus).toBe('identical'); + expect(result.products[0].comparisons.some(({ kind }) => kind === 'swiftpm-release-tree')).toBe( + true, + ); + expect(result.releaseDecision).toBe('unverified'); + const sourceFile = path.join(f.tree, `${prefix}/Sources/Oliphaunt/Oliphaunt.swift`); + let changed = false; + const readJson = async (endpoint) => { + if (endpoint.includes('/git/trees/') && !changed) { + changed = true; + writeFileSync(sourceFile, '// source changed during immutable historical API acquisition'); + } + return f.options.readJson(endpoint); + }; + await expect( + compareNativeCompletedPhysicalDelivery( + candidate, + [{ publication: f.source.publication, carriers: {}, productArtifacts: publishedFiles }], + { ...f.options, readPages: pages, readJson }, + ), + ).rejects.toThrow('frozen artifact bytes'); + })); + +for (const fault of ['removed', 'extra', 'changed', 'mode', 'symlink', 'version', 'supplier']) + test(`current physical Swift tree rejects ${fault} without treating the ZIP consumer as source-tag proof`, async () => + writerFixture(async (f) => { + const source = path.join(f.tree, `${prefix}/Sources/Oliphaunt/Oliphaunt.swift`); + if (fault === 'removed') rmSync(source); + if (fault === 'extra') + writeFileSync(path.join(path.dirname(source), 'extra.swift'), '// extra delivered source'); + if (fault === 'changed') writeFileSync(source, '// tree-only changed source'); + if (fault === 'mode') chmodSync(source, 0o755); + if (fault === 'symlink') { + rmSync(source); + symlinkSync(f.spec.generatedSwift, source); + } + if (fault === 'version') writeFileSync(path.join(f.tree, `${prefix}/VERSION`), '0.8.1\n'); + if (fault === 'supplier') + writeFileSync(path.join(f.tree, `${prefix}/LIBOLIPHAUNT_VERSION`), '0.3.2\n'); + expect(() => currentSwiftSourceTagMembers(f.candidate())).toThrow(); + })); + +test('matching executable ZIP/tree members still require an actual source publisher mode contract', async () => + writerFixture(async (f) => { + const member = 'Sources/Oliphaunt/Oliphaunt.swift'; + const packed = path.join(f.directory, 'extracted/package'); + const archive = path.join(f.directory, 'source_package/Oliphaunt-source.zip'); + extractPortableArchiveTree(archive, packed, 'package'); + chmodSync(path.join(packed, member), 0o755); + chmodSync(path.join(f.tree, prefix, member), 0o755); + writeFileSync(archive, await createDeterministicZip(packed, { keepParent: true })); + // The maintained parity contract accepts exact shared modes. The existing + // publisher still writes Git100644, so this separate mapping stays fail closed. + assertSwiftSourceDeliveryParity( + archive, + readSwiftSourceTagMembers(f.tree), + readFileSync(path.join(f.tree, 'Package.swift')), + ); + expect(() => currentSwiftSourceTagMembers(f.candidate())).toThrow('publisher mode contract'); + })); + +test('authentic Git symlink and changed delivered members cannot be erased by source-directory guessing', async () => + writerFixture(async (f) => { + const target = `${prefix}/Sources/Oliphaunt/Oliphaunt.swift`; + f.files.set(target, { bytes: Buffer.from('authentic tree source edit\n'), mode: '100644' }); + let objects = gitObjects(f.files); + const source = structuredClone(f.source); + source.commit.tree.sha = objects.tree; + const options = transport( + source, + (member) => blob(f.files.get(member).bytes, member), + (sha) => objects.trees.get(sha), + (sha) => objects.blobs.get(sha), + JSON.parse(readFileSync(f.spec.carrier, 'utf8')), + ); + const changed = await captureCompletedSwiftSourceTag( + { ...f.input, publication: source.publication }, + options, + ); + expect( + differentNativeDeliveredMembers(changed.members, currentSwiftSourceTagMembers(f.candidate())), + ).toEqual([target]); + const originalSource = readFileSync(path.join(f.tree, target)); + f.files.set(target, { bytes: originalSource, mode: '100755' }); + objects = gitObjects(f.files); + source.commit.tree.sha = objects.tree; + const changedMode = await captureCompletedSwiftSourceTag(f.input, options); + expect( + differentNativeDeliveredMembers( + changedMode.members, + currentSwiftSourceTagMembers(f.candidate()), + ), + ).toEqual([target]); + f.files.set(target, { bytes: originalSource, mode: '100644' }); + const extra = `${prefix}/Sources/Oliphaunt/retired.swift`; + f.files.set(extra, { + bytes: Buffer.from('actual historical delivered member\n'), + mode: '100644', + }); + objects = gitObjects(f.files); + source.commit.tree.sha = objects.tree; + const retired = await captureCompletedSwiftSourceTag(f.input, options); + expect( + differentNativeDeliveredMembers(retired.members, currentSwiftSourceTagMembers(f.candidate())), + ).toEqual([extra]); + f.files.set(target, { bytes: Buffer.from('../outside'), mode: '120000' }); + objects = gitObjects(f.files); + source.commit.tree.sha = objects.tree; + await expect(captureCompletedSwiftSourceTag(f.input, options)).rejects.toThrow( + 'regular member', + ); + })); + +test('retained completed Swift source archive preserves every immutable Git member and contains no invented version files', async () => { + const { input, options } = genuine(); + const directory = mkdtempSync('/tmp/swift-completed-retention-'); + try { + const file = path.join(directory, 'swift-source-tag-0.8.2.tar.gz'); + const result = await captureCompletedSwiftSourceTag( + { ...input, retainedArchive: file }, + options, + ); + expect(result.file?.path).toBe(file); + const extracted = path.join(directory, 'source'); + extractPortableArchiveTree(file, extracted); + const actual = readSwiftSourceTagMembers(extracted).sort((a, b) => + a.path.localeCompare(b.path), + ); + expect(actual).toEqual(result.members); + expect(actual.filter(({ type }) => type === 'file')).toHaveLength(29); + expect(actual.some(({ path }) => path === 'src/sdks/swift/LIBOLIPHAUNT_VERSION')).toBe(false); + expect(result.file?.sha256).toBe(hash(readFileSync(file))); + await expect( + captureCompletedSwiftSourceTag({ ...input, retainedArchive: file }, options), + ).rejects.toThrow('refusing to replace'); + expect(result.scope).toBe('construction'); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); +test('failed immutable Swift source proof retains no archive', async () => { + const { input, options } = genuine(); + const directory = mkdtempSync('/tmp/swift-completed-retention-'); + try { + const file = path.join(directory, 'swift-source-tag-0.8.2.tar.gz'); + await expect( + captureCompletedSwiftSourceTag( + { + ...input, + bindings: { ...input.bindings, sha256: 'f'.repeat(64) }, + retainedArchive: file, + }, + options, + ), + ).rejects.toThrow('manifest differs'); + expect(() => readFileSync(file)).toThrow(); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('completed source replay rechecks the entire Git-delivered archive and exact source reference', async () => { + const { input, options } = genuine(); + const directory = mkdtempSync('/tmp/swift-completed-replay-'); + try { + const result = await captureCompletedSwiftSourceTag( + { ...input, retainedArchive: path.join(directory, 'source.tar.gz') }, + options, + ); + const replay = await replayCompletedSwiftSourceArchive( + { ...input, source: result.source, file: result.file! }, + options, + ); + expect(replay.members).toEqual(result.members); + await expect( + replayCompletedSwiftSourceArchive( + { ...input, source: { ...result.source, tree: 'f'.repeat(40) }, file: result.file! }, + options, + ), + ).rejects.toThrow('source tag changed'); + const tree = path.join(directory, 'tree'); + extractPortableArchiveTree(result.file!.path, tree); + writeFileSync(path.join(tree, 'invented.txt'), 'extra'); + const { archiveDirectory } = await import('../packaging/archive-directory.mts'); + const extra = path.join(directory, 'extra.tar.gz'); + await archiveDirectory(tree, extra); + const { fileIdentity } = await import('./native-file-identity.mts'); + const identity = fileIdentity(extra); + await expect( + replayCompletedSwiftSourceArchive( + { + ...input, + source: result.source, + file: { path: extra, size: identity.size, sha256: identity.sha256 }, + }, + options, + ), + ).rejects.toThrow('archive member differs'); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('completed supplier source replay shares the actual public binding and validates full Git members', async () => + writerFixture(async (f) => { + const capturedSource = await captureCompletedSwiftSourceTag( + { + ...f.input, + retainedArchive: path.join(f.directory, 'source.tar.gz'), + }, + f.options, + ); + const binding = path.join(f.directory, 'release-assets', f.input.bindings.name); + const file = { + path: capturedSource.file!.path, + size: capturedSource.file!.size, + sha256: capturedSource.file!.sha256, + }; + const sourceRow = { + publication: f.input.publication, + artifact: `swift-source-tag:${f.input.publication.version}`, + source: capturedSource.source, + file, + }; + const product = f.candidate().products[0]; + const publicRows = expectedProductArtifactRows([product]).filter( + ({ role }) => role === 'github-release-asset' || role === 'github-release-metadata', + ); + const bindingRow = publicRows.find(({ kind }) => kind === 'swift-bindings')!; + let bindingReads = 0; + const originalPages = f.options.readPages; + const options = { + ...f.options, + readPages: async (endpoint) => { + if (endpoint !== `${repository}/releases/82/assets`) return originalPages(endpoint); + bindingReads++; + return publicRows.map((row, index) => ({ + id: index + 1, + name: row.name, + state: 'uploaded', + url: `https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/${index + 1}`, + size: row.id === bindingRow.id ? readFileSync(binding).length : 1, + digest: `sha256:${row.id === bindingRow.id ? hash(readFileSync(binding)) : '1'.repeat(64)}`, + })); + }, + }; + const input = { + publication: f.input.publication, + files: { [bindingRow.id]: binding }, + sourceTags: [sourceRow], + }; + const result = await captureCompletedNativeSwiftSourceSuppliers(input, options); + const sourceArchive = result.archives.find(({ id }) => id === sourceRow.artifact)!; + expect(sourceArchive.members).toEqual(capturedSource.members); + expect(sourceArchive.target).toBe('portable'); + expect(sourceArchive.size).toBe(file.size); + expect(sourceArchive.sha256).toBe(file.sha256); + expect(bindingReads).toBe(1); + expect(result.scope).toBe('construction'); + await expect( + captureCompletedNativeSwiftSourceSuppliers({ ...input, files: {} }, options), + ).rejects.toThrow('authenticated binding archive'); + await expect( + captureCompletedNativeSwiftSourceSuppliers( + { + ...input, + sourceTags: [{ ...sourceRow, source: { ...sourceRow.source, commit: 'f'.repeat(40) } }], + }, + options, + ), + ).rejects.toThrow('source tag changed'); + await expect( + captureCompletedNativeSwiftSourceSuppliers( + { ...input, sourceTags: [{ ...sourceRow, file: { ...file, sha256: '0'.repeat(64) } }] }, + options, + ), + ).rejects.toThrow('archive bytes differ'); + })); diff --git a/tools/release/consumer-compatibility.mts b/tools/release/consumer-compatibility.mts index 91f49f186..3b1442565 100644 --- a/tools/release/consumer-compatibility.mts +++ b/tools/release/consumer-compatibility.mts @@ -1,5 +1,5 @@ import { requireMatchingWasixRuntime } from './compatibility-version-policy.mts'; -import { buildBoundCompatibilityProducts } from './release-dependency-plan.mts'; +import { resolveBuildBoundCompatibilityProducts } from './release-dependency-plan.mts'; import { compareText, loadProducts, productCompatibilityVersion } from './release-graph.mts'; const EXTENSION_RUNTIMES = new Set(['liboliphaunt-native', 'liboliphaunt-wasix']); @@ -68,15 +68,13 @@ export function validateConsumerContractCoverage(products) { extensionConsumerContracts(products); } -export function validateReleaseConsumerCompatibility( - selectedProducts, - { +export function validateReleaseConsumerCompatibility(selectedProducts, options = {}) { + const { products = loadProducts(), readCompatibility = productCompatibilityVersion, - buildBound = buildBoundCompatibilityProducts(products), prefix = 'release-consumer-compatibility', - } = {}, -) { + } = options; + const buildBound = resolveBuildBoundCompatibilityProducts(products, options); validateConsumerContractCoverage(products); const selected = new Set(selectedProducts); for (const id of selected) { diff --git a/tools/release/consumer-compatibility.test.mts b/tools/release/consumer-compatibility.test.mts index b88925ac3..89f838080 100644 --- a/tools/release/consumer-compatibility.test.mts +++ b/tools/release/consumer-compatibility.test.mts @@ -13,6 +13,16 @@ test('compatible independent products pass without coupling their packaging vers ).not.toThrow(); }); +test('consumer admission rejects missing supplier coverage before reading published requirements', () => { + const state = fixture(); + for (const buildBound of [undefined, new Map(), new Map([['foreign', new Set()]])]) { + expect(() => + validateReleaseConsumerCompatibility(['oliphaunt-wasix-ts'], { ...state, buildBound }), + ).toThrow('buildBound'); + expect(state.reads).toEqual([]); + } +}); + test('source qualification cannot substitute a newer workspace addon for a published carrier', () => { const state = fixture(); state.published['oliphaunt-wasix-napi']['liboliphaunt-wasix'] = '0.3.0'; @@ -135,9 +145,8 @@ test('compiled SDK sources follow the binary closure while installed addon consu expect(() => validateReleaseConsumerCompatibility(selected, state)).toThrow( 'oliphaunt-wasix-napi targets liboliphaunt-wasix@0.3.2', ); - const buildBound = new Map([ - ['oliphaunt-wasix-napi', new Set(['oliphaunt-wasix-rust', 'liboliphaunt-wasix'])], - ]); + const buildBound = new Map(Object.keys(state.products).map((id) => [id, new Set()])); + buildBound.set('oliphaunt-wasix-napi', new Set(['oliphaunt-wasix-rust', 'liboliphaunt-wasix'])); expect(() => validateReleaseConsumerCompatibility(selected, { ...state, buildBound }), ).not.toThrow(); diff --git a/tools/release/default-extension-release-plan.mts b/tools/release/default-extension-release-plan.mts index 36b9bb814..63b3997fd 100644 --- a/tools/release/default-extension-release-plan.mts +++ b/tools/release/default-extension-release-plan.mts @@ -1,17 +1,52 @@ import { extensionConsumerRequirements } from './consumer-compatibility.mts'; -import { buildBoundCompatibilityProducts } from './release-dependency-plan.mts'; +import { resolveBuildBoundCompatibilityProducts } from './release-dependency-plan.mts'; import { productCompatibilityVersion } from './release-graph.mts'; +// These associations are controller-derived contracts, not a release selector. +// Authentication and descriptor/module equivalence stay with the acquired observations. +export function snapshotCurrentExactInputs(products, value = []) { + if (!Array.isArray(value)) + throw new Error('default-extension-release-plan: current exact inputs must be an array'); + const seen = new Set(); + return Object.freeze( + value.map((row) => { + if ( + !row || + typeof row !== 'object' || + Array.isArray(row) || + Object.keys(row).sort().join(',') !== 'product,sourceProduct' || + typeof row.product !== 'string' || + typeof row.sourceProduct !== 'string' || + !Object.hasOwn(products, row.product) || + !Object.hasOwn(products, row.sourceProduct) || + row.product === row.sourceProduct || + !Object.values(products[row.product].compatibility_versions ?? {}).some( + (entry) => entry.source_product === row.sourceProduct, + ) + ) + throw new Error( + 'default-extension-release-plan: current exact input lacks its conventional requirement', + ); + const key = `${row.product}:${row.sourceProduct}`; + if (seen.has(key)) + throw new Error('default-extension-release-plan: duplicate current exact input'); + seen.add(key); + return Object.freeze({ product: row.product, sourceProduct: row.sourceProduct }); + }), + ); +} + // Default installs constrain dependency requirements, not product version numbers. -export function defaultExtensionReleasePlan( - products, - selectedProducts, - { - readCompatibility = productCompatibilityVersion, - buildBound = buildBoundCompatibilityProducts(products), - } = {}, -) { +export function defaultExtensionReleasePlan(products, selectedProducts, options = {}) { + const { readCompatibility = productCompatibilityVersion } = options; + const buildBound = resolveBuildBoundCompatibilityProducts(products, options); + const currentExactInputs = snapshotCurrentExactInputs(products, options.currentExactInputs); const selected = new Set(selectedProducts); + const currentContracts = new Set( + currentExactInputs + .filter(({ product, sourceProduct }) => selected.has(product) && selected.has(sourceProduct)) + .map(({ product, sourceProduct }) => `${product}:${sourceProduct}`), + ); const required = new Set(selected); const requirements = new Map(); const extensions = Object.keys(products).filter( @@ -34,7 +69,7 @@ export function defaultExtensionReleasePlan( products, pin, buildBound, - ).filter(({ product, owner }) => !owner || products[owner].kind === 'sdk'); + ).filter(({ owner }) => !owner || products[owner].kind === 'sdk'); const runtimes = new Set(selectedConsumers.map(({ runtime }) => runtime)); if (extensions.some((product) => selected.has(product))) { for (const product of sdks) { @@ -44,8 +79,14 @@ export function defaultExtensionReleasePlan( } const maximum = (versions) => versions.sort(Bun.semver.order).at(-1); for (const runtime of runtimes) { + const requiredCurrentHost = extensions.some((product) => + currentContracts.has(`${product}:${runtime}`), + ); const hosts = extensions.map((product) => - selected.has(product) ? products[runtime].version : pin(product, runtime), + (selected.has(product) && buildBound.get(product).has(runtime)) || + currentContracts.has(`${product}:${runtime}`) + ? products[runtime].version + : pin(product, runtime), ); let target = maximum([ ...hosts, @@ -59,9 +100,29 @@ export function defaultExtensionReleasePlan( ); const repackage = hosts.some((host) => host !== target); if (repackage) { - // Extension producers cannot recreate an older host with current compiler inputs. - target = products[runtime].version; + // Only current compiler inputs force adoption of the workspace host. + if ( + extensions.some( + (product) => buildBound.get(product).has(runtime) && pin(product, runtime) !== target, + ) + ) + target = products[runtime].version; for (const product of extensions) { + if ( + !buildBound.get(product).has(runtime) && + readCompatibility(product, runtime, 'default-extension-release-plan', { ref: null }) !== + target + ) { + // A proven missing ABI export can require a new exact default host. + // Propose the conventional requirements together; final qualification + // must still execute every affected carrier on that exact host. + if (requiredCurrentHost && target === products[runtime].version) + writeRequirement(product, runtime, target); + else + throw new Error( + `default-extension-release-plan: ${product} retains a held ${runtime} requirement; update its conventional runtime requirement before targeting ${runtime}@${target}`, + ); + } if (pin(product, runtime) !== target || selected.has(product)) required.add(product); } } @@ -88,13 +149,19 @@ export function defaultExtensionReleasePlan( const target = requirements.get(`${sdk}:${runtime}`)?.version ?? pin(sdk, runtime); const addon = 'oliphaunt-wasix-napi'; const version = pin(sdk, addon); + const buildsRuntime = buildBound.get(addon)?.has(runtime); const currentHost = - selected.has(addon) && version === products[addon].version + buildsRuntime && selected.has(addon) && version === products[addon].version ? products[runtime].version : pin(addon, runtime, version); if (currentHost !== target) { - const host = selected.has(addon) ? products[runtime].version : pin(addon, runtime); + const host = + buildsRuntime && selected.has(addon) ? products[runtime].version : pin(addon, runtime); if (host !== target) { + if (!buildsRuntime) + throw new Error( + `default-extension-release-plan: ${addon} adopts ${runtime}@${host}; update its conventional runtime and SDK requirements before targeting ${runtime}@${target}`, + ); if (target !== products[runtime].version) throw new Error( `default-extension-release-plan: ${addon} cannot embed older ${runtime}@${target}`, @@ -122,5 +189,16 @@ export function defaultExtensionReleasePlan( if (oldHost !== target) writeRequirement(owner, provider, products[provider].version); } } + // A byte-qualified exact-module contract follows a new producer only when + // both products already have necessary deliveries. ABI reachability alone + // never adds a producer or consumer to the release set. + for (const { product, sourceProduct } of currentExactInputs) { + if (!selected.has(product) || !selected.has(sourceProduct)) continue; + const version = products[sourceProduct].version; + const previous = requirements.get(`${product}:${sourceProduct}`); + if (previous && previous.version !== version) + throw new Error('default-extension-release-plan: conflicting current exact requirement'); + if (pin(product, sourceProduct) !== version) writeRequirement(product, sourceProduct, version); + } return { required, requirements }; } diff --git a/tools/release/default-extension-release-plan.test.mts b/tools/release/default-extension-release-plan.test.mts index d0f5040ad..e9da0acea 100644 --- a/tools/release/default-extension-release-plan.test.mts +++ b/tools/release/default-extension-release-plan.test.mts @@ -1,6 +1,10 @@ import { expect, test } from 'bun:test'; import { validateReleaseConsumerCompatibility } from './consumer-compatibility.mts'; -import { defaultExtensionReleasePlan } from './default-extension-release-plan.mts'; +import { + defaultExtensionReleasePlan, + snapshotCurrentExactInputs, +} from './default-extension-release-plan.mts'; +import { loadProducts } from './release-graph.mts'; import { fixture } from './testdata/extension-release-fixture.mts'; const native = 'liboliphaunt-native'; @@ -59,6 +63,62 @@ test('runtime-only, SDK-only and compatible extension updates retain independent } }); +test('a supplied held extension host does not adopt an unrelated newer workspace runtime', () => { + const state = fixture(); + advance(state.products[native]); + advance(state.products[wasix]); + const buildBound = new Map(Object.keys(state.products).map((id) => [id, new Set()])); + const before = structuredClone({ products: state.products, pins: state.pins }); + const plan = defaultExtensionReleasePlan(state.products, [extension], { ...state, buildBound }); + expect([...plan.required]).toEqual([extension]); + expect(plan.requirements.size).toBe(0); + expect({ products: state.products, pins: state.pins }).toEqual(before); + expect(() => + validateReleaseConsumerCompatibility([extension], { ...state, buildBound }), + ).not.toThrow(); + + buildBound.get(extension).add(native); + const current = defaultExtensionReleasePlan(state.products, [extension], { + ...state, + buildBound, + }); + expect(current.requirements.get(`oliphaunt-js:${native}`).version).toBe( + state.products[native].version, + ); +}); + +test('conflicting held extension suppliers reject before synthetic host adoption', () => { + const state = fixture(); + const second = 'oliphaunt-extension-pg-hashids'; + state.products[second] = { + ...structuredClone(state.products[extension]), + tag_prefix: `${second}-v`, + }; + state.pins[second] = structuredClone(state.pins[extension]); + state.published[second] = structuredClone(state.pins[extension]); + advance(state.products[native]); + const buildBound = new Map(Object.keys(state.products).map((id) => [id, new Set()])); + buildBound.get(extension).add(native); + const before = structuredClone({ products: state.products, pins: state.pins }); + expect(() => + defaultExtensionReleasePlan(state.products, [extension], { ...state, buildBound }), + ).toThrow('update its conventional runtime requirement'); + expect({ products: state.products, pins: state.pins }).toEqual(before); + + // A source adoption can deliberately use a published host older than the + // unrelated workspace host; an empty map must not silently replace it. + advance(state.products[native]); + state.pins[extension][native] = '0.3.2'; + state.pins[second][native] = '0.3.2'; + buildBound.get(extension).clear(); + const adopted = defaultExtensionReleasePlan(state.products, [extension], { + ...state, + buildBound, + }); + expect(adopted.required.has(second)).toBe(true); + expect(adopted.requirements.get(`oliphaunt-js:${native}`).version).toBe('0.3.2'); +}); + test('a native host change selects exactly the required default SDK and wrapper updates', () => { const state = fixture(); advance(state.products[native]); @@ -79,6 +139,48 @@ test('a native host change selects exactly the required default SDK and wrapper ); }); +test('default native SDK adoption preserves independently held dynamic helpers', () => { + const state = fixture(); + for (const [id, version] of [ + ['oliphaunt-node-direct', '0.2.2'], + ['oliphaunt-broker', '0.3.1'], + ]) { + state.products[id] = { + version, + kind: 'runtime', + tag_prefix: `${id}-v`, + compatibility_versions: { + host: { source_product: native, public_support: false }, + }, + }; + state.pins[id] = { [native]: state.products[native].version }; + state.published[id] = structuredClone(state.pins[id]); + state.pins['oliphaunt-js'][id] = version; + state.published['oliphaunt-js'][id] = version; + state.products['oliphaunt-js'].compatibility_versions[id] = { + source_product: id, + public_support: false, + }; + } + advance(state.products[native]); + // The selected extension deliberately adopts an already published new host. + // Its ABI supplier map does not falsely turn dynamically loaded helpers into + // consumers that embed the current runtime. + state.pins[extension][native] = state.products[native].version; + const buildBound = new Map(Object.keys(state.products).map((id) => [id, new Set()])); + const before = structuredClone({ products: state.products, pins: state.pins }); + const plan = defaultExtensionReleasePlan(state.products, [extension], { ...state, buildBound }); + expect(plan.requirements.get(`oliphaunt-js:${native}`).version).toBe( + state.products[native].version, + ); + for (const helper of ['oliphaunt-node-direct', 'oliphaunt-broker']) { + expect(plan.required.has(helper)).toBe(false); + expect(plan.requirements.has(`oliphaunt-js:${helper}`)).toBe(false); + expect(state.pins['oliphaunt-js'][helper]).toBe(before.pins['oliphaunt-js'][helper]); + } + expect({ products: state.products, pins: state.pins }).toEqual(before); +}); + test('a WASIX host change selects a matching addon instead of substituting workspace bytes', () => { const state = fixture(); advance(state.products[wasix]); @@ -103,6 +205,19 @@ test('an existing compatible addon and historical platform SDKs avoid unnecessar expect(state.pins['oliphaunt-wasix-ts']['oliphaunt-wasix-napi']).toBe('0.2.1'); }); +test('a held registry addon cannot acquire a new runtime merely by selecting its product', () => { + for (const selected of [[extension], [extension, 'oliphaunt-wasix-napi']]) { + const state = fixture(); + delete state.products['oliphaunt-wasix-napi'].embedded_payload_products; + advance(state.products[wasix]); + const before = structuredClone({ products: state.products, pins: state.pins }); + expect(() => defaultExtensionReleasePlan(state.products, selected, state)).toThrow( + 'update its conventional runtime and SDK requirements', + ); + expect({ products: state.products, pins: state.pins }).toEqual(before); + } +}); + test('authored requirements beyond available producer versions fail before candidate application', () => { const state = fixture(); state.pins['oliphaunt-js'][native] = '9.0.0'; @@ -151,3 +266,69 @@ test('500 seeded sparse and broad releases close compatible defaults and preserv } } }, 30_000); + +// Physical module/descriptor authentication is the controller precondition; +// these tests exercise only the one frozen requirements/RP seam. +test('verified exact-module contracts retarget only necessary selected consumers and producers', () => { + const products = loadProducts('exact current requirement test'); + const product = 'database-resources', + sourceProduct = 'liboliphaunt-wasix'; + const buildBound = new Map(Object.keys(products).map((id) => [id, new Set()])); + const readCompatibility = () => '0.3.2'; + products[sourceProduct].version = '0.3.4'; + const currentExactInputs = [{ product, sourceProduct }]; + const before = structuredClone(products); + for (const selected of [[], [sourceProduct], [product]]) { + const plan = defaultExtensionReleasePlan(products, selected, { + buildBound, + readCompatibility, + currentExactInputs, + }); + expect([...plan.required]).toEqual(selected); + expect(plan.requirements.size).toBe(0); + } + const selected = [sourceProduct, product]; + const planned = defaultExtensionReleasePlan(products, selected, { + buildBound, + readCompatibility, + currentExactInputs, + }); + expect([...planned.required]).toEqual(selected); + expect([...planned.requirements.values()]).toEqual([ + { product, sourceProduct, version: '0.3.4' }, + ]); + expect(buildBound.get(product).size).toBe(0); + expect(products).toEqual(before); + const same = defaultExtensionReleasePlan(products, selected, { + buildBound, + readCompatibility: () => '0.3.4', + currentExactInputs, + }); + expect(same.requirements.size).toBe(0); +}); + +test('current exact associations are immutable, conventional, unique and cannot select releases', () => { + const products = loadProducts('exact current requirement negative'); + const pair = { product: 'database-resources', sourceProduct: 'liboliphaunt-wasix' }; + const input = [pair]; + const snapshot = snapshotCurrentExactInputs(products, input); + pair.sourceProduct = 'liboliphaunt-native'; + input.push({ product: 'foreign', sourceProduct: 'foreign' }); + expect(snapshot).toEqual([ + { product: 'database-resources', sourceProduct: 'liboliphaunt-wasix' }, + ]); + expect(Object.isFrozen(snapshot)).toBe(true); + expect(Object.isFrozen(snapshot[0])).toBe(true); + for (const invalid of [ + null, + {}, + [null], + [{ ...snapshot[0], version: '0.3.4' }], + [{ product: 'foreign', sourceProduct: 'liboliphaunt-wasix' }], + [{ product: 'database-resources', sourceProduct: 'database-resources' }], + [{ product: 'database-resources', sourceProduct: 'oliphaunt-query' }], + [...snapshot, ...snapshot], + ]) { + expect(() => snapshotCurrentExactInputs(products, invalid)).toThrow(); + } +}); diff --git a/tools/release/download-build-artifacts.test.mts b/tools/release/download-build-artifacts.test.mts index ab3efa80d..941fd46db 100644 --- a/tools/release/download-build-artifacts.test.mts +++ b/tools/release/download-build-artifacts.test.mts @@ -29,6 +29,44 @@ if (mode === 'prepare') { duplicate: [artifact, artifact], })) writeFileSync(path.join(root, `${name}.json`), JSON.stringify(value)); + if (kind === 'pending-snapshot') { + mkdirSync(path.join(root, 'snapshots')); + writeFileSync( + path.join(root, 'snapshots/run-77.json'), + JSON.stringify({ + schema: 'oliphaunt-github-actions-run-snapshot-v1', + repo: 'f0rr0/oliphaunt', + runId: '77', + headSha: 'a'.repeat(40), + headTree: 'b'.repeat(40), + workflowId: 9, + workflowName: 'CI', + workflowPath: '.github/workflows/ci.yml', + runWorkflowPath: '.github/workflows/ci.yml', + event: 'workflow_dispatch', + headBranch: 'main', + pullRequestNumbers: [], + runAttempt: 1, + status: 'in_progress', + conclusion: null, + jobs: [ + { + id: 501, + run_id: 77, + head_sha: 'a'.repeat(40), + name: 'Qualified', + run_attempt: 1, + status: 'in_progress', + conclusion: null, + created_at: '2026-10-11T00:59:59Z', + started_at: '2026-10-11T01:00:00Z', + completed_at: null, + }, + ], + artifacts: [], + }), + ); + } } else if (mode === 'assert') { assert.deepEqual( readdirSync(root).filter( @@ -37,12 +75,29 @@ if (mode === 'prepare') { [], ); assert.equal(existsSync(path.join(root, 'durable/partial.txt')), false); - if (kind === 'snapshot' || kind === 'pagination') { + if (kind === 'snapshot' || kind === 'pagination' || kind.startsWith('producer:')) { const endpoints = readFileSync(path.join(root, 'gh.log'), 'utf8') .trim() .split(/\r?\n/u) .map(JSON.parse); - if (kind === 'pagination') + if (kind.startsWith('producer:')) { + const [, reads, downloads, accepted] = kind.split(':'); + assert.equal( + endpoints.filter((endpoint) => /actions\/runs\/77$/u.test(endpoint)).length, + Number(reads), + ); + assert.equal( + endpoints.filter((endpoint) => /actions\/artifacts\/101\/zip$/u.test(endpoint)).length, + Number(downloads), + ); + if (accepted) { + const snapshot = JSON.parse(readFileSync(path.join(root, 'snapshots/run-77.json'), 'utf8')); + assert.equal(snapshot.jobs[0].status, 'completed'); + assert.equal(snapshot.jobs[0].conclusion, 'success'); + assert.equal(snapshot.artifacts[0].id, 101); + assert.equal(snapshot.artifacts[0].head_sha, 'a'.repeat(40)); + } + } else if (kind === 'pagination') assert.equal( endpoints.filter((endpoint) => endpoint.includes('/actions/workflows/9/runs?')).length, 2, diff --git a/tools/release/download-build-artifacts.test.sh b/tools/release/download-build-artifacts.test.sh index a38f60fb1..9a3871e04 100644 --- a/tools/release/download-build-artifacts.test.sh +++ b/tools/release/download-build-artifacts.test.sh @@ -18,10 +18,13 @@ invoke() { TMPDIR="$case_root" FAKE_ARTIFACT_ARCHIVE="$case_root/artifact.zip" \ FAKE_GH_LOG="$case_root/gh.log" FAKE_GH_STATE="$case_root/state" FAKE_MODE="$mode" \ FAKE_CANDIDATE_MODE="${candidate_mode:-}" FAKE_DUPLICATE_JOB="${duplicate_job:-}" \ + FAKE_JOB_CASE="${job_case:-}" \ FAKE_RUN_STATUS="${run_status:-completed}" FAKE_RUN_CONCLUSION="${run_conclusion-success}" \ GH_REPO=f0rr0/oliphaunt GH_TOKEN=test-token \ OLIPHAUNT_GITHUB_RUN_SNAPSHOT_DIR="$case_root/snapshots" \ OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS=0 OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS=0 \ + OLIPHAUNT_GITHUB_READ_DEADLINE_MS="${read_deadline:-300000}" \ + OLIPHAUNT_GITHUB_READ_MAX_ATTEMPTS="${read_attempts:-10}" \ bash .github/scripts/download-build-artifacts.sh CI "${requested_sha:-$sha}" "$case_root/durable" \ --job Qualified --artifact exact-artifact "$@" > "$case_root/result" 2>&1 } @@ -64,6 +67,49 @@ prepare snapshot invoke success --run-id 77 invoke success --run-id 77 clean snapshot +# Only a pending exact producer may converge; its immutable identity remains pinned. +producer=(--run-id 77 --job-success-only --workflow-path .github/workflows/ci.yml + --event workflow_dispatch --ref refs/heads/main --source-tree bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) +prepare producer-success +job_case=pending-success invoke success "${producer[@]}" +invoke success "${producer[@]}" +clean producer:2:2:accepted +prepare producer-cached pending-snapshot +job_case=cached-success invoke success "${producer[@]}" +clean producer:1:1:accepted +prepare producer-shared-cache +job_case=cache-other-pending invoke success "${producer[@]}" +job_case=cache-other-success invoke success "${producer[@]}" --job 'Second producer' +clean producer:2:2:accepted +prepare producer-immediate +# An unrelated failed workflow must not disqualify the successful requested role. +run_conclusion=failure invoke success "${producer[@]}" --run-attempt 1 --job-attempt 1 +clean producer:1:1:accepted +for fault in failure cancelled missing event; do + prepare "producer-$fault" + job_case="$fault" reject 1 'does not satisfy required job|missing required job|event mismatch' success "${producer[@]}" + [[ ! -e "$case_root/durable" && ! -e "$case_root/state" ]] + clean producer:1:0 +done +prepare producer-duplicate +job_case=pending-success duplicate_job=true reject 1 'ambiguous latest executions' success "${producer[@]}" +clean producer:1:0 +prepare producer-wrong-attempt +job_case=pending-success reject 1 'producing job attempt mismatch' success "${producer[@]}" --job-attempt 2 +clean producer:1:0 +for fault in failure source-drift producer-drift rerun-drift 404; do + prepare "producer-pending-$fault" + job_case="pending-$fault" reject 1 'does not satisfy required job|does not belong to commit|identity changed|HTTP 404' success "${producer[@]}" + [[ ! -e "$case_root/durable" && ! -e "$case_root/state" ]] + clean producer:2:0 +done +prepare producer-timeout +job_case=pending-timeout read_attempts=3 reject 1 'retry budget exhausted after 3 attempt' success "${producer[@]}" +clean producer:3:0 +prepare producer-deadline +# A larger ambient HTTP deadline must not expand the five-minute readiness cap. +job_case=pending-deadline read_deadline=3600000 reject 1 'deadline (exhausted|expired)' success "${producer[@]}" +clean producer:2:0 prepare pagination candidate_mode=beyond-first-page invoke success [[ "$(cat "$case_root/durable/payload.txt")" == correct ]] @@ -76,7 +122,7 @@ for status in in_progress completed; do [[ ! -e "$case_root/durable" && ! -e "$case_root/state" ]] done prepare duplicate-job -duplicate_job=true reject 1 'does not satisfy required job Qualified' success --run-id 77 +duplicate_job=true reject 1 'job Qualified has ambiguous latest executions' success --run-id 77 [[ ! -e "$case_root/durable" && ! -e "$case_root/state" ]] for kind in traversal corrupt; do prepare "$kind" "$kind" diff --git a/tools/release/example-cargo-versions.mts b/tools/release/example-cargo-versions.mts index a8483fc6f..cee776d70 100644 --- a/tools/release/example-cargo-versions.mts +++ b/tools/release/example-cargo-versions.mts @@ -1,4 +1,5 @@ import { readFileSync } from 'node:fs'; +import { loadReleaseMetadata } from './bazel-release-metadata.mts'; import path from 'node:path'; import { loadPublicationCatalog, resolveActualCarrier } from './publication-catalog.mts'; import { productCompatibilityVersion, ROOT } from './release-graph.mts'; @@ -56,6 +57,7 @@ export function exampleCargoPolicies() { export function exampleCargoReleaseVersionBindings() { const catalog = loadPublicationCatalog(TOOL); + const installed = loadReleaseMetadata(ROOT).products; const initialVersion = JSON.parse( readFileSync(path.join(ROOT, 'release-please-config.json'), 'utf8'), )['initial-version']; @@ -76,11 +78,14 @@ export function exampleCargoReleaseVersionBindings() { runtimeVersion && (carrier.product === policy.runtime.product || carrier.product === 'oliphaunt-extension-contrib-pg18'); - const followsBroker = sdk === 'oliphaunt-rust' && carrier.product === 'oliphaunt-broker'; + const followsBroker = + sdk === 'oliphaunt-rust' && + carrier.product === 'oliphaunt-broker' && + carrier.target !== null; const version = followsRuntime ? runtimeVersion : followsBroker - ? productCompatibilityVersion(sdk, 'oliphaunt-broker', TOOL) + ? installed[sdk].compatibility_versions[carrier.product] : carrier.version; bindings.push({ kind: 'dependency', diff --git a/tools/release/extension-release-metadata.mts b/tools/release/extension-release-metadata.mts new file mode 100644 index 000000000..1442bb741 --- /dev/null +++ b/tools/release/extension-release-metadata.mts @@ -0,0 +1,107 @@ +export const EXTENSION_VERSIONING_BY_CLASS = { + contrib: 'runtime-bound', + external: 'upstream-bound', + 'first-party': 'repo-bound', +}; + +function string(value, context) { + if (typeof value !== 'string' || !value) throw new Error(`${context} must be a nonempty string`); + return value; +} + +export function extensionNpmPackageForProduct(product) { + if (typeof product !== 'string' || !product.startsWith('oliphaunt-extension-')) + throw new TypeError( + `extension product must start with oliphaunt-extension-: ${JSON.stringify(product)}`, + ); + return `@oliphaunt/${product.slice('oliphaunt-'.length)}`; +} + +export function extensionCompatibilityMetadata(compatibility) { + return Object.fromEntries( + [ + ['postgresMajor', 'postgres_major'], + ['extensionRuntimeContract', 'extension_runtime_contract'], + ['nativeRuntimeProduct', 'native_runtime_product'], + ['nativeRuntimeVersion', 'native_runtime_version'], + ['wasixRuntimeProduct', 'wasix_runtime_product'], + ['wasixRuntimeVersion', 'wasix_runtime_version'], + ].map(([key, authored]) => [ + key, + string(compatibility?.[authored], `extension.compatibility.${authored}`), + ]), + ); +} + +export function declaredExtensionMetadata(product, extension) { + const sqlName = string(extension.sql_name, `${product}.extension.sql_name`); + if (EXTENSION_VERSIONING_BY_CLASS[extension.class] !== extension.versioning) + throw new Error(`${product} has inconsistent extension class/versioning`); + return { + sqlName, + sqlNames: [sqlName], + artifactProduct: product, + class: extension.class, + versioning: extension.versioning, + sourcePath: string(extension.source?.path, `${product}.extension.source.path`), + compatibility: extensionCompatibilityMetadata(extension.compatibility), + }; +} + +export function contribExtensionMetadata({ artifactProduct, sourcePath, sqlNames, compatibility }) { + return { + sqlName: undefined, + sqlNames, + class: 'contrib', + versioning: 'runtime-bound', + sourcePath, + artifactProduct, + compatibility, + }; +} + +export function extensionSourceMetadata(product, metadata, source, version = undefined) { + if (metadata.class === 'contrib') + return { + kind: 'postgres-contrib', + name: 'postgresql', + ...Object.fromEntries( + ['version', 'url', 'sha256'].map((key) => [ + key, + string(source.postgresql?.[key], `${metadata.sourcePath}.postgresql.${key}`), + ]), + ), + }; + if (metadata.class === 'external') + return { + kind: 'external', + ...Object.fromEntries( + ['name', 'url', 'branch', 'commit'].map((key) => [ + key, + string(source[key], `${metadata.sourcePath}.${key}`), + ]), + ), + }; + if (metadata.class === 'first-party') + return { + kind: 'repo', + name: metadata.sqlName ?? product, + path: metadata.sourcePath, + version: string(version, `${product} release version`), + }; + throw new Error(`${product} has unsupported extension source class ${metadata.class}`); +} + +export function extensionPublicationMetadataRows(product, metadata, sourceIdentity, memberPath) { + return metadata.sqlNames.map((sqlName) => ({ + product, + cargoPackage: product, + npmPackage: extensionNpmPackageForProduct(product), + mavenGroup: 'dev.oliphaunt.extensions', + mavenArtifact: product, + ...metadata, + sqlName, + memberPath: memberPath(sqlName), + sourceIdentity, + })); +} diff --git a/tools/release/fixtures/aquery-bazel-8.8.1/.gitattributes b/tools/release/fixtures/aquery-bazel-8.8.1/.gitattributes new file mode 100644 index 000000000..df5fd0600 --- /dev/null +++ b/tools/release/fixtures/aquery-bazel-8.8.1/.gitattributes @@ -0,0 +1 @@ +*.pb binary diff --git a/tools/release/fixtures/aquery-bazel-8.8.1/aquery.json b/tools/release/fixtures/aquery-bazel-8.8.1/aquery.json new file mode 100644 index 000000000..cc593ae2b --- /dev/null +++ b/tools/release/fixtures/aquery-bazel-8.8.1/aquery.json @@ -0,0 +1,2162 @@ +{ + "artifacts": [{ + "id": 1, + "pathFragmentId": 1 + }, { + "id": 2, + "pathFragmentId": 8 + }, { + "id": 3, + "pathFragmentId": 9 + }, { + "id": 4, + "pathFragmentId": 14 + }, { + "id": 5, + "pathFragmentId": 16 + }, { + "id": 6, + "pathFragmentId": 17 + }, { + "id": 7, + "pathFragmentId": 18 + }, { + "id": 8, + "pathFragmentId": 19 + }, { + "id": 9, + "pathFragmentId": 22 + }, { + "id": 10, + "pathFragmentId": 23 + }, { + "id": 11, + "pathFragmentId": 26, + "isTreeArtifact": true + }, { + "id": 12, + "pathFragmentId": 28 + }, { + "id": 13, + "pathFragmentId": 30 + }, { + "id": 14, + "pathFragmentId": 31 + }, { + "id": 15, + "pathFragmentId": 34 + }, { + "id": 16, + "pathFragmentId": 35 + }, { + "id": 17, + "pathFragmentId": 36 + }, { + "id": 18, + "pathFragmentId": 37 + }, { + "id": 19, + "pathFragmentId": 39 + }, { + "id": 20, + "pathFragmentId": 42 + }, { + "id": 21, + "pathFragmentId": 46 + }, { + "id": 22, + "pathFragmentId": 47 + }, { + "id": 23, + "pathFragmentId": 53 + }, { + "id": 24, + "pathFragmentId": 54 + }, { + "id": 25, + "pathFragmentId": 55, + "isTreeArtifact": true + }, { + "id": 26, + "pathFragmentId": 56 + }, { + "id": 27, + "pathFragmentId": 57 + }, { + "id": 28, + "pathFragmentId": 64 + }, { + "id": 29, + "pathFragmentId": 65 + }, { + "id": 30, + "pathFragmentId": 66 + }, { + "id": 31, + "pathFragmentId": 68 + }, { + "id": 32, + "pathFragmentId": 71 + }, { + "id": 33, + "pathFragmentId": 72 + }, { + "id": 34, + "pathFragmentId": 73 + }, { + "id": 35, + "pathFragmentId": 75 + }, { + "id": 36, + "pathFragmentId": 78 + }, { + "id": 37, + "pathFragmentId": 79, + "isTreeArtifact": true + }, { + "id": 38, + "pathFragmentId": 81 + }, { + "id": 39, + "pathFragmentId": 82 + }, { + "id": 40, + "pathFragmentId": 85 + }, { + "id": 41, + "pathFragmentId": 86 + }, { + "id": 42, + "pathFragmentId": 87 + }, { + "id": 43, + "pathFragmentId": 88 + }, { + "id": 44, + "pathFragmentId": 90 + }, { + "id": 45, + "pathFragmentId": 91 + }, { + "id": 46, + "pathFragmentId": 92 + }, { + "id": 47, + "pathFragmentId": 93 + }, { + "id": 48, + "pathFragmentId": 94 + }, { + "id": 49, + "pathFragmentId": 95 + }, { + "id": 50, + "pathFragmentId": 96 + }, { + "id": 51, + "pathFragmentId": 97 + }, { + "id": 52, + "pathFragmentId": 99 + }, { + "id": 53, + "pathFragmentId": 101 + }, { + "id": 54, + "pathFragmentId": 102 + }, { + "id": 55, + "pathFragmentId": 103 + }, { + "id": 56, + "pathFragmentId": 104 + }, { + "id": 57, + "pathFragmentId": 105 + }, { + "id": 58, + "pathFragmentId": 106 + }, { + "id": 59, + "pathFragmentId": 109 + }, { + "id": 60, + "pathFragmentId": 110 + }, { + "id": 61, + "pathFragmentId": 111, + "isTreeArtifact": true + }, { + "id": 62, + "pathFragmentId": 117 + }, { + "id": 63, + "pathFragmentId": 119, + "isTreeArtifact": true + }, { + "id": 64, + "pathFragmentId": 122 + }, { + "id": 65, + "pathFragmentId": 123 + }, { + "id": 66, + "pathFragmentId": 125 + }, { + "id": 67, + "pathFragmentId": 99 + }, { + "id": 68, + "pathFragmentId": 101 + }, { + "id": 69, + "pathFragmentId": 126 + }, { + "id": 70, + "pathFragmentId": 127 + }, { + "id": 71, + "pathFragmentId": 105 + }, { + "id": 72, + "pathFragmentId": 128 + }, { + "id": 73, + "pathFragmentId": 129 + }, { + "id": 74, + "pathFragmentId": 133 + }, { + "id": 75, + "pathFragmentId": 135 + }, { + "id": 76, + "pathFragmentId": 136 + }, { + "id": 77, + "pathFragmentId": 138 + }, { + "id": 78, + "pathFragmentId": 139 + }, { + "id": 79, + "pathFragmentId": 141, + "isTreeArtifact": true + }, { + "id": 80, + "pathFragmentId": 145 + }, { + "id": 81, + "pathFragmentId": 146 + }, { + "id": 82, + "pathFragmentId": 147 + }, { + "id": 83, + "pathFragmentId": 148 + }, { + "id": 84, + "pathFragmentId": 150 + }, { + "id": 85, + "pathFragmentId": 155 + }, { + "id": 86, + "pathFragmentId": 157 + }, { + "id": 87, + "pathFragmentId": 158 + }, { + "id": 88, + "pathFragmentId": 159 + }, { + "id": 89, + "pathFragmentId": 160 + }, { + "id": 90, + "pathFragmentId": 161 + }, { + "id": 91, + "pathFragmentId": 162 + }, { + "id": 92, + "pathFragmentId": 163 + }, { + "id": 93, + "pathFragmentId": 165 + }, { + "id": 94, + "pathFragmentId": 166 + }, { + "id": 95, + "pathFragmentId": 167 + }, { + "id": 96, + "pathFragmentId": 168 + }, { + "id": 97, + "pathFragmentId": 170 + }, { + "id": 98, + "pathFragmentId": 172 + }, { + "id": 99, + "pathFragmentId": 174 + }, { + "id": 100, + "pathFragmentId": 178 + }, { + "id": 101, + "pathFragmentId": 180 + }, { + "id": 102, + "pathFragmentId": 182 + }, { + "id": 103, + "pathFragmentId": 183 + }, { + "id": 104, + "pathFragmentId": 185 + }], + "actions": [{ + "targetId": 1, + "actionKey": "3272d1fc1376fba8926b3f5deec5f9ce1bd682b6c45d38252fc7f5b545daae63", + "mnemonic": "FileWrite", + "configurationId": 1, + "outputIds": [1], + "primaryOutputId": 1, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 2, + "actionKey": "1b76ff913898d2090b4b9aad252df73f4f29c85df9eec6f34421575c00cf6810", + "mnemonic": "FileWrite", + "configurationId": 2, + "outputIds": [2], + "primaryOutputId": 2, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 2, + "actionKey": "784a5dc4f99b530faf423a9953d183a9c90b5828f320b7d2fddf304d14e670cd", + "mnemonic": "CopyToDirectory", + "configurationId": 2, + "environmentVariables": [{ + "key": "GODEBUG", + "value": "winsymlink\u003d0" + }], + "inputDepSetIds": [1], + "outputIds": [11], + "primaryOutputId": 11, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 2, + "actionKey": "7a39b61d5744a8903119e17b3ddc7e56e330f240d2bead98c3ba081a81b5c9ac", + "mnemonic": "ExecutableSymlink", + "configurationId": 2, + "inputDepSetIds": [3], + "outputIds": [13], + "primaryOutputId": 13, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 2, + "actionKey": "f4b635ed843c3a32b801874310b9103478bbd7a65f0284d8e84ba2fd34741dac", + "mnemonic": "TemplateExpand", + "configurationId": 2, + "inputDepSetIds": [4], + "outputIds": [15], + "primaryOutputId": 15, + "executionPlatform": "@@platforms//host:host", + "templateContent": "import { isAbsolute, join, resolve } from \"node:path\";\n\nconst configuration \u003d @@CONFIG@@;\nconst declaredRoot \u003d process.env.RUNFILES_DIR ?? process.env.TEST_SRCDIR ?? join(import.meta.dir, configuration.runfilesSibling);\nif (!declaredRoot || !isAbsolute(declaredRoot)) {\n throw new Error(\"Bazel Bun entrypoints require an absolute directory runfiles root\");\n}\nconst root \u003d resolve(declaredRoot);\nconst args \u003d configuration.arguments.map((argument) \u003d\u003e\n \"file\" in argument ? join(root, argument.file) : argument.literal,\n);\nif (configuration.runfilesArgument) args.push(root);\nargs.push(...process.argv.slice(2));\nconst testArguments \u003d configuration.testRunner ? [\"test\"] : [];\nif (configuration.testRunner \u0026\u0026 !args.some((argument) \u003d\u003e argument \u003d\u003d\u003d \"--timeout\" || argument.startsWith(\"--timeout\u003d\"))) {\n testArguments.push(\"--timeout\u003d30000\");\n}\nconst environment \u003d { ...process.env, ...configuration.environment };\nfor (const name of configuration.runfilesEnvironment) environment[name] \u003d root;\n// Execute the authored runner as the main module: importing it would skip\n// runners guarded by import.meta.main. No script interpreter or shell is used.\nconst result \u003d Bun.spawnSync(\n [process.execPath, \"--no-install\", \"--no-env-file\", ...testArguments, join(root, configuration.runner), ...args],\n {\n cwd: join(root, configuration.testRunner ? configuration.sourceRoot : configuration.workspace),\n env: environment,\n stdin: \"inherit\",\n stdout: \"inherit\",\n stderr: \"inherit\",\n },\n);\nprocess.exit(result.exitCode);\n", + "substitutions": [{ + "key": "@@CONFIG@@", + "value": "{\"arguments\":[],\"environment\":{},\"runfilesArgument\":false,\"runfilesEnvironment\":[],\"runfilesSibling\":\"unit_test.runfiles\",\"runner\":\"_main/src/query/ts/unit_test.sources/_main/src/query/ts/test/protocol.test.ts\",\"sourceRoot\":\"_main/src/query/ts/unit_test.sources/_main\",\"testRunner\":true,\"workspace\":\"_main\"}" + }] + }, { + "targetId": 2, + "actionKey": "170a6ade2e703fab4f3dc67c45dee7c2309a69850303f8638d31b50bbba9979b", + "mnemonic": "RepoMappingManifest", + "configurationId": 2, + "outputIds": [16], + "primaryOutputId": 16, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 2, + "actionKey": "3a906f60ecc5e30400344adf6001ddb42db3e92b914004ae55e63580e01681c7", + "mnemonic": "SourceSymlinkManifest", + "configurationId": 2, + "outputIds": [17], + "primaryOutputId": 17, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 2, + "actionKey": "cb69b03d8a1b01347e46537d8b3df85ef4e388f5a184e9deb179862b9cd65f29", + "mnemonic": "SymlinkTree", + "configurationId": 2, + "inputDepSetIds": [5], + "outputIds": [18], + "primaryOutputId": 18, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 2, + "actionKey": "709e80c88487a2411e1ee4dfb9f22a861492d20c4765150c0c794abd70f8147c", + "mnemonic": "Middleman", + "configurationId": 2, + "inputDepSetIds": [6], + "outputIds": [19], + "primaryOutputId": 19, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 2, + "actionKey": "6ed99f9926c5224d162959d96f5725ecf16b892c1a3df98821d2c5892b186ea3", + "mnemonic": "TestRunner", + "configurationId": 2, + "environmentVariables": [{ + "key": "PATH", + "value": "/bin:/usr/bin:/usr/local/bin" + }], + "inputDepSetIds": [9], + "outputIds": [22, 23, 24, 25], + "primaryOutputId": 22, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 3, + "actionKey": "7a39b61d5744a8903119e17b3ddc7e56e330f240d2bead98c3ba081a81b5c9ac", + "mnemonic": "ExecutableSymlink", + "configurationId": 3, + "inputDepSetIds": [10], + "outputIds": [27], + "primaryOutputId": 27, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 3, + "actionKey": "9df0fc7af996fee90934caf5821e6d3bf171df2d4270b392733ad8c5820cfbfa", + "mnemonic": "RepoMappingManifest", + "configurationId": 3, + "outputIds": [28], + "primaryOutputId": 28, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 3, + "actionKey": "8bfd336cc84e266eab28b0241686be81d8b7b052c4033aef8a98a9430853f275", + "mnemonic": "SourceSymlinkManifest", + "configurationId": 3, + "outputIds": [29], + "primaryOutputId": 29, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 3, + "actionKey": "6c51cb2745410b7f3021e2c6da7719dd646a1f8007539f27ba608eeaec4dc9d9", + "mnemonic": "SymlinkTree", + "configurationId": 3, + "inputDepSetIds": [11], + "outputIds": [30], + "primaryOutputId": 30, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 3, + "actionKey": "709e80c88487a2411e1ee4dfb9f22a861492d20c4765150c0c794abd70f8147c", + "mnemonic": "Middleman", + "configurationId": 3, + "inputDepSetIds": [12], + "outputIds": [31], + "primaryOutputId": 31, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 4, + "actionKey": "05bd55fdbfdd933c77df990c9c0acd1c0da0963dece377b17e3e1dc87e54a33e", + "mnemonic": "FileWrite", + "configurationId": 1, + "outputIds": [32], + "primaryOutputId": 32, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 4, + "actionKey": "52509dd660d2da8dfa398df24019a0abcc8a70177dffc0c56122bb1e0b67ad26", + "mnemonic": "FileWrite", + "configurationId": 1, + "outputIds": [33], + "primaryOutputId": 33, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 4, + "actionKey": "4a9b99ad2ba2756cd3dafdd8d8a264442cde23e7a874c3b78e4c2379a98ef29b", + "mnemonic": "CopyToDirectory", + "configurationId": 1, + "environmentVariables": [{ + "key": "GODEBUG", + "value": "winsymlink\u003d0" + }], + "inputDepSetIds": [15], + "outputIds": [37], + "primaryOutputId": 37, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 4, + "actionKey": "14e4b9ba30e7e0fbf72f2d1a4350e0938c172b1965375bffaeafa4ba4fc8d8d8", + "mnemonic": "QueryEnvelope", + "configurationId": 1, + "inputDepSetIds": [17], + "outputIds": [50], + "primaryOutputId": 50, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 5, + "actionKey": "355c71261c2901fdb9a8b691e5b3994c2c7877c4e84cc840900585e5c25b3681", + "mnemonic": "CopyFile", + "configurationId": 1, + "inputDepSetIds": [20], + "outputIds": [52], + "executionInfo": [{ + "key": "supports-path-mapping", + "value": "1" + }], + "primaryOutputId": 52, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 5, + "actionKey": "ed93ae2d2ca6952c52ad071d3c447d0a55889f4d5cd51c67ff7d4c7e1a4dd89d", + "mnemonic": "CopyFile", + "configurationId": 1, + "inputDepSetIds": [21], + "outputIds": [53], + "executionInfo": [{ + "key": "supports-path-mapping", + "value": "1" + }], + "primaryOutputId": 53, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 5, + "actionKey": "eb16123fff5c14f3d38fd4f9395321e5eaaf4185e891bd23f5163f2313bfe32f", + "mnemonic": "CopyFile", + "configurationId": 1, + "inputDepSetIds": [22], + "outputIds": [55], + "executionInfo": [{ + "key": "supports-path-mapping", + "value": "1" + }], + "primaryOutputId": 55, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 5, + "actionKey": "ca78fdcddb26bc5090f6d7bad5544b75858f8d575b56254e51896b7ae1a47319", + "mnemonic": "CopyFile", + "configurationId": 1, + "inputDepSetIds": [23], + "outputIds": [57], + "executionInfo": [{ + "key": "supports-path-mapping", + "value": "1" + }], + "primaryOutputId": 57, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 5, + "actionKey": "8daa333b8da0ce7b58fc8e5efbd32a5d743e6c9cc88d02f4d5992a520e59260f", + "mnemonic": "TsValidateOptions", + "configurationId": 1, + "environmentVariables": [{ + "key": "PATH", + "value": "/bin:/usr/bin:/usr/local/bin" + }], + "inputDepSetIds": [24], + "outputIds": [60], + "executionInfo": [{ + "key": "supports-path-mapping", + "value": "1" + }], + "primaryOutputId": 60, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 5, + "actionKey": "121bdf1046708dcd2f7c80900beaafd362b9a7f02d02a4b39eb27f39d73c9d87", + "mnemonic": "TsProject", + "configurationId": 1, + "environmentVariables": [{ + "key": "PATH", + "value": "/bin:/usr/bin:/usr/local/bin" + }], + "inputDepSetIds": [27], + "outputIds": [39, 40, 41, 42], + "executionInfo": [{ + "key": "supports-path-mapping", + "value": "1" + }], + "primaryOutputId": 39, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 6, + "actionKey": "355c71261c2901fdb9a8b691e5b3994c2c7877c4e84cc840900585e5c25b3681", + "mnemonic": "CopyFile", + "configurationId": 1, + "inputDepSetIds": [33], + "outputIds": [67], + "executionInfo": [{ + "key": "supports-path-mapping", + "value": "1" + }], + "primaryOutputId": 67, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 6, + "actionKey": "ed93ae2d2ca6952c52ad071d3c447d0a55889f4d5cd51c67ff7d4c7e1a4dd89d", + "mnemonic": "CopyFile", + "configurationId": 1, + "inputDepSetIds": [34], + "outputIds": [68], + "executionInfo": [{ + "key": "supports-path-mapping", + "value": "1" + }], + "primaryOutputId": 68, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 6, + "actionKey": "ea8439ef62e576dc448185c76a34e296221a6445e2c72a1867d94d44609ca968", + "mnemonic": "CopyFile", + "configurationId": 1, + "inputDepSetIds": [35], + "outputIds": [70], + "executionInfo": [{ + "key": "supports-path-mapping", + "value": "1" + }], + "primaryOutputId": 70, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 6, + "actionKey": "ca78fdcddb26bc5090f6d7bad5544b75858f8d575b56254e51896b7ae1a47319", + "mnemonic": "CopyFile", + "configurationId": 1, + "inputDepSetIds": [36], + "outputIds": [71], + "executionInfo": [{ + "key": "supports-path-mapping", + "value": "1" + }], + "primaryOutputId": 71, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 6, + "actionKey": "409d1bf0360f30c3b7f0dc097f86cd5258a2bbd1440bc8531f8cbb5597a46032", + "mnemonic": "TsValidateOptions", + "configurationId": 1, + "environmentVariables": [{ + "key": "PATH", + "value": "/bin:/usr/bin:/usr/local/bin" + }], + "inputDepSetIds": [37], + "outputIds": [72], + "executionInfo": [{ + "key": "supports-path-mapping", + "value": "1" + }], + "primaryOutputId": 72, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 6, + "actionKey": "eb70c7f97e2bb8f5fafa862131b73ff9d4ead652d655ca0a50b666f0ab914da2", + "mnemonic": "TsProject", + "configurationId": 1, + "environmentVariables": [{ + "key": "PATH", + "value": "/bin:/usr/bin:/usr/local/bin" + }], + "inputDepSetIds": [39], + "outputIds": [43, 44, 45, 46], + "executionInfo": [{ + "key": "supports-path-mapping", + "value": "1" + }], + "primaryOutputId": 43, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 7, + "actionKey": "afe568d62434aab01c6f4fce627ca6120f1c42ad4c2f2a2fbc22a2d702ca14c4", + "mnemonic": "TemplateExpand", + "configurationId": 3, + "inputDepSetIds": [42], + "outputIds": [74], + "primaryOutputId": 74, + "executionPlatform": "@@platforms//host:host", + "templateContent": "#!/usr/bin/env bash\n\n# This bash script is a wrapper around the NodeJS JavaScript file\n# entry point with the following bazel label:\n# {{entry_point_label}}\n#\n# The script\u0027s was generated to execute the js_binary target\n# {{target_label}}\n#\n# The template used to generate this script is\n# {{template_label}}\n\nset -o pipefail -o errexit -o nounset\n\n{{envs}}\n\n# If PATH was not provided, then it is important to export it here so that child\n# processes get the default value generated by bash.\nexport PATH\n\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n# Handle --bazel-bindir flag\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\n# If a --bazel-bindir \u003cpath\u003e flag is passed it must be the first two\n# arguments. It is consumed by this launcher script and used to set\n# BAZEL_BINDIR, overriding any value already set in the environment.\nif [ $# -gt 0 ] \u0026\u0026 [ \"$1\" \u003d \"--bazel-bindir\" ]; then\n if [ $# -lt 2 ]; then\n echo \"ERROR: --bazel-bindir flag requires a value\" \u003e\u00262\n exit 1\n fi\n BAZEL_BINDIR\u003d\"$2\"\n export BAZEL_BINDIR\n shift 2\nfi\n\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n# Prepare stdout capture, stderr capture \u0026\u0026 logging\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\n# Convert stdout, stderr and exit_code capture outputs paths to absolute paths.\n# A path not starting with \"bazel-out/\" is relative to the bin directory; joining\n# it with BAZEL_BINDIR here (rather than baking in bazel-out/\u003cconfig\u003e/bin at\n# analysis time) keeps it correct when path mapping is active. This must happen\n# before any directory changes below since it resolves against $PWD.\nfunction resolve_capture_path {\n case \"$1\" in\n bazel-out/*) echo \"$PWD/$1\" ;;\n *) echo \"$PWD/$BAZEL_BINDIR/$1\" ;;\n esac\n}\n\n# TODO(4.0): remove support for capturing stderr, stdout, and exit code. The\n# js_run_binary macro now handles this in a way that does not require help from\n# the launcher.\nif [ \"${JS_BINARY__STDOUT_OUTPUT_FILE:-}\" ]; then\n JS_BINARY__STDOUT_OUTPUT_FILE\u003d\"$(resolve_capture_path \"$JS_BINARY__STDOUT_OUTPUT_FILE\")\"\nfi\nif [ \"${JS_BINARY__STDERR_OUTPUT_FILE:-}\" ]; then\n JS_BINARY__STDERR_OUTPUT_FILE\u003d\"$(resolve_capture_path \"$JS_BINARY__STDERR_OUTPUT_FILE\")\"\nfi\nif [ \"${JS_BINARY__EXIT_CODE_OUTPUT_FILE:-}\" ]; then\n JS_BINARY__EXIT_CODE_OUTPUT_FILE\u003d\"$(resolve_capture_path \"$JS_BINARY__EXIT_CODE_OUTPUT_FILE\")\"\nfi\n\n# A stream with a declared output file is written straight to that file so that\n# nothing has to run after node exits and this shell can exec node.\n#\n# A stream that is only subject to silent_on_success has no final destination, so\n# it is buffered in a temp file and replayed on failure.\nif [ \"${JS_BINARY__STDOUT_OUTPUT_FILE:-}\" ]; then\n STDOUT_CAPTURE\u003d\"$JS_BINARY__STDOUT_OUTPUT_FILE\"\nelif [ \"${JS_BINARY__SILENT_ON_SUCCESS:-}\" ]; then\n STDOUT_CAPTURE\u003d$(mktemp)\n STDOUT_CAPTURE_IS_TEMP\u003d1\nfi\n\nif [ \"${JS_BINARY__STDERR_OUTPUT_FILE:-}\" ]; then\n STDERR_CAPTURE\u003d\"$JS_BINARY__STDERR_OUTPUT_FILE\"\nelif [ \"${JS_BINARY__SILENT_ON_SUCCESS:-}\" ]; then\n STDERR_CAPTURE\u003d$(mktemp)\n STDERR_CAPTURE_IS_TEMP\u003d1\nfi\n\n# FATAL and ERROR diagnostics from this launcher only go into the stderr capture\n# if that capture is a temp file that will get replayed on failure. Otherwise,\n# we write these straight to stderr so that they do not get lost if the action\n# fails.\nLOG_ERROR_CAPTURE\u003d\"${STDERR_CAPTURE_IS_TEMP:+$STDERR_CAPTURE}\"\n\nexport JS_BINARY__LOG_PREFIX\u003d\"{{log_prefix_rule_set}}[{{log_prefix_rule}}]\"\n\n# Emit a log line to $1, or to the real stderr when $1 is empty.\nfunction log_to {\n local capture\u003d\"$1\"\n local level\u003d\"$2\"\n local message\u003d\"$3\"\n if [ \"$capture\" ]; then\n printf \"%s: %s: %s\\n\" \"$level\" \"$JS_BINARY__LOG_PREFIX\" \"$message\" \u003e\u003e\"$capture\"\n else\n printf \"%s: %s: %s\\n\" \"$level\" \"$JS_BINARY__LOG_PREFIX\" \"$message\" \u003e\u00262\n fi\n}\n\nfunction log_fatal {\n if [ \"${JS_BINARY__LOG_FATAL:-}\" ]; then\n log_to \"${LOG_ERROR_CAPTURE:-}\" FATAL \"$1\"\n fi\n}\n\nfunction log_error {\n if [ \"${JS_BINARY__LOG_ERROR:-}\" ]; then\n log_to \"${LOG_ERROR_CAPTURE:-}\" ERROR \"$1\"\n fi\n}\n\nfunction log_info {\n if [ \"${JS_BINARY__LOG_INFO:-}\" ]; then\n log_to \"${STDERR_CAPTURE:-}\" INFO \"$1\"\n fi\n}\n\nfunction log_debug {\n if [ \"${JS_BINARY__LOG_DEBUG:-}\" ]; then\n log_to \"${STDERR_CAPTURE:-}\" DEBUG \"$1\"\n fi\n}\n\n_exit() {\n EXIT_CODE\u003d$?\n\n # Streams captured to a declared output file were written there directly and\n # need no mop up. Only the temp files that back silent_on_success do.\n if [ \"${STDERR_CAPTURE_IS_TEMP:-}\" ]; then\n if [ \"$EXIT_CODE\" !\u003d 0 ] || [ -z \"${JS_BINARY__SILENT_ON_SUCCESS:-}\" ]; then\n cat \"$STDERR_CAPTURE\" \u003e\u00262\n fi\n rm \"$STDERR_CAPTURE\"\n fi\n\n if [ \"${STDOUT_CAPTURE_IS_TEMP:-}\" ]; then\n if [ \"$EXIT_CODE\" !\u003d 0 ] || [ -z \"${JS_BINARY__SILENT_ON_SUCCESS:-}\" ]; then\n cat \"$STDOUT_CAPTURE\"\n fi\n rm \"$STDOUT_CAPTURE\"\n fi\n\n log_debug \"exit code: $EXIT_CODE\"\n\n exit \"$EXIT_CODE\"\n}\n\ntrap _exit EXIT\n\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n# Initialize RUNFILES environment variable\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n{{initialize_runfiles}}\nJS_BINARY__RUNFILES\u003d\"$RUNFILES\"\nexport JS_BINARY__RUNFILES\n\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n# Prepare to run main program\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\n# The execroot the entry point is resolved against below. A parent js_binary process hands its\n# own down when it asks for an execroot entry point, because the entry point it resolved is in\n# that tree; otherwise this script was started in it. Nothing else here needs an execroot: the\n# launcher preload works out JS_BINARY__EXECROOT for the program and everything it spawns.\nif [ \"${JS_BINARY__USE_EXECROOT_ENTRY_POINT:-}\" ] \u0026\u0026 [ \"${JS_BINARY__EXECROOT:-}\" ]; then\n execroot\u003d\"$JS_BINARY__EXECROOT\"\nelse\n execroot\u003d\"$PWD\"\nfi\n\n# Build actions are started in the execroot, so change into the root of the Bazel output tree,\n# which is where js_binary programs run. See\n# https://github.com/aspect-build/rules_js/tree/dbb5af0d2a9a2bb50e4cf4a96dbc582b27567155#running-nodejs-programs\n# for more context on why we do this. It cannot wait for the preload: node resolves the bare\n# specifier of a --require in node_options against the directory it was started in.\n#\n# The bindir is only there to change into when this really is an execroot; in a runfiles tree,\n# or in a nested js_binary already running in the bindir, there is nothing to do. The preload\n# tells those apart from the broken case by JS_BINARY__CHANGED_TO_BINDIR.\nif [ -z \"${JS_BINARY__NO_CD_BINDIR:-}\" ] \u0026\u0026 [ \"${BAZEL_BINDIR:-}\" ] \u0026\u0026 [ -d \"$PWD/$BAZEL_BINDIR\" ]; then\n log_debug \"changing directory to BAZEL_BINDIR (root of Bazel output tree) $BAZEL_BINDIR\"\n export JS_BINARY__CHANGED_TO_BINDIR\u003d1\n cd \"$BAZEL_BINDIR\"\nfi\n\nif [ \"${JS_BINARY__USE_EXECROOT_ENTRY_POINT:-}\" ] \u0026\u0026 [ -z \"${BAZEL_BINDIR:-}\" ]; then\n log_fatal \"Expected BAZEL_BINDIR to be set when JS_BINARY__USE_EXECROOT_ENTRY_POINT is set\"\n exit 1\nfi\n\nfunction resolve_execroot_bin_path {\n local short_path\u003d\"$1\"\n if [[ \"$short_path\" \u003d\u003d ../* ]]; then\n echo \"$execroot/$BAZEL_BINDIR/external/${short_path:3}\"\n else\n echo \"$execroot/$BAZEL_BINDIR/$short_path\"\n fi\n}\n\nfunction resolve_execroot_src_path {\n local short_path\u003d\"$1\"\n if [[ \"$short_path\" \u003d\u003d ../* ]]; then\n echo \"$execroot/external/${short_path:3}\"\n else\n echo \"$execroot/$short_path\"\n fi\n}\n\n# Resolve a toolchain file that is a file of this workspace or another repository\n# in the runfiles tree, or an absolute path a user set in node_toolchain.\nfunction resolve_toolchain_path {\n local file\n file\u003d\"$(_normalize_path \"$1\")\"\n if [ \"${file:0:1}\" \u003d \"/\" ]; then\n echo \"$file\"\n elif [ \"${JS_BINARY__NO_RUNFILES:-}\" ]; then\n resolve_execroot_src_path \"$file\"\n else\n echo \"$JS_BINARY__RUNFILES/{{workspace_name}}/$file\"\n fi\n}\n\n# Everything below is resolved here only because node needs it on its command line\n# or bash needs it to start node at all. The checks that can wait, and the rest of\n# the environment the program sees, are done by the launcher preload once node is up.\n\nif [ \"${JS_BINARY__USE_EXECROOT_ENTRY_POINT:-}\" ] || [ \"${JS_BINARY__NO_RUNFILES:-}\" ]; then\n entry_point\u003d$(resolve_execroot_bin_path \"{{entry_point_path}}\")\nelse\n entry_point\u003d\"$JS_BINARY__RUNFILES/{{workspace_name}}/{{entry_point_path}}\"\nfi\n\nexport JS_BINARY__NODE_BINARY\nJS_BINARY__NODE_BINARY\u003d$(resolve_toolchain_path \"{{node}}\")\nif [ ! -f \"$JS_BINARY__NODE_BINARY\" ]; then\n log_fatal \"node binary \u0027$JS_BINARY__NODE_BINARY\u0027 not found\"\n exit 1\nfi\nif [ \"$_IS_WINDOWS\" -ne \"1\" ] \u0026\u0026 [ ! -x \"$JS_BINARY__NODE_BINARY\" ]; then\n log_fatal \"node binary \u0027$JS_BINARY__NODE_BINARY\u0027 is not executable\"\n exit 1\nfi\n\nnpm\u003d\"{{npm}}\"\nif [ \"$npm\" ]; then\n export JS_BINARY__NPM_BINARY\n JS_BINARY__NPM_BINARY\u003d$(resolve_toolchain_path \"$npm\")\nfi\n\nlauncher\u003d$(resolve_toolchain_path \"{{launcher}}\")\nif [ ! -f \"$launcher\" ]; then\n log_fatal \"launcher \u0027$launcher\u0027 not found\"\n exit 1\nfi\n\n# Gather node options\nJS_BINARY__NODE_OPTIONS\u003d()\n{{node_options}}\n\nARGS\u003d()\nALL_ARGS\u003d({{fixed_args}} \"$@\")\nfor ARG in ${ALL_ARGS[@]+\"${ALL_ARGS[@]}\"}; do\n case \"$ARG\" in\n # Let users pass through arguments to node itself\n --node_options\u003d*) JS_BINARY__NODE_OPTIONS+\u003d(\"${ARG#--node_options\u003d}\") ;;\n # Remaining argv is collected to pass to the program\n *) ARGS+\u003d(\"$ARG\") ;;\n esac\ndone\n\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n# Run the main program\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\n# Invoke node directly rather than through $JS_BINARY__NODE_WRAPPER. This way\n# we avoid spawning an extra bash process on every launch. The wrapper is\n# still put on the PATH as `node` so that child processes get the patched\n# runtime.\nnode_cmd\u003d(\"$JS_BINARY__NODE_BINARY\" --require \"$launcher\")\n\nif [ \"${JS_BINARY__LOG_INFO:-}\" ]; then\n log_info \"$(echo -n \"running\" \"${node_cmd[@]}\" ${JS_BINARY__NODE_OPTIONS[@]+\"${JS_BINARY__NODE_OPTIONS[@]}\"} -- \"$entry_point\" ${ARGS[@]+\"${ARGS[@]}\"})\"\nfi\n\n# De-export capture-related vars so child processes (e.g. a nested js_binary)\n# do not inherit them. The bash script has already consumed them above to set up\n# STDOUT_CAPTURE / STDERR_CAPTURE; leaking them would cause a nested js_binary\n# to silently swallow its own stdout or write to the wrong output file.\n# export -n keeps the value accessible to the _exit trap while removing it from\n# the environment seen by node and any processes it spawns.\nexport -n JS_BINARY__STDOUT_OUTPUT_FILE JS_BINARY__STDERR_OUTPUT_FILE JS_BINARY__EXIT_CODE_OUTPUT_FILE JS_BINARY__SILENT_ON_SUCCESS\n\nset +e\n\nif [ -z \"${JS_BINARY__EXPECTED_EXIT_CODE:-}\" ] \u0026\u0026 [ -z \"${JS_BINARY__EXIT_CODE_OUTPUT_FILE:-}\" ] \u0026\u0026\n [ -z \"${STDOUT_CAPTURE_IS_TEMP:-}\" ] \u0026\u0026 [ -z \"${STDERR_CAPTURE_IS_TEMP:-}\" ]; then\n # Nothing must run after node exits, so replace this shell with node. Signals\n # and terminal control are then delivered directly to node instead of being\n # proxied through a backgrounded child.\n if [ \"${STDOUT_CAPTURE:-}\" ]; then\n exec 1\u003e\u003e\"$STDOUT_CAPTURE\"\n fi\n if [ \"${STDERR_CAPTURE:-}\" ]; then\n exec 2\u003e\u003e\"$STDERR_CAPTURE\"\n fi\n exec \"${node_cmd[@]}\" ${JS_BINARY__NODE_OPTIONS[@]+\"${JS_BINARY__NODE_OPTIONS[@]}\"} -- \"$entry_point\" ${ARGS[@]+\"${ARGS[@]}\"}\n exit 127\nfi\n\nif [ \"${STDOUT_CAPTURE:-}\" ] \u0026\u0026 [ \"${STDERR_CAPTURE:-}\" ]; then\n \"${node_cmd[@]}\" ${JS_BINARY__NODE_OPTIONS[@]+\"${JS_BINARY__NODE_OPTIONS[@]}\"} -- \"$entry_point\" ${ARGS[@]+\"${ARGS[@]}\"} \u003c\u00260 \u003e\u003e\"$STDOUT_CAPTURE\" 2\u003e\u003e\"$STDERR_CAPTURE\" \u0026\nelif [ \"${STDOUT_CAPTURE:-}\" ]; then\n \"${node_cmd[@]}\" ${JS_BINARY__NODE_OPTIONS[@]+\"${JS_BINARY__NODE_OPTIONS[@]}\"} -- \"$entry_point\" ${ARGS[@]+\"${ARGS[@]}\"} \u003c\u00260 \u003e\u003e\"$STDOUT_CAPTURE\" \u0026\nelif [ \"${STDERR_CAPTURE:-}\" ]; then\n \"${node_cmd[@]}\" ${JS_BINARY__NODE_OPTIONS[@]+\"${JS_BINARY__NODE_OPTIONS[@]}\"} -- \"$entry_point\" ${ARGS[@]+\"${ARGS[@]}\"} \u003c\u00260 2\u003e\u003e\"$STDERR_CAPTURE\" \u0026\nelse\n \"${node_cmd[@]}\" ${JS_BINARY__NODE_OPTIONS[@]+\"${JS_BINARY__NODE_OPTIONS[@]}\"} -- \"$entry_point\" ${ARGS[@]+\"${ARGS[@]}\"} \u003c\u00260 \u0026\nfi\n\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n# Wait for program to finish\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\nreadonly child\u003d$!\n# Bash does not forward termination signals to any child process when\n# running in docker, so we need to manually trap and forward the signals.\n#\n# Each trap is reset as it fires, so that a repeat of that signal terminates this\n# script rather than being swallowed.\n_term() { trap - SIGTERM; kill -TERM \"${child}\" 2\u003e/dev/null; }\n_int() { trap - SIGINT; kill -INT \"${child}\" 2\u003e/dev/null; }\ntrap _term SIGTERM\ntrap _int SIGINT\n\n# A wait returns as soon as a trapped signal has been handled, whether or not the\n# child has exited, so keep waiting until it has.\nwait \"$child\"\nRESULT\u003d\"$?\"\nwhile kill -0 \"$child\" 2\u003e/dev/null; do\n wait \"$child\"\n RESULT\u003d\"$?\"\ndone\n\n# Remove traps now that the child process has exited\ntrap - SIGTERM SIGINT\nset -e\n\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n# Mop up after main program\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\nif [ \"${JS_BINARY__EXPECTED_EXIT_CODE:-}\" ]; then\n if [ \"$RESULT\" !\u003d \"$JS_BINARY__EXPECTED_EXIT_CODE\" ]; then\n log_error \"expected exit code to be \u0027$JS_BINARY__EXPECTED_EXIT_CODE\u0027, but got \u0027$RESULT\u0027\"\n if [ $RESULT -eq 0 ]; then\n # This exit code is handled specially by Bazel:\n # https://github.com/bazelbuild/bazel/blob/486206012a664ecb20bdb196a681efc9a9825049/src/main/java/com/google/devtools/build/lib/util/ExitCode.java#L44\n readonly BAZEL_EXIT_TESTS_FAILED\u003d3\n exit $BAZEL_EXIT_TESTS_FAILED\n fi\n exit $RESULT\n else\n exit 0\n fi\nfi\n\nif [ \"${JS_BINARY__EXIT_CODE_OUTPUT_FILE:-}\" ]; then\n # Exit zero if the exit code was captured\n echo -n \"$RESULT\" \u003e\"$JS_BINARY__EXIT_CODE_OUTPUT_FILE\"\n exit 0\nelse\n exit $RESULT\nfi\n", + "substitutions": [{ + "key": "{{target_label}}", + "value": "@@aspect_rules_ts++typescript+npm_typescript//:tsc_worker" + }, { + "key": "{{template_label}}", + "value": "@@aspect_rules_js+//js/private:js_binary.sh.tpl" + }, { + "key": "{{entry_point_label}}", + "value": "@@aspect_rules_ts++typescript+npm_typescript//:copy_ts_project_worker" + }, { + "key": "{{entry_point_path}}", + "value": "../aspect_rules_ts++typescript+npm_typescript/ts_project_worker.js" + }, { + "key": "{{envs}}", + "value": "export JS_BINARY__BINDIR\u003d\"bazel-out/k8-opt-exec-ST-d57f47055a04/bin\"\nexport JS_BINARY__COMPILATION_MODE\u003d\"opt\"\nexport JS_BINARY__TARGET_CPU\u003d\"k8\"\nexport JS_BINARY__BUILD_FILE_PATH\u003d\"BUILD.bazel\"\nexport JS_BINARY__PACKAGE\u003d\"\"\nexport JS_BINARY__TARGET_NAME\u003d\"tsc_worker\"\nexport JS_BINARY__TARGET\u003d\"@aspect_rules_ts++typescript+npm_typescript//:tsc_worker\"\nexport JS_BINARY__WORKSPACE\u003d\"_main\"\nif [[ -z \"${JS_BINARY__PATCH_NODE_FS:-}\" ]]; then export JS_BINARY__PATCH_NODE_FS\u003d\"1\"; fi\nexport JS_BINARY__COPY_DATA_TO_BIN\u003d\"1\"\nif [[ -z \"${JS_BINARY__LOG_FATAL:-}\" ]]; then export JS_BINARY__LOG_FATAL\u003d\"1\"; fi\nif [[ -z \"${JS_BINARY__LOG_ERROR:-}\" ]]; then export JS_BINARY__LOG_ERROR\u003d\"1\"; fi" + }, { + "key": "{{fixed_args}}" + }, { + "key": "{{initialize_runfiles}}", + "value": "\n# It helps to determine if we are running on a Windows environment (excludes WSL as it acts like Unix)\ncase \"$(uname -s)\" in\nCYGWIN*) _IS_WINDOWS\u003d1 ;;\nMINGW*) _IS_WINDOWS\u003d1 ;;\nMSYS_NT*) _IS_WINDOWS\u003d1 ;;\n*) _IS_WINDOWS\u003d0 ;;\nesac\n\n# It helps to normalizes paths when running on Windows.\n#\n# Example:\n# C:/Users/XUser/_bazel_XUser/7q7kkv32/execroot/A/b/C -\u003e /c/Users/XUser/_bazel_XUser/7q7kkv32/execroot/A/b/C\nfunction _normalize_path {\n if [ \"$_IS_WINDOWS\" -eq \"1\" ]; then\n # Apply the followings paths transformations to normalize paths on Windows\n # -process driver letter\n # -convert path separator\n sed -e \u0027s#^\\(.\\):#/\\L\\1#\u0027 -e \u0027s#\\\\#/#g\u0027 \u003c\u003c\u003c\"$1\"\n else\n echo \"$1\"\n fi\n return\n}\n\n# Set a RUNFILES environment variable to the root of the runfiles tree\n# since RUNFILES_DIR is not set by Bazel in all contexts.\n# For example, `RUNFILES\u003d/path/to/my_js_binary.sh.runfiles`.\n#\n# Call this program X. X was generated by a genrule and may be invoked\n# in many ways:\n# 1a) directly by a user, with $0 in the output tree\n# 1b) via \u0027bazel run\u0027 (similar to case 1a)\n# 2) directly by a user, with $0 in X\u0027s runfiles\n# 3) by another program Y which has a data dependency on X, with $0 in Y\u0027s\n# runfiles\n# 4a) via \u0027bazel test\u0027\n# 4b) case 3 in the context of a test\n# 5a) by a genrule cmd, with $0 in the output tree\n# 6a) case 3 in the context of a genrule\n#\n# For case 1, $0 will be a regular file, and the runfiles will be\n# at $0.runfiles.\n# For case 2 or 3, $0 will be a symlink to the file seen in case 1.\n# For case 4, $TEST_SRCDIR should already be set to the runfiles by\n# blaze.\n# Case 5a is handled like case 1.\n# Case 6a is handled like case 3.\nif [ \"${TEST_SRCDIR:-}\" ]; then\n # Case 4, bazel has identified runfiles for us.\n RUNFILES\u003d$(_normalize_path \"$TEST_SRCDIR\")\nelif [ \"${RUNFILES_MANIFEST_FILE:-}\" ]; then\n RUNFILES\u003d$(_normalize_path \"$RUNFILES_MANIFEST_FILE\")\n if [[ \"${RUNFILES}\" \u003d\u003d *.runfiles_manifest ]]; then\n # Bazel puts the manifest besides the runfiles with the suffix .runfiles_manifest.\n # For example, the runfiles directory is named my_binary.runfiles then the manifest is beside the\n # runfiles directory and named my_binary.runfiles_manifest\n RUNFILES\u003d${RUNFILES%_manifest}\n elif [[ \"${RUNFILES}\" \u003d\u003d */MANIFEST ]]; then\n # Bazel for windows puts the manifest file named MANIFEST in the runfiles directory\n RUNFILES\u003d${RUNFILES%/MANIFEST}\n else\n log_fatal \"Unexpected RUNFILES_MANIFEST_FILE value $RUNFILES_MANIFEST_FILE\"\n exit 1\n fi\nelse\n case \"$0\" in\n /*) self\u003d\"$0\" ;;\n *) self\u003d\"$PWD/$0\" ;;\n esac\n while true; do\n if [ -e \"$self.runfiles\" ]; then\n RUNFILES\u003d\"$self.runfiles\"\n break\n fi\n\n if [[ \"$self\" \u003d\u003d *.runfiles/* ]]; then\n RUNFILES\u003d\"${self%%.runfiles/*}.runfiles\"\n # don\u0027t break; this is a last resort for case 6b\n fi\n\n if [ ! -L \"$self\" ]; then\n break\n fi\n\n readlink\u003d\"$(readlink \"$self\")\"\n if [[ \"$readlink\" \u003d\u003d /* ]]; then\n self\u003d\"$readlink\"\n else\n # resolve relative symlink\n self\u003d\"${self%%/*}/$readlink\"\n fi\n done\n\n if [ -z \"${RUNFILES:-}\" ]; then\n log_fatal \"RUNFILES environment variable is not set\"\n exit 1\n fi\n\n RUNFILES\u003d$(_normalize_path \"$RUNFILES\")\nfi\nif [ \"${RUNFILES:0:1}\" !\u003d \"/\" ]; then\n # Ensure RUNFILES set above is an absolute path. It may be a path relative\n # to the PWD in case where RUNFILES_MANIFEST_FILE is used above.\n RUNFILES\u003d\"$PWD/$RUNFILES\"\nfi\n# Set RUNFILES_DIR if not already set so that tools such as @bazel/runfiles\n# can locate runfiles without requiring RUNFILES to be exported.\nexport RUNFILES_DIR\u003d\"${RUNFILES_DIR:-$RUNFILES}\"\n" + }, { + "key": "{{log_prefix_rule_set}}", + "value": "aspect_rules_js" + }, { + "key": "{{log_prefix_rule}}", + "value": "js_binary" + }, { + "key": "{{launcher}}", + "value": "../aspect_rules_js+/js/private/node-bootstrap/launcher.cjs" + }, { + "key": "{{node_options}}", + "value": "JS_BINARY__NODE_OPTIONS+\u003d(\"--preserve-symlinks-main\")" + }, { + "key": "{{node}}", + "value": "../rules_nodejs++node+nodejs_linux_amd64/bin/nodejs/bin/node" + }, { + "key": "{{npm}}" + }, { + "key": "{{workspace_name}}", + "value": "_main" + }] + }, { + "targetId": 7, + "actionKey": "4f4bf4b1b5b2284ce521a69b165072b12450dee320415b733ec58bd4930c216f", + "mnemonic": "RepoMappingManifest", + "configurationId": 3, + "outputIds": [75], + "primaryOutputId": 75, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 7, + "actionKey": "aeb51d69bd94c236f4ecfb31cbd3f2e1c7076041098ca62ed400c2617e654062", + "mnemonic": "SourceSymlinkManifest", + "configurationId": 3, + "inputDepSetIds": [43], + "outputIds": [77], + "primaryOutputId": 77, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 7, + "actionKey": "41ae5ee3bb7cce9243d85ef829862800b09b0a8e30356db261cc1c34d42eee02", + "mnemonic": "SymlinkTree", + "configurationId": 3, + "inputDepSetIds": [44], + "outputIds": [78], + "primaryOutputId": 78, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 7, + "actionKey": "709e80c88487a2411e1ee4dfb9f22a861492d20c4765150c0c794abd70f8147c", + "mnemonic": "Middleman", + "configurationId": 3, + "inputDepSetIds": [45], + "outputIds": [89], + "primaryOutputId": 89, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 8, + "actionKey": "54822de1b9155ce110e6c1afbc6d7402098b56f37a78e23f5a1062d5442543f6", + "mnemonic": "UnresolvedSymlink", + "configurationId": 1, + "outputIds": [62], + "primaryOutputId": 62, + "executionPlatform": "@@platforms//host:host", + "unresolvedSymlinkTarget": "../.aspect_rules_js/@types+node@24.12.4/node_modules/@types/node" + }, { + "targetId": 9, + "actionKey": "6d7045aec817638b04b2220a69243df1247acb88114594fb908a74248160dcc8", + "mnemonic": "TemplateExpand", + "configurationId": 3, + "inputDepSetIds": [42], + "outputIds": [58], + "primaryOutputId": 58, + "executionPlatform": "@@platforms//host:host", + "templateContent": "#!/usr/bin/env bash\n\n# This bash script is a wrapper around the NodeJS JavaScript file\n# entry point with the following bazel label:\n# {{entry_point_label}}\n#\n# The script\u0027s was generated to execute the js_binary target\n# {{target_label}}\n#\n# The template used to generate this script is\n# {{template_label}}\n\nset -o pipefail -o errexit -o nounset\n\n{{envs}}\n\n# If PATH was not provided, then it is important to export it here so that child\n# processes get the default value generated by bash.\nexport PATH\n\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n# Handle --bazel-bindir flag\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\n# If a --bazel-bindir \u003cpath\u003e flag is passed it must be the first two\n# arguments. It is consumed by this launcher script and used to set\n# BAZEL_BINDIR, overriding any value already set in the environment.\nif [ $# -gt 0 ] \u0026\u0026 [ \"$1\" \u003d \"--bazel-bindir\" ]; then\n if [ $# -lt 2 ]; then\n echo \"ERROR: --bazel-bindir flag requires a value\" \u003e\u00262\n exit 1\n fi\n BAZEL_BINDIR\u003d\"$2\"\n export BAZEL_BINDIR\n shift 2\nfi\n\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n# Prepare stdout capture, stderr capture \u0026\u0026 logging\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\n# Convert stdout, stderr and exit_code capture outputs paths to absolute paths.\n# A path not starting with \"bazel-out/\" is relative to the bin directory; joining\n# it with BAZEL_BINDIR here (rather than baking in bazel-out/\u003cconfig\u003e/bin at\n# analysis time) keeps it correct when path mapping is active. This must happen\n# before any directory changes below since it resolves against $PWD.\nfunction resolve_capture_path {\n case \"$1\" in\n bazel-out/*) echo \"$PWD/$1\" ;;\n *) echo \"$PWD/$BAZEL_BINDIR/$1\" ;;\n esac\n}\n\n# TODO(4.0): remove support for capturing stderr, stdout, and exit code. The\n# js_run_binary macro now handles this in a way that does not require help from\n# the launcher.\nif [ \"${JS_BINARY__STDOUT_OUTPUT_FILE:-}\" ]; then\n JS_BINARY__STDOUT_OUTPUT_FILE\u003d\"$(resolve_capture_path \"$JS_BINARY__STDOUT_OUTPUT_FILE\")\"\nfi\nif [ \"${JS_BINARY__STDERR_OUTPUT_FILE:-}\" ]; then\n JS_BINARY__STDERR_OUTPUT_FILE\u003d\"$(resolve_capture_path \"$JS_BINARY__STDERR_OUTPUT_FILE\")\"\nfi\nif [ \"${JS_BINARY__EXIT_CODE_OUTPUT_FILE:-}\" ]; then\n JS_BINARY__EXIT_CODE_OUTPUT_FILE\u003d\"$(resolve_capture_path \"$JS_BINARY__EXIT_CODE_OUTPUT_FILE\")\"\nfi\n\n# A stream with a declared output file is written straight to that file so that\n# nothing has to run after node exits and this shell can exec node.\n#\n# A stream that is only subject to silent_on_success has no final destination, so\n# it is buffered in a temp file and replayed on failure.\nif [ \"${JS_BINARY__STDOUT_OUTPUT_FILE:-}\" ]; then\n STDOUT_CAPTURE\u003d\"$JS_BINARY__STDOUT_OUTPUT_FILE\"\nelif [ \"${JS_BINARY__SILENT_ON_SUCCESS:-}\" ]; then\n STDOUT_CAPTURE\u003d$(mktemp)\n STDOUT_CAPTURE_IS_TEMP\u003d1\nfi\n\nif [ \"${JS_BINARY__STDERR_OUTPUT_FILE:-}\" ]; then\n STDERR_CAPTURE\u003d\"$JS_BINARY__STDERR_OUTPUT_FILE\"\nelif [ \"${JS_BINARY__SILENT_ON_SUCCESS:-}\" ]; then\n STDERR_CAPTURE\u003d$(mktemp)\n STDERR_CAPTURE_IS_TEMP\u003d1\nfi\n\n# FATAL and ERROR diagnostics from this launcher only go into the stderr capture\n# if that capture is a temp file that will get replayed on failure. Otherwise,\n# we write these straight to stderr so that they do not get lost if the action\n# fails.\nLOG_ERROR_CAPTURE\u003d\"${STDERR_CAPTURE_IS_TEMP:+$STDERR_CAPTURE}\"\n\nexport JS_BINARY__LOG_PREFIX\u003d\"{{log_prefix_rule_set}}[{{log_prefix_rule}}]\"\n\n# Emit a log line to $1, or to the real stderr when $1 is empty.\nfunction log_to {\n local capture\u003d\"$1\"\n local level\u003d\"$2\"\n local message\u003d\"$3\"\n if [ \"$capture\" ]; then\n printf \"%s: %s: %s\\n\" \"$level\" \"$JS_BINARY__LOG_PREFIX\" \"$message\" \u003e\u003e\"$capture\"\n else\n printf \"%s: %s: %s\\n\" \"$level\" \"$JS_BINARY__LOG_PREFIX\" \"$message\" \u003e\u00262\n fi\n}\n\nfunction log_fatal {\n if [ \"${JS_BINARY__LOG_FATAL:-}\" ]; then\n log_to \"${LOG_ERROR_CAPTURE:-}\" FATAL \"$1\"\n fi\n}\n\nfunction log_error {\n if [ \"${JS_BINARY__LOG_ERROR:-}\" ]; then\n log_to \"${LOG_ERROR_CAPTURE:-}\" ERROR \"$1\"\n fi\n}\n\nfunction log_info {\n if [ \"${JS_BINARY__LOG_INFO:-}\" ]; then\n log_to \"${STDERR_CAPTURE:-}\" INFO \"$1\"\n fi\n}\n\nfunction log_debug {\n if [ \"${JS_BINARY__LOG_DEBUG:-}\" ]; then\n log_to \"${STDERR_CAPTURE:-}\" DEBUG \"$1\"\n fi\n}\n\n_exit() {\n EXIT_CODE\u003d$?\n\n # Streams captured to a declared output file were written there directly and\n # need no mop up. Only the temp files that back silent_on_success do.\n if [ \"${STDERR_CAPTURE_IS_TEMP:-}\" ]; then\n if [ \"$EXIT_CODE\" !\u003d 0 ] || [ -z \"${JS_BINARY__SILENT_ON_SUCCESS:-}\" ]; then\n cat \"$STDERR_CAPTURE\" \u003e\u00262\n fi\n rm \"$STDERR_CAPTURE\"\n fi\n\n if [ \"${STDOUT_CAPTURE_IS_TEMP:-}\" ]; then\n if [ \"$EXIT_CODE\" !\u003d 0 ] || [ -z \"${JS_BINARY__SILENT_ON_SUCCESS:-}\" ]; then\n cat \"$STDOUT_CAPTURE\"\n fi\n rm \"$STDOUT_CAPTURE\"\n fi\n\n log_debug \"exit code: $EXIT_CODE\"\n\n exit \"$EXIT_CODE\"\n}\n\ntrap _exit EXIT\n\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n# Initialize RUNFILES environment variable\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n{{initialize_runfiles}}\nJS_BINARY__RUNFILES\u003d\"$RUNFILES\"\nexport JS_BINARY__RUNFILES\n\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n# Prepare to run main program\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\n# The execroot the entry point is resolved against below. A parent js_binary process hands its\n# own down when it asks for an execroot entry point, because the entry point it resolved is in\n# that tree; otherwise this script was started in it. Nothing else here needs an execroot: the\n# launcher preload works out JS_BINARY__EXECROOT for the program and everything it spawns.\nif [ \"${JS_BINARY__USE_EXECROOT_ENTRY_POINT:-}\" ] \u0026\u0026 [ \"${JS_BINARY__EXECROOT:-}\" ]; then\n execroot\u003d\"$JS_BINARY__EXECROOT\"\nelse\n execroot\u003d\"$PWD\"\nfi\n\n# Build actions are started in the execroot, so change into the root of the Bazel output tree,\n# which is where js_binary programs run. See\n# https://github.com/aspect-build/rules_js/tree/dbb5af0d2a9a2bb50e4cf4a96dbc582b27567155#running-nodejs-programs\n# for more context on why we do this. It cannot wait for the preload: node resolves the bare\n# specifier of a --require in node_options against the directory it was started in.\n#\n# The bindir is only there to change into when this really is an execroot; in a runfiles tree,\n# or in a nested js_binary already running in the bindir, there is nothing to do. The preload\n# tells those apart from the broken case by JS_BINARY__CHANGED_TO_BINDIR.\nif [ -z \"${JS_BINARY__NO_CD_BINDIR:-}\" ] \u0026\u0026 [ \"${BAZEL_BINDIR:-}\" ] \u0026\u0026 [ -d \"$PWD/$BAZEL_BINDIR\" ]; then\n log_debug \"changing directory to BAZEL_BINDIR (root of Bazel output tree) $BAZEL_BINDIR\"\n export JS_BINARY__CHANGED_TO_BINDIR\u003d1\n cd \"$BAZEL_BINDIR\"\nfi\n\nif [ \"${JS_BINARY__USE_EXECROOT_ENTRY_POINT:-}\" ] \u0026\u0026 [ -z \"${BAZEL_BINDIR:-}\" ]; then\n log_fatal \"Expected BAZEL_BINDIR to be set when JS_BINARY__USE_EXECROOT_ENTRY_POINT is set\"\n exit 1\nfi\n\nfunction resolve_execroot_bin_path {\n local short_path\u003d\"$1\"\n if [[ \"$short_path\" \u003d\u003d ../* ]]; then\n echo \"$execroot/$BAZEL_BINDIR/external/${short_path:3}\"\n else\n echo \"$execroot/$BAZEL_BINDIR/$short_path\"\n fi\n}\n\nfunction resolve_execroot_src_path {\n local short_path\u003d\"$1\"\n if [[ \"$short_path\" \u003d\u003d ../* ]]; then\n echo \"$execroot/external/${short_path:3}\"\n else\n echo \"$execroot/$short_path\"\n fi\n}\n\n# Resolve a toolchain file that is a file of this workspace or another repository\n# in the runfiles tree, or an absolute path a user set in node_toolchain.\nfunction resolve_toolchain_path {\n local file\n file\u003d\"$(_normalize_path \"$1\")\"\n if [ \"${file:0:1}\" \u003d \"/\" ]; then\n echo \"$file\"\n elif [ \"${JS_BINARY__NO_RUNFILES:-}\" ]; then\n resolve_execroot_src_path \"$file\"\n else\n echo \"$JS_BINARY__RUNFILES/{{workspace_name}}/$file\"\n fi\n}\n\n# Everything below is resolved here only because node needs it on its command line\n# or bash needs it to start node at all. The checks that can wait, and the rest of\n# the environment the program sees, are done by the launcher preload once node is up.\n\nif [ \"${JS_BINARY__USE_EXECROOT_ENTRY_POINT:-}\" ] || [ \"${JS_BINARY__NO_RUNFILES:-}\" ]; then\n entry_point\u003d$(resolve_execroot_bin_path \"{{entry_point_path}}\")\nelse\n entry_point\u003d\"$JS_BINARY__RUNFILES/{{workspace_name}}/{{entry_point_path}}\"\nfi\n\nexport JS_BINARY__NODE_BINARY\nJS_BINARY__NODE_BINARY\u003d$(resolve_toolchain_path \"{{node}}\")\nif [ ! -f \"$JS_BINARY__NODE_BINARY\" ]; then\n log_fatal \"node binary \u0027$JS_BINARY__NODE_BINARY\u0027 not found\"\n exit 1\nfi\nif [ \"$_IS_WINDOWS\" -ne \"1\" ] \u0026\u0026 [ ! -x \"$JS_BINARY__NODE_BINARY\" ]; then\n log_fatal \"node binary \u0027$JS_BINARY__NODE_BINARY\u0027 is not executable\"\n exit 1\nfi\n\nnpm\u003d\"{{npm}}\"\nif [ \"$npm\" ]; then\n export JS_BINARY__NPM_BINARY\n JS_BINARY__NPM_BINARY\u003d$(resolve_toolchain_path \"$npm\")\nfi\n\nlauncher\u003d$(resolve_toolchain_path \"{{launcher}}\")\nif [ ! -f \"$launcher\" ]; then\n log_fatal \"launcher \u0027$launcher\u0027 not found\"\n exit 1\nfi\n\n# Gather node options\nJS_BINARY__NODE_OPTIONS\u003d()\n{{node_options}}\n\nARGS\u003d()\nALL_ARGS\u003d({{fixed_args}} \"$@\")\nfor ARG in ${ALL_ARGS[@]+\"${ALL_ARGS[@]}\"}; do\n case \"$ARG\" in\n # Let users pass through arguments to node itself\n --node_options\u003d*) JS_BINARY__NODE_OPTIONS+\u003d(\"${ARG#--node_options\u003d}\") ;;\n # Remaining argv is collected to pass to the program\n *) ARGS+\u003d(\"$ARG\") ;;\n esac\ndone\n\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n# Run the main program\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\n# Invoke node directly rather than through $JS_BINARY__NODE_WRAPPER. This way\n# we avoid spawning an extra bash process on every launch. The wrapper is\n# still put on the PATH as `node` so that child processes get the patched\n# runtime.\nnode_cmd\u003d(\"$JS_BINARY__NODE_BINARY\" --require \"$launcher\")\n\nif [ \"${JS_BINARY__LOG_INFO:-}\" ]; then\n log_info \"$(echo -n \"running\" \"${node_cmd[@]}\" ${JS_BINARY__NODE_OPTIONS[@]+\"${JS_BINARY__NODE_OPTIONS[@]}\"} -- \"$entry_point\" ${ARGS[@]+\"${ARGS[@]}\"})\"\nfi\n\n# De-export capture-related vars so child processes (e.g. a nested js_binary)\n# do not inherit them. The bash script has already consumed them above to set up\n# STDOUT_CAPTURE / STDERR_CAPTURE; leaking them would cause a nested js_binary\n# to silently swallow its own stdout or write to the wrong output file.\n# export -n keeps the value accessible to the _exit trap while removing it from\n# the environment seen by node and any processes it spawns.\nexport -n JS_BINARY__STDOUT_OUTPUT_FILE JS_BINARY__STDERR_OUTPUT_FILE JS_BINARY__EXIT_CODE_OUTPUT_FILE JS_BINARY__SILENT_ON_SUCCESS\n\nset +e\n\nif [ -z \"${JS_BINARY__EXPECTED_EXIT_CODE:-}\" ] \u0026\u0026 [ -z \"${JS_BINARY__EXIT_CODE_OUTPUT_FILE:-}\" ] \u0026\u0026\n [ -z \"${STDOUT_CAPTURE_IS_TEMP:-}\" ] \u0026\u0026 [ -z \"${STDERR_CAPTURE_IS_TEMP:-}\" ]; then\n # Nothing must run after node exits, so replace this shell with node. Signals\n # and terminal control are then delivered directly to node instead of being\n # proxied through a backgrounded child.\n if [ \"${STDOUT_CAPTURE:-}\" ]; then\n exec 1\u003e\u003e\"$STDOUT_CAPTURE\"\n fi\n if [ \"${STDERR_CAPTURE:-}\" ]; then\n exec 2\u003e\u003e\"$STDERR_CAPTURE\"\n fi\n exec \"${node_cmd[@]}\" ${JS_BINARY__NODE_OPTIONS[@]+\"${JS_BINARY__NODE_OPTIONS[@]}\"} -- \"$entry_point\" ${ARGS[@]+\"${ARGS[@]}\"}\n exit 127\nfi\n\nif [ \"${STDOUT_CAPTURE:-}\" ] \u0026\u0026 [ \"${STDERR_CAPTURE:-}\" ]; then\n \"${node_cmd[@]}\" ${JS_BINARY__NODE_OPTIONS[@]+\"${JS_BINARY__NODE_OPTIONS[@]}\"} -- \"$entry_point\" ${ARGS[@]+\"${ARGS[@]}\"} \u003c\u00260 \u003e\u003e\"$STDOUT_CAPTURE\" 2\u003e\u003e\"$STDERR_CAPTURE\" \u0026\nelif [ \"${STDOUT_CAPTURE:-}\" ]; then\n \"${node_cmd[@]}\" ${JS_BINARY__NODE_OPTIONS[@]+\"${JS_BINARY__NODE_OPTIONS[@]}\"} -- \"$entry_point\" ${ARGS[@]+\"${ARGS[@]}\"} \u003c\u00260 \u003e\u003e\"$STDOUT_CAPTURE\" \u0026\nelif [ \"${STDERR_CAPTURE:-}\" ]; then\n \"${node_cmd[@]}\" ${JS_BINARY__NODE_OPTIONS[@]+\"${JS_BINARY__NODE_OPTIONS[@]}\"} -- \"$entry_point\" ${ARGS[@]+\"${ARGS[@]}\"} \u003c\u00260 2\u003e\u003e\"$STDERR_CAPTURE\" \u0026\nelse\n \"${node_cmd[@]}\" ${JS_BINARY__NODE_OPTIONS[@]+\"${JS_BINARY__NODE_OPTIONS[@]}\"} -- \"$entry_point\" ${ARGS[@]+\"${ARGS[@]}\"} \u003c\u00260 \u0026\nfi\n\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n# Wait for program to finish\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\nreadonly child\u003d$!\n# Bash does not forward termination signals to any child process when\n# running in docker, so we need to manually trap and forward the signals.\n#\n# Each trap is reset as it fires, so that a repeat of that signal terminates this\n# script rather than being swallowed.\n_term() { trap - SIGTERM; kill -TERM \"${child}\" 2\u003e/dev/null; }\n_int() { trap - SIGINT; kill -INT \"${child}\" 2\u003e/dev/null; }\ntrap _term SIGTERM\ntrap _int SIGINT\n\n# A wait returns as soon as a trapped signal has been handled, whether or not the\n# child has exited, so keep waiting until it has.\nwait \"$child\"\nRESULT\u003d\"$?\"\nwhile kill -0 \"$child\" 2\u003e/dev/null; do\n wait \"$child\"\n RESULT\u003d\"$?\"\ndone\n\n# Remove traps now that the child process has exited\ntrap - SIGTERM SIGINT\nset -e\n\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n# Mop up after main program\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\nif [ \"${JS_BINARY__EXPECTED_EXIT_CODE:-}\" ]; then\n if [ \"$RESULT\" !\u003d \"$JS_BINARY__EXPECTED_EXIT_CODE\" ]; then\n log_error \"expected exit code to be \u0027$JS_BINARY__EXPECTED_EXIT_CODE\u0027, but got \u0027$RESULT\u0027\"\n if [ $RESULT -eq 0 ]; then\n # This exit code is handled specially by Bazel:\n # https://github.com/bazelbuild/bazel/blob/486206012a664ecb20bdb196a681efc9a9825049/src/main/java/com/google/devtools/build/lib/util/ExitCode.java#L44\n readonly BAZEL_EXIT_TESTS_FAILED\u003d3\n exit $BAZEL_EXIT_TESTS_FAILED\n fi\n exit $RESULT\n else\n exit 0\n fi\nfi\n\nif [ \"${JS_BINARY__EXIT_CODE_OUTPUT_FILE:-}\" ]; then\n # Exit zero if the exit code was captured\n echo -n \"$RESULT\" \u003e\"$JS_BINARY__EXIT_CODE_OUTPUT_FILE\"\n exit 0\nelse\n exit $RESULT\nfi\n", + "substitutions": [{ + "key": "{{target_label}}", + "value": "@@aspect_rules_ts++typescript+npm_typescript//:validator" + }, { + "key": "{{template_label}}", + "value": "@@aspect_rules_js+//js/private:js_binary.sh.tpl" + }, { + "key": "{{entry_point_label}}", + "value": "@@aspect_rules_ts++typescript+npm_typescript//:copy_validator" + }, { + "key": "{{entry_point_path}}", + "value": "../aspect_rules_ts++typescript+npm_typescript/ts_project_options_validator.cjs" + }, { + "key": "{{envs}}", + "value": "export JS_BINARY__BINDIR\u003d\"bazel-out/k8-opt-exec-ST-d57f47055a04/bin\"\nexport JS_BINARY__COMPILATION_MODE\u003d\"opt\"\nexport JS_BINARY__TARGET_CPU\u003d\"k8\"\nexport JS_BINARY__BUILD_FILE_PATH\u003d\"BUILD.bazel\"\nexport JS_BINARY__PACKAGE\u003d\"\"\nexport JS_BINARY__TARGET_NAME\u003d\"validator\"\nexport JS_BINARY__TARGET\u003d\"@aspect_rules_ts++typescript+npm_typescript//:validator\"\nexport JS_BINARY__WORKSPACE\u003d\"_main\"\nif [[ -z \"${JS_BINARY__PATCH_NODE_FS:-}\" ]]; then export JS_BINARY__PATCH_NODE_FS\u003d\"1\"; fi\nexport JS_BINARY__COPY_DATA_TO_BIN\u003d\"1\"\nif [[ -z \"${JS_BINARY__LOG_FATAL:-}\" ]]; then export JS_BINARY__LOG_FATAL\u003d\"1\"; fi\nif [[ -z \"${JS_BINARY__LOG_ERROR:-}\" ]]; then export JS_BINARY__LOG_ERROR\u003d\"1\"; fi" + }, { + "key": "{{fixed_args}}" + }, { + "key": "{{initialize_runfiles}}", + "value": "\n# It helps to determine if we are running on a Windows environment (excludes WSL as it acts like Unix)\ncase \"$(uname -s)\" in\nCYGWIN*) _IS_WINDOWS\u003d1 ;;\nMINGW*) _IS_WINDOWS\u003d1 ;;\nMSYS_NT*) _IS_WINDOWS\u003d1 ;;\n*) _IS_WINDOWS\u003d0 ;;\nesac\n\n# It helps to normalizes paths when running on Windows.\n#\n# Example:\n# C:/Users/XUser/_bazel_XUser/7q7kkv32/execroot/A/b/C -\u003e /c/Users/XUser/_bazel_XUser/7q7kkv32/execroot/A/b/C\nfunction _normalize_path {\n if [ \"$_IS_WINDOWS\" -eq \"1\" ]; then\n # Apply the followings paths transformations to normalize paths on Windows\n # -process driver letter\n # -convert path separator\n sed -e \u0027s#^\\(.\\):#/\\L\\1#\u0027 -e \u0027s#\\\\#/#g\u0027 \u003c\u003c\u003c\"$1\"\n else\n echo \"$1\"\n fi\n return\n}\n\n# Set a RUNFILES environment variable to the root of the runfiles tree\n# since RUNFILES_DIR is not set by Bazel in all contexts.\n# For example, `RUNFILES\u003d/path/to/my_js_binary.sh.runfiles`.\n#\n# Call this program X. X was generated by a genrule and may be invoked\n# in many ways:\n# 1a) directly by a user, with $0 in the output tree\n# 1b) via \u0027bazel run\u0027 (similar to case 1a)\n# 2) directly by a user, with $0 in X\u0027s runfiles\n# 3) by another program Y which has a data dependency on X, with $0 in Y\u0027s\n# runfiles\n# 4a) via \u0027bazel test\u0027\n# 4b) case 3 in the context of a test\n# 5a) by a genrule cmd, with $0 in the output tree\n# 6a) case 3 in the context of a genrule\n#\n# For case 1, $0 will be a regular file, and the runfiles will be\n# at $0.runfiles.\n# For case 2 or 3, $0 will be a symlink to the file seen in case 1.\n# For case 4, $TEST_SRCDIR should already be set to the runfiles by\n# blaze.\n# Case 5a is handled like case 1.\n# Case 6a is handled like case 3.\nif [ \"${TEST_SRCDIR:-}\" ]; then\n # Case 4, bazel has identified runfiles for us.\n RUNFILES\u003d$(_normalize_path \"$TEST_SRCDIR\")\nelif [ \"${RUNFILES_MANIFEST_FILE:-}\" ]; then\n RUNFILES\u003d$(_normalize_path \"$RUNFILES_MANIFEST_FILE\")\n if [[ \"${RUNFILES}\" \u003d\u003d *.runfiles_manifest ]]; then\n # Bazel puts the manifest besides the runfiles with the suffix .runfiles_manifest.\n # For example, the runfiles directory is named my_binary.runfiles then the manifest is beside the\n # runfiles directory and named my_binary.runfiles_manifest\n RUNFILES\u003d${RUNFILES%_manifest}\n elif [[ \"${RUNFILES}\" \u003d\u003d */MANIFEST ]]; then\n # Bazel for windows puts the manifest file named MANIFEST in the runfiles directory\n RUNFILES\u003d${RUNFILES%/MANIFEST}\n else\n log_fatal \"Unexpected RUNFILES_MANIFEST_FILE value $RUNFILES_MANIFEST_FILE\"\n exit 1\n fi\nelse\n case \"$0\" in\n /*) self\u003d\"$0\" ;;\n *) self\u003d\"$PWD/$0\" ;;\n esac\n while true; do\n if [ -e \"$self.runfiles\" ]; then\n RUNFILES\u003d\"$self.runfiles\"\n break\n fi\n\n if [[ \"$self\" \u003d\u003d *.runfiles/* ]]; then\n RUNFILES\u003d\"${self%%.runfiles/*}.runfiles\"\n # don\u0027t break; this is a last resort for case 6b\n fi\n\n if [ ! -L \"$self\" ]; then\n break\n fi\n\n readlink\u003d\"$(readlink \"$self\")\"\n if [[ \"$readlink\" \u003d\u003d /* ]]; then\n self\u003d\"$readlink\"\n else\n # resolve relative symlink\n self\u003d\"${self%%/*}/$readlink\"\n fi\n done\n\n if [ -z \"${RUNFILES:-}\" ]; then\n log_fatal \"RUNFILES environment variable is not set\"\n exit 1\n fi\n\n RUNFILES\u003d$(_normalize_path \"$RUNFILES\")\nfi\nif [ \"${RUNFILES:0:1}\" !\u003d \"/\" ]; then\n # Ensure RUNFILES set above is an absolute path. It may be a path relative\n # to the PWD in case where RUNFILES_MANIFEST_FILE is used above.\n RUNFILES\u003d\"$PWD/$RUNFILES\"\nfi\n# Set RUNFILES_DIR if not already set so that tools such as @bazel/runfiles\n# can locate runfiles without requiring RUNFILES to be exported.\nexport RUNFILES_DIR\u003d\"${RUNFILES_DIR:-$RUNFILES}\"\n" + }, { + "key": "{{log_prefix_rule_set}}", + "value": "aspect_rules_js" + }, { + "key": "{{log_prefix_rule}}", + "value": "js_binary" + }, { + "key": "{{launcher}}", + "value": "../aspect_rules_js+/js/private/node-bootstrap/launcher.cjs" + }, { + "key": "{{node_options}}", + "value": "JS_BINARY__NODE_OPTIONS+\u003d(\"--preserve-symlinks-main\")" + }, { + "key": "{{node}}", + "value": "../rules_nodejs++node+nodejs_linux_amd64/bin/nodejs/bin/node" + }, { + "key": "{{npm}}" + }, { + "key": "{{workspace_name}}", + "value": "_main" + }] + }, { + "targetId": 9, + "actionKey": "bec6c834996de644e591e6008973b7e4952fba4a55a4ac5576c35cab841b5b2f", + "mnemonic": "RepoMappingManifest", + "configurationId": 3, + "outputIds": [90], + "primaryOutputId": 90, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 9, + "actionKey": "13d51e1fac28ddc9aca91b290ea8733ba5d35a33c7904c0df272ebf35cd12613", + "mnemonic": "SourceSymlinkManifest", + "configurationId": 3, + "inputDepSetIds": [43], + "outputIds": [91], + "primaryOutputId": 91, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 9, + "actionKey": "6f39b35c51abc0e698bc3153a3b074c18e08c2f6d3da4848388f8c84f2496ad3", + "mnemonic": "SymlinkTree", + "configurationId": 3, + "inputDepSetIds": [56], + "outputIds": [92], + "primaryOutputId": 92, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 9, + "actionKey": "709e80c88487a2411e1ee4dfb9f22a861492d20c4765150c0c794abd70f8147c", + "mnemonic": "Middleman", + "configurationId": 3, + "inputDepSetIds": [57], + "outputIds": [59], + "primaryOutputId": 59, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 10, + "actionKey": "fb5c7b1c9a26625c8867bbd46f6c4f5127737e5707afa60793261903642e0c81", + "mnemonic": "TemplateExpand", + "configurationId": 3, + "inputDepSetIds": [42], + "outputIds": [65], + "primaryOutputId": 65, + "executionPlatform": "@@platforms//host:host", + "templateContent": "#!/usr/bin/env bash\n\n# This bash script is a wrapper around the NodeJS JavaScript file\n# entry point with the following bazel label:\n# {{entry_point_label}}\n#\n# The script\u0027s was generated to execute the js_binary target\n# {{target_label}}\n#\n# The template used to generate this script is\n# {{template_label}}\n\nset -o pipefail -o errexit -o nounset\n\n{{envs}}\n\n# If PATH was not provided, then it is important to export it here so that child\n# processes get the default value generated by bash.\nexport PATH\n\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n# Handle --bazel-bindir flag\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\n# If a --bazel-bindir \u003cpath\u003e flag is passed it must be the first two\n# arguments. It is consumed by this launcher script and used to set\n# BAZEL_BINDIR, overriding any value already set in the environment.\nif [ $# -gt 0 ] \u0026\u0026 [ \"$1\" \u003d \"--bazel-bindir\" ]; then\n if [ $# -lt 2 ]; then\n echo \"ERROR: --bazel-bindir flag requires a value\" \u003e\u00262\n exit 1\n fi\n BAZEL_BINDIR\u003d\"$2\"\n export BAZEL_BINDIR\n shift 2\nfi\n\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n# Prepare stdout capture, stderr capture \u0026\u0026 logging\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\n# Convert stdout, stderr and exit_code capture outputs paths to absolute paths.\n# A path not starting with \"bazel-out/\" is relative to the bin directory; joining\n# it with BAZEL_BINDIR here (rather than baking in bazel-out/\u003cconfig\u003e/bin at\n# analysis time) keeps it correct when path mapping is active. This must happen\n# before any directory changes below since it resolves against $PWD.\nfunction resolve_capture_path {\n case \"$1\" in\n bazel-out/*) echo \"$PWD/$1\" ;;\n *) echo \"$PWD/$BAZEL_BINDIR/$1\" ;;\n esac\n}\n\n# TODO(4.0): remove support for capturing stderr, stdout, and exit code. The\n# js_run_binary macro now handles this in a way that does not require help from\n# the launcher.\nif [ \"${JS_BINARY__STDOUT_OUTPUT_FILE:-}\" ]; then\n JS_BINARY__STDOUT_OUTPUT_FILE\u003d\"$(resolve_capture_path \"$JS_BINARY__STDOUT_OUTPUT_FILE\")\"\nfi\nif [ \"${JS_BINARY__STDERR_OUTPUT_FILE:-}\" ]; then\n JS_BINARY__STDERR_OUTPUT_FILE\u003d\"$(resolve_capture_path \"$JS_BINARY__STDERR_OUTPUT_FILE\")\"\nfi\nif [ \"${JS_BINARY__EXIT_CODE_OUTPUT_FILE:-}\" ]; then\n JS_BINARY__EXIT_CODE_OUTPUT_FILE\u003d\"$(resolve_capture_path \"$JS_BINARY__EXIT_CODE_OUTPUT_FILE\")\"\nfi\n\n# A stream with a declared output file is written straight to that file so that\n# nothing has to run after node exits and this shell can exec node.\n#\n# A stream that is only subject to silent_on_success has no final destination, so\n# it is buffered in a temp file and replayed on failure.\nif [ \"${JS_BINARY__STDOUT_OUTPUT_FILE:-}\" ]; then\n STDOUT_CAPTURE\u003d\"$JS_BINARY__STDOUT_OUTPUT_FILE\"\nelif [ \"${JS_BINARY__SILENT_ON_SUCCESS:-}\" ]; then\n STDOUT_CAPTURE\u003d$(mktemp)\n STDOUT_CAPTURE_IS_TEMP\u003d1\nfi\n\nif [ \"${JS_BINARY__STDERR_OUTPUT_FILE:-}\" ]; then\n STDERR_CAPTURE\u003d\"$JS_BINARY__STDERR_OUTPUT_FILE\"\nelif [ \"${JS_BINARY__SILENT_ON_SUCCESS:-}\" ]; then\n STDERR_CAPTURE\u003d$(mktemp)\n STDERR_CAPTURE_IS_TEMP\u003d1\nfi\n\n# FATAL and ERROR diagnostics from this launcher only go into the stderr capture\n# if that capture is a temp file that will get replayed on failure. Otherwise,\n# we write these straight to stderr so that they do not get lost if the action\n# fails.\nLOG_ERROR_CAPTURE\u003d\"${STDERR_CAPTURE_IS_TEMP:+$STDERR_CAPTURE}\"\n\nexport JS_BINARY__LOG_PREFIX\u003d\"{{log_prefix_rule_set}}[{{log_prefix_rule}}]\"\n\n# Emit a log line to $1, or to the real stderr when $1 is empty.\nfunction log_to {\n local capture\u003d\"$1\"\n local level\u003d\"$2\"\n local message\u003d\"$3\"\n if [ \"$capture\" ]; then\n printf \"%s: %s: %s\\n\" \"$level\" \"$JS_BINARY__LOG_PREFIX\" \"$message\" \u003e\u003e\"$capture\"\n else\n printf \"%s: %s: %s\\n\" \"$level\" \"$JS_BINARY__LOG_PREFIX\" \"$message\" \u003e\u00262\n fi\n}\n\nfunction log_fatal {\n if [ \"${JS_BINARY__LOG_FATAL:-}\" ]; then\n log_to \"${LOG_ERROR_CAPTURE:-}\" FATAL \"$1\"\n fi\n}\n\nfunction log_error {\n if [ \"${JS_BINARY__LOG_ERROR:-}\" ]; then\n log_to \"${LOG_ERROR_CAPTURE:-}\" ERROR \"$1\"\n fi\n}\n\nfunction log_info {\n if [ \"${JS_BINARY__LOG_INFO:-}\" ]; then\n log_to \"${STDERR_CAPTURE:-}\" INFO \"$1\"\n fi\n}\n\nfunction log_debug {\n if [ \"${JS_BINARY__LOG_DEBUG:-}\" ]; then\n log_to \"${STDERR_CAPTURE:-}\" DEBUG \"$1\"\n fi\n}\n\n_exit() {\n EXIT_CODE\u003d$?\n\n # Streams captured to a declared output file were written there directly and\n # need no mop up. Only the temp files that back silent_on_success do.\n if [ \"${STDERR_CAPTURE_IS_TEMP:-}\" ]; then\n if [ \"$EXIT_CODE\" !\u003d 0 ] || [ -z \"${JS_BINARY__SILENT_ON_SUCCESS:-}\" ]; then\n cat \"$STDERR_CAPTURE\" \u003e\u00262\n fi\n rm \"$STDERR_CAPTURE\"\n fi\n\n if [ \"${STDOUT_CAPTURE_IS_TEMP:-}\" ]; then\n if [ \"$EXIT_CODE\" !\u003d 0 ] || [ -z \"${JS_BINARY__SILENT_ON_SUCCESS:-}\" ]; then\n cat \"$STDOUT_CAPTURE\"\n fi\n rm \"$STDOUT_CAPTURE\"\n fi\n\n log_debug \"exit code: $EXIT_CODE\"\n\n exit \"$EXIT_CODE\"\n}\n\ntrap _exit EXIT\n\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n# Initialize RUNFILES environment variable\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n{{initialize_runfiles}}\nJS_BINARY__RUNFILES\u003d\"$RUNFILES\"\nexport JS_BINARY__RUNFILES\n\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n# Prepare to run main program\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\n# The execroot the entry point is resolved against below. A parent js_binary process hands its\n# own down when it asks for an execroot entry point, because the entry point it resolved is in\n# that tree; otherwise this script was started in it. Nothing else here needs an execroot: the\n# launcher preload works out JS_BINARY__EXECROOT for the program and everything it spawns.\nif [ \"${JS_BINARY__USE_EXECROOT_ENTRY_POINT:-}\" ] \u0026\u0026 [ \"${JS_BINARY__EXECROOT:-}\" ]; then\n execroot\u003d\"$JS_BINARY__EXECROOT\"\nelse\n execroot\u003d\"$PWD\"\nfi\n\n# Build actions are started in the execroot, so change into the root of the Bazel output tree,\n# which is where js_binary programs run. See\n# https://github.com/aspect-build/rules_js/tree/dbb5af0d2a9a2bb50e4cf4a96dbc582b27567155#running-nodejs-programs\n# for more context on why we do this. It cannot wait for the preload: node resolves the bare\n# specifier of a --require in node_options against the directory it was started in.\n#\n# The bindir is only there to change into when this really is an execroot; in a runfiles tree,\n# or in a nested js_binary already running in the bindir, there is nothing to do. The preload\n# tells those apart from the broken case by JS_BINARY__CHANGED_TO_BINDIR.\nif [ -z \"${JS_BINARY__NO_CD_BINDIR:-}\" ] \u0026\u0026 [ \"${BAZEL_BINDIR:-}\" ] \u0026\u0026 [ -d \"$PWD/$BAZEL_BINDIR\" ]; then\n log_debug \"changing directory to BAZEL_BINDIR (root of Bazel output tree) $BAZEL_BINDIR\"\n export JS_BINARY__CHANGED_TO_BINDIR\u003d1\n cd \"$BAZEL_BINDIR\"\nfi\n\nif [ \"${JS_BINARY__USE_EXECROOT_ENTRY_POINT:-}\" ] \u0026\u0026 [ -z \"${BAZEL_BINDIR:-}\" ]; then\n log_fatal \"Expected BAZEL_BINDIR to be set when JS_BINARY__USE_EXECROOT_ENTRY_POINT is set\"\n exit 1\nfi\n\nfunction resolve_execroot_bin_path {\n local short_path\u003d\"$1\"\n if [[ \"$short_path\" \u003d\u003d ../* ]]; then\n echo \"$execroot/$BAZEL_BINDIR/external/${short_path:3}\"\n else\n echo \"$execroot/$BAZEL_BINDIR/$short_path\"\n fi\n}\n\nfunction resolve_execroot_src_path {\n local short_path\u003d\"$1\"\n if [[ \"$short_path\" \u003d\u003d ../* ]]; then\n echo \"$execroot/external/${short_path:3}\"\n else\n echo \"$execroot/$short_path\"\n fi\n}\n\n# Resolve a toolchain file that is a file of this workspace or another repository\n# in the runfiles tree, or an absolute path a user set in node_toolchain.\nfunction resolve_toolchain_path {\n local file\n file\u003d\"$(_normalize_path \"$1\")\"\n if [ \"${file:0:1}\" \u003d \"/\" ]; then\n echo \"$file\"\n elif [ \"${JS_BINARY__NO_RUNFILES:-}\" ]; then\n resolve_execroot_src_path \"$file\"\n else\n echo \"$JS_BINARY__RUNFILES/{{workspace_name}}/$file\"\n fi\n}\n\n# Everything below is resolved here only because node needs it on its command line\n# or bash needs it to start node at all. The checks that can wait, and the rest of\n# the environment the program sees, are done by the launcher preload once node is up.\n\nif [ \"${JS_BINARY__USE_EXECROOT_ENTRY_POINT:-}\" ] || [ \"${JS_BINARY__NO_RUNFILES:-}\" ]; then\n entry_point\u003d$(resolve_execroot_bin_path \"{{entry_point_path}}\")\nelse\n entry_point\u003d\"$JS_BINARY__RUNFILES/{{workspace_name}}/{{entry_point_path}}\"\nfi\n\nexport JS_BINARY__NODE_BINARY\nJS_BINARY__NODE_BINARY\u003d$(resolve_toolchain_path \"{{node}}\")\nif [ ! -f \"$JS_BINARY__NODE_BINARY\" ]; then\n log_fatal \"node binary \u0027$JS_BINARY__NODE_BINARY\u0027 not found\"\n exit 1\nfi\nif [ \"$_IS_WINDOWS\" -ne \"1\" ] \u0026\u0026 [ ! -x \"$JS_BINARY__NODE_BINARY\" ]; then\n log_fatal \"node binary \u0027$JS_BINARY__NODE_BINARY\u0027 is not executable\"\n exit 1\nfi\n\nnpm\u003d\"{{npm}}\"\nif [ \"$npm\" ]; then\n export JS_BINARY__NPM_BINARY\n JS_BINARY__NPM_BINARY\u003d$(resolve_toolchain_path \"$npm\")\nfi\n\nlauncher\u003d$(resolve_toolchain_path \"{{launcher}}\")\nif [ ! -f \"$launcher\" ]; then\n log_fatal \"launcher \u0027$launcher\u0027 not found\"\n exit 1\nfi\n\n# Gather node options\nJS_BINARY__NODE_OPTIONS\u003d()\n{{node_options}}\n\nARGS\u003d()\nALL_ARGS\u003d({{fixed_args}} \"$@\")\nfor ARG in ${ALL_ARGS[@]+\"${ALL_ARGS[@]}\"}; do\n case \"$ARG\" in\n # Let users pass through arguments to node itself\n --node_options\u003d*) JS_BINARY__NODE_OPTIONS+\u003d(\"${ARG#--node_options\u003d}\") ;;\n # Remaining argv is collected to pass to the program\n *) ARGS+\u003d(\"$ARG\") ;;\n esac\ndone\n\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n# Run the main program\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\n# Invoke node directly rather than through $JS_BINARY__NODE_WRAPPER. This way\n# we avoid spawning an extra bash process on every launch. The wrapper is\n# still put on the PATH as `node` so that child processes get the patched\n# runtime.\nnode_cmd\u003d(\"$JS_BINARY__NODE_BINARY\" --require \"$launcher\")\n\nif [ \"${JS_BINARY__LOG_INFO:-}\" ]; then\n log_info \"$(echo -n \"running\" \"${node_cmd[@]}\" ${JS_BINARY__NODE_OPTIONS[@]+\"${JS_BINARY__NODE_OPTIONS[@]}\"} -- \"$entry_point\" ${ARGS[@]+\"${ARGS[@]}\"})\"\nfi\n\n# De-export capture-related vars so child processes (e.g. a nested js_binary)\n# do not inherit them. The bash script has already consumed them above to set up\n# STDOUT_CAPTURE / STDERR_CAPTURE; leaking them would cause a nested js_binary\n# to silently swallow its own stdout or write to the wrong output file.\n# export -n keeps the value accessible to the _exit trap while removing it from\n# the environment seen by node and any processes it spawns.\nexport -n JS_BINARY__STDOUT_OUTPUT_FILE JS_BINARY__STDERR_OUTPUT_FILE JS_BINARY__EXIT_CODE_OUTPUT_FILE JS_BINARY__SILENT_ON_SUCCESS\n\nset +e\n\nif [ -z \"${JS_BINARY__EXPECTED_EXIT_CODE:-}\" ] \u0026\u0026 [ -z \"${JS_BINARY__EXIT_CODE_OUTPUT_FILE:-}\" ] \u0026\u0026\n [ -z \"${STDOUT_CAPTURE_IS_TEMP:-}\" ] \u0026\u0026 [ -z \"${STDERR_CAPTURE_IS_TEMP:-}\" ]; then\n # Nothing must run after node exits, so replace this shell with node. Signals\n # and terminal control are then delivered directly to node instead of being\n # proxied through a backgrounded child.\n if [ \"${STDOUT_CAPTURE:-}\" ]; then\n exec 1\u003e\u003e\"$STDOUT_CAPTURE\"\n fi\n if [ \"${STDERR_CAPTURE:-}\" ]; then\n exec 2\u003e\u003e\"$STDERR_CAPTURE\"\n fi\n exec \"${node_cmd[@]}\" ${JS_BINARY__NODE_OPTIONS[@]+\"${JS_BINARY__NODE_OPTIONS[@]}\"} -- \"$entry_point\" ${ARGS[@]+\"${ARGS[@]}\"}\n exit 127\nfi\n\nif [ \"${STDOUT_CAPTURE:-}\" ] \u0026\u0026 [ \"${STDERR_CAPTURE:-}\" ]; then\n \"${node_cmd[@]}\" ${JS_BINARY__NODE_OPTIONS[@]+\"${JS_BINARY__NODE_OPTIONS[@]}\"} -- \"$entry_point\" ${ARGS[@]+\"${ARGS[@]}\"} \u003c\u00260 \u003e\u003e\"$STDOUT_CAPTURE\" 2\u003e\u003e\"$STDERR_CAPTURE\" \u0026\nelif [ \"${STDOUT_CAPTURE:-}\" ]; then\n \"${node_cmd[@]}\" ${JS_BINARY__NODE_OPTIONS[@]+\"${JS_BINARY__NODE_OPTIONS[@]}\"} -- \"$entry_point\" ${ARGS[@]+\"${ARGS[@]}\"} \u003c\u00260 \u003e\u003e\"$STDOUT_CAPTURE\" \u0026\nelif [ \"${STDERR_CAPTURE:-}\" ]; then\n \"${node_cmd[@]}\" ${JS_BINARY__NODE_OPTIONS[@]+\"${JS_BINARY__NODE_OPTIONS[@]}\"} -- \"$entry_point\" ${ARGS[@]+\"${ARGS[@]}\"} \u003c\u00260 2\u003e\u003e\"$STDERR_CAPTURE\" \u0026\nelse\n \"${node_cmd[@]}\" ${JS_BINARY__NODE_OPTIONS[@]+\"${JS_BINARY__NODE_OPTIONS[@]}\"} -- \"$entry_point\" ${ARGS[@]+\"${ARGS[@]}\"} \u003c\u00260 \u0026\nfi\n\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n# Wait for program to finish\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\nreadonly child\u003d$!\n# Bash does not forward termination signals to any child process when\n# running in docker, so we need to manually trap and forward the signals.\n#\n# Each trap is reset as it fires, so that a repeat of that signal terminates this\n# script rather than being swallowed.\n_term() { trap - SIGTERM; kill -TERM \"${child}\" 2\u003e/dev/null; }\n_int() { trap - SIGINT; kill -INT \"${child}\" 2\u003e/dev/null; }\ntrap _term SIGTERM\ntrap _int SIGINT\n\n# A wait returns as soon as a trapped signal has been handled, whether or not the\n# child has exited, so keep waiting until it has.\nwait \"$child\"\nRESULT\u003d\"$?\"\nwhile kill -0 \"$child\" 2\u003e/dev/null; do\n wait \"$child\"\n RESULT\u003d\"$?\"\ndone\n\n# Remove traps now that the child process has exited\ntrap - SIGTERM SIGINT\nset -e\n\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n# Mop up after main program\n# \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n\nif [ \"${JS_BINARY__EXPECTED_EXIT_CODE:-}\" ]; then\n if [ \"$RESULT\" !\u003d \"$JS_BINARY__EXPECTED_EXIT_CODE\" ]; then\n log_error \"expected exit code to be \u0027$JS_BINARY__EXPECTED_EXIT_CODE\u0027, but got \u0027$RESULT\u0027\"\n if [ $RESULT -eq 0 ]; then\n # This exit code is handled specially by Bazel:\n # https://github.com/bazelbuild/bazel/blob/486206012a664ecb20bdb196a681efc9a9825049/src/main/java/com/google/devtools/build/lib/util/ExitCode.java#L44\n readonly BAZEL_EXIT_TESTS_FAILED\u003d3\n exit $BAZEL_EXIT_TESTS_FAILED\n fi\n exit $RESULT\n else\n exit 0\n fi\nfi\n\nif [ \"${JS_BINARY__EXIT_CODE_OUTPUT_FILE:-}\" ]; then\n # Exit zero if the exit code was captured\n echo -n \"$RESULT\" \u003e\"$JS_BINARY__EXIT_CODE_OUTPUT_FILE\"\n exit 0\nelse\n exit $RESULT\nfi\n", + "substitutions": [{ + "key": "{{target_label}}", + "value": "@@aspect_rules_ts++typescript+npm_typescript//:tsc" + }, { + "key": "{{template_label}}", + "value": "@@aspect_rules_js+//js/private:js_binary.sh.tpl" + }, { + "key": "{{entry_point_label}}", + "value": "@@aspect_rules_ts++typescript+npm_typescript//:tsc_entrypoint" + }, { + "key": "{{entry_point_path}}", + "value": "../aspect_rules_ts++typescript+npm_typescript/node_modules/.aspect_rules_js/typescript@6.0.3/node_modules/typescript/bin/tsc" + }, { + "key": "{{envs}}", + "value": "export JS_BINARY__BINDIR\u003d\"bazel-out/k8-opt-exec-ST-d57f47055a04/bin\"\nexport JS_BINARY__COMPILATION_MODE\u003d\"opt\"\nexport JS_BINARY__TARGET_CPU\u003d\"k8\"\nexport JS_BINARY__BUILD_FILE_PATH\u003d\"BUILD.bazel\"\nexport JS_BINARY__PACKAGE\u003d\"\"\nexport JS_BINARY__TARGET_NAME\u003d\"tsc\"\nexport JS_BINARY__TARGET\u003d\"@aspect_rules_ts++typescript+npm_typescript//:tsc\"\nexport JS_BINARY__WORKSPACE\u003d\"_main\"\nif [[ -z \"${JS_BINARY__PATCH_NODE_FS:-}\" ]]; then export JS_BINARY__PATCH_NODE_FS\u003d\"1\"; fi\nexport JS_BINARY__COPY_DATA_TO_BIN\u003d\"1\"\nif [[ -z \"${JS_BINARY__LOG_FATAL:-}\" ]]; then export JS_BINARY__LOG_FATAL\u003d\"1\"; fi\nif [[ -z \"${JS_BINARY__LOG_ERROR:-}\" ]]; then export JS_BINARY__LOG_ERROR\u003d\"1\"; fi" + }, { + "key": "{{fixed_args}}" + }, { + "key": "{{initialize_runfiles}}", + "value": "\n# It helps to determine if we are running on a Windows environment (excludes WSL as it acts like Unix)\ncase \"$(uname -s)\" in\nCYGWIN*) _IS_WINDOWS\u003d1 ;;\nMINGW*) _IS_WINDOWS\u003d1 ;;\nMSYS_NT*) _IS_WINDOWS\u003d1 ;;\n*) _IS_WINDOWS\u003d0 ;;\nesac\n\n# It helps to normalizes paths when running on Windows.\n#\n# Example:\n# C:/Users/XUser/_bazel_XUser/7q7kkv32/execroot/A/b/C -\u003e /c/Users/XUser/_bazel_XUser/7q7kkv32/execroot/A/b/C\nfunction _normalize_path {\n if [ \"$_IS_WINDOWS\" -eq \"1\" ]; then\n # Apply the followings paths transformations to normalize paths on Windows\n # -process driver letter\n # -convert path separator\n sed -e \u0027s#^\\(.\\):#/\\L\\1#\u0027 -e \u0027s#\\\\#/#g\u0027 \u003c\u003c\u003c\"$1\"\n else\n echo \"$1\"\n fi\n return\n}\n\n# Set a RUNFILES environment variable to the root of the runfiles tree\n# since RUNFILES_DIR is not set by Bazel in all contexts.\n# For example, `RUNFILES\u003d/path/to/my_js_binary.sh.runfiles`.\n#\n# Call this program X. X was generated by a genrule and may be invoked\n# in many ways:\n# 1a) directly by a user, with $0 in the output tree\n# 1b) via \u0027bazel run\u0027 (similar to case 1a)\n# 2) directly by a user, with $0 in X\u0027s runfiles\n# 3) by another program Y which has a data dependency on X, with $0 in Y\u0027s\n# runfiles\n# 4a) via \u0027bazel test\u0027\n# 4b) case 3 in the context of a test\n# 5a) by a genrule cmd, with $0 in the output tree\n# 6a) case 3 in the context of a genrule\n#\n# For case 1, $0 will be a regular file, and the runfiles will be\n# at $0.runfiles.\n# For case 2 or 3, $0 will be a symlink to the file seen in case 1.\n# For case 4, $TEST_SRCDIR should already be set to the runfiles by\n# blaze.\n# Case 5a is handled like case 1.\n# Case 6a is handled like case 3.\nif [ \"${TEST_SRCDIR:-}\" ]; then\n # Case 4, bazel has identified runfiles for us.\n RUNFILES\u003d$(_normalize_path \"$TEST_SRCDIR\")\nelif [ \"${RUNFILES_MANIFEST_FILE:-}\" ]; then\n RUNFILES\u003d$(_normalize_path \"$RUNFILES_MANIFEST_FILE\")\n if [[ \"${RUNFILES}\" \u003d\u003d *.runfiles_manifest ]]; then\n # Bazel puts the manifest besides the runfiles with the suffix .runfiles_manifest.\n # For example, the runfiles directory is named my_binary.runfiles then the manifest is beside the\n # runfiles directory and named my_binary.runfiles_manifest\n RUNFILES\u003d${RUNFILES%_manifest}\n elif [[ \"${RUNFILES}\" \u003d\u003d */MANIFEST ]]; then\n # Bazel for windows puts the manifest file named MANIFEST in the runfiles directory\n RUNFILES\u003d${RUNFILES%/MANIFEST}\n else\n log_fatal \"Unexpected RUNFILES_MANIFEST_FILE value $RUNFILES_MANIFEST_FILE\"\n exit 1\n fi\nelse\n case \"$0\" in\n /*) self\u003d\"$0\" ;;\n *) self\u003d\"$PWD/$0\" ;;\n esac\n while true; do\n if [ -e \"$self.runfiles\" ]; then\n RUNFILES\u003d\"$self.runfiles\"\n break\n fi\n\n if [[ \"$self\" \u003d\u003d *.runfiles/* ]]; then\n RUNFILES\u003d\"${self%%.runfiles/*}.runfiles\"\n # don\u0027t break; this is a last resort for case 6b\n fi\n\n if [ ! -L \"$self\" ]; then\n break\n fi\n\n readlink\u003d\"$(readlink \"$self\")\"\n if [[ \"$readlink\" \u003d\u003d /* ]]; then\n self\u003d\"$readlink\"\n else\n # resolve relative symlink\n self\u003d\"${self%%/*}/$readlink\"\n fi\n done\n\n if [ -z \"${RUNFILES:-}\" ]; then\n log_fatal \"RUNFILES environment variable is not set\"\n exit 1\n fi\n\n RUNFILES\u003d$(_normalize_path \"$RUNFILES\")\nfi\nif [ \"${RUNFILES:0:1}\" !\u003d \"/\" ]; then\n # Ensure RUNFILES set above is an absolute path. It may be a path relative\n # to the PWD in case where RUNFILES_MANIFEST_FILE is used above.\n RUNFILES\u003d\"$PWD/$RUNFILES\"\nfi\n# Set RUNFILES_DIR if not already set so that tools such as @bazel/runfiles\n# can locate runfiles without requiring RUNFILES to be exported.\nexport RUNFILES_DIR\u003d\"${RUNFILES_DIR:-$RUNFILES}\"\n" + }, { + "key": "{{log_prefix_rule_set}}", + "value": "aspect_rules_js" + }, { + "key": "{{log_prefix_rule}}", + "value": "js_binary" + }, { + "key": "{{launcher}}", + "value": "../aspect_rules_js+/js/private/node-bootstrap/launcher.cjs" + }, { + "key": "{{node_options}}", + "value": "JS_BINARY__NODE_OPTIONS+\u003d(\"--preserve-symlinks-main\")" + }, { + "key": "{{node}}", + "value": "../rules_nodejs++node+nodejs_linux_amd64/bin/nodejs/bin/node" + }, { + "key": "{{npm}}" + }, { + "key": "{{workspace_name}}", + "value": "_main" + }] + }, { + "targetId": 10, + "actionKey": "12c9b1f6f544d5257dfac27c1dd0b0313c3c828a3d038baeb2859a2090ae2103", + "mnemonic": "RepoMappingManifest", + "configurationId": 3, + "outputIds": [94], + "primaryOutputId": 94, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 10, + "actionKey": "508f993cdec86653e41f1ace9feaacb9cfa1eb8d095ddc04168c89046a1ec842", + "mnemonic": "SourceSymlinkManifest", + "configurationId": 3, + "inputDepSetIds": [43], + "outputIds": [95], + "primaryOutputId": 95, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 10, + "actionKey": "1f17070e60e3bf9a9669670316b52e74d536f87222038f3a83a6a7e8a90cb6d4", + "mnemonic": "SymlinkTree", + "configurationId": 3, + "inputDepSetIds": [64], + "outputIds": [96], + "primaryOutputId": 96, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 10, + "actionKey": "709e80c88487a2411e1ee4dfb9f22a861492d20c4765150c0c794abd70f8147c", + "mnemonic": "Middleman", + "configurationId": 3, + "inputDepSetIds": [65], + "outputIds": [66], + "primaryOutputId": 66, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 11, + "actionKey": "b60fb21ac7bb21678ef821a956e2508ff691213cd659ba78f5414cd91258a278", + "mnemonic": "UnresolvedSymlink", + "configurationId": 1, + "outputIds": [64], + "primaryOutputId": 64, + "executionPlatform": "@@platforms//host:host", + "unresolvedSymlinkTarget": ".aspect_rules_js/undici-types@7.16.0/node_modules/undici-types" + }, { + "targetId": 12, + "actionKey": "e196a0eb8ceb7641c504d13dfd062102e125ba5c01264de885de0e8516275a32", + "mnemonic": "NpmPackageExtract", + "configurationId": 1, + "environmentVariables": [{ + "key": "LC_ALL", + "value": "C.UTF-8" + }], + "inputDepSetIds": [72], + "outputIds": [61], + "executionInfo": [{ + "key": "supports-path-mapping", + "value": "1" + }], + "primaryOutputId": 61, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 13, + "actionKey": "c24bdb15c475ca888636662e24d9a20c43e6a0b85f35e1b0503dc6bc95ef5351", + "mnemonic": "FileWrite", + "configurationId": 3, + "outputIds": [81], + "primaryOutputId": 81, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 14, + "actionKey": "4d9f7a6fa4b2d6886c15eff907d69edd61b690860173627ee16c1e9beb1cf1ab", + "mnemonic": "UnresolvedSymlink", + "configurationId": 3, + "outputIds": [76], + "primaryOutputId": 76, + "executionPlatform": "@@platforms//host:host", + "unresolvedSymlinkTarget": ".aspect_rules_js/typescript@6.0.3/node_modules/typescript" + }, { + "targetId": 15, + "actionKey": "7a39b61d5744a8903119e17b3ddc7e56e330f240d2bead98c3ba081a81b5c9ac", + "mnemonic": "Symlink", + "configurationId": 3, + "inputDepSetIds": [73], + "outputIds": [82], + "primaryOutputId": 82, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 16, + "actionKey": "808d3dd8e3b7822833218c13dca70010d16f0a1d05e17e459ed5f277c8a3df49", + "mnemonic": "NpmPackageExtract", + "configurationId": 1, + "environmentVariables": [{ + "key": "LC_ALL", + "value": "C.UTF-8" + }], + "inputDepSetIds": [74], + "outputIds": [63], + "executionInfo": [{ + "key": "supports-path-mapping", + "value": "1" + }], + "primaryOutputId": 63, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 17, + "actionKey": "7a39b61d5744a8903119e17b3ddc7e56e330f240d2bead98c3ba081a81b5c9ac", + "mnemonic": "Symlink", + "configurationId": 3, + "inputDepSetIds": [75], + "outputIds": [80], + "primaryOutputId": 80, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 18, + "actionKey": "7a39b61d5744a8903119e17b3ddc7e56e330f240d2bead98c3ba081a81b5c9ac", + "mnemonic": "Symlink", + "configurationId": 3, + "inputDepSetIds": [76], + "outputIds": [93], + "primaryOutputId": 93, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 19, + "actionKey": "606062ce50521444fff34c66f30bc4178f53beb23bab023ae9d916101714c3f9", + "mnemonic": "CopyDirectory", + "configurationId": 3, + "environmentVariables": [{ + "key": "GODEBUG", + "value": "winsymlink\u003d0" + }], + "inputDepSetIds": [77], + "outputIds": [79], + "executionInfo": [{ + "key": "supports-path-mapping", + "value": "1" + }], + "primaryOutputId": 79, + "executionPlatform": "@@platforms//host:host" + }], + "targets": [{ + "id": 1, + "label": "//src/query/ts:shipping_package", + "ruleClassId": 1 + }, { + "id": 2, + "label": "//src/query/ts:unit_test", + "ruleClassId": 2 + }, { + "id": 3, + "label": "@@bazel_tools//tools/test:collect_coverage", + "ruleClassId": 3 + }, { + "id": 4, + "label": "//src/query/ts:npm", + "ruleClassId": 4 + }, { + "id": 5, + "label": "//src/query/ts:module", + "ruleClassId": 5 + }, { + "id": 6, + "label": "//src/query/ts:commonjs", + "ruleClassId": 5 + }, { + "id": 7, + "label": "@@aspect_rules_ts++typescript+npm_typescript//:tsc_worker", + "ruleClassId": 6 + }, { + "id": 8, + "label": "//src/query/ts:node_modules/@types/node", + "ruleClassId": 7 + }, { + "id": 9, + "label": "@@aspect_rules_ts++typescript+npm_typescript//:validator", + "ruleClassId": 6 + }, { + "id": 10, + "label": "@@aspect_rules_ts++typescript+npm_typescript//:tsc", + "ruleClassId": 6 + }, { + "id": 11, + "label": "//src/query/ts:node_modules/undici-types", + "ruleClassId": 7 + }, { + "id": 12, + "label": "//src/query/ts:.aspect_rules_js/node_modules/@types/node", + "ruleClassId": 8 + }, { + "id": 13, + "label": "@@aspect_rules_ts++typescript+npm_typescript//:package_json", + "ruleClassId": 9 + }, { + "id": 14, + "label": "@@aspect_rules_ts++typescript+npm_typescript//:node_modules/typescript", + "ruleClassId": 7 + }, { + "id": 15, + "label": "@@aspect_rules_ts++typescript+npm_typescript//:copy_ts_project_worker", + "ruleClassId": 10 + }, { + "id": 16, + "label": "//src/query/ts:.aspect_rules_js/node_modules/undici-types", + "ruleClassId": 8 + }, { + "id": 17, + "label": "@@aspect_rules_ts++typescript+npm_typescript//:copy_worker_js", + "ruleClassId": 10 + }, { + "id": 18, + "label": "@@aspect_rules_ts++typescript+npm_typescript//:copy_validator", + "ruleClassId": 10 + }, { + "id": 19, + "label": "@@aspect_rules_ts++typescript+npm_typescript//:.aspect_rules_js/node_modules/typescript", + "ruleClassId": 8 + }], + "depSetOfFiles": [{ + "id": 2, + "directArtifactIds": [3, 4, 5, 6, 7, 8, 9, 2] + }, { + "id": 1, + "transitiveDepSetIds": [2], + "directArtifactIds": [10] + }, { + "id": 3, + "directArtifactIds": [12] + }, { + "id": 4, + "directArtifactIds": [14] + }, { + "id": 5, + "directArtifactIds": [17] + }, { + "id": 8, + "directArtifactIds": [11, 4, 5, 6, 7, 8, 9, 3, 15, 12] + }, { + "id": 7, + "transitiveDepSetIds": [8], + "directArtifactIds": [13] + }, { + "id": 6, + "transitiveDepSetIds": [7], + "directArtifactIds": [18, 16] + }, { + "id": 9, + "directArtifactIds": [19, 20, 21] + }, { + "id": 10, + "directArtifactIds": [26] + }, { + "id": 11, + "directArtifactIds": [29] + }, { + "id": 14, + "directArtifactIds": [26, 27] + }, { + "id": 13, + "transitiveDepSetIds": [14], + "directArtifactIds": [27] + }, { + "id": 12, + "transitiveDepSetIds": [13], + "directArtifactIds": [30, 28] + }, { + "id": 16, + "directArtifactIds": [34, 35, 36, 33] + }, { + "id": 15, + "transitiveDepSetIds": [16], + "directArtifactIds": [10] + }, { + "id": 19, + "directArtifactIds": [38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 32, 34, 35, 36] + }, { + "id": 18, + "transitiveDepSetIds": [19], + "directArtifactIds": [37] + }, { + "id": 17, + "transitiveDepSetIds": [18], + "directArtifactIds": [12] + }, { + "id": 20, + "directArtifactIds": [4, 51] + }, { + "id": 21, + "directArtifactIds": [5, 51] + }, { + "id": 22, + "directArtifactIds": [54, 51] + }, { + "id": 23, + "directArtifactIds": [56, 51] + }, { + "id": 25, + "directArtifactIds": [55, 57] + }, { + "id": 26, + "directArtifactIds": [58, 59] + }, { + "id": 24, + "transitiveDepSetIds": [25, 26] + }, { + "id": 30, + "directArtifactIds": [61, 62] + }, { + "id": 31, + "directArtifactIds": [63, 64] + }, { + "id": 29, + "transitiveDepSetIds": [30, 31] + }, { + "id": 28, + "transitiveDepSetIds": [29, 25], + "directArtifactIds": [52, 53, 55, 57] + }, { + "id": 32, + "directArtifactIds": [65, 66] + }, { + "id": 27, + "transitiveDepSetIds": [28, 32] + }, { + "id": 33, + "directArtifactIds": [4, 51] + }, { + "id": 34, + "directArtifactIds": [5, 51] + }, { + "id": 35, + "directArtifactIds": [69, 51] + }, { + "id": 36, + "directArtifactIds": [56, 51] + }, { + "id": 38, + "directArtifactIds": [70, 71] + }, { + "id": 37, + "transitiveDepSetIds": [38, 26] + }, { + "id": 41, + "transitiveDepSetIds": [30, 31] + }, { + "id": 40, + "transitiveDepSetIds": [41, 38], + "directArtifactIds": [67, 68, 70, 71] + }, { + "id": 39, + "transitiveDepSetIds": [40, 32] + }, { + "id": 42, + "directArtifactIds": [73] + }, { + "id": 43, + "directArtifactIds": [76] + }, { + "id": 44, + "directArtifactIds": [77] + }, { + "id": 52, + "directArtifactIds": [79, 76] + }, { + "id": 51, + "transitiveDepSetIds": [52], + "directArtifactIds": [80, 81] + }, { + "id": 50, + "transitiveDepSetIds": [51], + "directArtifactIds": [82, 80, 81, 79, 76] + }, { + "id": 53, + "directArtifactIds": [79, 76] + }, { + "id": 49, + "transitiveDepSetIds": [50, 53] + }, { + "id": 54, + "directArtifactIds": [79, 76] + }, { + "id": 48, + "transitiveDepSetIds": [49, 54] + }, { + "id": 55, + "directArtifactIds": [74, 83, 84, 85, 86, 87, 88] + }, { + "id": 47, + "transitiveDepSetIds": [48, 55] + }, { + "id": 46, + "transitiveDepSetIds": [47], + "directArtifactIds": [74] + }, { + "id": 45, + "transitiveDepSetIds": [46], + "directArtifactIds": [78, 75] + }, { + "id": 56, + "directArtifactIds": [91] + }, { + "id": 62, + "transitiveDepSetIds": [52], + "directArtifactIds": [93, 79, 76] + }, { + "id": 61, + "transitiveDepSetIds": [62, 53] + }, { + "id": 60, + "transitiveDepSetIds": [61, 54] + }, { + "id": 63, + "directArtifactIds": [58, 83, 84, 85, 86, 87, 88] + }, { + "id": 59, + "transitiveDepSetIds": [60, 63] + }, { + "id": 58, + "transitiveDepSetIds": [59], + "directArtifactIds": [58] + }, { + "id": 57, + "transitiveDepSetIds": [58], + "directArtifactIds": [92, 90] + }, { + "id": 64, + "directArtifactIds": [95] + }, { + "id": 70, + "transitiveDepSetIds": [52], + "directArtifactIds": [79, 76] + }, { + "id": 69, + "transitiveDepSetIds": [70, 53] + }, { + "id": 68, + "transitiveDepSetIds": [69, 54] + }, { + "id": 71, + "directArtifactIds": [65, 83, 84, 85, 86, 87, 88] + }, { + "id": 67, + "transitiveDepSetIds": [68, 71] + }, { + "id": 66, + "transitiveDepSetIds": [67], + "directArtifactIds": [65] + }, { + "id": 65, + "transitiveDepSetIds": [66], + "directArtifactIds": [96, 94] + }, { + "id": 72, + "directArtifactIds": [97, 98] + }, { + "id": 73, + "directArtifactIds": [99] + }, { + "id": 74, + "directArtifactIds": [100, 98] + }, { + "id": 75, + "directArtifactIds": [101] + }, { + "id": 76, + "directArtifactIds": [102] + }, { + "id": 77, + "directArtifactIds": [103, 104] + }], + "configuration": [{ + "id": 1, + "mnemonic": "k8-fastbuild", + "platformName": "k8", + "checksum": "f55cd0755219b272bb7b1eeb31dd83dd10bc8c00329f25764eb9ea725eeff190" + }, { + "id": 2, + "mnemonic": "k8-fastbuild", + "platformName": "k8", + "checksum": "0db2b318338ce09df9dbfeda423511d29dd37e81a4519b8ba56a33ac4076bea9" + }, { + "id": 3, + "mnemonic": "k8-opt-exec-ST-d57f47055a04", + "platformName": "k8", + "checksum": "ed5797a767b96f3a1479df6c05824854fc306bea605a92620af0492ebf871581", + "isTool": true + }], + "ruleClasses": [{ + "id": 1, + "name": "shipping_package" + }, { + "id": 2, + "name": "_bun_test" + }, { + "id": 3, + "name": "sh_binary" + }, { + "id": 4, + "name": "query_envelope" + }, { + "id": 5, + "name": "ts_project" + }, { + "id": 6, + "name": "js_binary" + }, { + "id": 7, + "name": "npm_link_package_store" + }, { + "id": 8, + "name": "npm_package_store" + }, { + "id": 9, + "name": "_write_file" + }, { + "id": 10, + "name": "_copy_file" + }], + "pathFragments": [{ + "id": 7, + "label": "bazel-out" + }, { + "id": 6, + "label": "k8-fastbuild", + "parentId": 7 + }, { + "id": 5, + "label": "bin", + "parentId": 6 + }, { + "id": 4, + "label": "src", + "parentId": 5 + }, { + "id": 3, + "label": "query", + "parentId": 4 + }, { + "id": 2, + "label": "ts", + "parentId": 3 + }, { + "id": 1, + "label": "shipping_package.shipping.json", + "parentId": 2 + }, { + "id": 8, + "label": "unit_test.sources__main_config.json", + "parentId": 2 + }, { + "id": 13, + "label": "src" + }, { + "id": 12, + "label": "query", + "parentId": 13 + }, { + "id": 11, + "label": "ts", + "parentId": 12 + }, { + "id": 10, + "label": "test", + "parentId": 11 + }, { + "id": 9, + "label": "protocol.test.ts", + "parentId": 10 + }, { + "id": 15, + "label": "src", + "parentId": 11 + }, { + "id": 14, + "label": "protocol.ts", + "parentId": 15 + }, { + "id": 16, + "label": "query.ts", + "parentId": 15 + }, { + "id": 17, + "label": "query.test.ts", + "parentId": 10 + }, { + "id": 18, + "label": "protocol-fixtures.mts", + "parentId": 10 + }, { + "id": 21, + "label": "test-fixtures", + "parentId": 13 + }, { + "id": 20, + "label": "protocol", + "parentId": 21 + }, { + "id": 19, + "label": "query-response-cases.json", + "parentId": 20 + }, { + "id": 22, + "label": "structured-sql-cases.json", + "parentId": 20 + }, { + "id": 25, + "label": "external" + }, { + "id": 24, + "label": "bazel_lib++toolchains+copy_to_directory_linux_amd64", + "parentId": 25 + }, { + "id": 23, + "label": "copy_to_directory", + "parentId": 24 + }, { + "id": 27, + "label": "unit_test.sources", + "parentId": 2 + }, { + "id": 26, + "label": "_main", + "parentId": 27 + }, { + "id": 29, + "label": "+bun_toolchains+bun_linux_x64", + "parentId": 25 + }, { + "id": 28, + "label": "bun", + "parentId": 29 + }, { + "id": 30, + "label": "unit_test", + "parentId": 2 + }, { + "id": 33, + "label": "build_defs" + }, { + "id": 32, + "label": "foundation", + "parentId": 33 + }, { + "id": 31, + "label": "bun-test-entrypoint.mts.tpl", + "parentId": 32 + }, { + "id": 34, + "label": "unit_test.entry.mts", + "parentId": 2 + }, { + "id": 35, + "label": "unit_test.repo_mapping", + "parentId": 2 + }, { + "id": 36, + "label": "unit_test.runfiles_manifest", + "parentId": 2 + }, { + "id": 38, + "label": "unit_test.runfiles", + "parentId": 2 + }, { + "id": 37, + "label": "MANIFEST", + "parentId": 38 + }, { + "id": 41, + "label": "internal", + "parentId": 6 + }, { + "id": 40, + "label": "_middlemen", + "parentId": 41 + }, { + "id": 39, + "label": "src_Squery_Sts_Sunit_Utest-runfiles", + "parentId": 40 + }, { + "id": 45, + "label": "bazel_tools", + "parentId": 25 + }, { + "id": 44, + "label": "tools", + "parentId": 45 + }, { + "id": 43, + "label": "test", + "parentId": 44 + }, { + "id": 42, + "label": "test-setup.sh", + "parentId": 43 + }, { + "id": 46, + "label": "generate-xml.sh", + "parentId": 43 + }, { + "id": 52, + "label": "testlogs", + "parentId": 6 + }, { + "id": 51, + "label": "src", + "parentId": 52 + }, { + "id": 50, + "label": "query", + "parentId": 51 + }, { + "id": 49, + "label": "ts", + "parentId": 50 + }, { + "id": 48, + "label": "unit_test", + "parentId": 49 + }, { + "id": 47, + "label": "test.log", + "parentId": 48 + }, { + "id": 53, + "label": "test.xml", + "parentId": 48 + }, { + "id": 54, + "label": "test.cache_status", + "parentId": 48 + }, { + "id": 55, + "label": "test.outputs", + "parentId": 48 + }, { + "id": 56, + "label": "collect_coverage.sh", + "parentId": 43 + }, { + "id": 63, + "label": "k8-opt-exec-ST-d57f47055a04", + "parentId": 7 + }, { + "id": 62, + "label": "bin", + "parentId": 63 + }, { + "id": 61, + "label": "external", + "parentId": 62 + }, { + "id": 60, + "label": "bazel_tools", + "parentId": 61 + }, { + "id": 59, + "label": "tools", + "parentId": 60 + }, { + "id": 58, + "label": "test", + "parentId": 59 + }, { + "id": 57, + "label": "collect_coverage", + "parentId": 58 + }, { + "id": 64, + "label": "collect_coverage.repo_mapping", + "parentId": 58 + }, { + "id": 65, + "label": "collect_coverage.runfiles_manifest", + "parentId": 58 + }, { + "id": 67, + "label": "collect_coverage.runfiles", + "parentId": 58 + }, { + "id": 66, + "label": "MANIFEST", + "parentId": 67 + }, { + "id": 70, + "label": "internal", + "parentId": 63 + }, { + "id": 69, + "label": "_middlemen", + "parentId": 70 + }, { + "id": 68, + "label": "external_Sbazel_Utools_Stools_Stest_Scollect_Ucoverage-runfiles", + "parentId": 69 + }, { + "id": 71, + "label": "npm.entries.json", + "parentId": 2 + }, { + "id": 72, + "label": "npm.sources__main_config.json", + "parentId": 2 + }, { + "id": 74, + "label": "query", + "parentId": 33 + }, { + "id": 73, + "label": "package.mts", + "parentId": 74 + }, { + "id": 77, + "label": "tools" + }, { + "id": 76, + "label": "packaging", + "parentId": 77 + }, { + "id": 75, + "label": "archive-directory.mts", + "parentId": 76 + }, { + "id": 78, + "label": "portable-archive.mts", + "parentId": 76 + }, { + "id": 80, + "label": "npm.sources", + "parentId": 2 + }, { + "id": 79, + "label": "_main", + "parentId": 80 + }, { + "id": 81, + "label": "package.json", + "parentId": 11 + }, { + "id": 84, + "label": "dist", + "parentId": 2 + }, { + "id": 83, + "label": "module", + "parentId": 84 + }, { + "id": 82, + "label": "protocol.js", + "parentId": 83 + }, { + "id": 85, + "label": "query.js", + "parentId": 83 + }, { + "id": 86, + "label": "protocol.d.ts", + "parentId": 83 + }, { + "id": 87, + "label": "query.d.ts", + "parentId": 83 + }, { + "id": 89, + "label": "commonjs", + "parentId": 84 + }, { + "id": 88, + "label": "protocol.js", + "parentId": 89 + }, { + "id": 90, + "label": "query.js", + "parentId": 89 + }, { + "id": 91, + "label": "protocol.d.ts", + "parentId": 89 + }, { + "id": 92, + "label": "query.d.ts", + "parentId": 89 + }, { + "id": 93, + "label": "module.package.json", + "parentId": 11 + }, { + "id": 94, + "label": "README.md", + "parentId": 11 + }, { + "id": 95, + "label": "LICENSE", + "parentId": 11 + }, { + "id": 96, + "label": "oliphaunt-ts-query.tgz", + "parentId": 2 + }, { + "id": 98, + "label": "bazel_lib++toolchains+coreutils_linux_amd64", + "parentId": 25 + }, { + "id": 97, + "label": "coreutils", + "parentId": 98 + }, { + "id": 100, + "label": "src", + "parentId": 2 + }, { + "id": 99, + "label": "protocol.ts", + "parentId": 100 + }, { + "id": 101, + "label": "query.ts", + "parentId": 100 + }, { + "id": 102, + "label": "tsconfig.build.module.json", + "parentId": 11 + }, { + "id": 103, + "label": "tsconfig.build.module.json", + "parentId": 2 + }, { + "id": 104, + "label": "tsconfig.json", + "parentId": 11 + }, { + "id": 105, + "label": "tsconfig.json", + "parentId": 2 + }, { + "id": 108, + "label": "aspect_rules_ts++typescript+npm_typescript", + "parentId": 61 + }, { + "id": 107, + "label": "validator_", + "parentId": 108 + }, { + "id": 106, + "label": "validator", + "parentId": 107 + }, { + "id": 109, + "label": "external_Saspect_Urules_Uts++typescript+npm_Utypescript_Svalidator_U_Svalidator-runfiles", + "parentId": 69 + }, { + "id": 110, + "label": "module_params.validation", + "parentId": 2 + }, { + "id": 116, + "label": "node_modules", + "parentId": 2 + }, { + "id": 115, + "label": ".aspect_rules_js", + "parentId": 116 + }, { + "id": 114, + "label": "@types+node@24.12.4", + "parentId": 115 + }, { + "id": 113, + "label": "node_modules", + "parentId": 114 + }, { + "id": 112, + "label": "@types", + "parentId": 113 + }, { + "id": 111, + "label": "node", + "parentId": 112 + }, { + "id": 118, + "label": "@types", + "parentId": 116 + }, { + "id": 117, + "label": "node", + "parentId": 118 + }, { + "id": 121, + "label": "undici-types@7.16.0", + "parentId": 115 + }, { + "id": 120, + "label": "node_modules", + "parentId": 121 + }, { + "id": 119, + "label": "undici-types", + "parentId": 120 + }, { + "id": 122, + "label": "undici-types", + "parentId": 116 + }, { + "id": 124, + "label": "tsc_", + "parentId": 108 + }, { + "id": 123, + "label": "tsc", + "parentId": 124 + }, { + "id": 125, + "label": "external_Saspect_Urules_Uts++typescript+npm_Utypescript_Stsc_U_Stsc-runfiles", + "parentId": 69 + }, { + "id": 126, + "label": "tsconfig.build.commonjs.json", + "parentId": 11 + }, { + "id": 127, + "label": "tsconfig.build.commonjs.json", + "parentId": 2 + }, { + "id": 128, + "label": "commonjs_params.validation", + "parentId": 2 + }, { + "id": 132, + "label": "aspect_rules_js+", + "parentId": 25 + }, { + "id": 131, + "label": "js", + "parentId": 132 + }, { + "id": 130, + "label": "private", + "parentId": 131 + }, { + "id": 129, + "label": "js_binary.sh.tpl", + "parentId": 130 + }, { + "id": 134, + "label": "tsc_worker_", + "parentId": 108 + }, { + "id": 133, + "label": "tsc_worker", + "parentId": 134 + }, { + "id": 135, + "label": "tsc_worker.repo_mapping", + "parentId": 134 + }, { + "id": 137, + "label": "node_modules", + "parentId": 108 + }, { + "id": 136, + "label": "typescript", + "parentId": 137 + }, { + "id": 138, + "label": "tsc_worker.runfiles_manifest", + "parentId": 134 + }, { + "id": 140, + "label": "tsc_worker.runfiles", + "parentId": 134 + }, { + "id": 139, + "label": "MANIFEST", + "parentId": 140 + }, { + "id": 144, + "label": ".aspect_rules_js", + "parentId": 137 + }, { + "id": 143, + "label": "typescript@6.0.3", + "parentId": 144 + }, { + "id": 142, + "label": "node_modules", + "parentId": 143 + }, { + "id": 141, + "label": "typescript", + "parentId": 142 + }, { + "id": 145, + "label": "worker.js", + "parentId": 108 + }, { + "id": 146, + "label": "package.json", + "parentId": 108 + }, { + "id": 147, + "label": "ts_project_worker.js", + "parentId": 108 + }, { + "id": 149, + "label": "node_bin", + "parentId": 130 + }, { + "id": 148, + "label": "node", + "parentId": 149 + }, { + "id": 154, + "label": "rules_nodejs++node+nodejs_linux_amd64", + "parentId": 25 + }, { + "id": 153, + "label": "bin", + "parentId": 154 + }, { + "id": 152, + "label": "nodejs", + "parentId": 153 + }, { + "id": 151, + "label": "bin", + "parentId": 152 + }, { + "id": 150, + "label": "node", + "parentId": 151 + }, { + "id": 156, + "label": "node-bootstrap", + "parentId": 130 + }, { + "id": 155, + "label": "fs.cjs", + "parentId": 156 + }, { + "id": 157, + "label": "bootstrap.cjs", + "parentId": 156 + }, { + "id": 158, + "label": "launcher.cjs", + "parentId": 156 + }, { + "id": 159, + "label": "util.cjs", + "parentId": 156 + }, { + "id": 160, + "label": "external_Saspect_Urules_Uts++typescript+npm_Utypescript_Stsc_Uworker_U_Stsc_Uworker-runfiles", + "parentId": 69 + }, { + "id": 161, + "label": "validator.repo_mapping", + "parentId": 107 + }, { + "id": 162, + "label": "validator.runfiles_manifest", + "parentId": 107 + }, { + "id": 164, + "label": "validator.runfiles", + "parentId": 107 + }, { + "id": 163, + "label": "MANIFEST", + "parentId": 164 + }, { + "id": 165, + "label": "ts_project_options_validator.cjs", + "parentId": 108 + }, { + "id": 166, + "label": "tsc.repo_mapping", + "parentId": 124 + }, { + "id": 167, + "label": "tsc.runfiles_manifest", + "parentId": 124 + }, { + "id": 169, + "label": "tsc.runfiles", + "parentId": 124 + }, { + "id": 168, + "label": "MANIFEST", + "parentId": 169 + }, { + "id": 171, + "label": "+languages+query_types_node", + "parentId": 25 + }, { + "id": 170, + "label": "package.tgz", + "parentId": 171 + }, { + "id": 173, + "label": "tar.bzl++toolchains+bsd_tar_toolchains_linux_amd64", + "parentId": 25 + }, { + "id": 172, + "label": "tar", + "parentId": 173 + }, { + "id": 177, + "label": "aspect_rules_ts+", + "parentId": 25 + }, { + "id": 176, + "label": "ts", + "parentId": 177 + }, { + "id": 175, + "label": "private", + "parentId": 176 + }, { + "id": 174, + "label": "ts_project_worker.js", + "parentId": 175 + }, { + "id": 179, + "label": "+languages+query_undici_types", + "parentId": 25 + }, { + "id": 178, + "label": "package.tgz", + "parentId": 179 + }, { + "id": 181, + "label": "worker", + "parentId": 130 + }, { + "id": 180, + "label": "worker.js", + "parentId": 181 + }, { + "id": 182, + "label": "ts_project_options_validator.cjs", + "parentId": 175 + }, { + "id": 184, + "label": "aspect_rules_ts++typescript+npm_typescript", + "parentId": 25 + }, { + "id": 183, + "label": "package", + "parentId": 184 + }, { + "id": 186, + "label": "bazel_lib++toolchains+copy_directory_linux_amd64", + "parentId": 25 + }, { + "id": 185, + "label": "copy_directory", + "parentId": 186 + }] +} diff --git a/tools/release/fixtures/aquery-bazel-8.8.1/aquery.pb b/tools/release/fixtures/aquery-bazel-8.8.1/aquery.pb new file mode 100644 index 000000000..9d2cdf89e --- /dev/null +++ b/tools/release/fixtures/aquery-bazel-8.8.1/aquery.pb @@ -0,0 +1,1744 @@ +-'//src/query/ts:node_modules/@types/node82@@aspect_rules_ts++typescript+npm_typescript//:tsc +//src/query/ts:moduleLF@@aspect_rules_ts++typescript+npm_typescript//:node_modules/typescript?9@@aspect_rules_ts++typescript+npm_typescript//:tsc_worker: _write_file:  _bun_test:query_envelope //src/query/ts:npm//src/query/ts:unit_testA;@@aspect_rules_ts++typescript+npm_typescript//:package_json:npm_link_package_store.(//src/query/ts:node_modules/undici-types:  sh_binary0*@@bazel_tools//tools/test:collect_coverage:  js_binary:shipping_package% //src/query/ts:shipping_package: npm_package_store>8//src/query/ts:.aspect_rules_js/node_modules/@types/node > 8@@aspect_rules_ts++typescript+npm_typescript//:validator: + +_copy_fileKE@@aspect_rules_ts++typescript+npm_typescript//:copy_ts_project_worker +: +ts_project //src/query/ts:commonjs*gk8-opt-exec-ST-d57f47055a04k8"@ed5797a767b96f3a1479df6c05824854fc306bea605a92620af0492ebf871581(*V k8-fastbuildk8"@0db2b318338ce09df9dbfeda423511d29dd37e81a4519b8ba56a33ac4076bea9*V k8-fastbuildk8"@f55cd0755219b272bb7b1eeb31dd83dd10bc8c00329f25764eb9ea725eeff190B  bazel-outB externalB  node_modulesBaspect_rules_js+B node_modulesB)#unit_test.sources__main_config.jsonB!+languages+query_types_nodeB!#k8-opt-exec-ST-d57f47055a04B  +typescript BjsB$ tsc_worker_B  package.tgzB& bazel_toolsB k8-fastbuildB +tsc_worker$B %tools&B undici-typesB +test%B privateB1"+bazel_lib++toolchains+coreutils_linux_amd64B js_binary.sh.tplB '@typesB +node' + + B*aspect_rules_ts+B)ts* +B coreutils"B (private) + Bts_project_worker.js( +  +B/src²@4d9f7a6fa4b2d6886c15eff907d69edd61b690860173627ee16c1e9beb1cf1ab"UnresolvedSymlink(Jhr@@platforms//host:host’9.aspect_rules_js/typescript@6.0.3/node_modules/typescript +n@1b76ff913898d2090b4b9aad252df73f4f29c85df9eec6f34421575c00cf6810" FileWrite(Jhr@@platforms//host:hostB802tar.bzl++toolchains+bsd_tar_toolchains_linux_amd64B ,tar0 +," + B5.aspect_rules_jsB4@types+node@24.12.45B3 node_modules4B 2@types3B +1node2" +1¹@54822de1b9155ce110e6c1afbc6d7402098b56f37a78e23f5a1062d5442543f6"UnresolvedSymlink(J h r@@platforms//host:host’@../.aspect_rules_js/@types+node@24.12.4/node_modules/@types/nodeB6ts_project_worker.js +6¨@e196a0eb8ceb7641c504d13dfd062102e125ba5c01264de885de0e8516275a32"NpmPackageExtract(: +LC_ALLC.UTF-8BJZ +supports-path-mapping1hr@@platforms//host:hosto@7a39b61d5744a8903119e17b3ddc7e56e330f240d2bead98c3ba081a81b5c9ac"Symlink(BJhr@@platforms//host:hostB$shipping_package.shipping.json +n @3272d1fc1376fba8926b3f5deec5f9ce1bd682b6c45d38252fc7f5b545daae63" FileWrite(Jhr@@platforms//host:hostC=@@aspect_rules_ts++typescript+npm_typescript//:copy_worker_js +B +8test-B7protocol.test.ts8 +7B  package.jsonB9query.ts+ +9B: query.test.ts8C=@@aspect_rules_ts++typescript+npm_typescript//:copy_validator + +: + B;protocol-fixtures.mts8 +;]W@@aspect_rules_ts++typescript+npm_typescript//:.aspect_rules_js/node_modules/typescript B> test-fixtures/B=protocol>B<query-response-cases.json= +.aspect_rules_js/undici-types@7.16.0/node_modules/undici-typesn@c24bdb15c475ca888636662e24d9a20c43e6a0b85f35e1b0503dc6bc95ef5351" FileWrite(Jhr@@platforms//host:hostB0H*aspect_rules_ts++typescript+npm_typescriptB GpackageH +GB6J0bazel_lib++toolchains+copy_directory_linux_amd64BIcopy_directoryJB @workerB? worker.js@ +?" " BK worker.js +Ko@7a39b61d5744a8903119e17b3ddc7e56e330f240d2bead98c3ba081a81b5c9ac"Symlink(B Jhr@@platforms//host:hostB&A ts_project_options_validator.cjs( +A" +BM +validator_BL validatorM + LB&N ts_project_options_validator.cjs·›@afe568d62434aab01c6f4fce627ca6120f1c42ad4c2f2a2fbc22a2d702ca14c4"TemplateExpand(BJhr@@platforms//host:hostz¡q#!/usr/bin/env bash + +# This bash script is a wrapper around the NodeJS JavaScript file +# entry point with the following bazel label: +# {{entry_point_label}} +# +# The script's was generated to execute the js_binary target +# {{target_label}} +# +# The template used to generate this script is +# {{template_label}} + +set -o pipefail -o errexit -o nounset + +{{envs}} + +# If PATH was not provided, then it is important to export it here so that child +# processes get the default value generated by bash. +export PATH + +# ============================================================================== +# Handle --bazel-bindir flag +# ============================================================================== + +# If a --bazel-bindir flag is passed it must be the first two +# arguments. It is consumed by this launcher script and used to set +# BAZEL_BINDIR, overriding any value already set in the environment. +if [ $# -gt 0 ] && [ "$1" = "--bazel-bindir" ]; then + if [ $# -lt 2 ]; then + echo "ERROR: --bazel-bindir flag requires a value" >&2 + exit 1 + fi + BAZEL_BINDIR="$2" + export BAZEL_BINDIR + shift 2 +fi + +# ============================================================================== +# Prepare stdout capture, stderr capture && logging +# ============================================================================== + +# Convert stdout, stderr and exit_code capture outputs paths to absolute paths. +# A path not starting with "bazel-out/" is relative to the bin directory; joining +# it with BAZEL_BINDIR here (rather than baking in bazel-out//bin at +# analysis time) keeps it correct when path mapping is active. This must happen +# before any directory changes below since it resolves against $PWD. +function resolve_capture_path { + case "$1" in + bazel-out/*) echo "$PWD/$1" ;; + *) echo "$PWD/$BAZEL_BINDIR/$1" ;; + esac +} + +# TODO(4.0): remove support for capturing stderr, stdout, and exit code. The +# js_run_binary macro now handles this in a way that does not require help from +# the launcher. +if [ "${JS_BINARY__STDOUT_OUTPUT_FILE:-}" ]; then + JS_BINARY__STDOUT_OUTPUT_FILE="$(resolve_capture_path "$JS_BINARY__STDOUT_OUTPUT_FILE")" +fi +if [ "${JS_BINARY__STDERR_OUTPUT_FILE:-}" ]; then + JS_BINARY__STDERR_OUTPUT_FILE="$(resolve_capture_path "$JS_BINARY__STDERR_OUTPUT_FILE")" +fi +if [ "${JS_BINARY__EXIT_CODE_OUTPUT_FILE:-}" ]; then + JS_BINARY__EXIT_CODE_OUTPUT_FILE="$(resolve_capture_path "$JS_BINARY__EXIT_CODE_OUTPUT_FILE")" +fi + +# A stream with a declared output file is written straight to that file so that +# nothing has to run after node exits and this shell can exec node. +# +# A stream that is only subject to silent_on_success has no final destination, so +# it is buffered in a temp file and replayed on failure. +if [ "${JS_BINARY__STDOUT_OUTPUT_FILE:-}" ]; then + STDOUT_CAPTURE="$JS_BINARY__STDOUT_OUTPUT_FILE" +elif [ "${JS_BINARY__SILENT_ON_SUCCESS:-}" ]; then + STDOUT_CAPTURE=$(mktemp) + STDOUT_CAPTURE_IS_TEMP=1 +fi + +if [ "${JS_BINARY__STDERR_OUTPUT_FILE:-}" ]; then + STDERR_CAPTURE="$JS_BINARY__STDERR_OUTPUT_FILE" +elif [ "${JS_BINARY__SILENT_ON_SUCCESS:-}" ]; then + STDERR_CAPTURE=$(mktemp) + STDERR_CAPTURE_IS_TEMP=1 +fi + +# FATAL and ERROR diagnostics from this launcher only go into the stderr capture +# if that capture is a temp file that will get replayed on failure. Otherwise, +# we write these straight to stderr so that they do not get lost if the action +# fails. +LOG_ERROR_CAPTURE="${STDERR_CAPTURE_IS_TEMP:+$STDERR_CAPTURE}" + +export JS_BINARY__LOG_PREFIX="{{log_prefix_rule_set}}[{{log_prefix_rule}}]" + +# Emit a log line to $1, or to the real stderr when $1 is empty. +function log_to { + local capture="$1" + local level="$2" + local message="$3" + if [ "$capture" ]; then + printf "%s: %s: %s\n" "$level" "$JS_BINARY__LOG_PREFIX" "$message" >>"$capture" + else + printf "%s: %s: %s\n" "$level" "$JS_BINARY__LOG_PREFIX" "$message" >&2 + fi +} + +function log_fatal { + if [ "${JS_BINARY__LOG_FATAL:-}" ]; then + log_to "${LOG_ERROR_CAPTURE:-}" FATAL "$1" + fi +} + +function log_error { + if [ "${JS_BINARY__LOG_ERROR:-}" ]; then + log_to "${LOG_ERROR_CAPTURE:-}" ERROR "$1" + fi +} + +function log_info { + if [ "${JS_BINARY__LOG_INFO:-}" ]; then + log_to "${STDERR_CAPTURE:-}" INFO "$1" + fi +} + +function log_debug { + if [ "${JS_BINARY__LOG_DEBUG:-}" ]; then + log_to "${STDERR_CAPTURE:-}" DEBUG "$1" + fi +} + +_exit() { + EXIT_CODE=$? + + # Streams captured to a declared output file were written there directly and + # need no mop up. Only the temp files that back silent_on_success do. + if [ "${STDERR_CAPTURE_IS_TEMP:-}" ]; then + if [ "$EXIT_CODE" != 0 ] || [ -z "${JS_BINARY__SILENT_ON_SUCCESS:-}" ]; then + cat "$STDERR_CAPTURE" >&2 + fi + rm "$STDERR_CAPTURE" + fi + + if [ "${STDOUT_CAPTURE_IS_TEMP:-}" ]; then + if [ "$EXIT_CODE" != 0 ] || [ -z "${JS_BINARY__SILENT_ON_SUCCESS:-}" ]; then + cat "$STDOUT_CAPTURE" + fi + rm "$STDOUT_CAPTURE" + fi + + log_debug "exit code: $EXIT_CODE" + + exit "$EXIT_CODE" +} + +trap _exit EXIT + +# ============================================================================== +# Initialize RUNFILES environment variable +# ============================================================================== +{{initialize_runfiles}} +JS_BINARY__RUNFILES="$RUNFILES" +export JS_BINARY__RUNFILES + +# ============================================================================== +# Prepare to run main program +# ============================================================================== + +# The execroot the entry point is resolved against below. A parent js_binary process hands its +# own down when it asks for an execroot entry point, because the entry point it resolved is in +# that tree; otherwise this script was started in it. Nothing else here needs an execroot: the +# launcher preload works out JS_BINARY__EXECROOT for the program and everything it spawns. +if [ "${JS_BINARY__USE_EXECROOT_ENTRY_POINT:-}" ] && [ "${JS_BINARY__EXECROOT:-}" ]; then + execroot="$JS_BINARY__EXECROOT" +else + execroot="$PWD" +fi + +# Build actions are started in the execroot, so change into the root of the Bazel output tree, +# which is where js_binary programs run. See +# https://github.com/aspect-build/rules_js/tree/dbb5af0d2a9a2bb50e4cf4a96dbc582b27567155#running-nodejs-programs +# for more context on why we do this. It cannot wait for the preload: node resolves the bare +# specifier of a --require in node_options against the directory it was started in. +# +# The bindir is only there to change into when this really is an execroot; in a runfiles tree, +# or in a nested js_binary already running in the bindir, there is nothing to do. The preload +# tells those apart from the broken case by JS_BINARY__CHANGED_TO_BINDIR. +if [ -z "${JS_BINARY__NO_CD_BINDIR:-}" ] && [ "${BAZEL_BINDIR:-}" ] && [ -d "$PWD/$BAZEL_BINDIR" ]; then + log_debug "changing directory to BAZEL_BINDIR (root of Bazel output tree) $BAZEL_BINDIR" + export JS_BINARY__CHANGED_TO_BINDIR=1 + cd "$BAZEL_BINDIR" +fi + +if [ "${JS_BINARY__USE_EXECROOT_ENTRY_POINT:-}" ] && [ -z "${BAZEL_BINDIR:-}" ]; then + log_fatal "Expected BAZEL_BINDIR to be set when JS_BINARY__USE_EXECROOT_ENTRY_POINT is set" + exit 1 +fi + +function resolve_execroot_bin_path { + local short_path="$1" + if [[ "$short_path" == ../* ]]; then + echo "$execroot/$BAZEL_BINDIR/external/${short_path:3}" + else + echo "$execroot/$BAZEL_BINDIR/$short_path" + fi +} + +function resolve_execroot_src_path { + local short_path="$1" + if [[ "$short_path" == ../* ]]; then + echo "$execroot/external/${short_path:3}" + else + echo "$execroot/$short_path" + fi +} + +# Resolve a toolchain file that is a file of this workspace or another repository +# in the runfiles tree, or an absolute path a user set in node_toolchain. +function resolve_toolchain_path { + local file + file="$(_normalize_path "$1")" + if [ "${file:0:1}" = "/" ]; then + echo "$file" + elif [ "${JS_BINARY__NO_RUNFILES:-}" ]; then + resolve_execroot_src_path "$file" + else + echo "$JS_BINARY__RUNFILES/{{workspace_name}}/$file" + fi +} + +# Everything below is resolved here only because node needs it on its command line +# or bash needs it to start node at all. The checks that can wait, and the rest of +# the environment the program sees, are done by the launcher preload once node is up. + +if [ "${JS_BINARY__USE_EXECROOT_ENTRY_POINT:-}" ] || [ "${JS_BINARY__NO_RUNFILES:-}" ]; then + entry_point=$(resolve_execroot_bin_path "{{entry_point_path}}") +else + entry_point="$JS_BINARY__RUNFILES/{{workspace_name}}/{{entry_point_path}}" +fi + +export JS_BINARY__NODE_BINARY +JS_BINARY__NODE_BINARY=$(resolve_toolchain_path "{{node}}") +if [ ! -f "$JS_BINARY__NODE_BINARY" ]; then + log_fatal "node binary '$JS_BINARY__NODE_BINARY' not found" + exit 1 +fi +if [ "$_IS_WINDOWS" -ne "1" ] && [ ! -x "$JS_BINARY__NODE_BINARY" ]; then + log_fatal "node binary '$JS_BINARY__NODE_BINARY' is not executable" + exit 1 +fi + +npm="{{npm}}" +if [ "$npm" ]; then + export JS_BINARY__NPM_BINARY + JS_BINARY__NPM_BINARY=$(resolve_toolchain_path "$npm") +fi + +launcher=$(resolve_toolchain_path "{{launcher}}") +if [ ! -f "$launcher" ]; then + log_fatal "launcher '$launcher' not found" + exit 1 +fi + +# Gather node options +JS_BINARY__NODE_OPTIONS=() +{{node_options}} + +ARGS=() +ALL_ARGS=({{fixed_args}} "$@") +for ARG in ${ALL_ARGS[@]+"${ALL_ARGS[@]}"}; do + case "$ARG" in + # Let users pass through arguments to node itself + --node_options=*) JS_BINARY__NODE_OPTIONS+=("${ARG#--node_options=}") ;; + # Remaining argv is collected to pass to the program + *) ARGS+=("$ARG") ;; + esac +done + +# ============================================================================== +# Run the main program +# ============================================================================== + +# Invoke node directly rather than through $JS_BINARY__NODE_WRAPPER. This way +# we avoid spawning an extra bash process on every launch. The wrapper is +# still put on the PATH as `node` so that child processes get the patched +# runtime. +node_cmd=("$JS_BINARY__NODE_BINARY" --require "$launcher") + +if [ "${JS_BINARY__LOG_INFO:-}" ]; then + log_info "$(echo -n "running" "${node_cmd[@]}" ${JS_BINARY__NODE_OPTIONS[@]+"${JS_BINARY__NODE_OPTIONS[@]}"} -- "$entry_point" ${ARGS[@]+"${ARGS[@]}"})" +fi + +# De-export capture-related vars so child processes (e.g. a nested js_binary) +# do not inherit them. The bash script has already consumed them above to set up +# STDOUT_CAPTURE / STDERR_CAPTURE; leaking them would cause a nested js_binary +# to silently swallow its own stdout or write to the wrong output file. +# export -n keeps the value accessible to the _exit trap while removing it from +# the environment seen by node and any processes it spawns. +export -n JS_BINARY__STDOUT_OUTPUT_FILE JS_BINARY__STDERR_OUTPUT_FILE JS_BINARY__EXIT_CODE_OUTPUT_FILE JS_BINARY__SILENT_ON_SUCCESS + +set +e + +if [ -z "${JS_BINARY__EXPECTED_EXIT_CODE:-}" ] && [ -z "${JS_BINARY__EXIT_CODE_OUTPUT_FILE:-}" ] && + [ -z "${STDOUT_CAPTURE_IS_TEMP:-}" ] && [ -z "${STDERR_CAPTURE_IS_TEMP:-}" ]; then + # Nothing must run after node exits, so replace this shell with node. Signals + # and terminal control are then delivered directly to node instead of being + # proxied through a backgrounded child. + if [ "${STDOUT_CAPTURE:-}" ]; then + exec 1>>"$STDOUT_CAPTURE" + fi + if [ "${STDERR_CAPTURE:-}" ]; then + exec 2>>"$STDERR_CAPTURE" + fi + exec "${node_cmd[@]}" ${JS_BINARY__NODE_OPTIONS[@]+"${JS_BINARY__NODE_OPTIONS[@]}"} -- "$entry_point" ${ARGS[@]+"${ARGS[@]}"} + exit 127 +fi + +if [ "${STDOUT_CAPTURE:-}" ] && [ "${STDERR_CAPTURE:-}" ]; then + "${node_cmd[@]}" ${JS_BINARY__NODE_OPTIONS[@]+"${JS_BINARY__NODE_OPTIONS[@]}"} -- "$entry_point" ${ARGS[@]+"${ARGS[@]}"} <&0 >>"$STDOUT_CAPTURE" 2>>"$STDERR_CAPTURE" & +elif [ "${STDOUT_CAPTURE:-}" ]; then + "${node_cmd[@]}" ${JS_BINARY__NODE_OPTIONS[@]+"${JS_BINARY__NODE_OPTIONS[@]}"} -- "$entry_point" ${ARGS[@]+"${ARGS[@]}"} <&0 >>"$STDOUT_CAPTURE" & +elif [ "${STDERR_CAPTURE:-}" ]; then + "${node_cmd[@]}" ${JS_BINARY__NODE_OPTIONS[@]+"${JS_BINARY__NODE_OPTIONS[@]}"} -- "$entry_point" ${ARGS[@]+"${ARGS[@]}"} <&0 2>>"$STDERR_CAPTURE" & +else + "${node_cmd[@]}" ${JS_BINARY__NODE_OPTIONS[@]+"${JS_BINARY__NODE_OPTIONS[@]}"} -- "$entry_point" ${ARGS[@]+"${ARGS[@]}"} <&0 & +fi + +# ============================================================================== +# Wait for program to finish +# ============================================================================== + +readonly child=$! +# Bash does not forward termination signals to any child process when +# running in docker, so we need to manually trap and forward the signals. +# +# Each trap is reset as it fires, so that a repeat of that signal terminates this +# script rather than being swallowed. +_term() { trap - SIGTERM; kill -TERM "${child}" 2>/dev/null; } +_int() { trap - SIGINT; kill -INT "${child}" 2>/dev/null; } +trap _term SIGTERM +trap _int SIGINT + +# A wait returns as soon as a trapped signal has been handled, whether or not the +# child has exited, so keep waiting until it has. +wait "$child" +RESULT="$?" +while kill -0 "$child" 2>/dev/null; do + wait "$child" + RESULT="$?" +done + +# Remove traps now that the child process has exited +trap - SIGTERM SIGINT +set -e + +# ============================================================================== +# Mop up after main program +# ============================================================================== + +if [ "${JS_BINARY__EXPECTED_EXIT_CODE:-}" ]; then + if [ "$RESULT" != "$JS_BINARY__EXPECTED_EXIT_CODE" ]; then + log_error "expected exit code to be '$JS_BINARY__EXPECTED_EXIT_CODE', but got '$RESULT'" + if [ $RESULT -eq 0 ]; then + # This exit code is handled specially by Bazel: + # https://github.com/bazelbuild/bazel/blob/486206012a664ecb20bdb196a681efc9a9825049/src/main/java/com/google/devtools/build/lib/util/ExitCode.java#L44 + readonly BAZEL_EXIT_TESTS_FAILED=3 + exit $BAZEL_EXIT_TESTS_FAILED + fi + exit $RESULT + else + exit 0 + fi +fi + +if [ "${JS_BINARY__EXIT_CODE_OUTPUT_FILE:-}" ]; then + # Exit zero if the exit code was captured + echo -n "$RESULT" >"$JS_BINARY__EXIT_CODE_OUTPUT_FILE" + exit 0 +else + exit $RESULT +fi +‚M +{{target_label}}9@@aspect_rules_ts++typescript+npm_typescript//:tsc_worker‚E +{{template_label}}/@@aspect_rules_js+//js/private:js_binary.sh.tpl‚^ +{{entry_point_label}}E@@aspect_rules_ts++typescript+npm_typescript//:copy_ts_project_worker‚Z +{{entry_point_path}}B../aspect_rules_ts++typescript+npm_typescript/ts_project_worker.js‚± +{{envs}}¤export JS_BINARY__BINDIR="bazel-out/k8-opt-exec-ST-d57f47055a04/bin" +export JS_BINARY__COMPILATION_MODE="opt" +export JS_BINARY__TARGET_CPU="k8" +export JS_BINARY__BUILD_FILE_PATH="BUILD.bazel" +export JS_BINARY__PACKAGE="" +export JS_BINARY__TARGET_NAME="tsc_worker" +export JS_BINARY__TARGET="@aspect_rules_ts++typescript+npm_typescript//:tsc_worker" +export JS_BINARY__WORKSPACE="_main" +if [[ -z "${JS_BINARY__PATCH_NODE_FS:-}" ]]; then export JS_BINARY__PATCH_NODE_FS="1"; fi +export JS_BINARY__COPY_DATA_TO_BIN="1" +if [[ -z "${JS_BINARY__LOG_FATAL:-}" ]]; then export JS_BINARY__LOG_FATAL="1"; fi +if [[ -z "${JS_BINARY__LOG_ERROR:-}" ]]; then export JS_BINARY__LOG_ERROR="1"; fi‚ +{{fixed_args}}‚� +{{initialize_runfiles}}� +# It helps to determine if we are running on a Windows environment (excludes WSL as it acts like Unix) +case "$(uname -s)" in +CYGWIN*) _IS_WINDOWS=1 ;; +MINGW*) _IS_WINDOWS=1 ;; +MSYS_NT*) _IS_WINDOWS=1 ;; +*) _IS_WINDOWS=0 ;; +esac + +# It helps to normalizes paths when running on Windows. +# +# Example: +# C:/Users/XUser/_bazel_XUser/7q7kkv32/execroot/A/b/C -> /c/Users/XUser/_bazel_XUser/7q7kkv32/execroot/A/b/C +function _normalize_path { + if [ "$_IS_WINDOWS" -eq "1" ]; then + # Apply the followings paths transformations to normalize paths on Windows + # -process driver letter + # -convert path separator + sed -e 's#^\(.\):#/\L\1#' -e 's#\\#/#g' <<<"$1" + else + echo "$1" + fi + return +} + +# Set a RUNFILES environment variable to the root of the runfiles tree +# since RUNFILES_DIR is not set by Bazel in all contexts. +# For example, `RUNFILES=/path/to/my_js_binary.sh.runfiles`. +# +# Call this program X. X was generated by a genrule and may be invoked +# in many ways: +# 1a) directly by a user, with $0 in the output tree +# 1b) via 'bazel run' (similar to case 1a) +# 2) directly by a user, with $0 in X's runfiles +# 3) by another program Y which has a data dependency on X, with $0 in Y's +# runfiles +# 4a) via 'bazel test' +# 4b) case 3 in the context of a test +# 5a) by a genrule cmd, with $0 in the output tree +# 6a) case 3 in the context of a genrule +# +# For case 1, $0 will be a regular file, and the runfiles will be +# at $0.runfiles. +# For case 2 or 3, $0 will be a symlink to the file seen in case 1. +# For case 4, $TEST_SRCDIR should already be set to the runfiles by +# blaze. +# Case 5a is handled like case 1. +# Case 6a is handled like case 3. +if [ "${TEST_SRCDIR:-}" ]; then + # Case 4, bazel has identified runfiles for us. + RUNFILES=$(_normalize_path "$TEST_SRCDIR") +elif [ "${RUNFILES_MANIFEST_FILE:-}" ]; then + RUNFILES=$(_normalize_path "$RUNFILES_MANIFEST_FILE") + if [[ "${RUNFILES}" == *.runfiles_manifest ]]; then + # Bazel puts the manifest besides the runfiles with the suffix .runfiles_manifest. + # For example, the runfiles directory is named my_binary.runfiles then the manifest is beside the + # runfiles directory and named my_binary.runfiles_manifest + RUNFILES=${RUNFILES%_manifest} + elif [[ "${RUNFILES}" == */MANIFEST ]]; then + # Bazel for windows puts the manifest file named MANIFEST in the runfiles directory + RUNFILES=${RUNFILES%/MANIFEST} + else + log_fatal "Unexpected RUNFILES_MANIFEST_FILE value $RUNFILES_MANIFEST_FILE" + exit 1 + fi +else + case "$0" in + /*) self="$0" ;; + *) self="$PWD/$0" ;; + esac + while true; do + if [ -e "$self.runfiles" ]; then + RUNFILES="$self.runfiles" + break + fi + + if [[ "$self" == *.runfiles/* ]]; then + RUNFILES="${self%%.runfiles/*}.runfiles" + # don't break; this is a last resort for case 6b + fi + + if [ ! -L "$self" ]; then + break + fi + + readlink="$(readlink "$self")" + if [[ "$readlink" == /* ]]; then + self="$readlink" + else + # resolve relative symlink + self="${self%%/*}/$readlink" + fi + done + + if [ -z "${RUNFILES:-}" ]; then + log_fatal "RUNFILES environment variable is not set" + exit 1 + fi + + RUNFILES=$(_normalize_path "$RUNFILES") +fi +if [ "${RUNFILES:0:1}" != "/" ]; then + # Ensure RUNFILES set above is an absolute path. It may be a path relative + # to the PWD in case where RUNFILES_MANIFEST_FILE is used above. + RUNFILES="$PWD/$RUNFILES" +fi +# Set RUNFILES_DIR if not already set so that tools such as @bazel/runfiles +# can locate runfiles without requiring RUNFILES to be exported. +export RUNFILES_DIR="${RUNFILES_DIR:-$RUNFILES}" +‚* +{{log_prefix_rule_set}}aspect_rules_js‚ +{{log_prefix_rule}} js_binary‚J + {{launcher}}:../aspect_rules_js+/js/private/node-bootstrap/launcher.cjs‚I +{{node_options}}5JS_BINARY__NODE_OPTIONS+=("--preserve-symlinks-main")‚H +{{node}}<../rules_nodejs++node+nodejs_linux_amd64/bin/nodejs/bin/node‚ +{{npm}}‚ +{{workspace_name}}_main +!No@7a39b61d5744a8903119e17b3ddc7e56e330f240d2bead98c3ba081a81b5c9ac"Symlink(B +J!h!r@@platforms//host:host¸› @6d7045aec817638b04b2220a69243df1247acb88114594fb908a74248160dcc8"TemplateExpand(BJ h r@@platforms//host:hostz¡q#!/usr/bin/env bash + +# This bash script is a wrapper around the NodeJS JavaScript file +# entry point with the following bazel label: +# {{entry_point_label}} +# +# The script's was generated to execute the js_binary target +# {{target_label}} +# +# The template used to generate this script is +# {{template_label}} + +set -o pipefail -o errexit -o nounset + +{{envs}} + +# If PATH was not provided, then it is important to export it here so that child +# processes get the default value generated by bash. +export PATH + +# ============================================================================== +# Handle --bazel-bindir flag +# ============================================================================== + +# If a --bazel-bindir flag is passed it must be the first two +# arguments. It is consumed by this launcher script and used to set +# BAZEL_BINDIR, overriding any value already set in the environment. +if [ $# -gt 0 ] && [ "$1" = "--bazel-bindir" ]; then + if [ $# -lt 2 ]; then + echo "ERROR: --bazel-bindir flag requires a value" >&2 + exit 1 + fi + BAZEL_BINDIR="$2" + export BAZEL_BINDIR + shift 2 +fi + +# ============================================================================== +# Prepare stdout capture, stderr capture && logging +# ============================================================================== + +# Convert stdout, stderr and exit_code capture outputs paths to absolute paths. +# A path not starting with "bazel-out/" is relative to the bin directory; joining +# it with BAZEL_BINDIR here (rather than baking in bazel-out//bin at +# analysis time) keeps it correct when path mapping is active. This must happen +# before any directory changes below since it resolves against $PWD. +function resolve_capture_path { + case "$1" in + bazel-out/*) echo "$PWD/$1" ;; + *) echo "$PWD/$BAZEL_BINDIR/$1" ;; + esac +} + +# TODO(4.0): remove support for capturing stderr, stdout, and exit code. The +# js_run_binary macro now handles this in a way that does not require help from +# the launcher. +if [ "${JS_BINARY__STDOUT_OUTPUT_FILE:-}" ]; then + JS_BINARY__STDOUT_OUTPUT_FILE="$(resolve_capture_path "$JS_BINARY__STDOUT_OUTPUT_FILE")" +fi +if [ "${JS_BINARY__STDERR_OUTPUT_FILE:-}" ]; then + JS_BINARY__STDERR_OUTPUT_FILE="$(resolve_capture_path "$JS_BINARY__STDERR_OUTPUT_FILE")" +fi +if [ "${JS_BINARY__EXIT_CODE_OUTPUT_FILE:-}" ]; then + JS_BINARY__EXIT_CODE_OUTPUT_FILE="$(resolve_capture_path "$JS_BINARY__EXIT_CODE_OUTPUT_FILE")" +fi + +# A stream with a declared output file is written straight to that file so that +# nothing has to run after node exits and this shell can exec node. +# +# A stream that is only subject to silent_on_success has no final destination, so +# it is buffered in a temp file and replayed on failure. +if [ "${JS_BINARY__STDOUT_OUTPUT_FILE:-}" ]; then + STDOUT_CAPTURE="$JS_BINARY__STDOUT_OUTPUT_FILE" +elif [ "${JS_BINARY__SILENT_ON_SUCCESS:-}" ]; then + STDOUT_CAPTURE=$(mktemp) + STDOUT_CAPTURE_IS_TEMP=1 +fi + +if [ "${JS_BINARY__STDERR_OUTPUT_FILE:-}" ]; then + STDERR_CAPTURE="$JS_BINARY__STDERR_OUTPUT_FILE" +elif [ "${JS_BINARY__SILENT_ON_SUCCESS:-}" ]; then + STDERR_CAPTURE=$(mktemp) + STDERR_CAPTURE_IS_TEMP=1 +fi + +# FATAL and ERROR diagnostics from this launcher only go into the stderr capture +# if that capture is a temp file that will get replayed on failure. Otherwise, +# we write these straight to stderr so that they do not get lost if the action +# fails. +LOG_ERROR_CAPTURE="${STDERR_CAPTURE_IS_TEMP:+$STDERR_CAPTURE}" + +export JS_BINARY__LOG_PREFIX="{{log_prefix_rule_set}}[{{log_prefix_rule}}]" + +# Emit a log line to $1, or to the real stderr when $1 is empty. +function log_to { + local capture="$1" + local level="$2" + local message="$3" + if [ "$capture" ]; then + printf "%s: %s: %s\n" "$level" "$JS_BINARY__LOG_PREFIX" "$message" >>"$capture" + else + printf "%s: %s: %s\n" "$level" "$JS_BINARY__LOG_PREFIX" "$message" >&2 + fi +} + +function log_fatal { + if [ "${JS_BINARY__LOG_FATAL:-}" ]; then + log_to "${LOG_ERROR_CAPTURE:-}" FATAL "$1" + fi +} + +function log_error { + if [ "${JS_BINARY__LOG_ERROR:-}" ]; then + log_to "${LOG_ERROR_CAPTURE:-}" ERROR "$1" + fi +} + +function log_info { + if [ "${JS_BINARY__LOG_INFO:-}" ]; then + log_to "${STDERR_CAPTURE:-}" INFO "$1" + fi +} + +function log_debug { + if [ "${JS_BINARY__LOG_DEBUG:-}" ]; then + log_to "${STDERR_CAPTURE:-}" DEBUG "$1" + fi +} + +_exit() { + EXIT_CODE=$? + + # Streams captured to a declared output file were written there directly and + # need no mop up. Only the temp files that back silent_on_success do. + if [ "${STDERR_CAPTURE_IS_TEMP:-}" ]; then + if [ "$EXIT_CODE" != 0 ] || [ -z "${JS_BINARY__SILENT_ON_SUCCESS:-}" ]; then + cat "$STDERR_CAPTURE" >&2 + fi + rm "$STDERR_CAPTURE" + fi + + if [ "${STDOUT_CAPTURE_IS_TEMP:-}" ]; then + if [ "$EXIT_CODE" != 0 ] || [ -z "${JS_BINARY__SILENT_ON_SUCCESS:-}" ]; then + cat "$STDOUT_CAPTURE" + fi + rm "$STDOUT_CAPTURE" + fi + + log_debug "exit code: $EXIT_CODE" + + exit "$EXIT_CODE" +} + +trap _exit EXIT + +# ============================================================================== +# Initialize RUNFILES environment variable +# ============================================================================== +{{initialize_runfiles}} +JS_BINARY__RUNFILES="$RUNFILES" +export JS_BINARY__RUNFILES + +# ============================================================================== +# Prepare to run main program +# ============================================================================== + +# The execroot the entry point is resolved against below. A parent js_binary process hands its +# own down when it asks for an execroot entry point, because the entry point it resolved is in +# that tree; otherwise this script was started in it. Nothing else here needs an execroot: the +# launcher preload works out JS_BINARY__EXECROOT for the program and everything it spawns. +if [ "${JS_BINARY__USE_EXECROOT_ENTRY_POINT:-}" ] && [ "${JS_BINARY__EXECROOT:-}" ]; then + execroot="$JS_BINARY__EXECROOT" +else + execroot="$PWD" +fi + +# Build actions are started in the execroot, so change into the root of the Bazel output tree, +# which is where js_binary programs run. See +# https://github.com/aspect-build/rules_js/tree/dbb5af0d2a9a2bb50e4cf4a96dbc582b27567155#running-nodejs-programs +# for more context on why we do this. It cannot wait for the preload: node resolves the bare +# specifier of a --require in node_options against the directory it was started in. +# +# The bindir is only there to change into when this really is an execroot; in a runfiles tree, +# or in a nested js_binary already running in the bindir, there is nothing to do. The preload +# tells those apart from the broken case by JS_BINARY__CHANGED_TO_BINDIR. +if [ -z "${JS_BINARY__NO_CD_BINDIR:-}" ] && [ "${BAZEL_BINDIR:-}" ] && [ -d "$PWD/$BAZEL_BINDIR" ]; then + log_debug "changing directory to BAZEL_BINDIR (root of Bazel output tree) $BAZEL_BINDIR" + export JS_BINARY__CHANGED_TO_BINDIR=1 + cd "$BAZEL_BINDIR" +fi + +if [ "${JS_BINARY__USE_EXECROOT_ENTRY_POINT:-}" ] && [ -z "${BAZEL_BINDIR:-}" ]; then + log_fatal "Expected BAZEL_BINDIR to be set when JS_BINARY__USE_EXECROOT_ENTRY_POINT is set" + exit 1 +fi + +function resolve_execroot_bin_path { + local short_path="$1" + if [[ "$short_path" == ../* ]]; then + echo "$execroot/$BAZEL_BINDIR/external/${short_path:3}" + else + echo "$execroot/$BAZEL_BINDIR/$short_path" + fi +} + +function resolve_execroot_src_path { + local short_path="$1" + if [[ "$short_path" == ../* ]]; then + echo "$execroot/external/${short_path:3}" + else + echo "$execroot/$short_path" + fi +} + +# Resolve a toolchain file that is a file of this workspace or another repository +# in the runfiles tree, or an absolute path a user set in node_toolchain. +function resolve_toolchain_path { + local file + file="$(_normalize_path "$1")" + if [ "${file:0:1}" = "/" ]; then + echo "$file" + elif [ "${JS_BINARY__NO_RUNFILES:-}" ]; then + resolve_execroot_src_path "$file" + else + echo "$JS_BINARY__RUNFILES/{{workspace_name}}/$file" + fi +} + +# Everything below is resolved here only because node needs it on its command line +# or bash needs it to start node at all. The checks that can wait, and the rest of +# the environment the program sees, are done by the launcher preload once node is up. + +if [ "${JS_BINARY__USE_EXECROOT_ENTRY_POINT:-}" ] || [ "${JS_BINARY__NO_RUNFILES:-}" ]; then + entry_point=$(resolve_execroot_bin_path "{{entry_point_path}}") +else + entry_point="$JS_BINARY__RUNFILES/{{workspace_name}}/{{entry_point_path}}" +fi + +export JS_BINARY__NODE_BINARY +JS_BINARY__NODE_BINARY=$(resolve_toolchain_path "{{node}}") +if [ ! -f "$JS_BINARY__NODE_BINARY" ]; then + log_fatal "node binary '$JS_BINARY__NODE_BINARY' not found" + exit 1 +fi +if [ "$_IS_WINDOWS" -ne "1" ] && [ ! -x "$JS_BINARY__NODE_BINARY" ]; then + log_fatal "node binary '$JS_BINARY__NODE_BINARY' is not executable" + exit 1 +fi + +npm="{{npm}}" +if [ "$npm" ]; then + export JS_BINARY__NPM_BINARY + JS_BINARY__NPM_BINARY=$(resolve_toolchain_path "$npm") +fi + +launcher=$(resolve_toolchain_path "{{launcher}}") +if [ ! -f "$launcher" ]; then + log_fatal "launcher '$launcher' not found" + exit 1 +fi + +# Gather node options +JS_BINARY__NODE_OPTIONS=() +{{node_options}} + +ARGS=() +ALL_ARGS=({{fixed_args}} "$@") +for ARG in ${ALL_ARGS[@]+"${ALL_ARGS[@]}"}; do + case "$ARG" in + # Let users pass through arguments to node itself + --node_options=*) JS_BINARY__NODE_OPTIONS+=("${ARG#--node_options=}") ;; + # Remaining argv is collected to pass to the program + *) ARGS+=("$ARG") ;; + esac +done + +# ============================================================================== +# Run the main program +# ============================================================================== + +# Invoke node directly rather than through $JS_BINARY__NODE_WRAPPER. This way +# we avoid spawning an extra bash process on every launch. The wrapper is +# still put on the PATH as `node` so that child processes get the patched +# runtime. +node_cmd=("$JS_BINARY__NODE_BINARY" --require "$launcher") + +if [ "${JS_BINARY__LOG_INFO:-}" ]; then + log_info "$(echo -n "running" "${node_cmd[@]}" ${JS_BINARY__NODE_OPTIONS[@]+"${JS_BINARY__NODE_OPTIONS[@]}"} -- "$entry_point" ${ARGS[@]+"${ARGS[@]}"})" +fi + +# De-export capture-related vars so child processes (e.g. a nested js_binary) +# do not inherit them. The bash script has already consumed them above to set up +# STDOUT_CAPTURE / STDERR_CAPTURE; leaking them would cause a nested js_binary +# to silently swallow its own stdout or write to the wrong output file. +# export -n keeps the value accessible to the _exit trap while removing it from +# the environment seen by node and any processes it spawns. +export -n JS_BINARY__STDOUT_OUTPUT_FILE JS_BINARY__STDERR_OUTPUT_FILE JS_BINARY__EXIT_CODE_OUTPUT_FILE JS_BINARY__SILENT_ON_SUCCESS + +set +e + +if [ -z "${JS_BINARY__EXPECTED_EXIT_CODE:-}" ] && [ -z "${JS_BINARY__EXIT_CODE_OUTPUT_FILE:-}" ] && + [ -z "${STDOUT_CAPTURE_IS_TEMP:-}" ] && [ -z "${STDERR_CAPTURE_IS_TEMP:-}" ]; then + # Nothing must run after node exits, so replace this shell with node. Signals + # and terminal control are then delivered directly to node instead of being + # proxied through a backgrounded child. + if [ "${STDOUT_CAPTURE:-}" ]; then + exec 1>>"$STDOUT_CAPTURE" + fi + if [ "${STDERR_CAPTURE:-}" ]; then + exec 2>>"$STDERR_CAPTURE" + fi + exec "${node_cmd[@]}" ${JS_BINARY__NODE_OPTIONS[@]+"${JS_BINARY__NODE_OPTIONS[@]}"} -- "$entry_point" ${ARGS[@]+"${ARGS[@]}"} + exit 127 +fi + +if [ "${STDOUT_CAPTURE:-}" ] && [ "${STDERR_CAPTURE:-}" ]; then + "${node_cmd[@]}" ${JS_BINARY__NODE_OPTIONS[@]+"${JS_BINARY__NODE_OPTIONS[@]}"} -- "$entry_point" ${ARGS[@]+"${ARGS[@]}"} <&0 >>"$STDOUT_CAPTURE" 2>>"$STDERR_CAPTURE" & +elif [ "${STDOUT_CAPTURE:-}" ]; then + "${node_cmd[@]}" ${JS_BINARY__NODE_OPTIONS[@]+"${JS_BINARY__NODE_OPTIONS[@]}"} -- "$entry_point" ${ARGS[@]+"${ARGS[@]}"} <&0 >>"$STDOUT_CAPTURE" & +elif [ "${STDERR_CAPTURE:-}" ]; then + "${node_cmd[@]}" ${JS_BINARY__NODE_OPTIONS[@]+"${JS_BINARY__NODE_OPTIONS[@]}"} -- "$entry_point" ${ARGS[@]+"${ARGS[@]}"} <&0 2>>"$STDERR_CAPTURE" & +else + "${node_cmd[@]}" ${JS_BINARY__NODE_OPTIONS[@]+"${JS_BINARY__NODE_OPTIONS[@]}"} -- "$entry_point" ${ARGS[@]+"${ARGS[@]}"} <&0 & +fi + +# ============================================================================== +# Wait for program to finish +# ============================================================================== + +readonly child=$! +# Bash does not forward termination signals to any child process when +# running in docker, so we need to manually trap and forward the signals. +# +# Each trap is reset as it fires, so that a repeat of that signal terminates this +# script rather than being swallowed. +_term() { trap - SIGTERM; kill -TERM "${child}" 2>/dev/null; } +_int() { trap - SIGINT; kill -INT "${child}" 2>/dev/null; } +trap _term SIGTERM +trap _int SIGINT + +# A wait returns as soon as a trapped signal has been handled, whether or not the +# child has exited, so keep waiting until it has. +wait "$child" +RESULT="$?" +while kill -0 "$child" 2>/dev/null; do + wait "$child" + RESULT="$?" +done + +# Remove traps now that the child process has exited +trap - SIGTERM SIGINT +set -e + +# ============================================================================== +# Mop up after main program +# ============================================================================== + +if [ "${JS_BINARY__EXPECTED_EXIT_CODE:-}" ]; then + if [ "$RESULT" != "$JS_BINARY__EXPECTED_EXIT_CODE" ]; then + log_error "expected exit code to be '$JS_BINARY__EXPECTED_EXIT_CODE', but got '$RESULT'" + if [ $RESULT -eq 0 ]; then + # This exit code is handled specially by Bazel: + # https://github.com/bazelbuild/bazel/blob/486206012a664ecb20bdb196a681efc9a9825049/src/main/java/com/google/devtools/build/lib/util/ExitCode.java#L44 + readonly BAZEL_EXIT_TESTS_FAILED=3 + exit $BAZEL_EXIT_TESTS_FAILED + fi + exit $RESULT + else + exit 0 + fi +fi + +if [ "${JS_BINARY__EXIT_CODE_OUTPUT_FILE:-}" ]; then + # Exit zero if the exit code was captured + echo -n "$RESULT" >"$JS_BINARY__EXIT_CODE_OUTPUT_FILE" + exit 0 +else + exit $RESULT +fi +‚L +{{target_label}}8@@aspect_rules_ts++typescript+npm_typescript//:validator‚E +{{template_label}}/@@aspect_rules_js+//js/private:js_binary.sh.tpl‚V +{{entry_point_label}}=@@aspect_rules_ts++typescript+npm_typescript//:copy_validator‚f +{{entry_point_path}}N../aspect_rules_ts++typescript+npm_typescript/ts_project_options_validator.cjs‚¯ +{{envs}}¢export JS_BINARY__BINDIR="bazel-out/k8-opt-exec-ST-d57f47055a04/bin" +export JS_BINARY__COMPILATION_MODE="opt" +export JS_BINARY__TARGET_CPU="k8" +export JS_BINARY__BUILD_FILE_PATH="BUILD.bazel" +export JS_BINARY__PACKAGE="" +export JS_BINARY__TARGET_NAME="validator" +export JS_BINARY__TARGET="@aspect_rules_ts++typescript+npm_typescript//:validator" +export JS_BINARY__WORKSPACE="_main" +if [[ -z "${JS_BINARY__PATCH_NODE_FS:-}" ]]; then export JS_BINARY__PATCH_NODE_FS="1"; fi +export JS_BINARY__COPY_DATA_TO_BIN="1" +if [[ -z "${JS_BINARY__LOG_FATAL:-}" ]]; then export JS_BINARY__LOG_FATAL="1"; fi +if [[ -z "${JS_BINARY__LOG_ERROR:-}" ]]; then export JS_BINARY__LOG_ERROR="1"; fi‚ +{{fixed_args}}‚� +{{initialize_runfiles}}� +# It helps to determine if we are running on a Windows environment (excludes WSL as it acts like Unix) +case "$(uname -s)" in +CYGWIN*) _IS_WINDOWS=1 ;; +MINGW*) _IS_WINDOWS=1 ;; +MSYS_NT*) _IS_WINDOWS=1 ;; +*) _IS_WINDOWS=0 ;; +esac + +# It helps to normalizes paths when running on Windows. +# +# Example: +# C:/Users/XUser/_bazel_XUser/7q7kkv32/execroot/A/b/C -> /c/Users/XUser/_bazel_XUser/7q7kkv32/execroot/A/b/C +function _normalize_path { + if [ "$_IS_WINDOWS" -eq "1" ]; then + # Apply the followings paths transformations to normalize paths on Windows + # -process driver letter + # -convert path separator + sed -e 's#^\(.\):#/\L\1#' -e 's#\\#/#g' <<<"$1" + else + echo "$1" + fi + return +} + +# Set a RUNFILES environment variable to the root of the runfiles tree +# since RUNFILES_DIR is not set by Bazel in all contexts. +# For example, `RUNFILES=/path/to/my_js_binary.sh.runfiles`. +# +# Call this program X. X was generated by a genrule and may be invoked +# in many ways: +# 1a) directly by a user, with $0 in the output tree +# 1b) via 'bazel run' (similar to case 1a) +# 2) directly by a user, with $0 in X's runfiles +# 3) by another program Y which has a data dependency on X, with $0 in Y's +# runfiles +# 4a) via 'bazel test' +# 4b) case 3 in the context of a test +# 5a) by a genrule cmd, with $0 in the output tree +# 6a) case 3 in the context of a genrule +# +# For case 1, $0 will be a regular file, and the runfiles will be +# at $0.runfiles. +# For case 2 or 3, $0 will be a symlink to the file seen in case 1. +# For case 4, $TEST_SRCDIR should already be set to the runfiles by +# blaze. +# Case 5a is handled like case 1. +# Case 6a is handled like case 3. +if [ "${TEST_SRCDIR:-}" ]; then + # Case 4, bazel has identified runfiles for us. + RUNFILES=$(_normalize_path "$TEST_SRCDIR") +elif [ "${RUNFILES_MANIFEST_FILE:-}" ]; then + RUNFILES=$(_normalize_path "$RUNFILES_MANIFEST_FILE") + if [[ "${RUNFILES}" == *.runfiles_manifest ]]; then + # Bazel puts the manifest besides the runfiles with the suffix .runfiles_manifest. + # For example, the runfiles directory is named my_binary.runfiles then the manifest is beside the + # runfiles directory and named my_binary.runfiles_manifest + RUNFILES=${RUNFILES%_manifest} + elif [[ "${RUNFILES}" == */MANIFEST ]]; then + # Bazel for windows puts the manifest file named MANIFEST in the runfiles directory + RUNFILES=${RUNFILES%/MANIFEST} + else + log_fatal "Unexpected RUNFILES_MANIFEST_FILE value $RUNFILES_MANIFEST_FILE" + exit 1 + fi +else + case "$0" in + /*) self="$0" ;; + *) self="$PWD/$0" ;; + esac + while true; do + if [ -e "$self.runfiles" ]; then + RUNFILES="$self.runfiles" + break + fi + + if [[ "$self" == *.runfiles/* ]]; then + RUNFILES="${self%%.runfiles/*}.runfiles" + # don't break; this is a last resort for case 6b + fi + + if [ ! -L "$self" ]; then + break + fi + + readlink="$(readlink "$self")" + if [[ "$readlink" == /* ]]; then + self="$readlink" + else + # resolve relative symlink + self="${self%%/*}/$readlink" + fi + done + + if [ -z "${RUNFILES:-}" ]; then + log_fatal "RUNFILES environment variable is not set" + exit 1 + fi + + RUNFILES=$(_normalize_path "$RUNFILES") +fi +if [ "${RUNFILES:0:1}" != "/" ]; then + # Ensure RUNFILES set above is an absolute path. It may be a path relative + # to the PWD in case where RUNFILES_MANIFEST_FILE is used above. + RUNFILES="$PWD/$RUNFILES" +fi +# Set RUNFILES_DIR if not already set so that tools such as @bazel/runfiles +# can locate runfiles without requiring RUNFILES to be exported. +export RUNFILES_DIR="${RUNFILES_DIR:-$RUNFILES}" +‚* +{{log_prefix_rule_set}}aspect_rules_js‚ +{{log_prefix_rule}} js_binary‚J + {{launcher}}:../aspect_rules_js+/js/private/node-bootstrap/launcher.cjs‚I +{{node_options}}5JS_BINARY__NODE_OPTIONS+=("--preserve-symlinks-main")‚H +{{node}}<../rules_nodejs++node+nodejs_linux_amd64/bin/nodejs/bin/node‚ +{{npm}}‚ +{{workspace_name}}_main" B binB srcB queryBtsBnpm.entries.json +n @05bd55fdbfdd933c77df990c9c0acd1c0da0963dece377b17e3e1dc87e54a33e" FileWrite(Jhr@@platforms//host:hostB PsrcBO protocol.tsP +"OŒ @355c71261c2901fdb9a8b691e5b3994c2c7877c4e84cc840900585e5c25b3681"CopyFile(BJ"Z +supports-path-mapping1h"r@@platforms//host:hostB !bin# +IBexternal!B0*aspect_rules_ts++typescript+npm_typescriptB +tsc_" B tsc +BU.aspect_rules_js BTtypescript@6.0.3UBS node_modulesTBR +typescriptS +$Rª@606062ce50521444fff34c66f30bc4178f53beb23bab023ae9d916101714c3f9" CopyDirectory(: +GODEBUG winsymlink=0B J$Z +supports-path-mapping1h$r@@platforms//host:hostBcollect_coverage.sh + +" +" Õ›@fb5c7b1c9a26625c8867bbd46f6c4f5127737e5707afa60793261903642e0c81"TemplateExpand(BJhr@@platforms//host:hostz¡q#!/usr/bin/env bash + +# This bash script is a wrapper around the NodeJS JavaScript file +# entry point with the following bazel label: +# {{entry_point_label}} +# +# The script's was generated to execute the js_binary target +# {{target_label}} +# +# The template used to generate this script is +# {{template_label}} + +set -o pipefail -o errexit -o nounset + +{{envs}} + +# If PATH was not provided, then it is important to export it here so that child +# processes get the default value generated by bash. +export PATH + +# ============================================================================== +# Handle --bazel-bindir flag +# ============================================================================== + +# If a --bazel-bindir flag is passed it must be the first two +# arguments. It is consumed by this launcher script and used to set +# BAZEL_BINDIR, overriding any value already set in the environment. +if [ $# -gt 0 ] && [ "$1" = "--bazel-bindir" ]; then + if [ $# -lt 2 ]; then + echo "ERROR: --bazel-bindir flag requires a value" >&2 + exit 1 + fi + BAZEL_BINDIR="$2" + export BAZEL_BINDIR + shift 2 +fi + +# ============================================================================== +# Prepare stdout capture, stderr capture && logging +# ============================================================================== + +# Convert stdout, stderr and exit_code capture outputs paths to absolute paths. +# A path not starting with "bazel-out/" is relative to the bin directory; joining +# it with BAZEL_BINDIR here (rather than baking in bazel-out//bin at +# analysis time) keeps it correct when path mapping is active. This must happen +# before any directory changes below since it resolves against $PWD. +function resolve_capture_path { + case "$1" in + bazel-out/*) echo "$PWD/$1" ;; + *) echo "$PWD/$BAZEL_BINDIR/$1" ;; + esac +} + +# TODO(4.0): remove support for capturing stderr, stdout, and exit code. The +# js_run_binary macro now handles this in a way that does not require help from +# the launcher. +if [ "${JS_BINARY__STDOUT_OUTPUT_FILE:-}" ]; then + JS_BINARY__STDOUT_OUTPUT_FILE="$(resolve_capture_path "$JS_BINARY__STDOUT_OUTPUT_FILE")" +fi +if [ "${JS_BINARY__STDERR_OUTPUT_FILE:-}" ]; then + JS_BINARY__STDERR_OUTPUT_FILE="$(resolve_capture_path "$JS_BINARY__STDERR_OUTPUT_FILE")" +fi +if [ "${JS_BINARY__EXIT_CODE_OUTPUT_FILE:-}" ]; then + JS_BINARY__EXIT_CODE_OUTPUT_FILE="$(resolve_capture_path "$JS_BINARY__EXIT_CODE_OUTPUT_FILE")" +fi + +# A stream with a declared output file is written straight to that file so that +# nothing has to run after node exits and this shell can exec node. +# +# A stream that is only subject to silent_on_success has no final destination, so +# it is buffered in a temp file and replayed on failure. +if [ "${JS_BINARY__STDOUT_OUTPUT_FILE:-}" ]; then + STDOUT_CAPTURE="$JS_BINARY__STDOUT_OUTPUT_FILE" +elif [ "${JS_BINARY__SILENT_ON_SUCCESS:-}" ]; then + STDOUT_CAPTURE=$(mktemp) + STDOUT_CAPTURE_IS_TEMP=1 +fi + +if [ "${JS_BINARY__STDERR_OUTPUT_FILE:-}" ]; then + STDERR_CAPTURE="$JS_BINARY__STDERR_OUTPUT_FILE" +elif [ "${JS_BINARY__SILENT_ON_SUCCESS:-}" ]; then + STDERR_CAPTURE=$(mktemp) + STDERR_CAPTURE_IS_TEMP=1 +fi + +# FATAL and ERROR diagnostics from this launcher only go into the stderr capture +# if that capture is a temp file that will get replayed on failure. Otherwise, +# we write these straight to stderr so that they do not get lost if the action +# fails. +LOG_ERROR_CAPTURE="${STDERR_CAPTURE_IS_TEMP:+$STDERR_CAPTURE}" + +export JS_BINARY__LOG_PREFIX="{{log_prefix_rule_set}}[{{log_prefix_rule}}]" + +# Emit a log line to $1, or to the real stderr when $1 is empty. +function log_to { + local capture="$1" + local level="$2" + local message="$3" + if [ "$capture" ]; then + printf "%s: %s: %s\n" "$level" "$JS_BINARY__LOG_PREFIX" "$message" >>"$capture" + else + printf "%s: %s: %s\n" "$level" "$JS_BINARY__LOG_PREFIX" "$message" >&2 + fi +} + +function log_fatal { + if [ "${JS_BINARY__LOG_FATAL:-}" ]; then + log_to "${LOG_ERROR_CAPTURE:-}" FATAL "$1" + fi +} + +function log_error { + if [ "${JS_BINARY__LOG_ERROR:-}" ]; then + log_to "${LOG_ERROR_CAPTURE:-}" ERROR "$1" + fi +} + +function log_info { + if [ "${JS_BINARY__LOG_INFO:-}" ]; then + log_to "${STDERR_CAPTURE:-}" INFO "$1" + fi +} + +function log_debug { + if [ "${JS_BINARY__LOG_DEBUG:-}" ]; then + log_to "${STDERR_CAPTURE:-}" DEBUG "$1" + fi +} + +_exit() { + EXIT_CODE=$? + + # Streams captured to a declared output file were written there directly and + # need no mop up. Only the temp files that back silent_on_success do. + if [ "${STDERR_CAPTURE_IS_TEMP:-}" ]; then + if [ "$EXIT_CODE" != 0 ] || [ -z "${JS_BINARY__SILENT_ON_SUCCESS:-}" ]; then + cat "$STDERR_CAPTURE" >&2 + fi + rm "$STDERR_CAPTURE" + fi + + if [ "${STDOUT_CAPTURE_IS_TEMP:-}" ]; then + if [ "$EXIT_CODE" != 0 ] || [ -z "${JS_BINARY__SILENT_ON_SUCCESS:-}" ]; then + cat "$STDOUT_CAPTURE" + fi + rm "$STDOUT_CAPTURE" + fi + + log_debug "exit code: $EXIT_CODE" + + exit "$EXIT_CODE" +} + +trap _exit EXIT + +# ============================================================================== +# Initialize RUNFILES environment variable +# ============================================================================== +{{initialize_runfiles}} +JS_BINARY__RUNFILES="$RUNFILES" +export JS_BINARY__RUNFILES + +# ============================================================================== +# Prepare to run main program +# ============================================================================== + +# The execroot the entry point is resolved against below. A parent js_binary process hands its +# own down when it asks for an execroot entry point, because the entry point it resolved is in +# that tree; otherwise this script was started in it. Nothing else here needs an execroot: the +# launcher preload works out JS_BINARY__EXECROOT for the program and everything it spawns. +if [ "${JS_BINARY__USE_EXECROOT_ENTRY_POINT:-}" ] && [ "${JS_BINARY__EXECROOT:-}" ]; then + execroot="$JS_BINARY__EXECROOT" +else + execroot="$PWD" +fi + +# Build actions are started in the execroot, so change into the root of the Bazel output tree, +# which is where js_binary programs run. See +# https://github.com/aspect-build/rules_js/tree/dbb5af0d2a9a2bb50e4cf4a96dbc582b27567155#running-nodejs-programs +# for more context on why we do this. It cannot wait for the preload: node resolves the bare +# specifier of a --require in node_options against the directory it was started in. +# +# The bindir is only there to change into when this really is an execroot; in a runfiles tree, +# or in a nested js_binary already running in the bindir, there is nothing to do. The preload +# tells those apart from the broken case by JS_BINARY__CHANGED_TO_BINDIR. +if [ -z "${JS_BINARY__NO_CD_BINDIR:-}" ] && [ "${BAZEL_BINDIR:-}" ] && [ -d "$PWD/$BAZEL_BINDIR" ]; then + log_debug "changing directory to BAZEL_BINDIR (root of Bazel output tree) $BAZEL_BINDIR" + export JS_BINARY__CHANGED_TO_BINDIR=1 + cd "$BAZEL_BINDIR" +fi + +if [ "${JS_BINARY__USE_EXECROOT_ENTRY_POINT:-}" ] && [ -z "${BAZEL_BINDIR:-}" ]; then + log_fatal "Expected BAZEL_BINDIR to be set when JS_BINARY__USE_EXECROOT_ENTRY_POINT is set" + exit 1 +fi + +function resolve_execroot_bin_path { + local short_path="$1" + if [[ "$short_path" == ../* ]]; then + echo "$execroot/$BAZEL_BINDIR/external/${short_path:3}" + else + echo "$execroot/$BAZEL_BINDIR/$short_path" + fi +} + +function resolve_execroot_src_path { + local short_path="$1" + if [[ "$short_path" == ../* ]]; then + echo "$execroot/external/${short_path:3}" + else + echo "$execroot/$short_path" + fi +} + +# Resolve a toolchain file that is a file of this workspace or another repository +# in the runfiles tree, or an absolute path a user set in node_toolchain. +function resolve_toolchain_path { + local file + file="$(_normalize_path "$1")" + if [ "${file:0:1}" = "/" ]; then + echo "$file" + elif [ "${JS_BINARY__NO_RUNFILES:-}" ]; then + resolve_execroot_src_path "$file" + else + echo "$JS_BINARY__RUNFILES/{{workspace_name}}/$file" + fi +} + +# Everything below is resolved here only because node needs it on its command line +# or bash needs it to start node at all. The checks that can wait, and the rest of +# the environment the program sees, are done by the launcher preload once node is up. + +if [ "${JS_BINARY__USE_EXECROOT_ENTRY_POINT:-}" ] || [ "${JS_BINARY__NO_RUNFILES:-}" ]; then + entry_point=$(resolve_execroot_bin_path "{{entry_point_path}}") +else + entry_point="$JS_BINARY__RUNFILES/{{workspace_name}}/{{entry_point_path}}" +fi + +export JS_BINARY__NODE_BINARY +JS_BINARY__NODE_BINARY=$(resolve_toolchain_path "{{node}}") +if [ ! -f "$JS_BINARY__NODE_BINARY" ]; then + log_fatal "node binary '$JS_BINARY__NODE_BINARY' not found" + exit 1 +fi +if [ "$_IS_WINDOWS" -ne "1" ] && [ ! -x "$JS_BINARY__NODE_BINARY" ]; then + log_fatal "node binary '$JS_BINARY__NODE_BINARY' is not executable" + exit 1 +fi + +npm="{{npm}}" +if [ "$npm" ]; then + export JS_BINARY__NPM_BINARY + JS_BINARY__NPM_BINARY=$(resolve_toolchain_path "$npm") +fi + +launcher=$(resolve_toolchain_path "{{launcher}}") +if [ ! -f "$launcher" ]; then + log_fatal "launcher '$launcher' not found" + exit 1 +fi + +# Gather node options +JS_BINARY__NODE_OPTIONS=() +{{node_options}} + +ARGS=() +ALL_ARGS=({{fixed_args}} "$@") +for ARG in ${ALL_ARGS[@]+"${ALL_ARGS[@]}"}; do + case "$ARG" in + # Let users pass through arguments to node itself + --node_options=*) JS_BINARY__NODE_OPTIONS+=("${ARG#--node_options=}") ;; + # Remaining argv is collected to pass to the program + *) ARGS+=("$ARG") ;; + esac +done + +# ============================================================================== +# Run the main program +# ============================================================================== + +# Invoke node directly rather than through $JS_BINARY__NODE_WRAPPER. This way +# we avoid spawning an extra bash process on every launch. The wrapper is +# still put on the PATH as `node` so that child processes get the patched +# runtime. +node_cmd=("$JS_BINARY__NODE_BINARY" --require "$launcher") + +if [ "${JS_BINARY__LOG_INFO:-}" ]; then + log_info "$(echo -n "running" "${node_cmd[@]}" ${JS_BINARY__NODE_OPTIONS[@]+"${JS_BINARY__NODE_OPTIONS[@]}"} -- "$entry_point" ${ARGS[@]+"${ARGS[@]}"})" +fi + +# De-export capture-related vars so child processes (e.g. a nested js_binary) +# do not inherit them. The bash script has already consumed them above to set up +# STDOUT_CAPTURE / STDERR_CAPTURE; leaking them would cause a nested js_binary +# to silently swallow its own stdout or write to the wrong output file. +# export -n keeps the value accessible to the _exit trap while removing it from +# the environment seen by node and any processes it spawns. +export -n JS_BINARY__STDOUT_OUTPUT_FILE JS_BINARY__STDERR_OUTPUT_FILE JS_BINARY__EXIT_CODE_OUTPUT_FILE JS_BINARY__SILENT_ON_SUCCESS + +set +e + +if [ -z "${JS_BINARY__EXPECTED_EXIT_CODE:-}" ] && [ -z "${JS_BINARY__EXIT_CODE_OUTPUT_FILE:-}" ] && + [ -z "${STDOUT_CAPTURE_IS_TEMP:-}" ] && [ -z "${STDERR_CAPTURE_IS_TEMP:-}" ]; then + # Nothing must run after node exits, so replace this shell with node. Signals + # and terminal control are then delivered directly to node instead of being + # proxied through a backgrounded child. + if [ "${STDOUT_CAPTURE:-}" ]; then + exec 1>>"$STDOUT_CAPTURE" + fi + if [ "${STDERR_CAPTURE:-}" ]; then + exec 2>>"$STDERR_CAPTURE" + fi + exec "${node_cmd[@]}" ${JS_BINARY__NODE_OPTIONS[@]+"${JS_BINARY__NODE_OPTIONS[@]}"} -- "$entry_point" ${ARGS[@]+"${ARGS[@]}"} + exit 127 +fi + +if [ "${STDOUT_CAPTURE:-}" ] && [ "${STDERR_CAPTURE:-}" ]; then + "${node_cmd[@]}" ${JS_BINARY__NODE_OPTIONS[@]+"${JS_BINARY__NODE_OPTIONS[@]}"} -- "$entry_point" ${ARGS[@]+"${ARGS[@]}"} <&0 >>"$STDOUT_CAPTURE" 2>>"$STDERR_CAPTURE" & +elif [ "${STDOUT_CAPTURE:-}" ]; then + "${node_cmd[@]}" ${JS_BINARY__NODE_OPTIONS[@]+"${JS_BINARY__NODE_OPTIONS[@]}"} -- "$entry_point" ${ARGS[@]+"${ARGS[@]}"} <&0 >>"$STDOUT_CAPTURE" & +elif [ "${STDERR_CAPTURE:-}" ]; then + "${node_cmd[@]}" ${JS_BINARY__NODE_OPTIONS[@]+"${JS_BINARY__NODE_OPTIONS[@]}"} -- "$entry_point" ${ARGS[@]+"${ARGS[@]}"} <&0 2>>"$STDERR_CAPTURE" & +else + "${node_cmd[@]}" ${JS_BINARY__NODE_OPTIONS[@]+"${JS_BINARY__NODE_OPTIONS[@]}"} -- "$entry_point" ${ARGS[@]+"${ARGS[@]}"} <&0 & +fi + +# ============================================================================== +# Wait for program to finish +# ============================================================================== + +readonly child=$! +# Bash does not forward termination signals to any child process when +# running in docker, so we need to manually trap and forward the signals. +# +# Each trap is reset as it fires, so that a repeat of that signal terminates this +# script rather than being swallowed. +_term() { trap - SIGTERM; kill -TERM "${child}" 2>/dev/null; } +_int() { trap - SIGINT; kill -INT "${child}" 2>/dev/null; } +trap _term SIGTERM +trap _int SIGINT + +# A wait returns as soon as a trapped signal has been handled, whether or not the +# child has exited, so keep waiting until it has. +wait "$child" +RESULT="$?" +while kill -0 "$child" 2>/dev/null; do + wait "$child" + RESULT="$?" +done + +# Remove traps now that the child process has exited +trap - SIGTERM SIGINT +set -e + +# ============================================================================== +# Mop up after main program +# ============================================================================== + +if [ "${JS_BINARY__EXPECTED_EXIT_CODE:-}" ]; then + if [ "$RESULT" != "$JS_BINARY__EXPECTED_EXIT_CODE" ]; then + log_error "expected exit code to be '$JS_BINARY__EXPECTED_EXIT_CODE', but got '$RESULT'" + if [ $RESULT -eq 0 ]; then + # This exit code is handled specially by Bazel: + # https://github.com/bazelbuild/bazel/blob/486206012a664ecb20bdb196a681efc9a9825049/src/main/java/com/google/devtools/build/lib/util/ExitCode.java#L44 + readonly BAZEL_EXIT_TESTS_FAILED=3 + exit $BAZEL_EXIT_TESTS_FAILED + fi + exit $RESULT + else + exit 0 + fi +fi + +if [ "${JS_BINARY__EXIT_CODE_OUTPUT_FILE:-}" ]; then + # Exit zero if the exit code was captured + echo -n "$RESULT" >"$JS_BINARY__EXIT_CODE_OUTPUT_FILE" + exit 0 +else + exit $RESULT +fi +‚F +{{target_label}}2@@aspect_rules_ts++typescript+npm_typescript//:tsc‚E +{{template_label}}/@@aspect_rules_js+//js/private:js_binary.sh.tpl‚V +{{entry_point_label}}=@@aspect_rules_ts++typescript+npm_typescript//:tsc_entrypoint‚” +{{entry_point_path}}|../aspect_rules_ts++typescript+npm_typescript/node_modules/.aspect_rules_js/typescript@6.0.3/node_modules/typescript/bin/tsc‚£ +{{envs}}–export JS_BINARY__BINDIR="bazel-out/k8-opt-exec-ST-d57f47055a04/bin" +export JS_BINARY__COMPILATION_MODE="opt" +export JS_BINARY__TARGET_CPU="k8" +export JS_BINARY__BUILD_FILE_PATH="BUILD.bazel" +export JS_BINARY__PACKAGE="" +export JS_BINARY__TARGET_NAME="tsc" +export JS_BINARY__TARGET="@aspect_rules_ts++typescript+npm_typescript//:tsc" +export JS_BINARY__WORKSPACE="_main" +if [[ -z "${JS_BINARY__PATCH_NODE_FS:-}" ]]; then export JS_BINARY__PATCH_NODE_FS="1"; fi +export JS_BINARY__COPY_DATA_TO_BIN="1" +if [[ -z "${JS_BINARY__LOG_FATAL:-}" ]]; then export JS_BINARY__LOG_FATAL="1"; fi +if [[ -z "${JS_BINARY__LOG_ERROR:-}" ]]; then export JS_BINARY__LOG_ERROR="1"; fi‚ +{{fixed_args}}‚� +{{initialize_runfiles}}� +# It helps to determine if we are running on a Windows environment (excludes WSL as it acts like Unix) +case "$(uname -s)" in +CYGWIN*) _IS_WINDOWS=1 ;; +MINGW*) _IS_WINDOWS=1 ;; +MSYS_NT*) _IS_WINDOWS=1 ;; +*) _IS_WINDOWS=0 ;; +esac + +# It helps to normalizes paths when running on Windows. +# +# Example: +# C:/Users/XUser/_bazel_XUser/7q7kkv32/execroot/A/b/C -> /c/Users/XUser/_bazel_XUser/7q7kkv32/execroot/A/b/C +function _normalize_path { + if [ "$_IS_WINDOWS" -eq "1" ]; then + # Apply the followings paths transformations to normalize paths on Windows + # -process driver letter + # -convert path separator + sed -e 's#^\(.\):#/\L\1#' -e 's#\\#/#g' <<<"$1" + else + echo "$1" + fi + return +} + +# Set a RUNFILES environment variable to the root of the runfiles tree +# since RUNFILES_DIR is not set by Bazel in all contexts. +# For example, `RUNFILES=/path/to/my_js_binary.sh.runfiles`. +# +# Call this program X. X was generated by a genrule and may be invoked +# in many ways: +# 1a) directly by a user, with $0 in the output tree +# 1b) via 'bazel run' (similar to case 1a) +# 2) directly by a user, with $0 in X's runfiles +# 3) by another program Y which has a data dependency on X, with $0 in Y's +# runfiles +# 4a) via 'bazel test' +# 4b) case 3 in the context of a test +# 5a) by a genrule cmd, with $0 in the output tree +# 6a) case 3 in the context of a genrule +# +# For case 1, $0 will be a regular file, and the runfiles will be +# at $0.runfiles. +# For case 2 or 3, $0 will be a symlink to the file seen in case 1. +# For case 4, $TEST_SRCDIR should already be set to the runfiles by +# blaze. +# Case 5a is handled like case 1. +# Case 6a is handled like case 3. +if [ "${TEST_SRCDIR:-}" ]; then + # Case 4, bazel has identified runfiles for us. + RUNFILES=$(_normalize_path "$TEST_SRCDIR") +elif [ "${RUNFILES_MANIFEST_FILE:-}" ]; then + RUNFILES=$(_normalize_path "$RUNFILES_MANIFEST_FILE") + if [[ "${RUNFILES}" == *.runfiles_manifest ]]; then + # Bazel puts the manifest besides the runfiles with the suffix .runfiles_manifest. + # For example, the runfiles directory is named my_binary.runfiles then the manifest is beside the + # runfiles directory and named my_binary.runfiles_manifest + RUNFILES=${RUNFILES%_manifest} + elif [[ "${RUNFILES}" == */MANIFEST ]]; then + # Bazel for windows puts the manifest file named MANIFEST in the runfiles directory + RUNFILES=${RUNFILES%/MANIFEST} + else + log_fatal "Unexpected RUNFILES_MANIFEST_FILE value $RUNFILES_MANIFEST_FILE" + exit 1 + fi +else + case "$0" in + /*) self="$0" ;; + *) self="$PWD/$0" ;; + esac + while true; do + if [ -e "$self.runfiles" ]; then + RUNFILES="$self.runfiles" + break + fi + + if [[ "$self" == *.runfiles/* ]]; then + RUNFILES="${self%%.runfiles/*}.runfiles" + # don't break; this is a last resort for case 6b + fi + + if [ ! -L "$self" ]; then + break + fi + + readlink="$(readlink "$self")" + if [[ "$readlink" == /* ]]; then + self="$readlink" + else + # resolve relative symlink + self="${self%%/*}/$readlink" + fi + done + + if [ -z "${RUNFILES:-}" ]; then + log_fatal "RUNFILES environment variable is not set" + exit 1 + fi + + RUNFILES=$(_normalize_path "$RUNFILES") +fi +if [ "${RUNFILES:0:1}" != "/" ]; then + # Ensure RUNFILES set above is an absolute path. It may be a path relative + # to the PWD in case where RUNFILES_MANIFEST_FILE is used above. + RUNFILES="$PWD/$RUNFILES" +fi +# Set RUNFILES_DIR if not already set so that tools such as @bazel/runfiles +# can locate runfiles without requiring RUNFILES to be exported. +export RUNFILES_DIR="${RUNFILES_DIR:-$RUNFILES}" +‚* +{{log_prefix_rule_set}}aspect_rules_js‚ +{{log_prefix_rule}} js_binary‚J + {{launcher}}:../aspect_rules_js+/js/private/node-bootstrap/launcher.cjs‚I +{{node_options}}5JS_BINARY__NODE_OPTIONS+=("--preserve-symlinks-main")‚H +{{node}}<../rules_nodejs++node+nodejs_linux_amd64/bin/nodejs/bin/node‚ +{{npm}}‚ +{{workspace_name}}_mainBY bazel_toolsB XtoolsYB +WtestXBVcollect_coverageW +%Vy@7a39b61d5744a8903119e17b3ddc7e56e330f240d2bead98c3ba081a81b5c9ac"ExecutableSymlink(BJ%h%r@@platforms//host:hostBZquery.tsP +&ZŒ @ed93ae2d2ca6952c52ad071d3c447d0a55889f4d5cd51c67ff7d4c7e1a4dd89d"CopyFile(B J&Z +supports-path-mapping1h&r@@platforms//host:hostB"[tsconfig.build.commonjs.json- +'[" 'B"\tsconfig.build.commonjs.json +(\Œ @ea8439ef62e576dc448185c76a34e296221a6445e2c72a1867d94d44609ca968"CopyFile(B J(Z +supports-path-mapping1h(r@@platforms//host:hostB] tsconfig.json- +)]")B^ tsconfig.json +*^Œ @ca78fdcddb26bc5090f6d7bad5544b75858f8d575b56254e51896b7ae1a47319"CopyFile(BJ*Z +supports-path-mapping1h*r@@platforms//host:host?9//src/query/ts:.aspect_rules_js/node_modules/undici-types B .query/B-ts.B +src-B + protocol.ts+ +  +"  ++OŒ +@355c71261c2901fdb9a8b691e5b3994c2c7877c4e84cc840900585e5c25b3681"CopyFile(BJ+Z +supports-path-mapping1h+r@@platforms//host:host" +,ZŒ +@ed93ae2d2ca6952c52ad071d3c447d0a55889f4d5cd51c67ff7d4c7e1a4dd89d"CopyFile(BJ,Z +supports-path-mapping1h,r@@platforms//host:hostB atsconfig.build.module.json- +.aB#`+languages+query_undici_types".B_ package.tgz`B btsconfig.build.module.json +-_ +/bŒ +@eb16123fff5c14f3d38fd4f9395321e5eaaf4185e891bd23f5163f2313bfe32f"CopyFile(BJ/Z +supports-path-mapping1h/r@@platforms//host:host"-Beundici-types@7.16.05Bd node_moduleseBc undici-typesd +0c") +1^¨@808d3dd8e3b7822833218c13dca70010d16f0a1d05e17e459ed5f277c8a3df49"NpmPackageExtract(: +LC_ALLC.UTF-8BJ0Z +supports-path-mapping1h0r@@platforms//host:hostŒ +@ca78fdcddb26bc5090f6d7bad5544b75858f8d575b56254e51896b7ae1a47319"CopyFile(BJ1Z +supports-path-mapping1h1r@@platforms//host:host"(*Bjtsc_worker.repo_mapping$ +4jx@4f4bf4b1b5b2284ce521a69b165072b12450dee320415b733ec58bd4930c216f"RepoMappingManifest(J4h4r@@platforms//host:hostB#kcollect_coverage.repo_mappingW +5kx@9df0fc7af996fee90934caf5821e6d3bf171df2d4270b392733ad8c5820cfbfa"RepoMappingManifest(J5h5r@@platforms//host:hostB(l"collect_coverage.runfiles_manifestW" +6lB"mtsc_worker.runfiles_manifest$z@8bfd336cc84e266eab28b0241686be81d8b7b052c4033aef8a98a9430853f275"SourceSymlinkManifest(J6h6r@@platforms//host:host +7m}@aeb51d69bd94c236f4ecfb31cbd3f2e1c7076041098ca62ed400c2617e654062"SourceSymlinkManifest(BJ7h7r@@platforms//host:host"7"6Bocollect_coverage.runfilesWBnMANIFESTo +8nBqtsc_worker.runfiles$BpMANIFESTqs@6c51cb2745410b7f3021e2c6da7719dd646a1f8007539f27ba608eeaec4dc9d9" SymlinkTree(BJ8h8r@@platforms//host:host +9ps@41ae5ee3bb7cce9243d85ef829862800b09b0a8e30356db261cc1c34d42eee02" SymlinkTree(BJ9h9r@@platforms//host:host"$$"% +%" "$"#%%"  #85"/1Bhinternal# +EBg +_middlemenhB#Qnpm.sources__main_config.json�@784a5dc4f99b530faf423a9953d183a9c90b5828f320b7d2fddf304d14e670cd"CopyToDirectory(: +GODEBUG winsymlink=0BJhr@@platforms//host:host +#Qn @52509dd660d2da8dfa398df24019a0abcc8a70177dffc0c56122bb1e0b67ad26" FileWrite(J#h#r@@platforms//host:hostB#t+bun_toolchains+bun_linux_x64B sbunt +;s"&;Bu unit_test +<uy@7a39b61d5744a8903119e17b3ddc7e56e330f240d2bead98c3ba081a81b5c9ac"ExecutableSymlink(B&JyB^fXexternal_Saspect_Urules_Uts++typescript+npm_Utypescript_Svalidator_U_Svalidator-runfilesg +2f" 2"B {commonjs_params.validation +@{» @409d1bf0360f30c3b7f0dc097f86cd5258a2bbd1440bc8531f8cbb5597a46032"TsValidateOptions(:$ +PATH/bin:/usr/bin:/usr/local/binBJ@Z +supports-path-mapping1h@r@@platforms//host:host¶@f4b635ed843c3a32b801874310b9103478bbd7a65f0284d8e84ba2fd34741dac"TemplateExpand(B'J>h>r@@platforms//host:hostz÷ import { isAbsolute, join, resolve } from "node:path"; + +const configuration = @@CONFIG@@; +const declaredRoot = process.env.RUNFILES_DIR ?? process.env.TEST_SRCDIR ?? join(import.meta.dir, configuration.runfilesSibling); +if (!declaredRoot || !isAbsolute(declaredRoot)) { + throw new Error("Bazel Bun entrypoints require an absolute directory runfiles root"); +} +const root = resolve(declaredRoot); +const args = configuration.arguments.map((argument) => + "file" in argument ? join(root, argument.file) : argument.literal, +); +if (configuration.runfilesArgument) args.push(root); +args.push(...process.argv.slice(2)); +const testArguments = configuration.testRunner ? ["test"] : []; +if (configuration.testRunner && !args.some((argument) => argument === "--timeout" || argument.startsWith("--timeout="))) { + testArguments.push("--timeout=30000"); +} +const environment = { ...process.env, ...configuration.environment }; +for (const name of configuration.runfilesEnvironment) environment[name] = root; +// Execute the authored runner as the main module: importing it would skip +// runners guarded by import.meta.main. No script interpreter or shell is used. +const result = Bun.spawnSync( + [process.execPath, "--no-install", "--no-env-file", ...testArguments, join(root, configuration.runner), ...args], + { + cwd: join(root, configuration.testRunner ? configuration.sourceRoot : configuration.workspace), + env: environment, + stdin: "inherit", + stdout: "inherit", + stderr: "inherit", + }, +); +process.exit(result.exitCode); +‚ + +@@CONFIG@@³{"arguments":[],"environment":{},"runfilesArgument":false,"runfilesEnvironment":[],"runfilesSibling":"unit_test.runfiles","runner":"_main/src/query/ts/unit_test.sources/_main/src/query/ts/test/protocol.test.ts","sourceRoot":"_main/src/query/ts/unit_test.sources/_main","testRunner":true,"workspace":"_main"}B }queryxB| package.mts} +A|B +€toolsB packaging€B~archive-directory.mts +B~B�portable-archive.mts +C�")ABC#"()Bƒ npm.sourcesB ‚_mainƒ +D‚� @4a9b99ad2ba2756cd3dafdd8d8a264442cde23e7a874c3b78e4c2379a98ef29b"CopyToDirectory(: +GODEBUG winsymlink=0B(JDhDr@@platforms//host:host"- ".0",-." +,"&(*BS„Lexternal_Saspect_Urules_Uts++typescript+npm_Utypescript_Stsc_U_Stsc-runfilesg +E„"/EB‡unit_test.repo_mappingB… package.json-"Bˆmodule_params.validation +Iˆ» +@8daa333b8da0ce7b58fc8e5efbd32a5d743e6c9cc88d02f4d5992a520e59260f"TsValidateOptions(:$ +PATH/bin:/usr/bin:/usr/local/binBJIZ +supports-path-mapping1hIr@@platforms//host:host +3iB†tsc.runfiles_manifestx @bec6c834996de644e591e6008973b7e4952fba4a55a4ac5576c35cab841b5b2f"RepoMappingManifest(J3h3r@@platforms//host:host +G†"5-." 45+,/1"34/B ‹distBŠmodule‹B‰ protocol.jsŠ +J‰BŒquery.jsŠ +KŒB� protocol.d.tsŠ +L�BŽ +query.d.tsŠ +M޶ +@121bdf1046708dcd2f7c80900beaafd362b9a7f02d02a4b39eb27f39d73c9d87" TsProject(:$ +PATH/bin:/usr/bin:/usr/local/binB3JJKLMZ +supports-path-mapping1hJr@@platforms//host:host +H‡x@170a6ade2e703fab4f3dc67c45dee7c2309a69850303f8638d31b50bbba9979b"RepoMappingManifest(JHhHr@@platforms//host:host"*+/B�commonjs‹B� protocol.js� +N�B‘query.js� +O‘B’ protocol.d.ts� +P’B“ +query.d.ts� +Q“¶ @eb70c7f97e2bb8f5fafa862131b73ff9d4ead652d655ca0a50b666f0ab914da2" TsProject(:$ +PATH/bin:/usr/bin:/usr/local/binB*JNOPQZ +supports-path-mapping1hNr@@platforms//host:host +F…B”module.package.json- +R”B• README.md- +S•B–LICENSE- +T–"2FJKLMNOPQRSTABC"12D"01;B—oliphaunt-ts-query.tgz +U—u @14e4b9ba30e7e0fbf72f2d1a4350e0938c172b1965375bffaeafa4ba4fc8d8d8" QueryEnvelope(B0JUhUr@@platforms//host:host}@508f993cdec86653e41f1ace9feaacb9cfa1eb8d095ddc04168c89046a1ec842"SourceSymlinkManifest(BJGhGr@@platforms//host:hostB"˜validator.runfiles_manifestM +V˜"6G} @13d51e1fac28ddc9aca91b290ea8733ba5d35a33c7904c0df272ebf35cd12613"SourceSymlinkManifest(BJVhVr@@platforms//host:hostB"™unit_test.runfiles_manifestB› tsc.runfiles +W™BšMANIFEST› +Xšz@3a906f60ecc5e30400344adf6001ddb42db3e92b914004ae55e63580e01681c7"SourceSymlinkManifest(JWhWr@@platforms//host:hosts@1f17070e60e3bf9a9669670316b52e74d536f87222038f3a83a6a7e8a90cb6d4" SymlinkTree(B6JXhXr@@platforms//host:host" <$$"=$";<=">$":;>B�node_binB œnode� +YœB,¢%rules_nodejs++node+nodejs_linux_amd64B ¡bin¢B nodejs¡B Ÿbin B žnodeŸ"@V"AWB¥validator.runfilesMB£MANIFEST¥B¦unit_test.runfiles +ZžB¤MANIFEST¦ +\¤ +[£B¨node-bootstraps@cb69b03d8a1b01347e46537d8b3df85ef4e388f5a184e9deb179862b9cd65f29" SymlinkTree(BAJ\h\r@@platforms//host:hostB§fs.cjs¨ +]§s @6f39b35c51abc0e698bc3153a3b074c18e08c2f6d3da4848388f8c84f2496ad3" SymlinkTree(B@J[h[r@@platforms//host:hostB© bootstrap.cjs¨ +^©Bª launcher.cjs¨ +_ªB«util.cjs¨ +`«" ?YZ]^_`"9:?"89" 78X?q@709e80c88487a2411e1ee4dfb9f22a861492d20c4765150c0c794abd70f8147c" Middleman(B7JEhEr@@platforms//host:host"D + >;"CD<" BC\HB®internalB­ +_middlemen®B+¬#src_Squery_Sts_Sunit_Utest-runfiles­ +a¬q@709e80c88487a2411e1ee4dfb9f22a861492d20c4765150c0c794abd70f8147c" Middleman(BBJahar@@platforms//host:host" +J$!$"IJ="HI>" K YZ]^_`"GHK"FG " EF[3q @709e80c88487a2411e1ee4dfb9f22a861492d20c4765150c0c794abd70f8147c" Middleman(BEJ2h2r@@platforms//host:hostB¯ test-setup.sh +b¯B°generate-xml.sh +c°"LabcB¶testlogsB µsrc¶B ´queryµB +³ts´B² unit_test³B±test.log² +d±B·test.xml² +e·B¸test.cache_status² +f¸B¹ test.outputs² +g¹›@6ed99f9926c5224d162959d96f5725ecf16b892c1a3df98821d2c5892b186ea3" +TestRunner(:$ +PATH/bin:/usr/bin:/usr/local/binBLJdefghdr@@platforms//host:host" !"$"!=">" MYZ]^_`"M"" 94Bcº\external_Saspect_Urules_Uts++typescript+npm_Utypescript_Stsc_Uworker_U_Stsc_Uworker-runfilesg +hºq@709e80c88487a2411e1ee4dfb9f22a861492d20c4765150c0c794abd70f8147c" Middleman(BJhhhr@@platforms//host:host \ No newline at end of file diff --git a/tools/release/fixtures/aquery-bazel-8.8.1/provenance.json b/tools/release/fixtures/aquery-bazel-8.8.1/provenance.json new file mode 100644 index 000000000..eb55b88bd --- /dev/null +++ b/tools/release/fixtures/aquery-bazel-8.8.1/provenance.json @@ -0,0 +1,176 @@ +{ + "purpose": "Stock format/schema and resolved graph parity only; no native execution or release qualification claim.", + "sourceCommit": "5922eaede59aa50b8bd5349d2d037eb9200cef07", + "sourceState": "Root-owned local diagnostic with separately frozen scalar-AOT working changes.", + "bazelVersion": "8.8.1", + "scope": "deps(set(//src/query/ts:shipping_package //src/query/ts:unit_test))", + "files": [ + { + "name": "aquery.pb", + "sha256": "ef2b3048b90e11a17276bdb290fcb5fd91c83de1f969b7286eb8df81119e294d", + "size": 76151 + }, + { + "name": "aquery.json", + "sha256": "5d56248de7d5dd6acf9f9d583fbbeaea5c36075c7c837a17500e25ccd998926e", + "size": 130571 + }, + { + "name": "shipping_package.shipping.json", + "sha256": "a5d0fa5e824881995f0c699b7b9dbbd1465f35eb2816d68606d0daaa84f3d659", + "size": 314 + } + ], + "queries": { + "proto": { + "format": "proto", + "bazelVersion": "8.8.1", + "command": [ + "aquery" + ], + "residual": [ + "deps(set(//src/query/ts:shipping_package //src/query/ts:unit_test))" + ], + "options": [ + { + "name": "output", + "value": "proto" + }, + { + "name": "output_file", + "value": "/tmp/oliphaunt-5922-stock-proto-parity/aquery.pb" + }, + { + "name": "include_artifacts", + "value": "true" + }, + { + "name": "include_pruned_inputs", + "value": "true" + }, + { + "name": "include_aspects", + "value": "true" + }, + { + "name": "implicit_deps", + "value": "true" + }, + { + "name": "tool_deps", + "value": "true" + }, + { + "name": "nodep_deps", + "value": "true" + }, + { + "name": "include_commandline", + "value": "false" + }, + { + "name": "include_param_files", + "value": "false" + }, + { + "name": "include_file_write_contents", + "value": "false" + }, + { + "name": "skyframe_state", + "value": "false" + } + ] + }, + "jsonproto": { + "format": "jsonproto", + "bazelVersion": "8.8.1", + "command": [ + "aquery" + ], + "residual": [ + "deps(set(//src/query/ts:shipping_package //src/query/ts:unit_test))" + ], + "options": [ + { + "name": "output", + "value": "jsonproto" + }, + { + "name": "output_file", + "value": "/tmp/oliphaunt-5922-stock-proto-parity/aquery.json" + }, + { + "name": "include_artifacts", + "value": "true" + }, + { + "name": "include_pruned_inputs", + "value": "true" + }, + { + "name": "include_aspects", + "value": "true" + }, + { + "name": "implicit_deps", + "value": "true" + }, + { + "name": "tool_deps", + "value": "true" + }, + { + "name": "nodep_deps", + "value": "true" + }, + { + "name": "include_commandline", + "value": "false" + }, + { + "name": "include_param_files", + "value": "false" + }, + { + "name": "include_file_write_contents", + "value": "false" + }, + { + "name": "skyframe_state", + "value": "false" + } + ] + } + }, + "configurations": [ + { + "id": 1, + "mnemonic": "k8-fastbuild", + "platformName": "k8", + "checksum": "f55cd0755219b272bb7b1eeb31dd83dd10bc8c00329f25764eb9ea725eeff190" + }, + { + "id": 2, + "mnemonic": "k8-fastbuild", + "platformName": "k8", + "checksum": "0db2b318338ce09df9dbfeda423511d29dd37e81a4519b8ba56a33ac4076bea9" + }, + { + "id": 3, + "mnemonic": "k8-opt-exec-ST-d57f47055a04", + "platformName": "k8", + "checksum": "ed5797a767b96f3a1479df6c05824854fc306bea605a92620af0492ebf871581", + "isTool": true + } + ], + "compilationMode": { + "query": "stock default; command option omitted; actual graph mnemonic k8-fastbuild", + "shipping": "explicit -c fastbuild --output_groups=+shipping_manifest" + }, + "shipping": { + "producingTarget": "//src/query/ts:shipping_package", + "compilationMode": "fastbuild", + "path": "/tmp/oliphaunt-bazel-resources-output/execroot/_main/bazel-out/k8-fastbuild/bin/src/query/ts/shipping_package.shipping.json" + } +} diff --git a/tools/release/fixtures/aquery-bazel-8.8.1/shipping_package.shipping.json b/tools/release/fixtures/aquery-bazel-8.8.1/shipping_package.shipping.json new file mode 100644 index 000000000..c844e8254 --- /dev/null +++ b/tools/release/fixtures/aquery-bazel-8.8.1/shipping_package.shipping.json @@ -0,0 +1 @@ +{"label":"@@//src/query/ts:shipping_package","package":{"configuration":"portable","ecosystem":"npm","name":"@oliphaunt/ts-query","outputs":[{"owner":"@@//src/query/ts:npm","path":"bazel-out/k8-fastbuild/bin/src/query/ts/oliphaunt-ts-query.tgz"}],"product":"oliphaunt-query-ts","role":"facade","version":"0.1.1"}} diff --git a/tools/release/frozen-consumer.mts b/tools/release/frozen-consumer.mts index 79a715b64..219be548c 100644 --- a/tools/release/frozen-consumer.mts +++ b/tools/release/frozen-consumer.mts @@ -19,10 +19,14 @@ import { } from 'node:fs'; import os from 'node:os'; import path from 'node:path'; +import { stageCargoCarrierInputs } from '../packaging/frozen-cargo.mts'; import { extractPortableArchiveTree, readPortableArchiveEntries, } from '../packaging/portable-archive.mts'; + +export { stageCargoCarrierInputs } from '../packaging/frozen-cargo.mts'; + import { boundedResponseBytes } from './github-read.mts'; import { publicCargoEnvironment, sanitizedPublicEnvironment } from './public-consumer-smoke.mts'; import { loadPublicationCatalog } from './publication-catalog.mts'; @@ -701,23 +705,20 @@ function verifyFrozenFiles(lock) { } export function stageFrozenCargo(lock, directory) { - const patches = []; - for (const carrier of lock.carriers.filter((carrier) => carrier.ecosystem === 'cargo')) { - const { file: archive } = lockedCarrierFile(lock, 'cargo', carrier.name); - const destination = path.join(directory, 'crates', `${carrier.name}-${carrier.version}`); - extractPortableArchiveTree(archive, destination, `${carrier.name}-${carrier.version}`); - const manifest = Bun.TOML.parse(readFileSync(path.join(destination, 'Cargo.toml'), 'utf8')); - if ( - manifest.package?.name !== carrier.name || - manifest.package?.version !== carrier.version || - Object.hasOwn(manifest.package?.metadata?.oliphaunt ?? {}, 'qualificationOnly') - ) - throw new Error(`frozen Cargo identity differs: ${carrier.id}`); - patches.push(`${JSON.stringify(carrier.name)} = { path = ${JSON.stringify(destination)} }`); - } - const config = path.join(directory, 'cargo-config.toml'); - writeFileSync(config, `[patch.crates-io]\n${patches.join('\n')}\n`); - return config; + return stageCargoCarrierInputs( + lock.carriers + .filter((carrier) => carrier.ecosystem === 'cargo') + .map((carrier) => { + const { file, carrier: verified } = lockedCarrierFile(lock, 'cargo', carrier.name); + return { + file, + name: carrier.name, + version: carrier.version, + sha256: verified.artifacts[0].sha256, + }; + }), + directory, + ); } async function npmConsumer( @@ -1327,6 +1328,7 @@ async function swiftConsumer(test, lock, directory, environment) { outputFile: path.join(directory, 'Package.swift'), }); const app = path.join(directory, 'app'); + const swiftBuild = path.join(directory, 'swift-build'); mkdirSync(path.join(app, 'Sources/FrozenConsumer'), { recursive: true }); writeFileSync( path.join(app, 'Package.swift'), @@ -1352,6 +1354,8 @@ async function swiftConsumer(test, lock, directory, environment) { [ 'swift', 'build', + '--scratch-path', + swiftBuild, '--package-path', app, '--triple', @@ -1365,11 +1369,133 @@ async function swiftConsumer(test, lock, directory, environment) { ); } else await command( - ['swift', 'run', '--package-path', app, 'FrozenConsumer'], + ['swift', 'run', '--scratch-path', swiftBuild, '--package-path', app, 'FrozenConsumer'], directory, environment, path.join(directory, 'execute.log'), ); + const fixture = lock.productArtifacts.find( + (artifact) => + artifact.product === test.product && artifact.kind === 'swiftpm-extension-consumer-fixture', + ); + if (fixture) { + const { extensionReleaseConsumerInputs } = await import( + '../../src/native/sdks/swift/tools/swift-extension-release-consumer-inputs.mts' + ); + const { swiftExtensionReleaseConsumerFiles } = await import( + '../../src/native/sdks/swift/tools/extension-release-consumer.mts' + ); + const { localizeSwiftExtensionFixturePackage } = await import( + '../../src/native/sdks/swift/tools/swift-extension-fixture-consumer.mts' + ); + const source = lock.productArtifacts.find( + (artifact) => + artifact.product === test.product && artifact.kind === 'swiftpm-ios-carrier-manifest', + ); + if (!source) throw new Error('Swift fixture requires its original source carrier'); + const sourceCarrier = path.join(ROOT, source.path); + const base = json(sourceCarrier).base; + const resources = base.assets.find((asset) => asset.role === 'runtime-resources'); + if (!resources) throw new Error('Swift fixture requires original held resource archive'); + const resourceFile = path.join(directory, resources.name); + const frozen = lock.productArtifacts.find((artifact) => artifact.name === resources.name); + let resourceBytes; + if (frozen) resourceBytes = readFileSync(path.join(ROOT, frozen.path)); + else { + const response = await fetch(resources.url, { signal: AbortSignal.timeout(180_000) }); + if (!response.ok) + throw new Error(`Swift fixture resource provider returned ${response.status}`); + resourceBytes = await boundedResponseBytes( + response, + 2 * 1024 * 1024 * 1024, + 'Swift fixture resource provider', + ); + } + if ( + resourceBytes.length !== resources.bytes || + createHash('sha256').update(resourceBytes).digest('hex') !== resources.sha256 + ) + throw new Error('Swift fixture resource provider bytes differ'); + writeFileSync(resourceFile, resourceBytes); + const selected = path.join(directory, 'selected-extensions'); + cpSync(path.join(ROOT, fixture.path), selected, { recursive: true }); + const products = json(path.join(selected, 'extension-products.json')); + const owners = new Set(products.selected.map((row) => row.releaseProduct ?? row.product)); + const controls = lock.productArtifacts.filter( + (artifact) => artifact.kind === 'swift-extension-carrier' && owners.has(artifact.product), + ); + const coreFile = assets.find((file) => path.basename(file).startsWith('liboliphaunt-')); + const input = (file) => ({ + path: file, + size: readFileSync(file).length, + sha256: createHash('sha256').update(readFileSync(file)).digest('hex'), + }); + const plan = extensionReleaseConsumerInputs({ + sourceCarrierFile: sourceCarrier, + extensionCarrierFiles: controls.map((artifact) => path.join(ROOT, artifact.path)), + nativeBaseArchiveInputs: { + 'base-xcframework': input(coreFile), + 'runtime-resources': input(resourceFile), + }, + }); + writeFileSync( + path.join(selected, 'Package.swift'), + localizeSwiftExtensionFixturePackage( + readFileSync(path.join(selected, 'Package.swift'), 'utf8'), + products, + lock.products.find((product) => product.id === test.product).version, + directory, + ), + ); + const consumer = path.join(directory, 'extension-consumer'); + mkdirSync(path.join(consumer, 'Sources/OliphauntExtensionReleaseConsumer'), { + recursive: true, + }); + const generated = swiftExtensionReleaseConsumerFiles({ + plan, + products, + selectedPackage: selected, + releasePackage: directory, + }); + writeFileSync(path.join(consumer, 'Package.swift'), generated.packageFile); + writeFileSync( + path.join(consumer, 'Sources/OliphauntExtensionReleaseConsumer/main.swift'), + generated.main, + ); + const args = + test.integration === 'ios' + ? [ + 'build', + '--triple', + 'arm64-apple-ios17.0-simulator', + '--sdk', + ( + await command( + ['xcrun', '--sdk', 'iphonesimulator', '--show-sdk-path'], + directory, + environment, + path.join(directory, 'extension-sdk.log'), + ) + ).trim(), + ] + : ['run']; + const result = await command( + [ + 'swift', + ...args, + '--scratch-path', + swiftBuild, + '--package-path', + consumer, + ...(test.integration === 'ios' ? [] : ['OliphauntExtensionReleaseConsumer']), + ], + directory, + environment, + path.join(directory, 'extension-execute.log'), + ); + if (test.integration !== 'ios' && !result.includes('OLIPHAUNT_SWIFT_')) + throw new Error('Swift fixture final-link proof marker is missing'); + } const resolution = { manifest, providers: binaries.map(([, url, checksum]) => ({ url, checksum })), diff --git a/tools/release/github-read.mts b/tools/release/github-read.mts index f6345958f..93dfb63fe 100644 --- a/tools/release/github-read.mts +++ b/tools/release/github-read.mts @@ -45,6 +45,136 @@ function compareText(left, right) { return left < right ? -1 : left > right ? 1 : 0; } +/** Match a requested Actions ref, optionally against the acquired run facts. + * A queue ref remains construction context; it cannot establish reviewed main. + */ +export function matchesGithubWorkflowRef( + event: string, + ref: string, + origin?: { headBranch?: string; pullRequestNumbers?: number[] }, +) { + const pattern = + event === 'pull_request' + ? /^refs\/pull\/[1-9][0-9]*\/merge$/u + : event === 'merge_group' + ? /^refs\/heads\/gh-readonly-queue\/main\/[^\s\u0000-\u001f\u007f]+$/u + : ['push', 'workflow_dispatch'].includes(event) + ? /^refs\/heads\/[^\s\u0000-\u001f\u007f]+$/u + : undefined; + if (!pattern?.test(ref)) return false; + if (origin === undefined) return true; + return event === 'pull_request' + ? origin.pullRequestNumbers?.includes(Number(ref.split('/')[2])) === true + : ref === `refs/heads/${origin.headBranch}`; +} + +/** The latest execution of one role, not the latest workflow attempt. + * A newer failed or cancelled execution must never fall back to an older success. + */ +export function latestGithubJob(snapshot, name: string) { + const jobs = snapshot.jobs.filter((job) => job.name === name); + if (!jobs.length) return undefined; + if ( + jobs.some( + (job) => + !Number.isSafeInteger(job.run_attempt) || + job.run_attempt <= 0 || + job.run_attempt > snapshot.runAttempt, + ) + ) + throw new Error(`job ${name} has an invalid producing attempt`); + const attempt = jobs.reduce((maximum, job) => Math.max(maximum, job.run_attempt), 0); + const latest = jobs.filter((job) => job.run_attempt === attempt); + if (latest.length !== 1) throw new Error(`job ${name} has ambiguous latest executions`); + const selected = latest[0]; + if (selected.status !== 'completed') return selected; + const time = (value) => (typeof value === 'string' ? Date.parse(value) : NaN); + const start = time(selected.started_at); + const end = time(selected.completed_at); + const created = time(selected.created_at); + const sameWindow = (job) => + typeof selected.started_at === 'string' && + typeof selected.completed_at === 'string' && + job.started_at === selected.started_at && + job.completed_at === selected.completed_at; + const earlier = jobs.filter((job) => job.run_attempt < attempt); + // GitHub copies retained roles into reruns after their physical execution ended. + if (!(created > end) && !earlier.some(sameWindow)) return selected; + if ( + ![start, end, created].every(Number.isFinite) || + start > end || + !Number.isSafeInteger(selected.run_id) || + selected.run_id <= 0 || + typeof selected.head_sha !== 'string' || + !/^[0-9a-f]{40}$/u.test(selected.head_sha ?? '') || + typeof selected.conclusion !== 'string' || + selected.conclusion.length === 0 || + (snapshot.runId !== undefined && String(selected.run_id) !== String(snapshot.runId)) || + (snapshot.headSha !== undefined && selected.head_sha !== snapshot.headSha) + ) + throw new Error(`job ${name} has invalid inherited execution identity or window`); + const sameExecution = (job) => + ['name', 'run_id', 'head_sha', 'status', 'conclusion', 'started_at', 'completed_at'].every( + (field) => job[field] === selected[field], + ); + const retained = earlier.filter(sameWindow); + if (retained.some((job) => !sameExecution(job) || !Number.isFinite(time(job.created_at)))) + throw new Error(`job ${name} has conflicting inherited executions`); + const origins = retained.filter((job) => time(job.created_at) <= start); + if (origins.length !== 1) + throw new Error(`job ${name} has missing or ambiguous inherited execution origin`); + const origin = origins[0]; + if (retained.some((job) => job.run_attempt < origin.run_attempt)) + throw new Error(`job ${name} has an inherited execution before its origin`); + const lineage = jobs.filter((job) => job.run_attempt >= origin.run_attempt); + if (new Set(lineage.map((job) => job.run_attempt)).size !== lineage.length) + throw new Error(`job ${name} has ambiguous inherited executions`); + if ( + lineage.some( + (job) => + !Number.isSafeInteger(job.id) || + job.id <= 0 || + (job !== origin && + (!sameExecution(job) || + !Number.isFinite(time(job.created_at)) || + time(job.created_at) <= end)), + ) || + new Set(lineage.map((job) => job.id)).size !== lineage.length + ) + throw new Error(`job ${name} has conflicting inherited execution history`); + return origin; +} + +/** Artifact names can repeat on reruns. Bind the exact source and producer window first. */ +export function githubJobArtifact(snapshot, job, name: string, source: string) { + const start = Date.parse(job.started_at); + const end = Date.parse(job.completed_at); + if ( + job.status !== 'completed' || + job.conclusion !== 'success' || + !Number.isFinite(start) || + !Number.isFinite(end) || + start > end + ) + throw new Error(`job ${job.name} did not complete successfully with a valid producing window`); + const matches = snapshot.artifacts.filter((artifact) => { + const created = Date.parse(artifact.created_at); + return ( + artifact.name === name && + artifact.expired === false && + artifact.head_sha === source && + Number.isFinite(created) && + created >= start && + created < end + 1000 + ); + }); + if (matches.length !== 1) + throw new Error( + `${snapshot.runId}/${name} requires exactly one artifact bound to the selected source/job attempt; found ${matches.length}`, + ); + return matches[0]; +} + export class GitHubReadError extends Error { constructor( message, diff --git a/tools/release/github-read.test.mts b/tools/release/github-read.test.mts index 56bd54679..c47b4602c 100644 --- a/tools/release/github-read.test.mts +++ b/tools/release/github-read.test.mts @@ -9,7 +9,9 @@ import test from 'node:test'; import { readGitHubCoreRequestJournal } from './github-core-request-journal.mts'; import { GitHubReadError, + githubJobArtifact, githubReadOptionsFromEnv, + latestGithubJob, RetryableReadError, redactGitHubReadDetail, requestGithubGraphql, @@ -17,6 +19,169 @@ import { retryReadOperation, } from './github-read.mts'; +function inheritedJobFixture() { + // Execution fields and copy chronology follow run 39196019975's Linux x86_64 rows. + const original = { + id: 117880168369, + run_id: 39196019975, + head_sha: '1d5b15303737fe8d5a6bf49412755cdec99e69bf', + name: 'Linux runtime (x86_64)', + run_attempt: 1, + status: 'completed', + conclusion: 'success', + created_at: '2026-10-19T03:48:51Z', + started_at: '2026-10-19T03:48:53Z', + completed_at: '2026-10-19T06:51:36Z', + }; + const inherited = { + ...original, + id: 117974326985, + run_attempt: 2, + created_at: '2026-10-19T08:58:35Z', + }; + return { + original, + inherited, + snapshot: { + runId: String(original.run_id), + headSha: original.head_sha, + runAttempt: 2, + jobs: [original, inherited], + artifacts: [], + }, + }; +} + +test('inherited GitHub job records resolve to the original physical execution without rewriting snapshots', () => { + const { original, inherited, snapshot } = inheritedJobFixture(); + Object.assign(original, { steps: [{ name: 'Original display metadata' }] }); + Object.assign(inherited, { steps: [] }); + const before = JSON.stringify(snapshot); + assert.equal(latestGithubJob(snapshot, original.name), original); + assert.equal(JSON.stringify(snapshot), before); + snapshot.runAttempt = 3; + snapshot.jobs.push({ ...inherited, id: inherited.id + 1, run_attempt: 3 }); + assert.equal(latestGithubJob(snapshot, original.name), original); + original.created_at = original.started_at; + assert.equal(latestGithubJob(snapshot, original.name), original); +}); + +for (const outcome of ['success', 'failure', 'cancelled', 'pending']) + test(`a newer physical ${outcome} job remains selected ahead of an older success`, () => { + const { original, inherited, snapshot } = inheritedJobFixture(); + Object.assign(inherited, { + started_at: '2026-10-19T09:00:00Z', + completed_at: outcome === 'pending' ? null : '2026-10-19T09:01:00Z', + status: outcome === 'pending' ? 'in_progress' : 'completed', + conclusion: outcome === 'pending' ? null : outcome, + }); + assert.equal(latestGithubJob(snapshot, original.name), inherited); + }); + +for (const outcome of ['failure', 'cancelled']) + test(`an inherited ${outcome} job cannot become an older success`, () => { + const { original, inherited, snapshot } = inheritedJobFixture(); + original.conclusion = inherited.conclusion = outcome; + assert.equal(latestGithubJob(snapshot, original.name), original); + assert.equal(latestGithubJob(snapshot, original.name).conclusion, outcome); + }); + +const invalidInheritedJobs: [ + string, + (fixture: ReturnType) => unknown, +][] = [ + ['missing original', ({ snapshot }) => snapshot.jobs.shift()], + ['same-attempt copies', ({ inherited, snapshot }) => snapshot.jobs.push({ ...inherited, id: 9 })], + ['duplicate origins', ({ original, snapshot }) => snapshot.jobs.unshift({ ...original, id: 8 })], + [ + 'copy before its physical origin', + ({ original, inherited, snapshot }) => { + snapshot.jobs.splice(1, 0, { ...original, id: 8, run_attempt: 2 }); + original.created_at = inherited.created_at; + inherited.run_attempt = snapshot.runAttempt = 3; + }, + ], + ['changed source', ({ inherited }) => (inherited.head_sha = 'f'.repeat(40))], + ['changed run', ({ inherited }) => (inherited.run_id += 1)], + [ + 'missing source', + ({ original, inherited }) => { + Reflect.deleteProperty(original, 'head_sha'); + Reflect.deleteProperty(inherited, 'head_sha'); + }, + ], + [ + 'missing run', + ({ original, inherited }) => { + Reflect.deleteProperty(original, 'run_id'); + Reflect.deleteProperty(inherited, 'run_id'); + }, + ], + ['wrong snapshot source', ({ snapshot }) => (snapshot.headSha = 'e'.repeat(40))], + ['wrong snapshot run', ({ snapshot }) => (snapshot.runId = '123')], + ['changed outcome', ({ inherited }) => (inherited.conclusion = 'failure')], + ['missing creation', ({ inherited }) => Reflect.deleteProperty(inherited, 'created_at')], + ['invalid creation', ({ inherited }) => (inherited.created_at = 'invalid')], + [ + 'alias created at completion', + ({ inherited }) => (inherited.created_at = inherited.completed_at), + ], + [ + 'original created after start', + ({ original }) => (original.created_at = '2026-10-19T03:49:00Z'), + ], + [ + 'reversed window', + ({ original, inherited }) => { + original.started_at = inherited.started_at = '2026-10-19T07:00:00Z'; + }, + ], + [ + 'invalid window', + ({ original, inherited }) => { + original.started_at = inherited.started_at = 'invalid'; + }, + ], +]; +for (const [fault, mutate] of invalidInheritedJobs) + test(`inherited GitHub jobs reject ${fault}`, () => { + const f = inheritedJobFixture(); + mutate(f); + assert.throws(() => latestGithubJob(f.snapshot, f.original.name)); + }); + +for (const outcome of ['success', 'failure', 'cancelled', 'pending']) + test(`an inherited record cannot bypass an intervening physical ${outcome} execution`, () => { + const { original, inherited, snapshot } = inheritedJobFixture(); + snapshot.runAttempt = 3; + snapshot.jobs.push({ ...inherited, id: 7, run_attempt: 3 }); + Object.assign(inherited, { + started_at: '2026-10-19T09:00:00Z', + completed_at: outcome === 'pending' ? null : '2026-10-19T09:01:00Z', + status: outcome === 'pending' ? 'in_progress' : 'completed', + conclusion: outcome === 'pending' ? null : outcome, + }); + assert.throws(() => latestGithubJob(snapshot, original.name)); + }); + +test('a completed job with an incomplete window cannot fall back or authorize artifact download', () => { + const { original, inherited, snapshot } = inheritedJobFixture(); + Reflect.deleteProperty(inherited, 'completed_at'); + assert.equal(latestGithubJob(snapshot, original.name), inherited); + assert.throws( + () => githubJobArtifact(snapshot, inherited, 'native-build-evidence-x86_64', original.head_sha), + /valid producing window/u, + ); +}); + +test('an inherited Required record does not establish a current-attempt physical gate', () => { + const { original, inherited, snapshot } = inheritedJobFixture(); + original.name = inherited.name = 'Required'; + const required = latestGithubJob(snapshot, 'Required'); + assert.equal(required, original); + assert.notEqual(required.run_attempt, snapshot.runAttempt); +}); + function deterministic(overrides = {}) { let time = 1_000; return { diff --git a/tools/release/independent-version-pins.test.mts b/tools/release/independent-version-pins.test.mts index f0b901bb0..15929ef28 100644 --- a/tools/release/independent-version-pins.test.mts +++ b/tools/release/independent-version-pins.test.mts @@ -1,44 +1,44 @@ +import { test } from 'bun:test'; import assert from 'node:assert/strict'; import { spawnSync } from 'node:child_process'; import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; import path from 'node:path'; -import { test } from 'bun:test'; - -import { - compatibilityVersionEntries, - compatibilityVersionValue, - loadProducts, - productCompatibilityVersion, - productDependencyCompatibilityVersion, - ROOT, -} from './release-graph.mts'; -import { - prepareSourceOnlyNpmPackage, - SOURCE_ONLY_NPM_PROFILES, -} from '../packaging/source-only-sdk-package.mts'; -import { - packagedCargoManifestText, - packageGeneratedCargoSource, -} from '../packaging/cargo-source-package.mts'; -import { preparePackagedCargoTestClosure } from '../packaging/cargo-package-test-closure.mts'; import { renderReleaseCargoToml } from '../../src/native/sdks/rust/tools/prepare-rust-release-source.mts'; -import { renderOliphauntWasixReleaseCargoToml } from '../../src/wasix/sdks/rust/tools/prepare-rust-release-source.mts'; -import { prepareWasixTypescriptPackage } from '../../src/wasix/sdks/ts/tools/package.mts'; -import { assertWasixTypescriptManifest } from '../../src/wasix/sdks/ts/tools/wasix-typescript-package.mts'; +import { assertWasixNapiCarrierManifest } from '../../src/wasix/node-addon/tools/check-release-assets.mts'; import { + resolvedAdapterRuntimeContract, workspaceCarrierManifest, workspaceRuntimeVersion, } from '../../src/wasix/node-addon/tools/workspace-runtime-contract.mts'; -import { assertWasixNapiCarrierManifest } from '../../src/wasix/node-addon/tools/check-release-assets.mts'; -import { requireMatchingWasixRuntime } from './compatibility-version-policy.mts'; -import { workspaceBindingManifest } from '../../src/wasix/sdks/ts/tools/integration/packed-node-fixture.mts'; import { prepareWasixToolsTypescriptPackage } from '../../src/wasix/postgres-tools/ts/tools/wasix-tools-typescript-package.mts'; +import { renderOliphauntWasixReleaseCargoToml } from '../../src/wasix/sdks/rust/tools/prepare-rust-release-source.mts'; +import { workspaceBindingManifest } from '../../src/wasix/sdks/ts/tools/integration/packed-node-fixture.mts'; +import { prepareWasixTypescriptPackage } from '../../src/wasix/sdks/ts/tools/package.mts'; +import { assertWasixTypescriptManifest } from '../../src/wasix/sdks/ts/tools/wasix-typescript-package.mts'; +import { preparePackagedCargoTestClosure } from '../packaging/cargo-package-test-closure.mts'; +import { + packagedCargoManifestText, + packageGeneratedCargoSource, +} from '../packaging/cargo-source-package.mts'; +import { + prepareSourceOnlyNpmPackage, + SOURCE_ONLY_NPM_PROFILES, +} from '../packaging/source-only-sdk-package.mts'; import { validateCarrierCoverage } from './check_artifact_targets.mts'; +import { requireMatchingWasixRuntime } from './compatibility-version-policy.mts'; import { loadPublicationCatalog } from './publication-catalog.mts'; import { allArtifactTargets, nativeToolsOptionalPackageProducts, } from './release-artifact-targets.mts'; +import { + compatibilityVersionEntries, + compatibilityVersionValue, + loadProducts, + productCompatibilityVersion, + productDependencyCompatibilityVersion, + ROOT, +} from './release-graph.mts'; if (process.env.OLIPHAUNT_INDEPENDENT_VERSION_TEST !== '1' || existsSync(path.join(ROOT, '.git'))) { throw new Error('Run bash tools/release/independent-version-pins.test.sh'); @@ -68,6 +68,8 @@ for (const [index, product] of [...new Set(sdkPins.map((entry) => entry.sourcePr write(file, read(file).replace(/^version = "[^"]+"/mu, `version = "${version}"`)); } else if (path.basename(file) === 'gradle.properties') { write(file, read(file).replace(/^VERSION_NAME=.+/mu, `VERSION_NAME=${version}`)); + } else if (file.endsWith('.podspec')) { + write(file, read(file).replace(/(s\.version\s*=\s*)'[^']+'/u, `$1'${version}'`)); } else if (path.basename(file) === 'liboliphaunt_native.c') { write( file, @@ -91,11 +93,7 @@ function stageManifest(name, source) { test('every SDK retains its declared compatibility pins after independent dependency releases', () => { assert.ok(sdkPins.length > 0); for (const entry of sdkPins) { - assert.equal( - productCompatibilityVersion(entry.product, entry.sourceProduct), - entry.value, - entry.id, - ); + assert.equal(compatibilityVersionValue(entry), entry.value, entry.id); const source = products[entry.sourceProduct]; if (source.version !== manifest[source.path]) { assert.notEqual(entry.value, manifest[source.path], entry.id); @@ -142,7 +140,7 @@ test('React Native resolves the runtime through its pinned Swift release after S 'liboliphaunt-native', 'independent-version-pins', { - readCompatibility(product, source, prefix, { ref }) { + readCompatibility(product, source, _prefix, { ref }) { assert.equal(product, 'oliphaunt-swift'); assert.equal(source, 'liboliphaunt-native'); assert.equal(ref, `${products[product].tag_prefix}${swiftPin}`); @@ -209,51 +207,112 @@ test('WASIX tools staging retains its explicit SDK pin after that SDK advances', } }); -test('WASIX addon qualification identifies the compiled workspace runtime without changing release pins', () => { +test('WASIX addon qualification requires aligned local sources after producers advance', () => { const product = json('src/wasix/node-addon/package.json'); const original = json('src/wasix/node-addon/packages/linux-x64-gnu/package.json'); - const staged = workspaceCarrierManifest(original, product.oliphaunt); - assert.equal(staged.oliphaunt.runtimeVersion, workspaceRuntimeVersion()); - assert.notEqual(staged.oliphaunt.runtimeVersion, original.oliphaunt.runtimeVersion); - assert.equal(staged.oliphaunt.qualificationOnly, true); - const currentRust = Bun.TOML.parse(read('src/wasix/sdks/rust/Cargo.toml')).package.version; - const currentContract = { - runtimeVersion: workspaceRuntimeVersion(), - rustBindingVersion: currentRust, - }; - const aligned = workspaceCarrierManifest(original, currentContract); - assert.equal(Object.hasOwn(aligned.oliphaunt, 'qualificationOnly'), false); - const rustOnly = workspaceCarrierManifest(original, { - ...currentContract, - rustBindingVersion: '0.0.0', - }); - assert.equal(rustOnly.oliphaunt.qualificationOnly, true); - assert.deepEqual(json('src/wasix/node-addon/packages/linux-x64-gnu/package.json'), original); - const target = { - target: 'linux-x64-gnu', - npmPackage: original.name, - npmOs: 'linux', - npmCpu: 'x64', - npmLibc: 'glibc', - }; - assert.doesNotThrow(() => - assertWasixNapiCarrierManifest(staged, target, original.version, 'workspace', staged.oliphaunt), - ); - assert.throws( - () => assertWasixNapiCarrierManifest(staged, target, original.version), - /runtime\/ABI\/profile metadata/u, - ); - const result = spawnSync( - process.execPath, - [ - 'src/wasix/node-addon/tools/native-build-data.mts', - 'metadata', - 'src/wasix/node-addon/package.json', - ], - { cwd: ROOT, encoding: 'utf8' }, - ); - assert.equal(result.status, 0, result.stderr); - assert.equal(result.stdout.split('\t')[0], staged.oliphaunt.runtimeVersion); + assert.throws(() => resolvedAdapterRuntimeContract(), /must resolve local/u); + const files = [ + 'Cargo.toml', + 'Cargo.lock', + 'src/wasix/node-addon/Cargo.toml', + 'src/wasix/runtime/crates/assets/Cargo.toml', + ]; + const sources = new Map(files.map((file) => [file, read(file)])); + try { + const runtimeVersion = workspaceRuntimeVersion(); + const sdkVersion = Bun.TOML.parse(read('src/wasix/sdks/rust/Cargo.toml')).package.version; + write( + 'Cargo.toml', + sources + .get('Cargo.toml') + .replace(/^(oliphaunt-wasix = \{[^\n]*version = ")[^"]+/mu, `$1${sdkVersion}`), + ); + write( + 'src/wasix/node-addon/Cargo.toml', + sources + .get('src/wasix/node-addon/Cargo.toml') + .replace( + /^(liboliphaunt-wasix-portable = \{[^\n]*version = ")[^"]+/mu, + `$1=${runtimeVersion}`, + ), + ); + write( + 'src/wasix/runtime/crates/assets/Cargo.toml', + sources + .get('src/wasix/runtime/crates/assets/Cargo.toml') + .replace(/^version = "[^"]+"/mu, `version = "${runtimeVersion}"`), + ); + let lockText = sources.get('Cargo.lock'); + const lock = Bun.TOML.parse(lockText); + for (const [name, version] of [ + ['oliphaunt-wasix', sdkVersion], + ['liboliphaunt-wasix-portable', runtimeVersion], + ]) { + const rows = lock.package.filter((pkg) => pkg.name === name && !pkg.source); + assert.equal(rows.length, 1); + lockText = lockText.replace( + `name = "${name}"\nversion = "${rows[0].version}"`, + `name = "${name}"\nversion = "${version}"`, + ); + } + write('Cargo.lock', lockText); + const resolved = resolvedAdapterRuntimeContract(); + assert.deepEqual(resolved, { runtimeVersion, rustBindingVersion: sdkVersion }); + const staged = workspaceCarrierManifest(original, product.oliphaunt); + assert.equal(staged.oliphaunt.runtimeVersion, runtimeVersion); + assert.equal(staged.oliphaunt.rustBindingVersion, sdkVersion); + assert.notEqual(staged.oliphaunt.runtimeVersion, original.oliphaunt.runtimeVersion); + assert.equal(staged.oliphaunt.qualificationOnly, true); + assert.deepEqual(json('src/wasix/node-addon/packages/linux-x64-gnu/package.json'), original); + assert.deepEqual(json('src/wasix/node-addon/package.json'), product); + const target = { + target: 'linux-x64-gnu', + npmPackage: original.name, + npmOs: 'linux', + npmCpu: 'x64', + npmLibc: 'glibc', + }; + assert.doesNotThrow(() => + assertWasixNapiCarrierManifest( + staged, + target, + original.version, + 'workspace', + staged.oliphaunt, + ), + ); + assert.throws( + () => assertWasixNapiCarrierManifest(staged, target, original.version), + /runtime\/ABI\/profile metadata/u, + ); + const result = spawnSync( + process.execPath, + [ + 'src/wasix/node-addon/tools/native-build-data.mts', + 'metadata', + 'src/wasix/node-addon/package.json', + ], + { cwd: ROOT, encoding: 'utf8' }, + ); + assert.equal(result.status, 0, result.stderr); + assert.equal(result.stdout.split('\t')[0], runtimeVersion); + const runtimeRow = `name = "liboliphaunt-wasix-portable"\nversion = "${runtimeVersion}"`; + write( + 'Cargo.lock', + lockText.replace( + runtimeRow, + `${runtimeRow}\nsource = "registry+https://github.com/rust-lang/crates.io-index"`, + ), + ); + assert.throws(() => resolvedAdapterRuntimeContract(), /must resolve local/u); + write( + 'Cargo.lock', + lockText.replace(runtimeRow, 'name = "liboliphaunt-wasix-portable"\nversion = "0.0.0"'), + ); + assert.throws(() => resolvedAdapterRuntimeContract(), /must resolve local/u); + } finally { + for (const [file, source] of sources) write(file, source); + } }); test('WASIX SDK release requires the same portable and addon runtime', () => { @@ -295,7 +354,9 @@ test('WASIX workspace consumer uses current producers while its release package test('native Rust source generation uses its native runtime and broker pins', () => { const source = read('src/native/sdks/rust/Cargo.toml'); const original = Bun.TOML.parse(source); - const staged = Bun.TOML.parse(packagedCargoManifestText(renderReleaseCargoToml(source))); + const staged = Bun.TOML.parse( + packagedCargoManifestText(renderReleaseCargoToml(source), read('Cargo.toml')), + ); assert.equal( staged.dependencies['oliphaunt-query'].version, original.dependencies['oliphaunt-query'].version, @@ -317,7 +378,7 @@ test('native Rust source generation uses its native runtime and broker pins', () } }); -test('WASIX Rust source generation retains its runtime and explicit query pins', () => { +test('WASIX Rust source generation retains runtime, query, tools and ICU pins', () => { const source = read('src/wasix/sdks/rust/Cargo.toml'); const original = Bun.TOML.parse(source); const staged = Bun.TOML.parse(renderOliphauntWasixReleaseCargoToml(source)); @@ -325,14 +386,58 @@ test('WASIX Rust source generation retains its runtime and explicit query pins', assert.equal(staged.dependencies['liboliphaunt-wasix-portable'].version, runtimeVersion); assert.equal( staged.dependencies['oliphaunt-query'].version, - `=${original.dependencies['oliphaunt-query'].version}`, + original.dependencies['oliphaunt-query'].version, + ); + const toolsVersion = `=${original.package.metadata.oliphaunt['tools-version']}`; + assert.equal(staged.dependencies['oliphaunt-wasix-tools'].version, toolsVersion); + assert.equal( + staged.dependencies['oliphaunt-icu'].version, + `=${original.package.metadata.oliphaunt['icu-version']}`, ); for (const { dependencies } of Object.values(staged.target)) { for (const [name, dependency] of Object.entries(dependencies)) { if (name.startsWith('liboliphaunt-wasix-aot-')) assert.equal(dependency.version, runtimeVersion); + if (name.startsWith('oliphaunt-wasix-tools-aot-')) + assert.equal(dependency.version, toolsVersion); + } + } +}); + +test('WASIX optional public requirements change only when the SDK explicitly retargets them', () => { + const source = read('src/wasix/sdks/rust/Cargo.toml'); + const original = Bun.TOML.parse(renderOliphauntWasixReleaseCargoToml(source)); + for (const [field, product, packagePrefix] of [ + ['tools-version', 'postgres-tools-wasix', 'oliphaunt-wasix-tools'], + ['icu-version', 'database-resources', 'oliphaunt-icu'], + ]) { + const retargeted = Bun.TOML.parse( + renderOliphauntWasixReleaseCargoToml( + source.replace(new RegExp(`^${field} = "[^"]+"`, 'mu'), `${field} = "99.0.0"`), + ), + ); + assert.equal(retargeted.dependencies[packagePrefix].version, '=99.0.0', product); + for (const [section, changedSection] of [ + [original, retargeted], + ...Object.keys(original.target).map((key) => [original.target[key], retargeted.target[key]]), + ]) { + for (const [name, dependency] of Object.entries(section.dependencies)) { + assert.equal( + changedSection.dependencies[name].version, + name.startsWith(packagePrefix) ? '=99.0.0' : dependency.version, + name, + ); + } } } + assert.throws( + () => renderOliphauntWasixReleaseCargoToml(source.replace(/^tools-version = .+\n/mu, '')), + /Missing installed compatibility pin for oliphaunt-wasix-tools/u, + ); + assert.throws( + () => renderOliphauntWasixReleaseCargoToml(source.replace(/^icu-version = .+\n/mu, '')), + /Missing installed compatibility pin for oliphaunt-icu/u, + ); }); test('WASIX Rust package qualification does not patch older pins with newer workspace sources', () => { diff --git a/tools/release/independent-version-pins.test.sh b/tools/release/independent-version-pins.test.sh index 193a2f8dc..719bb5a2c 100644 --- a/tools/release/independent-version-pins.test.sh +++ b/tools/release/independent-version-pins.test.sh @@ -5,7 +5,7 @@ scratch="$(mktemp -d "${TMPDIR:-/tmp}/oliphaunt-independent-versions-XXXXXX")" trap 'rm -rf "$scratch"' EXIT # Exercise the current sources in an isolated tree, including uncommitted fixes. -git ls-files -z --cached --others --exclude-standard -- tools src \ +git ls-files -z --cached --others --exclude-standard -- tools src build_defs \ LICENSE THIRD_PARTY_NOTICES.md .prototools package.json Cargo.toml Cargo.lock \ release-please-config.json .release-please-manifest.json | while IFS= read -r -d '' file; do @@ -14,5 +14,5 @@ git ls-files -z --cached --others --exclude-standard -- tools src \ tar -cf "$scratch/source.tar" --null -T "$scratch/files" mkdir "$scratch/source" tar -xf "$scratch/source.tar" -C "$scratch/source" -bash tools/ci/with-projects.sh --exec env OLIPHAUNT_INDEPENDENT_VERSION_TEST=1 \ +env OLIPHAUNT_INDEPENDENT_VERSION_TEST=1 \ bash "$scratch/source/tools/dev/bun.sh" test ./tools/release/independent-version-pins.test.mts diff --git a/tools/release/moon.yml b/tools/release/moon.yml index 76ec61dd6..8de026bd0 100644 --- a/tools/release/moon.yml +++ b/tools/release/moon.yml @@ -68,6 +68,7 @@ tasks: - /.release-please-manifest.json - /src/benchmarks/moon.yml - /Cargo.lock + - /src/wasix/node-addon/Cargo.lock - /Cargo.toml - /src/examples/moon.yml - /src/examples/**/Cargo.toml @@ -122,6 +123,23 @@ tasks: - requires-rust command: bash tools/release/release-check.sh --mutation-tests-only inputs: + - /build_defs/languages/swift/source-package.mts + - /build_defs/languages/swift/source-package.fixture.mts + - /build_defs/languages/swift/source-delivery-contract.mts + - /build_defs/languages/jvm/maven-pom.mts + - /build_defs/release/testdata/swift-0.8.2-carrier.json + - /build_defs/release/swift-0.8.2-publication-source.json + - /build_defs/release/native-0.3.3-completed-publication.json + - /src/native/runtime/include/oliphaunt.h + - /src/native/sdks/swift/tools/swift-release-manifest.mts + - /src/native/sdks/swift/tools/swift-xcframework-contract.mts + - /src/native/sdks/swift/tools/extension-resource-inventory.mts + - /src/native/sdks/swift/tools/render-extension-products.mts + - /src/extensions/generated/sdk/extensions.json + - /build_defs/native/carriers/envelopes.mts + - /build_defs/native/carriers/payload.mts + - /src/native/runtime/tools/native-runtime-payload.mts + - /src/native/runtime/tools/native-runtime-payload-policy.json - /src/**/tools/frozen-*.mts - /src/wasix/sdks/ts/tools/browser-cdp.mts - /src/native/runtime/smoke/frozen-consumer.c @@ -154,12 +172,20 @@ tasks: - /.prototools - /tools/dev/bun.sh - /src/native/sdks/kotlin/tools/kotlin-maven-staging.mts + - /src/native/sdks/swift/tools/ios-carrier-manifest.mts + - /src/native/sdks/swift/tools/native-legal-source-basis.mts + - /src/native/sdks/swift/tools/swift-native-carrier-contract.mts + - /src/native/sdks/swift/tools/pinned-native-carrier.mts + - /src/native/sdks/swift/tools/swift-source-carrier-contract.mts + - /src/native/sdks/swift/tools/prepare-swift-release-consumer.mts + - /src/native/sdks/swift/tools/swift-carrier-resolver.mts - "**/*" - "!/tools/release/**/*.md" options: cache: false runFromWorkspaceRoot: true version-pins-unit: + # Kept separate from mutation tests so pin changes retain their narrow scope. tags: - quality - unit @@ -167,6 +193,7 @@ tasks: inputs: - /Cargo.toml - /Cargo.lock + - /src/wasix/node-addon/Cargo.lock - "@group(package-test-metadata)" - "@group(release-target-contract)" - "@group(legal-files)" @@ -190,76 +217,6 @@ tasks: options: cache: true runFromWorkspaceRoot: true - graph-unit: - tags: - - quality - - unit - - requires-rust - inputs: - - "@group(package-test-metadata)" - - /.moon/tasks/**/* - - /.moon/toolchains.yml - - /.moon/workspace.yml - - /src/benchmarks/moon.yml - - /src/examples/moon.yml - - /moon.yml - - /.release-please-manifest.json - - /Cargo.toml - - /Cargo.lock - - /rust-toolchain.toml - - /**/Cargo.toml - - /src/**/*.rs - - /Package.swift - - /package.json - - /release-please-config.json - - /**/release.toml - - /**/targets/**/*.toml - - /**/moon.yml - - /tools/ci/**/* - - /tools/**/moon.yml - - /src/third-party/tools/source-fetch-core.mts - - /tools/release/artifact-target-matrix.mts - - /src/extensions/artifacts/packages/tools/contrib-carriers.mts - - /src/extensions/tools/extension-artifact-archive-policy.mts - - project: extension-runtime-contract - group: contract - - /src/extensions/artifacts/packages/tools/extension-artifact-inventory.mts - - /src/extensions/artifacts/packages/tools/extension-registry-packages.mts - - /src/extensions/contracts/extension-target-profiles.mts - - /src/extensions/tools/extension-upstream-licenses.mts - - /src/extensions/artifacts/native/tools/native-extension-asset-index-contract.mts - - /src/native/runtime/tools/native-runtime-payload.mts - - /tools/release/platform-compatibility-policy.mts - - /tools/release/release-artifact-targets.mts - - /tools/release/prepare-release-candidate.mts - - /tools/release/prepare-release-candidate.test.mts - - /tools/release/close-release-candidate.sh - - /tools/release/sync-release-pr.{mts,sh} - - /tools/release/release-metadata-check.sh - - /tools/release/check_artifact_targets.mts - - /tools/release/check-release-metadata.mts - - /tools/release/check_release_please_config.mts - - /tools/release/verify-release-commit.mts - - /tools/release/release-please-state.sh - - /tools/release/with-{product,release}-history.sh - - /tools/release/release-dependency-plan.mts - - /tools/release/frozen-consumer.mts - - /tools/release/frozen-extension-consumer.mts - - /tools/release/publication-catalog.mts - - /tools/release/publication-consumer-proof.mts - - /tools/release/consumer-compatibility.mts - - /tools/release/default-extension-release-plan.mts - - /tools/release/testdata/extension-release-fixture.mts - - "@group(release-archive-contract)" - - /tools/release/release-graph.mts - - /src/wasix/runtime/tools/wasix-cargo-artifact-contract.mts - - /tools/packaging/windows-vc-runtime-closure.mts - - package.json - - /bun.lock - options: - cache: true - runFromWorkspaceRoot: true - command: bash tools/ci/with-projects.sh test ./tools/release/prepare-release-candidate.test.mts check: tags: - policy @@ -268,7 +225,6 @@ tasks: deps: - release-tools:metadata - release-tools:test - - release-tools:graph-unit - release-tools:version-pins-unit inputs: [] diff --git a/tools/release/native-aquery.mts b/tools/release/native-aquery.mts new file mode 100644 index 000000000..3e40490df --- /dev/null +++ b/tools/release/native-aquery.mts @@ -0,0 +1,44 @@ +/** Standard stock Bazel protobuf decoding at the captured File boundary. */ +import { readFileSync } from 'node:fs'; +import { createRequire } from 'node:module'; + +export function nativeAqueryType(bazelVersion: string) { + const snapshot = JSON.parse( + readFileSync(new URL('./bazel-8.8.1/sources.json', import.meta.url), 'utf8'), + ); + if (snapshot.bazelVersion !== bazelVersion) + throw new Error('native aquery schema differs from the producing Bazel version'); + // The publisher's standalone full bundle preserves CommonJS. + const protobuf = createRequire(import.meta.url)('protobufjs/dist/protobuf.js'); + const root = new protobuf.Root(); + for (const source of snapshot.files) { + protobuf.parse( + readFileSync(new URL(`./bazel-8.8.1/${source.file}`, import.meta.url), 'utf8'), + root, + { keepCase: false }, + ); + } + root.resolveAll(); + return root.lookupType('analysis.ActionGraphContainer'); +} + +/** The format comes from the canonical query BEP, never from the filename. */ +export function readNativeAquery( + file: string, + format: 'jsonproto' | 'proto', + bazelVersion: string, +): unknown { + if (format === 'jsonproto') return JSON.parse(readFileSync(file, 'utf8')); + if (format !== 'proto') throw new Error('unsupported native aquery format'); + const type = nativeAqueryType(bazelVersion); + return type.toObject(type.decode(readFileSync(file)), { + defaults: false, + arrays: false, + objects: false, + oneofs: false, + longs: String, + enums: String, + bytes: String, + json: true, + }); +} diff --git a/tools/release/native-aquery.test.mts b/tools/release/native-aquery.test.mts new file mode 100644 index 000000000..3ebfdddcd --- /dev/null +++ b/tools/release/native-aquery.test.mts @@ -0,0 +1,103 @@ +import { expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { buildShippingInputView, configuredAqueryTargetInputs } from './bazel-shipping-inputs.mts'; +import { nativeAqueryType, readNativeAquery } from './native-aquery.mts'; + +const version = '8.8.1'; +const file = (name: string) => + fileURLToPath(new URL(`./fixtures/aquery-bazel-8.8.1/${name}`, import.meta.url)); + +test('full original upstream schemas retain their pinned bytes and license headers', () => { + const snapshot = JSON.parse( + readFileSync(new URL('./bazel-8.8.1/sources.json', import.meta.url), 'utf8'), + ); + expect(snapshot.bazelVersion).toBe(version); + for (const source of snapshot.files) { + const bytes = readFileSync(new URL(`./bazel-8.8.1/${source.file}`, import.meta.url)); + expect(bytes.length).toBe(source.size); + expect(createHash('sha256').update(bytes).digest('hex')).toBe(source.sha256); + expect(bytes.toString('utf8')).toContain('Licensed under the Apache License, Version 2.0'); + } +}); + +test('genuine stock protobuf and JSON preserve configured TestRunner and FileWrite semantics', () => { + const protobuf = readNativeAquery(file('aquery.pb'), 'proto', version) as any; + const json = readNativeAquery(file('aquery.json'), 'jsonproto', version) as any; + const label = '//src/query/ts:unit_test'; + const configuration = (graph: any) => { + const target = graph.targets.find((row: any) => row.label.replace(/^@@?\/\//u, '//') === label); + const test = graph.actions.find( + (row: any) => row.targetId === target.id && row.mnemonic === 'TestRunner', + ); + return graph.configuration.find((row: any) => row.id === test.configurationId).checksum; + }; + expect(configuration(protobuf)).toBe(configuration(json)); + const inputs = (graph: any) => { + const actual = configuredAqueryTargetInputs(graph, label, configuration(graph)); + return { inputs: [...actual.inputs].sort(), written: [...actual.written].sort() }; + }; + expect(inputs(protobuf)).toEqual(inputs(json)); + expect(inputs(protobuf).inputs.length).toBeGreaterThan(0); + expect(inputs(protobuf).written.length).toBeGreaterThan(0); + expect(protobuf.actions.length).toBe(json.actions.length); + expect(protobuf.artifacts.length).toBe(json.artifacts.length); + // Use the real stock JSON model as the schema conversion control. Independent + // raw query IDs/order may differ because the stock proto emitter is parallel. + const type = nativeAqueryType(version); + expect(type.toObject(type.decode(type.encode(type.fromObject(json)).finish()))).toEqual(json); +}); + +test('genuine shipping metadata resolves the same complete package inputs and producer actions', () => { + const root = JSON.parse(readFileSync(file('shipping_package.shipping.json'), 'utf8')); + // Adapt the actual emitted NativeRoot to the existing input-view API. All + // product/version/output/owner values come from that genuine constructor File. + const exported = { + schema: 'oliphaunt-bazel-shipping-v1', + scope: 'construction', + packages: [root.package], + }; + const protobuf = buildShippingInputView( + exported, + readNativeAquery(file('aquery.pb'), 'proto', version), + ); + const json = buildShippingInputView( + exported, + readNativeAquery(file('aquery.json'), 'jsonproto', version), + ); + expect(protobuf).toEqual(json); + expect(protobuf.products[root.package.product].inputs.length).toBeGreaterThan(0); + expect(protobuf.products[root.package.product].actions.length).toBeGreaterThan(0); + expect(protobuf.physicalInputs.length).toBeGreaterThan(0); +}); + +test('historical JSON reading preserves its original graph without requiring a proto schema', () => { + expect(readNativeAquery(file('aquery.json'), 'jsonproto', 'historical-bazel')).toEqual( + JSON.parse(readFileSync(file('aquery.json'), 'utf8')), + ); +}); + +test('malformed, truncated, wrong-format and wrong-version captures fail', () => { + const directory = mkdtempSync(join(tmpdir(), 'native-aquery-')); + try { + const malformed = join(directory, 'malformed.pb'); + const truncated = join(directory, 'truncated.pb'); + writeFileSync( + malformed, + Buffer.from([0x0a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]), + ); + const bytes = readFileSync(file('aquery.pb')); + writeFileSync(truncated, bytes.subarray(0, bytes.length - 1)); + expect(() => readNativeAquery(malformed, 'proto', version)).toThrow(); + expect(() => readNativeAquery(truncated, 'proto', version)).toThrow(); + expect(() => readNativeAquery(file('aquery.pb'), 'jsonproto', version)).toThrow(); + expect(() => readNativeAquery(file('aquery.json'), 'proto', version)).toThrow(); + expect(() => readNativeAquery(file('aquery.pb'), 'streamed_proto' as any, version)).toThrow(); + expect(() => readNativeAquery(file('aquery.pb'), 'proto', '8.8.2')).toThrow(); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); diff --git a/tools/release/native-build-files.mts b/tools/release/native-build-files.mts new file mode 100644 index 000000000..f0039ce9f --- /dev/null +++ b/tools/release/native-build-files.mts @@ -0,0 +1,477 @@ +/** Transport final files and declared source tags with the existing evidence inventory. */ +import { deepStrictEqual } from 'node:assert'; +import { createHash } from 'node:crypto'; +import { chmodSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync } from 'node:fs'; +import path from 'node:path'; +import { parseArgs } from 'node:util'; +import { SEED_CONSTRUCTION_RECEIPT_SUFFIX } from '../../build_defs/resources/seed_construction.mts'; +import { + removeOwnedDirectory, + requireSafeDirectoryChain, +} from '../packaging/release-directory-safety.mts'; +import { + type NativeBuildEvidence, + type NativeBuildGithub, + validateNativeBuildEvidence, +} from './native-build-qualification.mts'; +import { + nativeSwiftSourceTagPublication, + nativeSwiftSourceTagRoots, + validateNativeSwiftSourceTagFiles, +} from './native-build-source-tag.mts'; +import { + captureNativeOutputMembers, + captureNativePublicationOutputs, + copyNativeOutputFile, + isNativeFinalTransportRoot, + nativeTransportStagingMode, +} from './native-publication-staging.mts'; +import { ROOT } from './release-graph.mts'; + +type File = { cohort: number; path: string; size: number; sha256: string }; + +function finalFiles(evidence: NativeBuildEvidence) { + const files: File[] = []; + const unsupported = []; + const supportedRoots = []; + const artifactFileKeys = new Set(); + for (const [cohort, value] of evidence.cohorts.entries()) { + const selected = new Set(); + const sourceInputs = new Set(nativeSwiftSourceTagRoots(value)); + for (const root of value.roots) { + const pkg = root.package; + if (!isNativeFinalTransportRoot(root)) continue; + if ( + pkg.ecosystem === 'swift' || + (pkg.role === 'release-input' && + !sourceInputs.has(root) && + pkg.outputs.some( + (output) => + value.outputs.find(({ path }) => path === output.path)?.members[0]?.type !== 'file', + )) + ) { + unsupported.push({ + cohort, + label: root.label, + reason: 'source publication input transport', + }); + continue; + } + supportedRoots.push({ cohort, root }); + for (const output of pkg.outputs) selected.add(output.path); + } + const seen = new Map(); + // Promotion needs the exact original constructor Files, not a reconstruction + // from a public compressed archive. They remain internal evidence inputs. + const seedFiles = new Set( + (value.seedConstructions ?? []).flatMap(({ path: file }) => [ + file, + `${file.slice(0, -SEED_CONSTRUCTION_RECEIPT_SUFFIX.length)}.tar`, + ]), + ); + for (const output of [ + ...value.outputs.filter(({ path }) => selected.has(path)), + ...value.inputs.filter(({ path }) => seedFiles.has(path)), + ...(value.qualificationInputs ?? []).flatMap(({ inputs }) => inputs), + ]) + for (const member of output.members) { + if (member.type !== 'file') continue; + const name = member.path ? `${output.path}/${member.path}` : output.path; + if (selected.has(output.path)) artifactFileKeys.add(`${cohort}\0${name}`); + const identity = { ...member, path: name }; + if (seen.has(name)) { + deepStrictEqual(seen.get(name), identity, 'overlapping native final file declarations'); + continue; + } + seen.set(name, identity); + files.push({ cohort, path: name, size: member.size, sha256: member.sha256 }); + } + } + files.sort((left, right) => left.cohort - right.cohort || left.path.localeCompare(right.path)); + return { files, unsupported, supportedRoots, artifactFileKeys }; +} + +/** No receipt is added: source/configuration/run and file identities remain in evidence. */ +export function writeNativeBuildFinalFiles(evidence: NativeBuildEvidence, directory: string) { + const root = requireSafeDirectoryChain(path.resolve(directory), { label: 'native file packet' }); + const destination = path.join(root, 'files'); + mkdirSync(destination); + try { + const { files } = finalFiles(evidence); + for (const file of files) { + const identity = copyNativeOutputFile( + evidence.cohorts[file.cohort].executionRoot, + file.path, + path.join(destination, String(file.cohort), file.path), + ); + deepStrictEqual( + { size: identity.size, sha256: identity.sha256 }, + { size: file.size, sha256: file.sha256 }, + 'native final file differs from build evidence', + ); + } + validateNativeSwiftSourceTagFiles(evidence, (cohort, file) => + path.join(destination, String(cohort), file), + ); + return files; + } catch (error) { + rmSync(destination, { recursive: true, force: true }); + throw error; + } +} + +/** Validate loose transport bytes independently; their modes are normalized by Actions ZIP. */ +export function readNativeBuildFinalFiles( + directory: string, + evidence: NativeBuildEvidence, + expected: Parameters[1], +) { + return readPhysicalNativeBuildFinalFiles( + directory, + evidence, + validateNativeBuildEvidence(evidence, expected), + ); +} + +/** Qualify one packet, then independently bind each physical copy to its captured Files. */ +export function readNativeBuildFinalFilesBatch( + directories: string[], + evidence: NativeBuildEvidence, + expected: Parameters[1], +) { + const qualification = validateNativeBuildEvidence(evidence, expected); + return directories.map((directory) => + readPhysicalNativeBuildFinalFiles(directory, evidence, qualification), + ); +} + +function readPhysicalNativeBuildFinalFiles( + directory: string, + evidence: NativeBuildEvidence, + qualification: ReturnType, +) { + const root = requireSafeDirectoryChain(path.resolve(directory), { label: 'native file packet' }); + const { supportedRoots, artifactFileKeys, ...inventory } = finalFiles(evidence); + const qualificationInputs = qualification.cohorts.flatMap((value, cohort) => + (value.qualificationInputs ?? []).map((test) => ({ cohort, ...structuredClone(test) })), + ); + const transport = path.join(root, 'files'); + if (!existsSync(transport)) { + if (inventory.files.length) throw new Error('native final file transport is missing'); + return { + scope: 'construction' as const, + qualification, + ...inventory, + artifactRoots: [] as string[], + qualificationInputs, + file(_cohort: number, _declaredPath: string): string { + throw new Error('native final packet does not contain the requested declared File'); + }, + }; + } + const expectedFiles = inventory.files.map(({ cohort, path }) => `${cohort}/${path}`).sort(); + const expectedDirectories = new Set(['']); + for (const file of expectedFiles) { + const parts = file.split('/'); + for (let index = 1; index < parts.length; index++) + expectedDirectories.add(parts.slice(0, index).join('/')); + } + const assertInventory = () => { + const actual = [] as string[]; + const directories = [] as string[]; + const visit = (relative: string) => { + const absolute = path.join(transport, relative); + requireSafeDirectoryChain(absolute, { label: 'native final files' }); + directories.push(relative); + for (const entry of readdirSync(absolute, { withFileTypes: true })) { + const child = relative ? `${relative}/${entry.name}` : entry.name; + if (entry.isDirectory()) visit(child); + else if (entry.isFile()) actual.push(child); + else throw new Error(`native final transport requires regular files: ${child}`); + } + }; + visit(''); + deepStrictEqual(actual.sort(), expectedFiles, 'native final file transport inventory'); + deepStrictEqual( + directories.sort(), + [...expectedDirectories].sort(), + 'native final directory inventory', + ); + }; + assertInventory(); + const captures = inventory.files.map((file) => { + const executionRoot = path.join(transport, String(file.cohort)); + const captured = captureNativeOutputMembers(executionRoot, file.path); + const member = captured.members[0]; + if (captured.members.length !== 1 || member.type !== 'file' || member.path !== '') + throw new Error('native final transport member must be a regular file'); + deepStrictEqual( + { size: member.size, sha256: member.sha256 }, + { size: file.size, sha256: file.sha256 }, + 'native final transport bytes', + ); + return { file, captured, absolute: path.join(executionRoot, file.path) }; + }); + validateNativeSwiftSourceTagFiles(evidence, (cohort, file) => + path.join(transport, String(cohort), file), + ); + const assertUnchanged = () => { + assertInventory(); + for (const { captured } of captures) captured.assertUnchanged(); + }; + const source = { ...evidence.source }; + const github = { ...evidence.github }; + // Retain only the validated staging data by value; callers cannot relabel it after reading. + const selected = evidence.cohorts.map((cohort, index) => { + const roots = structuredClone( + supportedRoots.filter(({ cohort }) => cohort === index).map(({ root }) => root), + ); + const outputs = new Set( + roots.flatMap(({ package: pkg }) => pkg.outputs.map(({ path }) => path)), + ); + return { + executionRoot: cohort.executionRoot, + aquery: cohort.aquery, + roots, + rootConfigurations: structuredClone(cohort.rootConfigurations), + outputs: structuredClone(cohort.outputs.filter(({ path }) => outputs.has(path))), + }; + }); + return { + scope: 'construction' as const, + qualification, + ...inventory, + qualificationInputs, + /** Resolve only a File whose bytes were retained and verified by this reader. */ + file(cohort: number, declaredPath: string) { + assertInventory(); + const captured = captures.find( + ({ file }) => file.cohort === cohort && file.path === declaredPath, + ); + if (!captured) + throw new Error('native final packet does not contain the requested declared File'); + captured.captured.assertUnchanged(); + return captured.absolute; + }, + artifactRoots: captures.flatMap(({ absolute }, index) => + artifactFileKeys.has(`${inventory.files[index].cohort}\0${inventory.files[index].path}`) + ? [absolute] + : [], + ), + assertUnchanged, + /** Restore only verified captured modes in owned staging, never in downloaded bytes. */ + stage( + options: { + stageDirectory?: string; + excludeRoles?: readonly string[]; + products?: readonly string[]; + artifactPhase?: 'pre-version' | 'final'; + } = {}, + ) { + assertUnchanged(); + if ( + options.artifactPhase !== undefined && + !['pre-version', 'final'].includes(options.artifactPhase) + ) + throw new Error('native File staging requires a conventional inventory phase'); + if ( + options.products !== undefined && + (!Array.isArray(options.products) || + !options.products.length || + new Set(options.products).size !== options.products.length || + options.products.some( + (id) => + typeof id !== 'string' || + !selected.some((cohort) => cohort.roots.some((root) => root.package.product === id)), + )) + ) + throw new Error('native File staging requires unique observed product IDs'); + const stagedSelection = selected.map((cohort) => ({ + ...cohort, + roots: cohort.roots.filter( + (root) => + !options.excludeRoles?.includes(root.package.role) && + (options.products === undefined || options.products.includes(root.package.product)) && + !( + options.artifactPhase === 'pre-version' && + root.package.role === 'release-input' && + root.package.name === 'swiftpm-extension-consumer-fixture' + ), + ), + })); + if (stagedSelection.every((cohort) => cohort.roots.length === 0)) return []; + const identity = createHash('sha256') + .update( + JSON.stringify({ + source, + github, + cohorts: stagedSelection.map( + ({ executionRoot, roots, rootConfigurations, outputs }) => ({ + executionRoot, + roots, + rootConfigurations, + outputs, + }), + ), + }), + ) + .digest('hex'); + const parent = requireSafeDirectoryChain(path.join(ROOT, 'target/native-file-stage'), { + create: true, + label: 'native file reconstruction', + }); + const reconstruction = path.join(parent, identity); + // Existing paths cannot substitute for this validated packet, including concurrent callers. + mkdirSync(reconstruction); + try { + const cohorts = stagedSelection.map((cohort, index) => ({ + ...cohort, + executionRoot: path.join(reconstruction, String(index)), + outputs: cohort.outputs.map((output) => ({ + ...output, + members: output.members.map((member) => ({ + ...member, + mode: nativeTransportStagingMode(member, cohort.executionRoot), + })), + })), + })); + for (const [index, cohort] of cohorts.entries()) { + requireSafeDirectoryChain(cohort.executionRoot, { + create: true, + label: 'native file reconstruction', + }); + const restored = new Map(); + const directories: { path: string; mode: number }[] = []; + const outputs = new Set( + cohort.roots.flatMap(({ package: pkg }) => pkg.outputs.map(({ path }) => path)), + ); + for (const output of stagedSelection[index].outputs.filter(({ path }) => + outputs.has(path), + )) { + for (const member of output.members) { + const relative = member.path ? `${output.path}/${member.path}` : output.path; + const target = path.join(cohort.executionRoot, relative); + const identity = { ...member, path: relative }; + if (restored.has(relative)) { + deepStrictEqual( + restored.get(relative), + identity, + 'native overlapping reconstructed members', + ); + continue; + } + restored.set(relative, identity); + const mode = nativeTransportStagingMode(member, stagedSelection[index].executionRoot); + if (member.type === 'directory') { + if ((mode & 0o500) !== 0o500 || (mode & 0o002) !== 0) + throw new Error( + `native transported directory has an unsafe captured mode ${member.mode.toString(8)}: ${relative}`, + ); + requireSafeDirectoryChain(target, { + create: true, + label: 'native file reconstruction', + }); + directories.push({ path: target, mode }); + } else { + if ( + (mode & 0o400) === 0 || + (mode & 0o002) !== 0 || + ((mode & 0o111) !== 0 && (mode & 0o020) !== 0) + ) + throw new Error( + `native transported file has an unsafe captured mode ${member.mode.toString(8)}: ${relative}`, + ); + const copied = copyNativeOutputFile( + path.join(transport, String(index)), + relative, + target, + ); + deepStrictEqual( + { size: copied.size, sha256: copied.sha256 }, + { size: member.size, sha256: member.sha256 }, + 'native reconstructed file bytes', + ); + chmodSync(target, mode); + } + } + } + for (const directory of directories.reverse()) chmodSync(directory.path, directory.mode); + for (const output of cohort.outputs.filter(({ path }) => outputs.has(path))) + deepStrictEqual( + captureNativeOutputMembers(cohort.executionRoot, output.path).members, + output.members, + 'native reconstructed output members', + ); + } + // Staging and publication modes apply only to owned copies; raw evidence stays exact. + const publication = cohorts.map((cohort, index) => ({ + ...cohort, + outputs: nativeSwiftSourceTagPublication({ + ...cohort, + roots: selected[index].roots, + }).outputs, + })); + for (const [index, cohort] of publication.entries()) + for (const [outputIndex, output] of cohort.outputs.entries()) { + if ( + output === cohorts[index].outputs[outputIndex] || + !cohort.roots.some(({ package: pkg }) => + pkg.outputs.some(({ path }) => path === output.path), + ) + ) + continue; + for (const member of output.members) + chmodSync(path.join(cohort.executionRoot, output.path, member.path), member.mode); + } + assertUnchanged(); + const staged = captureNativePublicationOutputs(publication, { + sourceCommit: source.commit, + stageDirectory: options.stageDirectory, + }).stage(); + assertUnchanged(); + return staged; + } finally { + removeOwnedDirectory(reconstruction); + } + }, + }; +} + +if (import.meta.main) { + try { + const { values } = parseArgs({ + options: Object.fromEntries( + ['evidence-root', 'source-commit', 'source-tree', 'github-json', 'output-directory'].map( + (name) => [name, { type: 'string' as const }], + ), + ), + strict: true, + allowPositionals: false, + }); + const required = (name: string) => { + const value = values[name]; + if (typeof value !== 'string' || !value) + throw new Error(`native file staging requires --${name}`); + return value; + }; + const directory = required('evidence-root'); + const packet = readNativeBuildFinalFiles( + directory, + JSON.parse(readFileSync(path.join(directory, 'native-build-evidence.json'), 'utf8')), + { + source: { commit: required('source-commit'), tree: required('source-tree') }, + github: JSON.parse(readFileSync(required('github-json'), 'utf8')) as NativeBuildGithub, + bazelVersion: readFileSync(path.join(ROOT, '.bazelversion'), 'utf8').trim(), + requireShippingAnalysis: true, + }, + ); + if (packet.unsupported.length || !packet.stage) + throw new Error('native file staging requires a complete supported final-file packet'); + process.stdout.write( + `${JSON.stringify(packet.stage({ stageDirectory: required('output-directory') }))}\n`, + ); + } catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exitCode = 1; + } +} diff --git a/tools/release/native-build-files.test.mts b/tools/release/native-build-files.test.mts new file mode 100644 index 000000000..64ddb67d3 --- /dev/null +++ b/tools/release/native-build-files.test.mts @@ -0,0 +1,801 @@ +import { expect, test } from 'bun:test'; +import { spawnSync } from 'node:child_process'; +import { + chmodSync, + cpSync, + existsSync, + mkdirSync, + readFileSync, + renameSync, + rmSync, + statSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { + captureSeedConstructionIntent, + writeSeedConstructionReceipt, +} from '../../build_defs/resources/seed_construction.mts'; +import { archiveDirectory } from '../packaging/archive-directory.mts'; +import { readPortableArchiveEntries } from '../packaging/portable-archive.mts'; +import { removeOwnedDirectory } from '../packaging/release-directory-safety.mts'; +import { + captureNativeBuildEvidence, + writeNativeBuildEvidence, +} from './capture-native-build-evidence.mts'; +import { fixture } from './completed-native-publication.fixture.mts'; +import { + readNativeBuildFinalFiles, + readNativeBuildFinalFilesBatch, +} from './native-build-files.mts'; +import { + captureNativeInputMembers, + captureNativeOutputMembers, + captureNativePublicationOutputs, + NATIVE_EXTENSION_RELEASE_INPUT_ROLES, +} from './native-publication-staging.mts'; +import { ROOT } from './release-graph.mts'; + +const constraints = (f) => ({ + source: f.origin.evidence.source, + github: f.origin.evidence.github, + bazelVersion: f.input.bazelVersion, +}); + +test('file staging CLI binds source and producer before reconstructing captured public files', async () => { + await fixture( + async (f) => { + const directory = path.join(f.directory, 'cli-packet'); + writeNativeBuildEvidence(f.capture, directory); + const github = path.join(f.directory, 'github.json'); + writeFileSync(github, JSON.stringify(f.origin.evidence.github)); + const argv = [ + path.join(ROOT, 'tools/release/native-build-files.mts'), + '--evidence-root', + directory, + '--source-commit', + f.origin.evidence.source.commit, + '--source-tree', + f.origin.evidence.source.tree, + '--github-json', + github, + '--output-directory', + path.relative(ROOT, path.join(f.directory, 'cli-stage')).split(path.sep).join('/'), + ]; + const invoke = (args: string[]) => spawnSync(process.execPath, args, { encoding: 'utf8' }); + const accepted = invoke(argv); + expect(accepted.stderr).toBe(''); + expect(accepted.status).toBe(0); + const staged = JSON.parse(accepted.stdout); + expect(staged).toHaveLength(3); + for (const file of staged) expect(readFileSync(file).length).toBeGreaterThan(0); + const differentSource = [...argv]; + differentSource[differentSource.indexOf('--source-tree') + 1] = 'f'.repeat(40); + const rejected = invoke(differentSource); + expect(rejected.status).toBe(1); + expect(rejected.stdout).toBe(''); + expect(rejected.stderr).toContain('source'); + expect(invoke([...argv, '--allow-dirty']).status).toBe(1); + }, + { producerCapture: true }, + ); +}); + +test('actual packed public files survive transport with exact members and held dependencies', async () => { + await fixture(async (f) => { + const directory = path.join(f.directory, 'packet'); + const file = writeNativeBuildEvidence(f.capture, directory); + const evidence = JSON.parse(readFileSync(file, 'utf8')); + const packet = readNativeBuildFinalFiles(directory, evidence, constraints(f)); + expect(packet.scope).toBe('construction'); + expect(packet.files).toHaveLength(3); + expect(packet.unsupported).toEqual([]); + for (const [index, transferred] of packet.artifactRoots.entries()) { + const original = path.join(evidence.cohorts[0].executionRoot, packet.files[index].path); + expect(readFileSync(transferred)).toEqual(readFileSync(original)); + const members = (file) => + [...readPortableArchiveEntries(file).values()].map((member) => ({ + name: member.name, + type: member.type, + mode: member.mode, + bytes: member.isFile ? member.data() : undefined, + })); + expect(members(transferred)).toEqual(members(original)); + // Actions ZIP normalizes loose transport modes, never packed inner modes. + chmodSync(transferred, 0o644); + } + const npm = packet.artifactRoots.find((file) => file.endsWith('alpha.tgz')); + const manifest = readPortableArchiveEntries(npm).get('package/package.json'); + expect(JSON.parse(manifest.data().toString()).dependencies).toEqual({ + '@fixture/held-runtime': '=0.3.2', + }); + expect(readNativeBuildFinalFiles(directory, evidence, constraints(f)).files).toEqual( + packet.files, + ); + const staged = captureNativePublicationOutputs( + evidence.cohorts.map((cohort, index) => ({ + ...cohort, + executionRoot: path.join(directory, 'files', String(index)), + roots: cohort.roots.filter(({ package: pkg }) => pkg.ecosystem !== 'internal'), + })), + { + sourceCommit: evidence.source.commit, + stageDirectory: path + .relative(ROOT, path.join(f.directory, 'stage')) + .split(path.sep) + .join('/'), + }, + ).stage(); + expect(staged.some((file) => path.basename(path.dirname(file)) === 'release-assets')).toBe( + true, + ); + const registry = staged + .filter((file) => file.endsWith('.tgz')) + .map((file) => + JSON.parse(readPortableArchiveEntries(file).get('package/package.json').data().toString()), + ) + .sort((left, right) => left.name.localeCompare(right.name)); + expect(registry.map(({ name, version }) => ({ name, version }))).toEqual([ + { name: '@fixture/alpha', version: '1.0.0' }, + { name: '@fixture/beta', version: '2.0.0' }, + ]); + expect(registry[0].dependencies['@fixture/held-runtime']).toBe('=0.3.2'); + }); +}); + +test('packet copies independently verify both physical transports against the same evidence', async () => { + await fixture(async (f) => { + const first = path.join(f.directory, 'first-packet'); + const file = writeNativeBuildEvidence(f.capture, first); + const second = path.join(f.directory, 'second-packet'); + cpSync(first, second, { recursive: true }); + const evidence = JSON.parse(readFileSync(file, 'utf8')); + const directories = [first, second]; + const packets = readNativeBuildFinalFilesBatch(directories, evidence, constraints(f)); + expect(packets).toHaveLength(2); + expect(packets[0].files).toEqual(packets[1].files); + for (const packet of packets) { + expect(packet.qualification.source).toEqual(evidence.source); + const target = packet.artifactRoots[0]; + const original = readFileSync(target); + writeFileSync(target, 'corrupted transport copy'); + expect(() => readNativeBuildFinalFilesBatch(directories, evidence, constraints(f))).toThrow( + 'native final transport bytes', + ); + writeFileSync(target, original); + } + writeFileSync(path.join(second, 'files', 'unexpected'), 'extra transport file'); + expect(() => readNativeBuildFinalFilesBatch(directories, evidence, constraints(f))).toThrow( + 'native final file transport inventory', + ); + }); +}); + +test('packet copies reject malformed evidence and a different expected source', async () => { + await fixture(async (f) => { + const first = path.join(f.directory, 'qualified-packet'); + const file = writeNativeBuildEvidence(f.capture, first); + const second = path.join(f.directory, 'qualified-copy'); + cpSync(first, second, { recursive: true }); + const evidence = JSON.parse(readFileSync(file, 'utf8')); + expect(() => + readNativeBuildFinalFilesBatch( + [first, second], + { ...evidence, schema: 'invalid' }, + constraints(f), + ), + ).toThrow('unsupported native build evidence'); + expect(() => + readNativeBuildFinalFilesBatch([first, second], evidence, { + ...constraints(f), + source: { ...evidence.source, tree: 'f'.repeat(40) }, + }), + ).toThrow('native build source mismatch'); + }); +}); + +test('selected File staging preserves source bytes while leaving other public products outside the release directory', async () => { + await fixture(async (f) => { + const directory = path.join(f.directory, 'selected-packet'); + const file = writeNativeBuildEvidence(f.capture, directory); + const evidence = JSON.parse(readFileSync(file, 'utf8')); + const packet = readNativeBuildFinalFiles(directory, evidence, constraints(f)); + const selected = packet.stage({ + products: ['alpha'], + stageDirectory: path + .relative(ROOT, path.join(f.directory, 'selected-alpha')) + .split(path.sep) + .join('/'), + }); + const registry = selected + .filter((file) => file.endsWith('.tgz')) + .map((file) => + JSON.parse(readPortableArchiveEntries(file).get('package/package.json').data().toString()), + ); + expect(registry.map(({ name }) => name)).toEqual(['@fixture/alpha']); + expect(registry[0].dependencies).toEqual({ '@fixture/held-runtime': '=0.3.2' }); + const together = packet.stage({ + products: ['alpha', 'beta'], + stageDirectory: path + .relative(ROOT, path.join(f.directory, 'selected-both')) + .split(path.sep) + .join('/'), + }); + expect(together.filter((file) => file.endsWith('.tgz'))).toHaveLength(2); + expect(() => packet.stage({ products: ['unobserved'] })).toThrow(/observed product/); + expect(() => packet.stage({ products: ['alpha', 'alpha'] })).toThrow(/unique observed/); + packet.assertUnchanged(); + }); +}); + +for (const windowsRoot of [ + undefined, + 'C:\\b\\execroot\\_main', + '\\\\server\\share\\execroot\\_main', +]) + test(`split Cargo public trees preserve parts and modes from ${windowsRoot ?? 'POSIX'} producers`, async () => { + await fixture(async (f) => { + const evidence = structuredClone(f.origin.evidence); + const cohort = evidence.cohorts[0]; + const root = cohort.roots[0]; + const previous = root.package.outputs[0].path; + const output = 'bazel-out/k8-opt/bin/alpha/crates'; + const physical = path.join(cohort.executionRoot, output); + mkdirSync(physical); + const packages = []; + for (const part of ['000', '001']) { + const name = `fixture-runtime-linux-x64-gnu-artifacts-part${part}`; + const source = path.join(f.directory, name); + mkdirSync(path.join(source, `${name}-1.0.0`), { recursive: true }); + writeFileSync( + path.join(source, `${name}-1.0.0/Cargo.toml`), + `[package]\nname = "${name}"\nversion = "1.0.0"\n`, + ); + writeFileSync( + path.join(source, `${name}-1.0.0/artifacts.part`), + `genuine part bytes ${part}`, + ); + const executable = path.join(source, `${name}-1.0.0/launch.sh`); + writeFileSync(executable, '#!/bin/sh\nexit 0\n'); + chmodSync(executable, 0o755); + const archive = path.join(physical, `${name}-1.0.0.crate`); + await archiveDirectory(source, `${archive}.tar.gz`); + renameSync(`${archive}.tar.gz`, archive); + packages.push({ name, file: path.basename(archive) }); + } + writeFileSync(path.join(physical, 'packages.json'), `${JSON.stringify(packages)}\n`); + writeFileSync(path.join(physical, 'Cargo.toml'), '[workspace]\n'); + const empty = path.join(physical, 'read-only-empty'); + mkdirSync(empty); + mkdirSync(path.join(physical, 'nested/empty'), { recursive: true }); + writeFileSync(path.join(physical, 'nested/control.json'), '{}\n'); + chmodSync(empty, 0o555); + chmodSync(physical, 0o500); + const treeMode = statSync(physical).mode & 0o777; + const emptyMode = statSync(empty).mode & 0o777; + const nestedMode = statSync(path.join(physical, 'nested/empty')).mode & 0o777; + const controlMode = statSync(path.join(physical, 'nested/control.json')).mode & 0o777; + const stagedDirectory = path.join(f.directory, 'read-only-stage'); + try { + const graph: any = cohort.aquery; + const fragments = new Map(graph.pathFragments.map((row) => [row.id, row])); + const resolved = (id) => { + const row: any = fragments.get(id); + return row.parentId === undefined ? row.label : `${resolved(row.parentId)}/${row.label}`; + }; + const artifact = graph.artifacts.find((row) => resolved(row.pathFragmentId) === previous); + const parts = output.split('/'); + graph.pathFragments.push( + ...parts.map((label, index) => ({ + id: `parts-${index}`, + label, + ...(index ? { parentId: `parts-${index - 1}` } : {}), + })), + ); + artifact.pathFragmentId = `parts-${parts.length - 1}`; + graph.pathFragments.push({ + id: 'parts-nested', + label: 'nested', + parentId: artifact.pathFragmentId, + }); + graph.artifacts.push({ ...artifact, id: 'parts-nested', pathFragmentId: 'parts-nested' }); + graph.actions + .find((action) => action.outputIds.includes(artifact.id)) + .outputIds.push('parts-nested'); + root.package.ecosystem = 'cargo'; + root.package.name = 'fixture-runtime-linux-x64-gnu'; + root.package.outputs[0].path = output; + root.package.outputs.push({ ...root.package.outputs[0], path: `${output}/nested` }); + const members = captureNativeOutputMembers(cohort.executionRoot, output).members; + for (const event of cohort.buildEvents as any[]) { + const files = event.namedSetOfFiles?.files; + if (!files?.some((file) => file.name === previous)) continue; + event.namedSetOfFiles.files = files.flatMap((file) => + file.name === previous + ? members + .filter((member) => member.type === 'file') + .map((member: any) => ({ + name: `${output}/${member.path}`, + digest: member.sha256, + length: String(member.size), + })) + : [file], + ); + } + const captured = captureNativeBuildEvidence({ + ...constraints(f), + cohorts: [ + { + ...cohort, + cquery: { + results: cohort.roots.map(({ label }) => ({ + target: { rule: { name: label } }, + configurationId: 1, + })), + configurations: [{ id: 1, checksum: cohort.rootConfigurations[0].configuration }], + }, + }, + ], + }); + const directory = path.join(f.directory, 'parts-packet'); + const file = writeNativeBuildEvidence(captured, directory); + const transported = JSON.parse(readFileSync(file, 'utf8')); + if (windowsRoot) { + // Simulate Windows stat metadata around genuine transported opaque archives. + transported.cohorts[0].executionRoot = windowsRoot; + transported.cohorts[0].buildEvents.find( + (event) => event.workspaceInfo, + ).workspaceInfo.localExecRoot = windowsRoot; + for (const output of transported.cohorts[0].outputs) + for (const member of output.members) member.mode = 0o666; + writeFileSync(file, JSON.stringify(transported)); + } + const originalEvidence = readFileSync(file); + const originalMetadata = structuredClone(transported); + const transportMembers = captureNativeInputMembers(directory, 'files').members; + const packet = readNativeBuildFinalFiles(directory, transported, constraints(f)); + const files = packet.artifactRoots.filter((file) => file.includes('/alpha/crates/')); + expect(files.map((file) => path.basename(file))).toEqual([ + 'Cargo.toml', + ...packages.map(({ file }) => file), + 'control.json', + 'packages.json', + ]); + const manifest = files.find((file) => file.endsWith('packages.json')); + expect(JSON.parse(readFileSync(manifest, 'utf8'))).toEqual(packages); + for (const file of files) + expect(readFileSync(file)).toEqual( + readFileSync(path.join(physical, file.split('/alpha/crates/')[1])), + ); + expect(packet.artifactRoots.some((file) => file.includes('-source/'))).toBe(false); + const staged = packet.stage({ + stageDirectory: path.relative(ROOT, stagedDirectory).split(path.sep).join('/'), + }); + const tree = staged.find((file) => path.basename(file) === 'crates'); + if (!tree) throw new Error('staged Cargo Tree is missing'); + expect(statSync(tree).mode & 0o777).toBe(windowsRoot ? 0o755 : treeMode); + expect(statSync(path.join(tree, 'read-only-empty')).mode & 0o777).toBe( + windowsRoot ? 0o755 : emptyMode, + ); + expect(statSync(path.join(tree, 'nested/empty')).mode & 0o777).toBe( + windowsRoot ? 0o755 : nestedMode, + ); + expect(statSync(path.join(tree, 'nested/control.json')).mode & 0o777).toBe( + windowsRoot ? 0o644 : controlMode, + ); + for (const { name, file } of packages) { + const staged = path.join(tree, file); + expect(readFileSync(staged)).toEqual(readFileSync(path.join(physical, file))); + expect(readPortableArchiveEntries(staged).get(`${name}-1.0.0/launch.sh`)?.mode).toBe( + 0o755, + ); + } + expect(readFileSync(file)).toEqual(originalEvidence); + expect(transported).toEqual(originalMetadata); + expect(captureNativeInputMembers(directory, 'files').members).toEqual(transportMembers); + if (windowsRoot) { + const conflicting = structuredClone(transported); + conflicting.cohorts[0].outputs.find( + ({ path }) => path === `${output}/nested`, + ).members[0].mode = 0o444; + expect(() => + readNativeBuildFinalFiles(directory, conflicting, constraints(f)).stage(), + ).toThrow('native overlapping reconstructed members'); + } else { + for (const executionRoot of [cohort.executionRoot, '//server/share/execroot']) { + const unsafe = structuredClone(transported); + unsafe.cohorts[0].executionRoot = executionRoot; + unsafe.cohorts[0].buildEvents.find( + (event) => event.workspaceInfo, + ).workspaceInfo.localExecRoot = executionRoot; + unsafe.cohorts[0].outputs.find(({ path }) => path === output).members[0].mode = 0o666; + expect(() => + readNativeBuildFinalFiles(directory, unsafe, constraints(f)).stage(), + ).toThrow('unsafe captured mode'); + } + for (const mode of [0o666, 0o775]) { + const unsafe = structuredClone(transported); + unsafe.cohorts[0].outputs.find(({ path }) => + path.endsWith('/beta.tgz'), + ).members[0].mode = mode; + expect(() => + readNativeBuildFinalFiles(directory, unsafe, constraints(f)).stage(), + ).toThrow('unsafe captured mode'); + } + } + expect(captureNativeOutputMembers(cohort.executionRoot, output).members).toEqual(members); + packet.assertUnchanged(); + removeOwnedDirectory(stagedDirectory); + expect(existsSync(stagedDirectory)).toBe(false); + expect(statSync(physical).mode & 0o777).toBe(treeMode); + expect(statSync(empty).mode & 0o777).toBe(emptyMode); + } finally { + if (existsSync(stagedDirectory)) removeOwnedDirectory(stagedDirectory); + chmodSync(physical, 0o755); + chmodSync(empty, 0o755); + } + }); + }); + +for (const kind of [ + 'tampered', + 'missing', + 'extra', + 'symlink-file', + 'symlink-parent', + 'empty-extra-directory', +]) + test(`rejects ${kind} final bytes independently of an unchanged evidence JSON`, async () => { + await fixture(async (f) => { + const directory = path.join(f.directory, 'packet'); + const file = writeNativeBuildEvidence(f.capture, directory); + const evidence = JSON.parse(readFileSync(file, 'utf8')); + const packet = readNativeBuildFinalFiles(directory, evidence, constraints(f)); + const target = packet.artifactRoots[0]; + if (kind === 'tampered') writeFileSync(target, 'substituted final archive'); + else if (kind === 'missing') rmSync(target); + else if (kind === 'extra') + writeFileSync(path.join(path.dirname(target), 'extra.crate'), 'extra'); + else if (kind === 'empty-extra-directory') mkdirSync(path.join(directory, 'files/empty')); + else if (kind === 'symlink-file') { + rmSync(target); + symlinkSync(path.join(evidence.cohorts[0].executionRoot, packet.files[0].path), target); + } else { + rmSync(path.join(directory, 'files/0'), { recursive: true }); + symlinkSync(evidence.cohorts[0].executionRoot, path.join(directory, 'files/0'), 'dir'); + } + expect(() => readNativeBuildFinalFiles(directory, evidence, constraints(f))).toThrow(); + expect(() => packet.assertUnchanged()).toThrow(); + expect(JSON.parse(readFileSync(file, 'utf8'))).toEqual(evidence); + }); + }); + +test('transport cannot substitute source, attempt, root configuration or output path', async () => { + await fixture(async (f) => { + const directory = path.join(f.directory, 'packet'); + const file = writeNativeBuildEvidence(f.capture, directory); + const evidence = JSON.parse(readFileSync(file, 'utf8')); + const expected = constraints(f); + for (const mutate of [ + (value) => { + value.source.commit = 'f'.repeat(40); + }, + (value) => { + value.github.runAttempt += 1; + }, + (value) => { + value.cohorts[0].rootConfigurations[0].configuration = 'f'.repeat(64); + }, + (value) => { + value.cohorts[0].roots[0].package.outputs[0].path = 'bazel-out/../../escape.tgz'; + }, + ]) { + const changed = structuredClone(evidence); + mutate(changed); + expect(() => readNativeBuildFinalFiles(directory, changed, expected)).toThrow(); + } + }); +}); + +test('extension join documents survive final transport and owned staging without public identities', async () => { + await fixture(async (f) => { + const evidence = f.origin.evidence; + const roots = evidence.cohorts[0].roots; + const documents = [roots[0], roots[1], roots[3]]; + for (const [index, role] of NATIVE_EXTENSION_RELEASE_INPUT_ROLES.entries()) { + documents[index].package.ecosystem = 'internal'; + documents[index].package.role = role; + } + const directory = path.join(f.directory, 'join-packet'); + const file = writeNativeBuildEvidence(f.capture, directory); + const packet = readNativeBuildFinalFiles( + directory, + JSON.parse(readFileSync(file, 'utf8')), + constraints(f), + ); + expect(packet.files).toHaveLength(3); + expect(packet.unsupported).toEqual([]); + const staged = packet.stage({ + stageDirectory: path + .relative(ROOT, path.join(f.directory, 'join-stage')) + .split(path.sep) + .join('/'), + }); + expect(staged).toHaveLength(3); + for (const root of documents) { + const original = path.join(evidence.cohorts[0].executionRoot, root.package.outputs[0].path); + const transferred = staged.find((file) => path.basename(file) === path.basename(original)); + expect(transferred).toBeDefined(); + expect(readFileSync(transferred)).toEqual(readFileSync(original)); + } + expect(roots.every(({ package: pkg }) => pkg.ecosystem === 'internal')).toBe(true); + expect(packet.stage({ excludeRoles: NATIVE_EXTENSION_RELEASE_INPUT_ROLES })).toEqual([]); + expect(packet.files).toHaveLength(3); + expect(packet).not.toHaveProperty('releaseDecision'); + }); +}); + +test('declared regular release inputs survive exact final transport and staging', async () => { + await fixture(async (f) => { + const evidence = f.origin.evidence; + const root = evidence.cohorts[0].roots[1]; + Object.assign(root.package, { + ecosystem: 'github', + name: 'beta.tgz', + role: 'release-input', + }); + const declared = root.package.outputs[0].path; + const original = readFileSync(path.join(evidence.cohorts[0].executionRoot, declared)); + const directory = path.join(f.directory, 'release-input-packet'); + const file = writeNativeBuildEvidence(f.capture, directory); + const captured = JSON.parse(readFileSync(file, 'utf8')); + const packet = readNativeBuildFinalFiles(directory, captured, constraints(f)); + expect(packet.unsupported).toEqual([]); + expect(packet.files.some(({ path }) => path === declared)).toBe(true); + const transferred = packet.file(0, declared); + expect(readFileSync(transferred)).toEqual(original); + const staged = packet.stage({ + stageDirectory: path + .relative(ROOT, path.join(f.directory, 'release-input-stage')) + .split(path.sep) + .join('/'), + }); + const stagedInput = staged.find((file) => file.endsWith('/beta/beta.tgz')); + expect(stagedInput).toBeDefined(); + expect(readFileSync(stagedInput)).toEqual(original); + expect(packet).not.toHaveProperty('releaseDecision'); + writeFileSync(transferred, 'substituted release input'); + expect(() => packet.assertUnchanged()).toThrow(); + expect(() => readNativeBuildFinalFiles(directory, captured, constraints(f))).toThrow(/bytes/); + expect(readFileSync(path.join(evidence.cohorts[0].executionRoot, declared))).toEqual(original); + }); +}); + +test('producer internals and unsupported source publication trees stay outside final-file transport', async () => { + await fixture(async (f) => { + const evidence = f.origin.evidence; + evidence.cohorts[0].roots[0].package.ecosystem = 'internal'; + evidence.cohorts[0].roots[0].package.role = 'construction'; + evidence.cohorts[0].roots[1].package.ecosystem = 'swift'; + evidence.cohorts[0].roots[2].package.ecosystem = 'github'; + evidence.cohorts[0].roots[2].package.role = 'release-input'; + const directory = path.join(f.directory, 'packet'); + const file = writeNativeBuildEvidence(f.capture, directory); + const packet = readNativeBuildFinalFiles( + directory, + JSON.parse(readFileSync(file, 'utf8')), + constraints(f), + ); + expect(packet.files).toHaveLength(1); + expect(packet.unsupported).toEqual([ + { + cohort: 0, + label: evidence.cohorts[0].roots[1].label, + reason: 'source publication input transport', + }, + { + cohort: 0, + label: evidence.cohorts[0].roots[2].label, + reason: 'source publication input transport', + }, + ]); + expect( + packet.files.some( + ({ path: file }) => file === evidence.cohorts[0].roots[0].package.outputs[0].path, + ), + ).toBe(false); + expect( + packet.files.some( + ({ path: file }) => file === evidence.cohorts[0].roots[1].package.outputs[0].path, + ), + ).toBe(false); + expect( + packet.files.some( + ({ path: file }) => file === evidence.cohorts[0].roots[2].package.outputs[0].path, + ), + ).toBe(false); + expect(packet).not.toHaveProperty('releaseDecision'); + }); +}); + +test('the exact private Apple basis transports real bytes and excludes unrelated internal roots', async () => { + await fixture(async (f) => { + const cohort = f.origin.evidence.cohorts[0]; + const root = cohort.roots[0]; + const previousLabel = root.label; + const previousPath = root.package.outputs[0].path; + const output = 'bazel-out/k8-opt/bin/src/native/runtime/apple_release_assets/ios.json'; + const contents = Buffer.from('{"schema":"controlled-Apple-basis-fixture"}\n'); + mkdirSync(path.dirname(path.join(cohort.executionRoot, output)), { recursive: true }); + writeFileSync(path.join(cohort.executionRoot, output), contents); + root.label = '//src/native/runtime:apple_ios_manifest_shipping'; + Object.assign(root.package, { + product: 'liboliphaunt-native', + ecosystem: 'internal', + name: 'ios.json', + configuration: 'ios-xcframework', + role: 'apple-base-ios-manifest-input', + }); + root.package.outputs[0].path = output; + cohort.rootConfigurations.find(({ label }) => label === previousLabel).label = root.label; + cohort.outputs.find(({ path: name }) => name === previousPath).path = output; + cohort.outputs.find(({ path: name }) => name === output).members = captureNativeOutputMembers( + cohort.executionRoot, + output, + ).members; + const graph = cohort.aquery as any; + const previous = new Map(graph.pathFragments.map((part) => [String(part.id), part])); + const resolve = (id: unknown): string => { + const part = previous.get(String(id)) as any; + return part.parentId ? `${resolve(part.parentId)}/${part.label}` : part.label; + }; + const artifact = graph.artifacts.find( + ({ pathFragmentId }) => resolve(pathFragmentId) === previousPath, + ); + const parts = output.split('/'); + graph.pathFragments.push( + ...parts.map((label, index) => ({ + id: `apple-${index}`, + label, + ...(index ? { parentId: `apple-${index - 1}` } : {}), + })), + ); + artifact.pathFragmentId = `apple-${parts.length - 1}`; + for (const event of cohort.buildEvents as any[]) { + if (event.id?.targetCompleted?.label === previousLabel) + event.id.targetCompleted.label = root.label; + for (const file of event.namedSetOfFiles?.files ?? []) + if (file.name === previousPath) + Object.assign(file, { + name: output, + length: String(contents.length), + digest: cohort.outputs.find(({ path: name }) => name === output).members[0].sha256, + }); + } + const directory = path.join(f.directory, 'private-apple-packet'); + const evidenceFile = writeNativeBuildEvidence(f.capture, directory); + const evidence = JSON.parse(readFileSync(evidenceFile, 'utf8')); + const packet = readNativeBuildFinalFiles(directory, evidence, constraints(f)); + const transferred = packet.artifactRoots.find((file) => + file.endsWith('/apple_release_assets/ios.json'), + ); + expect(readFileSync(transferred)).toEqual(contents); + expect(packet).not.toHaveProperty('releaseDecision'); + writeFileSync(transferred, 'substituted private Apple basis'); + expect(() => readNativeBuildFinalFiles(directory, evidence, constraints(f))).toThrow(/bytes/); + }); +}); + +test('exact reached seed TAR and receipt survive internal transport without entering public artifact roots', async () => { + await fixture(async (f) => { + const cohort = f.origin.evidence.cohorts[0]; + const graph = cohort.aquery as any; + const frozen = 'bazel-out/k8-opt/bin/seed.tar'; + const receipt = 'bazel-out/k8-opt/bin/seed.seed-construction.json'; + writeFileSync( + path.join(cohort.executionRoot, frozen), + 'exact original constructor TAR fixture', + ); + const pgdata = path.join(f.directory, 'fixture-pgdata'); + const contract = JSON.parse( + readFileSync(path.join(ROOT, 'src/database-resources/contracts/contract.json'), 'utf8'), + ); + for (const name of contract.pgdataDirectories) + mkdirSync(path.join(pgdata, name), { recursive: true }); + writeFileSync(path.join(pgdata, 'PG_VERSION'), '18\n'); + const input = cohort.inputs.find((input) => !input.path.startsWith('bazel-out/')); + if (!input) throw new Error('seed transport fixture needs a source File'); + const intent = captureSeedConstructionIntent( + { family: 'native', target: 'linux-x64-gnu', profile: 'standard' }, + { command: 'fixture-initdb' }, + { constructor: path.join(cohort.executionRoot, input.path) }, + ); + writeSeedConstructionReceipt( + path.join(cohort.executionRoot, receipt), + intent, + path.join(cohort.executionRoot, frozen), + pgdata, + ); + const ids = [frozen, receipt].map((file, offset) => { + const id = graph.artifacts.length + 1; + const parts = file.split('/'); + for (const [part, label] of parts.entries()) + graph.pathFragments.push({ + id: `seed-${offset}-${part}`, + label, + ...(part ? { parentId: `seed-${offset}-${part - 1}` } : {}), + }); + graph.artifacts.push({ id, pathFragmentId: `seed-${offset}-${parts.length - 1}` }); + return id; + }); + const targetId = graph.targets.length + 1; + graph.targets.push({ id: targetId, label: '//fixture:seed_constructor' }); + const depSetId = graph.depSetOfFiles.length + 1; + graph.depSetOfFiles.push({ id: depSetId, directArtifactIds: ids }); + graph.actions[0].inputDepSetIds.push(depSetId); + graph.actions.push({ + targetId, + configurationId: 1, + mnemonic: 'PostgresClusterSeed', + actionKey: 'actual-fixture-seed-constructor', + outputIds: ids, + primaryOutputId: ids[0], + }); + const captured = captureNativeBuildEvidence({ + ...constraints(f), + cohorts: [ + { + ...cohort, + roots: cohort.roots, + cquery: { + configurations: [{ id: 1, checksum: cohort.rootConfigurations[0].configuration }], + results: cohort.roots.map((root) => ({ + target: { rule: { name: root.label } }, + configurationId: 1, + })), + }, + }, + ], + }); + expect(captured.evidence.cohorts[0].seedConstructions).toHaveLength(1); + const directory = path.join(f.directory, 'seed-packet'); + const file = writeNativeBuildEvidence(captured, directory); + const packet = readNativeBuildFinalFiles( + directory, + JSON.parse(readFileSync(file, 'utf8')), + constraints(f), + ); + expect(packet.files).toHaveLength(5); + expect(packet.artifactRoots).toHaveLength(3); + for (const name of [frozen, receipt]) + expect(readFileSync(path.join(directory, 'files/0', name))).toEqual( + readFileSync(path.join(cohort.executionRoot, name)), + ); + expect(packet.stage()).toHaveLength(3); + writeFileSync(path.join(directory, 'files/0', frozen), 'substitution'); + expect(() => packet.assertUnchanged()).toThrow(); + }); +}); + +test('public final packet cannot promote caller-injected test inputs into publication artifacts', async () => { + await fixture(async (f) => { + const directory = path.join(f.directory, 'injected-test-packet'); + const evidenceFile = writeNativeBuildEvidence(f.capture, directory); + const evidence = JSON.parse(readFileSync(evidenceFile, 'utf8')); + const original = readNativeBuildFinalFiles(directory, evidence, constraints(f)); + expect(original.qualificationInputs).toEqual([]); + expect(original.file(0, original.files[0].path)).toBe(original.artifactRoots[0]); + evidence.cohorts[0].qualificationInputs = [ + { + label: '//fixture:unowned_test', + configuration: 'c'.repeat(64), + specification: evidence.cohorts[0].outputs[0].path, + inputs: evidence.cohorts[0].outputs, + }, + ]; + expect(() => readNativeBuildFinalFiles(directory, evidence, constraints(f))).toThrow( + /source-owned observer/, + ); + }); +}); diff --git a/tools/release/native-build-qualification.mts b/tools/release/native-build-qualification.mts new file mode 100644 index 000000000..ac95513b4 --- /dev/null +++ b/tools/release/native-build-qualification.mts @@ -0,0 +1,1330 @@ +/** Content binding inside qualification evidence; authentication and release admission remain external. */ +import { createHash } from 'node:crypto'; +import path from 'node:path'; +import { + SEED_CONSTRUCTION_RECEIPT_SUFFIX, + validateSeedConstructionReceipt, +} from '../../build_defs/resources/seed_construction.mts'; +import { + buildShippingInputView, + type ConfiguredFileWriteCheck, + canonicalShippingLabel, + createConfiguredAqueryTargetInputResolver, + type ShippingInputView, + validateNativeShippingSuppliers, +} from './bazel-shipping-inputs.mts'; +import type { NativeRoot } from './native-publication-artifacts.mts'; +import type { NativeOutputMember } from './native-publication-staging.mts'; + +type Row = Record; +export type NativeBuildSource = { commit: string; tree: string }; +export type NativeRequiredTest = { label: string; configuration: string }; +export type NativeBuildGithub = { + repository: string; + workflow: string; + workflowPath: string; + runId: number; + runAttempt: number; + job: string; +}; +export type NativeBuildFileCapture = { path: string; members: NativeOutputMember[] }; +export type NativeQualificationInputs = NativeRequiredTest & { + /** The same configured test's own input-free FileWrite, consumed by its runfiles/actions. */ + specification: string; + inputs: NativeBuildFileCapture[]; +}; +export type NativeProducerCapture = { + aqueryFile: string; + /** Successful scoped analysis in the same frozen producer window; no byte-authentication claim. */ + aqueryBuildEvents?: unknown[]; + shippingManifests: { path: string; contents: string }[]; + /** The existing owner export, delivered by the same producing invocation. */ + qualificationManifest?: { path: string; contents: string }; +}; + +export const NATIVE_AQUERY_FLAGS = [ + // The pinned JSON formatter avoids the proto serializer's blocked worker queue. + '--output=jsonproto', + '--include_commandline=false', + '--include_artifacts=true', + '--include_pruned_inputs=true', + '--include_aspects=true', + '--include_param_files=false', + '--include_file_write_contents=false', + '--tool_deps=true', + '--implicit_deps=true', + '--nodep_deps=true', + '--skyframe_state=false', +] as const; + +/** Read only the supported raw query format; full provenance binding follows below. */ +export function nativeAqueryOutputFormat(events: unknown[]): 'proto' | 'jsonproto' { + const commands = events + .map(object) + .filter((event) => event.structuredCommandLine?.commandLineLabel === 'canonical'); + if (commands.length !== 1) throw new Error('native scoped aquery requires one canonical command'); + const options = list(object(commands[0].structuredCommandLine).sections).flatMap((section) => + list(object(section).optionList?.option ?? []), + ); + const output = options.filter((option) => option.optionName === 'output'); + if (output.length !== 1 || !['proto', 'jsonproto'].includes(output[0].optionValue)) + throw new Error('native scoped aquery requires one supported output format'); + return output[0].optionValue; +} + +/** The complete requested configured closure, including owner policy and tests. */ +export function nativeAqueryExpression(targets: string[]) { + const labels = targets.map((value) => canonicalShippingLabel(text(value))); + if (!labels.length || labels.some((label) => !/^\/\/[^\s]*:[^\s]+$/u.test(label))) + throw new Error('native scoped aquery requires explicit workspace target labels'); + return `deps(set(${[...new Set(labels)] + .sort() + .map((label) => JSON.stringify(label)) + .join(' ')}))`; +} +export type NativeBuildCohortEvidence = { + executionRoot: string; + roots: NativeRoot[]; + rootConfigurations: { label: string; configuration: string }[]; + aquery: unknown; + buildEvents: unknown[]; + inputs: NativeBuildFileCapture[]; + outputs: NativeBuildFileCapture[]; + /** Present only when shipping identities were emitted by the producing analysis. */ + producerCapture?: NativeProducerCapture; + /** Reached internal constructor outputs; their JSON is bound to captured File bytes. */ + seedConstructions?: { path: string; contents: string }[]; + /** Actual configured-root buildfiles; repository acquisition provenance is separate. */ + analysisInputs?: NativeBuildFileCapture[]; + rootAnalysisInputPaths?: { label: string; paths: string[] }[]; + /** Exact source-owned mandatory-test inputs, retained only for qualification replay. */ + qualificationInputs?: NativeQualificationInputs[]; +}; +export type NativeBuildEvidence = { + schema: 'oliphaunt-native-build-evidence-v1'; + source: NativeBuildSource; + github: NativeBuildGithub; + cohorts: NativeBuildCohortEvidence[]; +}; + +function object(value: unknown): Row { + if (!value || Array.isArray(value) || typeof value !== 'object') + throw new Error('native build evidence requires an object'); + return value as Row; +} +function list(value: unknown): any[] { + if (!Array.isArray(value)) throw new Error('native build evidence requires a list'); + return value; +} +function text(value: unknown): string { + if (typeof value !== 'string' || !value || /[\u0000-\u001f\u007f]/u.test(value)) + throw new Error('native build evidence requires a nonempty identity'); + return value; +} +function relative(value: unknown) { + const name = text(value); + if ( + name.startsWith('/') || + name.includes('\\') || + name.normalize('NFC') !== name || + name.split('/').some((part) => !part || part === '.' || part === '..') + ) + throw new Error(`unsafe native build path: ${name}`); + return name; +} +function size(value: unknown): number { + if (typeof value === 'string' && /^(0|[1-9][0-9]*)$/u.test(value)) value = Number(value); + if (!Number.isSafeInteger(value) || Number(value) < 0) + throw new Error('native build file size must be a nonnegative safe integer'); + return Number(value); +} +function hash(value: unknown) { + if (typeof value !== 'string' || !/^[0-9a-f]{64}$/u.test(value)) + throw new Error('native build content requires SHA-256'); + return value; +} +function canonical(value: unknown): string { + if (Array.isArray(value)) return `[${value.map(canonical).join(',')}]`; + if (value && typeof value === 'object') + return `{${Object.entries(value) + .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)) + .map(([key, item]) => `${JSON.stringify(key)}:${canonical(item)}`) + .join(',')}}`; + return JSON.stringify(value); +} +function digest(value: unknown) { + const hash = createHash('sha256'); + // Batch canonical tokens instead of making a crypto call for every dep-set ID. + let chunks: string[] = []; + let characters = 0; + const emit = (chunk: string) => { + chunks.push(chunk); + characters += chunk.length; + if (characters >= 64 * 1024) { + hash.update(chunks.join('')); + chunks = []; + characters = 0; + } + }; + const update = (value: unknown) => { + if (Array.isArray(value)) { + emit('['); + for (let index = 0; index < value.length; index++) { + if (index) emit(','); + update(value[index]); + } + emit(']'); + } else if (value && typeof value === 'object') { + emit('{'); + let index = 0; + for (const [key, item] of Object.entries(value).sort(([a], [b]) => + a < b ? -1 : a > b ? 1 : 0, + )) { + if (index++) emit(','); + emit(`${JSON.stringify(key)}:`); + update(item); + } + emit('}'); + } else emit(JSON.stringify(value)); + }; + update(value); + if (chunks.length) hash.update(chunks.join('')); + return `sha256:${hash.digest('hex')}`; +} +function equal(actual: unknown, expected: unknown, context: string) { + if (canonical(actual) !== canonical(expected)) throw new Error(`${context} mismatch`); +} +function exactFields(value: Row, fields: string[], context: string) { + equal(Object.keys(value).sort(), fields.sort(), `${context} fields`); +} +function source(value: NativeBuildSource) { + exactFields(object(value), ['commit', 'tree'], 'native build source'); + if (![value.commit, value.tree].every((sha) => /^[0-9a-f]{40}$/u.test(sha ?? ''))) + throw new Error('native build requires exact source commit and tree'); +} +export function assertNativeBuildGithub(value: NativeBuildGithub) { + exactFields( + object(value), + ['repository', 'workflow', 'workflowPath', 'runId', 'runAttempt', 'job'], + 'native build GitHub', + ); + for (const key of ['repository', 'workflow', 'workflowPath', 'job']) text(value[key]); + if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/u.test(value.repository)) + throw new Error('native build repository is invalid'); + if (!/^\.github\/workflows\/[^/]+\.ya?ml$/u.test(value.workflowPath)) + throw new Error('native build workflow path is invalid'); + for (const key of ['runId', 'runAttempt']) + if (!Number.isSafeInteger(value[key]) || value[key] <= 0) + throw new Error('native build producing run and attempt must be positive integers'); +} + +/** Pass each entry to the real build as --build_metadata=KEY=VALUE. */ +export function nativeBuildMetadata(sourceIdentity: NativeBuildSource, github: NativeBuildGithub) { + source(sourceIdentity); + assertNativeBuildGithub(github); + return { + oliphaunt_source_commit: sourceIdentity.commit, + oliphaunt_source_tree: sourceIdentity.tree, + oliphaunt_repository: github.repository, + oliphaunt_workflow: github.workflow, + oliphaunt_workflow_path: github.workflowPath, + oliphaunt_run_id: String(github.runId), + oliphaunt_run_attempt: String(github.runAttempt), + oliphaunt_job: github.job, + }; +} + +function captures(value: unknown, expected: string[], context: string) { + const result = new Map(); + for (const raw of list(value)) { + const capture = object(raw) as NativeBuildFileCapture; + exactFields(capture, ['path', 'members'], context); + const name = relative(capture.path); + if (result.has(name)) throw new Error(`duplicate ${context}: ${name}`); + const members = list(capture.members); + if (!members.length || members[0].path !== '') + throw new Error(`${context} requires its captured root member: ${name}`); + const seen = new Map(); + for (const member of members) { + const row = object(member); + const memberPath = row.path === '' ? '' : relative(row.path); + if (seen.has(memberPath)) throw new Error(`duplicate ${context} member`); + if (!Number.isInteger(row.mode) || row.mode < 0 || row.mode > 0o777) + throw new Error(`${context} mode is invalid`); + if (row.type === 'file') { + exactFields(row, ['path', 'type', 'mode', 'size', 'sha256'], context); + size(row.size); + hash(row.sha256); + } else if (row.type === 'directory') exactFields(row, ['path', 'type', 'mode'], context); + else throw new Error(`${context} member must be a regular file or directory`); + if ( + memberPath && + seen.get(path.posix.dirname(memberPath) === '.' ? '' : path.posix.dirname(memberPath)) !== + 'directory' + ) + throw new Error(`${context} member has no captured directory parent`); + seen.set(memberPath, row.type); + } + equal([...seen.keys()], [...seen.keys()].sort(), `${context} member order`); + result.set(name, capture); + } + equal([...result.keys()].sort(), [...new Set(expected)].sort(), `${context} coverage`); + return result; +} + +/** Require causal leaves, consumed supplier Files and reached constructor companion values. */ +export function nativeRequiredCaptureInputs(view: ShippingInputView) { + const files = new Set(view.captureInputs); + const actions = new Set(Object.values(view.products).flatMap((product) => product.actions)); + for (const definition of actions) { + const action = object(JSON.parse(definition)); + if ( + !['PostgresClusterSeed', 'WasixClusterSeed', 'NativeSeedDomainAdmission'].includes( + action.mnemonic, + ) + ) + continue; + const outputs = list(action.outputs).map(relative); + for (const receipt of outputs.filter((file) => + file.endsWith(SEED_CONSTRUCTION_RECEIPT_SUFFIX), + )) { + const frozen = receipt.slice(0, -SEED_CONSTRUCTION_RECEIPT_SUFFIX.length) + '.tar'; + if (!outputs.includes(frozen)) + throw new Error('native seed constructor receipt requires its same-action frozen TAR'); + files.add(receipt); + files.add(frozen); + } + } + return [...files].sort(); +} + +/** Join each reached receipt to its own constructor action and frozen TAR File. */ +export function validateNativeSeedConstructions( + raw: unknown, + inputs: NativeBuildFileCapture[], + actions: string[], +) { + const expected = inputs + .filter((input) => input.path.endsWith(SEED_CONSTRUCTION_RECEIPT_SUFFIX)) + .map((input) => input.path) + .sort(); + const rows = raw === undefined ? [] : list(raw); + const result = rows.map((value) => { + const row = object(value); + exactFields(row, ['path', 'contents'], 'native seed constructor contents'); + const file = relative(row.path); + if (!file.startsWith('bazel-out/') || typeof row.contents !== 'string') + throw new Error('native seed constructor requires a generated UTF-8 File'); + const bytes = Buffer.from(row.contents, 'utf8'); + const capture = inputs.find((input) => input.path === file); + const member = capture?.members[0]; + if (capture?.members.length !== 1 || member?.type !== 'file') + throw new Error('native seed constructor contents have no captured File'); + equal( + { size: bytes.length, sha256: createHash('sha256').update(bytes).digest('hex') }, + { size: member.size, sha256: member.sha256 }, + 'native seed constructor File digest', + ); + const receipt = validateSeedConstructionReceipt(JSON.parse(row.contents)); + const frozen = file.slice(0, -SEED_CONSTRUCTION_RECEIPT_SUFFIX.length) + '.tar'; + const definitions = actions + .map((action) => object(JSON.parse(action))) + .filter((action) => list(action.outputs).includes(file)); + if ( + definitions.length !== 1 || + !['PostgresClusterSeed', 'WasixClusterSeed', 'NativeSeedDomainAdmission'].includes( + definitions[0].mnemonic, + ) || + !list(definitions[0].outputs).includes(frozen) + ) + throw new Error( + 'native seed constructor receipt and frozen TAR need the same actual constructor action', + ); + if ( + (definitions[0].mnemonic === 'WasixClusterSeed' ? 'wasix' : 'native') !== + receipt.intent.family + ) + throw new Error('native seed constructor family differs from its actual action'); + if ( + definitions[0].mnemonic === 'NativeSeedDomainAdmission' && + !['android-datum64', 'ios-datum64'].includes(receipt.intent.target) + ) + throw new Error('native seed domain receipt needs its own mobile domain slot'); + const frozenCapture = inputs.find((input) => input.path === frozen); + const frozenMember = frozenCapture?.members[0]; + if (frozenCapture?.members.length !== 1 || frozenMember?.type !== 'file') + throw new Error('native seed constructor needs its captured frozen TAR File'); + equal( + receipt.frozen, + { size: frozenMember.size, sha256: frozenMember.sha256 }, + 'native seed constructor frozen TAR identity', + ); + return { path: file, contents: row.contents as string }; + }); + equal(result.map((row) => row.path).sort(), expected, 'native reached seed constructor coverage'); + return result; +} + +/** Preserve direct loaded-file facts without claiming repository acquisition provenance. */ +export function nativeAnalysisInputBindings( + cohort: Pick, +) { + if (cohort.analysisInputs === undefined && cohort.rootAnalysisInputPaths === undefined) + return undefined; + const mappings = list(cohort.rootAnalysisInputPaths).map((raw) => { + const row = object(raw); + exactFields(row, ['label', 'paths'], 'native root analysis mapping'); + const label = canonicalShippingLabel(text(row.label)); + const paths = list(row.paths).map(relative); + if ( + !paths.length || + paths.some((file) => file.startsWith('bazel-out/') || file.startsWith('external/')) + ) + throw new Error('native analysis inputs must be concrete workspace files'); + equal(paths, [...new Set(paths)].sort(), 'native root analysis input order'); + return { label, paths }; + }); + equal( + mappings.map((row) => row.label).sort(), + cohort.roots.map((root) => canonicalShippingLabel(root.label)).sort(), + 'native root analysis coverage', + ); + const expected = [...new Set(mappings.flatMap((row) => row.paths))].sort(); + const inputs = captures(cohort.analysisInputs, expected, 'native analysis input content'); + for (const input of inputs.values()) + if (input.members.length !== 1 || input.members[0].type !== 'file') + throw new Error('native analysis inputs must be regular workspace Files'); + return { mappings, inputs: [...inputs.values()] }; +} + +export function nativeBuildEventIndex( + cohort: Pick, + bazelVersion: string, + metadata: Record, +) { + const events = list(cohort.buildEvents).map(object); + if (!events.length || events.at(-1)?.lastMessage !== true) + throw new Error('native BEP stream is incomplete'); + const one = (field: string) => { + const matches = events.filter((event) => event[field] !== undefined); + if (matches.length !== 1) throw new Error(`native BEP must contain one ${field} event`); + return object(matches[0][field]); + }; + const started = one('started'); + equal(started.buildToolVersion, bazelVersion, 'native BEP Bazel version'); + const invocationId = text(started.uuid); + const observedMetadata = object(one('buildMetadata').metadata); + for (const [key, value] of Object.entries(metadata)) + equal(observedMetadata[key], value, `native BEP ${key}`); + equal(one('workspaceInfo').localExecRoot, cohort.executionRoot, 'native BEP execution root'); + const finished = one('finished'); + if ( + finished.overallSuccess === false || + finished.exitCode?.name !== 'SUCCESS' || + size(finished.exitCode?.code ?? 0) !== 0 + ) + throw new Error('native BEP build did not succeed'); + const configs = new Map(); + const named = new Map(); + const completed: { label: string; configuration: string; value: Row }[] = []; + for (const event of events) { + if (event.configuration !== undefined) { + const key = text(event.id?.configuration?.id); + if (configs.has(key)) throw new Error('duplicate native BEP configuration'); + configs.set(key, object(event.configuration)); + } + if (event.namedSetOfFiles !== undefined) { + const key = text(event.id?.namedSet?.id); + if (named.has(key)) throw new Error('duplicate native BEP named set'); + named.set(key, object(event.namedSetOfFiles)); + } + if (event.id?.targetCompleted !== undefined) { + completed.push({ + label: text(event.id.targetCompleted.label), + configuration: text(event.id.targetCompleted.configuration?.id), + value: object(event.completed ?? event.aborted), + }); + } + } + const filesOf = (target: Row, groupName: string) => { + const files = new Map(); + const visitFile = (raw: unknown) => { + const file = object(raw); + const name = relative([...(file.pathPrefix ?? []), text(file.name)].join('/')); + const identity = { sha256: hash(file.digest), size: size(file.length ?? 0) }; + if (file.symlinkTargetPath) throw new Error('native BEP output is an unresolved symlink'); + if (files.has(name)) equal(files.get(name), identity, 'native BEP duplicate file'); + files.set(name, identity); + }; + const visited = new Set(); + const visit = (key: string, stack = new Set()) => { + if (stack.has(key)) throw new Error('cycle in native BEP named sets'); + if (visited.has(key)) return; + const set = named.get(key); + if (!set) throw new Error('missing native BEP named set'); + for (const file of list(set.files ?? [])) visitFile(file); + for (const child of list(set.fileSets ?? [])) visit(text(child.id), new Set(stack).add(key)); + visited.add(key); + }; + for (const group of list(target.outputGroup ?? [])) { + if (group.name !== groupName) continue; + if (group.incomplete === true) throw new Error('native BEP output group is incomplete'); + for (const set of list(group.fileSets ?? [])) visit(text(set.id)); + for (const file of list(group.inlineFiles ?? [])) visitFile(file); + } + return files; + }; + return { invocationId, configs, completed, filesOf, events }; +} + +/** Native metadata is content-bound by BEP; the separate action graph has no native digest receipt. */ +export function nativeShippingManifestBindings( + raw: NativeProducerCapture, + bep: ReturnType, +) { + const capture = object(raw) as NativeProducerCapture; + exactFields( + capture, + [ + 'aqueryFile', + ...(capture.aqueryBuildEvents === undefined ? [] : ['aqueryBuildEvents']), + 'shippingManifests', + ...(capture.qualificationManifest ? ['qualificationManifest'] : []), + ], + 'native producer capture', + ); + if ( + !path.posix.isAbsolute(text(capture.aqueryFile)) && + !path.win32.isAbsolute(capture.aqueryFile) + ) + throw new Error('native producer requires an absolute aquery file'); + const commands = bep.events.filter( + (event) => event.structuredCommandLine?.commandLineLabel === 'canonical', + ); + if (commands.length !== 1) throw new Error('native producer requires one canonical command line'); + const options = list(commands[0].structuredCommandLine.sections).flatMap((section) => + list(object(section).optionList?.option ?? []), + ); + let query: ReturnType | undefined; + if (capture.aqueryBuildEvents === undefined) { + // Historical immutable packets used Bazel's whole-server after-build dump. + for (const [name, value] of [ + ['experimental_aquery_dump_after_build_format', 'jsonproto'], + ['experimental_aquery_dump_after_build_output_file', capture.aqueryFile], + ]) { + const matches = options.filter((option) => option.optionName === name); + if (matches.length !== 1 || matches[0].optionValue !== value) + throw new Error(`native producer command line requires ${name}=${value}`); + } + } else { + const event = (field: string) => { + const matches = bep.events.filter((event) => event[field] !== undefined); + if (matches.length !== 1) throw new Error(`native producing BEP requires one ${field}`); + return object(matches[0][field]); + }; + query = nativeBuildEventIndex( + { + executionRoot: text(event('workspaceInfo').localExecRoot), + buildEvents: capture.aqueryBuildEvents, + }, + text(event('started').buildToolVersion), + object(event('buildMetadata').metadata), + ); + if (query.invocationId === bep.invocationId) + throw new Error('native scoped aquery requires its separate analysis invocation'); + const chunk = (command: Row, name: string) => { + const matches = list(command.sections).filter((section) => section.sectionLabel === name); + if (matches.length !== 1) throw new Error(`native command requires one ${name} section`); + return list(object(matches[0]).chunkList?.chunk).map(text); + }; + const queryCommands = query.events.filter( + (event) => event.structuredCommandLine?.commandLineLabel === 'canonical', + ); + if (queryCommands.length !== 1) + throw new Error('native scoped aquery requires one canonical command'); + const producerCommand = object(commands[0].structuredCommandLine); + const queryCommand = object(queryCommands[0].structuredCommandLine); + equal(chunk(producerCommand, 'command'), ['test'], 'native producing command'); + equal(chunk(queryCommand, 'command'), ['aquery'], 'native scoped analysis command'); + equal( + chunk(queryCommand, 'residual'), + [nativeAqueryExpression(chunk(producerCommand, 'residual'))], + 'native scoped aquery requested closure', + ); + const queryOptions = list(queryCommand.sections).flatMap((section) => + list(object(section).optionList?.option ?? []), + ); + for (const flag of NATIVE_AQUERY_FLAGS) { + const [name, literal] = flag.slice(2).split('='); + const value = name === 'output' ? nativeAqueryOutputFormat(query.events) : literal; + const matches = queryOptions.filter((option) => option.optionName === name); + if (matches.length !== 1 || matches[0].optionValue !== value) + throw new Error(`native scoped aquery command requires ${name}=${value}`); + } + const outputs = queryOptions.filter((option) => option.optionName === 'output_file'); + if (outputs.length !== 1 || outputs[0].optionValue !== capture.aqueryFile) + throw new Error('native scoped aquery output file differs from its captured graph'); + } + const paths = new Set(); + const labels = new Set(); + const bindings = list(capture.shippingManifests).map((raw) => { + const manifest = object(raw); + exactFields(manifest, ['path', 'contents'], 'native shipping manifest'); + const file = relative(manifest.path); + if (!file.startsWith('bazel-out/') || paths.has(file)) + throw new Error('native shipping manifest requires a unique generated file'); + paths.add(file); + if (typeof manifest.contents !== 'string') + throw new Error('native shipping manifest requires its exact UTF-8 contents'); + const bytes = Buffer.from(manifest.contents, 'utf8'); + const root = object(JSON.parse(manifest.contents)) as NativeRoot; + exactFields(root, ['label', 'package'], 'native shipping root'); + const label = canonicalShippingLabel(text(root.label)); + if (labels.has(label)) throw new Error('duplicate native shipping manifest root'); + labels.add(label); + const pkg = object(root.package); + exactFields( + pkg, + [ + 'product', + 'version', + 'ecosystem', + 'name', + 'configuration', + 'role', + 'outputs', + ...(Object.hasOwn(pkg, 'supplierInputs') ? ['supplierInputs'] : []), + ], + 'native shipping package', + ); + for (const field of ['product', 'version', 'ecosystem', 'name', 'configuration', 'role']) + text(pkg[field]); + if (Object.hasOwn(pkg, 'supplierInputs')) validateNativeShippingSuppliers(pkg.supplierInputs); + for (const output of list(pkg.outputs)) { + exactFields(object(output), ['path', 'owner'], 'native shipping output'); + relative(output.path); + text(output.owner); + } + const targets = bep.completed.filter( + (target) => canonicalShippingLabel(target.label) === label, + ); + if (targets.length !== 1 || targets[0].value.success !== true) + throw new Error(`native manifest requires one successful configured shipping root: ${label}`); + const target = targets[0]; + if (!bep.configs.has(target.configuration)) + throw new Error('native manifest target configuration is missing'); + const files = bep.filesOf(target.value, 'shipping_manifest'); + if (files.size !== 1 || !files.has(file)) + throw new Error(`native shipping_manifest output group mismatch: ${label}`); + equal( + files.get(file), + { sha256: createHash('sha256').update(bytes).digest('hex'), size: bytes.length }, + 'native BEP/shipping manifest digest', + ); + return { root, configuration: target.configuration, path: file }; + }); + if (!bindings.length) throw new Error('native producer requires shipping manifests'); + if (query) + for (const binding of bindings) + if (!query.configs.has(binding.configuration)) + throw new Error( + 'native scoped aquery shipping configuration differs from its producing build', + ); + return bindings; +} + +/** Bind source-owned mandatory tests to exactly the shipping roots they qualify. */ +export function nativeShippingQualificationPolicy( + capture: NativeProducerCapture, + bep: ReturnType, + roots: NativeRoot[], +) { + if (capture.qualificationManifest === undefined) return undefined; + const manifest = object(capture.qualificationManifest); + exactFields(manifest, ['path', 'contents'], 'native owner qualification manifest'); + const file = relative(manifest.path); + if (!file.startsWith('bazel-out/') || typeof manifest.contents !== 'string') + throw new Error('native owner qualification requires a generated UTF-8 manifest'); + const owner = object(JSON.parse(manifest.contents)); + exactFields( + owner, + [ + 'schema', + 'scope', + 'owner', + 'roots', + 'packages', + 'qualification', + ...(Object.hasOwn(owner, 'policies') ? ['policies'] : []), + ], + 'native owner qualification', + ); + if (owner.schema !== 'oliphaunt-bazel-shipping-v1' || owner.scope !== 'construction') + throw new Error('native owner qualification manifest has an unsupported schema'); + const label = canonicalShippingLabel(text(owner.owner)); + const labels = list(owner.roots).map((value) => canonicalShippingLabel(text(value))); + const tests = list(owner.qualification).map((value) => canonicalShippingLabel(text(value))); + for (const [values, context] of [ + [labels, 'roots'], + [tests, 'tests'], + ] as const) + if (new Set(values).size !== values.length || values.some((value) => !value.startsWith('//'))) + throw new Error(`native owner qualification requires unique workspace ${context}`); + const policies = ( + Object.hasOwn(owner, 'policies') + ? list(owner.policies) + : [{ owner: label, roots: labels, qualification: tests }] + ).map((raw) => { + const policy = object(raw); + exactFields(policy, ['owner', 'roots', 'qualification'], 'native source owner policy'); + const owner = canonicalShippingLabel(text(policy.owner)); + const roots = list(policy.roots).map((value) => canonicalShippingLabel(text(value))); + const qualification = list(policy.qualification).map((value) => + canonicalShippingLabel(text(value)), + ); + if ( + !owner.startsWith('//') || + !roots.length || + [roots, qualification].some( + (values) => + new Set(values).size !== values.length || values.some((value) => !value.startsWith('//')), + ) + ) + throw new Error('native source owner policy requires unique workspace roots and tests'); + return { owner, roots, qualification }; + }); + if (new Set(policies.map((policy) => policy.owner)).size !== policies.length) + throw new Error('native source owner policy repeats an owner'); + equal( + policies.flatMap((policy) => policy.roots).sort(), + [...labels].sort(), + 'native source owner policy root coverage', + ); + equal( + [...new Set(policies.flatMap((policy) => policy.qualification))].sort(), + [...tests].sort(), + 'native source owner policy test coverage', + ); + equal( + [...labels].sort(), + roots.map((root) => canonicalShippingLabel(root.label)).sort(), + 'native owner qualification root coverage', + ); + equal( + labels + .map((label, index) => ({ label, package: list(owner.packages)[index] })) + .sort((a, b) => a.label.localeCompare(b.label)), + roots + .map((root) => ({ ...root, label: canonicalShippingLabel(root.label) })) + .sort((a, b) => a.label.localeCompare(b.label)), + 'native owner qualification package coverage', + ); + if (list(owner.packages).length !== labels.length) + throw new Error('native owner qualification has extra package declarations'); + const targets = bep.completed.filter((target) => canonicalShippingLabel(target.label) === label); + if (targets.length !== 1 || targets[0].value.success !== true) + throw new Error('native owner qualification requires one successful configured export'); + const target = targets[0]; + if (!bep.configs.has(target.configuration)) + throw new Error('native owner qualification configuration is missing'); + const files = bep.filesOf(target.value, 'shipping_policy'); + if (files.size !== 1 || !files.has(file)) + throw new Error('native owner qualification output group differs'); + const bytes = Buffer.from(manifest.contents, 'utf8'); + equal( + files.get(file), + { sha256: createHash('sha256').update(bytes).digest('hex'), size: bytes.length }, + 'native BEP/owner qualification digest', + ); + const rootConfigurations = roots.map((root) => { + const matching = bep.completed.filter( + (candidate) => canonicalShippingLabel(candidate.label) === canonicalShippingLabel(root.label), + ); + if ( + matching.length !== 1 || + matching[0].value.success !== true || + !bep.configs.has(matching[0].configuration) + ) + throw new Error('native owner qualification has no unambiguous configured shipping root'); + return { label: canonicalShippingLabel(root.label), configuration: matching[0].configuration }; + }); + const requiredTests = tests.map((label) => { + const matching = bep.completed.filter( + (candidate) => canonicalShippingLabel(candidate.label) === label, + ); + if ( + matching.length !== 1 || + matching[0].value.success !== true || + !bep.configs.has(matching[0].configuration) + ) + throw new Error('native owner qualification has no unambiguous mandatory configured test'); + return { label, configuration: matching[0].configuration }; + }); + return { + owner: label, + configuration: target.configuration, + roots: labels, + rootConfigurations, + requiredTests, + policies: policies.map((policy) => ({ + owner: policy.owner, + roots: policy.roots, + requiredTests: requiredTests.filter((test) => policy.qualification.includes(test.label)), + })), + }; +} + +/** A test from another owner cannot qualify an owner with no declared policy. */ +export function nativeShippingRootsHaveQualification( + policy: ReturnType, + roots: Pick[], +) { + return ( + !!policy && + roots.length > 0 && + roots.every((root) => + (policy.policies ?? [policy]).some( + (owner) => + owner.roots.includes(canonicalShippingLabel(root.label)) && + owner.requiredTests.length > 0, + ), + ) + ); +} + +/** Actual observer Files of source-owned mandatory configured tests; never shipping inputs. */ +export function nativeQualificationInputBindings( + aquery: unknown, + bep: ReturnType, + policy: ReturnType, +) { + let resolveInputs: ReturnType | undefined; + return (policy?.requiredTests ?? []).flatMap((test) => { + const targets = bep.completed.filter( + (target) => + canonicalShippingLabel(target.label) === test.label && + target.configuration === test.configuration, + ); + if (targets.length !== 1 || targets[0].value.success !== true) + throw new Error('native qualification requires one successful source-owned configured test'); + const groups = list(targets[0].value.outputGroup ?? []).filter( + (group) => group.name === 'observation_inputs', + ); + if (!groups.length) return []; + if (groups.length !== 1) + throw new Error('native qualification requires one observation_inputs group'); + const files = bep.filesOf(targets[0].value, 'observation_inputs'); + if (![3, 4].includes(files.size)) + throw new Error( + 'native installed qualification requires its exact three or four observer Files', + ); + for (const file of files.keys()) + if (!file.startsWith('bazel-out/')) + throw new Error('native qualification observer requires a generated bazel-out File'); + resolveInputs ??= createConfiguredAqueryTargetInputResolver(aquery); + const declared = resolveInputs(test.label, test.configuration); + for (const file of files.keys()) + if (!declared.inputs.has(file)) + throw new Error( + 'native qualification observer File was not consumed by its configured test', + ); + const specifications = [...files.keys()].filter((file) => declared.written.has(file)); + if (specifications.length !== 1) + throw new Error( + 'native qualification requires exactly one same-test configured specification FileWrite', + ); + return [{ ...test, specification: specifications[0], files }]; + }); +} + +function validateNativeQualificationInputs( + raw: unknown, + bindings: ReturnType, +) { + const seen = new Set(); + const result = (raw === undefined ? [] : list(raw)).map((value) => { + const row = object(value); + exactFields( + row, + ['label', 'configuration', 'specification', 'inputs'], + 'native qualification inputs', + ); + const label = canonicalShippingLabel(row.label), + configuration = text(row.configuration); + const key = `${label}\0${configuration}`; + if (seen.has(key)) throw new Error('duplicate native qualification inputs'); + seen.add(key); + const binding = bindings.find( + (test) => test.label === label && test.configuration === configuration, + ); + if (!binding) + throw new Error('native qualification inputs are not a source-owned observer test'); + equal(relative(row.specification), binding.specification, 'native qualification specification'); + const captured = captures( + row.inputs, + [...binding.files.keys()], + 'native qualification observer', + ); + for (const [file, capture] of captured) { + const member = capture.members[0]; + if (capture.members.length !== 1 || member.type !== 'file') + throw new Error('native qualification observer requires a regular File'); + equal( + { sha256: member.sha256, size: member.size }, + binding.files.get(file), + 'native qualification BEP/physical observer digest', + ); + } + return { + label, + configuration, + specification: binding.specification, + inputs: structuredClone([...captured.values()]), + }; + }); + equal( + [...seen].sort(), + bindings.map((test) => `${test.label}\0${test.configuration}`).sort(), + 'native qualification inputs coverage', + ); + return result; +} + +/** Validate content reported by the actual qualifying builder, including cache-backed success. */ +export function validateNativeBuildEvidence( + raw: unknown, + expected: { + source: NativeBuildSource; + github: NativeBuildGithub; + bazelVersion: string; + requiredTests?: NativeRequiredTest[]; + requireShippingAnalysis?: boolean; + }, +) { + source(expected.source); + assertNativeBuildGithub(expected.github); + text(expected.bazelVersion); + const evidence = object(raw) as NativeBuildEvidence; + exactFields(evidence, ['schema', 'source', 'github', 'cohorts'], 'native build evidence'); + if (evidence.schema !== 'oliphaunt-native-build-evidence-v1') + throw new Error('unsupported native build evidence'); + source(evidence.source); + assertNativeBuildGithub(evidence.github); + equal(evidence.source, expected.source, 'native build source'); + equal(evidence.github, expected.github, 'native build producing workflow/run/attempt/job'); + if (!list(evidence.cohorts).length) + throw new Error('native build evidence requires configured cohorts'); + const invocations = new Set(); + const requiredTests = + expected.requiredTests === undefined + ? undefined + : list(expected.requiredTests).map((raw) => { + const row = object(raw); + exactFields(row, ['label', 'configuration'], 'native required test'); + return { + label: canonicalShippingLabel(row.label), + configuration: text(row.configuration), + }; + }); + if ( + requiredTests && + (!requiredTests.length || + new Set(requiredTests.map((test) => `${test.label}\0${test.configuration}`)).size !== + requiredTests.length) + ) + throw new Error('native required tests must be a nonempty unique configured root set'); + const testObservations = new Map< + string, + { label: string; configuration: string; invocationId: string }[] + >(); + const policyTests = new Map(); + const cohorts = evidence.cohorts.map((cohort) => { + exactFields( + object(cohort), + [ + 'executionRoot', + 'roots', + 'rootConfigurations', + 'aquery', + 'buildEvents', + 'inputs', + 'outputs', + ...(cohort.producerCapture === undefined ? [] : ['producerCapture']), + ...(cohort.seedConstructions === undefined ? [] : ['seedConstructions']), + ...(cohort.analysisInputs === undefined ? [] : ['analysisInputs']), + ...(cohort.rootAnalysisInputPaths === undefined ? [] : ['rootAnalysisInputPaths']), + ...(cohort.qualificationInputs === undefined ? [] : ['qualificationInputs']), + ], + 'native build cohort', + ); + if ( + !path.posix.isAbsolute(text(cohort.executionRoot)) && + !path.win32.isAbsolute(cohort.executionRoot) + ) + throw new Error('native build requires its absolute execution root'); + if (!list(cohort.roots).length) throw new Error('native build requires actual shipping roots'); + const rootConfigurations = new Map(); + const analysis = nativeAnalysisInputBindings(cohort); + for (const raw of list(cohort.rootConfigurations)) { + const row = object(raw); + exactFields(row, ['label', 'configuration'], 'native configured root'); + const label = text(row.label); + if (rootConfigurations.has(label)) throw new Error('duplicate native configured root'); + rootConfigurations.set(label, text(row.configuration)); + } + equal( + [...rootConfigurations.keys()].sort(), + cohort.roots.map((root) => text(root.label)).sort(), + 'native configured root coverage', + ); + let checkFileWrite!: ConfiguredFileWriteCheck; + const view = buildShippingInputView( + { + schema: 'oliphaunt-bazel-shipping-v1', + scope: 'construction', + packages: cohort.roots.map((root) => root.package), + }, + cohort.aquery, + { + inspectFileWrites: (check) => { + checkFileWrite = check; + }, + }, + ); + const graph = object(cohort.aquery); + const configurationIds = new Map( + list(graph.configuration).map((row) => [String(row.id), text(row.checksum)]), + ); + for (const action of list(graph.actions)) + if (!configurationIds.has(String(action.configurationId))) + throw new Error('native aquery action configuration is missing'); + const actions = [ + ...new Set(Object.values(view.products).flatMap((product) => product.actions)), + ].sort(); + const inputs = captures( + cohort.inputs, + nativeRequiredCaptureInputs(view), + 'native input content', + ); + const seedConstructions = validateNativeSeedConstructions( + cohort.seedConstructions, + [...inputs.values()], + actions, + ); + const outputs = captures( + cohort.outputs, + cohort.roots.flatMap((root) => root.package.outputs.map((output) => relative(output.path))), + 'native output content', + ); + const bep = nativeBuildEventIndex( + cohort, + expected.bazelVersion, + nativeBuildMetadata(expected.source, expected.github), + ); + if (invocations.has(bep.invocationId)) + throw new Error('native evidence repeats a build invocation'); + invocations.add(bep.invocationId); + if (cohort.producerCapture !== undefined) { + const bindings = nativeShippingManifestBindings(cohort.producerCapture, bep); + equal( + bindings.map(({ root }) => root).sort((a, b) => a.label.localeCompare(b.label)), + [...cohort.roots].sort((a, b) => a.label.localeCompare(b.label)), + 'native analysis shipping roots', + ); + for (const { root, configuration } of bindings) + equal( + rootConfigurations.get(root.label), + configuration, + 'native analysis shipping configuration', + ); + for (const { root, path, configuration } of bindings) + checkFileWrite( + { path, owner: root.label }, + configuration, + 'native shipping manifest requires its configured FileWrite action', + ); + } else if (expected.requireShippingAnalysis === true) + throw new Error('native qualification requires producing-analysis shipping manifests'); + const qualificationPolicy = + cohort.producerCapture === undefined + ? undefined + : nativeShippingQualificationPolicy(cohort.producerCapture, bep, cohort.roots); + if (qualificationPolicy) { + for (const test of qualificationPolicy.requiredTests) + policyTests.set(`${test.label}\0${test.configuration}`, test); + checkFileWrite( + { + path: cohort.producerCapture!.qualificationManifest!.path, + owner: qualificationPolicy.owner, + }, + qualificationPolicy.configuration, + 'native owner qualification requires its configured FileWrite action', + ); + } + const qualificationInputs = validateNativeQualificationInputs( + cohort.qualificationInputs, + nativeQualificationInputBindings(cohort.aquery, bep, qualificationPolicy), + ); + const cohortTests = new Map( + (requiredTests ?? []).map((test) => [`${test.label}\0${test.configuration}`, test]), + ); + for (const test of qualificationPolicy?.requiredTests ?? []) + cohortTests.set(`${test.label}\0${test.configuration}`, test); + for (const test of cohortTests.values()) { + const matches = (event: Row, field: string) => + event.id?.[field] !== undefined && + canonicalShippingLabel(event.id[field].label) === test.label && + event.id[field].configuration?.id === test.configuration; + const summaries = bep.events.filter((event) => matches(event, 'testSummary')); + if (!summaries.length) { + if ( + qualificationPolicy?.requiredTests.some( + (required) => + required.label === test.label && required.configuration === test.configuration, + ) + ) + throw new Error( + `native owner policy is missing its mandatory configured test: ${test.label}`, + ); + continue; + } + const targets = bep.completed.filter( + (target) => + canonicalShippingLabel(target.label) === test.label && + target.configuration === test.configuration, + ); + const results = bep.events.filter((event) => matches(event, 'testResult')); + if ( + summaries.length !== 1 || + summaries[0].testSummary?.overallStatus !== 'PASSED' || + size(summaries[0].testSummary?.totalRunCount ?? 0) === 0 || + targets.length !== 1 || + targets[0].value.success !== true || + !bep.configs.has(test.configuration) || + !results.length || + results.some((event) => event.testResult?.status !== 'PASSED') || + size(summaries[0].testSummary.totalRunCount) !== results.length || + new Set(results.map((event) => canonical(event.id.testResult))).size !== results.length + ) + throw new Error( + `native BEP requires complete successful test results: ${test.label} (${test.configuration})`, + ); + const key = `${test.label}\0${test.configuration}`; + testObservations.set(key, [ + ...(testObservations.get(key) ?? []), + { ...test, invocationId: bep.invocationId }, + ]); + } + const roots = cohort.roots.map((root) => { + const expectedFiles = root.package.outputs.flatMap((output) => + outputs + .get(output.path)! + .members.filter((member) => member.type === 'file') + .map((member) => ({ + path: member.path ? `${output.path}/${member.path}` : output.path, + sha256: member.sha256, + size: member.size, + })), + ); + if (!expectedFiles.length) + throw new Error('native shipping root has no delivered file digests'); + const matches = bep.completed + .filter( + (target) => + canonicalShippingLabel(target.label) === canonicalShippingLabel(root.label) && + target.value.success === true, + ) + .filter((target) => { + const files = bep.filesOf(target.value, 'default'); + return expectedFiles.every((file) => files.has(file.path)); + }); + if (matches.length !== 1) + throw new Error( + `native BEP requires one successful configured shipping root: ${root.label}`, + ); + const target = matches[0]; + const configuration = bep.configs.get(target.configuration); + if (!configuration) throw new Error('native BEP target configuration is missing'); + equal( + target.configuration, + rootConfigurations.get(root.label), + 'native BEP/cquery shipping configuration', + ); + const files = bep.filesOf(target.value, 'default'); + for (const { path: file, ...identity } of expectedFiles) + equal(files.get(file), identity, 'native BEP/physical output digest'); + return { + label: root.label, + configuration: target.configuration, + configurationDetails: configuration, + package: root.package, + outputs: root.package.outputs.map((output) => outputs.get(output.path)), + }; + }); + return { + invocationId: bep.invocationId, + roots, + inputContentsDigest: digest( + [...inputs.values()].sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0)), + ), + actionDefinitionsDigest: digest({ schema: view.schema, actions }), + // The raw evidence retains actual configured actions and every input member. + aqueryDigest: digest(cohort.aquery), + buildEventsDigest: digest(cohort.buildEvents), + ...(qualificationPolicy ? { qualificationPolicy } : {}), + ...(qualificationInputs.length ? { qualificationInputs } : {}), + ...(seedConstructions.length ? { seedConstructions } : {}), + ...(analysis + ? { + rootAnalysisInputPaths: analysis.mappings, + analysisInputsDigest: digest(analysis.inputs), + } + : {}), + }; + }); + if (requiredTests && policyTests.size) + for (const test of policyTests.values()) + if ( + !requiredTests.some( + (required) => + required.label === test.label && required.configuration === test.configuration, + ) + ) + throw new Error( + `native required test plan omits source-owned mandatory configured test: ${test.label}`, + ); + const testsToVerify = requiredTests ?? [...policyTests.values()]; + const tests = testsToVerify.map((test) => { + const matches = testObservations.get(`${test.label}\0${test.configuration}`) ?? []; + if (matches.length !== 1) + throw new Error( + `native BEP requires one mandatory configured test: ${test.label} (${test.configuration}); found ${matches.length}`, + ); + return matches[0]; + }); + return { + scope: 'construction' as const, + source: evidence.source, + github: evidence.github, + cohorts, + shippingAnalysis: evidence.cohorts.every((cohort) => cohort.producerCapture !== undefined) + ? ('bound' as const) + : ('unverified' as const), + testQualification: testsToVerify.length ? ('passed' as const) : ('unverified' as const), + requiredTests: tests, + qualificationPolicy: cohorts.every((cohort) => + nativeShippingRootsHaveQualification(cohort.qualificationPolicy, cohort.roots), + ) + ? ('bound' as const) + : ('unverified' as const), + releaseDecision: 'unverified' as const, + unverified: [ + 'authenticated producing workflow, attempt, job and immutable artifact', + 'immutable input lifetime from the producing build through content capture', + 'native action-graph dump bytes authenticated by the producing invocation', + ...(evidence.cohorts.some((cohort) => cohort.producerCapture === undefined) + ? ['shipping identities and configurations bound to the producing analysis'] + : []), + ...(cohorts.some( + (cohort) => !nativeShippingRootsHaveQualification(cohort.qualificationPolicy, cohort.roots), + ) + ? ['source-owned mandatory qualification policy bound to every configured shipping root'] + : []), + ...(!testsToVerify.length + ? ['declared mandatory test roots and successful BEP results'] + : []), + 'complete canonical product qualification and completed-baseline admission', + ], + }; +} + +/** Preparation checks the checkout API; final selected Swift must also qualify + * the exact prospective installed package under its final source-owned policy. + * These are checks on captured configured facts, never producer authority. */ +export function assertNativeSwiftShippingPhase( + qualification: ReturnType, + phase: 'pre-version' | 'final', +) { + const sourceOwners = [ + '//src/native/sdks/swift:preparation_shipping_export', + '//src/native/sdks/swift:shipping_export', + ]; + const sourceRoots = qualification.cohorts.flatMap((cohort) => + cohort.roots + .filter( + (root) => + root.package.product === 'oliphaunt-swift' && + ((root.package.ecosystem === 'github' && + root.package.role === 'release-input' && + root.package.name === 'Oliphaunt-source.zip') || + cohort.qualificationPolicy?.policies.some( + (policy) => + sourceOwners.includes(policy.owner) && + policy.roots.includes(canonicalShippingLabel(root.label)), + )), + ) + .map((root) => ({ cohort, root })), + ); + if (!sourceRoots.length) return; + const owner = + phase === 'pre-version' + ? '//src/native/sdks/swift:preparation_shipping_export' + : '//src/native/sdks/swift:shipping_export'; + for (const { cohort, root } of sourceRoots) { + const policies = cohort.qualificationPolicy?.policies ?? []; + const matches = policies.filter((policy) => + policy.roots.includes(canonicalShippingLabel(root.label)), + ); + if ( + matches.length !== 1 || + (phase === 'final' ? matches[0].owner !== owner : !sourceOwners.includes(matches[0].owner)) + ) + throw new Error('Swift ' + phase + ' requires its source-owned ' + owner + ' policy'); + if ( + phase === 'final' && + !matches[0].requiredTests.some( + (test) => test.label === '//src/native/sdks/swift:installed_consumer_test', + ) + ) + throw new Error('final selected Swift requires its configured installed consumer test'); + } +} + +/** Final selected source owners must carry their installed requirement proof. */ +export function assertNativeFinalShippingPhase( + qualification: ReturnType, + selectedProducts: readonly string[], +) { + if (selectedProducts.includes('oliphaunt-swift')) + assertNativeSwiftShippingPhase(qualification, 'final'); + for (const cohort of qualification.cohorts) + for (const { package: pkg } of cohort.roots) + if ( + selectedProducts.includes(pkg.product) && + pkg.role === 'extension-release-link-input' && + (pkg.ecosystem !== 'internal' || !pkg.name.endsWith('-wasix-final-link')) + ) + throw new Error('final WASIX extension requires prepared exact-host qualification'); + for (const cohort of qualification.cohorts) + for (const root of cohort.roots.filter( + (root) => + selectedProducts.includes(root.package.product) && + root.package.ecosystem === 'cargo' && + ((root.package.product === 'oliphaunt-rust' && root.package.name === 'oliphaunt') || + (root.package.product === 'oliphaunt-broker' && + root.package.name === 'oliphaunt-broker')), + )) { + const policies = (cohort.qualificationPolicy?.policies ?? []).filter((policy) => + policy.roots.includes(canonicalShippingLabel(root.label)), + ); + if ( + policies.length !== 1 || + !policies[0].requiredTests.some( + (test) => test.label === '//build_defs/languages/installed:consumer_minimum_test', + ) + ) + throw new Error( + 'final selected Cargo source requires its configured declared-minimum consumer test', + ); + } +} diff --git a/tools/release/native-build-qualification.test.mts b/tools/release/native-build-qualification.test.mts new file mode 100644 index 000000000..ff126202b --- /dev/null +++ b/tools/release/native-build-qualification.test.mts @@ -0,0 +1,1305 @@ +import { expect, test } from 'bun:test'; +import { execFileSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + captureSeedConstructionIntent, + writeSeedConstructionReceipt, +} from '../../build_defs/resources/seed_construction.mts'; +import { + assertAuthenticatedNativeBuildOrigin, + authenticateNativeBuildEvidence, +} from './authenticate-native-build-evidence.mts'; +import { + buildShippingInputView, + configuredAqueryTargetInputs, + createConfiguredAqueryTargetInputResolver, +} from './bazel-shipping-inputs.mts'; +import { + assertNativeFinalShippingPhase, + type NativeBuildEvidence, + nativeAnalysisInputBindings, + nativeBuildMetadata, + nativeQualificationInputBindings, + nativeRequiredCaptureInputs, + validateNativeBuildEvidence, + validateNativeSeedConstructions, +} from './native-build-qualification.mts'; +import { captureNativeOutputMembers } from './native-publication-staging.mts'; + +test('source WASIX host probes cannot replace prepared exact-host final qualification', () => { + const product = 'oliphaunt-extension-pg-textsearch'; + const pkg = { + product, + name: 'pg_textsearch-wasix-pre-version-link', + ecosystem: 'internal', + role: 'extension-release-link-input', + }; + const qualification = { cohorts: [{ roots: [{ package: pkg }] }] } as any; + expect(() => assertNativeFinalShippingPhase(qualification, [])).not.toThrow(); + expect(() => assertNativeFinalShippingPhase(qualification, [product])).toThrow( + 'prepared exact-host', + ); + pkg.name = 'pg_textsearch-wasix-final-link'; + expect(() => assertNativeFinalShippingPhase(qualification, [product])).not.toThrow(); + pkg.ecosystem = 'npm'; + expect(() => assertNativeFinalShippingPhase(qualification, [product])).toThrow( + 'prepared exact-host', + ); +}); + +test('selected SDK and Broker final sources require minimum proof, without a helper-only or held trigger', () => { + const common = '//build_defs/languages/installed:consumer_test'; + const minimum = '//build_defs/languages/installed:consumer_minimum_test'; + const descriptors = [ + ['//src/native/sdks/rust:shipping_package', 'oliphaunt-rust', 'oliphaunt'], + [ + '//src/native/sdks/rust/crates/oliphaunt-build:shipping_package', + 'oliphaunt-rust', + 'oliphaunt-build', + ], + ['//src/native/broker:shipping_package', 'oliphaunt-broker', 'oliphaunt-broker'], + ]; + const qualification = { + cohorts: [ + { + roots: descriptors.map(([label, product, name]) => ({ + label, + package: { product, name, ecosystem: 'cargo' }, + })), + qualificationPolicy: { + policies: descriptors.map(([label]) => ({ + roots: [label], + requiredTests: [{ label: common }], + })), + }, + }, + ], + } as any; + expect(() => + assertNativeFinalShippingPhase(qualification, ['liboliphaunt-native-bindings']), + ).not.toThrow(); + expect(() => assertNativeFinalShippingPhase(qualification, ['oliphaunt-rust'])).toThrow( + 'declared-minimum', + ); + expect(() => assertNativeFinalShippingPhase(qualification, ['oliphaunt-broker'])).toThrow( + 'declared-minimum', + ); + qualification.cohorts[0].qualificationPolicy.policies[0].requiredTests.push({ label: minimum }); + expect(() => assertNativeFinalShippingPhase(qualification, ['oliphaunt-rust'])).not.toThrow(); + expect(() => + assertNativeFinalShippingPhase(qualification, ['oliphaunt-rust', 'oliphaunt-broker']), + ).toThrow('declared-minimum'); + qualification.cohorts[0].qualificationPolicy.policies[2].requiredTests.push({ label: minimum }); + expect(() => + assertNativeFinalShippingPhase(qualification, ['oliphaunt-rust', 'oliphaunt-broker']), + ).not.toThrow(); + qualification.cohorts[0].qualificationPolicy.policies[2].requiredTests[1].label = `${minimum}_fixture`; + expect(() => assertNativeFinalShippingPhase(qualification, ['oliphaunt-broker'])).toThrow( + 'declared-minimum', + ); +}); + +// BEP fields follow an actual Bazel 8.8.1 capture, including omitted proto zeroes. +function fixture() { + const executionRoot = mkdtempSync(path.join(tmpdir(), 'oliphaunt-native-build-')); + const output = 'bazel-out/k8-opt/bin/package/native.tgz'; + const generated = 'bazel-out/k8-opt/bin/package/config.h'; + const source = 'package/source.mts'; + const tool = 'external/bun/bun'; + for (const [file, content] of [ + [output, 'packed public bytes'], + [generated, '#define VALUE 1\n'], + [source, 'source'], + [tool, 'compiler'], + ]) { + mkdirSync(path.dirname(path.join(executionRoot, file)), { recursive: true }); + writeFileSync(path.join(executionRoot, file), content); + } + const capture = (file: string) => ({ + path: file, + members: file.startsWith('bazel-out/') + ? captureNativeOutputMembers(executionRoot, file).members + : [ + { + path: '', + type: 'file' as const, + mode: 0o644, + size: readFileSync(path.join(executionRoot, file)).length, + sha256: createHash('sha256') + .update(readFileSync(path.join(executionRoot, file))) + .digest('hex'), + }, + ], + }); + const files = [source, tool, generated, output]; + const aquery = { + pathFragments: files.flatMap((file, index) => { + const parts = file.split('/'); + return parts.map((label, segment) => ({ + id: `${index}-${segment}`, + label, + ...(segment ? { parentId: `${index}-${segment - 1}` } : {}), + })); + }), + artifacts: files.map((file, index) => ({ + id: index + 1, + pathFragmentId: `${index}-${file.split('/').length - 1}`, + })), + targets: [ + { id: 1, label: '//package:generated' }, + { id: 2, label: '//package:archive' }, + ], + configuration: [{ id: 1, checksum: 'c'.repeat(64) }], + depSetOfFiles: [ + { id: 1, directArtifactIds: [1] }, + { id: 2, directArtifactIds: [1, 2, 3] }, + ], + actions: [ + { + targetId: 1, + configurationId: 1, + mnemonic: 'FileWrite', + actionKey: 'declaration-key-1', + inputDepSetIds: [1], + outputIds: [3], + primaryOutputId: 3, + fileContents: '#define VALUE 1\n', + }, + { + targetId: 2, + configurationId: 1, + mnemonic: 'Package', + actionKey: 'declaration-key-2', + arguments: ['bun', 'source.mts'], + inputDepSetIds: [2], + outputIds: [4], + primaryOutputId: 4, + }, + ], + }; + const expected = { + source: { commit: 'a'.repeat(40), tree: 'b'.repeat(40) }, + github: { + repository: 'f0rr0/oliphaunt', + workflow: 'Native Bazel qualification', + workflowPath: '.github/workflows/bazel.yml', + runId: 456, + runAttempt: 2, + job: 'Linux runtime (x86_64)', + }, + bazelVersion: '8.8.1', + }; + const out = capture(output).members[0]; + if (out.type !== 'file') throw new Error('fixture output must be a regular file'); + const events = [ + { + id: { started: {} }, + started: { uuid: 'actual-invocation', buildToolVersion: '8.8.1', command: 'build' }, + }, + { id: { workspace: {} }, workspaceInfo: { localExecRoot: executionRoot } }, + { + id: { configuration: { id: 'c'.repeat(64) } }, + configuration: { mnemonic: 'k8-opt', cpu: 'k8' }, + }, + { + id: { namedSet: { id: 'nested' } }, + namedSetOfFiles: { + files: [ + { + pathPrefix: ['bazel-out', 'k8-opt', 'bin'], + name: 'package/native.tgz', + digest: out.sha256, + length: String(out.size), + }, + ], + }, + }, + { id: { namedSet: { id: 'default' } }, namedSetOfFiles: { fileSets: [{ id: 'nested' }] } }, + { + id: { targetCompleted: { label: '//package:ship', configuration: { id: 'c'.repeat(64) } } }, + completed: { + success: true, + outputGroup: [{ name: 'default', fileSets: [{ id: 'default' }] }], + }, + }, + { + id: { buildFinished: {} }, + finished: { overallSuccess: true, exitCode: { name: 'SUCCESS' } }, + }, + { + id: { buildMetadata: {} }, + buildMetadata: { metadata: nativeBuildMetadata(expected.source, expected.github) }, + }, + { id: { buildMetrics: {} }, lastMessage: true, buildMetrics: {} }, + ]; + const evidence: NativeBuildEvidence = { + schema: 'oliphaunt-native-build-evidence-v1', + source: expected.source, + github: expected.github, + cohorts: [ + { + executionRoot, + rootConfigurations: [{ label: '//package:ship', configuration: 'c'.repeat(64) }], + roots: [ + { + label: '//package:ship', + package: { + product: 'fixture-native', + version: '1.0.0', + ecosystem: 'github', + name: 'native.tgz', + configuration: 'linux-x64-gnu', + role: 'github-release-asset', + outputs: [{ path: output, owner: '//package:archive' }], + }, + }, + ], + aquery, + buildEvents: events, + inputs: [], + outputs: [capture(output)], + }, + ], + }; + evidence.cohorts[0].inputs = nativeRequiredCaptureInputs( + buildShippingInputView( + { + schema: 'oliphaunt-bazel-shipping-v1', + scope: 'construction', + packages: evidence.cohorts[0].roots.map((root) => root.package), + }, + aquery, + ), + ).map(capture); + return { + evidence, + expected, + executionRoot, + output, + generated, + source, + tool, + capture, + cleanup: () => rmSync(executionRoot, { recursive: true, force: true }), + }; +} + +test('successful cache-backed target binds configured output bytes and all current input contents', () => { + const f = fixture(); + try { + const result = validateNativeBuildEvidence(f.evidence, f.expected); + expect(result.scope).toBe('construction'); + expect(result.releaseDecision).toBe('unverified'); + expect(result.testQualification).toBe('unverified'); + expect(result.github.runId).toBe(456); + expect(result.cohorts[0].roots[0].configuration).toBe('c'.repeat(64)); + expect(result.cohorts[0].roots[0].package.configuration).toBe('linux-x64-gnu'); + expect(result.cohorts[0].inputContentsDigest).toMatch(/^sha256:[0-9a-f]{64}$/); + expect(result.unverified).toContain( + 'authenticated producing workflow, attempt, job and immutable artifact', + ); + // No execution log exists or is needed: successful Bazel cache reuse is valid. + expect(Object.hasOwn(result, 'executionLog')).toBe(false); + } finally { + f.cleanup(); + } +}); + +// Real stock Bazel 8.8.1 NAPI capture had distinct external source-root Cargo.toml +// Files with no pathPrefix in observation_inputs. ShippingInfo outputs are the +// package's DefaultInfo, so input-only observations must not collide with finals. +test('shipping default outputs remain bound with real observation source-name collisions', () => { + const f = fixture(); + try { + const cohort = f.evidence.cohorts[0]; + const observations = [ + { + name: 'Cargo.toml', + uri: 'file:///diagnostic-output/external/registry-package-0/Cargo.toml', + digest: 'c4f4ae997dce02e055a1ce5df6f5dc289d7297702ef54e39a32d61f9d27d4fe6', + length: '7483', + }, + { + name: 'Cargo.toml', + uri: 'file:///diagnostic-output/external/registry-package-1/Cargo.toml', + digest: 'e17cb588cdea3490bc7cde3a145426e6097075b82879e0cb9eca0e0c8b735b90', + length: '11202', + }, + ]; + cohort.buildEvents.splice(3, 0, { + id: { namedSet: { id: 'observation' } }, + namedSetOfFiles: { files: observations }, + }); + const completed = (cohort.buildEvents as any[]).find((event) => event.id?.targetCompleted); + completed.completed.outputGroup.push({ + name: 'observation_inputs', + fileSets: [{ id: 'observation' }], + }); + const result = validateNativeBuildEvidence(f.evidence, f.expected); + expect(result.cohorts[0].roots[0].outputs).toEqual(cohort.outputs); + } finally { + f.cleanup(); + } +}); + +test('shipping default outputs reject conflicting repeated final identities', () => { + const f = fixture(); + try { + const cohort = f.evidence.cohorts[0]; + const output = (cohort.buildEvents as any[]).find( + (event) => event.id?.namedSet?.id === 'nested', + ); + output.namedSetOfFiles.files.push({ + ...output.namedSetOfFiles.files[0], + digest: 'f'.repeat(64), + }); + expect(() => validateNativeBuildEvidence(f.evidence, f.expected)).toThrow( + 'native BEP duplicate file mismatch', + ); + } finally { + f.cleanup(); + } +}); + +test('loaded-source facts bind each shipping root and remain optional for old diagnostic packets', () => { + const f = fixture(); + try { + const cohort = f.evidence.cohorts[0]; + expect(nativeAnalysisInputBindings(cohort)).toBeUndefined(); + cohort.analysisInputs = [f.capture(f.source)]; + cohort.rootAnalysisInputPaths = [{ label: cohort.roots[0].label, paths: [f.source] }]; + const result = validateNativeBuildEvidence(f.evidence, f.expected); + expect(result.cohorts[0].rootAnalysisInputPaths).toEqual(cohort.rootAnalysisInputPaths); + expect(result.cohorts[0].analysisInputsDigest).toMatch(/^sha256:[a-f0-9]{64}$/u); + expect(result.releaseDecision).toBe('unverified'); + for (const fault of [ + 'missing-capture', + 'missing-map', + 'foreign-root', + 'duplicate-root', + 'foreign-path', + 'generated', + 'empty', + 'directory', + ]) { + const changed = structuredClone(cohort); + if (fault === 'missing-capture') delete changed.analysisInputs; + if (fault === 'missing-map') delete changed.rootAnalysisInputPaths; + if (fault === 'foreign-root') changed.rootAnalysisInputPaths![0].label = '//foreign:shipping'; + if (fault === 'duplicate-root') + changed.rootAnalysisInputPaths!.push(changed.rootAnalysisInputPaths![0]); + if (fault === 'foreign-path') + changed.rootAnalysisInputPaths![0].paths = ['other/BUILD.bazel']; + if (fault === 'generated') + changed.rootAnalysisInputPaths![0].paths = ['bazel-out/k8-opt/bin/BUILD.bazel']; + if (fault === 'empty') changed.rootAnalysisInputPaths![0].paths = []; + if (fault === 'directory') + changed.analysisInputs![0].members = [{ path: '', type: 'directory', mode: 0o755 }]; + expect(() => nativeAnalysisInputBindings(changed), fault).toThrow(); + } + } finally { + f.cleanup(); + } +}); + +test('reached seed constructor JSON binds its own captured File and same-action frozen TAR', () => { + const f = fixture(); + try { + const stem = 'bazel-out/k8-opt/bin/package/seed'; + const frozen = `${stem}.tar`; + const receiptPath = `${stem}.seed-construction.json`; + writeFileSync(path.join(f.executionRoot, frozen), 'immutable frozen PGDATA fixture'); + const pgdata = path.join(f.executionRoot, 'pgdata'); + const contract = JSON.parse( + readFileSync( + new URL('../../src/database-resources/contracts/contract.json', import.meta.url), + 'utf8', + ), + ); + for (const name of contract.pgdataDirectories) + mkdirSync(path.join(pgdata, name), { recursive: true }); + writeFileSync(path.join(pgdata, 'PG_VERSION'), '18\n'); + const intent = captureSeedConstructionIntent( + { family: 'native', target: 'linux-x64-gnu', profile: 'standard' }, + { command: 'fixture-initdb' }, + { constructor: path.join(f.executionRoot, f.source) }, + ); + writeSeedConstructionReceipt( + path.join(f.executionRoot, receiptPath), + intent, + path.join(f.executionRoot, frozen), + pgdata, + ); + const rows = [ + { + path: receiptPath, + contents: readFileSync(path.join(f.executionRoot, receiptPath), 'utf8'), + }, + ]; + const inputs = [f.capture(receiptPath), f.capture(frozen)]; + const action = { mnemonic: 'PostgresClusterSeed', outputs: [frozen, receiptPath] }; + expect(validateNativeSeedConstructions(rows, inputs, [JSON.stringify(action)])).toEqual(rows); + for (const failure of [ + 'missing', + 'duplicate', + 'contents', + 'frozen', + 'action', + 'family', + 'split-output', + ] as const) { + const current = structuredClone(rows); + const files = structuredClone(inputs); + const producer = structuredClone(action); + if (failure === 'missing') current.length = 0; + else if (failure === 'duplicate') current.push(current[0]); + else if (failure === 'contents') current[0].contents += ' '; + else if (failure === 'frozen') files[1].members[0].sha256 = 'f'.repeat(64); + else if (failure === 'action') producer.mnemonic = 'FileWrite'; + else if (failure === 'family') producer.mnemonic = 'WasixClusterSeed'; + else producer.outputs = [receiptPath]; + expect(() => + validateNativeSeedConstructions(current, files, [JSON.stringify(producer)]), + ).toThrow(); + } + } finally { + f.cleanup(); + } +}); + +function requiredTestEvents() { + const identity = { label: '//package:consumer_test', configuration: { id: 'c'.repeat(64) } }; + return [ + { id: { targetCompleted: identity }, completed: { success: true } }, + { + id: { testResult: { ...identity, run: 1, shard: 1, attempt: 1 } }, + testResult: { status: 'PASSED', cachedLocally: true }, + }, + { + id: { testSummary: identity }, + testSummary: { overallStatus: 'PASSED', totalRunCount: 1, totalNumCached: 1 }, + }, + ]; +} + +test('explicit mandatory configured tests require actual successful BEP summaries and accept cache reuse', () => { + const f = fixture(); + try { + const expected = { + ...f.expected, + requiredTests: [{ label: '@@//package:consumer_test', configuration: 'c'.repeat(64) }], + }; + expect(() => validateNativeBuildEvidence(f.evidence, expected)).toThrow( + /mandatory configured test/, + ); + f.evidence.cohorts[0].buildEvents.splice(-1, 0, ...requiredTestEvents()); + const result = validateNativeBuildEvidence(f.evidence, expected); + expect(result.testQualification).toBe('passed'); + expect(result.requiredTests).toEqual([ + { + label: '//package:consumer_test', + configuration: 'c'.repeat(64), + invocationId: 'actual-invocation', + }, + ]); + expect(result.releaseDecision).toBe('unverified'); + expect(() => + validateNativeBuildEvidence(f.evidence, { ...expected, requiredTests: [] }), + ).toThrow(/nonempty unique/); + expect(() => + validateNativeBuildEvidence(f.evidence, { + ...expected, + requiredTests: [ + ...expected.requiredTests, + { label: '//package:consumer_test', configuration: 'c'.repeat(64) }, + ], + }), + ).toThrow(/nonempty unique/); + expect(() => + validateNativeBuildEvidence(f.evidence, { + ...expected, + requiredTests: [{ label: '//package:consumer_test', configuration: 'different' }], + }), + ).toThrow(/mandatory configured test/); + } finally { + f.cleanup(); + } +}); + +test('missing, failed, skipped, incomplete or ambiguous mandatory tests fail closed', () => { + const f = fixture(); + try { + const expected = { + ...f.expected, + requiredTests: [{ label: '//package:consumer_test', configuration: 'c'.repeat(64) }], + }; + for (const change of [ + (events: any[]) => events.pop(), + (events: any[]) => { + events[2].testSummary.overallStatus = 'FAILED'; + }, + (events: any[]) => { + events[2].testSummary.overallStatus = 'FLAKY'; + }, + (events: any[]) => { + events[2].testSummary.totalRunCount = 0; + }, + (events: any[]) => { + events[2].testSummary.totalRunCount = 2; + }, + (events: any[]) => { + delete events[2].testSummary; + events[2].aborted = { reason: 'SKIPPED' }; + }, + (events: any[]) => { + events[0].completed.success = false; + }, + (events: any[]) => { + events.splice(0, 1); + }, + (events: any[]) => { + events.splice(1, 1); + }, + (events: any[]) => { + events[1].testResult.status = 'FAILED'; + }, + (events: any[]) => { + events.push(structuredClone(events[2])); + }, + (events: any[]) => { + events.push(structuredClone(events[1])); + }, + (events: any[]) => { + events[2].id.testSummary.configuration.id = 'other'; + }, + ]) { + const evidence = structuredClone(f.evidence); + const events = requiredTestEvents(); + change(events); + evidence.cohorts[0].buildEvents.splice(-1, 0, ...events); + expect(() => validateNativeBuildEvidence(evidence, expected)).toThrow( + /mandatory configured test|complete successful test/, + ); + } + const evidence = structuredClone(f.evidence); + evidence.cohorts[0].buildEvents.splice(-1, 0, ...requiredTestEvents()); + const duplicate = structuredClone(evidence.cohorts[0]); + (duplicate.buildEvents[0] as any).started.uuid = 'second-invocation'; + evidence.cohorts.push(duplicate); + expect(() => validateNativeBuildEvidence(evidence, expected)).toThrow( + /mandatory configured test.*found 2/, + ); + } finally { + f.cleanup(); + } +}); + +test('source and tool content changes alter input diagnostics while identical delivered bytes stay identical', () => { + const f = fixture(); + try { + const before = validateNativeBuildEvidence(f.evidence, f.expected); + for (const file of [f.source, f.tool]) { + writeFileSync(path.join(f.executionRoot, file), `changed ${file}`); + f.evidence.cohorts[0].inputs = f.evidence.cohorts[0].inputs.map((row) => + row.path === file ? f.capture(file) : row, + ); + const after = validateNativeBuildEvidence(f.evidence, f.expected); + expect(after.cohorts[0].inputContentsDigest).not.toBe(before.cohorts[0].inputContentsDigest); + expect(after.cohorts[0].roots[0].outputs).toEqual(before.cohorts[0].roots[0].outputs); + expect(after.releaseDecision).toBe('unverified'); + } + } finally { + f.cleanup(); + } +}); + +test('declaration fingerprints ignore input-set factoring while raw graph evidence and real edge changes remain bound', () => { + const f = fixture(); + try { + const before = validateNativeBuildEvidence(f.evidence, f.expected).cohorts[0]; + const graph = f.evidence.cohorts[0].aquery as any; + graph.depSetOfFiles[1] = { id: 2, transitiveDepSetIds: [1, 3] }; + graph.depSetOfFiles.push({ id: 3, directArtifactIds: [3, 2] }); + const factored = validateNativeBuildEvidence(f.evidence, f.expected).cohorts[0]; + expect(factored.actionDefinitionsDigest).toBe(before.actionDefinitionsDigest); + expect(factored.inputContentsDigest).toBe(before.inputContentsDigest); + expect(factored.aqueryDigest).not.toBe(before.aqueryDigest); + graph.depSetOfFiles[0].directArtifactIds = [2]; + graph.depSetOfFiles[2].directArtifactIds = [3, 1]; + const swapped = validateNativeBuildEvidence(f.evidence, f.expected).cohorts[0]; + expect(swapped.inputContentsDigest).toBe(before.inputContentsDigest); + expect(swapped.actionDefinitionsDigest).not.toBe(before.actionDefinitionsDigest); + graph.actions[1].arguments.push('--changed-command'); + const command = validateNativeBuildEvidence(f.evidence, f.expected).cohorts[0]; + expect(command.actionDefinitionsDigest).not.toBe(swapped.actionDefinitionsDigest); + } finally { + f.cleanup(); + } +}); + +test('input capture requires exact frontier membership and safe file trees', () => { + const f = fixture(); + try { + for (const change of [ + (value: NativeBuildEvidence) => { + value.cohorts[0].inputs.shift(); + }, + (value: NativeBuildEvidence) => { + value.cohorts[0].inputs.push({ + path: 'unconsumed.txt', + members: value.cohorts[0].inputs[0].members, + }); + }, + (value: NativeBuildEvidence) => { + value.cohorts[0].inputs[0].members[0].path = '../escape'; + }, + (value: NativeBuildEvidence) => { + (value.cohorts[0].inputs[0].members[0] as any).sha256 = 'not a hash'; + }, + (value: NativeBuildEvidence) => { + value.cohorts[0].inputs.push(value.cohorts[0].inputs[0]); + }, + ]) { + const changed = structuredClone(f.evidence); + change(changed); + expect(() => validateNativeBuildEvidence(changed, f.expected)).toThrow(); + } + const tree = structuredClone(f.evidence); + tree.cohorts[0].inputs[0].members = [ + { path: '', type: 'directory', mode: 0o755 }, + { path: 'module.mts', type: 'file', mode: 0o644, size: 3, sha256: 'd'.repeat(64) }, + ]; + expect(() => validateNativeBuildEvidence(tree, f.expected)).not.toThrow(); + tree.cohorts[0].inputs[0].members[1].path = 'missing/module.mts'; + expect(() => validateNativeBuildEvidence(tree, f.expected)).toThrow(/directory parent/); + } finally { + f.cleanup(); + } +}); + +test('failed, skipped, missing, incomplete and ambiguous configurations cannot bind an output', () => { + const f = fixture(); + try { + for (const change of [ + (events: any[]) => { + events[6].finished.exitCode = { name: 'BUILD_FAILURE', code: 1 }; + }, + (events: any[]) => { + events[5].completed.success = false; + }, + (events: any[]) => { + delete events[5].completed; + events[5].aborted = { reason: 'SKIPPED' }; + }, + (events: any[]) => { + events.splice(5, 1); + }, + (events: any[]) => { + events[5].completed.outputGroup[0].incomplete = true; + }, + (events: any[]) => { + events[4].namedSetOfFiles.fileSets = [{ id: 'missing' }]; + }, + (events: any[]) => { + events[4].namedSetOfFiles.fileSets = [{ id: 'default' }]; + }, + (events: any[]) => { + events.pop(); + }, + (events: any[]) => { + events[5].id.targetCompleted.configuration.id = 'e'.repeat(64); + }, + (events: any[]) => { + const another = structuredClone(events[5]); + another.id.targetCompleted.configuration.id = 'e'.repeat(64); + events.splice(6, 0, another); + }, + ]) { + const changed = structuredClone(f.evidence); + change(changed.cohorts[0].buildEvents); + expect(() => validateNativeBuildEvidence(changed, f.expected)).toThrow(); + } + const mixed = structuredClone(f.evidence); + const other: any = structuredClone(mixed.cohorts[0].buildEvents[5]); + other.id.targetCompleted.configuration.id = 'e'.repeat(64); + other.completed.success = false; + mixed.cohorts[0].buildEvents.splice(6, 0, other); + expect(() => validateNativeBuildEvidence(mixed, f.expected)).not.toThrow(); + } finally { + f.cleanup(); + } +}); + +test('source, producing run/attempt/job, execroot and digest substitutions fail closed', () => { + const f = fixture(); + try { + for (const change of [ + (value: NativeBuildEvidence) => { + value.source.commit = 'f'.repeat(40); + }, + (value: NativeBuildEvidence) => { + value.source.tree = 'f'.repeat(40); + }, + (value: NativeBuildEvidence) => { + value.github.runId = 123; + }, + (value: NativeBuildEvidence) => { + value.github.runAttempt = 3; + }, + (value: NativeBuildEvidence) => { + value.github.job = 'Qualified'; + }, + (value: NativeBuildEvidence) => { + value.github.workflow = 'CI'; + }, + (value: NativeBuildEvidence) => { + value.cohorts[0].executionRoot = '/tmp/another-execroot'; + }, + (value: NativeBuildEvidence) => { + (value.cohorts[0].buildEvents[3] as any).namedSetOfFiles.files[0].digest = 'f'.repeat(64); + }, + (value: NativeBuildEvidence) => { + (value.cohorts[0].buildEvents[3] as any).namedSetOfFiles.files[0].length = '999'; + }, + (value: NativeBuildEvidence) => { + (value.cohorts[0].buildEvents[0] as any).started.buildToolVersion = 'other'; + }, + (value: NativeBuildEvidence) => { + (value.github as any).authenticated = true; + }, + (value: NativeBuildEvidence) => { + (value.cohorts[0].buildEvents[7] as any).buildMetadata.metadata.oliphaunt_run_id = '123'; + }, + (value: NativeBuildEvidence) => { + (value.cohorts[0].buildEvents[7] as any).buildMetadata.metadata.oliphaunt_source_commit = + 'f'.repeat(40); + }, + ]) { + const changed = structuredClone(f.evidence); + change(changed); + expect(() => validateNativeBuildEvidence(changed, f.expected)).toThrow(); + } + } finally { + f.cleanup(); + } +}); + +test('multiple successful cohorts retain their actual distinct configuration and foreign execroot', () => { + const f = fixture(); + try { + const another = structuredClone(f.evidence.cohorts[0]); + another.executionRoot = 'C:/bazel/execroot/_main'; + (another.buildEvents[0] as any).started.uuid = 'windows-invocation'; + (another.buildEvents[1] as any).workspaceInfo.localExecRoot = another.executionRoot; + (another.buildEvents[2] as any).id.configuration.id = 'e'.repeat(64); + (another.buildEvents[2] as any).configuration = { + mnemonic: 'x64_windows-opt', + cpu: 'x64_windows', + }; + (another.buildEvents[5] as any).id.targetCompleted.configuration.id = 'e'.repeat(64); + (another.aquery as any).configuration[0].checksum = 'e'.repeat(64); + another.rootConfigurations[0].configuration = 'e'.repeat(64); + another.roots[0].package.configuration = 'windows-x64'; + f.evidence.cohorts.push(another); + const result = validateNativeBuildEvidence(f.evidence, f.expected); + expect(result.cohorts.map((cohort) => cohort.roots[0].configuration)).toEqual([ + 'c'.repeat(64), + 'e'.repeat(64), + ]); + expect(result.cohorts[1].roots[0].configurationDetails.cpu).toBe('x64_windows'); + } finally { + f.cleanup(); + } +}); + +test('BEP configuration identifiers are opaque and unrelated null/source configurations remain valid', () => { + const f = fixture(); + try { + f.evidence.cohorts[0].buildEvents.splice(3, 0, { + id: { configuration: { id: 'none' } }, + configuration: {}, + }); + expect(() => validateNativeBuildEvidence(f.evidence, f.expected)).not.toThrow(); + (f.evidence.cohorts[0].buildEvents[2] as any).id.configuration.id = + 'opaque-build-configuration'; + (f.evidence.cohorts[0].buildEvents[6] as any).id.targetCompleted.configuration.id = + 'opaque-build-configuration'; + (f.evidence.cohorts[0].aquery as any).configuration[0].checksum = 'opaque-build-configuration'; + f.evidence.cohorts[0].rootConfigurations[0].configuration = 'opaque-build-configuration'; + expect( + validateNativeBuildEvidence(f.evidence, f.expected).cohorts[0].roots[0].configuration, + ).toBe('opaque-build-configuration'); + } finally { + f.cleanup(); + } +}); + +test('cquery roots and successful BEP must match while actual producer transitions remain valid', () => { + const f = fixture(); + try { + const mismatched = structuredClone(f.evidence); + mismatched.cohorts[0].rootConfigurations[0].configuration = 'd'.repeat(64); + expect(() => validateNativeBuildEvidence(mismatched, f.expected)).toThrow( + /shipping configuration mismatch/, + ); + const missingRoot = structuredClone(f.evidence); + missingRoot.cohorts[0].rootConfigurations = []; + expect(() => validateNativeBuildEvidence(missingRoot, f.expected)).toThrow(/root coverage/); + const duplicateRoot = structuredClone(f.evidence); + duplicateRoot.cohorts[0].rootConfigurations.push( + duplicateRoot.cohorts[0].rootConfigurations[0], + ); + expect(() => validateNativeBuildEvidence(duplicateRoot, f.expected)).toThrow(/duplicate.*root/); + const missing = structuredClone(f.evidence); + (missing.cohorts[0].aquery as any).configuration = []; + (missing.cohorts[0].aquery as any).actions[0].configurationId = 999; + expect(() => validateNativeBuildEvidence(missing, f.expected)).toThrow( + /configuration is missing/, + ); + const transitioned = structuredClone(f.evidence); + (transitioned.cohorts[0].aquery as any).configuration.push({ + id: 2, + checksum: 'e'.repeat(64), + isTool: true, + }); + (transitioned.cohorts[0].aquery as any).actions[0].configurationId = 2; + expect(() => validateNativeBuildEvidence(transitioned, f.expected)).not.toThrow(); + // A ShippingInfo wrapper need not own actions; its configured producers may transition. + (transitioned.cohorts[0].aquery as any).actions[1].configurationId = 2; + (transitioned.cohorts[0].aquery as any).configuration.shift(); + expect(() => validateNativeBuildEvidence(transitioned, f.expected)).not.toThrow(); + } finally { + f.cleanup(); + } +}); + +test('canonical main-repository roots bind BEP labels while external repositories remain distinct', () => { + const f = fixture(); + try { + const cohort = f.evidence.cohorts[0]; + cohort.roots[0].label = '@@//package:ship'; + cohort.rootConfigurations[0].label = '@@//package:ship'; + cohort.roots[0].package.outputs[0].owner = '@@//package:archive'; + expect(validateNativeBuildEvidence(f.evidence, f.expected).cohorts[0].roots[0].label).toBe( + '@@//package:ship', + ); + cohort.roots[0].label = '@@foreign//package:ship'; + cohort.rootConfigurations[0].label = '@@foreign//package:ship'; + expect(() => validateNativeBuildEvidence(f.evidence, f.expected)).toThrow( + /one successful configured shipping root/, + ); + } finally { + f.cleanup(); + } +}); + +test('native transport authenticates the same immutable buffer and configured tests without granting publication', async () => { + const f = fixture(); + const environment = { + PATH: `${path.dirname(process.execPath)}${path.delimiter}${process.env.PATH}`, + BUN_OPTIONS: `--preload=${path.resolve(import.meta.dir, 'testdata/download-build-artifacts-github.mts')}`, + GH_TOKEN: 'test-token', + GH_REPO: 'ignored/by-adapter', + OLIPHAUNT_GITHUB_READ_DEADLINE_MS: '1000', + OLIPHAUNT_GITHUB_READ_MAX_ATTEMPTS: '1', + OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS: '0', + OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS: '0', + FAKE_NATIVE_ORIGIN: 'true', + FAKE_NATIVE_CASE: '', + FAKE_NATIVE_SOURCE_COMMIT: '', + FAKE_NATIVE_SOURCE_TREE: '', + FAKE_NATIVE_MUTATE_LOCAL_PACKET: '', + FAKE_ARTIFACT_ARCHIVE: path.join(f.executionRoot, 'artifact.zip'), + FAKE_GH_LOG: path.join(f.executionRoot, 'api.log'), + FAKE_GH_STATE: path.join(f.executionRoot, 'download-count'), + FAKE_MODE: 'success', + FAKE_RUN_CONCLUSION: 'failure', + }; + const before = Object.fromEntries(Object.keys(environment).map((key) => [key, process.env[key]])); + try { + const runGit = (...args: string[]) => + execFileSync('git', args, { cwd: f.executionRoot, encoding: 'utf8' }).trim(); + runGit('init', '--quiet'); + runGit( + '-c', + 'user.name=Fixture', + '-c', + 'user.email=fixture@example.invalid', + 'commit', + '--quiet', + '--allow-empty', + '-m', + 'fixture', + ); + const commit = runGit('rev-parse', 'HEAD'); + const tree = runGit('rev-parse', 'HEAD^{tree}'); + f.evidence.source = { commit, tree }; + f.evidence.github = { ...f.evidence.github, runId: 77, runAttempt: 1 }; + (f.evidence.cohorts[0].buildEvents[7] as any).buildMetadata.metadata = nativeBuildMetadata( + f.evidence.source, + f.evidence.github, + ); + f.evidence.cohorts[0].buildEvents.splice(-1, 0, ...requiredTestEvents()); + const evidenceRoot = path.join(f.executionRoot, 'evidence'); + mkdirSync(evidenceRoot); + const packet = path.join(evidenceRoot, 'native-build-evidence.json'); + writeFileSync(packet, `${JSON.stringify(f.evidence)}\n`); + const packetBytes = readFileSync(packet); + execFileSync('zip', ['-q', environment.FAKE_ARTIFACT_ARCHIVE, 'native-build-evidence.json'], { + cwd: evidenceRoot, + }); + // Expectations constrain the real HTTP/ZIP acquisition. Synthetic transport + // exercises the boundary; it is not a live authenticated builder result. + const context = { + source: f.evidence.source, + github: f.evidence.github, + event: 'workflow_dispatch' as const, + ref: 'refs/heads/main', + artifactName: 'native-build-evidence-x86_64', + }; + const requiredTests = [{ label: '//package:consumer_test', configuration: 'c'.repeat(64) }]; + Object.assign(process.env, environment, { + FAKE_NATIVE_SOURCE_COMMIT: commit, + FAKE_NATIVE_SOURCE_TREE: tree, + FAKE_NATIVE_MUTATE_LOCAL_PACKET: packet, + }); + const origin = await authenticateNativeBuildEvidence(evidenceRoot, context); + expect(JSON.parse(readFileSync(packet, 'utf8'))).toEqual({ + changedAfterAuthenticatedRead: true, + }); + expect(origin.evidenceDigest).toBe( + `sha256:${createHash('sha256').update(packetBytes).digest('hex')}`, + ); + expect(origin.evidence).toEqual(JSON.parse(packetBytes.toString('utf8'))); + expect(origin.github).toEqual(context.github); + expect(origin.artifact.id).toBe(101); + expect(origin.artifact.name).toBe(context.artifactName); + expect(assertAuthenticatedNativeBuildOrigin(origin)).toBe(origin); + expect(Object.isFrozen(origin)).toBe(true); + expect(Object.isFrozen(origin.evidence)).toBe(true); + expect(Object.isFrozen((origin.evidence as NativeBuildEvidence).cohorts[0].buildEvents)).toBe( + true, + ); + expect(() => { + (origin.evidence as NativeBuildEvidence).source.commit = 'f'.repeat(40); + }).toThrow(); + for (const detached of [ + structuredClone(origin), + JSON.parse(JSON.stringify(origin)), + { github: context.github, artifact: origin.artifact }, + ]) + expect(() => assertAuthenticatedNativeBuildOrigin(detached)).toThrow( + /authenticated producer transport/, + ); + + const expected = { + source: context.source, + github: context.github, + bazelVersion: f.expected.bazelVersion, + requiredTests, + }; + const qualified = validateNativeBuildEvidence(origin.evidence, expected); + expect(qualified.scope).toBe('construction'); + expect(qualified.releaseDecision).toBe('unverified'); + expect(qualified.testQualification).toBe('passed'); + expect(qualified.requiredTests).toEqual([ + { ...requiredTests[0], invocationId: 'actual-invocation' }, + ]); + // Content validation stays diagnostic without declared tests, even when its + // immutable bytes came from an authenticated artifact. It grants no release. + const diagnostic = validateNativeBuildEvidence(origin.evidence, { + ...expected, + requiredTests: undefined, + }); + expect(diagnostic.testQualification).toBe('unverified'); + expect(diagnostic.releaseDecision).toBe('unverified'); + expect(diagnostic.unverified).toContain( + 'declared mandatory test roots and successful BEP results', + ); + for (const tests of [[], [{ ...requiredTests[0], configuration: 'd'.repeat(64) }]]) + expect(() => + validateNativeBuildEvidence(origin.evidence, { ...expected, requiredTests: tests }), + ).toThrow(); + expect(qualified.unverified).toContain( + 'complete canonical product qualification and completed-baseline admission', + ); + expect(Object.hasOwn(origin, 'releaseDecision')).toBe(false); + expect(Object.hasOwn(origin, 'baselineAdmission')).toBe(false); + writeFileSync(packet, packetBytes); + delete process.env.FAKE_NATIVE_MUTATE_LOCAL_PACKET; + + const again = await authenticateNativeBuildEvidence(evidenceRoot, context); + expect(again.evidenceDigest).toBe(origin.evidenceDigest); + expect(validateNativeBuildEvidence(again.evidence, expected)).toEqual(qualified); + for (const changed of [ + { ...context, source: { ...context.source, commit: 'f'.repeat(40) } }, + { ...context, source: { ...context.source, tree: 'f'.repeat(40) } }, + { ...context, github: { ...context.github, runId: 78 } }, + { ...context, github: { ...context.github, runAttempt: 2 } }, + { ...context, github: { ...context.github, job: 'Other producer' } }, + { ...context, artifactName: 'other-artifact' }, + ]) + await expect(authenticateNativeBuildEvidence(evidenceRoot, changed)).rejects.toThrow(); + for (const kind of ['job-failure', 'stale-artifact', 'digest']) { + process.env.FAKE_NATIVE_CASE = kind; + await expect(authenticateNativeBuildEvidence(evidenceRoot, context)).rejects.toThrow(); + } + process.env.FAKE_NATIVE_CASE = ''; + writeFileSync(packet, '{"tampered":true}'); + await expect(authenticateNativeBuildEvidence(evidenceRoot, context)).rejects.toThrow( + /bytes differ/, + ); + // An already acquired buffer is immutable and independent of later path mutation. + expect(assertAuthenticatedNativeBuildOrigin(origin)).toBe(origin); + expect(validateNativeBuildEvidence(origin.evidence, expected)).toEqual(qualified); + } finally { + for (const key of Object.keys(environment)) { + if (before[key] === undefined) delete process.env[key]; + else process.env[key] = before[key]; + } + f.cleanup(); + } +}); + +test('exact frontier rejects extra intermediate captures and requires every leaf and consumed supplier', () => { + const f = fixture(); + try { + const before = validateNativeBuildEvidence(f.evidence, f.expected); + const extra = structuredClone(f.evidence); + extra.cohorts[0].inputs.push(f.capture(f.generated)); + expect(() => validateNativeBuildEvidence(extra, f.expected)).toThrow( + 'native input content coverage', + ); + rmSync(path.join(f.executionRoot, f.generated)); + const current = validateNativeBuildEvidence(f.evidence, f.expected); + expect(current.cohorts[0].actionDefinitionsDigest).toBe( + before.cohorts[0].actionDefinitionsDigest, + ); + expect(current.cohorts[0].inputContentsDigest).toBe(before.cohorts[0].inputContentsDigest); + for (const file of [f.source, f.tool]) { + const missing = structuredClone(f.evidence); + missing.cohorts[0].inputs = missing.cohorts[0].inputs.filter((input) => input.path !== file); + expect(() => validateNativeBuildEvidence(missing, f.expected)).toThrow( + 'native input content coverage', + ); + } + const supplied = structuredClone(f.evidence); + (supplied.cohorts[0].roots[0].package as any).supplierInputs = [ + { + product: 'supplier', + version: '1.0.0', + configuration: 'linux-x64', + binding: 'abi-contract', + origin: { kind: 'current-source' }, + files: [{ path: f.generated }], + }, + ]; + expect(() => validateNativeBuildEvidence(supplied, f.expected)).toThrow( + 'native input content coverage', + ); + writeFileSync(path.join(f.executionRoot, f.generated), 'actual declared supplier File'); + supplied.cohorts[0].inputs.push(f.capture(f.generated)); + expect(validateNativeBuildEvidence(supplied, f.expected).scope).toBe('construction'); + const unrelated = structuredClone(f.evidence); + unrelated.cohorts[0].inputs.push({ + path: 'unrelated', + members: unrelated.cohorts[0].inputs[0].members, + }); + expect(() => validateNativeBuildEvidence(unrelated, f.expected)).toThrow( + 'native input content coverage', + ); + } finally { + f.cleanup(); + } +}); + +test('configured qualification follows TestRunner producer edges and rejects missing or cyclic closure', () => { + const f = fixture(); + try { + const graph = f.evidence.cohorts[0].aquery as any; + graph.actions[1].mnemonic = 'TestRunner'; + const observed = configuredAqueryTargetInputs(graph, '//package:archive', 'c'.repeat(64)); + expect([...observed.inputs].sort()).toEqual([f.source, f.tool, f.generated].sort()); + expect(() => configuredAqueryTargetInputs(graph, '//package:archive', 'd'.repeat(64))).toThrow( + /configured TestRunner/, + ); + expect(() => + configuredAqueryTargetInputs(graph, '//package:generated', 'c'.repeat(64)), + ).toThrow(/configured TestRunner/); + const conflicting = structuredClone(graph); + conflicting.actions.push({ ...conflicting.actions[0], actionKey: 'other-producer' }); + expect(() => createConfiguredAqueryTargetInputResolver(conflicting)).toThrow( + /conflicting aquery producers/, + ); + const missing = structuredClone(graph); + missing.depSetOfFiles[1].directArtifactIds.push(999); + const resolveMissing = createConfiguredAqueryTargetInputResolver(missing); + for (let attempt = 0; attempt < 2; attempt++) + expect(() => resolveMissing('//package:archive', 'c'.repeat(64))).toThrow( + /incomplete aquery graph/, + ); + graph.actions[0].mnemonic = 'Middleman'; + graph.depSetOfFiles[0].directArtifactIds.push(3); + const resolveCyclic = createConfiguredAqueryTargetInputResolver(graph); + for (let attempt = 0; attempt < 2; attempt++) + expect(() => resolveCyclic('//package:archive', 'c'.repeat(64))).toThrow(/cycle/); + } finally { + f.cleanup(); + } +}); + +test('one qualification graph keeps configured test inputs and specifications independent', () => { + const files = ['first.spec', 'second.spec', 'derived.spec', 'payload', 'runfiles'].map( + (name) => `bazel-out/${name}`, + ); + const graph = { + pathFragments: [ + { id: 'root', label: 'bazel-out' }, + ...files.map((file, id) => ({ id, label: file.split('/')[1], parentId: 'root' })), + ], + artifacts: files.map((_, id) => ({ id, pathFragmentId: id })), + targets: [ + { id: 1, label: '@@//package:first' }, + { id: 2, label: '//package:second' }, + ], + configuration: [ + { id: 1, checksum: 'first' }, + { id: 2, checksum: 'second' }, + ], + depSetOfFiles: [ + { id: 1, directArtifactIds: [0, 2, 4] }, + { id: 2, directArtifactIds: [1, 4] }, + { id: 3, directArtifactIds: [0, 4] }, + { id: 4, directArtifactIds: [3] }, + ], + actions: [ + { targetId: 1, configurationId: 1, mnemonic: 'FileWrite', outputIds: [0] }, + { targetId: 1, configurationId: 2, mnemonic: 'FileWrite', outputIds: [1] }, + { + targetId: 1, + configurationId: 1, + mnemonic: 'FileWrite', + inputDepSetIds: [4], + outputIds: [2], + }, + { + targetId: 2, + configurationId: 1, + mnemonic: 'Middleman', + inputDepSetIds: [4], + outputIds: [4], + }, + { targetId: 1, configurationId: 1, mnemonic: 'TestRunner', inputDepSetIds: [1] }, + { targetId: 1, configurationId: 2, mnemonic: 'TestRunner', inputDepSetIds: [2] }, + { targetId: 2, configurationId: 1, mnemonic: 'TestRunner', inputDepSetIds: [3] }, + ], + }; + const resolve = createConfiguredAqueryTargetInputResolver(graph); + const first = resolve('//package:first', 'first'); + expect(first.inputs).toEqual(new Set([files[0], files[2], files[4], files[3]])); + expect(first.written).toEqual(new Set([files[0]])); + const second = resolve('@//package:first', 'second'); + expect(second.inputs).toEqual(new Set([files[1], files[4], files[3]])); + expect(second.written).toEqual(new Set([files[1]])); + const sibling = resolve('//package:second', 'first'); + expect(sibling.inputs).toEqual(new Set([files[0], files[4], files[3]])); + expect(sibling.written.size).toBe(0); + expect(() => resolve('//package:second', 'second')).toThrow(/configured TestRunner/); + first.inputs.clear(); + first.written.clear(); + expect(resolve('//package:first', 'first')).toEqual( + configuredAqueryTargetInputs(graph, '//package:first', 'first'), + ); + + const requiredTests = ['first', 'second'].map((configuration) => ({ + label: '//package:first', + configuration, + })); + const completed = requiredTests.map((test, index) => ({ + ...test, + value: { + success: true, + outputGroup: [{ name: 'observation_inputs' }], + files: new Map([files[index], files[3], files[4]].map((file) => [file, {}])), + }, + })); + const bep = { completed, filesOf: (target: any) => target.files } as any; + const policy = { requiredTests } as any; + expect( + nativeQualificationInputBindings(graph, bep, policy).map((row) => row.specification), + ).toEqual(files.slice(0, 2)); + completed[1].value.files = new Map([files[0], files[3], files[4]].map((file) => [file, {}])); + expect(() => nativeQualificationInputBindings(graph, bep, policy)).toThrow(/not consumed/); + for (const target of completed) target.value.outputGroup = []; + expect(nativeQualificationInputBindings(null, bep, policy)).toEqual([]); +}); + +test('batched graph digests preserve canonical JSON bytes across boundaries and seeded values', () => { + const canonical = (value: unknown): string => { + if (Array.isArray(value)) return `[${value.map(canonical).join(',')}]`; + if (value !== null && typeof value === 'object') + return `{${Object.keys(value) + .sort() + .map( + (key) => `${JSON.stringify(key)}:${canonical((value as Record)[key])}`, + ) + .join(',')}}`; + return JSON.stringify(value); + }; + const f = fixture(); + try { + const graph = f.evidence.cohorts[0].aquery as Record; + const values: unknown[] = [ + {}, + [], + null, + true, + false, + 0, + -0, + 1e30, + -1e-30, + { '2': 'two', '10': 'ten' }, + { empty: '', escaped: 'quote" slash\\ line\n tab\t', unicode: 'é中文�\ud800\udfff' }, + { z: [], a: {}, b: [null, { beta: false, alpha: true }] }, + 'é中文�'.repeat(16_000), + Array.from({ length: 32_768 }, (_, i) => i), + ]; + let state = 0x9e3779b9; + const random = (bound: number) => { + state ^= state << 13; + state ^= state >>> 17; + state ^= state << 5; + return (state >>> 0) % bound; + }; + const generated = (depth: number): unknown => { + const leaves: unknown[] = [null, true, false, '', 'é\n�\ud800', random(10_000) - 5000]; + if (!depth || random(3) === 0) return leaves[random(leaves.length)]; + if (random(2) === 0) return Array.from({ length: random(6) }, () => generated(depth - 1)); + return Object.fromEntries( + Array.from({ length: random(6) }, (_, i) => [ + `key-${random(100)}-${i}`, + generated(depth - 1), + ]), + ); + }; + for (let i = 0; i < 128; i++) values.push(generated(4)); + for (const value of values) { + graph.digestFixture = value; + const expected = `sha256:${createHash('sha256').update(canonical(graph)).digest('hex')}`; + expect(validateNativeBuildEvidence(f.evidence, f.expected).cohorts[0].aqueryDigest).toBe( + expected, + ); + } + delete graph.digestFixture; + const expected = `sha256:${createHash('sha256').update(canonical(graph)).digest('hex')}`; + expect(validateNativeBuildEvidence(f.evidence, f.expected).cohorts[0].aqueryDigest).toBe( + expected, + ); + } finally { + f.cleanup(); + } +}); diff --git a/tools/release/native-build-source-tag.mts b/tools/release/native-build-source-tag.mts new file mode 100644 index 000000000..c032952a2 --- /dev/null +++ b/tools/release/native-build-source-tag.mts @@ -0,0 +1,127 @@ +/** Bind the declared Swift source-tag inputs; this is transport, never source admission. */ +import { deepStrictEqual } from 'node:assert'; +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import { assertSwiftSourceDeliveryParity } from '../../build_defs/languages/swift/source-delivery-contract.mts'; +import { + IOS_CARRIER_FILENAME, + validateFrozenNativeCarrierIdentity, +} from '../../src/native/sdks/swift/tools/swift-native-carrier-contract.mts'; +import { renderSwiftReleaseManifest } from '../../src/native/sdks/swift/tools/swift-release-manifest.mts'; +import type { NativeBuildEvidence } from './native-build-qualification.mts'; +import { expectedProductArtifactRows } from './publication-lock.mts'; + +/** Only the canonical source publisher's complete declared inventory admits a tree. */ +export function nativeSwiftSourceTagRoots(cohort: NativeBuildEvidence['cohorts'][number]) { + const roots = cohort.roots.filter( + ({ package: pkg }) => pkg.product === 'oliphaunt-swift' && pkg.ecosystem === 'github', + ); + if (!roots.some(({ package: pkg }) => pkg.role === 'release-input')) return []; + const version = roots[0].package.version; + const rows = expectedProductArtifactRows([{ id: 'oliphaunt-swift', kind: 'sdk', version }]); + deepStrictEqual( + roots.map(({ package: pkg }) => pkg.name).sort(), + rows.map(({ name }) => name).sort(), + 'Swift source-tag transport requires its complete canonical input and asset inventory', + ); + for (const root of roots) { + const pkg = root.package; + const row = rows.find(({ name }) => name === pkg.name); + if ( + !row || + pkg.version !== version || + pkg.role !== row.role || + pkg.configuration !== row.target || + pkg.outputs.length !== 1 + ) + throw new Error('Swift source-tag root identity or configuration differs from its contract'); + } + const tree = roots.find(({ package: pkg }) => pkg.name === 'release-tree').package.outputs[0]; + const carrier = roots.find(({ package: pkg }) => pkg.name === IOS_CARRIER_FILENAME).package + .outputs[0]; + deepStrictEqual(carrier, tree, 'Swift carrier must belong to the declared source-tag tree'); + for (const root of roots) { + const output = root.package.outputs[0].path; + const expectedName = + root.package.name === IOS_CARRIER_FILENAME ? 'release-tree' : root.package.name; + if (path.posix.basename(output) !== expectedName) + throw new Error('Swift source-tag output does not have its canonical filename'); + const captured = cohort.outputs.find(({ path: name }) => name === output); + if (!captured || captured.members[0].type !== (output === tree.path ? 'directory' : 'file')) + throw new Error('Swift source-tag output has the wrong physical file type'); + if (captured.members.some(({ path: name }) => name.split('/').includes('.git'))) + throw new Error('Swift source-tag tree cannot contain Git internals'); + } + return roots; +} + +/** The existing Swift source publisher writes Git100644; Bazel materialization modes are evidence only. */ +export function nativeSwiftSourceTagPublication(cohort: NativeBuildEvidence['cohorts'][number]) { + const tree = nativeSwiftSourceTagRoots(cohort).find( + ({ package: pkg }) => pkg.name === 'release-tree', + )?.package.outputs[0].path; + if (tree === undefined) return cohort; + return { + ...cohort, + outputs: cohort.outputs.map((output) => + output.path === tree + ? { + ...output, + members: output.members.map((member) => ({ + ...member, + mode: member.type === 'file' ? 0o644 : 0o755, + })), + } + : output, + ), + }; +} + +/** Current and held legal/source admission stays in the existing source-basis contract. */ +export function validateNativeSwiftSourceTagFiles( + evidence: NativeBuildEvidence, + resolve: (cohort: number, output: string) => string, +) { + for (const [index, captured] of evidence.cohorts.entries()) { + const cohort = nativeSwiftSourceTagPublication(captured); + const roots = nativeSwiftSourceTagRoots(cohort); + if (!roots.length) continue; + const output = (name: string) => + roots.find(({ package: pkg }) => pkg.name === name).package.outputs[0].path; + const tree = output('release-tree'); + const file = (member: string) => resolve(index, `${tree}/${member}`); + const text = (name: string) => + new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(readFileSync(name)); + const version = roots[0].package.version; + if (text(file('src/sdks/swift/VERSION')).trim() !== version) + throw new Error('Swift source-tag VERSION differs from its qualified owner version'); + const carrier = validateFrozenNativeCarrierIdentity({ + carrier: JSON.parse(text(file(`src/sdks/swift/Carriers/${IOS_CARRIER_FILENAME}`))), + expectedNativeVersion: text(file('src/sdks/swift/LIBOLIPHAUNT_VERSION')).trim(), + label: 'native Swift source-tag transport', + }); + const asset = carrier.base.assets.find(({ role }) => role === 'base-xcframework'); + const bindingsName = `oliphaunt-swift-${version}-bindings.xcframework.zip`; + const bindingsPath = output(bindingsName); + const bindings = cohort.outputs.find(({ path: name }) => name === bindingsPath).members[0]; + if (bindings.type !== 'file') throw new Error('Swift bindings archive must be a regular file'); + const canonical = renderSwiftReleaseManifest( + asset.url.slice(0, asset.url.lastIndexOf('/')), + carrier.base.version, + asset.sha256, + `https://github.com/f0rr0/oliphaunt/releases/download/oliphaunt-swift-v${version}/${bindingsName}`, + bindings.sha256, + ); + for (const manifest of [file('Package.swift'), resolve(index, output('Package.swift.release'))]) + if (!readFileSync(manifest).equals(Buffer.from(canonical))) + throw new Error( + 'Swift source-tag manifest differs from its qualified version and supplier contracts', + ); + for (const required of ['LICENSE', 'THIRD_PARTY_NOTICES.md']) readFileSync(file(required)); + assertSwiftSourceDeliveryParity( + resolve(index, output('Oliphaunt-source.zip')), + cohort.outputs.find(({ path: name }) => name === tree).members, + Buffer.from(canonical), + ); + } +} diff --git a/tools/release/native-build-source-tag.test.mts b/tools/release/native-build-source-tag.test.mts new file mode 100644 index 000000000..1648d9f40 --- /dev/null +++ b/tools/release/native-build-source-tag.test.mts @@ -0,0 +1,477 @@ +import { expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + copyFileSync, + existsSync, + mkdirSync, + readFileSync, + rmSync, + statSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { fixture as swiftInputs } from '../../build_defs/languages/swift/source-package.fixture.mts'; +import { packageSwiftSource } from '../../build_defs/languages/swift/source-package.mts'; +import { createDeterministicZip } from '../packaging/archive-directory.mts'; +import { extractPortableArchiveTree } from '../packaging/portable-archive.mts'; +import { + captureNativeBuildEvidence, + writeNativeBuildEvidence, +} from './capture-native-build-evidence.mts'; +import { fixture } from './completed-native-publication.fixture.mts'; +import { readNativeBuildFinalFiles } from './native-build-files.mts'; +import { nativeBuildMetadata } from './native-build-qualification.mts'; +import { + nativeSwiftSourceTagRoots, + validateNativeSwiftSourceTagFiles, +} from './native-build-source-tag.mts'; +import { + captureNativeInputMembers, + captureNativeOutputMembers, +} from './native-publication-staging.mts'; +import { expectedProductArtifactRows } from './publication-lock.mts'; +import { ROOT } from './release-graph.mts'; + +/** Real package writer and capture boundary; fixture BEP is never claimed to authenticate a build. */ +async function sourceFixture(f, rawExecutable = false) { + const inputs = path.join(f.directory, 'swift-inputs'); + mkdirSync(inputs); + const spec = await swiftInputs(inputs); + const executionRoot = f.origin.evidence.cohorts[0].executionRoot; + const prefix = 'bazel-out/darwin_arm64-opt/bin/src/native/sdks/swift'; + const source = `${prefix}/source_package`; + await packageSwiftSource(path.join(executionRoot, source), spec); + const assets = `${prefix}/release-assets`; + mkdirSync(path.join(executionRoot, assets)); + const bindings = path.basename(spec.bindingsArchive); + copyFileSync(spec.bindingsArchive, path.join(executionRoot, assets, bindings)); + const checksum = `oliphaunt-swift-${spec.version}-release-assets.sha256`; + writeFileSync( + path.join(executionRoot, assets, checksum), + `${createHash('sha256').update(readFileSync(spec.bindingsArchive)).digest('hex')} ./${bindings}\n`, + ); + const executable = `${source}/release-tree/src/sdks/swift/Templates/launch.sh`; + if (rawExecutable) { + // Physical executable evidence remains exact; this source publisher still declares Git100644. + writeFileSync(path.join(executionRoot, executable), '#!/bin/sh\nexit 0\n', { mode: 0o755 }); + const archive = path.join(executionRoot, source, 'Oliphaunt-source.zip'); + const portable = path.join(f.directory, 'package'); + extractPortableArchiveTree(archive, portable, 'package'); + writeFileSync(path.join(portable, 'Templates/launch.sh'), '#!/bin/sh\nexit 0\n', { + mode: 0o644, + }); + writeFileSync(archive, await createDeterministicZip(portable, { keepParent: true })); + } + const rows = expectedProductArtifactRows([ + { id: 'oliphaunt-swift', kind: 'sdk', version: spec.version }, + ]); + const roots = rows.map((row, index) => { + const output = + row.role === 'github-release-asset' + ? `${assets}/${row.name}` + : row.name === 'release-tree' || row.name === 'oliphaunt-react-native-ios-carriers.json' + ? `${source}/release-tree` + : `${source}/${row.name.endsWith('.mjs') || row.name === 'extension-owner-catalog.json' ? 'extension-generator/' : ''}${row.name}`; + return { + label: `//src/native/sdks/swift:shipping_${index}`, + package: { + product: row.product, + version: row.version, + ecosystem: 'github', + name: row.name, + configuration: row.target, + role: row.role, + outputs: [{ path: output, owner: '//src/native/sdks/swift:source_package' }], + }, + }; + }); + const outputs = [ + ...new Set(roots.flatMap(({ package: pkg }) => pkg.outputs.map(({ path }) => path))), + ]; + const configuration = 'd'.repeat(64); + const aquery = { + pathFragments: outputs.flatMap((file, index) => + file.split('/').map((label, part) => ({ + id: `${index}-${part}`, + label, + ...(part ? { parentId: `${index}-${part - 1}` } : {}), + })), + ), + artifacts: outputs.map((file, index) => ({ + id: index + 1, + pathFragmentId: `${index}-${file.split('/').length - 1}`, + })), + targets: [{ id: 1, label: '//src/native/sdks/swift:source_package' }], + configuration: [{ id: 1, checksum: configuration }], + depSetOfFiles: [], + actions: [ + { + targetId: 1, + configurationId: 1, + actionKey: 'fixture-source-envelope', + mnemonic: 'SourceEnvelope', + inputDepSetIds: [], + outputIds: outputs.map((_, index) => index + 1), + primaryOutputId: 1, + }, + ], + }; + const sourceIdentity = f.origin.evidence.source; + const github = f.origin.evidence.github; + const buildEvents = [ + { + id: { started: {} }, + started: { uuid: 'fixture-source-envelope', buildToolVersion: '8.8.1' }, + }, + { id: { workspace: {} }, workspaceInfo: { localExecRoot: executionRoot } }, + { + id: { configuration: { id: configuration } }, + configuration: { mnemonic: 'darwin_arm64-opt' }, + }, + ...roots.flatMap((root, index) => { + const output = root.package.outputs[0].path; + const members = captureNativeOutputMembers(executionRoot, output).members; + return [ + { + id: { namedSet: { id: String(index) } }, + namedSetOfFiles: { + files: members + .filter((member) => member.type === 'file') + .map((member: any) => ({ + name: member.path ? `${output}/${member.path}` : output, + digest: member.sha256, + length: String(member.size), + })), + }, + }, + { + id: { targetCompleted: { label: root.label, configuration: { id: configuration } } }, + completed: { + success: true, + outputGroup: [{ name: 'default', fileSets: [{ id: String(index) }] }], + }, + }, + ]; + }), + { + id: { buildMetadata: {} }, + buildMetadata: { metadata: nativeBuildMetadata(sourceIdentity, github) }, + }, + { id: { buildFinished: {} }, finished: { exitCode: { name: 'SUCCESS' } } }, + { id: { buildMetrics: {} }, buildMetrics: {}, lastMessage: true }, + ]; + const cquery = { + results: roots.map(({ label }) => ({ target: { rule: { name: label } }, configurationId: 17 })), + configurations: [{ id: 17, checksum: configuration }], + }; + const capture = () => { + const observedEvents = structuredClone(buildEvents); + for (const [index, root] of roots.entries()) { + const output = root.package.outputs[0].path; + observedEvents.find(({ id }) => id.namedSet?.id === String(index)).namedSetOfFiles.files = + captureNativeOutputMembers(executionRoot, output) + .members.filter((member) => member.type === 'file') + .map((member: any) => ({ + name: member.path ? `${output}/${member.path}` : output, + digest: member.sha256, + length: String(member.size), + })); + } + return captureNativeBuildEvidence({ + source: sourceIdentity, + github, + bazelVersion: '8.8.1', + cohorts: [{ executionRoot, roots, cquery, aquery, buildEvents: observedEvents }], + }); + }; + return { + spec, + capture, + executionRoot, + source, + executable, + expected: { source: sourceIdentity, github, bazelVersion: '8.8.1' }, + }; +} + +test('complete Swift source tag transfers once with exact raw modes and canonical publication modes', async () => { + await fixture(async (f) => { + const s = await sourceFixture(f, true); + const captured = s.capture(); + const directory = path.join(f.directory, 'source-packet'); + const evidence = JSON.parse( + readFileSync(writeNativeBuildEvidence(captured, directory), 'utf8'), + ); + const packet = readNativeBuildFinalFiles(directory, evidence, s.expected); + expect(packet.scope).toBe('construction'); + expect(packet.unsupported).toEqual([]); + const tree = evidence.cohorts[0].outputs.find( + ({ path }) => path === `${s.source}/release-tree`, + ); + const treeFiles = tree.members.filter(({ type }) => type === 'file'); + expect( + packet.files.filter(({ path: name }) => name.startsWith(`${s.source}/release-tree/`)), + ).toHaveLength(treeFiles.length); + for (const file of packet.artifactRoots) chmodSync(file, 0o644); + const normalized = readNativeBuildFinalFiles(directory, evidence, s.expected); + const stageDirectory = path + .relative(ROOT, path.join(f.directory, 'source-stage')) + .split(path.sep) + .join('/'); + const staged = normalized.stage({ stageDirectory }); + expect(normalized.stage({ stageDirectory })).toEqual(staged); + // A later mutation of the caller's JSON cannot relabel the captured staging identity. + evidence.source.commit = 'f'.repeat(40); + evidence.github.runAttempt += 1; + evidence.cohorts[0].rootConfigurations[0].configuration = 'f'.repeat(64); + expect(normalized.stage({ stageDirectory })).toEqual(staged); + const stagedTree = staged.find((name) => path.basename(name) === 'release-tree'); + const observed = captureNativeOutputMembers( + path.join(directory, 'files/0'), + `${s.source}/release-tree`, + ).members; + expect(observed.find(({ path }) => path.endsWith('launch.sh')).mode).toBe(0o644); + const stagingRoot = path.resolve(ROOT, stageDirectory); + const relativeTree = path.relative(stagingRoot, stagedTree).split(path.sep).join('/'); + expect(tree.members.find(({ path }) => path.endsWith('launch.sh')).mode).toBe(0o755); + expect(captureNativeInputMembers(stagingRoot, relativeTree).members).toEqual( + tree.members.map((member) => ({ ...member, mode: member.type === 'file' ? 0o644 : 0o755 })), + ); + for (const member of treeFiles) { + expect(readFileSync(path.join(stagedTree, member.path))).toEqual( + readFileSync(path.join(s.executionRoot, tree.path, member.path)), + ); + } + expect(readFileSync(path.join(stagedTree, 'Package.swift'))).toEqual( + readFileSync(staged.find((name) => path.basename(name) === 'Package.swift.release')), + ); + expect( + readFileSync(path.join(stagedTree, 'src/sdks/swift/LIBOLIPHAUNT_VERSION'), 'utf8').trim(), + ).toBe(s.spec.nativeVersion); + expect(packet).not.toHaveProperty('releaseDecision'); + const assetsOnly = normalized.stage({ + excludeRoles: ['release-input'], + stageDirectory: `${stageDirectory}-assets`, + }); + expect(assetsOnly).toHaveLength(2); + expect(assetsOnly.some((file) => path.basename(file) === 'release-tree')).toBe(false); + const inputsOnly = normalized.stage({ + excludeRoles: ['github-release-asset', 'github-release-metadata'], + stageDirectory: `${stageDirectory}-inputs`, + }); + const inputTree = inputsOnly.find((file) => path.basename(file) === 'release-tree'); + expect(inputTree).toBeDefined(); + expect( + inputsOnly.some((file) => + assetsOnly.some((asset) => path.basename(asset) === path.basename(file)), + ), + ).toBe(false); + expect(statSync(path.join(inputTree, 'src/sdks/swift/Templates/launch.sh')).mode & 0o777).toBe( + 0o644, + ); + expect(readFileSync(path.join(inputTree, 'Package.swift'))).toEqual( + readFileSync(path.join(stagedTree, 'Package.swift')), + ); + expect(tree.members.find(({ path }) => path.endsWith('launch.sh')).mode).toBe(0o755); + }); +}); + +for (const fault of ['removed', 'extra', 'changed', 'mode']) + test(`source ZIP qualification rejects a genuinely captured ${fault} source-tag representation`, async () => { + await fixture(async (f) => { + const s = await sourceFixture(f); + const source = path.join( + s.executionRoot, + s.source, + 'release-tree/src/sdks/swift/Sources/Oliphaunt/Oliphaunt.swift', + ); + if (fault === 'removed') rmSync(source); + if (fault === 'changed') writeFileSync(source, '// changed source tag only\n'); + if (fault === 'extra') + writeFileSync(path.join(path.dirname(source), 'extra.swift'), '// extra source tag only\n'); + if (fault === 'mode') { + const archive = path.join(s.executionRoot, s.source, 'Oliphaunt-source.zip'); + const packaged = path.join(f.directory, 'executable-source-zip', 'package'); + extractPortableArchiveTree(archive, packaged, 'package'); + chmodSync(path.join(packaged, 'Sources/Oliphaunt/Oliphaunt.swift'), 0o755); + writeFileSync(archive, await createDeterministicZip(packaged, { keepParent: true })); + } + const captured = s.capture(); + expect(() => + validateNativeSwiftSourceTagFiles(captured.evidence, (_, output) => + path.join(s.executionRoot, output), + ), + ).toThrow('shared delivered members differ'); + const directory = path.join(f.directory, 'source-packet'); + expect(() => writeNativeBuildEvidence(captured, directory)).toThrow( + 'shared delivered members differ', + ); + expect(existsSync(path.join(directory, 'native-build-evidence.json'))).toBe(false); + }); + }); + +for (const kind of [ + 'missing-manifest', + 'missing-canonical-root', + 'owner-version', + 'held-version', + 'manifest-supplier', + 'duplicate-root', + 'configuration', + 'tree-carrier-substitution', + 'traversal', +]) + test(`rejects source-tag ${kind} before packet completion`, async () => { + await fixture(async (f) => { + const s = await sourceFixture(f); + const captured = s.capture(); + const evidence = structuredClone(captured.evidence); + const cohort = evidence.cohorts[0]; + if (kind === 'duplicate-root') cohort.roots.push(structuredClone(cohort.roots[0])); + else if (kind === 'missing-canonical-root') + cohort.roots = cohort.roots.filter( + ({ package: pkg }) => pkg.name !== 'Package.swift.release', + ); + else if (kind === 'configuration') cohort.roots[0].package.configuration = 'windows-x64'; + else if (kind === 'tree-carrier-substitution') + cohort.roots.find( + ({ package: pkg }) => pkg.name === 'oliphaunt-react-native-ios-carriers.json', + ).package.outputs[0].path = cohort.roots[0].package.outputs[0].path; + else if (kind === 'traversal') + cohort.outputs + .find(({ path }) => path.endsWith('/release-tree')) + .members.push({ + path: '../outside', + type: 'file', + mode: 0o644, + size: 1, + sha256: 'a'.repeat(64), + }); + else { + const relative = + kind === 'missing-manifest' || kind === 'manifest-supplier' + ? 'Package.swift' + : `src/sdks/swift/${kind === 'owner-version' ? 'VERSION' : 'LIBOLIPHAUNT_VERSION'}`; + const target = path.join(s.executionRoot, s.source, 'release-tree', relative); + if (kind === 'missing-manifest') rmSync(target); + else + writeFileSync( + target, + kind === 'manifest-supplier' + ? readFileSync(target, 'utf8').replaceAll( + 'liboliphaunt-native-v0.3.3', + 'liboliphaunt-native-v0.3.4', + ) + : '9.9.9\n', + ); + } + if ( + [ + 'duplicate-root', + 'missing-canonical-root', + 'configuration', + 'tree-carrier-substitution', + ].includes(kind) + ) + expect(() => nativeSwiftSourceTagRoots(cohort)).toThrow(); + else if (kind === 'traversal') + expect(() => + readNativeBuildFinalFiles(path.join(f.directory, 'unused'), evidence, s.expected), + ).toThrow('unsafe native build path'); + else + expect(() => + validateNativeSwiftSourceTagFiles(evidence, (_, output) => + path.join(s.executionRoot, output), + ), + ).toThrow(); + const directory = path.join(f.directory, 'rejected-packet'); + expect(() => writeNativeBuildEvidence({ ...captured, evidence }, directory)).toThrow(); + expect(existsSync(path.join(directory, 'evidence.json'))).toBe(false); + }); + }); + +test('source tree transport rejects post-capture bytes and unsafe mode restoration without changing downloaded files', async () => { + await fixture(async (f) => { + const s = await sourceFixture(f, true); + const directory = path.join(f.directory, 'source-packet'); + const evidence = JSON.parse( + readFileSync(writeNativeBuildEvidence(s.capture(), directory), 'utf8'), + ); + const packet = readNativeBuildFinalFiles(directory, evidence, s.expected); + const manifest = packet.artifactRoots.find((name) => + name.endsWith('/release-tree/Package.swift'), + ); + const original = readFileSync(manifest); + writeFileSync(manifest, `${original.toString()}// substituted\n`); + expect(() => readNativeBuildFinalFiles(directory, evidence, s.expected)).toThrow( + 'native final transport bytes', + ); + expect(() => packet.stage()).toThrow(); + writeFileSync(manifest, original); + const changed = structuredClone(evidence); + changed.cohorts[0].outputs + .find(({ path }) => path.endsWith('/release-tree')) + .members.find(({ path }) => path.endsWith('launch.sh')).mode = 0o777; + expect(() => readNativeBuildFinalFiles(directory, changed, s.expected).stage()).toThrow( + 'unsafe captured mode', + ); + expect(statSync(manifest).mode & 0o777).toBe(0o644); + }); +}); + +test('readonly declared Swift source trees retain raw evidence and stage canonical publisher modes', async () => { + await fixture(async (f) => { + // The actual source writer creates0644 files. Stock Bazel8.8.1 makes every + // TreeArtifact member0555 after both cold execution and disk restoration. + const s = await sourceFixture(f); + const treePath = `${s.source}/release-tree`; + const physical = captureNativeOutputMembers(s.executionRoot, treePath).members; + try { + for (const member of physical) + chmodSync(path.join(s.executionRoot, treePath, member.path), 0o555); + const captured = s.capture(); + const original = JSON.stringify(captured.evidence); + const raw = captured.evidence.cohorts[0].outputs.find(({ path }) => path === treePath); + expect(raw.members.every(({ mode }) => mode === 0o555)).toBe(true); + const directory = path.join(f.directory, 'readonly-source-packet'); + const evidence = JSON.parse( + readFileSync(writeNativeBuildEvidence(captured, directory), 'utf8'), + ); + const packet = readNativeBuildFinalFiles(directory, evidence, s.expected); + const stageDirectory = path + .relative(ROOT, path.join(f.directory, 'readonly-source-stage')) + .split(path.sep) + .join('/'); + const staged = packet.stage({ stageDirectory }); + const tree = staged.find((file) => path.basename(file) === 'release-tree'); + const stagedMembers = captureNativeInputMembers( + path.dirname(tree), + path.basename(tree), + ).members; + expect(stagedMembers.map(({ mode, ...member }) => member)).toEqual( + raw.members.map(({ mode, ...member }) => member), + ); + expect( + stagedMembers.every(({ type, mode }) => mode === (type === 'file' ? 0o644 : 0o755)), + ).toBe(true); + expect(JSON.stringify(captured.evidence)).toBe(original); + expect(evidence.cohorts[0].outputs.find(({ path }) => path === treePath).members).toEqual( + raw.members, + ); + expect(captureNativeOutputMembers(s.executionRoot, treePath).members).toEqual(raw.members); + captured.assertUnchanged(); + const version = path.join(s.executionRoot, treePath, 'src/sdks/swift/VERSION'); + chmodSync(version, 0o444); + expect(() => captured.assertUnchanged()).toThrow('changed after capture'); + chmodSync(version, 0o555); + } finally { + // Restore only fixture-owned permissions so cleanup cannot mask the assertion. + for (const member of physical) + chmodSync( + path.join(s.executionRoot, treePath, member.path), + member.type === 'file' ? 0o644 : 0o755, + ); + } + }); +}); diff --git a/tools/release/native-close-release-candidate.mts b/tools/release/native-close-release-candidate.mts new file mode 100644 index 000000000..feaf10a5e --- /dev/null +++ b/tools/release/native-close-release-candidate.mts @@ -0,0 +1,56 @@ +/** Verify the native candidate already committed by its isolated Prepare coordinator. */ +import assert from 'node:assert/strict'; +import { execFileSync } from 'node:child_process'; +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import { validateReleaseMetadata } from './check-release-metadata.mts'; +import { validateReleaseConsumerCompatibility } from './consumer-compatibility.mts'; +import { + parseNativeReleaseInputRecord, + relocateNativeReleaseInputs, +} from './native-release-inputs.mts'; +import { assertNativeVersionSourceTransition } from './native-version-source.mts'; +import { ROOT } from './release-graph.mts'; +import { syncReleasePr } from './sync-release-pr.mts'; +import { verifyReleaseCommit } from './verify-release-commit.mts'; + +if (import.meta.main) { + assert.ok( + process.argv.length === 3 && + /^[1-9][0-9]*$/u.test(process.env.NATIVE_QUALIFICATION_RUN_ID ?? ''), + 'native close requires its isolated qualification coordinator', + ); + const directory = path.resolve(process.argv[2]); + const bytes = readFileSync(path.join(directory, 'native-version-source.json')); + assert.deepEqual( + bytes, + readFileSync(path.join(directory, 'native-release-inputs/native-version-source.json')), + 'native close and transported candidate differ', + ); + const { record, buildBound } = parseNativeReleaseInputRecord(JSON.parse(bytes.toString('utf8'))); + const git = (...args: string[]) => + execFileSync('git', args, { cwd: ROOT, encoding: 'utf8' }).trim(); + const currentSource = { commit: git('rev-parse', 'HEAD'), tree: git('rev-parse', 'HEAD^{tree}') }; + assert.deepEqual( + currentSource, + record.preparedSource, + 'native candidate advanced after preparation', + ); + assert.equal( + process.env.RELEASE_SOURCE_SHA, + currentSource.commit, + 'native close source context is stale', + ); + assertNativeVersionSourceTransition(record.bridge, currentSource, ROOT); + relocateNativeReleaseInputs(path.join(directory, 'native-release-inputs'), record); + verifyReleaseCommit({ + products: record.selectedProducts, + buildBound, + repo: ROOT, + headRef: 'HEAD', + }); + validateReleaseConsumerCompatibility(record.selectedProducts, { buildBound }); + validateReleaseMetadata({ publication: true, buildBound }); + await syncReleasePr(['--check'], { buildBound }); + console.log(`native release candidate verified (${record.selectedProducts.length} products)`); +} diff --git a/tools/release/native-completed-delivery.mts b/tools/release/native-completed-delivery.mts new file mode 100644 index 000000000..2b9fca077 --- /dev/null +++ b/tools/release/native-completed-delivery.mts @@ -0,0 +1,1349 @@ +/** Completed public bytes compared with a construction candidate; never release admission. */ +import { createHash } from 'node:crypto'; +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import { CONTRIB_CARRIERS_PATH } from '../../src/extensions/artifacts/packages/tools/contrib-carriers.mts'; +import { validateMavenCentralPublication } from '../packaging/maven-central-contract.mts'; +import { readPortableArchiveEntries } from '../packaging/portable-archive.mts'; +import { readCompletedContribCarrierRows } from './completed-contrib-carrier-context.mts'; +import { + type CompletedPublication, + createCompletedPublicationChecker, +} from './completed-release-publication.mts'; +import { + captureCompletedSwiftSourceTag, + currentSwiftSourceTagMembers, + replayCompletedSwiftSourceArchive, +} from './completed-swift-source-delivery.mts'; +import { requestGithubPages, requestGithubRepositoryJson } from './github-read.mts'; +import { fileIdentity, safeRelative } from './native-file-identity.mts'; +import { differentNativeDeliveredMembers } from './native-publication-delivery.mts'; +import { assertAuthenticatedNativePublicBaseline } from './native-publication-metadata.mts'; +import { + NATIVE_PUBLICATION_METADATA_KIND, + nativePublicationMetadataArtifactRow, +} from './native-publication-metadata-contract.mts'; +import { sourceCarrierMembers } from './native-source-carrier-changes.mts'; +import { + type NativeSupplierArtifact, + validateNativeSupplierArtifacts, +} from './native-supplier-artifacts.mts'; +import { + loadPublicationCatalog, + PUBLICATION_CATALOG_SCHEMA, + REGISTRY_KIND_TO_ECOSYSTEM, + resolveActualCarrier, +} from './publication-catalog.mts'; +import { + discoverPublicationArtifacts, + expectedProductArtifactRows, + validateCargoPayloadPartSets, + validatePublicationCandidate, +} from './publication-lock.mts'; +import { verifyRegistryCarrierIntegrity } from './registry-integrity.mts'; +import { contribCarrierDescriptor, PRODUCT_PRESETS } from './release-artifact-targets.mts'; +import { ROOT } from './release-graph.mts'; +import { requestReleaseAssetProof } from './verify_github_release_attestations.mts'; + +type Member = { + path: string; + type: 'file' | 'directory'; + mode: number; + size?: number; + sha256?: string; +}; +type Carrier = { + id: string; + ecosystem: string; + name: string; + version: string; + artifacts: { path: string; size: number; sha256: string }[]; +}; +export type CompletedDeliveryBaseline = { + publication: CompletedPublication; + /** Exact local downloaded files, not source folders or inferred historical Bazel roots. */ + carriers: Record; + productArtifacts?: Record; + metadataBaseline?: ReturnType; +}; +const utf8 = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }); +const sha = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +const stable = (value: unknown): string => + value && typeof value === 'object' + ? Array.isArray(value) + ? `[${value.map(stable).join(',')}]` + : `{${Object.entries(value) + .sort(([a], [b]) => a.localeCompare(b)) + .map(([k, v]) => `${JSON.stringify(k)}:${stable(v)}`) + .join(',')}}` + : JSON.stringify(value); +const same = (a: unknown, b: unknown) => stable(a) === stable(b); +const absolute = (file: string) => path.resolve(ROOT, file); +const requireValue = (condition: unknown, message: string) => { + if (!condition) throw new Error(`native completed delivery: ${message}`); +}; + +/** Installed archive member view. Compression, timestamps and outer names are not members. */ +export function nativeArchiveDeliveryMembers(file: string): Member[] { + return [ + { path: '', type: 'directory' as const, mode: 0o755 }, + ...[...readPortableArchiveEntries(file).values()].map((entry) => + entry.isDirectory + ? { + path: entry.name.replace(/\/$/u, ''), + type: 'directory' as const, + mode: entry.mode & 0o777, + } + : { + path: entry.name, + type: 'file' as const, + mode: entry.mode & 0o777, + size: entry.size, + sha256: sha(entry.data()), + }, + ), + ].sort((a, b) => a.path.localeCompare(b.path)); +} + +function ownedPomVersion(text: string, version: string) { + // The existing Central validator owns XML/coordinate validation. Mask the + // same nested coordinate scopes, retaining offsets, and replace only the + // one literal project.version. Dependencies/parents/properties stay exact. + const header = text.replace( + /<(parent|dependencies|dependencyManagement|properties|build|profiles|repositories|distributionManagement)(?:\s[^>]*)?>[\s\S]*?<\/\1>/gu, + (block) => ' '.repeat(block.length), + ); + const versions = [...header.matchAll(/]*)?>([\s\S]*?)<\/version>/gu)]; + requireValue( + versions.length === 1 && versions[0][1].trim() === version, + 'POM needs one literal own project.version', + ); + const match = versions[0]; + const content = match.index + match[0].indexOf('>') + 1; + const start = content + match[1].indexOf(version); + return text.slice(0, start) + '0.0.0' + text.slice(start + version.length); +} + +/** Preserve every Maven companion and packed member; neutralize only the own POM identity. */ +export function nativeCarrierDeliveryMembers(carrier: Carrier): Member[] | undefined { + const files = carrier.artifacts.map(({ path: file }) => absolute(file)); + if (['cargo', 'npm'].includes(carrier.ecosystem)) { + requireValue(files.length === 1, 'Cargo/npm delivery needs exactly one packed carrier'); + return sourceCarrierMembers(files[0], carrier).map(({ member, file, mode, sha256 }) => ({ + path: member === '.' ? '' : member.replace(/\/$/u, ''), + type: file ? 'file' : 'directory', + mode, + sha256, + })); + } + if (carrier.ecosystem !== 'maven') return undefined; + const poms = files.filter((file) => file.endsWith('.pom')); + requireValue(poms.length === 1, 'Maven delivery needs exactly one POM'); + const text = utf8.decode(readFileSync(poms[0])); + const identity = validateMavenCentralPublication({ + pomText: text, + files: carrier.artifacts.map((artifact) => ({ + name: path.basename(artifact.path), + size: artifact.size, + })), + }); + requireValue( + `${identity.groupId}:${identity.artifactId}` === carrier.name && + identity.version === carrier.version, + 'Maven own coordinate differs', + ); + const prefix = `${identity.artifactId}-${identity.version}`; + const members: Member[] = []; + const seen = new Set(); + for (const file of files) { + const name = path.basename(file); + requireValue( + name.startsWith(prefix) && name.length > prefix.length, + 'Maven companion lacks its exact coordinate basename', + ); + const suffix = name.slice(prefix.length); + requireValue(!seen.has(suffix), 'duplicate Maven companion'); + seen.add(suffix); + if (suffix === '.pom') { + const bytes = Buffer.from(ownedPomVersion(text, carrier.version)); + members.push({ + path: suffix, + type: 'file', + mode: 0o644, + size: bytes.length, + sha256: sha(bytes), + }); + } else if (/\.(?:jar|aar|zip|tar\.gz|tar\.zst)$/u.test(suffix)) { + members.push( + ...nativeArchiveDeliveryMembers(file).map((member) => ({ + ...member, + path: suffix + (member.path ? `/${member.path}` : ''), + })), + ); + } else return undefined; // Signatures/checksums/unknown publications are not guessed away. + } + return members.sort((a, b) => a.path.localeCompare(b.path)); +} + +function boundArtifacts(artifacts: Carrier['artifacts']) { + return artifacts.map((artifact) => { + const file = absolute(artifact.path); + const before = fileIdentity(file); + requireValue( + before.sha256 === artifact.sha256 && before.size === artifact.size, + 'candidate physical file differs from its captured artifact', + ); + return { file, before }; + }); +} + +async function completedRegistryDeclarations(publication, productPath, options) { + const contrib = contribCarrierDescriptor('completed registry declarations'); + const historicalContrib = [contrib.nativeOwner, contrib.wasixOwner].includes(publication.product) + ? await readCompletedContribCarrierRows(publication, { + repository: options.repository, + assertCompleted: options.assertCompletedPublication, + readJson: options.readJson, + }) + : undefined; + let descriptor; + if (historicalContrib) descriptor = historicalContrib.descriptor; + else { + const descriptorPath = `${productPath}/release.toml`; + const contents = await options.readJson( + `repos/${options.repository}/contents/${descriptorPath}?ref=${publication.publicationSha}`, + ); + requireValue( + contents.type === 'file' && + contents.path === descriptorPath && + contents.encoding === 'base64' && + typeof contents.content === 'string', + 'missing completed source descriptor', + ); + const bytes = Buffer.from(contents.content, 'base64'); + requireValue( + createHash('sha1').update(`blob ${bytes.length}\0`).update(bytes).digest('hex') === + contents.sha, + 'completed descriptor Git blob differs', + ); + descriptor = Bun.TOML.parse(utf8.decode(bytes)); + } + requireValue( + descriptor.id === publication.product && + (descriptor.registry_packages === undefined || Array.isArray(descriptor.registry_packages)), + 'completed descriptor owner/registry inventory differs', + ); + return { + descriptor, + declaredRegistry: historicalContrib + ? historicalContrib.registryRows.map(({ raw }) => raw) + : (descriptor.registry_packages ?? []), + historicalContrib, + }; +} + +/** Exact completed source declarations, including renamed owners and retired contracts. */ +export async function readCompletedNativeDeliveryInventory( + publication: CompletedPublication, + { + repository = 'f0rr0/oliphaunt', + assertCompletedPublication = createCompletedPublicationChecker({ repository }), + readJson = requestGithubRepositoryJson, + metadataBaseline = undefined as + | ReturnType + | undefined, + assertMetadataBaseline = assertAuthenticatedNativePublicBaseline, + } = {}, +) { + publication = structuredClone(publication); + requireValue(repository === 'f0rr0/oliphaunt', 'unsupported repository'); + requireValue( + same(await assertCompletedPublication(publication), publication), + 'completed inventory origin differs from requested source/version', + ); + const frozen = + metadataBaseline === undefined ? undefined : assertMetadataBaseline(metadataBaseline); + requireValue( + metadataBaseline === undefined || frozen, + 'frozen metadata authentication returned no baseline', + ); + if (frozen) { + requireValue(same(frozen.publication, publication), 'frozen metadata publication differs'); + requireValue( + frozen.metadata.repository === repository && + frozen.metadata.product.id === publication.product && + frozen.metadata.product.version === publication.version && + same(frozen.metadata.source, { + commit: publication.publicationSha, + tree: publication.publicationTree, + }), + 'frozen metadata source/product/version differs', + ); + } + const sources = new Map(); + const responses = new Map>(); + const read = (endpoint: string) => { + let response = responses.get(endpoint); + if (!response) { + response = Promise.resolve(readJson(endpoint)); + responses.set(endpoint, response); + } + return response; + }; + const text = async (file: string) => { + safeRelative(file); + if (!sources.has(file)) { + const value = await read( + `repos/${repository}/contents/${file}?ref=${publication.publicationSha}`, + ); + requireValue( + value.type === 'file' && + value.path === file && + value.encoding === 'base64' && + typeof value.content === 'string' && + /^[a-f0-9]{40}$/u.test(value.sha), + `missing exact historical file ${file}`, + ); + const bytes = Buffer.from(value.content, 'base64'); + requireValue( + createHash('sha1').update(`blob ${bytes.length}\0`).update(bytes).digest('hex') === + value.sha, + `historical Git blob differs for ${file}`, + ); + sources.set(file, { text: utf8.decode(bytes), sha: value.sha }); + } + const captured = sources.get(file); + if (!captured) throw new Error(`native completed delivery: uncaptured historical file ${file}`); + return captured.text; + }; + const config = JSON.parse(await text('release-please-config.json')); + const versions = JSON.parse(await text('.release-please-manifest.json')); + const ownerPaths = Object.entries(config.packages ?? {}) + .filter(([, entry]: [string, any]) => entry?.component === publication.product) + .map(([file]) => safeRelative(file)); + requireValue(ownerPaths.length === 1, 'completed product has no unique historical owner'); + const [ownerPath] = ownerPaths; + requireValue(versions[ownerPath] === publication.version, 'completed historical version differs'); + if (frozen) { + const descriptor = { + ...Bun.TOML.parse(await text(`${ownerPath}/release.toml`)), + path: ownerPath, + version: publication.version, + }; + requireValue( + descriptor.id === publication.product && + typeof descriptor.kind === 'string' && + Array.isArray(descriptor.publish_targets ?? []) && + (descriptor.publish_targets ?? []).every((target) => typeof target === 'string') && + Array.isArray(descriptor.registry_packages ?? []), + 'completed descriptor owner/registry inventory differs', + ); + const safeName = (name: string) => + typeof name === 'string' && name === path.basename(name) && safeRelative(name); + const files = (artifacts) => + Array.isArray(artifacts) && + artifacts.length && + artifacts.every( + (artifact) => + typeof artifact.path === 'string' && + safeName(path.basename(artifact.path)) && + (artifact.type === undefined || artifact.type === 'file') && + Number.isSafeInteger(artifact.size) && + artifact.size > 0 && + /^[a-f0-9]{64}$/u.test(artifact.sha256), + ); + const carriers = structuredClone(frozen.metadata.carriers); + requireValue( + Array.isArray(carriers) && new Set(carriers.map(({ id }) => id)).size === carriers.length, + 'frozen registry inventory is ambiguous', + ); + for (const carrier of carriers) { + requireValue( + carrier.product === publication.product && + carrier.version === publication.version && + Object.values(REGISTRY_KIND_TO_ECOSYSTEM).includes(carrier.ecosystem) && + typeof carrier.name === 'string' && + carrier.name.length && + !/[\u0000-\u0020\u007f]/u.test(carrier.name) && + carrier.id === `${carrier.ecosystem}:${carrier.name}` && + typeof carrier.role === 'string' && + carrier.role.length && + (carrier.target === null || typeof carrier.target === 'string') && + typeof carrier.declared === 'boolean', + 'frozen registry ownership differs', + ); + requireValue(files(carrier.artifacts), 'frozen registry File inventory differs'); + if (!carrier.declared) + requireValue(carrier.role === 'payload-part', 'frozen dynamic carrier is not a Cargo part'); + } + const declaredIds = (descriptor.registry_packages ?? []).map((raw) => { + requireValue(typeof raw === 'string', 'historical registry declaration is not a string'); + const separator = raw.indexOf(':'); + const ecosystem = REGISTRY_KIND_TO_ECOSYSTEM[raw.slice(0, separator)]; + requireValue( + separator > 0 && ecosystem && raw.slice(separator + 1), + 'historical registry identity differs', + ); + return `${ecosystem}:${raw.slice(separator + 1)}`; + }); + requireValue( + new Set(declaredIds).size === declaredIds.length && + declaredIds.every((id) => + carriers.some((carrier) => carrier.id === id && carrier.declared), + ), + 'frozen registry inventory omits a historical declaration', + ); + // Signed implicit contrib rows retain their recorded owner/role/target. + // The source's literal registry list is coverage, not a current name factory. + validateCargoPayloadPartSets(carriers); + for (const carrier of carriers.filter(({ role }) => role === 'payload-part')) { + const parent = carriers.find(({ id }) => id === carrier.parentCarrier); + requireValue( + parent && carrier.name === `${parent.name}-part-${String(carrier.part).padStart(3, '0')}`, + 'frozen Cargo part identity differs', + ); + } + const publicRows = frozen.metadata.productArtifacts + .filter(({ role }) => ['github-release-asset', 'github-release-metadata'].includes(role)) + .map((artifact) => { + requireValue( + artifact.version === undefined || artifact.version === publication.version, + 'frozen public version differs', + ); + return { ...structuredClone(artifact), version: publication.version }; + }) + .sort((left, right) => left.id.localeCompare(right.id)); + requireValue( + new Set(publicRows.map(({ id }) => id)).size === publicRows.length, + 'frozen public inventory is ambiguous', + ); + for (const row of publicRows) + requireValue( + row.product === publication.product && + !['checksums', NATIVE_PUBLICATION_METADATA_KIND].includes(row.kind) && + safeName(row.name) && + row.id === `github-release:${row.name}` && + files([row]), + 'frozen public File identity differs', + ); + const catalog = { + schema: PUBLICATION_CATALOG_SCHEMA, + products: [ + { + id: publication.product, + kind: descriptor.kind, + path: ownerPath, + version: publication.version, + publishTargets: descriptor.publish_targets ?? [], + dependencies: [], + }, + ], + carriers, + }; + return { + publication, + descriptor, + catalog, + carriers, + publicRows, + inputContext: { + products: { [publication.product]: descriptor }, + contrib: { nativeOwner: null, wasixOwner: null }, + readText: (file: string) => { + const captured = sources.get(safeRelative(file)); + if (!captured) + throw new Error( + `native completed delivery: uncaptured historical inventory input ${file}`, + ); + return captured.text; + }, + }, + sourceFiles: [...sources].map(([file, { sha }]) => ({ path: file, sha })), + }; + } + const declarations = await completedRegistryDeclarations(publication, ownerPath, { + repository, + assertCompletedPublication, + readJson: read, + }); + const descriptor = { ...declarations.descriptor, path: ownerPath, version: publication.version }; + await text(`${ownerPath}/release.toml`); + const products = { [publication.product]: descriptor }; + const inputContext = declarations.historicalContrib?.inputContext ?? { + products, + // Non-runtime products have no implicit contrib carriers. + contrib: { nativeOwner: null, wasixOwner: null }, + }; + if (declarations.historicalContrib) { + requireValue( + inputContext.contrib.nativeOwner !== null, + 'historical contrib context is missing', + ); + for (const { path: file } of declarations.historicalContrib.sourceFiles) await text(file); + } + inputContext.products[publication.product] = descriptor; + const normalizeTargets = async (owner: string, metadata) => { + if (metadata.artifact_targets !== undefined) return; + const moon = Bun.YAML.parse(await text(`${metadata.path}/moon.yml`)); + requireValue( + moon.id === owner && + moon.project?.release?.component === owner && + moon.project.release.packagePath === metadata.path, + 'historical Moon release owner differs', + ); + metadata.artifact_targets = moon.project.release.artifactTargets; + }; + if (descriptor.publish_targets?.includes('github-release-assets')) { + if (Object.hasOwn(PRODUCT_PRESETS, publication.product)) + await normalizeTargets(publication.product, descriptor); + if (publication.product === 'database-resources') + await text('src/database-resources/contracts/contract.json'); + if ( + declarations.historicalContrib || + ['exact-extension-artifact', 'exact-extension-bundle'].includes(descriptor.kind) + ) { + if (!declarations.historicalContrib) { + const carriers = Bun.TOML.parse(await text(CONTRIB_CARRIERS_PATH)); + requireValue( + [carriers.native_owner, carriers.wasix_owner, carriers.logical_product].every( + (value) => typeof value === 'string' && value.length, + ) && carriers.native_owner !== carriers.wasix_owner, + 'historical extension runtime ownership differs', + ); + inputContext.contrib = { + nativeOwner: carriers.native_owner, + wasixOwner: carriers.wasix_owner, + artifactProduct: carriers.logical_product, + }; + } + const owners = [inputContext.contrib.nativeOwner, inputContext.contrib.wasixOwner]; + for (const owner of owners) { + if (!inputContext.products[owner]) { + const paths = Object.entries(config.packages ?? {}) + .filter(([, entry]: [string, any]) => entry?.component === owner) + .map(([file]) => safeRelative(file)); + requireValue(paths.length === 1, 'historical extension runtime has no unique owner'); + const [ownerPath] = paths; + const metadata = Bun.TOML.parse(await text(`${ownerPath}/release.toml`)); + requireValue( + metadata.id === owner && typeof versions[ownerPath] === 'string', + 'historical extension runtime owner/version differs', + ); + inputContext.products[owner] = { + ...metadata, + path: ownerPath, + version: versions[ownerPath], + }; + } + await normalizeTargets(owner, inputContext.products[owner]); + } + } + if (['exact-extension-artifact', 'exact-extension-bundle'].includes(descriptor.kind)) + for (const file of [ + 'src/extensions/contracts/extension-target-profiles.toml', + 'src/extensions/generated/sdk/extensions.json', + 'src/extensions/generated/mobile/static-extensions.tsv', + ]) + await text(file); + } + const context = { + ...inputContext, + readText: (file: string) => { + const captured = sources.get(safeRelative(file)); + if (!captured) + throw new Error(`native completed delivery: uncaptured historical inventory input ${file}`); + return captured.text; + }, + }; + const catalog = loadPublicationCatalog('completed native delivery inventory', { + products: [publication.product], + inputContext: context, + }); + const decodedRows = expectedProductArtifactRows(catalog.products, { + inputContext: context, + }).filter(({ role }) => role === 'github-release-asset' || role === 'github-release-metadata'); + const carriers = catalog.carriers; + const publicRows = decodedRows; + return { + publication, + descriptor, + catalog, + carriers, + publicRows, + inputContext: context, + sourceFiles: [...sources].map(([file, { sha }]) => ({ path: file, sha })), + }; +} + +async function completedRegistryCarrier( + publication, + carrier, + files, + declaredRegistry, + options, + frozenCarrier = undefined, +) { + const owner = carrier.parentCarrier ?? carrier.id; + requireValue( + declaredRegistry.includes(owner.replace(/^cargo:/u, 'crates:')), + `historical registry ownership is unverified: ${carrier.id}`, + ); + requireValue(Array.isArray(files) && files.length, `completed carrier is missing: ${carrier.id}`); + const records = discoverPublicationArtifacts(files); + requireValue( + records.length === 1 && + records[0].ecosystem === carrier.ecosystem && + records[0].name === carrier.name && + records[0].version === publication.version, + 'completed carrier files have a different registry identity', + ); + const published = { + ...carrier, + version: publication.version, + artifacts: records[0].artifacts, + packageDependencies: records[0].dependencies, + }; + // Discovery must not acquire an adjacent Maven companion outside this input. + requireValue( + same( + published.artifacts.map(({ path: file }) => absolute(file)).sort(), + files.map(absolute).sort(), + ), + 'completed carrier includes undeclared companion files', + ); + const beforeFiles = boundArtifacts(published.artifacts); + if (frozenCarrier) { + const identities = (artifacts) => + artifacts + .map((artifact) => ({ + name: path.basename(artifact.path), + size: artifact.size, + sha256: artifact.sha256, + })) + .sort((left, right) => left.name.localeCompare(right.name)); + requireValue( + same(identities(published.artifacts), identities(frozenCarrier.artifacts)), + 'completed registry Files differ from frozen metadata', + ); + } + const registryProof = await verifyRegistryCarrierIntegrity(published, options); + for (const { file, before } of beforeFiles) + requireValue( + same(fileIdentity(file), before), + 'carrier changed during registry authentication', + ); + return { published, registryProof }; +} + +/** + * Authenticate only explicitly consumed registry carriers at a completed source. + * This is not complete owner inventory or a historical producer graph. Preserve + * every raw packed member: own versions and Cargo provenance are consumed bytes. + */ +export async function captureCompletedNativeRegistryCarriers( + { + publication, + carriers, + metadataBaseline, + }: Pick, + { + repository = 'f0rr0/oliphaunt', + assertCompletedPublication = createCompletedPublicationChecker({ repository }), + readJson = requestGithubRepositoryJson, + registryOptions = {}, + assertMetadataBaseline = assertAuthenticatedNativePublicBaseline, + } = {}, +) { + requireValue(repository === 'f0rr0/oliphaunt', 'unsupported repository'); + requireValue( + same(await assertCompletedPublication(publication), publication), + 'completed registry origin differs from requested source/version', + ); + requireValue( + carriers && typeof carriers === 'object' && !Array.isArray(carriers), + 'completed registry inputs must be an explicit carrier map', + ); + const inventory = await readCompletedNativeDeliveryInventory(publication, { + repository, + assertCompletedPublication, + readJson, + metadataBaseline, + assertMetadataBaseline, + }); + const { catalog, descriptor } = inventory; + const declaredRegistry = catalog.carriers.map(({ id }) => id.replace(/^cargo:/u, 'crates:')); + const archives = []; + const unknowns = []; + for (const [id, files] of Object.entries(carriers)) { + const separator = id.indexOf(':'); + requireValue(separator > 0, 'registry input lacks its canonical identity'); + const frozenCarrier = metadataBaseline + ? inventory.carriers.find((row) => row.id === id) + : undefined; + requireValue( + !metadataBaseline || frozenCarrier, + 'registry input is absent from frozen metadata', + ); + const carrier = + frozenCarrier ?? + resolveActualCarrier(catalog, id.slice(0, separator), id.slice(separator + 1)); + requireValue(carrier.id === id, 'registry input has a different canonical identity'); + const { published, registryProof } = await completedRegistryCarrier( + publication, + carrier, + files, + declaredRegistry, + registryOptions, + frozenCarrier, + ); + if (!['cargo', 'npm'].includes(carrier.ecosystem)) { + unknowns.push(`unsupported-supplier-registry-contract:${id}`); + continue; + } + const bindings = boundArtifacts(published.artifacts); + requireValue(bindings.length === 1, 'registry supplier needs exactly one packed archive'); + const packed = bindings[0]; + const root = + carrier.ecosystem === 'cargo' ? `${carrier.name}-${publication.version}/` : 'package/'; + const members = []; + for (const entry of readPortableArchiveEntries(packed.file).values()) { + requireValue( + entry.name.startsWith(root), + 'registry member is outside its owned package root', + ); + const member = entry.name.slice(root.length).replace(/\/$/u, ''); + if (!member) continue; + members.push( + entry.isDirectory + ? { path: member, type: 'directory' as const, mode: entry.mode & 0o777 } + : { + path: member, + type: 'file' as const, + mode: entry.mode & 0o777, + size: entry.size, + sha256: sha(entry.data()), + }, + ); + } + requireValue( + same(fileIdentity(packed.file), packed.before), + 'registry carrier changed during member capture', + ); + archives.push({ + ...published, + name: id, + target: carrier.target ?? 'portable', + members: members.sort((a, b) => a.path.localeCompare(b.path)), + registryProof, + }); + } + return { + scope: 'construction' as const, + origin: 'completed-registry-archives' as const, + publication, + descriptor, + declaredRegistry, + archives, + unknowns, + }; +} + +const archiveKinds = new Set([ + 'native-runtime', + 'native-tools', + 'apple-swiftpm-binary', + 'runtime-resources', + 'broker-helper', + 'node-direct-addon', + 'wasix-napi-addon', + 'swift-bindings', + 'wasix-runtime', + 'wasix-aot-runtime', + 'wasix-postmaster-runtime', + 'wasix-tools', + 'wasix-tools-aot', + 'icu-data', + 'swift-source', + 'runtime', + 'extension-bundle', + 'ios-dependency-xcframework', + 'ios-xcframework', +]); +const metadataKinds = new Set(['manifest-json', 'manifest-properties', 'swift-extension-carrier']); +const isPublicPayload = ({ kind }) => + !['checksums', NATIVE_PUBLICATION_METADATA_KIND].includes(kind); +function publicDeliveryContract(row: { kind: string; name: string }) { + // Both seed formats are canonical public assets. Preserve the descriptor and + // every PGDATA byte; unchanged construction must reuse the completed seed. + if (row.kind === 'native-seeds' || row.kind === 'wasix-seeds') { + if (row.name.endsWith('.tar.zst')) return 'archive'; + if (row.name.endsWith('.json')) return 'file'; + return undefined; + } + if (archiveKinds.has(row.kind)) return 'archive'; + if (metadataKinds.has(row.kind)) return 'file'; + return undefined; +} +// Canonical asset IDs contain the own versioned filename. Pair the two +// independently canonical inventories by their semantic slot, retaining each +// side's actual ID/name for API and physical-file authentication. +const artifactSlot = (row, version = row.version) => + stable([ + row.role, + row.kind, + row.target, + row.identity, + // Names come from the authenticated frozen inventory or the bounded legacy + // decoder. Preserve variants while removing only the own publication version. + row.name.replace(version, '{version}'), + ]); + +/** Genuine completed public files only; there are no historical producer roots here. */ +export async function captureCompletedNativePublicArtifacts( + { + publication, + files, + metadataBaseline, + }: Pick & { + files: Record; + }, + { + repository = 'f0rr0/oliphaunt', + assertCompletedPublication = createCompletedPublicationChecker({ repository }), + readJson = requestGithubRepositoryJson, + readPages = requestGithubPages, + proveAsset = requestReleaseAssetProof, + assertMetadataBaseline = assertAuthenticatedNativePublicBaseline, + } = {}, +) { + requireValue(repository === 'f0rr0/oliphaunt', 'unsupported repository'); + requireValue( + same(await assertCompletedPublication(publication), publication), + 'completed public origin differs from requested source/version', + ); + const inventory = await readCompletedNativeDeliveryInventory(publication, { + repository, + assertCompletedPublication, + readJson, + metadataBaseline, + assertMetadataBaseline, + }); + const rows = inventory.publicRows; + const release = await readJson( + `repos/${repository}/releases/tags/${encodeURIComponent(publication.tagName)}`, + ); + requireValue( + Number.isSafeInteger(release.id) && + release.id > 0 && + release.tag_name === publication.tagName && + release.target_commitish === publication.publicationSha && + release.draft === false && + release.prerelease === false, + 'public release differs from completed source', + ); + const assets = await readPages(`repos/${repository}/releases/${release.id}/assets`); + const unknowns = []; + const metadataName = nativePublicationMetadataArtifactRow({ + id: publication.product, + version: publication.version, + }).name; + const metadataAssets = assets.filter(({ name }) => name === metadataName); + // Metadata v1 excludes the separate outer checksum envelopes. Their actual + // names come from this completed release; full public verification owns their + // contents/coverage. Do not regenerate them from today's product recipes. + const excludedEnvelopes = metadataBaseline + ? assets.filter(({ name }) => name === metadataName || name.endsWith('.sha256')) + : metadataAssets; + const payloadAssets = assets.filter( + ({ name }) => + rows.some((row) => row.name === name) || !excludedEnvelopes.some((row) => row.name === name), + ); + if ( + metadataAssets.length > 1 || + new Set(assets.map(({ name }) => name)).size !== assets.length || + !same(payloadAssets.map(({ name }) => name).sort(), rows.map(({ name }) => name).sort()) + ) + unknowns.push('completed-public-asset-inventory-differs'); + if ( + Object.keys(files).some( + (id) => + !rows.some((row) => row.id === id) && + !excludedEnvelopes.some(({ name }) => id === `github-release:${name}`), + ) + ) + unknowns.push('completed-public-artifact-inventory-differs'); + const archives = []; + for (const row of rows) { + const contract = publicDeliveryContract(row); + if (!contract && row.kind !== 'checksums') { + unknowns.push(`unsupported-public-delivery-contract:${row.kind}`); + continue; + } + const file = files[row.id]; + if (!file) { + unknowns.push(`completed-public-artifact-missing:${row.id}`); + continue; + } + const matches = assets.filter((asset) => asset.name === row.name); + requireValue(matches.length === 1, 'completed public artifact is absent or ambiguous'); + const asset = matches[0]; + requireValue( + Number.isSafeInteger(asset.id) && + asset.id > 0 && + Number.isSafeInteger(asset.size) && + asset.size > 0 && + asset.state === 'uploaded' && + asset.url === `https://api.github.com/repos/${repository}/releases/assets/${asset.id}`, + 'completed asset has invalid identity/state', + ); + requireValue( + asset.digest == null || /^sha256:[a-f0-9]{64}$/u.test(asset.digest), + 'completed asset digest is invalid', + ); + const identity = fileIdentity(absolute(file)); + if (row.sha256 !== undefined) + requireValue( + identity.size === row.size && identity.sha256 === row.sha256, + 'completed public File differs from frozen metadata', + ); + const proof = asset.digest + ? { bytes: asset.size, sha256: asset.digest.slice(7) } + : await proveAsset(asset.url, row.name, asset.size); + requireValue( + identity.size === asset.size && + identity.size === proof.bytes && + identity.sha256 === proof.sha256, + 'completed public archive bytes differ', + ); + if (row.kind === 'checksums') continue; + const members = + contract === 'archive' + ? nativeArchiveDeliveryMembers(absolute(file)) + : [ + { + path: '', + type: 'file' as const, + mode: 0o644, + size: identity.size, + sha256: identity.sha256, + }, + ]; + requireValue( + same(fileIdentity(absolute(file)), identity), + 'public archive changed during capture', + ); + archives.push({ + ...row, + assetId: asset.id, + releaseId: release.id, + size: identity.size, + sha256: identity.sha256, + members, + }); + } + return { + scope: 'construction' as const, + origin: 'completed-published-archives' as const, + publication, + archives, + unknowns, + }; +} + +/** Reconstructed Git delivery uses the same authenticated completed binding archive. + * It is never interpreted as a published GitHub asset or an old Bazel output. */ +export async function captureCompletedNativeSwiftSourceSuppliers( + { + publication, + files, + carriers = {}, + sourceTags, + metadataBaseline, + }: { + publication: CompletedPublication; + files: Record; + carriers?: Record; + sourceTags: NativeSupplierArtifact[]; + metadataBaseline?: ReturnType; + }, + { + repository = 'f0rr0/oliphaunt', + assertCompletedPublication = createCompletedPublicationChecker({ repository }), + readJson = requestGithubRepositoryJson, + readPages = requestGithubPages, + proveAsset = requestReleaseAssetProof, + registryOptions = {}, + assertMetadataBaseline = assertAuthenticatedNativePublicBaseline, + } = {}, +) { + requireValue(repository === 'f0rr0/oliphaunt', 'unsupported repository'); + const rows = validateNativeSupplierArtifacts(sourceTags); + requireValue(rows.length === 1, 'one completed Swift source-tag input is required'); + const row = rows[0]; + requireValue( + same(row.publication, publication) && + row.source && + row.artifact === `swift-source-tag:${publication.version}`, + 'completed Swift source-tag input differs from its publication', + ); + const completions = new Map>(); + const completed = (value: CompletedPublication) => { + const key = stable(value); + let result = completions.get(key); + if (!result) { + result = Promise.resolve(assertCompletedPublication(value)); + completions.set(key, result); + } + return result; + }; + const reads = new Map>(); + const read = (endpoint: string) => { + let result = reads.get(endpoint); + if (!result) { + result = Promise.resolve(readJson(endpoint)); + reads.set(endpoint, result); + } + return result; + }; + const options = { + repository, + assertCompletedPublication: completed, + readJson: read, + readPages, + proveAsset, + registryOptions, + metadataBaseline, + assertMetadataBaseline, + }; + const publicOrigin = await captureCompletedNativePublicArtifacts( + { publication, files, metadataBaseline }, + options, + ); + const binding = publicOrigin.archives.filter(({ kind }) => kind === 'swift-bindings'); + requireValue( + binding.length === 1, + 'completed Swift source requires its authenticated binding archive', + ); + const { descriptor } = await readCompletedNativeDeliveryInventory(publication, options); + requireValue( + descriptor.publish_targets?.includes('swift-package-source-tag'), + 'completed owner does not declare a Swift source-tag delivery', + ); + const replayed = await replayCompletedSwiftSourceArchive( + { + publication, + descriptor, + bindings: { name: binding[0].name, sha256: binding[0].sha256 }, + source: row.source!, + file: row.file, + }, + options, + ); + const registry = Object.keys(carriers).length + ? await captureCompletedNativeRegistryCarriers( + { publication, carriers, metadataBaseline }, + options, + ) + : undefined; + return { + ...publicOrigin, + archives: [ + ...publicOrigin.archives, + ...(registry?.archives ?? []), + { + id: row.artifact, + name: row.artifact, + target: 'portable', + size: replayed.file.size, + sha256: replayed.file.sha256, + members: replayed.members, + }, + ], + unknowns: [...publicOrigin.unknowns, ...(registry?.unknowns ?? [])], + }; +} + +/** + * One physical completed-delivery bridge for the existing candidate schema. + * This compares public members, not consumed inputs or action keys. The old + * public origin supplies no historical BUILD graph. Necessary delivery stays + * unknown until the separate complete qualification/admission gates close. + */ +export async function compareNativeCompletedPhysicalDelivery( + candidate: any, + baselines: CompletedDeliveryBaseline[], + { + repository = 'f0rr0/oliphaunt', + assertCompletedPublication = createCompletedPublicationChecker({ repository }), + readJson = requestGithubRepositoryJson, + readPages = requestGithubPages, + proveAsset = requestReleaseAssetProof, + registryOptions = {}, + unreleasedProducts = [] as string[], + assertMetadataBaseline = assertAuthenticatedNativePublicBaseline, + } = {}, +) { + requireValue(repository === 'f0rr0/oliphaunt', 'unsupported repository'); + requireValue( + candidate.scope === 'construction' && !candidate.missing?.length, + 'requires a complete physical construction candidate', + ); + validatePublicationCandidate(candidate); + requireValue( + Array.isArray(unreleasedProducts) && + new Set(unreleasedProducts).size === unreleasedProducts.length && + unreleasedProducts.every((id) => + candidate.products.some((product) => product.id === id && product.version === '0.0.0'), + ) && + unreleasedProducts.every( + (id) => !baselines.some((baseline) => baseline.publication.product === id), + ), + 'first publications require unique explicit version-zero products without completed baselines', + ); + requireValue( + new Set(baselines.map(({ publication }) => publication.product)).size === baselines.length, + 'duplicate completed product origin', + ); + requireValue( + baselines.every(({ publication }) => + candidate.products.some(({ id }) => id === publication.product), + ), + 'completed origin exceeds candidate inventory', + ); + const products = []; + for (const product of candidate.products) { + const baseline = baselines.find(({ publication }) => publication.product === product.id); + const carriers = candidate.carriers.filter((carrier) => carrier.product === product.id); + const currentArtifacts = candidate.productArtifacts.filter( + (artifact) => artifact.product === product.id, + ); + const bindings = { + carriers: structuredClone(carriers), + productArtifacts: structuredClone(currentArtifacts), + }; + if (!baseline) { + const firstPublication = unreleasedProducts.includes(product.id); + products.push({ + product: product.id, + deliveryStatus: firstPublication ? ('different' as const) : ('unknown' as const), + reason: firstPublication ? 'verified-first-publication' : 'missing-completed-publication', + ...(firstPublication + ? { + contractChanges: { added: [`product:${product.id}`], removed: [] as string[] }, + comparisons: [] as any[], + unknowns: [] as string[], + } + : {}), + ...bindings, + }); + continue; + } + const publication = await assertCompletedPublication(baseline.publication); + requireValue( + same(publication, baseline.publication), + 'completed publication differs from requested source/version', + ); + const inventory = await readCompletedNativeDeliveryInventory(publication, { + repository, + assertCompletedPublication, + readJson, + metadataBaseline: baseline.metadataBaseline, + assertMetadataBaseline, + }); + const { descriptor } = inventory; + const declaredRegistry = inventory.catalog.carriers.map(({ id }) => + id.replace(/^cargo:/u, 'crates:'), + ); + const unknowns: string[] = []; + const comparisons = []; + const publishedCarriers = []; + for (const carrier of inventory.carriers) + if (!baseline.carriers[carrier.id]?.length) + unknowns.push(`completed-carrier-missing:${carrier.id}`); + for (const [id, files] of Object.entries(baseline.carriers).sort(([left], [right]) => + left.localeCompare(right), + )) { + const separator = id.indexOf(':'); + const frozenCarrier = baseline.metadataBaseline + ? inventory.carriers.find((row) => row.id === id) + : undefined; + requireValue( + !baseline.metadataBaseline || frozenCarrier, + 'completed carrier is absent from frozen metadata', + ); + let carrier; + try { + carrier = + frozenCarrier ?? + resolveActualCarrier(inventory.catalog, id.slice(0, separator), id.slice(separator + 1)); + } catch { + unknowns.push(`completed-carrier-undeclared:${id}`); + continue; + } + const { published, registryProof } = await completedRegistryCarrier( + publication, + carrier, + files, + declaredRegistry, + registryOptions, + frozenCarrier, + ); + const beforeFiles = boundArtifacts(published.artifacts); + const current = carriers.find((row) => row.id === carrier.id); + const currentFiles = current ? boundArtifacts(current.artifacts) : []; + const before = nativeCarrierDeliveryMembers(published); + const after = current ? nativeCarrierDeliveryMembers(current) : undefined; + for (const { file, before: identity } of [...beforeFiles, ...currentFiles]) + requireValue( + same(fileIdentity(file), identity), + 'carrier changed during delivery comparison', + ); + publishedCarriers.push(published); + if (!before || (current && !after)) + unknowns.push(`unsupported-registry-delivery-contract:${carrier.id}`); + else if (current) + comparisons.push({ + id: carrier.id, + kind: carrier.ecosystem, + differentMembers: differentNativeDeliveredMembers(before, after), + registryProof, + }); + } + validateCargoPayloadPartSets(publishedCarriers); + const publicRows = inventory.publicRows.filter(isPublicPayload); + const finalInputs = currentArtifacts.filter( + (row) => + ['github-release-asset', 'github-release-metadata'].includes(row.role) && + isPublicPayload(row), + ); + requireValue( + new Set(publicRows.map((row) => artifactSlot(row))).size === publicRows.length && + new Set(finalInputs.map((row) => artifactSlot(row, product.version))).size === + finalInputs.length, + 'ambiguous canonical public artifact slot', + ); + const previousContracts = new Set([ + ...publishedCarriers.map(({ id }) => id), + ...publicRows.map((row) => `public:${artifactSlot(row)}`), + ...(descriptor.publish_targets ?? []).map((target) => `publish:${target}`), + ]); + const currentContracts = new Set([ + ...carriers.map(({ id }) => id), + ...finalInputs.map((row) => `public:${artifactSlot(row, product.version)}`), + ...product.publishTargets.map((target) => `publish:${target}`), + ]); + const contractChanges = { + added: [...currentContracts].filter((id) => !previousContracts.has(id)).sort(), + removed: [...previousContracts].filter((id) => !currentContracts.has(id)).sort(), + }; + let capturedPublic; + if (publicRows.length) { + const captured = await captureCompletedNativePublicArtifacts( + { + publication, + files: baseline.productArtifacts ?? {}, + metadataBaseline: baseline.metadataBaseline, + }, + { + repository, + assertCompletedPublication, + readJson, + readPages, + proveAsset, + assertMetadataBaseline, + }, + ); + capturedPublic = captured; + unknowns.push(...captured.unknowns); + for (const row of captured.archives) { + const current = finalInputs.find( + (input) => artifactSlot(input, product.version) === artifactSlot(row), + ); + if (!current) continue; + const currentFiles = boundArtifacts([current]); + const memberView = (file: string) => + publicDeliveryContract(row) === 'archive' + ? nativeArchiveDeliveryMembers(file) + : [ + { + path: '', + type: 'file' as const, + mode: 0o644, + size: readFileSync(file).length, + sha256: sha(readFileSync(file)), + }, + ]; + const differentMembers = differentNativeDeliveredMembers( + row.members, + memberView(currentFiles[0].file), + ); + requireValue( + same(fileIdentity(currentFiles[0].file), currentFiles[0].before), + 'public archive changed during comparison', + ); + comparisons.push({ + id: row.id, + currentId: current.id, + kind: row.kind, + differentMembers, + assetId: row.assetId, + releaseId: row.releaseId, + }); + } + } + // The source publisher's separate unscoped commit is independently + // authenticated. It supplies actual delivered members, never old BUILD facts. + if (descriptor.publish_targets?.includes('swift-package-source-tag')) { + const bindingsArchive = capturedPublic?.archives.find( + ({ kind }) => kind === 'swift-bindings', + ); + if (product.id !== 'oliphaunt-swift' || !bindingsArchive) + unknowns.push('authenticated-swift-source-tag-delivery-missing'); + else { + const sourceTag = await captureCompletedSwiftSourceTag( + { publication, descriptor, bindings: bindingsArchive }, + { assertCompletedPublication, readJson, readPages }, + ); + if (product.publishTargets.includes('swift-package-source-tag')) + comparisons.push({ + id: 'release-input:swiftpm-release-tree', + kind: 'swiftpm-release-tree', + differentMembers: differentNativeDeliveredMembers( + sourceTag.members, + currentSwiftSourceTagMembers(candidate), + ), + sourceTag: sourceTag.source, + nativePublication: sourceTag.nativePublication, + }); + } + } + if (!comparisons.length && !contractChanges.added.length && !contractChanges.removed.length) + unknowns.push('delivered-contract-inventory-empty'); + products.push({ + product: product.id, + origin: publication, + deliveryStatus: unknowns.length + ? ('unknown' as const) + : contractChanges.added.length || + contractChanges.removed.length || + comparisons.some(({ differentMembers }) => differentMembers.length) + ? ('different' as const) + : ('identical' as const), + comparisons, + contractChanges, + unknowns, + ...bindings, + }); + } + return { + scope: 'construction' as const, + source: candidate.source, + releaseDecision: 'unverified' as const, + products, + unverified: [ + 'complete product-specific qualification and input lifetime admission', + 'historical producer graph is unavailable; public members are not historical ShippingInfo', + 'necessary delivery is unverified', + ], + }; +} diff --git a/tools/release/native-completed-delivery.test.mts b/tools/release/native-completed-delivery.test.mts new file mode 100644 index 000000000..435635f72 --- /dev/null +++ b/tools/release/native-completed-delivery.test.mts @@ -0,0 +1,1743 @@ +import { expect, test } from 'bun:test'; +import { execFileSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + copyFileSync, + mkdirSync, + mkdtempSync, + readFileSync, + renameSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { mavenPom } from '../../build_defs/languages/jvm/maven-pom.mts'; +import { archiveDirectory } from '../packaging/archive-directory.mts'; +import { packagePayload } from '../packaging/native-cargo-payload.mts'; +import { readPortableArchiveEntries } from '../packaging/portable-archive.mts'; +import { tarArchive } from '../packaging/testdata/tar-fixture.mts'; +import { zipArchive } from '../packaging/testdata/zip-fixture.mts'; +import { captureNativeBuildEvidence } from './capture-native-build-evidence.mts'; +import { fixture as observationFixture } from './completed-native-publication.fixture.mts'; +import { createCompletedPublicationChecker } from './completed-release-publication.mts'; +import { nativeBuildMetadata } from './native-build-qualification.mts'; +import { + captureCompletedNativePublicArtifacts, + captureCompletedNativeRegistryCarriers, + compareNativeCompletedPhysicalDelivery, + nativeArchiveDeliveryMembers, + nativeCarrierDeliveryMembers, + readCompletedNativeDeliveryInventory, +} from './native-completed-delivery.mts'; +import { + compareNativePreVersionDelivery, + differentNativeDeliveredMembers, +} from './native-publication-delivery.mts'; +import { nativePublicationMetadataArtifactRow } from './native-publication-metadata-contract.mts'; +import { observeNativePublicationConstruction } from './native-publication-observation.mts'; +import { + loadPublicationCatalog, + PUBLICATION_CATALOG_SCHEMA, + publicationCatalogDigest, + resolveActualCarrier, +} from './publication-catalog.mts'; +import { consumerDigest } from './publication-consumer-proof.mts'; +import { + buildPublicationCandidate, + expectedProductArtifactRows, + lockedPublicationFiles, + PUBLICATION_CANDIDATE_SCHEMA, + sourceIdentity, + validatePublicationCandidate, +} from './publication-lock.mts'; + +const hash = (file: string) => createHash('sha256').update(readFileSync(file)).digest('hex'); +const artifact = (file: string) => ({ + path: file, + size: readFileSync(file).length, + sha256: hash(file), +}); +function scratch(run) { + const directory = mkdtempSync(path.join(os.tmpdir(), 'completed-native-delivery-')); + try { + return run(directory); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +} +async function asyncScratch(run) { + const directory = mkdtempSync(path.join(os.tmpdir(), 'completed-native-delivery-')); + try { + return await run(directory); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +} +function carrier(ecosystem: string, name: string, version: string, files: string[]) { + return { id: `${ecosystem}:${name}`, ecosystem, name, version, artifacts: files.map(artifact) }; +} +const metadata = { + name: 'Oliphaunt test', + description: 'Declared Maven source', + inceptionYear: '2026', + url: 'https://oliphaunt.dev', + license: { name: 'MIT', url: 'https://opensource.org/license/mit', distribution: 'repo' }, + developer: { id: 'oliphaunt', name: 'Oliphaunt', url: 'https://github.com/f0rr0' }, + scm: { + url: 'https://github.com/f0rr0/oliphaunt', + connection: 'scm:git:https://github.com/f0rr0/oliphaunt.git', + developerConnection: 'scm:git:ssh://git@github.com/f0rr0/oliphaunt.git', + }, +}; +function maven( + directory: string, + version: string, + dependency = '0.3.2', + changed: Record = {}, +) { + mkdirSync(directory, { recursive: true }); + const prefix = path.join(directory, `library-${version}`); + writeFileSync( + `${prefix}.pom`, + mavenPom({ + coordinate: { groupId: 'dev.oliphaunt', artifactId: 'library', version, packaging: 'aar' }, + metadata, + dependencies: [{ module: 'dev.oliphaunt.runtime:liboliphaunt', version: dependency }], + }), + ); + for (const [suffix, members] of Object.entries({ + '.aar': { + 'AndroidManifest.xml': '', + 'classes.jar': 'exact compiler JAR bytes', + 'jni/arm64-v8a/liboliphaunt.so': 'exact compiled version public API 0.3.3', + }, + '-sources.jar': { 'Public.kt': '// exact shipped docs and source' }, + '-javadoc.jar': { 'index.html': '

Shipped API

' }, + })) + writeFileSync( + prefix + suffix, + zipArchive( + Object.entries(members).map(([name, data]) => ({ name, data: changed[name] ?? data })), + ), + ); + return carrier( + 'maven', + 'dev.oliphaunt:library', + version, + ['.pom', '.aar', '-sources.jar', '-javadoc.jar'].map((suffix) => prefix + suffix), + ); +} + +test('actual Maven writer neutralizes only root coordinate and keeps held pins and all companions', () => + scratch((directory) => { + const before = maven(path.join(directory, 'old'), '0.1.0'); + const current = maven(path.join(directory, 'new'), '0.2.0'); + expect( + differentNativeDeliveredMembers( + nativeCarrierDeliveryMembers(before)!, + nativeCarrierDeliveryMembers(current)!, + ), + ).toEqual([]); + const adopted = maven(path.join(directory, 'adopted'), '0.2.0', '0.3.3'); + expect( + differentNativeDeliveredMembers( + nativeCarrierDeliveryMembers(before)!, + nativeCarrierDeliveryMembers(adopted)!, + ), + ).toEqual(['.pom']); + for (const member of ['Public.kt', 'index.html', 'jni/arm64-v8a/liboliphaunt.so']) { + const changed = maven(path.join(directory, member.replaceAll('/', '_')), '0.2.0', '0.3.2', { + [member]: 'actual changed delivered bytes', + }); + expect( + differentNativeDeliveredMembers( + nativeCarrierDeliveryMembers(before)!, + nativeCarrierDeliveryMembers(changed)!, + ), + ).toHaveLength(1); + } + })); + +test('Maven rejects incomplete/duplicate identities and leaves unsupported module contracts unknown', () => + scratch((directory) => { + const current = maven(directory, '0.1.0'); + expect(() => nativeCarrierDeliveryMembers({ ...current, version: '0.2.0' })).toThrow( + 'own coordinate', + ); + expect(() => + nativeCarrierDeliveryMembers({ ...current, artifacts: current.artifacts.slice(0, 2) }), + ).toThrow('missing required file'); + expect(() => + nativeCarrierDeliveryMembers({ + ...current, + artifacts: [...current.artifacts, current.artifacts[1]], + }), + ).toThrow('duplicate'); + const module = path.join(directory, 'library-0.1.0.module'); + writeFileSync(module, JSON.stringify({ component: { version: '0.1.0' }, variants: [] })); + expect( + nativeCarrierDeliveryMembers({ + ...current, + artifacts: [...current.artifacts, artifact(module)], + }), + ).toBeUndefined(); + writeFileSync( + current.artifacts[0].path, + readFileSync(current.artifacts[0].path, 'utf8').replace( + '0.1.0', + '0.1.00.1.0', + ), + ); + expect(() => nativeCarrierDeliveryMembers(current)).toThrow('exactly one '); + })); + +test('Maven keeps source/byte modes and rejects unsafe packed entries', () => + scratch((directory) => { + const current = maven(directory, '0.1.0'); + const source = current.artifacts.find(({ path }) => path.endsWith('-sources.jar'))!.path; + const before = nativeCarrierDeliveryMembers(current)!; + writeFileSync( + source, + zipArchive([ + { + name: 'Public.kt', + data: '// exact shipped docs and source', + externalAttributes: 0o100755 << 16, + }, + ]), + ); + expect(differentNativeDeliveredMembers(before, nativeCarrierDeliveryMembers(current)!)).toEqual( + ['-sources.jar/Public.kt'], + ); + writeFileSync(source, zipArchive([{ name: '../outside', data: 'outside' }])); + expect(() => nativeCarrierDeliveryMembers(current)).toThrow(/unsafe|traversal|relative/); + })); + +test('outer archive representation and producer inputs cannot erase exact inner delivery differences', () => + scratch((directory) => { + const old = path.join(directory, 'old.tar.gz'); + const next = path.join(directory, 'next.zip'); + const file = { + name: 'runtime/bin/psql', + data: 'actual public interface version 0.3.3', + mode: 0o755, + }; + writeFileSync(old, tarArchive([file])); + writeFileSync(next, zipArchive([{ ...file, externalAttributes: 0o100755 << 16, method: 8 }])); + expect( + differentNativeDeliveredMembers( + nativeArchiveDeliveryMembers(old), + nativeArchiveDeliveryMembers(next), + ), + ).toEqual([]); + for (const change of [ + { data: 'public interface version 0.3.4' }, + { name: 'runtime/bin/renamed' }, + { externalAttributes: 0o100644 << 16 }, + ]) { + writeFileSync(next, zipArchive([{ ...file, externalAttributes: 0o100755 << 16, ...change }])); + expect( + differentNativeDeliveredMembers( + nativeArchiveDeliveryMembers(old), + nativeArchiveDeliveryMembers(next), + ).length, + ).toBeGreaterThan(0); + } + })); + +test('actual split Cargo writer preserves every payload, legal and aggregator member', () => + scratch((directory) => { + const payload = path.join(directory, 'payload'); + mkdirSync(path.join(payload, 'runtime/bin'), { recursive: true }); + writeFileSync(path.join(payload, 'runtime/bin/psql'), Buffer.alloc(96, 7)); + chmodSync(path.join(payload, 'runtime/bin/psql'), 0o755); + const output = path.join(directory, 'output'); + mkdirSync(output); + const packages = packagePayload( + payload, + path.join(directory, 'source'), + output, + path.join(directory, 'cargo'), + { + target: { target: 'linux-x64-gnu', triple: 'x86_64-unknown-linux-gnu' }, + version: '9.8.7', + partBytes: 64, + packageBase: 'oliphaunt-tools', + artifactProduct: 'postgres-tools-native', + artifactKind: 'native-tools', + artifactLabel: 'tools', + noticeProfile: 'native-tools', + executableFiles: ['runtime/bin/psql'], + }, + ); + const parts = packages.filter(({ role }) => role === 'part'); + expect(parts.length).toBeGreaterThan(1); + for (const item of packages) { + const record = carrier('cargo', item.name, item.version, [item.cratePath]); + const members = nativeCarrierDeliveryMembers(record)!; + expect(members.some(({ path }) => path === 'Cargo.toml')).toBe(true); + expect(members.some(({ path }) => path === 'THIRD_PARTY_NOTICES.md')).toBe(true); + expect(members.some(({ path }) => path === 'build.rs')).toBe(true); + if (item.role === 'part') + expect(members.some(({ path }) => path.startsWith('payload/chunks/'))).toBe(true); + const rows = [...readPortableArchiveEntries(item.cratePath).values()].map((entry) => ({ + name: entry.name + (entry.isDirectory ? '/' : ''), + type: entry.isFile ? '0' : '5', + mode: entry.mode, + data: entry.isFile ? entry.data() : Buffer.alloc(0), + })); + const target = rows.find((row) => row.name.endsWith('/build.rs'))!; + target.data = Buffer.concat([ + target.data, + Buffer.from('\n// changed reconstruction recipe\n'), + ]); + const changed = path.join(directory, item.name + '.crate'); + writeFileSync(changed, tarArchive(rows)); + expect( + differentNativeDeliveredMembers( + members, + nativeCarrierDeliveryMembers(carrier('cargo', item.name, item.version, [changed]))!, + ), + ).toEqual(['build.rs']); + } + })); + +async function publicFixture(directory: string, id: string, version = '9.8.7') { + const product = { + ...loadPublicationCatalog('completed public fixture', { products: [id] }).products[0], + version, + }; + const rows = expectedProductArtifactRows([product]).filter(({ role }) => + role.startsWith('github-release-'), + ); + const files: Record = {}; + for (const row of rows) { + const file = path.join(directory, 'release-assets', row.name); + files[row.id] = file; + if (row.kind === 'checksums') continue; + if (row.role === 'github-release-metadata' || row.name.endsWith('.json')) { + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync( + file, + row.kind === 'manifest-properties' ? 'fixture=exact\n' : '{"fixture":"exact"}\n', + ); + continue; + } + const payload = path.join(directory, 'members', row.name); + if (['native-seeds', 'wasix-seeds'].includes(row.kind)) { + mkdirSync(path.join(payload, 'global'), { recursive: true }); + mkdirSync(path.join(payload, 'pg_wal'), { recursive: true }); + writeFileSync(path.join(payload, 'PG_VERSION'), '18\n'); + writeFileSync(path.join(payload, 'global/pg_control'), 'frozen control identity'); + writeFileSync(path.join(payload, 'pg_wal/000000010000000000000001'), 'frozen WAL identity'); + await archiveDirectory(payload, file); + continue; + } + mkdirSync(path.join(payload, 'runtime/bin'), { recursive: true }); + writeFileSync( + path.join(payload, 'runtime/bin/psql'), + 'exact installed tools and held runtime API', + ); + chmodSync(path.join(payload, 'runtime/bin/psql'), 0o755); + writeFileSync(path.join(payload, 'THIRD_PARTY_NOTICES.md'), 'exact declared license bytes'); + await archiveDirectory(payload, file); + } + for (const row of rows.filter(({ kind }) => kind === 'checksums')) + writeFileSync( + files[row.id], + rows + .filter(({ kind }) => kind !== 'checksums') + .map(({ id, name }) => `${hash(files[id])} ./${name}\n`) + .join(''), + ); + const publication = { + product: id, + version, + tagName: `${id}-v${version}`, + publicationSha: '1'.repeat(40), + publicationTree: '2'.repeat(40), + releaseSha: '3'.repeat(40), + }; + // These responses exercise the production API/physical contract. They do + // not claim that the local writer fixture is an actual published release. + const release = { + id: 123, + tag_name: publication.tagName, + target_commitish: publication.publicationSha, + draft: false, + prerelease: false, + }; + const assets = rows.map(({ id, name }, index) => ({ + id: index + 1, + name, + size: readFileSync(files[id]).length, + digest: `sha256:${hash(files[id])}`, + state: 'uploaded', + url: `https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/${index + 1}`, + })); + const options = { + assertCompletedPublication: async (requested) => { + expect(requested).toEqual(publication); + return publication; + }, + readJson: async (endpoint) => { + if (endpoint === `repos/f0rr0/oliphaunt/releases/tags/${publication.tagName}`) return release; + const match = endpoint.match( + /^repos\/f0rr0\/oliphaunt\/contents\/(.+)\?ref=([a-f0-9]{40})$/u, + ); + if (!match || match[2] !== publication.publicationSha) + throw new Error(`unexpected fixture historical endpoint ${endpoint}`); + const file = match[1]; + const bytes = + file === '.release-please-manifest.json' + ? Buffer.from( + JSON.stringify({ + ...JSON.parse( + readFileSync( + new URL('../../.release-please-manifest.json', import.meta.url), + 'utf8', + ), + ), + [product.path]: version, + }), + ) + : readFileSync(new URL(`../../${file}`, import.meta.url)); + return { + type: 'file', + path: file, + encoding: 'base64', + content: bytes.toString('base64'), + sha: createHash('sha1').update(`blob ${bytes.length}\0`).update(bytes).digest('hex'), + }; + }, + readPages: async (endpoint) => { + expect(endpoint).toBe('repos/f0rr0/oliphaunt/releases/123/assets'); + return assets; + }, + proveAsset: async () => { + throw new Error('published API digest already binds every archive'); + }, + }; + return { input: { publication, files }, options, rows, release, assets }; +} + +test('canonical native and WASIX public inventory binds actual archive writer bytes and exact member changes', async () => + asyncScratch(async (directory) => { + for (const product of ['postgres-tools-native', 'postgres-tools-wasix']) { + const fixture = await publicFixture(path.join(directory, product), product); + const baseline = await captureCompletedNativePublicArtifacts(fixture.input, fixture.options); + expect(baseline.unknowns).toEqual([]); + expect(baseline.archives).toHaveLength( + fixture.rows.filter(({ kind }) => kind !== 'checksums').length, + ); + expect(baseline.scope).toBe('construction'); + const row = baseline.archives.find(({ target }) => target === 'linux-x64-gnu')!; + const original = fixture.input.files[row.id]; + expect( + differentNativeDeliveredMembers(row.members, nativeArchiveDeliveryMembers(original)), + ).toEqual([]); + const changed = path.join(directory, `${product}-changed.tar.gz`); + writeFileSync( + changed, + tarArchive([ + { name: 'runtime/bin/psql', data: 'new real compiled public interface', mode: 0o755 }, + { name: 'THIRD_PARTY_NOTICES.md', data: 'exact declared license bytes' }, + { name: 'runtime', type: '5', mode: 0o755 }, + { name: 'runtime/bin', type: '5', mode: 0o755 }, + ]), + ); + expect( + differentNativeDeliveredMembers(row.members, nativeArchiveDeliveryMembers(changed)), + ).toEqual(['runtime/bin/psql']); + fixture.input.files[row.id] = changed; + await expect( + captureCompletedNativePublicArtifacts(fixture.input, fixture.options), + ).rejects.toThrow('archive bytes differ'); + } + })); + +test('public baseline rejects source/asset substitutions and preserves missing or extra deliveries as unknown', async () => + asyncScratch(async (directory) => { + const fixture = await publicFixture(directory, 'postgres-tools-wasix'); + const row = fixture.rows.find( + ({ kind, target }) => kind !== 'checksums' && target === 'linux-x64-gnu', + )!; + const call = (input = fixture.input, options = fixture.options) => + captureCompletedNativePublicArtifacts(input, options); + const missing = structuredClone(fixture.input); + delete missing.files[row.id]; + expect((await call(missing)).unknowns).toContain(`completed-public-artifact-missing:${row.id}`); + const extra = structuredClone(fixture.input); + extra.files['github-release:foreign.tar.gz'] = fixture.input.files[row.id]; + expect((await call(extra)).unknowns).toContain('completed-public-artifact-inventory-differs'); + const asset = fixture.assets.find(({ name }) => name === row.name)!; + const saved = { ...asset }; + asset.digest = `sha256:${'f'.repeat(64)}`; + await expect(call()).rejects.toThrow('archive bytes differ'); + Object.assign(asset, saved); + asset.url = 'https://api.github.com/repos/foreign/release/assets/1'; + await expect(call()).rejects.toThrow('invalid identity'); + Object.assign(asset, saved); + fixture.release.target_commitish = 'f'.repeat(40); + await expect(call()).rejects.toThrow('completed source'); + fixture.release.target_commitish = fixture.input.publication.publicationSha; + fixture.assets.push({ ...asset }); + await expect(call()).rejects.toThrow('absent or ambiguous'); + fixture.assets.pop(); + const link = path.join(directory, 'linked.tar.gz'); + symlinkSync(fixture.input.files[row.id], link); + await expect( + call({ ...fixture.input, files: { ...fixture.input.files, [row.id]: link } }), + ).rejects.toThrow(); + delete asset.digest; + const fallback = await call(fixture.input, { + ...fixture.options, + proveAsset: async (url, name, size) => { + expect([url, name, size]).toEqual([saved.url, saved.name, saved.size]); + return { bytes: size, sha256: hash(fixture.input.files[row.id]) }; + }, + }); + expect(fallback.unknowns).toEqual([]); + const seedFixture = await publicFixture( + path.join(directory, 'missing-seeds'), + 'database-resources', + ); + const seeds = await captureCompletedNativePublicArtifacts( + { ...seedFixture.input, files: {} }, + seedFixture.options, + ); + for (const row of seedFixture.rows.filter(({ kind }) => + ['native-seeds', 'wasix-seeds'].includes(kind), + )) + expect(seeds.unknowns).toContain(`completed-public-artifact-missing:${row.id}`); + })); + +test('completed seed deliveries preserve every control and WAL byte rather than normalizing initdb entropy', async () => + asyncScratch(async (directory) => { + const fixture = await publicFixture(directory, 'database-resources'); + const baseline = await captureCompletedNativePublicArtifacts(fixture.input, fixture.options); + expect(baseline.unknowns).toEqual([]); + for (const kind of ['native-seeds', 'wasix-seeds']) { + const row = baseline.archives.find( + (artifact) => artifact.kind === kind && artifact.name.endsWith('.tar.zst'), + )!; + expect(row).toBeDefined(); + const original = fixture.input.files[row.id]; + expect( + differentNativeDeliveredMembers(row.members, nativeArchiveDeliveryMembers(original)), + ).toEqual([]); + const changed = path.join(directory, `${kind}-fresh.tar.gz`); + writeFileSync( + changed, + tarArchive([ + { name: 'PG_VERSION', data: '18\n' }, + { name: 'global', type: '5', mode: 0o755 }, + { name: 'global/pg_control', data: 'fresh initdb control identity' }, + { name: 'pg_wal', type: '5', mode: 0o755 }, + { name: 'pg_wal/000000010000000000000001', data: 'fresh initdb WAL identity' }, + ]), + ); + expect( + differentNativeDeliveredMembers(row.members, nativeArchiveDeliveryMembers(changed)), + ).toEqual(['global/pg_control', 'pg_wal/000000010000000000000001']); + await expect( + captureCompletedNativePublicArtifacts( + { ...fixture.input, files: { ...fixture.input.files, [row.id]: changed } }, + fixture.options, + ), + ).rejects.toThrow('archive bytes differ'); + } + expect(baseline.scope).toBe('construction'); + })); + +test('separately authenticated controller metadata stays outside seed delivery while extra or duplicate assets remain unknown', async () => + asyncScratch(async (directory) => { + const fixture = await publicFixture(directory, 'database-resources'); + const before = await captureCompletedNativePublicArtifacts(fixture.input, fixture.options); + const metadata = nativePublicationMetadataArtifactRow({ + id: fixture.input.publication.product, + version: fixture.input.publication.version, + }); + fixture.assets.push({ name: metadata.name }); + const withMetadata = await captureCompletedNativePublicArtifacts( + fixture.input, + fixture.options, + ); + expect(withMetadata.unknowns).toEqual([]); + expect(withMetadata.archives).toEqual(before.archives); + fixture.assets.push({ name: metadata.name }); + expect( + (await captureCompletedNativePublicArtifacts(fixture.input, fixture.options)).unknowns, + ).toContain('completed-public-asset-inventory-differs'); + fixture.assets.pop(); + fixture.assets.push({ name: 'database-resources-99.0.0-native-baseline.json' }); + expect( + (await captureCompletedNativePublicArtifacts(fixture.input, fixture.options)).unknowns, + ).toContain('completed-public-asset-inventory-differs'); + })); + +const sourceFixture = path.join(import.meta.dir, 'testdata/native-source-carriers'); +const captured = JSON.parse( + readFileSync(path.join(sourceFixture, 'captured-publication.json'), 'utf8'), +); +const publicationSha = 'c51052fe8b8ffc7e992266c5ab3d7a63b47441e7'; +function originEnvironment() { + const readJson = async (endpoint) => { + expect(Object.hasOwn(captured.responses, endpoint)).toBe(true); + return structuredClone(captured.responses[endpoint]); + }; + return { + readJson, + assertCompletedPublication: createCompletedPublicationChecker({ + repository: 'f0rr0/oliphaunt', + readJson, + listPullRequests: async () => captured.pullRequests, + readPages: async () => { + throw new Error('unexpected paged history'); + }, + }), + registryOptions: { + cratesIoReadGate: null, + fetchImpl: async (url) => { + if (url === 'https://crates.io/api/v1/crates/oliphaunt-query/0.1.1') + return Response.json(captured.registryMetadata.cargo); + expect(url).toBe('https://registry.npmjs.org/%40oliphaunt%2Fts-query/0.1.1'); + return Response.json(captured.registryMetadata.npm); + }, + }, + }; +} +const sourceProducts = ['oliphaunt-query', 'oliphaunt-query-ts']; +async function origins(options) { + return await Promise.all( + sourceProducts.map(async (product) => ({ + publication: await options.assertCompletedPublication({ + product, + version: '0.1.1', + tagName: `${product}-v0.1.1`, + publicationSha, + }), + carriers: + product === 'oliphaunt-query' + ? { 'cargo:oliphaunt-query': [path.join(sourceFixture, 'oliphaunt-query-0.1.1.crate')] } + : { + 'npm:@oliphaunt/ts-query': [path.join(sourceFixture, 'oliphaunt-ts-query-0.1.1.tgz')], + }, + })), + ); +} + +test('completed registry supplier capture retains genuine raw source and provenance bytes', async () => { + const options = originEnvironment(); + const input = (await origins(options))[0]; + const result = await captureCompletedNativeRegistryCarriers(input, options); + expect(result.unknowns).toEqual([]); + expect(result.archives).toHaveLength(1); + expect(result.archives[0].name).toBe('cargo:oliphaunt-query'); + const entries = readPortableArchiveEntries(input.carriers['cargo:oliphaunt-query'][0]); + for (const name of ['Cargo.toml', 'Cargo.toml.orig', '.cargo_vcs_info.json', 'src/lib.rs']) { + const entry = entries.get(`oliphaunt-query-0.1.1/${name}`)!; + const member = result.archives[0].members.find((member) => member.path === name)!; + expect(member.sha256).toBe(createHash('sha256').update(entry.data()).digest('hex')); + expect(member.size).toBe(entry.size); + } +}); + +test('completed registry suppliers reject substituted ownership, checksum and companions', async () => { + const options = originEnvironment(); + const input = (await origins(options))[0]; + await expect( + captureCompletedNativeRegistryCarriers( + { ...input, carriers: { 'cargo:foreign': input.carriers['cargo:oliphaunt-query'] } }, + options, + ), + ).rejects.toThrow('not declared'); + await expect( + captureCompletedNativeRegistryCarriers(input, { + ...options, + registryOptions: { + cratesIoReadGate: null, + fetchImpl: async () => Response.json({ version: { checksum: '0'.repeat(64) } }), + }, + }), + ).rejects.toThrow('registry checksum mismatch'); + const endpoint = `repos/f0rr0/oliphaunt/contents/src/query/rust/release.toml?ref=${publicationSha}`; + const descriptor = Buffer.from( + 'id="oliphaunt-query"\nkind="sdk"\npublish_targets=["crates-io"]\nregistry_packages=[]\n', + ); + await expect( + captureCompletedNativeRegistryCarriers(input, { + ...options, + readJson: async (request) => + request !== endpoint + ? options.readJson(request) + : { + type: 'file', + path: 'src/query/rust/release.toml', + encoding: 'base64', + content: descriptor.toString('base64'), + sha: createHash('sha1') + .update(`blob ${descriptor.length}\0`) + .update(descriptor) + .digest('hex'), + }, + }), + ).rejects.toThrow('not declared'); +}); + +test('completed registry suppliers reject an archive mutated during authentication', async () => + asyncScratch(async (directory) => { + const options = originEnvironment(); + const input = (await origins(options))[0]; + const original = input.carriers['cargo:oliphaunt-query'][0]; + const file = path.join(directory, 'oliphaunt-query.crate'); + copyFileSync(original, file); + input.carriers['cargo:oliphaunt-query'] = [file]; + await expect( + captureCompletedNativeRegistryCarriers(input, { + ...options, + registryOptions: { + cratesIoReadGate: null, + fetchImpl: async (url) => { + const response = await options.registryOptions.fetchImpl(url); + writeFileSync(file, 'substituted after registry checksum lookup'); + return response; + }, + }, + }), + ).rejects.toThrow('changed during registry authentication'); + })); + +test('authentic completed query archives enter the one pre-version comparison, never admission', async () => { + const candidate = { + ...buildPublicationCandidate({ products: sourceProducts, artifactRoots: [sourceFixture] }), + scope: 'construction', + }; + const options = originEnvironment(); + const completed = await compareNativeCompletedPhysicalDelivery( + candidate, + await origins(options), + options, + ); + expect(completed.products.map(({ deliveryStatus }) => deliveryStatus)).toEqual([ + 'identical', + 'identical', + ]); + expect( + completed.products + .flatMap(({ comparisons }) => comparisons!) + .every(({ differentMembers }) => !differentMembers.length), + ).toBe(true); + const preVersion = compareNativePreVersionDelivery({ + source: candidate.source, + products: sourceProducts, + completed, + affectedProducts: ['oliphaunt-query'], + }); + expect(preVersion.products.map(({ affectedBuild }) => affectedBuild)).toEqual([ + 'required', + 'not-required', + ]); + expect( + preVersion.products.every( + ({ deliveryStatus, necessaryDelivery }) => + deliveryStatus === 'identical' && necessaryDelivery === 'unknown', + ), + ).toBe(true); + expect(preVersion.releaseDecision).toBe('unverified'); + const observation: any = { + coverage: { completeProductInventory: true }, + authenticated: [ + { + evidence: { source: candidate.source }, + qualification: { + source: candidate.source, + testQualification: 'passed', + requiredTests: [{ label: '//fixture:test', configuration: 'a'.repeat(64) }], + unverified: ['fixture origin is unverified'], + }, + }, + ], + products: candidate.products.map((product) => ({ + product, + carriers: candidate.carriers + .filter((carrier) => carrier.product === product.id) + .map((carrier) => ({ + ...carrier, + qualifiedFiles: carrier.artifacts.map((artifact) => ({ + frozenPath: artifact.path, + label: '//fixture:shipping', + path: 'bazel-out/fixture/bin/package', + sha256: artifact.sha256, + size: artifact.size, + })), + })), + productArtifacts: [], + })), + }; + expect( + compareNativePreVersionDelivery({ + source: candidate.source, + products: sourceProducts, + completed, + observation, + }).products[0].deliveryStatus, + ).toBe('identical'); + const substituted = structuredClone(observation); + substituted.products[0].carriers[0].artifacts[0].sha256 = 'f'.repeat(64); + expect(() => + compareNativePreVersionDelivery({ + source: candidate.source, + products: sourceProducts, + completed, + observation: substituted, + }), + ).toThrow('qualified physical inventory'); + expect(() => + compareNativePreVersionDelivery({ + source: { ...candidate.source, commit: 'f'.repeat(40) }, + products: sourceProducts, + completed, + }), + ).toThrow('captured source'); +}); + +test('real observation output bindings do not become spurious envelope differences', async () => { + await observationFixture(async ({ input, origin }) => { + const old = input.publicationLock.carriers[0]; + writeFileSync( + old.artifacts[0].path, + readFileSync(path.join(sourceFixture, 'oliphaunt-ts-query-0.1.1.tgz')), + ); + const candidate = { + ...buildPublicationCandidate({ + products: ['oliphaunt-query-ts'], + artifactRoots: [old.artifacts[0].path], + }), + scope: 'construction', + }; + const carrier = candidate.carriers[0]; + const cohort = origin.evidence.cohorts[0]; + const root = cohort.roots.find(({ package: pkg }) => pkg.product === 'alpha'); + root.package = { + ...root.package, + product: carrier.product, + name: carrier.name, + version: carrier.version, + role: carrier.role, + }; + const output = root.package.outputs[0].path; + for (const event of cohort.buildEvents) { + if (event.buildMetadata) + event.buildMetadata.metadata = nativeBuildMetadata(candidate.source, origin.github); + for (const file of event.namedSetOfFiles?.files ?? []) + if (file.name === output) + Object.assign(file, { + digest: carrier.artifacts[0].sha256, + length: String(carrier.artifacts[0].size), + }); + } + // Reuse the existing fixture's configured actions and real physical input + // files. The actual collector binds the substituted authentic source archive. + origin.evidence = captureNativeBuildEvidence({ + source: candidate.source, + github: origin.github, + bazelVersion: input.bazelVersion, + cohorts: [ + { + executionRoot: cohort.executionRoot, + roots: [root], + aquery: cohort.aquery, + buildEvents: cohort.buildEvents, + cquery: { + results: [{ target: { rule: { name: root.label } }, configurationId: 1 }], + configurations: [{ id: 1, checksum: cohort.rootConfigurations[0].configuration }], + }, + }, + ], + }).evidence; + const build = { + ...input.builds[0], + expected: { ...input.builds[0].expected, source: candidate.source }, + }; + const observation = await observeNativePublicationConstruction( + { + envelope: candidate, + files: lockedPublicationFiles(candidate), + repository: input.repository, + bazelVersion: input.bazelVersion, + builds: [build], + }, + { authenticate: async () => origin }, + ); + expect(observation.products[0].carriers[0].qualifiedFiles).toHaveLength(1); + const options = originEnvironment(); + const baseline = (await origins(options)).filter( + ({ publication }) => publication.product === 'oliphaunt-query-ts', + ); + const completed = await compareNativeCompletedPhysicalDelivery(candidate, baseline, options); + const compared = compareNativePreVersionDelivery({ + source: candidate.source, + products: ['oliphaunt-query-ts'], + completed, + observation, + }); + expect(compared.products[0]).toMatchObject({ + deliveryStatus: 'identical', + configuredTests: 'observed-passed', + necessaryDelivery: 'unknown', + }); + const substituted = structuredClone(observation); + substituted.products[0].carriers[0].packageDependencies.push({ + ecosystem: 'npm', + name: 'substituted-held-pin', + requirement: '0.3.3', + scope: 'runtime', + }); + expect(() => + compareNativePreVersionDelivery({ + source: candidate.source, + products: ['oliphaunt-query-ts'], + completed, + observation: substituted, + }), + ).toThrow('qualified physical inventory'); + }); +}); + +test('missing/foreign completed source, carrier coverage and physical origin substitution fail closed', async () => + asyncScratch(async (directory) => { + const candidate = { + ...buildPublicationCandidate({ products: sourceProducts, artifactRoots: [sourceFixture] }), + scope: 'construction', + }; + const options = originEnvironment(); + const baselines = await origins(options); + expect( + (await compareNativeCompletedPhysicalDelivery(candidate, [], options)).products.every( + ({ deliveryStatus }) => deliveryStatus === 'unknown', + ), + ).toBe(true); + const missing = structuredClone(baselines); + missing[0].carriers = {}; + expect( + (await compareNativeCompletedPhysicalDelivery(candidate, missing, options)).products[0] + .deliveryStatus, + ).toBe('unknown'); + const extra = structuredClone(baselines); + extra[0].carriers['cargo:foreign'] = baselines[0].carriers['cargo:oliphaunt-query']; + expect( + (await compareNativeCompletedPhysicalDelivery(candidate, extra, options)).products[0] + .deliveryStatus, + ).toBe('unknown'); + await expect( + compareNativeCompletedPhysicalDelivery(candidate, [...baselines, baselines[0]], options), + ).rejects.toThrow('duplicate'); + const foreign = structuredClone(baselines); + foreign[0].publication.publicationSha = 'f'.repeat(40); + await expect( + compareNativeCompletedPhysicalDelivery(candidate, foreign, options), + ).rejects.toThrow(); + const original = baselines[0].carriers['cargo:oliphaunt-query'][0]; + const changed = path.join(directory, 'changed.crate'); + const rows = [...readPortableArchiveEntries(original).values()].map((entry) => ({ + name: entry.name + (entry.isDirectory ? '/' : ''), + type: entry.isFile ? '0' : '5', + mode: entry.mode, + data: entry.isFile ? entry.data() : Buffer.alloc(0), + })); + rows.find(({ name }) => name.endsWith('/README.md'))!.data = Buffer.from( + 'substituted published docs', + ); + writeFileSync(changed, tarArchive(rows)); + const forged = structuredClone(baselines); + forged[0].carriers['cargo:oliphaunt-query'] = [changed]; + await expect( + compareNativeCompletedPhysicalDelivery(candidate, forged, options), + ).rejects.toThrow(/checksum|payload mismatch/); + const link = path.join(directory, 'linked.crate'); + symlinkSync(original, link); + forged[0].carriers['cargo:oliphaunt-query'] = [link]; + await expect( + compareNativeCompletedPhysicalDelivery(candidate, forged, options), + ).rejects.toThrow(); + })); + +test('retired historical registry and source-tag obligations cannot disappear into identical delivery', async () => { + const candidate = { + ...buildPublicationCandidate({ products: sourceProducts, artifactRoots: [sourceFixture] }), + scope: 'construction', + }; + const options = originEnvironment(); + const baselines = await origins(options); + const target = candidate.products.find(({ id }) => id === 'oliphaunt-query')!; + const endpoint = `repos/f0rr0/oliphaunt/contents/${target.path}/release.toml?ref=${publicationSha}`; + const descriptor = await options.readJson(endpoint); + const original = Buffer.from(descriptor.content, 'base64').toString('utf8'); + for (const [text, expected] of [ + [ + original.replace( + /registry_packages\s*=\s*\[/u, + 'registry_packages = ["crates:retired-published-carrier",', + ), + 'completed-carrier-missing:cargo:retired-published-carrier', + ], + [ + original.replace( + /publish_targets\s*=\s*\[/u, + 'publish_targets = ["swift-package-source-tag",', + ), + 'authenticated-swift-source-tag-delivery-missing', + ], + ]) { + const bytes = Buffer.from(text); + const altered = { + ...descriptor, + content: bytes.toString('base64'), + sha: createHash('sha1').update(`blob ${bytes.length}\0`).update(bytes).digest('hex'), + }; + const readJson = async (request) => + request === endpoint ? altered : options.readJson(request); + const result = await compareNativeCompletedPhysicalDelivery(candidate, baselines, { + ...options, + readJson, + }); + expect(result.products.find(({ product }) => product === target.id)!.deliveryStatus).toBe( + 'unknown', + ); + expect(result.products.find(({ product }) => product === target.id)!.unknowns).toContain( + expected, + ); + } +}); + +test('complete canonical runtime inventory uses its genuine completed contrib declarations', async () => + asyncScratch(async (directory) => { + const publication = JSON.parse( + readFileSync( + new URL( + '../../build_defs/release/native-0.3.3-completed-publication.json', + import.meta.url, + ), + 'utf8', + ), + ); + const catalog = loadPublicationCatalog('completed contrib comparison fixture', { + products: [publication.product], + }); + const product = catalog.products[0]; + expect(product.version).toBe(publication.version); + const publicFiles = await publicFixture( + path.join(directory, 'public'), + product.id, + product.version, + ); + Object.assign(publicFiles.input.publication, publication); + publicFiles.release.target_commitish = publication.publicationSha; + const registryResponses = new Map Response>(); + const oldCarriers: Record = {}; + const carriers = []; + // The inventory is the actual canonical runtime inventory. Local packed + // bytes and controlled transports exercise its full comparison; they are + // not presented as genuinely published runtime binaries or qualification. + for (const [index, declared] of catalog.carriers.entries()) { + const root = path.join(directory, 'registry', String(index)); + mkdirSync(root, { recursive: true }); + let packed: string[]; + if (declared.ecosystem === 'maven') { + const [groupId, artifactId] = declared.name.split(':'); + const prefix = path.join(root, `${artifactId}-${product.version}`); + writeFileSync( + `${prefix}.pom`, + mavenPom({ + coordinate: { groupId, artifactId, version: product.version, packaging: 'jar' }, + metadata, + dependencies: [], + }), + ); + for (const suffix of ['.jar', '-sources.jar', '-javadoc.jar']) + writeFileSync( + prefix + suffix, + zipArchive([{ name: 'declared-member', data: declared.id }]), + ); + packed = ['.pom', '.jar', '-sources.jar', '-javadoc.jar'].map((suffix) => prefix + suffix); + for (const file of packed) + registryResponses.set( + `https://repo1.maven.org/maven2/${groupId.replaceAll('.', '/')}/${artifactId}/${product.version}/${path.basename(file)}`, + () => new Response(readFileSync(file)), + ); + } else { + const stage = path.join(root, 'stage'); + const member = + declared.ecosystem === 'cargo' ? `${declared.name}-${product.version}` : 'package'; + mkdirSync(path.join(stage, member), { recursive: true }); + writeFileSync( + path.join(stage, member, declared.ecosystem === 'cargo' ? 'Cargo.toml' : 'package.json'), + declared.ecosystem === 'cargo' + ? `[package]\nname=${JSON.stringify(declared.name)}\nversion=${JSON.stringify(product.version)}\nedition="2024"\n` + : JSON.stringify({ + name: declared.name, + version: product.version, + repository: { type: 'git', url: 'git+https://github.com/f0rr0/oliphaunt.git' }, + publishConfig: { access: 'public', provenance: true }, + }), + ); + writeFileSync( + path.join(stage, member, 'README.md'), + `Exact delivered member for ${declared.id}\n`, + ); + const file = path.join( + root, + declared.ecosystem === 'cargo' ? 'package.crate' : 'package.tgz', + ); + await archiveDirectory(stage, file + '.tar.gz'); + renameSync(file + '.tar.gz', file); + packed = [file]; + registryResponses.set( + declared.ecosystem === 'cargo' + ? `https://crates.io/api/v1/crates/${encodeURIComponent(declared.name)}/${product.version}` + : `https://registry.npmjs.org/${encodeURIComponent(declared.name)}/${product.version}`, + () => + Response.json( + declared.ecosystem === 'cargo' + ? { version: { checksum: hash(file) } } + : { + dist: { + integrity: `sha512-${createHash('sha512').update(readFileSync(file)).digest('base64')}`, + }, + }, + ), + ); + } + oldCarriers[declared.id] = packed; + const currentFiles = packed.map((file) => { + const current = path.join(root, 'current', path.basename(file)); + mkdirSync(path.dirname(current), { recursive: true }); + copyFileSync(file, current); + return current; + }); + carriers.push({ + ...declared, + parentCarrier: null, + part: null, + dependencies: [], + packageDependencies: [], + artifacts: currentFiles.map(artifact), + publishOrder: index, + }); + } + const productArtifacts = publicFiles.rows.map(({ version: _version, ...row }) => ({ + ...row, + ...artifact(publicFiles.input.files[row.id]), + })); + const candidate = { + schema: PUBLICATION_CANDIDATE_SCHEMA, + catalogSchema: PUBLICATION_CATALOG_SCHEMA, + catalogDigest: publicationCatalogDigest(catalog), + source: sourceIdentity('HEAD'), + scope: 'construction', + products: catalog.products, + carriers, + productArtifacts, + missing: [], + packageEnvelopeDigest: consumerDigest({ carriers, productArtifacts }), + }; + validatePublicationCandidate(candidate); + const sourceFiles = new Map(); + const options = { + assertCompletedPublication: publicFiles.options.assertCompletedPublication, + readPages: publicFiles.options.readPages, + readJson: async (endpoint: string) => { + if (endpoint.includes('/releases/tags/')) return publicFiles.options.readJson(endpoint); + const match = endpoint.match( + /^repos\/f0rr0\/oliphaunt\/contents\/(.+)\?ref=([a-f0-9]{40})$/u, + ); + if (!match || match[2] !== publication.publicationSha) + throw new Error(`unexpected historical source endpoint ${endpoint}`); + const file = match[1]; + if (!sourceFiles.has(file)) + sourceFiles.set( + file, + execFileSync('git', ['show', `${publication.publicationSha}:${file}`]), + ); + const bytes = sourceFiles.get(file); + if (!bytes) throw new Error(`missing historical fixture ${file}`); + return { + type: 'file', + path: file, + encoding: 'base64', + content: bytes.toString('base64'), + sha: createHash('sha1').update(`blob ${bytes.length}\0`).update(bytes).digest('hex'), + }; + }, + registryOptions: { + cratesIoReadGate: null, + fetchImpl: async (url) => { + const response = registryResponses.get(String(url)); + if (!response) throw new Error(`unexpected registry fixture ${url}`); + return response(); + }, + }, + }; + const baseline = [ + { publication, carriers: oldCarriers, productArtifacts: publicFiles.input.files }, + ]; + const result = await compareNativeCompletedPhysicalDelivery(candidate, baseline, options); + expect(result.products[0].unknowns).toEqual([]); + expect(result.products[0].deliveryStatus).toBe('identical'); + expect(result.products[0].comparisons).toHaveLength( + carriers.length + publicFiles.rows.filter(({ kind }) => kind !== 'checksums').length, + ); + expect(sourceFiles.size).toBe(12); + let random = 0x5eed; + for (let scenario = 0; scenario < 4; scenario++) { + const entries = Object.entries(oldCarriers); + for (let index = entries.length - 1; index > 0; index--) { + random = (Math.imul(random, 1664525) + 1013904223) >>> 0; + const swap = random % (index + 1); + [entries[index], entries[swap]] = [entries[swap], entries[index]]; + } + expect( + await compareNativeCompletedPhysicalDelivery( + candidate, + [ + { + ...baseline[0], + carriers: Object.fromEntries(entries), + }, + ], + options, + ), + ).toEqual(result); + } + // Controlled sealed-inventory fixture; actual parent-archive dependency checks run at acquisition. + const historical = await readCompletedNativeDeliveryInventory(publication, options); + const frozenMetadata: any = { + publication, + metadata: { + repository: 'f0rr0/oliphaunt', + source: { commit: publication.publicationSha, tree: publication.publicationTree }, + product, + carriers: structuredClone(carriers), + productArtifacts: productArtifacts.filter(({ kind }) => kind !== 'checksums'), + }, + }; + const oldRole = frozenMetadata.metadata.carriers.find(({ ecosystem }) => ecosystem === 'cargo'); + oldRole.role = 'retired-source-contract'; + oldRole.target = 'retired-target-v1'; + const visited = new Set(); + const frozenOptions = { + ...options, + assertMetadataBaseline: (value) => value, + readJson: async (endpoint: string) => { + if (endpoint.includes('/contents/')) { + const file = endpoint.match(/\/contents\/(.+)\?ref=/u)?.[1]; + expect([ + 'release-please-config.json', + '.release-please-manifest.json', + `${product.path}/release.toml`, + ]).toContain(file); + visited.add(file!); + } + return options.readJson(endpoint); + }, + }; + const frozenResult = await compareNativeCompletedPhysicalDelivery( + candidate, + [{ ...baseline[0], metadataBaseline: frozenMetadata }], + frozenOptions, + ); + expect(frozenResult.products[0].deliveryStatus).toBe('identical'); + expect(frozenResult.products[0].unknowns).toEqual([]); + expect(frozenResult.products[0].contractChanges).toEqual({ added: [], removed: [] }); + expect(visited.size).toBe(3); + const parent = frozenMetadata.metadata.carriers.find( + ({ ecosystem, role }) => ecosystem === 'cargo' && role === 'platform-leaf', + ); + if (!parent) throw new Error('runtime inventory fixture has no split-capable Cargo parent'); + const parts = [1, 2].map((number) => { + const name = `${parent.name}-part-${String(number).padStart(3, '0')}`; + return { + ...resolveActualCarrier(historical.catalog, 'cargo', name), + artifacts: [{ ...parent.artifacts[0], path: `original/${name}-${product.version}.crate` }], + packageDependencies: [], + }; + }); + parent.packageDependencies = parts.map(({ name }) => ({ ecosystem: 'cargo', name })); + frozenMetadata.metadata.carriers.push(...parts); + const frozen = await readCompletedNativeDeliveryInventory(publication, { + ...options, + metadataBaseline: frozenMetadata, + assertMetadataBaseline: (value) => value, + }); + expect(frozen.catalog.carriers).toEqual(frozen.carriers); + expect(frozen.carriers).toHaveLength(carriers.length + 2); + expect( + frozen.carriers.filter(({ role }) => role === 'payload-part').map(({ id }) => id), + ).toEqual(parts.map(({ id }) => id)); + const incomplete = structuredClone(frozenMetadata); + incomplete.metadata.carriers.pop(); + await expect( + readCompletedNativeDeliveryInventory(publication, { + ...options, + metadataBaseline: incomplete, + assertMetadataBaseline: (value) => value, + }), + ).rejects.toThrow('complete Cargo payload part set'); + const expanded = carriers.find(({ name }) => name === 'oliphaunt-extension-contrib-pg18'); + expect(expanded).toBeDefined(); + const file = expanded.artifacts[0].path; + const entries = [...readPortableArchiveEntries(file).values()].map((entry) => ({ + name: entry.name + (entry.isDirectory ? '/' : ''), + type: entry.isFile ? '0' : '5', + mode: entry.mode, + data: entry.isFile ? entry.data() : Buffer.alloc(0), + })); + const docs = entries.find(({ name }) => name.endsWith('/README.md')); + if (!docs) throw new Error('fixture lacks delivered contrib documentation'); + docs.data = Buffer.from('actual changed contrib delivered documentation'); + writeFileSync(file, tarArchive(entries)); + expanded.artifacts = [artifact(file)]; + candidate.packageEnvelopeDigest = consumerDigest({ carriers, productArtifacts }); + const changed = await compareNativeCompletedPhysicalDelivery(candidate, baseline, options); + expect(changed.products[0].deliveryStatus).toBe('different'); + expect( + changed.products[0].comparisons.find(({ id }) => id === expanded.id).differentMembers, + ).toEqual(['README.md']); + expect(changed.releaseDecision).toBe('unverified'); + })); + +function historicalFileResponse(file: string, contents: string) { + const bytes = Buffer.from(contents); + return { + type: 'file', + path: file, + encoding: 'base64', + content: bytes.toString('base64'), + sha: createHash('sha1').update(`blob ${bytes.length}\0`).update(bytes).digest('hex'), + }; +} + +test('missing published baselines cannot become first deliveries through explicit IDs', async () => { + const candidate = { + ...buildPublicationCandidate({ products: sourceProducts, artifactRoots: [sourceFixture] }), + scope: 'construction', + }; + const options = originEnvironment(); + const baseline = await origins(options); + const remaining = baseline.filter(({ publication }) => publication.product !== 'oliphaunt-query'); + expect( + (await compareNativeCompletedPhysicalDelivery(candidate, remaining, options)).products.find( + ({ product }) => product === 'oliphaunt-query', + )!.deliveryStatus, + ).toBe('unknown'); + for (const unreleasedProducts of [ + ['oliphaunt-query'], + ['foreign'], + ['oliphaunt-query', 'oliphaunt-query'], + ['oliphaunt-query-ts'], + ]) + await expect( + compareNativeCompletedPhysicalDelivery(candidate, remaining, { + ...options, + unreleasedProducts, + }), + ).rejects.toThrow('unique explicit version-zero products'); +}); + +test('verified historical registry additions and removals compare as necessary contract changes', async () => { + const candidate = { + ...buildPublicationCandidate({ products: sourceProducts, artifactRoots: [sourceFixture] }), + scope: 'construction', + }; + const options = originEnvironment(); + const baselines = await origins(options); + const owner = candidate.products.find(({ id }) => id === 'oliphaunt-query')!; + const file = `${owner.path}/release.toml`; + const endpoint = `repos/f0rr0/oliphaunt/contents/${file}?ref=${publicationSha}`; + const original = Buffer.from((await options.readJson(endpoint)).content, 'base64').toString( + 'utf8', + ); + const history = async (text: string) => ({ + ...options, + readJson: async (request: string) => + request === endpoint ? historicalFileResponse(file, text) : options.readJson(request), + }); + const added = structuredClone(baselines); + added[0].carriers = {}; + const addition = await compareNativeCompletedPhysicalDelivery( + candidate, + added, + await history(original.replace('"crates:oliphaunt-query"', '')), + ); + expect(addition.products[0].deliveryStatus).toBe('different'); + expect(addition.products[0].contractChanges.added).toEqual(['cargo:oliphaunt-query']); + expect(addition.products[0].unknowns).toEqual([]); + const removed = structuredClone(baselines); + removed[0].carriers['npm:@oliphaunt/ts-query'] = baselines[1].carriers['npm:@oliphaunt/ts-query']; + const removal = await compareNativeCompletedPhysicalDelivery( + candidate, + removed, + await history( + original.replace( + '"crates:oliphaunt-query"', + '"crates:oliphaunt-query", "npm:@oliphaunt/ts-query"', + ), + ), + ); + expect(removal.products[0].deliveryStatus).toBe('different'); + expect(removal.products[0].contractChanges.removed).toEqual(['npm:@oliphaunt/ts-query']); + expect(removal.products[0].unknowns).toEqual([]); + const missing = structuredClone(removed); + delete missing[0].carriers['npm:@oliphaunt/ts-query']; + expect( + ( + await compareNativeCompletedPhysicalDelivery( + candidate, + missing, + await history( + original.replace( + '"crates:oliphaunt-query"', + '"crates:oliphaunt-query", "npm:@oliphaunt/ts-query"', + ), + ), + ) + ).products[0].deliveryStatus, + ).toBe('unknown'); + await asyncScratch(async (directory) => { + const file = path.join(directory, 'retired.tgz'); + const originalArchive = removed[0].carriers['npm:@oliphaunt/ts-query'][0]; + const rows = [...readPortableArchiveEntries(originalArchive).values()].map((entry) => ({ + name: entry.name + (entry.isDirectory ? '/' : ''), + type: entry.isFile ? '0' : '5', + mode: entry.mode, + data: entry.isFile ? entry.data() : Buffer.alloc(0), + })); + const docs = rows.find(({ name }) => name.endsWith('/README.md')); + if (!docs) throw new Error('retired supplier fixture has no README'); + docs.data = Buffer.from('substituted retired contract'); + writeFileSync(file, tarArchive(rows)); + const changed = structuredClone(removed); + changed[0].carriers['npm:@oliphaunt/ts-query'] = [file]; + await expect( + compareNativeCompletedPhysicalDelivery( + candidate, + changed, + await history( + original.replace( + '"crates:oliphaunt-query"', + '"crates:oliphaunt-query", "npm:@oliphaunt/ts-query"', + ), + ), + ), + ).rejects.toThrow(/checksum|integrity|payload mismatch/); + }); +}); + +test('historical inventory uses exact owner path and targets rather than current directories or defaults', async () => + asyncScratch(async (directory) => { + const fixture = await publicFixture(directory, 'oliphaunt-broker'); + const original = fixture.options.readJson; + const oldPath = 'historical/broker'; + const readJson = async (endpoint: string) => { + const match = endpoint.match(/^repos\/f0rr0\/oliphaunt\/contents\/(.+)\?ref=/u); + if (!match) return original(endpoint); + const file = match[1]; + if (file === 'release-please-config.json') + return historicalFileResponse( + file, + JSON.stringify({ packages: { [oldPath]: { component: 'oliphaunt-broker' } } }), + ); + if (file === '.release-please-manifest.json') + return historicalFileResponse( + file, + JSON.stringify({ [oldPath]: fixture.input.publication.version }), + ); + if (file === `${oldPath}/release.toml`) + return historicalFileResponse( + file, + 'id="oliphaunt-broker"\nkind="tool"\npublish_targets=["github-release-assets"]\nregistry_packages=[]\n' + + '[artifact_targets]\npreset="broker-helper"\ntargets=["macos-arm64"]\n', + ); + throw new Error(`unexpected current-source request ${file}`); + }; + const inventory = await readCompletedNativeDeliveryInventory(fixture.input.publication, { + ...fixture.options, + readJson, + }); + expect(inventory.catalog.products[0].path).toBe(oldPath); + expect( + inventory.publicRows.map(({ target }) => target).filter((target) => target !== 'portable'), + ).toEqual(['macos-arm64']); + const legacy = await readCompletedNativeDeliveryInventory(fixture.input.publication, { + ...fixture.options, + readJson: async (endpoint: string) => { + if (endpoint.includes(`/contents/${oldPath}/moon.yml?`)) + return historicalFileResponse( + `${oldPath}/moon.yml`, + `id: oliphaunt-broker\nproject:\n release:\n component: oliphaunt-broker\n packagePath: ${oldPath}\n artifactTargets:\n preset: broker-helper\n targets: [macos-arm64]\n`, + ); + if (endpoint.includes(`/contents/${oldPath}/release.toml?`)) + return historicalFileResponse( + `${oldPath}/release.toml`, + 'id="oliphaunt-broker"\nkind="tool"\npublish_targets=["github-release-assets"]\nregistry_packages=[]\n', + ); + return readJson(endpoint); + }, + }); + expect(legacy.publicRows).toEqual(inventory.publicRows); + expect(legacy.sourceFiles.some(({ path: file }) => file === `${oldPath}/moon.yml`)).toBe(true); + const invalid = async (endpoint: string) => { + const response = await readJson(endpoint); + return endpoint.includes(`/contents/${oldPath}/release.toml?`) + ? { ...response, sha: '0'.repeat(40) } + : response; + }; + await expect( + readCompletedNativeDeliveryInventory(fixture.input.publication, { + ...fixture.options, + readJson: invalid, + }), + ).rejects.toThrow('Git blob differs'); + await expect( + readCompletedNativeDeliveryInventory(fixture.input.publication, { + ...fixture.options, + readJson: async () => { + throw new Error('history inaccessible'); + }, + }), + ).rejects.toThrow('history inaccessible'); + })); + +test('external public inventory captures its exact historical runtime owner tables and iOS closure', async () => + asyncScratch(async (directory) => { + const fixture = await publicFixture(directory, 'oliphaunt-extension-postgis'); + const inventory = await readCompletedNativeDeliveryInventory( + fixture.input.publication, + fixture.options, + ); + expect(inventory.publicRows).toEqual(fixture.rows); + const files = inventory.sourceFiles.map(({ path: file }) => file); + for (const file of [ + 'src/extensions/contrib/carriers.toml', + 'src/native/runtime/release.toml', + 'src/wasix/runtime/release.toml', + 'src/extensions/contracts/extension-target-profiles.toml', + 'src/extensions/generated/sdk/extensions.json', + 'src/extensions/generated/mobile/static-extensions.tsv', + ]) + expect(files).toContain(file); + expect(inventory.publicRows.some(({ kind }) => kind === 'ios-dependency-xcframework')).toBe( + true, + ); + expect( + (await captureCompletedNativePublicArtifacts(fixture.input, fixture.options)).unknowns, + ).toEqual([]); + })); + +test('frozen public names and File identities survive changed current filename templates', async () => + asyncScratch(async (directory) => { + const fixture = await publicFixture(directory, 'oliphaunt-broker'); + const row = fixture.rows.find(({ target }) => target === 'macos-arm64'); + if (!row) throw new Error('broker fixture has no macOS archive'); + const oldName = `old-broker-${fixture.input.publication.version}-macos.tar.gz`; + const oldId = `github-release:${oldName}`; + const files = { ...fixture.input.files, [oldId]: fixture.input.files[row.id] }; + delete files[row.id]; + const asset = fixture.assets.find(({ name }) => name === row.name); + if (!asset) throw new Error('broker fixture has no macOS asset'); + asset.name = oldName; + const metadataBaseline: any = { + publication: fixture.input.publication, + metadata: { + repository: 'f0rr0/oliphaunt', + source: { + commit: fixture.input.publication.publicationSha, + tree: fixture.input.publication.publicationTree, + }, + product: { + id: fixture.input.publication.product, + version: fixture.input.publication.version, + }, + carriers: [], + productArtifacts: fixture.rows + .filter(({ kind }) => kind !== 'checksums') + .map((item) => ({ + ...item, + ...(item.id === row.id ? { id: oldId, name: oldName } : {}), + ...artifact(fixture.input.files[item.id]), + })), + }, + }; + const visited = new Set(); + const options = { + ...fixture.options, + assertMetadataBaseline: (value) => value, + readJson: async (endpoint: string) => { + if (endpoint.includes('/contents/')) { + const file = endpoint.match(/\/contents\/(.+)\?ref=/u)?.[1]; + expect([ + 'release-please-config.json', + '.release-please-manifest.json', + 'src/native/broker/release.toml', + ]).toContain(file); + visited.add(file!); + } + if (endpoint.includes('/contents/src/native/broker/release.toml?')) + return historicalFileResponse( + 'src/native/broker/release.toml', + 'id="oliphaunt-broker"\nkind="retired-factory-v1"\npublish_targets=["github-release-assets"]\nregistry_packages=[]\n', + ); + return fixture.options.readJson(endpoint); + }, + }; + const inventory = await readCompletedNativeDeliveryInventory(fixture.input.publication, { + ...options, + metadataBaseline, + }); + expect(inventory.publicRows.some(({ name }) => name === oldName)).toBe(true); + expect(inventory.publicRows.some(({ name }) => name === row.name)).toBe(false); + expect(inventory.publicRows.every(({ kind }) => kind !== 'checksums')).toBe(true); + expect(visited.size).toBe(3); + expect( + ( + await captureCompletedNativePublicArtifacts( + { ...fixture.input, files, metadataBaseline }, + options, + ) + ).unknowns, + ).toEqual([]); + const checksumAsset = fixture.assets.find(({ name }) => name.endsWith('.sha256'))!; + checksumAsset.name = 'retired-outer-envelope.sha256'; + const payloadFiles = Object.fromEntries( + Object.entries(files).filter(([id]) => !id.endsWith('.sha256')), + ); + const capture = () => + captureCompletedNativePublicArtifacts( + { ...fixture.input, files: payloadFiles, metadataBaseline }, + options, + ); + expect((await capture()).unknowns).toEqual([]); + fixture.assets.push({ ...checksumAsset }); + expect((await capture()).unknowns).toContain('completed-public-asset-inventory-differs'); + fixture.assets.pop(); + fixture.assets.push({ ...checksumAsset, name: 'unlisted-delivery.bin' }); + expect((await capture()).unknowns).toContain('completed-public-asset-inventory-differs'); + fixture.assets.pop(); + const missingFile = { ...payloadFiles }; + delete missingFile[oldId]; + expect( + ( + await captureCompletedNativePublicArtifacts( + { ...fixture.input, files: missingFile, metadataBaseline }, + options, + ) + ).unknowns, + ).toContain(`completed-public-artifact-missing:${oldId}`); + await expect( + readCompletedNativeDeliveryInventory(fixture.input.publication, { + ...fixture.options, + metadataBaseline: structuredClone(metadataBaseline), + }), + ).rejects.toThrow('authenticated completed metadata origin'); + await expect( + readCompletedNativeDeliveryInventory(fixture.input.publication, { + ...options, + metadataBaseline, + assertMetadataBaseline: () => undefined, + }), + ).rejects.toThrow('authentication returned no baseline'); + const wrongSource = structuredClone(metadataBaseline); + wrongSource.metadata.source.commit = 'f'.repeat(40); + await expect( + readCompletedNativeDeliveryInventory(fixture.input.publication, { + ...options, + metadataBaseline: wrongSource, + }), + ).rejects.toThrow('source/product/version differs'); + const wrongHash = structuredClone(metadataBaseline); + wrongHash.metadata.productArtifacts.find(({ id }) => id === oldId).sha256 = 'f'.repeat(64); + await expect( + captureCompletedNativePublicArtifacts( + { ...fixture.input, files, metadataBaseline: wrongHash }, + options, + ), + ).rejects.toThrow('File differs from frozen metadata'); + const wrongOwner = structuredClone(metadataBaseline); + wrongOwner.metadata.productArtifacts[0].product = 'foreign'; + await expect( + readCompletedNativeDeliveryInventory(fixture.input.publication, { + ...options, + metadataBaseline: wrongOwner, + }), + ).rejects.toThrow('frozen public File identity differs'); + const wrongVersion = structuredClone(metadataBaseline); + wrongVersion.metadata.productArtifacts[0].version = '99.0.0'; + await expect( + readCompletedNativeDeliveryInventory(fixture.input.publication, { + ...options, + metadataBaseline: wrongVersion, + }), + ).rejects.toThrow('frozen public version differs'); + })); + +test('frozen registry inventory binds actual archive filenames and hashes before held supplier capture', async () => { + const options = originEnvironment(); + const input = (await origins(options))[0]; + const inventory = await readCompletedNativeDeliveryInventory(input.publication, options); + const metadataBaseline: any = { + publication: input.publication, + metadata: { + repository: 'f0rr0/oliphaunt', + source: { commit: input.publication.publicationSha, tree: input.publication.publicationTree }, + product: { id: input.publication.product, version: input.publication.version }, + carriers: inventory.catalog.carriers.map((carrier) => ({ + ...carrier, + artifacts: input.carriers[carrier.id].map(artifact), + packageDependencies: [], + })), + productArtifacts: [], + }, + }; + const transport = { ...options, assertMetadataBaseline: (value) => value }; + metadataBaseline.metadata.carriers[0].role = 'retired-classifier-role'; + metadataBaseline.metadata.carriers[0].target = 'retired-target-v1'; + expect( + (await captureCompletedNativeRegistryCarriers({ ...input, metadataBaseline }, transport)) + .unknowns, + ).toEqual([]); + await expect( + captureCompletedNativeRegistryCarriers( + { + ...input, + metadataBaseline, + carriers: { ...input.carriers, 'cargo:foreign': input.carriers['cargo:oliphaunt-query'] }, + }, + transport, + ), + ).rejects.toThrow('absent from frozen metadata'); + const wrongOwner = structuredClone(metadataBaseline); + wrongOwner.metadata.carriers[0].product = 'foreign'; + await expect( + readCompletedNativeDeliveryInventory(input.publication, { + ...transport, + metadataBaseline: wrongOwner, + }), + ).rejects.toThrow('frozen registry ownership differs'); + const changed = structuredClone(metadataBaseline); + changed.metadata.carriers[0].artifacts[0].sha256 = 'f'.repeat(64); + await expect( + captureCompletedNativeRegistryCarriers({ ...input, metadataBaseline: changed }, transport), + ).rejects.toThrow('Files differ from frozen metadata'); + const missing = structuredClone(metadataBaseline); + missing.metadata.carriers = []; + await expect( + readCompletedNativeDeliveryInventory(input.publication, { + ...transport, + metadataBaseline: missing, + }), + ).rejects.toThrow('omits a historical declaration'); +}); diff --git a/tools/release/native-configured-inputs.mts b/tools/release/native-configured-inputs.mts new file mode 100644 index 000000000..2bd3ccf38 --- /dev/null +++ b/tools/release/native-configured-inputs.mts @@ -0,0 +1,228 @@ +import assert from 'node:assert/strict'; +import { canonicalShippingLabel } from './bazel-shipping-inputs.mts'; + +export function nativeConfiguredWorkspaceLabel(value: string): string { + value = canonicalShippingLabel(value); + if (!/^\/\/[A-Za-z0-9_./+-]*:[A-Za-z0-9_./+-]+$/u.test(value)) + throw new Error(`shipping qualification requires an explicit workspace target: ${value}`); + return value; +} + +export type RecipeRoot = { label: string; configuration: string }; +export type RecipeGraph = { + labels: string[]; + packages: { package: string; label: string }[]; + roots: { label: string; packages: string[] }[]; + sourceRoots?: { label: string; configuration: string; labels: string[] }[]; +}; + +/** Index Bazel's configured edges once; do not expand selects in the loading graph. */ +export function configuredRecipeGraph( + raw: any, + roots: RecipeRoot[], + unionOnly = false, + rootSourceFilter?: (label: string) => boolean, +): RecipeGraph { + assert( + Array.isArray(raw?.results) && Array.isArray(raw.configurations), + 'configured recipe graph is missing', + ); + const configurations = new Map(); + for (const config of raw.configurations) { + assert(/^[a-f0-9]{64}$/u.test(config.checksum), 'configured recipe checksum is invalid'); + assert(!configurations.has(String(config.id)), 'duplicate configured recipe ID'); + configurations.set(String(config.id), config.checksum); + } + const checksum = (value: any) => { + const id = value.configurationId; + const declared = value.configurationChecksum ?? value.configuration?.checksum; + if (id === undefined || id === 0) { + assert( + declared === undefined || declared === 'null', + 'configured recipe reference lacks an ID', + ); + return 'null'; + } + const result = configurations.get(String(id)); + assert(result, 'configured recipe reference is missing'); + assert(declared === undefined || declared === result, 'configured recipe checksum differs'); + return result; + }; + const targetLabel = (value: unknown) => { + assert( + typeof value === 'string' && !/[\u0000-\u001f\u007f]/u.test(value), + 'configured recipe label is invalid', + ); + const result = canonicalShippingLabel(value); + assert(/^(?:@@?[^/]+)?\/\/[^:]*:.+$/u.test(result), 'configured recipe label is not explicit'); + return result; + }; + const key = (name: string, config: string) => `${name}\0${config}`; + const nodes = new Map< + string, + { label: string; kind: string; ruleClass?: string; edges: string[] } + >(); + for (const result of raw.results) { + const target = result.target; + const config = checksum(result); + const name = targetLabel( + target?.rule?.name ?? + target?.sourceFile?.name ?? + target?.generatedFile?.name ?? + target?.packageGroup?.name, + ); + const id = key(name, config); + const kind = target.rule + ? 'rule' + : target.sourceFile + ? 'source-file' + : target.generatedFile + ? 'generated-file' + : 'package-group'; + const edges = (target.rule?.configuredRuleInput ?? []).map((dep: any) => + key(targetLabel(dep.label), checksum(dep)), + ); + if (target.generatedFile) + edges.push(key(targetLabel(target.generatedFile.generatingRule), config)); + if (target.packageGroup) + edges.push( + ...(target.packageGroup.includedPackageGroup ?? []).map((name: string) => + key(targetLabel(name), 'null'), + ), + ); + // The stock cquery stream can repeat a node; only an identical definition is unambiguous. + const node = { + label: name, + kind, + ruleClass: target.rule?.ruleClass, + edges: [...new Set(edges)].sort(), + }; + const previous = nodes.get(id); + if (previous) assert.deepEqual(previous, node, 'conflicting configured recipe target'); + else nodes.set(id, node); + } + const labels = new Set(); + const names = new Set(); + const unionVisited = new Set(); + const unionActive = new Set(); + const sourceRoots: NonNullable = []; + const mapped = roots.map((root) => { + const name = targetLabel(root.label); + const rootId = key(name, root.configuration); + assert( + !names.has(rootId) && /^[a-f0-9]{64}$/u.test(root.configuration), + 'configured recipe roots are ambiguous', + ); + names.add(rootId); + const visited = unionOnly && !rootSourceFilter ? unionVisited : new Set(); + const active = unionOnly && !rootSourceFilter ? unionActive : new Set(); + const packages = new Set(); + const sourceLabels = new Set(); + const pending = [{ id: key(name, root.configuration), exit: false }]; + while (pending.length) { + const current = pending.pop(); + assert(current); + if (current.exit) { + active.delete(current.id); + visited.add(current.id); + continue; + } + if (visited.has(current.id)) continue; + assert(!active.has(current.id), 'cycle in configured recipe dependencies'); + const node = nodes.get(current.id); + assert(node, 'configured recipe dependency is missing'); + active.add(current.id); + labels.add(node.label); + if (node.kind === 'source-file' && rootSourceFilter?.(node.label)) + sourceLabels.add(node.label); + packages.add(node.label.slice(0, node.label.indexOf(':'))); + pending.push( + { id: current.id, exit: true }, + ...node.edges.map((id) => ({ id, exit: false })), + ); + } + if (rootSourceFilter) + sourceRoots.push({ + label: name, + configuration: root.configuration, + labels: [...sourceLabels].sort(), + }); + return { label: name, packages: [...packages].sort() }; + }); + const ordered = [...labels].sort(); + const packages = new Map(); + for (const name of ordered) { + const pkg = name.slice(0, name.indexOf(':')); + if (!packages.has(pkg)) packages.set(pkg, name); + } + return { + labels: ordered, + packages: [...packages].map(([pkg, name]) => ({ package: pkg, label: name })), + roots: unionOnly ? [] : mapped, + ...(rootSourceFilter ? { sourceRoots } : {}), + }; +} + +/** Publication roots retain their stronger unique workspace identity contract. */ +export function nativeConfiguredRecipeGraph(raw: any, roots: RecipeRoot[]): RecipeGraph { + const names = roots.map((root) => nativeConfiguredWorkspaceLabel(root.label)); + assert(new Set(names).size === names.length, 'configured recipe roots are ambiguous'); + return configuredRecipeGraph(raw, roots); +} + +/** Use real buildfiles label results: Bazel 8 omits BUILD.bazel subinclude in proto output. */ +export function nativeRecipeInputPaths( + graph: RecipeGraph, + queries: { packages: string[]; labels: string[] }[], +) { + const key = (packages: string[]) => JSON.stringify(packages); + const expected = new Set(graph.roots.map((root) => key(root.packages))); + const loaded = new Map(); + const workspacePath = (name: string) => { + assert( + typeof name === 'string' && !/[\u0000-\u001f\u007f]/u.test(name), + 'recipe source label is invalid', + ); + name = canonicalShippingLabel(name); + assert(/^(?:@@?[^/]+)?\/\/[^:]*:.+$/u.test(name), 'recipe source label is not explicit'); + if (!name.startsWith('//')) return undefined; + const separator = name.indexOf(':'); + const result = [name.slice(2, separator), name.slice(separator + 1)].filter(Boolean).join('/'); + assert( + result && + !name.includes('\\') && + !result.split('/').some((part) => part === '..' || part === '.' || !part), + 'recipe source path escapes', + ); + return result; + }; + for (const query of queries) { + assert(Array.isArray(query.packages), 'recipe package set is missing'); + const id = key(query.packages); + assert(expected.has(id) && !loaded.has(id), 'recipe package-set query is ambiguous'); + assert(Array.isArray(query.labels), 'recipe package sources are missing'); + const names = query.labels.map((name) => canonicalShippingLabel(name)); + assert(new Set(names).size === names.length, 'duplicate recipe source File'); + for (const pkg of query.packages.filter((pkg) => pkg.startsWith('//'))) { + const buildNames = names.filter( + (name) => name === `${pkg}:BUILD` || name === `${pkg}:BUILD.bazel`, + ); + assert(buildNames.length === 1, 'configured package BUILD File is missing or ambiguous'); + } + loaded.set( + id, + names.flatMap((name) => { + const file = workspacePath(name); + return file === undefined ? [] : [file]; + }), + ); + } + assert(loaded.size === expected.size, 'configured package-set recipe query is missing'); + return graph.roots.map((root) => { + const files = loaded.get(key(root.packages)); + assert(files, 'configured package-set recipe query is missing'); + const paths = new Set(files); + assert(paths.size, 'shipping analysis has no loaded workspace recipe sources'); + return { label: root.label, paths: [...paths].sort() }; + }); +} diff --git a/tools/release/native-extension-final-inputs.mts b/tools/release/native-extension-final-inputs.mts new file mode 100644 index 000000000..7e8e9703a --- /dev/null +++ b/tools/release/native-extension-final-inputs.mts @@ -0,0 +1,333 @@ +/** File aliases from the controller's existing authenticated producer transport. */ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileIdentity, safeRelative } from './native-file-identity.mts'; + +export type ExtensionFinalInputFile = { + path: string; + size: number; + sha256: string; + producer: { + evidenceDigest: string; + invocationId: string; + root: string; + configuration: string; + output: string; + }; + /** Existing captured TreeArtifact member path; absent for a regular output. */ + member?: string; +}; +/** Original payload carriers from the existing same-source producer handoff. */ +export type NativeCurrentArtifact = { + product: string; + version: string; + artifact: string; + configuration: string; + source: { commit: string; tree: string }; + file: ExtensionFinalInputFile; +}; +export type ExtensionFinalInput = { + product: string; + owner: string; + version: string; + family: 'native' | 'wasix'; + target: string; + github: ExtensionFinalInputFile[]; + npm: ExtensionFinalInputFile[]; + cargo: ExtensionFinalInputFile[]; + manifest: ExtensionFinalInputFile; + frozen: ExtensionFinalInputFile; +}; +export type NativeAppleBaseInput = { + owner: 'liboliphaunt-native'; + version: string; + file: ExtensionFinalInputFile; + framework: ExtensionFinalInputFile; + resources: ExtensionFinalInputFile; +}; +export type NativeSwiftSourceInput = { + owner: 'oliphaunt-swift'; + version: string; + archive: ExtensionFinalInputFile; + carrier: ExtensionFinalInputFile; + ownerCatalog: ExtensionFinalInputFile; + bindingsArchive: ExtensionFinalInputFile; +}; +function fields(value: unknown, names: string[], label: string) { + assert.ok( + value && typeof value === 'object' && !Array.isArray(value), + `${label} needs an object`, + ); + assert.deepEqual(Object.keys(value).sort(), names.sort(), `${label} fields differ`); +} +/** A fact-only regular File alias. The original controller authenticates its producer. */ +export function projectOriginalNativeFinalFile(file: ExtensionFinalInputFile, prefix: string) { + fields( + file, + ['path', 'size', 'sha256', 'producer', ...(file.member === undefined ? [] : ['member'])], + 'original native File', + ); + assert.ok(path.isAbsolute(file.path), 'original native import needs an absolute retained File'); + const actual = fileIdentity(file.path); + assert.deepEqual( + { size: actual.size, sha256: actual.sha256 }, + { size: file.size, sha256: file.sha256 }, + 'original native File bytes differ', + ); + fields( + file.producer, + ['evidenceDigest', 'invocationId', 'root', 'configuration', 'output'], + 'original native producer', + ); + assert.match(file.producer.evidenceDigest, /^sha256:[a-f0-9]{64}$/u); + assert.match(file.producer.configuration, /^[a-f0-9]{64}$/u); + assert.match(file.producer.root, /^\/\/[A-Za-z0-9_./+-]*:[A-Za-z0-9_.+-]+$/u); + const packagePath = file.producer.root.slice(2, file.producer.root.indexOf(':')); + if (packagePath) safeRelative(packagePath); + assert.ok( + typeof file.producer.invocationId === 'string' && + file.producer.invocationId.length && + !/[\u0000-\u001f\u007f]/u.test(file.producer.invocationId), + ); + safeRelative(file.producer.output); + if (file.member !== undefined) safeRelative(file.member); + safeRelative(prefix); + const basename = path.basename(file.path); + assert.match(basename, /^[A-Za-z0-9][A-Za-z0-9._-]*$/u); + const output = `${prefix}/${file.sha256}/${basename}`; + return { + file: { ...structuredClone(file), path: `@oliphaunt_metadata//:${output}` }, + alias: { source: file.path, path: output, size: file.size, sha256: file.sha256 }, + }; +} + +/** This projection preserves File facts; acquisition authenticates their original producer. */ +export function projectNativeCurrentArtifacts( + value: unknown, + source?: { commit: string; tree: string }, +) { + assert.ok(Array.isArray(value), 'current native artifacts need an array'); + const artifacts: Record = {}; + const files: ReturnType['alias'][] = []; + for (const row of value as NativeCurrentArtifact[]) { + fields( + row, + ['product', 'version', 'artifact', 'configuration', 'source', 'file'], + 'current native artifact', + ); + assert.match(row.product, /^[a-z][a-z0-9-]*$/u); + assert.match(row.version, /^\d+\.\d+\.\d+(?:[-+][A-Za-z0-9.-]+)?$/u); + assert.match(row.configuration, /^[A-Za-z0-9][A-Za-z0-9._-]*$/u); + fields(row.source, ['commit', 'tree'], 'current native artifact source'); + for (const sha of [row.source.commit, row.source.tree]) assert.match(sha, /^[a-f0-9]{40}$/u); + assert.deepEqual(row.source, source, 'current native artifact source differs'); + const match = row.artifact.match(/^(cargo|github-release):([A-Za-z0-9][A-Za-z0-9._-]*)$/u); + assert.ok(match, 'current native artifact needs a canonical carrier identity'); + if (match[1] === 'github-release') + assert.equal( + path.basename(row.file.path), + match[2], + 'current native artifact filename differs', + ); + else assert.ok(row.file.path.endsWith('.crate'), 'current native Cargo File needs .crate'); + const key = `${row.product}/${row.version}/${row.artifact}`; + assert.ok(!Object.hasOwn(artifacts, key), 'current native artifact repeats'); + const projected = projectOriginalNativeFinalFile( + row.file, + `native-current-artifacts/${row.product}/${row.version}`, + ); + artifacts[key] = { ...structuredClone(row), file: projected.file }; + files.push(projected.alias); + } + return { artifacts, files }; +} + +export function projectNativeAppleBaseInput(value: unknown) { + fields(value, ['owner', 'version', 'file', 'framework', 'resources'], 'native Apple base input'); + const input = value as NativeAppleBaseInput; + assert.equal(input.owner, 'liboliphaunt-native'); + assert.match(input.version, /^\d+\.\d+\.\d+(?:[-+][A-Za-z0-9.-]+)?$/u); + assert.equal( + input.file.member, + undefined, + 'Apple base manifest must remain its whole regular original File', + ); + assert.equal(path.basename(input.file.path), 'ios.json'); + const expected = { + file: ['ios.json', '//src/native/runtime:apple_ios_manifest_shipping'], + framework: [ + `liboliphaunt-${input.version}-apple-spm-xcframework.zip`, + '//src/native/runtime:apple_swiftpm_shipping', + ], + resources: [ + `liboliphaunt-${input.version}-runtime-resources-ios-datum64.tar.gz`, + '//src/native/runtime:apple_resources_shipping', + ], + }; + const projected = { owner: input.owner, version: input.version } as NativeAppleBaseInput; + const files = []; + for (const name of ['file', 'framework', 'resources'] as const) { + assert.equal( + input[name].member, + undefined, + 'Apple tuple requires whole original regular Files', + ); + assert.equal( + path.basename(input[name].path), + expected[name][0], + 'Apple original File name differs', + ); + assert.equal( + input[name].producer.root, + expected[name][1], + 'Apple original producer root differs', + ); + assert.equal( + input[name].producer.evidenceDigest, + input.file.producer.evidenceDigest, + 'Apple tuple mixes producer evidence', + ); + assert.equal( + input[name].producer.invocationId, + input.file.producer.invocationId, + 'Apple tuple mixes producer invocations', + ); + assert.equal( + input[name].producer.configuration, + input.file.producer.configuration, + 'Apple tuple mixes original configurations', + ); + const result = projectOriginalNativeFinalFile(input[name], `native-apple-base/${name}`); + projected[name] = result.file; + files.push(result.alias); + } + return { input: projected, files }; +} + +/** The final fixture consumes original source/control Files, never a source + * checkout or a re-created source ZIP under another version. */ +export function projectNativeSwiftSourceInput(value: unknown) { + fields( + value, + ['owner', 'version', 'archive', 'carrier', 'ownerCatalog', 'bindingsArchive'], + 'native Swift source input', + ); + const input = value as NativeSwiftSourceInput; + assert.equal(input.owner, 'oliphaunt-swift'); + assert.match(input.version, /^\d+\.\d+\.\d+(?:[-+][A-Za-z0-9.-]+)?$/u); + const expected = { + archive: 'Oliphaunt-source.zip', + carrier: 'oliphaunt-react-native-ios-carriers.json', + ownerCatalog: 'extension-owner-catalog.json', + bindingsArchive: `oliphaunt-swift-${input.version}-bindings.xcframework.zip`, + }; + const aliases = []; + const projected = { owner: input.owner, version: input.version } as NativeSwiftSourceInput; + for (const name of ['archive', 'carrier', 'ownerCatalog', 'bindingsArchive'] as const) { + assert.equal( + path.basename(input[name].path), + expected[name], + 'Swift source input name differs', + ); + if (name !== 'carrier') + assert.equal( + input[name].member, + undefined, + 'Swift source ZIP/catalog must remain whole original Files', + ); + const result = projectOriginalNativeFinalFile(input[name], `native-swift-source/${name}`); + assert.equal( + input[name].producer.evidenceDigest, + input.archive.producer.evidenceDigest, + 'Swift source tuple mixes producer evidence', + ); + assert.equal( + input[name].producer.invocationId, + input.archive.producer.invocationId, + 'Swift source tuple mixes producer invocations', + ); + projected[name] = result.file; + aliases.push(result.alias); + } + assert.equal( + input.bindingsArchive.producer.root, + '//src/native/sdks/swift:shipping_bindings', + 'Swift bindings File needs its original canonical shipping root', + ); + const carrier = JSON.parse(readFileSync(input.carrier.path, 'utf8')); + assert.equal(carrier.schema, 'oliphaunt-react-native-ios-carrier-v1'); + assert.equal(carrier.base?.product, 'liboliphaunt-native'); + assert.match(carrier.base.version, /^\d+\.\d+\.\d+(?:[-+][A-Za-z0-9.-]+)?$/u); + assert.equal(carrier.base.tag, `liboliphaunt-native-v${carrier.base.version}`); + assert.deepEqual(carrier.extensions, []); + assert.deepEqual(carrier.carriers, []); + return { input: { ...projected, nativeVersion: carrier.base.version }, files: aliases }; +} + +/** Byte checks bind the import; authentication remains with the original controller. */ +export function projectNativeExtensionFinalInputs(value: unknown) { + assert.ok(Array.isArray(value), 'extension final inputs need an array'); + const leaves: Record = {}; + const files = new Map(); + const refs = new Set(); + for (const input of value as ExtensionFinalInput[]) { + fields( + input, + [ + 'product', + 'owner', + 'version', + 'family', + 'target', + 'github', + 'npm', + 'cargo', + 'manifest', + 'frozen', + ], + 'extension final input', + ); + for (const id of [input.product, input.owner]) assert.match(id, /^[a-z0-9][a-z0-9-]*$/u); + assert.match(input.target, /^[a-z0-9][a-z0-9_-]*$/u); + assert.match(input.version, /^\d+\.\d+\.\d+(?:[-+][A-Za-z0-9.-]+)?$/u); + assert.ok(['native', 'wasix'].includes(input.family)); + assert.ok(input.family !== 'wasix' || input.target === 'wasix-portable'); + const slot = `${input.product}/${input.family}/${input.target}`; + assert.ok(!leaves[slot], 'duplicate extension final constructor slot'); + const alias = (file: ExtensionFinalInputFile) => { + const projected = projectOriginalNativeFinalFile( + file, + `extension-final-inputs/${input.product}/${input.family}/${input.target}`, + ); + const ref = JSON.stringify([file.producer, file.member ?? '']); + assert.ok(!refs.has(ref), 'extension original File repeats across constructor slots'); + refs.add(ref); + const output = projected.alias.path; + assert.ok(!files.has(output), 'extension final File alias repeats'); + files.set(output, projected.alias); + return projected.file; + }; + const groups = Object.fromEntries( + (['github', 'npm', 'cargo'] as const).map((name) => { + const group = input[name]; + assert.ok(Array.isArray(group)); + assert.ok( + group.length > 0 || + (name !== 'github' && + input.family === 'native' && + /^(android-|ios-)/u.test(input.target)), + 'desktop/WASIX import is missing a public carrier group', + ); + return [name, group.map(alias)]; + }), + ) as Pick; + leaves[slot] = { + ...input, + ...groups, + manifest: alias(input.manifest), + frozen: alias(input.frozen), + }; + } + return { leaves, files: [...files.values()] }; +} diff --git a/tools/release/native-extension-final-inputs.test.mts b/tools/release/native-extension-final-inputs.test.mts new file mode 100644 index 000000000..184d4c09a --- /dev/null +++ b/tools/release/native-extension-final-inputs.test.mts @@ -0,0 +1,278 @@ +import { expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + type ExtensionFinalInput, + projectNativeAppleBaseInput, + projectNativeCurrentArtifacts, + projectNativeExtensionFinalInputs, + projectNativeSwiftSourceInput, +} from './native-extension-final-inputs.mts'; + +function fixture() { + const directory = mkdtempSync(path.join(tmpdir(), 'extension-original-files-')); + const file = (name: string) => { + const bytes = Buffer.from(`original fixture ${name}`); + const source = path.join(directory, name); + mkdirSync(path.dirname(source), { recursive: true }); + writeFileSync(source, bytes); + return { + path: source, + size: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + producer: { + evidenceDigest: `sha256:${'3'.repeat(64)}`, + invocationId: 'original-qualified-invocation', + root: '//src/extensions/external/pgtap:native_frozen_shipping', + configuration: '4'.repeat(64), + output: `bazel-out/k8-opt/bin/${name}`, + }, + }; + }; + const leaf: ExtensionFinalInput = { + product: 'oliphaunt-extension-pgtap', + owner: 'oliphaunt-extension-pgtap', + version: '0.1.1', + family: 'native', + target: 'linux-x64-gnu', + github: [file('pgtap.tar.gz')], + npm: [file('pgtap.tgz')], + cargo: [{ ...file('cargo/pgtap.crate'), member: 'pgtap.crate' }], + manifest: file('manifest.json'), + frozen: file('extension-artifacts.json'), + }; + return { directory, leaf, file }; +} + +test('Swift source tuple retains the genuine binding producer and rejects version/cohort substitutions', () => { + const { directory, file } = fixture(); + try { + const carrier = file('oliphaunt-react-native-ios-carriers.json'); + const document = Buffer.from( + JSON.stringify({ + schema: 'oliphaunt-react-native-ios-carrier-v1', + base: { + product: 'liboliphaunt-native', + version: '0.3.3', + tag: 'liboliphaunt-native-v0.3.3', + }, + extensions: [], + carriers: [], + }), + ); + writeFileSync(carrier.path, document); + carrier.size = document.length; + carrier.sha256 = createHash('sha256').update(document).digest('hex'); + const bindingsArchive = file('oliphaunt-swift-0.8.3-bindings.xcframework.zip'); + bindingsArchive.producer.root = '//src/native/sdks/swift:shipping_bindings'; + const input = { + owner: 'oliphaunt-swift', + version: '0.8.3', + archive: file('Oliphaunt-source.zip'), + carrier, + ownerCatalog: file('extension-owner-catalog.json'), + bindingsArchive, + }; + const projected = projectNativeSwiftSourceInput(input); + expect(projected.files).toHaveLength(4); + expect(projected.input.bindingsArchive.producer).toEqual(bindingsArchive.producer); + expect(projected.input.bindingsArchive.path).toStartWith( + '@oliphaunt_metadata//:native-swift-source/bindingsArchive/', + ); + for (const change of [ + (value) => delete value.bindingsArchive, + (value) => (value.version = '0.8.4'), + (value) => (value.bindingsArchive.member = 'binding.zip'), + (value) => (value.bindingsArchive.producer.root = '//wrong:bindings'), + (value) => (value.bindingsArchive.producer.invocationId = 'different-candidate-run'), + (value) => (value.bindingsArchive.producer.evidenceDigest = `sha256:${'a'.repeat(64)}`), + (value) => (value.bindingsArchive.sha256 = '0'.repeat(64)), + ]) { + const changed = structuredClone(input); + change(changed); + expect(() => projectNativeSwiftSourceInput(changed)).toThrow(); + } + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('Apple base preserves the final manifest/archive tuple and rejects stale versions and mixed producer runs', () => { + const { directory, leaf, file: original } = fixture(); + try { + const source = path.join(directory, 'ios.json'); + const bytes = Buffer.from('actual original base manifest fixture'); + writeFileSync(source, bytes); + const file = { + ...leaf.manifest, + path: source, + size: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + producer: { + ...leaf.manifest.producer, + root: '//src/native/runtime:apple_ios_manifest_shipping', + output: 'bazel-out/config/bin/apple_release_assets/ios.json', + }, + }; + const framework = original('liboliphaunt-0.3.3-apple-spm-xcframework.zip'); + framework.producer.root = '//src/native/runtime:apple_swiftpm_shipping'; + const resources = original('liboliphaunt-0.3.3-runtime-resources-ios-datum64.tar.gz'); + resources.producer.root = '//src/native/runtime:apple_resources_shipping'; + const input = { owner: 'liboliphaunt-native', version: '0.3.3', file, framework, resources }; + const projected = projectNativeAppleBaseInput(input); + expect(projected.input.file.path).toStartWith('@oliphaunt_metadata//:native-apple-base/'); + expect(projected.input.file.producer).toEqual(file.producer); + expect(projected.files).toHaveLength(3); + for (const changed of [ + { ...input, owner: 'liboliphaunt-wasix' }, + { ...input, authenticated: true }, + { ...input, file: { ...file, member: 'ios.json' } }, + { ...input, file: { ...file, sha256: '0'.repeat(64) } }, + { ...input, version: '0.3.4' }, + { ...input, framework: undefined }, + { + ...input, + framework: { ...framework, producer: { ...framework.producer, root: '//wrong:archive' } }, + }, + { + ...input, + resources: { + ...resources, + producer: { ...resources.producer, invocationId: 'pre-version-run' }, + }, + }, + ]) + expect(() => projectNativeAppleBaseInput(changed)).toThrow(); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('projects each actual File once and retains original configured producer references', () => { + const { directory, leaf } = fixture(); + try { + const projected = projectNativeExtensionFinalInputs([leaf]); + expect(projected.files).toHaveLength(5); + const saved = projected.leaves['oliphaunt-extension-pgtap/native/linux-x64-gnu']; + expect(saved.cargo[0].member).toBe('pgtap.crate'); + expect(saved.cargo[0].producer).toEqual(leaf.cargo[0].producer); + expect(saved.cargo[0].path).toStartWith('@oliphaunt_metadata//:extension-final-inputs/'); + expect(projected.files.map((file) => file.source).sort()).toEqual( + [...leaf.github, ...leaf.npm, ...leaf.cargo, leaf.manifest, leaf.frozen] + .map((file) => file.path) + .sort(), + ); + saved.cargo[0].producer.root = '//wrong:root'; + expect(leaf.cargo[0].producer.root).toBe( + '//src/extensions/external/pgtap:native_frozen_shipping', + ); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('rejects unknown fields, duplicate constructor slots and repeated original File ownership', () => { + const { directory, leaf } = fixture(); + try { + expect(() => projectNativeExtensionFinalInputs([{ ...leaf, qualified: true }])).toThrow(); + for (const changed of [ + { ...leaf, product: 'oliphaunt_extension_pgtap' }, + { ...leaf, owner: 'oliphaunt_extension_pgtap' }, + { ...leaf, target: '../android-x86_64' }, + ]) + expect(() => projectNativeExtensionFinalInputs([changed])).toThrow(); + expect(() => projectNativeExtensionFinalInputs([leaf, leaf])).toThrow(/duplicate/); + expect(() => projectNativeExtensionFinalInputs([{ ...leaf, npm: leaf.github }])).toThrow( + /repeats/, + ); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('rejects corrupt bytes, path traversal and incomplete original producer references', () => { + const { directory, leaf } = fixture(); + try { + for (const changed of [ + { ...leaf.frozen, sha256: '0'.repeat(64) }, + { ...leaf.frozen, member: '../extension-artifacts.json' }, + { ...leaf.frozen, producer: { ...leaf.frozen.producer, output: '../output' } }, + { ...leaf.frozen, producer: { ...leaf.frozen.producer, root: '//wrong/../path:root' } }, + { ...leaf.frozen, producer: { ...leaf.frozen.producer, configuration: 'unknown' } }, + ]) + expect(() => projectNativeExtensionFinalInputs([{ ...leaf, frozen: changed }])).toThrow(); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('requires GH Files for every mobile target and all registry groups for desktop/WASIX', () => { + const { directory, leaf } = fixture(); + try { + expect(() => projectNativeExtensionFinalInputs([{ ...leaf, npm: [] }])).toThrow(); + expect(() => + projectNativeExtensionFinalInputs([ + { ...leaf, family: 'wasix', target: 'wasix-portable', cargo: [] }, + ]), + ).toThrow(); + for (const target of ['android-arm64-v8a', 'android-x86_64', 'ios-xcframework']) { + expect(() => + projectNativeExtensionFinalInputs([{ ...leaf, target, github: [], npm: [], cargo: [] }]), + ).toThrow(); + expect( + projectNativeExtensionFinalInputs([{ ...leaf, target, npm: [], cargo: [] }]).files, + ).toHaveLength(3); + } + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('current payload aliases retain exact source/File tuples and reject invalid carriers, source and bytes', () => { + const { directory, file } = fixture(); + try { + const source = { commit: 'a'.repeat(40), tree: 'b'.repeat(40) }; + const row = { + product: 'liboliphaunt-native', + version: '0.3.3', + artifact: 'cargo:liboliphaunt-native-linux-x64-gnu', + configuration: 'linux-x64-gnu', + source, + file: { + ...file('native_cargo_export.crate'), + member: 'native_cargo_export.crate', + }, + }; + const projected = projectNativeCurrentArtifacts([row], source); + const key = `${row.product}/${row.version}/${row.artifact}`; + expect(projected.artifacts[key].file.producer).toEqual(row.file.producer); + expect(projected.artifacts[key].file.member).toBe(row.file.member); + expect(projected.artifacts[key].file.path).toStartWith( + '@oliphaunt_metadata//:native-current-artifacts/', + ); + expect(projected.files[0].source).toBe(row.file.path); + expect(projected.artifacts[key].file.path).toEndWith('/native_cargo_export.crate'); + expect(projectNativeCurrentArtifacts([], source).artifacts).toEqual({}); + for (const change of [ + (value) => (value.source.commit = 'c'.repeat(40)), + (value) => (value.version = 'not-a-version'), + (value) => (value.artifact = 'cargo:invalid/name'), + (value) => (value.file.path = value.file.path.replace(/\.crate$/u, '.tgz')), + (value) => (value.file.sha256 = '0'.repeat(64)), + (value) => (value.file.producer.output = '../output'), + (value) => (value.authenticated = true), + ]) { + const changed = structuredClone(row); + change(changed); + expect(() => projectNativeCurrentArtifacts([changed], source)).toThrow(); + } + expect(() => projectNativeCurrentArtifacts([row, row], source)).toThrow('repeats'); + expect(() => + projectNativeCurrentArtifacts([{ ...row, artifact: 'github-release:other.crate' }], source), + ).toThrow('filename differs'); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); diff --git a/tools/release/native-extension-release-files.mts b/tools/release/native-extension-release-files.mts new file mode 100644 index 000000000..e18167ad7 --- /dev/null +++ b/tools/release/native-extension-release-files.mts @@ -0,0 +1,103 @@ +/** Rebase frozen extension documents through their declared original public Files. */ +import assert from 'node:assert/strict'; +import { mkdirSync, realpathSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { readPortableArchiveEntries } from '../packaging/portable-archive.mts'; +import { fileIdentity, safeRelative } from './native-file-identity.mts'; + +type Asset = { + name: string; + path: string; + sha256: string; + bytes: number; + carrierAsset?: string; + carrierRoot?: string; + memberPath?: string; + [key: string]: any; +}; +type Member = { sqlName: string; assets: Asset[]; [key: string]: any }; +type Frozen = { + extensions?: Member[]; + carrierAssets?: Asset[]; + assets?: Asset[]; + [key: string]: any; +}; + +export function extensionReleaseDocumentRows(frozen: Frozen) { + const members: Member[] = frozen.extensions ?? [frozen as Member]; + const directAssets: Asset[] = frozen.carrierAssets ?? members[0]?.assets; + assert.ok(Array.isArray(members) && members.length > 0, 'extension manifest lacks members'); + assert.ok( + Array.isArray(directAssets) && directAssets.length > 0, + 'extension manifest lacks direct assets', + ); + return { members, directAssets }; +} + +/** Path fields are private locators, never permission to read an ambient producer path. + * Public archives stay byte exact; a bundle's original nested archives are copied out. */ +export function stageDeclaredExtensionReleaseFiles( + frozen: Frozen, + files: readonly string[], + productRoot: string, + root: string, + copy: (source: string, destination: string) => { size: number; sha256: string } = fileIdentity, +) { + const { members, directAssets: assets } = extensionReleaseDocumentRows(frozen); + const physical = new Map(files.map((file) => [path.basename(file), realpathSync(file)])); + assert.equal(physical.size, files.length, 'repeated imported GitHub File'); + const relative = (file: string) => path.relative(root, file).split(path.sep).join('/'); + const directAssets = assets.map((asset) => { + const source = physical.get(asset.name); + assert(source, 'extension asset lacks its declared original GitHub File'); + const destination = path.join(productRoot, 'release-assets', safeRelative(asset.name)); + mkdirSync(path.dirname(destination), { recursive: true }); + const expected = { size: asset.bytes, sha256: asset.sha256 }; + const identity = copy(source, destination); + assert.deepEqual( + { size: identity.size, sha256: identity.sha256 }, + expected, + 'declared extension asset bytes differ', + ); + return { ...asset, path: relative(destination) }; + }); + const bundles = new Map>(); + const staged = members.map((member) => ({ + ...member, + assets: member.assets.map((asset) => { + if (!asset.carrierAsset) { + const direct = directAssets.find((row) => row.name === asset.name); + assert(direct, 'extension member lacks its declared direct asset'); + assert.equal(direct.sha256, asset.sha256, 'extension direct member digest differs'); + assert.equal(direct.bytes, asset.bytes, 'extension direct member size differs'); + return { ...asset, path: direct.path }; + } + const outer = physical.get(asset.carrierAsset); + assert(outer, 'nested member lacks its actual closed bundle File'); + if (!bundles.has(outer)) bundles.set(outer, readPortableArchiveEntries(outer)); + const entry = `${safeRelative(asset.carrierRoot!)}/${safeRelative(asset.memberPath!)}`; + const bytes = bundles.get(outer)!.get(entry)?.data(); + assert(bytes, 'nested member is absent from the original closed bundle'); + const destination = path.join( + productRoot, + 'member-assets', + safeRelative(member.sqlName), + safeRelative(asset.name), + ); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, bytes); + const identity = fileIdentity(destination); + assert.equal(identity.sha256, asset.sha256, 'nested extension member digest differs'); + assert.equal(identity.size, asset.bytes, 'nested extension member size differs'); + return { ...asset, path: relative(destination) }; + }), + })); + const manifest = frozen.extensions + ? { + ...frozen, + extensions: staged, + ...(frozen.carrierAssets ? { carrierAssets: directAssets } : {}), + } + : { ...frozen, assets: staged[0].assets }; + return { manifest, members: staged, directAssets, productRoot }; +} diff --git a/tools/release/native-file-identity.mts b/tools/release/native-file-identity.mts new file mode 100644 index 000000000..0de01a8c5 --- /dev/null +++ b/tools/release/native-file-identity.mts @@ -0,0 +1,94 @@ +/** Bounded identities for exact declared Files, independent of release discovery. */ +import { createHash } from 'node:crypto'; +import { + chmodSync, + closeSync, + constants, + fstatSync, + lstatSync, + openSync, + readSync, + realpathSync, + writeSync, +} from 'node:fs'; +import path from 'node:path'; +import { requireSafeDirectoryChain } from '../packaging/release-directory-safety.mts'; + +export function safeRelative(value: string) { + if ( + typeof value !== 'string' || + value.startsWith('/') || + value.includes('\\') || + /[\u0000-\u001f\u007f]/u.test(value) || + value.normalize('NFC') !== value || + value.split('/').some((part) => !part || part === '.' || part === '..') + ) + throw new Error(`unsafe native staging path: ${JSON.stringify(value)}`); + return value; +} + +export function fileIdentity(file: string, destination?: string) { + requireSafeDirectoryChain(path.dirname(file), { label: 'native output' }); + const source = openSync(file, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0)); + let target; + try { + const before = fstatSync(source); + if (!before.isFile()) throw new Error(`native output must be a regular file: ${file}`); + if (destination !== undefined) { + requireSafeDirectoryChain(path.dirname(destination), { create: true, label: 'native stage' }); + target = openSync( + destination, + constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY, + 0o600, + ); + } + const hash = createHash('sha256'); + const buffer = Buffer.allocUnsafe(Math.max(1, Math.min(before.size, 1024 * 1024))); + let size = 0; + for (;;) { + const count = readSync(source, buffer, 0, buffer.length, null); + if (!count) break; + const bytes = buffer.subarray(0, count); + hash.update(bytes); + size += count; + if (target !== undefined) { + let offset = 0; + while (offset < count) offset += writeSync(target, bytes, offset, count - offset); + } + } + const after = fstatSync(source); + const named = lstatSync(file); + if ( + !named.isFile() || + named.isSymbolicLink() || + [after, named].some( + (stat) => + stat.dev !== before.dev || + stat.ino !== before.ino || + stat.size !== size || + stat.mode !== before.mode || + stat.mtimeMs !== before.mtimeMs || + stat.ctimeMs !== before.ctimeMs, + ) + ) + throw new Error(`native output changed while being read: ${file}`); + if (destination !== undefined) chmodSync(destination, before.mode & 0o777); + return { type: 'file', mode: before.mode & 0o777, size, sha256: hash.digest('hex') }; + } finally { + closeSync(source); + if (target !== undefined) closeSync(target); + } +} + +/** Copy an exact declared input with the bounded reader, retaining its captured link identity. */ +export function copyNativeInputFile(executionRoot: string, input: string, destination: string) { + if (!path.isAbsolute(executionRoot ?? '')) + throw new Error('native input requires the captured absolute executionRoot'); + const root = realpathSync(executionRoot); + const declared = path.join(root, safeRelative(input)); + const physical = realpathSync(declared); + const identity = fileIdentity(physical, destination); + if (realpathSync(declared) !== physical) + throw new Error('native input path changed while being copied'); + return identity; +} diff --git a/tools/release/native-file-identity.test.mts b/tools/release/native-file-identity.test.mts new file mode 100644 index 000000000..97cf4cc7d --- /dev/null +++ b/tools/release/native-file-identity.test.mts @@ -0,0 +1,95 @@ +import { test } from 'bun:test'; +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { + lstatSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { copyNativeInputFile, fileIdentity } from './native-file-identity.mts'; + +test('bounded identities preserve empty, small and multi-chunk bytes without oversized read buffers', () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-native-file-')); + const originalAllocate = Buffer.allocUnsafe; + try { + for (const size of [ + 0, + 17, + 8192, + 1024 * 1024 - 1, + 1024 * 1024, + 1024 * 1024 + 1, + 2 * 1024 * 1024 + 19, + ]) { + const bytes = Buffer.alloc(size, 0x5a); + const source = path.join(root, `source-${size}`); + const destination = path.join(root, `copy-${size}`); + writeFileSync(source, bytes, { mode: 0o600 }); + const capacities: number[] = []; + Buffer.allocUnsafe = (capacity: number) => { + capacities.push(capacity); + return originalAllocate(capacity); + }; + const identity = fileIdentity(source); + const copy = fileIdentity(source, destination); + Buffer.allocUnsafe = originalAllocate; + assert.deepEqual(copy, identity); + assert.deepEqual(readFileSync(destination), bytes); + assert.equal(identity.mode, lstatSync(source).mode & 0o777); + assert.equal(identity.size, size); + assert.equal(identity.sha256, createHash('sha256').update(bytes).digest('hex')); + assert.ok(capacities.length > 0); + assert.ok(capacities.every((capacity) => capacity > 0 && capacity <= 1024 * 1024)); + if (size < 1024 * 1024) + assert.ok( + capacities.every((capacity) => capacity <= Math.max(1, size)), + 'a tiny File must not allocate a MiB read buffer', + ); + } + } finally { + Buffer.allocUnsafe = originalAllocate; + rmSync(root, { recursive: true, force: true }); + } +}); + +test('declared repository aliases copy exact regular bytes through the bounded reader', () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-native-input-')); + try { + const source = path.join(root, 'source'); + mkdirSync(source); + const bytes = Buffer.alloc(2 * 1024 * 1024 + 19, 0x5a); + writeFileSync(path.join(source, 'payload.bin'), bytes); + const execution = path.join(root, 'execution'); + mkdirSync(execution); + symlinkSync( + source, + path.join(execution, 'external'), + process.platform === 'win32' ? 'junction' : 'dir', + ); + const output = path.join(root, 'private', 'payload.bin'); + const identity = copyNativeInputFile(execution, 'external/payload.bin', output); + assert.equal(identity.sha256, createHash('sha256').update(bytes).digest('hex')); + assert.equal(identity.size, bytes.length); + assert.deepEqual(readFileSync(output), bytes); + assert.throws(() => + copyNativeInputFile(execution, '../source/payload.bin', path.join(root, 'escape')), + ); + assert.throws(() => copyNativeInputFile(execution, 'external', path.join(root, 'directory'))); + assert.throws(() => copyNativeInputFile(execution, 'external/payload.bin', output), /EEXIST/); + const alias = path.join(root, 'aliased-output'); + symlinkSync(source, alias, process.platform === 'win32' ? 'junction' : 'dir'); + assert.throws( + () => copyNativeInputFile(execution, 'external/payload.bin', path.join(alias, 'overwritten')), + /symlink|regular directory/u, + ); + assert.deepEqual(readFileSync(path.join(source, 'payload.bin')), bytes); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/tools/release/native-first-publication.test.mts b/tools/release/native-first-publication.test.mts new file mode 100644 index 000000000..69085f43d --- /dev/null +++ b/tools/release/native-first-publication.test.mts @@ -0,0 +1,220 @@ +import { expect, test } from 'bun:test'; +import { execFileSync } from 'node:child_process'; +import { + copyFileSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; + +test('a new source owner selects its first release and keeps registry libraries separate from installed helpers', () => { + const repository = path.resolve(import.meta.dir, '../..'); + const directory = mkdtempSync(path.join(tmpdir(), 'native-first-publication-')); + const snapshot = path.join(directory, 'source'); + const owner = 'src/query/review-first'; + const git = (...args: string[]) => + execFileSync('git', args, { cwd: snapshot, encoding: 'utf8' }).trim(); + try { + mkdirSync(snapshot); + execFileSync('git', ['archive', 'HEAD', '--output', path.join(directory, 'source.tar')], { + cwd: repository, + }); + execFileSync('tar', ['-xf', path.join(directory, 'source.tar'), '-C', snapshot]); + // Exercise checked-out readers even before their source change is committed. + for (const file of [ + 'native-completed-delivery.mts', + 'completed-contrib-carrier-context.mts', + 'publication-lock.mts', + 'with-source.mts', + 'publication-catalog.mts', + 'release-graph.mts', + 'release-artifact-targets.mts', + 'native-release-preparation.mts', + 'native-publication-metadata.mts', + 'compatibility-version-parser.mts', + 'testdata/prepare-release-candidate-fixtures.mts', + ]) + copyFileSync( + path.join(repository, 'tools/release', file), + path.join(snapshot, 'tools/release', file), + ); + // The shared parser has no file dependencies; use its actual current + // implementation with the checked-out acquisition readers above. + copyFileSync( + path.join(repository, 'tools/packaging/cargo-manifest.mts'), + path.join(snapshot, 'tools/packaging/cargo-manifest.mts'), + ); + symlinkSync( + path.join(repository, 'node_modules'), + path.join(snapshot, 'node_modules'), + 'junction', + ); + symlinkSync( + path.join(repository, 'tools/release/node_modules'), + path.join(snapshot, 'tools/release/node_modules'), + 'junction', + ); + mkdirSync(path.join(snapshot, owner, 'src'), { recursive: true }); + const config = JSON.parse( + readFileSync(path.join(snapshot, 'release-please-config.json'), 'utf8'), + ); + config.packages[owner] = { + 'release-type': 'rust', + component: 'review-first', + 'package-name': 'review-first', + 'changelog-path': 'CHANGELOG.md', + }; + writeFileSync(path.join(snapshot, 'release-please-config.json'), JSON.stringify(config)); + const versions = JSON.parse( + readFileSync(path.join(snapshot, '.release-please-manifest.json'), 'utf8'), + ); + versions[owner] = '0.0.0'; + writeFileSync(path.join(snapshot, '.release-please-manifest.json'), JSON.stringify(versions)); + writeFileSync( + path.join(snapshot, owner, 'release.toml'), + 'id = "review-first"\nowner = "@oliphaunt/core"\nkind = "sdk"\npublish_targets = ["crates-io"]\nregistry_packages = ["crates:review-first"]\nrelease_artifacts = ["cargo-crate"]\n[compatibility_versions.current_core]\npublic_support = false\nsource_product = "liboliphaunt-native-bindings"\npath = "src/query/review-first/Cargo.toml"\nparser = "toml:dependencies.liboliphaunt-native-bindings.version"\n', + ); + writeFileSync( + path.join(snapshot, owner, 'Cargo.toml'), + '[package]\nname = "review-first"\nversion = "0.0.0"\nlicense = "MIT"\n[dependencies]\nliboliphaunt-native-bindings = { path = "../../native/rust-bindings", version = "0.2.0" }\n', + ); + writeFileSync(path.join(snapshot, owner, 'src/lib.rs'), 'pub fn first() -> bool { true }\n'); + writeFileSync(path.join(snapshot, owner, 'CHANGELOG.md'), ''); + git('init', '-q'); + git('add', '.'); + git( + '-c', + 'user.name=Fixture', + '-c', + 'user.email=fixture@example.invalid', + 'commit', + '-qm', + 'feat: first product fixture', + ); + const commit = git('rev-parse', 'HEAD'); + const source = { ref: 'HEAD', commit, tree: git('rev-parse', 'HEAD^{tree}'), checkout: commit }; + const script = path.join(snapshot, 'first-publication.mts'); + writeFileSync( + script, + `import { readFileSync, writeFileSync } from 'node:fs'; +import { tarArchive } from './tools/packaging/testdata/tar-fixture.mts'; +import { buildPublicationCandidate } from './tools/release/publication-lock.mts'; +import { compareNativeCompletedPhysicalDelivery } from './tools/release/native-completed-delivery.mts'; +import { acquireNativePublicationInputs } from './tools/release/native-release-preparation.mts'; +const acquired = await acquireNativePublicationInputs({ source: { commit: '${source.commit}', tree: '${source.tree}' }, directory: 'current-source-inputs', consumerProducts: ['review-first'] }, { + readJson: async () => { throw new Error('local Cargo inputs must not request a completed registry publication'); }, + readPages: async () => { throw new Error('local Cargo inputs must not request completed release assets'); }, +}); +const archive = 'review-first-0.0.0.crate'; +writeFileSync(archive, tarArchive([ + { name: 'review-first-0.0.0/Cargo.toml', data: readFileSync('${owner}/Cargo.toml') }, + { name: 'review-first-0.0.0/src/lib.rs', data: readFileSync('${owner}/src/lib.rs') }, +])); +const candidate = buildPublicationCandidate({ products: ['review-first'], artifactRoots: [archive], artifactPhase: 'pre-version' }); +const initial = await compareNativeCompletedPhysicalDelivery(candidate, [], { unreleasedProducts: ['review-first'] }); +const unknown = await compareNativeCompletedPhysicalDelivery(candidate, []); +process.stdout.write(JSON.stringify({ initial: initial.products[0], unknown: unknown.products[0].deliveryStatus, suppliers: acquired.snapshot.supplierPublications })); +`, + ); + const result = JSON.parse( + execFileSync(process.execPath, [script], { + cwd: snapshot, + encoding: 'utf8', + env: { ...process.env, OLIPHAUNT_GIT_SOURCE_JSON: JSON.stringify(source) }, + }), + ); + expect(result.initial.deliveryStatus).toBe('different'); + expect(result.initial.reason).toBe('verified-first-publication'); + expect(result.initial.contractChanges).toEqual({ + added: ['product:review-first'], + removed: [], + }); + expect(result.unknown).toBe('unknown'); + expect(result.suppliers).toEqual([]); + // An aliased registry library and independently held helper belong to the + // same owner, but request different completed deliveries and surfaces. + const libraryDescriptor = `id = "review-first" +owner = "@oliphaunt/core" +kind = "sdk" +publish_targets = ["crates-io"] +registry_packages = ["crates:review-first"] +release_artifacts = ["cargo-crate"] +[compatibility_versions.broker_library] +public_support = false +source_product = "oliphaunt-broker" +path = "${owner}/Cargo.toml" +parser = "toml:dependencies.broker-library.version" +`; + writeFileSync(path.join(snapshot, owner, 'release.toml'), libraryDescriptor); + writeFileSync( + path.join(snapshot, owner, 'Cargo.toml'), + `[package]\nname = "review-first"\nversion = "0.0.0"\nlicense = "MIT"\n[dependencies]\nbroker-library = { package = "oliphaunt-broker", version = "0.3.1" }\n`, + ); + const scriptRoles = path.join(snapshot, 'source-role-inputs.mts'); + writeFileSync( + scriptRoles, + `import assert from 'node:assert/strict'; +import { mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { acquireNativePublicationInputs } from './tools/release/native-release-preparation.mts'; +import { fileIdentity } from './tools/release/native-file-identity.mts'; +import { fixtureCompletedNativeInventory } from './tools/release/testdata/prepare-release-candidate-fixtures.mts'; +import { tarArchive } from './tools/packaging/testdata/tar-fixture.mts'; +const downloads = []; +const registries = []; +const publication = { product: 'oliphaunt-broker', version: '0.3.2', tagName: 'oliphaunt-broker-v0.3.2', publicationSha: 'c'.repeat(40), publicationTree: 'd'.repeat(40), releaseSha: 'c'.repeat(40) }; +const helperRows = (await fixtureCompletedNativeInventory(publication)).publicRows.filter(row => row.kind === 'broker-helper'); +const assets = helperRows.map((row, index) => ({ id: index + 1, name: row.name, state: 'uploaded', size: Buffer.byteLength(row.name), url: 'https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/' + (index + 1) })); +const transports = { + inventory: fixtureCompletedNativeInventory, + readJson: async endpoint => ({ id: endpoint.endsWith('0.3.2') ? 32 : 31, target_commitish: 'c'.repeat(40), tag_name: decodeURIComponent(endpoint.split('/').at(-1)) }), + readPages: async endpoint => endpoint.includes('/32/') ? assets : [], + assertCompleted: async request => ({ ...request, publicationTree: 'd'.repeat(40), releaseSha: request.publicationSha }), + materialize: async (carrier, options) => { + registries.push(carrier.id + '@' + carrier.version); + mkdirSync(options.directory, { recursive: true }); + const file = path.join(options.directory, carrier.artifacts[0].path); + writeFileSync(file, tarArchive([{ name: carrier.name + '-' + carrier.version + '/Cargo.toml', data: '[package]\\nname = ' + JSON.stringify(carrier.name) + '\\nversion = ' + JSON.stringify(carrier.version) + '\\n' }])); + const { size, sha256 } = fileIdentity(file); + return { carrier: { ...carrier, artifacts: [{ path: file, size, sha256 }] }, receipt: {}, metadata: {} }; + }, + proveAsset: async (_url, name, size, options) => { + downloads.push(name); + mkdirSync(path.dirname(options.retainedPath), { recursive: true }); + writeFileSync(options.retainedPath, name); + const actual = fileIdentity(options.retainedPath); + assert.equal(actual.size, size); + return { bytes: actual.size, sha256: actual.sha256 }; + }, +}; +const request = { source: { commit: '${source.commit}', tree: '${source.tree}' }, consumerProducts: ['review-first'] }; +const library = await acquireNativePublicationInputs({ ...request, directory: 'library-only-inputs' }, transports); +assert.deepEqual(registries, ['cargo:oliphaunt-broker@0.3.1']); +assert.deepEqual(downloads, []); +await assert.rejects(acquireNativePublicationInputs({ ...request, directory: 'missing-library-inputs' }, { ...transports, inventory: async (publication, options) => { const value = await fixtureCompletedNativeInventory(publication, options); return { ...value, carriers: value.carriers.filter(row => row.id !== 'cargo:oliphaunt-broker') }; } }), /requested supplier is absent/); +writeFileSync('${owner}/release.toml', readFileSync('${owner}/release.toml', 'utf8') + '\\n[compatibility_versions.broker_helper]\\npublic_support = false\\nsource_product = "oliphaunt-broker"\\npath = "${owner}/Cargo.toml"\\nparser = "toml:package.metadata.oliphaunt.broker-version"\\n'); +writeFileSync('${owner}/Cargo.toml', readFileSync('${owner}/Cargo.toml', 'utf8') + '\\n[package.metadata.oliphaunt]\\nbroker-version = "0.3.2"\\n'); +const mixed = await acquireNativePublicationInputs({ ...request, directory: 'mixed-role-inputs' }, transports); +assert.deepEqual(registries, ['cargo:oliphaunt-broker@0.3.1', 'cargo:oliphaunt-broker@0.3.1']); +assert.deepEqual(downloads, helperRows.map(row => row.name)); +process.stdout.write(JSON.stringify({ library: library.snapshot.supplierArtifacts.map(row => [row.artifact, row.publication.version]), mixed: mixed.snapshot.supplierArtifacts.map(row => [row.artifact, row.publication.version]), helpers: helperRows.map(row => row.id), publications: mixed.snapshot.supplierPublications.map(row => row.version).sort() })); +`, + ); + const roles = JSON.parse( + execFileSync(process.execPath, [scriptRoles], { cwd: snapshot, encoding: 'utf8' }), + ); + expect(roles.library).toEqual([['cargo:oliphaunt-broker', '0.3.1']]); + expect(roles.mixed).toEqual([ + ['cargo:oliphaunt-broker', '0.3.1'], + ...roles.helpers.map((id: string) => [id, '0.3.2']), + ]); + expect(roles.publications).toEqual(['0.3.1', '0.3.2']); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); diff --git a/tools/release/native-freeze-publication-candidate.mts b/tools/release/native-freeze-publication-candidate.mts new file mode 100644 index 000000000..71833bef1 --- /dev/null +++ b/tools/release/native-freeze-publication-candidate.mts @@ -0,0 +1,1078 @@ +/** Freeze post-version native Files. Selection was decided before the version edit. */ +import assert from 'node:assert/strict'; +import { execFileSync } from 'node:child_process'; +import { appendFileSync, existsSync, mkdtempSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { parseArgs } from 'node:util'; +import { + extensionReleaseConsumerInputs, + requestedSwiftExtensionCarrierProducts, +} from '../../src/native/sdks/swift/tools/swift-extension-release-consumer-inputs.mts'; +import { requireSafeDirectoryChain } from '../packaging/release-directory-safety.mts'; +import { assertAuthenticatedNativeBuildOrigin } from './authenticate-native-build-evidence.mts'; +import { validateReleaseConsumerCompatibility } from './consumer-compatibility.mts'; +import { requestGithubPages, requestGithubRepositoryJson } from './github-read.mts'; +import { + assertNativeFinalShippingPhase, + type NativeBuildSource, +} from './native-build-qualification.mts'; +import { readCompletedNativeDeliveryInventory } from './native-completed-delivery.mts'; +import { fileIdentity } from './native-file-identity.mts'; +import { + acquireCompletedNativeMetadataBaseline, + observedNativePublicationMetadata, + writeMetadataRecords, +} from './native-publication-metadata.mts'; +import { NATIVE_PUBLICATION_METADATA_KIND } from './native-publication-metadata-contract.mts'; +import { + type NativePublicationBuild, + observeNativePublicationConstruction, + projectNativePublicationConstruction, +} from './native-publication-observation.mts'; +import { NATIVE_EXTENSION_RELEASE_INPUT_ROLES } from './native-publication-staging.mts'; +import { + acquirePreparedNativeReleaseInputs, + assertAcquiredPreparedNativeReleaseInputs, + type NativeReleaseInputRecord, + parseNativeReleaseInputRecord, + resolveNativeReleaseInputContext, +} from './native-release-inputs.mts'; +import { + acquireNativePublicationBuilds, + stageNativeReleaseFamilies, +} from './native-release-preparation.mts'; +import { projectNativeBuildBoundSuppliers } from './native-shipping-suppliers.mts'; +import { + type NativeSupplierArtifact, + validateNativeSupplierArtifacts, +} from './native-supplier-artifacts.mts'; +import { loadPublicationCatalog, publicationCatalogDigest } from './publication-catalog.mts'; +import { consumerDigest } from './publication-consumer-proof.mts'; +import { + buildPublicationCandidate, + expectedProductArtifactRows, + freezeNativePublicationCandidate, + lockedPublicationFiles, + sourceIdentity, + validatePublicationCandidate, +} from './publication-lock.mts'; +import { materializeRegistryCarrierIntegrity } from './registry-integrity.mts'; +import { ROOT } from './release-graph.mts'; +import { requestReleaseAssetProof } from './verify_github_release_attestations.mts'; +import { releaseProductsFromManifests } from './verify-release-commit.mts'; + +type Candidate = ReturnType; +type Acquisition = Awaited>; +type Observation = Awaited>; +type Prepared = Awaited>; +type Origin = Acquisition['origins'] extends Map ? Value : never; +type CompletedInputs = NonNullable< + Parameters[0]['completed'] +>; +const repository = 'f0rr0/oliphaunt'; +const admitted = new WeakMap< + object, + { + digest: string; + prepared: Prepared; + origins: readonly Origin[]; + } +>(); +const reviewedObservations = new WeakMap< + object, + { complete: string; run: string; observation: string } +>(); +const equal = (actual: unknown, expected: unknown, message: string) => + assert.equal(consumerDigest(actual), consumerDigest(expected), message); + +/** The controller reads requirements from retained original Files, not a newer + * checkout's pins. Construction and authentication are separate obligations. + */ +export function nativeSwiftFixtureRequest( + complete: Candidate, + selectedProducts: readonly string[], +) { + if (!selectedProducts.includes('oliphaunt-swift')) return []; + const source = complete.productArtifacts.filter( + (artifact) => + artifact.product === 'oliphaunt-swift' && artifact.kind === 'swiftpm-ios-carrier-manifest', + ); + assert.equal(source.length, 1, 'Swift fixture request needs the original source carrier'); + const read = (artifact) => JSON.parse(readFileSync(path.resolve(ROOT, artifact.path), 'utf8')); + const carriers = complete.productArtifacts + .filter( + (artifact) => + artifact.kind === 'swift-extension-carrier' && selectedProducts.includes(artifact.product), + ) + .map((artifact) => { + const document = read(artifact); + assert.equal( + document.release?.product, + artifact.product, + 'Swift fixture carrier owner differs', + ); + assert.equal( + document.release?.version, + complete.products.find(({ id }) => id === artifact.product)?.version, + 'Swift fixture carrier version differs', + ); + return document; + }); + return requestedSwiftExtensionCarrierProducts({ + selectedProducts, + sourceBase: read(source[0]).base, + carriers, + }); +} + +function assertNativeSwiftFixture( + candidate: Candidate, + complete: Candidate, + selectedProducts: readonly string[], + nativeBaseArchiveInputs = undefined, +) { + const requested = nativeSwiftFixtureRequest(complete, selectedProducts); + const fixtures = candidate.productArtifacts.filter( + ({ kind }) => kind === 'swiftpm-extension-consumer-fixture', + ); + assert.equal( + fixtures.length, + requested.length ? 1 : 0, + 'Swift fixture differs from the source-bound requested tuple', + ); + if (!requested.length) return; + const source = complete.productArtifacts.find( + (artifact) => + artifact.product === 'oliphaunt-swift' && artifact.kind === 'swiftpm-ios-carrier-manifest', + ); + assert.ok(source); + const controls = complete.productArtifacts.filter( + (artifact) => + artifact.kind === 'swift-extension-carrier' && requested.includes(artifact.product), + ); + const plan = extensionReleaseConsumerInputs({ + sourceCarrierFile: path.resolve(ROOT, source.path), + extensionCarrierFiles: controls.map((artifact) => path.resolve(ROOT, artifact.path)), + nativeBaseArchiveInputs, + }); + const document = JSON.parse( + readFileSync(path.resolve(ROOT, fixtures[0].path, 'extension-products.json'), 'utf8'), + ); + equal( + document.selected.map(({ sqlName }) => sqlName).sort(), + plan.extensions, + 'Swift fixture SQL closure differs', + ); + equal( + document.nativeRuntime, + { product: plan.finalLink.runtimeProduct, version: plan.finalLink.runtimeVersion }, + 'Swift fixture native requirement differs', + ); + assert.equal( + document.basePackage?.version, + candidate.products.find(({ id }) => id === 'oliphaunt-swift')?.version, + 'Swift fixture source version differs', + ); + const expected = controls + .map(({ product }) => ({ + product, + version: complete.products.find(({ id }) => id === product)?.version, + })) + .sort((a, b) => a.product.localeCompare(b.product)); + const actual = [ + ...new Map( + document.selected.map(({ releaseProduct, version }) => [ + releaseProduct, + { product: releaseProduct, version }, + ]), + ).values(), + ].sort((a: any, b: any) => a.product.localeCompare(b.product)); + equal(actual, expected, 'Swift fixture selected carrier identities differ'); +} + +function publicationQualification( + prepared: Prepared, + acquisition: Acquisition, + complete: Candidate, +) { + assertAcquiredPreparedNativeReleaseInputs(prepared); + assertSuccessfulNativePublicationRun(acquisition.run, complete.source); + const origin = prepared.origin; + return { + source: complete.source, + prepare: { + runId: origin.runId, + runAttempt: origin.runAttempt, + artifact: { + id: origin.artifact.id, + name: origin.artifact.name, + digest: origin.artifact.digest, + size: origin.artifact.size_in_bytes, + }, + codeSource: origin.codeSource, + preparedSource: origin.preparedSource, + }, + bridge: prepared.record.bridge, + selectedProducts: prepared.record.selectedProducts, + producer: { + runId: acquisition.run.id, + runAttempt: acquisition.run.run_attempt, + event: acquisition.run.event, + ref: 'refs/heads/main', + workflowPath: acquisition.run.path, + }, + inventory: { + products: complete.products.map(({ id }) => id).sort(), + artifactPhase: complete.artifactPhase, + packageEnvelopeDigest: complete.packageEnvelopeDigest, + }, + }; +} + +/** This checks run facts; authenticated per-job artifacts remain separately mandatory. */ +export function assertSuccessfulNativePublicationRun(run: any, source: NativeBuildSource) { + assert.ok( + Number.isSafeInteger(run?.id) && + run.id > 0 && + Number.isSafeInteger(run.run_attempt) && + run.run_attempt > 0 && + run.head_sha === source.commit && + run.head_branch === 'main' && + ['push', 'workflow_dispatch'].includes(run.event) && + run.path === '.github/workflows/bazel.yml' && + run.name === 'Native Bazel qualification' && + run.status === 'completed' && + run.conclusion === 'success', + 'native publication requires successful exact post-version main qualification', + ); +} + +/** Selection projection is structural. It cannot authenticate producers or authorize freeze. */ +export function assertSelectedNativeEnvelope( + candidate: Candidate, + complete: Candidate, + selectedProducts: readonly string[], + { nativeBaseArchiveInputs = undefined } = {}, +) { + assert.ok( + selectedProducts.length > 0 && new Set(selectedProducts).size === selectedProducts.length, + 'native publication selection must be nonempty and unique', + ); + const selected = new Set(selectedProducts); + equal(candidate.source, complete.source, 'selected native source differs'); + equal( + candidate.products, + complete.products.filter(({ id }) => selected.has(id)), + 'selected native products differ from the authenticated release scope', + ); + equal( + candidate.products.map(({ id }) => id).sort(), + [...selected].sort(), + 'native publication cannot add an unchanged or omit a selected product', + ); + assert.equal( + candidate.artifactPhase ?? 'final', + 'final', + 'selected native envelope must be final', + ); + const artifactIdentity = ({ path: _path, ...row }) => row; + const carrier = ({ dependencies: _dependencies, publishOrder: _publishOrder, ...row }) => ({ + ...row, + artifacts: row.artifacts.map(artifactIdentity), + }); + const carriers = (rows: any[]) => rows.map(carrier).sort((a, b) => a.id.localeCompare(b.id)); + equal( + carriers(candidate.carriers), + carriers(complete.carriers.filter((row) => selected.has(row.product))), + 'selected native carrier bytes or manifest requirements changed', + ); + assertNativeSwiftFixture(candidate, complete, selectedProducts, nativeBaseArchiveInputs); + for (const artifact of candidate.productArtifacts) { + if (artifact.kind === NATIVE_PUBLICATION_METADATA_KIND) continue; + if (artifact.kind === 'swiftpm-extension-consumer-fixture') { + assert.ok( + expectedProductArtifactRows(candidate.products, { swiftExtensionFixture: true }).some( + (row) => row.product === artifact.product && row.id === artifact.id, + ), + 'unselected Swift fixture cannot enter a native publication', + ); + // The final observation independently binds this selection-specific File. + continue; + } + const original = complete.productArtifacts.find( + (row) => row.product === artifact.product && row.id === artifact.id, + ); + assert.ok(original, 'selected native public artifact was not observed'); + equal( + artifactIdentity(artifact), + artifactIdentity(original), + 'selected native public artifact changed after observation', + ); + } +} + +function assertCompleteInventory(complete: Candidate) { + validatePublicationCandidate(complete); + const catalog = loadPublicationCatalog('native publication complete inventory'); + equal(complete.products, catalog.products, 'native publication requires every canonical product'); + assert.equal( + complete.catalogDigest, + publicationCatalogDigest(catalog), + 'native publication catalog differs', + ); + assert.deepEqual(complete.missing, [], 'native publication is missing final carriers'); + assert.equal( + complete.artifactPhase, + 'pre-version', + 'complete inventory must exclude only the selection-conditional final fixture', + ); +} + +async function observeAuthenticated( + complete: Candidate, + acquisition: Acquisition, + bazelVersion: string, +) { + assertSuccessfulNativePublicationRun(acquisition.run, complete.source); + assert.equal( + acquisition.origins.size, + acquisition.builds.length, + 'native producer inventory differs', + ); + const authenticate = async ( + evidenceRoot: string, + expected: NativePublicationBuild['expected'], + ) => { + const build = acquisition.builds.find((row) => row.evidenceRoot === evidenceRoot); + assert.ok(build, 'native publication cannot import an unacquired producer'); + equal(expected, build.expected, 'cached native producer constraints changed'); + assert.equal(expected.github.runId, acquisition.run.id, 'native producer run differs'); + assert.ok( + Number.isSafeInteger(expected.github.runAttempt) && + expected.github.runAttempt > 0 && + expected.github.runAttempt <= acquisition.run.run_attempt, + 'native producer attempt is newer than the observation', + ); + assert.equal(expected.ref, 'refs/heads/main', 'native publication producer must be main'); + assert.equal(expected.event, acquisition.run.event, 'native producer event differs'); + return assertAuthenticatedNativeBuildOrigin(acquisition.origins.get(evidenceRoot)); + }; + const observation = await observeNativePublicationConstruction( + { + envelope: complete, + files: lockedPublicationFiles(complete), + repository, + bazelVersion, + builds: acquisition.builds, + reviewedSource: complete.source, + }, + { authenticate }, + ); + assert.equal( + observation.coverage.completeProductInventory, + true, + 'native publication requires complete coverage', + ); + assert.equal( + observation.coverage.releaseInputsRequired, + true, + 'native publication requires construction inputs', + ); + for (const build of observation.authenticated) { + assert.ok(build.producerAssurance, 'native publication requires reviewed producer assurance'); + assert.equal( + build.qualification.shippingAnalysis, + 'bound', + 'native publication requires producing analysis', + ); + assert.equal( + build.qualification.qualificationPolicy, + 'bound', + "native publication requires each shipping root's mandatory successful configured tests", + ); + } + reviewedObservations.set(observation, { + complete: consumerDigest(complete), + run: consumerDigest(acquisition.run), + observation: consumerDigest(observation), + }); + return observation; +} + +/** Acquire only held Files actually declared by the authenticated configured producers. + * Existing completion/registry/public-asset readers reauthenticate these contexts. */ +export async function acquireObservedCompletedSuppliers( + observation: Observation, + directory: string, + retainedArtifacts: unknown = [], + { + inventory = readCompletedNativeDeliveryInventory, + readJson = requestGithubRepositoryJson, + readPages = requestGithubPages, + materialize = materializeRegistryCarrierIntegrity, + proveAsset = requestReleaseAssetProof, + acquireMetadata = acquireCompletedNativeMetadataBaseline, + } = {}, +): Promise { + const retained = validateNativeSupplierArtifacts(retainedArtifacts); + const retainedFile = (publication, artifact: string) => { + const matches = retained.filter( + (row) => + consumerDigest(row.publication) === consumerDigest(publication) && + row.artifact === artifact, + ); + assert.ok(matches.length <= 1, 'retained completed supplier artifact repeats'); + const row = matches[0]; + if (row) { + const physical = fileIdentity(row.file.path); + equal( + { size: physical.size, sha256: physical.sha256 }, + { size: row.file.size, sha256: row.file.sha256 }, + 'retained completed supplier File changed', + ); + } + return row; + }; + const groups = new Map }>(); + for (const { evidence } of observation.authenticated) + for (const cohort of evidence.cohorts) + for (const root of cohort.roots) + for (const supplier of root.package.supplierInputs ?? []) { + if (supplier.origin.kind !== 'completed-publication') continue; + const publication = supplier.origin.publication; + const key = consumerDigest(publication); + let group = groups.get(key); + if (!group) { + group = { publication, artifacts: new Set() }; + groups.set(key, group); + } + group.artifacts.add(supplier.origin.artifact); + } + const inputs: CompletedInputs = []; + for (const [index, { publication, artifacts }] of [...groups.values()].entries()) { + const release = await readJson( + `repos/${repository}/releases/tags/${encodeURIComponent(publication.tagName)}`, + ); + const assets = await readPages(`repos/${repository}/releases/${release.id}/assets`); + const metadataBaseline = ( + await acquireMetadata( + { publication, directory: path.join(directory, String(index), 'metadata'), assets }, + { proveAsset }, + ) + )?.baseline; + const historical = await inventory(publication, { metadataBaseline, readJson }); + const carriers: Record = {}; + const files: Record = {}; + const sourceTags: NativeSupplierArtifact[] = []; + for (const [item, identity] of [...artifacts].sort().entries()) { + if (identity.startsWith('swift-source-tag:')) { + const retainedSource = retainedFile(publication, identity); + assert.ok( + retainedSource?.source, + 'completed Git source supplier is absent from the acquired Prepare inputs', + ); + const bindings = historical.publicRows.filter( + ({ kind, role }) => kind === 'swift-bindings' && role === 'github-release-asset', + ); + assert.equal( + bindings.length, + 1, + 'completed source supplier needs one canonical binding archive', + ); + const binding = retainedFile(publication, bindings[0].id); + assert.ok( + binding && !binding.source, + 'completed source supplier requires its retained same-publication binding archive', + ); + files[bindings[0].id] = binding.file.path; + sourceTags.push(retainedSource); + continue; + } + const separator = identity.indexOf(':'); + const ecosystem = identity.slice(0, separator); + if (['cargo', 'npm'].includes(ecosystem)) { + const matching = historical.carriers.filter((row) => row.id === identity); + assert.equal( + matching.length, + 1, + 'held registry supplier is absent from its historical inventory', + ); + const carrier = matching[0]; + assert.equal(carrier.product, publication.product, 'held registry supplier owner differs'); + const captured = retainedFile(publication, identity); + if (captured) { + carriers[identity] = [captured.file.path]; + continue; + } + const retained = await materialize( + { + ...carrier, + version: publication.version, + artifacts: carrier.artifacts?.map((artifact) => ({ + ...artifact, + path: path.basename(artifact.path), + })) ?? [ + { + path: + ecosystem === 'cargo' + ? `${carrier.name}-${publication.version}.crate` + : `${carrier.name.replace(/[^a-zA-Z0-9.-]/gu, '-')}-${publication.version}.tgz`, + }, + ], + }, + { directory: path.join(directory, String(index), String(item)) }, + ); + carriers[identity] = retained.carrier.artifacts.map(({ path: file }) => file); + } else { + const rows = historical.publicRows; + const matching = rows.filter((row) => row.id === identity || row.name === identity); + assert.equal( + matching.length, + 1, + 'held supplier requires an exact canonical public artifact', + ); + const row = matching[0]; + const captured = retainedFile(publication, row.id); + if (captured) { + files[row.id] = captured.file.path; + continue; + } + const matches = assets.filter((asset) => asset.name === row.name); + assert.equal(matches.length, 1, 'held supplier public asset is absent or ambiguous'); + const asset = matches[0]; + assert.ok( + asset.state === 'uploaded' && + Number.isSafeInteger(asset.id) && + asset.id > 0 && + asset.url === + `https://api.github.com/repos/${repository}/releases/assets/${asset.id}` && + Number.isSafeInteger(asset.size) && + asset.size > 0 && + (asset.digest == null || /^sha256:[a-f0-9]{64}$/u.test(asset.digest)) && + (row.size === undefined || row.size === asset.size) && + (row.sha256 === undefined || + asset.digest == null || + asset.digest === `sha256:${row.sha256}`), + 'held supplier public asset identity differs', + ); + const retainedPath = path.join(directory, String(index), String(item), row.name); + await proveAsset(asset.url, row.name, asset.size, { + retainedPath, + ...(row.sha256 || asset.digest + ? { expectedSha256: row.sha256 ?? asset.digest.slice(7) } + : {}), + }); + files[row.id] = retainedPath; + } + } + const context = { publication, ...(metadataBaseline ? { metadataBaseline } : {}) }; + if (sourceTags.length) inputs.push({ ...context, files, carriers, sourceTags }); + else { + if (Object.keys(carriers).length) inputs.push({ ...context, carriers }); + if (Object.keys(files).length) inputs.push({ ...context, files }); + } + } + return inputs; +} + +/** Only this fixed, authenticated entry point can mint a fresh native freeze capability. */ +export async function admitNativePublicationCandidate({ + candidate, + complete, + prepared, + acquisition, + observation, + completed, +}: { + candidate: Candidate; + complete: Candidate; + prepared: Prepared; + acquisition: Acquisition; + observation: Observation; + completed: CompletedInputs; +}) { + assertAcquiredPreparedNativeReleaseInputs(prepared); + assertCompleteInventory(complete); + assertSuccessfulNativePublicationRun(acquisition.run, candidate.source); + equal( + candidate.source.tree, + prepared.record.preparedSource.tree, + 'native publication source differs from prepared tree', + ); + const sourceCarrier = complete.productArtifacts.find( + (artifact) => + artifact.product === 'oliphaunt-swift' && artifact.kind === 'swiftpm-ios-carrier-manifest', + ); + let nativeBaseArchiveInputs; + if (sourceCarrier && prepared.record.selectedProducts.includes('oliphaunt-swift')) { + const sourceBase = JSON.parse( + readFileSync(path.resolve(ROOT, sourceCarrier.path), 'utf8'), + ).base; + const snapshot = JSON.parse(readFileSync(prepared.snapshotFile, 'utf8')); + const archives = Object.fromEntries( + sourceBase.assets.flatMap((asset) => { + const rows = (snapshot.supplierArtifacts ?? []).filter( + (row) => + row.publication.product === sourceBase.product && + row.publication.version === sourceBase.version && + row.artifact === `github-release:${asset.name}`, + ); + assert.ok(rows.length <= 1, 'Swift fixture source base archive repeats'); + return rows.length ? [[asset.role, rows[0].file]] : []; + }), + ); + if (Object.keys(archives).length) { + assert.equal( + Object.keys(archives).length, + 2, + 'Swift fixture source base archive tuple is incomplete', + ); + nativeBaseArchiveInputs = archives; + } + } + assertSelectedNativeEnvelope(candidate, complete, prepared.record.selectedProducts, { + nativeBaseArchiveInputs, + }); + validatePublicationCandidate(candidate); + assert.deepEqual(candidate.missing, [], 'native selected publication is incomplete'); + const reviewed = reviewedObservations.get(observation); + assert.ok( + reviewed, + 'native publication observation was not checked against actual acquired producers', + ); + equal( + reviewed.complete, + consumerDigest(complete), + 'native complete envelope changed after observation', + ); + equal( + reviewed.run, + consumerDigest(acquisition.run), + 'native qualifying run changed after observation', + ); + equal( + reviewed.observation, + consumerDigest(observation), + 'native physical observation changed after validation', + ); + // The observer must be the already checked actual origins, never supplied JSON. + equal( + observation.authenticated.map(({ origin }) => origin.evidenceDigest).sort(), + [...acquisition.origins.values()] + .map((origin) => assertAuthenticatedNativeBuildOrigin(origin).evidenceDigest) + .sort(), + 'native observation is not the acquired producer set', + ); + for (const { origin } of observation.authenticated) assertAuthenticatedNativeBuildOrigin(origin); + const metadata = candidate.productArtifacts.filter( + (artifact) => artifact.kind === NATIVE_PUBLICATION_METADATA_KIND, + ); + const withoutMetadata = { + ...candidate, + productArtifacts: candidate.productArtifacts.filter( + (artifact) => artifact.kind !== NATIVE_PUBLICATION_METADATA_KIND, + ), + }; + const selectedFiles = lockedPublicationFiles(candidate).filter( + (file) => !metadata.some((artifact) => file.path === artifact.path), + ); + const selectedObservation = projectNativePublicationConstruction( + { envelope: withoutMetadata, files: selectedFiles }, + observation.authenticated, + ); + for (const build of selectedObservation.authenticated) + assertNativeFinalShippingPhase(build.qualification, prepared.record.selectedProducts); + const records = observedNativePublicationMetadata( + { + envelope: withoutMetadata, + files: selectedFiles, + repository, + bazelVersion: readFileSync(path.join(ROOT, '.bazelversion'), 'utf8').trim(), + builds: acquisition.builds, + reviewedSource: candidate.source, + }, + selectedObservation, + publicationQualification(prepared, acquisition, complete), + ); + assert.equal(metadata.length, records.length, 'native selected metadata coverage differs'); + for (const record of records) { + const artifact = metadata.find((row) => row.product === record.product.id); + assert.ok(artifact, 'native selected product provenance is missing'); + equal( + JSON.parse(readFileSync(path.resolve(ROOT, artifact.path), 'utf8')), + record, + 'native publication metadata differs from actual configured observation', + ); + } + const suppliers = await projectNativeBuildBoundSuppliers({ + products: Object.fromEntries(complete.products.map((product) => [product.id, product])), + source: complete.source, + observation, + completed, + }); + assert.deepEqual( + suppliers.unknowns, + [], + 'native publication has unknown supplier bytes or origins', + ); + assert.ok(suppliers.buildBound, 'native publication lacks complete configured suppliers'); + const edges = (map: Map>) => + [...map] + .map(([id, rows]) => [id, [...rows].sort()]) + .sort(([a], [b]) => String(a).localeCompare(String(b))); + equal( + edges(suppliers.buildBound), + edges(prepared.buildBound), + 'post-version supplier adoption differs from prepared selection', + ); + validateReleaseConsumerCompatibility(prepared.record.selectedProducts, { + buildBound: suppliers.buildBound, + }); + lockedPublicationFiles(candidate); + admitted.set(candidate, { + digest: consumerDigest(candidate), + prepared, + origins: Object.freeze([...acquisition.origins.values()]), + }); + return suppliers; +} + +/** A structural record, clone, edited candidate or missing retained File cannot authorize freeze. */ +export function assertAdmittedNativePublicationCandidate(candidate: Candidate) { + const proof = admitted.get(candidate); + assert.ok(proof, 'native candidate has not passed authenticated publication admission'); + equal(consumerDigest(candidate), proof.digest, 'native admitted candidate changed'); + assertAcquiredPreparedNativeReleaseInputs(proof.prepared); + for (const origin of proof.origins) assertAuthenticatedNativeBuildOrigin(origin); + lockedPublicationFiles(candidate); +} + +export async function acquireNativePublicationPreparation({ + source, + prepareRunId, + pullNumber, + directory, +}: { + source: NativeBuildSource; + prepareRunId?: number; + pullNumber?: number; + directory: string; +}) { + const context = await resolveNativeReleaseInputContext({ source, pullNumber }); + assert.ok( + context, + 'native publication requires an authenticated canonical release PR transition', + ); + if (prepareRunId === undefined) { + // Reuse the same exact-source workflow selector used by native CI, without + // accepting any unrelated branch or current main run as preparation. + const parent = requireSafeDirectoryChain(path.dirname(directory), { + create: true, + }); + const result = path.join(parent, 'prepare-run.output'); + execFileSync( + 'bash', + [ + path.join(ROOT, '.github/scripts/require-workflow-success.sh'), + 'Release', + context.prepareSourceCommit, + '900', + '--event', + 'workflow_dispatch', + '--job', + 'Prepare release PR', + '--artifact', + 'native-release-inputs', + ], + { + cwd: ROOT, + env: { ...process.env, GH_REPO: repository, GITHUB_OUTPUT: result }, + stdio: ['ignore', 'inherit', 'inherit'], + }, + ); + const match = /^run_id=([1-9][0-9]*)$/mu.exec(readFileSync(result, 'utf8')); + assert.ok(match, 'exact-source Prepare selection did not return a run'); + prepareRunId = Number(match[1]); + } + const prepared = await acquirePreparedNativeReleaseInputs({ + runId: prepareRunId, + pullNumber: context.pullNumber, + source, + directory, + }); + assertAcquiredPreparedNativeReleaseInputs(prepared); + return { prepared, prepareRunId }; +} + +/** Project facts only; callers must acquire the actual successful Prepare producer. */ +export function projectPreparedNativePublicationPlan( + record: NativeReleaseInputRecord, + source: NativeBuildSource, + directory = ROOT, +) { + parseNativeReleaseInputRecord(record); + equal(source.tree, record.preparedSource.tree, 'native plan differs from the prepared tree'); + const read = (commit: string, file: string) => + JSON.parse( + execFileSync('git', ['show', `${commit}:${file}`], { + cwd: directory, + encoding: 'utf8', + maxBuffer: 16 * 1024 * 1024, + }), + ); + const config = read(source.commit, 'release-please-config.json'); + const after = read(source.commit, '.release-please-manifest.json'); + const products = releaseProductsFromManifests( + config, + read(record.bridge.source.commit, '.release-please-manifest.json'), + after, + ); + equal(products, record.selectedProducts, 'native plan differs from the actual RP scope'); + const versions = Object.fromEntries( + products.map((id) => { + const packagePath = Object.entries(config.packages).find( + ([, entry]: [string, any]) => entry.component === id, + )?.[0]; + assert.ok(packagePath, 'native publication owner has no conventional manifest path'); + const version = after[packagePath]; + assert.match(version, /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u); + return [id, version]; + }), + ); + return { + mode: 'release-bump', + publicationSha: source.commit, + releaseSha: source.commit, + products, + versions, + }; +} + +export async function planNativePublicationFromPrepare(headRef = 'HEAD') { + const source = sourceIdentity(headRef); + const parent = requireSafeDirectoryChain(path.join(ROOT, 'target/native-publication'), { + create: true, + }); + const directory = mkdtempSync(path.join(parent, 'plan-')); + const { prepared } = await acquireNativePublicationPreparation({ + source, + directory: path.join(directory, 'prepared'), + }); + return projectPreparedNativePublicationPlan(prepared.record, source); +} + +export async function freezeNativePublicationFromRun({ + runId, + prepareRunId, + pullNumber, + products, + headRef = 'HEAD', + output, +}: { + runId: number; + prepareRunId?: number; + pullNumber?: number; + products: string[]; + headRef?: string; + output: string; +}) { + const source = sourceIdentity(headRef); + equal(sourceIdentity('HEAD'), source, 'native publication requires the exact source checkout'); + execFileSync( + 'bash', + [path.join(ROOT, 'tools/release/qualified-release-replay.sh'), source.commit, source.commit], + { cwd: ROOT, stdio: ['ignore', 'ignore', 'pipe'] }, + ); + const parent = requireSafeDirectoryChain(path.join(ROOT, 'target/native-publication'), { + create: true, + }); + const directory = mkdtempSync(path.join(parent, `${runId}-`)); + const preparation = await acquireNativePublicationPreparation({ + source, + prepareRunId, + pullNumber, + directory: path.join(directory, 'prepared'), + }); + const { prepared } = preparation; + prepareRunId = preparation.prepareRunId; + equal( + [...products].sort(), + prepared.record.selectedProducts, + 'requested native publication differs from actual RP versions', + ); + const acquisition = await acquireNativePublicationBuilds({ + source, + runId, + directory: path.join(directory, 'producers'), + }); + assertSuccessfulNativePublicationRun(acquisition.run, source); + const artifactRoots: string[] = []; + for (const origin of acquisition.origins.values()) { + assertAuthenticatedNativeBuildOrigin(origin); + assert.ok( + origin.finalFiles && 'stage' in origin.finalFiles, + 'native publication has no retained public File transport', + ); + artifactRoots.push( + ...origin.finalFiles.stage({ + excludeRoles: [ + 'github-release-asset', + 'github-release-metadata', + ...NATIVE_EXTENSION_RELEASE_INPUT_ROLES, + ], + artifactPhase: 'pre-version', + }), + ); + } + const families = stageNativeReleaseFamilies( + acquisition.origins, + source, + path.join(directory, 'families'), + ); + const complete = buildPublicationCandidate({ + products: loadPublicationCatalog('native complete publication').products.map(({ id }) => id), + artifactRoots: [...artifactRoots, ...families], + headRef: source.commit, + artifactPhase: 'pre-version', + }); + assertCompleteInventory(complete); + const bazelVersion = readFileSync(path.join(ROOT, '.bazelversion'), 'utf8').trim(); + const observation = await observeAuthenticated(complete, acquisition, bazelVersion); + // Stage only the selected public roots for publication. Full inventory staging + // above is qualification scratch, never an implicit release selection. + const selectedRoots: string[] = []; + for (const origin of acquisition.origins.values()) { + const observedProducts = new Set( + origin.evidence.cohorts.flatMap((cohort) => cohort.roots.map((root) => root.package.product)), + ); + const owned = products.filter((id) => observedProducts.has(id)); + if (!owned.length) continue; + assert.ok(origin.finalFiles && 'stage' in origin.finalFiles); + selectedRoots.push( + ...origin.finalFiles.stage({ + products: owned, + excludeRoles: [ + 'github-release-asset', + 'github-release-metadata', + ...NATIVE_EXTENSION_RELEASE_INPUT_ROLES, + ], + }), + ); + } + const selectedFamilies = stageNativeReleaseFamilies( + acquisition.origins, + source, + path.join(directory, 'selected-families'), + products, + ); + const selected = buildPublicationCandidate({ + products, + artifactRoots: [...selectedRoots, ...selectedFamilies], + headRef: source.commit, + swiftExtensionFixture: nativeSwiftFixtureRequest(complete, products).length > 0, + }); + const selectedObservation = projectNativePublicationConstruction( + { envelope: selected, files: lockedPublicationFiles(selected) }, + observation.authenticated, + ); + const records = observedNativePublicationMetadata( + { + envelope: selected, + files: lockedPublicationFiles(selected), + repository, + bazelVersion, + builds: acquisition.builds, + reviewedSource: source, + }, + selectedObservation, + publicationQualification(prepared, acquisition, complete), + ); + await writeMetadataRecords(path.join(directory, 'metadata'), records); + const candidate = buildPublicationCandidate({ + products, + artifactRoots: [...selectedRoots, ...selectedFamilies, path.join(directory, 'metadata')], + headRef: source.commit, + nativeMetadataProducts: products, + swiftExtensionFixture: nativeSwiftFixtureRequest(complete, products).length > 0, + }); + const completed = await acquireObservedCompletedSuppliers( + observation, + path.join(directory, 'held'), + JSON.parse(readFileSync(prepared.snapshotFile, 'utf8')).supplierArtifacts ?? [], + ); + await admitNativePublicationCandidate({ + candidate, + complete, + prepared, + acquisition, + observation, + completed, + }); + const lock = await freezeNativePublicationCandidate(candidate); + const destination = path.resolve(output); + requireSafeDirectoryChain(path.dirname(destination), { + create: true, + label: 'native publication lock', + }); + assert.ok(!existsSync(destination), 'native publication lock output already exists'); + writeFileSync(destination, `${JSON.stringify(lock, null, 2)}\n`, { flag: 'wx', mode: 0o600 }); + return { lock, file: destination, runId, prepareRunId }; +} + +if (import.meta.main) { + const { values } = parseArgs({ + allowPositionals: false, + options: { + 'run-id': { type: 'string' }, + 'prepare-run-id': { type: 'string' }, + 'pull-number': { type: 'string' }, + 'products-json': { type: 'string' }, + 'plan-publication': { type: 'boolean' }, + 'github-output': { type: 'string' }, + 'head-ref': { type: 'string', default: 'HEAD' }, + output: { type: 'string', default: 'target/release/publication-lock.json' }, + }, + }); + if (values['plan-publication']) { + assert.ok( + !['run-id', 'prepare-run-id', 'pull-number', 'products-json'].some((name) => values[name]), + 'native publication planning derives its authenticated Prepare scope', + ); + const plan = await planNativePublicationFromPrepare(values['head-ref']); + if (values['github-output']) + appendFileSync( + values['github-output'], + [ + `mode=${plan.mode}`, + `publication_sha=${plan.publicationSha}`, + `release_sha=${plan.releaseSha}`, + `products_json=${JSON.stringify(plan.products)}`, + '', + ].join('\n'), + ); + console.log(JSON.stringify(plan)); + process.exit(0); + } + const id = (name: string, optional = false) => { + if (optional && values[name] === undefined) return undefined; + const value = Number(values[name]); + assert.ok(Number.isSafeInteger(value) && value > 0, `native publication requires --${name}`); + return value; + }; + const products = JSON.parse(values['products-json'] ?? 'null'); + assert.ok( + Array.isArray(products) && + products.length && + products.every((value) => typeof value === 'string'), + 'native publication requires --products-json', + ); + const result = await freezeNativePublicationFromRun({ + runId: id('run-id'), + prepareRunId: id('prepare-run-id', true), + pullNumber: id('pull-number', true), + products, + headRef: values['head-ref'], + output: values.output, + }); + console.log(result.file); +} diff --git a/tools/release/native-freeze-publication-candidate.test.mts b/tools/release/native-freeze-publication-candidate.test.mts new file mode 100644 index 000000000..d22e18b36 --- /dev/null +++ b/tools/release/native-freeze-publication-candidate.test.mts @@ -0,0 +1,414 @@ +import { expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { assertNativeSwiftShippingPhase } from './native-build-qualification.mts'; +import { + acquireObservedCompletedSuppliers, + admitNativePublicationCandidate, + assertAdmittedNativePublicationCandidate, + assertSelectedNativeEnvelope, + assertSuccessfulNativePublicationRun, + nativeSwiftFixtureRequest, +} from './native-freeze-publication-candidate.mts'; +import { loadPublicationCatalog } from './publication-catalog.mts'; +import { + expectedProductArtifactRows, + freezeNativePublicationCandidate, +} from './publication-lock.mts'; +import { fixtureCompletedNativeInventory } from './testdata/prepare-release-candidate-fixtures.mts'; + +const source = { commit: 'a'.repeat(40), tree: 'b'.repeat(40) }; +const successful = { + id: 77, + run_attempt: 2, + head_sha: source.commit, + head_branch: 'main', + event: 'push', + path: '.github/workflows/bazel.yml', + name: 'Native Bazel qualification', + status: 'completed', + conclusion: 'success', +}; +test('post-version publication accepts only the exact successful main Native run', () => { + expect(() => assertSuccessfulNativePublicationRun(successful, source)).not.toThrow(); + for (const [field, value] of [ + ['id', 0], + ['run_attempt', 0], + ['head_sha', 'c'.repeat(40)], + ['head_branch', 'feature'], + ['event', 'pull_request'], + ['path', '.github/workflows/ci.yml'], + ['name', 'CI Builds'], + ['status', 'in_progress'], + ['conclusion', 'failure'], + ]) + expect(() => + assertSuccessfulNativePublicationRun({ ...successful, [field]: value }, source), + ).toThrow(); +}); + +function envelopes() { + const products = ['sdk', 'query', 'broker'].map((id, index) => ({ + id, + version: `0.${index + 1}.0`, + })); + const carriers = products.map(({ id, version }, index) => ({ + id: `npm:${id}`, + product: id, + version, + ecosystem: 'npm', + name: id, + dependencies: [], + publishOrder: index, + packageDependencies: [ + { ecosystem: 'npm', name: 'held', requirement: '1.2.3', scope: 'optional' }, + ], + artifacts: [{ path: `target/${id}.tgz`, sha256: `${index + 1}`.repeat(64), size: 100 + index }], + })); + const artifacts = products.map(({ id }, index) => ({ + id: `github-release:${id}.tar.gz`, + product: id, + kind: 'native-runtime', + path: `target/${id}.tar.gz`, + sha256: `${index + 1}`.repeat(64), + size: 200 + index, + })); + return { source, products, carriers, productArtifacts: artifacts, artifactPhase: 'pre-version' }; +} +function select(full, products: string[]) { + const copy = structuredClone(full); + return { + ...copy, + artifactPhase: 'final', + products: copy.products.filter(({ id }) => products.includes(id)), + carriers: copy.carriers + .filter(({ product }) => products.includes(product)) + .map((row, publishOrder) => ({ ...row, publishOrder })), + productArtifacts: copy.productArtifacts.filter(({ product }) => products.includes(product)), + }; +} +test('one or several products project original byte identities without retargeting held requirements', () => { + const full = envelopes(); + for (const ids of [['query'], ['sdk', 'broker'], ['sdk', 'query', 'broker']]) { + const candidate = select(full, ids); + expect(() => assertSelectedNativeEnvelope(candidate as any, full as any, ids)).not.toThrow(); + expect(full.carriers.filter(({ product }) => !ids.includes(product))).toEqual( + envelopes().carriers.filter(({ product }) => !ids.includes(product)), + ); + } +}); +test('scope, source, manifest requirement and carrier payload substitutions fail before freeze', () => { + const full = envelopes(); + for (const mutate of [ + (candidate) => { + candidate.source.commit = 'c'.repeat(40); + }, + (candidate) => { + candidate.products.push(full.products[0]); + }, + (candidate) => { + candidate.carriers[0].version = '9.0.0'; + }, + (candidate) => { + candidate.carriers[0].packageDependencies[0].requirement = '9.0.0'; + }, + (candidate) => { + candidate.carriers[0].artifacts[0].sha256 = 'f'.repeat(64); + }, + (candidate) => { + candidate.productArtifacts[0].size++; + }, + (candidate) => { + candidate.artifactPhase = 'pre-version'; + }, + ]) { + const candidate = select(full, ['query']); + mutate(candidate); + expect(() => assertSelectedNativeEnvelope(candidate as any, full as any, ['query'])).toThrow(); + } + expect(() => + assertSelectedNativeEnvelope(select(full, ['query']) as any, full as any, ['query', 'query']), + ).toThrow(); +}); +test('structural prepared inputs and raw observation JSON cannot mint admission', async () => { + await expect( + admitNativePublicationCandidate({ + candidate: {}, + complete: {}, + prepared: { record: { selectedProducts: ['query'] } }, + acquisition: { run: successful, origins: new Map(), builds: [] }, + observation: {}, + completed: [], + } as any), + ).rejects.toThrow(/authenticated Prepare producer/); + expect(() => assertAdmittedNativePublicationCandidate({} as any)).toThrow( + /authenticated publication admission/, + ); + // The native freezer still validates the entire canonical envelope first. + await expect(freezeNativePublicationCandidate({})).rejects.toThrow(); +}); + +test('Swift fixture requests follow the original source requirements, not selected product co-occurrence', () => { + const root = mkdtempSync(path.join(tmpdir(), 'native-swift-fixture-scope-')); + const reference = (product, version) => ({ product, version, tag: `${product}-v${version}` }); + const artifact = (product, version, baseVersion, kind) => { + const file = path.join(root, `${product}.json`); + writeFileSync( + file, + JSON.stringify({ + release: reference(product, version), + base: reference('liboliphaunt-native', baseVersion), + }), + ); + return { product, kind, path: file }; + }; + try { + const complete = { + products: [ + { id: 'oliphaunt-swift', version: '1.0.0' }, + { id: 'liboliphaunt-native', version: '0.3.4' }, + { id: 'oliphaunt-extension-vector', version: '0.2.0' }, + { id: 'liboliphaunt-wasix', version: '0.3.4' }, + ], + productArtifacts: [ + artifact('oliphaunt-swift', '1.0.0', '0.3.3', 'swiftpm-ios-carrier-manifest'), + artifact('liboliphaunt-native', '0.3.4', '0.3.4', 'swift-extension-carrier'), + artifact('oliphaunt-extension-vector', '0.2.0', '0.3.3', 'swift-extension-carrier'), + ], + } as any; + for (const [selection, requested] of [ + [['oliphaunt-swift'], []], + [['oliphaunt-swift', 'liboliphaunt-wasix'], []], + [['oliphaunt-swift', 'liboliphaunt-native'], []], + [['oliphaunt-swift', 'oliphaunt-extension-vector'], ['oliphaunt-extension-vector']], + [ + ['oliphaunt-swift', 'oliphaunt-extension-vector', 'liboliphaunt-native'], + ['oliphaunt-extension-vector'], + ], + [['liboliphaunt-native', 'oliphaunt-extension-vector'], []], + ]) + expect(nativeSwiftFixtureRequest(complete, selection)).toEqual(requested); + // Substituting a final control from another package version fails before + // compatibility matching; no mismatched artifact is silently discarded. + writeFileSync( + complete.productArtifacts[2].path, + JSON.stringify({ + release: reference('oliphaunt-extension-vector', '9.0.0'), + base: reference('liboliphaunt-native', '9.0.0'), + }), + ); + expect(() => + nativeSwiftFixtureRequest(complete, ['oliphaunt-swift', 'oliphaunt-extension-vector']), + ).toThrow(/carrier version differs/); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('artifact inventory records an explicit consumer input without reading current SDK adoption for historical locks', () => { + const catalog = loadPublicationCatalog('actual Swift fixture scope', { + products: ['oliphaunt-swift', 'liboliphaunt-native'], + }); + const fixture = (options = {}) => + expectedProductArtifactRows(catalog.products, options).filter( + ({ kind }) => kind === 'swiftpm-extension-consumer-fixture', + ); + expect(fixture()).toHaveLength(0); + expect(fixture({ swiftExtensionFixture: true })).toHaveLength(1); + expect(fixture({ swiftExtensionFixture: true, artifactPhase: 'pre-version' })).toHaveLength(0); + expect(() => + expectedProductArtifactRows( + catalog.products.filter(({ id }) => id !== 'oliphaunt-swift'), + { swiftExtensionFixture: true }, + ), + ).toThrow(/source SDK product/); +}); + +test('two source cycles reuse the exact prepared Git source and owned binding without a download or current substitution', async () => { + const directory = mkdtempSync(path.join(tmpdir(), 'native-freeze-source-suppliers-')); + try { + const publication = (version) => ({ + product: 'oliphaunt-swift', + version, + tagName: `oliphaunt-swift-v${version}`, + publicationSha: '1'.repeat(40), + publicationTree: '2'.repeat(40), + releaseSha: '3'.repeat(40), + }); + const rows = (version) => { + const completed = publication(version); + const file = (name, bytes) => { + const target = path.join(directory, name); + writeFileSync(target, bytes); + return { + path: target, + size: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + }; + }; + return [ + { + publication: completed, + artifact: `swift-source-tag:${version}`, + source: { + commit: '4'.repeat(40), + tree: '5'.repeat(40), + member: 'src/sdks/swift/Carriers/oliphaunt-react-native-ios-carriers.json', + blob: '6'.repeat(40), + }, + file: file( + `source-${version}.tar.gz`, + Buffer.from('controlled retained Git source; replay remains mandatory'), + ), + }, + { + publication: completed, + artifact: `github-release:retired-swift-${version}.zip`, + file: file( + `retired-swift-${version}.zip`, + Buffer.from('controlled retained binding; public authentication remains mandatory'), + ), + }, + ]; + }; + const observation = (origin) => ({ + authenticated: [ + { evidence: { cohorts: [{ roots: [{ package: { supplierInputs: [{ origin }] } }] }] } }, + ], + }); + const origin = (version) => ({ + kind: 'completed-publication', + publication: publication(version), + artifact: `swift-source-tag:${version}`, + }); + const first = rows('0.8.2'); + const acquireHeld = (observation, directory, retained) => + acquireObservedCompletedSuppliers(observation, directory, retained, { + inventory: async (publication) => { + const historic = await fixtureCompletedNativeInventory(publication); + return { + ...historic, + publicRows: historic.publicRows.map((row) => + row.kind === 'swift-bindings' + ? { + ...row, + name: `retired-swift-${publication.version}.zip`, + id: `github-release:retired-swift-${publication.version}.zip`, + } + : row, + ), + }; + }, + readJson: async () => ({ id: 82 }), + readPages: async () => [], + }); + const held = await acquireHeld( + observation(origin('0.8.2')) as any, + path.join(directory, 'held'), + first, + ); + expect(held).toHaveLength(1); + expect(held[0]).toHaveProperty('sourceTags'); + expect(held[0].files[first[1].artifact]).toBe(first[1].file.path); + expect(held[0].sourceTags[0]).toEqual(first[0]); + const nextSource = await acquireHeld( + observation(origin('0.8.2')) as any, + path.join(directory, 'next-source'), + first, + ); + expect(nextSource).toEqual(held); + expect( + await acquireHeld( + observation({ kind: 'current-source' }) as any, + path.join(directory, 'current'), + first, + ), + ).toEqual([]); + const next = rows('0.8.3'); + const nextHeld = await acquireHeld( + observation(origin('0.8.3')) as any, + path.join(directory, 'next-held'), + [...first, ...next], + ); + expect(nextHeld[0].sourceTags[0]).toEqual(next[0]); + await expect( + acquireHeld(observation(origin('0.8.3')) as any, path.join(directory, 'missing'), first), + ).rejects.toThrow('absent from the acquired Prepare inputs'); + await expect( + acquireHeld(observation(origin('0.8.2')) as any, path.join(directory, 'no-binding'), [ + first[0], + ]), + ).rejects.toThrow('same-publication binding archive'); + const wrongBinding = structuredClone(first[1]); + wrongBinding.publication.publicationSha = '7'.repeat(40); + await expect( + acquireHeld(observation(origin('0.8.2')) as any, path.join(directory, 'wrong-binding'), [ + first[0], + wrongBinding, + ]), + ).rejects.toThrow('source differs'); + writeFileSync(first[0].file.path, 'tampered'); + await expect( + acquireHeld(observation(origin('0.8.2')) as any, path.join(directory, 'wrong-file'), first), + ).rejects.toThrow('File changed'); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('Swift preparation proves the source phase but cannot replace selected final installed qualification', () => { + const sourceRoot = { + label: '//src/native/sdks/swift:shipping_Oliphaunt-source_zip', + package: { + product: 'oliphaunt-swift', + ecosystem: 'github', + role: 'release-input', + name: 'Oliphaunt-source.zip', + }, + }; + const make = (owner: string, installed: boolean) => ({ + cohorts: [ + { + roots: [sourceRoot], + qualificationPolicy: { + policies: [ + { + owner, + roots: [sourceRoot.label], + requiredTests: [ + { label: '//src/native/sdks/swift:unit_test', configuration: 'source' }, + ...(installed + ? [ + { + label: '//src/native/sdks/swift:installed_consumer_test', + configuration: 'installed', + }, + ] + : []), + ], + }, + ], + }, + }, + ], + }); + const preparation = make('//src/native/sdks/swift:preparation_shipping_export', false); + const final = make('//src/native/sdks/swift:shipping_export', true); + expect(() => assertNativeSwiftShippingPhase(preparation as any, 'pre-version')).not.toThrow(); + expect(() => assertNativeSwiftShippingPhase(preparation as any, 'final')).toThrow('source-owned'); + expect(() => assertNativeSwiftShippingPhase(final as any, 'final')).not.toThrow(); + expect(() => assertNativeSwiftShippingPhase(final as any, 'pre-version')).not.toThrow(); + expect(() => + assertNativeSwiftShippingPhase( + make('//src/native/sdks/swift:shipping_export', false) as any, + 'final', + ), + ).toThrow('installed consumer'); + // A Native-only selection projects no Swift root and needs no final Swift run. + expect(() => assertNativeSwiftShippingPhase({ cohorts: [] } as any, 'final')).not.toThrow(); + const unrelated = structuredClone(final); + unrelated.cohorts[0].qualificationPolicy.policies[0].roots = ['//another:root']; + expect(() => assertNativeSwiftShippingPhase(unrelated as any, 'final')).toThrow('source-owned'); +}); diff --git a/tools/release/native-legal-source-basis.test.mts b/tools/release/native-legal-source-basis.test.mts new file mode 100644 index 000000000..3a07fa348 --- /dev/null +++ b/tools/release/native-legal-source-basis.test.mts @@ -0,0 +1,395 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { chmodSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import { buildIosCarrierManifest } from '../../src/native/sdks/swift/tools/ios-carrier-manifest.mts'; +import { + createCapturedPublishedNativeLegalSourceBasis, + createPublishedNativeLegalSourceBasis, + currentNativeLegalSourceBasis, + nativeBaseLegalForSource, +} from '../../src/native/sdks/swift/tools/native-legal-source-basis.mts'; +import { pinnedNativeCarrierDirectory } from '../../src/native/sdks/swift/tools/pinned-native-carrier.mts'; +import { IOS_CARRIER_SCHEMA } from '../../src/native/sdks/swift/tools/swift-native-carrier-contract.mts'; +import { validateSwiftSourceReleaseContract } from '../../src/native/sdks/swift/tools/swift-source-carrier-contract.mts'; +import { archiveDirectory } from '../packaging/archive-directory.mts'; +import { currentProductVersionSync } from './release-artifact-targets.mts'; + +function fixture({ nativeVersion = '2.3.4' } = {}) { + const swiftVersion = '4.5.6'; + const nativeSha = 'a'.repeat(40); + const swiftSha = 'b'.repeat(40); + const sourceSha = 'c'.repeat(40); + const groups = [ + { role: 'base-xcframework', profile: 'native-runtime', prefix: 'liboliphaunt.xcframework/' }, + { role: 'runtime-resources', profile: 'native-runtime-resources', prefix: '' }, + ]; + const carrier = { + schema: IOS_CARRIER_SCHEMA, + base: { + product: 'liboliphaunt-native', + version: nativeVersion, + tag: `liboliphaunt-native-v${nativeVersion}`, + assets: groups.map(({ role }, index) => { + const name = `liboliphaunt-${nativeVersion}-${index ? 'runtime-resources-ios-datum64.tar.gz' : 'apple-spm-xcframework.zip'}`; + return { + role, + name, + url: `https://github.com/f0rr0/oliphaunt/releases/download/liboliphaunt-native-v${nativeVersion}/${name}`, + sha256: createHash('sha256').update(name).digest('hex'), + bytes: Buffer.byteLength(name), + format: index ? 'tar.gz' : 'zip', + member: index ? 'oliphaunt' : 'liboliphaunt.xcframework', + }; + }), + }, + carriers: [], + extensions: [], + legal: { + base: groups.map(({ role, profile, prefix }) => ({ + assetRole: role, + profile, + spdx: 'MIT AND Historical-License', + files: [ + { kind: 'license', member: `${prefix}LICENSE`, sha256: '3'.repeat(64), bytes: 29 }, + { + kind: 'notice', + member: `${prefix}THIRD_PARTY_NOTICES.historical.md`, + sha256: '4'.repeat(64), + bytes: 37, + }, + ], + })), + extensions: [], + }, + }; + const bytes = Buffer.from(JSON.stringify(carrier)); + const blob = createHash('sha1').update(`blob ${bytes.length}\0`).update(bytes).digest('hex'); + const sourceMember = 'src/sdks/swift/Carriers/oliphaunt-react-native-ios-carriers.json'; + const responses = new Map([ + [ + `repos/f0rr0/oliphaunt/releases/tags/liboliphaunt-native-v${nativeVersion}`, + { + id: 1, + tag_name: `liboliphaunt-native-v${nativeVersion}`, + draft: false, + prerelease: false, + target_commitish: nativeSha, + }, + ], + [ + `repos/f0rr0/oliphaunt/releases/tags/oliphaunt-swift-v${swiftVersion}`, + { + id: 2, + tag_name: `oliphaunt-swift-v${swiftVersion}`, + draft: false, + prerelease: false, + target_commitish: swiftSha, + }, + ], + [ + `repos/f0rr0/oliphaunt/git/ref/tags/${swiftVersion}`, + { ref: `refs/tags/${swiftVersion}`, object: { type: 'commit', sha: sourceSha } }, + ], + [ + `repos/f0rr0/oliphaunt/git/commits/${sourceSha}`, + { sha: sourceSha, tree: { sha: 'd'.repeat(40) }, parents: [{ sha: swiftSha }] }, + ], + [ + `repos/f0rr0/oliphaunt/contents/${sourceMember}?ref=${sourceSha}`, + { + path: sourceMember, + type: 'file', + encoding: 'base64', + sha: blob, + content: bytes.toString('base64'), + }, + ], + ]); + const assets = carrier.base.assets.map((asset, index) => ({ + id: index + 10, + name: asset.name, + browser_download_url: asset.url, + digest: `sha256:${asset.sha256}`, + size: asset.bytes, + })); + const completed = []; + const options = { + nativeVersion, + swiftVersion, + readJson: async (endpoint) => { + assert.ok(responses.has(endpoint), endpoint); + return responses.get(endpoint); + }, + readPages: async (endpoint) => { + assert.equal(endpoint, 'repos/f0rr0/oliphaunt/releases/1/assets'); + return assets; + }, + assertCompletedPublication: async (identity) => { + completed.push(identity); + return { ...identity, publicationTree: 'e'.repeat(40), releaseSha: 'f'.repeat(40) }; + }, + }; + const captures = { + publication: { + product: 'liboliphaunt-native', + version: nativeVersion, + tagName: `liboliphaunt-native-v${nativeVersion}`, + publicationSha: nativeSha, + publicationTree: 'e'.repeat(40), + releaseSha: 'f'.repeat(40), + }, + nativeRelease: responses.get( + `repos/f0rr0/oliphaunt/releases/tags/liboliphaunt-native-v${nativeVersion}`, + ), + sourcePublication: { + product: 'oliphaunt-swift', + version: swiftVersion, + tagName: `oliphaunt-swift-v${swiftVersion}`, + publicationSha: swiftSha, + publicationTree: 'e'.repeat(40), + releaseSha: 'f'.repeat(40), + }, + sourceReference: responses.get(`repos/f0rr0/oliphaunt/git/ref/tags/${swiftVersion}`), + sourceCommit: responses.get(`repos/f0rr0/oliphaunt/git/commits/${sourceSha}`), + carrierContents: responses.get( + `repos/f0rr0/oliphaunt/contents/${sourceMember}?ref=${sourceSha}`, + ), + nativeAssets: assets, + }; + return { carrier, responses, assets, completed, options, sourceSha, captures }; +} + +test('declared independently verified captures bind the same historical package contract offline', () => { + const { carrier, captures } = fixture(); + const sourceBasis = createCapturedPublishedNativeLegalSourceBasis(captures); + const asset = carrier.base.assets[0]; + const inputs = { + carrier, + expectedNativeVersion: carrier.base.version, + manifestText: `.binaryTarget(name: "liboliphaunt", url: "${asset.url}", checksum: "${asset.sha256}")`, + }; + assert.throws( + () => validateSwiftSourceReleaseContract(inputs), + /canonical native Apple legal locators/, + ); + assert.deepEqual(validateSwiftSourceReleaseContract({ ...inputs, sourceBasis }).carrier, carrier); + const changed = structuredClone(carrier); + changed.legal.base[0].files[0].sha256 = '0'.repeat(64); + assert.throws( + () => validateSwiftSourceReleaseContract({ ...inputs, carrier: changed, sourceBasis }), + /canonical native Apple legal locators/, + ); + captures.nativeRelease.target_commitish = '0'.repeat(40); + assert.throws( + () => createCapturedPublishedNativeLegalSourceBasis(captures), + /completion differs/, + ); +}); + +test('historical source policy survives later legal changes and same-version fresh construction', async () => { + const { carrier, options, completed } = fixture(); + const basis = await createPublishedNativeLegalSourceBasis(options); + assert.equal(completed.length, 2); + assert.deepEqual( + nativeBaseLegalForSource({ + base: carrier.base, + sourceBasis: basis, + currentLegal: () => { + throw new Error('current source must not reinterpret historical policy'); + }, + }), + carrier.legal.base, + ); + const fresh = [{ assetRole: 'base-xcframework', files: ['future legal source'] }]; + assert.deepEqual( + nativeBaseLegalForSource({ + base: carrier.base, + sourceBasis: currentNativeLegalSourceBasis, + currentLegal: () => fresh, + }), + fresh, + ); + const changed = structuredClone(carrier.base); + changed.assets[0].sha256 = '9'.repeat(64); + assert.throws( + () => + nativeBaseLegalForSource({ base: changed, sourceBasis: basis, currentLegal: () => fresh }), + /differs from the authenticated publication/, + ); + assert.throws( + () => + nativeBaseLegalForSource({ + base: carrier.base, + sourceBasis: JSON.parse(JSON.stringify(basis)), + currentLegal: () => fresh, + }), + /authenticated published source basis/, + ); + const legal = nativeBaseLegalForSource({ + base: carrier.base, + sourceBasis: basis, + currentLegal: () => fresh, + }); + legal[0].files[0].sha256 = '0'.repeat(64); + assert.deepEqual( + nativeBaseLegalForSource({ base: carrier.base, sourceBasis: basis, currentLegal: () => fresh }), + carrier.legal.base, + ); +}); + +test('held source requires exact completion, source parent, Git blob and native asset identities', async () => { + const completion = fixture(); + completion.options.assertCompletedPublication = async (identity) => ({ + ...identity, + publicationSha: '0'.repeat(40), + publicationTree: 'e'.repeat(40), + releaseSha: 'f'.repeat(40), + }); + await assert.rejects( + createPublishedNativeLegalSourceBasis(completion.options), + /completion differs/, + ); + const parent = fixture(); + parent.responses.get(`repos/f0rr0/oliphaunt/git/commits/${parent.sourceSha}`).parents[0].sha = + '0'.repeat(40); + await assert.rejects(createPublishedNativeLegalSourceBasis(parent.options), /publication parent/); + const blob = fixture(); + const contents = [...blob.responses.values()].find((row) => row.encoding === 'base64'); + contents.content = Buffer.from('{}').toString('base64'); + await assert.rejects(createPublishedNativeLegalSourceBasis(blob.options), /immutable Git blob/); + const asset = fixture(); + asset.assets[0].digest = `sha256:${'0'.repeat(64)}`; + await assert.rejects( + createPublishedNativeLegalSourceBasis(asset.options), + /asset differs from immutable source/, + ); + const repeated = fixture(); + repeated.assets[1].id = repeated.assets[0].id; + await assert.rejects( + createPublishedNativeLegalSourceBasis(repeated.options), + /repeats an asset identity/, + ); +}); + +test('explicit held origin downloads published bytes for the same version as changed current source', async () => { + const version = currentProductVersionSync( + 'liboliphaunt-native', + 'native-legal-source-basis.test', + ); + const { carrier, options } = fixture({ nativeVersion: version }); + const sourceBasis = await createPublishedNativeLegalSourceBasis(options); + const workRoot = mkdtempSync(path.join(os.tmpdir(), 'published-native-carrier-')); + let downloads = 0; + let corrupt = false; + const fetchImpl = async (input) => { + const row = carrier.base.assets.find((asset) => asset.url === String(input)); + assert.ok(row, String(input)); + downloads += 1; + const response = new Response(corrupt ? 'x'.repeat(row.bytes) : row.name); + Object.defineProperty(response, 'url', { value: row.url }); + return response; + }; + try { + const inputs = { + version: carrier.base.version, + sourceBasis, + assetDir: '/different-current-source', + workRoot, + fetchImpl, + }; + assert.equal( + await pinnedNativeCarrierDirectory({ ...inputs, sourceBasis: currentNativeLegalSourceBasis }), + '/different-current-source', + ); + const directory = await pinnedNativeCarrierDirectory(inputs); + for (const asset of carrier.base.assets) + assert.equal(readFileSync(path.join(directory, asset.name), 'utf8'), asset.name); + assert.equal(downloads, 2); + await pinnedNativeCarrierDirectory(inputs); + assert.equal(downloads, 2); + rmSync(path.join(workRoot, 'pinned-native-carrier-cache'), { recursive: true }); + corrupt = true; + await assert.rejects(pinnedNativeCarrierDirectory(inputs), /checksum mismatch/); + await assert.rejects( + pinnedNativeCarrierDirectory({ ...inputs, version: '2.3.5' }), + /does not bind runtime/, + ); + } finally { + rmSync(workRoot, { recursive: true, force: true }); + } +}); + +test('held construction preserves historical member names while enforcing physical legal bytes and modes', async () => { + const { carrier, captures } = fixture(); + const directory = mkdtempSync(path.join(os.tmpdir(), 'held-native-legal-members-')); + const legalBytes = { + LICENSE: Buffer.from('independent historical license\n'), + 'THIRD_PARTY_NOTICES.historical.md': Buffer.from('historical notice before source changes\n'), + }; + const updateCapture = () => { + for (const [index, asset] of carrier.base.assets.entries()) { + const bytes = readFileSync(path.join(directory, asset.name)); + asset.sha256 = createHash('sha256').update(bytes).digest('hex'); + asset.bytes = bytes.length; + captures.nativeAssets[index].digest = `sha256:${asset.sha256}`; + captures.nativeAssets[index].size = asset.bytes; + } + const bytes = Buffer.from(JSON.stringify(carrier)); + captures.carrierContents.content = bytes.toString('base64'); + captures.carrierContents.sha = createHash('sha1') + .update(`blob ${bytes.length}\0`) + .update(bytes) + .digest('hex'); + return createCapturedPublishedNativeLegalSourceBasis(captures); + }; + try { + for (const [index, group] of carrier.legal.base.entries()) { + const staging = path.join(directory, `staging-${index}`); + const root = index ? staging : path.join(staging, 'liboliphaunt.xcframework'); + mkdirSync(path.join(staging, index ? 'oliphaunt' : 'liboliphaunt.xcframework'), { + recursive: true, + }); + writeFileSync( + path.join(staging, index ? 'oliphaunt/payload' : 'liboliphaunt.xcframework/payload'), + 'runtime fixture\n', + ); + for (const file of group.files) { + const bytes = legalBytes[path.posix.basename(file.member)]; + const output = path.join(staging, file.member); + writeFileSync(output, bytes); + chmodSync(output, 0o644); + file.sha256 = createHash('sha256').update(bytes).digest('hex'); + file.bytes = bytes.length; + } + await archiveDirectory(root, path.join(directory, carrier.base.assets[index].name), { + keepParent: index === 0, + }); + } + const options = { + baseAssetDir: directory, + baseRuntimeVersion: carrier.base.version, + extensionManifests: [], + }; + assert.throws( + () => buildIosCarrierManifest(options), + /canonical SHA-256|missing regular legal file/, + ); + const baseSourceBasis = updateCapture(); + assert.deepEqual(buildIosCarrierManifest({ ...options, baseSourceBasis }), carrier); + chmodSync(path.join(directory, 'staging-1/LICENSE'), 0o755); + await archiveDirectory( + path.join(directory, 'staging-1'), + path.join(directory, carrier.base.assets[1].name), + { keepParent: false }, + ); + assert.throws( + () => buildIosCarrierManifest({ ...options, baseSourceBasis: updateCapture() }), + /mode 0644/, + ); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); diff --git a/tools/release/native-prepare-continuation.mts b/tools/release/native-prepare-continuation.mts new file mode 100644 index 000000000..fa380f18e --- /dev/null +++ b/tools/release/native-prepare-continuation.mts @@ -0,0 +1,478 @@ +import assert from 'node:assert/strict'; +import { execFileSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { appendFileSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { readPortableArchiveEntries } from '../packaging/portable-archive.mts'; +import { + authHeaders, + boundedResponseBytes, + githubReadOptionsFromEnv, + requestGithubDownload, + requestGithubPages, + requestGithubRepositoryJson, + retryReadOperation, +} from './github-read.mts'; + +const REPOSITORY = 'f0rr0/oliphaunt'; +const API = `repos/${REPOSITORY}`; +const RELEASE = { name: 'Release', path: '.github/workflows/release.yml' }; +const NATIVE = { name: 'Native Bazel qualification', path: '.github/workflows/bazel.yml' }; +const REQUEST_JOB = 'Resolve native qualification for preparation'; +const INTENT_UPLOAD_STEP = 'Retain pending Prepare intent'; +const MAX_INTENT_BYTES = 64 * 1024; +const positive = (value) => Number.isSafeInteger(value) && value > 0; +const sha = (value) => typeof value === 'string' && /^[0-9a-f]{40}$/u.test(value); +export const nativePrepareIntentName = (attempt) => { + assert(positive(attempt), 'Prepare intent requires a positive original attempt'); + return `native-prepare-intent-${attempt}`; +}; + +function assertIntent(intent) { + assert( + intent?.schema === 1 && + intent.repository === REPOSITORY && + sha(intent.sourceSha) && + sha(intent.sourceTree) && + [ + intent.originalRunId, + intent.originalAttempt, + intent.nativeRunId, + intent.nativeAttempt, + ].every(positive), + 'Malformed native Prepare intent', + ); + assert.equal( + Object.keys(intent).sort().join(','), + 'nativeAttempt,nativeRunId,originalAttempt,originalRunId,repository,schema,sourceSha,sourceTree', + 'Unexpected native Prepare intent fields', + ); + return intent; +} + +export function recordNativePrepareIntent(environment, checkout) { + assert.equal(environment.GITHUB_REPOSITORY, REPOSITORY); + assert.equal(environment.GITHUB_EVENT_NAME, 'workflow_dispatch'); + assert.equal(environment.GITHUB_REF, 'refs/heads/main'); + assert.equal(environment.GITHUB_WORKFLOW_REF, `${REPOSITORY}/${RELEASE.path}@refs/heads/main`); + assert.equal(environment.RELEASE_OPERATION, 'prepare-release-pr'); + assert.equal( + environment.GITHUB_SHA, + checkout.sha, + 'Prepare intent must describe the actual checkout', + ); + return assertIntent({ + schema: 1, + repository: REPOSITORY, + sourceSha: checkout.sha, + sourceTree: checkout.tree, + originalRunId: Number(environment.GITHUB_RUN_ID), + originalAttempt: Number(environment.GITHUB_RUN_ATTEMPT), + nativeRunId: Number(environment.NATIVE_PENDING_RUN_ID), + nativeAttempt: Number(environment.NATIVE_PENDING_RUN_ATTEMPT), + }); +} + +function assertRun(run, workflow, sourceSha) { + assert( + positive(run?.id) && positive(run.workflow_id) && positive(run.run_attempt), + 'Malformed workflow run identity', + ); + assert.equal(run.repository?.full_name, REPOSITORY, 'Workflow run repository mismatch'); + assert.equal( + run.head_repository?.full_name, + REPOSITORY, + 'Workflow run source repository mismatch', + ); + assert.equal(run.name, workflow.name, 'Workflow run name mismatch'); + assert.equal(run.path, workflow.path, 'Workflow run path mismatch'); + assert.equal(run.head_branch, 'main', 'Workflow run must originate from main'); + assert.equal(run.head_sha, sourceSha, 'Workflow run source mismatch'); + assert(['push', 'workflow_dispatch'].includes(run.event), 'Workflow run event is ineligible'); +} + +class PendingCompletionMetadata extends Error {} + +function requireCompleted(value, label) { + if (value.status === 'completed') return; + assert( + ['queued', 'in_progress', 'waiting', 'pending', 'requested'].includes(value.status) && + value.conclusion === null, + `${label} has malformed completion metadata`, + ); + throw new PendingCompletionMetadata(`${label} is not yet visible as completed`); +} + +function oneJob(jobs, name, attempt, previous) { + const matches = jobs.filter((job) => job.name === name); + assert(matches.length <= 1, `Expected one ${name} job`); + if (!matches.length) throw new PendingCompletionMetadata(`${name} job is not yet visible`); + const job = matches[0]; + assert.equal(job.run_attempt, attempt, `${name} job attempt mismatch`); + assert(positive(job.id), `${name} job identity is invalid`); + if (previous) assert.equal(job.id, previous.id, `${name} job identity changed`); + return job; +} + +function githubIo(environment) { + return { + read: (endpoint, options) => requestGithubRepositoryJson(endpoint, { environment, ...options }), + list: (endpoint, itemsField, options) => + requestGithubPages(endpoint, { environment, itemsField, ...options }), + download: async (id, { timeoutMs }) => + boundedResponseBytes( + await requestGithubDownload(`https://api.github.com/${API}/actions/artifacts/${id}/zip`, { + environment, + timeoutMs: Math.min(30_000, timeoutMs), + }), + MAX_INTENT_BYTES, + 'Native Prepare intent artifact', + ), + rerun: async (id) => { + // A mutation is sent once. An ambiguous response needs operator inspection. + let response; + try { + response = await fetch(`https://api.github.com/${API}/actions/runs/${id}/rerun`, { + method: 'POST', + redirect: 'error', + signal: AbortSignal.timeout(30_000), + headers: { + ...authHeaders('application/vnd.github+json', environment.GH_TOKEN), + 'X-GitHub-Api-Version': '2026-03-10', + }, + }); + } catch (cause) { + throw new Error( + `Prepare rerun outcome is unknown; inspect Release run ${id} before retrying`, + { cause }, + ); + } + assert.equal( + response.status, + 201, + `Prepare rerun was not acknowledged; inspect Release run ${id} before retrying`, + ); + await response.body?.cancel?.(); + }, + }; +} + +async function readIntentArtifact(artifact, original, repositoryId, io) { + assert( + positive(artifact.id) && + !artifact.expired && + positive(artifact.size_in_bytes) && + artifact.size_in_bytes <= MAX_INTENT_BYTES && + /^sha256:[0-9a-f]{64}$/u.test(artifact.digest ?? ''), + 'Prepare intent artifact metadata is invalid or expired', + ); + assert.equal(artifact.workflow_run?.id, original.id, 'Prepare intent artifact producer mismatch'); + assert.equal(artifact.workflow_run?.repository_id, repositoryId); + assert.equal(artifact.workflow_run?.head_repository_id, repositoryId); + assert.equal(artifact.workflow_run?.head_branch, 'main'); + assert.equal(artifact.workflow_run?.head_sha, original.head_sha); + const bytes = await io.download(artifact.id); + assert.equal(bytes.length, artifact.size_in_bytes, 'Prepare intent artifact size mismatch'); + assert.equal( + `sha256:${createHash('sha256').update(bytes).digest('hex')}`, + artifact.digest, + 'Prepare intent artifact digest mismatch', + ); + const scratch = mkdtempSync(path.join(tmpdir(), 'native-prepare-intent-')); + try { + const archive = path.join(scratch, 'intent.zip'); + writeFileSync(archive, bytes); + const entries = readPortableArchiveEntries(archive, { + maxArchiveBytes: MAX_INTENT_BYTES, + maxEntries: 1, + maxEntryBytes: MAX_INTENT_BYTES, + maxExpandedBytes: MAX_INTENT_BYTES, + }); + assert.equal(entries.size, 1, 'Prepare intent artifact must contain only intent.json'); + const entry = entries.get('intent.json'); + assert.equal(entry?.type, 'file', 'Prepare intent artifact must contain intent.json'); + return assertIntent(JSON.parse(entry.data().toString('utf8'))); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +} + +// Intent routes an existing Prepare request. It never substitutes for Required +// or authorizes publication: the rerun repeats the original preparation gates. +export async function reconcileNativePrepare(event, io, readOptions = {}) { + assert.equal(event.repository?.full_name, REPOSITORY, 'Continuation repository mismatch'); + assert.equal(event.action, 'completed', 'Continuation requires a completion event'); + const trigger = event.workflow_run; + assert(sha(trigger?.head_sha), 'Continuation trigger source is invalid'); + const workflow = trigger.name === RELEASE.name ? RELEASE : NATIVE; + assertRun(trigger, workflow, trigger.head_sha); + assert.equal(trigger.status, 'completed'); + if ( + workflow === RELEASE && + (trigger.event !== 'workflow_dispatch' || + trigger.display_title !== 'Release / prepare-release-pr / main') + ) + return []; + const settings = githubReadOptionsFromEnv( + { + OLIPHAUNT_GITHUB_READ_DEADLINE_MS: '300000', + OLIPHAUNT_GITHUB_READ_MAX_ATTEMPTS: '10', + OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS: '5000', + OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS: '30000', + ...(readOptions.environment ?? process.env), + }, + readOptions, + ); + const now = settings.now ?? Date.now; + const deadline = now() + Math.min(300_000, settings.deadlineMs); + const remaining = () => { + const milliseconds = deadline - now(); + assert( + milliseconds > 0, + 'Prepare continuation metadata deadline exhausted; rerun original Prepare', + ); + return milliseconds; + }; + const reads = { + read: (endpoint) => io.read(endpoint, { deadlineMs: remaining(), now, sleep: settings.sleep }), + list: (endpoint, field) => + io.list(endpoint, field, { deadlineMs: remaining(), now, sleep: settings.sleep }), + download: (id) => io.download(id, { timeoutMs: remaining() }), + }; + const sourceSha = trigger.head_sha; + const repository = await reads.read(API); + assert.equal(repository.full_name, REPOSITORY); + assert(positive(repository.id), 'Canonical repository ID is missing'); + const workflows = await reads.list(`${API}/actions/workflows`, 'workflows'); + const workflowId = (expected) => { + const rows = workflows.filter( + (row) => row.name === expected.name && row.path === expected.path, + ); + assert.equal(rows.length, 1, `Expected one ${expected.name} workflow`); + assert(positive(rows[0].id), 'Workflow ID is invalid'); + return rows[0].id; + }; + const releaseId = workflowId(RELEASE), + nativeId = workflowId(NATIVE); + assert.equal(trigger.workflow_id, workflow === RELEASE ? releaseId : nativeId); + const originals = + workflow === RELEASE + ? [trigger] + : await reads.list( + `${API}/actions/workflows/${releaseId}/runs?head_sha=${sourceSha}&event=workflow_dispatch`, + 'workflow_runs', + ); + const resumed = []; + for (const candidate of originals) { + if (candidate.display_title !== 'Release / prepare-release-pr / main') continue; + assert(positive(candidate.id), 'Prepare candidate run identity is invalid'); + if (candidate.status === 'completed') + assert(positive(candidate.run_attempt), 'Completed Prepare candidate attempt is invalid'); + let originalAttempt = workflow === RELEASE ? trigger.run_attempt : undefined; + let originalCompleted = workflow === RELEASE; + let selectedNativeAttempt = workflow === NATIVE ? trigger.run_attempt : undefined; + let nativeCompleted = workflow === NATIVE; + let nativeEvent; + let intent; + let producer; + let required; + const readRun = async (id, expected) => { + const run = await reads.read(`${API}/actions/runs/${id}`); + assertRun(run, expected, sourceSha); + assert.equal(run.id, id, 'Workflow run ID mismatch'); + assert.equal(run.workflow_id, expected === RELEASE ? releaseId : nativeId); + if (expected === RELEASE) { + assert.equal(run.event, 'workflow_dispatch'); + assert.equal(run.display_title, 'Release / prepare-release-pr / main'); + } + return run; + }; + const runId = await retryReadOperation( + `Prepare run ${candidate.id} completion metadata; rerun original Prepare if readiness does not converge`, + async () => { + const original = await readRun(candidate.id, RELEASE); + if (originalAttempt === undefined) { + originalAttempt = Math.max( + original.run_attempt, + candidate.status === 'completed' ? candidate.run_attempt : 0, + ); + originalCompleted = + candidate.status === 'completed' && candidate.run_attempt === originalAttempt; + } + if (original.run_attempt > originalAttempt) return; + if ( + workflow === RELEASE && + trigger.conclusion !== 'success' && + original.status !== 'completed' + ) + return; // No need to await metadata for an unsuccessful request. + if (original.run_attempt < originalAttempt) + throw new PendingCompletionMetadata('Original Prepare attempt is not yet visible'); + if (original.status !== 'completed' && !originalCompleted) return; + requireCompleted(original, 'Original Prepare'); + originalCompleted = true; + if (workflow === RELEASE) + assert.equal( + original.conclusion, + trigger.conclusion, + 'Completed Prepare result conflicts with its trigger', + ); + if (original.conclusion !== 'success') return; // Never revive a failed/cancelled request. + if (!intent) { + const requestJobs = await reads.list( + `${API}/actions/runs/${original.id}/attempts/${originalAttempt}/jobs`, + 'jobs', + ); + producer = oneJob(requestJobs, REQUEST_JOB, originalAttempt, producer); + requireCompleted(producer, REQUEST_JOB); + assert.equal(producer.conclusion, 'success', 'Prepare intent producer did not succeed'); + const upload = producer.steps?.filter((step) => step.name === INTENT_UPLOAD_STEP) ?? []; + assert(upload.length <= 1, 'Prepare intent upload step is ambiguous'); + if (!upload.length) + throw new PendingCompletionMetadata('Prepare intent upload step is not yet visible'); + requireCompleted(upload[0], INTENT_UPLOAD_STEP); + if (upload[0].conclusion === 'skipped') return; + assert.equal(upload[0].conclusion, 'success', 'Prepare intent upload did not succeed'); + const artifacts = await reads.list( + `${API}/actions/runs/${original.id}/artifacts`, + 'artifacts', + ); + const matches = artifacts.filter( + (row) => row.name === nativePrepareIntentName(originalAttempt), + ); + assert(matches.length <= 1, 'Prepare intent artifact is ambiguous'); + if (!matches.length) + throw new PendingCompletionMetadata( + 'Uploaded Prepare intent artifact is not yet visible', + ); + const captured = await readIntentArtifact(matches[0], original, repository.id, reads); + assert.equal(captured.originalRunId, original.id); + assert.equal(captured.originalAttempt, originalAttempt); + assert.equal(captured.sourceSha, sourceSha); + const commit = await reads.read(`${API}/git/commits/${sourceSha}`); + assert.equal(commit.sha, sourceSha); + assert.equal( + commit.tree?.sha, + captured.sourceTree, + 'Prepare intent source tree mismatch', + ); + intent = captured; + } + if (workflow === NATIVE && trigger.id !== intent.nativeRunId) return; + const native = await readRun(intent.nativeRunId, NATIVE); + nativeEvent ??= native.event; + assert.equal(native.event, nativeEvent, 'Bound Native event changed'); + if (workflow === NATIVE) + assert.equal(native.event, trigger.event, 'Native trigger event mismatch'); + selectedNativeAttempt ??= Math.max(native.run_attempt, intent.nativeAttempt); + if (native.run_attempt > selectedNativeAttempt) return; + if ( + workflow === NATIVE && + trigger.conclusion !== 'success' && + native.status !== 'completed' + ) + assert.fail(`Bound Native qualification failed: ${trigger.html_url}`); + if (native.run_attempt < selectedNativeAttempt) + throw new PendingCompletionMetadata('Completed Native attempt is not yet visible'); + assert( + native.run_attempt >= intent.nativeAttempt, + `Bound Native attempt predates observed intent; rerun original Prepare https://github.com/${REPOSITORY}/actions/runs/${original.id} to select current proof`, + ); + if (native.status !== 'completed' && !nativeCompleted) return; + requireCompleted(native, 'Bound Native run'); + nativeCompleted = true; + if (workflow === NATIVE) + assert.equal( + native.conclusion, + trigger.conclusion, + 'Native completion result conflicts with its trigger', + ); + assert.equal( + native.conclusion, + 'success', + `Bound Native qualification failed: ${native.html_url}`, + ); + const nativeJobs = await reads.list( + `${API}/actions/runs/${native.id}/attempts/${selectedNativeAttempt}/jobs`, + 'jobs', + ); + required = oneJob(nativeJobs, 'Required', selectedNativeAttempt, required); + requireCompleted(required, 'Required'); + assert( + required.conclusion === 'success' || + (selectedNativeAttempt === intent.nativeAttempt && + native.event === 'push' && + required.conclusion === 'skipped'), + 'Bound Native run did not pass Required or finish as a successful scoped push', + ); + const currentMain = await reads.read(`${API}/git/ref/heads/main`); + assert.equal( + currentMain.object?.sha, + sourceSha, + 'Prepare source is no longer current main', + ); + const latestNative = await readRun(native.id, NATIVE); + assert.equal(latestNative.event, nativeEvent, 'Bound Native event changed'); + if (latestNative.run_attempt > selectedNativeAttempt) return; + if (latestNative.run_attempt < selectedNativeAttempt) + throw new PendingCompletionMetadata('Completed Native attempt is not yet visible'); + requireCompleted(latestNative, 'Bound Native run'); + assert.equal(latestNative.conclusion, 'success', 'Bound Native qualification changed'); + // Recheck after all reads under the controller's per-source concurrency lock. + const latest = await readRun(original.id, RELEASE); + if (latest.run_attempt > originalAttempt) return; + if (latest.run_attempt < originalAttempt) + throw new PendingCompletionMetadata('Original Prepare attempt is not yet visible'); + requireCompleted(latest, 'Original Prepare'); + assert.equal(latest.conclusion, 'success'); + return original.id; + }, + { + ...settings, + deadlineMs: remaining(), + classify: (error) => error instanceof PendingCompletionMetadata, + }, + ); + if (runId === undefined) continue; + await io.rerun(runId); // A mutation is never inside the metadata retry. + resumed.push({ + runId, + url: `https://github.com/${REPOSITORY}/actions/runs/${runId}`, + }); + } + return resumed; +} + +if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) { + const [command, file] = process.argv.slice(2); + if (command === 'record' && file) { + const intent = recordNativePrepareIntent(process.env, { + sha: execFileSync('git', ['rev-parse', 'HEAD'], { encoding: 'utf8' }).trim(), + tree: execFileSync('git', ['rev-parse', 'HEAD^{tree}'], { encoding: 'utf8' }).trim(), + }); + writeFileSync(file, JSON.stringify(intent) + '\n'); + appendFileSync( + process.env.GITHUB_OUTPUT, + `artifact_name=${nativePrepareIntentName(intent.originalAttempt)}\n`, + ); + } else if (command === 'resume' && file) { + assert.equal(process.env.GITHUB_REPOSITORY, REPOSITORY); + assert.equal(process.env.GITHUB_EVENT_NAME, 'workflow_run'); + assert.equal( + process.env.GITHUB_WORKFLOW_REF, + `${REPOSITORY}/.github/workflows/continue-release-prepare.yml@refs/heads/main`, + ); + const resumed = await reconcileNativePrepare( + JSON.parse(readFileSync(file, 'utf8')), + githubIo(process.env), + ); + const message = resumed.length + ? resumed.map((run) => `Resumed original Prepare: ${run.url}`).join('\n') + : 'No resumable Prepare request observed. If a pending request was missed, rerun original Prepare; indexed discovery has no automatic retry.'; + console.log(message); + if (process.env.GITHUB_STEP_SUMMARY) + appendFileSync(process.env.GITHUB_STEP_SUMMARY, message + '\n'); + } else throw new Error('usage: native-prepare-continuation.mts record|resume '); +} diff --git a/tools/release/native-prepare-continuation.test.mts b/tools/release/native-prepare-continuation.test.mts new file mode 100644 index 000000000..dcb91ae65 --- /dev/null +++ b/tools/release/native-prepare-continuation.test.mts @@ -0,0 +1,505 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import test from 'node:test'; +import { + reconcileNativePrepare, + recordNativePrepareIntent, +} from './native-prepare-continuation.mts'; +import { nativePrepareContinuationFixture } from './testdata/native-prepare-continuation-fixture.mts'; + +test('completion controller retains workflow_dispatch authority without idle waiting or publication credentials', () => { + const workflow = Bun.YAML.parse( + readFileSync( + new URL('../../.github/workflows/continue-release-prepare.yml', import.meta.url), + 'utf8', + ), + ); + assert.deepEqual(workflow.on.workflow_run, { + workflows: ['Native Bazel qualification', 'Release'], + types: ['completed'], + }); + assert.equal( + workflow.concurrency.group, + 'prepare-continuation-${{ github.event.workflow_run.head_sha }}', + ); + assert.equal(workflow.concurrency['cancel-in-progress'], false); + const job = workflow.jobs['resume-prepare']; + assert.deepEqual(job.permissions, { actions: 'write', contents: 'read' }); + assert.equal(job.environment, undefined); + assert.equal(job.steps[0].with.ref, '${{ github.sha }}'); + assert.match(job.if, /github\.repository == 'f0rr0\/oliphaunt'/u); + assert.match(job.if, /head_repository\.full_name == 'f0rr0\/oliphaunt'/u); + assert.match(job.if, /head_branch == 'main'/u); + assert.equal(job.steps.at(-1).env.GH_TOKEN, '${{ github.token }}'); + assert.equal( + job.steps.at(-1).run, + 'bun tools/release/native-prepare-continuation.mts resume "$GITHUB_EVENT_PATH"', + ); + assert.doesNotMatch(JSON.stringify(workflow), /secrets\.|release-mutation|sleep/u); +}); + +test('both completion orders resume the original exact-source request once', async () => { + for (const first of ['native', 'release']) { + const { state, io, event } = nativePrepareContinuationFixture(); + const second = first === 'native' ? 'release' : 'native'; + state[second === 'release' ? 'original' : 'native'].status = 'in_progress'; + assert.deepEqual(await reconcileNativePrepare(event(first), io), []); + state[second === 'release' ? 'original' : 'native'].status = 'completed'; + const result = await reconcileNativePrepare(event(second), io); + assert.deepEqual(result, [ + { runId: 41, url: 'https://github.com/f0rr0/oliphaunt/actions/runs/41' }, + ]); + assert.deepEqual(state.posts, [41]); + state.original.status = 'completed'; + assert.deepEqual(await reconcileNativePrepare(event('release'), io), []); + assert.deepEqual(state.posts, [41]); + } +}); + +test('successful scoped push wakes only the original request stage and dispatch never treats skipped Required as scoped', async () => { + const { state, io, event } = nativePrepareContinuationFixture(); + state.native.event = 'push'; + state.required = 'skipped'; + assert.equal((await reconcileNativePrepare(event(), io))[0].runId, 41); + const full = nativePrepareContinuationFixture(); + full.state.required = 'skipped'; + await assert.rejects(reconcileNativePrepare(full.event(), full.io), /did not pass Required/u); + assert.deepEqual(full.state.posts, []); +}); + +test('retained bytes, producer, source tree, bound Native attempt and current main guard the rerun', async () => { + const faults = [ + [ + (state) => { + state.bytes = Buffer.from('changed artifact'); + }, + /artifact size mismatch/u, + ], + [ + (state) => { + state.artifact.digest = `sha256:${'0'.repeat(64)}`; + }, + /artifact digest mismatch/u, + ], + [ + (state) => { + state.artifact.workflow_run.id = 42; + }, + /artifact producer mismatch/u, + ], + [ + (state) => { + state.producer = 'failure'; + }, + /producer did not succeed/u, + ], + [ + (state) => { + state.sourceTree = 'c'.repeat(40); + }, + /source tree mismatch/u, + ], + [ + (state) => { + state.native.conclusion = 'failure'; + }, + /Bound Native qualification failed/u, + ], + [ + (state) => { + state.currentMain = 'c'.repeat(40); + }, + /no longer current main/u, + ], + [ + (state) => { + state.native.head_repository = { full_name: 'attacker/fork' }; + }, + /source repository mismatch/u, + ], + ]; + for (const [fault, message] of faults) { + const { state, io, event } = nativePrepareContinuationFixture(); + fault(state); + await assert.rejects(reconcileNativePrepare(event('release'), io), message); + assert.deepEqual(state.posts, []); + } +}); + +test('a failed bound Native attempt can recover automatically through successful full proof on the same run', async () => { + const { state, io, event } = nativePrepareContinuationFixture(); + state.native.conclusion = 'failure'; + await assert.rejects(reconcileNativePrepare(event(), io), /Bound Native qualification failed/u); + assert.deepEqual(state.posts, []); + state.native.run_attempt = 2; + state.native.conclusion = 'success'; + assert.equal((await reconcileNativePrepare(event(), io))[0].runId, 41); + assert.deepEqual(state.posts, [41]); + assert.ok(state.requests.includes('repos/f0rr0/oliphaunt/actions/runs/88/attempts/2/jobs')); + assert.equal( + state.intent.nativeAttempt, + 1, + 'retained attempt 1 remains routing intent, never attempt 2 proof', + ); +}); + +test('recovery refuses stale completion, old Required jobs, skipped current Required, failure and an earlier attempt', async () => { + const stale = nativePrepareContinuationFixture(); + const previousCompletion = stale.event(); + stale.state.native.run_attempt = 2; + assert.deepEqual(await reconcileNativePrepare(previousCompletion, stale.io), []); + assert.deepEqual(stale.state.posts, []); + for (const mode of ['old-job', 'skipped', 'required-failed', 'failed', 'earlier']) { + const fixture = + mode === 'earlier' + ? nativePrepareContinuationFixture('a'.repeat(40), 'b'.repeat(40), 88, 2) + : nativePrepareContinuationFixture(); + const { state, io, event } = fixture; + state.native.run_attempt = mode === 'earlier' ? 1 : 2; + if (mode === 'old-job') state.requiredAttempt = 1; + if (mode === 'skipped') { + state.native.event = 'push'; + state.required = 'skipped'; + } + if (mode === 'required-failed') state.required = 'failure'; + if (mode === 'failed') state.native.conclusion = 'failure'; + const message = { + 'old-job': /Required job attempt mismatch/u, + skipped: /did not pass Required/u, + 'required-failed': /did not pass Required/u, + failed: /Bound Native qualification failed/u, + earlier: /predates observed intent/u, + }[mode]; + await assert.rejects(reconcileNativePrepare(event(), io), message); + assert.deepEqual(state.posts, []); + } +}); + +test('an explicit rerun racing the final read wins, and an ambiguous mutation is never retried', async () => { + const advanced = nativePrepareContinuationFixture(); + advanced.state.advanceBeforePost = true; + assert.deepEqual(await reconcileNativePrepare(advanced.event(), advanced.io), []); + assert.deepEqual(advanced.state.posts, []); + const ambiguous = nativePrepareContinuationFixture(); + ambiguous.state.ambiguous = true; + await assert.rejects( + reconcileNativePrepare(ambiguous.event(), ambiguous.io), + /outcome is unknown/u, + ); + assert.deepEqual(ambiguous.state.posts, [41]); +}); + +test('ordinary releases without a pending intent and failed original requests never resume', async () => { + for (const mode of ['no-intent', 'failed', 'publish']) { + const { state, io, event } = nativePrepareContinuationFixture(); + if (mode === 'no-intent') state.hasIntent = false; + if (mode === 'failed') state.original.conclusion = 'failure'; + if (mode === 'publish') state.original.display_title = 'Release / publish / main'; + assert.deepEqual(await reconcileNativePrepare(event('release'), io), []); + assert.deepEqual(state.posts, []); + } +}); + +test('intent records the actual source checkout and cannot route another release operation', () => { + const { state } = nativePrepareContinuationFixture(); + assert.throws( + () => + recordNativePrepareIntent(state.environment, { sha: 'c'.repeat(40), tree: state.sourceTree }), + /actual checkout/u, + ); + assert.throws( + () => + recordNativePrepareIntent( + { ...state.environment, RELEASE_OPERATION: 'publish' }, + { sha: state.intent.sourceSha, tree: state.sourceTree }, + ), + /prepare-release-pr/u, + ); +}); + +const api = 'repos/f0rr0/oliphaunt'; +const requestJob = (attempt, steps = []) => ({ + id: 701, + name: 'Resolve native qualification for preparation', + run_attempt: attempt, + status: 'completed', + conclusion: 'success', + steps, +}); +const pendingJob = (id, name, attempt) => ({ + id, + name, + run_attempt: attempt, + status: 'in_progress', + conclusion: null, +}); + +test('completed callbacks converge each expected API stage in either completion order', async () => { + for (const which of ['release', 'native']) + for (const stage of [ + 'original-attempt', + 'original-status', + 'request-missing', + 'request-pending', + 'upload-missing', + 'upload-pending', + 'artifact-missing', + 'required-missing', + 'required-pending', + ]) { + const fixture = nativePrepareContinuationFixture('a'.repeat(40), 'b'.repeat(40), 88, 2, 2); + const { state, io, event, readOptions } = fixture; + const trigger = event(which); + const original = `${api}/actions/runs/41`; + const request = `${original}/attempts/2/jobs`; + const required = `${api}/actions/runs/88/attempts/2/jobs`; + const [endpoint, value] = { + 'original-attempt': [original, { ...state.original, run_attempt: 1 }], + 'original-status': [ + original, + { ...state.original, status: 'in_progress', conclusion: null }, + ], + 'request-missing': [request, []], + 'request-pending': [ + request, + [pendingJob(701, 'Resolve native qualification for preparation', 2)], + ], + 'upload-missing': [request, [requestJob(2)]], + 'upload-pending': [ + request, + [ + requestJob(2, [ + { name: 'Retain pending Prepare intent', status: 'in_progress', conclusion: null }, + ]), + ], + ], + 'artifact-missing': [`${original}/artifacts`, []], + 'required-missing': [required, []], + 'required-pending': [required, [pendingJob(702, 'Required', 2)]], + }[stage]; + state.responses.set(endpoint, [value]); + assert.equal( + (await reconcileNativePrepare(trigger, io, readOptions))[0].runId, + 41, + `${which}/${stage}`, + ); + assert.equal(state.sleeps.length, 1, `${which}/${stage}`); + assert.deepEqual(state.posts, [41]); + assert.deepEqual(state.downloads, [501], 'authenticated intent is acquired once'); + assert(state.budgets.every((value) => value > 0 && value <= 300_000)); + } +}); + +test('Native completion catches up to its trigger attempt and status without changing selected proof', async () => { + const { state, io, event, readOptions } = nativePrepareContinuationFixture( + 'a'.repeat(40), + 'b'.repeat(40), + 88, + 2, + ); + const trigger = event(); + state.responses.set(`${api}/actions/runs/88`, [ + { ...state.native, run_attempt: 1 }, + { ...state.native, status: 'in_progress', conclusion: null }, + ]); + assert.equal((await reconcileNativePrepare(trigger, io, readOptions))[0].runId, 41); + assert.equal(state.sleeps.length, 2); + assert.deepEqual(state.downloads, [501]); + assert.deepEqual(state.posts, [41]); +}); + +test('Release completion catches up to the positively observed Native minimum without replacing it', async () => { + const { state, io, event, readOptions } = nativePrepareContinuationFixture( + 'a'.repeat(40), + 'b'.repeat(40), + 88, + 2, + ); + state.responses.set(`${api}/actions/runs/88`, [ + { ...state.native, run_attempt: 1, conclusion: 'failure' }, + ]); + assert.equal((await reconcileNativePrepare(event('release'), io, readOptions))[0].runId, 41); + assert.equal(state.sleeps.length, 1); + assert.deepEqual(state.downloads, [501]); +}); + +test('same-attempt terminal API results must agree with either completed trigger', async () => { + for (const which of ['release', 'native']) + for (const conclusion of ['failure', 'cancelled']) { + const { state, io, event, readOptions } = nativePrepareContinuationFixture(); + const trigger = event(which); + trigger.workflow_run.conclusion = conclusion; + await assert.rejects( + reconcileNativePrepare(trigger, io, readOptions), + /result conflicts with its trigger/u, + ); + assert.deepEqual(state.sleeps, []); + assert.deepEqual(state.posts, []); + } +}); + +test('unknown indexed absence, skipped upload and genuinely running counterparts return without polling', async () => { + for (const mode of ['unindexed', 'no-intent', 'release-running', 'native-running']) { + const { state, io, event, readOptions } = nativePrepareContinuationFixture(); + const which = mode === 'native-running' ? 'release' : 'native'; + if (mode === 'unindexed') state.indexedOriginals = []; + if (mode === 'no-intent') state.hasIntent = false; + if (mode === 'release-running') state.original.status = 'in_progress'; + if (mode === 'native-running') state.native.status = 'in_progress'; + assert.deepEqual(await reconcileNativePrepare(event(which), io, readOptions), []); + assert.deepEqual(state.sleeps, []); + assert.deepEqual(state.posts, []); + if (mode !== 'native-running') assert.deepEqual(state.downloads, []); + } +}); + +test('expected intent and Required visibility exhaust visibly within the existing retry budget', async () => { + for (const mode of ['intent', 'required']) { + const { state, io, event, readOptions } = nativePrepareContinuationFixture(); + if (mode === 'intent') { + state.hasIntent = false; + state.upload = 'success'; + } else state.responses.set(`${api}/actions/runs/88/attempts/1/jobs`, Array(3).fill([])); + await assert.rejects( + reconcileNativePrepare(event(), io, { ...readOptions, maxAttempts: 3 }), + /Prepare run 41.*retry budget exhausted after 3 attempt.*not yet visible/u, + ); + assert.equal(state.sleeps.length, 2); + assert.deepEqual(state.posts, []); + assert.equal(state.downloads.length, mode === 'intent' ? 0 : 1); + } +}); + +test('one five-minute deadline bounds nested reads despite a larger ambient setting', async () => { + const { state, io, event, readOptions } = nativePrepareContinuationFixture(); + state.responses.set(`${api}/actions/runs/41`, [ + () => { + state.now += 299_999; + return { ...state.original, status: 'in_progress', conclusion: null }; + }, + ]); + await assert.rejects( + reconcileNativePrepare(event('release'), io, { ...readOptions, deadlineMs: 3_600_000 }), + /overall deadline exhausted/u, + ); + assert.deepEqual(state.posts, []); + assert.deepEqual(state.sleeps, []); + assert(state.budgets.every((value) => value > 0 && value <= 300_000)); + const shared = nativePrepareContinuationFixture(); + shared.state.responses.set(api, [ + () => { + shared.state.now += 300_000; + return shared.state.original.repository; + }, + ]); + await assert.rejects( + reconcileNativePrepare(shared.event(), shared.io, shared.readOptions), + /metadata deadline exhausted/u, + ); + assert.equal(shared.state.requests.length, 1, 'discovery reads share the readiness deadline'); +}); + +test('observed producer identities and terminal failures never become readiness retries', async () => { + for (const mode of [ + 'job-drift', + 'source-drift', + 'failure', + 'ambiguous', + 'wrong-attempt', + 'upload-failed', + 'artifact-ambiguous', + 'http404', + ]) { + const { state, io, event, readOptions } = nativePrepareContinuationFixture(); + const required = `${api}/actions/runs/88/attempts/1/jobs`; + if (mode === 'job-drift') + state.responses.set(required, [ + [pendingJob(702, 'Required', 1)], + [{ ...pendingJob(703, 'Required', 1), status: 'completed', conclusion: 'success' }], + ]); + if (mode === 'source-drift') { + state.responses.set(required, [[pendingJob(702, 'Required', 1)]]); + state.responses.set(`${api}/actions/runs/88`, [ + state.native, + { ...state.native, head_sha: 'f'.repeat(40) }, + ]); + } + if (mode === 'failure') state.required = 'failure'; + if (mode === 'ambiguous') + state.responses.set(required, [ + [pendingJob(702, 'Required', 1), pendingJob(703, 'Required', 1)], + ]); + if (mode === 'wrong-attempt') state.requiredAttempt = 2; + if (mode === 'upload-failed') state.upload = 'failure'; + if (mode === 'artifact-ambiguous') + state.responses.set(`${api}/actions/runs/41/artifacts`, [ + [state.artifact, { ...state.artifact, id: 502 }], + ]); + if (mode === 'http404') + state.responses.set(`${api}/actions/runs/88`, [new Error('GitHub API returned HTTP 404')]); + await assert.rejects( + reconcileNativePrepare(event(), io, readOptions), + /permanent read failure/u, + ); + assert.equal(state.sleeps.length, ['job-drift', 'source-drift'].includes(mode) ? 1 : 0, mode); + assert.deepEqual(state.posts, []); + } +}); + +test('a newer actual Native attempt supersedes the trigger or selected proof before any POST', async () => { + for (const which of ['native', 'release']) { + const { state, io, event, readOptions } = nativePrepareContinuationFixture(); + state.advanceNativeBeforePost = true; + assert.deepEqual(await reconcileNativePrepare(event(which), io, readOptions), []); + assert.deepEqual(state.posts, []); + assert.deepEqual(state.sleeps, []); + } + const { state, io, event, readOptions } = nativePrepareContinuationFixture(); + const trigger = event(); + state.native.run_attempt = 2; + assert.deepEqual(await reconcileNativePrepare(trigger, io, readOptions), []); + assert.deepEqual(state.posts, []); +}); + +test('a Native attempt advancing during Required convergence is never substituted', async () => { + for (const which of ['release', 'native']) { + const { state, io, event, readOptions } = nativePrepareContinuationFixture(); + state.responses.set(`${api}/actions/runs/88`, [ + state.native, + { ...state.native, run_attempt: 2 }, + ]); + state.responses.set(`${api}/actions/runs/88/attempts/1/jobs`, [ + [pendingJob(702, 'Required', 1)], + ]); + assert.deepEqual(await reconcileNativePrepare(event(which), io, readOptions), []); + assert.equal(state.sleeps.length, 1); + assert.deepEqual(state.posts, []); + } +}); + +test('metadata convergence never retries an ambiguous POST and preserves final source guards', async () => { + for (const mode of ['post', 'original', 'main']) { + const { state, io, event, readOptions } = nativePrepareContinuationFixture(); + state.responses.set(`${api}/actions/runs/88/attempts/1/jobs`, [ + [pendingJob(702, 'Required', 1)], + ]); + if (mode === 'post') state.ambiguous = true; + if (mode === 'original') + state.responses.set(`${api}/actions/runs/41`, [ + state.original, + state.original, + { ...state.original, run_attempt: 2 }, + ]); + if (mode === 'main') state.currentMain = 'c'.repeat(40); + if (mode === 'original') + assert.deepEqual(await reconcileNativePrepare(event(), io, readOptions), []); + else + await assert.rejects( + reconcileNativePrepare(event(), io, readOptions), + mode === 'post' ? /outcome is unknown/u : /no longer current main/u, + ); + assert.equal(state.sleeps.length, 1); + assert.deepEqual(state.posts, mode === 'post' ? [41] : []); + assert.deepEqual(state.downloads, [501]); + } +}); diff --git a/tools/release/native-prepare-release-candidate.test.mts b/tools/release/native-prepare-release-candidate.test.mts new file mode 100644 index 000000000..d04b6ed52 --- /dev/null +++ b/tools/release/native-prepare-release-candidate.test.mts @@ -0,0 +1,1617 @@ +import { expect, test } from 'bun:test'; +import { spawnSync } from 'node:child_process'; +import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { ManifestPlugin } from 'release-please/build/src/plugin.js'; +import { mergeUpdates } from 'release-please/build/src/updaters/composite.js'; +import { Version } from 'release-please/build/src/version.js'; +import { projectCargoWorkspace, renderToml } from '../../build_defs/languages/cargo-metadata.mts'; +import { sourceManifest } from '../../build_defs/languages/source-package.mts'; +import { readCommitHistory, readCommitPaths } from './commit-paths.mts'; +import { applyCandidate } from './prepare-release-candidate.mts'; +import { loadProducts, productCompatibilityVersion, ROOT } from './release-graph.mts'; +import { syncLockfile } from './sync-release-pr.mts'; +import { + fixtureCompletionChecker, + generateHistoryCandidate, + generateProductCandidateForGraph, + historyProducts, + historyShared, + historyVersionUpdates, + nativeHistoryOptions, +} from './testdata/prepare-release-candidate-fixtures.mts'; + +const graph = { products: loadProducts('native-prepare-release-candidate.test') }; +const native = 'src/native/runtime'; +const wasix = 'src/wasix/runtime'; +const first = 'a'.repeat(40); +const second = 'b'.repeat(40); +const head = 'c'.repeat(40); +function generateProductCandidate(...args) { + return generateProductCandidateForGraph(graph, ...args); +} +function nativeProductOptions(necessary) { + // The controller's already-verified decision is the injected fixture precondition. + return { + nativeNecessaryProducts: necessary, + buildBound: new Map(Object.keys(graph.products).map((id) => [id, new Set()])), + nativeObservation: { + coverage: { completeProductInventory: true }, + products: Object.entries(graph.products).map(([id, metadata]) => ({ + product: { id }, + construction: [ + { + leafInputPaths: [ + `${metadata.path}/src/implementation`, + `${metadata.path}/source.toml`, + `${metadata.path}/ios/OliphauntAdapter.swift`, + `${metadata.path}/crates/oliphaunt-build/src/lib.rs`, + ], + analysisInputPaths: [], + }, + ], + })), + }, + observeNativePlan: async () => {}, + }; +} +test('native necessary scope uses actual captured leaves, including zero and patch intent without ownership expansion', async () => { + for (const selected of [[], ['alpha'], ['alpha', 'beta', 'gamma']]) { + const plans = []; + const candidates = await generateHistoryCandidate( + [ + { + sha: head, + message: 'feat: old shared ownership and unselected source intent', + files: [historyShared, 'actual/shipping/beta.c'], + }, + { sha: first, message: 'fix: already delivered', files: [historyShared] }, + ], + { + controllerOptions: nativeHistoryOptions(selected, { + observeNativePlan: async (plan) => { + plans.push(plan); + }, + }), + }, + ); + expect(historyVersionUpdates(candidates).map(([file]) => file)).toEqual( + selected.map((id) => `products/${id}/VERSION`), + ); + expect(plans).toHaveLength(1); + expect(plans[0].selectedProducts).toEqual(selected); + if (selected.includes('alpha')) + expect( + historyVersionUpdates(candidates).find(([file]) => file === 'products/alpha/VERSION')![1], + ).toBe('0.2.1'); + } +}); + +test('native first delivery uses the configured Release Please initial version', async () => { + const candidates = await generateHistoryCandidate( + [ + { sha: head, message: 'feat: initial alpha interface', files: ['actual/shipping/alpha.c'] }, + { + sha: second, + message: 'feat!: earlier unrelated acquisition change', + files: ['acquisition/old-tool.toml'], + }, + { sha: first, message: 'fix: published other products', files: [historyShared] }, + ], + { unreleased: ['alpha'], controllerOptions: nativeHistoryOptions(['alpha']) }, + ); + expect(historyVersionUpdates(candidates)).toEqual([['products/alpha/VERSION', '0.1.0']]); +}); + +test('native loaded recipe breaking intent applies only to a necessary configured consumer', async () => { + const options = nativeHistoryOptions(['alpha']); + options.nativeObservation.products[0].construction[0].analysisInputPaths = [ + 'build_defs/alpha/producer.bzl', + ]; + options.nativeObservation.products[1].construction[0].analysisInputPaths = [ + 'build_defs/beta/producer.bzl', + ]; + const candidates = await generateHistoryCandidate( + [ + { + sha: head, + message: 'feat!: change native producer ABI', + files: ['build_defs/alpha/producer.bzl'], + }, + { + sha: second, + message: 'feat!: unrelated producer change', + files: ['build_defs/beta/producer.bzl'], + }, + { sha: first, message: 'fix: baseline', files: [historyShared] }, + ], + { controllerOptions: options }, + ); + expect(historyVersionUpdates(candidates)).toEqual([['products/alpha/VERSION', '0.3.0']]); + delete options.nativeObservation.products[0].construction[0].analysisInputPaths; + await expect(generateHistoryCandidate([], { controllerOptions: options })).rejects.toThrow( + 'unknown loaded recipe version intent', + ); +}); + +test('native breaking intent follows removed Files to their authenticated historical owner', async () => { + const options = nativeHistoryOptions(['alpha', 'beta']); + options.nativeVersionIntentBaselines = { + alpha: { + product: { id: 'alpha' }, + construction: [ + { leafInputPaths: ['actual/shipping/removed-alpha.c'], analysisInputPaths: [] }, + ], + }, + }; + const candidates = await generateHistoryCandidate( + [ + { + sha: head, + message: 'feat!: remove alpha entry and update beta', + files: ['actual/shipping/removed-alpha.c', 'actual/shipping/beta.c'], + }, + { sha: first, message: 'fix: baseline', files: [historyShared] }, + ], + { controllerOptions: options }, + ); + expect(historyVersionUpdates(candidates)).toEqual([ + ['products/alpha/VERSION', '0.3.0'], + ['products/beta/VERSION', '0.3.0'], + ]); + options.nativeNecessaryProducts = ['beta']; + expect( + historyVersionUpdates( + await generateHistoryCandidate( + [ + { + sha: head, + message: 'feat!: remove alpha entry and update beta', + files: ['actual/shipping/removed-alpha.c', 'actual/shipping/beta.c'], + }, + { sha: first, message: 'fix: baseline', files: [historyShared] }, + ], + { controllerOptions: options }, + ), + ), + ).toEqual([['products/beta/VERSION', '0.3.0']]); +}); + +test('partly mapped breaking history cannot silently patch a necessary legacy product without its old footprint', async () => { + const commits = [ + { + sha: head, + message: 'feat!: remove an old alpha entry and update beta', + files: ['actual/shipping/removed-alpha.c', 'actual/shipping/beta.c'], + }, + { sha: first, message: 'fix: baseline', files: [historyShared] }, + ]; + await expect( + generateHistoryCandidate(commits, { + controllerOptions: nativeHistoryOptions(['alpha', 'beta']), + }), + ).rejects.toThrow('unknown breaking acquisition intent for alpha'); + commits[0].message = 'feat(alpha)!: explicitly remove the alpha entry'; + expect( + historyVersionUpdates( + await generateHistoryCandidate(commits, { + controllerOptions: nativeHistoryOptions(['alpha', 'beta']), + }), + ), + ).toEqual([ + ['products/alpha/VERSION', '0.3.0'], + ['products/beta/VERSION', '0.3.0'], + ]); +}); + +test('native unmapped breaking acquisition stays unknown until an explicit component intent resolves it', async () => { + const commits = [ + { + sha: head, + message: 'feat!: replace acquired compiler ABI', + files: ['acquisition/compiler-pin.toml'], + }, + { sha: first, message: 'fix: published baseline', files: [historyShared] }, + ]; + await expect( + generateHistoryCandidate(commits, { controllerOptions: nativeHistoryOptions(['alpha']) }), + ).rejects.toThrow('unknown breaking acquisition intent'); + commits[0].message = 'feat(alpha)!: replace acquired compiler ABI'; + const candidate = await generateHistoryCandidate(commits, { + controllerOptions: nativeHistoryOptions(['alpha']), + }); + expect(historyVersionUpdates(candidate)).toEqual([['products/alpha/VERSION', '0.3.0']]); + commits[0].message = 'feat(beta)!: replace beta acquired compiler ABI'; + expect( + historyVersionUpdates( + await generateHistoryCandidate(commits, { + controllerOptions: nativeHistoryOptions(['alpha']), + }), + ), + ).toEqual([['products/alpha/VERSION', '0.2.1']]); + // The same unmapped breaking commit was already delivered by alpha. It + // cannot block alpha merely because another owner has an older baseline. + commits[0].message = 'feat!: replace acquired compiler ABI'; + expect( + historyVersionUpdates( + await generateHistoryCandidate(commits, { + baselines: { alpha: head, beta: first, gamma: first }, + controllerOptions: nativeHistoryOptions(['alpha']), + }), + ), + ).toEqual([['products/alpha/VERSION', '0.2.1']]); +}); + +test('native workspace cannot create unselected dependents or retarget a held independently necessary package', async () => { + const commits = [ + { + sha: head, + message: 'fix: change physical deliveries', + files: ['actual/shipping/alpha.c', 'actual/shipping/beta.c'], + }, + { sha: first, message: 'fix: baseline', files: [historyShared] }, + ]; + for (const current of [false, true]) { + const selected = ['alpha', 'beta']; + const candidates = await generateHistoryCandidate(commits, { + nodeWorkspace: true, + controllerOptions: nativeHistoryOptions(selected, { current }), + }); + expect(candidates[0].body.releaseData.map(({ component }) => component).sort()).toEqual( + selected, + ); + const packageUpdate = candidates[0].updates.filter( + ({ path }) => path === 'products/alpha/package.json', + ); + let text = JSON.stringify({ name: 'alpha', version: '0.2.0', dependencies: { beta: '0.2.0' } }); + for (const update of packageUpdate) text = update.updater.updateContent(text); + expect(JSON.parse(text).dependencies.beta).toBe(current ? '0.2.1' : '0.2.0'); + } + const candidates = await generateHistoryCandidate(commits, { + nodeWorkspace: true, + controllerOptions: nativeHistoryOptions(['beta']), + }); + expect(candidates[0].body.releaseData.map(({ component }) => component)).toEqual(['beta']); +}); + +test('native missing coverage and rejected adoption decision stop before an applicable candidate exists', async () => { + const commits = [ + { sha: head, message: 'fix: delivery', files: ['actual/shipping/alpha.c'] }, + { sha: first, message: 'fix: baseline', files: [historyShared] }, + ]; + for (const change of [ + (options) => { + delete options.buildBound; + }, + (options) => { + options.nativeObservation.products[0].construction[0].leafInputPaths = undefined; + }, + (options) => { + options.nativeObservation.products.pop(); + }, + (options) => { + options.nativeNecessaryProducts = ['foreign']; + }, + ]) { + const options = nativeHistoryOptions(['alpha']); + change(options); + await expect(generateHistoryCandidate(commits, { controllerOptions: options })).rejects.toThrow( + 'native Release Please', + ); + } + await expect( + generateHistoryCandidate(commits, { + controllerOptions: nativeHistoryOptions(['alpha'], { + observeNativePlan: async () => { + throw new Error('adoption physical qualification is unknown'); + }, + }), + }), + ).rejects.toThrow('qualification is unknown'); +}); + +test('native explicit default-install fixed point is approved before RP and retains one exact candidate scope', async () => { + const buildBound = new Map(Object.keys(graph.products).map((id) => [id, new Set()])); + buildBound.get('oliphaunt-wasix-napi')!.add('liboliphaunt-wasix'); + for (const [id, metadata] of Object.entries(graph.products)) + if (metadata.extension?.class === 'external') + buildBound.set(id, new Set(['liboliphaunt-native', 'liboliphaunt-wasix'])); + const needed = ['liboliphaunt-wasix', 'oliphaunt-extension-vector']; + let approved; + const { candidate } = await generateProductCandidate( + [ + { + sha: head, + message: 'fix: qualified changed host and member', + files: [`${wasix}/toolchain.toml`, 'src/extensions/external/vector/source.toml'], + }, + ], + undefined, + undefined, + { + buildBound, + nativeNecessaryProducts: needed, + nativeObservation: { + coverage: { completeProductInventory: true }, + products: Object.entries(graph.products).map(([id, metadata]) => ({ + product: { id }, + construction: [ + { + leafInputPaths: [ + `${metadata.path}/VERSION`, + `${metadata.path}/source.toml`, + `${metadata.path}/toolchain.toml`, + ], + analysisInputPaths: [], + }, + ], + })), + }, + observeNativePlan: async (plan) => { + approved = plan; + }, + }, + ); + const actual = candidate.body.releaseData.map(({ component }) => component).sort(); + expect(actual).toEqual(approved.selectedProducts); + expect(actual).toContain('oliphaunt-wasix-napi'); + expect(actual).toContain('oliphaunt-wasix-ts'); + expect(actual).not.toContain('liboliphaunt-native'); + expect(approved.requirements.length).toBeGreaterThan(0); + expect([...buildBound.get('oliphaunt-wasix-napi')!]).toEqual(['liboliphaunt-wasix']); +}); + +test('native ABI extension adoption changes the source SDK requirement through RP while retaining dynamic helpers', async () => { + const product = 'oliphaunt-extension-vector'; + const buildBound = new Map(Object.keys(graph.products).map((id) => [id, new Set()])); + const sdkFile = 'src/native/sdks/ts/package.json'; + const before = readFileSync(path.join(ROOT, sdkFile), 'utf8'); + let approved; + const { candidate } = await generateProductCandidate( + [ + { + sha: head, + message: 'fix: update extension payload', + files: ['src/extensions/external/vector/source.toml'], + }, + ], + undefined, + undefined, + { + buildBound, + nativeNecessaryProducts: [product], + nativeObservation: { + coverage: { completeProductInventory: true }, + products: Object.entries(graph.products).map(([id, metadata]) => ({ + product: { id }, + construction: [ + { leafInputPaths: [`${metadata.path}/source.toml`], analysisInputPaths: [] }, + ], + })), + }, + observeNativePlan: async (plan) => { + approved = plan; + }, + }, + ); + const selected = candidate.body.releaseData.map(({ component }) => component).sort(); + expect(selected).toEqual(approved.selectedProducts); + expect(selected).toContain(product); + expect(selected).toContain('oliphaunt-js'); + for (const held of [ + 'liboliphaunt-native', + 'liboliphaunt-wasix', + 'oliphaunt-node-direct', + 'oliphaunt-broker', + 'liboliphaunt-native-bindings', + ]) + expect(selected).not.toContain(held); + const sdkUpdate = mergeUpdates(candidate.updates).find(({ path }) => path === sdkFile); + expect(sdkUpdate).toBeDefined(); + const source = JSON.parse(before); + const adopted = JSON.parse(sdkUpdate.updater.updateContent(before)); + expect(adopted.oliphaunt.liboliphauntVersion).toBe(graph.products['liboliphaunt-native'].version); + expect(adopted.version).not.toBe(source.version); + expect(adopted.oliphaunt.nodeDirectAddonVersion).toBe(source.oliphaunt.nodeDirectAddonVersion); + expect(adopted.oliphaunt.brokerVersion).toBe(source.oliphaunt.brokerVersion); + expect(readFileSync(path.join(ROOT, sdkFile), 'utf8')).toBe(before); +}); + +test('actual Rust, npm, Swift and Gradle strategy updates apply to one local candidate', async () => { + const root = path.resolve(import.meta.dir, '../..'); + const selected = [ + 'src/native/sdks/rust', + 'src/native/sdks/ts', + 'src/native/sdks/swift', + 'src/native/sdks/kotlin', + ]; + const { candidate, versions } = await generateProductCandidate( + [ + { + sha: head, + message: 'fix: correct the selected SDK behavior', + files: selected.map((owner) => `${owner}/src/implementation`), + }, + ], + undefined, + undefined, + nativeProductOptions(['oliphaunt-rust', 'oliphaunt-js', 'oliphaunt-swift', 'oliphaunt-kotlin']), + ); + const scratch = mkdtempSync(path.join(os.tmpdir(), 'release-please-ecosystems-')); + try { + for (const update of candidate.updates) { + const input = path.join(root, update.path); + if (existsSync(input)) { + const destination = path.join(scratch, update.path); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, readFileSync(input)); + } + } + applyCandidate(scratch, candidate); + const after = JSON.parse( + readFileSync(path.join(scratch, '.release-please-manifest.json'), 'utf8'), + ); + const read = (file) => readFileSync(path.join(scratch, file), 'utf8'); + expect(Bun.TOML.parse(read('src/native/sdks/rust/Cargo.toml')).package.version).toBe( + after['src/native/sdks/rust'], + ); + expect( + Bun.TOML.parse(read('src/native/sdks/rust/crates/oliphaunt-build/Cargo.toml')).package + .version, + ).toBe(after['src/native/sdks/rust']); + expect(JSON.parse(read('src/native/sdks/ts/package.json')).version).toBe( + after['src/native/sdks/ts'], + ); + expect(read('src/native/sdks/swift/VERSION').trim()).toBe(after['src/native/sdks/swift']); + expect(read('src/native/sdks/kotlin/VERSION').trim()).toBe(after['src/native/sdks/kotlin']); + expect(read('src/native/sdks/kotlin/gradle.properties')).toContain( + `VERSION_NAME=${after['src/native/sdks/kotlin']}`, + ); + expect(existsSync(path.join(scratch, 'src/native/sdks/rust/Cargo.lock'))).toBe(false); + for (const owner of selected) expect(after[owner]).not.toBe(versions[owner]); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +}); + +test('independent SDK pins do not impose a single global runtime version', async () => { + const readCompatibility = (product, source) => + product === 'oliphaunt-react-native' ? '0.2.0' : graph.products[source].version; + const { candidate } = await generateProductCandidate( + [ + { + sha: head, + message: 'fix: repair mobile adapters', + files: [ + 'src/native/sdks/kotlin/src/implementation', + 'src/native/sdks/react-native/ios/OliphauntAdapter.swift', + ], + }, + ], + readCompatibility, + undefined, + nativeProductOptions(['oliphaunt-kotlin', 'oliphaunt-react-native']), + ); + expect(candidate).toBeDefined(); + expect( + candidate.updates.some(({ path: file }) => file.startsWith('src/extensions/external/')), + ).toBe(false); +}); + +test('removing published exact host support supplies breaking intent before native version selection', async () => { + const vector = graph.products['oliphaunt-extension-vector']; + const reads = []; + const readCompatibility = (product, source, _prefix, { ref = null } = {}) => { + reads.push({ product, source, ref }); + return product === 'oliphaunt-extension-vector' + ? ref + ? '0.1.0' + : graph.products[source].version + : productCompatibilityVersion(product, source); + }; + const { candidate, versions } = await generateProductCandidate( + [ + { + sha: head, + message: 'fix: repair vector packaging', + files: [`${vector.path}/source.toml`], + }, + ], + readCompatibility, + undefined, + nativeProductOptions(['oliphaunt-extension-vector']), + ); + const update = mergeUpdates(candidate.updates).find( + ({ path: file }) => file === '.release-please-manifest.json', + ); + const after = JSON.parse(update.updater.updateContent(JSON.stringify(versions))); + const [major, minor] = vector.version.split('.').map(Number); + expect(after[vector.path]).toBe(`${major}.${minor + 1}.0`); + const changelog = candidate.updates + .find(({ path: file }) => file === vector.changelog_path) + .updater.updateContent('# Changelog\n'); + expect(changelog).toContain('replace exact host support'); + expect(changelog).toContain('repair vector packaging'); + expect( + reads.some(({ product, ref }) => product === 'oliphaunt-extension-vector' && ref !== null), + ).toBe(true); +}); + +test('unchanged public support permits an ordinary patch release', async () => { + const vector = graph.products['oliphaunt-extension-vector']; + const { candidate, versions } = await generateProductCandidate( + [ + { + sha: head, + message: 'fix: repair vector SQL', + files: [`${vector.path}/source.toml`], + }, + ], + undefined, + undefined, + nativeProductOptions(['oliphaunt-extension-vector']), + ); + const update = mergeUpdates(candidate.updates).find( + ({ path: file }) => file === '.release-please-manifest.json', + ); + const after = JSON.parse(update.updater.updateContent(JSON.stringify(versions))); + const [major, minor, patch] = vector.version.split('.').map(Number); + expect(after[vector.path]).toBe(`${major}.${minor}.${patch + 1}`); +}); + +test('unrelated Rust candidates do not inject unselected extension support intent', async () => { + const vector = graph.products['oliphaunt-extension-vector']; + let bump; + await generateProductCandidate( + [ + { + sha: head, + message: 'fix: update build helper API', + files: ['src/native/sdks/rust/crates/oliphaunt-build/src/lib.rs'], + }, + ], + (_product, source, _prefix, { ref = null } = {}) => + ref ? '0.1.0' : graph.products[source].version, + (manifest, github) => { + manifest.plugins.push( + new (class extends ManifestPlugin { + async preconfigure(strategies, _commits, releases) { + bump = await strategies[vector.path].versioningStrategy.bump( + releases[vector.path].tag.version, + [], + ); + return strategies; + } + })(github, 'main', manifest.repositoryConfig), + ); + }, + nativeProductOptions(['oliphaunt-rust']), + ); + const [major, minor, patch] = vector.version.split('.').map(Number); + expect(bump.toString()).toBe(`${major}.${minor}.${patch + 1}`); +}); + +test('docs changes do not read compatibility or create candidates', async () => { + const { candidate } = await generateProductCandidate( + [ + { + sha: head, + message: 'docs: clarify preparation', + files: ['src/docs/maintainers/release.md'], + }, + ], + () => { + throw new Error('unexpected compatibility read'); + }, + undefined, + nativeProductOptions([]), + ); + expect(candidate).toBeUndefined(); +}); + +function nativeHistorySourceOptions(necessary) { + const options = nativeHistoryOptions(necessary); + for (const row of options.nativeObservation.products) + row.construction[0].leafInputPaths.push( + historyShared, + `products/${row.product.id}/src/lib.rs`, + `products/${row.product.id}/src/old.rs`, + ); + return options; +} + +test('out-of-directory completed releases strictly bound each owner before strategy selection', async () => { + const old = 'd'.repeat(40); + const candidates = await generateHistoryCandidate( + [ + { sha: head, message: 'fix: new beta delivery', files: ['products/beta/src/lib.rs'] }, + { + sha: second, + message: 'fix: publication recovery', + files: ['tools/release/controller.mts'], + }, + { + sha: old, + message: 'fix: old shared delivery', + files: [historyShared, 'products/beta/src/old.rs', 'products/gamma/src/old.rs'], + }, + { sha: first, message: 'fix: original recovery', files: ['tools/release/controller.mts'] }, + ], + { + baselines: { alpha: first, beta: second, gamma: second }, + controllerOptions: nativeHistorySourceOptions(['alpha', 'beta']), + inspect(selected) { + expect(selected['products/alpha'].map(({ sha }) => sha)).toEqual([old]); + expect(selected['products/beta'].map(({ sha }) => sha)).toEqual([head]); + expect(selected['products/gamma']).toEqual([]); + }, + }, + ); + expect(historyVersionUpdates(candidates).sort()).toEqual([ + ['products/alpha/VERSION', '0.2.1'], + ['products/beta/VERSION', '0.2.1'], + ]); + const notes = candidates[0].body.toString(); + expect(notes.match(/old shared delivery/gu)).toHaveLength(1); + expect(notes.match(/new beta delivery/gu)).toHaveLength(1); + expect(notes).not.toContain('publication recovery'); + expect(notes).not.toContain('original recovery'); +}); + +test('public release boundaries require a completed canonical version transition', async () => { + const commits = [ + { sha: head, message: 'fix: new alpha behavior', files: ['products/alpha/src/lib.rs'] }, + { sha: first, message: 'chore(release): public baseline', files: [] }, + ]; + for (const completion of [{ pending: ['alpha'] }, { missingLabels: ['alpha'] }]) + await expect( + generateHistoryCandidate(commits, { + completion, + controllerOptions: nativeHistorySourceOptions(['alpha']), + }), + ).rejects.toThrow('publication is not complete'); + for (const completion of [{ omitCompletions: ['alpha'] }, { unchangedAtMerge: ['alpha'] }]) + await expect( + generateHistoryCandidate(commits, { + completion, + controllerOptions: nativeHistorySourceOptions(['alpha']), + }), + ).rejects.toThrow('no unique canonical release completion'); +}); + +test('completed publication resolves the exact published tree and original release independently', async () => { + const config = { 'products/alpha': { component: 'alpha' } }; + const versions = { 'products/alpha': Version.parse('0.2.0') }; + const identity = { + product: 'alpha', + version: '0.2.0', + publicationSha: second, + tagName: 'alpha-v0.2.0', + }; + const check = fixtureCompletionChecker( + config, + versions, + { 'products/alpha': second }, + { + releaseMergeShas: { alpha: first }, + }, + ); + expect(await check(identity)).toEqual({ + ...identity, + publicationTree: 'd'.repeat(40), + releaseSha: first, + }); + for (const commit of [ + { sha: head, tree: { sha: 'd'.repeat(40) } }, + { sha: second, tree: {} }, + ]) { + const reject = fixtureCompletionChecker( + config, + versions, + { 'products/alpha': second }, + { + releaseMergeShas: { alpha: first }, + sourceCommits: { [second]: commit }, + }, + ); + await expect(reject(identity)).rejects.toThrow('publication source has no exact Git tree'); + } +}); + +test('completed publication recovery retains the original canonical release and exact source versions', async () => { + const recovery = { + controllerOptions: nativeHistorySourceOptions(['alpha']), + baselines: Object.fromEntries(historyProducts.map((product) => [product, second])), + completion: { + releaseMergeShas: Object.fromEntries(historyProducts.map((product) => [product, first])), + }, + }; + const commits = [ + { sha: head, message: 'fix: new alpha behavior', files: ['products/alpha/src/lib.rs'] }, + { sha: second, message: 'fix: recover publication', files: ['tools/release/controller.mts'] }, + ]; + expect(historyVersionUpdates(await generateHistoryCandidate(commits, recovery))).toEqual([ + ['products/alpha/VERSION', '0.2.1'], + ]); + expect( + historyVersionUpdates( + await generateHistoryCandidate(commits, { + ...recovery, + completion: { + ...recovery.completion, + comparisons: { + [`${first}...${second}`]: { + status: 'ahead', + behind_by: 0, + base_commit: { sha: first }, + merge_base_commit: { sha: first }, + total_commits: 2, + commits: [{ sha: second }, { sha: 'd'.repeat(40) }], + }, + }, + }, + }), + ), + ).toEqual([['products/alpha/VERSION', '0.2.1']]); + for (const interval of [ + [{ sha: second }, { sha: second }], + [{ sha: second }, { sha: 'invalid' }], + [{ sha: 'd'.repeat(40) }, { sha: 'e'.repeat(40) }], + ]) + await expect( + generateHistoryCandidate(commits, { + ...recovery, + completion: { + ...recovery.completion, + comparisons: { + [`${first}...${second}`]: { + status: 'ahead', + behind_by: 0, + base_commit: { sha: first }, + merge_base_commit: { sha: first }, + total_commits: 2, + commits: interval, + }, + }, + }, + }), + ).rejects.toThrow('publication recovery history is incomplete'); + await expect( + generateHistoryCandidate(commits, { + ...recovery, + completion: { ...recovery.completion, releaseTargets: { 'alpha-v0.2.0': first } }, + }), + ).rejects.toThrow('public release does not bind its exact publication source'); + await expect( + generateHistoryCandidate(commits, { + ...recovery, + completion: { + ...recovery.completion, + sourceVersions: { + [second]: { + 'products/alpha': '0.3.0', + 'products/beta': '0.2.0', + 'products/gamma': '0.2.0', + }, + }, + }, + }), + ).rejects.toThrow('publication source has different product versions'); + await expect( + generateHistoryCandidate(commits, { + ...recovery, + completion: { + ...recovery.completion, + sourceVersions: { + [second]: { + 'products/alpha': '0.2.0', + 'products/beta': '0.3.0', + 'products/gamma': '0.2.0', + }, + }, + }, + }), + ).rejects.toThrow('publication source has different product versions'); + await expect( + generateHistoryCandidate(commits, { + ...recovery, + completion: { + ...recovery.completion, + comparisons: { + [`${first}...${second}`]: { + status: 'diverged', + behind_by: 1, + base_commit: { sha: first }, + merge_base_commit: { sha: first }, + }, + }, + }, + }), + ).rejects.toThrow('publication source is not a release descendant'); + const intervening = 'd'.repeat(40); + await expect( + generateHistoryCandidate(commits, { + ...recovery, + completion: { + ...recovery.completion, + extraPullRequests: [ + { + number: 999, + title: 'chore(release): prepare main releases', + state: 'closed', + merged_at: '2026-09-12T00:00:00Z', + merge_commit_sha: intervening, + base: { ref: 'main', repo: { full_name: 'f0rr0/oliphaunt' } }, + head: { ref: 'release-please--branches--main', repo: { full_name: 'f0rr0/oliphaunt' } }, + labels: [{ name: 'autorelease: tagged' }], + body: '', + }, + ], + comparisons: { + [`${first}...${second}`]: { + status: 'ahead', + behind_by: 0, + base_commit: { sha: first }, + merge_base_commit: { sha: first }, + total_commits: 2, + commits: [{ sha: intervening }, { sha: second }], + }, + }, + }, + }), + ).rejects.toThrow('publication source follows another release candidate'); +}); + +test('long publication recovery is completely paged and shared across product checks', async () => { + const interval = Array.from({ length: 150 }, (_, index) => ({ + sha: (3_000_000 + index).toString(16).padStart(40, '0'), + })); + interval[149] = { sha: second }; + const calls = {}; + const options = { + controllerOptions: nativeHistorySourceOptions(historyProducts), + baselines: Object.fromEntries(historyProducts.map((product) => [product, second])), + completion: { + releaseMergeShas: Object.fromEntries(historyProducts.map((product) => [product, first])), + comparisons: { + [`${first}...${second}`]: { + status: 'ahead', + behind_by: 0, + base_commit: { sha: first }, + merge_base_commit: { sha: first }, + total_commits: 150, + commits: interval.slice(0, 100), + }, + }, + pagedComparisons: { [`${first}...${second}`]: interval }, + calls, + }, + }; + const commits = [ + { sha: head, message: 'fix: new shared behavior', files: [historyShared] }, + { sha: second, message: 'fix: recover publication', files: [] }, + ]; + expect(historyVersionUpdates(await generateHistoryCandidate(commits, options))).toHaveLength(3); + expect(calls.pages).toBe(1); + await expect( + generateHistoryCandidate(commits, { + ...options, + completion: { ...options.completion, pagedComparisons: {} }, + }), + ).rejects.toThrow('publication recovery history is incomplete'); +}); + +test('actual Git ancestry bounds Release Please despite clock skew and reordered API history', async () => { + const fixture = mkdtempSync(path.join(os.tmpdir(), 'release-history-ancestry-')); + try { + for (const delivered of [false, true]) { + const repo = path.join(fixture, String(delivered)); + mkdirSync(repo); + let date = '2020-01-01T12:00:00Z'; + const run = (command, args) => { + const result = spawnSync(command, args, { + cwd: repo, + encoding: 'utf8', + env: { + ...process.env, + GIT_AUTHOR_NAME: 'Fixture', + GIT_AUTHOR_EMAIL: 'fixture@example.com', + GIT_COMMITTER_NAME: 'Fixture', + GIT_COMMITTER_EMAIL: 'fixture@example.com', + GIT_AUTHOR_DATE: date, + GIT_COMMITTER_DATE: date, + }, + }); + if (result.status !== 0) throw new Error(`${command}: ${result.stderr}`); + return result.stdout.trim(); + }; + const commit = (message, nextDate) => { + date = nextDate; + run('git', ['add', '.']); + run('git', ['commit', '--allow-empty', '-qm', message]); + return run('git', ['rev-parse', 'HEAD']); + }; + run('git', ['init', '-q', '-b', 'main']); + mkdirSync(path.join(repo, 'products/alpha/src'), { recursive: true }); + writeFileSync(path.join(repo, 'products/alpha/src/lib.rs'), 'original\n'); + const root = commit('chore: original source', '2020-01-01T12:00:00Z'); + run('git', ['checkout', '-qb', 'feature']); + writeFileSync(path.join(repo, 'products/alpha/src/lib.rs'), 'new API\n'); + const branch = commit('feat!: new alpha API', '2020-01-04T12:00:00Z'); + run('git', ['checkout', '-q', 'main']); + let baseline; + if (!delivered) + baseline = commit('chore(release): completed versions', '2020-01-05T12:00:00Z'); + date = '2020-01-06T12:00:00Z'; + run('git', ['merge', '--no-ff', '-qm', 'chore: merge feature', 'feature']); + const merge = run('git', ['rev-parse', 'HEAD']); + if (delivered) + baseline = commit('chore(release): completed versions', '2020-01-02T12:00:00Z'); + const source = delivered ? commit('docs: controller notes', '2020-01-07T12:00:00Z') : merge; + const snapshot = path.join(repo, 'snapshot'); + run('bash', [ + path.join(ROOT, 'tools/release/snapshot-commit-paths.sh'), + repo, + source, + snapshot, + ]); + const commitHistory = readCommitHistory(snapshot); + const apiOrder = delivered + ? [branch, source, baseline, merge, root] + : [baseline, root, branch, source]; + const commits = apiOrder.map((sha) => ({ + sha, + message: run('git', ['show', '-s', '--format=%B', sha]), + files: [], + })); + const options = { + controllerOptions: nativeHistorySourceOptions(delivered ? [] : ['alpha']), + baselines: Object.fromEntries(historyProducts.map((product) => [product, baseline])), + commitHistory, + readCommitFiles: (sha) => readCommitPaths(sha, snapshot), + sourceSha: source, + readSource: async () => ({ object: { sha: source } }), + }; + const candidates = await generateHistoryCandidate(commits, { + ...options, + inspect(selected, calls) { + expect(calls.commits.maxResults).toBe(commitHistory.commits.size); + expect(selected['products/beta']).toEqual([]); + expect(selected['products/gamma']).toEqual([]); + expect(new Set(selected['products/alpha'].map(({ sha }) => sha))).toEqual( + new Set(delivered ? [] : [merge, branch]), + ); + }, + }); + expect(historyVersionUpdates(candidates)).toEqual( + delivered ? [] : [['products/alpha/VERSION', '0.3.0']], + ); + await expect( + generateHistoryCandidate(commits, { + ...options, + readSource: async () => ({ object: { sha: root } }), + }), + ).rejects.toThrow('main changed before'); + await expect( + generateHistoryCandidate(commits, { ...options, sourceSha: root }), + ).rejects.toThrow('captured Git history does not match'); + await expect( + generateHistoryCandidate( + [{ sha: 'f'.repeat(40), message: 'fix: foreign' }, ...commits], + options, + ), + ).rejects.toThrow('outside the captured source'); + await expect( + generateHistoryCandidate( + commits.filter(({ sha }) => sha !== source), + options, + ), + ).rejects.toThrow('API history did not cover captured source'); + await expect(generateHistoryCandidate([commits[0], ...commits], options)).rejects.toThrow( + 'duplicate history commit', + ); + if (!delivered) { + expect( + historyVersionUpdates( + await generateHistoryCandidate(commits, { + ...options, + unreleased: historyProducts, + bootstrapSha: baseline, + }), + ), + ).toEqual([['products/alpha/VERSION', '0.1.0']]); + } + } + } finally { + rmSync(fixture, { recursive: true, force: true }); + } +}); + +test('actual RP exact-module requirements preserve held resources and independently version a qualified current adoption', async () => { + const product = 'database-resources', + sourceProduct = 'liboliphaunt-wasix'; + const resource = graph.products[product], + core = graph.products[sourceProduct]; + for (const selected of [[sourceProduct], [product], [sourceProduct, product]]) { + const plans = []; + const options = nativeProductOptions(selected); + for (const producer of [sourceProduct, 'oliphaunt-wasix-rust']) + options.buildBound.get('oliphaunt-wasix-napi').add(producer); + options.nativeCurrentExactInputs = [{ product, sourceProduct }]; + options.observeNativePlan = async (plan) => { + plans.push(plan); + }; + const { candidate, versions } = await generateProductCandidate( + [], + () => '0.3.2', + () => { + // Mutation after the hook receives the derived list cannot change its plan. + options.nativeCurrentExactInputs[0].sourceProduct = 'liboliphaunt-native'; + }, + options, + ); + expect(plans).toHaveLength(1); + expect(plans[0].selectedProducts).toEqual( + [...selected, ...(selected.includes(sourceProduct) ? ['oliphaunt-wasix-napi'] : [])].sort(), + ); + const updates = mergeUpdates(candidate.updates); + const manifest = updates.find(({ path: file }) => file === '.release-please-manifest.json'); + const after = JSON.parse(manifest.updater.updateContent(JSON.stringify(versions))); + const expectedCore = selected.includes(sourceProduct) + ? core.version + .split('.') + .map((part, index) => (index === 2 ? Number(part) + 1 : Number(part))) + .join('.') + : core.version; + expect(after[core.path]).toBe(expectedCore); + const pin = updates.find( + ({ path: file }) => file === 'src/database-resources/seeds/wasix/Cargo.toml', + ); + const original = readFileSync( + path.join(ROOT, 'src/database-resources/seeds/wasix/Cargo.toml'), + 'utf8', + ); + const final = pin ? pin.updater.updateContent(original) : original; + expect(Bun.TOML.parse(final).package.metadata.oliphaunt['runtime-version']).toBe( + selected.includes(sourceProduct) && selected.includes(product) ? expectedCore : '0.3.2', + ); + expect(plans[0].requirements.filter((entry) => entry.product === product)).toEqual( + selected.length === 2 ? [{ product, sourceProduct, version: expectedCore }] : [], + ); + expect(options.buildBound.get(product).size).toBe(0); + if (selected.includes(product)) expect(after[resource.path]).not.toBe(resource.version); + else expect(after[resource.path]).toBe(resource.version); + } +}); + +{ + const runtime = 'liboliphaunt-wasix'; + const sdk = 'oliphaunt-wasix-rust'; + const addon = 'oliphaunt-wasix-napi'; + const server = 'oliphaunt-pgwire-server'; + const query = 'oliphaunt-query'; + const patch = (version) => { + const [major, minor, patch] = version.split('.').map(Number); + return `${major}.${minor}.${patch + 1}`; + }; + for (const scenario of [ + { name: 'runtime-only', necessary: [runtime], selected: [runtime, addon], compiled: true }, + { + name: 'SDK-only adopts shared pgwire requirement', + necessary: [sdk], + selected: [sdk, addon, server], + compiled: true, + }, + { name: 'addon-only', necessary: [addon], selected: [addon], compiled: true }, + { name: 'unrelated Cargo producer', necessary: [query], selected: [query], compiled: true }, + { + name: 'no current compiled edge', + necessary: [runtime], + selected: [runtime], + compiled: false, + }, + ]) + test(`actual RP current embedded Cargo owners: ${scenario.name}`, async () => { + const options = nativeProductOptions(scenario.necessary); + if (scenario.compiled) + for (const producer of [runtime, sdk]) options.buildBound.get(addon).add(producer); + let plan; + options.observeNativePlan = async (value) => { + plan = value; + }; + const { candidate, versions } = await generateProductCandidate( + [], + undefined, + undefined, + options, + ); + const updates = mergeUpdates(candidate.updates); + const read = (file) => { + const original = readFileSync(path.join(ROOT, file), 'utf8'); + return ( + updates.find((update) => update.path === file)?.updater.updateContent(original) ?? + original + ); + }; + const after = JSON.parse(read('.release-please-manifest.json')); + expect(plan.selectedProducts).toEqual([...scenario.selected].sort()); + expect(candidate.body.releaseData.map(({ component }) => component).sort()).toEqual( + [...scenario.selected].sort(), + ); + for (const product of [runtime, sdk, addon, server, query]) + expect(after[graph.products[product].path]).toBe( + scenario.selected.includes(product) + ? patch(graph.products[product].version) + : versions[graph.products[product].path], + ); + const runtimeVersion = after[graph.products[runtime].path]; + const sdkVersion = after[graph.products[sdk].path]; + const addonSelected = scenario.selected.includes(addon); + const product = JSON.parse(read('src/wasix/node-addon/package.json')); + expect(product.oliphaunt.runtimeVersion).toBe( + addonSelected ? runtimeVersion : graph.products[runtime].version, + ); + expect(product.oliphaunt.rustBindingVersion).toBe( + addonSelected ? sdkVersion : graph.products[sdk].version, + ); + for (const platform of [ + 'darwin-arm64', + 'linux-arm64-gnu', + 'linux-x64-gnu', + 'win32-x64-msvc', + ]) { + const manifest = JSON.parse(read(`src/wasix/node-addon/packages/${platform}/package.json`)); + expect(manifest.version).toBe(after[graph.products[addon].path]); + expect(manifest.oliphaunt.runtimeVersion).toBe(product.oliphaunt.runtimeVersion); + } + const addonCargo = Bun.TOML.parse(read('src/wasix/node-addon/Cargo.toml')); + expect(addonCargo.package.version).toBe(after[graph.products[addon].path]); + expect(addonCargo.dependencies['liboliphaunt-wasix-portable']).toEqual({ + version: `=${runtimeVersion}`, + path: '../runtime/crates/assets', + }); + const workspace = Bun.TOML.parse(read('Cargo.toml')); + expect(workspace.workspace.dependencies['oliphaunt-wasix']).toEqual({ + path: 'src/wasix/sdks/rust', + version: sdkVersion, + }); + if (scenario.necessary.includes(sdk)) { + expect( + plan.requirements + .filter((entry) => entry.path === 'Cargo.toml') + .map((entry) => entry.product) + .sort(), + ).toEqual([addon, server].sort()); + const packed = sourceManifest( + read('src/wasix/pgwire-server/Cargo.toml'), + read('Cargo.toml'), + { + product: server, + version: after[graph.products[server].path], + compatibility: {}, + dependencyOwners: {}, + }, + ); + expect(packed.dependencies['oliphaunt-wasix'].version).toBe(sdkVersion); + expect(packed.dependencies['oliphaunt-wasix'].path).toBeUndefined(); + } + // Private source embedding does not replace the SDK's public runtime floor. + expect( + Bun.TOML.parse(read('src/wasix/sdks/rust/Cargo.toml')).package.metadata.oliphaunt[ + 'runtime-version' + ], + ).toBe(graph.products[runtime].version); + expect( + plan.selectedProducts.some((id) => graph.products[id].extension?.class === 'external'), + ).toBe(false); + expect( + plan.requirements.filter((entry) => entry.product === addon && !entry.binding), + ).toEqual( + addonSelected && scenario.necessary.some((id) => id === runtime || id === sdk) + ? [ + { + product: addon, + sourceProduct: scenario.necessary[0], + version: scenario.necessary[0] === runtime ? runtimeVersion : sdkVersion, + }, + ] + : [], + ); + if (!scenario.compiled) + expect( + plan.requirements + .filter((entry) => entry.path === 'src/wasix/node-addon/Cargo.toml') + .map((entry) => entry.product), + ).toEqual([null]); + }); +} + +{ + const product = 'oliphaunt-extension-pg-textsearch', + sourceProduct = 'liboliphaunt-wasix', + otherProduct = 'oliphaunt-extension-vector'; + const extension = graph.products[product], + core = graph.products[sourceProduct]; + const patch = (version) => { + const [major, minor, patch] = version.split('.').map(Number); + return `${major}.${minor}.${patch + 1}`; + }; + const breaking = (version) => { + const [major, minor] = version.split('.').map(Number); + return major === 0 ? `0.${minor + 1}.0` : `${major + 1}.0.0`; + }; + for (const { name, necessary } of [ + { name: 'producer only retains held extension', necessary: [sourceProduct] }, + { name: 'consumer only retains held runtime', necessary: [product] }, + { name: 'selected pair adopts current host', necessary: [sourceProduct, product] }, + { + name: 'selected pair retargets an already-selected extension', + necessary: [sourceProduct, product, otherProduct], + }, + ]) + test(`actual RP public WASIX exact-host adoption: ${name}`, async () => { + const plans = []; + const options = nativeProductOptions(necessary); + // The addon embeds current runtime and SDK Files; the extension remains ABI-only. + for (const producer of [sourceProduct, 'oliphaunt-wasix-rust']) + options.buildBound.get('oliphaunt-wasix-napi').add(producer); + options.nativeCurrentExactInputs = [{ product, sourceProduct }]; + options.observeNativePlan = async (plan) => { + plans.push(plan); + }; + const { candidate, versions } = await generateProductCandidate( + [], + undefined, + undefined, + options, + ); + expect(plans).toHaveLength(1); + const updates = mergeUpdates(candidate.updates); + const manifest = updates.find(({ path: file }) => file === '.release-please-manifest.json'); + const after = JSON.parse(manifest.updater.updateContent(JSON.stringify(versions))); + const adopts = necessary.includes(product) && necessary.includes(sourceProduct); + const expectedCore = necessary.includes(sourceProduct) ? patch(core.version) : core.version; + expect(after[core.path]).toBe(expectedCore); + expect(after[extension.path]).toBe( + !necessary.includes(product) + ? extension.version + : adopts + ? breaking(extension.version) + : patch(extension.version), + ); + for (const participant of [product, sourceProduct]) + expect(plans[0].selectedProducts.includes(participant)).toBe( + necessary.includes(participant), + ); + expect( + plans[0].requirements.filter( + (entry) => entry.product === product && entry.sourceProduct === sourceProduct, + ), + ).toEqual(adopts ? [{ product, sourceProduct, version: expectedCore }] : []); + for (const owner of [product, ...(necessary.includes(otherProduct) ? [otherProduct] : [])]) { + const metadata = graph.products[owner]; + const file = metadata.path + '/release.toml'; + const original = readFileSync(path.join(ROOT, file), 'utf8'); + const update = updates.find(({ path }) => path === file); + const result = update ? update.updater.updateContent(original) : original; + expect(Bun.TOML.parse(result).extension.compatibility.wasix_runtime_version).toBe( + adopts + ? expectedCore + : Bun.TOML.parse(original).extension.compatibility.wasix_runtime_version, + ); + if (adopts) { + expect(after[metadata.path]).toBe(breaking(metadata.version)); + const changelog = updates + .find(({ path: file }) => file === metadata.changelog_path) + .updater.updateContent('# Changelog\n'); + expect(changelog).toContain('replace exact host support'); + expect(changelog).toContain(sourceProduct + '@' + core.version); + expect(changelog).toContain(sourceProduct + '@' + expectedCore); + } + } + expect(options.buildBound.get(product).size).toBe(0); + expect(options.buildBound.get(otherProduct).size).toBe(0); + }); +} + +test('actual RP local Cargo closure preserves held pins and projects released source minimums offline', async () => { + const core = 'liboliphaunt-native-bindings', + broker = 'oliphaunt-broker', + sdk = 'oliphaunt-rust'; + const cases = [ + { owner: core, message: undefined, necessary: [], selected: [] }, + { owner: core, message: 'fix: update Core', necessary: [core], selected: [core] }, + { owner: core, message: 'fix: update Core', necessary: [core, sdk], selected: [core, sdk] }, + { + owner: core, + message: 'fix: update Core', + necessary: [core, broker], + selected: [core, broker], + }, + { + owner: core, + message: 'fix: update Core', + necessary: [core, sdk], + selected: [core, sdk, 'oliphaunt-query'], + sharedConsumer: 'oliphaunt-query', + }, + { + owner: core, + message: 'feat!: change Core API', + necessary: [core, broker], + selected: [core, broker, sdk], + }, + { + owner: broker, + message: 'feat!: change Broker API', + necessary: [broker], + selected: [broker, sdk], + }, + ]; + for (const scenario of cases) { + const options = nativeProductOptions(scenario.necessary); + options.buildBound.get(broker).add(core); + // The compiled broker contains Core; the source fa\u00E7ade contains its own + // manifest. An adoption uses the existing private requirement bump policy. + options.nativeObservation.products + .find(({ product }) => product.id === broker) + .construction[0].leafInputPaths.push(graph.products[core].path + '/src/implementation'); + let plan; + options.observeNativePlan = async (value) => { + plan = value; + }; + const sharedFile = scenario.sharedConsumer + ? graph.products[scenario.sharedConsumer].path + '/Cargo.toml' + : undefined; + const original = (file) => { + const text = readFileSync(path.join(ROOT, file), 'utf8'); + if (file !== sharedFile) return text; + const manifest = Bun.TOML.parse(text); + manifest.dependencies ??= {}; + manifest.dependencies[core] = { workspace: true }; + return renderToml(manifest); + }; + const configure = (_manifest, github) => { + if (!sharedFile) return; + const get = github.getFileContentsOnBranch.bind(github); + github.getFileContentsOnBranch = async (file) => { + if (file !== sharedFile) return get(file); + const parsedContent = original(file); + return { parsedContent, content: Buffer.from(parsedContent).toString('base64') }; + }; + }; + const { candidate, versions } = await generateProductCandidate( + scenario.message + ? [ + { + sha: head, + message: scenario.message, + files: [graph.products[scenario.owner].path + '/src/implementation'], + }, + ] + : [], + undefined, + configure, + options, + ); + const updates = candidate ? mergeUpdates(candidate.updates) : []; + const read = (file) => { + const before = original(file); + return ( + updates.find((update) => update.path === file)?.updater.updateContent(before) ?? before + ); + }; + const after = JSON.parse(read('.release-please-manifest.json')); + const selected = candidate?.body.releaseData.map(({ component }) => component).sort() ?? []; + expect(selected).toEqual([...scenario.selected].sort()); + expect(plan.selectedProducts).toEqual(selected); + const workspace = Bun.TOML.parse(read('Cargo.toml')); + const coreManifest = Bun.TOML.parse(read(graph.products[core].path + '/Cargo.toml')); + const brokerText = read(graph.products[broker].path + '/Cargo.toml'); + const brokerManifest = Bun.TOML.parse(brokerText); + const sdkText = read(graph.products[sdk].path + '/Cargo.toml'); + const sdkManifest = Bun.TOML.parse(sdkText); + const addon = Bun.TOML.parse(read('src/native/node-addon/Cargo.toml')); + const imported = projectCargoWorkspace( + workspace, + Bun.TOML.parse(readFileSync(path.join(ROOT, 'Cargo.lock'), 'utf8')), + [graph.products[sdk].path, graph.products[broker].path], + (file) => Bun.TOML.parse(read(file)), + (file) => existsSync(path.join(ROOT, file)), + ); + expect(imported.facts[graph.products[core].path].version).toBe(coreManifest.package.version); + expect(imported.facts[graph.products[broker].path].version).toBe( + brokerManifest.package.version, + ); + const heldSdk = Bun.TOML.parse( + readFileSync(path.join(ROOT, graph.products[sdk].path, 'Cargo.toml'), 'utf8'), + ); + expect(sdkManifest.package.metadata.oliphaunt).toEqual(heldSdk.package.metadata.oliphaunt); + expect(read(graph.products[sdk].path + '/src/broker.rs')).toBe( + readFileSync(path.join(ROOT, graph.products[sdk].path, 'src/broker.rs'), 'utf8'), + ); + expect(workspace.workspace.dependencies[core].version).toBe( + selected.includes(sdk) && selected.includes(core) ? coreManifest.package.version : '0.2.0', + ); + expect(brokerManifest.dependencies[core].version).toBe( + selected.includes(broker) && selected.includes(core) ? coreManifest.package.version : '0.2.0', + ); + expect(sdkManifest.dependencies[broker].version).toBe( + selected.includes(sdk) && selected.includes(broker) + ? brokerManifest.package.version + : heldSdk.dependencies[broker].version, + ); + if (selected.includes(sdk)) expect(sdkManifest.package.version).toBe('0.3.3'); + if (!selected.includes(sdk) && !selected.includes(broker)) + expect(plan.requirements).toEqual([]); + if (sharedFile) { + // A single workspace declaration changes every public inheritor's + // normalized source envelope; the existing fixed point admits it. + const packed = sourceManifest(read(sharedFile), read('Cargo.toml'), { + product: scenario.sharedConsumer, + version: after[graph.products[scenario.sharedConsumer].path], + dependencyOwners: {}, + compatibility: {}, + }); + expect(packed.dependencies[core]).toEqual({ version: coreManifest.package.version }); + expect( + plan.requirements + .filter(({ path: file }) => file === 'Cargo.toml') + .map(({ product }) => product) + .sort(), + ).toEqual([sdk, scenario.sharedConsumer].sort()); + } + for (const [product, text] of [ + [broker, brokerText], + [sdk, sdkText], + ]) { + const packed = sourceManifest(text, read('Cargo.toml'), { + product, + version: after[graph.products[product].path], + dependencyOwners: {}, + compatibility: {}, + }); + expect(packed.dependencies[core].path).toBeUndefined(); + expect(packed.dependencies[core].version).toBe( + product === broker + ? brokerManifest.dependencies[core].version + : workspace.workspace.dependencies[core].version, + ); + if (product === sdk) { + expect(packed.dependencies[broker].path).toBeUndefined(); + expect(packed.dependencies[broker].version).toBe(sdkManifest.dependencies[broker].version); + } + } + // Use real Cargo resolution, rather than --no-deps enumeration. The fixture + // keeps exactly the repository's generated local version/path contracts; + // unrelated registry dependencies need no repeated fetch or compilation. + const scratch = mkdtempSync(path.join(os.tmpdir(), 'native-cargo-cohort-')); + try { + const names = ['core', 'broker', 'sdk', 'addon']; + const packageNames = [ + coreManifest.package.name, + brokerManifest.package.name, + sdkManifest.package.name, + addon.package.name, + ]; + const finalVersions = [ + coreManifest.package.version, + brokerManifest.package.version, + sdkManifest.package.version, + addon.package.version, + ]; + const beforeVersions = [ + graph.products[core].version, + graph.products[broker].version, + graph.products[sdk].version, + addon.package.version, + ]; + const write = (pins, packageVersions) => { + writeFileSync( + path.join(scratch, 'Cargo.toml'), + renderToml({ + workspace: { + members: names, + resolver: '3', + dependencies: { + [coreManifest.package.name]: { path: 'core', version: pins.sdkCore }, + }, + }, + }), + ); + for (const [index, name] of names.entries()) { + mkdirSync(path.join(scratch, name, 'src'), { recursive: true }); + writeFileSync(path.join(scratch, name, 'src/lib.rs'), 'pub fn fixture() {}\n'); + const dependencies = + name === 'broker' + ? { [coreManifest.package.name]: { path: '../core', version: pins.brokerCore } } + : name === 'sdk' + ? { + [coreManifest.package.name]: { workspace: true }, + [brokerManifest.package.name]: { + path: '../broker', + version: pins.sdkBroker, + optional: true, + }, + } + : name === 'addon' + ? { [coreManifest.package.name]: { path: '../core', version: pins.addonCore } } + : undefined; + writeFileSync( + path.join(scratch, name, 'Cargo.toml'), + renderToml({ + package: { + name: packageNames[index], + version: packageVersions[index], + edition: '2024', + }, + ...(dependencies ? { dependencies } : {}), + ...(name === 'sdk' + ? { + features: { + default: ['desktop'], + desktop: ['dep:' + brokerManifest.package.name], + }, + } + : {}), + }), + ); + } + }; + const originalAddon = Bun.TOML.parse( + readFileSync(path.join(ROOT, 'src/native/node-addon/Cargo.toml'), 'utf8'), + ); + write( + { + sdkCore: '0.2.0', + brokerCore: '0.2.0', + sdkBroker: heldSdk.dependencies[broker].version, + addonCore: originalAddon.dependencies[core].version, + }, + beforeVersions, + ); + const cargo = (...args) => + spawnSync('cargo', args, { + cwd: scratch, + encoding: 'utf8', + env: { + ...process.env, + CARGO_HOME: path.join(scratch, 'cargo-home'), + CARGO_NET_OFFLINE: 'true', + }, + timeout: 30_000, + }); + const locked = cargo('generate-lockfile', '--offline'); + expect(locked.status, locked.stderr).toBe(0); + write( + { + sdkCore: workspace.workspace.dependencies[core].version, + brokerCore: brokerManifest.dependencies[core].version, + sdkBroker: sdkManifest.dependencies[broker].version, + addonCore: addon.dependencies[core].version, + }, + finalVersions, + ); + syncLockfile( + path.join(scratch, 'Cargo.lock'), + new Map(packageNames.map((name, index) => [name, finalVersions[index]])), + [], + { write: true }, + ); + const resolved = cargo('metadata', '--frozen', '--format-version', '1'); + expect(resolved.status, resolved.stderr).toBe(0); + const metadata = JSON.parse(resolved.stdout); + expect(metadata.resolve.nodes).toHaveLength(4); + expect(metadata.packages.map(({ name, version }) => [name, version]).sort()).toEqual( + packageNames.map((name, index) => [name, finalVersions[index]]).sort(), + ); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } + for (const product of Object.keys(graph.products).filter( + (product) => !selected.includes(product), + )) + expect(after[graph.products[product].path]).toBe(versions[graph.products[product].path]); + } +}); diff --git a/tools/release/native-publication-artifacts.mts b/tools/release/native-publication-artifacts.mts new file mode 100644 index 000000000..a2a6d746e --- /dev/null +++ b/tools/release/native-publication-artifacts.mts @@ -0,0 +1,216 @@ +/** Read physical native envelopes; this remains construction evidence. */ +import { lstatSync, realpathSync } from 'node:fs'; +import path from 'node:path'; +import type { NativeLegalSourceBasis } from '../../src/native/sdks/swift/tools/native-legal-source-basis.mts'; +import { + type ConfiguredShippingCohort, + type CoverageAuthority, + checkShippingCoverage, +} from '../bazel/shipping-coverage.mts'; +import type { NativeShippingSupplier } from './bazel-shipping-inputs.mts'; +import { + assertWasixPublicationPackages, + discoverProductArtifacts, + discoverPublicationArtifacts, + expectedProductArtifactRows, + validateCargoPayloadPartSets, +} from './publication-lock.mts'; + +export interface PhysicalShippingCohort extends ConfiguredShippingCohort { + executionRoot: string; +} + +export type NativeRoot = { + label: string; + package: { + product: string; + version: string; + ecosystem: string; + name: string; + configuration: string; + role: string; + outputs: { path: string; owner: string }[]; + supplierInputs?: NativeShippingSupplier[]; + }; +}; + +/** Physical containment uses the host path rules, not textual path spelling. */ +export function nativePathIsDescendant(parent: string, child: string, paths = path) { + if (!paths.isAbsolute(parent) || !paths.isAbsolute(child)) return false; + const relative = paths.relative(parent, child); + return ( + relative !== '' && + relative !== '..' && + !relative.startsWith(`..${paths.sep}`) && + !paths.isAbsolute(relative) + ); +} + +export function nativeOutputPath(executionRoot: string, relative: unknown) { + if ( + typeof relative !== 'string' || + !relative.startsWith('bazel-out/') || + relative.includes('\\') || + relative.includes('\0') || + relative.split('/').some((part) => !part || part === '.' || part === '..') + ) + throw new Error(`unsafe native output path: ${JSON.stringify(relative)}`); + if (!path.isAbsolute(executionRoot)) + throw new Error('native output requires the captured absolute executionRoot'); + const physicalExecutionRoot = realpathSync(executionRoot); + const absolute = path.join(physicalExecutionRoot, relative); + const stat = lstatSync(absolute); + if (stat.isSymbolicLink() || (!stat.isFile() && !stat.isDirectory())) + throw new Error(`native output is not a physical file or directory: ${absolute}`); + const physicalRoot = realpathSync(path.join(physicalExecutionRoot, 'bazel-out')); + const physicalOutput = realpathSync(absolute); + if ( + !nativePathIsDescendant(physicalExecutionRoot, physicalRoot) || + !nativePathIsDescendant(physicalRoot, physicalOutput) + ) + throw new Error(`native output escapes its captured executionRoot: ${absolute}`); + return absolute; +} + +/** + * Query rows must come from the same configured cohort as their captured execroot. + * Archive readers supply identities, versions, dependencies, hashes and sizes; + * ShippingInfo declarations cannot substitute for those physical observations. + * Successful reading does not prove build provenance, qualification or baseline + * equivalence, and cannot select a release or authorize publication. + */ +export function readNativePublicationArtifacts( + authority: CoverageAuthority, + cohorts: PhysicalShippingCohort[], + { + products, + nativeSourceBasis, + artifactPhase = 'final', + }: { + products?: string[]; + nativeSourceBasis?: NativeLegalSourceBasis; + artifactPhase?: 'pre-version' | 'final'; + } = {}, +) { + const phaseAuthority = + artifactPhase === 'final' + ? authority + : { + ...authority, + artifactRows: expectedProductArtifactRows(authority.catalog.products, { artifactPhase }), + }; + const coverage = checkShippingCoverage(phaseAuthority, cohorts, { + products, + includeReleaseInputs: true, + }); + const roots = cohorts.flatMap((cohort) => { + if (!path.isAbsolute(cohort.executionRoot ?? '')) + throw new Error('each physical cohort requires its captured absolute executionRoot'); + const executionRoot = realpathSync(cohort.executionRoot); + return cohort.roots.flatMap((raw) => { + const root = raw as NativeRoot; + if (root.package.ecosystem === 'internal') return []; + return [ + { + ...root, + paths: root.package.outputs.map((output) => nativeOutputPath(executionRoot, output.path)), + }, + ]; + }); + }); + const registryRoots = roots.filter(({ package: pkg }) => + ['cargo', 'npm', 'maven'].includes(pkg.ecosystem), + ); + const registryArtifacts = registryRoots.length + ? discoverPublicationArtifacts([...new Set(registryRoots.flatMap(({ paths }) => paths))]) + : []; + const isRootOutput = (root, artifactPath) => { + const actualPath = realpathSync(path.resolve(import.meta.dir, '../..', artifactPath)); + return root.paths.some((output) => { + const expectedPath = realpathSync(output); + return actualPath === expectedPath || actualPath.startsWith(`${expectedPath}${path.sep}`); + }); + }; + for (const root of registryRoots) { + const identity = `${root.package.ecosystem}:${root.package.name}`; + const records = registryArtifacts.filter((record) => + record.artifacts.some((artifact) => isRootOutput(root, artifact.path)), + ); + if (!records.some((record) => `${record.ecosystem}:${record.name}` === identity)) + throw new Error(`${root.label} physical output does not contain ${identity}`); + for (const record of records) { + if (record.artifacts.some((artifact) => !isRootOutput(root, artifact.path))) + throw new Error(`${root.label} physical registry file is not a declared output`); + const actual = authority.resolveCarrier(record.ecosystem, record.name); + if ( + actual.product !== root.package.product || + actual.version !== record.version || + (actual.id !== identity && actual.parentCarrier !== identity) || + record.qualificationOnly + ) + throw new Error( + `${root.label} physical carrier does not match its canonical identity: ${actual.id}@${record.version}`, + ); + } + } + assertWasixPublicationPackages(registryArtifacts); + validateCargoPayloadPartSets( + registryArtifacts.map((record) => ({ + ...authority.resolveCarrier(record.ecosystem, record.name), + packageDependencies: record.dependencies, + })), + ); + const selected = new Set(coverage.products); + const productArtifacts = discoverProductArtifacts( + [...new Set(roots.flatMap(({ paths }) => paths))], + authority.catalog.products.filter(({ id }) => selected.has(id)), + { nativeSourceBasis, artifactPhase }, + ); + const expectedIds = phaseAuthority.artifactRows + .filter(({ product }) => selected.has(product)) + .map(({ product, id }) => `${product}:${id}`) + .sort(); + const actualIds = productArtifacts.map(({ product, id }) => `${product}:${id}`).sort(); + if (JSON.stringify(expectedIds) !== JSON.stringify(actualIds)) + throw new Error('physical native product artifact inventory is incomplete'); + for (const artifact of productArtifacts) { + const declared = phaseAuthority.artifactRows.find( + (row) => row.product === artifact.product && row.id === artifact.id, + ); + if ( + !declared || + ['role', 'kind', 'target', 'identity', 'name'].some((key) => declared[key] !== artifact[key]) + ) + throw new Error( + `physical native product artifact does not match canonical inventory: ${artifact.product}:${artifact.id}`, + ); + const root = roots.find( + ({ package: pkg }) => + pkg.product === artifact.product && + pkg.name === artifact.name && + pkg.role === artifact.role, + ); + const actualPath = realpathSync(path.resolve(import.meta.dir, '../..', artifact.path)); + if ( + !root?.paths.some((output) => { + const expectedPath = realpathSync(output); + return actualPath === expectedPath || actualPath.startsWith(`${expectedPath}${path.sep}`); + }) + ) + throw new Error( + `physical native artifact is not an output of its declared root: ${artifact.product}:${artifact.id}`, + ); + } + return { + ...coverage, + artifactRoots: [...new Set(roots.flatMap(({ paths }) => paths))].sort(), + registryArtifacts, + productArtifacts, + unverified: [ + ...coverage.unverified.filter( + (fact) => fact !== 'packed manifests, artifact kinds and payload identities', + ), + 'frozen source and completed-publication construction equivalence', + ], + }; +} diff --git a/tools/release/native-publication-artifacts.test.mts b/tools/release/native-publication-artifacts.test.mts new file mode 100644 index 000000000..9b3430472 --- /dev/null +++ b/tools/release/native-publication-artifacts.test.mts @@ -0,0 +1,554 @@ +import { expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { gzipSync } from 'node:zlib'; +import { iosBaseLegalMetadata } from '../../src/native/sdks/swift/tools/ios-carrier-manifest.mts'; +import { createDeterministicTar } from '../packaging/cargo-source-package.mts'; +import { releaseJavaScript } from '../packaging/emit-javascript.mts'; +import { + nativeOutputPath, + nativePathIsDescendant, + readNativePublicationArtifacts, +} from './native-publication-artifacts.mts'; +import { buildNativePublicationCandidate } from './native-publication-candidate.mts'; +import { loadPublicationCatalog, resolveActualCarrier } from './publication-catalog.mts'; +import { + expectedProductArtifactRows, + freezePublicationCandidate, + PUBLICATION_CANDIDATE_SCHEMA, + PUBLICATION_LOCK_SCHEMA, + sourceIdentity, + validatePublicationCandidate, + validatePublicationLock, +} from './publication-lock.mts'; +import { productCompatibilityVersion } from './release-graph.mts'; + +function fixture(run) { + const executionRoot = mkdtempSync(path.join(os.tmpdir(), 'native-physical-')); + const catalog = loadPublicationCatalog('native-physical-test'); + const carrier = catalog.carriers.find(({ product }) => product === 'oliphaunt-query-ts'); + const authority = { + catalog, + artifactRows: expectedProductArtifactRows(catalog.products), + resolveCarrier: (ecosystem, name) => resolveActualCarrier(catalog, ecosystem, name), + }; + const output = 'bazel-out/fixture/bin/query.tgz'; + const archive = path.join(executionRoot, output); + const source = path.join(executionRoot, 'stage'); + mkdirSync(path.dirname(archive), { recursive: true }); + mkdirSync(source); + const pack = (metadata = {}) => { + writeFileSync( + path.join(source, 'package.json'), + JSON.stringify({ + name: carrier.name, + version: carrier.version, + repository: { + type: 'git', + url: 'git+https://github.com/f0rr0/oliphaunt.git', + directory: 'src/query/ts', + }, + publishConfig: { access: 'public', provenance: true }, + ...metadata, + }), + ); + writeFileSync( + archive, + gzipSync(createDeterministicTar(source, 'package', { fixedFileMode: 0o644 })), + ); + }; + pack(); + const cohort = { + executionRoot, + roots: [ + { + label: '//fixture:shipping', + package: { + ...carrier, + configuration: 'portable', + outputs: [{ path: output, owner: '//fixture:archive' }], + }, + }, + ], + aquery: { + pathFragments: [ + { id: 1, label: 'source.ts' }, + { id: 2, label: 'bazel-out' }, + { id: 3, parentId: 2, label: 'fixture' }, + { id: 4, parentId: 3, label: 'bin' }, + { id: 5, parentId: 4, label: 'query.tgz' }, + ], + targets: [{ id: 1, label: '//fixture:archive' }], + artifacts: [ + { id: 1, pathFragmentId: 1 }, + { id: 2, pathFragmentId: 5 }, + ], + depSetOfFiles: [{ id: 1, directArtifactIds: [1] }], + actions: [ + { + targetId: 1, + configurationId: 1, + actionKey: 'fixture', + mnemonic: 'Package', + inputDepSetIds: [1], + outputIds: [2], + primaryOutputId: 2, + arguments: ['package', 'source.ts', output], + }, + ], + configuration: [{ id: 1 }], + }, + }; + const read = () => + readNativePublicationArtifacts(authority, [cohort], { products: [carrier.product] }); + try { + run({ executionRoot, archive, carrier, authority, cohort, pack, read }); + } finally { + rmSync(executionRoot, { recursive: true, force: true }); + } +} + +test('reads native package bytes without granting release authority or full coverage', () => { + fixture(({ carrier, read }) => { + const result = read(); + expect(result.scope).toBe('construction'); + expect(result.completeProductInventory).toBe(false); + expect(result.registryArtifacts[0]).toMatchObject({ + ecosystem: 'npm', + name: carrier.name, + version: carrier.version, + }); + expect(result.registryArtifacts[0].artifacts[0].sha256).toMatch(/^[0-9a-f]{64}$/); + expect(result.unverified).toContain('producer execution or trusted cached-result provenance'); + expect(result.unverified).toContain( + 'frozen source and completed-publication construction equivalence', + ); + }); +}); + +test('physical native roots enter the existing candidate and cannot freeze as publication evidence', () => { + fixture(({ carrier, cohort, archive }) => { + const candidate = buildNativePublicationCandidate({ + products: [carrier.product], + cohorts: [{ ...cohort, source: sourceIdentity('HEAD') }], + }); + expect(candidate.schema).toBe(PUBLICATION_CANDIDATE_SCHEMA); + expect(candidate.scope).toBe('construction'); + expect(candidate.source).toEqual(sourceIdentity('HEAD')); + expect(candidate.nativePayloads.source).toEqual(candidate.source); + expect(candidate.nativePayloads.products).toEqual([ + { id: carrier.product, version: carrier.version, roots: [] }, + ]); + expect(candidate.missing).toEqual([]); + expect(candidate.carriers).toHaveLength(1); + expect(candidate.carriers[0].artifacts[0].sha256).toBe( + createHash('sha256').update(readFileSync(archive)).digest('hex'), + ); + expect(candidate.carriers[0].artifacts[0].path).toMatch(/^target\/n\//u); + expect( + buildNativePublicationCandidate({ + products: [carrier.product], + cohorts: [{ ...cohort, source: sourceIdentity('HEAD') }], + }).packageEnvelopeDigest, + ).toBe(candidate.packageEnvelopeDigest); + expect(validatePublicationCandidate(candidate)).toBe(candidate); + expect(() => freezePublicationCandidate(candidate)).toThrow('cannot freeze'); + expect(() => + validatePublicationLock({ ...candidate, schema: PUBLICATION_LOCK_SCHEMA }), + ).toThrow('construction evidence cannot authorize'); + const withoutScope = { ...candidate }; + delete withoutScope.scope; + for (const value of [withoutScope, { ...withoutScope, nativePayloads: undefined }]) { + expect(() => freezePublicationCandidate(value)).toThrow('cannot freeze'); + expect(() => validatePublicationLock({ ...value, schema: PUBLICATION_LOCK_SCHEMA })).toThrow( + 'construction evidence cannot authorize', + ); + } + }); +}); + +test('native candidate rejects foreign frozen sources, missing cohort outputs and incomplete inventory', () => { + fixture(({ carrier, cohort }) => { + const source = sourceIdentity('HEAD'); + const run = (value, products = [carrier.product]) => + buildNativePublicationCandidate({ products, cohorts: [value] }); + expect(() => run({ ...cohort })).toThrow('exact frozen candidate source'); + expect(() => run({ ...cohort, source: { ...source, commit: '0'.repeat(40) } })).toThrow( + 'exact frozen candidate source', + ); + expect(() => run({ ...cohort, source: { ...source, tree: '0'.repeat(40) } })).toThrow( + 'exact frozen candidate source', + ); + expect(() => run({ ...cohort, source, roots: [] })).toThrow(); + expect(() => run({ ...cohort, source }, ['oliphaunt-query', carrier.product])).toThrow(); + expect(() => + run({ ...cohort, source, executionRoot: path.dirname(cohort.executionRoot) }), + ).toThrow(); + }); +}); + +test('native candidate rejects a replaced source snapshot between physical capture and candidate assembly', () => { + fixture(({ carrier, cohort }) => { + const snapshot = process.env.OLIPHAUNT_GIT_SOURCE_JSON!; + const source = sourceIdentity('HEAD'); + try { + for (const replacement of [ + { ...JSON.parse(snapshot), commit: 'b'.repeat(40), checkout: 'b'.repeat(40) }, + { ...JSON.parse(snapshot), tree: 'c'.repeat(40) }, + ]) { + process.env.OLIPHAUNT_GIT_SOURCE_JSON = snapshot; + const changing = Object.defineProperty({ ...cohort, source }, 'aquery', { + get() { + process.env.OLIPHAUNT_GIT_SOURCE_JSON = JSON.stringify(replacement); + return cohort.aquery; + }, + }); + expect(() => + buildNativePublicationCandidate({ products: [carrier.product], cohorts: [changing] }), + ).toThrow(); + } + } finally { + process.env.OLIPHAUNT_GIT_SOURCE_JSON = snapshot; + } + }); +}); + +test('native declarations cannot substitute for the actual packed identity or version', () => { + fixture(({ pack, read }) => { + pack({ name: '@oliphaunt/other' }); + expect(read).toThrow('physical output does not contain'); + pack({ version: '99.0.0' }); + expect(read).toThrow('physical carrier does not match its canonical identity'); + }); +}); + +test('uses only the captured execroot and rejects missing, symlinked or incomplete outputs', () => { + fixture(({ executionRoot, archive, authority, cohort, read }) => { + cohort.executionRoot = 'relative'; + expect(read).toThrow('captured absolute executionRoot'); + cohort.executionRoot = executionRoot; + rmSync(archive); + expect(read).toThrow('ENOENT'); + symlinkSync(path.join(executionRoot, 'stage/package.json'), archive); + expect(read).toThrow('not a physical file or directory'); + expect(() => readNativePublicationArtifacts(authority, [cohort])).toThrow( + 'incomplete native shipping coverage', + ); + }); +}); + +test('native output containment uses standard Windows and POSIX path semantics', () => { + const root = 'D:/a/_temp/b/execroot/_main'; + for (const [parent, child, expected] of [ + [root, `${root}/bazel-out/opt/bin/shipping.json`, true], + [root, 'D:\\a\\_temp\\b\\execroot\\_main\\bazel-out\\opt\\bin\\shipping.json', true], + [`${root}/`, 'd:\\A\\_TEMP\\B\\EXECROOT\\_MAIN\\bazel-out\\shipping.json', true], + [`${root}/.`, `${root}/bazel-out/shipping.json`, true], + [root, root, false], + [root, `${root}/`, false], + [root, `${root}/..`, false], + [root, `${root}/../outside/shipping.json`, false], + [root, `${root}-sibling/bazel-out/shipping.json`, false], + [root, 'E:/a/_temp/b/execroot/_main/bazel-out/shipping.json', false], + [root, 'D:relative/bazel-out/shipping.json', false], + ['D:relative', `${root}/bazel-out/shipping.json`, false], + ['D:/', 'd:\\a\\shipping.json', true], + ['//server/share/root', '\\\\SERVER\\SHARE\\root\\bazel-out\\shipping.json', true], + ['//server/share/root', '//server/other/root/shipping.json', false], + ['//server/share/root', '//other/share/root/shipping.json', false], + ] as const) + expect(nativePathIsDescendant(parent, child, path.win32)).toBe(expected); + for (const [parent, child, expected] of [ + ['/execroot', '/execroot/bazel-out/shipping.json', true], + ['/execroot/', '/execroot/bazel-out/shipping.json', true], + ['/', '/execroot/bazel-out/shipping.json', true], + ['/execroot', '/execroot', false], + ['/execroot', '/execroot-sibling/shipping.json', false], + ['/execroot', '/Execroot/bazel-out/shipping.json', false], + ['/execroot', '/execroot/../outside/shipping.json', false], + ['relative', '/execroot/shipping.json', false], + ] as const) + expect(nativePathIsDescendant(parent, child, path.posix)).toBe(expected); +}); + +test('native outputs resolve the captured execroot before checking physical containment', () => { + fixture(({ executionRoot, archive }) => { + const output = 'bazel-out/fixture/bin/query.tgz'; + for (const root of [ + `${executionRoot}${path.sep}`, + `${executionRoot}${path.sep}.`, + executionRoot.split(path.sep).join('/'), + ]) + expect(readFileSync(nativeOutputPath(root, output))).toEqual(readFileSync(archive)); + const alias = path.join(executionRoot, 'captured-root-alias'); + symlinkSync(executionRoot, alias, process.platform === 'win32' ? 'junction' : 'dir'); + expect(readFileSync(nativeOutputPath(alias, output))).toEqual(readFileSync(archive)); + expect(() => nativeOutputPath('relative', output)).toThrow('captured absolute executionRoot'); + }); +}); + +test('rejects an output parent symlink that escapes the captured execroot', () => { + fixture(({ archive, read }) => { + const outside = mkdtempSync(path.join(os.tmpdir(), 'native-physical-outside-')); + try { + writeFileSync(path.join(outside, path.basename(archive)), readFileSync(archive)); + rmSync(path.dirname(archive), { recursive: true }); + symlinkSync(outside, path.dirname(archive)); + expect(read).toThrow('escapes its captured executionRoot'); + } finally { + rmSync(outside, { recursive: true, force: true }); + } + }); +}); + +test('rejects a physical bazel-out root outside the captured execroot', () => { + fixture(({ executionRoot, archive }) => { + const outside = mkdtempSync(path.join(os.tmpdir(), 'native-output-root-outside-')); + try { + const output = 'bazel-out/fixture/bin/query.tgz'; + const relocated = path.join(outside, 'fixture/bin/query.tgz'); + mkdirSync(path.dirname(relocated), { recursive: true }); + writeFileSync(relocated, readFileSync(archive)); + rmSync(path.join(executionRoot, 'bazel-out'), { recursive: true }); + symlinkSync( + outside, + path.join(executionRoot, 'bazel-out'), + process.platform === 'win32' ? 'junction' : 'dir', + ); + expect(() => nativeOutputPath(executionRoot, output)).toThrow( + 'escapes its captured executionRoot', + ); + } finally { + rmSync(outside, { recursive: true, force: true }); + } + }); +}); + +test('Maven companion files must belong to the declared native output', () => { + fixture(({ archive, executionRoot, authority, cohort }) => { + const carrier = authority.catalog.carriers.find(({ ecosystem }) => ecosystem === 'maven'); + const product = authority.catalog.products.find(({ id }) => id === carrier.product); + const [group, artifact] = carrier.name.split(':'); + const prefix = `${artifact}-${carrier.version}`; + rmSync(archive); + const pom = path.join(path.dirname(archive), `${prefix}.pom`); + writeFileSync( + pom, + `4.0.0${group}${artifact}${carrier.version}FixtureFixturehttps://github.com/f0rr0/oliphauntMIThttps://opensource.org/license/mitFixturehttps://github.com/f0rr0scm:git:https://github.com/f0rr0/oliphaunt.gitscm:git:ssh://git@github.com/f0rr0/oliphaunt.githttps://github.com/f0rr0/oliphaunt\n`, + ); + for (const suffix of ['.jar', '-sources.jar', '-javadoc.jar']) + writeFileSync(path.join(path.dirname(pom), `${prefix}${suffix}`), 'fixture'); + authority.catalog = { ...authority.catalog, products: [product], carriers: [carrier] }; + authority.artifactRows = []; + cohort.aquery.pathFragments[4].label = path.basename(pom); + cohort.roots[0].package = { + ...carrier, + configuration: 'portable', + outputs: [{ path: path.relative(executionRoot, pom), owner: '//fixture:archive' }], + }; + const read = () => + readNativePublicationArtifacts(authority, [cohort], { products: [product.id] }); + expect(read).toThrow('physical registry file is not a declared output'); + cohort.roots[0].package.outputs[0].path = path.relative(executionRoot, path.dirname(pom)); + cohort.aquery.artifacts[1].pathFragmentId = 4; + expect(read().registryArtifacts[0].artifacts).toHaveLength(4); + }); +}); + +test('validates the frozen Swift manifest and source tree as actual native outputs', () => { + const executionRoot = mkdtempSync(path.join(os.tmpdir(), 'native-physical-swift-')); + const catalog = loadPublicationCatalog('native-physical-swift'); + const product = catalog.products.find(({ id }) => id === 'oliphaunt-swift'); + const rows = expectedProductArtifactRows([product]); + const sdk = 'bazel-out/fixture/bin/swift'; + const paths = rows.map((row) => { + const directory = + row.role === 'github-release-asset' + ? 'release-assets' + : row.kind === 'swiftpm-ios-carrier-manifest' + ? 'release-tree/src/sdks/swift/Carriers' + : row.kind.startsWith('swiftpm-extension-') || row.kind === 'swiftpm-carrier-resolver' + ? 'extension-generator' + : ''; + return path.posix.join(sdk, directory, row.name); + }); + const write = (name, bytes) => { + const index = rows.findIndex((row) => row.name === name); + const file = path.join(executionRoot, paths[index]); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, bytes); + }; + const nativeVersion = productCompatibilityVersion('oliphaunt-swift', 'liboliphaunt-native'); + const tag = `liboliphaunt-native-v${nativeVersion}`; + const assets = [ + [ + 'base-xcframework', + `liboliphaunt-${nativeVersion}-apple-spm-xcframework.zip`, + 'zip', + 'liboliphaunt.xcframework', + ], + [ + 'runtime-resources', + `liboliphaunt-${nativeVersion}-runtime-resources-ios-datum64.tar.gz`, + 'tar.gz', + 'oliphaunt', + ], + ].map(([role, name, format, member], index) => ({ + role, + name, + format, + member, + bytes: index + 1, + sha256: String(index + 1).repeat(64), + url: `https://github.com/f0rr0/oliphaunt/releases/download/${tag}/${name}`, + })); + const carrier = { + schema: 'oliphaunt-react-native-ios-carrier-v1', + base: { product: 'liboliphaunt-native', version: nativeVersion, tag, assets }, + carriers: [], + extensions: [], + legal: { base: iosBaseLegalMetadata(), extensions: [] }, + }; + const manifest = `.binaryTarget(name: "liboliphaunt", url: "${assets[0].url}", checksum: "${assets[0].sha256}")\n`; + try { + for (const row of rows.filter(({ kind }) => kind !== 'swiftpm-release-tree')) + write(row.name, `${row.name}\n`); + write('Package.swift.release', manifest); + write('oliphaunt-react-native-ios-carriers.json', JSON.stringify(carrier)); + write( + 'extension-owner-catalog.json', + readFileSync(new URL('../../src/extensions/generated/sdk/extensions.json', import.meta.url)), + ); + write( + 'extension-resource-inventory.mjs', + releaseJavaScript( + path.resolve( + import.meta.dir, + '../../src/native/sdks/swift/tools/extension-resource-inventory.mts', + ), + ), + ); + const bindings = rows.find(({ kind }) => kind === 'swift-bindings'); + const checksum = rows.find(({ kind }) => kind === 'checksums'); + write( + checksum.name, + `${createHash('sha256').update(`${bindings.name}\n`).digest('hex')} ./${bindings.name}\n`, + ); + const pathFragments = []; + const artifacts = paths.map((output, index) => { + let parentId; + for (const label of output.split('/')) { + const id = pathFragments.length + 1; + pathFragments.push({ id, label, ...(parentId ? { parentId } : {}) }); + parentId = id; + } + return { id: index + 1, pathFragmentId: parentId }; + }); + const cohort = { + executionRoot, + roots: rows.map((row, index) => ({ + label: `//fixture:swift_${index}`, + package: { + ...row, + ecosystem: 'github', + configuration: row.target, + outputs: [ + { + path: paths[index], + owner: + row.role === 'github-release-asset' ? '//fixture:bindings' : '//fixture:producer', + }, + ], + }, + })), + aquery: { + pathFragments, + artifacts, + targets: [ + { id: 1, label: '//fixture:producer' }, + { id: 2, label: '//fixture:bindings' }, + ], + depSetOfFiles: [], + configuration: [{ id: 1 }], + actions: [ + { + targetId: 1, + configurationId: 1, + actionKey: 'fixture', + mnemonic: 'Package', + inputDepSetIds: [], + outputIds: artifacts + .filter((_, index) => rows[index].role !== 'github-release-asset') + .map(({ id }) => id), + primaryOutputId: artifacts.find( + (_, index) => rows[index].role !== 'github-release-asset', + ).id, + arguments: ['fixture'], + }, + { + targetId: 2, + configurationId: 1, + actionKey: 'bindings', + mnemonic: 'Package', + inputDepSetIds: [], + outputIds: artifacts + .filter((_, index) => rows[index].role === 'github-release-asset') + .map(({ id }) => id), + primaryOutputId: artifacts.find( + (_, index) => rows[index].role === 'github-release-asset', + ).id, + arguments: ['bindings'], + }, + ], + }, + }; + const authority = { + catalog, + artifactRows: rows, + resolveCarrier: (ecosystem, name) => resolveActualCarrier(catalog, ecosystem, name), + }; + const read = () => + readNativePublicationArtifacts(authority, [cohort], { products: [product.id] }); + const result = read(); + authority.artifactRows = expectedProductArtifactRows(catalog.products, { + swiftExtensionFixture: true, + }); + expect(read).toThrow(/incomplete native shipping coverage/u); + const preVersion = readNativePublicationArtifacts(authority, [cohort], { + products: [product.id], + artifactPhase: 'pre-version', + }); + expect(preVersion.productArtifacts).toEqual(result.productArtifacts); + expect(preVersion.registryArtifacts).toEqual(result.registryArtifacts); + authority.artifactRows = rows; + expect(result.sourcePublicationInputs).toBe(2); + expect(result.productArtifacts).toHaveLength(rows.length); + expect( + result.productArtifacts.find(({ kind }) => kind === 'swiftpm-release-tree').sha256, + ).toMatch(/^[0-9a-f]{64}$/); + const candidate = buildNativePublicationCandidate({ + products: [product.id], + cohorts: [{ ...cohort, source: sourceIdentity('HEAD') }], + }); + const before = result.productArtifacts.filter(({ role }) => role === 'github-release-asset'); + const after = candidate.productArtifacts.filter(({ role }) => role === 'github-release-asset'); + expect(after.map(({ name, sha256 }) => ({ name, sha256 }))).toEqual( + before.map(({ name, sha256 }) => ({ name, sha256 })), + ); + for (const artifact of after) + expect(path.basename(path.dirname(artifact.path))).toBe('release-assets'); + expect(candidate.scope).toBe('construction'); + expect(() => freezePublicationCandidate(candidate)).toThrow('cannot freeze'); + carrier.extensions.push({ sqlName: 'pgtap' }); + write('oliphaunt-react-native-ios-carriers.json', JSON.stringify(carrier)); + expect(read).toThrow('selection-neutral'); + carrier.extensions = []; + write('oliphaunt-react-native-ios-carriers.json', JSON.stringify(carrier)); + write('Package.swift.release', manifest.replace(assets[0].sha256, 'f'.repeat(64))); + expect(read).toThrow('checksum'); + } finally { + rmSync(executionRoot, { recursive: true, force: true }); + } +}); diff --git a/tools/release/native-publication-candidate.mts b/tools/release/native-publication-candidate.mts new file mode 100644 index 000000000..848171255 --- /dev/null +++ b/tools/release/native-publication-candidate.mts @@ -0,0 +1,71 @@ +/** Physical native providers adapted to the existing candidate; authority stays construction. */ +import type { NativeLegalSourceBasis } from '../../src/native/sdks/swift/tools/native-legal-source-basis.mts'; +import { + readNativePublicationArtifacts, + type PhysicalShippingCohort, +} from './native-publication-artifacts.mts'; +import { loadPublicationCatalog, resolveActualCarrier } from './publication-catalog.mts'; +import { captureNativePublicationOutputs } from './native-publication-staging.mts'; +import { captureNativePreEnvelopePayloads } from './native-publication-payloads.mts'; +import { + buildPublicationCandidate, + expectedProductArtifactRows, + sourceIdentity, +} from './publication-lock.mts'; + +export interface NativeCandidateCohort extends PhysicalShippingCohort { + source: { commit: string; tree: string }; +} + +export function buildNativePublicationCandidate({ + cohorts, + products, + headRef = 'HEAD', + nativeSourceBasis, +}: { + cohorts: NativeCandidateCohort[]; + products?: string[]; + headRef?: string; + nativeSourceBasis?: NativeLegalSourceBasis; +}) { + const source = sourceIdentity(headRef); + if (!Array.isArray(cohorts) || !cohorts.length) + throw new Error('native candidate requires actual configured physical cohorts'); + for (const cohort of cohorts) + if (cohort.source?.commit !== source.commit || cohort.source?.tree !== source.tree) + throw new Error('native cohort does not match the exact frozen candidate source'); + const outputs = captureNativePublicationOutputs(cohorts, { sourceCommit: source.commit }); + const catalog = loadPublicationCatalog('native-publication-candidate'); + const selected = new Set(products ?? catalog.products.map(({ id }) => id)); + const payloads = captureNativePreEnvelopePayloads(cohorts, { + source, + products: catalog.products.filter(({ id }) => selected.has(id)), + }); + const authority = { + catalog, + artifactRows: expectedProductArtifactRows( + catalog.products.filter(({ id }) => selected.has(id)), + ), + resolveCarrier: (ecosystem: string, name: string) => + resolveActualCarrier(catalog, ecosystem, name, 'native-publication-candidate'), + }; + const physical = readNativePublicationArtifacts(authority, cohorts, { + products, + nativeSourceBasis, + }); + const candidate = buildPublicationCandidate({ + products, + artifactRoots: outputs.stage(), + headRef: source.commit, + nativeSourceBasis, + }); + if (candidate.source.commit !== source.commit || candidate.source.tree !== source.tree) + throw new Error('native candidate source changed after its physical cohorts were captured'); + payloads.assertUnchanged(); + return { + ...candidate, + scope: 'construction' as const, + nativePayloads: payloads.payloads, + unverified: physical.unverified, + }; +} diff --git a/tools/release/native-publication-delivery.mts b/tools/release/native-publication-delivery.mts new file mode 100644 index 000000000..db095f3f9 --- /dev/null +++ b/tools/release/native-publication-delivery.mts @@ -0,0 +1,764 @@ +/** Physical archive bindings and completed delivery bytes, never publication admission. */ +import { createHash } from 'node:crypto'; +import { closeSync, constants, fstatSync, lstatSync, openSync, readSync } from 'node:fs'; +import path from 'node:path'; +import { + requiredRuntimeMemberPaths, + requiredToolsMemberPaths, +} from '../../src/native/runtime/tools/native-runtime-payload.mts'; +import { readPortableArchiveEntries } from '../packaging/portable-archive.mts'; +import { requireSafeDirectoryChain } from '../packaging/release-directory-safety.mts'; +import { validateReviewedNativeProducerAssurance } from './authenticate-native-build-evidence.mts'; +import { + type CompletedPublication, + createCompletedPublicationChecker, +} from './completed-release-publication.mts'; +import { requestGithubPages, requestGithubRepositoryJson } from './github-read.mts'; +import { nativeShippingRootsHaveQualification } from './native-build-qualification.mts'; +import { + assertSeedConstructionBaseline, + type NativeSeedConstructionBaseline, + seedArchiveHasChangedDeclaredContents, +} from './native-seed-baseline.mts'; +import type { compareNativeCompletedPhysicalDelivery } from './native-completed-delivery.mts'; +import { nativeOutputPath } from './native-publication-artifacts.mts'; +import type { observeNativePublicationConstruction } from './native-publication-observation.mts'; +import { + type NativeDeliveryVerification, + type NativePayloadCohort, + type NativePayloads, + nativePayloadDigest, +} from './native-publication-payloads.mts'; +import { + captureNativeOutputMembers, + type NativeOutputMember, +} from './native-publication-staging.mts'; +import type { compareNativeCompletedSourceDelivery } from './native-source-carrier-changes.mts'; +import { loadPublicationCatalog } from './publication-catalog.mts'; +import { expectedProductArtifactRows } from './publication-lock.mts'; +import { requestReleaseAssetProof } from './verify_github_release_attestations.mts'; + +type Artifact = { + product: string; + version: string; + id: string; + role: string; + kind: string; + target: string; + name: string; +}; +type Source = { commit: string; tree: string }; +type DeliveredRoot = NativeDeliveryVerification['deliveredPayloads'][number]; +type DeliveredMember = { path: string; mode: number }; +const kinds = new Map([ + ['liboliphaunt-native', 'native-runtime'], + ['postgres-tools-native', 'native-tools'], +]); +const canonical = (value: unknown): string => + Array.isArray(value) + ? `[${value.map(canonical).join(',')}]` + : value && typeof value === 'object' + ? `{${Object.entries(value) + .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)) + .map(([key, child]) => `${JSON.stringify(key)}:${canonical(child)}`) + .join(',')}}` + : JSON.stringify(value); +const hash = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +const same = (left: unknown, right: unknown) => canonical(left) === canonical(right); +const sortedMembers = (members: NativeOutputMember[]) => + members.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0)); + +/** Exact inner member equality, independent of producer labels, actions and outer envelopes. */ +export function differentNativeDeliveredMembers( + before: readonly DeliveredMember[], + after: readonly DeliveredMember[], +) { + const index = (members: readonly DeliveredMember[]) => { + const result = new Map(); + for (const member of members) { + if ( + typeof member.path !== 'string' || + (member.path !== '' && + (member.path.startsWith('/') || + member.path.includes('\\') || + /[\u0000-\u001f\u007f]/u.test(member.path) || + member.path.split('/').some((part) => !part || part === '.' || part === '..'))) || + !Number.isInteger(member.mode) || + member.mode < 0 || + member.mode > 0o777 || + result.has(member.path) + ) + throw new Error('native delivery member identity is unsafe, duplicate or has invalid mode'); + // Keep every adapter-supplied identity field. Source-envelope adapters + // neutralize only their typed own identity before calling this function. + result.set(member.path, canonical(member)); + } + return result; + }; + const old = index(before); + const current = index(after); + return [...new Set([...old.keys(), ...current.keys()])] + .filter((name) => old.get(name) !== current.get(name)) + .sort(); +} + +function exactSource(source: Source) { + if (![source?.commit, source?.tree].every((sha) => /^[a-f0-9]{40}$/u.test(sha ?? ''))) + throw new Error('native archive delivery requires exact source commit/tree'); +} + +function rows(products = loadPublicationCatalog('native archive delivery').products) { + return expectedProductArtifactRows(products).filter( + (row) => row.role === 'github-release-asset' && kinds.get(row.product) === row.kind, + ) as Artifact[]; +} + +function memberIdentities(file: string): NativeOutputMember[] { + // This is the installed-tree contract, not the TAR wrapper header. Both + // retained extractors force the destination root to 0755, including ZIPs + // without a root marker; all actual inner paths and modes remain below. + const members: NativeOutputMember[] = [{ path: '', type: 'directory', mode: 0o755 }]; + for (const entry of readPortableArchiveEntries(file).values()) { + const memberPath = entry.name.replace(/\/$/u, ''); + members.push( + entry.isDirectory + ? { path: memberPath, type: 'directory', mode: entry.mode & 0o777 } + : { + path: memberPath, + type: 'file', + mode: entry.mode & 0o777, + size: entry.size, + sha256: hash(entry.data()), + }, + ); + } + return sortedMembers(members); +} + +function payloadContract(members: NativeOutputMember[], artifact: Artifact) { + const executable = new Set( + artifact.kind === 'native-runtime' + ? requiredRuntimeMemberPaths(artifact.target, 'runtime/bin') + : requiredToolsMemberPaths(artifact.target, 'runtime/bin'), + ); + for (const name of executable) + if (!members.some((member) => member.path === name && member.type === 'file')) + throw new Error(`native archive delivery is missing declared executable ${name}`); + // These are precisely copyDeclaredTree(executableFiles) + archiveDirectory + // modes from the existing native GitHub envelope, not a guessed chmod policy. + return sortedMembers( + members.map((member) => ({ + ...member, + mode: member.type === 'directory' || executable.has(member.path) ? 0o755 : 0o644, + })), + ); +} + +/** Bind final native GitHub members to actual declared pre-envelope outputs. */ +export function bindNativeArchiveDelivery( + payloads: NativePayloads, + cohorts: NativePayloadCohort[], + artifactRows = rows(), +) { + exactSource(payloads.source); + if (payloads.scope !== 'construction') throw new Error('native archive binding is construction'); + for (const cohort of cohorts) + if (!same(cohort.source, payloads.source)) + throw new Error('native archive cohort differs from captured payload source'); + const products = payloads.products.map((product) => { + const deliveredPayloads: DeliveredRoot[] = []; + const archives = []; + let reason = 'pre-envelope-roots-missing'; + for (const root of product.roots) { + reason = 'unsupported-native-delivery-contract'; + const expected = artifactRows.filter( + (artifact) => + artifact.product === product.id && + artifact.version === product.version && + artifact.target === root.configuration && + artifact.role === 'github-release-asset' && + artifact.kind === kinds.get(product.id), + ); + if (!expected.length) continue; + if ( + expected.length !== 1 || + root.name !== `${product.id}-public-payload` || + root.role !== 'construction' || + root.outputs.length !== 1 || + !root.outputs[0].members.some((member) => member.path === '' && member.type === 'directory') + ) + throw new Error('native archive requires one unambiguous declared payload directory'); + const declaredPayloads = cohorts.flatMap((cohort) => + cohort.roots.filter( + ({ label, package: pkg }) => + cohort.executionRoot === root.executionRoot && + label === root.label && + pkg.product === product.id && + pkg.version === product.version && + pkg.ecosystem === 'internal' && + pkg.name === root.name && + pkg.configuration === root.configuration && + pkg.role === root.role && + same( + pkg.outputs, + root.outputs.map(({ members: _members, ...output }) => output), + ), + ), + ); + reason = 'declared-pre-envelope-root-missing'; + if (!declaredPayloads.length) continue; + if (declaredPayloads.length !== 1) throw new Error('ambiguous declared native payload root'); + const capturedPayload = captureNativeOutputMembers(root.executionRoot, root.outputs[0].path); + if (!same(capturedPayload.members, root.outputs[0].members)) + throw new Error('native raw payload differs from its captured physical members'); + const artifact = expected[0]; + const observed = cohorts.flatMap((cohort) => + cohort.roots + .filter( + ({ package: pkg }) => + pkg.product === artifact.product && + pkg.ecosystem === 'github' && + pkg.name === artifact.name && + pkg.configuration === artifact.target && + pkg.role === artifact.role, + ) + .map((root) => ({ cohort, root })), + ); + reason = 'declared-final-archive-missing'; + if (!observed.length) continue; + if ( + observed.length !== 1 || + observed[0].root.package.version !== artifact.version || + observed[0].root.package.outputs.length !== 1 + ) + throw new Error('native final archive declaration is ambiguous or has a different version'); + const { cohort, root: archiveRoot } = observed[0]; + const output = archiveRoot.package.outputs[0]; + if (!output.owner || path.posix.basename(output.path) !== artifact.name) + throw new Error('native final archive differs from its declared canonical file'); + const capture = captureNativeOutputMembers(cohort.executionRoot, output.path); + const physical = capture.members[0]; + if (capture.members.length !== 1 || physical.type !== 'file') + throw new Error('native final archive must be one declared regular File'); + const members = memberIdentities(nativeOutputPath(cohort.executionRoot, output.path)); + if (!same(members, payloadContract(root.outputs[0].members, artifact))) + throw new Error( + 'native final archive does not exactly deliver its captured payload contract', + ); + capture.assertUnchanged(); + capturedPayload.assertUnchanged(); + archives.push({ ...artifact, size: physical.size, sha256: physical.sha256 }); + deliveredPayloads.push({ + name: root.name, + configuration: root.configuration, + role: root.role, + outputs: [{ name: path.posix.basename(root.outputs[0].path), members }], + }); + } + const complete = + deliveredPayloads.length > 0 && deliveredPayloads.length === product.roots.length; + const completeConfiguredArchiveInventory = + complete && + same( + artifactRows + .filter( + (artifact) => + artifact.product === product.id && + artifact.version === product.version && + artifact.kind === kinds.get(product.id), + ) + .map(({ target }) => target) + .sort(), + deliveredPayloads.map(({ configuration }) => configuration).sort(), + ); + return { + product: product.id, + version: product.version, + reason: complete ? 'physical-final-members-bound' : reason, + archives, + completeConfiguredArchiveInventory, + physicalDelivery: complete + ? ({ + source: payloads.source, + product: product.id, + version: product.version, + payloadDigest: nativePayloadDigest(product), + deliveredPayloads, + } satisfies NativeDeliveryVerification) + : undefined, + }; + }); + return { + scope: 'construction' as const, + source: payloads.source, + products, + unverified: [ + 'producer execution or trusted cached-result provenance', + 'native qualification workflow proof', + 'producer equivalence to the declared frozen source cohort', + 'remaining registry carrier, facade and public artifact delivery coverage', + ], + }; +} + +function regularArchiveIdentity(file: string) { + requireSafeDirectoryChain(path.dirname(path.resolve(file)), { + label: 'completed native archive', + }); + const descriptor = openSync(file, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0)); + try { + const before = fstatSync(descriptor); + if (!before.isFile()) throw new Error('completed native archive must be regular'); + const digest = createHash('sha256'); + const buffer = Buffer.allocUnsafe(1024 * 1024); + let size = 0; + for (;;) { + const count = readSync(descriptor, buffer); + if (!count) break; + digest.update(buffer.subarray(0, count)); + size += count; + } + const after = fstatSync(descriptor); + const named = lstatSync(file); + if ( + !named.isFile() || + named.isSymbolicLink() || + [after, named].some( + (stat) => + stat.dev !== before.dev || + stat.ino !== before.ino || + stat.size !== size || + stat.mtimeMs !== before.mtimeMs || + stat.ctimeMs !== before.ctimeMs, + ) + ) + throw new Error('completed native archive changed during capture'); + return { size, sha256: digest.digest('hex'), device: before.dev, inode: before.ino }; + } finally { + closeSync(descriptor); + } +} + +/** Authenticate actual completed public assets; never infer historical Bazel outputs. */ +export async function captureCompletedNativeArchiveDelivery( + { + publication, + files, + }: { + publication: CompletedPublication; + files: { target: string; file: string }[]; + }, + { + repository = 'f0rr0/oliphaunt', + assertCompletedPublication = createCompletedPublicationChecker({ repository }), + readJson = requestGithubRepositoryJson, + readPages = requestGithubPages, + proveAsset = requestReleaseAssetProof, + } = {}, +) { + if (repository !== 'f0rr0/oliphaunt' || !kinds.has(publication?.product)) + throw new Error('unsupported completed native archive repository/product'); + const completed = await assertCompletedPublication(publication); + if (!same(completed, publication)) throw new Error('completed native archive source differs'); + exactSource({ commit: completed.publicationSha, tree: completed.publicationTree }); + const catalog = loadPublicationCatalog('completed native archive'); + const product = catalog.products.find(({ id }) => id === completed.product)!; + const expected = rows([{ ...product, version: completed.version }]); + const release = await readJson(`repos/${repository}/releases/tags/${completed.tagName}`); + if ( + !Number.isSafeInteger(release.id) || + release.id <= 0 || + release.tag_name !== completed.tagName || + release.target_commitish !== completed.publicationSha || + release.draft !== false || + release.prerelease !== false + ) + throw new Error('published native release differs from completed source'); + const assets = await readPages(`repos/${repository}/releases/${release.id}/assets`); + const targets = new Set(); + const archives = []; + for (const { target, file } of files) { + if (targets.has(target)) throw new Error('duplicate completed native archive target'); + targets.add(target); + const matches = expected.filter((row) => row.target === target); + if (matches.length !== 1) + throw new Error('completed native archive has no canonical target contract'); + const artifact = matches[0]; + const matchingAssets = assets.filter((asset) => asset.name === artifact.name); + if (matchingAssets.length !== 1) + throw new Error('completed native archive public asset is missing/ambiguous'); + const asset = matchingAssets[0]; + if ( + !Number.isSafeInteger(asset.id) || + asset.id <= 0 || + !Number.isSafeInteger(asset.size) || + asset.size <= 0 + ) + throw new Error('completed native archive public asset identity is invalid'); + if ( + asset.state !== 'uploaded' || + asset.url !== `https://api.github.com/repos/${repository}/releases/assets/${asset.id}` + ) + throw new Error('completed native archive asset is not the canonical uploaded File'); + if (asset.digest != null && !/^sha256:[a-f0-9]{64}$/u.test(asset.digest)) + throw new Error('completed native archive API digest is invalid'); + const before = regularArchiveIdentity(file); + const downloaded = /^sha256:[a-f0-9]{64}$/u.test(asset.digest ?? '') + ? { bytes: asset.size, sha256: asset.digest.slice(7) } + : await proveAsset(asset.url, artifact.name, asset.size); + if ( + before.size !== asset.size || + before.size !== downloaded.bytes || + before.sha256 !== downloaded.sha256 + ) + throw new Error('completed native archive bytes differ from authenticated public asset'); + const members = memberIdentities(file); + if (!same(before, regularArchiveIdentity(file))) + throw new Error('completed native archive changed after read'); + archives.push({ + ...artifact, + assetId: asset.id, + releaseId: release.id, + size: before.size, + sha256: before.sha256, + members, + }); + } + if (!archives.length) throw new Error('completed native archive target coverage is empty'); + return { + scope: 'construction' as const, + origin: 'completed-published-archives' as const, + publication: completed, + archives, + unverified: [ + 'historical native producer inputs, configured actions and execution/cache provenance', + ], + }; +} + +/** Delivery differences alone remain diagnostic; qualification decides no release here. */ +export function compareCompletedNativeArchiveDelivery( + current: ReturnType, + origins: Awaited>[], +) { + return { + scope: 'construction' as const, + source: current.source, + currentArchives: current.products.flatMap(({ archives }) => archives), + releaseDecision: 'unverified' as const, + products: current.products.map((product) => { + const matches = origins.filter((origin) => origin.publication.product === product.product); + if (matches.length > 1) throw new Error('ambiguous completed native archive origin'); + const before = matches[0]?.archives; + const after = product.physicalDelivery?.deliveredPayloads; + if ( + !product.completeConfiguredArchiveInventory || + !before || + !after || + !same( + before.map(({ target }) => target).sort(), + after.map(({ configuration }) => configuration).sort(), + ) + ) + return { product: product.product, deliveryStatus: 'unknown' as const }; + const identical = after.every( + (root) => + !differentNativeDeliveredMembers( + root.outputs[0].members, + before.find(({ target }) => target === root.configuration)!.members, + ).length, + ); + return { + product: product.product, + deliveryStatus: identical ? ('identical' as const) : ('different' as const), + }; + }), + }; +} + +/** + * One pre-version comparison for the supported completed delivery bridges. + * Invoke before version updates or controller metadata sealing. Changed inputs + * and action definitions request checks only. A source-owned configured policy, + * reviewed producing origin and complete physical contract admit each decision. + * Complete repository resolution is separate from execution: held baselines may + * be reused only after their causal input and contract identity has been proven. + */ +export function compareNativePreVersionDelivery({ + source, + products, + archives, + sources, + completed, + affectedProducts, + observation, + seedConstructionBaseline, +}: { + source: Source; + products: string[]; + archives?: ReturnType; + sources?: Awaited>; + completed?: Awaited>; + affectedProducts?: string[]; + observation?: Awaited>; + seedConstructionBaseline?: NativeSeedConstructionBaseline; +}) { + exactSource(source); + if (seedConstructionBaseline) assertSeedConstructionBaseline(seedConstructionBaseline, source); + if (!Array.isArray(products) || new Set(products).size !== products.length) + throw new Error('native pre-version comparison requires unique explicit products'); + if ( + affectedProducts !== undefined && + (!Array.isArray(affectedProducts) || + new Set(affectedProducts).size !== affectedProducts.length || + affectedProducts.some((product) => !products.includes(product))) + ) + throw new Error('native affected build selection differs from the explicit product inventory'); + const catalog = loadPublicationCatalog('native pre-version delivery'); + const selected = catalog.products.filter((product) => products.includes(product.id)); + if (selected.length !== products.length) + throw new Error('native pre-version comparison contains an unknown product'); + for (const comparison of [archives, sources, completed]) { + if (!comparison) continue; + if (comparison.scope !== 'construction' || !same(comparison.source, source)) + throw new Error('native pre-version comparison differs from its captured source'); + if ( + new Set(comparison.products.map(({ product }) => product)).size !== comparison.products.length + ) + throw new Error('ambiguous native pre-version product comparison'); + if (comparison.products.some(({ product }) => !products.includes(product))) + throw new Error('native pre-version comparison exceeds explicit product inventory'); + } + const qualificationUnknowns: string[] = []; + let producerAssured = false; + if (observation) { + if (!observation.authenticated.length || !observation.coverage.completeProductInventory) + throw new Error('native pre-version observation has incomplete frozen inventory'); + if (!same(observation.products.map(({ product }) => product.id).sort(), [...products].sort())) + throw new Error('native pre-version observation differs from product inventory'); + for (const build of observation.authenticated) { + if ( + !same(build.evidence.source, source) || + !same(build.qualification.source, source) || + build.qualification.testQualification !== 'passed' || + !build.qualification.requiredTests.length + ) + throw new Error('native pre-version observation differs from source/configured tests'); + qualificationUnknowns.push(...build.qualification.unverified); + if (build.producerAssurance) + validateReviewedNativeProducerAssurance(build.producerAssurance, { + source, + github: build.origin.github, + artifact: build.origin.artifact, + evidenceDigest: build.origin.evidenceDigest, + requiredTests: build.qualification.requiredTests, + }); + } + producerAssured = observation.authenticated.every((build) => build.producerAssurance); + } + if (!producerAssured) + qualificationUnknowns.push('immutable input lifetime and loaded-analysis provenance'); + const results = selected.map((product) => { + const sourceDelivery = sources?.products.find((row) => row.product === product.id); + const archiveDelivery = archives?.products.find((row) => row.product === product.id); + const completedDelivery = completed?.products.find((row) => row.product === product.id); + let deliveryStatus = 'unknown' as 'unknown' | 'identical' | 'different'; + let reason = 'completed-delivery-origin-or-contract-missing'; + if (completedDelivery) { + deliveryStatus = completedDelivery.deliveryStatus; + reason = + deliveryStatus === 'unknown' + ? completedDelivery.unknowns?.join(',') || completedDelivery.reason || reason + : 'completed-public-members-compared'; + if (observation) { + const observed = observation.products.find(({ product: row }) => row.id === product.id); + const ordered = (records) => [...records].sort((a, b) => a.id.localeCompare(b.id)); + // Observation adds authenticated output locations to the same original + // envelope. Compare every envelope field; those derived bindings were + // already checked against the producing packet by the observer. + const envelope = (records) => records.map(({ qualifiedFiles: _bindings, ...row }) => row); + if ( + !observed || + observed.product.version !== product.version || + !same(ordered(envelope(observed.carriers)), ordered(completedDelivery.carriers)) || + !same( + ordered(envelope(observed.productArtifacts)), + ordered(completedDelivery.productArtifacts), + ) + ) + throw new Error('completed delivery differs from qualified physical inventory'); + } + } else if (sourceDelivery && sourceDelivery.deliveryStatus !== 'unknown') { + deliveryStatus = sourceDelivery.deliveryStatus as 'identical' | 'different'; + reason = 'source-envelope-members-compared'; + if (observation) { + const observed = observation.products.find(({ product: row }) => row.id === product.id); + if ( + !observed || + observed.product.version !== product.version || + observed.productArtifacts.length + ) + throw new Error('source delivery observation has a different identity or output class'); + for (const carrier of sourceDelivery.carriers ?? []) { + const actual = observed.carriers.filter(({ id }) => id === carrier.carrier); + if (actual.length !== 1 || !same(actual[0].artifacts, [carrier.currentArtifact])) + throw new Error('source comparison differs from qualified physical envelope'); + } + if (observed.carriers.length !== sourceDelivery.carriers?.length) + throw new Error('source comparison has incomplete qualified carrier inventory'); + } + } else if (archiveDelivery) { + // These bridges currently map the two native GitHub archive families. + // Their registry facades/parts and contrib carriers are separate public + // contracts, so an identical archive must not certify the whole product. + reason = 'remaining-public-carrier-contracts-unmapped'; + if (observation) { + const observed = observation.products.find(({ product: row }) => row.id === product.id); + if (!observed || observed.product.version !== product.version) + throw new Error('archive delivery observation has a different identity'); + for (const archive of archives?.currentArchives.filter( + (row) => row.product === product.id, + ) ?? []) { + const actual = observed.productArtifacts.filter(({ id }) => id === archive.id); + if ( + actual.length !== 1 || + actual[0].name !== archive.name || + actual[0].kind !== archive.kind || + actual[0].target !== archive.target || + actual[0].sha256 !== archive.sha256 || + actual[0].size !== archive.size + ) + throw new Error('archive comparison differs from qualified physical envelope'); + } + } + } else if (sourceDelivery) reason = sourceDelivery.reason ?? reason; + const relevantBuilds = + observation?.authenticated.filter((build) => + (build.qualification.cohorts ?? []).some((cohort) => + cohort.roots.some((root) => root.package.product === product.id), + ), + ) ?? []; + const relevantCohorts = relevantBuilds.flatMap((build) => + build.qualification.cohorts.filter((cohort) => + cohort.roots.some((root) => root.package.product === product.id), + ), + ); + const policiesBound = + relevantCohorts.length > 0 && + relevantCohorts.every((cohort) => + nativeShippingRootsHaveQualification( + cohort.qualificationPolicy, + cohort.roots.filter((root) => root.package.product === product.id), + ), + ); + const productUnknowns = relevantBuilds + .flatMap((build) => build.qualification.unverified) + .filter( + (unknown) => + unknown !== 'complete canonical product qualification and completed-baseline admission' && + !( + policiesBound && + unknown === + 'source-owned mandatory qualification policy bound to every configured shipping root' + ), + ); + const qualified = + policiesBound && + relevantBuilds.every((build) => build.producerAssurance) && + !productUnknowns.length; + // Fresh initdb identity needs causal freeze/reuse evidence, even after its tests pass. + const seedRows = expectedProductArtifactRows([product]).filter((artifact) => + ['native-seeds', 'wasix-seeds'].includes(artifact.kind), + ); + const seedComparisons = + completedDelivery?.comparisons?.filter((comparison) => + ['native-seeds', 'wasix-seeds'].includes(comparison.kind), + ) ?? []; + const unclassifiedSeedChange = + seedRows.length > 0 && + deliveryStatus === 'different' && + (!same( + seedRows.map(({ id }) => id).sort(), + seedComparisons.map((comparison) => comparison.currentId ?? comparison.id).sort(), + ) || + seedComparisons.some((comparison) => { + const row = seedRows.find((row) => row.id === (comparison.currentId ?? comparison.id)); + if (!comparison.differentMembers.length || !row?.name.endsWith('.tar.zst')) return false; + if (!seedConstructionBaseline || !observation || !completedDelivery?.origin) return true; + try { + return !seedArchiveHasChangedDeclaredContents({ + declaration: seedConstructionBaseline, + source, + publication: completedDelivery.origin, + observation, + artifactId: comparison.currentId ?? comparison.id, + }); + } catch { + return true; // Missing or conflicting causal/public File joins remain unclassified. + } + })); + if (unclassifiedSeedChange) reason = 'seed-lifetime-or-reuse-unverified'; + const necessaryDelivery = + !unclassifiedSeedChange && qualified && deliveryStatus !== 'unknown' + ? deliveryStatus === 'different' + ? ('needed' as const) + : ('not-needed' as const) + : ('unknown' as const); + return { + product: product.id, + affectedBuild: + affectedProducts === undefined + ? ('unknown' as const) + : affectedProducts.includes(product.id) + ? ('required' as const) + : ('not-required' as const), + deliveryStatus, + ...(archiveDelivery ? { archiveDeliveryStatus: archiveDelivery.deliveryStatus } : {}), + configuredTests: qualified + ? ('qualified' as const) + : observation + ? ('observed-passed' as const) + : ('unverified' as const), + necessaryDelivery, + reason, + }; + }); + const completeRepositoryInventory = same( + [...products].sort(), + catalog.products.map(({ id }) => id).sort(), + ); + const completeDecisions = results.every((product) => product.necessaryDelivery !== 'unknown'); + if (!completeDecisions) + qualificationUnknowns.push( + 'admitted complete product-specific qualification and delivery contract', + ); + if (!completeRepositoryInventory) + qualificationUnknowns.push('complete repository product decision inventory'); + const unverified = [...new Set(qualificationUnknowns)].filter( + (unknown) => + !( + completeDecisions && + unknown === 'complete canonical product qualification and completed-baseline admission' + ), + ); + const releaseDecision = + completeRepositoryInventory && completeDecisions && !unverified.length + ? ('qualified' as const) + : ('unverified' as const); + return { + scope: 'construction' as const, + source: structuredClone(source), + releaseDecision, + completeRepositoryInventory, + ...(releaseDecision === 'qualified' + ? { + selectedProducts: results + .filter((product) => product.necessaryDelivery === 'needed') + .map(({ product }) => product) + .sort(), + } + : {}), + products: results, + unverified, + }; +} diff --git a/tools/release/native-publication-delivery.test.mts b/tools/release/native-publication-delivery.test.mts new file mode 100644 index 000000000..8f2c334f9 --- /dev/null +++ b/tools/release/native-publication-delivery.test.mts @@ -0,0 +1,959 @@ +import { expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + copyFileSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + statSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { packageEnvelope } from '../../build_defs/native/carriers/envelopes.mts'; +import { + requiredRuntimeMemberPaths, + requiredToolsMemberPaths, +} from '../../src/native/runtime/tools/native-runtime-payload.mts'; +import { archiveDirectory } from '../packaging/archive-directory.mts'; +import { + extractPortableArchiveTree, + readPortableArchiveEntries, +} from '../packaging/portable-archive.mts'; +import { tarArchive } from '../packaging/testdata/tar-fixture.mts'; +import type { CompletedPublication } from './completed-release-publication.mts'; +import { + bindNativeArchiveDelivery, + captureCompletedNativeArchiveDelivery, + compareCompletedNativeArchiveDelivery, + compareNativePreVersionDelivery, + differentNativeDeliveredMembers, +} from './native-publication-delivery.mts'; +import { + captureNativePreEnvelopePayloads, + type NativePayloadCohort, +} from './native-publication-payloads.mts'; +import { loadPublicationCatalog } from './publication-catalog.mts'; +import { expectedProductArtifactRows } from './publication-lock.mts'; +import { allArtifactTargets } from './release-artifact-targets.mts'; + +const source = { commit: '1'.repeat(40), tree: '2'.repeat(40) }; +const hash = (file: string) => createHash('sha256').update(readFileSync(file)).digest('hex'); +const ids = ['liboliphaunt-native', 'postgres-tools-native']; + +test('canonical member equality preserves names, modes and every delivered identity field', () => { + const file = { path: 'public.bin', mode: 0o644, type: 'file', size: 1, sha256: 'a'.repeat(64) }; + const directory = { path: '', mode: 0o755, type: 'directory' }; + expect(differentNativeDeliveredMembers([directory, file], [file, directory])).toEqual([]); + for (const updated of [ + { ...file, path: 'renamed.bin' }, + { ...file, mode: 0o755 }, + { ...file, sha256: 'b'.repeat(64) }, + { ...file, size: 2 }, + { ...file, type: 'directory' }, + ]) + expect(differentNativeDeliveredMembers([file], [updated]).length).toBeGreaterThan(0); + expect(() => differentNativeDeliveredMembers([file, file], [])).toThrow(/duplicate/); + expect(() => differentNativeDeliveredMembers([{ ...file, path: '../outside' }], [])).toThrow( + /unsafe/, + ); +}); + +// These origin shapes exercise the decision seam. Authentication, physical +// archive readers and owner-policy capture have their separate real fixtures. +function decisionFixture( + ids = loadPublicationCatalog('native decision fixture').products.map(({ id }) => id), +) { + const products = loadPublicationCatalog('native decision fixture', { products: ids }).products; + const github = { + repository: 'f0rr0/oliphaunt', + workflow: 'Native Bazel qualification', + workflowPath: '.github/workflows/bazel.yml', + runId: 7, + runAttempt: 1, + job: 'Linux runtime (x86_64)', + }; + const artifact = { + id: 9, + name: 'native-build-evidence-x86_64', + digest: `sha256:${'d'.repeat(64)}`, + size: 1, + }; + const evidenceDigest = `sha256:${'e'.repeat(64)}`; + const configuration = 'c'.repeat(64); + const requiredTests = [ + { label: '//fixture:installed_test', configuration, invocationId: 'fixture-qualified' }, + ]; + const roots = products.map((product) => ({ + label: `//fixture/${product.id}:shipping`, + configuration, + package: { product: product.id, version: product.version }, + })); + const qualificationPolicy = { + owner: '//fixture:shipping_export', + configuration, + roots: roots.map(({ label }) => label), + requiredTests: requiredTests.map(({ invocationId: _, ...test }) => test), + }; + const producerAssurance = { + scope: 'reviewed-producer-assurance', + reviewedSource: source, + event: 'push', + ref: 'refs/heads/main', + github, + artifact, + evidenceDigest, + shippingAnalysis: 'bound', + testQualification: 'passed', + requiredTests, + acceptedExecutionAssumptions: [ + 'producer inputs remained immutable through capture in the reviewed isolated job', + 'the reviewed coordinator retained the native after-build dump from its producer invocation', + ], + }; + const observation: any = { + coverage: { completeProductInventory: true }, + products: products.map((product) => ({ product, carriers: [], productArtifacts: [] })), + authenticated: [ + { + origin: { github, artifact, evidenceDigest }, + evidence: { source }, + producerAssurance, + qualification: { + source, + shippingAnalysis: 'bound', + testQualification: 'passed', + requiredTests, + cohorts: [{ roots, qualificationPolicy }], + unverified: ['complete canonical product qualification and completed-baseline admission'], + }, + }, + ], + }; + const completed: any = { + scope: 'construction', + source, + products: products.map(({ id }) => ({ + product: id, + deliveryStatus: 'identical', + carriers: [], + productArtifacts: [], + })), + }; + return { source, products: ids, observation, completed }; +} + +test('complete catalog resolves zero, few and many changes independently of checks while seed reuse remains unverified', () => { + const input = decisionFixture(); + const seeds = new Set( + loadPublicationCatalog('native seed decision fixture') + .products.filter((product) => + expectedProductArtifactRows([product]).some((row) => + ['native-seeds', 'wasix-seeds'].includes(row.kind), + ), + ) + .map(({ id }) => id), + ); + expect(seeds.size).toBeGreaterThan(0); + const initial = compareNativePreVersionDelivery(input); + expect(initial.completeRepositoryInventory).toBe(true); + expect(initial.releaseDecision).toBe('qualified'); + expect(initial.selectedProducts).toEqual([]); + let seed = 0x294b4e1; + for (let scenario = 0; scenario < 24; scenario++) { + const expected = []; + const affected = []; + for (const [index, product] of input.completed.products.entries()) { + seed = (Math.imul(seed, 1664525) + 1013904223) >>> 0; + const changed = + scenario === 0 + ? false + : scenario === 1 + ? index === 0 + : scenario === 2 + ? true + : Boolean(seed & 1); + product.deliveryStatus = changed ? 'different' : 'identical'; + if (changed && !seeds.has(product.product)) expected.push(product.product); + if (seed & 2) affected.push(product.product); + } + const result = compareNativePreVersionDelivery({ ...input, affectedProducts: affected }); + const seedChanged = input.completed.products.some( + (product) => seeds.has(product.product) && product.deliveryStatus === 'different', + ); + expect(result.releaseDecision).toBe(seedChanged ? 'unverified' : 'qualified'); + expect(result.selectedProducts).toEqual(seedChanged ? undefined : expected.sort()); + for (const product of result.products) { + expect(product.affectedBuild).toBe( + affected.includes(product.product) ? 'required' : 'not-required', + ); + expect(product.necessaryDelivery).toBe( + seeds.has(product.product) && + input.completed.products.find((row) => row.product === product.product).deliveryStatus === + 'different' + ? 'unknown' + : expected.includes(product.product) + ? 'needed' + : 'not-needed', + ); + } + } +}); + +test('unchanged real catalog seeds need no release, while fresh control or WAL entropy cannot justify one', () => { + const catalog = loadPublicationCatalog('native real seed negative'); + const product = catalog.products.find((product) => + expectedProductArtifactRows([product]).some((row) => row.kind === 'native-seeds'), + )!; + const input = decisionFixture([product.id]); + const rows = expectedProductArtifactRows([product]) + .filter((row) => ['native-seeds', 'wasix-seeds'].includes(row.kind)) + .map((row) => ({ ...row, sha256: 'f'.repeat(64), size: 1, path: `target/${row.name}` })); + expect(rows.some((row) => row.kind === 'native-seeds')).toBe(true); + expect(rows.some((row) => row.kind === 'wasix-seeds')).toBe(true); + input.observation.products[0].productArtifacts = rows; + input.completed.products[0].productArtifacts = rows; + expect(compareNativePreVersionDelivery(input).products[0].necessaryDelivery).toBe('not-needed'); + input.completed.products[0].deliveryStatus = 'different'; + input.completed.products[0].comparisons = rows.map((row) => ({ + id: row.id, + currentId: row.id, + kind: row.kind, + differentMembers: [], + })); + const nonSeed = catalog.carriers.find( + (carrier) => carrier.product === product.id && carrier.ecosystem === 'npm', + )!; + input.completed.products[0].comparisons.push({ + id: nonSeed.id, + kind: 'npm', + differentMembers: ['THIRD_PARTY_NOTICES.md'], + }); + expect(compareNativePreVersionDelivery(input).products[0].necessaryDelivery).toBe('needed'); + for (const differentMembers of [ + ['pgdata/global/pg_control'], + ['pgdata/pg_wal/000000010000000000000001'], + ]) { + input.completed.products[0].deliveryStatus = 'different'; + input.completed.products[0].comparisons = rows.map((row) => ({ + id: row.id, + kind: row.kind, + differentMembers, + })); + const result = compareNativePreVersionDelivery(input); + expect(result.products[0].configuredTests).toBe('qualified'); + expect(result.products[0].deliveryStatus).toBe('different'); + expect(result.products[0].necessaryDelivery).toBe('unknown'); + expect(result.products[0].reason).toBe('seed-lifetime-or-reuse-unverified'); + expect(result.releaseDecision).toBe('unverified'); + } +}); + +test('focused qualification can resolve a product without claiming a complete repository release plan', () => { + const input = decisionFixture(['oliphaunt-query-ts']); + input.completed.products[0].deliveryStatus = 'different'; + const result = compareNativePreVersionDelivery(input); + expect(result.products[0].necessaryDelivery).toBe('needed'); + expect(result.completeRepositoryInventory).toBe(false); + expect(result.releaseDecision).toBe('unverified'); + expect(result.selectedProducts).toBeUndefined(); + expect(result.unverified).toContain('complete repository product decision inventory'); +}); + +test('qualified decision snapshots its source and rejects foreign or duplicate affected products', () => { + const input = decisionFixture(); + input.source = { ...source }; + const result = compareNativePreVersionDelivery(input); + input.source.commit = 'f'.repeat(40); + expect(result.source).toEqual(source); + for (const affectedProducts of [['foreign'], [input.products[0], input.products[0]]]) + expect(() => + compareNativePreVersionDelivery({ ...decisionFixture(), affectedProducts }), + ).toThrow(/affected build selection/); +}); + +test('an unrelated unknown producer does not erase a complete product decision', () => { + const input = decisionFixture(['oliphaunt-query-ts', 'oliphaunt-query']); + const build = input.observation.authenticated[0]; + const other = structuredClone(build); + build.qualification.cohorts[0].roots = build.qualification.cohorts[0].roots.filter( + (root) => root.package.product === 'oliphaunt-query-ts', + ); + other.qualification.cohorts[0].roots = other.qualification.cohorts[0].roots.filter( + (root) => root.package.product === 'oliphaunt-query', + ); + delete other.producerAssurance; + other.qualification.unverified.push('unreviewed separate producer'); + input.observation.authenticated.push(other); + const result = compareNativePreVersionDelivery(input); + expect( + result.products.find(({ product }) => product === 'oliphaunt-query-ts')?.necessaryDelivery, + ).toBe('not-needed'); + expect( + result.products.find(({ product }) => product === 'oliphaunt-query')?.necessaryDelivery, + ).toBe('unknown'); + expect(result.releaseDecision).toBe('unverified'); +}); + +for (const fault of [ + 'observed-only', + 'missing-policy', + 'empty-policy', + 'unknown-delivery', + 'qualification-unknown', + 'archive-only', +] as const) + test(`complete native delivery decisions remain unverified for ${fault}`, () => { + const input = decisionFixture(); + const build = input.observation.authenticated[0]; + if (fault === 'observed-only') delete build.producerAssurance; + else if (fault === 'missing-policy') delete build.qualification.cohorts[0].qualificationPolicy; + else if (fault === 'empty-policy') + build.qualification.cohorts[0].qualificationPolicy.requiredTests = []; + else if (fault === 'unknown-delivery') input.completed.products[0].deliveryStatus = 'unknown'; + else if (fault === 'qualification-unknown') + build.qualification.unverified.push('unmapped producer qualification'); + const result = compareNativePreVersionDelivery({ + ...input, + ...(fault === 'archive-only' + ? { + completed: undefined, + archives: { + scope: 'construction', + source, + releaseDecision: 'unverified', + currentArchives: [], + products: input.products.map((product) => ({ product, deliveryStatus: 'identical' })), + } as any, + } + : {}), + }); + expect(result.releaseDecision).toBe('unverified'); + expect(result.selectedProducts).toBeUndefined(); + expect(result.products.some(({ necessaryDelivery }) => necessaryDelivery === 'unknown')).toBe( + true, + ); + }); + +test('reviewed assurance cannot be transplanted from another source, artifact or workflow role', () => { + for (const change of [ + (build) => { + build.producerAssurance.reviewedSource = { ...source, tree: 'f'.repeat(40) }; + }, + (build) => { + build.producerAssurance.evidenceDigest = `sha256:${'f'.repeat(64)}`; + }, + (build) => { + build.producerAssurance.github = { ...build.origin.github, job: 'Unreviewed producer' }; + }, + ]) { + const input = decisionFixture(); + change(input.observation.authenticated[0]); + expect(() => compareNativePreVersionDelivery(input)).toThrow(); + } +}); + +async function fixture(run) { + const executionRoot = mkdtempSync(path.join(os.tmpdir(), 'native-delivered-members-')); + const catalog = loadPublicationCatalog('native final-member fixture', { products: ids }); + const artifactRows = expectedProductArtifactRows(catalog.products).filter((row) => + ['native-runtime', 'native-tools'].includes(row.kind), + ); + const roots = []; + const files = []; + for (const row of artifactRows) { + const output = `bazel-out/fixture/bin/${row.product}/${row.target}/public_payload`; + const directory = path.join(executionRoot, output); + const executable = + row.kind === 'native-runtime' + ? requiredRuntimeMemberPaths(row.target, 'runtime/bin') + : requiredToolsMemberPaths(row.target, 'runtime/bin'); + for (const name of [...executable, 'lib/public-interface.bin', 'THIRD_PARTY_NOTICES.md']) { + const file = path.join(directory, name); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, `${row.product} ${name} exact bytes`); + // Physical Bazel file permissions deliberately differ from public modes. + chmodSync(file, 0o555); + } + const artifact = allArtifactTargets({ product: row.product, surface: 'github-release' }).find( + (artifact) => artifact.kind === row.kind && artifact.target === row.target, + )!; + const archiveOutput = `bazel-out/fixture/bin/${row.product}/${row.target}/release-assets/${row.name}`; + const archive = path.join(executionRoot, archiveOutput); + const pack = () => + packageEnvelope({ + phase: 'github', + artifact, + version: row.version, + carriers: [], + payload: directory, + sources: {}, + legal: {}, + output: archive, + }); + await pack(); + roots.push( + { + label: `//fixture/${row.product}:payload_${row.target}`, + package: { + product: row.product, + version: row.version, + ecosystem: 'internal', + name: `${row.product}-public-payload`, + configuration: row.target, + role: 'construction', + outputs: [{ path: output, owner: `//fixture/${row.product}:payload` }], + }, + }, + { + label: `//fixture/${row.product}:github_${row.target}`, + package: { + product: row.product, + version: row.version, + ecosystem: 'github', + name: row.name, + configuration: row.target, + role: row.role, + outputs: [{ path: archiveOutput, owner: `//fixture/${row.product}:archive` }], + }, + }, + ); + files.push({ row, directory, archive, pack }); + } + const cohort: NativePayloadCohort = { + source, + executionRoot, + roots, + get aquery() { + throw new Error('physical archive binding must not infer execution'); + }, + }; + const capture = () => + captureNativePreEnvelopePayloads([cohort], { source, products: catalog.products }); + const bind = () => bindNativeArchiveDelivery(capture().payloads, [cohort], artifactRows); + try { + await run({ cohort, catalog, files, capture, bind, executionRoot, artifactRows }); + } finally { + rmSync(executionRoot, { recursive: true, force: true }); + } +} + +function completedFixture(product, files) { + // Synthetic transport responses test the genuine default API contract. They + // do not authenticate these fixture bytes as a real published release. + const publication: CompletedPublication = { + product: product.id, + version: product.version, + tagName: `${product.id}-v${product.version}`, + publicationSha: source.commit, + publicationTree: source.tree, + releaseSha: '3'.repeat(40), + }; + const release = { + id: 123, + tag_name: publication.tagName, + target_commitish: source.commit, + draft: false, + prerelease: false, + }; + const assets = files.map(({ row, archive }, index) => ({ + id: index + 1, + name: row.name, + size: readFileSync(archive).length, + digest: `sha256:${hash(archive)}`, + state: 'uploaded', + url: `https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/${index + 1}`, + })); + const requests = []; + const options = { + assertCompletedPublication: async (requested) => { + requests.push(['completion', requested]); + return publication; + }, + readJson: async (endpoint) => { + expect(endpoint).toBe(`repos/f0rr0/oliphaunt/releases/tags/${publication.tagName}`); + return release; + }, + readPages: async (endpoint) => { + expect(endpoint).toBe('repos/f0rr0/oliphaunt/releases/123/assets'); + return assets; + }, + proveAsset: async () => { + throw new Error('API asset digest should bind fixture bytes'); + }, + }; + const input = { + publication, + files: files.map(({ row, archive }) => ({ target: row.target, file: archive })), + }; + return { input, options, publication, release, assets, requests }; +} + +test('actual GitHub envelope writer binds both native family member/mode contracts without granting qualification', async () => { + await fixture(({ bind, capture }) => { + const current = bind(); + expect(current.scope).toBe('construction'); + expect( + current.products.every( + ({ completeConfiguredArchiveInventory }) => completeConfiguredArchiveInventory, + ), + ).toBe(true); + expect(current.products.every(({ physicalDelivery }) => physicalDelivery)).toBe(true); + expect(current.unverified).toContain('native qualification workflow proof'); + const raw = capture().payloads.products[0].roots[0].outputs[0].members; + expect(raw.filter(({ type }) => type === 'file').every(({ mode }) => mode === 0o555)).toBe( + true, + ); + const delivered = current.products[0].physicalDelivery!.deliveredPayloads[0].outputs[0].members; + expect(delivered.find(({ path }) => path === 'THIRD_PARTY_NOTICES.md')!.mode).toBe(0o644); + expect(delivered.find(({ path }) => path.startsWith('runtime/bin/'))!.mode).toBe(0o755); + }); +}); + +test('completed public member origin compares exact delivery while release necessity remains unverified', async () => { + await fixture(async ({ bind, catalog, files }) => { + const origins = []; + for (const product of catalog.products) { + const completed = completedFixture( + product, + files.filter(({ row }) => row.product === product.id), + ); + origins.push(await captureCompletedNativeArchiveDelivery(completed.input, completed.options)); + expect(completed.requests).toEqual([['completion', completed.publication]]); + } + const before = compareCompletedNativeArchiveDelivery(bind(), origins); + expect(before.releaseDecision).toBe('unverified'); + expect(before.products.map(({ deliveryStatus }) => deliveryStatus)).toEqual([ + 'identical', + 'identical', + ]); + const changed = files.find(({ row }) => row.product === 'postgres-tools-native')!; + chmodSync(path.join(changed.directory, 'THIRD_PARTY_NOTICES.md'), 0o644); + writeFileSync( + path.join(changed.directory, 'THIRD_PARTY_NOTICES.md'), + 'actual changed public legal bytes', + ); + await changed.pack(); + expect(compareCompletedNativeArchiveDelivery(bind(), origins).products).toEqual([ + { product: 'liboliphaunt-native', deliveryStatus: 'identical' }, + { product: 'postgres-tools-native', deliveryStatus: 'different' }, + ]); + expect( + compareCompletedNativeArchiveDelivery(bind(), []).products.every( + ({ deliveryStatus }) => deliveryStatus === 'unknown', + ), + ).toBe(true); + }); +}); + +test('archive wrapper root changes preserve the actual retained installed-tree contract', async () => { + await fixture(async ({ bind, catalog, files, executionRoot }) => { + const product = catalog.products[0]; + const published = completedFixture( + product, + files.filter(({ row }) => row.product === product.id), + ); + const origin = await captureCompletedNativeArchiveDelivery(published.input, published.options); + const file = files.find( + ({ row }) => row.product === product.id && row.name.endsWith('.tar.gz'), + ); + if (!file) throw new Error('fixture has no native TAR archive'); + const originalHash = hash(file.archive); + const inner = [...readPortableArchiveEntries(file.archive).values()].map((entry) => ({ + name: entry.name + (entry.isDirectory ? '/' : ''), + type: entry.isDirectory ? '5' : '0', + mode: entry.mode, + data: entry.isFile ? entry.data() : Buffer.alloc(0), + })); + for (const [index, root] of [[{ name: './', type: '5', mode: 0o700 }], []].entries()) { + writeFileSync(file.archive, tarArchive([...root, ...inner])); + expect(hash(file.archive)).not.toBe(originalHash); + const destination = path.join(executionRoot, `installed-root-${index}`); + extractPortableArchiveTree(file.archive, destination); + expect(statSync(destination).mode & 0o777).toBe(0o755); + const current = bind(); + expect( + current.products[0].archives.find(({ target }) => target === file.row.target)?.sha256, + ).toBe(hash(file.archive)); + expect( + compareCompletedNativeArchiveDelivery(current, [origin]).products[0].deliveryStatus, + ).toBe('identical'); + } + }); +}); + +test('observed configured tests cannot bind a substituted archive envelope or source', async () => { + await fixture(async ({ bind, catalog, files }) => { + const origins = []; + for (const product of catalog.products) { + const published = completedFixture( + product, + files.filter(({ row }) => row.product === product.id), + ); + origins.push(await captureCompletedNativeArchiveDelivery(published.input, published.options)); + } + const archives = compareCompletedNativeArchiveDelivery(bind(), origins); + // Transport-shaped fixtures exercise only this comparison binding; they + // cannot authenticate a job, admit its contract or produce a release verdict. + const observation: any = { + coverage: { completeProductInventory: true }, + authenticated: [ + { + evidence: { source }, + qualification: { + source, + testQualification: 'passed', + requiredTests: [{ label: '//fixture:test', configuration: 'a'.repeat(64) }], + unverified: ['fixture origin is unverified'], + }, + }, + ], + products: catalog.products.map((product) => ({ + product, + carriers: [], + productArtifacts: archives.currentArchives.filter((row) => row.product === product.id), + })), + }; + expect( + compareNativePreVersionDelivery({ + source, + products: ids, + archives, + observation, + }).products.every(({ necessaryDelivery }) => necessaryDelivery === 'unknown'), + ).toBe(true); + observation.products[0].productArtifacts[0] = { + ...observation.products[0].productArtifacts[0], + sha256: 'f'.repeat(64), + }; + expect(() => + compareNativePreVersionDelivery({ source, products: ids, archives, observation }), + ).toThrow(/qualified physical envelope/); + observation.authenticated[0].evidence.source = { ...source, commit: 'f'.repeat(40) }; + expect(() => + compareNativePreVersionDelivery({ source, products: ids, archives, observation }), + ).toThrow(/source\/configured tests/); + }); +}); + +test('seeded physical scenarios separate affected checks from zero, few and many archive changes', async () => { + await fixture(async ({ bind, catalog, files, executionRoot }) => { + const selected = catalog.products.map((product) => { + const file = files.find(({ row }) => row.product === product.id); + if (!file) throw new Error('fixture product has no public archive'); + return file; + }); + for (const file of selected) { + writeFileSync( + path.join(file.directory, 'consumed-compatibility.json'), + '{"nativeRuntime":"=0.3.2"}\n', + ); + await file.pack(); + } + const origins = []; + for (const product of catalog.products) { + const published = completedFixture( + product, + files.filter(({ row }) => row.product === product.id), + ); + origins.push(await captureCompletedNativeArchiveDelivery(published.input, published.options)); + } + let seed = 0x29493c80; + const random = () => { + seed = (Math.imul(seed, 1664525) + 1013904223) >>> 0; + return seed; + }; + const witnessed = new Set(); + for (let scenario = 0; scenario < 24; scenario++) { + const expected = new Map(); + const affected = []; + for (const [index, file] of selected.entries()) { + const variant = scenario < 8 ? (scenario + index) % 8 : random() % 8; + witnessed.add(variant); + if (random() & 1) affected.push(file.row.product); + const publicFile = path.join(file.directory, 'lib/public-interface.bin'); + const renamed = path.join(file.directory, 'lib/renamed-interface.bin'); + rmSync(renamed, { force: true }); + rmSync(publicFile, { force: true }); + writeFileSync(publicFile, `${file.row.product} lib/public-interface.bin exact bytes`); + chmodSync(path.join(file.directory, 'THIRD_PARTY_NOTICES.md'), 0o644); + writeFileSync( + path.join(file.directory, 'THIRD_PARTY_NOTICES.md'), + `${file.row.product} THIRD_PARTY_NOTICES.md exact bytes`, + ); + writeFileSync( + path.join(file.directory, 'consumed-compatibility.json'), + '{"nativeRuntime":"=0.3.2"}\n', + ); + if (variant === 1 || variant === 2) { + // Changed compiler source/action helper or controller stamp can request + // checks while the actual existing envelope writer delivers equal bytes. + writeFileSync( + path.join(executionRoot, 'changed-input.txt'), + `source/helper change ${random()}\n`, + ); + writeFileSync( + path.join(executionRoot, 'controller-version.json'), + `{"version":"${scenario}.0.0"}\n`, + ); + if (!affected.includes(file.row.product)) affected.push(file.row.product); + } else if (variant === 3) { + writeFileSync( + path.join(file.directory, 'THIRD_PARTY_NOTICES.md'), + 'actual changed legal bytes', + ); + } else if (variant === 4) { + writeFileSync(publicFile, 'actual compiled public version/interface changed'); + } else if (variant === 5) { + writeFileSync(renamed, readFileSync(publicFile)); + rmSync(publicFile); + } else if (variant === 7) { + writeFileSync( + path.join(file.directory, 'consumed-compatibility.json'), + '{"nativeRuntime":"=0.3.3"}\n', + ); + } + if (variant !== 5) chmodSync(publicFile, variant === 6 ? 0o444 : 0o555); + await file.pack(); + expected.set(file.row.product, [3, 4, 5, 7].includes(variant) ? 'different' : 'identical'); + } + const archives = compareCompletedNativeArchiveDelivery(bind(), origins); + expect(archives.products.map((product) => [product.product, product.deliveryStatus])).toEqual( + catalog.products.map((product) => [product.id, expected.get(product.id)]), + ); + const result = compareNativePreVersionDelivery({ + source, + products: ids, + archives, + affectedProducts: affected, + }); + expect(result.releaseDecision).toBe('unverified'); + for (const product of result.products) { + expect(product.affectedBuild).toBe( + affected.includes(product.product) ? 'required' : 'not-required', + ); + expect(product.archiveDeliveryStatus).toBe(expected.get(product.product)); + // Registry parts/facades/contrib and mandatory qualification are not + // proved by the complete GitHub archive family, even when bytes match. + expect(product.deliveryStatus).toBe('unknown'); + expect(product.necessaryDelivery).toBe('unknown'); + } + } + expect([...witnessed].sort()).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); + }); +}); + +test('pre-version comparison fails closed for absent seed mapping, origin, inventory and source substitution', () => { + const products = ['oliphaunt-query', 'database-resources']; + const missing = compareNativePreVersionDelivery({ source, products, affectedProducts: [] }); + expect( + missing.products.every( + (product) => product.deliveryStatus === 'unknown' && product.necessaryDelivery === 'unknown', + ), + ).toBe(true); + expect(missing.products.every((product) => product.affectedBuild === 'not-required')).toBe(true); + expect(() => + compareNativePreVersionDelivery({ source, products: [products[0], products[0]] }), + ).toThrow(/unique/); + expect(() => + compareNativePreVersionDelivery({ + source, + products: [products[0]], + archives: { + scope: 'construction', + source: { ...source, tree: 'f'.repeat(40) }, + currentArchives: [], + releaseDecision: 'unverified', + products: [], + }, + }), + ).toThrow(/captured source/); + expect(() => + compareNativePreVersionDelivery({ + source, + products: [products[0]], + archives: { + scope: 'construction', + source, + currentArchives: [], + releaseDecision: 'unverified', + products: [{ product: 'database-resources', deliveryStatus: 'identical' }], + }, + }), + ).toThrow(/explicit product inventory/); + expect(() => + compareNativePreVersionDelivery({ + source, + products, + observation: { authenticated: [], coverage: { completeProductInventory: false } } as any, + }), + ).toThrow(/incomplete frozen inventory/); +}); + +test('missing root/final archive or configured coverage remains unknown; substitutions fail', async () => { + await fixture(({ cohort, capture, artifactRows }) => { + const payloads = capture().payloads; + const incomplete = Object.assign(Object.create(cohort), { roots: cohort.roots.slice(2) }); + const report = bindNativeArchiveDelivery(payloads, [incomplete], artifactRows); + expect(report.products[0].physicalDelivery).toBeUndefined(); + expect(report.products[0].completeConfiguredArchiveInventory).toBe(false); + expect(() => + bindNativeArchiveDelivery( + payloads, + [Object.assign(Object.create(cohort), { source: { ...source, tree: '4'.repeat(40) } })], + artifactRows, + ), + ).toThrow('captured payload source'); + const root = cohort.roots.find(({ package: pkg }) => pkg.ecosystem === 'github')!; + root.package.version = '99.0.0'; + expect(() => bindNativeArchiveDelivery(payloads, [cohort], artifactRows)).toThrow( + 'different version', + ); + }); +}); + +test('actual extra, missing or changed archive members cannot masquerade as captured payloads', async () => { + await fixture(async ({ capture, cohort, files, artifactRows }) => { + const payloads = capture().payloads; + writeFileSync(path.join(files[0].directory, 'undeclared-member'), 'extra delivery'); + await files[0].pack(); + rmSync(path.join(files[0].directory, 'undeclared-member')); + expect(() => bindNativeArchiveDelivery(payloads, [cohort], artifactRows)).toThrow( + 'exactly deliver', + ); + }); +}); + +test('a raw payload changed after capture cannot bind an unchanged final archive', async () => { + await fixture(({ capture, cohort, files, artifactRows }) => { + const payloads = capture().payloads; + const changed = path.join(files[0].directory, 'lib/public-interface.bin'); + chmodSync(changed, 0o644); + writeFileSync(changed, 'new unbound raw payload bytes'); + expect(() => bindNativeArchiveDelivery(payloads, [cohort], artifactRows)).toThrow( + 'captured physical members', + ); + }); +}); + +test('same file bytes with an incorrect final executable mode do not satisfy the public contract', async () => { + await fixture(async ({ capture, cohort, files, artifactRows }) => { + const payloads = capture().payloads; + const value = files[0]; + const executable = + value.row.kind === 'native-runtime' + ? requiredRuntimeMemberPaths(value.row.target, 'runtime/bin') + : requiredToolsMemberPaths(value.row.target, 'runtime/bin'); + await archiveDirectory(value.directory, value.archive, { + modes: { + ...Object.fromEntries(executable.map((name) => [name, 0o755])), + 'lib/public-interface.bin': 0o755, + 'THIRD_PARTY_NOTICES.md': 0o644, + }, + }); + expect(() => bindNativeArchiveDelivery(payloads, [cohort], artifactRows)).toThrow( + 'exactly deliver', + ); + }); +}); + +test('digest-less public assets use the retained streaming proof and partial origins stay unknown', async () => { + await fixture(async ({ catalog, files, bind }) => { + const product = catalog.products[0]; + const one = files.filter(({ row }) => row.product === product.id).slice(0, 1); + const completed = completedFixture(product, one); + delete completed.assets[0].digest; + let downloads = 0; + const proveAsset = async (url, name, size) => { + expect(url).toBe(completed.assets[0].url); + expect(name).toBe(one[0].row.name); + expect(size).toBe(readFileSync(one[0].archive).length); + downloads++; + return { bytes: size, sha256: hash(one[0].archive) }; + }; + const origin = await captureCompletedNativeArchiveDelivery(completed.input, { + ...completed.options, + proveAsset, + }); + expect(downloads).toBe(1); + expect( + compareCompletedNativeArchiveDelivery(bind(), [origin]).products.every( + ({ deliveryStatus }) => deliveryStatus === 'unknown', + ), + ).toBe(true); + await expect( + captureCompletedNativeArchiveDelivery(completed.input, { + ...completed.options, + proveAsset: async () => ({ bytes: 1, sha256: hash(one[0].archive) }), + }), + ).rejects.toThrow('authenticated public asset'); + }); +}); + +test('completed origin binds actual release/source/asset identity, downloaded bytes and safe physical archive', async () => { + await fixture(async ({ catalog, files, executionRoot }) => { + const product = catalog.products[0]; + const completed = completedFixture( + product, + files.filter(({ row }) => row.product === product.id), + ); + const call = () => captureCompletedNativeArchiveDelivery(completed.input, completed.options); + completed.release.target_commitish = '4'.repeat(40); + await expect(call()).rejects.toThrow('completed source'); + completed.release.target_commitish = source.commit; + completed.assets[0].digest = `sha256:${'0'.repeat(64)}`; + await expect(call()).rejects.toThrow('authenticated public asset'); + completed.assets[0].digest = `sha256:${hash(completed.input.files[0].file)}`; + const archive = completed.input.files[0].file; + const backup = path.join(executionRoot, 'backup.tar.gz'); + copyFileSync(archive, backup); + rmSync(archive); + symlinkSync(backup, archive); + await expect(call()).rejects.toThrow(); + }); +}); + +test('qualified descriptor comparison classifies core-only resource hold and explicit admitted-consumer adoption before versioning', () => { + const catalog = loadPublicationCatalog('WASIX resource admission fixture'); + const resource = catalog.products.find((row) => row.id === 'database-resources')!; + const core = catalog.products.find((row) => row.id === 'liboliphaunt-wasix')!; + const input = decisionFixture(); + const rows = expectedProductArtifactRows([resource]) + .filter((row) => ['native-seeds', 'wasix-seeds'].includes(row.kind)) + .map((row) => ({ ...row, sha256: 'f'.repeat(64), size: 1, path: 'target/' + row.name })); + input.observation.products.find((row) => row.product.id === resource.id).productArtifacts = rows; + const completedResource = input.completed.products.find((row) => row.product === resource.id); + completedResource.productArtifacts = rows; + const completedCore = input.completed.products.find((row) => row.product === core.id); + completedCore.deliveryStatus = 'different'; + completedCore.comparisons = [ + { id: 'fixture-core', kind: 'wasix-runtime', differentMembers: ['oliphaunt/bin/postgres'] }, + ]; + const hold = compareNativePreVersionDelivery({ + ...input, + affectedProducts: [core.id, resource.id], + }); + expect(hold.selectedProducts).toEqual([core.id]); + expect(hold.products.find((row) => row.product === resource.id).necessaryDelivery).toBe( + 'not-needed', + ); + const descriptor = rows.find((row) => row.kind === 'wasix-seeds' && row.name.endsWith('.json'))!; + completedResource.deliveryStatus = 'different'; + completedResource.comparisons = rows.map((row) => ({ + id: row.id, + currentId: row.id, + kind: row.kind, + differentMembers: row.id === descriptor.id ? ['runtime.version', 'runtime.consumerSha256'] : [], + })); + const adopt = compareNativePreVersionDelivery({ ...input, affectedProducts: [resource.id] }); + expect(adopt.selectedProducts).toEqual([resource.id, core.id].sort()); + expect(adopt.products.find((row) => row.product === resource.id).necessaryDelivery).toBe( + 'needed', + ); + expect( + input.observation.products.find((row) => row.product.id === resource.id).productArtifacts, + ).toEqual(rows); +}); diff --git a/tools/release/native-publication-metadata-contract.mts b/tools/release/native-publication-metadata-contract.mts new file mode 100644 index 000000000..ebf2611e5 --- /dev/null +++ b/tools/release/native-publication-metadata-contract.mts @@ -0,0 +1,462 @@ +/** Canonical controller metadata; it is never a shipping payload or admission. */ +import { deepStrictEqual } from 'node:assert'; +import { validateReviewedNativeProducerAssurance } from './authenticate-native-build-evidence.mts'; +import { canonicalShippingLabel } from './bazel-shipping-inputs.mts'; +import { validateNativeSeedConstructions } from './native-build-qualification.mts'; +import { validateNativeVersionSourceBridge } from './native-version-source.mts'; + +export const NATIVE_PUBLICATION_METADATA_SCHEMA = 'oliphaunt-native-publication-metadata-v1'; +export const NATIVE_PUBLICATION_METADATA_KIND = 'native-baseline'; +// The real 17-root tools projection contains 20.21 MiB of construction facts. +// This bounded headroom is not proof that every future product/cohort will fit. +export const NATIVE_PUBLICATION_METADATA_MAX_BYTES = 64 * 1024 * 1024; +export function nativePublicationMetadataArtifactRow(product: { id: string; version: string }) { + if ( + !/^[a-z0-9][a-z0-9-]*$/u.test(product?.id) || + !/^\d+\.\d+\.\d+(?:[-+][a-zA-Z0-9.-]+)?$/u.test(product?.version) + ) + throw new Error('native metadata requires a canonical product/version'); + const name = `${product.id}-${product.version}-native-baseline.json`; + return { + product: product.id, + version: product.version, + id: `github-release:${name}`, + role: 'github-release-metadata', + kind: NATIVE_PUBLICATION_METADATA_KIND, + target: 'portable', + identity: null, + name, + }; +} +/** Explicit controller opt-in; ordinary publication inventories remain unchanged. */ +export function nativePublicationMetadataArtifactRows( + products: { id: string; version: string }[], + selected: string[] = [], +) { + if ( + !Array.isArray(selected) || + selected.some((id) => typeof id !== 'string') || + new Set(selected).size !== selected.length || + selected.some((id) => !products.some((product) => product.id === id)) + ) + throw new Error('native metadata selection must contain unique selected product IDs'); + return products + .filter((product) => selected.includes(product.id)) + .map(nativePublicationMetadataArtifactRow); +} +function fields(value: any, expected: string[], context: string) { + if (!value || typeof value !== 'object' || Array.isArray(value)) + throw new Error(`${context} must be an object`); + deepStrictEqual(Object.keys(value).sort(), expected.slice().sort(), `${context} fields`); +} +export function validateNativePublicationMetadata( + value: any, + expected: { + repository?: string; + product?: { id: string; version: string }; + source?: { commit: string; tree: string }; + } = {}, +) { + fields( + value, + [ + 'schema', + 'scope', + 'repository', + 'source', + 'product', + 'builds', + 'carriers', + 'productArtifacts', + 'construction', + 'preEnvelopeCapture', + 'baselineAdmission', + 'releaseDecision', + 'unverified', + ...(Object.hasOwn(value, 'publicationQualification') ? ['publicationQualification'] : []), + ], + 'native metadata', + ); + if ( + value.schema !== NATIVE_PUBLICATION_METADATA_SCHEMA || + value.scope !== 'construction' || + value.baselineAdmission !== 'unknown' || + value.releaseDecision !== 'unverified' + ) + throw new Error('native metadata cannot grant admission or a release decision'); + if (typeof value.repository !== 'string' || !/^[^/\s]+\/[^/\s]+$/u.test(value.repository)) + throw new Error('native metadata repository identity is missing'); + fields(value.source, ['commit', 'tree'], 'native metadata source'); + if (![value.source.commit, value.source.tree].every((sha) => /^[a-f0-9]{40}$/u.test(sha))) + throw new Error('native metadata source must be exact'); + if (Object.hasOwn(value, 'publicationQualification')) + validateNativePublicationQualification(value.publicationQualification, value); + const product = value.product; + nativePublicationMetadataArtifactRow(product); + if ( + !Array.isArray(value.carriers) || + !Array.isArray(value.productArtifacts) || + !Array.isArray(value.builds) || + !value.builds.length || + !Array.isArray(value.construction) || + !value.construction.length || + !Array.isArray(value.unverified) || + !value.unverified.length || + !['observed', 'absent'].includes(value.preEnvelopeCapture) + ) + throw new Error('native metadata inventory/builds/limitations are incomplete'); + for (const build of value.builds) { + fields( + build, + [ + 'github', + 'artifact', + 'evidenceDigest', + 'shippingAnalysis', + 'unverified', + 'testQualification', + 'requiredTests', + ...(Object.hasOwn(build, 'producerAssurance') ? ['producerAssurance'] : []), + ], + 'native metadata build', + ); + if ( + build.testQualification !== 'passed' || + !Array.isArray(build.requiredTests) || + !build.requiredTests.length || + !/^sha256:[a-f0-9]{64}$/u.test(build.evidenceDigest) + ) + throw new Error( + 'native metadata requires observed successful configured tests and exact evidence', + ); + if ( + !['bound', 'unverified'].includes(build.shippingAnalysis) || + !Array.isArray(build.unverified) || + !build.unverified.length + ) + throw new Error('native metadata must preserve construction qualification limitations'); + if (Object.hasOwn(build, 'producerAssurance')) + validateReviewedNativeProducerAssurance(build.producerAssurance, { + source: value.source, + github: build.github, + artifact: build.artifact, + evidenceDigest: build.evidenceDigest, + requiredTests: build.requiredTests, + }); + } + for (const row of [...value.carriers, ...value.productArtifacts]) { + if ( + row.product !== product.id || + (row.version !== undefined && row.version !== product.version) + ) + throw new Error('native metadata inventory owner/version differs'); + if (row.kind === 'checksums' || row.kind === NATIVE_PUBLICATION_METADATA_KIND) + throw new Error('native metadata must exclude itself and outer checksum artifacts'); + } + for (const observation of value.construction) { + if ( + !Array.isArray(observation.roots) || + !observation.roots.length || + observation.roots.some( + (root) => root.package.product !== product.id || root.package.version !== product.version, + ) || + !Array.isArray(observation.actions) || + !Array.isArray(observation.inputs) + ) + throw new Error('native metadata construction owner/closure differs'); + // Earlier construction observations did not retain this projection. Their + // causal leaves remain unknown; never infer them from generated input names. + if (Object.hasOwn(observation, 'leafInputPaths')) { + const paths = observation.leafInputPaths; + if ( + !Array.isArray(paths) || + paths.some( + (name) => + typeof name !== 'string' || + name.startsWith('bazel-out/') || + !observation.inputs.some((input) => input.path === name), + ) + ) + throw new Error('native metadata causal leaf is not a captured source input'); + deepStrictEqual(paths, [...new Set(paths)].sort(), 'native metadata causal leaf order'); + } + if (Object.hasOwn(observation, 'seedConstructions')) + validateNativeSeedConstructions( + observation.seedConstructions, + observation.inputs, + observation.actions, + ); + if ( + Object.hasOwn(observation, 'analysisInputPaths') || + Object.hasOwn(observation, 'analysisInputs') + ) { + if ( + !Array.isArray(observation.analysisInputPaths) || + !Array.isArray(observation.analysisInputs) + ) + throw new Error('native metadata loaded-file mapping is incomplete'); + const paths = observation.analysisInputPaths; + deepStrictEqual(paths, [...new Set(paths)].sort(), 'native metadata loaded-file path order'); + deepStrictEqual( + observation.analysisInputs.map((input) => input.path).sort(), + paths, + 'native metadata loaded-file capture coverage', + ); + for (const input of observation.analysisInputs) { + fields(input, ['path', 'members'], 'native metadata loaded-file capture'); + if ( + typeof input.path !== 'string' || + input.path.startsWith('/') || + input.path.startsWith('bazel-out/') || + input.path.startsWith('external/') || + /[\\\u0000-\u001f\u007f]/u.test(input.path) || + input.path.split('/').some((part) => !part || part === '.' || part === '..') || + !Array.isArray(input.members) || + input.members.length !== 1 + ) + throw new Error('native metadata loaded input is not a workspace File'); + const member = input.members[0]; + fields( + member, + ['path', 'type', 'mode', 'size', 'sha256'], + 'native metadata loaded-file content', + ); + if ( + member.path !== '' || + member.type !== 'file' || + !Number.isInteger(member.mode) || + member.mode < 0 || + member.mode > 0o777 || + !Number.isSafeInteger(member.size) || + member.size < 0 || + !/^[a-f0-9]{64}$/u.test(member.sha256) + ) + throw new Error('native metadata loaded-file identity differs'); + } + } + if (Object.hasOwn(observation, 'qualificationPolicy')) { + const policy = observation.qualificationPolicy; + fields( + policy, + [ + 'owner', + 'configuration', + 'roots', + 'requiredTests', + ...(Object.hasOwn(policy, 'rootConfigurations') ? ['rootConfigurations'] : []), + ...(Object.hasOwn(policy, 'policies') ? ['policies'] : []), + ], + 'native metadata owner policy', + ); + if ( + typeof policy.owner !== 'string' || + !policy.owner.startsWith('//') || + !/^[a-f0-9]{64}$/u.test(policy.configuration) || + !Array.isArray(policy.roots) || + !policy.roots.length || + policy.roots.some((label) => typeof label !== 'string' || !label.startsWith('//')) || + new Set(policy.roots).size !== policy.roots.length || + !Array.isArray(policy.requiredTests) + ) + throw new Error('native metadata owner policy identity is invalid'); + const build = value.builds.find( + (build) => build.evidenceDigest === observation.evidenceDigest, + ); + for (const test of policy.requiredTests) { + fields(test, ['label', 'configuration'], 'native metadata owner policy test'); + if ( + typeof test.label !== 'string' || + !test.label.startsWith('//') || + !/^[a-f0-9]{64}$/u.test(test.configuration) || + !build?.requiredTests.some( + (required) => + required.label === test.label && required.configuration === test.configuration, + ) + ) + throw new Error('native metadata owner policy test has no qualified build result'); + } + if ( + new Set(policy.requiredTests.map((test) => test.label)).size !== + policy.requiredTests.length || + observation.roots.some( + (root) => + !policy.roots.includes(canonicalShippingLabel(root.label)) || + !/^[a-f0-9]{64}$/u.test(root.configuration), + ) + ) + throw new Error('native metadata owner policy differs from configured shipping roots'); + if (Object.hasOwn(policy, 'rootConfigurations')) { + if ( + !Array.isArray(policy.rootConfigurations) || + new Set(policy.rootConfigurations.map((root) => root.label)).size !== + policy.rootConfigurations.length + ) + throw new Error('native metadata owner policy configured roots are invalid'); + for (const root of policy.rootConfigurations) { + fields(root, ['label', 'configuration'], 'native metadata policy configured root'); + if (!policy.roots.includes(root.label) || !/^[a-f0-9]{64}$/u.test(root.configuration)) + throw new Error('native metadata owner policy configured root identity differs'); + } + deepStrictEqual( + policy.rootConfigurations.map((root) => root.label).sort(), + [...policy.roots].sort(), + 'native metadata policy configured root coverage', + ); + if ( + observation.roots.some( + (root) => + !policy.rootConfigurations.some( + (configured) => + configured.label === canonicalShippingLabel(root.label) && + configured.configuration === root.configuration, + ), + ) + ) + throw new Error('native metadata owner policy has a different configured shipping root'); + } + if (Object.hasOwn(policy, 'policies')) { + if ( + !Array.isArray(policy.policies) || + !policy.policies.length || + new Set(policy.policies.map((owner) => owner.owner)).size !== policy.policies.length + ) + throw new Error('native metadata source owner policies are invalid'); + for (const owner of policy.policies) { + fields(owner, ['owner', 'roots', 'requiredTests'], 'native metadata source owner policy'); + if ( + typeof owner.owner !== 'string' || + !owner.owner.startsWith('//') || + !Array.isArray(owner.roots) || + !owner.roots.length || + owner.roots.some((root) => !policy.roots.includes(root)) || + !Array.isArray(owner.requiredTests) + ) + throw new Error('native metadata source owner policy identity differs'); + for (const test of owner.requiredTests) + if ( + !policy.requiredTests.some( + (required) => + required.label === test.label && required.configuration === test.configuration, + ) + ) + throw new Error('native metadata source owner policy has a foreign test'); + } + deepStrictEqual( + policy.policies.flatMap((owner) => owner.roots).sort(), + [...policy.roots].sort(), + 'native metadata source owner root coverage', + ); + deepStrictEqual( + [ + ...new Set( + policy.policies.flatMap((owner) => + owner.requiredTests.map((test) => JSON.stringify(test)), + ), + ), + ].sort(), + [...new Set(policy.requiredTests.map((test) => JSON.stringify(test)))].sort(), + 'native metadata source owner test coverage', + ); + } + } + } + if (expected.repository !== undefined) + deepStrictEqual(value.repository, expected.repository, 'native metadata repository'); + if (expected.source !== undefined) + deepStrictEqual(value.source, expected.source, 'native metadata source'); + if (expected.product !== undefined) + deepStrictEqual( + { id: product.id, version: product.version }, + expected.product, + 'native metadata product', + ); + return value; +} + +/** Durable description of the authenticated post-version controller. Parsing + * this record cannot grant fresh freeze authority or authorize publication. */ +export function validateNativePublicationQualification(qualification: any, metadata: any) { + fields( + qualification, + ['source', 'prepare', 'bridge', 'selectedProducts', 'producer', 'inventory'], + 'native publication qualification', + ); + deepStrictEqual(qualification.source, metadata.source, 'native publication qualification source'); + validateNativeVersionSourceBridge(qualification.bridge); + const prepare = qualification.prepare; + fields( + prepare, + ['runId', 'runAttempt', 'artifact', 'codeSource', 'preparedSource'], + 'native publication Prepare origin', + ); + fields(prepare.artifact, ['id', 'name', 'digest', 'size'], 'native publication Prepare artifact'); + deepStrictEqual( + prepare.codeSource, + qualification.bridge.source, + 'native publication bridge source', + ); + fields(prepare.preparedSource, ['commit', 'tree'], 'native publication prepared source'); + if ( + ![prepare.preparedSource.commit, prepare.preparedSource.tree].every((sha) => + /^[a-f0-9]{40}$/u.test(sha), + ) || + prepare.preparedSource.tree !== metadata.source.tree || + prepare.artifact.name !== 'native-release-inputs' || + !/^sha256:[a-f0-9]{64}$/u.test(prepare.artifact.digest) + ) + throw new Error('native publication Prepare artifact or prepared tree differs'); + const producer = qualification.producer; + fields( + producer, + ['runId', 'runAttempt', 'event', 'ref', 'workflowPath'], + 'native publication producer', + ); + if ( + !['push', 'workflow_dispatch'].includes(producer.event) || + producer.ref !== 'refs/heads/main' || + producer.workflowPath !== '.github/workflows/bazel.yml' + ) + throw new Error('native publication producer is not exact main qualification'); + for (const number of [ + prepare.runId, + prepare.runAttempt, + prepare.artifact.id, + prepare.artifact.size, + producer.runId, + producer.runAttempt, + ]) + if (!Number.isSafeInteger(number) || number <= 0) + throw new Error('native publication origin requires positive IDs and sizes'); + const inventory = qualification.inventory; + fields( + inventory, + ['products', 'artifactPhase', 'packageEnvelopeDigest'], + 'native publication complete inventory', + ); + const selection = qualification.selectedProducts; + for (const ids of [selection, inventory.products]) { + if ( + !Array.isArray(ids) || + !ids.length || + ids.some((id) => typeof id !== 'string' || !/^[a-z0-9][a-z0-9-]*$/u.test(id)) + ) + throw new Error('native publication scope requires canonical product IDs'); + deepStrictEqual(ids, [...new Set(ids)].sort(), 'native publication scope order'); + } + if ( + !selection.includes(metadata.product.id) || + selection.some((id) => !inventory.products.includes(id)) || + inventory.artifactPhase !== 'pre-version' || + !/^[a-f0-9]{64}$/u.test(inventory.packageEnvelopeDigest) + ) + throw new Error('native publication selection or complete inventory differs'); + for (const build of metadata.builds) + if ( + build.github.runId !== producer.runId || + !Number.isSafeInteger(build.github.runAttempt) || + build.github.runAttempt <= 0 || + build.github.runAttempt > producer.runAttempt + ) + throw new Error('native publication producing run differs from observed builds'); + return qualification; +} diff --git a/tools/release/native-publication-metadata.mts b/tools/release/native-publication-metadata.mts new file mode 100644 index 000000000..3b4631357 --- /dev/null +++ b/tools/release/native-publication-metadata.mts @@ -0,0 +1,508 @@ +/** Prepared observations become authenticated public origins, never native admission. */ +import { deepStrictEqual } from 'node:assert'; +import { execFile, execFileSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { lstatSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { parseArgs, promisify } from 'node:util'; +import { requireSafeDirectoryChain } from '../packaging/release-directory-safety.mts'; +import { reviewedNativeProducerUnknowns } from './authenticate-native-build-evidence.mts'; +import { + type CompletedPublication, + createCompletedPublicationChecker, +} from './completed-release-publication.mts'; +import { requestGithubPages, requestGithubRepositoryJson } from './github-read.mts'; +import { + NATIVE_PUBLICATION_METADATA_KIND, + NATIVE_PUBLICATION_METADATA_MAX_BYTES, + NATIVE_PUBLICATION_METADATA_SCHEMA, + nativePublicationMetadataArtifactRow, + validateNativePublicationMetadata, +} from './native-publication-metadata-contract.mts'; +import { observeNativePublicationConstruction } from './native-publication-observation.mts'; +import { captureNativeInputMembers } from './native-publication-staging.mts'; +import { + assertPublicationLockSource, + loadPublicationLock, + lockedPublicationFiles, + sourceIdentity, +} from './publication-lock.mts'; +import { ROOT } from './release-graph.mts'; +import { + prepareBundleVerification, + readGhBundleVerification, + releaseAttestationPublisherRequest, + requestReleaseAssetProof, + verifyAttestationBundleSubject, + writeImmutableReceipt, +} from './verify_github_release_attestations.mts'; + +const execute = promisify(execFile); +const hash = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +const authenticatedBaselines = new WeakMap void }>(); +export function assertAuthenticatedNativePublicBaseline(value: unknown) { + if (!value || typeof value !== 'object' || !authenticatedBaselines.has(value)) + throw new Error('native seed baseline lacks its authenticated completed metadata origin'); + const proof = authenticatedBaselines.get(value)!; + proof.unchanged(); + if (hash(Buffer.from(JSON.stringify(value))) !== proof.digest) + throw new Error('authenticated completed native metadata facts changed'); + return value as Awaited>; +} + +/** Acquire the optional frozen inventory before interpreting an older release. + * The default reader authenticates the original completed metadata object. */ +export async function acquireCompletedNativeMetadataBaseline( + { + publication, + directory, + assets, + metadataOrigin, + }: { + publication: CompletedPublication; + directory: string; + assets: readonly any[]; + metadataOrigin?: { publisherSha: string; bundlePaths: string[] }; + }, + { + proveAsset = requestReleaseAssetProof, + readBaseline = readCompletedNativePublicBaseline, + baselineTransports = {} as Parameters[1], + } = {}, +) { + const artifact = nativePublicationMetadataArtifactRow({ + id: publication.product, + version: publication.version, + }); + const matching = assets.filter((asset) => asset.name === artifact.name); + if (matching.length > 1) throw new Error('completed native metadata asset is ambiguous'); + if (!matching.length) return undefined; + const asset = matching[0]; + if ( + !Number.isSafeInteger(asset.id) || + asset.id <= 0 || + asset.state !== 'uploaded' || + asset.url !== `https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/${asset.id}` || + !Number.isSafeInteger(asset.size) || + asset.size <= 0 || + asset.size > NATIVE_PUBLICATION_METADATA_MAX_BYTES || + (asset.digest != null && !/^sha256:[a-f0-9]{64}$/u.test(asset.digest)) + ) + throw new Error('completed native metadata asset identity differs'); + const file = path.join(directory, artifact.name); + requireSafeDirectoryChain(path.dirname(file), { + create: true, + label: 'completed native metadata', + }); + await proveAsset(asset.url, artifact.name, asset.size, { + retainedPath: file, + ...(asset.digest ? { expectedSha256: asset.digest.slice(7) } : {}), + }); + const request = { publication, file, ...(metadataOrigin ?? {}) }; + const baseline = + readBaseline === readCompletedNativePublicBaseline + ? assertAuthenticatedNativePublicBaseline(await readBaseline(request)) + : await readBaseline(request, baselineTransports); + return { baseline, file }; +} +const limitations = [ + 'immutable input lifetime from the producing build through content capture', + 'native action-graph dump bytes authenticated by the producing invocation', + 'loaded analysis and acquisition provenance for every consumed producer input', + 'qualified mapping from pre-envelope members to every delivered product contract', + 'complete migration inventory and product-specific mandatory qualification policy', + 'necessary delivery comparison against a prior admitted native baseline', +]; + +/** Input envelope/files are prevalidated together at their exact source. Initial origin authentication is mandatory. */ +export async function prepareNativePublicationMetadata( + input: Parameters[0], + transports: Parameters[1] = {}, +) { + const frozen = structuredClone(input); + const observation = await observeNativePublicationConstruction(frozen, transports); + return observedNativePublicationMetadata(frozen, observation); +} + +/** Describe a previously observed producer set without another acquisition or + * graph validation. Descriptive metadata cannot grant publication authority. */ +export function observedNativePublicationMetadata( + input: Parameters[0], + observation: Awaited>, + publicationQualification?: Record, +) { + return observation.products.map((product) => + validateNativePublicationMetadata({ + schema: NATIVE_PUBLICATION_METADATA_SCHEMA, + scope: 'construction', + repository: input.repository, + source: input.envelope.source, + ...(publicationQualification === undefined ? {} : { publicationQualification }), + ...product, + // The separately attested control file never includes itself or a checksum + // envelope. Existing producer checksums remain unchanged outside this file. + productArtifacts: product.productArtifacts.filter( + (artifact) => !['checksums', NATIVE_PUBLICATION_METADATA_KIND].includes(artifact.kind), + ), + builds: observation.authenticated.map(({ origin, qualification, producerAssurance }) => ({ + github: origin.github, + artifact: origin.artifact, + evidenceDigest: origin.evidenceDigest, + shippingAnalysis: qualification.shippingAnalysis, + unverified: qualification.unverified, + testQualification: qualification.testQualification, + requiredTests: qualification.requiredTests, + ...(producerAssurance ? { producerAssurance } : {}), + })), + releaseDecision: 'unverified', + unverified: observation.authenticated.every((build) => build.producerAssurance) + ? reviewedNativeProducerUnknowns(limitations) + : limitations, + }), + ); +} + +/** An executable writer consumed by the explicit inventory option; never a capsule extra. */ +export async function writePreparedNativePublicationMetadata( + directory: string, + input: Parameters[0], + transports: Parameters[1] = {}, +) { + const records = await prepareNativePublicationMetadata(input, transports); + return writeMetadataRecords(directory, records); +} + +export async function writeMetadataRecords( + directory: string, + records: ReturnType[], +) { + for (const record of records) { + const size = Buffer.byteLength(`${JSON.stringify(record, null, 2)}\n`); + if (size > NATIVE_PUBLICATION_METADATA_MAX_BYTES) + throw new Error( + `${record.product.id} native metadata is ${size} bytes, exceeds ${NATIVE_PUBLICATION_METADATA_MAX_BYTES} bytes`, + ); + } + requireSafeDirectoryChain(path.resolve(directory), { + create: true, + label: 'native publication metadata', + }); + const artifacts = []; + for (const record of records) { + const row = nativePublicationMetadataArtifactRow(record.product); + const file = path.join(directory, row.name); + await writeImmutableReceipt(file, record, { + maximumBytes: NATIVE_PUBLICATION_METADATA_MAX_BYTES, + }); + const bytes = readFileSync(file); + artifacts.push({ ...row, path: file, sha256: hash(bytes), size: bytes.length }); + } + return artifacts; +} + +/** The executable controller opts in only at an exact, clean frozen-lock checkout. */ +export async function runNativePublicationMetadataController(args = process.argv.slice(2)) { + const { values } = parseArgs({ + args, + allowPositionals: false, + options: { + lock: { type: 'string' }, + builds: { type: 'string' }, + repository: { type: 'string' }, + 'bazel-version': { type: 'string' }, + 'output-directory': { type: 'string' }, + 'head-ref': { type: 'string', default: 'HEAD' }, + 'reviewed-source-ref': { type: 'string' }, + }, + }); + const required = (name: string) => { + const value = values[name]; + if (!value) throw new Error(`native metadata controller requires --${name}`); + return value; + }; + const source = sourceIdentity(values['head-ref']); + const assertCheckout = () => { + try { + execFileSync( + 'bash', + [ + path.join(ROOT, 'tools/release/qualified-release-replay.sh'), + source.commit, + source.commit, + ], + { cwd: ROOT, stdio: ['ignore', 'ignore', 'pipe'] }, + ); + } catch (cause) { + throw new Error('native metadata controller requires a frozen clean exact source checkout', { + cause, + }); + } + }; + assertCheckout(); + const lockFile = required('lock'); + const lock = loadPublicationLock(lockFile); + assertPublicationLockSource(lock, source.commit); + const files = lockedPublicationFiles(lock); + const reviewedSource = + values['reviewed-source-ref'] === undefined + ? undefined + : sourceIdentity(values['reviewed-source-ref']); + const records = await prepareNativePublicationMetadata({ + envelope: lock, + files, + repository: required('repository'), + bazelVersion: required('bazel-version'), + builds: JSON.parse(readFileSync(required('builds'), 'utf8')), + ...(reviewedSource ? { reviewedSource } : {}), + }); + const assertFrozen = () => { + assertCheckout(); + deepStrictEqual(loadPublicationLock(lockFile), lock, 'native metadata frozen lock changed'); + deepStrictEqual(lockedPublicationFiles(lock), files, 'native metadata frozen files changed'); + }; + assertFrozen(); + const artifacts = await writeMetadataRecords(required('output-directory'), records); + assertFrozen(); + return { + artifacts, + producerPolicy: reviewedSource ? 'reviewed-main' : 'observed', + releaseDecision: 'unverified', + }; +} + +async function authenticatePublicMetadataAttestation({ + file, + artifact, + repository, + publisherSha, + bundlePaths, +}) { + if (!Array.isArray(bundlePaths) || bundlePaths.length !== 1) + throw new Error('public native metadata requires exactly one signed bundle'); + const scratch = mkdtempSync(path.join(tmpdir(), 'oliphaunt-native-metadata-attestation-')); + const context = { + bundlePath: bundlePaths[0], + file, + name: artifact.name, + sha256: artifact.sha256, + repo: repository, + publisherSha, + }; + try { + await verifyAttestationBundleSubject(context, { + verifyBundleImpl: (options) => prepareBundleVerification(options, scratch), + }); + await execute( + 'bash', + [ + path.join(ROOT, 'tools/release/verify-github-release-attestations.sh'), + '--verify-prepared', + scratch, + ], + { cwd: ROOT, maxBuffer: 1024 * 1024 }, + ); + return await verifyAttestationBundleSubject(context, { + verifyBundleImpl: (options) => readGhBundleVerification(options, scratch), + }); + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +} + +/** Public asset + canonical completion + release-workflow signature supersede an expiring Actions pointer. */ +export async function readCompletedNativePublicBaseline( + { + publication, + file, + publisherSha, + bundlePaths, + }: { + publication: CompletedPublication; + file: string; + publisherSha?: string; + bundlePaths?: string[]; + }, + { + repository = 'f0rr0/oliphaunt', + assertCompleted = undefined as ReturnType | undefined, + readJson = requestGithubRepositoryJson, + readPages = requestGithubPages, + proveAsset = requestReleaseAssetProof, + verifyAttestation = authenticatePublicMetadataAttestation, + } = {}, +) { + if (publisherSha !== undefined && !/^[a-f0-9]{40}$/u.test(publisherSha)) + throw new Error('public native metadata requires exact publishing controller source'); + if (Boolean(publisherSha) !== Boolean(bundlePaths)) + throw new Error('native metadata explicit publisher and bundles must be paired'); + const completed = await (assertCompleted ?? createCompletedPublicationChecker({ repository }))( + publication, + ); + deepStrictEqual(completed, publication, 'native metadata completion'); + const source = { commit: completed.publicationSha, tree: completed.publicationTree }; + const artifact = nativePublicationMetadataArtifactRow({ + id: completed.product, + version: completed.version, + }); + const absolute = path.resolve(file); + requireSafeDirectoryChain(path.dirname(absolute), { label: 'public native metadata' }); + const stat = lstatSync(absolute); + if ( + !stat.isFile() || + stat.isSymbolicLink() || + stat.size > NATIVE_PUBLICATION_METADATA_MAX_BYTES || + path.basename(absolute) !== artifact.name + ) + throw new Error('public native metadata must be its canonical bounded regular File'); + const capture = captureNativeInputMembers(path.dirname(absolute), path.basename(absolute)); + const bytes = readFileSync(absolute); + const sha256 = hash(bytes); + if ( + capture.members.length !== 1 || + capture.members[0].type !== 'file' || + capture.members[0].sha256 !== sha256 || + capture.members[0].size !== bytes.length + ) + throw new Error('public native metadata bytes changed while captured'); + const release = await readJson(`repos/${repository}/releases/tags/${completed.tagName}`); + if ( + !Number.isSafeInteger(release.id) || + release.id <= 0 || + release.tag_name !== completed.tagName || + release.target_commitish !== source.commit || + release.draft !== false || + release.prerelease !== false + ) + throw new Error('public native metadata release differs from completed source'); + const assets = await readPages(`repos/${repository}/releases/${release.id}/assets`); + const matches = assets.filter((asset) => asset.name === artifact.name); + if (matches.length !== 1) throw new Error('public native metadata asset is missing or ambiguous'); + const asset = matches[0]; + if ( + !Number.isSafeInteger(asset.id) || + asset.id <= 0 || + asset.url !== `https://api.github.com/repos/${repository}/releases/assets/${asset.id}` || + asset.state !== 'uploaded' || + asset.size !== bytes.length || + (asset.digest != null && !/^sha256:[a-f0-9]{64}$/u.test(asset.digest)) + ) + throw new Error('public native metadata asset identity differs'); + const proof = + asset.digest == null + ? await proveAsset(asset.url, artifact.name, asset.size) + : { bytes: asset.size, sha256: asset.digest.slice(7) }; + if (proof.bytes !== bytes.length || proof.sha256 !== sha256) + throw new Error('public native metadata bytes differ from authenticated asset'); + let attestation; + if (publisherSha) { + attestation = await verifyAttestation({ + file: absolute, + artifact: { ...artifact, sha256, size: bytes.length }, + repository, + publisherSha, + bundlePaths, + }); + } else { + const rows = await readPages(`repos/${repository}/attestations/sha256:${sha256}`, { + itemsField: 'attestations', + maxPages: 10, + }); + const scratch = mkdtempSync(path.join(tmpdir(), 'oliphaunt-completed-metadata-bundles-')); + const seen = new Set(); + try { + for (const row of rows) { + let request; + try { + request = releaseAttestationPublisherRequest(row.bundle, { + repo: repository, + name: artifact.name, + sha256, + }); + } catch { + continue; + } + if (!request) continue; + const contents = Buffer.from(JSON.stringify(row.bundle)); + if (contents.length > 32 * 1024 * 1024) + throw new Error('completed metadata attestation bundle exceeds bound'); + const digest = hash(contents); + if (seen.has(digest)) continue; + seen.add(digest); + const bundle = path.join(scratch, `${digest}.json`); + writeFileSync(bundle, contents, { flag: 'wx' }); + try { + const verified = await verifyAttestation({ + file: absolute, + artifact: { ...artifact, sha256, size: bytes.length }, + repository, + publisherSha: request.publisherSha, + bundlePaths: [bundle], + }); + if ( + verified?.subjects?.filter( + (subject) => subject.name === artifact.name && subject.sha256 === sha256, + ).length !== 1 + ) + continue; + attestation = verified; + publisherSha = request.publisherSha; + break; + } catch { + /* Unsigned lookup fields cannot replace an authenticated signer. */ + } + } + } finally { + rmSync(scratch, { recursive: true, force: true }); + } + } + if ( + !attestation || + !Array.isArray(attestation.subjects) || + attestation.subjects.filter( + (subject) => subject.name === artifact.name && subject.sha256 === sha256, + ).length !== 1 + ) + throw new Error('public native metadata has no authenticated exact attestation subject'); + const metadata = validateNativePublicationMetadata( + JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes)), + { repository, source, product: { id: completed.product, version: completed.version } }, + ); + capture.assertUnchanged(); + const result = { + scope: 'construction' as const, + publication: completed, + metadata, + publicOrigin: { + releaseId: release.id, + assetId: asset.id, + sha256, + size: bytes.length, + publisherSha, + attestation, + }, + baselineAdmission: 'unknown' as const, + releaseDecision: 'unverified' as const, + }; + if ( + assertCompleted === undefined && + readJson === requestGithubRepositoryJson && + readPages === requestGithubPages && + proveAsset === requestReleaseAssetProof && + verifyAttestation === authenticatePublicMetadataAttestation + ) + authenticatedBaselines.set(result, { + digest: hash(Buffer.from(JSON.stringify(result))), + unchanged: capture.assertUnchanged, + }); + return result; +} + +if (import.meta.main) { + try { + process.stdout.write(`${JSON.stringify(await runNativePublicationMetadataController())}\n`); + } catch (error) { + console.error(error instanceof Error ? error.message : String(error)); + process.exitCode = 1; + } +} diff --git a/tools/release/native-publication-metadata.test.mts b/tools/release/native-publication-metadata.test.mts new file mode 100644 index 000000000..4548aff29 --- /dev/null +++ b/tools/release/native-publication-metadata.test.mts @@ -0,0 +1,870 @@ +import { expect, test } from 'bun:test'; +import { spawnSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { fixture, source } from './completed-native-publication.fixture.mts'; +import { + acquireCompletedNativeMetadataBaseline, + assertAuthenticatedNativePublicBaseline, + prepareNativePublicationMetadata, + readCompletedNativePublicBaseline, + writePreparedNativePublicationMetadata, +} from './native-publication-metadata.mts'; +import { + NATIVE_PUBLICATION_METADATA_MAX_BYTES, + nativePublicationMetadataArtifactRow, + validateNativePublicationMetadata, +} from './native-publication-metadata-contract.mts'; +import { loadPublicationCatalog } from './publication-catalog.mts'; +import { + buildPublicationCandidate, + discoverProductArtifacts, + expectedProductArtifactRows, + freezePublicationCandidate, + validatePublicationCandidate, + validatePublicationLock, +} from './publication-lock.mts'; +import { + verifyAttestationBundleSubject, + writeImmutableReceipt, +} from './verify_github_release_attestations.mts'; + +const hash = (bytes) => createHash('sha256').update(bytes).digest('hex'); + +test('optional completed metadata is acquired before inventory decoding and keeps its original reader object', async () => { + const directory = mkdtempSync(path.join(tmpdir(), 'completed-metadata-acquisition-')); + const publication = { + product: 'database-resources', + version: '0.2.2', + tagName: 'database-resources-v0.2.2', + publicationSha: 'a'.repeat(40), + publicationTree: 'b'.repeat(40), + releaseSha: 'c'.repeat(40), + }; + const artifact = nativePublicationMetadataArtifactRow({ + id: publication.product, + version: publication.version, + }); + const bytes = Buffer.from('{"controlled":"metadata"}'); + const asset = { + id: 17, + name: artifact.name, + state: 'uploaded', + size: bytes.length, + digest: `sha256:${hash(bytes)}`, + url: 'https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/17', + }; + const baseline = { publication, metadata: {}, baselineAdmission: 'unknown' } as any; + const requests = []; + const transports = { + proveAsset: async (_url, name, size, options) => { + requests.push('download'); + expect(name).toBe(artifact.name); + expect(size).toBe(bytes.length); + expect(options.expectedSha256).toBe(hash(bytes)); + writeFileSync(options.retainedPath, bytes, { flag: 'wx' }); + return { bytes: bytes.length, sha256: hash(bytes) }; + }, + readBaseline: async ({ publication: completed, file }) => { + requests.push('authenticate'); + expect(completed).toBe(publication); + expect(readFileSync(file)).toEqual(bytes); + return baseline; + }, + }; + try { + expect( + await acquireCompletedNativeMetadataBaseline( + { publication, directory, assets: [] }, + transports, + ), + ).toBeUndefined(); + expect(requests).toEqual([]); + await expect( + acquireCompletedNativeMetadataBaseline( + { publication, directory, assets: [asset, asset] }, + transports, + ), + ).rejects.toThrow('ambiguous'); + await expect( + acquireCompletedNativeMetadataBaseline( + { publication, directory, assets: [{ ...asset, digest: 'invalid' }] }, + transports, + ), + ).rejects.toThrow('identity'); + const result = await acquireCompletedNativeMetadataBaseline( + { publication, directory, assets: [asset] }, + transports, + ); + expect(result!.baseline).toBe(baseline); + expect(requests).toEqual(['download', 'authenticate']); + expect(() => assertAuthenticatedNativePublicBaseline(result!.baseline)).toThrow( + 'authenticated completed metadata origin', + ); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); +const preparation = (input) => ({ + envelope: input.publicationLock, + files: input.publicationFiles, + repository: input.repository, + bazelVersion: input.bazelVersion, + builds: input.builds, +}); +const subject = (name, sha256) => ({ name, digest: { sha256 } }); +const normalizedSubjects = (subjects) => + subjects + .map(({ name, digest }) => ({ name, sha256: digest.sha256 })) + .sort((a, b) => a.name.localeCompare(b.name)); +function bundle(directory, subjects) { + const file = path.join(directory, 'attestation.json'); + writeFileSync( + file, + JSON.stringify({ + dsseEnvelope: { + payload: Buffer.from( + JSON.stringify({ + _type: 'https://in-toto.io/Statement/v1', + predicateType: 'https://slsa.dev/provenance/v1', + subject: subjects, + }), + ).toString('base64'), + }, + }), + ); + return file; +} + +test('compiler and ABI roots retain construction evidence without claiming pre-envelope capture', async () => { + await fixture(async ({ input, transports, origin }) => { + const root = origin.evidence.cohorts[0].roots.find( + (root) => root.package.ecosystem === 'internal', + ); + if (!root) throw new Error('fixture requires an internal construction root'); + for (const role of ['compiled-source', 'abi-contract', 'extension-release-frozen-input']) { + root.package.role = role; + const records = await prepareNativePublicationMetadata(preparation(input), transports); + const product = records.find((record) => record.product.id === root.package.product); + expect(product?.preEnvelopeCapture).toBe( + role === 'extension-release-frozen-input' ? 'observed' : 'absent', + ); + expect(product?.construction[0].roots.some((value) => value.label === root.label)).toBe(true); + } + }); +}); + +test('prepared metadata authenticates actual captured construction and excludes circular envelopes', async () => { + await fixture(async ({ input, transports, requests }) => { + const records = await prepareNativePublicationMetadata(preparation(input), transports); + expect(requests).toEqual(['auth']); + expect(records.map((record) => record.product.id)).toEqual(['alpha', 'beta']); + expect(records[0].carriers[0].packageDependencies[0].requirement).toBe('=0.3.2'); + expect(records[1].preEnvelopeCapture).toBe('observed'); + expect( + records.every( + (record) => + record.baselineAdmission === 'unknown' && record.releaseDecision === 'unverified', + ), + ).toBe(true); + expect(records[0].builds[0].requiredTests).toHaveLength(2); + expect(records[0].construction[0].inputs.every((input) => !input.path.includes('/beta/'))).toBe( + true, + ); + const construction = records[0].construction[0]; + expect(construction.leafInputPaths).toEqual([ + 'external/compiler/compiler', + 'src/alpha/index.ts', + ]); + const intermediate = 'bazel-out/k8-opt/bin/alpha/config.h'; + expect(construction.inputs.map(({ path }) => path)).not.toContain(intermediate); + const actions = construction.actions.map((definition) => JSON.parse(definition)); + expect(actions).toHaveLength(2); + expect(actions.find((action) => action.target === '//fixture/alpha:config')).toMatchObject({ + outputs: [intermediate], + inputs: { + count: 2, + sha256: hash(Buffer.from(JSON.stringify(construction.leafInputPaths))), + }, + }); + expect(actions.find((action) => action.target === '//fixture/alpha:archive')).toMatchObject({ + outputs: ['bazel-out/k8-opt/bin/alpha/alpha.tgz'], + inputs: { + count: 3, + sha256: hash( + Buffer.from(JSON.stringify([...construction.leafInputPaths, intermediate].sort())), + ), + }, + }); + for (const paths of [ + ['bazel-out/k8-opt/bin/alpha/config.h'], + ['src/missing/index.ts'], + ['src/alpha/index.ts', 'src/alpha/index.ts'], + ]) { + const changed = structuredClone(records[0]); + changed.construction[0].leafInputPaths = paths; + expect(() => validateNativePublicationMetadata(changed)).toThrow(/causal leaf/); + } + const earlierObservation = structuredClone(records[0]); + delete earlierObservation.construction[0].leafInputPaths; + expect(validateNativePublicationMetadata(earlierObservation).baselineAdmission).toBe('unknown'); + for (const mutate of [ + (record) => { + record.lockDigest = '9'.repeat(64); + }, + (record) => { + record.baselineAdmission = 'admitted'; + }, + (record) => { + record.productArtifacts.push({ product: record.product.id, kind: 'checksums' }); + }, + (record) => { + record.productArtifacts.push(nativePublicationMetadataArtifactRow(record.product)); + }, + (record) => { + record.source.commit = '9'.repeat(40); + }, + ]) { + const modified = structuredClone(records[0]); + mutate(modified); + expect(() => validateNativePublicationMetadata(modified, { source })).toThrow(); + } + }); +}); + +test('post-version metadata preserves the exact Prepare bridge and Native run without granting parsed authority', async () => { + await fixture(async ({ input, transports }) => { + const [historical] = await prepareNativePublicationMetadata(preparation(input), transports); + const updates = [ + { + path: '.release-please-manifest.json', + before: { size: 10, sha256: '1'.repeat(64) }, + after: { size: 11, sha256: '2'.repeat(64) }, + }, + ]; + const codeSource = { commit: '3'.repeat(40), tree: '4'.repeat(40) }; + const build = historical.builds[0].github; + const qualification = { + source: historical.source, + prepare: { + runId: 88, + runAttempt: 1, + artifact: { + id: 99, + name: 'native-release-inputs', + digest: `sha256:${'5'.repeat(64)}`, + size: 1024, + }, + codeSource, + preparedSource: historical.source, + }, + bridge: { + source: codeSource, + updates, + updatesSha256: hash(Buffer.from(JSON.stringify(updates))), + }, + selectedProducts: ['alpha'], + producer: { + runId: build.runId, + runAttempt: build.runAttempt + 1, + event: 'push', + ref: 'refs/heads/main', + workflowPath: '.github/workflows/bazel.yml', + }, + inventory: { + products: ['alpha', 'beta'], + artifactPhase: 'pre-version', + packageEnvelopeDigest: '6'.repeat(64), + }, + }; + const described = { ...structuredClone(historical), publicationQualification: qualification }; + expect(validateNativePublicationMetadata(described).publicationQualification).toEqual( + qualification, + ); + expect(described.scope).toBe('construction'); + expect(described.builds[0].github.runAttempt).toBe(build.runAttempt); + expect(historical.publicationQualification).toBeUndefined(); + for (const attempt of [undefined, 0, 1.5, qualification.producer.runAttempt + 1]) { + const changed = structuredClone(described); + changed.builds[0].github.runAttempt = attempt; + expect(() => validateNativePublicationMetadata(changed)).toThrow(/producing run/); + } + for (const mutate of [ + (control) => { + control.source.commit = '7'.repeat(40); + }, + (control) => { + control.prepare.preparedSource.tree = '7'.repeat(40); + }, + (control) => { + control.bridge.updates[0].after.sha256 = '7'.repeat(64); + }, + (control) => { + control.prepare.codeSource = { ...control.prepare.codeSource, commit: '7'.repeat(40) }; + }, + (control) => { + control.producer.runId++; + }, + (control) => { + control.selectedProducts = ['beta']; + }, + (control) => { + control.inventory.products = ['alpha', 'alpha']; + }, + (control) => { + control.inventory.artifactPhase = 'final'; + }, + (control) => { + control.prepare.artifact.name = 'arbitrary'; + }, + ]) { + const changed = structuredClone(described); + mutate(changed.publicationQualification); + expect(() => validateNativePublicationMetadata(changed)).toThrow(); + } + }); +}); + +test('prepared metadata preserves captured owner policy without upgrading older or incomplete observations', async () => { + await fixture( + async ({ input, transports }) => { + const records = await prepareNativePublicationMetadata( + { ...preparation(input), reviewedSource: source }, + transports, + ); + const record = records[0]; + const policy = record.construction[0].qualificationPolicy; + expect(policy.owner).toBe('//fixture:shipping_export'); + expect(policy.requiredTests).toHaveLength(2); + expect(record.baselineAdmission).toBe('unknown'); + expect(record.releaseDecision).toBe('unverified'); + const canonicalAlias = structuredClone(record); + canonicalAlias.construction[0].roots[0].label = `@@${canonicalAlias.construction[0].roots[0].label}`; + expect(validateNativePublicationMetadata(canonicalAlias).baselineAdmission).toBe('unknown'); + const earlier = structuredClone(record); + delete earlier.construction[0].qualificationPolicy; + expect(validateNativePublicationMetadata(earlier).baselineAdmission).toBe('unknown'); + for (const change of [ + (policy) => { + policy.owner = 'outside'; + }, + (policy) => { + policy.configuration = 'foreign-config'; + }, + (policy) => { + policy.roots = ['//fixture:foreign']; + }, + (policy) => { + policy.roots.push(policy.roots[0]); + }, + (policy) => { + policy.requiredTests.push(policy.requiredTests[0]); + }, + (policy) => { + policy.requiredTests[0].label = '//fixture:unqualified_test'; + }, + ]) { + const substituted = structuredClone(record); + change(substituted.construction[0].qualificationPolicy); + expect(() => validateNativePublicationMetadata(substituted)).toThrow(); + } + }, + { producerCapture: true, ownerPolicy: true }, + ); +}); + +test('explicit reviewed controller sealing retains authenticated main assurance without granting release authority', async () => { + await fixture( + async ({ input, transports, directory, requests }) => { + const prepared = { ...preparation(input), reviewedSource: source }; + const artifacts = await writePreparedNativePublicationMetadata( + path.join(directory, 'reviewed'), + prepared, + transports, + ); + expect(requests).toEqual(['auth']); + for (const artifact of artifacts) { + const record = JSON.parse(readFileSync(artifact.path, 'utf8')); + const assurance = record.builds[0].producerAssurance; + expect(assurance.scope).toBe('reviewed-producer-assurance'); + expect(assurance.reviewedSource).toEqual(source); + expect(assurance.event).toBe('push'); + expect(assurance.ref).toBe('refs/heads/main'); + expect(assurance.artifact.name).toBe('native-build-evidence-x86_64'); + expect(assurance.shippingAnalysis).toBe('bound'); + expect(assurance.requiredTests).toEqual(record.builds[0].requiredTests); + expect(record.builds[0].unverified).not.toContain( + 'immutable input lifetime from the producing build through content capture', + ); + expect(record.unverified).not.toContain( + 'native action-graph dump bytes authenticated by the producing invocation', + ); + expect(record.unverified).toContain( + 'qualified mapping from pre-envelope members to every delivered product contract', + ); + expect(record.baselineAdmission).toBe('unknown'); + expect(record.releaseDecision).toBe('unverified'); + expect(record.carriers[0].packageDependencies[0].requirement).toBe('=0.3.2'); + for (const change of [ + (a) => { + a.reviewedSource.commit = '9'.repeat(40); + }, + (a) => { + a.ref = 'refs/heads/release'; + }, + (a) => { + a.event = 'pull_request'; + }, + (a) => { + a.github.job = 'Linux runtime (aarch64)'; + }, + (a) => { + a.artifact.id += 1; + }, + (a) => { + a.evidenceDigest = `sha256:${'9'.repeat(64)}`; + }, + (a) => { + a.requiredTests.pop(); + }, + (a) => { + a.acceptedExecutionAssumptions.push('all products are qualified'); + }, + ]) { + const altered = structuredClone(record); + change(altered.builds[0].producerAssurance); + expect(() => validateNativePublicationMetadata(altered)).toThrow(); + } + const undefinedAssurance = structuredClone(record); + undefinedAssurance.builds[0].producerAssurance = undefined; + expect(() => validateNativePublicationMetadata(undefinedAssurance)).toThrow(); + } + }, + { producerCapture: true }, + ); +}); + +test('reviewed metadata rejects PR and substituted producer origins before sealing files', async () => { + for (const change of [ + (input, _origin) => { + input.builds[0].expected.event = 'pull_request'; + input.builds[0].expected.ref = 'refs/pull/1/merge'; + }, + (input, _origin) => { + input.builds[0].expected.ref = 'refs/heads/release'; + }, + (_input, origin) => { + origin.github.runAttempt += 1; + }, + (_input, origin) => { + origin.artifact.name = 'native-build-evidence-aarch64'; + }, + (input, _origin) => { + input.builds[0].requiredTests[0].configuration = '9'.repeat(64); + }, + ]) + await fixture( + async ({ input, origin, transports, directory }) => { + change(input, origin); + const destination = path.join(directory, 'reviewed'); + await expect( + writePreparedNativePublicationMetadata( + destination, + { ...preparation(input), reviewedSource: source }, + transports, + ), + ).rejects.toThrow(); + expect(existsSync(destination)).toBe(false); + }, + { producerCapture: true }, + ); + await fixture(async ({ input, transports, directory }) => { + const destination = path.join(directory, 'legacy-analysis'); + await expect( + writePreparedNativePublicationMetadata( + destination, + { ...preparation(input), reviewedSource: source }, + transports, + ), + ).rejects.toThrow(/producing-analysis/); + expect(existsSync(destination)).toBe(false); + }); +}); + +test('actual controller CLI rejects a substituted checkout before reading suppliers or sealing', () => { + const result = spawnSync( + process.execPath, + [ + path.join(import.meta.dir, 'native-publication-metadata.mts'), + '--lock', + '/missing/lock.json', + '--builds', + '/missing/builds.json', + '--repository', + 'f0rr0/oliphaunt', + '--bazel-version', + '8.8.1', + '--output-directory', + '/missing/sealed', + '--reviewed-source-ref', + 'HEAD', + ], + { + encoding: 'utf8', + env: { + ...process.env, + OLIPHAUNT_GIT_SOURCE_JSON: JSON.stringify({ + ref: 'HEAD', + commit: source.commit, + tree: source.tree, + checkout: source.commit, + }), + }, + }, + ); + expect(result.status).toBe(1); + expect(result.stdout).toBe(''); + expect(result.stderr).toContain('frozen clean exact source checkout'); +}); + +test('controller sealing is canonical, immutable and requires initial supplier authentication', async () => { + await fixture(async ({ input, transports, directory }) => { + const destination = path.join(directory, 'controller-sealed'); + await expect( + writePreparedNativePublicationMetadata(destination, preparation(input), { + authenticate: async () => { + throw new Error('supplier artifact is unauthenticated'); + }, + }), + ).rejects.toThrow(/unauthenticated/); + expect(existsSync(destination)).toBe(false); + const artifacts = await writePreparedNativePublicationMetadata( + destination, + preparation(input), + transports, + ); + expect(artifacts.map((row) => row.name)).toEqual([ + 'alpha-1.0.0-native-baseline.json', + 'beta-2.0.0-native-baseline.json', + ]); + expect( + artifacts.every( + (row) => row.role === 'github-release-metadata' && row.kind === 'native-baseline', + ), + ).toBe(true); + const before = readFileSync(artifacts[0].path); + await writePreparedNativePublicationMetadata(destination, preparation(input), transports); + expect(readFileSync(artifacts[0].path)).toEqual(before); + const changed = preparation(structuredClone(input)); + changed.builds[0].requiredTests = changed.builds[0].requiredTests.slice(0, 1); + await expect( + writePreparedNativePublicationMetadata(destination, changed, transports), + ).rejects.toThrow(); + expect(readFileSync(artifacts[0].path)).toEqual(before); + }); +}); + +test('measured native metadata bound preserves the default receipt limit and immutable reruns', async () => { + await fixture(async ({ directory }) => { + const record = { data: 'x'.repeat(17 * 1024 * 1024) }; + const defaultFile = path.join(directory, 'default.json'); + await expect(writeImmutableReceipt(defaultFile, record)).rejects.toThrow( + /exceeds 16777216 bytes/, + ); + expect(existsSync(defaultFile)).toBe(false); + const nativeFile = path.join(directory, 'native.json'); + await writeImmutableReceipt(nativeFile, record, { + maximumBytes: NATIVE_PUBLICATION_METADATA_MAX_BYTES, + }); + await writeImmutableReceipt(nativeFile, record, { + maximumBytes: NATIVE_PUBLICATION_METADATA_MAX_BYTES, + }); + expect(JSON.parse(readFileSync(nativeFile, 'utf8'))).toEqual(record); + await expect(writeImmutableReceipt(nativeFile, record, { maximumBytes: 1 })).rejects.toThrow( + /is \d+ bytes, exceeds 1 bytes/, + ); + await expect( + writeImmutableReceipt(nativeFile, record, { maximumBytes: Infinity }), + ).rejects.toThrow(/positive safe integer/); + expect(JSON.parse(readFileSync(nativeFile, 'utf8'))).toEqual(record); + }); +}); + +test('public baseline joins completed source and signed public bytes without an expiring Actions read', async () => { + await fixture( + async ({ input, transports, directory, requests }) => { + const [artifact] = await writePreparedNativePublicationMetadata( + path.join(directory, 'sealed'), + { ...preparation(input), reviewedSource: source }, + transports, + ); + requests.length = 0; + const publication = { + product: 'alpha', + version: '1.0.0', + tagName: 'alpha-v1.0.0', + publicationSha: source.commit, + publicationTree: source.tree, + releaseSha: 'f'.repeat(40), + }; + const subjects = [ + subject(artifact.name, artifact.sha256), + subject('other-product.tgz', '9'.repeat(64)), + ]; + const bundlePath = bundle(directory, subjects); + const release = { + id: 20, + tag_name: publication.tagName, + target_commitish: source.commit, + draft: false, + prerelease: false, + }; + const asset = { + id: 30, + name: artifact.name, + state: 'uploaded', + url: 'https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/30', + size: artifact.size, + digest: `sha256:${artifact.sha256}`, + }; + let signatures = 0; + const publicTransports = { + assertCompleted: async (requested) => { + requests.push('completion'); + return requested; + }, + readJson: async () => release, + readPages: async () => [asset], + proveAsset: async () => { + throw new Error('digest-bearing API asset needs no fallback download'); + }, + verifyAttestation: async ({ file, artifact, repository, publisherSha }) => { + signatures++; + return verifyAttestationBundleSubject( + { + file, + name: artifact.name, + sha256: artifact.sha256, + repo: repository, + publisherSha, + bundlePath, + }, + { verifyBundleImpl: async () => normalizedSubjects(subjects) }, + ); + }, + }; + const request = { + publication, + file: artifact.path, + publisherSha: 'e'.repeat(40), + bundlePaths: [bundlePath], + }; + const result = await readCompletedNativePublicBaseline(request, publicTransports); + expect(requests).toEqual(['completion']); + expect(signatures).toBe(1); + expect(result.metadata.builds[0].artifact.id).toBe(101); + expect(result.metadata.builds[0].producerAssurance.ref).toBe('refs/heads/main'); + expect(result.publicOrigin.sha256).toBe(artifact.sha256); + expect(result.baselineAdmission).toBe('unknown'); + expect(() => assertAuthenticatedNativePublicBaseline(result)).toThrow( + 'authenticated completed metadata origin', + ); + const autoBundle = JSON.parse(readFileSync(bundlePath, 'utf8')); + const statement = JSON.parse( + Buffer.from(autoBundle.dsseEnvelope.payload, 'base64').toString('utf8'), + ); + statement.predicate = { + buildDefinition: { + externalParameters: { + workflow: { + repository: 'https://github.com/f0rr0/oliphaunt', + ref: 'refs/heads/main', + path: '.github/workflows/release.yml', + }, + }, + resolvedDependencies: [ + { + uri: 'git+https://github.com/f0rr0/oliphaunt@refs/heads/main', + digest: { gitCommit: 'e'.repeat(40) }, + }, + ], + }, + }; + autoBundle.dsseEnvelope.payload = Buffer.from(JSON.stringify(statement)).toString('base64'); + const automatic = await readCompletedNativePublicBaseline( + { publication, file: artifact.path }, + { + ...publicTransports, + readPages: async (endpoint, options) => { + if (endpoint.includes('/attestations/sha256:')) { + expect(options.itemsField).toBe('attestations'); + expect(endpoint).toEndWith(artifact.sha256); + return [{ bundle: {} }, { bundle: autoBundle }, { bundle: autoBundle }]; + } + return [asset]; + }, + verifyAttestation: async ({ publisherSha, bundlePaths }) => { + expect(publisherSha).toBe('e'.repeat(40)); + expect(JSON.parse(readFileSync(bundlePaths[0], 'utf8'))).toEqual(autoBundle); + return { subjects: normalizedSubjects(subjects) }; + }, + }, + ); + expect(automatic.publicOrigin.publisherSha).toBe('e'.repeat(40)); + await expect( + readCompletedNativePublicBaseline( + { publication, file: artifact.path }, + { + ...publicTransports, + readPages: async (endpoint) => + endpoint.includes('/attestations/') ? [{ bundle: autoBundle }] : [asset], + verifyAttestation: async () => { + throw new Error('actual signer differs from unsigned lookup'); + }, + }, + ), + ).rejects.toThrow('authenticated exact attestation subject'); + for (const overrides of [ + { + assertCompleted: async (requested) => ({ ...requested, publicationTree: '9'.repeat(40) }), + }, + { readJson: async () => ({ ...release, target_commitish: '9'.repeat(40) }) }, + { readJson: async () => ({ ...release, draft: true }) }, + { readPages: async () => [] }, + { readPages: async () => [asset, asset] }, + { readPages: async () => [{ ...asset, digest: `sha256:${'9'.repeat(64)}` }] }, + { verifyAttestation: async () => true }, + { verifyAttestation: async () => ({ subjects: [subject(artifact.name, '9'.repeat(64))] }) }, + ]) + await expect( + readCompletedNativePublicBaseline(request, { ...publicTransports, ...overrides }), + ).rejects.toThrow(); + await expect( + readCompletedNativePublicBaseline(request, { + ...publicTransports, + verifyAttestation: async () => { + writeFileSync( + artifact.path, + Buffer.concat([readFileSync(artifact.path), Buffer.from(' ')]), + ); + return { subjects: normalizedSubjects(subjects) }; + }, + }), + ).rejects.toThrow(/changed/); + }, + { producerCapture: true }, + ); +}); + +test('a single public metadata subject may share a bundle without accepting substituted verified subjects', async () => { + await fixture(async ({ directory }) => { + const file = path.join(directory, 'metadata.json'); + const bytes = Buffer.from('{}'); + writeFileSync(file, bytes); + const subjects = [subject('metadata.json', hash(bytes)), subject('other.tgz', '9'.repeat(64))]; + const bundlePath = bundle(directory, subjects); + const request = { + bundlePath, + file, + name: 'metadata.json', + sha256: hash(bytes), + repo: 'f0rr0/oliphaunt', + publisherSha: 'e'.repeat(40), + }; + const verified = await verifyAttestationBundleSubject(request, { + verifyBundleImpl: async () => normalizedSubjects(subjects), + }); + expect(verified.subjects).toEqual(normalizedSubjects(subjects)); + await expect( + verifyAttestationBundleSubject( + { ...request, sha256: '8'.repeat(64) }, + { verifyBundleImpl: async () => subjects }, + ), + ).rejects.toThrow(/exact subject digest/); + await expect( + verifyAttestationBundleSubject(request, { verifyBundleImpl: async () => [subjects[0]] }), + ).rejects.toThrow(/verified asset subjects differ/); + }); +}); + +test('native metadata inventory is explicit, separate from payload checksums and cannot authorize freeze', async () => { + await fixture(async ({ input, transports, directory }) => { + const [record] = await prepareNativePublicationMetadata(preparation(input), transports); + // This controller-preview fixture uses a real canonical owner/catalog, but + // its observation remains synthetic construction, never admission proof. + const product = loadPublicationCatalog('native-metadata fixture', { + products: ['oliphaunt-query'], + }).products[0]; + record.product = product; + for (const carrier of record.carriers) { + carrier.product = product.id; + carrier.version = product.version; + } + for (const construction of record.construction) + for (const root of construction.roots) { + root.package.product = product.id; + root.package.version = product.version; + } + const row = nativePublicationMetadataArtifactRow(product); + const sealedDirectory = path.join(directory, 'controller-sealed'); + mkdirSync(sealedDirectory); + const file = path.join(sealedDirectory, row.name); + writeFileSync(file, JSON.stringify(record)); + expect(expectedProductArtifactRows([product])).toEqual([]); + expect( + expectedProductArtifactRows([product], { nativeMetadataProducts: [product.id] }), + ).toEqual([row]); + expect(() => + expectedProductArtifactRows([product], { nativeMetadataProducts: ['unknown'] }), + ).toThrow(/selected product IDs/); + expect(() => + expectedProductArtifactRows([product], { nativeMetadataProducts: [product.id, product.id] }), + ).toThrow(/unique selected/); + expect(discoverProductArtifacts([sealedDirectory], [product])).toEqual([]); + const discovered = discoverProductArtifacts([sealedDirectory], [product], { + nativeMetadataProducts: [product.id], + nativeMetadataSource: source, + }); + expect(discovered).toHaveLength(1); + expect(discovered[0].sha256).toBe(hash(readFileSync(file))); + expect(() => + discoverProductArtifacts([sealedDirectory], [product], { + nativeMetadataProducts: [product.id], + nativeMetadataSource: { ...source, commit: '9'.repeat(40) }, + }), + ).toThrow(/source/); + const before = process.env.OLIPHAUNT_GIT_SOURCE_JSON; + process.env.OLIPHAUNT_GIT_SOURCE_JSON = JSON.stringify({ + ...source, + checkout: source.commit, + ref: source.commit, + }); + try { + const legacy = buildPublicationCandidate({ + products: [product.id], + artifactRoots: [sealedDirectory], + allowMissing: true, + headRef: source.commit, + }); + expect(legacy.scope).toBeUndefined(); + expect(legacy.productArtifacts).toEqual([]); + const candidate = buildPublicationCandidate({ + products: [product.id], + artifactRoots: [sealedDirectory], + allowMissing: true, + headRef: source.commit, + nativeMetadataProducts: [product.id], + }); + expect(validatePublicationCandidate(candidate).scope).toBe('construction'); + expect(() => freezePublicationCandidate(candidate)).toThrow(/cannot freeze/); + delete candidate.scope; + expect(() => freezePublicationCandidate(candidate)).toThrow(/requires construction scope/); + expect(() => validatePublicationLock(candidate)).toThrow(/construction evidence/); + } finally { + if (before === undefined) delete process.env.OLIPHAUNT_GIT_SOURCE_JSON; + else process.env.OLIPHAUNT_GIT_SOURCE_JSON = before; + } + }); +}); diff --git a/tools/release/native-publication-observation.mts b/tools/release/native-publication-observation.mts new file mode 100644 index 000000000..886c6fb09 --- /dev/null +++ b/tools/release/native-publication-observation.mts @@ -0,0 +1,317 @@ +/** Shared observed construction for preparation and completed publication. */ + +import path from 'node:path'; +import { type CoverageAuthority, checkShippingCoverage } from '../bazel/shipping-coverage.mts'; +import { + assureReviewedNativeBuildProducer, + authenticateNativeBuildEvidence, + reviewedNativeProducerUnknowns, +} from './authenticate-native-build-evidence.mts'; +import { buildShippingInputView, canonicalShippingLabel } from './bazel-shipping-inputs.mts'; +import { + type NativeBuildEvidence, + type NativeBuildSource, + type NativeRequiredTest, + nativeRequiredCaptureInputs, + validateNativeBuildEvidence, +} from './native-build-qualification.mts'; +import type { NativeRoot } from './native-publication-artifacts.mts'; +import { isNativePreEnvelopePayloadRoot } from './native-publication-payloads.mts'; +import { consumerDigest } from './publication-consumer-proof.mts'; + +type Row = Record; +type Authenticated = { + origin: Awaited>; + qualification: ReturnType; + evidence: NativeBuildEvidence; + producerAssurance?: Awaited>['assurance']; +}; +export type NativePublicationBuild = { + evidenceRoot: string; + expected: Parameters[1]; + requiredTests: NativeRequiredTest[]; +}; +export type NativePublicationFile = { path: string; sha256: string; size: number }; +export function assertNativePublicationBuildPlan(builds: NativePublicationBuild[]) { + if ( + !Array.isArray(builds) || + !builds.length || + builds.some((build) => !Array.isArray(build.requiredTests) || !build.requiredTests.length) + ) + throw new Error( + 'native observations require an explicit nonempty configured test plan for every build', + ); +} +function equal(actual: unknown, expected: unknown, context: string) { + if (consumerDigest(actual) !== consumerDigest(expected)) throw new Error(`${context} mismatch`); +} +/** Envelope and files are prevalidated together at their exact source; no historical catalog rehydration. */ +export async function observeNativePublicationConstruction( + { + envelope: lock, + files, + repository, + bazelVersion, + builds: requestedBuilds, + reviewedSource, + }: { + envelope: Row; + files: NativePublicationFile[]; + repository: string; + bazelVersion: string; + builds: NativePublicationBuild[]; + /** Explicit controller opt-in; PR/legacy observations do not assert producer discipline. */ + reviewedSource?: NativeBuildSource; + }, + { authenticate = authenticateNativeBuildEvidence } = {}, +) { + assertNativePublicationBuildPlan(requestedBuilds); + const authenticated = []; + for (const build of requestedBuilds) { + equal(build.expected.source, lock.source, 'native build/frozen source'); + equal(build.expected.github.repository, repository, 'native build repository'); + const reviewed = + reviewedSource === undefined + ? undefined + : await assureReviewedNativeBuildProducer( + build.evidenceRoot, + { + expected: build.expected, + reviewedSource, + bazelVersion, + requiredTests: build.requiredTests, + }, + { authenticate }, + ); + const origin = reviewed?.origin ?? (await authenticate(build.evidenceRoot, build.expected)); + const qualification = + reviewed?.qualification ?? + validateNativeBuildEvidence(origin.evidence, { + source: lock.source, + github: build.expected.github, + bazelVersion, + requiredTests: build.requiredTests, + }); + if (qualification.testQualification !== 'passed') + throw new Error('completed native observations require successful configured tests'); + equal(origin.github, qualification.github, 'authenticated native build origin'); + authenticated.push({ + origin, + qualification: reviewed + ? { ...qualification, unverified: reviewedNativeProducerUnknowns(qualification.unverified) } + : qualification, + evidence: origin.evidence as NativeBuildEvidence, + ...(reviewed ? { producerAssurance: reviewed.assurance } : {}), + }); + } + return projectNativePublicationConstruction({ envelope: lock, files }, authenticated); +} + +/** Reuse an already observed producer set for a selected envelope. This projection + * does not authenticate origins or grant publication authority. */ +export function projectNativePublicationConstruction( + { envelope: lock, files }: { envelope: Row; files: NativePublicationFile[] }, + authenticated: Authenticated[], +) { + const selected = new Set(lock.products.map((product) => product.id)); + // The only conditional final input is constructed for the actual release + // selection, after the unconditional product inventory has been qualified. + const cohorts = authenticated + .flatMap(({ evidence }) => evidence.cohorts) + .map((cohort) => ({ + ...cohort, + roots: cohort.roots.filter( + (root) => + selected.has(root.package.product) && + !( + lock.artifactPhase === 'pre-version' && + root.package.product === 'oliphaunt-swift' && + root.package.name === 'swiftpm-extension-consumer-fixture' && + root.package.role === 'release-input' && + root.package.configuration === 'portable' + ), + ), + })) + .filter((cohort) => cohort.roots.length > 0); + const authority: CoverageAuthority = { + catalog: { + schema: lock.catalogSchema, + products: lock.products, + carriers: lock.carriers.filter((carrier) => carrier.declared), + }, + artifactRows: lock.productArtifacts.map((artifact) => ({ + ...artifact, + version: lock.products.find((product) => product.id === artifact.product).version, + })), + resolveCarrier: (ecosystem, name) => { + const carrier = lock.carriers.find((row) => row.id === `${ecosystem}:${name}`); + if (!carrier) throw new Error(`carrier absent from frozen publication: ${ecosystem}:${name}`); + return carrier; + }, + }; + const coverage = checkShippingCoverage(authority, cohorts, { includeReleaseInputs: true }); + const capturedFiles = (root: NativeRoot, cohort: NativeBuildEvidence['cohorts'][number]) => + root.package.outputs.flatMap((output) => { + const capture = cohort.outputs.find((capture) => capture.path === output.path); + if (!capture) throw new Error(`missing qualified output capture: ${output.path}`); + return capture.members + .filter((member) => member.type === 'file') + .map((member) => ({ + ...member, + path: member.path ? `${output.path}/${member.path}` : output.path, + })); + }); + const bind = (artifact: Row, product: string, roots: { root: NativeRoot; cohort: any }[]) => { + const concrete = files.filter( + (file) => file.path === artifact.path || file.path.startsWith(`${artifact.path}/`), + ); + if (!concrete.length) + throw new Error(`missing frozen concrete files: ${product}/${artifact.path}`); + if (concrete[0].path === artifact.path) { + equal( + concrete, + [{ path: artifact.path, sha256: artifact.sha256, size: artifact.size }], + 'frozen file envelope', + ); + } else if (concrete.reduce((size, file) => size + file.size, 0) !== artifact.size) { + throw new Error(`incomplete frozen directory file list: ${product}/${artifact.path}`); + } + return concrete.map((file) => { + const suffix = + file.path === artifact.path + ? path.posix.basename(file.path) + : file.path.slice(artifact.path.length + 1); + const matches = roots.flatMap(({ root, cohort }) => + capturedFiles(root, cohort) + .filter( + (member) => + (file.path === artifact.path + ? path.posix.basename(member.path) === suffix + : root.package.outputs.some( + (output) => member.path === `${output.path}/${suffix}`, + )) && + member.sha256 === file.sha256 && + member.size === file.size, + ) + .map((member) => ({ + label: root.label, + path: member.path, + sha256: member.sha256, + size: member.size, + })), + ); + if (matches.length !== 1) + throw new Error(`frozen file needs one qualified output: ${product}/${file.path}`); + return { frozenPath: file.path, ...matches[0] }; + }); + }; + const products = lock.products.map((product) => { + const roots = cohorts.flatMap((cohort) => + cohort.roots + .filter((root) => root.package.product === product.id) + .map((root) => ({ root, cohort })), + ); + const carriers = lock.carriers + .filter((carrier) => carrier.product === product.id) + .map((carrier) => { + const carrierRoots = roots.filter( + ({ root }) => + `${root.package.ecosystem}:${root.package.name}` === + (carrier.parentCarrier ?? carrier.id), + ); + return { + ...carrier, + qualifiedFiles: carrier.artifacts.flatMap((artifact) => + bind(artifact, product.id, carrierRoots), + ), + }; + }); + const productArtifacts = lock.productArtifacts + .filter((artifact) => artifact.product === product.id) + .map((artifact) => ({ + ...artifact, + qualifiedFiles: bind( + artifact, + product.id, + roots.filter( + ({ root }) => + root.package.name === artifact.name && root.package.role === artifact.role, + ), + ), + })); + const construction = authenticated.flatMap(({ origin, evidence, qualification }) => + evidence.cohorts.flatMap((cohort, index) => { + const selectedRoots = cohort.roots.filter((root) => root.package.product === product.id); + if (!selectedRoots.length) return []; + const view = buildShippingInputView( + { + schema: 'oliphaunt-bazel-shipping-v1', + scope: 'construction', + packages: selectedRoots.map((root) => root.package), + }, + cohort.aquery, + ); + const needed = new Set([...view.physicalInputs, ...nativeRequiredCaptureInputs(view)]); + const analysisPaths = + cohort.rootAnalysisInputPaths === undefined + ? undefined + : [ + ...new Set( + cohort.rootAnalysisInputPaths + .filter((row) => + selectedRoots.some( + (root) => canonicalShippingLabel(root.label) === row.label, + ), + ) + .flatMap((row) => row.paths), + ), + ].sort(); + return [ + { + evidenceDigest: origin.evidenceDigest, + invocationId: qualification.cohorts[index].invocationId, + shippingAnalysis: cohort.producerCapture === undefined ? 'unverified' : 'bound', + unverified: qualification.unverified, + roots: qualification.cohorts[index].roots.filter( + (root) => root.package.product === product.id, + ), + actions: view.products[product.id].actions, + inputs: cohort.inputs.filter((input) => needed.has(input.path)), + // Index the causal leaves in the same captured input records. Generated + // intermediates remain evidence, but cannot stand in for source changes. + leafInputPaths: view.products[product.id].inputs, + ...(analysisPaths === undefined + ? {} + : { + analysisInputPaths: analysisPaths, + analysisInputs: cohort.analysisInputs!.filter((input) => + analysisPaths.includes(input.path), + ), + }), + ...(qualification.cohorts[index].qualificationPolicy + ? { qualificationPolicy: qualification.cohorts[index].qualificationPolicy } + : {}), + ...(cohort.seedConstructions?.some((receipt) => needed.has(receipt.path)) + ? { + seedConstructions: cohort.seedConstructions.filter((receipt) => + needed.has(receipt.path), + ), + } + : {}), + }, + ]; + }), + ); + return { + product: structuredClone(product), + carriers, + productArtifacts, + construction, + preEnvelopeCapture: roots.some(({ root }) => isNativePreEnvelopePayloadRoot(root)) + ? 'observed' + : 'absent', + baselineAdmission: 'unknown' as const, + }; + }); + return { products, authenticated, coverage }; +} diff --git a/tools/release/native-publication-payloads.mts b/tools/release/native-publication-payloads.mts new file mode 100644 index 000000000..6ea56060e --- /dev/null +++ b/tools/release/native-publication-payloads.mts @@ -0,0 +1,302 @@ +/** Declared pre-envelope bytes; neither capture nor comparison grants release authority. */ +import { createHash } from 'node:crypto'; +import path from 'node:path'; +import type { CompletedPublication } from './completed-release-publication.mts'; +import type { NativeRoot, PhysicalShippingCohort } from './native-publication-artifacts.mts'; +import { + captureNativeOutputMembers, + type NativeOutputMember, +} from './native-publication-staging.mts'; + +type Source = { commit: string; tree: string }; +export interface NativePayloadProduct { + id: string; + version: string; + roots: { + label: string; + executionRoot: string; + name: string; + configuration: string; + role: string; + outputs: { path: string; owner: string; members: NativeOutputMember[] }[]; + }[]; +} +export interface NativePayloads { + scope: 'construction'; + source: Source; + products: NativePayloadProduct[]; +} +export interface NativePayloadCohort extends PhysicalShippingCohort { + source: Source; +} + +const compareText = (left: string, right: string) => (left < right ? -1 : left > right ? 1 : 0); +function canonical(value: unknown): string { + if (Array.isArray(value)) return `[${value.map(canonical).join(',')}]`; + if (value && typeof value === 'object') + return `{${Object.entries(value) + .sort(([a], [b]) => compareText(a, b)) + .map(([key, child]) => `${JSON.stringify(key)}:${canonical(child)}`) + .join(',')}}`; + return JSON.stringify(value); +} +function nonempty(value: unknown): asserts value is string { + if (typeof value !== 'string' || !value || /[\u0000-\u001f\u007f]/u.test(value)) + throw new Error('native payload requires a nonempty identity'); +} +function source(value: Source) { + if (![value?.commit, value?.tree].every((sha) => /^[0-9a-f]{40}$/u.test(sha ?? ''))) + throw new Error('native payload requires exact source SHA and tree'); +} +function rootKey(root: { name: string; configuration: string; role: string }) { + return canonical([root.name, root.configuration, root.role]); +} +export function nativePayloadDigest(product: NativePayloadProduct) { + return createHash('sha256').update(canonical(product)).digest('hex'); +} + +export function isNativePreEnvelopePayloadRoot(root: NativeRoot) { + const pkg = root.package; + return pkg.ecosystem === 'internal' && !['compiled-source', 'abi-contract'].includes(pkg.role); +} + +/** Reads only supplied internal ShippingInfo outputs, never guessed source directories. */ +export function captureNativePreEnvelopePayloads( + cohorts: NativePayloadCohort[], + { source: frozen, products }: { source: Source; products: { id: string; version: string }[] }, +) { + source(frozen); + const observed = new Map(); + for (const product of products) { + nonempty(product.id); + nonempty(product.version); + if (observed.has(product.id)) throw new Error(`duplicate native payload product ${product.id}`); + observed.set(product.id, { id: product.id, version: product.version, roots: [] }); + } + const captures: ReturnType[] = []; + for (const cohort of cohorts) { + source(cohort.source); + if (canonical(cohort.source) !== canonical(frozen)) + throw new Error('native payload cohort does not match the frozen source'); + for (const root of cohort.roots as NativeRoot[]) { + const pkg = root.package; + const product = observed.get(pkg.product); + if (!isNativePreEnvelopePayloadRoot(root) || !product) continue; + if (pkg.version !== product.version) + throw new Error(`native payload version disagrees for ${product.id}`); + for (const value of [root.label, pkg.name, pkg.configuration, pkg.role]) nonempty(value); + if (!Array.isArray(pkg.outputs) || !pkg.outputs.length) + throw new Error(`native payload root has no declared outputs: ${root.label}`); + if (product.roots.some((previous) => rootKey(previous) === rootKey(pkg))) + throw new Error(`duplicate native payload root: ${product.id}:${rootKey(pkg)}`); + const names = new Set(); + const outputs = pkg.outputs.map((output) => { + nonempty(output.owner); + const name = path.posix.basename(output.path); + if (names.has(name)) throw new Error(`ambiguous native payload output: ${root.label}`); + names.add(name); + const capture = captureNativeOutputMembers(cohort.executionRoot, output.path); + captures.push(capture); + return { ...output, members: capture.members }; + }); + product.roots.push({ + label: root.label, + executionRoot: cohort.executionRoot, + name: pkg.name, + configuration: pkg.configuration, + role: pkg.role, + outputs: outputs.sort((a, b) => compareText(a.path, b.path)), + }); + } + } + for (const product of observed.values()) + product.roots.sort((a, b) => compareText(rootKey(a), rootKey(b))); + const payloads: NativePayloads = { + scope: 'construction', + source: { ...frozen }, + products: [...observed.values()].sort((a, b) => compareText(a.id, b.id)), + }; + return { + payloads, + assertUnchanged() { + for (const capture of captures) capture.assertUnchanged(); + }, + }; +} + +type DeliveryPayload = { + name: string; + configuration: string; + role: string; + outputs: { name: string; members: NativeOutputMember[] }[]; +}; +/** + * Supplied by an authenticated origin/qualified-contract adapter, not by labels + * or aquery. Physical modes can differ from the producer's declared shipping + * modes; that adapter must provide the complete existing contract's mapping. + */ +export interface NativeDeliveryVerification { + source: Source; + product: string; + version: string; + payloadDigest: string; + deliveredPayloads: DeliveryPayload[]; +} +export interface NativeCompletedPayloadOrigin { + publication: CompletedPublication; + payloads: NativePayloads; +} + +function deliveryShape(product: NativePayloadProduct): DeliveryPayload[] { + return product.roots.map(({ name, configuration, role, outputs }) => ({ + name, + configuration, + role, + outputs: outputs + .map(({ path: output, members }) => ({ + name: path.posix.basename(output), + members: [...members].sort((a, b) => compareText(a.path, b.path)), + })) + .sort((a, b) => compareText(a.name, b.name)), + })); +} +function checkedDelivery( + verification: NativeDeliveryVerification, + product: NativePayloadProduct, + frozen: Source, +) { + if ( + !verification || + canonical(verification.source) !== canonical(frozen) || + verification.product !== product.id || + verification.version !== product.version || + verification.payloadDigest !== nativePayloadDigest(product) || + !Array.isArray(verification.deliveredPayloads) + ) + throw new Error( + 'native delivery verification does not bind the captured product/source/payload', + ); + const delivered = structuredClone(verification.deliveredPayloads); + for (const root of delivered) { + if (!Array.isArray(root.outputs)) throw new Error('native delivery contract is incomplete'); + for (const output of root.outputs) { + if (!Array.isArray(output.members)) throw new Error('native delivery contract is incomplete'); + for (const member of output.members) + if (!Number.isInteger(member.mode) || member.mode < 0 || member.mode > 0o777) + throw new Error('native delivery contract has an invalid mode'); + output.members.sort((a, b) => compareText(a.path, b.path)); + } + root.outputs.sort((a, b) => compareText(a.name, b.name)); + } + delivered.sort((a, b) => compareText(rootKey(a), rootKey(b))); + const withoutModes = (value) => + value.map((root) => ({ + ...root, + outputs: root.outputs.map((output) => ({ + ...output, + members: output.members.map(({ mode: _mode, ...member }) => member), + })), + })); + if (canonical(withoutModes(delivered)) !== canonical(withoutModes(deliveryShape(product)))) + throw new Error( + 'native delivery contract must cover every captured member and its exact bytes', + ); + return delivered; +} + +function deliveryIdentity(payloads: DeliveryPayload[]) { + return payloads.map((root) => ({ + ...root, + // A singleton directory is rooted by its ShippingInfo identity. Its Bazel + // wrapper is still bound above, but is not a delivered member inside it. + // A regular File's basename remains part of its delivered identity. + outputs: root.outputs.map((output) => ({ + ...output, + name: + root.outputs.length === 1 && + output.members.some((member) => member.path === '' && member.type === 'directory') + ? '' + : output.name, + })), + })); +} + +/** + * Input affectedness requests build/check work, not publication. Only qualified + * delivered members can be compared to an authenticated completed origin. + * Missing adapters are unknown. Even a conditional verdict retains construction + * scope: the existing candidate/lock guard still forbids publication admission. + */ +export async function compareNativePreEnvelopeDelivery( + current: NativePayloads, + origins: Record, + { + affectedProducts, + verifyOrigin, + verifyQualifiedCoverage, + }: { + affectedProducts?: string[]; + verifyOrigin?: ( + origin: NativeCompletedPayloadOrigin, + product: NativePayloadProduct, + ) => Promise<(NativeDeliveryVerification & { publication: CompletedPublication }) | undefined>; + verifyQualifiedCoverage?: ( + current: NativePayloads, + product: NativePayloadProduct, + ) => Promise; + } = {}, +) { + source(current.source); + if (current.scope !== 'construction') + throw new Error('native payload comparison is construction'); + const results = []; + const ids = [ + ...new Set([...current.products.map(({ id }) => id), ...Object.keys(origins)]), + ].sort(); + for (const id of ids) { + const product = current.products.find((product) => product.id === id); + const origin = origins[id]; + const result = { + product: id, + affectedBuild: + affectedProducts === undefined + ? ('unknown' as const) + : affectedProducts.includes(id) + ? ('required' as const) + : ('not-required' as const), + necessaryDelivery: 'unknown' as 'needed' | 'not-needed' | 'unknown', + reason: 'current-pre-envelope-roots-missing', + }; + if (product?.roots.length) { + result.reason = 'completed-origin-missing'; + const previous = origin?.payloads.products.find((product) => product.id === id); + if (previous?.roots.length) { + source(origin.payloads.source); + if ( + origin.publication.product !== id || + origin.publication.version !== previous.version || + origin.publication.publicationSha !== origin.payloads.source.commit || + origin.publication.publicationTree !== origin.payloads.source.tree + ) + throw new Error('native completed origin does not bind its product/source/payload'); + result.reason = 'completed-origin-unverified'; + const verifiedOrigin = await verifyOrigin?.(origin, previous); + if (verifiedOrigin !== undefined) { + if (canonical(verifiedOrigin.publication) !== canonical(origin.publication)) + throw new Error('native completed origin verification has a different publication'); + const before = checkedDelivery(verifiedOrigin, previous, origin.payloads.source); + result.reason = 'qualified-delivery-contract-unverified'; + const qualified = await verifyQualifiedCoverage?.(current, product); + if (qualified !== undefined) { + const after = checkedDelivery(qualified, product, current.source); + const same = canonical(deliveryIdentity(before)) === canonical(deliveryIdentity(after)); + result.necessaryDelivery = same ? 'not-needed' : 'needed'; + result.reason = same ? 'qualified-delivery-identical' : 'qualified-delivery-different'; + } + } + } + } + results.push(result); + } + return { scope: 'construction' as const, products: results }; +} diff --git a/tools/release/native-publication-payloads.test.mts b/tools/release/native-publication-payloads.test.mts new file mode 100644 index 000000000..059e01244 --- /dev/null +++ b/tools/release/native-publication-payloads.test.mts @@ -0,0 +1,552 @@ +import { expect, test } from 'bun:test'; +import { + chmodSync, + mkdirSync, + mkdtempSync, + readFileSync, + readdirSync, + renameSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { archiveDirectory } from '../packaging/archive-directory.mts'; +import { readPortableArchiveEntries } from '../packaging/portable-archive.mts'; +import { + captureNativePreEnvelopePayloads, + compareNativePreEnvelopeDelivery, + nativePayloadDigest, + type NativeCompletedPayloadOrigin, + type NativeDeliveryVerification, + type NativePayloadCohort, + type NativePayloadProduct, + type NativePayloads, +} from './native-publication-payloads.mts'; + +const initial = { commit: '1'.repeat(40), tree: '2'.repeat(40) }; +const updated = { commit: '3'.repeat(40), tree: '4'.repeat(40) }; + +async function fixture(run, ids = ['runtime', 'tools', 'sdk']) { + const executionRoot = mkdtempSync(path.join(os.tmpdir(), 'native-payload-facts-')); + const products = ids.map((id) => ({ id, version: '1.0.0' })); + const roots = products.map(({ id, version }) => { + const output = `bazel-out/fixture/bin/${id}/public_payload`; + const directory = path.join(executionRoot, output); + mkdirSync(path.join(directory, 'lib'), { recursive: true }); + writeFileSync(path.join(directory, 'lib/module.bin'), `${id} public bytes`); + writeFileSync(path.join(directory, 'LICENSE'), 'exact legal bytes'); + chmodSync(path.join(directory, 'lib/module.bin'), 0o644); + chmodSync(path.join(directory, 'LICENSE'), 0o644); + return { + label: `//fixture/${id}:shipping_payload`, + package: { + product: id, + version, + ecosystem: 'internal', + name: `${id}-public-payload`, + configuration: 'linux-x64-gnu', + role: 'construction', + outputs: [{ path: output, owner: `//fixture/${id}:payload` }], + }, + }; + }); + const cohort: NativePayloadCohort = { + source: initial, + executionRoot, + roots, + // There is deliberately no graph mirror or action-success surrogate. + get aquery() { + throw new Error('payload capture must not infer execution from aquery'); + }, + }; + const directory = (id) => path.join(executionRoot, `bazel-out/fixture/bin/${id}/public_payload`); + const capture = (source = initial, selected = products, cohorts = [cohort]) => + captureNativePreEnvelopePayloads( + cohorts.map((cohort) => + Object.defineProperties( + {}, + { + ...Object.getOwnPropertyDescriptors(cohort), + source: { value: source, enumerable: true, configurable: true }, + }, + ), + ) as NativePayloadCohort[], + { source, products: selected }, + ); + try { + // No checkout, source package path, conventional manifest or history exists here. + expect(readdirSync(executionRoot)).toEqual(['bazel-out']); + await run({ capture, cohort, products, directory, executionRoot }); + } finally { + rmSync(executionRoot, { recursive: true, force: true }); + } +} + +function origins(payloads: NativePayloads): Record { + return Object.fromEntries( + payloads.products.map((product) => [ + product.id, + { + publication: { + product: product.id, + version: product.version, + tagName: `${product.id}-v${product.version}`, + publicationSha: payloads.source.commit, + publicationTree: payloads.source.tree, + releaseSha: payloads.source.commit, + }, + payloads: structuredClone(payloads), + }, + ]), + ); +} + +// These synthetic adapters exercise only the conditional comparison contract. +// They are not an authenticated completed origin or real qualification adapter. +function verification(payloads: NativePayloads, product: NativePayloadProduct) { + return { + source: payloads.source, + product: product.id, + version: product.version, + payloadDigest: nativePayloadDigest(product), + deliveredPayloads: product.roots.map(({ name, role, configuration, outputs }) => ({ + name, + role, + configuration, + outputs: outputs.map(({ path: output, members }) => ({ + name: path.posix.basename(output), + members: structuredClone(members), + })), + })), + } satisfies NativeDeliveryVerification; +} +const syntheticVerifiers = { + verifyOrigin: async (origin, product) => ({ + ...verification(origin.payloads, product), + publication: origin.publication, + }), + verifyQualifiedCoverage: async (current, product) => verification(current, product), +}; + +test('captures only declared internal roots and binds their physical bytes to the exact source', async () => { + await fixture(({ capture, cohort, directory }) => { + const value = capture(); + expect(value.payloads.scope).toBe('construction'); + expect(value.payloads.source).toEqual(initial); + expect(value.payloads.products).toHaveLength(3); + const root = value.payloads.products.find(({ id }) => id === 'tools')!.roots[0]; + expect(root.outputs[0].members.find(({ path }) => path === 'LICENSE')).toMatchObject({ + type: 'file', + mode: 0o644, + size: 17, + }); + const foreign = Object.defineProperties( + {}, + { + ...Object.getOwnPropertyDescriptors(cohort), + source: { value: updated, enumerable: true }, + }, + ) as NativePayloadCohort; + expect(() => + captureNativePreEnvelopePayloads([foreign], { + source: initial, + products: [{ id: 'tools', version: '1.0.0' }], + }), + ).toThrow('frozen source'); + expect(() => capture({ ...initial, commit: 'main' })).toThrow('exact source'); + writeFileSync(path.join(directory('tools'), 'LICENSE'), 'changed legal bytes'); + expect(() => value.assertUnchanged()).toThrow('changed after capture'); + }); +}); + +test('compiler and ABI evidence stays outside payloads while final input roles remain captured', async () => { + await fixture(async ({ capture, cohort, executionRoot }) => { + const original = capture().payloads; + const payload = cohort.roots[0]; + const outputs = ['android-arm64', 'android-x86_64'].map((target) => { + const file = `bazel-out/${target}/bin/runtime/liboliphaunt.so`; + mkdirSync(path.dirname(path.join(executionRoot, file)), { recursive: true }); + writeFileSync(path.join(executionRoot, file), `${target} compiler evidence`); + return { path: file, owner: '//fixture/runtime:library' }; + }); + for (const role of ['compiled-source', 'abi-contract']) + cohort.roots.push({ + label: `//fixture/runtime:${role}`, + package: { ...payload.package, name: `runtime-${role}`, role, outputs }, + }); + expect(capture().payloads).toEqual(original); + + cohort.roots.push({ + label: '//fixture/runtime:frozen', + package: { + ...payload.package, + name: 'runtime-frozen', + role: 'extension-release-frozen-input', + outputs: [outputs[0]], + }, + }); + const captured = capture().payloads.products.find(({ id }) => id === payload.package.product); + expect(captured?.roots.map(({ name }) => name)).toEqual([ + 'runtime-frozen', + 'runtime-public-payload', + ]); + payload.package.outputs = outputs; + expect(() => capture()).toThrow('ambiguous native payload output'); + }); +}); + +test('missing origin, qualification or complete shipping-mode contract stays unknown', async () => { + await fixture(async ({ capture }) => { + const current = capture().payloads; + const previous = origins(current); + expect( + (await compareNativePreEnvelopeDelivery(current, {})).products.every( + ({ necessaryDelivery }) => necessaryDelivery === 'unknown', + ), + ).toBe(true); + const unchecked = await compareNativePreEnvelopeDelivery(current, previous); + expect(unchecked.products.map(({ reason }) => reason)).toEqual([ + 'completed-origin-unverified', + 'completed-origin-unverified', + 'completed-origin-unverified', + ]); + const noQualification = await compareNativePreEnvelopeDelivery(current, previous, { + verifyOrigin: syntheticVerifiers.verifyOrigin, + }); + expect( + noQualification.products.every(({ necessaryDelivery }) => necessaryDelivery === 'unknown'), + ).toBe(true); + await expect( + compareNativePreEnvelopeDelivery(current, previous, { + verifyOrigin: async () => true as any, + }), + ).rejects.toThrow('publication'); + await expect( + compareNativePreEnvelopeDelivery(current, previous, { + ...syntheticVerifiers, + verifyQualifiedCoverage: async () => ({ label: '//fixture:qualified' }) as any, + }), + ).rejects.toThrow('captured product/source/payload'); + }); +}); + +test('input and toolchain checks do not require delivery when qualified members are identical', async () => { + await fixture(async ({ capture }) => { + const baseline = origins(capture().payloads); + const current = capture(updated).payloads; + const result = await compareNativePreEnvelopeDelivery(current, baseline, { + ...syntheticVerifiers, + affectedProducts: ['runtime', 'tools', 'sdk'], + }); + expect(result.scope).toBe('construction'); + expect(result.products.every(({ affectedBuild }) => affectedBuild === 'required')).toBe(true); + expect( + result.products.every(({ necessaryDelivery }) => necessaryDelivery === 'not-needed'), + ).toBe(true); + }); +}); + +test('own envelope versions and undeclared metadata do not erase or introduce payload differences', async () => { + await fixture(async ({ capture, cohort, products }) => { + const baseline = origins(capture().payloads); + const renamedVersions = products.map(({ id }) => ({ id, version: '2.0.0' })); + const metadataOnly = { + executionRoot: cohort.executionRoot, + source: updated, + roots: cohort.roots.map((root: any) => ({ + ...root, + package: { ...root.package, version: '2.0.0' }, + })), + aquery: {}, + }; + metadataOnly.roots.push({ + label: '//fixture:unused_envelope', + package: { + product: 'tools', + version: '2.0.0', + ecosystem: 'npm', + name: '@fixture/tools', + role: 'facade', + configuration: 'portable', + outputs: [ + { path: 'bazel-out/missing/version-and-vcs-envelope.tgz', owner: '//fixture:unused' }, + ], + }, + }); + const current = capture(updated, renamedVersions, [metadataOnly]).payloads; + const result = await compareNativePreEnvelopeDelivery(current, baseline, syntheticVerifiers); + expect( + result.products.every(({ necessaryDelivery }) => necessaryDelivery === 'not-needed'), + ).toBe(true); + expect(current.products.every(({ roots }) => roots.length === 1)).toBe(true); + }); +}); + +test('a singleton TreeArtifact wrapper rename preserves the same declared delivered members', async () => { + await fixture(async ({ capture, cohort, directory }) => { + const baseline = origins(capture().payloads); + const root = cohort.roots[0] as any; + renameSync( + directory('runtime'), + path.join(path.dirname(directory('runtime')), 'renamed_wrapper'), + ); + root.package.outputs[0].path = 'bazel-out/fixture/bin/runtime/renamed_wrapper'; + const current = capture(updated).payloads; + const result = await compareNativePreEnvelopeDelivery(current, baseline, syntheticVerifiers); + expect( + result.products.every(({ necessaryDelivery }) => necessaryDelivery === 'not-needed'), + ).toBe(true); + expect(current.products.find(({ id }) => id === 'runtime')!.roots[0].outputs[0].path).toEndWith( + '/renamed_wrapper', + ); + }); +}); + +test('a directly delivered singleton File rename remains a delivery difference', async () => { + await fixture( + async ({ capture, cohort, executionRoot }) => { + const original = 'bazel-out/fixture/bin/tools/delivered.so'; + const renamed = 'bazel-out/fixture/bin/tools/renamed.so'; + writeFileSync(path.join(executionRoot, original), 'exact delivered library bytes'); + chmodSync(path.join(executionRoot, original), 0o644); + const output = cohort.roots[0].package.outputs[0]; + output.path = original; + const baseline = origins(capture().payloads); + renameSync(path.join(executionRoot, original), path.join(executionRoot, renamed)); + output.path = renamed; + const current = capture(updated).payloads; + expect(current.products[0].roots[0].outputs[0].members[0]).toMatchObject({ + path: '', + type: 'file', + }); + const result = await compareNativePreEnvelopeDelivery(current, baseline, syntheticVerifiers); + expect(result.products[0].necessaryDelivery).toBe('needed'); + }, + ['tools'], + ); +}); + +test('raw Bazel modes need the actual complete delivered archive contract rather than guessed chmod', async () => { + await fixture( + async ({ capture, directory, executionRoot }) => { + const before = capture().payloads; + const baseline = origins(before); + const product = before.products[0]; + const packed = async (payloads: NativePayloads, destination: string) => { + // Exercise the existing archive writer/reader with a declared fixture + // contract. Synthetic trust adapters below still grant no real admission. + await archiveDirectory(directory('tools'), destination, { + modes: { LICENSE: 0o644, 'lib/module.bin': 0o644 }, + }); + const entries = [...readPortableArchiveEntries(destination).values()]; + const proof = verification(payloads, payloads.products[0]); + for (const member of proof.deliveredPayloads[0].outputs[0].members) { + if (member.path === '') continue; // The portable reader omits the archive's root marker. + const entry = entries.find( + ({ name }) => name.replace(/\/$/u, '').replace(/^\.$/u, '') === member.path, + ); + expect(entry).toBeDefined(); + member.mode = entry!.mode & 0o777; + } + return proof; + }; + const verifiedBefore = await packed(before, path.join(executionRoot, 'before.tar.gz')); + chmodSync(path.join(directory('tools'), 'LICENSE'), 0o555); + const current = capture(updated).payloads; + expect( + current.products[0].roots[0].outputs[0].members.find(({ path }) => path === 'LICENSE')! + .mode, + ).toBe(0o555); + const unchecked = await compareNativePreEnvelopeDelivery(current, baseline, { + verifyOrigin: async () => ({ + ...verifiedBefore, + publication: baseline[product.id].publication, + }), + }); + expect(unchecked.products[0].necessaryDelivery).toBe('unknown'); + const verifiedAfter = await packed(current, path.join(executionRoot, 'after.tar.gz')); + expect(readFileSync(path.join(executionRoot, 'after.tar.gz'))).toEqual( + readFileSync(path.join(executionRoot, 'before.tar.gz')), + ); + const result = await compareNativePreEnvelopeDelivery(current, baseline, { + verifyOrigin: async () => ({ + ...verifiedBefore, + publication: baseline[product.id].publication, + }), + verifyQualifiedCoverage: async () => verifiedAfter, + }); + expect(result.products[0].necessaryDelivery).toBe('not-needed'); + }, + ['tools'], + ); +}); + +test('zero, few and many delivered changes select only the corresponding conditional decisions', async () => { + await fixture( + async ({ capture, directory, products }) => { + const baseline = origins(capture().payloads); + const compare = () => + compareNativePreEnvelopeDelivery(capture(updated).payloads, baseline, { + ...syntheticVerifiers, + affectedProducts: [], + }); + expect( + (await compare()).products.every( + ({ necessaryDelivery }) => necessaryDelivery === 'not-needed', + ), + ).toBe(true); + for (const id of ['product-2', 'product-5']) + writeFileSync(path.join(directory(id), 'lib/module.bin'), 'actual changed library'); + expect( + (await compare()).products + .filter(({ necessaryDelivery }) => necessaryDelivery === 'needed') + .map(({ product }) => product), + ).toEqual(['product-2', 'product-5']); + for (const { id } of products) + writeFileSync(path.join(directory(id), 'LICENSE'), 'new shipped legal text'); + expect( + (await compare()).products.every(({ necessaryDelivery }) => necessaryDelivery === 'needed'), + ).toBe(true); + }, + Array.from({ length: 8 }, (_, index) => `product-${index}`), + ); +}); + +test('held consumed compatibility stays unchanged until its actual declared payload is adopted', async () => { + await fixture(async ({ capture, directory }) => { + const manifest = path.join(directory('sdk'), 'consumed-runtime.json'); + writeFileSync(manifest, '{"native_runtime":"0.3.2"}'); + const baseline = origins(capture().payloads); + writeFileSync(path.join(directory('runtime'), 'lib/module.bin'), 'new runtime construction'); + const compare = () => + compareNativePreEnvelopeDelivery(capture(updated).payloads, baseline, syntheticVerifiers); + expect( + (await compare()).products.find(({ product }) => product === 'sdk')!.necessaryDelivery, + ).toBe('not-needed'); + writeFileSync(manifest, '{"native_runtime":"0.3.3"}'); + expect( + (await compare()).products.find(({ product }) => product === 'sdk')!.necessaryDelivery, + ).toBe('needed'); + }); +}); + +test('member renames, executable modes and public compiled version bytes remain delivery differences', async () => { + for (const mutate of [ + (directory) => { + rmSync(path.join(directory, 'lib/module.bin')); + writeFileSync(path.join(directory, 'lib/renamed.bin'), 'tools public bytes'); + }, + (directory) => chmodSync(path.join(directory, 'lib/module.bin'), 0o755), + (directory) => + writeFileSync(path.join(directory, 'lib/module.bin'), 'public version API 1.0.1'), + ]) + await fixture(async ({ capture, directory }) => { + const baseline = origins(capture().payloads); + mutate(directory('tools')); + const result = await compareNativePreEnvelopeDelivery( + capture(updated).payloads, + baseline, + syntheticVerifiers, + ); + expect(result.products.find(({ product }) => product === 'tools')!.necessaryDelivery).toBe( + 'needed', + ); + expect( + result.products + .filter(({ product }) => product !== 'tools') + .every(({ necessaryDelivery }) => necessaryDelivery === 'not-needed'), + ).toBe(true); + }); +}); + +test('missing a required module is unknown when the actual qualification contract cannot complete', async () => { + await fixture(async ({ capture, directory }) => { + const baseline = origins(capture().payloads); + rmSync(path.join(directory('tools'), 'lib/module.bin')); + const result = await compareNativePreEnvelopeDelivery(capture(updated).payloads, baseline, { + ...syntheticVerifiers, + verifyQualifiedCoverage: async (current, product) => + product.id === 'tools' ? undefined : verification(current, product), + }); + expect(result.products.find(({ product }) => product === 'tools')).toMatchObject({ + necessaryDelivery: 'unknown', + reason: 'qualified-delivery-contract-unverified', + }); + }); +}); + +test('bootstrap and source-only products without declared pre-envelope roots are unknown', async () => { + await fixture(async ({ capture, products, cohort }) => { + const selected = [ + ...products, + { id: 'first-native', version: '0.0.0' }, + { id: 'source-only', version: '1.0.0' }, + ]; + const baseline = origins(capture().payloads); + const current = capture(updated, selected, [cohort]).payloads; + const result = await compareNativePreEnvelopeDelivery(current, baseline, syntheticVerifiers); + expect( + result.products + .filter(({ product }) => ['first-native', 'source-only'].includes(product)) + .every( + ({ necessaryDelivery, reason }) => + necessaryDelivery === 'unknown' && reason === 'current-pre-envelope-roots-missing', + ), + ).toBe(true); + }); +}); + +test('source, completed publication, snapshot and complete delivered member bindings cannot be substituted', async () => { + await fixture(async ({ capture }) => { + const current = capture(updated).payloads; + const baseline = origins(capture().payloads); + for (const substitute of [ + (proof) => { + proof.source = initial; + }, + (proof) => { + proof.payloadDigest = '0'.repeat(64); + }, + (proof) => { + proof.deliveredPayloads[0].outputs[0].members.pop(); + }, + (proof) => { + proof.deliveredPayloads[0].outputs[0].members.find(({ type }) => type === 'file').sha256 = + '0'.repeat(64); + }, + ]) + await expect( + compareNativePreEnvelopeDelivery(current, baseline, { + ...syntheticVerifiers, + verifyQualifiedCoverage: async (value, product) => { + const proof = verification(value, product); + substitute(proof); + return proof; + }, + }), + ).rejects.toThrow(); + baseline.tools.publication.publicationSha = '9'.repeat(40); + await expect( + compareNativePreEnvelopeDelivery(current, baseline, syntheticVerifiers), + ).rejects.toThrow('completed origin'); + }); +}); + +test('declared output boundaries reject traversal, symlinks and missing physical payloads', async () => { + await fixture(({ capture, cohort, directory }) => { + const output = cohort.roots[0] as any; + output.package.outputs[0].path = 'bazel-out/fixture/bin/runtime/../tools/public_payload'; + expect(capture).toThrow('unsafe'); + output.package.outputs[0].path = 'bazel-out/fixture/bin/runtime/public_payload'; + rmSync(path.join(directory('runtime'), 'LICENSE')); + symlinkSync( + path.join(directory('tools'), 'LICENSE'), + path.join(directory('runtime'), 'LICENSE'), + ); + expect(capture).toThrow('regular file or directory'); + rmSync(directory('runtime'), { recursive: true }); + expect(capture).toThrow(); + }); +}); diff --git a/tools/release/native-publication-staging.mts b/tools/release/native-publication-staging.mts new file mode 100644 index 000000000..2b7534da5 --- /dev/null +++ b/tools/release/native-publication-staging.mts @@ -0,0 +1,294 @@ +import { isNativeAppleBaseInputRoot } from './bazel-shipping-inputs.mts'; +import { fileIdentity, safeRelative } from './native-file-identity.mts'; + +export { copyNativeInputFile } from './native-file-identity.mts'; + +/** Copy only captured native outputs into the existing target/ capsule boundary. */ +import { createHash } from 'node:crypto'; +import { + chmodSync, + lstatSync, + mkdtempSync, + readdirSync, + realpathSync, + renameSync, + rmSync, +} from 'node:fs'; +import path from 'node:path'; +import { requireSafeDirectoryChain } from '../packaging/release-directory-safety.mts'; +import { + type NativeRoot, + nativeOutputPath, + type PhysicalShippingCohort, +} from './native-publication-artifacts.mts'; +import { ROOT } from './release-graph.mts'; + +function digest(value) { + return createHash('sha256').update(JSON.stringify(value)).digest('hex'); +} + +function snapshot(outputs: { key: string; relative: string; absolute: string }[]) { + const rows = new Map(); + const visit = (key: string, relative: string, absolute: string) => { + safeRelative(relative); + const stat = lstatSync(absolute); + if (stat.isSymbolicLink() || (!stat.isDirectory() && !stat.isFile())) + throw new Error(`native output must be a regular file or directory: ${absolute}`); + const id = `${key}/${relative}`; + const identity = stat.isFile() + ? fileIdentity(absolute) + : { type: 'directory', mode: stat.mode & 0o777 }; + const existing = rows.get(id); + if (existing) { + const { id: _id, absolute: _absolute, ...previous } = existing; + if (existing.absolute !== absolute || JSON.stringify(previous) !== JSON.stringify(identity)) + throw new Error('duplicate native output declarations have conflicting bytes or modes'); + } + rows.set(id, { id, absolute, ...identity }); + if (stat.isDirectory()) { + requireSafeDirectoryChain(absolute, { label: 'native output' }); + for (const name of readdirSync(absolute).sort()) + visit(key, `${relative}/${name}`, path.join(absolute, name)); + } + }; + for (const output of outputs) visit(output.key, output.relative, output.absolute); + return [...rows.values()].sort((left, right) => + left.id < right.id ? -1 : left.id > right.id ? 1 : 0, + ); +} + +function identities(rows) { + return rows.map(({ absolute: _absolute, ...identity }) => identity); +} + +export type NativeOutputMember = + | { path: string; type: 'directory'; mode: number } + | { path: string; type: 'file'; mode: number; size: number; sha256: string }; + +/** Windows stat bits have no POSIX permission meaning; normalize only owned staging. */ +export function nativeTransportStagingMode( + member: Pick, + executionRoot: string, +): number { + // Ambiguous POSIX-looking roots, including slash-spelled UNC paths, retain POSIX checks. + return !path.posix.isAbsolute(executionRoot) && path.win32.isAbsolute(executionRoot) + ? member.type === 'directory' + ? 0o755 + : 0o644 + : member.mode; +} + +/** Copy one declared regular output through the same bounded reader as candidate staging. */ +export function copyNativeOutputFile(executionRoot: string, output: string, destination: string) { + return fileIdentity(nativeOutputPath(executionRoot, safeRelative(output)), destination); +} + +function captureMembers(absolute: string, assertPath: () => void) { + requireSafeDirectoryChain(path.dirname(absolute), { label: 'native output' }); + const outputs = [{ key: 'payload', relative: 'root', absolute }]; + const observed = identities(snapshot(outputs)); + const expected = JSON.stringify(observed); + return { + members: observed.map(({ id, ...member }) => ({ + path: id.slice('payload/root'.length).replace(/^\//u, ''), + ...member, + })) as NativeOutputMember[], + assertUnchanged() { + assertPath(); + requireSafeDirectoryChain(path.dirname(absolute), { label: 'native output' }); + if (JSON.stringify(identities(snapshot(outputs))) !== expected) + throw new Error('native payload bytes, modes or membership changed after capture'); + }, + }; +} + +/** Read one declared output, retaining physical modes without a shipping-mode policy. */ +export function captureNativeOutputMembers(executionRoot: string, output: string) { + if (!path.isAbsolute(executionRoot ?? '')) + throw new Error('native payload requires the captured absolute executionRoot'); + const root = realpathSync(executionRoot); + const absolute = nativeOutputPath(root, safeRelative(output)); + return captureMembers(absolute, () => { + if (nativeOutputPath(root, output) !== absolute) + throw new Error('native output path changed after capture'); + }); +} + +/** Resolve an exact declared Bazel input; workspace/repository links are part of its execroot. */ +export function captureNativeInputMembers(executionRoot: string, input: string) { + if (!path.isAbsolute(executionRoot ?? '')) + throw new Error('native input requires the captured absolute executionRoot'); + const root = realpathSync(executionRoot); + const declared = path.join(root, safeRelative(input)); + const absolute = realpathSync(declared); + return captureMembers(absolute, () => { + if (realpathSync(declared) !== absolute) + throw new Error('native input path changed after capture'); + }); +} + +/** + * Capturing before physical validation and comparing again before/after copying + * binds the staged candidate to those same bytes and directory members. This is + * byte staging, never producer execution, qualification or release selection. + */ +/** Final envelopes and the exact documents required to join extension target leaves. */ +export const NATIVE_EXTENSION_RELEASE_INPUT_ROLES = [ + 'extension-release-manifest-input', + 'extension-release-frozen-input', + 'extension-release-family-input', +] as const; + +export function isNativeFinalTransportRoot(root: NativeRoot) { + const pkg = root.package; + return ( + isNativeAppleBaseInputRoot(root) || + pkg.ecosystem !== 'internal' || + (NATIVE_EXTENSION_RELEASE_INPUT_ROLES as readonly string[]).includes(pkg.role) + ); +} + +export function captureNativePublicationOutputs( + cohorts: PhysicalShippingCohort[], + { sourceCommit, stageDirectory }: { sourceCommit: string; stageDirectory?: string }, +) { + if (!/^[0-9a-f]{40}$/u.test(sourceCommit)) + throw new Error('native stage requires a full source SHA'); + if (stageDirectory !== undefined) { + safeRelative(stageDirectory); + if (!stageDirectory.startsWith('target/')) + throw new Error('native stage must remain under target/'); + } + const outputs = cohorts.flatMap((cohort) => { + if (!path.isAbsolute(cohort.executionRoot ?? '')) + throw new Error('native stage requires the captured absolute executionRoot'); + const executionRoot = realpathSync(cohort.executionRoot); + const roots = (cohort.roots as NativeRoot[]).filter(isNativeFinalTransportRoot); + const declarations = roots + .map(({ package: pkg }) => ({ + product: pkg.product, + version: pkg.version, + ecosystem: pkg.ecosystem, + name: pkg.name, + configuration: pkg.configuration, + role: pkg.role, + outputs: pkg.outputs + .map(({ path: relative, owner }) => ({ path: safeRelative(relative), owner })) + .sort((left, right) => JSON.stringify(left).localeCompare(JSON.stringify(right))), + })) + .sort((left, right) => + JSON.stringify(left) < JSON.stringify(right) + ? -1 + : JSON.stringify(left) > JSON.stringify(right) + ? 1 + : 0, + ); + const cohortKey = digest({ executionRoot, declarations }); + const producers = new Map }>(); + for (const { package: pkg } of roots) + for (const { path: sourceRelative, owner } of pkg.outputs) { + if (typeof owner !== 'string' || !owner || /[\u0000-\u001f\u007f]/u.test(owner)) + throw new Error('native stage requires the declared output producer'); + const parts = safeRelative(sourceRelative).split('/'); + if (parts[0] !== 'bazel-out' || parts.length < 4) + throw new Error(`unsafe native output path: ${JSON.stringify(sourceRelative)}`); + const namespace = parts.slice(0, 3).join('/'); + const producer = JSON.stringify([owner, namespace]); + if (!producers.has(producer)) + producers.set(producer, { owner, namespace, paths: new Set() }); + producers.get(producer)!.paths.add(sourceRelative); + } + return [...producers.values()].flatMap(({ owner, namespace, paths }) => { + const declared = [...paths].sort(); + let parent = path.posix.dirname(declared[0]).split('/'); + for (const sourceRelative of declared.slice(1)) { + const parts = path.posix.dirname(sourceRelative).split('/'); + const mismatch = parent.findIndex((part, index) => part !== parts[index]); + if (mismatch >= 0) parent = parent.slice(0, mismatch); + } + const base = path.posix.dirname(parent.join('/')); + // Keep the shared parent and tree basenames; carriers can require those directory boundaries. + const key = digest({ sourceCommit, cohortKey, owner, namespace, base, outputs: declared }); + return declared.map((sourceRelative) => { + const relative = safeRelative(path.posix.relative(base, sourceRelative)); + const absolute = nativeOutputPath(executionRoot, sourceRelative); + requireSafeDirectoryChain(path.dirname(absolute), { label: 'native output' }); + return { key, relative, sourceRelative, executionRoot, absolute: realpathSync(absolute) }; + }); + }); + }); + const observed = snapshot(outputs); + const expected = JSON.stringify(identities(observed)); + const relative = safeRelative( + stageDirectory ?? + `target/n/${digest({ sourceCommit, outputs: identities(observed) }).slice(0, 32)}`, + ); + if (!relative.startsWith('target/')) throw new Error('native stage must remain under target/'); + const destination = path.join(ROOT, relative); + const stagedOutputs = (directory) => + outputs.map((output) => ({ + ...output, + absolute: path.join(directory, output.key, output.relative), + })); + const assertUnchanged = () => { + for (const output of outputs) { + requireSafeDirectoryChain( + path.dirname(path.join(output.executionRoot, output.sourceRelative)), + { + label: 'native output', + }, + ); + if ( + realpathSync(nativeOutputPath(output.executionRoot, output.sourceRelative)) !== + output.absolute + ) + throw new Error('native output path changed after capture'); + } + if (JSON.stringify(identities(snapshot(outputs))) !== expected) + throw new Error('native output bytes, modes or directory membership changed after capture'); + }; + return { + stage() { + assertUnchanged(); + const parent = requireSafeDirectoryChain(path.dirname(destination), { + create: true, + label: 'native stage', + }); + let existing; + try { + existing = lstatSync(destination); + } catch (cause) { + if (cause.code !== 'ENOENT') throw cause; + } + if (existing) { + requireSafeDirectoryChain(destination, { label: 'native stage' }); + if (JSON.stringify(identities(snapshot(stagedOutputs(destination)))) !== expected) + throw new Error('existing native stage differs from the captured outputs'); + } else { + const temporary = mkdtempSync(path.join(parent, '.native-stage-')); + try { + for (const row of observed) { + const target = path.join(temporary, row.id); + if (row.type === 'directory') + requireSafeDirectoryChain(target, { create: true, label: 'native stage' }); + else { + const { id: _id, absolute: _absolute, ...identity } = row; + if (JSON.stringify(fileIdentity(row.absolute, target)) !== JSON.stringify(identity)) + throw new Error('native output changed while being copied'); + } + } + for (const row of observed.filter(({ type }) => type === 'directory').reverse()) + chmodSync(path.join(temporary, row.id), row.mode); + assertUnchanged(); + if (JSON.stringify(identities(snapshot(stagedOutputs(temporary)))) !== expected) + throw new Error('staged native output differs from its captured bytes'); + renameSync(temporary, destination); + } finally { + rmSync(temporary, { recursive: true, force: true }); + } + } + assertUnchanged(); + return [...new Set(stagedOutputs(destination).map(({ absolute }) => absolute))].sort(); + }, + }; +} diff --git a/tools/release/native-publication-staging.test.mts b/tools/release/native-publication-staging.test.mts new file mode 100644 index 000000000..b91d27feb --- /dev/null +++ b/tools/release/native-publication-staging.test.mts @@ -0,0 +1,285 @@ +import { expect, test } from 'bun:test'; +import { + chmodSync, + existsSync, + lstatSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { tarHeader } from '../packaging/archive-directory.mts'; +import { captureNativePublicationOutputs } from './native-publication-staging.mts'; +import { ROOT } from './release-graph.mts'; + +function fixture(run) { + const executionRoot = mkdtempSync(path.join(os.tmpdir(), 'native-output-stage-')); + const target = path.join(ROOT, 'target'); + mkdirSync(target, { recursive: true }); + const workspace = mkdtempSync(path.join(target, 'native-output-stage-test-')); + const output = 'bazel-out/fixture/bin/package'; + const directory = path.join(executionRoot, output); + mkdirSync(path.join(directory, 'empty'), { recursive: true }); + writeFileSync(path.join(directory, 'package.pom'), 'POM'); + writeFileSync(path.join(directory, 'package.jar'), 'JAR'); + chmodSync(path.join(directory, 'package.jar'), 0o755); + const cohort = { + executionRoot, + roots: [ + { + label: '//fixture:shipping', + package: { + product: 'fixture', + version: '1.0.0', + ecosystem: 'maven', + name: 'dev:fixture', + role: 'facade', + configuration: 'portable', + outputs: [{ path: output, owner: '//fixture:producer' }], + }, + }, + ], + aquery: {}, + }; + const stageDirectory = path + .relative(ROOT, path.join(workspace, 'staged')) + .split(path.sep) + .join('/'); + const capture = (cohorts = [cohort], destination = stageDirectory) => + captureNativePublicationOutputs(cohorts, { + sourceCommit: '1'.repeat(40), + stageDirectory: destination, + }); + try { + run({ capture, cohort, directory, executionRoot, workspace, stageDirectory }); + } finally { + rmSync(executionRoot, { recursive: true, force: true }); + rmSync(workspace, { recursive: true, force: true }); + } +} + +test('stages exact declared tree bytes, empty directories and modes under target with companion layout', () => { + fixture(({ capture, directory }) => { + const staged = capture().stage(); + expect(staged).toHaveLength(1); + expect(path.relative(ROOT, staged[0])).toMatch(/^target\//u); + expect(staged[0]).toEndWith('/package'); + expect(readFileSync(path.join(staged[0], 'package.pom'), 'utf8')).toBe('POM'); + expect(readFileSync(path.join(staged[0], 'package.jar'), 'utf8')).toBe('JAR'); + expect(lstatSync(path.join(staged[0], 'empty')).isDirectory()).toBe(true); + expect(lstatSync(path.join(staged[0], 'package.jar')).mode & 0o777).toBe(0o755); + expect(capture().stage()).toEqual(staged); + rmSync(directory, { recursive: true }); + expect(readFileSync(path.join(staged[0], 'package.jar'), 'utf8')).toBe('JAR'); + }); +}); + +test('rejects bytes, modes, removed files and added directory members changed after capture', () => { + for (const mutate of [ + (directory) => writeFileSync(path.join(directory, 'package.jar'), 'BAD'), + (directory) => chmodSync(path.join(directory, 'package.jar'), 0o644), + (directory) => rmSync(path.join(directory, 'package.jar')), + (directory) => writeFileSync(path.join(directory, 'extra'), 'extra'), + ]) + fixture(({ capture, directory, workspace }) => { + const captured = capture(); + mutate(directory); + expect(() => captured.stage()).toThrow('changed after capture'); + expect(existsSync(path.join(workspace, 'staged'))).toBe(false); + }); +}); + +test('rejects source symlinks, output parent aliases and unsafe or symlinked target parents', () => { + fixture(({ capture, cohort, directory, workspace }) => { + const file = path.join(directory, 'package.jar'); + rmSync(file); + symlinkSync(path.join(directory, 'package.pom'), file); + expect(capture).toThrow('regular file or directory'); + rmSync(file); + writeFileSync(file, 'JAR'); + const captured = capture(); + const moved = `${directory}-moved`; + mkdirSync(moved); + writeFileSync(path.join(moved, 'package.jar'), 'JAR'); + writeFileSync(path.join(moved, 'package.pom'), 'POM'); + rmSync(directory, { recursive: true }); + symlinkSync(moved, directory); + expect(() => captured.stage()).toThrow('not a physical file or directory'); + cohort.roots[0].package.outputs[0].path = `${cohort.roots[0].package.outputs[0].path}/package.jar`; + expect(capture).toThrow('symlink or non-directory ancestor'); + expect(() => capture([cohort], 'target/../outside')).toThrow('unsafe native staging path'); + expect(() => capture([cohort], '/tmp/outside')).toThrow('unsafe native staging path'); + rmSync(directory); + mkdirSync(directory); + writeFileSync(path.join(directory, 'package.jar'), 'JAR'); + const external = path.join(workspace, 'external'); + mkdirSync(external); + symlinkSync(external, path.join(workspace, 'link')); + const aliased = path + .relative(ROOT, path.join(workspace, 'link', 'staged')) + .split(path.sep) + .join('/'); + expect(() => capture([cohort], aliased).stage()).toThrow('symlink or non-directory ancestor'); + expect(existsSync(path.join(external, 'staged'))).toBe(false); + }); +}); + +test('overlapping tree and file declarations deduplicate and cohort order preserves staged paths', () => { + fixture(({ capture, cohort, stageDirectory }) => { + cohort.roots[0].package.outputs.push({ + path: 'bazel-out/fixture/bin/package/package.jar', + owner: '//fixture:producer', + }); + const second = { + ...cohort, + roots: [ + { + ...cohort.roots[0], + package: { + ...cohort.roots[0].package, + name: 'dev:second', + }, + }, + ], + }; + const first = capture([cohort, second]).stage(); + expect(capture([second, cohort], stageDirectory).stage()).toEqual(first); + expect(first).toHaveLength(4); + expect(first.filter((output) => output.endsWith('/package.jar'))).toHaveLength(2); + }); +}); + +test('existing staged mutations fail closed without replacing the accepted directory', () => { + fixture(({ capture }) => { + const staged = capture().stage(); + writeFileSync(path.join(staged[0], 'package.jar'), 'BAD'); + expect(() => capture().stage()).toThrow('existing native stage differs'); + expect(readFileSync(path.join(staged[0], 'package.jar'), 'utf8')).toBe('BAD'); + }); +}); + +test('real Gradle marker, Maven companions and Swift tree retain producer layout in capsule ustar', () => { + fixture(({ cohort, executionRoot }) => { + const files = [ + 'bazel-out/k8-fastbuild/bin/src/native/sdks/kotlin/oliphaunt-android-gradle-plugin/marker_maven/maven/dev/oliphaunt/android/dev.oliphaunt.android.gradle.plugin/0.3.3/dev.oliphaunt.android.gradle.plugin-0.3.3.pom', + 'bazel-out/k8-fastbuild/bin/src/native/sdks/kotlin/android_maven/maven/dev/oliphaunt/oliphaunt-android/0.3.3/oliphaunt-android-0.3.3-javadoc.jar', + 'bazel-out/k8-fastbuild/bin/src/native/sdks/kotlin/android_maven/maven/dev/oliphaunt/oliphaunt-android/0.3.3/oliphaunt-android-0.3.3.pom', + 'bazel-out/darwin_arm64-fastbuild/bin/src/native/sdks/swift/source_package/Package.swift.release', + 'bazel-out/darwin_arm64-fastbuild/bin/src/native/sdks/swift/source_package/extension-generator/extension-owner-catalog.json', + 'bazel-out/darwin_arm64-fastbuild/bin/src/native/sdks/swift/source_package/release-tree/src/sdks/swift/Sources/OliphauntExtensionSupport/OliphauntExtensionSupport.swift', + 'bazel-out/darwin_arm64-fastbuild/bin/src/native/sdks/swift/source_package/release-tree/src/sdks/swift/Carriers/ios-carriers.json', + ]; + for (const relative of files) { + const file = path.join(executionRoot, relative); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, 'fixture'); + } + const swiftTree = + 'bazel-out/darwin_arm64-fastbuild/bin/src/native/sdks/swift/source_package/release-tree'; + const declarations = [files[0], files[1], files[2], files[3], files[4], swiftTree]; + cohort.roots = declarations.map((relative, index) => ({ + ...cohort.roots[0], + label: `//fixture:shipping_${index}`, + package: { + ...cohort.roots[0].package, + name: `fixture-${index}`, + outputs: [ + { + path: relative, + owner: + index === 0 + ? '//fixture:marker_maven' + : index < 3 + ? '//fixture:android_maven' + : '//fixture:source_package', + }, + ], + }, + })); + const staged = captureNativePublicationOutputs([cohort], { + sourceCommit: '1'.repeat(40), + }).stage(); + const stageRoot = path.join( + ROOT, + ...path.relative(ROOT, staged[0]).split(path.sep).slice(0, 3), + ); + try { + expect( + path.dirname(staged.find((file) => file.endsWith('/oliphaunt-android-0.3.3-javadoc.jar'))!), + ).toBe(path.dirname(staged.find((file) => file.endsWith('/oliphaunt-android-0.3.3.pom'))!)); + const manifest = staged.find((file) => file.endsWith('/Package.swift.release'))!; + const tree = staged.find((file) => file.endsWith('/release-tree'))!; + expect(path.dirname(manifest)).toBe(path.dirname(tree)); + expect( + readFileSync(path.join(tree, 'src/sdks/swift/Carriers/ios-carriers.json'), 'utf8'), + ).toBe('fixture'); + expect( + staged.find((file) => file.endsWith('/extension-generator/extension-owner-catalog.json')), + ).toStartWith(`${path.dirname(tree)}/`); + const leaves = staged + .filter((file) => lstatSync(file).isFile()) + .concat( + files + .slice(-2) + .map((file) => + path.join(tree, file.slice(file.indexOf('/release-tree/') + '/release-tree/'.length)), + ), + ); + expect( + leaves.some((file) => file.endsWith('/dev.oliphaunt.android.gradle.plugin-0.3.3.pom')), + ).toBe(true); + for (const file of leaves) { + const relative = path.relative(ROOT, file).split(path.sep).join('/'); + const header = tarHeader({ name: relative }, 7, 0o644); + const name = header.subarray(0, 100).toString().split('\0')[0]; + const prefix = header.subarray(345, 500).toString().split('\0')[0]; + expect(`${prefix}/${name}`).toBe(relative); + } + } finally { + rmSync(stageRoot, { recursive: true, force: true }); + } + }); +}); + +test('same producer configurations and same-name carrier parts remain distinct with full source binding', () => { + fixture(({ cohort, executionRoot, capture }) => { + const originals = [ + ['bazel-out/k8-opt/bin/deep/producer/part.crate', 'x64'], + ['bazel-out/arm64-opt/bin/deep/producer/part.crate', 'arm64'], + ['bazel-out/k8-opt/bin/other/producer/part.crate', 'other'], + ]; + cohort.roots = originals.map(([relative, bytes], index) => { + const file = path.join(executionRoot, relative); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, bytes); + return { + ...cohort.roots[0], + package: { + ...cohort.roots[0].package, + name: `part-${index}`, + outputs: [ + { path: relative, owner: index < 2 ? '//fixture:producer' : '//other:producer' }, + ], + }, + }; + }); + const staged = capture().stage(); + expect(staged).toHaveLength(3); + expect(new Set(staged.map((file) => path.dirname(file))).size).toBe(3); + expect(staged.map((file) => readFileSync(file, 'utf8')).sort()).toEqual([ + 'arm64', + 'other', + 'x64', + ]); + const captured = capture(); + cohort.roots[0].package.outputs[0].path = originals[1][0]; + expect(() => capture().stage()).toThrow(); + expect(captured.stage()).toEqual(staged); + delete cohort.roots[0].package.outputs[0].owner; + expect(capture).toThrow('declared output producer'); + }); +}); diff --git a/tools/release/native-registry-preparation.test.mts b/tools/release/native-registry-preparation.test.mts new file mode 100644 index 000000000..8adeb2946 --- /dev/null +++ b/tools/release/native-registry-preparation.test.mts @@ -0,0 +1,39 @@ +import { expect, test } from 'bun:test'; +import { + nativePreparedRegistryBuildBound, + parseReleaseVersionCheckArgs, +} from './check_release_versions.mts'; + +test('native registry routing is explicit and retains the actual requested source and products', () => { + const args = parseReleaseVersionCheckArgs([ + '--native-preparation', + '--check-registries', + '--products-json', + '["oliphaunt-rust"]', + '--head-ref', + 'a'.repeat(40), + ]); + expect(args.nativePreparation).toBe(true); + expect(args.checkRegistries).toBe(true); + expect(args.productsJson).toBe('["oliphaunt-rust"]'); + expect(args.headRef).toBe('a'.repeat(40)); + expect(parseReleaseVersionCheckArgs(['--check-registries']).nativePreparation).toBe(false); +}); + +test('operator records, same-version labels and complete-looking maps cannot authenticate Prepare', () => { + const source = { commit: 'a'.repeat(40), tree: 'b'.repeat(40) }; + const raw = { + record: { preparedSource: source, selectedProducts: ['oliphaunt-rust'] }, + buildBound: new Map([['oliphaunt-rust', new Set(['liboliphaunt-native'])]]), + origin: { runId: 1, runAttempt: 1, artifact: { id: 1 }, codeSource: source }, + }; + for (const value of [ + undefined, + raw, + { ...raw, authenticated: true }, + { ...raw, buildBound: new Map() }, + ]) + expect(() => nativePreparedRegistryBuildBound(value, source, ['oliphaunt-rust'])).toThrow( + 'authenticated Prepare', + ); +}); diff --git a/tools/release/native-release-assets.test.mts b/tools/release/native-release-assets.test.mts new file mode 100644 index 000000000..532f6a14e --- /dev/null +++ b/tools/release/native-release-assets.test.mts @@ -0,0 +1,129 @@ +import { expect, test } from 'bun:test'; +import { + mkdirSync, + mkdtempSync, + readFileSync, + renameSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { assembleNativeReleaseAssets } from '../../build_defs/native/carriers/checksums.mts'; +import { captureNativePublicationOutputs } from './native-publication-staging.mts'; +import { loadPublicationCatalog } from './publication-catalog.mts'; +import { discoverProductArtifacts, expectedProductArtifactRows } from './publication-lock.mts'; + +function fixture() { + const scratch = mkdtempSync(path.join(tmpdir(), 'native-release-assets-')); + const products = loadPublicationCatalog('native-release-assets-test', { + products: ['postgres-tools-wasix'], + }).products; + const rows = expectedProductArtifactRows(products); + const checksum = rows.find((row) => row.kind === 'checksums'); + if (!checksum) throw new Error('canonical tools checksum is missing'); + const expected = rows.filter((row) => row !== checksum).map((row) => row.name); + const sources = path.join(scratch, 'sources'); + mkdirSync(sources); + const files = expected.map((name, index) => { + const file = path.join(sources, name); + // This fixture tests final placement/checksums; actual archive and installed + // payload behavior is qualified by the tools construction targets. + writeFileSync(file, `independent producer ${index}\n`); + return file; + }); + const relative = 'bazel-out/fixture/bin/tools/release-assets'; + const directory = path.join(scratch, relative); + return { + scratch, + products, + rows, + relative, + directory, + spec: { + expected, + files, + copies: expected.map((name) => path.join(directory, name)), + output: path.join(directory, checksum.name), + }, + }; +} + +test('assembled product assets pass the canonical publication reader before and after frozen staging', () => { + const value = fixture(); + const stageDirectory = `target/native-release-assets-test-${path.basename(value.scratch)}`; + try { + // The executor projects declared input leaves as symlinks; publication + // staging must nevertheless observe only regular assembled output files. + renameSync(value.spec.files[0], `${value.spec.files[0]}.producer`); + symlinkSync(`${value.spec.files[0]}.producer`, value.spec.files[0]); + assembleNativeReleaseAssets(value.spec); + const expected = discoverProductArtifacts([value.directory], value.products); + expect(expected).toHaveLength(value.rows.length); + const roots = value.rows.map((row) => ({ + label: `//tools:${row.kind}-${row.target}`, + package: { + product: row.product, + version: row.version, + ecosystem: 'github', + name: row.name, + configuration: row.target, + role: row.role, + outputs: [ + { path: `${value.relative}/${row.name}`, owner: '//tools:assembled_release_assets' }, + ], + }, + })); + const capture = captureNativePublicationOutputs([{ executionRoot: value.scratch, roots }], { + sourceCommit: 'a'.repeat(40), + stageDirectory, + }); + const staged = capture.stage(); + expect(capture.stage()).toEqual(staged); + const observed = discoverProductArtifacts(staged, value.products); + expect(observed.map(({ id, sha256, size }) => ({ id, sha256, size }))).toEqual( + expected.map(({ id, sha256, size }) => ({ id, sha256, size })), + ); + writeFileSync( + value.spec.output, + readFileSync(value.spec.output, 'utf8').replaceAll(' ./', ' '), + ); + expect(() => discoverProductArtifacts([value.directory], value.products)).toThrow( + 'checksum line', + ); + expect(() => capture.stage()).toThrow('changed'); + } finally { + rmSync(value.scratch, { recursive: true, force: true }); + rmSync(path.resolve(import.meta.dir, '../..', stageDirectory), { + recursive: true, + force: true, + }); + } +}); + +test('product assembly rejects incomplete, repeated and split-directory assets', () => { + const value = fixture(); + try { + expect(() => + assembleNativeReleaseAssets({ ...value.spec, files: value.spec.files.slice(1) }), + ).toThrow('inventory'); + expect(() => + assembleNativeReleaseAssets({ + ...value.spec, + files: [...value.spec.files, value.spec.files[0]], + }), + ).toThrow('repeat'); + expect(() => + assembleNativeReleaseAssets({ ...value.spec, copies: value.spec.copies.slice(1) }), + ).toThrow('destinations'); + expect(() => + assembleNativeReleaseAssets({ + ...value.spec, + output: path.join(value.scratch, 'elsewhere', path.basename(value.spec.output)), + }), + ).toThrow('one directory'); + } finally { + rmSync(value.scratch, { recursive: true, force: true }); + } +}); diff --git a/tools/release/native-release-entrypoints.test.mts b/tools/release/native-release-entrypoints.test.mts new file mode 100644 index 000000000..aacd27614 --- /dev/null +++ b/tools/release/native-release-entrypoints.test.mts @@ -0,0 +1,374 @@ +/** These dispatch fixtures grant no qualification or publication authority. */ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { + chmodSync, + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { test } from 'node:test'; +import { isolatedGitHubTestEnvironment } from './testdata/isolated-github-test-environment.mts'; +import { reconcileNativePrepare } from './native-prepare-continuation.mts'; +import { nativePrepareContinuationFixture } from './testdata/native-prepare-continuation-fixture.mts'; + +const ROOT = path.resolve(import.meta.dir, '../..'); +const invalidRuns = [undefined, '', '0', '01', '-1', '1.5', '12\n']; + +function fixture(run) { + const root = mkdtempSync(path.join(os.tmpdir(), 'native-release-entrypoints-')); + let deferredCleanup = false; + const log = path.join(root, '.git/commands'); + const directory = path.join(root, '.git/candidate'); + const output = path.join(root, '.git/outputs'); + const write = (file, content) => { + const destination = path.join(root, file); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, content); + }; + const git = (...args) => { + const result = spawnSync('git', args, { cwd: root, encoding: 'utf8' }); + assert.equal(result.status, 0, result.stderr); + return result.stdout.trim(); + }; + try { + git('init', '--quiet'); + for (const file of ['prepare-release-pr.sh', 'close-release-candidate.sh']) + write(`tools/release/${file}`, readFileSync(path.join(ROOT, 'tools/release', file))); + write('tools/ci/with-projects.sh', 'echo legacy-selector-invoked >&2\nexit 97\n'); + for (const [file, count] of [ + ['with-source.sh', 1], + ['with-product-history.sh', 4], + ['release-please-state.sh', 2], + ['with-release-history.sh', 2], + ]) + write(`tools/release/${file}`, `shift ${count}\nexec "$@"\n`); + write( + 'tools/dev/bun.sh', + 'printf "%s\\n" "$*" >> "$TEST_COMMAND_LOG"\n' + + 'if [[ "$1" == tools/release/prepare-release-candidate.mts ]]; then\n' + + ' mkdir -p "$2"\n' + + ' printf "%s\\n" "$TEST_CANDIDATE_REQUIRED" > "$2/required"\n' + + ' if [[ "$TEST_NATIVE_PACKET" == true ]]; then\n' + + ' mkdir -p "$2/native-release-inputs"\n' + + ' touch "$2/native-release-inputs/native-version-source.json" "$2/native-release-inputs/native-publication-inputs.json"\n' + + ' fi\n' + + 'fi\n', + ); + git('add', '.'); + git( + '-c', + 'user.name=Release Fixture', + '-c', + 'user.email=fixture@example.invalid', + 'commit', + '--quiet', + '-m', + 'test: release entrypoints', + ); + const source = git('rev-parse', 'HEAD'); + const env = isolatedGitHubTestEnvironment({ + TEST_COMMAND_LOG: log, + TEST_CANDIDATE_REQUIRED: 'true', + TEST_NATIVE_PACKET: 'true', + GITHUB_OUTPUT: output, + }); + delete env.NATIVE_QUALIFICATION_RUN_ID; + const command = (file, qualification, additions = {}) => + spawnSync('bash', [`tools/release/${file}`, directory], { + cwd: root, + encoding: 'utf8', + timeout: 10_000, + env: { + ...env, + ...(qualification === undefined ? {} : { NATIVE_QUALIFICATION_RUN_ID: qualification }), + ...additions, + }, + }); + const result = run({ root, directory, log, output, source, git, command, write }); + if (result?.then) { + deferredCleanup = true; + return result.finally(() => rmSync(root, { recursive: true, force: true })); + } + return result; + } finally { + if (!deferredCleanup) rmSync(root, { recursive: true, force: true }); + } +} + +test('release shell entrypoints reject missing or malformed native proof before reads or mutation', () => { + fixture(({ command, git, source, log }) => { + for (const file of ['prepare-release-pr.sh', 'close-release-candidate.sh']) { + for (const run of invalidRuns) { + const result = command(file, run); + assert.equal(result.status, 1); + assert.match(result.stderr, /exact positive qualification run ID/u); + assert.equal(git('rev-parse', 'HEAD'), source); + assert.equal(git('status', '--porcelain', '--untracked-files=all'), ''); + } + } + assert.throws(() => readFileSync(log), { code: 'ENOENT' }); + }); +}); + +test('Prepare reuses successful Required proof and returns pending Native work without preparing', { + timeout: 20_000, +}, () => { + const workflow = Bun.YAML.parse( + readFileSync(path.join(ROOT, '.github/workflows/release.yml'), 'utf8'), + ); + const prerequisite = workflow.jobs['qualify-prepare-source']; + const prepare = workflow.jobs['prepare-release-pr']; + assert.equal(prerequisite.permissions.actions, 'write'); + assert.equal(prepare.permissions.actions, 'read'); + assert.ok(prepare.needs.includes('qualify-prepare-source')); + assert.match(prepare.if, /needs\.qualify-prepare-source\.outputs\.run_id != ''/u); + assert.equal( + prepare.steps.find((step) => step.id === 'prepare_candidate').env.NATIVE_QUALIFICATION_RUN_ID, + '${{ needs.qualify-prepare-source.outputs.run_id }}', + ); + const request = prerequisite.steps.find((step) => step.id === 'native_qualification'); + assert.equal(request.env.GH_TOKEN, '${{ github.token }}'); + assert.match(request.run, /--request-native-qualification/u); + for (const mode of [ + 'reuse', + 'active', + 'source', + 'absent', + 'feature', + 'failed', + 'dispatch-skipped', + 'advanced', + 'race', + 'ambiguous', + ]) { + fixture(({ root, source, command, write, directory }) => { + const bin = path.join(root, '.git/bin'); + const output = path.join(root, '.git/native-output'); + const dispatch = path.join(root, '.git/native-dispatch.json'); + mkdirSync(bin); + write( + '.git/bin/gh', + '#!/usr/bin/env bash\nset -euo pipefail\n[[ "$1" == api && "$2" == --method && "$3" == POST && ! -e "$FAKE_DISPATCH" ]] || exit 93\nwhile [[ $# -gt 0 ]]; do if [[ "$1" == --input ]]; then cp "$2" "$FAKE_DISPATCH"; break; fi; shift; done\n[[ "$FAKE_MODE" != native-ambiguous ]] || exit 95\nprintf \'{"workflow_run_id":88}\\n\'\n', + ); + chmodSync(path.join(bin, 'gh'), 0o755); + const result = spawnSync('bash', ['-c', request.run], { + cwd: ROOT, + encoding: 'utf8', + timeout: 10_000, + env: isolatedGitHubTestEnvironment({ + PATH: `${bin}:${path.dirname(process.execPath)}:${process.env.PATH}`, + GH_TOKEN: 'test-token', + GH_REPO: 'f0rr0/oliphaunt', + GITHUB_SHA: source, + GITHUB_OUTPUT: output, + BUN_OPTIONS: `--preload=${ROOT}/tools/release/testdata/require-workflow-success-github.mts`, + FAKE_NATIVE_SHA: source, + FAKE_MODE: `native-${mode}`, + FAKE_DISPATCH: dispatch, + FAKE_LOG: path.join(root, '.git/native-reads'), + OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS: '0', + OLIPHAUNT_GITHUB_READ_DEADLINE_MS: '1000', + OLIPHAUNT_GITHUB_READ_MAX_ATTEMPTS: '1', + OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS: '0', + }), + }); + if (mode === 'reuse') { + assert.equal(result.status, 0, result.stderr); + const proof = /^run_id=(\d+)$/mu.exec(readFileSync(output, 'utf8'))?.[1]; + assert.equal(proof, '77'); + assert.equal(command('prepare-release-pr.sh', proof).status, 0); + assert.ok(readFileSync(path.join(directory, 'required'), 'utf8').includes('true')); + } else if (['active', 'source', 'absent', 'feature'].includes(mode)) { + assert.equal(result.status, 0, result.stderr); + const pending = readFileSync(output, 'utf8'); + assert.doesNotMatch(pending, /^run_id=/mu); + assert.match( + pending, + new RegExp(`qualification_pending_run_id=${mode === 'active' ? 77 : 88}`), + ); + assert.match( + pending, + /qualification_pending_run_url=https:\/\/github\.com\/f0rr0\/oliphaunt\/actions\/runs\//u, + ); + assert.match(pending, /qualification_pending_run_attempt=1/u); + assert.match(result.stderr, /resume automatically after qualification/u); + assert.equal(command('prepare-release-pr.sh', undefined).status, 1); + } else { + assert.notEqual(result.status, 0); + assert.ok(!existsSync(output), result.stdout); + } + if (['source', 'absent', 'feature', 'race', 'ambiguous'].includes(mode)) + assert.deepEqual(JSON.parse(readFileSync(dispatch, 'utf8')), { ref: 'main' }); + else assert.ok(!existsSync(dispatch)); + }); + } +}); + +test('one Prepare request retains pending Native intent and resumes the original producer after full proof', async () => { + await fixture(async ({ root, source, git, write, command }) => { + const workflow = Bun.YAML.parse( + readFileSync(path.join(ROOT, '.github/workflows/release.yml'), 'utf8'), + ); + const steps = workflow.jobs['qualify-prepare-source'].steps; + const request = steps.find((step) => step.id === 'native_qualification'); + const record = steps.find((step) => step.id === 'prepare_intent'); + const upload = steps.find((step) => step.name === 'Retain pending Prepare intent'); + assert.equal(upload.with.name, '${{ steps.prepare_intent.outputs.artifact_name }}'); + assert.equal(upload.with['retention-days'], 30); + const bin = path.join(root, '.git/bin'); + mkdirSync(bin); + write( + '.git/bin/gh', + '#!/usr/bin/env bash\nset -euo pipefail\n[[ ! -e "$FAKE_DISPATCH" ]] || exit 93\nwhile [[ $# -gt 0 ]]; do if [[ "$1" == --input ]]; then cp "$2" "$FAKE_DISPATCH"; break; fi; shift; done\nprintf \'{"workflow_run_id":88}\\n\'\n', + ); + chmodSync(path.join(bin, 'gh'), 0o755); + const output = path.join(root, '.git/request-output'); + const env = isolatedGitHubTestEnvironment({ + PATH: `${bin}:${path.dirname(process.execPath)}:${process.env.PATH}`, + GH_TOKEN: 'test-token', + GH_REPO: 'f0rr0/oliphaunt', + GITHUB_SHA: source, + GITHUB_OUTPUT: output, + BUN_OPTIONS: `--preload=${ROOT}/tools/release/testdata/require-workflow-success-github.mts`, + FAKE_NATIVE_SHA: source, + FAKE_MODE: 'native-absent', + FAKE_DISPATCH: path.join(root, '.git/dispatch.json'), + FAKE_LOG: path.join(root, '.git/reads'), + OLIPHAUNT_GITHUB_READ_MAX_ATTEMPTS: '1', + }); + const runRequest = () => + spawnSync('bash', ['-c', request.run], { cwd: ROOT, encoding: 'utf8', timeout: 10_000, env }); + const pending = runRequest(); + assert.equal(pending.status, 0, pending.stderr); + const outputs = Object.fromEntries( + readFileSync(output, 'utf8') + .trim() + .split('\n') + .map((line) => line.split('=')), + ); + assert.equal(outputs.run_id, undefined); + assert.equal(outputs.qualification_pending_run_id, '88'); + assert.equal(command('prepare-release-pr.sh', undefined).status, 1); + const intentFile = path.join(root, '.git/intent.json'); + const controller = nativePrepareContinuationFixture( + source, + git('rev-parse', 'HEAD^{tree}'), + 88, + ); + const recorded = spawnSync( + 'bash', + [ + '-c', + record.run.replace( + 'tools/release/native-prepare-continuation.mts', + `${ROOT}/tools/release/native-prepare-continuation.mts`, + ), + ], + { + cwd: root, + encoding: 'utf8', + timeout: 10_000, + env: isolatedGitHubTestEnvironment({ + ...controller.state.environment, + RUNNER_TEMP: path.dirname(intentFile), + GITHUB_OUTPUT: path.join(root, '.git/intent-output'), + NATIVE_PENDING_RUN_ID: outputs.qualification_pending_run_id, + NATIVE_PENDING_RUN_ATTEMPT: outputs.qualification_pending_run_attempt, + }), + }, + ); + assert.equal(recorded.status, 0, recorded.stderr); + assert.deepEqual(JSON.parse(readFileSync(intentFile, 'utf8')), controller.state.intent); + assert.equal( + readFileSync(path.join(root, '.git/intent-output'), 'utf8'), + 'artifact_name=native-prepare-intent-1\n', + ); + controller.state.native.status = 'in_progress'; + assert.deepEqual(await reconcileNativePrepare(controller.event('release'), controller.io), []); + controller.state.native.status = 'completed'; + assert.equal((await reconcileNativePrepare(controller.event(), controller.io))[0].runId, 41); + assert.deepEqual(controller.state.posts, [41]); + assert.equal(controller.state.original.event, 'workflow_dispatch'); + assert.equal(controller.state.original.head_sha, source); + env.FAKE_NATIVE_COMPLETE = 'true'; + env.GITHUB_OUTPUT = path.join(root, '.git/resumed-output'); + const resumed = runRequest(); + assert.equal(resumed.status, 0, resumed.stderr); + const proof = /^run_id=(\d+)$/mu.exec(readFileSync(env.GITHUB_OUTPUT, 'utf8'))?.[1]; + assert.equal(proof, '88'); + assert.equal(command('prepare-release-pr.sh', proof).status, 0); + assert.equal(git('rev-parse', 'HEAD'), source); + assert.deepEqual(JSON.parse(readFileSync(env.FAKE_DISPATCH, 'utf8')), { ref: 'main' }); + }); +}); + +test('native preparation routes once without Moon and requires its retained packet for a release', () => { + for (const [required, packet, status] of [ + ['false', 'false', 0], + ['true', 'true', 0], + ['true', 'false', 1], + ]) + fixture(({ command, directory, log, output }) => { + const result = command('prepare-release-pr.sh', '123', { + TEST_CANDIDATE_REQUIRED: required, + TEST_NATIVE_PACKET: packet, + }); + assert.equal(result.status, status, result.stderr); + assert.deepEqual(readFileSync(log, 'utf8').trim().split('\n'), [ + 'tools/release/release-please-pr-lifecycle.mts assert-clean --base main', + `tools/release/prepare-release-candidate.mts ${directory}`, + ]); + if (status === 0) + assert.equal( + readFileSync(output, 'utf8'), + `required=${required}\nnative_inputs=${required}\n`, + ); + else assert.match(result.stderr, /did not retain its completed input packet/u); + }); +}); + +test('native close verifies the already committed candidate without another source commit', () => { + fixture(({ command, directory, log, write, git, source }) => { + write('.git/candidate/required', 'true\n'); + const result = command('close-release-candidate.sh', '123'); + assert.equal(result.status, 0, result.stderr); + assert.deepEqual(readFileSync(log, 'utf8').trim().split('\n'), [ + 'tools/release/check_release_please_config.mts', + 'tools/release/check_artifact_targets.mts', + `tools/release/native-close-release-candidate.mts ${directory}`, + ]); + assert.equal(git('rev-parse', 'HEAD'), source); + assert.equal(git('status', '--porcelain', '--untracked-files=all'), ''); + }); +}); + +test('direct TypeScript preparation cannot fall back when its native coordinator is absent', () => { + for (const qualification of [...invalidRuns, '9007199254740993']) { + const env = isolatedGitHubTestEnvironment({ + RELEASE_SOURCE_SHA: 'a'.repeat(40), + GITHUB_REPOSITORY: 'f0rr0/oliphaunt', + }); + delete env.NATIVE_QUALIFICATION_RUN_ID; + if (qualification !== undefined) env.NATIVE_QUALIFICATION_RUN_ID = qualification; + const result = spawnSync( + process.execPath, + [ + path.join(ROOT, 'tools/release/prepare-release-candidate.mts'), + '/not-created/native-candidate', + ], + { cwd: ROOT, encoding: 'utf8', timeout: 10_000, env }, + ); + assert.equal(result.status, 1); + assert.match( + result.stderr, + /native preparation requires an exact positive qualification run ID/u, + ); + assert.doesNotMatch(result.stderr, /source date|fetch|Moon|ENOTFOUND/u); + } +}); diff --git a/tools/release/native-release-inputs.mts b/tools/release/native-release-inputs.mts new file mode 100644 index 000000000..ab73a1a98 --- /dev/null +++ b/tools/release/native-release-inputs.mts @@ -0,0 +1,931 @@ +/** Transport the existing constructor snapshot through the reviewed Prepare producer. */ +import assert from 'node:assert/strict'; +import { execFile, execFileSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { + appendFileSync, + copyFileSync, + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { parseArgs, promisify } from 'node:util'; +import { validateSeedConstructionReceipt } from '../../build_defs/resources/seed_construction.mts'; +import { requireSafeDirectoryChain } from '../packaging/release-directory-safety.mts'; +import type { CompletedPublication } from './completed-release-publication.mts'; +import { + githubJobArtifact, + latestGithubJob, + requestGithubPages, + requestGithubRepositoryJson, +} from './github-read.mts'; +import type { NativeBuildSource } from './native-build-qualification.mts'; +import { + type ExtensionFinalInput, + type ExtensionFinalInputFile, + type NativeAppleBaseInput, + type NativeCurrentArtifact, + type NativeSwiftSourceInput, + projectNativeAppleBaseInput, + projectNativeCurrentArtifacts, + projectNativeExtensionFinalInputs, + projectNativeSwiftSourceInput, +} from './native-extension-final-inputs.mts'; +import { fileIdentity } from './native-file-identity.mts'; +import { type NativeSeedInputControl, projectNativeSeedInputs } from './native-seed-inputs.mts'; +import { + type NativeSupplierArtifact, + validateNativeSupplierArtifacts, +} from './native-supplier-artifacts.mts'; +import { + assertNativeVersionSourceTransition, + type NativeVersionSourceBridge, + validateNativeVersionSourceBridge, +} from './native-version-source.mts'; +import { sourceIdentity } from './publication-lock.mts'; +import { resolveBuildBoundCompatibilityProducts } from './release-dependency-plan.mts'; +import { loadProducts, ROOT } from './release-graph.mts'; +import { releaseProductsFromManifests } from './verify-release-commit.mts'; + +const execute = promisify(execFile); +const acquiredPreparedInputs = new WeakMap< + object, + { digest: string; file: { size: number; sha256: string } } +>(); +const preparedDigest = (value: Awaited>) => + createHash('sha256') + .update( + JSON.stringify({ + record: value.record, + origin: value.origin, + buildBound: [...value.buildBound].map(([id, suppliers]) => [id, [...suppliers]]), + }), + ) + .digest('hex'); +/** A parsed record carries facts; only actual canonical Prepare acquisition carries origin. */ +export function assertAcquiredPreparedNativeReleaseInputs(value: unknown) { + if (!value || typeof value !== 'object' || !acquiredPreparedInputs.has(value)) + throw new Error('prepared native inputs lack their authenticated Prepare producer'); + const result = value as Awaited>; + const proof = acquiredPreparedInputs.get(result); + assert.ok(proof); + assert.equal(preparedDigest(result), proof.digest, 'acquired native Prepare facts changed'); + const actual = fileIdentity(result.snapshotFile); + assert.deepEqual( + { size: actual.size, sha256: actual.sha256 }, + proof.file, + 'acquired native Prepare snapshot changed', + ); + const snapshot = readJson(result.snapshotFile); + projectNativeSeedInputs(snapshot.seedControls, snapshot.source); + assertSupplierFiles(snapshot.supplierArtifacts ?? [], snapshot.supplierPublications); + assertFinalInputFiles(snapshot); + return result; +} +const repository = 'f0rr0/oliphaunt'; +export const nativeReleaseInputsArtifact = 'native-release-inputs'; +export type NativeReleaseInputRecord = { + bridge: NativeVersionSourceBridge; + selectedProducts: string[]; + preparedSource: NativeBuildSource; + buildBound: [string, string[]][]; +}; +export type NativeReleaseFinalInputs = { + extensionFinalInputs?: ExtensionFinalInput[]; + nativeAppleBase?: NativeAppleBaseInput; + nativeSwiftSource?: NativeSwiftSourceInput; + nativeCurrentArtifacts?: NativeCurrentArtifact[]; +}; +const finalInputFields = (value: NativeReleaseFinalInputs) => + ['extensionFinalInputs', 'nativeAppleBase', 'nativeSwiftSource', 'nativeCurrentArtifacts'].filter( + (name) => Object.hasOwn(value, name), + ); +const fields = (value: unknown, names: string[]) => { + assert.ok(value && typeof value === 'object' && !Array.isArray(value)); + assert.deepEqual( + Object.keys(value).sort(), + [...names].sort(), + 'native release input fields differ', + ); +}; +const source = (value: NativeBuildSource) => { + fields(value, ['commit', 'tree']); + for (const sha of [value.commit, value.tree]) assert.match(sha, /^[a-f0-9]{40}$/u); +}; +const readJson = (file: string) => JSON.parse(readFileSync(file, 'utf8')); +const writeJson = (file: string, value: unknown) => + writeFileSync(file, `${JSON.stringify(value)}\n`, { flag: 'wx' }); + +/** Resolve an exact producer request, never the latest branch run. Unchanged + * main commits and ordinary PRs need no prepared-release input acquisition. + */ +export async function resolveNativeReleaseInputContext( + { + source: currentSource, + pullNumber, + event = process.env.GITHUB_EVENT_NAME, + }: { source: NativeBuildSource; pullNumber?: number; event?: string }, + { read = requestGithubRepositoryJson, pages = requestGithubPages, gitDirectory = ROOT } = {}, +): Promise< + | { + pullNumber: number; + prepareSourceCommit: string; + sourcePolicy?: { subject: string; base: string; head: string; branch: string }; + } + | undefined +> { + source(currentSource); + let pull; + if (pullNumber !== undefined) { + assert.ok(Number.isSafeInteger(pullNumber) && pullNumber > 0); + pull = await read(`repos/${repository}/pulls/${pullNumber}`); + assert.equal(pull.number, pullNumber); + if (pull.head?.ref !== 'release-please--branches--main') return undefined; + } else { + const git = (...args: string[]) => + execFileSync('git', args, { cwd: gitDirectory, encoding: 'utf8' }).trim(); + assert.equal( + git('rev-parse', `${currentSource.commit}^{tree}`), + currentSource.tree, + 'native input context source tree differs', + ); + const parents = git('rev-list', '--parents', '-n', '1', currentSource.commit) + .split(/\s+/u) + .slice(1); + if ( + event !== 'merge_group' && + (!parents.length || + !git( + 'diff', + '--name-only', + parents[0], + currentSource.commit, + '--', + '.release-please-manifest.json', + )) + ) + return undefined; + const matches = ( + await pages(`repos/${repository}/commits/${currentSource.commit}/pulls`) + ).filter( + (row) => + (event === 'merge_group' + ? row.state === 'open' && !row.merged_at + : row.merged_at && row.merge_commit_sha === currentSource.commit) && + row.head?.ref === 'release-please--branches--main', + ); + if ( + event === 'merge_group' && + matches.length === 0 && + parents.length > 0 && + !git( + 'diff', + '--name-only', + parents[0], + currentSource.commit, + '--', + '.release-please-manifest.json', + ) + ) + return undefined; // Ordinary queues use the source-bound public input path. + assert.equal( + matches.length, + 1, + event === 'merge_group' + ? 'queued source requires one canonical open release PR' + : 'versioned main source requires one canonical merged release PR', + ); + pull = matches[0]; + } + assert.ok( + pull.base?.ref === 'main' && + pull.base?.repo?.full_name === repository && + pull.head?.repo?.full_name === repository, + 'native input context requires the canonical release PR', + ); + const commit = await read(`repos/${repository}/git/commits/${pull.head.sha}`); + assert.equal(commit.sha, pull.head.sha); + const preparedSource = { commit: commit.sha, tree: commit.tree?.sha }; + source(preparedSource); + assert.equal( + preparedSource.tree, + currentSource.tree, + event === 'merge_group' + ? 'mixed merge queue source differs from the release PR tree; refresh the release PR against the queue base' + : 'native release input context differs from the PR tree', + ); + assert.ok( + Array.isArray(commit.parents) && commit.parents.length === 1, + 'native prepared PR requires one exact source parent', + ); + assert.match(commit.parents[0].sha, /^[a-f0-9]{40}$/u); + const result = { pullNumber: pull.number, prepareSourceCommit: commit.parents[0].sha }; + if (event !== 'merge_group') return result; + const subject = commit.message?.split(/\r?\n/u)[0]; + assert.ok( + typeof subject === 'string' && subject && !/[\u0000-\u001f\u007f]/u.test(subject), + 'queued release commit requires an exact safe source policy subject', + ); + return { + ...result, + sourcePolicy: { + subject, + base: commit.parents[0].sha, + head: preparedSource.commit, + branch: pull.head.ref, + }, + }; +} + +/** Structural parsing alone grants neither supplier nor producer authority. */ +export function parseNativeReleaseInputRecord(value: NativeReleaseInputRecord) { + fields(value, ['bridge', 'selectedProducts', 'preparedSource', 'buildBound']); + validateNativeVersionSourceBridge(value.bridge); + source(value.preparedSource); + const products = loadProducts(); + assert.ok(Array.isArray(value.selectedProducts) && value.selectedProducts.length > 0); + assert.deepEqual(value.selectedProducts, [...new Set(value.selectedProducts)].sort()); + for (const product of value.selectedProducts) assert.ok(Object.hasOwn(products, product)); + assert.ok(Array.isArray(value.buildBound)); + const buildBound = new Map>(); + for (const row of value.buildBound) { + assert.ok( + Array.isArray(row) && row.length === 2 && typeof row[0] === 'string' && Array.isArray(row[1]), + ); + assert.deepEqual(row[1], [...new Set(row[1])].sort()); + assert.ok(!buildBound.has(row[0]), 'native supplier transport repeats an owner'); + buildBound.set(row[0], new Set(row[1])); + } + resolveBuildBoundCompatibilityProducts(products, { buildBound }); + assert.deepEqual( + value.buildBound.map(([id]) => id), + Object.keys(products).sort(), + ); + return { record: structuredClone(value), buildBound }; +} + +const relativeFile = (file: { path: string; size: number; sha256: string }) => { + assert.match(file.sha256, /^[a-f0-9]{64}$/u); + const name = path.basename(file.path); + assert.match(name, /^[A-Za-z0-9][A-Za-z0-9._-]*$/u); + return path.join('files', file.sha256, name); +}; +function mapSeedFiles( + controls: NativeSeedInputControl[], + map: (file: { path: string; size: number; sha256: string }) => { + path: string; + size: number; + sha256: string; + }, +) { + return controls.map((row) => { + if (row.promotion) + return { + ...row, + promotion: { + ...row.promotion, + frozen: map(row.promotion.frozen), + receipt: map(row.promotion.receipt), + }, + }; + assert.ok(row.reuse); + return { + ...row, + reuse: { + ...row.reuse, + archive: map(row.reuse.archive), + manifest: map(row.reuse.manifest), + ...(row.reuse.metadata ? { metadata: map(row.reuse.metadata) } : {}), + ...(row.reuse.anchor ? { anchor: map(row.reuse.anchor) } : {}), + }, + }; + }); +} + +function copyInputFile(file: { path: string; size: number; sha256: string }, destination: string) { + const before = fileIdentity(file.path); + assert.deepEqual( + { size: before.size, sha256: before.sha256 }, + { size: file.size, sha256: file.sha256 }, + 'native input File changed before transport', + ); + const output = path.join(destination, relativeFile(file)); + mkdirSync(path.dirname(output), { recursive: true }); + if (!existsSync(output)) copyFileSync(file.path, output); + const actual = fileIdentity(output); + assert.deepEqual( + { size: actual.size, sha256: actual.sha256 }, + { size: file.size, sha256: file.sha256 }, + 'transported native seed File differs', + ); + return { ...file, path: output }; +} +function copySeedFiles(controls: NativeSeedInputControl[], destination: string) { + return mapSeedFiles(controls, (file) => copyInputFile(file, destination)); +} +function mapSupplierFiles( + rows: NativeSupplierArtifact[], + map: (file: NativeSupplierArtifact['file']) => NativeSupplierArtifact['file'], +) { + return validateNativeSupplierArtifacts(rows).map((row) => ({ ...row, file: map(row.file) })); +} +function assertSupplierFiles(value: unknown, publications: CompletedPublication[]) { + const rows = validateNativeSupplierArtifacts(value); + for (const row of rows) { + const matches = publications.filter( + (publication) => + publication.product === row.publication.product && + publication.version === row.publication.version, + ); + assert.equal(matches.length, 1, 'retained supplier lacks its unique completed origin'); + assert.deepEqual(row.publication, matches[0], 'retained supplier origin differs'); + const file = fileIdentity(row.file.path); + assert.deepEqual( + { size: file.size, sha256: file.sha256 }, + { size: row.file.size, sha256: row.file.sha256 }, + 'retained supplier File bytes differ', + ); + } + return rows; +} + +function assertFinalInputFiles(inputs: NativeReleaseFinalInputs & { source?: NativeBuildSource }) { + if (inputs.nativeCurrentArtifacts !== undefined) { + const source = inputs.source ?? inputs.nativeCurrentArtifacts[0]?.source; + projectNativeCurrentArtifacts(inputs.nativeCurrentArtifacts, source); + } + if (inputs.extensionFinalInputs !== undefined) + projectNativeExtensionFinalInputs(inputs.extensionFinalInputs); + if (inputs.nativeAppleBase !== undefined) projectNativeAppleBaseInput(inputs.nativeAppleBase); + if (inputs.nativeSwiftSource !== undefined) + projectNativeSwiftSourceInput(inputs.nativeSwiftSource); +} +function mapFinalInputFiles( + inputs: NativeReleaseFinalInputs, + map: (file: ExtensionFinalInputFile) => ExtensionFinalInputFile, +): NativeReleaseFinalInputs { + return { + ...(inputs.nativeCurrentArtifacts === undefined + ? {} + : { + nativeCurrentArtifacts: inputs.nativeCurrentArtifacts.map((row) => ({ + ...row, + file: map(row.file), + })), + }), + ...(inputs.extensionFinalInputs === undefined + ? {} + : { + extensionFinalInputs: inputs.extensionFinalInputs.map((row) => ({ + ...row, + github: row.github.map(map), + npm: row.npm.map(map), + cargo: row.cargo.map(map), + manifest: map(row.manifest), + frozen: map(row.frozen), + })), + }), + ...(inputs.nativeAppleBase === undefined + ? {} + : { + nativeAppleBase: { + ...inputs.nativeAppleBase, + file: map(inputs.nativeAppleBase.file), + framework: map(inputs.nativeAppleBase.framework), + resources: map(inputs.nativeAppleBase.resources), + }, + }), + ...(inputs.nativeSwiftSource === undefined + ? {} + : { + nativeSwiftSource: { + ...inputs.nativeSwiftSource, + archive: map(inputs.nativeSwiftSource.archive), + carrier: map(inputs.nativeSwiftSource.carrier), + ownerCatalog: map(inputs.nativeSwiftSource.ownerCatalog), + bindingsArchive: map(inputs.nativeSwiftSource.bindingsArchive), + }, + }), + }; +} + +/** Public input snapshots transport facts, never current producer or version authority. */ +function publicInputSnapshot(file: string, currentSource: NativeBuildSource) { + const snapshot = readJson(file); + fields(snapshot, [ + 'source', + 'seedControls', + 'supplierPublications', + ...(Object.hasOwn(snapshot, 'supplierArtifacts') ? ['supplierArtifacts'] : []), + ...(Object.hasOwn(snapshot, 'selectedProducts') ? ['selectedProducts'] : []), + ...finalInputFields(snapshot), + ]); + source(snapshot.source); + assert.deepEqual(snapshot.source, currentSource, 'public native inputs source differs'); + assert.ok(Array.isArray(snapshot.seedControls) && Array.isArray(snapshot.supplierPublications)); + assert.ok( + snapshot.seedControls.every((row: NativeSeedInputControl) => row.reuse && !row.promotion), + 'public native inputs cannot promote a current construction', + ); + const products = loadProducts(); + if (Object.hasOwn(snapshot, 'selectedProducts')) { + assert.ok(Array.isArray(snapshot.selectedProducts)); + assert.deepEqual(snapshot.selectedProducts, [...new Set(snapshot.selectedProducts)].sort()); + for (const product of snapshot.selectedProducts) assert.ok(Object.hasOwn(products, product)); + } + const seen = new Set(); + for (const publication of snapshot.supplierPublications as CompletedPublication[]) { + fields(publication, [ + 'product', + 'version', + 'tagName', + 'publicationSha', + 'publicationTree', + 'releaseSha', + ]); + assert.ok(Object.hasOwn(products, publication.product), 'public input supplier owner differs'); + assert.match(publication.version, /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u); + assert.equal(publication.tagName, `${publication.product}-v${publication.version}`); + for (const value of [ + publication.publicationSha, + publication.publicationTree, + publication.releaseSha, + ]) + assert.match(value, /^[a-f0-9]{40}$/u); + const key = `${publication.product}@${publication.version}`; + assert.ok(!seen.has(key), 'public input supplier origin is duplicated'); + seen.add(key); + } + validateNativeSupplierArtifacts(snapshot.supplierArtifacts ?? []); + return snapshot; +} + +/** One acquisition can supply isolated jobs through the existing SHA-addressed File pool. */ +export function transportPublicNativePublicationInputs( + file: string, + directory: string, + currentSource: NativeBuildSource, +) { + source(currentSource); + const snapshot = publicInputSnapshot(file, currentSource); + projectNativeSeedInputs(snapshot.seedControls, currentSource); + const suppliers = assertSupplierFiles( + snapshot.supplierArtifacts ?? [], + snapshot.supplierPublications, + ); + assertFinalInputFiles(snapshot); + const destination = path.resolve(directory); + requireSafeDirectoryChain(path.dirname(destination), { + create: true, + label: 'public native input transport', + }); + assert.ok(!existsSync(destination), 'public native input transport needs an owned directory'); + mkdirSync(destination); + try { + const seedControls = copySeedFiles(snapshot.seedControls, destination); + const supplierArtifacts = mapSupplierFiles(suppliers, (file) => + copyInputFile(file, destination), + ); + const finalInputs = mapFinalInputFiles(snapshot, (file) => ({ + ...file, + ...copyInputFile(file, destination), + })); + projectNativeSeedInputs(seedControls, currentSource); + assertFinalInputFiles(finalInputs); + const result = path.join(destination, 'native-publication-inputs.json'); + writeJson(result, { + ...snapshot, + seedControls, + ...(Object.hasOwn(snapshot, 'supplierArtifacts') ? { supplierArtifacts } : {}), + ...finalInputs, + }); + return result; + } catch (error) { + rmSync(destination, { recursive: true, force: true }); + throw error; + } +} + +/** Same-source relocation derives local paths from File identity, ignoring producer paths. */ +export function importPublicNativePublicationInputs( + directory: string, + currentSource: NativeBuildSource, +) { + source(currentSource); + const snapshot = publicInputSnapshot( + path.join(directory, 'native-publication-inputs.json'), + currentSource, + ); + const seedControls = mapSeedFiles(snapshot.seedControls, (file) => ({ + ...file, + path: path.join(path.resolve(directory), relativeFile(file)), + })); + projectNativeSeedInputs(seedControls, currentSource); + const supplierArtifacts = mapSupplierFiles(snapshot.supplierArtifacts ?? [], (file) => ({ + ...file, + path: path.join(path.resolve(directory), relativeFile(file)), + })); + assertSupplierFiles(supplierArtifacts, snapshot.supplierPublications); + const finalInputs = mapFinalInputFiles(snapshot, (file) => ({ + ...file, + path: path.join(path.resolve(directory), relativeFile(file)), + })); + assertFinalInputFiles(finalInputs); + const output = path.join(directory, 'native-publication-inputs-current.json'); + writeJson(output, { + ...snapshot, + seedControls, + ...(Object.hasOwn(snapshot, 'supplierArtifacts') ? { supplierArtifacts } : {}), + ...finalInputs, + }); + return output; +} +function assertPromotedReceipt(row: NativeSeedInputControl) { + assert.ok(row.promotion, 'prepared seed inputs must retain a qualified construction'); + const receipt = validateSeedConstructionReceipt(readJson(row.promotion.receipt.path)); + assert.deepEqual(receipt.frozen, { + size: row.promotion.frozen.size, + sha256: row.promotion.frozen.sha256, + }); + assert.equal(receipt.intent.family, row.family); + assert.equal(receipt.intent.target, row.target); + assert.equal(receipt.intent.profile, row.profile); +} + +/** Retain original source-specific Files while their authenticated origins still live in the coordinator. */ +export function writeNativeReleaseInputs( + directory: string, + record: NativeReleaseInputRecord, + seedControls: NativeSeedInputControl[], + supplierPublications: CompletedPublication[], + supplierArtifacts: NativeSupplierArtifact[] = [], + finalInputs: NativeReleaseFinalInputs = {}, +) { + parseNativeReleaseInputRecord(record); + projectNativeSeedInputs(seedControls, record.preparedSource); + assertSupplierFiles(supplierArtifacts, supplierPublications); + fields(finalInputs, finalInputFields(finalInputs)); + assertFinalInputFiles(finalInputs); + for (const row of seedControls) { + assertPromotedReceipt(row); + assert.deepEqual(row.promotion?.source, record.bridge.source); + assert.deepEqual(row.promotion?.transition, { + source: record.preparedSource, + updatesSha256: record.bridge.updatesSha256, + }); + } + const destination = path.resolve(directory); + requireSafeDirectoryChain(path.dirname(destination), { + create: true, + label: 'native release inputs', + }); + assert.ok(!existsSync(destination), 'native release inputs need a new owned directory'); + mkdirSync(destination); + try { + const controls = copySeedFiles(seedControls, destination); + const retainedFinalInputs = mapFinalInputFiles(finalInputs, (file) => ({ + ...file, + ...copyInputFile(file, destination), + })); + projectNativeSeedInputs(controls, record.preparedSource); + assertFinalInputFiles(retainedFinalInputs); + writeJson(path.join(destination, 'native-version-source.json'), record); + writeJson(path.join(destination, 'native-publication-inputs.json'), { + source: record.preparedSource, + selectedProducts: record.selectedProducts, + seedControls: controls, + supplierPublications, + ...retainedFinalInputs, + ...(supplierArtifacts.length + ? { + supplierArtifacts: mapSupplierFiles(supplierArtifacts, (file) => + copyInputFile(file, destination), + ), + } + : {}), + }); + return path.join(destination, 'native-publication-inputs.json'); + } catch (error) { + rmSync(destination, { recursive: true, force: true }); + throw error; + } +} + +/** Exact authenticated packet bytes are relocated; original absolute paths never locate Files. */ +export function relocateNativeReleaseInputs( + directory: string, + record: NativeReleaseInputRecord, + currentSource = record.preparedSource, +) { + const snapshot = readJson(path.join(directory, 'native-publication-inputs.json')); + fields(snapshot, [ + 'source', + 'selectedProducts', + 'seedControls', + 'supplierPublications', + ...(Object.hasOwn(snapshot, 'supplierArtifacts') ? ['supplierArtifacts'] : []), + ...finalInputFields(snapshot), + ]); + assert.deepEqual(snapshot.source, record.preparedSource, 'prepared importer source differs'); + assert.deepEqual( + snapshot.selectedProducts, + record.selectedProducts, + 'prepared importer selected products differ', + ); + assert.ok(Array.isArray(snapshot.seedControls) && Array.isArray(snapshot.supplierPublications)); + const controls = mapSeedFiles(snapshot.seedControls, (file) => ({ + ...file, + path: path.join(directory, relativeFile(file)), + })); + const supplierArtifacts = mapSupplierFiles(snapshot.supplierArtifacts ?? [], (file) => ({ + ...file, + path: path.join(directory, relativeFile(file)), + })); + assertSupplierFiles(supplierArtifacts, snapshot.supplierPublications); + const finalInputs = mapFinalInputFiles(snapshot, (file) => ({ + ...file, + path: path.join(path.resolve(directory), relativeFile(file)), + })); + assertFinalInputFiles(finalInputs); + projectNativeSeedInputs(controls, record.preparedSource); + for (const row of controls) { + assertPromotedReceipt(row); + assert.deepEqual( + row.promotion?.source, + record.bridge.source, + 'promoted constructor source differs', + ); + assert.deepEqual(row.promotion?.transition, { + source: record.preparedSource, + updatesSha256: record.bridge.updatesSha256, + }); + if (row.promotion) row.promotion.transition.source = structuredClone(currentSource); + } + projectNativeSeedInputs(controls, currentSource); + return { + ...snapshot, + source: structuredClone(currentSource), + seedControls: controls, + ...(Object.hasOwn(snapshot, 'supplierArtifacts') ? { supplierArtifacts } : {}), + ...finalInputs, + }; +} + +/** Only the canonical reviewed-main Prepare job and independently read PR head supply authority. */ +export async function acquirePreparedNativeReleaseInputs( + { + runId, + pullNumber, + source: currentSource, + directory, + }: { runId: number; pullNumber: number; source: NativeBuildSource; directory: string }, + { read = requestGithubRepositoryJson, download = execute, gitDirectory = ROOT } = {}, +) { + for (const id of [runId, pullNumber]) assert.ok(Number.isSafeInteger(id) && id > 0); + source(currentSource); + const [run, pull] = await Promise.all([ + read(`repos/${repository}/actions/runs/${runId}`), + read(`repos/${repository}/pulls/${pullNumber}`), + ]); + assert.ok( + run.id === runId && + run.event === 'workflow_dispatch' && + run.head_branch === 'main' && + Number.isSafeInteger(run.run_attempt) && + run.run_attempt > 0, + 'native prepared inputs require the canonical main dispatch', + ); + assert.ok( + pull.number === pullNumber && + pull.base?.ref === 'main' && + pull.base?.repo?.full_name === repository && + pull.head?.repo?.full_name === repository && + pull.head?.ref === 'release-please--branches--main', + 'native prepared inputs require the canonical release PR', + ); + const commits = await Promise.all( + [run.head_sha, pull.head.sha].map((sha) => read(`repos/${repository}/git/commits/${sha}`)), + ); + const [codeSource, preparedSource] = commits.map((commit, index) => { + assert.equal(commit.sha, index === 0 ? run.head_sha : pull.head.sha); + const value = { commit: commit.sha, tree: commit.tree?.sha }; + source(value); + return value; + }); + assert.deepEqual( + commits[1].parents?.map((parent) => parent.sha), + [codeSource.commit], + 'native prepared release PR must have the exact source as its sole parent', + ); + const destination = path.resolve(directory); + requireSafeDirectoryChain(path.dirname(destination), { + create: true, + label: 'prepared native input acquisition', + }); + assert.ok(!existsSync(destination), 'prepared native inputs need a new owned directory'); + const scratch = mkdtempSync(path.join(tmpdir(), 'native-prepared-origin-')); + try { + const snapshots = path.join(scratch, 'snapshots'); + await download( + 'bash', + [ + path.join(ROOT, '.github/scripts/download-build-artifacts.sh'), + 'Release', + codeSource.commit, + destination, + '--run-id', + String(runId), + '--job', + 'Prepare release PR', + '--job-success-only', + '--workflow-path', + '.github/workflows/release.yml', + '--event', + 'workflow_dispatch', + '--ref', + 'refs/heads/main', + '--run-attempt', + String(run.run_attempt), + '--source-tree', + codeSource.tree, + '--artifact', + nativeReleaseInputsArtifact, + ], + { + cwd: ROOT, + env: { ...process.env, GH_REPO: repository, OLIPHAUNT_GITHUB_RUN_SNAPSHOT_DIR: snapshots }, + maxBuffer: 1024 * 1024, + }, + ); + const origin = readJson(path.join(snapshots, `run-${runId}.json`)); + assert.equal(origin.repo, repository); + assert.equal(String(origin.runId), String(runId)); + assert.equal(origin.headSha, codeSource.commit); + assert.equal(origin.headTree, codeSource.tree); + assert.equal(origin.workflowName, 'Release'); + assert.equal(origin.workflowPath, '.github/workflows/release.yml'); + assert.equal(origin.runAttempt, run.run_attempt); + assert.equal(origin.event, 'workflow_dispatch'); + assert.equal(origin.headBranch, 'main'); + const job = latestGithubJob(origin, 'Prepare release PR'); + assert.ok(job); + assert.ok( + job.status === 'completed' && job.conclusion === 'success', + 'native Prepare producer did not complete successfully', + ); + const artifacts = [ + githubJobArtifact(origin, job, nativeReleaseInputsArtifact, codeSource.commit), + ]; + assert.ok( + Number.isSafeInteger(artifacts[0].id) && + artifacts[0].id > 0 && + Number.isSafeInteger(artifacts[0].size_in_bytes) && + artifacts[0].size_in_bytes > 0, + ); + assert.match(artifacts[0].digest, /^sha256:[a-f0-9]{64}$/u); + const { record, buildBound } = parseNativeReleaseInputRecord( + readJson(path.join(destination, 'native-version-source.json')), + ); + assert.deepEqual(record.bridge.source, codeSource, 'native Prepare code source differs'); + // The existing publisher preserves an old head on a no-op rerun. Its exact + // tree and parent, rather than a local commit timestamp, identify the output. + assert.equal( + record.preparedSource.tree, + preparedSource.tree, + 'native Prepare release PR tree differs', + ); + assertNativeVersionSourceTransition(record.bridge, currentSource, gitDirectory); + assert.equal( + currentSource.tree, + preparedSource.tree, + 'native prepared candidate tree differs from the qualified release PR', + ); + const gitJson = (tree: string, file: string) => + JSON.parse( + execFileSync('git', ['show', `${tree}:${file}`], { + cwd: gitDirectory, + encoding: 'utf8', + maxBuffer: 64 * 1024 * 1024, + }), + ); + assert.deepEqual( + record.selectedProducts, + releaseProductsFromManifests( + gitJson(currentSource.tree, 'release-please-config.json'), + gitJson(record.bridge.source.tree, '.release-please-manifest.json'), + gitJson(currentSource.tree, '.release-please-manifest.json'), + ), + 'authenticated prepared product set differs from committed versions', + ); + const snapshot = relocateNativeReleaseInputs(destination, record, currentSource); + const snapshotFile = path.join(destination, 'native-publication-inputs-current.json'); + writeJson(snapshotFile, snapshot); + const result = { + snapshotFile, + record, + buildBound, + origin: { + runId, + runAttempt: job.run_attempt, + artifact: artifacts[0], + codeSource, + preparedSource, + }, + }; + // Controlled transport fixtures cannot mint production admission capability. + if (download === execute && read === requestGithubRepositoryJson) { + Object.freeze(result.record); + Object.freeze(result.origin); + Object.freeze(result); + const file = fileIdentity(snapshotFile); + acquiredPreparedInputs.set(result, { + digest: preparedDigest(result), + file: { size: file.size, sha256: file.sha256 }, + }); + } + return result; + } catch (error) { + rmSync(destination, { recursive: true, force: true }); + throw error; + } finally { + rmSync(scratch, { recursive: true, force: true }); + } +} + +if (import.meta.main) { + const { values } = parseArgs({ + options: { + 'run-id': { type: 'string' }, + 'pull-number': { type: 'string' }, + 'output-directory': { type: 'string' }, + 'resolve-context': { type: 'boolean' }, + 'transport-public-inputs': { type: 'string' }, + 'import-public-inputs': { type: 'string' }, + }, + strict: true, + }); + if (values['transport-public-inputs'] || values['import-public-inputs']) { + assert.ok( + !values['resolve-context'] && + !values['run-id'] && + !values['pull-number'] && + Boolean(values['transport-public-inputs']) !== Boolean(values['import-public-inputs']) && + Boolean(values['output-directory']) === Boolean(values['transport-public-inputs']), + 'public input transport needs exactly one export or import operation', + ); + const currentSource = sourceIdentity('HEAD'); + console.log( + values['transport-public-inputs'] + ? transportPublicNativePublicationInputs( + values['transport-public-inputs'], + values['output-directory']!, + currentSource, + ) + : importPublicNativePublicationInputs(values['import-public-inputs']!, currentSource), + ); + } else if (values['resolve-context']) { + assert.ok( + values['run-id'] === undefined && + values['output-directory'] === undefined && + (values['pull-number'] === undefined || /^[1-9][0-9]*$/u.test(values['pull-number'])), + 'native context lookup accepts only an optional pull number', + ); + const context = await resolveNativeReleaseInputContext({ + source: sourceIdentity('HEAD'), + ...(values['pull-number'] === undefined ? {} : { pullNumber: Number(values['pull-number']) }), + }); + const output = [ + `native_inputs=${Boolean(context)}`, + ...(context + ? [`pull_number=${context.pullNumber}`, `prepare_source_sha=${context.prepareSourceCommit}`] + : []), + ...(context?.sourcePolicy + ? Object.entries(context.sourcePolicy).map( + ([key, value]) => `source_policy_${key}=${value}`, + ) + : []), + '', + ].join('\n'); + if (process.env.GITHUB_OUTPUT) appendFileSync(process.env.GITHUB_OUTPUT, output); + else process.stdout.write(output); + } else { + assert.ok( + values['output-directory'] && + /^[1-9][0-9]*$/u.test(values['run-id'] ?? '') && + /^[1-9][0-9]*$/u.test(values['pull-number'] ?? ''), + 'usage: native-release-inputs.mts --run-id ID --pull-number NUMBER --output-directory DIR', + ); + const result = await acquirePreparedNativeReleaseInputs({ + runId: Number(values['run-id']), + pullNumber: Number(values['pull-number']), + source: sourceIdentity('HEAD'), + directory: values['output-directory'], + }); + console.log(result.snapshotFile); + } +} diff --git a/tools/release/native-release-inputs.test.mts b/tools/release/native-release-inputs.test.mts new file mode 100644 index 000000000..91089f663 --- /dev/null +++ b/tools/release/native-release-inputs.test.mts @@ -0,0 +1,1491 @@ +import { expect, test } from 'bun:test'; +import { execFileSync, spawnSync } from 'node:child_process'; +import { + cpSync, + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { cargoPayloadPool } from '../../build_defs/languages/installed/consumer.mts'; +import { + captureSeedConstructionIntent, + writeSeedConstructionReceipt, +} from '../../build_defs/resources/seed_construction.mts'; +import { createDeterministicTar } from '../packaging/archive-directory.mts'; +import { tarArchive } from '../packaging/testdata/tar-fixture.mts'; +import { + loadReleaseMetadata, + nativeSupplierGithubArtifactDeclarations, +} from './bazel-release-metadata.mts'; +import type { ExtensionFinalInputFile } from './native-extension-final-inputs.mts'; +import { fileIdentity } from './native-file-identity.mts'; +import { projectPreparedNativePublicationPlan } from './native-freeze-publication-candidate.mts'; +import { + acquirePreparedNativeReleaseInputs, + assertAcquiredPreparedNativeReleaseInputs, + importPublicNativePublicationInputs, + type NativeReleaseFinalInputs, + parseNativeReleaseInputRecord, + relocateNativeReleaseInputs, + resolveNativeReleaseInputContext, + transportPublicNativePublicationInputs, + writeNativeReleaseInputs, +} from './native-release-inputs.mts'; +import { + nativeArchiveConstructionFinalInputs, + nativeConstructorProducerArtifacts, + writeNativeConstructionInputSnapshot, +} from './native-release-preparation.mts'; +import { + collectNativeVersionUpdates, + commitNativeVersionUpdates, +} from './native-version-source.mts'; +import { loadPublicationCatalog } from './publication-catalog.mts'; +import { discoverPublicationArtifacts, expectedProductArtifactRows } from './publication-lock.mts'; +import { + isNativeCurrentCargoRoot, + isNativeCurrentGithubRoot, +} from './qualified-native-extension-final-inputs.mts'; +import { loadProducts } from './release-graph.mts'; + +async function fixture() { + const root = mkdtempSync(path.join(tmpdir(), 'native-release-inputs-')); + const git = (...args: string[]) => + execFileSync('git', args, { cwd: root, encoding: 'utf8' }).trim(); + git('init', '-q'); + writeFileSync( + path.join(root, 'release-please-config.json'), + JSON.stringify({ + 'changelog-sections': [{ type: 'feat', section: 'Features' }], + packages: { 'src/database-resources': { component: 'database-resources' } }, + }), + ); + const manifest = path.join(root, '.release-please-manifest.json'); + writeFileSync(manifest, '{"src/database-resources":"0.2.2"}\n'); + git('add', '.'); + git( + '-c', + 'user.name=Fixture', + '-c', + 'user.email=fixture@example.invalid', + 'commit', + '-qm', + 'source', + ); + const source = { commit: git('rev-parse', 'HEAD'), tree: git('rev-parse', 'HEAD^{tree}') }; + const collector = collectNativeVersionUpdates(); + const before = readFileSync(manifest); + const after = Buffer.from('{"src/database-resources":"0.2.3"}\n'); + writeFileSync(manifest, after); + collector.observe({ path: '.release-please-manifest.json', before, after }); + const bridge = collector.freeze(source); + const preparedSource = commitNativeVersionUpdates( + bridge, + 'chore(release): prepare main releases', + root, + ); + const record = { + bridge, + selectedProducts: ['database-resources'], + preparedSource, + buildBound: Object.keys(loadProducts()) + .sort() + .map((id) => [id, []] as [string, string[]]), + }; + const seedRoot = path.join(root, 'constructor'); + const pgdata = path.join(seedRoot, 'pgdata'); + const contract = JSON.parse( + readFileSync( + new URL('../../src/database-resources/contracts/contract.json', import.meta.url), + 'utf8', + ), + ); + for (const directory of contract.pgdataDirectories) + mkdirSync(path.join(pgdata, directory), { recursive: true }); + writeFileSync(path.join(pgdata, 'PG_VERSION'), '18\n'); + writeFileSync(path.join(pgdata, 'global/pg_control'), 'original control bytes\n'); + writeFileSync(path.join(pgdata, 'pg_wal/000000010000000000000001'), 'original WAL bytes\n'); + const tool = path.join(seedRoot, 'constructor.mts'); + writeFileSync(tool, 'declared constructor input\n'); + const slot = { family: 'native' as const, target: 'linux-x64-gnu', profile: 'standard' as const }; + const intent = captureSeedConstructionIntent(slot, { command: 'fixture' }, { tool }); + const frozen = path.join(seedRoot, 'seed.tar'); + const receipt = path.join(seedRoot, 'seed.seed-construction.json'); + writeFileSync(frozen, await createDeterministicTar(pgdata)); + writeSeedConstructionReceipt(receipt, intent, frozen, pgdata); + const file = (file: string) => { + const actual = fileIdentity(file); + return { path: file, size: actual.size, sha256: actual.sha256 }; + }; + const controls = [ + { + ...slot, + promotion: { + source, + evidenceDigest: `sha256:${'a'.repeat(64)}`, + invocationId: 'fixture-invocation', + frozen: file(frozen), + receipt: file(receipt), + transition: { source: preparedSource, updatesSha256: bridge.updatesSha256 }, + }, + }, + ]; + const capsule = path.join(root, 'native-release-inputs'); + writeNativeReleaseInputs(capsule, record, controls, []); + return { + root, + git, + record, + controls, + capsule, + cleanup: () => rmSync(root, { recursive: true, force: true }), + }; +} + +function finalInputsFixture(root: string): Required { + const directory = path.join(root, 'original-final-files'); + mkdirSync(directory); + const file = ( + name: string, + label: string, + contents = `original ${name}\n`, + member?: string, + ): ExtensionFinalInputFile => { + const absolute = path.join(directory, name); + writeFileSync(absolute, contents); + const { size, sha256 } = fileIdentity(absolute); + return { + path: absolute, + size, + sha256, + producer: { + evidenceDigest: `sha256:${'a'.repeat(64)}`, + invocationId: 'original-constructor-invocation', + root: label, + configuration: 'b'.repeat(64), + output: `bazel-out/original/bin/${name}`, + }, + ...(member === undefined ? {} : { member }), + }; + }; + return { + extensionFinalInputs: [ + { + product: 'pg-hashids', + owner: 'pg-hashids', + version: '0.1.0', + family: 'native', + target: 'linux-x64-gnu', + github: [ + file( + 'pg-hashids-0.1.0-linux-x64-gnu.tar.gz', + '//src/extensions/pg_hashids:shipping_github', + undefined, + 'archives/pg-hashids-0.1.0-linux-x64-gnu.tar.gz', + ), + ], + npm: [file('pg-hashids-0.1.0.tgz', '//src/extensions/pg_hashids:shipping_npm')], + cargo: [file('pg-hashids-0.1.0.crate', '//src/extensions/pg_hashids:shipping_cargo')], + manifest: file('pg-hashids-release.json', '//src/extensions/pg_hashids:shipping_manifest'), + frozen: file('pg-hashids-frozen.json', '//src/extensions/pg_hashids:shipping_frozen'), + }, + ], + nativeAppleBase: { + owner: 'liboliphaunt-native', + version: '0.3.3', + file: file('ios.json', '//src/native/runtime:apple_ios_manifest_shipping'), + framework: file( + 'liboliphaunt-0.3.3-apple-spm-xcframework.zip', + '//src/native/runtime:apple_swiftpm_shipping', + ), + resources: file( + 'liboliphaunt-0.3.3-runtime-resources-ios-datum64.tar.gz', + '//src/native/runtime:apple_resources_shipping', + ), + }, + nativeSwiftSource: { + owner: 'oliphaunt-swift', + version: '0.8.2', + archive: file( + 'Oliphaunt-source.zip', + '//src/native/sdks/swift:shipping_Oliphaunt-source_zip', + ), + carrier: file( + 'oliphaunt-react-native-ios-carriers.json', + '//src/native/sdks/swift:shipping_oliphaunt-react-native-ios-carriers_json', + JSON.stringify({ + schema: 'oliphaunt-react-native-ios-carrier-v1', + base: { + product: 'liboliphaunt-native', + version: '0.3.3', + tag: 'liboliphaunt-native-v0.3.3', + }, + extensions: [], + carriers: [], + }), + 'src/sdks/swift/Carriers/oliphaunt-react-native-ios-carriers.json', + ), + ownerCatalog: file( + 'extension-owner-catalog.json', + '//src/native/sdks/swift:shipping_extension-owner-catalog_json', + ), + bindingsArchive: file( + 'oliphaunt-swift-0.8.2-bindings.xcframework.zip', + '//src/native/sdks/swift:shipping_bindings', + ), + }, + }; +} + +function finalFiles(inputs: NativeReleaseFinalInputs): ExtensionFinalInputFile[] { + return [ + ...(inputs.nativeCurrentArtifacts ?? []).map((row) => row.file), + ...(inputs.extensionFinalInputs ?? []).flatMap((row) => [ + ...row.github, + ...row.npm, + ...row.cargo, + row.manifest, + row.frozen, + ]), + ...(inputs.nativeAppleBase + ? [ + inputs.nativeAppleBase.file, + inputs.nativeAppleBase.framework, + inputs.nativeAppleBase.resources, + ] + : []), + ...(inputs.nativeSwiftSource + ? [ + inputs.nativeSwiftSource.archive, + inputs.nativeSwiftSource.carrier, + inputs.nativeSwiftSource.ownerCatalog, + inputs.nativeSwiftSource.bindingsArchive, + ] + : []), + ]; +} + +test('native publication scope and versions project the exact Prepare transition without a second ownership graph', async () => { + const f = await fixture(); + try { + expect(projectPreparedNativePublicationPlan(f.record, f.record.preparedSource, f.root)).toEqual( + { + mode: 'release-bump', + publicationSha: f.record.preparedSource.commit, + releaseSha: f.record.preparedSource.commit, + products: ['database-resources'], + versions: { 'database-resources': '0.2.3' }, + }, + ); + expect(() => + projectPreparedNativePublicationPlan( + f.record, + { ...f.record.preparedSource, tree: 'f'.repeat(40) }, + f.root, + ), + ).toThrow(/prepared tree/u); + expect(() => + projectPreparedNativePublicationPlan( + { ...f.record, selectedProducts: ['oliphaunt-query'] }, + f.record.preparedSource, + f.root, + ), + ).toThrow(/actual RP scope/u); + expect(() => assertAcquiredPreparedNativeReleaseInputs(f.record)).toThrow( + /authenticated Prepare/u, + ); + } finally { + f.cleanup(); + } +}); + +test('native release source guard checks ownership and the normalized parent without recalculating suppliers', async () => { + const f = await fixture(); + try { + const run = (branch: string, head = f.record.preparedSource.commit) => + spawnSync( + 'bash', + [ + path.resolve(import.meta.dir, '../../.github/scripts/check-release-intent.sh'), + 'chore(release): prepare main releases', + f.record.bridge.source.commit, + head, + branch, + 'pull_request', + 'refs/pull/17/merge', + '--source-policy-only', + ], + { + cwd: f.root, + env: { + ...process.env, + PATH: `${path.dirname(process.execPath)}${path.delimiter}${process.env.PATH}`, + MOON_BIN: '/definitely-unavailable-moon', + }, + encoding: 'utf8', + timeout: 30_000, + }, + ); + const generated = run('release-please--branches--main'); + expect(generated.status, generated.stderr).toBe(0); + const authored = run('feature'); + expect(authored.status).not.toBe(0); + expect(authored.stderr).toContain('manifest version bumps are release owned'); + f.git( + '-c', + 'user.name=Fixture', + '-c', + 'user.email=fixture@example.invalid', + 'commit', + '--allow-empty', + '-qm', + 'extra', + ); + const extra = run('release-please--branches--main', f.git('rev-parse', 'HEAD')); + expect(extra.status).not.toBe(0); + expect(extra.stderr).toContain('one normalized release-bump commit'); + } finally { + f.cleanup(); + } +}); + +test('public seed facts transport once and relocate for the exact source without prepared authority', async () => { + const f = await fixture(); + try { + const publication = { + product: 'database-resources', + version: '0.2.2', + tagName: 'database-resources-v0.2.2', + publicationSha: 'a'.repeat(40), + publicationTree: 'b'.repeat(40), + releaseSha: 'c'.repeat(40), + }; + const raw = path.join(f.root, 'public.json'); + const snapshot = { + source: f.record.bridge.source, + seedControls: f.controls.map(({ promotion, ...slot }) => ({ + ...slot, + reuse: { + operation: 'adopt', + publication, + archive: promotion.frozen, + manifest: promotion.receipt, + }, + })), + supplierPublications: [publication], + }; + writeFileSync(raw, JSON.stringify(snapshot)); + const exported = path.join(f.root, 'public-export'); + transportPublicNativePublicationInputs(raw, exported, f.record.bridge.source); + const destination = path.join(f.root, 'public-downloaded'); + cpSync(exported, destination, { recursive: true }); + rmSync(path.join(f.root, 'constructor'), { recursive: true }); + const importedFile = importPublicNativePublicationInputs(destination, f.record.bridge.source); + const imported = JSON.parse(readFileSync(importedFile, 'utf8')); + expect(imported.source).toEqual(f.record.bridge.source); + expect(imported.seedControls[0].reuse.archive.path).toStartWith(destination); + expect(imported.seedControls[0].reuse.archive.sha256).toBe( + snapshot.seedControls[0].reuse.archive.sha256, + ); + expect(imported.supplierPublications).toEqual([publication]); + expect(() => assertAcquiredPreparedNativeReleaseInputs(imported)).toThrow( + 'authenticated Prepare', + ); + expect(() => importPublicNativePublicationInputs(destination, f.record.preparedSource)).toThrow( + 'source differs', + ); + writeFileSync(imported.seedControls[0].reuse.archive.path, 'changed public seed'); + expect(() => importPublicNativePublicationInputs(destination, f.record.bridge.source)).toThrow( + 'File bytes differ', + ); + writeFileSync( + raw, + JSON.stringify({ ...snapshot, supplierPublications: [publication, publication] }), + ); + expect(() => + transportPublicNativePublicationInputs( + raw, + path.join(f.root, 'bad-public'), + f.record.bridge.source, + ), + ).toThrow('duplicated'); + writeFileSync(raw, JSON.stringify({ ...snapshot, seedControls: f.controls })); + expect(() => + transportPublicNativePublicationInputs( + raw, + path.join(f.root, 'bad-promotion'), + f.record.bridge.source, + ), + ).toThrow('cannot promote'); + } finally { + f.cleanup(); + } +}); + +test('retained suppliers share the existing public and prepared File pool, relocate by digest, and never authenticate serialized origins', async () => { + const f = await fixture(); + try { + const publication = { + product: 'liboliphaunt-wasix', + version: '0.3.2', + tagName: 'liboliphaunt-wasix-v0.3.2', + publicationSha: 'a'.repeat(40), + publicationTree: 'b'.repeat(40), + releaseSha: 'c'.repeat(40), + }; + const original = path.join(f.root, 'retained-supplier.crate'); + writeFileSync(original, 'opaque retained stream fixture'); + const actual = fileIdentity(original); + const supplierArtifacts = [ + { + publication, + artifact: 'cargo:liboliphaunt-wasix-portable', + file: { path: original, size: actual.size, sha256: actual.sha256 }, + }, + ]; + const raw = path.join(f.root, 'supplier-public.json'); + writeFileSync( + raw, + JSON.stringify({ + source: f.record.bridge.source, + seedControls: [], + supplierPublications: [publication], + supplierArtifacts, + }), + ); + const exported = path.join(f.root, 'supplier-public-export'); + transportPublicNativePublicationInputs(raw, exported, f.record.bridge.source); + const prepared = path.join(f.root, 'supplier-prepared'); + writeNativeReleaseInputs(prepared, f.record, f.controls, [publication], supplierArtifacts); + const downloaded = path.join(f.root, 'supplier-downloaded'); + cpSync(exported, downloaded, { recursive: true }); + rmSync(original); + const imported = JSON.parse( + readFileSync(importPublicNativePublicationInputs(downloaded, f.record.bridge.source), 'utf8'), + ); + expect(imported.supplierArtifacts[0].publication).toEqual(publication); + expect(imported.supplierArtifacts[0].file.path).toStartWith( + path.join(downloaded, 'files', actual.sha256), + ); + expect(readFileSync(imported.supplierArtifacts[0].file.path, 'utf8')).toBe( + 'opaque retained stream fixture', + ); + expect(() => assertAcquiredPreparedNativeReleaseInputs(imported)).toThrow( + 'authenticated Prepare', + ); + const relocated = relocateNativeReleaseInputs(prepared, f.record); + expect(relocated.supplierArtifacts[0].file.path).toStartWith( + path.join(prepared, 'files', actual.sha256), + ); + expect(relocated.supplierArtifacts[0].publication).toEqual(publication); + writeFileSync(imported.supplierArtifacts[0].file.path, 'substituted supplier'); + expect(() => importPublicNativePublicationInputs(downloaded, f.record.bridge.source)).toThrow( + 'supplier File bytes differ', + ); + const snapshot = JSON.parse( + readFileSync(path.join(prepared, 'native-publication-inputs.json'), 'utf8'), + ); + snapshot.supplierPublications[0].publicationTree = 'd'.repeat(40); + writeFileSync(path.join(prepared, 'native-publication-inputs.json'), JSON.stringify(snapshot)); + expect(() => relocateNativeReleaseInputs(prepared, f.record)).toThrow( + 'supplier origin differs', + ); + } finally { + f.cleanup(); + } +}); + +test('public and prepared final constructor facts relocate every File through the existing pool without producer authority', async () => { + const f = await fixture(); + try { + const finalInputs = finalInputsFixture(f.root); + const originals = finalFiles(finalInputs); + const publication = { + product: 'oliphaunt-swift', + version: '0.8.2', + tagName: 'oliphaunt-swift-v0.8.2', + publicationSha: 'c'.repeat(40), + publicationTree: 'd'.repeat(40), + releaseSha: 'e'.repeat(40), + }; + const supplier = { + publication, + artifact: 'swift-source-tag:0.8.2', + source: { + commit: 'f'.repeat(40), + tree: '1'.repeat(40), + member: 'src/sdks/swift/Carriers/oliphaunt-react-native-ios-carriers.json', + blob: '2'.repeat(40), + }, + file: { + path: finalInputs.nativeSwiftSource.archive.path, + size: finalInputs.nativeSwiftSource.archive.size, + sha256: finalInputs.nativeSwiftSource.archive.sha256, + }, + }; + const raw = path.join(f.root, 'final-public.json'); + writeFileSync( + raw, + JSON.stringify({ + source: f.record.bridge.source, + selectedProducts: f.record.selectedProducts, + seedControls: [], + supplierPublications: [publication], + supplierArtifacts: [supplier], + ...finalInputs, + }), + ); + const exported = path.join(f.root, 'final-public-export'); + transportPublicNativePublicationInputs(raw, exported, f.record.bridge.source); + const prepared = path.join(f.root, 'final-prepared'); + writeNativeReleaseInputs( + prepared, + f.record, + f.controls, + [publication], + [supplier], + finalInputs, + ); + const downloaded = path.join(f.root, 'final-downloaded'); + cpSync(exported, downloaded, { recursive: true }); + const serializedFile = path.join(downloaded, 'native-publication-inputs.json'); + const serialized = JSON.parse(readFileSync(serializedFile, 'utf8')); + for (const file of finalFiles(serialized)) + file.path = path.join('/missing/original-producer', path.basename(file.path)); + writeFileSync(serializedFile, JSON.stringify(serialized)); + rmSync(path.join(f.root, 'original-final-files'), { recursive: true }); + const imported = JSON.parse( + readFileSync(importPublicNativePublicationInputs(downloaded, f.record.bridge.source), 'utf8'), + ); + const relocated = relocateNativeReleaseInputs(prepared, f.record, { + ...f.record.preparedSource, + commit: '3'.repeat(40), + }); + expect(finalFiles(imported)).toHaveLength(12); + for (const [index, file] of finalFiles(imported).entries()) { + expect(file.path).toBe( + path.join(downloaded, 'files', file.sha256, path.basename(originals[index].path)), + ); + expect(file.producer).toEqual(originals[index].producer); + expect(file.member).toEqual(originals[index].member); + expect(fileIdentity(file.path).sha256).toBe(originals[index].sha256); + expect(finalFiles(relocated)[index].producer).toEqual(originals[index].producer); + expect(finalFiles(relocated)[index].member).toEqual(originals[index].member); + expect(finalFiles(relocated)[index].path).toStartWith(prepared); + } + expect(imported.supplierArtifacts[0].file.path).toBe(imported.nativeSwiftSource.archive.path); + expect(imported.supplierArtifacts[0].source).toEqual(supplier.source); + expect(imported.selectedProducts).toEqual(f.record.selectedProducts); + expect(relocated.selectedProducts).toEqual(f.record.selectedProducts); + expect(() => assertAcquiredPreparedNativeReleaseInputs(imported)).toThrow( + 'authenticated Prepare', + ); + expect(() => assertAcquiredPreparedNativeReleaseInputs(structuredClone(relocated))).toThrow( + 'authenticated Prepare', + ); + writeFileSync(imported.nativeAppleBase.resources.path, 'substituted original resource File'); + expect(() => importPublicNativePublicationInputs(downloaded, f.record.bridge.source)).toThrow( + 'File bytes differ', + ); + } finally { + f.cleanup(); + } +}); + +test('final constructor transport rejects source, selected scope, tuple identity, and byte substitutions without restamping', async () => { + const f = await fixture(); + try { + const finalInputs = finalInputsFixture(f.root); + const prepared = path.join(f.root, 'final-rejections'); + writeNativeReleaseInputs(prepared, f.record, [], [], [], finalInputs); + const file = path.join(prepared, 'native-publication-inputs.json'); + const snapshot = JSON.parse(readFileSync(file, 'utf8')); + for (const mutate of [ + (value) => { + value.source.commit = 'f'.repeat(40); + }, + (value) => { + value.selectedProducts = ['oliphaunt-query']; + }, + (value) => { + value.nativeAppleBase.owner = 'oliphaunt-swift'; + }, + (value) => { + value.nativeAppleBase.version = '0.3.4'; + }, + (value) => { + value.nativeSwiftSource.version = '0.8.3'; + }, + (value) => { + value.nativeSwiftSource.bindingsArchive.producer.invocationId = 'another-invocation'; + }, + ]) { + const changed = structuredClone(snapshot); + mutate(changed); + writeFileSync(file, JSON.stringify(changed)); + expect(() => relocateNativeReleaseInputs(prepared, f.record)).toThrow(); + } + writeFileSync(file, JSON.stringify(snapshot)); + const publicFile = path.join(f.root, 'wrong-source-final-public.json'); + writeFileSync( + publicFile, + JSON.stringify({ + source: f.record.bridge.source, + seedControls: [], + supplierPublications: [], + ...finalInputs, + }), + ); + expect(() => + transportPublicNativePublicationInputs( + publicFile, + path.join(f.root, 'wrong-source-final-export'), + f.record.preparedSource, + ), + ).toThrow('source differs'); + writeFileSync(finalInputs.extensionFinalInputs[0].frozen.path, 'substituted frozen File'); + const destination = path.join(f.root, 'bad-final-writer'); + expect(() => writeNativeReleaseInputs(destination, f.record, [], [], [], finalInputs)).toThrow( + 'File bytes differ', + ); + expect(existsSync(destination)).toBe(false); + } finally { + f.cleanup(); + } +}); + +test('prepared transport retains original seed and receipt, relocates from exact hashes, and carries one complete supplier map', async () => { + const f = await fixture(); + try { + const destination = path.join(f.root, 'downloaded'); + cpSync(f.capsule, destination, { recursive: true }); + rmSync(path.join(f.root, 'constructor'), { recursive: true }); + const snapshot = relocateNativeReleaseInputs(destination, f.record); + expect(snapshot.seedControls[0].promotion.source).toEqual(f.record.bridge.source); + expect(snapshot.seedControls[0].promotion.frozen.path).toStartWith(destination); + expect(snapshot.seedControls[0].promotion.frozen.sha256).toBe( + f.controls[0].promotion.frozen.sha256, + ); + expect(parseNativeReleaseInputRecord(f.record).buildBound.size).toBe(27); + expect(snapshot).not.toHaveProperty('ready'); + writeFileSync(snapshot.seedControls[0].promotion.frozen.path, 'fresh entropy'); + expect(() => relocateNativeReleaseInputs(destination, f.record)).toThrow(/bytes differ/u); + } finally { + f.cleanup(); + } +}); + +test('producer context is the actual canonical PR parent and skips ordinary PRs or unchanged main without release reads', async () => { + const f = await fixture(); + try { + const pull = { + number: 17, + head: { + ref: 'release-please--branches--main', + sha: f.record.preparedSource.commit, + repo: { full_name: 'f0rr0/oliphaunt' }, + }, + base: { ref: 'main', repo: { full_name: 'f0rr0/oliphaunt' } }, + }; + const read = async (endpoint: string) => + endpoint.endsWith('/pulls/17') + ? pull + : { + sha: f.record.preparedSource.commit, + tree: { sha: f.record.preparedSource.tree }, + parents: [{ sha: f.record.bridge.source.commit }], + }; + const context = await resolveNativeReleaseInputContext( + { source: f.record.preparedSource, pullNumber: 17 }, + { read, gitDirectory: f.root }, + ); + expect(context).toEqual({ pullNumber: 17, prepareSourceCommit: f.record.bridge.source.commit }); + expect( + await resolveNativeReleaseInputContext( + { source: f.record.preparedSource, pullNumber: 17 }, + { + read: async () => ({ ...pull, head: { ...pull.head, ref: 'feature' } }), + gitDirectory: f.root, + }, + ), + ).toBeUndefined(); + f.git( + '-c', + 'user.name=Fixture', + '-c', + 'user.email=fixture@example.invalid', + 'commit', + '--allow-empty', + '-qm', + 'docs only', + ); + const current = { commit: f.git('rev-parse', 'HEAD'), tree: f.git('rev-parse', 'HEAD^{tree}') }; + let reads = 0; + expect( + await resolveNativeReleaseInputContext( + { source: current }, + { + read: async () => { + reads++; + throw new Error('unexpected read'); + }, + pages: async () => { + reads++; + throw new Error('unexpected page'); + }, + gitDirectory: f.root, + }, + ), + ).toBeUndefined(); + expect(reads).toBe(0); + await expect( + resolveNativeReleaseInputContext( + { source: { ...current, tree: 'f'.repeat(40) }, pullNumber: 17 }, + { read, gitDirectory: f.root }, + ), + ).rejects.toThrow(/PR tree/u); + } finally { + f.cleanup(); + } +}); + +test('versioned main resolves the canonical PR associated with that exact commit', async () => { + const f = await fixture(); + try { + const commit = execFileSync( + 'git', + [ + '-c', + 'user.name=Fixture', + '-c', + 'user.email=fixture@example.invalid', + 'commit-tree', + f.record.preparedSource.tree, + '-p', + f.record.bridge.source.commit, + '-m', + 'chore(release): merged candidate', + ], + { cwd: f.root, encoding: 'utf8' }, + ).trim(); + f.git('reset', '--hard', commit); + const current = { commit, tree: f.record.preparedSource.tree }; + const pull = { + number: 17, + merged_at: '2026-10-12T00:00:00Z', + merge_commit_sha: commit, + head: { + ref: 'release-please--branches--main', + sha: f.record.preparedSource.commit, + repo: { full_name: 'f0rr0/oliphaunt' }, + }, + base: { ref: 'main', repo: { full_name: 'f0rr0/oliphaunt' } }, + }; + const options = { + read: async () => ({ + sha: f.record.preparedSource.commit, + tree: { sha: f.record.preparedSource.tree }, + parents: [{ sha: f.record.bridge.source.commit }], + }), + pages: async (endpoint: string) => { + expect(endpoint).toContain(`/commits/${commit}/pulls`); + return [pull]; + }, + gitDirectory: f.root, + }; + expect(await resolveNativeReleaseInputContext({ source: current }, options)).toEqual({ + pullNumber: 17, + prepareSourceCommit: f.record.bridge.source.commit, + }); + f.git( + '-c', + 'user.name=Fixture', + '-c', + 'user.email=fixture@example.invalid', + 'commit', + '--allow-empty', + '-qm', + 'later unchanged controller', + ); + expect(await resolveNativeReleaseInputContext({ source: current }, options)).toEqual({ + pullNumber: 17, + prepareSourceCommit: f.record.bridge.source.commit, + }); + await expect( + resolveNativeReleaseInputContext({ source: { ...current, tree: 'f'.repeat(40) } }, options), + ).rejects.toThrow('source tree differs'); + await expect( + resolveNativeReleaseInputContext( + { source: current }, + { ...options, pages: async () => [pull, pull] }, + ), + ).rejects.toThrow(/one canonical/u); + } finally { + f.cleanup(); + } +}); + +test('merge queue reuses only the exact canonical open release tree and rejects mixed or ambiguous queue contents', async () => { + const f = await fixture(); + try { + const queued = execFileSync( + 'git', + [ + '-c', + 'user.name=Fixture', + '-c', + 'user.email=fixture@example.invalid', + 'commit-tree', + f.record.preparedSource.tree, + '-p', + f.record.bridge.source.commit, + '-m', + 'Merge queue synthetic title', + ], + { cwd: f.root, encoding: 'utf8' }, + ).trim(); + const pull = { + number: 17, + state: 'open', + merged_at: null, + head: { + ref: 'release-please--branches--main', + sha: f.record.preparedSource.commit, + repo: { full_name: 'f0rr0/oliphaunt' }, + }, + base: { ref: 'main', repo: { full_name: 'f0rr0/oliphaunt' } }, + }; + const options = { + gitDirectory: f.root, + pages: async (endpoint: string) => { + expect(endpoint).toContain(`/commits/${queued}/pulls`); + return [pull]; + }, + read: async () => ({ + sha: f.record.preparedSource.commit, + tree: { sha: f.record.preparedSource.tree }, + parents: [{ sha: f.record.bridge.source.commit }], + message: 'chore(release): publish prepared products\n\nRelease body', + }), + }; + const request = { + source: { commit: queued, tree: f.record.preparedSource.tree }, + event: 'merge_group', + }; + expect(await resolveNativeReleaseInputContext(request, options)).toEqual({ + pullNumber: 17, + prepareSourceCommit: f.record.bridge.source.commit, + sourcePolicy: { + subject: 'chore(release): publish prepared products', + base: f.record.bridge.source.commit, + head: f.record.preparedSource.commit, + branch: 'release-please--branches--main', + }, + }); + await expect( + resolveNativeReleaseInputContext(request, { ...options, pages: async () => [pull, pull] }), + ).rejects.toThrow('one canonical'); + await expect( + resolveNativeReleaseInputContext( + { + ...request, + source: { commit: f.record.bridge.source.commit, tree: f.record.bridge.source.tree }, + }, + { ...options, pages: async () => [pull] }, + ), + ).rejects.toThrow('mixed merge queue'); + await expect( + resolveNativeReleaseInputContext(request, { + ...options, + pages: async () => [{ ...pull, merged_at: '2026-10-12' }], + }), + ).rejects.toThrow('canonical open'); + await expect( + resolveNativeReleaseInputContext(request, { + ...options, + read: async () => ({ + sha: f.record.preparedSource.commit, + tree: { sha: f.record.preparedSource.tree }, + parents: [{ sha: f.record.bridge.source.commit }, { sha: 'f'.repeat(40) }], + }), + }), + ).rejects.toThrow('one exact source parent'); + await expect( + resolveNativeReleaseInputContext(request, { + ...options, + read: async () => ({ + ...(await options.read()), + message: 'chore(release): unsafe\toutput', + }), + }), + ).rejects.toThrow('safe source policy subject'); + } finally { + f.cleanup(); + } +}); + +test('ordinary merge queues retain source version checks and do not request release producers', async () => { + const f = await fixture(); + try { + const queued = execFileSync( + 'git', + [ + '-c', + 'user.name=Fixture', + '-c', + 'user.email=fixture@example.invalid', + 'commit-tree', + f.record.bridge.source.tree, + '-p', + f.record.bridge.source.commit, + '-m', + 'Merge queue feature changes', + ], + { cwd: f.root, encoding: 'utf8' }, + ).trim(); + const options = { + gitDirectory: f.root, + pages: async () => [{ state: 'open', merged_at: null, head: { ref: 'feature' } }], + read: async () => { + throw new Error('ordinary queue must not read a Prepare source'); + }, + }; + expect( + await resolveNativeReleaseInputContext( + { + source: { commit: queued, tree: f.record.bridge.source.tree }, + event: 'merge_group', + }, + options, + ), + ).toBeUndefined(); + await expect( + resolveNativeReleaseInputContext( + { + source: f.record.preparedSource, + event: 'merge_group', + }, + options, + ), + ).rejects.toThrow('one canonical open'); + } finally { + f.cleanup(); + } +}); + +for (const fault of [ + 'missing-owner', + 'duplicate-owner', + 'unknown-selected', + 'bridge-digest', + 'changed-receipt-slot', +] as const) + test(`prepared input structure rejects ${fault} without granting origin authority`, async () => { + const f = await fixture(); + try { + const record = structuredClone(f.record); + if (fault === 'missing-owner') record.buildBound.pop(); + if (fault === 'duplicate-owner') record.buildBound.push(record.buildBound[0]); + if (fault === 'unknown-selected') record.selectedProducts = ['unknown']; + if (fault === 'bridge-digest') record.bridge.updatesSha256 = 'f'.repeat(64); + if (fault === 'changed-receipt-slot') { + const controls = structuredClone(f.controls); + controls[0].target = 'linux-arm64-gnu'; + expect(() => + writeNativeReleaseInputs(path.join(f.root, 'bad'), record, controls, []), + ).toThrow(); + } else expect(() => parseNativeReleaseInputRecord(record)).toThrow(); + } finally { + f.cleanup(); + } + }); + +for (const fault of [ + 'none', + 'pr-head', + 'code-source', + 'product-scope', + 'failed-job', + 'artifact-digest', + 'outside-update', + 'feature-dispatch', + 'preserved-old-head', + 'retained-producer-attempt', + 'wrong-parent', +] as const) + test(`actual Prepare acquisition joins PR/API/source/Files (${fault})`, async () => { + const f = await fixture(); + const destination = path.join(f.root, 'acquired'); + try { + // A merge commit can preserve the prepared tree while changing its commit identity. + f.git( + '-c', + 'user.name=Fixture', + '-c', + 'user.email=fixture@example.invalid', + 'commit', + '--allow-empty', + '-qm', + 'merged release PR', + ); + const currentSource = { + commit: f.git('rev-parse', 'HEAD'), + tree: f.git('rev-parse', 'HEAD^{tree}'), + }; + if (fault === 'outside-update') { + writeFileSync(path.join(f.root, 'extra.mts'), 'unrecorded source change'); + f.git('add', 'extra.mts'); + f.git( + '-c', + 'user.name=Fixture', + '-c', + 'user.email=fixture@example.invalid', + 'commit', + '-qm', + 'extra', + ); + currentSource.commit = f.git('rev-parse', 'HEAD'); + currentSource.tree = f.git('rev-parse', 'HEAD^{tree}'); + } + const read = async (endpoint: string) => { + if (endpoint.endsWith('/actions/runs/41')) + return { + id: 41, + event: 'workflow_dispatch', + head_branch: fault === 'feature-dispatch' ? 'feature' : 'main', + head_sha: f.record.bridge.source.commit, + run_attempt: 2, + }; + if (endpoint.endsWith('/pulls/17')) + return { + number: 17, + base: { ref: 'main', repo: { full_name: 'f0rr0/oliphaunt' } }, + head: { + ref: 'release-please--branches--main', + repo: { full_name: 'f0rr0/oliphaunt' }, + sha: + fault === 'pr-head' + ? f.record.bridge.source.commit + : f.record.preparedSource.commit, + }, + }; + const sha = endpoint.split('/').at(-1); + return { + sha, + tree: { sha: f.git('rev-parse', `${sha}^{tree}`) }, + parents: [ + { + sha: fault === 'wrong-parent' ? currentSource.commit : f.record.bridge.source.commit, + }, + ], + }; + }; + let downloads = 0; + const download = async ( + _command: string, + args: string[], + options: { env: Record }, + ) => { + downloads++; + expect(args).toContain('--job-success-only'); + expect(args).toContain('Prepare release PR'); + expect(args).toContain('native-release-inputs'); + cpSync(f.capsule, args[3], { recursive: true }); + const recordFile = path.join(args[3], 'native-version-source.json'); + const record = JSON.parse(readFileSync(recordFile, 'utf8')); + if (fault === 'preserved-old-head') { + record.preparedSource.commit = 'c'.repeat(40); + const snapshotFile = path.join(args[3], 'native-publication-inputs.json'); + const snapshot = JSON.parse(readFileSync(snapshotFile, 'utf8')); + snapshot.source.commit = record.preparedSource.commit; + for (const row of snapshot.seedControls) + row.promotion.transition.source.commit = record.preparedSource.commit; + writeFileSync(snapshotFile, JSON.stringify(snapshot)); + } + if (fault === 'code-source') record.bridge.source = f.record.preparedSource; + if (fault === 'product-scope') record.selectedProducts = ['oliphaunt-query']; + writeFileSync(recordFile, JSON.stringify(record)); + const snapshots = options.env.OLIPHAUNT_GITHUB_RUN_SNAPSHOT_DIR; + mkdirSync(snapshots, { recursive: true }); + writeFileSync( + path.join(snapshots, 'run-41.json'), + JSON.stringify({ + repo: 'f0rr0/oliphaunt', + runId: '41', + headSha: f.record.bridge.source.commit, + headTree: f.record.bridge.source.tree, + workflowName: 'Release', + workflowPath: '.github/workflows/release.yml', + runAttempt: 2, + event: 'workflow_dispatch', + headBranch: 'main', + jobs: [ + { + name: 'Prepare release PR', + run_attempt: fault === 'retained-producer-attempt' ? 1 : 2, + started_at: '2026-10-11T01:00:00Z', + completed_at: '2026-10-11T01:02:00Z', + status: 'completed', + conclusion: fault === 'failed-job' ? 'failure' : 'success', + }, + ], + artifacts: [ + { + name: 'native-release-inputs', + expired: false, + head_sha: f.record.bridge.source.commit, + created_at: '2026-10-11T01:01:00Z', + id: 51, + size_in_bytes: 512, + digest: fault === 'artifact-digest' ? 'unknown' : `sha256:${'b'.repeat(64)}`, + }, + ], + }), + ); + }; + const acquisition = acquirePreparedNativeReleaseInputs( + { runId: 41, pullNumber: 17, source: currentSource, directory: destination }, + { read, download: download as never, gitDirectory: f.root }, + ); + if ( + fault === 'none' || + fault === 'preserved-old-head' || + fault === 'retained-producer-attempt' + ) { + const result = await acquisition; + expect(() => assertAcquiredPreparedNativeReleaseInputs(result)).toThrow( + /authenticated Prepare producer/u, + ); + const snapshot = JSON.parse(readFileSync(result.snapshotFile, 'utf8')); + expect(snapshot.source).toEqual(currentSource); + expect(snapshot.seedControls[0].promotion.transition.source).toEqual(currentSource); + expect(snapshot.seedControls[0].promotion.source).toEqual(f.record.bridge.source); + expect(snapshot.seedControls[0].promotion.frozen.sha256).toBe( + f.controls[0].promotion.frozen.sha256, + ); + expect(result.origin.runAttempt).toBe(fault === 'retained-producer-attempt' ? 1 : 2); + expect(result.buildBound.size).toBe(27); + expect(downloads).toBe(1); + } else { + await expect(acquisition).rejects.toThrow(); + expect(existsSync(destination)).toBe(false); + } + } finally { + f.cleanup(); + } + }); + +test('current Cargo identity survives arbitrary producer filenames and snapshot transport into installed staging', async () => { + const f = await fixture(); + try { + const finalInputs = finalInputsFixture(f.root); + const name = 'native_cargo_export.crate'; + const currentFile = path.join(f.root, name); + writeFileSync( + currentFile, + tarArchive([ + { + name: 'liboliphaunt-native-linux-x64-gnu-0.3.3/Cargo.toml', + data: '[package]\nname = "liboliphaunt-native-linux-x64-gnu"\nversion = "0.3.3"\n', + }, + ]), + ); + const identity = fileIdentity(currentFile); + finalInputs.nativeCurrentArtifacts = [ + { + product: 'liboliphaunt-native', + version: '0.3.3', + artifact: 'cargo:liboliphaunt-native-linux-x64-gnu', + configuration: 'linux-x64-gnu', + source: f.record.preparedSource, + file: { + path: currentFile, + size: identity.size, + sha256: identity.sha256, + producer: { + evidenceDigest: 'sha256:' + 'c'.repeat(64), + invocationId: 'same-candidate-native', + root: '//src/native/runtime:native_cargo_shipping', + configuration: 'd'.repeat(64), + output: 'bazel-out/cfg/bin/cargo-packages', + }, + member: name, + }, + }, + ]; + const inherited = path.join(f.root, 'source-inputs.json'); + const snapshot = { + source: f.record.preparedSource, + selectedProducts: f.record.selectedProducts, + seedControls: [], + supplierPublications: [], + extensionFinalInputs: [], + nativeSwiftSource: finalInputs.nativeSwiftSource, + }; + writeFileSync(inherited, JSON.stringify(snapshot)); + const current = structuredClone(finalInputs); + current.nativeSwiftSource.archive.producer.evidenceDigest = `sha256:${'c'.repeat(64)}`; + for (const key of ['carrier', 'ownerCatalog', 'bindingsArchive']) + current.nativeSwiftSource[key].producer.evidenceDigest = + current.nativeSwiftSource.archive.producer.evidenceDigest; + const output = writeNativeConstructionInputSnapshot({ + source: f.record.preparedSource, + file: inherited, + directory: path.join(f.root, 'source-fresh'), + finalInputs: current, + }); + const written = JSON.parse(readFileSync(output, 'utf8')); + expect(written.source).toEqual(snapshot.source); + expect(written.selectedProducts).toEqual(snapshot.selectedProducts); + expect(written.nativeSwiftSource).toEqual(current.nativeSwiftSource); + expect(written.extensionFinalInputs).toEqual(current.extensionFinalInputs); + expect(written.nativeAppleBase).toEqual(current.nativeAppleBase); + expect(written.nativeCurrentArtifacts).toEqual(current.nativeCurrentArtifacts); + expect(written.nativeSwiftSource.archive.producer.evidenceDigest).not.toBe( + snapshot.nativeSwiftSource.archive.producer.evidenceDigest, + ); + const exported = transportPublicNativePublicationInputs( + output, + path.join(f.root, 'source-export'), + f.record.preparedSource, + ); + const relocated = importPublicNativePublicationInputs( + path.dirname(exported), + f.record.preparedSource, + ); + const imported = JSON.parse(readFileSync(relocated, 'utf8')); + const originalFiles = finalFiles(current), + importedFiles = finalFiles(imported); + expect(importedFiles).toHaveLength(originalFiles.length); + for (const [index, file] of importedFiles.entries()) { + expect(file.path).not.toBe(originalFiles[index].path); + expect(fileIdentity(file.path).sha256).toBe(originalFiles[index].sha256); + expect(file.producer).toEqual(originalFiles[index].producer); + expect(file.member).toEqual(originalFiles[index].member); + } + const importedCurrent = imported.nativeCurrentArtifacts[0]; + expect(path.basename(importedCurrent.file.path)).toBe(name); + expect(discoverPublicationArtifacts([importedCurrent.file.path])).toMatchObject([ + { ecosystem: 'cargo', name: 'liboliphaunt-native-linux-x64-gnu', version: '0.3.3' }, + ]); + expect(importedCurrent.file.producer).toEqual(current.nativeCurrentArtifacts[0].file.producer); + for (const fault of ['none', 'name', 'version', 'owner']) { + const row = structuredClone(importedCurrent); + if (fault === 'name') row.artifact = 'cargo:other-cargo-package'; + if (fault === 'version') row.version = '0.3.4'; + if (fault === 'owner') row.product = 'other-product'; + const staging = path.join(f.root, `cargo-consumer-${fault}`); + mkdirSync(staging); + const read = () => { + const owners = + fault === 'owner' + ? { + 'liboliphaunt-native-linux-x64-gnu': { + product: 'liboliphaunt-native', + version: '0.3.3', + }, + } + : {}; + const pool = cargoPayloadPool( + { completed: [], current: [row], owners }, + {}, + (file) => file, + staging, + ); + return pool.read(pool.current[0]); + }; + if (fault === 'none') + expect(read()).toMatchObject({ + name: 'liboliphaunt-native-linux-x64-gnu', + version: '0.3.3', + sha256: importedCurrent.file.sha256, + }); + else + expect(read).toThrow( + fault === 'owner' ? 'Payload owner differs' : `Payload package ${fault} differs`, + ); + } + const wrongCurrent = structuredClone(written); + wrongCurrent.nativeCurrentArtifacts[0].source.commit = 'f'.repeat(40); + const forged = path.join(f.root, 'wrong-current-source.json'); + writeFileSync(forged, JSON.stringify(wrongCurrent)); + expect(() => + transportPublicNativePublicationInputs( + forged, + path.join(f.root, 'wrong-current-export'), + f.record.preparedSource, + ), + ).toThrow('current native artifact source differs'); + const missing = structuredClone(current); + delete missing.nativeSwiftSource.bindingsArchive; + expect(() => + writeNativeConstructionInputSnapshot({ + source: f.record.preparedSource, + file: inherited, + directory: path.join(f.root, 'missing-source-tuple'), + finalInputs: missing, + }), + ).toThrow('fields differ'); + expect(existsSync(path.join(f.root, 'missing-source-tuple'))).toBe(false); + const restamped = structuredClone(current); + restamped.nativeSwiftSource.version = '0.8.3'; + expect(() => + writeNativeConstructionInputSnapshot({ + source: f.record.preparedSource, + file: inherited, + directory: path.join(f.root, 'restamp'), + finalInputs: restamped, + }), + ).toThrow('name differs'); + expect(() => + writeNativeConstructionInputSnapshot({ + source: f.record.bridge.source, + file: inherited, + directory: path.join(f.root, 'wrong-source'), + finalInputs: current, + }), + ).toThrow('source differs'); + } finally { + f.cleanup(); + } +}); + +test('canonical WASIX core and contrib Cargo roots survive a shared extension constructor owner', () => { + const metadata = loadReleaseMetadata(path.resolve(import.meta.dir, '../..')); + const owner = '//extensions:compiled_carriers'; + const extensionConstructors = new Set([owner]); + const cargoRoot = (carrier: (typeof metadata.publicationCarriers)[number]) => ({ + package: { + product: carrier.product, + ecosystem: carrier.ecosystem, + configuration: carrier.target ?? 'source', + name: carrier.name, + outputs: [{ owner }], + }, + }); + const wasixCarriers = metadata.publicationCarriers.filter( + (row) => + row.product === 'liboliphaunt-wasix' && + row.ecosystem === 'cargo' && + row.target !== null && + row.target !== 'source', + ); + expect(wasixCarriers.some((row) => row.name.startsWith('liboliphaunt-wasix-'))).toBe(true); + expect(wasixCarriers.some((row) => row.name.startsWith('oliphaunt-extension-contrib-'))).toBe( + true, + ); + for (const carrier of wasixCarriers) { + const root = cargoRoot(carrier); + expect(isNativeCurrentCargoRoot(root, metadata, extensionConstructors)).toBe(true); + expect( + isNativeCurrentCargoRoot( + { package: { ...root.package, configuration: 'source' } }, + metadata, + extensionConstructors, + ), + ).toBe(false); + expect( + isNativeCurrentCargoRoot( + { package: { ...root.package, name: `${carrier.name}-uncanonical` } }, + metadata, + extensionConstructors, + ), + ).toBe(false); + } + const extensionCarrier = metadata.publicationCarriers.find( + (row) => + row.ecosystem === 'cargo' && + row.target !== null && + row.target !== 'source' && + metadata.extensionReleaseMetadata.some( + (extension) => extension.class === 'external' && extension.product === row.product, + ), + ); + expect(extensionCarrier).toBeDefined(); + const extensionRoot = cargoRoot(extensionCarrier!); + expect(isNativeCurrentCargoRoot(extensionRoot, metadata, new Set())).toBe(true); + expect(isNativeCurrentCargoRoot(extensionRoot, metadata, extensionConstructors)).toBe(false); +}); + +test('current GitHub construction covers every canonical product asset and rejects other identities', () => { + const metadata = loadReleaseMetadata(path.resolve(import.meta.dir, '../..')); + const declared = new Set( + nativeSupplierGithubArtifactDeclarations(metadata).map(({ product, asset }) => { + const version = metadata.products[product].version; + return `${product}/${version}/${asset.replaceAll('{version}', version)}`; + }), + ); + const rows = expectedProductArtifactRows(loadPublicationCatalog().products); + const assets = rows.filter((row) => row.role === 'github-release-asset'); + for (const row of rows) { + const root = { + package: { + product: row.product, + version: metadata.products[row.product].version, + ecosystem: 'github', + role: row.role, + name: row.name, + }, + }; + expect(isNativeCurrentGithubRoot(root, declared)).toBe(row.role === 'github-release-asset'); + if (row.role !== 'github-release-asset') continue; + for (const change of [ + { product: 'unknown-product' }, + { version: '999.0.0' }, + { ecosystem: 'npm' }, + { role: 'release-input' }, + { name: `${row.name}.unknown` }, + ]) + expect(isNativeCurrentGithubRoot({ package: { ...root.package, ...change } }, declared)).toBe( + false, + ); + } + for (const product of [ + 'database-resources', + 'oliphaunt-swift', + 'liboliphaunt-native', + 'liboliphaunt-wasix', + ]) + expect(assets.some((row) => row.product === product)).toBe(true); +}); + +test('the constructor coordinator keeps RN and WASIX bootstrap roles separate and rejects raw origins', () => { + expect(nativeConstructorProducerArtifacts(['oliphaunt-react-native'])).toEqual([ + 'native-build-evidence-mobile-ios', + ]); + expect(nativeConstructorProducerArtifacts(['oliphaunt-wasix-napi'])).toEqual([ + 'native-build-evidence-wasix-tools', + ]); + expect(nativeConstructorProducerArtifacts(['oliphaunt-wasix-rust'])).toEqual([ + 'native-build-evidence-wasix-tools', + ]); + expect(nativeConstructorProducerArtifacts(['liboliphaunt-wasix-postmaster'])).toEqual([ + 'native-build-evidence-postmaster-linux', + ]); + for (const consumers of [ + ['oliphaunt-react-native', 'oliphaunt-swift'], + ['oliphaunt-react-native', 'oliphaunt-wasix-napi'], + ]) + expect(() => nativeConstructorProducerArtifacts(consumers)).toThrow('canonical consumer'); + const source = { commit: 'a'.repeat(40), tree: 'b'.repeat(40) }; + expect(() => + nativeArchiveConstructionFinalInputs( + { builds: [], origins: new Map([['raw', {}]]) } as any, + source, + ), + ).toThrow('producer plan differs'); + expect(() => + nativeArchiveConstructionFinalInputs( + { + builds: [{ evidenceRoot: 'raw', expected: { source } }], + origins: new Map([['raw', {}]]), + } as any, + source, + ), + ).toThrow('authenticated producer transport'); +}); diff --git a/tools/release/native-release-preparation.mts b/tools/release/native-release-preparation.mts new file mode 100644 index 000000000..37a792639 --- /dev/null +++ b/tools/release/native-release-preparation.mts @@ -0,0 +1,2525 @@ +/** The actual pre-version controller composes existing authentication and delivery readers. */ +import assert from 'node:assert/strict'; +import { + appendFileSync, + chmodSync, + copyFileSync, + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + realpathSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { parseArgs } from 'node:util'; +import { sourceManifest } from '../../build_defs/languages/source-package.mts'; +import { + SEED_CONSTRUCTION_RECEIPT_SUFFIX, + selectCompletedSeed, + validateSeedConstructionReceipt, +} from '../../build_defs/resources/seed_construction.mts'; +import { wasixSeedConsumerDeclaration } from '../../src/database-resources/seeds/wasix/consumer-contract.mts'; +import { + cargoDependencyMinimum, + resolveCargoWorkspaceInheritance, +} from '../packaging/cargo-manifest.mts'; +import { readPortableArchiveEntries } from '../packaging/portable-archive.mts'; +import { + removeOwnedDirectory, + requireSafeDirectoryChain, +} from '../packaging/release-directory-safety.mts'; +import { nativeCargoArtifactRows } from '../packaging/rust-native-targets.mts'; +import { + acquireAuthenticatedNativeBuildEvidence, + assertAuthenticatedNativeBuildOrigin, + createNativeBuildEvidenceAcquirer, + reviewedNativeProducerArtifacts, + validateAuthenticatedNativeBuildEvidence, + validateReviewedNativeProducerAssurance, +} from './authenticate-native-build-evidence.mts'; +import { + loadReleaseMetadata, + nativePublicationInputProjection, + type ReleaseMetadata, +} from './bazel-release-metadata.mts'; +import { selectObservedShippingChanges } from './bazel-shipping-inputs.mts'; +import { cargoCompatibilityDependency } from './compatibility-version-parser.mts'; +import { + type CompletedPublication, + createCompletedPublicationChecker, +} from './completed-release-publication.mts'; +import { captureCompletedSwiftSourceTag } from './completed-swift-source-delivery.mts'; +import { consumerHostTarget } from './frozen-consumer.mts'; +import { + matchesGithubWorkflowRef, + requestGithubPages, + requestGithubRepositoryJson, +} from './github-read.mts'; +import { + assertNativeSwiftShippingPhase, + type NativeBuildSource, + nativeShippingRootsHaveQualification, +} from './native-build-qualification.mts'; +import { + type CompletedDeliveryBaseline, + captureCompletedNativePublicArtifacts, + captureCompletedNativeRegistryCarriers, + captureCompletedNativeSwiftSourceSuppliers, + compareNativeCompletedPhysicalDelivery, + readCompletedNativeDeliveryInventory, +} from './native-completed-delivery.mts'; +import { fileIdentity } from './native-file-identity.mts'; +import { compareNativePreVersionDelivery } from './native-publication-delivery.mts'; +import { + acquireCompletedNativeMetadataBaseline, + type assertAuthenticatedNativePublicBaseline, + readCompletedNativePublicBaseline, +} from './native-publication-metadata.mts'; +import { + type NativePublicationBuild, + observeNativePublicationConstruction, +} from './native-publication-observation.mts'; +import { + NATIVE_EXTENSION_RELEASE_INPUT_ROLES, + nativeTransportStagingMode, +} from './native-publication-staging.mts'; +import { + extensionReleaseDocumentRows, + stageDeclaredExtensionReleaseFiles, +} from './native-extension-release-files.mts'; +import { + type NativeSeedConstructionBaseline, + proposeSeedConstructionAnchor, + readDeclaredSeedConstructionAnchor, + writeSeedConstructionAnchorProposal, +} from './native-seed-baseline.mts'; +import { type NativeSeedInputControl, projectNativeSeedInputs } from './native-seed-inputs.mts'; +import { projectNativeBuildBoundSuppliers } from './native-shipping-suppliers.mts'; +import { + type NativeSupplierArtifact, + validateNativeSupplierArtifacts, +} from './native-supplier-artifacts.mts'; +import { + assertNativeVersionSourceTransition, + type NativeVersionSourceBridge, +} from './native-version-source.mts'; +import { loadPublicationCatalog, resolveActualCarrier } from './publication-catalog.mts'; +import { + buildPublicationCandidate, + discoverPublicationArtifacts, + expectedProductArtifactRows, + lockedPublicationFiles, + sourceIdentity, + validateCargoPayloadPartSets, +} from './publication-lock.mts'; +import { constructionNativeFinalInputs } from './qualified-native-extension-final-inputs.mts'; +import { materializeRegistryCarrierIntegrity } from './registry-integrity.mts'; +import { + allArtifactTargets, + contribCarrierDescriptor, + DESKTOP_TARGETS, + extensionReleaseMetadataRows, +} from './release-artifact-targets.mts'; +import { + compatibilityVersionEntries, + compatibilityVersionFromText, + loadProducts, + productCompatibilityVersion, + ROOT, +} from './release-graph.mts'; +import { requestReleaseAssetProof } from './verify_github_release_attestations.mts'; + +/** Actual SDK declarations request exact internal source floors for installed qualification. */ +export function nativeCargoMinimumBindings( + catalog: ReturnType, + consumerProducts: string[], + readText: (file: string) => string, +) { + const requests = new Map< + string, + { + consumer: string; + producer: string; + producerVersion: string; + requestedCarrier: string; + } + >(); + const consumers = ['oliphaunt-rust', 'oliphaunt-broker'].filter((id) => + consumerProducts.includes(id), + ); + if (!consumers.length) return []; + const workspace = Bun.TOML.parse(readText('Cargo.toml')).workspace ?? {}; + for (const id of consumers) { + const consumer = catalog.products.find((product) => product.id === id); + assert(consumer, 'installed minimum needs its canonical source owner'); + const manifest = resolveCargoWorkspaceInheritance( + Bun.TOML.parse(readText(path.posix.join(consumer.path, 'Cargo.toml'))), + workspace, + ); + const dependencies = new Map< + string, + { carrier: (typeof catalog.carriers)[number]; requirements: string[] } + >(); + for (const table of [manifest, ...Object.values(manifest.target ?? {})] as any[]) + for (const section of ['dependencies', 'build-dependencies']) + for (const [alias, declaration] of Object.entries(table[section] ?? {})) { + const dependency = + typeof declaration === 'string' ? { version: declaration } : (declaration as any); + const carrier = catalog.carriers.find( + (row) => + row.ecosystem === 'cargo' && + row.target === null && + row.name === (dependency.package ?? alias), + ); + if (!carrier) continue; + assert.equal( + typeof dependency.version, + 'string', + `Internal Cargo minimum needs its authored requirement: ${alias}`, + ); + const group = dependencies.get(carrier.name) ?? { carrier, requirements: [] }; + group.requirements.push(dependency.version); + dependencies.set(carrier.name, group); + } + for (const { carrier, requirements } of dependencies.values()) { + const producerVersion = cargoDependencyMinimum(requirements); + // An initial same-source dependency has no publication to acquire. Its + // final qualification still requires the exact prepared selected File. + if (producerVersion === '0.0.0' && carrier.version === '0.0.0') continue; + const request = { + consumer: consumer.id, + producer: carrier.product, + producerVersion, + requestedCarrier: carrier.id, + }; + requests.set(`${consumer.id}/${carrier.id}@${producerVersion}`, request); + } + } + return [...requests.values()]; +} + +/** Request the payload identities written into the public source package. */ +export function nativeCargoPayloadBindings( + catalog: ReturnType, + consumerProducts: string[], + readText: (file: string) => string, + products = loadProducts(), +) { + const requests: { + consumer: string; + producer: string; + producerVersion: string; + requestedCarrier: string; + }[] = []; + for (const id of ['oliphaunt-rust', 'oliphaunt-wasix-rust'].filter((id) => + consumerProducts.includes(id), + )) { + const consumer = catalog.products.find((row) => row.id === id); + assert(consumer, 'Source payload request needs its canonical consumer'); + const compatibility: Record = {}; + for (const entry of compatibilityVersionEntries(products, { requireSourceProduct: true })) { + if (entry.product !== id) continue; + const text = readText(entry.path); + const dependency = cargoCompatibilityDependency(entry, text); + if (dependency?.path !== undefined) continue; + const carrier = + dependency && + catalog.carriers.find( + (row) => + row.product === entry.sourceProduct && + row.ecosystem === 'cargo' && + row.name === dependency.packageName, + ); + if ( + carrier?.target === null && + catalog.carriers.some( + (row) => + row.product === entry.sourceProduct && row.ecosystem === 'cargo' && row.target !== null, + ) + ) + continue; + const version = compatibilityVersionFromText(entry, text); + assert( + !compatibility[entry.sourceProduct] || compatibility[entry.sourceProduct] === version, + 'Source payload compatibility versions conflict', + ); + compatibility[entry.sourceProduct] = version; + } + const artifacts = (producer: string) => + nativeCargoArtifactRows( + producer, + products[producer].artifact_targets.targets, + products[producer].registry_packages, + ); + const manifest = sourceManifest( + readText(path.posix.join(consumer.path, 'Cargo.toml')), + readText('Cargo.toml'), + { + product: id, + version: consumer.version, + compatibility, + dependencyOwners: Object.fromEntries( + catalog.carriers + .filter((row) => row.ecosystem === 'cargo') + .map((row) => [row.name, row.product]), + ), + ...(id === 'oliphaunt-rust' + ? { + nativeArtifacts: artifacts('liboliphaunt-native'), + brokerArtifacts: artifacts('oliphaunt-broker'), + } + : {}), + }, + ); + for (const { carrier, version: producerVersion } of cargoPayloadRequests( + manifest, + catalog, + products, + )) { + if (producerVersion === '0.0.0' && carrier.version === '0.0.0') continue; + requests.push({ + consumer: id, + producer: carrier.product, + producerVersion, + requestedCarrier: carrier.id, + }); + } + } + return requests; +} + +function isCargoPayloadCarrier(carrier, products) { + return ( + carrier.ecosystem === 'cargo' && + (carrier.product === 'liboliphaunt-native' || carrier.product === 'oliphaunt-broker' + ? carrier.target !== null && + products[carrier.product].registry_packages.includes(`crates:${carrier.name}`) + : (['liboliphaunt-wasix', 'postgres-tools-wasix'].includes(carrier.product) && + products[carrier.product].registry_packages.includes(`crates:${carrier.name}`)) || + (carrier.product === 'database-resources' && carrier.name === 'oliphaunt-icu')) + ); +} + +function exactCargoPayloadVersion(requirement: string) { + const exact = + typeof requirement === 'string' && + /^=\s*(\d+\.\d+\.\d+(?:[-+][A-Za-z0-9.-]+)?)$/u.exec(requirement.trim()); + assert(exact, 'Cargo payload requires its exact authored version'); + return exact[1]; +} + +function cargoPayloadRequests(manifest, catalog, products) { + const requests = new Map(); + for (const table of [manifest, ...Object.values(manifest.target ?? {})] as any[]) + for (const section of ['dependencies', 'build-dependencies']) + for (const [alias, declaration] of Object.entries(table[section] ?? {}) as [string, any][]) { + const carrier = catalog.carriers.find( + (row) => row.ecosystem === 'cargo' && row.name === (declaration.package ?? alias), + ); + if (!carrier || !isCargoPayloadCarrier(carrier, products)) continue; + const version = exactCargoPayloadVersion( + typeof declaration === 'string' ? declaration : declaration.version, + ); + const prior = requests.get(carrier.id); + assert(!prior || prior.version === version, 'Cargo payload versions conflict'); + requests.set(carrier.id, { carrier, version }); + } + return [...requests.values()]; +} + +function cacheGithubPages(readPages: typeof requestGithubPages) { + const reads = new Map>(); + return (...args: Parameters) => { + const key = JSON.stringify(args); + let result = reads.get(key); + if (!result) { + result = Promise.resolve(readPages(...args)); + reads.set(key, result); + } + return result; + }; +} + +/** Construct the existing importer snapshot only from authenticated acquisition. + * Old public seeds are explicit adoptions; they supply no historical recipe. + */ +export async function acquireNativePublicationInputs( + { + source, + directory, + consumerProducts = ['database-resources'], + metadataOrigin, + }: { + source: NativeBuildSource; + directory: string; + consumerProducts?: string[]; + metadataOrigin?: { publisherSha: string; bundlePaths: string[] }; + }, + { + readJson = requestGithubRepositoryJson, + readPages = requestGithubPages, + proveAsset = requestReleaseAssetProof, + readBaseline = readCompletedNativePublicBaseline, + readSeedAnchor = readDeclaredSeedConstructionAnchor, + materialize = materializeRegistryCarrierIntegrity, + captureSwiftSource = captureCompletedSwiftSourceTag, + inventory = readCompletedNativeDeliveryInventory, + assertCompleted = undefined as ReturnType | undefined, + } = {}, +) { + const repository = 'f0rr0/oliphaunt'; + const reads = new Map>(); + const read = (endpoint: string) => { + let result = reads.get(endpoint); + if (!result) { + result = Promise.resolve(readJson(endpoint)); + reads.set(endpoint, result); + } + return result; + }; + const pages = cacheGithubPages(readPages); + const complete = + assertCompleted ?? + createCompletedPublicationChecker({ + repository, + readJson: read, + readPages: pages, + }); + const catalog = loadPublicationCatalog('native publication input acquisition'); + assert.ok( + Array.isArray(consumerProducts) && + new Set(consumerProducts).size === consumerProducts.length && + consumerProducts.every((id) => catalog.products.some((product) => product.id === id)), + 'native input requests need unique canonical consumer owners', + ); + const seedConsumer = wasixSeedConsumerDeclaration( + Bun.TOML.parse( + readFileSync(path.join(ROOT, 'src/database-resources/seeds/wasix/Cargo.toml'), 'utf8'), + ), + productCompatibilityVersion('database-resources', 'liboliphaunt-wasix'), + catalog.products.find(({ id }) => id === 'liboliphaunt-wasix')!.version, + ); + const authoredProducts = loadProducts(); + const wasixExtensions = loadReleaseMetadata(ROOT).wasixExtensions; + const conventionalFiles = new Map(); + const conventionalText = (file: string) => { + if (!conventionalFiles.has(file)) + conventionalFiles.set(file, readFileSync(path.join(ROOT, file), 'utf8')); + return conventionalFiles.get(file)!; + }; + const payloadBindings = nativeCargoPayloadBindings( + catalog, + consumerProducts, + conventionalText, + authoredProducts, + ); + const bindings = [ + ...new Map( + compatibilityVersionEntries(authoredProducts, { requireSourceProduct: true }) + .filter((entry) => consumerProducts.includes(entry.product)) + .flatMap((entry) => { + const text = conventionalText(entry.path); + const dependency = cargoCompatibilityDependency(entry, text); + if (dependency?.path !== undefined) return []; + let requestedCarrier = dependency ? `cargo:${dependency.packageName}` : undefined; + const extension = authoredProducts[entry.product].extension; + if ( + entry.sourceProduct === 'liboliphaunt-wasix' && + extension?.class === 'external' && + typeof wasixExtensions[extension.sql_name]?.['native-module-file'] === 'string' + ) + requestedCarrier = 'cargo:liboliphaunt-wasix-portable'; + if (entry.product === 'oliphaunt-wasix-ts') { + if (entry.sourceProduct === 'liboliphaunt-wasix') { + const names = authoredProducts[entry.sourceProduct].registry_packages.filter((name) => + name.startsWith('npm:'), + ); + assert.equal(names.length, 1, 'WASIX SDK needs its authored runtime npm identity'); + requestedCarrier = names[0]; + } else if (entry.sourceProduct === 'oliphaunt-wasix-napi') { + const manifest = JSON.parse(text); + const hosts = catalog.carriers.filter((carrier) => { + if ( + carrier.product !== entry.sourceProduct || + carrier.ecosystem !== 'npm' || + !Object.hasOwn(manifest.optionalDependencies ?? {}, carrier.name) + ) + return false; + const target = consumerHostTarget(carrier.target); + const platform = target && DESKTOP_TARGETS[target]; + return platform?.npmOs === process.platform && platform?.npmCpu === process.arch; + }); + assert.equal(hosts.length, 1, 'WASIX SDK needs its declared host NAPI npm identity'); + requestedCarrier = hosts[0].id; + } + } + return [ + { + consumer: entry.product, + producer: entry.sourceProduct, + producerVersion: dependency + ? cargoDependencyMinimum(compatibilityVersionFromText(entry, text)) + : compatibilityVersionFromText(entry, text), + ...(requestedCarrier ? { requestedCarrier } : {}), + }, + ]; + }) + .filter( + (binding) => + !( + seedConsumer.source === 'current' && + binding.consumer === 'database-resources' && + binding.producer === 'liboliphaunt-wasix' + ), + ) + .filter( + (binding) => + !( + ['oliphaunt-rust', 'oliphaunt-wasix-rust'].includes(binding.consumer) && + binding.producerVersion === '0.0.0' && + catalog.products.some((row) => row.id === binding.producer && row.version === '0.0.0') + ) && + (binding.requestedCarrier || + !payloadBindings.some( + (payload) => + payload.consumer === binding.consumer && + payload.producer === binding.producer && + payload.producerVersion === binding.producerVersion, + )), + ) + .concat(nativeCargoMinimumBindings(catalog, consumerProducts, conventionalText)) + .concat(payloadBindings) + .map((binding) => [ + `${binding.consumer}/${binding.producer}@${binding.producerVersion}/${binding.requestedCarrier ?? 'installed'}`, + binding, + ]), + ).values(), + ]; + const supplierRequests = [ + ...new Map( + bindings.map((binding) => [ + `${binding.producer}@${binding.producerVersion}`, + { product: binding.producer, version: binding.producerVersion }, + ]), + ).values(), + ]; + const resource = catalog.products.find((product) => product.id === 'database-resources'); + assert.ok(resource, 'native publication inputs need the canonical resource owner'); + const publication = async (product: string, version: string) => { + assert.ok( + catalog.products.some((row) => row.id === product), + 'unknown native input supplier owner', + ); + const tagName = `${product}-v${version}`; + const release = await read(`repos/${repository}/releases/tags/${encodeURIComponent(tagName)}`); + return complete({ product, version, tagName, publicationSha: release.target_commitish }); + }; + const supplierPublications: CompletedPublication[] = []; + const supplierArtifacts: NativeSupplierArtifact[] = []; + let metadataBaseline: Awaited> | undefined; + const supplierMetadata = new Map< + string, + Awaited> + >(); + let metadataFile: string | undefined; + for (const request of supplierRequests) { + supplierPublications.push(await publication(request.product, request.version)); + } + const owned = path.resolve(directory); + requireSafeDirectoryChain(path.dirname(owned), { + create: true, + label: 'native publication inputs', + }); + assert.ok(!existsSync(owned), 'native publication inputs require a new owned directory'); + mkdirSync(owned); + const completeSupplier = async (product: string, version: string) => { + const prior = supplierPublications.find( + (row) => row.product === product && row.version === version, + ); + if (prior) return prior; + const completed = await publication(product, version); + supplierPublications.push(completed); + return completed; + }; + const historicalInputs = new Map>>>(); + const completedInventory = (completed: CompletedPublication) => { + const key = `${completed.product}@${completed.version}`; + let result = historicalInputs.get(key); + if (!result) { + result = (async () => { + const release = await read( + `repos/${repository}/releases/tags/${encodeURIComponent(completed.tagName)}`, + ); + const assets = await pages(`repos/${repository}/releases/${release.id}/assets`); + const acquired = await acquireCompletedNativeMetadataBaseline( + { + publication: completed, + directory: path.join(owned, 'metadata', completed.product, completed.version), + assets, + metadataOrigin, + }, + { + proveAsset, + readBaseline, + baselineTransports: { + repository, + assertCompleted: complete, + readJson: read, + readPages: pages, + }, + }, + ); + if (acquired) supplierMetadata.set(key, acquired.baseline); + if (completed.product === resource.id && acquired) { + metadataBaseline = acquired.baseline; + metadataFile = acquired.file; + } + return inventory(completed, { + repository, + assertCompletedPublication: complete, + readJson: read, + ...(acquired ? { metadataBaseline: acquired.baseline } : {}), + }); + })(); + historicalInputs.set(key, result); + } + return result; + }; + const retainCarrier = async ( + completed: CompletedPublication, + carrier: { + id: string; + product: string; + ecosystem: string; + name: string; + declared?: boolean; + artifacts?: { path: string; size: number; sha256: string }[]; + }, + payloadClosure = isCargoPayloadCarrier(carrier, authoredProducts), + ): Promise => { + assert.ok( + ['npm', 'cargo'].includes(carrier.ecosystem), + 'supplier source carrier must be npm or Cargo', + ); + const prior = supplierArtifacts.find( + (row) => + row.artifact === carrier.id && + row.publication.product === completed.product && + row.publication.version === completed.version, + ); + if (prior) return prior; + const retained = await materialize( + { + ...carrier, + version: completed.version, + artifacts: carrier.artifacts?.map((artifact) => ({ + ...artifact, + path: path.basename(artifact.path), + })) ?? [ + { + path: `${carrier.name.split('/').at(-1)}-${completed.version}.${carrier.ecosystem === 'cargo' ? 'crate' : 'tgz'}`, + }, + ], + }, + { + directory: path.join( + owned, + 'suppliers', + completed.product, + completed.version, + `registry-${supplierArtifacts.length}`, + ), + }, + ); + assert.equal( + retained.carrier.artifacts.length, + 1, + 'completed supplier carrier must retain one actual registry archive', + ); + const records = + carrier.ecosystem === 'cargo' + ? discoverPublicationArtifacts([retained.carrier.artifacts[0].path]) + : []; + if (carrier.ecosystem === 'cargo') { + assert.ok( + records.length === 1 && + records[0].ecosystem === carrier.ecosystem && + records[0].name === carrier.name && + records[0].version === completed.version, + 'Completed supplier archive differs from its requested identity', + ); + assert.equal( + records[0].artifacts[0].sha256, + retained.carrier.artifacts[0].sha256, + 'Completed supplier archive SHA differs from retained bytes', + ); + assert.equal( + records[0].artifacts[0].size, + retained.carrier.artifacts[0].size, + 'Completed supplier archive size differs from retained bytes', + ); + } + const row = { + publication: completed, + artifact: carrier.id, + file: retained.carrier.artifacts[0], + }; + supplierArtifacts.push(row); + if (carrier.ecosystem === 'cargo' && carrier.declared) { + const historical = await completedInventory(completed); + const parts = []; + for (const dependency of records[0].dependencies.filter( + (dependency) => + dependency.ecosystem === 'cargo' && dependency.name.startsWith(`${carrier.name}-part-`), + )) { + assert.equal( + exactCargoPayloadVersion(dependency.requirement), + completed.version, + 'Completed Cargo part version differs from its parent', + ); + const frozenPart = historical.carriers.find( + (part) => part.id === `cargo:${dependency.name}`, + ); + assert( + !supplierMetadata.has(`${completed.product}@${completed.version}`) || frozenPart, + 'Completed Cargo part is absent from frozen inventory', + ); + const part = + frozenPart ?? resolveActualCarrier(historical.catalog, 'cargo', dependency.name); + const retainedPart = await retainCarrier(completed, part); + const partRecords = discoverPublicationArtifacts([retainedPart.file.path]); + parts.push({ ...part, packageDependencies: partRecords[0].dependencies }); + } + if (parts.length) + validateCargoPayloadPartSets([ + { ...carrier, packageDependencies: records[0].dependencies }, + ...parts, + ]); + if (payloadClosure) + for (const dependency of records[0].dependencies) { + if ( + dependency.ecosystem !== 'cargo' || + dependency.name.startsWith(`${carrier.name}-part-`) + ) + continue; + const internal = historical.carriers.find( + (entry) => + entry.id === `cargo:${dependency.name}` && + entry.product === completed.product && + entry.version === completed.version && + entry.declared, + ); + if (!internal) continue; + assert.equal( + exactCargoPayloadVersion(dependency.requirement), + completed.version, + 'Completed internal payload version differs from its publication', + ); + await retainCarrier(completed, internal, true); + } + } + // Server qualification follows the authentic held SDK's payload pins. + if (carrier.ecosystem === 'cargo' && ['oliphaunt', 'oliphaunt-wasix'].includes(carrier.name)) { + const manifest = readPortableArchiveEntries(row.file.path).get( + `${carrier.name}-${completed.version}/Cargo.toml`, + ); + assert(manifest?.isFile, 'Completed SDK archive needs its conventional manifest'); + for (const { carrier: payload, version } of cargoPayloadRequests( + Bun.TOML.parse(manifest.data().toString('utf8')), + catalog, + authoredProducts, + )) { + const origin = await completeSupplier(payload.product, version); + const original = (await completedInventory(origin)).carriers.find( + (entry) => entry.id === payload.id, + ); + assert(original, 'Requested Cargo payload is absent from its completed inventory'); + await retainCarrier(origin, original); + } + } + return row; + }; + const retainPublicAssets = async (completed: CompletedPublication, expected) => { + assert.ok(expected.length, 'completed supplier needs canonical public archive rows'); + const release = await read( + `repos/${repository}/releases/tags/${encodeURIComponent(completed.tagName)}`, + ); + const assets = await pages(`repos/${repository}/releases/${release.id}/assets`); + for (const row of expected) { + if ( + supplierArtifacts.some( + (existing) => + existing.artifact === row.id && + existing.publication.product === completed.product && + existing.publication.version === completed.version, + ) + ) + continue; + const matches = assets.filter((asset) => asset.name === row.name); + assert.equal(matches.length, 1, 'completed supplier archive is missing or ambiguous'); + const asset = matches[0]; + assert.ok( + Number.isSafeInteger(asset.id) && + asset.id > 0 && + asset.state === 'uploaded' && + asset.url === `https://api.github.com/repos/${repository}/releases/assets/${asset.id}` && + Number.isSafeInteger(asset.size) && + asset.size > 0 && + (asset.digest == null || /^sha256:[a-f0-9]{64}$/u.test(asset.digest)) && + (row.size === undefined || row.size === asset.size) && + (row.sha256 === undefined || + asset.digest == null || + asset.digest === `sha256:${row.sha256}`), + 'completed supplier asset identity differs', + ); + const file = path.join(owned, 'suppliers', completed.product, completed.version, row.name); + const proof = await proveAsset(asset.url, row.name, asset.size, { + retainedPath: file, + ...(row.sha256 || asset.digest + ? { expectedSha256: row.sha256 ?? asset.digest.slice(7) } + : {}), + }); + const actual = fileIdentity(file); + assert.deepEqual( + { size: actual.size, sha256: actual.sha256 }, + { size: proof.bytes, sha256: proof.sha256 }, + 'completed supplier File differs', + ); + supplierArtifacts.push({ + publication: completed, + artifact: row.id, + file: { path: file, size: actual.size, sha256: actual.sha256 }, + }); + } + }; + const finish = (seedControls: NativeSeedInputControl[], completed?: CompletedPublication) => { + projectNativeSeedInputs(seedControls, source); + const snapshot = { + source: structuredClone(source), + seedControls, + supplierPublications, + ...(supplierArtifacts.length + ? { supplierArtifacts: validateNativeSupplierArtifacts(supplierArtifacts) } + : {}), + }; + const file = path.join(owned, 'native-publication-inputs.json'); + writeFileSync(file, `${JSON.stringify(snapshot)}\n`, { flag: 'wx', mode: 0o600 }); + return { + file, + snapshot, + publication: completed, + supplierMetadata, + ...(metadataBaseline ? { metadataBaseline } : {}), + }; + }; + try { + // Conventional requests identify retained source carriers; configured File origins decide actual consumption. + for (const binding of bindings) { + const completed = await completeSupplier(binding.producer, binding.producerVersion); + const historical = await completedInventory(completed); + if (binding.requestedCarrier) { + const carrier = historical.carriers.find( + (row) => row.product === binding.producer && row.id === binding.requestedCarrier, + ); + assert.ok(carrier, 'requested supplier is absent from its completed inventory'); + await retainCarrier(completed, carrier); + continue; + } + for (const ecosystem of ['cargo', 'npm']) { + const carriers = historical.carriers.filter( + (carrier) => carrier.product === binding.producer && carrier.ecosystem === ecosystem, + ); + if (carriers.length !== 1) continue; + await retainCarrier(completed, carriers[0]); + } + } + const appleConsumers = new Set( + expectedProductArtifactRows( + catalog.products.filter((product) => consumerProducts.includes(product.id)), + ) + .filter((row) => row.target.includes('ios') || row.target.startsWith('apple-')) + .map((row) => row.product), + ); + for (const binding of bindings.filter( + (binding) => + !binding.requestedCarrier && + binding.producer === 'liboliphaunt-native' && + appleConsumers.has(binding.consumer), + )) { + const completed = await completeSupplier(binding.producer, binding.producerVersion); + const rows = (await completedInventory(completed)).publicRows.filter( + (row) => + row.kind === 'apple-swiftpm-binary' || + (row.kind === 'runtime-resources' && row.target === 'ios-datum64'), + ); + assert.equal(rows.length, 2); + await retainPublicAssets(completed, rows); + } + for (const binding of bindings.filter( + (binding) => + !binding.requestedCarrier && + binding.consumer === 'database-resources' && + binding.producer === 'liboliphaunt-wasix', + )) { + const completed = await completeSupplier(binding.producer, binding.producerVersion); + const rows = (await completedInventory(completed)).publicRows.filter( + (row) => row.kind === 'wasix-runtime' && row.target === 'portable', + ); + assert.equal(rows.length, 1, 'WASIX seed consumer needs one canonical portable archive'); + await retainPublicAssets(completed, rows); + } + for (const binding of bindings.filter( + (binding) => !binding.requestedCarrier && binding.producer === 'oliphaunt-broker', + )) { + const completed = await completeSupplier(binding.producer, binding.producerVersion); + const rows = (await completedInventory(completed)).publicRows.filter( + (row) => row.kind === 'broker-helper', + ); + await retainPublicAssets(completed, rows); + } + for (const request of [ + ...new Map( + bindings + .filter((binding) => !binding.requestedCarrier && binding.producer === 'oliphaunt-swift') + .map((binding) => [binding.producerVersion, binding]), + ).values(), + ]) { + const completed = await completeSupplier(request.producer, request.producerVersion); + const historical = await completedInventory(completed); + const rows = historical.publicRows.filter((row) => row.kind === 'swift-bindings'); + assert.equal( + rows.length, + 1, + 'completed Swift source needs its actual owned bindings archive', + ); + await retainPublicAssets(completed, rows); + const bindings = supplierArtifacts.find( + (row) => + row.publication.product === completed.product && + row.publication.version === completed.version && + row.artifact === rows[0].id, + )!; + const retained = await captureSwiftSource( + { + publication: completed, + descriptor: historical.descriptor, + bindings: { name: rows[0].name, sha256: bindings.file.sha256 }, + retainedArchive: path.join( + owned, + 'suppliers', + completed.product, + completed.version, + `swift-source-tag-${completed.version}.tar.gz`, + ), + }, + { assertCompletedPublication: complete, readJson: read, readPages: pages }, + ); + assert.ok( + retained.file, + 'completed Swift source must retain its authenticated Git delivery bytes', + ); + supplierArtifacts.push({ + publication: completed, + artifact: `swift-source-tag:${completed.version}`, + source: retained.source, + file: retained.file, + }); + } + if (consumerProducts.includes('oliphaunt-wasix-ts')) { + const facade = catalog.products.find((product) => product.id === 'oliphaunt-wasix-ts')!; + const facadePublication = await completeSupplier(facade.id, facade.version); + const historicalFacade = await completedInventory(facadePublication); + const carriers = historicalFacade.carriers.filter( + (carrier) => carrier.product === facade.id && carrier.ecosystem === 'npm', + ); + assert.equal(carriers.length, 1); + const retained = await retainCarrier(facadePublication, carriers[0]); + const entries = readPortableArchiveEntries(retained.file.path); + const manifest = entries.get('package/package.json'); + assert.ok(manifest?.isFile, 'completed WASIX facade needs its actual packed package.json'); + const declared = JSON.parse(manifest.data().toString('utf8')); + assert.equal(declared.name, carriers[0].name); + assert.equal(declared.version, facade.version); + const hosts: { publication: CompletedPublication; carrier: any }[] = []; + for (const version of new Set(Object.values(declared.optionalDependencies ?? {}))) { + assert.match( + version as string, + /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u, + 'completed WASIX facade must pin its actual host NAPI version', + ); + const hostPublication = await completeSupplier('oliphaunt-wasix-napi', version as string); + const historicalHost = await completedInventory(hostPublication); + for (const carrier of historicalHost.carriers.filter( + (row) => row.ecosystem === 'npm' && declared.optionalDependencies[row.name] === version, + )) { + const target = consumerHostTarget(carrier.target); + const platform = target && DESKTOP_TARGETS[target]; + if (platform?.npmOs === process.platform && platform?.npmCpu === process.arch) + hosts.push({ publication: hostPublication, carrier }); + } + } + assert.equal(hosts.length, 1, 'WASIX facade acquisition needs one exact historical host'); + await retainCarrier(hosts[0].publication, hosts[0].carrier); + } + if (!consumerProducts.includes(resource.id)) return finish([]); + const completed = await publication(resource.id, resource.version); + const release = await read( + `repos/${repository}/releases/tags/${encodeURIComponent(completed.tagName)}`, + ); + const assets = await pages(`repos/${repository}/releases/${release.id}/assets`); + const historical = await completedInventory(completed); + const rows = historical.publicRows; + const seedRows = rows.filter((row) => ['native-seeds', 'wasix-seeds'].includes(row.kind)); + const files = new Map(); + const retain = async (name: string) => { + const prior = files.get(name); + if (prior) return prior; + const matches = assets.filter((asset) => asset.name === name); + assert.equal(matches.length, 1, 'native seed completed asset is missing or ambiguous'); + const asset = matches[0]; + const row = seedRows.find((row) => row.name === name)!; + assert.ok( + Number.isSafeInteger(asset.id) && + asset.id > 0 && + asset.state === 'uploaded' && + asset.url === `https://api.github.com/repos/${repository}/releases/assets/${asset.id}` && + Number.isSafeInteger(asset.size) && + asset.size > 0 && + (asset.digest == null || /^sha256:[a-f0-9]{64}$/u.test(asset.digest)) && + (row.size === undefined || row.size === asset.size) && + (row.sha256 === undefined || + asset.digest == null || + asset.digest === `sha256:${row.sha256}`), + 'native seed completed asset identity differs', + ); + const retainedPath = path.join(owned, 'files', name); + const proof = await proveAsset(asset.url, name, asset.size, { + retainedPath, + ...(row.sha256 || asset.digest + ? { expectedSha256: row.sha256 ?? asset.digest.slice(7) } + : {}), + }); + const file = { path: retainedPath, size: proof.bytes, sha256: proof.sha256 }; + const retained = fileIdentity(retainedPath); + assert.deepEqual( + { size: retained.size, sha256: retained.sha256 }, + { size: file.size, sha256: file.sha256 }, + 'retained seed File differs from public proof', + ); + files.set(name, file); + return file; + }; + const capturedMetadata = metadataFile ? fileIdentity(metadataFile) : undefined; + const metadata = capturedMetadata + ? { path: metadataFile!, size: capturedMetadata.size, sha256: capturedMetadata.sha256 } + : undefined; + let anchor: { path: string; size: number; sha256: string } | undefined; + if (!metadata) { + const declaration = readSeedAnchor(source); + if (declaration) { + assert.deepEqual( + declaration.anchor.publication, + completed, + 'seed adoption contract differs from the genuine completed origin', + ); + const anchorPath = path.join(owned, 'construction-anchor.json'); + copyFileSync(declaration.file.path, anchorPath); + const captured = fileIdentity(anchorPath); + assert.deepEqual( + { size: captured.size, sha256: captured.sha256 }, + { size: declaration.file.size, sha256: declaration.file.sha256 }, + 'seed adoption contract changed during input acquisition', + ); + anchor = { path: anchorPath, size: captured.size, sha256: captured.sha256 }; + } + } + const seedControls: NativeSeedInputControl[] = []; + for (const row of seedRows.filter((row) => row.name.endsWith('.json'))) { + const manifest = await retain(row.name); + const descriptor = JSON.parse(readFileSync(manifest.path, 'utf8')); + const family = row.kind === 'native-seeds' ? ('native' as const) : ('wasix' as const); + const profile = descriptor.catalogProfile; + assert.ok( + ['standard', 'icu'].includes(profile) && + descriptor.runtime?.engineFamily === family && + descriptor.runtime?.target === row.target, + 'native seed completed descriptor slot differs', + ); + const archiveRow = seedRows.find( + (candidate) => + candidate.name === descriptor.archive?.path && + candidate.target === row.target && + candidate.kind === row.kind, + ); + assert.ok( + archiveRow?.name.endsWith('.tar.zst'), + 'native seed completed descriptor has no canonical archive', + ); + const archive = await retain(archiveRow.name); + const reuse = { + operation: metadata || anchor ? ('reuse' as const) : ('adopt' as const), + publication: completed, + archive, + manifest, + ...(metadata ? { metadata } : {}), + ...(anchor ? { anchor } : {}), + }; + // This temporary value supplies only the slot required by the existing + // byte/descriptor validator. It is neither retained nor a recipe claim. + selectCompletedSeed( + { family, target: row.target, profile, invocation: {}, inputs: [] }, + { ...reuse, operation: 'adopt' }, + ); + seedControls.push({ family, target: row.target, profile, reuse }); + } + return finish(seedControls, completed); + } catch (error) { + rmSync(owned, { recursive: true, force: true }); + throw error; + } +} + +/** The one migration proposal uses real immutable CI receipts and genuine public PGDATA. */ +export async function acquireNativeSeedConstructionAnchor({ + source, + runId, + ref, + directory, +}: { + source: NativeBuildSource; + runId: number; + ref: string; + directory: string; +}) { + const destination = path.resolve(directory); + requireSafeDirectoryChain(path.dirname(destination), { + create: true, + label: 'seed adoption proposal', + }); + assert.ok(!existsSync(destination), 'seed adoption proposal needs a new owned directory'); + mkdirSync(destination); + try { + const inputs = await acquireNativePublicationInputs({ + source, + directory: path.join(destination, 'completed'), + consumerProducts: ['database-resources'], + }); + const { origins } = await acquireNativePublicationBuilds({ + source, + runId, + ref, + directory: path.join(destination, 'producers'), + }); + const anchor = proposeSeedConstructionAnchor({ + source, + origins, + seedControls: inputs.snapshot.seedControls, + }); + const file = path.join(destination, 'construction-anchor.json'); + writeSeedConstructionAnchorProposal(file, anchor); + return file; + } catch (error) { + rmSync(destination, { recursive: true, force: true }); + throw error; + } +} + +/** Acquire configured construction once through the same finite producer roles. + * Coverage/admission belong to the observing caller, never this transport. + */ +export async function acquireNativePublicationBuilds( + { + source, + runId, + directory, + ref = 'refs/heads/main', + excludeArtifactNames = [], + requestedArtifactNames, + }: { + source: NativeBuildSource; + runId: number; + directory: string; + ref?: string; + excludeArtifactNames?: string[]; + requestedArtifactNames?: string[]; + }, + { + readJson = requestGithubRepositoryJson, + readPages = requestGithubPages, + acquire = acquireAuthenticatedNativeBuildEvidence, + } = {}, +) { + assert.ok(Number.isSafeInteger(runId) && runId > 0, 'native construction requires an exact run'); + const repository = 'f0rr0/oliphaunt'; + const run = await readJson(`repos/${repository}/actions/runs/${runId}`); + const contextMatches = + matchesGithubWorkflowRef(run.event, ref, { + headBranch: run.head_branch, + pullRequestNumbers: run.pull_requests?.map((request) => request.number), + }) && + (run.event !== 'push' || run.head_branch === 'main'); + assert.ok( + run.id === runId && + run.head_sha === source.commit && + contextMatches && + run.path === '.github/workflows/bazel.yml' && + run.name === 'Native Bazel qualification' && + Number.isSafeInteger(run.run_attempt) && + run.run_attempt > 0, + 'native construction requires exact eligible qualification', + ); + const allRoles = reviewedNativeProducerArtifacts(); + assert.ok( + excludeArtifactNames.every((name) => + allRoles.some(({ artifactName }) => artifactName === name), + ) && new Set(excludeArtifactNames).size === excludeArtifactNames.length, + 'native construction exclusions must be finite producer roles', + ); + assert.ok( + requestedArtifactNames === undefined || + (requestedArtifactNames.length > 0 && + new Set(requestedArtifactNames).size === requestedArtifactNames.length && + requestedArtifactNames.every( + (name) => + allRoles.some(({ artifactName }) => artifactName === name) && + !excludeArtifactNames.includes(name), + )), + 'native construction requests must use finite producer roles', + ); + const artifacts = await readPages(`repos/${repository}/actions/runs/${runId}/artifacts`, { + itemsField: 'artifacts', + }); + const roles = allRoles.filter( + ({ artifactName }) => + !excludeArtifactNames.includes(artifactName) && + (requestedArtifactNames === undefined || requestedArtifactNames.includes(artifactName)) && + artifacts.some((artifact) => artifact.name === artifactName && artifact.expired === false), + ); + assert.ok(roles.length, 'native construction has no retained source producer artifacts'); + if (requestedArtifactNames) + assert.deepEqual( + roles.map(({ artifactName }) => artifactName).sort(), + [...requestedArtifactNames].sort(), + 'requested native constructor producer is not completed and retained', + ); + const destination = path.resolve(directory); + requireSafeDirectoryChain(path.dirname(destination), { + create: true, + label: 'native construction acquisition', + }); + assert.ok(!existsSync(destination), 'native construction requires a new owned directory'); + mkdirSync(destination); + const origins = new Map>>(); + const builds: NativePublicationBuild[] = []; + const session = + acquire === acquireAuthenticatedNativeBuildEvidence + ? createNativeBuildEvidenceAcquirer() + : undefined; + try { + for (const [index, { job, artifactName }] of roles.entries()) { + const expected = { + source, + github: { + repository, + workflow: 'Native Bazel qualification', + workflowPath: '.github/workflows/bazel.yml', + runId, + job, + }, + workflowRunAttempt: run.run_attempt, + event: run.event as NativePublicationBuild['expected']['event'], + ref, + artifactName, + }; + const evidenceRoot = path.join(destination, String(index)); + const origin = await (session?.acquire ?? acquire)(evidenceRoot, expected); + assert.ok(origin.finalFiles, `native producer ${artifactName} has no physical transport`); + origins.set(evidenceRoot, origin); + const { workflowRunAttempt: _, ...producingExpected } = expected; + builds.push({ + evidenceRoot, + expected: { ...producingExpected, github: origin.github }, + requiredTests: (origin.finalFiles.qualification?.requiredTests ?? []).map( + ({ label, configuration }) => ({ + label, + configuration, + }), + ), + }); + } + return { run, origins, builds }; + } catch (error) { + rmSync(destination, { recursive: true, force: true }); + throw error; + } finally { + session?.dispose(); + } +} + +/** Assemble inputs for the once-only source-owned family checksum producer. + * The workflow may still be running; the existing downloader authenticates + * each finite, already successful producer job before retaining any File. + */ +export async function acquireNativeReleaseArchives( + { + source, + runId, + directory, + ref = 'refs/heads/main', + publicationInputs, + consumerProducts, + }: { + source: NativeBuildSource; + runId: number; + directory: string; + ref?: string; + publicationInputs?: string; + consumerProducts?: string[]; + }, + { + readJson = requestGithubRepositoryJson, + readPages = requestGithubPages, + acquire = acquireAuthenticatedNativeBuildEvidence, + } = {}, +) { + const destination = path.resolve(directory); + requireSafeDirectoryChain(path.dirname(destination), { + create: true, + label: 'native archive assembly', + }); + assert.ok(!existsSync(destination), 'native archive assembly requires a new owned directory'); + const snapshotDirectory = `${destination}.inputs`; + assert.ok( + !existsSync(snapshotDirectory), + 'native archive assembly requires a new owned input snapshot directory', + ); + try { + const construction = await acquireNativePublicationBuilds( + { + source, + runId, + directory: destination, + ref, + excludeArtifactNames: [ + 'native-build-evidence-release-families', + 'native-build-evidence-react-native-macos-arm64', + ], + ...(consumerProducts === undefined + ? {} + : { + requestedArtifactNames: nativeConstructorProducerArtifacts(consumerProducts), + }), + }, + { readJson, readPages, acquire }, + ); + const snapshot = + publicationInputs === undefined + ? undefined + : writeNativeConstructionInputSnapshot({ + source, + file: publicationInputs, + directory: snapshotDirectory, + finalInputs: nativeArchiveConstructionFinalInputs(construction, source), + }); + return { + ...construction, + directory: destination, + ...(snapshot ? { publicationInputs: snapshot } : {}), + }; + } catch (error) { + rmSync(destination, { recursive: true, force: true }); + rmSync(snapshotDirectory, { recursive: true, force: true }); + throw error; + } +} + +/** Existing producer composition owns the tuple used by the selected factory. + * This narrows construction acquisition, never release necessity or admission. */ +export function nativeConstructorProducerArtifacts(consumerProducts: string[]) { + const artifactByConsumer: Record = { + 'oliphaunt-react-native': 'native-build-evidence-mobile-ios', + 'oliphaunt-wasix-napi': 'native-build-evidence-wasix-tools', + 'oliphaunt-wasix-rust': 'native-build-evidence-wasix-tools', + 'liboliphaunt-wasix-postmaster': 'native-build-evidence-postmaster-linux', + }; + assert.ok( + consumerProducts.length === 1 && Object.hasOwn(artifactByConsumer, consumerProducts[0]), + 'native constructor bootstrap requires one canonical consumer', + ); + const roles = reviewedNativeProducerArtifacts().filter( + ({ artifactName }) => artifactName === artifactByConsumer[consumerProducts[0]], + ); + assert.equal(roles.length, 1, 'source-owned constructor role is absent'); + return roles.map(({ artifactName }) => artifactName); +} + +/** Reuse the actual acquired cohort; construction does not assert reviewed-main discipline. */ +export function nativeArchiveConstructionFinalInputs( + construction: Awaited>, + source: NativeBuildSource, + metadata: ReleaseMetadata = loadReleaseMetadata(ROOT), +) { + assert.equal( + construction.builds.length, + construction.origins.size, + 'native construction producer plan differs', + ); + const seen = new Set(); + const bazelVersion = readFileSync(path.join(ROOT, '.bazelversion'), 'utf8').trim(); + const authenticated = construction.builds.map((build) => { + assert.ok(!seen.has(build.evidenceRoot), 'native construction producer repeats'); + seen.add(build.evidenceRoot); + const origin = assertAuthenticatedNativeBuildOrigin( + construction.origins.get(build.evidenceRoot), + ); + assert.deepEqual(build.expected.source, source, 'native constructor input source differs'); + assert.deepEqual( + origin.github, + build.expected.github, + 'native constructor producer context differs', + ); + assert.equal( + origin.artifact.name, + build.expected.artifactName, + 'native constructor artifact role differs', + ); + assert.ok( + origin.finalFiles?.qualification, + 'native constructor requires acquired physical qualification', + ); + const qualification = validateAuthenticatedNativeBuildEvidence(origin, { + source, + github: build.expected.github, + bazelVersion, + requireShippingAnalysis: true, + }); + assert.equal(qualification.testQualification, 'passed'); + assert.equal(qualification.qualificationPolicy, 'bound'); + assert.ok( + qualification.requiredTests.length, + 'native constructor imports need mandatory configured tests', + ); + return { origin, evidence: origin.evidence, qualification }; + }); + return constructionNativeFinalInputs( + { observation: { authenticated }, origins: construction.origins }, + metadata, + ); +} + +/** Replace constructor facts with this source's actual fresh envelopes. + * Source/selection/public completion facts are preserved; this JSON grants no admission. */ +export function writeNativeConstructionInputSnapshot( + { + source, + file, + directory, + finalInputs, + }: { + source: NativeBuildSource; + file: string; + directory: string; + finalInputs: ReturnType; + }, + metadata: ReleaseMetadata = loadReleaseMetadata(ROOT), +) { + const before = fileIdentity(file); + const snapshot = JSON.parse(readFileSync(file, 'utf8')); + assert.deepEqual(snapshot.source, source, 'native construction snapshot source differs'); + // Validate the inherited input facts before replacing only source-constructor tuples. + nativePublicationInputProjection(snapshot, metadata); + const next = { ...snapshot }; + delete next.extensionFinalInputs; + delete next.nativeAppleBase; + delete next.nativeSwiftSource; + delete next.nativeCurrentArtifacts; + Object.assign(next, finalInputs); + nativePublicationInputProjection(next, metadata); + assert.deepEqual(fileIdentity(file), before, 'native construction input snapshot changed'); + const destination = path.resolve(directory); + requireSafeDirectoryChain(path.dirname(destination), { + create: true, + label: 'native constructor inputs', + }); + assert.ok(!existsSync(destination), 'native constructor snapshot needs a new owned directory'); + mkdirSync(destination); + try { + const output = path.join(destination, 'native-publication-inputs.json'); + writeFileSync(output, JSON.stringify(next) + '\n', { flag: 'wx', mode: 0o444 }); + return output; + } catch (error) { + rmSync(destination, { recursive: true, force: true }); + throw error; + } +} + +/** Stage the complete canonical construction inventory from its original producer Files. + * This creates no release selection, reviewed-main assurance, or publication admission. */ +export function stageNativePublicationConstruction({ + source, + runId, + origins, + builds, + directory, +}: { + source: NativeBuildSource; + runId: number; + origins: Awaited>['origins']; + builds: NativePublicationBuild[]; + directory?: string; +}) { + assert.equal(origins.size, builds.length, 'native construction producer inventory differs'); + assert.ok(builds.length, 'native construction requires original producing builds'); + const catalog = loadPublicationCatalog('native release construction'); + const bazelVersion = readFileSync(path.join(ROOT, '.bazelversion'), 'utf8').trim(); + const familyParent = requireSafeDirectoryChain(path.join(ROOT, 'target/native-release-family'), { + create: true, + label: 'native release families', + }); + const familyCapture = + directory === undefined + ? mkdtempSync(path.join(familyParent, `${runId}-`)) + : path.resolve(directory); + if (directory !== undefined) { + const relative = path.relative(ROOT, familyCapture); + assert.ok( + relative.startsWith(`target${path.sep}`) && !relative.split(path.sep).includes('..'), + 'native construction staging must remain under target/', + ); + requireSafeDirectoryChain(path.dirname(familyCapture), { + create: true, + label: 'native construction staging', + }); + assert.ok( + !existsSync(familyCapture), + 'native construction staging requires a new owned directory', + ); + mkdirSync(familyCapture); + } + try { + const artifactRoots: string[] = []; + for (const [index, { evidenceRoot, expected }] of builds.entries()) { + const origin = origins.get(evidenceRoot); + assert.ok(origin); + const qualification = validateAuthenticatedNativeBuildEvidence(origin, { + source, + github: expected.github, + bazelVersion, + requireShippingAnalysis: true, + }); + assert.equal( + qualification.qualificationPolicy, + 'bound', + `native producer ${expected.artifactName} has incomplete source-owned qualification`, + ); + assertNativeSwiftShippingPhase(qualification, 'pre-version'); + assert.ok( + origin.finalFiles && 'stage' in origin.finalFiles, + `native producer ${expected.artifactName} has no physical transport`, + ); + artifactRoots.push( + ...origin.finalFiles.stage({ + excludeRoles: [ + 'github-release-asset', + 'github-release-metadata', + ...NATIVE_EXTENSION_RELEASE_INPUT_ROLES, + ], + artifactPhase: 'pre-version', + stageDirectory: path + .relative(ROOT, path.join(familyCapture, 'registry', String(index))) + .split(path.sep) + .join('/'), + }), + ); + } + const products = catalog.products.map(({ id }) => id); + const publicFamilies = stageNativeReleaseFamilies( + origins, + source, + path.join(familyCapture, 'products'), + ); + // The conventional envelope reader enforces actual complete carrier/artifact inventory. + const candidate = { + ...buildPublicationCandidate({ + products, + artifactRoots: [...artifactRoots, ...publicFamilies], + headRef: source.commit, + artifactPhase: 'pre-version', + }), + scope: 'construction' as const, + }; + return { candidate, products, bazelVersion }; + } catch (error) { + removeOwnedDirectory(familyCapture); + throw error; + } +} + +/** Acquire the historical contract once; current names and payload-part counts are separate facts. */ +export async function acquireCompletedNativeDeliveryBaseline( + { + publication, + directory, + metadataBaseline, + }: { + publication: CompletedPublication; + directory: string; + metadataBaseline?: CompletedDeliveryBaseline['metadataBaseline']; + }, + { + inventory = readCompletedNativeDeliveryInventory, + readJson = requestGithubRepositoryJson, + readPages = requestGithubPages, + assertCompleted = createCompletedPublicationChecker({ repository: 'f0rr0/oliphaunt' }), + materialize = materializeRegistryCarrierIntegrity, + proveAsset = requestReleaseAssetProof, + } = {}, +) { + const historical = await inventory(publication, { + repository: 'f0rr0/oliphaunt', + assertCompletedPublication: assertCompleted, + readJson, + metadataBaseline, + }); + const carriers: Record = {}; + const retained = []; + const published = []; + const pending = [...(historical.carriers ?? historical.catalog.carriers)]; + for (const [index, carrier] of pending.entries()) { + assert.ok(!Object.hasOwn(carriers, carrier.id), 'historical carrier is duplicated'); + const artifacts = + carrier.artifacts?.map(({ path: file, size, sha256 }) => ({ + path: path.basename(file), + size, + sha256, + })) ?? + (carrier.ecosystem === 'maven' + ? [] + : [ + { + path: + carrier.ecosystem === 'cargo' + ? `${carrier.name}-${publication.version}.crate` + : `${carrier.name.split('/').at(-1)}-${publication.version}.tgz`, + }, + ]); + const acquired = await materialize( + { ...carrier, artifacts }, + { directory: path.join(directory, `registry-${index}`) }, + ); + const files = acquired.carrier.artifacts.map(({ path: file }) => file); + carriers[carrier.id] = files; + retained.push(acquired); + const records = discoverPublicationArtifacts(files); + assert.ok( + records.length === 1 && + records[0].ecosystem === carrier.ecosystem && + records[0].name === carrier.name && + records[0].version === publication.version, + 'historical registry archive differs from its declared identity', + ); + published.push({ ...carrier, packageDependencies: records[0].dependencies }); + if (carrier.ecosystem === 'cargo' && carrier.declared) + for (const dependency of records[0].dependencies.filter( + (row) => row.ecosystem === 'cargo' && row.name.startsWith(`${carrier.name}-part-`), + )) { + const frozenPart = + metadataBaseline && + historical.carriers.find((row) => row.id === `cargo:${dependency.name}`); + assert.ok( + !metadataBaseline || frozenPart, + 'completed Cargo part is absent from frozen inventory', + ); + const part = + frozenPart ?? resolveActualCarrier(historical.catalog, 'cargo', dependency.name); + if (!pending.some((row) => row.id === part.id)) pending.push(part); + } + } + validateCargoPayloadPartSets(published); + const release = await readJson( + `repos/f0rr0/oliphaunt/releases/tags/${encodeURIComponent(publication.tagName)}`, + ); + const assets = await readPages(`repos/f0rr0/oliphaunt/releases/${release.id}/assets`); + const productArtifacts: Record = {}; + for (const row of historical.publicRows) { + const matches = assets.filter((asset) => asset.name === row.name); + assert.equal( + matches.length, + 1, + `completed native artifact ${row.name} is missing or ambiguous`, + ); + const asset = matches[0]; + if (row.size !== undefined) + assert.equal(asset.size, row.size, 'completed asset differs from its frozen size'); + if (row.sha256 && typeof asset.digest === 'string') + assert.equal( + asset.digest, + `sha256:${row.sha256}`, + 'completed asset differs from its frozen digest', + ); + const retainedPath = path.join(directory, 'public', row.name); + await proveAsset(asset.url, row.name, asset.size, { + retainedPath, + ...(row.sha256 || typeof asset.digest === 'string' + ? { expectedSha256: row.sha256 ?? asset.digest.replace(/^sha256:/u, '') } + : {}), + }); + productArtifacts[row.id] = retainedPath; + } + return { + baseline: { + publication, + carriers, + productArtifacts, + ...(metadataBaseline ? { metadataBaseline } : {}), + }, + historical, + retained, + assets, + }; +} + +/** A declared initial version and complete public tag inventory distinguish first publication from lost history. */ +export async function assertNeverPublishedNativeProducts( + products: { id: string; version: string }[], + { readPages = requestGithubPages } = {}, +) { + if (!products.length) return; + assert.ok( + new Set(products.map(({ id }) => id)).size === products.length && + products.every(({ id, version }) => /^[a-z][a-z0-9-]*$/u.test(id) && version === '0.0.0'), + 'first publication requires unique canonical initial products', + ); + const [tags, releases] = await Promise.all([ + readPages('repos/f0rr0/oliphaunt/tags'), + readPages('repos/f0rr0/oliphaunt/releases'), + ]); + assert.ok( + Array.isArray(tags) && + tags.every((tag) => typeof tag.name === 'string' && tag.name) && + Array.isArray(releases) && + releases.every((release) => typeof release.tag_name === 'string' && release.tag_name), + 'first publication has no complete public version inventory', + ); + for (const product of products) + assert.ok( + !tags.some((tag) => tag.name.startsWith(`${product.id}-v`)) && + !releases.some((release) => release.tag_name.startsWith(`${product.id}-v`)), + `initial product ${product.id} already has published version history`, + ); +} + +export async function prepareNativeReleaseDelivery( + { + source, + runId, + completedVersions, + directory, + }: { + source: NativeBuildSource; + runId: number; + completedVersions: Record; + directory: string; + }, + { + readJson = requestGithubRepositoryJson, + readPages = requestGithubPages, + acquire = acquireAuthenticatedNativeBuildEvidence, + materialize = materializeRegistryCarrierIntegrity, + proveAsset = requestReleaseAssetProof, + } = {}, +) { + assert.ok( + Number.isSafeInteger(runId) && runId > 0, + 'native preparation requires an exact qualification run', + ); + const repository = 'f0rr0/oliphaunt'; + const reads = new Map>(); + const read = (endpoint: string) => { + if (!reads.has(endpoint)) reads.set(endpoint, Promise.resolve(readJson(endpoint))); + return reads.get(endpoint)!; + }; + const pages = cacheGithubPages(readPages); + const run = await read(`repos/${repository}/actions/runs/${runId}`); + assert.ok( + run.id === runId && + run.head_sha === source.commit && + run.head_branch === 'main' && + run.path === '.github/workflows/bazel.yml' && + run.name === 'Native Bazel qualification' && + ['push', 'workflow_dispatch'].includes(run.event) && + run.status === 'completed' && + run.conclusion === 'success' && + Number.isSafeInteger(run.run_attempt) && + run.run_attempt > 0, + 'native preparation requires successful exact reviewed-main qualification', + ); + const retained = await pages(`repos/${repository}/actions/runs/${runId}/artifacts`, { + itemsField: 'artifacts', + }); + assert.ok( + reviewedNativeProducerArtifacts().some(({ artifactName }) => + retained.some((artifact) => artifact.name === artifactName && artifact.expired === false), + ), + 'native preparation has no retained reviewed producer artifacts', + ); + const catalog = loadPublicationCatalog('native release preparation'); + for (const product of catalog.products) + assert.equal( + completedVersions[product.id], + product.version, + `native pre-version ${product.id} must retain its completed conventional version`, + ); + mkdirSync(directory, { recursive: true }); + const bazelVersion = readFileSync(path.join(ROOT, '.bazelversion'), 'utf8').trim(); + const { origins, builds } = await acquireNativePublicationBuilds( + { source, runId, directory: path.join(directory, 'producers') }, + { readJson: read, readPages: pages, acquire }, + ); + const { candidate, products } = stageNativePublicationConstruction({ + source, + runId, + origins, + builds, + }); + const authenticate = async ( + evidenceRoot: string, + expected: NativePublicationBuild['expected'], + ) => { + const origin = origins.get(evidenceRoot); + const build = builds.find((build) => build.evidenceRoot === evidenceRoot); + assert.ok(origin && build, 'native preparation cannot import an unacquired producer'); + assert.deepEqual( + expected, + build.expected, + 'native preparation cached producer constraints differ', + ); + origin.finalFiles?.assertUnchanged?.(); + return origin; + }; + const observation = await observeNativePublicationConstruction( + { + envelope: candidate, + files: lockedPublicationFiles(candidate), + repository, + bazelVersion, + builds, + reviewedSource: source, + }, + { authenticate }, + ); + const assertCompleted = createCompletedPublicationChecker({ + repository, + readJson: read, + readPages: pages, + }); + const baselines: CompletedDeliveryBaseline[] = []; + const registryReceipts = new Map(); + const retainedRegistry = new Map< + string, + Awaited> + >(); + const publicProofs = new Map(); + const retainedPublic = new Map< + string, + { path: string; name: string; size: number; sha256: string } + >(); + const retainPublic: typeof requestReleaseAssetProof = async (url, name, size, options = {}) => { + const prior = retainedPublic.get(url); + if (prior) { + assert.equal(prior.name, name); + assert.equal(prior.size, size); + const actual = fileIdentity(prior.path); + assert.deepEqual( + { size: actual.size, sha256: actual.sha256 }, + { size: prior.size, sha256: prior.sha256 }, + 'cached completed public File changed', + ); + if (options.expectedSha256) assert.equal(options.expectedSha256, prior.sha256); + if (options.retainedPath && path.resolve(options.retainedPath) !== path.resolve(prior.path)) { + requireSafeDirectoryChain(path.dirname(options.retainedPath), { + create: true, + label: 'retained public input', + }); + assert.ok( + !existsSync(options.retainedPath), + 'retained public input destination already exists', + ); + copyFileSync(prior.path, options.retainedPath); + } + return { + bytes: prior.size, + sha256: prior.sha256, + ...(options.retainedPath ? { path: options.retainedPath } : {}), + }; + } + const proof = await proveAsset(url, name, size, options); + if (options.retainedPath) + retainedPublic.set(url, { + path: options.retainedPath, + name, + size: proof.bytes, + sha256: proof.sha256, + }); + publicProofs.set(url, { bytes: proof.bytes, sha256: proof.sha256 }); + return proof; + }; + let signedSeedBaseline: NativeSeedConstructionBaseline | undefined; + const shippingBaselines: Record< + string, + ReturnType['metadata'] + > = {}; + const unreleased = candidate.products.filter(({ version }) => version === '0.0.0'); + await assertNeverPublishedNativeProducts(unreleased, { readPages: pages }); + for (const product of candidate.products) { + if (product.version === '0.0.0') continue; + const tagName = `${product.id}-v${completedVersions[product.id]}`; + const release = await read(`repos/${repository}/releases/tags/${encodeURIComponent(tagName)}`); + const publication = await assertCompleted({ + product: product.id, + version: completedVersions[product.id], + tagName, + publicationSha: release.target_commitish, + }); + const assets = await pages(`repos/${repository}/releases/${release.id}/assets`); + const metadataBaseline = ( + await acquireCompletedNativeMetadataBaseline( + { publication, directory: path.join(directory, 'completed', product.id, 'public'), assets }, + { proveAsset: retainPublic }, + ) + )?.baseline; + const historical = await acquireCompletedNativeDeliveryBaseline( + { publication, directory: path.join(directory, 'completed', product.id), metadataBaseline }, + { readJson: read, readPages: pages, assertCompleted, materialize, proveAsset: retainPublic }, + ); + for (const retained of historical.retained) { + registryReceipts.set(retained.carrier.id, retained.receipt); + retainedRegistry.set( + `${publication.product}@${publication.version}/${retained.carrier.id}`, + retained, + ); + } + baselines.push(historical.baseline); + if (metadataBaseline) { + // Authentication preserves historical facts. A construction diagnostic + // cannot prove an unchanged qualified footprint or authorize held CI. + if ( + metadataBaseline.metadata.publicationQualification && + metadataBaseline.metadata.construction.every( + (view) => + view.shippingAnalysis === 'bound' && + metadataBaseline.metadata.builds.some( + (build) => build.evidenceDigest === view.evidenceDigest && build.producerAssurance, + ) && + nativeShippingRootsHaveQualification(view.qualificationPolicy, view.roots), + ) + ) + shippingBaselines[product.id] = metadataBaseline.metadata; + if (product.id === 'database-resources') + signedSeedBaseline = { + metadata: metadataBaseline, + files: historical.baseline.productArtifacts, + }; + } + } + const completed = await compareNativeCompletedPhysicalDelivery(candidate, baselines, { + repository, + assertCompletedPublication: assertCompleted, + readJson: read, + readPages: pages, + proveAsset: async (url, name, size) => { + const proof = publicProofs.get(url); + assert.ok( + proof && proof.bytes === size, + `native comparison cannot acquire an unretained public asset ${name}`, + ); + return proof; + }, + registryOptions: { cachedReceipts: registryReceipts }, + unreleasedProducts: unreleased.map(({ id }) => id), + }); + const seedConstructionBaseline = signedSeedBaseline ?? readDeclaredSeedConstructionAnchor(source); + assert.ok( + seedConstructionBaseline, + 'native release preparation requires authenticated completed constructor metadata or the immutable reviewed seed adoption contract', + ); + const shippingChanges = selectObservedShippingChanges( + observation.products, + shippingBaselines, + completed.products, + ); + const decision = compareNativePreVersionDelivery({ + source, + products, + completed, + affectedProducts: shippingChanges.affectedProducts, + observation, + seedConstructionBaseline, + }); + const publicationInputs = await acquireNativePublicationInputs( + { source, directory: path.join(directory, 'publication-inputs'), consumerProducts: products }, + { + readJson: read, + readPages: pages, + assertCompleted, + proveAsset: retainPublic, + materialize: async (carrier, options) => { + const key = `${carrier.product}@${carrier.version}/${carrier.id}`; + const prior = retainedRegistry.get(key); + if (prior) { + for (const file of prior.carrier.artifacts) { + const actual = fileIdentity(file.path); + assert.deepEqual( + { size: actual.size, sha256: actual.sha256 }, + { size: file.size, sha256: file.sha256 }, + 'cached completed registry File changed', + ); + } + return prior; + } + const retained = await materialize(carrier, options); + retainedRegistry.set(key, retained); + return retained; + }, + }, + ); + const supplierBaselines: ((typeof baselines)[number] & { + sourceTags?: NativeSupplierArtifact[]; + })[] = baselines.map((baseline) => ({ + ...baseline, + carriers: { ...baseline.carriers }, + productArtifacts: { ...baseline.productArtifacts }, + })); + for (const row of publicationInputs.snapshot.supplierArtifacts ?? []) { + let baseline = supplierBaselines.find( + (baseline) => + baseline.publication.product === row.publication.product && + baseline.publication.version === row.publication.version, + ); + if (!baseline) { + const metadataBaseline = publicationInputs.supplierMetadata.get( + `${row.publication.product}@${row.publication.version}`, + ); + baseline = { + publication: row.publication, + carriers: {}, + productArtifacts: {}, + ...(metadataBaseline ? { metadataBaseline } : {}), + }; + supplierBaselines.push(baseline); + } + assert.deepEqual( + baseline.publication, + row.publication, + 'retained supplier completed source differs', + ); + if (row.source) { + baseline.sourceTags ??= []; + baseline.sourceTags.push(row); + } else if (row.artifact.startsWith('github-release:')) + baseline.productArtifacts[row.artifact] = row.file.path; + else baseline.carriers[row.artifact] = [row.file.path]; + } + const supplierTransports = { + repository, + assertCompletedPublication: assertCompleted, + readJson: read, + readPages: pages, + proveAsset: async (url, _name, size) => { + const proof = publicProofs.get(url); + assert.ok(proof && proof.bytes === size, 'native supplier lacks its retained public proof'); + return proof; + }, + registryOptions: { cachedReceipts: registryReceipts }, + }; + const suppliers = await projectNativeBuildBoundSuppliers( + { + products: Object.fromEntries( + candidate.products.map((product) => [product.id, { version: product.version }]), + ), + source, + observation, + completed: supplierBaselines.map((baseline) => ({ + publication: baseline.publication, + files: baseline.productArtifacts ?? {}, + carriers: baseline.carriers, + ...(baseline.metadataBaseline ? { metadataBaseline: baseline.metadataBaseline } : {}), + ...(baseline.sourceTags ? { sourceTags: baseline.sourceTags } : {}), + })), + }, + { + authenticateCompleted: async (input) => { + assert.ok( + 'files' in input && !Array.isArray(input.files) && 'carriers' in input, + 'native preparation supplier origin must come from its retained completed baseline', + ); + if ('sourceTags' in input) + return captureCompletedNativeSwiftSourceSuppliers(input, { + ...supplierTransports, + registryOptions: { + cachedReceipts: new Map( + [...retainedRegistry] + .filter(([key]) => + key.startsWith(`${input.publication.product}@${input.publication.version}/`), + ) + .map(([, retained]) => [retained.carrier.id, retained.receipt]), + ), + }, + }); + const publicOrigin = await captureCompletedNativePublicArtifacts( + { + publication: input.publication, + files: input.files, + metadataBaseline: input.metadataBaseline, + }, + supplierTransports, + ); + const registryOrigin = await captureCompletedNativeRegistryCarriers( + { + publication: input.publication, + carriers: input.carriers, + metadataBaseline: input.metadataBaseline, + }, + { + ...supplierTransports, + registryOptions: { + cachedReceipts: new Map( + [...retainedRegistry] + .filter(([key]) => + key.startsWith(`${input.publication.product}@${input.publication.version}/`), + ) + .map(([, retained]) => [retained.carrier.id, retained.receipt]), + ), + }, + }, + ); + return { + ...publicOrigin, + archives: [...publicOrigin.archives, ...registryOrigin.archives], + unknowns: [...publicOrigin.unknowns, ...registryOrigin.unknowns], + }; + }, + }, + ); + // Partial diagnostics cannot become an authority for Release Please. + assert.equal( + decision.releaseDecision, + 'qualified', + `native release decision is incomplete: ${decision.products + .filter((product) => product.necessaryDelivery === 'unknown') + .map((product) => product.product) + .join(', ')}`, + ); + assert.ok( + suppliers.buildBound && !suppliers.unknowns.length, + 'native release compatibility projection is incomplete', + ); + return { + candidate, + observation, + shippingBaselines, + completed, + shippingChanges, + decision, + suppliers, + baselines, + builds, + origins, + publicationInputs, + // Retain the existing one-pass public byte proofs for exact held inputs + // discovered after RP freezes independent producer/consumer scope. + completedPublicFiles: [...retainedPublic.values()].map((file) => + Object.freeze(structuredClone(file)), + ), + }; +} + +/** Conventional readers require host assets and separate checksum outputs together. */ +export function stageNativeReleaseFamilies( + origins: Map>>, + source: NativeBuildSource, + directory: string, + products?: readonly string[], +) { + const destination = path.resolve(directory); + assert.ok( + path.relative(ROOT, destination).startsWith(`target${path.sep}`), + 'native release families must remain under target/', + ); + requireSafeDirectoryChain(path.dirname(destination), { + create: true, + label: 'native release files', + }); + assert.ok(!existsSync(destination), 'native release files require a new owned directory'); + const catalog = loadPublicationCatalog('native release files'); + assert.ok( + products === undefined || + (Array.isArray(products) && + products.length > 0 && + new Set(products).size === products.length && + products.every((id) => catalog.products.some((product) => product.id === id))), + 'native release family selection requires unique canonical product IDs', + ); + const expected = expectedProductArtifactRows(catalog.products); + type PublicFile = { + owner: string; + name: string; + file: string; + member: any; + executionRoot: string; + }; + const publicFiles = new Map(); + const manifests: { owner: string; value: any }[] = []; + const families = new Set(); + mkdirSync(destination); + try { + for (const [evidenceRoot, origin] of origins) { + const evidence = origin.evidence as any; + assert.deepEqual(evidence.source, source, 'native family producer source differs'); + assert.ok(origin.finalFiles, 'native family needs retained authenticated Files'); + origin.finalFiles.assertUnchanged?.(); + for (const [cohort, value] of evidence.cohorts.entries()) + for (const root of value.roots.filter( + (root) => + (products === undefined || products.includes(root.package.product)) && + ((root.package.ecosystem === 'github' && + ['github-release-asset', 'github-release-metadata'].includes(root.package.role)) || + root.package.role === 'extension-release-family-input'), + )) { + const outputPaths = new Set(root.package.outputs.map((output) => output.path)); + const files = value.outputs + .filter((output) => outputPaths.has(output.path)) + .flatMap((output) => + output.members + .filter( + (member) => + member.type === 'file' && + path.posix.basename(member.path || output.path) === + (root.package.role === 'extension-release-family-input' + ? 'extension-artifacts.json' + : root.package.name), + ) + .map((member) => ({ output, member })), + ); + assert.equal( + files.length, + 1, + 'native family identity needs its exact original regular File', + ); + const [{ output, member }] = files; + const file = member.path ? `${output.path}/${member.path}` : output.path; + assert.equal( + origin.finalFiles.files.filter( + (captured) => captured.cohort === cohort && captured.path === file, + ).length, + 1, + 'native family File is absent from authenticated transport', + ); + const retained = path.join(evidenceRoot, 'files', String(cohort), file); + if (root.package.role === 'extension-release-family-input') { + const manifest = JSON.parse(readFileSync(retained, 'utf8')); + assert.equal( + manifest.releaseProduct ?? manifest.product, + root.package.product, + 'native family manifest release owner differs', + ); + assert.equal( + manifest.version, + root.package.version, + 'native family manifest version differs', + ); + manifests.push({ owner: root.package.product, value: manifest }); + continue; + } + const name = root.package.name; + assert.equal( + expected.filter((row) => row.product === root.package.product && row.name === name) + .length, + 1, + `native family ${name} has no unique canonical public owner`, + ); + const key = `${root.package.product}/${name}`; + assert.ok(!publicFiles.has(key), `native family repeats an observed public File ${key}`); + publicFiles.set(key, { + owner: root.package.product, + name, + file: retained, + member, + executionRoot: value.executionRoot, + }); + } + origin.finalFiles.assertUnchanged?.(); + } + const copy = (file: PublicFile, target: string) => { + const mode = nativeTransportStagingMode(file.member, file.executionRoot); + assert.ok( + (mode & 0o400) !== 0 && + (mode & 0o002) === 0 && + !((mode & 0o111) !== 0 && (mode & 0o020) !== 0), + 'native family File has an unsafe captured mode', + ); + requireSafeDirectoryChain(path.dirname(target), { + create: true, + label: 'native release family', + }); + copyFileSync(file.file, target); + chmodSync(target, mode); + const identity = fileIdentity(target); + assert.deepEqual( + { size: identity.size, sha256: identity.sha256 }, + { size: file.member.size, sha256: file.member.sha256 }, + 'native family File changed during relocation', + ); + return identity; + }; + const claimed = new Set(); + const complete = new Set(); + const contrib = contribCarrierDescriptor('native release family'); + for (const { owner, value } of manifests) { + const artifactProduct = value.artifactProduct ?? value.product; + const family = value.family ?? null; + const product = catalog.products.find((product) => product.id === owner)!; + assert.equal(value.version, product.version, 'native family version is not canonical'); + if (artifactProduct === contrib.artifactProduct) { + assert.ok(family === 'native' || family === 'wasix', 'contrib family is not canonical'); + assert.equal( + owner, + family === 'native' ? contrib.nativeOwner : contrib.wasixOwner, + 'contrib family owner differs', + ); + } else { + assert.equal(artifactProduct, owner, 'extension family artifact owner differs'); + assert.ok( + ['exact-extension-artifact', 'exact-extension-bundle'].includes(product.kind), + 'native family is not an extension product', + ); + assert.equal(family, null, 'independent extension family must be complete'); + } + const key = `${owner}/${artifactProduct}/${family ?? 'combined'}`; + assert.ok(!complete.has(key), 'native family repeats its complete aggregate manifest'); + complete.add(key); + const { directAssets: direct } = extensionReleaseDocumentRows(value); + const names = [ + ...direct.map((asset) => asset.name), + ...extensionReleaseMetadataRows( + { id: artifactProduct, version: value.version }, + family, + ).map(([, name]) => name), + ]; + assert.equal(new Set(names).size, names.length, 'native family repeats a public asset'); + const files = names.map((name) => { + const identity = `${owner}/${name}`; + assert.ok( + !claimed.has(identity), + 'native family public File belongs to multiple aggregate manifests', + ); + const file = publicFiles.get(identity); + assert.ok(file, `native family lacks its declared public File ${identity}`); + claimed.add(identity); + return file; + }); + const productRoot = path.join(destination, key); + const byPath = new Map(files.map((file) => [realpathSync(file.file), file])); + const staged = stageDeclaredExtensionReleaseFiles( + value, + files.map((file) => file.file), + productRoot, + ROOT, + (source, target) => copy(byPath.get(source)!, target), + ); + for (const file of files.filter((file) => !direct.some((asset) => asset.name === file.name))) + copy(file, path.join(productRoot, 'release-assets', file.name)); + writeFileSync( + path.join(productRoot, 'extension-artifacts.json'), + `${JSON.stringify(staged.manifest, null, 2)}\n`, + ); + families.add(productRoot); + } + for (const [key, file] of publicFiles) { + if (claimed.has(key)) continue; + const product = catalog.products.find((product) => product.id === file.owner)!; + assert.ok( + allArtifactTargets( + { product: file.owner, surface: 'github-release' }, + 'native release family', + ).some((target) => target.asset.replaceAll('{version}', product.version) === file.name), + `native family ${key} lacks its complete aggregate manifest`, + ); + const family = path.join(destination, file.owner, 'release-assets'); + copy(file, path.join(family, file.name)); + families.add(family); + } + for (const origin of origins.values()) origin.finalFiles.assertUnchanged?.(); + return [...families].sort(); + } catch (error) { + rmSync(destination, { recursive: true, force: true }); + throw error; + } +} + +/** Freeze genuine pre-version constructor Files for final-runtime qualification. */ +export function qualifiedNativeSeedControls( + preparation: Pick< + Awaited>, + 'observation' | 'origins' + >, + bridge: NativeVersionSourceBridge, + finalSource: NativeBuildSource, + directory = ROOT, +) { + const transition = assertNativeVersionSourceTransition(bridge, finalSource, directory); + const controls: NativeSeedInputControl[] = []; + for (const [evidenceRoot, origin] of preparation.origins) { + const build = preparation.observation.authenticated.find( + (build) => + build.origin.evidenceDigest === origin.evidenceDigest && + build.origin.artifact.id === origin.artifact.id, + ); + assert.ok( + build?.producerAssurance && origin.finalFiles, + 'seed promotion requires a retained authenticated reviewed producer', + ); + validateReviewedNativeProducerAssurance(build.producerAssurance, { + source: bridge.source, + github: origin.github, + artifact: origin.artifact, + evidenceDigest: origin.evidenceDigest, + requiredTests: build.qualification.requiredTests, + }); + const finalFiles = origin.finalFiles; + finalFiles.assertUnchanged?.(); + for (const [cohort, evidence] of build.evidence.cohorts.entries()) { + for (const row of evidence.seedConstructions ?? []) { + const receipt = validateSeedConstructionReceipt(JSON.parse(row.contents)); + const frozenPath = `${row.path.slice(0, -SEED_CONSTRUCTION_RECEIPT_SUFFIX.length)}.tar`; + const file = (name: string) => { + const captured = finalFiles.files.filter( + (file) => file.cohort === cohort && file.path === name, + ); + assert.equal( + captured.length, + 1, + 'seed promotion needs its exact authenticated supporting File', + ); + return { + path: path.join(evidenceRoot, 'files', String(cohort), name), + size: captured[0].size, + sha256: captured[0].sha256, + }; + }; + const frozen = file(frozenPath); + assert.deepEqual( + { size: frozen.size, sha256: frozen.sha256 }, + receipt.frozen, + 'seed promotion original constructor TAR differs', + ); + controls.push({ + family: receipt.intent.family, + target: receipt.intent.target, + profile: receipt.intent.profile, + promotion: { + source: structuredClone(bridge.source), + evidenceDigest: origin.evidenceDigest, + invocationId: build.qualification.cohorts[cohort].invocationId, + frozen, + receipt: file(row.path), + transition, + }, + }); + } + } + } + // The existing importer validates exact File bytes and source-bound slots. + projectNativeSeedInputs(controls, finalSource); + return controls; +} + +if (import.meta.main) { + const { values } = parseArgs({ + options: { + 'stage-release-archives': { type: 'boolean' }, + 'publication-inputs': { type: 'boolean' }, + 'seed-adoption-anchor': { type: 'boolean' }, + 'consumer-products-json': { type: 'string' }, + 'metadata-publisher-sha': { type: 'string' }, + 'metadata-bundles-json': { type: 'string' }, + 'run-id': { type: 'string' }, + ref: { type: 'string' }, + 'output-directory': { type: 'string' }, + }, + strict: true, + }); + if ( + [ + values['stage-release-archives'], + values['publication-inputs'], + values['seed-adoption-anchor'], + ].filter(Boolean).length !== 1 || + !values['output-directory'] || + (values['stage-release-archives'] && + (!values['run-id'] || !/^[1-9][0-9]*$/u.test(values['run-id']))) || + (values['seed-adoption-anchor'] && + (!values['run-id'] || !/^[1-9][0-9]*$/u.test(values['run-id']) || !values.ref)) || + (values['publication-inputs'] && + (values['run-id'] !== undefined || values.ref !== undefined)) || + Boolean(values['metadata-publisher-sha']) !== Boolean(values['metadata-bundles-json']) + ) + throw new Error( + 'usage: native-release-preparation.mts (--stage-release-archives --run-id ID [--ref REF] | --publication-inputs [--consumer-products-json FILE]) --output-directory DIR', + ); + try { + if (values['publication-inputs']) { + const result = await acquireNativePublicationInputs({ + source: sourceIdentity('HEAD'), + directory: values['output-directory'], + ...(values['consumer-products-json'] + ? { consumerProducts: JSON.parse(readFileSync(values['consumer-products-json'], 'utf8')) } + : { consumerProducts: Object.keys(loadProducts()) }), + ...(values['metadata-publisher-sha'] + ? { + metadataOrigin: { + publisherSha: values['metadata-publisher-sha'], + bundlePaths: JSON.parse(readFileSync(values['metadata-bundles-json']!, 'utf8')), + }, + } + : {}), + }); + console.log(result.file); + } else if (values['seed-adoption-anchor']) { + console.log( + await acquireNativeSeedConstructionAnchor({ + source: sourceIdentity('HEAD'), + runId: Number(values['run-id']), + ref: values.ref!, + directory: values['output-directory'], + }), + ); + } else { + assert.ok( + process.env.OLIPHAUNT_NATIVE_PUBLICATION_INPUTS, + 'native family construction requires the source-bound input snapshot', + ); + const result = await acquireNativeReleaseArchives({ + source: sourceIdentity('HEAD'), + publicationInputs: process.env.OLIPHAUNT_NATIVE_PUBLICATION_INPUTS, + ...(values['consumer-products-json'] + ? { consumerProducts: JSON.parse(readFileSync(values['consumer-products-json'], 'utf8')) } + : {}), + runId: Number(values['run-id']), + directory: values['output-directory'], + ref: values.ref, + }); + if (result.publicationInputs && process.env.GITHUB_ENV) + appendFileSync( + process.env.GITHUB_ENV, + `OLIPHAUNT_NATIVE_PUBLICATION_INPUTS=${result.publicationInputs}\n`, + ); + console.log(result.directory); + } + } catch (error) { + console.error(error instanceof Error ? error.message : error); + process.exitCode = 1; + } +} diff --git a/tools/release/native-release-preparation.test.mts b/tools/release/native-release-preparation.test.mts new file mode 100644 index 000000000..5fb42f7ea --- /dev/null +++ b/tools/release/native-release-preparation.test.mts @@ -0,0 +1,2317 @@ +import { expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { + chmodSync, + existsSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + rmSync, + statSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { mergeNativeFinalMembers } from '../../build_defs/extensions/owner_carriers.mts'; +import { sourceManifest } from '../../build_defs/languages/source-package.mts'; +import { seedCarrierIdentities } from '../../src/database-resources/seeds/carrier-identities.mts'; +import { composeExtensionReleaseDocuments } from '../../src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts'; +import { renderCargoToml } from '../packaging/cargo-manifest.mts'; +import { tarArchive } from '../packaging/testdata/tar-fixture.mts'; +import { + loadReleaseMetadata, + nativePublicationInputProjection, +} from './bazel-release-metadata.mts'; +import { requestGithubPages } from './github-read.mts'; +import { fileIdentity } from './native-file-identity.mts'; +import { nativePublicationMetadataArtifactRow } from './native-publication-metadata-contract.mts'; +import { + acquireCompletedNativeDeliveryBaseline, + acquireNativePublicationBuilds, + acquireNativePublicationInputs, + acquireNativeReleaseArchives, + assertNeverPublishedNativeProducts, + nativeCargoMinimumBindings, + nativeCargoPayloadBindings, + prepareNativeReleaseDelivery, + stageNativeReleaseFamilies, +} from './native-release-preparation.mts'; +import { loadPublicationCatalog } from './publication-catalog.mts'; +import { discoverProductArtifacts, expectedProductArtifactRows } from './publication-lock.mts'; +import { + allArtifactTargets, + contribCarrierDescriptor, + extensionMetadata, + extensionSourceIdentity, +} from './release-artifact-targets.mts'; +import { loadProducts, ROOT } from './release-graph.mts'; +import { fixtureCompletedNativeInventory } from './testdata/prepare-release-candidate-fixtures.mts'; +import { + extensionGithubReleaseFixture, + githubReleaseFixture, +} from './testdata/publication-artifact-fixtures.mts'; + +const source = { commit: 'a'.repeat(40), tree: 'b'.repeat(40) }; + +const sourceText = (file: string) => readFileSync(path.join(ROOT, file), 'utf8'); + +test('source payload requests preserve held pins and request an explicitly newer published native pin', () => { + const catalog = loadPublicationCatalog('payload request fixture'); + const held = nativeCargoPayloadBindings(catalog, ['oliphaunt-rust'], sourceText); + const nativeVersion = Bun.TOML.parse(sourceText('src/native/sdks/rust/Cargo.toml')).package + .metadata.oliphaunt['native-version']; + expect(held).toHaveLength(8); + expect( + held.filter((row) => row.producer === 'liboliphaunt-native').map((row) => row.producerVersion), + ).toEqual(Array(4).fill(nativeVersion)); + expect( + held.some( + (row) => + row.requestedCarrier.includes('extension-') || + row.requestedCarrier === 'cargo:oliphaunt-broker', + ), + ).toBe(false); + const next = '0.3.3'; + const newerCheckout = structuredClone(catalog); + for (const carrier of newerCheckout.carriers) + if (carrier.product === 'liboliphaunt-native') carrier.version = '9.2.1'; + const directory = mkdtempSync(path.join(tmpdir(), 'published-payload-pin-')); + try { + const original = sourceText('src/native/sdks/rust/Cargo.toml'); + const file = path.join(directory, 'Cargo.toml'); + writeFileSync( + file, + original.replace(`native-version = "${nativeVersion}"`, `native-version = "${next}"`), + ); + const changed = nativeCargoPayloadBindings(newerCheckout, ['oliphaunt-rust'], (name) => + name === 'src/native/sdks/rust/Cargo.toml' ? readFileSync(file, 'utf8') : sourceText(name), + ); + expect( + changed + .filter((row) => row.producer === 'liboliphaunt-native') + .map((row) => row.producerVersion), + ).toEqual(Array(4).fill(next)); + expect(changed.filter((row) => row.producer === 'oliphaunt-broker')).toEqual( + held.filter((row) => row.producer === 'oliphaunt-broker'), + ); + expect(sourceText('src/native/sdks/rust/Cargo.toml')).toBe(original); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('WASIX source payload requests include optional and foreign carriers without registry acquisition for the local server SDK', () => { + const catalog = loadPublicationCatalog('WASIX payload request fixture'); + const requests = nativeCargoPayloadBindings(catalog, ['oliphaunt-wasix-rust'], sourceText); + expect(requests.filter((row) => row.producer === 'liboliphaunt-wasix')).toHaveLength(5); + expect(requests.filter((row) => row.producer === 'postgres-tools-wasix')).toHaveLength(5); + expect(requests.filter((row) => row.producer === 'database-resources')).toHaveLength(1); + expect(nativeCargoPayloadBindings(catalog, ['oliphaunt-pgwire-server'], sourceText)).toEqual([]); + expect( + nativeCargoPayloadBindings( + catalog, + ['oliphaunt-pgwire-server', 'oliphaunt-wasix-rust'], + sourceText, + ), + ).toEqual(requests); + const original = sourceText('src/wasix/sdks/rust/Cargo.toml'); + expect(() => + nativeCargoPayloadBindings(catalog, ['oliphaunt-wasix-rust'], (name) => + name === 'src/wasix/sdks/rust/Cargo.toml' + ? original.replace( + 'liboliphaunt-wasix-portable = { version = "*", path = "../../runtime/crates/assets" }', + 'liboliphaunt-wasix-portable = { version = "0.3.2" }', + ) + : sourceText(name), + ), + ).toThrow('exact authored version'); + const initial = structuredClone(catalog); + for (const product of initial.products) + if (product.id === 'liboliphaunt-native') product.version = '0.0.0'; + for (const carrier of initial.carriers) + if (carrier.product === 'liboliphaunt-native') carrier.version = '0.0.0'; + const initialSource = sourceText('src/native/sdks/rust/Cargo.toml').replace( + /native-version = "[^"]+"/u, + 'native-version = "0.0.0"', + ); + expect( + nativeCargoPayloadBindings(initial, ['oliphaunt-rust'], (name) => + name === 'src/native/sdks/rust/Cargo.toml' ? initialSource : sourceText(name), + ).some((row) => row.producer === 'liboliphaunt-native'), + ).toBe(false); +}); + +function payloadAcquisitionTransport({ failure = '', heldRuntime = '' } = {}) { + const catalog = loadPublicationCatalog('retained payload fixture'); + const metadata = loadReleaseMetadata(ROOT); + const requests: string[] = []; + const transport = { + inventory: async (publication) => { + const original = await fixtureCompletedNativeInventory(publication); + return { + ...original, + carriers: original.carriers.map((carrier) => ({ + ...carrier, + version: publication.version, + })), + }; + }, + readPages: async () => [], + readJson: async (endpoint) => ({ + id: 7, + target_commitish: 'c'.repeat(40), + tag_name: decodeURIComponent(endpoint.split('/').at(-1) ?? ''), + }), + assertCompleted: async (request) => ({ + ...request, + publicationTree: 'd'.repeat(40), + releaseSha: request.publicationSha, + }), + materialize: async (carrier, options) => { + expect(carrier.ecosystem).toBe('cargo'); + const key = `${carrier.id}@${carrier.version}`; + requests.push(key); + if (failure === 'missing' && carrier.name.endsWith('-part-001')) + throw new Error('missing actual part'); + mkdirSync(options.directory, { recursive: true }); + const file = path.join(options.directory, carrier.artifacts[0].path); + let manifest: any = { package: { name: carrier.name, version: carrier.version } }; + if (carrier.name === 'liboliphaunt-wasix-portable') { + const context = JSON.parse( + sourceText('build_defs/languages/installed/wasix/sdk/registry-index.json'), + ); + const original = context.indexes + .flatMap((index) => index.records) + .find((row) => row.name === carrier.name); + manifest.dependencies = Object.fromEntries( + original.deps + .filter((dependency) => + catalog.carriers.some( + (row) => row.id === `cargo:${dependency.name}` && row.product === carrier.product, + ), + ) + .map((dependency) => [dependency.name, `=${carrier.version}`]), + ); + } + if (carrier.product === 'liboliphaunt-native' && carrier.declared) + manifest['build-dependencies'] = Object.fromEntries( + [1, 2].map((part) => [ + `${carrier.name}-part-${String(part).padStart(3, '0')}`, + `=${failure === 'requirement' ? '0.0.9' : carrier.version}`, + ]), + ); + if (carrier.name === 'oliphaunt-wasix') { + const owner = metadata.products['oliphaunt-wasix-rust']; + const original = sourceText(`${owner.path}/Cargo.toml`); + const heldSource = heldRuntime + ? original.replace(/runtime-version = "[^"]+"/u, `runtime-version = "${heldRuntime}"`) + : original; + manifest = sourceManifest(heldSource, sourceText('Cargo.toml'), { + product: owner.id, + version: owner.version, + compatibility: { + ...owner.compatibility_versions, + ...(heldRuntime ? { 'liboliphaunt-wasix': heldRuntime } : {}), + }, + dependencyOwners: Object.fromEntries( + catalog.carriers + .filter((row) => row.ecosystem === 'cargo') + .map((row) => [row.name, row.product]), + ), + }); + manifest.package.version = carrier.version; + } + if (failure === 'version' && carrier.name.endsWith('-part-001')) + manifest.package.version = '0.0.9'; + writeFileSync( + file, + tarArchive([ + { + name: `${carrier.name}-${carrier.version}/Cargo.toml`, + data: renderCargoToml(manifest), + }, + ]), + ); + const { size, sha256 } = fileIdentity(file); + return { + carrier: { ...carrier, artifacts: [{ path: file, size, sha256 }] }, + receipt: {}, + metadata: {}, + }; + }, + }; + return { requests, transport }; +} + +test('source payload acquisition retains actual native parts once through the existing snapshot', async () => { + const directory = mkdtempSync(path.join(tmpdir(), 'actual-native-payload-inputs-')); + try { + const fixture = payloadAcquisitionTransport(); + const acquired = await acquireNativePublicationInputs( + { source, directory: path.join(directory, 'owned'), consumerProducts: ['oliphaunt-rust'] }, + fixture.transport, + ); + const rows = acquired.snapshot.supplierArtifacts ?? []; + expect(rows.filter((row) => row.publication.product === 'liboliphaunt-native')).toHaveLength( + 12, + ); + expect(rows.filter((row) => row.artifact.startsWith('cargo:oliphaunt-broker-'))).toHaveLength( + 4, + ); + expect(rows.every((row) => row.artifact.startsWith('cargo:'))).toBe(true); + expect(new Set(fixture.requests).size).toBe(fixture.requests.length); + for (const row of rows) expect(fileIdentity(row.file.path).sha256).toBe(row.file.sha256); + expect(acquired.snapshot.seedControls).toEqual([]); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('completed payload acquisition rejects missing, wrong-version and wrong-requirement parts', async () => { + const directory = mkdtempSync(path.join(tmpdir(), 'bad-native-payload-inputs-')); + try { + for (const failure of ['missing', 'version', 'requirement', 'frozen-missing']) { + const fixture = payloadAcquisitionTransport({ failure }); + const nativeVersion = Bun.TOML.parse(sourceText('src/native/sdks/rust/Cargo.toml')).package + .metadata.oliphaunt['native-version']; + const metadata = nativePublicationMetadataArtifactRow({ + id: 'liboliphaunt-native', + version: nativeVersion, + }); + const transport = + failure !== 'frozen-missing' + ? fixture.transport + : { + ...fixture.transport, + readPages: async () => [ + { + id: 1, + name: metadata.name, + state: 'uploaded', + size: 2, + url: 'https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/1', + }, + ], + readBaseline: async () => ({ controlledFrozenInventory: true }) as any, + proveAsset: async (_url, _name, _size, options) => { + mkdirSync(path.dirname(options.retainedPath), { recursive: true }); + writeFileSync(options.retainedPath, '{}'); + const actual = fileIdentity(options.retainedPath); + return { bytes: actual.size, sha256: actual.sha256 }; + }, + }; + await expect( + acquireNativePublicationInputs( + { + source, + directory: path.join(directory, failure), + consumerProducts: ['oliphaunt-rust'], + }, + transport, + ), + ).rejects.toThrow( + failure === 'missing' + ? 'missing actual part' + : failure === 'version' + ? 'requested identity' + : failure === 'requirement' + ? 'differs from its parent' + : 'absent from frozen inventory', + ); + expect(existsSync(path.join(directory, failure))).toBe(false); + } + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('SDK source payloads deduplicate shared requests while a local server SDK needs no held runtime', async () => { + const directory = mkdtempSync(path.join(tmpdir(), 'held-wasix-payload-inputs-')); + try { + const fixture = payloadAcquisitionTransport(); + const acquired = await acquireNativePublicationInputs( + { + source, + directory: path.join(directory, 'shared'), + consumerProducts: ['oliphaunt-pgwire-server', 'oliphaunt-wasix-rust'], + }, + fixture.transport, + ); + expect(new Set(fixture.requests).size).toBe(fixture.requests.length); + const runtimeRows = + acquired.snapshot.supplierArtifacts?.filter( + (row) => row.publication.product === 'liboliphaunt-wasix', + ) ?? []; + expect( + runtimeRows.filter((row) => row.artifact.startsWith('cargo:liboliphaunt-wasix-')), + ).toHaveLength(5); + expect( + runtimeRows.filter((row) => row.artifact.startsWith('cargo:oliphaunt-extension-contrib-')), + ).toHaveLength(5); + const held = payloadAcquisitionTransport({ heldRuntime: '0.3.1' }); + const heldOnly = await acquireNativePublicationInputs( + { + source, + directory: path.join(directory, 'held'), + consumerProducts: ['oliphaunt-pgwire-server'], + }, + held.transport, + ); + expect( + heldOnly.snapshot.supplierArtifacts + ?.filter((row) => row.artifact.startsWith('cargo:liboliphaunt-wasix-')) + .map((row) => row.publication.version), + ).toEqual([]); + expect(held.requests.map((request) => request.split('@')[0])).toEqual([ + 'cargo:oliphaunt-query', + ]); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('compiled external WASIX hosts retain their exact portable crate without an SDK request', async () => { + const directory = mkdtempSync(path.join(tmpdir(), 'external-wasix-host-inputs-')); + const metadata = loadReleaseMetadata(ROOT); + const products = loadProducts(); + const consumer = 'oliphaunt-extension-pg-textsearch'; + const floor = metadata.products[consumer].compatibility_versions['liboliphaunt-wasix']; + expect(typeof metadata.wasixExtensions.pg_textsearch['native-module-file']).toBe('string'); + try { + for (const consumers of [ + [consumer], + [consumer, 'oliphaunt-extension-pg-ivm', 'oliphaunt-wasix-rust'], + ]) { + const fixture = payloadAcquisitionTransport(); + const nativeFloors = new Set( + consumers + .filter((id) => products[id].extension?.class === 'external') + .map((id) => metadata.products[id].compatibility_versions['liboliphaunt-native']), + ); + const nativeRows = [...nativeFloors].flatMap((version) => + expectedProductArtifactRows([{ ...products['liboliphaunt-native'], version }]).filter( + (row) => + row.kind === 'apple-swiftpm-binary' || + (row.kind === 'runtime-resources' && row.target === 'ios-datum64'), + ), + ); + const publicFiles = new Map( + nativeRows.map((row, index) => [ + row.name, + { + id: index + 100, + row, + bytes: Buffer.from(`controlled held native archive ${row.name}`), + }, + ]), + ); + const acquired = await acquireNativePublicationInputs( + { + source, + directory: path.join(directory, String(consumers.length)), + consumerProducts: consumers, + }, + { + ...fixture.transport, + readPages: async () => + [...publicFiles.values()].map(({ id, row, bytes }) => ({ + id, + name: row.name, + state: 'uploaded', + size: bytes.length, + digest: `sha256:${createHash('sha256').update(bytes).digest('hex')}`, + url: `https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/${id}`, + })), + proveAsset: async (url, name, size, options) => { + const retained = publicFiles.get(name)!; + expect(retained).toBeDefined(); + expect(url).toBe( + `https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/${retained.id}`, + ); + expect(size).toBe(retained.bytes.length); + mkdirSync(path.dirname(options.retainedPath), { recursive: true }); + writeFileSync(options.retainedPath, retained.bytes); + const identity = fileIdentity(options.retainedPath); + expect(identity.sha256).toBe(options.expectedSha256); + return { bytes: identity.size, sha256: identity.sha256 }; + }, + }, + ); + const artifact = 'cargo:liboliphaunt-wasix-portable'; + expect(fixture.requests.filter((request) => request === `${artifact}@${floor}`)).toHaveLength( + 1, + ); + expect(new Set(fixture.requests).size).toBe(fixture.requests.length); + expect(fixture.requests.some((request) => request.startsWith('cargo:oliphaunt-wasix@'))).toBe( + false, + ); + const rows = (acquired.snapshot.supplierArtifacts ?? []).filter( + (row) => row.artifact === artifact, + ); + expect(rows).toHaveLength(1); + const row = rows[0]; + expect(row.publication.product).toBe('liboliphaunt-wasix'); + expect(row.publication.version).toBe(floor); + expect(fileIdentity(row.file.path).sha256).toBe(row.file.sha256); + expect( + (acquired.snapshot.supplierArtifacts ?? []) + .filter((row) => row.publication.product === 'liboliphaunt-native') + .map((row) => row.artifact) + .sort(), + ).toEqual(nativeRows.map((row) => row.id).sort()); + const key = `liboliphaunt-wasix/${floor}/${artifact}`; + const projected = nativePublicationInputProjection(acquired.snapshot).supplierArtifacts[key]; + expect(projected.publication).toEqual(row.publication); + expect(projected.file).toEqual({ + ...row.file, + path: `@oliphaunt_metadata//:supplier-artifacts/liboliphaunt-wasix/${floor}/${row.file.sha256}/${path.basename(row.file.path)}`, + }); + } + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('first publication requires initial source versions and proves public absence once for all new owners', async () => { + const calls = []; + const readPages = async (endpoint) => { + calls.push(endpoint); + return []; + }; + await assertNeverPublishedNativeProducts([], { readPages }); + expect(calls).toEqual([]); + await assertNeverPublishedNativeProducts( + [ + { id: 'new-alpha', version: '0.0.0' }, + { id: 'new-beta', version: '0.0.0' }, + ], + { readPages }, + ); + expect(calls).toEqual(['repos/f0rr0/oliphaunt/tags', 'repos/f0rr0/oliphaunt/releases']); + for (const historical of ['tag', 'release']) + await expect( + assertNeverPublishedNativeProducts([{ id: 'new-alpha', version: '0.0.0' }], { + readPages: async (endpoint) => + endpoint.endsWith(historical === 'tag' ? '/tags' : '/releases') + ? [ + historical === 'tag' + ? { name: 'new-alpha-v0.1.0' } + : { tag_name: 'new-alpha-v0.1.0' }, + ] + : [], + }), + ).rejects.toThrow('already has published version history'); + await expect( + assertNeverPublishedNativeProducts([{ id: 'new-alpha', version: '0.1.0' }], { readPages }), + ).rejects.toThrow('initial products'); + await expect( + assertNeverPublishedNativeProducts([{ id: 'new-alpha', version: '0.0.0' }], { + readPages: async () => { + throw new Error('history unavailable'); + }, + }), + ).rejects.toThrow('history unavailable'); +}); + +test('historical acquisition retains retired identities and follows the old parent archive part set once', async () => { + const directory = mkdtempSync(path.join(tmpdir(), 'native-historical-acquisition-')); + const publication = { + product: 'liboliphaunt-native', + version: '1.0.0', + tagName: 'liboliphaunt-native-v1.0.0', + publicationSha: 'c'.repeat(40), + publicationTree: 'd'.repeat(40), + releaseSha: 'c'.repeat(40), + }; + const parent = { + id: 'cargo:oliphaunt-linux-x64-gnu', + product: publication.product, + ecosystem: 'cargo', + name: 'oliphaunt-linux-x64-gnu', + version: publication.version, + role: 'platform-leaf', + target: 'linux-x64-gnu', + declared: true, + }; + const npm = { + id: 'npm:@oliphaunt/retired-native', + product: publication.product, + ecosystem: 'npm', + name: '@oliphaunt/retired-native', + version: publication.version, + role: 'platform-leaf', + target: 'linux-x64-gnu', + declared: true, + }; + const requested = []; + const assets = [ + { + name: 'retired-native-1.0.0.tar.gz', + url: 'https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/1', + size: 3, + }, + ]; + const transport = { + inventory: async () => ({ + publication, + catalog: { products: [], carriers: [parent, npm] }, + publicRows: [{ id: 'github-release:retired-native-1.0.0.tar.gz', name: assets[0].name }], + }), + readJson: async () => ({ id: 1 }), + readPages: async () => assets, + materialize: async (carrier, options) => { + requested.push(carrier.id); + mkdirSync(options.directory, { recursive: true }); + const file = path.join(options.directory, carrier.artifacts[0].path); + writeFileSync( + file, + tarArchive( + carrier.ecosystem === 'npm' + ? [ + { + name: 'package/package.json', + data: JSON.stringify({ + name: carrier.name, + version: publication.version, + repository: { type: 'git', url: 'git+https://github.com/f0rr0/oliphaunt.git' }, + }), + }, + ] + : [ + { + name: `${carrier.name}-${publication.version}/Cargo.toml`, + data: `[package]\nname = "${carrier.name}"\nversion = "${publication.version}"\n${carrier.id === parent.id ? `[dependencies]\n${parent.name}-part-001 = "=${publication.version}"\n` : ''}`, + }, + ], + ), + ); + const identity = fileIdentity(file); + if (carrier.artifacts[0].sha256) { + expect(carrier.artifacts[0].sha256).toBe(identity.sha256); + expect(carrier.artifacts[0].size).toBe(identity.size); + } + return { + carrier: { + ...carrier, + artifacts: [{ path: file, size: identity.size, sha256: identity.sha256 }], + }, + receipt: {}, + metadata: {}, + }; + }, + proveAsset: async (_url, _name, _size, options) => { + requested.push('old-public-target'); + mkdirSync(path.dirname(options.retainedPath), { recursive: true }); + writeFileSync(options.retainedPath, 'old'); + const identity = fileIdentity(options.retainedPath); + return { bytes: identity.size, sha256: identity.sha256 }; + }, + }; + try { + const result = await acquireCompletedNativeDeliveryBaseline( + { publication, directory }, + transport, + ); + expect(requested).toEqual([ + parent.id, + npm.id, + `cargo:${parent.name}-part-001`, + 'old-public-target', + ]); + expect(Object.keys(result.baseline.carriers).sort()).toEqual( + [parent.id, npm.id, `cargo:${parent.name}-part-001`].sort(), + ); + expect(Object.keys(result.baseline.productArtifacts)).toEqual([ + 'github-release:retired-native-1.0.0.tar.gz', + ]); + const metadataBaseline = { originalAuthenticatedObject: true } as any; + requested.length = 0; + const frozen = await acquireCompletedNativeDeliveryBaseline( + { publication, directory: path.join(directory, 'frozen'), metadataBaseline }, + { + ...transport, + inventory: async (_publication, options) => { + expect(options.metadataBaseline).toBe(metadataBaseline); + return { + publication, + catalog: result.historical.catalog, + carriers: result.retained.map(({ carrier }) => carrier), + publicRows: [ + { + id: 'github-release:retired-native-1.0.0.tar.gz', + name: assets[0].name, + size: 3, + sha256: createHash('sha256').update('old').digest('hex'), + }, + ], + }; + }, + }, + ); + expect(frozen.baseline.metadataBaseline).toBe(metadataBaseline); + expect(requested).toEqual([ + parent.id, + npm.id, + `cargo:${parent.name}-part-001`, + 'old-public-target', + ]); + await expect( + acquireCompletedNativeDeliveryBaseline( + { publication, directory: path.join(directory, 'missing-frozen-part'), metadataBaseline }, + { + ...transport, + inventory: async () => ({ + publication, + catalog: result.historical.catalog, + carriers: result.retained + .map(({ carrier }) => carrier) + .filter((carrier) => carrier.id !== `cargo:${parent.name}-part-001`), + publicRows: [], + }), + }, + ), + ).rejects.toThrow('completed Cargo part is absent from frozen inventory'); + await expect( + acquireCompletedNativeDeliveryBaseline( + { publication, directory: path.join(directory, 'missing') }, + { ...transport, readPages: async () => [] }, + ), + ).rejects.toThrow('missing or ambiguous'); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('WASIX source SDK and historical facade retain their own exact runtime and host packages once', async () => { + const directory = mkdtempSync(path.join(tmpdir(), 'native-facade-supplier-')); + const hosts = allArtifactTargets({ + product: 'oliphaunt-wasix-napi', + surface: 'npm-optional', + }).filter((row) => row.npm_os === process.platform && row.npm_cpu === process.arch); + expect(hosts).toHaveLength(1); + const sourceSdk = JSON.parse(sourceText('src/wasix/sdks/ts/package.json')); + const sourceHostVersion = sourceSdk.oliphaunt.wasixNapiVersion; + const coreName = loadProducts()['liboliphaunt-wasix'].registry_packages.find((name) => + name.startsWith('npm:'), + )!; + let historicalHost = '@oliphaunt/retired-host-native'; + let historicalHostVersion = '0.1.9'; + let missingSourceHost = false; + expect(sourceHostVersion).not.toBe(historicalHostVersion); + const facade = loadPublicationCatalog('published facade fixture').products.find( + (product) => product.id === 'oliphaunt-wasix-ts', + )!; + const acquisitions: string[] = []; + const transport = { + inventory: async (publication) => { + const value = await fixtureCompletedNativeInventory(publication); + if (publication.product === 'liboliphaunt-wasix') + expect(value.carriers.filter((row) => row.ecosystem === 'npm')).toHaveLength(2); + if (publication.product !== 'oliphaunt-wasix-napi') return value; + const host = value.carriers.find((row) => row.name === hosts[0].npm_package)!; + if (missingSourceHost && publication.version === sourceHostVersion) + return { ...value, carriers: value.carriers.filter((row) => row.name !== host.name) }; + if (publication.version !== historicalHostVersion) return value; + return { + ...value, + inputContext: undefined, + carriers: [ + { + ...host, + id: `npm:${historicalHost}`, + name: historicalHost, + role: 'previous-host-role', + }, + ], + }; + }, + readPages: async () => [], + readJson: async (endpoint: string) => ({ + id: 1, + target_commitish: 'c'.repeat(40), + tag_name: decodeURIComponent(endpoint.split('/').at(-1)!), + }), + assertCompleted: async (request: any) => ({ + ...request, + publicationTree: 'd'.repeat(40), + releaseSha: request.publicationSha, + }), + materialize: async (carrier: any, options: any) => { + acquisitions.push(`${carrier.id}@${carrier.version}`); + mkdirSync(options.directory, { recursive: true }); + const file = path.join(options.directory, carrier.artifacts[0].path); + writeFileSync( + file, + tarArchive([ + { + name: 'package/package.json', + data: JSON.stringify( + carrier.product === facade.id + ? { + name: carrier.name, + version: carrier.version, + oliphaunt: { runtimeVersion: '0.3.2' }, + optionalDependencies: { [historicalHost]: historicalHostVersion }, + } + : { name: carrier.name, version: carrier.version }, + ), + }, + ]), + ); + const { size, sha256 } = fileIdentity(file); + return { + carrier: { ...carrier, artifacts: [{ path: file, size, sha256 }] }, + receipt: {}, + metadata: {}, + }; + }, + }; + try { + const result = await acquireNativePublicationInputs( + { source, directory: path.join(directory, 'owned'), consumerProducts: [facade.id] }, + transport, + ); + expect(acquisitions.toSorted()).toEqual( + [ + 'npm:@oliphaunt/ts-query@0.1.1', + `${coreName}@${sourceSdk.oliphaunt.runtimeVersion}`, + `npm:${hosts[0].npm_package}@${sourceHostVersion}`, + `npm:@oliphaunt/wasix-ts@${facade.version}`, + `npm:${historicalHost}@${historicalHostVersion}`, + ].sort(), + ); + expect(result.snapshot.seedControls).toEqual([]); + expect( + result.snapshot.supplierArtifacts + ?.map((row) => [row.artifact, row.publication.version]) + .sort(), + ).toEqual( + [ + ['npm:@oliphaunt/ts-query', '0.1.1'], + [coreName, sourceSdk.oliphaunt.runtimeVersion], + [`npm:${hosts[0].npm_package}`, sourceHostVersion], + ['npm:@oliphaunt/wasix-ts', facade.version], + [`npm:${historicalHost}`, historicalHostVersion], + ].sort(), + ); + expect( + result.snapshot.supplierArtifacts?.every( + (row) => fileIdentity(row.file.path).sha256 === row.file.sha256, + ), + ).toBe(true); + expect(new Set(acquisitions).size).toBe(acquisitions.length); + expect(result.snapshot).not.toHaveProperty('ready'); + acquisitions.length = 0; + historicalHost = hosts[0].npm_package; + historicalHostVersion = sourceHostVersion; + const shared = await acquireNativePublicationInputs( + { source, directory: path.join(directory, 'shared'), consumerProducts: [facade.id] }, + transport, + ); + expect(acquisitions).toHaveLength(4); + expect(new Set(acquisitions).size).toBe(acquisitions.length); + expect( + shared.snapshot.supplierArtifacts?.filter((row) => row.artifact === `npm:${historicalHost}`), + ).toHaveLength(1); + missingSourceHost = true; + await expect( + acquireNativePublicationInputs( + { + source, + directory: path.join(directory, 'missing-source-host'), + consumerProducts: [facade.id], + }, + transport, + ), + ).rejects.toThrow('requested supplier is absent from its completed inventory'); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); +const eligible = { + id: 77, + head_sha: source.commit, + head_branch: 'main', + path: '.github/workflows/bazel.yml', + name: 'Native Bazel qualification', + event: 'push', + status: 'completed', + conclusion: 'success', + run_attempt: 1, +}; + +test('source Cargo requirements retain each canonical completed crate once through the shared snapshot', async () => { + const directory = mkdtempSync(path.join(tmpdir(), 'native-source-cargo-inputs-')); + const retained: string[] = []; + try { + const result = await acquireNativePublicationInputs( + { + source, + directory: path.join(directory, 'owned'), + consumerProducts: ['oliphaunt-pgwire-server'], + }, + { + inventory: fixtureCompletedNativeInventory, + readPages: async () => [], + readJson: async (endpoint) => ({ + id: 7, + target_commitish: 'c'.repeat(40), + tag_name: decodeURIComponent(endpoint.split('/').at(-1)!), + }), + assertCompleted: async (request) => ({ + ...request, + publicationTree: 'd'.repeat(40), + releaseSha: request.publicationSha, + }), + materialize: async (carrier, options) => { + expect(carrier.ecosystem).toBe('cargo'); + expect(carrier.artifacts[0].path).toBe(`${carrier.name}-${carrier.version}.crate`); + mkdirSync(options.directory, { recursive: true }); + const file = path.join(options.directory, carrier.artifacts[0].path); + writeFileSync( + file, + tarArchive([ + { + name: `${carrier.name}-${carrier.version}/Cargo.toml`, + data: `[package]\nname = "${carrier.name}"\nversion = "${carrier.version}"\n`, + }, + ]), + ); + const { size, sha256 } = fileIdentity(file); + retained.push(carrier.id); + return { + carrier: { ...carrier, artifacts: [{ path: file, size, sha256 }] }, + receipt: {}, + metadata: {}, + }; + }, + }, + ); + expect(retained.sort()).toEqual(['cargo:oliphaunt-query']); + expect(new Set(retained).size).toBe(retained.length); + expect(result.snapshot.seedControls).toEqual([]); + expect(result.snapshot.supplierArtifacts?.map((row) => row.artifact).sort()).toEqual(retained); + expect( + result.snapshot.supplierArtifacts?.every( + (row) => fileIdentity(row.file.path).sha256 === row.file.sha256, + ), + ).toBe(true); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +for (const fault of [ + 'source', + 'branch', + 'workflow', + 'event', + 'pending', + 'failed', + 'attempt', + 'ID', +] as const) + test(`actual preparation rejects ${fault} before artifacts or package acquisition`, async () => { + const root = mkdtempSync(path.join(tmpdir(), 'native-release-preparation-')); + try { + const run = { ...eligible }; + if (fault === 'source') run.head_sha = 'f'.repeat(40); + if (fault === 'branch') run.head_branch = 'feature'; + if (fault === 'workflow') run.path = '.github/workflows/main.yml'; + if (fault === 'event') run.event = 'pull_request'; + if (fault === 'pending') run.status = 'in_progress'; + if (fault === 'failed') run.conclusion = 'failure'; + if (fault === 'attempt') run.run_attempt = 0; + if (fault === 'ID') run.id = 78; + let reads = 0; + await expect( + prepareNativeReleaseDelivery( + { source, runId: 77, completedVersions: {}, directory: path.join(root, 'owned') }, + { + readJson: async () => { + reads++; + return run; + }, + readPages: async () => { + throw new Error('artifact acquisition must not run'); + }, + acquire: async () => { + throw new Error('producer acquisition must not run'); + }, + materialize: async () => { + throw new Error('registry acquisition must not run'); + }, + }, + ), + ).rejects.toThrow(/successful exact reviewed-main qualification/); + expect(reads).toBe(1); + expect(existsSync(path.join(root, 'owned'))).toBe(false); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }); + +for (const artifacts of [ + [], + [{ name: 'arbitrary-unreviewed-evidence', expired: false }], + [{ name: 'native-build-evidence-x86_64', expired: true }], +]) + test('an eligible run without retained canonical producer roles cannot invent a native release set', async () => { + const root = mkdtempSync(path.join(tmpdir(), 'native-release-preparation-')); + try { + await expect( + prepareNativeReleaseDelivery( + { source, runId: 77, completedVersions: {}, directory: path.join(root, 'owned') }, + { + readJson: async () => eligible, + readPages: (endpoint, options) => + requestGithubPages(endpoint, { + ...options, + environment: {}, + fetchImpl: async (url) => { + expect(url).toBe( + 'https://api.github.com/repos/f0rr0/oliphaunt/actions/runs/77/artifacts?per_page=100&page=1', + ); + return Response.json({ total_count: artifacts.length, artifacts }); + }, + }), + acquire: async () => { + throw new Error('no producer may be acquired'); + }, + }, + ), + ).rejects.toThrow(/no retained reviewed producer artifacts/); + expect(existsSync(path.join(root, 'owned'))).toBe(false); + } finally { + rmSync(root, { recursive: true, force: true }); + } + }); + +function producer( + directory: string, + row: ReturnType[number], + content: string | Uint8Array, + mode?: number, +) { + const output = `bazel-out/k8-opt/bin/${row.product}/${row.name}`; + const file = path.join(directory, 'files/0', output); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, content); + if (mode !== undefined) chmodSync(file, mode); + const identity = fileIdentity(file); + return { + file, + origin: { + github: { + repository: 'f0rr0/oliphaunt', + workflow: 'Native Bazel qualification', + workflowPath: '.github/workflows/bazel.yml', + runId: 77, + runAttempt: 1, + job: 'Linux runtime (x86_64)', + }, + evidence: { + source, + cohorts: [ + { + executionRoot: '/fixture/execroot', + roots: [ + { + label: `//${row.product}:shipping`, + package: { + product: row.product, + version: row.version, + ecosystem: 'github', + name: row.name, + role: row.role, + outputs: [{ path: output }], + }, + }, + ], + outputs: [ + { + path: output, + members: [ + { + path: '', + type: 'file', + size: identity.size, + sha256: identity.sha256, + mode: identity.mode, + }, + ], + }, + ], + }, + ], + }, + finalFiles: { + files: [{ cohort: 0, path: output, size: identity.size, sha256: identity.sha256 }], + file(cohort: number, declaredPath: string) { + expect(cohort).toBe(0); + expect(declaredPath).toBe(output); + expect(fileIdentity(file)).toEqual(identity); + return file; + }, + assertUnchanged() { + expect(fileIdentity(file)).toEqual(identity); + }, + }, + } as any, + }; +} + +test('family staging joins unique original host assets with a separate checksum File and preserves producer roots', () => { + const directory = mkdtempSync(path.join(tmpdir(), 'native-family-test-')); + const finalDirectory = path.join( + ROOT, + 'target', + `native-family-test-${path.basename(directory)}`, + ); + try { + const rows = expectedProductArtifactRows( + loadPublicationCatalog('family staging test').products, + ); + const asset = rows.find( + (row) => row.product === 'liboliphaunt-native' && row.role === 'github-release-asset', + )!; + const checksum = rows.find( + (row) => + row.product === asset.product && + row.role === 'github-release-asset' && + row.kind === 'checksums', + )!; + const origins = new Map(); + for (const [index, row] of [asset, checksum].entries()) { + const evidenceRoot = path.join(directory, `producer-${index}`); + origins.set(evidenceRoot, producer(evidenceRoot, row, `qualified ${row.name}`).origin); + } + const original = structuredClone([...origins.values()].map((origin) => origin.evidence)); + const final = stageNativeReleaseFamilies(origins, source, finalDirectory); + expect(final).toEqual([path.join(finalDirectory, asset.product, 'release-assets')]); + for (const row of [asset, checksum]) + expect(readFileSync(path.join(final[0], row.name), 'utf8')).toBe(`qualified ${row.name}`); + expect([...origins.values()].map((origin) => origin.evidence)).toEqual(original); + const selectedDirectory = `${finalDirectory}-selected`; + try { + expect( + stageNativeReleaseFamilies(origins, source, selectedDirectory, [asset.product]), + ).toEqual([path.join(selectedDirectory, asset.product, 'release-assets')]); + expect( + readFileSync(path.join(selectedDirectory, asset.product, 'release-assets', asset.name)), + ).toEqual(readFileSync(path.join(final[0], asset.name))); + } finally { + rmSync(selectedDirectory, { recursive: true, force: true }); + } + expect(() => + stageNativeReleaseFamilies(origins, source, `${finalDirectory}-unknown`, ['unknown']), + ).toThrow(/canonical product/); + expect(() => + stageNativeReleaseFamilies(origins, source, `${finalDirectory}-duplicate`, [ + asset.product, + asset.product, + ]), + ).toThrow(/unique canonical/); + expect(() => stageNativeReleaseFamilies(origins, source, finalDirectory)).toThrow( + 'new owned directory', + ); + expect(() => + stageNativeReleaseFamilies(origins, source, path.join(directory, 'outside-target')), + ).toThrow('must remain under target/'); + } finally { + rmSync(directory, { recursive: true, force: true }); + rmSync(finalDirectory, { recursive: true, force: true }); + } +}); + +test('family staging preserves complete runtime, contrib and external publication layouts', { + timeout: 30_000, +}, () => { + const directory = mkdtempSync(path.join(tmpdir(), 'native-publication-families-')); + const destination = path.join(ROOT, 'target', path.basename(directory)); + const fixtureRoot = path.join(directory, 'original-layouts'); + const catalog = loadPublicationCatalog('family publication reader test', { + products: ['liboliphaunt-native', 'liboliphaunt-wasix', 'oliphaunt-extension-vector'], + }); + const expected = expectedProductArtifactRows(catalog.products); + const contrib = contribCarrierDescriptor('family publication reader test'); + const origins = new Map(); + const familyInputs: { owner: string; key: string }[] = []; + const fixedNames = new Map(); + const publicFiles = new Map(); + let sequence = 0; + const retain = (row, file: string) => { + const key = path.join(directory, 'packets', String(sequence++)); + const retained = producer(key, row, readFileSync(file), statSync(file).mode & 0o777); + origins.set(key, retained.origin); + return { key, ...retained }; + }; + const retainPublic = (owner: string, assetDirectory: string) => { + for (const entry of readdirSync(assetDirectory, { withFileTypes: true })) { + expect(entry.isFile()).toBe(true); + const row = expected.find((row) => row.product === owner && row.name === entry.name); + expect(row).toBeDefined(); + const retained = retain(row, path.join(assetDirectory, entry.name)); + publicFiles.set(`${owner}/${entry.name}`, retained); + } + }; + const retainFamily = (product, options = {}) => { + const family = extensionGithubReleaseFixture(fixtureRoot, product, options); + if (product.kind === 'exact-extension-artifact') { + const frozen = JSON.parse(readFileSync(family.manifestPath, 'utf8')); + const releaseMetadata = { + ...extensionMetadata(product.id, 'family publication reader test'), + sourceIdentity: extensionSourceIdentity(product.id, 'family publication reader test'), + }; + const inputs = { + product: product.id, + releaseProduct: product.id, + version: product.version, + releaseMetadata, + }; + const targets = [...new Set(frozen.assets.map((asset) => asset.target))]; + const cohorts = targets.map((target) => { + const assets = frozen.assets.filter((asset) => asset.target === target); + const leaf = composeExtensionReleaseDocuments({ + ...inputs, + family: target === 'ios-xcframework' ? 'native' : null, + members: [ + { + ...frozen, + assets, + iosNativeDependencies: + target === 'ios-xcframework' ? frozen.iosNativeDependencies : [], + iosRegistration: target === 'ios-xcframework' ? frozen.iosRegistration : null, + wasixInstall: assets[0].family === 'wasix' ? frozen.wasixInstall : null, + }, + ], + directAssets: assets, + }); + return { members: [leaf.manifest] }; + }); + const members = mergeNativeFinalMembers( + { + ...inputs, + members: [{ sqlName: frozen.sqlName }], + } as Parameters[0], + cohorts, + ); + const documents = composeExtensionReleaseDocuments({ + ...inputs, + family: null, + members, + directAssets: family.assets, + }); + expect(documents.manifest).toEqual(frozen); + expect(JSON.parse(JSON.stringify(documents.releaseData))).toEqual( + JSON.parse( + readFileSync( + path.join(family.directory, `${product.id}-${product.version}-manifest.json`), + 'utf8', + ), + ), + ); + writeFileSync(family.manifestPath, JSON.stringify(documents.manifest)); + } + retainPublic(product.id, family.directory); + const row = expected.find((row) => row.product === product.id)!; + const input = retain( + { ...row, name: 'extension-artifacts.json', role: 'extension-release-family-input' }, + family.manifestPath, + ); + const root = input.origin.evidence.cohorts[0].roots[0]; + root.package.ecosystem = 'internal'; + root.package.name = `${product.id}-${familyInputs.length}-release-family`; + root.package.configuration = 'portable'; + familyInputs.push({ owner: product.id, key: input.key }); + return family; + }; + const selectedProducts = (ids: readonly string[]) => + catalog.products.filter((product) => ids.includes(product.id)); + const discover = (roots: string[], ids: readonly string[]) => { + const products = selectedProducts(ids); + const rows = discoverProductArtifacts(roots, products); + const versions = new Map(products.map(({ id, version }) => [id, version])); + expect( + rows.map(({ product, id, role, kind, target, identity, name }) => ({ + product, + version: versions.get(product), + id, + role, + kind, + target, + identity, + name, + })), + ).toEqual(expectedProductArtifactRows(products)); + for (const row of rows) { + expect(path.resolve(ROOT, row.path).startsWith(`${destination}${path.sep}`)).toBe(true); + const retained = publicFiles.get(`${row.product}/${row.name}`)!; + expect(statSync(path.resolve(ROOT, row.path)).mode & 0o777).toBe( + statSync(retained.file).mode & 0o777, + ); + } + return rows; + }; + try { + for (const product of catalog.products) { + if (![contrib.nativeOwner, contrib.wasixOwner].includes(product.id)) continue; + const fixed = githubReleaseFixture(fixtureRoot, product); + fixedNames.set(product.id, fixed.rows.map(({ name }) => name).sort()); + retainPublic(product.id, fixed.directory); + } + const native = catalog.products.find(({ id }) => id === contrib.nativeOwner)!; + const wasix = catalog.products.find(({ id }) => id === contrib.wasixOwner)!; + const external = catalog.products.find(({ id }) => id === 'oliphaunt-extension-vector')!; + const nativeFamily = retainFamily(native, { + artifactProduct: contrib.artifactProduct, + family: 'native', + }); + retainFamily(wasix, { artifactProduct: contrib.artifactProduct, family: 'wasix' }); + retainFamily(external); + const original = structuredClone([...origins.values()].map(({ evidence }) => evidence)); + // Raw manifest paths now point at deleted originals; retained Files must supply every byte. + rmSync(fixtureRoot, { recursive: true, force: true }); + const ids = catalog.products.map(({ id }) => id); + const staged = stageNativeReleaseFamilies(origins, source, destination, ids); + const published = discover(staged, ids); + const contribChecksums = published.filter( + (row) => + [native.id, wasix.id].includes(row.product) && + row.role === 'github-release-metadata' && + row.kind === 'checksums', + ); + expect(contribChecksums).toHaveLength(2); + expect(new Set(contribChecksums.map(({ path: file }) => path.dirname(file))).size).toBe(2); + for (const row of contribChecksums) { + const version = catalog.products.find(({ id }) => id === row.product)!.version; + expect(row.name).toBe(`${contrib.artifactProduct}-${version}-release-assets.sha256`); + } + for (const [owner, names] of fixedNames) + expect(readdirSync(path.join(destination, owner, 'release-assets')).sort()).toEqual(names); + expect([...origins.values()].map(({ evidence }) => evidence)).toEqual(original); + for (const product of catalog.products) { + const selected = path.join(destination, `selected-${product.id}`); + const roots = stageNativeReleaseFamilies(origins, source, selected, [product.id]); + const rows = discover(roots, [product.id]); + expect(new Set(rows.map(({ product: owner }) => owner))).toEqual(new Set([product.id])); + } + const nativeAsset = publicFiles.get(`${native.id}/${nativeFamily.assets[0].name}`)!; + const fixedChecksum = expected.find( + (row) => + row.product === native.id && + row.role === 'github-release-asset' && + row.kind === 'checksums', + )!; + const checksum = publicFiles.get(`${native.id}/${fixedChecksum.name}`)!; + for (const [fault, message] of [ + ['missing-family', /lacks its complete aggregate manifest/u], + ['missing-asset', /lacks its declared public File/u], + ['foreign-file', /canonical public owner/u], + ['checksum', /checksum/u], + ] as const) { + const changed = new Map(origins); + if (fault === 'missing-family') + changed.delete(familyInputs.find(({ owner }) => owner === native.id)!.key); + if (fault === 'missing-asset') changed.delete(nativeAsset.key); + if (fault === 'foreign-file' || fault === 'checksum') { + const row = + fault === 'foreign-file' + ? { ...fixedChecksum, name: 'foreign-public.bin' } + : fixedChecksum; + const content = + fault === 'foreign-file' + ? 'foreign public bytes' + : readFileSync(checksum.file, 'utf8').replace(/^[0-9a-f]{64}/u, '0'.repeat(64)); + const key = path.join(directory, 'packets', fault); + changed.set(key, producer(key, row, content).origin); + if (fault === 'checksum') changed.delete(checksum.key); + } + const invalid = path.join(destination, fault); + expect(() => { + const roots = stageNativeReleaseFamilies(changed, source, invalid, [native.id]); + discoverProductArtifacts(roots, [native]); + }).toThrow(message); + } + for (const origin of origins.values()) origin.finalFiles.assertUnchanged(); + } finally { + rmSync(directory, { recursive: true, force: true }); + rmSync(destination, { recursive: true, force: true }); + } +}); + +test('family staging projects Windows loose modes while retaining POSIX safety and original evidence', () => { + const directory = mkdtempSync(path.join(tmpdir(), 'native-family-modes-')); + const finalDirectory = path.join(ROOT, 'target', path.basename(directory)); + try { + const rows = expectedProductArtifactRows( + loadPublicationCatalog('family transport modes').products, + ); + const asset = rows.find( + (row) => + row.product === 'liboliphaunt-native' && + row.role === 'github-release-asset' && + row.target.includes('windows'), + )!; + expect(asset).toBeDefined(); + const checksum = rows.find( + (row) => + row.product === asset.product && + row.role === 'github-release-asset' && + row.kind === 'checksums', + )!; + for (const scenario of [ + { + name: 'windows-drive', + executionRoot: 'C:\\b\\execroot\\_main', + mode: 0o666, + expected: 0o644, + }, + { + name: 'windows-slashes', + executionRoot: 'D:/b/execroot/_main', + mode: 0o444, + expected: 0o644, + }, + { + name: 'windows-unc', + executionRoot: '\\\\runner\\share\\execroot\\_main', + mode: 0o666, + expected: 0o644, + }, + { + name: 'posix-read-only', + executionRoot: '/windows-target/execroot', + mode: 0o444, + expected: 0o444, + }, + { + name: 'posix-executable', + executionRoot: '/windows-target/execroot', + mode: 0o555, + expected: 0o555, + }, + { name: 'posix-world-writable', executionRoot: '/windows-target/execroot', mode: 0o666 }, + { name: 'posix-writable-executable', executionRoot: '/windows-target/execroot', mode: 0o775 }, + { name: 'posix-unreadable', executionRoot: '/windows-target/execroot', mode: 0o222 }, + ]) { + const originals = [asset, checksum].map((row, index) => { + const evidenceRoot = path.join(directory, scenario.name, String(index)); + const captured = producer(evidenceRoot, row, `qualified ${row.name}`); + const cohort = captured.origin.evidence.cohorts[0]; + cohort.executionRoot = scenario.executionRoot; + cohort.outputs[0].members[0].mode = scenario.mode; + return { ...captured, evidenceRoot }; + }); + const origins = new Map(originals.map(({ evidenceRoot, origin }) => [evidenceRoot, origin])); + const evidence = structuredClone(originals.map(({ origin }) => origin.evidence)); + const identities = originals.map(({ file }) => fileIdentity(file)); + const destination = path.join(finalDirectory, scenario.name); + if (scenario.expected === undefined) { + expect(() => stageNativeReleaseFamilies(origins, source, destination)).toThrow( + 'unsafe captured mode', + ); + expect(existsSync(destination)).toBe(false); + } else { + const staged = stageNativeReleaseFamilies(origins, source, destination); + for (const row of [asset, checksum]) { + const file = path.join(staged[0], row.name); + expect(readFileSync(file, 'utf8')).toBe(`qualified ${row.name}`); + expect(statSync(file).mode & 0o777).toBe(scenario.expected); + } + if (scenario.name === 'windows-drive') { + const selected = stageNativeReleaseFamilies(origins, source, `${destination}-selected`, [ + asset.product, + ]); + expect(readFileSync(path.join(selected[0], asset.name))).toEqual( + readFileSync(path.join(staged[0], asset.name)), + ); + expect(statSync(path.join(selected[0], asset.name)).mode & 0o777).toBe(0o644); + } + } + expect(originals.map(({ origin }) => origin.evidence)).toEqual(evidence); + expect(originals.map(({ file }) => fileIdentity(file))).toEqual(identities); + } + } finally { + rmSync(directory, { recursive: true, force: true }); + rmSync(finalDirectory, { recursive: true, force: true }); + } +}); + +test('family staging selects each declared fixed asset from its shared original Tree', () => { + const directory = mkdtempSync(path.join(tmpdir(), 'native-shared-family-')); + const finalDirectory = path.join(ROOT, 'target', path.basename(directory)); + try { + const rows = expectedProductArtifactRows( + loadPublicationCatalog('shared iOS family staging test').products, + ).filter( + (row) => + row.product === 'liboliphaunt-native' && + (row.kind === 'apple-swiftpm-binary' || + (row.kind === 'runtime-resources' && row.target === 'ios-datum64')), + ); + expect(rows).toHaveLength(2); + const evidenceRoot = path.join(directory, 'producer'); + const originals = rows.map((row) => producer(evidenceRoot, row, `qualified ${row.name}`)); + const output = path.posix.dirname(originals[0].origin.evidence.cohorts[0].outputs[0].path); + const members = originals.map((value, index) => ({ + ...value.origin.evidence.cohorts[0].outputs[0].members[0], + path: rows[index].name, + })); + const roots = originals.map((value, index) => ({ + ...value.origin.evidence.cohorts[0].roots[0], + label: `//fixture:ios_asset_${index}`, + package: { + ...value.origin.evidence.cohorts[0].roots[0].package, + outputs: [{ path: output }], + }, + })); + const origin = originals[0].origin; + origin.evidence.cohorts[0] = { + executionRoot: '/fixture/execroot', + roots, + outputs: [{ path: output, members }], + }; + origin.finalFiles = { + files: originals.flatMap((value) => value.origin.finalFiles.files), + assertUnchanged() { + for (const [index, value] of originals.entries()) { + const actual = fileIdentity(value.file); + expect({ size: actual.size, sha256: actual.sha256 }).toEqual({ + size: members[index].size, + sha256: members[index].sha256, + }); + } + }, + }; + const origins = new Map([[evidenceRoot, origin]]); + const original = structuredClone(origin.evidence); + const final = stageNativeReleaseFamilies(origins, source, finalDirectory); + expect(final).toEqual([path.join(finalDirectory, rows[0].product, 'release-assets')]); + for (const row of rows) + for (const family of final) + expect(readFileSync(path.join(family, row.name), 'utf8')).toBe(`qualified ${row.name}`); + expect(origin.evidence).toEqual(original); + + for (const [label, change, message] of [ + [ + 'missing', + (value: any) => value.evidence.cohorts[0].outputs[0].members.shift(), + 'exact original regular File', + ], + [ + 'ambiguous', + (value: any) => + value.evidence.cohorts[0].outputs[0].members.push({ + ...members[0], + path: `nested/${members[0].path}`, + }), + 'exact original regular File', + ], + [ + 'duplicate', + (value: any) => value.evidence.cohorts[0].roots.push(structuredClone(roots[0])), + 'repeats an observed public File', + ], + [ + 'owner', + (value: any) => { + value.evidence.cohorts[0].roots[0].package.product = 'database-resources'; + }, + 'unique canonical public owner', + ], + [ + 'hash', + (value: any) => { + value.evidence.cohorts[0].outputs[0].members[0].sha256 = '0'.repeat(64); + }, + 'changed during relocation', + ], + ] as const) { + const changed = { ...origin, evidence: structuredClone(original) }; + change(changed); + const destination = path.join(finalDirectory, label); + expect(() => + stageNativeReleaseFamilies(new Map([[evidenceRoot, changed]]), source, destination), + ).toThrow(message); + expect(existsSync(destination)).toBe(false); + expect(origin.evidence).toEqual(original); + } + } finally { + rmSync(directory, { recursive: true, force: true }); + rmSync(finalDirectory, { recursive: true, force: true }); + } +}); + +test('native archive acquisition preserves preexisting output directories', async () => { + const directory = mkdtempSync(path.join(tmpdir(), 'native-family-owned-')); + const destination = path.join(directory, 'input'); + try { + for (const existing of [destination, `${destination}.inputs`]) { + mkdirSync(existing); + const sentinel = path.join(existing, 'sentinel'); + writeFileSync(sentinel, 'retained'); + await expect( + acquireNativeReleaseArchives( + { source, runId: 77, directory: destination }, + { + readJson: async () => { + throw new Error('preexisting output must reject before acquisition'); + }, + }, + ), + ).rejects.toThrow('new owned'); + expect(readFileSync(sentinel, 'utf8')).toBe('retained'); + rmSync(existing, { recursive: true }); + } + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('PR family construction uses finite completed producer transport and never admits release assurance', async () => { + const directory = mkdtempSync(path.join(tmpdir(), 'native-family-pr-')); + try { + const rows = expectedProductArtifactRows( + loadPublicationCatalog('family staging test').products, + ); + const row = rows.find( + (row) => row.product === 'liboliphaunt-native' && row.role === 'github-release-asset', + )!; + const acquired: any[] = []; + const result = await acquireNativeReleaseArchives( + { source, runId: 77, ref: 'refs/pull/295/merge', directory: path.join(directory, 'input') }, + { + readJson: async () => ({ + ...eligible, + status: 'in_progress', + conclusion: null, + event: 'pull_request', + head_branch: 'feature', + pull_requests: [{ number: 295 }], + }), + readPages: async () => [ + { name: 'native-build-evidence-x86_64', expired: false }, + { name: 'native-build-evidence-release-families', expired: false }, + { name: 'native-build-evidence-react-native-macos-arm64', expired: false }, + { name: 'arbitrary', expired: false }, + ], + acquire: async (evidenceRoot, expected) => { + acquired.push(expected); + return producer(evidenceRoot, row, 'current PR bytes').origin; + }, + }, + ); + expect(acquired).toHaveLength(1); + expect(acquired.map((row) => row.artifactName)).toEqual(['native-build-evidence-x86_64']); + expect(acquired[0].event).toBe('pull_request'); + expect(acquired[0].ref).toBe('refs/pull/295/merge'); + expect(acquired[0].github).not.toHaveProperty('runAttempt'); + expect([...result.origins.values()][0].github.runAttempt).toBe(1); + expect([...result.origins.keys()]).toEqual([path.join(result.directory, '0')]); + expect([...result.origins.values()].every((origin) => !('producerAssurance' in origin))).toBe( + true, + ); + await expect( + acquireNativeReleaseArchives( + { source, runId: 77, ref: 'refs/pull/296/merge', directory: path.join(directory, 'wrong') }, + { + readJson: async () => ({ + ...eligible, + event: 'pull_request', + pull_requests: [{ number: 295 }], + }), + readPages: async () => { + throw new Error('no artifact reads'); + }, + }, + ), + ).rejects.toThrow('exact eligible qualification'); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +for (const event of ['workflow_dispatch', 'merge_group'] as const) + test(`${event} family construction binds its exact branch while release preparation remains main-only`, async () => { + const directory = mkdtempSync(path.join(tmpdir(), 'native-family-context-')); + try { + const row = expectedProductArtifactRows( + loadPublicationCatalog('dispatch family test').products, + ).find((row) => row.product === 'liboliphaunt-native' && row.role === 'github-release-asset'); + if (!row) throw new Error('missing canonical dispatch test asset'); + const run = { + ...eligible, + status: 'in_progress', + conclusion: null, + event, + head_branch: + event === 'merge_group' ? 'gh-readonly-queue/main/pr-295-aabbcc' : 'feature/native', + }; + const requests: any[] = []; + await acquireNativeReleaseArchives( + { + source, + runId: 77, + ref: `refs/heads/${run.head_branch}`, + directory: path.join(directory, 'input'), + }, + { + readJson: async () => run, + readPages: async () => [{ name: 'native-build-evidence-x86_64', expired: false }], + acquire: async (evidenceRoot, expected) => { + requests.push(expected); + return producer(evidenceRoot, row, 'dispatch construction').origin; + }, + }, + ); + expect(requests[0].ref).toBe(`refs/heads/${run.head_branch}`); + expect(requests[0].event).toBe(event); + await expect( + acquireNativeReleaseArchives( + { source, runId: 77, ref: 'refs/heads/main', directory: path.join(directory, 'wrong') }, + { + readJson: async () => run, + readPages: async () => { + throw new Error('no artifact reads'); + }, + }, + ), + ).rejects.toThrow('exact eligible qualification'); + await expect( + prepareNativeReleaseDelivery( + { source, runId: 77, directory: path.join(directory, 'release'), completedVersions: {} }, + { + readJson: async () => ({ ...run, status: 'completed', conclusion: 'success' }), + readPages: async () => { + throw new Error('no artifact reads'); + }, + }, + ), + ).rejects.toThrow('successful exact reviewed-main'); + } finally { + rmSync(directory, { recursive: true, force: true }); + } + }); + +test('producer seed snapshot adopts all genuine completed slots without claiming historical constructor intent', async () => { + const directory = mkdtempSync(path.join(tmpdir(), 'native-seed-baseline-')); + try { + const resource = loadPublicationCatalog('seed baseline test').products.find( + (row) => row.id === 'database-resources', + ); + if (!resource) throw new Error('missing canonical resource test owner'); + const rows = expectedProductArtifactRows([resource]).filter((row) => + ['native-seeds', 'wasix-seeds'].includes(row.kind), + ); + const bytes = new Map(); + for (const row of rows.filter((row) => row.name.endsWith('.tar.zst'))) + bytes.set(row.name, Buffer.from(`fixture public PGDATA archive ${row.name}`)); + for (const row of rows.filter((row) => row.name.endsWith('.json'))) { + const identity = seedCarrierIdentities().find((identity) => + row.name.endsWith(`-seed-${identity.suffix}.json`), + ); + if (!identity) throw new Error('missing canonical seed slot'); + const name = row.name.replace(/\.json$/u, '.tar.zst'); + const archive = bytes.get(name)!; + bytes.set( + row.name, + Buffer.from( + JSON.stringify({ + catalogProfile: identity.profile, + runtime: { engineFamily: identity.family, target: identity.target, postgresMajor: 18 }, + archive: { + path: name, + compressedBytes: archive.length, + sha256: createHash('sha256').update(archive).digest('hex'), + }, + }), + ), + ); + } + const wasix = loadPublicationCatalog('seed consumer test').products.find( + (row) => row.id === 'liboliphaunt-wasix', + )!; + const admitted = Bun.TOML.parse( + readFileSync('src/database-resources/seeds/wasix/Cargo.toml', 'utf8'), + ).package.metadata.oliphaunt['runtime-version']; + const consumer = expectedProductArtifactRows([{ ...wasix, version: admitted }]).find( + (row) => row.kind === 'wasix-runtime' && row.target === 'portable', + )!; + bytes.set(consumer.name, Buffer.from('retained admitted consumer archive fixture')); + const assets = [...bytes].map(([name, value], index) => ({ + id: index + 1, + name, + state: 'uploaded', + size: value.length, + url: `https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/${index + 1}`, + digest: `sha256:${createHash('sha256').update(value).digest('hex')}`, + })); + const downloads: string[] = []; + const transport = { + inventory: fixtureCompletedNativeInventory, + readSeedAnchor: () => undefined, + readJson: async (endpoint: string) => ({ + id: 7, + target_commitish: 'c'.repeat(40), + tag_name: decodeURIComponent(endpoint.split('/').at(-1)!), + }), + readPages: async () => assets, + assertCompleted: async (request: any) => ({ + ...request, + publicationTree: 'd'.repeat(40), + releaseSha: request.publicationSha, + }), + proveAsset: async (_url: string, name: string, size: number, options: any) => { + const data = bytes.get(name)!; + expect(data.length).toBe(size); + mkdirSync(path.dirname(options.retainedPath), { recursive: true }); + writeFileSync(options.retainedPath, data); + downloads.push(name); + return { bytes: data.length, sha256: createHash('sha256').update(data).digest('hex') }; + }, + }; + const result = await acquireNativePublicationInputs( + { source, directory: path.join(directory, 'owned') }, + transport, + ); + expect(result.snapshot.seedControls).toHaveLength(rows.length / 2); + expect(downloads).toHaveLength(rows.length + 1); + expect(result.snapshot.supplierArtifacts).toHaveLength(1); + expect(result.snapshot.supplierArtifacts[0].publication.version).toBe(admitted); + expect(result.snapshot.supplierArtifacts[0].artifact).toBe(consumer.id); + expect(new Set(downloads).size).toBe(downloads.length); + expect( + result.snapshot.seedControls.every( + (row) => 'reuse' in row && row.reuse.operation === 'adopt' && !row.reuse.metadata, + ), + ).toBe(true); + expect(readFileSync(result.file, 'utf8')).not.toContain('intentSha256'); + expect( + result.snapshot.supplierPublications.every( + (publication) => publication.publicationSha === 'c'.repeat(40), + ), + ).toBe(true); + const absent = await acquireNativePublicationInputs( + { source, directory: path.join(directory, 'none'), consumerProducts: [] }, + { + readJson: async () => { + throw new Error('no unused completion reads'); + }, + readPages: async () => { + throw new Error('no unused asset reads'); + }, + }, + ); + expect(absent.snapshot.seedControls).toEqual([]); + expect(absent.snapshot.supplierPublications).toEqual([]); + const first = assets[0]; + await expect( + acquireNativePublicationInputs( + { source, directory: path.join(directory, 'missing') }, + { ...transport, readPages: async () => assets.filter((asset) => asset !== first) }, + ), + ).rejects.toThrow('missing or ambiguous'); + expect(existsSync(path.join(directory, 'missing'))).toBe(false); + const metadataName = `database-resources-${resource.version}-native-baseline.json`; + const metadataBytes = Buffer.from( + JSON.stringify({ + scope: 'construction', + source: { commit: 'c'.repeat(40), tree: 'd'.repeat(40) }, + product: { id: resource.id, version: resource.version }, + construction: [], + }), + ); + bytes.set(metadataName, metadataBytes); + const metadataAsset = { + ...first, + id: assets.length + 1, + name: metadataName, + size: metadataBytes.length, + digest: `sha256:${createHash('sha256').update(metadataBytes).digest('hex')}`, + url: `https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/${assets.length + 1}`, + }; + let metadataReads = 0; + const described = await acquireNativePublicationInputs( + { source, directory: path.join(directory, 'described-history') }, + { + ...transport, + readPages: async () => [...assets, metadataAsset], + readBaseline: async (request) => { + metadataReads++; + expect(request.publisherSha).toBeUndefined(); + expect(JSON.parse(readFileSync(request.file, 'utf8')).construction).toEqual([]); + return { + scope: 'construction', + publication: request.publication, + metadata: {}, + baselineAdmission: 'unknown', + releaseDecision: 'unverified', + } as any; + }, + }, + ); + expect(metadataReads).toBe(1); + expect( + described.snapshot.seedControls.every( + (row) => row.reuse?.operation === 'reuse' && row.reuse.metadata, + ), + ).toBe(true); + expect(described.metadataBaseline?.baselineAdmission).toBe('unknown'); + await expect( + acquireNativePublicationInputs( + { source, directory: path.join(directory, 'unauthenticated-history') }, + { + ...transport, + readPages: async () => [...assets, metadataAsset], + readBaseline: async () => { + throw new Error('metadata lacks authenticated exact attestation subject'); + }, + }, + ), + ).rejects.toThrow('authenticated exact attestation subject'); + expect(existsSync(path.join(directory, 'unauthenticated-history'))).toBe(false); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('declared held Swift source uses its retired binding name and historical owner path once', async () => { + const directory = mkdtempSync(path.join(tmpdir(), 'held-swift-inputs-')); + const bindings = Buffer.from('controlled owned binding ZIP bytes'); + const expected = 'retired-swift-binding-0.8.2.zip'; + const metadataName = 'oliphaunt-swift-0.8.2-native-baseline.json'; + const metadataBytes = Buffer.from('controlled completed metadata bytes'); + const originalMetadata = { metadata: {}, baselineAdmission: 'unknown' } as any; + const acquisitions: string[] = []; + const captures: any[] = []; + try { + const result = await acquireNativePublicationInputs( + { + source, + directory: path.join(directory, 'owned'), + consumerProducts: ['oliphaunt-react-native'], + }, + { + inventory: async (publication, options) => { + const historical = await fixtureCompletedNativeInventory(publication); + if (publication.product !== 'oliphaunt-swift') return historical; + expect(options.metadataBaseline).toBe(originalMetadata); + return { + ...historical, + descriptor: { ...historical.descriptor, path: 'retired/swift-source' }, + publicRows: historical.publicRows.map((row) => + row.kind === 'swift-bindings' + ? { ...row, id: `github-release:${expected}`, name: expected } + : row, + ), + }; + }, + readJson: async (endpoint) => ({ + id: 82, + target_commitish: 'c'.repeat(40), + tag_name: decodeURIComponent(endpoint.split('/').at(-1)!), + }), + readPages: async () => [ + { + id: 1, + name: expected, + state: 'uploaded', + size: bindings.length, + url: 'https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/1', + digest: 'sha256:' + createHash('sha256').update(bindings).digest('hex'), + }, + { + id: 2, + name: metadataName, + state: 'uploaded', + size: metadataBytes.length, + url: 'https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/2', + digest: 'sha256:' + createHash('sha256').update(metadataBytes).digest('hex'), + }, + ], + readBaseline: async ({ file }) => { + expect(readFileSync(file)).toEqual(metadataBytes); + return originalMetadata; + }, + assertCompleted: async (request) => ({ + ...request, + publicationTree: 'd'.repeat(40), + releaseSha: request.publicationSha, + }), + proveAsset: async (_url, name, size, options) => { + acquisitions.push(name); + mkdirSync(path.dirname(options.retainedPath), { recursive: true }); + const bytes = name === metadataName ? metadataBytes : bindings; + expect(size).toBe(bytes.length); + writeFileSync(options.retainedPath, bytes); + return { bytes: size, sha256: createHash('sha256').update(bytes).digest('hex') }; + }, + materialize: async (carrier: any, options: any) => { + expect(carrier.product).toBe('oliphaunt-query-ts'); + expect(carrier.id).toBe('npm:@oliphaunt/ts-query'); + expect(carrier.version).toBe('0.1.1'); + mkdirSync(options.directory, { recursive: true }); + const file = path.join(options.directory, carrier.artifacts[0].path); + writeFileSync( + file, + tarArchive([ + { + name: 'package/package.json', + data: JSON.stringify({ name: carrier.name, version: carrier.version }), + }, + ]), + ); + const { size, sha256 } = fileIdentity(file); + return { + carrier: { ...carrier, artifacts: [{ path: file, size, sha256 }] }, + receipt: {}, + metadata: {}, + }; + }, + captureSwiftSource: async (input) => { + captures.push(input); + writeFileSync(input.retainedArchive, Buffer.from('controlled Git delivery bytes')); + const { size, sha256 } = fileIdentity(input.retainedArchive); + return { + scope: 'construction', + publication: input.publication, + nativePublication: input.publication, + members: [], + source: { + commit: 'e'.repeat(40), + tree: 'f'.repeat(40), + member: 'src/sdks/swift/Carriers/oliphaunt-react-native-ios-carriers.json', + blob: '1'.repeat(40), + }, + file: { path: input.retainedArchive, size, sha256 }, + }; + }, + } as any, + ); + expect(acquisitions).toEqual([metadataName, expected]); + expect(result.supplierMetadata.get('oliphaunt-swift@0.8.2')).toBe(originalMetadata); + expect(readFileSync(result.file, 'utf8')).not.toContain('baselineAdmission'); + expect(captures).toHaveLength(1); + expect(captures[0].descriptor.path).toBe('retired/swift-source'); + expect(captures[0].bindings.name).toBe(expected); + expect(captures[0].bindings.sha256).toBe(createHash('sha256').update(bindings).digest('hex')); + expect(result.snapshot.seedControls).toEqual([]); + expect(result.snapshot.supplierArtifacts!.map((row) => row.artifact)).toEqual([ + 'npm:@oliphaunt/ts-query', + 'github-release:' + expected, + 'swift-source-tag:0.8.2', + ]); + expect(result.snapshot.supplierArtifacts!.find((row) => row.source)!.source!.commit).not.toBe( + result.snapshot.supplierArtifacts!.find((row) => row.source)!.publication.publicationSha, + ); + expect( + result.snapshot.supplierArtifacts!.every( + (row) => fileIdentity(row.file.path).sha256 === row.file.sha256, + ), + ).toBe(true); + expect(result.snapshot).not.toHaveProperty('ready'); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('RN bootstrap acquires only the original Apple role and cannot wait on its own consumer or the checksum job', async () => { + const directory = mkdtempSync(path.join(tmpdir(), 'native-rn-bootstrap-')); + const requests: string[] = []; + try { + const options = { + source, + runId: 77, + directory: path.join(directory, 'producers'), + requestedArtifactNames: ['native-build-evidence-mobile-ios'], + excludeArtifactNames: [ + 'native-build-evidence-release-families', + 'native-build-evidence-react-native-macos-arm64', + ], + }; + const readJson = async () => eligible; + const artifacts = [ + { name: 'native-build-evidence-mobile-ios', expired: false }, + { name: 'native-build-evidence-native-macos-arm64', expired: false }, + { name: 'native-build-evidence-react-native-macos-arm64', expired: false }, + { name: 'native-build-evidence-release-families', expired: false }, + ]; + const readPages = (endpoint, options) => + requestGithubPages(endpoint, { + ...options, + environment: {}, + fetchImpl: async (url) => { + expect(url).toBe( + 'https://api.github.com/repos/f0rr0/oliphaunt/actions/runs/77/artifacts?per_page=100&page=1', + ); + return Response.json({ total_count: artifacts.length, artifacts }); + }, + }); + const acquire = async (_root: string, expected: any) => { + requests.push(expected.artifactName); + return { + github: { ...expected.github, runAttempt: 1 }, + finalFiles: { qualification: { requiredTests: [] } }, + } as any; + }; + const result = await acquireNativePublicationBuilds(options, { readJson, readPages, acquire }); + expect(requests).toEqual(['native-build-evidence-mobile-ios']); + expect(result.builds).toHaveLength(1); + await expect( + acquireNativePublicationBuilds( + { ...options, directory: path.join(directory, 'missing') }, + { + readJson, + readPages: async () => [ + { name: 'native-build-evidence-native-macos-arm64', expired: false }, + ], + acquire, + }, + ), + ).rejects.toThrow('no retained source producer'); + expect(requests).toHaveLength(1); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('mixed producer acquisition keeps latest run observation separate from each authenticated role', async () => { + const directory = mkdtempSync(path.join(tmpdir(), 'native-mixed-attempts-')); + try { + const requests: any[] = []; + const attempts = new Map([ + ['native-build-evidence-x86_64', 2], + ['native-build-evidence-aarch64', 1], + ]); + const result = await acquireNativePublicationBuilds( + { source, runId: 77, directory: path.join(directory, 'producers') }, + { + readJson: async () => ({ ...eligible, run_attempt: 2 }), + readPages: async () => [...attempts.keys()].map((name) => ({ name, expired: false })), + acquire: async (_directory, expected) => { + requests.push(expected); + return { + github: { ...expected.github, runAttempt: attempts.get(expected.artifactName) }, + finalFiles: { qualification: { requiredTests: [] } }, + } as any; + }, + }, + ); + expect(result.run.run_attempt).toBe(2); + expect( + requests.every( + (request) => + !Object.hasOwn(request.github, 'runAttempt') && request.workflowRunAttempt === 2, + ), + ).toBe(true); + expect(result.builds.map((build) => build.expected.github.runAttempt)).toEqual([2, 1]); + expect([...result.origins.values()].map((origin) => origin.github.runAttempt)).toEqual([2, 1]); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('SDK minimum acquisition asks its exact authored internal floors, including the declared helper', () => { + const catalog = { + products: [{ id: 'oliphaunt-rust', path: 'sdk', version: '0.3.3' }], + carriers: [ + { + id: 'cargo:liboliphaunt-native-bindings', + name: 'liboliphaunt-native-bindings', + ecosystem: 'cargo', + target: null, + product: 'liboliphaunt-native-bindings', + version: '0.2.2', + }, + { + id: 'cargo:oliphaunt-build', + name: 'oliphaunt-build', + ecosystem: 'cargo', + target: null, + product: 'oliphaunt-rust', + version: '0.3.3', + }, + ], + } as any; + const source = `[package]\nname="oliphaunt"\nversion="0.3.3"\n[dependencies]\ncore={package="liboliphaunt-native-bindings",workspace=true}\nserde="1"\n[build-dependencies]\noliphaunt-build="0.3.2"\n`; + const workspace = `[workspace.dependencies]\ncore={package="liboliphaunt-native-bindings",path="core",version="^0.2.1"}\n`; + const read = (file: string) => (file === 'Cargo.toml' ? workspace : source); + expect(nativeCargoMinimumBindings(catalog, [], read)).toEqual([]); + expect(nativeCargoMinimumBindings(catalog, ['oliphaunt-rust'], read)).toEqual([ + { + consumer: 'oliphaunt-rust', + producer: 'liboliphaunt-native-bindings', + producerVersion: '0.2.1', + requestedCarrier: 'cargo:liboliphaunt-native-bindings', + }, + { + consumer: 'oliphaunt-rust', + producer: 'oliphaunt-rust', + producerVersion: '0.3.2', + requestedCarrier: 'cargo:oliphaunt-build', + }, + ]); + for (const floor of ['0.2.1', '^0.2.1', '~0.2.1', '=0.2.1', '>=0.2.1, <0.3.0']) + expect( + nativeCargoMinimumBindings(catalog, ['oliphaunt-rust'], (file) => + read(file).replace('^0.2.1', floor), + )[0].producerVersion, + ).toBe('0.2.1'); + for (const floor of ['0.2', '^0.2', '~0.2', '=0.2', '>=0.2, <0.3']) + expect( + nativeCargoMinimumBindings(catalog, ['oliphaunt-rust'], (file) => + read(file).replace('^0.2.1', floor), + )[0].producerVersion, + ).toBe('0.2.0'); + for (const floor of ['*', '>0.2.1', '>=0.2.1, <0.2.1', '^0.2.1 || ^0.3.0']) + expect(() => + nativeCargoMinimumBindings(catalog, ['oliphaunt-rust'], (file) => + read(file).replace('^0.2.1', floor), + ), + ).toThrow('Internal Cargo minimum'); + const initial = { + ...catalog, + carriers: catalog.carriers.map((row: any) => ({ ...row, version: '0.0.0' })), + }; + expect( + nativeCargoMinimumBindings(initial, ['oliphaunt-rust'], (file) => + read(file).replaceAll('0.2.1', '0.0.0').replaceAll('0.3.2', '0.0.0'), + ), + ).toEqual([]); +}); + +test('shared SDK supplier acquisition retains exact source floors once as physical pool Files', async () => { + const directory = mkdtempSync(path.join(tmpdir(), 'native-sdk-floor-inputs-')); + const requests: string[] = []; + const assets = expectedProductArtifactRows( + loadPublicationCatalog().products.filter((row) => row.id === 'oliphaunt-broker'), + ) + .filter((row) => row.kind === 'broker-helper') + .map((row, index) => ({ + id: index + 1, + name: row.name, + size: 3, + state: 'uploaded', + url: `https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/${index + 1}`, + })); + try { + const result = await acquireNativePublicationInputs( + { source, directory: path.join(directory, 'owned'), consumerProducts: ['oliphaunt-rust'] }, + { + inventory: fixtureCompletedNativeInventory, + readBaseline: async () => undefined, + readPages: async () => assets, + readJson: async (endpoint) => ({ + id: 1, + target_commitish: 'c'.repeat(40), + tag_name: decodeURIComponent(endpoint.split('/').at(-1)!), + }), + assertCompleted: async (request) => ({ + ...request, + publicationTree: 'd'.repeat(40), + releaseSha: request.publicationSha, + }), + materialize: async (carrier, options) => { + requests.push(`${carrier.id}@${carrier.version}`); + mkdirSync(options.directory, { recursive: true }); + const file = path.join(options.directory, carrier.artifacts[0].path); + writeFileSync( + file, + tarArchive([ + { + name: `${carrier.name}-${carrier.version}/Cargo.toml`, + data: `[package]\nname="${carrier.name}"\nversion="${carrier.version}"\n`, + }, + ]), + ); + const identity = fileIdentity(file); + return { + carrier: { + ...carrier, + artifacts: [{ path: file, size: identity.size, sha256: identity.sha256 }], + }, + receipt: {}, + metadata: {}, + }; + }, + proveAsset: async (_url, _name, _size, options) => { + mkdirSync(path.dirname(options.retainedPath), { recursive: true }); + writeFileSync(options.retainedPath, 'old'); + const identity = fileIdentity(options.retainedPath); + return { bytes: identity.size, sha256: identity.sha256 }; + }, + }, + ); + const sourceRequests = [ + 'cargo:liboliphaunt-native-bindings@0.2.0', + 'cargo:oliphaunt-broker@0.3.1', + 'cargo:oliphaunt-build@0.3.2', + 'cargo:oliphaunt-query@0.1.1', + ]; + const payloadRequests = [ + 'linux-arm64-gnu', + 'linux-x64-gnu', + 'macos-arm64', + 'windows-x64-msvc', + ].flatMap((target) => [ + `cargo:liboliphaunt-native-${target}@0.3.2`, + `cargo:oliphaunt-broker-${target}@0.3.1`, + ]); + const expected = [...sourceRequests, ...payloadRequests].toSorted(); + expect(requests.toSorted()).toEqual(expected); + expect(new Set(requests).size).toBe(expected.length); + const retained = + result.snapshot.supplierArtifacts?.filter((row) => row.artifact.startsWith('cargo:')) ?? []; + const identities = retained.map((row) => `${row.artifact}@${row.publication.version}`); + expect(identities.toSorted()).toEqual(expected); + const sourceFloors = identities.filter((id) => sourceRequests.includes(id)); + expect(sourceFloors.toSorted()).toEqual(sourceRequests); + expect(sourceFloors).toHaveLength(4); + expect(identities.filter((id) => payloadRequests.includes(id))).toHaveLength(8); + for (const row of retained) + expect(fileIdentity(row.file.path)).toMatchObject({ + size: row.file.size, + sha256: row.file.sha256, + }); + expect(result.snapshot).not.toHaveProperty('qualified'); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('native floor acquisition groups alias normal/build/target requirements before one exact lookup', () => { + const catalog = { + products: [{ id: 'oliphaunt-rust', path: 'sdk', version: '0.3.3' }], + carriers: [ + { + id: 'cargo:liboliphaunt-native-bindings', + name: 'liboliphaunt-native-bindings', + ecosystem: 'cargo', + target: null, + product: 'liboliphaunt-native-bindings', + version: '0.2.2', + }, + ], + } as any; + const requests = (normal: string, build: string) => + nativeCargoMinimumBindings(catalog, ['oliphaunt-rust'], (file) => + file === 'Cargo.toml' + ? '[workspace]\n' + : `[package]\nname="oliphaunt"\nversion="0.3.3"\n[dependencies]\ncore={package="liboliphaunt-native-bindings",version="${normal}"}\n[build-dependencies]\ncore_build={package="liboliphaunt-native-bindings",version="${build}"}\n[target.'cfg(unix)'.dependencies]\ncore_target={package="liboliphaunt-native-bindings",version="^0.2.0"}\n`, + ); + const expected = [ + { + consumer: 'oliphaunt-rust', + producer: 'liboliphaunt-native-bindings', + producerVersion: '0.2.1', + requestedCarrier: 'cargo:liboliphaunt-native-bindings', + }, + ]; + expect(requests('^0.2.0', '^0.2.1')).toEqual(expected); + expect(requests('^0.2.1', '^0.2.0')).toEqual(expected); + expect(requests('0.2', '^0.2.1')).toEqual(expected); + expect(requests('^0.2.1', '0.2')).toEqual(expected); + expect(() => requests('=0.2.0', '^0.2.1')).toThrow('requirements conflict'); +}); diff --git a/tools/release/native-seed-baseline.mts b/tools/release/native-seed-baseline.mts new file mode 100644 index 000000000..e67086110 --- /dev/null +++ b/tools/release/native-seed-baseline.mts @@ -0,0 +1,396 @@ +/** One reviewed source adoption contract closes missing legacy constructor history. */ +import assert from 'node:assert/strict'; +import { execFileSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { existsSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { + assertSeedPublicData, + SEED_CONSTRUCTION_ANCHOR_SCHEMA, + SEED_CONSTRUCTION_RECEIPT_SUFFIX, + type SeedConstructionAnchor, + seedConstructionIntentSha256, + validateSeedConstructionAnchor, + validateSeedConstructionReceipt, +} from '../../build_defs/resources/seed_construction.mts'; +import { assertAuthenticatedNativeBuildOrigin } from './authenticate-native-build-evidence.mts'; +import { buildShippingInputView } from './bazel-shipping-inputs.mts'; +import type { CompletedPublication } from './completed-release-publication.mts'; +import { + type NativeBuildSource, + nativeRequiredCaptureInputs, + nativeShippingRootsHaveQualification, +} from './native-build-qualification.mts'; +import { fileIdentity } from './native-file-identity.mts'; +import { assertAuthenticatedNativePublicBaseline } from './native-publication-metadata.mts'; +import type { observeNativePublicationConstruction } from './native-publication-observation.mts'; +import type { NativeSeedInputControl } from './native-seed-inputs.mts'; +import { loadPublicationCatalog } from './publication-catalog.mts'; +import { expectedProductArtifactRows } from './publication-lock.mts'; +import { ROOT } from './release-graph.mts'; + +export const seedConstructionAnchorPath = 'src/database-resources/seeds/construction-anchor.json'; +export type NativeSeedConstructionBaseline = + | NonNullable> + | { + metadata: ReturnType; + files: Record; + }; +const identity = (file: string) => { + const actual = fileIdentity(file); + return { size: actual.size, sha256: actual.sha256 }; +}; +const declaredAnchors = new WeakMap< + object, + { source: NativeBuildSource; directory: string; sha256: string } +>(); + +/** An immutable committed contract is a source declaration, never producer assurance. */ +export function readDeclaredSeedConstructionAnchor(source: NativeBuildSource, directory = ROOT) { + const git = (...args: string[]) => + execFileSync('git', args, { cwd: directory, encoding: 'utf8' }).trim(); + assert.equal( + git('rev-parse', `${source.commit}^{tree}`), + source.tree, + 'seed baseline source tree differs', + ); + const file = path.join(directory, seedConstructionAnchorPath); + if (!git('ls-tree', '--name-only', source.commit, '--', seedConstructionAnchorPath)) { + assert.ok( + !git('log', '--format=%H', source.commit, '--', seedConstructionAnchorPath), + 'seed adoption contract was removed from source', + ); + assert.ok(!existsSync(file), 'seed adoption contract must be committed in the current source'); + return undefined; + } + assert.match( + git('ls-tree', source.commit, '--', seedConstructionAnchorPath), + /^100644 blob [a-f0-9]{40}\tsrc\/database-resources\/seeds\/construction-anchor\.json$/u, + 'seed adoption contract must be a regular source file', + ); + const blob = execFileSync('git', ['show', `${source.commit}:${seedConstructionAnchorPath}`], { + cwd: directory, + }); + assert.deepEqual( + readFileSync(file), + blob, + 'seed adoption contract differs from committed source', + ); + const changes = git( + 'log', + '--reverse', + '--format=%H', + source.commit, + '--', + seedConstructionAnchorPath, + ) + .split('\n') + .filter(Boolean); + assert.ok(changes.length, 'seed adoption contract has no introduction'); + const original = execFileSync('git', ['show', `${changes[0]}:${seedConstructionAnchorPath}`], { + cwd: directory, + }); + assert.deepEqual( + blob, + original, + 'seed adoption contract changed after its original introduction', + ); + const anchor = validateSeedConstructionAnchor(JSON.parse(blob.toString('utf8'))); + const value = { anchor, file: { path: file, ...identity(file) } }; + declaredAnchors.set(value, { + source: structuredClone(source), + directory, + sha256: value.file.sha256, + }); + return value; +} + +export function assertDeclaredSeedConstructionAnchor(value: unknown, source: NativeBuildSource) { + assert.ok( + value && typeof value === 'object' && declaredAnchors.has(value), + 'seed baseline requires its actual immutable source declaration', + ); + const proof = declaredAnchors.get(value)!; + assert.deepEqual(proof.source, source, 'seed baseline observation source differs'); + const fresh = readDeclaredSeedConstructionAnchor(source, proof.directory); + assert.ok(fresh); + assert.equal(fresh.file.sha256, proof.sha256, 'seed baseline declaration changed'); + assert.deepEqual(value, fresh, 'seed baseline facts changed'); + return value as NonNullable>; +} + +/** Published constructor facts replace the one-time adoption contract after release. */ +export function assertSeedConstructionBaseline( + value: NativeSeedConstructionBaseline, + source: NativeBuildSource, +) { + if ('anchor' in value) return assertDeclaredSeedConstructionAnchor(value, source); + assertAuthenticatedNativePublicBaseline(value.metadata); + assert.equal(value.metadata.publication.product, 'database-resources'); + return value; +} + +/** Diagnostic PR captures may propose this contract; main review grants source policy. */ +export function proposeSeedConstructionAnchor({ + source, + origins, + seedControls, +}: { + source: NativeBuildSource; + origins: Map>; + seedControls: NativeSeedInputControl[]; +}) { + assert.ok(seedControls.length, 'seed adoption needs complete public slots'); + const publication = seedControls[0].reuse?.publication; + assert.ok(publication); + const resource = loadPublicationCatalog('seed adoption source contract').products.find( + (product) => product.id === publication.product, + )!; + const expected = expectedProductArtifactRows([{ ...resource, version: publication.version }]) + .filter( + (row) => ['native-seeds', 'wasix-seeds'].includes(row.kind) && row.name.endsWith('.json'), + ) + .map((row) => row.name) + .sort(); + assert.deepEqual( + seedControls.map((row) => path.basename(row.reuse!.manifest.path)).sort(), + expected, + 'seed adoption requires every canonical public slot', + ); + const seeds: SeedConstructionAnchor['seeds'] = []; + for (const origin of origins.values()) assertAuthenticatedNativeBuildOrigin(origin); + for (const control of seedControls) { + assert.ok( + control.reuse && control.reuse.operation === 'adopt' && !control.promotion, + 'seed adoption requires explicitly acquired legacy public data', + ); + assert.deepEqual(control.reuse.publication, publication, 'seed adoption public origin differs'); + const matches: SeedConstructionAnchor['seeds'] = []; + for (const [directory, origin] of origins) { + assert.deepEqual(origin.evidence.source, source, 'seed adoption producer source differs'); + assert.ok(origin.finalFiles?.qualification); + const qualification = origin.finalFiles.qualification; + assert.equal(qualification.shippingAnalysis, 'bound'); + assert.equal(qualification.testQualification, 'passed'); + for (const [index, cohort] of origin.evidence.cohorts.entries()) { + const roots = cohort.roots.filter( + (root) => + root.package.product === publication.product && + root.package.name === path.basename(control.reuse!.archive.path) && + root.package.configuration === control.target, + ); + if (!roots.length) continue; + assert.equal(roots.length, 1, 'seed adoption shipping owner is ambiguous'); + assert.ok( + nativeShippingRootsHaveQualification( + qualification.cohorts[index].qualificationPolicy, + roots, + ), + 'seed adoption requires its actual source-owned mandatory qualification', + ); + const view = buildShippingInputView( + { + schema: 'oliphaunt-bazel-shipping-v1', + scope: 'construction', + packages: roots.map((root) => root.package), + }, + cohort.aquery, + ); + const reached = new Set([...view.physicalInputs, ...nativeRequiredCaptureInputs(view)]); + const rows = (cohort.seedConstructions ?? []).filter( + (row) => + reached.has(row.path) && + ['family', 'target', 'profile'].every( + (key) => + validateSeedConstructionReceipt(JSON.parse(row.contents)).intent[key] === + control[key], + ), + ); + assert.equal( + rows.length, + 1, + 'seed adoption requires its unique reached constructor receipt', + ); + const row = rows[0]; + const receipt = validateSeedConstructionReceipt(JSON.parse(row.contents)); + const receiptPath = path.join(directory, 'files', String(index), row.path); + assert.equal( + readFileSync(receiptPath, 'utf8'), + row.contents, + 'seed adoption original receipt File differs', + ); + const frozenPath = path.join( + directory, + 'files', + String(index), + `${row.path.slice(0, -SEED_CONSTRUCTION_RECEIPT_SUFFIX.length)}.tar`, + ); + assert.deepEqual( + identity(frozenPath), + receipt.frozen, + 'seed adoption original frozen File differs', + ); + assertSeedPublicData(control.reuse.archive.path, receipt); + matches.push({ + family: control.family, + target: control.target, + profile: control.profile, + archive: identity(control.reuse.archive.path), + manifest: identity(control.reuse.manifest.path), + receipt: { ...identity(receiptPath), contents: row.contents }, + producer: { + evidenceDigest: origin.evidenceDigest, + invocationId: qualification.cohorts[index].invocationId, + root: roots[0].label, + configuration: qualification.cohorts[index].roots.find( + (row) => row.label === roots[0].label, + )!.configuration, + output: row.path, + }, + }); + } + } + assert.equal( + matches.length, + 1, + 'seed adoption requires one independently authenticated producer per public slot', + ); + seeds.push(matches[0]); + } + for (const origin of origins.values()) origin.finalFiles!.assertUnchanged(); + seeds.sort((left, right) => + `${left.family}/${left.target}/${left.profile}`.localeCompare( + `${right.family}/${right.target}/${right.profile}`, + ), + ); + return validateSeedConstructionAnchor({ + schema: SEED_CONSTRUCTION_ANCHOR_SCHEMA, + source: structuredClone(source), + publication, + seeds, + }); +} + +export function writeSeedConstructionAnchorProposal(file: string, anchor: SeedConstructionAnchor) { + assert.ok(!existsSync(file), 'seed adoption is one immutable source contract'); + writeFileSync(file, `${JSON.stringify(validateSeedConstructionAnchor(anchor), null, 2)}\n`, { + flag: 'wx', + }); +} + +/** Causal input changes justify a fresh seed only after joining its exact public PGDATA. */ +export function seedArchiveHasChangedDeclaredContents({ + declaration, + source, + publication, + observation, + artifactId, +}: { + declaration: NativeSeedConstructionBaseline; + source: NativeBuildSource; + publication: CompletedPublication; + observation: Awaited>; + artifactId: string; +}) { + const baseline = assertSeedConstructionBaseline(declaration, source); + assert.deepEqual( + 'anchor' in baseline ? baseline.anchor.publication : baseline.metadata.publication, + publication, + 'seed causal baseline completed origin differs', + ); + const product = observation.products.find(({ product }) => product.id === publication.product); + assert.ok(product, 'seed causal comparison lacks the observed resource owner'); + const archive = product.productArtifacts.find( + (row) => + row.id === artifactId && + ['native-seeds', 'wasix-seeds'].includes(row.kind) && + row.name.endsWith('.tar.zst'), + ); + assert.ok(archive, 'seed causal comparison needs its canonical public archive'); + const descriptors = product.productArtifacts.filter( + (row) => + row.kind === archive.kind && row.target === archive.target && row.name.endsWith('.json'), + ); + const descriptorFiles = descriptors + .map((row) => { + assert.equal(row.qualifiedFiles.length, 1); + const file = row.qualifiedFiles[0]; + assert.deepEqual( + identity(file.frozenPath), + { size: file.size, sha256: file.sha256 }, + 'seed causal descriptor File changed', + ); + return JSON.parse(readFileSync(file.frozenPath, 'utf8')); + }) + .filter((descriptor) => descriptor.archive?.path === archive.name); + assert.equal(descriptorFiles.length, 1, 'seed causal descriptor slot is ambiguous'); + const descriptor = descriptorFiles[0]; + const slot = { + family: archive.kind === 'native-seeds' ? 'native' : 'wasix', + target: archive.target, + profile: descriptor.catalogProfile, + }; + assert.equal(archive.qualifiedFiles.length, 1); + const archiveFile = archive.qualifiedFiles[0]; + assert.deepEqual( + identity(archiveFile.frozenPath), + { size: archiveFile.size, sha256: archiveFile.sha256 }, + 'seed causal public File changed', + ); + const rows = product.construction.flatMap((construction) => { + if (!construction.roots.some((root) => root.label === archiveFile.label)) return []; + return (construction.seedConstructions ?? []) + .map(({ contents }) => validateSeedConstructionReceipt(JSON.parse(contents))) + .filter((receipt) => + ['family', 'target', 'profile'].every((key) => receipt.intent[key] === slot[key]), + ); + }); + assert.equal(rows.length, 1, 'seed causal comparison needs its unique actual constructor'); + const current = rows[0]; + assertSeedPublicData(archiveFile.frozenPath, current); + let previous: ReturnType; + if ('anchor' in baseline) { + const seed = baseline.anchor.seeds.find((seed) => + ['family', 'target', 'profile'].every((key) => seed[key] === slot[key]), + ); + assert.ok(seed, 'seed causal baseline slot is absent'); + previous = validateSeedConstructionReceipt(JSON.parse(seed.receipt.contents)); + } else { + const metadata = baseline.metadata.metadata; + const oldArchives = metadata.productArtifacts.filter( + (row) => + row.kind === archive.kind && row.target === archive.target && row.name.endsWith('.tar.zst'), + ); + const matches = oldArchives.flatMap((row) => { + const receipts = metadata.construction.flatMap((construction) => { + if (!construction.roots.some((root) => root.package.name === row.name)) return []; + return (construction.seedConstructions ?? []) + .map(({ contents }) => validateSeedConstructionReceipt(JSON.parse(contents))) + .filter((receipt) => + ['family', 'target', 'profile'].every((key) => receipt.intent[key] === slot[key]), + ); + }); + return receipts.map((receipt) => ({ row, receipt })); + }); + assert.equal(matches.length, 1, 'signed seed baseline needs its unique original constructor'); + const { row, receipt } = matches[0]; + const file = baseline.files[row.id]; + assert.ok(file, 'signed seed baseline lacks its retained public archive'); + assert.equal(row.qualifiedFiles.length, 1, 'signed seed baseline public File is ambiguous'); + assert.deepEqual( + identity(file), + { size: row.qualifiedFiles[0].size, sha256: row.qualifiedFiles[0].sha256 }, + 'signed seed baseline differs from its original public File', + ); + assertSeedPublicData(file, receipt); + previous = receipt; + } + const oldContent = previous.qualificationContentIntent ?? previous.contentIntent; + const newContent = current.qualificationContentIntent ?? current.contentIntent; + return ( + !!oldContent && + !!newContent && + current.origin.kind === 'constructed' && + seedConstructionIntentSha256(oldContent) !== seedConstructionIntentSha256(newContent) + ); +} diff --git a/tools/release/native-seed-baseline.test.mts b/tools/release/native-seed-baseline.test.mts new file mode 100644 index 000000000..cdd76d959 --- /dev/null +++ b/tools/release/native-seed-baseline.test.mts @@ -0,0 +1,345 @@ +import { expect, test } from 'bun:test'; +import { execFileSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + captureSeedConstructionIntent, + captureSeedContentIntent, + SEED_CONSTRUCTION_ANCHOR_SCHEMA, + selectCompletedSeed, + writeSeedConstructionReceipt, +} from '../../build_defs/resources/seed_construction.mts'; +import { + bootstrapFiles, + fixture, + identity, + publication, +} from '../../build_defs/resources/seed-construction-fixture.mts'; +import { packageClusterSeed } from '../../src/database-resources/seeds/package.mts'; +import { createDeterministicTar } from '../packaging/archive-directory.mts'; +import { + assertDeclaredSeedConstructionAnchor, + assertSeedConstructionBaseline, + readDeclaredSeedConstructionAnchor, + seedArchiveHasChangedDeclaredContents, + seedConstructionAnchorPath, +} from './native-seed-baseline.mts'; + +test('signed-looking serialized constructor metadata cannot replace the actual completed publisher capability', () => { + const source = { commit: 'a'.repeat(40), tree: 'b'.repeat(40) }; + expect(() => + assertSeedConstructionBaseline( + { + metadata: { + publication: { product: 'database-resources' }, + metadata: { construction: [] }, + publicOrigin: { attestation: { subjects: [] } }, + }, + files: {}, + } as any, + source, + ), + ).toThrow('authenticated completed metadata'); +}); + +test('one committed adoption contract survives unrelated commits, rejects source/receipt edits and cannot be removed or cloned into authority', async () => { + const root = mkdtempSync(path.join(tmpdir(), 'seed-anchor-source-')); + const git = (...args: string[]) => + execFileSync('git', args, { cwd: root, encoding: 'utf8' }).trim(); + const commit = () => { + git('add', '.'); + git( + '-c', + 'user.name=Fixture', + '-c', + 'user.email=fixture@example.invalid', + 'commit', + '-qm', + 'fixture', + ); + return { commit: git('rev-parse', 'HEAD'), tree: git('rev-parse', 'HEAD^{tree}') }; + }; + try { + git('init', '-q'); + writeFileSync(path.join(root, 'source.mts'), '// initial source'); + let current = commit(); + expect(readDeclaredSeedConstructionAnchor(current, root)).toBeUndefined(); + const workspace = mkdtempSync(path.join(tmpdir(), 'seed-anchor-bytes-')); + try { + const pgdata = path.join(workspace, 'pgdata'); + mkdirSync(path.join(pgdata, 'global'), { recursive: true }); + // The receipt writer requires the canonical full directory contract. + const contract = JSON.parse( + readFileSync( + new URL('../../src/database-resources/contracts/contract.json', import.meta.url), + 'utf8', + ), + ); + for (const dir of contract.pgdataDirectories) + mkdirSync(path.join(pgdata, dir), { recursive: true }); + writeFileSync(path.join(pgdata, 'PG_VERSION'), '18\n'); + writeFileSync(path.join(pgdata, 'global/pg_control'), 'fixed actual bytes'); + const input = path.join(workspace, 'bootstrap.sql'); + writeFileSync(input, 'bootstrap actual bytes'); + const intent = captureSeedConstructionIntent( + { family: 'native', target: 'linux-x64-gnu', profile: 'standard' }, + { contract: 'PG18' }, + { bootstrap: input }, + ); + const frozen = path.join(workspace, 'seed.tar'); + writeFileSync(frozen, await createDeterministicTar(pgdata)); + const publication = { + product: 'database-resources', + version: '0.2.2', + tagName: 'database-resources-v0.2.2', + publicationSha: 'a'.repeat(40), + publicationTree: 'b'.repeat(40), + releaseSha: 'c'.repeat(40), + }; + const archive = { size: 42, sha256: 'd'.repeat(64) }, + manifest = { size: 43, sha256: 'e'.repeat(64) }; + const receiptPath = path.join(workspace, 'receipt.json'); + writeSeedConstructionReceipt( + receiptPath, + intent, + frozen, + pgdata, + { kind: 'completed-publication', operation: 'adopted', publication, archive, manifest }, + intent, + ); + const contents = readFileSync(receiptPath, 'utf8'); + const anchor = { + schema: SEED_CONSTRUCTION_ANCHOR_SCHEMA, + source: current, + publication, + seeds: [ + { + family: intent.family, + target: intent.target, + profile: intent.profile, + archive, + manifest, + receipt: { + size: Buffer.byteLength(contents), + sha256: createHash('sha256').update(contents).digest('hex'), + contents, + }, + producer: { + evidenceDigest: `sha256:${'f'.repeat(64)}`, + invocationId: 'original-PR-observation', + root: '//resource:root', + configuration: 'real-config', + output: 'seed.seed-construction.json', + }, + }, + ], + }; + const file = path.join(root, seedConstructionAnchorPath); + mkdirSync(path.dirname(file), { recursive: true }); + const bytes = JSON.stringify(anchor); + writeFileSync(file, bytes); + expect(() => readDeclaredSeedConstructionAnchor(current, root)).toThrow('must be committed'); + current = commit(); + const declared = readDeclaredSeedConstructionAnchor(current, root); + expect(assertDeclaredSeedConstructionAnchor(declared, current).anchor.source).toEqual( + anchor.source, + ); + expect(() => + assertDeclaredSeedConstructionAnchor(structuredClone(declared), current), + ).toThrow('actual immutable'); + expect(() => + readDeclaredSeedConstructionAnchor({ ...current, tree: '1'.repeat(40) }, root), + ).toThrow('tree differs'); + writeFileSync(path.join(root, 'source.mts'), '// unrelated comments after many releases'); + current = commit(); + expect(readDeclaredSeedConstructionAnchor(current, root)?.anchor).toEqual(anchor); + writeFileSync(file, `${bytes}\n`); + expect(() => readDeclaredSeedConstructionAnchor(current, root)).toThrow( + 'differs from committed', + ); + current = commit(); + expect(() => readDeclaredSeedConstructionAnchor(current, root)).toThrow('changed after'); + writeFileSync(file, bytes); + current = commit(); + expect(readDeclaredSeedConstructionAnchor(current, root)?.anchor).toEqual(anchor); + rmSync(file); + current = commit(); + expect(() => readDeclaredSeedConstructionAnchor(current, root)).toThrow('removed'); + } finally { + rmSync(workspace, { recursive: true, force: true }); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('actual archive/receipt/source join distinguishes changed content from fresh control/WAL entropy', async () => { + const f = await fixture('native'); + const repository = mkdtempSync(path.join(tmpdir(), 'seed-causal-source-')); + const git = (...args: string[]) => + execFileSync('git', args, { cwd: repository, encoding: 'utf8' }).trim(); + const commit = () => { + git('add', '.'); + git( + '-c', + 'user.name=Fixture', + '-c', + 'user.email=fixture@example.invalid', + 'commit', + '-qm', + 'source', + ); + return { commit: git('rev-parse', 'HEAD'), tree: git('rev-parse', 'HEAD^{tree}') }; + }; + try { + git('init', '-q'); + writeFileSync(path.join(repository, 'source.mts'), '// source'); + const originalSource = commit(); + const share = bootstrapFiles(f.root); + const oldContent = captureSeedContentIntent( + f.intent, + { contract: 'actual desired contents' }, + share, + ); + const adopted = selectCompletedSeed( + f.intent, + { ...f.control(), metadata: undefined, operation: 'adopt' }, + oldContent, + ); + writeSeedConstructionReceipt( + f.receiptPath, + f.intent, + f.frozen, + f.pgdata, + adopted?.origin, + oldContent, + ); + const contents = readFileSync(f.receiptPath, 'utf8'); + const plain = (file: string) => { + const { path: _, ...value } = identity(file); + return value; + }; + const anchor = { + schema: SEED_CONSTRUCTION_ANCHOR_SCHEMA, + source: originalSource, + publication, + seeds: [ + { + family: 'native', + target: f.intent.target, + profile: f.intent.profile, + archive: plain(f.assets.archive), + manifest: plain(f.assets.manifest), + receipt: { ...plain(f.receiptPath), contents }, + producer: { + evidenceDigest: `sha256:${'f'.repeat(64)}`, + invocationId: 'original-PR-construction', + root: '//resource:seed', + configuration: 'config', + output: 'seed.seed-construction.json', + }, + }, + ], + }; + const file = path.join(repository, seedConstructionAnchorPath); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, JSON.stringify(anchor)); + const source = commit(); + const declaration = readDeclaredSeedConstructionAnchor(source, repository)!; + writeFileSync(path.join(share, 'postgres.bki'), 'changed desired bootstrap catalog'); + const newContent = captureSeedContentIntent( + f.intent, + { contract: 'actual desired contents' }, + share, + ); + writeFileSync(path.join(f.pgdata, 'global/pg_control'), 'fresh actual control'); + writeFileSync(path.join(f.pgdata, 'pg_wal/000000010000000000000001'), 'fresh actual WAL'); + writeFileSync(f.frozen, await createDeterministicTar(f.pgdata)); + const current = await packageClusterSeed({ + family: 'native', + target: f.intent.target, + profile: 'standard', + pgdata: f.pgdata, + runtime: path.dirname(path.dirname(f.inputs.postgres)), + contract: f.invocation.contract, + version: publication.version, + runtimeVersion: '0.3.2', + outputDir: path.join(f.root, 'current-assets'), + }); + const receipt = writeSeedConstructionReceipt( + f.receiptPath, + f.intent, + f.frozen, + f.pgdata, + undefined, + newContent, + ); + const qualified = (file: string) => ({ + frozenPath: file, + label: '//resource:seed', + ...plain(file), + }); + const observation: any = { + products: [ + { + product: { id: publication.product }, + productArtifacts: [ + { + id: 'current-archive', + kind: 'native-seeds', + target: f.intent.target, + name: path.basename(current.archive), + qualifiedFiles: [qualified(current.archive)], + }, + { + id: 'current-descriptor', + kind: 'native-seeds', + target: f.intent.target, + name: path.basename(current.manifest), + qualifiedFiles: [qualified(current.manifest)], + }, + ], + construction: [ + { + roots: [{ label: '//resource:seed' }], + seedConstructions: [ + { path: 'seed.seed-construction.json', contents: JSON.stringify(receipt) }, + ], + }, + ], + }, + ], + }; + const input = { declaration, source, publication, observation, artifactId: 'current-archive' }; + expect(seedArchiveHasChangedDeclaredContents(input)).toBe(true); + const entropyOnly = writeSeedConstructionReceipt( + f.receiptPath, + f.intent, + f.frozen, + f.pgdata, + undefined, + oldContent, + ); + observation.products[0].construction[0].seedConstructions[0].contents = + JSON.stringify(entropyOnly); + expect(seedArchiveHasChangedDeclaredContents(input)).toBe(false); + expect(() => + seedArchiveHasChangedDeclaredContents({ + ...input, + publication: { ...publication, publicationSha: '1'.repeat(40) }, + }), + ).toThrow('completed origin differs'); + const wrongTree = structuredClone(entropyOnly); + wrongTree.pgdata.treeSha256 = '1'.repeat(64); + observation.products[0].construction[0].seedConstructions[0].contents = + JSON.stringify(wrongTree); + expect(() => seedArchiveHasChangedDeclaredContents(input)).toThrow('PGDATA differs'); + writeFileSync(current.archive, 'substituted physical archive'); + expect(() => seedArchiveHasChangedDeclaredContents(input)).toThrow('public File changed'); + } finally { + rmSync(f.root, { recursive: true, force: true }); + rmSync(repository, { recursive: true, force: true }); + } +}); diff --git a/tools/release/native-seed-inputs.mts b/tools/release/native-seed-inputs.mts new file mode 100644 index 000000000..dcf168a12 --- /dev/null +++ b/tools/release/native-seed-inputs.mts @@ -0,0 +1,150 @@ +/** One-way File projection from the controller's already authenticated input snapshot. */ +import assert from 'node:assert/strict'; +import path from 'node:path'; +import type { + QualifiedSeedControl, + SeedReuseControl, +} from '../../build_defs/resources/seed_construction.mts'; +import { fileIdentity } from './native-file-identity.mts'; + +type Slot = { family: 'native' | 'wasix'; target: string; profile: 'standard' | 'icu' }; +export type NativeSeedInputControl = Slot & + ( + | { reuse: SeedReuseControl; promotion?: never } + | { promotion: QualifiedSeedControl; reuse?: never } + ); +const fields = (value: unknown, names: string[], context: string) => { + assert.ok( + value && typeof value === 'object' && !Array.isArray(value), + `${context} needs an object`, + ); + assert.deepEqual(Object.keys(value).sort(), [...names].sort(), `${context} fields differ`); +}; +const source = (value: { commit: string; tree: string }) => { + fields(value, ['commit', 'tree'], 'seed input source'); + for (const sha of [value.commit, value.tree]) assert.match(sha, /^[a-f0-9]{40}$/u); +}; + +/** Source provenance remains a controller check; names never grant readiness. */ +export function projectNativeSeedInputs( + value: unknown, + currentSource?: { commit: string; tree: string }, +) { + assert.ok(Array.isArray(value), 'native seed controls need an array'); + if (currentSource) source(currentSource); + const controls: Record> = {}; + const files = new Map(); + for (const raw of value as NativeSeedInputControl[]) { + const operation = raw.promotion ? 'promotion' : 'reuse'; + fields(raw, ['family', 'target', 'profile', operation], 'native seed control'); + assert.ok(['native', 'wasix'].includes(raw.family)); + assert.ok(['standard', 'icu'].includes(raw.profile)); + assert.match(raw.target, /^[a-z0-9][a-z0-9_-]*$/u); + assert.ok( + raw.family !== 'wasix' || raw.target === 'portable', + 'WASIX seed target must be portable', + ); + const key = `${raw.family}/${raw.target}/${raw.profile}`; + assert.ok(!controls[key], 'duplicate native seed control slot'); + const attributes: Record = {}; + const alias = (file: { path: string; size: number; sha256: string }) => { + fields(file, ['path', 'size', 'sha256'], 'native seed File'); + assert.ok( + path.isAbsolute(file.path), + 'native seed snapshot must name an absolute frozen File', + ); + const actual = fileIdentity(file.path); + assert.deepEqual( + { size: actual.size, sha256: actual.sha256 }, + { size: file.size, sha256: file.sha256 }, + 'native seed snapshot File bytes differ', + ); + assert.match( + path.basename(file.path), + /^[A-Za-z0-9][A-Za-z0-9._-]*$/u, + 'seed File basename is unsafe', + ); + const output = `seed-inputs/${file.sha256}/${path.basename(file.path)}`; + const prior = files.get(output); + if (prior) + assert.deepEqual( + prior, + { source: file.path, path: output, size: file.size, sha256: file.sha256 }, + 'seed File alias is ambiguous', + ); + else + files.set(output, { + source: file.path, + path: output, + size: file.size, + sha256: file.sha256, + }); + return `@oliphaunt_metadata//:${output}`; + }; + if (operation === 'promotion') { + const promotion = raw.promotion; + assert.ok(promotion); + fields( + promotion, + ['source', 'evidenceDigest', 'invocationId', 'frozen', 'receipt', 'transition'], + 'qualified seed control', + ); + source(promotion.source); + fields(promotion.transition, ['source', 'updatesSha256'], 'seed version transition'); + source(promotion.transition.source); + if (currentSource) + assert.deepEqual( + promotion.transition.source, + currentSource, + 'seed promotion target source differs', + ); + assert.match(promotion.evidenceDigest, /^sha256:[a-f0-9]{64}$/u); + assert.ok(typeof promotion.invocationId === 'string' && promotion.invocationId.length > 0); + assert.match(promotion.transition.updatesSha256, /^[a-f0-9]{64}$/u); + attributes.qualified_frozen = alias(promotion.frozen); + attributes.qualified_receipt = alias(promotion.receipt); + attributes.promotion_control = JSON.stringify(promotion); + } else { + const reuse = raw.reuse; + assert.ok(reuse); + fields( + reuse, + [ + 'operation', + 'publication', + 'archive', + 'manifest', + ...(reuse.metadata ? ['metadata'] : []), + ...(reuse.anchor ? ['anchor'] : []), + ], + 'completed seed control', + ); + assert.ok(['reuse', 'adopt'].includes(reuse.operation)); + const publication = reuse.publication; + fields( + publication, + ['product', 'version', 'tagName', 'publicationSha', 'publicationTree', 'releaseSha'], + 'completed seed publication', + ); + assert.equal(publication.product, 'database-resources'); + assert.match(publication.version, /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/u); + assert.equal(publication.tagName, `${publication.product}-v${publication.version}`); + for (const sha of [ + publication.publicationSha, + publication.publicationTree, + publication.releaseSha, + ]) + assert.match(sha, /^[a-f0-9]{40}$/u); + attributes.completed_archive = alias(reuse.archive); + attributes.completed_manifest = alias(reuse.manifest); + if (reuse.metadata) attributes.completed_metadata = alias(reuse.metadata); + if (reuse.anchor) attributes.completed_anchor = alias(reuse.anchor); + attributes.reuse_control = JSON.stringify(reuse); + } + controls[key] = attributes; + } + return { + controls, + files: [...files.values()].sort((left, right) => left.path.localeCompare(right.path)), + }; +} diff --git a/tools/release/native-seed-inputs.test.mts b/tools/release/native-seed-inputs.test.mts new file mode 100644 index 000000000..fba0c86d9 --- /dev/null +++ b/tools/release/native-seed-inputs.test.mts @@ -0,0 +1,181 @@ +import { expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { seedCarrierIdentities } from '../../src/database-resources/seeds/carrier-identities.mts'; +import { projectNativeSeedInputs } from './native-seed-inputs.mts'; + +const publication = { + product: 'database-resources', + version: '0.2.2', + tagName: 'database-resources-v0.2.2', + publicationSha: 'a'.repeat(40), + publicationTree: 'b'.repeat(40), + releaseSha: 'c'.repeat(40), +}; +const source = { commit: 'd'.repeat(40), tree: 'e'.repeat(40) }; +function fixture() { + const root = mkdtempSync(path.join(tmpdir(), 'seed-input-projection-')); + const file = (name: string, contents: string) => { + const destination = path.join(root, name); + writeFileSync(destination, contents); + const bytes = readFileSync(destination); + return { + path: destination, + size: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + }; + }; + const archive = file('seed.tar.zst', 'opaque verified archive File fixture'); + const manifest = file('seed.json', 'opaque verified descriptor File fixture'); + const metadata = file('construction.json', 'opaque verified completed metadata File fixture'); + return { root, archive, manifest, metadata }; +} + +test('empty native input snapshot preserves construction defaults and grants no public origin', () => { + expect(projectNativeSeedInputs([])).toEqual({ controls: {}, files: [] }); +}); + +test('public seed slots and concrete Android constructor slots project without renaming', () => { + const f = fixture(); + try { + const slots = [ + ...seedCarrierIdentities(), + ...['standard', 'icu'].map((profile) => ({ + family: 'native', + target: 'android-x86_64', + profile, + })), + ].map(({ family, target, profile }) => ({ family, target, profile })); + const reuse = { + operation: 'reuse', + publication, + archive: f.archive, + manifest: f.manifest, + metadata: f.metadata, + }; + const promotion = { + source, + evidenceDigest: `sha256:${'3'.repeat(64)}`, + invocationId: 'original-android-constructor', + frozen: f.archive, + receipt: f.metadata, + transition: { source, updatesSha256: '4'.repeat(64) }, + }; + for (const operation of [{ reuse }, { promotion }]) { + const projected = projectNativeSeedInputs( + slots.map((slot) => ({ ...slot, ...operation })), + source, + ); + expect(Object.keys(projected.controls)).toEqual( + slots.map(({ family, target, profile }) => `${family}/${target}/${profile}`), + ); + for (const profile of ['standard', 'icu']) { + const control = projected.controls[`native/android-x86_64/${profile}`]; + expect(JSON.parse(control.reuse_control ?? control.promotion_control)).toEqual( + 'reuse' in operation ? reuse : promotion, + ); + } + } + for (const target of [ + '', + '../android-x86_64', + 'android/x86_64', + 'android\\x86_64', + 'android x86_64', + ]) + expect(() => + projectNativeSeedInputs([{ family: 'native', target, profile: 'standard', reuse }]), + ).toThrow(); + expect(() => + projectNativeSeedInputs([ + { family: 'wasix', target: 'android-x86_64', profile: 'standard', reuse }, + ]), + ).toThrow('WASIX seed target must be portable'); + } finally { + rmSync(f.root, { recursive: true, force: true }); + } +}); + +test('one per-run completed snapshot projects exact File identities and deduplicates shared metadata', () => { + const f = fixture(); + try { + const reuse = { + operation: 'reuse' as const, + publication, + archive: f.archive, + manifest: f.manifest, + metadata: f.metadata, + }; + const rows = [ + { family: 'native' as const, target: 'linux-x64-gnu', profile: 'standard' as const, reuse }, + { family: 'wasix' as const, target: 'portable', profile: 'icu' as const, reuse }, + ]; + const projected = projectNativeSeedInputs(rows, source); + expect(Object.keys(projected.controls)).toEqual([ + 'native/linux-x64-gnu/standard', + 'wasix/portable/icu', + ]); + expect(projected.files).toHaveLength(3); + expect(projected.controls['native/linux-x64-gnu/standard'].completed_metadata).toBe( + projected.controls['wasix/portable/icu'].completed_metadata, + ); + expect(projected.controls['native/linux-x64-gnu/standard']).not.toHaveProperty('ready'); + expect(JSON.parse(projected.controls['native/linux-x64-gnu/standard'].reuse_control)).toEqual( + reuse, + ); + expect(() => projectNativeSeedInputs([rows[0], rows[0]], source)).toThrow( + 'duplicate native seed control slot', + ); + expect(() => projectNativeSeedInputs([{ ...rows[0], ready: true }], source)).toThrow( + 'fields differ', + ); + writeFileSync(f.archive.path, 'altered mutable transport'); + expect(() => projectNativeSeedInputs(rows, source)).toThrow('snapshot File bytes differ'); + } finally { + rmSync(f.root, { recursive: true, force: true }); + } +}); + +test('qualified seed projection binds exact final source and preserves original evidence', () => { + const f = fixture(); + try { + const promotion = { + source: { commit: '1'.repeat(40), tree: '2'.repeat(40) }, + evidenceDigest: `sha256:${'3'.repeat(64)}`, + invocationId: 'original-invocation', + frozen: f.archive, + receipt: f.metadata, + transition: { source, updatesSha256: '4'.repeat(64) }, + }; + const row = { family: 'native', target: 'linux-x64-gnu', profile: 'standard', promotion }; + const projected = projectNativeSeedInputs([row], source); + const attrs = projected.controls['native/linux-x64-gnu/standard']; + expect(JSON.parse(attrs.promotion_control)).toEqual(promotion); + expect(attrs).not.toHaveProperty('completed_archive'); + expect(projected.files).toHaveLength(2); + expect(() => projectNativeSeedInputs([row], { ...source, commit: '5'.repeat(40) })).toThrow( + 'target source differs', + ); + expect(() => + projectNativeSeedInputs( + [{ ...row, promotion: { ...promotion, evidenceDigest: 'unverified' } }], + source, + ), + ).toThrow(); + expect(() => + projectNativeSeedInputs( + [ + { + ...row, + promotion: { ...promotion, frozen: { ...promotion.frozen, path: 'relative.tar' } }, + }, + ], + source, + ), + ).toThrow('absolute frozen File'); + } finally { + rmSync(f.root, { recursive: true, force: true }); + } +}); diff --git a/tools/release/native-shipping-suppliers.mts b/tools/release/native-shipping-suppliers.mts new file mode 100644 index 000000000..6a1b4f1a2 --- /dev/null +++ b/tools/release/native-shipping-suppliers.mts @@ -0,0 +1,547 @@ +/** Typed configured supplier Files; this projection cannot admit a publication. */ + +import path from 'node:path'; +import { + buildShippingInputView, + canonicalShippingLabel, + isNativeAppleBaseInputRoot, + type NativeShippingSupplier, + validateNativeShippingSuppliers, +} from './bazel-shipping-inputs.mts'; +import type { NativeBuildSource } from './native-build-qualification.mts'; +import { + captureCompletedNativePublicArtifacts, + captureCompletedNativeRegistryCarriers, + captureCompletedNativeSwiftSourceSuppliers, + nativeArchiveDeliveryMembers, +} from './native-completed-delivery.mts'; +import { fileIdentity } from './native-file-identity.mts'; +import { captureCompletedNativeArchiveDelivery } from './native-publication-delivery.mts'; +import type { observeNativePublicationConstruction } from './native-publication-observation.mts'; +import { consumerDigest } from './publication-consumer-proof.mts'; +import { resolveBuildBoundCompatibilityProducts } from './release-dependency-plan.mts'; + +export type { NativeShippingSupplier } from './bazel-shipping-inputs.mts'; + +type Observation = Awaited>; +type CompletedInput = + | Parameters[0] + | Parameters[0] + | Parameters[0] + | Parameters[0]; +const authenticateCompletedSupplier = (input: CompletedInput) => + 'sourceTags' in input + ? captureCompletedNativeSwiftSourceSuppliers(input) + : 'carriers' in input + ? captureCompletedNativeRegistryCarriers(input) + : Array.isArray(input.files) + ? captureCompletedNativeArchiveDelivery( + input as Parameters[0], + ) + : captureCompletedNativePublicArtifacts( + input as Parameters[0], + ); + +/** Only these canonical original Swift documents are data/ABI construction inputs. */ +function swiftSourceDocument(root, member: string | undefined) { + const pkg = root.package; + if ( + pkg.product !== 'oliphaunt-swift' || + pkg.ecosystem !== 'github' || + pkg.role !== 'release-input' || + pkg.configuration !== 'portable' || + pkg.outputs.length !== 1 || + !pkg.outputs[0].path.startsWith('bazel-out/') + ) + return false; + const name = canonicalShippingLabel(root.label); + return ( + (name === '//src/native/sdks/swift:shipping_oliphaunt-react-native-ios-carriers_json' && + pkg.name === 'oliphaunt-react-native-ios-carriers.json' && + pkg.outputs[0].path.endsWith('/source_package/release-tree') && + member === 'src/sdks/swift/Carriers/oliphaunt-react-native-ios-carriers.json') || + (name === '//src/native/sdks/swift:shipping_extension-owner-catalog_json' && + pkg.name === 'extension-owner-catalog.json' && + pkg.outputs[0].path.endsWith( + '/source_package/extension-generator/extension-owner-catalog.json', + ) && + member === undefined) + ); +} + +function swiftSourceArchive(root, member: string | undefined) { + const pkg = root.package; + return ( + canonicalShippingLabel(root.label) === + '//src/native/sdks/swift:shipping_Oliphaunt-source_zip' && + pkg.product === 'oliphaunt-swift' && + pkg.ecosystem === 'github' && + pkg.role === 'release-input' && + pkg.configuration === 'portable' && + pkg.name === 'Oliphaunt-source.zip' && + member === undefined && + pkg.outputs.length === 1 && + pkg.outputs[0].path.startsWith('bazel-out/') && + pkg.outputs[0].path.endsWith('/source_package/Oliphaunt-source.zip') + ); +} + +function equal(actual: unknown, expected: unknown, context: string) { + if (consumerDigest(actual) !== consumerDigest(expected)) + throw new Error(`native suppliers: ${context} mismatch`); +} +function exactSource(source: NativeBuildSource) { + if ( + !source || + Object.keys(source).sort().join(',') !== 'commit,tree' || + ![source.commit, source.tree].every((value) => /^[a-f0-9]{40}$/u.test(value)) + ) + throw new Error('native suppliers require an exact source commit and tree'); +} + +/** + * Consume an existing authenticated observation, never raw aquery as authority. + * Each package explicitly reports its supplier Files through the producing + * ShippingInfo manifest. Missing coverage returns no map. A completed supplier + * is independently reauthenticated using the retained archive/completion reader; + * historical labels or actions are neither required nor invented. + * + * This is a structural construction projection. The existing native admission + * guard and complete product-specific qualification policy remain external. + */ +export async function projectNativeBuildBoundSuppliers( + { + products, + source, + observation, + completed = [], + }: { + products: Record; + source: NativeBuildSource; + observation: Observation; + completed?: CompletedInput[]; + }, + { authenticateCompleted = authenticateCompletedSupplier } = {}, +) { + exactSource(source); + const ids = Object.keys(products).sort(); + if (!ids.length) throw new Error('native suppliers require explicit product inventory'); + equal( + observation.products.map(({ product }) => product.id).sort(), + ids, + 'observed product inventory', + ); + const unknowns = new Set(); + if (!observation.coverage.completeProductInventory) + unknowns.add('incomplete configured product inventory'); + if (!observation.authenticated.length) unknowns.add('missing authenticated producing builds'); + const covered = new Set(); + const records: (NativeShippingSupplier & { + consumer: string; + root: string; + consumerConfiguration: string; + rootConfiguration: string; + })[] = []; + const pending: { + supplier: NativeShippingSupplier; + files: { declaration: NativeShippingSupplier['files'][number]; member: any }[]; + }[] = []; + const imported: typeof pending = []; + for (const build of observation.authenticated) { + equal(build.evidence.source, source, 'producing evidence source'); + equal(build.qualification.source, source, 'qualified source'); + equal(build.origin.github, build.qualification.github, 'authenticated producing context'); + if ( + build.qualification.testQualification !== 'passed' || + !build.qualification.requiredTests.length || + build.qualification.shippingAnalysis !== 'bound' + ) + unknowns.add('unbound producing analysis or configured qualification'); + for (const cohort of build.evidence.cohorts) { + const rootConfigurations = new Map( + cohort.rootConfigurations.map(({ label, configuration }) => [ + canonicalShippingLabel(label), + configuration, + ]), + ); + const captures = new Map(cohort.inputs.map((capture) => [capture.path, capture])); + const roots = new Map(cohort.roots.map((root) => [root.package, root])); + const producerRoots: { + product: string; + configuration: string; + outputs: Set; + consumes: (path: string) => boolean; + }[] = []; + const currentSuppliers: NativeShippingSupplier[] = []; + buildShippingInputView( + { + schema: 'oliphaunt-bazel-shipping-v1', + scope: 'construction', + packages: cohort.roots.map((root) => root.package), + }, + cohort.aquery, + { + inspectPackageInputs(pkg, consumes) { + const root = roots.get(pkg as any)!; + const consumer = root.package.product; + const label = canonicalShippingLabel(root.label); + if (!Object.hasOwn(products, consumer) || !rootConfigurations.has(label)) + throw new Error('native supplier root has unknown product/configuration'); + equal(root.package.version, products[consumer].version, 'consumer version'); + covered.add(consumer); + // Candidate control/metadata Files are not the core's delivery roots. + if ( + !isNativeAppleBaseInputRoot(root) && + root.package.role !== 'release-input' && + (root.package.ecosystem !== 'github' || root.package.role === 'github-release-asset') + ) + producerRoots.push({ + product: consumer, + configuration: root.package.configuration, + outputs: new Set(root.package.outputs.map(({ path }) => path)), + consumes, + }); + const supplied = (pkg as any).supplierInputs; + if (supplied === undefined) { + unknowns.add(`missing supplier coverage: ${label}@${rootConfigurations.get(label)}`); + return; + } + if (!Array.isArray(supplied)) + throw new Error('native supplier coverage must be an explicit array'); + for (const supplier of validateNativeShippingSuppliers(supplied)) { + if (!Object.hasOwn(products, supplier.product)) + throw new Error('native supplier has unknown product'); + const files = supplier.files.map((declaration) => { + const name = declaration.path; + if (!consumes(name)) + throw new Error(`native supplier File is not consumed by ${label}: ${name}`); + const capture = captures.get(name); + const member = capture?.members[0]; + if ( + capture?.members.length !== 1 || + member?.path !== '' || + member.type !== 'file' || + !/^[a-f0-9]{64}$/u.test(member.sha256) || + !Number.isSafeInteger(member.size) || + member.size < 0 + ) + throw new Error('native supplier must be an exact captured regular File'); + return { declaration, member: structuredClone(member) }; + }); + if (supplier.origin?.kind === 'current-source') { + // Current Files belong to the authenticated producing cohort. + // Putting its Git SHA in analysis metadata would add a false input. + equal( + supplier.version, + products[supplier.product].version, + 'current supplier version', + ); + if (supplier.origin.producer) imported.push({ supplier, files }); + else if (supplier.binding === 'compiled-input') + for (const { path } of supplier.files) + if (path.startsWith('external/')) + unknowns.add('unverified current supplier producer transport'); + else if (!path.startsWith('bazel-out/')) + throw new Error( + 'current compiled supplier requires an actual generated File', + ); + currentSuppliers.push(supplier); + } else if (supplier.origin?.kind === 'completed-publication') { + pending.push({ supplier, files }); + } else throw new Error('native supplier requires an explicit physical origin'); + records.push({ + ...supplier, + consumer, + root: label, + consumerConfiguration: root.package.configuration, + rootConfiguration: rootConfigurations.get(label)!, + }); + } + }, + }, + ); + for (const supplier of currentSuppliers) { + if (supplier.origin.kind === 'current-source' && supplier.origin.producer) continue; + const configured = producerRoots.filter( + (root) => + root.product === supplier.product && root.configuration === supplier.configuration, + ); + for (const file of supplier.files) { + if (supplier.binding === 'compiled-input' && file.path.startsWith('external/')) continue; + if (!configured.length) + throw new Error('current supplier lacks its own configured shipping producer'); + if ( + supplier.binding === 'compiled-input' && + !configured.some((root) => root.outputs.has(file.path) || root.consumes(file.path)) + ) + throw new Error('current supplier File lacks its own configured shipping producer'); + } + } + } + } + for (const id of ids) if (!covered.has(id)) unknowns.add(`missing configured consumer: ${id}`); + for (const { supplier, files } of imported) { + if (supplier.origin.kind !== 'current-source' || !supplier.origin.producer) continue; + const producer = supplier.origin.producer; + const builds = observation.authenticated.filter( + ({ origin }) => origin.evidenceDigest === producer.evidenceDigest, + ); + if (!builds.length) { + unknowns.add('missing authenticated original current supplier producer'); + continue; + } + if (builds.length !== 1) throw new Error('ambiguous original current supplier producer'); + const original = builds[0]; + const cohorts = original.evidence.cohorts + .map((cohort, index) => ({ cohort, index })) + .filter( + ({ index }) => + original.qualification.cohorts?.[index]?.invocationId === producer.invocationId, + ); + if (cohorts.length !== 1) throw new Error('current supplier original invocation mismatch'); + const { cohort, index } = cohorts[0]; + const roots = cohort.roots.filter( + ({ label }) => canonicalShippingLabel(label) === canonicalShippingLabel(producer.root), + ); + if (roots.length !== 1) throw new Error('current supplier original root mismatch'); + const root = roots[0]; + const configurations = cohort.rootConfigurations.filter( + ({ label }) => canonicalShippingLabel(label) === canonicalShippingLabel(root.label), + ); + if (configurations.length !== 1 || configurations[0].configuration !== producer.configuration) + throw new Error('current supplier original configured root mismatch'); + equal( + { + product: root.package.product, + version: root.package.version, + configuration: root.package.configuration, + }, + { + product: supplier.product, + version: supplier.version, + configuration: supplier.configuration, + }, + 'original current supplier identity', + ); + const appleBase = isNativeAppleBaseInputRoot(root); + const document = appleBase || swiftSourceDocument(root, producer.member); + const sourceArchive = swiftSourceArchive(root, producer.member); + const dataInput = document || sourceArchive; + if ( + (canonicalShippingLabel(root.label) === + '//src/native/sdks/swift:shipping_Oliphaunt-source_zip' && + !sourceArchive) || + (!dataInput && + (!['cargo', 'npm', 'github'].includes(root.package.ecosystem) || + (root.package.ecosystem === 'github' && root.package.role !== 'github-release-asset'))) || + (dataInput && + (supplier.binding !== 'abi-contract' || + (appleBase && producer.member !== undefined) || + files.some(({ declaration }) => declaration.member !== undefined))) || + root.package.outputs.filter(({ path }) => path === producer.output).length !== 1 + ) + throw new Error('current supplier requires its original public final archive'); + const outputs = cohort.outputs.filter(({ path }) => path === producer.output); + const outputRoot = outputs[0]?.members[0]; + const membersAtPath = + producer.member === undefined + ? outputs[0]?.members + : outputs[0]?.members.filter(({ path }) => path === producer.member); + const output = membersAtPath?.[0]; + if ( + outputs.length !== 1 || + membersAtPath?.length !== 1 || + output?.type !== 'file' || + (producer.member === undefined + ? output.path !== '' + : outputRoot?.path !== '' || outputRoot.type !== 'directory') + ) + throw new Error('current supplier original output must be a captured regular archive'); + if ( + producer.member !== undefined && + root.package.ecosystem === 'github' && + path.posix.basename(producer.member) !== root.package.name + ) + throw new Error( + 'current supplier original Tree leaf differs from its canonical GitHub identity', + ); + const outputPath = + producer.member === undefined ? producer.output : `${producer.output}/${producer.member}`; + const transport = original.origin.finalFiles; + if (!transport || !('artifactRoots' in transport)) { + unknowns.add('missing authenticated original current supplier transport'); + continue; + } + const captured = transport.files.filter( + (file) => file.cohort === index && file.path === outputPath, + ); + if (captured.length !== 1) + throw new Error('current supplier original transported output mismatch'); + equal( + { size: captured[0].size, sha256: captured[0].sha256 }, + { size: output.size, sha256: output.sha256 }, + 'original current supplier output bytes', + ); + const suffix = `/${index}/${outputPath}`; + const archives = transport.artifactRoots.filter((file) => + path.resolve(file).split(path.sep).join('/').endsWith(suffix), + ); + if (archives.length !== 1) + throw new Error('current supplier original archive transport mismatch'); + transport.assertUnchanged?.(); + const before = fileIdentity(archives[0]); + equal( + { size: before.size, sha256: before.sha256 }, + { size: output.size, sha256: output.sha256 }, + 'original current supplier physical archive', + ); + const members = document ? [] : nativeArchiveDeliveryMembers(archives[0]); + equal(fileIdentity(archives[0]), before, 'original current supplier archive after read'); + transport.assertUnchanged?.(); + for (const { declaration, member } of files) { + if (declaration.member === undefined) { + equal( + { sha256: member.sha256, size: member.size }, + { sha256: output.sha256, size: output.size }, + 'captured supplier/original current outer archive bytes', + ); + continue; + } + const published = members.filter((value) => value.path === declaration.member); + if (published.length !== 1 || published[0].type !== 'file') + throw new Error('current supplier requires its exact original regular archive member'); + equal( + { sha256: member.sha256, size: member.size }, + { sha256: published[0].sha256, size: published[0].size }, + 'captured supplier/original current member bytes', + ); + } + } + const origins = new Map>(); + for (const { supplier, files } of pending) { + if (supplier.origin.kind !== 'completed-publication') continue; + const publication = supplier.origin.publication; + const matches = completed.filter((input) => { + if (consumerDigest(input.publication) !== consumerDigest(publication)) return false; + const artifact = supplier.origin.artifact; + if ( + 'sourceTags' in input && + input.sourceTags.some( + (row) => + row.artifact === artifact && + consumerDigest(row.publication) === consumerDigest(publication), + ) + ) + return true; + if ('carriers' in input && input.carriers && Object.hasOwn(input.carriers, artifact)) + return true; + if (!('files' in input)) return false; + if (!Array.isArray(input.files)) + return ( + Object.hasOwn(input.files, artifact) || + Object.hasOwn(input.files, `github-release:${artifact}`) + ); + return input.files.some( + ({ target, file }) => + target === supplier.configuration && + [path.basename(file), `github-release:${path.basename(file)}`].includes(artifact), + ); + }); + if (matches.length > 1) throw new Error('ambiguous completed supplier archive input'); + if (!matches.length) { + unknowns.add(`missing completed supplier bytes: ${supplier.product}@${supplier.version}`); + continue; + } + if ( + 'files' in matches[0] && + Array.isArray(matches[0].files) && + !['liboliphaunt-native', 'postgres-tools-native'].includes(supplier.product) + ) { + unknowns.add(`unsupported completed supplier contract: ${supplier.product}`); + continue; + } + const original = matches[0]; + if (!origins.has(original)) { + // The authenticated metadata capability is tied to its original object. + // Clone structural facts without manufacturing a replacement capability. + let snapshot: CompletedInput; + if ('metadataBaseline' in original) { + const { metadataBaseline, ...facts } = original; + snapshot = { ...structuredClone(facts), metadataBaseline }; + } else snapshot = structuredClone(original); + origins.set(original, authenticateCompleted(snapshot)); + } + const origin = await origins.get(original)!; + equal(origin.publication, publication, 'authenticated completed supplier'); + if ('unknowns' in origin) + // Unconsumed target Files are not required for this supplier binding. + // A historical declaration/inventory mismatch remains genuinely unknown. + for (const unknown of origin.unknowns) + if (!unknown.startsWith('completed-public-artifact-missing:')) + unknowns.add(`completed supplier origin: ${unknown}`); + const archives = origin.archives.filter( + (archive) => + (archive.id === supplier.origin.artifact || archive.name === supplier.origin.artifact) && + archive.target === supplier.configuration, + ); + if (archives.length !== 1) + throw new Error('completed supplier requires its exact configured public archive'); + for (const { declaration, member } of files) { + if (declaration.member === undefined) { + const archive = archives[0]; + const identity = + archive.size !== undefined && archive.sha256 !== undefined + ? { size: archive.size, sha256: archive.sha256 } + : archive.artifacts?.length === 1 + ? { size: archive.artifacts[0].size, sha256: archive.artifacts[0].sha256 } + : undefined; + if (!identity) + throw new Error('whole archive supplier requires its authenticated outer bytes'); + equal( + { size: member.size, sha256: member.sha256 }, + identity, + 'captured supplier/published outer archive bytes', + ); + continue; + } + const published = archives[0].members.filter((row) => row.path === declaration.member); + if (published.length !== 1 || published[0].type !== 'file') + throw new Error('completed supplier requires its exact regular archive member'); + equal( + { sha256: member.sha256, size: member.size }, + { sha256: published[0].sha256, size: published[0].size }, + 'captured supplier/published member bytes', + ); + } + } + const buildBound = new Map(ids.map((id) => [id, new Set()])); + const decisions = new Map(); + for (const supplier of records) { + if (supplier.binding !== 'compiled-input' || supplier.product === supplier.consumer) continue; + const key = `${supplier.consumer}:${supplier.product}`; + const decision = consumerDigest({ + version: supplier.version, + origin: + supplier.origin.kind === 'current-source' + ? { kind: 'current-source' } + : { kind: supplier.origin.kind, publication: supplier.origin.publication }, + }); + const previous = decisions.get(key); + // The existing conventional compatibility field applies to the entire + // product; this Map cannot truthfully retarget only some configurations. + if (previous && previous !== decision) + throw new Error('conflicting current/held compiled suppliers across consumer configurations'); + decisions.set(key, decision); + if (supplier.origin.kind === 'current-source') + buildBound.get(supplier.consumer)!.add(supplier.product); + } + return { + scope: 'construction' as const, + source: structuredClone(source), + suppliers: records, + unknowns: [...unknowns].sort(), + buildBound: unknowns.size + ? undefined + : resolveBuildBoundCompatibilityProducts(products, { buildBound }), + }; +} diff --git a/tools/release/native-shipping-suppliers.test.mts b/tools/release/native-shipping-suppliers.test.mts new file mode 100644 index 000000000..efa3f9b8c --- /dev/null +++ b/tools/release/native-shipping-suppliers.test.mts @@ -0,0 +1,1553 @@ +import { expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { archiveDirectory } from '../packaging/archive-directory.mts'; +import { readPortableArchiveEntries } from '../packaging/portable-archive.mts'; +import { buildShippingInputView } from './bazel-shipping-inputs.mts'; +import { createCompletedPublicationChecker } from './completed-release-publication.mts'; +import { validateReleaseConsumerCompatibility } from './consumer-compatibility.mts'; +import { defaultExtensionReleasePlan } from './default-extension-release-plan.mts'; +import { + captureCompletedNativePublicArtifacts, + captureCompletedNativeRegistryCarriers, + nativeArchiveDeliveryMembers, +} from './native-completed-delivery.mts'; +import { captureCompletedNativeArchiveDelivery } from './native-publication-delivery.mts'; +import { + captureNativeInputMembers, + captureNativeOutputMembers, +} from './native-publication-staging.mts'; +import { + type NativeShippingSupplier, + projectNativeBuildBoundSuppliers, +} from './native-shipping-suppliers.mts'; +import { loadPublicationCatalog } from './publication-catalog.mts'; +import { expectedProductArtifactRows } from './publication-lock.mts'; +import { ROOT } from './release-graph.mts'; + +const source = { commit: 'a'.repeat(40), tree: 'b'.repeat(40) }; +const github = { + repository: 'f0rr0/oliphaunt', + workflow: 'Native Bazel qualification', + workflowPath: '.github/workflows/bazel.yml', + runId: 123, + runAttempt: 1, + job: 'Linux runtime', +}; +const product = 'liboliphaunt-native'; +const consumer = 'fixture-extension'; +const version = '0.3.3'; +const configuration = 'linux-x64-gnu'; +const currentFile = 'bazel-out/cfg/bin/runtime/liboliphaunt.so'; +const heldFile = 'external/held/lib/liboliphaunt.so'; +const header = 'external/postgres/pg_config.h'; +const publication = { + product, + version, + tagName: `${product}-v${version}`, + publicationSha: 'c'.repeat(40), + publicationTree: 'd'.repeat(40), + releaseSha: 'e'.repeat(40), +}; +const artifact = `liboliphaunt-${version}-${configuration}.tar.gz`; +const products = { + [product]: { version }, + [consumer]: { version: '1.0.0' }, + 'fixture-source': { version: '2.0.0' }, +}; +function current(binding: NativeShippingSupplier['binding'] = 'compiled-input') { + return { + product, + version, + configuration, + binding, + origin: { kind: 'current-source' as const }, + files: [{ path: binding === 'abi-contract' ? header : currentFile }], + }; +} +function held() { + return { + product, + version, + configuration, + binding: 'compiled-input' as const, + origin: { + kind: 'completed-publication' as const, + publication: structuredClone(publication), + artifact, + }, + files: [{ path: heldFile, member: 'lib/liboliphaunt.so' }], + }; +} + +async function fixture(run, mode = 'current', targets = [configuration]) { + const executionRoot = mkdtempSync(path.join(os.tmpdir(), 'native-supplier-files-')); + try { + const write = (name, contents) => { + mkdirSync(path.dirname(path.join(executionRoot, name)), { recursive: true }); + writeFileSync(path.join(executionRoot, name), contents); + }; + write(currentFile, 'current runtime bytes'); + write(heldFile, 'authentic fixture published runtime bytes'); + write(header, '#define POSTGRES_ABI 18\n'); + write('runtime/source.c', 'current source'); + write('source/README.md', 'public source docs'); + const layouts = [ + { label: '//runtime:library', output: currentFile, inputs: ['runtime/source.c'] }, + { + label: '//extensions:server', + output: 'bazel-out/cfg/bin/extensions/server.so', + inputs: [header], + }, + { + label: '//extensions:embedded', + output: 'bazel-out/cfg/bin/extensions/embedded.so', + inputs: [mode === 'held' ? heldFile : currentFile, header], + }, + { + label: '//source:archive', + output: 'bazel-out/cfg/bin/source/source.crate', + inputs: ['source/README.md'], + }, + ]; + for (const row of layouts.slice(1)) write(row.output, `built ${row.label}`); + const files = [...new Set(layouts.flatMap((row) => [row.output, ...row.inputs]))]; + const aquery = { + pathFragments: files.flatMap((name, i) => + name.split('/').map((label, segment) => ({ + id: `${i}-${segment}`, + label, + ...(segment ? { parentId: `${i}-${segment - 1}` } : {}), + })), + ), + artifacts: files.map((name, i) => ({ + id: i + 1, + pathFragmentId: `${i}-${name.split('/').length - 1}`, + })), + targets: layouts.map(({ label }, i) => ({ id: i + 1, label })), + configuration: [{ id: 1, checksum: 'f'.repeat(64) }], + depSetOfFiles: layouts.map(({ inputs }, i) => ({ + id: i + 1, + directArtifactIds: inputs.map((name) => files.indexOf(name) + 1), + })), + actions: layouts.map(({ output }, i) => ({ + targetId: i + 1, + configurationId: 1, + actionKey: `fixture-action-${i}`, + mnemonic: 'FixtureProducer', + inputDepSetIds: [i + 1], + outputIds: [files.indexOf(output) + 1], + primaryOutputId: files.indexOf(output) + 1, + })), + }; + const roots = layouts.map(({ label, output }, i) => ({ + label: `${label}_shipping`, + package: { + product: i === 0 ? product : i === 3 ? 'fixture-source' : consumer, + version: i === 0 ? version : i === 3 ? '2.0.0' : '1.0.0', + ecosystem: 'internal', + name: label, + configuration, + role: 'construction', + outputs: [{ path: output, owner: label }], + supplierInputs: + i === 1 + ? [current('abi-contract')] + : i === 2 + ? [mode === 'held' ? held() : current()] + : [], + }, + })); + const view = buildShippingInputView( + { + schema: 'oliphaunt-bazel-shipping-v1', + scope: 'construction', + packages: roots.map((root) => root.package), + }, + aquery, + ); + const cohort = { + executionRoot, + roots, + rootConfigurations: roots.map(({ label }) => ({ label, configuration: 'f'.repeat(64) })), + aquery, + inputs: view.physicalInputs.map((name) => ({ + path: name, + members: captureNativeInputMembers(executionRoot, name).members, + })), + outputs: [], + buildEvents: [], + }; + // This controlled transport fixture supplies the observer's documented + // precondition. It makes no real GitHub/build qualification assertion. + const observation = { + products: Object.entries(products).map(([id, metadata]) => ({ + product: { id, ...metadata }, + })), + coverage: { completeProductInventory: true }, + authenticated: [ + { + evidence: { source: structuredClone(source), github, cohorts: [cohort] }, + origin: { github }, + qualification: { + source: structuredClone(source), + github, + shippingAnalysis: 'bound', + testQualification: 'passed', + requiredTests: [{ label: '//fixture:test', configuration: 'f'.repeat(64) }], + }, + }, + ], + }; + const published = path.join(executionRoot, 'published'); + mkdirSync(path.join(published, 'lib'), { recursive: true }); + writeFileSync( + path.join(published, 'lib/liboliphaunt.so'), + readFileSync(path.join(executionRoot, heldFile)), + ); + const archives = []; + for (const target of targets) { + const name = `liboliphaunt-${version}-${target}.tar.gz`; + const file = path.join(executionRoot, name); + await archiveDirectory(published, file); + archives.push({ name, target, file, bytes: readFileSync(file) }); + } + let reads = 0; + const authenticateCompleted = (input) => + captureCompletedNativeArchiveDelivery(input, { + assertCompletedPublication: async (expected) => { + expect(expected).toEqual(publication); + return publication; + }, + readJson: async () => ({ + id: 11, + tag_name: publication.tagName, + target_commitish: publication.publicationSha, + draft: false, + prerelease: false, + }), + readPages: async () => { + reads++; + return archives.map(({ name, bytes }, index) => ({ + id: 12 + index, + name, + size: bytes.length, + digest: `sha256:${createHash('sha256').update(bytes).digest('hex')}`, + state: 'uploaded', + url: `https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/${12 + index}`, + })); + }, + }); + const input = { + products: structuredClone(products), + source, + observation: observation as any, + completed: [{ publication, files: archives.map(({ target, file }) => ({ target, file })) }], + }; + const project = () => projectNativeBuildBoundSuppliers(input, { authenticateCompleted }); + await run({ + input, + project, + roots, + cohort, + observation, + authenticateCompleted, + readCount: () => reads, + executionRoot, + }); + } finally { + rmSync(executionRoot, { recursive: true, force: true }); + } +} + +test('exact current File adds one edge; server ABI and source-only packages add none', async () => { + await fixture(async ({ project }) => { + const result = await project(); + expect(result.unknowns).toEqual([]); + expect([...result.buildBound!.get(consumer)!]).toEqual([product]); + expect([...result.buildBound!.get(product)!]).toEqual([]); + expect([...result.buildBound!.get('fixture-source')!]).toEqual([]); + expect(result.scope).toBe('construction'); + }); +}); + +test('same-version held member is independently archive-authenticated and stays held', async () => { + await fixture(async ({ project, readCount }) => { + const result = await project(); + expect([...result.buildBound!.get(consumer)!]).toEqual([]); + expect(result.suppliers.find((row) => row.binding === 'compiled-input')!.version).toBe(version); + expect(readCount()).toBe(1); + }, 'held'); +}); + +test('one completed publication keeps Cargo and GitHub supplier contexts distinct', async () => { + await fixture(async ({ input, roots, cohort, executionRoot }) => { + const carrier = 'cargo:liboliphaunt-native'; + const cargoRoot = path.join(executionRoot, 'cargo-origin'); + mkdirSync(path.join(cargoRoot, 'include'), { recursive: true }); + const bytes = readFileSync(path.join(executionRoot, header)); + writeFileSync(path.join(cargoRoot, 'include/pg_config.h'), bytes); + const cargo = path.join(executionRoot, 'cargo-origin.tar.gz'); + await archiveDirectory(cargoRoot, cargo); + roots[1].package.supplierInputs = [ + { + ...held(), + configuration: 'portable', + binding: 'abi-contract', + origin: { kind: 'completed-publication', publication, artifact: carrier }, + files: [{ path: header, member: 'include/pg_config.h' }], + }, + ]; + input.completed.push({ publication, carriers: { [carrier]: [cargo] } } as any); + const seen: string[] = []; + // Controlled origins exercise selection and caching; no live authentication claim. + const authenticateCompleted = async (context) => { + const registry = 'carriers' in context; + const entry = readPortableArchiveEntries( + registry ? context.carriers[carrier][0] : context.files[0].file, + ).get(registry ? 'include/pg_config.h' : 'lib/liboliphaunt.so')!; + const name = registry ? carrier : artifact; + seen.push(name); + return { + publication, + archives: [ + { + name, + target: registry ? 'portable' : configuration, + members: [ + { + path: registry ? 'include/pg_config.h' : 'lib/liboliphaunt.so', + type: 'file', + size: entry.size, + sha256: createHash('sha256').update(entry.data()).digest('hex'), + }, + ], + }, + ], + }; + }; + const project = () => projectNativeBuildBoundSuppliers(input, { authenticateCompleted }); + expect((await project()).unknowns).toEqual([]); + expect(seen.sort()).toEqual([carrier, artifact].sort()); + input.completed.push(structuredClone(input.completed[1])); + await expect(project()).rejects.toThrow('ambiguous completed supplier archive input'); + input.completed.pop(); + cohort.inputs.find(({ path }) => path === header)!.members[0].sha256 = '0'.repeat(64); + await expect(project()).rejects.toThrow('published member bytes'); + }, 'held'); +}); + +test('completed supplier projection preserves the original metadata capability while cloning structural facts', async () => { + await fixture(async ({ input }) => { + const metadataBaseline = { originalAuthenticatedObject: true }; + input.completed[0].metadataBaseline = metadataBaseline; + const original = input.completed[0]; + await expect( + projectNativeBuildBoundSuppliers(input, { + authenticateCompleted: (snapshot) => { + expect(snapshot).not.toBe(original); + expect(snapshot.metadataBaseline).toBe(metadataBaseline); + expect(snapshot.publication).not.toBe(original.publication); + // The existing completed reader still decides authenticity. A clone + // must never replace the capability it is asked to verify. + throw new Error('completed metadata authenticity remains mandatory'); + }, + }), + ).rejects.toThrow('completed metadata authenticity remains mandatory'); + }, 'held'); +}); + +test('genuine completed registry source is bound by raw archive bytes, independent of its File path', async () => { + await fixture(async ({ input, roots, cohort, executionRoot, observation }) => { + const root = path.join(import.meta.dir, 'testdata/native-source-carriers'); + const captured = JSON.parse(readFileSync(path.join(root, 'captured-publication.json'), 'utf8')); + const readJson = async (endpoint) => { + if (!Object.hasOwn(captured.responses, endpoint)) + throw new Error(`uncaptured source ${endpoint}`); + return structuredClone(captured.responses[endpoint]); + }; + const assertCompletedPublication = createCompletedPublicationChecker({ + repository: 'f0rr0/oliphaunt', + readJson, + listPullRequests: async () => captured.pullRequests, + readPages: async () => { + throw new Error('unexpected history'); + }, + }); + const completed = await assertCompletedPublication({ + product: 'oliphaunt-query', + version: '0.1.1', + tagName: 'oliphaunt-query-v0.1.1', + publicationSha: 'c51052fe8b8ffc7e992266c5ab3d7a63b47441e7', + }); + const archive = path.join(root, 'oliphaunt-query-0.1.1.crate'); + const bytes = readPortableArchiveEntries(archive) + .get('oliphaunt-query-0.1.1/Cargo.toml')! + .data(); + writeFileSync(path.join(executionRoot, heldFile), bytes); + cohort.inputs.find(({ path: name }) => name === heldFile)!.members = captureNativeInputMembers( + executionRoot, + heldFile, + ).members; + delete input.products[product]; + input.products[completed.product] = { version: completed.version }; + const metadata = observation.products.find(({ product: row }) => row.id === product)!.product; + metadata.id = completed.product; + metadata.version = completed.version; + roots[0].package.product = completed.product; + roots[0].package.version = completed.version; + roots[1].package.supplierInputs = []; + roots[2].package.supplierInputs = [ + { + product: completed.product, + version: completed.version, + configuration: 'portable', + binding: 'compiled-input', + origin: { + kind: 'completed-publication', + publication: completed, + artifact: 'cargo:oliphaunt-query', + }, + files: [{ path: heldFile, member: 'Cargo.toml' }], + }, + ]; + input.completed = [ + { publication: completed, carriers: { 'cargo:oliphaunt-query': [archive] } }, + ] as any; + const authenticateCompleted = (origin) => + captureCompletedNativeRegistryCarriers(origin, { + assertCompletedPublication, + readJson, + registryOptions: { + cratesIoReadGate: null, + fetchImpl: async () => Response.json(captured.registryMetadata.cargo), + }, + }); + const result = await projectNativeBuildBoundSuppliers(input, { authenticateCompleted }); + expect(result.unknowns).toEqual([]); + expect([...result.buildBound!.get(consumer)!]).toEqual([]); + expect(result.suppliers[0].origin).toEqual(roots[2].package.supplierInputs[0].origin); + cohort.inputs.find(({ path: name }) => name === heldFile)!.members[0].sha256 = '0'.repeat(64); + await expect( + projectNativeBuildBoundSuppliers(input, { authenticateCompleted }), + ).rejects.toThrow('published member bytes'); + }, 'held'); +}); + +test('held WASIX payload uses canonical completed public archive members, never its Cargo File name', async () => { + await fixture(async ({ input, roots, cohort, observation, executionRoot }) => { + const id = 'liboliphaunt-wasix'; + const heldVersion = '0.3.2'; + const completed = { + ...publication, + product: id, + version: heldVersion, + tagName: `${id}-v${heldVersion}`, + }; + const descriptor = loadPublicationCatalog('supplier fixture', { products: [id] }).products[0]; + const rows = expectedProductArtifactRows([{ ...descriptor, version: heldVersion }]).filter( + ({ role }) => role === 'github-release-asset' || role === 'github-release-metadata', + ); + const row = rows.find(({ kind }) => kind === 'wasix-runtime')!; + const published = path.join(executionRoot, 'wasix-published'); + mkdirSync(path.join(published, 'bin'), { recursive: true }); + const bytes = Buffer.from([0, 97, 115, 109, 1, 0, 0, 0]); + writeFileSync(path.join(published, 'bin/initdb.wasix.wasm'), bytes); + const archive = path.join(executionRoot, row.name); + await archiveDirectory(published, archive); + const archiveBytes = readFileSync(archive); + const sha256 = createHash('sha256').update(archiveBytes).digest('hex'); + delete input.products[product]; + input.products[id] = { version: heldVersion }; + observation.products = Object.entries(input.products).map(([id, metadata]) => ({ + product: { id, ...metadata }, + })); + roots[0].package.product = id; + roots[0].package.version = heldVersion; + roots[1].package.supplierInputs = []; + roots[2].package.configuration = 'portable'; + roots[2].package.supplierInputs = [ + { + product: id, + version: heldVersion, + configuration: row.target, + binding: 'compiled-input', + origin: { kind: 'completed-publication', publication: completed, artifact: row.id }, + files: [{ path: heldFile, member: 'bin/initdb.wasix.wasm' }], + }, + ]; + const capture = cohort.inputs.find(({ path }) => path === heldFile)!; + writeFileSync(path.join(executionRoot, heldFile), bytes); + capture.members = captureNativeInputMembers(executionRoot, heldFile).members; + input.completed = [{ publication: completed, files: { [row.id]: archive } }] as any; + let publicRows = rows; + const authenticateCompleted = (input) => + captureCompletedNativePublicArtifacts(input, { + assertCompletedPublication: async (requested) => { + expect(requested).toEqual(completed); + return completed; + }, + readJson: async (endpoint) => { + const prefix = 'repos/f0rr0/oliphaunt/contents/'; + if (!endpoint.startsWith(prefix)) + return { + id: 11, + tag_name: completed.tagName, + target_commitish: completed.publicationSha, + draft: false, + prerelease: false, + }; + expect(endpoint.endsWith(`?ref=${completed.publicationSha}`)).toBe(true); + const file = endpoint.slice(prefix.length).split('?ref=')[0]; + let text = readFileSync(path.join(ROOT, file), 'utf8'); + if (file === '.release-please-manifest.json') { + const versions = JSON.parse(text); + versions[descriptor.path] = completed.version; + text = JSON.stringify(versions); + } + const bytes = Buffer.from(text); + return { + type: 'file', + path: file, + encoding: 'base64', + content: bytes.toString('base64'), + sha: createHash('sha1').update(`blob ${bytes.length}\0`).update(bytes).digest('hex'), + }; + }, + readPages: async () => + publicRows.map((expected, index) => ({ + id: index + 12, + name: expected.name, + size: expected.id === row.id ? archiveBytes.length : 1, + digest: `sha256:${expected.id === row.id ? sha256 : '1'.repeat(64)}`, + state: 'uploaded', + url: `https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/${index + 12}`, + })), + }); + const project = () => projectNativeBuildBoundSuppliers(input, { authenticateCompleted }); + const result = await project(); + expect(result.unknowns).toEqual([]); + expect([...result.buildBound!.get(consumer)!]).toEqual([]); + capture.members[0].sha256 = '2'.repeat(64); + await expect(project()).rejects.toThrow(/published member bytes/); + capture.members = captureNativeInputMembers(executionRoot, heldFile).members; + publicRows = rows.slice(1); + expect((await project()).buildBound).toBeUndefined(); + }, 'held'); +}); + +test('portable consumer binds the native supplier delivery slot independently of its own configuration', async () => { + await fixture(async ({ roots, project }) => { + roots[2].package.configuration = 'portable'; + const result = await project(); + const supplied = result.suppliers.find((row) => row.binding === 'compiled-input')!; + expect(supplied.configuration).toBe(configuration); + expect(supplied.consumerConfiguration).toBe('portable'); + expect(supplied.rootConfiguration).toBe('f'.repeat(64)); + expect([...result.buildBound!.get(consumer)!]).toEqual([product]); + }); + await fixture(async ({ roots, project }) => { + roots[2].package.configuration = 'portable'; + expect([...(await project()).buildBound!.get(consumer)!]).toEqual([]); + }, 'held'); +}); + +test('different held target archives from one completed release retain one conventional supplier pin', async () => { + await fixture( + async ({ cohort, roots, observation, project, readCount }) => { + const other = structuredClone(cohort); + other.roots = [structuredClone(roots[2])]; + other.roots[0].label = '//extensions:arm_shipping'; + other.roots[0].package.configuration = 'linux-arm64-gnu'; + const supplier = other.roots[0].package.supplierInputs[0]; + supplier.configuration = 'linux-arm64-gnu'; + supplier.origin.artifact = `liboliphaunt-${version}-linux-arm64-gnu.tar.gz`; + other.rootConfigurations = [{ label: other.roots[0].label, configuration: '2'.repeat(64) }]; + other.aquery.configuration[0].checksum = '2'.repeat(64); + observation.authenticated[0].evidence.cohorts.push(other); + const result = await project(); + expect(result.unknowns).toEqual([]); + expect([...result.buildBound!.get(consumer)!]).toEqual([]); + expect(result.suppliers.filter(({ binding }) => binding === 'compiled-input')).toHaveLength( + 2, + ); + expect(readCount()).toBe(1); + }, + 'held', + [configuration, 'linux-arm64-gnu'], + ); +}); + +test('a current imported File stays unknown until its original qualified transport is bound', async () => { + await fixture(async ({ roots, project }) => { + roots[2].package.supplierInputs = [current()]; + roots[2].package.supplierInputs[0].files[0].path = heldFile; + const result = await project(); + expect(result.buildBound).toBeUndefined(); + expect(result.unknowns).toContain('unverified current supplier producer transport'); + expect(result.suppliers.find(({ binding }) => binding === 'compiled-input')!.origin.kind).toBe( + 'current-source', + ); + }, 'held'); +}); + +test('per-package closure cannot borrow the embedded File from a same-product server sibling', async () => { + await fixture(async ({ roots, project }) => { + roots[1].package.supplierInputs = [current()]; + await expect(project()).rejects.toThrow(/not consumed/); + }); +}); + +test('a consumed consumer-owned generated File cannot be relabeled as the current core', async () => { + await fixture(async ({ roots, cohort, project, executionRoot }) => { + const output = roots[1].package.outputs[0].path; + const id = cohort.aquery.actions[1].outputIds[0]; + cohort.aquery.depSetOfFiles[2].directArtifactIds.push(id); + cohort.inputs.push({ + path: output, + members: captureNativeInputMembers(executionRoot, output).members, + }); + roots[2].package.supplierInputs[0].files[0].path = output; + await expect(project()).rejects.toThrow(/own configured shipping producer/); + }); +}); + +test('candidate metadata cannot substitute for the configured core delivery producer', async () => { + await fixture(async ({ roots, project }) => { + roots[0].package.ecosystem = 'github'; + roots[0].package.role = 'github-release-metadata'; + await expect(project()).rejects.toThrow(/own configured shipping producer/); + }); +}); + +test('a current consumer cannot borrow its supplier producer from another cohort', async () => { + await fixture(async ({ roots, cohort, observation, project }) => { + const other = structuredClone(cohort); + other.roots = [structuredClone(roots[0])]; + other.rootConfigurations = [other.rootConfigurations[0]]; + cohort.roots = roots.slice(1); + cohort.rootConfigurations = cohort.rootConfigurations.slice(1); + observation.authenticated[0].evidence.cohorts.push(other); + await expect(project()).rejects.toThrow(/own configured shipping producer/); + }); +}); + +test('explicit empty coverage is distinct from missing/partial producing coverage', async () => { + await fixture(async ({ roots, project, observation }) => { + delete (roots[1].package as any).supplierInputs; + expect((await project()).buildBound).toBeUndefined(); + roots[1].package.supplierInputs = []; + observation.coverage.completeProductInventory = false; + expect((await project()).buildBound).toBeUndefined(); + observation.coverage.completeProductInventory = true; + observation.authenticated[0].qualification.shippingAnalysis = 'unverified'; + expect((await project()).buildBound).toBeUndefined(); + }); +}); + +test('unavailable completed bytes stay unknown instead of falling back to current same-version producer', async () => { + await fixture(async ({ input, project, readCount }) => { + input.completed = []; + const result = await project(); + expect(result.buildBound).toBeUndefined(); + expect(result.unknowns.join(',')).toContain('missing completed supplier bytes'); + expect(readCount()).toBe(0); + }, 'held'); +}); + +test('a substituted archive cannot borrow another artifact from its completed publication', async () => { + await fixture(async ({ roots, project, readCount }) => { + roots[2].package.supplierInputs[0].origin.artifact = 'different.tar.gz'; + const result = await project(); + expect(result.buildBound).toBeUndefined(); + expect(result.unknowns.join(',')).toContain('missing completed supplier bytes'); + expect(readCount()).toBe(0); + }, 'held'); +}); + +test('held captured bytes and archive member substitutions fail', async () => { + for (const change of [ + ({ roots }) => { + roots[2].package.supplierInputs[0].files[0].member = 'lib/missing.so'; + }, + ({ cohort }) => { + cohort.inputs.find(({ path }) => path === heldFile).members[0].sha256 = '1'.repeat(64); + }, + ]) + await fixture(async (f) => { + change(f); + await expect(f.project()).rejects.toThrow(); + }, 'held'); +}); + +test('a substituted completed source cannot reuse bytes from another immutable origin', async () => { + await fixture(async ({ roots, project }) => { + (roots[2].package.supplierInputs[0].origin as any).publication.publicationSha = '1'.repeat(40); + expect((await project()).buildBound).toBeUndefined(); + }, 'held'); +}); + +test('current source/version/configuration and regular File coverage are exact', async () => { + for (const change of [ + ({ observation }) => { + observation.authenticated[0].evidence.source.commit = '1'.repeat(40); + }, + ({ roots }) => { + roots[2].package.supplierInputs[0].version = '0.3.2'; + }, + ({ roots }) => { + roots[2].package.supplierInputs[0].configuration = 'linux-arm64-gnu'; + }, + ({ cohort }) => { + cohort.inputs.find(({ path }) => path === currentFile).members = [ + { path: '', type: 'directory', mode: 0o755 }, + ]; + }, + ({ roots }) => { + roots[2].package.supplierInputs[0].files[0].path = 'runtime/source.c'; + }, + ({ roots }) => { + roots[2].package.supplierInputs[0].files[0].path = '../outside'; + }, + ]) + await fixture(async (f) => { + change(f); + await expect(f.project()).rejects.toThrow(); + }); +}); + +test('missing, duplicate and untyped supplier facts cannot create inferred edges', async () => { + for (const change of [ + ({ roots }) => { + roots[2].package.supplierInputs = [current(), current()]; + }, + ({ roots }) => { + roots[2].package.supplierInputs[0].files.push({ path: currentFile }); + }, + ({ roots }) => { + delete roots[2].package.supplierInputs[0].origin; + }, + ({ roots }) => { + roots[2].package.supplierInputs[0].files = []; + }, + ({ roots }) => { + roots[2].package.supplierInputs[0].product = 'unowned-product'; + }, + ({ roots }) => { + roots[2].package.supplierInputs[0].binding = 'owner-path'; + }, + ({ roots }) => { + roots[2].package.supplierInputs[0].compiled = true; + }, + ]) + await fixture(async (f) => { + change(f); + await expect(f.project()).rejects.toThrow(); + }); +}); + +test('own-product incorporation is checked without creating a contrib version self edge', async () => { + await fixture(async ({ roots, project }) => { + roots[2].package.product = product; + roots[2].package.version = version; + roots[1].package.supplierInputs = []; + // Keep the extension's configured server root as its explicit empty input + // contract; ownership and supplier relationships remain independent. + expect([...(await project()).buildBound!.get(product)!]).toEqual([]); + }); +}); + +test('ABI-only current origin does not conflict with held compiled supplier', async () => { + await fixture(async ({ project }) => { + const result = await project(); + expect(result.suppliers.map(({ binding }) => binding).sort()).toEqual([ + 'abi-contract', + 'compiled-input', + ]); + expect([...result.buildBound!.get(consumer)!]).toEqual([]); + }, 'held'); +}); + +test('a changed dynamically linked core requests checks without inventing extension host adoption', async () => { + await fixture(async ({ input, roots, cohort, executionRoot, project }) => { + roots[2].package.supplierInputs = [ + { ...current('abi-contract'), files: [{ path: currentFile }] }, + ]; + const module = readFileSync(path.join(executionRoot, roots[2].package.outputs[0].path)); + const before = await project(); + const core = cohort.inputs.find(({ path: name }) => name === currentFile)!; + const oldHash = core.members[0].sha256; + writeFileSync( + path.join(executionRoot, currentFile), + 'different core implementation; same public ABI', + ); + core.members = captureNativeInputMembers(executionRoot, currentFile).members; + const after = await project(); + expect(core.members[0].sha256).not.toBe(oldHash); + expect(readFileSync(path.join(executionRoot, roots[2].package.outputs[0].path))).toEqual( + module, + ); + expect([...after.buildBound!.get(consumer)!]).toEqual([]); + expect(after.buildBound).toEqual(before.buildBound); + + const metadata = structuredClone(input.products) as any; + metadata[consumer].extension = { class: 'external' }; + metadata[consumer].compatibility_versions = { host: { source_product: product } }; + metadata['fixture-source'].kind = 'sdk'; + metadata['fixture-source'].exact_extension_runtime = product; + metadata['fixture-source'].compatibility_versions = { host: { source_product: product } }; + const options = { + products: metadata, + buildBound: after.buildBound, + readCompatibility: () => '0.3.2', + }; + const runtimeOnly = defaultExtensionReleasePlan(metadata, [product], options); + expect([...runtimeOnly.required]).toEqual([product]); + expect(runtimeOnly.requirements.size).toBe(0); + // A separately changed extension may still ship for its authored held host. + const extensionOnly = defaultExtensionReleasePlan(metadata, [consumer], options); + expect([...extensionOnly.required]).toEqual([consumer]); + expect(extensionOnly.requirements.size).toBe(0); + expect(() => validateReleaseConsumerCompatibility([consumer], options)).not.toThrow(); + expect(after.scope).toBe('construction'); + }); +}); + +test('mixed compiled origins reject instead of unioning configurations', async () => { + await fixture(async ({ cohort, roots, project, observation }) => { + const other = structuredClone(cohort); + other.roots = [structuredClone(roots[2])]; + other.roots[0].label = '//extensions:other_configuration_shipping'; + other.rootConfigurations = [{ label: other.roots[0].label, configuration: '1'.repeat(64) }]; + other.roots[0].package.supplierInputs = [held()]; + // Both Files really reach this output; do not satisfy the held assertion + // from another root's inventory. + const heldId = other.aquery.artifacts.length + 1; + const index = heldId - 1; + other.aquery.pathFragments.push( + ...heldFile.split('/').map((label, segment) => ({ + id: `${index}-${segment}`, + label, + ...(segment ? { parentId: `${index}-${segment - 1}` } : {}), + })), + ); + other.aquery.artifacts.push({ + id: heldId, + pathFragmentId: `${index}-${heldFile.split('/').length - 1}`, + }); + other.aquery.depSetOfFiles[2].directArtifactIds.push(heldId); + other.inputs.push({ + path: heldFile, + members: [ + { + path: '', + type: 'file', + mode: 0o644, + size: 'authentic fixture published runtime bytes'.length, + sha256: createHash('sha256') + .update('authentic fixture published runtime bytes') + .digest('hex'), + }, + ], + }); + observation.authenticated[0].evidence.cohorts.push(other); + await expect(project()).rejects.toThrow(/conflicting current\/held/); + }); +}); + +async function importedFixture(run, wholeArchive = false) { + await fixture(async (context) => { + const { roots, cohort, observation, executionRoot } = context; + const tree = path.join(executionRoot, 'imported-current-source'); + mkdirSync(path.join(tree, 'modules'), { recursive: true }); + writeFileSync( + path.join(tree, 'modules/native.so'), + readFileSync(path.join(executionRoot, heldFile)), + ); + const output = 'bazel-out/producer/bin/runtime/bound.tar.gz'; + const archive = path.join(executionRoot, output); + mkdirSync(path.dirname(archive), { recursive: true }); + await archiveDirectory(tree, archive); + const original = structuredClone(cohort); + const invocationId = 'original-linux-invocation'; + const root = structuredClone(roots[0]); + root.label = '//runtime:bound_archive_shipping'; + root.package.ecosystem = 'github'; + root.package.role = 'github-release-asset'; + root.package.outputs = [{ path: output, owner: '//runtime:bound_archive' }]; + original.roots = [root]; + original.rootConfigurations = [{ label: root.label, configuration: '9'.repeat(64) }]; + original.outputs = [ + { path: output, members: captureNativeOutputMembers(executionRoot, output).members }, + ]; + const id = 1000; + original.aquery.pathFragments.push( + ...output.split('/').map((label, segment) => ({ + id: `imported-${segment}`, + label, + ...(segment ? { parentId: `imported-${segment - 1}` } : {}), + })), + ); + original.aquery.artifacts.push({ + id, + pathFragmentId: `imported-${output.split('/').length - 1}`, + }); + original.aquery.targets.push({ id, label: '//runtime:bound_archive' }); + original.aquery.actions.push({ + targetId: id, + configurationId: 1, + actionKey: 'original-archive', + mnemonic: 'FixtureArchive', + inputDepSetIds: [1], + outputIds: [id], + primaryOutputId: id, + }); + const packetArchive = path.join(executionRoot, 'packet/files/0', output); + mkdirSync(path.dirname(packetArchive), { recursive: true }); + writeFileSync(packetArchive, readFileSync(archive)); + const githubOrigin = { ...github, runId: 124, job: 'Original Linux builder' }; + const build = { + evidence: { source: structuredClone(source), github: githubOrigin, cohorts: [original] }, + qualification: { + ...structuredClone(observation.authenticated[0].qualification), + github: githubOrigin, + cohorts: [{ invocationId }], + }, + origin: { + github: githubOrigin, + evidenceDigest: `sha256:${'7'.repeat(64)}`, + finalFiles: { + files: [ + { + cohort: 0, + path: output, + size: original.outputs[0].members[0].size, + sha256: original.outputs[0].members[0].sha256, + }, + ], + artifactRoots: [packetArchive], + assertUnchanged() {}, + }, + }, + }; + // The fixture injects the already-authenticated observer boundary; no + // synthetic workflow is asserted to be an actual release qualification. + observation.authenticated.push(build); + roots[2].package.configuration = 'macos-arm64'; + roots[2].package.supplierInputs = [ + { + product, + version, + configuration, + binding: 'compiled-input', + origin: { + kind: 'current-source', + producer: { + evidenceDigest: build.origin.evidenceDigest, + invocationId, + root: root.label, + configuration: '9'.repeat(64), + output, + }, + }, + files: [{ path: heldFile, member: 'modules/native.so' }], + }, + ]; + if (wholeArchive) { + delete roots[2].package.supplierInputs[0].files[0].member; + writeFileSync(path.join(executionRoot, heldFile), readFileSync(packetArchive)); + cohort.inputs.find(({ path: file }) => file === heldFile).members = captureNativeInputMembers( + executionRoot, + heldFile, + ).members; + } + await run({ + ...context, + original, + build, + supplier: roots[2].package.supplierInputs[0], + packetArchive, + }); + }, 'held'); +} + +test('imported current member binds the qualified invocation without inventing a raw cohort field', async () => { + await importedFixture(async ({ project }) => { + const result = await project(); + expect(result.unknowns).toEqual([]); + expect([...result.buildBound!.get(consumer)!]).toEqual([product]); + expect( + result.suppliers.find((row) => row.origin.kind === 'current-source' && row.origin.producer)! + .consumerConfiguration, + ).toBe('macos-arm64'); + }); +}); + +for (const wholeArchive of [false, true]) { + const kind = wholeArchive ? 'whole archive' : 'member'; + test(`missing original current ${kind} evidence or transported bytes stays unknown`, async () => { + await importedFixture(async ({ project, build, supplier }) => { + supplier.origin.producer.evidenceDigest = `sha256:${'8'.repeat(64)}`; + expect((await project()).buildBound).toBeUndefined(); + supplier.origin.producer.evidenceDigest = build.origin.evidenceDigest; + delete build.origin.finalFiles; + const result = await project(); + expect(result.buildBound).toBeUndefined(); + expect(result.unknowns).toContain( + 'missing authenticated original current supplier transport', + ); + }, wholeArchive); + }); + + test(`current ${kind} import rejects root/configuration/member/source/run substitution`, async () => { + for (const mutate of [ + ({ supplier }) => { + supplier.origin.producer.root = '//runtime:another_shipping'; + }, + ({ supplier }) => { + supplier.origin.producer.configuration = '8'.repeat(64); + }, + ({ supplier }) => { + supplier.origin.producer.invocationId = 'another-invocation'; + }, + ({ supplier }) => { + supplier.origin.producer.output = 'bazel-out/producer/bin/runtime/other.tar.gz'; + }, + ({ supplier }) => { + supplier.files[0].member = 'modules/other.so'; + }, + ({ build }) => { + build.evidence.source.commit = 'c'.repeat(40); + }, + ({ build }) => { + build.origin.github = { ...build.origin.github, runAttempt: 2 }; + }, + ]) + await importedFixture(async (context) => { + mutate(context); + await expect(context.project()).rejects.toThrow( + /mismatch|exact original regular|original public final/, + ); + }, wholeArchive); + }); + + test(`imported current ${kind} transport and consumed File byte substitutions reject`, async () => { + await importedFixture(async ({ project, packetArchive }) => { + writeFileSync(packetArchive, 'substituted final archive'); + await expect(project()).rejects.toThrow(/physical archive/); + }, wholeArchive); + await importedFixture(async ({ project, cohort, executionRoot }) => { + writeFileSync(path.join(executionRoot, heldFile), 'substituted consumer input'); + cohort.inputs.find((input) => input.path === heldFile).members = captureNativeInputMembers( + executionRoot, + heldFile, + ).members; + await expect(project()).rejects.toThrow( + wholeArchive ? /original current outer archive bytes/ : /original current member bytes/, + ); + }, wholeArchive); + }); +} + +for (const binding of ['abi-contract', 'compiled-input'] as const) + test(`whole imported current ${binding} archive retains original provenance and adoption semantics`, async () => { + await importedFixture(async ({ project, supplier }) => { + supplier.binding = binding; + const result = await project(); + expect(result.unknowns).toEqual([]); + expect([...result.buildBound!.get(consumer)!]).toEqual( + binding === 'compiled-input' ? [product] : [], + ); + expect( + result.suppliers.find(({ origin }) => origin.kind === 'current-source' && origin.producer)! + .origin, + ).toEqual(supplier.origin); + }, true); + }); + +test('an extracted current member cannot stand in for the whole original archive', async () => { + await importedFixture(async ({ project, supplier }) => { + delete supplier.files[0].member; + await expect(project()).rejects.toThrow(/original current outer archive bytes/); + }); +}); + +test('a whole compiled current archive must reach its own consumer action', async () => { + await importedFixture(async ({ project, cohort }) => { + cohort.aquery.depSetOfFiles[2].directArtifactIds.shift(); + await expect(project()).rejects.toThrow(/supplier File is not consumed/); + }, true); +}); + +async function importedAppleFixture(run) { + await importedFixture(async (context) => { + const { supplier, original, build, executionRoot, cohort } = context; + const output = 'bazel-out/producer/bin/src/native/runtime/apple_release_assets/ios.json'; + const bytes = Buffer.from('{"schema":"controlled-private-ios-fixture","version":"0.3.3"}\n'); + mkdirSync(path.dirname(path.join(executionRoot, output)), { recursive: true }); + writeFileSync(path.join(executionRoot, output), bytes); + original.outputs[0] = { + path: output, + members: captureNativeOutputMembers(executionRoot, output).members, + }; + const root = original.roots[0]; + root.label = '//src/native/runtime:apple_ios_manifest_shipping'; + Object.assign(root.package, { + ecosystem: 'internal', + role: 'apple-base-ios-manifest-input', + configuration: 'ios-xcframework', + name: 'ios.json', + outputs: [{ path: output, owner: '//runtime:bound_archive' }], + }); + original.rootConfigurations[0].label = root.label; + const artifact = original.aquery.artifacts.find(({ id }) => id === 1000)!; + original.aquery.pathFragments.push( + ...output.split('/').map((label, segment) => ({ + id: `apple-${segment}`, + label, + ...(segment ? { parentId: `apple-${segment - 1}` } : {}), + })), + ); + artifact.pathFragmentId = `apple-${output.split('/').length - 1}`; + supplier.configuration = 'ios-xcframework'; + supplier.binding = 'abi-contract'; + Object.assign(supplier.origin.producer, { root: root.label, output }); + delete supplier.files[0].member; + const archive = path.join(executionRoot, 'packet/files/0', output); + mkdirSync(path.dirname(archive), { recursive: true }); + writeFileSync(archive, bytes); + build.origin.finalFiles.artifactRoots = [archive]; + Object.assign(build.origin.finalFiles.files[0], { + path: output, + size: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + }); + writeFileSync(path.join(executionRoot, heldFile), bytes); + cohort.inputs.find(({ path: file }) => file === heldFile).members = captureNativeInputMembers( + executionRoot, + heldFile, + ).members; + await run({ ...context, archive }); + }); +} + +test('the canonical private Apple document reuses its exact qualified File without an archive or compiler claim', async () => { + await importedAppleFixture(async ({ project, archive }) => { + const result = await project(); + expect(result.unknowns).toEqual([]); + expect([...result.buildBound!.get(consumer)!]).toEqual([]); + writeFileSync(archive, 'substituted private input'); + await expect(project()).rejects.toThrow(/physical archive/); + }); +}); + +test('private Apple reuse cannot bless another role, owner, slot, root or compiled member', async () => { + for (const mutate of [ + ({ original }) => { + original.roots[0].package.role = 'construction'; + }, + ({ original }) => { + original.roots[0].package.product = consumer; + }, + ({ original }) => { + original.roots[0].package.configuration = configuration; + }, + ({ supplier }) => { + supplier.origin.producer.root = '//other:ios_manifest'; + }, + ({ supplier }) => { + supplier.binding = 'compiled-input'; + supplier.files[0].member = 'file'; + }, + ]) + await importedAppleFixture(async (context) => { + mutate(context); + await expect(context.project()).rejects.toThrow(); + }); +}); + +async function importedTreeFixture(run) { + await importedFixture(async (context) => { + const { supplier, original, build, executionRoot, packetArchive, cohort } = context; + const output = supplier.origin.producer.output; + const name = 'liboliphaunt-0.3.3-android-arm64-v8a.tar.gz'; + const bytes = readFileSync(packetArchive); + rmSync(path.join(executionRoot, output)); + mkdirSync(path.join(executionRoot, output)); + writeFileSync(path.join(executionRoot, output, name), bytes); + original.outputs[0].members = captureNativeOutputMembers(executionRoot, output).members; + original.roots[0].package.name = name; + supplier.origin.producer.member = name; + supplier.binding = 'abi-contract'; + delete supplier.files[0].member; + const archive = `${packetArchive}/${name}`; + rmSync(packetArchive); + mkdirSync(packetArchive); + writeFileSync(archive, bytes); + build.origin.finalFiles.artifactRoots = [archive]; + build.origin.finalFiles.files[0].path = `${output}/${name}`; + writeFileSync(path.join(executionRoot, heldFile), bytes); + cohort.inputs.find(({ path: file }) => file === heldFile).members = captureNativeInputMembers( + executionRoot, + heldFile, + ).members; + await run({ ...context, archive }); + }); +} + +for (const binding of ['abi-contract', 'compiled-input'] as const) + test(`whole imported Tree ${binding} archive binds the original canonical regular leaf`, async () => { + await importedTreeFixture(async ({ project, supplier }) => { + supplier.binding = binding; + expect(supplier.origin.producer.member).toBe('liboliphaunt-0.3.3-android-arm64-v8a.tar.gz'); + expect(supplier.files).toEqual([{ path: heldFile }]); + const result = await project(); + expect(result.unknowns).toEqual([]); + expect([...result.buildBound!.get(consumer)!]).toEqual( + binding === 'compiled-input' ? [product] : [], + ); + }); + }); + +test('imported Tree archive rejects root, member, canonical identity and byte substitutions', async () => { + for (const mutate of [ + ({ supplier }) => { + delete supplier.origin.producer.member; + }, + ({ supplier }) => { + supplier.origin.producer.member = '../outside.tar.gz'; + }, + ({ supplier }) => { + supplier.origin.producer.member = 'missing.tar.gz'; + }, + ({ original }) => { + original.outputs[0].members[0].type = 'file'; + }, + ({ original }) => { + original.roots[0].package.name = 'another-canonical-asset.tar.gz'; + }, + ({ archive }) => { + writeFileSync(archive, 'different transported archive'); + }, + ]) + await importedTreeFixture(async (context) => { + context.supplier.binding = 'compiled-input'; + mutate(context); + await expect(context.project()).rejects.toThrow(); + }); +}); + +for (const binding of ['abi-contract', 'compiled-input'] as const) + test(`whole completed ${binding} archive binds authenticated outer bytes and stays held`, async () => { + await fixture( + async ({ project, roots, cohort, input, executionRoot, authenticateCompleted }) => { + const supplier = roots[2].package.supplierInputs[0]; + supplier.binding = binding; + delete supplier.files[0].member; + writeFileSync( + path.join(executionRoot, heldFile), + readFileSync(input.completed[0].files[0].file), + ); + cohort.inputs.find((row) => row.path === heldFile).members = captureNativeInputMembers( + executionRoot, + heldFile, + ).members; + const result = await project(); + expect(result.unknowns).toEqual([]); + expect([...result.buildBound!.get(consumer)!]).toEqual([]); + expect( + result.suppliers.find(({ origin }) => origin.kind === 'completed-publication')!.origin, + ).toEqual(supplier.origin); + await expect( + projectNativeBuildBoundSuppliers(input, { + authenticateCompleted: async (request) => { + const origin = await authenticateCompleted(request); + for (const archive of origin.archives) { + delete (archive as any).size; + delete (archive as any).sha256; + } + return origin; + }, + }), + ).rejects.toThrow(/authenticated outer bytes/); + writeFileSync(path.join(executionRoot, heldFile), 'different archive bytes'); + cohort.inputs.find((row) => row.path === heldFile).members = captureNativeInputMembers( + executionRoot, + heldFile, + ).members; + await expect(project()).rejects.toThrow(/published outer archive bytes/); + }, + 'held', + ); + }); + +test('an extracted held member cannot stand in for the whole published archive', async () => { + await fixture(async ({ project, roots }) => { + delete roots[2].package.supplierInputs[0].files[0].member; + await expect(project()).rejects.toThrow(/published outer archive bytes/); + }, 'held'); +}); + +async function importedSwiftDocumentFixture(kind: 'carrier' | 'ownerCatalog' | 'archive', run) { + await importedAppleFixture(async (context) => { + const { supplier, original, build, executionRoot, cohort, input, observation } = context; + const swift = 'oliphaunt-swift'; + input.products[swift] = { version: '0.8.2' }; + observation.products.push({ product: { id: swift, version: '0.8.2' } }); + const isTree = kind === 'carrier'; + const basename = + kind === 'archive' + ? 'Oliphaunt-source.zip' + : isTree + ? 'oliphaunt-react-native-ios-carriers.json' + : 'extension-owner-catalog.json'; + const output = + 'bazel-out/producer/bin/src/native/sdks/swift/source_package/' + + (isTree ? 'release-tree' : kind === 'archive' ? basename : 'extension-generator/' + basename); + const member = 'src/sdks/swift/Carriers/' + basename; + const full = isTree ? output + '/' + member : output; + let bytes = Buffer.from('{"genuine-captured-document":"' + kind + '"}\n'); + mkdirSync(path.dirname(path.join(executionRoot, full)), { recursive: true }); + if (kind === 'archive') { + const tree = path.join(executionRoot, 'original-swift-source/package/Sources'); + mkdirSync(tree, { recursive: true }); + writeFileSync(path.join(tree, 'Core.swift'), 'public struct OriginalCapturedSource {}\n'); + await archiveDirectory(path.dirname(path.dirname(tree)), path.join(executionRoot, full)); + bytes = readFileSync(path.join(executionRoot, full)); + } else writeFileSync(path.join(executionRoot, full), bytes); + const root = original.roots[0]; + root.label = '//src/native/sdks/swift:shipping_' + basename.replaceAll('.', '_'); + Object.assign(root.package, { + product: swift, + version: '0.8.2', + ecosystem: 'github', + configuration: 'portable', + role: 'release-input', + name: basename, + outputs: [{ path: output, owner: '//runtime:bound_archive' }], + }); + original.rootConfigurations[0].label = root.label; + original.aquery.pathFragments.push( + ...output.split('/').map((label, segment) => ({ + id: `swift-${segment}`, + label, + ...(segment ? { parentId: `swift-${segment - 1}` } : {}), + })), + ); + original.aquery.artifacts.find(({ id }) => id === 1000).pathFragmentId = + `swift-${output.split('/').length - 1}`; + original.outputs[0] = { + path: output, + members: captureNativeOutputMembers(executionRoot, output).members, + }; + supplier.product = swift; + supplier.version = '0.8.2'; + supplier.configuration = 'portable'; + Object.assign(supplier.origin.producer, { root: root.label, output }); + if (isTree) supplier.origin.producer.member = member; + const archive = path.join(executionRoot, 'packet/files/0', full); + mkdirSync(path.dirname(archive), { recursive: true }); + writeFileSync(archive, bytes); + build.origin.finalFiles.artifactRoots = [archive]; + Object.assign(build.origin.finalFiles.files[0], { + path: full, + size: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + }); + writeFileSync(path.join(executionRoot, heldFile), bytes); + cohort.inputs.find(({ path: name }) => name === heldFile).members = captureNativeInputMembers( + executionRoot, + heldFile, + ).members; + await run({ ...context, archive }); + }); +} + +for (const kind of ['carrier', 'ownerCatalog', 'archive'] as const) { + test( + 'exact original Swift ' + kind + ' File is ABI/data reuse without compiled adoption', + async () => { + await importedSwiftDocumentFixture(kind, async ({ project, archive }) => { + const result = await project(); + expect(result.unknowns).toEqual([]); + expect([...result.buildBound.get(consumer)]).toEqual([]); + writeFileSync(archive, 'substituted document'); + await expect(project()).rejects.toThrow(/physical archive/); + }); + }, + ); + test( + 'Swift ' + kind + ' document cannot bless wrong role, root, slot, member or compiler claim', + async () => { + for (const change of [ + ({ original }) => (original.roots[0].package.role = 'github-release-asset'), + ({ supplier }) => (supplier.origin.producer.root = '//swift:borrowed_document'), + ({ original }) => (original.roots[0].package.configuration = 'apple-xcframework'), + ({ supplier }) => + (supplier.origin.producer.member = + 'unrelated/' + + (kind === 'carrier' + ? 'oliphaunt-react-native-ios-carriers.json' + : 'extension-owner-catalog.json')), + ({ supplier }) => { + supplier.binding = 'compiled-input'; + supplier.files[0].member = 'inside'; + }, + ({ supplier }) => (supplier.files[0].member = 'inside'), + ]) + await importedSwiftDocumentFixture(kind, async (context) => { + change(context); + await expect(context.project()).rejects.toThrow(); + }); + }, + ); +} + +test('completed Git source context binds exact retained members and never becomes a current compiled adoption', async () => { + await fixture(async ({ input, roots, cohort, observation, executionRoot }) => { + const id = 'oliphaunt-swift'; + const version = '0.8.2'; + const completed = { ...publication, product: id, version, tagName: `${id}-v${version}` }; + const artifact = `swift-source-tag:${version}`; + const member = 'src/sdks/swift/Sources/Oliphaunt/Oliphaunt.swift'; + const bytes = Buffer.from('public struct FrozenSwiftSource {}\n'); + const tree = path.join(executionRoot, 'source-tag-tree'); + mkdirSync(path.join(tree, path.dirname(member)), { recursive: true }); + writeFileSync(path.join(tree, member), bytes); + const archive = path.join(executionRoot, 'source-tag.tar.gz'); + await archiveDirectory(tree, archive); + const outer = { + path: archive, + size: readFileSync(archive).length, + sha256: createHash('sha256').update(readFileSync(archive)).digest('hex'), + }; + const row = { + publication: completed, + artifact, + source: { + commit: '1'.repeat(40), + tree: '2'.repeat(40), + member: 'src/sdks/swift/Carriers/oliphaunt-react-native-ios-carriers.json', + blob: '3'.repeat(40), + }, + file: outer, + }; + delete input.products[product]; + input.products[id] = { version: '0.8.3' }; + observation.products = Object.entries(input.products).map(([id, metadata]) => ({ + product: { id, ...metadata }, + })); + roots[0].package.product = id; + roots[0].package.version = '0.8.3'; + roots[1].package.supplierInputs = []; + roots[2].package.supplierInputs = [ + { + product: id, + version, + configuration: 'portable', + binding: 'abi-contract', + origin: { kind: 'completed-publication', publication: completed, artifact }, + files: [{ path: heldFile, member }], + }, + ]; + writeFileSync(path.join(executionRoot, heldFile), bytes); + const capture = cohort.inputs.find(({ path: name }) => name === heldFile)!; + capture.members = captureNativeInputMembers(executionRoot, heldFile).members; + input.completed = [ + { publication: completed, files: {}, carriers: {}, sourceTags: [structuredClone(row)] }, + ] as any; + let reads = 0; + const authenticateCompleted = async (context) => { + reads++; + expect(context.sourceTags).toEqual([row]); + return { + scope: 'construction', + publication: completed, + unknowns: [], + archives: [ + { + id: artifact, + name: artifact, + target: 'portable', + size: outer.size, + sha256: outer.sha256, + members: nativeArchiveDeliveryMembers(archive), + }, + ], + }; + }; + const project = () => projectNativeBuildBoundSuppliers(input, { authenticateCompleted }); + const result = await project(); + expect(result.unknowns).toEqual([]); + expect([...result.buildBound!.get(consumer)!]).toEqual([]); + expect(reads).toBe(1); + capture.members[0].sha256 = '0'.repeat(64); + await expect(project()).rejects.toThrow('published member bytes'); + capture.members = captureNativeInputMembers(executionRoot, heldFile).members; + delete roots[2].package.supplierInputs[0].files[0].member; + capture.members = [ + { path: '', type: 'file', mode: 0o644, size: outer.size, sha256: outer.sha256 }, + ]; + expect((await project()).unknowns).toEqual([]); + input.completed[0].sourceTags[0].publication.publicationSha = '4'.repeat(40); + expect((await project()).unknowns).toContain( + 'missing completed supplier bytes: oliphaunt-swift@0.8.2', + ); + }, 'held'); +}); + +test('a current compiled Rust library needs its own configured producer and cannot masquerade as source or completed bytes', async () => { + await fixture(async ({ input, project, roots, cohort, executionRoot }) => { + const rlib = roots[3].package.outputs[0].path.replace('source.crate', 'libbindings.rlib'); + writeFileSync(path.join(executionRoot, rlib), 'controlled compiled binding bytes'); + const artifact = cohort.aquery.artifacts.find( + (row) => row.id === cohort.aquery.actions[3].outputIds[0], + ); + const fragment = cohort.aquery.pathFragments.find((row) => row.id === artifact.pathFragmentId); + fragment.label = 'libbindings.rlib'; + roots[3].package.outputs[0].path = rlib; + roots[2].package.supplierInputs = [ + { + product: 'fixture-source', + version: '2.0.0', + configuration, + binding: 'compiled-input', + origin: { kind: 'current-source' }, + files: [{ path: rlib }], + }, + ]; + // The consumer's actual action now incorporates the same generated library File. + cohort.aquery.depSetOfFiles[2].directArtifactIds = [ + cohort.aquery.depSetOfFiles[2].directArtifactIds[1], + artifact.id, + ]; + cohort.inputs.push({ + path: rlib, + members: captureNativeInputMembers(executionRoot, rlib).members, + }); + const result = await project(); + expect([...result.buildBound.get(consumer)]).toEqual(['fixture-source']); + expect(result.suppliers.find((row) => row.product === 'fixture-source').origin).toEqual({ + kind: 'current-source', + }); + roots[3].package.configuration = 'wrong-profile'; + await expect(project()).rejects.toThrow('own configured shipping producer'); + roots[3].package.configuration = configuration; + roots[3].package.product = consumer; + roots[3].package.version = input.products[consumer].version; + await expect(project()).rejects.toThrow('own configured shipping producer'); + roots[3].package.product = 'fixture-source'; + roots[3].package.version = input.products['fixture-source'].version; + roots[2].package.supplierInputs[0].files[0].path = 'source/README.md'; + cohort.aquery.depSetOfFiles[2].directArtifactIds.push( + cohort.aquery.depSetOfFiles[3].directArtifactIds[0], + ); + await expect(project()).rejects.toThrow('actual generated File'); + roots[2].package.supplierInputs[0].files[0].path = rlib; + roots[2].package.supplierInputs[0].version = '9.0.0'; + await expect(project()).rejects.toThrow('current supplier version'); + expect(input.products['fixture-source'].version).toBe('2.0.0'); + }); +}); diff --git a/tools/release/native-source-carrier-changes.mts b/tools/release/native-source-carrier-changes.mts new file mode 100644 index 000000000..885873776 --- /dev/null +++ b/tools/release/native-source-carrier-changes.mts @@ -0,0 +1,448 @@ +/** Compare completed delivery bytes; this cannot determine release necessity. */ +import { createHash } from 'node:crypto'; +import { readFileSync, statSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { readPortableArchiveEntries } from '../packaging/portable-archive.mts'; +import { + type CompletedPublication, + createCompletedPublicationChecker, +} from './completed-release-publication.mts'; +import { requestGithubRepositoryJson } from './github-read.mts'; +import { differentNativeDeliveredMembers } from './native-publication-delivery.mts'; +import { validatePublicationCandidate } from './publication-lock.mts'; +import { verifyRegistryCarrierIntegrity } from './registry-integrity.mts'; +import { syncTomlStringPath } from './sync-release-pr.mts'; + +const ownVersion = '0.0.0'; +const fullSha = /^[0-9a-f]{40}$/u; +const utf8 = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }); +const hash = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +const stable = (value: any): string => + value && typeof value === 'object' + ? Array.isArray(value) + ? `[${value.map(stable).join(',')}]` + : `{${Object.keys(value) + .sort() + .map((key) => `${JSON.stringify(key)}:${stable(value[key])}`) + .join(',')}}` + : JSON.stringify(value); + +export type CompletedSourceBaseline = { + version: string; + tagName: string; + publicationSha: string; + archives: Record; +}; + +function requireValue(condition: unknown, message: string): asserts condition { + if (!condition) throw new Error(`native source comparison: ${message}`); +} + +function cargoOwnVersion(text: string, name: string, version: string, label: string) { + const manifest = Bun.TOML.parse(text) as any; + requireValue(manifest.package?.name === name, `${label} package name differs`); + if (manifest.package.version?.workspace === true) return text; + requireValue(manifest.package.version === version, `${label} package version differs`); + return syncTomlStringPath(text, 'package.version', ownVersion, label).text; +} + +function cargoLockOwnVersion(text: string, name: string, version: string) { + const lock = Bun.TOML.parse(text) as any; + requireValue( + [3, 4].includes(lock.version) && Array.isArray(lock.package), + 'shipped Cargo.lock has no conventional package records', + ); + let own = 0; + const result = text + .split(/(?=^\[\[package\]\]\s*$)/mu) + .map((block) => { + if (!block.startsWith('[[package]]')) return block; + const row = (Bun.TOML.parse(block) as any).package[0]; + if (row.name !== name || row.source !== undefined) return block; + requireValue(row.version === version, 'shipped Cargo.lock own package version differs'); + own++; + // Reuse the bounded string writer on this one authenticated package table. + const table = block.replace('[[package]]', '[package]'); + return syncTomlStringPath( + table, + 'package.version', + ownVersion, + 'Cargo.lock own package', + ).text.replace('[package]', '[[package]]'); + }) + .join(''); + requireValue(own === 1, 'shipped Cargo.lock must contain exactly one own package'); + return result; +} + +function npmOwnVersion(text: string, version: string) { + // Token positions preserve every other byte, including nested dependency versions. + const tokens = [...text.matchAll(/"(?:\\.|[^"\\])*"|[{}[\]:,]/gu)]; + let depth = 0; + const own = []; + for (const [index, token] of tokens.entries()) { + if (token[0] === '{' || token[0] === '[') depth++; + else if (token[0] === '}' || token[0] === ']') depth--; + else if ( + depth === 1 && + token[0].startsWith('"') && + JSON.parse(token[0]) === 'version' && + ['{', ','].includes(tokens[index - 1]?.[0]) && + tokens[index + 1]?.[0] === ':' + ) { + const value = tokens[index + 2]; + requireValue(value && JSON.parse(value[0]) === version, 'npm own package version differs'); + own.push(value); + } + } + requireValue(own.length === 1, 'npm manifest must contain exactly one own version field'); + const value = own[0]; + return ( + text.slice(0, value.index) + + JSON.stringify(ownVersion) + + text.slice(value.index + value[0].length) + ); +} + +function cargoVcsCommitDiagnostic(text: string) { + // Cargo documents this as best-effort provenance, not source authentication: + // https://doc.rust-lang.org/cargo/commands/cargo-package.html + // A crate can nevertheless read this file. This projection is diagnostic; + // it is never an admitted delivery contract or a release-selection input. + const value = JSON.parse(text); + const object = (row: any) => row && typeof row === 'object' && !Array.isArray(row); + requireValue( + object(value) && + object(value.git) && + Object.keys(value).sort().join(',') === 'git,path_in_vcs' && + ['sha1', 'dirty,sha1'].includes(Object.keys(value.git).sort().join(',')) && + fullSha.test(value.git.sha1) && + (value.git.dirty === undefined || value.git.dirty === false) && + typeof value.path_in_vcs === 'string' && + (value.path_in_vcs === '' || + (!value.path_in_vcs.startsWith('/') && + !/[\\\u0000-\u001f\u007f]/u.test(value.path_in_vcs) && + !value.path_in_vcs.split('/').some((part) => !part || part === '.' || part === '..'))), + 'Cargo VCS diagnostic requires a supported clean record and safe path_in_vcs', + ); + const tokens = [...text.matchAll(/"(?:\\.|[^"\\])*"|[{}[\]:,]/gu)]; + let depth = 0; + const keys = [[], []] as string[][]; + const stamps = []; + for (const [index, token] of tokens.entries()) { + if (token[0] === '{' || token[0] === '[') depth++; + else if (token[0] === '}' || token[0] === ']') depth--; + else if ( + token[0].startsWith('"') && + ['{', ','].includes(tokens[index - 1]?.[0]) && + tokens[index + 1]?.[0] === ':' + ) { + requireValue(depth === 1 || depth === 2, 'unsupported Cargo VCS diagnostic nesting'); + const key = JSON.parse(token[0]); + keys[depth - 1].push(key); + if (depth === 2 && key === 'sha1') stamps.push(tokens[index + 2]); + } + } + requireValue( + keys[0].sort().join(',') === 'git,path_in_vcs' && + keys[1].sort().join(',') === Object.keys(value.git).sort().join(',') && + stamps.length === 1 && + JSON.parse(stamps[0][0]) === value.git.sha1, + 'Cargo VCS diagnostic has duplicate or unsupported fields', + ); + const stamp = stamps[0]; + // Retain whitespace, path_in_vcs, dirty:false, modes, and every other member. + return ( + text.slice(0, stamp.index) + + JSON.stringify('0'.repeat(40)) + + text.slice(stamp.index + stamp[0].length) + ); +} + +/** Compare all shipped members, with only typed own package identities neutralized. */ +export function sourceCarrierMembers( + file: string, + carrier: { ecosystem: string; name: string; version: string }, + { cargoVcsCommit = 'preserve' }: { cargoVcsCommit?: 'preserve' | 'provenance-diagnostic' } = {}, +) { + const entries = readPortableArchiveEntries(file); + const prefix = carrier.ecosystem === 'cargo' ? `${carrier.name}-${carrier.version}/` : 'package/'; + const manifestName = carrier.ecosystem === 'cargo' ? 'Cargo.toml' : 'package.json'; + requireValue(['cargo', 'npm'].includes(carrier.ecosystem), 'unsupported source ecosystem'); + const manifestEntry = entries.get(prefix + manifestName); + requireValue(manifestEntry?.isFile, `missing packed ${manifestName}`); + const manifest = + carrier.ecosystem === 'cargo' + ? (Bun.TOML.parse(utf8.decode(manifestEntry.data())) as any).package + : JSON.parse(utf8.decode(manifestEntry.data())); + requireValue( + manifest?.name === carrier.name && manifest.version === carrier.version, + 'packed candidate name or own version differs from its independent carrier identity', + ); + requireValue( + !Object.hasOwn( + carrier.ecosystem === 'cargo' + ? ((Bun.TOML.parse(utf8.decode(manifestEntry.data())) as any).package?.metadata + ?.oliphaunt ?? {}) + : (manifest.oliphaunt ?? {}), + 'qualificationOnly', + ), + 'qualification-only carrier cannot establish delivery equivalence', + ); + return [...entries.values()] + .map((entry) => { + const packageRoot = entry.isDirectory && entry.name === prefix.slice(0, -1); + requireValue( + packageRoot || entry.name.startsWith(prefix), + `packed member escapes own package: ${entry.name}`, + ); + const member = packageRoot ? '.' : entry.name.slice(prefix.length); + let bytes = entry.isFile ? entry.data() : Buffer.alloc(0); + if (entry.isFile && carrier.ecosystem === 'cargo') { + if (member === 'Cargo.toml' || member === 'Cargo.toml.orig') + bytes = Buffer.from( + cargoOwnVersion(utf8.decode(bytes), carrier.name, carrier.version, member), + ); + else if (member === 'Cargo.lock') + bytes = Buffer.from( + cargoLockOwnVersion(utf8.decode(bytes), carrier.name, carrier.version), + ); + else if (member === '.cargo_vcs_info.json' && cargoVcsCommit === 'provenance-diagnostic') + bytes = Buffer.from(cargoVcsCommitDiagnostic(utf8.decode(bytes))); + } else if (entry.isFile && member === 'package.json') { + bytes = Buffer.from(npmOwnVersion(utf8.decode(bytes), carrier.version)); + } + return { member, file: entry.isFile, mode: entry.mode, sha256: hash(bytes) }; + }) + .sort((left, right) => left.member.localeCompare(right.member, 'en')); +} + +function artifactFile(artifact: any) { + const file = path.resolve(fileURLToPath(new URL('../..', import.meta.url)), artifact.path); + const stat = statSync(file); + requireValue(stat.isFile() && stat.size === artifact.size, 'candidate artifact size differs'); + requireValue(hash(readFileSync(file)) === artifact.sha256, 'candidate artifact bytes differ'); + return file; +} + +/** + * This is a delivery comparison of an existing physical construction candidate. + * It supplies no execution/cache, qualification or historical Bazel provenance. + * A different delivery may contain only a provenance stamp from an unrelated + * commit. Different does not mean needs-release; identical does not qualify a + * changed producer. Release causality remains unverified, including recipe and + * toolchain changes. Callers cannot use this report to select or freeze releases. + */ +export async function compareNativeCompletedSourceDelivery( + candidate: any, + baselines: Record, + { + repository = 'f0rr0/oliphaunt', + readJson = requestGithubRepositoryJson, + assertCompletedPublication = createCompletedPublicationChecker({ repository }), + registryOptions = {}, + cargoVcsCommitDiagnostic: vcsDiagnostic = false, + } = {}, +) { + requireValue( + candidate.scope === 'construction', + 'requires a native physical construction candidate', + ); + requireValue( + fullSha.test(candidate.source?.commit) && fullSha.test(candidate.source?.tree), + 'candidate has no exact source commit/tree', + ); + requireValue( + Array.isArray(candidate.missing) && !candidate.missing.length, + 'candidate inventory is incomplete', + ); + validatePublicationCandidate(candidate); + const products = []; + for (const product of candidate.products) { + const baseline = baselines[product.id]; + if (!baseline) { + products.push({ + product: product.id, + deliveryStatus: 'unknown', + reason: 'missing-completed-publication', + }); + continue; + } + const origin: CompletedPublication = await assertCompletedPublication({ + product: product.id, + ...baseline, + }); + requireValue( + origin.product === product.id && + origin.version === baseline.version && + origin.publicationSha === baseline.publicationSha && + origin.tagName === baseline.tagName && + fullSha.test(origin.publicationTree) && + fullSha.test(origin.releaseSha), + 'completed origin differs from requested product publication', + ); + const sourceText = async (file: string) => { + requireValue( + !file.startsWith('/') && + !file.split('/').some((part) => !part || part === '.' || part === '..'), + 'unsafe historical source path', + ); + const value = await readJson( + `repos/${repository}/contents/${file}?ref=${origin.publicationSha}`, + ); + requireValue( + value.encoding === 'base64' && + typeof value.content === 'string' && + value.type === 'file' && + value.path === file && + fullSha.test(value.sha), + `missing historical ${file}`, + ); + const bytes = Buffer.from(value.content, 'base64'); + requireValue( + createHash('sha1').update(`blob ${bytes.length}\0`).update(bytes).digest('hex') === + value.sha, + `historical ${file} Git blob differs`, + ); + return utf8.decode(bytes); + }; + const descriptor = Bun.TOML.parse(await sourceText(`${product.path}/release.toml`)) as any; + requireValue(descriptor.id === product.id, 'historical descriptor has a different owner'); + const sourceOnly = + Array.isArray(descriptor.release_artifacts) && + descriptor.release_artifacts.length && + descriptor.release_artifacts.every((kind) => ['cargo-crate', 'npm-package'].includes(kind)); + if ( + !sourceOnly || + candidate.productArtifacts.some((artifact) => artifact.product === product.id) + ) { + products.push({ + product: product.id, + origin, + deliveryStatus: 'unknown', + reason: 'first-native-producer-baseline-required', + }); + continue; + } + const carriers = candidate.carriers.filter((carrier) => carrier.product === product.id); + requireValue(carriers.length > 0, 'source product has no physical carriers'); + requireValue( + stable( + carriers + .map(({ ecosystem, name }) => `${ecosystem === 'cargo' ? 'crates' : ecosystem}:${name}`) + .sort(), + ) === stable([...(descriptor.registry_packages ?? [])].sort()), + 'historical source carrier inventory differs; explicit native baseline required', + ); + const changes = []; + for (const current of carriers) { + requireValue( + ['cargo', 'npm'].includes(current.ecosystem) && current.artifacts.length === 1, + 'source product has an unsupported physical carrier', + ); + const raw = `${current.ecosystem === 'cargo' ? 'crates' : 'npm'}:${current.name}`; + requireValue( + descriptor.registry_packages?.includes(raw), + 'historical descriptor does not own this carrier', + ); + requireValue( + current.version === product.version, + 'candidate carrier version differs from owner', + ); + const manifestFile = `${product.path}/${current.ecosystem === 'cargo' ? 'Cargo.toml' : 'package.json'}`; + const manifestText = await sourceText(manifestFile); + const sourceManifest = + current.ecosystem === 'cargo' + ? (Bun.TOML.parse(manifestText) as any).package + : JSON.parse(manifestText); + requireValue( + sourceManifest?.name === current.name && sourceManifest.version === origin.version, + 'published conventional manifest differs from completed carrier identity', + ); + const publishedFile = baseline.archives[current.id]; + requireValue( + typeof publishedFile === 'string', + `missing authenticated published archive for ${current.id}`, + ); + const published = { + ...current, + version: origin.version, + artifacts: [ + { + path: publishedFile, + size: statSync(publishedFile).size, + sha256: hash(readFileSync(publishedFile)), + }, + ], + }; + const before = sourceCarrierMembers(publishedFile, published); + const after = sourceCarrierMembers(artifactFile(current.artifacts[0]), current); + const registryProof = await verifyRegistryCarrierIntegrity(published, registryOptions); + const identity = ({ member, ...row }) => ({ + ...row, + path: member === '.' ? '' : member.replace(/\/$/u, ''), + }); + const differentMembers = differentNativeDeliveredMembers( + before.map(identity), + after.map(identity), + ).map((member) => member || '.'); + const provenanceDiagnostic = vcsDiagnostic + ? { + differentMembers: differentNativeDeliveredMembers( + sourceCarrierMembers(publishedFile, published, { + cargoVcsCommit: 'provenance-diagnostic', + }).map(identity), + sourceCarrierMembers(artifactFile(current.artifacts[0]), current, { + cargoVcsCommit: 'provenance-diagnostic', + }).map(identity), + ).map((member) => member || '.'), + releaseDecision: 'unverified' as const, + } + : undefined; + changes.push({ + carrier: current.id, + currentArtifact: current.artifacts[0], + differentMembers, + registryProof, + ...(provenanceDiagnostic === undefined ? {} : { provenanceDiagnostic }), + }); + } + products.push({ + product: product.id, + origin, + deliveryStatus: changes.some(({ differentMembers }) => differentMembers.length) + ? 'different' + : 'identical', + carriers: changes, + }); + } + return { + scope: 'construction' as const, + releaseDecision: 'unverified' as const, + source: candidate.source, + products, + unverified: [ + 'native producer execution/cache and qualification', + 'completed native configured producer/input provenance', + ], + }; +} + +if (import.meta.main) { + const [candidate, baselines] = process.argv.slice(2); + requireValue( + process.argv.length === 4, + 'usage: native-source-carrier-changes.mts candidate.json baselines.json', + ); + console.log( + JSON.stringify( + await compareNativeCompletedSourceDelivery( + JSON.parse(readFileSync(candidate, 'utf8')), + JSON.parse(readFileSync(baselines, 'utf8')), + ), + null, + 2, + ), + ); +} diff --git a/tools/release/native-source-carrier-changes.test.mts b/tools/release/native-source-carrier-changes.test.mts new file mode 100644 index 000000000..eea742038 --- /dev/null +++ b/tools/release/native-source-carrier-changes.test.mts @@ -0,0 +1,789 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import test, { after } from 'node:test'; +import { fileURLToPath } from 'node:url'; +import { readPortableArchiveEntries } from '../packaging/portable-archive.mts'; +import { tarArchive } from '../packaging/testdata/tar-fixture.mts'; +import { createCompletedPublicationChecker } from './completed-release-publication.mts'; +import { compareNativePreVersionDelivery } from './native-publication-delivery.mts'; +import { + compareNativeCompletedSourceDelivery, + sourceCarrierMembers, +} from './native-source-carrier-changes.mts'; +import { loadPublicationCatalog } from './publication-catalog.mts'; +import { buildPublicationCandidate, freezePublicationCandidate } from './publication-lock.mts'; + +const fixture = fileURLToPath(new URL('./testdata/native-source-carriers/', import.meta.url)); +const captured = JSON.parse(readFileSync(path.join(fixture, 'captured-publication.json'), 'utf8')); +const publicationSha = 'c51052fe8b8ffc7e992266c5ab3d7a63b47441e7'; +const cargo = { ecosystem: 'cargo', name: 'oliphaunt-query', version: '0.1.1' }; +const npm = { ecosystem: 'npm', name: '@oliphaunt/ts-query', version: '0.1.1' }; +const cargoFile = path.join(fixture, 'oliphaunt-query-0.1.1.crate'); +const npmFile = path.join(fixture, 'oliphaunt-ts-query-0.1.1.tgz'); +const baselines = { + 'oliphaunt-query': { + version: '0.1.1', + tagName: 'oliphaunt-query-v0.1.1', + publicationSha, + archives: { 'cargo:oliphaunt-query': cargoFile }, + }, + 'oliphaunt-query-ts': { + version: '0.1.1', + tagName: 'oliphaunt-query-ts-v0.1.1', + publicationSha, + archives: { 'npm:@oliphaunt/ts-query': npmFile }, + }, +}; + +const candidateDirectories: string[] = []; +after(() => { + for (const directory of candidateDirectories) rmSync(directory, { recursive: true, force: true }); +}); + +function environment( + changes: { responses?: any; pullRequests?: any; registryMetadata?: any } = {}, +) { + const responses = changes.responses ?? captured.responses; + const readJson = async (endpoint: string) => { + assert.ok(Object.hasOwn(responses, endpoint), `unexpected GitHub fixture read ${endpoint}`); + return structuredClone(responses[endpoint]); + }; + return { + repository: 'f0rr0/oliphaunt', + readJson, + assertCompletedPublication: createCompletedPublicationChecker({ + repository: 'f0rr0/oliphaunt', + readJson, + listPullRequests: async () => structuredClone(changes.pullRequests ?? captured.pullRequests), + readPages: async () => { + throw new Error('captured recovery history is complete'); + }, + }), + registryOptions: { + cratesIoReadGate: null, + fetchImpl: async (url: string) => { + const metadata = changes.registryMetadata ?? captured.registryMetadata; + if (url === 'https://crates.io/api/v1/crates/oliphaunt-query/0.1.1') + return Response.json(metadata.cargo); + assert.equal(url, 'https://registry.npmjs.org/%40oliphaunt%2Fts-query/0.1.1'); + return Response.json(metadata.npm); + }, + }, + }; +} + +function candidate(roots = [fixture], products = Object.keys(baselines)) { + const versions = new Map( + loadPublicationCatalog('source fixture', { products }).products.map(({ id, version }) => [ + id, + version, + ]), + ); + let artifactRoots = roots; + if (products.some((product) => versions.get(product) !== baselines[product].version)) { + // Keep authenticated historical archives immutable; simulate only current own stamps. + const directory = mkdtempSync(path.join(tmpdir(), 'native-source-current-fixture-')); + candidateDirectories.push(directory); + for (const root of roots) + for (const file of readdirSync(root)) { + if (!/\.(?:crate|tgz)$/u.test(file)) continue; + const product = file.endsWith('.crate') ? 'oliphaunt-query' : 'oliphaunt-query-ts'; + const version = versions.get(product) ?? baselines[product].version; + const rows = archiveRows(path.join(root, file)).map((row) => { + const member = row.name.slice( + file.endsWith('.crate') ? 'oliphaunt-query-0.1.1/'.length : 'package/'.length, + ); + let data = row.data; + if (['Cargo.toml', 'Cargo.toml.orig', 'Cargo.lock'].includes(member)) + data = Buffer.from( + data.toString().replace('version = "0.1.1"', `version = "${version}"`), + ); + else if (row.name === 'package/package.json') + data = Buffer.from( + data.toString().replace('"version": "0.1.1"', `"version": "${version}"`), + ); + return { + ...row, + name: row.name.replace(/^oliphaunt-query-0\.1\.1/u, `oliphaunt-query-${version}`), + data, + }; + }); + writeFileSync(path.join(directory, file), tarArchive(rows)); + } + artifactRoots = [directory]; + } + return { + ...buildPublicationCandidate({ products, artifactRoots }), + scope: 'construction', + }; +} + +function archiveRows(file: string) { + return [...readPortableArchiveEntries(file).values()].map((entry) => ({ + name: entry.name + (entry.isDirectory && !entry.name.endsWith('/') ? '/' : ''), + type: entry.isFile ? '0' : '5', + mode: entry.mode, + data: entry.isFile ? entry.data() : Buffer.alloc(0), + })); +} + +function repack(t: any, file: string, transform: (rows: any[]) => any[]) { + const directory = mkdtempSync(path.join(tmpdir(), 'native-source-carrier-')); + t.after(() => rmSync(directory, { recursive: true, force: true })); + const output = path.join(directory, path.basename(file)); + writeFileSync(output, tarArchive(transform(archiveRows(file)))); + return output; +} + +function differentMembers(before: any[], after: any[]) { + const old = new Map(before.map((row) => [row.member, JSON.stringify(row)])); + const current = new Map(after.map((row) => [row.member, JSON.stringify(row)])); + return [...new Set([...old.keys(), ...current.keys()])] + .filter((name) => old.get(name) !== current.get(name)) + .sort(); +} + +test('authentic completed tagged publications and registry bytes bridge source packages only', async () => { + const input = candidate(); + const report = await compareNativeCompletedSourceDelivery(input, baselines, environment()); + assert.equal(report.scope, 'construction'); + assert.equal(report.releaseDecision, 'unverified'); + assert.deepEqual(report.source, input.source); + assert.deepEqual( + report.products.map(({ deliveryStatus }) => deliveryStatus), + ['identical', 'identical'], + ); + for (const product of report.products) { + assert.equal(product.origin.publicationSha, publicationSha); + assert.equal(product.origin.publicationTree, '59791800860832994b48b8009bb48c5a74a7764e'); + assert.equal(product.origin.releaseSha, '7b192697ff522f71f9c694593d352aa30469cea1'); + assert.deepEqual(product.carriers[0].differentMembers, []); + } + assert.deepEqual( + report.products.map(({ carriers }) => carriers[0].registryProof.registryProof.source), + ['crates.io-version-checksum', 'npm-dist-integrity'], + ); + assert.ok(report.unverified.includes('completed native configured producer/input provenance')); + assert.throws( + () => freezePublicationCandidate({ ...input, comparison: report }), + /construction|qualified producer/u, + ); +}); + +test('pre-version source comparison binds observed physical inventory without admitting fixture qualification', async () => { + const input = candidate(); + const sources = await compareNativeCompletedSourceDelivery(input, baselines, environment()); + // This object exercises binding only; authenticated production observations + // must come from observeNativePublicationConstruction and its real read gate. + const observation: any = { + coverage: { completeProductInventory: true }, + authenticated: [ + { + evidence: { source: input.source }, + qualification: { + source: input.source, + testQualification: 'passed', + requiredTests: [{ label: '//fixture:test', configuration: 'a'.repeat(64) }], + unverified: ['fixture origin is unverified'], + }, + }, + ], + products: input.products.map((product) => ({ + product, + productArtifacts: [], + carriers: structuredClone(input.carriers.filter((carrier) => carrier.product === product.id)), + })), + }; + const result = compareNativePreVersionDelivery({ + source: input.source, + products: Object.keys(baselines), + sources, + observation, + }); + assert.ok( + result.products.every( + ({ deliveryStatus, necessaryDelivery }) => + deliveryStatus === 'identical' && necessaryDelivery === 'unknown', + ), + ); + observation.products[0].carriers[0].artifacts[0].sha256 = 'f'.repeat(64); + assert.throws( + () => + compareNativePreVersionDelivery({ + source: input.source, + products: Object.keys(baselines), + sources, + observation, + }), + /qualified physical envelope/u, + ); +}); + +test('neutralizes only typed Cargo own identity across manifest, original and lock', (t) => { + const updated = repack(t, cargoFile, (rows) => + rows.map((row) => { + const member = row.name.slice('oliphaunt-query-0.1.1/'.length); + const data = ['Cargo.toml', 'Cargo.toml.orig', 'Cargo.lock'].includes(member) + ? Buffer.from(row.data.toString().replace(/version = "0\.1\.1"/u, 'version = "0.2.0"')) + : row.data; + return { + ...row, + name: row.name.replace('oliphaunt-query-0.1.1', 'oliphaunt-query-0.2.0'), + data, + }; + }), + ); + assert.deepEqual( + sourceCarrierMembers(updated, { ...cargo, version: '0.2.0' }), + sourceCarrierMembers(cargoFile, cargo), + ); + const vcs = sourceCarrierMembers(updated, { ...cargo, version: '0.2.0' }).find( + ({ member }) => member === '.cargo_vcs_info.json', + ); + assert.equal( + vcs.sha256, + createHash('sha256') + .update( + readPortableArchiveEntries(cargoFile) + .get('oliphaunt-query-0.1.1/.cargo_vcs_info.json') + .data(), + ) + .digest('hex'), + ); +}); + +test('neutralizes only npm top-level version while preserving other manifest bytes', (t) => { + const updated = repack(t, npmFile, (rows) => + rows.map((row) => + row.name === 'package/package.json' + ? { + ...row, + data: Buffer.from( + row.data.toString().replace('"version": "0.1.1"', '"version": "0.2.0"'), + ), + } + : row, + ), + ); + assert.deepEqual( + sourceCarrierMembers(updated, { ...npm, version: '0.2.0' }), + sourceCarrierMembers(npmFile, npm), + ); + const formatChange = repack(t, npmFile, (rows) => + rows.map((row) => + row.name === 'package/package.json' + ? { ...row, data: Buffer.from(`${row.data.toString()}\n`) } + : row, + ), + ); + assert.deepEqual( + differentMembers(sourceCarrierMembers(npmFile, npm), sourceCarrierMembers(formatChange, npm)), + ['package.json'], + ); +}); + +test('real shipped source, legal, modes, dependency pins and VCS changes remain reasons', (t) => { + const original = [...readPortableArchiveEntries(cargoFile).values()]; + const source = original.find((row) => row.isFile && row.name.endsWith('.rs')).name; + const legal = original.find((row) => row.isFile && /LICENSE|NOTICE/u.test(row.name)).name; + const updated = repack(t, cargoFile, (rows) => + rows.map((row) => { + if (row.name === source) + return { + ...row, + data: Buffer.concat([row.data, Buffer.from('\n// consumed source change\n')]), + }; + if (row.name === legal) return { ...row, mode: 0o600 }; + if (row.name.endsWith('/.cargo_vcs_info.json')) + return { + ...row, + data: Buffer.from( + row.data.toString().replace('79c340949f4121e962741b75d80e686b5ba023c2', publicationSha), + ), + }; + if (row.name.endsWith('/Cargo.lock')) + return { + ...row, + data: Buffer.concat([ + row.data, + Buffer.from( + '\n[[package]]\nname = "held-library"\nversion = "1.0.0"\nsource = "registry+https://github.com/rust-lang/crates.io-index"\n', + ), + ]), + }; + return row; + }), + ); + assert.deepEqual( + differentMembers(sourceCarrierMembers(cargoFile, cargo), sourceCarrierMembers(updated, cargo)), + [ + '.cargo_vcs_info.json', + 'Cargo.lock', + legal.slice('oliphaunt-query-0.1.1/'.length), + source.slice('oliphaunt-query-0.1.1/'.length), + ].sort(), + ); + const npmUpdated = repack(t, npmFile, (rows) => + rows.map((row) => + row.name === 'package/package.json' + ? { + ...row, + data: Buffer.from( + row.data + .toString() + .replace( + '"version": "0.1.1",', + '"version": "0.1.1",\n "dependencies": { "held-library": "=1.0.0" },', + ), + ), + } + : row, + ), + ); + assert.deepEqual( + differentMembers(sourceCarrierMembers(npmFile, npm), sourceCarrierMembers(npmUpdated, npm)), + ['package.json'], + ); +}); + +test('reports actual changed package members through the existing candidate adapter', async (t) => { + const modified = repack(t, cargoFile, (rows) => + rows.map((row) => + row.name.endsWith('/src/lib.rs') + ? { ...row, data: Buffer.concat([row.data, Buffer.from('\n// actual shipped change\n')]) } + : row, + ), + ); + const report = await compareNativeCompletedSourceDelivery( + candidate([path.dirname(modified)], ['oliphaunt-query']), + baselines, + environment(), + ); + assert.equal(report.products[0].deliveryStatus, 'different'); + assert.deepEqual(report.products[0].carriers[0].differentMembers, ['src/lib.rs']); + assert.equal(report.releaseDecision, 'unverified'); +}); + +test('seeded authentic source envelopes compare singleton and many products independently of requested checks', async (t) => { + let seed = 0x93c8079; + const random = () => { + seed = (Math.imul(seed, 1103515245) + 12345) >>> 0; + return seed; + }; + const witnessed = new Set(); + for (let scenario = 0; scenario < 12; scenario++) { + const mask = scenario < 4 ? scenario : (random() >>> 16) % 4; + witnessed.add(mask); + const directory = mkdtempSync(path.join(tmpdir(), 'native-source-many-products-')); + t.after(() => rmSync(directory, { recursive: true, force: true })); + for (const [index, file] of [cargoFile, npmFile].entries()) { + const rows = archiveRows(file).map((row) => { + if (!(mask & (1 << index))) return row; + const member = row.name + .replace(/^oliphaunt-query-0\.1\.1\//u, '') + .replace(/^package\//u, ''); + if (member === 'README.md') + return { + ...row, + data: Buffer.concat([row.data, Buffer.from(`\nShipped documentation ${scenario}\n`)]), + }; + return row; + }); + writeFileSync(path.join(directory, path.basename(file)), tarArchive(rows)); + } + const input = candidate([directory]); + const sources = await compareNativeCompletedSourceDelivery(input, baselines, environment()); + // The request may arise from compiler/helper/input changes. It is separate + // from equality of the actual completed and candidate source envelopes. + const affectedProducts = scenario % 2 ? Object.keys(baselines) : []; + const result = compareNativePreVersionDelivery({ + source: input.source, + products: Object.keys(baselines), + sources, + affectedProducts, + }); + assert.deepEqual( + result.products.map(({ deliveryStatus }) => deliveryStatus), + [mask & 1 ? 'different' : 'identical', mask & 2 ? 'different' : 'identical'], + ); + assert.ok( + result.products.every( + ({ affectedBuild }) => + affectedBuild === (affectedProducts.length ? 'required' : 'not-required'), + ), + ); + assert.ok(result.products.every(({ necessaryDelivery }) => necessaryDelivery === 'unknown')); + assert.equal(result.releaseDecision, 'unverified'); + const singletonSources = await compareNativeCompletedSourceDelivery( + candidate([directory], ['oliphaunt-query']), + baselines, + environment(), + ); + const singleton = compareNativePreVersionDelivery({ + source: input.source, + products: ['oliphaunt-query'], + sources: singletonSources, + affectedProducts: affectedProducts.filter((product) => product === 'oliphaunt-query'), + }); + assert.equal(singleton.products.length, 1); + assert.equal(singleton.products[0].deliveryStatus, mask & 1 ? 'different' : 'identical'); + } + assert.deepEqual([...witnessed].sort(), [0, 1, 2, 3]); +}); + +test('an unrelated-commit provenance stamp differs in delivery without asserting release necessity', async (t) => { + const { commits, sourceTree, scope } = captured.provenanceOnlyExample; + assert.notEqual(commits[0], commits[1]); + assert.match(sourceTree, /^[0-9a-f]{40}$/u); + assert.match(scope, /not configured producer/u); + const updated = repack(t, cargoFile, (rows) => + rows.map((row) => { + if (!row.name.endsWith('/.cargo_vcs_info.json')) return row; + const vcs = JSON.parse(row.data.toString()); + assert.equal(vcs.git.sha1, commits[0]); + return { ...row, data: Buffer.from(row.data.toString().replace(commits[0], commits[1])) }; + }), + ); + const report = await compareNativeCompletedSourceDelivery( + candidate([path.dirname(updated)], ['oliphaunt-query']), + baselines, + { ...environment(), cargoVcsCommitDiagnostic: true }, + ); + assert.equal(report.products[0].deliveryStatus, 'different'); + assert.deepEqual(report.products[0].carriers[0].differentMembers, ['.cargo_vcs_info.json']); + assert.deepEqual(report.products[0].carriers[0].provenanceDiagnostic.differentMembers, []); + assert.equal(report.products[0].carriers[0].provenanceDiagnostic.releaseDecision, 'unverified'); + assert.equal(report.releaseDecision, 'unverified'); + assert.equal(Object.hasOwn(report, 'selectedProducts'), false); + assert.ok(report.unverified.includes('completed native configured producer/input provenance')); + const preVersion = compareNativePreVersionDelivery({ + source: report.source, + products: ['oliphaunt-query'], + sources: report, + affectedProducts: ['oliphaunt-query'], + }); + assert.equal(preVersion.products[0].deliveryStatus, 'different'); + assert.equal(preVersion.products[0].affectedBuild, 'required'); + assert.equal(preVersion.products[0].necessaryDelivery, 'unknown'); +}); + +test('Cargo commit diagnostic retains path, clean state, formatting, modes and member presence', (t) => { + const identity = (file: string) => + sourceCarrierMembers(file, cargo, { cargoVcsCommit: 'provenance-diagnostic' }); + const baseline = identity(cargoFile); + for (const transform of [ + (text: string) => text.replace('src/query/rust', 'src/query/renamed'), + (text: string) => text.replace('"sha1":', '"dirty": false,\n "sha1":'), + (text: string) => `${text}\n`, + ]) { + const changed = repack(t, cargoFile, (rows) => + rows.map((row) => + row.name.endsWith('/.cargo_vcs_info.json') + ? { ...row, data: Buffer.from(transform(row.data.toString())) } + : row, + ), + ); + assert.deepEqual(differentMembers(baseline, identity(changed)), ['.cargo_vcs_info.json']); + } + const mode = repack(t, cargoFile, (rows) => + rows.map((row) => (row.name.endsWith('/.cargo_vcs_info.json') ? { ...row, mode: 0o600 } : row)), + ); + const absent = repack(t, cargoFile, (rows) => + rows.filter((row) => !row.name.endsWith('/.cargo_vcs_info.json')), + ); + assert.deepEqual(differentMembers(baseline, identity(mode)), ['.cargo_vcs_info.json']); + assert.deepEqual(differentMembers(baseline, identity(absent)), ['.cargo_vcs_info.json']); +}); + +test('Cargo provenance diagnostic rejects dirty, invalid, duplicate and unsupported records', (t) => { + const text = readPortableArchiveEntries(cargoFile) + .get('oliphaunt-query-0.1.1/.cargo_vcs_info.json') + .data() + .toString(); + for (const invalid of [ + text.replace('"sha1":', '"dirty": true, "sha1":'), + text.replace('79c340949f4121e962741b75d80e686b5ba023c2', 'invalid'), + text.replace('"sha1":', `"sha1": "${'a'.repeat(40)}", "sha1":`), + text.replace('"path_in_vcs":', '"path_in_vcs": "safe", "path_in_vcs":'), + text.replace('src/query/rust', '../outside'), + text.replace('"sha1":', '"other": 1, "sha1":'), + '{broken', + ]) { + const changed = repack(t, cargoFile, (rows) => + rows.map((row) => + row.name.endsWith('/.cargo_vcs_info.json') ? { ...row, data: Buffer.from(invalid) } : row, + ), + ); + assert.throws(() => + sourceCarrierMembers(changed, cargo, { cargoVcsCommit: 'provenance-diagnostic' }), + ); + } + const malformed = repack(t, cargoFile, (rows) => + rows.map((row) => + row.name.endsWith('/.cargo_vcs_info.json') + ? { ...row, data: Buffer.concat([row.data, Buffer.from([0xff])]) } + : row, + ), + ); + assert.throws( + () => sourceCarrierMembers(malformed, cargo, { cargoVcsCommit: 'provenance-diagnostic' }), + /encoded|UTF/u, + ); +}); + +test('a crate can consume its VCS stamp; diagnostic equality never supplies an inert-source contract', (t) => { + const consumer = repack(t, cargoFile, (rows) => + rows.map((row) => + row.name.endsWith('/src/lib.rs') + ? { + ...row, + data: Buffer.from( + 'pub const COMMIT: &str = include_str!("../.cargo_vcs_info.json");\n', + ), + } + : row, + ), + ); + const changed = repack(t, consumer, (rows) => + rows.map((row) => + row.name.endsWith('/.cargo_vcs_info.json') + ? { + ...row, + data: Buffer.from( + row.data + .toString() + .replace('79c340949f4121e962741b75d80e686b5ba023c2', 'a'.repeat(40)), + ), + } + : row, + ), + ); + assert.deepEqual( + differentMembers(sourceCarrierMembers(consumer, cargo), sourceCarrierMembers(changed, cargo)), + ['.cargo_vcs_info.json'], + ); + assert.deepEqual( + differentMembers( + sourceCarrierMembers(consumer, cargo, { cargoVcsCommit: 'provenance-diagnostic' }), + sourceCarrierMembers(changed, cargo, { cargoVcsCommit: 'provenance-diagnostic' }), + ), + [], + ); + // Diagnostic masking neither authenticates these repacked fixtures nor proves + // the new source's include_str! result is independent of that stamp. +}); + +test('missing origins stay unknown and incomplete candidates fail closed', async () => { + const input = candidate(); + const report = await compareNativeCompletedSourceDelivery(input, {}, environment()); + assert.ok( + report.products.every( + ({ deliveryStatus, reason }) => + deliveryStatus === 'unknown' && reason === 'missing-completed-publication', + ), + ); + const incomplete = structuredClone(input); + incomplete.carriers.pop(); + await assert.rejects( + compareNativeCompletedSourceDelivery(incomplete, baselines, environment()), + /missing carrier set mismatch/u, + ); +}); + +test('a completed source publication cannot supply missing native binary or seed producer facts', async () => { + for (const kind of ['runtime-tree', 'database-seed']) { + const responses = structuredClone(captured.responses); + const descriptor = + responses[`repos/f0rr0/oliphaunt/contents/src/query/rust/release.toml?ref=${publicationSha}`]; + // Deliberately vary the classification input; archive identity is still genuine. + const bytes = Buffer.from( + Buffer.from(descriptor.content, 'base64') + .toString() + .replace( + 'release_artifacts = ["cargo-crate"]', + `release_artifacts = ["cargo-crate", "${kind}"]`, + ), + ); + descriptor.content = bytes.toString('base64'); + descriptor.sha = createHash('sha1') + .update(`blob ${bytes.length}\0`) + .update(bytes) + .digest('hex'); + const report = await compareNativeCompletedSourceDelivery( + candidate([fixture], ['oliphaunt-query']), + baselines, + environment({ responses }), + ); + assert.equal(report.products[0].deliveryStatus, 'unknown'); + assert.equal(report.products[0].reason, 'first-native-producer-baseline-required'); + assert.equal(report.products[0].origin.publicationSha, publicationSha); + assert.equal(report.products[0].carriers, undefined); + } +}); + +test('registry integrity authenticates completed archives independently of the candidate', async (t) => { + const substituted = repack(t, cargoFile, (rows) => + rows.map((row) => + row.name.endsWith('/src/lib.rs') + ? { ...row, data: Buffer.concat([row.data, Buffer.from('\n// counterfeit baseline\n')]) } + : row, + ), + ); + await assert.rejects( + compareNativeCompletedSourceDelivery( + candidate(), + { + ...baselines, + 'oliphaunt-query': { + ...baselines['oliphaunt-query'], + archives: { 'cargo:oliphaunt-query': substituted }, + }, + }, + environment(), + ), + /registry checksum mismatch/u, + ); + const registryMetadata = structuredClone(captured.registryMetadata); + registryMetadata.npm.dist.integrity = 'sha512-invalid'; + await assert.rejects( + compareNativeCompletedSourceDelivery(candidate(), baselines, environment({ registryMetadata })), + /registry integrity mismatch/u, + ); +}); + +test('pending completion and substituted historical Git blobs cannot establish an origin', async () => { + const pending = structuredClone(captured.pullRequests); + pending[0].labels = [{ name: 'autorelease: pending' }]; + await assert.rejects( + compareNativeCompletedSourceDelivery( + candidate(), + baselines, + environment({ pullRequests: pending }), + ), + /publication is not complete/u, + ); + const responses = structuredClone(captured.responses); + responses[ + `repos/f0rr0/oliphaunt/contents/src/query/rust/Cargo.toml?ref=${publicationSha}` + ].content = Buffer.from('[package]\nname="counterfeit"\nversion="0.1.1"\n').toString('base64'); + await assert.rejects( + compareNativeCompletedSourceDelivery(candidate(), baselines, environment({ responses })), + /Git blob differs/u, + ); +}); + +test('own identity, original/lock identity and qualification markers are validated before normalization', (t) => { + assert.throws( + () => sourceCarrierMembers(cargoFile, { ...cargo, version: '0.2.0' }), + /missing packed/u, + ); + for (const member of ['Cargo.toml.orig', 'Cargo.lock']) { + const wrong = repack(t, cargoFile, (rows) => + rows.map((row) => + row.name.endsWith(`/${member}`) + ? { + ...row, + data: Buffer.from( + row.data.toString().replace('version = "0.1.1"', 'version = "9.0.0"'), + ), + } + : row, + ), + ); + assert.throws(() => sourceCarrierMembers(wrong, cargo), /package version differs/u); + } + const cargoQualified = repack(t, cargoFile, (rows) => + rows.map((row) => + row.name.endsWith('/Cargo.toml') + ? { + ...row, + data: Buffer.concat([ + row.data, + Buffer.from('\n[package.metadata.oliphaunt]\nqualificationOnly = false\n'), + ]), + } + : row, + ), + ); + assert.throws(() => sourceCarrierMembers(cargoQualified, cargo), /qualification-only/u); + const npmQualified = repack(t, npmFile, (rows) => + rows.map((row) => + row.name === 'package/package.json' + ? { + ...row, + data: Buffer.from( + row.data + .toString() + .replace( + '"version": "0.1.1",', + '"version": "0.1.1",\n "oliphaunt": { "qualificationOnly": false },', + ), + ), + } + : row, + ), + ); + assert.throws(() => sourceCarrierMembers(npmQualified, npm), /qualification-only/u); +}); + +test('normalization preserves valid replacement characters and rejects malformed UTF-8 bytes', (t) => { + for (const member of ['Cargo.toml', 'Cargo.toml.orig', 'Cargo.lock', 'package.json']) { + const descriptor = member === 'package.json' ? npm : cargo; + const archive = member === 'package.json' ? npmFile : cargoFile; + const packedPath = `${member === 'package.json' ? 'package' : 'oliphaunt-query-0.1.1'}/${member}`; + const valid = repack(t, archive, (rows) => + rows.map((row) => + row.name === packedPath + ? { + ...row, + data: + member === 'package.json' + ? Buffer.from(row.data.toString().replace('{', '{"utf8-proof":"\ufffd",')) + : Buffer.concat([row.data, Buffer.from('\n# UTF-8 proof: \ufffd\n')]), + } + : row, + ), + ); + assert.deepEqual( + differentMembers( + sourceCarrierMembers(archive, descriptor), + sourceCarrierMembers(valid, descriptor), + ), + [member], + ); + const malformed = repack(t, valid, (rows) => + rows.map((row) => { + if (row.name !== packedPath) return row; + const offset = row.data.indexOf(Buffer.from('\ufffd')); + assert.ok(offset >= 0); + return { + ...row, + data: Buffer.concat([ + row.data.subarray(0, offset), + Buffer.from([0xff]), + row.data.subarray(offset + 3), + ]), + }; + }), + ); + assert.throws(() => sourceCarrierMembers(malformed, descriptor), /encoded data was not valid/u); + } +}); + +test('the versioned outer Cargo directory retains its delivered mode', (t) => { + const root = 'oliphaunt-query-0.1.1/'; + const before = repack(t, cargoFile, (rows) => [ + { name: root, type: '5', mode: 0o755, data: '' }, + ...rows.filter(({ name }) => name !== root), + ]); + const after = repack(t, before, (rows) => + rows.map((row) => (row.name === root ? { ...row, mode: 0o700 } : row)), + ); + assert.deepEqual( + differentMembers(sourceCarrierMembers(before, cargo), sourceCarrierMembers(after, cargo)), + ['.'], + ); +}); diff --git a/tools/release/native-supplier-artifacts.mts b/tools/release/native-supplier-artifacts.mts new file mode 100644 index 000000000..07bd8dee5 --- /dev/null +++ b/tools/release/native-supplier-artifacts.mts @@ -0,0 +1,119 @@ +/** Retained completed carrier Files in the existing per-run metadata snapshot. + * Authentication remains with the controller's completed-publication readers. */ +import assert from 'node:assert/strict'; +import path from 'node:path'; +import { validateNativeSupplierPublications } from './bazel-shipping-inputs.mts'; +import type { CompletedPublication } from './completed-release-publication.mts'; +import { fileIdentity, safeRelative } from './native-file-identity.mts'; + +export type NativeSupplierArtifact = { + publication: CompletedPublication; + artifact: string; + /** Git-delivered Swift source; the carrier blob is an anchor, not the full-tree proof. */ + source?: { commit: string; tree: string; member: string; blob: string }; + file: { path: string; size: number; sha256: string }; +}; + +function fields(value: unknown, names: string[], label: string) { + assert.ok( + value && typeof value === 'object' && !Array.isArray(value), + `${label} needs an object`, + ); + assert.deepEqual(Object.keys(value).sort(), names.sort(), `${label} fields differ`); +} + +/** Structural facts only; public identity and bytes are verified by their consumers. */ +export function validateNativeSupplierArtifacts(value: unknown): NativeSupplierArtifact[] { + assert.ok(Array.isArray(value), 'completed supplier artifacts need an array'); + const publications = new Map(); + const keys = new Set(); + return (value as NativeSupplierArtifact[]).map((raw) => { + const sourceTag = + typeof raw?.artifact === 'string' && raw.artifact.startsWith('swift-source-tag:'); + fields( + raw, + ['publication', 'artifact', 'file', ...(sourceTag ? ['source'] : [])], + 'completed supplier artifact', + ); + const publication = validateNativeSupplierPublications([raw.publication])[0]; + assert.match(publication.product, /^[a-z][a-z0-9-]*$/u); + assert.match(publication.version, /^\d+\.\d+\.\d+(?:[-+][A-Za-z0-9.-]+)?$/u); + const owner = `${publication.product}@${publication.version}`; + if (publications.has(owner)) + assert.deepEqual(publication, publications.get(owner), 'completed supplier source differs'); + publications.set(owner, publication); + if (sourceTag) { + assert.equal(publication.product, 'oliphaunt-swift', 'source-tag supplier owner differs'); + assert.equal( + raw.artifact, + `swift-source-tag:${publication.version}`, + 'source-tag supplier version differs', + ); + assert.ok(raw.source, 'completed source-tag origin is missing'); + fields(raw.source, ['commit', 'tree', 'member', 'blob'], 'completed source-tag origin'); + for (const value of [raw.source.commit, raw.source.tree, raw.source.blob]) + assert.match(value, /^[a-f0-9]{40}$/u); + safeRelative(raw.source.member); + } else { + assert.match(raw.artifact, /^(?:cargo|npm|maven|github-release):[^\u0000-\u001f\u007f]+$/u); + safeRelative(raw.artifact.slice(raw.artifact.indexOf(':') + 1)); + } + const key = `${publication.product}/${publication.version}/${raw.artifact}`; + assert.ok(!keys.has(key), 'duplicate completed supplier artifact'); + keys.add(key); + fields(raw.file, ['path', 'size', 'sha256'], 'completed supplier File'); + assert.ok(path.isAbsolute(raw.file.path), 'completed supplier needs an absolute retained File'); + assert.ok(Number.isSafeInteger(raw.file.size) && raw.file.size >= 0); + assert.match(raw.file.sha256, /^[a-f0-9]{64}$/u); + assert.match(path.basename(raw.file.path), /^[A-Za-z0-9][A-Za-z0-9._-]*$/u); + return { + publication, + artifact: raw.artifact, + ...(sourceTag ? { source: structuredClone(raw.source) } : {}), + file: structuredClone(raw.file), + }; + }); +} + +/** Safe File aliases are construction facts, never completed-publication authentication. */ +export function projectNativeSupplierArtifacts(value: unknown) { + const rows = validateNativeSupplierArtifacts(value); + const artifacts: Record = {}; + const files: { source: string; path: string; size: number; sha256: string }[] = []; + const aliases = new Set(); + for (const raw of rows) { + const publication = raw.publication; + const key = `${publication.product}/${publication.version}/${raw.artifact}`; + const basename = path.basename(raw.file.path); + if (raw.artifact.startsWith('github-release:')) + assert.equal( + basename, + raw.artifact.slice('github-release:'.length), + 'completed asset filename differs', + ); + const actual = fileIdentity(raw.file.path); + assert.deepEqual( + { size: actual.size, sha256: actual.sha256 }, + { size: raw.file.size, sha256: raw.file.sha256 }, + 'completed supplier File bytes differ', + ); + const alias = safeRelative( + `supplier-artifacts/${publication.product}/${publication.version}/${raw.file.sha256}/${basename}`, + ); + assert.ok(!aliases.has(alias), 'completed supplier File alias repeats'); + aliases.add(alias); + artifacts[key] = { + publication, + artifact: raw.artifact, + ...(raw.source ? { source: structuredClone(raw.source) } : {}), + file: { ...raw.file, path: `@oliphaunt_metadata//:${alias}` }, + }; + files.push({ + source: raw.file.path, + path: alias, + size: raw.file.size, + sha256: raw.file.sha256, + }); + } + return { artifacts, files }; +} diff --git a/tools/release/native-supplier-artifacts.test.mts b/tools/release/native-supplier-artifacts.test.mts new file mode 100644 index 000000000..cf7cccc50 --- /dev/null +++ b/tools/release/native-supplier-artifacts.test.mts @@ -0,0 +1,291 @@ +import { expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdtempSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { + loadReleaseMetadata, + nativePublicationInputProjection, + renderReleaseMetadata, +} from './bazel-release-metadata.mts'; +import { + projectNativeSupplierArtifacts, + validateNativeSupplierArtifacts, +} from './native-supplier-artifacts.mts'; + +const metadata = loadReleaseMetadata(path.resolve(import.meta.dir, '../..')); +function fixture() { + const directory = mkdtempSync(path.join(os.tmpdir(), 'completed-supplier-alias-')); + const publication = { + product: 'liboliphaunt-native', + version: '9.2.1', + tagName: 'liboliphaunt-native-v9.2.1', + publicationSha: 'a'.repeat(40), + publicationTree: 'b'.repeat(40), + releaseSha: 'c'.repeat(40), + }; + const name = 'liboliphaunt-9.2.1-apple-spm-xcframework.zip'; + const bytes = Buffer.from('controlled physical archive fixture, not authentication'); + const file = { + path: path.join(directory, name), + size: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + }; + writeFileSync(file.path, bytes); + return { directory, row: { publication, artifact: `github-release:${name}`, file } }; +} + +test('canonical old-version Files join the existing snapshot without current-version or producer assumptions', () => { + const { directory, row } = fixture(); + try { + const snapshot = { + source: { commit: 'd'.repeat(40), tree: 'e'.repeat(40) }, + selectedProducts: ['liboliphaunt-native'], + supplierArtifacts: [row], + }; + const projected = nativePublicationInputProjection(snapshot, metadata); + const key = `${row.publication.product}/${row.publication.version}/${row.artifact}`; + expect(projected.supplierArtifacts[key].publication).toEqual(row.publication); + expect(projected.supplierArtifacts[key].file.path).toStartWith( + '@oliphaunt_metadata//:supplier-artifacts/', + ); + expect(projected.files[0]).toEqual({ + source: row.file.path, + path: projected.supplierArtifacts[key].file.path.slice('@oliphaunt_metadata//:'.length), + size: row.file.size, + sha256: row.file.sha256, + }); + const rendered = renderReleaseMetadata(metadata, '@identity//:identity.bzl', projected); + expect(rendered.bzl).toContain('COMPLETED_SUPPLIER_ARTIFACTS ='); + expect(JSON.parse(rendered.completedSupplierArtifacts)).toEqual(projected.supplierArtifacts); + expect(rendered.build).toContain('"completed-supplier-artifacts.json"'); + expect(rendered.build).toContain(projected.files[0].path); + expect(row.file.path).toStartWith(directory); + expect(projectNativeSupplierArtifacts([row]).artifacts[key].publication).toEqual( + row.publication, + ); + expect(() => + nativePublicationInputProjection({ ...snapshot, supplierArtifacts: null }, metadata), + ).toThrow(); + expect(() => + nativePublicationInputProjection( + { ...snapshot, supplierPublications: [{ ...row.publication, releaseSha: 'f'.repeat(40) }] }, + metadata, + ), + ).toThrow(/conflicts/); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('held identities retain structural origin facts without inferring current ownership or authentication', () => { + const { directory, row } = fixture(); + try { + const publication = { + ...row.publication, + product: 'oliphaunt-wasix-napi', + version: '0.3.2', + tagName: 'oliphaunt-wasix-napi-v0.3.2', + }; + const held = { ...row, publication, artifact: 'npm:@oliphaunt/wasix-napi-linux-x64-gnu' }; + const projected = projectNativeSupplierArtifacts([held]); + expect(Object.values(projected.artifacts)[0].publication).toEqual(publication); + expect(projected.files[0].sha256).toBe(row.file.sha256); + const differentOwner = projectNativeSupplierArtifacts([ + { ...held, publication: row.publication }, + ]); + expect(Object.values(differentOwner.artifacts)[0].publication).toEqual(row.publication); + expect(Object.values(differentOwner.artifacts)[0]).not.toHaveProperty('authenticated'); + expect( + Object.values( + projectNativeSupplierArtifacts([{ ...held, artifact: 'npm:@oliphaunt/old-name' }]) + .artifacts, + )[0].artifact, + ).toBe('npm:@oliphaunt/old-name'); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('duplicate, contradictory completion, guessed filename and serialized authentication facts fail closed', () => { + const { directory, row } = fixture(); + try { + const name = 'liboliphaunt-9.2.1-runtime-resources-ios-datum64.tar.gz'; + const file = { ...row.file, path: path.join(directory, name) }; + writeFileSync(file.path, 'controlled physical archive fixture, not authentication'); + for (const rows of [ + [row, row], + [ + row, + { + ...row, + artifact: `github-release:${name}`, + file, + publication: { ...row.publication, publicationTree: 'f'.repeat(40) }, + }, + ], + [{ ...row, artifact: `github-release:${name}` }], + [{ ...row, authenticated: true }], + [{ ...row, publication: { ...row.publication, tagName: 'latest' } }], + [{ ...row, file: { ...row.file, producer: {} } }], + ]) + expect(() => projectNativeSupplierArtifacts(rows)).toThrow(); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('changed bytes, size, traversal and symlink inputs cannot become File aliases', () => { + const { directory, row } = fixture(); + try { + const link = path.join(directory, 'symlink.zip'); + symlinkSync(row.file.path, link); + for (const file of [ + { ...row.file, sha256: '0'.repeat(64) }, + { ...row.file, size: row.file.size + 1 }, + { ...row.file, path: '../archive.zip' }, + { ...row.file, path: link }, + ]) + expect(() => + projectNativeSupplierArtifacts([ + { ...row, artifact: 'npm:@oliphaunt/liboliphaunt-linux-x64-gnu', file }, + ]), + ).toThrow(); + writeFileSync(row.file.path, 'substituted public bytes'); + expect(() => projectNativeSupplierArtifacts([row])).toThrow(/bytes differ/); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +function sourceTagFixture() { + const { directory, row } = fixture(); + return { + directory, + row: { + ...row, + publication: { + ...row.publication, + product: 'oliphaunt-swift', + version: '0.8.2', + tagName: 'oliphaunt-swift-v0.8.2', + }, + artifact: 'swift-source-tag:0.8.2', + source: { + commit: '1'.repeat(40), + tree: '2'.repeat(40), + member: 'src/sdks/swift/Carriers/oliphaunt-react-native-ios-carriers.json', + blob: '3'.repeat(40), + }, + }, + }; +} + +test('retained source-tag Files preserve their distinct Git source and existing snapshot aliases', () => { + const { directory, row } = sourceTagFixture(); + try { + const projected = nativePublicationInputProjection( + { source: { commit: 'd'.repeat(40), tree: 'e'.repeat(40) }, supplierArtifacts: [row] }, + metadata, + ); + const key = `${row.publication.product}/${row.publication.version}/${row.artifact}`; + const alias = projected.supplierArtifacts[key]; + expect(alias.publication).toEqual(row.publication); + expect(alias.source).toEqual(row.source); + expect(alias.source.commit).not.toBe(row.publication.publicationSha); + expect(projected.files[0].source).toBe(row.file.path); + expect(alias.file.path).toBe(`@oliphaunt_metadata//:${projected.files[0].path}`); + const rendered = renderReleaseMetadata(metadata, '@identity//:identity.bzl', projected); + expect(JSON.parse(rendered.completedSupplierArtifacts)[key]).toEqual(alias); + const originalSource = structuredClone(row.source); + row.source.tree = 'f'.repeat(40); + expect(alias.source).toEqual(originalSource); + expect(Object.values(projectNativeSupplierArtifacts([row]).artifacts)[0].source).toEqual( + row.source, + ); + const unpromised = structuredClone(metadata); + unpromised.products['oliphaunt-swift'].publish_targets = ['github-release']; + const oldDeclaration = nativePublicationInputProjection( + { source: { commit: 'd'.repeat(40), tree: 'e'.repeat(40) }, supplierArtifacts: [row] }, + unpromised, + ); + expect(oldDeclaration.supplierArtifacts[key].source).toEqual(row.source); + expect(oldDeclaration.supplierArtifacts[key]).not.toHaveProperty('authenticated'); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('source-tag references require exact namespace, owner, version and safe immutable Git facts', () => { + const { directory, row } = sourceTagFixture(); + try { + const { source: _source, ...missingSource } = row; + for (const bad of [ + missingSource, + { ...row, source: undefined }, + { ...row, source: { ...row.source, authenticated: true } }, + { ...row, artifact: 'swift-source-tag:0.8.3' }, + { + ...row, + publication: { + ...row.publication, + product: 'liboliphaunt-native', + tagName: 'liboliphaunt-native-v0.8.2', + }, + }, + { ...row, artifact: 'github-release:oliphaunt-swift-0.8.2-bindings.xcframework.zip' }, + { ...row, source: { ...row.source, commit: 'main' } }, + { ...row, source: { ...row.source, tree: 'A'.repeat(40) } }, + { ...row, source: { ...row.source, blob: '0'.repeat(64) } }, + { ...row, source: { ...row.source, member: '../carrier.json' } }, + { ...row, source: { ...row.source, member: '/carrier.json' } }, + ]) + expect(() => validateNativeSupplierArtifacts([bad])).toThrow(); + expect(() => projectNativeSupplierArtifacts([row, row])).toThrow(/duplicate/); + writeFileSync(row.file.path, 'substituted retained source delivery'); + expect(() => projectNativeSupplierArtifacts([row])).toThrow(/bytes differ/); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('retired registry and GitHub names remain safe structural Files independently of the current catalog', () => { + const { directory, row } = fixture(); + try { + const artifacts = ( + [ + ['cargo:old-helper-part-linux-x64-00', 'old-helper-part-linux-x64-00-9.2.1.crate'], + ['npm:@oliphaunt/old-name', 'old-name-9.2.1.tgz'], + ['maven:dev.oliphaunt:retired-runtime', 'retired-runtime-9.2.1.jar'], + ['github-release:old-only-platform-name.tar.gz', 'old-only-platform-name.tar.gz'], + ] as const + ).map(([artifact, basename]) => { + const file = { ...row.file, path: path.join(directory, basename) }; + writeFileSync(file.path, 'controlled physical archive fixture, not authentication'); + return { ...row, artifact, file }; + }); + const projected = projectNativeSupplierArtifacts(artifacts); + expect(Object.values(projected.artifacts).map(({ artifact }) => artifact)).toEqual( + artifacts.map(({ artifact }) => artifact), + ); + expect(projected.files).toHaveLength(4); + for (const value of Object.values(projected.artifacts)) { + expect(value.publication).toEqual(row.publication); + expect(value).not.toHaveProperty('authenticated'); + } + for (const bad of [ + 'foreign:old-name', + 'npm:../old-name', + 'github-release:../old-only-platform-name.tar.gz', + 'npm:old\u0000name', + ]) + expect(() => projectNativeSupplierArtifacts([{ ...artifacts[0], artifact: bad }])).toThrow(); + expect(() => + projectNativeSupplierArtifacts([ + { ...artifacts[3], artifact: 'github-release:guessed-name.tar.gz' }, + ]), + ).toThrow('filename differs'); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); diff --git a/tools/release/native-version-source.mts b/tools/release/native-version-source.mts new file mode 100644 index 000000000..b5151d054 --- /dev/null +++ b/tools/release/native-version-source.mts @@ -0,0 +1,204 @@ +/** A version transition is exactly the bytes generated by the frozen candidate. */ +import assert from 'node:assert/strict'; +import { execFileSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import type { NativeBuildSource } from './native-build-qualification.mts'; + +type Identity = { size: number; sha256: string }; +export type NativeVersionUpdate = { path: string; before?: Identity; after: Identity }; +export type NativeVersionSourceBridge = { + source: NativeBuildSource; + updates: NativeVersionUpdate[]; + updatesSha256: string; +}; +const digest = (bytes: Uint8Array) => createHash('sha256').update(bytes).digest('hex'); +const identity = (bytes: Uint8Array): Identity => ({ size: bytes.length, sha256: digest(bytes) }); +const exactFields = (value: object, fields: string[]) => + assert.deepEqual(Object.keys(value).sort(), fields.sort(), 'version transition fields differ'); +const safePath = (file: string) => { + assert.ok( + typeof file === 'string' && + file && + !file.startsWith('/') && + !/[\\\u0000-\u001f\u007f]/u.test(file) && + file.normalize('NFC') === file && + !file.split('/').some((part) => !part || part === '.' || part === '..'), + 'version transition requires a safe repository path', + ); + return file; +}; +const sourceIdentity = (source: NativeBuildSource) => { + exactFields(source, ['commit', 'tree']); + for (const sha of [source.commit, source.tree]) assert.match(sha, /^[a-f0-9]{40}$/u); +}; +const assertIdentity = (value: Identity) => { + exactFields(value, ['size', 'sha256']); + assert.ok(Number.isSafeInteger(value.size) && value.size >= 0); + assert.match(value.sha256, /^[a-f0-9]{64}$/u); +}; + +/** Share this observer with the existing RP and synchronization writers. */ +export function collectNativeVersionUpdates() { + const rows = new Map(); + return { + observe({ + path: file, + before, + after, + }: { + path: string; + before?: Uint8Array; + after: Uint8Array; + }) { + safePath(file); + const previous = rows.get(file); + const beforeIdentity = before === undefined ? undefined : identity(before); + if (previous) + assert.deepEqual( + beforeIdentity, + previous.after, + 'generated update writer changed its preceding bytes', + ); + rows.set(file, { + path: file, + ...((previous ? previous.before : beforeIdentity) === undefined + ? {} + : { before: previous ? previous.before : beforeIdentity }), + after: identity(after), + }); + }, + freeze(source: NativeBuildSource): NativeVersionSourceBridge { + sourceIdentity(source); + const updates = [...rows.values()] + .filter((row) => JSON.stringify(row.before) !== JSON.stringify(row.after)) + .sort((left, right) => left.path.localeCompare(right.path)); + return { + source: structuredClone(source), + updates: structuredClone(updates), + updatesSha256: digest(Buffer.from(JSON.stringify(updates))), + }; + }, + }; +} + +export function validateNativeVersionSourceBridge(bridge: NativeVersionSourceBridge) { + exactFields(bridge, ['source', 'updates', 'updatesSha256']); + sourceIdentity(bridge.source); + assert.ok( + Array.isArray(bridge.updates) && bridge.updates.length > 0, + 'version transition needs actual generated updates', + ); + for (const row of bridge.updates) { + exactFields(row, ['path', 'after', ...(row.before === undefined ? [] : ['before'])]); + safePath(row.path); + if (row.before !== undefined) assertIdentity(row.before); + assertIdentity(row.after); + } + assert.deepEqual( + bridge.updates.map((row) => row.path), + [...new Set(bridge.updates.map((row) => row.path))].sort((left, right) => + left.localeCompare(right), + ), + 'version transition update order differs', + ); + assert.equal( + bridge.updatesSha256, + digest(Buffer.from(JSON.stringify(bridge.updates))), + 'version transition generated update digest differs', + ); + return structuredClone(bridge); +} + +/** No path allowlist can substitute for exact generated content and file modes. */ +export function assertNativeVersionSourceTransition( + bridge: NativeVersionSourceBridge, + finalSource: NativeBuildSource, + directory = process.cwd(), +) { + validateNativeVersionSourceBridge(bridge); + sourceIdentity(finalSource); + const git = (...args: string[]) => + execFileSync('git', args, { cwd: directory, maxBuffer: 64 * 1024 * 1024 }); + for (const source of [bridge.source, finalSource]) + assert.equal( + git('rev-parse', `${source.commit}^{tree}`).toString('utf8').trim(), + source.tree, + 'version transition commit/tree differs', + ); + const changed = git( + 'diff-tree', + '-r', + '--no-commit-id', + '--name-only', + '-z', + bridge.source.tree, + finalSource.tree, + ) + .toString('utf8') + .split('\0') + .filter(Boolean) + .sort((left, right) => left.localeCompare(right)); + assert.deepEqual( + changed, + bridge.updates.map((row) => row.path), + 'version transition contains changes outside the generated updates', + ); + const entry = (source: NativeBuildSource, file: string) => { + const row = git('ls-tree', '-z', source.tree, '--', file).toString('utf8'); + if (!row) return undefined; + const match = /^(100644|100755) blob ([a-f0-9]{40})\t([^\0]+)\0$/u.exec(row); + assert.ok(match && match[3] === file, 'version transition requires regular tracked Files'); + return { mode: match[1], identity: identity(git('cat-file', 'blob', match[2])) }; + }; + for (const update of bridge.updates) { + const before = entry(bridge.source, update.path); + const after = entry(finalSource, update.path); + assert.deepEqual(before?.identity, update.before, 'version transition original bytes differ'); + assert.deepEqual(after?.identity, update.after, 'version transition generated bytes differ'); + assert.equal(after?.mode, before?.mode ?? '100644', 'version transition changed a File mode'); + } + return { source: structuredClone(finalSource), updatesSha256: bridge.updatesSha256 }; +} + +/** Commit only the already observed writers' output, never ambient checkout changes. */ +export function commitNativeVersionUpdates( + bridge: NativeVersionSourceBridge, + title: string, + directory = process.cwd(), +) { + validateNativeVersionSourceBridge(bridge); + assert.match(title, /^chore\(release\): [^\r\n]+$/u); + const git = (...args: string[]) => + execFileSync('git', args, { + cwd: directory, + encoding: 'utf8', + maxBuffer: 64 * 1024 * 1024, + }).trim(); + assert.equal(git('rev-parse', 'HEAD'), bridge.source.commit, 'native candidate source advanced'); + assert.equal( + git('diff', '--cached', '--name-only'), + '', + 'native candidate has ambient staged changes', + ); + const changed = git('diff', '--name-only', '-z').split('\0').filter(Boolean).sort(); + const existingUpdates = bridge.updates + .filter((row) => row.before !== undefined) + .map((row) => row.path) + .sort(); + assert.deepEqual(changed, existingUpdates, 'native candidate has ambient tracked changes'); + for (const row of bridge.updates) { + assert.deepEqual( + identity(readFileSync(path.join(directory, row.path))), + row.after, + 'native candidate generated bytes changed before commit', + ); + } + git('add', '--', ...bridge.updates.map((row) => row.path)); + const bot = JSON.parse(readFileSync(path.join(import.meta.dir, 'release-bot.json'), 'utf8')); + git('-c', `user.name=${bot.name}`, '-c', `user.email=${bot.email}`, 'commit', '-m', title); + const source = { commit: git('rev-parse', 'HEAD'), tree: git('rev-parse', 'HEAD^{tree}') }; + assertNativeVersionSourceTransition(bridge, source, directory); + return source; +} diff --git a/tools/release/native-version-source.test.mts b/tools/release/native-version-source.test.mts new file mode 100644 index 000000000..7bfb1aeb0 --- /dev/null +++ b/tools/release/native-version-source.test.mts @@ -0,0 +1,161 @@ +import { expect, test } from 'bun:test'; +import { execFileSync } from 'node:child_process'; +import { chmodSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { + assertNativeVersionSourceTransition, + collectNativeVersionUpdates, + commitNativeVersionUpdates, +} from './native-version-source.mts'; + +function fixture() { + const directory = mkdtempSync(path.join(tmpdir(), 'native-version-source-')); + const git = (...args: string[]) => + execFileSync('git', args, { cwd: directory, encoding: 'utf8' }).trim(); + const commit = () => { + git('add', '.'); + git( + '-c', + 'user.name=Fixture', + '-c', + 'user.email=fixture@example.invalid', + 'commit', + '-qm', + 'generated versions', + ); + return { commit: git('rev-parse', 'HEAD'), tree: git('rev-parse', 'HEAD^{tree}') }; + }; + git('init', '-q'); + writeFileSync(path.join(directory, 'package.json'), '{"version":"1.0.0"}\n'); + writeFileSync(path.join(directory, 'source.mts'), 'source unchanged\n'); + const source = commit(); + const collector = collectNativeVersionUpdates(); + const write = (file: string, contents: string) => { + let before: Buffer | undefined; + try { + before = readFileSync(path.join(directory, file)); + } catch {} + const after = Buffer.from(contents); + writeFileSync(path.join(directory, file), after); + collector.observe({ path: file, before, after }); + }; + return { + directory, + source, + collector, + write, + commit, + cleanup: () => rmSync(directory, { recursive: true, force: true }), + }; +} + +test('native commit includes only observed updates and leaves unrelated untracked diagnostics alone', () => { + const f = fixture(); + try { + f.write('package.json', '{"version":"1.0.1"}\n'); + f.write('CHANGELOG.md', 'generated notes\n'); + writeFileSync(path.join(f.directory, 'diagnostic.json'), 'private diagnostic\n'); + const bridge = f.collector.freeze(f.source); + const source = commitNativeVersionUpdates( + bridge, + 'chore(release): prepare main releases', + f.directory, + ); + expect(assertNativeVersionSourceTransition(bridge, source, f.directory).source).toEqual(source); + const tracked = execFileSync('git', ['ls-files'], { cwd: f.directory, encoding: 'utf8' }); + expect(tracked).toContain('CHANGELOG.md'); + expect(tracked).not.toContain('diagnostic.json'); + } finally { + f.cleanup(); + } +}); + +for (const fault of ['tracked', 'staged', 'writer-bytes', 'advanced-head'] as const) + test(`native commit rejects ${fault} before staging generated outputs`, () => { + const f = fixture(); + try { + f.write('package.json', '{"version":"1.0.1"}\n'); + const bridge = f.collector.freeze(f.source); + if (fault === 'tracked') + writeFileSync(path.join(f.directory, 'source.mts'), 'ambient change\n'); + if (fault === 'staged') execFileSync('git', ['add', 'package.json'], { cwd: f.directory }); + if (fault === 'writer-bytes') + writeFileSync(path.join(f.directory, 'package.json'), 'unexpected bytes\n'); + if (fault === 'advanced-head') f.commit(); + expect(() => + commitNativeVersionUpdates(bridge, 'chore(release): prepare main releases', f.directory), + ).toThrow(); + } finally { + f.cleanup(); + } + }); + +test('promotion source is exactly the frozen RP and synchronization writes, including a new changelog written twice', () => { + const f = fixture(); + try { + f.write('package.json', '{"version":"1.0.1"}\n'); + f.write('CHANGELOG.md', 'first generated notes\n'); + f.write('CHANGELOG.md', 'final generated notes\n'); + const bridge = f.collector.freeze(f.source); + expect(bridge.updates.find((row) => row.path === 'CHANGELOG.md')?.before).toBeUndefined(); + const after = f.commit(); + expect(assertNativeVersionSourceTransition(bridge, after, f.directory)).toEqual({ + source: after, + updatesSha256: bridge.updatesSha256, + }); + f.source.tree = 'f'.repeat(40); + expect(bridge.source.tree).not.toBe(f.source.tree); + } finally { + f.cleanup(); + } +}); + +for (const fault of [ + 'unrecorded-source', + 'generated-bytes', + 'mode', + 'original-bytes', + 'digest', + 'tree', + 'empty', +] as const) + test(`source promotion rejects ${fault}`, () => { + const f = fixture(); + try { + f.write('package.json', '{"version":"1.0.1"}\n'); + const bridge = f.collector.freeze(f.source); + if (fault === 'unrecorded-source') + writeFileSync(path.join(f.directory, 'source.mts'), 'unreviewed source\n'); + if (fault === 'generated-bytes') + writeFileSync(path.join(f.directory, 'package.json'), '{"version":"9.0.0"}\n'); + if (fault === 'mode') chmodSync(path.join(f.directory, 'package.json'), 0o755); + const after = f.commit(); + if (fault === 'original-bytes') bridge.updates[0].before!.sha256 = 'f'.repeat(64); + if (fault === 'digest') bridge.updatesSha256 = 'f'.repeat(64); + if (fault === 'tree') after.tree = 'f'.repeat(40); + if (fault === 'empty') bridge.updates = []; + expect(() => assertNativeVersionSourceTransition(bridge, after, f.directory)).toThrow(); + } finally { + f.cleanup(); + } + }); + +test('the shared writer observer rejects a changed preimage or unsafe generated path', () => { + const collector = collectNativeVersionUpdates(); + collector.observe({ + path: 'package.json', + before: Buffer.from('old'), + after: Buffer.from('new'), + }); + expect(() => + collector.observe({ + path: 'package.json', + before: Buffer.from('foreign'), + after: Buffer.from('next'), + }), + ).toThrow(/preceding bytes/); + expect(() => collector.observe({ path: '../source.mts', after: Buffer.from('next') })).toThrow( + /safe repository path/, + ); +}); diff --git a/tools/release/normal-publication-plan.test.mts b/tools/release/normal-publication-plan.test.mts index de344acb5..38285595e 100644 --- a/tools/release/normal-publication-plan.test.mts +++ b/tools/release/normal-publication-plan.test.mts @@ -1,8 +1,8 @@ import { describe, expect, test } from 'bun:test'; import { loadPublicationCatalog } from './publication-catalog.mts'; import { extensionSqlNames } from './release-artifact-targets.mts'; -import { buildPlan, loadGraph } from './release-graph.mts'; import { normalPublicationPlan } from './normal-publication-plan.mts'; +import { projectInternalDependencyIds } from './publication-lock.mts'; function carrier({ id, product, publishOrder, dependencies = [] }) { const separator = id.indexOf(':'); @@ -24,10 +24,7 @@ function lock(carriers) { }; } -function realSelection(changedFile) { - const graph = loadGraph('normal-publication-plan.test'); - const release = buildPlan(graph, [changedFile], 'normal-publication-plan.test'); - const publicationProducts = release.releaseProducts; +function selectedCatalog(publicationProducts) { const catalog = loadPublicationCatalog('normal-publication-plan.test', { products: publicationProducts, }); @@ -40,34 +37,18 @@ function realSelection(changedFile) { })), }; return { - release, catalog, topology: normalPublicationPlan(frozen, publicationProducts), }; } describe('normal publication plan', () => { - test('SDK documentation does not select releases while source and explicit inputs do', () => { - const graph = loadGraph('normal-publication-plan.test'); - const files = [ - 'src/native/sdks/rust/README.md', - 'src/native/sdks/ts/README.md', - 'src/native/sdks/swift/README.md', - 'src/native/sdks/kotlin/README.md', - 'src/native/sdks/react-native/README.md', - 'src/wasix/sdks/ts/README.md', - 'src/wasix/sdks/rust/README.md', - 'src/native/sdks/rust/docs/guide.mdx', - ]; - expect(buildPlan(graph, files).releaseProducts).toEqual([]); - expect(buildPlan(graph, [...files, 'src/native/sdks/rust/src/lib.rs']).releaseProducts).toEqual( - ['oliphaunt-kotlin', 'oliphaunt-rust', 'oliphaunt-swift'], - ); - const explicit = { - ...graph, - shared_release_sources: [{ files: [files[0]], products: ['oliphaunt-rust'] }], - }; - expect(buildPlan(explicit, files).releaseProducts).toEqual(['oliphaunt-rust']); + test('the explicit SDK scope publishes its own carriers without expanding consumer owners', () => { + const { catalog, topology } = selectedCatalog(['oliphaunt-rust']); + expect(catalog.products.map(({ id }) => id)).toEqual(['oliphaunt-rust']); + expect(catalog.carriers.length).toBeGreaterThan(0); + expect(catalog.carriers.every(({ product }) => product === 'oliphaunt-rust')).toBe(true); + expect(topology.carrierCount).toBe(catalog.carriers.length); }); test('executes exact frozen carriers in lock-derived dependency order', () => { @@ -191,18 +172,55 @@ describe('normal publication plan', () => { expect(() => normalPublicationPlan(value, ['a', 'b'])).toThrow(/dependency cycle/u); }); - test('real release selections include exact embedded consumers without unrelated products', () => { - const external = realSelection('src/extensions/external/vector/CHANGELOG.md'); - expect(external.release.directProducts).toEqual(['oliphaunt-extension-vector']); - expect(external.release.releaseProducts).toEqual(['oliphaunt-extension-vector']); - expect(external.catalog.products.map(({ id }) => id)).toEqual(external.release.releaseProducts); + test('orders actual packages when current cross-ecosystem relations form a product cycle', () => { + const rows = [ + carrier({ id: 'npm:tools', product: 'tools', publishOrder: 0 }), + carrier({ id: 'cargo:sdk', product: 'sdk', publishOrder: 1 }), + carrier({ id: 'npm:sdk', product: 'sdk', publishOrder: 2 }), + carrier({ id: 'cargo:tools', product: 'tools', publishOrder: 3 }), + ]; + const requirements = { + 'npm:tools': [{ ecosystem: 'npm', name: 'sdk', requirement: '1.0.0', scope: 'runtime' }], + 'cargo:sdk': [{ ecosystem: 'cargo', name: 'tools', requirement: '=1.0.0', scope: 'build' }], + }; + for (const row of rows) { + row.dependencies = projectInternalDependencyIds(rows, requirements[row.id] ?? []); + } + expect( + normalPublicationPlan(lock(rows), ['sdk', 'tools']).operations.map( + ({ carrierId }) => carrierId, + ), + ).toEqual(['npm:sdk', 'npm:tools', 'cargo:tools', 'cargo:sdk']); + }); + + test('a held package requirement does not depend on a newly selected same-name carrier', () => { + const rows = [ + carrier({ id: 'npm:tools', product: 'tools', publishOrder: 0 }), + carrier({ id: 'npm:sdk', product: 'sdk', publishOrder: 1 }), + ]; + const requirements = { + 'npm:tools': [{ ecosystem: 'npm', name: 'sdk', requirement: '1.0.0', scope: 'runtime' }], + 'npm:sdk': [{ ecosystem: 'npm', name: 'tools', requirement: '0.2.4', scope: 'optional' }], + }; + const project = () => { + for (const row of rows) + row.dependencies = projectInternalDependencyIds(rows, requirements[row.id]); + return normalPublicationPlan(lock(rows), ['sdk', 'tools']); + }; + expect(project().operations.map(({ carrierId }) => carrierId)).toEqual([ + 'npm:sdk', + 'npm:tools', + ]); + requirements['npm:sdk'][0].requirement = '1.0.0'; + expect(project).toThrow(/publication unit dependency cycle/u); + }); + + test('canonical selected owners retain their shared carriers and exact publication scope', () => { + const external = selectedCatalog(['oliphaunt-extension-vector']); + expect(external.catalog.products.map(({ id }) => id)).toEqual(['oliphaunt-extension-vector']); expect(external.topology.carrierCount).toBe(external.catalog.carriers.length); - const runtime = realSelection('src/native/runtime/CHANGELOG.md'); - expect(runtime.release.directProducts).toEqual(['liboliphaunt-native']); - expect(runtime.release.releaseProducts).toContain('liboliphaunt-native'); - expect(runtime.release.releaseProducts).not.toContain('liboliphaunt-wasix'); - expect(runtime.release.releaseProducts).not.toContain('oliphaunt-extension-contrib-pg18'); + const runtime = selectedCatalog(['liboliphaunt-native']); expect( extensionSqlNames('oliphaunt-extension-contrib-pg18', 'normal-publication-plan.test'), ).toContain('amcheck'); @@ -211,37 +229,35 @@ describe('normal publication plan', () => { ); expect(contribCarriers.length).toBeGreaterThan(0); expect(contribCarriers.every(({ product }) => product === 'liboliphaunt-native')).toBe(true); - expect(runtime.release.releaseProducts).not.toContain('oliphaunt-extension-vector'); - expect(runtime.release.releaseProducts).toEqual(['liboliphaunt-native']); - expect(runtime.catalog.products.map(({ id }) => id)).toEqual(runtime.release.releaseProducts); + expect(runtime.catalog.products.map(({ id }) => id)).toEqual(['liboliphaunt-native']); expect(runtime.topology.carrierCount).toBe(runtime.catalog.carriers.length); - const contrib = realSelection('src/extensions/contrib/postgres18.toml'); - expect(contrib.release.directProducts).toEqual([ + const contrib = selectedCatalog(['liboliphaunt-native', 'liboliphaunt-wasix']); + expect(contrib.catalog.products.map(({ id }) => id)).toEqual([ 'liboliphaunt-native', 'liboliphaunt-wasix', - 'oliphaunt-wasix-napi', - ]); - expect(contrib.release.releaseProducts).toEqual([ - 'liboliphaunt-native', - 'liboliphaunt-wasix', - 'oliphaunt-wasix-napi', ]); + expect( + [ + ...new Set( + contrib.catalog.carriers + .filter(({ name }) => name.includes('extension-contrib-pg18')) + .map(({ product }) => product), + ), + ].sort(), + ).toEqual(['liboliphaunt-native', 'liboliphaunt-wasix']); - const icu = realSelection('src/database-resources/icu/cargo/src/lib.rs'); - expect(icu.release.directProducts.sort()).toEqual([ - 'database-resources', - 'oliphaunt-wasix-napi', - ]); - expect(icu.release.releaseProducts.sort()).toEqual([ - 'database-resources', + const icu = selectedCatalog(['database-resources']); + expect(icu.catalog.products.map(({ id }) => id)).toEqual(['database-resources']); + + const pgwire = selectedCatalog(['oliphaunt-pgwire-server', 'oliphaunt-wasix-napi']); + expect(pgwire.catalog.products.map(({ id }) => id)).toEqual([ + 'oliphaunt-pgwire-server', 'oliphaunt-wasix-napi', ]); - const sdk = realSelection('src/native/sdks/react-native/CHANGELOG.md'); - expect(sdk.release.directProducts).toEqual(['oliphaunt-react-native']); - expect(sdk.release.releaseProducts).toEqual(['oliphaunt-react-native']); - expect(sdk.catalog.products.map(({ id }) => id)).toEqual(sdk.release.releaseProducts); + const sdk = selectedCatalog(['oliphaunt-react-native']); + expect(sdk.catalog.products.map(({ id }) => id)).toEqual(['oliphaunt-react-native']); expect(sdk.topology.carrierCount).toBe(sdk.catalog.carriers.length); }); }); diff --git a/tools/release/package.json b/tools/release/package.json index 4b2f9ce02..e2676e8e7 100644 --- a/tools/release/package.json +++ b/tools/release/package.json @@ -3,6 +3,7 @@ "private": true, "type": "module", "dependencies": { + "protobufjs": "8.8.1", "release-please": "17.3.0" } } diff --git a/tools/release/platform-compatibility-policy.mts b/tools/release/platform-compatibility-policy.mts index 9450a351f..8101ff1ae 100644 --- a/tools/release/platform-compatibility-policy.mts +++ b/tools/release/platform-compatibility-policy.mts @@ -62,6 +62,7 @@ function androidElfContract(architecture, machine) { ...ELF64_LITTLE_ENDIAN, machine, androidApiLevel: 24, + minimumLoadSegmentAlignment: 16_384, forbiddenRequiredVersionFamilies: FORBIDDEN_ANDROID_VERSION_FAMILIES, }), }); @@ -138,6 +139,13 @@ export function renderPublicPlatformCompatibilityTable() { if (androidArm64 !== androidX64) { throw new Error('published Android targets disagree on the minimum API level'); } + const androidAlignment = + PLATFORM_COMPATIBILITY_POLICY['android-arm64-v8a'].elf.minimumLoadSegmentAlignment; + if ( + androidAlignment !== + PLATFORM_COMPATIBILITY_POLICY['android-x86_64'].elf.minimumLoadSegmentAlignment + ) + throw new Error('published Android targets disagree on the ELF page alignment'); const directMacos = PLATFORM_COMPATIBILITY_POLICY['macos-arm64'].apple.platforms.macos; const xcframework = PLATFORM_COMPATIBILITY_POLICY['ios-xcframework'].apple.platforms; return [ @@ -145,7 +153,7 @@ export function renderPublicPlatformCompatibilityTable() { '| --- | --- |', `| Linux x64/arm64 GNU | Provides binaries requiring at most \`GLIBC_${displayVersion(linuxX64.GLIBC)}\` or \`GLIBCXX_${displayVersion(linuxX64.GLIBCXX)}\`. |`, `| Direct macOS arm64 runtime | Requires macOS ${displayVersion(directMacos.maximumMinimumOs)}. |`, - `| Android \`arm64-v8a\` and \`x86_64\` | Minimum Android API level is ${androidArm64}. |`, + `| Android \`arm64-v8a\` and \`x86_64\` | Minimum Android API level is ${androidArm64}; ELF load segments support ${androidAlignment / 1024} KiB pages. |`, `| Apple XCFramework | Contains macOS arm64, iOS device arm64, and iOS Simulator arm64 slices; minimum targets are macOS ${displayVersion(xcframework.macos.maximumMinimumOs)}, iOS ${displayVersion(xcframework.ios.maximumMinimumOs)}, and iOS Simulator ${displayVersion(xcframework.iosSimulator.maximumMinimumOs)}. |`, '| Windows x64 MSVC | Ships with its required Visual C++ runtime libraries. Windows ARM64 is unavailable. |', ].join('\n'); diff --git a/tools/release/platform-compatibility-policy.test.mts b/tools/release/platform-compatibility-policy.test.mts index 1bbef2916..ab18ca33d 100644 --- a/tools/release/platform-compatibility-policy.test.mts +++ b/tools/release/platform-compatibility-policy.test.mts @@ -84,6 +84,8 @@ describe('platform compatibility policy', () => { PLATFORM_COMPATIBILITY_POLICY['ios-xcframework'].apple.platforms.ios.maximumMinimumOs, ).toEqual([17, 0, 0]); expect(PLATFORM_COMPATIBILITY_POLICY['android-arm64-v8a'].elf.androidApiLevel).toBe(24); + for (const target of ['android-arm64-v8a', 'android-x86_64']) + expect(PLATFORM_COMPATIBILITY_POLICY[target].elf.minimumLoadSegmentAlignment).toBe(16_384); expect( PLATFORM_COMPATIBILITY_POLICY['linux-x64-gnu'].elf.maximumRequiredVersions.GLIBC, ).toEqual([2, 38, 0]); diff --git a/tools/release/prepare-release-candidate.mts b/tools/release/prepare-release-candidate.mts index fbb5e8a66..e34400dd5 100644 --- a/tools/release/prepare-release-candidate.mts +++ b/tools/release/prepare-release-candidate.mts @@ -1,3 +1,4 @@ +import { execFileSync } from 'node:child_process'; import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; import { createRequire } from 'node:module'; import path from 'node:path'; @@ -5,24 +6,59 @@ import { GitHub, Manifest, registerChangelogNotes } from 'release-please'; import { DefaultChangelogNotes } from 'release-please/build/src/changelog-notes/default.js'; import { parseConventionalCommits } from 'release-please/build/src/commit.js'; import { ManifestPlugin } from 'release-please/build/src/plugin.js'; -import { mergeUpdates } from 'release-please/build/src/updaters/composite.js'; import { Changelog } from 'release-please/build/src/updaters/changelog.js'; +import { mergeUpdates } from 'release-please/build/src/updaters/composite.js'; import { GenericJson } from 'release-please/build/src/updaters/generic-json.js'; import { ReleasePleaseManifest } from 'release-please/build/src/updaters/release-please-manifest.js'; -import { appendDependenciesSectionToChangelog } from 'release-please/build/src/plugins/workspace.js'; +import { TagName } from 'release-please/build/src/util/tag-name.js'; import { Version } from 'release-please/build/src/version.js'; -import { defaultExtensionReleasePlan } from './default-extension-release-plan.mts'; -import { syncTomlStringPath } from './sync-release-pr.mts'; +import { loadReleaseMetadata } from './bazel-release-metadata.mts'; +import { readCommitHistory, readCommitPaths } from './commit-paths.mts'; +import { cargoCompatibilityDependency } from './compatibility-version-parser.mts'; +import { createCompletedPublicationChecker } from './completed-release-publication.mts'; +import { + defaultExtensionReleasePlan, + snapshotCurrentExactInputs, +} from './default-extension-release-plan.mts'; +import { requestGithubRepositoryJson } from './github-read.mts'; +import { fileIdentity } from './native-file-identity.mts'; +import { writeNativeReleaseInputs } from './native-release-inputs.mts'; +import { + prepareNativeReleaseDelivery, + qualifiedNativeSeedControls, +} from './native-release-preparation.mts'; +import { + collectNativeVersionUpdates, + commitNativeVersionUpdates, +} from './native-version-source.mts'; +import { sourceIdentity } from './publication-lock.mts'; +import { deriveQualifiedNativeCurrentExactInputs } from './qualified-native-current-exact-inputs.mts'; import { - buildBoundCompatibilityProducts, releaseDependencyPlan, + resolveBuildBoundCompatibilityProducts, } from './release-dependency-plan.mts'; import { buildPlan, compatibilityVersionEntries, - loadGraph, + loadProducts, productCompatibilityVersion, + ROOT, } from './release-graph.mts'; +import { + cargoPathDependencyBindings, + cargoPathDependencyConsumers, + desiredCargoPathDependencyVersion, + syncExampleCargoManifestText, + syncReleasePr, + syncTomlStringPath, +} from './sync-release-pr.mts'; +import { releaseProductsFromManifests } from './verify-release-commit.mts'; + +// Initialize RP's public CommonJS entrypoint before its circular workspace modules. +const { NodeWorkspace } = await import('release-please/build/src/plugins/node-workspace.js'); +const { appendDependenciesSectionToChangelog } = await import( + 'release-please/build/src/plugins/workspace.js' +); // Supply source ownership and public host support intent. Release Please // owns version policy, changelog text and ecosystem updaters in both cases. @@ -31,13 +67,199 @@ export function includeOwnedSourceCommits( github, graph, readCompatibility = productCompatibilityVersion, + options = {}, ) { + const buildBound = resolveBuildBoundCompatibilityProducts(graph.products, options); + const native = Object.hasOwn(options, 'nativeNecessaryProducts'); + if (!native && Object.hasOwn(options, 'nativeCurrentExactInputs')) + throw new Error('current exact inputs require the native necessary decision'); + const nativeCurrentExactInputs = native + ? snapshotCurrentExactInputs(graph.products, options.nativeCurrentExactInputs) + : undefined; + const nativeSelected = new Set(); + const nativeLeaves = new Map>(); + let nativePlan; + let nativeCargoManifests; + if (native) { + const necessary = options.nativeNecessaryProducts; + if ( + !(Array.isArray(necessary) || necessary instanceof Set) || + !Object.hasOwn(options, 'buildBound') || + typeof options.observeNativePlan !== 'function' || + options.nativeObservation?.coverage?.completeProductInventory !== true + ) + throw new Error( + 'native Release Please requires a complete necessary decision and supplier map', + ); + for (const product of necessary) { + if (!Object.hasOwn(graph.products, product) || nativeSelected.has(product)) + throw new Error('native Release Please has unknown or duplicate necessary products'); + nativeSelected.add(product); + } + for (const { product, construction } of options.nativeObservation.products) { + if ( + !Object.hasOwn(graph.products, product.id) || + nativeLeaves.has(product.id) || + !Array.isArray(construction) || + !construction.length + ) + throw new Error('native Release Please lacks exact configured product input coverage'); + const leaves = new Set(); + for (const view of construction) { + if ( + !Array.isArray(view.leafInputPaths) || + view.leafInputPaths.some((file) => typeof file !== 'string' || !file) + ) + throw new Error('native Release Please lacks captured causal source leaves'); + if ( + !Array.isArray(view.analysisInputPaths) || + view.analysisInputPaths.some((file) => typeof file !== 'string' || !file) + ) + throw new Error('native Release Please has unknown loaded recipe version intent'); + for (const file of [...view.leafInputPaths, ...view.analysisInputPaths]) leaves.add(file); + } + nativeLeaves.set(product.id, leaves); + } + // Removed Files still carry the conventional intent of their former owner. + for (const [id, baseline] of Object.entries(options.nativeVersionIntentBaselines ?? {})) { + if (baseline.product.id !== id || !nativeLeaves.has(id)) + throw new Error('native version intent baseline has a different owner'); + for (const view of baseline.construction) + for (const file of [...(view.leafInputPaths ?? []), ...(view.analysisInputPaths ?? [])]) + nativeLeaves.get(id).add(file); + } + if (nativeLeaves.size !== Object.keys(graph.products).length) + throw new Error('native Release Please lacks complete configured product input coverage'); + // Use the pinned workspace extension hooks before it creates any dependency + // updater. A held dependency cannot adopt an independently selected producer. + manifest.plugins = manifest.plugins.map((plugin) => { + if (!(plugin instanceof NodeWorkspace)) return plugin; + return new (class extends NodeWorkspace { + packageProducts = new Map(); + async buildGraph(packages) { + const graph = await super.buildGraph(packages); + this.packageProducts = new Map( + [...graph].map(([name, node]) => [ + name, + this.repositoryConfig[this.pathFromPackage(node.value)].component, + ]), + ); + return graph; + } + buildGraphOrder(graph, names) { + return super + .buildGraphOrder(graph, names) + .filter((pkg) => + nativeSelected.has(this.repositoryConfig[this.pathFromPackage(pkg)].component), + ); + } + updateCandidate(candidate, pkg, versions) { + const consumer = this.repositoryConfig[this.pathFromPackage(pkg)].component; + const adopted = new Set( + [...nativePlan.requirements.values()] + .filter((entry) => entry.product === consumer) + .map((entry) => entry.sourceProduct), + ); + return super.updateCandidate( + candidate, + pkg, + new Map( + [...versions].filter(([name]) => { + const producer = this.packageProducts.get(name); + return ( + name === pkg.name || + buildBound.get(consumer)?.has(producer) || + adopted.has(producer) + ); + }), + ), + ); + } + })(github, 'main', manifest.repositoryConfig, { + logger: plugin.logger, + manifestPath: plugin.manifestPath, + merge: plugin.merge, + updateAllPackages: plugin.updateAllPackages, + alwaysLinkLocal: plugin.alwaysLinkLocal, + updatePeerDependencies: plugin.updatePeerDependencies, + }); + }); + } + const { + readCommitFiles, + commitHistory, + assertCompletedPublication = createCompletedPublicationChecker({ + repository: `${github.repository.owner}/${github.repository.repo}`, + }), + } = options; const observed = []; + const published = new Map(); + const selectedHistory = new Map(); + const releases = github.releaseIterator.bind(github); + github.releaseIterator = async function* (options = {}) { + published.clear(); + for await (const release of releases({ ...options, maxResults: Number.MAX_SAFE_INTEGER })) { + if (release.draft) continue; + published.set(release.tagName, release.sha); + yield release; + } + }; const iterate = github.mergeCommitIterator.bind(github); - github.mergeCommitIterator = async function* (...args) { - for await (const commit of iterate(...args)) { - observed.push(commit); - yield commit; + github.mergeCommitIterator = async function* (branch, options = {}) { + observed.length = 0; + selectedHistory.clear(); + const required = new Set(); + if (commitHistory) { + for (const [ownerPath, config] of Object.entries(manifest.repositoryConfig)) { + const version = manifest.releasedVersions[ownerPath]?.toString(); + const matches = [...published].filter(([name]) => { + const tag = TagName.parse(name); + return tag?.component === config.component && tag.version.toString() === version; + }); + if (version !== '0.0.0' && matches.length !== 1) + throw new Error( + `prepare-release-candidate: ${config.component}@${version} has no unique published release boundary`, + ); + const boundary = version === '0.0.0' ? manifest.bootstrapSha : matches[0][1]; + const selected = commitHistory.after(boundary); + selectedHistory.set(ownerPath, { boundary, selected }); + for (const sha of selected) required.add(sha); + if (boundary) required.add(boundary); + } + } + const seen = new Set(); + // Buffer the exact local ancestry interval before Manifest can stop at a + // delivered release SHA. API history order does not define publication scope. + for await (const commit of iterate(branch, { + ...options, + maxResults: commitHistory?.commits.size ?? Number.MAX_SAFE_INTEGER, + backfillFiles: readCommitFiles ? false : options.backfillFiles, + })) { + if (commitHistory && !commitHistory.commits.has(commit.sha)) + throw new Error( + `prepare-release-candidate: history commit ${commit.sha} is outside the captured source`, + ); + if (seen.has(commit.sha)) + throw new Error(`prepare-release-candidate: duplicate history commit ${commit.sha}`); + seen.add(commit.sha); + const captured = readCommitFiles + ? { ...commit, files: await readCommitFiles(commit.sha) } + : commit; + observed.push(captured); + if (!commitHistory) yield captured; + else { + required.delete(commit.sha); + if (!required.size) break; + } + } + if (commitHistory) { + if (required.size) + throw new Error( + `prepare-release-candidate: API history did not cover captured source commits ${[...required].join(', ')}`, + ); + const order = new Map([...commitHistory.commits].map((sha, index) => [sha, index])); + observed.sort((left, right) => order.get(left.sha) - order.get(right.sha)); + yield* observed; } }; manifest.plugins.push( @@ -46,26 +268,151 @@ export function includeOwnedSourceCommits( releasesByPath; async preconfigure(strategies, commitsByPath, releasesByPath) { + if ( + native && + nativeSelected.size && + !nativeCargoManifests && + Object.values(graph.products).some((product) => + product.registry_packages?.some((name) => name.startsWith('crates:')), + ) + ) { + const read = async (file) => { + try { + const text = (await github.getFileContentsOnBranch(file)).parsedContent; + return { text, manifest: Bun.TOML.parse(text) }; + } catch (error) { + if (error.status === 404) return undefined; + throw error; + } + }; + const workspace = await read('Cargo.toml'); + const files = new Set([ + ...(workspace?.manifest.workspace?.members ?? []).map( + (member) => member + '/Cargo.toml', + ), + ...(workspace?.manifest.workspace?.exclude ?? []).map( + (member) => member + '/Cargo.toml', + ), + ...Object.values(graph.products).flatMap( + (product) => product.embedded_cargo_manifests ?? [], + ), + ]); + nativeCargoManifests = new Map([ + ...(workspace ? [['Cargo.toml', workspace]] : []), + ...( + await Promise.all( + [...files] + .filter((file) => file !== 'Cargo.toml') + .map(async (file) => [file, await read(file)]), + ) + ).filter(([, value]) => value), + ]); + } this.strategies = strategies; this.releasesByPath = releasesByPath; + const seen = new Set(); + for (const commit of observed) { + if (seen.has(commit.sha)) + throw new Error(`prepare-release-candidate: duplicate history commit ${commit.sha}`); + if (!Array.isArray(commit.files)) + throw new Error(`prepare-release-candidate: missing changed files for ${commit.sha}`); + seen.add(commit.sha); + } + const needsBootstrap = Object.keys(manifest.repositoryConfig).some( + (ownerPath) => manifest.releasedVersions[ownerPath]?.toString() === '0.0.0', + ); + if (needsBootstrap && manifest.bootstrapSha && !seen.has(manifest.bootstrapSha)) + throw new Error( + `prepare-release-candidate: history did not reach bootstrap boundary ${manifest.bootstrapSha}`, + ); const owners = new Map( observed.map((commit) => [ commit.sha, - new Set( - buildPlan(graph, commit.files ?? [], 'prepare-release-candidate').releaseProducts, - ), + native + ? new Set( + [...nativeLeaves] + .filter(([, leaves]) => commit.files.some((file) => leaves.has(file))) + .map(([product]) => product), + ) + : new Set( + buildPlan(graph, commit.files ?? [], 'prepare-release-candidate').releaseProducts, + ), ]), ); + const unmappedBreaking = new Set(); + const partiallyMappedBreaking = new Set(); + const knownNativeFiles = new Set([...nativeLeaves.values()].flatMap((files) => [...files])); + const unknownIntent = new Map(); + if (native) + for (const commit of observed) { + const parsed = parseConventionalCommits([commit]); + for (const intent of parsed) { + // Existing conventional component scopes are an explicit intent + // contract, including repository inputs whose Git origin is not + // yet represented by action leaves or loaded BUILD files. + if (intent.scope && Object.hasOwn(graph.products, intent.scope)) + owners.get(commit.sha).add(intent.scope); + else if (intent.notes?.length) { + if (!owners.get(commit.sha).size) unmappedBreaking.add(commit.sha); + else if (commit.files.some((file) => !knownNativeFiles.has(file))) + partiallyMappedBreaking.add(commit.sha); + } + } + } for (const [ownerPath, config] of Object.entries(manifest.repositoryConfig)) { - const boundary = releasesByPath[ownerPath]?.sha; - const selected = new Map( - (commitsByPath[ownerPath] ?? []).map((commit) => [commit.sha, commit]), - ); + const release = releasesByPath[ownerPath]; + const version = manifest.releasedVersions[ownerPath]?.toString(); + if (!version) + throw new Error(`prepare-release-candidate: missing product version for ${ownerPath}`); + if ( + version !== '0.0.0' && + (!release?.sha || published.get(release.tag.toString()) !== release.sha) + ) + throw new Error( + `prepare-release-candidate: ${config.component}@${version} has no published release boundary`, + ); + if (version !== '0.0.0') + await assertCompletedPublication({ + product: config.component, + version, + publicationSha: release.sha, + tagName: release.tag.toString(), + }); + const boundary = release?.sha || (needsBootstrap ? manifest.bootstrapSha : undefined); + const local = selectedHistory.get(ownerPath); + if (local && local.boundary !== boundary) + throw new Error( + `prepare-release-candidate: ${config.component} release boundary changed during capture`, + ); + if (boundary && !seen.has(boundary)) + throw new Error( + `prepare-release-candidate: history did not reach ${config.component} boundary ${boundary}`, + ); + const selected = []; + const unknown = []; for (const commit of observed) { - if (commit.sha === boundary) break; - if (owners.get(commit.sha).has(config.component)) selected.set(commit.sha, commit); + if (local ? !local.selected.has(commit.sha) : commit.sha === boundary) { + if (local) continue; + break; + } + if (unmappedBreaking.has(commit.sha)) unknown.push(commit.sha); + if ( + partiallyMappedBreaking.has(commit.sha) && + !owners.get(commit.sha).has(config.component) && + !options.nativeVersionIntentBaselines?.[config.component] + ) + unknown.push(commit.sha); + if ( + (!native || nativeSelected.has(config.component)) && + owners.get(commit.sha).has(config.component) + ) + selected.push(commit); } - commitsByPath[ownerPath] = observed.filter((commit) => selected.has(commit.sha)); + // A first publication has no prior API to break. Legacy products + // without a captured old footprint need explicit component intent + // when a breaking commit is only partly attributable to known Files. + unknownIntent.set(config.component, version === '0.0.0' ? [] : unknown); + commitsByPath[ownerPath] = selected; } const entries = compatibilityVersionEntries(graph.products, { requireSourceProduct: true }); const hasReleaseIntent = (ownerPath, config) => { @@ -74,16 +421,32 @@ export function includeOwnedSourceCommits( .filter((section) => !section.hidden) .map((section) => section.type), ); + if (!releaseTypes.size) + for (const type of ['feat', 'fix', 'perf', 'refactor', 'revert']) + releaseTypes.add(type); return parseConventionalCommits(commitsByPath[ownerPath] ?? []).some( (commit) => commit.notes?.length || releaseTypes.has(commit.type), ); }; - const workspaceIntent = Object.entries(manifest.repositoryConfig).some( - ([ownerPath, config]) => - config.releaseType === 'rust' && hasReleaseIntent(ownerPath, config), - ); + const addNativeIntent = (product, adoption = false) => { + const ownerPath = graph.products[product].path; + if (unknownIntent.get(product)?.length) + throw new Error( + `native Release Please has unknown breaking acquisition intent for ${product}: ${unknownIntent.get(product).join(', ')}`, + ); + if (!strategies[ownerPath]) + throw new Error(`native Release Please lacks strategy for ${product}`); + if (hasReleaseIntent(ownerPath, manifest.repositoryConfig[ownerPath])) return; + commitsByPath[ownerPath].push({ + sha: '', + files: [], + message: adoption + ? `${graph.products[product].extension?.class === 'external' ? 'fix!' : 'fix'}: align default extension installation` + : 'fix: qualified native delivery changed', + }); + }; + if (native) for (const product of nativeSelected) addNativeIntent(product); const plannedProducts = structuredClone(graph.products); - const compiled = buildBoundCompatibilityProducts(graph.products); // Only these source-selected producers determine public exact host retargets. for (const runtime of ['liboliphaunt-native', 'liboliphaunt-wasix']) { const owner = graph.products[runtime]?.path; @@ -98,6 +461,13 @@ export function includeOwnedSourceCommits( ); if (candidate) plannedProducts[runtime].version = candidate.version.toString(); } + const nativeSupportRequirements = native + ? defaultExtensionReleasePlan(plannedProducts, nativeSelected, { + readCompatibility, + buildBound, + currentExactInputs: nativeCurrentExactInputs, + }).requirements + : undefined; for (const [ownerPath, config] of Object.entries(manifest.repositoryConfig)) { const product = config.component; if (!graph.products[product] || !releasesByPath[ownerPath]) continue; @@ -105,12 +475,16 @@ export function includeOwnedSourceCommits( const runtimeChanged = ['liboliphaunt-native', 'liboliphaunt-wasix'].some( (runtime) => plannedProducts[runtime]?.version !== graph.products[runtime]?.version, ); - if (!releaseIntent && !runtimeChanged && !workspaceIntent) continue; + if (!releaseIntent && !runtimeChanged) continue; const plan = releaseDependencyPlan(plannedProducts, [product], { entries: entries.filter((entry) => entry.product === product && entry.publicSupport), - buildBound: compiled, + buildBound, readValue: (entry) => readCompatibility(entry.product, entry.sourceProduct), }); + for (const entry of plan) { + const adopted = nativeSupportRequirements?.get(`${product}:${entry.sourceProduct}`); + if (adopted) entry.version = adopted.version; + } const changes = plan.flatMap((entry) => { const previous = readCompatibility( product, @@ -155,6 +529,155 @@ export function includeOwnedSourceCommits( return candidate; }; } + if (native) { + this.planNativeRequirements = (products, selected) => { + const plan = defaultExtensionReleasePlan(products, selected, { + readCompatibility, + buildBound, + currentExactInputs: nativeCurrentExactInputs, + }); + if (!nativeCargoManifests) return plan; + // Exact source identities follow actual compiled Files. Cargo ranges + // retain the separate minimum policy below. + for (const entry of entries) { + if ( + !products[entry.product].embedded_cargo_manifests?.length || + !buildBound.get(entry.product).has(entry.sourceProduct) || + (!selected.has(entry.product) && !selected.has(entry.sourceProduct)) + ) + continue; + const conventional = nativeCargoManifests.get(entry.path); + if (conventional && cargoCompatibilityDependency(entry, conventional.text)) continue; + const version = products[entry.sourceProduct].version; + if (readCompatibility(entry.product, entry.sourceProduct) === version) continue; + plan.required.add(entry.product); + plan.requirements.set(`${entry.product}:${entry.sourceProduct}`, { + product: entry.product, + sourceProduct: entry.sourceProduct, + version, + }); + } + const owners = new Map( + Object.entries(products).flatMap(([id, product]) => + (product.registry_packages ?? []) + .filter((name) => name.startsWith('crates:')) + .map((name) => [name.slice(7), id]), + ), + ); + const workspace = nativeCargoManifests.get('Cargo.toml')?.manifest.workspace ?? {}; + const packages = new Map( + [...nativeCargoManifests].flatMap(([file, { manifest }]) => { + if (!manifest.package) return []; + const actual = manifest.package; + const owner = owners.get(actual.name); + const version = owner + ? products[owner].version + : actual.version?.workspace === true + ? workspace.package?.version + : actual.version; + return typeof actual.name === 'string' && typeof version === 'string' + ? [[path.resolve(ROOT, file), [actual.name, version]]] + : []; + }), + ); + for (const [file, { text, manifest }] of nativeCargoManifests) { + for (const binding of cargoPathDependencyBindings( + text, + path.resolve(ROOT, file), + packages, + )) { + const declaration = binding.entryParts.reduce( + (value, key) => value?.[key], + manifest, + ); + const input = path.resolve( + ROOT, + path.dirname(file), + declaration.path, + 'Cargo.toml', + ); + const sourceProduct = owners.get(packages.get(input)?.[0]); + if (!selected.has(sourceProduct)) continue; + const consumers = cargoPathDependencyConsumers( + file, + manifest, + nativeCargoManifests, + owners, + binding, + products, + ); + binding.expected = desiredCargoPathDependencyVersion( + declaration.version, + products[sourceProduct].version, + consumers.some((product) => selected.has(product)), + ); + if (declaration.version === binding.expected) continue; + // A changed normalized public Cargo requirement is a changed + // source envelope. Private build/test manifests need a coherent + // checkout without inventing another public delivery. + const affected = consumers.filter( + (product) => + selected.has(product) || + buildBound.get(product).has(sourceProduct) || + products[product].registry_packages?.some((name) => name.startsWith('crates:')), + ); + for (const product of new Set(affected.length ? affected : [null])) { + if (product) plan.required.add(product); + plan.requirements.set( + 'cargo:' + file + ':' + JSON.stringify(binding.entryParts) + ':' + product, + { + product, + sourceProduct, + version: products[sourceProduct].version, + path: file, + binding, + }, + ); + } + } + } + return plan; + }; + const predicted = structuredClone(graph.products); + const previewed = new Set(); + for (;;) { + for (const product of nativeSelected) { + if (previewed.has(product)) continue; + const ownerPath = graph.products[product].path; + let commits = parseConventionalCommits(commitsByPath[ownerPath]); + for (const plugin of manifest.plugins) commits = plugin.processCommits(commits); + const candidate = await strategies[ownerPath].buildReleasePullRequest( + commits, + releasesByPath[ownerPath], + manifest.draftPullRequest, + manifest.labels, + ); + if (!candidate) + throw new Error(`native necessary delivery produced no candidate: ${product}`); + predicted[product].version = candidate.version.toString(); + previewed.add(product); + } + nativePlan = this.planNativeRequirements(predicted, nativeSelected); + const missing = [...nativePlan.required].filter( + (product) => !nativeSelected.has(product), + ); + if (!missing.length) break; + for (const product of missing) { + nativeSelected.add(product); + addNativeIntent(product, true); + } + } + await options.observeNativePlan( + Object.freeze({ + selectedProducts: Object.freeze([...nativeSelected].sort()), + requirements: Object.freeze( + [...nativePlan.requirements.values()].map((entry) => + Object.freeze(structuredClone(entry)), + ), + ), + }), + ); + } return strategies; } @@ -168,7 +691,24 @@ export function includeOwnedSourceCommits( products[product].version = candidate.pullRequest.version.toString(); selected.add(product); } - plan = defaultExtensionReleasePlan(products, selected, { readCompatibility }); + if (native) { + if ( + selected.size !== nativeSelected.size || + [...selected].some((product) => !nativeSelected.has(product)) + ) + throw new Error('native Release Please escaped its frozen necessary/adoption scope'); + plan = this.planNativeRequirements(products, selected); + if ( + [...plan.required].some((product) => !nativeSelected.has(product)) || + JSON.stringify([...plan.requirements]) !== + JSON.stringify([...nativePlan.requirements]) + ) + throw new Error('native Release Please changed its admitted adoption plan'); + } else + plan = defaultExtensionReleasePlan(products, selected, { + readCompatibility, + buildBound, + }); const missing = [...plan.required].filter((product) => !selected.has(product)); if (!missing.length) break; for (const product of missing) { @@ -209,7 +749,8 @@ export function includeOwnedSourceCommits( const changes = [...plan.requirements.values()].filter( (entry) => entry.product === product, ); - for (const { sourceProduct, version } of changes) { + for (const { sourceProduct, version, binding } of changes) { + if (binding) continue; for (const entry of entries.filter( (entry) => entry.product === product && entry.sourceProduct === sourceProduct, )) { @@ -230,9 +771,10 @@ export function includeOwnedSourceCommits( } if (!changes.length) continue; const notes = changes - .map( - ({ sourceProduct, version }) => - `* Require ${sourceProduct}@${version} for the default extension install.`, + .map(({ sourceProduct, version, binding }) => + binding + ? `* Update the local Cargo requirement for ${binding.name} to ${binding.expected}.` + : `* Require ${sourceProduct}@${version} for the default extension install.`, ) .join('\n'); for (const update of candidate.pullRequest.updates) { @@ -245,6 +787,32 @@ export function includeOwnedSourceCommits( for (const release of candidate.pullRequest.body.releaseData) release.notes = appendDependenciesSectionToChangelog(release.notes, notes); } + if (native) { + const written = new Set(); + for (const requirement of plan.requirements.values()) { + if (!requirement.binding) continue; + const key = requirement.path + ':' + JSON.stringify(requirement.binding.entryParts); + if (written.has(key)) continue; + written.add(key); + const candidate = candidates.find( + (candidate) => + this.repositoryConfig[candidate.path].component === requirement.sourceProduct, + ); + if (!candidate) throw new Error('native Cargo requirement has no selected producer'); + candidate.pullRequest.updates.push({ + path: requirement.path, + createIfMissing: false, + updater: { + updateContent: (content) => + syncExampleCargoManifestText(content, { + policy: {}, + bindings: [requirement.binding], + label: requirement.path, + }).text, + }, + }); + } + } return candidates; } })(github, 'main', manifest.repositoryConfig), @@ -269,7 +837,27 @@ export function useSourceDate(sourceDate) { ); } -export function applyCandidate(root, candidate) { +export function bindReleaseSourceHistory( + github, + commitHistory, + sha, + readSource = () => + requestGithubRepositoryJson( + `repos/${github.repository.owner}/${github.repository.repo}/git/ref/heads/main`, + ), +) { + if (commitHistory.head !== sha) + throw new Error('captured Git history does not match the release source'); + const iterate = github.mergeCommitIterator.bind(github); + github.mergeCommitIterator = async function* (...args) { + const source = await readSource(); + if (source.object?.sha !== sha) + throw new Error('main changed before Release Please history capture'); + yield* iterate(...args); + }; +} + +export function applyCandidate(root, candidate, observeUpdate = undefined) { const changed = []; for (const update of mergeUpdates(candidate.updates)) { const destination = path.resolve(root, update.path); @@ -281,6 +869,11 @@ export function applyCandidate(root, candidate) { if (after && after !== before) { mkdirSync(path.dirname(destination), { recursive: true }); writeFileSync(destination, after); + observeUpdate?.({ + path: update.path, + before: before === undefined ? undefined : Buffer.from(before), + after: Buffer.from(after), + }); changed.push(update.path); } } @@ -294,6 +887,9 @@ async function main() { const repository = process.env.GITHUB_REPOSITORY; if (!destination || !/^[0-9a-f]{40}$/u.test(sha ?? '') || repository !== 'f0rr0/oliphaunt') throw new Error('candidate generation requires an exact canonical source and output directory'); + const nativeRun = process.env.NATIVE_QUALIFICATION_RUN_ID; + if (!/^[1-9][0-9]*$/u.test(nativeRun ?? '') || !Number.isSafeInteger(Number(nativeRun))) + throw new Error('native preparation requires an exact positive qualification run ID'); useSourceDate(process.env.RELEASE_SOURCE_DATE); const [owner, repo] = repository.split('/'); const github = await GitHub.create({ @@ -312,23 +908,87 @@ async function main() { // File reads use the exact source even if main advances during API pagination. const getFile = github.getFileContentsOnBranch.bind(github); github.getFileContentsOnBranch = (file) => getFile(file, sha); - const iterate = github.mergeCommitIterator.bind(github); - github.mergeCommitIterator = async function* (...args) { - let first = true; - for await (const commit of iterate(...args)) { - if (first && commit.sha !== sha) - throw new Error('main changed before Release Please history capture'); - first = false; - yield commit; - } - if (first) throw new Error('Release Please returned no source history'); - }; + const commitHistory = readCommitHistory(); + bindReleaseSourceHistory(github, commitHistory, sha); const manifest = await Manifest.fromManifest(github, 'main'); - includeOwnedSourceCommits(manifest, github, loadGraph('prepare-release-candidate')); + const graph = { products: loadProducts('prepare-release-candidate') }; + const versionUpdates = collectNativeVersionUpdates(); + let nativeFinalProducts: string[] | undefined; + const native = await prepareNativeReleaseDelivery({ + source: sourceIdentity(sha), + runId: Number(nativeRun), + completedVersions: Object.fromEntries( + Object.entries(graph.products).map(([product, metadata]) => [ + product, + manifest.releasedVersions[metadata.path]?.toString(), + ]), + ), + directory: path.join(destination, 'native'), + }); + const nativeCurrentExactInputs = deriveQualifiedNativeCurrentExactInputs( + native, + loadReleaseMetadata(root), + ); + includeOwnedSourceCommits(manifest, github, graph, undefined, { + readCommitFiles: readCommitPaths, + commitHistory, + buildBound: native.suppliers.buildBound, + nativeNecessaryProducts: native.decision.selectedProducts, + nativeObservation: native.observation, + nativeVersionIntentBaselines: native.shippingBaselines, + nativeCurrentExactInputs, + observeNativePlan: async ({ selectedProducts, requirements }) => { + const necessary = new Set(native.decision.selectedProducts); + if ( + !Array.isArray(selectedProducts) || + new Set(selectedProducts).size !== selectedProducts.length || + selectedProducts.some((product) => !graph.products[product]) || + [...necessary].some((product) => !selectedProducts.includes(product)) + ) + throw new Error('native final release set differs from the qualified necessary products'); + for (const product of selectedProducts.filter((product) => !necessary.has(product))) { + const declaredRetarget = [...requirements.values()].some( + (entry) => entry.product === product, + ); + const currentEmbedding = [...native.suppliers.buildBound.get(product)].some((supplier) => + selectedProducts.includes(supplier), + ); + if (!declaredRetarget && !currentEmbedding) + throw new Error( + `native ${product} has no explicit default-install or current-embedding adoption`, + ); + } + for (const requirement of requirements.values()) { + if ( + requirement.product !== 'database-resources' || + requirement.sourceProduct !== 'liboliphaunt-wasix' + ) + continue; + if ( + !nativeCurrentExactInputs.some( + (pair) => + pair.product === requirement.product && + pair.sourceProduct === requirement.sourceProduct, + ) || + !selectedProducts.includes(requirement.product) || + !selectedProducts.includes(requirement.sourceProduct) + ) + throw new Error( + 'native current exact requirement lacks its authenticated two-profile consumer contract', + ); + } + const selected = [...selectedProducts].sort(); + if (nativeFinalProducts && JSON.stringify(nativeFinalProducts) !== JSON.stringify(selected)) + throw new Error('native final release set changed after its fixed point'); + nativeFinalProducts = selected; + }, + }); const candidates = await manifest.buildPullRequests(); if (candidates.length > 1) throw new Error('expected one grouped Release Please candidate'); mkdirSync(destination, { recursive: true }); if (!candidates.length) { + if (native.decision.selectedProducts.length) + throw new Error('native necessary delivery produced no release candidate'); writeFileSync(path.join(destination, 'required'), 'false\n'); return; } @@ -338,7 +998,96 @@ async function main() { candidate.title.toString() !== 'chore(release): prepare main releases' ) throw new Error('unexpected Release Please branch/title'); - applyCandidate(root, candidate); + if (!nativeFinalProducts) + throw new Error('native candidate did not freeze its compatible product set'); + applyCandidate(root, candidate, versionUpdates.observe); + await syncReleasePr([], { + buildBound: native.suppliers.buildBound, + observeUpdate: versionUpdates.observe, + }); + const bridge = versionUpdates.freeze(native.candidate.source); + const before = JSON.parse( + execFileSync('git', ['show', `${bridge.source.commit}:.release-please-manifest.json`], { + cwd: root, + encoding: 'utf8', + }), + ); + const after = JSON.parse(readFileSync(path.join(root, '.release-please-manifest.json'), 'utf8')); + const config = JSON.parse(readFileSync(path.join(root, 'release-please-config.json'), 'utf8')); + if ( + JSON.stringify(releaseProductsFromManifests(config, before, after)) !== + JSON.stringify(nativeFinalProducts) + ) + throw new Error('native generated manifest differs from the frozen release set'); + const preparedSource = commitNativeVersionUpdates(bridge, candidate.title.toString(), root); + const record = { + bridge, + selectedProducts: nativeFinalProducts, + preparedSource, + buildBound: [...native.suppliers.buildBound] + .sort(([left], [right]) => left.localeCompare(right)) + .map(([consumer, suppliers]) => [consumer, [...suppliers].sort()] as [string, string[]]), + }; + const supplierArtifacts = [...(native.publicationInputs.snapshot.supplierArtifacts ?? [])]; + const finalConsumer = loadReleaseMetadata(root).databaseResourceWasixConsumer; + if (nativeCurrentExactInputs.length && finalConsumer?.source === 'completed') { + // An independent core-only release leaves the resource's old exact request + // held. Its genuine baseline archive was already acquired and proved. + const baseline = native.baselines.find( + ({ publication }) => + publication.product === 'liboliphaunt-wasix' && + publication.version === finalConsumer.version, + ); + const rows = native.candidate.productArtifacts.filter( + (artifact) => + artifact.product === 'liboliphaunt-wasix' && + artifact.kind === 'wasix-runtime' && + artifact.target === 'portable', + ); + if (!baseline || rows.length !== 1) + throw new Error('native held WASIX consumer has no exact completed baseline'); + const artifact = rows[0]; + const original = native.completedPublicFiles.filter( + (file) => file.path === baseline.productArtifacts?.[artifact.id], + ); + if (original.length !== 1) + throw new Error('native held WASIX archive is absent from its original public transport'); + const actual = fileIdentity(original[0].path); + if (actual.size !== original[0].size || actual.sha256 !== original[0].sha256) + throw new Error('native held WASIX archive changed after public authentication'); + if ( + !supplierArtifacts.some( + (row) => + row.publication.product === baseline.publication.product && + row.publication.version === baseline.publication.version && + row.artifact === artifact.id, + ) + ) + supplierArtifacts.push({ + publication: baseline.publication, + artifact: artifact.id, + file: { path: original[0].path, size: actual.size, sha256: actual.sha256 }, + }); + } + writeNativeReleaseInputs( + path.join(destination, 'native-release-inputs'), + record, + qualifiedNativeSeedControls(native, bridge, preparedSource, root), + [ + ...new Map( + [ + ...native.baselines.map(({ publication }) => publication), + ...native.publicationInputs.snapshot.supplierPublications, + ].map((publication) => [`${publication.product}@${publication.version}`, publication]), + ).values(), + ], + supplierArtifacts, + ); + writeFileSync( + path.join(destination, 'native-version-source.json'), + `${JSON.stringify(record)}\n`, + { flag: 'wx' }, + ); writeFileSync(path.join(destination, 'required'), 'true\n'); writeFileSync(path.join(destination, 'title'), `${candidate.title.toString()}\n`); writeFileSync(path.join(destination, 'body.md'), `${candidate.body.toString()}\n`); diff --git a/tools/release/prepare-release-candidate.test.mts b/tools/release/prepare-release-candidate.test.mts index e906ecfa3..c9a067389 100644 --- a/tools/release/prepare-release-candidate.test.mts +++ b/tools/release/prepare-release-candidate.test.mts @@ -17,9 +17,11 @@ import { Manifest } from 'release-please'; import { ManifestPlugin } from 'release-please/build/src/plugin.js'; import { mergeUpdates } from 'release-please/build/src/updaters/composite.js'; import { Version } from 'release-please/build/src/version.js'; +import { readCommitHistory, readCommitPaths } from './commit-paths.mts'; import { frozenConsumerMatrix, frozenConsumerPlan } from './frozen-consumer.mts'; import { applyCandidate, + bindReleaseSourceHistory, includeOwnedSourceCommits, useSourceDate, } from './prepare-release-candidate.mts'; @@ -29,12 +31,19 @@ import { buildPlan, compatibilityVersionEntries, compatibilityVersionFromText, - compatibilityVersionValue, declaredSharedSourceImpacts, loadGraph, productCompatibilityVersion, ROOT, } from './release-graph.mts'; +import { + fixtureCompletionChecker, + generateHistoryCandidate, + generateProductCandidateForGraph, + historyProducts, + historyShared, + historyVersionUpdates, +} from './testdata/prepare-release-candidate-fixtures.mts'; const graph = loadGraph('prepare-release-candidate.test'); const native = 'src/native/runtime'; @@ -55,30 +64,21 @@ test('extension facade generator changes select every product shipping its outpu ).toEqual(['liboliphaunt-native', ...products].sort()); }); -test('every binary release includes its compiled sources across product boundaries', () => { +test('binary releases include local compiled sources and retain independent registry dependencies', () => { const mobile = ['oliphaunt-swift', 'oliphaunt-kotlin']; for (const [file, products] of [ - ['src/wasix/sdks/rust/src/oliphaunt/base.rs', ['oliphaunt-wasix-rust', 'oliphaunt-wasix-napi']], + ['src/wasix/sdks/rust/src/oliphaunt/base.rs', ['oliphaunt-wasix-rust']], ['src/wasix/pgwire-server/src/lib.rs', ['oliphaunt-pgwire-server', 'oliphaunt-wasix-napi']], - [ - 'src/query/rust/src/lib.rs', - ['oliphaunt-query', 'oliphaunt-broker', 'oliphaunt-wasix-napi', ...mobile], - ], - ['src/wasix/runtime/crates/assets/src/lib.rs', ['liboliphaunt-wasix', 'oliphaunt-wasix-napi']], - ['src/wasix/runtime/toolchain.toml', ['liboliphaunt-wasix', 'oliphaunt-wasix-napi']], - [ - 'src/wasix/postgres-tools/crates/tools/build-support.rs', - ['postgres-tools-wasix', 'oliphaunt-wasix-napi'], - ], - ['src/database-resources/icu/cargo/src/lib.rs', ['database-resources', 'oliphaunt-wasix-napi']], - [ - 'src/native/rust-bindings/src/lib.rs', - ['liboliphaunt-native-bindings', 'oliphaunt-broker', 'oliphaunt-node-direct', ...mobile], - ], - ['src/native/broker/src/lib.rs', ['oliphaunt-broker', ...mobile]], + ['src/query/rust/src/lib.rs', ['oliphaunt-query']], + ['src/wasix/runtime/crates/assets/src/lib.rs', ['liboliphaunt-wasix']], + ['src/wasix/runtime/toolchain.toml', ['liboliphaunt-wasix']], + ['src/wasix/postgres-tools/crates/tools/build-support.rs', ['postgres-tools-wasix']], + ['src/database-resources/icu/cargo/src/lib.rs', ['database-resources']], + ['src/native/rust-bindings/src/lib.rs', ['liboliphaunt-native-bindings']], + ['src/native/broker/src/lib.rs', ['oliphaunt-broker']], ['src/native/sdks/rust/src/lib.rs', ['oliphaunt-rust', ...mobile]], ['src/native/mobile-bindings/src/lib.rs', mobile], - ['src/native/sdks/rust/crates/oliphaunt-build/src/lib.rs', ['oliphaunt-rust', ...mobile]], + ['src/native/sdks/rust/crates/oliphaunt-build/src/lib.rs', ['oliphaunt-rust']], ]) { const plan = buildPlan(graph, [file]); expect(plan.releaseProducts.sort()).toEqual(products.sort()); @@ -106,7 +106,6 @@ test('every binary release includes its compiled sources across product boundari 'oliphaunt-kotlin', 'oliphaunt-node-direct', 'oliphaunt-swift', - 'oliphaunt-wasix-napi', ]); } }); @@ -183,13 +182,15 @@ test('Cargo owns transitive, inherited, renamed, build, target and custom source } }); -test('embedded generated payloads follow private producer ownership for source-pin changes', () => { - for (const file of ['src/third-party/postgres/source.toml', 'src/third-party/icu/source.toml']) { - expect(existsSync(path.join(ROOT, file))).toBe(true); - const plan = buildPlan(graph, [file]); - expect(plan.releaseProducts).toContain('liboliphaunt-wasix'); - expect(plan.releaseProducts).toContain('oliphaunt-wasix-napi'); - } +test('upstream source pins retain conservative legacy project scope independently of held payload declarations', () => { + const postgres = buildPlan(graph, ['src/third-party/postgres/source.toml']); + expect(postgres.releaseProducts).toContain('liboliphaunt-wasix'); + expect(postgres.releaseProducts).not.toContain('oliphaunt-wasix-napi'); + const icu = buildPlan(graph, ['src/third-party/icu/source.toml']); + expect(icu.releaseProducts).toContain('liboliphaunt-wasix'); + // Legacy Moon private-project traversal still includes the addon for ICU; + // this conservative scope does not retarget its registry-installed payloads. + expect(icu.releaseProducts).toContain('oliphaunt-wasix-napi'); }); async function generate(commits, baselines = { [native]: first, [wasix]: first }) { @@ -243,10 +244,17 @@ async function generate(commits, baselines = { [native]: first, [wasix]: first } }, { separatePullRequests: false, + // biome-ignore lint/suspicious/noTemplateCurlyInString: Release Please expands this title pattern. groupPullRequestTitlePattern: 'chore(release): prepare ${branch} releases', }, ); - includeOwnedSourceCommits(manifest, github, graph); + includeOwnedSourceCommits(manifest, github, graph, undefined, { + assertCompletedPublication: fixtureCompletionChecker( + config, + manifest.releasedVersions, + baselines, + ), + }); return manifest.buildPullRequests(); } @@ -317,61 +325,314 @@ test('shared source qualification respects each owner release boundary and ignor ).toEqual([`${native}/VERSION`]); }); -async function generateProductCandidate( - commits, - readCompatibility = (product, source) => productCompatibilityVersion(product, source), - configure = () => {}, - { root = ROOT, baseline = first } = {}, -) { - const config = JSON.parse(readFileSync(path.join(root, 'release-please-config.json'), 'utf8')); - const versions = JSON.parse( - readFileSync(path.join(root, '.release-please-manifest.json'), 'utf8'), - ); - const github = { - repository: { owner: 'f0rr0', repo: 'oliphaunt', defaultBranch: 'main' }, - async *releaseIterator() { - for (const owner of Object.keys(config.packages)) - yield { - tagName: `${config.packages[owner].component}-v${versions[owner]}`, - sha: baseline, - notes: 'Existing release', - }; - }, - async *mergeCommitIterator() { - yield* commits; - yield { sha: baseline, message: 'chore(release): previous versions', files: [] }; - }, - async getFileContentsOnBranch(file) { - const local = path.join(root, file); - const parsedContent = - file === 'release-please-config.json' - ? JSON.stringify(config) - : file === '.release-please-manifest.json' - ? JSON.stringify(versions) - : existsSync(local) - ? readFileSync(local, 'utf8') - : undefined; - if (parsedContent === undefined) - throw Object.assign(new Error(`missing ${file}`), { status: 404 }); - return { parsedContent, content: Buffer.from(parsedContent).toString('base64') }; +test('bounded Release Please selection produces zero, one and many owner candidates', async () => { + for (const [files, expected] of [ + [['tools/release/controller.mts', 'products/alpha/README.md'], []], + [['products/alpha/src/lib.rs'], ['alpha']], + [[historyShared], historyProducts], + ]) { + const candidates = await generateHistoryCandidate([ + { sha: head, message: 'fix: change selected delivery', files }, + { sha: first, message: 'fix: already delivered behavior', files: [historyShared] }, + ]); + expect(historyVersionUpdates(candidates).sort()).toEqual( + expected.map((product) => [`products/${product}/VERSION`, '0.2.1']).sort(), + ); + } +}); + +test('actual capture retains move-out, move-in and renamed product inputs before Release Please selection', async () => { + const fixture = mkdtempSync(path.join(os.tmpdir(), 'release-commit-moves-')); + const snapshot = path.join(fixture, 'snapshot'); + const run = (command, args) => { + const result = spawnSync(command, args, { + cwd: fixture, + encoding: 'utf8', + env: { + ...process.env, + GIT_AUTHOR_NAME: 'Fixture', + GIT_AUTHOR_EMAIL: 'fixture@example.com', + GIT_COMMITTER_NAME: 'Fixture', + GIT_COMMITTER_EMAIL: 'fixture@example.com', + }, + }); + if (result.status !== 0) throw new Error(`${command}: ${result.stderr}`); + return result.stdout.trim(); + }; + try { + run('git', ['init', '-q']); + mkdirSync(path.join(fixture, 'products/alpha/src'), { recursive: true }); + mkdirSync(path.join(fixture, 'products/beta/src'), { recursive: true }); + mkdirSync(path.join(fixture, 'unowned'), { recursive: true }); + writeFileSync(path.join(fixture, 'products/alpha/src/source.rs'), 'alpha\n'); + writeFileSync(path.join(fixture, 'unowned/source.rs'), 'beta\n'); + run('git', ['add', '.']); + run('git', ['commit', '-qm', 'chore: published baseline']); + const baseline = run('git', ['rev-parse', 'HEAD']); + run('git', ['mv', 'products/alpha/src/source.rs', 'unowned/alpha.rs']); + run('git', ['commit', '-qm', 'fix: remove alpha input']); + const moveOut = run('git', ['rev-parse', 'HEAD']); + run('git', ['mv', 'unowned/source.rs', 'products/beta/src/source.rs']); + run('git', ['commit', '-qm', 'fix: install beta input']); + const moveIn = run('git', ['rev-parse', 'HEAD']); + run('git', ['mv', 'products/beta/src/source.rs', 'products/beta/src/renamed.rs']); + run('git', ['commit', '-qm', 'fix: rename beta input']); + const rename = run('git', ['rev-parse', 'HEAD']); + run('bash', [ + path.join(ROOT, 'tools/release/snapshot-commit-paths.sh'), + fixture, + rename, + snapshot, + ]); + const candidates = await generateHistoryCandidate( + [ + { sha: rename, message: 'fix: rename beta input', files: ['products/beta/src/renamed.rs'] }, + { sha: moveIn, message: 'fix: install beta input', files: ['products/beta/src/source.rs'] }, + { sha: moveOut, message: 'fix: remove alpha input', files: ['unowned/alpha.rs'] }, + { sha: baseline, message: 'chore: published baseline', files: [] }, + ], + { + baselines: Object.fromEntries(historyProducts.map((product) => [product, baseline])), + readCommitFiles: (sha) => readCommitPaths(sha, snapshot), + commitHistory: readCommitHistory(snapshot), + sourceSha: rename, + readSource: async () => ({ object: { sha: rename } }), + inspect(selected, calls) { + expect(calls.commits.backfillFiles).toBe(false); + expect(selected['products/alpha'].map(({ sha }) => sha)).toEqual([moveOut]); + expect(selected['products/alpha'][0].files).toEqual([ + 'products/alpha/src/source.rs', + 'unowned/alpha.rs', + ]); + expect(selected['products/beta'].map(({ sha }) => sha)).toEqual([rename, moveIn]); + expect(selected['products/beta'][0].files).toEqual([ + 'products/beta/src/renamed.rs', + 'products/beta/src/source.rs', + ]); + expect(selected['products/gamma']).toEqual([]); + }, + }, + ); + expect(historyVersionUpdates(candidates).sort()).toEqual([ + ['products/alpha/VERSION', '0.2.1'], + ['products/beta/VERSION', '0.2.1'], + ]); + } finally { + rmSync(fixture, { recursive: true, force: true }); + } +}); + +test('history capture reaches release boundaries beyond pinned library search limits', async () => { + const commits = Array.from({ length: 510 }, (_, index) => ({ + sha: (index + 1000).toString(16).padStart(40, '0'), + message: 'docs: controller maintenance', + files: ['tools/release/README.md'], + })); + commits.push( + { + sha: head, + message: 'fix: older unshipped alpha change', + files: ['products/alpha/src/lib.rs'], }, - async getFileContents(file) { - return this.getFileContentsOnBranch(file); + { sha: first, message: 'chore(release): completed baseline', files: [] }, + ); + const candidates = await generateHistoryCandidate(commits, { + unrelatedReleaseCount: 410, + inspect(_selected, calls) { + expect(calls.commits.maxResults).toBe(Number.MAX_SAFE_INTEGER); + expect(calls.releases.maxResults).toBe(Number.MAX_SAFE_INTEGER); }, - async getFileJson(file) { - return JSON.parse((await this.getFileContentsOnBranch(file)).parsedContent); + }); + expect(historyVersionUpdates(candidates)).toEqual([['products/alpha/VERSION', '0.2.1']]); +}); + +test('missing, skipped, draft and tag-only release boundaries stop preparation', async () => { + const baseline = { sha: first, message: 'chore(release): completed baseline', files: [] }; + const current = { + sha: head, + message: 'fix: alpha delivery', + files: ['products/alpha/src/lib.rs'], + }; + await expect(generateHistoryCandidate([current])).rejects.toThrow('did not reach alpha boundary'); + await expect( + generateHistoryCandidate([current, baseline], { lastReleaseSha: head }), + ).rejects.toThrow('did not reach alpha boundary'); + for (const options of [{ drafts: ['alpha'] }, { tagOnly: ['alpha'] }, { missing: ['alpha'] }]) + await expect(generateHistoryCandidate([current, baseline], options)).rejects.toThrow( + 'alpha@0.2.0 has no published release boundary', + ); + await expect(generateHistoryCandidate([current, current, baseline])).rejects.toThrow( + 'duplicate history commit', + ); + await expect( + generateHistoryCandidate([{ sha: head, message: 'fix: unknown file history' }, baseline]), + ).rejects.toThrow(/missing.*files/u); +}); + +test('first releases consume the complete exclusive bootstrap boundary', async () => { + const commits = [ + { sha: head, message: 'fix: first alpha delivery', files: ['products/alpha/src/lib.rs'] }, + { sha: first, message: 'fix: legacy shared delivery', files: [historyShared] }, + ]; + const options = { unreleased: historyProducts, bootstrapSha: first }; + expect(historyVersionUpdates(await generateHistoryCandidate(commits, options))).toEqual([ + ['products/alpha/VERSION', '0.1.0'], + ]); + await expect(generateHistoryCandidate(commits.slice(0, 1), options)).rejects.toThrow( + 'did not reach bootstrap boundary', + ); +}); + +test('a new product without bootstrap uses complete history alongside published owners', async () => { + const candidates = await generateHistoryCandidate( + [ + { sha: head, message: 'docs: explain beta', files: ['products/beta/README.md'] }, + { sha: second, message: 'chore(release): existing owners', files: [] }, + { sha: first, message: 'feat: first gamma delivery', files: ['products/gamma/src/lib.rs'] }, + ], + { + baselines: { alpha: second, beta: second }, + unreleased: ['gamma'], + inspect(selected) { + expect(selected['products/alpha']).toEqual([]); + expect(selected['products/beta']).toEqual([]); + expect(selected['products/gamma'].map(({ sha }) => sha)).toEqual([first]); + }, }, + ); + expect(historyVersionUpdates(candidates)).toEqual([['products/gamma/VERSION', '0.1.0']]); +}); + +test('seeded histories match independent per-owner published-boundary oracles', async () => { + let state = 0x294; + const random = () => { + state = (Math.imul(state, 1664525) + 1013904223) >>> 0; + return state; }; - const manifest = await Manifest.fromManifest(github, 'main'); - useSourceDate('2026-09-11'); - includeOwnedSourceCommits(manifest, github, graph, readCompatibility); - configure(manifest, github); - const candidates = await manifest.buildPullRequests(); - expect(candidates.length).toBeLessThanOrEqual(1); - const [candidate] = candidates; - return { candidate, versions }; + for (let scenario = 0; scenario < 24; scenario++) { + const expectedOwners = []; + const commits = Array.from({ length: 32 }, (_, index) => { + const choice = random() % 6; + const owners = choice < 3 ? [historyProducts[choice]] : choice === 3 ? historyProducts : []; + expectedOwners.push(owners); + return { + sha: (10000 + scenario * 100 + index).toString(16).padStart(40, '0'), + message: `fix: scenario ${scenario} input ${index}`, + files: + choice < 3 + ? [`products/${historyProducts[choice]}/src/lib.rs`] + : [ + choice === 3 + ? historyShared + : choice === 4 + ? 'products/alpha/README.md' + : 'tools/controller.mts', + ], + }; + }); + const boundaries = Object.fromEntries( + historyProducts.map((product) => [product, 4 + (random() % 28)]), + ); + const expected = Object.fromEntries( + historyProducts.map((product) => [ + `products/${product}`, + commits.filter( + (_commit, index) => + index < boundaries[product] && expectedOwners[index].includes(product), + ), + ]), + ); + const captured = mkdtempSync(path.join(os.tmpdir(), 'release-random-ancestry-')); + try { + writeFileSync( + path.join(captured, '.parents'), + `head ${commits[0].sha}\n${commits + .map( + (commit, index) => + `${commit.sha}${commits[index + 1] ? ` ${commits[index + 1].sha}` : ''}\n`, + ) + .join('')}`, + ); + const apiCommits = [...commits]; + for (let index = apiCommits.length - 1; index > 0; index--) { + const other = random() % (index + 1); + [apiCommits[index], apiCommits[other]] = [apiCommits[other], apiCommits[index]]; + } + const candidates = await generateHistoryCandidate(apiCommits, { + commitHistory: readCommitHistory(captured), + baselines: Object.fromEntries( + historyProducts.map((product) => [product, commits[boundaries[product]].sha]), + ), + inspect(selected) { + for (const [owner, entries] of Object.entries(expected)) + expect(selected[owner].map(({ sha }) => sha)).toEqual(entries.map(({ sha }) => sha)); + }, + }); + expect(historyVersionUpdates(candidates).sort()).toEqual( + Object.entries(expected) + .filter(([, entries]) => entries.length) + .map(([owner]) => [`${owner}/VERSION`, '0.2.1']) + .sort(), + ); + } finally { + rmSync(captured, { recursive: true, force: true }); + } + } +}); + +function generateProductCandidate(...args) { + return generateProductCandidateForGraph(graph, ...args); } +test('one supplied current-source map reaches RP support intent and default-install closure without caller mutation', async () => { + const buildBound = new Map(Object.keys(graph.products).map((id) => [id, new Set()])); + const addon = 'oliphaunt-wasix-napi'; + buildBound.get(addon).add('liboliphaunt-wasix'); + for (const [product, metadata] of Object.entries(graph.products)) + if (metadata.extension?.class === 'external') + buildBound.set(product, new Set(['liboliphaunt-native', 'liboliphaunt-wasix'])); + const { candidate } = await generateProductCandidate( + [ + { + sha: head, + message: 'fix: update compiled WASIX host and extension', + files: [`${wasix}/toolchain.toml`, 'src/extensions/external/vector/source.toml'], + }, + ], + undefined, + () => buildBound.get(addon).clear(), + { buildBound }, + ); + const selected = candidate.body.releaseData.map(({ component }) => component); + expect(selected).toContain('liboliphaunt-wasix'); + expect(selected).toContain(addon); + expect(selected).toContain('oliphaunt-wasix-ts'); + expect(selected).not.toContain('liboliphaunt-native'); + expect(buildBound.get(addon).size).toBe(0); +}); + +test('missing supplied relationships stop RP before source and compatibility reads', async () => { + let reads = 0; + await expect( + generateProductCandidate( + [ + { + sha: head, + message: 'fix: update extension', + files: ['src/extensions/external/vector/source.toml'], + }, + ], + () => { + reads++; + throw new Error('compatibility must not be read'); + }, + undefined, + { buildBound: new Map() }, + ), + ).rejects.toThrow('buildBound'); + expect(reads).toBe(0); +}); + for (const scenario of [ { name: 'documentation only', @@ -387,15 +648,11 @@ for (const scenario of [ products: ['oliphaunt-js'], }, { - name: 'query updates and native ecosystem dependency bumps', + name: 'independent query updates and npm ecosystem dependency bumps', files: ['src/query/ts/src/query.ts', 'src/query/rust/src/lib.rs'], products: [ 'oliphaunt-query-ts', 'oliphaunt-query', - 'oliphaunt-broker', - 'oliphaunt-kotlin', - 'oliphaunt-swift', - 'oliphaunt-wasix-napi', 'oliphaunt-js', 'oliphaunt-react-native', 'oliphaunt-wasix-ts', @@ -431,35 +688,17 @@ for (const scenario of [ 'src/wasix/sdks/rust/src/oliphaunt/base.rs', 'src/wasix/sdks/ts/src/index.ts', ], - products: [ - 'liboliphaunt-wasix', - 'oliphaunt-wasix-napi', - 'oliphaunt-wasix-rust', - 'oliphaunt-wasix-ts', - ], + products: ['liboliphaunt-wasix', 'oliphaunt-wasix-rust', 'oliphaunt-wasix-ts'], }, { - name: 'both runtime families and one extension close all default installs', + name: 'a changed WASIX default extension host requires explicit addon adoption before version closure', files: [ `${native}/src/liboliphaunt.c`, `${wasix}/toolchain.toml`, 'src/extensions/external/vector/source.toml', ], - products: [ - 'liboliphaunt-native', - 'liboliphaunt-wasix', - ...Object.keys(graph.products).filter( - (id) => graph.products[id].extension?.class === 'external', - ), - 'oliphaunt-js', - 'oliphaunt-kotlin', - 'oliphaunt-swift', - 'oliphaunt-react-native', - 'oliphaunt-wasix-rust', - 'oliphaunt-wasix-ts', - 'oliphaunt-wasix-napi', - 'oliphaunt-pgwire-server', - ], + products: ['liboliphaunt-native', 'liboliphaunt-wasix', 'oliphaunt-extension-vector'], + error: 'update its conventional runtime and SDK requirements', }, { name: 'shared package writer', @@ -479,8 +718,13 @@ for (const scenario of [ 'oliphaunt-react-native', ], }, + { + name: 'local pgwire input changes release the addon while its registry SDK and runtime stay held', + files: ['src/wasix/pgwire-server/src/lib.rs'], + products: ['oliphaunt-pgwire-server', 'oliphaunt-wasix-napi'], + }, ]) - test(`release scenario: ${scenario.name} produces coherent versions and exact consumer scope`, async () => { + test(`release scenario: ${scenario.name} ${scenario.error ? 'rejects incompatible default installs before application' : 'produces coherent versions and exact consumer scope'}`, async () => { if (!scenario.products.length) { const { candidate } = await generateProductCandidate([ { sha: head, message: 'docs: clarify usage', files: scenario.files }, @@ -523,7 +767,14 @@ for (const scenario of [ encoding: 'utf8', }); expect(changed.status).toBe(0); - for (const file of changed.stdout.split('\0').filter(Boolean)) { + const untracked = spawnSync('git', ['ls-files', '--others', '--exclude-standard', '-z'], { + cwd: ROOT, + encoding: 'utf8', + }); + expect(untracked.status).toBe(0); + for (const file of new Set( + `${changed.stdout}${untracked.stdout}`.split('\0').filter(Boolean), + )) { const destination = path.join(scratch, file); if (existsSync(path.join(ROOT, file))) { mkdirSync(path.dirname(destination), { recursive: true }); @@ -534,6 +785,9 @@ for (const scenario of [ symlinkSync(path.join(ROOT, 'node_modules'), path.join(scratch, 'node_modules')); run('git', ['config', 'user.name', 'Release Fixture']); run('git', ['config', 'user.email', 'release@example.invalid']); + // Copied in-flight source/fixture edits must have their derived evidence + // in the source baseline. Closing a release may only change versions. + run('bash', ['tools/release/sync-release-pr.sh']); run('git', ['add', '-A']); run('git', ['commit', '--allow-empty', '-qm', 'test: published release baseline']); const baseline = run('git', ['rev-parse', 'HEAD']); @@ -561,6 +815,32 @@ for (const scenario of [ : readFileSync(path.join(scratch, entry.path), 'utf8'), ); }; + const queryManifest = path.join(scratch, 'src/wasix/sdks/rust/Cargo.toml'); + const declaredQueryRequirement = Bun.TOML.parse(readFileSync(queryManifest, 'utf8')) + .dependencies['oliphaunt-query'].version; + const addonLockfile = path.join(scratch, 'src/wasix/node-addon/Cargo.lock'); + const publishedCargoRows = Bun.TOML.parse(readFileSync(addonLockfile, 'utf8')).package.filter( + (pkg) => pkg.source, + ); + if (scenario.error) { + await expect( + generateProductCandidate( + [ + { + sha: source, + message: 'fix: repair shipped behavior', + files: run('git', ['diff', '--name-only', baseline, source]).split('\n'), + }, + ], + readCompatibility, + undefined, + { root: scratch, baseline }, + ), + ).rejects.toThrow(scenario.error); + expect(run('git', ['status', '--porcelain', '--untracked-files=all'])).toBe(''); + expect(run('git', ['rev-parse', 'HEAD'])).toBe(source); + return; + } const { candidate, versions } = await generateProductCandidate( [ { @@ -574,6 +854,9 @@ for (const scenario of [ { root: scratch, baseline }, ); applyCandidate(scratch, candidate); + expect( + Bun.TOML.parse(readFileSync(queryManifest, 'utf8')).dependencies['oliphaunt-query'].version, + ).toBe(declaredQueryRequirement); const declaredRequirements = new Map( entries.map((entry) => [ entry.id, @@ -586,6 +869,11 @@ for (const scenario of [ writeFileSync(path.join(metadata, 'title'), `${candidate.title.toString()}\n`); writeFileSync(path.join(metadata, 'body.md'), `${candidate.body.toString()}\n`); run('bash', ['tools/release/close-release-candidate.sh', metadata]); + expect( + Bun.TOML.parse(readFileSync(queryManifest, 'utf8')).dependencies['oliphaunt-query'].version, + ).toBe(declaredQueryRequirement); + const addonCargoRows = Bun.TOML.parse(readFileSync(addonLockfile, 'utf8')).package; + expect(addonCargoRows.filter((pkg) => pkg.source)).toEqual(publishedCargoRows); const closed = run('git', ['rev-parse', 'HEAD']); expect(run('git', ['rev-parse', 'HEAD^'])).toBe(source); run('bash', ['tools/release/sync-release-pr.sh']); @@ -597,6 +885,14 @@ for (const scenario of [ readFileSync(path.join(scratch, '.release-please-manifest.json'), 'utf8'), ); const changedOwners = Object.keys(after).filter((owner) => after[owner] !== versions[owner]); + for (const product of ['oliphaunt-wasix-napi', 'oliphaunt-pgwire-server']) { + const cargo = Bun.TOML.parse( + readFileSync(path.join(scratch, graph.products[product].path, 'Cargo.toml'), 'utf8'), + ); + expect( + addonCargoRows.find((pkg) => pkg.name === cargo.package.name && !pkg.source).version, + ).toBe(cargo.package.version); + } expect(changedOwners.sort()).toEqual( scenario.products.map((id) => graph.products[id].path).sort(), ); @@ -689,7 +985,7 @@ for (const scenario of [ ), ); expect(readCompatibility('oliphaunt-wasix-napi', 'liboliphaunt-wasix')).toBe( - products['liboliphaunt-wasix'].version, + graph.products['liboliphaunt-wasix'].version, ); run('git', ['reset', '--hard', source]); applyCandidate(scratch, candidate); @@ -709,58 +1005,6 @@ for (const scenario of [ } }, 180_000); -test('actual Rust, npm, Swift and Gradle strategy updates apply to one local candidate', async () => { - const root = path.resolve(import.meta.dir, '../..'); - const selected = [ - 'src/native/sdks/rust', - 'src/native/sdks/ts', - 'src/native/sdks/swift', - 'src/native/sdks/kotlin', - ]; - const { candidate, versions } = await generateProductCandidate([ - { - sha: head, - message: 'fix: correct the selected SDK behavior', - files: selected.map((owner) => `${owner}/src/implementation`), - }, - ]); - const scratch = mkdtempSync(path.join(os.tmpdir(), 'release-please-ecosystems-')); - try { - for (const update of candidate.updates) { - const input = path.join(root, update.path); - if (existsSync(input)) { - const destination = path.join(scratch, update.path); - mkdirSync(path.dirname(destination), { recursive: true }); - writeFileSync(destination, readFileSync(input)); - } - } - applyCandidate(scratch, candidate); - const after = JSON.parse( - readFileSync(path.join(scratch, '.release-please-manifest.json'), 'utf8'), - ); - const read = (file) => readFileSync(path.join(scratch, file), 'utf8'); - expect(Bun.TOML.parse(read('src/native/sdks/rust/Cargo.toml')).package.version).toBe( - after['src/native/sdks/rust'], - ); - expect( - Bun.TOML.parse(read('src/native/sdks/rust/crates/oliphaunt-build/Cargo.toml')).package - .version, - ).toBe(after['src/native/sdks/rust']); - expect(JSON.parse(read('src/native/sdks/ts/package.json')).version).toBe( - after['src/native/sdks/ts'], - ); - expect(read('src/native/sdks/swift/VERSION').trim()).toBe(after['src/native/sdks/swift']); - expect(read('src/native/sdks/kotlin/VERSION').trim()).toBe(after['src/native/sdks/kotlin']); - expect(read('src/native/sdks/kotlin/gradle.properties')).toContain( - `VERSION_NAME=${after['src/native/sdks/kotlin']}`, - ); - expect(existsSync(path.join(scratch, 'src/native/sdks/rust/Cargo.lock'))).toBe(false); - for (const owner of selected) expect(after[owner]).not.toBe(versions[owner]); - } finally { - rmSync(scratch, { recursive: true, force: true }); - } -}); - test('runtime and SDK changes retain independent extension releases', async () => { for (const sdk of ['oliphaunt-kotlin', 'oliphaunt-wasix-rust', 'oliphaunt-react-native']) { const { candidate } = await generateProductCandidate([ @@ -776,125 +1020,6 @@ test('runtime and SDK changes retain independent extension releases', async () = } }); -test('independent SDK pins do not impose a single global runtime version', async () => { - const readCompatibility = (product, source) => - product === 'oliphaunt-react-native' ? '0.2.0' : graph.products[source].version; - const { candidate } = await generateProductCandidate( - [ - { - sha: head, - message: 'fix: repair mobile adapters', - files: [ - 'src/native/sdks/kotlin/src/implementation', - 'src/native/sdks/react-native/ios/OliphauntAdapter.swift', - ], - }, - ], - readCompatibility, - ); - expect(candidate).toBeDefined(); - expect( - candidate.updates.some(({ path: file }) => file.startsWith('src/extensions/external/')), - ).toBe(false); -}); - -test('removing published exact host support supplies breaking intent before native version selection', async () => { - const vector = graph.products['oliphaunt-extension-vector']; - const reads = []; - const readCompatibility = (product, source, _prefix, { ref = null } = {}) => { - reads.push({ product, source, ref }); - return ref ? '0.1.0' : graph.products[source].version; - }; - const { candidate, versions } = await generateProductCandidate( - [ - { - sha: head, - message: 'fix: repair vector packaging', - files: [`${vector.path}/source.toml`], - }, - ], - readCompatibility, - ); - const update = mergeUpdates(candidate.updates).find( - ({ path: file }) => file === '.release-please-manifest.json', - ); - const after = JSON.parse(update.updater.updateContent(JSON.stringify(versions))); - const [major, minor] = vector.version.split('.').map(Number); - expect(after[vector.path]).toBe(`${major}.${minor + 1}.0`); - const changelog = candidate.updates - .find(({ path: file }) => file === vector.changelog_path) - .updater.updateContent('# Changelog\n'); - expect(changelog).toContain('replace exact host support'); - expect(changelog).toContain('repair vector packaging'); - expect( - reads.some(({ product, ref }) => product === 'oliphaunt-extension-vector' && ref !== null), - ).toBe(true); -}); - -test('unchanged public support permits an ordinary patch release', async () => { - const vector = graph.products['oliphaunt-extension-vector']; - const { candidate, versions } = await generateProductCandidate([ - { - sha: head, - message: 'fix: repair vector SQL', - files: [`${vector.path}/source.toml`], - }, - ]); - const update = mergeUpdates(candidate.updates).find( - ({ path: file }) => file === '.release-please-manifest.json', - ); - const after = JSON.parse(update.updater.updateContent(JSON.stringify(versions))); - const [major, minor, patch] = vector.version.split('.').map(Number); - expect(after[vector.path]).toBe(`${major}.${minor}.${patch + 1}`); -}); - -test('workspace-created candidates receive public support intent through native bump selection', async () => { - const vector = graph.products['oliphaunt-extension-vector']; - let bump; - await generateProductCandidate( - [ - { - sha: head, - message: 'fix: update build helper API', - files: ['src/native/sdks/rust/crates/oliphaunt-build/src/lib.rs'], - }, - ], - (_product, source, _prefix, { ref = null } = {}) => - ref ? '0.1.0' : graph.products[source].version, - (manifest, github) => { - manifest.plugins.push( - new (class extends ManifestPlugin { - async preconfigure(strategies, _commits, releases) { - bump = await strategies[vector.path].versioningStrategy.bump( - releases[vector.path].tag.version, - [], - ); - return strategies; - } - })(github, 'main', manifest.repositoryConfig), - ); - }, - ); - const [major, minor] = vector.version.split('.').map(Number); - expect(bump.toString()).toBe(`${major}.${minor + 1}.0`); -}); - -test('docs changes do not read compatibility or create candidates', async () => { - const { candidate } = await generateProductCandidate( - [ - { - sha: head, - message: 'docs: clarify preparation', - files: ['src/docs/maintainers/release.md'], - }, - ], - () => { - throw new Error('unexpected compatibility read'); - }, - ); - expect(candidate).toBeUndefined(); -}); - test('regeneration preserves the grouped body and complete update set', async () => { const commits = [ { sha: head, message: 'fix: repair runtime', files: [`${native}/tools/package.sh`] }, diff --git a/tools/release/prepare-release-pr.sh b/tools/release/prepare-release-pr.sh index 47d0add16..26ea22b12 100644 --- a/tools/release/prepare-release-pr.sh +++ b/tools/release/prepare-release-pr.sh @@ -1,11 +1,15 @@ #!/usr/bin/env bash set -euo pipefail -root="$(git rev-parse --show-toplevel)" -cd "$root" [[ $# == 1 ]] || { echo 'usage: prepare-release-pr.sh OUTPUT_DIRECTORY' >&2 exit 2 } +[[ "${NATIVE_QUALIFICATION_RUN_ID:-}" =~ ^[1-9][0-9]*$ ]] || { + echo 'native preparation requires an exact positive qualification run ID' >&2 + exit 1 +} +root="$(git rev-parse --show-toplevel)" +cd "$root" [[ -z "$(git status --porcelain --untracked-files=all)" ]] || { echo 'release preparation requires a clean source checkout' >&2 exit 1 @@ -14,9 +18,18 @@ export RELEASE_SOURCE_SHA RELEASE_SOURCE_DATE RELEASE_SOURCE_SHA="$(git rev-parse HEAD)" RELEASE_SOURCE_DATE="$(git show -s --format=%cs HEAD)" bash tools/dev/bun.sh tools/release/release-please-pr-lifecycle.mts assert-clean --base main -bash tools/ci/with-projects.sh --exec \ +OLIPHAUNT_CAPTURE_COMMIT_PATHS=1 bash tools/release/with-source.sh HEAD \ bash tools/release/with-product-history.sh "$PWD" HEAD '' @workspace \ bash tools/dev/bun.sh tools/release/prepare-release-candidate.mts "$1" if [[ -n "${GITHUB_OUTPUT:-}" ]]; then printf 'required=%s\n' "$(cat "$1/required")" >>"$GITHUB_OUTPUT" + native_inputs=false + if [[ "$(cat "$1/required")" == true ]]; then + [[ -f "$1/native-release-inputs/native-version-source.json" && -f "$1/native-release-inputs/native-publication-inputs.json" ]] || { + echo 'native preparation did not retain its completed input packet' >&2 + exit 1 + } + native_inputs=true + fi + printf 'native_inputs=%s\n' "$native_inputs" >>"$GITHUB_OUTPUT" fi diff --git a/tools/release/public-consumer-smoke.mts b/tools/release/public-consumer-smoke.mts index 9fe69887f..7f5b4cebc 100644 --- a/tools/release/public-consumer-smoke.mts +++ b/tools/release/public-consumer-smoke.mts @@ -16,7 +16,11 @@ import path from 'node:path'; import process from 'node:process'; import { EXTENSION_PORTABLE_TARGET } from '../../src/wasix/runtime/tools/wasix-cargo-artifact-contract.mts'; import { assertWasixTypescriptNativeCarrier } from '../../src/wasix/sdks/ts/tools/wasix-typescript-package.mts'; -import { DEFAULT_PUBLICATION_LOCK, loadPublicationLock } from './publication-lock.mts'; +import { + DEFAULT_PUBLICATION_LOCK, + loadPublicationLock, + packageDependencyMatchesCarrier, +} from './publication-lock.mts'; import { registryRetryDelaySeconds, registryStatusRetryable } from './registry-http-retry.mts'; import { validateRegistryReceiptEvidence } from './registry-integrity.mts'; import { DESKTOP_TARGETS } from './release-artifact-targets.mts'; @@ -180,17 +184,12 @@ function consumerDependencyIds(carrier, selectedCarrierIds, byId) { ...new Set( carrier.packageDependencies .filter((dependency) => scopes.has(dependency.scope)) - .filter((dependency) => { - const candidate = byId.get(`${dependency.ecosystem}:${dependency.name}`); - if (!candidate) return false; - let requirement = dependency.requirement; - if (dependency.ecosystem === 'maven') return requirement === candidate.version; - if (dependency.ecosystem === 'cargo') { - if (/^\d+(?:\.\d+){0,2}$/u.test(requirement)) requirement = `^${requirement}`; - requirement = requirement.replaceAll(',', ' '); - } - return Bun.semver.satisfies(candidate.version, requirement); - }) + .filter((dependency) => + packageDependencyMatchesCarrier( + dependency, + byId.get(`${dependency.ecosystem}:${dependency.name}`), + ), + ) .map((dependency) => `${dependency.ecosystem}:${dependency.name}`) .filter((id) => selectedCarrierIds.has(id)), ), diff --git a/tools/release/publication-catalog.mts b/tools/release/publication-catalog.mts index fb5bf20d2..7d5d31254 100644 --- a/tools/release/publication-catalog.mts +++ b/tools/release/publication-catalog.mts @@ -193,9 +193,9 @@ export function publicationCatalogDigest(catalog) { export function loadPublicationCatalog( prefix = 'publication-catalog', - { products = undefined } = {}, + { products = undefined, inputContext = undefined } = {}, ) { - const graph = { products: loadProducts(prefix) }; + const graph = { products: inputContext?.products ?? loadProducts(prefix) }; const known = new Set(Object.keys(graph.products)); const selected = products === undefined ? [...known] : sortedUniqueStrings(products, 'products', prefix); @@ -214,7 +214,9 @@ export function loadPublicationCatalog( `${product}.publish_targets`, prefix, ); - const registryPackages = registryPackageRows({ product }, prefix).map((row) => row.raw); + const registryPackages = registryPackageRows({ product, inputContext }, prefix).map( + (row) => row.raw, + ); productRows.push({ id: product, kind: config.kind, diff --git a/tools/release/publication-consumer-proof.mts b/tools/release/publication-consumer-proof.mts index 749ebc341..bb16ce5e8 100644 --- a/tools/release/publication-consumer-proof.mts +++ b/tools/release/publication-consumer-proof.mts @@ -30,6 +30,7 @@ export const CONSUMER_CONFIGURATION_FILES = [ 'rust-toolchain.toml', '.github/workflows/release.yml', 'tools/packaging/portable-archive.mts', + 'tools/packaging/frozen-cargo.mts', 'tools/release/public-consumer-smoke.mts', 'src/native/sdks/swift/tools/prepare-swift-release-consumer.mts', 'src/native/sdks/kotlin/gradle/libs.versions.toml', diff --git a/tools/release/publication-lock.mts b/tools/release/publication-lock.mts index acc164ff6..95900dca7 100644 --- a/tools/release/publication-lock.mts +++ b/tools/release/publication-lock.mts @@ -1,5 +1,7 @@ #!/usr/bin/env bun import { createHash } from 'node:crypto'; +import { sourceIdentity } from './with-source.mts'; +export { sourceIdentity } from './with-source.mts'; import { existsSync, lstatSync, @@ -10,7 +12,10 @@ import { writeFileSync, } from 'node:fs'; import path from 'node:path'; -import { extensionRuntimeAssetContract } from '../../src/extensions/artifacts/packages/tools/extension-runtime-asset-contract.mts'; +import { + extensionRuntimeAssetContract, + projectNativeRuntimeAssetMember, +} from '../../src/extensions/artifacts/packages/tools/extension-runtime-asset-contract.mts'; import { assertWasixExtensionMemberInstall } from '../../src/extensions/contracts/wasix-extension-install.mts'; import { extensionCarrierLegalContract, @@ -24,12 +29,11 @@ import { validateSelectionNeutralSwiftSourceCarrier, validateSwiftSourceReleaseContract, } from '../../src/native/sdks/swift/tools/swift-source-carrier-contract.mts'; -import { releaseJavaScript } from '../packaging/emit-javascript.mts'; import { assertWasixTypescriptManifest, assertWasixTypescriptNativeCarrier, } from '../../src/wasix/sdks/ts/tools/wasix-typescript-package.mts'; -import { requireMatchingWasixRuntime } from './compatibility-version-policy.mts'; +import { releaseJavaScript } from '../packaging/emit-javascript.mts'; import { parseMavenArtifactManifest } from '../packaging/maven-artifact-manifest.mts'; import { validateMavenCentralPublication } from '../packaging/maven-central-contract.mts'; import { validateNpmTrustedPublishingManifest } from '../packaging/npm-trusted-publishing.mts'; @@ -37,6 +41,15 @@ import { readFileOnlyTarGzipEntries, readPortableArchiveEntries, } from '../packaging/portable-archive.mts'; +import { validateCargoPayloadPartSets } from './cargo-payload-part-contract.mts'; +import { validateChecksumManifest } from './checksum-manifest.mts'; +import { requireMatchingWasixRuntime } from './compatibility-version-policy.mts'; +import { + NATIVE_PUBLICATION_METADATA_KIND, + NATIVE_PUBLICATION_METADATA_MAX_BYTES, + nativePublicationMetadataArtifactRows, + validateNativePublicationMetadata, +} from './native-publication-metadata-contract.mts'; import { loadPublicationCatalog, PUBLICATION_CATALOG_SCHEMA, @@ -45,12 +58,16 @@ import { } from './publication-catalog.mts'; import { allArtifactTargets, + canonicalExtensionAssetName, + canonicalExtensionBundleAssetName, contribCarrierDescriptor, - currentProductVersionSync, + expectedExtensionGithubReleaseAssetRows as declaredExtensionGithubReleaseAssetRows, + extensionReleaseMetadataRows as declaredExtensionReleaseMetadataRows, extensionArtifactTargets, extensionMetadata, extensionSourceIdentity, extensionSqlNames, + readArtifactInputText, } from './release-artifact-targets.mts'; import { compareText, @@ -59,6 +76,7 @@ import { ROOT, } from './release-graph.mts'; +export { validateCargoPayloadPartSets } from './cargo-payload-part-contract.mts'; export { validateSelectionNeutralSwiftSourceCarrier }; export const PUBLICATION_CANDIDATE_SCHEMA = 'oliphaunt-publication-candidate-v1'; @@ -83,6 +101,19 @@ const ROLE_ORDER = new Map([ ['tool-facade', 4], ['facade', 5], ]); +const PUBLICATION_DEPENDENCY_SCOPES = Object.freeze({ + cargo: new Set(['build', 'runtime']), + maven: new Set(['compile', 'runtime']), + npm: new Set(['optional', 'peer', 'runtime']), +}); +const SWIFT_RELEASE_INPUT_FILES = [ + ['Oliphaunt-source.zip', 'swiftpm-source-archive'], + ['Package.swift.release', 'swiftpm-release-manifest'], + ['extension-owner-catalog.json', 'swiftpm-extension-owner-catalog'], + ['extension-resource-inventory.mjs', 'swiftpm-extension-resource-inventory'], + ['render-extension-products.mjs', 'swiftpm-extension-generator'], + ['swift-carrier-resolver.mjs', 'swiftpm-carrier-resolver'], +]; function error(message) { return new Error(`publication-lock: ${message}`); @@ -562,39 +593,6 @@ function exactDirectFileSet(directory, expectedNames, context) { } } -function validateChecksumManifest(file, payloadFiles, context) { - const declared = new Map(); - for (const [index, rawLine] of readFileSync(file, 'utf8').split(/\r?\n/u).entries()) { - if (rawLine.length === 0) { - continue; - } - const match = rawLine.match(/^([0-9a-f]{64}) {2}\.\/([^/\0]+)$/u); - if (match === null) { - throw error(`${context} checksum line ${index + 1} must be ' ./'`); - } - const [, digest, name] = match; - if (declared.has(name)) { - throw error(`${context} checksum manifest declares ${name} more than once`); - } - declared.set(name, digest); - } - const expected = new Map( - payloadFiles.map((payload) => [path.basename(payload), sha256File(payload)]), - ); - const declaredNames = [...declared.keys()].sort(compareText); - const expectedNames = [...expected.keys()].sort(compareText); - if (stableJson(declaredNames) !== stableJson(expectedNames)) { - throw error( - `${context} checksum entries do not exactly cover public payloads: expected=${JSON.stringify(expectedNames)}, actual=${JSON.stringify(declaredNames)}`, - ); - } - for (const [name, digest] of expected) { - if (declared.get(name) !== digest) { - throw error(`${context} checksum for ${name} does not match its frozen bytes`); - } - } -} - function fixedGithubReleaseArtifacts(files, product) { const targets = allArtifactTargets( { @@ -678,8 +676,11 @@ function extensionAssetKindAllowed(family, target, kind) { return kind === 'runtime'; } -function parseTsv(file) { - const lines = readFileSync(file, 'utf8') +function parseTsv(file, inputContext = undefined) { + const lines = readArtifactInputText( + path.relative(ROOT, file).split(path.sep).join('/'), + inputContext, + ) .split(/\r?\n/u) .filter((line) => line.length > 0 && !line.startsWith('#')); const header = lines[0].split('\t'); @@ -689,12 +690,12 @@ function parseTsv(file) { }); } -function exactExtensionIosContract(product, sqlName) { - if (!extensionSqlNames(product, 'publication-lock').includes(sqlName)) { +function exactExtensionIosContract(product, sqlName, inputContext = undefined) { + if (!extensionSqlNames(product, 'publication-lock', inputContext).includes(sqlName)) { throw error(`${product} does not own extension SQL name ${sqlName}`); } const generated = JSON.parse( - readFileSync(path.join(ROOT, 'src/extensions/generated/sdk/extensions.json'), 'utf8'), + readArtifactInputText('src/extensions/generated/sdk/extensions.json', inputContext), ); const row = generated.extensions?.find((item) => item?.['sql-name'] === sqlName); if (row === undefined) { @@ -709,6 +710,7 @@ function exactExtensionIosContract(product, sqlName) { } const staticRows = parseTsv( path.join(ROOT, 'src/extensions/generated/mobile/static-extensions.tsv'), + inputContext, ); const staticRow = staticRows.find((item) => item['sql-name'] === sqlName); if (staticRow === undefined || staticRow['native-module-stem'] !== nativeModuleStem) { @@ -727,11 +729,11 @@ function exactExtensionIosContract(product, sqlName) { return { sqlName, nativeModuleStem, dependencies, metadata: row }; } -function extensionRequiredArtifactRows(product) { +function extensionRequiredArtifactRows(product, inputContext = undefined) { const rows = []; - for (const target of extensionArtifactTargets({ product }, 'publication-lock')) { + for (const target of extensionArtifactTargets({ product, inputContext }, 'publication-lock')) { const sqlName = target.sqlName ?? target.sql_name; - const ios = exactExtensionIosContract(product, sqlName); + const ios = exactExtensionIosContract(product, sqlName, inputContext); if (target.family === 'wasix') { rows.push({ sqlName, @@ -804,9 +806,9 @@ export function extensionRequiredAssetKeys(product) { ); } -function extensionBundleCarrierRows(product, family = null) { +function extensionBundleCarrierRows(product, family = null, inputContext = undefined) { const groups = new Map(); - for (const row of extensionArtifactTargets({ product }, 'publication-lock')) { + for (const row of extensionArtifactTargets({ product, inputContext }, 'publication-lock')) { if (family !== null && row.family !== family) continue; const key = `${row.family}\0${row.target}`; if (!groups.has(key)) { @@ -833,39 +835,20 @@ export function expectedExtensionGithubReleaseAssetCount(product) { return extensionRequiredAssetKeys(product).length + 4; } -function canonicalExtensionAssetName(product, row) { - const prefix = `${product.id}-${product.version}`; - if (row.family === 'wasix') { - return `${prefix}-wasix-portable.tar.zst`; - } - if (row.kind === 'ios-xcframework') { - return `${prefix}-native-ios-xcframework.zip`; - } - if (row.kind === 'ios-dependency-xcframework') { - return `${prefix}-native-ios-dependency-${row.identity}-xcframework.zip`; - } - if (row.target === 'ios-xcframework') { - return `${prefix}-native-ios-runtime.tar.gz`; - } - return `${prefix}-native-${row.target}-runtime.tar.gz`; -} - -function canonicalExtensionBundleAssetName(product, { family, target }) { - return `${product.id}-${product.version}-${family}-${target}-bundle.tar.gz`; -} - -function expectedExtensionGithubReleaseAssetRows(product) { - if (extensionSqlNames(product.id, 'publication-lock').length > 1) { - return extensionBundleCarrierRows(product.id, extensionCarrierFamily(product)).map((row) => ({ - ...row, - identity: row.family, - name: canonicalExtensionBundleAssetName(product, row), - })); - } - return extensionRequiredArtifactRows(product.id).map((row) => ({ - ...row, - name: canonicalExtensionAssetName(product, row), - })); +export function expectedExtensionGithubReleaseAssetRows( + product, + declared = undefined, + inputContext = undefined, +) { + if (declared !== undefined) return declaredExtensionGithubReleaseAssetRows(product, declared); + const sqlNames = extensionSqlNames(product.id, 'publication-lock', inputContext); + return declaredExtensionGithubReleaseAssetRows(product, { + sqlNames, + requiredRows: + sqlNames.length > 1 + ? extensionBundleCarrierRows(product.id, extensionCarrierFamily(product), inputContext) + : extensionRequiredArtifactRows(product.id, inputContext), + }); } function exactExtensionManifestRows(product, manifest, manifestPath) { @@ -981,6 +964,12 @@ function publicExtensionMember(member) { extensionSqlFileNames: member.extensionSqlFileNames, extensionSqlFilePrefixes: member.extensionSqlFilePrefixes, nativeModuleStem: member.nativeModuleStem, + ...(member.nativeDependencyModules === undefined + ? {} + : { nativeDependencyModules: member.nativeDependencyModules }), + ...(member.nativeConstructionLicenseFiles === undefined + ? {} + : { nativeConstructionLicenseFiles: member.nativeConstructionLicenseFiles }), iosNativeDependencies: member.iosNativeDependencies, iosRegistration: member.iosRegistration, wasixInstall, @@ -1191,10 +1180,18 @@ function extensionBundleGithubReleaseArtifacts({ if (stableJson(memberNames) !== stableJson(expectedSqlNames)) { throw error(`${rel(file)} aggregate carrier does not contain every exact bundle member`); } - const legal = extensionCarrierLegalContract(product.id, memberNames, { + const legalOptions = { family: row.family, target: row.target, - }); + memberContracts: members.map((member) => { + const asset = member.assets.find( + (asset) => + asset.family === row.family && asset.target === row.target && asset.kind === 'runtime', + ); + return asset ? projectNativeRuntimeAssetMember(member, asset) : member; + }), + }; + const legal = extensionCarrierLegalContract(product.id, memberNames, legalOptions); const expectedBundleManifest = { schema: 'oliphaunt-extension-bundle-v1', product: product.id, @@ -1207,10 +1204,7 @@ function extensionBundleGithubReleaseArtifacts({ members: manifestMembers, }; const entries = extensionBundleEntries(file); - const legalFiles = extensionCarrierLegalFileInventory(product.id, memberNames, { - family: row.family, - target: row.target, - }); + const legalFiles = extensionCarrierLegalFileInventory(product.id, memberNames, legalOptions); const expectedArchiveFiles = [ bundleManifestPath, ...manifestMembers.map((member) => `${carrierRoot}/${member.path}`), @@ -1298,9 +1292,7 @@ function extensionBundleGithubReleaseArtifacts({ sourceIdentity: extensionSourceIdentity(product.id, 'publication-lock'), compatibility: metadata.compatibility, extensions: members.map(publicExtensionMember), - assets: [...carriersByName.values()] - .map(({ row }) => publicExtensionAsset(row)) - .sort((left, right) => compareText(left.name, right.name)), + assets: [...carriersByName.values()].map(({ row }) => publicExtensionAsset(row)), }; if (stableJson(publicManifest) !== stableJson(expectedPublicManifest)) { throw error( @@ -1332,12 +1324,7 @@ function extensionBundleGithubReleaseArtifacts({ ); } } - const controlFiles = [ - ['manifest-json', manifestName], - ['manifest-properties', `${product.id}-${product.version}-manifest.properties`], - ...(swiftCarrierName === null ? [] : [['swift-extension-carrier', swiftCarrierName]]), - ['checksums', `${product.id}-${product.version}-release-assets.sha256`], - ]; + const controlFiles = extensionReleaseMetadataRows(product); const expectedNames = [...[...carriersByName.keys()], ...controlFiles.map(([, name]) => name)]; exactDirectFileSet(directory, expectedNames, product.id); const checksumName = controlFiles.find(([kind]) => kind === 'checksums')[1]; @@ -1525,6 +1512,12 @@ function extensionGithubReleaseArtifacts(files, product) { extensionSqlFileNames: publicMember.extensionSqlFileNames, extensionSqlFilePrefixes: publicMember.extensionSqlFilePrefixes, nativeModuleStem: publicMember.nativeModuleStem, + ...(publicMember.nativeDependencyModules === undefined + ? {} + : { nativeDependencyModules: publicMember.nativeDependencyModules }), + ...(publicMember.nativeConstructionLicenseFiles === undefined + ? {} + : { nativeConstructionLicenseFiles: publicMember.nativeConstructionLicenseFiles }), iosNativeDependencies: publicMember.iosNativeDependencies, iosRegistration: publicMember.iosRegistration, wasixInstall: publicMember.wasixInstall, @@ -1565,12 +1558,7 @@ function extensionGithubReleaseArtifacts(files, product) { ); } } - const controlFiles = [ - ['manifest-json', `${product.id}-${product.version}-manifest.json`], - ['manifest-properties', `${product.id}-${product.version}-manifest.properties`], - ...(swiftCarrierName === null ? [] : [['swift-extension-carrier', swiftCarrierName]]), - ['checksums', `${product.id}-${product.version}-release-assets.sha256`], - ]; + const controlFiles = extensionReleaseMetadataRows(product); const expectedNames = [ ...[...rows.values()].map(({ row }) => row.name), ...controlFiles.map(([, name]) => name), @@ -1613,21 +1601,17 @@ function extensionGithubReleaseArtifacts(files, product) { ]; } -function swiftReleaseInputs(files, product, { requireExtensionFixture }) { +function swiftReleaseInputs( + files, + product, + { requireExtensionFixture, nativeSourceBasis = undefined }, +) { for (const file of files.filter((file) => path.basename(file) === 'Package.swift.release')) { if (existsSync(path.join(path.dirname(file), 'qualification.json'))) { throw error(`${product.id} cannot publish a workspace qualification carrier: ${rel(file)}`); } } - const expectedFiles = [ - ['Oliphaunt-source.zip', 'swiftpm-source-archive'], - ['Package.swift.release', 'swiftpm-release-manifest'], - ['extension-owner-catalog.json', 'swiftpm-extension-owner-catalog'], - ['extension-resource-inventory.mjs', 'swiftpm-extension-resource-inventory'], - ['render-extension-products.mjs', 'swiftpm-extension-generator'], - ['swift-carrier-resolver.mjs', 'swiftpm-carrier-resolver'], - ]; - const artifacts = expectedFiles.map(([name, kind]) => { + const artifacts = SWIFT_RELEASE_INPUT_FILES.map(([name, kind]) => { const generatorInput = !['Oliphaunt-source.zip', 'Package.swift.release'].includes(name); const matches = files.filter( (file) => @@ -1722,7 +1706,9 @@ function swiftReleaseInputs(files, product, { requireExtensionFixture }) { throw error(`${rel(carrierFile)} is not valid JSON: ${cause.message}`); } try { - validateSelectionNeutralSwiftSourceCarrier(carrier, rel(carrierFile)); + validateSelectionNeutralSwiftSourceCarrier(carrier, rel(carrierFile), { + sourceBasis: nativeSourceBasis, + }); const manifestArtifact = artifacts.find(({ kind }) => kind === 'swiftpm-release-manifest'); if (manifestArtifact === undefined) { throw new Error(`${product.id} is missing its frozen Package.swift.release artifact`); @@ -1736,6 +1722,7 @@ function swiftReleaseInputs(files, product, { requireExtensionFixture }) { ), label: `${product.id} frozen source release`, manifestText: readFileSync(path.resolve(ROOT, manifestArtifact.path), 'utf8'), + sourceBasis: nativeSourceBasis, }); } catch (cause) { throw error(cause instanceof Error ? cause.message : String(cause)); @@ -1778,10 +1765,7 @@ function swiftReleaseInputs(files, product, { requireExtensionFixture }) { function reactNativeReleaseInputs(files, product) { const name = 'oliphaunt-react-native-ios-carriers.json'; const matches = files.filter( - (file) => - path.basename(file) === name && - (rel(file).startsWith('target/release/ios-carriers/') || - rel(file).includes('/release/ios-carriers/')), + (file) => path.basename(file) === name && path.basename(path.dirname(file)) === 'ios-carriers', ); if (matches.length !== 1) { throw error( @@ -1817,18 +1801,45 @@ function runtimeOwnedExtensionGithubReleaseArtifacts(files, product) { ); } -function discoverProductArtifactsForSelection(roots, products, selectedProducts) { +function discoverProductArtifactsForSelection( + roots, + products, + selectedProducts, + { + nativeSourceBasis = undefined, + nativeMetadataProducts = [], + nativeMetadataSource = undefined, + artifactPhase = 'final', + swiftExtensionFixture = false, + } = {}, +) { const files = [...new Set(roots.flatMap((root) => walkFiles(path.resolve(ROOT, root))))].sort( compareText, ); const artifacts = []; - const contrib = contribCarrierDescriptor('publication-lock'); - const hasSelectedExtensionProducts = selectedProducts.some( - (product) => - EXTENSION_PRODUCT_KINDS.has(product?.kind) || - product?.id === contrib.nativeOwner || - product?.id === contrib.wasixOwner, - ); + for (const row of nativePublicationMetadataArtifactRows(products, nativeMetadataProducts)) { + const matches = files.filter((file) => path.basename(file) === row.name); + if (matches.length !== 1) + throw error( + `${row.product} requires exactly one controller-sealed native metadata file ${row.name}, found ${matches.length}`, + ); + if (statSync(matches[0]).size > NATIVE_PUBLICATION_METADATA_MAX_BYTES) + throw error( + `${row.product} controller-sealed native metadata is ${statSync(matches[0]).size} bytes, exceeds ${NATIVE_PUBLICATION_METADATA_MAX_BYTES} bytes`, + ); + validateNativePublicationMetadata( + JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(readFileSync(matches[0]))), + { + product: { id: row.product, version: row.version }, + source: nativeMetadataSource, + }, + ); + artifacts.push(productArtifact({ ...row, file: matches[0] })); + } + const requireExtensionFixture = expectedProductArtifactRows(selectedProducts, { + artifactPhase, + swiftExtensionFixture, + }).some((row) => row.kind === 'swiftpm-extension-consumer-fixture'); for (const product of products) { if (typeof product?.id !== 'string' || typeof product?.version !== 'string') { throw error('product artifact discovery requires canonical product rows with id and version'); @@ -1842,7 +1853,8 @@ function discoverProductArtifactsForSelection(roots, products, selectedProducts) if (product.id === 'oliphaunt-swift') { artifacts.push( ...swiftReleaseInputs(files, product, { - requireExtensionFixture: hasSelectedExtensionProducts, + requireExtensionFixture, + nativeSourceBasis, }), ); } else if (product.id === 'oliphaunt-react-native') { @@ -1858,108 +1870,46 @@ function discoverProductArtifactsForSelection(roots, products, selectedProducts) ); } -export function discoverProductArtifacts(roots, products) { - return discoverProductArtifactsForSelection(roots, products, products); +export function discoverProductArtifacts(roots, products, options = {}) { + return discoverProductArtifactsForSelection(roots, products, products, options); } -function sourceIdentity(headRef) { - const snapshot = JSON.parse(process.env.OLIPHAUNT_GIT_SOURCE_JSON || '{}'); - if ( - ![snapshot.commit, snapshot.tree, snapshot.checkout].every((value) => - /^[0-9a-f]{40}$/u.test(value ?? ''), - ) || - !( - headRef === snapshot.ref || - headRef === snapshot.commit || - (headRef === 'HEAD' && snapshot.checkout === snapshot.commit) - ) - ) { - throw error( - 'source identity for ' + - headRef + - ' requires a matching Git snapshot from bash tools/release/with-source.sh', - ); +export function packageDependencyMatchesCarrier(dependency, carrier) { + if (carrier === undefined || `${dependency.ecosystem}:${dependency.name}` !== carrier.id) { + return false; } - return { commit: snapshot.commit, tree: snapshot.tree }; + let requirement = dependency.requirement; + if (dependency.ecosystem === 'maven') return requirement === carrier.version; + if (dependency.ecosystem === 'cargo') { + // Cargo's bare version is a caret requirement; npm's bare version is exact. + requirement = requirement.trim(); + if (/^\d+(?:\.\d+){0,2}(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/u.test(requirement)) { + requirement = `^${requirement}`; + } + requirement = requirement.replaceAll(',', ' '); + } + return Bun.semver.satisfies(carrier.version, requirement); } export function projectInternalDependencyIds(carriers, dependencies) { - const ids = new Set(carriers.map((carrier) => carrier.id)); + const byId = new Map(carriers.map((carrier) => [carrier.id, carrier])); return [ ...new Set( dependencies - .map((dependency) => `${dependency.ecosystem}:${dependency.name}`) - .filter((id) => ids.has(id)), + .filter((dependency) => + PUBLICATION_DEPENDENCY_SCOPES[dependency.ecosystem]?.has(dependency.scope), + ) + .filter((dependency) => + packageDependencyMatchesCarrier( + dependency, + byId.get(`${dependency.ecosystem}:${dependency.name}`), + ), + ) + .map((dependency) => `${dependency.ecosystem}:${dependency.name}`), ), ].sort(compareText); } -export function validateCargoPayloadPartSets(carriers) { - const byId = new Map(carriers.map((carrier) => [carrier.id, carrier])); - const partsByParent = new Map(); - for (const carrier of carriers) { - if (carrier.role !== 'payload-part') { - continue; - } - if ( - carrier.declared || - carrier.ecosystem !== 'cargo' || - typeof carrier.parentCarrier !== 'string' - ) { - throw error(`${carrier.id} has invalid dynamic Cargo payload-part metadata`); - } - const list = partsByParent.get(carrier.parentCarrier) ?? []; - list.push(carrier); - partsByParent.set(carrier.parentCarrier, list); - } - - const parents = new Set(partsByParent.keys()); - for (const carrier of carriers) { - if (carrier.ecosystem !== 'cargo' || carrier.role === 'payload-part') { - continue; - } - if ( - (carrier.packageDependencies ?? []).some( - (dependency) => - dependency.ecosystem === 'cargo' && dependency.name.startsWith(`${carrier.name}-part-`), - ) - ) { - parents.add(carrier.id); - } - } - - for (const parentId of [...parents].sort(compareText)) { - const parent = byId.get(parentId); - if (parent === undefined || parent.ecosystem !== 'cargo' || !parent.declared) { - throw error(`dynamic Cargo payload parts require their declared parent carrier ${parentId}`); - } - const parts = [...(partsByParent.get(parentId) ?? [])].sort( - (left, right) => left.part - right.part, - ); - if (parts.length === 0 || parts.length > 999) { - throw error(`${parentId} must have between 1 and 999 Cargo payload parts`); - } - const actualNumbers = parts.map((part) => part.part); - const expectedNumbers = Array.from({ length: parts.length }, (_, index) => index + 1); - if (stableJson(actualNumbers) !== stableJson(expectedNumbers)) { - throw error( - `${parentId} Cargo payload parts must be contiguous from part-001; found ${actualNumbers.map((part) => String(part).padStart(3, '0')).join(', ')}`, - ); - } - const actualIds = parts.map((part) => part.id).sort(compareText); - const dependencyIds = (parent.packageDependencies ?? []) - .filter( - (dependency) => - dependency.ecosystem === 'cargo' && dependency.name.startsWith(`${parent.name}-part-`), - ) - .map((dependency) => `cargo:${dependency.name}`) - .sort(compareText); - if (stableJson(actualIds) !== stableJson(dependencyIds)) { - throw error(`${parentId} must depend on exactly its complete Cargo payload part set`); - } - } -} - function assignPublishOrder(carriers, products) { const productOrder = new Map(products.map((product, index) => [product.id, index])); const byId = new Map(carriers.map((carrier) => [carrier.id, carrier])); @@ -2036,7 +1986,12 @@ export function buildPublicationCandidate({ artifactRoots, headRef = 'HEAD', allowMissing = false, + nativeSourceBasis = undefined, + nativeMetadataProducts = [], + artifactPhase = 'final', + swiftExtensionFixture = false, } = {}) { + const source = sourceIdentity(headRef); const catalog = loadPublicationCatalog('publication-lock', { products }); const fullCatalog = loadPublicationCatalog('publication-lock artifact classification'); const selectedProducts = new Set(catalog.products.map((product) => product.id)); @@ -2046,7 +2001,13 @@ export function buildPublicationCandidate({ selectedProducts, ); assertWasixPublicationPackages(artifacts); - const productArtifacts = discoverProductArtifacts(artifactRoots, catalog.products); + const productArtifacts = discoverProductArtifacts(artifactRoots, catalog.products, { + nativeSourceBasis, + nativeMetadataProducts, + nativeMetadataSource: source, + artifactPhase, + swiftExtensionFixture, + }); const carriers = []; const seenStableIds = new Set(); for (const artifact of artifacts) { @@ -2098,6 +2059,7 @@ export function buildPublicationCandidate({ validateCargoPayloadPartSets(carriers); assignPublishOrder(carriers, catalog.products); const packageEnvelopeDigest = digestValue({ + ...(artifactPhase === 'pre-version' ? { artifactPhase } : {}), carriers: carriers.map(carrierEnvelope), productArtifacts: productArtifacts.map(productArtifactEnvelope), }); @@ -2105,7 +2067,11 @@ export function buildPublicationCandidate({ schema: PUBLICATION_CANDIDATE_SCHEMA, catalogSchema: PUBLICATION_CATALOG_SCHEMA, catalogDigest: publicationCatalogDigest(catalog), - source: sourceIdentity(headRef), + source, + ...(nativeMetadataProducts.length || artifactPhase === 'pre-version' + ? { scope: 'construction' } + : {}), + ...(artifactPhase === 'pre-version' ? { artifactPhase } : {}), products: catalog.products, carriers, productArtifacts, @@ -2174,6 +2140,11 @@ function withoutDigest(value) { export function freezePublicationCandidate(candidate) { validatePublicationCandidate(candidate); + if (candidate.scope !== undefined || Object.hasOwn(candidate, 'nativePayloads')) { + throw error( + 'native construction candidate lacks qualified producer and completed-baseline evidence; cannot freeze', + ); + } if (candidate.missing.length > 0) { throw error(`cannot freeze candidate with missing carriers: ${candidate.missing.join(', ')}`); } @@ -2186,6 +2157,39 @@ export function freezePublicationCandidate(candidate) { return frozen; } +/** Fresh native publication is authorized only by the authenticated post-version + * controller. Parsed construction JSON and metadata cannot mint this capability. */ +export async function freezeNativePublicationCandidate(candidate) { + validatePublicationCandidate(candidate); + const { assertAdmittedNativePublicationCandidate } = await import( + './native-freeze-publication-candidate.mts' + ); + assertAdmittedNativePublicationCandidate(candidate); + if ( + candidate.scope !== 'construction' || + (candidate.artifactPhase ?? 'final') !== 'final' || + candidate.missing.length || + Object.hasOwn(candidate, 'nativePayloads') + ) + throw error('native publication admission requires an exact complete final envelope'); + const metadata = candidate.productArtifacts.filter( + (artifact) => artifact.kind === NATIVE_PUBLICATION_METADATA_KIND, + ); + if ( + metadata.length !== candidate.products.length || + candidate.products.some( + (product) => metadata.filter((artifact) => artifact.product === product.id).length !== 1, + ) + ) + throw error('native publication admission requires every selected product provenance file'); + const frozen = { ...structuredClone(candidate), schema: PUBLICATION_LOCK_SCHEMA }; + delete frozen.scope; + delete frozen.missing; + frozen.lockDigest = digestValue(withoutDigest(frozen)); + validatePublicationLock(frozen); + return frozen; +} + function assertHash(value, context) { if (typeof value !== 'string' || !/^[0-9a-f]{64}$/u.test(value)) { throw error(`${context} must be a lowercase SHA-256 digest`); @@ -2277,15 +2281,153 @@ function validateCandidateCatalog(candidate) { } function expectedExtensionMetadataNames(product) { - const family = extensionCarrierFamily(product); + return extensionReleaseMetadataRows(product) + .map(([, name]) => name) + .sort(compareText); +} + +export function extensionReleaseMetadataRows(product, family = extensionCarrierFamily(product)) { + return declaredExtensionReleaseMetadataRows(product, family); +} + +function expectedExtensionProductArtifactRows(product, inputContext = undefined) { + const owner = extensionPublicationOwner(product); return [ - `${product.id}-${product.version}-manifest.json`, - `${product.id}-${product.version}-manifest.properties`, - ...(family === null || family === 'native' - ? [swiftExtensionCarrierAssetName(product.id, product.version)] - : []), - `${product.id}-${product.version}-release-assets.sha256`, - ].sort(compareText); + ...expectedExtensionGithubReleaseAssetRows(product, undefined, inputContext).map((row) => ({ + product: owner, + version: product.version, + id: `github-release:${row.name}`, + role: 'github-release-asset', + kind: row.kind, + target: row.target, + identity: row.identity, + name: row.name, + })), + ...extensionReleaseMetadataRows(product).map(([kind, name]) => ({ + product: owner, + version: product.version, + id: `github-release:${name}`, + role: 'github-release-metadata', + kind, + target: 'portable', + identity: null, + name, + })), + ]; +} + +function expectedProductArtifacts( + product, + hasSelectedExtensionProducts, + artifactPhase, + inputContext = undefined, +) { + if (EXTENSION_PRODUCT_KINDS.has(product.kind)) + return expectedExtensionProductArtifactRows(product, inputContext); + const rows = allArtifactTargets( + { product: product.id, surface: 'github-release', inputContext }, + 'publication-lock', + ).map((target) => { + const name = target.asset.replaceAll('{version}', product.version); + return { + product: product.id, + version: product.version, + id: `github-release:${name}`, + role: 'github-release-asset', + kind: target.kind, + target: target.target, + identity: null, + name, + }; + }); + const releaseInputs = []; + if (product.id === 'oliphaunt-swift') { + releaseInputs.push( + ...SWIFT_RELEASE_INPUT_FILES.map(([name, kind]) => ({ name, kind })), + { name: 'oliphaunt-react-native-ios-carriers.json', kind: 'swiftpm-ios-carrier-manifest' }, + { id: 'swiftpm-release-tree', name: 'release-tree', kind: 'swiftpm-release-tree' }, + ...(hasSelectedExtensionProducts && artifactPhase === 'final' + ? [ + { + name: 'swiftpm-extension-consumer-fixture', + kind: 'swiftpm-extension-consumer-fixture', + }, + ] + : []), + ); + } else if (product.id === 'oliphaunt-react-native') { + releaseInputs.push({ + name: 'oliphaunt-react-native-ios-carriers.json', + kind: 'react-native-ios-carrier-manifest', + }); + } + rows.push( + ...releaseInputs.map(({ id, name, kind }) => ({ + product: product.id, + version: product.version, + id: `release-input:${id ?? name}`, + role: 'release-input', + kind, + target: 'portable', + identity: null, + name, + })), + ); + const contrib = contribCarrierDescriptor('publication-lock', inputContext); + for (const family of ['native', 'wasix']) { + const owner = family === 'native' ? contrib.nativeOwner : contrib.wasixOwner; + if (product.id === owner) + rows.push( + ...expectedExtensionProductArtifactRows( + { + id: contrib.artifactProduct, + version: product.version, + releaseProduct: product.id, + family, + }, + inputContext, + ), + ); + } + return rows; +} + +export function expectedProductArtifactRows( + products, + { + nativeMetadataProducts = [], + artifactPhase = 'final', + swiftExtensionFixture = false, + inputContext = undefined, + } = {}, +) { + if (!['pre-version', 'final'].includes(artifactPhase)) + throw error('artifact inventory phase must be pre-version or final'); + if ( + !Array.isArray(products) || + products.some( + (product) => + !product || + typeof product.id !== 'string' || + typeof product.version !== 'string' || + typeof product.kind !== 'string', + ) + ) + throw error('expected artifact inventory requires canonical product rows'); + if (new Set(products.map(({ id }) => id)).size !== products.length) + throw error('expected artifact inventory requires unique product rows'); + if (typeof swiftExtensionFixture !== 'boolean') + throw error('Swift extension fixture request must be explicit'); + if (swiftExtensionFixture && !products.some(({ id }) => id === 'oliphaunt-swift')) + throw error('Swift extension fixture requires the source SDK product'); + return [ + ...products.flatMap((product) => + expectedProductArtifacts(product, swiftExtensionFixture, artifactPhase, inputContext), + ), + ...nativePublicationMetadataArtifactRows(products, nativeMetadataProducts), + ].sort((left, right) => + compareText(`${left.product}:${left.id}`, `${right.product}:${right.id}`), + ); } function validateExtensionProductArtifactInventory(product, artifacts) { @@ -2326,40 +2468,34 @@ function validateExtensionProductArtifactInventory(product, artifacts) { } } -function validateProductArtifactInventory(product, artifacts, { hasSelectedExtensionProducts }) { - if (EXTENSION_PRODUCT_KINDS.has(product.kind)) { - validateExtensionProductArtifactInventory(product, artifacts); - return; - } - - const targets = allArtifactTargets( - { - product: product.id, - surface: 'github-release', - }, - 'publication-lock', +function validateProductArtifactInventory(product, artifacts, { expectedRows }) { + const nativeMetadata = artifacts.filter( + (artifact) => artifact.kind === NATIVE_PUBLICATION_METADATA_KIND, ); - const expected = targets.map( - (target) => `github-release:${target.asset.replaceAll('{version}', product.version)}`, + const expectedNativeMetadata = nativePublicationMetadataArtifactRows( + [product], + nativeMetadata.length ? [product.id] : [], ); - if (product.id === 'oliphaunt-swift') { - expected.push( - 'release-input:Oliphaunt-source.zip', - 'release-input:Package.swift.release', - 'release-input:extension-owner-catalog.json', - 'release-input:extension-resource-inventory.mjs', - 'release-input:oliphaunt-react-native-ios-carriers.json', - 'release-input:render-extension-products.mjs', - 'release-input:swift-carrier-resolver.mjs', - 'release-input:swiftpm-release-tree', - ); - if (hasSelectedExtensionProducts) { - expected.push('release-input:swiftpm-extension-consumer-fixture'); + if (nativeMetadata.length > 1) throw error(`${product.id} has ambiguous native metadata`); + for (const artifact of nativeMetadata) { + const expected = expectedNativeMetadata[0]; + for (const key of ['id', 'product', 'role', 'kind', 'target', 'identity', 'name']) { + if (artifact[key] !== expected[key]) + throw error(`${product.id} has noncanonical native metadata ${key}`); } } - if (product.id === 'oliphaunt-react-native') { - expected.push('release-input:oliphaunt-react-native-ios-carriers.json'); + const deliveryArtifacts = artifacts.filter( + (artifact) => artifact.kind !== NATIVE_PUBLICATION_METADATA_KIND, + ); + if (EXTENSION_PRODUCT_KINDS.has(product.kind)) { + validateExtensionProductArtifactInventory(product, deliveryArtifacts); + return; } + + const expected = [ + ...expectedRows.filter((row) => row.product === product.id), + ...expectedNativeMetadata, + ].map(({ id }) => id); const contrib = contribCarrierDescriptor('publication-lock'); for (const family of ['native', 'wasix']) { const owner = family === 'native' ? contrib.nativeOwner : contrib.wasixOwner; @@ -2377,7 +2513,6 @@ function validateProductArtifactInventory(product, artifacts, { hasSelectedExten const nameSet = new Set(names); const extensionArtifacts = artifacts.filter((artifact) => nameSet.has(artifact.name)); validateExtensionProductArtifactInventory(extensionProduct, extensionArtifacts); - expected.push(...names.map((name) => `github-release:${name}`)); } expected.sort(compareText); const actual = artifacts.map((artifact) => artifact.id).sort(compareText); @@ -2388,8 +2523,14 @@ function validateProductArtifactInventory(product, artifacts, { hasSelectedExten } } -export function validatePublicationCandidate(candidate) { +export function validatePublicationCandidate(candidate, { nativeMetadata = false } = {}) { requireObject(candidate, 'candidate'); + const artifactPhase = candidate.artifactPhase ?? 'final'; + if ( + !['pre-version', 'final'].includes(artifactPhase) || + (artifactPhase === 'pre-version' && candidate.scope !== 'construction') + ) + throw error('pre-version artifact inventory requires construction scope'); if (candidate.schema !== PUBLICATION_CANDIDATE_SCHEMA) { throw error(`candidate schema must be ${PUBLICATION_CANDIDATE_SCHEMA}`); } @@ -2413,6 +2554,14 @@ export function validatePublicationCandidate(candidate) { ) { throw error('candidate products, carriers, productArtifacts, and missing must be lists'); } + if ( + candidate.productArtifacts.some( + (artifact) => artifact.kind === NATIVE_PUBLICATION_METADATA_KIND, + ) && + candidate.scope !== 'construction' && + !nativeMetadata + ) + throw error('native metadata requires construction scope or an admitted publication lock'); const products = new Map(); for (const [index, product] of candidate.products.entries()) { requireObject(product, `candidate product ${index}`); @@ -2585,17 +2734,24 @@ export function validatePublicationCandidate(candidate) { throw error(`${id} contains invalid artifact metadata`); } } - const hasSelectedExtensionProducts = candidate.products.some((product) => - EXTENSION_PRODUCT_KINDS.has(product.kind), - ); + // The fixture is an optional consumer input. Its source-bound requirement is + // checked before native admission; historical structure follows these frozen + // artifacts rather than a newer checkout's independently adopted native pin. + const expectedRows = expectedProductArtifactRows(candidate.products, { + artifactPhase, + swiftExtensionFixture: candidate.productArtifacts.some( + ({ kind }) => kind === 'swiftpm-extension-consumer-fixture', + ), + }); for (const product of candidate.products) { validateProductArtifactInventory( product, candidate.productArtifacts.filter((artifact) => artifact.product === product.id), - { hasSelectedExtensionProducts }, + { expectedRows }, ); } const expectedEnvelope = digestValue({ + ...(artifactPhase === 'pre-version' ? { artifactPhase } : {}), carriers: candidate.carriers.map(carrierEnvelope), productArtifacts: candidate.productArtifacts.map(productArtifactEnvelope), }); @@ -2609,12 +2765,34 @@ export function validatePublicationCandidate(candidate) { export function validatePublicationLock(lock) { requireObject(lock, 'publication lock'); + if ( + lock.scope !== undefined || + Object.hasOwn(lock, 'nativePayloads') || + (lock.schema !== PUBLICATION_LOCK_SCHEMA && + lock.productArtifacts?.some((artifact) => artifact.kind === NATIVE_PUBLICATION_METADATA_KIND)) + ) { + throw error('construction evidence cannot authorize a publication lock'); + } if (lock.schema !== PUBLICATION_LOCK_SCHEMA) { throw error(`publication lock schema must be ${PUBLICATION_LOCK_SCHEMA}`); } const candidate = { ...structuredClone(lock), schema: PUBLICATION_CANDIDATE_SCHEMA, missing: [] }; delete candidate.lockDigest; - validatePublicationCandidate(candidate); + const nativeMetadata = lock.productArtifacts.some( + (artifact) => artifact.kind === NATIVE_PUBLICATION_METADATA_KIND, + ); + if ( + nativeMetadata && + lock.products.some( + (product) => + lock.productArtifacts.filter( + (artifact) => + artifact.product === product.id && artifact.kind === NATIVE_PUBLICATION_METADATA_KIND, + ).length !== 1, + ) + ) + throw error('native publication lock must retain every selected product provenance file'); + validatePublicationCandidate(candidate, { nativeMetadata }); assertHash(lock.lockDigest, 'publication lock lockDigest'); const expected = digestValue(withoutDigest(lock)); if (lock.lockDigest !== expected) { @@ -2797,13 +2975,18 @@ export function assertLockedArtifactSet(lock, actual, { product, products, ecosy } } -export function assertLockedProductArtifacts(lock, product, roots) { +export function assertLockedProductArtifacts(lock, product, roots, options = {}) { const expected = lock.productArtifacts.filter((artifact) => artifact.product === product); const productRow = lock.products.find((row) => row.id === product); if (productRow === undefined) { throw error(`publication lock does not select product ${product}`); } - const actual = discoverProductArtifactsForSelection(roots, [productRow], lock.products); + const actual = discoverProductArtifactsForSelection(roots, [productRow], lock.products, { + ...options, + swiftExtensionFixture: lock.productArtifacts.some( + ({ kind }) => kind === 'swiftpm-extension-consumer-fixture', + ), + }); const envelope = (artifacts) => artifacts .map( @@ -2945,7 +3128,7 @@ function parseArgs(argv) { if (value === undefined) { throw error(`--${key} requires a value`); } - if (key === 'artifact-root') { + if (key === 'artifact-root' || key === 'native-cohort') { repeated.set(key, [...(repeated.get(key) ?? []), value]); } else { values.set(key, value); @@ -2975,15 +3158,31 @@ function writeJson(file, value) { writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`); } -function main(argv) { +async function main(argv) { const { command, values, repeated, booleans } = parseArgs([...argv]); + const nativeCohorts = repeated.get('native-cohort') ?? []; + if ( + nativeCohorts.length && + (command !== 'candidate' || repeated.has('artifact-root') || booleans.has('allow-missing')) + ) { + throw error( + '--native-cohort supports only exhaustive construction candidates; cannot create, mix artifact roots or allow missing carriers', + ); + } if (command === 'candidate' || command === 'create') { - const candidate = buildPublicationCandidate({ + const options = { products: productsFlag(values), artifactRoots: repeated.get('artifact-root') ?? [], headRef: values.get('head-ref') ?? 'HEAD', allowMissing: command === 'candidate' && booleans.has('allow-missing'), - }); + }; + const candidate = nativeCohorts.length + ? (await import('./native-publication-candidate.mts')).buildNativePublicationCandidate({ + products: options.products, + headRef: options.headRef, + cohorts: nativeCohorts.map((file) => JSON.parse(readFileSync(file, 'utf8'))), + }) + : buildPublicationCandidate(options); const output = path.resolve( ROOT, values.get('output') ?? @@ -3020,14 +3219,14 @@ function main(argv) { return; } console.log( - 'usage: tools/release/publication-lock.mts [--products-json JSON] [--artifact-root PATH ...] [--head-ref REF] [--output PATH] [--allow-missing]', + 'usage: tools/release/publication-lock.mts [--products-json JSON] [--artifact-root PATH ... | --native-cohort FILE ...] [--head-ref REF] [--output PATH] [--allow-missing]', ); process.exit(command === '-h' || command === '--help' ? 0 : 2); } if (import.meta.main) { try { - main(Bun.argv.slice(2)); + await main(Bun.argv.slice(2)); } catch (cause) { console.error(cause instanceof Error ? cause.message : String(cause)); process.exit(1); diff --git a/tools/release/publication-lock.test.mts b/tools/release/publication-lock.test.mts index 5a49749d8..3d0ac6aba 100644 --- a/tools/release/publication-lock.test.mts +++ b/tools/release/publication-lock.test.mts @@ -5,6 +5,7 @@ import { chmodSync, mkdirSync, mkdtempSync, + readdirSync, readFileSync, rmSync, unlinkSync, @@ -13,20 +14,21 @@ import { import os from 'node:os'; import path from 'node:path'; import { gunzipSync } from 'node:zlib'; -import { - extensionCarrierLegalContract, - stageExtensionUpstreamLicenses, -} from '../../src/extensions/tools/extension-upstream-licenses.mts'; +import { composeExtensionReleaseDocuments } from '../../src/extensions/artifacts/packages/tools/build-extension-ci-artifacts.mts'; +import { bundleCarrierAssets } from '../../src/extensions/artifacts/packages/tools/bundle-carrier-assets.mts'; +import { projectNativeRuntimeAssetMember } from '../../src/extensions/artifacts/packages/tools/extension-runtime-asset-contract.mts'; +import { nativeExtensionConstructionLicenseInventory } from '../../src/extensions/tools/extension-upstream-licenses.mts'; +import { iosBaseLegalMetadata } from '../../src/native/sdks/swift/tools/ios-carrier-manifest.mts'; import { extensionDependencyRequirement } from '../../src/wasix/runtime/tools/package_liboliphaunt_wasix_cargo_artifacts.mts'; -import { - buildSwiftExtensionCarrierManifest, - iosBaseLegalMetadata, - swiftExtensionCarrierAssetName, -} from '../../src/native/sdks/swift/tools/ios-carrier-manifest.mts'; import { createDeterministicTar } from '../packaging/cargo-source-package.mts'; import { releaseJavaScript } from '../packaging/emit-javascript.mts'; -import { canonicalGzipSync } from '../packaging/portable-archive.mts'; -import { stageReleaseNotices } from '../packaging/release-notices.mts'; +import { canonicalGzipSync, readPortableArchiveEntries } from '../packaging/portable-archive.mts'; +import { + extensionGithubArtifactInputs, + loadReleaseMetadata, + nativePublicationInputProjection, + nativeSupplierGithubArtifactDeclarations, +} from './bazel-release-metadata.mts'; import { loadPublicationCatalog, resolveActualCarrier } from './publication-catalog.mts'; import { assertLockedArtifactSet, @@ -36,6 +38,8 @@ import { buildPublicationCandidate, discoverProductArtifacts, discoverPublicationArtifacts, + expectedExtensionGithubReleaseAssetRows, + expectedProductArtifactRows, freezePublicationCandidate, lockedCarrierFile, lockedPublicationFiles, @@ -46,17 +50,69 @@ import { } from './publication-lock.mts'; import { allArtifactTargets, + contribCarrierDescriptor, currentProductVersionSync, - extensionArtifactProductRoot, extensionArtifactTargets, - extensionMetadata, - extensionSourceIdentity, extensionSqlNames, + validateExtensionCatalogRows, } from './release-artifact-targets.mts'; -import { productCompatibilityVersion, ROOT } from './release-graph.mts'; +import { loadProducts, productCompatibilityVersion, ROOT } from './release-graph.mts'; +import { + extensionGithubReleaseFixture, + githubReleaseFixture, + sha256File, +} from './testdata/publication-artifact-fixtures.mts'; const temporaryDirectories = []; +function writeProducedExtensionControls(fixture, frozen, mutatePublic = undefined) { + const prefix = `${frozen.product}-${frozen.version}`; + const publicFile = path.join(fixture.directory, `${prefix}-manifest.json`); + const previous = JSON.parse(readFileSync(publicFile, 'utf8')); + const { releaseData } = composeExtensionReleaseDocuments({ + product: frozen.product, + releaseProduct: frozen.releaseProduct ?? frozen.product, + family: frozen.family ?? null, + version: frozen.version, + members: frozen.extensions ?? [frozen], + directAssets: frozen.carrierAssets ?? frozen.assets, + releaseMetadata: { + class: previous.extensionClass, + versioning: previous.versioning, + sourceIdentity: previous.sourceIdentity, + compatibility: frozen.compatibility, + }, + }); + mutatePublic?.(releaseData); + writeFileSync(fixture.manifestPath, JSON.stringify(frozen)); + writeFileSync(publicFile, JSON.stringify(releaseData)); + const checksum = `${prefix}-release-assets.sha256`; + writeFileSync( + path.join(fixture.directory, checksum), + readdirSync(fixture.directory) + .filter((name) => name !== checksum) + .sort() + .map((name) => `${sha256File(path.join(fixture.directory, name))} ./${name}\n`) + .join(''), + ); +} + +function assertExpectedArtifactInventory(artifacts, products) { + const versions = new Map(products.map(({ id, version }) => [id, version])); + expect( + artifacts.map(({ product, id, role, kind, target, identity, name }) => ({ + product, + version: versions.get(product), + id, + role, + kind, + target, + identity, + name, + })), + ).toEqual(expectedProductArtifactRows(products)); +} + if (['prepare-handoff', 'prepare-npm-preflight'].includes(process.argv[2])) { const root = process.argv[3]; const catalog = loadPublicationCatalog('publication-lock.test', { products: ['oliphaunt-js'] }); @@ -93,6 +149,413 @@ if (process.argv[2] === 'assert-source') { process.exit(0); } +test('native publication inventory requires no Moon metadata and preserves runtime carrier ownership', () => { + const script = ` + Bun.YAML.parse = () => { throw new Error('Moon metadata must not be read'); }; + const { loadPublicationCatalog } = await import('./tools/release/publication-catalog.mts'); + const { expectedProductArtifactRows } = await import('./tools/release/publication-lock.mts'); + const catalog = loadPublicationCatalog('native-inventory-test'); + const rows = expectedProductArtifactRows(catalog.products); + const versions = new Map(catalog.products.map(({ id, version }) => [id, version])); + if (rows.some(row => row.version !== versions.get(row.product))) throw new Error('Wrong release owner version'); + if (new Set(rows.map(row => row.product + ':' + row.id)).size !== rows.length) throw new Error('Duplicate artifact identity'); + const contrib = rows.filter(row => row.name.startsWith('oliphaunt-extension-contrib-pg18-')); + if (!contrib.some(row => row.product === 'liboliphaunt-native' && row.identity === 'native')) throw new Error('Missing native contrib envelope'); + if (!contrib.some(row => row.product === 'liboliphaunt-wasix' && row.identity === 'wasix')) throw new Error('Missing WASIX contrib envelope'); + if (contrib.some(row => row.product === 'oliphaunt-extension-contrib-pg18')) throw new Error('Contrib has no independent release version'); + const swiftOnly = loadPublicationCatalog('native-inventory-swift', { products: ['oliphaunt-swift'] }); + if (expectedProductArtifactRows(swiftOnly.products).some(row => row.kind === 'swiftpm-extension-consumer-fixture')) throw new Error('Unselected extension fixture'); + if (rows.some(row => row.kind === 'swiftpm-extension-consumer-fixture')) throw new Error('Undeclared consumer fixture'); + if (!expectedProductArtifactRows(catalog.products, { swiftExtensionFixture: true }).some(row => row.kind === 'swiftpm-extension-consumer-fixture')) throw new Error('Missing requested extension fixture'); + `; + const result = Bun.spawnSync([process.execPath, '-e', script], { + cwd: ROOT, + env: { ...process.env, OLIPHAUNT_MOON_PROJECTS_FILE: '/missing-moon-projects.json' }, + }); + expect(result.exitCode, result.stderr.toString()).toBe(0); +}); + +function historicalArtifactContext() { + const files = new Map( + [ + 'src/database-resources/contracts/contract.json', + 'src/extensions/contracts/extension-target-profiles.toml', + 'src/extensions/generated/sdk/extensions.json', + 'src/extensions/generated/mobile/static-extensions.tsv', + ].map((file) => [file, readFileSync(path.join(ROOT, file), 'utf8')]), + ); + return { + files, + context: { + products: structuredClone(loadProducts('historical-artifact-test')), + contrib: structuredClone(contribCarrierDescriptor('historical-artifact-test')), + readText: (file) => { + if (!files.has(file)) throw new Error(`uncaptured historical input ${file}`); + return files.get(file); + }, + }, + }; +} + +test('historical artifact context preserves all current canonical renderer output', () => { + const { context } = historicalArtifactContext(); + const catalog = loadPublicationCatalog('historical-artifact-parity'); + expect(expectedProductArtifactRows(catalog.products, { inputContext: context })).toEqual( + expectedProductArtifactRows(catalog.products), + ); +}); + +test('historical artifact context uses captured runtime targets and contrib member profiles', () => { + const { context, files } = historicalArtifactContext(); + const native = context.contrib.nativeOwner; + const wasix = context.contrib.wasixOwner; + context.products[native].artifact_targets.targets = ['linux-x64-gnu']; + context.products[wasix].artifact_targets.targets = ['portable']; + context.contrib.members = [ + { id: 'old_one', 'sql-name': 'old_one' }, + { id: 'old_two', 'sql-name': 'old_two' }, + ]; + files.set( + 'src/extensions/contracts/extension-target-profiles.toml', + `schema = "oliphaunt-extension-artifact-target-profiles-v1" +[[profiles]] +id = "old-native" +[[profiles.targets]] +target = "linux-x64-gnu" +family = "native" +kind = "native-dynamic" +[[profiles]] +id = "old-wasix" +[[profiles.targets]] +target = "wasix-portable" +family = "wasix" +kind = "wasix-runtime" +`, + ); + // Bundled historical members do not require today's singleton mobile files. + files.delete('src/extensions/generated/sdk/extensions.json'); + files.delete('src/extensions/generated/mobile/static-extensions.tsv'); + const product = { id: native, kind: context.products[native].kind, version: '0.1.0' }; + const rows = expectedProductArtifactRows([product], { inputContext: context }); + expect(rows.filter((row) => row.kind === 'native-runtime').map((row) => row.target)).toEqual([ + 'linux-x64-gnu', + ]); + expect(rows.filter((row) => row.kind === 'extension-bundle').map((row) => row.name)).toEqual([ + `${context.contrib.artifactProduct}-0.1.0-native-linux-x64-gnu-bundle.tar.gz`, + ]); + expect(extensionSqlNames(context.contrib.artifactProduct, 'historical-test', context)).toEqual([ + 'old_one', + 'old_two', + ]); +}); + +test('historical artifact context uses the captured resource contract rather than current seed slots', () => { + const { context, files } = historicalArtifactContext(); + files.set( + 'src/database-resources/contracts/contract.json', + JSON.stringify({ + compatibilityKeys: { native: { 'linux-x64-gnu': [] } }, + profiles: { standard: {} }, + }), + ); + const rows = expectedProductArtifactRows( + [ + { + id: 'database-resources', + kind: context.products['database-resources'].kind, + version: '0.1.0', + }, + ], + { inputContext: context }, + ); + expect( + rows.filter((row) => ['native-seeds', 'wasix-seeds'].includes(row.kind)).map((row) => row.name), + ).toEqual([ + 'database-resources-0.1.0-seed-native-linux-x64-gnu-standard.json', + 'database-resources-0.1.0-seed-native-linux-x64-gnu-standard.tar.zst', + 'database-resources-0.1.0-seed-wasix-standard.json', + 'database-resources-0.1.0-seed-wasix-standard.tar.zst', + ]); + files.delete('src/database-resources/contracts/contract.json'); + expect(() => + expectedProductArtifactRows( + [{ id: 'database-resources', kind: 'resource', version: '0.1.0' }], + { inputContext: context }, + ), + ).toThrow('uncaptured historical input'); +}); + +test('historical artifact context keeps old iOS module and dependency identities without current file fallback', () => { + const { context, files } = historicalArtifactContext(); + context.products = { + [context.contrib.nativeOwner]: { + ...context.products[context.contrib.nativeOwner], + artifact_targets: { preset: 'liboliphaunt-native', targets: ['ios-xcframework'] }, + }, + [context.contrib.wasixOwner]: { + ...context.products[context.contrib.wasixOwner], + artifact_targets: { preset: 'liboliphaunt-wasix', targets: ['portable'] }, + }, + 'oliphaunt-extension-vector': { + kind: 'exact-extension-artifact', + extension_sql_name: 'vector', + path: 'gone/old-vector', + }, + }; + files.set( + 'src/extensions/contracts/extension-target-profiles.toml', + `schema = "oliphaunt-extension-artifact-target-profiles-v1" +[[profiles]] +id = "old-ios" +[[profiles.targets]] +target = "ios-xcframework" +family = "native" +kind = "native-static-registry" +`, + ); + files.set( + 'src/extensions/generated/sdk/extensions.json', + JSON.stringify({ extensions: [{ 'sql-name': 'vector', 'native-module-stem': 'old_vector' }] }), + ); + files.set( + 'src/extensions/generated/mobile/static-extensions.tsv', + 'sql-name\tnative-module-stem\tios-static-dependencies\nvector\told_vector\topenssl\n', + ); + const product = { + id: 'oliphaunt-extension-vector', + kind: 'exact-extension-artifact', + version: '0.0.9', + }; + const rows = expectedProductArtifactRows([product], { inputContext: context }); + expect(rows.filter((row) => row.role === 'github-release-asset').map((row) => row.name)).toEqual([ + 'oliphaunt-extension-vector-0.0.9-native-ios-dependency-openssl-xcframework.zip', + 'oliphaunt-extension-vector-0.0.9-native-ios-runtime.tar.gz', + 'oliphaunt-extension-vector-0.0.9-native-ios-xcframework.zip', + ]); + expect(rows.find((row) => row.kind === 'ios-xcframework').identity).toBe('old_vector'); + const outsideOldTables = new Map(files); + outsideOldTables.set( + 'src/extensions/contracts/extension-target-profiles.toml', + files.get('src/extensions/contracts/extension-target-profiles.toml') + + ` +[[profiles.targets]] +target = "linux-arm64-gnu" +family = "native" +kind = "native-dynamic" +`, + ); + const rejected = Bun.spawnSync( + [ + process.execPath, + '-e', + ` + import { expectedProductArtifactRows } from './tools/release/publication-lock.mts'; + const { product, context, files } = JSON.parse(process.env.HISTORICAL_ARTIFACT_FIXTURE); + context.readText = (file) => { + if (!Object.hasOwn(files, file)) throw new Error('uncaptured historical input ' + file); + return files[file]; + }; + expectedProductArtifactRows([product], { inputContext: context }); + `, + ], + { + cwd: ROOT, + env: { + ...process.env, + HISTORICAL_ARTIFACT_FIXTURE: JSON.stringify({ + product, + context, + files: Object.fromEntries(outsideOldTables), + }), + }, + }, + ); + expect(rejected.exitCode).not.toBe(0); + expect(rejected.stderr.toString()).toContain('not backed by runtime artifact metadata'); + const wasixTargets = context.products[context.contrib.wasixOwner].artifact_targets; + delete context.products[context.contrib.wasixOwner].artifact_targets; + expect(() => expectedProductArtifactRows([product], { inputContext: context })).toThrow( + 'missing historical runtime artifact targets', + ); + context.products[context.contrib.wasixOwner].artifact_targets = wasixTargets; + files.delete('src/extensions/generated/mobile/static-extensions.tsv'); + expect(() => expectedProductArtifactRows([product], { inputContext: context })).toThrow( + 'uncaptured historical input', + ); + files.delete('src/extensions/generated/sdk/extensions.json'); + expect(() => expectedProductArtifactRows([product], { inputContext: context })).toThrow( + 'uncaptured historical input', + ); + files.delete('src/extensions/contracts/extension-target-profiles.toml'); + expect(() => expectedProductArtifactRows([product], { inputContext: context })).toThrow( + 'uncaptured historical input', + ); + delete context.products[context.contrib.nativeOwner]; + expect(() => + allArtifactTargets({ product: 'liboliphaunt-native', inputContext: context }), + ).toThrow('missing historical product'); +}); + +test('canonical extension GitHub projection matches every legacy native asset row', () => { + const metadata = loadReleaseMetadata(ROOT); + const nativePayloads = metadata.extensionGithubArtifacts.filter( + (row) => row.family === 'native' && !row.control, + ); + const distributions = [ + ...new Set(metadata.extensionGithubArtifacts.map((row) => row.artifactProduct)), + ]; + expect(distributions).toHaveLength(8); + for (const artifactProduct of distributions) { + const actual = nativePayloads.filter((row) => row.artifactProduct === artifactProduct); + const identity = { id: artifactProduct, version: actual[0].version, family: 'native' }; + const legacy = expectedExtensionGithubReleaseAssetRows(identity).filter( + (row) => row.family === 'native', + ); + expect(actual).toEqual( + legacy.map((row) => ({ + artifactProduct, + owner: actual[0].owner, + product: actual[0].owner, + version: actual[0].version, + id: `github-release:${row.name}`, + role: 'github-release-asset', + family: row.family, + kind: row.kind, + target: row.target, + identity: row.identity, + name: row.name, + })), + ); + expect( + expectedExtensionGithubReleaseAssetRows(identity, { + sqlNames: extensionSqlNames(artifactProduct), + requiredRows: legacy.map(({ name: _name, ...row }) => row), + }), + ).toEqual(legacy); + } + expect(nativePayloads).toHaveLength(68); + expect( + metadata.extensionGithubArtifacts.filter((row) => row.family === 'wasix' && !row.control), + ).toHaveLength(8); + expect(metadata.extensionGithubArtifacts.filter((row) => row.control)).toHaveLength(35); + for (const [target, count] of [ + ['android-arm64-v8a', 8], + ['android-x86_64', 8], + ['ios-xcframework', 20], + ]) + expect(metadata.extensionGithubArtifacts.filter((row) => row.target === target)).toHaveLength( + count, + ); + const catalog = loadPublicationCatalog('canonical-extension-github-projection'); + const old = expectedProductArtifactRows(catalog.products).filter( + (row) => + row.role === 'github-release-asset' && + metadata.extensionGithubArtifacts.some( + (asset) => asset.product === row.product && asset.id === row.id, + ), + ); + expect( + metadata.extensionGithubArtifacts + .filter((row) => !row.control) + .map(({ artifactProduct: _artifactProduct, owner: _owner, family: _family, ...row }) => row) + .sort((left, right) => left.id.localeCompare(right.id)), + ).toEqual(old.sort((left, right) => left.id.localeCompare(right.id))); +}); + +test('canonical extension GitHub projection preserves all 39 legacy mobile member contracts', () => { + const metadata = loadReleaseMetadata(ROOT); + const catalog = validateExtensionCatalogRows( + JSON.parse( + readFileSync(path.join(ROOT, 'src/extensions/generated/extensions.catalog.json'), 'utf8'), + ), + ); + const sdk = JSON.parse( + readFileSync(path.join(ROOT, 'src/extensions/generated/sdk/extensions.json'), 'utf8'), + ); + const lines = readFileSync( + path.join(ROOT, 'src/extensions/generated/mobile/static-extensions.tsv'), + 'utf8', + ) + .split(/\r?\n/u) + .filter((line) => line && !line.startsWith('#')); + const columns = lines[0].split('\t'); + const statics = new Map( + lines.slice(1).map((line) => { + const values = line.split('\t'); + const row = Object.fromEntries(columns.map((key, index) => [key, values[index] ?? ''])); + return [row['sql-name'], row]; + }), + ); + expect(metadata.extensionReleaseMetadata).toHaveLength(39); + let compared = 0; + for (const member of metadata.extensionReleaseMetadata) { + const sqlName = member.sqlName; + const legacy = sdk.extensions.find((row) => row['sql-name'] === sqlName); + expect(legacy).toBeDefined(); + const stem = legacy['native-module-stem'] ?? null; + const profiles = Object.keys(metadata.nativeMobileComponentClosures[sqlName]).map((target) => ({ + target, + family: 'native', + kind: 'native-static-registry', + })); + expect(profiles).toHaveLength(3); + const identity = { + artifactProduct: member.artifactProduct, + owner: 'fixture', + version: '1.2.3', + sqlNames: [sqlName], + }; + const actual = extensionGithubArtifactInputs( + identity, + profiles, + catalog, + metadata.nativeMobileComponentClosures, + ); + for (const { target } of profiles) { + const dependencies = + stem === null + ? [] + : ( + statics.get(sqlName)?.[ + target === 'ios-xcframework' + ? 'ios-static-dependencies' + : 'android-static-dependencies' + ] ?? '' + ) + .split(',') + .filter(Boolean) + .sort(); + expect([...metadata.nativeMobileComponentClosures[sqlName][target].linkUnits].sort()).toEqual( + dependencies, + ); + const rows = [{ sqlName, family: 'native', target, kind: 'runtime', identity: null }]; + if (target === 'ios-xcframework' && stem !== null) + rows.push( + { sqlName, family: 'native', target, kind: 'ios-xcframework', identity: stem }, + ...dependencies.map((dependency) => ({ + sqlName, + family: 'native', + target, + kind: 'ios-dependency-xcframework', + identity: dependency, + })), + ); + rows.sort( + (left, right) => + left.kind.localeCompare(right.kind) || + (left.identity ?? '').localeCompare(right.identity ?? ''), + ); + expect( + actual + .filter((row) => row.target === target) + .map(({ kind, identity }) => ({ kind, identity })), + ).toEqual(rows.map(({ kind, identity }) => ({ kind, identity }))); + compared += 1; + } + } + expect(compared).toBe(117); +}); + test('frozen Cargo bytes reject a changed archive header with unchanged package identity', () => { const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-frozen-cargo-')); temporaryDirectories.push(root); @@ -114,46 +577,6 @@ test('frozen Cargo bytes reject a changed archive header with unchanged package ).toThrow(/frozen artifact bytes mismatch/u); }); -function sortJsonValue(value) { - if (Array.isArray(value)) return value.map(sortJsonValue); - if (value !== null && typeof value === 'object') { - return Object.fromEntries( - Object.keys(value) - .sort() - .map((key) => [key, sortJsonValue(value[key])]), - ); - } - return value; -} - -function canonicalJson(value) { - return `${JSON.stringify(sortJsonValue(value), null, 2)}\n`; -} - -function wasixInstall(sqlName, dependencies, createsExtension) { - return { - schema: 'oliphaunt-wasix-extension-install-v1', - name: sqlName, - nativeModule: null, - nativeModules: [], - coreExportsRequired: [], - dependencies, - loadOrder: [], - lifecycle: { - createExtension: createsExtension, - createSchema: 'pg_catalog', - loadSql: [], - postCreateSql: [], - startupConfig: [], - preloadRequired: false, - restartRequired: false, - sharedMemoryRequired: false, - }, - installedFiles: [`share/postgresql/extension/${sqlName}.control`], - unresolvedImports: [], - }; -} - function refreshTarHeaderChecksum(tar, offset = 0) { tar.fill(0x20, offset + 148, offset + 156); const checksum = tar.subarray(offset, offset + 512).reduce((total, byte) => total + byte, 0); @@ -202,6 +625,44 @@ function selectionNeutralSwiftSourceCarrier(version = '1.2.3') { }; } +test('React Native aggregate carrier discovery accepts declared and legacy layouts without selecting Swift source inputs', () => { + const root = temporaryDirectory(); + const name = 'oliphaunt-react-native-ios-carriers.json'; + const products = loadPublicationCatalog('publication-lock.test', { + products: ['oliphaunt-react-native'], + }).products; + const bytes = Buffer.from(`${JSON.stringify(selectionNeutralSwiftSourceCarrier())}\n`); + const sourceTree = path.join(root, 'release-tree/src/sdks/swift/Carriers'); + mkdirSync(sourceTree, { recursive: true }); + writeFileSync(path.join(sourceTree, name), bytes); + expect(() => discoverProductArtifacts([root], products)).toThrow( + /exactly one canonical aggregate iOS carrier manifest, found 0/u, + ); + + for (const layout of ['npm/ios-carriers', 'release/ios-carriers']) { + const directory = path.join(root, layout); + mkdirSync(directory, { recursive: true }); + const file = path.join(directory, name); + writeFileSync(file, bytes); + const artifacts = discoverProductArtifacts([root], products); + expect(artifacts).toHaveLength(1); + expect(artifacts[0]).toMatchObject({ + product: 'oliphaunt-react-native', + id: `release-input:${name}`, + kind: 'react-native-ios-carrier-manifest', + size: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + }); + unlinkSync(file); + } + + for (const layout of ['npm/ios-carriers', 'release/ios-carriers']) + writeFileSync(path.join(root, layout, name), bytes); + expect(() => discoverProductArtifacts([root], products)).toThrow( + /exactly one canonical aggregate iOS carrier manifest, found 2/u, + ); +}); + function tarGzip(output, cwd, member) { writeFileSync( output, @@ -354,419 +815,6 @@ function mavenFixture(root, group, artifact, version) { return pom; } -function sha256File(file) { - return createHash('sha256').update(readFileSync(file)).digest('hex'); -} - -function githubReleaseFixture(root, product) { - const directory = path.join(root, product.id, 'release-assets'); - mkdirSync(directory, { recursive: true }); - const rows = allArtifactTargets( - { - product: product.id, - surface: 'github-release', - }, - 'publication-lock.test', - ).map((target) => ({ - target, - name: target.asset.replaceAll('{version}', product.version), - })); - const checksum = rows.find((row) => row.target.kind === 'checksums'); - for (const row of rows.filter((item) => item !== checksum)) { - writeFileSync(path.join(directory, row.name), `fixture:${row.name}\n`); - } - const checksumLines = rows - .filter((item) => item !== checksum) - .map((row) => `${sha256File(path.join(directory, row.name))} ./${row.name}\n`) - .sort(); - writeFileSync(path.join(directory, checksum.name), checksumLines.join('')); - return { checksum, directory, rows }; -} - -function extensionGithubReleaseFixture( - root, - product, - { - artifactProduct = product.id, - family = null, - mutateBundleArchive = undefined, - mutateBundleStage = undefined, - bundleFixedFileMode = 0o644, - } = {}, -) { - const productRoot = extensionArtifactProductRoot( - artifactProduct, - family ?? 'native', - path.join(root, 'target', 'extension-artifacts'), - 'publication-lock.test', - ); - const directory = path.join(productRoot, 'release-assets'); - rmSync(productRoot, { recursive: true, force: true }); - mkdirSync(directory, { recursive: true }); - const sqlNames = extensionSqlNames(artifactProduct, 'publication-lock.test'); - const bundled = sqlNames.length > 1; - const releaseMetadata = extensionMetadata(artifactProduct, 'publication-lock.test'); - const ownership = - artifactProduct === product.id - ? {} - : { releaseProduct: product.id, family: family ?? 'combined' }; - const compatibility = releaseMetadata.compatibility; - const generated = JSON.parse( - readFileSync( - path.join(import.meta.dir, '../../src/extensions/generated/sdk/extensions.json'), - 'utf8', - ), - ); - const staticLines = readFileSync( - path.join(import.meta.dir, '../../src/extensions/generated/mobile/static-extensions.tsv'), - 'utf8', - ) - .split(/\r?\n/u) - .filter((line) => line.length > 0 && !line.startsWith('#')); - const staticHeader = staticLines[0].split('\t'); - const staticRows = staticLines - .slice(1) - .map((line) => - Object.fromEntries( - staticHeader.map((column, index) => [column, line.split('\t')[index] ?? '']), - ), - ); - const assets = []; - const extensions = []; - for (const sqlName of sqlNames) { - const extension = generated.extensions.find((row) => row['sql-name'] === sqlName); - const nativeModuleStem = extension['native-module-stem']; - const staticRow = staticRows.find((row) => row['sql-name'] === sqlName); - const iosNativeDependencies = - nativeModuleStem === null - ? [] - : (staticRow?.['ios-static-dependencies'] ?? '').split(',').filter(Boolean).sort(); - const memberAssets = []; - for (const target of extensionArtifactTargets( - { product: artifactProduct }, - 'publication-lock.test', - ).filter((row) => row.sqlName === sqlName && (family === null || row.family === family))) { - const roles = - target.family === 'wasix' - ? ['wasix-runtime'] - : target.target === 'ios-xcframework' - ? [ - 'runtime', - ...(nativeModuleStem === null - ? [] - : [ - 'ios-xcframework', - ...iosNativeDependencies.map( - (dependency) => `ios-dependency-xcframework:${dependency}`, - ), - ]), - ] - : ['runtime']; - for (const role of roles) { - const [kind, dependencyIdentity] = role.split(':'); - const identity = - kind === 'ios-xcframework' - ? nativeModuleStem - : kind === 'ios-dependency-xcframework' - ? dependencyIdentity - : null; - const prefix = `${artifactProduct}-${product.version}`; - const name = - target.family === 'wasix' - ? `${prefix}-wasix-portable.tar.zst` - : kind === 'ios-xcframework' - ? `${prefix}-native-ios-xcframework.zip` - : kind === 'ios-dependency-xcframework' - ? `${prefix}-native-ios-dependency-${identity}-xcframework.zip` - : target.target === 'ios-xcframework' - ? `${prefix}-native-ios-runtime.tar.gz` - : `${prefix}-native-${target.target}-runtime.tar.gz`; - const file = path.join( - bundled ? path.join(productRoot, 'member-assets', sqlName) : directory, - name, - ); - mkdirSync(path.dirname(file), { recursive: true }); - writeFileSync(file, `fixture:${name}\n`); - const asset = { - name, - family: target.family, - target: target.target, - kind, - identity, - path: file, - sha256: sha256File(file), - bytes: readFileSync(file).length, - }; - assets.push(asset); - memberAssets.push(asset); - } - } - const dependencies = [...extension['selected-extension-dependencies']].sort(); - const createsExtension = extension['creates-extension'] !== false; - const stagesIos = memberAssets.some((asset) => asset.target === 'ios-xcframework'); - extensions.push({ - sqlName, - createsExtension, - dependencies, - dataFiles: [...extension['runtime-share-data-files']].sort(), - extensionSqlFileNames: [...extension['extension-sql-file-names']].sort(), - extensionSqlFilePrefixes: [...extension['extension-sql-file-prefixes']].sort(), - nativeModuleStem, - iosNativeDependencies: stagesIos ? iosNativeDependencies : [], - iosRegistration: - nativeModuleStem === null || !stagesIos - ? null - : { - schema: 'oliphaunt-ios-extension-registration-v1', - sqlName, - nativeModuleStem, - magicSymbol: `oliphaunt_static_${nativeModuleStem.replaceAll(/[^A-Za-z0-9_]/gu, '_')}_Pg_magic_func`, - initSymbol: null, - symbols: [], - }, - wasixInstall: memberAssets.some((asset) => asset.family === 'wasix') - ? wasixInstall(sqlName, dependencies, createsExtension) - : null, - sharedPreloadLibraries: [...extension['shared-preload-libraries']].sort(), - assets: memberAssets, - }); - } - const carrierAssets = []; - if (bundled) { - const groups = new Map(); - for (const extension of extensions) { - for (const asset of extension.assets) { - const key = `${asset.family}\0${asset.target}`; - const group = groups.get(key) ?? { family: asset.family, target: asset.target, rows: [] }; - group.rows.push({ sqlName: extension.sqlName, asset }); - groups.set(key, group); - } - } - for (const group of [...groups.values()].sort((left, right) => - `${left.family}\0${left.target}`.localeCompare(`${right.family}\0${right.target}`), - )) { - const archiveRoot = `${artifactProduct}-${product.version}-${group.family}-${group.target}-bundle`; - const stage = path.join(productRoot, 'bundle-stage', archiveRoot); - rmSync(stage, { recursive: true, force: true }); - mkdirSync(stage, { recursive: true }); - const manifestMembers = []; - for (const { sqlName, asset } of group.rows.sort((left, right) => - `${left.sqlName}\0${left.asset.kind}\0${left.asset.identity ?? ''}`.localeCompare( - `${right.sqlName}\0${right.asset.kind}\0${right.asset.identity ?? ''}`, - ), - )) { - const memberPath = `extensions/${sqlName}/${asset.name}`; - const destination = path.join(stage, ...memberPath.split('/')); - mkdirSync(path.dirname(destination), { recursive: true }); - writeFileSync(destination, readFileSync(asset.path)); - asset.carrierAsset = `${archiveRoot}.tar.gz`; - asset.carrierRoot = archiveRoot; - asset.memberPath = memberPath; - manifestMembers.push({ - sqlName, - kind: asset.kind, - identity: asset.identity, - path: memberPath, - sha256: asset.sha256, - bytes: asset.bytes, - }); - } - const memberNames = [...new Set(manifestMembers.map(({ sqlName }) => sqlName))].sort(); - const legal = extensionCarrierLegalContract(artifactProduct, memberNames, { - family: group.family, - target: group.target, - }); - for (const sqlName of memberNames) stageExtensionUpstreamLicenses(sqlName, stage); - const bundleManifest = path.join(stage, 'bundle-manifest.json'); - writeFileSync( - bundleManifest, - canonicalJson({ - schema: 'oliphaunt-extension-bundle-v1', - product: artifactProduct, - version: product.version, - compatibility, - family: group.family, - target: group.target, - licenseProfile: legal.profile, - licenseFiles: legal.licenseFiles, - members: manifestMembers, - }), - ); - stageReleaseNotices(stage, { profile: legal.profile }); - mutateBundleStage?.({ - archiveRoot, - bundleManifest, - family: group.family, - legal, - stage, - target: group.target, - }); - const output = path.join(directory, `${archiveRoot}.tar.gz`); - const tarOptions = { - includeDirectories: false, - fail(message) { - throw new Error(`publication lock fixture: ${message}`); - }, - }; - if (bundleFixedFileMode !== null) tarOptions.fixedFileMode = bundleFixedFileMode; - writeFileSync( - output, - canonicalGzipSync(createDeterministicTar(stage, archiveRoot, tarOptions)), - ); - mutateBundleArchive?.({ - archiveRoot, - family: group.family, - output, - target: group.target, - }); - carrierAssets.push({ - name: path.basename(output), - path: output, - sha256: sha256File(output), - bytes: readFileSync(output).length, - family: group.family, - target: group.target, - kind: 'extension-bundle', - memberCount: sqlNames.length, - }); - } - } - const extensionManifestPath = path.join(productRoot, 'extension-artifacts.json'); - const extensionManifest = bundled - ? { - schema: 'oliphaunt-extension-ci-artifacts-v2', - product: artifactProduct, - ...ownership, - version: product.version, - compatibility, - extensions, - carrierAssets, - } - : { - schema: 'oliphaunt-extension-ci-artifacts-v1', - product: artifactProduct, - ...ownership, - version: product.version, - compatibility, - ...extensions[0], - }; - writeFileSync(extensionManifestPath, `${JSON.stringify(extensionManifest, null, 2)}\n`); - const manifestName = `${artifactProduct}-${product.version}-manifest.json`; - const propertiesName = `${artifactProduct}-${product.version}-manifest.properties`; - const swiftCarrierName = swiftExtensionCarrierAssetName(artifactProduct, product.version); - const checksumName = `${artifactProduct}-${product.version}-release-assets.sha256`; - const directAssets = bundled ? carrierAssets : assets; - writeFileSync( - path.join(directory, manifestName), - `${JSON.stringify( - { - schema: bundled - ? 'oliphaunt-extension-release-manifest-v2' - : 'oliphaunt-extension-release-manifest-v1', - product: artifactProduct, - ...ownership, - version: product.version, - extensionClass: releaseMetadata.class, - versioning: releaseMetadata.versioning, - sourceIdentity: extensionSourceIdentity(artifactProduct, 'publication-lock.test'), - compatibility, - ...(bundled - ? { - extensions: extensions.map((row) => ({ - ...row, - assets: row.assets.map( - ({ - name, - family, - target, - kind, - identity, - sha256, - bytes, - carrierAsset, - carrierRoot, - memberPath, - }) => ({ - name, - family, - target, - kind, - identity, - sha256, - bytes, - carrierAsset, - carrierRoot, - memberPath, - }), - ), - })), - assets: carrierAssets.map( - ({ name, family, target, kind, sha256, bytes, memberCount }) => ({ - name, - family, - target, - kind, - sha256, - bytes, - memberCount, - }), - ), - } - : { - sqlName: extensions[0].sqlName, - createsExtension: extensions[0].createsExtension, - dependencies: extensions[0].dependencies, - dataFiles: extensions[0].dataFiles, - extensionSqlFileNames: extensions[0].extensionSqlFileNames, - extensionSqlFilePrefixes: extensions[0].extensionSqlFilePrefixes, - nativeModuleStem: extensions[0].nativeModuleStem, - iosNativeDependencies: extensions[0].iosNativeDependencies, - iosRegistration: extensions[0].iosRegistration, - wasixInstall: extensions[0].wasixInstall, - sharedPreloadLibraries: extensions[0].sharedPreloadLibraries, - assets: assets.map(({ name, family, target, kind, identity, sha256, bytes }) => ({ - name, - family, - target, - kind, - identity, - sha256, - bytes, - })), - }), - }, - null, - 2, - )}\n`, - ); - writeFileSync( - path.join(directory, propertiesName), - `schema=oliphaunt-extension-release-manifest-v${bundled ? '2' : '1'}\nproduct=${artifactProduct}\n${artifactProduct === product.id ? '' : `releaseProduct=${product.id}\ncarrierFamily=${family ?? 'combined'}\n`}version=${product.version}\n`, - ); - writeFileSync( - path.join(directory, swiftCarrierName), - `${JSON.stringify( - buildSwiftExtensionCarrierManifest({ - extensionManifest: extensionManifestPath, - verifyMembers: false, - }), - null, - 2, - )}\n`, - ); - const payloadNames = [ - ...directAssets.map((asset) => asset.name), - manifestName, - propertiesName, - swiftCarrierName, - ].sort(); - writeFileSync( - path.join(directory, checksumName), - payloadNames.map((name) => `${sha256File(path.join(directory, name))} ./${name}\n`).join(''), - ); - return { assets: directAssets, directory, manifestPath: extensionManifestPath, swiftCarrierName }; -} - afterEach(() => { while (temporaryDirectories.length > 0) { rmSync(temporaryDirectories.pop(), { recursive: true, force: true }); @@ -776,9 +824,9 @@ afterEach(() => { describe('canonical publication catalog', () => { test('projects repeated package dependencies to one sorted internal carrier edge', () => { const carriers = [ - { id: 'npm:@oliphaunt/zeta' }, - { id: 'cargo:oliphaunt-tools' }, - { id: 'cargo:oliphaunt' }, + { id: 'npm:@oliphaunt/zeta', version: '0.1.0' }, + { id: 'cargo:oliphaunt-tools', version: '0.1.0' }, + { id: 'cargo:oliphaunt', version: '0.1.0' }, ]; const packageDependencies = [ { ecosystem: 'cargo', name: 'oliphaunt-tools', requirement: '=0.1.0', scope: 'runtime' }, @@ -793,6 +841,59 @@ describe('canonical publication catalog', () => { ]); }); + test('projects only matching selected versions and package-manager publication scopes', () => { + const carriers = [ + { id: 'cargo:tools', version: '0.3.1' }, + { id: 'npm:tools', version: '0.3.1' }, + { id: 'maven:example:tools', version: '0.3.1' }, + ]; + const edge = (ecosystem, name, requirement, scope = 'runtime') => ({ + ecosystem, + name, + requirement, + scope, + }); + expect( + projectInternalDependencyIds(carriers, [ + edge('cargo', 'tools', '=0.2.4'), + edge('npm', 'tools', '0.2.4'), + edge('maven', 'example:tools', '0.2.4'), + edge('cargo', 'tools', '=0.3.1', 'development'), + edge('maven', 'example:tools', '0.3.1', 'test'), + ]), + ).toEqual([]); + expect( + projectInternalDependencyIds(carriers, [ + edge('cargo', 'tools', '0.3.0', 'build'), + edge('cargo', 'tools', '>=0.3.0,<0.4.0'), + edge('npm', 'tools', '^0.3.0', 'optional'), + edge('maven', 'example:tools', '0.3.1', 'compile'), + ]), + ).toEqual(['cargo:tools', 'maven:example:tools', 'npm:tools']); + expect(projectInternalDependencyIds(carriers, [edge('npm', 'tools', '0.3.0')])).toEqual([]); + expect(projectInternalDependencyIds(carriers, [edge('cargo', 'tools', '0.2.4')])).toEqual([]); + }); + + test('Cargo bare prerelease and build versions retain implicit caret semantics', () => { + const carriers = [ + { id: 'cargo:tools', version: '1.0.1' }, + { id: 'npm:tools', version: '1.0.1' }, + ]; + for (const requirement of ['1.0.0-rc.1', '1.0.0+build', ' 1.0.0-rc.1+build ']) { + expect( + projectInternalDependencyIds(carriers, [ + { ecosystem: 'cargo', name: 'tools', requirement, scope: 'runtime' }, + { ecosystem: 'npm', name: 'tools', requirement, scope: 'runtime' }, + ]), + ).toEqual(['cargo:tools']); + } + expect( + projectInternalDependencyIds(carriers, [ + { ecosystem: 'cargo', name: 'tools', requirement: '=1.0.0-rc.1', scope: 'runtime' }, + ]), + ).toEqual([]); + }); + test('permits only Cargo part identities as dynamic carriers', () => { const catalog = loadPublicationCatalog('publication-lock.test', { products: ['liboliphaunt-native'], @@ -865,6 +966,31 @@ describe('canonical publication catalog', () => { }); describe('publication artifact discovery and freezing', () => { + test('freezes a held-version package cycle and rejects a selected new package cycle', () => { + const version = currentProductVersionSync('oliphaunt-rust'); + const fixture = (requirement, scope = 'dependencies') => { + const root = temporaryDirectory(); + cargoFixture(root, 'oliphaunt-build', version, { + manifestSuffix: `\n${scope === 'dependencies' ? '' : `[${scope}]\n`}oliphaunt = "${requirement}"\n`, + }); + cargoFixture(root, 'oliphaunt', version, { + manifestSuffix: `\noliphaunt-build = "=${version}"\n`, + }); + return () => + buildPublicationCandidate({ products: ['oliphaunt-rust'], artifactRoots: [root] }); + }; + const held = fixture('=0.0.0')(); + expect(held.carriers.find(({ id }) => id === 'cargo:oliphaunt-build').dependencies).toEqual([]); + expect(held.carriers.find(({ id }) => id === 'cargo:oliphaunt').dependencies).toEqual([ + 'cargo:oliphaunt-build', + ]); + expect(() => validatePublicationLock(freezePublicationCandidate(held))).not.toThrow(); + expect(() => + freezePublicationCandidate(fixture(`=${version}`, 'dev-dependencies')()), + ).not.toThrow(); + expect(fixture(`=${version}`)).toThrow('carrier dependency cycle'); + }); + test('publish resolution rejects regenerated paths and mutations', () => { const root = mkdtempSync(path.join(import.meta.dir, '../../target/publication-lock-publish-')); temporaryDirectories.push(root); @@ -1138,6 +1264,7 @@ describe('publication artifact discovery and freezing', () => { const { checksum, directory, rows } = githubReleaseFixture(root, product); const artifacts = discoverProductArtifacts([root], [product]); expect(artifacts).toHaveLength(rows.length); + assertExpectedArtifactInventory(artifacts, [product]); expect( artifacts.every( (artifact) => artifact.role === 'github-release-asset' && artifact.sha256.length === 64, @@ -1170,6 +1297,7 @@ describe('publication artifact discovery and freezing', () => { product, ); const artifacts = discoverProductArtifacts([root], [product]); + assertExpectedArtifactInventory(artifacts, [product]); expect(artifacts).toHaveLength(assets.length + 4); expect( new Set( @@ -1255,6 +1383,7 @@ describe('publication artifact discovery and freezing', () => { const { assets, manifestPath } = extensionGithubReleaseFixture(root, product, fixtureOptions); const artifacts = discoverProductArtifacts([root], [product]); expect(artifacts).toHaveLength(runtimeAssets.length + assets.length + 4); + assertExpectedArtifactInventory(artifacts, [product]); expect(assets.every(({ name }) => /^oliphaunt-extension-contrib-pg18-[^-]+/u.test(name))).toBe( true, ); @@ -1306,6 +1435,115 @@ describe('publication artifact discovery and freezing', () => { ); }); + test('reads produced contrib bundle legal inventories from each selected runtime asset', { + timeout: 30_000, + }, () => { + const root = temporaryDirectory(); + const artifactProduct = 'oliphaunt-extension-contrib-pg18'; + const product = loadPublicationCatalog('publication-lock.test', { + products: ['liboliphaunt-native'], + }).products[0]; + githubReleaseFixture(root, product); + const fixture = extensionGithubReleaseFixture(root, product, { + artifactProduct, + family: 'native', + }); + const frozen = JSON.parse(readFileSync(fixture.manifestPath, 'utf8')); + frozen.carrierAssets.reverse(); + const pgcrypto = frozen.extensions.find(({ sqlName }) => sqlName === 'pgcrypto'); + expect(pgcrypto).toBeDefined(); + const linuxAssets = ['linux-x64-gnu', 'linux-arm64-gnu'].map((target) => { + const asset = pgcrypto.assets.find( + (asset) => asset.target === target && asset.kind === 'runtime', + ); + expect(asset).toBeDefined(); + asset.nativeConstructionLicenseFiles = nativeExtensionConstructionLicenseInventory( + 'pgcrypto', + target, + ).map(({ mode, path, sha256 }) => ({ mode, path, sha256 })); + expect(asset.nativeConstructionLicenseFiles).toHaveLength(2); + return asset; + }); + const rebuildBundle = (target, profile) => { + const members = frozen.extensions.map((member) => { + const assets = member.assets.filter((asset) => asset.target === target); + const runtime = assets.find((asset) => asset.kind === 'runtime'); + return { + ...projectNativeRuntimeAssetMember(member, runtime), + assets: assets.map((asset) => ({ + ...asset, + path: path.relative(root, asset.path).split(path.sep).join('/'), + })), + }; + }); + const carriers = bundleCarrierAssets( + artifactProduct, + product.version, + path.dirname(fixture.manifestPath), + members, + frozen.compatibility, + { root }, + ); + expect(carriers).toHaveLength(1); + const carrier = { ...carriers[0], path: path.resolve(root, carriers[0].path) }; + Object.assign( + frozen.carrierAssets.find((asset) => asset.target === target), + carrier, + ); + const archiveRoot = path.basename(carrier.name, '.tar.gz'); + const entries = readPortableArchiveEntries(carrier.path); + const bundleManifest = JSON.parse( + entries.get(`${archiveRoot}/bundle-manifest.json`).data().toString('utf8'), + ); + expect(bundleManifest.licenseProfile).toBe(profile); + }; + for (const { target } of linuxAssets) rebuildBundle(target, 'contrib-native-openssl'); + writeProducedExtensionControls(fixture, frozen); + assertExpectedArtifactInventory(discoverProductArtifacts([root], [product]), [product]); + + writeProducedExtensionControls(fixture, frozen, (data) => data.assets.reverse()); + expect(() => discoverProductArtifacts([root], [product])).toThrow( + /does not exactly expose the frozen aggregate member\/carrier inventory/u, + ); + writeProducedExtensionControls(fixture, frozen); + + // Legacy member-level facts remain the default when an asset has no override. + pgcrypto.nativeConstructionLicenseFiles = linuxAssets[0].nativeConstructionLicenseFiles; + delete linuxAssets[0].nativeConstructionLicenseFiles; + writeProducedExtensionControls(fixture, frozen); + assertExpectedArtifactInventory(discoverProductArtifacts([root], [product]), [product]); + + // An explicit empty target inventory must override those legacy member facts. + linuxAssets[1].nativeConstructionLicenseFiles = []; + rebuildBundle(linuxAssets[1].target, 'contrib-native'); + writeProducedExtensionControls(fixture, frozen); + assertExpectedArtifactInventory(discoverProductArtifacts([root], [product]), [product]); + }); + + test('reads produced singleton controls with exact optional native member facts', () => { + const root = temporaryDirectory(); + const product = loadPublicationCatalog('publication-lock.test', { + products: ['oliphaunt-extension-vector'], + }).products[0]; + const fixture = extensionGithubReleaseFixture(root, product); + const frozen = JSON.parse(readFileSync(fixture.manifestPath, 'utf8')); + frozen.nativeDependencyModules = ['support.so']; + frozen.nativeConstructionLicenseFiles = []; + writeProducedExtensionControls(fixture, frozen); + assertExpectedArtifactInventory(discoverProductArtifacts([root], [product]), [product]); + for (const field of ['nativeDependencyModules', 'nativeConstructionLicenseFiles']) { + for (const value of [undefined, ['changed']]) { + writeProducedExtensionControls(fixture, frozen, (data) => { + if (value === undefined) delete data[field]; + else data[field] = value; + }); + expect(() => discoverProductArtifacts([root], [product])).toThrow( + /does not exactly expose the canonical extension identity and frozen asset inventory/u, + ); + } + } + }); + test('rejects stale, missing, extra, substituted, or wrongly-moded aggregate bundle legal material', { timeout: 60_000, }, () => { @@ -1442,6 +1680,31 @@ describe('publication artifact discovery and freezing', () => { ).toBe(true); }); + test('pre-version inventory is digest-bound construction and cannot be frozen', () => { + const root = mkdtempSync(path.join(ROOT, 'target/publication-lock-phase-')); + temporaryDirectories.push(root); + const product = loadPublicationCatalog('publication-lock-phase', { products: ['oliphaunt-js'] }) + .products[0]; + npmFixture(root, '@oliphaunt/ts', product.version); + const final = buildPublicationCandidate({ products: [product.id], artifactRoots: [root] }); + const pre = buildPublicationCandidate({ + products: [product.id], + artifactRoots: [root], + artifactPhase: 'pre-version', + }); + expect(pre.carriers).toEqual(final.carriers); + expect(pre.productArtifacts).toEqual(final.productArtifacts); + expect(pre.packageEnvelopeDigest).not.toBe(final.packageEnvelopeDigest); + expect(() => validatePublicationCandidate(pre)).not.toThrow(); + expect(() => freezePublicationCandidate(pre)).toThrow(/construction.*cannot freeze/u); + const forged = { ...pre, artifactPhase: 'final' }; + expect(() => validatePublicationCandidate(forged)).toThrow(/packageEnvelopeDigest/u); + expect(() => validatePublicationCandidate({ ...pre, scope: undefined })).toThrow( + /construction scope/u, + ); + expect(() => freezePublicationCandidate(final)).not.toThrow(); + }); + test('freezes a selection-neutral Swift source carrier and separately composed dependency-closed output', () => { const workspaceRoot = mkdtempSync( path.join(import.meta.dir, '../../target/publication-lock-swift-'), @@ -1535,11 +1798,29 @@ describe('publication artifact discovery and freezing', () => { expect(() => discoverProductArtifacts([sdk, fixture], [product])).toThrow( /selects no extension products and requires no frozen Swift consumer fixture/u, ); - expect(() => discoverProductArtifacts([sdk, extensionRoot], catalog.products)).toThrow( - /selects extension products and requires exactly one frozen Swift consumer fixture/u, + expect(() => + discoverProductArtifacts([sdk, extensionRoot], catalog.products, { + swiftExtensionFixture: true, + }), + ).toThrow(/selects extension products and requires exactly one frozen Swift consumer fixture/u); + const preVersionArtifacts = discoverProductArtifacts([sdk, extensionRoot], catalog.products, { + artifactPhase: 'pre-version', + }); + expect( + preVersionArtifacts.some(({ kind }) => kind === 'swiftpm-extension-consumer-fixture'), + ).toBe(false); + expect(preVersionArtifacts.map(({ product, id }) => `${product}:${id}`).sort()).toEqual( + expectedProductArtifactRows(catalog.products, { artifactPhase: 'pre-version' }) + .map(({ product, id }) => `${product}:${id}`) + .sort(), ); - const artifacts = discoverProductArtifacts(selectedRoots, catalog.products); + const artifacts = discoverProductArtifacts(selectedRoots, catalog.products, { + swiftExtensionFixture: true, + }); + expect(artifacts.filter(({ kind }) => kind !== 'swiftpm-extension-consumer-fixture')).toEqual( + preVersionArtifacts, + ); const swiftArtifacts = artifacts.filter((artifact) => artifact.product === product.id); expect(swiftArtifacts.map(({ id }) => id).sort()).toEqual([ `github-release:${bindingsName}`, @@ -1563,9 +1844,9 @@ describe('publication artifact discovery and freezing', () => { ).not.toThrow(); const qualificationMarker = path.join(sdk, 'qualification.json'); writeFileSync(qualificationMarker, JSON.stringify({ qualificationOnly: true })); - expect(() => discoverProductArtifacts(selectedRoots, catalog.products)).toThrow( - 'workspace qualification carrier', - ); + expect(() => + discoverProductArtifacts(selectedRoots, catalog.products, { swiftExtensionFixture: true }), + ).toThrow('workspace qualification carrier'); unlinkSync(qualificationMarker); const frozenFixture = swiftArtifacts.find( ({ id }) => id === 'release-input:swiftpm-extension-consumer-fixture', @@ -1577,7 +1858,9 @@ describe('publication artifact discovery and freezing', () => { ), 'tampered\n', ); - const tamperedFixture = discoverProductArtifacts(selectedRoots, catalog.products).find( + const tamperedFixture = discoverProductArtifacts(selectedRoots, catalog.products, { + swiftExtensionFixture: true, + }).find( ({ id, product: artifactProduct }) => artifactProduct === product.id && id === 'release-input:swiftpm-extension-consumer-fixture', ); @@ -1586,9 +1869,9 @@ describe('publication artifact discovery and freezing', () => { const selectedSourceCarrier = structuredClone(canonicalSourceCarrier); selectedSourceCarrier.extensions.push({ sqlName: 'pgtap' }); writeFileSync(sourceCarrier, `${JSON.stringify(selectedSourceCarrier)}\n`); - expect(() => discoverProductArtifacts(selectedRoots, catalog.products)).toThrow( - /ios-carriers\.json\.extensions.*selection-neutral/u, - ); + expect(() => + discoverProductArtifacts(selectedRoots, catalog.products, { swiftExtensionFixture: true }), + ).toThrow(/ios-carriers\.json\.extensions.*selection-neutral/u); const malformedSourceCarrier = structuredClone(canonicalSourceCarrier); delete malformedSourceCarrier.carriers; @@ -1607,3 +1890,103 @@ describe('publication artifact discovery and freezing', () => { ); }); }); + +test('completed supplier projection preserves current and historical File facts without catalog authority', () => { + const directory = mkdtempSync(path.join(os.tmpdir(), 'complete-supplier-catalog-')); + try { + const root = path.resolve(import.meta.dir, '../..'); + const metadata = loadReleaseMetadata(root); + const catalog = loadPublicationCatalog('complete supplier catalog fixture'); + const expected = expectedProductArtifactRows(catalog.products).filter( + (row) => row.role === 'github-release-asset' || row.role === 'github-release-metadata', + ); + const declarations = nativeSupplierGithubArtifactDeclarations(metadata) + .map( + (row) => + row.product + + '/' + + row.asset.replaceAll('{version}', metadata.products[row.product].version), + ) + .sort(); + expect(declarations).toEqual(expected.map((row) => row.product + '/' + row.name).sort()); + const bytes = Buffer.from('catalog File fixture; no public or runtime qualification'); + const sha256 = createHash('sha256').update(bytes).digest('hex'); + const supplierArtifacts = expected.map((row) => { + const file = path.join(directory, row.name); + writeFileSync(file, bytes); + const version = metadata.products[row.product].version; + return { + publication: { + product: row.product, + version, + tagName: row.product + '-v' + version, + publicationSha: 'a'.repeat(40), + publicationTree: 'b'.repeat(40), + releaseSha: 'c'.repeat(40), + }, + artifact: row.id, + file: { path: file, size: bytes.length, sha256 }, + }; + }); + const snapshot = { + source: { commit: 'd'.repeat(40), tree: 'e'.repeat(40) }, + supplierArtifacts, + }; + const result = nativePublicationInputProjection(snapshot, metadata); + expect(Object.keys(result.supplierArtifacts)).toHaveLength(expected.length); + expect( + Object.values(result.supplierArtifacts).some( + (row) => row.publication.product === 'oliphaunt-swift', + ), + ).toBe(true); + expect( + Object.values(result.supplierArtifacts).some((row) => row.artifact.includes('extension-')), + ).toBe(true); + expect(() => + nativePublicationInputProjection( + { + ...snapshot, + supplierArtifacts: [ + { ...supplierArtifacts[0], artifact: 'github-release:invented-private.bin' }, + ], + }, + metadata, + ), + ).toThrow('filename differs'); + // Structural relocation preserves declared history; the completed reader + // independently authenticates its owner, source and inventory. + const historicalOwner = nativePublicationInputProjection( + { + ...snapshot, + supplierArtifacts: [ + { + ...supplierArtifacts[0], + publication: { + ...supplierArtifacts[0].publication, + product: 'oliphaunt-rust', + tagName: 'oliphaunt-rust-v' + supplierArtifacts[0].publication.version, + }, + }, + ], + }, + metadata, + ); + expect(Object.values(historicalOwner.supplierArtifacts)).toHaveLength(1); + expect(Object.values(historicalOwner.supplierArtifacts)[0].publication.product).toBe( + 'oliphaunt-rust', + ); + const subset = structuredClone(metadata); + subset.products['oliphaunt-swift'].publish_targets = ['swift-package-source-tag']; + const binding = supplierArtifacts.find( + (row) => row.publication.product === 'oliphaunt-swift' && row.artifact.endsWith('.zip'), + ); + const heldSwift = nativePublicationInputProjection( + { ...snapshot, supplierArtifacts: [binding] }, + subset, + ); + expect(Object.values(heldSwift.supplierArtifacts)).toHaveLength(1); + expect(Object.values(heldSwift.supplierArtifacts)[0].artifact).toBe(binding.artifact); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); diff --git a/tools/release/publication-lock.test.sh b/tools/release/publication-lock.test.sh index ab78ea741..a57fe5190 100644 --- a/tools/release/publication-lock.test.sh +++ b/tools/release/publication-lock.test.sh @@ -3,7 +3,7 @@ set -euo pipefail cd "$(dirname "$0")/../.." if [[ "${1:-}" != --context ]]; then exec bash tools/release/release-please-state.sh "$PWD" HEAD \ - bash tools/release/with-source.sh HEAD bash tools/ci/with-projects.sh --exec \ + bash tools/release/with-source.sh HEAD \ bash tools/release/publication-lock.test.sh --context fi scratch="$(mktemp -d)" diff --git a/tools/release/publish_swiftpm_source_tag.mts b/tools/release/publish_swiftpm_source_tag.mts index 971bbd335..4be84d94f 100644 --- a/tools/release/publish_swiftpm_source_tag.mts +++ b/tools/release/publish_swiftpm_source_tag.mts @@ -118,7 +118,8 @@ async function prepare(scratch, argv) { const files = []; if (args.manifest) { const manifest = path.resolve(args.manifest); - const text = readFileSync(manifest, 'utf8'); + const manifestBytes = readFileSync(manifest); + const text = manifestBytes.toString('utf8'); if (!resource && (!text.includes('binaryTarget(') || !text.includes('liboliphaunt-native-v'))) throw new Error( 'SwiftPM release manifest must contain a checksum-pinned liboliphaunt binaryTarget', @@ -135,7 +136,14 @@ async function prepare(scratch, argv) { const file = path.join(directory, entry.name); const relative = path.relative(root, file).split(path.sep).join('/'); if (resource && relative === 'Package.swift') continue; - if (relative === 'Package.swift' || relative.split('/').includes('.git')) + if (relative === 'Package.swift') { + if (!entry.isFile() || !readFileSync(file).equals(manifestBytes)) + throw new Error( + 'SwiftPM tree Package.swift differs from the frozen release manifest', + ); + continue; + } + if (relative.split('/').includes('.git')) throw new Error('forbidden SwiftPM generated path: ' + relative); if (entry.isDirectory()) visit(file); else if (entry.isFile()) files.push(file, relative); diff --git a/tools/release/publish_swiftpm_source_tag.test.sh b/tools/release/publish_swiftpm_source_tag.test.sh index 1178fca96..af2e3e8a3 100644 --- a/tools/release/publish_swiftpm_source_tag.test.sh +++ b/tools/release/publish_swiftpm_source_tag.test.sh @@ -1,9 +1,6 @@ #!/usr/bin/env bash set -euo pipefail cd "$(git rev-parse --show-toplevel)" -if [[ "${1:-}" != --with-projects ]]; then - exec bash tools/ci/with-projects.sh --exec bash "$0" --with-projects -fi source_root="$PWD" bash tools/dev/bun.sh test ./tools/release/publish_swiftpm_source_tag.test.mts scratch="$(mktemp -d)" @@ -65,6 +62,18 @@ version="$(jq -r .swift "$scratch/versions.json")" ref="refs/tags/$version" invoke() { bash "$publisher" --target HEAD --manifest Package.swift.release --include-tree frozen-tree "$@" > "$scratch/result" 2>&1; } invoke --preflight +# A complete native source tree carries the same root manifest as its separate frozen input. +cp Package.swift.release frozen-tree/Package.swift +invoke --preflight +printf 'conflicting root manifest' > frozen-tree/Package.swift +if invoke --preflight; then exit 1; fi +rg -q 'differs from the frozen release manifest' "$scratch/result" +rm frozen-tree/Package.swift +ln -s "$PWD/Package.swift.release" frozen-tree/Package.swift +if invoke --preflight; then exit 1; fi +rg -q 'differs from the frozen release manifest' "$scratch/result" +rm frozen-tree/Package.swift +cp Package.swift.release frozen-tree/Package.swift [[ -z "$(git tag --list "$version")" && -z "$(git ls-remote --refs --tags origin "$ref")" ]] GIT_AUTHOR_DATE='946684800 +0000' GIT_COMMITTER_DATE='946684800 +0000' GIT_AUTHOR_NAME=ambient invoke first="$(git rev-parse "$ref")" diff --git a/tools/release/qualified-native-current-exact-inputs.mts b/tools/release/qualified-native-current-exact-inputs.mts new file mode 100644 index 000000000..d88bba6ec --- /dev/null +++ b/tools/release/qualified-native-current-exact-inputs.mts @@ -0,0 +1,748 @@ +/** Physical proof of exact current WASIX resource and extension ABI inputs. */ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import { isDeepStrictEqual } from 'node:util'; +import { WASIX_PORTABLE_RELEASE_MEMBERS } from '../../src/wasix/runtime/tools/wasix-runtime-npm-contract.mts'; +import { wasixRuntimeNpmPayloadInputs } from '../../src/wasix/runtime/tools/wasix-runtime-npm-payload.mts'; +import { + readPortableArchiveEntries, + readPortableTarZstdBufferEntries, +} from '../packaging/portable-archive.mts'; +import { + assertAuthenticatedNativeBuildOrigin, + validateReviewedNativeProducerAssurance, +} from './authenticate-native-build-evidence.mts'; +import type { ReleaseMetadata } from './bazel-release-metadata.mts'; +import { + canonicalShippingLabel, + validateNativeShippingSuppliers, +} from './bazel-shipping-inputs.mts'; +import { fileIdentity } from './native-file-identity.mts'; +import type { prepareNativeReleaseDelivery } from './native-release-preparation.mts'; + +type Preparation = Pick< + Awaited>, + 'observation' | 'origins' | 'suppliers' | 'baselines' +>; +type Association = Readonly<{ product: string; sourceProduct: string }>; +type Inspection = { + metadata: ReleaseMetadata; + observation: Preparation['observation']; + suppliers: Preparation['suppliers']['suppliers']; + readOutput: (file: any) => Buffer; + inputIdentity: (supplier: any, file: any) => { size: number; sha256: string }; + readDeclaredRuntime?: (product: string, version: string) => Buffer; + readDeclaredCargo?: (supplier: any) => string; +}; + +/** Physical construction projection only. The controller below authenticates the producer inputs. */ +export function inspectNativeCurrentExactInputs(input: Inspection): readonly Association[] { + return Object.freeze([ + ...inspectCurrentResourceInputs(input), + ...inspectCurrentWasixExtensionInputs(input), + ]); +} + +function inspectCurrentResourceInputs({ + metadata, + observation, + suppliers, + readOutput, + inputIdentity, +}: Inspection): readonly Association[] { + const declaration = metadata.databaseResourceWasixConsumer; + assert.ok(declaration, 'WASIX admitted consumer declaration is missing'); + if (declaration.source === 'completed') return Object.freeze([]); + assert.equal(declaration.source, 'current'); + const producer = 'liboliphaunt-wasix'; + const consumer = 'database-resources'; + assert.equal( + declaration.version, + metadata.products[producer].version, + 'current WASIX admitted version differs from source', + ); + const product = observation.products.find(({ product }) => product.id === producer); + const resources = observation.products.find(({ product }) => product.id === consumer); + assert.ok(product && resources, 'current WASIX exact contract owners are missing'); + assert.equal(product.product.version, metadata.products[producer].version); + assert.equal(resources.product.version, metadata.products[consumer].version); + const archives = product.productArtifacts.filter( + (row) => + row.kind === 'wasix-runtime' && + row.target === 'portable' && + row.role === 'github-release-asset', + ); + assert.equal( + archives.length, + 1, + 'current WASIX contract needs one actual portable public archive', + ); + assert.equal(archives[0].qualifiedFiles.length, 1); + const coreFile = archives[0].qualifiedFiles[0]; + const coreBytes = readOutput(coreFile); + const core = readPortableTarZstdBufferEntries(coreBytes); + const manifest = core.get(WASIX_PORTABLE_RELEASE_MEMBERS.manifest); + const runtime = core.get(WASIX_PORTABLE_RELEASE_MEMBERS.runtimeArchive); + assert.ok(manifest?.isFile && runtime?.isFile, 'current WASIX portable archive is incomplete'); + const coreManifest = JSON.parse(manifest.data().toString('utf8')); + wasixRuntimeNpmPayloadInputs({ + manifestBytes: manifest.data(), + runtimeBytes: runtime.data(), + label: 'qualified current resource consumer', + }); + assert.ok(metadata.databaseResourceContract, 'WASIX resource contract is missing'); + const profiles = Object.keys(metadata.databaseResourceContract.profiles as object); + const declarations = metadata.databaseResourceArtifacts.filter( + (row) => + row.kind === 'wasix-seeds' && + row.target === 'portable' && + String(row.asset).endsWith('.json'), + ); + assert.equal( + declarations.length, + profiles.length, + 'WASIX exact contract profile inventory differs', + ); + for (const expected of declarations) { + const descriptors = resources.productArtifacts.filter( + (row) => + row.id === + `github-release:${String(expected.asset).replace('{version}', resources.product.version)}`, + ); + assert.equal( + descriptors.length, + 1, + 'WASIX exact contract lacks a qualified profile descriptor', + ); + assert.equal(descriptors[0].qualifiedFiles.length, 1); + const descriptorFile = descriptors[0].qualifiedFiles[0]; + const descriptor = JSON.parse(readOutput(descriptorFile).toString('utf8')); + assert.equal(descriptor.runtime.engineFamily, 'wasix'); + assert.equal( + descriptor.runtime.version, + declaration.version, + 'WASIX exact descriptor does not admit the current source version', + ); + assert.equal( + descriptor.runtime.consumerSha256, + coreManifest.runtime['module-sha256'], + 'WASIX descriptor admits another module', + ); + assert.equal(descriptor.runtime.target, 'portable'); + assert.ok(profiles.includes(descriptor.catalogProfile)); + assert.ok( + String(expected.asset).includes(`-${descriptor.catalogProfile}.json`), + 'WASIX profile descriptor is relabelled', + ); + const supplied = suppliers.filter( + (row) => + row.consumer === consumer && + row.product === producer && + canonicalShippingLabel(row.root) === canonicalShippingLabel(descriptorFile.label), + ); + assert.equal( + supplied.length, + 1, + 'WASIX exact descriptor lacks its own actual supplier binding', + ); + const supplier = supplied[0]; + assert.equal(supplier.binding, 'abi-contract'); + assert.equal( + supplier.origin.kind, + 'current-source', + 'WASIX exact adoption cannot relabel a held supplier', + ); + assert.equal(supplier.version, declaration.version); + assert.equal(supplier.configuration, 'portable'); + assert.equal( + supplier.files.length, + 1, + 'WASIX exact consumer needs the entire actual portable archive File', + ); + assert.equal(supplier.files[0].member, undefined); + assert.deepEqual( + inputIdentity(supplier, supplier.files[0]), + { size: coreFile.size, sha256: coreFile.sha256 }, + 'WASIX exact consumer File differs from the actual producer archive', + ); + } + return Object.freeze([Object.freeze({ product: consumer, sourceProduct: producer })]); +} + +function inspectCurrentWasixExtensionInputs({ + metadata, + observation, + suppliers, + readOutput, + inputIdentity, + readDeclaredRuntime, + readDeclaredCargo, +}: Inspection): readonly Association[] { + const producer = 'liboliphaunt-wasix'; + const roots = (observation.authenticated ?? []).flatMap(({ evidence }) => + evidence.cohorts.flatMap((cohort) => cohort.roots.map((root) => ({ cohort, root }))), + ); + const consumers = new Set( + roots + .filter(({ root }) => root.package.role === 'extension-release-link-input') + .map(({ root }) => root.package.product), + ); + const internal = roots.filter( + ({ root }) => + root.package.role === 'extension-release-link-input' || + (root.package.role === 'extension-release-frozen-input' && + root.package.configuration === 'wasix-portable' && + consumers.has(root.package.product)), + ); + const seen = new Set(); + for (const { root } of internal) { + const key = `${root.package.product}/${root.package.role}`; + assert.ok(!seen.has(key), 'WASIX exact extension has duplicate internal roots'); + seen.add(key); + } + const identity = (bytes: Buffer) => ({ + size: bytes.length, + sha256: createHash('sha256').update(bytes).digest('hex'), + }); + const digest = (value: unknown) => { + assert.ok( + typeof value === 'string' && /^[a-f0-9]{64}$/u.test(value), + 'WASIX exact digest is invalid', + ); + return value; + }; + const strings = (value: unknown, label: string) => { + assert.ok( + Array.isArray(value) && value.every((name) => typeof name === 'string' && name.length), + label, + ); + assert.deepEqual(value, [...new Set(value)].sort(), `${label} must be sorted and unique`); + return value as string[]; + }; + const document = ({ cohort, root }: (typeof roots)[number]) => { + assert.equal(root.package.outputs.length, 1, 'WASIX exact internal root needs one output'); + const output = root.package.outputs[0]; + const captures = cohort.outputs.filter((row) => row.path === output.path); + assert.equal(captures.length, 1, 'WASIX exact internal output is not captured'); + assert.equal(captures[0].members.length, 1, 'WASIX exact internal output is not one File'); + const member = captures[0].members[0]; + assert.equal(member.type, 'file'); + assert.equal(member.path, ''); + const file = { label: root.label, path: output.path, size: member.size, sha256: member.sha256 }; + const bytes = readOutput(file); + assert.deepEqual( + identity(bytes), + { size: file.size, sha256: file.sha256 }, + 'WASIX exact original document changed', + ); + return JSON.parse(bytes.toString('utf8')); + }; + const portable = (bytes: Buffer, label: string) => { + const entries = readPortableTarZstdBufferEntries(bytes); + const manifest = entries.get(WASIX_PORTABLE_RELEASE_MEMBERS.manifest); + const runtime = entries.get(WASIX_PORTABLE_RELEASE_MEMBERS.runtimeArchive); + assert.ok( + manifest?.isFile && !manifest.isSymbolicLink && runtime?.isFile && !runtime.isSymbolicLink, + `${label} portable archive is incomplete`, + ); + const inputs = wasixRuntimeNpmPayloadInputs({ + manifestBytes: manifest.data(), + runtimeBytes: runtime.data(), + label, + }); + return { inputs, manifest: JSON.parse(manifest.data().toString('utf8')) }; + }; + // Mirror the original analyzer: receipt selection alone never proves ABI adoption. + const resolve = (item: any, exports: any[]) => { + assert.ok( + typeof item.name === 'string' && item.name.length && typeof item.kind === 'string', + 'WASIX exact import is invalid', + ); + let candidates = exports.filter((row) => row.name === item.name); + if (!candidates.length) + candidates = exports.filter( + (row) => row.name.replace(/^_+/u, '') === item.name.replace(/^_+/u, ''), + ); + if (!candidates.length) return undefined; + const kind = + item.module === 'GOT.func' ? 'func' : item.module === 'GOT.mem' ? 'global' : item.kind; + const found = candidates.find((row) => row.kind === kind); + assert.ok(found, 'WASIX exact import has an incompatible export kind'); + return found.name as string; + }; + const associations: Association[] = []; + for (const entry of internal.filter( + ({ root }) => root.package.role === 'extension-release-link-input', + )) { + const pkg = entry.root.package; + const declared = metadata.extensionReleaseMetadata.filter( + (row) => row.class === 'external' && row.product === pkg.product, + ); + assert.equal(declared.length, 1, 'WASIX exact link names an unknown external product'); + const extension = declared[0]; + assert.equal(pkg.ecosystem, 'internal'); + assert.equal(pkg.configuration, 'wasix-portable'); + assert.equal( + pkg.version, + metadata.products[pkg.product]?.version, + 'WASIX exact extension version differs', + ); + const receipt = document(entry); + assert.equal(receipt.schema, 'oliphaunt-declared-wasix-extension-link-v1'); + assert.equal(receipt.sqlName, extension.sqlName, 'WASIX exact link names another SQL member'); + const selection = receipt.runtimeSelection; + if (selection === undefined) continue; + assert.ok( + ['completed-publication', 'current-source'].includes(selection.kind), + 'WASIX exact selection kind is invalid', + ); + if (selection.kind === 'completed-publication') continue; + const missing = strings(selection.missingExports, 'WASIX exact missing exports'); + assert.ok(missing.length, 'WASIX exact adoption needs a positive missing-export proof'); + assert.ok( + readDeclaredRuntime, + 'WASIX exact adoption needs its completed public runtime reader', + ); + const compatibility = extension.compatibility as Record; + assert.equal(compatibility.wasixRuntimeProduct, producer); + const version = compatibility.wasixRuntimeVersion; + assert.equal( + version, + metadata.products[producer].version, + 'WASIX exact adoption cannot replace an older runtime floor', + ); + const held = portable( + readDeclaredRuntime(producer, version), + 'completed WASIX extension runtime', + ); + const products = observation.products.filter(({ product }) => product.id === producer); + assert.equal(products.length, 1, 'WASIX exact runtime owner is missing or repeated'); + assert.equal(products[0].product.version, version); + const archives = products[0].productArtifacts.filter( + (row) => + row.kind === 'wasix-runtime' && + row.target === 'portable' && + row.role === 'github-release-asset', + ); + assert.equal( + archives.length, + 1, + 'WASIX exact extension needs one current public runtime archive', + ); + assert.equal(archives[0].qualifiedFiles.length, 1); + const coreFile = archives[0].qualifiedFiles[0]; + const original = roots.filter( + ({ root }) => + canonicalShippingLabel(root.label) === canonicalShippingLabel(coreFile.label) && + root.package.product === producer && + root.package.role === 'github-release-asset' && + root.package.outputs.some((output) => output.path === coreFile.path), + ); + assert.equal(original.length, 1, 'WASIX exact candidate lacks its original public root'); + assert.equal(original[0].root.package.version, version); + assert.equal(original[0].root.package.ecosystem, 'github'); + assert.equal(original[0].root.package.configuration, 'portable'); + assert.equal(original[0].root.package.outputs.length, 1); + assert.equal( + canonicalShippingLabel(original[0].root.package.outputs[0].owner), + '//src/wasix/runtime:release_archive_portable', + 'WASIX exact candidate is not the original portable producer File', + ); + const bytes = readOutput(coreFile); + assert.deepEqual( + identity(bytes), + { size: coreFile.size, sha256: coreFile.sha256 }, + 'WASIX exact current archive changed', + ); + const current = portable(bytes, 'current WASIX extension runtime'); + assert.equal( + digest(selection.declaredModuleSha256), + held.manifest.runtime['module-sha256'], + 'WASIX exact declared module differs from completed archive', + ); + assert.equal( + digest(selection.currentModuleSha256), + current.manifest.runtime['module-sha256'], + 'WASIX exact current module differs from original archive', + ); + assert.equal( + digest(selection.selectedModuleSha256), + selection.currentModuleSha256, + 'WASIX exact selected module is not current', + ); + assert.equal(receipt.sourceFingerprint, current.manifest['source-fingerprint']); + assert.equal(receipt.postgresVersion, current.manifest.runtime['postgres-version']); + const supplied = suppliers.filter( + (row) => + row.consumer === pkg.product && + row.product === producer && + canonicalShippingLabel(row.root) === canonicalShippingLabel(entry.root.label), + ); + const heldSuppliers = supplied.filter((row) => row.origin.kind === 'completed-publication'); + const currentSuppliers = supplied.filter((row) => row.origin.kind === 'current-source'); + assert.equal(heldSuppliers.length, 1, 'WASIX exact link needs one held runtime supplier'); + assert.equal(currentSuppliers.length, 1, 'WASIX exact link needs one current runtime supplier'); + const historical = heldSuppliers[0]; + assert.ok(historical.origin.kind === 'completed-publication'); + assert.equal(historical.binding, 'abi-contract'); + assert.equal(historical.version, version); + const cargoDeclarations = metadata.publicationCarriers.filter( + (row) => + row.product === producer && + row.ecosystem === 'cargo' && + row.name === 'liboliphaunt-wasix-portable', + ); + assert.equal( + cargoDeclarations.length, + 1, + 'WASIX exact held runtime has no canonical Cargo carrier', + ); + assert.equal(historical.configuration, cargoDeclarations[0].target ?? 'portable'); + assert.equal(historical.origin.publication.product, producer); + assert.equal(historical.origin.publication.version, version); + assert.equal(historical.origin.artifact, 'cargo:liboliphaunt-wasix-portable'); + assert.equal( + historical.files.length, + 1, + 'WASIX exact held runtime needs its original Cargo archive', + ); + assert.equal(historical.files[0].member, undefined); + assert.ok(readDeclaredCargo, 'WASIX exact adoption needs its completed Cargo reader'); + const cargoPath = readDeclaredCargo(historical); + const cargoIdentity = identity(readFileSync(cargoPath)); + assert.deepEqual( + inputIdentity(historical, historical.files[0]), + cargoIdentity, + 'WASIX exact held supplier differs from completed Cargo archive', + ); + const cargo = readPortableArchiveEntries(cargoPath, { format: 'tar.gz' }); + assert.deepEqual( + identity(readFileSync(cargoPath)), + cargoIdentity, + 'WASIX exact completed Cargo archive changed', + ); + const prefix = `liboliphaunt-wasix-portable-${version}`; + assert.ok( + [...cargo.keys()].every((name) => name === prefix || name.startsWith(`${prefix}/`)), + 'WASIX exact completed Cargo prefix differs', + ); + const cargoManifest = cargo.get(`${prefix}/Cargo.toml`); + assert.ok( + cargoManifest?.isFile && !cargoManifest.isSymbolicLink, + 'WASIX exact completed Cargo manifest is missing', + ); + const cargoPackage = Bun.TOML.parse(cargoManifest.data().toString('utf8')).package; + assert.equal(cargoPackage?.name, 'liboliphaunt-wasix-portable'); + assert.equal(cargoPackage?.version, version); + for (const [member, expected] of [ + ['payload/manifest.json', held.inputs.manifest], + ['payload/oliphaunt.wasix.tar.zst', held.inputs.runtimeArchive], + ] as const) { + const file = cargo.get(`${prefix}/${member}`); + assert.ok( + file?.isFile && !file.isSymbolicLink, + 'WASIX exact completed Cargo payload is missing', + ); + assert.deepEqual( + identity(file.data()), + { size: expected.size, sha256: expected.sha256 }, + 'WASIX exact held Cargo payload differs from completed public archive', + ); + } + const candidate = currentSuppliers[0]; + assert.equal(candidate.binding, 'abi-contract'); + assert.equal(candidate.version, version); + assert.equal(candidate.configuration, 'wasix-portable'); + assert.equal(candidate.files.length, 1); + assert.equal(candidate.files[0].member, undefined); + assert.equal( + candidate.files[0].path, + coreFile.path, + 'WASIX exact candidate is not the original public archive', + ); + assert.deepEqual( + inputIdentity(candidate, candidate.files[0]), + { size: coreFile.size, sha256: coreFile.sha256 }, + 'WASIX exact current supplier differs from original public archive', + ); + const frozenRoots = internal.filter( + ({ root }) => + root.package.product === pkg.product && + root.package.role === 'extension-release-frozen-input', + ); + assert.equal(frozenRoots.length, 1, 'WASIX exact link needs one original frozen member'); + const frozenRoot = frozenRoots[0]; + assert.equal( + frozenRoot.cohort, + entry.cohort, + 'WASIX exact frozen member comes from another producer', + ); + assert.equal(frozenRoot.root.package.version, pkg.version); + assert.equal(frozenRoot.root.package.configuration, pkg.configuration); + const frozen = document(frozenRoot); + assert.equal(frozenRoot.root.package.ecosystem, 'internal'); + assert.equal( + canonicalShippingLabel(frozenRoot.root.package.outputs[0].owner), + canonicalShippingLabel(pkg.outputs[0].owner), + 'WASIX exact link and frozen member have different constructors', + ); + assert.equal(frozen.product, pkg.product); + assert.equal(frozen.version, pkg.version); + assert.equal(frozen.sqlName, receipt.sqlName); + assert.equal(frozen.compatibility.wasixRuntimeVersion, version); + assert.deepEqual( + frozen.wasixInstall.nativeModules, + receipt.nativeModules, + 'WASIX exact compiled modules differ from frozen member', + ); + assert.deepEqual( + frozen.wasixInstall.coreExportsRequired, + receipt.coreExportsRequired, + 'WASIX exact core requirements differ from frozen member', + ); + assert.deepEqual(receipt.unresolvedImports, []); + assert.deepEqual(frozen.wasixInstall.unresolvedImports, []); + assert.ok( + Array.isArray(receipt.nativeModules) && receipt.nativeModules.length, + 'WASIX exact adoption needs compiled modules', + ); + const names = receipt.nativeModules.map((module) => module.name); + assert.deepEqual( + names, + [...new Set(names)].sort(), + 'WASIX exact compiled modules repeat or are unsorted', + ); + assert.ok(names.includes(receipt.sqlName)); + assert.deepEqual(Object.keys(receipt.moduleLinkMetadata).sort(), names); + const byBasename = new Map(); + for (const module of receipt.nativeModules) { + assert.equal(digest(module.sha256), digest(module.moduleSha256)); + assert.ok(Number.isSafeInteger(module.size) && module.size > 0); + assert.ok( + typeof module.path === 'string' && + module.path.startsWith('lib/postgresql/') && + !module.path.split('/').some((part) => !part || part === '.' || part === '..'), + ); + const basename = path.posix.basename(module.path); + assert.ok(!byBasename.has(basename), 'WASIX exact compiled module basenames repeat'); + byBasename.set(basename, module.name); + } + const unresolved: string[] = []; + const required = new Set(); + for (const module of receipt.nativeModules) { + const providers: any[] = []; + const pending = [module.name]; + const visited = new Set(); + while (pending.length) { + const name = pending.pop()!; + if (visited.has(name)) continue; + visited.add(name); + const link = receipt.moduleLinkMetadata[name]; + assert.ok(link && Array.isArray(link.imports) && Array.isArray(link.exports)); + providers.push(...link.exports); + assert.ok(Array.isArray(link['dylink-needed'])); + for (const needed of link['dylink-needed']) { + const dependency = byBasename.get(needed); + assert.ok(dependency, 'WASIX exact side-module dependency is missing'); + pending.push(dependency); + } + } + for (const item of receipt.moduleLinkMetadata[module.name].imports) { + if (!['env', 'GOT.func', 'GOT.mem'].includes(item.module)) continue; + if ( + (item.module === 'env' && + [ + '__c_longjmp', + '__cpp_exception', + '__indirect_function_table', + '__memory_base', + '__stack_pointer', + '__table_base', + 'memory', + ].includes(item.name)) || + (item.module === 'GOT.mem' && + ['__heap_base', '__stack_high', '__stack_low'].includes(item.name)) + ) + continue; + if (resolve(item, providers)) continue; + if (!resolve(item, held.manifest.runtime.link.exports)) unresolved.push(item.name); + const resolved = resolve(item, current.manifest.runtime.link.exports); + assert.ok(resolved, 'WASIX exact selected runtime still lacks a required export'); + required.add(resolved); + } + } + assert.deepEqual( + missing, + [...new Set(unresolved)].sort(), + 'WASIX exact missing-export proof differs from actual imports', + ); + assert.deepEqual( + strings(receipt.coreExportsRequired, 'WASIX exact core exports'), + [...required].sort(), + 'WASIX exact selected core requirements differ from actual imports', + ); + associations.push(Object.freeze({ product: pkg.product, sourceProduct: producer })); + } + return Object.freeze(associations); +} + +/** Only the actual retained reviewed producer capabilities can feed the RP controller. */ +export function deriveQualifiedNativeCurrentExactInputs( + preparation: Preparation, + metadata: ReleaseMetadata, +): readonly Association[] { + assert.ok( + preparation.suppliers.buildBound && !preparation.suppliers.unknowns.length, + 'current exact contracts require complete physical supplier coverage', + ); + const observed = preparation.observation.authenticated; + assert.ok(observed.length, 'current exact contracts need producing evidence'); + const source = observed[0].evidence.source; + for (const origin of preparation.origins.values()) { + assertAuthenticatedNativeBuildOrigin(origin); + const matches = observed.filter((build) => build.origin === origin); + assert.equal( + matches.length, + 1, + 'current exact contracts need the same acquired observed producer', + ); + const build = matches[0]; + assert.deepEqual(build.evidence.source, source, 'current exact producer source differs'); + assert.deepEqual( + build.qualification.source, + source, + 'current exact qualification source differs', + ); + assert.deepEqual(build.evidence, origin.evidence, 'current exact producer evidence changed'); + assert.ok( + build.producerAssurance && origin.finalFiles, + 'current exact contract needs original reviewed qualification and retained Files', + ); + validateReviewedNativeProducerAssurance(build.producerAssurance, { + source: build.evidence.source, + github: origin.github, + artifact: origin.artifact, + evidenceDigest: origin.evidenceDigest, + requiredTests: build.qualification.requiredTests, + }); + assert.equal(build.qualification.qualificationPolicy, 'bound'); + } + assert.equal( + observed.length, + preparation.origins.size, + 'current exact contract imported an unacquired producer', + ); + const locate = (file: any) => { + const roots = [...preparation.origins].flatMap(([directory, origin]) => + origin.evidence.cohorts.flatMap((cohort, index) => + cohort.roots + .filter( + (root) => + canonicalShippingLabel(root.label) === canonicalShippingLabel(file.label) && + root.package.outputs.some( + ({ path }) => file.path === path || file.path.startsWith(`${path}/`), + ), + ) + .map(() => ({ directory, origin, cohort, index })), + ), + ); + assert.equal(roots.length, 1, 'current exact File needs one original configured root'); + const { directory, origin, index } = roots[0]; + assert.ok(origin.finalFiles, 'current exact File has no retained transport'); + const captured = origin.finalFiles.files.filter( + (row) => row.cohort === index && row.path === file.path, + ); + assert.equal(captured.length, 1, 'current exact File is absent from retained transport'); + const expected = { size: file.size, sha256: file.sha256 }; + assert.deepEqual({ size: captured[0].size, sha256: captured[0].sha256 }, expected); + const absolute = path.join(directory, 'files', String(index), file.path); + const actual = fileIdentity(absolute); + assert.deepEqual( + { size: actual.size, sha256: actual.sha256 }, + expected, + 'current exact original output changed', + ); + return absolute; + }; + const associations = inspectNativeCurrentExactInputs({ + metadata, + observation: preparation.observation, + suppliers: preparation.suppliers.suppliers, + readOutput: (file) => readFileSync(locate(file)), + inputIdentity: (supplier, file) => { + const cohorts = observed + .flatMap(({ evidence }) => evidence.cohorts) + .filter((cohort) => + cohort.rootConfigurations.some( + ({ label, configuration }) => + canonicalShippingLabel(label) === supplier.root && + configuration === supplier.rootConfiguration, + ), + ); + assert.equal(cohorts.length, 1, 'current exact supplier has ambiguous configured provenance'); + const roots = cohorts[0].roots.filter( + (root) => canonicalShippingLabel(root.label) === supplier.root, + ); + assert.equal(roots.length, 1, 'current exact supplier needs its original ShippingInfo root'); + const { product, version, configuration, binding, origin, files } = supplier; + const declaration = { product, version, configuration, binding, origin, files }; + const supplied = validateNativeShippingSuppliers(roots[0].package.supplierInputs); + assert.equal( + supplied.filter((row) => isDeepStrictEqual(row, declaration)).length, + 1, + 'current exact supplier differs from original captured ShippingInfo', + ); + const captures = cohorts[0].inputs.filter((input) => input.path === file.path); + assert.equal(captures.length, 1, 'current exact supplier File is not captured'); + assert.equal(captures[0].members.length, 1); + const member = captures[0].members[0]; + assert.equal(member.path, ''); + assert.equal(member.type, 'file'); + return { size: member.size, sha256: member.sha256 }; + }, + readDeclaredRuntime: (product, version) => { + const baselines = preparation.baselines.filter( + (row) => row.publication.product === product && row.publication.version === version, + ); + assert.equal( + baselines.length, + 1, + 'WASIX exact declared runtime needs one completed baseline', + ); + const rows = metadata.wasixArtifacts.filter( + (row) => + row.product === product && row.kind === 'wasix-runtime' && row.target === 'portable', + ); + assert.equal(rows.length, 1, 'WASIX exact declared runtime needs one portable public row'); + const artifact = `github-release:${String(rows[0].asset).replace('{version}', version)}`; + const file = baselines[0].productArtifacts?.[artifact]; + assert.ok(file, 'WASIX exact declared runtime public archive is missing'); + return readFileSync(file); + }, + readDeclaredCargo: (supplier) => { + assert.ok(supplier.origin.kind === 'completed-publication'); + const baselines = preparation.baselines.filter( + (row) => + row.publication.product === supplier.product && + row.publication.version === supplier.version, + ); + assert.equal(baselines.length, 1, 'WASIX exact held Cargo needs one completed baseline'); + assert.deepEqual( + baselines[0].publication, + supplier.origin.publication, + 'WASIX exact held Cargo publication differs', + ); + const files = baselines[0].carriers[supplier.origin.artifact]; + assert.equal( + files?.length, + 1, + 'WASIX exact held Cargo original archive is missing or repeated', + ); + return files[0]; + }, + }); + for (const origin of preparation.origins.values()) origin.finalFiles?.assertUnchanged?.(); + return associations; +} diff --git a/tools/release/qualified-native-current-exact-inputs.test.mts b/tools/release/qualified-native-current-exact-inputs.test.mts new file mode 100644 index 000000000..7e41a2573 --- /dev/null +++ b/tools/release/qualified-native-current-exact-inputs.test.mts @@ -0,0 +1,630 @@ +import { afterEach, expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { gunzipSync } from 'node:zlib'; +import { WASIX_PORTABLE_RELEASE_MEMBERS } from '../../src/wasix/runtime/tools/wasix-runtime-npm-contract.mts'; +import { releaseZstdCompressSync } from '../packaging/portable-archive.mts'; +import { tarArchive } from '../packaging/testdata/tar-fixture.mts'; +import { loadReleaseMetadata } from './bazel-release-metadata.mts'; +import { + deriveQualifiedNativeCurrentExactInputs, + inspectNativeCurrentExactInputs, +} from './qualified-native-current-exact-inputs.mts'; + +const sha = (bytes: Buffer) => createHash('sha256').update(bytes).digest('hex'); +const extensionFixtureDirectories: string[] = []; +afterEach(() => { + for (const directory of extensionFixtureDirectories.splice(0)) + rmSync(directory, { recursive: true, force: true }); +}); +/** Controlled archives have real manifest/module digests, never authenticated producer status. */ +function fixture() { + const metadata = loadReleaseMetadata(path.resolve(import.meta.dir, '../..')); + const version = metadata.products['liboliphaunt-wasix'].version; + metadata.databaseResourceWasixConsumer = { source: 'current', version }; + const module = Buffer.from('controlled WASIX consuming module'); + const runtime = releaseZstdCompressSync( + gunzipSync(tarArchive([{ name: 'oliphaunt/bin/postgres', data: module }])), + ); + const manifest = { + 'format-version': 2, + 'source-fingerprint': 'controlled current source', + runtime: { + archive: 'oliphaunt.wasix.tar.zst', + sha256: sha(runtime), + size: runtime.length, + 'module-sha256': sha(module), + 'postgres-version': '18.4', + link: { exports: [] }, + }, + 'runtime-support': [], + extensions: [], + }; + const bytes = releaseZstdCompressSync( + gunzipSync( + tarArchive([ + { name: WASIX_PORTABLE_RELEASE_MEMBERS.runtimeArchive, data: runtime }, + { name: WASIX_PORTABLE_RELEASE_MEMBERS.manifest, data: JSON.stringify(manifest) }, + ]), + ), + ); + const core = { + path: 'bazel-out/core/public.tar.zst', + label: '//core:public', + size: bytes.length, + sha256: sha(bytes), + }; + const files = new Map([[core.path, bytes]]); + const descriptors = metadata.databaseResourceArtifacts + .filter((row) => row.kind === 'wasix-seeds' && String(row.asset).endsWith('.json')) + .map((row) => { + const profile = String(row.asset).includes('-standard.') ? 'standard' : 'icu'; + const descriptor = { + catalogProfile: profile, + runtime: { + engineFamily: 'wasix', + target: 'portable', + version, + consumerSha256: sha(module), + producerSha256: 'b'.repeat(64), + }, + }; + const data = Buffer.from(JSON.stringify(descriptor)); + const qualified = { + path: `bazel-out/resources/${profile}.json`, + label: `//resources:${profile}`, + size: data.length, + sha256: sha(data), + }; + files.set(qualified.path, data); + return { + id: `github-release:${String(row.asset).replace('{version}', metadata.products['database-resources'].version)}`, + qualifiedFiles: [qualified], + kind: 'wasix-seeds', + target: 'portable', + }; + }); + const observation = { + products: [ + { + product: metadata.products['liboliphaunt-wasix'], + productArtifacts: [ + { + kind: 'wasix-runtime', + target: 'portable', + role: 'github-release-asset', + qualifiedFiles: [core], + }, + ], + }, + { product: metadata.products['database-resources'], productArtifacts: descriptors }, + ], + } as any; + const suppliers = descriptors.map((row) => ({ + consumer: 'database-resources', + product: 'liboliphaunt-wasix', + version, + configuration: 'portable', + root: row.qualifiedFiles[0].label, + binding: 'abi-contract', + origin: { kind: 'current-source' }, + files: [{ path: 'bazel-out/core/raw.tar.zst' }], + })) as any; + return { + metadata, + observation, + suppliers, + files, + readOutput: (file: any) => files.get(file.path)!, + inputIdentity: () => ({ size: core.size, sha256: core.sha256 }), + }; +} + +test('both exact current profile descriptors bind the actual archive module and retain original creator identity', () => { + const value = fixture(); + expect(inspectNativeCurrentExactInputs(value)).toEqual([ + { product: 'database-resources', sourceProduct: 'liboliphaunt-wasix' }, + ]); + const descriptor = JSON.parse(value.files.get('bazel-out/resources/standard.json')!.toString()); + expect(descriptor.runtime.producerSha256).not.toBe(descriptor.runtime.consumerSha256); + value.metadata.databaseResourceWasixConsumer = { + ...value.metadata.databaseResourceWasixConsumer!, + source: 'completed', + }; + expect(inspectNativeCurrentExactInputs(value)).toEqual([]); +}); +for (const fault of ['one-profile', 'wrong-module', 'held-origin', 'wrong-input', 'wrong-version']) + test(`current exact consumer fails closed: ${fault}`, () => { + const value = fixture(); + if (fault === 'one-profile') value.observation.products[1].productArtifacts.pop(); + if (fault === 'wrong-module') { + const descriptor = JSON.parse(value.files.get('bazel-out/resources/icu.json')!.toString()); + descriptor.runtime.consumerSha256 = 'f'.repeat(64); + value.files.set('bazel-out/resources/icu.json', Buffer.from(JSON.stringify(descriptor))); + } + if (fault === 'held-origin') value.suppliers[1].origin.kind = 'completed-publication'; + if (fault === 'wrong-input') + value.inputIdentity = () => ({ size: 123, sha256: 'f'.repeat(64) }); + if (fault === 'wrong-version') + value.metadata.databaseResourceWasixConsumer = { + ...value.metadata.databaseResourceWasixConsumer!, + version: '1.2.3', + }; + expect(() => inspectNativeCurrentExactInputs(value)).toThrow(); + }); +test('physical construction data and copied JSON origins cannot mint a controller association', () => { + const value = fixture(); + const origin = { + evidence: { source: { commit: 'a'.repeat(40), tree: 'b'.repeat(40) }, cohorts: [] }, + evidenceDigest: `sha256:${'a'.repeat(64)}`, + }; + const preparation = { + origins: new Map([['/tmp/fake', origin]]), + observation: { ...value.observation, authenticated: [{ origin, evidence: origin.evidence }] }, + suppliers: { suppliers: value.suppliers, buildBound: new Map(), unknowns: [] }, + } as any; + expect(() => deriveQualifiedNativeCurrentExactInputs(preparation, value.metadata)).toThrow( + 'authenticated producer transport', + ); +}); + +function extensionFixture() { + const metadata = loadReleaseMetadata(path.resolve(import.meta.dir, '../..')); + const producer = 'liboliphaunt-wasix'; + const sqlName = 'pg_textsearch'; + const canonical = metadata.extensionReleaseMetadata.find( + (row) => row.class === 'external' && row.sqlName === sqlName, + ) as any; + const consumer = canonical.product; + const version = metadata.products[producer].version; + canonical.compatibility.wasixRuntimeVersion = version; + metadata.databaseResourceWasixConsumer = { source: 'completed', version }; + const identity = (bytes: Buffer) => ({ size: bytes.length, sha256: sha(bytes) }); + const archive = (entries: { name: string; data: Buffer | string }[]) => + releaseZstdCompressSync(gunzipSync(tarArchive(entries))); + const runtime = (name: string, exports: string[]) => { + const module = Buffer.from(`controlled ${name} WASIX module`); + const bytes = archive([{ name: 'oliphaunt/bin/postgres', data: module }]); + return { + module, + bytes, + manifest: { + 'format-version': 2, + 'source-fingerprint': `controlled ${name} source`, + runtime: { + archive: 'oliphaunt.wasix.tar.zst', + ...identity(bytes), + 'module-sha256': sha(module), + 'postgres-version': '18.4', + link: { exports: exports.map((name) => ({ name, kind: 'func' })) }, + }, + 'runtime-support': [], + extensions: [], + }, + }; + }; + const held = runtime('held', ['legacy_']); + const current = runtime('current', ['backend', 'callback', 'legacy_']); + const publicArchive = (value: typeof held) => + archive([ + { name: WASIX_PORTABLE_RELEASE_MEMBERS.runtimeArchive, data: value.bytes }, + { name: WASIX_PORTABLE_RELEASE_MEMBERS.manifest, data: JSON.stringify(value.manifest) }, + ]); + const coreBytes = publicArchive(current); + const coreFile = { + path: 'bazel-out/core/current-public.tar.zst', + label: '//src/wasix/runtime:release_archive_portable', + ...identity(coreBytes), + }; + const module = Buffer.from('controlled compiled pg_textsearch side module'); + const nativeModules = [ + { + name: sqlName, + path: `lib/postgresql/${sqlName}.so`, + ...identity(module), + moduleSha256: sha(module), + }, + ]; + const receipt = { + schema: 'oliphaunt-declared-wasix-extension-link-v1', + sqlName, + nativeModules, + coreExportsRequired: ['backend', 'callback', 'legacy_'], + unresolvedImports: [] as string[], + moduleLinkMetadata: { + [sqlName]: { + 'dylink-needed': [], + imports: [ + { module: 'env', name: 'backend', kind: 'func' }, + { module: 'GOT.func', name: 'backend', kind: 'global' }, + { module: 'env', name: 'callback', kind: 'func' }, + { module: 'env', name: 'legacy_', kind: 'func' }, + ], + exports: [{ name: sqlName, kind: 'func' }], + }, + }, + sourceFingerprint: current.manifest['source-fingerprint'], + postgresVersion: current.manifest.runtime['postgres-version'], + runtimeSelection: { + kind: 'current-source', + declaredModuleSha256: sha(held.module), + currentModuleSha256: sha(current.module), + selectedModuleSha256: sha(current.module), + missingExports: ['backend', 'callback'], + }, + }; + const frozen = { + product: consumer, + version: metadata.products[consumer].version, + sqlName, + compatibility: { wasixRuntimeVersion: version }, + wasixInstall: { + nativeModules: structuredClone(nativeModules), + coreExportsRequired: [...receipt.coreExportsRequired], + unresolvedImports: [], + }, + }; + const root = (label: string, role: string, file: string) => ({ + label, + package: { + product: consumer, + version: metadata.products[consumer].version, + ecosystem: 'internal', + configuration: 'wasix-portable', + name: `${sqlName}-${role}`, + role, + outputs: [{ path: file, owner: '//extensions:pg_textsearch_carriers' }], + }, + }); + const linkRoot = root( + '//extensions:pg_textsearch_link_shipping', + 'extension-release-link-input', + 'bazel-out/extensions/pg_textsearch.link.json', + ); + const frozenRoot = root( + '//extensions:pg_textsearch_frozen_shipping', + 'extension-release-frozen-input', + 'bazel-out/extensions/pg_textsearch.frozen.json', + ); + const coreRoot = { + label: coreFile.label, + package: { + product: producer, + version, + ecosystem: 'github', + configuration: 'portable', + name: 'controlled-current-wasix.tar.zst', + role: 'github-release-asset', + outputs: [{ path: coreFile.path, owner: coreFile.label }], + }, + }; + const cohort = { roots: [coreRoot, linkRoot, frozenRoot], outputs: [] as any[] }; + const files = new Map([[coreFile.path, coreBytes]]); + const directory = mkdtempSync(path.join(tmpdir(), 'oliphaunt-exact-wasix-abi-')); + extensionFixtureDirectories.push(directory); + const declaredCargoPath = path.join(directory, 'original.crate'); + const cargo = { + name: 'liboliphaunt-wasix-portable', + version, + manifest: null as Buffer | null, + runtime: null as Buffer | null, + }; + const put = (root: typeof linkRoot, bytes: Buffer) => { + const file = root.package.outputs[0].path; + files.set(file, bytes); + cohort.outputs = cohort.outputs.filter((row) => row.path !== file); + cohort.outputs.push({ + path: file, + members: [{ path: '', type: 'file', mode: 0o644, ...identity(bytes) }], + }); + }; + const sync = () => { + put(coreRoot, files.get(coreFile.path)!); + put(linkRoot, Buffer.from(JSON.stringify(receipt))); + put(frozenRoot, Buffer.from(JSON.stringify(frozen))); + const prefix = `liboliphaunt-wasix-portable-${version}`; + writeFileSync( + declaredCargoPath, + tarArchive([ + { + name: `${prefix}/Cargo.toml`, + data: `[package]\nname = ${JSON.stringify(cargo.name)}\nversion = ${JSON.stringify(cargo.version)}\n`, + }, + { + name: `${prefix}/payload/manifest.json`, + data: cargo.manifest ?? Buffer.from(JSON.stringify(held.manifest)), + }, + { + name: `${prefix}/payload/oliphaunt.wasix.tar.zst`, + data: cargo.runtime ?? held.bytes, + }, + ]), + ); + }; + sync(); + const observation = { + products: [ + { + product: metadata.products[producer], + productArtifacts: [ + { + kind: 'wasix-runtime', + target: 'portable', + role: 'github-release-asset', + qualifiedFiles: [coreFile], + }, + ], + }, + { product: metadata.products[consumer], productArtifacts: [] }, + ], + // This is controlled physical evidence, without an authenticated origin capability. + authenticated: [{ evidence: { cohorts: [cohort] } }], + } as any; + const heldSupplier = { + consumer, + product: producer, + version, + configuration: 'portable', + root: linkRoot.label, + binding: 'abi-contract', + origin: { + kind: 'completed-publication', + publication: { + product: producer, + version, + tagName: `${producer}-v${version}`, + publicationSha: 'a'.repeat(40), + publicationTree: 'b'.repeat(40), + releaseSha: 'c'.repeat(40), + }, + artifact: 'cargo:liboliphaunt-wasix-portable', + }, + files: [{ path: 'external/held/original.crate' }], + }; + const currentSupplier = { + consumer, + product: producer, + version, + configuration: 'wasix-portable', + root: linkRoot.label, + binding: 'abi-contract', + origin: { kind: 'current-source' }, + files: [{ path: coreFile.path }], + }; + return { + metadata, + observation, + suppliers: [heldSupplier, currentSupplier] as any, + readOutput: (file: any) => files.get(file.path)!, + readDeclaredRuntime: (product: string, requestedVersion: string) => { + expect([product, requestedVersion]).toEqual([producer, version]); + return publicArchive(held); + }, + readDeclaredCargo: (_supplier: any) => declaredCargoPath, + inputIdentity: (_supplier: any, file: any) => { + const bytes = + file.path === heldSupplier.files[0].path + ? readFileSync(declaredCargoPath) + : files.get(file.path)!; + return identity(bytes); + }, + consumer, + producer, + held, + current, + cargo, + receipt, + frozen, + coreFile, + files, + cohort, + linkRoot, + frozenRoot, + heldSupplier, + currentSupplier, + sync, + refreshCurrent: () => { + const bytes = publicArchive(current); + Object.assign(coreFile, identity(bytes)); + files.set(coreFile.path, bytes); + sync(); + }, + }; +} + +test('a compiled external WASIX ABI receipt binds both physical runtimes before current adoption', () => { + const value = extensionFixture(); + expect(inspectNativeCurrentExactInputs(value)).toEqual([ + { product: value.consumer, sourceProduct: value.producer }, + ]); + expect(value.receipt.runtimeSelection.missingExports).toEqual(['backend', 'callback']); + expect(value.receipt.runtimeSelection.declaredModuleSha256).not.toBe( + value.receipt.runtimeSelection.currentModuleSha256, + ); +}); + +test('native frozen roots for the same extension do not interfere with WASIX adoption', () => { + const value = extensionFixture(); + for (const configuration of ['linux-x64', 'macos-aarch64']) { + const root = structuredClone(value.frozenRoot); + root.label = `//extensions:pg_textsearch_${configuration}_frozen_shipping`; + root.package.configuration = configuration; + const file = `bazel-out/extensions/pg_textsearch-${configuration}.frozen.json`; + root.package.outputs = [ + { path: file, owner: `//extensions:pg_textsearch_${configuration}_carriers` }, + ]; + const bytes = Buffer.from(JSON.stringify({ ...value.frozen, wasixInstall: null })); + value.files.set(file, bytes); + value.cohort.roots.push(root); + value.cohort.outputs.push({ + path: file, + members: [{ path: '', type: 'file', mode: 0o644, size: bytes.length, sha256: sha(bytes) }], + }); + } + expect(inspectNativeCurrentExactInputs(value)).toEqual([ + { product: value.consumer, sourceProduct: value.producer }, + ]); +}); + +test('a held-preferred compiled WASIX ABI receipt creates no current association', () => { + const value = extensionFixture(); + value.held.manifest.runtime.link.exports.push( + { name: 'backend', kind: 'func' }, + { name: 'callback', kind: 'func' }, + ); + value.receipt.runtimeSelection.kind = 'completed-publication'; + value.receipt.runtimeSelection.selectedModuleSha256 = sha(value.held.module); + value.receipt.runtimeSelection.missingExports = []; + value.sync(); + expect(inspectNativeCurrentExactInputs(value)).toEqual([]); +}); + +test('current WASIX ABI adoption requires the physical declared-runtime reader', () => { + const value = extensionFixture(); + expect(() => + inspectNativeCurrentExactInputs({ ...value, readDeclaredRuntime: undefined }), + ).toThrow(); +}); + +test('current WASIX ABI adoption requires the original whole Cargo reader', () => { + const value = extensionFixture(); + expect(() => + inspectNativeCurrentExactInputs({ ...value, readDeclaredCargo: undefined }), + ).toThrow(); +}); + +const invalidExtensionAdoptions: [string, (value: ReturnType) => void][] = + [ + [ + 'invalid current archive', + (value) => value.files.set(value.coreFile.path, Buffer.from('invalid')), + ], + [ + 'held manifest module mismatch', + (value) => (value.held.manifest.runtime['module-sha256'] = 'f'.repeat(64)), + ], + [ + 'captured whole Cargo input mismatch', + (value) => { + const original = value.inputIdentity; + value.inputIdentity = (supplier, file) => + file.path === value.heldSupplier.files[0].path + ? { size: 1, sha256: 'f'.repeat(64) } + : original(supplier, file); + }, + ], + ['wrong Cargo package name', (value) => (value.cargo.name = 'invented-runtime')], + ['wrong Cargo package version', (value) => (value.cargo.version = '999.0.0')], + [ + 'Cargo manifest differs from completed public archive', + (value) => { + const manifest = structuredClone(value.held.manifest); + manifest['source-fingerprint'] = 'another controlled source'; + value.cargo.manifest = Buffer.from(JSON.stringify(manifest)); + }, + ], + [ + 'Cargo runtime differs from completed public archive', + (value) => (value.cargo.runtime = Buffer.from('another controlled runtime archive')), + ], + ['missing current supplier', (value) => value.suppliers.pop()], + [ + 'current supplier is held', + (value) => (value.currentSupplier.origin.kind = 'completed-publication'), + ], + [ + 'wrong current supplier configuration', + (value) => (value.currentSupplier.configuration = 'portable'), + ], + [ + 'held Cargo binding names an extracted member', + (value) => { + Reflect.set(value.heldSupplier.files[0], 'member', 'payload/manifest.json'); + }, + ], + [ + 'wrong supplier input path', + (value) => (value.currentSupplier.files[0].path = 'bazel-out/unqualified'), + ], + [ + 'wrong selected module', + (value) => (value.receipt.runtimeSelection.selectedModuleSha256 = 'f'.repeat(64)), + ], + [ + 'wrong declared module', + (value) => (value.receipt.runtimeSelection.declaredModuleSha256 = 'f'.repeat(64)), + ], + [ + 'wrong current module', + (value) => (value.receipt.runtimeSelection.currentModuleSha256 = 'f'.repeat(64)), + ], + [ + 'current runtime drops a held-supported export', + (value) => { + value.current.manifest.runtime.link.exports = + value.current.manifest.runtime.link.exports.filter((row) => row.name !== 'legacy_'); + value.refreshCurrent(); + }, + ], + [ + 'runtime import has the wrong kind', + (value) => (value.receipt.moduleLinkMetadata.pg_textsearch.imports[0].kind = 'global'), + ], + [ + 'current runtime export has the wrong kind', + (value) => { + value.current.manifest.runtime.link.exports[0].kind = 'global'; + value.refreshCurrent(); + }, + ], + ['empty missing-export proof', (value) => (value.receipt.runtimeSelection.missingExports = [])], + [ + 'duplicate missing-export proof', + (value) => (value.receipt.runtimeSelection.missingExports = ['backend', 'backend']), + ], + [ + 'unsorted missing-export proof', + (value) => (value.receipt.runtimeSelection.missingExports = ['callback', 'backend']), + ], + [ + 'invented missing-export proof', + (value) => (value.receipt.runtimeSelection.missingExports = ['invented']), + ], + [ + 'export already supplied by held runtime', + (value) => (value.receipt.runtimeSelection.missingExports = ['legacy_']), + ], + [ + 'frozen module differs', + (value) => (value.frozen.wasixInstall.nativeModules[0].moduleSha256 = 'f'.repeat(64)), + ], + [ + 'frozen module metadata is incomplete', + (value) => { + Reflect.deleteProperty(value.frozen.wasixInstall.nativeModules[0], 'size'); + }, + ], + [ + 'frozen export requirements differ', + (value) => (value.frozen.wasixInstall.coreExportsRequired = ['backend']), + ], + ['unresolved imports', (value) => value.receipt.unresolvedImports.push('env.invented')], + ['unknown SQL identity', (value) => (value.receipt.sqlName = 'unknown_extension')], + ['wrong canonical product', (value) => (value.linkRoot.package.product = 'database-resources')], + ['wrong extension version', (value) => (value.linkRoot.package.version = '999.0.0')], + ['wrong held floor', (value) => (value.heldSupplier.version = '999.0.0')], + ['duplicate link root', (value) => value.cohort.roots.push(structuredClone(value.linkRoot))], + [ + 'duplicate frozen root', + (value) => value.cohort.roots.push(structuredClone(value.frozenRoot)), + ], + ]; +for (const [fault, mutate] of invalidExtensionAdoptions) + test(`compiled external WASIX current adoption fails closed: ${fault}`, () => { + const value = extensionFixture(); + mutate(value); + value.sync(); + expect(() => inspectNativeCurrentExactInputs(value)).toThrow(); + }); diff --git a/tools/release/qualified-native-extension-final-inputs.mts b/tools/release/qualified-native-extension-final-inputs.mts new file mode 100644 index 000000000..300028089 --- /dev/null +++ b/tools/release/qualified-native-extension-final-inputs.mts @@ -0,0 +1,549 @@ +/** Preserve original authenticated constructor Files for the existing owner join. */ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import path from 'node:path'; +import { + assertAuthenticatedNativeBuildOrigin, + validateReviewedNativeProducerAssurance, +} from './authenticate-native-build-evidence.mts'; +import { + nativeSupplierGithubArtifactDeclarations, + type ReleaseMetadata, +} from './bazel-release-metadata.mts'; +import { canonicalShippingLabel } from './bazel-shipping-inputs.mts'; +import { + type ExtensionFinalInput, + type ExtensionFinalInputFile, + type NativeAppleBaseInput, + type NativeCurrentArtifact, + type NativeSwiftSourceInput, + projectNativeAppleBaseInput, + projectNativeCurrentArtifacts, + projectNativeExtensionFinalInputs, + projectNativeSwiftSourceInput, +} from './native-extension-final-inputs.mts'; +import { fileIdentity } from './native-file-identity.mts'; +import type { prepareNativeReleaseDelivery } from './native-release-preparation.mts'; +import { resolveActualCarrier } from './publication-catalog.mts'; +import { discoverPublicationArtifacts, validateCargoPayloadPartSets } from './publication-lock.mts'; + +type NativeFinalInputPreparation = { + observation: Pick< + Awaited>['observation'], + 'authenticated' + >; + origins: Awaited>['origins']; +}; + +/** Reviewed-main qualification remains required by release decisions. */ +export function qualifiedNativeFinalInputs( + preparation: NativeFinalInputPreparation, + metadata: ReleaseMetadata, +) { + for (const origin of preparation.origins.values()) { + const build = preparation.observation.authenticated.find((row) => row.origin === origin); + assert.ok( + build?.producerAssurance, + 'extension imports need the original authenticated reviewed producer', + ); + validateReviewedNativeProducerAssurance(build.producerAssurance, { + source: build.evidence.source, + github: origin.github, + artifact: origin.artifact, + evidenceDigest: origin.evidenceDigest, + requiredTests: build.qualification.requiredTests, + }); + } + return collectNativeFinalInputs(preparation, metadata, false); +} + +/** Same-source construction imports retain actual configured provenance. + * PR producers supply construction facts and never reviewed-main assurance. */ +export function constructionNativeFinalInputs( + preparation: NativeFinalInputPreparation, + metadata: ReleaseMetadata, +) { + return collectNativeFinalInputs(preparation, metadata, true); +} + +/** Physical classification only; collection still requires the authenticated original producer. */ +export function isNativeCurrentCargoRoot( + root: { + package: { + product: string; + ecosystem: string; + configuration: string; + name: string; + outputs: readonly { owner: string }[]; + }; + }, + metadata: ReleaseMetadata, + extensionConstructors: ReadonlySet, +) { + const pkg = root.package; + return ( + pkg.ecosystem === 'cargo' && + pkg.configuration !== 'source' && + metadata.publicationCarriers.some( + (row) => row.product === pkg.product && row.ecosystem === 'cargo' && row.name === pkg.name, + ) && + // NAPI embeds the original core/contrib crates while the extension tuple + // retains its own final installed-consumer inputs from the same constructor. + (pkg.product === 'liboliphaunt-wasix' || + !pkg.outputs.some((output) => + extensionConstructors.has(canonicalShippingLabel(output.owner)), + )) + ); +} + +/** Match an observed asset to its source owner's complete public declarations. */ +export function isNativeCurrentGithubRoot( + { + package: pkg, + }: { + package: { product: string; version: string; ecosystem: string; role: string; name: string }; + }, + declared: ReadonlySet, +) { + return ( + pkg.ecosystem === 'github' && + pkg.role === 'github-release-asset' && + declared.has(`${pkg.product}/${pkg.version}/${pkg.name}`) + ); +} + +function collectNativeFinalInputs( + preparation: NativeFinalInputPreparation, + metadata: ReleaseMetadata, + currentArtifacts: boolean, +) { + const inputs: ExtensionFinalInput[] = []; + const current = new Map(); + const githubArtifacts = new Set( + nativeSupplierGithubArtifactDeclarations(metadata).map(({ product, asset }) => { + const version = metadata.products[product].version; + return `${product}/${version}/${asset.replaceAll('{version}', version)}`; + }), + ); + const catalog = { + carriers: metadata.publicationCarriers.map((row) => ({ + ...row, + id: `${row.ecosystem}:${row.name}`, + declared: true, + })), + }; + const apple: Partial = {}; + const swift: Partial = {}; + for (const [evidenceRoot, origin] of preparation.origins) { + const build = preparation.observation.authenticated.find( + (value) => + value.origin.evidenceDigest === origin.evidenceDigest && + value.origin.artifact.id === origin.artifact.id, + ); + assertAuthenticatedNativeBuildOrigin(origin); + assert.ok( + build && build.origin === origin && origin.finalFiles, + 'extension imports need the actual acquired original producer', + ); + assert.deepEqual( + build.evidence, + origin.evidence, + 'extension import evidence differs from acquired producer', + ); + assert.deepEqual( + build.qualification.source, + build.evidence.source, + 'extension import source differs', + ); + assert.deepEqual( + build.qualification.github, + origin.github, + 'extension import GitHub context differs', + ); + assert.equal(build.qualification.testQualification, 'passed'); + assert.equal(build.qualification.shippingAnalysis, 'bound'); + assert.equal(build.qualification.qualificationPolicy, 'bound'); + assert.ok( + build.qualification.requiredTests.length, + 'extension imports require actual configured mandatory tests', + ); + const finalFiles = origin.finalFiles; + for (const [cohortIndex, cohort] of build.evidence.cohorts.entries()) { + const records = ( + root: (typeof cohort.roots)[number], + producerLabel?: string, + ): ExtensionFinalInputFile[] => { + const configuration = cohort.rootConfigurations.filter( + (value) => value.label === root.label, + ); + assert.equal( + configuration.length, + 1, + 'extension File needs its original configured shipping root', + ); + return root.package.outputs.flatMap((declared) => { + if (producerLabel) + assert.equal( + canonicalShippingLabel(declared.owner), + producerLabel, + 'extension root mixes different constructors', + ); + const outputs = cohort.outputs.filter((output) => output.path === declared.path); + assert.equal( + outputs.length, + 1, + 'extension declared output is absent from original capture', + ); + return outputs[0].members + .filter((member) => member.type === 'file') + .map((member) => { + const relative = member.path ? `${declared.path}/${member.path}` : declared.path; + const captured = finalFiles.files.filter( + (file) => file.cohort === cohortIndex && file.path === relative, + ); + assert.equal( + captured.length, + 1, + 'extension File is absent from retained authenticated transport', + ); + assert.deepEqual( + { size: captured[0].size, sha256: captured[0].sha256 }, + { size: member.size, sha256: member.sha256 }, + ); + const source = path.join(evidenceRoot, 'files', String(cohortIndex), relative); + assert.ok( + finalFiles.artifactRoots?.filter( + (file) => path.resolve(file) === path.resolve(source), + ).length === 1, + 'extension source File is not the actual retained original transport', + ); + const identity = fileIdentity(source); + assert.deepEqual( + { size: identity.size, sha256: identity.sha256 }, + { size: captured[0].size, sha256: captured[0].sha256 }, + 'extension original File changed', + ); + return { + path: source, + size: identity.size, + sha256: identity.sha256, + producer: { + evidenceDigest: origin.evidenceDigest, + invocationId: build.qualification.cohorts[cohortIndex].invocationId, + root: canonicalShippingLabel(root.label), + configuration: configuration[0].configuration, + output: declared.path, + }, + ...(member.path ? { member: member.path } : {}), + }; + }); + }); + }; + const frozenRoots = cohort.roots.filter( + (root) => root.package.role === 'extension-release-frozen-input', + ); + const extensionConstructors = new Set( + frozenRoots.flatMap((root) => + root.package.outputs.map((output) => canonicalShippingLabel(output.owner)), + ), + ); + if (currentArtifacts) { + for (const root of cohort.roots) { + const pkg = root.package; + const cargo = isNativeCurrentCargoRoot(root, metadata, extensionConstructors); + const github = isNativeCurrentGithubRoot(root, githubArtifacts); + if (!(cargo || github)) continue; + assert.equal( + pkg.version, + metadata.products[pkg.product]?.version, + 'current carrier version differs from source owner', + ); + const files = records(root); + const retain = (artifact: string, file: ExtensionFinalInputFile) => { + const key = `${pkg.product}/${pkg.version}/${artifact}`; + const row: NativeCurrentArtifact = { + product: pkg.product, + version: pkg.version, + artifact, + configuration: pkg.configuration, + source: { ...build.evidence.source }, + file, + }; + const prior = current.get(key); + if (prior) + assert.deepEqual(prior, row, 'current carrier has conflicting original producers'); + else current.set(key, row); + }; + if (pkg.ecosystem === 'github') { + const selected = files.filter((file) => path.basename(file.path) === pkg.name); + assert.equal( + selected.length, + 1, + 'current GitHub carrier needs its exact original regular File', + ); + retain(`github-release:${pkg.name}`, selected[0]); + continue; + } + const crates = files.filter((file) => file.path.endsWith('.crate')); + assert.ok(crates.length, 'current Cargo carrier lacks its original package Files'); + const index = files.filter((file) => path.basename(file.path) === 'packages.json'); + let indexed: Record[] | undefined; + if (files.some((file) => file.member !== undefined)) { + assert.equal( + index.length, + 1, + 'current Cargo Tree needs its original package inventory', + ); + const document = JSON.parse(readFileSync(index[0].path, 'utf8')); + assert.equal(document.schema, 'oliphaunt-liboliphaunt-cargo-artifacts-v1'); + assert.ok(Array.isArray(document.packages)); + indexed = document.packages; + assert.deepEqual( + indexed.map((row) => path.basename(row.cratePath)).sort(), + crates.map((file) => path.basename(file.path)).sort(), + 'current Cargo Tree differs from its original package inventory', + ); + } + const published = []; + for (const file of crates) { + const discovered = discoverPublicationArtifacts([file.path]); + assert.equal( + discovered.length, + 1, + 'current Cargo File needs exactly one package identity', + ); + const record = discovered[0]; + assert.equal(record.ecosystem, 'cargo'); + assert.equal(record.version, pkg.version, 'current Cargo package version differs'); + const carrier = resolveActualCarrier(catalog, 'cargo', record.name); + assert.equal(carrier.product, pkg.product, 'current Cargo package owner differs'); + if (indexed) { + const rows = indexed.filter( + (row) => path.basename(row.cratePath) === path.basename(file.path), + ); + assert.equal(rows.length, 1); + assert.equal(rows[0].name, record.name, 'current Cargo inventory name differs'); + assert.equal( + rows[0].role, + carrier.role === 'payload-part' ? 'part' : 'aggregator', + 'current Cargo inventory role differs', + ); + } + published.push({ ...carrier, packageDependencies: record.dependencies }); + retain(carrier.id, file); + } + assert.deepEqual( + published.filter((row) => row.declared).map((row) => row.name), + [pkg.name], + 'current Cargo Tree differs from its declared parent identity', + ); + validateCargoPayloadPartSets(published); + } + } + const nativeVersion = metadata.products['liboliphaunt-native'].version; + const appleNames = { + 'ios.json': [ + 'file', + 'internal', + 'apple-base-ios-manifest-input', + 'ios-xcframework', + '//src/native/runtime:apple_ios_manifest_shipping', + ], + [`liboliphaunt-${nativeVersion}-apple-spm-xcframework.zip`]: [ + 'framework', + 'github', + 'github-release-asset', + 'apple-spm-xcframework', + '//src/native/runtime:apple_swiftpm_shipping', + ], + [`liboliphaunt-${nativeVersion}-runtime-resources-ios-datum64.tar.gz`]: [ + 'resources', + 'github', + 'github-release-asset', + 'ios-datum64', + '//src/native/runtime:apple_resources_shipping', + ], + } as const; + const swiftNames = { + 'Oliphaunt-source.zip': 'archive', + 'oliphaunt-react-native-ios-carriers.json': 'carrier', + 'extension-owner-catalog.json': 'ownerCatalog', + [`oliphaunt-swift-${metadata.products['oliphaunt-swift'].version}-bindings.xcframework.zip`]: + 'bindingsArchive', + } as const; + for (const root of cohort.roots) { + if ( + root.package.product !== 'oliphaunt-swift' || + !Object.hasOwn(swiftNames, root.package.name) + ) + continue; + assert.equal(root.package.ecosystem, 'github'); + const group = swiftNames[root.package.name]; + assert.equal( + root.package.role, + group === 'bindingsArchive' ? 'github-release-asset' : 'release-input', + ); + assert.equal( + root.package.configuration, + group === 'bindingsArchive' ? 'apple-xcframework' : 'portable', + ); + assert.equal( + root.package.version, + metadata.products['oliphaunt-swift'].version, + 'original Swift source version differs from constructor source', + ); + assert.equal(swift[group], undefined, 'original Swift source File repeats'); + const files = records(root).filter( + (file) => path.basename(file.path) === root.package.name, + ); + assert.equal(files.length, 1, 'original Swift source/control needs its exact File'); + swift[group] = files[0]; + swift.owner = 'oliphaunt-swift'; + swift.version = root.package.version; + } + for (const root of cohort.roots) { + if ( + root.package.product !== 'liboliphaunt-native' || + !Object.hasOwn(appleNames, root.package.name) + ) + continue; + const [group, ecosystem, role, configuration, label] = appleNames[root.package.name]; + assert.equal(apple[group], undefined, 'original Apple constructor File repeats'); + assert.equal(root.package.ecosystem, ecosystem); + assert.equal(root.package.role, role); + assert.equal(root.package.version, nativeVersion); + assert.equal(root.package.configuration, configuration); + assert.equal(canonicalShippingLabel(root.label), label); + const files = records(root); + assert.equal(files.length, 1, 'original Apple base manifest requires its one regular File'); + assert.equal(files[0].member, undefined); + apple[group] = files[0]; + apple.owner = 'liboliphaunt-native'; + apple.version = root.package.version; + } + for (const frozenRoot of frozenRoots) { + assert.equal( + frozenRoot.package.outputs.length, + 1, + 'extension constructor needs one frozen document', + ); + const producerLabel = canonicalShippingLabel(frozenRoot.package.outputs[0].owner); + const frozen = records(frozenRoot, producerLabel); + assert.equal(frozen.length, 1); + const document = JSON.parse(readFileSync(frozen[0].path, 'utf8')); + const members = document.extensions ?? [document]; + const families = new Set( + members.flatMap((member) => member.assets.map((asset) => asset.family)), + ); + assert.equal(families.size, 1, 'selected constructor cannot invent another owner family'); + const family = [...families][0] as 'native' | 'wasix'; + assert.ok(['native', 'wasix'].includes(family)); + const canonical = metadata.extensionReleaseMetadata.filter( + (row) => row.artifactProduct === document.product, + ); + assert.ok( + canonical.length > 0, + 'extension frozen document names an undeclared distribution', + ); + const compatibility = canonical[0].compatibility as Record; + const owner = + canonical[0].class === 'contrib' + ? compatibility[family === 'native' ? 'nativeRuntimeProduct' : 'wasixRuntimeProduct'] + : (canonical[0].product as string); + assert.equal( + frozenRoot.package.product, + owner, + 'extension frozen document belongs to another conventional owner', + ); + assert.equal(document.version, frozenRoot.package.version); + assert.equal(metadata.products[owner]?.version, document.version); + assert.deepEqual( + members.map((member) => member.sqlName).sort(), + canonical.map((row) => row.sqlName).sort(), + 'extension constructor omits or substitutes canonical members', + ); + const siblings = cohort.roots.filter( + (root) => + root.package.product === owner && + root.package.version === document.version && + root.package.outputs.some( + (output) => canonicalShippingLabel(output.owner) === producerLabel, + ), + ); + const group = (name: string) => { + const files = siblings + .filter((root) => root.package.ecosystem === name) + .flatMap((root) => { + const output = records(root, producerLabel); + if (name !== 'github') return output; + // A mobile Tree may back several declared GitHub identities. Each + // leaf keeps the root that actually declares its own public name. + const selected = output.filter( + (file) => path.basename(file.path) === root.package.name, + ); + assert.equal( + selected.length, + 1, + 'GitHub identity needs its actual original regular archive File', + ); + return selected; + }); + const unique = new Map(); + for (const file of files) { + const prior = unique.get(file.path); + if (prior) + assert.deepEqual( + { size: prior.size, sha256: prior.sha256 }, + { size: file.size, sha256: file.sha256 }, + ); + else unique.set(file.path, file); + } + return [...unique.values()]; + }; + const manifests = siblings + .filter((root) => root.package.role === 'extension-release-manifest-input') + .flatMap((root) => records(root, producerLabel)); + assert.equal( + manifests.length, + 1, + 'extension constructor needs its original selected-target public manifest', + ); + inputs.push({ + product: document.product, + owner, + version: document.version, + family, + target: frozenRoot.package.configuration, + github: group('github'), + npm: group('npm'), + cargo: group('cargo'), + manifest: manifests[0], + frozen: frozen[0], + }); + } + } + finalFiles.assertUnchanged?.(); + } + projectNativeExtensionFinalInputs(inputs); + if (current.size) + projectNativeCurrentArtifacts([...current.values()], [...current.values()][0].source); + const nativeAppleBase = Object.keys(apple).length ? (apple as NativeAppleBaseInput) : undefined; + if (nativeAppleBase) projectNativeAppleBaseInput(nativeAppleBase); + const nativeSwiftSource = Object.keys(swift).length + ? (swift as NativeSwiftSourceInput) + : undefined; + if (nativeSwiftSource) projectNativeSwiftSourceInput(nativeSwiftSource); + return { + extensionFinalInputs: inputs, + ...(currentArtifacts ? { nativeCurrentArtifacts: [...current.values()] } : {}), + ...(nativeAppleBase ? { nativeAppleBase } : {}), + ...(nativeSwiftSource ? { nativeSwiftSource } : {}), + }; +} + +export function qualifiedNativeExtensionFinalInputs( + preparation: Parameters[0], + metadata: ReleaseMetadata, +) { + return qualifiedNativeFinalInputs(preparation, metadata).extensionFinalInputs; +} diff --git a/tools/release/qualify-native-shipping.mts b/tools/release/qualify-native-shipping.mts new file mode 100644 index 000000000..0d3148010 --- /dev/null +++ b/tools/release/qualify-native-shipping.mts @@ -0,0 +1,886 @@ +#!/usr/bin/env bun +import assert from 'node:assert/strict'; +/** Build shipping roots once and retain configured construction evidence. */ +import { type ChildProcess, execFileSync, spawn, type SpawnOptions } from 'node:child_process'; +import { + closeSync, + openSync, + readFileSync, + readSync, + rmSync, + statSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { parseArgs } from 'node:util'; +import { + captureConfiguredCiRequest, + writeConfiguredCiSuccessReceipt, +} from '../ci/configured-scope.mts'; +import { completedCiRequestRoots } from '../ci/run-configured-request.mts'; +import { requireSafeDirectoryChain } from '../packaging/release-directory-safety.mts'; +import { + canonicalShippingLabel, + validateNativeShippingSuppliers, +} from './bazel-shipping-inputs.mts'; +import { + NATIVE_AQUERY_FLAGS, + type NativeBuildEvidence, + type NativeBuildGithub, + type NativeRequiredTest, + nativeAqueryExpression, + nativeBuildEventIndex, + nativeBuildMetadata, +} from './native-build-qualification.mts'; +import { + nativeConfiguredRecipeGraph, + nativeConfiguredWorkspaceLabel, + nativeRecipeInputPaths, +} from './native-configured-inputs.mts'; +import { readNativePublicationArtifacts } from './native-publication-artifacts.mts'; +import { + captureNativeOutputMembers, + captureNativePublicationOutputs, +} from './native-publication-staging.mts'; +import { loadPublicationCatalog, resolveActualCarrier } from './publication-catalog.mts'; +import { + assertWasixPublicationPackages, + discoverProductArtifacts, + discoverPublicationArtifacts, + expectedProductArtifactRows, + validateCargoPayloadPartSets, +} from './publication-lock.mts'; + +export type NativeShippingRequest = { + ci?: { id: string; job: string; mode: 'full' | 'source'; requires: string[]; handoff?: boolean }; + github: NativeBuildGithub; + startup?: string[]; + configuration: string[]; + shipping: { export: string } | { roots: string[] }; + targets?: string[]; + completeProducts?: string[]; + outputDirectory: string; +}; + +function argv(value: unknown, context: string): string[] { + if ( + !Array.isArray(value) || + value.some((item) => typeof item !== 'string' || !item || /[\u0000-\u001f\u007f]/u.test(item)) + ) + throw new Error(`${context} must be an array of nonempty argv strings`); + return value; +} + +const label = nativeConfiguredWorkspaceLabel; +function json(file: string): unknown { + return JSON.parse(readFileSync(file, 'utf8')); +} + +export { + nativeConfiguredRecipeGraph, + nativeRecipeInputPaths, +} from './native-configured-inputs.mts'; + +/** Policy edges name actual tests; cquery cannot expand test_suite or tests(). */ +function configuredQualificationTests(raw: unknown): NativeRequiredTest[] { + const query = raw as { + configurations?: { id: number; checksum: string }[]; + results?: { + target?: { rule?: { name: string; ruleClass: string } }; + configurationId: number; + }[]; + }; + if (!query || typeof query !== 'object' || Array.isArray(query)) + throw new Error('shipping qualification requires configured policy query results'); + const configurations = new Map(); + for (const row of query.configurations ?? []) { + if ( + !Number.isSafeInteger(row.id) || + row.id <= 0 || + configurations.has(row.id) || + !/^[a-f0-9]{64}$/u.test(row.checksum) + ) + throw new Error('shipping qualification requires unique configured policy checksums'); + configurations.set(row.id, row.checksum); + } + const tests = (query.results ?? []).map((result) => { + const rule = result.target?.rule; + const configuration = configurations.get(result.configurationId); + if (!rule?.ruleClass.endsWith('_test') || !configuration) + throw new Error('shipping qualification policy must declare configured actual test rules'); + return { label: label(rule.name), configuration }; + }); + if (new Set(tests.map((test) => test.label)).size !== tests.length) + throw new Error('shipping qualification policy requires one configuration per test rule'); + return tests.sort((left, right) => left.label.localeCompare(right.label)); +} + +/** A complete family must survive the conventional readers before and after freezing its outputs. */ +function checkCompleteProducts(evidence: NativeBuildEvidence, products: string[]) { + const catalog = loadPublicationCatalog('native shipping qualification'); + const selected = new Set(products); + const authority = { + catalog, + artifactRows: expectedProductArtifactRows(catalog.products), + resolveCarrier: (ecosystem: string, name: string) => + resolveActualCarrier(catalog, ecosystem, name, 'native shipping qualification'), + }; + const cohorts = evidence.cohorts + .map((cohort) => ({ + ...cohort, + roots: cohort.roots.filter(({ package: pkg }) => selected.has(pkg.product)), + })) + .filter((cohort) => cohort.roots.length); + const outputs = captureNativePublicationOutputs(cohorts, { + sourceCommit: evidence.source.commit, + }); + for (const cohort of cohorts) { + const declared = new Set( + cohort.roots + .filter(({ package: pkg }) => pkg.ecosystem !== 'internal') + .flatMap(({ package: pkg }) => pkg.outputs.map(({ path: file }) => file)), + ); + for (const file of declared) { + const expected = cohort.outputs.find(({ path: output }) => output === file); + if (!expected) + throw new Error('native complete-family output is missing from build evidence'); + assert.deepStrictEqual( + captureNativeOutputMembers(cohort.executionRoot, file).members, + expected.members, + 'native complete-family output differs from build evidence', + ); + } + } + const physical = readNativePublicationArtifacts(authority, cohorts, { products }); + const staged = outputs.stage(); + const registry = discoverPublicationArtifacts(staged); + assertWasixPublicationPackages(registry); + validateCargoPayloadPartSets( + registry.map((record) => ({ + ...authority.resolveCarrier(record.ecosystem, record.name), + packageDependencies: record.dependencies, + })), + ); + const publicFiles = discoverProductArtifacts( + staged, + catalog.products.filter(({ id }) => selected.has(id)), + ); + const registryBytes = (records: typeof registry) => + records + .map((record) => ({ + ecosystem: record.ecosystem, + name: record.name, + version: record.version, + dependencies: record.dependencies, + qualificationOnly: record.qualificationOnly, + artifacts: record.artifacts.map(({ size, sha256 }) => ({ size, sha256 })), + })) + .sort((left, right) => + `${left.ecosystem}:${left.name}`.localeCompare(`${right.ecosystem}:${right.name}`), + ); + const publicBytes = (records: typeof publicFiles) => + records + .map(({ path: _path, ...record }) => record) + .sort((left, right) => + `${left.product}:${left.id}`.localeCompare(`${right.product}:${right.id}`), + ); + assert.deepStrictEqual(registryBytes(registry), registryBytes(physical.registryArtifacts)); + assert.deepStrictEqual(publicBytes(publicFiles), publicBytes(physical.productArtifacts)); +} + +/** The caller keeps this checkout and its producer inputs frozen through capture. */ +export async function qualifyNativeShipping( + request: NativeShippingRequest, + directory = process.cwd(), +) { + let interrupted: NodeJS.Signals | undefined; + let activeBazel: ChildProcess | undefined; + let activeCapture: ChildProcess | undefined; + const assertRunning = () => { + if (interrupted) throw new Error(`shipping qualification interrupted (${interrupted})`); + }; + const interrupt = (signal: NodeJS.Signals) => { + if (interrupted) return; + interrupted = signal; + activeBazel?.kill('SIGINT'); + if (activeCapture?.pid !== undefined) { + if (process.platform === 'win32') activeCapture.kill('SIGTERM'); + else { + try { + process.kill(-activeCapture.pid, 'SIGTERM'); + } catch (error) { + if ((error as NodeJS.ErrnoException).code !== 'ESRCH') throw error; + } + } + } + }; + const onInterrupt = () => interrupt('SIGINT'); + const onTerminate = () => interrupt('SIGTERM'); + process.on('SIGINT', onInterrupt); + process.on('SIGTERM', onTerminate); + try { + return await qualifyOwnedNativeShipping(request, directory, { + assertRunning, + get interrupted() { + return interrupted !== undefined; + }, + spawnBazel(command, args, options) { + assertRunning(); + const child = spawn(command, args, options); + activeBazel = child; + child.once('close', () => { + if (activeBazel === child) activeBazel = undefined; + }); + return child; + }, + spawnCapture(command, args, options) { + assertRunning(); + const child = spawn(command, args, { + ...options, + ...(process.platform === 'win32' ? {} : { detached: true }), + }); + activeCapture = child; + child.once('close', () => { + if (activeCapture === child) activeCapture = undefined; + }); + return child; + }, + }); + } finally { + process.removeListener('SIGINT', onInterrupt); + process.removeListener('SIGTERM', onTerminate); + } +} + +async function qualifyOwnedNativeShipping( + request: NativeShippingRequest, + directory: string, + commands: { + assertRunning(): void; + readonly interrupted: boolean; + spawnBazel(command: string, args: string[], options: SpawnOptions): ChildProcess; + spawnCapture(command: string, args: string[], options: SpawnOptions): ChildProcess; + }, +) { + const git = (...args: string[]) => + execFileSync('git', args, { cwd: directory, encoding: 'utf8', maxBuffer: 1024 * 1024 }).trim(); + const workspace = git('rev-parse', '--show-toplevel'); + const source = { + commit: git('rev-parse', 'HEAD^{commit}'), + tree: git('rev-parse', 'HEAD^{tree}'), + }; + const assertSource = () => { + try { + execFileSync( + 'bash', + ['tools/release/qualified-release-replay.sh', source.commit, source.commit], + { + cwd: workspace, + stdio: ['ignore', 'ignore', 'pipe'], + }, + ); + } catch (cause) { + throw new Error( + 'shipping qualification requires a clean checkout without index suppression flags', + { cause }, + ); + } + if ( + git('rev-parse', 'HEAD^{commit}') !== source.commit || + git('rev-parse', 'HEAD^{tree}') !== source.tree + ) + throw new Error('shipping qualification source changed during construction'); + }; + assertSource(); + const startup = argv(request.startup ?? [], 'startup'); + if (startup.includes('--')) throw new Error('startup cannot contain an argv separator'); + const configuration = argv(request.configuration, 'configuration'); + if ( + configuration.some( + (item) => + item === '--' || + /^--(?:build_metadata|build_event_json_file|output|output_file|output_groups|profile|query_file|starlark:file|starlark:expr|experimental_aquery_dump_after_build_format|experimental_aquery_dump_after_build_output_file)(?:=|$)/u.test( + item, + ), + ) + ) + throw new Error('configuration cannot override qualification metadata or query output'); + const targets = argv(request.targets ?? [], 'additional targets').map(label); + const completeProducts = argv(request.completeProducts ?? [], 'complete products'); + if (new Set(completeProducts).size !== completeProducts.length) + throw new Error('complete products must be unique'); + const metadata = Object.entries(nativeBuildMetadata(source, request.github)).map( + ([key, value]) => `--build_metadata=${key}=${value}`, + ); + const output = requireSafeDirectoryChain(path.resolve(workspace, request.outputDirectory), { + create: true, + label: 'shipping qualification', + }); + const file = (name: string) => path.join(output, name); + const diagnostics = requireSafeDirectoryChain(file('diagnostics'), { + create: true, + label: 'shipping qualification diagnostics', + }); + const diagnosticFile = (name: string) => path.join(diagnostics, name); + writeFileSync(file('github.json'), `${JSON.stringify(request.github)}\n`, { flag: 'wx' }); + writeFileSync(file('configuration.json'), `${JSON.stringify(configuration)}\n`, { flag: 'wx' }); + writeFileSync(file('startup.json'), `${JSON.stringify(startup)}\n`, { flag: 'wx' }); + const phase = (name: string) => { + const started = Date.now(); + console.error(`native qualification: ${name} started`); + return () => + console.error(`native qualification: ${name} finished in ${Date.now() - started} ms`); + }; + const run = async ( + name: string, + command: string, + args: string[], + stdout?: string, + spawnCommand: typeof commands.spawnBazel = spawn, + ) => { + commands.assertRunning(); + const finish = phase(name); + const fd = stdout === undefined ? undefined : openSync(stdout, 'wx'); + try { + await new Promise((resolve, reject) => { + const child = spawnCommand(command, args, { + cwd: workspace, + stdio: ['ignore', fd ?? 'inherit', 'inherit'], + }); + let error: Error | undefined; + child.once('error', (cause) => { + error = cause; + }); + child.once('close', (code, signal) => { + try { + commands.assertRunning(); + if (error) throw error; + if (code !== 0) + throw new Error( + `shipping qualification ${command} ${args[0] ?? ''} failed (${signal ?? code})`, + ); + resolve(); + } catch (cause) { + reject(cause); + } + }); + }); + } finally { + if (fd !== undefined) closeSync(fd); + finish(); + } + }; + const bazel = (args: string[], stdout?: string) => + run(args[0], 'bash', ['tools/dev/bazel.sh', ...startup, ...args], stdout, commands.spawnBazel); + const captureQueryDiagnostics = async () => { + try { + const base = startup.find((arg) => arg.startsWith('--output_base='))?.slice(14); + if (!base || process.platform === 'win32') return; + const server = path.join(path.resolve(workspace, base), 'server'); + const pid = readFileSync(path.join(server, 'server.pid.txt'), 'utf8').trim(); + if (!/^[1-9][0-9]*$/u.test(pid)) throw new Error('invalid Bazel server PID'); + const command = execFileSync('ps', ['-p', pid, '-o', 'comm='], { + encoding: 'utf8', + timeout: 2000, + killSignal: 'SIGKILL', + }).trim(); + if (!/^(?:(?:.*\/)?java|bazel(?:\(.*\))?)$/u.test(command)) + throw new Error('Bazel server PID does not name its JVM'); + const log = path.resolve( + workspace, + startup.find((arg) => arg.startsWith('--server_jvm_out='))?.slice(17) ?? + path.join(server, 'jvm.out'), + ); + const offset = statSync(log).size; + process.kill(Number(pid), 'SIGQUIT'); + await new Promise((resolve) => setTimeout(resolve, 2000)); + // Retain only the new thread dump; earlier server output can contain action diagnostics. + const snapshot = Buffer.alloc( + Math.min(2 * 1024 * 1024, Math.max(0, statSync(log).size - offset)), + ); + const fd = openSync(log, 'r'); + try { + const bytes = readSync(fd, snapshot, 0, snapshot.length, offset); + writeFileSync(diagnosticFile('aquery-jvm.log'), snapshot.subarray(0, bytes), { + flag: 'wx', + mode: 0o600, + }); + } finally { + closeSync(fd); + } + } finally { + for (const [name, command, args] of [ + ['disk.txt', 'df', ['-Pk', output]], + ['processes.txt', 'ps', ['-axo', 'pid,ppid,state,etime,%cpu,%mem,comm']], + ] as const) + writeFileSync( + diagnosticFile(name), + execFileSync(command, args, { + timeout: 2000, + killSignal: 'SIGKILL', + }), + { + flag: 'wx', + mode: 0o600, + }, + ); + } + }; + const aquery = async (args: string[]) => { + const finish = phase('aquery'); + try { + await new Promise((resolve, reject) => { + const child = commands.spawnBazel('bash', ['tools/dev/bazel.sh', ...startup, ...args], { + cwd: workspace, + stdio: ['ignore', 'inherit', 'inherit'], + }); + let exceeded = false; + let error: Error | undefined; + let snapshot: Promise | undefined; + let escalation: ReturnType | undefined; + // Ordinary captures finish in seconds. A stalled serializer must not consume the build's job budget. + const timer = setTimeout( + () => { + if (commands.interrupted) return; + exceeded = true; + snapshot = captureQueryDiagnostics() + .catch((error: NodeJS.ErrnoException) => + console.error( + `native qualification: aquery diagnostics unavailable (${error.code ?? 'unknown'})`, + ), + ) + .finally(() => { + if (commands.interrupted || child.exitCode !== null || child.signalCode !== null) + return; + escalation = setTimeout(() => { + if (!commands.interrupted) child.kill('SIGKILL'); + }, 5000); + child.kill('SIGTERM'); + }); + }, + 5 * 60 * 1000, + ); + child.once('error', (cause) => { + error = cause; + clearTimeout(timer); + clearTimeout(escalation); + }); + child.once('close', async (code, signal) => { + clearTimeout(timer); + await snapshot; + clearTimeout(escalation); + try { + commands.assertRunning(); + if (error) throw error; + if (exceeded) + throw new Error('shipping qualification aquery exceeded its five-minute limit'); + if (code !== 0) + throw new Error(`shipping qualification aquery failed (${signal ?? code})`); + resolve(); + } catch (cause) { + reject(cause); + } + }); + }); + } finally { + finish(); + } + }; + let roots: string[]; + let shippingExport: string | undefined; + let sliceGroups: string[] = []; + let requiredTests: NativeRequiredTest[] = []; + let requiredLabels: string[] = []; + const sourceOnly = request.ci?.mode === 'source' && !request.ci.handoff; + if ('export' in request.shipping) { + const owner = label(request.shipping.export); + shippingExport = owner; + await bazel( + [ + 'cquery', + owner, + ...configuration, + `--universe_scope=${owner}`, + '--output=starlark', + '--starlark:expr=json.encode({"roots": [str(value.label) for value in providers(target)["//build_defs/release:shipping.bzl%ShippingExportInfo"].packages], "qualification": [str(value.label) for value in providers(target)["//build_defs/release:shipping.bzl%ShippingExportInfo"].qualification], "sliceGroups": [name for name in dir(providers(target)["OutputGroupInfo"]) if name.startswith("apple_slice_")], "suppliers": [providers(value)["//build_defs/release:shipping.bzl%ShippingInfo"].supplier_inputs for value in providers(target)["//build_defs/release:shipping.bzl%ShippingExportInfo"].packages if providers(value)["//build_defs/release:shipping.bzl%ShippingInfo"].supplier_inputs != None]})', + ], + file('selected-owner.json'), + ); + let selected: { + roots: unknown; + qualification: unknown; + sliceGroups: unknown; + suppliers: unknown; + }; + try { + selected = json(file('selected-owner.json')) as typeof selected; + } catch (cause) { + // cquery can return success with empty output for an incompatible owner. + // Ask Bazel for its dependency diagnostic without executing any actions. + try { + await bazel(['build', owner, ...configuration, '--nobuild']); + } catch (analysisError) { + throw new Error(`Shipping export ${owner}: Bazel configuration analysis failed`, { + cause: new AggregateError([cause, analysisError]), + }); + } + throw new Error(`Shipping export ${owner} returned no readable configured export provider`, { + cause, + }); + } + if ( + !selected || + typeof selected !== 'object' || + Array.isArray(selected) || + Object.keys(selected).sort().join(',') !== 'qualification,roots,sliceGroups,suppliers' || + !Array.isArray(selected.suppliers) + ) + throw new Error('shipping qualification requires its configured export provider'); + // Carriers may share suppliers, so duplicate checks stay local to each package. + for (const suppliers of selected.suppliers) validateNativeShippingSuppliers(suppliers); + roots = argv(selected.roots, 'source-owned shipping roots').map(label); + sliceGroups = argv(selected.sliceGroups, 'Apple slice output groups').sort(); + if ( + new Set(sliceGroups).size !== sliceGroups.length || + sliceGroups.some((group) => !/^apple_slice_[a-z0-9_-]+$/u.test(group)) + ) + throw new Error('Apple slice output groups must be unique SDK identifiers'); + const tests = argv(selected.qualification, 'source-owned qualification').map(label); + requiredLabels = tests; + if (new Set(tests).size !== tests.length) + throw new Error('shipping qualification requires unique source-owned tests'); + // These graph edges are source-owned, independently of caller targets. + // An incompatible declared test fails analysis rather than disappearing. + if (tests.length && !sourceOnly) + await bazel( + [ + 'cquery', + `set(${tests.join(' ')})`, + ...configuration, + `--universe_scope=${owner}`, + '--output=jsonproto', + '--proto:include_configurations', + ], + file('qualification-targets.json'), + ); + if (tests.length && !sourceOnly) { + requiredTests = configuredQualificationTests(json(file('qualification-targets.json'))); + assert.deepStrictEqual( + requiredTests.map((test) => test.label).sort(), + [...tests].sort(), + 'configured source-owned test coverage', + ); + } + } else roots = argv(request.shipping.roots, 'shipping roots').map(label); + if (!roots.length || new Set(roots).size !== roots.length) + throw new Error('shipping qualification requires nonempty unique shipping roots'); + roots.sort(); + writeFileSync(file('selected-roots.json'), `${JSON.stringify(roots)}\n`, { flag: 'wx' }); + // Only loading options apply to the buildfiles query below. + const loadingFlags = configuration.filter((flag) => + /^--(?:lockfile_mode|enable_bzlmod|repo_env|override_repository|repository_cache|registry)(?:=|$)/u.test( + flag, + ), + ); + assertSource(); + const buildTargets = [ + ...new Set([ + ...roots, + ...(shippingExport ? [shippingExport] : []), + ...requiredLabels, + ...targets, + ]), + ]; + const ciIdentity = request.ci && { + id: request.ci.id, + job: request.ci.job, + requires: request.ci.requires, + source, + github: request.github, + outputDirectory: output, + workspaceRoot: workspace, + }; + // Finish each SDK's existing actions before changing its sandbox population. + // The final test invocation still qualifies the complete requested scope once. + for (const group of sliceGroups) { + await bazel([ + 'build', + ...roots, + ...configuration, + ...metadata, + `--output_groups=${group}`, + '--run_validations=false', + `--profile=${diagnosticFile(`${group}-profile.json.gz`)}`, + ]); + assertSource(); + } + if (sourceOnly) { + await bazel(['test', ...buildTargets, ...configuration, ...metadata]); + return writeConfiguredCiSuccessReceipt(ciIdentity!); + } + await bazel([ + 'test', + ...buildTargets, + ...configuration, + ...metadata, + `--build_event_json_file=${file('build-events.jsonl')}`, + `--profile=${diagnosticFile('build-profile.json.gz')}`, + '--output_groups=+shipping_manifest,+shipping_policy,+observation_inputs', + ]); + assertSource(); + await aquery([ + 'aquery', + nativeAqueryExpression(buildTargets), + ...configuration, + ...metadata, + ...NATIVE_AQUERY_FLAGS, + `--output_file=${file('aquery.json')}`, + `--build_event_json_file=${file('aquery-build-events.jsonl')}`, + `--profile=${diagnosticFile('aquery-profile.json.gz')}`, + ]); + assertSource(); + await bazel(['info', ...configuration, 'execution_root'], file('execution-root.txt')); + const executionRoot = readFileSync(file('execution-root.txt'), 'utf8').trim(); + if (!path.isAbsolute(executionRoot) || /[\u0000-\u001f\u007f]/u.test(executionRoot)) + throw new Error('shipping qualification requires one absolute execution root'); + assertSource(); + const buildEvents = readFileSync(file('build-events.jsonl'), 'utf8') + .split(/\r?\n/u) + .filter(Boolean) + .map((line) => JSON.parse(line)); + const bep = nativeBuildEventIndex( + { executionRoot, buildEvents }, + readFileSync(new URL('../../.bazelversion', import.meta.url), 'utf8').trim(), + nativeBuildMetadata(source, request.github), + ); + const rootConfigurations = roots.map((root) => { + const matches = bep.completed.filter((target) => canonicalShippingLabel(target.label) === root); + assert( + matches.length === 1 && matches[0].value.success === true, + 'shipping recipe root has no unique successful configuration', + ); + return { label: root, configuration: matches[0].configuration }; + }); + const depsFile = file('analysis-deps.json'); + const depsQuery = file('analysis-deps.query'); + writeFileSync( + depsQuery, + `deps(set(${(request.ci?.mode === 'full' ? buildTargets : roots).map((root) => JSON.stringify(root)).join(' ')}))`, + { + flag: 'wx', + }, + ); + await bazel( + [ + 'cquery', + `--query_file=${depsQuery}`, + ...configuration, + ...(request.ci?.mode === 'full' ? ['--lockfile_mode=update', '--consistent_labels'] : []), + '--output=jsonproto', + '--transitions=lite', + '--proto:include_configurations', + '--proto:output_rule_attrs=', + ], + depsFile, + ); + const graph = nativeConfiguredRecipeGraph(json(depsFile), rootConfigurations); + // Query each distinct configured package set once, including external + // packages: their BUILD files can load workspace Starlark. Representatives + // are actual reached labels. Bazel 8 proto omits BUILD.bazel subinclude, so + // use the real buildfiles label inventory in this frozen source context. + const packageLabels = new Map(graph.packages.map((row) => [row.package, row.label])); + const recipeQueries = new Map(); + for (const root of graph.roots) { + const key = JSON.stringify(root.packages); + if (recipeQueries.has(key)) continue; + const index = recipeQueries.size; + const recipeFile = file(`analysis-buildfiles-${index}.txt`); + const recipeQuery = file(`analysis-buildfiles-${index}.query`); + writeFileSync( + recipeQuery, + `buildfiles(set(${root.packages.map((pkg) => JSON.stringify(packageLabels.get(pkg))).join(' ')}))`, + { flag: 'wx' }, + ); + await bazel( + [ + 'query', + `--query_file=${recipeQuery}`, + ...loadingFlags, + ...(request.ci?.mode === 'full' ? ['--consistent_labels'] : []), + '--output=label', + ], + recipeFile, + ); + recipeQueries.set(key, { + packages: root.packages, + labels: readFileSync(recipeFile, 'utf8').split(/\r?\n/u).filter(Boolean), + }); + } + const rootInputs = nativeRecipeInputPaths(graph, [...recipeQueries.values()]); + writeFileSync(file('analysis-root-inputs.json'), `${JSON.stringify(rootInputs)}\n`, { + flag: 'wx', + }); + assertSource(); + writeFileSync( + file('expected-qualification.json'), + `${JSON.stringify({ + source, + github: request.github, + bazelVersion: readFileSync(new URL('../../.bazelversion', import.meta.url), 'utf8').trim(), + ...(requiredTests.length ? { requiredTests, requireShippingAnalysis: true } : {}), + })}\n`, + { flag: 'wx' }, + ); + // Retain OS CPU timing without the memory overhead of continuous sampling. + const macos = process.platform === 'darwin'; + await run( + 'capture', + macos ? '/usr/bin/time' : 'bash', + [ + ...(macos ? ['-p', 'bash'] : []), + 'tools/release/with-source.sh', + 'HEAD', + 'bash', + 'tools/dev/bun.sh', + 'tools/release/capture-native-build-evidence.mts', + '--github-json', + file('github.json'), + '--expected-qualification-json', + file('expected-qualification.json'), + '--producer-cohort', + file('selected-roots.json'), + file('aquery.json'), + file('build-events.jsonl'), + executionRoot, + '--aquery-build-events', + file('aquery-build-events.jsonl'), + ...(shippingExport ? ['--shipping-export', shippingExport] : []), + '--analysis-root-inputs', + file('analysis-root-inputs.json'), + workspace, + '--output-directory', + file('evidence'), + '--source-ref', + 'HEAD', + ], + undefined, + commands.spawnCapture, + ); + const evidence = file('evidence/native-build-evidence.json'); + try { + assertSource(); + if (completeProducts.length) { + checkCompleteProducts(json(evidence) as NativeBuildEvidence, completeProducts); + assertSource(); + } + } catch (error) { + // The collector completed, so this file belongs to this invocation. Keep + // raw diagnostics, but remove a packet that failed final validation. + rmSync(path.dirname(evidence), { recursive: true, force: true }); + throw error; + } + if (request.ci?.mode === 'full') { + commands.assertRunning(); + await captureConfiguredCiRequest( + { + ...ciIdentity!, + configuration, + startup, + requestedTargets: buildTargets, + completedRoots: completedCiRequestRoots(bep, buildTargets), + executionRoot, + nativeEvidence: evidence, + configuredGraph: json(depsFile), + recipeQueries: [...recipeQueries.values()], + }, + { bazel, assertRunning: commands.assertRunning }, + ); + } else if (ciIdentity) { + commands.assertRunning(); + writeConfiguredCiSuccessReceipt(ciIdentity); + } + commands.assertRunning(); + return evidence; +} + +async function main() { + const { values } = parseArgs({ + options: { + 'github-json': { type: 'string' }, + 'configuration-json': { type: 'string' }, + 'startup-json': { type: 'string' }, + 'shipping-export': { type: 'string' }, + 'shipping-roots-json': { type: 'string' }, + 'targets-json': { type: 'string' }, + 'complete-products-json': { type: 'string' }, + 'output-directory': { type: 'string' }, + 'ci-request-id': { type: 'string' }, + 'ci-job': { type: 'string' }, + 'ci-mode': { type: 'string' }, + 'ci-requires-json': { type: 'string' }, + 'ci-handoff': { type: 'boolean', default: false }, + }, + strict: true, + }); + if ( + !values['github-json'] || + !values['configuration-json'] || + !values['output-directory'] || + Boolean(values['shipping-export']) === Boolean(values['shipping-roots-json']) + ) + throw new Error( + 'usage: qualify-native-shipping.mts --github-json FILE --configuration-json FILE [--startup-json FILE] (--shipping-export LABEL | --shipping-roots-json FILE) [--targets-json FILE] [--complete-products-json FILE] --output-directory DIR', + ); + let shipping: NativeShippingRequest['shipping']; + const ciMode = values['ci-mode']; + const ciId = values['ci-request-id']; + const ciJob = values['ci-job']; + if ( + (ciMode || ciId || ciJob || values['ci-requires-json'] || values['ci-handoff']) && + (!['full', 'source'].includes(ciMode ?? '') || !ciId || !ciJob) + ) + throw new Error('CI qualification requires mode, request ID and job'); + if (values['shipping-export']) shipping = { export: values['shipping-export'] }; + else { + const rootsFile = values['shipping-roots-json']; + if (!rootsFile) throw new Error('shipping roots are missing'); + shipping = { roots: argv(json(rootsFile), 'shipping roots') }; + } + console.log( + await qualifyNativeShipping({ + ...(ciMode && ciId && ciJob + ? { + ci: { + id: ciId, + job: ciJob, + mode: ciMode as 'full' | 'source', + requires: values['ci-requires-json'] + ? argv(json(values['ci-requires-json']), 'CI prerequisites') + : [], + handoff: values['ci-handoff'], + }, + } + : {}), + github: json(values['github-json']) as NativeBuildGithub, + startup: values['startup-json'] ? argv(json(values['startup-json']), 'startup') : [], + configuration: argv(json(values['configuration-json']), 'configuration'), + shipping, + targets: values['targets-json'] + ? argv(json(values['targets-json']), 'additional targets') + : [], + completeProducts: values['complete-products-json'] + ? argv(json(values['complete-products-json']), 'complete products') + : [], + outputDirectory: values['output-directory'], + }), + ); +} + +if (import.meta.main) { + try { + await main(); + } catch (error) { + console.error(error instanceof Error ? error.message : error); + process.exitCode = 1; + } +} diff --git a/tools/release/qualify-native-shipping.test.mts b/tools/release/qualify-native-shipping.test.mts new file mode 100644 index 000000000..f1eb3a2fa --- /dev/null +++ b/tools/release/qualify-native-shipping.test.mts @@ -0,0 +1,1838 @@ +import { expect, spyOn, test } from 'bun:test'; +import * as childProcess from 'node:child_process'; +import { execFileSync } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { + appendFileSync, + copyFileSync, + existsSync, + mkdirSync, + mkdtempSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import * as shippingInputs from './bazel-shipping-inputs.mts'; +import { + nativeAqueryExpression, + validateNativeBuildEvidence, +} from './native-build-qualification.mts'; +import { + type NativeShippingRequest, + nativeConfiguredRecipeGraph, + nativeRecipeInputPaths, + qualifyNativeShipping, +} from './qualify-native-shipping.mts'; + +const realCapture = fileURLToPath(new URL('./capture-native-build-evidence.mts', import.meta.url)); +const withSource = fileURLToPath(new URL('./with-source.sh', import.meta.url)); +const qualifiedReplay = fileURLToPath(new URL('./qualified-release-replay.sh', import.meta.url)); + +function recipeFixture() { + const one = '1'.repeat(64), + two = '2'.repeat(64), + tool = '3'.repeat(64); + const rule = (name: string, config: number, deps: [string, number][]) => ({ + configurationId: config, + target: { + rule: { + name, + configuredRuleInput: deps.map(([label, configurationId]) => ({ + label, + ...(configurationId ? { configurationId } : {}), + })), + }, + }, + }); + const query = { + configurations: [ + { id: 1, checksum: one }, + { id: 2, checksum: two }, + { id: 3, checksum: tool }, + ], + results: [ + rule('//a:shipping', 1, [['//lib:adapter', 1]]), + rule('//b:shipping', 2, [['//lib:adapter', 2]]), + rule('//lib:adapter', 1, [ + ['//left:implementation', 1], + ['//common:tool', 3], + ]), + rule('//lib:adapter', 2, [ + ['//right:implementation', 2], + ['//common:tool', 3], + ]), + rule('//left:implementation', 1, []), + rule('//right:implementation', 2, []), + rule('//common:tool', 3, [['//common:header.h', 0]]), + { + configuration: { checksum: 'null' }, + target: { sourceFile: { name: '//common:header.h' } }, + }, + rule('//unrelated:qualification_only', 2, []), + ], + }; + const roots = [ + { label: '//a:shipping', configuration: one }, + { label: '//b:shipping', configuration: two }, + ]; + const files = ['a', 'b', 'lib', 'left', 'right', 'common', 'unrelated'].map((pkg) => ({ + package: `//${pkg}`, + labels: [ + `//${pkg}:BUILD.bazel`, + `//recipes:${pkg}.bzl`, + '//recipes:shared.bzl', + '@@external//:helper.bzl', + ], + })); + return { query, roots, files }; +} + +function queriedRecipes(graph, files) { + const sets = new Map(); + for (const root of graph.roots) { + sets.set(JSON.stringify(root.packages), { + packages: root.packages, + labels: root.packages.flatMap((pkg) => + files.filter((row) => row.package === pkg).flatMap((row) => row.labels), + ), + }); + } + return [...sets.values()].map((row) => ({ ...row, labels: [...new Set(row.labels)] })); +} + +test('one configured recipe graph preserves shared loads, disconnected targets and transitions', () => { + const f = recipeFixture(); + const graph = nativeConfiguredRecipeGraph(f.query, f.roots); + expect(graph.labels).not.toContain('//unrelated:qualification_only'); + expect(graph.packages).toEqual( + ['a', 'b', 'common', 'left', 'lib', 'right'].map((pkg) => ({ + package: `//${pkg}`, + label: + pkg === 'a' || pkg === 'b' + ? `//${pkg}:shipping` + : pkg === 'common' + ? '//common:header.h' + : pkg === 'lib' + ? '//lib:adapter' + : `//${pkg}:implementation`, + })), + ); + const rows = nativeRecipeInputPaths(graph, queriedRecipes(graph, f.files)); + expect(rows[0].paths).toEqual([ + 'a/BUILD.bazel', + 'common/BUILD.bazel', + 'left/BUILD.bazel', + 'lib/BUILD.bazel', + 'recipes/a.bzl', + 'recipes/common.bzl', + 'recipes/left.bzl', + 'recipes/lib.bzl', + 'recipes/shared.bzl', + ]); + expect(rows[1].paths).toEqual([ + 'b/BUILD.bazel', + 'common/BUILD.bazel', + 'lib/BUILD.bazel', + 'recipes/b.bzl', + 'recipes/common.bzl', + 'recipes/lib.bzl', + 'recipes/right.bzl', + 'recipes/shared.bzl', + 'right/BUILD.bazel', + ]); +}); + +test('generated Files follow their actual configured generating rule', () => { + const f = recipeFixture(); + f.query.results[0].target.rule.configuredRuleInput = [ + { label: '//generated:header.h', configurationId: 1 }, + ]; + f.query.results.push({ + configurationId: 1, + target: { + generatedFile: { name: '//generated:header.h', generatingRule: '//left:implementation' }, + }, + } as any); + const graph = nativeConfiguredRecipeGraph(f.query, f.roots.slice(0, 1)); + expect(graph.labels).toContain('//left:implementation'); + expect(graph.labels).not.toContain('//right:implementation'); +}); + +test('missing, substituted and cyclic configured recipes or loads reject', () => { + for (const mutate of [ + (f) => { + f.roots[0].configuration = '4'.repeat(64); + }, + (f) => { + f.query.results[0].target.rule.configuredRuleInput[0].configurationId = 999; + }, + (f) => { + f.query.results[0].target.rule.configuredRuleInput[0].configurationChecksum = '4'.repeat(64); + }, + (f) => { + f.query.results[0].target.rule.configuredRuleInput[0].label = '//missing:rule'; + }, + (f) => { + f.query.results[4].target.rule.configuredRuleInput = [ + { label: '//a:shipping', configurationId: 1 }, + ]; + }, + (f) => { + const conflict = structuredClone(f.query.results[0]); + conflict.target.rule.configuredRuleInput.push({ + label: '//right:implementation', + configurationId: 2, + }); + f.query.results.push(conflict); + }, + (f) => { + f.files = f.files.filter((row) => row.package !== '//common'); + }, + (f) => { + const common = f.files.find((row) => row.package === '//common'); + if (!common) throw new Error('missing common fixture'); + common.labels = ['//recipes:shared.bzl']; + }, + (f) => { + f.files[0].labels.push('//recipes:../outside.bzl'); + }, + (f) => { + f.files[0].labels.push('//a:BUILD'); + }, + ]) { + const f = recipeFixture(); + mutate(f); + expect(() => + nativeRecipeInputPaths( + nativeConfiguredRecipeGraph(f.query, f.roots), + queriedRecipes(nativeConfiguredRecipeGraph(f.query, f.roots), f.files), + ), + ).toThrow(); + } +}); + +test('repeated configured nodes preserve typed topology and loaded source closure', () => { + const f = recipeFixture(); + const graph = nativeConfiguredRecipeGraph(f.query, f.roots); + const paths = nativeRecipeInputPaths(graph, queriedRecipes(graph, f.files)); + for (const reverse of [false, true]) { + const repeated = structuredClone(f.query); + for (const row of structuredClone(repeated.results)) { + const inputs = row.target.rule?.configuredRuleInput; + if (inputs?.length) { + inputs.reverse(); + inputs.push(inputs[0]); + } + repeated.results.push(row); + } + if (reverse) repeated.results.reverse(); + const actual = nativeConfiguredRecipeGraph(repeated, f.roots); + expect(actual).toEqual(graph); + expect(nativeRecipeInputPaths(actual, queriedRecipes(actual, f.files))).toEqual(paths); + } +}); + +test('repeated generated files and package groups must retain their actual dependency definition', () => { + const f = recipeFixture(); + f.query.results[0].target.rule.configuredRuleInput.push( + { label: '//generated:header.h', configurationId: 1 }, + { label: '//visibility:group' }, + ); + f.query.results.push( + { + configurationId: 1, + target: { + generatedFile: { name: '//generated:header.h', generatingRule: '//left:implementation' }, + }, + } as any, + { + target: { + packageGroup: { name: '//visibility:group', includedPackageGroup: ['//visibility:leaf'] }, + }, + } as any, + { target: { packageGroup: { name: '//visibility:leaf', includedPackageGroup: [] } } } as any, + ); + const graph = nativeConfiguredRecipeGraph(f.query, f.roots); + const repeated = structuredClone(f.query); + repeated.results.push(...structuredClone(f.query.results.slice(-3))); + expect(nativeConfiguredRecipeGraph(repeated, f.roots)).toEqual(graph); + for (const [index, mutate] of [ + [ + 0, + (row: any) => { + row.target.rule.ruleClass = 'different_rule'; + }, + ], + [ + 7, + (row: any) => { + row.target = { rule: { name: '//common:header.h', configuredRuleInput: [] } }; + }, + ], + [ + 9, + (row: any) => { + row.target.generatedFile.generatingRule = '//right:implementation'; + }, + ], + [ + 10, + (row: any) => { + row.target.packageGroup.includedPackageGroup = []; + }, + ], + ] as const) { + const conflict = structuredClone(f.query); + const row = structuredClone(conflict.results[index]); + mutate(row); + conflict.results.push(row); + expect(() => nativeConfiguredRecipeGraph(conflict, f.roots)).toThrow( + 'conflicting configured recipe target', + ); + } +}); + +test('external configured packages retain workspace loads and equal package sets share one result', () => { + const f = recipeFixture(); + f.query.results[6].target.rule.configuredRuleInput.push({ + label: '@@original//native:library', + configurationId: 3, + }); + f.query.results.push({ + configurationId: 3, + target: { rule: { name: '@@original//native:library', configuredRuleInput: [] } }, + } as any); + f.files.push({ + package: '@@original//native', + labels: ['@original//native:BUILD.bazel', '//private:original-runtime-contract.bzl'], + }); + const graph = nativeConfiguredRecipeGraph(f.query, f.roots); + const queries = queriedRecipes(graph, f.files); + const result = nativeRecipeInputPaths(graph, queries); + expect(result.every((row) => row.paths.includes('private/original-runtime-contract.bzl'))).toBe( + true, + ); + const same = nativeConfiguredRecipeGraph(f.query, [f.roots[0]]); + same.roots.push({ ...same.roots[0], label: '//alias:shipping' }); + const shared = queriedRecipes(same, f.files); + expect(shared).toHaveLength(1); + expect(nativeRecipeInputPaths(same, shared)[1].paths).toEqual( + nativeRecipeInputPaths(same, shared)[0].paths, + ); + for (const value of [ + [], + [...queries, queries[0]], + [...queries, { packages: ['//injected'], labels: ['//injected:BUILD.bazel'] }], + queries.map((row) => ({ ...row, labels: [...row.labels, row.labels[0]] })), + ]) + expect(() => nativeRecipeInputPaths(graph, value)).toThrow(); +}); + +function fixture(mode = 'success') { + const directory = mkdtempSync(path.join(tmpdir(), 'qualify-native-shipping-')); + const workspace = path.join(directory, 'workspace'); + const executionRoot = path.join(directory, 'bazel/execroot/_main'); + const outputDirectory = path.join(directory, 'capture'); + const stateFile = path.join(directory, 'state.json'); + const callsFile = path.join(directory, 'calls.jsonl'); + const countsFile = path.join(directory, 'capture-counts.json'); + for (const name of ['src', 'tools/dev', 'tools/release']) + mkdirSync(path.join(workspace, name), { recursive: true }); + mkdirSync(path.join(executionRoot, 'bazel-out/k8-fastbuild/bin'), { recursive: true }); + writeFileSync(path.join(workspace, 'src/input.mts'), 'declared source'); + writeFileSync(path.join(workspace, '.bazelversion'), '8.8.1\n'); + writeFileSync( + path.join(workspace, 'MODULE.bazel.lock'), + '{"lockFileVersion":28,"moduleExtensions":{}}', + ); + writeFileSync( + path.join(directory, 'bazel/MODULE.bazel.lock'), + '{"lockFileVersion":28,"moduleExtensions":{}}', + ); + mkdirSync(path.join(directory, 'bazel/external')); + writeFileSync(path.join(directory, 'bazel/external/@registry.marker'), `${'a'.repeat(64)}\n`); + mkdirSync(path.join(workspace, 'fixture')); + writeFileSync(path.join(workspace, 'fixture/BUILD.bazel'), 'declared shipping recipe'); + writeFileSync(path.join(workspace, 'fixture/macro1.bzl'), 'load(":macro2.bzl", "macro2")'); + writeFileSync(path.join(workspace, 'fixture/macro2.bzl'), 'def macro2(): pass'); + symlinkSync(path.join(workspace, 'src'), path.join(executionRoot, 'src'), 'dir'); + const output = 'bazel-out/k8-fastbuild/bin/native.tar.gz'; + const outputBytes = Buffer.from('final archive'); + writeFileSync(path.join(executionRoot, output), outputBytes); + const shellQuote = (value: string) => `'${value.replaceAll("'", "'\\''")}'`; + writeFileSync( + path.join(workspace, 'tools/dev/bun.sh'), + `#!/usr/bin/env bash\nexec ${shellQuote(process.execPath)} "$@"\n`, + ); + copyFileSync(withSource, path.join(workspace, 'tools/release/with-source.sh')); + copyFileSync(qualifiedReplay, path.join(workspace, 'tools/release/qualified-release-replay.sh')); + if (mode === 'capture-count') + writeFileSync( + path.join(workspace, 'tools/release/capture-counter.mts'), + `import {spyOn} from 'bun:test'; +import {writeFileSync} from 'node:fs'; +import * as graph from ${JSON.stringify(fileURLToPath(new URL('./bazel-shipping-inputs.mts', import.meta.url)))}; +const views=spyOn(graph,'buildShippingInputView'); +process.on('exit',()=>writeFileSync(${JSON.stringify(countsFile)},JSON.stringify({views:views.mock.calls.length}))); +`, + ); + writeFileSync( + path.join(workspace, 'tools/release/capture-native-build-evidence.mts'), + `import {spawn,spawnSync} from 'node:child_process'; +import {readFileSync,writeFileSync} from 'node:fs'; +const state=JSON.parse(readFileSync(${JSON.stringify(stateFile)},'utf8')); +if(state.mode==='capture-interrupt') { + const child=spawn(process.execPath,['--no-install','--no-env-file','-e',${JSON.stringify(` +import {appendFileSync,mkdirSync,readFileSync,rmSync,writeFileSync} from 'node:fs'; +const state=JSON.parse(readFileSync(${JSON.stringify(stateFile)},'utf8')); +mkdirSync(state.commandLock); +process.on('exit',()=>appendFileSync(state.commandEvents,'closed\\n')); +process.on('SIGTERM',()=>{appendFileSync(state.commandEvents,'SIGTERM\\n');rmSync(state.commandLock,{recursive:true});process.exit(0);}); +writeFileSync(state.commandReady,String(process.pid)); +setInterval(()=>{},1000); +`)}],{stdio:'inherit'}); + await new Promise(resolve=>child.once('close',resolve)); + process.exit(0); +} +if(state.mode==='capture-race') writeFileSync('src/input.mts','changed during capture'); +const preload=state.mode==='capture-count'?['--preload',${JSON.stringify(path.join(workspace, 'tools/release/capture-counter.mts'))}]:[]; +const result=spawnSync(process.execPath,[...preload,${JSON.stringify(realCapture)},...process.argv.slice(2)],{stdio:'inherit'}); +if(state.mode==='capture-output-race' && result.status===0) writeFileSync(state.output,'changed after capture'); +process.exit(result.status??1); +`, + ); + writeFileSync( + path.join(workspace, 'tools/dev/bazel.sh'), + `#!/usr/bin/env bash\nexec ${shellQuote(process.execPath)} tools/dev/bazel-fixture.mts "$@"\n`, + ); + writeFileSync( + path.join(workspace, 'tools/dev/bazel-fixture.mts'), + `import {appendFileSync,existsSync,mkdirSync,readFileSync,rmSync,writeFileSync} from 'node:fs'; +import {createHash} from 'node:crypto'; +import {execFileSync} from 'node:child_process'; +const state=JSON.parse(readFileSync(${JSON.stringify(stateFile)},'utf8')); +const invocation=process.argv.slice(2); +appendFileSync(${JSON.stringify(callsFile)},JSON.stringify(invocation)+'\\n'); +const args=invocation.slice(invocation.findIndex((arg:string)=>['test','build','cquery','query','aquery','info'].includes(arg))); +if(state.commandLock && args[0]!=='test' && existsSync(state.commandLock)) throw Error('previous Bazel command still owns the lock'); +const profile=args.find((arg:string)=>arg.startsWith('--profile=')); +if(profile) writeFileSync(profile.slice(10),'fixture profile'); +const expression=args[1]?.startsWith('--query_file=')?readFileSync(args[1].slice(13),'utf8'):args[1]; +if(args[0]==='test') { + if(state.mode==='build-interrupt-zero' || state.mode==='build-interrupt-failure') { + mkdirSync(state.commandLock); + process.on('exit',()=>appendFileSync(state.commandEvents,'closed\\n')); + process.on('SIGINT',()=>{ + appendFileSync(state.commandEvents,'SIGINT\\n'); + setTimeout(()=>{rmSync(state.commandLock,{recursive:true});process.exit(state.mode==='build-interrupt-zero'?0:130);},50); + }); + writeFileSync(state.commandReady,String(process.pid)); + setInterval(()=>{},1000); + await new Promise(()=>{}); + } + if(state.mode==='build-failure') process.exit(1); + if(state.mode==='build-race') writeFileSync('src/input.mts','changed during build'); + if(state.mode==='head-race') { + writeFileSync('src/input.mts','new committed source'); + execFileSync('git',['add','src/input.mts']); + execFileSync('git',['-c','user.name=Fixture','-c','user.email=fixture@example.invalid','commit','-qm','changed source']); + } + const metadata=Object.fromEntries(args.filter((arg:string)=>arg.startsWith('--build_metadata=')).map((arg:string)=>{const value=arg.slice(17);const split=value.indexOf('=');return [value.slice(0,split),value.slice(split+1)];})); + if(state.mode==='raw-metadata-mismatch') metadata.fixture_observation='build-value'; + if(state.mode==='manifest-tamper') writeFileSync(state.manifest,JSON.stringify({...state.root,package:{...state.root.package,version:'1.0.1'}})+'\\n'); + if(state.policy) { + const policy={...state.policy,qualification:(state.qualification.results??[]).map((result:any)=>result.target.rule.name.replace(/^@@?\\/\\//,'//'))}; + const contents=JSON.stringify(policy)+'\\n'; + writeFileSync(state.policyFile,contents); + const file=state.events.find((event:any)=>event.id?.namedSet?.id==='shipping-policy').namedSetOfFiles.files[0]; + file.digest=createHash('sha256').update(contents).digest('hex');file.length=String(Buffer.byteLength(contents)); + } + const options=args.filter((arg:string)=>arg.startsWith('--')).map((arg:string)=>{const split=arg.indexOf('=');return {optionName:arg.slice(2,split<0?undefined:split),optionValue:split<0?'':arg.slice(split+1)};}); + const canonical={id:{structuredCommandLine:{commandLineLabel:'canonical'}},structuredCommandLine:{commandLineLabel:'canonical',sections:[{sectionLabel:'command',chunkList:{chunk:['test']}},{sectionLabel:'command options',optionList:{option:options}},{sectionLabel:'residual',chunkList:{chunk:args.filter((arg:string)=>arg.startsWith('//'))}}]}}; + const events=[...state.events,...state.testEvents,canonical,{id:{buildMetadata:{}},buildMetadata:{metadata}},{id:{buildFinished:{}},finished:{exitCode:{name:'SUCCESS'}}},{id:{buildMetrics:{}},buildMetrics:{},lastMessage:true}]; + const bep=args.find((arg:string)=>arg.startsWith('--build_event_json_file=')); + if(bep) writeFileSync(bep.slice(24),events.map((event:unknown)=>JSON.stringify(event)).join('\\n')+'\\n'); +} else if(args[0]==='aquery') { + if(state.mode==='aquery-failure') process.exit(1); + if(state.mode==='aquery-hang' || state.mode==='aquery-ignore-term') { + if(state.mode==='aquery-ignore-term') process.on('SIGTERM',()=>{}); + writeFileSync(args.find((arg:string)=>arg.startsWith('--output_file=')).slice(14),'partial output'); + setInterval(()=>{},1000); + await new Promise(()=>{}); + } + if(state.mode==='aquery-race') writeFileSync('src/input.mts','changed during analysis'); + const metadata=Object.fromEntries(args.filter((arg:string)=>arg.startsWith('--build_metadata=')).map((arg:string)=>{const value=arg.slice(17);const split=value.indexOf('=');return [value.slice(0,split),value.slice(split+1)];})); + if(state.mode==='raw-metadata-mismatch') metadata.fixture_observation='query-value'; + const options=args.filter((arg:string)=>arg.startsWith('--')).map((arg:string)=>{const split=arg.indexOf('=');const value=split<0?'':arg.slice(split+1);return {optionName:arg.slice(2,split<0?undefined:split),optionValue:value};}); + const canonical={id:{structuredCommandLine:{commandLineLabel:'canonical'}},structuredCommandLine:{commandLineLabel:'canonical',sections:[{sectionLabel:'command',chunkList:{chunk:['aquery']}},{sectionLabel:'command options',optionList:{option:[...options,{optionName:'client_env',optionValue:'PRIVATE=not-for-retention'}]}},{sectionLabel:'residual',chunkList:{chunk:[expression]}}]}}; + const prefix=structuredClone(state.events.filter((event:any)=>event.started||event.workspaceInfo||event.configuration)); + prefix.find((event:any)=>event.started).started.uuid='fixture-aquery'; + const events=[...prefix,canonical,{id:{progress:{}},progress:{stdout:'private-query-diagnostic'}},{id:{buildMetadata:{}},buildMetadata:{metadata}},{id:{buildFinished:{}},finished:{exitCode:{name:'SUCCESS'}}},{id:{buildMetrics:{}},buildMetrics:{},lastMessage:true}]; + writeFileSync(args.find((arg:string)=>arg.startsWith('--build_event_json_file=')).slice(24),events.map((event:unknown)=>JSON.stringify(event)).join('\\n')+'\\n'); + if(state.mode!=='dump-missing') writeFileSync(args.find((arg:string)=>arg.startsWith('--output_file=')).slice(14),JSON.stringify(state.aquery)+'\\n'); +} else if(args[0]==='build') { + const group=args.find((arg:string)=>arg.startsWith('--output_groups=apple_slice_'))?.slice(16); + if(group) { + if(group===state.interruptedSliceGroup) { + if(state.mode==='slice-failure') process.exit(1); + if(state.mode==='slice-race') writeFileSync('src/input.mts','changed during slice build'); + } + process.exit(0); + } + if(args.at(-1)!=='--nobuild') throw new Error('failure diagnosis must not construct targets'); + if(state.mode==='incompatible-owner') { + console.error('Target //fixture:shipping_export is incompatible because dependency //fixture:host_library is incompatible'); + process.exit(1); + } +} else if(args[0]==='info') console.log(state.executionRoot); +else if(args[0]==='query') { + if(state.mode==='analysis-failure' || state.mode==='deleted-load') process.exit(1); + if(!expression.startsWith('buildfiles(set("//fixture:')) throw new Error('configured package label must be quoted'); + console.log('//fixture:BUILD.bazel'); + console.log('//fixture:macro1.bzl'); + console.log('//fixture:macro2.bzl'); + console.log('@@registry//:helper.bzl'); +} +else { + if(state.mode==='discovery-failure') process.exit(1); + if(!expression.startsWith('deps(') && !expression.startsWith('set(')) { + if(state.mode==='incompatible-owner') process.exit(0); + if(state.mode==='malformed-owner') { console.log('{invalid'); process.exit(0); } + } + if(expression.startsWith('deps(')) { + console.log(JSON.stringify(state.recipeGraph)); + } else if(expression.startsWith('set(')) { + if(state.mode==='incompatible-policy') process.exit(1); + console.log(JSON.stringify(state.qualification)); + } else console.log(JSON.stringify({roots:['@@//fixture:shipping'],qualification:(state.qualification.results??[]).map((result:any)=>result.target.rule.name),sliceGroups:state.sliceGroups??[],suppliers:state.root.package.supplierInputs==null?[]:[state.root.package.supplierInputs]})); +} +`, + ); + const git = (...args: string[]) => + execFileSync('git', args, { cwd: workspace, encoding: 'utf8' }).trim(); + git('init', '--quiet'); + git('add', '.'); + git( + '-c', + 'user.name=Fixture', + '-c', + 'user.email=fixture@example.invalid', + 'commit', + '-qm', + 'fixture', + ); + const configuration = 'c'.repeat(64); + const root = { + label: '//fixture:shipping', + package: { + product: 'fixture', + version: '1.0.0', + ecosystem: 'github', + name: 'native.tar.gz', + configuration: 'linux-x64-gnu', + role: 'github-release-asset', + outputs: [{ path: output, owner: '//fixture:package' }], + }, + }; + const manifest = 'bazel-out/k8-fastbuild/bin/shipping.shipping.json'; + const manifestBytes = Buffer.from(`${JSON.stringify(root)}\n`); + writeFileSync(path.join(executionRoot, manifest), manifestBytes); + const policyFile = 'bazel-out/k8-fastbuild/bin/shipping_export.json'; + const policy = { + schema: 'oliphaunt-bazel-shipping-v1', + scope: 'construction', + owner: '//fixture:shipping_export', + roots: [root.label], + packages: [root.package], + qualification: ['//fixture:mandatory_test'], + }; + const policyBytes = Buffer.from(`${JSON.stringify(policy)}\n`); + writeFileSync(path.join(executionRoot, policyFile), policyBytes); + const paths = ['src/input.mts', output, manifest, policyFile]; + const aquery = { + pathFragments: paths.flatMap((file, index) => + file.split('/').map((name, part) => ({ + id: index * 100 + part + 1, + label: name, + ...(part ? { parentId: index * 100 + part } : {}), + })), + ), + artifacts: paths.map((file, index) => ({ + id: index + 1, + pathFragmentId: index * 100 + file.split('/').length, + })), + targets: [ + { id: 1, label: '//fixture:package' }, + { id: 2, label: root.label }, + { id: 3, label: '//fixture:shipping_export' }, + ], + configuration: [{ id: 1, checksum: configuration }], + depSetOfFiles: [{ id: 1, directArtifactIds: [1] }], + actions: [ + { + targetId: 1, + configurationId: 1, + actionKey: 'declared-package', + mnemonic: 'Package', + inputDepSetIds: [1], + outputIds: [2], + primaryOutputId: 2, + }, + { + targetId: 2, + configurationId: 1, + actionKey: 'declared-shipping-manifest', + mnemonic: 'FileWrite', + outputIds: [3], + primaryOutputId: 3, + }, + { + targetId: 3, + configurationId: 1, + actionKey: 'declared-owner-policy', + mnemonic: 'FileWrite', + outputIds: [4], + primaryOutputId: 4, + }, + ], + }; + const events = [ + { id: { started: {} }, started: { uuid: 'fixture-build', buildToolVersion: '8.8.1' } }, + { id: { workspace: {} }, workspaceInfo: { localExecRoot: executionRoot } }, + { id: { configuration: { id: configuration } }, configuration: { mnemonic: 'fixture' } }, + { + id: { namedSet: { id: 'outputs' } }, + namedSetOfFiles: { + files: [ + { + name: output, + digest: createHash('sha256').update(outputBytes).digest('hex'), + length: String(outputBytes.length), + }, + ], + }, + }, + { + id: { namedSet: { id: 'shipping-manifest' } }, + namedSetOfFiles: { + files: [ + { + name: manifest, + digest: createHash('sha256').update(manifestBytes).digest('hex'), + length: String(manifestBytes.length), + }, + ], + }, + }, + { + id: { targetCompleted: { label: root.label, configuration: { id: configuration } } }, + completed: { + success: true, + outputGroup: [ + { name: 'default', fileSets: [{ id: 'outputs' }] }, + { name: 'shipping_manifest', fileSets: [{ id: 'shipping-manifest' }] }, + ], + }, + }, + ]; + events.push( + { + id: { namedSet: { id: 'shipping-policy' } }, + namedSetOfFiles: { + files: [ + { + name: policyFile, + digest: createHash('sha256').update(policyBytes).digest('hex'), + length: String(policyBytes.length), + }, + ], + }, + }, + { + id: { + targetCompleted: { + label: '//fixture:shipping_export', + configuration: { id: configuration }, + }, + }, + completed: { + success: true, + outputGroup: [{ name: 'shipping_policy', fileSets: [{ id: 'shipping-policy' }] }], + }, + }, + ); + const identity = { + label: '//fixture:mandatory_test', + configuration: { id: configuration }, + }; + const testEvents = [ + { id: { targetCompleted: identity }, completed: { success: true } }, + { + id: { testResult: { ...identity, run: 1, shard: 1, attempt: 1 } }, + testResult: { status: 'PASSED', cachedLocally: true }, + }, + { + id: { testSummary: identity }, + testSummary: { overallStatus: 'PASSED', totalRunCount: 1, totalNumCached: 1 }, + }, + ]; + const qualification = { + configurations: [{ id: 1, checksum: configuration }], + results: [ + { + configurationId: 1, + target: { + rule: { + name: '@@//fixture:mandatory_test', + ruleClass: '_installed_test', + attribute: [{ name: 'tags', stringListValue: ['manual'] }], + }, + }, + }, + ], + }; + writeFileSync( + stateFile, + JSON.stringify({ + mode, + executionRoot, + output: path.join(executionRoot, output), + root, + manifest: path.join(executionRoot, manifest), + aquery, + events, + testEvents, + qualification, + recipeGraph: { + configurations: [{ id: 1, checksum: configuration }], + results: [ + { + configurationId: 1, + target: { + rule: { + name: root.label, + configuredRuleInput: [{ label: '@@registry//:LICENSE (Apache)' }], + }, + }, + }, + { + configuration: { checksum: 'null' }, + target: { sourceFile: { name: '@@registry//:LICENSE (Apache)' } }, + }, + ], + }, + policy, + policyFile: path.join(executionRoot, policyFile), + }), + ); + const request: NativeShippingRequest = { + github: { + repository: 'f0rr0/oliphaunt', + workflow: 'Native Bazel qualification', + workflowPath: '.github/workflows/bazel.yml', + runId: 123, + runAttempt: 1, + job: 'Linux runtime (x86_64)', + }, + configuration: [ + '--config=wasix-aot', + '--platforms=//fixture:platform', + '--test_env=VALUE=two words', + '--jobs=1', + ], + shipping: { roots: [root.label] }, + targets: ['//fixture:consumer'], + outputDirectory, + }; + return { + workspace, + request, + outputDirectory, + calls: () => + existsSync(callsFile) + ? readFileSync(callsFile, 'utf8') + .trim() + .split('\n') + .map((line) => JSON.parse(line) as string[]) + : [], + update: (change: (state: any) => void) => { + const state = JSON.parse(readFileSync(stateFile, 'utf8')); + change(state); + writeFileSync(stateFile, JSON.stringify(state)); + }, + countsFile, + cleanup: () => rmSync(directory, { recursive: true, force: true }), + }; +} + +test('Mac capture CPU timing preserves evidence, collector failures and source freeze', async () => { + const platform = process.platform; + const originalSpawn = childProcess.spawn; + const captures: string[][] = []; + const calls = spyOn(childProcess, 'spawn').mockImplementation((( + command: string, + args: string[], + options: any, + ) => { + if (command === '/usr/bin/time') captures.push(args); + return originalSpawn(command, args, options); + }) as typeof childProcess.spawn); + try { + Object.defineProperty(process, 'platform', { value: 'darwin' }); + for (const mode of ['success', 'manifest-tamper', 'capture-race']) { + const f = fixture(mode); + const listeners = ['SIGINT', 'SIGTERM'].map((signal) => process.listenerCount(signal)); + try { + if (mode === 'success') { + const output = await qualifyNativeShipping(f.request, f.workspace); + const evidence = JSON.parse(readFileSync(output, 'utf8')); + expect(evidence.github).toEqual(f.request.github); + expect(evidence.cohorts[0].roots[0].label).toBe('//fixture:shipping'); + expect(JSON.stringify(evidence)).not.toContain('--cpu-prof'); + } else { + await expect(qualifyNativeShipping(f.request, f.workspace)).rejects.toThrow( + mode === 'manifest-tamper' ? /failed/u : /clean checkout/u, + ); + expect( + existsSync(path.join(f.outputDirectory, 'evidence/native-build-evidence.json')), + ).toBe(false); + } + const command = captures.at(-1); + expect(command?.slice(0, 6)).toEqual([ + '-p', + 'bash', + 'tools/release/with-source.sh', + 'HEAD', + 'bash', + 'tools/dev/bun.sh', + ]); + expect(command?.[6]).toBe('tools/release/capture-native-build-evidence.mts'); + expect(command?.some((argument) => argument.startsWith('--cpu-prof'))).toBe(false); + expect(existsSync(path.join(f.outputDirectory, 'diagnostics/capture.cpuprofile'))).toBe( + false, + ); + expect( + f + .calls() + .flat() + .some((argument) => argument.startsWith('--cpu-prof')), + ).toBe(false); + } finally { + f.cleanup(); + expect(['SIGINT', 'SIGTERM'].map((signal) => process.listenerCount(signal))).toEqual( + listeners, + ); + } + } + expect(captures).toHaveLength(3); + } finally { + Object.defineProperty(process, 'platform', { value: platform }); + calls.mockRestore(); + } +}); + +for (const { signal, exit, phase } of [ + ...(['SIGINT', 'SIGTERM'] as const).flatMap((signal) => + ['zero', 'failure'].map((exit) => ({ signal, exit, phase: 'build' })), + ), + { signal: 'SIGTERM' as const, exit: 'zero', phase: 'capture' }, +]) + test.skipIf(process.platform === 'win32')( + `qualification ${signal} releases its owned ${phase} before rejecting (${exit} child exit)`, + async () => { + const f = fixture(phase === 'capture' ? 'capture-interrupt' : `build-interrupt-${exit}`); + const directory = path.dirname(f.workspace); + const lock = path.join(directory, 'command.lock'); + const ready = path.join(directory, 'command.pid'); + const events = path.join(directory, 'command-events.txt'); + const listeners = path.join(directory, 'listeners.json'); + f.update((state) => { + state.commandLock = lock; + state.commandReady = ready; + state.commandEvents = events; + }); + f.request.ci = { id: 'fixture/cancel', job: 'fixture', mode: 'full', requires: [] }; + const entry = path.join(directory, 'interrupt-qualification.mts'); + writeFileSync( + entry, + `import {appendFileSync,writeFileSync} from 'node:fs'; +import {qualifyNativeShipping} from ${JSON.stringify(fileURLToPath(new URL('./qualify-native-shipping.mts', import.meta.url)))}; +const before=['SIGINT','SIGTERM'].map(signal=>process.listenerCount(signal)); +try {await qualifyNativeShipping(${JSON.stringify(f.request)},${JSON.stringify(f.workspace)});} +catch(error) {console.error(error.message);process.exitCode=1;} +finally { + writeFileSync(${JSON.stringify(listeners)},JSON.stringify({before,after:['SIGINT','SIGTERM'].map(signal=>process.listenerCount(signal))})); + appendFileSync(${JSON.stringify(events)},'settled\\n'); +} +`, + ); + const sentinel = childProcess.spawn( + process.execPath, + ['--no-install', '--no-env-file', '-e', 'setInterval(()=>{},1000)'], + { stdio: 'ignore' }, + ); + const child = childProcess.spawn(process.execPath, ['--no-install', '--no-env-file', entry], { + stdio: ['ignore', 'ignore', 'pipe'], + }); + let stderr = ''; + child.stderr!.on('data', (data) => { + stderr += data; + }); + const closed = new Promise((resolve, reject) => { + child.once('error', reject); + child.once('close', resolve); + }); + const stopOwnedFixture = () => { + if (existsSync(ready)) { + try { + process.kill(Number(readFileSync(ready, 'utf8')), 'SIGKILL'); + } catch {} + } + child.kill('SIGKILL'); + }; + const watchdog = setTimeout(stopOwnedFixture, 5000); + try { + const deadline = Date.now() + 4000; + while (!existsSync(ready) && Date.now() < deadline) await Bun.sleep(10); + expect(existsSync(ready)).toBe(true); + expect(child.kill(signal)).toBe(true); + await Bun.sleep(10); + child.kill(signal === 'SIGINT' ? 'SIGTERM' : 'SIGINT'); + expect(await closed).toBe(1); + expect(stderr).toContain(`interrupted (${signal})`); + const observed = readFileSync(events, 'utf8').trim().split('\n'); + expect(phase === 'capture' ? observed.sort() : observed).toEqual( + phase === 'capture' ? ['SIGTERM', 'closed', 'settled'] : ['SIGINT', 'closed', 'settled'], + ); + expect(existsSync(lock)).toBe(false); + expect(() => process.kill(Number(readFileSync(ready, 'utf8')), 0)).toThrow(); + expect(process.kill(sentinel.pid!, 0)).toBe(true); + const counts = JSON.parse(readFileSync(listeners, 'utf8')); + expect(counts.after).toEqual(counts.before); + expect(f.calls().map((call) => call[0])).toEqual( + phase === 'capture' ? ['test', 'aquery', 'info', 'cquery', 'query'] : ['test'], + ); + if (phase === 'build') + expect(existsSync(path.join(f.outputDirectory, 'aquery.json'))).toBe(false); + for (const name of ['ci-request.json', 'evidence']) + expect(existsSync(path.join(f.outputDirectory, name))).toBe(false); + expect( + execFileSync('bash', ['tools/dev/bazel.sh', 'info', 'execution_root'], { + cwd: f.workspace, + encoding: 'utf8', + }).trim(), + ).toContain('execroot/_main'); + } finally { + clearTimeout(watchdog); + stopOwnedFixture(); + sentinel.kill('SIGTERM'); + await closed.catch(() => {}); + f.cleanup(); + } + }, + ); + +for (const selection of ['explicit', 'export']) + test(`qualifies ${selection} roots with one request and the real evidence collector`, async () => { + const f = fixture(); + try { + if (selection === 'export') f.request.shipping = { export: '//fixture:shipping_export' }; + const output = await qualifyNativeShipping(f.request, f.workspace); + const evidence = JSON.parse(readFileSync(output, 'utf8')); + expect(evidence.cohorts[0].roots[0].label).toBe('//fixture:shipping'); + expect(evidence.github).toEqual(f.request.github); + const calls = f.calls(); + const builds = calls.filter((call) => call[0] === 'test'); + expect(builds).toHaveLength(1); + expect(builds[0]).toContain( + `--profile=${path.join(f.outputDirectory, 'diagnostics/build-profile.json.gz')}`, + ); + expect(builds[0]).toContain('//fixture:shipping'); + expect(builds[0]).toContain('//fixture:consumer'); + expect(builds[0]).toContain( + '--output_groups=+shipping_manifest,+shipping_policy,+observation_inputs', + ); + expect(builds[0].some((flag) => flag.startsWith('--experimental_aquery_dump_'))).toBe(false); + const queries = calls.filter((call) => call[0] === 'aquery'); + expect(queries).toHaveLength(1); + expect(queries[0]).toContain( + `--profile=${path.join(f.outputDirectory, 'diagnostics/aquery-profile.json.gz')}`, + ); + expect(queries[0]).toContain('--include_pruned_inputs=true'); + expect(queries[0]).toContain('--include_artifacts=true'); + expect(queries[0]).toContain('--include_aspects=true'); + expect(queries[0]).toContain('--include_commandline=false'); + expect(queries[0]).toContain('--output=jsonproto'); + expect(queries[0]).toContain(`--output_file=${path.join(f.outputDirectory, 'aquery.json')}`); + expect(queries[0][1]).toBe( + nativeAqueryExpression(builds[0].filter((arg) => arg.startsWith('//'))), + ); + expect(calls.map((call) => call[0])).toEqual( + selection === 'export' + ? ['cquery', 'cquery', 'test', 'aquery', 'info', 'cquery', 'query'] + : ['test', 'aquery', 'info', 'cquery', 'query'], + ); + expect( + calls.filter((call) => call[0] === 'cquery' && call[1].startsWith('--query_file=')), + ).toHaveLength(1); + expect(calls.filter((call) => call[0] === 'query')).toHaveLength(1); + for (const call of calls.filter((call) => call[0] !== 'query')) + for (const flag of f.request.configuration) expect(call).toContain(flag); + expect(calls.find((call) => call[0] === 'query')).not.toContain( + '--platforms=//fixture:platform', + ); + expect(evidence.cohorts[0].rootAnalysisInputPaths).toEqual([ + { + label: '//fixture:shipping', + paths: ['fixture/BUILD.bazel', 'fixture/macro1.bzl', 'fixture/macro2.bzl'], + }, + ]); + expect(evidence.cohorts[0].analysisInputs[0].members[0].sha256).toBe( + createHash('sha256').update('declared shipping recipe').digest('hex'), + ); + expect(existsSync(path.join(f.outputDirectory, 'build-events.jsonl'))).toBe(true); + expect(existsSync(path.join(f.outputDirectory, 'cquery.json'))).toBe(false); + expect(existsSync(path.join(f.outputDirectory, 'roots.jsonl'))).toBe(false); + expect(existsSync(path.join(f.outputDirectory, 'aquery.json'))).toBe(true); + expect(evidence.cohorts[0].producerCapture.aqueryFile).toBe( + path.join(f.outputDirectory, 'aquery.json'), + ); + const transferred = path.join( + f.outputDirectory, + 'evidence/files/0', + evidence.cohorts[0].outputs[0].path, + ); + expect(readFileSync(transferred)).toEqual(Buffer.from('final archive')); + expect(existsSync(path.join(f.outputDirectory, 'evidence/files/0/src/input.mts'))).toBe( + false, + ); + } finally { + f.cleanup(); + } + }); + +test('scoped action capture binds full requested scope, output, source and configured identity', async () => { + const f = fixture(); + try { + f.request.shipping = { export: '//fixture:shipping_export' }; + f.request.targets = ['//fixture:consumer', '//fixture:consumer', '//fixture:mandatory_test']; + const output = await qualifyNativeShipping(f.request, f.workspace); + const evidence = JSON.parse(readFileSync(output, 'utf8')); + const build = f.calls().find((call) => call[0] === 'test'); + expect(JSON.stringify(evidence)).not.toContain('not-for-retention'); + expect(JSON.stringify(evidence)).not.toContain('private-query-diagnostic'); + expect(build?.filter((arg) => arg === '//fixture:consumer')).toHaveLength(1); + expect(build?.filter((arg) => arg === '//fixture:mandatory_test')).toHaveLength(1); + const queryEvents = (packet: any) => packet.cohorts[0].producerCapture.aqueryBuildEvents; + const command = (packet: any) => + queryEvents(packet).find((event: any) => event.structuredCommandLine)?.structuredCommandLine; + const option = (packet: any, name: string) => + command(packet) + .sections.flatMap((section: any) => section.optionList?.option ?? []) + .find((option: any) => option.optionName === name); + const checks = { + source: evidence.source, + github: evidence.github, + bazelVersion: '8.8.1', + requireShippingAnalysis: true, + }; + expect(validateNativeBuildEvidence(evidence, checks).shippingAnalysis).toBe('bound'); + expect(option(evidence, 'include_commandline').optionValue).toBe('false'); + expect(option(evidence, 'include_artifacts').optionValue).toBe('true'); + expect(option(evidence, 'include_pruned_inputs').optionValue).toBe('true'); + for (const mutate of [ + (packet: any) => { + delete packet.cohorts[0].producerCapture.aqueryBuildEvents; + }, + (packet: any) => { + queryEvents(packet).at(-1).lastMessage = false; + }, + (packet: any) => { + queryEvents(packet).find((event: any) => event.started).started.uuid = 'fixture-build'; + }, + (packet: any) => { + queryEvents(packet).find((event: any) => event.workspaceInfo).workspaceInfo.localExecRoot += + '-other'; + }, + (packet: any) => { + queryEvents(packet).find( + (event: any) => event.buildMetadata, + ).buildMetadata.metadata.oliphaunt_source_commit = 'd'.repeat(40); + }, + (packet: any) => { + queryEvents(packet).find( + (event: any) => event.buildMetadata, + ).buildMetadata.metadata.oliphaunt_run_attempt = '99'; + }, + (packet: any) => { + queryEvents(packet).find((event: any) => event.id?.configuration).id.configuration.id = + 'd'.repeat(64); + }, + (packet: any) => { + command(packet).sections.find( + (section: any) => section.sectionLabel === 'command', + ).chunkList.chunk = ['build']; + }, + (packet: any) => { + command(packet).sections.find( + (section: any) => section.sectionLabel === 'residual', + ).chunkList.chunk = [nativeAqueryExpression(['//fixture:shipping'])]; + }, + (packet: any) => { + option(packet, 'output_file').optionValue += '.other'; + }, + (packet: any) => { + option(packet, 'include_pruned_inputs').optionValue = 'false'; + }, + (packet: any) => { + option(packet, 'include_commandline').optionValue = 'true'; + }, + (packet: any) => { + option(packet, 'include_artifacts').optionValue = 'false'; + }, + (packet: any) => { + option(packet, 'include_aspects').optionValue = 'false'; + }, + ]) { + const tampered = structuredClone(evidence); + mutate(tampered); + expect(() => validateNativeBuildEvidence(tampered, checks)).toThrow(); + } + } finally { + f.cleanup(); + } +}); + +test('SDK phases preserve one canonical qualification with the same roots, base and configuration', async () => { + for (const sourceOnly of [false, true]) { + for (const sliceGroups of [[], ['apple_slice_macos-arm64', 'apple_slice_ios-arm64']]) { + const f = fixture(); + try { + f.request.shipping = { export: '//fixture:shipping_export' }; + f.request.startup = ['--output_base=/same-bazel-server']; + f.update((state) => { + state.sliceGroups = sliceGroups; + }); + if (sourceOnly) + f.request.ci = { + id: 'portable/macos/apple', + job: 'portable/macos', + mode: 'source', + requires: [], + }; + const output = await qualifyNativeShipping(f.request, f.workspace); + expect(existsSync(output)).toBe(true); + const calls = f.calls().map((call) => call.slice(1)); + const batches = calls.filter((call) => call[0] === 'build'); + expect(batches).toHaveLength(sliceGroups.length); + expect(f.calls().every((call) => call[0] === '--output_base=/same-bazel-server')).toBe( + true, + ); + const producing = calls.filter((call) => call[0] === 'test'); + expect(producing).toHaveLength(1); + expect(producing[0].filter((arg) => arg.startsWith('//'))).toEqual([ + '//fixture:shipping', + '//fixture:shipping_export', + '//fixture:mandatory_test', + '//fixture:consumer', + ]); + for (const flag of f.request.configuration) expect(producing[0]).toContain(flag); + expect(producing[0]).not.toContain('--run_validations=false'); + for (const [index, group] of [...sliceGroups].sort().entries()) { + const profile = path.join(f.outputDirectory, 'diagnostics', `${group}-profile.json.gz`); + expect(batches[index]).toEqual([ + 'build', + '//fixture:shipping', + ...f.request.configuration, + ...producing[0].filter((arg) => arg.startsWith('--build_metadata=')), + `--output_groups=${group}`, + '--run_validations=false', + `--profile=${profile}`, + ]); + expect(readFileSync(profile, 'utf8')).toBe('fixture profile'); + expect(calls.indexOf(batches[index])).toBeLessThan(calls.indexOf(producing[0])); + } + expect(calls.filter((call) => call[0] === 'aquery')).toHaveLength(sourceOnly ? 0 : 1); + if (!sourceOnly) { + const query = calls.find((call) => call[0] === 'aquery')!; + expect(query[1]).toBe( + nativeAqueryExpression(producing[0].filter((arg) => arg.startsWith('//'))), + ); + expect(calls.indexOf(query)).toBeGreaterThan(calls.indexOf(producing[0])); + } + } finally { + f.cleanup(); + } + } + } +}); + +for (const failure of ['slice-failure', 'slice-race']) + test(`SDK phases never qualify or capture after ${failure}`, async () => { + for (const sourceOnly of [false, true]) { + const f = fixture(failure); + try { + f.request.shipping = { export: '//fixture:shipping_export' }; + if (sourceOnly) + f.request.ci = { + id: 'portable/macos/apple', + job: 'portable/macos', + mode: 'source', + requires: [], + }; + f.update((state) => { + state.sliceGroups = ['apple_slice_macos-arm64', 'apple_slice_ios-arm64']; + state.interruptedSliceGroup = 'apple_slice_macos-arm64'; + }); + await expect(qualifyNativeShipping(f.request, f.workspace)).rejects.toThrow( + failure === 'slice-failure' ? /failed/u : /clean checkout/u, + ); + expect(f.calls().map((call) => call[0])).toEqual([ + 'cquery', + ...(sourceOnly ? [] : ['cquery']), + 'build', + 'build', + ]); + for (const file of ['ci-request.json', 'aquery.json', 'evidence']) + expect(existsSync(path.join(f.outputDirectory, file))).toBe(false); + } finally { + f.cleanup(); + } + } + }); + +test('SDK phase discovery rejects duplicate or noncanonical output groups before construction', async () => { + for (const sliceGroups of [ + ['apple_slice_ios-arm64', 'apple_slice_ios-arm64'], + ['apple_slice_ios-arm64,+default'], + ['apple_slice_'], + ]) { + const f = fixture(); + try { + f.request.shipping = { export: '//fixture:shipping_export' }; + f.update((state) => { + state.sliceGroups = sliceGroups; + }); + await expect(qualifyNativeShipping(f.request, f.workspace)).rejects.toThrow( + 'Apple slice output groups must be unique SDK identifiers', + ); + expect(f.calls().map((call) => call[0])).toEqual(['cquery']); + } finally { + f.cleanup(); + } + } +}); + +test('configured supplier declarations are checked before constructing shipping products', async () => { + const supplier = { + product: 'liboliphaunt-wasix', + version: '0.3.3', + configuration: 'portable', + binding: 'compiled-input', + origin: { + kind: 'current-source', + producer: { + evidenceDigest: `sha256:${'7'.repeat(64)}`, + invocationId: 'original-wasix-invocation', + root: '//src/wasix/runtime/crates/assets:shipping_package', + configuration: '9'.repeat(64), + output: 'bazel-out/original/bin/liboliphaunt-wasix-portable-0.3.3.crate', + }, + }, + files: [{ path: 'external/current/liboliphaunt-wasix-portable-0.3.3.crate' }], + }; + for (const malformed of [false, true]) { + const f = fixture(); + try { + f.request.shipping = { export: '//fixture:shipping_export' }; + const declared = [{ ...supplier, binding: malformed ? 'untyped' : supplier.binding }]; + f.update((state) => { + state.root.package.supplierInputs = declared; + state.sliceGroups = malformed ? ['apple_slice_ios-arm64'] : []; + }); + if (malformed) { + await expect(qualifyNativeShipping(f.request, f.workspace)).rejects.toThrow( + 'native supplier has invalid binding', + ); + expect(f.calls().map((call) => call[0])).toEqual(['cquery']); + } else { + f.request.ci = { + id: 'portable/linux/napi', + job: 'portable/linux', + mode: 'source', + requires: [], + }; + const output = await qualifyNativeShipping(f.request, f.workspace); + expect(JSON.parse(readFileSync(output, 'utf8')).mode).toBe('source'); + expect(f.calls().map((call) => call[0])).toEqual(['cquery', 'test']); + } + const discovery = f.calls()[0].find((arg) => arg.startsWith('--starlark:expr='))!; + expect(discovery).toContain('//build_defs/release:shipping.bzl%ShippingInfo'); + expect(discovery).toContain('.supplier_inputs'); + expect( + JSON.parse(readFileSync(path.join(f.outputDirectory, 'selected-owner.json'), 'utf8')) + .suppliers, + ).toEqual([declared]); + } finally { + f.cleanup(); + } + } +}); + +test('ordinary shipping checks run once and keep existing policy discovery without publication export', async () => { + for (const owner of [false, true]) { + const f = fixture(); + try { + if (owner) f.request.shipping = { export: '//fixture:shipping_export' }; + f.request.ci = { + id: 'portable/linux/napi', + job: 'portable/linux', + mode: 'source', + requires: [], + }; + const output = await qualifyNativeShipping(f.request, f.workspace); + const receipt = JSON.parse(readFileSync(output, 'utf8')); + expect(receipt.mode).toBe('source'); + expect(receipt.projection).toBeUndefined(); + expect(f.calls().map((call) => call[0])).toEqual(owner ? ['cquery', 'test'] : ['test']); + expect(f.calls().find((call) => call[0] === 'test')).toContain('//fixture:consumer'); + if (owner) + expect(f.calls().find((call) => call[0] === 'test')).toContain('//fixture:mandatory_test'); + expect(existsSync(path.join(f.outputDirectory, 'aquery.json'))).toBe(false); + expect(existsSync(path.join(f.outputDirectory, 'evidence'))).toBe(false); + expect( + f + .calls() + .find((call) => call[0] === 'test')! + .some((flag) => flag.startsWith('--output_groups=')), + ).toBe(false); + } finally { + f.cleanup(); + } + } +}); + +test('source requests preserve physical handoff capture and never receipt a failed producer', async () => { + for (const failed of [false, true]) { + const f = fixture(failed ? 'build-failure' : 'success'); + try { + f.request.ci = { + id: 'wasix/producer', + job: 'wasix', + mode: 'source', + requires: [], + handoff: true, + }; + if (failed) { + await expect(qualifyNativeShipping(f.request, f.workspace)).rejects.toThrow(); + expect(existsSync(path.join(f.outputDirectory, 'ci-request.json'))).toBe(false); + } else { + const output = await qualifyNativeShipping(f.request, f.workspace); + expect(JSON.parse(readFileSync(output, 'utf8')).schema).toBe( + 'oliphaunt-native-build-evidence-v1', + ); + expect( + JSON.parse(readFileSync(path.join(f.outputDirectory, 'ci-request.json'), 'utf8')).mode, + ).toBe('source'); + expect(f.calls().map((call) => call[0])).toEqual([ + 'test', + 'aquery', + 'info', + 'cquery', + 'query', + ]); + } + } finally { + f.cleanup(); + } + } +}); + +test('ordinary source receipt guard rejects a tracked source mutation during the producer', async () => { + const f = fixture('build-race'); + try { + f.request.ci = { + id: 'portable/linux/napi', + job: 'portable/linux', + mode: 'source', + requires: [], + }; + await expect(qualifyNativeShipping(f.request, f.workspace)).rejects.toThrow(); + expect(f.calls().map((call) => call[0])).toEqual(['test']); + expect(existsSync(path.join(f.outputDirectory, 'ci-request.json'))).toBe(false); + } finally { + f.cleanup(); + } +}); + +test('large configured graphs keep query expressions out of OS-limited argv', async () => { + const f = fixture(); + try { + f.update((state) => { + for (let i = 0; i < 1500; i++) { + const name = `@@registry//:${i}-${'x'.repeat(100)}`; + state.recipeGraph.results[0].target.rule.configuredRuleInput.push({ label: name }); + state.recipeGraph.results.push({ target: { sourceFile: { name } } }); + } + const representative = `//fixture:a-${'x'.repeat(130 * 1024)}`; + state.recipeGraph.results[0].target.rule.configuredRuleInput.push({ label: representative }); + state.recipeGraph.results.push({ target: { sourceFile: { name: representative } } }); + }); + await qualifyNativeShipping(f.request, f.workspace); + const query = readFileSync(path.join(f.outputDirectory, 'analysis-buildfiles-0.query'), 'utf8'); + expect(Buffer.byteLength(query)).toBeGreaterThan(128 * 1024); + expect(query).toStartWith('buildfiles(set("//fixture:a-'); + expect(readFileSync(path.join(f.outputDirectory, 'analysis-deps.json')).length).toBeGreaterThan( + 128 * 1024, + ); + const calls = f.calls(); + expect(calls.find((call) => call[0] === 'query')?.[1]).toBe( + `--query_file=${path.join(f.outputDirectory, 'analysis-buildfiles-0.query')}`, + ); + expect(calls.every((call) => call.every((arg) => Buffer.byteLength(arg) < 128 * 1024))).toBe( + true, + ); + } finally { + f.cleanup(); + } +}); + +for (const targets of [[], undefined]) + test(`source-owned manual tests remain mandatory with ${targets ? 'empty' : 'omitted'} caller targets`, async () => { + const f = fixture(); + try { + f.request.shipping = { export: '//fixture:shipping_export' }; + f.request.targets = targets; + const output = await qualifyNativeShipping(f.request, f.workspace); + const evidence = JSON.parse(readFileSync(output, 'utf8')); + const requiredTests = [{ label: '//fixture:mandatory_test', configuration: 'c'.repeat(64) }]; + const result = validateNativeBuildEvidence(evidence, { + source: evidence.source, + github: f.request.github, + bazelVersion: '8.8.1', + requiredTests, + requireShippingAnalysis: true, + }); + expect(result.testQualification).toBe('passed'); + expect(result.qualificationPolicy).toBe('bound'); + expect(result.requiredTests).toEqual([ + { ...requiredTests[0], invocationId: 'fixture-build' }, + ]); + const calls = f.calls(); + expect(calls[1]).toContain('set(//fixture:mandatory_test)'); + expect(calls[1]).toContain('--universe_scope=//fixture:shipping_export'); + expect(calls[1]).toContain('--output=jsonproto'); + expect(calls.find((call) => call[0] === 'test')).toContain('//fixture:mandatory_test'); + expect(calls.find((call) => call[0] === 'test')).toContain('//fixture:shipping_export'); + const events = readFileSync(path.join(f.outputDirectory, 'build-events.jsonl'), 'utf8') + .trim() + .split('\n') + .map((line) => JSON.parse(line)); + expect(events.find((event: any) => event.testResult)?.testResult.cachedLocally).toBe(true); + } finally { + f.cleanup(); + } + }); + +test('one exact serialized qualification replaces the raw and parent replay without trusting a cached view', async () => { + const f = fixture('capture-count'); + const parentViews = spyOn(shippingInputs, 'buildShippingInputView'); + try { + f.request.shipping = { export: '//fixture:shipping_export' }; + f.request.targets = []; + const output = await qualifyNativeShipping(f.request, f.workspace); + const evidence = JSON.parse(readFileSync(output, 'utf8')); + expect(JSON.parse(readFileSync(f.countsFile, 'utf8')).views).toBe(2); + expect(parentViews.mock.calls).toHaveLength(0); + expect( + JSON.parse(readFileSync(path.join(f.outputDirectory, 'expected-qualification.json'), 'utf8')), + ).toEqual({ + source: evidence.source, + github: f.request.github, + bazelVersion: '8.8.1', + requiredTests: [{ label: '//fixture:mandatory_test', configuration: 'c'.repeat(64) }], + requireShippingAnalysis: true, + }); + expect( + evidence.cohorts[0].buildEvents.find((event: any) => event.testSummary).testSummary + .overallStatus, + ).toBe('PASSED'); + expect( + readFileSync( + path.join(f.outputDirectory, 'evidence/files/0', evidence.cohorts[0].outputs[0].path), + ), + ).toEqual(Buffer.from('final archive')); + } finally { + parentViews.mockRestore(); + f.cleanup(); + } +}); + +test('the existing CLI accepts omitted additional targets and still runs owner policy', () => { + const f = fixture(); + try { + const input = path.dirname(f.outputDirectory); + const github = path.join(input, 'github.json'); + const configuration = path.join(input, 'configuration.json'); + writeFileSync(github, JSON.stringify(f.request.github)); + writeFileSync(configuration, JSON.stringify(f.request.configuration)); + execFileSync( + process.execPath, + [ + fileURLToPath(new URL('./qualify-native-shipping.mts', import.meta.url)), + '--github-json', + github, + '--configuration-json', + configuration, + '--shipping-export', + '//fixture:shipping_export', + '--output-directory', + f.outputDirectory, + ], + { cwd: f.workspace, stdio: 'pipe' }, + ); + expect(f.calls().find((call) => call[0] === 'test')).toContain('//fixture:mandatory_test'); + expect(existsSync(path.join(f.outputDirectory, 'evidence/native-build-evidence.json'))).toBe( + true, + ); + } finally { + f.cleanup(); + } +}); + +for (const failure of [ + 'missing-summary', + 'failed-result', + 'configuration-mismatch', + 'raw-metadata-mismatch', +]) + test(`removes evidence when source-owned configured qualification has ${failure}`, async () => { + const f = fixture(); + try { + f.request.shipping = { export: '//fixture:shipping_export' }; + f.request.targets = []; + f.update((state) => { + if (failure === 'missing-summary') + state.testEvents = state.testEvents.filter((event: any) => !event.testSummary); + else if (failure === 'failed-result') + state.testEvents.find((event: any) => event.testResult).testResult.status = 'FAILED'; + else if (failure === 'configuration-mismatch') + state.qualification.configurations[0].checksum = 'd'.repeat(64); + else state.mode = failure; + }); + await expect(qualifyNativeShipping(f.request, f.workspace)).rejects.toThrow( + /with-source.sh failed/, + ); + expect(existsSync(path.join(f.outputDirectory, 'evidence/native-build-evidence.json'))).toBe( + false, + ); + expect(existsSync(path.join(f.outputDirectory, 'evidence/files'))).toBe(false); + expect(existsSync(path.join(f.outputDirectory, 'build-events.jsonl'))).toBe(true); + } finally { + f.cleanup(); + } + }); + +for (const ruleClass of ['filegroup', 'test_suite']) + test(`rejects ${ruleClass} policy nodes before construction`, async () => { + const f = fixture(); + try { + f.request.shipping = { export: '//fixture:shipping_export' }; + f.update((state) => { + state.qualification.results[0].target.rule.ruleClass = ruleClass; + }); + await expect(qualifyNativeShipping(f.request, f.workspace)).rejects.toThrow( + 'configured actual test rules', + ); + expect(f.calls().map((call) => call[0])).toEqual(['cquery', 'cquery']); + } finally { + f.cleanup(); + } + }); + +for (const mode of ['incompatible-owner', 'malformed-owner']) + test(`diagnoses ${mode} configured export output without construction`, async () => { + const f = fixture(mode); + try { + f.request.shipping = { export: '//fixture:shipping_export' }; + await expect(qualifyNativeShipping(f.request, f.workspace)).rejects.toThrow( + mode === 'incompatible-owner' + ? 'Bazel configuration analysis failed' + : 'readable configured export provider', + ); + const calls = f.calls(); + expect(calls.map((call) => call[0])).toEqual(['cquery', 'build']); + expect(calls[1].at(-1)).toBe('--nobuild'); + expect(calls[1]).toContain('//fixture:shipping_export'); + expect(calls[1].slice(2, -1)).toEqual(f.request.configuration ?? []); + expect(existsSync(path.join(f.outputDirectory, 'build-events.jsonl'))).toBe(false); + expect(existsSync(path.join(f.outputDirectory, 'evidence'))).toBe(false); + } finally { + f.cleanup(); + } + }); + +test('an incompatible declared mandatory test fails policy analysis before construction', async () => { + const f = fixture('incompatible-policy'); + try { + f.request.shipping = { export: '//fixture:shipping_export' }; + await expect(qualifyNativeShipping(f.request, f.workspace)).rejects.toThrow('failed'); + expect(f.calls().map((call) => call[0])).toEqual(['cquery', 'cquery']); + expect(existsSync(path.join(f.outputDirectory, 'evidence/native-build-evidence.json'))).toBe( + false, + ); + } finally { + f.cleanup(); + } +}); + +test('an explicitly empty owner policy retains construction-only compatibility', async () => { + const f = fixture(); + try { + f.request.shipping = { export: '//fixture:shipping_export' }; + delete f.request.targets; + f.update((state) => { + state.qualification = {}; + state.testEvents = []; + }); + const output = await qualifyNativeShipping(f.request, f.workspace); + const evidence = JSON.parse(readFileSync(output, 'utf8')); + const result = validateNativeBuildEvidence(evidence, { + source: evidence.source, + github: f.request.github, + bazelVersion: '8.8.1', + }); + expect(result.testQualification).toBe('unverified'); + expect(result.releaseDecision).toBe('unverified'); + expect(f.calls().find((call) => call[0] === 'test')).not.toContain('//fixture:mandatory_test'); + } finally { + f.cleanup(); + } +}); + +test('complete-family validation rejects bytes changed after successful evidence capture', async () => { + const f = fixture('capture-output-race'); + try { + f.request.completeProducts = ['fixture']; + await expect(qualifyNativeShipping(f.request, f.workspace)).rejects.toThrow( + 'native complete-family output differs from build evidence', + ); + expect(existsSync(path.join(f.outputDirectory, 'evidence/native-build-evidence.json'))).toBe( + false, + ); + expect(existsSync(path.join(f.outputDirectory, 'evidence/files'))).toBe(false); + expect(f.calls().map((call) => call[0])).toEqual(['test', 'aquery', 'info', 'cquery', 'query']); + } finally { + f.cleanup(); + } +}); + +test('caller query substitution is rejected before any process even beyond OS argv limits', async () => { + const f = fixture(); + try { + f.request.configuration.push(`--query_file=${'x'.repeat(130 * 1024)}`); + await expect(qualifyNativeShipping(f.request, f.workspace)).rejects.toThrow('cannot override'); + expect(f.calls()).toEqual([]); + expect(existsSync(f.outputDirectory)).toBe(false); + f.request.configuration.pop(); + f.request.configuration.push('--output_file=/tmp/substituted-query.json'); + await expect(qualifyNativeShipping(f.request, f.workspace)).rejects.toThrow('cannot override'); + expect(f.calls()).toEqual([]); + } finally { + f.cleanup(); + } +}); + +test('rejects dirty source before any Bazel request', async () => { + const f = fixture(); + try { + writeFileSync(path.join(f.workspace, 'src/input.mts'), 'dirty'); + await expect(qualifyNativeShipping(f.request, f.workspace)).rejects.toThrow('clean checkout'); + expect(f.calls()).toEqual([]); + } finally { + f.cleanup(); + } +}); + +for (const flag of ['--assume-unchanged', '--skip-worktree']) + test(`rejects ${flag} when git status hides a modified tracked input`, async () => { + const f = fixture(); + try { + execFileSync('git', ['update-index', flag, 'src/input.mts'], { cwd: f.workspace }); + writeFileSync(path.join(f.workspace, 'src/input.mts'), 'hidden changed source'); + expect( + execFileSync('git', ['status', '--porcelain'], { cwd: f.workspace, encoding: 'utf8' }), + ).toBe(''); + await expect(qualifyNativeShipping(f.request, f.workspace)).rejects.toThrow( + 'index suppression flags', + ); + expect(f.calls()).toEqual([]); + } finally { + f.cleanup(); + } + }); + +test('preserves startup argv before every command and configuration afterward', async () => { + const f = fixture(); + try { + const startup = ['--output_base=/tmp/approved base', '--host_jvm_args=-Xmx2g']; + f.request.startup = startup; + f.request.shipping = { export: '//fixture:shipping_export' }; + await qualifyNativeShipping(f.request, f.workspace); + const calls = f.calls(); + expect(calls.filter((call) => call[2] === 'test')).toHaveLength(1); + for (const call of calls) { + expect(call.slice(0, 2)).toEqual(startup); + expect(['test', 'aquery', 'cquery', 'query', 'info']).toContain(call[2]); + if (call[2] !== 'query') + for (const flag of f.request.configuration) expect(call.indexOf(flag)).toBeGreaterThan(2); + } + } finally { + f.cleanup(); + } +}); + +for (const product of ['unknown-product', 'postgres-tools-wasix']) + test(`removes its packet when canonical complete-family coverage fails for ${product}`, async () => { + const f = fixture(); + try { + f.request.completeProducts = [product]; + await expect(qualifyNativeShipping(f.request, f.workspace)).rejects.toThrow( + product === 'unknown-product' + ? 'unknown selected product' + : 'incomplete native shipping coverage', + ); + expect(f.calls().map((call) => call[0])).toEqual([ + 'test', + 'aquery', + 'info', + 'cquery', + 'query', + ]); + expect(existsSync(path.join(f.outputDirectory, 'evidence/native-build-evidence.json'))).toBe( + false, + ); + expect(existsSync(path.join(f.outputDirectory, 'build-events.jsonl'))).toBe(true); + } finally { + f.cleanup(); + } + }); + +for (const mode of [ + 'build-race', + 'head-race', + 'build-failure', + 'discovery-failure', + 'analysis-failure', + 'deleted-load', + 'capture-race', + 'dump-missing', + 'aquery-failure', + 'aquery-race', + 'manifest-tamper', +]) + test(`does not return evidence after ${mode}`, async () => { + const f = fixture(mode); + try { + if (mode === 'discovery-failure') + f.request.shipping = { export: '//fixture:shipping_export' }; + await expect(qualifyNativeShipping(f.request, f.workspace)).rejects.toThrow(); + expect(existsSync(path.join(f.outputDirectory, 'evidence/native-build-evidence.json'))).toBe( + false, + ); + if (mode.startsWith('build-') || mode === 'head-race') + expect(f.calls().map((call) => call[0])).toEqual(['test']); + } finally { + f.cleanup(); + } + }); + +for (const mode of ['aquery-hang', 'aquery-ignore-term']) + test(`a stalled query (${mode}) is terminated without retry or downstream capture`, async () => { + const f = fixture(mode); + const base = path.join(path.dirname(f.outputDirectory), 'bazel-base'); + const server = path.join(base, 'server'); + mkdirSync(server, { recursive: true }); + writeFileSync(path.join(server, 'server.pid.txt'), String(process.pid)); + const log = path.join(server, 'jvm.out'); + writeFileSync(log, 'historical action diagnostic must stay private\n'); + f.request.startup = [`--output_base=${base}`]; + const execute = childProcess.execFileSync; + const commands = spyOn(childProcess, 'execFileSync').mockImplementation((( + command: string, + args: string[], + options: any, + ) => + command === 'ps' && args[0] === '-p' + ? 'java\n' + : execute(command, args, options)) as typeof execFileSync); + const start = childProcess.spawn; + const terminated: string[] = []; + const children = spyOn(childProcess, 'spawn').mockImplementation(((...args: any[]) => { + const child = start(...(args as Parameters)); + const kill = child.kill; + spyOn(child, 'kill').mockImplementation((kind) => { + terminated.push(String(kind)); + return kill.call(child, kind); + }); + return child; + }) as typeof childProcess.spawn); + const signal = process.kill; + const signals = spyOn(process, 'kill').mockImplementation((pid, kind) => { + if (pid === process.pid && kind === 'SIGQUIT') { + appendFileSync(log, 'new JVM thread snapshot\n'); + return true; + } + return signal(pid, kind); + }); + const schedule = globalThis.setTimeout; + const deadlines: number[] = []; + let escalation: ReturnType | undefined; + const cleared = spyOn(globalThis, 'clearTimeout'); + const timer = spyOn(globalThis, 'setTimeout').mockImplementation((( + callback: (...args: any[]) => void, + delay?: number, + ...args: any[] + ) => { + deadlines.push(delay ?? 0); + const scheduled = schedule( + callback, + delay === 300000 ? 500 : delay === 2000 ? 0 : delay === 5000 ? 100 : delay, + ...args, + ); + if (delay === 5000) escalation = scheduled; + return scheduled; + }) as typeof setTimeout); + try { + await expect(qualifyNativeShipping(f.request, f.workspace)).rejects.toThrow( + 'five-minute limit', + ); + expect(deadlines).toEqual([300000, 2000, 5000]); + expect(cleared).toHaveBeenCalledWith(escalation); + expect(terminated).toEqual( + mode === 'aquery-ignore-term' ? ['SIGTERM', 'SIGKILL'] : ['SIGTERM'], + ); + expect(f.calls().map((call) => call[1])).toEqual(['test', 'aquery']); + expect(signals).toHaveBeenCalledWith(process.pid, 'SIGQUIT'); + expect(readFileSync(path.join(f.outputDirectory, 'diagnostics/aquery-jvm.log'), 'utf8')).toBe( + 'new JVM thread snapshot\n', + ); + expect(readFileSync(path.join(f.outputDirectory, 'aquery.json'), 'utf8')).toBe( + 'partial output', + ); + expect(existsSync(path.join(f.outputDirectory, 'diagnostics/disk.txt'))).toBe(true); + expect(existsSync(path.join(f.outputDirectory, 'diagnostics/processes.txt'))).toBe(true); + expect(existsSync(path.join(f.outputDirectory, 'evidence'))).toBe(false); + } finally { + timer.mockRestore(); + cleared.mockRestore(); + signals.mockRestore(); + commands.mockRestore(); + children.mockRestore(); + f.cleanup(); + } + }); diff --git a/tools/release/query.mts b/tools/release/query.mts index 54ab7f06d..a7bbbd6a9 100644 --- a/tools/release/query.mts +++ b/tools/release/query.mts @@ -1,21 +1,19 @@ #!/usr/bin/env bun import { parseArgs } from 'node:util'; - +import { extensionPublicationMetadataRows } from './extension-release-metadata.mts'; import { ciNpmPackageArtifactRows, ciReleaseAssetArtifactRows, + exactExtensionProducts, extensionArtifactProductRoot, extensionArtifactProductsForReleaseProducts, extensionMemberPath, extensionMetadata, extensionReleaseProduct, - extensionSqlNames, extensionSourceIdentity, - exactExtensionProducts, sdkPackageProducts, } from './release-artifact-targets.mts'; import { compareText, loadProducts, releaseOrder } from './release-graph.mts'; -import { extensionNpmPackageForProduct } from '../../src/extensions/artifacts/packages/tools/extension-registry-packages.mts'; const TOOL = 'release_graph_query.mts'; @@ -200,17 +198,12 @@ function runExtensionMetadata(argv) { printJson( products.flatMap((product) => { const metadata = extensionMetadata(product, TOOL); - return extensionSqlNames(product, TOOL).map((sqlName) => ({ + return extensionPublicationMetadataRows( product, - cargoPackage: product, - npmPackage: extensionNpmPackageForProduct(product), - mavenGroup: 'dev.oliphaunt.extensions', - mavenArtifact: product, - ...metadata, - sqlName, - memberPath: extensionMemberPath(product, sqlName, TOOL), - sourceIdentity: extensionSourceIdentity(product, TOOL), - })); + metadata, + extensionSourceIdentity(product, TOOL), + (sqlName) => extensionMemberPath(product, sqlName, TOOL), + ); }), ); } diff --git a/tools/release/registry-integrity.mts b/tools/release/registry-integrity.mts index b4b1debd8..07c06abac 100644 --- a/tools/release/registry-integrity.mts +++ b/tools/release/registry-integrity.mts @@ -1,8 +1,9 @@ #!/usr/bin/env bun import { createHash } from 'node:crypto'; import { - lstatSync, + promises as fs, linkSync, + lstatSync, mkdirSync, readFileSync, statSync, @@ -11,10 +12,12 @@ import { } from 'node:fs'; import path from 'node:path'; import process from 'node:process'; - -import { createCratesIoReadGate } from './registry-http-retry.mts'; +import { mavenCentralPublicationFiles } from '../packaging/maven-central-contract.mts'; import { loadPublicationLock } from './publication-lock.mts'; -import { ROOT, compareText } from './release-graph.mts'; +import { createCratesIoReadGate } from './registry-http-retry.mts'; +import { compareText, ROOT } from './release-graph.mts'; +import { createRetainedDownload } from './retained-download.mts'; + const CRATES_IO_API = process.env.CRATES_IO_API || 'https://crates.io/api/v1'; const DEFAULT_NPM_REGISTRY = 'https://registry.npmjs.org'; const MAVEN_CENTRAL_BASE = process.env.MAVEN_CENTRAL_BASE || 'https://repo1.maven.org/maven2'; @@ -28,6 +31,7 @@ const MAX_TRANSIENT_RETRY_DELAY_MS = 30_000; const MAX_RATE_LIMIT_RETRY_DELAY_MS = 5 * 60_000; const MAX_RETRY_DELAY_BUDGET_MS = 10 * 60_000; const MAX_METADATA_RESPONSE_BYTES = 8 * 1024 * 1024; +const MAX_RETAINED_ARCHIVE_BYTES = 1024 * 1024 * 1024; const MAX_REGISTRY_RECEIPT_EVIDENCE_BYTES = 64 * 1024 * 1024; export const REGISTRY_RECEIPT_EVIDENCE_SCHEMA = 'oliphaunt-registry-integrity-receipts-v1'; const DEFAULT_CRATES_IO_READ_GATE = createCratesIoReadGate(); @@ -307,45 +311,83 @@ async function requestJson(url, fetchImpl, cratesIoReadGate = null) { ); } -async function responseSha256(response, maximum, context) { +async function responseSha256(response, maximum, context, options = {}) { const declared = declaredResponseLength(response, context); if (declared !== null && declared > maximum) { await response.body?.cancel?.().catch(() => {}); throw new RegistryResponseError(`${context} response exceeds locked size ${maximum}`); } const hash = createHash('sha256'); + const sha512 = options.expectedSha512 === undefined ? null : createHash('sha512'); + let retained = null; + try { + if (options.retainedPath !== undefined) { + retained = await createRetainedDownload(options.retainedPath); + } + } catch (cause) { + await response.body?.cancel?.().catch(() => {}); + throw new RegistryResponseError(cause.message); + } let size = 0; - if (response.body?.getReader !== undefined) { - const reader = response.body.getReader(); - try { - for (;;) { - const { done, value } = await reader.read(); - if (done) break; - const bytes = Buffer.from(value); - size += bytes.length; - if (size > maximum) { - await reader.cancel().catch(() => {}); - throw new RegistryResponseError(`${context} response exceeds locked size ${maximum}`); + try { + if (response.body?.getReader !== undefined) { + const reader = response.body.getReader(); + try { + for (;;) { + const { done, value } = await reader.read(); + if (done) break; + const bytes = Buffer.from(value); + size += bytes.length; + if (size > maximum) { + await reader.cancel().catch(() => {}); + throw new RegistryResponseError(`${context} response exceeds locked size ${maximum}`); + } + hash.update(bytes); + sha512?.update(bytes); + await retained?.write(bytes); } - hash.update(bytes); + } catch (cause) { + await reader.cancel().catch(() => {}); + throw cause; + } finally { + reader.releaseLock(); } - } finally { - reader.releaseLock(); + } else { + const bytes = Buffer.from(await response.arrayBuffer()); + if (bytes.length > maximum) { + throw new RegistryResponseError(`${context} response exceeds locked size ${maximum}`); + } + hash.update(bytes); + sha512?.update(bytes); + await retained?.write(bytes); + size = bytes.length; } - } else { - const bytes = Buffer.from(await response.arrayBuffer()); - if (bytes.length > maximum) { - throw new RegistryResponseError(`${context} response exceeds locked size ${maximum}`); + const proof = { sha256: hash.digest('hex'), size }; + if (options.expectedSize !== undefined && size !== options.expectedSize) { + throw new RegistryResponseError( + `${context} size ${size} does not match expected size ${options.expectedSize}`, + ); + } + if (options.expectedSha256 !== undefined && proof.sha256 !== options.expectedSha256) { + throw new RegistryResponseError(`${context} SHA256 does not match expected digest`); + } + if (sha512 !== null && sha512.digest('base64') !== options.expectedSha512) { + throw new RegistryResponseError(`${context} SHA512 does not match registry integrity`); } - hash.update(bytes); - size = bytes.length; + if (retained !== null) return { ...proof, path: await retained.commit() }; + return proof; + } finally { + await retained?.abort(); } - return { sha256: hash.digest('hex'), size }; } -async function requestSha256(url, fetchImpl, maximum) { - return request(url, 'application/octet-stream', fetchImpl, (response) => - responseSha256(response, maximum, url), +async function requestSha256(url, fetchImpl, maximum, options = {}, cratesIoReadGate = null) { + return request( + url, + 'application/octet-stream', + fetchImpl, + (response) => responseSha256(response, maximum, url, options), + cratesIoReadGate, ); } @@ -355,6 +397,18 @@ function lockedArtifactEnvelope(carrier) { .sort((left, right) => compareText(left.sha256, right.sha256)); } +function carrierReceipt(carrier, registryProof) { + return { + id: carrier.id, + product: carrier.product, + ecosystem: carrier.ecosystem, + name: carrier.name, + version: carrier.version, + lockedArtifacts: lockedArtifactEnvelope(carrier), + registryProof, + }; +} + function expectedCargoReceipt(carrier) { if (carrier.artifacts.length !== 1) { throw error( @@ -364,20 +418,12 @@ function expectedCargoReceipt(carrier) { const file = requireLockedFile(carrier.artifacts[0], '.crate', carrier); const digest = hashFile(file, 'sha256'); const url = `${CRATES_IO_API.replace(/\/+$/u, '')}/crates/${encodeURIComponent(carrier.name)}/${encodeURIComponent(carrier.version)}`; - return { - id: carrier.id, - product: carrier.product, - ecosystem: carrier.ecosystem, - name: carrier.name, - version: carrier.version, - lockedArtifacts: lockedArtifactEnvelope(carrier), - registryProof: { - algorithm: 'sha256', - digest, - source: 'crates.io-version-checksum', - url, - }, - }; + return carrierReceipt(carrier, { + algorithm: 'sha256', + digest, + source: 'crates.io-version-checksum', + url, + }); } async function cargoReceipt(carrier, fetchImpl, cratesIoReadGate) { @@ -401,20 +447,12 @@ function expectedNpmReceipt(carrier) { const file = requireLockedFile(carrier.artifacts[0], '.tgz', carrier); const digest = hashFile(file, 'sha512', 'base64'); const url = `${canonicalNpmRegistry()}/${encodeURIComponent(carrier.name)}/${encodeURIComponent(carrier.version)}`; - return { - id: carrier.id, - product: carrier.product, - ecosystem: carrier.ecosystem, - name: carrier.name, - version: carrier.version, - lockedArtifacts: lockedArtifactEnvelope(carrier), - registryProof: { - algorithm: 'sha512', - digest, - source: 'npm-dist-integrity', - url, - }, - }; + return carrierReceipt(carrier, { + algorithm: 'sha512', + digest, + source: 'npm-dist-integrity', + url, + }); } async function npmReceipt(carrier, fetchImpl) { @@ -481,20 +519,12 @@ function expectedMavenReceipt(carrier) { url, }); } - return { - id: carrier.id, - product: carrier.product, - ecosystem: carrier.ecosystem, - name: carrier.name, - version: carrier.version, - lockedArtifacts: lockedArtifactEnvelope(carrier), - registryProof: { - algorithm: 'sha256', - digest: digestValue(proofs), - files: proofs, - source: 'maven-central-payload-bytes', - }, - }; + return carrierReceipt(carrier, { + algorithm: 'sha256', + digest: digestValue(proofs), + files: proofs, + source: 'maven-central-payload-bytes', + }); } async function mavenReceipt(carrier, fetchImpl) { @@ -511,7 +541,7 @@ async function mavenReceipt(carrier, fetchImpl) { return receipt; } -function expectedLockedCarrierReceipt(carrier, lock) { +function expectedLockedCarrierReceipt(carrier) { if (carrier.ecosystem === 'cargo') return expectedCargoReceipt(carrier); if (carrier.ecosystem === 'npm') return expectedNpmReceipt(carrier); if (carrier.ecosystem === 'maven') return expectedMavenReceipt(carrier); @@ -684,9 +714,7 @@ export function validateLockedRegistryReceipts( const carriers = selectedLockedRegistryCarriers(lock, { products, ecosystems, carrierIds }); const expectedById = receiptMode === 'local' - ? new Map( - carriers.map((carrier) => [carrier.id, expectedLockedCarrierReceipt(carrier, lock)]), - ) + ? new Map(carriers.map((carrier) => [carrier.id, expectedLockedCarrierReceipt(carrier)])) : new Map(carriers.map((carrier) => [carrier.id, carrier])); const observedById = new Map(); for (const receipt of receipts) { @@ -825,13 +853,42 @@ export function validateRegistryReceiptEvidence( return evidence; } -export async function verifyLockedCarrierIntegrity( - lock, - carrierId, - { fetchImpl = fetch, cratesIoReadGate = DEFAULT_CRATES_IO_READ_GATE } = {}, +export async function verifyRegistryCarrierIntegrity( + carrier, + { + fetchImpl = fetch, + cratesIoReadGate = DEFAULT_CRATES_IO_READ_GATE, + cachedReceipt, + cachedReceipts, + } = {}, ) { - const carrier = lock.carriers.find((entry) => entry.id === carrierId); - if (carrier === undefined) throw error(`publication lock has no carrier ${carrierId}`); + if (cachedReceipts !== undefined && !(cachedReceipts instanceof Map)) { + throw error('cachedReceipts must be a Map keyed by exact carrier identity'); + } + if (cachedReceipts?.has(carrier.id)) { + const cached = cachedReceipts.get(carrier.id); + if ( + cached?.id !== carrier.id || + (cachedReceipt !== undefined && stableJson(cachedReceipt) !== stableJson(cached)) + ) { + throw error(`${carrier.id} has conflicting cached registry receipts`); + } + cachedReceipt ??= cached; + } + if (cachedReceipt !== undefined) { + validateSealedLockedCarrierReceipt(cachedReceipt, carrier); + for (const artifact of carrier.artifacts) { + const stat = lstatSync(path.resolve(ROOT, artifact.path)); + if (!stat.isFile() || stat.isSymbolicLink()) { + throw error(`${carrier.id} cached registry bytes must be regular owned files`); + } + } + const expected = expectedLockedCarrierReceipt(carrier); + if (stableJson(cachedReceipt) !== stableJson(expected)) { + throw error(`${carrier.id} cached registry receipt does not match its local bytes`); + } + return cachedReceipt; + } if (carrier.ecosystem === 'cargo') return cargoReceipt(carrier, fetchImpl, cratesIoReadGate); if (carrier.ecosystem === 'npm') return npmReceipt(carrier, fetchImpl); if (carrier.ecosystem === 'maven') return mavenReceipt(carrier, fetchImpl); @@ -840,6 +897,233 @@ export async function verifyLockedCarrierIntegrity( ); } +export async function materializeRegistryCarrierIntegrity( + carrier, + { + directory, + fetchImpl = fetch, + cratesIoReadGate = DEFAULT_CRATES_IO_READ_GATE, + maximumBytes = MAX_RETAINED_ARCHIVE_BYTES, + } = {}, +) { + if (typeof directory !== 'string' || directory.length === 0) { + throw error('registry materialization requires an owned output directory'); + } + if ( + !Number.isSafeInteger(maximumBytes) || + maximumBytes < 1 || + maximumBytes > MAX_RETAINED_ARCHIVE_BYTES + ) { + throw error( + `registry materialization maximumBytes must be from 1 through ${MAX_RETAINED_ARCHIVE_BYTES}`, + ); + } + for (const field of ['id', 'product', 'ecosystem', 'name', 'version']) { + if ( + typeof carrier?.[field] !== 'string' || + carrier[field].length === 0 || + /[\u0000-\u001f\u007f]/u.test(carrier[field]) + ) { + throw error(`registry materialization requires an exact carrier ${field}`); + } + } + if (!SUPPORTED_ECOSYSTEMS.has(carrier.ecosystem)) { + throw error(`${carrier.id} registry materialization does not support ${carrier.ecosystem}`); + } + if ( + !/^[A-Za-z0-9][A-Za-z0-9.+-]*$/u.test(carrier.version) || + (carrier.ecosystem === 'cargo' && !/^[A-Za-z0-9_-]+$/u.test(carrier.name)) || + (carrier.ecosystem === 'npm' && + !/^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/u.test(carrier.name)) + ) { + throw error(`${carrier.id} has an invalid exact registry package name or version`); + } + if ( + !Array.isArray(carrier.artifacts) || + (carrier.artifacts.length === 0 && carrier.ecosystem !== 'maven') + ) { + throw error(`${carrier.id} registry materialization requires explicit artifact names`); + } + const names = new Set(); + for (const artifact of carrier.artifacts) { + const name = typeof artifact.path === 'string' ? path.basename(artifact.path) : ''; + if ( + !name || + name === '.' || + name === '..' || + /[\\:\u0000-\u001f\u007f]/u.test(name) || + names.has(name) + ) { + throw error(`${carrier.id} requires unique safe publication artifact basenames`); + } + names.add(name); + if ( + artifact.size !== undefined && + (!Number.isSafeInteger(artifact.size) || artifact.size < 0 || artifact.size > maximumBytes) + ) { + throw error(`${carrier.id} has an invalid expected artifact size`); + } + if (artifact.sha256 !== undefined && !/^[a-f0-9]{64}$/u.test(artifact.sha256)) { + throw error(`${carrier.id} has an invalid expected artifact SHA256`); + } + } + if (carrier.ecosystem !== 'maven') { + const suffix = carrier.ecosystem === 'cargo' ? '.crate' : '.tgz'; + if (carrier.artifacts.length !== 1 || !carrier.artifacts[0].path.endsWith(suffix)) { + throw error(`${carrier.id} must declare exactly one ${suffix} archive`); + } + } + await fs.mkdir(path.resolve(directory), { recursive: true }); + const ownedDirectory = await fs.mkdtemp(path.join(path.resolve(directory), 'registry-carrier-')); + const artifacts = []; + let metadata = null; + let registryProof; + const capture = async (artifact, url, options = {}, gate = null) => { + const observed = await requestSha256( + url, + fetchImpl, + options.expectedSize ?? artifact.size ?? maximumBytes, + { + expectedSize: artifact.size, + expectedSha256: artifact.sha256, + retainedPath: path.join(ownedDirectory, path.basename(artifact.path)), + ...options, + }, + gate, + ); + artifacts.push({ + ...artifact, + path: observed.path, + size: observed.size, + sha256: observed.sha256, + }); + return observed; + }; + try { + if (carrier.ecosystem === 'cargo') { + const url = `${CRATES_IO_API.replace(/\/+$/u, '')}/crates/${encodeURIComponent(carrier.name)}/${encodeURIComponent(carrier.version)}`; + metadata = await requestJson(url, fetchImpl, cratesIoReadGate); + const version = metadata?.version; + if ( + version?.crate !== carrier.name || + version?.num !== carrier.version || + !/^[a-f0-9]{64}$/u.test(version?.checksum ?? '') + ) { + throw error(`${carrier.id} Cargo metadata changed its exact version identity or checksum`); + } + const artifact = carrier.artifacts[0]; + if (artifact.sha256 !== undefined && artifact.sha256 !== version.checksum) { + throw error(`${carrier.id} registry checksum mismatch`); + } + if ( + version.crate_size !== undefined && + (!Number.isSafeInteger(version.crate_size) || + version.crate_size < 0 || + version.crate_size > maximumBytes || + (artifact.size !== undefined && artifact.size !== version.crate_size)) + ) { + throw error(`${carrier.id} Cargo metadata has an invalid or conflicting archive size`); + } + await capture( + artifact, + `${url}/download`, + { + expectedSha256: version.checksum, + expectedSize: artifact.size ?? version.crate_size, + }, + cratesIoReadGate, + ); + registryProof = { + algorithm: 'sha256', + digest: version.checksum, + source: 'crates.io-version-checksum', + url, + }; + } else if (carrier.ecosystem === 'npm') { + const url = `${canonicalNpmRegistry()}/${encodeURIComponent(carrier.name)}/${encodeURIComponent(carrier.version)}`; + metadata = await requestJson(url, fetchImpl); + if (metadata?.name !== carrier.name || metadata?.version !== carrier.version) { + throw error(`${carrier.id} npm metadata changed its exact package version identity`); + } + const integrity = metadata?.dist?.integrity; + const digests = + typeof integrity === 'string' + ? [ + ...new Set( + integrity + .trim() + .split(/\s+/u) + .filter((token) => token.startsWith('sha512-')) + .map((token) => token.slice(7)), + ), + ] + : []; + if (digests.length !== 1) + throw error(`${carrier.id} npm metadata requires one exact SHA512 integrity`); + assertCanonicalSha512Base64(digests[0], `${carrier.id} npm integrity`); + const basename = carrier.name.split('/').at(-1); + const tarball = `${canonicalNpmRegistry()}/${carrier.name}/-/${basename}-${carrier.version}.tgz`; + if (metadata.dist.tarball !== tarball) { + throw error(`${carrier.id} npm tarball must use its exact canonical package version URL`); + } + await capture(carrier.artifacts[0], tarball, { expectedSha512: digests[0] }); + registryProof = { + algorithm: 'sha512', + digest: digests[0], + source: 'npm-dist-integrity', + url, + }; + } else { + const { artifact: artifactName, base } = mavenCoordinate(carrier); + const files = []; + const remoteNames = new Set(); + const declared = [...carrier.artifacts]; + if (!declared.length) declared.push({ path: `${artifactName}-${carrier.version}.pom` }); + for (const artifact of declared) { + const remoteName = mavenRemoteFilename(carrier, artifact, artifactName); + if (remoteNames.has(remoteName)) + throw error(`${carrier.id} declares duplicate Maven companion ${remoteName}`); + remoteNames.add(remoteName); + const url = `${base}/${encodeURIComponent(remoteName)}`; + const observed = await capture(artifact, url); + files.push({ algorithm: 'sha256', digest: observed.sha256, size: observed.size, url }); + if (!carrier.artifacts.length && remoteName.endsWith('.pom')) { + const publication = mavenCentralPublicationFiles(readFileSync(observed.path, 'utf8')); + if ( + `${publication.groupId}:${publication.artifactId}` !== carrier.name || + publication.version !== carrier.version + ) + throw error(`${carrier.id} historical POM differs from its exact coordinate`); + declared.push( + ...publication.files + .filter((name) => name !== remoteName) + .map((name) => ({ path: name })), + ); + } + } + registryProof = { + algorithm: 'sha256', + digest: digestValue(files), + files, + source: 'maven-central-payload-bytes', + }; + } + const materialized = { ...carrier, artifacts }; + const receipt = carrierReceipt(materialized, registryProof); + validateSealedLockedCarrierReceipt(receipt, materialized); + return { carrier: materialized, receipt, metadata }; + } catch (cause) { + await fs.rm(ownedDirectory, { recursive: true, force: true }); + throw cause; + } +} + +export async function verifyLockedCarrierIntegrity(lock, carrierId, options = {}) { + const carrier = lock.carriers.find((entry) => entry.id === carrierId); + if (carrier === undefined) throw error(`publication lock has no carrier ${carrierId}`); + return verifyRegistryCarrierIntegrity(carrier, options); +} + export async function verifyLockedRegistryIntegrity( lock, { @@ -849,6 +1133,7 @@ export async function verifyLockedRegistryIntegrity( fetchImpl = fetch, concurrency = Number(process.env.REGISTRY_INTEGRITY_CONCURRENCY ?? 8), cratesIoReadGate = DEFAULT_CRATES_IO_READ_GATE, + cachedReceipts = new Map(), } = {}, ) { if (!Number.isSafeInteger(concurrency) || concurrency < 1 || concurrency > 32) { @@ -857,6 +1142,14 @@ export async function verifyLockedRegistryIntegrity( ); } const carriers = selectedLockedRegistryCarriers(lock, { products, ecosystems, carrierIds }); + if (!(cachedReceipts instanceof Map)) + throw error('cachedReceipts must be a Map keyed by exact carrier identity'); + const selectedIds = new Set(carriers.map(({ id }) => id)); + for (const [id, receipt] of cachedReceipts) { + if (!selectedIds.has(id) || receipt?.id !== id) { + throw error('cachedReceipts must contain unique selected carrier identities'); + } + } const receipts = new Array(carriers.length); let next = 0; const worker = async () => { @@ -867,6 +1160,7 @@ export async function verifyLockedRegistryIntegrity( receipts[index] = await verifyLockedCarrierIntegrity(lock, carriers[index].id, { fetchImpl, cratesIoReadGate, + cachedReceipts, }); } }; diff --git a/tools/release/registry-integrity.test.mts b/tools/release/registry-integrity.test.mts index edfc2c30a..d7376217d 100644 --- a/tools/release/registry-integrity.test.mts +++ b/tools/release/registry-integrity.test.mts @@ -1,23 +1,473 @@ #!/usr/bin/env bun import assert from 'node:assert/strict'; import { createHash } from 'node:crypto'; -import { mkdirSync, mkdtempSync, rmSync, statSync, writeFileSync } from 'node:fs'; +import { + chmodSync, + lstatSync, + mkdirSync, + mkdtempSync, + readdirSync, + readFileSync, + rmSync, + statSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; import path from 'node:path'; import test from 'node:test'; - +import { createCratesIoReadGate } from './registry-http-retry.mts'; import { + materializeRegistryCarrierIntegrity, validateLockedRegistryReceipts, validateRegistryReceiptEvidence, verifyLockedCarrierIntegrity, verifyLockedRegistryIntegrity, + verifyRegistryCarrierIntegrity, writeRegistryReceiptEvidence, } from './registry-integrity.mts'; -import { createCratesIoReadGate } from './registry-http-retry.mts'; const ROOT = path.resolve(import.meta.dir, '../..'); const sha = (bytes, algorithm, encoding = 'hex') => createHash(algorithm).update(bytes).digest(encoding); +test('historical Maven files come from the exact old POM and each companion is acquired once', async () => { + const root = mkdtempSync(path.join('/tmp', 'historical-maven-')); + const pom = (packaging) => + `4.0.0dev.exampleretired1.0.0${packaging}RetiredHistorical packagehttps://example.orgMIThttps://example.org/licenseMaintainerhttps://example.orgscm:git:https://example.org/reposcm:git:ssh://example.org/repohttps://example.org/repo`; + try { + for (const packaging of ['pom', 'jar', 'aar', 'tar.gz']) { + const names = [ + 'retired-1.0.0.pom', + ...(packaging === 'pom' + ? [] + : [ + `retired-1.0.0.${packaging}`, + 'retired-1.0.0-sources.jar', + 'retired-1.0.0-javadoc.jar', + ]), + ]; + const requested = []; + const result = await materializeRegistryCarrierIntegrity( + { + id: 'maven:dev.example:retired', + product: 'fixture', + ecosystem: 'maven', + name: 'dev.example:retired', + version: '1.0.0', + artifacts: [], + }, + { + directory: path.join(root, packaging), + fetchImpl: async (url) => { + const name = new URL(url).pathname.split('/').at(-1); + assert.ok(names.includes(name)); + requested.push(name); + return new Response(name.endsWith('.pom') ? pom(packaging) : `exact old ${name}`); + }, + }, + ); + assert.deepEqual(requested, names); + assert.deepEqual( + result.carrier.artifacts.map((artifact) => path.basename(artifact.path)), + names, + ); + await verifyRegistryCarrierIntegrity(result.carrier, { + cachedReceipt: result.receipt, + fetchImpl: () => assert.fail('retained receipt must not fetch'), + }); + } + for (const fault of ['wrong-coordinate', 'missing-companion']) { + const requested = []; + await assert.rejects( + materializeRegistryCarrierIntegrity( + { + id: 'maven:dev.example:retired', + product: 'fixture', + ecosystem: 'maven', + name: 'dev.example:retired', + version: '1.0.0', + artifacts: [], + }, + { + directory: path.join(root, fault), + fetchImpl: async (url) => { + const name = new URL(url).pathname.split('/').at(-1); + requested.push(name); + if (name.endsWith('.pom')) + return new Response( + fault === 'wrong-coordinate' + ? pom('jar').replace('retired', 'wrong') + : pom('jar'), + ); + return new Response('missing', { status: 404 }); + }, + }, + ), + fault === 'wrong-coordinate' ? /exact coordinate/ : /HTTP 404/, + ); + assert.equal(requested[0], 'retired-1.0.0.pom'); + assert.deepEqual(readdirSync(path.join(root, fault)), []); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('materializes exact Cargo/npm archives and all Maven companions once and reuses authenticated receipts', async () => { + mkdirSync(path.join(ROOT, 'target'), { recursive: true }); + const root = mkdtempSync(path.join(ROOT, 'target', 'registry-materialization-test-')); + try { + const requested = []; + const payloads = new Map([ + ['https://crates.io/api/v1/crates/alpha/1.0.0/download', Buffer.from('crate bytes')], + ['https://registry.npmjs.org/@example/alpha/-/alpha-1.0.0.tgz', Buffer.from('npm bytes')], + [ + 'https://repo1.maven.org/maven2/dev/example/alpha/1.0.0/alpha-1.0.0.pom', + Buffer.from('pom bytes'), + ], + [ + 'https://repo1.maven.org/maven2/dev/example/alpha/1.0.0/alpha-1.0.0.jar', + Buffer.from('jar bytes'), + ], + [ + 'https://repo1.maven.org/maven2/dev/example/alpha/1.0.0/alpha-1.0.0-sources.jar', + Buffer.from('sources bytes'), + ], + ]); + const crateBytes = payloads.get('https://crates.io/api/v1/crates/alpha/1.0.0/download'); + const npmBytes = payloads.get('https://registry.npmjs.org/@example/alpha/-/alpha-1.0.0.tgz'); + const fetchImpl = async (url) => { + requested.push(url); + if (url === 'https://crates.io/api/v1/crates/alpha/1.0.0') { + return Response.json({ + version: { + crate: 'alpha', + num: '1.0.0', + checksum: sha(crateBytes, 'sha256'), + crate_size: crateBytes.length, + }, + }); + } + if (url === 'https://registry.npmjs.org/%40example%2Falpha/1.0.0') { + return Response.json({ + name: '@example/alpha', + version: '1.0.0', + dist: { + integrity: `sha512-${sha(npmBytes, 'sha512', 'base64')}`, + tarball: 'https://registry.npmjs.org/@example/alpha/-/alpha-1.0.0.tgz', + }, + }); + } + const bytes = payloads.get(url); + assert.ok(bytes, `unexpected acquisition ${url}`); + return new Response( + new ReadableStream({ + start(controller) { + controller.enqueue(bytes.subarray(0, 3)); + controller.enqueue(bytes.subarray(3)); + controller.close(); + }, + }), + ); + }; + const carriers = [ + { + id: 'cargo:alpha', + product: 'alpha', + ecosystem: 'cargo', + name: 'alpha', + version: '1.0.0', + artifacts: [{ path: 'alpha.crate' }], + }, + { + id: 'npm:@example/alpha', + product: 'alpha', + ecosystem: 'npm', + name: '@example/alpha', + version: '1.0.0', + artifacts: [{ path: 'alpha.tgz', size: npmBytes.length, sha256: sha(npmBytes, 'sha256') }], + }, + { + id: 'maven:dev.example:alpha', + product: 'alpha', + ecosystem: 'maven', + name: 'dev.example:alpha', + version: '1.0.0', + artifacts: [ + { path: 'alpha-1.0.0.pom' }, + { path: 'alpha-1.0.0.jar' }, + { path: 'alpha-1.0.0-sources.jar' }, + ], + }, + ]; + const gateRequests = []; + const results = []; + for (const [publishOrder, carrier] of carriers.entries()) { + const result = await materializeRegistryCarrierIntegrity( + { ...carrier, publishOrder }, + { + directory: root, + fetchImpl, + cratesIoReadGate: { beforeRequest: async (url) => gateRequests.push(url), defer() {} }, + }, + ); + results.push(result); + for (const artifact of result.carrier.artifacts) { + assert.ok(path.isAbsolute(artifact.path)); + assert.equal(sha(readFileSync(artifact.path), 'sha256'), artifact.sha256); + assert.equal(lstatSync(artifact.path).size, artifact.size); + assert.equal(lstatSync(artifact.path).mode & 0o222, 0); + } + assert.deepEqual( + await verifyRegistryCarrierIntegrity(result.carrier, { + cachedReceipt: result.receipt, + fetchImpl: () => assert.fail('cached receipt must not fetch'), + }), + result.receipt, + ); + assert.deepEqual( + await verifyRegistryCarrierIntegrity(result.carrier, { + cachedReceipts: new Map([[result.carrier.id, result.receipt]]), + fetchImpl: () => assert.fail('mapped cached receipt must not fetch'), + }), + result.receipt, + ); + } + assert.equal(requested.length, 7); + assert.equal(new Set(requested).size, requested.length); + await assert.rejects( + verifyRegistryCarrierIntegrity(results[0].carrier, { + cachedReceipt: { ...results[0].receipt, product: 'different' }, + cachedReceipts: new Map([[results[0].carrier.id, results[0].receipt]]), + }), + /conflicting cached registry receipts/u, + ); + assert.deepEqual(gateRequests, [ + 'https://crates.io/api/v1/crates/alpha/1.0.0', + 'https://crates.io/api/v1/crates/alpha/1.0.0/download', + ]); + assert.deepEqual( + await verifyLockedRegistryIntegrity( + { carriers: results.map(({ carrier }) => carrier) }, + { + cachedReceipts: new Map(results.map(({ receipt }) => [receipt.id, receipt])), + fetchImpl: () => assert.fail('bulk cached receipt must not fetch'), + }, + ), + results.map(({ receipt }) => receipt), + ); + await assert.rejects( + verifyRegistryCarrierIntegrity( + { ...results[0].carrier, version: '2.0.0' }, + { cachedReceipt: results[0].receipt }, + ), + /changed version/u, + ); + const npmFile = results[1].carrier.artifacts[0].path; + chmodSync(npmFile, 0o600); + writeFileSync(npmFile, Buffer.from('changed!!')); + await assert.rejects( + verifyRegistryCarrierIntegrity(results[1].carrier, { cachedReceipt: results[1].receipt }), + /no longer matches/u, + ); + const symlink = path.join(root, 'unrelated.tgz'); + symlinkSync(results[1].carrier.artifacts[0].path, symlink); + await assert.rejects( + verifyRegistryCarrierIntegrity( + { + ...results[1].carrier, + artifacts: [{ ...results[1].carrier.artifacts[0], path: symlink }], + }, + { cachedReceipt: results[1].receipt }, + ), + /regular owned files/u, + ); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('registry materialization rejects metadata, bounds, digest and descriptor conflicts without retaining partial files', async () => { + mkdirSync(path.join(ROOT, 'target'), { recursive: true }); + const root = mkdtempSync(path.join(ROOT, 'target', 'registry-materialization-negative-')); + try { + const bytes = Buffer.from('archive bytes'); + const npmCarrier = { + id: 'npm:alpha', + product: 'alpha', + ecosystem: 'npm', + name: 'alpha', + version: '1.0.0', + artifacts: [{ path: 'alpha.tgz' }], + }; + const metadata = { + name: 'alpha', + version: '1.0.0', + dist: { + integrity: `sha512-${sha(bytes, 'sha512', 'base64')}`, + tarball: 'https://registry.npmjs.org/alpha/-/alpha-1.0.0.tgz', + }, + }; + const cases = [ + { + metadata: { ...metadata, version: '2.0.0' }, + match: /exact package version identity/u, + calls: 1, + }, + { + metadata: { + ...metadata, + dist: { ...metadata.dist, tarball: 'https://example.com/alpha.tgz' }, + }, + match: /canonical package version URL/u, + calls: 1, + }, + { bytes: Buffer.from('wrong bytes'), match: /SHA512/u, calls: 2 }, + { maximumBytes: 3, match: /exceeds locked size/u, calls: 2 }, + { + artifacts: [{ path: 'alpha.tgz', size: bytes.length + 1 }], + match: /does not match expected size/u, + calls: 2, + }, + { artifacts: [{ path: 'alpha.tgz', sha256: '0'.repeat(64) }], match: /SHA256/u, calls: 2 }, + { + artifacts: [{ path: 'alpha.tgz', sha256: 'bad' }], + match: /invalid expected artifact SHA256/u, + calls: 0, + }, + { + artifacts: [{ path: 'alpha.tgz' }, { path: 'other.tgz' }], + match: /exactly one/u, + calls: 0, + }, + { name: '../alpha', match: /invalid exact registry package name/u, calls: 0 }, + ]; + for (const scenario of cases) { + let calls = 0; + await assert.rejects( + materializeRegistryCarrierIntegrity( + { + ...npmCarrier, + name: scenario.name ?? npmCarrier.name, + artifacts: scenario.artifacts ?? npmCarrier.artifacts, + }, + { + directory: root, + maximumBytes: scenario.maximumBytes ?? 1024, + fetchImpl: async () => { + calls += 1; + return calls === 1 + ? Response.json(scenario.metadata ?? metadata) + : new Response(scenario.bytes ?? bytes); + }, + }, + ), + scenario.match, + ); + assert.equal(calls, scenario.calls); + assert.deepEqual(readdirSync(root), []); + } + const cargo = { + ...npmCarrier, + id: 'cargo:alpha', + ecosystem: 'cargo', + artifacts: [{ path: 'alpha.crate', sha256: '0'.repeat(64) }], + }; + await assert.rejects( + materializeRegistryCarrierIntegrity(cargo, { + directory: root, + cratesIoReadGate: null, + fetchImpl: async () => + Response.json({ + version: { crate: 'alpha', num: '1.0.0', checksum: sha(bytes, 'sha256') }, + }), + }), + /registry checksum mismatch/u, + ); + assert.deepEqual(readdirSync(root), []); + let mavenCalls = 0; + await assert.rejects( + materializeRegistryCarrierIntegrity( + { + ...npmCarrier, + id: 'maven:alpha', + ecosystem: 'maven', + name: 'dev.example:alpha', + artifacts: [ + { path: 'alpha-1.0.0.pom' }, + { path: 'alpha-1.0.0.jar', sha256: '0'.repeat(64) }, + ], + }, + { + directory: root, + fetchImpl: async () => { + mavenCalls += 1; + return new Response(bytes); + }, + }, + ), + /SHA256/u, + ); + assert.equal(mavenCalls, 2); + assert.deepEqual(readdirSync(root), []); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + +test('registry materialization retries a transient partial stream with a fresh owned file', async () => { + mkdirSync(path.join(ROOT, 'target'), { recursive: true }); + const root = mkdtempSync(path.join(ROOT, 'target', 'registry-materialization-retry-')); + try { + const bytes = Buffer.from('complete archive'); + let calls = 0; + let reads = 0; + let cancels = 0; + const result = await materializeRegistryCarrierIntegrity( + { + id: 'maven:alpha', + product: 'alpha', + ecosystem: 'maven', + name: 'dev.example:alpha', + version: '1.0.0', + artifacts: [{ path: 'alpha-1.0.0.jar', size: bytes.length, sha256: sha(bytes, 'sha256') }], + }, + { + directory: root, + fetchImpl: async () => { + calls += 1; + if (calls === 2) return new Response(bytes); + return { + ok: true, + headers: new Headers(), + body: { + getReader: () => ({ + read: async () => { + reads += 1; + if (reads === 1) return { done: false, value: bytes.subarray(0, 3) }; + throw new Error('transient interrupted stream'); + }, + cancel: async () => { + cancels += 1; + }, + releaseLock() {}, + }), + }, + }; + }, + }, + ); + assert.equal(calls, 2); + assert.equal(cancels, 1); + assert.deepEqual(readFileSync(result.carrier.artifacts[0].path), bytes); + assert.deepEqual(readdirSync(path.dirname(result.carrier.artifacts[0].path)), [ + 'alpha-1.0.0.jar', + ]); + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); + test('proves Cargo checksum and npm SRI against frozen archive bytes and rejects same-version byte conflicts', async () => { mkdirSync(path.join(ROOT, 'target'), { recursive: true }); const root = mkdtempSync(path.join(ROOT, 'target', 'registry-integrity-test-')); diff --git a/tools/release/release-app-token.test.mts b/tools/release/release-app-token.test.mts index ff8663854..7a52141e6 100644 --- a/tools/release/release-app-token.test.mts +++ b/tools/release/release-app-token.test.mts @@ -185,8 +185,15 @@ test('release workflow reserves repository mutations for Oli with per-step token assert.equal(steps.get('release_attestation_token').with['permission-attestations'], 'write'); const pr = workflow.jobs['prepare-release-pr']; assert.equal(pr.environment, 'release-pr'); - for (const step of pr.steps.filter((step) => step.env?.GH_TOKEN)) - assert.equal(step.env.GH_TOKEN, '${{ steps.release_pr_token.outputs.token }}'); + for (const step of pr.steps.filter((step) => step.env?.GH_TOKEN)) { + if (step.id === 'native_qualification') { + assert.equal(step.env.GH_TOKEN, '${{ github.token }}'); + assert.match(step.run, /require-workflow-success\.sh/u); + assert.equal(pr.permissions.actions, 'read'); + } else { + assert.equal(step.env.GH_TOKEN, '${{ steps.release_pr_token.outputs.token }}'); + } + } for (const name of ['publish-bootstrap', 'publish']) { const preflight = workflow.jobs[name].steps.find( (step) => step.name === 'Preflight selected product tag and release collisions', @@ -196,7 +203,33 @@ test('release workflow reserves repository mutations for Oli with per-step token const tokenStep = workflow.jobs[name].steps.find((step) => step.id === tokenId); assert.equal(tokenStep.with['permission-contents'], 'write', 'draft collision visibility'); } - assert.equal(workflow.jobs['request-qualification'].permissions.actions, 'write'); + for (const [name, job] of Object.entries(workflow.jobs) as [string, any][]) { + if (name === 'qualify-prepare-source') { + assert.deepEqual(job.permissions, { actions: 'write', contents: 'read' }); + assert.equal(job.needs, 'validate-inputs'); + assert.equal(job.if, "${{ inputs.operation == 'prepare-release-pr' }}"); + const request = job.steps.find((step) => step.id === 'native_qualification'); + assert.equal(request.env.GH_TOKEN, '${{ github.token }}'); + assert.equal(request.env.GH_REPO, '${{ github.repository }}'); + assert.match( + request.run, + /require-workflow-success\.sh 'Native Bazel qualification' "\$GITHUB_SHA" 0/u, + ); + assert.match(request.run, /--request-native-qualification/u); + assert.doesNotMatch( + JSON.stringify(job), + /secrets\.|create-github-app-token|permission-contents|publish-release-pr/u, + ); + for (const step of job.steps.filter((step) => step.env?.GH_TOKEN)) + assert.equal( + step.id, + 'native_qualification', + 'Actions write serves only the Native request', + ); + } else { + assert.notEqual(job.permissions?.actions, 'write', `${name} observes existing runs`); + } + } assert.equal(workflow.jobs['publish-bootstrap'].permissions['id-token'], 'write'); assert.equal(workflow.jobs.publish.permissions['id-token'], 'write'); }); diff --git a/tools/release/release-artifact-targets.mts b/tools/release/release-artifact-targets.mts index ba26a83e0..1a7522e5a 100644 --- a/tools/release/release-artifact-targets.mts +++ b/tools/release/release-artifact-targets.mts @@ -1,27 +1,52 @@ import { existsSync, readFileSync } from 'node:fs'; import path from 'node:path'; import { seedCarrierIdentities } from '../../src/database-resources/seeds/carrier-identities.mts'; -import { RUST_PAYLOAD_LICENSE as MOBILE_BINDINGS_LICENSE } from '../../src/native/mobile-bindings/tools/dependency-license-contract.mts'; - -import { - PLATFORM_COMPATIBILITY_POLICY, - platformCompatibilityContract, -} from './platform-compatibility-policy.mts'; +import { loadContribCarriers } from '../../src/extensions/artifacts/packages/tools/contrib-carriers.mts'; import { extensionNativeRegistryPackageStrings, extensionWasixRegistryPackageStrings, } from '../../src/extensions/artifacts/packages/tools/extension-registry-packages.mts'; -import { loadContribCarriers } from '../../src/extensions/artifacts/packages/tools/contrib-carriers.mts'; import { EXTENSION_TARGET_PROFILES_RELATIVE_PATH, loadExtensionTargetProfiles, + validateExtensionTargetProfiles, } from '../../src/extensions/contracts/extension-target-profiles.mts'; +import { RUST_PAYLOAD_LICENSE as MOBILE_BINDINGS_LICENSE } from '../../src/native/mobile-bindings/tools/dependency-license-contract.mts'; +import { + contribExtensionMetadata, + declaredExtensionMetadata, + EXTENSION_VERSIONING_BY_CLASS, + extensionSourceMetadata, +} from './extension-release-metadata.mts'; +import { + PLATFORM_COMPATIBILITY_POLICY, + platformCompatibilityContract, +} from './platform-compatibility-policy.mts'; import { loadProducts, versionFiles } from './release-graph.mts'; export { PLATFORM_COMPATIBILITY_POLICY }; export const ROOT = path.resolve(import.meta.dir, '../..'); +export function extensionReleaseMetadataRows(product, family) { + if (family !== null && family !== 'native' && family !== 'wasix') { + throw new Error(`release-artifact-targets.mts: unsupported extension family ${family}`); + } + return [ + ['manifest-json', `${product.id}-${product.version}-manifest.json`], + ['manifest-properties', `${product.id}-${product.version}-manifest.properties`], + ...(family === null || family === 'native' + ? [ + [ + 'swift-extension-carrier', + `${product.id}-${product.version}-swift-extension-carrier.json`, + ], + ] + : []), + ['checksums', `${product.id}-${product.version}-release-assets.sha256`], + ]; +} + export const DESKTOP_TARGETS = { 'linux-arm64-gnu': { triple: 'aarch64-unknown-linux-gnu', @@ -125,7 +150,7 @@ const WASIX_POSTMASTER_TARGETS = new Set(RELEASE_HOST_TARGETS); const BROKER_TARGETS = new Set(RELEASE_HOST_TARGETS); const NODE_DIRECT_TARGETS = BROKER_TARGETS; const WASIX_NAPI_TARGETS = BROKER_TARGETS; -const PRODUCT_PRESETS = { +export const PRODUCT_PRESETS = { 'postgres-tools-native': 'postgres-tools-native', 'postgres-tools-wasix': 'postgres-tools-wasix', 'liboliphaunt-native': 'liboliphaunt-native', @@ -137,11 +162,6 @@ const PRODUCT_PRESETS = { }; const EXTENSION_FAMILIES = new Set(['native', 'wasix']); const EXTENSION_KINDS = new Set(['native-dynamic', 'native-static-registry', 'wasix-runtime']); -const EXTENSION_VERSIONING_BY_CLASS = { - contrib: 'runtime-bound', - external: 'upstream-bound', - 'first-party': 'repo-bound', -}; const EXTENSION_PRODUCT_KINDS = new Set(['exact-extension-artifact', 'exact-extension-bundle']); const EXTENSION_CATALOG_PATH = path.join(ROOT, 'src/extensions/generated/extensions.catalog.json'); @@ -166,17 +186,93 @@ export function compareText(left, right) { return left < right ? -1 : left > right ? 1 : 0; } +export function canonicalExtensionAssetName(product, row) { + const prefix = `${product.id}-${product.version}`; + if (row.family === 'wasix') return `${prefix}-wasix-portable.tar.zst`; + if (row.kind === 'ios-xcframework') return `${prefix}-native-ios-xcframework.zip`; + if (row.kind === 'ios-dependency-xcframework') + return `${prefix}-native-ios-dependency-${row.identity}-xcframework.zip`; + if (row.target === 'ios-xcframework') return `${prefix}-native-ios-runtime.tar.gz`; + return `${prefix}-native-${row.target}-runtime.tar.gz`; +} + +export function canonicalExtensionBundleAssetName(product, { family, target }) { + return `${product.id}-${product.version}-${family}-${target}-bundle.tar.gz`; +} + +/** The canonical release names can also consume already declared target/member rows. */ +export function expectedExtensionGithubReleaseAssetRows(product, { sqlNames, requiredRows }) { + if ( + !Array.isArray(sqlNames) || + sqlNames.length === 0 || + sqlNames.some((name) => typeof name !== 'string' || !name) || + new Set(sqlNames).size !== sqlNames.length || + !Array.isArray(requiredRows) + ) + throw new Error('extension asset inventory requires explicit unique SQL names and target rows'); + if (sqlNames.length > 1) { + const groups = new Map(); + for (const { family, target } of requiredRows) { + if (product.family != null && family !== product.family) continue; + const key = `${family}\0${target}`; + if (!groups.has(key)) groups.set(key, { family, target, kind: 'extension-bundle' }); + } + return [...groups.values()] + .sort((left, right) => + compareText(`${left.family}\0${left.target}`, `${right.family}\0${right.target}`), + ) + .map((row) => ({ + ...row, + identity: row.family, + name: canonicalExtensionBundleAssetName(product, row), + })); + } + return requiredRows.map((row) => ({ ...row, name: canonicalExtensionAssetName(product, row) })); +} + export function rel(file) { const relative = path.relative(ROOT, file); return relative.startsWith('..') ? file : relative.split(path.sep).join('/'); } -function productConfigs(prefix) { +/** Explicit source snapshots never fall through to the current checkout. */ +export function readArtifactInputText(relative, inputContext = undefined) { + if (inputContext === undefined) return readFileSync(path.join(ROOT, relative), 'utf8'); + if (typeof inputContext.readText !== 'function') + throw new Error(`release-artifact-targets.mts: historical inputContext must read ${relative}`); + const text = inputContext.readText(relative); + if (typeof text !== 'string') + throw new Error(`release-artifact-targets.mts: missing historical input ${relative}`); + return text; +} + +function productConfigs(prefix, inputContext = undefined) { + if (inputContext !== undefined) { + if ( + !inputContext.products || + typeof inputContext.products !== 'object' || + Array.isArray(inputContext.products) + ) + throw new Error(`${prefix}: historical inputContext requires product descriptors`); + return inputContext.products; + } if (!productsCache.has(prefix)) productsCache.set(prefix, loadProducts(prefix)); return productsCache.get(prefix); } -export function contribCarrierDescriptor(prefix = 'release-artifact-targets.mts') { +export function contribCarrierDescriptor( + prefix = 'release-artifact-targets.mts', + inputContext = undefined, +) { + if (inputContext !== undefined) { + if ( + !inputContext.contrib || + typeof inputContext.contrib !== 'object' || + Array.isArray(inputContext.contrib) + ) + throw new Error(`${prefix}: historical inputContext requires its contrib descriptor`); + return inputContext.contrib; + } if (contribCarriersCache !== undefined) return contribCarriersCache; let value; try { @@ -269,38 +365,45 @@ function assertStringList(value, label, prefix) { return value; } -function artifactTargetConfig(product, expectedPreset, prefix) { - const release = releaseMetadata(product, prefix); - const config = release.artifactTargets; +export function artifactTargetConfig( + product, + expectedPreset, + prefix = 'release-artifact-targets.mts', + inputContext = undefined, +) { + const release = productConfig(product, prefix, inputContext); + return artifactTargetConfigFromRelease(product, release, expectedPreset, prefix); +} + +function artifactTargetConfigFromRelease(product, release, expectedPreset, prefix) { + const config = release.artifact_targets; if (typeof config !== 'object' || config === null || Array.isArray(config)) { - fail(prefix, `Moon release metadata for ${product} must declare artifactTargets`); + fail(prefix, `${product} release.toml must declare artifact_targets`); } if (config.preset !== expectedPreset) { - fail( - prefix, - `Moon release metadata for ${product} artifactTargets.preset must be ${expectedPreset}`, - ); + fail(prefix, `${product} release.toml artifact_targets.preset must be ${expectedPreset}`); } return config; } function productTargets(product, expectedPreset, knownTargets, prefix) { const config = artifactTargetConfig(product, expectedPreset, prefix); + return productTargetsFromConfig(product, config, knownTargets, prefix); +} + +function productTargetsFromConfig(product, config, knownTargets, prefix) { const targets = assertStringList(config.targets ?? [], `${product}.targets`, prefix); const duplicates = [ ...new Set(targets.filter((target, index) => targets.indexOf(target) !== index)), ]; if (duplicates.length > 0) { - fail( - prefix, - `Moon release metadata for ${product} artifactTargets.targets contains duplicates`, - ); + fail(prefix, `${product} release.toml artifact_targets.targets contains duplicates`); } const unknown = targets.filter((target) => !knownTargets.has(target)).sort(compareText); if (unknown.length > 0) { fail( prefix, - `Moon release metadata for ${product} declares unknown artifact target(s): ${unknown.join(', ')}`, + `${product} release.toml declares unknown artifact target(s): ${unknown.join(', ')}`, ); } return targets; @@ -366,15 +469,16 @@ export function liboliphauntAndroidAbi(target) { return abi; } -function liboliphauntNativeRows(prefix) { +function liboliphauntNativeRows(prefix, declaredTargets = undefined) { const product = 'liboliphaunt-native'; const targets = new Set( - productTargets( - product, - PRODUCT_PRESETS[product], - new Set(Object.keys(NATIVE_RUNTIME_TARGETS)), - prefix, - ), + declaredTargets ?? + productTargets( + product, + PRODUCT_PRESETS[product], + new Set(Object.keys(NATIVE_RUNTIME_TARGETS)), + prefix, + ), ); const rows = []; for (const target of [...targets].sort(compareText)) { @@ -449,15 +553,16 @@ function githubChecksumRow(product, asset = `${product}-{version}-release-assets }; } -function postgresToolsNativeRows(prefix) { +function postgresToolsNativeRows(prefix, declaredTargets = undefined) { const product = 'postgres-tools-native'; const targets = new Set( - productTargets( - product, - PRODUCT_PRESETS[product], - new Set(Object.keys(DESKTOP_TARGETS)), - prefix, - ), + declaredTargets ?? + productTargets( + product, + PRODUCT_PRESETS[product], + new Set(Object.keys(DESKTOP_TARGETS)), + prefix, + ), ); const rows = []; for (const target of [...targets].filter((item) => item in DESKTOP_TARGETS).sort(compareText)) { @@ -483,9 +588,10 @@ function postgresToolsNativeRows(prefix) { return rows; } -function postgresToolsWasixRows(prefix) { +function postgresToolsWasixRows(prefix, declaredTargets = undefined) { const product = 'postgres-tools-wasix'; - const targets = productTargets(product, PRODUCT_PRESETS[product], WASIX_TARGETS, prefix); + const targets = + declaredTargets ?? productTargets(product, PRODUCT_PRESETS[product], WASIX_TARGETS, prefix); const rows = targets.map((target) => { const portable = target === 'portable'; const platform = DESKTOP_TARGETS[target]; @@ -515,9 +621,11 @@ function postgresToolsWasixRows(prefix) { return rows; } -function liboliphauntWasixRows(prefix) { +function liboliphauntWasixRows(prefix, declaredTargets = undefined) { const product = 'liboliphaunt-wasix'; - const targets = new Set(productTargets(product, PRODUCT_PRESETS[product], WASIX_TARGETS, prefix)); + const targets = new Set( + declaredTargets ?? productTargets(product, PRODUCT_PRESETS[product], WASIX_TARGETS, prefix), + ); if (!targets.has('portable')) { fail(prefix, `Moon release metadata for ${product} must include the portable runtime target`); } @@ -553,14 +661,12 @@ function liboliphauntWasixRows(prefix) { return rows; } -function liboliphauntWasixPostmasterRows(prefix) { +function liboliphauntWasixPostmasterRows(prefix, declaredTargets = undefined) { const product = 'liboliphaunt-wasix-postmaster'; const rows = []; - for (const target of productTargets( - product, - PRODUCT_PRESETS[product], - WASIX_POSTMASTER_TARGETS, - prefix, + for (const target of ( + declaredTargets ?? + productTargets(product, PRODUCT_PRESETS[product], WASIX_POSTMASTER_TARGETS, prefix) ).sort(compareText)) { const platform = DESKTOP_TARGETS[target]; rows.push({ @@ -587,14 +693,11 @@ function liboliphauntWasixPostmasterRows(prefix) { return rows; } -function brokerRows(prefix) { +function brokerRows(prefix, declaredTargets = undefined) { const product = 'oliphaunt-broker'; const rows = []; - for (const target of productTargets( - product, - PRODUCT_PRESETS[product], - BROKER_TARGETS, - prefix, + for (const target of ( + declaredTargets ?? productTargets(product, PRODUCT_PRESETS[product], BROKER_TARGETS, prefix) ).sort(compareText)) { const platform = DESKTOP_TARGETS[target]; rows.push({ @@ -623,14 +726,12 @@ function brokerRows(prefix) { return rows; } -function nodeDirectRows(prefix) { +function nodeDirectRows(prefix, declaredTargets = undefined) { const product = 'oliphaunt-node-direct'; const rows = []; - for (const target of productTargets( - product, - PRODUCT_PRESETS[product], - NODE_DIRECT_TARGETS, - prefix, + for (const target of ( + declaredTargets ?? + productTargets(product, PRODUCT_PRESETS[product], NODE_DIRECT_TARGETS, prefix) ).sort(compareText)) { const platform = DESKTOP_TARGETS[target]; rows.push({ @@ -655,14 +756,59 @@ function nodeDirectRows(prefix) { return rows; } -function wasixNapiRows(prefix) { - const product = 'oliphaunt-wasix-napi'; - const rows = []; - for (const target of productTargets( +/** Reuse canonical helper assets with explicitly read release.toml targets. */ +export function nativeHelperArtifactRows( + product, + declaredTargets, + prefix = 'release-artifact-targets.mts', +) { + const knownTargets = + product === 'oliphaunt-broker' + ? BROKER_TARGETS + : product === 'oliphaunt-node-direct' + ? NODE_DIRECT_TARGETS + : null; + if (knownTargets === null) fail(prefix, `not a native helper product: ${product}`); + const targets = productTargetsFromConfig( product, - PRODUCT_PRESETS[product], - WASIX_NAPI_TARGETS, + { targets: declaredTargets }, + knownTargets, prefix, + ); + return product === 'oliphaunt-broker' + ? brokerRows(prefix, [...targets]) + : nodeDirectRows(prefix, [...targets]); +} + +/** Project canonical runtime assets from explicitly read release targets. */ +export function nativeRuntimeArtifactRows( + product, + declaredTargets, + prefix = 'release-artifact-targets.mts', +) { + const knownTargets = + product === 'liboliphaunt-native' + ? new Set(Object.keys(NATIVE_RUNTIME_TARGETS)) + : product === 'postgres-tools-native' + ? new Set(Object.keys(DESKTOP_TARGETS)) + : null; + if (knownTargets === null) fail(prefix, `not a native runtime product: ${product}`); + const targets = productTargetsFromConfig( + product, + { targets: declaredTargets }, + knownTargets, + prefix, + ); + return product === 'liboliphaunt-native' + ? liboliphauntNativeRows(prefix, targets) + : postgresToolsNativeRows(prefix, targets); +} + +function wasixNapiRows(prefix, declaredTargets = undefined) { + const product = 'oliphaunt-wasix-napi'; + const rows = []; + for (const target of ( + declaredTargets ?? productTargets(product, PRODUCT_PRESETS[product], WASIX_NAPI_TARGETS, prefix) ).sort(compareText)) { const platform = DESKTOP_TARGETS[target]; rows.push({ @@ -695,7 +841,7 @@ function wasixNapiRows(prefix) { return rows; } -function databaseResourceRows() { +export function databaseResourceArtifactRows(contract = undefined) { const rows = [ { id: 'database-resources.swift-source', @@ -717,7 +863,7 @@ function databaseResourceRows() { _source_file: 'Moon release metadata', }, ]; - for (const { family, target, profile, suffix } of seedCarrierIdentities()) { + for (const { family, target, profile, suffix } of seedCarrierIdentities(contract)) { for (const extension of ['tar.zst', 'json']) { rows.push({ id: `database-resources.${family}.${target}.${profile}.${extension}`, @@ -734,7 +880,34 @@ function databaseResourceRows() { return rows; } -export function rawArtifactTargetRows(prefix = 'release-artifact-targets.mts') { +/** Project the maintained WASIX artifact contracts from explicit release targets. */ +export function wasixArtifactRows( + product, + declaredTargets, + prefix = 'release-artifact-targets.mts', +) { + const renderers = { + 'liboliphaunt-wasix': { render: liboliphauntWasixRows, targets: WASIX_TARGETS }, + 'postgres-tools-wasix': { render: postgresToolsWasixRows, targets: WASIX_TARGETS }, + 'liboliphaunt-wasix-postmaster': { + render: liboliphauntWasixPostmasterRows, + targets: WASIX_POSTMASTER_TARGETS, + }, + 'oliphaunt-wasix-napi': { render: wasixNapiRows, targets: WASIX_NAPI_TARGETS }, + }; + const descriptor = renderers[product]; + if (!descriptor) fail(prefix, `not a WASIX artifact product: ${product}`); + const targets = productTargetsFromConfig( + product, + { targets: declaredTargets }, + descriptor.targets, + prefix, + ); + return descriptor.render(prefix, [...targets]); +} + +/** Source-owned Swift archive declarations, shared by metadata and inventory. */ +export function swiftArtifactRows() { return [ { id: 'oliphaunt-swift.bindings', @@ -750,7 +923,38 @@ export function rawArtifactTargetRows(prefix = 'release-artifact-targets.mts') { ...githubChecksumRow('oliphaunt-swift'), _source_file: 'src/native/sdks/swift/tools/build-bindings-xcframework.sh', }, - ...databaseResourceRows(), + ]; +} + +export function rawArtifactTargetRows( + prefix = 'release-artifact-targets.mts', + inputContext = undefined, + product = undefined, +) { + if (inputContext !== undefined) { + const products = productConfigs(prefix, inputContext); + const selected = product === undefined ? Object.keys(products) : [product]; + return selected.flatMap((id) => { + productConfig(id, prefix, inputContext); + if (id === 'oliphaunt-swift') return swiftArtifactRows(); + if (id === 'database-resources') + return databaseResourceArtifactRows( + JSON.parse( + readArtifactInputText('src/database-resources/contracts/contract.json', inputContext), + ), + ); + if (!(id in PRODUCT_PRESETS)) return []; + const targets = artifactTargetConfig(id, PRODUCT_PRESETS[id], prefix, inputContext).targets; + if (id === 'liboliphaunt-native' || id === 'postgres-tools-native') + return nativeRuntimeArtifactRows(id, targets, prefix); + if (id === 'oliphaunt-broker' || id === 'oliphaunt-node-direct') + return nativeHelperArtifactRows(id, targets, prefix); + return wasixArtifactRows(id, targets, prefix); + }); + } + return [ + ...swiftArtifactRows(), + ...databaseResourceArtifactRows(), ...liboliphauntNativeRows(prefix), ...postgresToolsNativeRows(prefix), ...postgresToolsWasixRows(prefix), @@ -853,12 +1057,12 @@ function normalizeArtifactTarget(row, prefix) { } export function allArtifactTargets( - { product = undefined, kind = undefined, surface = undefined } = {}, + { product = undefined, kind = undefined, surface = undefined, inputContext = undefined } = {}, prefix = 'release-artifact-targets.mts', ) { - const products = productConfigs(prefix); + const products = productConfigs(prefix, inputContext); const seen = new Set(); - return rawArtifactTargetRows(prefix) + return rawArtifactTargetRows(prefix, inputContext, product) .map((row) => normalizeArtifactTarget(row, prefix)) .filter((target) => { if (seen.has(target.id)) { @@ -1035,7 +1239,7 @@ export function expectedAssetRows( } export function registryPackageRows( - { product, packageKind = undefined } = {}, + { product, packageKind = undefined, inputContext = undefined } = {}, prefix = 'release-artifact-targets.mts', ) { if (typeof product !== 'string' || product.length === 0) { @@ -1044,7 +1248,9 @@ export function registryPackageRows( if (packageKind !== undefined && (typeof packageKind !== 'string' || packageKind.length === 0)) { fail(prefix, 'registry package kind must be a non-empty string'); } - const config = productConfig(product, prefix); + const config = + inputContext === undefined ? productConfig(product, prefix) : inputContext.products[product]; + if (config === undefined) fail(prefix, `unknown release product ${product}`); const declaredEntries = config.registry_packages ?? []; if ( !Array.isArray(declaredEntries) || @@ -1053,9 +1259,13 @@ export function registryPackageRows( fail(prefix, `${product}.registry_packages must be a string list`); } const entries = [...declaredEntries]; - const contrib = contribCarrierDescriptor(prefix); + const contrib = + inputContext === undefined ? contribCarrierDescriptor(prefix) : inputContext.contrib; if (product === contrib.nativeOwner || product === contrib.wasixOwner) { - const targets = extensionRegistryPackageTargetSets(contrib.artifactProduct, prefix); + const targets = + inputContext === undefined + ? extensionRegistryPackageTargetSets(contrib.artifactProduct, prefix) + : inputContext.contribRegistryTargets; if (product === contrib.nativeOwner) { entries.push( ...extensionNativeRegistryPackageStrings({ @@ -1106,54 +1316,6 @@ export function registryPackageRows( ); } -const releaseMetadataCache = new Map(); - -export function releaseMetadata(product, prefix) { - const key = `${prefix}\0${product}`; - if (releaseMetadataCache.has(key)) return releaseMetadataCache.get(key); - const config = productConfig(product, prefix); - let directory = path.join(ROOT, config.path); - let release; - // Only literal product metadata is needed here. Dependency resolution stays in Moon. - while (directory !== ROOT) { - const file = path.join(directory, 'moon.yml'); - if (existsSync(file)) { - const project = Bun.YAML.parse(readFileSync(file, 'utf8')); - if (project.id !== product) - fail(prefix, `Moon project at ${rel(file)} does not own ${product}`); - release = project.project?.release; - break; - } - directory = path.dirname(directory); - if (!directory.startsWith(ROOT + path.sep)) break; - } - if (!release) { - fail(prefix, `Moon release metadata does not include ${product}`); - } - if (release.component !== product) { - fail(prefix, `Moon release metadata for ${product} must use matching component`); - } - if (release.packagePath !== config.path) { - fail(prefix, `Moon release metadata for ${product} must match package path ${config.path}`); - } - const expectedPreset = PRODUCT_PRESETS[product]; - if (expectedPreset !== undefined) { - const artifactTargets = release.artifactTargets; - if ( - typeof artifactTargets !== 'object' || - artifactTargets === null || - artifactTargets.preset !== expectedPreset - ) { - fail( - prefix, - `Moon release metadata for ${product} must use artifactTargets preset ${expectedPreset}`, - ); - } - } - releaseMetadataCache.set(key, release); - return release; -} - const versionCache = new Map(); export function currentProductVersionSync(product, prefix = 'release-artifact-targets.mts') { @@ -1209,19 +1371,25 @@ export function expectedAssets(product, kind, version, prefix) { return assets.sort(compareText); } -function productConfig(product, prefix) { - const config = productConfigs(prefix)[product]; +function productConfig(product, prefix, inputContext = undefined) { + const config = productConfigs(prefix, inputContext)[product]; if (!config) { + if (inputContext !== undefined) + throw new Error(`${prefix}: missing historical product ${product}`); fail(prefix, `unknown release product ${product}`); } return config; } -export function exactExtensionProducts(prefix = 'release-artifact-targets.mts') { - const products = Object.entries(productConfigs(prefix)) +export function exactExtensionProducts( + prefix = 'release-artifact-targets.mts', + inputContext = undefined, +) { + const products = Object.entries(productConfigs(prefix, inputContext)) .filter(([, config]) => EXTENSION_PRODUCT_KINDS.has(config.kind)) .map(([product]) => product); - products.push(contribCarrierDescriptor(prefix).artifactProduct); + const contrib = contribCarrierDescriptor(prefix, inputContext); + if (contrib.artifactProduct !== undefined) products.push(contrib.artifactProduct); return [...new Set(products)].sort(compareText); } @@ -1265,8 +1433,8 @@ export function extensionSqlName(product, prefix = 'release-artifact-targets.mts return names[0]; } -function contribMemberRows(product, prefix) { - const descriptor = contribCarrierDescriptor(prefix); +function contribMemberRows(product, prefix, inputContext = undefined) { + const descriptor = contribCarrierDescriptor(prefix, inputContext); if (product !== descriptor.artifactProduct) { fail(prefix, `${product} is not the shared PostgreSQL contrib artifact product`); } @@ -1315,14 +1483,18 @@ export function extensionSqlNamesForProducts(products, prefix = 'release-artifac return rows.map(({ sqlName }) => sqlName).sort(compareText); } -export function extensionSqlNames(product, prefix = 'release-artifact-targets.mts') { - const contrib = contribCarrierDescriptor(prefix); +export function extensionSqlNames( + product, + prefix = 'release-artifact-targets.mts', + inputContext = undefined, +) { + const contrib = contribCarrierDescriptor(prefix, inputContext); if (product === contrib.artifactProduct) { - return contribMemberRows(product, prefix) + return contribMemberRows(product, prefix, inputContext) .map((row) => row.sqlName) .sort(compareText); } - const config = productConfig(product, prefix); + const config = productConfig(product, prefix, inputContext); if (config.kind === 'exact-extension-artifact') { const value = config.extension_sql_name; if (typeof value !== 'string' || !value) { @@ -1348,7 +1520,7 @@ export function extensionSqlNames(product, prefix = 'release-artifact-targets.mt if (new Set(sorted).size !== sorted.length || JSON.stringify(values) !== JSON.stringify(sorted)) { fail(prefix, `${product}.extension_sql_names must be unique and sorted`); } - const manifestNames = contribMemberRows(product, prefix) + const manifestNames = contribMemberRows(product, prefix, inputContext) .map((row) => row.sqlName) .sort(compareText); if (JSON.stringify(sorted) !== JSON.stringify(manifestNames)) { @@ -1368,6 +1540,11 @@ function extensionCatalogRows(prefix) { } catch (error) { fail(prefix, `${rel(EXTENSION_CATALOG_PATH)} is not readable JSON: ${error.message}`); } + extensionCatalogRowsCache = validateExtensionCatalogRows(catalog, prefix); + return extensionCatalogRowsCache; +} + +export function validateExtensionCatalogRows(catalog, prefix = 'release-artifact-targets.mts') { if (catalog?.['format-version'] !== 1 || !Array.isArray(catalog.extensions)) { fail( prefix, @@ -1392,8 +1569,7 @@ function extensionCatalogRows(prefix) { } bySqlName.set(sqlName, row); } - extensionCatalogRowsCache = bySqlName; - return extensionCatalogRowsCache; + return bySqlName; } export function extensionPublicDependencySqlNames( @@ -1508,11 +1684,8 @@ export function extensionMetadata(product, prefix = 'release-artifact-targets.mt `${contrib.sourcePath}.postgresql.version must begin with a stable major version`, ); } - return { - sqlName: undefined, + return contribExtensionMetadata({ sqlNames: extensionSqlNames(product, prefix), - class: 'contrib', - versioning: 'runtime-bound', sourcePath: contrib.sourcePath, artifactProduct: contrib.artifactProduct, compatibility: { @@ -1523,7 +1696,7 @@ export function extensionMetadata(product, prefix = 'release-artifact-targets.mt wasixRuntimeProduct: contrib.wasixOwner, wasixRuntimeVersion: currentProductVersionSync(contrib.wasixOwner, prefix), }, - }; + }); } const config = productConfig(product, prefix); if (!EXTENSION_PRODUCT_KINDS.has(config.kind)) { @@ -1651,77 +1824,27 @@ export function extensionMetadata(product, prefix = 'release-artifact-targets.mt `${product}.extension.compatibility.wasix_runtime_product must be 'liboliphaunt-wasix'`, ); } - const nativeVersion = nonEmptyString( + nonEmptyString( compatibility.native_runtime_version, `${product}.extension.compatibility.native_runtime_version`, prefix, ); - const wasixVersion = nonEmptyString( + nonEmptyString( compatibility.wasix_runtime_version, `${product}.extension.compatibility.wasix_runtime_version`, prefix, ); - return { - sqlName, - sqlNames, - artifactProduct: product, - class: extensionClass, - versioning, - sourcePath, - compatibility: { - postgresMajor, - extensionRuntimeContract: contractPath, - nativeRuntimeProduct: nativeProduct, - nativeRuntimeVersion: nativeVersion, - wasixRuntimeProduct: wasixProduct, - wasixRuntimeVersion: wasixVersion, - }, - }; + return declaredExtensionMetadata(product, metadata); } export function extensionSourceIdentity(product, prefix = 'release-artifact-targets.mts') { const metadata = extensionMetadata(product, prefix); const source = Bun.TOML.parse(readFileSync(path.join(ROOT, metadata.sourcePath), 'utf8')); - if (metadata.class === 'contrib') { - const postgresql = source.postgresql; - if (postgresql === null || Array.isArray(postgresql) || typeof postgresql !== 'object') { - fail( - prefix, - `${metadata.sourcePath} must declare [postgresql] for contrib extension products`, - ); - } - return { - kind: 'postgres-contrib', - name: 'postgresql', - version: nonEmptyString( - postgresql.version, - `${metadata.sourcePath}.postgresql.version`, - prefix, - ), - url: nonEmptyString(postgresql.url, `${metadata.sourcePath}.postgresql.url`, prefix), - sha256: nonEmptyString(postgresql.sha256, `${metadata.sourcePath}.postgresql.sha256`, prefix), - }; - } - if (metadata.class === 'external') { - return { - kind: 'external', - name: nonEmptyString(source.name, `${metadata.sourcePath}.name`, prefix), - url: nonEmptyString(source.url, `${metadata.sourcePath}.url`, prefix), - branch: nonEmptyString(source.branch, `${metadata.sourcePath}.branch`, prefix), - commit: nonEmptyString(source.commit, `${metadata.sourcePath}.commit`, prefix), - }; - } - if (metadata.class === 'first-party') { - return { - kind: 'repo', - name: metadata.sqlName ?? product, - path: metadata.sourcePath, - version: currentProductVersionSync(product, prefix), - }; - } - fail( - prefix, - `${product}.extension.class has unsupported source identity class ${JSON.stringify(metadata.class)}`, + return extensionSourceMetadata( + product, + metadata, + source, + metadata.class === 'first-party' ? currentProductVersionSync(product, prefix) : undefined, ); } @@ -1729,12 +1852,9 @@ function wasixExtensionTargetId(runtimeTarget) { return runtimeTarget === 'portable' ? 'wasix-portable' : runtimeTarget; } -function runtimeExtensionTargetRows(prefix) { +function runtimeExtensionTargetRowsFromTargets(nativeTargets, wasixTargets) { const rows = []; - for (const target of allArtifactTargets( - { product: 'liboliphaunt-native', kind: 'native-runtime' }, - prefix, - )) { + for (const target of nativeTargets) { if (!target.extensionArtifacts) { continue; } @@ -1747,28 +1867,75 @@ function runtimeExtensionTargetRows(prefix) { : 'native-dynamic', }); } - for (const target of allArtifactTargets( - { product: 'liboliphaunt-wasix', kind: 'wasix-runtime' }, - prefix, - )) { + for (const target of wasixTargets) { rows.push({ target: wasixExtensionTargetId(target.target), family: 'wasix', kind: 'wasix-runtime', }); } - if (rows.length === 0) { + return rows; +} + +function runtimeExtensionTargetRows(prefix) { + const rows = runtimeExtensionTargetRowsFromTargets( + allArtifactTargets({ product: 'liboliphaunt-native', kind: 'native-runtime' }, prefix), + allArtifactTargets({ product: 'liboliphaunt-wasix', kind: 'wasix-runtime' }, prefix), + ); + if (rows.length === 0) fail(prefix, 'could not derive any exact-extension artifact targets from runtime products'); - } return rows; } -function readExtensionTargetRows(prefix) { +/** Same runtime target policy, with an explicit descriptor snapshot for imports. */ +export function runtimeExtensionTargetRowsFromConfigs( + products, + prefix = 'release-artifact-targets.mts', + { nativeOwner = 'liboliphaunt-native', wasixOwner = 'liboliphaunt-wasix' } = {}, +) { + const targets = (product, preset, known) => + productTargetsFromConfig( + product, + artifactTargetConfigFromRelease(product, products[product], preset, prefix), + known, + prefix, + ); + const nativeTargets = targets( + nativeOwner, + 'liboliphaunt-native', + new Set(Object.keys(NATIVE_RUNTIME_TARGETS)), + ); + for (const target of nativeTargets) requiredBinaryCompatibility(target, 'native runtime', prefix); + return runtimeExtensionTargetRowsFromTargets( + nativeTargets.map((target) => ({ target, extensionArtifacts: true })), + targets(wasixOwner, 'liboliphaunt-wasix', WASIX_TARGETS).map((target) => ({ target })), + ); +} + +function readExtensionTargetRows(prefix, inputContext = undefined) { const relative = EXTENSION_TARGET_PROFILES_RELATIVE_PATH; + const contrib = + inputContext === undefined ? undefined : contribCarrierDescriptor(prefix, inputContext); + if (inputContext !== undefined) { + for (const owner of [contrib.nativeOwner, contrib.wasixOwner]) { + if (typeof owner !== 'string' || !owner) + throw new Error(`${prefix}: historical profiles require their exact runtime owners`); + if (productConfig(owner, prefix, inputContext).artifact_targets === undefined) + throw new Error(`${prefix}: missing historical runtime artifact targets ${owner}`); + } + } const allowed = new Set( - runtimeExtensionTargetRows(prefix).map((row) => `${row.target}\0${row.family}\0${row.kind}`), + (inputContext === undefined + ? runtimeExtensionTargetRows(prefix) + : runtimeExtensionTargetRowsFromConfigs(inputContext.products, prefix, contrib) + ).map((row) => `${row.target}\0${row.family}\0${row.kind}`), ); - const rows = loadExtensionTargetProfiles().targets; + const rows = + inputContext === undefined + ? loadExtensionTargetProfiles().targets + : validateExtensionTargetProfiles( + Bun.TOML.parse(readArtifactInputText(relative, inputContext)), + ).targets; for (const row of rows) { if (!allowed.has(`${row.target}\0${row.family}\0${row.kind}`)) { fail( @@ -1788,18 +1955,18 @@ function nonEmptyString(value, label, prefix) { } export function extensionArtifactTargets( - { product = undefined, family = undefined } = {}, + { product = undefined, family = undefined, inputContext = undefined } = {}, prefix = 'release-artifact-targets.mts', ) { - const products = product === undefined ? exactExtensionProducts(prefix) : [product]; + const products = product === undefined ? exactExtensionProducts(prefix, inputContext) : [product]; const parsed = []; for (const productId of products) { - if (!exactExtensionProducts(prefix).includes(productId)) { + if (!exactExtensionProducts(prefix, inputContext).includes(productId)) { fail(prefix, `${productId} is not an exact-extension artifact product`); } - for (const sqlName of extensionSqlNames(productId, prefix)) { + for (const sqlName of extensionSqlNames(productId, prefix, inputContext)) { const seen = new Set(); - for (const [index, row] of readExtensionTargetRows(prefix).entries()) { + for (const [index, row] of readExtensionTargetRows(prefix, inputContext).entries()) { const source = EXTENSION_TARGET_PROFILES_RELATIVE_PATH; const target = nonEmptyString(row.target, `${source} targets[${index}].target`, prefix); const targetFamily = nonEmptyString( @@ -1855,22 +2022,29 @@ export function extensionTargetIds({ family }, prefix = 'release-artifact-target ].sort(compareText); } -function extensionPublishedTargets(product, family, kind, prefix) { - return [ - ...new Set( - extensionArtifactTargets({ product, family }, prefix) - .filter((target) => target.kind === kind) - .map((target) => target.target), - ), - ].sort(compareText); +export function extensionRegistryPackageTargetSets( + product, + prefix = 'release-artifact-targets.mts', +) { + return extensionRegistryPackageTargetSetsFromRows( + product, + extensionSqlNames(product, prefix), + extensionArtifactTargets({ product }, prefix), + extensionWasixAotMemberSqlNames(product, prefix), + prefix, + ); } -export function extensionRegistryPackageTargetSets( +/** Canonical carrier expansion from explicitly supplied, validated construction facts. */ +export function extensionRegistryPackageTargetSetsFromRows( product, + sqlNames, + artifactRows, + wasixAotMembers, prefix = 'release-artifact-targets.mts', ) { - const memberSignatures = extensionSqlNames(product, prefix).map((sqlName) => { - const rows = extensionArtifactTargets({ product }, prefix) + const memberSignatures = sqlNames.map((sqlName) => { + const rows = artifactRows .filter((row) => row.sqlName === sqlName) .map((row) => `${row.target}\0${row.family}\0${row.kind}`) .sort(compareText); @@ -1886,23 +2060,22 @@ export function extensionRegistryPackageTargetSets( `${product} bundle members must publish an identical target carrier set; mismatched members: ${mismatched.join(', ')}`, ); } - const nativeDynamicTargets = extensionPublishedTargets( - product, - 'native', - 'native-dynamic', - prefix, - ); + const published = (family, kind) => + [ + ...new Set( + artifactRows + .filter((row) => row.family === family && row.kind === kind) + .map((row) => row.target), + ), + ].sort(compareText); + const nativeDynamicTargets = published('native', 'native-dynamic'); if (nativeDynamicTargets.length === 0) { fail(prefix, `${product} has no native dynamic extension registry targets`); } - const androidTargets = extensionPublishedTargets( - product, - 'native', - 'native-static-registry', - prefix, - ).filter((target) => target.startsWith('android-')); - const wasixRuntimeTargets = extensionPublishedTargets(product, 'wasix', 'wasix-runtime', prefix); - const wasixAotMembers = extensionWasixAotMemberSqlNames(product, prefix); + const androidTargets = published('native', 'native-static-registry').filter((target) => + target.startsWith('android-'), + ); + const wasixRuntimeTargets = published('wasix', 'wasix-runtime'); return { androidTargets, npmTargets: nativeDynamicTargets, diff --git a/tools/release/release-check-registries.sh b/tools/release/release-check-registries.sh index 67efab975..f77a24c50 100644 --- a/tools/release/release-check-registries.sh +++ b/tools/release/release-check-registries.sh @@ -6,7 +6,7 @@ args=() while [ "$#" -gt 0 ]; do case "$1" in -h|--help) - echo 'usage: release-check-registries.sh [--products-json JSON] [--head-ref REF] [--registry-inventory-output FILE] [--require-identities]' + echo 'usage: release-check-registries.sh [--products-json JSON] [--head-ref REF] [--native-preparation] [--registry-inventory-output FILE] [--require-identities]' exit 0 ;; --require-identities) require_identities=true; shift ;; --products-json) diff --git a/tools/release/release-check.sh b/tools/release/release-check.sh index b70b80116..cf2acb153 100644 --- a/tools/release/release-check.sh +++ b/tools/release/release-check.sh @@ -33,7 +33,7 @@ test_files=() shell_tests=() while IFS= read -r -d '' test_file; do case "$test_file" in - tools/release/prepare-release-candidate.test.*) continue ;; + tools/release/prepare-release-candidate.test.*|tools/release/independent-version-pins.test.*) continue ;; *.test.sh|*.test.mjs|*.test.mts) ;; *) continue ;; esac @@ -49,5 +49,7 @@ while IFS= read -r -d '' test_file; do done < "$inventory" [ "${#test_files[@]}" -gt 0 ] || { echo 'No release tests found' >&2; exit 1; } -bash tools/release/release-please-state.sh "$PWD" HEAD bash tools/release/with-source.sh HEAD bash tools/ci/with-projects.sh test "${test_files[@]}" +bash tools/release/release-please-state.sh "$PWD" HEAD bash tools/release/with-source.sh HEAD bash tools/dev/bun.sh test "${test_files[@]}" for shell_test in "${shell_tests[@]}"; do bash "$shell_test"; done +# The complete local check includes the isolated version-pin suite once. +if [ "$metadata" = 1 ]; then bash tools/release/independent-version-pins.test.sh; fi diff --git a/tools/release/release-dependency-plan.mts b/tools/release/release-dependency-plan.mts index ac4eba239..8409c4cbb 100644 --- a/tools/release/release-dependency-plan.mts +++ b/tools/release/release-dependency-plan.mts @@ -19,10 +19,11 @@ export function buildBoundCompatibilityProducts(products) { Object.entries(products) .filter( ([producer, metadata]) => - product.embedded_payload_products?.includes(producer) || - (product.extension?.class === 'external' && - ['liboliphaunt-native', 'liboliphaunt-wasix'].includes(producer)) || - inputs.get(id).has(`${metadata.path}/Cargo.toml`), + producer !== id && + (product.embedded_payload_products?.includes(producer) || + (product.extension?.class === 'external' && + ['liboliphaunt-native', 'liboliphaunt-wasix'].includes(producer)) || + inputs.get(id).has(`${metadata.path}/Cargo.toml`)), ) .map(([producer]) => producer), ), @@ -30,15 +31,45 @@ export function buildBoundCompatibilityProducts(products) { ); } -export function releaseDependencyPlan( - products, - selectedProducts, - { +// Structural per-run input only; this map does not establish configured or authenticated coverage. +export function resolveBuildBoundCompatibilityProducts(products, options = {}) { + const ids = Object.keys(products); + const buildBound = Object.hasOwn(options, 'buildBound') + ? options.buildBound + : buildBoundCompatibilityProducts(products); + if ( + !(buildBound instanceof Map) || + buildBound.size !== ids.length || + [...buildBound.keys()].some( + (consumer) => typeof consumer !== 'string' || !Object.hasOwn(products, consumer), + ) + ) + throw new Error('release-dependency-plan: buildBound must be a complete product Map'); + const snapshot = new Map(); + for (const consumer of ids) { + const producers = buildBound.get(consumer); + if (!(producers instanceof Set)) + throw new Error(`release-dependency-plan: buildBound ${consumer} must be a Set`); + for (const producer of producers) + if ( + typeof producer !== 'string' || + !Object.hasOwn(products, producer) || + producer === consumer + ) + throw new Error( + `release-dependency-plan: buildBound ${consumer} has an unknown or self producer`, + ); + snapshot.set(consumer, new Set(producers)); + } + return snapshot; +} + +export function releaseDependencyPlan(products, selectedProducts, options = {}) { + const buildBound = resolveBuildBoundCompatibilityProducts(products, options); + const { entries = compatibilityVersionEntries(products, { requireSourceProduct: true }), - buildBound = buildBoundCompatibilityProducts(products), readValue = compatibilityVersionValue, - } = {}, -) { + } = options; const selected = new Set(selectedProducts); return entries.map((entry) => { const compiled = diff --git a/tools/release/release-dependency-plan.test.mts b/tools/release/release-dependency-plan.test.mts index c12b168f2..363a1bb68 100644 --- a/tools/release/release-dependency-plan.test.mts +++ b/tools/release/release-dependency-plan.test.mts @@ -1,15 +1,32 @@ import { expect, test } from 'bun:test'; import { + loadProducts, + compatibilityVersionEntries, + compatibilityVersionValue, +} from './release-graph.mts'; +import { + buildBoundCompatibilityProducts, releaseDependencyPlan, requirePublicSupportTransition, + resolveBuildBoundCompatibilityProducts, } from './release-dependency-plan.mts'; -test('selected source consumers retain declarations while compiled payloads name their real inputs', () => { +function fixture() { const products = { sdk: { version: '1.2.0' }, binary: { version: '1.0.1' }, runtime: { version: '2.0.0' }, }; + const buildBound = new Map([ + ['sdk', new Set()], + ['binary', new Set(['runtime'])], + ['runtime', new Set()], + ]); + return { products, buildBound }; +} + +test('selected source consumers retain declarations while compiled payloads name their real inputs', () => { + const { products, buildBound } = fixture(); const entries = ['sdk', 'binary'].map((product) => ({ id: product, product, @@ -18,7 +35,7 @@ test('selected source consumers retain declarations while compiled payloads name })); const plan = releaseDependencyPlan(products, ['sdk', 'binary'], { entries, - buildBound: new Map([['binary', new Set(['runtime'])]]), + buildBound, readValue: () => '1.0.0', }); expect(plan.map(({ version, binding }) => ({ version, binding }))).toEqual([ @@ -28,12 +45,123 @@ test('selected source consumers retain declarations while compiled payloads name expect( releaseDependencyPlan(products, [], { entries, - buildBound: new Map([['binary', new Set(['runtime'])]]), + buildBound, readValue: () => '1.0.0', }).every(({ version }) => version === '1.0.0'), ).toBe(true); }); +test('an absent buildBound option keeps legacy relationships without self dependencies', () => { + const { products } = fixture(); + products.binary.embedded_payload_products = ['binary', 'runtime']; + const expected = new Map([ + ['sdk', new Set()], + ['binary', new Set(['runtime'])], + ['runtime', new Set()], + ]); + expect(buildBoundCompatibilityProducts(products)).toEqual(expected); + expect(resolveBuildBoundCompatibilityProducts(products)).toEqual(expected); + expect( + resolveBuildBoundCompatibilityProducts(products, Object.create({ buildBound: null })), + ).toEqual(expected); +}); + +test('an explicit complete empty map retains held pins instead of merging legacy relationships', () => { + const { products } = fixture(); + products.binary.embedded_payload_products = ['runtime']; + const buildBound = new Map(Object.keys(products).map((id) => [id, new Set()])); + let reads = 0; + const plan = releaseDependencyPlan(products, ['binary'], { + entries: [{ product: 'binary', sourceProduct: 'runtime' }], + buildBound, + readValue: () => { + reads += 1; + return '= 1.0.0'; + }, + }); + expect(plan).toEqual([ + { + product: 'binary', + sourceProduct: 'runtime', + version: '= 1.0.0', + binding: 'declared-requirement', + }, + ]); + expect(reads).toBe(1); +}); + +test('the resolver snapshots every Map and Set without retaining either direction of aliasing', async () => { + const { products, buildBound } = fixture(); + const snapshot = resolveBuildBoundCompatibilityProducts(products, { buildBound }); + expect(snapshot).not.toBe(buildBound); + for (const id of Object.keys(products)) expect(snapshot.get(id)).not.toBe(buildBound.get(id)); + await Promise.resolve(); + buildBound.get('binary').clear(); + buildBound.set('sdk', new Set(['runtime'])); + buildBound.delete('runtime'); + expect(snapshot.get('binary')).toEqual(new Set(['runtime'])); + expect(snapshot.get('sdk')).toEqual(new Set()); + expect(snapshot.has('runtime')).toBe(true); + snapshot.get('sdk').add('binary'); + snapshot.delete('binary'); + expect(buildBound.get('sdk')).toEqual(new Set(['runtime'])); + expect(buildBound.has('binary')).toBe(true); +}); + +test('dependency planning uses its snapshot even when a held-pin reader mutates the supplied map', () => { + const { products, buildBound } = fixture(); + const plan = releaseDependencyPlan(products, ['sdk', 'binary'], { + entries: ['sdk', 'binary'].map((product) => ({ product, sourceProduct: 'runtime' })), + buildBound, + readValue: () => { + buildBound.get('binary').clear(); + return '1.0.0'; + }, + }); + expect(plan.map(({ version, binding }) => ({ version, binding }))).toEqual([ + { version: '1.0.0', binding: 'declared-requirement' }, + { version: '2.0.0', binding: 'compiled-input' }, + ]); +}); + +for (const [name, invalid] of [ + ['undefined', () => undefined], + ['null', () => null], + ['object', () => ({ binary: new Set(['runtime']) })], + ['partial Map', () => new Map([['binary', new Set(['runtime'])]])], + ['extra consumer', (map) => map.set('foreign', new Set())], + [ + 'unknown consumer replacing a required key', + (map) => { + map.delete('sdk'); + return map.set('foreign', new Set()); + }, + ], + ['non-string consumer', (map) => map.set(1, new Set())], + ['non-Set producers', (map) => map.set('binary', ['runtime'])], + ['undefined producers', (map) => map.set('binary', undefined)], + ['unknown producer', (map) => map.set('binary', new Set(['foreign']))], + ['inherited producer name', (map) => map.set('binary', new Set(['constructor']))], + ['non-string producer', (map) => map.set('binary', new Set([1]))], + ['self producer', (map) => map.set('binary', new Set(['binary']))], +]) + test(`invalid injected buildBound rejects ${name} before reading held pins`, () => { + const { products, buildBound } = fixture(); + const supplied = invalid(buildBound); + let reads = 0; + expect(() => + releaseDependencyPlan(products, ['binary'], { + entries: [{ product: 'binary', sourceProduct: 'runtime' }], + buildBound: supplied, + readValue: () => { + reads += 1; + return '1.0.0'; + }, + }), + ).toThrow('buildBound'); + expect(reads).toBe(0); + }); + test('support removal requires the configured pre-1.0 or stable breaking boundary', () => { const base = { product: 'extension', @@ -64,3 +192,21 @@ test('support removal requires the configured pre-1.0 or stable breaking boundar }), ).not.toThrow(); }); + +test('resource admitted consumer stays held when both independent products are selected', () => { + const graph = loadProducts('resource consumer held plan'); + const entry = compatibilityVersionEntries(graph, { requireSourceProduct: true }).find( + (row) => row.product === 'database-resources' && row.sourceProduct === 'liboliphaunt-wasix', + ); + expect(entry).toBeDefined(); + const held = compatibilityVersionValue(entry); + graph['liboliphaunt-wasix'].version = '999.0.0'; + graph['database-resources'].version = '999.0.0'; + const buildBound = new Map(Object.keys(graph).map((id) => [id, new Set()])); + const planned = releaseDependencyPlan(graph, ['database-resources', 'liboliphaunt-wasix'], { + buildBound, + }); + const actual = planned.find((row) => row.product === entry.product && row.id === entry.id); + expect(actual.version).toBe(held); + expect(actual.binding).toBe('declared-requirement'); +}); diff --git a/tools/release/release-graph.mts b/tools/release/release-graph.mts index bbc9b375b..0d7bb14cf 100644 --- a/tools/release/release-graph.mts +++ b/tools/release/release-graph.mts @@ -5,6 +5,7 @@ import { CONTRIB_CARRIERS_PATH, loadContribCarriers, } from '../../src/extensions/artifacts/packages/tools/contrib-carriers.mts'; +import { compatibilityVersionFromText as parseCompatibilityVersionFromText } from './compatibility-version-parser.mts'; import { historyAncestor, historyChanges, @@ -647,41 +648,7 @@ export function compatibilityVersionFromText( text, { prefix = 'release-graph', missingValue = undefined } = {}, ) { - if (entry.parser === 'raw') return text.trim(); - if (entry.parser.startsWith('rust-const:')) { - const name = entry.parser.slice('rust-const:'.length); - if (!/^[A-Z][A-Z0-9_]*$/u.test(name)) { - fail(prefix, `${entry.id} has an invalid Rust constant parser`); - } - const matches = [ - ...text.matchAll( - new RegExp(`(?:pub\\s+)?const\\s+${name}\\s*:[^=]+?=\\s*"([^"]+)"\\s*;`, 'gu'), - ), - ]; - if (matches.length !== 1) { - if (matches.length === 0 && missingValue !== undefined) return missingValue; - fail(prefix, `${entry.id} must name exactly one Rust string constant`); - } - return matches[0][1]; - } - const separator = entry.parser.indexOf(':'); - const type = entry.parser.slice(0, separator); - if (type !== 'json' && type !== 'toml') { - fail(prefix, `${entry.id} uses unsupported compatibility parser ${entry.parser}`); - } - const parts = entry.parser.slice(separator + 1).split('.'); - let data; - try { - data = type === 'json' ? JSON.parse(text) : type === 'toml' ? Bun.TOML.parse(text) : null; - } catch (cause) { - fail(prefix, `${entry.path} is not valid ${type.toUpperCase()}: ${cause.message}`); - } - const value = valueAtPath(data, parts); - if (typeof value !== 'string' || value.length === 0) { - if (value === undefined && missingValue !== undefined) return missingValue; - fail(prefix, `${entry.id} parser ${entry.parser} must resolve to a non-empty string`); - } - return value; + return parseCompatibilityVersionFromText(entry, text, { prefix, missingValue, fail }); } export function productCompatibilityVersion( @@ -1430,35 +1397,12 @@ function releaseProductsForSourceProjects(products, projects, projectIds, prefix return selected; } -export function releaseOrder(products, _projects, selected, prefix = 'release-graph') { - const selectedSet = new Set(selected); - const ordered = []; - const remaining = new Set(selectedSet); - while (remaining.size > 0) { - const ready = []; - for (const product of [...remaining].sort(compareText)) { - const deps = new Set( - Object.values(products[product]?.compatibility_versions ?? {}) - .map((dependency) => dependency?.source_product) - .filter((dependency) => typeof dependency === 'string' && dependency !== product), - ); - const selectedDeps = [...deps].filter((dependency) => selectedSet.has(dependency)); - if (selectedDeps.every((dependency) => ordered.includes(dependency))) { - ready.push(product); - } - } - if (ready.length === 0) { - fail( - prefix, - `release compatibility graph has a dependency cycle: ${JSON.stringify([...remaining].sort(compareText))}`, - ); - } - for (const product of ready) { - ordered.push(product); - remaining.delete(product); - } - } - return ordered; +export function releaseOrder(_products, _projects, selected, _prefix = 'release-graph') { + // Installed compatibility may refer to an older published version, and one + // product can own unrelated Cargo and npm packages. Collapsing those facts + // into product edges invents cycles. Frozen, version-matched package edges + // determine the actual registry mutation order. + return [...new Set(selected)].sort(compareText); } export function buildPlan(graph, files, prefix = 'release-graph') { diff --git a/tools/release/release-project-snapshot.test.mts b/tools/release/release-project-snapshot.test.mts index 1d879059f..46627eb09 100644 --- a/tools/release/release-project-snapshot.test.mts +++ b/tools/release/release-project-snapshot.test.mts @@ -31,7 +31,15 @@ test('release planning consumes resolved dependency scopes independently of publ }; assert.deepEqual(releaseOrder(products, graph, Object.keys(products)), [ 'consumer-build', - 'runtime', 'consumer-production', + 'runtime', ]); }); + +test('product selection accepts held and cross-package compatibility cycles', () => { + const products = { + sdk: { compatibility_versions: { tools: { source_product: 'tools' } } }, + tools: { compatibility_versions: { sdk: { source_product: 'sdk' } } }, + }; + assert.deepEqual(releaseOrder(products, {}, ['tools', 'sdk', 'tools']), ['sdk', 'tools']); +}); diff --git a/tools/release/release-test-environment.test.mts b/tools/release/release-test-environment.test.mts index ee2028809..41b7dc0a5 100644 --- a/tools/release/release-test-environment.test.mts +++ b/tools/release/release-test-environment.test.mts @@ -1,4 +1,8 @@ import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; import { test } from 'node:test'; import { isolatedGitHubTestEnvironment as mutationTestEnvironment } from './testdata/isolated-github-test-environment.mts'; @@ -19,3 +23,63 @@ test('release mutation tests cannot consume a live publish request journal', () { KEEP_ME: 'preserved' }, ); }); + +test('the local release check runs each test once and isolates the version-pin suite', () => { + const root = mkdtempSync(path.join(os.tmpdir(), 'release-test-ownership-')); + const log = path.join(root, 'invocations.log'); + const script = readFileSync(new URL('./release-check.sh', import.meta.url), 'utf8'); + const write = (file: string, content: string) => { + const target = path.join(root, file); + mkdirSync(path.dirname(target), { recursive: true }); + writeFileSync(target, content); + }; + try { + const initialized = spawnSync('git', ['init', '--quiet'], { cwd: root, encoding: 'utf8' }); + assert.equal(initialized.status, 0, initialized.stderr); + write('tools/release/release-check.sh', script); + write( + 'tools/dev/bun.sh', + 'if [[ "${1:-}" == -p ]]; then\n' + + ' printf "%s\\n" "$TEST_RELEASE_CHECK_BUN"\n' + + 'else\n' + + ' printf "unit:%s\\n" "$*" >> "$TEST_RELEASE_CHECK_LOG"\n' + + 'fi\n', + ); + write( + 'tools/release/release-metadata-check.sh', + 'echo metadata >> "$TEST_RELEASE_CHECK_LOG"\n', + ); + write('tools/release/release-please-state.sh', 'shift 2\nexec "$@"\n'); + write('tools/release/with-source.sh', 'shift\nexec "$@"\n'); + write('tools/ci/with-projects.sh', 'exit 97\n'); + write( + 'tools/release/independent-version-pins.test.sh', + 'echo pins >> "$TEST_RELEASE_CHECK_LOG"\n', + ); + write('tools/release/independent-version-pins.test.mts', ''); + write('tools/release/prepare-release-candidate.test.mts', ''); + write('tools/release/unit.test.mts', ''); + write('tools/release/paired.test.mts', ''); + write('tools/release/paired.test.sh', 'echo paired >> "$TEST_RELEASE_CHECK_LOG"\n'); + + for (const [arguments_, expected] of [ + [[], ['metadata', 'unit:test ./tools/release/unit.test.mts', 'paired', 'pins']], + [['--mutation-tests-only'], ['unit:test ./tools/release/unit.test.mts', 'paired']], + ] as const) { + writeFileSync(log, ''); + const result = spawnSync('bash', ['tools/release/release-check.sh', ...arguments_], { + cwd: root, + encoding: 'utf8', + env: { + ...mutationTestEnvironment(), + TEST_RELEASE_CHECK_BUN: process.execPath, + TEST_RELEASE_CHECK_LOG: log, + }, + }); + assert.equal(result.status, 0, `${result.stdout}\n${result.stderr}`); + assert.deepEqual(readFileSync(log, 'utf8').trim().split('\n'), expected); + } + } finally { + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/tools/release/release-verification-shell.test.sh b/tools/release/release-verification-shell.test.sh index a704b7932..5e396192c 100644 --- a/tools/release/release-verification-shell.test.sh +++ b/tools/release/release-verification-shell.test.sh @@ -56,4 +56,8 @@ FAIL_GATE="$first_gate" run release-check-registries.sh --products-json "$produc [[ "$status" == 2 ]] head -n 1 "$scratch/registry-success" > "$scratch/expected" cmp "$scratch/expected" "$CALL_LOG" +run release-check-registries.sh --native-preparation --products-json "$products" --head-ref "$head_commit" +record tools/release/check_release_versions.mts --native-preparation --products-json "$products" \ + --head-ref "$head_commit" --check-registries > "$scratch/expected" +cmp "$scratch/expected" "$CALL_LOG" echo 'Release verification: receipt arguments preserved and failed gates stop subsequent work' diff --git a/tools/release/retained-download.mts b/tools/release/retained-download.mts new file mode 100644 index 000000000..859afbb43 --- /dev/null +++ b/tools/release/retained-download.mts @@ -0,0 +1,63 @@ +import { randomUUID } from 'node:crypto'; +import { promises as fs } from 'node:fs'; +import path from 'node:path'; + +export async function createRetainedDownload(destination: string) { + const absolute = path.resolve(destination); + await fs.mkdir(path.dirname(absolute), { recursive: true }); + try { + await fs.lstat(absolute); + throw new Error(`refusing to replace existing retained download ${absolute}`); + } catch (cause) { + if (cause?.code !== 'ENOENT') throw cause; + } + const temporary = `${absolute}.tmp-${process.pid}-${randomUUID()}`; + let handle: Awaited> | null = await fs.open(temporary, 'wx', 0o600); + let committed = false; + let published: { dev: number; ino: number } | null = null; + const close = async () => { + if (handle === null) return; + const owned = handle; + handle = null; + await owned.close(); + }; + return { + async write(bytes: Uint8Array) { + if (handle === null) throw new Error('retained download is already closed'); + await handle.writeFile(bytes); + }, + async commit() { + if (handle === null) throw new Error('retained download is already closed'); + const ownership = await handle.stat(); + await handle.chmod(0o444); + await close(); + await fs.link(temporary, absolute); + published = ownership; + await fs.unlink(temporary); + committed = true; + return absolute; + }, + async abort() { + if (committed) return; + try { + await close(); + } finally { + try { + if (published !== null) { + const stat = await fs.lstat(absolute).catch((cause) => { + if (cause?.code !== 'ENOENT') throw cause; + return null; + }); + if (stat?.dev === published.dev && stat?.ino === published.ino) { + await fs.unlink(absolute); + } + } + } finally { + await fs.unlink(temporary).catch((cause) => { + if (cause?.code !== 'ENOENT') throw cause; + }); + } + } + }, + }; +} diff --git a/tools/release/snapshot-commit-paths.sh b/tools/release/snapshot-commit-paths.sh new file mode 100644 index 000000000..fc856e64b --- /dev/null +++ b/tools/release/snapshot-commit-paths.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +set -euo pipefail + +[[ "$#" == 3 ]] || { + echo 'usage: snapshot-commit-paths.sh REPOSITORY HEAD NEW_DIRECTORY' >&2 + exit 2 +} +repo="$1"; head_ref="$2"; destination="$3" +[[ "$(git -C "$repo" rev-parse --is-shallow-repository)" == false ]] || { + echo 'commit path capture requires complete Git history' >&2 + exit 1 +} +head="$(git -C "$repo" rev-parse --verify "$head_ref^{commit}")" +mkdir "$destination" +complete=false +trap 'if [[ "$complete" != true ]]; then rm -rf "$destination"; fi' EXIT +printf 'head %s\n' "$head" > "$destination/.parents" + +# One Git traversal captures every reachable commit. --no-renames reports both +# the old deletion and new addition; merge commits compare with their first +# parent, and --root supplies the initial creation. An empty NUL field begins +# each commit frame and cannot be confused with a legal Git filename. +git --no-replace-objects -C "$repo" log '--format=%x00%H %P' --no-show-signature --name-only -z --root --no-renames \ + --diff-merges=first-parent --no-ext-diff --no-textconv --ignore-submodules=none \ + "$head" -- > "$destination/.capture" +expect_sha=false +first_path=false +current='' +commit_frame='^[0-9a-f]{40}( [0-9a-f]{40})*$' +while IFS= read -r -d '' field; do + if [[ -z "$field" ]]; then + expect_sha=true + elif [[ "$expect_sha" == true ]]; then + metadata="${field% }" + current="${metadata%% *}" + [[ "$metadata" =~ $commit_frame && ! -e "$destination/$current" ]] || { + echo 'malformed or duplicate commit frame in Git path capture' >&2 + exit 1 + } + printf '%s\n' "$metadata" >> "$destination/.parents" + : > "$destination/$current" + expect_sha=false + first_path=true + else + [[ -n "$current" ]] || { echo 'missing commit frame in Git path capture' >&2; exit 1; } + # Git inserts exactly one LF between its commit header and the first path. + # Remove that separator, preserving any LF belonging to the filename. + if [[ "$first_path" == true ]]; then + [[ "$field" == $'\n'* ]] || { echo 'missing Git path separator' >&2; exit 1; } + field="${field#$'\n'}" + first_path=false + fi + [[ -n "$field" ]] || { echo 'empty path in Git capture' >&2; exit 1; } + printf '%s\0' "$field" >> "$destination/$current" + fi +done < "$destination/.capture" +[[ -f "$destination/$head" && "$expect_sha" == false ]] || { + echo 'incomplete Git commit path capture' >&2 + exit 1 +} +rm "$destination/.capture" +complete=true diff --git a/tools/release/snapshot-commit-paths.test.mts b/tools/release/snapshot-commit-paths.test.mts new file mode 100644 index 000000000..8918ac31e --- /dev/null +++ b/tools/release/snapshot-commit-paths.test.mts @@ -0,0 +1,290 @@ +import { expect, test } from 'bun:test'; +import { spawnSync } from 'node:child_process'; +import { + existsSync, + mkdirSync, + mkdtempSync, + readdirSync, + renameSync, + rmSync, + writeFileSync, +} from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { readCommitHistory, readCommitPaths } from './commit-paths.mts'; + +const capture = path.join(import.meta.dir, 'snapshot-commit-paths.sh'); +const historyWrapper = path.join(import.meta.dir, 'with-product-history.sh'); +const bunWrapper = path.join(import.meta.dir, '../dev/bun.sh'); + +function run( + command: string, + args: string[], + cwd: string, + environment: Record = {}, +) { + const result = spawnSync(command, args, { + cwd, + encoding: 'utf8', + env: { + ...process.env, + GIT_AUTHOR_NAME: 'Fixture', + GIT_AUTHOR_EMAIL: 'fixture@example.test', + GIT_COMMITTER_NAME: 'Fixture', + GIT_COMMITTER_EMAIL: 'fixture@example.test', + GIT_CONFIG_NOSYSTEM: '1', + GIT_CONFIG_GLOBAL: '/dev/null', + ...environment, + }, + }); + if (result.error || result.status !== 0) { + throw new Error(`${command} ${args.join(' ')} failed: ${result.error ?? result.stderr}`); + } + return result.stdout.trim(); +} + +function repository(check: (root: string, git: (...args: string[]) => string) => void) { + const root = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-commit-paths-')); + const git = (...args: string[]) => run('git', args, root); + git('init', '-q', '-b', 'main'); + try { + check(root, git); + } finally { + rmSync(root, { recursive: true, force: true }); + } +} + +test('real Git capture preserves move-out, move-in, rename, deletion and unusual paths', () => { + repository((root, git) => { + const source = 'products/alpha/src/query.rs'; + const spaced = 'products/alpha/src/space name.rs'; + const newline = 'products/alpha/src/\nline\nname.rs'; + const leadingNewline = '\nroot\nname.rs'; + mkdirSync(path.join(root, 'products/alpha/src'), { recursive: true }); + for (const file of [source, spaced, newline, leadingNewline]) + writeFileSync(path.join(root, file), file); + git('add', '.'); + git('commit', '-qm', 'feat: initial source'); + const initial = git('rev-parse', 'HEAD'); + mkdirSync(path.join(root, 'archive')); + renameSync(path.join(root, source), path.join(root, 'archive/query.rs')); + git('add', '-A'); + git('commit', '-qm', 'fix: move source outside product'); + const movedOut = git('rev-parse', 'HEAD'); + const movedInPath = 'products/alpha/src/moved.rs'; + renameSync(path.join(root, 'archive/query.rs'), path.join(root, movedInPath)); + git('add', '-A'); + git('commit', '-qm', 'fix: restore source into product'); + const movedIn = git('rev-parse', 'HEAD'); + const renamed = 'products/alpha/src/renamed.rs'; + renameSync(path.join(root, movedInPath), path.join(root, renamed)); + git('add', '-A'); + git('commit', '-qm', 'fix: rename source within product'); + const renamedCommit = git('rev-parse', 'HEAD'); + rmSync(path.join(root, renamed)); + git('add', '-A'); + git('commit', '-qm', 'fix: delete source'); + const deleted = git('rev-parse', 'HEAD'); + git('commit', '--allow-empty', '-qm', 'chore: empty commit'); + const empty = git('rev-parse', 'HEAD'); + const destination = path.join(root, 'capture'); + run('bash', [capture, root, empty, destination], root); + expect(readCommitPaths(initial, destination).sort()).toEqual( + [source, spaced, newline, leadingNewline].sort(), + ); + expect(readCommitPaths(movedOut, destination).sort()).toEqual( + [source, 'archive/query.rs'].sort(), + ); + expect(readCommitPaths(movedIn, destination).sort()).toEqual( + ['archive/query.rs', movedInPath].sort(), + ); + expect(readCommitPaths(renamedCommit, destination).sort()).toEqual( + [movedInPath, renamed].sort(), + ); + expect(readCommitPaths(deleted, destination)).toEqual([renamed]); + expect(readCommitPaths(empty, destination)).toEqual([]); + expect(readCommitHistory(destination).head).toBe(empty); + expect(readdirSync(destination).filter((file) => /^[0-9a-f]{40}$/.test(file))).toHaveLength(6); + }); +}); + +test('merge capture compares first parent and also records reachable branch commits', () => { + repository((root, git) => { + const dated = (date: string, ...args: string[]) => + run('git', args, root, { GIT_AUTHOR_DATE: date, GIT_COMMITTER_DATE: date }); + writeFileSync(path.join(root, 'base.txt'), 'base'); + git('add', '.'); + dated('2020-01-01T00:00:00Z', 'commit', '-qm', 'feat: base'); + const base = git('rev-parse', 'HEAD'); + git('checkout', '-qb', 'branch'); + writeFileSync(path.join(root, 'branch.txt'), 'branch'); + git('add', '.'); + dated('2020-01-02T00:00:00Z', 'commit', '-qm', 'feat: branch'); + const branch = git('rev-parse', 'HEAD'); + git('checkout', '-q', 'main'); + writeFileSync(path.join(root, 'main.txt'), 'main'); + git('add', '.'); + dated('2020-01-03T00:00:00Z', 'commit', '-qm', 'fix: main'); + const boundary = git('rev-parse', 'HEAD'); + dated('2020-01-04T00:00:00Z', 'merge', '--no-ff', '-qm', 'feat: merge branch', 'branch'); + const merge = git('rev-parse', 'HEAD'); + const destination = path.join(root, 'capture'); + run('bash', [capture, root, merge, destination], root); + expect(readCommitPaths(merge, destination)).toEqual(['branch.txt']); + expect(readCommitPaths(branch, destination)).toEqual(['branch.txt']); + const history = readCommitHistory(destination); + const after = history.after(boundary); + expect([...after].sort()).toEqual([merge, branch].sort()); + expect(after.has(base)).toBe(false); + expect(history.after(boundary)).toBe(after); + expect(git('log', '--format=%H').split('\n')).toEqual([merge, boundary, branch, base]); + expect([...history.commits]).toEqual([merge, boundary, branch, base]); + expect(history.commits.size).toBe(4); + }); +}); + +test('captured ancestry excludes delivered ancestors even when Git emits them before the boundary', () => { + repository((root, git) => { + const dated = (date: string, ...args: string[]) => + run('git', args, root, { GIT_AUTHOR_DATE: date, GIT_COMMITTER_DATE: date }); + git('commit', '--allow-empty', '-qm', 'chore: root'); + git('checkout', '-qb', 'branch'); + writeFileSync(path.join(root, 'branch.txt'), 'old branch'); + git('add', '.'); + dated('2020-01-10T00:00:00Z', 'commit', '-qm', 'feat: delivered branch'); + const delivered = git('rev-parse', 'HEAD'); + git('checkout', '-q', 'main'); + dated('2020-01-02T00:00:00Z', 'commit', '--allow-empty', '-qm', 'chore: main'); + dated('2020-01-03T00:00:00Z', 'merge', '--no-ff', '-qm', 'Merge branch', 'branch'); + dated('2020-01-04T00:00:00Z', 'commit', '--allow-empty', '-qm', 'chore(release): alpha1.0.0'); + const boundary = git('rev-parse', 'HEAD'); + git('checkout', '-q', 'branch'); + writeFileSync(path.join(root, 'branch.txt'), 'new branch'); + git('add', '.'); + dated('2020-01-20T00:00:00Z', 'commit', '-qm', 'feat: pending branch'); + const pending = git('rev-parse', 'HEAD'); + git('checkout', '-q', 'main'); + dated('2020-01-21T00:00:00Z', 'merge', '--no-ff', '-qm', 'Merge branch again', 'branch'); + const head = git('rev-parse', 'HEAD'); + const order = git('log', '--format=%H').split('\n'); + expect(order.indexOf(delivered)).toBeLessThan(order.indexOf(boundary)); + const destination = path.join(root, 'capture'); + run('bash', [capture, root, head, destination], root); + const history = readCommitHistory(destination); + expect([...history.after(boundary)].sort()).toEqual([head, pending].sort()); + expect(history.after(boundary).has(delivered)).toBe(false); + }); +}); + +test('aggregate product history preserves both paths when source moves outside its owner', () => { + repository((root, git) => { + const source = 'products/alpha/src/query.rs'; + const moved = 'archive/query.rs'; + mkdirSync(path.join(root, 'products/alpha/src'), { recursive: true }); + writeFileSync(path.join(root, source), 'source'); + writeFileSync(path.join(root, 'products/alpha/VERSION'), '1.0.0'); + writeFileSync( + path.join(root, 'release-please-config.json'), + JSON.stringify({ packages: { 'products/alpha': { component: 'alpha' } } }), + ); + writeFileSync( + path.join(root, '.release-please-manifest.json'), + JSON.stringify({ 'products/alpha': '1.0.0' }), + ); + git('add', '.'); + git('commit', '-qm', 'feat: initial product'); + git('tag', 'alpha-v1.0.0'); + git('config', 'diff.renames', 'true'); + mkdirSync(path.join(root, 'archive')); + renameSync(path.join(root, source), path.join(root, moved)); + git('add', '-A'); + git('commit', '-qm', 'fix: move source outside owner'); + const graph = path.join(root, 'graph.json'); + writeFileSync( + graph, + JSON.stringify({ + products: { + alpha: { + path: 'products/alpha', + version: '1.0.0', + tag_prefix: 'alpha-v', + version_files: ['products/alpha/VERSION'], + }, + }, + }), + ); + const check = path.join(root, 'check.mts'); + writeFileSync( + check, + `import { historyChanges } from ${JSON.stringify(path.join(import.meta.dir, 'release-history.mts'))};\nconsole.log(JSON.stringify(historyChanges(process.argv[2], 'alpha-v1.0.0', 'HEAD')));\n`, + ); + const result = run( + 'bash', + [historyWrapper, root, 'HEAD', '', graph, 'bash', bunWrapper, check, root], + root, + ); + expect(JSON.parse(result).sort()).toEqual([source, moved].sort()); + }); +}); + +test('capture rejects shallow history and preserves an existing destination', () => { + repository((root, git) => { + git('commit', '--allow-empty', '-qm', 'chore: root'); + git('commit', '--allow-empty', '-qm', 'chore: head'); + const destination = path.join(root, 'capture'); + mkdirSync(destination); + writeFileSync(path.join(destination, 'keep'), 'existing'); + const existing = spawnSync('bash', [capture, root, 'HEAD', destination], { encoding: 'utf8' }); + expect(existing.status).not.toBe(0); + expect(existsSync(path.join(destination, 'keep'))).toBe(true); + const clone = path.join(root, 'shallow'); + run('git', ['clone', '-q', '--depth=1', `file://${root}`, clone], root); + const failedDestination = path.join(root, 'failed'); + const shallow = spawnSync('bash', [capture, clone, 'HEAD', failedDestination], { + encoding: 'utf8', + }); + expect(shallow.status).not.toBe(0); + expect(shallow.stderr).toContain('complete Git history'); + expect(existsSync(failedDestination)).toBe(false); + }); +}); + +test('reader rejects missing, malformed and truncated captured records', () => { + const directory = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-commit-reader-')); + const sha = 'a'.repeat(40); + try { + expect(() => readCommitPaths('../unsafe', directory)).toThrow('exact SHA'); + expect(() => readCommitPaths(sha, directory)).toThrow(); + writeFileSync(path.join(directory, sha), 'products/alpha/src/query.rs'); + expect(() => readCommitPaths(sha, directory)).toThrow('incomplete'); + writeFileSync(path.join(directory, sha), '../outside\0'); + expect(() => readCommitPaths(sha, directory)).toThrow('unsafe'); + writeFileSync(path.join(directory, sha), 'file\0file\0'); + expect(() => readCommitPaths(sha, directory)).toThrow('duplicate'); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); + +test('ancestry reader rejects incomplete, duplicate and unrelated records', () => { + const directory = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-commit-ancestry-')); + const sha = 'a'.repeat(40); + const parent = 'b'.repeat(40); + const ledger = path.join(directory, '.parents'); + try { + writeFileSync(ledger, `head ${sha}\n${sha} ${parent}\n`); + expect(() => readCommitHistory(directory)).toThrow(`missing ${parent}`); + writeFileSync(ledger, `head ${sha}\n${sha}\n${sha}\n`); + expect(() => readCommitHistory(directory)).toThrow('duplicate'); + writeFileSync(ledger, `head ${sha}\n${sha}\n${parent}\n`); + expect(() => readCommitHistory(directory)).toThrow('outside its head'); + writeFileSync(ledger, `head ${sha}\n${sha}`); + expect(() => readCommitHistory(directory)).toThrow('incomplete'); + writeFileSync(ledger, `head ${sha}\n${sha}\n`); + expect(() => readCommitHistory(directory).after(parent)).toThrow(`missing ${parent}`); + expect(() => readCommitHistory(directory).after('')).toThrow('missing'); + expect(readCommitHistory(directory).after().size).toBe(1); + } finally { + rmSync(directory, { recursive: true, force: true }); + } +}); diff --git a/tools/release/snapshot-commit-paths.test.sh b/tools/release/snapshot-commit-paths.test.sh new file mode 100644 index 000000000..df4df6b33 --- /dev/null +++ b/tools/release/snapshot-commit-paths.test.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +exec bash "$root/tools/dev/bun.sh" test "$root/tools/release/snapshot-commit-paths.test.mts" diff --git a/tools/release/sync-release-pr.mts b/tools/release/sync-release-pr.mts index f0e32fb08..0202fd11e 100644 --- a/tools/release/sync-release-pr.mts +++ b/tools/release/sync-release-pr.mts @@ -1,10 +1,12 @@ #!/usr/bin/env bun import { existsSync, readFileSync, realpathSync, writeFileSync } from 'node:fs'; import path from 'node:path'; +import { cargoSatisfies } from '../../build_defs/languages/cargo-metadata.mts'; import { electronReleaseDependencies } from '../../src/examples/tools/example-release-dependencies.mts'; import { extensionRegistryPackageStrings } from '../../src/extensions/artifacts/packages/tools/extension-registry-packages.mts'; import { currentEvidenceTable } from '../../src/extensions/tools/extension-evidence.mts'; import { catalogPath, readJson } from '../../src/extensions/tools/extension-projections.mts'; +import { isCargoPathCompatibility } from './compatibility-version-parser.mts'; import { requireMatchingWasixRuntime } from './compatibility-version-policy.mts'; import { exampleCargoPolicies, @@ -19,12 +21,11 @@ import { ROOT, } from './release-artifact-targets.mts'; import { - buildBoundCompatibilityProducts, releaseDependencyPlan, + resolveBuildBoundCompatibilityProducts, } from './release-dependency-plan.mts'; import { compatibilityVersionEntries, - loadGraph, loadProducts, productCompatibilityVersion, } from './release-graph.mts'; @@ -40,7 +41,7 @@ export { cargoManifestPaths } from './release-please-transition.mts'; const PREFIX = 'sync-release-pr.mts'; const DEPENDENCY_TABLES = ['dependencies', 'dev-dependencies', 'build-dependencies']; -const LOCKFILES = [path.join(ROOT, 'Cargo.lock')]; +const CARGO_LOCKFILE = path.join(ROOT, 'Cargo.lock'); const BUN_LOCKFILE = path.join(ROOT, 'bun.lock'); const RELEASE_PLEASE_CONFIG = path.join(ROOT, 'release-please-config.json'); const RELEASE_PLEASE_MANIFEST = path.join(ROOT, '.release-please-manifest.json'); @@ -84,14 +85,16 @@ function jsonText(value) { return `${JSON.stringify(value, null, 2)}\n`; } -function writeTextIfChanged(file, text, changes, detail, { write }) { - const before = readText(file); +function writeTextIfChanged(file, text, changes, detail, { write, observeUpdate }) { + const beforeBytes = readFileSync(file); + const before = beforeBytes.toString('utf8'); if (before === text) { return; } changes.push({ path: file, detail }); if (write) { writeFileSync(file, text, 'utf8'); + observeUpdate?.({ path: rel(file), before: beforeBytes, after: Buffer.from(text) }); } } @@ -160,9 +163,14 @@ function setJsonPath(data, dotted, expected, context) { export function syncTomlStringPath(text, dotted, expected, context) { const entryParts = dotted.split('.'); if (entryParts.at(-1) === 'version' && DEPENDENCY_TABLES.includes(entryParts.at(-3))) { + // Compatibility reads normalize Cargo's exact requirement to its installed + // version. Writing that value must retain the authored constraint. + const actual = valueAt(Bun.TOML.parse(text), entryParts); + const exact = typeof actual === 'string' ? /^(=\s*)/u.exec(actual) : null; + const requirement = exact && !expected.startsWith('=') ? `${exact[1]}${expected}` : expected; return replaceUniqueDependencyVersion( text, - { entryParts: entryParts.slice(0, -1), expected, name: context }, + { entryParts: entryParts.slice(0, -1), expected: requirement, name: context }, context, ); } @@ -232,7 +240,7 @@ function replaceTopLevelArrayAssignment(text, key, values, context) { return output.join(''); } -function syncExtensionRegistryMetadata(changes, { write }) { +function syncExtensionRegistryMetadata(changes, { write, observeUpdate }) { const expectedPublishTargets = ['github-release-assets', 'npm', 'maven-central', 'crates-io']; for (const product of exactExtensionReleaseProducts(PREFIX)) { const releaseToml = path.join(ROOT, packagePath(product), 'release.toml'); @@ -259,13 +267,13 @@ function syncExtensionRegistryMetadata(changes, { write }) { updated, changes, 'synced explicit extension registry metadata', - { write }, + { write, observeUpdate }, ); } } } -function syncReleasePleaseBootstrapBoundary(changes, { write }) { +function syncReleasePleaseBootstrapBoundary(changes, { write, observeUpdate }) { const config = readJsonObject(RELEASE_PLEASE_CONFIG); const manifest = readJsonObject(RELEASE_PLEASE_MANIFEST); const updated = releasePleaseConfigAfterBootstrapConsumption(config, manifest); @@ -275,18 +283,22 @@ function syncReleasePleaseBootstrapBoundary(changes, { write }) { jsonText(updated), changes, 'removed the consumed one-time bootstrap-sha history boundary', - { write }, + { write, observeUpdate }, ); } } -async function syncCompatibilityVersions(changes, { write, transitions }) { +async function syncCompatibilityVersions( + changes, + { write, observeUpdate, transitions, buildBound }, +) { const links = compatibilityEntriesForBumpedProducts(compatibilityVersionLinks(), transitions); const plan = releaseDependencyPlan( graphProducts(), transitions.map(({ product }) => product), { entries: links, + buildBound, }, ); for (const { id: specId, sourceProduct, path: pathText, parser, version: expected } of plan) { @@ -297,7 +309,7 @@ async function syncCompatibilityVersions(changes, { write, transitions }) { `${expected}\n`, changes, `${specId} -> ${sourceProduct} ${expected}`, - { write }, + { write, observeUpdate }, ); continue; } @@ -305,21 +317,25 @@ async function syncCompatibilityVersions(changes, { write, transitions }) { const data = readJsonObject(file); const detail = setJsonPath(data, parser.split(':', 2)[1], expected, specId); if (detail !== undefined) { - writeTextIfChanged(file, jsonText(data), changes, detail, { write }); + writeTextIfChanged(file, jsonText(data), changes, detail, { write, observeUpdate }); } continue; } if (parser.startsWith('toml:')) { + // Cargo requirements were projected before scope froze; runtime/helper + // metadata retains its separate installed-artifact adoption contract. + if (isCargoPathCompatibility({ id: specId, path: pathText, parser }, readText(file))) + continue; const [text, detail] = setTomlStringPath(file, parser.split(':', 2)[1], expected, specId); if (text !== undefined && detail !== undefined) { - writeTextIfChanged(file, text, changes, detail, { write }); + writeTextIfChanged(file, text, changes, detail, { write, observeUpdate }); } continue; } if (parser.startsWith('rust-const:')) { const [text, detail] = setRustConstString(file, parser.split(':', 2)[1], expected, specId); if (text !== undefined && detail !== undefined) { - writeTextIfChanged(file, text, changes, detail, { write }); + writeTextIfChanged(file, text, changes, detail, { write, observeUpdate }); } continue; } @@ -335,9 +351,10 @@ async function expectedNativeToolsOptionalVersions() { return versions; } -async function syncNativeToolsOptionalDependencies(changes, { write, transitions }) { +async function syncNativeToolsOptionalDependencies(changes, { write, observeUpdate, transitions }) { return syncOptionalRuntimeDependencies(changes, { write, + observeUpdate, transitions, ownerProduct: 'postgres-tools-native', packageFile: NATIVE_TOOLS_FACADE_PACKAGE, @@ -347,7 +364,7 @@ async function syncNativeToolsOptionalDependencies(changes, { write, transitions async function syncOptionalRuntimeDependencies( changes, - { write, transitions, ownerProduct, packageFile, runtimeVersions }, + { write, observeUpdate, transitions, ownerProduct, packageFile, runtimeVersions }, ) { if (!transitions.some(({ product }) => product === ownerProduct)) { return; @@ -370,11 +387,11 @@ async function syncOptionalRuntimeDependencies( } } if (changed) { - writeTextIfChanged(file, jsonText(data), changes, details.join('; '), { write }); + writeTextIfChanged(file, jsonText(data), changes, details.join('; '), { write, observeUpdate }); } } -function syncElectronExampleDependencies(changes, { write, transitions }) { +function syncElectronExampleDependencies(changes, { write, observeUpdate, transitions }) { if ( transitions.length && !transitions.some(({ product }) => ['oliphaunt-js', 'postgres-tools-native'].includes(product)) @@ -402,14 +419,15 @@ function syncElectronExampleDependencies(changes, { write, transitions }) { if (changed) { writeTextIfChanged(ELECTRON_EXAMPLE_PACKAGE, jsonText(data), changes, details.join('; '), { write, + observeUpdate, }); } } -function localCargoPackagesByManifest() { +function localCargoPackagesByManifest(manifests) { const packages = new Map(); - for (const manifest of cargoManifestPaths()) { - const data = Bun.TOML.parse(readText(manifest)); + for (const manifest of manifests?.keys() ?? cargoManifestPaths()) { + const data = manifests?.get(manifest).manifest ?? Bun.TOML.parse(readText(manifest)); const packageConfig = data.package; if ( packageConfig === null || @@ -440,10 +458,11 @@ function localCargoPackageVersions() { return versions; } -function iterDependencyTables(manifest) { +export function iterDependencyTables(manifest) { const tables = []; for (const [parts, owner] of [ [[], manifest], + ...(manifest.workspace ? [[['workspace'], manifest.workspace]] : []), ...Object.entries(manifest.target ?? {}).map(([target, value]) => [['target', target], value]), ]) { for (const tableName of DEPENDENCY_TABLES) { @@ -455,8 +474,38 @@ function iterDependencyTables(manifest) { return tables; } -export function desiredCargoPathDependencyVersion(current, packageVersion) { - if (current === '*') return current; +export function cargoPathDependencyConsumers( + file, + manifest, + manifests, + owners, + binding, + products = {}, +) { + const consumerOwners = (file, manifest) => { + const relative = path.isAbsolute(file) ? rel(file) : file; + return [ + owners.get(manifest.package?.name), + ...Object.entries(products) + .filter(([, product]) => product.embedded_cargo_manifests?.includes(relative)) + .map(([id]) => id), + ]; + }; + const consumers = + file === 'Cargo.toml' + ? [...manifests] + .filter(([, { manifest }]) => + iterDependencyTables(manifest).some( + ([, table]) => table[binding.name]?.workspace === true, + ), + ) + .flatMap(([file, { manifest }]) => consumerOwners(file, manifest)) + : consumerOwners(file, manifest); + return [...new Set(consumers.filter(Boolean))]; +} + +export function desiredCargoPathDependencyVersion(current, packageVersion, updateMinimum = false) { + if (!updateMinimum && cargoSatisfies(packageVersion, current)) return current; return current.startsWith('=') ? `=${packageVersion}` : packageVersion; } @@ -505,7 +554,9 @@ export function cargoPathDependencyBindings( continue; } const dependencyManifest = path.resolve(path.dirname(manifestPath), pathValue, 'Cargo.toml'); - const packageInfo = localPackages.get(realpathIfExists(dependencyManifest)); + const packageInfo = + localPackages.get(dependencyManifest) ?? + localPackages.get(realpathIfExists(dependencyManifest)); if (packageInfo === undefined) { continue; } @@ -525,27 +576,40 @@ export function cargoPathDependencyBindings( return desired; } -function syncCargoPathDependencyPins(changes, { write, transitions }) { - const localPackages = localCargoPackagesByManifest(); +function syncCargoPathDependencyPins(changes, { write, observeUpdate, transitions, buildBound }) { + const manifests = new Map( + cargoManifestPaths().map((file) => { + const text = readText(file); + return [file, { text, manifest: Bun.TOML.parse(text) }]; + }), + ); + const localPackages = localCargoPackagesByManifest(manifests); const products = graphProducts(); - const compiled = buildBoundCompatibilityProducts(products); + const owners = new Map( + Object.entries(products).flatMap(([id, product]) => + (product.registry_packages ?? []) + .filter((name) => name.startsWith('crates:')) + .map((name) => [name.slice(7), id]), + ), + ); + const selected = new Set(transitions.map(({ product }) => product)); const selectedRoots = transitions .map(({ product }) => ({ product, root: path.join(ROOT, packagePath(product)) })) .sort( (left, right) => right.root.length - left.root.length || compareText(left.root, right.root), ); - for (const manifestPath of cargoManifestPaths()) { + for (const [manifestPath, { text: source, manifest: parsed }] of manifests) { + const file = rel(manifestPath); const owner = selectedRoots.find( ({ root }) => manifestPath === root || manifestPath.startsWith(`${root}${path.sep}`), ); - if (!owner) continue; - const source = readText(manifestPath); - const parsed = Bun.TOML.parse(source); + if (!owner && file !== 'Cargo.toml') continue; + const priorVersions = priorCargoPathDependencyVersions(manifestPath); const bindings = cargoPathDependencyBindings( source, manifestPath, localPackages, - priorCargoPathDependencyVersions(manifestPath), + priorVersions, ).filter((binding) => { const dependency = valueAt(parsed, binding.entryParts); const input = path.resolve(path.dirname(manifestPath), dependency.path); @@ -556,7 +620,40 @@ function syncCargoPathDependencyPins(changes, { write, transitions }) { input.startsWith(path.join(ROOT, metadata.path) + path.sep), ) .sort((left, right) => right[1].path.length - left[1].path.length)[0]?.[0]; - return compiled.get(owner.product)?.has(producer); + const consumers = cargoPathDependencyConsumers( + file, + parsed, + manifests, + owners, + binding, + products, + ); + const producerSelected = selected.has(producer); + const adopts = producerSelected && consumers.some((product) => selected.has(product)); + if (adopts) + binding.expected = desiredCargoPathDependencyVersion( + binding.expected, + products[producer].version, + true, + ); + if (file === 'Cargo.toml' && producerSelected) { + const held = consumers.filter( + (product) => + !selected.has(product) && + (buildBound.get(product)?.has(producer) || + products[product].registry_packages?.some((name) => name.startsWith('crates:'))), + ); + const prior = priorVersions.get(JSON.stringify(binding.entryParts)) ?? dependency.version; + if (held.length && binding.expected !== prior) + fail( + 'workspace Cargo requirement ' + + binding.name + + ' would change unselected public consumers: ' + + held.join(', '), + ); + return adopts; + } + return adopts || Boolean(owner && buildBound.get(owner.product)?.has(producer)); }); const result = syncExampleCargoManifestText(source, { policy: { crateDir: path.dirname(manifestPath) }, @@ -564,7 +661,10 @@ function syncCargoPathDependencyPins(changes, { write, transitions }) { label: rel(manifestPath), }); if (result.details.length) - writeTextIfChanged(manifestPath, result.text, changes, result.details.join('; '), { write }); + writeTextIfChanged(manifestPath, result.text, changes, result.details.join('; '), { + write, + observeUpdate, + }); } } @@ -755,7 +855,7 @@ export function syncExampleCargoManifestText( return { text: updated, details }; } -function syncExampleCargoRegistryPins(changes, { write, transitions }) { +function syncExampleCargoRegistryPins(changes, { write, observeUpdate, transitions }) { const bindings = exampleCargoReleaseVersionBindings(); for (const policy of exampleCargoPolicies()) { if ( @@ -779,7 +879,10 @@ function syncExampleCargoRegistryPins(changes, { write, transitions }) { fail(cause.message); } if (result.details.length > 0) { - writeTextIfChanged(file, result.text, changes, result.details.join('; '), { write }); + writeTextIfChanged(file, result.text, changes, result.details.join('; '), { + write, + observeUpdate, + }); } } } @@ -807,7 +910,7 @@ function replaceVersionLine(line, version) { return `${match[1]}"${version}"${match[2]}${newline}`; } -export function syncLockfile(lockfile, versions, changes, { write }) { +export function syncLockfile(lockfile, versions, changes, { write, observeUpdate }) { const data = Bun.TOML.parse(readText(lockfile)); if (!Array.isArray(data.package)) { fail(`${rel(lockfile)} is missing [[package]] entries`); @@ -847,15 +950,16 @@ export function syncLockfile(lockfile, versions, changes, { write }) { } } if (fileChanges.length > 0) { - writeTextIfChanged(lockfile, lines.join(''), changes, fileChanges.join('; '), { write }); + writeTextIfChanged(lockfile, lines.join(''), changes, fileChanges.join('; '), { + write, + observeUpdate, + }); } } -function syncLockfiles(changes, { write }) { +function syncLockfiles(changes, { write, observeUpdate }) { const versions = localCargoPackageVersions(); - for (const lockfile of LOCKFILES) { - syncLockfile(lockfile, versions, changes, { write }); - } + syncLockfile(CARGO_LOCKFILE, versions, changes, { write, observeUpdate }); // Bun can defer workspace dependency changes when their package versions also change. const lock = Bun.JSONC.parse(readText(BUN_LOCKFILE)); const updated = []; @@ -867,10 +971,13 @@ function syncLockfiles(changes, { write }) { } } if (updated.length > 0) - writeTextIfChanged(BUN_LOCKFILE, jsonText(lock), changes, 'npm workspace versions', { write }); + writeTextIfChanged(BUN_LOCKFILE, jsonText(lock), changes, 'npm workspace versions', { + write, + observeUpdate, + }); } -function syncExtensionEvidenceSummary(changes, { write }) { +function syncExtensionEvidenceSummary(changes, { write, observeUpdate }) { const identity = { commit: process.env.OLIPHAUNT_EVIDENCE_COMMIT, tree: process.env.OLIPHAUNT_EVIDENCE_TREE, @@ -884,7 +991,7 @@ function syncExtensionEvidenceSummary(changes, { write }) { expected, changes, 'extension evidence summary', - { write }, + { write, observeUpdate }, ); } @@ -921,13 +1028,15 @@ function parseArgs(argv) { return args; } -async function main(argv) { +export async function syncReleasePr(argv = process.argv.slice(2), options = {}) { const args = parseArgs(argv); + const buildBound = resolveBuildBoundCompatibilityProducts(graphProducts(), options); const changes = []; const write = !args.check; + const observeUpdate = options.observeUpdate; const transitions = releasePleaseWorktreeTransitions(ROOT, { prefix: PREFIX }); - syncReleasePleaseBootstrapBoundary(changes, { write }); - await syncCompatibilityVersions(changes, { write, transitions }); + syncReleasePleaseBootstrapBoundary(changes, { write, observeUpdate }); + await syncCompatibilityVersions(changes, { write, observeUpdate, transitions, buildBound }); if ( transitions.some(({ product }) => product === 'oliphaunt-wasix-ts') && (write || changes.length === 0) @@ -955,14 +1064,14 @@ async function main(argv) { { prefix: PREFIX }, ); } - syncExtensionRegistryMetadata(changes, { write }); - await syncNativeToolsOptionalDependencies(changes, { write, transitions }); - syncElectronExampleDependencies(changes, { write, transitions }); - syncCargoPathDependencyPins(changes, { write, transitions }); - syncExampleCargoRegistryPins(changes, { write, transitions }); - syncLockfiles(changes, { write }); + syncExtensionRegistryMetadata(changes, { write, observeUpdate }); + await syncNativeToolsOptionalDependencies(changes, { write, observeUpdate, transitions }); + syncElectronExampleDependencies(changes, { write, observeUpdate, transitions }); + syncCargoPathDependencyPins(changes, { write, observeUpdate, transitions, buildBound }); + syncExampleCargoRegistryPins(changes, { write, observeUpdate, transitions }); + syncLockfiles(changes, { write, observeUpdate }); if (!args.generatedReleaseCheck) { - syncExtensionEvidenceSummary(changes, { write }); + syncExtensionEvidenceSummary(changes, { write, observeUpdate }); } if (changes.length === 0) { console.log('release PR derived files are in sync'); @@ -994,7 +1103,7 @@ export function releaseDerivedPathInventory() { return [ ...new Set( [ - ...LOCKFILES, + CARGO_LOCKFILE, BUN_LOCKFILE, RELEASE_PLEASE_CONFIG, ELECTRON_EXAMPLE_PACKAGE, @@ -1013,5 +1122,5 @@ export function releaseDerivedPathInventory() { } if (import.meta.main) { - await main(Bun.argv.slice(2)); + await syncReleasePr(Bun.argv.slice(2)); } diff --git a/tools/release/sync-release-pr.sh b/tools/release/sync-release-pr.sh index e10fe1238..db6f8ff36 100755 --- a/tools/release/sync-release-pr.sh +++ b/tools/release/sync-release-pr.sh @@ -4,7 +4,7 @@ cd "$(git -C "$(dirname "${BASH_SOURCE[0]}")" rev-parse --show-toplevel)" OLIPHAUNT_EVIDENCE_COMMIT="$(git rev-parse 'HEAD^{commit}')" OLIPHAUNT_EVIDENCE_TREE="$(git rev-parse 'HEAD^{tree}')" export OLIPHAUNT_EVIDENCE_COMMIT OLIPHAUNT_EVIDENCE_TREE -bash tools/ci/with-projects.sh --exec bash tools/release/release-please-state.sh "$PWD" HEAD \ +bash tools/release/release-please-state.sh "$PWD" HEAD \ bash tools/release/with-product-history.sh "$PWD" HEAD '' @workspace \ bash tools/dev/bun.sh tools/release/sync-release-pr.mts "$@" diff --git a/tools/release/sync-release-pr.test.mts b/tools/release/sync-release-pr.test.mts index 852526875..f08dd9934 100644 --- a/tools/release/sync-release-pr.test.mts +++ b/tools/release/sync-release-pr.test.mts @@ -4,13 +4,17 @@ import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import test from 'node:test'; +import { renderToml } from '../../build_defs/languages/cargo-metadata.mts'; +import { loadProducts } from './release-graph.mts'; import { cargoManifestPaths, cargoPathDependencyBindings, desiredCargoPathDependencyVersion, priorCargoPathDependencyVersions, + releaseDerivedPathInventory, syncExampleCargoManifestText, syncLockfile, + syncReleasePr, syncTomlStringPath, } from './sync-release-pr.mts'; @@ -34,6 +38,107 @@ if (mode === 'inventory') { process.exit(0); } +if (mode === 'workspace-floor') { + const core = 'liboliphaunt-native-bindings'; + const manifests = ['src/native/rust-bindings/Cargo.toml', 'src/native/sdks/rust/Cargo.toml']; + if (stage === 'prepare') { + const versionsFile = path.join(root, '.release-please-manifest.json'); + const versions = JSON.parse(readFileSync(versionsFile, 'utf8')); + for (const file of manifests) { + const text = readFileSync(path.join(root, file), 'utf8'); + const version = Bun.TOML.parse(text).package.version; + const next = version.replace(/\d+$/u, (patch) => String(Number(patch) + 1)); + writeFileSync( + path.join(root, file), + text.replace('version = "' + version + '"', 'version = "' + next + '"'), + ); + versions[path.posix.dirname(file)] = next; + } + writeFileSync(versionsFile, JSON.stringify(versions, null, 2) + '\n'); + } else if (stage === 'hold') { + const file = path.join(root, loadProducts()['oliphaunt-query'].path, 'Cargo.toml'); + const manifest = Bun.TOML.parse(readFileSync(file, 'utf8')); + manifest.dependencies ??= {}; + manifest.dependencies[core] = { workspace: true }; + writeFileSync(file, renderToml(manifest)); + } else { + const before = readFileSync(path.join(root, 'Cargo.toml')); + const buildBound = new Map(Object.keys(loadProducts()).map((id) => [id, new Set()])); + await syncReleasePr(['--check'], { buildBound }); + assert.deepEqual(readFileSync(path.join(root, 'Cargo.toml')), before); + throw new Error('missing workspace floor was accepted'); + } + process.exit(0); +} + +// Invoke the real runner in a disposable full checkout; no production CLI option. +if (mode === 'supplier-map') { + const sdk = path.join(root, 'src/native/sdks/rust/Cargo.toml'); + const broker = path.join(root, 'src/native/broker/Cargo.toml'); + const manifestFile = path.join(root, '.release-please-manifest.json'); + const parsed = (file) => Bun.TOML.parse(readFileSync(file, 'utf8')); + const next = (version) => version.replace(/\d+$/u, (patch) => String(Number(patch) + 1)); + if (stage === 'prepare') { + const manifest = JSON.parse(readFileSync(manifestFile, 'utf8')); + for (const file of [sdk, broker]) { + const version = parsed(file).package.version; + writeFileSync( + file, + readFileSync(file, 'utf8').replace( + `version = "${version}"`, + `version = "${next(version)}"`, + ), + ); + manifest[path.relative(root, path.dirname(file)).split(path.sep).join('/')] = next(version); + } + writeFileSync(manifestFile, `${JSON.stringify(manifest, null, 2)}\n`); + process.exit(0); + } + const buildBound = new Map( + Object.keys(loadProducts('sync fixture')).map((id) => [id, new Set()]), + ); + const constantFile = path.join(root, 'src/native/sdks/rust/src/broker.rs'); + const beforeSdk = parsed(sdk); + const beforeConstant = readFileSync(constantFile, 'utf8'); + if (stage === 'held') { + // The checkout already contains version transitions and stale derived pins. + // Unknown supplier coverage must reject before changing any derived file. + const before = new Map( + releaseDerivedPathInventory().map((file) => [file, readFileSync(path.join(root, file))]), + ); + for (const unknown of [undefined, new Map()]) { + await assert.rejects(syncReleasePr([], { buildBound: unknown }), /buildBound/u); + for (const [file, contents] of before) + assert.deepEqual(readFileSync(path.join(root, file)), contents); + } + } else { + assert.equal(stage, 'current'); + buildBound.get('oliphaunt-rust').add('oliphaunt-broker'); + } + await syncReleasePr([], { buildBound }); + const afterSdk = parsed(sdk); + const expected = + stage === 'held' + ? beforeSdk.package.metadata.oliphaunt['broker-version'] + : parsed(broker).package.version; + assert.equal(afterSdk.package.metadata.oliphaunt['broker-version'], expected); + assert.equal(afterSdk.dependencies['oliphaunt-broker'].version, parsed(broker).package.version); + assert.match( + readFileSync(constantFile, 'utf8'), + new RegExp(`BROKER_RELEASE_VERSION: &str = "${expected.replaceAll('.', '[.]')}"`, 'u'), + ); + assert.equal( + afterSdk.package.metadata.oliphaunt['native-version'], + beforeSdk.package.metadata.oliphaunt['native-version'], + ); + assert.equal( + afterSdk.dependencies['oliphaunt-query'].version, + beforeSdk.dependencies['oliphaunt-query'].version, + ); + if (stage === 'held') assert.equal(readFileSync(constantFile, 'utf8'), beforeConstant); + process.exit(0); +} + test('compatibility sync handles inline and table Cargo dependencies without changing other fields', () => { for (const source of [ `[dependencies]\nquery = { path = '../query', version = '0.1.0', features = ['one'] }\n`, @@ -50,10 +155,47 @@ test('compatibility sync handles inline and table Cargo dependencies without cha } }); +test('unknown supplied relationships reject the actual sync runner before derived writes', async () => { + const file = path.resolve(import.meta.dir, '../../release-please-config.json'); + const before = readFileSync(file); + for (const buildBound of [undefined, null, new Map()]) { + await assert.rejects(syncReleasePr([], { buildBound }), /buildBound/u); + assert.deepEqual(readFileSync(file), before); + } +}); + test('release sync preserves wildcard Cargo path dependencies', () => { assert.equal(desiredCargoPathDependencyVersion('*', '0.2.0'), '*'); + assert.equal(desiredCargoPathDependencyVersion('0.2.0', '0.2.1'), '0.2.0'); + assert.equal(desiredCargoPathDependencyVersion('^0.2.0', '0.2.1'), '^0.2.0'); + assert.equal(desiredCargoPathDependencyVersion('=0.2.0', '0.2.1'), '=0.2.1'); assert.equal(desiredCargoPathDependencyVersion('0.1.0', '0.2.0'), '0.2.0'); assert.equal(desiredCargoPathDependencyVersion('=0.1.0', '0.2.0'), '=0.2.0'); + assert.equal(desiredCargoPathDependencyVersion('^0.2.0', '0.2.1', true), '0.2.1'); +}); + +test('compatibility sync preserves exact installed Cargo requirements and their operator spacing', () => { + for (const requirement of ['=0.1.1', '= 0.1.1']) { + for (const source of [ + `[dependencies]\nquery = { version = '${requirement}', features = ['one'] }\n`, + `[dependencies.query]\nversion = '${requirement}'\nfeatures = ['one']\n`, + `[workspace.dependencies]\nquery = { version = '${requirement}' }\n`, + ]) { + const dotted = source.startsWith('[workspace.') + ? 'workspace.dependencies.query.version' + : 'dependencies.query.version'; + assert.deepEqual(syncTomlStringPath(source, dotted, '0.1.1', 'consumer'), { + text: source, + detail: undefined, + }); + const result = syncTomlStringPath(source, dotted, '0.1.2', 'consumer'); + const expected = Bun.TOML.parse(source); + (expected.workspace?.dependencies ?? expected.dependencies).query.version = + requirement.replace('0.1.1', '0.1.2'); + assert.deepEqual(Bun.TOML.parse(result.text), expected); + assert.equal(syncTomlStringPath(result.text, dotted, '0.1.2', 'consumer').detail, undefined); + } + } }); test('release sync updates table-form Cargo pins and keeps target-specific requirements distinct', () => { @@ -106,16 +248,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" ['serde', '9.9.9'], ]); const checkChanges = []; - syncLockfile(lockfile, versions, checkChanges, { write: false }); + const observed = []; + const observeUpdate = (update) => observed.push(update); + syncLockfile(lockfile, versions, checkChanges, { write: false, observeUpdate }); assert.equal(readFileSync(lockfile, 'utf8'), initial); + assert.deepEqual(observed, []); assert.deepEqual( checkChanges.map(({ detail }) => detail), ['oliphaunt 0.0.0 -> 0.1.0'], ); const writeChanges = []; - syncLockfile(lockfile, versions, writeChanges, { write: true }); + syncLockfile(lockfile, versions, writeChanges, { write: true, observeUpdate }); const updated = readFileSync(lockfile, 'utf8'); + assert.equal(observed.length, 1); + assert.deepEqual(observed[0].before, Buffer.from(initial)); + assert.deepEqual(observed[0].after, readFileSync(lockfile)); + syncLockfile(lockfile, versions, [], { write: true, observeUpdate }); + assert.equal(observed.length, 1); assert.match(updated, /name = "oliphaunt"\nversion = "0[.]1[.]0"/u); assert.match(updated, /name = "serde"\nversion = "1[.]0[.]0"\nsource =/u); assert.deepEqual( diff --git a/tools/release/sync-release-pr.test.sh b/tools/release/sync-release-pr.test.sh index d57a02144..8a20c8fb3 100644 --- a/tools/release/sync-release-pr.test.sh +++ b/tools/release/sync-release-pr.test.sh @@ -40,3 +40,72 @@ bun tools/release/sync-release-pr.mts --check --check-generated-release > "$scra [[ "$status" == 2 ]] rg -q 'mutually exclusive' "$scratch/result" echo 'Release sync: real tracked/untracked Cargo inventory and prior constraints passed' + +# The imported runner uses its own checkout's canonical catalog and real snapshots. +repo="$scratch/suppliers" +git clone --quiet --shared "$source_root" "$repo" +fixture_files=( + build_defs/languages/cargo-metadata.mts + tools/packaging/cargo-manifest.mts + tools/release/bazel-release-metadata.mts + tools/release/bazel-shipping-inputs.mts + tools/release/compatibility-version-parser.mts + tools/release/example-cargo-versions.mts + tools/release/native-supplier-artifacts.mts + tools/release/native-extension-final-inputs.mts + tools/release/release-artifact-targets.mts + tools/release/release-dependency-plan.mts + tools/release/sync-release-pr.mts + tools/release/sync-release-pr.test.mts +) +for file in "${fixture_files[@]}"; do + cp "$source_root/$file" "$repo/$file" +done +printf '/node_modules\n' >> "$repo/.git/info/exclude" +ln -s "$source_root/node_modules" "$repo/node_modules" +cd "$repo" +git config user.name Fixture +git config user.email fixture@example.invalid +git add -- "${fixture_files[@]}" +git commit --allow-empty -qm 'test: source controller baseline' +baseline="$(git rev-parse HEAD)" +bash tools/dev/bun.sh tools/release/sync-release-pr.test.mts supplier-map "$repo" prepare +git add .release-please-manifest.json src/native/sdks/rust/Cargo.toml src/native/broker/Cargo.toml +git commit -qm 'chore(release): select broker and source SDK independently' +OLIPHAUNT_EVIDENCE_COMMIT="$(git rev-parse 'HEAD^{commit}')" +OLIPHAUNT_EVIDENCE_TREE="$(git rev-parse 'HEAD^{tree}')" +export OLIPHAUNT_EVIDENCE_COMMIT OLIPHAUNT_EVIDENCE_TREE +for stage in held current; do + bash tools/release/release-please-state.sh "$repo" HEAD \ + bash tools/release/with-product-history.sh "$repo" HEAD '' @workspace \ + bash tools/dev/bun.sh tools/release/sync-release-pr.test.mts supplier-map "$repo" "$stage" +done +echo 'Release sync: supplied held/current relationships and unknown-before-write admission passed' + +# A root workspace binding has no product directory owner. Check the same +# public-inheritor decision used by release preparation without changing Files. +git reset --hard -q "$baseline" +bash tools/dev/bun.sh tools/release/sync-release-pr.test.mts workspace-floor "$repo" prepare +git add .release-please-manifest.json src/native/rust-bindings/Cargo.toml src/native/sdks/rust/Cargo.toml +git commit -qm 'chore(release): select Core and source SDK' +OLIPHAUNT_EVIDENCE_COMMIT="$(git rev-parse 'HEAD^{commit}')" +OLIPHAUNT_EVIDENCE_TREE="$(git rev-parse 'HEAD^{tree}')" +export OLIPHAUNT_EVIDENCE_COMMIT OLIPHAUNT_EVIDENCE_TREE +check_floor() { + bash tools/release/release-please-state.sh "$repo" HEAD \ + bash tools/release/with-product-history.sh "$repo" HEAD '' @workspace \ + bash tools/dev/bun.sh tools/release/sync-release-pr.test.mts workspace-floor "$repo" check +} +workspace_before="$(git hash-object Cargo.toml)" +status=0 +check_floor > "$scratch/floor-check" 2>&1 || status=$? +[[ "$status" == 1 ]] +rg -q '^Cargo.toml: liboliphaunt-native-bindings' "$scratch/floor-check" +[[ "$(git hash-object Cargo.toml)" == "$workspace_before" ]] +bash tools/dev/bun.sh tools/release/sync-release-pr.test.mts workspace-floor "$repo" hold +status=0 +check_floor > "$scratch/held-check" 2>&1 || status=$? +[[ "$status" == 2 ]] +rg -q 'would change unselected public consumers: oliphaunt-query' "$scratch/held-check" +[[ "$(git hash-object Cargo.toml)" == "$workspace_before" ]] +echo 'Release sync: missing workspace floor and held public inheritor checks passed' diff --git a/tools/release/testdata/download-build-artifacts-github.mts b/tools/release/testdata/download-build-artifacts-github.mts index 5ecaf699c..178b2c721 100644 --- a/tools/release/testdata/download-build-artifacts-github.mts +++ b/tools/release/testdata/download-build-artifacts-github.mts @@ -2,6 +2,20 @@ import assert from 'node:assert/strict'; import crypto from 'node:crypto'; import fs from 'node:fs'; +const native = process.env.FAKE_NATIVE_ORIGIN === 'true'; +const nativeCase = process.env.FAKE_NATIVE_CASE; +const mixed = nativeCase?.startsWith('mixed') === true; +const nativeSourceCommit = process.env.FAKE_NATIVE_SOURCE_COMMIT || 'a'.repeat(40); +const nativeSourceTree = process.env.FAKE_NATIVE_SOURCE_TREE || 'b'.repeat(40); +const jobCase = process.env.FAKE_JOB_CASE || ''; +let snapshotReads = 0; +if (nativeCase === 'mixed-pending') { + process.env.OLIPHAUNT_GITHUB_READ_BASE_DELAY_MS = '0'; + process.env.OLIPHAUNT_GITHUB_READ_MAX_DELAY_MS = '0'; +} +let now = Date.now(); +if (jobCase === 'pending-deadline') Date.now = () => now; + globalThis.fetch = async (input, options) => { const url = new URL(input); assert.equal(url.origin, 'https://api.github.com'); @@ -40,40 +54,198 @@ globalThis.fetch = async (input, options) => { const bytes = fs.readFileSync(process.env.FAKE_ARTIFACT_ARCHIVE); const identity = { id: Number(process.env.FAKE_ARTIFACT_ID || '101'), - name: 'exact-artifact', + name: native ? 'native-build-evidence-x86_64' : 'exact-artifact', size_in_bytes: bytes.length, expired: false, digest: 'sha256:' + crypto.createHash('sha256').update(bytes).digest('hex'), + created_at: '2026-10-11T01:01:00Z', + workflow_run: { id: 77, head_sha: 'a'.repeat(40) }, + ...(native + ? { + created_at: + nativeCase === 'stale-artifact' ? '2026-10-10T01:00:00Z' : '2026-10-11T01:01:00Z', + workflow_run: { + id: 77, + head_sha: nativeCase === 'artifact-source' ? 'f'.repeat(40) : nativeSourceCommit, + }, + } + : {}), }; + if (mixed) { + const old = { ...identity, id: 102, name: 'native-build-evidence-aarch64' }; + const retry = { ...old, id: 103, created_at: '2026-10-11T02:01:00Z' }; + return Response.json({ + artifacts: nativeCase === 'mixed-stale' ? [identity, old] : [identity, old, retry], + }); + } + if (nativeCase === 'digest') identity.digest = 'sha256:' + 'f'.repeat(64); + if (nativeCase === 'artifact-missing') identity.name = 'other-artifact'; + if (nativeCase === 'artifact-window-missing') delete identity.created_at; + if (nativeCase === 'artifact-head-missing') delete identity.workflow_run.head_sha; return Response.json({ - artifacts: [identity, { ...identity, id: 102, name: 'exact-artifact-near-match' }], + artifacts: [ + identity, + { + ...identity, + id: 102, + name: nativeCase === 'artifact-ambiguous' ? identity.name : 'exact-artifact-near-match', + }, + ], }); } if (/actions\/runs\/77\/jobs/.test(endpoint)) { + const pending = + jobCase.startsWith('pending-') && + (snapshotReads === 1 || ['pending-timeout', 'pending-deadline'].includes(jobCase)); const jobs = [ - { id: 501, name: 'Qualified', status: 'completed', conclusion: 'success', run_attempt: 1 }, + { + id: 501, + run_id: 77, + head_sha: native ? nativeSourceCommit : 'a'.repeat(40), + name: native ? 'Linux runtime (x86_64)' : 'Qualified', + status: pending ? 'in_progress' : 'completed', + conclusion: pending + ? null + : nativeCase === 'job-failure' || ['pending-failure', 'failure'].includes(jobCase) + ? 'failure' + : jobCase === 'cancelled' + ? 'cancelled' + : 'success', + run_attempt: nativeCase === 'job-attempt' ? 2 : 1, + created_at: '2026-10-11T00:59:59Z', + started_at: '2026-10-11T01:00:00Z', + completed_at: pending ? null : '2026-10-11T01:02:00Z', + }, ]; + if (mixed) { + const retry = { + ...jobs[0], + id: 503, + name: 'Linux runtime (aarch64)', + run_attempt: 2, + created_at: '2026-10-11T01:59:59Z', + status: nativeCase === 'mixed-pending' ? 'in_progress' : 'completed', + started_at: '2026-10-11T02:00:00Z', + completed_at: nativeCase === 'mixed-pending' ? null : '2026-10-11T02:02:00Z', + conclusion: + nativeCase === 'mixed-pending' + ? null + : nativeCase === 'mixed-failed' + ? 'failure' + : nativeCase === 'mixed-cancelled' + ? 'cancelled' + : 'success', + }; + // Partial reruns inherit completed roles with new IDs/attempts and their original execution window. + const inherited = { + ...jobs[0], + id: 505, + run_attempt: 2, + created_at: '2026-10-11T02:00:00Z', + }; + const all = [jobs[0], { ...jobs[0], id: 502, name: retry.name }, inherited, retry]; + if (nativeCase === 'mixed-ambiguous') all.push({ ...retry, id: 504 }); + return Response.json({ + jobs: url.searchParams.get('filter') === 'all' ? all : [inherited, retry], + }); + } + if (native) + jobs.push({ + id: 502, + name: 'Unrelated WASIX lane', + status: 'completed', + conclusion: 'failure', + run_attempt: 1, + }); + if (nativeCase === 'job-window-missing') delete jobs[0].started_at; + if (jobCase === 'pending-producer-drift' && snapshotReads > 1) jobs[0].id = 502; + if (jobCase.startsWith('cache-other-')) + jobs.push({ + ...jobs[0], + id: 502, + name: 'Second producer', + status: jobCase === 'cache-other-pending' ? 'in_progress' : 'completed', + conclusion: jobCase === 'cache-other-pending' ? null : 'success', + completed_at: jobCase === 'cache-other-pending' ? null : jobs[0].completed_at, + }); + if (jobCase === 'missing') jobs.length = 0; if (process.env.FAKE_DUPLICATE_JOB === 'true') jobs.push({ ...jobs[0], id: 502 }); return Response.json({ jobs }); } if (/actions\/runs\/77$/.test(endpoint)) { + snapshotReads += 1; + if (jobCase === 'pending-deadline') now += 160_000; + if (jobCase === 'pending-404' && snapshotReads > 1) + return new Response('not found', { status: 404 }); return Response.json({ id: 77, - head_sha: 'a'.repeat(40), + head_sha: + nativeCase === 'source' || (jobCase === 'pending-source-drift' && snapshotReads > 1) + ? 'f'.repeat(40) + : native + ? nativeSourceCommit + : 'a'.repeat(40), workflow_id: 9, - run_attempt: 1, + run_attempt: + nativeCase === 'attempt' + ? 0 + : mixed || (jobCase === 'pending-rerun-drift' && snapshotReads > 1) + ? 2 + : 1, status: process.env.FAKE_RUN_STATUS || 'completed', conclusion: process.env.FAKE_RUN_CONCLUSION || 'success', + path: '.github/workflows/ci.yml', + event: jobCase === 'event' ? 'push' : 'workflow_dispatch', + head_branch: 'main', + pull_requests: [], + ...(native + ? { + path: + nativeCase === 'run-workflow' + ? '.github/workflows/other.yml' + : '.github/workflows/bazel.yml', + event: + nativeCase === 'event' + ? 'pull_request' + : process.env.FAKE_NATIVE_EVENT || 'workflow_dispatch', + head_branch: + nativeCase === 'ref' ? 'other' : process.env.FAKE_NATIVE_HEAD_BRANCH || 'main', + pull_requests: [], + } + : {}), }); } - if (/actions\/workflows\/9$/.test(endpoint)) return Response.json({ id: 9, name: 'CI' }); - if (/actions\/artifacts\/101\/zip$/.test(endpoint)) { + if (/actions\/workflows\/9$/.test(endpoint)) + return Response.json({ + id: 9, + name: native ? 'Native Bazel qualification' : 'CI', + path: '.github/workflows/ci.yml', + ...(native + ? { + path: + nativeCase === 'workflow' + ? '.github/workflows/other.yml' + : '.github/workflows/bazel.yml', + } + : {}), + }); + if (/git\/commits\/[0-9a-f]{40}$/.test(endpoint)) + return Response.json({ + sha: url.pathname.split('/').at(-1), + tree: { sha: nativeCase === 'tree' ? 'f'.repeat(40) : nativeSourceTree }, + }); + if (/actions\/artifacts\/(101|103)\/zip$/.test(endpoint)) { const state = process.env.FAKE_GH_STATE; const count = fs.existsSync(state) ? Number(fs.readFileSync(state, 'utf8')) : 0; fs.writeFileSync(state, String(count + 1)); if (process.env.FAKE_MODE === 'transient' && count === 0) return new Response('unavailable', { status: 503 }); if (process.env.FAKE_MODE === 'permanent') return new Response('not found', { status: 404 }); + if (native && process.env.FAKE_NATIVE_MUTATE_LOCAL_PACKET) + fs.writeFileSync( + process.env.FAKE_NATIVE_MUTATE_LOCAL_PACKET, + '{"changedAfterAuthenticatedRead":true}', + ); return new Response(fs.readFileSync(process.env.FAKE_ARTIFACT_ARCHIVE)); } throw new Error('unexpected GitHub endpoint ' + endpoint); diff --git a/tools/release/testdata/extension-release-fixture.mts b/tools/release/testdata/extension-release-fixture.mts index 40bb592b0..0889d48ce 100644 --- a/tools/release/testdata/extension-release-fixture.mts +++ b/tools/release/testdata/extension-release-fixture.mts @@ -40,6 +40,9 @@ export function fixture() { ? { exact_extension_runtime: false } : {}), ...(id === 'oliphaunt-extension-vector' ? { extension: { class: 'external' } } : {}), + ...(id === 'oliphaunt-wasix-napi' + ? { embedded_payload_products: ['liboliphaunt-wasix'] } + : {}), }, ]), ); diff --git a/tools/release/testdata/native-prepare-continuation-fixture.mts b/tools/release/testdata/native-prepare-continuation-fixture.mts new file mode 100644 index 000000000..ea3ffed76 --- /dev/null +++ b/tools/release/testdata/native-prepare-continuation-fixture.mts @@ -0,0 +1,220 @@ +import assert from 'node:assert/strict'; +import { createHash } from 'node:crypto'; +import { zipArchive } from '../../packaging/testdata/zip-fixture.mts'; +import { + nativePrepareIntentName, + recordNativePrepareIntent, +} from '../native-prepare-continuation.mts'; + +export function nativePrepareContinuationFixture( + sourceSha = 'a'.repeat(40), + sourceTree = 'b'.repeat(40), + nativeRunId = 88, + nativeAttempt = 1, + originalAttempt = 1, +) { + const repository = { full_name: 'f0rr0/oliphaunt', id: 123 }; + const original = { + id: 41, + workflow_id: 7, + name: 'Release', + path: '.github/workflows/release.yml', + event: 'workflow_dispatch', + display_title: 'Release / prepare-release-pr / main', + head_sha: sourceSha, + head_branch: 'main', + repository, + head_repository: repository, + run_attempt: originalAttempt, + status: 'completed', + conclusion: 'success', + }; + const native = { + ...original, + id: nativeRunId, + workflow_id: 9, + name: 'Native Bazel qualification', + path: '.github/workflows/bazel.yml', + display_title: 'Native / main', + html_url: `https://github.com/f0rr0/oliphaunt/actions/runs/${nativeRunId}`, + run_attempt: nativeAttempt, + }; + const environment = { + GITHUB_REPOSITORY: repository.full_name, + GITHUB_EVENT_NAME: 'workflow_dispatch', + GITHUB_REF: 'refs/heads/main', + GITHUB_WORKFLOW_REF: 'f0rr0/oliphaunt/.github/workflows/release.yml@refs/heads/main', + GITHUB_SHA: sourceSha, + GITHUB_RUN_ID: '41', + GITHUB_RUN_ATTEMPT: String(originalAttempt), + RELEASE_OPERATION: 'prepare-release-pr', + NATIVE_PENDING_RUN_ID: String(nativeRunId), + NATIVE_PENDING_RUN_ATTEMPT: String(nativeAttempt), + }; + const intent = recordNativePrepareIntent(environment, { sha: sourceSha, tree: sourceTree }); + const bytes = zipArchive([{ name: 'intent.json', data: JSON.stringify(intent) }]); + const artifact = { + id: 501, + name: nativePrepareIntentName(originalAttempt), + size_in_bytes: bytes.length, + expired: false, + digest: `sha256:${createHash('sha256').update(bytes).digest('hex')}`, + workflow_run: { + id: original.id, + repository_id: 123, + head_repository_id: 123, + head_sha: sourceSha, + head_branch: 'main', + }, + }; + const state = { + original, + native, + intent, + artifact, + bytes, + environment, + sourceTree, + currentMain: sourceSha, + required: 'success', + producer: 'success', + hasIntent: true, + requests: [], + posts: [], + originalReads: 0, + advanceBeforePost: false, + ambiguous: false, + requiredAttempt: undefined, + upload: undefined, + indexedOriginals: undefined, + responses: new Map(), + budgets: [], + downloads: [], + sleeps: [], + now: 0, + nativeReads: 0, + advanceNativeBeforePost: false, + }; + const prefix = 'repos/f0rr0/oliphaunt'; + const observe = (endpoint, value, options) => { + state.requests.push(endpoint); + state.budgets.push(options?.deadlineMs ?? options?.timeoutMs); + const sequence = state.responses.get(endpoint); + let result = sequence?.length ? sequence.shift() : value; + if (typeof result === 'function') result = result(); + if (result instanceof Error) throw result; + return structuredClone(result); + }; + const io = { + read: async (endpoint, options) => { + if (endpoint === prefix) return observe(endpoint, repository, options); + if (endpoint === `${prefix}/actions/runs/41`) { + if (++state.originalReads === 2 && state.advanceBeforePost) + state.original.run_attempt = originalAttempt + 1; + return observe(endpoint, state.original, options); + } + if (endpoint === `${prefix}/actions/runs/${nativeRunId}`) { + if (++state.nativeReads === 2 && state.advanceNativeBeforePost) + state.native.run_attempt = nativeAttempt + 1; + return observe(endpoint, state.native, options); + } + if (endpoint === `${prefix}/git/commits/${sourceSha}`) + return observe(endpoint, { sha: sourceSha, tree: { sha: state.sourceTree } }, options); + if (endpoint === `${prefix}/git/ref/heads/main`) + return observe(endpoint, { object: { sha: state.currentMain } }, options); + throw new Error(`Unexpected continuation read: ${endpoint}`); + }, + list: async (endpoint, field, options) => { + if (endpoint === `${prefix}/actions/workflows` && field === 'workflows') + return observe( + endpoint, + [state.original, state.native].map((row) => ({ + id: row.workflow_id, + name: row.name, + path: row.path, + })), + options, + ); + if ( + endpoint === + `${prefix}/actions/workflows/7/runs?head_sha=${sourceSha}&event=workflow_dispatch` && + field === 'workflow_runs' + ) + return observe(endpoint, state.indexedOriginals ?? [state.original], options); + if (endpoint === `${prefix}/actions/runs/41/artifacts` && field === 'artifacts') + return observe(endpoint, state.hasIntent ? [state.artifact] : [], options); + if (/\/actions\/runs\/41\/attempts\/[1-9][0-9]*\/jobs$/u.test(endpoint) && field === 'jobs') + return observe( + endpoint, + [ + { + id: 701, + name: 'Resolve native qualification for preparation', + run_attempt: Number(endpoint.split('/').at(-2)), + status: 'completed', + conclusion: state.producer, + steps: [ + { + name: 'Retain pending Prepare intent', + status: 'completed', + conclusion: + state.upload ?? + (state.hasIntent && endpoint.includes(`/attempts/${originalAttempt}/`) + ? 'success' + : 'skipped'), + }, + ], + }, + ], + options, + ); + if ( + endpoint === + `${prefix}/actions/runs/${nativeRunId}/attempts/${state.native.run_attempt}/jobs` && + field === 'jobs' + ) + return observe( + endpoint, + [ + { + id: 702, + name: 'Required', + run_attempt: state.requiredAttempt ?? state.native.run_attempt, + status: 'completed', + conclusion: state.required, + }, + ], + options, + ); + throw new Error(`Unexpected continuation list: ${endpoint} (${field})`); + }, + download: async (id, options) => { + assert.equal(id, 501); + state.downloads.push(id); + state.budgets.push(options?.timeoutMs); + return state.bytes; + }, + rerun: async (id) => { + assert.equal(id, 41); + state.posts.push(id); + if (state.ambiguous) throw new Error('Prepare rerun outcome is unknown'); + state.original.run_attempt = originalAttempt + 1; + state.original.status = 'queued'; + }, + }; + const event = (which = 'native') => ({ + repository, + action: 'completed', + workflow_run: { ...(which === 'native' ? state.native : state.original) }, + }); + const readOptions = { + environment: {}, + now: () => state.now, + sleep: async (milliseconds) => { + state.sleeps.push(milliseconds); + state.now += milliseconds; + }, + random: () => 0.5, + }; + return { state, io, event, readOptions }; +} diff --git a/tools/release/testdata/native-source-carriers/captured-publication.json b/tools/release/testdata/native-source-carriers/captured-publication.json new file mode 100644 index 000000000..68768e5a5 --- /dev/null +++ b/tools/release/testdata/native-source-carriers/captured-publication.json @@ -0,0 +1,283 @@ +{ + "provenance": { + "repository": "f0rr0/oliphaunt", + "captured": "2026-10-11", + "publicApi": "saved completed-publication live audit; immutable local Git blobs and ancestry at exact source SHA", + "registries": [ + "https://crates.io/api/v1/crates/oliphaunt-query/0.1.1", + "https://registry.npmjs.org/%40oliphaunt%2Fts-query/0.1.1" + ] + }, + "pullRequests": [ + { + "number": 223, + "state": "closed", + "title": "chore(release): prepare main releases", + "body": ":robot: I have created a release *beep* *boop*\n---\n\n\n
liboliphaunt-native: 0.3.0\n\n## [0.3.0]() (2026-09-29)\n\n\n### \u26a0 BREAKING CHANGES\n\n* **mobile:** native runtime ABI advances to 12 for streaming archive APIs; rebuild native clients and workers with matching artifacts.\n* **sdk:** Native extension lists use typed selections, and native TypeScript restore accepts a directory storage descriptor instead of a path.\n\n### Features\n\n* **mobile:** add unified iOS and Android broker modes ([#219](https://github.com/f0rr0/oliphaunt/issues/219)) ([6f205e9](https://github.com/f0rr0/oliphaunt/commit/6f205e966c6ce404f252ddcc5c5c1b0b8da47e31))\n\n\n### Bug Fixes\n\n* **ci:** unify Bun test entrypoints and import Swift signing keys ([#214](https://github.com/f0rr0/oliphaunt/issues/214)) ([a7724ef](https://github.com/f0rr0/oliphaunt/commit/a7724efe3ebda8c7f2e1af64d66b64fed645e3bf))\n* **sdk:** align resource loading and extension selection ([#216](https://github.com/f0rr0/oliphaunt/issues/216)) ([b25d496](https://github.com/f0rr0/oliphaunt/commit/b25d49655de694525544c5553e77bdd83b2e1632))\n\n\n### Code Refactoring\n\n* model product dependencies and simplify qualification ([#209](https://github.com/f0rr0/oliphaunt/issues/209)) ([e058785](https://github.com/f0rr0/oliphaunt/commit/e0587850e153fb8f8866711aa73717ca37bdb657))\n* organize sources by native and WASIX runtime families ([#215](https://github.com/f0rr0/oliphaunt/issues/215)) ([a8f9bfe](https://github.com/f0rr0/oliphaunt/commit/a8f9bfe75f4cff0426f0089eb248783efacbde2e))\n
\n\n
oliphaunt-rust: 0.3.0\n\n## [0.3.0]() (2026-09-29)\n\n\n### \u26a0 BREAKING CHANGES\n\n* **mobile:** native runtime ABI advances to 12 for streaming archive APIs; rebuild native clients and workers with matching artifacts.\n* **sdk:** Native extension lists use typed selections, and native TypeScript restore accepts a directory storage descriptor instead of a path.\n\n### Features\n\n* **mobile:** add unified iOS and Android broker modes ([#219](https://github.com/f0rr0/oliphaunt/issues/219)) ([6f205e9](https://github.com/f0rr0/oliphaunt/commit/6f205e966c6ce404f252ddcc5c5c1b0b8da47e31))\n\n\n### Bug Fixes\n\n* **ci:** unify Bun test entrypoints and import Swift signing keys ([#214](https://github.com/f0rr0/oliphaunt/issues/214)) ([a7724ef](https://github.com/f0rr0/oliphaunt/commit/a7724efe3ebda8c7f2e1af64d66b64fed645e3bf))\n* **sdk:** align resource loading and extension selection ([#216](https://github.com/f0rr0/oliphaunt/issues/216)) ([b25d496](https://github.com/f0rr0/oliphaunt/commit/b25d49655de694525544c5553e77bdd83b2e1632))\n\n\n### Code Refactoring\n\n* model product dependencies and simplify qualification ([#209](https://github.com/f0rr0/oliphaunt/issues/209)) ([e058785](https://github.com/f0rr0/oliphaunt/commit/e0587850e153fb8f8866711aa73717ca37bdb657))\n* organize sources by native and WASIX runtime families ([#215](https://github.com/f0rr0/oliphaunt/issues/215)) ([a8f9bfe](https://github.com/f0rr0/oliphaunt/commit/a8f9bfe75f4cff0426f0089eb248783efacbde2e))\n
\n\n
oliphaunt-broker: 0.3.0\n\n## [0.3.0]() (2026-09-29)\n\n\n### \u26a0 BREAKING CHANGES\n\n* **mobile:** native runtime ABI advances to 12 for streaming archive APIs; rebuild native clients and workers with matching artifacts.\n* **sdk:** Native extension lists use typed selections, and native TypeScript restore accepts a directory storage descriptor instead of a path.\n\n### Features\n\n* **mobile:** add unified iOS and Android broker modes ([#219](https://github.com/f0rr0/oliphaunt/issues/219)) ([6f205e9](https://github.com/f0rr0/oliphaunt/commit/6f205e966c6ce404f252ddcc5c5c1b0b8da47e31))\n\n\n### Bug Fixes\n\n* **sdk:** align resource loading and extension selection ([#216](https://github.com/f0rr0/oliphaunt/issues/216)) ([b25d496](https://github.com/f0rr0/oliphaunt/commit/b25d49655de694525544c5553e77bdd83b2e1632))\n\n\n### Code Refactoring\n\n* organize sources by native and WASIX runtime families ([#215](https://github.com/f0rr0/oliphaunt/issues/215)) ([a8f9bfe](https://github.com/f0rr0/oliphaunt/commit/a8f9bfe75f4cff0426f0089eb248783efacbde2e))\n
\n\n
oliphaunt-swift: 0.8.0\n\n## [0.8.0]() (2026-09-29)\n\n\n### \u26a0 BREAKING CHANGES\n\n* **mobile:** native runtime ABI advances to 12 for streaming archive APIs; rebuild native clients and workers with matching artifacts.\n* **sdk:** Native extension lists use typed selections, and native TypeScript restore accepts a directory storage descriptor instead of a path.\n\n### Features\n\n* **mobile:** add unified iOS and Android broker modes ([#219](https://github.com/f0rr0/oliphaunt/issues/219)) ([6f205e9](https://github.com/f0rr0/oliphaunt/commit/6f205e966c6ce404f252ddcc5c5c1b0b8da47e31))\n\n\n### Bug Fixes\n\n* **sdk:** align resource loading and extension selection ([#216](https://github.com/f0rr0/oliphaunt/issues/216)) ([b25d496](https://github.com/f0rr0/oliphaunt/commit/b25d49655de694525544c5553e77bdd83b2e1632))\n\n\n### Code Refactoring\n\n* organize sources by native and WASIX runtime families ([#215](https://github.com/f0rr0/oliphaunt/issues/215)) ([a8f9bfe](https://github.com/f0rr0/oliphaunt/commit/a8f9bfe75f4cff0426f0089eb248783efacbde2e))\n
\n\n
oliphaunt-kotlin: 0.3.0\n\n## [0.3.0]() (2026-09-29)\n\n\n### \u26a0 BREAKING CHANGES\n\n* **mobile:** native runtime ABI advances to 12 for streaming archive APIs; rebuild native clients and workers with matching artifacts.\n* **sdk:** Native extension lists use typed selections, and native TypeScript restore accepts a directory storage descriptor instead of a path.\n\n### Features\n\n* **mobile:** add unified iOS and Android broker modes ([#219](https://github.com/f0rr0/oliphaunt/issues/219)) ([6f205e9](https://github.com/f0rr0/oliphaunt/commit/6f205e966c6ce404f252ddcc5c5c1b0b8da47e31))\n\n\n### Bug Fixes\n\n* **ci:** unify Bun test entrypoints and import Swift signing keys ([#214](https://github.com/f0rr0/oliphaunt/issues/214)) ([a7724ef](https://github.com/f0rr0/oliphaunt/commit/a7724efe3ebda8c7f2e1af64d66b64fed645e3bf))\n* **sdk:** align resource loading and extension selection ([#216](https://github.com/f0rr0/oliphaunt/issues/216)) ([b25d496](https://github.com/f0rr0/oliphaunt/commit/b25d49655de694525544c5553e77bdd83b2e1632))\n\n\n### Code Refactoring\n\n* model product dependencies and simplify qualification ([#209](https://github.com/f0rr0/oliphaunt/issues/209)) ([e058785](https://github.com/f0rr0/oliphaunt/commit/e0587850e153fb8f8866711aa73717ca37bdb657))\n* organize sources by native and WASIX runtime families ([#215](https://github.com/f0rr0/oliphaunt/issues/215)) ([a8f9bfe](https://github.com/f0rr0/oliphaunt/commit/a8f9bfe75f4cff0426f0089eb248783efacbde2e))\n
\n\n
oliphaunt-extension-pg-hashids: 0.3.0\n\n## [0.3.0]() (2026-09-29)\n\n\n### \u26a0 BREAKING CHANGES\n\n* **sdk:** Native extension lists use typed selections, and native TypeScript restore accepts a directory storage descriptor instead of a path.\n* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.\n* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))\n\n### Features\n\n* introduce oliphaunt ([a4f438c](https://github.com/f0rr0/oliphaunt/commit/a4f438c3b2770a841efc8eb9864b474eb76e6114))\n* unify native and WASIX runtimes and SDKs ([#129](https://github.com/f0rr0/oliphaunt/issues/129)) ([fae2bd7](https://github.com/f0rr0/oliphaunt/commit/fae2bd7bde00ae436d9b62ba6a37d919679ac790))\n\n\n### Bug Fixes\n\n* **ci:** unify Bun test entrypoints and import Swift signing keys ([#214](https://github.com/f0rr0/oliphaunt/issues/214)) ([a7724ef](https://github.com/f0rr0/oliphaunt/commit/a7724efe3ebda8c7f2e1af64d66b64fed645e3bf))\n* **runtime:** close mobile package and readiness gaps [skip ci] ([60b9df9](https://github.com/f0rr0/oliphaunt/commit/60b9df9de1d710d6faeb34114ac66409b689cf22))\n* **sdk:** align resource loading and extension selection ([#216](https://github.com/f0rr0/oliphaunt/issues/216)) ([b25d496](https://github.com/f0rr0/oliphaunt/commit/b25d49655de694525544c5553e77bdd83b2e1632))\n\n\n### Code Refactoring\n\n* **ci:** model independent product dependencies ([#173](https://github.com/f0rr0/oliphaunt/issues/173)) ([2d5f90c](https://github.com/f0rr0/oliphaunt/commit/2d5f90c837ef7ecd8b43c2547e4b3c9b04767121))\n* model product dependencies and simplify qualification ([#209](https://github.com/f0rr0/oliphaunt/issues/209)) ([e058785](https://github.com/f0rr0/oliphaunt/commit/e0587850e153fb8f8866711aa73717ca37bdb657))\n* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127)) ([c45082d](https://github.com/f0rr0/oliphaunt/commit/c45082dc522f04ed0f020464282ed79150f83ecc))\n
\n\n
oliphaunt-extension-pg-ivm: 0.3.0\n\n## [0.3.0]() (2026-09-29)\n\n\n### \u26a0 BREAKING CHANGES\n\n* **sdk:** Native extension lists use typed selections, and native TypeScript restore accepts a directory storage descriptor instead of a path.\n* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.\n* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))\n\n### Features\n\n* introduce oliphaunt ([a4f438c](https://github.com/f0rr0/oliphaunt/commit/a4f438c3b2770a841efc8eb9864b474eb76e6114))\n* unify native and WASIX runtimes and SDKs ([#129](https://github.com/f0rr0/oliphaunt/issues/129)) ([fae2bd7](https://github.com/f0rr0/oliphaunt/commit/fae2bd7bde00ae436d9b62ba6a37d919679ac790))\n\n\n### Bug Fixes\n\n* **ci:** unify Bun test entrypoints and import Swift signing keys ([#214](https://github.com/f0rr0/oliphaunt/issues/214)) ([a7724ef](https://github.com/f0rr0/oliphaunt/commit/a7724efe3ebda8c7f2e1af64d66b64fed645e3bf))\n* **runtime:** close mobile package and readiness gaps [skip ci] ([60b9df9](https://github.com/f0rr0/oliphaunt/commit/60b9df9de1d710d6faeb34114ac66409b689cf22))\n* **sdk:** align resource loading and extension selection ([#216](https://github.com/f0rr0/oliphaunt/issues/216)) ([b25d496](https://github.com/f0rr0/oliphaunt/commit/b25d49655de694525544c5553e77bdd83b2e1632))\n\n\n### Code Refactoring\n\n* **ci:** model independent product dependencies ([#173](https://github.com/f0rr0/oliphaunt/issues/173)) ([2d5f90c](https://github.com/f0rr0/oliphaunt/commit/2d5f90c837ef7ecd8b43c2547e4b3c9b04767121))\n* model product dependencies and simplify qualification ([#209](https://github.com/f0rr0/oliphaunt/issues/209)) ([e058785](https://github.com/f0rr0/oliphaunt/commit/e0587850e153fb8f8866711aa73717ca37bdb657))\n* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127)) ([c45082d](https://github.com/f0rr0/oliphaunt/commit/c45082dc522f04ed0f020464282ed79150f83ecc))\n
\n\n
oliphaunt-extension-pg-textsearch: 0.3.0\n\n## [0.3.0]() (2026-09-29)\n\n\n### \u26a0 BREAKING CHANGES\n\n* **sdk:** Native extension lists use typed selections, and native TypeScript restore accepts a directory storage descriptor instead of a path.\n* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.\n* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))\n\n### Features\n\n* introduce oliphaunt ([a4f438c](https://github.com/f0rr0/oliphaunt/commit/a4f438c3b2770a841efc8eb9864b474eb76e6114))\n* unify native and WASIX runtimes and SDKs ([#129](https://github.com/f0rr0/oliphaunt/issues/129)) ([fae2bd7](https://github.com/f0rr0/oliphaunt/commit/fae2bd7bde00ae436d9b62ba6a37d919679ac790))\n\n\n### Bug Fixes\n\n* **ci:** unify Bun test entrypoints and import Swift signing keys ([#214](https://github.com/f0rr0/oliphaunt/issues/214)) ([a7724ef](https://github.com/f0rr0/oliphaunt/commit/a7724efe3ebda8c7f2e1af64d66b64fed645e3bf))\n* **runtime:** close mobile package and readiness gaps [skip ci] ([60b9df9](https://github.com/f0rr0/oliphaunt/commit/60b9df9de1d710d6faeb34114ac66409b689cf22))\n* **sdk:** align resource loading and extension selection ([#216](https://github.com/f0rr0/oliphaunt/issues/216)) ([b25d496](https://github.com/f0rr0/oliphaunt/commit/b25d49655de694525544c5553e77bdd83b2e1632))\n\n\n### Code Refactoring\n\n* **ci:** model independent product dependencies ([#173](https://github.com/f0rr0/oliphaunt/issues/173)) ([2d5f90c](https://github.com/f0rr0/oliphaunt/commit/2d5f90c837ef7ecd8b43c2547e4b3c9b04767121))\n* model product dependencies and simplify qualification ([#209](https://github.com/f0rr0/oliphaunt/issues/209)) ([e058785](https://github.com/f0rr0/oliphaunt/commit/e0587850e153fb8f8866711aa73717ca37bdb657))\n* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127)) ([c45082d](https://github.com/f0rr0/oliphaunt/commit/c45082dc522f04ed0f020464282ed79150f83ecc))\n
\n\n
oliphaunt-extension-pg-uuidv7: 0.3.0\n\n## [0.3.0]() (2026-09-29)\n\n\n### \u26a0 BREAKING CHANGES\n\n* **sdk:** Native extension lists use typed selections, and native TypeScript restore accepts a directory storage descriptor instead of a path.\n* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.\n* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))\n\n### Features\n\n* introduce oliphaunt ([a4f438c](https://github.com/f0rr0/oliphaunt/commit/a4f438c3b2770a841efc8eb9864b474eb76e6114))\n* unify native and WASIX runtimes and SDKs ([#129](https://github.com/f0rr0/oliphaunt/issues/129)) ([fae2bd7](https://github.com/f0rr0/oliphaunt/commit/fae2bd7bde00ae436d9b62ba6a37d919679ac790))\n\n\n### Bug Fixes\n\n* **ci:** unify Bun test entrypoints and import Swift signing keys ([#214](https://github.com/f0rr0/oliphaunt/issues/214)) ([a7724ef](https://github.com/f0rr0/oliphaunt/commit/a7724efe3ebda8c7f2e1af64d66b64fed645e3bf))\n* **runtime:** close mobile package and readiness gaps [skip ci] ([60b9df9](https://github.com/f0rr0/oliphaunt/commit/60b9df9de1d710d6faeb34114ac66409b689cf22))\n* **sdk:** align resource loading and extension selection ([#216](https://github.com/f0rr0/oliphaunt/issues/216)) ([b25d496](https://github.com/f0rr0/oliphaunt/commit/b25d49655de694525544c5553e77bdd83b2e1632))\n\n\n### Code Refactoring\n\n* **ci:** model independent product dependencies ([#173](https://github.com/f0rr0/oliphaunt/issues/173)) ([2d5f90c](https://github.com/f0rr0/oliphaunt/commit/2d5f90c837ef7ecd8b43c2547e4b3c9b04767121))\n* model product dependencies and simplify qualification ([#209](https://github.com/f0rr0/oliphaunt/issues/209)) ([e058785](https://github.com/f0rr0/oliphaunt/commit/e0587850e153fb8f8866711aa73717ca37bdb657))\n* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127)) ([c45082d](https://github.com/f0rr0/oliphaunt/commit/c45082dc522f04ed0f020464282ed79150f83ecc))\n
\n\n
oliphaunt-extension-pgtap: 0.3.0\n\n## [0.3.0]() (2026-09-29)\n\n\n### \u26a0 BREAKING CHANGES\n\n* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.\n* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))\n\n### Features\n\n* introduce oliphaunt ([a4f438c](https://github.com/f0rr0/oliphaunt/commit/a4f438c3b2770a841efc8eb9864b474eb76e6114))\n* unify native and WASIX runtimes and SDKs ([#129](https://github.com/f0rr0/oliphaunt/issues/129)) ([fae2bd7](https://github.com/f0rr0/oliphaunt/commit/fae2bd7bde00ae436d9b62ba6a37d919679ac790))\n\n\n### Bug Fixes\n\n* **ci:** unify Bun test entrypoints and import Swift signing keys ([#214](https://github.com/f0rr0/oliphaunt/issues/214)) ([a7724ef](https://github.com/f0rr0/oliphaunt/commit/a7724efe3ebda8c7f2e1af64d66b64fed645e3bf))\n* **runtime:** close mobile package and readiness gaps [skip ci] ([60b9df9](https://github.com/f0rr0/oliphaunt/commit/60b9df9de1d710d6faeb34114ac66409b689cf22))\n\n\n### Code Refactoring\n\n* **ci:** model independent product dependencies ([#173](https://github.com/f0rr0/oliphaunt/issues/173)) ([2d5f90c](https://github.com/f0rr0/oliphaunt/commit/2d5f90c837ef7ecd8b43c2547e4b3c9b04767121))\n* model product dependencies and simplify qualification ([#209](https://github.com/f0rr0/oliphaunt/issues/209)) ([e058785](https://github.com/f0rr0/oliphaunt/commit/e0587850e153fb8f8866711aa73717ca37bdb657))\n* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127)) ([c45082d](https://github.com/f0rr0/oliphaunt/commit/c45082dc522f04ed0f020464282ed79150f83ecc))\n
\n\n
oliphaunt-extension-postgis: 0.3.0\n\n## [0.3.0]() (2026-09-29)\n\n\n### \u26a0 BREAKING CHANGES\n\n* **sdk:** Native extension lists use typed selections, and native TypeScript restore accepts a directory storage descriptor instead of a path.\n* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.\n* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))\n\n### Features\n\n* introduce oliphaunt ([a4f438c](https://github.com/f0rr0/oliphaunt/commit/a4f438c3b2770a841efc8eb9864b474eb76e6114))\n* unify native and WASIX runtimes and SDKs ([#129](https://github.com/f0rr0/oliphaunt/issues/129)) ([fae2bd7](https://github.com/f0rr0/oliphaunt/commit/fae2bd7bde00ae436d9b62ba6a37d919679ac790))\n\n\n### Bug Fixes\n\n* **ci:** unify Bun test entrypoints and import Swift signing keys ([#214](https://github.com/f0rr0/oliphaunt/issues/214)) ([a7724ef](https://github.com/f0rr0/oliphaunt/commit/a7724efe3ebda8c7f2e1af64d66b64fed645e3bf))\n* **runtime:** close mobile package and readiness gaps [skip ci] ([60b9df9](https://github.com/f0rr0/oliphaunt/commit/60b9df9de1d710d6faeb34114ac66409b689cf22))\n* **sdk:** align resource loading and extension selection ([#216](https://github.com/f0rr0/oliphaunt/issues/216)) ([b25d496](https://github.com/f0rr0/oliphaunt/commit/b25d49655de694525544c5553e77bdd83b2e1632))\n\n\n### Code Refactoring\n\n* **ci:** model independent product dependencies ([#173](https://github.com/f0rr0/oliphaunt/issues/173)) ([2d5f90c](https://github.com/f0rr0/oliphaunt/commit/2d5f90c837ef7ecd8b43c2547e4b3c9b04767121))\n* model product dependencies and simplify qualification ([#209](https://github.com/f0rr0/oliphaunt/issues/209)) ([e058785](https://github.com/f0rr0/oliphaunt/commit/e0587850e153fb8f8866711aa73717ca37bdb657))\n* organize sources by native and WASIX runtime families ([#215](https://github.com/f0rr0/oliphaunt/issues/215)) ([a8f9bfe](https://github.com/f0rr0/oliphaunt/commit/a8f9bfe75f4cff0426f0089eb248783efacbde2e))\n* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127)) ([c45082d](https://github.com/f0rr0/oliphaunt/commit/c45082dc522f04ed0f020464282ed79150f83ecc))\n
\n\n
oliphaunt-extension-vector: 0.3.0\n\n## [0.3.0]() (2026-09-29)\n\n\n### \u26a0 BREAKING CHANGES\n\n* **sdk:** Native extension lists use typed selections, and native TypeScript restore accepts a directory storage descriptor instead of a path.\n* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.\n* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))\n\n### Features\n\n* introduce oliphaunt ([a4f438c](https://github.com/f0rr0/oliphaunt/commit/a4f438c3b2770a841efc8eb9864b474eb76e6114))\n* unify native and WASIX runtimes and SDKs ([#129](https://github.com/f0rr0/oliphaunt/issues/129)) ([fae2bd7](https://github.com/f0rr0/oliphaunt/commit/fae2bd7bde00ae436d9b62ba6a37d919679ac790))\n\n\n### Bug Fixes\n\n* **ci:** unify Bun test entrypoints and import Swift signing keys ([#214](https://github.com/f0rr0/oliphaunt/issues/214)) ([a7724ef](https://github.com/f0rr0/oliphaunt/commit/a7724efe3ebda8c7f2e1af64d66b64fed645e3bf))\n* **runtime:** close mobile package and readiness gaps [skip ci] ([60b9df9](https://github.com/f0rr0/oliphaunt/commit/60b9df9de1d710d6faeb34114ac66409b689cf22))\n* **sdk:** align resource loading and extension selection ([#216](https://github.com/f0rr0/oliphaunt/issues/216)) ([b25d496](https://github.com/f0rr0/oliphaunt/commit/b25d49655de694525544c5553e77bdd83b2e1632))\n\n\n### Code Refactoring\n\n* **ci:** model independent product dependencies ([#173](https://github.com/f0rr0/oliphaunt/issues/173)) ([2d5f90c](https://github.com/f0rr0/oliphaunt/commit/2d5f90c837ef7ecd8b43c2547e4b3c9b04767121))\n* model product dependencies and simplify qualification ([#209](https://github.com/f0rr0/oliphaunt/issues/209)) ([e058785](https://github.com/f0rr0/oliphaunt/commit/e0587850e153fb8f8866711aa73717ca37bdb657))\n* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127)) ([c45082d](https://github.com/f0rr0/oliphaunt/commit/c45082dc522f04ed0f020464282ed79150f83ecc))\n
\n\n
liboliphaunt-wasix: 0.3.0\n\n## [0.3.0]() (2026-09-29)\n\n\n### \u26a0 BREAKING CHANGES\n\n* **mobile:** native runtime ABI advances to 12 for streaming archive APIs; rebuild native clients and workers with matching artifacts.\n* **sdk:** Native extension lists use typed selections, and native TypeScript restore accepts a directory storage descriptor instead of a path.\n\n### Features\n\n* **mobile:** add unified iOS and Android broker modes ([#219](https://github.com/f0rr0/oliphaunt/issues/219)) ([6f205e9](https://github.com/f0rr0/oliphaunt/commit/6f205e966c6ce404f252ddcc5c5c1b0b8da47e31))\n\n\n### Bug Fixes\n\n* **ci:** unify Bun test entrypoints and import Swift signing keys ([#214](https://github.com/f0rr0/oliphaunt/issues/214)) ([a7724ef](https://github.com/f0rr0/oliphaunt/commit/a7724efe3ebda8c7f2e1af64d66b64fed645e3bf))\n* **sdk:** align resource loading and extension selection ([#216](https://github.com/f0rr0/oliphaunt/issues/216)) ([b25d496](https://github.com/f0rr0/oliphaunt/commit/b25d49655de694525544c5553e77bdd83b2e1632))\n\n\n### Code Refactoring\n\n* model product dependencies and simplify qualification ([#209](https://github.com/f0rr0/oliphaunt/issues/209)) ([e058785](https://github.com/f0rr0/oliphaunt/commit/e0587850e153fb8f8866711aa73717ca37bdb657))\n* organize sources by native and WASIX runtime families ([#215](https://github.com/f0rr0/oliphaunt/issues/215)) ([a8f9bfe](https://github.com/f0rr0/oliphaunt/commit/a8f9bfe75f4cff0426f0089eb248783efacbde2e))\n
\n\n
liboliphaunt-wasix-postmaster: 0.1.1\n\n## [0.1.1]() (2026-09-29)\n\n\n### Bug Fixes\n\n* **ci:** unify Bun test entrypoints and import Swift signing keys ([#214](https://github.com/f0rr0/oliphaunt/issues/214)) ([a7724ef](https://github.com/f0rr0/oliphaunt/commit/a7724efe3ebda8c7f2e1af64d66b64fed645e3bf))\n\n\n### Code Refactoring\n\n* model product dependencies and simplify qualification ([#209](https://github.com/f0rr0/oliphaunt/issues/209)) ([e058785](https://github.com/f0rr0/oliphaunt/commit/e0587850e153fb8f8866711aa73717ca37bdb657))\n* organize sources by native and WASIX runtime families ([#215](https://github.com/f0rr0/oliphaunt/issues/215)) ([a8f9bfe](https://github.com/f0rr0/oliphaunt/commit/a8f9bfe75f4cff0426f0089eb248783efacbde2e))\n
\n\n
oliphaunt-wasix-rust: 0.3.0\n\n## [0.3.0]() (2026-09-29)\n\n\n### \u26a0 BREAKING CHANGES\n\n* **mobile:** native runtime ABI advances to 12 for streaming archive APIs; rebuild native clients and workers with matching artifacts.\n* **sdk:** Native extension lists use typed selections, and native TypeScript restore accepts a directory storage descriptor instead of a path.\n\n### Features\n\n* **mobile:** add unified iOS and Android broker modes ([#219](https://github.com/f0rr0/oliphaunt/issues/219)) ([6f205e9](https://github.com/f0rr0/oliphaunt/commit/6f205e966c6ce404f252ddcc5c5c1b0b8da47e31))\n\n\n### Bug Fixes\n\n* **ci:** unify Bun test entrypoints and import Swift signing keys ([#214](https://github.com/f0rr0/oliphaunt/issues/214)) ([a7724ef](https://github.com/f0rr0/oliphaunt/commit/a7724efe3ebda8c7f2e1af64d66b64fed645e3bf))\n* **sdk:** align resource loading and extension selection ([#216](https://github.com/f0rr0/oliphaunt/issues/216)) ([b25d496](https://github.com/f0rr0/oliphaunt/commit/b25d49655de694525544c5553e77bdd83b2e1632))\n\n\n### Code Refactoring\n\n* model product dependencies and simplify qualification ([#209](https://github.com/f0rr0/oliphaunt/issues/209)) ([e058785](https://github.com/f0rr0/oliphaunt/commit/e0587850e153fb8f8866711aa73717ca37bdb657))\n* organize sources by native and WASIX runtime families ([#215](https://github.com/f0rr0/oliphaunt/issues/215)) ([a8f9bfe](https://github.com/f0rr0/oliphaunt/commit/a8f9bfe75f4cff0426f0089eb248783efacbde2e))\n
\n\n
oliphaunt-query: 0.1.1\n\n## [0.1.1]() (2026-09-29)\n\n\n### Code Refactoring\n\n* organize sources by native and WASIX runtime families ([#215](https://github.com/f0rr0/oliphaunt/issues/215)) ([a8f9bfe](https://github.com/f0rr0/oliphaunt/commit/a8f9bfe75f4cff0426f0089eb248783efacbde2e))\n
\n\n
liboliphaunt-native-bindings: 0.2.0\n\n## [0.2.0]() (2026-09-29)\n\n\n### \u26a0 BREAKING CHANGES\n\n* **mobile:** native runtime ABI advances to 12 for streaming archive APIs; rebuild native clients and workers with matching artifacts.\n* **sdk:** Native extension lists use typed selections, and native TypeScript restore accepts a directory storage descriptor instead of a path.\n* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153))\n* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.\n* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))\n\n### Features\n\n* introduce oliphaunt ([a4f438c](https://github.com/f0rr0/oliphaunt/commit/a4f438c3b2770a841efc8eb9864b474eb76e6114))\n* **mobile:** add unified iOS and Android broker modes ([#219](https://github.com/f0rr0/oliphaunt/issues/219)) ([6f205e9](https://github.com/f0rr0/oliphaunt/commit/6f205e966c6ce404f252ddcc5c5c1b0b8da47e31))\n* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153)) ([4384d1b](https://github.com/f0rr0/oliphaunt/commit/4384d1bdfafee07e4e1963ac68027b4bcf002a1e))\n* unify native and WASIX runtimes and SDKs ([#129](https://github.com/f0rr0/oliphaunt/issues/129)) ([fae2bd7](https://github.com/f0rr0/oliphaunt/commit/fae2bd7bde00ae436d9b62ba6a37d919679ac790))\n\n\n### Bug Fixes\n\n* **ci:** unify Bun test entrypoints and import Swift signing keys ([#214](https://github.com/f0rr0/oliphaunt/issues/214)) ([a7724ef](https://github.com/f0rr0/oliphaunt/commit/a7724efe3ebda8c7f2e1af64d66b64fed645e3bf))\n* **runtime:** close mobile package and readiness gaps [skip ci] ([60b9df9](https://github.com/f0rr0/oliphaunt/commit/60b9df9de1d710d6faeb34114ac66409b689cf22))\n* **sdk:** align resource loading and extension selection ([#216](https://github.com/f0rr0/oliphaunt/issues/216)) ([b25d496](https://github.com/f0rr0/oliphaunt/commit/b25d49655de694525544c5553e77bdd83b2e1632))\n\n\n### Code Refactoring\n\n* **ci:** align product and release task boundaries ([#170](https://github.com/f0rr0/oliphaunt/issues/170)) ([009a5f5](https://github.com/f0rr0/oliphaunt/commit/009a5f5ec0659d70f6a22902c071a81e0806fabe))\n* **ci:** model independent product dependencies ([#173](https://github.com/f0rr0/oliphaunt/issues/173)) ([2d5f90c](https://github.com/f0rr0/oliphaunt/commit/2d5f90c837ef7ecd8b43c2547e4b3c9b04767121))\n* model product dependencies and simplify qualification ([#209](https://github.com/f0rr0/oliphaunt/issues/209)) ([e058785](https://github.com/f0rr0/oliphaunt/commit/e0587850e153fb8f8866711aa73717ca37bdb657))\n* organize sources by native and WASIX runtime families ([#215](https://github.com/f0rr0/oliphaunt/issues/215)) ([a8f9bfe](https://github.com/f0rr0/oliphaunt/commit/a8f9bfe75f4cff0426f0089eb248783efacbde2e))\n* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127)) ([c45082d](https://github.com/f0rr0/oliphaunt/commit/c45082dc522f04ed0f020464282ed79150f83ecc))\n
\n\n
postgres-tools-native: 0.2.2\n\n## [0.2.2]() (2026-09-29)\n\n\n### Code Refactoring\n\n* organize sources by native and WASIX runtime families ([#215](https://github.com/f0rr0/oliphaunt/issues/215)) ([a8f9bfe](https://github.com/f0rr0/oliphaunt/commit/a8f9bfe75f4cff0426f0089eb248783efacbde2e))\n
\n\n
postgres-tools-wasix: 0.2.2\n\n## [0.2.2]() (2026-09-29)\n\n\n### Code Refactoring\n\n* organize sources by native and WASIX runtime families ([#215](https://github.com/f0rr0/oliphaunt/issues/215)) ([a8f9bfe](https://github.com/f0rr0/oliphaunt/commit/a8f9bfe75f4cff0426f0089eb248783efacbde2e))\n
\n\n
database-resources: 0.2.2\n\n## [0.2.2]() (2026-09-29)\n\n\n### Bug Fixes\n\n* **ci:** unify Bun test entrypoints and import Swift signing keys ([#214](https://github.com/f0rr0/oliphaunt/issues/214)) ([a7724ef](https://github.com/f0rr0/oliphaunt/commit/a7724efe3ebda8c7f2e1af64d66b64fed645e3bf))\n\n\n### Code Refactoring\n\n* model product dependencies and simplify qualification ([#209](https://github.com/f0rr0/oliphaunt/issues/209)) ([e058785](https://github.com/f0rr0/oliphaunt/commit/e0587850e153fb8f8866711aa73717ca37bdb657))\n* organize sources by native and WASIX runtime families ([#215](https://github.com/f0rr0/oliphaunt/issues/215)) ([a8f9bfe](https://github.com/f0rr0/oliphaunt/commit/a8f9bfe75f4cff0426f0089eb248783efacbde2e))\n
\n\n
oliphaunt-pgwire-server: 0.2.0\n\n## [0.2.0]() (2026-09-29)\n\n\n### \u26a0 BREAKING CHANGES\n\n* **mobile:** native runtime ABI advances to 12 for streaming archive APIs; rebuild native clients and workers with matching artifacts.\n* **sdk:** Native extension lists use typed selections, and native TypeScript restore accepts a directory storage descriptor instead of a path.\n* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153))\n* Rust WASIX removes temporary/application-data storage variants, and browser IndexedDB uses the new per-database v3 layout without migrating prior generations.\n* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127))\n\n### Features\n\n* introduce oliphaunt ([a4f438c](https://github.com/f0rr0/oliphaunt/commit/a4f438c3b2770a841efc8eb9864b474eb76e6114))\n* **mobile:** add unified iOS and Android broker modes ([#219](https://github.com/f0rr0/oliphaunt/issues/219)) ([6f205e9](https://github.com/f0rr0/oliphaunt/commit/6f205e966c6ce404f252ddcc5c5c1b0b8da47e31))\n* **sdk:** unify embedded PostgreSQL public APIs ([#153](https://github.com/f0rr0/oliphaunt/issues/153)) ([4384d1b](https://github.com/f0rr0/oliphaunt/commit/4384d1bdfafee07e4e1963ac68027b4bcf002a1e))\n* unify native and WASIX runtimes and SDKs ([#129](https://github.com/f0rr0/oliphaunt/issues/129)) ([fae2bd7](https://github.com/f0rr0/oliphaunt/commit/fae2bd7bde00ae436d9b62ba6a37d919679ac790))\n\n\n### Bug Fixes\n\n* **ci:** serialize extension source acquisition ([#195](https://github.com/f0rr0/oliphaunt/issues/195)) ([c1fd04e](https://github.com/f0rr0/oliphaunt/commit/c1fd04e797f30c20289cb7d2dc2c62bb4a4e2e6e))\n* **ci:** unify Bun test entrypoints and import Swift signing keys ([#214](https://github.com/f0rr0/oliphaunt/issues/214)) ([a7724ef](https://github.com/f0rr0/oliphaunt/commit/a7724efe3ebda8c7f2e1af64d66b64fed645e3bf))\n* **runtime:** close mobile package and readiness gaps [skip ci] ([60b9df9](https://github.com/f0rr0/oliphaunt/commit/60b9df9de1d710d6faeb34114ac66409b689cf22))\n* **sdk:** align resource loading and extension selection ([#216](https://github.com/f0rr0/oliphaunt/issues/216)) ([b25d496](https://github.com/f0rr0/oliphaunt/commit/b25d49655de694525544c5553e77bdd83b2e1632))\n\n\n### Code Refactoring\n\n* **ci:** align product and release task boundaries ([#170](https://github.com/f0rr0/oliphaunt/issues/170)) ([009a5f5](https://github.com/f0rr0/oliphaunt/commit/009a5f5ec0659d70f6a22902c071a81e0806fabe))\n* **ci:** model independent product dependencies ([#173](https://github.com/f0rr0/oliphaunt/issues/173)) ([2d5f90c](https://github.com/f0rr0/oliphaunt/commit/2d5f90c837ef7ecd8b43c2547e4b3c9b04767121))\n* model product dependencies and simplify qualification ([#209](https://github.com/f0rr0/oliphaunt/issues/209)) ([e058785](https://github.com/f0rr0/oliphaunt/commit/e0587850e153fb8f8866711aa73717ca37bdb657))\n* organize sources by native and WASIX runtime families ([#215](https://github.com/f0rr0/oliphaunt/issues/215)) ([a8f9bfe](https://github.com/f0rr0/oliphaunt/commit/a8f9bfe75f4cff0426f0089eb248783efacbde2e))\n* **release:** simplify releases and make contrib runtime-owned ([#127](https://github.com/f0rr0/oliphaunt/issues/127)) ([c45082d](https://github.com/f0rr0/oliphaunt/commit/c45082dc522f04ed0f020464282ed79150f83ecc))\n
\n\n
oliphaunt-node-direct: 0.2.1\n\n## [0.2.1]() (2026-09-29)\n\n\n### Code Refactoring\n\n* organize sources by native and WASIX runtime families ([#215](https://github.com/f0rr0/oliphaunt/issues/215)) ([a8f9bfe](https://github.com/f0rr0/oliphaunt/commit/a8f9bfe75f4cff0426f0089eb248783efacbde2e))\n
\n\n
oliphaunt-react-native: 0.3.0\n\n## [0.3.0]() (2026-09-29)\n\n\n### \u26a0 BREAKING CHANGES\n\n* **mobile:** native runtime ABI advances to 12 for streaming archive APIs; rebuild native clients and workers with matching artifacts.\n* **sdk:** Native extension lists use typed selections, and native TypeScript restore accepts a directory storage descriptor instead of a path.\n\n### Features\n\n* **mobile:** add unified iOS and Android broker modes ([#219](https://github.com/f0rr0/oliphaunt/issues/219)) ([6f205e9](https://github.com/f0rr0/oliphaunt/commit/6f205e966c6ce404f252ddcc5c5c1b0b8da47e31))\n* **react-native:** discover Expo resources through autolinking ([#217](https://github.com/f0rr0/oliphaunt/issues/217)) ([df2b112](https://github.com/f0rr0/oliphaunt/commit/df2b112e866f8ea76d320d7b3e172cf7be764177))\n\n\n### Bug Fixes\n\n* **ci:** unify Bun test entrypoints and import Swift signing keys ([#214](https://github.com/f0rr0/oliphaunt/issues/214)) ([a7724ef](https://github.com/f0rr0/oliphaunt/commit/a7724efe3ebda8c7f2e1af64d66b64fed645e3bf))\n* **sdk:** align resource loading and extension selection ([#216](https://github.com/f0rr0/oliphaunt/issues/216)) ([b25d496](https://github.com/f0rr0/oliphaunt/commit/b25d49655de694525544c5553e77bdd83b2e1632))\n\n\n### Code Refactoring\n\n* model product dependencies and simplify qualification ([#209](https://github.com/f0rr0/oliphaunt/issues/209)) ([e058785](https://github.com/f0rr0/oliphaunt/commit/e0587850e153fb8f8866711aa73717ca37bdb657))\n* organize sources by native and WASIX runtime families ([#215](https://github.com/f0rr0/oliphaunt/issues/215)) ([a8f9bfe](https://github.com/f0rr0/oliphaunt/commit/a8f9bfe75f4cff0426f0089eb248783efacbde2e))\n\n\n### Dependencies\n\n* The following workspace dependencies were updated\n * dependencies\n * @oliphaunt/ts-query bumped from 0.1.0 to 0.1.1\n
\n\n
oliphaunt-js: 0.3.0\n\n## [0.3.0]() (2026-09-29)\n\n\n### \u26a0 BREAKING CHANGES\n\n* **mobile:** native runtime ABI advances to 12 for streaming archive APIs; rebuild native clients and workers with matching artifacts.\n* **sdk:** Native extension lists use typed selections, and native TypeScript restore accepts a directory storage descriptor instead of a path.\n\n### Features\n\n* **mobile:** add unified iOS and Android broker modes ([#219](https://github.com/f0rr0/oliphaunt/issues/219)) ([6f205e9](https://github.com/f0rr0/oliphaunt/commit/6f205e966c6ce404f252ddcc5c5c1b0b8da47e31))\n\n\n### Bug Fixes\n\n* **sdk:** align resource loading and extension selection ([#216](https://github.com/f0rr0/oliphaunt/issues/216)) ([b25d496](https://github.com/f0rr0/oliphaunt/commit/b25d49655de694525544c5553e77bdd83b2e1632))\n\n\n### Code Refactoring\n\n* organize sources by native and WASIX runtime families ([#215](https://github.com/f0rr0/oliphaunt/issues/215)) ([a8f9bfe](https://github.com/f0rr0/oliphaunt/commit/a8f9bfe75f4cff0426f0089eb248783efacbde2e))\n\n\n### Dependencies\n\n* The following workspace dependencies were updated\n * dependencies\n * @oliphaunt/ts-query bumped from 0.1.0 to 0.1.1\n
\n\n
oliphaunt-query-ts: 0.1.1\n\n## [0.1.1]() (2026-09-29)\n\n\n### Code Refactoring\n\n* organize sources by native and WASIX runtime families ([#215](https://github.com/f0rr0/oliphaunt/issues/215)) ([a8f9bfe](https://github.com/f0rr0/oliphaunt/commit/a8f9bfe75f4cff0426f0089eb248783efacbde2e))\n
\n\n
oliphaunt-wasix-napi: 0.2.0\n\n## [0.2.0]() (2026-09-29)\n\n\n### \u26a0 BREAKING CHANGES\n\n* **mobile:** native runtime ABI advances to 12 for streaming archive APIs; rebuild native clients and workers with matching artifacts.\n* **sdk:** Native extension lists use typed selections, and native TypeScript restore accepts a directory storage descriptor instead of a path.\n\n### Features\n\n* **mobile:** add unified iOS and Android broker modes ([#219](https://github.com/f0rr0/oliphaunt/issues/219)) ([6f205e9](https://github.com/f0rr0/oliphaunt/commit/6f205e966c6ce404f252ddcc5c5c1b0b8da47e31))\n\n\n### Bug Fixes\n\n* **ci:** unify Bun test entrypoints and import Swift signing keys ([#214](https://github.com/f0rr0/oliphaunt/issues/214)) ([a7724ef](https://github.com/f0rr0/oliphaunt/commit/a7724efe3ebda8c7f2e1af64d66b64fed645e3bf))\n* **sdk:** align resource loading and extension selection ([#216](https://github.com/f0rr0/oliphaunt/issues/216)) ([b25d496](https://github.com/f0rr0/oliphaunt/commit/b25d49655de694525544c5553e77bdd83b2e1632))\n\n\n### Code Refactoring\n\n* model product dependencies and simplify qualification ([#209](https://github.com/f0rr0/oliphaunt/issues/209)) ([e058785](https://github.com/f0rr0/oliphaunt/commit/e0587850e153fb8f8866711aa73717ca37bdb657))\n* organize sources by native and WASIX runtime families ([#215](https://github.com/f0rr0/oliphaunt/issues/215)) ([a8f9bfe](https://github.com/f0rr0/oliphaunt/commit/a8f9bfe75f4cff0426f0089eb248783efacbde2e))\n
\n\n
oliphaunt-wasix-ts: 0.2.0\n\n## [0.2.0]() (2026-09-29)\n\n\n### \u26a0 BREAKING CHANGES\n\n* **mobile:** native runtime ABI advances to 12 for streaming archive APIs; rebuild native clients and workers with matching artifacts.\n* **sdk:** Native extension lists use typed selections, and native TypeScript restore accepts a directory storage descriptor instead of a path.\n\n### Features\n\n* **mobile:** add unified iOS and Android broker modes ([#219](https://github.com/f0rr0/oliphaunt/issues/219)) ([6f205e9](https://github.com/f0rr0/oliphaunt/commit/6f205e966c6ce404f252ddcc5c5c1b0b8da47e31))\n\n\n### Bug Fixes\n\n* **ci:** unify Bun test entrypoints and import Swift signing keys ([#214](https://github.com/f0rr0/oliphaunt/issues/214)) ([a7724ef](https://github.com/f0rr0/oliphaunt/commit/a7724efe3ebda8c7f2e1af64d66b64fed645e3bf))\n* **sdk:** align resource loading and extension selection ([#216](https://github.com/f0rr0/oliphaunt/issues/216)) ([b25d496](https://github.com/f0rr0/oliphaunt/commit/b25d49655de694525544c5553e77bdd83b2e1632))\n\n\n### Code Refactoring\n\n* model product dependencies and simplify qualification ([#209](https://github.com/f0rr0/oliphaunt/issues/209)) ([e058785](https://github.com/f0rr0/oliphaunt/commit/e0587850e153fb8f8866711aa73717ca37bdb657))\n* organize sources by native and WASIX runtime families ([#215](https://github.com/f0rr0/oliphaunt/issues/215)) ([a8f9bfe](https://github.com/f0rr0/oliphaunt/commit/a8f9bfe75f4cff0426f0089eb248783efacbde2e))\n\n\n### Dependencies\n\n* The following workspace dependencies were updated\n * dependencies\n * @oliphaunt/ts-query bumped from 0.1.0 to 0.1.1\n
\n\n---\nThis PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).\n", + "merged_at": "2026-09-28T22:30:01Z", + "merge_commit_sha": "7b192697ff522f71f9c694593d352aa30469cea1", + "labels": [ + { + "name": "autorelease: tagged" + } + ], + "head": { + "ref": "release-please--branches--main", + "repo": { + "full_name": "f0rr0/oliphaunt" + } + }, + "base": { + "ref": "main", + "repo": { + "full_name": "f0rr0/oliphaunt" + } + } + } + ], + "responses": { + "repos/f0rr0/oliphaunt/git/commits/7b192697ff522f71f9c694593d352aa30469cea1": { + "sha": "7b192697ff522f71f9c694593d352aa30469cea1", + "tree": { + "sha": "70ab96b6e98c07d707b5873bcc3c23c48afb9ce8" + }, + "parents": [ + { + "sha": "e619376b438b70cd174750c9648bcc9255342eb8" + } + ] + }, + "repos/f0rr0/oliphaunt/git/commits/c51052fe8b8ffc7e992266c5ab3d7a63b47441e7": { + "sha": "c51052fe8b8ffc7e992266c5ab3d7a63b47441e7", + "tree": { + "sha": "59791800860832994b48b8009bb48c5a74a7764e" + }, + "parents": [ + { + "sha": "79c340949f4121e962741b75d80e686b5ba023c2" + } + ] + }, + "repos/f0rr0/oliphaunt/contents/release-please-config.json?ref=7b192697ff522f71f9c694593d352aa30469cea1": { + "type": "file", + "path": "release-please-config.json", + "sha": "7d7334c6e3cfc2768ea9fa4bf97a2f3b22fbab8a", + "encoding": "base64", + "content": "ewogICIkc2NoZW1hIjogImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9nb29nbGVhcGlzL3JlbGVhc2UtcGxlYXNlL21haW4vc2NoZW1hcy9jb25maWcuanNvbiIsCiAgImluY2x1ZGUtdi1pbi10YWciOiB0cnVlLAogICJzZXBhcmF0ZS1wdWxsLXJlcXVlc3RzIjogZmFsc2UsCiAgInRhZy1zZXBhcmF0b3IiOiAiLSIsCiAgInB1bGwtcmVxdWVzdC10aXRsZS1wYXR0ZXJuIjogImNob3JlJHtzY29wZX06IHJlbGVhc2Uke2NvbXBvbmVudH0gJHt2ZXJzaW9ufSIsCiAgImdyb3VwLXB1bGwtcmVxdWVzdC10aXRsZS1wYXR0ZXJuIjogImNob3JlKHJlbGVhc2UpOiBwcmVwYXJlICR7YnJhbmNofSByZWxlYXNlcyIsCiAgImluaXRpYWwtdmVyc2lvbiI6ICIwLjEuMCIsCiAgImJ1bXAtbWlub3ItcHJlLW1ham9yIjogdHJ1ZSwKICAiYnVtcC1wYXRjaC1mb3ItbWlub3ItcHJlLW1ham9yIjogdHJ1ZSwKICAiY2hhbmdlbG9nLXNlY3Rpb25zIjogWwogICAgewogICAgICAidHlwZSI6ICJmZWF0IiwKICAgICAgInNlY3Rpb24iOiAiRmVhdHVyZXMiLAogICAgICAiaGlkZGVuIjogZmFsc2UKICAgIH0sCiAgICB7CiAgICAgICJ0eXBlIjogImZpeCIsCiAgICAgICJzZWN0aW9uIjogIkJ1ZyBGaXhlcyIsCiAgICAgICJoaWRkZW4iOiBmYWxzZQogICAgfSwKICAgIHsKICAgICAgInR5cGUiOiAicGVyZiIsCiAgICAgICJzZWN0aW9uIjogIlBlcmZvcm1hbmNlIEltcHJvdmVtZW50cyIsCiAgICAgICJoaWRkZW4iOiBmYWxzZQogICAgfSwKICAgIHsKICAgICAgInR5cGUiOiAicmVmYWN0b3IiLAogICAgICAic2VjdGlvbiI6ICJDb2RlIFJlZmFjdG9yaW5nIiwKICAgICAgImhpZGRlbiI6IGZhbHNlCiAgICB9LAogICAgewogICAgICAidHlwZSI6ICJyZXZlcnQiLAogICAgICAic2VjdGlvbiI6ICJSZXZlcnRzIiwKICAgICAgImhpZGRlbiI6IGZhbHNlCiAgICB9CiAgXSwKICAicGx1Z2lucyI6IFsKICAgIHsKICAgICAgInR5cGUiOiAibm9kZS13b3Jrc3BhY2UiLAogICAgICAibWVyZ2UiOiBmYWxzZQogICAgfQogIF0sCiAgInBhY2thZ2VzIjogewogICAgInNyYy9uYXRpdmUvcnVudGltZSI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJzaW1wbGUiLAogICAgICAiY29tcG9uZW50IjogImxpYm9saXBoYXVudC1uYXRpdmUiLAogICAgICAicGFja2FnZS1uYW1lIjogImxpYm9saXBoYXVudC1uYXRpdmUiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIiwKICAgICAgImV4dHJhLWZpbGVzIjogWwogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAicGFja2FnZXMvZGFyd2luLWFybTY0L3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJwYWNrYWdlcy9saW51eC1hcm02NC1nbnUvcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogInBhY2thZ2VzL2xpbnV4LXg2NC1nbnUvcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogInBhY2thZ2VzL3dpbjMyLXg2NC1tc3ZjL3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAiZ2VuZXJpYyIsCiAgICAgICAgICAicGF0aCI6ICJzcmMvbGlib2xpcGhhdW50X25hdGl2ZS5jIgogICAgICAgIH0KICAgICAgXQogICAgfSwKICAgICJzcmMvbmF0aXZlL3Nka3MvcnVzdCI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJydXN0IiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtcnVzdCIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAib2xpcGhhdW50IiwKICAgICAgImNoYW5nZWxvZy1wYXRoIjogIkNIQU5HRUxPRy5tZCIsCiAgICAgICJleHRyYS1maWxlcyI6IFsKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJ0b21sIiwKICAgICAgICAgICJwYXRoIjogImNyYXRlcy9vbGlwaGF1bnQtYnVpbGQvQ2FyZ28udG9tbCIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC5wYWNrYWdlLnZlcnNpb24iCiAgICAgICAgfQogICAgICBdCiAgICB9LAogICAgInNyYy9uYXRpdmUvYnJva2VyIjogewogICAgICAicmVsZWFzZS10eXBlIjogInJ1c3QiLAogICAgICAiY29tcG9uZW50IjogIm9saXBoYXVudC1icm9rZXIiLAogICAgICAicGFja2FnZS1uYW1lIjogIm9saXBoYXVudC1icm9rZXIiLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIiwKICAgICAgImV4dHJhLWZpbGVzIjogWwogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAicGFja2FnZXMvZGFyd2luLWFybTY0L3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJwYWNrYWdlcy9saW51eC1hcm02NC1nbnUvcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogInBhY2thZ2VzL2xpbnV4LXg2NC1nbnUvcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogInBhY2thZ2VzL3dpbjMyLXg2NC1tc3ZjL3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAidG9tbCIsCiAgICAgICAgICAicGF0aCI6ICJjcmF0ZXMvbGludXgtYXJtNjQtZ251L0NhcmdvLnRvbWwiLAogICAgICAgICAgImpzb25wYXRoIjogIiQucGFja2FnZS52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAidG9tbCIsCiAgICAgICAgICAicGF0aCI6ICJjcmF0ZXMvbGludXgteDY0LWdudS9DYXJnby50b21sIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnBhY2thZ2UudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogInRvbWwiLAogICAgICAgICAgInBhdGgiOiAiY3JhdGVzL21hY29zLWFybTY0L0NhcmdvLnRvbWwiLAogICAgICAgICAgImpzb25wYXRoIjogIiQucGFja2FnZS52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAidG9tbCIsCiAgICAgICAgICAicGF0aCI6ICJjcmF0ZXMvd2luZG93cy14NjQtbXN2Yy9DYXJnby50b21sIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnBhY2thZ2UudmVyc2lvbiIKICAgICAgICB9CiAgICAgIF0KICAgIH0sCiAgICAic3JjL25hdGl2ZS9ub2RlLWFkZG9uIjogewogICAgICAicmVsZWFzZS10eXBlIjogIm5vZGUiLAogICAgICAiY29tcG9uZW50IjogIm9saXBoYXVudC1ub2RlLWRpcmVjdCIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAiQG9saXBoYXVudC9ub2RlLWRpcmVjdCIsCiAgICAgICJjaGFuZ2Vsb2ctcGF0aCI6ICJDSEFOR0VMT0cubWQiLAogICAgICAiZXh0cmEtZmlsZXMiOiBbCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJwYWNrYWdlcy9kYXJ3aW4tYXJtNjQvcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogInBhY2thZ2VzL2xpbnV4LWFybTY0LWdudS9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAicGFja2FnZXMvbGludXgteDY0LWdudS9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAicGFja2FnZXMvd2luMzIteDY0LW1zdmMvcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfQogICAgICBdCiAgICB9LAogICAgInNyYy93YXNpeC9ub2RlLWFkZG9uIjogewogICAgICAicmVsZWFzZS10eXBlIjogIm5vZGUiLAogICAgICAiY29tcG9uZW50IjogIm9saXBoYXVudC13YXNpeC1uYXBpIiwKICAgICAgInBhY2thZ2UtbmFtZSI6ICJAb2xpcGhhdW50L3dhc2l4LW5hcGkiLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIiwKICAgICAgImV4dHJhLWZpbGVzIjogWwogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogInRvbWwiLAogICAgICAgICAgInBhdGgiOiAiQ2FyZ28udG9tbCIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC5wYWNrYWdlLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogInBhY2thZ2VzL2Rhcndpbi1hcm02NC9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAicGFja2FnZXMvbGludXgtYXJtNjQtZ251L3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJwYWNrYWdlcy9saW51eC14NjQtZ251L3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJwYWNrYWdlcy93aW4zMi14NjQtbXN2Yy9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9CiAgICAgIF0KICAgIH0sCiAgICAic3JjL25hdGl2ZS9zZGtzL3N3aWZ0IjogewogICAgICAicmVsZWFzZS10eXBlIjogInNpbXBsZSIsCiAgICAgICJjb21wb25lbnQiOiAib2xpcGhhdW50LXN3aWZ0IiwKICAgICAgInBhY2thZ2UtbmFtZSI6ICJvbGlwaGF1bnQtc3dpZnQiLAogICAgICAiaW5pdGlhbC12ZXJzaW9uIjogIjAuNi4wIiwKICAgICAgImJ1bXAtcGF0Y2gtZm9yLW1pbm9yLXByZS1tYWpvciI6IGZhbHNlLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvbmF0aXZlL3Nka3Mva290bGluIjogewogICAgICAicmVsZWFzZS10eXBlIjogInNpbXBsZSIsCiAgICAgICJjb21wb25lbnQiOiAib2xpcGhhdW50LWtvdGxpbiIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAiZGV2Lm9saXBoYXVudDpvbGlwaGF1bnQtYW5kcm9pZCIsCiAgICAgICJ2ZXJzaW9uLWZpbGUiOiAiVkVSU0lPTiIsCiAgICAgICJjaGFuZ2Vsb2ctcGF0aCI6ICJDSEFOR0VMT0cubWQiLAogICAgICAiZXh0cmEtZmlsZXMiOiBbCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAiZ2VuZXJpYyIsCiAgICAgICAgICAicGF0aCI6ICJncmFkbGUucHJvcGVydGllcyIKICAgICAgICB9CiAgICAgIF0KICAgIH0sCiAgICAic3JjL25hdGl2ZS9zZGtzL3JlYWN0LW5hdGl2ZSI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJub2RlIiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtcmVhY3QtbmF0aXZlIiwKICAgICAgInBhY2thZ2UtbmFtZSI6ICJAb2xpcGhhdW50L3JlYWN0LW5hdGl2ZSIsCiAgICAgICJjaGFuZ2Vsb2ctcGF0aCI6ICJDSEFOR0VMT0cubWQiCiAgICB9LAogICAgInNyYy9uYXRpdmUvc2Rrcy90cyI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJub2RlIiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtanMiLAogICAgICAicGFja2FnZS1uYW1lIjogIkBvbGlwaGF1bnQvdHMiLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wZ19oYXNoaWRzIjogewogICAgICAicmVsZWFzZS10eXBlIjogInNpbXBsZSIsCiAgICAgICJjb21wb25lbnQiOiAib2xpcGhhdW50LWV4dGVuc2lvbi1wZy1oYXNoaWRzIiwKICAgICAgInBhY2thZ2UtbmFtZSI6ICJvbGlwaGF1bnQtZXh0ZW5zaW9uLXBnLWhhc2hpZHMiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wZ19pdm0iOiB7CiAgICAgICJyZWxlYXNlLXR5cGUiOiAic2ltcGxlIiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtZXh0ZW5zaW9uLXBnLWl2bSIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAib2xpcGhhdW50LWV4dGVuc2lvbi1wZy1pdm0iLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wZ190ZXh0c2VhcmNoIjogewogICAgICAicmVsZWFzZS10eXBlIjogInNpbXBsZSIsCiAgICAgICJjb21wb25lbnQiOiAib2xpcGhhdW50LWV4dGVuc2lvbi1wZy10ZXh0c2VhcmNoIiwKICAgICAgInBhY2thZ2UtbmFtZSI6ICJvbGlwaGF1bnQtZXh0ZW5zaW9uLXBnLXRleHRzZWFyY2giLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wZ191dWlkdjciOiB7CiAgICAgICJyZWxlYXNlLXR5cGUiOiAic2ltcGxlIiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtZXh0ZW5zaW9uLXBnLXV1aWR2NyIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAib2xpcGhhdW50LWV4dGVuc2lvbi1wZy11dWlkdjciLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wZ3RhcCI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJzaW1wbGUiLAogICAgICAiY29tcG9uZW50IjogIm9saXBoYXVudC1leHRlbnNpb24tcGd0YXAiLAogICAgICAicGFja2FnZS1uYW1lIjogIm9saXBoYXVudC1leHRlbnNpb24tcGd0YXAiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wb3N0Z2lzIjogewogICAgICAicmVsZWFzZS10eXBlIjogInNpbXBsZSIsCiAgICAgICJjb21wb25lbnQiOiAib2xpcGhhdW50LWV4dGVuc2lvbi1wb3N0Z2lzIiwKICAgICAgInBhY2thZ2UtbmFtZSI6ICJvbGlwaGF1bnQtZXh0ZW5zaW9uLXBvc3RnaXMiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC92ZWN0b3IiOiB7CiAgICAgICJyZWxlYXNlLXR5cGUiOiAic2ltcGxlIiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtZXh0ZW5zaW9uLXZlY3RvciIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAib2xpcGhhdW50LWV4dGVuc2lvbi12ZWN0b3IiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvd2FzaXgvcnVudGltZSI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJzaW1wbGUiLAogICAgICAiY29tcG9uZW50IjogImxpYm9saXBoYXVudC13YXNpeCIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAibGlib2xpcGhhdW50LXdhc2l4IiwKICAgICAgInZlcnNpb24tZmlsZSI6ICJWRVJTSU9OIiwKICAgICAgImNoYW5nZWxvZy1wYXRoIjogIkNIQU5HRUxPRy5tZCIsCiAgICAgICJleHRyYS1maWxlcyI6IFsKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJ0b21sIiwKICAgICAgICAgICJwYXRoIjogImNyYXRlcy9hc3NldHMvQ2FyZ28udG9tbCIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC5wYWNrYWdlLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJ0b21sIiwKICAgICAgICAgICJwYXRoIjogImNyYXRlcy9hb3QvYWFyY2g2NC1hcHBsZS1kYXJ3aW4vQ2FyZ28udG9tbCIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC5wYWNrYWdlLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJ0b21sIiwKICAgICAgICAgICJwYXRoIjogImNyYXRlcy9hb3QvYWFyY2g2NC11bmtub3duLWxpbnV4LWdudS9DYXJnby50b21sIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnBhY2thZ2UudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogInRvbWwiLAogICAgICAgICAgInBhdGgiOiAiY3JhdGVzL2FvdC94ODZfNjQtcGMtd2luZG93cy1tc3ZjL0NhcmdvLnRvbWwiLAogICAgICAgICAgImpzb25wYXRoIjogIiQucGFja2FnZS52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAidG9tbCIsCiAgICAgICAgICAicGF0aCI6ICJjcmF0ZXMvYW90L3g4Nl82NC11bmtub3duLWxpbnV4LWdudS9DYXJnby50b21sIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnBhY2thZ2UudmVyc2lvbiIKICAgICAgICB9CiAgICAgIF0KICAgIH0sCiAgICAic3JjL3dhc2l4L3Bvc3RtYXN0ZXIiOiB7CiAgICAgICJyZWxlYXNlLXR5cGUiOiAic2ltcGxlIiwKICAgICAgImNvbXBvbmVudCI6ICJsaWJvbGlwaGF1bnQtd2FzaXgtcG9zdG1hc3RlciIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAibGlib2xpcGhhdW50LXdhc2l4LXBvc3RtYXN0ZXIiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvd2FzaXgvc2Rrcy9ydXN0IjogewogICAgICAicmVsZWFzZS10eXBlIjogInJ1c3QiLAogICAgICAiY29tcG9uZW50IjogIm9saXBoYXVudC13YXNpeC1ydXN0IiwKICAgICAgInBhY2thZ2UtbmFtZSI6ICJvbGlwaGF1bnQtd2FzaXgiLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvd2FzaXgvc2Rrcy90cyI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJub2RlIiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtd2FzaXgtdHMiLAogICAgICAicGFja2FnZS1uYW1lIjogIkBvbGlwaGF1bnQvd2FzaXgtdHMiLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvcXVlcnkvcnVzdCI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJydXN0IiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtcXVlcnkiLAogICAgICAicGFja2FnZS1uYW1lIjogIm9saXBoYXVudC1xdWVyeSIsCiAgICAgICJjaGFuZ2Vsb2ctcGF0aCI6ICJDSEFOR0VMT0cubWQiCiAgICB9LAogICAgInNyYy9xdWVyeS90cyI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJub2RlIiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtcXVlcnktdHMiLAogICAgICAicGFja2FnZS1uYW1lIjogIkBvbGlwaGF1bnQvdHMtcXVlcnkiLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvbmF0aXZlL3J1c3QtYmluZGluZ3MiOiB7CiAgICAgICJyZWxlYXNlLXR5cGUiOiAicnVzdCIsCiAgICAgICJjb21wb25lbnQiOiAibGlib2xpcGhhdW50LW5hdGl2ZS1iaW5kaW5ncyIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAibGlib2xpcGhhdW50LW5hdGl2ZS1iaW5kaW5ncyIsCiAgICAgICJjaGFuZ2Vsb2ctcGF0aCI6ICJDSEFOR0VMT0cubWQiCiAgICB9LAogICAgInNyYy9uYXRpdmUvcG9zdGdyZXMtdG9vbHMiOiB7CiAgICAgICJyZWxlYXNlLXR5cGUiOiAic2ltcGxlIiwKICAgICAgImNvbXBvbmVudCI6ICJwb3N0Z3Jlcy10b29scy1uYXRpdmUiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIiwKICAgICAgImluaXRpYWwtdmVyc2lvbiI6ICIwLjIuMSIsCiAgICAgICJleHRyYS1maWxlcyI6IFsKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogIm5wbS1wbGF0Zm9ybXMvZGFyd2luLWFybTY0L3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJucG0tcGxhdGZvcm1zL2xpbnV4LWFybTY0LWdudS9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAibnBtLXBsYXRmb3Jtcy9saW51eC14NjQtZ251L3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJucG0tcGxhdGZvcm1zL3dpbjMyLXg2NC1tc3ZjL3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJucG0vcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJ0b21sIiwKICAgICAgICAgICJwYXRoIjogImNyYXRlcy90b29scy9DYXJnby50b21sIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnBhY2thZ2UudmVyc2lvbiIKICAgICAgICB9CiAgICAgIF0KICAgIH0sCiAgICAic3JjL3dhc2l4L3Bvc3RncmVzLXRvb2xzIjogewogICAgICAicmVsZWFzZS10eXBlIjogInNpbXBsZSIsCiAgICAgICJjb21wb25lbnQiOiAicG9zdGdyZXMtdG9vbHMtd2FzaXgiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIiwKICAgICAgImluaXRpYWwtdmVyc2lvbiI6ICIwLjIuMSIsCiAgICAgICJleHRyYS1maWxlcyI6IFsKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJ0b21sIiwKICAgICAgICAgICJwYXRoIjogImNyYXRlcy90b29scy9DYXJnby50b21sIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnBhY2thZ2UudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogInRvbWwiLAogICAgICAgICAgInBhdGgiOiAiY3JhdGVzL2FvdC9hYXJjaDY0LWFwcGxlLWRhcndpbi9DYXJnby50b21sIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnBhY2thZ2UudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogInRvbWwiLAogICAgICAgICAgInBhdGgiOiAiY3JhdGVzL2FvdC9hYXJjaDY0LXVua25vd24tbGludXgtZ251L0NhcmdvLnRvbWwiLAogICAgICAgICAgImpzb25wYXRoIjogIiQucGFja2FnZS52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAidG9tbCIsCiAgICAgICAgICAicGF0aCI6ICJjcmF0ZXMvYW90L3g4Nl82NC1wYy13aW5kb3dzLW1zdmMvQ2FyZ28udG9tbCIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC5wYWNrYWdlLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJ0b21sIiwKICAgICAgICAgICJwYXRoIjogImNyYXRlcy9hb3QveDg2XzY0LXVua25vd24tbGludXgtZ251L0NhcmdvLnRvbWwiLAogICAgICAgICAgImpzb25wYXRoIjogIiQucGFja2FnZS52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJucG0vcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogInRzL3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJucG0tcGxhdGZvcm1zL2xpbnV4LWFybTY0LWdudS9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAibnBtLXBsYXRmb3Jtcy9saW51eC14NjQtZ251L3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJucG0tcGxhdGZvcm1zL2Rhcndpbi1hcm02NC9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAibnBtLXBsYXRmb3Jtcy93aW4zMi14NjQtbXN2Yy9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9CiAgICAgIF0KICAgIH0sCiAgICAic3JjL2RhdGFiYXNlLXJlc291cmNlcyI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJzaW1wbGUiLAogICAgICAiY29tcG9uZW50IjogImRhdGFiYXNlLXJlc291cmNlcyIsCiAgICAgICJ2ZXJzaW9uLWZpbGUiOiAiVkVSU0lPTiIsCiAgICAgICJjaGFuZ2Vsb2ctcGF0aCI6ICJDSEFOR0VMT0cubWQiLAogICAgICAiaW5pdGlhbC12ZXJzaW9uIjogIjAuMi4xIiwKICAgICAgImV4dHJhLWZpbGVzIjogWwogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAiaWN1L25wbS9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImdlbmVyaWMiLAogICAgICAgICAgInBhdGgiOiAiaWN1L25wbS9PbGlwaGF1bnRJQ1UucG9kc3BlYyIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogInRvbWwiLAogICAgICAgICAgInBhdGgiOiAiaWN1L2NhcmdvL0NhcmdvLnRvbWwiLAogICAgICAgICAgImpzb25wYXRoIjogIiQucGFja2FnZS52ZXJzaW9uIgogICAgICAgIH0KICAgICAgXQogICAgfSwKICAgICJzcmMvd2FzaXgvcGd3aXJlLXNlcnZlciI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJydXN0IiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtcGd3aXJlLXNlcnZlciIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAib2xpcGhhdW50LXBnd2lyZS1zZXJ2ZXIiLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIiwKICAgICAgImluaXRpYWwtdmVyc2lvbiI6ICIwLjEuMCIKICAgIH0KICB9Cn0K" + }, + "repos/f0rr0/oliphaunt/contents/.release-please-manifest.json?ref=7b192697ff522f71f9c694593d352aa30469cea1": { + "type": "file", + "path": ".release-please-manifest.json", + "sha": "a06fb685e447398cc660d5eb12cfa190f1392f50", + "encoding": "base64", + "content": "ewogICJzcmMvbmF0aXZlL3J1bnRpbWUiOiAiMC4zLjAiLAogICJzcmMvbmF0aXZlL3Nka3MvcnVzdCI6ICIwLjMuMCIsCiAgInNyYy9uYXRpdmUvYnJva2VyIjogIjAuMy4wIiwKICAic3JjL25hdGl2ZS9ub2RlLWFkZG9uIjogIjAuMi4xIiwKICAic3JjL3dhc2l4L25vZGUtYWRkb24iOiAiMC4yLjAiLAogICJzcmMvbmF0aXZlL3Nka3Mvc3dpZnQiOiAiMC44LjAiLAogICJzcmMvbmF0aXZlL3Nka3Mva290bGluIjogIjAuMy4wIiwKICAic3JjL25hdGl2ZS9zZGtzL3JlYWN0LW5hdGl2ZSI6ICIwLjMuMCIsCiAgInNyYy9uYXRpdmUvc2Rrcy90cyI6ICIwLjMuMCIsCiAgInNyYy9leHRlbnNpb25zL2V4dGVybmFsL3BnX2hhc2hpZHMiOiAiMC4zLjAiLAogICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wZ19pdm0iOiAiMC4zLjAiLAogICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wZ190ZXh0c2VhcmNoIjogIjAuMy4wIiwKICAic3JjL2V4dGVuc2lvbnMvZXh0ZXJuYWwvcGdfdXVpZHY3IjogIjAuMy4wIiwKICAic3JjL2V4dGVuc2lvbnMvZXh0ZXJuYWwvcGd0YXAiOiAiMC4zLjAiLAogICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wb3N0Z2lzIjogIjAuMy4wIiwKICAic3JjL2V4dGVuc2lvbnMvZXh0ZXJuYWwvdmVjdG9yIjogIjAuMy4wIiwKICAic3JjL3dhc2l4L3J1bnRpbWUiOiAiMC4zLjAiLAogICJzcmMvd2FzaXgvcG9zdG1hc3RlciI6ICIwLjEuMSIsCiAgInNyYy93YXNpeC9zZGtzL3J1c3QiOiAiMC4zLjAiLAogICJzcmMvd2FzaXgvc2Rrcy90cyI6ICIwLjIuMCIsCiAgInNyYy9xdWVyeS9ydXN0IjogIjAuMS4xIiwKICAic3JjL3F1ZXJ5L3RzIjogIjAuMS4xIiwKICAic3JjL25hdGl2ZS9ydXN0LWJpbmRpbmdzIjogIjAuMi4wIiwKICAic3JjL25hdGl2ZS9wb3N0Z3Jlcy10b29scyI6ICIwLjIuMiIsCiAgInNyYy93YXNpeC9wb3N0Z3Jlcy10b29scyI6ICIwLjIuMiIsCiAgInNyYy9kYXRhYmFzZS1yZXNvdXJjZXMiOiAiMC4yLjIiLAogICJzcmMvd2FzaXgvcGd3aXJlLXNlcnZlciI6ICIwLjIuMCIKfQo=" + }, + "repos/f0rr0/oliphaunt/contents/release-please-config.json?ref=e619376b438b70cd174750c9648bcc9255342eb8": { + "type": "file", + "path": "release-please-config.json", + "sha": "7d7334c6e3cfc2768ea9fa4bf97a2f3b22fbab8a", + "encoding": "base64", + "content": "ewogICIkc2NoZW1hIjogImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9nb29nbGVhcGlzL3JlbGVhc2UtcGxlYXNlL21haW4vc2NoZW1hcy9jb25maWcuanNvbiIsCiAgImluY2x1ZGUtdi1pbi10YWciOiB0cnVlLAogICJzZXBhcmF0ZS1wdWxsLXJlcXVlc3RzIjogZmFsc2UsCiAgInRhZy1zZXBhcmF0b3IiOiAiLSIsCiAgInB1bGwtcmVxdWVzdC10aXRsZS1wYXR0ZXJuIjogImNob3JlJHtzY29wZX06IHJlbGVhc2Uke2NvbXBvbmVudH0gJHt2ZXJzaW9ufSIsCiAgImdyb3VwLXB1bGwtcmVxdWVzdC10aXRsZS1wYXR0ZXJuIjogImNob3JlKHJlbGVhc2UpOiBwcmVwYXJlICR7YnJhbmNofSByZWxlYXNlcyIsCiAgImluaXRpYWwtdmVyc2lvbiI6ICIwLjEuMCIsCiAgImJ1bXAtbWlub3ItcHJlLW1ham9yIjogdHJ1ZSwKICAiYnVtcC1wYXRjaC1mb3ItbWlub3ItcHJlLW1ham9yIjogdHJ1ZSwKICAiY2hhbmdlbG9nLXNlY3Rpb25zIjogWwogICAgewogICAgICAidHlwZSI6ICJmZWF0IiwKICAgICAgInNlY3Rpb24iOiAiRmVhdHVyZXMiLAogICAgICAiaGlkZGVuIjogZmFsc2UKICAgIH0sCiAgICB7CiAgICAgICJ0eXBlIjogImZpeCIsCiAgICAgICJzZWN0aW9uIjogIkJ1ZyBGaXhlcyIsCiAgICAgICJoaWRkZW4iOiBmYWxzZQogICAgfSwKICAgIHsKICAgICAgInR5cGUiOiAicGVyZiIsCiAgICAgICJzZWN0aW9uIjogIlBlcmZvcm1hbmNlIEltcHJvdmVtZW50cyIsCiAgICAgICJoaWRkZW4iOiBmYWxzZQogICAgfSwKICAgIHsKICAgICAgInR5cGUiOiAicmVmYWN0b3IiLAogICAgICAic2VjdGlvbiI6ICJDb2RlIFJlZmFjdG9yaW5nIiwKICAgICAgImhpZGRlbiI6IGZhbHNlCiAgICB9LAogICAgewogICAgICAidHlwZSI6ICJyZXZlcnQiLAogICAgICAic2VjdGlvbiI6ICJSZXZlcnRzIiwKICAgICAgImhpZGRlbiI6IGZhbHNlCiAgICB9CiAgXSwKICAicGx1Z2lucyI6IFsKICAgIHsKICAgICAgInR5cGUiOiAibm9kZS13b3Jrc3BhY2UiLAogICAgICAibWVyZ2UiOiBmYWxzZQogICAgfQogIF0sCiAgInBhY2thZ2VzIjogewogICAgInNyYy9uYXRpdmUvcnVudGltZSI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJzaW1wbGUiLAogICAgICAiY29tcG9uZW50IjogImxpYm9saXBoYXVudC1uYXRpdmUiLAogICAgICAicGFja2FnZS1uYW1lIjogImxpYm9saXBoYXVudC1uYXRpdmUiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIiwKICAgICAgImV4dHJhLWZpbGVzIjogWwogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAicGFja2FnZXMvZGFyd2luLWFybTY0L3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJwYWNrYWdlcy9saW51eC1hcm02NC1nbnUvcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogInBhY2thZ2VzL2xpbnV4LXg2NC1nbnUvcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogInBhY2thZ2VzL3dpbjMyLXg2NC1tc3ZjL3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAiZ2VuZXJpYyIsCiAgICAgICAgICAicGF0aCI6ICJzcmMvbGlib2xpcGhhdW50X25hdGl2ZS5jIgogICAgICAgIH0KICAgICAgXQogICAgfSwKICAgICJzcmMvbmF0aXZlL3Nka3MvcnVzdCI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJydXN0IiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtcnVzdCIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAib2xpcGhhdW50IiwKICAgICAgImNoYW5nZWxvZy1wYXRoIjogIkNIQU5HRUxPRy5tZCIsCiAgICAgICJleHRyYS1maWxlcyI6IFsKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJ0b21sIiwKICAgICAgICAgICJwYXRoIjogImNyYXRlcy9vbGlwaGF1bnQtYnVpbGQvQ2FyZ28udG9tbCIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC5wYWNrYWdlLnZlcnNpb24iCiAgICAgICAgfQogICAgICBdCiAgICB9LAogICAgInNyYy9uYXRpdmUvYnJva2VyIjogewogICAgICAicmVsZWFzZS10eXBlIjogInJ1c3QiLAogICAgICAiY29tcG9uZW50IjogIm9saXBoYXVudC1icm9rZXIiLAogICAgICAicGFja2FnZS1uYW1lIjogIm9saXBoYXVudC1icm9rZXIiLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIiwKICAgICAgImV4dHJhLWZpbGVzIjogWwogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAicGFja2FnZXMvZGFyd2luLWFybTY0L3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJwYWNrYWdlcy9saW51eC1hcm02NC1nbnUvcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogInBhY2thZ2VzL2xpbnV4LXg2NC1nbnUvcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogInBhY2thZ2VzL3dpbjMyLXg2NC1tc3ZjL3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAidG9tbCIsCiAgICAgICAgICAicGF0aCI6ICJjcmF0ZXMvbGludXgtYXJtNjQtZ251L0NhcmdvLnRvbWwiLAogICAgICAgICAgImpzb25wYXRoIjogIiQucGFja2FnZS52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAidG9tbCIsCiAgICAgICAgICAicGF0aCI6ICJjcmF0ZXMvbGludXgteDY0LWdudS9DYXJnby50b21sIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnBhY2thZ2UudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogInRvbWwiLAogICAgICAgICAgInBhdGgiOiAiY3JhdGVzL21hY29zLWFybTY0L0NhcmdvLnRvbWwiLAogICAgICAgICAgImpzb25wYXRoIjogIiQucGFja2FnZS52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAidG9tbCIsCiAgICAgICAgICAicGF0aCI6ICJjcmF0ZXMvd2luZG93cy14NjQtbXN2Yy9DYXJnby50b21sIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnBhY2thZ2UudmVyc2lvbiIKICAgICAgICB9CiAgICAgIF0KICAgIH0sCiAgICAic3JjL25hdGl2ZS9ub2RlLWFkZG9uIjogewogICAgICAicmVsZWFzZS10eXBlIjogIm5vZGUiLAogICAgICAiY29tcG9uZW50IjogIm9saXBoYXVudC1ub2RlLWRpcmVjdCIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAiQG9saXBoYXVudC9ub2RlLWRpcmVjdCIsCiAgICAgICJjaGFuZ2Vsb2ctcGF0aCI6ICJDSEFOR0VMT0cubWQiLAogICAgICAiZXh0cmEtZmlsZXMiOiBbCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJwYWNrYWdlcy9kYXJ3aW4tYXJtNjQvcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogInBhY2thZ2VzL2xpbnV4LWFybTY0LWdudS9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAicGFja2FnZXMvbGludXgteDY0LWdudS9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAicGFja2FnZXMvd2luMzIteDY0LW1zdmMvcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfQogICAgICBdCiAgICB9LAogICAgInNyYy93YXNpeC9ub2RlLWFkZG9uIjogewogICAgICAicmVsZWFzZS10eXBlIjogIm5vZGUiLAogICAgICAiY29tcG9uZW50IjogIm9saXBoYXVudC13YXNpeC1uYXBpIiwKICAgICAgInBhY2thZ2UtbmFtZSI6ICJAb2xpcGhhdW50L3dhc2l4LW5hcGkiLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIiwKICAgICAgImV4dHJhLWZpbGVzIjogWwogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogInRvbWwiLAogICAgICAgICAgInBhdGgiOiAiQ2FyZ28udG9tbCIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC5wYWNrYWdlLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogInBhY2thZ2VzL2Rhcndpbi1hcm02NC9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAicGFja2FnZXMvbGludXgtYXJtNjQtZ251L3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJwYWNrYWdlcy9saW51eC14NjQtZ251L3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJwYWNrYWdlcy93aW4zMi14NjQtbXN2Yy9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9CiAgICAgIF0KICAgIH0sCiAgICAic3JjL25hdGl2ZS9zZGtzL3N3aWZ0IjogewogICAgICAicmVsZWFzZS10eXBlIjogInNpbXBsZSIsCiAgICAgICJjb21wb25lbnQiOiAib2xpcGhhdW50LXN3aWZ0IiwKICAgICAgInBhY2thZ2UtbmFtZSI6ICJvbGlwaGF1bnQtc3dpZnQiLAogICAgICAiaW5pdGlhbC12ZXJzaW9uIjogIjAuNi4wIiwKICAgICAgImJ1bXAtcGF0Y2gtZm9yLW1pbm9yLXByZS1tYWpvciI6IGZhbHNlLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvbmF0aXZlL3Nka3Mva290bGluIjogewogICAgICAicmVsZWFzZS10eXBlIjogInNpbXBsZSIsCiAgICAgICJjb21wb25lbnQiOiAib2xpcGhhdW50LWtvdGxpbiIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAiZGV2Lm9saXBoYXVudDpvbGlwaGF1bnQtYW5kcm9pZCIsCiAgICAgICJ2ZXJzaW9uLWZpbGUiOiAiVkVSU0lPTiIsCiAgICAgICJjaGFuZ2Vsb2ctcGF0aCI6ICJDSEFOR0VMT0cubWQiLAogICAgICAiZXh0cmEtZmlsZXMiOiBbCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAiZ2VuZXJpYyIsCiAgICAgICAgICAicGF0aCI6ICJncmFkbGUucHJvcGVydGllcyIKICAgICAgICB9CiAgICAgIF0KICAgIH0sCiAgICAic3JjL25hdGl2ZS9zZGtzL3JlYWN0LW5hdGl2ZSI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJub2RlIiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtcmVhY3QtbmF0aXZlIiwKICAgICAgInBhY2thZ2UtbmFtZSI6ICJAb2xpcGhhdW50L3JlYWN0LW5hdGl2ZSIsCiAgICAgICJjaGFuZ2Vsb2ctcGF0aCI6ICJDSEFOR0VMT0cubWQiCiAgICB9LAogICAgInNyYy9uYXRpdmUvc2Rrcy90cyI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJub2RlIiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtanMiLAogICAgICAicGFja2FnZS1uYW1lIjogIkBvbGlwaGF1bnQvdHMiLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wZ19oYXNoaWRzIjogewogICAgICAicmVsZWFzZS10eXBlIjogInNpbXBsZSIsCiAgICAgICJjb21wb25lbnQiOiAib2xpcGhhdW50LWV4dGVuc2lvbi1wZy1oYXNoaWRzIiwKICAgICAgInBhY2thZ2UtbmFtZSI6ICJvbGlwaGF1bnQtZXh0ZW5zaW9uLXBnLWhhc2hpZHMiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wZ19pdm0iOiB7CiAgICAgICJyZWxlYXNlLXR5cGUiOiAic2ltcGxlIiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtZXh0ZW5zaW9uLXBnLWl2bSIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAib2xpcGhhdW50LWV4dGVuc2lvbi1wZy1pdm0iLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wZ190ZXh0c2VhcmNoIjogewogICAgICAicmVsZWFzZS10eXBlIjogInNpbXBsZSIsCiAgICAgICJjb21wb25lbnQiOiAib2xpcGhhdW50LWV4dGVuc2lvbi1wZy10ZXh0c2VhcmNoIiwKICAgICAgInBhY2thZ2UtbmFtZSI6ICJvbGlwaGF1bnQtZXh0ZW5zaW9uLXBnLXRleHRzZWFyY2giLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wZ191dWlkdjciOiB7CiAgICAgICJyZWxlYXNlLXR5cGUiOiAic2ltcGxlIiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtZXh0ZW5zaW9uLXBnLXV1aWR2NyIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAib2xpcGhhdW50LWV4dGVuc2lvbi1wZy11dWlkdjciLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wZ3RhcCI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJzaW1wbGUiLAogICAgICAiY29tcG9uZW50IjogIm9saXBoYXVudC1leHRlbnNpb24tcGd0YXAiLAogICAgICAicGFja2FnZS1uYW1lIjogIm9saXBoYXVudC1leHRlbnNpb24tcGd0YXAiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wb3N0Z2lzIjogewogICAgICAicmVsZWFzZS10eXBlIjogInNpbXBsZSIsCiAgICAgICJjb21wb25lbnQiOiAib2xpcGhhdW50LWV4dGVuc2lvbi1wb3N0Z2lzIiwKICAgICAgInBhY2thZ2UtbmFtZSI6ICJvbGlwaGF1bnQtZXh0ZW5zaW9uLXBvc3RnaXMiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC92ZWN0b3IiOiB7CiAgICAgICJyZWxlYXNlLXR5cGUiOiAic2ltcGxlIiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtZXh0ZW5zaW9uLXZlY3RvciIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAib2xpcGhhdW50LWV4dGVuc2lvbi12ZWN0b3IiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvd2FzaXgvcnVudGltZSI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJzaW1wbGUiLAogICAgICAiY29tcG9uZW50IjogImxpYm9saXBoYXVudC13YXNpeCIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAibGlib2xpcGhhdW50LXdhc2l4IiwKICAgICAgInZlcnNpb24tZmlsZSI6ICJWRVJTSU9OIiwKICAgICAgImNoYW5nZWxvZy1wYXRoIjogIkNIQU5HRUxPRy5tZCIsCiAgICAgICJleHRyYS1maWxlcyI6IFsKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJ0b21sIiwKICAgICAgICAgICJwYXRoIjogImNyYXRlcy9hc3NldHMvQ2FyZ28udG9tbCIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC5wYWNrYWdlLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJ0b21sIiwKICAgICAgICAgICJwYXRoIjogImNyYXRlcy9hb3QvYWFyY2g2NC1hcHBsZS1kYXJ3aW4vQ2FyZ28udG9tbCIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC5wYWNrYWdlLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJ0b21sIiwKICAgICAgICAgICJwYXRoIjogImNyYXRlcy9hb3QvYWFyY2g2NC11bmtub3duLWxpbnV4LWdudS9DYXJnby50b21sIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnBhY2thZ2UudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogInRvbWwiLAogICAgICAgICAgInBhdGgiOiAiY3JhdGVzL2FvdC94ODZfNjQtcGMtd2luZG93cy1tc3ZjL0NhcmdvLnRvbWwiLAogICAgICAgICAgImpzb25wYXRoIjogIiQucGFja2FnZS52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAidG9tbCIsCiAgICAgICAgICAicGF0aCI6ICJjcmF0ZXMvYW90L3g4Nl82NC11bmtub3duLWxpbnV4LWdudS9DYXJnby50b21sIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnBhY2thZ2UudmVyc2lvbiIKICAgICAgICB9CiAgICAgIF0KICAgIH0sCiAgICAic3JjL3dhc2l4L3Bvc3RtYXN0ZXIiOiB7CiAgICAgICJyZWxlYXNlLXR5cGUiOiAic2ltcGxlIiwKICAgICAgImNvbXBvbmVudCI6ICJsaWJvbGlwaGF1bnQtd2FzaXgtcG9zdG1hc3RlciIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAibGlib2xpcGhhdW50LXdhc2l4LXBvc3RtYXN0ZXIiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvd2FzaXgvc2Rrcy9ydXN0IjogewogICAgICAicmVsZWFzZS10eXBlIjogInJ1c3QiLAogICAgICAiY29tcG9uZW50IjogIm9saXBoYXVudC13YXNpeC1ydXN0IiwKICAgICAgInBhY2thZ2UtbmFtZSI6ICJvbGlwaGF1bnQtd2FzaXgiLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvd2FzaXgvc2Rrcy90cyI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJub2RlIiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtd2FzaXgtdHMiLAogICAgICAicGFja2FnZS1uYW1lIjogIkBvbGlwaGF1bnQvd2FzaXgtdHMiLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvcXVlcnkvcnVzdCI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJydXN0IiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtcXVlcnkiLAogICAgICAicGFja2FnZS1uYW1lIjogIm9saXBoYXVudC1xdWVyeSIsCiAgICAgICJjaGFuZ2Vsb2ctcGF0aCI6ICJDSEFOR0VMT0cubWQiCiAgICB9LAogICAgInNyYy9xdWVyeS90cyI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJub2RlIiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtcXVlcnktdHMiLAogICAgICAicGFja2FnZS1uYW1lIjogIkBvbGlwaGF1bnQvdHMtcXVlcnkiLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvbmF0aXZlL3J1c3QtYmluZGluZ3MiOiB7CiAgICAgICJyZWxlYXNlLXR5cGUiOiAicnVzdCIsCiAgICAgICJjb21wb25lbnQiOiAibGlib2xpcGhhdW50LW5hdGl2ZS1iaW5kaW5ncyIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAibGlib2xpcGhhdW50LW5hdGl2ZS1iaW5kaW5ncyIsCiAgICAgICJjaGFuZ2Vsb2ctcGF0aCI6ICJDSEFOR0VMT0cubWQiCiAgICB9LAogICAgInNyYy9uYXRpdmUvcG9zdGdyZXMtdG9vbHMiOiB7CiAgICAgICJyZWxlYXNlLXR5cGUiOiAic2ltcGxlIiwKICAgICAgImNvbXBvbmVudCI6ICJwb3N0Z3Jlcy10b29scy1uYXRpdmUiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIiwKICAgICAgImluaXRpYWwtdmVyc2lvbiI6ICIwLjIuMSIsCiAgICAgICJleHRyYS1maWxlcyI6IFsKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogIm5wbS1wbGF0Zm9ybXMvZGFyd2luLWFybTY0L3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJucG0tcGxhdGZvcm1zL2xpbnV4LWFybTY0LWdudS9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAibnBtLXBsYXRmb3Jtcy9saW51eC14NjQtZ251L3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJucG0tcGxhdGZvcm1zL3dpbjMyLXg2NC1tc3ZjL3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJucG0vcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJ0b21sIiwKICAgICAgICAgICJwYXRoIjogImNyYXRlcy90b29scy9DYXJnby50b21sIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnBhY2thZ2UudmVyc2lvbiIKICAgICAgICB9CiAgICAgIF0KICAgIH0sCiAgICAic3JjL3dhc2l4L3Bvc3RncmVzLXRvb2xzIjogewogICAgICAicmVsZWFzZS10eXBlIjogInNpbXBsZSIsCiAgICAgICJjb21wb25lbnQiOiAicG9zdGdyZXMtdG9vbHMtd2FzaXgiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIiwKICAgICAgImluaXRpYWwtdmVyc2lvbiI6ICIwLjIuMSIsCiAgICAgICJleHRyYS1maWxlcyI6IFsKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJ0b21sIiwKICAgICAgICAgICJwYXRoIjogImNyYXRlcy90b29scy9DYXJnby50b21sIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnBhY2thZ2UudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogInRvbWwiLAogICAgICAgICAgInBhdGgiOiAiY3JhdGVzL2FvdC9hYXJjaDY0LWFwcGxlLWRhcndpbi9DYXJnby50b21sIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnBhY2thZ2UudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogInRvbWwiLAogICAgICAgICAgInBhdGgiOiAiY3JhdGVzL2FvdC9hYXJjaDY0LXVua25vd24tbGludXgtZ251L0NhcmdvLnRvbWwiLAogICAgICAgICAgImpzb25wYXRoIjogIiQucGFja2FnZS52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAidG9tbCIsCiAgICAgICAgICAicGF0aCI6ICJjcmF0ZXMvYW90L3g4Nl82NC1wYy13aW5kb3dzLW1zdmMvQ2FyZ28udG9tbCIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC5wYWNrYWdlLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJ0b21sIiwKICAgICAgICAgICJwYXRoIjogImNyYXRlcy9hb3QveDg2XzY0LXVua25vd24tbGludXgtZ251L0NhcmdvLnRvbWwiLAogICAgICAgICAgImpzb25wYXRoIjogIiQucGFja2FnZS52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJucG0vcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogInRzL3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJucG0tcGxhdGZvcm1zL2xpbnV4LWFybTY0LWdudS9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAibnBtLXBsYXRmb3Jtcy9saW51eC14NjQtZ251L3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJucG0tcGxhdGZvcm1zL2Rhcndpbi1hcm02NC9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAibnBtLXBsYXRmb3Jtcy93aW4zMi14NjQtbXN2Yy9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9CiAgICAgIF0KICAgIH0sCiAgICAic3JjL2RhdGFiYXNlLXJlc291cmNlcyI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJzaW1wbGUiLAogICAgICAiY29tcG9uZW50IjogImRhdGFiYXNlLXJlc291cmNlcyIsCiAgICAgICJ2ZXJzaW9uLWZpbGUiOiAiVkVSU0lPTiIsCiAgICAgICJjaGFuZ2Vsb2ctcGF0aCI6ICJDSEFOR0VMT0cubWQiLAogICAgICAiaW5pdGlhbC12ZXJzaW9uIjogIjAuMi4xIiwKICAgICAgImV4dHJhLWZpbGVzIjogWwogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAiaWN1L25wbS9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImdlbmVyaWMiLAogICAgICAgICAgInBhdGgiOiAiaWN1L25wbS9PbGlwaGF1bnRJQ1UucG9kc3BlYyIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogInRvbWwiLAogICAgICAgICAgInBhdGgiOiAiaWN1L2NhcmdvL0NhcmdvLnRvbWwiLAogICAgICAgICAgImpzb25wYXRoIjogIiQucGFja2FnZS52ZXJzaW9uIgogICAgICAgIH0KICAgICAgXQogICAgfSwKICAgICJzcmMvd2FzaXgvcGd3aXJlLXNlcnZlciI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJydXN0IiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtcGd3aXJlLXNlcnZlciIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAib2xpcGhhdW50LXBnd2lyZS1zZXJ2ZXIiLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIiwKICAgICAgImluaXRpYWwtdmVyc2lvbiI6ICIwLjEuMCIKICAgIH0KICB9Cn0K" + }, + "repos/f0rr0/oliphaunt/contents/.release-please-manifest.json?ref=e619376b438b70cd174750c9648bcc9255342eb8": { + "type": "file", + "path": ".release-please-manifest.json", + "sha": "ff6a63c0c0235808177c6a63c1cebd79e7696996", + "encoding": "base64", + "content": "ewogICJzcmMvbmF0aXZlL3J1bnRpbWUiOiAiMC4yLjAiLAogICJzcmMvbmF0aXZlL3Nka3MvcnVzdCI6ICIwLjIuMCIsCiAgInNyYy9uYXRpdmUvYnJva2VyIjogIjAuMi4wIiwKICAic3JjL25hdGl2ZS9ub2RlLWFkZG9uIjogIjAuMi4wIiwKICAic3JjL3dhc2l4L25vZGUtYWRkb24iOiAiMC4xLjAiLAogICJzcmMvbmF0aXZlL3Nka3Mvc3dpZnQiOiAiMC43LjAiLAogICJzcmMvbmF0aXZlL3Nka3Mva290bGluIjogIjAuMi4wIiwKICAic3JjL25hdGl2ZS9zZGtzL3JlYWN0LW5hdGl2ZSI6ICIwLjIuMCIsCiAgInNyYy9uYXRpdmUvc2Rrcy90cyI6ICIwLjIuMCIsCiAgInNyYy9leHRlbnNpb25zL2V4dGVybmFsL3BnX2hhc2hpZHMiOiAiMC4yLjAiLAogICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wZ19pdm0iOiAiMC4yLjAiLAogICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wZ190ZXh0c2VhcmNoIjogIjAuMi4wIiwKICAic3JjL2V4dGVuc2lvbnMvZXh0ZXJuYWwvcGdfdXVpZHY3IjogIjAuMi4wIiwKICAic3JjL2V4dGVuc2lvbnMvZXh0ZXJuYWwvcGd0YXAiOiAiMC4yLjAiLAogICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wb3N0Z2lzIjogIjAuMi4wIiwKICAic3JjL2V4dGVuc2lvbnMvZXh0ZXJuYWwvdmVjdG9yIjogIjAuMi4wIiwKICAic3JjL3dhc2l4L3J1bnRpbWUiOiAiMC4yLjAiLAogICJzcmMvd2FzaXgvcG9zdG1hc3RlciI6ICIwLjEuMCIsCiAgInNyYy93YXNpeC9zZGtzL3J1c3QiOiAiMC4yLjAiLAogICJzcmMvd2FzaXgvc2Rrcy90cyI6ICIwLjEuMCIsCiAgInNyYy9xdWVyeS9ydXN0IjogIjAuMS4wIiwKICAic3JjL3F1ZXJ5L3RzIjogIjAuMS4wIiwKICAic3JjL25hdGl2ZS9ydXN0LWJpbmRpbmdzIjogIjAuMS4wIiwKICAic3JjL25hdGl2ZS9wb3N0Z3Jlcy10b29scyI6ICIwLjIuMSIsCiAgInNyYy93YXNpeC9wb3N0Z3Jlcy10b29scyI6ICIwLjIuMSIsCiAgInNyYy9kYXRhYmFzZS1yZXNvdXJjZXMiOiAiMC4yLjEiLAogICJzcmMvd2FzaXgvcGd3aXJlLXNlcnZlciI6ICIwLjEuMCIKfQo=" + }, + "repos/f0rr0/oliphaunt/contents/release-please-config.json?ref=c51052fe8b8ffc7e992266c5ab3d7a63b47441e7": { + "type": "file", + "path": "release-please-config.json", + "sha": "7d7334c6e3cfc2768ea9fa4bf97a2f3b22fbab8a", + "encoding": "base64", + "content": "ewogICIkc2NoZW1hIjogImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9nb29nbGVhcGlzL3JlbGVhc2UtcGxlYXNlL21haW4vc2NoZW1hcy9jb25maWcuanNvbiIsCiAgImluY2x1ZGUtdi1pbi10YWciOiB0cnVlLAogICJzZXBhcmF0ZS1wdWxsLXJlcXVlc3RzIjogZmFsc2UsCiAgInRhZy1zZXBhcmF0b3IiOiAiLSIsCiAgInB1bGwtcmVxdWVzdC10aXRsZS1wYXR0ZXJuIjogImNob3JlJHtzY29wZX06IHJlbGVhc2Uke2NvbXBvbmVudH0gJHt2ZXJzaW9ufSIsCiAgImdyb3VwLXB1bGwtcmVxdWVzdC10aXRsZS1wYXR0ZXJuIjogImNob3JlKHJlbGVhc2UpOiBwcmVwYXJlICR7YnJhbmNofSByZWxlYXNlcyIsCiAgImluaXRpYWwtdmVyc2lvbiI6ICIwLjEuMCIsCiAgImJ1bXAtbWlub3ItcHJlLW1ham9yIjogdHJ1ZSwKICAiYnVtcC1wYXRjaC1mb3ItbWlub3ItcHJlLW1ham9yIjogdHJ1ZSwKICAiY2hhbmdlbG9nLXNlY3Rpb25zIjogWwogICAgewogICAgICAidHlwZSI6ICJmZWF0IiwKICAgICAgInNlY3Rpb24iOiAiRmVhdHVyZXMiLAogICAgICAiaGlkZGVuIjogZmFsc2UKICAgIH0sCiAgICB7CiAgICAgICJ0eXBlIjogImZpeCIsCiAgICAgICJzZWN0aW9uIjogIkJ1ZyBGaXhlcyIsCiAgICAgICJoaWRkZW4iOiBmYWxzZQogICAgfSwKICAgIHsKICAgICAgInR5cGUiOiAicGVyZiIsCiAgICAgICJzZWN0aW9uIjogIlBlcmZvcm1hbmNlIEltcHJvdmVtZW50cyIsCiAgICAgICJoaWRkZW4iOiBmYWxzZQogICAgfSwKICAgIHsKICAgICAgInR5cGUiOiAicmVmYWN0b3IiLAogICAgICAic2VjdGlvbiI6ICJDb2RlIFJlZmFjdG9yaW5nIiwKICAgICAgImhpZGRlbiI6IGZhbHNlCiAgICB9LAogICAgewogICAgICAidHlwZSI6ICJyZXZlcnQiLAogICAgICAic2VjdGlvbiI6ICJSZXZlcnRzIiwKICAgICAgImhpZGRlbiI6IGZhbHNlCiAgICB9CiAgXSwKICAicGx1Z2lucyI6IFsKICAgIHsKICAgICAgInR5cGUiOiAibm9kZS13b3Jrc3BhY2UiLAogICAgICAibWVyZ2UiOiBmYWxzZQogICAgfQogIF0sCiAgInBhY2thZ2VzIjogewogICAgInNyYy9uYXRpdmUvcnVudGltZSI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJzaW1wbGUiLAogICAgICAiY29tcG9uZW50IjogImxpYm9saXBoYXVudC1uYXRpdmUiLAogICAgICAicGFja2FnZS1uYW1lIjogImxpYm9saXBoYXVudC1uYXRpdmUiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIiwKICAgICAgImV4dHJhLWZpbGVzIjogWwogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAicGFja2FnZXMvZGFyd2luLWFybTY0L3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJwYWNrYWdlcy9saW51eC1hcm02NC1nbnUvcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogInBhY2thZ2VzL2xpbnV4LXg2NC1nbnUvcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogInBhY2thZ2VzL3dpbjMyLXg2NC1tc3ZjL3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAiZ2VuZXJpYyIsCiAgICAgICAgICAicGF0aCI6ICJzcmMvbGlib2xpcGhhdW50X25hdGl2ZS5jIgogICAgICAgIH0KICAgICAgXQogICAgfSwKICAgICJzcmMvbmF0aXZlL3Nka3MvcnVzdCI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJydXN0IiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtcnVzdCIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAib2xpcGhhdW50IiwKICAgICAgImNoYW5nZWxvZy1wYXRoIjogIkNIQU5HRUxPRy5tZCIsCiAgICAgICJleHRyYS1maWxlcyI6IFsKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJ0b21sIiwKICAgICAgICAgICJwYXRoIjogImNyYXRlcy9vbGlwaGF1bnQtYnVpbGQvQ2FyZ28udG9tbCIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC5wYWNrYWdlLnZlcnNpb24iCiAgICAgICAgfQogICAgICBdCiAgICB9LAogICAgInNyYy9uYXRpdmUvYnJva2VyIjogewogICAgICAicmVsZWFzZS10eXBlIjogInJ1c3QiLAogICAgICAiY29tcG9uZW50IjogIm9saXBoYXVudC1icm9rZXIiLAogICAgICAicGFja2FnZS1uYW1lIjogIm9saXBoYXVudC1icm9rZXIiLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIiwKICAgICAgImV4dHJhLWZpbGVzIjogWwogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAicGFja2FnZXMvZGFyd2luLWFybTY0L3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJwYWNrYWdlcy9saW51eC1hcm02NC1nbnUvcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogInBhY2thZ2VzL2xpbnV4LXg2NC1nbnUvcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogInBhY2thZ2VzL3dpbjMyLXg2NC1tc3ZjL3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAidG9tbCIsCiAgICAgICAgICAicGF0aCI6ICJjcmF0ZXMvbGludXgtYXJtNjQtZ251L0NhcmdvLnRvbWwiLAogICAgICAgICAgImpzb25wYXRoIjogIiQucGFja2FnZS52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAidG9tbCIsCiAgICAgICAgICAicGF0aCI6ICJjcmF0ZXMvbGludXgteDY0LWdudS9DYXJnby50b21sIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnBhY2thZ2UudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogInRvbWwiLAogICAgICAgICAgInBhdGgiOiAiY3JhdGVzL21hY29zLWFybTY0L0NhcmdvLnRvbWwiLAogICAgICAgICAgImpzb25wYXRoIjogIiQucGFja2FnZS52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAidG9tbCIsCiAgICAgICAgICAicGF0aCI6ICJjcmF0ZXMvd2luZG93cy14NjQtbXN2Yy9DYXJnby50b21sIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnBhY2thZ2UudmVyc2lvbiIKICAgICAgICB9CiAgICAgIF0KICAgIH0sCiAgICAic3JjL25hdGl2ZS9ub2RlLWFkZG9uIjogewogICAgICAicmVsZWFzZS10eXBlIjogIm5vZGUiLAogICAgICAiY29tcG9uZW50IjogIm9saXBoYXVudC1ub2RlLWRpcmVjdCIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAiQG9saXBoYXVudC9ub2RlLWRpcmVjdCIsCiAgICAgICJjaGFuZ2Vsb2ctcGF0aCI6ICJDSEFOR0VMT0cubWQiLAogICAgICAiZXh0cmEtZmlsZXMiOiBbCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJwYWNrYWdlcy9kYXJ3aW4tYXJtNjQvcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogInBhY2thZ2VzL2xpbnV4LWFybTY0LWdudS9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAicGFja2FnZXMvbGludXgteDY0LWdudS9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAicGFja2FnZXMvd2luMzIteDY0LW1zdmMvcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfQogICAgICBdCiAgICB9LAogICAgInNyYy93YXNpeC9ub2RlLWFkZG9uIjogewogICAgICAicmVsZWFzZS10eXBlIjogIm5vZGUiLAogICAgICAiY29tcG9uZW50IjogIm9saXBoYXVudC13YXNpeC1uYXBpIiwKICAgICAgInBhY2thZ2UtbmFtZSI6ICJAb2xpcGhhdW50L3dhc2l4LW5hcGkiLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIiwKICAgICAgImV4dHJhLWZpbGVzIjogWwogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogInRvbWwiLAogICAgICAgICAgInBhdGgiOiAiQ2FyZ28udG9tbCIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC5wYWNrYWdlLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogInBhY2thZ2VzL2Rhcndpbi1hcm02NC9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAicGFja2FnZXMvbGludXgtYXJtNjQtZ251L3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJwYWNrYWdlcy9saW51eC14NjQtZ251L3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJwYWNrYWdlcy93aW4zMi14NjQtbXN2Yy9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9CiAgICAgIF0KICAgIH0sCiAgICAic3JjL25hdGl2ZS9zZGtzL3N3aWZ0IjogewogICAgICAicmVsZWFzZS10eXBlIjogInNpbXBsZSIsCiAgICAgICJjb21wb25lbnQiOiAib2xpcGhhdW50LXN3aWZ0IiwKICAgICAgInBhY2thZ2UtbmFtZSI6ICJvbGlwaGF1bnQtc3dpZnQiLAogICAgICAiaW5pdGlhbC12ZXJzaW9uIjogIjAuNi4wIiwKICAgICAgImJ1bXAtcGF0Y2gtZm9yLW1pbm9yLXByZS1tYWpvciI6IGZhbHNlLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvbmF0aXZlL3Nka3Mva290bGluIjogewogICAgICAicmVsZWFzZS10eXBlIjogInNpbXBsZSIsCiAgICAgICJjb21wb25lbnQiOiAib2xpcGhhdW50LWtvdGxpbiIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAiZGV2Lm9saXBoYXVudDpvbGlwaGF1bnQtYW5kcm9pZCIsCiAgICAgICJ2ZXJzaW9uLWZpbGUiOiAiVkVSU0lPTiIsCiAgICAgICJjaGFuZ2Vsb2ctcGF0aCI6ICJDSEFOR0VMT0cubWQiLAogICAgICAiZXh0cmEtZmlsZXMiOiBbCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAiZ2VuZXJpYyIsCiAgICAgICAgICAicGF0aCI6ICJncmFkbGUucHJvcGVydGllcyIKICAgICAgICB9CiAgICAgIF0KICAgIH0sCiAgICAic3JjL25hdGl2ZS9zZGtzL3JlYWN0LW5hdGl2ZSI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJub2RlIiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtcmVhY3QtbmF0aXZlIiwKICAgICAgInBhY2thZ2UtbmFtZSI6ICJAb2xpcGhhdW50L3JlYWN0LW5hdGl2ZSIsCiAgICAgICJjaGFuZ2Vsb2ctcGF0aCI6ICJDSEFOR0VMT0cubWQiCiAgICB9LAogICAgInNyYy9uYXRpdmUvc2Rrcy90cyI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJub2RlIiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtanMiLAogICAgICAicGFja2FnZS1uYW1lIjogIkBvbGlwaGF1bnQvdHMiLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wZ19oYXNoaWRzIjogewogICAgICAicmVsZWFzZS10eXBlIjogInNpbXBsZSIsCiAgICAgICJjb21wb25lbnQiOiAib2xpcGhhdW50LWV4dGVuc2lvbi1wZy1oYXNoaWRzIiwKICAgICAgInBhY2thZ2UtbmFtZSI6ICJvbGlwaGF1bnQtZXh0ZW5zaW9uLXBnLWhhc2hpZHMiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wZ19pdm0iOiB7CiAgICAgICJyZWxlYXNlLXR5cGUiOiAic2ltcGxlIiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtZXh0ZW5zaW9uLXBnLWl2bSIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAib2xpcGhhdW50LWV4dGVuc2lvbi1wZy1pdm0iLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wZ190ZXh0c2VhcmNoIjogewogICAgICAicmVsZWFzZS10eXBlIjogInNpbXBsZSIsCiAgICAgICJjb21wb25lbnQiOiAib2xpcGhhdW50LWV4dGVuc2lvbi1wZy10ZXh0c2VhcmNoIiwKICAgICAgInBhY2thZ2UtbmFtZSI6ICJvbGlwaGF1bnQtZXh0ZW5zaW9uLXBnLXRleHRzZWFyY2giLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wZ191dWlkdjciOiB7CiAgICAgICJyZWxlYXNlLXR5cGUiOiAic2ltcGxlIiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtZXh0ZW5zaW9uLXBnLXV1aWR2NyIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAib2xpcGhhdW50LWV4dGVuc2lvbi1wZy11dWlkdjciLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wZ3RhcCI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJzaW1wbGUiLAogICAgICAiY29tcG9uZW50IjogIm9saXBoYXVudC1leHRlbnNpb24tcGd0YXAiLAogICAgICAicGFja2FnZS1uYW1lIjogIm9saXBoYXVudC1leHRlbnNpb24tcGd0YXAiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wb3N0Z2lzIjogewogICAgICAicmVsZWFzZS10eXBlIjogInNpbXBsZSIsCiAgICAgICJjb21wb25lbnQiOiAib2xpcGhhdW50LWV4dGVuc2lvbi1wb3N0Z2lzIiwKICAgICAgInBhY2thZ2UtbmFtZSI6ICJvbGlwaGF1bnQtZXh0ZW5zaW9uLXBvc3RnaXMiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC92ZWN0b3IiOiB7CiAgICAgICJyZWxlYXNlLXR5cGUiOiAic2ltcGxlIiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtZXh0ZW5zaW9uLXZlY3RvciIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAib2xpcGhhdW50LWV4dGVuc2lvbi12ZWN0b3IiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvd2FzaXgvcnVudGltZSI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJzaW1wbGUiLAogICAgICAiY29tcG9uZW50IjogImxpYm9saXBoYXVudC13YXNpeCIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAibGlib2xpcGhhdW50LXdhc2l4IiwKICAgICAgInZlcnNpb24tZmlsZSI6ICJWRVJTSU9OIiwKICAgICAgImNoYW5nZWxvZy1wYXRoIjogIkNIQU5HRUxPRy5tZCIsCiAgICAgICJleHRyYS1maWxlcyI6IFsKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJ0b21sIiwKICAgICAgICAgICJwYXRoIjogImNyYXRlcy9hc3NldHMvQ2FyZ28udG9tbCIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC5wYWNrYWdlLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJ0b21sIiwKICAgICAgICAgICJwYXRoIjogImNyYXRlcy9hb3QvYWFyY2g2NC1hcHBsZS1kYXJ3aW4vQ2FyZ28udG9tbCIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC5wYWNrYWdlLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJ0b21sIiwKICAgICAgICAgICJwYXRoIjogImNyYXRlcy9hb3QvYWFyY2g2NC11bmtub3duLWxpbnV4LWdudS9DYXJnby50b21sIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnBhY2thZ2UudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogInRvbWwiLAogICAgICAgICAgInBhdGgiOiAiY3JhdGVzL2FvdC94ODZfNjQtcGMtd2luZG93cy1tc3ZjL0NhcmdvLnRvbWwiLAogICAgICAgICAgImpzb25wYXRoIjogIiQucGFja2FnZS52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAidG9tbCIsCiAgICAgICAgICAicGF0aCI6ICJjcmF0ZXMvYW90L3g4Nl82NC11bmtub3duLWxpbnV4LWdudS9DYXJnby50b21sIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnBhY2thZ2UudmVyc2lvbiIKICAgICAgICB9CiAgICAgIF0KICAgIH0sCiAgICAic3JjL3dhc2l4L3Bvc3RtYXN0ZXIiOiB7CiAgICAgICJyZWxlYXNlLXR5cGUiOiAic2ltcGxlIiwKICAgICAgImNvbXBvbmVudCI6ICJsaWJvbGlwaGF1bnQtd2FzaXgtcG9zdG1hc3RlciIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAibGlib2xpcGhhdW50LXdhc2l4LXBvc3RtYXN0ZXIiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvd2FzaXgvc2Rrcy9ydXN0IjogewogICAgICAicmVsZWFzZS10eXBlIjogInJ1c3QiLAogICAgICAiY29tcG9uZW50IjogIm9saXBoYXVudC13YXNpeC1ydXN0IiwKICAgICAgInBhY2thZ2UtbmFtZSI6ICJvbGlwaGF1bnQtd2FzaXgiLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvd2FzaXgvc2Rrcy90cyI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJub2RlIiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtd2FzaXgtdHMiLAogICAgICAicGFja2FnZS1uYW1lIjogIkBvbGlwaGF1bnQvd2FzaXgtdHMiLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvcXVlcnkvcnVzdCI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJydXN0IiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtcXVlcnkiLAogICAgICAicGFja2FnZS1uYW1lIjogIm9saXBoYXVudC1xdWVyeSIsCiAgICAgICJjaGFuZ2Vsb2ctcGF0aCI6ICJDSEFOR0VMT0cubWQiCiAgICB9LAogICAgInNyYy9xdWVyeS90cyI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJub2RlIiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtcXVlcnktdHMiLAogICAgICAicGFja2FnZS1uYW1lIjogIkBvbGlwaGF1bnQvdHMtcXVlcnkiLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIgogICAgfSwKICAgICJzcmMvbmF0aXZlL3J1c3QtYmluZGluZ3MiOiB7CiAgICAgICJyZWxlYXNlLXR5cGUiOiAicnVzdCIsCiAgICAgICJjb21wb25lbnQiOiAibGlib2xpcGhhdW50LW5hdGl2ZS1iaW5kaW5ncyIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAibGlib2xpcGhhdW50LW5hdGl2ZS1iaW5kaW5ncyIsCiAgICAgICJjaGFuZ2Vsb2ctcGF0aCI6ICJDSEFOR0VMT0cubWQiCiAgICB9LAogICAgInNyYy9uYXRpdmUvcG9zdGdyZXMtdG9vbHMiOiB7CiAgICAgICJyZWxlYXNlLXR5cGUiOiAic2ltcGxlIiwKICAgICAgImNvbXBvbmVudCI6ICJwb3N0Z3Jlcy10b29scy1uYXRpdmUiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIiwKICAgICAgImluaXRpYWwtdmVyc2lvbiI6ICIwLjIuMSIsCiAgICAgICJleHRyYS1maWxlcyI6IFsKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogIm5wbS1wbGF0Zm9ybXMvZGFyd2luLWFybTY0L3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJucG0tcGxhdGZvcm1zL2xpbnV4LWFybTY0LWdudS9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAibnBtLXBsYXRmb3Jtcy9saW51eC14NjQtZ251L3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJucG0tcGxhdGZvcm1zL3dpbjMyLXg2NC1tc3ZjL3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJucG0vcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJ0b21sIiwKICAgICAgICAgICJwYXRoIjogImNyYXRlcy90b29scy9DYXJnby50b21sIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnBhY2thZ2UudmVyc2lvbiIKICAgICAgICB9CiAgICAgIF0KICAgIH0sCiAgICAic3JjL3dhc2l4L3Bvc3RncmVzLXRvb2xzIjogewogICAgICAicmVsZWFzZS10eXBlIjogInNpbXBsZSIsCiAgICAgICJjb21wb25lbnQiOiAicG9zdGdyZXMtdG9vbHMtd2FzaXgiLAogICAgICAidmVyc2lvbi1maWxlIjogIlZFUlNJT04iLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIiwKICAgICAgImluaXRpYWwtdmVyc2lvbiI6ICIwLjIuMSIsCiAgICAgICJleHRyYS1maWxlcyI6IFsKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJ0b21sIiwKICAgICAgICAgICJwYXRoIjogImNyYXRlcy90b29scy9DYXJnby50b21sIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnBhY2thZ2UudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogInRvbWwiLAogICAgICAgICAgInBhdGgiOiAiY3JhdGVzL2FvdC9hYXJjaDY0LWFwcGxlLWRhcndpbi9DYXJnby50b21sIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnBhY2thZ2UudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogInRvbWwiLAogICAgICAgICAgInBhdGgiOiAiY3JhdGVzL2FvdC9hYXJjaDY0LXVua25vd24tbGludXgtZ251L0NhcmdvLnRvbWwiLAogICAgICAgICAgImpzb25wYXRoIjogIiQucGFja2FnZS52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAidG9tbCIsCiAgICAgICAgICAicGF0aCI6ICJjcmF0ZXMvYW90L3g4Nl82NC1wYy13aW5kb3dzLW1zdmMvQ2FyZ28udG9tbCIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC5wYWNrYWdlLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJ0b21sIiwKICAgICAgICAgICJwYXRoIjogImNyYXRlcy9hb3QveDg2XzY0LXVua25vd24tbGludXgtZ251L0NhcmdvLnRvbWwiLAogICAgICAgICAgImpzb25wYXRoIjogIiQucGFja2FnZS52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJucG0vcGFja2FnZS5qc29uIiwKICAgICAgICAgICJqc29ucGF0aCI6ICIkLnZlcnNpb24iCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAidHlwZSI6ICJqc29uIiwKICAgICAgICAgICJwYXRoIjogInRzL3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJucG0tcGxhdGZvcm1zL2xpbnV4LWFybTY0LWdudS9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAibnBtLXBsYXRmb3Jtcy9saW51eC14NjQtZ251L3BhY2thZ2UuanNvbiIsCiAgICAgICAgICAianNvbnBhdGgiOiAiJC52ZXJzaW9uIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgInR5cGUiOiAianNvbiIsCiAgICAgICAgICAicGF0aCI6ICJucG0tcGxhdGZvcm1zL2Rhcndpbi1hcm02NC9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAibnBtLXBsYXRmb3Jtcy93aW4zMi14NjQtbXN2Yy9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9CiAgICAgIF0KICAgIH0sCiAgICAic3JjL2RhdGFiYXNlLXJlc291cmNlcyI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJzaW1wbGUiLAogICAgICAiY29tcG9uZW50IjogImRhdGFiYXNlLXJlc291cmNlcyIsCiAgICAgICJ2ZXJzaW9uLWZpbGUiOiAiVkVSU0lPTiIsCiAgICAgICJjaGFuZ2Vsb2ctcGF0aCI6ICJDSEFOR0VMT0cubWQiLAogICAgICAiaW5pdGlhbC12ZXJzaW9uIjogIjAuMi4xIiwKICAgICAgImV4dHJhLWZpbGVzIjogWwogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImpzb24iLAogICAgICAgICAgInBhdGgiOiAiaWN1L25wbS9wYWNrYWdlLmpzb24iLAogICAgICAgICAgImpzb25wYXRoIjogIiQudmVyc2lvbiIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogImdlbmVyaWMiLAogICAgICAgICAgInBhdGgiOiAiaWN1L25wbS9PbGlwaGF1bnRJQ1UucG9kc3BlYyIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJ0eXBlIjogInRvbWwiLAogICAgICAgICAgInBhdGgiOiAiaWN1L2NhcmdvL0NhcmdvLnRvbWwiLAogICAgICAgICAgImpzb25wYXRoIjogIiQucGFja2FnZS52ZXJzaW9uIgogICAgICAgIH0KICAgICAgXQogICAgfSwKICAgICJzcmMvd2FzaXgvcGd3aXJlLXNlcnZlciI6IHsKICAgICAgInJlbGVhc2UtdHlwZSI6ICJydXN0IiwKICAgICAgImNvbXBvbmVudCI6ICJvbGlwaGF1bnQtcGd3aXJlLXNlcnZlciIsCiAgICAgICJwYWNrYWdlLW5hbWUiOiAib2xpcGhhdW50LXBnd2lyZS1zZXJ2ZXIiLAogICAgICAiY2hhbmdlbG9nLXBhdGgiOiAiQ0hBTkdFTE9HLm1kIiwKICAgICAgImluaXRpYWwtdmVyc2lvbiI6ICIwLjEuMCIKICAgIH0KICB9Cn0K" + }, + "repos/f0rr0/oliphaunt/contents/.release-please-manifest.json?ref=c51052fe8b8ffc7e992266c5ab3d7a63b47441e7": { + "type": "file", + "path": ".release-please-manifest.json", + "sha": "a06fb685e447398cc660d5eb12cfa190f1392f50", + "encoding": "base64", + "content": "ewogICJzcmMvbmF0aXZlL3J1bnRpbWUiOiAiMC4zLjAiLAogICJzcmMvbmF0aXZlL3Nka3MvcnVzdCI6ICIwLjMuMCIsCiAgInNyYy9uYXRpdmUvYnJva2VyIjogIjAuMy4wIiwKICAic3JjL25hdGl2ZS9ub2RlLWFkZG9uIjogIjAuMi4xIiwKICAic3JjL3dhc2l4L25vZGUtYWRkb24iOiAiMC4yLjAiLAogICJzcmMvbmF0aXZlL3Nka3Mvc3dpZnQiOiAiMC44LjAiLAogICJzcmMvbmF0aXZlL3Nka3Mva290bGluIjogIjAuMy4wIiwKICAic3JjL25hdGl2ZS9zZGtzL3JlYWN0LW5hdGl2ZSI6ICIwLjMuMCIsCiAgInNyYy9uYXRpdmUvc2Rrcy90cyI6ICIwLjMuMCIsCiAgInNyYy9leHRlbnNpb25zL2V4dGVybmFsL3BnX2hhc2hpZHMiOiAiMC4zLjAiLAogICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wZ19pdm0iOiAiMC4zLjAiLAogICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wZ190ZXh0c2VhcmNoIjogIjAuMy4wIiwKICAic3JjL2V4dGVuc2lvbnMvZXh0ZXJuYWwvcGdfdXVpZHY3IjogIjAuMy4wIiwKICAic3JjL2V4dGVuc2lvbnMvZXh0ZXJuYWwvcGd0YXAiOiAiMC4zLjAiLAogICJzcmMvZXh0ZW5zaW9ucy9leHRlcm5hbC9wb3N0Z2lzIjogIjAuMy4wIiwKICAic3JjL2V4dGVuc2lvbnMvZXh0ZXJuYWwvdmVjdG9yIjogIjAuMy4wIiwKICAic3JjL3dhc2l4L3J1bnRpbWUiOiAiMC4zLjAiLAogICJzcmMvd2FzaXgvcG9zdG1hc3RlciI6ICIwLjEuMSIsCiAgInNyYy93YXNpeC9zZGtzL3J1c3QiOiAiMC4zLjAiLAogICJzcmMvd2FzaXgvc2Rrcy90cyI6ICIwLjIuMCIsCiAgInNyYy9xdWVyeS9ydXN0IjogIjAuMS4xIiwKICAic3JjL3F1ZXJ5L3RzIjogIjAuMS4xIiwKICAic3JjL25hdGl2ZS9ydXN0LWJpbmRpbmdzIjogIjAuMi4wIiwKICAic3JjL25hdGl2ZS9wb3N0Z3Jlcy10b29scyI6ICIwLjIuMiIsCiAgInNyYy93YXNpeC9wb3N0Z3Jlcy10b29scyI6ICIwLjIuMiIsCiAgInNyYy9kYXRhYmFzZS1yZXNvdXJjZXMiOiAiMC4yLjIiLAogICJzcmMvd2FzaXgvcGd3aXJlLXNlcnZlciI6ICIwLjIuMCIKfQo=" + }, + "repos/f0rr0/oliphaunt/contents/src/query/rust/release.toml?ref=c51052fe8b8ffc7e992266c5ab3d7a63b47441e7": { + "type": "file", + "path": "src/query/rust/release.toml", + "sha": "5fb0c3f4004db101ea6083a3791195fd2f4132eb", + "encoding": "base64", + "content": "aWQgPSAib2xpcGhhdW50LXF1ZXJ5Igpvd25lciA9ICJAb2xpcGhhdW50L2NvcmUiCmtpbmQgPSAic2RrIgpwdWJsaXNoX3RhcmdldHMgPSBbImNyYXRlcy1pbyJdCnJlZ2lzdHJ5X3BhY2thZ2VzID0gWyJjcmF0ZXM6b2xpcGhhdW50LXF1ZXJ5Il0KcmVsZWFzZV9hcnRpZmFjdHMgPSBbImNhcmdvLWNyYXRlIl0K" + }, + "repos/f0rr0/oliphaunt/contents/src/query/rust/Cargo.toml?ref=c51052fe8b8ffc7e992266c5ab3d7a63b47441e7": { + "type": "file", + "path": "src/query/rust/Cargo.toml", + "sha": "a4528f6dcdd916c618e3939865ef72fcf7eebd55", + "encoding": "base64", + "content": "W3BhY2thZ2VdCm5hbWUgPSAib2xpcGhhdW50LXF1ZXJ5Igp2ZXJzaW9uID0gIjAuMS4xIgplZGl0aW9uLndvcmtzcGFjZSA9IHRydWUKcnVzdC12ZXJzaW9uLndvcmtzcGFjZSA9IHRydWUKcmVwb3NpdG9yeS53b3Jrc3BhY2UgPSB0cnVlCmhvbWVwYWdlLndvcmtzcGFjZSA9IHRydWUKbGljZW5zZS53b3Jrc3BhY2UgPSB0cnVlCmRlc2NyaXB0aW9uID0gIlBvc3RncmVTUUwgcXVlcnkgZW5jb2RpbmcsIHJlc3VsdCBkZWNvZGluZyBhbmQgc2hhcmVkIHR5cGVzIGZvciBPbGlwaGF1bnQgU0RLcy4iCnJlYWRtZSA9ICJSRUFETUUubWQiCmV4Y2x1ZGUgPSBbIm1vb24ueW1sIiwgInJlbGVhc2UudG9tbCJdCg==" + }, + "repos/f0rr0/oliphaunt/contents/src/query/ts/release.toml?ref=c51052fe8b8ffc7e992266c5ab3d7a63b47441e7": { + "type": "file", + "path": "src/query/ts/release.toml", + "sha": "1f8e6ca8bf84ef079554c360f937f9b61e9031d6", + "encoding": "base64", + "content": "aWQgPSAib2xpcGhhdW50LXF1ZXJ5LXRzIgpvd25lciA9ICJAb2xpcGhhdW50L3Nkay1qcyIKa2luZCA9ICJzZGsiCnB1Ymxpc2hfdGFyZ2V0cyA9IFsibnBtIl0KcmVnaXN0cnlfcGFja2FnZXMgPSBbIm5wbTpAb2xpcGhhdW50L3RzLXF1ZXJ5Il0KcmVsZWFzZV9hcnRpZmFjdHMgPSBbIm5wbS1wYWNrYWdlIl0K" + }, + "repos/f0rr0/oliphaunt/contents/src/query/ts/package.json?ref=c51052fe8b8ffc7e992266c5ab3d7a63b47441e7": { + "type": "file", + "path": "src/query/ts/package.json", + "sha": "50a865beedd87127dcd5e05489e7ab2e06d0cafa", + "encoding": "base64", + "content": "ewogICJuYW1lIjogIkBvbGlwaGF1bnQvdHMtcXVlcnkiLAogICJ2ZXJzaW9uIjogIjAuMS4xIiwKICAiZXhwb3J0cyI6IHsKICAgICIuL3Byb3RvY29sIjogewogICAgICAiaW1wb3J0IjogewogICAgICAgICJ0eXBlcyI6ICIuL2Rpc3QvbW9kdWxlL3Byb3RvY29sLmQudHMiLAogICAgICAgICJkZWZhdWx0IjogIi4vZGlzdC9tb2R1bGUvcHJvdG9jb2wuanMiCiAgICAgIH0sCiAgICAgICJyZXF1aXJlIjogewogICAgICAgICJ0eXBlcyI6ICIuL2Rpc3QvY29tbW9uanMvcHJvdG9jb2wuZC50cyIsCiAgICAgICAgImRlZmF1bHQiOiAiLi9kaXN0L2NvbW1vbmpzL3Byb3RvY29sLmpzIgogICAgICB9CiAgICB9LAogICAgIi4vcXVlcnkiOiB7CiAgICAgICJpbXBvcnQiOiB7CiAgICAgICAgInR5cGVzIjogIi4vZGlzdC9tb2R1bGUvcXVlcnkuZC50cyIsCiAgICAgICAgImRlZmF1bHQiOiAiLi9kaXN0L21vZHVsZS9xdWVyeS5qcyIKICAgICAgfSwKICAgICAgInJlcXVpcmUiOiB7CiAgICAgICAgInR5cGVzIjogIi4vZGlzdC9jb21tb25qcy9xdWVyeS5kLnRzIiwKICAgICAgICAiZGVmYXVsdCI6ICIuL2Rpc3QvY29tbW9uanMvcXVlcnkuanMiCiAgICAgIH0KICAgIH0KICB9LAogICJmaWxlcyI6IFsKICAgICJkaXN0L21vZHVsZSIsCiAgICAiZGlzdC9jb21tb25qcyIKICBdLAogICJzY3JpcHRzIjogewogICAgImJ1aWxkIjogInRzYyAtcCB0c2NvbmZpZy5idWlsZC5tb2R1bGUuanNvbiAmJiB0c2MgLXAgdHNjb25maWcuYnVpbGQuY29tbW9uanMuanNvbiAmJiBjcCBtb2R1bGUucGFja2FnZS5qc29uIGRpc3QvbW9kdWxlL3BhY2thZ2UuanNvbiIsCiAgICAidGVzdCI6ICJiYXNoIC4uLy4uLy4uL3Rvb2xzL2Rldi9idW4uc2ggdGVzdCAtLWN3ZCBzcmMvcXVlcnkvdHMgLi90ZXN0IiwKICAgICJ0eXBlY2hlY2siOiAidHNjIC0tbm9FbWl0IiwKICAgICJmb3JtYXQiOiAiYnVuIHggLS1uby1pbnN0YWxsIGJpb21lIGZvcm1hdCAtLXdyaXRlIC0tbm8tZXJyb3JzLW9uLXVubWF0Y2hlZCAuIiwKICAgICJmb3JtYXQtY2hlY2siOiAiYnVuIHggLS1uby1pbnN0YWxsIGJpb21lIGZvcm1hdCAtLW5vLWVycm9ycy1vbi11bm1hdGNoZWQgLiIsCiAgICAibGludCI6ICJidW4geCAtLW5vLWluc3RhbGwgYmlvbWUgbGludCAtLWRpYWdub3N0aWMtbGV2ZWw9ZXJyb3IgLS1uby1lcnJvcnMtb24tdW5tYXRjaGVkIC4iLAogICAgInBhY2thZ2UiOiAiYmFzaCB0b29scy9wYWNrYWdlLnNoIgogIH0sCiAgImRldkRlcGVuZGVuY2llcyI6IHsKICAgICJAdHlwZXMvbm9kZSI6ICJeMjQuMTAuMSIsCiAgICAidHlwZXNjcmlwdCI6ICJjYXRhbG9nOiIKICB9LAogICJsaWNlbnNlIjogIk1JVCIsCiAgImRlc2NyaXB0aW9uIjogIlBvc3RncmVTUUwgcXVlcnkgZW5jb2RpbmcsIGRlY29kaW5nIGFuZCByZXN1bHQgdHlwZXMgZm9yIE9saXBoYXVudCBUeXBlU2NyaXB0IFNES3MuIiwKICAicmVwb3NpdG9yeSI6IHsKICAgICJ0eXBlIjogImdpdCIsCiAgICAidXJsIjogImdpdCtodHRwczovL2dpdGh1Yi5jb20vZjBycjAvb2xpcGhhdW50LmdpdCIsCiAgICAiZGlyZWN0b3J5IjogInNyYy9xdWVyeS90cyIKICB9LAogICJob21lcGFnZSI6ICJodHRwczovL29saXBoYXVudC5kZXYiLAogICJwdWJsaXNoQ29uZmlnIjogewogICAgImFjY2VzcyI6ICJwdWJsaWMiLAogICAgInByb3ZlbmFuY2UiOiB0cnVlCiAgfQp9Cg==" + }, + "repos/f0rr0/oliphaunt/compare/7b192697ff522f71f9c694593d352aa30469cea1...c51052fe8b8ffc7e992266c5ab3d7a63b47441e7?per_page=100": { + "status": "ahead", + "behind_by": 0, + "base_commit": { + "sha": "7b192697ff522f71f9c694593d352aa30469cea1" + }, + "merge_base_commit": { + "sha": "7b192697ff522f71f9c694593d352aa30469cea1" + }, + "commits": [ + { + "sha": "34e4931880fbfb80bae3139042eb37e7116228d0" + }, + { + "sha": "32ce7b29510b74333e799601b69a71fd28122e80" + }, + { + "sha": "d2541fff3d92743e2db5d42b092577238009eb3a" + }, + { + "sha": "a702d56cdfdf8a5f7e09b618cc94705fb9c8e889" + }, + { + "sha": "ba9276381d538009395edd924f998363a53a0a8b" + }, + { + "sha": "0a8ed6672940ac5c6e45186a7275eac1b09ce66f" + }, + { + "sha": "79c340949f4121e962741b75d80e686b5ba023c2" + }, + { + "sha": "c51052fe8b8ffc7e992266c5ab3d7a63b47441e7" + } + ], + "total_commits": 8 + }, + "repos/f0rr0/oliphaunt/releases/tags/oliphaunt-query-v0.1.1": { + "tag_name": "oliphaunt-query-v0.1.1", + "draft": false, + "prerelease": false, + "target_commitish": "c51052fe8b8ffc7e992266c5ab3d7a63b47441e7" + }, + "repos/f0rr0/oliphaunt/releases/tags/oliphaunt-query-ts-v0.1.1": { + "tag_name": "oliphaunt-query-ts-v0.1.1", + "draft": false, + "prerelease": false, + "target_commitish": "c51052fe8b8ffc7e992266c5ab3d7a63b47441e7" + } + }, + "registryMetadata": { + "cargo": { + "version": { + "id": 3388553, + "crate": "oliphaunt-query", + "num": "0.1.1", + "dl_path": "/api/v1/crates/oliphaunt-query/0.1.1/download", + "readme_path": "/api/v1/crates/oliphaunt-query/0.1.1/readme", + "updated_at": "2026-10-03T01:03:22.249836Z", + "created_at": "2026-10-03T01:03:22.249836Z", + "downloads": 67, + "features": {}, + "yanked": false, + "yank_message": null, + "lib_links": null, + "license": "MIT", + "links": { + "dependencies": "/api/v1/crates/oliphaunt-query/0.1.1/dependencies", + "version_downloads": "/api/v1/crates/oliphaunt-query/0.1.1/downloads", + "authors": "/api/v1/crates/oliphaunt-query/0.1.1/authors" + }, + "crate_size": 26284, + "published_by": { + "id": 358558, + "login": "f0rr0", + "name": "Sid Jain", + "avatar": "https://avatars.githubusercontent.com/u/8574219?v=4", + "url": "https://github.com/f0rr0", + "github_username_matches": true, + "created_at": "2014-08-28T00:24:28Z" + }, + "audit_actions": [ + { + "action": "publish", + "user": { + "id": 358558, + "login": "f0rr0", + "name": "Sid Jain", + "avatar": "https://avatars.githubusercontent.com/u/8574219?v=4", + "url": "https://github.com/f0rr0", + "github_username_matches": true, + "created_at": "2014-08-28T00:24:28Z" + }, + "time": "2026-10-03T01:03:22.249836Z" + } + ], + "checksum": "523a7416f6a830ef02928994a2a89e9fd9d01e4fe67b22f0480d377d5f9b235c", + "rust_version": "1.93", + "has_lib": true, + "bin_names": [], + "edition": "2024", + "description": "PostgreSQL query encoding, result decoding and shared types for Oliphaunt SDKs.", + "homepage": "https://oliphaunt.dev", + "documentation": null, + "repository": "https://github.com/f0rr0/oliphaunt", + "trustpub_data": null, + "linecounts": { + "languages": { + "Rust": { + "code_lines": 3431, + "comment_lines": 6, + "files": 2 + } + }, + "total_code_lines": 3431, + "total_comment_lines": 6 + } + } + }, + "npm": { + "name": "@oliphaunt/ts-query", + "version": "0.1.1", + "dist": { + "shasum": "1548eae0ebc1d8b2c79199599b0b6a34da815169", + "tarball": "https://registry.npmjs.org/@oliphaunt/ts-query/-/ts-query-0.1.1.tgz", + "fileCount": 12, + "integrity": "sha512-QV9Sv0S80qyCfJpgtGd6167nA3rvNdJ1gyFYb+ro11jZlElRALVwMntSdBeiggHK12BXg6BvPuIVora0OC62QQ==", + "signatures": [ + { + "sig": "MEYCIQDU7d+VQPzqf/z0bCaG0D3c9sSX47jEkFh3RL+fG0QWpAIhAP/DCAKRWeYJGRoHc40ccmVlf+s4LoWGYTfeSQ9CpIIV", + "keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U" + } + ], + "attestations": { + "url": "https://registry.npmjs.org/-/npm/v1/attestations/@oliphaunt%2fts-query@0.1.1", + "provenance": { + "predicateType": "https://slsa.dev/provenance/v1" + } + }, + "unpackedSize": 179361 + } + } + }, + "provenanceOnlyExample": { + "commits": [ + "79c340949f4121e962741b75d80e686b5ba023c2", + "c51052fe8b8ffc7e992266c5ab3d7a63b47441e7" + ], + "sourcePath": "src/query/rust", + "sourceTree": "fd38123c6fec6ebae5456f26c94dfc76667f404b", + "scope": "Git source subtree equality only; not configured producer/toolchain equivalence" + } +} diff --git a/tools/release/testdata/native-source-carriers/oliphaunt-query-0.1.1.crate b/tools/release/testdata/native-source-carriers/oliphaunt-query-0.1.1.crate new file mode 100644 index 000000000..dfbde7853 Binary files /dev/null and b/tools/release/testdata/native-source-carriers/oliphaunt-query-0.1.1.crate differ diff --git a/tools/release/testdata/native-source-carriers/oliphaunt-ts-query-0.1.1.tgz b/tools/release/testdata/native-source-carriers/oliphaunt-ts-query-0.1.1.tgz new file mode 100644 index 000000000..f1521746f Binary files /dev/null and b/tools/release/testdata/native-source-carriers/oliphaunt-ts-query-0.1.1.tgz differ diff --git a/tools/release/testdata/prepare-release-candidate-fixtures.mts b/tools/release/testdata/prepare-release-candidate-fixtures.mts new file mode 100644 index 000000000..753658e71 --- /dev/null +++ b/tools/release/testdata/prepare-release-candidate-fixtures.mts @@ -0,0 +1,411 @@ +/** Shared fixtures invoke the pinned RP strategies; synthetic records grant no release authority. */ +import { expect } from 'bun:test'; +import { existsSync, readFileSync } from 'node:fs'; +import path from 'node:path'; +import { Manifest } from 'release-please'; +import { ManifestPlugin } from 'release-please/build/src/plugin.js'; +import { PullRequestBody } from 'release-please/build/src/util/pull-request-body.js'; +import { Version } from 'release-please/build/src/version.js'; +import { createCompletedPublicationChecker } from '../completed-release-publication.mts'; +import { + bindReleaseSourceHistory, + includeOwnedSourceCommits, + useSourceDate, +} from '../prepare-release-candidate.mts'; +import { loadPublicationCatalog } from '../publication-catalog.mts'; +import { expectedProductArtifactRows } from '../publication-lock.mts'; +import { contribCarrierDescriptor } from '../release-artifact-targets.mts'; +import { loadProducts, productCompatibilityVersion, ROOT } from '../release-graph.mts'; + +/** Controlled historical transport for caller tests; the real reader has separate + * tag/blob/attestation tests. This fixture grants no completed origin authority. */ +export async function fixtureCompletedNativeInventory(publication) { + const catalog = loadPublicationCatalog('completed native caller fixture'); + const descriptor = { ...loadProducts()[publication.product], version: publication.version }; + return { + publication, + descriptor, + catalog, + carriers: catalog.carriers.filter((row) => row.product === publication.product), + publicRows: expectedProductArtifactRows([{ id: publication.product, ...descriptor }]), + inputContext: { + products: loadProducts(), + contrib: contribCarrierDescriptor(), + readText: (file) => readFileSync(path.join(ROOT, file), 'utf8'), + }, + } as any; +} + +const first = 'a'.repeat(40); +const head = 'c'.repeat(40); +export function fixtureCompletionChecker( + config, + versions, + baselines = {}, + { + pending = [], + missingLabels = [], + releaseMergeShas = {}, + comparisons = {}, + extraPullRequests = [], + sourceVersions = {}, + pagedComparisons = {}, + omitCompletions = [], + unchangedAtMerge = [], + releaseTargets = {}, + sourceCommits = {}, + calls = {}, + } = {}, +) { + const repository = 'f0rr0/oliphaunt'; + const after = Object.fromEntries( + Object.entries(versions).map(([owner, version]) => [owner, version.toString()]), + ); + const groups = new Map(); + for (const [owner, entry] of Object.entries(config)) { + if (after[owner] === '0.0.0') continue; + const publicationSha = baselines[owner] ?? first; + const releaseSha = releaseMergeShas[entry.component] ?? publicationSha; + if (!groups.has(releaseSha)) groups.set(releaseSha, []); + groups.get(releaseSha).push({ owner, product: entry.component, publicationSha }); + } + const states = new Map(); + const commits = new Map(); + const pullRequests = [...groups].map(([sha, products], index) => { + const parent = (2_000_000 + index).toString(16).padStart(40, '0'); + states.set(sha, after); + states.set(parent, { + ...after, + ...Object.fromEntries( + products.map(({ owner, product }) => [ + owner, + unchangedAtMerge.includes(product) ? after[owner] : '0.0.0', + ]), + ), + }); + for (const { publicationSha } of products) { + states.set(publicationSha, after); + commits.set(publicationSha, { sha: publicationSha, tree: { sha: 'd'.repeat(40) } }); + } + commits.set(sha, { sha, parents: [{ sha: parent }], tree: { sha: 'd'.repeat(40) } }); + return { + number: 500 + index, + title: 'chore(release): prepare main releases', + state: 'closed', + merged_at: '2026-09-11T00:00:00Z', + merge_commit_sha: sha, + base: { ref: 'main', repo: { full_name: repository } }, + head: { ref: 'release-please--branches--main', repo: { full_name: repository } }, + labels: products.some(({ product }) => missingLabels.includes(product)) + ? [] + : [ + { + name: products.some(({ product }) => pending.includes(product)) + ? 'autorelease: pending' + : 'autorelease: tagged', + }, + ], + body: new PullRequestBody( + products.map(({ product, owner }) => ({ + component: product, + version: Version.parse(after[owner]), + notes: 'Fixture release', + })), + { useComponents: true }, + ).toString(), + }; + }); + for (const [sha, versions] of Object.entries(sourceVersions)) states.set(sha, versions); + for (const [sha, commit] of Object.entries(sourceCommits)) commits.set(sha, commit); + return createCompletedPublicationChecker({ + repository, + listPullRequests: async () => [ + ...pullRequests.filter( + (pullRequest) => + !groups + .get(pullRequest.merge_commit_sha) + .some(({ product }) => omitCompletions.includes(product)), + ), + ...extraPullRequests, + ], + readJson: async (endpoint) => { + const relative = endpoint.slice(`repos/${repository}/`.length); + if (relative.startsWith('releases/tags/')) { + const tag = decodeURIComponent(relative.slice('releases/tags/'.length)); + const [owner] = Object.entries(config).find( + ([owner, entry]) => `${entry.component}-v${after[owner]}` === tag, + ); + return { + tag_name: tag, + draft: false, + prerelease: false, + target_commitish: releaseTargets[tag] ?? baselines[owner] ?? first, + }; + } + if (relative.startsWith('git/commits/')) return commits.get(relative.slice(12)); + if (relative.startsWith('compare/')) { + const [base, publication] = relative.slice(8).split('?')[0].split('...'); + return ( + comparisons[`${base}...${publication}`] ?? { + status: 'ahead', + behind_by: 0, + base_commit: { sha: base }, + merge_base_commit: { sha: base }, + total_commits: 1, + commits: [{ sha: publication }], + } + ); + } + const [file, sha] = relative.slice('contents/'.length).split('?ref='); + if (!states.has(sha)) throw new Error(`fixture has no version state at ${sha}`); + const content = + file === 'release-please-config.json' ? { packages: config } : states.get(sha); + return { + encoding: 'base64', + content: Buffer.from(JSON.stringify(content)).toString('base64'), + }; + }, + readPages: async (endpoint) => { + calls.pages = (calls.pages ?? 0) + 1; + return pagedComparisons[endpoint.slice(`repos/${repository}/compare/`.length)]; + }, + }); +} + +export const historyProducts = ['alpha', 'beta', 'gamma']; +export const historyShared = 'shared/shipped.c'; + +export async function generateHistoryCandidate( + commits, + { + baselines = Object.fromEntries(historyProducts.map((product) => [product, first])), + unreleased = [], + drafts = [], + tagOnly = [], + missing = [], + unrelatedReleaseCount = 0, + bootstrapSha = undefined, + lastReleaseSha = undefined, + completion = {}, + readCommitFiles, + commitHistory, + sourceSha, + readSource, + inspect = () => {}, + controllerOptions = {}, + nodeWorkspace = false, + } = {}, +) { + const products = Object.fromEntries( + historyProducts.map((product) => [ + product, + { + path: `products/${product}`, + kind: 'source-package', + tag_prefix: `${product}-v`, + version: unreleased.includes(product) ? '0.0.0' : '0.2.0', + }, + ]), + ); + const fixtureGraph = { + products, + moon_projects: Object.fromEntries( + historyProducts.map((id) => [id, { id, source: products[id].path, dependencies: [] }]), + ), + shared_release_sources: [{ files: [historyShared], products: historyProducts }], + }; + const config = Object.fromEntries( + historyProducts.map((product) => [ + products[product].path, + { + releaseType: nodeWorkspace ? 'node' : 'simple', + component: product, + packageName: product, + versionFile: 'VERSION', + changelogPath: 'CHANGELOG.md', + includeVInTag: true, + tagSeparator: '-', + initialVersion: '0.1.0', + bumpMinorPreMajor: true, + bumpPatchForMinorPreMajor: true, + }, + ]), + ); + const versions = Object.fromEntries( + Object.values(products).map((product) => [product.path, Version.parse(product.version)]), + ); + const calls = {}; + const releaseRecords = historyProducts + .filter((product) => !unreleased.includes(product) && !missing.includes(product)) + .map((product) => ({ + tagName: `${product}-v0.2.0`, + sha: baselines[product], + draft: drafts.includes(product), + notes: 'Completed release', + })); + const github = { + repository: { owner: 'f0rr0', repo: 'oliphaunt', defaultBranch: 'main' }, + async *releaseIterator(options = {}) { + calls.releases = options; + const records = [ + ...Array.from({ length: unrelatedReleaseCount }, (_, index) => ({ + tagName: `unrelated-v1.0.${index}`, + sha: head, + draft: false, + })), + ...releaseRecords, + ]; + for (const release of records.slice(0, options.maxResults)) { + if (!tagOnly.includes(release.tagName.split('-v')[0])) yield release; + } + }, + async *tagIterator() { + for (const release of releaseRecords) yield { name: release.tagName, sha: release.sha }; + }, + async *mergeCommitIterator(_branch, options = {}) { + calls.commits = options; + yield* commits.slice(0, options.maxResults); + }, + async getFileContentsOnBranch(file) { + const owner = Object.values(products).find((product) => file.startsWith(`${product.path}/`)); + const parsedContent = file.endsWith('/VERSION') + ? `${owner.version}\n` + : file.endsWith('/package.json') + ? JSON.stringify({ + name: historyProducts.find((id) => products[id] === owner), + version: owner.version, + ...(owner === products.alpha ? { dependencies: { beta: '0.2.0' } } : {}), + }) + : '# Changelog\n'; + return { parsedContent, content: Buffer.from(parsedContent).toString('base64') }; + }, + async getFileContents(file) { + return this.getFileContentsOnBranch(file); + }, + }; + const logger = { info() {}, debug() {}, warn() {}, error() {} }; + const manifest = new Manifest(github, 'main', config, versions, { + separatePullRequests: false, + bootstrapSha, + lastReleaseSha, + logger, + plugins: nodeWorkspace ? [{ type: 'node-workspace', merge: false }] : [], + }); + if (sourceSha) bindReleaseSourceHistory(github, commitHistory, sourceSha, readSource); + includeOwnedSourceCommits(manifest, github, fixtureGraph, undefined, { + readCommitFiles, + commitHistory, + assertCompletedPublication: fixtureCompletionChecker( + config, + versions, + Object.fromEntries( + historyProducts.map((product) => [products[product].path, baselines[product]]), + ), + completion, + ), + ...controllerOptions, + }); + manifest.plugins.push( + new (class extends ManifestPlugin { + async preconfigure(strategies, selected) { + // This supported hook runs before Release Please's individual candidate strategies. + inspect(selected, calls); + return strategies; + } + })(github, 'main', config), + ); + return manifest.buildPullRequests(); +} + +export function historyVersionUpdates(candidates) { + return candidates.flatMap((candidate) => + candidate.updates + .filter((update) => update.path.endsWith('/VERSION')) + .map((update) => [update.path, update.updater.updateContent('0.2.0\n').trim()]), + ); +} + +export function nativeHistoryOptions( + necessary, + { current = false, observeNativePlan = async () => {} } = {}, +) { + // Controlled invocation of the actual pinned strategy/plugin API; these + // fixture records do not claim authenticated workflow/product qualification. + const buildBound = new Map(historyProducts.map((id) => [id, new Set()])); + if (current) buildBound.get('alpha')!.add('beta'); + return { + nativeNecessaryProducts: necessary, + buildBound, + observeNativePlan, + nativeObservation: { + coverage: { completeProductInventory: true }, + products: historyProducts.map((id) => ({ + product: { id }, + construction: [{ leafInputPaths: [`actual/shipping/${id}.c`], analysisInputPaths: [] }], + })), + }, + }; +} + +export async function generateProductCandidateForGraph( + graph, + commits, + readCompatibility = (product, source) => productCompatibilityVersion(product, source), + configure = () => {}, + { root = ROOT, baseline = first, ...dependencyOptions } = {}, +) { + const config = JSON.parse(readFileSync(path.join(root, 'release-please-config.json'), 'utf8')); + const versions = JSON.parse( + readFileSync(path.join(root, '.release-please-manifest.json'), 'utf8'), + ); + const github = { + repository: { owner: 'f0rr0', repo: 'oliphaunt', defaultBranch: 'main' }, + async *releaseIterator() { + for (const owner of Object.keys(config.packages)) + yield { + tagName: `${config.packages[owner].component}-v${versions[owner]}`, + sha: baseline, + notes: 'Existing release', + }; + }, + async *mergeCommitIterator() { + yield* commits; + yield { sha: baseline, message: 'chore(release): previous versions', files: [] }; + }, + async getFileContentsOnBranch(file) { + const local = path.join(root, file); + const parsedContent = + file === 'release-please-config.json' + ? JSON.stringify(config) + : file === '.release-please-manifest.json' + ? JSON.stringify(versions) + : existsSync(local) + ? readFileSync(local, 'utf8') + : undefined; + if (parsedContent === undefined) + throw Object.assign(new Error(`missing ${file}`), { status: 404 }); + return { parsedContent, content: Buffer.from(parsedContent).toString('base64') }; + }, + async getFileContents(file) { + return this.getFileContentsOnBranch(file); + }, + async getFileJson(file) { + return JSON.parse((await this.getFileContentsOnBranch(file)).parsedContent); + }, + }; + const manifest = await Manifest.fromManifest(github, 'main'); + useSourceDate('2026-09-11'); + includeOwnedSourceCommits(manifest, github, graph, readCompatibility, { + ...dependencyOptions, + assertCompletedPublication: fixtureCompletionChecker( + manifest.repositoryConfig, + manifest.releasedVersions, + Object.fromEntries(Object.keys(manifest.repositoryConfig).map((owner) => [owner, baseline])), + ), + }); + configure(manifest, github); + const candidates = await manifest.buildPullRequests(); + expect(candidates.length).toBeLessThanOrEqual(1); + const [candidate] = candidates; + return { candidate, versions }; +} diff --git a/tools/release/testdata/publication-artifact-fixtures.mts b/tools/release/testdata/publication-artifact-fixtures.mts new file mode 100644 index 000000000..26f33ef83 --- /dev/null +++ b/tools/release/testdata/publication-artifact-fixtures.mts @@ -0,0 +1,475 @@ +/** Canonical public layouts and real checksums; synthetic payloads grant no release authority. */ +import { createHash } from 'node:crypto'; +import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { + extensionCarrierLegalContract, + stageExtensionUpstreamLicenses, +} from '../../../src/extensions/tools/extension-upstream-licenses.mts'; +import { + buildSwiftExtensionCarrierManifest, + swiftExtensionCarrierAssetName, +} from '../../../src/native/sdks/swift/tools/ios-carrier-manifest.mts'; +import { createDeterministicTar } from '../../packaging/cargo-source-package.mts'; +import { canonicalGzipSync } from '../../packaging/portable-archive.mts'; +import { stageReleaseNotices } from '../../packaging/release-notices.mts'; +import { + allArtifactTargets, + extensionArtifactProductRoot, + extensionArtifactTargets, + extensionMetadata, + extensionSourceIdentity, + extensionSqlNames, +} from '../release-artifact-targets.mts'; +import { ROOT } from '../release-graph.mts'; + +function sortJsonValue(value) { + if (Array.isArray(value)) return value.map(sortJsonValue); + if (value !== null && typeof value === 'object') { + return Object.fromEntries( + Object.keys(value) + .sort() + .map((key) => [key, sortJsonValue(value[key])]), + ); + } + return value; +} + +function canonicalJson(value) { + return `${JSON.stringify(sortJsonValue(value), null, 2)}\n`; +} + +function wasixInstall(sqlName, dependencies, createsExtension) { + return { + schema: 'oliphaunt-wasix-extension-install-v1', + name: sqlName, + nativeModule: null, + nativeModules: [], + coreExportsRequired: [], + dependencies, + loadOrder: [], + lifecycle: { + createExtension: createsExtension, + createSchema: 'pg_catalog', + loadSql: [], + postCreateSql: [], + startupConfig: [], + preloadRequired: false, + restartRequired: false, + sharedMemoryRequired: false, + }, + installedFiles: [`share/postgresql/extension/${sqlName}.control`], + unresolvedImports: [], + }; +} + +export function sha256File(file) { + return createHash('sha256').update(readFileSync(file)).digest('hex'); +} + +export function githubReleaseFixture(root, product) { + const directory = path.join(root, product.id, 'release-assets'); + mkdirSync(directory, { recursive: true }); + const rows = allArtifactTargets( + { + product: product.id, + surface: 'github-release', + }, + 'publication-lock.test', + ).map((target) => ({ + target, + name: target.asset.replaceAll('{version}', product.version), + })); + const checksum = rows.find((row) => row.target.kind === 'checksums'); + for (const row of rows.filter((item) => item !== checksum)) { + writeFileSync(path.join(directory, row.name), `fixture:${row.name}\n`); + } + const checksumLines = rows + .filter((item) => item !== checksum) + .map((row) => `${sha256File(path.join(directory, row.name))} ./${row.name}\n`) + .sort(); + writeFileSync(path.join(directory, checksum.name), checksumLines.join('')); + return { checksum, directory, rows }; +} + +export function extensionGithubReleaseFixture( + root, + product, + { + artifactProduct = product.id, + family = null, + mutateBundleArchive = undefined, + mutateBundleStage = undefined, + bundleFixedFileMode = 0o644, + } = {}, +) { + const productRoot = extensionArtifactProductRoot( + artifactProduct, + family ?? 'native', + path.join(root, 'target', 'extension-artifacts'), + 'publication-lock.test', + ); + const directory = path.join(productRoot, 'release-assets'); + rmSync(productRoot, { recursive: true, force: true }); + mkdirSync(directory, { recursive: true }); + const sqlNames = extensionSqlNames(artifactProduct, 'publication-lock.test'); + const bundled = sqlNames.length > 1; + const releaseMetadata = extensionMetadata(artifactProduct, 'publication-lock.test'); + const ownership = + artifactProduct === product.id + ? {} + : { releaseProduct: product.id, family: family ?? 'combined' }; + const compatibility = releaseMetadata.compatibility; + const generated = JSON.parse( + readFileSync(path.join(ROOT, 'src/extensions/generated/sdk/extensions.json'), 'utf8'), + ); + const staticLines = readFileSync( + path.join(ROOT, 'src/extensions/generated/mobile/static-extensions.tsv'), + 'utf8', + ) + .split(/\r?\n/u) + .filter((line) => line.length > 0 && !line.startsWith('#')); + const staticHeader = staticLines[0].split('\t'); + const staticRows = staticLines + .slice(1) + .map((line) => + Object.fromEntries( + staticHeader.map((column, index) => [column, line.split('\t')[index] ?? '']), + ), + ); + const assets = []; + const extensions = []; + for (const sqlName of sqlNames) { + const extension = generated.extensions.find((row) => row['sql-name'] === sqlName); + const nativeModuleStem = extension['native-module-stem']; + const staticRow = staticRows.find((row) => row['sql-name'] === sqlName); + const iosNativeDependencies = + nativeModuleStem === null + ? [] + : (staticRow?.['ios-static-dependencies'] ?? '').split(',').filter(Boolean).sort(); + const memberAssets = []; + for (const target of extensionArtifactTargets( + { product: artifactProduct }, + 'publication-lock.test', + ).filter((row) => row.sqlName === sqlName && (family === null || row.family === family))) { + const roles = + target.family === 'wasix' + ? ['wasix-runtime'] + : target.target === 'ios-xcframework' + ? [ + 'runtime', + ...(nativeModuleStem === null + ? [] + : [ + 'ios-xcframework', + ...iosNativeDependencies.map( + (dependency) => `ios-dependency-xcframework:${dependency}`, + ), + ]), + ] + : ['runtime']; + for (const role of roles) { + const [kind, dependencyIdentity] = role.split(':'); + const identity = + kind === 'ios-xcframework' + ? nativeModuleStem + : kind === 'ios-dependency-xcframework' + ? dependencyIdentity + : null; + const prefix = `${artifactProduct}-${product.version}`; + const name = + target.family === 'wasix' + ? `${prefix}-wasix-portable.tar.zst` + : kind === 'ios-xcframework' + ? `${prefix}-native-ios-xcframework.zip` + : kind === 'ios-dependency-xcframework' + ? `${prefix}-native-ios-dependency-${identity}-xcframework.zip` + : target.target === 'ios-xcframework' + ? `${prefix}-native-ios-runtime.tar.gz` + : `${prefix}-native-${target.target}-runtime.tar.gz`; + const file = path.join( + bundled ? path.join(productRoot, 'member-assets', sqlName) : directory, + name, + ); + mkdirSync(path.dirname(file), { recursive: true }); + writeFileSync(file, `fixture:${name}\n`); + const asset = { + name, + family: target.family, + target: target.target, + kind, + identity, + path: file, + sha256: sha256File(file), + bytes: readFileSync(file).length, + }; + assets.push(asset); + memberAssets.push(asset); + } + } + const dependencies = [...extension['selected-extension-dependencies']].sort(); + const createsExtension = extension['creates-extension'] !== false; + const stagesIos = memberAssets.some((asset) => asset.target === 'ios-xcframework'); + extensions.push({ + sqlName, + createsExtension, + dependencies, + dataFiles: [...extension['runtime-share-data-files']].sort(), + extensionSqlFileNames: [...extension['extension-sql-file-names']].sort(), + extensionSqlFilePrefixes: [...extension['extension-sql-file-prefixes']].sort(), + nativeModuleStem, + iosNativeDependencies: stagesIos ? iosNativeDependencies : [], + iosRegistration: + nativeModuleStem === null || !stagesIos + ? null + : { + schema: 'oliphaunt-ios-extension-registration-v1', + sqlName, + nativeModuleStem, + magicSymbol: `oliphaunt_static_${nativeModuleStem.replaceAll(/[^A-Za-z0-9_]/gu, '_')}_Pg_magic_func`, + initSymbol: null, + symbols: [], + }, + wasixInstall: memberAssets.some((asset) => asset.family === 'wasix') + ? wasixInstall(sqlName, dependencies, createsExtension) + : null, + sharedPreloadLibraries: [...extension['shared-preload-libraries']].sort(), + assets: memberAssets, + }); + } + const carrierAssets = []; + if (bundled) { + const groups = new Map(); + for (const extension of extensions) { + for (const asset of extension.assets) { + const key = `${asset.family}\0${asset.target}`; + const group = groups.get(key) ?? { family: asset.family, target: asset.target, rows: [] }; + group.rows.push({ sqlName: extension.sqlName, asset }); + groups.set(key, group); + } + } + for (const group of [...groups.values()].sort((left, right) => + `${left.family}\0${left.target}`.localeCompare(`${right.family}\0${right.target}`), + )) { + const archiveRoot = `${artifactProduct}-${product.version}-${group.family}-${group.target}-bundle`; + const stage = path.join(productRoot, 'bundle-stage', archiveRoot); + rmSync(stage, { recursive: true, force: true }); + mkdirSync(stage, { recursive: true }); + const manifestMembers = []; + for (const { sqlName, asset } of group.rows.sort((left, right) => + `${left.sqlName}\0${left.asset.kind}\0${left.asset.identity ?? ''}`.localeCompare( + `${right.sqlName}\0${right.asset.kind}\0${right.asset.identity ?? ''}`, + ), + )) { + const memberPath = `extensions/${sqlName}/${asset.name}`; + const destination = path.join(stage, ...memberPath.split('/')); + mkdirSync(path.dirname(destination), { recursive: true }); + writeFileSync(destination, readFileSync(asset.path)); + asset.carrierAsset = `${archiveRoot}.tar.gz`; + asset.carrierRoot = archiveRoot; + asset.memberPath = memberPath; + manifestMembers.push({ + sqlName, + kind: asset.kind, + identity: asset.identity, + path: memberPath, + sha256: asset.sha256, + bytes: asset.bytes, + }); + } + const memberNames = [...new Set(manifestMembers.map(({ sqlName }) => sqlName))].sort(); + const legal = extensionCarrierLegalContract(artifactProduct, memberNames, { + family: group.family, + target: group.target, + }); + for (const sqlName of memberNames) stageExtensionUpstreamLicenses(sqlName, stage); + const bundleManifest = path.join(stage, 'bundle-manifest.json'); + writeFileSync( + bundleManifest, + canonicalJson({ + schema: 'oliphaunt-extension-bundle-v1', + product: artifactProduct, + version: product.version, + compatibility, + family: group.family, + target: group.target, + licenseProfile: legal.profile, + licenseFiles: legal.licenseFiles, + members: manifestMembers, + }), + ); + stageReleaseNotices(stage, { profile: legal.profile }); + mutateBundleStage?.({ + archiveRoot, + bundleManifest, + family: group.family, + legal, + stage, + target: group.target, + }); + const output = path.join(directory, `${archiveRoot}.tar.gz`); + const tarOptions = { + includeDirectories: false, + fail(message) { + throw new Error(`publication lock fixture: ${message}`); + }, + }; + if (bundleFixedFileMode !== null) tarOptions.fixedFileMode = bundleFixedFileMode; + writeFileSync( + output, + canonicalGzipSync(createDeterministicTar(stage, archiveRoot, tarOptions)), + ); + mutateBundleArchive?.({ + archiveRoot, + family: group.family, + output, + target: group.target, + }); + carrierAssets.push({ + name: path.basename(output), + path: output, + sha256: sha256File(output), + bytes: readFileSync(output).length, + family: group.family, + target: group.target, + kind: 'extension-bundle', + memberCount: sqlNames.length, + }); + } + } + const extensionManifestPath = path.join(productRoot, 'extension-artifacts.json'); + const extensionManifest = bundled + ? { + schema: 'oliphaunt-extension-ci-artifacts-v2', + product: artifactProduct, + ...ownership, + version: product.version, + compatibility, + extensions, + carrierAssets, + } + : { + schema: 'oliphaunt-extension-ci-artifacts-v1', + product: artifactProduct, + ...ownership, + version: product.version, + compatibility, + ...extensions[0], + }; + writeFileSync(extensionManifestPath, `${JSON.stringify(extensionManifest, null, 2)}\n`); + const manifestName = `${artifactProduct}-${product.version}-manifest.json`; + const propertiesName = `${artifactProduct}-${product.version}-manifest.properties`; + const swiftCarrierName = swiftExtensionCarrierAssetName(artifactProduct, product.version); + const checksumName = `${artifactProduct}-${product.version}-release-assets.sha256`; + const directAssets = bundled ? carrierAssets : assets; + writeFileSync( + path.join(directory, manifestName), + `${JSON.stringify( + { + schema: bundled + ? 'oliphaunt-extension-release-manifest-v2' + : 'oliphaunt-extension-release-manifest-v1', + product: artifactProduct, + ...ownership, + version: product.version, + extensionClass: releaseMetadata.class, + versioning: releaseMetadata.versioning, + sourceIdentity: extensionSourceIdentity(artifactProduct, 'publication-lock.test'), + compatibility, + ...(bundled + ? { + extensions: extensions.map((row) => ({ + ...row, + assets: row.assets.map( + ({ + name, + family, + target, + kind, + identity, + sha256, + bytes, + carrierAsset, + carrierRoot, + memberPath, + }) => ({ + name, + family, + target, + kind, + identity, + sha256, + bytes, + carrierAsset, + carrierRoot, + memberPath, + }), + ), + })), + assets: carrierAssets.map( + ({ name, family, target, kind, sha256, bytes, memberCount }) => ({ + name, + family, + target, + kind, + sha256, + bytes, + memberCount, + }), + ), + } + : { + sqlName: extensions[0].sqlName, + createsExtension: extensions[0].createsExtension, + dependencies: extensions[0].dependencies, + dataFiles: extensions[0].dataFiles, + extensionSqlFileNames: extensions[0].extensionSqlFileNames, + extensionSqlFilePrefixes: extensions[0].extensionSqlFilePrefixes, + nativeModuleStem: extensions[0].nativeModuleStem, + iosNativeDependencies: extensions[0].iosNativeDependencies, + iosRegistration: extensions[0].iosRegistration, + wasixInstall: extensions[0].wasixInstall, + sharedPreloadLibraries: extensions[0].sharedPreloadLibraries, + assets: assets.map(({ name, family, target, kind, identity, sha256, bytes }) => ({ + name, + family, + target, + kind, + identity, + sha256, + bytes, + })), + }), + }, + null, + 2, + )}\n`, + ); + writeFileSync( + path.join(directory, propertiesName), + `schema=oliphaunt-extension-release-manifest-v${bundled ? '2' : '1'}\nproduct=${artifactProduct}\n${artifactProduct === product.id ? '' : `releaseProduct=${product.id}\ncarrierFamily=${family ?? 'combined'}\n`}version=${product.version}\n`, + ); + if (family !== 'wasix') + writeFileSync( + path.join(directory, swiftCarrierName), + `${JSON.stringify( + buildSwiftExtensionCarrierManifest({ + extensionManifest: extensionManifestPath, + verifyMembers: false, + }), + null, + 2, + )}\n`, + ); + const payloadNames = [ + ...directAssets.map((asset) => asset.name), + manifestName, + propertiesName, + ...(family === 'wasix' ? [] : [swiftCarrierName]), + ].sort(); + writeFileSync( + path.join(directory, checksumName), + payloadNames.map((name) => `${sha256File(path.join(directory, name))} ./${name}\n`).join(''), + ); + return { assets: directAssets, directory, manifestPath: extensionManifestPath, swiftCarrierName }; +} diff --git a/tools/release/testdata/require-workflow-success-github.mts b/tools/release/testdata/require-workflow-success-github.mts index 85327d11f..1361d6092 100644 --- a/tools/release/testdata/require-workflow-success-github.mts +++ b/tools/release/testdata/require-workflow-success-github.mts @@ -10,6 +10,70 @@ globalThis.fetch = async (input, options) => { throw new Error('unexpected GitHub request'); const endpoint = url.pathname.slice(1) + url.search; fs.appendFileSync(process.env.FAKE_LOG, JSON.stringify(endpoint) + '\n'); + if (process.env.FAKE_MODE.startsWith('native-')) { + const mode = process.env.FAKE_MODE; + const dispatched = fs.existsSync(process.env.FAKE_DISPATCH); + const record = (id) => ({ + id, + workflow_id: 9, + run_attempt: 1, + head_sha: mode === 'native-race' && id === 88 ? 'b'.repeat(40) : process.env.FAKE_NATIVE_SHA, + head_branch: mode === 'native-feature' && id === 77 ? 'feature' : 'main', + path: '.github/workflows/bazel.yml', + event: + id === 88 || ['native-feature', 'native-failed', 'native-dispatch-skipped'].includes(mode) + ? 'workflow_dispatch' + : 'push', + status: + (id === 88 && process.env.FAKE_NATIVE_COMPLETE !== 'true') || mode === 'native-active' + ? 'in_progress' + : 'completed', + conclusion: + (id === 88 && process.env.FAKE_NATIVE_COMPLETE !== 'true') || mode === 'native-active' + ? null + : mode === 'native-failed' + ? 'failure' + : 'success', + html_url: `https://github.com/f0rr0/oliphaunt/actions/runs/${id}`, + }); + if (/actions\/workflows[?]/.test(endpoint)) + return Response.json({ workflows: [{ id: 9, name: 'Native Bazel qualification' }] }); + if (/actions\/workflows\/9$/.test(endpoint)) + return Response.json({ id: 9, name: 'Native Bazel qualification' }); + if (/git\/ref\/heads\/main$/.test(endpoint)) + return Response.json({ + object: { sha: mode === 'native-advanced' ? 'b'.repeat(40) : process.env.FAKE_NATIVE_SHA }, + }); + if (/actions\/workflows\/9\/runs[?]/.test(endpoint)) { + const absent = [ + 'native-absent', + 'native-advanced', + 'native-race', + 'native-ambiguous', + ].includes(mode); + return Response.json({ + workflow_runs: dispatched ? [record(88)] : absent ? [] : [record(77)], + }); + } + const match = endpoint.match(/actions\/runs\/(77|88)(?:\/(jobs))?(?:\?.*)?$/); + if (match) { + if (match[2]) + return Response.json({ + jobs: [ + { + name: 'Required', + conclusion: ['native-source', 'native-dispatch-skipped'].includes(mode) + ? 'skipped' + : mode === 'native-failed' + ? 'failure' + : 'success', + }, + ], + }); + return Response.json(record(Number(match[1]))); + } + throw new Error('unexpected Native qualification endpoint ' + endpoint); + } if (process.env.FAKE_MODE.startsWith('qualification-')) { const mode = process.env.FAKE_MODE; const dispatched = fs.existsSync(process.env.FAKE_DISPATCH); diff --git a/tools/release/validate-release-workflow-inputs.test.mts b/tools/release/validate-release-workflow-inputs.test.mts index 55706b0b9..8785f6275 100644 --- a/tools/release/validate-release-workflow-inputs.test.mts +++ b/tools/release/validate-release-workflow-inputs.test.mts @@ -6,25 +6,22 @@ import path from 'node:path'; import test from 'node:test'; const ROOT = path.resolve(import.meta.dir, '../..'); -test('publication scopes tag planning to the verified Release Please candidate', () => { +test('publication plans once from the authenticated Prepare scope', () => { const { steps } = Bun.YAML.parse( readFileSync(path.join(ROOT, '.github/workflows/release.yml'), 'utf8'), ).jobs['plan-candidate']; - const identity = steps.findIndex((step) => step.id === 'release_scope'); const plan = steps.findIndex((step) => step.id === 'release_plan'); - assert.ok(identity >= 0 && identity < plan); - assert.match(steps[identity].run, /--derive-products/u); - assert.equal(steps[plan].env.PRODUCTS_JSON, `\${{ steps.release_scope.outputs.products_json }}`); - assert.match(steps[plan].run, /--products-json "\$PRODUCTS_JSON"/u); - const proof = steps.findIndex((step) => step.id === 'verify_publication_candidate'); - assert.ok(proof > plan); - assert.equal(steps[proof].env.PRODUCTS_JSON, `\${{ steps.release_plan.outputs.products_json }}`); + const markable = steps.findIndex((step) => step.id === 'assert_release_please_markable'); + assert.ok(plan >= 0 && markable > plan); + assert.match(steps[plan].run, /native-freeze-publication-candidate\.mts --plan-publication/u); + assert.match(steps[markable].run, /steps\.release_plan\.outputs\.release_sha/u); + assert.equal(steps.filter((step) => step.id === 'release_plan').length, 1); }); -test('registry bootstrap remains eligible when qualification dispatch was skipped', () => { +test('registry bootstrap consumes the prepared native candidate', () => { const { jobs } = Bun.YAML.parse( readFileSync(path.join(ROOT, '.github/workflows/release.yml'), 'utf8'), ); - assert.ok(jobs['prepare-candidate'].needs.includes('request-qualification')); + assert.deepEqual(jobs['prepare-candidate'].needs, ['plan-candidate']); const bootstrap = jobs['publish-bootstrap']; assert.ok(bootstrap.needs.includes('prepare-candidate')); assert.match(bootstrap.if, /!cancelled\(\)/u); @@ -43,7 +40,7 @@ test('both npm publication jobs can generate required provenance', () => { ); } }); -test('qualified recovery packages the original source and restores its checked controller', () => { +test('qualified recovery freezes original outputs and restores its checked controller', () => { const { jobs } = Bun.YAML.parse( readFileSync(path.join(ROOT, '.github/workflows/release.yml'), 'utf8'), ); @@ -52,17 +49,18 @@ test('qualified recovery packages the original source and restores its checked c (step) => step.name === 'Checkout qualified source for unchanged packaging', ); const registry = steps.findIndex((step) => step.id === 'validate_release_registry_state'); - const pack = steps.findIndex((step) => step.name === 'Package public release carriers'); + const outputs = steps.findIndex((step) => step.id === 'freeze_publication_lock'); const freeze = steps.findIndex((step) => step.id === 'freeze_publication_candidate'); const restore = steps.findIndex((step) => step.name === 'Restore checked publication controller'); const credentials = steps.findIndex((step) => step.id === 'bootstrap_credentials'); assert.ok( registry < checkout && - checkout < pack && - pack < freeze && + checkout < outputs && + outputs < freeze && freeze < restore && restore < credentials, ); + assert.match(steps[outputs].run, /native-freeze-publication-candidate\.mts/u); for (const index of [checkout, restore]) assert.equal(steps[index].if, `\${{ inputs.qualification_run_id != '' }}`); const scratch = mkdtempSync(path.join(os.tmpdir(), 'oliphaunt-qualified-recovery-')); diff --git a/tools/release/verify-github-release-http.test.mts b/tools/release/verify-github-release-http.test.mts index e1f7c5257..d1d3829c9 100644 --- a/tools/release/verify-github-release-http.test.mts +++ b/tools/release/verify-github-release-http.test.mts @@ -1,5 +1,8 @@ -import { createHash } from 'node:crypto'; import { describe, expect, test } from 'bun:test'; +import { createHash } from 'node:crypto'; +import { lstat, mkdtemp, readdir, readFile, rm, symlink, writeFile } from 'node:fs/promises'; +import os from 'node:os'; +import path from 'node:path'; import { assertExactReleaseAssetNames, @@ -77,6 +80,219 @@ describe('GitHub release HTTP boundaries', () => { expect(request.options.signal).toBeInstanceOf(AbortSignal); }); + test('retains the authenticated stream once after exact size and digest checks', async () => { + const directory = await mkdtemp(path.join(os.tmpdir(), 'github-retained-asset-')); + try { + const retainedPath = path.join(directory, 'asset.tar.zst'); + const chunks = [Buffer.from('exact '), Buffer.from('release asset bytes\n')]; + const bytes = Buffer.concat(chunks); + const sha256 = createHash('sha256').update(bytes).digest('hex'); + let fetches = 0; + const proof = await requestReleaseAssetProof( + 'https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/1', + 'asset.tar.zst', + bytes.length, + { + retainedPath, + expectedSha256: sha256, + fetchImpl: async () => { + fetches += 1; + return new Response( + new ReadableStream({ + start(controller) { + for (const chunk of chunks) controller.enqueue(chunk); + controller.close(); + }, + }), + ); + }, + }, + ); + expect(proof).toEqual({ bytes: bytes.length, sha256, path: retainedPath }); + expect(fetches).toBe(1); + expect(await readFile(proof.path)).toEqual(bytes); + expect((await lstat(proof.path)).mode & 0o222).toBe(0); + expect(await readdir(directory)).toEqual(['asset.tar.zst']); + } finally { + await rm(directory, { recursive: true, force: true }); + } + }); + + test('removes every partial retained file when the download or proof fails', async () => { + const directory = await mkdtemp(path.join(os.tmpdir(), 'github-retained-failure-')); + try { + let cancelled = 0; + const scenarios = [ + { + label: 'overruns size', + fetchImpl: async () => + new Response( + new ReadableStream({ + start(controller) { + controller.enqueue(Buffer.from('123')); + controller.enqueue(Buffer.from('45')); + }, + cancel() { + cancelled += 1; + }, + }), + ), + error: 'exceeds expected size 4', + }, + { + label: 'underruns size', + fetchImpl: async () => new Response('123'), + error: 'size 3 does not match expected size 4', + }, + { + label: 'declares wrong size', + fetchImpl: async () => new Response('1234', { headers: { 'content-length': '5' } }), + error: 'Content-Length 5 does not match expected size 4', + }, + { + label: 'has wrong digest', + fetchImpl: async () => new Response('1234'), + expectedSha256: '0'.repeat(64), + error: 'does not match expected sha256', + }, + { + label: 'fails while streaming', + fetchImpl: async () => + new Response( + new ReadableStream({ + start(controller) { + controller.enqueue(Buffer.from('12')); + }, + pull(controller) { + controller.error(new Error('interrupted stream')); + }, + }), + ), + error: 'interrupted stream', + }, + { + label: 'cancels fetch', + fetchImpl: async () => { + throw new DOMException('cancelled fetch', 'AbortError'); + }, + error: 'cancelled fetch', + }, + { + label: 'receives HTTP error', + fetchImpl: async () => new Response('failure', { status: 500 }), + error: 'HTTP 500', + }, + ]; + for (const scenario of scenarios) { + await expect( + requestReleaseAssetProof( + 'https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/1', + scenario.label, + 4, + { ...scenario, retainedPath: path.join(directory, 'asset.tar.zst') }, + ), + ).rejects.toThrow(scenario.error); + expect(await readdir(directory)).toEqual([]); + } + expect(cancelled).toBe(1); + } finally { + await rm(directory, { recursive: true, force: true }); + } + }); + + test('refuses occupied and symlink destinations without modifying unrelated files', async () => { + const directory = await mkdtemp(path.join(os.tmpdir(), 'github-retained-occupied-')); + try { + const existing = path.join(directory, 'existing'); + const symbolic = path.join(directory, 'symbolic'); + await writeFile(existing, 'unrelated bytes'); + await symlink(existing, symbolic); + let fetches = 0; + for (const retainedPath of [existing, symbolic]) { + await expect( + requestReleaseAssetProof( + 'https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/1', + 'asset.tar.zst', + 4, + { + retainedPath, + fetchImpl: async () => { + fetches += 1; + return new Response('1234'); + }, + }, + ), + ).rejects.toThrow(); + } + expect(fetches).toBe(0); + expect(await readFile(existing, 'utf8')).toBe('unrelated bytes'); + expect((await lstat(symbolic)).isSymbolicLink()).toBe(true); + expect((await readdir(directory)).sort()).toEqual(['existing', 'symbolic']); + } finally { + await rm(directory, { recursive: true, force: true }); + } + }); + + test('rejects malformed expected digests before creating a retained file or fetching', async () => { + const directory = await mkdtemp(path.join(os.tmpdir(), 'github-retained-invalid-')); + try { + let fetches = 0; + for (const expectedSha256 of ['invalid', 'A'.repeat(64), 123]) { + await expect( + requestReleaseAssetProof( + 'https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/1', + 'asset.tar.zst', + 4, + { + expectedSha256, + retainedPath: path.join(directory, 'asset.tar.zst'), + fetchImpl: async () => { + fetches += 1; + return new Response('1234'); + }, + }, + ), + ).rejects.toThrow('invalid expected sha256'); + } + expect(fetches).toBe(0); + expect(await readdir(directory)).toEqual([]); + } finally { + await rm(directory, { recursive: true, force: true }); + } + }); + + test('preserves files and symlinks that appear while a retained download is in flight', async () => { + const directory = await mkdtemp(path.join(os.tmpdir(), 'github-retained-race-')); + try { + const unrelated = path.join(directory, 'unrelated'); + await writeFile(unrelated, 'unrelated bytes'); + for (const kind of ['file', 'symlink']) { + const retainedPath = path.join(directory, kind); + await expect( + requestReleaseAssetProof( + 'https://api.github.com/repos/f0rr0/oliphaunt/releases/assets/1', + 'asset.tar.zst', + 4, + { + retainedPath, + fetchImpl: async () => { + if (kind === 'file') await writeFile(retainedPath, 'racing file'); + else await symlink(unrelated, retainedPath); + return new Response('1234'); + }, + }, + ), + ).rejects.toThrow(); + } + expect(await readFile(path.join(directory, 'file'), 'utf8')).toBe('racing file'); + expect((await lstat(path.join(directory, 'symlink'))).isSymbolicLink()).toBe(true); + expect(await readFile(unrelated, 'utf8')).toBe('unrelated bytes'); + expect((await readdir(directory)).sort()).toEqual(['file', 'symlink', 'unrelated']); + } finally { + await rm(directory, { recursive: true, force: true }); + } + }); + test('rejects size mismatches before buffering or hashing an unbounded asset', async () => { await expect( requestReleaseAssetProof( diff --git a/tools/release/verify-release-commit.mts b/tools/release/verify-release-commit.mts index e3f6ff373..a2deba2ce 100644 --- a/tools/release/verify-release-commit.mts +++ b/tools/release/verify-release-commit.mts @@ -2,16 +2,17 @@ import { existsSync, readdirSync, readFileSync, realpathSync, writeFileSync } from 'node:fs'; import path from 'node:path'; import process from 'node:process'; +import { cargoSatisfies } from '../../build_defs/languages/cargo-metadata.mts'; import { electronReleaseDependencies } from '../../src/examples/tools/example-release-dependencies.mts'; -import { exampleCargoReleaseVersionBindings } from './example-cargo-versions.mts'; import { isDefaultExtensionRequirement } from './consumer-compatibility.mts'; +import { exampleCargoReleaseVersionBindings } from './example-cargo-versions.mts'; import { nativeToolsOptionalPackageProducts, registryPackageRows, } from './release-artifact-targets.mts'; import { - buildBoundCompatibilityProducts, requirePublicSupportTransition, + resolveBuildBoundCompatibilityProducts, } from './release-dependency-plan.mts'; import { compatibilityVersionEntries, @@ -19,14 +20,16 @@ import { loadProducts, } from './release-graph.mts'; import { RELEASE_PLEASE_BOOTSTRAP_SHA } from './release-please-bootstrap.mts'; -import { releaseDerivedPathInventory } from './sync-release-pr.mts'; +import { + desiredCargoPathDependencyVersion, + releaseDerivedPathInventory, +} from './sync-release-pr.mts'; const TOOL = 'verify-release-commit.mts'; const ROOT = path.resolve(import.meta.dir, '../..'); const SEMVER = /^(?:0|[1-9][0-9]*)[.](?:0|[1-9][0-9]*)[.](?:0|[1-9][0-9]*)(?:-(?:(?:0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*)(?:[.](?:0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+[0-9A-Za-z-]+(?:[.][0-9A-Za-z-]+)*)?$/u; const CARGO_DEPENDENCY_TABLES = new Set(['dependencies', 'dev-dependencies', 'build-dependencies']); -let cachedDerivedRules; function error(message) { return new Error(`${TOOL}: ${message}`); @@ -321,9 +324,7 @@ function structuredRuleKey(type, file, parts) { return `${type}\0${file}\0${pathKey(parts)}`; } -function derivedVersionRules() { - if (cachedDerivedRules !== undefined) return cachedDerivedRules; - const products = loadProducts(TOOL); +function derivedVersionRules(products, buildBound, suppliedBuildBound) { const structured = new Map(); const text = new Map(); const addStructured = ( @@ -344,7 +345,24 @@ function derivedVersionRules() { ) { throw error(`conflicting derived version rules for ${file}:${parts.join('.')}`); } - const rule = { sourceProduct, wrapped, consumerProduct }; + const rule = { + sourceProduct, + wrapped, + consumerProduct, + // RP may update installed ecosystem requirements of selected packages. + // A supplied held map cannot authorize generated runtime metadata/consts + // merely because the independent producer is also selected. + allowSelectedProducerRetarget: + !suppliedBuildBound || + (type === 'json' && + file.endsWith('/package.json') && + ['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies'].includes( + parts[0], + )) || + (type === 'toml' && + parts.at(-1) === 'version' && + CARGO_DEPENDENCY_TABLES.has(parts.at(-3))), + }; structured.set(key, rule); if ( type === 'json' && @@ -372,7 +390,6 @@ function derivedVersionRules() { text.set(file, rule); }; - const buildBound = buildBoundCompatibilityProducts(products); for (const entry of compatibilityVersionEntries(products, { requireSourceProduct: true, prefix: TOOL, @@ -468,6 +485,7 @@ function derivedVersionRules() { } for (const rule of text.values()) { if (rule.consumerProduct !== undefined) { + rule.allowSelectedProducerRetarget = !suppliedBuildBound; rule.buildBound = buildBound.get(rule.consumerProduct)?.has(rule.sourceProduct) ?? false; rule.defaultInstall = isDefaultExtensionRequirement( products, @@ -476,8 +494,7 @@ function derivedVersionRules() { ); } } - cachedDerivedRules = { structured, text }; - return cachedDerivedRules; + return { structured, text }; } function productTransition(rule, before, after, transitions, productVersions) { @@ -498,7 +515,9 @@ function productTransition(rule, before, after, transitions, productVersions) { (rule.defaultInstall ? Bun.semver.order(after, productVersions.get(rule.sourceProduct)) <= 0 : after === productVersions.get(rule.sourceProduct) && - (rule.buildBound || transitions.some(({ product }) => product === rule.sourceProduct))) && + (rule.buildBound || + (rule.allowSelectedProducerRetarget && + transitions.some(({ product }) => product === rule.sourceProduct)))) && Bun.semver.order(after, before) > 0 ); } @@ -523,6 +542,13 @@ function cargoDependencyEntryPath(parts) { if (names.length === 3 && CARGO_DEPENDENCY_TABLES.has(names[0]) && names[2] === 'version') { return names.slice(0, 2); } + if ( + names.length === 4 && + names[0] === 'workspace' && + names[1] === 'dependencies' && + names[3] === 'version' + ) + return names.slice(0, 3); if ( names.length === 5 && names[0] === 'target' && @@ -548,6 +574,9 @@ function cargoDependencyVersionChange({ afterRoot, before, after, + products, + transitions, + updateMinimum = false, }) { if (path.posix.basename(file) !== 'Cargo.toml') return false; const entryPath = cargoDependencyEntryPath(parts); @@ -590,10 +619,15 @@ function cargoDependencyVersionChange({ ) { return false; } - const exact = typeof before === 'string' && before.startsWith('='); + const producer = Object.entries(products).find(([, product]) => + product.registry_packages?.includes('crates:' + nextPackage.name), + )?.[0]; return ( - before === `${exact ? '=' : ''}${priorPackage.version}` && - after === `${exact ? '=' : ''}${nextPackage.version}` + transitions.some(({ product }) => product === producer) && + typeof before === 'string' && + cargoSatisfies(priorPackage.version, before) && + (updateMinimum || !cargoSatisfies(nextPackage.version, before)) && + after === desiredCargoPathDependencyVersion(before, nextPackage.version, updateMinimum) ); } @@ -680,6 +714,26 @@ function authorizedDerivedStructuredChange(context, rules) { return true; } const rule = rules.structured.get(structuredRuleKey(context.type, context.file, context.parts)); + const cargoPath = context.type === 'toml' ? cargoDependencyEntryPath(context.parts) : undefined; + if (cargoPath && typeof valueAt(context.beforeRoot, cargoPath)?.path === 'string') { + const consumer = + rule?.consumerProduct ?? + Object.entries(context.products).find(([, product]) => + product.registry_packages?.includes('crates:' + context.beforeRoot.package?.name), + )?.[0]; + if ( + consumer && + context.products[consumer].registry_packages?.some((name) => name.startsWith('crates:')) && + !context.transitions.some(({ product }) => product === consumer) + ) + return false; + return cargoDependencyVersionChange({ + ...context, + updateMinimum: Boolean( + consumer && context.transitions.some(({ product }) => product === consumer), + ), + }); + } if (rule !== undefined) return productTransition( rule, @@ -801,8 +855,11 @@ function validateAllowedFileSemantics({ derivedFiles, transitions, productVersions, + products, + buildBound, + suppliedBuildBound, }) { - const derivedRules = derivedVersionRules(); + const derivedRules = derivedVersionRules(products, buildBound, suppliedBuildBound); const cargoVersions = new Map(); for (const file of changed) { if (file === '.release-please-manifest.json' || changelogs.has(file)) continue; @@ -857,6 +914,7 @@ function validateAllowedFileSemantics({ transitions, cargoVersions, productVersions, + products, }, derivedRules, ) @@ -935,7 +993,10 @@ export function releaseProductsFromManifests(config, before, after) { return changedProducts; } -export function verifyReleaseCommit({ repo = ROOT, headRef = 'HEAD', products }) { +export function verifyReleaseCommit(options) { + const { repo = ROOT, headRef = 'HEAD', products } = options; + const metadata = loadProducts(TOOL); + const buildBound = resolveBuildBoundCompatibilityProducts(metadata, options); if ( !Array.isArray(products) || products.length === 0 || @@ -1145,9 +1206,11 @@ export function verifyReleaseCommit({ repo = ROOT, headRef = 'HEAD', products }) productVersions: new Map( [...byProduct].map(([product, { packagePath }]) => [product, after[packagePath]]), ), + products: metadata, + buildBound, + suppliedBuildBound: Object.hasOwn(options, 'buildBound'), }); - const metadata = loadProducts(TOOL); for (const entry of publicSupportEntries()) { const transition = transitions.find(({ product }) => product === entry.product); if (!transition || transition.before === '0.0.0') continue; @@ -1171,13 +1234,14 @@ export function verifyReleaseCommit({ repo = ROOT, headRef = 'HEAD', products }) }; } -export function latestVerifiedReleaseCommit({ repo = ROOT, headRef = 'HEAD' } = {}) { +export function latestVerifiedReleaseCommit(options = {}) { + const { repo = ROOT, headRef = 'HEAD' } = options; const { release, commit } = releaseHistory(repo); if (releaseCommit(repo, headRef) !== commit) throw error('latest release history belongs to another head'); if (release === '') return null; const { products } = deriveReleaseProducts({ repo, headRef: release }); - return verifyReleaseCommit({ repo, headRef: release, products }); + return verifyReleaseCommit({ ...options, repo, headRef: release, products }); } function parseArgs(argv) { diff --git a/tools/release/verify-release-commit.test.mts b/tools/release/verify-release-commit.test.mts index 446ce47a6..95a2f0435 100644 --- a/tools/release/verify-release-commit.test.mts +++ b/tools/release/verify-release-commit.test.mts @@ -1,6 +1,7 @@ import assert from 'node:assert/strict'; import { mkdirSync, writeFileSync } from 'node:fs'; import path from 'node:path'; +import { loadProducts } from './release-graph.mts'; import { RELEASE_PLEASE_BOOTSTRAP_SHA } from './release-please-bootstrap.mts'; import { deriveReleaseProducts, @@ -258,10 +259,22 @@ function prepareCompatibility(base) { }; const producers = { [nativePath]: simple(native), 'src/native/broker': simple(broker) }; json('release-please-config.json', { packages: { ...producers, ...consumers } }); - const producerVersion = base || scenario === 'consumer-only' ? '0.3.1' : '0.3.2'; - const consumerVersion = base || scenario === 'unselected-consumer' ? '0.1.0' : '0.2.0'; - const pin = base ? '0.3.0' : producerVersion; + const heldProducers = ['consumer-only', 'supplier-map-isolation', 'authored'].includes(scenario); + const producerVersion = base || heldProducers ? '0.3.1' : '0.3.2'; + const consumerVersion = + base || ['unselected-consumer', 'authored'].includes(scenario) ? '0.1.0' : '0.2.0'; + const pin = base + ? '0.3.0' + : ['authored', 'authored-adoption'].includes(scenario) + ? '0.3.1' + : ['supplier-map-isolation', 'selected-held-supplier', 'registry-update'].includes(scenario) + ? '0.3.0' + : producerVersion; const consumerPin = scenario === 'consumer-only' ? '0.3.0' : pin; + const compiledBrokerPin = + !base && ['supplier-map-isolation', 'selected-held-supplier'].includes(scenario) + ? producerVersion + : consumerPin; json('.release-please-manifest.json', { ...Object.fromEntries(Object.keys(producers).map((folder) => [folder, producerVersion])), ...Object.fromEntries(Object.keys(consumers).map((folder) => [folder, consumerVersion])), @@ -287,11 +300,12 @@ function prepareCompatibility(base) { write( 'src/native/sdks/rust/Cargo.toml', cargo('oliphaunt', consumerVersion) + - `\n[package.metadata.oliphaunt]\nnative-version = "${consumerPin}"\nbroker-version = "${consumerPin}"\n`, + `\n[package.metadata.oliphaunt]\nnative-version = "${consumerPin}"\nbroker-version = "${compiledBrokerPin}"\n` + + `\n[dependencies]\noliphaunt-broker = { version = "${scenario === 'registry-update' ? producerVersion : consumerPin}", optional = true }\n`, ); write( 'src/native/sdks/rust/src/broker.rs', - `const BROKER_RELEASE_VERSION: &str = "${scenario === 'wrong-rust-const' ? '0.4.0' : consumerPin}";\n`, + `const BROKER_RELEASE_VERSION: &str = "${scenario === 'wrong-rust-const' ? '0.4.0' : compiledBrokerPin}";\n`, ); write('src/native/sdks/swift/VERSION', `${consumerVersion}\n`); write( @@ -314,6 +328,75 @@ function preparePublicSupport(base) { `[extension.compatibility]\nnative_runtime_version = "${base ? '0.3.2' : '0.3.3'}"\nwasix_runtime_version = "0.3.2"\n`, ); } + +function prepareLocalCargo(base) { + const core = 'liboliphaunt-native-bindings', + corePath = 'src/native/rust-bindings', + sdkPath = 'src/native/sdks/rust', + addonPath = 'src/native/node-addon'; + const compatible = scenario.includes('compatible'); + const adopted = !base && !['unselected-public-path', 'held-compatible-path'].includes(scenario); + const version = base ? '0.2.5' : compatible ? '0.2.6' : '0.3.0'; + json('release-please-config.json', { + packages: { + [corePath]: { 'release-type': 'rust', component: core }, + [sdkPath]: { 'release-type': 'rust', component: 'oliphaunt-rust' }, + [addonPath]: { 'release-type': 'node', component: 'oliphaunt-node-direct' }, + }, + }); + json('.release-please-manifest.json', { + [corePath]: version, + [sdkPath]: adopted ? '0.3.3' : '0.3.2', + [addonPath]: '0.2.2', + }); + write(corePath + '/Cargo.toml', cargo(core, version)); + changelog(corePath, version); + json(addonPath + '/package.json', { name: 'private-native-addon', version: '0.2.2' }); + const requirement = + base || compatible ? '0.2.0' : scenario === 'wrong-private-path' ? '0.4.0' : '0.3.0'; + const publicRequirement = base + ? '0.2.0' + : scenario === 'wrong-compatible-path' + ? '0.2.4' + : version; + const location = 'path="../rust-bindings",'; + write( + addonPath + '/Cargo.toml', + cargo('private-native-addon', '0.2.2') + + '\n[dependencies]\n' + + core + + '={' + + location + + 'version="' + + requirement + + '",features=' + + (!base && scenario === 'private-path-features' ? '["hidden"]' : '[]') + + '}\n', + ); + + write( + 'Cargo.toml', + '[workspace]\nmembers=["' + + corePath + + '","' + + sdkPath + + '"]\n[workspace.dependencies]\n' + + core + + '={path="' + + corePath + + '",version="' + + publicRequirement + + '"}\n', + ); + write( + sdkPath + '/Cargo.toml', + cargo('oliphaunt', adopted ? '0.3.3' : '0.3.2') + + '[dependencies]\n' + + core + + '.workspace=true\n', + ); + if (adopted) changelog(sdkPath, '0.3.3'); +} if (phase === 'write') { if (scenario === 'later-fix') write('fix.txt', 'post-release fix\n'); else { @@ -321,6 +404,7 @@ if (phase === 'write') { bootstrap: prepareBasic, basic: prepareBasic, cargo: prepareCargo, + 'cargo-path': prepareLocalCargo, wildcard: prepareWildcard, wasix: prepareWasix, example: prepareExample, @@ -332,30 +416,53 @@ if (phase === 'write') { } } else if (phase === 'assert') { const products = - family === 'public-support' - ? ['oliphaunt-extension-vector'] - : family === 'compatibility' - ? [ - ...(scenario === 'consumer-only' ? [] : [native, broker]), - ...(scenario === 'unselected-consumer' - ? [] - : [ - 'oliphaunt-extension-pg-hashids', - 'oliphaunt-js', - 'oliphaunt-rust', - 'oliphaunt-swift', - ]), - ].sort() - : family === 'cargo' - ? [broker, 'oliphaunt-rust'].sort() - : family === 'wasix' - ? ['liboliphaunt-wasix', 'oliphaunt-wasix-ts'] - : family === 'example' && scenario !== 'missing-native-transition' - ? [native, 'oliphaunt-rust'] - : scenario === 'hidden-version-config' - ? ['beta'] - : [broker]; - const verify = () => verifyReleaseCommit({ repo, headRef, products }); + family === 'cargo-path' + ? [ + 'liboliphaunt-native-bindings', + ...(!['unselected-public-path', 'held-compatible-path'].includes(scenario) + ? ['oliphaunt-rust'] + : []), + ].sort() + : family === 'public-support' + ? ['oliphaunt-extension-vector'] + : family === 'compatibility' + ? [ + ...(['consumer-only', 'supplier-map-isolation'].includes(scenario) + ? [] + : [native, broker]), + ...(scenario === 'unselected-consumer' + ? [] + : [ + 'oliphaunt-extension-pg-hashids', + 'oliphaunt-js', + 'oliphaunt-rust', + 'oliphaunt-swift', + ]), + ].sort() + : family === 'cargo' + ? [broker, 'oliphaunt-rust'].sort() + : family === 'wasix' + ? ['liboliphaunt-wasix', 'oliphaunt-wasix-ts'] + : family === 'example' && scenario !== 'missing-native-transition' + ? [native, 'oliphaunt-rust'] + : scenario === 'hidden-version-config' + ? ['beta'] + : [broker]; + const supplierMap = () => + new Map(Object.keys(loadProducts()).map((id) => [id, new Set()])); + const compiled = supplierMap(); + compiled.get('oliphaunt-rust').add(broker); + const verify = () => + verifyReleaseCommit({ + repo, + headRef, + products, + ...(['supplier-map-isolation', 'selected-held-supplier'].includes(scenario) + ? { buildBound: compiled } + : ['registry-update', 'authored-adoption'].includes(scenario) + ? { buildBound: supplierMap() } + : {}), + }); if (scenario === 'base') assert.equal(latestVerifiedReleaseCommit({ repo, headRef }), null); else if (scenario === 'later-fix') { assert.equal(latestVerifiedReleaseCommit({ repo, headRef }).commit, releaseRef); @@ -363,6 +470,11 @@ if (phase === 'write') { } else { const rejected = { + 'unselected-public-path': /non-version semantic change/u, + 'held-compatible-path': /non-version semantic change/u, + 'wrong-compatible-path': /non-version semantic change/u, + 'wrong-private-path': /non-version semantic change/u, + 'private-path-features': /non-version semantic change/u, mutated: /release-please-config[.]json contains a non-version semantic change/u, 'authored-patch': /must satisfy.*breaking-version policy/u, downgrade: /must advance to a semver version/u, @@ -401,6 +513,13 @@ if (phase === 'write') { else { const result = verify(); assert.deepEqual(result.products, products); + if (['supplier-map-isolation', 'selected-held-supplier'].includes(scenario)) { + assert.throws( + () => verifyReleaseCommit({ repo, headRef, products, buildBound: supplierMap() }), + /non-version semantic change/u, + ); + assert.deepEqual(verify().products, products); + } if (family === 'basic' && scenario === 'clean') { assert.deepEqual(deriveReleaseProducts({ repo, headRef }).products, [broker]); assert.equal(result.versions[broker], '0.1.0'); diff --git a/tools/release/verify-release-commit.test.sh b/tools/release/verify-release-commit.test.sh index 3edd7b13e..63760bbcd 100644 --- a/tools/release/verify-release-commit.test.sh +++ b/tools/release/verify-release-commit.test.sh @@ -15,7 +15,7 @@ assert_history() { bash "$root/tools/release/with-release-history.sh" "$repo" "$head" \ bash "$root/tools/dev/bun.sh" "$fixture" assert "$repo" "$family" "$1" "$head" "${release:-}" } -for family in bootstrap basic cargo wildcard wasix example compatibility public-support; do +for family in bootstrap basic cargo cargo-path wildcard wasix example compatibility public-support; do repo="$scratch/$family" git init -q "$repo" git -C "$repo" config user.name 'Release Test' @@ -30,17 +30,18 @@ for family in bootstrap basic cargo wildcard wasix example compatibility public- bootstrap) assert_history base; scenarios=(clean mutated) ;; basic) scenarios=(clean later-fix downgrade tainted kotlin-readme swift-readme deletion rename hidden-version-config hidden-derived-config derived-version-only unrelated-derived-dependency) ;; cargo) scenarios=(exact unrelated-pin unrelated-package unrelated-lock wrong-workspace-version unrelated-workspace-version workspace-metadata) ;; + cargo-path) scenarios=(private-path unselected-public-path wrong-private-path private-path-features selected-compatible-path held-compatible-path wrong-compatible-path) ;; wildcard) scenarios=(workspace-wildcard local-version wrong-version changed-path removed-path changed-features) ;; wasix) scenarios=(workspace-links) ;; example) scenarios=(exact wrong-registry-version wrong-runtime-version unrelated-registry-version missing-native-transition) ;; - compatibility) scenarios=(with-producer consumer-only unselected-consumer wrong-toml-pin wrong-json-pin wrong-raw-pin wrong-rust-const non-version-edit) ;; + compatibility) scenarios=(with-producer consumer-only supplier-map-isolation selected-held-supplier registry-update authored-adoption unselected-consumer wrong-toml-pin wrong-json-pin wrong-raw-pin wrong-rust-const non-version-edit) ;; public-support) scenarios=(authored-patch authored-breaking) ;; esac for scenario in "${scenarios[@]}"; do start="$base" if [[ "$scenario" == later-fix || "$scenario" == downgrade ]]; then start="$release"; fi git -C "$repo" switch -qc "$scenario" "$start" - if [[ "$family" == public-support ]]; then + if [[ "$family" == public-support || "$scenario" == authored-adoption ]]; then bash "$root/tools/dev/bun.sh" "$fixture" write "$repo" "$family" authored commit 'fix!: retarget the public native host before release generation' fi diff --git a/tools/release/verify_github_release_attestations.mts b/tools/release/verify_github_release_attestations.mts index 9f4597b19..aaabc2620 100755 --- a/tools/release/verify_github_release_attestations.mts +++ b/tools/release/verify_github_release_attestations.mts @@ -19,6 +19,7 @@ import { import { currentVersion } from './product-version.mts'; import { assertPublicationLockSource, loadPublicationLock } from './publication-lock.mts'; import { + artifactTargetConfig, contribCarrierDescriptor, expectedAssets as expectedDesktopAssets, extensionArtifactProductRoot, @@ -26,8 +27,8 @@ import { extensionReleaseProduct, extensionSourceIdentity, extensionSqlNames, - releaseMetadata, } from './release-artifact-targets.mts'; +import { createRetainedDownload } from './retained-download.mts'; export { requestBoundedGithubJson, requestGithubJsonWithRetry } from './github-read.mts'; @@ -272,21 +273,10 @@ function repository() { } function productTargets(product, preset) { - const release = releaseMetadata(product, PREFIX); - if (!release) { - fail(`Moon release metadata does not include ${product}`); - } - const artifactTargets = release.artifactTargets; - if ( - artifactTargets === null || - typeof artifactTargets !== 'object' || - artifactTargets.preset !== preset - ) { - fail(`Moon release metadata for ${product} must use artifactTargets preset ${preset}`); - } + const artifactTargets = artifactTargetConfig(product, preset, PREFIX); const targets = artifactTargets.targets; if (!Array.isArray(targets) || !targets.every((target) => typeof target === 'string' && target)) { - fail(`Moon release metadata for ${product} must declare artifactTargets.targets`); + fail(`${product} release.toml must declare artifact_targets.targets`); } return [...targets].sort(compareText); } @@ -418,7 +408,7 @@ async function expectedAssets(product, version, { extensionAssets } = {}) { fail(`asset expectation is not defined for ${product}`); } -async function exactResponseProof(response, expectedSize, context) { +async function exactResponseProof(response, expectedSize, context, retained, expectedSha256) { const declared = responseContentLength(response, context); if (declared !== null && declared !== expectedSize) { await response.body?.cancel?.().catch(() => {}); @@ -434,6 +424,7 @@ async function exactResponseProof(response, expectedSize, context) { size = bytes.byteLength; if (size > expectedSize) throw new Error(`${context} exceeds expected size ${expectedSize}`); hash.update(bytes); + await retained?.write(bytes); } else { try { for (;;) { @@ -441,11 +432,14 @@ async function exactResponseProof(response, expectedSize, context) { if (done) break; size += value.byteLength; if (size > expectedSize) { - await reader.cancel().catch(() => {}); throw new Error(`${context} exceeds expected size ${expectedSize}`); } hash.update(value); + await retained?.write(value); } + } catch (error) { + await reader.cancel().catch(() => {}); + throw error; } finally { reader.releaseLock(); } @@ -453,7 +447,11 @@ async function exactResponseProof(response, expectedSize, context) { if (size !== expectedSize) { throw new Error(`${context} size ${size} does not match expected size ${expectedSize}`); } - return { bytes: size, sha256: hash.digest('hex') }; + const sha256 = hash.digest('hex'); + if (expectedSha256 !== undefined && sha256 !== expectedSha256) { + throw new Error(`${context} sha256 ${sha256} does not match expected sha256 ${expectedSha256}`); + } + return { bytes: size, sha256 }; } function releaseAssetApiUrl(rawUrl, name) { @@ -507,20 +505,48 @@ export async function requestReleaseAssetProof( url, name, expectedSize, - { fetchImpl = fetch, timeoutMs = RELEASE_ASSET_TIMEOUT_MS } = {}, + { fetchImpl = fetch, timeoutMs = RELEASE_ASSET_TIMEOUT_MS, retainedPath, expectedSha256 } = {}, ) { const size = expectedAssetSize(expectedSize, name); - await reserveGitHubCoreRequest({ label: `prove GitHub release asset ${name}` }); - const response = await fetchImpl(releaseAssetApiUrl(url, name), { - headers: authHeaders('application/octet-stream'), - redirect: 'follow', - signal: AbortSignal.timeout(timeoutMs), - }); - if (!response.ok) { - await response.body?.cancel?.().catch(() => {}); - throw new Error(`GitHub asset download returned HTTP ${response.status} for ${name}`); + const apiUrl = releaseAssetApiUrl(url, name); + if ( + expectedSha256 !== undefined && + (typeof expectedSha256 !== 'string' || !/^[a-f0-9]{64}$/u.test(expectedSha256)) + ) { + throw new Error(`GitHub release asset ${name} has invalid expected sha256`); + } + const retained = + retainedPath === undefined ? undefined : await createRetainedDownload(retainedPath); + try { + await reserveGitHubCoreRequest({ label: `prove GitHub release asset ${name}` }); + const response = await fetchImpl(apiUrl, { + headers: authHeaders('application/octet-stream'), + redirect: 'follow', + signal: AbortSignal.timeout(timeoutMs), + }); + if (!response.ok) { + await response.body?.cancel?.().catch(() => {}); + throw new Error(`GitHub asset download returned HTTP ${response.status} for ${name}`); + } + const proof = await exactResponseProof( + response, + size, + `GitHub release asset ${name}`, + retained, + expectedSha256, + ); + return retained === undefined ? proof : { ...proof, path: await retained.commit() }; + } catch (error) { + try { + await retained?.abort(); + } catch (cleanupError) { + throw new AggregateError( + [error, cleanupError], + `GitHub release asset ${name} cleanup failed`, + ); + } + throw error; } - return exactResponseProof(response, size, `GitHub release asset ${name}`); } async function githubJson(url) { @@ -2318,12 +2344,12 @@ export async function prepareBundleVerification(options, directory) { ); } -async function readGhBundleVerification(options) { +export async function readGhBundleVerification( + options, + directory = process.env.OLIPHAUNT_ATTESTATION_VERIFICATION_DIR, +) { const { bundle, bundlePath } = options; - const { stem } = bundleVerificationFile( - options, - process.env.OLIPHAUNT_ATTESTATION_VERIFICATION_DIR, - ); + const { stem } = bundleVerificationFile(options, directory); const output = parseJsonBytes( await readBoundedRegularFile( stem + '.json', @@ -2349,6 +2375,35 @@ async function readGhBundleVerification(options) { return statementSubjects(statement, `gh verified statement for ${bundlePath}`); } +/** Authenticate one subject without claiming publication of other signed subjects. */ +export async function verifyAttestationBundleSubject( + { bundlePath, file, name, sha256, repo, publisherSha }, + { verifyBundleImpl = readGhBundleVerification } = {}, +) { + const absolute = path.resolve(bundlePath); + const bytes = await readBoundedRegularFile( + absolute, + MAX_ATTESTATION_BUNDLE_BYTES, + 'asset attestation bundle', + ); + const bundle = parseJsonBytes(bytes, 'asset attestation bundle'); + const subjects = statementSubjects(decodeBundleStatement(bundle, absolute), absolute); + const matches = subjects.filter((subject) => subject.name === name && subject.sha256 === sha256); + if (matches.length !== 1) throw new Error('asset attestation must bind the exact subject digest'); + const verified = await verifyBundleImpl({ + bundle, + bundlePath: absolute, + file, + head: publisherSha, + repo: normalizedRepository(repo), + }); + if (stableStringify(verified) !== stableStringify(subjects)) + throw new Error( + 'cryptographically verified asset subjects differ from supplied DSSE statement', + ); + return { bundleSha256: sha256Bytes(bytes), subjects }; +} + export async function verifyAttestationBundles( lock, bundlePaths, @@ -2432,13 +2487,19 @@ async function readReceipt(file) { export async function writeImmutableReceipt( file, receipt, - { linkImpl = (source, target) => fs.link(source, target) } = {}, + { + linkImpl = (source, target) => fs.link(source, target), + maximumBytes = MAX_ATTESTATION_RECEIPT_BYTES, + } = {}, ) { + if (!Number.isSafeInteger(maximumBytes) || maximumBytes <= 0) + throw new Error('immutable receipt maximumBytes must be a positive safe integer'); const absolute = path.resolve(file); const body = `${JSON.stringify(receipt, null, 2)}\n`; - if (Buffer.byteLength(body) > MAX_ATTESTATION_RECEIPT_BYTES) { + const size = Buffer.byteLength(body); + if (size > maximumBytes) { throw new Error( - `GitHub attestation receipt ${file} exceeds ${MAX_ATTESTATION_RECEIPT_BYTES} bytes`, + `GitHub attestation receipt ${file} is ${size} bytes, exceeds ${maximumBytes} bytes`, ); } await fs.mkdir(path.dirname(absolute), { recursive: true }); @@ -2455,7 +2516,7 @@ export async function writeImmutableReceipt( if (error?.code !== 'EEXIST') throw error; const existing = await readBoundedRegularFile( absolute, - MAX_ATTESTATION_RECEIPT_BYTES, + maximumBytes, `GitHub attestation receipt ${file}`, ); if (existing.toString('utf8') !== body) { @@ -2643,7 +2704,6 @@ function parseLegacyArgs(argv) { } else if (value === '--head-ref') { index += 1; } else if (value.startsWith('--head-ref=')) { - continue; } else if (value === '--help' || value === '-h') { console.log( 'usage: bash tools/release/verify-github-release-attestations.sh [--product ID...] [--products-json JSON] [--head-ref REF]', @@ -2724,3 +2784,25 @@ async function main(argv) { if (import.meta.main) { await main(Bun.argv.slice(2)); } + +/** An unsigned request only; gh subsequently authenticates this exact signer digest and workflow. */ +export function releaseAttestationPublisherRequest(bundle, { repo, name, sha256 }) { + const statement = decodeBundleStatement(bundle, 'completed release attestation'); + const subjects = statementSubjects(statement, 'completed release attestation'); + if (subjects.filter((subject) => subject.name === name && subject.sha256 === sha256).length !== 1) + return undefined; + const definition = statement.predicate?.buildDefinition; + const workflow = definition?.externalParameters?.workflow; + if ( + workflow?.repository !== `https://github.com/${repo}` || + workflow?.ref !== 'refs/heads/main' || + workflow?.path !== '.github/workflows/release.yml' + ) + return undefined; + const dependencies = definition?.resolvedDependencies?.filter( + (dependency) => dependency.uri === `git+https://github.com/${repo}@refs/heads/main`, + ); + if (dependencies?.length !== 1 || !/^[a-f0-9]{40}$/u.test(dependencies[0].digest?.gitCommit)) + return undefined; + return { publisherSha: dependencies[0].digest.gitCommit }; +} diff --git a/tools/release/with-product-history.sh b/tools/release/with-product-history.sh index e287c4a31..68ad04208 100644 --- a/tools/release/with-product-history.sh +++ b/tools/release/with-product-history.sh @@ -9,6 +9,10 @@ export OLIPHAUNT_PRODUCT_HISTORY="$state" reader="$owner/release-history.mts" bash "$owner/../dev/bun.sh" "$owner/release-graph.mts" --history-inputs "$repo" "$graph" head="$(git -C "$repo" rev-parse --verify "$head_ref^{commit}")" +if [[ "${OLIPHAUNT_CAPTURE_COMMIT_PATHS:-0}" == 1 ]]; then + bash "$owner/snapshot-commit-paths.sh" "$repo" "$head" "$state/commit-paths" + export OLIPHAUNT_COMMIT_PATHS="$state/commit-paths" +fi empty=4b825dc642cb6eb9a060e54bf8d69288fbee4904 printf '%s\0%s\0%s\0' "$repo" "$head_ref" "$head" > "$state/context" printf '%s\0%s\0%s\0%s\0%s\0%s\0' "$head_ref" "$head" "$head" "$head" "$empty" "$empty" > "$state/refs" @@ -30,9 +34,9 @@ record_diff() { if [[ "$base" != "$empty" ]]; then commit="$(git -C "$repo" rev-parse --verify "$base^{commit}")"; fi [[ ! -f "$state/changes/$commit" ]] || return 0 if [[ "$base" == "$empty" ]]; then - git -C "$repo" diff --name-only -z "$empty" "$head" -- > "$state/changes/$commit" + git -C "$repo" diff --no-renames --name-only -z "$empty" "$head" -- > "$state/changes/$commit" else - git -C "$repo" diff --name-only -z "$commit...$head" -- > "$state/changes/$commit" + git -C "$repo" diff --no-renames --name-only -z "$commit...$head" -- > "$state/changes/$commit" fi } record_diff "$empty" diff --git a/tools/release/with-source.mts b/tools/release/with-source.mts new file mode 100644 index 000000000..79faf41ea --- /dev/null +++ b/tools/release/with-source.mts @@ -0,0 +1,21 @@ +/** Identity supplied by the existing Git snapshot launcher. */ +export function sourceIdentity(headRef: string) { + const snapshot = JSON.parse(process.env.OLIPHAUNT_GIT_SOURCE_JSON || '{}'); + if ( + ![snapshot.commit, snapshot.tree, snapshot.checkout].every((value) => + /^[0-9a-f]{40}$/u.test(value ?? ''), + ) || + !( + headRef === snapshot.ref || + headRef === snapshot.commit || + (headRef === 'HEAD' && snapshot.checkout === snapshot.commit) + ) + ) { + throw new Error( + 'publication-lock: source identity for ' + + headRef + + ' requires a matching Git snapshot from bash tools/release/with-source.sh', + ); + } + return { commit: snapshot.commit, tree: snapshot.tree }; +}